Import Tint changes from Dawn

Changes:
  - 0ce9ab042ef5896b57833dd73dfa19fc94973b13 tint: Change all ProgramBuilder literals to 'i' or 'u' su... by Ben Clayton <bclayton@google.com>
  - f7357f89a38a95bed97612f417100214a273b23f tint: Castable - support non-default-constructable return... by Ben Clayton <bclayton@google.com>
  - c188ca62ca3ec311cbcf00e96ba0ebd0d7800ebe tint: add --overrides flag to specify pipeline overrides by Antonio Maiorano <amaiorano@google.com>
  - d3921b8230101c802c4fefb9c45a5bab9c503cdc Fixes for C++20 support. by Peter Kasting <pkasting@chromium.org>
  - 7cbd8202e6715ee5d51314bd1e745a5243da82c1 tint: Add Bitcast helper by Ben Clayton <bclayton@google.com>
  - 26cba1cb3925a46e2be60656d2e407e10ce243a1 tint: Fix CFI error in BlockAllocator by Ben Clayton <bclayton@google.com>
  - 06496d4d1a77cc3843fbdaeef1340244c77bd23a tint/reader/spirv: Generate 'i' suffixed literals by Ben Clayton <bclayton@google.com>
  - 8822e2966acf3b7fc0b222af7bad6ef4bcdc597f tint: Merge [S|U]intLiteralExpression by Ben Clayton <bclayton@google.com>
  - f693488bff822ac29a9cd4d0c62a0c94fe745619 tint: Lex three types of integer literal by Ben Clayton <bclayton@google.com>
  - e55877d017ef99cb1edf7301e53df116c1994f85 tint: Chromium-style fixes by Ben Clayton <bclayton@google.com>
  - b3aab0965214e10efea7a5d6fe7e014cb8252a69 AST fuzzer: Change unary expression operator by Author: Shiyu Liu <jamessliu2020@gmail.com>
  - 507a671e7d84fda9a5d34580bcce4eb235f5acf5 tint: Fix indentation in code templates by Ben Clayton <bclayton@google.com>
  - e23283f4974df5b1465f424dde10a5675aba7ab8 tint: Fix `[chromium-style]` auto pointer warnings by Ben Clayton <bclayton@google.com>
  - 4e98fb0bd8c99ac7cc91f7157428f645099b86d3 Factor out code to flatten bindings for msl by Antonio Maiorano <amaiorano@google.com>
  - 8aff0ed684cd140a6dd010b95ceac1decb734f74 tint: Add ProgramBuilder::Else() helper by James Price <jrprice@google.com>
  - 41e4d9a34c1d9dcb2eef3ff39ff9c1f987bfa02a Consistent formatting for Dawn/Tint. by dan sinclair <dsinclair@chromium.org>
  - 41cbf0279c46f66aee1ca50c13c15fa23db753ff Reland ExternalTexture Gamma/Gamut Correction by Brandon Jones <brandon1.jones@intel.com>
  - 9432887ce845063ff1ffa5b6c90fb3e5ac94a3ba tint/sem: Add abstract int and float types by Ben Clayton <bclayton@google.com>
  - 26ebe5ec3644decb5d47d64580d50ab80a7c8c64 tint: Refactor if-else statement representation by James Price <jrprice@google.com>
  - 01004b7732abf4e2587a7d560828e49156ca6633 tint: Remove '_type' suffix from file names by Ben Clayton <bclayton@google.com>
  - 7e8df044c6506297cc830f3b34c6bd391c8791e5 tint/writer/spirv: Replace Operand with std::variant by Ben Clayton <bclayton@google.com>
  - 617570a7da4a30d4277f84f6c58f7d851114e47e tint/writer: Replace scope_stack_, fix type ctor scoping. by Ben Clayton <bclayton@google.com>
  - e85fe161cdaf2c464149a5a9d273437a3998c8e1 tint: ProgramBuilder: Rename Const() to Let() by Ben Clayton <bclayton@google.com>
  - 046abc08e850c95a6573bdeac6601ecf21f66ec5 tint/writer: Replace use of strings for cache keys by Ben Clayton <bclayton@google.com>
  - f7ec85f9bd532918a982b5130aa311c39bb4dab2 Rename UniformConstant to Handle. by dan sinclair <dsinclair@chromium.org>
  - 6bdd6592d9becdc5886c4c4f4487e849bfabc5e7 DEPS: Update Dawn standalone toolchains by Ben Clayton <bclayton@google.com>
  - 3b1e30a496e3b1e2ea92d37a84190fa0596f9948 tint: Add `i` suffix and validate UInt literal non-negative by Zhaoming Jiang <zhaoming.jiang@intel.com>
  - 7098d3d692827ed973564c5e2371ee77ffbfb0d9 tint: Add enable directive for extensions by Zhaoming Jiang <zhaoming.jiang@intel.com>
  - d3a5080c7bf8be17fce355a5f60223ab8271ece4 Fixup validator tests added during split from resolver. by dan sinclair <dsinclair@chromium.org>
  - 1d882f55b7f47dd06fe57efdf286100bf2a3ad6b Revert "Add External Texture Gamma/Gamut Correction" by Ben Clayton <bclayton@google.com>
  - f4a861dd60b9e5f89b31a5690cf01c47b11a5326 tint/fuzzers: Build protobufs after remove_stale_autogen_... by Ben Clayton <bclayton@google.com>
  - b52d740227043bc3e07dca0a98778b16d959eaea D3D12: Indirect validation shader name cleanup and parame... by Enrico Galli <enrico.galli@intel.com>
  - 857175e59b39e42fd21092fd4a96af9ea2c30297 Add External Texture Gamma/Gamut Correction by Brandon Jones <brandon1.jones@intel.com>
  - 67af2087583562f19ced01d659af7c6d4bda138a GN: Move dawn import into build_with_chromium cond by Ben Clayton <bclayton@google.com>
  - 25775308a98aef286d7d8ff2b62bd316beff8ed7 Implement support for Unicode Pattern_White_Space by Antonio Maiorano <amaiorano@google.com>
  - 790e4c2d60ffba5a0c20f209c94cdcdaa8bbd3d1 GLSL writer: emit gl_PointSize = 1 in all vertex shaders ... by Stephen White <senorblanco@chromium.org>
  - e6d7ea708a960a3fbc775ff3a5bcfb4c6a0b1043 tint: Use resolved source var in the Inspector by James Price <jrprice@google.com>
  - a9d8da4434efb043b8ad00ac0c2628f2ff44c209 tint: Use resolved source var in LocalizeStructArrayAssig... by James Price <jrprice@google.com>
  - 98eb1696920974aa18b960efb96a00ad4e7b2cce tint: Track originating variables in the resolver by James Price <jrprice@google.com>
  - eba0e85c335c5b55b03f5dfa9f37501b1959e7a2 tint: make Lexer use line breaks from Source::File by Antonio Maiorano <amaiorano@google.com>
  - a238e7bf9d639da9f8ce941cf58b3b7c2e6deef9 tint_generator_wgsl_corpus should wait for remove_stale_a... by Fumitoshi Ukai <ukai@google.com>
  - aacad7c65e80fdc1517348a5a4e7000ecec57d2e tint: Update FirstIndexOffsetTest expected results by James Price <jrprice@google.com>
  - 6cb57a9847f591b9ff53db529fb659098ddb4770 Change External Texture YUV-to-RGB Conversion to Use Matrix by Brandon Jones <brandon1.jones@intel.com>
  - f05575bb21584fda1e8e174470348c8d1679cf80 [tint] Move validation code into a Validator class. by dan sinclair <dsinclair@chromium.org>
  - 45ec7c352815154142de230588a769537da09389 D3D12: Duplicate first/baseVertex on Draw[Indexed]Indirect by Enrico Galli <enrico.galli@intel.com>
GitOrigin-RevId: 0ce9ab042ef5896b57833dd73dfa19fc94973b13
Change-Id: Ia8280f68ae3b4e53f42372ebc7d8e2db91ed1ada
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/87667
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/.clang-format b/include/tint/.clang-format
deleted file mode 100644
index 2fb833a..0000000
--- a/include/tint/.clang-format
+++ /dev/null
@@ -1,2 +0,0 @@
-# http://clang.llvm.org/docs/ClangFormatStyleOptions.html
-BasedOnStyle: Chromium
diff --git a/src/tint/.clang-format b/src/tint/.clang-format
deleted file mode 100644
index 2fb833a..0000000
--- a/src/tint/.clang-format
+++ /dev/null
@@ -1,2 +0,0 @@
-# http://clang.llvm.org/docs/ClangFormatStyleOptions.html
-BasedOnStyle: Chromium
diff --git a/src/tint/BUILD.gn b/src/tint/BUILD.gn
index 980b16d..71cd2dc 100644
--- a/src/tint/BUILD.gn
+++ b/src/tint/BUILD.gn
@@ -222,8 +222,8 @@
     "ast/disable_validation_attribute.h",
     "ast/discard_statement.cc",
     "ast/discard_statement.h",
-    "ast/else_statement.cc",
-    "ast/else_statement.h",
+    "ast/enable.cc",
+    "ast/enable.h",
     "ast/expression.cc",
     "ast/expression.h",
     "ast/external_texture.cc",
@@ -288,8 +288,6 @@
     "ast/sampled_texture.h",
     "ast/sampler.cc",
     "ast/sampler.h",
-    "ast/sint_literal_expression.cc",
-    "ast/sint_literal_expression.h",
     "ast/stage_attribute.cc",
     "ast/stage_attribute.h",
     "ast/statement.cc",
@@ -322,8 +320,6 @@
     "ast/type_name.h",
     "ast/u32.cc",
     "ast/u32.h",
-    "ast/uint_literal_expression.cc",
-    "ast/uint_literal_expression.h",
     "ast/unary_op.cc",
     "ast/unary_op.h",
     "ast/unary_op_expression.cc",
@@ -349,6 +345,7 @@
     "debug.h",
     "demangler.cc",
     "demangler.h",
+    "number.h",
     "diagnostic/diagnostic.cc",
     "diagnostic/diagnostic.h",
     "diagnostic/formatter.cc",
@@ -376,52 +373,53 @@
     "resolver/resolver.cc",
     "resolver/resolver.h",
     "resolver/resolver_constants.cc",
-    "resolver/resolver_validation.cc",
     "resolver/sem_helper.cc",
     "resolver/sem_helper.h",
+    "resolver/validator.cc",
+    "resolver/validator.h",
     "scope_stack.h",
     "sem/array.h",
-    "sem/atomic_type.h",
+    "sem/atomic.h",
     "sem/behavior.h",
     "sem/binding_point.h",
-    "sem/bool_type.h",
+    "sem/bool.h",
     "sem/builtin.h",
     "sem/builtin_type.h",
     "sem/call.h",
     "sem/call_target.h",
     "sem/constant.h",
-    "sem/depth_multisampled_texture_type.h",
-    "sem/depth_texture_type.h",
+    "sem/depth_multisampled_texture.h",
+    "sem/depth_texture.h",
     "sem/expression.h",
-    "sem/external_texture_type.h",
-    "sem/f32_type.h",
+    "sem/external_texture.h",
+    "sem/f32.h",
     "sem/for_loop_statement.h",
-    "sem/i32_type.h",
+    "sem/i32.h",
     "sem/if_statement.h",
     "sem/info.h",
     "sem/loop_statement.h",
-    "sem/matrix_type.h",
+    "sem/matrix.h",
     "sem/module.h",
-    "sem/multisampled_texture_type.h",
+    "sem/multisampled_texture.h",
     "sem/node.h",
     "sem/parameter_usage.h",
     "sem/pipeline_stage_set.h",
-    "sem/pointer_type.h",
-    "sem/reference_type.h",
-    "sem/sampled_texture_type.h",
+    "sem/pointer.h",
+    "sem/reference.h",
+    "sem/sampled_texture.h",
+    "sem/sampler.h",
     "sem/sampler_texture_pair.h",
-    "sem/sampler_type.h",
-    "sem/storage_texture_type.h",
+    "sem/storage_texture.h",
     "sem/switch_statement.h",
-    "sem/texture_type.h",
+    "sem/texture.h",
     "sem/type.h",
     "sem/type_constructor.h",
     "sem/type_conversion.h",
     "sem/type_manager.h",
     "sem/type_mappings.h",
-    "sem/u32_type.h",
-    "sem/vector_type.h",
-    "sem/void_type.h",
+    "sem/u32.h",
+    "sem/vector.h",
+    "sem/void.h",
     "source.cc",
     "source.h",
     "symbol.cc",
@@ -513,6 +511,7 @@
     "transform/wrap_arrays_in_structs.h",
     "transform/zero_init_workgroup_memory.cc",
     "transform/zero_init_workgroup_memory.h",
+    "utils/bitcast.h",
     "utils/block_allocator.h",
     "utils/crc32.h",
     "utils/debugger.cc",
@@ -529,6 +528,8 @@
     "writer/append_vector.h",
     "writer/array_length_from_uniform_options.cc",
     "writer/array_length_from_uniform_options.h",
+    "writer/flatten_bindings.cc",
+    "writer/flatten_bindings.h",
     "writer/float_to_string.cc",
     "writer/float_to_string.h",
     "writer/generate_external_texture_bindings.cc",
@@ -552,16 +553,22 @@
 
 libtint_source_set("libtint_sem_src") {
   sources = [
+    "sem/abstract_float.cc",
+    "sem/abstract_float.h",
+    "sem/abstract_int.cc",
+    "sem/abstract_int.h",
+    "sem/abstract_numeric.cc",
+    "sem/abstract_numeric.h",
     "sem/array.cc",
     "sem/array.h",
-    "sem/atomic_type.cc",
-    "sem/atomic_type.h",
+    "sem/atomic.cc",
+    "sem/atomic.h",
     "sem/behavior.cc",
     "sem/behavior.h",
     "sem/binding_point.h",
     "sem/block_statement.cc",
-    "sem/bool_type.cc",
-    "sem/bool_type.h",
+    "sem/bool.cc",
+    "sem/bool.h",
     "sem/builtin.cc",
     "sem/builtin.h",
     "sem/builtin_type.cc",
@@ -572,55 +579,55 @@
     "sem/call_target.h",
     "sem/constant.cc",
     "sem/constant.h",
-    "sem/depth_multisampled_texture_type.cc",
-    "sem/depth_multisampled_texture_type.h",
-    "sem/depth_texture_type.cc",
-    "sem/depth_texture_type.h",
+    "sem/depth_multisampled_texture.cc",
+    "sem/depth_multisampled_texture.h",
+    "sem/depth_texture.cc",
+    "sem/depth_texture.h",
     "sem/expression.cc",
     "sem/expression.h",
-    "sem/external_texture_type.cc",
-    "sem/external_texture_type.h",
-    "sem/f32_type.cc",
-    "sem/f32_type.h",
+    "sem/external_texture.cc",
+    "sem/external_texture.h",
+    "sem/f32.cc",
+    "sem/f32.h",
     "sem/for_loop_statement.cc",
     "sem/for_loop_statement.h",
     "sem/function.cc",
-    "sem/i32_type.cc",
-    "sem/i32_type.h",
+    "sem/i32.cc",
+    "sem/i32.h",
     "sem/if_statement.cc",
     "sem/if_statement.h",
     "sem/info.cc",
     "sem/info.h",
     "sem/loop_statement.cc",
     "sem/loop_statement.h",
-    "sem/matrix_type.cc",
-    "sem/matrix_type.h",
+    "sem/matrix.cc",
+    "sem/matrix.h",
     "sem/member_accessor_expression.cc",
     "sem/module.cc",
     "sem/module.h",
-    "sem/multisampled_texture_type.cc",
-    "sem/multisampled_texture_type.h",
+    "sem/multisampled_texture.cc",
+    "sem/multisampled_texture.h",
     "sem/node.cc",
     "sem/node.h",
     "sem/parameter_usage.cc",
     "sem/parameter_usage.h",
     "sem/pipeline_stage_set.h",
-    "sem/pointer_type.cc",
-    "sem/pointer_type.h",
-    "sem/reference_type.cc",
-    "sem/reference_type.h",
-    "sem/sampled_texture_type.cc",
-    "sem/sampled_texture_type.h",
-    "sem/sampler_type.cc",
-    "sem/sampler_type.h",
+    "sem/pointer.cc",
+    "sem/pointer.h",
+    "sem/reference.cc",
+    "sem/reference.h",
+    "sem/sampled_texture.cc",
+    "sem/sampled_texture.h",
+    "sem/sampler.cc",
+    "sem/sampler.h",
     "sem/statement.cc",
-    "sem/storage_texture_type.cc",
-    "sem/storage_texture_type.h",
+    "sem/storage_texture.cc",
+    "sem/storage_texture.h",
     "sem/struct.cc",
     "sem/switch_statement.cc",
     "sem/switch_statement.h",
-    "sem/texture_type.cc",
-    "sem/texture_type.h",
+    "sem/texture.cc",
+    "sem/texture.h",
     "sem/type.cc",
     "sem/type.h",
     "sem/type_constructor.cc",
@@ -630,13 +637,13 @@
     "sem/type_manager.cc",
     "sem/type_manager.h",
     "sem/type_mappings.h",
-    "sem/u32_type.cc",
-    "sem/u32_type.h",
+    "sem/u32.cc",
+    "sem/u32.h",
     "sem/variable.cc",
-    "sem/vector_type.cc",
-    "sem/vector_type.h",
-    "sem/void_type.cc",
-    "sem/void_type.h",
+    "sem/vector.cc",
+    "sem/vector.h",
+    "sem/void.cc",
+    "sem/void.h",
   ]
 
   public_deps = [ ":libtint_core_all_src" ]
diff --git a/src/tint/CMakeLists.txt b/src/tint/CMakeLists.txt
index ae3f224..4d10bcb 100644
--- a/src/tint/CMakeLists.txt
+++ b/src/tint/CMakeLists.txt
@@ -110,8 +110,8 @@
   ast/depth_texture.h
   ast/discard_statement.cc
   ast/discard_statement.h
-  ast/else_statement.cc
-  ast/else_statement.h
+  ast/enable.cc
+  ast/enable.h
   ast/expression.cc
   ast/expression.h
   ast/external_texture.cc
@@ -174,8 +174,6 @@
   ast/sampled_texture.h
   ast/sampler.cc
   ast/sampler.h
-  ast/sint_literal_expression.cc
-  ast/sint_literal_expression.h
   ast/stage_attribute.cc
   ast/stage_attribute.h
   ast/statement.cc
@@ -211,8 +209,6 @@
   ast/type_name.h
   ast/u32.cc
   ast/u32.h
-  ast/uint_literal_expression.cc
-  ast/uint_literal_expression.h
   ast/unary_op_expression.cc
   ast/unary_op_expression.h
   ast/unary_op.cc
@@ -236,6 +232,7 @@
   clone_context.h
   demangler.cc
   demangler.h
+  number.h
   inspector/entry_point.cc
   inspector/entry_point.h
   inspector/inspector.cc
@@ -256,15 +253,22 @@
   resolver/dependency_graph.h
   resolver/resolver.cc
   resolver/resolver_constants.cc
-  resolver/resolver_validation.cc
   resolver/resolver.h
   resolver/sem_helper.cc
   resolver/sem_helper.h
+  resolver/validator.cc
+  resolver/validator.h
   scope_stack.h
+  sem/abstract_float.cc
+  sem/abstract_float.h
+  sem/abstract_int.cc
+  sem/abstract_int.h
+  sem/abstract_numeric.cc
+  sem/abstract_numeric.h
   sem/array.cc
   sem/array.h
-  sem/atomic_type.cc
-  sem/atomic_type.h
+  sem/atomic.cc
+  sem/atomic.h
   sem/behavior.cc
   sem/behavior.h
   sem/binding_point.h
@@ -280,8 +284,8 @@
   sem/call.h
   sem/constant.cc
   sem/constant.h
-  sem/depth_multisampled_texture_type.cc
-  sem/depth_multisampled_texture_type.h
+  sem/depth_multisampled_texture.cc
+  sem/depth_multisampled_texture.h
   sem/expression.cc
   sem/expression.h
   sem/function.cc
@@ -389,40 +393,40 @@
   transform/utils/get_insertion_point.h
   transform/utils/hoist_to_decl_before.cc
   transform/utils/hoist_to_decl_before.h
-  sem/bool_type.cc
-  sem/bool_type.h
-  sem/depth_texture_type.cc
-  sem/depth_texture_type.h
-  sem/external_texture_type.cc
-  sem/external_texture_type.h
-  sem/f32_type.cc
-  sem/f32_type.h
+  sem/bool.cc
+  sem/bool.h
+  sem/depth_texture.cc
+  sem/depth_texture.h
+  sem/external_texture.cc
+  sem/external_texture.h
+  sem/f32.cc
+  sem/f32.h
   sem/for_loop_statement.cc
   sem/for_loop_statement.h
-  sem/i32_type.cc
-  sem/i32_type.h
+  sem/i32.cc
+  sem/i32.h
   sem/if_statement.cc
   sem/if_statement.h
   sem/loop_statement.cc
   sem/loop_statement.h
-  sem/matrix_type.cc
-  sem/matrix_type.h
-  sem/multisampled_texture_type.cc
-  sem/multisampled_texture_type.h
-  sem/pointer_type.cc
-  sem/pointer_type.h
-  sem/reference_type.cc
-  sem/reference_type.h
-  sem/sampled_texture_type.cc
-  sem/sampled_texture_type.h
-  sem/sampler_type.cc
-  sem/sampler_type.h
-  sem/storage_texture_type.cc
-  sem/storage_texture_type.h
+  sem/matrix.cc
+  sem/matrix.h
+  sem/multisampled_texture.cc
+  sem/multisampled_texture.h
+  sem/pointer.cc
+  sem/pointer.h
+  sem/reference.cc
+  sem/reference.h
+  sem/sampled_texture.cc
+  sem/sampled_texture.h
+  sem/sampler.cc
+  sem/sampler.h
+  sem/storage_texture.cc
+  sem/storage_texture.h
   sem/switch_statement.cc
   sem/switch_statement.h
-  sem/texture_type.cc
-  sem/texture_type.h
+  sem/texture.cc
+  sem/texture.h
   sem/type_constructor.cc
   sem/type_constructor.h
   sem/type_conversion.cc
@@ -431,12 +435,13 @@
   sem/type.h
   sem/type_manager.cc
   sem/type_manager.h
-  sem/u32_type.cc
-  sem/u32_type.h
-  sem/vector_type.cc
-  sem/vector_type.h
-  sem/void_type.cc
-  sem/void_type.h
+  sem/u32.cc
+  sem/u32.h
+  sem/vector.cc
+  sem/vector.h
+  sem/void.cc
+  sem/void.h
+  utils/bitcast.h
   utils/block_allocator.h
   utils/crc32.h
   utils/enum_set.h
@@ -451,6 +456,8 @@
   writer/append_vector.h
   writer/array_length_from_uniform_options.cc
   writer/array_length_from_uniform_options.h
+  writer/flatten_bindings.cc
+  writer/flatten_bindings.h
   writer/float_to_string.cc
   writer/float_to_string.h
   writer/generate_external_texture_bindings.cc
@@ -673,7 +680,7 @@
     ast/depth_multisampled_texture_test.cc
     ast/depth_texture_test.cc
     ast/discard_statement_test.cc
-    ast/else_statement_test.cc
+    ast/enable_test.cc
     ast/external_texture_test.cc
     ast/f32_test.cc
     ast/fallthrough_statement_test.cc
@@ -702,7 +709,6 @@
     ast/return_statement_test.cc
     ast/sampled_texture_test.cc
     ast/sampler_test.cc
-    ast/sint_literal_expression_test.cc
     ast/stage_attribute_test.cc
     ast/storage_texture_test.cc
     ast/stride_attribute_test.cc
@@ -716,7 +722,6 @@
     ast/texture_test.cc
     ast/traverse_expressions_test.cc
     ast/u32_test.cc
-    ast/uint_literal_expression_test.cc
     ast/unary_op_expression_test.cc
     ast/variable_decl_statement_test.cc
     ast/variable_test.cc
@@ -762,6 +767,7 @@
     resolver/resolver_test_helper.h
     resolver/resolver_test.cc
     resolver/side_effects_test.cc
+    resolver/source_variable_test.cc
     resolver/storage_class_layout_validation_test.cc
     resolver/storage_class_validation_test.cc
     resolver/struct_layout_test.cc
@@ -770,30 +776,31 @@
     resolver/type_constructor_validation_test.cc
     resolver/type_validation_test.cc
     resolver/validation_test.cc
+    resolver/validator_is_storeable_test.cc
     resolver/var_let_test.cc
     resolver/var_let_validation_test.cc
     scope_stack_test.cc
-    sem/atomic_type_test.cc
-    sem/bool_type_test.cc
+    sem/atomic.cc
+    sem/bool_test.cc
     sem/builtin_test.cc
-    sem/depth_multisampled_texture_type_test.cc
-    sem/depth_texture_type_test.cc
-    sem/external_texture_type_test.cc
-    sem/f32_type_test.cc
-    sem/i32_type_test.cc
-    sem/matrix_type_test.cc
-    sem/multisampled_texture_type_test.cc
-    sem/pointer_type_test.cc
-    sem/reference_type_test.cc
-    sem/sampled_texture_type_test.cc
-    sem/sampler_type_test.cc
+    sem/depth_multisampled_texture_test.cc
+    sem/depth_texture_test.cc
+    sem/external_texture_test.cc
+    sem/f32_test.cc
+    sem/i32_test.cc
+    sem/matrix_test.cc
+    sem/multisampled_texture_test.cc
+    sem/pointer_test.cc
+    sem/reference_test.cc
+    sem/sampled_texture_test.cc
+    sem/sampler_test.cc
     sem/sem_array_test.cc
     sem/sem_struct_test.cc
-    sem/storage_texture_type_test.cc
-    sem/texture_type_test.cc
+    sem/storage_texture_test.cc
+    sem/texture_test.cc
     sem/type_manager_test.cc
-    sem/u32_type_test.cc
-    sem/vector_type_test.cc
+    sem/u32_test.cc
+    sem/vector_test.cc
     source_test.cc
     symbol_table_test.cc
     symbol_test.cc
@@ -801,6 +808,7 @@
     text/unicode_test.cc
     traits_test.cc
     transform/transform_test.cc
+    utils/bitcast_test.cc
     utils/block_allocator_test.cc
     utils/crc32_test.cc
     utils/defer_test.cc
@@ -817,6 +825,7 @@
     utils/unique_allocator_test.cc
     utils/unique_vector_test.cc
     writer/append_vector_test.cc
+    writer/flatten_bindings_test.cc
     writer/float_to_string_test.cc
     writer/generate_external_texture_bindings_test.cc
     writer/text_generator_test.cc
@@ -888,9 +897,9 @@
       reader/wgsl/parser_impl_const_literal_test.cc
       reader/wgsl/parser_impl_continue_stmt_test.cc
       reader/wgsl/parser_impl_continuing_stmt_test.cc
-      reader/wgsl/parser_impl_depth_texture_type_test.cc
-      reader/wgsl/parser_impl_external_texture_type_test.cc
-      reader/wgsl/parser_impl_elseif_stmt_test.cc
+      reader/wgsl/parser_impl_depth_texture_test.cc
+      reader/wgsl/parser_impl_enable_directive_test.cc
+      reader/wgsl/parser_impl_external_texture_test.cc
       reader/wgsl/parser_impl_equality_expression_test.cc
       reader/wgsl/parser_impl_error_msg_test.cc
       reader/wgsl/parser_impl_error_resync_test.cc
@@ -916,14 +925,14 @@
       reader/wgsl/parser_impl_primary_expression_test.cc
       reader/wgsl/parser_impl_relational_expression_test.cc
       reader/wgsl/parser_impl_reserved_keyword_test.cc
-      reader/wgsl/parser_impl_sampled_texture_type_test.cc
-      reader/wgsl/parser_impl_sampler_type_test.cc
+      reader/wgsl/parser_impl_sampled_texture_test.cc
+      reader/wgsl/parser_impl_sampler_test.cc
       reader/wgsl/parser_impl_shift_expression_test.cc
       reader/wgsl/parser_impl_singular_expression_test.cc
       reader/wgsl/parser_impl_statement_test.cc
       reader/wgsl/parser_impl_statements_test.cc
       reader/wgsl/parser_impl_storage_class_test.cc
-      reader/wgsl/parser_impl_storage_texture_type_test.cc
+      reader/wgsl/parser_impl_storage_texture_test.cc
       reader/wgsl/parser_impl_struct_body_decl_test.cc
       reader/wgsl/parser_impl_struct_decl_test.cc
       reader/wgsl/parser_impl_struct_attribute_decl_test.cc
@@ -936,7 +945,7 @@
       reader/wgsl/parser_impl_test_helper.cc
       reader/wgsl/parser_impl_test_helper.h
       reader/wgsl/parser_impl_texel_format_test.cc
-      reader/wgsl/parser_impl_texture_sampler_types_test.cc
+      reader/wgsl/parser_impl_texture_sampler_test.cc
       reader/wgsl/parser_impl_type_alias_test.cc
       reader/wgsl/parser_impl_type_decl_test.cc
       reader/wgsl/parser_impl_unary_expression_test.cc
@@ -1003,6 +1012,7 @@
       writer/wgsl/generator_impl_constructor_test.cc
       writer/wgsl/generator_impl_continue_test.cc
       writer/wgsl/generator_impl_discard_test.cc
+      writer/wgsl/generator_impl_enable_test.cc
       writer/wgsl/generator_impl_fallthrough_test.cc
       writer/wgsl/generator_impl_function_test.cc
       writer/wgsl/generator_impl_global_decl_test.cc
@@ -1034,6 +1044,7 @@
       transform/decompose_memory_access_test.cc
       transform/decompose_strided_array_test.cc
       transform/decompose_strided_matrix_test.cc
+      transform/expand_compound_assignment_test.cc
       transform/first_index_offset_test.cc
       transform/fold_constants_test.cc
       transform/fold_trivial_single_use_lets_test.cc
diff --git a/src/tint/ast/access.cc b/src/tint/ast/access.cc
index 575463d..642d852 100644
--- a/src/tint/ast/access.cc
+++ b/src/tint/ast/access.cc
@@ -17,25 +17,25 @@
 namespace tint::ast {
 
 std::ostream& operator<<(std::ostream& out, Access access) {
-  switch (access) {
-    case ast::Access::kUndefined: {
-      out << "undefined";
-      break;
+    switch (access) {
+        case ast::Access::kUndefined: {
+            out << "undefined";
+            break;
+        }
+        case ast::Access::kRead: {
+            out << "read";
+            break;
+        }
+        case ast::Access::kReadWrite: {
+            out << "read_write";
+            break;
+        }
+        case ast::Access::kWrite: {
+            out << "write";
+            break;
+        }
     }
-    case ast::Access::kRead: {
-      out << "read";
-      break;
-    }
-    case ast::Access::kReadWrite: {
-      out << "read_write";
-      break;
-    }
-    case ast::Access::kWrite: {
-      out << "write";
-      break;
-    }
-  }
-  return out;
+    return out;
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/access.h b/src/tint/ast/access.h
index aa9f656..3714b70 100644
--- a/src/tint/ast/access.h
+++ b/src/tint/ast/access.h
@@ -22,16 +22,16 @@
 
 /// The access control settings
 enum Access {
-  /// Not declared in the source
-  kUndefined = 0,
-  /// Read only
-  kRead,
-  /// Write only
-  kWrite,
-  /// Read write
-  kReadWrite,
-  // Last valid access mode
-  kLastValid = kReadWrite,
+    /// Not declared in the source
+    kUndefined = 0,
+    /// Read only
+    kRead,
+    /// Write only
+    kWrite,
+    /// Read write
+    kReadWrite,
+    // Last valid access mode
+    kLastValid = kReadWrite,
 };
 
 /// @param out the std::ostream to write to
diff --git a/src/tint/ast/alias.cc b/src/tint/ast/alias.cc
index 1f76749..fa98cd4 100644
--- a/src/tint/ast/alias.cc
+++ b/src/tint/ast/alias.cc
@@ -20,12 +20,9 @@
 
 namespace tint::ast {
 
-Alias::Alias(ProgramID pid,
-             const Source& src,
-             const Symbol& n,
-             const Type* subtype)
+Alias::Alias(ProgramID pid, const Source& src, const Symbol& n, const Type* subtype)
     : Base(pid, src, n), type(subtype) {
-  TINT_ASSERT(AST, type);
+    TINT_ASSERT(AST, type);
 }
 
 Alias::Alias(Alias&&) = default;
@@ -33,11 +30,11 @@
 Alias::~Alias() = default;
 
 const Alias* Alias::Clone(CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  auto sym = ctx->Clone(name);
-  auto* ty = ctx->Clone(type);
-  return ctx->dst->create<Alias>(src, sym, ty);
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    auto sym = ctx->Clone(name);
+    auto* ty = ctx->Clone(type);
+    return ctx->dst->create<Alias>(src, sym, ty);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/alias.h b/src/tint/ast/alias.h
index f527d43..87ce578 100644
--- a/src/tint/ast/alias.h
+++ b/src/tint/ast/alias.h
@@ -23,28 +23,25 @@
 
 /// A type alias type. Holds a name and pointer to another type.
 class Alias final : public Castable<Alias, TypeDecl> {
- public:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  /// @param name the symbol for the alias
-  /// @param subtype the alias'd type
-  Alias(ProgramID pid,
-        const Source& src,
-        const Symbol& name,
-        const Type* subtype);
-  /// Move constructor
-  Alias(Alias&&);
-  /// Destructor
-  ~Alias() override;
+  public:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    /// @param name the symbol for the alias
+    /// @param subtype the alias'd type
+    Alias(ProgramID pid, const Source& src, const Symbol& name, const Type* subtype);
+    /// Move constructor
+    Alias(Alias&&);
+    /// Destructor
+    ~Alias() override;
 
-  /// Clones this type and all transitive types using the `CloneContext` `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned type
-  const Alias* Clone(CloneContext* ctx) const override;
+    /// Clones this type and all transitive types using the `CloneContext` `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned type
+    const Alias* Clone(CloneContext* ctx) const override;
 
-  /// the alias type
-  const Type* const type;
+    /// the alias type
+    const Type* const type;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/alias_test.cc b/src/tint/ast/alias_test.cc
index 6669e52..c734751 100644
--- a/src/tint/ast/alias_test.cc
+++ b/src/tint/ast/alias_test.cc
@@ -33,10 +33,10 @@
 using AstAliasTest = TestHelper;
 
 TEST_F(AstAliasTest, Create) {
-  auto* u32 = create<U32>();
-  auto* a = Alias("a_type", u32);
-  EXPECT_EQ(a->name, Symbol(1, ID()));
-  EXPECT_EQ(a->type, u32);
+    auto* u32 = create<U32>();
+    auto* a = Alias("a_type", u32);
+    EXPECT_EQ(a->name, Symbol(1, ID()));
+    EXPECT_EQ(a->type, u32);
 }
 
 }  // namespace
diff --git a/src/tint/ast/array.cc b/src/tint/ast/array.cc
index 58d8a45..0389ed0 100644
--- a/src/tint/ast/array.cc
+++ b/src/tint/ast/array.cc
@@ -24,17 +24,16 @@
 
 namespace {
 // Returns the string representation of an array size expression.
-std::string SizeExprToString(const Expression* size,
-                             const SymbolTable& symbols) {
-  if (auto* ident = size->As<IdentifierExpression>()) {
-    return symbols.NameFor(ident->symbol);
-  }
-  if (auto* literal = size->As<IntLiteralExpression>()) {
-    return std::to_string(literal->ValueAsU32());
-  }
-  // This will never be exposed to the user as the Resolver will reject this
-  // expression for array size.
-  return "<invalid>";
+std::string SizeExprToString(const Expression* size, const SymbolTable& symbols) {
+    if (auto* ident = size->As<IdentifierExpression>()) {
+        return symbols.NameFor(ident->symbol);
+    }
+    if (auto* literal = size->As<IntLiteralExpression>()) {
+        return std::to_string(literal->value);
+    }
+    // This will never be exposed to the user as the Resolver will reject this
+    // expression for array size.
+    return "<invalid>";
 }
 }  // namespace
 
@@ -50,27 +49,27 @@
 Array::~Array() = default;
 
 std::string Array::FriendlyName(const SymbolTable& symbols) const {
-  std::ostringstream out;
-  for (auto* attr : attributes) {
-    if (auto* stride = attr->As<ast::StrideAttribute>()) {
-      out << "@stride(" << stride->stride << ") ";
+    std::ostringstream out;
+    for (auto* attr : attributes) {
+        if (auto* stride = attr->As<ast::StrideAttribute>()) {
+            out << "@stride(" << stride->stride << ") ";
+        }
     }
-  }
-  out << "array<" << type->FriendlyName(symbols);
-  if (!IsRuntimeArray()) {
-    out << ", " << SizeExprToString(count, symbols);
-  }
-  out << ">";
-  return out.str();
+    out << "array<" << type->FriendlyName(symbols);
+    if (!IsRuntimeArray()) {
+        out << ", " << SizeExprToString(count, symbols);
+    }
+    out << ">";
+    return out.str();
 }
 
 const Array* Array::Clone(CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  auto* ty = ctx->Clone(type);
-  auto* cnt = ctx->Clone(count);
-  auto attrs = ctx->Clone(attributes);
-  return ctx->dst->create<Array>(src, ty, cnt, attrs);
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    auto* ty = ctx->Clone(type);
+    auto* cnt = ctx->Clone(count);
+    auto attrs = ctx->Clone(attributes);
+    return ctx->dst->create<Array>(src, ty, cnt, attrs);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/array.h b/src/tint/ast/array.h
index 0867c6d..e92902d 100644
--- a/src/tint/ast/array.h
+++ b/src/tint/ast/array.h
@@ -29,45 +29,45 @@
 
 /// An array type. If size is zero then it is a runtime array.
 class Array final : public Castable<Array, Type> {
- public:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  /// @param subtype the type of the array elements
-  /// @param count the number of elements in the array. nullptr represents a
-  /// runtime-sized array.
-  /// @param attributes the array attributes
-  Array(ProgramID pid,
-        const Source& src,
-        const Type* subtype,
-        const Expression* count,
-        AttributeList attributes);
-  /// Move constructor
-  Array(Array&&);
-  ~Array() override;
+  public:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    /// @param subtype the type of the array elements
+    /// @param count the number of elements in the array. nullptr represents a
+    /// runtime-sized array.
+    /// @param attributes the array attributes
+    Array(ProgramID pid,
+          const Source& src,
+          const Type* subtype,
+          const Expression* count,
+          AttributeList attributes);
+    /// Move constructor
+    Array(Array&&);
+    ~Array() override;
 
-  /// @returns true if this is a runtime array.
-  /// i.e. the size is determined at runtime
-  bool IsRuntimeArray() const { return count == nullptr; }
+    /// @returns true if this is a runtime array.
+    /// i.e. the size is determined at runtime
+    bool IsRuntimeArray() const { return count == nullptr; }
 
-  /// @param symbols the program's symbol table
-  /// @returns the name for this type that closely resembles how it would be
-  /// declared in WGSL.
-  std::string FriendlyName(const SymbolTable& symbols) const override;
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type that closely resembles how it would be
+    /// declared in WGSL.
+    std::string FriendlyName(const SymbolTable& symbols) const override;
 
-  /// Clones this type and all transitive types using the `CloneContext` `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned type
-  const Array* Clone(CloneContext* ctx) const override;
+    /// Clones this type and all transitive types using the `CloneContext` `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned type
+    const Array* Clone(CloneContext* ctx) const override;
 
-  /// the array element type
-  const Type* const type;
+    /// the array element type
+    const Type* const type;
 
-  /// the array size in elements, or nullptr for a runtime array
-  const Expression* const count;
+    /// the array size in elements, or nullptr for a runtime array
+    const Expression* const count;
 
-  /// the array attributes
-  const AttributeList attributes;
+    /// the array attributes
+    const AttributeList attributes;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/array_test.cc b/src/tint/ast/array_test.cc
index e255920..baed079 100644
--- a/src/tint/ast/array_test.cc
+++ b/src/tint/ast/array_test.cc
@@ -16,53 +16,54 @@
 
 #include "src/tint/ast/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::ast {
 namespace {
 
 using AstArrayTest = TestHelper;
 
 TEST_F(AstArrayTest, CreateSizedArray) {
-  auto* u32 = create<U32>();
-  auto* count = Expr(3);
-  auto* arr = create<Array>(u32, count, AttributeList{});
-  EXPECT_EQ(arr->type, u32);
-  EXPECT_EQ(arr->count, count);
-  EXPECT_TRUE(arr->Is<Array>());
-  EXPECT_FALSE(arr->IsRuntimeArray());
+    auto* u32 = create<U32>();
+    auto* count = Expr(3_u);
+    auto* arr = create<Array>(u32, count, AttributeList{});
+    EXPECT_EQ(arr->type, u32);
+    EXPECT_EQ(arr->count, count);
+    EXPECT_TRUE(arr->Is<Array>());
+    EXPECT_FALSE(arr->IsRuntimeArray());
 }
 
 TEST_F(AstArrayTest, CreateRuntimeArray) {
-  auto* u32 = create<U32>();
-  auto* arr = create<Array>(u32, nullptr, AttributeList{});
-  EXPECT_EQ(arr->type, u32);
-  EXPECT_EQ(arr->count, nullptr);
-  EXPECT_TRUE(arr->Is<Array>());
-  EXPECT_TRUE(arr->IsRuntimeArray());
+    auto* u32 = create<U32>();
+    auto* arr = create<Array>(u32, nullptr, AttributeList{});
+    EXPECT_EQ(arr->type, u32);
+    EXPECT_EQ(arr->count, nullptr);
+    EXPECT_TRUE(arr->Is<Array>());
+    EXPECT_TRUE(arr->IsRuntimeArray());
 }
 
 TEST_F(AstArrayTest, FriendlyName_RuntimeSized) {
-  auto* i32 = create<I32>();
-  auto* arr = create<Array>(i32, nullptr, AttributeList{});
-  EXPECT_EQ(arr->FriendlyName(Symbols()), "array<i32>");
+    auto* i32 = create<I32>();
+    auto* arr = create<Array>(i32, nullptr, AttributeList{});
+    EXPECT_EQ(arr->FriendlyName(Symbols()), "array<i32>");
 }
 
 TEST_F(AstArrayTest, FriendlyName_LiteralSized) {
-  auto* i32 = create<I32>();
-  auto* arr = create<Array>(i32, Expr(5), AttributeList{});
-  EXPECT_EQ(arr->FriendlyName(Symbols()), "array<i32, 5>");
+    auto* i32 = create<I32>();
+    auto* arr = create<Array>(i32, Expr(5_u), AttributeList{});
+    EXPECT_EQ(arr->FriendlyName(Symbols()), "array<i32, 5>");
 }
 
 TEST_F(AstArrayTest, FriendlyName_ConstantSized) {
-  auto* i32 = create<I32>();
-  auto* arr = create<Array>(i32, Expr("size"), AttributeList{});
-  EXPECT_EQ(arr->FriendlyName(Symbols()), "array<i32, size>");
+    auto* i32 = create<I32>();
+    auto* arr = create<Array>(i32, Expr("size"), AttributeList{});
+    EXPECT_EQ(arr->FriendlyName(Symbols()), "array<i32, size>");
 }
 
 TEST_F(AstArrayTest, FriendlyName_WithStride) {
-  auto* i32 = create<I32>();
-  auto* arr =
-      create<Array>(i32, Expr(5), AttributeList{create<StrideAttribute>(32)});
-  EXPECT_EQ(arr->FriendlyName(Symbols()), "@stride(32) array<i32, 5>");
+    auto* i32 = create<I32>();
+    auto* arr = create<Array>(i32, Expr(5_u), AttributeList{create<StrideAttribute>(32)});
+    EXPECT_EQ(arr->FriendlyName(Symbols()), "@stride(32) array<i32, 5>");
 }
 
 }  // namespace
diff --git a/src/tint/ast/assignment_statement.cc b/src/tint/ast/assignment_statement.cc
index 575e5d2..d7d7bc5 100644
--- a/src/tint/ast/assignment_statement.cc
+++ b/src/tint/ast/assignment_statement.cc
@@ -25,10 +25,10 @@
                                          const Expression* l,
                                          const Expression* r)
     : Base(pid, src), lhs(l), rhs(r) {
-  TINT_ASSERT(AST, lhs);
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, lhs, program_id);
-  TINT_ASSERT(AST, rhs);
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, rhs, program_id);
+    TINT_ASSERT(AST, lhs);
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, lhs, program_id);
+    TINT_ASSERT(AST, rhs);
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, rhs, program_id);
 }
 
 AssignmentStatement::AssignmentStatement(AssignmentStatement&&) = default;
@@ -36,11 +36,11 @@
 AssignmentStatement::~AssignmentStatement() = default;
 
 const AssignmentStatement* AssignmentStatement::Clone(CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  auto* l = ctx->Clone(lhs);
-  auto* r = ctx->Clone(rhs);
-  return ctx->dst->create<AssignmentStatement>(src, l, r);
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    auto* l = ctx->Clone(lhs);
+    auto* r = ctx->Clone(rhs);
+    return ctx->dst->create<AssignmentStatement>(src, l, r);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/assignment_statement.h b/src/tint/ast/assignment_statement.h
index 5fb8e3a..9def075 100644
--- a/src/tint/ast/assignment_statement.h
+++ b/src/tint/ast/assignment_statement.h
@@ -21,33 +21,32 @@
 namespace tint::ast {
 
 /// An assignment statement
-class AssignmentStatement final
-    : public Castable<AssignmentStatement, Statement> {
- public:
-  /// Constructor
-  /// @param program_id the identifier of the program that owns this node
-  /// @param source the assignment statement source
-  /// @param lhs the left side of the expression
-  /// @param rhs the right side of the expression
-  AssignmentStatement(ProgramID program_id,
-                      const Source& source,
-                      const Expression* lhs,
-                      const Expression* rhs);
-  /// Move constructor
-  AssignmentStatement(AssignmentStatement&&);
-  ~AssignmentStatement() override;
+class AssignmentStatement final : public Castable<AssignmentStatement, Statement> {
+  public:
+    /// Constructor
+    /// @param program_id the identifier of the program that owns this node
+    /// @param source the assignment statement source
+    /// @param lhs the left side of the expression
+    /// @param rhs the right side of the expression
+    AssignmentStatement(ProgramID program_id,
+                        const Source& source,
+                        const Expression* lhs,
+                        const Expression* rhs);
+    /// Move constructor
+    AssignmentStatement(AssignmentStatement&&);
+    ~AssignmentStatement() override;
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const AssignmentStatement* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const AssignmentStatement* Clone(CloneContext* ctx) const override;
 
-  /// left side expression
-  const Expression* const lhs;
+    /// left side expression
+    const Expression* const lhs;
 
-  /// right side expression
-  const Expression* const rhs;
+    /// right side expression
+    const Expression* const rhs;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/assignment_statement_test.cc b/src/tint/ast/assignment_statement_test.cc
index 39f8b83..477501b 100644
--- a/src/tint/ast/assignment_statement_test.cc
+++ b/src/tint/ast/assignment_statement_test.cc
@@ -17,75 +17,76 @@
 #include "gtest/gtest-spi.h"
 #include "src/tint/ast/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::ast {
 namespace {
 
 using AssignmentStatementTest = TestHelper;
 
 TEST_F(AssignmentStatementTest, Creation) {
-  auto* lhs = Expr("lhs");
-  auto* rhs = Expr("rhs");
+    auto* lhs = Expr("lhs");
+    auto* rhs = Expr("rhs");
 
-  auto* stmt = create<AssignmentStatement>(lhs, rhs);
-  EXPECT_EQ(stmt->lhs, lhs);
-  EXPECT_EQ(stmt->rhs, rhs);
+    auto* stmt = create<AssignmentStatement>(lhs, rhs);
+    EXPECT_EQ(stmt->lhs, lhs);
+    EXPECT_EQ(stmt->rhs, rhs);
 }
 
 TEST_F(AssignmentStatementTest, CreationWithSource) {
-  auto* lhs = Expr("lhs");
-  auto* rhs = Expr("rhs");
+    auto* lhs = Expr("lhs");
+    auto* rhs = Expr("rhs");
 
-  auto* stmt =
-      create<AssignmentStatement>(Source{Source::Location{20, 2}}, lhs, rhs);
-  auto src = stmt->source;
-  EXPECT_EQ(src.range.begin.line, 20u);
-  EXPECT_EQ(src.range.begin.column, 2u);
+    auto* stmt = create<AssignmentStatement>(Source{Source::Location{20, 2}}, lhs, rhs);
+    auto src = stmt->source;
+    EXPECT_EQ(src.range.begin.line, 20u);
+    EXPECT_EQ(src.range.begin.column, 2u);
 }
 
 TEST_F(AssignmentStatementTest, IsAssign) {
-  auto* lhs = Expr("lhs");
-  auto* rhs = Expr("rhs");
+    auto* lhs = Expr("lhs");
+    auto* rhs = Expr("rhs");
 
-  auto* stmt = create<AssignmentStatement>(lhs, rhs);
-  EXPECT_TRUE(stmt->Is<AssignmentStatement>());
+    auto* stmt = create<AssignmentStatement>(lhs, rhs);
+    EXPECT_TRUE(stmt->Is<AssignmentStatement>());
 }
 
 TEST_F(AssignmentStatementTest, Assert_Null_LHS) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.create<AssignmentStatement>(nullptr, b.Expr(1));
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.create<AssignmentStatement>(nullptr, b.Expr(1_i));
+        },
+        "internal compiler error");
 }
 
 TEST_F(AssignmentStatementTest, Assert_Null_RHS) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.create<AssignmentStatement>(b.Expr(1), nullptr);
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.create<AssignmentStatement>(b.Expr(1_i), nullptr);
+        },
+        "internal compiler error");
 }
 
 TEST_F(AssignmentStatementTest, Assert_DifferentProgramID_LHS) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.create<AssignmentStatement>(b2.Expr("lhs"), b1.Expr("rhs"));
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.create<AssignmentStatement>(b2.Expr("lhs"), b1.Expr("rhs"));
+        },
+        "internal compiler error");
 }
 
 TEST_F(AssignmentStatementTest, Assert_DifferentProgramID_RHS) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.create<AssignmentStatement>(b1.Expr("lhs"), b2.Expr("rhs"));
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.create<AssignmentStatement>(b1.Expr("lhs"), b2.Expr("rhs"));
+        },
+        "internal compiler error");
 }
 
 }  // namespace
diff --git a/src/tint/ast/atomic.cc b/src/tint/ast/atomic.cc
index 714dda4..ce7019b 100644
--- a/src/tint/ast/atomic.cc
+++ b/src/tint/ast/atomic.cc
@@ -24,9 +24,9 @@
     : Base(pid, src), type(subtype) {}
 
 std::string Atomic::FriendlyName(const SymbolTable& symbols) const {
-  std::ostringstream out;
-  out << "atomic<" << type->FriendlyName(symbols) << ">";
-  return out.str();
+    std::ostringstream out;
+    out << "atomic<" << type->FriendlyName(symbols) << ">";
+    return out.str();
 }
 
 Atomic::Atomic(Atomic&&) = default;
@@ -34,10 +34,10 @@
 Atomic::~Atomic() = default;
 
 const Atomic* Atomic::Clone(CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  auto* ty = ctx->Clone(type);
-  return ctx->dst->create<Atomic>(src, ty);
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    auto* ty = ctx->Clone(type);
+    return ctx->dst->create<Atomic>(src, ty);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/atomic.h b/src/tint/ast/atomic.h
index 734898f..5f63422 100644
--- a/src/tint/ast/atomic.h
+++ b/src/tint/ast/atomic.h
@@ -23,28 +23,28 @@
 
 /// An atomic type.
 class Atomic final : public Castable<Atomic, Type> {
- public:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  /// @param subtype the pointee type
-  Atomic(ProgramID pid, const Source& src, const Type* const subtype);
-  /// Move constructor
-  Atomic(Atomic&&);
-  ~Atomic() override;
+  public:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    /// @param subtype the pointee type
+    Atomic(ProgramID pid, const Source& src, const Type* const subtype);
+    /// Move constructor
+    Atomic(Atomic&&);
+    ~Atomic() override;
 
-  /// @param symbols the program's symbol table
-  /// @returns the name for this type that closely resembles how it would be
-  /// declared in WGSL.
-  std::string FriendlyName(const SymbolTable& symbols) const override;
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type that closely resembles how it would be
+    /// declared in WGSL.
+    std::string FriendlyName(const SymbolTable& symbols) const override;
 
-  /// Clones this type and all transitive types using the `CloneContext` `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned type
-  const Atomic* Clone(CloneContext* ctx) const override;
+    /// Clones this type and all transitive types using the `CloneContext` `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned type
+    const Atomic* Clone(CloneContext* ctx) const override;
 
-  /// the pointee type
-  const Type* const type;
+    /// the pointee type
+    const Type* const type;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/atomic_test.cc b/src/tint/ast/atomic_test.cc
index cd192c1..2b0ada9 100644
--- a/src/tint/ast/atomic_test.cc
+++ b/src/tint/ast/atomic_test.cc
@@ -23,15 +23,15 @@
 using AstAtomicTest = TestHelper;
 
 TEST_F(AstAtomicTest, Creation) {
-  auto* i32 = create<I32>();
-  auto* p = create<Atomic>(i32);
-  EXPECT_EQ(p->type, i32);
+    auto* i32 = create<I32>();
+    auto* p = create<Atomic>(i32);
+    EXPECT_EQ(p->type, i32);
 }
 
 TEST_F(AstAtomicTest, FriendlyName) {
-  auto* i32 = create<I32>();
-  auto* p = create<Atomic>(i32);
-  EXPECT_EQ(p->FriendlyName(Symbols()), "atomic<i32>");
+    auto* i32 = create<I32>();
+    auto* p = create<Atomic>(i32);
+    EXPECT_EQ(p->FriendlyName(Symbols()), "atomic<i32>");
 }
 
 }  // namespace
diff --git a/src/tint/ast/attribute.h b/src/tint/ast/attribute.h
index b5c0ffc..cb9bf76 100644
--- a/src/tint/ast/attribute.h
+++ b/src/tint/ast/attribute.h
@@ -24,17 +24,17 @@
 
 /// The base class for all attributes
 class Attribute : public Castable<Attribute, Node> {
- public:
-  ~Attribute() override;
+  public:
+    ~Attribute() override;
 
-  /// @returns the WGSL name for the attribute
-  virtual std::string Name() const = 0;
+    /// @returns the WGSL name for the attribute
+    virtual std::string Name() const = 0;
 
- protected:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  Attribute(ProgramID pid, const Source& src) : Base(pid, src) {}
+  protected:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    Attribute(ProgramID pid, const Source& src) : Base(pid, src) {}
 };
 
 /// A list of attributes
@@ -44,24 +44,24 @@
 /// @returns true if `attributes` includes a attribute of type `T`
 template <typename T>
 bool HasAttribute(const AttributeList& attributes) {
-  for (auto* attr : attributes) {
-    if (attr->Is<T>()) {
-      return true;
+    for (auto* attr : attributes) {
+        if (attr->Is<T>()) {
+            return true;
+        }
     }
-  }
-  return false;
+    return false;
 }
 
 /// @param attributes the list of attributes to search
 /// @returns a pointer to `T` from `attributes` if found, otherwise nullptr.
 template <typename T>
 const T* GetAttribute(const AttributeList& attributes) {
-  for (auto* attr : attributes) {
-    if (attr->Is<T>()) {
-      return attr->As<T>();
+    for (auto* attr : attributes) {
+        if (attr->Is<T>()) {
+            return attr->As<T>();
+        }
     }
-  }
-  return nullptr;
+    return nullptr;
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/binary_expression.cc b/src/tint/ast/binary_expression.cc
index 6d67851..e3ccd8b 100644
--- a/src/tint/ast/binary_expression.cc
+++ b/src/tint/ast/binary_expression.cc
@@ -26,11 +26,11 @@
                                    const Expression* l,
                                    const Expression* r)
     : Base(pid, src), op(o), lhs(l), rhs(r) {
-  TINT_ASSERT(AST, lhs);
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, lhs, program_id);
-  TINT_ASSERT(AST, rhs);
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, rhs, program_id);
-  TINT_ASSERT(AST, op != BinaryOp::kNone);
+    TINT_ASSERT(AST, lhs);
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, lhs, program_id);
+    TINT_ASSERT(AST, rhs);
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, rhs, program_id);
+    TINT_ASSERT(AST, op != BinaryOp::kNone);
 }
 
 BinaryExpression::BinaryExpression(BinaryExpression&&) = default;
@@ -38,11 +38,11 @@
 BinaryExpression::~BinaryExpression() = default;
 
 const BinaryExpression* BinaryExpression::Clone(CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  auto* l = ctx->Clone(lhs);
-  auto* r = ctx->Clone(rhs);
-  return ctx->dst->create<BinaryExpression>(src, op, l, r);
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    auto* l = ctx->Clone(lhs);
+    auto* r = ctx->Clone(rhs);
+    return ctx->dst->create<BinaryExpression>(src, op, l, r);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/binary_expression.h b/src/tint/ast/binary_expression.h
index ab3f6be..ad59da4 100644
--- a/src/tint/ast/binary_expression.h
+++ b/src/tint/ast/binary_expression.h
@@ -21,240 +21,240 @@
 
 /// The operator type
 enum class BinaryOp {
-  kNone = 0,
-  kAnd,  // &
-  kOr,   // |
-  kXor,
-  kLogicalAnd,  // &&
-  kLogicalOr,   // ||
-  kEqual,
-  kNotEqual,
-  kLessThan,
-  kGreaterThan,
-  kLessThanEqual,
-  kGreaterThanEqual,
-  kShiftLeft,
-  kShiftRight,
-  kAdd,
-  kSubtract,
-  kMultiply,
-  kDivide,
-  kModulo,
+    kNone = 0,
+    kAnd,  // &
+    kOr,   // |
+    kXor,
+    kLogicalAnd,  // &&
+    kLogicalOr,   // ||
+    kEqual,
+    kNotEqual,
+    kLessThan,
+    kGreaterThan,
+    kLessThanEqual,
+    kGreaterThanEqual,
+    kShiftLeft,
+    kShiftRight,
+    kAdd,
+    kSubtract,
+    kMultiply,
+    kDivide,
+    kModulo,
 };
 
 /// An binary expression
 class BinaryExpression final : public Castable<BinaryExpression, Expression> {
- public:
-  /// Constructor
-  /// @param program_id the identifier of the program that owns this node
-  /// @param source the binary expression source
-  /// @param op the operation type
-  /// @param lhs the left side of the expression
-  /// @param rhs the right side of the expression
-  BinaryExpression(ProgramID program_id,
-                   const Source& source,
-                   BinaryOp op,
-                   const Expression* lhs,
-                   const Expression* rhs);
-  /// Move constructor
-  BinaryExpression(BinaryExpression&&);
-  ~BinaryExpression() override;
+  public:
+    /// Constructor
+    /// @param program_id the identifier of the program that owns this node
+    /// @param source the binary expression source
+    /// @param op the operation type
+    /// @param lhs the left side of the expression
+    /// @param rhs the right side of the expression
+    BinaryExpression(ProgramID program_id,
+                     const Source& source,
+                     BinaryOp op,
+                     const Expression* lhs,
+                     const Expression* rhs);
+    /// Move constructor
+    BinaryExpression(BinaryExpression&&);
+    ~BinaryExpression() override;
 
-  /// @returns true if the op is and
-  bool IsAnd() const { return op == BinaryOp::kAnd; }
-  /// @returns true if the op is or
-  bool IsOr() const { return op == BinaryOp::kOr; }
-  /// @returns true if the op is xor
-  bool IsXor() const { return op == BinaryOp::kXor; }
-  /// @returns true if the op is logical and
-  bool IsLogicalAnd() const { return op == BinaryOp::kLogicalAnd; }
-  /// @returns true if the op is logical or
-  bool IsLogicalOr() const { return op == BinaryOp::kLogicalOr; }
-  /// @returns true if the op is equal
-  bool IsEqual() const { return op == BinaryOp::kEqual; }
-  /// @returns true if the op is not equal
-  bool IsNotEqual() const { return op == BinaryOp::kNotEqual; }
-  /// @returns true if the op is less than
-  bool IsLessThan() const { return op == BinaryOp::kLessThan; }
-  /// @returns true if the op is greater than
-  bool IsGreaterThan() const { return op == BinaryOp::kGreaterThan; }
-  /// @returns true if the op is less than equal
-  bool IsLessThanEqual() const { return op == BinaryOp::kLessThanEqual; }
-  /// @returns true if the op is greater than equal
-  bool IsGreaterThanEqual() const { return op == BinaryOp::kGreaterThanEqual; }
-  /// @returns true if the op is shift left
-  bool IsShiftLeft() const { return op == BinaryOp::kShiftLeft; }
-  /// @returns true if the op is shift right
-  bool IsShiftRight() const { return op == BinaryOp::kShiftRight; }
-  /// @returns true if the op is add
-  bool IsAdd() const { return op == BinaryOp::kAdd; }
-  /// @returns true if the op is subtract
-  bool IsSubtract() const { return op == BinaryOp::kSubtract; }
-  /// @returns true if the op is multiply
-  bool IsMultiply() const { return op == BinaryOp::kMultiply; }
-  /// @returns true if the op is divide
-  bool IsDivide() const { return op == BinaryOp::kDivide; }
-  /// @returns true if the op is modulo
-  bool IsModulo() const { return op == BinaryOp::kModulo; }
-  /// @returns true if the op is an arithmetic operation
-  bool IsArithmetic() const;
-  /// @returns true if the op is a comparison operation
-  bool IsComparison() const;
-  /// @returns true if the op is a bitwise operation
-  bool IsBitwise() const;
-  /// @returns true if the op is a bit shift operation
-  bool IsBitshift() const;
-  /// @returns true if the op is a logical expression
-  bool IsLogical() const;
+    /// @returns true if the op is and
+    bool IsAnd() const { return op == BinaryOp::kAnd; }
+    /// @returns true if the op is or
+    bool IsOr() const { return op == BinaryOp::kOr; }
+    /// @returns true if the op is xor
+    bool IsXor() const { return op == BinaryOp::kXor; }
+    /// @returns true if the op is logical and
+    bool IsLogicalAnd() const { return op == BinaryOp::kLogicalAnd; }
+    /// @returns true if the op is logical or
+    bool IsLogicalOr() const { return op == BinaryOp::kLogicalOr; }
+    /// @returns true if the op is equal
+    bool IsEqual() const { return op == BinaryOp::kEqual; }
+    /// @returns true if the op is not equal
+    bool IsNotEqual() const { return op == BinaryOp::kNotEqual; }
+    /// @returns true if the op is less than
+    bool IsLessThan() const { return op == BinaryOp::kLessThan; }
+    /// @returns true if the op is greater than
+    bool IsGreaterThan() const { return op == BinaryOp::kGreaterThan; }
+    /// @returns true if the op is less than equal
+    bool IsLessThanEqual() const { return op == BinaryOp::kLessThanEqual; }
+    /// @returns true if the op is greater than equal
+    bool IsGreaterThanEqual() const { return op == BinaryOp::kGreaterThanEqual; }
+    /// @returns true if the op is shift left
+    bool IsShiftLeft() const { return op == BinaryOp::kShiftLeft; }
+    /// @returns true if the op is shift right
+    bool IsShiftRight() const { return op == BinaryOp::kShiftRight; }
+    /// @returns true if the op is add
+    bool IsAdd() const { return op == BinaryOp::kAdd; }
+    /// @returns true if the op is subtract
+    bool IsSubtract() const { return op == BinaryOp::kSubtract; }
+    /// @returns true if the op is multiply
+    bool IsMultiply() const { return op == BinaryOp::kMultiply; }
+    /// @returns true if the op is divide
+    bool IsDivide() const { return op == BinaryOp::kDivide; }
+    /// @returns true if the op is modulo
+    bool IsModulo() const { return op == BinaryOp::kModulo; }
+    /// @returns true if the op is an arithmetic operation
+    bool IsArithmetic() const;
+    /// @returns true if the op is a comparison operation
+    bool IsComparison() const;
+    /// @returns true if the op is a bitwise operation
+    bool IsBitwise() const;
+    /// @returns true if the op is a bit shift operation
+    bool IsBitshift() const;
+    /// @returns true if the op is a logical expression
+    bool IsLogical() const;
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const BinaryExpression* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const BinaryExpression* Clone(CloneContext* ctx) const override;
 
-  /// the binary op type
-  const BinaryOp op;
-  /// the left side expression
-  const Expression* const lhs;
-  /// the right side expression
-  const Expression* const rhs;
+    /// the binary op type
+    const BinaryOp op;
+    /// the left side expression
+    const Expression* const lhs;
+    /// the right side expression
+    const Expression* const rhs;
 };
 
 /// @param op the operator
 /// @returns true if the op is an arithmetic operation
 inline bool IsArithmetic(BinaryOp op) {
-  switch (op) {
-    case ast::BinaryOp::kAdd:
-    case ast::BinaryOp::kSubtract:
-    case ast::BinaryOp::kMultiply:
-    case ast::BinaryOp::kDivide:
-    case ast::BinaryOp::kModulo:
-      return true;
-    default:
-      return false;
-  }
+    switch (op) {
+        case ast::BinaryOp::kAdd:
+        case ast::BinaryOp::kSubtract:
+        case ast::BinaryOp::kMultiply:
+        case ast::BinaryOp::kDivide:
+        case ast::BinaryOp::kModulo:
+            return true;
+        default:
+            return false;
+    }
 }
 
 /// @param op the operator
 /// @returns true if the op is a comparison operation
 inline bool IsComparison(BinaryOp op) {
-  switch (op) {
-    case ast::BinaryOp::kEqual:
-    case ast::BinaryOp::kNotEqual:
-    case ast::BinaryOp::kLessThan:
-    case ast::BinaryOp::kLessThanEqual:
-    case ast::BinaryOp::kGreaterThan:
-    case ast::BinaryOp::kGreaterThanEqual:
-      return true;
-    default:
-      return false;
-  }
+    switch (op) {
+        case ast::BinaryOp::kEqual:
+        case ast::BinaryOp::kNotEqual:
+        case ast::BinaryOp::kLessThan:
+        case ast::BinaryOp::kLessThanEqual:
+        case ast::BinaryOp::kGreaterThan:
+        case ast::BinaryOp::kGreaterThanEqual:
+            return true;
+        default:
+            return false;
+    }
 }
 
 /// @param op the operator
 /// @returns true if the op is a bitwise operation
 inline bool IsBitwise(BinaryOp op) {
-  switch (op) {
-    case ast::BinaryOp::kAnd:
-    case ast::BinaryOp::kOr:
-    case ast::BinaryOp::kXor:
-      return true;
-    default:
-      return false;
-  }
+    switch (op) {
+        case ast::BinaryOp::kAnd:
+        case ast::BinaryOp::kOr:
+        case ast::BinaryOp::kXor:
+            return true;
+        default:
+            return false;
+    }
 }
 
 /// @param op the operator
 /// @returns true if the op is a bit shift operation
 inline bool IsBitshift(BinaryOp op) {
-  switch (op) {
-    case ast::BinaryOp::kShiftLeft:
-    case ast::BinaryOp::kShiftRight:
-      return true;
-    default:
-      return false;
-  }
+    switch (op) {
+        case ast::BinaryOp::kShiftLeft:
+        case ast::BinaryOp::kShiftRight:
+            return true;
+        default:
+            return false;
+    }
 }
 
 inline bool BinaryExpression::IsLogical() const {
-  switch (op) {
-    case ast::BinaryOp::kLogicalAnd:
-    case ast::BinaryOp::kLogicalOr:
-      return true;
-    default:
-      return false;
-  }
+    switch (op) {
+        case ast::BinaryOp::kLogicalAnd:
+        case ast::BinaryOp::kLogicalOr:
+            return true;
+        default:
+            return false;
+    }
 }
 
 inline bool BinaryExpression::IsArithmetic() const {
-  return ast::IsArithmetic(op);
+    return ast::IsArithmetic(op);
 }
 
 inline bool BinaryExpression::IsComparison() const {
-  return ast::IsComparison(op);
+    return ast::IsComparison(op);
 }
 
 inline bool BinaryExpression::IsBitwise() const {
-  return ast::IsBitwise(op);
+    return ast::IsBitwise(op);
 }
 
 inline bool BinaryExpression::IsBitshift() const {
-  return ast::IsBitshift(op);
+    return ast::IsBitshift(op);
 }
 
 /// @returns the human readable name of the given BinaryOp
 /// @param op the BinaryOp
 constexpr const char* FriendlyName(BinaryOp op) {
-  switch (op) {
-    case BinaryOp::kNone:
-      return "none";
-    case BinaryOp::kAnd:
-      return "and";
-    case BinaryOp::kOr:
-      return "or";
-    case BinaryOp::kXor:
-      return "xor";
-    case BinaryOp::kLogicalAnd:
-      return "logical_and";
-    case BinaryOp::kLogicalOr:
-      return "logical_or";
-    case BinaryOp::kEqual:
-      return "equal";
-    case BinaryOp::kNotEqual:
-      return "not_equal";
-    case BinaryOp::kLessThan:
-      return "less_than";
-    case BinaryOp::kGreaterThan:
-      return "greater_than";
-    case BinaryOp::kLessThanEqual:
-      return "less_than_equal";
-    case BinaryOp::kGreaterThanEqual:
-      return "greater_than_equal";
-    case BinaryOp::kShiftLeft:
-      return "shift_left";
-    case BinaryOp::kShiftRight:
-      return "shift_right";
-    case BinaryOp::kAdd:
-      return "add";
-    case BinaryOp::kSubtract:
-      return "subtract";
-    case BinaryOp::kMultiply:
-      return "multiply";
-    case BinaryOp::kDivide:
-      return "divide";
-    case BinaryOp::kModulo:
-      return "modulo";
-  }
-  return "INVALID";
+    switch (op) {
+        case BinaryOp::kNone:
+            return "none";
+        case BinaryOp::kAnd:
+            return "and";
+        case BinaryOp::kOr:
+            return "or";
+        case BinaryOp::kXor:
+            return "xor";
+        case BinaryOp::kLogicalAnd:
+            return "logical_and";
+        case BinaryOp::kLogicalOr:
+            return "logical_or";
+        case BinaryOp::kEqual:
+            return "equal";
+        case BinaryOp::kNotEqual:
+            return "not_equal";
+        case BinaryOp::kLessThan:
+            return "less_than";
+        case BinaryOp::kGreaterThan:
+            return "greater_than";
+        case BinaryOp::kLessThanEqual:
+            return "less_than_equal";
+        case BinaryOp::kGreaterThanEqual:
+            return "greater_than_equal";
+        case BinaryOp::kShiftLeft:
+            return "shift_left";
+        case BinaryOp::kShiftRight:
+            return "shift_right";
+        case BinaryOp::kAdd:
+            return "add";
+        case BinaryOp::kSubtract:
+            return "subtract";
+        case BinaryOp::kMultiply:
+            return "multiply";
+        case BinaryOp::kDivide:
+            return "divide";
+        case BinaryOp::kModulo:
+            return "modulo";
+    }
+    return "INVALID";
 }
 
 /// @param out the std::ostream to write to
 /// @param op the BinaryOp
 /// @return the std::ostream so calls can be chained
 inline std::ostream& operator<<(std::ostream& out, BinaryOp op) {
-  out << FriendlyName(op);
-  return out;
+    out << FriendlyName(op);
+    return out;
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/binary_expression_test.cc b/src/tint/ast/binary_expression_test.cc
index 5bec07b..18ded61 100644
--- a/src/tint/ast/binary_expression_test.cc
+++ b/src/tint/ast/binary_expression_test.cc
@@ -21,72 +21,69 @@
 using BinaryExpressionTest = TestHelper;
 
 TEST_F(BinaryExpressionTest, Creation) {
-  auto* lhs = Expr("lhs");
-  auto* rhs = Expr("rhs");
+    auto* lhs = Expr("lhs");
+    auto* rhs = Expr("rhs");
 
-  auto* r = create<BinaryExpression>(BinaryOp::kEqual, lhs, rhs);
-  EXPECT_EQ(r->lhs, lhs);
-  EXPECT_EQ(r->rhs, rhs);
-  EXPECT_EQ(r->op, BinaryOp::kEqual);
+    auto* r = create<BinaryExpression>(BinaryOp::kEqual, lhs, rhs);
+    EXPECT_EQ(r->lhs, lhs);
+    EXPECT_EQ(r->rhs, rhs);
+    EXPECT_EQ(r->op, BinaryOp::kEqual);
 }
 
 TEST_F(BinaryExpressionTest, Creation_WithSource) {
-  auto* lhs = Expr("lhs");
-  auto* rhs = Expr("rhs");
+    auto* lhs = Expr("lhs");
+    auto* rhs = Expr("rhs");
 
-  auto* r = create<BinaryExpression>(Source{Source::Location{20, 2}},
-                                     BinaryOp::kEqual, lhs, rhs);
-  auto src = r->source;
-  EXPECT_EQ(src.range.begin.line, 20u);
-  EXPECT_EQ(src.range.begin.column, 2u);
+    auto* r = create<BinaryExpression>(Source{Source::Location{20, 2}}, BinaryOp::kEqual, lhs, rhs);
+    auto src = r->source;
+    EXPECT_EQ(src.range.begin.line, 20u);
+    EXPECT_EQ(src.range.begin.column, 2u);
 }
 
 TEST_F(BinaryExpressionTest, IsBinary) {
-  auto* lhs = Expr("lhs");
-  auto* rhs = Expr("rhs");
+    auto* lhs = Expr("lhs");
+    auto* rhs = Expr("rhs");
 
-  auto* r = create<BinaryExpression>(BinaryOp::kEqual, lhs, rhs);
-  EXPECT_TRUE(r->Is<BinaryExpression>());
+    auto* r = create<BinaryExpression>(BinaryOp::kEqual, lhs, rhs);
+    EXPECT_TRUE(r->Is<BinaryExpression>());
 }
 
 TEST_F(BinaryExpressionTest, Assert_Null_LHS) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.create<BinaryExpression>(BinaryOp::kEqual, nullptr, b.Expr("rhs"));
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.create<BinaryExpression>(BinaryOp::kEqual, nullptr, b.Expr("rhs"));
+        },
+        "internal compiler error");
 }
 
 TEST_F(BinaryExpressionTest, Assert_Null_RHS) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.create<BinaryExpression>(BinaryOp::kEqual, b.Expr("lhs"), nullptr);
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.create<BinaryExpression>(BinaryOp::kEqual, b.Expr("lhs"), nullptr);
+        },
+        "internal compiler error");
 }
 
 TEST_F(BinaryExpressionTest, Assert_DifferentProgramID_LHS) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.create<BinaryExpression>(BinaryOp::kEqual, b2.Expr("lhs"),
-                                    b1.Expr("rhs"));
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.create<BinaryExpression>(BinaryOp::kEqual, b2.Expr("lhs"), b1.Expr("rhs"));
+        },
+        "internal compiler error");
 }
 
 TEST_F(BinaryExpressionTest, Assert_DifferentProgramID_RHS) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.create<BinaryExpression>(BinaryOp::kEqual, b1.Expr("lhs"),
-                                    b2.Expr("rhs"));
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.create<BinaryExpression>(BinaryOp::kEqual, b1.Expr("lhs"), b2.Expr("rhs"));
+        },
+        "internal compiler error");
 }
 
 }  // namespace
diff --git a/src/tint/ast/binding_attribute.cc b/src/tint/ast/binding_attribute.cc
index 2fdfe20..b9282f2 100644
--- a/src/tint/ast/binding_attribute.cc
+++ b/src/tint/ast/binding_attribute.cc
@@ -22,21 +22,19 @@
 
 namespace tint::ast {
 
-BindingAttribute::BindingAttribute(ProgramID pid,
-                                   const Source& src,
-                                   uint32_t val)
+BindingAttribute::BindingAttribute(ProgramID pid, const Source& src, uint32_t val)
     : Base(pid, src), value(val) {}
 
 BindingAttribute::~BindingAttribute() = default;
 
 std::string BindingAttribute::Name() const {
-  return "binding";
+    return "binding";
 }
 
 const BindingAttribute* BindingAttribute::Clone(CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  return ctx->dst->create<BindingAttribute>(src, value);
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    return ctx->dst->create<BindingAttribute>(src, value);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/binding_attribute.h b/src/tint/ast/binding_attribute.h
index 6ae6a0e..33c5f69 100644
--- a/src/tint/ast/binding_attribute.h
+++ b/src/tint/ast/binding_attribute.h
@@ -23,25 +23,25 @@
 
 /// A binding attribute
 class BindingAttribute final : public Castable<BindingAttribute, Attribute> {
- public:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  /// @param value the binding value
-  BindingAttribute(ProgramID pid, const Source& src, uint32_t value);
-  ~BindingAttribute() override;
+  public:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    /// @param value the binding value
+    BindingAttribute(ProgramID pid, const Source& src, uint32_t value);
+    ~BindingAttribute() override;
 
-  /// @returns the WGSL name for the attribute
-  std::string Name() const override;
+    /// @returns the WGSL name for the attribute
+    std::string Name() const override;
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const BindingAttribute* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const BindingAttribute* Clone(CloneContext* ctx) const override;
 
-  /// the binding value
-  const uint32_t value;
+    /// the binding value
+    const uint32_t value;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/binding_attribute_test.cc b/src/tint/ast/binding_attribute_test.cc
index 8515651..f51fc25 100644
--- a/src/tint/ast/binding_attribute_test.cc
+++ b/src/tint/ast/binding_attribute_test.cc
@@ -20,8 +20,8 @@
 using BindingAttributeTest = TestHelper;
 
 TEST_F(BindingAttributeTest, Creation) {
-  auto* d = create<BindingAttribute>(2);
-  EXPECT_EQ(2u, d->value);
+    auto* d = create<BindingAttribute>(2);
+    EXPECT_EQ(2u, d->value);
 }
 
 }  // namespace
diff --git a/src/tint/ast/bitcast_expression.cc b/src/tint/ast/bitcast_expression.cc
index 9626c47..a81c5dd 100644
--- a/src/tint/ast/bitcast_expression.cc
+++ b/src/tint/ast/bitcast_expression.cc
@@ -25,20 +25,20 @@
                                      const Type* t,
                                      const Expression* e)
     : Base(pid, src), type(t), expr(e) {
-  TINT_ASSERT(AST, type);
-  TINT_ASSERT(AST, expr);
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, expr, program_id);
+    TINT_ASSERT(AST, type);
+    TINT_ASSERT(AST, expr);
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, expr, program_id);
 }
 
 BitcastExpression::BitcastExpression(BitcastExpression&&) = default;
 BitcastExpression::~BitcastExpression() = default;
 
 const BitcastExpression* BitcastExpression::Clone(CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  auto* t = ctx->Clone(type);
-  auto* e = ctx->Clone(expr);
-  return ctx->dst->create<BitcastExpression>(src, t, e);
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    auto* t = ctx->Clone(type);
+    auto* e = ctx->Clone(expr);
+    return ctx->dst->create<BitcastExpression>(src, t, e);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/bitcast_expression.h b/src/tint/ast/bitcast_expression.h
index 8eacf71..a231cd2 100644
--- a/src/tint/ast/bitcast_expression.h
+++ b/src/tint/ast/bitcast_expression.h
@@ -26,30 +26,30 @@
 
 /// A bitcast expression
 class BitcastExpression final : public Castable<BitcastExpression, Expression> {
- public:
-  /// Constructor
-  /// @param program_id the identifier of the program that owns this node
-  /// @param source the bitcast expression source
-  /// @param type the type
-  /// @param expr the expr
-  BitcastExpression(ProgramID program_id,
-                    const Source& source,
-                    const Type* type,
-                    const Expression* expr);
-  /// Move constructor
-  BitcastExpression(BitcastExpression&&);
-  ~BitcastExpression() override;
+  public:
+    /// Constructor
+    /// @param program_id the identifier of the program that owns this node
+    /// @param source the bitcast expression source
+    /// @param type the type
+    /// @param expr the expr
+    BitcastExpression(ProgramID program_id,
+                      const Source& source,
+                      const Type* type,
+                      const Expression* expr);
+    /// Move constructor
+    BitcastExpression(BitcastExpression&&);
+    ~BitcastExpression() override;
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const BitcastExpression* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const BitcastExpression* Clone(CloneContext* ctx) const override;
 
-  /// the target cast type
-  const Type* const type;
-  /// the expression
-  const Expression* const expr;
+    /// the target cast type
+    const Type* const type;
+    /// the expression
+    const Expression* const expr;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/bitcast_expression_test.cc b/src/tint/ast/bitcast_expression_test.cc
index 170d765..7478456 100644
--- a/src/tint/ast/bitcast_expression_test.cc
+++ b/src/tint/ast/bitcast_expression_test.cc
@@ -23,56 +23,55 @@
 using BitcastExpressionTest = TestHelper;
 
 TEST_F(BitcastExpressionTest, Create) {
-  auto* expr = Expr("expr");
+    auto* expr = Expr("expr");
 
-  auto* exp = create<BitcastExpression>(ty.f32(), expr);
-  EXPECT_TRUE(exp->type->Is<ast::F32>());
-  ASSERT_EQ(exp->expr, expr);
+    auto* exp = create<BitcastExpression>(ty.f32(), expr);
+    EXPECT_TRUE(exp->type->Is<ast::F32>());
+    ASSERT_EQ(exp->expr, expr);
 }
 
 TEST_F(BitcastExpressionTest, CreateWithSource) {
-  auto* expr = Expr("expr");
+    auto* expr = Expr("expr");
 
-  auto* exp = create<BitcastExpression>(Source{Source::Location{20, 2}},
-                                        ty.f32(), expr);
-  auto src = exp->source;
-  EXPECT_EQ(src.range.begin.line, 20u);
-  EXPECT_EQ(src.range.begin.column, 2u);
+    auto* exp = create<BitcastExpression>(Source{Source::Location{20, 2}}, ty.f32(), expr);
+    auto src = exp->source;
+    EXPECT_EQ(src.range.begin.line, 20u);
+    EXPECT_EQ(src.range.begin.column, 2u);
 }
 
 TEST_F(BitcastExpressionTest, IsBitcast) {
-  auto* expr = Expr("expr");
+    auto* expr = Expr("expr");
 
-  auto* exp = create<BitcastExpression>(ty.f32(), expr);
-  EXPECT_TRUE(exp->Is<BitcastExpression>());
+    auto* exp = create<BitcastExpression>(ty.f32(), expr);
+    EXPECT_TRUE(exp->Is<BitcastExpression>());
 }
 
 TEST_F(BitcastExpressionTest, Assert_Null_Type) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.create<BitcastExpression>(nullptr, b.Expr("idx"));
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.create<BitcastExpression>(nullptr, b.Expr("idx"));
+        },
+        "internal compiler error");
 }
 
 TEST_F(BitcastExpressionTest, Assert_Null_Expr) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.create<BitcastExpression>(b.ty.f32(), nullptr);
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.create<BitcastExpression>(b.ty.f32(), nullptr);
+        },
+        "internal compiler error");
 }
 
 TEST_F(BitcastExpressionTest, Assert_DifferentProgramID_Expr) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.create<BitcastExpression>(b1.ty.f32(), b2.Expr("idx"));
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.create<BitcastExpression>(b1.ty.f32(), b2.Expr("idx"));
+        },
+        "internal compiler error");
 }
 
 }  // namespace
diff --git a/src/tint/ast/block_statement.cc b/src/tint/ast/block_statement.cc
index 4368e24..7d4f492 100644
--- a/src/tint/ast/block_statement.cc
+++ b/src/tint/ast/block_statement.cc
@@ -20,14 +20,12 @@
 
 namespace tint::ast {
 
-BlockStatement::BlockStatement(ProgramID pid,
-                               const Source& src,
-                               const StatementList& stmts)
+BlockStatement::BlockStatement(ProgramID pid, const Source& src, const StatementList& stmts)
     : Base(pid, src), statements(std::move(stmts)) {
-  for (auto* stmt : statements) {
-    TINT_ASSERT(AST, stmt);
-    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, stmt, program_id);
-  }
+    for (auto* stmt : statements) {
+        TINT_ASSERT(AST, stmt);
+        TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, stmt, program_id);
+    }
 }
 
 BlockStatement::BlockStatement(BlockStatement&&) = default;
@@ -35,10 +33,10 @@
 BlockStatement::~BlockStatement() = default;
 
 const BlockStatement* BlockStatement::Clone(CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  auto stmts = ctx->Clone(statements);
-  return ctx->dst->create<BlockStatement>(src, stmts);
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    auto stmts = ctx->Clone(statements);
+    return ctx->dst->create<BlockStatement>(src, stmts);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/block_statement.h b/src/tint/ast/block_statement.h
index 2afce5e..48ea35a 100644
--- a/src/tint/ast/block_statement.h
+++ b/src/tint/ast/block_statement.h
@@ -23,34 +23,30 @@
 
 /// A block statement
 class BlockStatement final : public Castable<BlockStatement, Statement> {
- public:
-  /// Constructor
-  /// @param program_id the identifier of the program that owns this node
-  /// @param source the block statement source
-  /// @param statements the statements
-  BlockStatement(ProgramID program_id,
-                 const Source& source,
-                 const StatementList& statements);
-  /// Move constructor
-  BlockStatement(BlockStatement&&);
-  ~BlockStatement() override;
+  public:
+    /// Constructor
+    /// @param program_id the identifier of the program that owns this node
+    /// @param source the block statement source
+    /// @param statements the statements
+    BlockStatement(ProgramID program_id, const Source& source, const StatementList& statements);
+    /// Move constructor
+    BlockStatement(BlockStatement&&);
+    ~BlockStatement() override;
 
-  /// @returns true if the block has no statements
-  bool Empty() const { return statements.empty(); }
+    /// @returns true if the block has no statements
+    bool Empty() const { return statements.empty(); }
 
-  /// @returns the last statement in the block or nullptr if block empty
-  const Statement* Last() const {
-    return statements.empty() ? nullptr : statements.back();
-  }
+    /// @returns the last statement in the block or nullptr if block empty
+    const Statement* Last() const { return statements.empty() ? nullptr : statements.back(); }
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const BlockStatement* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const BlockStatement* Clone(CloneContext* ctx) const override;
 
-  /// the statement list
-  const StatementList statements;
+    /// the statement list
+    const StatementList statements;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/block_statement_test.cc b/src/tint/ast/block_statement_test.cc
index 17ae585..4097b20 100644
--- a/src/tint/ast/block_statement_test.cc
+++ b/src/tint/ast/block_statement_test.cc
@@ -23,46 +23,44 @@
 using BlockStatementTest = TestHelper;
 
 TEST_F(BlockStatementTest, Creation) {
-  auto* d = create<DiscardStatement>();
-  auto* ptr = d;
+    auto* d = create<DiscardStatement>();
+    auto* ptr = d;
 
-  auto* b = create<BlockStatement>(StatementList{d});
+    auto* b = create<BlockStatement>(StatementList{d});
 
-  ASSERT_EQ(b->statements.size(), 1u);
-  EXPECT_EQ(b->statements[0], ptr);
+    ASSERT_EQ(b->statements.size(), 1u);
+    EXPECT_EQ(b->statements[0], ptr);
 }
 
 TEST_F(BlockStatementTest, Creation_WithSource) {
-  auto* b = create<BlockStatement>(Source{Source::Location{20, 2}},
-                                   ast::StatementList{});
-  auto src = b->source;
-  EXPECT_EQ(src.range.begin.line, 20u);
-  EXPECT_EQ(src.range.begin.column, 2u);
+    auto* b = create<BlockStatement>(Source{Source::Location{20, 2}}, ast::StatementList{});
+    auto src = b->source;
+    EXPECT_EQ(src.range.begin.line, 20u);
+    EXPECT_EQ(src.range.begin.column, 2u);
 }
 
 TEST_F(BlockStatementTest, IsBlock) {
-  auto* b = create<BlockStatement>(ast::StatementList{});
-  EXPECT_TRUE(b->Is<BlockStatement>());
+    auto* b = create<BlockStatement>(ast::StatementList{});
+    EXPECT_TRUE(b->Is<BlockStatement>());
 }
 
 TEST_F(BlockStatementTest, Assert_Null_Statement) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.create<BlockStatement>(ast::StatementList{nullptr});
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.create<BlockStatement>(ast::StatementList{nullptr});
+        },
+        "internal compiler error");
 }
 
 TEST_F(BlockStatementTest, Assert_DifferentProgramID_Statement) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.create<BlockStatement>(
-            ast::StatementList{b2.create<DiscardStatement>()});
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.create<BlockStatement>(ast::StatementList{b2.create<DiscardStatement>()});
+        },
+        "internal compiler error");
 }
 
 }  // namespace
diff --git a/src/tint/ast/bool.cc b/src/tint/ast/bool.cc
index 3f126e6..af951e7 100644
--- a/src/tint/ast/bool.cc
+++ b/src/tint/ast/bool.cc
@@ -27,12 +27,12 @@
 Bool::~Bool() = default;
 
 std::string Bool::FriendlyName(const SymbolTable&) const {
-  return "bool";
+    return "bool";
 }
 
 const Bool* Bool::Clone(CloneContext* ctx) const {
-  auto src = ctx->Clone(source);
-  return ctx->dst->create<Bool>(src);
+    auto src = ctx->Clone(source);
+    return ctx->dst->create<Bool>(src);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/bool.h b/src/tint/ast/bool.h
index 50a4fcb..bfe3b78 100644
--- a/src/tint/ast/bool.h
+++ b/src/tint/ast/bool.h
@@ -29,24 +29,24 @@
 
 /// A boolean type
 class Bool final : public Castable<Bool, Type> {
- public:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  Bool(ProgramID pid, const Source& src);
-  /// Move constructor
-  Bool(Bool&&);
-  ~Bool() override;
+  public:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    Bool(ProgramID pid, const Source& src);
+    /// Move constructor
+    Bool(Bool&&);
+    ~Bool() override;
 
-  /// @param symbols the program's symbol table
-  /// @returns the name for this type that closely resembles how it would be
-  /// declared in WGSL.
-  std::string FriendlyName(const SymbolTable& symbols) const override;
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type that closely resembles how it would be
+    /// declared in WGSL.
+    std::string FriendlyName(const SymbolTable& symbols) const override;
 
-  /// Clones this type and all transitive types using the `CloneContext` `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned type
-  const Bool* Clone(CloneContext* ctx) const override;
+    /// Clones this type and all transitive types using the `CloneContext` `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned type
+    const Bool* Clone(CloneContext* ctx) const override;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/bool_literal_expression.cc b/src/tint/ast/bool_literal_expression.cc
index c86036c..cfaacb9 100644
--- a/src/tint/ast/bool_literal_expression.cc
+++ b/src/tint/ast/bool_literal_expression.cc
@@ -20,18 +20,15 @@
 
 namespace tint::ast {
 
-BoolLiteralExpression::BoolLiteralExpression(ProgramID pid,
-                                             const Source& src,
-                                             bool val)
+BoolLiteralExpression::BoolLiteralExpression(ProgramID pid, const Source& src, bool val)
     : Base(pid, src), value(val) {}
 
 BoolLiteralExpression::~BoolLiteralExpression() = default;
 
-const BoolLiteralExpression* BoolLiteralExpression::Clone(
-    CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  return ctx->dst->create<BoolLiteralExpression>(src, value);
+const BoolLiteralExpression* BoolLiteralExpression::Clone(CloneContext* ctx) const {
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    return ctx->dst->create<BoolLiteralExpression>(src, value);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/bool_literal_expression.h b/src/tint/ast/bool_literal_expression.h
index 9fbd775..f2c4c3f 100644
--- a/src/tint/ast/bool_literal_expression.h
+++ b/src/tint/ast/bool_literal_expression.h
@@ -22,24 +22,23 @@
 namespace tint::ast {
 
 /// A boolean literal
-class BoolLiteralExpression final
-    : public Castable<BoolLiteralExpression, LiteralExpression> {
- public:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  /// @param value the bool literals value
-  BoolLiteralExpression(ProgramID pid, const Source& src, bool value);
-  ~BoolLiteralExpression() override;
+class BoolLiteralExpression final : public Castable<BoolLiteralExpression, LiteralExpression> {
+  public:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    /// @param value the bool literals value
+    BoolLiteralExpression(ProgramID pid, const Source& src, bool value);
+    ~BoolLiteralExpression() override;
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const BoolLiteralExpression* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const BoolLiteralExpression* Clone(CloneContext* ctx) const override;
 
-  /// The boolean literal value
-  const bool value;
+    /// The boolean literal value
+    const bool value;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/bool_literal_expression_test.cc b/src/tint/ast/bool_literal_expression_test.cc
index ac73802..efaa4ee 100644
--- a/src/tint/ast/bool_literal_expression_test.cc
+++ b/src/tint/ast/bool_literal_expression_test.cc
@@ -20,15 +20,15 @@
 using BoolLiteralExpressionTest = TestHelper;
 
 TEST_F(BoolLiteralExpressionTest, True) {
-  auto* b = create<BoolLiteralExpression>(true);
-  ASSERT_TRUE(b->Is<BoolLiteralExpression>());
-  ASSERT_TRUE(b->value);
+    auto* b = create<BoolLiteralExpression>(true);
+    ASSERT_TRUE(b->Is<BoolLiteralExpression>());
+    ASSERT_TRUE(b->value);
 }
 
 TEST_F(BoolLiteralExpressionTest, False) {
-  auto* b = create<BoolLiteralExpression>(false);
-  ASSERT_TRUE(b->Is<BoolLiteralExpression>());
-  ASSERT_FALSE(b->value);
+    auto* b = create<BoolLiteralExpression>(false);
+    ASSERT_TRUE(b->Is<BoolLiteralExpression>());
+    ASSERT_FALSE(b->value);
 }
 
 }  // namespace
diff --git a/src/tint/ast/bool_test.cc b/src/tint/ast/bool_test.cc
index 665b23f..d3842b9 100644
--- a/src/tint/ast/bool_test.cc
+++ b/src/tint/ast/bool_test.cc
@@ -22,8 +22,8 @@
 using AstBoolTest = TestHelper;
 
 TEST_F(AstBoolTest, FriendlyName) {
-  auto* b = create<Bool>();
-  EXPECT_EQ(b->FriendlyName(Symbols()), "bool");
+    auto* b = create<Bool>();
+    EXPECT_EQ(b->FriendlyName(Symbols()), "bool");
 }
 
 }  // namespace
diff --git a/src/tint/ast/break_statement.cc b/src/tint/ast/break_statement.cc
index 5748833..0290014 100644
--- a/src/tint/ast/break_statement.cc
+++ b/src/tint/ast/break_statement.cc
@@ -20,17 +20,16 @@
 
 namespace tint::ast {
 
-BreakStatement::BreakStatement(ProgramID pid, const Source& src)
-    : Base(pid, src) {}
+BreakStatement::BreakStatement(ProgramID pid, const Source& src) : Base(pid, src) {}
 
 BreakStatement::BreakStatement(BreakStatement&&) = default;
 
 BreakStatement::~BreakStatement() = default;
 
 const BreakStatement* BreakStatement::Clone(CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  return ctx->dst->create<BreakStatement>(src);
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    return ctx->dst->create<BreakStatement>(src);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/break_statement.h b/src/tint/ast/break_statement.h
index bb5b00c..29e5eeb 100644
--- a/src/tint/ast/break_statement.h
+++ b/src/tint/ast/break_statement.h
@@ -21,20 +21,20 @@
 
 /// An break statement
 class BreakStatement final : public Castable<BreakStatement, Statement> {
- public:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  BreakStatement(ProgramID pid, const Source& src);
-  /// Move constructor
-  BreakStatement(BreakStatement&&);
-  ~BreakStatement() override;
+  public:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    BreakStatement(ProgramID pid, const Source& src);
+    /// Move constructor
+    BreakStatement(BreakStatement&&);
+    ~BreakStatement() override;
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const BreakStatement* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const BreakStatement* Clone(CloneContext* ctx) const override;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/break_statement_test.cc b/src/tint/ast/break_statement_test.cc
index dba28cf..d2a1043 100644
--- a/src/tint/ast/break_statement_test.cc
+++ b/src/tint/ast/break_statement_test.cc
@@ -22,15 +22,15 @@
 using BreakStatementTest = TestHelper;
 
 TEST_F(BreakStatementTest, Creation_WithSource) {
-  auto* stmt = create<BreakStatement>(Source{Source::Location{20, 2}});
-  auto src = stmt->source;
-  EXPECT_EQ(src.range.begin.line, 20u);
-  EXPECT_EQ(src.range.begin.column, 2u);
+    auto* stmt = create<BreakStatement>(Source{Source::Location{20, 2}});
+    auto src = stmt->source;
+    EXPECT_EQ(src.range.begin.line, 20u);
+    EXPECT_EQ(src.range.begin.column, 2u);
 }
 
 TEST_F(BreakStatementTest, IsBreak) {
-  auto* stmt = create<BreakStatement>();
-  EXPECT_TRUE(stmt->Is<BreakStatement>());
+    auto* stmt = create<BreakStatement>();
+    EXPECT_TRUE(stmt->Is<BreakStatement>());
 }
 
 }  // namespace
diff --git a/src/tint/ast/builtin.cc b/src/tint/ast/builtin.cc
index 3640411..d215a5c 100644
--- a/src/tint/ast/builtin.cc
+++ b/src/tint/ast/builtin.cc
@@ -17,64 +17,64 @@
 namespace tint::ast {
 
 std::ostream& operator<<(std::ostream& out, Builtin builtin) {
-  switch (builtin) {
-    case Builtin::kNone: {
-      out << "none";
-      break;
+    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";
+        }
     }
-    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;
+    return out;
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/builtin.h b/src/tint/ast/builtin.h
index a0b8d5d..699632a 100644
--- a/src/tint/ast/builtin.h
+++ b/src/tint/ast/builtin.h
@@ -21,23 +21,23 @@
 
 /// The builtin identifiers
 enum class Builtin {
-  kNone = -1,
-  kPosition,
-  kVertexIndex,
-  kInstanceIndex,
-  kFrontFacing,
-  kFragDepth,
-  kLocalInvocationId,
-  kLocalInvocationIndex,
-  kGlobalInvocationId,
-  kWorkgroupId,
-  kNumWorkgroups,
-  kSampleIndex,
-  kSampleMask,
+    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,
+    // 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
diff --git a/src/tint/ast/builtin_attribute.cc b/src/tint/ast/builtin_attribute.cc
index f3d013a..03e47b6 100644
--- a/src/tint/ast/builtin_attribute.cc
+++ b/src/tint/ast/builtin_attribute.cc
@@ -28,13 +28,13 @@
 BuiltinAttribute::~BuiltinAttribute() = default;
 
 std::string BuiltinAttribute::Name() const {
-  return "builtin";
+    return "builtin";
 }
 
 const BuiltinAttribute* BuiltinAttribute::Clone(CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  return ctx->dst->create<BuiltinAttribute>(src, builtin);
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    return ctx->dst->create<BuiltinAttribute>(src, builtin);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/builtin_attribute.h b/src/tint/ast/builtin_attribute.h
index cc562f4..75898be 100644
--- a/src/tint/ast/builtin_attribute.h
+++ b/src/tint/ast/builtin_attribute.h
@@ -24,25 +24,25 @@
 
 /// A builtin attribute
 class BuiltinAttribute final : public Castable<BuiltinAttribute, Attribute> {
- public:
-  /// constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  /// @param builtin the builtin value
-  BuiltinAttribute(ProgramID pid, const Source& src, Builtin builtin);
-  ~BuiltinAttribute() override;
+  public:
+    /// constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    /// @param builtin the builtin value
+    BuiltinAttribute(ProgramID pid, const Source& src, Builtin builtin);
+    ~BuiltinAttribute() override;
 
-  /// @returns the WGSL name for the attribute
-  std::string Name() const override;
+    /// @returns the WGSL name for the attribute
+    std::string Name() const override;
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const BuiltinAttribute* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const BuiltinAttribute* Clone(CloneContext* ctx) const override;
 
-  /// The builtin value
-  const Builtin builtin;
+    /// The builtin value
+    const Builtin builtin;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/builtin_attribute_test.cc b/src/tint/ast/builtin_attribute_test.cc
index 82b681d..a57f5b1 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>(Builtin::kFragDepth);
+    EXPECT_EQ(Builtin::kFragDepth, d->builtin);
 }
 
 }  // namespace
diff --git a/src/tint/ast/builtin_texture_helper_test.cc b/src/tint/ast/builtin_texture_helper_test.cc
index 85567e0..8f9091d 100644
--- a/src/tint/ast/builtin_texture_helper_test.cc
+++ b/src/tint/ast/builtin_texture_helper_test.cc
@@ -14,25 +14,22 @@
 
 #include "src/tint/ast/builtin_texture_helper_test.h"
 
-#include "src/tint/sem/depth_texture_type.h"
-#include "src/tint/sem/multisampled_texture_type.h"
-#include "src/tint/sem/sampled_texture_type.h"
+#include "src/tint/sem/depth_texture.h"
+#include "src/tint/sem/multisampled_texture.h"
+#include "src/tint/sem/sampled_texture.h"
+
+using namespace tint::number_suffixes;  // NOLINT
 
 namespace tint::ast::builtin::test {
 
-using u32 = ProgramBuilder::u32;
-using i32 = ProgramBuilder::i32;
-using f32 = ProgramBuilder::f32;
-
-TextureOverloadCase::TextureOverloadCase(
-    ValidTextureOverload o,
-    const char* desc,
-    TextureKind tk,
-    ast::SamplerKind sk,
-    ast::TextureDimension dims,
-    TextureDataType datatype,
-    const char* f,
-    std::function<ExpressionList(ProgramBuilder*)> a)
+TextureOverloadCase::TextureOverloadCase(ValidTextureOverload o,
+                                         const char* desc,
+                                         TextureKind tk,
+                                         ast::SamplerKind sk,
+                                         ast::TextureDimension dims,
+                                         TextureDataType datatype,
+                                         const char* f,
+                                         std::function<ExpressionList(ProgramBuilder*)> a)
     : overload(o),
       description(desc),
       texture_kind(tk),
@@ -41,14 +38,13 @@
       texture_data_type(datatype),
       function(f),
       args(std::move(a)) {}
-TextureOverloadCase::TextureOverloadCase(
-    ValidTextureOverload o,
-    const char* desc,
-    TextureKind tk,
-    ast::TextureDimension dims,
-    TextureDataType datatype,
-    const char* f,
-    std::function<ExpressionList(ProgramBuilder*)> a)
+TextureOverloadCase::TextureOverloadCase(ValidTextureOverload o,
+                                         const char* desc,
+                                         TextureKind tk,
+                                         ast::TextureDimension dims,
+                                         TextureDataType datatype,
+                                         const char* f,
+                                         std::function<ExpressionList(ProgramBuilder*)> a)
     : overload(o),
       description(desc),
       texture_kind(tk),
@@ -56,15 +52,14 @@
       texture_data_type(datatype),
       function(f),
       args(std::move(a)) {}
-TextureOverloadCase::TextureOverloadCase(
-    ValidTextureOverload o,
-    const char* d,
-    Access acc,
-    ast::TexelFormat fmt,
-    ast::TextureDimension dims,
-    TextureDataType datatype,
-    const char* f,
-    std::function<ExpressionList(ProgramBuilder*)> a)
+TextureOverloadCase::TextureOverloadCase(ValidTextureOverload o,
+                                         const char* d,
+                                         Access acc,
+                                         ast::TexelFormat fmt,
+                                         ast::TextureDimension dims,
+                                         TextureDataType datatype,
+                                         const char* f,
+                                         std::function<ExpressionList(ProgramBuilder*)> a)
     : overload(o),
       description(d),
       texture_kind(TextureKind::kStorage),
@@ -78,2203 +73,2195 @@
 TextureOverloadCase::~TextureOverloadCase() = default;
 
 std::ostream& operator<<(std::ostream& out, const TextureKind& kind) {
-  switch (kind) {
-    case TextureKind::kRegular:
-      out << "regular";
-      break;
-    case TextureKind::kDepth:
-      out << "depth";
-      break;
-    case TextureKind::kDepthMultisampled:
-      out << "depth-multisampled";
-      break;
-    case TextureKind::kMultisampled:
-      out << "multisampled";
-      break;
-    case TextureKind::kStorage:
-      out << "storage";
-      break;
-  }
-  return out;
+    switch (kind) {
+        case TextureKind::kRegular:
+            out << "regular";
+            break;
+        case TextureKind::kDepth:
+            out << "depth";
+            break;
+        case TextureKind::kDepthMultisampled:
+            out << "depth-multisampled";
+            break;
+        case TextureKind::kMultisampled:
+            out << "multisampled";
+            break;
+        case TextureKind::kStorage:
+            out << "storage";
+            break;
+    }
+    return out;
 }
 
 std::ostream& operator<<(std::ostream& out, const TextureDataType& ty) {
-  switch (ty) {
-    case TextureDataType::kF32:
-      out << "f32";
-      break;
-    case TextureDataType::kU32:
-      out << "u32";
-      break;
-    case TextureDataType::kI32:
-      out << "i32";
-      break;
-  }
-  return out;
+    switch (ty) {
+        case TextureDataType::kF32:
+            out << "f32";
+            break;
+        case TextureDataType::kU32:
+            out << "u32";
+            break;
+        case TextureDataType::kI32:
+            out << "i32";
+            break;
+    }
+    return out;
 }
 
 std::ostream& operator<<(std::ostream& out, const TextureOverloadCase& data) {
-  out << "TextureOverloadCase " << static_cast<int>(data.overload) << "\n";
-  out << data.description << "\n";
-  out << "texture_kind:      " << data.texture_kind << "\n";
-  out << "sampler_kind:      ";
-  if (data.texture_kind != TextureKind::kStorage) {
-    out << data.sampler_kind;
-  } else {
-    out << "<unused>";
-  }
-  out << "\n";
-  out << "access:            " << data.access << "\n";
-  out << "texel_format:      " << data.texel_format << "\n";
-  out << "texture_dimension: " << data.texture_dimension << "\n";
-  out << "texture_data_type: " << data.texture_data_type << "\n";
-  return out;
-}
-
-const ast::Type* TextureOverloadCase::BuildResultVectorComponentType(
-    ProgramBuilder* b) const {
-  switch (texture_data_type) {
-    case ast::builtin::test::TextureDataType::kF32:
-      return b->ty.f32();
-    case ast::builtin::test::TextureDataType::kU32:
-      return b->ty.u32();
-    case ast::builtin::test::TextureDataType::kI32:
-      return b->ty.i32();
-  }
-
-  TINT_UNREACHABLE(AST, b->Diagnostics());
-  return {};
-}
-
-const ast::Variable* TextureOverloadCase::BuildTextureVariable(
-    ProgramBuilder* b) const {
-  AttributeList attrs = {
-      b->create<ast::GroupAttribute>(0),
-      b->create<ast::BindingAttribute>(0),
-  };
-  switch (texture_kind) {
-    case ast::builtin::test::TextureKind::kRegular:
-      return b->Global("texture",
-                       b->ty.sampled_texture(texture_dimension,
-                                             BuildResultVectorComponentType(b)),
-                       attrs);
-
-    case ast::builtin::test::TextureKind::kDepth:
-      return b->Global("texture", b->ty.depth_texture(texture_dimension),
-                       attrs);
-
-    case ast::builtin::test::TextureKind::kDepthMultisampled:
-      return b->Global("texture",
-                       b->ty.depth_multisampled_texture(texture_dimension),
-                       attrs);
-
-    case ast::builtin::test::TextureKind::kMultisampled:
-      return b->Global(
-          "texture",
-          b->ty.multisampled_texture(texture_dimension,
-                                     BuildResultVectorComponentType(b)),
-          attrs);
-
-    case ast::builtin::test::TextureKind::kStorage: {
-      auto* st = b->ty.storage_texture(texture_dimension, texel_format, access);
-      return b->Global("texture", st, attrs);
+    out << "TextureOverloadCase " << static_cast<int>(data.overload) << "\n";
+    out << data.description << "\n";
+    out << "texture_kind:      " << data.texture_kind << "\n";
+    out << "sampler_kind:      ";
+    if (data.texture_kind != TextureKind::kStorage) {
+        out << data.sampler_kind;
+    } else {
+        out << "<unused>";
     }
-  }
-
-  TINT_UNREACHABLE(AST, b->Diagnostics());
-  return nullptr;
+    out << "\n";
+    out << "access:            " << data.access << "\n";
+    out << "texel_format:      " << data.texel_format << "\n";
+    out << "texture_dimension: " << data.texture_dimension << "\n";
+    out << "texture_data_type: " << data.texture_data_type << "\n";
+    return out;
 }
 
-const ast::Variable* TextureOverloadCase::BuildSamplerVariable(
-    ProgramBuilder* b) const {
-  AttributeList attrs = {
-      b->create<ast::GroupAttribute>(0),
-      b->create<ast::BindingAttribute>(1),
-  };
-  return b->Global("sampler", b->ty.sampler(sampler_kind), attrs);
+const ast::Type* TextureOverloadCase::BuildResultVectorComponentType(ProgramBuilder* b) const {
+    switch (texture_data_type) {
+        case ast::builtin::test::TextureDataType::kF32:
+            return b->ty.f32();
+        case ast::builtin::test::TextureDataType::kU32:
+            return b->ty.u32();
+        case ast::builtin::test::TextureDataType::kI32:
+            return b->ty.i32();
+    }
+
+    TINT_UNREACHABLE(AST, b->Diagnostics());
+    return {};
+}
+
+const ast::Variable* TextureOverloadCase::BuildTextureVariable(ProgramBuilder* b) const {
+    AttributeList attrs = {
+        b->create<ast::GroupAttribute>(0),
+        b->create<ast::BindingAttribute>(0),
+    };
+    switch (texture_kind) {
+        case ast::builtin::test::TextureKind::kRegular:
+            return b->Global(
+                "texture",
+                b->ty.sampled_texture(texture_dimension, BuildResultVectorComponentType(b)), attrs);
+
+        case ast::builtin::test::TextureKind::kDepth:
+            return b->Global("texture", b->ty.depth_texture(texture_dimension), attrs);
+
+        case ast::builtin::test::TextureKind::kDepthMultisampled:
+            return b->Global("texture", b->ty.depth_multisampled_texture(texture_dimension), attrs);
+
+        case ast::builtin::test::TextureKind::kMultisampled:
+            return b->Global(
+                "texture",
+                b->ty.multisampled_texture(texture_dimension, BuildResultVectorComponentType(b)),
+                attrs);
+
+        case ast::builtin::test::TextureKind::kStorage: {
+            auto* st = b->ty.storage_texture(texture_dimension, texel_format, access);
+            return b->Global("texture", st, attrs);
+        }
+    }
+
+    TINT_UNREACHABLE(AST, b->Diagnostics());
+    return nullptr;
+}
+
+const ast::Variable* TextureOverloadCase::BuildSamplerVariable(ProgramBuilder* b) const {
+    AttributeList attrs = {
+        b->create<ast::GroupAttribute>(0),
+        b->create<ast::BindingAttribute>(1),
+    };
+    return b->Global("sampler", b->ty.sampler(sampler_kind), attrs);
 }
 
 std::vector<TextureOverloadCase> TextureOverloadCase::ValidCases() {
-  return {
-      {
-          ValidTextureOverload::kDimensions1d,
-          "textureDimensions(t : texture_1d<f32>) -> i32",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k1d,
-          TextureDataType::kF32,
-          "textureDimensions",
-          [](ProgramBuilder* b) { return b->ExprList("texture"); },
-      },
-      {
-          ValidTextureOverload::kDimensions2d,
-          "textureDimensions(t : texture_2d<f32>) -> vec2<i32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2d,
-          TextureDataType::kF32,
-          "textureDimensions",
-          [](ProgramBuilder* b) { return b->ExprList("texture"); },
-      },
-      {
-          ValidTextureOverload::kDimensions2dLevel,
-          "textureDimensions(t     : texture_2d<f32>,\n"
-          "                  level : i32) -> vec2<i32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2d,
-          TextureDataType::kF32,
-          "textureDimensions",
-          [](ProgramBuilder* b) { return b->ExprList("texture", 1); },
-      },
-      {
-          ValidTextureOverload::kDimensions2dArray,
-          "textureDimensions(t : texture_2d_array<f32>) -> vec2<i32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2dArray,
-          TextureDataType::kF32,
-          "textureDimensions",
-          [](ProgramBuilder* b) { return b->ExprList("texture"); },
-      },
-      {
-          ValidTextureOverload::kDimensions2dArrayLevel,
-          "textureDimensions(t     : texture_2d_array<f32>,\n"
-          "                  level : i32) -> vec2<i32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2dArray,
-          TextureDataType::kF32,
-          "textureDimensions",
-          [](ProgramBuilder* b) { return b->ExprList("texture", 1); },
-      },
-      {
-          ValidTextureOverload::kDimensions3d,
-          "textureDimensions(t : texture_3d<f32>) -> vec3<i32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k3d,
-          TextureDataType::kF32,
-          "textureDimensions",
-          [](ProgramBuilder* b) { return b->ExprList("texture"); },
-      },
-      {
-          ValidTextureOverload::kDimensions3dLevel,
-          "textureDimensions(t     : texture_3d<f32>,\n"
-          "                  level : i32) -> vec3<i32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k3d,
-          TextureDataType::kF32,
-          "textureDimensions",
-          [](ProgramBuilder* b) { return b->ExprList("texture", 1); },
-      },
-      {
-          ValidTextureOverload::kDimensionsCube,
-          "textureDimensions(t : texture_cube<f32>) -> vec2<i32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::kCube,
-          TextureDataType::kF32,
-          "textureDimensions",
-          [](ProgramBuilder* b) { return b->ExprList("texture"); },
-      },
-      {
-          ValidTextureOverload::kDimensionsCubeLevel,
-          "textureDimensions(t     : texture_cube<f32>,\n"
-          "                  level : i32) -> vec2<i32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::kCube,
-          TextureDataType::kF32,
-          "textureDimensions",
-          [](ProgramBuilder* b) { return b->ExprList("texture", 1); },
-      },
-      {
-          ValidTextureOverload::kDimensionsCubeArray,
-          "textureDimensions(t : texture_cube_array<f32>) -> vec2<i32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::kCubeArray,
-          TextureDataType::kF32,
-          "textureDimensions",
-          [](ProgramBuilder* b) { return b->ExprList("texture"); },
-      },
-      {
-          ValidTextureOverload::kDimensionsCubeArrayLevel,
-          "textureDimensions(t     : texture_cube_array<f32>,\n"
-          "                  level : i32) -> vec2<i32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::kCubeArray,
-          TextureDataType::kF32,
-          "textureDimensions",
-          [](ProgramBuilder* b) { return b->ExprList("texture", 1); },
-      },
-      {
-          ValidTextureOverload::kDimensionsMultisampled2d,
-          "textureDimensions(t : texture_multisampled_2d<f32>)-> vec2<i32>",
-          TextureKind::kMultisampled,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2d,
-          TextureDataType::kF32,
-          "textureDimensions",
-          [](ProgramBuilder* b) { return b->ExprList("texture"); },
-      },
-      {
-          ValidTextureOverload::kDimensionsDepth2d,
-          "textureDimensions(t : texture_depth_2d) -> vec2<i32>",
-          TextureKind::kDepth,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2d,
-          TextureDataType::kF32,
-          "textureDimensions",
-          [](ProgramBuilder* b) { return b->ExprList("texture"); },
-      },
-      {
-          ValidTextureOverload::kDimensionsDepth2dLevel,
-          "textureDimensions(t     : texture_depth_2d,\n"
-          "                  level : i32) -> vec2<i32>",
-          TextureKind::kDepth,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2d,
-          TextureDataType::kF32,
-          "textureDimensions",
-          [](ProgramBuilder* b) { return b->ExprList("texture", 1); },
-      },
-      {
-          ValidTextureOverload::kDimensionsDepth2dArray,
-          "textureDimensions(t : texture_depth_2d_array) -> vec2<i32>",
-          TextureKind::kDepth,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2dArray,
-          TextureDataType::kF32,
-          "textureDimensions",
-          [](ProgramBuilder* b) { return b->ExprList("texture"); },
-      },
-      {
-          ValidTextureOverload::kDimensionsDepth2dArrayLevel,
-          "textureDimensions(t     : texture_depth_2d_array,\n"
-          "                  level : i32) -> vec2<i32>",
-          TextureKind::kDepth,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2dArray,
-          TextureDataType::kF32,
-          "textureDimensions",
-          [](ProgramBuilder* b) { return b->ExprList("texture", 1); },
-      },
-      {
-          ValidTextureOverload::kDimensionsDepthCube,
-          "textureDimensions(t : texture_depth_cube) -> vec2<i32>",
-          TextureKind::kDepth,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::kCube,
-          TextureDataType::kF32,
-          "textureDimensions",
-          [](ProgramBuilder* b) { return b->ExprList("texture"); },
-      },
-      {
-          ValidTextureOverload::kDimensionsDepthCubeLevel,
-          "textureDimensions(t     : texture_depth_cube,\n"
-          "                  level : i32) -> vec2<i32>",
-          TextureKind::kDepth,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::kCube,
-          TextureDataType::kF32,
-          "textureDimensions",
-          [](ProgramBuilder* b) { return b->ExprList("texture", 1); },
-      },
-      {
-          ValidTextureOverload::kDimensionsDepthCubeArray,
-          "textureDimensions(t : texture_depth_cube_array) -> vec2<i32>",
-          TextureKind::kDepth,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::kCubeArray,
-          TextureDataType::kF32,
-          "textureDimensions",
-          [](ProgramBuilder* b) { return b->ExprList("texture"); },
-      },
-      {
-          ValidTextureOverload::kDimensionsDepthCubeArrayLevel,
-          "textureDimensions(t     : texture_depth_cube_array,\n"
-          "                  level : i32) -> vec2<i32>",
-          TextureKind::kDepth,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::kCubeArray,
-          TextureDataType::kF32,
-          "textureDimensions",
-          [](ProgramBuilder* b) { return b->ExprList("texture", 1); },
-      },
-      {
-          ValidTextureOverload::kDimensionsDepthMultisampled2d,
-          "textureDimensions(t : texture_depth_multisampled_2d) -> vec2<i32>",
-          TextureKind::kDepthMultisampled,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2d,
-          TextureDataType::kF32,
-          "textureDimensions",
-          [](ProgramBuilder* b) { return b->ExprList("texture"); },
-      },
-      {
-          ValidTextureOverload::kDimensionsStorageWO1d,
-          "textureDimensions(t : texture_storage_1d<rgba32float>) -> i32",
-          ast::Access::kWrite,
-          ast::TexelFormat::kRgba32Float,
-          ast::TextureDimension::k1d,
-          TextureDataType::kF32,
-          "textureDimensions",
-          [](ProgramBuilder* b) { return b->ExprList("texture"); },
-      },
-      {
-          ValidTextureOverload::kDimensionsStorageWO2d,
-          "textureDimensions(t : texture_storage_2d<rgba32float>) -> "
-          "vec2<i32>",
-          ast::Access::kWrite,
-          ast::TexelFormat::kRgba32Float,
-          ast::TextureDimension::k2d,
-          TextureDataType::kF32,
-          "textureDimensions",
-          [](ProgramBuilder* b) { return b->ExprList("texture"); },
-      },
-      {
-          ValidTextureOverload::kDimensionsStorageWO2dArray,
-          "textureDimensions(t : texture_storage_2d_array<rgba32float>) -> "
-          "vec2<i32>",
-          ast::Access::kWrite,
-          ast::TexelFormat::kRgba32Float,
-          ast::TextureDimension::k2dArray,
-          TextureDataType::kF32,
-          "textureDimensions",
-          [](ProgramBuilder* b) { return b->ExprList("texture"); },
-      },
-      {
-          ValidTextureOverload::kDimensionsStorageWO3d,
-          "textureDimensions(t : texture_storage_3d<rgba32float>) -> "
-          "vec3<i32>",
-          ast::Access::kWrite,
-          ast::TexelFormat::kRgba32Float,
-          ast::TextureDimension::k3d,
-          TextureDataType::kF32,
-          "textureDimensions",
-          [](ProgramBuilder* b) { return b->ExprList("texture"); },
-      },
+    return {
+        {
+            ValidTextureOverload::kDimensions1d,
+            "textureDimensions(t : texture_1d<f32>) -> i32",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k1d,
+            TextureDataType::kF32,
+            "textureDimensions",
+            [](ProgramBuilder* b) { return b->ExprList("texture"); },
+        },
+        {
+            ValidTextureOverload::kDimensions2d,
+            "textureDimensions(t : texture_2d<f32>) -> vec2<i32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2d,
+            TextureDataType::kF32,
+            "textureDimensions",
+            [](ProgramBuilder* b) { return b->ExprList("texture"); },
+        },
+        {
+            ValidTextureOverload::kDimensions2dLevel,
+            "textureDimensions(t     : texture_2d<f32>,\n"
+            "                  level : i32) -> vec2<i32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2d,
+            TextureDataType::kF32,
+            "textureDimensions",
+            [](ProgramBuilder* b) { return b->ExprList("texture", 1_i); },
+        },
+        {
+            ValidTextureOverload::kDimensions2dArray,
+            "textureDimensions(t : texture_2d_array<f32>) -> vec2<i32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2dArray,
+            TextureDataType::kF32,
+            "textureDimensions",
+            [](ProgramBuilder* b) { return b->ExprList("texture"); },
+        },
+        {
+            ValidTextureOverload::kDimensions2dArrayLevel,
+            "textureDimensions(t     : texture_2d_array<f32>,\n"
+            "                  level : i32) -> vec2<i32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2dArray,
+            TextureDataType::kF32,
+            "textureDimensions",
+            [](ProgramBuilder* b) { return b->ExprList("texture", 1_i); },
+        },
+        {
+            ValidTextureOverload::kDimensions3d,
+            "textureDimensions(t : texture_3d<f32>) -> vec3<i32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k3d,
+            TextureDataType::kF32,
+            "textureDimensions",
+            [](ProgramBuilder* b) { return b->ExprList("texture"); },
+        },
+        {
+            ValidTextureOverload::kDimensions3dLevel,
+            "textureDimensions(t     : texture_3d<f32>,\n"
+            "                  level : i32) -> vec3<i32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k3d,
+            TextureDataType::kF32,
+            "textureDimensions",
+            [](ProgramBuilder* b) { return b->ExprList("texture", 1_i); },
+        },
+        {
+            ValidTextureOverload::kDimensionsCube,
+            "textureDimensions(t : texture_cube<f32>) -> vec2<i32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::kCube,
+            TextureDataType::kF32,
+            "textureDimensions",
+            [](ProgramBuilder* b) { return b->ExprList("texture"); },
+        },
+        {
+            ValidTextureOverload::kDimensionsCubeLevel,
+            "textureDimensions(t     : texture_cube<f32>,\n"
+            "                  level : i32) -> vec2<i32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::kCube,
+            TextureDataType::kF32,
+            "textureDimensions",
+            [](ProgramBuilder* b) { return b->ExprList("texture", 1_i); },
+        },
+        {
+            ValidTextureOverload::kDimensionsCubeArray,
+            "textureDimensions(t : texture_cube_array<f32>) -> vec2<i32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::kCubeArray,
+            TextureDataType::kF32,
+            "textureDimensions",
+            [](ProgramBuilder* b) { return b->ExprList("texture"); },
+        },
+        {
+            ValidTextureOverload::kDimensionsCubeArrayLevel,
+            "textureDimensions(t     : texture_cube_array<f32>,\n"
+            "                  level : i32) -> vec2<i32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::kCubeArray,
+            TextureDataType::kF32,
+            "textureDimensions",
+            [](ProgramBuilder* b) { return b->ExprList("texture", 1_i); },
+        },
+        {
+            ValidTextureOverload::kDimensionsMultisampled2d,
+            "textureDimensions(t : texture_multisampled_2d<f32>)-> vec2<i32>",
+            TextureKind::kMultisampled,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2d,
+            TextureDataType::kF32,
+            "textureDimensions",
+            [](ProgramBuilder* b) { return b->ExprList("texture"); },
+        },
+        {
+            ValidTextureOverload::kDimensionsDepth2d,
+            "textureDimensions(t : texture_depth_2d) -> vec2<i32>",
+            TextureKind::kDepth,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2d,
+            TextureDataType::kF32,
+            "textureDimensions",
+            [](ProgramBuilder* b) { return b->ExprList("texture"); },
+        },
+        {
+            ValidTextureOverload::kDimensionsDepth2dLevel,
+            "textureDimensions(t     : texture_depth_2d,\n"
+            "                  level : i32) -> vec2<i32>",
+            TextureKind::kDepth,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2d,
+            TextureDataType::kF32,
+            "textureDimensions",
+            [](ProgramBuilder* b) { return b->ExprList("texture", 1_i); },
+        },
+        {
+            ValidTextureOverload::kDimensionsDepth2dArray,
+            "textureDimensions(t : texture_depth_2d_array) -> vec2<i32>",
+            TextureKind::kDepth,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2dArray,
+            TextureDataType::kF32,
+            "textureDimensions",
+            [](ProgramBuilder* b) { return b->ExprList("texture"); },
+        },
+        {
+            ValidTextureOverload::kDimensionsDepth2dArrayLevel,
+            "textureDimensions(t     : texture_depth_2d_array,\n"
+            "                  level : i32) -> vec2<i32>",
+            TextureKind::kDepth,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2dArray,
+            TextureDataType::kF32,
+            "textureDimensions",
+            [](ProgramBuilder* b) { return b->ExprList("texture", 1_i); },
+        },
+        {
+            ValidTextureOverload::kDimensionsDepthCube,
+            "textureDimensions(t : texture_depth_cube) -> vec2<i32>",
+            TextureKind::kDepth,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::kCube,
+            TextureDataType::kF32,
+            "textureDimensions",
+            [](ProgramBuilder* b) { return b->ExprList("texture"); },
+        },
+        {
+            ValidTextureOverload::kDimensionsDepthCubeLevel,
+            "textureDimensions(t     : texture_depth_cube,\n"
+            "                  level : i32) -> vec2<i32>",
+            TextureKind::kDepth,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::kCube,
+            TextureDataType::kF32,
+            "textureDimensions",
+            [](ProgramBuilder* b) { return b->ExprList("texture", 1_i); },
+        },
+        {
+            ValidTextureOverload::kDimensionsDepthCubeArray,
+            "textureDimensions(t : texture_depth_cube_array) -> vec2<i32>",
+            TextureKind::kDepth,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::kCubeArray,
+            TextureDataType::kF32,
+            "textureDimensions",
+            [](ProgramBuilder* b) { return b->ExprList("texture"); },
+        },
+        {
+            ValidTextureOverload::kDimensionsDepthCubeArrayLevel,
+            "textureDimensions(t     : texture_depth_cube_array,\n"
+            "                  level : i32) -> vec2<i32>",
+            TextureKind::kDepth,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::kCubeArray,
+            TextureDataType::kF32,
+            "textureDimensions",
+            [](ProgramBuilder* b) { return b->ExprList("texture", 1_i); },
+        },
+        {
+            ValidTextureOverload::kDimensionsDepthMultisampled2d,
+            "textureDimensions(t : texture_depth_multisampled_2d) -> vec2<i32>",
+            TextureKind::kDepthMultisampled,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2d,
+            TextureDataType::kF32,
+            "textureDimensions",
+            [](ProgramBuilder* b) { return b->ExprList("texture"); },
+        },
+        {
+            ValidTextureOverload::kDimensionsStorageWO1d,
+            "textureDimensions(t : texture_storage_1d<rgba32float>) -> i32",
+            ast::Access::kWrite,
+            ast::TexelFormat::kRgba32Float,
+            ast::TextureDimension::k1d,
+            TextureDataType::kF32,
+            "textureDimensions",
+            [](ProgramBuilder* b) { return b->ExprList("texture"); },
+        },
+        {
+            ValidTextureOverload::kDimensionsStorageWO2d,
+            "textureDimensions(t : texture_storage_2d<rgba32float>) -> "
+            "vec2<i32>",
+            ast::Access::kWrite,
+            ast::TexelFormat::kRgba32Float,
+            ast::TextureDimension::k2d,
+            TextureDataType::kF32,
+            "textureDimensions",
+            [](ProgramBuilder* b) { return b->ExprList("texture"); },
+        },
+        {
+            ValidTextureOverload::kDimensionsStorageWO2dArray,
+            "textureDimensions(t : texture_storage_2d_array<rgba32float>) -> "
+            "vec2<i32>",
+            ast::Access::kWrite,
+            ast::TexelFormat::kRgba32Float,
+            ast::TextureDimension::k2dArray,
+            TextureDataType::kF32,
+            "textureDimensions",
+            [](ProgramBuilder* b) { return b->ExprList("texture"); },
+        },
+        {
+            ValidTextureOverload::kDimensionsStorageWO3d,
+            "textureDimensions(t : texture_storage_3d<rgba32float>) -> "
+            "vec3<i32>",
+            ast::Access::kWrite,
+            ast::TexelFormat::kRgba32Float,
+            ast::TextureDimension::k3d,
+            TextureDataType::kF32,
+            "textureDimensions",
+            [](ProgramBuilder* b) { return b->ExprList("texture"); },
+        },
 
-      {
-          ValidTextureOverload::kGather2dF32,
-          "textureGather(component : i32,\n"
-          "              t         : texture_2d<T>,\n"
-          "              s         : sampler,\n"
-          "              coords    : vec2<f32>) -> vec4<T>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2d,
-          TextureDataType::kF32,
-          "textureGather",
-          [](ProgramBuilder* b) {
-            return b->ExprList(0,                        // component
-                               "texture",                // t
-                               "sampler",                // s
-                               b->vec2<f32>(1.f, 2.f));  // coords
-          },
-      },
-      {
-          ValidTextureOverload::kGather2dOffsetF32,
-          "textureGather(component : i32,\n"
-          "              t         : texture_2d<T>,\n"
-          "              s         : sampler,\n"
-          "              coords    : vec2<f32>,\n"
-          "              offset    : vec2<i32>) -> vec4<T>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2d,
-          TextureDataType::kF32,
-          "textureGather",
-          [](ProgramBuilder* b) {
-            return b->ExprList(0,                       // component
-                               "texture",               // t
-                               "sampler",               // s
-                               b->vec2<f32>(1.f, 2.f),  // coords
-                               b->vec2<i32>(3, 4));     // offset
-          },
-      },
-      {
-          ValidTextureOverload::kGather2dArrayF32,
-          "textureGather(component   : i32,\n"
-          "              t           : texture_2d_array<T>,\n"
-          "              s           : sampler,\n"
-          "              coords      : vec2<f32>,\n"
-          "              array_index : i32) -> vec4<T>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2dArray,
-          TextureDataType::kF32,
-          "textureGather",
-          [](ProgramBuilder* b) {
-            return b->ExprList(0,                       // component
-                               "texture",               // t
-                               "sampler",               // s
-                               b->vec2<f32>(1.f, 2.f),  // coords
-                               3);                      // array index
-          },
-      },
-      {
-          ValidTextureOverload::kGather2dArrayOffsetF32,
-          "textureGather(component   : i32,\n"
-          "              t           : texture_2d_array<T>,\n"
-          "              s           : sampler,\n"
-          "              coords      : vec2<f32>,\n"
-          "              array_index : i32,\n"
-          "              offset      : vec2<i32>) -> vec4<T>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2dArray,
-          TextureDataType::kF32,
-          "textureGather",
-          [](ProgramBuilder* b) {
-            return b->ExprList(0,                       // component
-                               "texture",               // t
-                               "sampler",               // s
-                               b->vec2<f32>(1.f, 2.f),  // coords
-                               3,                       // array_index
-                               b->vec2<i32>(4, 5));     // offset
-          },
-      },
-      {
-          ValidTextureOverload::kGatherCubeF32,
-          "textureGather(component : i32,\n"
-          "              t         : texture_cube<T>,\n"
-          "              s         : sampler,\n"
-          "              coords    : vec3<f32>) -> vec4<T>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::kCube,
-          TextureDataType::kF32,
-          "textureGather",
-          [](ProgramBuilder* b) {
-            return b->ExprList(0,                             // component
-                               "texture",                     // t
-                               "sampler",                     // s
-                               b->vec3<f32>(1.f, 2.f, 3.f));  // coords
-          },
-      },
-      {
-          ValidTextureOverload::kGatherCubeArrayF32,
-          "textureGather(component   : i32,\n"
-          "              t           : texture_cube_array<T>,\n"
-          "              s           : sampler,\n"
-          "              coords      : vec3<f32>,\n"
-          "              array_index : i32) -> vec4<T>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::kCubeArray,
-          TextureDataType::kF32,
-          "textureGather",
-          [](ProgramBuilder* b) {
-            return b->ExprList(0,                            // component
-                               "texture",                    // t
-                               "sampler",                    // s
-                               b->vec3<f32>(1.f, 2.f, 3.f),  // coords
-                               4);                           // array_index
-          },
-      },
-      {
-          ValidTextureOverload::kGatherDepth2dF32,
-          "textureGather(t      : texture_depth_2d,\n"
-          "              s      : sampler,\n"
-          "              coords : vec2<f32>) -> vec4<f32>",
-          TextureKind::kDepth,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2d,
-          TextureDataType::kF32,
-          "textureGather",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",                // t
-                               "sampler",                // s
-                               b->vec2<f32>(1.f, 2.f));  // coords
-          },
-      },
-      {
-          ValidTextureOverload::kGatherDepth2dOffsetF32,
-          "textureGather(t      : texture_depth_2d,\n"
-          "              s      : sampler,\n"
-          "              coords : vec2<f32>,\n"
-          "              offset : vec2<i32>) -> vec4<f32>",
-          TextureKind::kDepth,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2d,
-          TextureDataType::kF32,
-          "textureGather",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",               // t
-                               "sampler",               // s
-                               b->vec2<f32>(1.f, 2.f),  // coords
-                               b->vec2<i32>(3, 4));     // offset
-          },
-      },
-      {
-          ValidTextureOverload::kGatherDepth2dArrayF32,
-          "textureGather(t           : texture_depth_2d_array,\n"
-          "              s           : sampler,\n"
-          "              coords      : vec2<f32>,\n"
-          "              array_index : i32) -> vec4<f32>",
-          TextureKind::kDepth,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2dArray,
-          TextureDataType::kF32,
-          "textureGather",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",               // t
-                               "sampler",               // s
-                               b->vec2<f32>(1.f, 2.f),  // coords
-                               3);                      // array_index
-          },
-      },
-      {
-          ValidTextureOverload::kGatherDepth2dArrayOffsetF32,
-          "textureGather(t           : texture_depth_2d_array,\n"
-          "              s           : sampler,\n"
-          "              coords      : vec2<f32>,\n"
-          "              array_index : i32,\n"
-          "              offset      : vec2<i32>) -> vec4<f32>",
-          TextureKind::kDepth,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2dArray,
-          TextureDataType::kF32,
-          "textureGather",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",               // t
-                               "sampler",               // s
-                               b->vec2<f32>(1.f, 2.f),  // coords
-                               3,                       // array_index
-                               b->vec2<i32>(4, 5));     // offset
-          },
-      },
-      {
-          ValidTextureOverload::kGatherDepthCubeF32,
-          "textureGather(t      : texture_depth_cube,\n"
-          "              s      : sampler,\n"
-          "              coords : vec3<f32>) -> vec4<f32>",
-          TextureKind::kDepth,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::kCube,
-          TextureDataType::kF32,
-          "textureGather",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",                     // t
-                               "sampler",                     // s
-                               b->vec3<f32>(1.f, 2.f, 3.f));  // coords
-          },
-      },
-      {
-          ValidTextureOverload::kGatherDepthCubeArrayF32,
-          "textureGather(t           : texture_depth_cube_array,\n"
-          "              s           : sampler,\n"
-          "              coords      : vec3<f32>,\n"
-          "              array_index : i32) -> vec4<f32>",
-          TextureKind::kDepth,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::kCubeArray,
-          TextureDataType::kF32,
-          "textureGather",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",                    // t
-                               "sampler",                    // s
-                               b->vec3<f32>(1.f, 2.f, 3.f),  // coords
-                               4);                           // array_index
-          },
-      },
-      {
-          ValidTextureOverload::kGatherCompareDepth2dF32,
-          "textureGatherCompare(t         : texture_depth_2d,\n"
-          "                     s         : sampler_comparison,\n"
-          "                     coords    : vec2<f32>,\n"
-          "                     depth_ref : f32) -> vec4<f32>",
-          TextureKind::kDepth,
-          ast::SamplerKind::kComparisonSampler,
-          ast::TextureDimension::k2d,
-          TextureDataType::kF32,
-          "textureGatherCompare",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",               // t
-                               "sampler",               // s
-                               b->vec2<f32>(1.f, 2.f),  // coords
-                               3.f);                    // depth_ref
-          },
-      },
-      {
-          ValidTextureOverload::kGatherCompareDepth2dOffsetF32,
-          "textureGatherCompare(t         : texture_depth_2d,\n"
-          "                     s         : sampler_comparison,\n"
-          "                     coords    : vec2<f32>,\n"
-          "                     depth_ref : f32,\n"
-          "                     offset    : vec2<i32>) -> vec4<f32>",
-          TextureKind::kDepth,
-          ast::SamplerKind::kComparisonSampler,
-          ast::TextureDimension::k2d,
-          TextureDataType::kF32,
-          "textureGatherCompare",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",               // t
-                               "sampler",               // s
-                               b->vec2<f32>(1.f, 2.f),  // coords
-                               3.f,                     // depth_ref
-                               b->vec2<i32>(4, 5));     // offset
-          },
-      },
-      {
-          ValidTextureOverload::kGatherCompareDepth2dArrayF32,
-          "textureGatherCompare(t           : texture_depth_2d_array,\n"
-          "                     s           : sampler_comparison,\n"
-          "                     coords      : vec2<f32>,\n"
-          "                     array_index : i32,\n"
-          "                     depth_ref   : f32) -> vec4<f32>",
-          TextureKind::kDepth,
-          ast::SamplerKind::kComparisonSampler,
-          ast::TextureDimension::k2dArray,
-          TextureDataType::kF32,
-          "textureGatherCompare",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",               // t
-                               "sampler",               // s
-                               b->vec2<f32>(1.f, 2.f),  // coords
-                               3,                       // array_index
-                               4.f);                    // depth_ref
-          },
-      },
-      {
-          ValidTextureOverload::kGatherCompareDepth2dArrayOffsetF32,
-          "textureGatherCompare(t           : texture_depth_2d_array,\n"
-          "                     s           : sampler_comparison,\n"
-          "                     coords      : vec2<f32>,\n"
-          "                     array_index : i32,\n"
-          "                     depth_ref   : f32,\n"
-          "                     offset      : vec2<i32>) -> vec4<f32>",
-          TextureKind::kDepth,
-          ast::SamplerKind::kComparisonSampler,
-          ast::TextureDimension::k2dArray,
-          TextureDataType::kF32,
-          "textureGatherCompare",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",               // t
-                               "sampler",               // s
-                               b->vec2<f32>(1.f, 2.f),  // coords
-                               3,                       // array_index
-                               4.f,                     // depth_ref
-                               b->vec2<i32>(5, 6));     // offset
-          },
-      },
-      {
-          ValidTextureOverload::kGatherCompareDepthCubeF32,
-          "textureGatherCompare(t         : texture_depth_cube,\n"
-          "                     s         : sampler_comparison,\n"
-          "                     coords    : vec3<f32>,\n"
-          "                     depth_ref : f32) -> vec4<f32>",
-          TextureKind::kDepth,
-          ast::SamplerKind::kComparisonSampler,
-          ast::TextureDimension::kCube,
-          TextureDataType::kF32,
-          "textureGatherCompare",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",                    // t
-                               "sampler",                    // s
-                               b->vec3<f32>(1.f, 2.f, 3.f),  // coords
-                               4.f);                         // depth_ref
-          },
-      },
-      {
-          ValidTextureOverload::kGatherCompareDepthCubeArrayF32,
-          "textureGatherCompare(t           : texture_depth_cube_array,\n"
-          "                     s           : sampler_comparison,\n"
-          "                     coords      : vec3<f32>,\n"
-          "                     array_index : i32,\n"
-          "                     depth_ref   : f32) -> vec4<f32>",
-          TextureKind::kDepth,
-          ast::SamplerKind::kComparisonSampler,
-          ast::TextureDimension::kCubeArray,
-          TextureDataType::kF32,
-          "textureGatherCompare",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",                    // t
-                               "sampler",                    // s
-                               b->vec3<f32>(1.f, 2.f, 3.f),  // coords
-                               4,                            // array_index
-                               5.f);                         // depth_ref
-          },
-      },
-      {
-          ValidTextureOverload::kNumLayers2dArray,
-          "textureNumLayers(t : texture_2d_array<f32>) -> i32",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2dArray,
-          TextureDataType::kF32,
-          "textureNumLayers",
-          [](ProgramBuilder* b) { return b->ExprList("texture"); },
-      },
-      {
-          ValidTextureOverload::kNumLayersCubeArray,
-          "textureNumLayers(t : texture_cube_array<f32>) -> i32",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::kCubeArray,
-          TextureDataType::kF32,
-          "textureNumLayers",
-          [](ProgramBuilder* b) { return b->ExprList("texture"); },
-      },
-      {
-          ValidTextureOverload::kNumLayersDepth2dArray,
-          "textureNumLayers(t : texture_depth_2d_array) -> i32",
-          TextureKind::kDepth,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2dArray,
-          TextureDataType::kF32,
-          "textureNumLayers",
-          [](ProgramBuilder* b) { return b->ExprList("texture"); },
-      },
-      {
-          ValidTextureOverload::kNumLayersDepthCubeArray,
-          "textureNumLayers(t : texture_depth_cube_array) -> i32",
-          TextureKind::kDepth,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::kCubeArray,
-          TextureDataType::kF32,
-          "textureNumLayers",
-          [](ProgramBuilder* b) { return b->ExprList("texture"); },
-      },
-      {
-          ValidTextureOverload::kNumLayersStorageWO2dArray,
-          "textureNumLayers(t : texture_storage_2d_array<rgba32float>) -> i32",
-          ast::Access::kWrite,
-          ast::TexelFormat::kRgba32Float,
-          ast::TextureDimension::k2dArray,
-          TextureDataType::kF32,
-          "textureNumLayers",
-          [](ProgramBuilder* b) { return b->ExprList("texture"); },
-      },
-      {
-          ValidTextureOverload::kNumLevels2d,
-          "textureNumLevels(t : texture_2d<f32>) -> i32",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2d,
-          TextureDataType::kF32,
-          "textureNumLevels",
-          [](ProgramBuilder* b) { return b->ExprList("texture"); },
-      },
-      {
-          ValidTextureOverload::kNumLevels2dArray,
-          "textureNumLevels(t : texture_2d_array<f32>) -> i32",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2dArray,
-          TextureDataType::kF32,
-          "textureNumLevels",
-          [](ProgramBuilder* b) { return b->ExprList("texture"); },
-      },
-      {
-          ValidTextureOverload::kNumLevels3d,
-          "textureNumLevels(t : texture_3d<f32>) -> i32",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k3d,
-          TextureDataType::kF32,
-          "textureNumLevels",
-          [](ProgramBuilder* b) { return b->ExprList("texture"); },
-      },
-      {
-          ValidTextureOverload::kNumLevelsCube,
-          "textureNumLevels(t : texture_cube<f32>) -> i32",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::kCube,
-          TextureDataType::kF32,
-          "textureNumLevels",
-          [](ProgramBuilder* b) { return b->ExprList("texture"); },
-      },
-      {
-          ValidTextureOverload::kNumLevelsCubeArray,
-          "textureNumLevels(t : texture_cube_array<f32>) -> i32",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::kCubeArray,
-          TextureDataType::kF32,
-          "textureNumLevels",
-          [](ProgramBuilder* b) { return b->ExprList("texture"); },
-      },
-      {
-          ValidTextureOverload::kNumLevelsDepth2d,
-          "textureNumLevels(t : texture_depth_2d) -> i32",
-          TextureKind::kDepth,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2d,
-          TextureDataType::kF32,
-          "textureNumLevels",
-          [](ProgramBuilder* b) { return b->ExprList("texture"); },
-      },
-      {
-          ValidTextureOverload::kNumLevelsDepth2dArray,
-          "textureNumLevels(t : texture_depth_2d_array) -> i32",
-          TextureKind::kDepth,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2dArray,
-          TextureDataType::kF32,
-          "textureNumLevels",
-          [](ProgramBuilder* b) { return b->ExprList("texture"); },
-      },
-      {
-          ValidTextureOverload::kNumLevelsDepthCube,
-          "textureNumLevels(t : texture_depth_cube) -> i32",
-          TextureKind::kDepth,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::kCube,
-          TextureDataType::kF32,
-          "textureNumLevels",
-          [](ProgramBuilder* b) { return b->ExprList("texture"); },
-      },
-      {
-          ValidTextureOverload::kNumLevelsDepthCubeArray,
-          "textureNumLevels(t : texture_depth_cube_array) -> i32",
-          TextureKind::kDepth,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::kCubeArray,
-          TextureDataType::kF32,
-          "textureNumLevels",
-          [](ProgramBuilder* b) { return b->ExprList("texture"); },
-      },
-      {
-          ValidTextureOverload::kNumSamplesMultisampled2d,
-          "textureNumSamples(t : texture_multisampled_2d<f32>) -> i32",
-          TextureKind::kMultisampled,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2d,
-          TextureDataType::kF32,
-          "textureNumSamples",
-          [](ProgramBuilder* b) { return b->ExprList("texture"); },
-      },
-      {
-          ValidTextureOverload::kSample1dF32,
-          "textureSample(t      : texture_1d<f32>,\n"
-          "              s      : sampler,\n"
-          "              coords : f32) -> vec4<f32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k1d,
-          TextureDataType::kF32,
-          "textureSample",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",  // t
-                               "sampler",  // s
-                               1.0f);      // coords
-          },
-      },
-      {
-          ValidTextureOverload::kSample2dF32,
-          "textureSample(t      : texture_2d<f32>,\n"
-          "              s      : sampler,\n"
-          "              coords : vec2<f32>) -> vec4<f32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2d,
-          TextureDataType::kF32,
-          "textureSample",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",                // t
-                               "sampler",                // s
-                               b->vec2<f32>(1.f, 2.f));  // coords
-          },
-      },
-      {
-          ValidTextureOverload::kSample2dOffsetF32,
-          "textureSample(t      : texture_2d<f32>,\n"
-          "              s      : sampler,\n"
-          "              coords : vec2<f32>\n"
-          "              offset : vec2<i32>) -> vec4<f32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2d,
-          TextureDataType::kF32,
-          "textureSample",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",               // t
-                               "sampler",               // s
-                               b->vec2<f32>(1.f, 2.f),  // coords
-                               b->vec2<i32>(3, 4));     // offset
-          },
-      },
-      {
-          ValidTextureOverload::kSample2dArrayF32,
-          "textureSample(t           : texture_2d_array<f32>,\n"
-          "              s           : sampler,\n"
-          "              coords      : vec2<f32>,\n"
-          "              array_index : i32) -> vec4<f32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2dArray,
-          TextureDataType::kF32,
-          "textureSample",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",               // t
-                               "sampler",               // s
-                               b->vec2<f32>(1.f, 2.f),  // coords
-                               3);                      // array_index
-          },
-      },
-      {
-          ValidTextureOverload::kSample2dArrayOffsetF32,
-          "textureSample(t           : texture_2d_array<f32>,\n"
-          "              s           : sampler,\n"
-          "              coords      : vec2<f32>,\n"
-          "              array_index : i32\n"
-          "              offset      : vec2<i32>) -> vec4<f32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2dArray,
-          TextureDataType::kF32,
-          "textureSample",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",               // t
-                               "sampler",               // s
-                               b->vec2<f32>(1.f, 2.f),  // coords
-                               3,                       // array_index
-                               b->vec2<i32>(4, 5));     // offset
-          },
-      },
-      {
-          ValidTextureOverload::kSample3dF32,
-          "textureSample(t      : texture_3d<f32>,\n"
-          "              s      : sampler,\n"
-          "              coords : vec3<f32>) -> vec4<f32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k3d,
-          TextureDataType::kF32,
-          "textureSample",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",                     // t
-                               "sampler",                     // s
-                               b->vec3<f32>(1.f, 2.f, 3.f));  // coords
-          },
-      },
-      {
-          ValidTextureOverload::kSample3dOffsetF32,
-          "textureSample(t      : texture_3d<f32>,\n"
-          "              s      : sampler,\n"
-          "              coords : vec3<f32>\n"
-          "              offset : vec3<i32>) -> vec4<f32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k3d,
-          TextureDataType::kF32,
-          "textureSample",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",                    // t
-                               "sampler",                    // s
-                               b->vec3<f32>(1.f, 2.f, 3.f),  // coords
-                               b->vec3<i32>(4, 5, 6));       // offset
-          },
-      },
-      {
-          ValidTextureOverload::kSampleCubeF32,
-          "textureSample(t      : texture_cube<f32>,\n"
-          "              s      : sampler,\n"
-          "              coords : vec3<f32>) -> vec4<f32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::kCube,
-          TextureDataType::kF32,
-          "textureSample",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",                     // t
-                               "sampler",                     // s
-                               b->vec3<f32>(1.f, 2.f, 3.f));  // coords
-          },
-      },
-      {
-          ValidTextureOverload::kSampleCubeArrayF32,
-          "textureSample(t           : texture_cube_array<f32>,\n"
-          "              s           : sampler,\n"
-          "              coords      : vec3<f32>,\n"
-          "              array_index : i32) -> vec4<f32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::kCubeArray,
-          TextureDataType::kF32,
-          "textureSample",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",                    // t
-                               "sampler",                    // s
-                               b->vec3<f32>(1.f, 2.f, 3.f),  // coords
-                               4);                           // array_index
-          },
-      },
-      {
-          ValidTextureOverload::kSampleDepth2dF32,
-          "textureSample(t      : texture_depth_2d,\n"
-          "              s      : sampler,\n"
-          "              coords : vec2<f32>) -> f32",
-          TextureKind::kDepth,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2d,
-          TextureDataType::kF32,
-          "textureSample",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",                // t
-                               "sampler",                // s
-                               b->vec2<f32>(1.f, 2.f));  // coords
-          },
-      },
-      {
-          ValidTextureOverload::kSampleDepth2dOffsetF32,
-          "textureSample(t      : texture_depth_2d,\n"
-          "              s      : sampler,\n"
-          "              coords : vec2<f32>\n"
-          "              offset : vec2<i32>) -> f32",
-          TextureKind::kDepth,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2d,
-          TextureDataType::kF32,
-          "textureSample",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",               // t
-                               "sampler",               // s
-                               b->vec2<f32>(1.f, 2.f),  // coords
-                               b->vec2<i32>(3, 4));     // offset
-          },
-      },
-      {
-          ValidTextureOverload::kSampleDepth2dArrayF32,
-          "textureSample(t           : texture_depth_2d_array,\n"
-          "              s           : sampler,\n"
-          "              coords      : vec2<f32>,\n"
-          "              array_index : i32) -> f32",
-          TextureKind::kDepth,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2dArray,
-          TextureDataType::kF32,
-          "textureSample",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",               // t
-                               "sampler",               // s
-                               b->vec2<f32>(1.f, 2.f),  // coords
-                               3);                      // array_index
-          },
-      },
-      {
-          ValidTextureOverload::kSampleDepth2dArrayOffsetF32,
-          "textureSample(t           : texture_depth_2d_array,\n"
-          "              s           : sampler,\n"
-          "              coords      : vec2<f32>,\n"
-          "              array_index : i32\n"
-          "              offset      : vec2<i32>) -> f32",
-          TextureKind::kDepth,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2dArray,
-          TextureDataType::kF32,
-          "textureSample",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",               // t
-                               "sampler",               // s
-                               b->vec2<f32>(1.f, 2.f),  // coords
-                               3,                       // array_index
-                               b->vec2<i32>(4, 5));     // offset
-          },
-      },
-      {
-          ValidTextureOverload::kSampleDepthCubeF32,
-          "textureSample(t      : texture_depth_cube,\n"
-          "              s      : sampler,\n"
-          "              coords : vec3<f32>) -> f32",
-          TextureKind::kDepth,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::kCube,
-          TextureDataType::kF32,
-          "textureSample",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",                     // t
-                               "sampler",                     // s
-                               b->vec3<f32>(1.f, 2.f, 3.f));  // coords
-          },
-      },
-      {
-          ValidTextureOverload::kSampleDepthCubeArrayF32,
-          "textureSample(t           : texture_depth_cube_array,\n"
-          "              s           : sampler,\n"
-          "              coords      : vec3<f32>,\n"
-          "              array_index : i32) -> f32",
-          TextureKind::kDepth,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::kCubeArray,
-          TextureDataType::kF32,
-          "textureSample",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",                    // t
-                               "sampler",                    // s
-                               b->vec3<f32>(1.f, 2.f, 3.f),  // coords
-                               4);                           // array_index
-          },
-      },
-      {
-          ValidTextureOverload::kSampleBias2dF32,
-          "textureSampleBias(t      : texture_2d<f32>,\n"
-          "                  s      : sampler,\n"
-          "                  coords : vec2<f32>,\n"
-          "                  bias   : f32) -> vec4<f32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2d,
-          TextureDataType::kF32,
-          "textureSampleBias",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",               // t
-                               "sampler",               // s
-                               b->vec2<f32>(1.f, 2.f),  // coords
-                               3.f);                    // bias
-          },
-      },
-      {
-          ValidTextureOverload::kSampleBias2dOffsetF32,
-          "textureSampleBias(t      : texture_2d<f32>,\n"
-          "                  s      : sampler,\n"
-          "                  coords : vec2<f32>,\n"
-          "                  bias   : f32,\n"
-          "                  offset : vec2<i32>) -> vec4<f32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2d,
-          TextureDataType::kF32,
-          "textureSampleBias",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",               // t
-                               "sampler",               // s
-                               b->vec2<f32>(1.f, 2.f),  // coords
-                               3.f,                     // bias
-                               b->vec2<i32>(4, 5));     // offset
-          },
-      },
-      {
-          ValidTextureOverload::kSampleBias2dArrayF32,
-          "textureSampleBias(t           : texture_2d_array<f32>,\n"
-          "                  s           : sampler,\n"
-          "                  coords      : vec2<f32>,\n"
-          "                  array_index : i32,\n"
-          "                  bias        : f32) -> vec4<f32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2dArray,
-          TextureDataType::kF32,
-          "textureSampleBias",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",               // t
-                               "sampler",               // s
-                               b->vec2<f32>(1.f, 2.f),  // coords
-                               4,                       // array_index
-                               3.f);                    // bias
-          },
-      },
-      {
-          ValidTextureOverload::kSampleBias2dArrayOffsetF32,
-          "textureSampleBias(t           : texture_2d_array<f32>,\n"
-          "                  s           : sampler,\n"
-          "                  coords      : vec2<f32>,\n"
-          "                  array_index : i32,\n"
-          "                  bias        : f32,\n"
-          "                  offset      : vec2<i32>) -> vec4<f32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2dArray,
-          TextureDataType::kF32,
-          "textureSampleBias",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",               // t
-                               "sampler",               // s
-                               b->vec2<f32>(1.f, 2.f),  // coords
-                               3,                       // array_index
-                               4.f,                     // bias
-                               b->vec2<i32>(5, 6));     // offset
-          },
-      },
-      {
-          ValidTextureOverload::kSampleBias3dF32,
-          "textureSampleBias(t      : texture_3d<f32>,\n"
-          "                  s      : sampler,\n"
-          "                  coords : vec3<f32>,\n"
-          "                  bias   : f32) -> vec4<f32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k3d,
-          TextureDataType::kF32,
-          "textureSampleBias",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",                    // t
-                               "sampler",                    // s
-                               b->vec3<f32>(1.f, 2.f, 3.f),  // coords
-                               4.f);                         // bias
-          },
-      },
-      {
-          ValidTextureOverload::kSampleBias3dOffsetF32,
-          "textureSampleBias(t      : texture_3d<f32>,\n"
-          "                  s      : sampler,\n"
-          "                  coords : vec3<f32>,\n"
-          "                  bias   : f32,\n"
-          "                  offset : vec3<i32>) -> vec4<f32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k3d,
-          TextureDataType::kF32,
-          "textureSampleBias",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",                    // t
-                               "sampler",                    // s
-                               b->vec3<f32>(1.f, 2.f, 3.f),  // coords
-                               4.f,                          // bias
-                               b->vec3<i32>(5, 6, 7));       // offset
-          },
-      },
-      {
-          ValidTextureOverload::kSampleBiasCubeF32,
-          "textureSampleBias(t      : texture_cube<f32>,\n"
-          "                  s      : sampler,\n"
-          "                  coords : vec3<f32>,\n"
-          "                  bias   : f32) -> vec4<f32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::kCube,
-          TextureDataType::kF32,
-          "textureSampleBias",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",                    // t
-                               "sampler",                    // s
-                               b->vec3<f32>(1.f, 2.f, 3.f),  // coords
-                               4.f);                         // bias
-          },
-      },
-      {
-          ValidTextureOverload::kSampleBiasCubeArrayF32,
-          "textureSampleBias(t           : texture_cube_array<f32>,\n"
-          "                  s           : sampler,\n"
-          "                  coords      : vec3<f32>,\n"
-          "                  array_index : i32,\n"
-          "                  bias        : f32) -> vec4<f32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::kCubeArray,
-          TextureDataType::kF32,
-          "textureSampleBias",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",                    // t
-                               "sampler",                    // s
-                               b->vec3<f32>(1.f, 2.f, 3.f),  // coords
-                               3,                            // array_index
-                               4.f);                         // bias
-          },
-      },
-      {
-          ValidTextureOverload::kSampleLevel2dF32,
-          "textureSampleLevel(t      : texture_2d<f32>,\n"
-          "                   s      : sampler,\n"
-          "                   coords : vec2<f32>,\n"
-          "                   level  : f32) -> vec4<f32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2d,
-          TextureDataType::kF32,
-          "textureSampleLevel",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",               // t
-                               "sampler",               // s
-                               b->vec2<f32>(1.f, 2.f),  // coords
-                               3.f);                    // level
-          },
-      },
-      {
-          ValidTextureOverload::kSampleLevel2dOffsetF32,
-          "textureSampleLevel(t      : texture_2d<f32>,\n"
-          "                   s      : sampler,\n"
-          "                   coords : vec2<f32>,\n"
-          "                   level  : f32,\n"
-          "                   offset : vec2<i32>) -> vec4<f32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2d,
-          TextureDataType::kF32,
-          "textureSampleLevel",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",               // t
-                               "sampler",               // s
-                               b->vec2<f32>(1.f, 2.f),  // coords
-                               3.f,                     // level
-                               b->vec2<i32>(4, 5));     // offset
-          },
-      },
-      {
-          ValidTextureOverload::kSampleLevel2dArrayF32,
-          "textureSampleLevel(t           : texture_2d_array<f32>,\n"
-          "                   s           : sampler,\n"
-          "                   coords      : vec2<f32>,\n"
-          "                   array_index : i32,\n"
-          "                   level       : f32) -> vec4<f32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2dArray,
-          TextureDataType::kF32,
-          "textureSampleLevel",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",               // t
-                               "sampler",               // s
-                               b->vec2<f32>(1.f, 2.f),  // coords
-                               3,                       // array_index
-                               4.f);                    // level
-          },
-      },
-      {
-          ValidTextureOverload::kSampleLevel2dArrayOffsetF32,
-          "textureSampleLevel(t           : texture_2d_array<f32>,\n"
-          "                   s           : sampler,\n"
-          "                   coords      : vec2<f32>,\n"
-          "                   array_index : i32,\n"
-          "                   level       : f32,\n"
-          "                   offset      : vec2<i32>) -> vec4<f32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2dArray,
-          TextureDataType::kF32,
-          "textureSampleLevel",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",               // t
-                               "sampler",               // s
-                               b->vec2<f32>(1.f, 2.f),  // coords
-                               3,                       // array_index
-                               4.f,                     // level
-                               b->vec2<i32>(5, 6));     // offset
-          },
-      },
-      {
-          ValidTextureOverload::kSampleLevel3dF32,
-          "textureSampleLevel(t      : texture_3d<f32>,\n"
-          "                   s      : sampler,\n"
-          "                   coords : vec3<f32>,\n"
-          "                   level  : f32) -> vec4<f32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k3d,
-          TextureDataType::kF32,
-          "textureSampleLevel",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",                    // t
-                               "sampler",                    // s
-                               b->vec3<f32>(1.f, 2.f, 3.f),  // coords
-                               4.f);                         // level
-          },
-      },
-      {
-          ValidTextureOverload::kSampleLevel3dOffsetF32,
-          "textureSampleLevel(t      : texture_3d<f32>,\n"
-          "                   s      : sampler,\n"
-          "                   coords : vec3<f32>,\n"
-          "                   level  : f32,\n"
-          "                   offset : vec3<i32>) -> vec4<f32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k3d,
-          TextureDataType::kF32,
-          "textureSampleLevel",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",                    // t
-                               "sampler",                    // s
-                               b->vec3<f32>(1.f, 2.f, 3.f),  // coords
-                               4.f,                          // level
-                               b->vec3<i32>(5, 6, 7));       // offset
-          },
-      },
-      {
-          ValidTextureOverload::kSampleLevelCubeF32,
-          "textureSampleLevel(t      : texture_cube<f32>,\n"
-          "                   s      : sampler,\n"
-          "                   coords : vec3<f32>,\n"
-          "                   level  : f32) -> vec4<f32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::kCube,
-          TextureDataType::kF32,
-          "textureSampleLevel",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",                    // t
-                               "sampler",                    // s
-                               b->vec3<f32>(1.f, 2.f, 3.f),  // coords
-                               4.f);                         // level
-          },
-      },
-      {
-          ValidTextureOverload::kSampleLevelCubeArrayF32,
-          "textureSampleLevel(t           : texture_cube_array<f32>,\n"
-          "                   s           : sampler,\n"
-          "                   coords      : vec3<f32>,\n"
-          "                   array_index : i32,\n"
-          "                   level       : f32) -> vec4<f32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::kCubeArray,
-          TextureDataType::kF32,
-          "textureSampleLevel",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",                    // t
-                               "sampler",                    // s
-                               b->vec3<f32>(1.f, 2.f, 3.f),  // coords
-                               4,                            // array_index
-                               5.f);                         // level
-          },
-      },
-      {
-          ValidTextureOverload::kSampleLevelDepth2dF32,
-          "textureSampleLevel(t      : texture_depth_2d,\n"
-          "                   s      : sampler,\n"
-          "                   coords : vec2<f32>,\n"
-          "                   level  : i32) -> f32",
-          TextureKind::kDepth,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2d,
-          TextureDataType::kF32,
-          "textureSampleLevel",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",               // t
-                               "sampler",               // s
-                               b->vec2<f32>(1.f, 2.f),  // coords
-                               3);                      // level
-          },
-      },
-      {
-          ValidTextureOverload::kSampleLevelDepth2dOffsetF32,
-          "textureSampleLevel(t      : texture_depth_2d,\n"
-          "                   s      : sampler,\n"
-          "                   coords : vec2<f32>,\n"
-          "                   level  : i32,\n"
-          "                   offset : vec2<i32>) -> f32",
-          TextureKind::kDepth,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2d,
-          TextureDataType::kF32,
-          "textureSampleLevel",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",               // t
-                               "sampler",               // s
-                               b->vec2<f32>(1.f, 2.f),  // coords
-                               3,                       // level
-                               b->vec2<i32>(4, 5));     // offset
-          },
-      },
-      {
-          ValidTextureOverload::kSampleLevelDepth2dArrayF32,
-          "textureSampleLevel(t           : texture_depth_2d_array,\n"
-          "                   s           : sampler,\n"
-          "                   coords      : vec2<f32>,\n"
-          "                   array_index : i32,\n"
-          "                   level       : i32) -> f32",
-          TextureKind::kDepth,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2dArray,
-          TextureDataType::kF32,
-          "textureSampleLevel",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",               // t
-                               "sampler",               // s
-                               b->vec2<f32>(1.f, 2.f),  // coords
-                               3,                       // array_index
-                               4);                      // level
-          },
-      },
-      {
-          ValidTextureOverload::kSampleLevelDepth2dArrayOffsetF32,
-          "textureSampleLevel(t           : texture_depth_2d_array,\n"
-          "                   s           : sampler,\n"
-          "                   coords      : vec2<f32>,\n"
-          "                   array_index : i32,\n"
-          "                   level       : i32,\n"
-          "                   offset      : vec2<i32>) -> f32",
-          TextureKind::kDepth,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2dArray,
-          TextureDataType::kF32,
-          "textureSampleLevel",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",               // t
-                               "sampler",               // s
-                               b->vec2<f32>(1.f, 2.f),  // coords
-                               3,                       // array_index
-                               4,                       // level
-                               b->vec2<i32>(5, 6));     // offset
-          },
-      },
-      {
-          ValidTextureOverload::kSampleLevelDepthCubeF32,
-          "textureSampleLevel(t      : texture_depth_cube,\n"
-          "                   s      : sampler,\n"
-          "                   coords : vec3<f32>,\n"
-          "                   level  : i32) -> f32",
-          TextureKind::kDepth,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::kCube,
-          TextureDataType::kF32,
-          "textureSampleLevel",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",                    // t
-                               "sampler",                    // s
-                               b->vec3<f32>(1.f, 2.f, 3.f),  // coords
-                               4);                           // level
-          },
-      },
-      {
-          ValidTextureOverload::kSampleLevelDepthCubeArrayF32,
-          "textureSampleLevel(t           : texture_depth_cube_array,\n"
-          "                   s           : sampler,\n"
-          "                   coords      : vec3<f32>,\n"
-          "                   array_index : i32,\n"
-          "                   level       : i32) -> f32",
-          TextureKind::kDepth,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::kCubeArray,
-          TextureDataType::kF32,
-          "textureSampleLevel",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",                    // t
-                               "sampler",                    // s
-                               b->vec3<f32>(1.f, 2.f, 3.f),  // coords
-                               4,                            // array_index
-                               5);                           // level
-          },
-      },
-      {
-          ValidTextureOverload::kSampleGrad2dF32,
-          "textureSampleGrad(t      : texture_2d<f32>,\n"
-          "                  s      : sampler,\n"
-          "                  coords : vec2<f32>\n"
-          "                  ddx    : vec2<f32>,\n"
-          "                  ddy    : vec2<f32>) -> vec4<f32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2d,
-          TextureDataType::kF32,
-          "textureSampleGrad",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",                  // t
-                               "sampler",                  // s
-                               b->vec2<f32>(1.0f, 2.0f),   // coords
-                               b->vec2<f32>(3.0f, 4.0f),   // ddx
-                               b->vec2<f32>(5.0f, 6.0f));  // ddy
-          },
-      },
-      {
-          ValidTextureOverload::kSampleGrad2dOffsetF32,
-          "textureSampleGrad(t      : texture_2d<f32>,\n"
-          "                  s      : sampler,\n"
-          "                  coords : vec2<f32>,\n"
-          "                  ddx    : vec2<f32>,\n"
-          "                  ddy    : vec2<f32>,\n"
-          "                  offset : vec2<i32>) -> vec4<f32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2d,
-          TextureDataType::kF32,
-          "textureSampleGrad",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",               // t
-                               "sampler",               // s
-                               b->vec2<f32>(1.f, 2.f),  // coords
-                               b->vec2<f32>(3.f, 4.f),  // ddx
-                               b->vec2<f32>(5.f, 6.f),  // ddy
-                               b->vec2<i32>(7, 7));     // offset
-          },
-      },
-      {
-          ValidTextureOverload::kSampleGrad2dArrayF32,
-          "textureSampleGrad(t           : texture_2d_array<f32>,\n"
-          "                  s           : sampler,\n"
-          "                  coords      : vec2<f32>,\n"
-          "                  array_index : i32,\n"
-          "                  ddx         : vec2<f32>,\n"
-          "                  ddy         : vec2<f32>) -> vec4<f32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2dArray,
-          TextureDataType::kF32,
-          "textureSampleGrad",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",                // t
-                               "sampler",                // s
-                               b->vec2<f32>(1.f, 2.f),   // coords
-                               3,                        // array_index
-                               b->vec2<f32>(4.f, 5.f),   // ddx
-                               b->vec2<f32>(6.f, 7.f));  // ddy
-          },
-      },
-      {
-          ValidTextureOverload::kSampleGrad2dArrayOffsetF32,
-          "textureSampleGrad(t           : texture_2d_array<f32>,\n"
-          "                  s           : sampler,\n"
-          "                  coords      : vec2<f32>,\n"
-          "                  array_index : i32,\n"
-          "                  ddx         : vec2<f32>,\n"
-          "                  ddy         : vec2<f32>,\n"
-          "                  offset      : vec2<i32>) -> vec4<f32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k2dArray,
-          TextureDataType::kF32,
-          "textureSampleGrad",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",               // t
-                               "sampler",               // s
-                               b->vec2<f32>(1.f, 2.f),  // coords
-                               3,                       // array_index
-                               b->vec2<f32>(4.f, 5.f),  // ddx
-                               b->vec2<f32>(6.f, 7.f),  // ddy
-                               b->vec2<i32>(6, 7));     // offset
-          },
-      },
-      {
-          ValidTextureOverload::kSampleGrad3dF32,
-          "textureSampleGrad(t      : texture_3d<f32>,\n"
-          "                  s      : sampler,\n"
-          "                  coords : vec3<f32>,\n"
-          "                  ddx    : vec3<f32>,\n"
-          "                  ddy    : vec3<f32>) -> vec4<f32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k3d,
-          TextureDataType::kF32,
-          "textureSampleGrad",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",                     // t
-                               "sampler",                     // s
-                               b->vec3<f32>(1.f, 2.f, 3.f),   // coords
-                               b->vec3<f32>(4.f, 5.f, 6.f),   // ddx
-                               b->vec3<f32>(7.f, 8.f, 9.f));  // ddy
-          },
-      },
-      {
-          ValidTextureOverload::kSampleGrad3dOffsetF32,
-          "textureSampleGrad(t      : texture_3d<f32>,\n"
-          "                  s      : sampler,\n"
-          "                  coords : vec3<f32>,\n"
-          "                  ddx    : vec3<f32>,\n"
-          "                  ddy    : vec3<f32>,\n"
-          "                  offset : vec3<i32>) -> vec4<f32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::k3d,
-          TextureDataType::kF32,
-          "textureSampleGrad",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",                    // t
-                               "sampler",                    // s
-                               b->vec3<f32>(1.f, 2.f, 3.f),  // coords
-                               b->vec3<f32>(4.f, 5.f, 6.f),  // ddx
-                               b->vec3<f32>(7.f, 8.f, 9.f),  // ddy
-                               b->vec3<i32>(0, 1, 2));       // offset
-          },
-      },
-      {
-          ValidTextureOverload::kSampleGradCubeF32,
-          "textureSampleGrad(t      : texture_cube<f32>,\n"
-          "                  s      : sampler,\n"
-          "                  coords : vec3<f32>,\n"
-          "                  ddx    : vec3<f32>,\n"
-          "                  ddy    : vec3<f32>) -> vec4<f32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::kCube,
-          TextureDataType::kF32,
-          "textureSampleGrad",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",                     // t
-                               "sampler",                     // s
-                               b->vec3<f32>(1.f, 2.f, 3.f),   // coords
-                               b->vec3<f32>(4.f, 5.f, 6.f),   // ddx
-                               b->vec3<f32>(7.f, 8.f, 9.f));  // ddy
-          },
-      },
-      {
-          ValidTextureOverload::kSampleGradCubeArrayF32,
-          "textureSampleGrad(t           : texture_cube_array<f32>,\n"
-          "                  s           : sampler,\n"
-          "                  coords      : vec3<f32>,\n"
-          "                  array_index : i32,\n"
-          "                  ddx         : vec3<f32>,\n"
-          "                  ddy         : vec3<f32>) -> vec4<f32>",
-          TextureKind::kRegular,
-          ast::SamplerKind::kSampler,
-          ast::TextureDimension::kCubeArray,
-          TextureDataType::kF32,
-          "textureSampleGrad",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",                      // t
-                               "sampler",                      // s
-                               b->vec3<f32>(1.f, 2.f, 3.f),    // coords
-                               4,                              // array_index
-                               b->vec3<f32>(5.f, 6.f, 7.f),    // ddx
-                               b->vec3<f32>(8.f, 9.f, 10.f));  // ddy
-          },
-      },
-      {
-          ValidTextureOverload::kSampleCompareDepth2dF32,
-          "textureSampleCompare(t         : texture_depth_2d,\n"
-          "                     s         : sampler_comparison,\n"
-          "                     coords    : vec2<f32>,\n"
-          "                     depth_ref : f32) -> f32",
-          TextureKind::kDepth,
-          ast::SamplerKind::kComparisonSampler,
-          ast::TextureDimension::k2d,
-          TextureDataType::kF32,
-          "textureSampleCompare",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",               // t
-                               "sampler",               // s
-                               b->vec2<f32>(1.f, 2.f),  // coords
-                               3.f);                    // depth_ref
-          },
-      },
-      {
-          ValidTextureOverload::kSampleCompareDepth2dOffsetF32,
-          "textureSampleCompare(t         : texture_depth_2d,\n"
-          "                     s         : sampler_comparison,\n"
-          "                     coords    : vec2<f32>,\n"
-          "                     depth_ref : f32,\n"
-          "                     offset    : vec2<i32>) -> f32",
-          TextureKind::kDepth,
-          ast::SamplerKind::kComparisonSampler,
-          ast::TextureDimension::k2d,
-          TextureDataType::kF32,
-          "textureSampleCompare",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",               // t
-                               "sampler",               // s
-                               b->vec2<f32>(1.f, 2.f),  // coords
-                               3.f,                     // depth_ref
-                               b->vec2<i32>(4, 5));     // offset
-          },
-      },
-      {
-          ValidTextureOverload::kSampleCompareDepth2dArrayF32,
-          "textureSampleCompare(t           : texture_depth_2d_array,\n"
-          "                     s           : sampler_comparison,\n"
-          "                     coords      : vec2<f32>,\n"
-          "                     array_index : i32,\n"
-          "                     depth_ref   : f32) -> f32",
-          TextureKind::kDepth,
-          ast::SamplerKind::kComparisonSampler,
-          ast::TextureDimension::k2dArray,
-          TextureDataType::kF32,
-          "textureSampleCompare",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",               // t
-                               "sampler",               // s
-                               b->vec2<f32>(1.f, 2.f),  // coords
-                               4,                       // array_index
-                               3.f);                    // depth_ref
-          },
-      },
-      {
-          ValidTextureOverload::kSampleCompareDepth2dArrayOffsetF32,
-          "textureSampleCompare(t           : texture_depth_2d_array,\n"
-          "                     s           : sampler_comparison,\n"
-          "                     coords      : vec2<f32>,\n"
-          "                     array_index : i32,\n"
-          "                     depth_ref   : f32,\n"
-          "                     offset      : vec2<i32>) -> f32",
-          TextureKind::kDepth,
-          ast::SamplerKind::kComparisonSampler,
-          ast::TextureDimension::k2dArray,
-          TextureDataType::kF32,
-          "textureSampleCompare",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",               // t
-                               "sampler",               // s
-                               b->vec2<f32>(1.f, 2.f),  // coords
-                               4,                       // array_index
-                               3.f,                     // depth_ref
-                               b->vec2<i32>(5, 6));     // offset
-          },
-      },
-      {
-          ValidTextureOverload::kSampleCompareDepthCubeF32,
-          "textureSampleCompare(t         : texture_depth_cube,\n"
-          "                     s         : sampler_comparison,\n"
-          "                     coords    : vec3<f32>,\n"
-          "                     depth_ref : f32) -> f32",
-          TextureKind::kDepth,
-          ast::SamplerKind::kComparisonSampler,
-          ast::TextureDimension::kCube,
-          TextureDataType::kF32,
-          "textureSampleCompare",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",                    // t
-                               "sampler",                    // s
-                               b->vec3<f32>(1.f, 2.f, 3.f),  // coords
-                               4.f);                         // depth_ref
-          },
-      },
-      {
-          ValidTextureOverload::kSampleCompareDepthCubeArrayF32,
-          "textureSampleCompare(t           : texture_depth_cube_array,\n"
-          "                     s           : sampler_comparison,\n"
-          "                     coords      : vec3<f32>,\n"
-          "                     array_index : i32,\n"
-          "                     depth_ref   : f32) -> f32",
-          TextureKind::kDepth,
-          ast::SamplerKind::kComparisonSampler,
-          ast::TextureDimension::kCubeArray,
-          TextureDataType::kF32,
-          "textureSampleCompare",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",                    // t
-                               "sampler",                    // s
-                               b->vec3<f32>(1.f, 2.f, 3.f),  // coords
-                               4,                            // array_index
-                               5.f);                         // depth_ref
-          },
-      },
-      {
-          ValidTextureOverload::kLoad1dLevelF32,
-          "textureLoad(t      : texture_1d<f32>,\n"
-          "            coords : i32,\n"
-          "            level  : i32) -> vec4<f32>",
-          TextureKind::kRegular,
-          ast::TextureDimension::k1d,
-          TextureDataType::kF32,
-          "textureLoad",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",  // t
-                               1,          // coords
-                               3);         // level
-          },
-      },
-      {
-          ValidTextureOverload::kLoad1dLevelU32,
-          "textureLoad(t      : texture_1d<u32>,\n"
-          "            coords : i32,\n"
-          "            level  : i32) -> vec4<u32>",
-          TextureKind::kRegular,
-          ast::TextureDimension::k1d,
-          TextureDataType::kU32,
-          "textureLoad",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",  // t
-                               1,          // coords
-                               3);         // level
-          },
-      },
-      {
-          ValidTextureOverload::kLoad1dLevelI32,
-          "textureLoad(t      : texture_1d<i32>,\n"
-          "            coords : i32,\n"
-          "            level  : i32) -> vec4<i32>",
-          TextureKind::kRegular,
-          ast::TextureDimension::k1d,
-          TextureDataType::kI32,
-          "textureLoad",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",  // t
-                               1,          // coords
-                               3);         // level
-          },
-      },
-      {
-          ValidTextureOverload::kLoad2dLevelF32,
-          "textureLoad(t      : texture_2d<f32>,\n"
-          "            coords : vec2<i32>,\n"
-          "            level  : i32) -> vec4<f32>",
-          TextureKind::kRegular,
-          ast::TextureDimension::k2d,
-          TextureDataType::kF32,
-          "textureLoad",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",           // t
-                               b->vec2<i32>(1, 2),  // coords
-                               3);                  // level
-          },
-      },
-      {
-          ValidTextureOverload::kLoad2dLevelU32,
-          "textureLoad(t      : texture_2d<u32>,\n"
-          "            coords : vec2<i32>,\n"
-          "            level  : i32) -> vec4<u32>",
-          TextureKind::kRegular,
-          ast::TextureDimension::k2d,
-          TextureDataType::kU32,
-          "textureLoad",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",           // t
-                               b->vec2<i32>(1, 2),  // coords
-                               3);                  // level
-          },
-      },
-      {
-          ValidTextureOverload::kLoad2dLevelI32,
-          "textureLoad(t      : texture_2d<i32>,\n"
-          "            coords : vec2<i32>,\n"
-          "            level  : i32) -> vec4<i32>",
-          TextureKind::kRegular,
-          ast::TextureDimension::k2d,
-          TextureDataType::kI32,
-          "textureLoad",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",           // t
-                               b->vec2<i32>(1, 2),  // coords
-                               3);                  // level
-          },
-      },
-      {
-          ValidTextureOverload::kLoad2dArrayLevelF32,
-          "textureLoad(t           : texture_2d_array<f32>,\n"
-          "            coords      : vec2<i32>,\n"
-          "            array_index : i32,\n"
-          "            level       : i32) -> vec4<f32>",
-          TextureKind::kRegular,
-          ast::TextureDimension::k2dArray,
-          TextureDataType::kF32,
-          "textureLoad",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",           // t
-                               b->vec2<i32>(1, 2),  // coords
-                               3,                   // array_index
-                               4);                  // level
-          },
-      },
-      {
-          ValidTextureOverload::kLoad2dArrayLevelU32,
-          "textureLoad(t           : texture_2d_array<u32>,\n"
-          "            coords      : vec2<i32>,\n"
-          "            array_index : i32,\n"
-          "            level       : i32) -> vec4<u32>",
-          TextureKind::kRegular,
-          ast::TextureDimension::k2dArray,
-          TextureDataType::kU32,
-          "textureLoad",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",           // t
-                               b->vec2<i32>(1, 2),  // coords
-                               3,                   // array_index
-                               4);                  // level
-          },
-      },
-      {
-          ValidTextureOverload::kLoad2dArrayLevelI32,
-          "textureLoad(t           : texture_2d_array<i32>,\n"
-          "            coords      : vec2<i32>,\n"
-          "            array_index : i32,\n"
-          "            level       : i32) -> vec4<i32>",
-          TextureKind::kRegular,
-          ast::TextureDimension::k2dArray,
-          TextureDataType::kI32,
-          "textureLoad",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",           // t
-                               b->vec2<i32>(1, 2),  // coords
-                               3,                   // array_index
-                               4);                  // level
-          },
-      },
-      {
-          ValidTextureOverload::kLoad3dLevelF32,
-          "textureLoad(t      : texture_3d<f32>,\n"
-          "            coords : vec3<i32>,\n"
-          "            level  : i32) -> vec4<f32>",
-          TextureKind::kRegular,
-          ast::TextureDimension::k3d,
-          TextureDataType::kF32,
-          "textureLoad",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",              // t
-                               b->vec3<i32>(1, 2, 3),  // coords
-                               4);                     // level
-          },
-      },
-      {
-          ValidTextureOverload::kLoad3dLevelU32,
-          "textureLoad(t      : texture_3d<u32>,\n"
-          "            coords : vec3<i32>,\n"
-          "            level  : i32) -> vec4<u32>",
-          TextureKind::kRegular,
-          ast::TextureDimension::k3d,
-          TextureDataType::kU32,
-          "textureLoad",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",              // t
-                               b->vec3<i32>(1, 2, 3),  // coords
-                               4);                     // level
-          },
-      },
-      {
-          ValidTextureOverload::kLoad3dLevelI32,
-          "textureLoad(t      : texture_3d<i32>,\n"
-          "            coords : vec3<i32>,\n"
-          "            level  : i32) -> vec4<i32>",
-          TextureKind::kRegular,
-          ast::TextureDimension::k3d,
-          TextureDataType::kI32,
-          "textureLoad",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",              // t
-                               b->vec3<i32>(1, 2, 3),  // coords
-                               4);                     // level
-          },
-      },
-      {
-          ValidTextureOverload::kLoadMultisampled2dF32,
-          "textureLoad(t            : texture_multisampled_2d<f32>,\n"
-          "            coords       : vec2<i32>,\n"
-          "            sample_index : i32) -> vec4<f32>",
-          TextureKind::kMultisampled,
-          ast::TextureDimension::k2d,
-          TextureDataType::kF32,
-          "textureLoad",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",           // t
-                               b->vec2<i32>(1, 2),  // coords
-                               3);                  // sample_index
-          },
-      },
-      {
-          ValidTextureOverload::kLoadMultisampled2dU32,
-          "textureLoad(t            : texture_multisampled_2d<u32>,\n"
-          "            coords       : vec2<i32>,\n"
-          "            sample_index : i32) -> vec4<u32>",
-          TextureKind::kMultisampled,
-          ast::TextureDimension::k2d,
-          TextureDataType::kU32,
-          "textureLoad",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",           // t
-                               b->vec2<i32>(1, 2),  // coords
-                               3);                  // sample_index
-          },
-      },
-      {
-          ValidTextureOverload::kLoadMultisampled2dI32,
-          "textureLoad(t            : texture_multisampled_2d<i32>,\n"
-          "            coords       : vec2<i32>,\n"
-          "            sample_index : i32) -> vec4<i32>",
-          TextureKind::kMultisampled,
-          ast::TextureDimension::k2d,
-          TextureDataType::kI32,
-          "textureLoad",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",           // t
-                               b->vec2<i32>(1, 2),  // coords
-                               3);                  // sample_index
-          },
-      },
-      {
-          ValidTextureOverload::kLoadDepth2dLevelF32,
-          "textureLoad(t      : texture_depth_2d,\n"
-          "            coords : vec2<i32>,\n"
-          "            level  : i32) -> f32",
-          TextureKind::kDepth,
-          ast::TextureDimension::k2d,
-          TextureDataType::kF32,
-          "textureLoad",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",           // t
-                               b->vec2<i32>(1, 2),  // coords
-                               3);                  // level
-          },
-      },
-      {
-          ValidTextureOverload::kLoadDepth2dArrayLevelF32,
-          "textureLoad(t           : texture_depth_2d_array,\n"
-          "            coords      : vec2<i32>,\n"
-          "            array_index : i32,\n"
-          "            level       : i32) -> f32",
-          TextureKind::kDepth,
-          ast::TextureDimension::k2dArray,
-          TextureDataType::kF32,
-          "textureLoad",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",           // t
-                               b->vec2<i32>(1, 2),  // coords
-                               3,                   // array_index
-                               4);                  // level
-          },
-      },
-      {
-          ValidTextureOverload::kStoreWO1dRgba32float,
-          "textureStore(t      : texture_storage_1d<rgba32float>,\n"
-          "             coords : i32,\n"
-          "             value  : vec4<T>)",
-          ast::Access::kWrite,
-          ast::TexelFormat::kRgba32Float,
-          ast::TextureDimension::k1d,
-          TextureDataType::kF32,
-          "textureStore",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",                          // t
-                               1,                                  // coords
-                               b->vec4<f32>(2.f, 3.f, 4.f, 5.f));  // value
-          },
-      },
-      {
-          ValidTextureOverload::kStoreWO2dRgba32float,
-          "textureStore(t      : texture_storage_2d<rgba32float>,\n"
-          "             coords : vec2<i32>,\n"
-          "             value  : vec4<T>)",
-          ast::Access::kWrite,
-          ast::TexelFormat::kRgba32Float,
-          ast::TextureDimension::k2d,
-          TextureDataType::kF32,
-          "textureStore",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",                          // t
-                               b->vec2<i32>(1, 2),                 // coords
-                               b->vec4<f32>(3.f, 4.f, 5.f, 6.f));  // value
-          },
-      },
-      {
-          ValidTextureOverload::kStoreWO2dArrayRgba32float,
-          "textureStore(t           : texture_storage_2d_array<rgba32float>,\n"
-          "             coords      : vec2<i32>,\n"
-          "             array_index : i32,\n"
-          "             value       : vec4<T>)",
-          ast::Access::kWrite,
-          ast::TexelFormat::kRgba32Float,
-          ast::TextureDimension::k2dArray,
-          TextureDataType::kF32,
-          "textureStore",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",           // t
-                               b->vec2<i32>(1, 2),  // coords
-                               3,                   // array_index
-                               b->vec4<f32>(4.f, 5.f, 6.f, 7.f));  // value
-          },
-      },
-      {
-          ValidTextureOverload::kStoreWO3dRgba32float,
-          "textureStore(t      : texture_storage_3d<rgba32float>,\n"
-          "             coords : vec3<i32>,\n"
-          "             value  : vec4<T>)",
-          ast::Access::kWrite,
-          ast::TexelFormat::kRgba32Float,
-          ast::TextureDimension::k3d,
-          TextureDataType::kF32,
-          "textureStore",
-          [](ProgramBuilder* b) {
-            return b->ExprList("texture",                          // t
-                               b->vec3<i32>(1, 2, 3),              // coords
-                               b->vec4<f32>(4.f, 5.f, 6.f, 7.f));  // value
-          },
-      },
-  };
+        {
+            ValidTextureOverload::kGather2dF32,
+            "textureGather(component : i32,\n"
+            "              t         : texture_2d<T>,\n"
+            "              s         : sampler,\n"
+            "              coords    : vec2<f32>) -> vec4<T>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2d,
+            TextureDataType::kF32,
+            "textureGather",
+            [](ProgramBuilder* b) {
+                return b->ExprList(0_i,                      // component
+                                   "texture",                // t
+                                   "sampler",                // s
+                                   b->vec2<f32>(1.f, 2.f));  // coords
+            },
+        },
+        {
+            ValidTextureOverload::kGather2dOffsetF32,
+            "textureGather(component : i32,\n"
+            "              t         : texture_2d<T>,\n"
+            "              s         : sampler,\n"
+            "              coords    : vec2<f32>,\n"
+            "              offset    : vec2<i32>) -> vec4<T>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2d,
+            TextureDataType::kF32,
+            "textureGather",
+            [](ProgramBuilder* b) {
+                return b->ExprList(0_i,                      // component
+                                   "texture",                // t
+                                   "sampler",                // s
+                                   b->vec2<f32>(1.f, 2.f),   // coords
+                                   b->vec2<i32>(3_i, 4_i));  // offset
+            },
+        },
+        {
+            ValidTextureOverload::kGather2dArrayF32,
+            "textureGather(component   : i32,\n"
+            "              t           : texture_2d_array<T>,\n"
+            "              s           : sampler,\n"
+            "              coords      : vec2<f32>,\n"
+            "              array_index : i32) -> vec4<T>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2dArray,
+            TextureDataType::kF32,
+            "textureGather",
+            [](ProgramBuilder* b) {
+                return b->ExprList(0_i,                     // component
+                                   "texture",               // t
+                                   "sampler",               // s
+                                   b->vec2<f32>(1.f, 2.f),  // coords
+                                   3_i);                    // array index
+            },
+        },
+        {
+            ValidTextureOverload::kGather2dArrayOffsetF32,
+            "textureGather(component   : i32,\n"
+            "              t           : texture_2d_array<T>,\n"
+            "              s           : sampler,\n"
+            "              coords      : vec2<f32>,\n"
+            "              array_index : i32,\n"
+            "              offset      : vec2<i32>) -> vec4<T>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2dArray,
+            TextureDataType::kF32,
+            "textureGather",
+            [](ProgramBuilder* b) {
+                return b->ExprList(0_i,                      // component
+                                   "texture",                // t
+                                   "sampler",                // s
+                                   b->vec2<f32>(1.f, 2.f),   // coords
+                                   3_i,                      // array_index
+                                   b->vec2<i32>(4_i, 5_i));  // offset
+            },
+        },
+        {
+            ValidTextureOverload::kGatherCubeF32,
+            "textureGather(component : i32,\n"
+            "              t         : texture_cube<T>,\n"
+            "              s         : sampler,\n"
+            "              coords    : vec3<f32>) -> vec4<T>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::kCube,
+            TextureDataType::kF32,
+            "textureGather",
+            [](ProgramBuilder* b) {
+                return b->ExprList(0_i,                           // component
+                                   "texture",                     // t
+                                   "sampler",                     // s
+                                   b->vec3<f32>(1.f, 2.f, 3.f));  // coords
+            },
+        },
+        {
+            ValidTextureOverload::kGatherCubeArrayF32,
+            "textureGather(component   : i32,\n"
+            "              t           : texture_cube_array<T>,\n"
+            "              s           : sampler,\n"
+            "              coords      : vec3<f32>,\n"
+            "              array_index : i32) -> vec4<T>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::kCubeArray,
+            TextureDataType::kF32,
+            "textureGather",
+            [](ProgramBuilder* b) {
+                return b->ExprList(0_i,                          // component
+                                   "texture",                    // t
+                                   "sampler",                    // s
+                                   b->vec3<f32>(1.f, 2.f, 3.f),  // coords
+                                   4_i);                         // array_index
+            },
+        },
+        {
+            ValidTextureOverload::kGatherDepth2dF32,
+            "textureGather(t      : texture_depth_2d,\n"
+            "              s      : sampler,\n"
+            "              coords : vec2<f32>) -> vec4<f32>",
+            TextureKind::kDepth,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2d,
+            TextureDataType::kF32,
+            "textureGather",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                // t
+                                   "sampler",                // s
+                                   b->vec2<f32>(1.f, 2.f));  // coords
+            },
+        },
+        {
+            ValidTextureOverload::kGatherDepth2dOffsetF32,
+            "textureGather(t      : texture_depth_2d,\n"
+            "              s      : sampler,\n"
+            "              coords : vec2<f32>,\n"
+            "              offset : vec2<i32>) -> vec4<f32>",
+            TextureKind::kDepth,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2d,
+            TextureDataType::kF32,
+            "textureGather",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                // t
+                                   "sampler",                // s
+                                   b->vec2<f32>(1.f, 2.f),   // coords
+                                   b->vec2<i32>(3_i, 4_i));  // offset
+            },
+        },
+        {
+            ValidTextureOverload::kGatherDepth2dArrayF32,
+            "textureGather(t           : texture_depth_2d_array,\n"
+            "              s           : sampler,\n"
+            "              coords      : vec2<f32>,\n"
+            "              array_index : i32) -> vec4<f32>",
+            TextureKind::kDepth,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2dArray,
+            TextureDataType::kF32,
+            "textureGather",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",               // t
+                                   "sampler",               // s
+                                   b->vec2<f32>(1.f, 2.f),  // coords
+                                   3_i);                    // array_index
+            },
+        },
+        {
+            ValidTextureOverload::kGatherDepth2dArrayOffsetF32,
+            "textureGather(t           : texture_depth_2d_array,\n"
+            "              s           : sampler,\n"
+            "              coords      : vec2<f32>,\n"
+            "              array_index : i32,\n"
+            "              offset      : vec2<i32>) -> vec4<f32>",
+            TextureKind::kDepth,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2dArray,
+            TextureDataType::kF32,
+            "textureGather",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                // t
+                                   "sampler",                // s
+                                   b->vec2<f32>(1.f, 2.f),   // coords
+                                   3_i,                      // array_index
+                                   b->vec2<i32>(4_i, 5_i));  // offset
+            },
+        },
+        {
+            ValidTextureOverload::kGatherDepthCubeF32,
+            "textureGather(t      : texture_depth_cube,\n"
+            "              s      : sampler,\n"
+            "              coords : vec3<f32>) -> vec4<f32>",
+            TextureKind::kDepth,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::kCube,
+            TextureDataType::kF32,
+            "textureGather",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                     // t
+                                   "sampler",                     // s
+                                   b->vec3<f32>(1.f, 2.f, 3.f));  // coords
+            },
+        },
+        {
+            ValidTextureOverload::kGatherDepthCubeArrayF32,
+            "textureGather(t           : texture_depth_cube_array,\n"
+            "              s           : sampler,\n"
+            "              coords      : vec3<f32>,\n"
+            "              array_index : i32) -> vec4<f32>",
+            TextureKind::kDepth,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::kCubeArray,
+            TextureDataType::kF32,
+            "textureGather",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                    // t
+                                   "sampler",                    // s
+                                   b->vec3<f32>(1.f, 2.f, 3.f),  // coords
+                                   4_i);                         // array_index
+            },
+        },
+        {
+            ValidTextureOverload::kGatherCompareDepth2dF32,
+            "textureGatherCompare(t         : texture_depth_2d,\n"
+            "                     s         : sampler_comparison,\n"
+            "                     coords    : vec2<f32>,\n"
+            "                     depth_ref : f32) -> vec4<f32>",
+            TextureKind::kDepth,
+            ast::SamplerKind::kComparisonSampler,
+            ast::TextureDimension::k2d,
+            TextureDataType::kF32,
+            "textureGatherCompare",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",               // t
+                                   "sampler",               // s
+                                   b->vec2<f32>(1.f, 2.f),  // coords
+                                   3.f);                    // depth_ref
+            },
+        },
+        {
+            ValidTextureOverload::kGatherCompareDepth2dOffsetF32,
+            "textureGatherCompare(t         : texture_depth_2d,\n"
+            "                     s         : sampler_comparison,\n"
+            "                     coords    : vec2<f32>,\n"
+            "                     depth_ref : f32,\n"
+            "                     offset    : vec2<i32>) -> vec4<f32>",
+            TextureKind::kDepth,
+            ast::SamplerKind::kComparisonSampler,
+            ast::TextureDimension::k2d,
+            TextureDataType::kF32,
+            "textureGatherCompare",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                // t
+                                   "sampler",                // s
+                                   b->vec2<f32>(1.f, 2.f),   // coords
+                                   3.f,                      // depth_ref
+                                   b->vec2<i32>(4_i, 5_i));  // offset
+            },
+        },
+        {
+            ValidTextureOverload::kGatherCompareDepth2dArrayF32,
+            "textureGatherCompare(t           : texture_depth_2d_array,\n"
+            "                     s           : sampler_comparison,\n"
+            "                     coords      : vec2<f32>,\n"
+            "                     array_index : i32,\n"
+            "                     depth_ref   : f32) -> vec4<f32>",
+            TextureKind::kDepth,
+            ast::SamplerKind::kComparisonSampler,
+            ast::TextureDimension::k2dArray,
+            TextureDataType::kF32,
+            "textureGatherCompare",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",               // t
+                                   "sampler",               // s
+                                   b->vec2<f32>(1.f, 2.f),  // coords
+                                   3_i,                     // array_index
+                                   4.f);                    // depth_ref
+            },
+        },
+        {
+            ValidTextureOverload::kGatherCompareDepth2dArrayOffsetF32,
+            "textureGatherCompare(t           : texture_depth_2d_array,\n"
+            "                     s           : sampler_comparison,\n"
+            "                     coords      : vec2<f32>,\n"
+            "                     array_index : i32,\n"
+            "                     depth_ref   : f32,\n"
+            "                     offset      : vec2<i32>) -> vec4<f32>",
+            TextureKind::kDepth,
+            ast::SamplerKind::kComparisonSampler,
+            ast::TextureDimension::k2dArray,
+            TextureDataType::kF32,
+            "textureGatherCompare",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                // t
+                                   "sampler",                // s
+                                   b->vec2<f32>(1.f, 2.f),   // coords
+                                   3_i,                      // array_index
+                                   4.f,                      // depth_ref
+                                   b->vec2<i32>(5_i, 6_i));  // offset
+            },
+        },
+        {
+            ValidTextureOverload::kGatherCompareDepthCubeF32,
+            "textureGatherCompare(t         : texture_depth_cube,\n"
+            "                     s         : sampler_comparison,\n"
+            "                     coords    : vec3<f32>,\n"
+            "                     depth_ref : f32) -> vec4<f32>",
+            TextureKind::kDepth,
+            ast::SamplerKind::kComparisonSampler,
+            ast::TextureDimension::kCube,
+            TextureDataType::kF32,
+            "textureGatherCompare",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                    // t
+                                   "sampler",                    // s
+                                   b->vec3<f32>(1.f, 2.f, 3.f),  // coords
+                                   4.f);                         // depth_ref
+            },
+        },
+        {
+            ValidTextureOverload::kGatherCompareDepthCubeArrayF32,
+            "textureGatherCompare(t           : texture_depth_cube_array,\n"
+            "                     s           : sampler_comparison,\n"
+            "                     coords      : vec3<f32>,\n"
+            "                     array_index : i32,\n"
+            "                     depth_ref   : f32) -> vec4<f32>",
+            TextureKind::kDepth,
+            ast::SamplerKind::kComparisonSampler,
+            ast::TextureDimension::kCubeArray,
+            TextureDataType::kF32,
+            "textureGatherCompare",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                    // t
+                                   "sampler",                    // s
+                                   b->vec3<f32>(1.f, 2.f, 3.f),  // coords
+                                   4_i,                          // array_index
+                                   5.f);                         // depth_ref
+            },
+        },
+        {
+            ValidTextureOverload::kNumLayers2dArray,
+            "textureNumLayers(t : texture_2d_array<f32>) -> i32",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2dArray,
+            TextureDataType::kF32,
+            "textureNumLayers",
+            [](ProgramBuilder* b) { return b->ExprList("texture"); },
+        },
+        {
+            ValidTextureOverload::kNumLayersCubeArray,
+            "textureNumLayers(t : texture_cube_array<f32>) -> i32",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::kCubeArray,
+            TextureDataType::kF32,
+            "textureNumLayers",
+            [](ProgramBuilder* b) { return b->ExprList("texture"); },
+        },
+        {
+            ValidTextureOverload::kNumLayersDepth2dArray,
+            "textureNumLayers(t : texture_depth_2d_array) -> i32",
+            TextureKind::kDepth,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2dArray,
+            TextureDataType::kF32,
+            "textureNumLayers",
+            [](ProgramBuilder* b) { return b->ExprList("texture"); },
+        },
+        {
+            ValidTextureOverload::kNumLayersDepthCubeArray,
+            "textureNumLayers(t : texture_depth_cube_array) -> i32",
+            TextureKind::kDepth,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::kCubeArray,
+            TextureDataType::kF32,
+            "textureNumLayers",
+            [](ProgramBuilder* b) { return b->ExprList("texture"); },
+        },
+        {
+            ValidTextureOverload::kNumLayersStorageWO2dArray,
+            "textureNumLayers(t : texture_storage_2d_array<rgba32float>) -> i32",
+            ast::Access::kWrite,
+            ast::TexelFormat::kRgba32Float,
+            ast::TextureDimension::k2dArray,
+            TextureDataType::kF32,
+            "textureNumLayers",
+            [](ProgramBuilder* b) { return b->ExprList("texture"); },
+        },
+        {
+            ValidTextureOverload::kNumLevels2d,
+            "textureNumLevels(t : texture_2d<f32>) -> i32",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2d,
+            TextureDataType::kF32,
+            "textureNumLevels",
+            [](ProgramBuilder* b) { return b->ExprList("texture"); },
+        },
+        {
+            ValidTextureOverload::kNumLevels2dArray,
+            "textureNumLevels(t : texture_2d_array<f32>) -> i32",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2dArray,
+            TextureDataType::kF32,
+            "textureNumLevels",
+            [](ProgramBuilder* b) { return b->ExprList("texture"); },
+        },
+        {
+            ValidTextureOverload::kNumLevels3d,
+            "textureNumLevels(t : texture_3d<f32>) -> i32",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k3d,
+            TextureDataType::kF32,
+            "textureNumLevels",
+            [](ProgramBuilder* b) { return b->ExprList("texture"); },
+        },
+        {
+            ValidTextureOverload::kNumLevelsCube,
+            "textureNumLevels(t : texture_cube<f32>) -> i32",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::kCube,
+            TextureDataType::kF32,
+            "textureNumLevels",
+            [](ProgramBuilder* b) { return b->ExprList("texture"); },
+        },
+        {
+            ValidTextureOverload::kNumLevelsCubeArray,
+            "textureNumLevels(t : texture_cube_array<f32>) -> i32",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::kCubeArray,
+            TextureDataType::kF32,
+            "textureNumLevels",
+            [](ProgramBuilder* b) { return b->ExprList("texture"); },
+        },
+        {
+            ValidTextureOverload::kNumLevelsDepth2d,
+            "textureNumLevels(t : texture_depth_2d) -> i32",
+            TextureKind::kDepth,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2d,
+            TextureDataType::kF32,
+            "textureNumLevels",
+            [](ProgramBuilder* b) { return b->ExprList("texture"); },
+        },
+        {
+            ValidTextureOverload::kNumLevelsDepth2dArray,
+            "textureNumLevels(t : texture_depth_2d_array) -> i32",
+            TextureKind::kDepth,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2dArray,
+            TextureDataType::kF32,
+            "textureNumLevels",
+            [](ProgramBuilder* b) { return b->ExprList("texture"); },
+        },
+        {
+            ValidTextureOverload::kNumLevelsDepthCube,
+            "textureNumLevels(t : texture_depth_cube) -> i32",
+            TextureKind::kDepth,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::kCube,
+            TextureDataType::kF32,
+            "textureNumLevels",
+            [](ProgramBuilder* b) { return b->ExprList("texture"); },
+        },
+        {
+            ValidTextureOverload::kNumLevelsDepthCubeArray,
+            "textureNumLevels(t : texture_depth_cube_array) -> i32",
+            TextureKind::kDepth,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::kCubeArray,
+            TextureDataType::kF32,
+            "textureNumLevels",
+            [](ProgramBuilder* b) { return b->ExprList("texture"); },
+        },
+        {
+            ValidTextureOverload::kNumSamplesMultisampled2d,
+            "textureNumSamples(t : texture_multisampled_2d<f32>) -> i32",
+            TextureKind::kMultisampled,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2d,
+            TextureDataType::kF32,
+            "textureNumSamples",
+            [](ProgramBuilder* b) { return b->ExprList("texture"); },
+        },
+        {
+            ValidTextureOverload::kSample1dF32,
+            "textureSample(t      : texture_1d<f32>,\n"
+            "              s      : sampler,\n"
+            "              coords : f32) -> vec4<f32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k1d,
+            TextureDataType::kF32,
+            "textureSample",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",  // t
+                                   "sampler",  // s
+                                   1.0f);      // coords
+            },
+        },
+        {
+            ValidTextureOverload::kSample2dF32,
+            "textureSample(t      : texture_2d<f32>,\n"
+            "              s      : sampler,\n"
+            "              coords : vec2<f32>) -> vec4<f32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2d,
+            TextureDataType::kF32,
+            "textureSample",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                // t
+                                   "sampler",                // s
+                                   b->vec2<f32>(1.f, 2.f));  // coords
+            },
+        },
+        {
+            ValidTextureOverload::kSample2dOffsetF32,
+            "textureSample(t      : texture_2d<f32>,\n"
+            "              s      : sampler,\n"
+            "              coords : vec2<f32>\n"
+            "              offset : vec2<i32>) -> vec4<f32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2d,
+            TextureDataType::kF32,
+            "textureSample",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                // t
+                                   "sampler",                // s
+                                   b->vec2<f32>(1.f, 2.f),   // coords
+                                   b->vec2<i32>(3_i, 4_i));  // offset
+            },
+        },
+        {
+            ValidTextureOverload::kSample2dArrayF32,
+            "textureSample(t           : texture_2d_array<f32>,\n"
+            "              s           : sampler,\n"
+            "              coords      : vec2<f32>,\n"
+            "              array_index : i32) -> vec4<f32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2dArray,
+            TextureDataType::kF32,
+            "textureSample",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",               // t
+                                   "sampler",               // s
+                                   b->vec2<f32>(1.f, 2.f),  // coords
+                                   3_i);                    // array_index
+            },
+        },
+        {
+            ValidTextureOverload::kSample2dArrayOffsetF32,
+            "textureSample(t           : texture_2d_array<f32>,\n"
+            "              s           : sampler,\n"
+            "              coords      : vec2<f32>,\n"
+            "              array_index : i32\n"
+            "              offset      : vec2<i32>) -> vec4<f32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2dArray,
+            TextureDataType::kF32,
+            "textureSample",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                // t
+                                   "sampler",                // s
+                                   b->vec2<f32>(1.f, 2.f),   // coords
+                                   3_i,                      // array_index
+                                   b->vec2<i32>(4_i, 5_i));  // offset
+            },
+        },
+        {
+            ValidTextureOverload::kSample3dF32,
+            "textureSample(t      : texture_3d<f32>,\n"
+            "              s      : sampler,\n"
+            "              coords : vec3<f32>) -> vec4<f32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k3d,
+            TextureDataType::kF32,
+            "textureSample",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                     // t
+                                   "sampler",                     // s
+                                   b->vec3<f32>(1.f, 2.f, 3.f));  // coords
+            },
+        },
+        {
+            ValidTextureOverload::kSample3dOffsetF32,
+            "textureSample(t      : texture_3d<f32>,\n"
+            "              s      : sampler,\n"
+            "              coords : vec3<f32>\n"
+            "              offset : vec3<i32>) -> vec4<f32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k3d,
+            TextureDataType::kF32,
+            "textureSample",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                     // t
+                                   "sampler",                     // s
+                                   b->vec3<f32>(1.f, 2.f, 3.f),   // coords
+                                   b->vec3<i32>(4_i, 5_i, 6_i));  // offset
+            },
+        },
+        {
+            ValidTextureOverload::kSampleCubeF32,
+            "textureSample(t      : texture_cube<f32>,\n"
+            "              s      : sampler,\n"
+            "              coords : vec3<f32>) -> vec4<f32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::kCube,
+            TextureDataType::kF32,
+            "textureSample",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                     // t
+                                   "sampler",                     // s
+                                   b->vec3<f32>(1.f, 2.f, 3.f));  // coords
+            },
+        },
+        {
+            ValidTextureOverload::kSampleCubeArrayF32,
+            "textureSample(t           : texture_cube_array<f32>,\n"
+            "              s           : sampler,\n"
+            "              coords      : vec3<f32>,\n"
+            "              array_index : i32) -> vec4<f32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::kCubeArray,
+            TextureDataType::kF32,
+            "textureSample",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                    // t
+                                   "sampler",                    // s
+                                   b->vec3<f32>(1.f, 2.f, 3.f),  // coords
+                                   4_i);                         // array_index
+            },
+        },
+        {
+            ValidTextureOverload::kSampleDepth2dF32,
+            "textureSample(t      : texture_depth_2d,\n"
+            "              s      : sampler,\n"
+            "              coords : vec2<f32>) -> f32",
+            TextureKind::kDepth,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2d,
+            TextureDataType::kF32,
+            "textureSample",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                // t
+                                   "sampler",                // s
+                                   b->vec2<f32>(1.f, 2.f));  // coords
+            },
+        },
+        {
+            ValidTextureOverload::kSampleDepth2dOffsetF32,
+            "textureSample(t      : texture_depth_2d,\n"
+            "              s      : sampler,\n"
+            "              coords : vec2<f32>\n"
+            "              offset : vec2<i32>) -> f32",
+            TextureKind::kDepth,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2d,
+            TextureDataType::kF32,
+            "textureSample",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                // t
+                                   "sampler",                // s
+                                   b->vec2<f32>(1.f, 2.f),   // coords
+                                   b->vec2<i32>(3_i, 4_i));  // offset
+            },
+        },
+        {
+            ValidTextureOverload::kSampleDepth2dArrayF32,
+            "textureSample(t           : texture_depth_2d_array,\n"
+            "              s           : sampler,\n"
+            "              coords      : vec2<f32>,\n"
+            "              array_index : i32) -> f32",
+            TextureKind::kDepth,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2dArray,
+            TextureDataType::kF32,
+            "textureSample",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",               // t
+                                   "sampler",               // s
+                                   b->vec2<f32>(1.f, 2.f),  // coords
+                                   3_i);                    // array_index
+            },
+        },
+        {
+            ValidTextureOverload::kSampleDepth2dArrayOffsetF32,
+            "textureSample(t           : texture_depth_2d_array,\n"
+            "              s           : sampler,\n"
+            "              coords      : vec2<f32>,\n"
+            "              array_index : i32\n"
+            "              offset      : vec2<i32>) -> f32",
+            TextureKind::kDepth,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2dArray,
+            TextureDataType::kF32,
+            "textureSample",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                // t
+                                   "sampler",                // s
+                                   b->vec2<f32>(1.f, 2.f),   // coords
+                                   3_i,                      // array_index
+                                   b->vec2<i32>(4_i, 5_i));  // offset
+            },
+        },
+        {
+            ValidTextureOverload::kSampleDepthCubeF32,
+            "textureSample(t      : texture_depth_cube,\n"
+            "              s      : sampler,\n"
+            "              coords : vec3<f32>) -> f32",
+            TextureKind::kDepth,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::kCube,
+            TextureDataType::kF32,
+            "textureSample",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                     // t
+                                   "sampler",                     // s
+                                   b->vec3<f32>(1.f, 2.f, 3.f));  // coords
+            },
+        },
+        {
+            ValidTextureOverload::kSampleDepthCubeArrayF32,
+            "textureSample(t           : texture_depth_cube_array,\n"
+            "              s           : sampler,\n"
+            "              coords      : vec3<f32>,\n"
+            "              array_index : i32) -> f32",
+            TextureKind::kDepth,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::kCubeArray,
+            TextureDataType::kF32,
+            "textureSample",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                    // t
+                                   "sampler",                    // s
+                                   b->vec3<f32>(1.f, 2.f, 3.f),  // coords
+                                   4_i);                         // array_index
+            },
+        },
+        {
+            ValidTextureOverload::kSampleBias2dF32,
+            "textureSampleBias(t      : texture_2d<f32>,\n"
+            "                  s      : sampler,\n"
+            "                  coords : vec2<f32>,\n"
+            "                  bias   : f32) -> vec4<f32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2d,
+            TextureDataType::kF32,
+            "textureSampleBias",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",               // t
+                                   "sampler",               // s
+                                   b->vec2<f32>(1.f, 2.f),  // coords
+                                   3.f);                    // bias
+            },
+        },
+        {
+            ValidTextureOverload::kSampleBias2dOffsetF32,
+            "textureSampleBias(t      : texture_2d<f32>,\n"
+            "                  s      : sampler,\n"
+            "                  coords : vec2<f32>,\n"
+            "                  bias   : f32,\n"
+            "                  offset : vec2<i32>) -> vec4<f32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2d,
+            TextureDataType::kF32,
+            "textureSampleBias",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                // t
+                                   "sampler",                // s
+                                   b->vec2<f32>(1.f, 2.f),   // coords
+                                   3.f,                      // bias
+                                   b->vec2<i32>(4_i, 5_i));  // offset
+            },
+        },
+        {
+            ValidTextureOverload::kSampleBias2dArrayF32,
+            "textureSampleBias(t           : texture_2d_array<f32>,\n"
+            "                  s           : sampler,\n"
+            "                  coords      : vec2<f32>,\n"
+            "                  array_index : i32,\n"
+            "                  bias        : f32) -> vec4<f32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2dArray,
+            TextureDataType::kF32,
+            "textureSampleBias",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",               // t
+                                   "sampler",               // s
+                                   b->vec2<f32>(1.f, 2.f),  // coords
+                                   4_i,                     // array_index
+                                   3.f);                    // bias
+            },
+        },
+        {
+            ValidTextureOverload::kSampleBias2dArrayOffsetF32,
+            "textureSampleBias(t           : texture_2d_array<f32>,\n"
+            "                  s           : sampler,\n"
+            "                  coords      : vec2<f32>,\n"
+            "                  array_index : i32,\n"
+            "                  bias        : f32,\n"
+            "                  offset      : vec2<i32>) -> vec4<f32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2dArray,
+            TextureDataType::kF32,
+            "textureSampleBias",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                // t
+                                   "sampler",                // s
+                                   b->vec2<f32>(1.f, 2.f),   // coords
+                                   3_i,                      // array_index
+                                   4.f,                      // bias
+                                   b->vec2<i32>(5_i, 6_i));  // offset
+            },
+        },
+        {
+            ValidTextureOverload::kSampleBias3dF32,
+            "textureSampleBias(t      : texture_3d<f32>,\n"
+            "                  s      : sampler,\n"
+            "                  coords : vec3<f32>,\n"
+            "                  bias   : f32) -> vec4<f32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k3d,
+            TextureDataType::kF32,
+            "textureSampleBias",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                    // t
+                                   "sampler",                    // s
+                                   b->vec3<f32>(1.f, 2.f, 3.f),  // coords
+                                   4.f);                         // bias
+            },
+        },
+        {
+            ValidTextureOverload::kSampleBias3dOffsetF32,
+            "textureSampleBias(t      : texture_3d<f32>,\n"
+            "                  s      : sampler,\n"
+            "                  coords : vec3<f32>,\n"
+            "                  bias   : f32,\n"
+            "                  offset : vec3<i32>) -> vec4<f32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k3d,
+            TextureDataType::kF32,
+            "textureSampleBias",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                     // t
+                                   "sampler",                     // s
+                                   b->vec3<f32>(1.f, 2.f, 3.f),   // coords
+                                   4.f,                           // bias
+                                   b->vec3<i32>(5_i, 6_i, 7_i));  // offset
+            },
+        },
+        {
+            ValidTextureOverload::kSampleBiasCubeF32,
+            "textureSampleBias(t      : texture_cube<f32>,\n"
+            "                  s      : sampler,\n"
+            "                  coords : vec3<f32>,\n"
+            "                  bias   : f32) -> vec4<f32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::kCube,
+            TextureDataType::kF32,
+            "textureSampleBias",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                    // t
+                                   "sampler",                    // s
+                                   b->vec3<f32>(1.f, 2.f, 3.f),  // coords
+                                   4.f);                         // bias
+            },
+        },
+        {
+            ValidTextureOverload::kSampleBiasCubeArrayF32,
+            "textureSampleBias(t           : texture_cube_array<f32>,\n"
+            "                  s           : sampler,\n"
+            "                  coords      : vec3<f32>,\n"
+            "                  array_index : i32,\n"
+            "                  bias        : f32) -> vec4<f32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::kCubeArray,
+            TextureDataType::kF32,
+            "textureSampleBias",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                    // t
+                                   "sampler",                    // s
+                                   b->vec3<f32>(1.f, 2.f, 3.f),  // coords
+                                   3_i,                          // array_index
+                                   4.f);                         // bias
+            },
+        },
+        {
+            ValidTextureOverload::kSampleLevel2dF32,
+            "textureSampleLevel(t      : texture_2d<f32>,\n"
+            "                   s      : sampler,\n"
+            "                   coords : vec2<f32>,\n"
+            "                   level  : f32) -> vec4<f32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2d,
+            TextureDataType::kF32,
+            "textureSampleLevel",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",               // t
+                                   "sampler",               // s
+                                   b->vec2<f32>(1.f, 2.f),  // coords
+                                   3.f);                    // level
+            },
+        },
+        {
+            ValidTextureOverload::kSampleLevel2dOffsetF32,
+            "textureSampleLevel(t      : texture_2d<f32>,\n"
+            "                   s      : sampler,\n"
+            "                   coords : vec2<f32>,\n"
+            "                   level  : f32,\n"
+            "                   offset : vec2<i32>) -> vec4<f32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2d,
+            TextureDataType::kF32,
+            "textureSampleLevel",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                // t
+                                   "sampler",                // s
+                                   b->vec2<f32>(1.f, 2.f),   // coords
+                                   3.f,                      // level
+                                   b->vec2<i32>(4_i, 5_i));  // offset
+            },
+        },
+        {
+            ValidTextureOverload::kSampleLevel2dArrayF32,
+            "textureSampleLevel(t           : texture_2d_array<f32>,\n"
+            "                   s           : sampler,\n"
+            "                   coords      : vec2<f32>,\n"
+            "                   array_index : i32,\n"
+            "                   level       : f32) -> vec4<f32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2dArray,
+            TextureDataType::kF32,
+            "textureSampleLevel",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",               // t
+                                   "sampler",               // s
+                                   b->vec2<f32>(1.f, 2.f),  // coords
+                                   3_i,                     // array_index
+                                   4.f);                    // level
+            },
+        },
+        {
+            ValidTextureOverload::kSampleLevel2dArrayOffsetF32,
+            "textureSampleLevel(t           : texture_2d_array<f32>,\n"
+            "                   s           : sampler,\n"
+            "                   coords      : vec2<f32>,\n"
+            "                   array_index : i32,\n"
+            "                   level       : f32,\n"
+            "                   offset      : vec2<i32>) -> vec4<f32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2dArray,
+            TextureDataType::kF32,
+            "textureSampleLevel",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                // t
+                                   "sampler",                // s
+                                   b->vec2<f32>(1.f, 2.f),   // coords
+                                   3_i,                      // array_index
+                                   4.f,                      // level
+                                   b->vec2<i32>(5_i, 6_i));  // offset
+            },
+        },
+        {
+            ValidTextureOverload::kSampleLevel3dF32,
+            "textureSampleLevel(t      : texture_3d<f32>,\n"
+            "                   s      : sampler,\n"
+            "                   coords : vec3<f32>,\n"
+            "                   level  : f32) -> vec4<f32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k3d,
+            TextureDataType::kF32,
+            "textureSampleLevel",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                    // t
+                                   "sampler",                    // s
+                                   b->vec3<f32>(1.f, 2.f, 3.f),  // coords
+                                   4.f);                         // level
+            },
+        },
+        {
+            ValidTextureOverload::kSampleLevel3dOffsetF32,
+            "textureSampleLevel(t      : texture_3d<f32>,\n"
+            "                   s      : sampler,\n"
+            "                   coords : vec3<f32>,\n"
+            "                   level  : f32,\n"
+            "                   offset : vec3<i32>) -> vec4<f32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k3d,
+            TextureDataType::kF32,
+            "textureSampleLevel",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                     // t
+                                   "sampler",                     // s
+                                   b->vec3<f32>(1.f, 2.f, 3.f),   // coords
+                                   4.f,                           // level
+                                   b->vec3<i32>(5_i, 6_i, 7_i));  // offset
+            },
+        },
+        {
+            ValidTextureOverload::kSampleLevelCubeF32,
+            "textureSampleLevel(t      : texture_cube<f32>,\n"
+            "                   s      : sampler,\n"
+            "                   coords : vec3<f32>,\n"
+            "                   level  : f32) -> vec4<f32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::kCube,
+            TextureDataType::kF32,
+            "textureSampleLevel",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                    // t
+                                   "sampler",                    // s
+                                   b->vec3<f32>(1.f, 2.f, 3.f),  // coords
+                                   4.f);                         // level
+            },
+        },
+        {
+            ValidTextureOverload::kSampleLevelCubeArrayF32,
+            "textureSampleLevel(t           : texture_cube_array<f32>,\n"
+            "                   s           : sampler,\n"
+            "                   coords      : vec3<f32>,\n"
+            "                   array_index : i32,\n"
+            "                   level       : f32) -> vec4<f32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::kCubeArray,
+            TextureDataType::kF32,
+            "textureSampleLevel",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                    // t
+                                   "sampler",                    // s
+                                   b->vec3<f32>(1.f, 2.f, 3.f),  // coords
+                                   4_i,                          // array_index
+                                   5.f);                         // level
+            },
+        },
+        {
+            ValidTextureOverload::kSampleLevelDepth2dF32,
+            "textureSampleLevel(t      : texture_depth_2d,\n"
+            "                   s      : sampler,\n"
+            "                   coords : vec2<f32>,\n"
+            "                   level  : i32) -> f32",
+            TextureKind::kDepth,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2d,
+            TextureDataType::kF32,
+            "textureSampleLevel",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",               // t
+                                   "sampler",               // s
+                                   b->vec2<f32>(1.f, 2.f),  // coords
+                                   3_i);                    // level
+            },
+        },
+        {
+            ValidTextureOverload::kSampleLevelDepth2dOffsetF32,
+            "textureSampleLevel(t      : texture_depth_2d,\n"
+            "                   s      : sampler,\n"
+            "                   coords : vec2<f32>,\n"
+            "                   level  : i32,\n"
+            "                   offset : vec2<i32>) -> f32",
+            TextureKind::kDepth,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2d,
+            TextureDataType::kF32,
+            "textureSampleLevel",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                // t
+                                   "sampler",                // s
+                                   b->vec2<f32>(1.f, 2.f),   // coords
+                                   3_i,                      // level
+                                   b->vec2<i32>(4_i, 5_i));  // offset
+            },
+        },
+        {
+            ValidTextureOverload::kSampleLevelDepth2dArrayF32,
+            "textureSampleLevel(t           : texture_depth_2d_array,\n"
+            "                   s           : sampler,\n"
+            "                   coords      : vec2<f32>,\n"
+            "                   array_index : i32,\n"
+            "                   level       : i32) -> f32",
+            TextureKind::kDepth,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2dArray,
+            TextureDataType::kF32,
+            "textureSampleLevel",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",               // t
+                                   "sampler",               // s
+                                   b->vec2<f32>(1.f, 2.f),  // coords
+                                   3_i,                     // array_index
+                                   4_i);                    // level
+            },
+        },
+        {
+            ValidTextureOverload::kSampleLevelDepth2dArrayOffsetF32,
+            "textureSampleLevel(t           : texture_depth_2d_array,\n"
+            "                   s           : sampler,\n"
+            "                   coords      : vec2<f32>,\n"
+            "                   array_index : i32,\n"
+            "                   level       : i32,\n"
+            "                   offset      : vec2<i32>) -> f32",
+            TextureKind::kDepth,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2dArray,
+            TextureDataType::kF32,
+            "textureSampleLevel",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                // t
+                                   "sampler",                // s
+                                   b->vec2<f32>(1.f, 2.f),   // coords
+                                   3_i,                      // array_index
+                                   4_i,                      // level
+                                   b->vec2<i32>(5_i, 6_i));  // offset
+            },
+        },
+        {
+            ValidTextureOverload::kSampleLevelDepthCubeF32,
+            "textureSampleLevel(t      : texture_depth_cube,\n"
+            "                   s      : sampler,\n"
+            "                   coords : vec3<f32>,\n"
+            "                   level  : i32) -> f32",
+            TextureKind::kDepth,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::kCube,
+            TextureDataType::kF32,
+            "textureSampleLevel",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                    // t
+                                   "sampler",                    // s
+                                   b->vec3<f32>(1.f, 2.f, 3.f),  // coords
+                                   4_i);                         // level
+            },
+        },
+        {
+            ValidTextureOverload::kSampleLevelDepthCubeArrayF32,
+            "textureSampleLevel(t           : texture_depth_cube_array,\n"
+            "                   s           : sampler,\n"
+            "                   coords      : vec3<f32>,\n"
+            "                   array_index : i32,\n"
+            "                   level       : i32) -> f32",
+            TextureKind::kDepth,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::kCubeArray,
+            TextureDataType::kF32,
+            "textureSampleLevel",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                    // t
+                                   "sampler",                    // s
+                                   b->vec3<f32>(1.f, 2.f, 3.f),  // coords
+                                   4_i,                          // array_index
+                                   5_i);                         // level
+            },
+        },
+        {
+            ValidTextureOverload::kSampleGrad2dF32,
+            "textureSampleGrad(t      : texture_2d<f32>,\n"
+            "                  s      : sampler,\n"
+            "                  coords : vec2<f32>\n"
+            "                  ddx    : vec2<f32>,\n"
+            "                  ddy    : vec2<f32>) -> vec4<f32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2d,
+            TextureDataType::kF32,
+            "textureSampleGrad",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                  // t
+                                   "sampler",                  // s
+                                   b->vec2<f32>(1.0f, 2.0f),   // coords
+                                   b->vec2<f32>(3.0f, 4.0f),   // ddx
+                                   b->vec2<f32>(5.0f, 6.0f));  // ddy
+            },
+        },
+        {
+            ValidTextureOverload::kSampleGrad2dOffsetF32,
+            "textureSampleGrad(t      : texture_2d<f32>,\n"
+            "                  s      : sampler,\n"
+            "                  coords : vec2<f32>,\n"
+            "                  ddx    : vec2<f32>,\n"
+            "                  ddy    : vec2<f32>,\n"
+            "                  offset : vec2<i32>) -> vec4<f32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2d,
+            TextureDataType::kF32,
+            "textureSampleGrad",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                // t
+                                   "sampler",                // s
+                                   b->vec2<f32>(1.f, 2.f),   // coords
+                                   b->vec2<f32>(3.f, 4.f),   // ddx
+                                   b->vec2<f32>(5.f, 6.f),   // ddy
+                                   b->vec2<i32>(7_i, 7_i));  // offset
+            },
+        },
+        {
+            ValidTextureOverload::kSampleGrad2dArrayF32,
+            "textureSampleGrad(t           : texture_2d_array<f32>,\n"
+            "                  s           : sampler,\n"
+            "                  coords      : vec2<f32>,\n"
+            "                  array_index : i32,\n"
+            "                  ddx         : vec2<f32>,\n"
+            "                  ddy         : vec2<f32>) -> vec4<f32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2dArray,
+            TextureDataType::kF32,
+            "textureSampleGrad",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                // t
+                                   "sampler",                // s
+                                   b->vec2<f32>(1.f, 2.f),   // coords
+                                   3_i,                      // array_index
+                                   b->vec2<f32>(4.f, 5.f),   // ddx
+                                   b->vec2<f32>(6.f, 7.f));  // ddy
+            },
+        },
+        {
+            ValidTextureOverload::kSampleGrad2dArrayOffsetF32,
+            "textureSampleGrad(t           : texture_2d_array<f32>,\n"
+            "                  s           : sampler,\n"
+            "                  coords      : vec2<f32>,\n"
+            "                  array_index : i32,\n"
+            "                  ddx         : vec2<f32>,\n"
+            "                  ddy         : vec2<f32>,\n"
+            "                  offset      : vec2<i32>) -> vec4<f32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k2dArray,
+            TextureDataType::kF32,
+            "textureSampleGrad",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                // t
+                                   "sampler",                // s
+                                   b->vec2<f32>(1.f, 2.f),   // coords
+                                   3_i,                      // array_index
+                                   b->vec2<f32>(4.f, 5.f),   // ddx
+                                   b->vec2<f32>(6.f, 7.f),   // ddy
+                                   b->vec2<i32>(6_i, 7_i));  // offset
+            },
+        },
+        {
+            ValidTextureOverload::kSampleGrad3dF32,
+            "textureSampleGrad(t      : texture_3d<f32>,\n"
+            "                  s      : sampler,\n"
+            "                  coords : vec3<f32>,\n"
+            "                  ddx    : vec3<f32>,\n"
+            "                  ddy    : vec3<f32>) -> vec4<f32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k3d,
+            TextureDataType::kF32,
+            "textureSampleGrad",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                     // t
+                                   "sampler",                     // s
+                                   b->vec3<f32>(1.f, 2.f, 3.f),   // coords
+                                   b->vec3<f32>(4.f, 5.f, 6.f),   // ddx
+                                   b->vec3<f32>(7.f, 8.f, 9.f));  // ddy
+            },
+        },
+        {
+            ValidTextureOverload::kSampleGrad3dOffsetF32,
+            "textureSampleGrad(t      : texture_3d<f32>,\n"
+            "                  s      : sampler,\n"
+            "                  coords : vec3<f32>,\n"
+            "                  ddx    : vec3<f32>,\n"
+            "                  ddy    : vec3<f32>,\n"
+            "                  offset : vec3<i32>) -> vec4<f32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::k3d,
+            TextureDataType::kF32,
+            "textureSampleGrad",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                     // t
+                                   "sampler",                     // s
+                                   b->vec3<f32>(1.f, 2.f, 3.f),   // coords
+                                   b->vec3<f32>(4.f, 5.f, 6.f),   // ddx
+                                   b->vec3<f32>(7.f, 8.f, 9.f),   // ddy
+                                   b->vec3<i32>(0_i, 1_i, 2_i));  // offset
+            },
+        },
+        {
+            ValidTextureOverload::kSampleGradCubeF32,
+            "textureSampleGrad(t      : texture_cube<f32>,\n"
+            "                  s      : sampler,\n"
+            "                  coords : vec3<f32>,\n"
+            "                  ddx    : vec3<f32>,\n"
+            "                  ddy    : vec3<f32>) -> vec4<f32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::kCube,
+            TextureDataType::kF32,
+            "textureSampleGrad",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                     // t
+                                   "sampler",                     // s
+                                   b->vec3<f32>(1.f, 2.f, 3.f),   // coords
+                                   b->vec3<f32>(4.f, 5.f, 6.f),   // ddx
+                                   b->vec3<f32>(7.f, 8.f, 9.f));  // ddy
+            },
+        },
+        {
+            ValidTextureOverload::kSampleGradCubeArrayF32,
+            "textureSampleGrad(t           : texture_cube_array<f32>,\n"
+            "                  s           : sampler,\n"
+            "                  coords      : vec3<f32>,\n"
+            "                  array_index : i32,\n"
+            "                  ddx         : vec3<f32>,\n"
+            "                  ddy         : vec3<f32>) -> vec4<f32>",
+            TextureKind::kRegular,
+            ast::SamplerKind::kSampler,
+            ast::TextureDimension::kCubeArray,
+            TextureDataType::kF32,
+            "textureSampleGrad",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                      // t
+                                   "sampler",                      // s
+                                   b->vec3<f32>(1.f, 2.f, 3.f),    // coords
+                                   4_i,                            // array_index
+                                   b->vec3<f32>(5.f, 6.f, 7.f),    // ddx
+                                   b->vec3<f32>(8.f, 9.f, 10.f));  // ddy
+            },
+        },
+        {
+            ValidTextureOverload::kSampleCompareDepth2dF32,
+            "textureSampleCompare(t         : texture_depth_2d,\n"
+            "                     s         : sampler_comparison,\n"
+            "                     coords    : vec2<f32>,\n"
+            "                     depth_ref : f32) -> f32",
+            TextureKind::kDepth,
+            ast::SamplerKind::kComparisonSampler,
+            ast::TextureDimension::k2d,
+            TextureDataType::kF32,
+            "textureSampleCompare",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",               // t
+                                   "sampler",               // s
+                                   b->vec2<f32>(1.f, 2.f),  // coords
+                                   3.f);                    // depth_ref
+            },
+        },
+        {
+            ValidTextureOverload::kSampleCompareDepth2dOffsetF32,
+            "textureSampleCompare(t         : texture_depth_2d,\n"
+            "                     s         : sampler_comparison,\n"
+            "                     coords    : vec2<f32>,\n"
+            "                     depth_ref : f32,\n"
+            "                     offset    : vec2<i32>) -> f32",
+            TextureKind::kDepth,
+            ast::SamplerKind::kComparisonSampler,
+            ast::TextureDimension::k2d,
+            TextureDataType::kF32,
+            "textureSampleCompare",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                // t
+                                   "sampler",                // s
+                                   b->vec2<f32>(1.f, 2.f),   // coords
+                                   3.f,                      // depth_ref
+                                   b->vec2<i32>(4_i, 5_i));  // offset
+            },
+        },
+        {
+            ValidTextureOverload::kSampleCompareDepth2dArrayF32,
+            "textureSampleCompare(t           : texture_depth_2d_array,\n"
+            "                     s           : sampler_comparison,\n"
+            "                     coords      : vec2<f32>,\n"
+            "                     array_index : i32,\n"
+            "                     depth_ref   : f32) -> f32",
+            TextureKind::kDepth,
+            ast::SamplerKind::kComparisonSampler,
+            ast::TextureDimension::k2dArray,
+            TextureDataType::kF32,
+            "textureSampleCompare",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",               // t
+                                   "sampler",               // s
+                                   b->vec2<f32>(1.f, 2.f),  // coords
+                                   4_i,                     // array_index
+                                   3.f);                    // depth_ref
+            },
+        },
+        {
+            ValidTextureOverload::kSampleCompareDepth2dArrayOffsetF32,
+            "textureSampleCompare(t           : texture_depth_2d_array,\n"
+            "                     s           : sampler_comparison,\n"
+            "                     coords      : vec2<f32>,\n"
+            "                     array_index : i32,\n"
+            "                     depth_ref   : f32,\n"
+            "                     offset      : vec2<i32>) -> f32",
+            TextureKind::kDepth,
+            ast::SamplerKind::kComparisonSampler,
+            ast::TextureDimension::k2dArray,
+            TextureDataType::kF32,
+            "textureSampleCompare",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                // t
+                                   "sampler",                // s
+                                   b->vec2<f32>(1.f, 2.f),   // coords
+                                   4_i,                      // array_index
+                                   3.f,                      // depth_ref
+                                   b->vec2<i32>(5_i, 6_i));  // offset
+            },
+        },
+        {
+            ValidTextureOverload::kSampleCompareDepthCubeF32,
+            "textureSampleCompare(t         : texture_depth_cube,\n"
+            "                     s         : sampler_comparison,\n"
+            "                     coords    : vec3<f32>,\n"
+            "                     depth_ref : f32) -> f32",
+            TextureKind::kDepth,
+            ast::SamplerKind::kComparisonSampler,
+            ast::TextureDimension::kCube,
+            TextureDataType::kF32,
+            "textureSampleCompare",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                    // t
+                                   "sampler",                    // s
+                                   b->vec3<f32>(1.f, 2.f, 3.f),  // coords
+                                   4.f);                         // depth_ref
+            },
+        },
+        {
+            ValidTextureOverload::kSampleCompareDepthCubeArrayF32,
+            "textureSampleCompare(t           : texture_depth_cube_array,\n"
+            "                     s           : sampler_comparison,\n"
+            "                     coords      : vec3<f32>,\n"
+            "                     array_index : i32,\n"
+            "                     depth_ref   : f32) -> f32",
+            TextureKind::kDepth,
+            ast::SamplerKind::kComparisonSampler,
+            ast::TextureDimension::kCubeArray,
+            TextureDataType::kF32,
+            "textureSampleCompare",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                    // t
+                                   "sampler",                    // s
+                                   b->vec3<f32>(1.f, 2.f, 3.f),  // coords
+                                   4_i,                          // array_index
+                                   5.f);                         // depth_ref
+            },
+        },
+        {
+            ValidTextureOverload::kLoad1dLevelF32,
+            "textureLoad(t      : texture_1d<f32>,\n"
+            "            coords : i32,\n"
+            "            level  : i32) -> vec4<f32>",
+            TextureKind::kRegular,
+            ast::TextureDimension::k1d,
+            TextureDataType::kF32,
+            "textureLoad",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",  // t
+                                   1_i,        // coords
+                                   3_i);       // level
+            },
+        },
+        {
+            ValidTextureOverload::kLoad1dLevelU32,
+            "textureLoad(t      : texture_1d<u32>,\n"
+            "            coords : i32,\n"
+            "            level  : i32) -> vec4<u32>",
+            TextureKind::kRegular,
+            ast::TextureDimension::k1d,
+            TextureDataType::kU32,
+            "textureLoad",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",  // t
+                                   1_i,        // coords
+                                   3_i);       // level
+            },
+        },
+        {
+            ValidTextureOverload::kLoad1dLevelI32,
+            "textureLoad(t      : texture_1d<i32>,\n"
+            "            coords : i32,\n"
+            "            level  : i32) -> vec4<i32>",
+            TextureKind::kRegular,
+            ast::TextureDimension::k1d,
+            TextureDataType::kI32,
+            "textureLoad",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",  // t
+                                   1_i,        // coords
+                                   3_i);       // level
+            },
+        },
+        {
+            ValidTextureOverload::kLoad2dLevelF32,
+            "textureLoad(t      : texture_2d<f32>,\n"
+            "            coords : vec2<i32>,\n"
+            "            level  : i32) -> vec4<f32>",
+            TextureKind::kRegular,
+            ast::TextureDimension::k2d,
+            TextureDataType::kF32,
+            "textureLoad",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",               // t
+                                   b->vec2<i32>(1_i, 2_i),  // coords
+                                   3_i);                    // level
+            },
+        },
+        {
+            ValidTextureOverload::kLoad2dLevelU32,
+            "textureLoad(t      : texture_2d<u32>,\n"
+            "            coords : vec2<i32>,\n"
+            "            level  : i32) -> vec4<u32>",
+            TextureKind::kRegular,
+            ast::TextureDimension::k2d,
+            TextureDataType::kU32,
+            "textureLoad",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",               // t
+                                   b->vec2<i32>(1_i, 2_i),  // coords
+                                   3_i);                    // level
+            },
+        },
+        {
+            ValidTextureOverload::kLoad2dLevelI32,
+            "textureLoad(t      : texture_2d<i32>,\n"
+            "            coords : vec2<i32>,\n"
+            "            level  : i32) -> vec4<i32>",
+            TextureKind::kRegular,
+            ast::TextureDimension::k2d,
+            TextureDataType::kI32,
+            "textureLoad",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",               // t
+                                   b->vec2<i32>(1_i, 2_i),  // coords
+                                   3_i);                    // level
+            },
+        },
+        {
+            ValidTextureOverload::kLoad2dArrayLevelF32,
+            "textureLoad(t           : texture_2d_array<f32>,\n"
+            "            coords      : vec2<i32>,\n"
+            "            array_index : i32,\n"
+            "            level       : i32) -> vec4<f32>",
+            TextureKind::kRegular,
+            ast::TextureDimension::k2dArray,
+            TextureDataType::kF32,
+            "textureLoad",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",               // t
+                                   b->vec2<i32>(1_i, 2_i),  // coords
+                                   3_i,                     // array_index
+                                   4_i);                    // level
+            },
+        },
+        {
+            ValidTextureOverload::kLoad2dArrayLevelU32,
+            "textureLoad(t           : texture_2d_array<u32>,\n"
+            "            coords      : vec2<i32>,\n"
+            "            array_index : i32,\n"
+            "            level       : i32) -> vec4<u32>",
+            TextureKind::kRegular,
+            ast::TextureDimension::k2dArray,
+            TextureDataType::kU32,
+            "textureLoad",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",               // t
+                                   b->vec2<i32>(1_i, 2_i),  // coords
+                                   3_i,                     // array_index
+                                   4_i);                    // level
+            },
+        },
+        {
+            ValidTextureOverload::kLoad2dArrayLevelI32,
+            "textureLoad(t           : texture_2d_array<i32>,\n"
+            "            coords      : vec2<i32>,\n"
+            "            array_index : i32,\n"
+            "            level       : i32) -> vec4<i32>",
+            TextureKind::kRegular,
+            ast::TextureDimension::k2dArray,
+            TextureDataType::kI32,
+            "textureLoad",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",               // t
+                                   b->vec2<i32>(1_i, 2_i),  // coords
+                                   3_i,                     // array_index
+                                   4_i);                    // level
+            },
+        },
+        {
+            ValidTextureOverload::kLoad3dLevelF32,
+            "textureLoad(t      : texture_3d<f32>,\n"
+            "            coords : vec3<i32>,\n"
+            "            level  : i32) -> vec4<f32>",
+            TextureKind::kRegular,
+            ast::TextureDimension::k3d,
+            TextureDataType::kF32,
+            "textureLoad",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                    // t
+                                   b->vec3<i32>(1_i, 2_i, 3_i),  // coords
+                                   4_i);                         // level
+            },
+        },
+        {
+            ValidTextureOverload::kLoad3dLevelU32,
+            "textureLoad(t      : texture_3d<u32>,\n"
+            "            coords : vec3<i32>,\n"
+            "            level  : i32) -> vec4<u32>",
+            TextureKind::kRegular,
+            ast::TextureDimension::k3d,
+            TextureDataType::kU32,
+            "textureLoad",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                    // t
+                                   b->vec3<i32>(1_i, 2_i, 3_i),  // coords
+                                   4_i);                         // level
+            },
+        },
+        {
+            ValidTextureOverload::kLoad3dLevelI32,
+            "textureLoad(t      : texture_3d<i32>,\n"
+            "            coords : vec3<i32>,\n"
+            "            level  : i32) -> vec4<i32>",
+            TextureKind::kRegular,
+            ast::TextureDimension::k3d,
+            TextureDataType::kI32,
+            "textureLoad",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                    // t
+                                   b->vec3<i32>(1_i, 2_i, 3_i),  // coords
+                                   4_i);                         // level
+            },
+        },
+        {
+            ValidTextureOverload::kLoadMultisampled2dF32,
+            "textureLoad(t            : texture_multisampled_2d<f32>,\n"
+            "            coords       : vec2<i32>,\n"
+            "            sample_index : i32) -> vec4<f32>",
+            TextureKind::kMultisampled,
+            ast::TextureDimension::k2d,
+            TextureDataType::kF32,
+            "textureLoad",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",               // t
+                                   b->vec2<i32>(1_i, 2_i),  // coords
+                                   3_i);                    // sample_index
+            },
+        },
+        {
+            ValidTextureOverload::kLoadMultisampled2dU32,
+            "textureLoad(t            : texture_multisampled_2d<u32>,\n"
+            "            coords       : vec2<i32>,\n"
+            "            sample_index : i32) -> vec4<u32>",
+            TextureKind::kMultisampled,
+            ast::TextureDimension::k2d,
+            TextureDataType::kU32,
+            "textureLoad",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",               // t
+                                   b->vec2<i32>(1_i, 2_i),  // coords
+                                   3_i);                    // sample_index
+            },
+        },
+        {
+            ValidTextureOverload::kLoadMultisampled2dI32,
+            "textureLoad(t            : texture_multisampled_2d<i32>,\n"
+            "            coords       : vec2<i32>,\n"
+            "            sample_index : i32) -> vec4<i32>",
+            TextureKind::kMultisampled,
+            ast::TextureDimension::k2d,
+            TextureDataType::kI32,
+            "textureLoad",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",               // t
+                                   b->vec2<i32>(1_i, 2_i),  // coords
+                                   3_i);                    // sample_index
+            },
+        },
+        {
+            ValidTextureOverload::kLoadDepth2dLevelF32,
+            "textureLoad(t      : texture_depth_2d,\n"
+            "            coords : vec2<i32>,\n"
+            "            level  : i32) -> f32",
+            TextureKind::kDepth,
+            ast::TextureDimension::k2d,
+            TextureDataType::kF32,
+            "textureLoad",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",               // t
+                                   b->vec2<i32>(1_i, 2_i),  // coords
+                                   3_i);                    // level
+            },
+        },
+        {
+            ValidTextureOverload::kLoadDepth2dArrayLevelF32,
+            "textureLoad(t           : texture_depth_2d_array,\n"
+            "            coords      : vec2<i32>,\n"
+            "            array_index : i32,\n"
+            "            level       : i32) -> f32",
+            TextureKind::kDepth,
+            ast::TextureDimension::k2dArray,
+            TextureDataType::kF32,
+            "textureLoad",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",               // t
+                                   b->vec2<i32>(1_i, 2_i),  // coords
+                                   3_i,                     // array_index
+                                   4_i);                    // level
+            },
+        },
+        {
+            ValidTextureOverload::kStoreWO1dRgba32float,
+            "textureStore(t      : texture_storage_1d<rgba32float>,\n"
+            "             coords : i32,\n"
+            "             value  : vec4<T>)",
+            ast::Access::kWrite,
+            ast::TexelFormat::kRgba32Float,
+            ast::TextureDimension::k1d,
+            TextureDataType::kF32,
+            "textureStore",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                          // t
+                                   1_i,                                // coords
+                                   b->vec4<f32>(2.f, 3.f, 4.f, 5.f));  // value
+            },
+        },
+        {
+            ValidTextureOverload::kStoreWO2dRgba32float,
+            "textureStore(t      : texture_storage_2d<rgba32float>,\n"
+            "             coords : vec2<i32>,\n"
+            "             value  : vec4<T>)",
+            ast::Access::kWrite,
+            ast::TexelFormat::kRgba32Float,
+            ast::TextureDimension::k2d,
+            TextureDataType::kF32,
+            "textureStore",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                          // t
+                                   b->vec2<i32>(1_i, 2_i),             // coords
+                                   b->vec4<f32>(3.f, 4.f, 5.f, 6.f));  // value
+            },
+        },
+        {
+            ValidTextureOverload::kStoreWO2dArrayRgba32float,
+            "textureStore(t           : texture_storage_2d_array<rgba32float>,\n"
+            "             coords      : vec2<i32>,\n"
+            "             array_index : i32,\n"
+            "             value       : vec4<T>)",
+            ast::Access::kWrite,
+            ast::TexelFormat::kRgba32Float,
+            ast::TextureDimension::k2dArray,
+            TextureDataType::kF32,
+            "textureStore",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                          // t
+                                   b->vec2<i32>(1_i, 2_i),             // coords
+                                   3_i,                                // array_index
+                                   b->vec4<f32>(4.f, 5.f, 6.f, 7.f));  // value
+            },
+        },
+        {
+            ValidTextureOverload::kStoreWO3dRgba32float,
+            "textureStore(t      : texture_storage_3d<rgba32float>,\n"
+            "             coords : vec3<i32>,\n"
+            "             value  : vec4<T>)",
+            ast::Access::kWrite,
+            ast::TexelFormat::kRgba32Float,
+            ast::TextureDimension::k3d,
+            TextureDataType::kF32,
+            "textureStore",
+            [](ProgramBuilder* b) {
+                return b->ExprList("texture",                          // t
+                                   b->vec3<i32>(1_i, 2_i, 3_i),        // coords
+                                   b->vec4<f32>(4.f, 5.f, 6.f, 7.f));  // value
+            },
+        },
+    };
 }
 
 bool ReturnsVoid(ValidTextureOverload texture_overload) {
-  switch (texture_overload) {
-    case ValidTextureOverload::kStoreWO1dRgba32float:
-    case ValidTextureOverload::kStoreWO2dRgba32float:
-    case ValidTextureOverload::kStoreWO2dArrayRgba32float:
-    case ValidTextureOverload::kStoreWO3dRgba32float:
-      return true;
-    default:
-      return false;
-  }
+    switch (texture_overload) {
+        case ValidTextureOverload::kStoreWO1dRgba32float:
+        case ValidTextureOverload::kStoreWO2dRgba32float:
+        case ValidTextureOverload::kStoreWO2dArrayRgba32float:
+        case ValidTextureOverload::kStoreWO3dRgba32float:
+            return true;
+        default:
+            return false;
+    }
 }
 
 }  // namespace tint::ast::builtin::test
diff --git a/src/tint/ast/builtin_texture_helper_test.h b/src/tint/ast/builtin_texture_helper_test.h
index ad60757..d2737e1 100644
--- a/src/tint/ast/builtin_texture_helper_test.h
+++ b/src/tint/ast/builtin_texture_helper_test.h
@@ -19,17 +19,11 @@
 
 #include "src/tint/ast/access.h"
 #include "src/tint/program_builder.h"
-#include "src/tint/sem/storage_texture_type.h"
+#include "src/tint/sem/storage_texture.h"
 
 namespace tint::ast::builtin::test {
 
-enum class TextureKind {
-  kRegular,
-  kDepth,
-  kDepthMultisampled,
-  kMultisampled,
-  kStorage
-};
+enum class TextureKind { kRegular, kDepth, kDepthMultisampled, kMultisampled, kStorage };
 enum class TextureDataType { kF32, kU32, kI32 };
 
 std::ostream& operator<<(std::ostream& out, const TextureKind& kind);
@@ -37,144 +31,144 @@
 
 /// Non-exhaustive list of valid texture overloads
 enum class ValidTextureOverload {
-  kDimensions1d,
-  kDimensions2d,
-  kDimensions2dLevel,
-  kDimensions2dArray,
-  kDimensions2dArrayLevel,
-  kDimensions3d,
-  kDimensions3dLevel,
-  kDimensionsCube,
-  kDimensionsCubeLevel,
-  kDimensionsCubeArray,
-  kDimensionsCubeArrayLevel,
-  kDimensionsMultisampled2d,
-  kDimensionsDepth2d,
-  kDimensionsDepth2dLevel,
-  kDimensionsDepth2dArray,
-  kDimensionsDepth2dArrayLevel,
-  kDimensionsDepthCube,
-  kDimensionsDepthCubeLevel,
-  kDimensionsDepthCubeArray,
-  kDimensionsDepthCubeArrayLevel,
-  kDimensionsDepthMultisampled2d,
-  kDimensionsStorageWO1d,
-  kDimensionsStorageWO2d,
-  kDimensionsStorageWO2dArray,
-  kDimensionsStorageWO3d,
-  kGather2dF32,
-  kGather2dOffsetF32,
-  kGather2dArrayF32,
-  kGather2dArrayOffsetF32,
-  kGatherCubeF32,
-  kGatherCubeArrayF32,
-  kGatherDepth2dF32,
-  kGatherDepth2dOffsetF32,
-  kGatherDepth2dArrayF32,
-  kGatherDepth2dArrayOffsetF32,
-  kGatherDepthCubeF32,
-  kGatherDepthCubeArrayF32,
-  kGatherCompareDepth2dF32,
-  kGatherCompareDepth2dOffsetF32,
-  kGatherCompareDepth2dArrayF32,
-  kGatherCompareDepth2dArrayOffsetF32,
-  kGatherCompareDepthCubeF32,
-  kGatherCompareDepthCubeArrayF32,
-  kNumLayers2dArray,
-  kNumLayersCubeArray,
-  kNumLayersDepth2dArray,
-  kNumLayersDepthCubeArray,
-  kNumLayersStorageWO2dArray,
-  kNumLevels2d,
-  kNumLevels2dArray,
-  kNumLevels3d,
-  kNumLevelsCube,
-  kNumLevelsCubeArray,
-  kNumLevelsDepth2d,
-  kNumLevelsDepth2dArray,
-  kNumLevelsDepthCube,
-  kNumLevelsDepthCubeArray,
-  kNumSamplesMultisampled2d,
-  kNumSamplesDepthMultisampled2d,
-  kSample1dF32,
-  kSample2dF32,
-  kSample2dOffsetF32,
-  kSample2dArrayF32,
-  kSample2dArrayOffsetF32,
-  kSample3dF32,
-  kSample3dOffsetF32,
-  kSampleCubeF32,
-  kSampleCubeArrayF32,
-  kSampleDepth2dF32,
-  kSampleDepth2dOffsetF32,
-  kSampleDepth2dArrayF32,
-  kSampleDepth2dArrayOffsetF32,
-  kSampleDepthCubeF32,
-  kSampleDepthCubeArrayF32,
-  kSampleBias2dF32,
-  kSampleBias2dOffsetF32,
-  kSampleBias2dArrayF32,
-  kSampleBias2dArrayOffsetF32,
-  kSampleBias3dF32,
-  kSampleBias3dOffsetF32,
-  kSampleBiasCubeF32,
-  kSampleBiasCubeArrayF32,
-  kSampleLevel2dF32,
-  kSampleLevel2dOffsetF32,
-  kSampleLevel2dArrayF32,
-  kSampleLevel2dArrayOffsetF32,
-  kSampleLevel3dF32,
-  kSampleLevel3dOffsetF32,
-  kSampleLevelCubeF32,
-  kSampleLevelCubeArrayF32,
-  kSampleLevelDepth2dF32,
-  kSampleLevelDepth2dOffsetF32,
-  kSampleLevelDepth2dArrayF32,
-  kSampleLevelDepth2dArrayOffsetF32,
-  kSampleLevelDepthCubeF32,
-  kSampleLevelDepthCubeArrayF32,
-  kSampleGrad2dF32,
-  kSampleGrad2dOffsetF32,
-  kSampleGrad2dArrayF32,
-  kSampleGrad2dArrayOffsetF32,
-  kSampleGrad3dF32,
-  kSampleGrad3dOffsetF32,
-  kSampleGradCubeF32,
-  kSampleGradCubeArrayF32,
-  kSampleCompareDepth2dF32,
-  kSampleCompareDepth2dOffsetF32,
-  kSampleCompareDepth2dArrayF32,
-  kSampleCompareDepth2dArrayOffsetF32,
-  kSampleCompareDepthCubeF32,
-  kSampleCompareDepthCubeArrayF32,
-  kSampleCompareLevelDepth2dF32,
-  kSampleCompareLevelDepth2dOffsetF32,
-  kSampleCompareLevelDepth2dArrayF32,
-  kSampleCompareLevelDepth2dArrayOffsetF32,
-  kSampleCompareLevelDepthCubeF32,
-  kSampleCompareLevelDepthCubeArrayF32,
-  kLoad1dLevelF32,
-  kLoad1dLevelU32,
-  kLoad1dLevelI32,
-  kLoad2dLevelF32,
-  kLoad2dLevelU32,
-  kLoad2dLevelI32,
-  kLoad2dArrayLevelF32,
-  kLoad2dArrayLevelU32,
-  kLoad2dArrayLevelI32,
-  kLoad3dLevelF32,
-  kLoad3dLevelU32,
-  kLoad3dLevelI32,
-  kLoadMultisampled2dF32,
-  kLoadMultisampled2dU32,
-  kLoadMultisampled2dI32,
-  kLoadDepth2dLevelF32,
-  kLoadDepth2dArrayLevelF32,
-  kLoadDepthMultisampled2dF32,
-  kStoreWO1dRgba32float,       // Not permutated for all texel formats
-  kStoreWO2dRgba32float,       // Not permutated for all texel formats
-  kStoreWO2dArrayRgba32float,  // Not permutated for all texel formats
-  kStoreWO3dRgba32float,       // Not permutated for all texel formats
+    kDimensions1d,
+    kDimensions2d,
+    kDimensions2dLevel,
+    kDimensions2dArray,
+    kDimensions2dArrayLevel,
+    kDimensions3d,
+    kDimensions3dLevel,
+    kDimensionsCube,
+    kDimensionsCubeLevel,
+    kDimensionsCubeArray,
+    kDimensionsCubeArrayLevel,
+    kDimensionsMultisampled2d,
+    kDimensionsDepth2d,
+    kDimensionsDepth2dLevel,
+    kDimensionsDepth2dArray,
+    kDimensionsDepth2dArrayLevel,
+    kDimensionsDepthCube,
+    kDimensionsDepthCubeLevel,
+    kDimensionsDepthCubeArray,
+    kDimensionsDepthCubeArrayLevel,
+    kDimensionsDepthMultisampled2d,
+    kDimensionsStorageWO1d,
+    kDimensionsStorageWO2d,
+    kDimensionsStorageWO2dArray,
+    kDimensionsStorageWO3d,
+    kGather2dF32,
+    kGather2dOffsetF32,
+    kGather2dArrayF32,
+    kGather2dArrayOffsetF32,
+    kGatherCubeF32,
+    kGatherCubeArrayF32,
+    kGatherDepth2dF32,
+    kGatherDepth2dOffsetF32,
+    kGatherDepth2dArrayF32,
+    kGatherDepth2dArrayOffsetF32,
+    kGatherDepthCubeF32,
+    kGatherDepthCubeArrayF32,
+    kGatherCompareDepth2dF32,
+    kGatherCompareDepth2dOffsetF32,
+    kGatherCompareDepth2dArrayF32,
+    kGatherCompareDepth2dArrayOffsetF32,
+    kGatherCompareDepthCubeF32,
+    kGatherCompareDepthCubeArrayF32,
+    kNumLayers2dArray,
+    kNumLayersCubeArray,
+    kNumLayersDepth2dArray,
+    kNumLayersDepthCubeArray,
+    kNumLayersStorageWO2dArray,
+    kNumLevels2d,
+    kNumLevels2dArray,
+    kNumLevels3d,
+    kNumLevelsCube,
+    kNumLevelsCubeArray,
+    kNumLevelsDepth2d,
+    kNumLevelsDepth2dArray,
+    kNumLevelsDepthCube,
+    kNumLevelsDepthCubeArray,
+    kNumSamplesMultisampled2d,
+    kNumSamplesDepthMultisampled2d,
+    kSample1dF32,
+    kSample2dF32,
+    kSample2dOffsetF32,
+    kSample2dArrayF32,
+    kSample2dArrayOffsetF32,
+    kSample3dF32,
+    kSample3dOffsetF32,
+    kSampleCubeF32,
+    kSampleCubeArrayF32,
+    kSampleDepth2dF32,
+    kSampleDepth2dOffsetF32,
+    kSampleDepth2dArrayF32,
+    kSampleDepth2dArrayOffsetF32,
+    kSampleDepthCubeF32,
+    kSampleDepthCubeArrayF32,
+    kSampleBias2dF32,
+    kSampleBias2dOffsetF32,
+    kSampleBias2dArrayF32,
+    kSampleBias2dArrayOffsetF32,
+    kSampleBias3dF32,
+    kSampleBias3dOffsetF32,
+    kSampleBiasCubeF32,
+    kSampleBiasCubeArrayF32,
+    kSampleLevel2dF32,
+    kSampleLevel2dOffsetF32,
+    kSampleLevel2dArrayF32,
+    kSampleLevel2dArrayOffsetF32,
+    kSampleLevel3dF32,
+    kSampleLevel3dOffsetF32,
+    kSampleLevelCubeF32,
+    kSampleLevelCubeArrayF32,
+    kSampleLevelDepth2dF32,
+    kSampleLevelDepth2dOffsetF32,
+    kSampleLevelDepth2dArrayF32,
+    kSampleLevelDepth2dArrayOffsetF32,
+    kSampleLevelDepthCubeF32,
+    kSampleLevelDepthCubeArrayF32,
+    kSampleGrad2dF32,
+    kSampleGrad2dOffsetF32,
+    kSampleGrad2dArrayF32,
+    kSampleGrad2dArrayOffsetF32,
+    kSampleGrad3dF32,
+    kSampleGrad3dOffsetF32,
+    kSampleGradCubeF32,
+    kSampleGradCubeArrayF32,
+    kSampleCompareDepth2dF32,
+    kSampleCompareDepth2dOffsetF32,
+    kSampleCompareDepth2dArrayF32,
+    kSampleCompareDepth2dArrayOffsetF32,
+    kSampleCompareDepthCubeF32,
+    kSampleCompareDepthCubeArrayF32,
+    kSampleCompareLevelDepth2dF32,
+    kSampleCompareLevelDepth2dOffsetF32,
+    kSampleCompareLevelDepth2dArrayF32,
+    kSampleCompareLevelDepth2dArrayOffsetF32,
+    kSampleCompareLevelDepthCubeF32,
+    kSampleCompareLevelDepthCubeArrayF32,
+    kLoad1dLevelF32,
+    kLoad1dLevelU32,
+    kLoad1dLevelI32,
+    kLoad2dLevelF32,
+    kLoad2dLevelU32,
+    kLoad2dLevelI32,
+    kLoad2dArrayLevelF32,
+    kLoad2dArrayLevelU32,
+    kLoad2dArrayLevelI32,
+    kLoad3dLevelF32,
+    kLoad3dLevelU32,
+    kLoad3dLevelI32,
+    kLoadMultisampled2dF32,
+    kLoadMultisampled2dU32,
+    kLoadMultisampled2dI32,
+    kLoadDepth2dLevelF32,
+    kLoadDepth2dArrayLevelF32,
+    kLoadDepthMultisampled2dF32,
+    kStoreWO1dRgba32float,       // Not permutated for all texel formats
+    kStoreWO2dRgba32float,       // Not permutated for all texel formats
+    kStoreWO2dArrayRgba32float,  // Not permutated for all texel formats
+    kStoreWO3dRgba32float,       // Not permutated for all texel formats
 };
 
 /// @param texture_overload the ValidTextureOverload
@@ -183,77 +177,76 @@
 
 /// Describes a texture builtin overload
 struct TextureOverloadCase {
-  /// Constructor for textureSample...() functions
-  TextureOverloadCase(ValidTextureOverload,
-                      const char*,
-                      TextureKind,
-                      ast::SamplerKind,
-                      ast::TextureDimension,
-                      TextureDataType,
-                      const char*,
-                      std::function<ExpressionList(ProgramBuilder*)>);
-  /// Constructor for textureLoad() functions with non-storage textures
-  TextureOverloadCase(ValidTextureOverload,
-                      const char*,
-                      TextureKind,
-                      ast::TextureDimension,
-                      TextureDataType,
-                      const char*,
-                      std::function<ExpressionList(ProgramBuilder*)>);
-  /// Constructor for textureLoad() with storage textures
-  TextureOverloadCase(ValidTextureOverload,
-                      const char*,
-                      Access,
-                      ast::TexelFormat,
-                      ast::TextureDimension,
-                      TextureDataType,
-                      const char*,
-                      std::function<ExpressionList(ProgramBuilder*)>);
-  /// Copy constructor
-  TextureOverloadCase(const TextureOverloadCase&);
-  /// Destructor
-  ~TextureOverloadCase();
+    /// Constructor for textureSample...() functions
+    TextureOverloadCase(ValidTextureOverload,
+                        const char*,
+                        TextureKind,
+                        ast::SamplerKind,
+                        ast::TextureDimension,
+                        TextureDataType,
+                        const char*,
+                        std::function<ExpressionList(ProgramBuilder*)>);
+    /// Constructor for textureLoad() functions with non-storage textures
+    TextureOverloadCase(ValidTextureOverload,
+                        const char*,
+                        TextureKind,
+                        ast::TextureDimension,
+                        TextureDataType,
+                        const char*,
+                        std::function<ExpressionList(ProgramBuilder*)>);
+    /// Constructor for textureLoad() with storage textures
+    TextureOverloadCase(ValidTextureOverload,
+                        const char*,
+                        Access,
+                        ast::TexelFormat,
+                        ast::TextureDimension,
+                        TextureDataType,
+                        const char*,
+                        std::function<ExpressionList(ProgramBuilder*)>);
+    /// Copy constructor
+    TextureOverloadCase(const TextureOverloadCase&);
+    /// Destructor
+    ~TextureOverloadCase();
 
-  /// @return a vector containing a large number (non-exhaustive) of valid
-  /// texture overloads.
-  static std::vector<TextureOverloadCase> ValidCases();
+    /// @return a vector containing a large number (non-exhaustive) of valid
+    /// texture overloads.
+    static std::vector<TextureOverloadCase> ValidCases();
 
-  /// @param builder the AST builder used for the test
-  /// @returns the vector component type of the texture function return value
-  const ast::Type* BuildResultVectorComponentType(
-      ProgramBuilder* builder) const;
-  /// @param builder the AST builder used for the test
-  /// @returns a variable holding the test texture, automatically registered as
-  /// a global variable.
-  const ast::Variable* BuildTextureVariable(ProgramBuilder* builder) const;
-  /// @param builder the AST builder used for the test
-  /// @returns a Variable holding the test sampler, automatically registered as
-  /// a global variable.
-  const ast::Variable* BuildSamplerVariable(ProgramBuilder* builder) const;
+    /// @param builder the AST builder used for the test
+    /// @returns the vector component type of the texture function return value
+    const ast::Type* BuildResultVectorComponentType(ProgramBuilder* builder) const;
+    /// @param builder the AST builder used for the test
+    /// @returns a variable holding the test texture, automatically registered as
+    /// a global variable.
+    const ast::Variable* BuildTextureVariable(ProgramBuilder* builder) const;
+    /// @param builder the AST builder used for the test
+    /// @returns a Variable holding the test sampler, automatically registered as
+    /// a global variable.
+    const ast::Variable* BuildSamplerVariable(ProgramBuilder* builder) const;
 
-  /// The enumerator for this overload
-  const ValidTextureOverload overload;
-  /// A human readable description of the overload
-  const char* const description;
-  /// The texture kind for the texture parameter
-  const TextureKind texture_kind;
-  /// The sampler kind for the sampler parameter
-  /// Used only when texture_kind is not kStorage
-  ast::SamplerKind const sampler_kind = ast::SamplerKind::kSampler;
-  /// The access control for the storage texture
-  /// Used only when texture_kind is kStorage
-  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;
-  /// The dimensions of the texture parameter
-  ast::TextureDimension const texture_dimension;
-  /// The data type of the texture parameter
-  const TextureDataType texture_data_type;
-  /// Name of the function. e.g. `textureSample`, `textureSampleGrad`, etc
-  const char* const function;
-  /// A function that builds the AST arguments for the overload
-  std::function<ExpressionList(ProgramBuilder*)> const args;
+    /// The enumerator for this overload
+    const ValidTextureOverload overload;
+    /// A human readable description of the overload
+    const char* const description;
+    /// The texture kind for the texture parameter
+    const TextureKind texture_kind;
+    /// The sampler kind for the sampler parameter
+    /// Used only when texture_kind is not kStorage
+    ast::SamplerKind const sampler_kind = ast::SamplerKind::kSampler;
+    /// The access control for the storage texture
+    /// Used only when texture_kind is kStorage
+    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;
+    /// The dimensions of the texture parameter
+    ast::TextureDimension const texture_dimension;
+    /// The data type of the texture parameter
+    const TextureDataType texture_data_type;
+    /// Name of the function. e.g. `textureSample`, `textureSampleGrad`, etc
+    const char* const function;
+    /// A function that builds the AST arguments for the overload
+    std::function<ExpressionList(ProgramBuilder*)> const args;
 };
 
 std::ostream& operator<<(std::ostream& out, const TextureOverloadCase& data);
diff --git a/src/tint/ast/call_expression.cc b/src/tint/ast/call_expression.cc
index cfb6bd9..68b6dc3 100644
--- a/src/tint/ast/call_expression.cc
+++ b/src/tint/ast/call_expression.cc
@@ -22,14 +22,14 @@
 
 namespace {
 CallExpression::Target ToTarget(const IdentifierExpression* name) {
-  CallExpression::Target target;
-  target.name = name;
-  return target;
+    CallExpression::Target target;
+    target.name = name;
+    return target;
 }
 CallExpression::Target ToTarget(const Type* type) {
-  CallExpression::Target target;
-  target.type = type;
-  return target;
+    CallExpression::Target target;
+    target.type = type;
+    return target;
 }
 }  // namespace
 
@@ -38,25 +38,22 @@
                                const IdentifierExpression* name,
                                ExpressionList a)
     : Base(pid, src), target(ToTarget(name)), args(a) {
-  TINT_ASSERT(AST, name);
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, name, program_id);
-  for (auto* arg : args) {
-    TINT_ASSERT(AST, arg);
-    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, arg, program_id);
-  }
+    TINT_ASSERT(AST, name);
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, name, program_id);
+    for (auto* arg : args) {
+        TINT_ASSERT(AST, arg);
+        TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, arg, program_id);
+    }
 }
 
-CallExpression::CallExpression(ProgramID pid,
-                               const Source& src,
-                               const Type* type,
-                               ExpressionList a)
+CallExpression::CallExpression(ProgramID pid, const Source& src, const Type* type, ExpressionList a)
     : Base(pid, src), target(ToTarget(type)), args(a) {
-  TINT_ASSERT(AST, type);
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, type, program_id);
-  for (auto* arg : args) {
-    TINT_ASSERT(AST, arg);
-    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, arg, program_id);
-  }
+    TINT_ASSERT(AST, type);
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, type, program_id);
+    for (auto* arg : args) {
+        TINT_ASSERT(AST, arg);
+        TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, arg, program_id);
+    }
 }
 
 CallExpression::CallExpression(CallExpression&&) = default;
@@ -64,13 +61,11 @@
 CallExpression::~CallExpression() = default;
 
 const CallExpression* CallExpression::Clone(CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  auto p = ctx->Clone(args);
-  return target.name
-             ? ctx->dst->create<CallExpression>(src, ctx->Clone(target.name), p)
-             : ctx->dst->create<CallExpression>(src, ctx->Clone(target.type),
-                                                p);
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    auto p = ctx->Clone(args);
+    return target.name ? ctx->dst->create<CallExpression>(src, ctx->Clone(target.name), p)
+                       : ctx->dst->create<CallExpression>(src, ctx->Clone(target.type), p);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/call_expression.h b/src/tint/ast/call_expression.h
index aab2b81..9f19711 100644
--- a/src/tint/ast/call_expression.h
+++ b/src/tint/ast/call_expression.h
@@ -31,52 +31,52 @@
 /// * sem::TypeConstructor
 /// * sem::TypeConversion
 class CallExpression final : public Castable<CallExpression, Expression> {
- public:
-  /// Constructor
-  /// @param program_id the identifier of the program that owns this node
-  /// @param source the call expression source
-  /// @param name the function or type name
-  /// @param args the arguments
-  CallExpression(ProgramID program_id,
-                 const Source& source,
-                 const IdentifierExpression* name,
-                 ExpressionList args);
+  public:
+    /// Constructor
+    /// @param program_id the identifier of the program that owns this node
+    /// @param source the call expression source
+    /// @param name the function or type name
+    /// @param args the arguments
+    CallExpression(ProgramID program_id,
+                   const Source& source,
+                   const IdentifierExpression* name,
+                   ExpressionList args);
 
-  /// Constructor
-  /// @param program_id the identifier of the program that owns this node
-  /// @param source the call expression source
-  /// @param type the type
-  /// @param args the arguments
-  CallExpression(ProgramID program_id,
-                 const Source& source,
-                 const Type* type,
-                 ExpressionList args);
+    /// Constructor
+    /// @param program_id the identifier of the program that owns this node
+    /// @param source the call expression source
+    /// @param type the type
+    /// @param args the arguments
+    CallExpression(ProgramID program_id,
+                   const Source& source,
+                   const Type* type,
+                   ExpressionList args);
 
-  /// Move constructor
-  CallExpression(CallExpression&&);
-  ~CallExpression() override;
+    /// Move constructor
+    CallExpression(CallExpression&&);
+    ~CallExpression() override;
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const CallExpression* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const CallExpression* Clone(CloneContext* ctx) const override;
 
-  /// Target is either an identifier, or a Type.
-  /// One of these must be nullptr and the other a non-nullptr.
-  struct Target {
-    /// name is a function or builtin to call, or type name to construct or
-    /// cast-to
-    const IdentifierExpression* name = nullptr;
-    /// type to construct or cast-to
-    const Type* type = nullptr;
-  };
+    /// Target is either an identifier, or a Type.
+    /// One of these must be nullptr and the other a non-nullptr.
+    struct Target {
+        /// name is a function or builtin to call, or type name to construct or
+        /// cast-to
+        const IdentifierExpression* name = nullptr;
+        /// type to construct or cast-to
+        const Type* type = nullptr;
+    };
 
-  /// The target function
-  const Target target;
+    /// The target function
+    const Target target;
 
-  /// The arguments
-  const ExpressionList args;
+    /// The arguments
+    const ExpressionList args;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/call_expression_test.cc b/src/tint/ast/call_expression_test.cc
index 4da5048..5cb31cb 100644
--- a/src/tint/ast/call_expression_test.cc
+++ b/src/tint/ast/call_expression_test.cc
@@ -21,126 +21,124 @@
 using CallExpressionTest = TestHelper;
 
 TEST_F(CallExpressionTest, CreationIdentifier) {
-  auto* func = Expr("func");
-  ExpressionList params;
-  params.push_back(Expr("param1"));
-  params.push_back(Expr("param2"));
+    auto* func = Expr("func");
+    ExpressionList params;
+    params.push_back(Expr("param1"));
+    params.push_back(Expr("param2"));
 
-  auto* stmt = create<CallExpression>(func, params);
-  EXPECT_EQ(stmt->target.name, func);
-  EXPECT_EQ(stmt->target.type, nullptr);
+    auto* stmt = create<CallExpression>(func, params);
+    EXPECT_EQ(stmt->target.name, func);
+    EXPECT_EQ(stmt->target.type, nullptr);
 
-  const auto& vec = stmt->args;
-  ASSERT_EQ(vec.size(), 2u);
-  EXPECT_EQ(vec[0], params[0]);
-  EXPECT_EQ(vec[1], params[1]);
+    const auto& vec = stmt->args;
+    ASSERT_EQ(vec.size(), 2u);
+    EXPECT_EQ(vec[0], params[0]);
+    EXPECT_EQ(vec[1], params[1]);
 }
 
 TEST_F(CallExpressionTest, CreationIdentifier_WithSource) {
-  auto* func = Expr("func");
-  auto* stmt = create<CallExpression>(Source{{20, 2}}, func, ExpressionList{});
-  EXPECT_EQ(stmt->target.name, func);
-  EXPECT_EQ(stmt->target.type, nullptr);
+    auto* func = Expr("func");
+    auto* stmt = create<CallExpression>(Source{{20, 2}}, func, ExpressionList{});
+    EXPECT_EQ(stmt->target.name, func);
+    EXPECT_EQ(stmt->target.type, nullptr);
 
-  auto src = stmt->source;
-  EXPECT_EQ(src.range.begin.line, 20u);
-  EXPECT_EQ(src.range.begin.column, 2u);
+    auto src = stmt->source;
+    EXPECT_EQ(src.range.begin.line, 20u);
+    EXPECT_EQ(src.range.begin.column, 2u);
 }
 
 TEST_F(CallExpressionTest, CreationType) {
-  auto* type = ty.f32();
-  ExpressionList params;
-  params.push_back(Expr("param1"));
-  params.push_back(Expr("param2"));
+    auto* type = ty.f32();
+    ExpressionList params;
+    params.push_back(Expr("param1"));
+    params.push_back(Expr("param2"));
 
-  auto* stmt = create<CallExpression>(type, params);
-  EXPECT_EQ(stmt->target.name, nullptr);
-  EXPECT_EQ(stmt->target.type, type);
+    auto* stmt = create<CallExpression>(type, params);
+    EXPECT_EQ(stmt->target.name, nullptr);
+    EXPECT_EQ(stmt->target.type, type);
 
-  const auto& vec = stmt->args;
-  ASSERT_EQ(vec.size(), 2u);
-  EXPECT_EQ(vec[0], params[0]);
-  EXPECT_EQ(vec[1], params[1]);
+    const auto& vec = stmt->args;
+    ASSERT_EQ(vec.size(), 2u);
+    EXPECT_EQ(vec[0], params[0]);
+    EXPECT_EQ(vec[1], params[1]);
 }
 
 TEST_F(CallExpressionTest, CreationType_WithSource) {
-  auto* type = ty.f32();
-  auto* stmt = create<CallExpression>(Source{{20, 2}}, type, ExpressionList{});
-  EXPECT_EQ(stmt->target.name, nullptr);
-  EXPECT_EQ(stmt->target.type, type);
+    auto* type = ty.f32();
+    auto* stmt = create<CallExpression>(Source{{20, 2}}, type, ExpressionList{});
+    EXPECT_EQ(stmt->target.name, nullptr);
+    EXPECT_EQ(stmt->target.type, type);
 
-  auto src = stmt->source;
-  EXPECT_EQ(src.range.begin.line, 20u);
-  EXPECT_EQ(src.range.begin.column, 2u);
+    auto src = stmt->source;
+    EXPECT_EQ(src.range.begin.line, 20u);
+    EXPECT_EQ(src.range.begin.column, 2u);
 }
 
 TEST_F(CallExpressionTest, IsCall) {
-  auto* func = Expr("func");
-  auto* stmt = create<CallExpression>(func, ExpressionList{});
-  EXPECT_TRUE(stmt->Is<CallExpression>());
+    auto* func = Expr("func");
+    auto* stmt = create<CallExpression>(func, ExpressionList{});
+    EXPECT_TRUE(stmt->Is<CallExpression>());
 }
 
 TEST_F(CallExpressionTest, Assert_Null_Identifier) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.create<CallExpression>(static_cast<IdentifierExpression*>(nullptr),
-                                 ExpressionList{});
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.create<CallExpression>(static_cast<IdentifierExpression*>(nullptr), ExpressionList{});
+        },
+        "internal compiler error");
 }
 
 TEST_F(CallExpressionTest, Assert_Null_Type) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.create<CallExpression>(static_cast<Type*>(nullptr), ExpressionList{});
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.create<CallExpression>(static_cast<Type*>(nullptr), ExpressionList{});
+        },
+        "internal compiler error");
 }
 
 TEST_F(CallExpressionTest, Assert_Null_Param) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        ExpressionList params;
-        params.push_back(b.Expr("param1"));
-        params.push_back(nullptr);
-        params.push_back(b.Expr("param2"));
-        b.create<CallExpression>(b.Expr("func"), params);
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            ExpressionList params;
+            params.push_back(b.Expr("param1"));
+            params.push_back(nullptr);
+            params.push_back(b.Expr("param2"));
+            b.create<CallExpression>(b.Expr("func"), params);
+        },
+        "internal compiler error");
 }
 
 TEST_F(CallExpressionTest, Assert_DifferentProgramID_Identifier) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.create<CallExpression>(b2.Expr("func"), ExpressionList{});
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.create<CallExpression>(b2.Expr("func"), ExpressionList{});
+        },
+        "internal compiler error");
 }
 
 TEST_F(CallExpressionTest, Assert_DifferentProgramID_Type) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.create<CallExpression>(b2.ty.f32(), ExpressionList{});
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.create<CallExpression>(b2.ty.f32(), ExpressionList{});
+        },
+        "internal compiler error");
 }
 
 TEST_F(CallExpressionTest, Assert_DifferentProgramID_Param) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.create<CallExpression>(b1.Expr("func"),
-                                  ExpressionList{b2.Expr("param1")});
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.create<CallExpression>(b1.Expr("func"), ExpressionList{b2.Expr("param1")});
+        },
+        "internal compiler error");
 }
 
 }  // namespace
diff --git a/src/tint/ast/call_statement.cc b/src/tint/ast/call_statement.cc
index 717b1a9..5e98fc9 100644
--- a/src/tint/ast/call_statement.cc
+++ b/src/tint/ast/call_statement.cc
@@ -20,12 +20,10 @@
 
 namespace tint::ast {
 
-CallStatement::CallStatement(ProgramID pid,
-                             const Source& src,
-                             const CallExpression* call)
+CallStatement::CallStatement(ProgramID pid, const Source& src, const CallExpression* call)
     : Base(pid, src), expr(call) {
-  TINT_ASSERT(AST, expr);
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, expr, program_id);
+    TINT_ASSERT(AST, expr);
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, expr, program_id);
 }
 
 CallStatement::CallStatement(CallStatement&&) = default;
@@ -33,10 +31,10 @@
 CallStatement::~CallStatement() = default;
 
 const CallStatement* CallStatement::Clone(CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  auto* call = ctx->Clone(expr);
-  return ctx->dst->create<CallStatement>(src, call);
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    auto* call = ctx->Clone(expr);
+    return ctx->dst->create<CallStatement>(src, call);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/call_statement.h b/src/tint/ast/call_statement.h
index 7b0677b..d0d9f53 100644
--- a/src/tint/ast/call_statement.h
+++ b/src/tint/ast/call_statement.h
@@ -22,24 +22,24 @@
 
 /// A call expression
 class CallStatement final : public Castable<CallStatement, Statement> {
- public:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node for the statement
-  /// @param call the function
-  CallStatement(ProgramID pid, const Source& src, const CallExpression* call);
-  /// Move constructor
-  CallStatement(CallStatement&&);
-  ~CallStatement() override;
+  public:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node for the statement
+    /// @param call the function
+    CallStatement(ProgramID pid, const Source& src, const CallExpression* call);
+    /// Move constructor
+    CallStatement(CallStatement&&);
+    ~CallStatement() override;
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const CallStatement* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const CallStatement* Clone(CloneContext* ctx) const override;
 
-  /// The call expression
-  const CallExpression* const expr;
+    /// The call expression
+    const CallExpression* const expr;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/call_statement_test.cc b/src/tint/ast/call_statement_test.cc
index 1f06a99..3426597 100644
--- a/src/tint/ast/call_statement_test.cc
+++ b/src/tint/ast/call_statement_test.cc
@@ -23,35 +23,34 @@
 using CallStatementTest = TestHelper;
 
 TEST_F(CallStatementTest, Creation) {
-  auto* expr = create<CallExpression>(Expr("func"), ExpressionList{});
+    auto* expr = create<CallExpression>(Expr("func"), ExpressionList{});
 
-  auto* c = create<CallStatement>(expr);
-  EXPECT_EQ(c->expr, expr);
+    auto* c = create<CallStatement>(expr);
+    EXPECT_EQ(c->expr, expr);
 }
 
 TEST_F(CallStatementTest, IsCall) {
-  auto* c = create<CallStatement>(Call("f"));
-  EXPECT_TRUE(c->Is<CallStatement>());
+    auto* c = create<CallStatement>(Call("f"));
+    EXPECT_TRUE(c->Is<CallStatement>());
 }
 
 TEST_F(CallStatementTest, Assert_Null_Call) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.create<CallStatement>(nullptr);
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.create<CallStatement>(nullptr);
+        },
+        "internal compiler error");
 }
 
 TEST_F(CallStatementTest, Assert_DifferentProgramID_Call) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.create<CallStatement>(
-            b2.create<CallExpression>(b2.Expr("func"), ExpressionList{}));
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.create<CallStatement>(b2.create<CallExpression>(b2.Expr("func"), ExpressionList{}));
+        },
+        "internal compiler error");
 }
 
 }  // namespace
diff --git a/src/tint/ast/case_statement.cc b/src/tint/ast/case_statement.cc
index d4a5559..bf1f0bf 100644
--- a/src/tint/ast/case_statement.cc
+++ b/src/tint/ast/case_statement.cc
@@ -25,12 +25,12 @@
                              CaseSelectorList s,
                              const BlockStatement* b)
     : Base(pid, src), selectors(s), body(b) {
-  TINT_ASSERT(AST, body);
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, body, program_id);
-  for (auto* selector : selectors) {
-    TINT_ASSERT(AST, selector);
-    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, selector, program_id);
-  }
+    TINT_ASSERT(AST, body);
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, body, program_id);
+    for (auto* selector : selectors) {
+        TINT_ASSERT(AST, selector);
+        TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, selector, program_id);
+    }
 }
 
 CaseStatement::CaseStatement(CaseStatement&&) = default;
@@ -38,11 +38,11 @@
 CaseStatement::~CaseStatement() = default;
 
 const CaseStatement* CaseStatement::Clone(CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  auto sel = ctx->Clone(selectors);
-  auto* b = ctx->Clone(body);
-  return ctx->dst->create<CaseStatement>(src, sel, b);
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    auto sel = ctx->Clone(selectors);
+    auto* b = ctx->Clone(body);
+    return ctx->dst->create<CaseStatement>(src, sel, b);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/case_statement.h b/src/tint/ast/case_statement.h
index d030e70..19ca693 100644
--- a/src/tint/ast/case_statement.h
+++ b/src/tint/ast/case_statement.h
@@ -27,34 +27,34 @@
 
 /// A case statement
 class CaseStatement final : public Castable<CaseStatement, Statement> {
- public:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  /// @param selectors the case selectors
-  /// @param body the case body
-  CaseStatement(ProgramID pid,
-                const Source& src,
-                CaseSelectorList selectors,
-                const BlockStatement* body);
-  /// Move constructor
-  CaseStatement(CaseStatement&&);
-  ~CaseStatement() override;
+  public:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    /// @param selectors the case selectors
+    /// @param body the case body
+    CaseStatement(ProgramID pid,
+                  const Source& src,
+                  CaseSelectorList selectors,
+                  const BlockStatement* body);
+    /// Move constructor
+    CaseStatement(CaseStatement&&);
+    ~CaseStatement() override;
 
-  /// @returns true if this is a default statement
-  bool IsDefault() const { return selectors.empty(); }
+    /// @returns true if this is a default statement
+    bool IsDefault() const { return selectors.empty(); }
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const CaseStatement* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const CaseStatement* Clone(CloneContext* ctx) const override;
 
-  /// The case selectors, empty if none set
-  const CaseSelectorList selectors;
+    /// The case selectors, empty if none set
+    const CaseSelectorList selectors;
 
-  /// The case body
-  const BlockStatement* const body;
+    /// The case body
+    const BlockStatement* const body;
 };
 
 /// A list of case statements
diff --git a/src/tint/ast/case_statement_test.cc b/src/tint/ast/case_statement_test.cc
index d6b217f..12fcbda 100644
--- a/src/tint/ast/case_statement_test.cc
+++ b/src/tint/ast/case_statement_test.cc
@@ -19,116 +19,116 @@
 #include "src/tint/ast/if_statement.h"
 #include "src/tint/ast/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::ast {
 namespace {
 
 using CaseStatementTest = TestHelper;
 
 TEST_F(CaseStatementTest, Creation_i32) {
-  CaseSelectorList b;
-  auto* selector = create<SintLiteralExpression>(2);
-  b.push_back(selector);
+    CaseSelectorList b;
+    auto* selector = Expr(2_i);
+    b.push_back(selector);
 
-  auto* discard = create<DiscardStatement>();
-  auto* body = create<BlockStatement>(StatementList{discard});
+    auto* discard = create<DiscardStatement>();
+    auto* body = create<BlockStatement>(StatementList{discard});
 
-  auto* c = create<CaseStatement>(b, body);
-  ASSERT_EQ(c->selectors.size(), 1u);
-  EXPECT_EQ(c->selectors[0], selector);
-  ASSERT_EQ(c->body->statements.size(), 1u);
-  EXPECT_EQ(c->body->statements[0], discard);
+    auto* c = create<CaseStatement>(b, body);
+    ASSERT_EQ(c->selectors.size(), 1u);
+    EXPECT_EQ(c->selectors[0], selector);
+    ASSERT_EQ(c->body->statements.size(), 1u);
+    EXPECT_EQ(c->body->statements[0], discard);
 }
 
 TEST_F(CaseStatementTest, Creation_u32) {
-  CaseSelectorList b;
-  auto* selector = create<UintLiteralExpression>(2u);
-  b.push_back(selector);
+    CaseSelectorList b;
+    auto* selector = Expr(2_u);
+    b.push_back(selector);
 
-  auto* discard = create<DiscardStatement>();
-  auto* body = create<BlockStatement>(StatementList{discard});
+    auto* discard = create<DiscardStatement>();
+    auto* body = create<BlockStatement>(StatementList{discard});
 
-  auto* c = create<CaseStatement>(b, body);
-  ASSERT_EQ(c->selectors.size(), 1u);
-  EXPECT_EQ(c->selectors[0], selector);
-  ASSERT_EQ(c->body->statements.size(), 1u);
-  EXPECT_EQ(c->body->statements[0], discard);
+    auto* c = create<CaseStatement>(b, body);
+    ASSERT_EQ(c->selectors.size(), 1u);
+    EXPECT_EQ(c->selectors[0], selector);
+    ASSERT_EQ(c->body->statements.size(), 1u);
+    EXPECT_EQ(c->body->statements[0], discard);
 }
 
 TEST_F(CaseStatementTest, Creation_WithSource) {
-  CaseSelectorList b;
-  b.push_back(create<SintLiteralExpression>(2));
+    CaseSelectorList b;
+    b.push_back(Expr(2_i));
 
-  auto* body = create<BlockStatement>(StatementList{
-      create<DiscardStatement>(),
-  });
-  auto* c = create<CaseStatement>(Source{Source::Location{20, 2}}, b, body);
-  auto src = c->source;
-  EXPECT_EQ(src.range.begin.line, 20u);
-  EXPECT_EQ(src.range.begin.column, 2u);
+    auto* body = create<BlockStatement>(StatementList{
+        create<DiscardStatement>(),
+    });
+    auto* c = create<CaseStatement>(Source{Source::Location{20, 2}}, b, body);
+    auto src = c->source;
+    EXPECT_EQ(src.range.begin.line, 20u);
+    EXPECT_EQ(src.range.begin.column, 2u);
 }
 
 TEST_F(CaseStatementTest, IsDefault_WithoutSelectors) {
-  auto* body = create<BlockStatement>(StatementList{
-      create<DiscardStatement>(),
-  });
-  auto* c = create<CaseStatement>(CaseSelectorList{}, body);
-  EXPECT_TRUE(c->IsDefault());
+    auto* body = create<BlockStatement>(StatementList{
+        create<DiscardStatement>(),
+    });
+    auto* c = create<CaseStatement>(CaseSelectorList{}, body);
+    EXPECT_TRUE(c->IsDefault());
 }
 
 TEST_F(CaseStatementTest, IsDefault_WithSelectors) {
-  CaseSelectorList b;
-  b.push_back(create<SintLiteralExpression>(2));
+    CaseSelectorList b;
+    b.push_back(Expr(2_i));
 
-  auto* c = create<CaseStatement>(b, create<BlockStatement>(StatementList{}));
-  EXPECT_FALSE(c->IsDefault());
+    auto* c = create<CaseStatement>(b, create<BlockStatement>(StatementList{}));
+    EXPECT_FALSE(c->IsDefault());
 }
 
 TEST_F(CaseStatementTest, IsCase) {
-  auto* c = create<CaseStatement>(CaseSelectorList{},
-                                  create<BlockStatement>(StatementList{}));
-  EXPECT_TRUE(c->Is<CaseStatement>());
+    auto* c = create<CaseStatement>(CaseSelectorList{}, create<BlockStatement>(StatementList{}));
+    EXPECT_TRUE(c->Is<CaseStatement>());
 }
 
 TEST_F(CaseStatementTest, Assert_Null_Body) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.create<CaseStatement>(CaseSelectorList{}, nullptr);
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.create<CaseStatement>(CaseSelectorList{}, nullptr);
+        },
+        "internal compiler error");
 }
 
 TEST_F(CaseStatementTest, Assert_Null_Selector) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.create<CaseStatement>(CaseSelectorList{nullptr},
-                                b.create<BlockStatement>(StatementList{}));
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.create<CaseStatement>(CaseSelectorList{nullptr},
+                                    b.create<BlockStatement>(StatementList{}));
+        },
+        "internal compiler error");
 }
 
 TEST_F(CaseStatementTest, Assert_DifferentProgramID_Call) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.create<CaseStatement>(CaseSelectorList{},
-                                 b2.create<BlockStatement>(StatementList{}));
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.create<CaseStatement>(CaseSelectorList{},
+                                     b2.create<BlockStatement>(StatementList{}));
+        },
+        "internal compiler error");
 }
 
 TEST_F(CaseStatementTest, Assert_DifferentProgramID_Selector) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.create<CaseStatement>(
-            CaseSelectorList{b2.create<SintLiteralExpression>(2)},
-            b1.create<BlockStatement>(StatementList{}));
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.create<CaseStatement>(CaseSelectorList{b2.Expr(2_i)},
+                                     b1.create<BlockStatement>(StatementList{}));
+        },
+        "internal compiler error");
 }
 
 }  // namespace
diff --git a/src/tint/ast/compound_assignment_statement.cc b/src/tint/ast/compound_assignment_statement.cc
index 2df37f7..848d500 100644
--- a/src/tint/ast/compound_assignment_statement.cc
+++ b/src/tint/ast/compound_assignment_statement.cc
@@ -26,24 +26,22 @@
                                                          const Expression* r,
                                                          BinaryOp o)
     : Base(pid, src), lhs(l), rhs(r), op(o) {
-  TINT_ASSERT(AST, lhs);
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, lhs, program_id);
-  TINT_ASSERT(AST, rhs);
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, rhs, program_id);
+    TINT_ASSERT(AST, lhs);
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, lhs, program_id);
+    TINT_ASSERT(AST, rhs);
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, rhs, program_id);
 }
 
-CompoundAssignmentStatement::CompoundAssignmentStatement(
-    CompoundAssignmentStatement&&) = default;
+CompoundAssignmentStatement::CompoundAssignmentStatement(CompoundAssignmentStatement&&) = default;
 
 CompoundAssignmentStatement::~CompoundAssignmentStatement() = default;
 
-const CompoundAssignmentStatement* CompoundAssignmentStatement::Clone(
-    CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  auto* l = ctx->Clone(lhs);
-  auto* r = ctx->Clone(rhs);
-  return ctx->dst->create<CompoundAssignmentStatement>(src, l, r, op);
+const CompoundAssignmentStatement* CompoundAssignmentStatement::Clone(CloneContext* ctx) const {
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    auto* l = ctx->Clone(lhs);
+    auto* r = ctx->Clone(rhs);
+    return ctx->dst->create<CompoundAssignmentStatement>(src, l, r, op);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/compound_assignment_statement.h b/src/tint/ast/compound_assignment_statement.h
index 030efea..ba9a558 100644
--- a/src/tint/ast/compound_assignment_statement.h
+++ b/src/tint/ast/compound_assignment_statement.h
@@ -22,38 +22,37 @@
 namespace tint::ast {
 
 /// A compound assignment statement
-class CompoundAssignmentStatement final
-    : public Castable<CompoundAssignmentStatement, Statement> {
- public:
-  /// Constructor
-  /// @param program_id the identifier of the program that owns this node
-  /// @param source the compound assignment statement source
-  /// @param lhs the left side of the expression
-  /// @param rhs the right side of the expression
-  /// @param op the binary operator
-  CompoundAssignmentStatement(ProgramID program_id,
-                              const Source& source,
-                              const Expression* lhs,
-                              const Expression* rhs,
-                              BinaryOp op);
-  /// Move constructor
-  CompoundAssignmentStatement(CompoundAssignmentStatement&&);
-  ~CompoundAssignmentStatement() override;
+class CompoundAssignmentStatement final : public Castable<CompoundAssignmentStatement, Statement> {
+  public:
+    /// Constructor
+    /// @param program_id the identifier of the program that owns this node
+    /// @param source the compound assignment statement source
+    /// @param lhs the left side of the expression
+    /// @param rhs the right side of the expression
+    /// @param op the binary operator
+    CompoundAssignmentStatement(ProgramID program_id,
+                                const Source& source,
+                                const Expression* lhs,
+                                const Expression* rhs,
+                                BinaryOp op);
+    /// Move constructor
+    CompoundAssignmentStatement(CompoundAssignmentStatement&&);
+    ~CompoundAssignmentStatement() override;
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const CompoundAssignmentStatement* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const CompoundAssignmentStatement* Clone(CloneContext* ctx) const override;
 
-  /// left side expression
-  const Expression* const lhs;
+    /// left side expression
+    const Expression* const lhs;
 
-  /// right side expression
-  const Expression* const rhs;
+    /// right side expression
+    const Expression* const rhs;
 
-  /// the binary operator
-  const BinaryOp op;
+    /// the binary operator
+    const BinaryOp op;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/compound_assignment_statement_test.cc b/src/tint/ast/compound_assignment_statement_test.cc
index 080f93e..7560889 100644
--- a/src/tint/ast/compound_assignment_statement_test.cc
+++ b/src/tint/ast/compound_assignment_statement_test.cc
@@ -17,83 +17,80 @@
 #include "gtest/gtest-spi.h"
 #include "src/tint/ast/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::ast {
 namespace {
 
 using CompoundAssignmentStatementTest = TestHelper;
 
 TEST_F(CompoundAssignmentStatementTest, Creation) {
-  auto* lhs = Expr("lhs");
-  auto* rhs = Expr("rhs");
-  auto op = BinaryOp::kAdd;
+    auto* lhs = Expr("lhs");
+    auto* rhs = Expr("rhs");
+    auto op = BinaryOp::kAdd;
 
-  auto* stmt = create<CompoundAssignmentStatement>(lhs, rhs, op);
-  EXPECT_EQ(stmt->lhs, lhs);
-  EXPECT_EQ(stmt->rhs, rhs);
-  EXPECT_EQ(stmt->op, op);
+    auto* stmt = create<CompoundAssignmentStatement>(lhs, rhs, op);
+    EXPECT_EQ(stmt->lhs, lhs);
+    EXPECT_EQ(stmt->rhs, rhs);
+    EXPECT_EQ(stmt->op, op);
 }
 
 TEST_F(CompoundAssignmentStatementTest, CreationWithSource) {
-  auto* lhs = Expr("lhs");
-  auto* rhs = Expr("rhs");
-  auto op = BinaryOp::kMultiply;
+    auto* lhs = Expr("lhs");
+    auto* rhs = Expr("rhs");
+    auto op = BinaryOp::kMultiply;
 
-  auto* stmt = create<CompoundAssignmentStatement>(
-      Source{Source::Location{20, 2}}, lhs, rhs, op);
-  auto src = stmt->source;
-  EXPECT_EQ(src.range.begin.line, 20u);
-  EXPECT_EQ(src.range.begin.column, 2u);
+    auto* stmt = create<CompoundAssignmentStatement>(Source{Source::Location{20, 2}}, lhs, rhs, op);
+    auto src = stmt->source;
+    EXPECT_EQ(src.range.begin.line, 20u);
+    EXPECT_EQ(src.range.begin.column, 2u);
 }
 
 TEST_F(CompoundAssignmentStatementTest, IsCompoundAssign) {
-  auto* lhs = Expr("lhs");
-  auto* rhs = Expr("rhs");
-  auto op = BinaryOp::kSubtract;
+    auto* lhs = Expr("lhs");
+    auto* rhs = Expr("rhs");
+    auto op = BinaryOp::kSubtract;
 
-  auto* stmt = create<CompoundAssignmentStatement>(lhs, rhs, op);
-  EXPECT_TRUE(stmt->Is<CompoundAssignmentStatement>());
+    auto* stmt = create<CompoundAssignmentStatement>(lhs, rhs, op);
+    EXPECT_TRUE(stmt->Is<CompoundAssignmentStatement>());
 }
 
 TEST_F(CompoundAssignmentStatementTest, Assert_Null_LHS) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.create<CompoundAssignmentStatement>(nullptr, b.Expr(1),
-                                              BinaryOp::kAdd);
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.create<CompoundAssignmentStatement>(nullptr, b.Expr(1_i), BinaryOp::kAdd);
+        },
+        "internal compiler error");
 }
 
 TEST_F(CompoundAssignmentStatementTest, Assert_Null_RHS) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.create<CompoundAssignmentStatement>(b.Expr(1), nullptr,
-                                              BinaryOp::kAdd);
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.create<CompoundAssignmentStatement>(b.Expr(1_i), nullptr, BinaryOp::kAdd);
+        },
+        "internal compiler error");
 }
 
 TEST_F(CompoundAssignmentStatementTest, Assert_DifferentProgramID_LHS) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.create<CompoundAssignmentStatement>(b2.Expr("lhs"), b1.Expr("rhs"),
-                                               BinaryOp::kAdd);
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.create<CompoundAssignmentStatement>(b2.Expr("lhs"), b1.Expr("rhs"), BinaryOp::kAdd);
+        },
+        "internal compiler error");
 }
 
 TEST_F(CompoundAssignmentStatementTest, Assert_DifferentProgramID_RHS) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.create<CompoundAssignmentStatement>(b1.Expr("lhs"), b2.Expr("rhs"),
-                                               BinaryOp::kAdd);
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.create<CompoundAssignmentStatement>(b1.Expr("lhs"), b2.Expr("rhs"), BinaryOp::kAdd);
+        },
+        "internal compiler error");
 }
 
 }  // namespace
diff --git a/src/tint/ast/continue_statement.cc b/src/tint/ast/continue_statement.cc
index e7d669f..8ae4b9c 100644
--- a/src/tint/ast/continue_statement.cc
+++ b/src/tint/ast/continue_statement.cc
@@ -20,17 +20,16 @@
 
 namespace tint::ast {
 
-ContinueStatement::ContinueStatement(ProgramID pid, const Source& src)
-    : Base(pid, src) {}
+ContinueStatement::ContinueStatement(ProgramID pid, const Source& src) : Base(pid, src) {}
 
 ContinueStatement::ContinueStatement(ContinueStatement&&) = default;
 
 ContinueStatement::~ContinueStatement() = default;
 
 const ContinueStatement* ContinueStatement::Clone(CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  return ctx->dst->create<ContinueStatement>(src);
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    return ctx->dst->create<ContinueStatement>(src);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/continue_statement.h b/src/tint/ast/continue_statement.h
index 5761bfc..17d8586 100644
--- a/src/tint/ast/continue_statement.h
+++ b/src/tint/ast/continue_statement.h
@@ -21,20 +21,20 @@
 
 /// An continue statement
 class ContinueStatement final : public Castable<ContinueStatement, Statement> {
- public:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  ContinueStatement(ProgramID pid, const Source& src);
-  /// Move constructor
-  ContinueStatement(ContinueStatement&&);
-  ~ContinueStatement() override;
+  public:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    ContinueStatement(ProgramID pid, const Source& src);
+    /// Move constructor
+    ContinueStatement(ContinueStatement&&);
+    ~ContinueStatement() override;
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const ContinueStatement* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const ContinueStatement* Clone(CloneContext* ctx) const override;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/continue_statement_test.cc b/src/tint/ast/continue_statement_test.cc
index 943cdee..31cabdd 100644
--- a/src/tint/ast/continue_statement_test.cc
+++ b/src/tint/ast/continue_statement_test.cc
@@ -22,15 +22,15 @@
 using ContinueStatementTest = TestHelper;
 
 TEST_F(ContinueStatementTest, Creation_WithSource) {
-  auto* stmt = create<ContinueStatement>(Source{Source::Location{20, 2}});
-  auto src = stmt->source;
-  EXPECT_EQ(src.range.begin.line, 20u);
-  EXPECT_EQ(src.range.begin.column, 2u);
+    auto* stmt = create<ContinueStatement>(Source{Source::Location{20, 2}});
+    auto src = stmt->source;
+    EXPECT_EQ(src.range.begin.line, 20u);
+    EXPECT_EQ(src.range.begin.column, 2u);
 }
 
 TEST_F(ContinueStatementTest, IsContinue) {
-  auto* stmt = create<ContinueStatement>();
-  EXPECT_TRUE(stmt->Is<ContinueStatement>());
+    auto* stmt = create<ContinueStatement>();
+    EXPECT_TRUE(stmt->Is<ContinueStatement>());
 }
 
 }  // namespace
diff --git a/src/tint/ast/depth_multisampled_texture.cc b/src/tint/ast/depth_multisampled_texture.cc
index 9b09864..66c5a86 100644
--- a/src/tint/ast/depth_multisampled_texture.cc
+++ b/src/tint/ast/depth_multisampled_texture.cc
@@ -22,7 +22,7 @@
 namespace {
 
 bool IsValidDepthDimension(TextureDimension dim) {
-  return dim == TextureDimension::k2d;
+    return dim == TextureDimension::k2d;
 }
 
 }  // namespace
@@ -31,24 +31,22 @@
                                                    const Source& src,
                                                    TextureDimension d)
     : Base(pid, src, d) {
-  TINT_ASSERT(AST, IsValidDepthDimension(dim));
+    TINT_ASSERT(AST, IsValidDepthDimension(dim));
 }
 
-DepthMultisampledTexture::DepthMultisampledTexture(DepthMultisampledTexture&&) =
-    default;
+DepthMultisampledTexture::DepthMultisampledTexture(DepthMultisampledTexture&&) = default;
 
 DepthMultisampledTexture::~DepthMultisampledTexture() = default;
 
 std::string DepthMultisampledTexture::FriendlyName(const SymbolTable&) const {
-  std::ostringstream out;
-  out << "texture_depth_multisampled_" << dim;
-  return out.str();
+    std::ostringstream out;
+    out << "texture_depth_multisampled_" << dim;
+    return out.str();
 }
 
-const DepthMultisampledTexture* DepthMultisampledTexture::Clone(
-    CloneContext* ctx) const {
-  auto src = ctx->Clone(source);
-  return ctx->dst->create<DepthMultisampledTexture>(src, dim);
+const DepthMultisampledTexture* DepthMultisampledTexture::Clone(CloneContext* ctx) const {
+    auto src = ctx->Clone(source);
+    return ctx->dst->create<DepthMultisampledTexture>(src, dim);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/depth_multisampled_texture.h b/src/tint/ast/depth_multisampled_texture.h
index 67f6ab0..d15ac7a 100644
--- a/src/tint/ast/depth_multisampled_texture.h
+++ b/src/tint/ast/depth_multisampled_texture.h
@@ -22,29 +22,26 @@
 namespace tint::ast {
 
 /// A multisampled depth texture type.
-class DepthMultisampledTexture final
-    : public Castable<DepthMultisampledTexture, Texture> {
- public:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  /// @param dim the dimensionality of the texture
-  DepthMultisampledTexture(ProgramID pid,
-                           const Source& src,
-                           TextureDimension dim);
-  /// Move constructor
-  DepthMultisampledTexture(DepthMultisampledTexture&&);
-  ~DepthMultisampledTexture() override;
+class DepthMultisampledTexture final : public Castable<DepthMultisampledTexture, Texture> {
+  public:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    /// @param dim the dimensionality of the texture
+    DepthMultisampledTexture(ProgramID pid, const Source& src, TextureDimension dim);
+    /// Move constructor
+    DepthMultisampledTexture(DepthMultisampledTexture&&);
+    ~DepthMultisampledTexture() override;
 
-  /// @param symbols the program's symbol table
-  /// @returns the name for this type that closely resembles how it would be
-  /// declared in WGSL.
-  std::string FriendlyName(const SymbolTable& symbols) const override;
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type that closely resembles how it would be
+    /// declared in WGSL.
+    std::string FriendlyName(const SymbolTable& symbols) const override;
 
-  /// Clones this type and all transitive types using the `CloneContext` `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned type
-  const DepthMultisampledTexture* Clone(CloneContext* ctx) const override;
+    /// Clones this type and all transitive types using the `CloneContext` `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned type
+    const DepthMultisampledTexture* Clone(CloneContext* ctx) const override;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/depth_multisampled_texture_test.cc b/src/tint/ast/depth_multisampled_texture_test.cc
index 0ae0ada..1de335d 100644
--- a/src/tint/ast/depth_multisampled_texture_test.cc
+++ b/src/tint/ast/depth_multisampled_texture_test.cc
@@ -22,13 +22,13 @@
 using AstDepthMultisampledTextureTest = TestHelper;
 
 TEST_F(AstDepthMultisampledTextureTest, Dim) {
-  auto* d = create<DepthMultisampledTexture>(TextureDimension::k2d);
-  EXPECT_EQ(d->dim, TextureDimension::k2d);
+    auto* d = create<DepthMultisampledTexture>(TextureDimension::k2d);
+    EXPECT_EQ(d->dim, TextureDimension::k2d);
 }
 
 TEST_F(AstDepthMultisampledTextureTest, FriendlyName) {
-  auto* d = create<DepthMultisampledTexture>(TextureDimension::k2d);
-  EXPECT_EQ(d->FriendlyName(Symbols()), "texture_depth_multisampled_2d");
+    auto* d = create<DepthMultisampledTexture>(TextureDimension::k2d);
+    EXPECT_EQ(d->FriendlyName(Symbols()), "texture_depth_multisampled_2d");
 }
 
 }  // namespace
diff --git a/src/tint/ast/depth_texture.cc b/src/tint/ast/depth_texture.cc
index fc1c923..6c0858f 100644
--- a/src/tint/ast/depth_texture.cc
+++ b/src/tint/ast/depth_texture.cc
@@ -22,15 +22,15 @@
 namespace {
 
 bool IsValidDepthDimension(TextureDimension dim) {
-  return dim == TextureDimension::k2d || dim == TextureDimension::k2dArray ||
-         dim == TextureDimension::kCube || dim == TextureDimension::kCubeArray;
+    return dim == TextureDimension::k2d || dim == TextureDimension::k2dArray ||
+           dim == TextureDimension::kCube || dim == TextureDimension::kCubeArray;
 }
 
 }  // namespace
 
 DepthTexture::DepthTexture(ProgramID pid, const Source& src, TextureDimension d)
     : Base(pid, src, d) {
-  TINT_ASSERT(AST, IsValidDepthDimension(dim));
+    TINT_ASSERT(AST, IsValidDepthDimension(dim));
 }
 
 DepthTexture::DepthTexture(DepthTexture&&) = default;
@@ -38,14 +38,14 @@
 DepthTexture::~DepthTexture() = default;
 
 std::string DepthTexture::FriendlyName(const SymbolTable&) const {
-  std::ostringstream out;
-  out << "texture_depth_" << dim;
-  return out.str();
+    std::ostringstream out;
+    out << "texture_depth_" << dim;
+    return out.str();
 }
 
 const DepthTexture* DepthTexture::Clone(CloneContext* ctx) const {
-  auto src = ctx->Clone(source);
-  return ctx->dst->create<DepthTexture>(src, dim);
+    auto src = ctx->Clone(source);
+    return ctx->dst->create<DepthTexture>(src, dim);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/depth_texture.h b/src/tint/ast/depth_texture.h
index ddf4e95..42349e3 100644
--- a/src/tint/ast/depth_texture.h
+++ b/src/tint/ast/depth_texture.h
@@ -23,25 +23,25 @@
 
 /// A depth texture type.
 class DepthTexture final : public Castable<DepthTexture, Texture> {
- public:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  /// @param dim the dimensionality of the texture
-  DepthTexture(ProgramID pid, const Source& src, TextureDimension dim);
-  /// Move constructor
-  DepthTexture(DepthTexture&&);
-  ~DepthTexture() override;
+  public:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    /// @param dim the dimensionality of the texture
+    DepthTexture(ProgramID pid, const Source& src, TextureDimension dim);
+    /// Move constructor
+    DepthTexture(DepthTexture&&);
+    ~DepthTexture() override;
 
-  /// @param symbols the program's symbol table
-  /// @returns the name for this type that closely resembles how it would be
-  /// declared in WGSL.
-  std::string FriendlyName(const SymbolTable& symbols) const override;
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type that closely resembles how it would be
+    /// declared in WGSL.
+    std::string FriendlyName(const SymbolTable& symbols) const override;
 
-  /// Clones this type and all transitive types using the `CloneContext` `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned type
-  const DepthTexture* Clone(CloneContext* ctx) const override;
+    /// Clones this type and all transitive types using the `CloneContext` `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned type
+    const DepthTexture* Clone(CloneContext* ctx) const override;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/depth_texture_test.cc b/src/tint/ast/depth_texture_test.cc
index 4ec2aaa..15dc356 100644
--- a/src/tint/ast/depth_texture_test.cc
+++ b/src/tint/ast/depth_texture_test.cc
@@ -22,20 +22,20 @@
 using AstDepthTextureTest = TestHelper;
 
 TEST_F(AstDepthTextureTest, IsTexture) {
-  Texture* ty = create<DepthTexture>(TextureDimension::kCube);
-  EXPECT_TRUE(ty->Is<DepthTexture>());
-  EXPECT_FALSE(ty->Is<SampledTexture>());
-  EXPECT_FALSE(ty->Is<StorageTexture>());
+    Texture* ty = create<DepthTexture>(TextureDimension::kCube);
+    EXPECT_TRUE(ty->Is<DepthTexture>());
+    EXPECT_FALSE(ty->Is<SampledTexture>());
+    EXPECT_FALSE(ty->Is<StorageTexture>());
 }
 
 TEST_F(AstDepthTextureTest, Dim) {
-  auto* d = create<DepthTexture>(TextureDimension::kCube);
-  EXPECT_EQ(d->dim, TextureDimension::kCube);
+    auto* d = create<DepthTexture>(TextureDimension::kCube);
+    EXPECT_EQ(d->dim, TextureDimension::kCube);
 }
 
 TEST_F(AstDepthTextureTest, FriendlyName) {
-  auto* d = create<DepthTexture>(TextureDimension::kCube);
-  EXPECT_EQ(d->FriendlyName(Symbols()), "texture_depth_cube");
+    auto* d = create<DepthTexture>(TextureDimension::kCube);
+    EXPECT_EQ(d->FriendlyName(Symbols()), "texture_depth_cube");
 }
 
 }  // namespace
diff --git a/src/tint/ast/disable_validation_attribute.cc b/src/tint/ast/disable_validation_attribute.cc
index cd009b4..4bc9f74 100644
--- a/src/tint/ast/disable_validation_attribute.cc
+++ b/src/tint/ast/disable_validation_attribute.cc
@@ -20,36 +20,33 @@
 
 namespace tint::ast {
 
-DisableValidationAttribute::DisableValidationAttribute(ProgramID pid,
-                                                       DisabledValidation val)
+DisableValidationAttribute::DisableValidationAttribute(ProgramID pid, DisabledValidation val)
     : Base(pid), validation(val) {}
 
 DisableValidationAttribute::~DisableValidationAttribute() = default;
 
 std::string DisableValidationAttribute::InternalName() const {
-  switch (validation) {
-    case DisabledValidation::kFunctionHasNoBody:
-      return "disable_validation__function_has_no_body";
-    case DisabledValidation::kBindingPointCollision:
-      return "disable_validation__binding_point_collision";
-    case DisabledValidation::kIgnoreStorageClass:
-      return "disable_validation__ignore_storage_class";
-    case DisabledValidation::kEntryPointParameter:
-      return "disable_validation__entry_point_parameter";
-    case DisabledValidation::kIgnoreConstructibleFunctionParameter:
-      return "disable_validation__ignore_constructible_function_parameter";
-    case DisabledValidation::kIgnoreStrideAttribute:
-      return "disable_validation__ignore_stride";
-    case DisabledValidation::kIgnoreInvalidPointerArgument:
-      return "disable_validation__ignore_invalid_pointer_argument";
-  }
-  return "<invalid>";
+    switch (validation) {
+        case DisabledValidation::kFunctionHasNoBody:
+            return "disable_validation__function_has_no_body";
+        case DisabledValidation::kBindingPointCollision:
+            return "disable_validation__binding_point_collision";
+        case DisabledValidation::kIgnoreStorageClass:
+            return "disable_validation__ignore_storage_class";
+        case DisabledValidation::kEntryPointParameter:
+            return "disable_validation__entry_point_parameter";
+        case DisabledValidation::kIgnoreConstructibleFunctionParameter:
+            return "disable_validation__ignore_constructible_function_parameter";
+        case DisabledValidation::kIgnoreStrideAttribute:
+            return "disable_validation__ignore_stride";
+        case DisabledValidation::kIgnoreInvalidPointerArgument:
+            return "disable_validation__ignore_invalid_pointer_argument";
+    }
+    return "<invalid>";
 }
 
-const DisableValidationAttribute* DisableValidationAttribute::Clone(
-    CloneContext* ctx) const {
-  return ctx->dst->ASTNodes().Create<DisableValidationAttribute>(ctx->dst->ID(),
-                                                                 validation);
+const DisableValidationAttribute* DisableValidationAttribute::Clone(CloneContext* ctx) const {
+    return ctx->dst->ASTNodes().Create<DisableValidationAttribute>(ctx->dst->ID(), validation);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/disable_validation_attribute.h b/src/tint/ast/disable_validation_attribute.h
index 5bc37ee..db70ad4 100644
--- a/src/tint/ast/disable_validation_attribute.h
+++ b/src/tint/ast/disable_validation_attribute.h
@@ -24,28 +24,28 @@
 /// Enumerator of validation features that can be disabled with a
 /// DisableValidationAttribute attribute.
 enum class DisabledValidation {
-  /// When applied to a function, the validator will not complain there is no
-  /// body to a function.
-  kFunctionHasNoBody,
-  /// When applied to a module-scoped variable, the validator will not complain
-  /// if two resource variables have the same binding points.
-  kBindingPointCollision,
-  /// When applied to a variable, the validator will not complain about the
-  /// declared storage class.
-  kIgnoreStorageClass,
-  /// When applied to an entry-point function parameter, the validator will not
-  /// check for entry IO attributes.
-  kEntryPointParameter,
-  /// When applied to a function parameter, the validator will not
-  /// check if parameter type is constructible
-  kIgnoreConstructibleFunctionParameter,
-  /// When applied to a member attribute, a stride attribute may be applied to
-  /// non-array types.
-  kIgnoreStrideAttribute,
-  /// When applied to a pointer function parameter, the validator will not
-  /// require a function call argument passed for that parameter to have a
-  /// certain form.
-  kIgnoreInvalidPointerArgument,
+    /// When applied to a function, the validator will not complain there is no
+    /// body to a function.
+    kFunctionHasNoBody,
+    /// When applied to a module-scoped variable, the validator will not complain
+    /// if two resource variables have the same binding points.
+    kBindingPointCollision,
+    /// When applied to a variable, the validator will not complain about the
+    /// declared storage class.
+    kIgnoreStorageClass,
+    /// When applied to an entry-point function parameter, the validator will not
+    /// check for entry IO attributes.
+    kEntryPointParameter,
+    /// When applied to a function parameter, the validator will not
+    /// check if parameter type is constructible
+    kIgnoreConstructibleFunctionParameter,
+    /// When applied to a member attribute, a stride attribute may be applied to
+    /// non-array types.
+    kIgnoreStrideAttribute,
+    /// When applied to a pointer function parameter, the validator will not
+    /// require a function call argument passed for that parameter to have a
+    /// certain form.
+    kIgnoreInvalidPointerArgument,
 };
 
 /// An internal attribute used to tell the validator to ignore specific
@@ -53,27 +53,26 @@
 /// would otherwise cause validation errors.
 class DisableValidationAttribute final
     : public Castable<DisableValidationAttribute, InternalAttribute> {
- public:
-  /// Constructor
-  /// @param program_id the identifier of the program that owns this node
-  /// @param validation the validation to disable
-  explicit DisableValidationAttribute(ProgramID program_id,
-                                      DisabledValidation validation);
+  public:
+    /// Constructor
+    /// @param program_id the identifier of the program that owns this node
+    /// @param validation the validation to disable
+    explicit DisableValidationAttribute(ProgramID program_id, DisabledValidation validation);
 
-  /// Destructor
-  ~DisableValidationAttribute() override;
+    /// Destructor
+    ~DisableValidationAttribute() override;
 
-  /// @return a short description of the internal attribute which will be
-  /// displayed in WGSL as `@internal(<name>)` (but is not parsable).
-  std::string InternalName() const override;
+    /// @return a short description of the internal attribute which will be
+    /// displayed in WGSL as `@internal(<name>)` (but is not parsable).
+    std::string InternalName() const override;
 
-  /// Performs a deep clone of this object using the CloneContext `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned object
-  const DisableValidationAttribute* Clone(CloneContext* ctx) const override;
+    /// Performs a deep clone of this object using the CloneContext `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned object
+    const DisableValidationAttribute* Clone(CloneContext* ctx) const override;
 
-  /// The validation that this attribute disables
-  const DisabledValidation validation;
+    /// The validation that this attribute disables
+    const DisabledValidation validation;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/discard_statement.cc b/src/tint/ast/discard_statement.cc
index ba081ab..7ca673f 100644
--- a/src/tint/ast/discard_statement.cc
+++ b/src/tint/ast/discard_statement.cc
@@ -20,17 +20,16 @@
 
 namespace tint::ast {
 
-DiscardStatement::DiscardStatement(ProgramID pid, const Source& src)
-    : Base(pid, src) {}
+DiscardStatement::DiscardStatement(ProgramID pid, const Source& src) : Base(pid, src) {}
 
 DiscardStatement::DiscardStatement(DiscardStatement&&) = default;
 
 DiscardStatement::~DiscardStatement() = default;
 
 const DiscardStatement* DiscardStatement::Clone(CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  return ctx->dst->create<DiscardStatement>(src);
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    return ctx->dst->create<DiscardStatement>(src);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/discard_statement.h b/src/tint/ast/discard_statement.h
index c17813e..9d18c74 100644
--- a/src/tint/ast/discard_statement.h
+++ b/src/tint/ast/discard_statement.h
@@ -21,20 +21,20 @@
 
 /// A discard statement
 class DiscardStatement final : public Castable<DiscardStatement, Statement> {
- public:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  DiscardStatement(ProgramID pid, const Source& src);
-  /// Move constructor
-  DiscardStatement(DiscardStatement&&);
-  ~DiscardStatement() override;
+  public:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    DiscardStatement(ProgramID pid, const Source& src);
+    /// Move constructor
+    DiscardStatement(DiscardStatement&&);
+    ~DiscardStatement() override;
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const DiscardStatement* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const DiscardStatement* Clone(CloneContext* ctx) const override;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/discard_statement_test.cc b/src/tint/ast/discard_statement_test.cc
index 4101ef1..ee16ed3 100644
--- a/src/tint/ast/discard_statement_test.cc
+++ b/src/tint/ast/discard_statement_test.cc
@@ -22,25 +22,25 @@
 using DiscardStatementTest = TestHelper;
 
 TEST_F(DiscardStatementTest, Creation) {
-  auto* stmt = create<DiscardStatement>();
-  EXPECT_EQ(stmt->source.range.begin.line, 0u);
-  EXPECT_EQ(stmt->source.range.begin.column, 0u);
-  EXPECT_EQ(stmt->source.range.end.line, 0u);
-  EXPECT_EQ(stmt->source.range.end.column, 0u);
+    auto* stmt = create<DiscardStatement>();
+    EXPECT_EQ(stmt->source.range.begin.line, 0u);
+    EXPECT_EQ(stmt->source.range.begin.column, 0u);
+    EXPECT_EQ(stmt->source.range.end.line, 0u);
+    EXPECT_EQ(stmt->source.range.end.column, 0u);
 }
 
 TEST_F(DiscardStatementTest, Creation_WithSource) {
-  auto* stmt = create<DiscardStatement>(
-      Source{Source::Range{Source::Location{20, 2}, Source::Location{20, 5}}});
-  EXPECT_EQ(stmt->source.range.begin.line, 20u);
-  EXPECT_EQ(stmt->source.range.begin.column, 2u);
-  EXPECT_EQ(stmt->source.range.end.line, 20u);
-  EXPECT_EQ(stmt->source.range.end.column, 5u);
+    auto* stmt = create<DiscardStatement>(
+        Source{Source::Range{Source::Location{20, 2}, Source::Location{20, 5}}});
+    EXPECT_EQ(stmt->source.range.begin.line, 20u);
+    EXPECT_EQ(stmt->source.range.begin.column, 2u);
+    EXPECT_EQ(stmt->source.range.end.line, 20u);
+    EXPECT_EQ(stmt->source.range.end.column, 5u);
 }
 
 TEST_F(DiscardStatementTest, IsDiscard) {
-  auto* stmt = create<DiscardStatement>();
-  EXPECT_TRUE(stmt->Is<DiscardStatement>());
+    auto* stmt = create<DiscardStatement>();
+    EXPECT_TRUE(stmt->Is<DiscardStatement>());
 }
 
 }  // namespace
diff --git a/src/tint/ast/else_statement.cc b/src/tint/ast/else_statement.cc
deleted file mode 100644
index d047177..0000000
--- a/src/tint/ast/else_statement.cc
+++ /dev/null
@@ -1,45 +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/else_statement.h"
-
-#include "src/tint/program_builder.h"
-
-TINT_INSTANTIATE_TYPEINFO(tint::ast::ElseStatement);
-
-namespace tint::ast {
-
-ElseStatement::ElseStatement(ProgramID pid,
-                             const Source& src,
-                             const Expression* cond,
-                             const BlockStatement* b)
-    : Base(pid, src), condition(cond), body(b) {
-  TINT_ASSERT(AST, body);
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, body, program_id);
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, condition, program_id);
-}
-
-ElseStatement::ElseStatement(ElseStatement&&) = default;
-
-ElseStatement::~ElseStatement() = default;
-
-const ElseStatement* ElseStatement::Clone(CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  auto* cond = ctx->Clone(condition);
-  auto* b = ctx->Clone(body);
-  return ctx->dst->create<ElseStatement>(src, cond, b);
-}
-
-}  // namespace tint::ast
diff --git a/src/tint/ast/else_statement.h b/src/tint/ast/else_statement.h
deleted file mode 100644
index c8c6e51..0000000
--- a/src/tint/ast/else_statement.h
+++ /dev/null
@@ -1,59 +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_ELSE_STATEMENT_H_
-#define SRC_TINT_AST_ELSE_STATEMENT_H_
-
-#include <vector>
-
-#include "src/tint/ast/block_statement.h"
-#include "src/tint/ast/expression.h"
-
-namespace tint::ast {
-
-/// An else statement
-class ElseStatement final : public Castable<ElseStatement, Statement> {
- public:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  /// @param condition the else condition
-  /// @param body the else body
-  ElseStatement(ProgramID pid,
-                const Source& src,
-                const Expression* condition,
-                const BlockStatement* body);
-  /// Move constructor
-  ElseStatement(ElseStatement&&);
-  ~ElseStatement() override;
-
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const ElseStatement* Clone(CloneContext* ctx) const override;
-
-  /// The else condition or nullptr if none set
-  const Expression* const condition;
-
-  /// The else body
-  const BlockStatement* const body;
-};
-
-/// A list of else statements
-using ElseStatementList = std::vector<const ElseStatement*>;
-
-}  // namespace tint::ast
-
-#endif  // SRC_TINT_AST_ELSE_STATEMENT_H_
diff --git a/src/tint/ast/else_statement_test.cc b/src/tint/ast/else_statement_test.cc
deleted file mode 100644
index a088438..0000000
--- a/src/tint/ast/else_statement_test.cc
+++ /dev/null
@@ -1,92 +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 "gtest/gtest-spi.h"
-#include "src/tint/ast/discard_statement.h"
-#include "src/tint/ast/if_statement.h"
-#include "src/tint/ast/test_helper.h"
-
-namespace tint::ast {
-namespace {
-
-using ElseStatementTest = TestHelper;
-
-TEST_F(ElseStatementTest, Creation) {
-  auto* cond = Expr(true);
-  auto* body = create<BlockStatement>(StatementList{
-      create<DiscardStatement>(),
-  });
-  auto* discard = body->statements[0];
-
-  auto* e = create<ElseStatement>(cond, body);
-  EXPECT_EQ(e->condition, cond);
-  ASSERT_EQ(e->body->statements.size(), 1u);
-  EXPECT_EQ(e->body->statements[0], discard);
-}
-
-TEST_F(ElseStatementTest, Creation_WithSource) {
-  auto* e = create<ElseStatement>(Source{Source::Location{20, 2}}, Expr(true),
-                                  Block());
-  auto src = e->source;
-  EXPECT_EQ(src.range.begin.line, 20u);
-  EXPECT_EQ(src.range.begin.column, 2u);
-}
-
-TEST_F(ElseStatementTest, IsElse) {
-  auto* e = create<ElseStatement>(nullptr, Block());
-  EXPECT_TRUE(e->Is<ElseStatement>());
-}
-
-TEST_F(ElseStatementTest, HasCondition) {
-  auto* cond = Expr(true);
-  auto* e = create<ElseStatement>(cond, Block());
-  EXPECT_TRUE(e->condition);
-}
-
-TEST_F(ElseStatementTest, HasContition_NullCondition) {
-  auto* e = create<ElseStatement>(nullptr, Block());
-  EXPECT_FALSE(e->condition);
-}
-
-TEST_F(ElseStatementTest, Assert_Null_Body) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.create<ElseStatement>(b.Expr(true), nullptr);
-      },
-      "internal compiler error");
-}
-
-TEST_F(ElseStatementTest, Assert_DifferentProgramID_Condition) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.create<ElseStatement>(b2.Expr(true), b1.Block());
-      },
-      "internal compiler error");
-}
-
-TEST_F(ElseStatementTest, Assert_DifferentProgramID_Body) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.create<ElseStatement>(b1.Expr(true), b2.Block());
-      },
-      "internal compiler error");
-}
-
-}  // namespace
-}  // namespace tint::ast
diff --git a/src/tint/ast/enable.cc b/src/tint/ast/enable.cc
new file mode 100644
index 0000000..f4c6dd6
--- /dev/null
+++ b/src/tint/ast/enable.cc
@@ -0,0 +1,58 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/ast/enable.h"
+
+#include "src/tint/program_builder.h"
+#include "src/tint/sem/variable.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::ast::Enable);
+
+namespace tint::ast {
+
+Enable::ExtensionKind Enable::NameToKind(const std::string& name) {
+    // The reserved internal extension name for testing
+    if (name == "InternalExtensionForTesting") {
+        return Enable::ExtensionKind::kInternalExtensionForTesting;
+    }
+
+    return Enable::ExtensionKind::kNotAnExtension;
+}
+
+std::string Enable::KindToName(ExtensionKind kind) {
+    switch (kind) {
+        // The reserved internal extension for testing
+        case ExtensionKind::kInternalExtensionForTesting:
+            return "InternalExtensionForTesting";
+        case ExtensionKind::kNotAnExtension:
+            // Return an empty string for kNotAnExtension
+            return {};
+            // No default case, as this switch must cover all ExtensionKind values.
+    }
+    // This return shall never get hit.
+    return {};
+}
+
+Enable::Enable(ProgramID pid, const Source& src, const std::string& ext_name)
+    : Base(pid, src), name(ext_name), kind(NameToKind(ext_name)) {}
+
+Enable::Enable(Enable&&) = default;
+
+Enable::~Enable() = default;
+
+const Enable* Enable::Clone(CloneContext* ctx) const {
+    auto src = ctx->Clone(source);
+    return ctx->dst->create<Enable>(src, name);
+}
+}  // namespace tint::ast
diff --git a/src/tint/ast/enable.h b/src/tint/ast/enable.h
new file mode 100644
index 0000000..67c47c9
--- /dev/null
+++ b/src/tint/ast/enable.h
@@ -0,0 +1,88 @@
+// 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_AST_ENABLE_H_
+#define SRC_TINT_AST_ENABLE_H_
+
+#include <string>
+#include <unordered_set>
+#include <utility>
+
+#include "src/tint/ast/access.h"
+#include "src/tint/ast/expression.h"
+
+namespace tint::ast {
+
+/// An instance of this class represents one extension mentioned in a
+/// "enable" derictive. Example:
+///       // Enable an extension named "f16"
+///       enable f16;
+class Enable : public Castable<Enable, Node> {
+  public:
+    ///  The enum class identifing each supported WGSL extension
+    enum class ExtensionKind {
+        /// An internal reserved extension for test, named
+        /// "InternalExtensionForTesting"
+        kInternalExtensionForTesting = -2,
+        kNotAnExtension = -1,
+    };
+
+    /// Convert a string of extension name into one of ExtensionKind enum value,
+    /// the result will be ExtensionKind::kNotAnExtension if the name is not a
+    /// known extension name. A extension node of kind kNotAnExtension 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 ExtensionKind enum value for the extension of given name, or
+    /// kNotAnExtension if no known extension has the given name
+    static ExtensionKind NameToKind(const std::string& name);
+
+    /// Convert the ExtensionKind enum value to corresponding extension name
+    /// string. If the given enum value is kNotAnExtension or don't have a known
+    /// name, return an empty string instead.
+    /// @param kind the ExtensionKind enum value
+    /// @return string of the extension name corresponding to the given kind, or
+    /// an empty string if the given enum value is kNotAnExtension or don't have a
+    /// known corresponding name
+    static std::string KindToName(ExtensionKind kind);
+
+    /// Create a extension
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    /// @param name the name of extension
+    Enable(ProgramID pid, const Source& src, const std::string& name);
+    /// Move constructor
+    Enable(Enable&&);
+
+    ~Enable() override;
+
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const Enable* Clone(CloneContext* ctx) const override;
+
+    /// The extension name
+    const std::string name;
+
+    /// The extension kind
+    const ExtensionKind kind;
+};
+
+///  A set of extension kinds
+using ExtensionSet = std::unordered_set<Enable::ExtensionKind>;
+
+}  // namespace tint::ast
+
+#endif  // SRC_TINT_AST_ENABLE_H_
diff --git a/src/tint/ast/enable_test.cc b/src/tint/ast/enable_test.cc
new file mode 100644
index 0000000..9fde780
--- /dev/null
+++ b/src/tint/ast/enable_test.cc
@@ -0,0 +1,59 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/ast/enable.h"
+
+#include "src/tint/ast/test_helper.h"
+
+namespace tint::ast {
+namespace {
+
+using AstExtensionTest = TestHelper;
+
+TEST_F(AstExtensionTest, Creation) {
+    auto* ext =
+        create<Enable>(Source{Source::Range{Source::Location{20, 2}, Source::Location{20, 5}}},
+                       "InternalExtensionForTesting");
+    EXPECT_EQ(ext->source.range.begin.line, 20u);
+    EXPECT_EQ(ext->source.range.begin.column, 2u);
+    EXPECT_EQ(ext->source.range.end.line, 20u);
+    EXPECT_EQ(ext->source.range.end.column, 5u);
+    EXPECT_EQ(ext->kind, ast::Enable::ExtensionKind::kInternalExtensionForTesting);
+}
+
+TEST_F(AstExtensionTest, Creation_InvalidName) {
+    auto* ext = create<Enable>(
+        Source{Source::Range{Source::Location{20, 2}, Source::Location{20, 5}}}, std::string());
+    EXPECT_EQ(ext->source.range.begin.line, 20u);
+    EXPECT_EQ(ext->source.range.begin.column, 2u);
+    EXPECT_EQ(ext->source.range.end.line, 20u);
+    EXPECT_EQ(ext->source.range.end.column, 5u);
+    EXPECT_EQ(ext->kind, ast::Enable::ExtensionKind::kNotAnExtension);
+}
+
+TEST_F(AstExtensionTest, NameToKind_InvalidName) {
+    EXPECT_EQ(ast::Enable::NameToKind(std::string()), ast::Enable::ExtensionKind::kNotAnExtension);
+    EXPECT_EQ(ast::Enable::NameToKind("__ImpossibleExtensionName"),
+              ast::Enable::ExtensionKind::kNotAnExtension);
+    EXPECT_EQ(ast::Enable::NameToKind("123"), ast::Enable::ExtensionKind::kNotAnExtension);
+}
+
+TEST_F(AstExtensionTest, KindToName) {
+    EXPECT_EQ(ast::Enable::KindToName(ast::Enable::ExtensionKind::kInternalExtensionForTesting),
+              "InternalExtensionForTesting");
+    EXPECT_EQ(ast::Enable::KindToName(ast::Enable::ExtensionKind::kNotAnExtension), std::string());
+}
+
+}  // namespace
+}  // namespace tint::ast
diff --git a/src/tint/ast/expression.h b/src/tint/ast/expression.h
index 2338dfc..dc69ff8 100644
--- a/src/tint/ast/expression.h
+++ b/src/tint/ast/expression.h
@@ -25,16 +25,16 @@
 
 /// Base expression class
 class Expression : public Castable<Expression, Node> {
- public:
-  ~Expression() override;
+  public:
+    ~Expression() override;
 
- protected:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  Expression(ProgramID pid, const Source& src);
-  /// Move constructor
-  Expression(Expression&&);
+  protected:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    Expression(ProgramID pid, const Source& src);
+    /// Move constructor
+    Expression(Expression&&);
 };
 
 /// A list of expressions
diff --git a/src/tint/ast/external_texture.cc b/src/tint/ast/external_texture.cc
index 01f66f1..b88de90 100644
--- a/src/tint/ast/external_texture.cc
+++ b/src/tint/ast/external_texture.cc
@@ -29,11 +29,11 @@
 ExternalTexture::~ExternalTexture() = default;
 
 std::string ExternalTexture::FriendlyName(const SymbolTable&) const {
-  return "texture_external";
+    return "texture_external";
 }
 
 const ExternalTexture* ExternalTexture::Clone(CloneContext* ctx) const {
-  return ctx->dst->create<ExternalTexture>();
+    return ctx->dst->create<ExternalTexture>();
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/external_texture.h b/src/tint/ast/external_texture.h
index 614bb10..17224cf 100644
--- a/src/tint/ast/external_texture.h
+++ b/src/tint/ast/external_texture.h
@@ -23,25 +23,25 @@
 
 /// An external texture type
 class ExternalTexture final : public Castable<ExternalTexture, Texture> {
- public:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  ExternalTexture(ProgramID pid, const Source& src);
+  public:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    ExternalTexture(ProgramID pid, const Source& src);
 
-  /// Move constructor
-  ExternalTexture(ExternalTexture&&);
-  ~ExternalTexture() override;
+    /// Move constructor
+    ExternalTexture(ExternalTexture&&);
+    ~ExternalTexture() override;
 
-  /// @param symbols the program's symbol table
-  /// @returns the name for this type that closely resembles how it would be
-  /// declared in WGSL.
-  std::string FriendlyName(const SymbolTable& symbols) const override;
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type that closely resembles how it would be
+    /// declared in WGSL.
+    std::string FriendlyName(const SymbolTable& symbols) const override;
 
-  /// Clones this type and all transitive types using the `CloneContext` `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned type
-  const ExternalTexture* Clone(CloneContext* ctx) const override;
+    /// Clones this type and all transitive types using the `CloneContext` `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned type
+    const ExternalTexture* Clone(CloneContext* ctx) const override;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/external_texture_test.cc b/src/tint/ast/external_texture_test.cc
index b4a186e..dfe097e 100644
--- a/src/tint/ast/external_texture_test.cc
+++ b/src/tint/ast/external_texture_test.cc
@@ -22,22 +22,22 @@
 using AstExternalTextureTest = TestHelper;
 
 TEST_F(AstExternalTextureTest, IsTexture) {
-  Texture* ty = create<ExternalTexture>();
-  EXPECT_FALSE(ty->Is<DepthTexture>());
-  EXPECT_TRUE(ty->Is<ExternalTexture>());
-  EXPECT_FALSE(ty->Is<MultisampledTexture>());
-  EXPECT_FALSE(ty->Is<SampledTexture>());
-  EXPECT_FALSE(ty->Is<StorageTexture>());
+    Texture* ty = create<ExternalTexture>();
+    EXPECT_FALSE(ty->Is<DepthTexture>());
+    EXPECT_TRUE(ty->Is<ExternalTexture>());
+    EXPECT_FALSE(ty->Is<MultisampledTexture>());
+    EXPECT_FALSE(ty->Is<SampledTexture>());
+    EXPECT_FALSE(ty->Is<StorageTexture>());
 }
 
 TEST_F(AstExternalTextureTest, Dim) {
-  auto* ty = create<ExternalTexture>();
-  EXPECT_EQ(ty->dim, ast::TextureDimension::k2d);
+    auto* ty = create<ExternalTexture>();
+    EXPECT_EQ(ty->dim, ast::TextureDimension::k2d);
 }
 
 TEST_F(AstExternalTextureTest, FriendlyName) {
-  auto* ty = create<ExternalTexture>();
-  EXPECT_EQ(ty->FriendlyName(Symbols()), "texture_external");
+    auto* ty = create<ExternalTexture>();
+    EXPECT_EQ(ty->FriendlyName(Symbols()), "texture_external");
 }
 
 }  // namespace
diff --git a/src/tint/ast/f32.cc b/src/tint/ast/f32.cc
index 0412693..b731e65 100644
--- a/src/tint/ast/f32.cc
+++ b/src/tint/ast/f32.cc
@@ -27,12 +27,12 @@
 F32::~F32() = default;
 
 std::string F32::FriendlyName(const SymbolTable&) const {
-  return "f32";
+    return "f32";
 }
 
 const F32* F32::Clone(CloneContext* ctx) const {
-  auto src = ctx->Clone(source);
-  return ctx->dst->create<F32>(src);
+    auto src = ctx->Clone(source);
+    return ctx->dst->create<F32>(src);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/f32.h b/src/tint/ast/f32.h
index 321cf3e..db81491 100644
--- a/src/tint/ast/f32.h
+++ b/src/tint/ast/f32.h
@@ -23,24 +23,24 @@
 
 /// A float 32 type
 class F32 final : public Castable<F32, Type> {
- public:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  F32(ProgramID pid, const Source& src);
-  /// Move constructor
-  F32(F32&&);
-  ~F32() override;
+  public:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    F32(ProgramID pid, const Source& src);
+    /// Move constructor
+    F32(F32&&);
+    ~F32() override;
 
-  /// @param symbols the program's symbol table
-  /// @returns the name for this type that closely resembles how it would be
-  /// declared in WGSL.
-  std::string FriendlyName(const SymbolTable& symbols) const override;
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type that closely resembles how it would be
+    /// declared in WGSL.
+    std::string FriendlyName(const SymbolTable& symbols) const override;
 
-  /// Clones this type and all transitive types using the `CloneContext` `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned type
-  const F32* Clone(CloneContext* ctx) const override;
+    /// Clones this type and all transitive types using the `CloneContext` `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned type
+    const F32* Clone(CloneContext* ctx) const override;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/f32_test.cc b/src/tint/ast/f32_test.cc
index 73791e9..793289f 100644
--- a/src/tint/ast/f32_test.cc
+++ b/src/tint/ast/f32_test.cc
@@ -22,8 +22,8 @@
 using AstF32Test = TestHelper;
 
 TEST_F(AstF32Test, FriendlyName) {
-  auto* f = create<F32>();
-  EXPECT_EQ(f->FriendlyName(Symbols()), "f32");
+    auto* f = create<F32>();
+    EXPECT_EQ(f->FriendlyName(Symbols()), "f32");
 }
 
 }  // namespace
diff --git a/src/tint/ast/fallthrough_statement.cc b/src/tint/ast/fallthrough_statement.cc
index ff9b3b9..446534d 100644
--- a/src/tint/ast/fallthrough_statement.cc
+++ b/src/tint/ast/fallthrough_statement.cc
@@ -20,18 +20,16 @@
 
 namespace tint::ast {
 
-FallthroughStatement::FallthroughStatement(ProgramID pid, const Source& src)
-    : Base(pid, src) {}
+FallthroughStatement::FallthroughStatement(ProgramID pid, const Source& src) : Base(pid, src) {}
 
 FallthroughStatement::FallthroughStatement(FallthroughStatement&&) = default;
 
 FallthroughStatement::~FallthroughStatement() = default;
 
-const FallthroughStatement* FallthroughStatement::Clone(
-    CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  return ctx->dst->create<FallthroughStatement>(src);
+const FallthroughStatement* FallthroughStatement::Clone(CloneContext* ctx) const {
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    return ctx->dst->create<FallthroughStatement>(src);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/fallthrough_statement.h b/src/tint/ast/fallthrough_statement.h
index 262bd87..b313efb 100644
--- a/src/tint/ast/fallthrough_statement.h
+++ b/src/tint/ast/fallthrough_statement.h
@@ -20,22 +20,21 @@
 namespace tint::ast {
 
 /// An fallthrough statement
-class FallthroughStatement final
-    : public Castable<FallthroughStatement, Statement> {
- public:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  FallthroughStatement(ProgramID pid, const Source& src);
-  /// Move constructor
-  FallthroughStatement(FallthroughStatement&&);
-  ~FallthroughStatement() override;
+class FallthroughStatement final : public Castable<FallthroughStatement, Statement> {
+  public:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    FallthroughStatement(ProgramID pid, const Source& src);
+    /// Move constructor
+    FallthroughStatement(FallthroughStatement&&);
+    ~FallthroughStatement() override;
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const FallthroughStatement* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const FallthroughStatement* Clone(CloneContext* ctx) const override;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/fallthrough_statement_test.cc b/src/tint/ast/fallthrough_statement_test.cc
index 3069f03..f823e91 100644
--- a/src/tint/ast/fallthrough_statement_test.cc
+++ b/src/tint/ast/fallthrough_statement_test.cc
@@ -22,23 +22,23 @@
 using FallthroughStatementTest = TestHelper;
 
 TEST_F(FallthroughStatementTest, Creation) {
-  auto* stmt = create<FallthroughStatement>();
-  EXPECT_EQ(stmt->source.range.begin.line, 0u);
-  EXPECT_EQ(stmt->source.range.begin.column, 0u);
-  EXPECT_EQ(stmt->source.range.end.line, 0u);
-  EXPECT_EQ(stmt->source.range.end.column, 0u);
+    auto* stmt = create<FallthroughStatement>();
+    EXPECT_EQ(stmt->source.range.begin.line, 0u);
+    EXPECT_EQ(stmt->source.range.begin.column, 0u);
+    EXPECT_EQ(stmt->source.range.end.line, 0u);
+    EXPECT_EQ(stmt->source.range.end.column, 0u);
 }
 
 TEST_F(FallthroughStatementTest, Creation_WithSource) {
-  auto* stmt = create<FallthroughStatement>(Source{Source::Location{20, 2}});
-  auto src = stmt->source;
-  EXPECT_EQ(src.range.begin.line, 20u);
-  EXPECT_EQ(src.range.begin.column, 2u);
+    auto* stmt = create<FallthroughStatement>(Source{Source::Location{20, 2}});
+    auto src = stmt->source;
+    EXPECT_EQ(src.range.begin.line, 20u);
+    EXPECT_EQ(src.range.begin.column, 2u);
 }
 
 TEST_F(FallthroughStatementTest, IsFallthrough) {
-  auto* stmt = create<FallthroughStatement>();
-  EXPECT_TRUE(stmt->Is<FallthroughStatement>());
+    auto* stmt = create<FallthroughStatement>();
+    EXPECT_TRUE(stmt->Is<FallthroughStatement>());
 }
 
 }  // namespace
diff --git a/src/tint/ast/float_literal_expression.cc b/src/tint/ast/float_literal_expression.cc
index d22cec9..5be5a19 100644
--- a/src/tint/ast/float_literal_expression.cc
+++ b/src/tint/ast/float_literal_expression.cc
@@ -22,18 +22,15 @@
 
 namespace tint::ast {
 
-FloatLiteralExpression::FloatLiteralExpression(ProgramID pid,
-                                               const Source& src,
-                                               float val)
+FloatLiteralExpression::FloatLiteralExpression(ProgramID pid, const Source& src, float val)
     : Base(pid, src), value(val) {}
 
 FloatLiteralExpression::~FloatLiteralExpression() = default;
 
-const FloatLiteralExpression* FloatLiteralExpression::Clone(
-    CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  return ctx->dst->create<FloatLiteralExpression>(src, value);
+const FloatLiteralExpression* FloatLiteralExpression::Clone(CloneContext* ctx) const {
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    return ctx->dst->create<FloatLiteralExpression>(src, value);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/float_literal_expression.h b/src/tint/ast/float_literal_expression.h
index e2b0fa3..d1e1a64 100644
--- a/src/tint/ast/float_literal_expression.h
+++ b/src/tint/ast/float_literal_expression.h
@@ -22,24 +22,23 @@
 namespace tint::ast {
 
 /// A float literal
-class FloatLiteralExpression final
-    : public Castable<FloatLiteralExpression, LiteralExpression> {
- public:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  /// @param value the float literals value
-  FloatLiteralExpression(ProgramID pid, const Source& src, float value);
-  ~FloatLiteralExpression() override;
+class FloatLiteralExpression final : public Castable<FloatLiteralExpression, LiteralExpression> {
+  public:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    /// @param value the float literals value
+    FloatLiteralExpression(ProgramID pid, const Source& src, float value);
+    ~FloatLiteralExpression() override;
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const FloatLiteralExpression* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const FloatLiteralExpression* Clone(CloneContext* ctx) const override;
 
-  /// The float literal value
-  const float value;
+    /// The float literal value
+    const float value;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/float_literal_expression_test.cc b/src/tint/ast/float_literal_expression_test.cc
index dfb912d..c0f1e16 100644
--- a/src/tint/ast/float_literal_expression_test.cc
+++ b/src/tint/ast/float_literal_expression_test.cc
@@ -20,9 +20,9 @@
 using FloatLiteralExpressionTest = TestHelper;
 
 TEST_F(FloatLiteralExpressionTest, Value) {
-  auto* f = create<FloatLiteralExpression>(47.2f);
-  ASSERT_TRUE(f->Is<FloatLiteralExpression>());
-  EXPECT_EQ(f->value, 47.2f);
+    auto* f = create<FloatLiteralExpression>(47.2f);
+    ASSERT_TRUE(f->Is<FloatLiteralExpression>());
+    EXPECT_EQ(f->value, 47.2f);
 }
 
 }  // namespace
diff --git a/src/tint/ast/for_loop_statement.cc b/src/tint/ast/for_loop_statement.cc
index 0a08893..804389c 100644
--- a/src/tint/ast/for_loop_statement.cc
+++ b/src/tint/ast/for_loop_statement.cc
@@ -26,17 +26,13 @@
                                    const Expression* cond,
                                    const Statement* cont,
                                    const BlockStatement* b)
-    : Base(pid, src),
-      initializer(init),
-      condition(cond),
-      continuing(cont),
-      body(b) {
-  TINT_ASSERT(AST, body);
+    : Base(pid, src), initializer(init), condition(cond), continuing(cont), body(b) {
+    TINT_ASSERT(AST, body);
 
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, initializer, program_id);
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, condition, program_id);
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, continuing, program_id);
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, body, program_id);
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, initializer, program_id);
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, condition, program_id);
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, continuing, program_id);
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, body, program_id);
 }
 
 ForLoopStatement::ForLoopStatement(ForLoopStatement&&) = default;
@@ -44,14 +40,14 @@
 ForLoopStatement::~ForLoopStatement() = default;
 
 const ForLoopStatement* ForLoopStatement::Clone(CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
 
-  auto* init = ctx->Clone(initializer);
-  auto* cond = ctx->Clone(condition);
-  auto* cont = ctx->Clone(continuing);
-  auto* b = ctx->Clone(body);
-  return ctx->dst->create<ForLoopStatement>(src, init, cond, cont, b);
+    auto* init = ctx->Clone(initializer);
+    auto* cond = ctx->Clone(condition);
+    auto* cont = ctx->Clone(continuing);
+    auto* b = ctx->Clone(body);
+    return ctx->dst->create<ForLoopStatement>(src, init, cond, cont, b);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/for_loop_statement.h b/src/tint/ast/for_loop_statement.h
index 904d327..464ea49 100644
--- a/src/tint/ast/for_loop_statement.h
+++ b/src/tint/ast/for_loop_statement.h
@@ -23,41 +23,41 @@
 
 /// A for loop statement
 class ForLoopStatement final : public Castable<ForLoopStatement, Statement> {
- public:
-  /// Constructor
-  /// @param program_id the identifier of the program that owns this node
-  /// @param source the for loop statement source
-  /// @param initializer the optional loop initializer statement
-  /// @param condition the optional loop condition expression
-  /// @param continuing the optional continuing statement
-  /// @param body the loop body
-  ForLoopStatement(ProgramID program_id,
-                   Source const& source,
-                   const Statement* initializer,
-                   const Expression* condition,
-                   const Statement* continuing,
-                   const BlockStatement* body);
-  /// Move constructor
-  ForLoopStatement(ForLoopStatement&&);
-  ~ForLoopStatement() override;
+  public:
+    /// Constructor
+    /// @param program_id the identifier of the program that owns this node
+    /// @param source the for loop statement source
+    /// @param initializer the optional loop initializer statement
+    /// @param condition the optional loop condition expression
+    /// @param continuing the optional continuing statement
+    /// @param body the loop body
+    ForLoopStatement(ProgramID program_id,
+                     Source const& source,
+                     const Statement* initializer,
+                     const Expression* condition,
+                     const Statement* continuing,
+                     const BlockStatement* body);
+    /// Move constructor
+    ForLoopStatement(ForLoopStatement&&);
+    ~ForLoopStatement() override;
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const ForLoopStatement* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const ForLoopStatement* Clone(CloneContext* ctx) const override;
 
-  /// The initializer statement
-  const Statement* const initializer;
+    /// The initializer statement
+    const Statement* const initializer;
 
-  /// The condition expression
-  const Expression* const condition;
+    /// The condition expression
+    const Expression* const condition;
 
-  /// The continuing statement
-  const Statement* const continuing;
+    /// The continuing statement
+    const Statement* const continuing;
 
-  /// The loop body block
-  const BlockStatement* const body;
+    /// The loop body block
+    const BlockStatement* const body;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/for_loop_statement_test.cc b/src/tint/ast/for_loop_statement_test.cc
index 9c03a30..5e2a000 100644
--- a/src/tint/ast/for_loop_statement_test.cc
+++ b/src/tint/ast/for_loop_statement_test.cc
@@ -16,86 +16,87 @@
 #include "src/tint/ast/binary_expression.h"
 #include "src/tint/ast/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::ast {
 namespace {
 
 using ForLoopStatementTest = TestHelper;
 
 TEST_F(ForLoopStatementTest, Creation) {
-  auto* init = Decl(Var("i", ty.u32()));
-  auto* cond =
-      create<BinaryExpression>(BinaryOp::kLessThan, Expr("i"), Expr(5u));
-  auto* cont = Assign("i", Add("i", 1));
-  auto* body = Block(Return());
-  auto* l = For(init, cond, cont, body);
+    auto* init = Decl(Var("i", ty.u32()));
+    auto* cond = create<BinaryExpression>(BinaryOp::kLessThan, Expr("i"), Expr(5_u));
+    auto* cont = Assign("i", Add("i", 1_u));
+    auto* body = Block(Return());
+    auto* l = For(init, cond, cont, body);
 
-  EXPECT_EQ(l->initializer, init);
-  EXPECT_EQ(l->condition, cond);
-  EXPECT_EQ(l->continuing, cont);
-  EXPECT_EQ(l->body, body);
+    EXPECT_EQ(l->initializer, init);
+    EXPECT_EQ(l->condition, cond);
+    EXPECT_EQ(l->continuing, cont);
+    EXPECT_EQ(l->body, body);
 }
 
 TEST_F(ForLoopStatementTest, Creation_WithSource) {
-  auto* body = Block(Return());
-  auto* l = For(Source{{20u, 2u}}, nullptr, nullptr, nullptr, body);
-  auto src = l->source;
-  EXPECT_EQ(src.range.begin.line, 20u);
-  EXPECT_EQ(src.range.begin.column, 2u);
+    auto* body = Block(Return());
+    auto* l = For(Source{{20u, 2u}}, nullptr, nullptr, nullptr, body);
+    auto src = l->source;
+    EXPECT_EQ(src.range.begin.line, 20u);
+    EXPECT_EQ(src.range.begin.column, 2u);
 }
 
 TEST_F(ForLoopStatementTest, Creation_Null_InitCondCont) {
-  auto* body = Block(Return());
-  auto* l = For(nullptr, nullptr, nullptr, body);
-  EXPECT_EQ(l->body, body);
+    auto* body = Block(Return());
+    auto* l = For(nullptr, nullptr, nullptr, body);
+    EXPECT_EQ(l->body, body);
 }
 
 TEST_F(ForLoopStatementTest, Assert_Null_Body) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.For(nullptr, nullptr, nullptr, nullptr);
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.For(nullptr, nullptr, nullptr, nullptr);
+        },
+        "internal compiler error");
 }
 
 TEST_F(ForLoopStatementTest, Assert_DifferentProgramID_Initializer) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.For(b2.Block(), nullptr, nullptr, b1.Block());
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.For(b2.Block(), nullptr, nullptr, b1.Block());
+        },
+        "internal compiler error");
 }
 
 TEST_F(ForLoopStatementTest, Assert_DifferentProgramID_Condition) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.For(nullptr, b2.Expr(true), nullptr, b1.Block());
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.For(nullptr, b2.Expr(true), nullptr, b1.Block());
+        },
+        "internal compiler error");
 }
 
 TEST_F(ForLoopStatementTest, Assert_DifferentProgramID_Continuing) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.For(nullptr, nullptr, b2.Block(), b1.Block());
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.For(nullptr, nullptr, b2.Block(), b1.Block());
+        },
+        "internal compiler error");
 }
 
 TEST_F(ForLoopStatementTest, Assert_DifferentProgramID_Body) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.For(nullptr, nullptr, nullptr, b2.Block());
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.For(nullptr, nullptr, nullptr, b2.Block());
+        },
+        "internal compiler error");
 }
 
 }  // namespace
diff --git a/src/tint/ast/function.cc b/src/tint/ast/function.cc
index 885ca51..d8485d6 100644
--- a/src/tint/ast/function.cc
+++ b/src/tint/ast/function.cc
@@ -37,20 +37,20 @@
       body(b),
       attributes(std::move(attrs)),
       return_type_attributes(std::move(return_type_attrs)) {
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, symbol, program_id);
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, body, program_id);
-  for (auto* param : params) {
-    TINT_ASSERT(AST, param && param->is_const);
-    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, param, program_id);
-  }
-  TINT_ASSERT(AST, symbol.IsValid());
-  TINT_ASSERT(AST, return_type);
-  for (auto* attr : attributes) {
-    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, attr, program_id);
-  }
-  for (auto* attr : return_type_attributes) {
-    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, attr, program_id);
-  }
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, symbol, program_id);
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, body, program_id);
+    for (auto* param : params) {
+        TINT_ASSERT(AST, param && param->is_const);
+        TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, param, program_id);
+    }
+    TINT_ASSERT(AST, symbol.IsValid());
+    TINT_ASSERT(AST, return_type);
+    for (auto* attr : attributes) {
+        TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, attr, program_id);
+    }
+    for (auto* attr : return_type_attributes) {
+        TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, attr, program_id);
+    }
 }
 
 Function::Function(Function&&) = default;
@@ -58,49 +58,49 @@
 Function::~Function() = default;
 
 PipelineStage Function::PipelineStage() const {
-  if (auto* stage = GetAttribute<StageAttribute>(attributes)) {
-    return stage->stage;
-  }
-  return PipelineStage::kNone;
+    if (auto* stage = GetAttribute<StageAttribute>(attributes)) {
+        return stage->stage;
+    }
+    return PipelineStage::kNone;
 }
 
 const Function* Function::Clone(CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  auto sym = ctx->Clone(symbol);
-  auto p = ctx->Clone(params);
-  auto* ret = ctx->Clone(return_type);
-  auto* b = ctx->Clone(body);
-  auto attrs = ctx->Clone(attributes);
-  auto ret_attrs = ctx->Clone(return_type_attributes);
-  return ctx->dst->create<Function>(src, sym, p, ret, b, attrs, ret_attrs);
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    auto sym = ctx->Clone(symbol);
+    auto p = ctx->Clone(params);
+    auto* ret = ctx->Clone(return_type);
+    auto* b = ctx->Clone(body);
+    auto attrs = ctx->Clone(attributes);
+    auto ret_attrs = ctx->Clone(return_type_attributes);
+    return ctx->dst->create<Function>(src, sym, p, ret, b, attrs, ret_attrs);
 }
 
 const Function* FunctionList::Find(Symbol sym) const {
-  for (auto* func : *this) {
-    if (func->symbol == sym) {
-      return func;
+    for (auto* func : *this) {
+        if (func->symbol == sym) {
+            return func;
+        }
     }
-  }
-  return nullptr;
+    return nullptr;
 }
 
 const Function* FunctionList::Find(Symbol sym, PipelineStage stage) const {
-  for (auto* func : *this) {
-    if (func->symbol == sym && func->PipelineStage() == stage) {
-      return func;
+    for (auto* func : *this) {
+        if (func->symbol == sym && func->PipelineStage() == stage) {
+            return func;
+        }
     }
-  }
-  return nullptr;
+    return nullptr;
 }
 
 bool FunctionList::HasStage(ast::PipelineStage stage) const {
-  for (auto* func : *this) {
-    if (func->PipelineStage() == stage) {
-      return true;
+    for (auto* func : *this) {
+        if (func->PipelineStage() == stage) {
+            return true;
+        }
     }
-  }
-  return false;
+    return false;
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/function.h b/src/tint/ast/function.h
index e23edf7..843877e 100644
--- a/src/tint/ast/function.h
+++ b/src/tint/ast/function.h
@@ -33,82 +33,82 @@
 
 /// A Function statement.
 class Function final : public Castable<Function, Node> {
- public:
-  /// Create a function
-  /// @param program_id the identifier of the program that owns this node
-  /// @param source the variable source
-  /// @param symbol the function symbol
-  /// @param params the function parameters
-  /// @param return_type the return type
-  /// @param body the function body
-  /// @param attributes the function attributes
-  /// @param return_type_attributes the return type attributes
-  Function(ProgramID program_id,
-           const Source& source,
-           Symbol symbol,
-           VariableList params,
-           const Type* return_type,
-           const BlockStatement* body,
-           AttributeList attributes,
-           AttributeList return_type_attributes);
-  /// Move constructor
-  Function(Function&&);
+  public:
+    /// Create a function
+    /// @param program_id the identifier of the program that owns this node
+    /// @param source the variable source
+    /// @param symbol the function symbol
+    /// @param params the function parameters
+    /// @param return_type the return type
+    /// @param body the function body
+    /// @param attributes the function attributes
+    /// @param return_type_attributes the return type attributes
+    Function(ProgramID program_id,
+             const Source& source,
+             Symbol symbol,
+             VariableList params,
+             const Type* return_type,
+             const BlockStatement* body,
+             AttributeList attributes,
+             AttributeList return_type_attributes);
+    /// Move constructor
+    Function(Function&&);
 
-  ~Function() override;
+    ~Function() override;
 
-  /// @returns the functions pipeline stage or None if not set
-  ast::PipelineStage PipelineStage() const;
+    /// @returns the functions pipeline stage or None if not set
+    ast::PipelineStage PipelineStage() const;
 
-  /// @returns true if this function is an entry point
-  bool IsEntryPoint() const { return PipelineStage() != PipelineStage::kNone; }
+    /// @returns true if this function is an entry point
+    bool IsEntryPoint() const { return PipelineStage() != PipelineStage::kNone; }
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const Function* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const Function* Clone(CloneContext* ctx) const override;
 
-  /// The function symbol
-  const Symbol symbol;
+    /// The function symbol
+    const Symbol symbol;
 
-  /// The function params
-  const VariableList params;
+    /// The function params
+    const VariableList params;
 
-  /// The function return type
-  const Type* const return_type;
+    /// The function return type
+    const Type* const return_type;
 
-  /// The function body
-  const BlockStatement* const body;
+    /// The function body
+    const BlockStatement* const body;
 
-  /// The attributes attached to this function
-  const AttributeList attributes;
+    /// The attributes attached to this function
+    const AttributeList attributes;
 
-  /// The attributes attached to the function return type.
-  const AttributeList return_type_attributes;
+    /// The attributes attached to the function return type.
+    const AttributeList return_type_attributes;
 };
 
 /// A list of functions
 class FunctionList : public std::vector<const Function*> {
- public:
-  /// Appends f to the end of the list
-  /// @param f the function to append to this list
-  void Add(const Function* f) { this->emplace_back(f); }
+  public:
+    /// Appends f to the end of the list
+    /// @param f the function to append to this list
+    void Add(const Function* f) { this->emplace_back(f); }
 
-  /// Returns the function with the given name
-  /// @param sym the function symbol to search for
-  /// @returns the associated function or nullptr if none exists
-  const Function* Find(Symbol sym) const;
+    /// Returns the function with the given name
+    /// @param sym the function symbol to search for
+    /// @returns the associated function or nullptr if none exists
+    const Function* Find(Symbol sym) const;
 
-  /// Returns the function with the given name
-  /// @param sym the function symbol to search for
-  /// @param stage the pipeline stage
-  /// @returns the associated function or nullptr if none exists
-  const Function* Find(Symbol sym, PipelineStage stage) const;
+    /// Returns the function with the given name
+    /// @param sym the function symbol to search for
+    /// @param stage the pipeline stage
+    /// @returns the associated function or nullptr if none exists
+    const Function* Find(Symbol sym, PipelineStage stage) const;
 
-  /// @param stage the pipeline stage
-  /// @returns true if the Builder contains an entrypoint function with
-  /// the given stage
-  bool HasStage(PipelineStage stage) const;
+    /// @param stage the pipeline stage
+    /// @returns true if the Builder contains an entrypoint function with
+    /// the given stage
+    bool HasStage(PipelineStage stage) const;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/function_test.cc b/src/tint/ast/function_test.cc
index 7851ff9..bd05fd8 100644
--- a/src/tint/ast/function_test.cc
+++ b/src/tint/ast/function_test.cc
@@ -18,176 +18,173 @@
 #include "src/tint/ast/test_helper.h"
 #include "src/tint/ast/workgroup_attribute.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::ast {
 namespace {
 
 using FunctionTest = TestHelper;
 
 TEST_F(FunctionTest, Creation) {
-  VariableList params;
-  params.push_back(Param("var", ty.i32()));
-  auto* var = params[0];
+    VariableList params;
+    params.push_back(Param("var", ty.i32()));
+    auto* var = params[0];
 
-  auto* f = Func("func", params, ty.void_(), StatementList{}, AttributeList{});
-  EXPECT_EQ(f->symbol, Symbols().Get("func"));
-  ASSERT_EQ(f->params.size(), 1u);
-  EXPECT_TRUE(f->return_type->Is<ast::Void>());
-  EXPECT_EQ(f->params[0], var);
+    auto* f = Func("func", params, ty.void_(), StatementList{}, AttributeList{});
+    EXPECT_EQ(f->symbol, Symbols().Get("func"));
+    ASSERT_EQ(f->params.size(), 1u);
+    EXPECT_TRUE(f->return_type->Is<ast::Void>());
+    EXPECT_EQ(f->params[0], var);
 }
 
 TEST_F(FunctionTest, Creation_WithSource) {
-  VariableList params;
-  params.push_back(Param("var", ty.i32()));
+    VariableList params;
+    params.push_back(Param("var", ty.i32()));
 
-  auto* f = Func(Source{Source::Location{20, 2}}, "func", params, ty.void_(),
-                 StatementList{}, AttributeList{});
-  auto src = f->source;
-  EXPECT_EQ(src.range.begin.line, 20u);
-  EXPECT_EQ(src.range.begin.column, 2u);
+    auto* f = Func(Source{Source::Location{20, 2}}, "func", params, ty.void_(), StatementList{},
+                   AttributeList{});
+    auto src = f->source;
+    EXPECT_EQ(src.range.begin.line, 20u);
+    EXPECT_EQ(src.range.begin.column, 2u);
 }
 
 TEST_F(FunctionTest, Assert_InvalidName) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.Func("", VariableList{}, b.ty.void_(), StatementList{},
-               AttributeList{});
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.Func("", VariableList{}, b.ty.void_(), StatementList{}, AttributeList{});
+        },
+        "internal compiler error");
 }
 
 TEST_F(FunctionTest, Assert_Null_ReturnType) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.Func("f", VariableList{}, nullptr, StatementList{}, AttributeList{});
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.Func("f", VariableList{}, nullptr, StatementList{}, AttributeList{});
+        },
+        "internal compiler error");
 }
 
 TEST_F(FunctionTest, Assert_Null_Param) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        VariableList params;
-        params.push_back(b.Param("var", b.ty.i32()));
-        params.push_back(nullptr);
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            VariableList params;
+            params.push_back(b.Param("var", b.ty.i32()));
+            params.push_back(nullptr);
 
-        b.Func("f", params, b.ty.void_(), StatementList{}, AttributeList{});
-      },
-      "internal compiler error");
+            b.Func("f", params, b.ty.void_(), StatementList{}, AttributeList{});
+        },
+        "internal compiler error");
 }
 
 TEST_F(FunctionTest, Assert_DifferentProgramID_Symbol) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.Func(b2.Sym("func"), VariableList{}, b1.ty.void_(), StatementList{});
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.Func(b2.Sym("func"), VariableList{}, b1.ty.void_(), StatementList{});
+        },
+        "internal compiler error");
 }
 
 TEST_F(FunctionTest, Assert_DifferentProgramID_Param) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.Func("func", VariableList{b2.Param("var", b2.ty.i32())},
-                b1.ty.void_(), StatementList{});
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.Func("func", VariableList{b2.Param("var", b2.ty.i32())}, b1.ty.void_(),
+                    StatementList{});
+        },
+        "internal compiler error");
 }
 
 TEST_F(FunctionTest, Assert_DifferentProgramID_Attr) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.Func("func", VariableList{}, b1.ty.void_(), StatementList{},
-                AttributeList{
-                    b2.WorkgroupSize(2, 4, 6),
-                });
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.Func("func", VariableList{}, b1.ty.void_(), StatementList{},
+                    AttributeList{
+                        b2.WorkgroupSize(2_i, 4_i, 6_i),
+                    });
+        },
+        "internal compiler error");
 }
 
 TEST_F(FunctionTest, Assert_DifferentProgramID_ReturnAttr) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.Func("func", VariableList{}, b1.ty.void_(), StatementList{},
-                AttributeList{},
-                AttributeList{
-                    b2.WorkgroupSize(2, 4, 6),
-                });
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.Func("func", VariableList{}, b1.ty.void_(), StatementList{}, AttributeList{},
+                    AttributeList{
+                        b2.WorkgroupSize(2_i, 4_i, 6_i),
+                    });
+        },
+        "internal compiler error");
 }
 
 TEST_F(FunctionTest, Assert_NonConstParam) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        VariableList params;
-        params.push_back(b.Var("var", b.ty.i32(), ast::StorageClass::kNone));
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            VariableList params;
+            params.push_back(b.Var("var", b.ty.i32(), ast::StorageClass::kNone));
 
-        b.Func("f", params, b.ty.void_(), StatementList{}, AttributeList{});
-      },
-      "internal compiler error");
+            b.Func("f", params, b.ty.void_(), StatementList{}, AttributeList{});
+        },
+        "internal compiler error");
 }
 
 using FunctionListTest = TestHelper;
 
 TEST_F(FunctionListTest, FindSymbol) {
-  auto* func = Func("main", VariableList{}, ty.f32(), StatementList{},
-                    ast::AttributeList{});
-  FunctionList list;
-  list.Add(func);
-  EXPECT_EQ(func, list.Find(Symbols().Register("main")));
+    auto* func = Func("main", VariableList{}, ty.f32(), StatementList{}, ast::AttributeList{});
+    FunctionList list;
+    list.Add(func);
+    EXPECT_EQ(func, list.Find(Symbols().Register("main")));
 }
 
 TEST_F(FunctionListTest, FindSymbolMissing) {
-  FunctionList list;
-  EXPECT_EQ(nullptr, list.Find(Symbols().Register("Missing")));
+    FunctionList list;
+    EXPECT_EQ(nullptr, list.Find(Symbols().Register("Missing")));
 }
 
 TEST_F(FunctionListTest, FindSymbolStage) {
-  auto* fs = Func("main", VariableList{}, ty.f32(), StatementList{},
-                  ast::AttributeList{
-                      Stage(PipelineStage::kFragment),
-                  });
-  auto* vs = Func("main", VariableList{}, ty.f32(), StatementList{},
-                  ast::AttributeList{
-                      Stage(PipelineStage::kVertex),
-                  });
-  FunctionList list;
-  list.Add(fs);
-  list.Add(vs);
-  EXPECT_EQ(fs,
-            list.Find(Symbols().Register("main"), PipelineStage::kFragment));
-  EXPECT_EQ(vs, list.Find(Symbols().Register("main"), PipelineStage::kVertex));
+    auto* fs = Func("main", VariableList{}, ty.f32(), StatementList{},
+                    ast::AttributeList{
+                        Stage(PipelineStage::kFragment),
+                    });
+    auto* vs = Func("main", VariableList{}, ty.f32(), StatementList{},
+                    ast::AttributeList{
+                        Stage(PipelineStage::kVertex),
+                    });
+    FunctionList list;
+    list.Add(fs);
+    list.Add(vs);
+    EXPECT_EQ(fs, list.Find(Symbols().Register("main"), PipelineStage::kFragment));
+    EXPECT_EQ(vs, list.Find(Symbols().Register("main"), PipelineStage::kVertex));
 }
 
 TEST_F(FunctionListTest, FindSymbolStageMissing) {
-  FunctionList list;
-  list.Add(Func("main", VariableList{}, ty.f32(), StatementList{},
-                ast::AttributeList{
-                    Stage(PipelineStage::kFragment),
-                }));
-  EXPECT_EQ(nullptr,
-            list.Find(Symbols().Register("main"), PipelineStage::kVertex));
+    FunctionList list;
+    list.Add(Func("main", VariableList{}, ty.f32(), StatementList{},
+                  ast::AttributeList{
+                      Stage(PipelineStage::kFragment),
+                  }));
+    EXPECT_EQ(nullptr, list.Find(Symbols().Register("main"), PipelineStage::kVertex));
 }
 
 TEST_F(FunctionListTest, HasStage) {
-  FunctionList list;
-  list.Add(Func("main", VariableList{}, ty.f32(), StatementList{},
-                ast::AttributeList{
-                    Stage(PipelineStage::kFragment),
-                }));
-  EXPECT_TRUE(list.HasStage(PipelineStage::kFragment));
-  EXPECT_FALSE(list.HasStage(PipelineStage::kVertex));
+    FunctionList list;
+    list.Add(Func("main", VariableList{}, ty.f32(), StatementList{},
+                  ast::AttributeList{
+                      Stage(PipelineStage::kFragment),
+                  }));
+    EXPECT_TRUE(list.HasStage(PipelineStage::kFragment));
+    EXPECT_FALSE(list.HasStage(PipelineStage::kVertex));
 }
 
 }  // namespace
diff --git a/src/tint/ast/group_attribute.cc b/src/tint/ast/group_attribute.cc
index 9cd82b9..394a690 100644
--- a/src/tint/ast/group_attribute.cc
+++ b/src/tint/ast/group_attribute.cc
@@ -28,13 +28,13 @@
 GroupAttribute::~GroupAttribute() = default;
 
 std::string GroupAttribute::Name() const {
-  return "group";
+    return "group";
 }
 
 const GroupAttribute* GroupAttribute::Clone(CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  return ctx->dst->create<GroupAttribute>(src, value);
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    return ctx->dst->create<GroupAttribute>(src, value);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/group_attribute.h b/src/tint/ast/group_attribute.h
index de7015b..a559461 100644
--- a/src/tint/ast/group_attribute.h
+++ b/src/tint/ast/group_attribute.h
@@ -23,25 +23,25 @@
 
 /// A group attribute
 class GroupAttribute final : public Castable<GroupAttribute, Attribute> {
- public:
-  /// constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  /// @param value the group value
-  GroupAttribute(ProgramID pid, const Source& src, uint32_t value);
-  ~GroupAttribute() override;
+  public:
+    /// constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    /// @param value the group value
+    GroupAttribute(ProgramID pid, const Source& src, uint32_t value);
+    ~GroupAttribute() override;
 
-  /// @returns the WGSL name for the attribute
-  std::string Name() const override;
+    /// @returns the WGSL name for the attribute
+    std::string Name() const override;
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const GroupAttribute* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const GroupAttribute* Clone(CloneContext* ctx) const override;
 
-  /// The group value
-  const uint32_t value;
+    /// The group value
+    const uint32_t value;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/group_attribute_test.cc b/src/tint/ast/group_attribute_test.cc
index 38cd309..53167bb 100644
--- a/src/tint/ast/group_attribute_test.cc
+++ b/src/tint/ast/group_attribute_test.cc
@@ -20,8 +20,8 @@
 using GroupAttributeTest = TestHelper;
 
 TEST_F(GroupAttributeTest, Creation) {
-  auto* d = create<GroupAttribute>(2);
-  EXPECT_EQ(2u, d->value);
+    auto* d = create<GroupAttribute>(2);
+    EXPECT_EQ(2u, d->value);
 }
 
 }  // namespace
diff --git a/src/tint/ast/i32.cc b/src/tint/ast/i32.cc
index 294699d..46fe75e 100644
--- a/src/tint/ast/i32.cc
+++ b/src/tint/ast/i32.cc
@@ -27,12 +27,12 @@
 I32::~I32() = default;
 
 std::string I32::FriendlyName(const SymbolTable&) const {
-  return "i32";
+    return "i32";
 }
 
 const I32* I32::Clone(CloneContext* ctx) const {
-  auto src = ctx->Clone(source);
-  return ctx->dst->create<I32>(src);
+    auto src = ctx->Clone(source);
+    return ctx->dst->create<I32>(src);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/i32.h b/src/tint/ast/i32.h
index 62043e6..acafd37 100644
--- a/src/tint/ast/i32.h
+++ b/src/tint/ast/i32.h
@@ -23,24 +23,24 @@
 
 /// A signed int 32 type.
 class I32 final : public Castable<I32, Type> {
- public:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  I32(ProgramID pid, const Source& src);
-  /// Move constructor
-  I32(I32&&);
-  ~I32() override;
+  public:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    I32(ProgramID pid, const Source& src);
+    /// Move constructor
+    I32(I32&&);
+    ~I32() override;
 
-  /// @param symbols the program's symbol table
-  /// @returns the name for this type that closely resembles how it would be
-  /// declared in WGSL.
-  std::string FriendlyName(const SymbolTable& symbols) const override;
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type that closely resembles how it would be
+    /// declared in WGSL.
+    std::string FriendlyName(const SymbolTable& symbols) const override;
 
-  /// Clones this type and all transitive types using the `CloneContext` `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned type
-  const I32* Clone(CloneContext* ctx) const override;
+    /// Clones this type and all transitive types using the `CloneContext` `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned type
+    const I32* Clone(CloneContext* ctx) const override;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/i32_test.cc b/src/tint/ast/i32_test.cc
index 7a632a7..ee220cb 100644
--- a/src/tint/ast/i32_test.cc
+++ b/src/tint/ast/i32_test.cc
@@ -22,8 +22,8 @@
 using AstI32Test = TestHelper;
 
 TEST_F(AstI32Test, FriendlyName) {
-  auto* i = create<I32>();
-  EXPECT_EQ(i->FriendlyName(Symbols()), "i32");
+    auto* i = create<I32>();
+    EXPECT_EQ(i->FriendlyName(Symbols()), "i32");
 }
 
 }  // namespace
diff --git a/src/tint/ast/id_attribute.cc b/src/tint/ast/id_attribute.cc
index ac5957d..b6e1957 100644
--- a/src/tint/ast/id_attribute.cc
+++ b/src/tint/ast/id_attribute.cc
@@ -28,13 +28,13 @@
 IdAttribute::~IdAttribute() = default;
 
 std::string IdAttribute::Name() const {
-  return "id";
+    return "id";
 }
 
 const IdAttribute* IdAttribute::Clone(CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  return ctx->dst->create<IdAttribute>(src, value);
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    return ctx->dst->create<IdAttribute>(src, value);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/id_attribute.h b/src/tint/ast/id_attribute.h
index 4789e0d..5e3ec12 100644
--- a/src/tint/ast/id_attribute.h
+++ b/src/tint/ast/id_attribute.h
@@ -23,25 +23,25 @@
 
 /// An id attribute for pipeline-overridable constants
 class IdAttribute final : public Castable<IdAttribute, Attribute> {
- public:
-  /// Create an id attribute.
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  /// @param val the numeric id value
-  IdAttribute(ProgramID pid, const Source& src, uint32_t val);
-  ~IdAttribute() override;
+  public:
+    /// Create an id attribute.
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    /// @param val the numeric id value
+    IdAttribute(ProgramID pid, const Source& src, uint32_t val);
+    ~IdAttribute() override;
 
-  /// @returns the WGSL name for the attribute
-  std::string Name() const override;
+    /// @returns the WGSL name for the attribute
+    std::string Name() const override;
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const IdAttribute* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const IdAttribute* Clone(CloneContext* ctx) const override;
 
-  /// The id value
-  const uint32_t value;
+    /// The id value
+    const uint32_t value;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/id_attribute_test.cc b/src/tint/ast/id_attribute_test.cc
index af623ba..6957d66 100644
--- a/src/tint/ast/id_attribute_test.cc
+++ b/src/tint/ast/id_attribute_test.cc
@@ -22,8 +22,8 @@
 using IdAttributeTest = TestHelper;
 
 TEST_F(IdAttributeTest, Creation) {
-  auto* d = create<IdAttribute>(12);
-  EXPECT_EQ(12u, d->value);
+    auto* d = create<IdAttribute>(12);
+    EXPECT_EQ(12u, d->value);
 }
 
 }  // namespace
diff --git a/src/tint/ast/identifier_expression.cc b/src/tint/ast/identifier_expression.cc
index ff04f73..453ae69 100644
--- a/src/tint/ast/identifier_expression.cc
+++ b/src/tint/ast/identifier_expression.cc
@@ -20,24 +20,21 @@
 
 namespace tint::ast {
 
-IdentifierExpression::IdentifierExpression(ProgramID pid,
-                                           const Source& src,
-                                           Symbol sym)
+IdentifierExpression::IdentifierExpression(ProgramID pid, const Source& src, Symbol sym)
     : Base(pid, src), symbol(sym) {
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, symbol, program_id);
-  TINT_ASSERT(AST, symbol.IsValid());
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, symbol, program_id);
+    TINT_ASSERT(AST, symbol.IsValid());
 }
 
 IdentifierExpression::IdentifierExpression(IdentifierExpression&&) = default;
 
 IdentifierExpression::~IdentifierExpression() = default;
 
-const IdentifierExpression* IdentifierExpression::Clone(
-    CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  auto sym = ctx->Clone(symbol);
-  return ctx->dst->create<IdentifierExpression>(src, sym);
+const IdentifierExpression* IdentifierExpression::Clone(CloneContext* ctx) const {
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    auto sym = ctx->Clone(symbol);
+    return ctx->dst->create<IdentifierExpression>(src, sym);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/identifier_expression.h b/src/tint/ast/identifier_expression.h
index 80e013e..c3e1c30 100644
--- a/src/tint/ast/identifier_expression.h
+++ b/src/tint/ast/identifier_expression.h
@@ -20,26 +20,25 @@
 namespace tint::ast {
 
 /// An identifier expression
-class IdentifierExpression final
-    : public Castable<IdentifierExpression, Expression> {
- public:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  /// @param sym the symbol for the identifier
-  IdentifierExpression(ProgramID pid, const Source& src, Symbol sym);
-  /// Move constructor
-  IdentifierExpression(IdentifierExpression&&);
-  ~IdentifierExpression() override;
+class IdentifierExpression final : public Castable<IdentifierExpression, Expression> {
+  public:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    /// @param sym the symbol for the identifier
+    IdentifierExpression(ProgramID pid, const Source& src, Symbol sym);
+    /// Move constructor
+    IdentifierExpression(IdentifierExpression&&);
+    ~IdentifierExpression() override;
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const IdentifierExpression* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const IdentifierExpression* Clone(CloneContext* ctx) const override;
 
-  /// The symbol for the identifier
-  const Symbol symbol;
+    /// The symbol for the identifier
+    const Symbol symbol;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/identifier_expression_test.cc b/src/tint/ast/identifier_expression_test.cc
index 0609eb1..1f8033d 100644
--- a/src/tint/ast/identifier_expression_test.cc
+++ b/src/tint/ast/identifier_expression_test.cc
@@ -21,41 +21,41 @@
 using IdentifierExpressionTest = TestHelper;
 
 TEST_F(IdentifierExpressionTest, Creation) {
-  auto* i = Expr("ident");
-  EXPECT_EQ(i->symbol, Symbol(1, ID()));
+    auto* i = Expr("ident");
+    EXPECT_EQ(i->symbol, Symbol(1, ID()));
 }
 
 TEST_F(IdentifierExpressionTest, Creation_WithSource) {
-  auto* i = Expr(Source{Source::Location{20, 2}}, "ident");
-  EXPECT_EQ(i->symbol, Symbol(1, ID()));
+    auto* i = Expr(Source{Source::Location{20, 2}}, "ident");
+    EXPECT_EQ(i->symbol, Symbol(1, ID()));
 
-  auto src = i->source;
-  EXPECT_EQ(src.range.begin.line, 20u);
-  EXPECT_EQ(src.range.begin.column, 2u);
+    auto src = i->source;
+    EXPECT_EQ(src.range.begin.line, 20u);
+    EXPECT_EQ(src.range.begin.column, 2u);
 }
 
 TEST_F(IdentifierExpressionTest, IsIdentifier) {
-  auto* i = Expr("ident");
-  EXPECT_TRUE(i->Is<IdentifierExpression>());
+    auto* i = Expr("ident");
+    EXPECT_TRUE(i->Is<IdentifierExpression>());
 }
 
 TEST_F(IdentifierExpressionTest, Assert_InvalidSymbol) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.Expr("");
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.Expr("");
+        },
+        "internal compiler error");
 }
 
 TEST_F(IdentifierExpressionTest, Assert_DifferentProgramID_Symbol) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.Expr(b2.Sym("b2"));
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.Expr(b2.Sym("b2"));
+        },
+        "internal compiler error");
 }
 
 }  // namespace
diff --git a/src/tint/ast/if_statement.cc b/src/tint/ast/if_statement.cc
index 4b78da3..c8fd374 100644
--- a/src/tint/ast/if_statement.cc
+++ b/src/tint/ast/if_statement.cc
@@ -24,19 +24,16 @@
                          const Source& src,
                          const Expression* cond,
                          const BlockStatement* b,
-                         ElseStatementList else_stmts)
-    : Base(pid, src),
-      condition(cond),
-      body(b),
-      else_statements(std::move(else_stmts)) {
-  TINT_ASSERT(AST, condition);
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, condition, program_id);
-  TINT_ASSERT(AST, body);
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, body, program_id);
-  for (auto* el : else_statements) {
-    TINT_ASSERT(AST, el);
-    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, el, program_id);
-  }
+                         const Statement* else_stmt)
+    : Base(pid, src), condition(cond), body(b), else_statement(else_stmt) {
+    TINT_ASSERT(AST, condition);
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, condition, program_id);
+    TINT_ASSERT(AST, body);
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, body, program_id);
+    if (else_statement) {
+        TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, else_statement, program_id);
+        TINT_ASSERT(AST, (else_statement->IsAnyOf<ast::IfStatement, ast::BlockStatement>()));
+    }
 }
 
 IfStatement::IfStatement(IfStatement&&) = default;
@@ -44,12 +41,12 @@
 IfStatement::~IfStatement() = default;
 
 const IfStatement* IfStatement::Clone(CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  auto* cond = ctx->Clone(condition);
-  auto* b = ctx->Clone(body);
-  auto el = ctx->Clone(else_statements);
-  return ctx->dst->create<IfStatement>(src, cond, b, el);
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    auto* cond = ctx->Clone(condition);
+    auto* b = ctx->Clone(body);
+    auto* el = ctx->Clone(else_statement);
+    return ctx->dst->create<IfStatement>(src, cond, b, el);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/if_statement.h b/src/tint/ast/if_statement.h
index df843f8..75e6eee 100644
--- a/src/tint/ast/if_statement.h
+++ b/src/tint/ast/if_statement.h
@@ -17,42 +17,43 @@
 
 #include <utility>
 
-#include "src/tint/ast/else_statement.h"
+#include "src/tint/ast/block_statement.h"
+#include "src/tint/ast/expression.h"
 
 namespace tint::ast {
 
 /// An if statement
 class IfStatement final : public Castable<IfStatement, Statement> {
- public:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  /// @param condition the if condition
-  /// @param body the if body
-  /// @param else_stmts the else statements
-  IfStatement(ProgramID pid,
-              const Source& src,
-              const Expression* condition,
-              const BlockStatement* body,
-              ElseStatementList else_stmts);
-  /// Move constructor
-  IfStatement(IfStatement&&);
-  ~IfStatement() override;
+  public:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    /// @param condition the if condition
+    /// @param body the if body
+    /// @param else_stmt the else statement, or nullptr
+    IfStatement(ProgramID pid,
+                const Source& src,
+                const Expression* condition,
+                const BlockStatement* body,
+                const Statement* else_stmt);
+    /// Move constructor
+    IfStatement(IfStatement&&);
+    ~IfStatement() override;
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const IfStatement* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const IfStatement* Clone(CloneContext* ctx) const override;
 
-  /// The if condition or nullptr if none set
-  const Expression* const condition;
+    /// The if condition or nullptr if none set
+    const Expression* const condition;
 
-  /// The if body
-  const BlockStatement* const body;
+    /// The if body
+    const BlockStatement* const body;
 
-  /// The else statements
-  const ElseStatementList else_statements;
+    /// The optional else statement, or nullptr
+    const Statement* else_statement;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/if_statement_test.cc b/src/tint/ast/if_statement_test.cc
index 83f998a..9115cb7 100644
--- a/src/tint/ast/if_statement_test.cc
+++ b/src/tint/ast/if_statement_test.cc
@@ -24,80 +24,73 @@
 using IfStatementTest = TestHelper;
 
 TEST_F(IfStatementTest, Creation) {
-  auto* cond = Expr("cond");
-  auto* stmt = create<IfStatement>(Source{Source::Location{20, 2}}, cond,
-                                   Block(create<DiscardStatement>()),
-                                   ElseStatementList{});
-  auto src = stmt->source;
-  EXPECT_EQ(src.range.begin.line, 20u);
-  EXPECT_EQ(src.range.begin.column, 2u);
+    auto* cond = Expr("cond");
+    auto* stmt = If(Source{Source::Location{20, 2}}, cond, Block(create<DiscardStatement>()));
+    auto src = stmt->source;
+    EXPECT_EQ(src.range.begin.line, 20u);
+    EXPECT_EQ(src.range.begin.column, 2u);
 }
 
 TEST_F(IfStatementTest, IsIf) {
-  auto* stmt = create<IfStatement>(Expr(true), Block(), ElseStatementList{});
-  EXPECT_TRUE(stmt->Is<IfStatement>());
+    auto* stmt = If(Expr(true), Block());
+    EXPECT_TRUE(stmt->Is<IfStatement>());
 }
 
 TEST_F(IfStatementTest, Assert_Null_Condition) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.create<IfStatement>(nullptr, b.Block(), ElseStatementList{});
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.If(nullptr, b.Block());
+        },
+        "internal compiler error");
 }
 
 TEST_F(IfStatementTest, Assert_Null_Body) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.create<IfStatement>(b.Expr(true), nullptr, ElseStatementList{});
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.If(b.Expr(true), nullptr);
+        },
+        "internal compiler error");
 }
 
-TEST_F(IfStatementTest, Assert_Null_ElseStatement) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        auto* body = b.create<BlockStatement>(StatementList{});
-        b.create<IfStatement>(b.Expr(true), body, ElseStatementList{nullptr});
-      },
-      "internal compiler error");
+TEST_F(IfStatementTest, Assert_InvalidElse) {
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.If(b.Expr(true), b.Block(), b.Else(b.CallStmt(b.Call("foo"))));
+        },
+        "internal compiler error");
 }
 
 TEST_F(IfStatementTest, Assert_DifferentProgramID_Cond) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.create<IfStatement>(b2.Expr(true), b1.Block(), ElseStatementList{});
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.If(b2.Expr(true), b1.Block());
+        },
+        "internal compiler error");
 }
 
 TEST_F(IfStatementTest, Assert_DifferentProgramID_Body) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.create<IfStatement>(b1.Expr(true), b2.Block(), ElseStatementList{});
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.If(b1.Expr(true), b2.Block());
+        },
+        "internal compiler error");
 }
 
 TEST_F(IfStatementTest, Assert_DifferentProgramID_ElseStatement) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.create<IfStatement>(
-            b1.Expr(true), b1.Block(),
-            ElseStatementList{
-                b2.create<ElseStatement>(b2.Expr("ident"), b2.Block()),
-            });
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.If(b1.Expr(true), b1.Block(), b2.Else(b2.If(b2.Expr("ident"), b2.Block())));
+        },
+        "internal compiler error");
 }
 
 }  // namespace
diff --git a/src/tint/ast/increment_decrement_statement.cc b/src/tint/ast/increment_decrement_statement.cc
index 4ec7f87..99c65cb 100644
--- a/src/tint/ast/increment_decrement_statement.cc
+++ b/src/tint/ast/increment_decrement_statement.cc
@@ -25,20 +25,18 @@
                                                          const Expression* l,
                                                          bool inc)
     : Base(pid, src), lhs(l), increment(inc) {
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, lhs, program_id);
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, lhs, program_id);
 }
 
-IncrementDecrementStatement::IncrementDecrementStatement(
-    IncrementDecrementStatement&&) = default;
+IncrementDecrementStatement::IncrementDecrementStatement(IncrementDecrementStatement&&) = default;
 
 IncrementDecrementStatement::~IncrementDecrementStatement() = default;
 
-const IncrementDecrementStatement* IncrementDecrementStatement::Clone(
-    CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  auto* l = ctx->Clone(lhs);
-  return ctx->dst->create<IncrementDecrementStatement>(src, l, increment);
+const IncrementDecrementStatement* IncrementDecrementStatement::Clone(CloneContext* ctx) const {
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    auto* l = ctx->Clone(lhs);
+    return ctx->dst->create<IncrementDecrementStatement>(src, l, increment);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/increment_decrement_statement.h b/src/tint/ast/increment_decrement_statement.h
index f7882da..05b8478 100644
--- a/src/tint/ast/increment_decrement_statement.h
+++ b/src/tint/ast/increment_decrement_statement.h
@@ -21,33 +21,29 @@
 namespace tint::ast {
 
 /// An increment or decrement statement
-class IncrementDecrementStatement final
-    : public Castable<IncrementDecrementStatement, Statement> {
- public:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  /// @param lhs the LHS expression
-  /// @param inc `true` for increment, `false` for decrement
-  IncrementDecrementStatement(ProgramID pid,
-                              const Source& src,
-                              const Expression* lhs,
-                              bool inc);
-  /// Move constructor
-  IncrementDecrementStatement(IncrementDecrementStatement&&);
-  ~IncrementDecrementStatement() override;
+class IncrementDecrementStatement final : public Castable<IncrementDecrementStatement, Statement> {
+  public:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    /// @param lhs the LHS expression
+    /// @param inc `true` for increment, `false` for decrement
+    IncrementDecrementStatement(ProgramID pid, const Source& src, const Expression* lhs, bool inc);
+    /// Move constructor
+    IncrementDecrementStatement(IncrementDecrementStatement&&);
+    ~IncrementDecrementStatement() override;
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const IncrementDecrementStatement* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const IncrementDecrementStatement* Clone(CloneContext* ctx) const override;
 
-  /// The LHS expression.
-  const Expression* const lhs;
+    /// The LHS expression.
+    const Expression* const lhs;
 
-  /// `true` for increment, `false` for decrement.
-  bool increment;
+    /// `true` for increment, `false` for decrement.
+    bool increment;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/increment_decrement_statement_test.cc b/src/tint/ast/increment_decrement_statement_test.cc
index ccb5f07..6a5ae67 100644
--- a/src/tint/ast/increment_decrement_statement_test.cc
+++ b/src/tint/ast/increment_decrement_statement_test.cc
@@ -23,45 +23,44 @@
 using IncrementDecrementStatementTest = TestHelper;
 
 TEST_F(IncrementDecrementStatementTest, Creation) {
-  auto* expr = Expr("expr");
+    auto* expr = Expr("expr");
 
-  auto* i = create<IncrementDecrementStatement>(expr, true);
-  EXPECT_EQ(i->lhs, expr);
-  EXPECT_TRUE(i->increment);
+    auto* i = create<IncrementDecrementStatement>(expr, true);
+    EXPECT_EQ(i->lhs, expr);
+    EXPECT_TRUE(i->increment);
 }
 
 TEST_F(IncrementDecrementStatementTest, Creation_WithSource) {
-  auto* expr = Expr("expr");
-  auto* i = create<IncrementDecrementStatement>(Source{Source::Location{20, 2}},
-                                                expr, true);
-  auto src = i->source;
-  EXPECT_EQ(i->lhs, expr);
-  EXPECT_TRUE(i->increment);
-  EXPECT_EQ(src.range.begin.line, 20u);
-  EXPECT_EQ(src.range.begin.column, 2u);
+    auto* expr = Expr("expr");
+    auto* i = create<IncrementDecrementStatement>(Source{Source::Location{20, 2}}, expr, true);
+    auto src = i->source;
+    EXPECT_EQ(i->lhs, expr);
+    EXPECT_TRUE(i->increment);
+    EXPECT_EQ(src.range.begin.line, 20u);
+    EXPECT_EQ(src.range.begin.column, 2u);
 }
 
 TEST_F(IncrementDecrementStatementTest, IsIncrementDecrement) {
-  auto* expr = Expr("expr");
-  auto* i = create<IncrementDecrementStatement>(expr, true);
-  EXPECT_TRUE(i->Is<IncrementDecrementStatement>());
+    auto* expr = Expr("expr");
+    auto* i = create<IncrementDecrementStatement>(expr, true);
+    EXPECT_TRUE(i->Is<IncrementDecrementStatement>());
 }
 
 TEST_F(IncrementDecrementStatementTest, Decrement) {
-  auto* expr = Expr("expr");
-  auto* i = create<IncrementDecrementStatement>(expr, false);
-  EXPECT_EQ(i->lhs, expr);
-  EXPECT_FALSE(i->increment);
+    auto* expr = Expr("expr");
+    auto* i = create<IncrementDecrementStatement>(expr, false);
+    EXPECT_EQ(i->lhs, expr);
+    EXPECT_FALSE(i->increment);
 }
 
 TEST_F(IncrementDecrementStatementTest, Assert_DifferentProgramID_Expr) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.create<IncrementDecrementStatement>(b2.Expr(true), true);
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.create<IncrementDecrementStatement>(b2.Expr(true), true);
+        },
+        "internal compiler error");
 }
 
 }  // namespace
diff --git a/src/tint/ast/index_accessor_expression.cc b/src/tint/ast/index_accessor_expression.cc
index 6fed4ea..232bc79 100644
--- a/src/tint/ast/index_accessor_expression.cc
+++ b/src/tint/ast/index_accessor_expression.cc
@@ -25,24 +25,22 @@
                                                  const Expression* obj,
                                                  const Expression* idx)
     : Base(pid, src), object(obj), index(idx) {
-  TINT_ASSERT(AST, object);
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, object, program_id);
-  TINT_ASSERT(AST, idx);
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, idx, program_id);
+    TINT_ASSERT(AST, object);
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, object, program_id);
+    TINT_ASSERT(AST, idx);
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, idx, program_id);
 }
 
-IndexAccessorExpression::IndexAccessorExpression(IndexAccessorExpression&&) =
-    default;
+IndexAccessorExpression::IndexAccessorExpression(IndexAccessorExpression&&) = default;
 
 IndexAccessorExpression::~IndexAccessorExpression() = default;
 
-const IndexAccessorExpression* IndexAccessorExpression::Clone(
-    CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  auto* obj = ctx->Clone(object);
-  auto* idx = ctx->Clone(index);
-  return ctx->dst->create<IndexAccessorExpression>(src, obj, idx);
+const IndexAccessorExpression* IndexAccessorExpression::Clone(CloneContext* ctx) const {
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    auto* obj = ctx->Clone(object);
+    auto* idx = ctx->Clone(index);
+    return ctx->dst->create<IndexAccessorExpression>(src, obj, idx);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/index_accessor_expression.h b/src/tint/ast/index_accessor_expression.h
index a5e48cc..c36f6b8 100644
--- a/src/tint/ast/index_accessor_expression.h
+++ b/src/tint/ast/index_accessor_expression.h
@@ -20,33 +20,32 @@
 namespace tint::ast {
 
 /// An index accessor expression
-class IndexAccessorExpression final
-    : public Castable<IndexAccessorExpression, Expression> {
- public:
-  /// Constructor
-  /// @param program_id the identifier of the program that owns this node
-  /// @param source the index accessor source
-  /// @param obj the object
-  /// @param idx the index expression
-  IndexAccessorExpression(ProgramID program_id,
-                          const Source& source,
-                          const Expression* obj,
-                          const Expression* idx);
-  /// Move constructor
-  IndexAccessorExpression(IndexAccessorExpression&&);
-  ~IndexAccessorExpression() override;
+class IndexAccessorExpression final : public Castable<IndexAccessorExpression, Expression> {
+  public:
+    /// Constructor
+    /// @param program_id the identifier of the program that owns this node
+    /// @param source the index accessor source
+    /// @param obj the object
+    /// @param idx the index expression
+    IndexAccessorExpression(ProgramID program_id,
+                            const Source& source,
+                            const Expression* obj,
+                            const Expression* idx);
+    /// Move constructor
+    IndexAccessorExpression(IndexAccessorExpression&&);
+    ~IndexAccessorExpression() override;
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const IndexAccessorExpression* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const IndexAccessorExpression* Clone(CloneContext* ctx) const override;
 
-  /// the array, vector or matrix
-  const Expression* const object;
+    /// the array, vector or matrix
+    const Expression* const object;
 
-  /// the index expression
-  const Expression* const index;
+    /// the index expression
+    const Expression* const index;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/index_accessor_expression_test.cc b/src/tint/ast/index_accessor_expression_test.cc
index 45fef2b..efdcecb 100644
--- a/src/tint/ast/index_accessor_expression_test.cc
+++ b/src/tint/ast/index_accessor_expression_test.cc
@@ -21,68 +21,68 @@
 using IndexAccessorExpressionTest = TestHelper;
 
 TEST_F(IndexAccessorExpressionTest, Create) {
-  auto* obj = Expr("obj");
-  auto* idx = Expr("idx");
+    auto* obj = Expr("obj");
+    auto* idx = Expr("idx");
 
-  auto* exp = IndexAccessor(obj, idx);
-  ASSERT_EQ(exp->object, obj);
-  ASSERT_EQ(exp->index, idx);
+    auto* exp = IndexAccessor(obj, idx);
+    ASSERT_EQ(exp->object, obj);
+    ASSERT_EQ(exp->index, idx);
 }
 
 TEST_F(IndexAccessorExpressionTest, CreateWithSource) {
-  auto* obj = Expr("obj");
-  auto* idx = Expr("idx");
+    auto* obj = Expr("obj");
+    auto* idx = Expr("idx");
 
-  auto* exp = IndexAccessor(Source{{20, 2}}, obj, idx);
-  auto src = exp->source;
-  EXPECT_EQ(src.range.begin.line, 20u);
-  EXPECT_EQ(src.range.begin.column, 2u);
+    auto* exp = IndexAccessor(Source{{20, 2}}, obj, idx);
+    auto src = exp->source;
+    EXPECT_EQ(src.range.begin.line, 20u);
+    EXPECT_EQ(src.range.begin.column, 2u);
 }
 
 TEST_F(IndexAccessorExpressionTest, IsIndexAccessor) {
-  auto* obj = Expr("obj");
-  auto* idx = Expr("idx");
+    auto* obj = Expr("obj");
+    auto* idx = Expr("idx");
 
-  auto* exp = IndexAccessor(obj, idx);
-  EXPECT_TRUE(exp->Is<IndexAccessorExpression>());
+    auto* exp = IndexAccessor(obj, idx);
+    EXPECT_TRUE(exp->Is<IndexAccessorExpression>());
 }
 
 TEST_F(IndexAccessorExpressionTest, Assert_Null_Array) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.IndexAccessor(nullptr, b.Expr("idx"));
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.IndexAccessor(nullptr, b.Expr("idx"));
+        },
+        "internal compiler error");
 }
 
 TEST_F(IndexAccessorExpressionTest, Assert_Null_Index) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.IndexAccessor(b.Expr("arr"), nullptr);
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.IndexAccessor(b.Expr("arr"), nullptr);
+        },
+        "internal compiler error");
 }
 
 TEST_F(IndexAccessorExpressionTest, Assert_DifferentProgramID_Array) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.IndexAccessor(b2.Expr("arr"), b1.Expr("idx"));
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.IndexAccessor(b2.Expr("arr"), b1.Expr("idx"));
+        },
+        "internal compiler error");
 }
 
 TEST_F(IndexAccessorExpressionTest, Assert_DifferentProgramID_Index) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.IndexAccessor(b1.Expr("arr"), b2.Expr("idx"));
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.IndexAccessor(b1.Expr("arr"), b2.Expr("idx"));
+        },
+        "internal compiler error");
 }
 
 }  // namespace
diff --git a/src/tint/ast/int_literal_expression.cc b/src/tint/ast/int_literal_expression.cc
index 8cd68c9..7e11f7e 100644
--- a/src/tint/ast/int_literal_expression.cc
+++ b/src/tint/ast/int_literal_expression.cc
@@ -14,13 +14,35 @@
 
 #include "src/tint/ast/int_literal_expression.h"
 
+#include "src/tint/program_builder.h"
+
 TINT_INSTANTIATE_TYPEINFO(tint::ast::IntLiteralExpression);
 
 namespace tint::ast {
 
-IntLiteralExpression::IntLiteralExpression(ProgramID pid, const Source& src)
-    : Base(pid, src) {}
+IntLiteralExpression::IntLiteralExpression(ProgramID pid,
+                                           const Source& src,
+                                           int64_t val,
+                                           Suffix suf)
+    : Base(pid, src), value(val), suffix(suf) {}
 
 IntLiteralExpression::~IntLiteralExpression() = default;
 
+const IntLiteralExpression* IntLiteralExpression::Clone(CloneContext* ctx) const {
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    return ctx->dst->create<IntLiteralExpression>(src, value, suffix);
+}
+
+std::ostream& operator<<(std::ostream& out, IntLiteralExpression::Suffix suffix) {
+    switch (suffix) {
+        default:
+            return out;
+        case IntLiteralExpression::Suffix::kI:
+            return out << "i";
+        case IntLiteralExpression::Suffix::kU:
+            return out << "u";
+    }
+}
+
 }  // namespace tint::ast
diff --git a/src/tint/ast/int_literal_expression.h b/src/tint/ast/int_literal_expression.h
index 9ca3105..8ff58ea 100644
--- a/src/tint/ast/int_literal_expression.h
+++ b/src/tint/ast/int_literal_expression.h
@@ -19,24 +19,46 @@
 
 namespace tint::ast {
 
-/// An integer literal. This could be either signed or unsigned.
-class IntLiteralExpression
-    : public Castable<IntLiteralExpression, LiteralExpression> {
- public:
-  ~IntLiteralExpression() override;
+/// An integer literal. The literal may have an 'i', 'u' or no suffix.
+class IntLiteralExpression : public Castable<IntLiteralExpression, LiteralExpression> {
+  public:
+    /// Literal suffix
+    enum class Suffix {
+        /// No suffix
+        kNone,
+        /// 'i' suffix (i32)
+        kI,
+        /// 'u' suffix (u32)
+        kU,
+    };
 
-  /// @returns the literal value as a u32
-  virtual uint32_t ValueAsU32() const = 0;
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    /// @param val the literal value
+    /// @param suf the literal suffix
+    IntLiteralExpression(ProgramID pid, const Source& src, int64_t val, Suffix suf);
 
-  /// @returns the literal value as an i32
-  int32_t ValueAsI32() const { return static_cast<int32_t>(ValueAsU32()); }
+    ~IntLiteralExpression() override;
 
- protected:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  IntLiteralExpression(ProgramID pid, const Source& src);
-};  // namespace ast
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const IntLiteralExpression* Clone(CloneContext* ctx) const override;
+
+    /// The literal value
+    const int64_t value;
+
+    /// The literal suffix
+    const Suffix suffix;
+};
+
+/// Writes the integer literal suffix to the std::ostream.
+/// @param out the std::ostream to write to
+/// @param suffix the suffix to write
+/// @returns out so calls can be chained
+std::ostream& operator<<(std::ostream& out, IntLiteralExpression::Suffix suffix);
 
 }  // namespace tint::ast
 
diff --git a/src/tint/ast/int_literal_expression_test.cc b/src/tint/ast/int_literal_expression_test.cc
index d04def1..8bc3d2f 100644
--- a/src/tint/ast/int_literal_expression_test.cc
+++ b/src/tint/ast/int_literal_expression_test.cc
@@ -19,14 +19,25 @@
 
 using IntLiteralExpressionTest = TestHelper;
 
-TEST_F(IntLiteralExpressionTest, Sint_IsInt) {
-  auto* i = create<SintLiteralExpression>(47);
-  ASSERT_TRUE(i->Is<IntLiteralExpression>());
+TEST_F(IntLiteralExpressionTest, SuffixNone) {
+    auto* i = create<IntLiteralExpression>(42, IntLiteralExpression::Suffix::kNone);
+    ASSERT_TRUE(i->Is<IntLiteralExpression>());
+    EXPECT_EQ(i->value, 42);
+    EXPECT_EQ(i->suffix, IntLiteralExpression::Suffix::kNone);
 }
 
-TEST_F(IntLiteralExpressionTest, Uint_IsInt) {
-  auto* i = create<UintLiteralExpression>(42);
-  EXPECT_TRUE(i->Is<IntLiteralExpression>());
+TEST_F(IntLiteralExpressionTest, SuffixI) {
+    auto* i = create<IntLiteralExpression>(42, IntLiteralExpression::Suffix::kI);
+    ASSERT_TRUE(i->Is<IntLiteralExpression>());
+    EXPECT_EQ(i->value, 42);
+    EXPECT_EQ(i->suffix, IntLiteralExpression::Suffix::kI);
+}
+
+TEST_F(IntLiteralExpressionTest, SuffixU) {
+    auto* i = create<IntLiteralExpression>(42, IntLiteralExpression::Suffix::kU);
+    ASSERT_TRUE(i->Is<IntLiteralExpression>());
+    EXPECT_EQ(i->value, 42);
+    EXPECT_EQ(i->suffix, IntLiteralExpression::Suffix::kU);
 }
 
 }  // namespace
diff --git a/src/tint/ast/internal_attribute.cc b/src/tint/ast/internal_attribute.cc
index b42af9c..180e909 100644
--- a/src/tint/ast/internal_attribute.cc
+++ b/src/tint/ast/internal_attribute.cc
@@ -23,7 +23,7 @@
 InternalAttribute::~InternalAttribute() = default;
 
 std::string InternalAttribute::Name() const {
-  return "internal";
+    return "internal";
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/internal_attribute.h b/src/tint/ast/internal_attribute.h
index 7e35dcb..bb13559 100644
--- a/src/tint/ast/internal_attribute.h
+++ b/src/tint/ast/internal_attribute.h
@@ -25,20 +25,20 @@
 /// These attributes are not produced by generators, but instead are usually
 /// created by transforms for consumption by a particular backend.
 class InternalAttribute : public Castable<InternalAttribute, Attribute> {
- public:
-  /// Constructor
-  /// @param program_id the identifier of the program that owns this node
-  explicit InternalAttribute(ProgramID program_id);
+  public:
+    /// Constructor
+    /// @param program_id the identifier of the program that owns this node
+    explicit InternalAttribute(ProgramID program_id);
 
-  /// Destructor
-  ~InternalAttribute() override;
+    /// Destructor
+    ~InternalAttribute() override;
 
-  /// @return a short description of the internal attribute which will be
-  /// displayed in WGSL as `@internal(<name>)` (but is not parsable).
-  virtual std::string InternalName() const = 0;
+    /// @return a short description of the internal attribute which will be
+    /// displayed in WGSL as `@internal(<name>)` (but is not parsable).
+    virtual std::string InternalName() const = 0;
 
-  /// @returns the WGSL name for the attribute
-  std::string Name() const override;
+    /// @returns the WGSL name for the attribute
+    std::string Name() const override;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/interpolate_attribute.cc b/src/tint/ast/interpolate_attribute.cc
index 6f452a9..909e827 100644
--- a/src/tint/ast/interpolate_attribute.cc
+++ b/src/tint/ast/interpolate_attribute.cc
@@ -31,54 +31,53 @@
 InterpolateAttribute::~InterpolateAttribute() = default;
 
 std::string InterpolateAttribute::Name() const {
-  return "interpolate";
+    return "interpolate";
 }
 
-const InterpolateAttribute* InterpolateAttribute::Clone(
-    CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  return ctx->dst->create<InterpolateAttribute>(src, type, sampling);
+const InterpolateAttribute* InterpolateAttribute::Clone(CloneContext* ctx) const {
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    return ctx->dst->create<InterpolateAttribute>(src, type, sampling);
 }
 
 std::ostream& operator<<(std::ostream& out, InterpolationType type) {
-  switch (type) {
-    case InterpolationType::kPerspective: {
-      out << "perspective";
-      break;
+    switch (type) {
+        case InterpolationType::kPerspective: {
+            out << "perspective";
+            break;
+        }
+        case InterpolationType::kLinear: {
+            out << "linear";
+            break;
+        }
+        case InterpolationType::kFlat: {
+            out << "flat";
+            break;
+        }
     }
-    case InterpolationType::kLinear: {
-      out << "linear";
-      break;
-    }
-    case InterpolationType::kFlat: {
-      out << "flat";
-      break;
-    }
-  }
-  return out;
+    return out;
 }
 
 std::ostream& operator<<(std::ostream& out, InterpolationSampling sampling) {
-  switch (sampling) {
-    case InterpolationSampling::kNone: {
-      out << "none";
-      break;
+    switch (sampling) {
+        case InterpolationSampling::kNone: {
+            out << "none";
+            break;
+        }
+        case InterpolationSampling::kCenter: {
+            out << "center";
+            break;
+        }
+        case InterpolationSampling::kCentroid: {
+            out << "centroid";
+            break;
+        }
+        case InterpolationSampling::kSample: {
+            out << "sample";
+            break;
+        }
     }
-    case InterpolationSampling::kCenter: {
-      out << "center";
-      break;
-    }
-    case InterpolationSampling::kCentroid: {
-      out << "centroid";
-      break;
-    }
-    case InterpolationSampling::kSample: {
-      out << "sample";
-      break;
-    }
-  }
-  return out;
+    return out;
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/interpolate_attribute.h b/src/tint/ast/interpolate_attribute.h
index a659ef9..4b2a2df 100644
--- a/src/tint/ast/interpolate_attribute.h
+++ b/src/tint/ast/interpolate_attribute.h
@@ -29,34 +29,33 @@
 enum class InterpolationSampling { kNone = -1, kCenter, kCentroid, kSample };
 
 /// An interpolate attribute
-class InterpolateAttribute final
-    : public Castable<InterpolateAttribute, Attribute> {
- public:
-  /// Create an interpolate attribute.
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  /// @param type the interpolation type
-  /// @param sampling the interpolation sampling
-  InterpolateAttribute(ProgramID pid,
-                       const Source& src,
-                       InterpolationType type,
-                       InterpolationSampling sampling);
-  ~InterpolateAttribute() override;
+class InterpolateAttribute final : public Castable<InterpolateAttribute, Attribute> {
+  public:
+    /// Create an interpolate attribute.
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    /// @param type the interpolation type
+    /// @param sampling the interpolation sampling
+    InterpolateAttribute(ProgramID pid,
+                         const Source& src,
+                         InterpolationType type,
+                         InterpolationSampling sampling);
+    ~InterpolateAttribute() override;
 
-  /// @returns the WGSL name for the attribute
-  std::string Name() const override;
+    /// @returns the WGSL name for the attribute
+    std::string Name() const override;
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const InterpolateAttribute* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const InterpolateAttribute* Clone(CloneContext* ctx) const override;
 
-  /// The interpolation type
-  const InterpolationType type;
+    /// The interpolation type
+    const InterpolationType type;
 
-  /// The interpolation sampling
-  const InterpolationSampling sampling;
+    /// The interpolation sampling
+    const InterpolationSampling sampling;
 };
 
 /// @param out the std::ostream to write to
diff --git a/src/tint/ast/interpolate_attribute_test.cc b/src/tint/ast/interpolate_attribute_test.cc
index 8bf85e1..d8b6601 100644
--- a/src/tint/ast/interpolate_attribute_test.cc
+++ b/src/tint/ast/interpolate_attribute_test.cc
@@ -22,10 +22,10 @@
 using InterpolateAttributeTest = TestHelper;
 
 TEST_F(InterpolateAttributeTest, Creation) {
-  auto* d = create<InterpolateAttribute>(InterpolationType::kLinear,
-                                         InterpolationSampling::kCenter);
-  EXPECT_EQ(InterpolationType::kLinear, d->type);
-  EXPECT_EQ(InterpolationSampling::kCenter, d->sampling);
+    auto* d =
+        create<InterpolateAttribute>(InterpolationType::kLinear, InterpolationSampling::kCenter);
+    EXPECT_EQ(InterpolationType::kLinear, d->type);
+    EXPECT_EQ(InterpolationSampling::kCenter, d->sampling);
 }
 
 }  // namespace
diff --git a/src/tint/ast/invariant_attribute.cc b/src/tint/ast/invariant_attribute.cc
index 31dd4b7..1b0f126 100644
--- a/src/tint/ast/invariant_attribute.cc
+++ b/src/tint/ast/invariant_attribute.cc
@@ -20,19 +20,18 @@
 
 namespace tint::ast {
 
-InvariantAttribute::InvariantAttribute(ProgramID pid, const Source& src)
-    : Base(pid, src) {}
+InvariantAttribute::InvariantAttribute(ProgramID pid, const Source& src) : Base(pid, src) {}
 
 InvariantAttribute::~InvariantAttribute() = default;
 
 std::string InvariantAttribute::Name() const {
-  return "invariant";
+    return "invariant";
 }
 
 const InvariantAttribute* InvariantAttribute::Clone(CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  return ctx->dst->create<InvariantAttribute>(src);
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    return ctx->dst->create<InvariantAttribute>(src);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/invariant_attribute.h b/src/tint/ast/invariant_attribute.h
index 375eb3c..6bb42fc 100644
--- a/src/tint/ast/invariant_attribute.h
+++ b/src/tint/ast/invariant_attribute.h
@@ -22,23 +22,22 @@
 namespace tint::ast {
 
 /// The invariant attribute
-class InvariantAttribute final
-    : public Castable<InvariantAttribute, Attribute> {
- public:
-  /// constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  InvariantAttribute(ProgramID pid, const Source& src);
-  ~InvariantAttribute() override;
+class InvariantAttribute final : public Castable<InvariantAttribute, Attribute> {
+  public:
+    /// constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    InvariantAttribute(ProgramID pid, const Source& src);
+    ~InvariantAttribute() override;
 
-  /// @returns the WGSL name for the attribute
-  std::string Name() const override;
+    /// @returns the WGSL name for the attribute
+    std::string Name() const override;
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const InvariantAttribute* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const InvariantAttribute* Clone(CloneContext* ctx) const override;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/literal_expression.cc b/src/tint/ast/literal_expression.cc
index 6863357..d05279d 100644
--- a/src/tint/ast/literal_expression.cc
+++ b/src/tint/ast/literal_expression.cc
@@ -18,8 +18,7 @@
 
 namespace tint::ast {
 
-LiteralExpression::LiteralExpression(ProgramID pid, const Source& src)
-    : Base(pid, src) {}
+LiteralExpression::LiteralExpression(ProgramID pid, const Source& src) : Base(pid, src) {}
 
 LiteralExpression::~LiteralExpression() = default;
 
diff --git a/src/tint/ast/literal_expression.h b/src/tint/ast/literal_expression.h
index e794f59..56fc1f0 100644
--- a/src/tint/ast/literal_expression.h
+++ b/src/tint/ast/literal_expression.h
@@ -23,14 +23,14 @@
 
 /// Base class for a literal value expressions
 class LiteralExpression : public Castable<LiteralExpression, Expression> {
- public:
-  ~LiteralExpression() override;
+  public:
+    ~LiteralExpression() override;
 
- protected:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the input source
-  LiteralExpression(ProgramID pid, const Source& src);
+  protected:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the input source
+    LiteralExpression(ProgramID pid, const Source& src);
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/location_attribute.cc b/src/tint/ast/location_attribute.cc
index e6d4f68..1eae823 100644
--- a/src/tint/ast/location_attribute.cc
+++ b/src/tint/ast/location_attribute.cc
@@ -22,21 +22,19 @@
 
 namespace tint::ast {
 
-LocationAttribute::LocationAttribute(ProgramID pid,
-                                     const Source& src,
-                                     uint32_t val)
+LocationAttribute::LocationAttribute(ProgramID pid, const Source& src, uint32_t val)
     : Base(pid, src), value(val) {}
 
 LocationAttribute::~LocationAttribute() = default;
 
 std::string LocationAttribute::Name() const {
-  return "location";
+    return "location";
 }
 
 const LocationAttribute* LocationAttribute::Clone(CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  return ctx->dst->create<LocationAttribute>(src, value);
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    return ctx->dst->create<LocationAttribute>(src, value);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/location_attribute.h b/src/tint/ast/location_attribute.h
index eefd863..3646c54 100644
--- a/src/tint/ast/location_attribute.h
+++ b/src/tint/ast/location_attribute.h
@@ -23,25 +23,25 @@
 
 /// A location attribute
 class LocationAttribute final : public Castable<LocationAttribute, Attribute> {
- public:
-  /// constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  /// @param value the location value
-  LocationAttribute(ProgramID pid, const Source& src, uint32_t value);
-  ~LocationAttribute() override;
+  public:
+    /// constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    /// @param value the location value
+    LocationAttribute(ProgramID pid, const Source& src, uint32_t value);
+    ~LocationAttribute() override;
 
-  /// @returns the WGSL name for the attribute
-  std::string Name() const override;
+    /// @returns the WGSL name for the attribute
+    std::string Name() const override;
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const LocationAttribute* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const LocationAttribute* Clone(CloneContext* ctx) const override;
 
-  /// The location value
-  const uint32_t value;
+    /// The location value
+    const uint32_t value;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/location_attribute_test.cc b/src/tint/ast/location_attribute_test.cc
index e71b7fb..a1562d5 100644
--- a/src/tint/ast/location_attribute_test.cc
+++ b/src/tint/ast/location_attribute_test.cc
@@ -20,8 +20,8 @@
 using LocationAttributeTest = TestHelper;
 
 TEST_F(LocationAttributeTest, Creation) {
-  auto* d = create<LocationAttribute>(2);
-  EXPECT_EQ(2u, d->value);
+    auto* d = create<LocationAttribute>(2);
+    EXPECT_EQ(2u, d->value);
 }
 
 }  // namespace
diff --git a/src/tint/ast/loop_statement.cc b/src/tint/ast/loop_statement.cc
index 35f8d79..9d14960 100644
--- a/src/tint/ast/loop_statement.cc
+++ b/src/tint/ast/loop_statement.cc
@@ -25,9 +25,9 @@
                              const BlockStatement* b,
                              const BlockStatement* cont)
     : Base(pid, src), body(b), continuing(cont) {
-  TINT_ASSERT(AST, body);
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, body, program_id);
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, continuing, program_id);
+    TINT_ASSERT(AST, body);
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, body, program_id);
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, continuing, program_id);
 }
 
 LoopStatement::LoopStatement(LoopStatement&&) = default;
@@ -35,11 +35,11 @@
 LoopStatement::~LoopStatement() = default;
 
 const LoopStatement* LoopStatement::Clone(CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  auto* b = ctx->Clone(body);
-  auto* cont = ctx->Clone(continuing);
-  return ctx->dst->create<LoopStatement>(src, b, cont);
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    auto* b = ctx->Clone(body);
+    auto* cont = ctx->Clone(continuing);
+    return ctx->dst->create<LoopStatement>(src, b, cont);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/loop_statement.h b/src/tint/ast/loop_statement.h
index 921b68e..5a044fe 100644
--- a/src/tint/ast/loop_statement.h
+++ b/src/tint/ast/loop_statement.h
@@ -21,31 +21,31 @@
 
 /// A loop statement
 class LoopStatement final : public Castable<LoopStatement, Statement> {
- public:
-  /// Constructor
-  /// @param program_id the identifier of the program that owns this node
-  /// @param source the loop statement source
-  /// @param body the body statements
-  /// @param continuing the continuing statements
-  LoopStatement(ProgramID program_id,
-                const Source& source,
-                const BlockStatement* body,
-                const BlockStatement* continuing);
-  /// Move constructor
-  LoopStatement(LoopStatement&&);
-  ~LoopStatement() override;
+  public:
+    /// Constructor
+    /// @param program_id the identifier of the program that owns this node
+    /// @param source the loop statement source
+    /// @param body the body statements
+    /// @param continuing the continuing statements
+    LoopStatement(ProgramID program_id,
+                  const Source& source,
+                  const BlockStatement* body,
+                  const BlockStatement* continuing);
+    /// Move constructor
+    LoopStatement(LoopStatement&&);
+    ~LoopStatement() override;
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const LoopStatement* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const LoopStatement* Clone(CloneContext* ctx) const override;
 
-  /// The loop body
-  const BlockStatement* const body;
+    /// The loop body
+    const BlockStatement* const body;
 
-  /// The continuing statements
-  const BlockStatement* const continuing;
+    /// The continuing statements
+    const BlockStatement* const continuing;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/loop_statement_test.cc b/src/tint/ast/loop_statement_test.cc
index 9c8e812..c28665b 100644
--- a/src/tint/ast/loop_statement_test.cc
+++ b/src/tint/ast/loop_statement_test.cc
@@ -25,78 +25,77 @@
 using LoopStatementTest = TestHelper;
 
 TEST_F(LoopStatementTest, Creation) {
-  auto* body = Block(create<DiscardStatement>());
-  auto* b = body->Last();
+    auto* body = Block(create<DiscardStatement>());
+    auto* b = body->Last();
 
-  auto* continuing = Block(create<DiscardStatement>());
+    auto* continuing = Block(create<DiscardStatement>());
 
-  auto* l = create<LoopStatement>(body, continuing);
-  ASSERT_EQ(l->body->statements.size(), 1u);
-  EXPECT_EQ(l->body->statements[0], b);
-  ASSERT_EQ(l->continuing->statements.size(), 1u);
-  EXPECT_EQ(l->continuing->statements[0], continuing->Last());
+    auto* l = create<LoopStatement>(body, continuing);
+    ASSERT_EQ(l->body->statements.size(), 1u);
+    EXPECT_EQ(l->body->statements[0], b);
+    ASSERT_EQ(l->continuing->statements.size(), 1u);
+    EXPECT_EQ(l->continuing->statements[0], continuing->Last());
 }
 
 TEST_F(LoopStatementTest, Creation_WithSource) {
-  auto* body = Block(create<DiscardStatement>());
+    auto* body = Block(create<DiscardStatement>());
 
-  auto* continuing = Block(create<DiscardStatement>());
+    auto* continuing = Block(create<DiscardStatement>());
 
-  auto* l =
-      create<LoopStatement>(Source{Source::Location{20, 2}}, body, continuing);
-  auto src = l->source;
-  EXPECT_EQ(src.range.begin.line, 20u);
-  EXPECT_EQ(src.range.begin.column, 2u);
+    auto* l = create<LoopStatement>(Source{Source::Location{20, 2}}, body, continuing);
+    auto src = l->source;
+    EXPECT_EQ(src.range.begin.line, 20u);
+    EXPECT_EQ(src.range.begin.column, 2u);
 }
 
 TEST_F(LoopStatementTest, IsLoop) {
-  auto* l = create<LoopStatement>(Block(), Block());
-  EXPECT_TRUE(l->Is<LoopStatement>());
+    auto* l = create<LoopStatement>(Block(), Block());
+    EXPECT_TRUE(l->Is<LoopStatement>());
 }
 
 TEST_F(LoopStatementTest, HasContinuing_WithoutContinuing) {
-  auto* body = Block(create<DiscardStatement>());
+    auto* body = Block(create<DiscardStatement>());
 
-  auto* l = create<LoopStatement>(body, nullptr);
-  EXPECT_FALSE(l->continuing);
+    auto* l = create<LoopStatement>(body, nullptr);
+    EXPECT_FALSE(l->continuing);
 }
 
 TEST_F(LoopStatementTest, HasContinuing_WithContinuing) {
-  auto* body = Block(create<DiscardStatement>());
+    auto* body = Block(create<DiscardStatement>());
 
-  auto* continuing = Block(create<DiscardStatement>());
+    auto* continuing = Block(create<DiscardStatement>());
 
-  auto* l = create<LoopStatement>(body, continuing);
-  EXPECT_TRUE(l->continuing);
+    auto* l = create<LoopStatement>(body, continuing);
+    EXPECT_TRUE(l->continuing);
 }
 
 TEST_F(LoopStatementTest, Assert_Null_Body) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.create<LoopStatement>(nullptr, nullptr);
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.create<LoopStatement>(nullptr, nullptr);
+        },
+        "internal compiler error");
 }
 
 TEST_F(LoopStatementTest, Assert_DifferentProgramID_Body) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.create<LoopStatement>(b2.Block(), b1.Block());
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.create<LoopStatement>(b2.Block(), b1.Block());
+        },
+        "internal compiler error");
 }
 
 TEST_F(LoopStatementTest, Assert_DifferentProgramID_Continuing) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.create<LoopStatement>(b1.Block(), b2.Block());
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.create<LoopStatement>(b1.Block(), b2.Block());
+        },
+        "internal compiler error");
 }
 
 }  // namespace
diff --git a/src/tint/ast/matrix.cc b/src/tint/ast/matrix.cc
index 8ad2b8a..1f74a26 100644
--- a/src/tint/ast/matrix.cc
+++ b/src/tint/ast/matrix.cc
@@ -20,17 +20,13 @@
 
 namespace tint::ast {
 
-Matrix::Matrix(ProgramID pid,
-               const Source& src,
-               const Type* subtype,
-               uint32_t r,
-               uint32_t c)
+Matrix::Matrix(ProgramID pid, const Source& src, const Type* subtype, uint32_t r, uint32_t c)
     : Base(pid, src), type(subtype), rows(r), columns(c) {
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, subtype, program_id);
-  TINT_ASSERT(AST, rows > 1);
-  TINT_ASSERT(AST, rows < 5);
-  TINT_ASSERT(AST, columns > 1);
-  TINT_ASSERT(AST, columns < 5);
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, subtype, program_id);
+    TINT_ASSERT(AST, rows > 1);
+    TINT_ASSERT(AST, rows < 5);
+    TINT_ASSERT(AST, columns > 1);
+    TINT_ASSERT(AST, columns < 5);
 }
 
 Matrix::Matrix(Matrix&&) = default;
@@ -38,19 +34,19 @@
 Matrix::~Matrix() = default;
 
 std::string Matrix::FriendlyName(const SymbolTable& symbols) const {
-  std::ostringstream out;
-  out << "mat" << columns << "x" << rows;
-  if (type) {
-    out << "<" << type->FriendlyName(symbols) << ">";
-  }
-  return out.str();
+    std::ostringstream out;
+    out << "mat" << columns << "x" << rows;
+    if (type) {
+        out << "<" << type->FriendlyName(symbols) << ">";
+    }
+    return out.str();
 }
 
 const Matrix* Matrix::Clone(CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  auto* ty = ctx->Clone(type);
-  return ctx->dst->create<Matrix>(src, ty, rows, columns);
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    auto* ty = ctx->Clone(type);
+    return ctx->dst->create<Matrix>(src, ty, rows, columns);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/matrix.h b/src/tint/ast/matrix.h
index cb1f6d9..620f28a 100644
--- a/src/tint/ast/matrix.h
+++ b/src/tint/ast/matrix.h
@@ -23,44 +23,40 @@
 
 /// A matrix type
 class Matrix final : public Castable<Matrix, Type> {
- public:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  /// @param subtype the declared type of the matrix components. May be null for
-  ///        matrix constructors, where the element type will be inferred from
-  ///        the constructor arguments
-  /// @param rows the number of rows in the matrix
-  /// @param columns the number of columns in the matrix
-  Matrix(ProgramID pid,
-         const Source& src,
-         const Type* subtype,
-         uint32_t rows,
-         uint32_t columns);
-  /// Move constructor
-  Matrix(Matrix&&);
-  ~Matrix() override;
+  public:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    /// @param subtype the declared type of the matrix components. May be null for
+    ///        matrix constructors, where the element type will be inferred from
+    ///        the constructor arguments
+    /// @param rows the number of rows in the matrix
+    /// @param columns the number of columns in the matrix
+    Matrix(ProgramID pid, const Source& src, const Type* subtype, uint32_t rows, uint32_t columns);
+    /// Move constructor
+    Matrix(Matrix&&);
+    ~Matrix() override;
 
-  /// @param symbols the program's symbol table
-  /// @returns the name for this type that closely resembles how it would be
-  /// declared in WGSL.
-  std::string FriendlyName(const SymbolTable& symbols) const override;
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type that closely resembles how it would be
+    /// declared in WGSL.
+    std::string FriendlyName(const SymbolTable& symbols) const override;
 
-  /// Clones this type and all transitive types using the `CloneContext` `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned type
-  const Matrix* Clone(CloneContext* ctx) const override;
+    /// Clones this type and all transitive types using the `CloneContext` `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned type
+    const Matrix* Clone(CloneContext* ctx) const override;
 
-  /// The declared type of the matrix components. May be null for matrix
-  /// constructors, where the element type will be inferred from the constructor
-  /// arguments
-  const Type* const type;
+    /// The declared type of the matrix components. May be null for matrix
+    /// constructors, where the element type will be inferred from the constructor
+    /// arguments
+    const Type* const type;
 
-  /// The number of rows in the matrix
-  const uint32_t rows;
+    /// The number of rows in the matrix
+    const uint32_t rows;
 
-  /// The number of columns in the matrix
-  const uint32_t columns;
+    /// The number of columns in the matrix
+    const uint32_t columns;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/matrix_test.cc b/src/tint/ast/matrix_test.cc
index 216408f..66ea84d 100644
--- a/src/tint/ast/matrix_test.cc
+++ b/src/tint/ast/matrix_test.cc
@@ -33,22 +33,22 @@
 using AstMatrixTest = TestHelper;
 
 TEST_F(AstMatrixTest, Creation) {
-  auto* i32 = create<I32>();
-  auto* m = create<Matrix>(i32, 2, 4);
-  EXPECT_EQ(m->type, i32);
-  EXPECT_EQ(m->rows, 2u);
-  EXPECT_EQ(m->columns, 4u);
+    auto* i32 = create<I32>();
+    auto* m = create<Matrix>(i32, 2, 4);
+    EXPECT_EQ(m->type, i32);
+    EXPECT_EQ(m->rows, 2u);
+    EXPECT_EQ(m->columns, 4u);
 }
 
 TEST_F(AstMatrixTest, FriendlyName) {
-  auto* i32 = create<I32>();
-  auto* m = create<Matrix>(i32, 3, 2);
-  EXPECT_EQ(m->FriendlyName(Symbols()), "mat2x3<i32>");
+    auto* i32 = create<I32>();
+    auto* m = create<Matrix>(i32, 3, 2);
+    EXPECT_EQ(m->FriendlyName(Symbols()), "mat2x3<i32>");
 }
 
 TEST_F(AstMatrixTest, FriendlyName_WithoutType) {
-  auto* m = create<Matrix>(nullptr, 3, 2);
-  EXPECT_EQ(m->FriendlyName(Symbols()), "mat2x3");
+    auto* m = create<Matrix>(nullptr, 3, 2);
+    EXPECT_EQ(m->FriendlyName(Symbols()), "mat2x3");
 }
 
 }  // namespace
diff --git a/src/tint/ast/member_accessor_expression.cc b/src/tint/ast/member_accessor_expression.cc
index 71f1991..a087ea4 100644
--- a/src/tint/ast/member_accessor_expression.cc
+++ b/src/tint/ast/member_accessor_expression.cc
@@ -20,30 +20,27 @@
 
 namespace tint::ast {
 
-MemberAccessorExpression::MemberAccessorExpression(
-    ProgramID pid,
-    const Source& src,
-    const Expression* str,
-    const IdentifierExpression* mem)
+MemberAccessorExpression::MemberAccessorExpression(ProgramID pid,
+                                                   const Source& src,
+                                                   const Expression* str,
+                                                   const IdentifierExpression* mem)
     : Base(pid, src), structure(str), member(mem) {
-  TINT_ASSERT(AST, structure);
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, structure, program_id);
-  TINT_ASSERT(AST, member);
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, member, program_id);
+    TINT_ASSERT(AST, structure);
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, structure, program_id);
+    TINT_ASSERT(AST, member);
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, member, program_id);
 }
 
-MemberAccessorExpression::MemberAccessorExpression(MemberAccessorExpression&&) =
-    default;
+MemberAccessorExpression::MemberAccessorExpression(MemberAccessorExpression&&) = default;
 
 MemberAccessorExpression::~MemberAccessorExpression() = default;
 
-const MemberAccessorExpression* MemberAccessorExpression::Clone(
-    CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  auto* str = ctx->Clone(structure);
-  auto* mem = ctx->Clone(member);
-  return ctx->dst->create<MemberAccessorExpression>(src, str, mem);
+const MemberAccessorExpression* MemberAccessorExpression::Clone(CloneContext* ctx) const {
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    auto* str = ctx->Clone(structure);
+    auto* mem = ctx->Clone(member);
+    return ctx->dst->create<MemberAccessorExpression>(src, str, mem);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/member_accessor_expression.h b/src/tint/ast/member_accessor_expression.h
index 800d018..07054ca 100644
--- a/src/tint/ast/member_accessor_expression.h
+++ b/src/tint/ast/member_accessor_expression.h
@@ -20,33 +20,32 @@
 namespace tint::ast {
 
 /// A member accessor expression
-class MemberAccessorExpression final
-    : public Castable<MemberAccessorExpression, Expression> {
- public:
-  /// Constructor
-  /// @param program_id the identifier of the program that owns this node
-  /// @param source the member accessor expression source
-  /// @param structure the structure
-  /// @param member the member
-  MemberAccessorExpression(ProgramID program_id,
-                           const Source& source,
-                           const Expression* structure,
-                           const IdentifierExpression* member);
-  /// Move constructor
-  MemberAccessorExpression(MemberAccessorExpression&&);
-  ~MemberAccessorExpression() override;
+class MemberAccessorExpression final : public Castable<MemberAccessorExpression, Expression> {
+  public:
+    /// Constructor
+    /// @param program_id the identifier of the program that owns this node
+    /// @param source the member accessor expression source
+    /// @param structure the structure
+    /// @param member the member
+    MemberAccessorExpression(ProgramID program_id,
+                             const Source& source,
+                             const Expression* structure,
+                             const IdentifierExpression* member);
+    /// Move constructor
+    MemberAccessorExpression(MemberAccessorExpression&&);
+    ~MemberAccessorExpression() override;
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const MemberAccessorExpression* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const MemberAccessorExpression* Clone(CloneContext* ctx) const override;
 
-  /// The structure
-  const Expression* const structure;
+    /// The structure
+    const Expression* const structure;
 
-  /// The member expression
-  const IdentifierExpression* const member;
+    /// The member expression
+    const IdentifierExpression* const member;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/member_accessor_expression_test.cc b/src/tint/ast/member_accessor_expression_test.cc
index ed134a0..d56b740 100644
--- a/src/tint/ast/member_accessor_expression_test.cc
+++ b/src/tint/ast/member_accessor_expression_test.cc
@@ -21,66 +21,63 @@
 using MemberAccessorExpressionTest = TestHelper;
 
 TEST_F(MemberAccessorExpressionTest, Creation) {
-  auto* str = Expr("structure");
-  auto* mem = Expr("member");
+    auto* str = Expr("structure");
+    auto* mem = Expr("member");
 
-  auto* stmt = create<MemberAccessorExpression>(str, mem);
-  EXPECT_EQ(stmt->structure, str);
-  EXPECT_EQ(stmt->member, mem);
+    auto* stmt = create<MemberAccessorExpression>(str, mem);
+    EXPECT_EQ(stmt->structure, str);
+    EXPECT_EQ(stmt->member, mem);
 }
 
 TEST_F(MemberAccessorExpressionTest, Creation_WithSource) {
-  auto* stmt = create<MemberAccessorExpression>(
-      Source{Source::Location{20, 2}}, Expr("structure"), Expr("member"));
-  auto src = stmt->source;
-  EXPECT_EQ(src.range.begin.line, 20u);
-  EXPECT_EQ(src.range.begin.column, 2u);
+    auto* stmt = create<MemberAccessorExpression>(Source{Source::Location{20, 2}},
+                                                  Expr("structure"), Expr("member"));
+    auto src = stmt->source;
+    EXPECT_EQ(src.range.begin.line, 20u);
+    EXPECT_EQ(src.range.begin.column, 2u);
 }
 
 TEST_F(MemberAccessorExpressionTest, IsMemberAccessor) {
-  auto* stmt =
-      create<MemberAccessorExpression>(Expr("structure"), Expr("member"));
-  EXPECT_TRUE(stmt->Is<MemberAccessorExpression>());
+    auto* stmt = create<MemberAccessorExpression>(Expr("structure"), Expr("member"));
+    EXPECT_TRUE(stmt->Is<MemberAccessorExpression>());
 }
 
 TEST_F(MemberAccessorExpressionTest, Assert_Null_Struct) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.create<MemberAccessorExpression>(nullptr, b.Expr("member"));
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.create<MemberAccessorExpression>(nullptr, b.Expr("member"));
+        },
+        "internal compiler error");
 }
 
 TEST_F(MemberAccessorExpressionTest, Assert_Null_Member) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.create<MemberAccessorExpression>(b.Expr("struct"), nullptr);
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.create<MemberAccessorExpression>(b.Expr("struct"), nullptr);
+        },
+        "internal compiler error");
 }
 
 TEST_F(MemberAccessorExpressionTest, Assert_DifferentProgramID_Struct) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.create<MemberAccessorExpression>(b2.Expr("structure"),
-                                            b1.Expr("member"));
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.create<MemberAccessorExpression>(b2.Expr("structure"), b1.Expr("member"));
+        },
+        "internal compiler error");
 }
 
 TEST_F(MemberAccessorExpressionTest, Assert_DifferentProgramID_Member) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.create<MemberAccessorExpression>(b1.Expr("structure"),
-                                            b2.Expr("member"));
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.create<MemberAccessorExpression>(b1.Expr("structure"), b2.Expr("member"));
+        },
+        "internal compiler error");
 }
 
 }  // namespace
diff --git a/src/tint/ast/module.cc b/src/tint/ast/module.cc
index 8fd5cae..e163c19 100644
--- a/src/tint/ast/module.cc
+++ b/src/tint/ast/module.cc
@@ -25,101 +25,107 @@
 
 Module::Module(ProgramID pid, const Source& src) : Base(pid, src) {}
 
-Module::Module(ProgramID pid,
-               const Source& src,
-               std::vector<const ast::Node*> global_decls)
+Module::Module(ProgramID pid, const Source& src, std::vector<const ast::Node*> global_decls)
     : Base(pid, src), global_declarations_(std::move(global_decls)) {
-  for (auto* decl : global_declarations_) {
-    if (decl == nullptr) {
-      continue;
+    for (auto* decl : global_declarations_) {
+        if (decl == nullptr) {
+            continue;
+        }
+        diag::List diags;
+        BinGlobalDeclaration(decl, diags);
     }
-    diag::List diags;
-    BinGlobalDeclaration(decl, diags);
-  }
 }
 
 Module::~Module() = default;
 
 const ast::TypeDecl* Module::LookupType(Symbol name) const {
-  for (auto* ty : TypeDecls()) {
-    if (ty->name == name) {
-      return ty;
+    for (auto* ty : TypeDecls()) {
+        if (ty->name == name) {
+            return ty;
+        }
     }
-  }
-  return nullptr;
+    return nullptr;
 }
 
 void Module::AddGlobalDeclaration(const tint::ast::Node* decl) {
-  diag::List diags;
-  BinGlobalDeclaration(decl, diags);
-  global_declarations_.emplace_back(decl);
+    diag::List diags;
+    BinGlobalDeclaration(decl, diags);
+    global_declarations_.emplace_back(decl);
 }
 
-void Module::BinGlobalDeclaration(const tint::ast::Node* decl,
-                                  diag::List& diags) {
-  Switch(
-      decl,  //
-      [&](const ast::TypeDecl* type) {
-        TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, type, program_id);
-        type_decls_.push_back(type);
-      },
-      [&](const Function* func) {
-        TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, func, program_id);
-        functions_.push_back(func);
-      },
-      [&](const Variable* var) {
-        TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, var, program_id);
-        global_variables_.push_back(var);
-      },
-      [&](Default) {
-        TINT_ICE(AST, diags) << "Unknown global declaration type";
-      });
+void Module::BinGlobalDeclaration(const tint::ast::Node* decl, diag::List& diags) {
+    Switch(
+        decl,  //
+        [&](const ast::TypeDecl* type) {
+            TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, type, program_id);
+            type_decls_.push_back(type);
+        },
+        [&](const Function* func) {
+            TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, func, program_id);
+            functions_.push_back(func);
+        },
+        [&](const Variable* var) {
+            TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, var, program_id);
+            global_variables_.push_back(var);
+        },
+        [&](const Enable* ext) {
+            TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, ext, program_id);
+            extensions_.insert(ext->kind);
+        },
+        [&](Default) { TINT_ICE(AST, diags) << "Unknown global declaration type"; });
+}
+
+void Module::AddEnable(const ast::Enable* ext) {
+    TINT_ASSERT(AST, ext);
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, ext, program_id);
+    global_declarations_.push_back(ext);
+    extensions_.insert(ext->kind);
 }
 
 void Module::AddGlobalVariable(const ast::Variable* var) {
-  TINT_ASSERT(AST, var);
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, var, program_id);
-  global_variables_.push_back(var);
-  global_declarations_.push_back(var);
+    TINT_ASSERT(AST, var);
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, var, program_id);
+    global_variables_.push_back(var);
+    global_declarations_.push_back(var);
 }
 
 void Module::AddTypeDecl(const ast::TypeDecl* type) {
-  TINT_ASSERT(AST, type);
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, type, program_id);
-  type_decls_.push_back(type);
-  global_declarations_.push_back(type);
+    TINT_ASSERT(AST, type);
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, type, program_id);
+    type_decls_.push_back(type);
+    global_declarations_.push_back(type);
 }
 
 void Module::AddFunction(const ast::Function* func) {
-  TINT_ASSERT(AST, func);
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, func, program_id);
-  functions_.push_back(func);
-  global_declarations_.push_back(func);
+    TINT_ASSERT(AST, func);
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, func, program_id);
+    functions_.push_back(func);
+    global_declarations_.push_back(func);
 }
 
 const Module* Module::Clone(CloneContext* ctx) const {
-  auto* out = ctx->dst->create<Module>();
-  out->Copy(ctx, this);
-  return out;
+    auto* out = ctx->dst->create<Module>();
+    out->Copy(ctx, this);
+    return out;
 }
 
 void Module::Copy(CloneContext* ctx, const Module* src) {
-  ctx->Clone(global_declarations_, src->global_declarations_);
+    ctx->Clone(global_declarations_, src->global_declarations_);
 
-  // During the clone, declarations may have been placed into the module.
-  // Clear everything out, as we're about to re-bin the declarations.
-  type_decls_.clear();
-  functions_.clear();
-  global_variables_.clear();
+    // During the clone, declarations may have been placed into the module.
+    // Clear everything out, as we're about to re-bin the declarations.
+    type_decls_.clear();
+    functions_.clear();
+    global_variables_.clear();
+    extensions_.clear();
 
-  for (auto* decl : global_declarations_) {
-    if (!decl) {
-      TINT_ICE(AST, ctx->dst->Diagnostics())
-          << "src global declaration was nullptr";
-      continue;
+    for (auto* decl : global_declarations_) {
+        if (!decl) {
+            TINT_ICE(AST, ctx->dst->Diagnostics()) << "src global declaration was nullptr";
+            continue;
+        }
+        BinGlobalDeclaration(decl, ctx->dst->Diagnostics());
     }
-    BinGlobalDeclaration(decl, ctx->dst->Diagnostics());
-  }
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/module.h b/src/tint/ast/module.h
index 03e64d9..d8be2ed 100644
--- a/src/tint/ast/module.h
+++ b/src/tint/ast/module.h
@@ -18,6 +18,7 @@
 #include <string>
 #include <vector>
 
+#include "src/tint/ast/enable.h"
 #include "src/tint/ast/function.h"
 #include "src/tint/ast/type.h"
 
@@ -28,94 +29,98 @@
 /// Module holds the top-level AST types, functions and global variables used by
 /// a Program.
 class Module final : public Castable<Module, Node> {
- public:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  Module(ProgramID pid, const Source& src);
+  public:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    Module(ProgramID pid, const Source& src);
 
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  /// @param global_decls the list of global types, functions, and variables, in
-  /// the order they were declared in the source program
-  Module(ProgramID pid,
-         const Source& src,
-         std::vector<const Node*> global_decls);
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    /// @param global_decls the list of global types, functions, and variables, in
+    /// the order they were declared in the source program
+    Module(ProgramID pid, const Source& src, std::vector<const Node*> global_decls);
 
-  /// Destructor
-  ~Module() override;
+    /// Destructor
+    ~Module() override;
 
-  /// @returns the declaration-ordered global declarations for the module
-  const std::vector<const Node*>& GlobalDeclarations() const {
-    return global_declarations_;
-  }
+    /// @returns the declaration-ordered global declarations for the module
+    const std::vector<const Node*>& GlobalDeclarations() const { return global_declarations_; }
 
-  /// Add a global variable to the Builder
-  /// @param var the variable to add
-  void AddGlobalVariable(const Variable* var);
+    /// Add a enable directive to the Builder
+    /// @param ext the enable directive to add
+    void AddEnable(const Enable* ext);
 
-  /// @returns true if the module has the global declaration `decl`
-  /// @param decl the declaration to check
-  bool HasGlobalDeclaration(Node* decl) const {
-    for (auto* d : global_declarations_) {
-      if (d == decl) {
-        return true;
-      }
+    /// Add a global variable to the Builder
+    /// @param var the variable to add
+    void AddGlobalVariable(const Variable* var);
+
+    /// @returns true if the module has the global declaration `decl`
+    /// @param decl the declaration to check
+    bool HasGlobalDeclaration(Node* decl) const {
+        for (auto* d : global_declarations_) {
+            if (d == decl) {
+                return true;
+            }
+        }
+        return false;
     }
-    return false;
-  }
 
-  /// Adds a global declaration to the Builder.
-  /// @param decl the declaration to add
-  void AddGlobalDeclaration(const tint::ast::Node* decl);
+    /// Adds a global declaration to the Builder.
+    /// @param decl the declaration to add
+    void AddGlobalDeclaration(const tint::ast::Node* decl);
 
-  /// @returns the global variables for the module
-  const VariableList& GlobalVariables() const { return global_variables_; }
+    /// @returns the global variables for the module
+    const VariableList& GlobalVariables() const { return global_variables_; }
 
-  /// @returns the global variables for the module
-  VariableList& GlobalVariables() { return global_variables_; }
+    /// @returns the global variables for the module
+    VariableList& GlobalVariables() { return global_variables_; }
 
-  /// Adds a type declaration to the Builder.
-  /// @param decl the type declaration to add
-  void AddTypeDecl(const TypeDecl* decl);
+    /// @returns the extension set for the module
+    const ExtensionSet& Extensions() const { return extensions_; }
 
-  /// @returns the TypeDecl registered as a TypeDecl()
-  /// @param name the name of the type to search for
-  const TypeDecl* LookupType(Symbol name) const;
+    /// Adds a type declaration to the Builder.
+    /// @param decl the type declaration to add
+    void AddTypeDecl(const TypeDecl* decl);
 
-  /// @returns the declared types in the module
-  const std::vector<const TypeDecl*>& TypeDecls() const { return type_decls_; }
+    /// @returns the TypeDecl registered as a TypeDecl()
+    /// @param name the name of the type to search for
+    const TypeDecl* LookupType(Symbol name) const;
 
-  /// Add a function to the Builder
-  /// @param func the function to add
-  void AddFunction(const Function* func);
+    /// @returns the declared types in the module
+    const std::vector<const TypeDecl*>& TypeDecls() const { return type_decls_; }
 
-  /// @returns the functions declared in the module
-  const FunctionList& Functions() const { return functions_; }
+    /// Add a function to the Builder
+    /// @param func the function to add
+    void AddFunction(const Function* func);
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const Module* Clone(CloneContext* ctx) const override;
+    /// @returns the functions declared in the module
+    const FunctionList& Functions() const { return functions_; }
 
-  /// Copy copies the content of the Module src into this module.
-  /// @param ctx the clone context
-  /// @param src the module to copy into this module
-  void Copy(CloneContext* ctx, const Module* src);
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const Module* Clone(CloneContext* ctx) const override;
 
- private:
-  /// Adds `decl` to either:
-  /// * #global_declarations_
-  /// * #type_decls_
-  /// * #functions_
-  void BinGlobalDeclaration(const tint::ast::Node* decl, diag::List& diags);
+    /// Copy copies the content of the Module src into this module.
+    /// @param ctx the clone context
+    /// @param src the module to copy into this module
+    void Copy(CloneContext* ctx, const Module* src);
 
-  std::vector<const Node*> global_declarations_;
-  std::vector<const TypeDecl*> type_decls_;
-  FunctionList functions_;
-  VariableList global_variables_;
+  private:
+    /// Adds `decl` to either:
+    /// * #global_declarations_
+    /// * #type_decls_
+    /// * #functions_
+    void BinGlobalDeclaration(const tint::ast::Node* decl, diag::List& diags);
+
+    std::vector<const Node*> global_declarations_;
+    std::vector<const TypeDecl*> type_decls_;
+    FunctionList functions_;
+    VariableList global_variables_;
+    ExtensionSet extensions_;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/module_clone_test.cc b/src/tint/ast/module_clone_test.cc
index 3cb900b..65c2406 100644
--- a/src/tint/ast/module_clone_test.cc
+++ b/src/tint/ast/module_clone_test.cc
@@ -23,9 +23,9 @@
 
 TEST(ModuleCloneTest, Clone) {
 #if TINT_BUILD_WGSL_READER && TINT_BUILD_WGSL_WRITER
-  // Shader that exercises the bulk of the AST nodes and types.
-  // See also fuzzers/tint_ast_clone_fuzzer.cc for further coverage of cloning.
-  Source::File file("test.wgsl", R"(struct S0 {
+    // Shader that exercises the bulk of the AST nodes and types.
+    // See also fuzzers/tint_ast_clone_fuzzer.cc for further coverage of cloning.
+    Source::File file("test.wgsl", R"(struct S0 {
   @size(4)
   m0 : u32,
   m1 : array<u32>,
@@ -116,62 +116,62 @@
 
 )");
 
-  // Parse the wgsl, create the src program
-  auto src = reader::wgsl::Parse(&file);
+    // Parse the wgsl, create the src program
+    auto src = reader::wgsl::Parse(&file);
 
-  ASSERT_TRUE(src.IsValid()) << diag::Formatter().format(src.Diagnostics());
+    ASSERT_TRUE(src.IsValid()) << diag::Formatter().format(src.Diagnostics());
 
-  // Clone the src program to dst
-  Program dst(src.Clone());
+    // Clone the src program to dst
+    Program dst(src.Clone());
 
-  ASSERT_TRUE(dst.IsValid()) << diag::Formatter().format(dst.Diagnostics());
+    ASSERT_TRUE(dst.IsValid()) << diag::Formatter().format(dst.Diagnostics());
 
-  // Expect the printed strings to match
-  EXPECT_EQ(Program::printer(&src), Program::printer(&dst));
+    // Expect the printed strings to match
+    EXPECT_EQ(Program::printer(&src), Program::printer(&dst));
 
-  // Check that none of the AST nodes or type pointers in dst are found in src
-  std::unordered_set<const ast::Node*> src_nodes;
-  for (auto* src_node : src.ASTNodes().Objects()) {
-    src_nodes.emplace(src_node);
-  }
-  std::unordered_set<const sem::Type*> src_types;
-  for (auto* src_type : src.Types()) {
-    src_types.emplace(src_type);
-  }
-  for (auto* dst_node : dst.ASTNodes().Objects()) {
-    ASSERT_EQ(src_nodes.count(dst_node), 0u);
-  }
-  for (auto* dst_type : dst.Types()) {
-    ASSERT_EQ(src_types.count(dst_type), 0u);
-  }
+    // Check that none of the AST nodes or type pointers in dst are found in src
+    std::unordered_set<const ast::Node*> src_nodes;
+    for (auto* src_node : src.ASTNodes().Objects()) {
+        src_nodes.emplace(src_node);
+    }
+    std::unordered_set<const sem::Type*> src_types;
+    for (auto* src_type : src.Types()) {
+        src_types.emplace(src_type);
+    }
+    for (auto* dst_node : dst.ASTNodes().Objects()) {
+        ASSERT_EQ(src_nodes.count(dst_node), 0u);
+    }
+    for (auto* dst_type : dst.Types()) {
+        ASSERT_EQ(src_types.count(dst_type), 0u);
+    }
 
-  // Regenerate the wgsl for the src program. We use this instead of the
-  // original source so that reformatting doesn't impact the final wgsl
-  // comparison.
-  writer::wgsl::Options options;
-  std::string src_wgsl;
-  {
-    auto result = writer::wgsl::Generate(&src, options);
-    ASSERT_TRUE(result.success) << result.error;
-    src_wgsl = result.wgsl;
+    // Regenerate the wgsl for the src program. We use this instead of the
+    // original source so that reformatting doesn't impact the final wgsl
+    // comparison.
+    writer::wgsl::Options options;
+    std::string src_wgsl;
+    {
+        auto result = writer::wgsl::Generate(&src, options);
+        ASSERT_TRUE(result.success) << result.error;
+        src_wgsl = result.wgsl;
 
-    // Move the src program to a temporary that'll be dropped, so that the src
-    // program is released before we attempt to print the dst program. This
-    // guarantee that all the source program nodes and types are destructed and
-    // freed. ASAN should error if there's any remaining references in dst when
-    // we try to reconstruct the WGSL.
-    auto tmp = std::move(src);
-  }
+        // Move the src program to a temporary that'll be dropped, so that the src
+        // program is released before we attempt to print the dst program. This
+        // guarantee that all the source program nodes and types are destructed and
+        // freed. ASAN should error if there's any remaining references in dst when
+        // we try to reconstruct the WGSL.
+        auto tmp = std::move(src);
+    }
 
-  // Print the dst module, check it matches the original source
-  auto result = writer::wgsl::Generate(&dst, options);
-  ASSERT_TRUE(result.success);
-  auto dst_wgsl = result.wgsl;
-  ASSERT_EQ(src_wgsl, dst_wgsl);
+    // Print the dst module, check it matches the original source
+    auto result = writer::wgsl::Generate(&dst, options);
+    ASSERT_TRUE(result.success);
+    auto dst_wgsl = result.wgsl;
+    ASSERT_EQ(src_wgsl, dst_wgsl);
 
 #else  // #if TINT_BUILD_WGSL_READER && TINT_BUILD_WGSL_WRITER
-  GTEST_SKIP() << "ModuleCloneTest requires TINT_BUILD_WGSL_READER and "
-                  "TINT_BUILD_WGSL_WRITER to be enabled";
+    GTEST_SKIP() << "ModuleCloneTest requires TINT_BUILD_WGSL_READER and "
+                    "TINT_BUILD_WGSL_WRITER to be enabled";
 #endif
 }
 
diff --git a/src/tint/ast/module_test.cc b/src/tint/ast/module_test.cc
index 0d65509..6ac610e 100644
--- a/src/tint/ast/module_test.cc
+++ b/src/tint/ast/module_test.cc
@@ -22,119 +22,112 @@
 using ModuleTest = TestHelper;
 
 TEST_F(ModuleTest, Creation) {
-  EXPECT_EQ(Program(std::move(*this)).AST().Functions().size(), 0u);
+    EXPECT_EQ(Program(std::move(*this)).AST().Functions().size(), 0u);
 }
 
 TEST_F(ModuleTest, LookupFunction) {
-  auto* func = Func("main", VariableList{}, ty.f32(), StatementList{},
-                    ast::AttributeList{});
+    auto* func = Func("main", VariableList{}, ty.f32(), StatementList{}, ast::AttributeList{});
 
-  Program program(std::move(*this));
-  EXPECT_EQ(func,
-            program.AST().Functions().Find(program.Symbols().Get("main")));
+    Program program(std::move(*this));
+    EXPECT_EQ(func, program.AST().Functions().Find(program.Symbols().Get("main")));
 }
 
 TEST_F(ModuleTest, LookupFunctionMissing) {
-  Program program(std::move(*this));
-  EXPECT_EQ(nullptr,
-            program.AST().Functions().Find(program.Symbols().Get("Missing")));
+    Program program(std::move(*this));
+    EXPECT_EQ(nullptr, program.AST().Functions().Find(program.Symbols().Get("Missing")));
 }
 
 TEST_F(ModuleTest, Assert_Null_GlobalVariable) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder builder;
-        builder.AST().AddGlobalVariable(nullptr);
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder builder;
+            builder.AST().AddGlobalVariable(nullptr);
+        },
+        "internal compiler error");
 }
 
 TEST_F(ModuleTest, Assert_Null_TypeDecl) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder builder;
-        builder.AST().AddTypeDecl(nullptr);
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder builder;
+            builder.AST().AddTypeDecl(nullptr);
+        },
+        "internal compiler error");
 }
 
 TEST_F(ModuleTest, Assert_DifferentProgramID_Function) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.AST().AddFunction(b2.create<ast::Function>(
-            b2.Symbols().Register("func"), VariableList{}, b2.ty.f32(),
-            b2.Block(), AttributeList{}, AttributeList{}));
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.AST().AddFunction(b2.create<ast::Function>(b2.Symbols().Register("func"),
+                                                          VariableList{}, b2.ty.f32(), b2.Block(),
+                                                          AttributeList{}, AttributeList{}));
+        },
+        "internal compiler error");
 }
 
 TEST_F(ModuleTest, Assert_DifferentProgramID_GlobalVariable) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.AST().AddGlobalVariable(
-            b2.Var("var", b2.ty.i32(), ast::StorageClass::kPrivate));
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.AST().AddGlobalVariable(b2.Var("var", b2.ty.i32(), ast::StorageClass::kPrivate));
+        },
+        "internal compiler error");
 }
 
 TEST_F(ModuleTest, Assert_Null_Function) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder builder;
-        builder.AST().AddFunction(nullptr);
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder builder;
+            builder.AST().AddFunction(nullptr);
+        },
+        "internal compiler error");
 }
 
 TEST_F(ModuleTest, CloneOrder) {
-  // Create a program with a function, alias decl and var decl.
-  Program p = [] {
-    ProgramBuilder b;
-    b.Func("F", {}, b.ty.void_(), {});
-    b.Alias("A", b.ty.u32());
-    b.Global("V", b.ty.i32(), ast::StorageClass::kPrivate);
-    return Program(std::move(b));
-  }();
+    // Create a program with a function, alias decl and var decl.
+    Program p = [] {
+        ProgramBuilder b;
+        b.Func("F", {}, b.ty.void_(), {});
+        b.Alias("A", b.ty.u32());
+        b.Global("V", b.ty.i32(), ast::StorageClass::kPrivate);
+        return Program(std::move(b));
+    }();
 
-  // Clone the program, using ReplaceAll() to create new module-scope
-  // declarations. We want to test that these are added just before the
-  // declaration that triggered the ReplaceAll().
-  ProgramBuilder cloned;
-  CloneContext ctx(&cloned, &p);
-  ctx.ReplaceAll([&](const ast::Function*) -> const ast::Function* {
-    ctx.dst->Alias("inserted_before_F", cloned.ty.u32());
-    return nullptr;
-  });
-  ctx.ReplaceAll([&](const ast::Alias*) -> const ast::Alias* {
-    ctx.dst->Alias("inserted_before_A", cloned.ty.u32());
-    return nullptr;
-  });
-  ctx.ReplaceAll([&](const ast::Variable*) -> const ast::Variable* {
-    ctx.dst->Alias("inserted_before_V", cloned.ty.u32());
-    return nullptr;
-  });
-  ctx.Clone();
+    // Clone the program, using ReplaceAll() to create new module-scope
+    // declarations. We want to test that these are added just before the
+    // declaration that triggered the ReplaceAll().
+    ProgramBuilder cloned;
+    CloneContext ctx(&cloned, &p);
+    ctx.ReplaceAll([&](const ast::Function*) -> const ast::Function* {
+        ctx.dst->Alias("inserted_before_F", cloned.ty.u32());
+        return nullptr;
+    });
+    ctx.ReplaceAll([&](const ast::Alias*) -> const ast::Alias* {
+        ctx.dst->Alias("inserted_before_A", cloned.ty.u32());
+        return nullptr;
+    });
+    ctx.ReplaceAll([&](const ast::Variable*) -> const ast::Variable* {
+        ctx.dst->Alias("inserted_before_V", cloned.ty.u32());
+        return nullptr;
+    });
+    ctx.Clone();
 
-  auto& decls = cloned.AST().GlobalDeclarations();
-  ASSERT_EQ(decls.size(), 6u);
-  EXPECT_TRUE(decls[1]->Is<ast::Function>());
-  EXPECT_TRUE(decls[3]->Is<ast::Alias>());
-  EXPECT_TRUE(decls[5]->Is<ast::Variable>());
+    auto& decls = cloned.AST().GlobalDeclarations();
+    ASSERT_EQ(decls.size(), 6u);
+    EXPECT_TRUE(decls[1]->Is<ast::Function>());
+    EXPECT_TRUE(decls[3]->Is<ast::Alias>());
+    EXPECT_TRUE(decls[5]->Is<ast::Variable>());
 
-  ASSERT_TRUE(decls[0]->Is<ast::Alias>());
-  ASSERT_TRUE(decls[2]->Is<ast::Alias>());
-  ASSERT_TRUE(decls[4]->Is<ast::Alias>());
+    ASSERT_TRUE(decls[0]->Is<ast::Alias>());
+    ASSERT_TRUE(decls[2]->Is<ast::Alias>());
+    ASSERT_TRUE(decls[4]->Is<ast::Alias>());
 
-  ASSERT_EQ(cloned.Symbols().NameFor(decls[0]->As<ast::Alias>()->name),
-            "inserted_before_F");
-  ASSERT_EQ(cloned.Symbols().NameFor(decls[2]->As<ast::Alias>()->name),
-            "inserted_before_A");
-  ASSERT_EQ(cloned.Symbols().NameFor(decls[4]->As<ast::Alias>()->name),
-            "inserted_before_V");
+    ASSERT_EQ(cloned.Symbols().NameFor(decls[0]->As<ast::Alias>()->name), "inserted_before_F");
+    ASSERT_EQ(cloned.Symbols().NameFor(decls[2]->As<ast::Alias>()->name), "inserted_before_A");
+    ASSERT_EQ(cloned.Symbols().NameFor(decls[4]->As<ast::Alias>()->name), "inserted_before_V");
 }
 
 }  // namespace
diff --git a/src/tint/ast/multisampled_texture.cc b/src/tint/ast/multisampled_texture.cc
index fd5fc59..91f8edf 100644
--- a/src/tint/ast/multisampled_texture.cc
+++ b/src/tint/ast/multisampled_texture.cc
@@ -25,26 +25,24 @@
                                          TextureDimension d,
                                          const Type* ty)
     : Base(pid, src, d), type(ty) {
-  TINT_ASSERT(AST, type);
+    TINT_ASSERT(AST, type);
 }
 
 MultisampledTexture::MultisampledTexture(MultisampledTexture&&) = default;
 
 MultisampledTexture::~MultisampledTexture() = default;
 
-std::string MultisampledTexture::FriendlyName(
-    const SymbolTable& symbols) const {
-  std::ostringstream out;
-  out << "texture_multisampled_" << dim << "<" << type->FriendlyName(symbols)
-      << ">";
-  return out.str();
+std::string MultisampledTexture::FriendlyName(const SymbolTable& symbols) const {
+    std::ostringstream out;
+    out << "texture_multisampled_" << dim << "<" << type->FriendlyName(symbols) << ">";
+    return out.str();
 }
 
 const MultisampledTexture* MultisampledTexture::Clone(CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  auto* ty = ctx->Clone(type);
-  return ctx->dst->create<MultisampledTexture>(src, dim, ty);
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    auto* ty = ctx->Clone(type);
+    return ctx->dst->create<MultisampledTexture>(src, dim, ty);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/multisampled_texture.h b/src/tint/ast/multisampled_texture.h
index 9214124..1d95505 100644
--- a/src/tint/ast/multisampled_texture.h
+++ b/src/tint/ast/multisampled_texture.h
@@ -22,34 +22,30 @@
 namespace tint::ast {
 
 /// A multisampled texture type.
-class MultisampledTexture final
-    : public Castable<MultisampledTexture, Texture> {
- public:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  /// @param dim the dimensionality of the texture
-  /// @param type the data type of the multisampled texture
-  MultisampledTexture(ProgramID pid,
-                      const Source& src,
-                      TextureDimension dim,
-                      const Type* type);
-  /// Move constructor
-  MultisampledTexture(MultisampledTexture&&);
-  ~MultisampledTexture() override;
+class MultisampledTexture final : public Castable<MultisampledTexture, Texture> {
+  public:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    /// @param dim the dimensionality of the texture
+    /// @param type the data type of the multisampled texture
+    MultisampledTexture(ProgramID pid, const Source& src, TextureDimension dim, const Type* type);
+    /// Move constructor
+    MultisampledTexture(MultisampledTexture&&);
+    ~MultisampledTexture() override;
 
-  /// @param symbols the program's symbol table
-  /// @returns the name for this type that closely resembles how it would be
-  /// declared in WGSL.
-  std::string FriendlyName(const SymbolTable& symbols) const override;
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type that closely resembles how it would be
+    /// declared in WGSL.
+    std::string FriendlyName(const SymbolTable& symbols) const override;
 
-  /// Clones this type and all transitive types using the `CloneContext` `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned type
-  const MultisampledTexture* Clone(CloneContext* ctx) const override;
+    /// Clones this type and all transitive types using the `CloneContext` `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned type
+    const MultisampledTexture* Clone(CloneContext* ctx) const override;
 
-  /// The subtype of the multisampled texture
-  const Type* const type;
+    /// The subtype of the multisampled texture
+    const Type* const type;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/multisampled_texture_test.cc b/src/tint/ast/multisampled_texture_test.cc
index 14b3252..bc3b87f 100644
--- a/src/tint/ast/multisampled_texture_test.cc
+++ b/src/tint/ast/multisampled_texture_test.cc
@@ -38,30 +38,30 @@
 using AstMultisampledTextureTest = TestHelper;
 
 TEST_F(AstMultisampledTextureTest, IsTexture) {
-  auto* f32 = create<F32>();
-  Texture* ty = create<MultisampledTexture>(TextureDimension::kCube, f32);
-  EXPECT_FALSE(ty->Is<DepthTexture>());
-  EXPECT_TRUE(ty->Is<MultisampledTexture>());
-  EXPECT_FALSE(ty->Is<SampledTexture>());
-  EXPECT_FALSE(ty->Is<StorageTexture>());
+    auto* f32 = create<F32>();
+    Texture* ty = create<MultisampledTexture>(TextureDimension::kCube, f32);
+    EXPECT_FALSE(ty->Is<DepthTexture>());
+    EXPECT_TRUE(ty->Is<MultisampledTexture>());
+    EXPECT_FALSE(ty->Is<SampledTexture>());
+    EXPECT_FALSE(ty->Is<StorageTexture>());
 }
 
 TEST_F(AstMultisampledTextureTest, Dim) {
-  auto* f32 = create<F32>();
-  auto* s = create<MultisampledTexture>(TextureDimension::k3d, f32);
-  EXPECT_EQ(s->dim, TextureDimension::k3d);
+    auto* f32 = create<F32>();
+    auto* s = create<MultisampledTexture>(TextureDimension::k3d, f32);
+    EXPECT_EQ(s->dim, TextureDimension::k3d);
 }
 
 TEST_F(AstMultisampledTextureTest, Type) {
-  auto* f32 = create<F32>();
-  auto* s = create<MultisampledTexture>(TextureDimension::k3d, f32);
-  EXPECT_EQ(s->type, f32);
+    auto* f32 = create<F32>();
+    auto* s = create<MultisampledTexture>(TextureDimension::k3d, f32);
+    EXPECT_EQ(s->type, f32);
 }
 
 TEST_F(AstMultisampledTextureTest, FriendlyName) {
-  auto* f32 = create<F32>();
-  auto* s = create<MultisampledTexture>(TextureDimension::k3d, f32);
-  EXPECT_EQ(s->FriendlyName(Symbols()), "texture_multisampled_3d<f32>");
+    auto* f32 = create<F32>();
+    auto* s = create<MultisampledTexture>(TextureDimension::k3d, f32);
+    EXPECT_EQ(s->FriendlyName(Symbols()), "texture_multisampled_3d<f32>");
 }
 
 }  // namespace
diff --git a/src/tint/ast/node.h b/src/tint/ast/node.h
index 90699ad..41eeefe 100644
--- a/src/tint/ast/node.h
+++ b/src/tint/ast/node.h
@@ -32,25 +32,25 @@
 
 /// AST base class node
 class Node : public Castable<Node, Cloneable> {
- public:
-  ~Node() override;
+  public:
+    ~Node() override;
 
-  /// The identifier of the program that owns this node
-  const ProgramID program_id;
+    /// The identifier of the program that owns this node
+    const ProgramID program_id;
 
-  /// The node source data
-  const Source source;
+    /// The node source data
+    const Source source;
 
- protected:
-  /// Create a new node
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the input source for the node
-  Node(ProgramID pid, const Source& src);
-  /// Move constructor
-  Node(Node&&);
+  protected:
+    /// Create a new node
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the input source for the node
+    Node(ProgramID pid, const Source& src);
+    /// Move constructor
+    Node(Node&&);
 
- private:
-  Node(const Node&) = delete;
+  private:
+    Node(const Node&) = delete;
 };
 
 }  // namespace tint::ast
@@ -60,7 +60,7 @@
 /// @param node a pointer to an AST node
 /// @returns the ProgramID of the given AST node.
 inline ProgramID ProgramIDOf(const ast::Node* node) {
-  return node ? node->program_id : ProgramID();
+    return node ? node->program_id : ProgramID();
 }
 
 }  // namespace tint
diff --git a/src/tint/ast/phony_expression.cc b/src/tint/ast/phony_expression.cc
index eb52063..a3fd4fd 100644
--- a/src/tint/ast/phony_expression.cc
+++ b/src/tint/ast/phony_expression.cc
@@ -20,17 +20,16 @@
 
 namespace tint::ast {
 
-PhonyExpression::PhonyExpression(ProgramID pid, const Source& src)
-    : Base(pid, src) {}
+PhonyExpression::PhonyExpression(ProgramID pid, const Source& src) : Base(pid, src) {}
 
 PhonyExpression::PhonyExpression(PhonyExpression&&) = default;
 
 PhonyExpression::~PhonyExpression() = default;
 
 const PhonyExpression* PhonyExpression::Clone(CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  return ctx->dst->create<PhonyExpression>(src);
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    return ctx->dst->create<PhonyExpression>(src);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/phony_expression.h b/src/tint/ast/phony_expression.h
index b6012b0..4fc32dd 100644
--- a/src/tint/ast/phony_expression.h
+++ b/src/tint/ast/phony_expression.h
@@ -22,20 +22,20 @@
 /// Represents the `_` of a phony assignment `_ = <expr>`
 /// @see https://www.w3.org/TR/WGSL/#phony-assignment-section
 class PhonyExpression final : public Castable<PhonyExpression, Expression> {
- public:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  PhonyExpression(ProgramID pid, const Source& src);
-  /// Move constructor
-  PhonyExpression(PhonyExpression&&);
-  ~PhonyExpression() override;
+  public:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    PhonyExpression(ProgramID pid, const Source& src);
+    /// Move constructor
+    PhonyExpression(PhonyExpression&&);
+    ~PhonyExpression() override;
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const PhonyExpression* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const PhonyExpression* Clone(CloneContext* ctx) const override;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/phony_expression_test.cc b/src/tint/ast/phony_expression_test.cc
index f15b2ff..8a4dd23 100644
--- a/src/tint/ast/phony_expression_test.cc
+++ b/src/tint/ast/phony_expression_test.cc
@@ -20,20 +20,20 @@
 using IdentifierExpressionTest = TestHelper;
 
 TEST_F(IdentifierExpressionTest, Creation) {
-  EXPECT_NE(Phony(), nullptr);
+    EXPECT_NE(Phony(), nullptr);
 }
 
 TEST_F(IdentifierExpressionTest, Creation_WithSource) {
-  auto* p = Phony(Source{{20, 2}});
+    auto* p = Phony(Source{{20, 2}});
 
-  auto src = p->source;
-  EXPECT_EQ(src.range.begin.line, 20u);
-  EXPECT_EQ(src.range.begin.column, 2u);
+    auto src = p->source;
+    EXPECT_EQ(src.range.begin.line, 20u);
+    EXPECT_EQ(src.range.begin.column, 2u);
 }
 
 TEST_F(IdentifierExpressionTest, IsPhony) {
-  auto* p = Phony();
-  EXPECT_TRUE(p->Is<PhonyExpression>());
+    auto* p = Phony();
+    EXPECT_TRUE(p->Is<PhonyExpression>());
 }
 
 }  // namespace
diff --git a/src/tint/ast/pipeline_stage.cc b/src/tint/ast/pipeline_stage.cc
index fc604a1..79157da 100644
--- a/src/tint/ast/pipeline_stage.cc
+++ b/src/tint/ast/pipeline_stage.cc
@@ -17,25 +17,25 @@
 namespace tint::ast {
 
 std::ostream& operator<<(std::ostream& out, PipelineStage stage) {
-  switch (stage) {
-    case PipelineStage::kNone: {
-      out << "none";
-      break;
+    switch (stage) {
+        case PipelineStage::kNone: {
+            out << "none";
+            break;
+        }
+        case PipelineStage::kVertex: {
+            out << "vertex";
+            break;
+        }
+        case PipelineStage::kFragment: {
+            out << "fragment";
+            break;
+        }
+        case PipelineStage::kCompute: {
+            out << "compute";
+            break;
+        }
     }
-    case PipelineStage::kVertex: {
-      out << "vertex";
-      break;
-    }
-    case PipelineStage::kFragment: {
-      out << "fragment";
-      break;
-    }
-    case PipelineStage::kCompute: {
-      out << "compute";
-      break;
-    }
-  }
-  return out;
+    return out;
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/pointer.cc b/src/tint/ast/pointer.cc
index 74b1da7..42c3fa9 100644
--- a/src/tint/ast/pointer.cc
+++ b/src/tint/ast/pointer.cc
@@ -28,17 +28,17 @@
     : Base(pid, src), type(subtype), storage_class(sc), access(ac) {}
 
 std::string Pointer::FriendlyName(const SymbolTable& symbols) const {
-  std::ostringstream out;
-  out << "ptr<";
-  if (storage_class != ast::StorageClass::kNone) {
-    out << storage_class << ", ";
-  }
-  out << type->FriendlyName(symbols);
-  if (access != ast::Access::kUndefined) {
-    out << ", " << access;
-  }
-  out << ">";
-  return out.str();
+    std::ostringstream out;
+    out << "ptr<";
+    if (storage_class != ast::StorageClass::kNone) {
+        out << storage_class << ", ";
+    }
+    out << type->FriendlyName(symbols);
+    if (access != ast::Access::kUndefined) {
+        out << ", " << access;
+    }
+    out << ">";
+    return out.str();
 }
 
 Pointer::Pointer(Pointer&&) = default;
@@ -46,10 +46,10 @@
 Pointer::~Pointer() = default;
 
 const Pointer* Pointer::Clone(CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  auto* ty = ctx->Clone(type);
-  return ctx->dst->create<Pointer>(src, ty, storage_class, access);
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    auto* ty = ctx->Clone(type);
+    return ctx->dst->create<Pointer>(src, ty, storage_class, access);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/pointer.h b/src/tint/ast/pointer.h
index 9742e78..030e844 100644
--- a/src/tint/ast/pointer.h
+++ b/src/tint/ast/pointer.h
@@ -25,40 +25,40 @@
 
 /// A pointer type.
 class Pointer final : public Castable<Pointer, Type> {
- public:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  /// @param subtype the pointee type
-  /// @param storage_class the storage class of the pointer
-  /// @param access the access control of the pointer
-  Pointer(ProgramID pid,
-          const Source& src,
-          const Type* const subtype,
-          ast::StorageClass storage_class,
-          ast::Access access);
-  /// Move constructor
-  Pointer(Pointer&&);
-  ~Pointer() override;
+  public:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    /// @param subtype the pointee type
+    /// @param storage_class the storage class of the pointer
+    /// @param access the access control of the pointer
+    Pointer(ProgramID pid,
+            const Source& src,
+            const Type* const subtype,
+            ast::StorageClass storage_class,
+            ast::Access access);
+    /// Move constructor
+    Pointer(Pointer&&);
+    ~Pointer() override;
 
-  /// @param symbols the program's symbol table
-  /// @returns the name for this type that closely resembles how it would be
-  /// declared in WGSL.
-  std::string FriendlyName(const SymbolTable& symbols) const override;
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type that closely resembles how it would be
+    /// declared in WGSL.
+    std::string FriendlyName(const SymbolTable& symbols) const override;
 
-  /// Clones this type and all transitive types using the `CloneContext` `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned type
-  const Pointer* Clone(CloneContext* ctx) const override;
+    /// Clones this type and all transitive types using the `CloneContext` `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned type
+    const Pointer* Clone(CloneContext* ctx) const override;
 
-  /// The pointee type
-  const Type* const type;
+    /// The pointee type
+    const Type* const type;
 
-  /// The storage class of the pointer
-  ast::StorageClass const storage_class;
+    /// The storage class of the pointer
+    ast::StorageClass const storage_class;
 
-  /// The access control of the pointer
-  ast::Access const access;
+    /// The access control of the pointer
+    ast::Access const access;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/pointer_test.cc b/src/tint/ast/pointer_test.cc
index c755e1e..dbfd3b0 100644
--- a/src/tint/ast/pointer_test.cc
+++ b/src/tint/ast/pointer_test.cc
@@ -23,25 +23,23 @@
 using AstPointerTest = TestHelper;
 
 TEST_F(AstPointerTest, Creation) {
-  auto* i32 = create<I32>();
-  auto* p = create<Pointer>(i32, ast::StorageClass::kStorage, Access::kRead);
-  EXPECT_EQ(p->type, i32);
-  EXPECT_EQ(p->storage_class, ast::StorageClass::kStorage);
-  EXPECT_EQ(p->access, Access::kRead);
+    auto* i32 = create<I32>();
+    auto* p = create<Pointer>(i32, ast::StorageClass::kStorage, Access::kRead);
+    EXPECT_EQ(p->type, i32);
+    EXPECT_EQ(p->storage_class, ast::StorageClass::kStorage);
+    EXPECT_EQ(p->access, Access::kRead);
 }
 
 TEST_F(AstPointerTest, FriendlyName) {
-  auto* i32 = create<I32>();
-  auto* p =
-      create<Pointer>(i32, ast::StorageClass::kWorkgroup, Access::kUndefined);
-  EXPECT_EQ(p->FriendlyName(Symbols()), "ptr<workgroup, i32>");
+    auto* i32 = create<I32>();
+    auto* p = create<Pointer>(i32, ast::StorageClass::kWorkgroup, Access::kUndefined);
+    EXPECT_EQ(p->FriendlyName(Symbols()), "ptr<workgroup, i32>");
 }
 
 TEST_F(AstPointerTest, FriendlyNameWithAccess) {
-  auto* i32 = create<I32>();
-  auto* p =
-      create<Pointer>(i32, ast::StorageClass::kStorage, Access::kReadWrite);
-  EXPECT_EQ(p->FriendlyName(Symbols()), "ptr<storage, i32, read_write>");
+    auto* i32 = create<I32>();
+    auto* p = create<Pointer>(i32, ast::StorageClass::kStorage, Access::kReadWrite);
+    EXPECT_EQ(p->FriendlyName(Symbols()), "ptr<storage, i32, read_write>");
 }
 
 }  // namespace
diff --git a/src/tint/ast/return_statement.cc b/src/tint/ast/return_statement.cc
index 0adbecb..976c063 100644
--- a/src/tint/ast/return_statement.cc
+++ b/src/tint/ast/return_statement.cc
@@ -23,11 +23,9 @@
 ReturnStatement::ReturnStatement(ProgramID pid, const Source& src)
     : Base(pid, src), value(nullptr) {}
 
-ReturnStatement::ReturnStatement(ProgramID pid,
-                                 const Source& src,
-                                 const Expression* val)
+ReturnStatement::ReturnStatement(ProgramID pid, const Source& src, const Expression* val)
     : Base(pid, src), value(val) {
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, value, program_id);
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, value, program_id);
 }
 
 ReturnStatement::ReturnStatement(ReturnStatement&&) = default;
@@ -35,10 +33,10 @@
 ReturnStatement::~ReturnStatement() = default;
 
 const ReturnStatement* ReturnStatement::Clone(CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  auto* ret = ctx->Clone(value);
-  return ctx->dst->create<ReturnStatement>(src, ret);
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    auto* ret = ctx->Clone(value);
+    return ctx->dst->create<ReturnStatement>(src, ret);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/return_statement.h b/src/tint/ast/return_statement.h
index d43874c..34d8678 100644
--- a/src/tint/ast/return_statement.h
+++ b/src/tint/ast/return_statement.h
@@ -22,29 +22,29 @@
 
 /// A return statement
 class ReturnStatement final : public Castable<ReturnStatement, Statement> {
- public:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  ReturnStatement(ProgramID pid, const Source& src);
+  public:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    ReturnStatement(ProgramID pid, const Source& src);
 
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  /// @param value the return value
-  ReturnStatement(ProgramID pid, const Source& src, const Expression* value);
-  /// Move constructor
-  ReturnStatement(ReturnStatement&&);
-  ~ReturnStatement() override;
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    /// @param value the return value
+    ReturnStatement(ProgramID pid, const Source& src, const Expression* value);
+    /// Move constructor
+    ReturnStatement(ReturnStatement&&);
+    ~ReturnStatement() override;
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const ReturnStatement* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const ReturnStatement* Clone(CloneContext* ctx) const override;
 
-  /// The value returned. May be null.
-  const Expression* const value;
+    /// The value returned. May be null.
+    const Expression* const value;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/return_statement_test.cc b/src/tint/ast/return_statement_test.cc
index d17a89d..bbe860d 100644
--- a/src/tint/ast/return_statement_test.cc
+++ b/src/tint/ast/return_statement_test.cc
@@ -23,43 +23,43 @@
 using ReturnStatementTest = TestHelper;
 
 TEST_F(ReturnStatementTest, Creation) {
-  auto* expr = Expr("expr");
+    auto* expr = Expr("expr");
 
-  auto* r = create<ReturnStatement>(expr);
-  EXPECT_EQ(r->value, expr);
+    auto* r = create<ReturnStatement>(expr);
+    EXPECT_EQ(r->value, expr);
 }
 
 TEST_F(ReturnStatementTest, Creation_WithSource) {
-  auto* r = create<ReturnStatement>(Source{Source::Location{20, 2}});
-  auto src = r->source;
-  EXPECT_EQ(src.range.begin.line, 20u);
-  EXPECT_EQ(src.range.begin.column, 2u);
+    auto* r = create<ReturnStatement>(Source{Source::Location{20, 2}});
+    auto src = r->source;
+    EXPECT_EQ(src.range.begin.line, 20u);
+    EXPECT_EQ(src.range.begin.column, 2u);
 }
 
 TEST_F(ReturnStatementTest, IsReturn) {
-  auto* r = create<ReturnStatement>();
-  EXPECT_TRUE(r->Is<ReturnStatement>());
+    auto* r = create<ReturnStatement>();
+    EXPECT_TRUE(r->Is<ReturnStatement>());
 }
 
 TEST_F(ReturnStatementTest, WithoutValue) {
-  auto* r = create<ReturnStatement>();
-  EXPECT_EQ(r->value, nullptr);
+    auto* r = create<ReturnStatement>();
+    EXPECT_EQ(r->value, nullptr);
 }
 
 TEST_F(ReturnStatementTest, WithValue) {
-  auto* expr = Expr("expr");
-  auto* r = create<ReturnStatement>(expr);
-  EXPECT_NE(r->value, nullptr);
+    auto* expr = Expr("expr");
+    auto* r = create<ReturnStatement>(expr);
+    EXPECT_NE(r->value, nullptr);
 }
 
 TEST_F(ReturnStatementTest, Assert_DifferentProgramID_Expr) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.create<ReturnStatement>(b2.Expr(true));
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.create<ReturnStatement>(b2.Expr(true));
+        },
+        "internal compiler error");
 }
 
 }  // namespace
diff --git a/src/tint/ast/sampled_texture.cc b/src/tint/ast/sampled_texture.cc
index 21cb0f5..9c4cea6 100644
--- a/src/tint/ast/sampled_texture.cc
+++ b/src/tint/ast/sampled_texture.cc
@@ -20,12 +20,9 @@
 
 namespace tint::ast {
 
-SampledTexture::SampledTexture(ProgramID pid,
-                               const Source& src,
-                               TextureDimension d,
-                               const Type* ty)
+SampledTexture::SampledTexture(ProgramID pid, const Source& src, TextureDimension d, const Type* ty)
     : Base(pid, src, d), type(ty) {
-  TINT_ASSERT(AST, type);
+    TINT_ASSERT(AST, type);
 }
 
 SampledTexture::SampledTexture(SampledTexture&&) = default;
@@ -33,16 +30,16 @@
 SampledTexture::~SampledTexture() = default;
 
 std::string SampledTexture::FriendlyName(const SymbolTable& symbols) const {
-  std::ostringstream out;
-  out << "texture_" << dim << "<" << type->FriendlyName(symbols) << ">";
-  return out.str();
+    std::ostringstream out;
+    out << "texture_" << dim << "<" << type->FriendlyName(symbols) << ">";
+    return out.str();
 }
 
 const SampledTexture* SampledTexture::Clone(CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  auto* ty = ctx->Clone(type);
-  return ctx->dst->create<SampledTexture>(src, dim, ty);
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    auto* ty = ctx->Clone(type);
+    return ctx->dst->create<SampledTexture>(src, dim, ty);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/sampled_texture.h b/src/tint/ast/sampled_texture.h
index d7c28f5..f68fccf 100644
--- a/src/tint/ast/sampled_texture.h
+++ b/src/tint/ast/sampled_texture.h
@@ -23,32 +23,29 @@
 
 /// A sampled texture type.
 class SampledTexture final : public Castable<SampledTexture, Texture> {
- public:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  /// @param dim the dimensionality of the texture
-  /// @param type the data type of the sampled texture
-  SampledTexture(ProgramID pid,
-                 const Source& src,
-                 TextureDimension dim,
-                 const Type* type);
-  /// Move constructor
-  SampledTexture(SampledTexture&&);
-  ~SampledTexture() override;
+  public:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    /// @param dim the dimensionality of the texture
+    /// @param type the data type of the sampled texture
+    SampledTexture(ProgramID pid, const Source& src, TextureDimension dim, const Type* type);
+    /// Move constructor
+    SampledTexture(SampledTexture&&);
+    ~SampledTexture() override;
 
-  /// @param symbols the program's symbol table
-  /// @returns the name for this type that closely resembles how it would be
-  /// declared in WGSL.
-  std::string FriendlyName(const SymbolTable& symbols) const override;
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type that closely resembles how it would be
+    /// declared in WGSL.
+    std::string FriendlyName(const SymbolTable& symbols) const override;
 
-  /// Clones this type and all transitive types using the `CloneContext` `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned type
-  const SampledTexture* Clone(CloneContext* ctx) const override;
+    /// Clones this type and all transitive types using the `CloneContext` `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned type
+    const SampledTexture* Clone(CloneContext* ctx) const override;
 
-  /// The subtype of the sampled texture
-  const Type* const type;
+    /// The subtype of the sampled texture
+    const Type* const type;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/sampled_texture_test.cc b/src/tint/ast/sampled_texture_test.cc
index d89ff96..f85d2df 100644
--- a/src/tint/ast/sampled_texture_test.cc
+++ b/src/tint/ast/sampled_texture_test.cc
@@ -23,29 +23,29 @@
 using AstSampledTextureTest = TestHelper;
 
 TEST_F(AstSampledTextureTest, IsTexture) {
-  auto* f32 = create<F32>();
-  Texture* ty = create<SampledTexture>(TextureDimension::kCube, f32);
-  EXPECT_FALSE(ty->Is<DepthTexture>());
-  EXPECT_TRUE(ty->Is<SampledTexture>());
-  EXPECT_FALSE(ty->Is<StorageTexture>());
+    auto* f32 = create<F32>();
+    Texture* ty = create<SampledTexture>(TextureDimension::kCube, f32);
+    EXPECT_FALSE(ty->Is<DepthTexture>());
+    EXPECT_TRUE(ty->Is<SampledTexture>());
+    EXPECT_FALSE(ty->Is<StorageTexture>());
 }
 
 TEST_F(AstSampledTextureTest, Dim) {
-  auto* f32 = create<F32>();
-  auto* s = create<SampledTexture>(TextureDimension::k3d, f32);
-  EXPECT_EQ(s->dim, TextureDimension::k3d);
+    auto* f32 = create<F32>();
+    auto* s = create<SampledTexture>(TextureDimension::k3d, f32);
+    EXPECT_EQ(s->dim, TextureDimension::k3d);
 }
 
 TEST_F(AstSampledTextureTest, Type) {
-  auto* f32 = create<F32>();
-  auto* s = create<SampledTexture>(TextureDimension::k3d, f32);
-  EXPECT_EQ(s->type, f32);
+    auto* f32 = create<F32>();
+    auto* s = create<SampledTexture>(TextureDimension::k3d, f32);
+    EXPECT_EQ(s->type, f32);
 }
 
 TEST_F(AstSampledTextureTest, FriendlyName) {
-  auto* f32 = create<F32>();
-  auto* s = create<SampledTexture>(TextureDimension::k3d, f32);
-  EXPECT_EQ(s->FriendlyName(Symbols()), "texture_3d<f32>");
+    auto* f32 = create<F32>();
+    auto* s = create<SampledTexture>(TextureDimension::k3d, f32);
+    EXPECT_EQ(s->FriendlyName(Symbols()), "texture_3d<f32>");
 }
 
 }  // namespace
diff --git a/src/tint/ast/sampler.cc b/src/tint/ast/sampler.cc
index 68eddaf..5d88bf8 100644
--- a/src/tint/ast/sampler.cc
+++ b/src/tint/ast/sampler.cc
@@ -21,31 +21,30 @@
 namespace tint::ast {
 
 std::ostream& operator<<(std::ostream& out, SamplerKind kind) {
-  switch (kind) {
-    case SamplerKind::kSampler:
-      out << "sampler";
-      break;
-    case SamplerKind::kComparisonSampler:
-      out << "comparison_sampler";
-      break;
-  }
-  return out;
+    switch (kind) {
+        case SamplerKind::kSampler:
+            out << "sampler";
+            break;
+        case SamplerKind::kComparisonSampler:
+            out << "comparison_sampler";
+            break;
+    }
+    return out;
 }
 
-Sampler::Sampler(ProgramID pid, const Source& src, SamplerKind k)
-    : Base(pid, src), kind(k) {}
+Sampler::Sampler(ProgramID pid, const Source& src, SamplerKind k) : Base(pid, src), kind(k) {}
 
 Sampler::Sampler(Sampler&&) = default;
 
 Sampler::~Sampler() = default;
 
 std::string Sampler::FriendlyName(const SymbolTable&) const {
-  return kind == SamplerKind::kSampler ? "sampler" : "sampler_comparison";
+    return kind == SamplerKind::kSampler ? "sampler" : "sampler_comparison";
 }
 
 const Sampler* Sampler::Clone(CloneContext* ctx) const {
-  auto src = ctx->Clone(source);
-  return ctx->dst->create<Sampler>(src, kind);
+    auto src = ctx->Clone(source);
+    return ctx->dst->create<Sampler>(src, kind);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/sampler.h b/src/tint/ast/sampler.h
index 18c6fa2..067fc38 100644
--- a/src/tint/ast/sampler.h
+++ b/src/tint/ast/sampler.h
@@ -23,10 +23,10 @@
 
 /// The different kinds of samplers
 enum class SamplerKind {
-  /// A regular sampler
-  kSampler,
-  /// A comparison sampler
-  kComparisonSampler
+    /// A regular sampler
+    kSampler,
+    /// A comparison sampler
+    kComparisonSampler
 };
 
 /// @param out the std::ostream to write to
@@ -36,31 +36,31 @@
 
 /// A sampler type.
 class Sampler final : public Castable<Sampler, Type> {
- public:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  /// @param kind the kind of sampler
-  Sampler(ProgramID pid, const Source& src, SamplerKind kind);
-  /// Move constructor
-  Sampler(Sampler&&);
-  ~Sampler() override;
+  public:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    /// @param kind the kind of sampler
+    Sampler(ProgramID pid, const Source& src, SamplerKind kind);
+    /// Move constructor
+    Sampler(Sampler&&);
+    ~Sampler() override;
 
-  /// @returns true if this is a comparison sampler
-  bool IsComparison() const { return kind == SamplerKind::kComparisonSampler; }
+    /// @returns true if this is a comparison sampler
+    bool IsComparison() const { return kind == SamplerKind::kComparisonSampler; }
 
-  /// @param symbols the program's symbol table
-  /// @returns the name for this type that closely resembles how it would be
-  /// declared in WGSL.
-  std::string FriendlyName(const SymbolTable& symbols) const override;
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type that closely resembles how it would be
+    /// declared in WGSL.
+    std::string FriendlyName(const SymbolTable& symbols) const override;
 
-  /// Clones this type and all transitive types using the `CloneContext` `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned type
-  const Sampler* Clone(CloneContext* ctx) const override;
+    /// Clones this type and all transitive types using the `CloneContext` `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned type
+    const Sampler* Clone(CloneContext* ctx) const override;
 
-  /// The sampler type
-  const SamplerKind kind;
+    /// The sampler type
+    const SamplerKind kind;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/sampler_test.cc b/src/tint/ast/sampler_test.cc
index 16e2129..14500d9 100644
--- a/src/tint/ast/sampler_test.cc
+++ b/src/tint/ast/sampler_test.cc
@@ -22,24 +22,24 @@
 using AstSamplerTest = TestHelper;
 
 TEST_F(AstSamplerTest, Creation) {
-  auto* s = create<Sampler>(SamplerKind::kSampler);
-  EXPECT_EQ(s->kind, SamplerKind::kSampler);
+    auto* s = create<Sampler>(SamplerKind::kSampler);
+    EXPECT_EQ(s->kind, SamplerKind::kSampler);
 }
 
 TEST_F(AstSamplerTest, Creation_ComparisonSampler) {
-  auto* s = create<Sampler>(SamplerKind::kComparisonSampler);
-  EXPECT_EQ(s->kind, SamplerKind::kComparisonSampler);
-  EXPECT_TRUE(s->IsComparison());
+    auto* s = create<Sampler>(SamplerKind::kComparisonSampler);
+    EXPECT_EQ(s->kind, SamplerKind::kComparisonSampler);
+    EXPECT_TRUE(s->IsComparison());
 }
 
 TEST_F(AstSamplerTest, FriendlyNameSampler) {
-  auto* s = create<Sampler>(SamplerKind::kSampler);
-  EXPECT_EQ(s->FriendlyName(Symbols()), "sampler");
+    auto* s = create<Sampler>(SamplerKind::kSampler);
+    EXPECT_EQ(s->FriendlyName(Symbols()), "sampler");
 }
 
 TEST_F(AstSamplerTest, FriendlyNameComparisonSampler) {
-  auto* s = create<Sampler>(SamplerKind::kComparisonSampler);
-  EXPECT_EQ(s->FriendlyName(Symbols()), "sampler_comparison");
+    auto* s = create<Sampler>(SamplerKind::kComparisonSampler);
+    EXPECT_EQ(s->FriendlyName(Symbols()), "sampler_comparison");
 }
 
 }  // namespace
diff --git a/src/tint/ast/sint_literal_expression.cc b/src/tint/ast/sint_literal_expression.cc
deleted file mode 100644
index 5a215ec..0000000
--- a/src/tint/ast/sint_literal_expression.cc
+++ /dev/null
@@ -1,41 +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/sint_literal_expression.h"
-
-#include "src/tint/program_builder.h"
-
-TINT_INSTANTIATE_TYPEINFO(tint::ast::SintLiteralExpression);
-
-namespace tint::ast {
-
-SintLiteralExpression::SintLiteralExpression(ProgramID pid,
-                                             const Source& src,
-                                             int32_t val)
-    : Base(pid, src), value(val) {}
-
-SintLiteralExpression::~SintLiteralExpression() = default;
-
-uint32_t SintLiteralExpression::ValueAsU32() const {
-  return static_cast<uint32_t>(value);
-}
-
-const SintLiteralExpression* SintLiteralExpression::Clone(
-    CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  return ctx->dst->create<SintLiteralExpression>(src, value);
-}
-
-}  // namespace tint::ast
diff --git a/src/tint/ast/sint_literal_expression.h b/src/tint/ast/sint_literal_expression.h
deleted file mode 100644
index 74d60fc..0000000
--- a/src/tint/ast/sint_literal_expression.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_SINT_LITERAL_EXPRESSION_H_
-#define SRC_TINT_AST_SINT_LITERAL_EXPRESSION_H_
-
-#include <string>
-
-#include "src/tint/ast/int_literal_expression.h"
-
-namespace tint::ast {
-
-/// A signed int literal
-class SintLiteralExpression final
-    : public Castable<SintLiteralExpression, IntLiteralExpression> {
- public:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  /// @param value the signed int literals value
-  SintLiteralExpression(ProgramID pid, const Source& src, int32_t value);
-  ~SintLiteralExpression() override;
-
-  /// @returns the literal value as a u32
-  uint32_t ValueAsU32() const override;
-
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const SintLiteralExpression* Clone(CloneContext* ctx) const override;
-
-  /// The int literal value
-  const int32_t value;
-};
-
-}  // namespace tint::ast
-
-#endif  // SRC_TINT_AST_SINT_LITERAL_EXPRESSION_H_
diff --git a/src/tint/ast/sint_literal_expression_test.cc b/src/tint/ast/sint_literal_expression_test.cc
deleted file mode 100644
index 79be9b2..0000000
--- a/src/tint/ast/sint_literal_expression_test.cc
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2020 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/tint/ast/test_helper.h"
-
-namespace tint::ast {
-namespace {
-
-using SintLiteralExpressionTest = TestHelper;
-
-TEST_F(SintLiteralExpressionTest, Value) {
-  auto* i = create<SintLiteralExpression>(47);
-  ASSERT_TRUE(i->Is<SintLiteralExpression>());
-  EXPECT_EQ(i->value, 47);
-}
-
-}  // namespace
-}  // namespace tint::ast
diff --git a/src/tint/ast/stage_attribute.cc b/src/tint/ast/stage_attribute.cc
index 0b59633..51cfe8c 100644
--- a/src/tint/ast/stage_attribute.cc
+++ b/src/tint/ast/stage_attribute.cc
@@ -22,21 +22,19 @@
 
 namespace tint::ast {
 
-StageAttribute::StageAttribute(ProgramID pid,
-                               const Source& src,
-                               PipelineStage s)
+StageAttribute::StageAttribute(ProgramID pid, const Source& src, PipelineStage s)
     : Base(pid, src), stage(s) {}
 
 StageAttribute::~StageAttribute() = default;
 
 std::string StageAttribute::Name() const {
-  return "stage";
+    return "stage";
 }
 
 const StageAttribute* StageAttribute::Clone(CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  return ctx->dst->create<StageAttribute>(src, stage);
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    return ctx->dst->create<StageAttribute>(src, stage);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/stage_attribute.h b/src/tint/ast/stage_attribute.h
index 6195eaa..a447d1f 100644
--- a/src/tint/ast/stage_attribute.h
+++ b/src/tint/ast/stage_attribute.h
@@ -24,27 +24,25 @@
 
 /// A workgroup attribute
 class StageAttribute final : public Castable<StageAttribute, Attribute> {
- public:
-  /// constructor
-  /// @param program_id the identifier of the program that owns this node
-  /// @param stage the pipeline stage
-  /// @param source the source of this attribute
-  StageAttribute(ProgramID program_id,
-                 const Source& source,
-                 PipelineStage stage);
-  ~StageAttribute() override;
+  public:
+    /// constructor
+    /// @param program_id the identifier of the program that owns this node
+    /// @param stage the pipeline stage
+    /// @param source the source of this attribute
+    StageAttribute(ProgramID program_id, const Source& source, PipelineStage stage);
+    ~StageAttribute() override;
 
-  /// @returns the WGSL name for the attribute
-  std::string Name() const override;
+    /// @returns the WGSL name for the attribute
+    std::string Name() const override;
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const StageAttribute* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const StageAttribute* Clone(CloneContext* ctx) const override;
 
-  /// The pipeline stage
-  const PipelineStage stage;
+    /// The pipeline stage
+    const PipelineStage stage;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/stage_attribute_test.cc b/src/tint/ast/stage_attribute_test.cc
index f1d8b5a..d4baaf2 100644
--- a/src/tint/ast/stage_attribute_test.cc
+++ b/src/tint/ast/stage_attribute_test.cc
@@ -23,8 +23,8 @@
 using StageAttributeTest = TestHelper;
 
 TEST_F(StageAttributeTest, Creation_1param) {
-  auto* d = create<StageAttribute>(PipelineStage::kFragment);
-  EXPECT_EQ(d->stage, PipelineStage::kFragment);
+    auto* d = create<StageAttribute>(PipelineStage::kFragment);
+    EXPECT_EQ(d->stage, PipelineStage::kFragment);
 }
 
 }  // namespace
diff --git a/src/tint/ast/statement.cc b/src/tint/ast/statement.cc
index 0d8750d..12a1cc9 100644
--- a/src/tint/ast/statement.cc
+++ b/src/tint/ast/statement.cc
@@ -37,49 +37,46 @@
 Statement::~Statement() = default;
 
 const char* Statement::Name() const {
-  if (Is<AssignmentStatement>()) {
-    return "assignment statement";
-  }
-  if (Is<BlockStatement>()) {
-    return "block statement";
-  }
-  if (Is<BreakStatement>()) {
-    return "break statement";
-  }
-  if (Is<CaseStatement>()) {
-    return "case statement";
-  }
-  if (Is<CallStatement>()) {
-    return "function call";
-  }
-  if (Is<ContinueStatement>()) {
-    return "continue statement";
-  }
-  if (Is<DiscardStatement>()) {
-    return "discard statement";
-  }
-  if (Is<ElseStatement>()) {
-    return "else statement";
-  }
-  if (Is<FallthroughStatement>()) {
-    return "fallthrough statement";
-  }
-  if (Is<IfStatement>()) {
-    return "if statement";
-  }
-  if (Is<LoopStatement>()) {
-    return "loop statement";
-  }
-  if (Is<ReturnStatement>()) {
-    return "return statement";
-  }
-  if (Is<SwitchStatement>()) {
-    return "switch statement";
-  }
-  if (Is<VariableDeclStatement>()) {
-    return "variable declaration";
-  }
-  return "statement";
+    if (Is<AssignmentStatement>()) {
+        return "assignment statement";
+    }
+    if (Is<BlockStatement>()) {
+        return "block statement";
+    }
+    if (Is<BreakStatement>()) {
+        return "break statement";
+    }
+    if (Is<CaseStatement>()) {
+        return "case statement";
+    }
+    if (Is<CallStatement>()) {
+        return "function call";
+    }
+    if (Is<ContinueStatement>()) {
+        return "continue statement";
+    }
+    if (Is<DiscardStatement>()) {
+        return "discard statement";
+    }
+    if (Is<FallthroughStatement>()) {
+        return "fallthrough statement";
+    }
+    if (Is<IfStatement>()) {
+        return "if statement";
+    }
+    if (Is<LoopStatement>()) {
+        return "loop statement";
+    }
+    if (Is<ReturnStatement>()) {
+        return "return statement";
+    }
+    if (Is<SwitchStatement>()) {
+        return "switch statement";
+    }
+    if (Is<VariableDeclStatement>()) {
+        return "variable declaration";
+    }
+    return "statement";
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/statement.h b/src/tint/ast/statement.h
index 931e1b5..94de247 100644
--- a/src/tint/ast/statement.h
+++ b/src/tint/ast/statement.h
@@ -23,19 +23,19 @@
 
 /// Base statement class
 class Statement : public Castable<Statement, Node> {
- public:
-  ~Statement() override;
+  public:
+    ~Statement() override;
 
-  /// @returns the human readable name for the statement type.
-  const char* Name() const;
+    /// @returns the human readable name for the statement type.
+    const char* Name() const;
 
- protected:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of the expression
-  Statement(ProgramID pid, const Source& src);
-  /// Move constructor
-  Statement(Statement&&);
+  protected:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of the expression
+    Statement(ProgramID pid, const Source& src);
+    /// Move constructor
+    Statement(Statement&&);
 };
 
 /// A list of statements
diff --git a/src/tint/ast/storage_class.cc b/src/tint/ast/storage_class.cc
index 00d6d92..3161271 100644
--- a/src/tint/ast/storage_class.cc
+++ b/src/tint/ast/storage_class.cc
@@ -17,33 +17,33 @@
 namespace tint::ast {
 
 const char* ToString(StorageClass sc) {
-  switch (sc) {
-    case StorageClass::kInvalid:
-      return "invalid";
-    case StorageClass::kNone:
-      return "none";
-    case StorageClass::kInput:
-      return "in";
-    case StorageClass::kOutput:
-      return "out";
-    case StorageClass::kUniform:
-      return "uniform";
-    case StorageClass::kWorkgroup:
-      return "workgroup";
-    case StorageClass::kUniformConstant:
-      return "uniform_constant";
-    case StorageClass::kStorage:
-      return "storage";
-    case StorageClass::kPrivate:
-      return "private";
-    case StorageClass::kFunction:
-      return "function";
-  }
-  return "<unknown>";
+    switch (sc) {
+        case StorageClass::kInvalid:
+            return "invalid";
+        case StorageClass::kNone:
+            return "none";
+        case StorageClass::kInput:
+            return "in";
+        case StorageClass::kOutput:
+            return "out";
+        case StorageClass::kUniform:
+            return "uniform";
+        case StorageClass::kWorkgroup:
+            return "workgroup";
+        case StorageClass::kHandle:
+            return "handle";
+        case StorageClass::kStorage:
+            return "storage";
+        case StorageClass::kPrivate:
+            return "private";
+        case StorageClass::kFunction:
+            return "function";
+    }
+    return "<unknown>";
 }
 std::ostream& operator<<(std::ostream& out, StorageClass sc) {
-  out << ToString(sc);
-  return out;
+    out << ToString(sc);
+    return out;
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/storage_class.h b/src/tint/ast/storage_class.h
index dc7a94a..d4e6479 100644
--- a/src/tint/ast/storage_class.h
+++ b/src/tint/ast/storage_class.h
@@ -21,23 +21,23 @@
 
 /// Storage class of a given pointer.
 enum class StorageClass {
-  kInvalid = -1,
-  kNone,
-  kInput,
-  kOutput,
-  kUniform,
-  kWorkgroup,
-  kUniformConstant,
-  kStorage,
-  kPrivate,
-  kFunction
+    kInvalid = -1,
+    kNone,
+    kInput,
+    kOutput,
+    kUniform,
+    kWorkgroup,
+    kHandle,
+    kStorage,
+    kPrivate,
+    kFunction
 };
 
 /// @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;
+    return sc == ast::StorageClass::kUniform || sc == ast::StorageClass::kStorage;
 }
 
 /// @param sc the StorageClass
diff --git a/src/tint/ast/storage_texture.cc b/src/tint/ast/storage_texture.cc
index 170b2ee..ccc250d 100644
--- a/src/tint/ast/storage_texture.cc
+++ b/src/tint/ast/storage_texture.cc
@@ -26,60 +26,60 @@
 // 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;
+    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,
@@ -95,50 +95,50 @@
 StorageTexture::~StorageTexture() = default;
 
 std::string StorageTexture::FriendlyName(const SymbolTable&) const {
-  std::ostringstream out;
-  out << "texture_storage_" << dim << "<" << format << ", " << access << ">";
-  return out.str();
+    std::ostringstream out;
+    out << "texture_storage_" << dim << "<" << format << ", " << access << ">";
+    return out.str();
 }
 
 const StorageTexture* StorageTexture::Clone(CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  auto* ty = ctx->Clone(type);
-  return ctx->dst->create<StorageTexture>(src, dim, format, ty, access);
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    auto* ty = ctx->Clone(type);
+    return ctx->dst->create<StorageTexture>(src, dim, format, ty, access);
 }
 
 Type* StorageTexture::SubtypeFor(TexelFormat format, ProgramBuilder& builder) {
-  switch (format) {
-    case TexelFormat::kR32Uint:
-    case TexelFormat::kRgba8Uint:
-    case TexelFormat::kRg32Uint:
-    case TexelFormat::kRgba16Uint:
-    case TexelFormat::kRgba32Uint: {
-      return builder.create<U32>();
+    switch (format) {
+        case TexelFormat::kR32Uint:
+        case TexelFormat::kRgba8Uint:
+        case TexelFormat::kRg32Uint:
+        case TexelFormat::kRgba16Uint:
+        case TexelFormat::kRgba32Uint: {
+            return builder.create<U32>();
+        }
+
+        case TexelFormat::kR32Sint:
+        case TexelFormat::kRgba8Sint:
+        case TexelFormat::kRg32Sint:
+        case TexelFormat::kRgba16Sint:
+        case TexelFormat::kRgba32Sint: {
+            return builder.create<I32>();
+        }
+
+        case TexelFormat::kRgba8Unorm:
+        case TexelFormat::kRgba8Snorm:
+        case TexelFormat::kR32Float:
+        case TexelFormat::kRg32Float:
+        case TexelFormat::kRgba16Float:
+        case TexelFormat::kRgba32Float: {
+            return builder.create<F32>();
+        }
+
+        case TexelFormat::kNone:
+            break;
     }
 
-    case TexelFormat::kR32Sint:
-    case TexelFormat::kRgba8Sint:
-    case TexelFormat::kRg32Sint:
-    case TexelFormat::kRgba16Sint:
-    case TexelFormat::kRgba32Sint: {
-      return builder.create<I32>();
-    }
-
-    case TexelFormat::kRgba8Unorm:
-    case TexelFormat::kRgba8Snorm:
-    case TexelFormat::kR32Float:
-    case TexelFormat::kRg32Float:
-    case TexelFormat::kRgba16Float:
-    case TexelFormat::kRgba32Float: {
-      return builder.create<F32>();
-    }
-
-    case TexelFormat::kNone:
-      break;
-  }
-
-  return nullptr;
+    return nullptr;
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/storage_texture.h b/src/tint/ast/storage_texture.h
index ca962c1..3cf779e 100644
--- a/src/tint/ast/storage_texture.h
+++ b/src/tint/ast/storage_texture.h
@@ -24,23 +24,23 @@
 
 /// 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,
+    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
@@ -50,48 +50,48 @@
 
 /// A storage texture type.
 class StorageTexture final : public Castable<StorageTexture, Texture> {
- public:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  /// @param dim the dimensionality of the texture
-  /// @param format the image format of the texture
-  /// @param subtype the storage subtype. Use SubtypeFor() to calculate this.
-  /// @param access_control the access control for the texture.
-  StorageTexture(ProgramID pid,
-                 const Source& src,
-                 TextureDimension dim,
-                 TexelFormat format,
-                 const Type* subtype,
-                 Access access_control);
+  public:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    /// @param dim the dimensionality of the texture
+    /// @param format the image format of the texture
+    /// @param subtype the storage subtype. Use SubtypeFor() to calculate this.
+    /// @param access_control the access control for the texture.
+    StorageTexture(ProgramID pid,
+                   const Source& src,
+                   TextureDimension dim,
+                   TexelFormat format,
+                   const Type* subtype,
+                   Access access_control);
 
-  /// Move constructor
-  StorageTexture(StorageTexture&&);
-  ~StorageTexture() override;
+    /// Move constructor
+    StorageTexture(StorageTexture&&);
+    ~StorageTexture() override;
 
-  /// @param symbols the program's symbol table
-  /// @returns the name for this type that closely resembles how it would be
-  /// declared in WGSL.
-  std::string FriendlyName(const SymbolTable& symbols) const override;
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type that closely resembles how it would be
+    /// declared in WGSL.
+    std::string FriendlyName(const SymbolTable& symbols) const override;
 
-  /// Clones this type and all transitive types using the `CloneContext` `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned type
-  const StorageTexture* Clone(CloneContext* ctx) const override;
+    /// Clones this type and all transitive types using the `CloneContext` `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned type
+    const StorageTexture* Clone(CloneContext* ctx) const override;
 
-  /// @param format the storage texture image format
-  /// @param builder the ProgramBuilder used to build the returned type
-  /// @returns the storage texture subtype for the given TexelFormat
-  static Type* SubtypeFor(TexelFormat format, ProgramBuilder& builder);
+    /// @param format the storage texture image format
+    /// @param builder the ProgramBuilder used to build the returned type
+    /// @returns the storage texture subtype for the given TexelFormat
+    static Type* SubtypeFor(TexelFormat format, ProgramBuilder& builder);
 
-  /// The image format
-  const TexelFormat format;
+    /// The image format
+    const TexelFormat format;
 
-  /// The storage subtype
-  const Type* const type;
+    /// The storage subtype
+    const Type* const type;
 
-  /// The access control
-  const Access access;
+    /// The access control
+    const Access access;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/storage_texture_test.cc b/src/tint/ast/storage_texture_test.cc
index 77447a8..8f1b221 100644
--- a/src/tint/ast/storage_texture_test.cc
+++ b/src/tint/ast/storage_texture_test.cc
@@ -22,71 +22,63 @@
 using AstStorageTextureTest = TestHelper;
 
 TEST_F(AstStorageTextureTest, IsTexture) {
-  auto* subtype = StorageTexture::SubtypeFor(TexelFormat::kRgba32Float, *this);
-  Texture* ty =
-      create<StorageTexture>(TextureDimension::k2dArray,
-                             TexelFormat::kRgba32Float, subtype, Access::kRead);
-  EXPECT_FALSE(ty->Is<DepthTexture>());
-  EXPECT_FALSE(ty->Is<SampledTexture>());
-  EXPECT_TRUE(ty->Is<StorageTexture>());
+    auto* subtype = StorageTexture::SubtypeFor(TexelFormat::kRgba32Float, *this);
+    Texture* ty = create<StorageTexture>(TextureDimension::k2dArray, TexelFormat::kRgba32Float,
+                                         subtype, Access::kRead);
+    EXPECT_FALSE(ty->Is<DepthTexture>());
+    EXPECT_FALSE(ty->Is<SampledTexture>());
+    EXPECT_TRUE(ty->Is<StorageTexture>());
 }
 
 TEST_F(AstStorageTextureTest, Dim) {
-  auto* subtype = StorageTexture::SubtypeFor(TexelFormat::kRgba32Float, *this);
-  auto* s =
-      create<StorageTexture>(TextureDimension::k2dArray,
-                             TexelFormat::kRgba32Float, subtype, Access::kRead);
-  EXPECT_EQ(s->dim, TextureDimension::k2dArray);
+    auto* subtype = StorageTexture::SubtypeFor(TexelFormat::kRgba32Float, *this);
+    auto* s = create<StorageTexture>(TextureDimension::k2dArray, TexelFormat::kRgba32Float, subtype,
+                                     Access::kRead);
+    EXPECT_EQ(s->dim, TextureDimension::k2dArray);
 }
 
 TEST_F(AstStorageTextureTest, Format) {
-  auto* subtype = StorageTexture::SubtypeFor(TexelFormat::kRgba32Float, *this);
-  auto* s =
-      create<StorageTexture>(TextureDimension::k2dArray,
-                             TexelFormat::kRgba32Float, subtype, Access::kRead);
-  EXPECT_EQ(s->format, TexelFormat::kRgba32Float);
+    auto* subtype = StorageTexture::SubtypeFor(TexelFormat::kRgba32Float, *this);
+    auto* s = create<StorageTexture>(TextureDimension::k2dArray, TexelFormat::kRgba32Float, subtype,
+                                     Access::kRead);
+    EXPECT_EQ(s->format, TexelFormat::kRgba32Float);
 }
 
 TEST_F(AstStorageTextureTest, FriendlyName) {
-  auto* subtype = StorageTexture::SubtypeFor(TexelFormat::kRgba32Float, *this);
-  auto* s =
-      create<StorageTexture>(TextureDimension::k2dArray,
-                             TexelFormat::kRgba32Float, subtype, Access::kRead);
-  EXPECT_EQ(s->FriendlyName(Symbols()),
-            "texture_storage_2d_array<rgba32float, read>");
+    auto* subtype = StorageTexture::SubtypeFor(TexelFormat::kRgba32Float, *this);
+    auto* s = create<StorageTexture>(TextureDimension::k2dArray, TexelFormat::kRgba32Float, subtype,
+                                     Access::kRead);
+    EXPECT_EQ(s->FriendlyName(Symbols()), "texture_storage_2d_array<rgba32float, read>");
 }
 
 TEST_F(AstStorageTextureTest, F32) {
-  auto* subtype = StorageTexture::SubtypeFor(TexelFormat::kRgba32Float, *this);
-  Type* s =
-      create<StorageTexture>(TextureDimension::k2dArray,
-                             TexelFormat::kRgba32Float, subtype, Access::kRead);
+    auto* subtype = StorageTexture::SubtypeFor(TexelFormat::kRgba32Float, *this);
+    Type* s = create<StorageTexture>(TextureDimension::k2dArray, TexelFormat::kRgba32Float, subtype,
+                                     Access::kRead);
 
-  ASSERT_TRUE(s->Is<Texture>());
-  ASSERT_TRUE(s->Is<StorageTexture>());
-  EXPECT_TRUE(s->As<StorageTexture>()->type->Is<F32>());
+    ASSERT_TRUE(s->Is<Texture>());
+    ASSERT_TRUE(s->Is<StorageTexture>());
+    EXPECT_TRUE(s->As<StorageTexture>()->type->Is<F32>());
 }
 
 TEST_F(AstStorageTextureTest, U32) {
-  auto* subtype = StorageTexture::SubtypeFor(TexelFormat::kRg32Uint, *this);
-  Type* s =
-      create<StorageTexture>(TextureDimension::k2dArray, TexelFormat::kRg32Uint,
-                             subtype, Access::kRead);
+    auto* subtype = StorageTexture::SubtypeFor(TexelFormat::kRg32Uint, *this);
+    Type* s = create<StorageTexture>(TextureDimension::k2dArray, TexelFormat::kRg32Uint, subtype,
+                                     Access::kRead);
 
-  ASSERT_TRUE(s->Is<Texture>());
-  ASSERT_TRUE(s->Is<StorageTexture>());
-  EXPECT_TRUE(s->As<StorageTexture>()->type->Is<U32>());
+    ASSERT_TRUE(s->Is<Texture>());
+    ASSERT_TRUE(s->Is<StorageTexture>());
+    EXPECT_TRUE(s->As<StorageTexture>()->type->Is<U32>());
 }
 
 TEST_F(AstStorageTextureTest, I32) {
-  auto* subtype = StorageTexture::SubtypeFor(TexelFormat::kRgba32Sint, *this);
-  Type* s =
-      create<StorageTexture>(TextureDimension::k2dArray,
-                             TexelFormat::kRgba32Sint, subtype, Access::kRead);
+    auto* subtype = StorageTexture::SubtypeFor(TexelFormat::kRgba32Sint, *this);
+    Type* s = create<StorageTexture>(TextureDimension::k2dArray, TexelFormat::kRgba32Sint, subtype,
+                                     Access::kRead);
 
-  ASSERT_TRUE(s->Is<Texture>());
-  ASSERT_TRUE(s->Is<StorageTexture>());
-  EXPECT_TRUE(s->As<StorageTexture>()->type->Is<I32>());
+    ASSERT_TRUE(s->Is<Texture>());
+    ASSERT_TRUE(s->Is<StorageTexture>());
+    EXPECT_TRUE(s->As<StorageTexture>()->type->Is<I32>());
 }
 
 }  // namespace
diff --git a/src/tint/ast/stride_attribute.cc b/src/tint/ast/stride_attribute.cc
index 3eb1f6d..14a0733 100644
--- a/src/tint/ast/stride_attribute.cc
+++ b/src/tint/ast/stride_attribute.cc
@@ -28,13 +28,13 @@
 StrideAttribute::~StrideAttribute() = default;
 
 std::string StrideAttribute::Name() const {
-  return "stride";
+    return "stride";
 }
 
 const StrideAttribute* StrideAttribute::Clone(CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  return ctx->dst->create<StrideAttribute>(src, stride);
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    return ctx->dst->create<StrideAttribute>(src, stride);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/stride_attribute.h b/src/tint/ast/stride_attribute.h
index 232bae7..4315f21 100644
--- a/src/tint/ast/stride_attribute.h
+++ b/src/tint/ast/stride_attribute.h
@@ -25,25 +25,25 @@
 /// A stride attribute used by the SPIR-V reader for strided arrays and
 /// matrices.
 class StrideAttribute final : public Castable<StrideAttribute, Attribute> {
- public:
-  /// constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  /// @param stride the stride value
-  StrideAttribute(ProgramID pid, const Source& src, uint32_t stride);
-  ~StrideAttribute() override;
+  public:
+    /// constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    /// @param stride the stride value
+    StrideAttribute(ProgramID pid, const Source& src, uint32_t stride);
+    ~StrideAttribute() override;
 
-  /// @returns the WGSL name for the attribute
-  std::string Name() const override;
+    /// @returns the WGSL name for the attribute
+    std::string Name() const override;
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const StrideAttribute* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const StrideAttribute* Clone(CloneContext* ctx) const override;
 
-  /// The stride value
-  const uint32_t stride;
+    /// The stride value
+    const uint32_t stride;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/stride_attribute_test.cc b/src/tint/ast/stride_attribute_test.cc
index 1eba1e1..61c4fb5 100644
--- a/src/tint/ast/stride_attribute_test.cc
+++ b/src/tint/ast/stride_attribute_test.cc
@@ -20,17 +20,17 @@
 using StrideAttributeTest = TestHelper;
 
 TEST_F(StrideAttributeTest, Creation) {
-  auto* d = create<StrideAttribute>(2);
-  EXPECT_EQ(2u, d->stride);
+    auto* d = create<StrideAttribute>(2);
+    EXPECT_EQ(2u, d->stride);
 }
 
 TEST_F(StrideAttributeTest, Source) {
-  auto* d = create<StrideAttribute>(
-      Source{Source::Range{Source::Location{1, 2}, Source::Location{3, 4}}}, 2);
-  EXPECT_EQ(d->source.range.begin.line, 1u);
-  EXPECT_EQ(d->source.range.begin.column, 2u);
-  EXPECT_EQ(d->source.range.end.line, 3u);
-  EXPECT_EQ(d->source.range.end.column, 4u);
+    auto* d = create<StrideAttribute>(
+        Source{Source::Range{Source::Location{1, 2}, Source::Location{3, 4}}}, 2);
+    EXPECT_EQ(d->source.range.begin.line, 1u);
+    EXPECT_EQ(d->source.range.begin.column, 2u);
+    EXPECT_EQ(d->source.range.end.line, 3u);
+    EXPECT_EQ(d->source.range.end.column, 4u);
 }
 
 }  // namespace
diff --git a/src/tint/ast/struct.cc b/src/tint/ast/struct.cc
index 4f82c3a..19a30de 100644
--- a/src/tint/ast/struct.cc
+++ b/src/tint/ast/struct.cc
@@ -22,20 +22,16 @@
 
 namespace tint::ast {
 
-Struct::Struct(ProgramID pid,
-               const Source& src,
-               Symbol n,
-               StructMemberList m,
-               AttributeList attrs)
+Struct::Struct(ProgramID pid, const Source& src, Symbol n, StructMemberList m, AttributeList attrs)
     : Base(pid, src, n), members(std::move(m)), attributes(std::move(attrs)) {
-  for (auto* mem : members) {
-    TINT_ASSERT(AST, mem);
-    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, mem, program_id);
-  }
-  for (auto* attr : attributes) {
-    TINT_ASSERT(AST, attr);
-    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, attr, program_id);
-  }
+    for (auto* mem : members) {
+        TINT_ASSERT(AST, mem);
+        TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, mem, program_id);
+    }
+    for (auto* attr : attributes) {
+        TINT_ASSERT(AST, attr);
+        TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, attr, program_id);
+    }
 }
 
 Struct::Struct(Struct&&) = default;
@@ -43,12 +39,12 @@
 Struct::~Struct() = default;
 
 const Struct* Struct::Clone(CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  auto n = ctx->Clone(name);
-  auto mem = ctx->Clone(members);
-  auto attrs = ctx->Clone(attributes);
-  return ctx->dst->create<Struct>(src, n, mem, attrs);
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    auto n = ctx->Clone(name);
+    auto mem = ctx->Clone(members);
+    auto attrs = ctx->Clone(attributes);
+    return ctx->dst->create<Struct>(src, n, mem, attrs);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/struct.h b/src/tint/ast/struct.h
index 7e44da4..5c28b4c 100644
--- a/src/tint/ast/struct.h
+++ b/src/tint/ast/struct.h
@@ -26,34 +26,34 @@
 
 /// A struct statement.
 class Struct final : public Castable<Struct, TypeDecl> {
- public:
-  /// Create a new struct statement
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node for the import statement
-  /// @param name The name of the structure
-  /// @param members The struct members
-  /// @param attributes The struct attributes
-  Struct(ProgramID pid,
-         const Source& src,
-         Symbol name,
-         StructMemberList members,
-         AttributeList attributes);
-  /// Move constructor
-  Struct(Struct&&);
+  public:
+    /// Create a new struct statement
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node for the import statement
+    /// @param name The name of the structure
+    /// @param members The struct members
+    /// @param attributes The struct attributes
+    Struct(ProgramID pid,
+           const Source& src,
+           Symbol name,
+           StructMemberList members,
+           AttributeList attributes);
+    /// Move constructor
+    Struct(Struct&&);
 
-  ~Struct() override;
+    ~Struct() override;
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const Struct* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const Struct* Clone(CloneContext* ctx) const override;
 
-  /// The members
-  const StructMemberList members;
+    /// The members
+    const StructMemberList members;
 
-  /// The struct attributes
-  const AttributeList attributes;
+    /// The struct attributes
+    const AttributeList attributes;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/struct_member.cc b/src/tint/ast/struct_member.cc
index b1cff3b..6113484 100644
--- a/src/tint/ast/struct_member.cc
+++ b/src/tint/ast/struct_member.cc
@@ -26,13 +26,13 @@
                            const ast::Type* ty,
                            AttributeList attrs)
     : Base(pid, src), symbol(sym), type(ty), attributes(std::move(attrs)) {
-  TINT_ASSERT(AST, type);
-  TINT_ASSERT(AST, symbol.IsValid());
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, symbol, program_id);
-  for (auto* attr : attributes) {
-    TINT_ASSERT(AST, attr);
-    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, attr, program_id);
-  }
+    TINT_ASSERT(AST, type);
+    TINT_ASSERT(AST, symbol.IsValid());
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, symbol, program_id);
+    for (auto* attr : attributes) {
+        TINT_ASSERT(AST, attr);
+        TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, attr, program_id);
+    }
 }
 
 StructMember::StructMember(StructMember&&) = default;
@@ -40,12 +40,12 @@
 StructMember::~StructMember() = default;
 
 const StructMember* StructMember::Clone(CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  auto sym = ctx->Clone(symbol);
-  auto* ty = ctx->Clone(type);
-  auto attrs = ctx->Clone(attributes);
-  return ctx->dst->create<StructMember>(src, sym, ty, attrs);
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    auto sym = ctx->Clone(symbol);
+    auto* ty = ctx->Clone(type);
+    auto attrs = ctx->Clone(attributes);
+    return ctx->dst->create<StructMember>(src, sym, ty, attrs);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/struct_member.h b/src/tint/ast/struct_member.h
index 7d21c9d..022a34c 100644
--- a/src/tint/ast/struct_member.h
+++ b/src/tint/ast/struct_member.h
@@ -29,37 +29,37 @@
 
 /// A struct member statement.
 class StructMember final : public Castable<StructMember, Node> {
- public:
-  /// Create a new struct member statement
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node for the struct member statement
-  /// @param sym The struct member symbol
-  /// @param type The struct member type
-  /// @param attributes The struct member attributes
-  StructMember(ProgramID pid,
-               const Source& src,
-               const Symbol& sym,
-               const ast::Type* type,
-               AttributeList attributes);
-  /// Move constructor
-  StructMember(StructMember&&);
+  public:
+    /// Create a new struct member statement
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node for the struct member statement
+    /// @param sym The struct member symbol
+    /// @param type The struct member type
+    /// @param attributes The struct member attributes
+    StructMember(ProgramID pid,
+                 const Source& src,
+                 const Symbol& sym,
+                 const ast::Type* type,
+                 AttributeList attributes);
+    /// Move constructor
+    StructMember(StructMember&&);
 
-  ~StructMember() override;
+    ~StructMember() override;
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const StructMember* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const StructMember* Clone(CloneContext* ctx) const override;
 
-  /// The symbol
-  const Symbol symbol;
+    /// The symbol
+    const Symbol symbol;
 
-  /// The type
-  const ast::Type* const type;
+    /// The type
+    const ast::Type* const type;
 
-  /// The attributes
-  const AttributeList attributes;
+    /// The attributes
+    const AttributeList attributes;
 };
 
 /// A list of struct members
diff --git a/src/tint/ast/struct_member_align_attribute.cc b/src/tint/ast/struct_member_align_attribute.cc
index 8736dd1..f586e7e 100644
--- a/src/tint/ast/struct_member_align_attribute.cc
+++ b/src/tint/ast/struct_member_align_attribute.cc
@@ -23,22 +23,19 @@
 
 namespace tint::ast {
 
-StructMemberAlignAttribute::StructMemberAlignAttribute(ProgramID pid,
-                                                       const Source& src,
-                                                       uint32_t a)
+StructMemberAlignAttribute::StructMemberAlignAttribute(ProgramID pid, const Source& src, uint32_t a)
     : Base(pid, src), align(a) {}
 
 StructMemberAlignAttribute::~StructMemberAlignAttribute() = default;
 
 std::string StructMemberAlignAttribute::Name() const {
-  return "align";
+    return "align";
 }
 
-const StructMemberAlignAttribute* StructMemberAlignAttribute::Clone(
-    CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  return ctx->dst->create<StructMemberAlignAttribute>(src, align);
+const StructMemberAlignAttribute* StructMemberAlignAttribute::Clone(CloneContext* ctx) const {
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    return ctx->dst->create<StructMemberAlignAttribute>(src, align);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/struct_member_align_attribute.h b/src/tint/ast/struct_member_align_attribute.h
index d8e629e..10a6507 100644
--- a/src/tint/ast/struct_member_align_attribute.h
+++ b/src/tint/ast/struct_member_align_attribute.h
@@ -23,27 +23,26 @@
 namespace tint::ast {
 
 /// A struct member align attribute
-class StructMemberAlignAttribute final
-    : public Castable<StructMemberAlignAttribute, Attribute> {
- public:
-  /// constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  /// @param align the align value
-  StructMemberAlignAttribute(ProgramID pid, const Source& src, uint32_t align);
-  ~StructMemberAlignAttribute() override;
+class StructMemberAlignAttribute final : public Castable<StructMemberAlignAttribute, Attribute> {
+  public:
+    /// constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    /// @param align the align value
+    StructMemberAlignAttribute(ProgramID pid, const Source& src, uint32_t align);
+    ~StructMemberAlignAttribute() override;
 
-  /// @returns the WGSL name for the attribute
-  std::string Name() const override;
+    /// @returns the WGSL name for the attribute
+    std::string Name() const override;
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const StructMemberAlignAttribute* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const StructMemberAlignAttribute* Clone(CloneContext* ctx) const override;
 
-  /// The align value
-  const uint32_t align;
+    /// The align value
+    const uint32_t align;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/struct_member_align_attribute_test.cc b/src/tint/ast/struct_member_align_attribute_test.cc
index 47b57aa..5b4ff48 100644
--- a/src/tint/ast/struct_member_align_attribute_test.cc
+++ b/src/tint/ast/struct_member_align_attribute_test.cc
@@ -22,8 +22,8 @@
 using StructMemberAlignAttributeTest = TestHelper;
 
 TEST_F(StructMemberAlignAttributeTest, Creation) {
-  auto* d = create<StructMemberAlignAttribute>(2);
-  EXPECT_EQ(2u, d->align);
+    auto* d = create<StructMemberAlignAttribute>(2);
+    EXPECT_EQ(2u, d->align);
 }
 
 }  // namespace
diff --git a/src/tint/ast/struct_member_offset_attribute.cc b/src/tint/ast/struct_member_offset_attribute.cc
index 5d9ec16..0a33127 100644
--- a/src/tint/ast/struct_member_offset_attribute.cc
+++ b/src/tint/ast/struct_member_offset_attribute.cc
@@ -30,14 +30,13 @@
 StructMemberOffsetAttribute::~StructMemberOffsetAttribute() = default;
 
 std::string StructMemberOffsetAttribute::Name() const {
-  return "offset";
+    return "offset";
 }
 
-const StructMemberOffsetAttribute* StructMemberOffsetAttribute::Clone(
-    CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  return ctx->dst->create<StructMemberOffsetAttribute>(src, offset);
+const StructMemberOffsetAttribute* StructMemberOffsetAttribute::Clone(CloneContext* ctx) const {
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    return ctx->dst->create<StructMemberOffsetAttribute>(src, offset);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/struct_member_offset_attribute.h b/src/tint/ast/struct_member_offset_attribute.h
index b1a25e0..92cc68e 100644
--- a/src/tint/ast/struct_member_offset_attribute.h
+++ b/src/tint/ast/struct_member_offset_attribute.h
@@ -31,29 +31,26 @@
 /// trivial for the Resolver to handle `@offset(n)` or `@size(n)` /
 /// `@align(n)` attributes, so this is what we do, keeping all the layout
 /// logic in one place.
-class StructMemberOffsetAttribute final
-    : public Castable<StructMemberOffsetAttribute, Attribute> {
- public:
-  /// constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  /// @param offset the offset value
-  StructMemberOffsetAttribute(ProgramID pid,
-                              const Source& src,
-                              uint32_t offset);
-  ~StructMemberOffsetAttribute() override;
+class StructMemberOffsetAttribute final : public Castable<StructMemberOffsetAttribute, Attribute> {
+  public:
+    /// constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    /// @param offset the offset value
+    StructMemberOffsetAttribute(ProgramID pid, const Source& src, uint32_t offset);
+    ~StructMemberOffsetAttribute() override;
 
-  /// @returns the WGSL name for the attribute
-  std::string Name() const override;
+    /// @returns the WGSL name for the attribute
+    std::string Name() const override;
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const StructMemberOffsetAttribute* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const StructMemberOffsetAttribute* Clone(CloneContext* ctx) const override;
 
-  /// The offset value
-  const uint32_t offset;
+    /// The offset value
+    const uint32_t offset;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/struct_member_offset_attribute_test.cc b/src/tint/ast/struct_member_offset_attribute_test.cc
index 8039926..3c0eb41 100644
--- a/src/tint/ast/struct_member_offset_attribute_test.cc
+++ b/src/tint/ast/struct_member_offset_attribute_test.cc
@@ -20,8 +20,8 @@
 using StructMemberOffsetAttributeTest = TestHelper;
 
 TEST_F(StructMemberOffsetAttributeTest, Creation) {
-  auto* d = create<StructMemberOffsetAttribute>(2);
-  EXPECT_EQ(2u, d->offset);
+    auto* d = create<StructMemberOffsetAttribute>(2);
+    EXPECT_EQ(2u, d->offset);
 }
 
 }  // namespace
diff --git a/src/tint/ast/struct_member_size_attribute.cc b/src/tint/ast/struct_member_size_attribute.cc
index 5e01c7d..a7f291b 100644
--- a/src/tint/ast/struct_member_size_attribute.cc
+++ b/src/tint/ast/struct_member_size_attribute.cc
@@ -23,22 +23,19 @@
 
 namespace tint::ast {
 
-StructMemberSizeAttribute::StructMemberSizeAttribute(ProgramID pid,
-                                                     const Source& src,
-                                                     uint32_t sz)
+StructMemberSizeAttribute::StructMemberSizeAttribute(ProgramID pid, const Source& src, uint32_t sz)
     : Base(pid, src), size(sz) {}
 
 StructMemberSizeAttribute::~StructMemberSizeAttribute() = default;
 
 std::string StructMemberSizeAttribute::Name() const {
-  return "size";
+    return "size";
 }
 
-const StructMemberSizeAttribute* StructMemberSizeAttribute::Clone(
-    CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  return ctx->dst->create<StructMemberSizeAttribute>(src, size);
+const StructMemberSizeAttribute* StructMemberSizeAttribute::Clone(CloneContext* ctx) const {
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    return ctx->dst->create<StructMemberSizeAttribute>(src, size);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/struct_member_size_attribute.h b/src/tint/ast/struct_member_size_attribute.h
index 967e602..0c4ddd6 100644
--- a/src/tint/ast/struct_member_size_attribute.h
+++ b/src/tint/ast/struct_member_size_attribute.h
@@ -23,27 +23,26 @@
 namespace tint::ast {
 
 /// A struct member size attribute
-class StructMemberSizeAttribute final
-    : public Castable<StructMemberSizeAttribute, Attribute> {
- public:
-  /// constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  /// @param size the size value
-  StructMemberSizeAttribute(ProgramID pid, const Source& src, uint32_t size);
-  ~StructMemberSizeAttribute() override;
+class StructMemberSizeAttribute final : public Castable<StructMemberSizeAttribute, Attribute> {
+  public:
+    /// constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    /// @param size the size value
+    StructMemberSizeAttribute(ProgramID pid, const Source& src, uint32_t size);
+    ~StructMemberSizeAttribute() override;
 
-  /// @returns the WGSL name for the attribute
-  std::string Name() const override;
+    /// @returns the WGSL name for the attribute
+    std::string Name() const override;
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const StructMemberSizeAttribute* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const StructMemberSizeAttribute* Clone(CloneContext* ctx) const override;
 
-  /// The size value
-  const uint32_t size;
+    /// The size value
+    const uint32_t size;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/struct_member_size_attribute_test.cc b/src/tint/ast/struct_member_size_attribute_test.cc
index 8998d1d..a9d4637 100644
--- a/src/tint/ast/struct_member_size_attribute_test.cc
+++ b/src/tint/ast/struct_member_size_attribute_test.cc
@@ -22,8 +22,8 @@
 using StructMemberSizeAttributeTest = TestHelper;
 
 TEST_F(StructMemberSizeAttributeTest, Creation) {
-  auto* d = create<StructMemberSizeAttribute>(2);
-  EXPECT_EQ(2u, d->size);
+    auto* d = create<StructMemberSizeAttribute>(2);
+    EXPECT_EQ(2u, d->size);
 }
 
 }  // namespace
diff --git a/src/tint/ast/struct_member_test.cc b/src/tint/ast/struct_member_test.cc
index 9fd4d7b..cec82ae 100644
--- a/src/tint/ast/struct_member_test.cc
+++ b/src/tint/ast/struct_member_test.cc
@@ -21,75 +21,74 @@
 using StructMemberTest = TestHelper;
 
 TEST_F(StructMemberTest, Creation) {
-  auto* st = Member("a", ty.i32(), {MemberSize(4)});
-  EXPECT_EQ(st->symbol, Symbol(1, ID()));
-  EXPECT_TRUE(st->type->Is<ast::I32>());
-  EXPECT_EQ(st->attributes.size(), 1u);
-  EXPECT_TRUE(st->attributes[0]->Is<StructMemberSizeAttribute>());
-  EXPECT_EQ(st->source.range.begin.line, 0u);
-  EXPECT_EQ(st->source.range.begin.column, 0u);
-  EXPECT_EQ(st->source.range.end.line, 0u);
-  EXPECT_EQ(st->source.range.end.column, 0u);
+    auto* st = Member("a", ty.i32(), {MemberSize(4)});
+    EXPECT_EQ(st->symbol, Symbol(1, ID()));
+    EXPECT_TRUE(st->type->Is<ast::I32>());
+    EXPECT_EQ(st->attributes.size(), 1u);
+    EXPECT_TRUE(st->attributes[0]->Is<StructMemberSizeAttribute>());
+    EXPECT_EQ(st->source.range.begin.line, 0u);
+    EXPECT_EQ(st->source.range.begin.column, 0u);
+    EXPECT_EQ(st->source.range.end.line, 0u);
+    EXPECT_EQ(st->source.range.end.column, 0u);
 }
 
 TEST_F(StructMemberTest, CreationWithSource) {
-  auto* st = Member(
-      Source{Source::Range{Source::Location{27, 4}, Source::Location{27, 8}}},
-      "a", ty.i32());
-  EXPECT_EQ(st->symbol, Symbol(1, ID()));
-  EXPECT_TRUE(st->type->Is<ast::I32>());
-  EXPECT_EQ(st->attributes.size(), 0u);
-  EXPECT_EQ(st->source.range.begin.line, 27u);
-  EXPECT_EQ(st->source.range.begin.column, 4u);
-  EXPECT_EQ(st->source.range.end.line, 27u);
-  EXPECT_EQ(st->source.range.end.column, 8u);
+    auto* st = Member(Source{Source::Range{Source::Location{27, 4}, Source::Location{27, 8}}}, "a",
+                      ty.i32());
+    EXPECT_EQ(st->symbol, Symbol(1, ID()));
+    EXPECT_TRUE(st->type->Is<ast::I32>());
+    EXPECT_EQ(st->attributes.size(), 0u);
+    EXPECT_EQ(st->source.range.begin.line, 27u);
+    EXPECT_EQ(st->source.range.begin.column, 4u);
+    EXPECT_EQ(st->source.range.end.line, 27u);
+    EXPECT_EQ(st->source.range.end.column, 8u);
 }
 
 TEST_F(StructMemberTest, Assert_Empty_Symbol) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.Member("", b.ty.i32());
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.Member("", b.ty.i32());
+        },
+        "internal compiler error");
 }
 
 TEST_F(StructMemberTest, Assert_Null_Type) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.Member("a", nullptr);
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.Member("a", nullptr);
+        },
+        "internal compiler error");
 }
 
 TEST_F(StructMemberTest, Assert_Null_Attribute) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.Member("a", b.ty.i32(), {b.MemberSize(4), nullptr});
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.Member("a", b.ty.i32(), {b.MemberSize(4), nullptr});
+        },
+        "internal compiler error");
 }
 
 TEST_F(StructMemberTest, Assert_DifferentProgramID_Symbol) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.Member(b2.Sym("a"), b1.ty.i32(), {b1.MemberSize(4)});
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.Member(b2.Sym("a"), b1.ty.i32(), {b1.MemberSize(4)});
+        },
+        "internal compiler error");
 }
 
 TEST_F(StructMemberTest, Assert_DifferentProgramID_Attribute) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.Member("a", b1.ty.i32(), {b2.MemberSize(4)});
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.Member("a", b1.ty.i32(), {b2.MemberSize(4)});
+        },
+        "internal compiler error");
 }
 
 }  // namespace
diff --git a/src/tint/ast/struct_test.cc b/src/tint/ast/struct_test.cc
index 2c629a2..895d501 100644
--- a/src/tint/ast/struct_test.cc
+++ b/src/tint/ast/struct_test.cc
@@ -32,99 +32,92 @@
 namespace {
 
 using AstStructTest = TestHelper;
-using SpirvBlockAttribute =
-    transform::AddSpirvBlockAttribute::SpirvBlockAttribute;
+using SpirvBlockAttribute = transform::AddSpirvBlockAttribute::SpirvBlockAttribute;
 
 TEST_F(AstStructTest, Creation) {
-  auto name = Sym("s");
-  auto* s = create<Struct>(name, StructMemberList{Member("a", ty.i32())},
-                           AttributeList{});
-  EXPECT_EQ(s->name, name);
-  EXPECT_EQ(s->members.size(), 1u);
-  EXPECT_TRUE(s->attributes.empty());
-  EXPECT_EQ(s->source.range.begin.line, 0u);
-  EXPECT_EQ(s->source.range.begin.column, 0u);
-  EXPECT_EQ(s->source.range.end.line, 0u);
-  EXPECT_EQ(s->source.range.end.column, 0u);
+    auto name = Sym("s");
+    auto* s = create<Struct>(name, StructMemberList{Member("a", ty.i32())}, AttributeList{});
+    EXPECT_EQ(s->name, name);
+    EXPECT_EQ(s->members.size(), 1u);
+    EXPECT_TRUE(s->attributes.empty());
+    EXPECT_EQ(s->source.range.begin.line, 0u);
+    EXPECT_EQ(s->source.range.begin.column, 0u);
+    EXPECT_EQ(s->source.range.end.line, 0u);
+    EXPECT_EQ(s->source.range.end.column, 0u);
 }
 
 TEST_F(AstStructTest, Creation_WithAttributes) {
-  auto name = Sym("s");
-  AttributeList attrs;
-  attrs.push_back(ASTNodes().Create<SpirvBlockAttribute>(ID()));
+    auto name = Sym("s");
+    AttributeList attrs;
+    attrs.push_back(ASTNodes().Create<SpirvBlockAttribute>(ID()));
 
-  auto* s =
-      create<Struct>(name, StructMemberList{Member("a", ty.i32())}, attrs);
-  EXPECT_EQ(s->name, name);
-  EXPECT_EQ(s->members.size(), 1u);
-  ASSERT_EQ(s->attributes.size(), 1u);
-  EXPECT_TRUE(s->attributes[0]->Is<SpirvBlockAttribute>());
-  EXPECT_EQ(s->source.range.begin.line, 0u);
-  EXPECT_EQ(s->source.range.begin.column, 0u);
-  EXPECT_EQ(s->source.range.end.line, 0u);
-  EXPECT_EQ(s->source.range.end.column, 0u);
+    auto* s = create<Struct>(name, StructMemberList{Member("a", ty.i32())}, attrs);
+    EXPECT_EQ(s->name, name);
+    EXPECT_EQ(s->members.size(), 1u);
+    ASSERT_EQ(s->attributes.size(), 1u);
+    EXPECT_TRUE(s->attributes[0]->Is<SpirvBlockAttribute>());
+    EXPECT_EQ(s->source.range.begin.line, 0u);
+    EXPECT_EQ(s->source.range.begin.column, 0u);
+    EXPECT_EQ(s->source.range.end.line, 0u);
+    EXPECT_EQ(s->source.range.end.column, 0u);
 }
 
 TEST_F(AstStructTest, CreationWithSourceAndAttributes) {
-  auto name = Sym("s");
-  auto* s = create<Struct>(
-      Source{Source::Range{Source::Location{27, 4}, Source::Location{27, 8}}},
-      name, StructMemberList{Member("a", ty.i32())},
-      AttributeList{ASTNodes().Create<SpirvBlockAttribute>(ID())});
-  EXPECT_EQ(s->name, name);
-  EXPECT_EQ(s->members.size(), 1u);
-  ASSERT_EQ(s->attributes.size(), 1u);
-  EXPECT_TRUE(s->attributes[0]->Is<SpirvBlockAttribute>());
-  EXPECT_EQ(s->source.range.begin.line, 27u);
-  EXPECT_EQ(s->source.range.begin.column, 4u);
-  EXPECT_EQ(s->source.range.end.line, 27u);
-  EXPECT_EQ(s->source.range.end.column, 8u);
+    auto name = Sym("s");
+    auto* s =
+        create<Struct>(Source{Source::Range{Source::Location{27, 4}, Source::Location{27, 8}}},
+                       name, StructMemberList{Member("a", ty.i32())},
+                       AttributeList{ASTNodes().Create<SpirvBlockAttribute>(ID())});
+    EXPECT_EQ(s->name, name);
+    EXPECT_EQ(s->members.size(), 1u);
+    ASSERT_EQ(s->attributes.size(), 1u);
+    EXPECT_TRUE(s->attributes[0]->Is<SpirvBlockAttribute>());
+    EXPECT_EQ(s->source.range.begin.line, 27u);
+    EXPECT_EQ(s->source.range.begin.column, 4u);
+    EXPECT_EQ(s->source.range.end.line, 27u);
+    EXPECT_EQ(s->source.range.end.column, 8u);
 }
 
 TEST_F(AstStructTest, Assert_Null_StructMember) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.create<Struct>(b.Sym("S"),
-                         StructMemberList{b.Member("a", b.ty.i32()), nullptr},
-                         AttributeList{});
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.create<Struct>(b.Sym("S"), StructMemberList{b.Member("a", b.ty.i32()), nullptr},
+                             AttributeList{});
+        },
+        "internal compiler error");
 }
 
 TEST_F(AstStructTest, Assert_Null_Attribute) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.create<Struct>(b.Sym("S"),
-                         StructMemberList{b.Member("a", b.ty.i32())},
-                         AttributeList{nullptr});
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.create<Struct>(b.Sym("S"), StructMemberList{b.Member("a", b.ty.i32())},
+                             AttributeList{nullptr});
+        },
+        "internal compiler error");
 }
 
 TEST_F(AstStructTest, Assert_DifferentProgramID_StructMember) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.create<Struct>(b1.Sym("S"),
-                          StructMemberList{b2.Member("a", b2.ty.i32())},
-                          AttributeList{});
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.create<Struct>(b1.Sym("S"), StructMemberList{b2.Member("a", b2.ty.i32())},
+                              AttributeList{});
+        },
+        "internal compiler error");
 }
 
 TEST_F(AstStructTest, Assert_DifferentProgramID_Attribute) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.create<Struct>(
-            b1.Sym("S"), StructMemberList{b1.Member("a", b1.ty.i32())},
-            AttributeList{b2.ASTNodes().Create<SpirvBlockAttribute>(b2.ID())});
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.create<Struct>(b1.Sym("S"), StructMemberList{b1.Member("a", b1.ty.i32())},
+                              AttributeList{b2.ASTNodes().Create<SpirvBlockAttribute>(b2.ID())});
+        },
+        "internal compiler error");
 }
 
 }  // namespace
diff --git a/src/tint/ast/switch_statement.cc b/src/tint/ast/switch_statement.cc
index 13c455a..08095a1 100644
--- a/src/tint/ast/switch_statement.cc
+++ b/src/tint/ast/switch_statement.cc
@@ -25,12 +25,12 @@
                                  const Expression* cond,
                                  CaseStatementList b)
     : Base(pid, src), condition(cond), body(b) {
-  TINT_ASSERT(AST, condition);
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, condition, program_id);
-  for (auto* stmt : body) {
-    TINT_ASSERT(AST, stmt);
-    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, stmt, program_id);
-  }
+    TINT_ASSERT(AST, condition);
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, condition, program_id);
+    for (auto* stmt : body) {
+        TINT_ASSERT(AST, stmt);
+        TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, stmt, program_id);
+    }
 }
 
 SwitchStatement::SwitchStatement(SwitchStatement&&) = default;
@@ -38,11 +38,11 @@
 SwitchStatement::~SwitchStatement() = default;
 
 const SwitchStatement* SwitchStatement::Clone(CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  auto* cond = ctx->Clone(condition);
-  auto b = ctx->Clone(body);
-  return ctx->dst->create<SwitchStatement>(src, cond, b);
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    auto* cond = ctx->Clone(condition);
+    auto b = ctx->Clone(body);
+    return ctx->dst->create<SwitchStatement>(src, cond, b);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/switch_statement.h b/src/tint/ast/switch_statement.h
index 34394c8..5ac13b7 100644
--- a/src/tint/ast/switch_statement.h
+++ b/src/tint/ast/switch_statement.h
@@ -22,35 +22,35 @@
 
 /// A switch statement
 class SwitchStatement final : public Castable<SwitchStatement, Statement> {
- public:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  /// @param condition the switch condition
-  /// @param body the switch body
-  SwitchStatement(ProgramID pid,
-                  const Source& src,
-                  const Expression* condition,
-                  CaseStatementList body);
-  /// Move constructor
-  SwitchStatement(SwitchStatement&&);
-  ~SwitchStatement() override;
+  public:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    /// @param condition the switch condition
+    /// @param body the switch body
+    SwitchStatement(ProgramID pid,
+                    const Source& src,
+                    const Expression* condition,
+                    CaseStatementList body);
+    /// Move constructor
+    SwitchStatement(SwitchStatement&&);
+    ~SwitchStatement() override;
 
-  /// @returns true if this is a default statement
-  bool IsDefault() const { return condition == nullptr; }
+    /// @returns true if this is a default statement
+    bool IsDefault() const { return condition == nullptr; }
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const SwitchStatement* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const SwitchStatement* Clone(CloneContext* ctx) const override;
 
-  /// The switch condition or nullptr if none set
-  const Expression* const condition;
+    /// The switch condition or nullptr if none set
+    const Expression* const condition;
 
-  /// The Switch body
-  const CaseStatementList body;
-  SwitchStatement(const SwitchStatement&) = delete;
+    /// The Switch body
+    const CaseStatementList body;
+    SwitchStatement(const SwitchStatement&) = delete;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/switch_statement_test.cc b/src/tint/ast/switch_statement_test.cc
index 3b927ce..19d1cfb 100644
--- a/src/tint/ast/switch_statement_test.cc
+++ b/src/tint/ast/switch_statement_test.cc
@@ -17,99 +17,100 @@
 #include "gtest/gtest-spi.h"
 #include "src/tint/ast/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::ast {
 namespace {
 
 using SwitchStatementTest = TestHelper;
 
 TEST_F(SwitchStatementTest, Creation) {
-  CaseSelectorList lit;
-  lit.push_back(create<SintLiteralExpression>(1));
+    CaseSelectorList lit;
+    lit.push_back(Expr(1_u));
 
-  auto* ident = Expr("ident");
-  CaseStatementList body;
-  auto* case_stmt = create<CaseStatement>(lit, Block());
-  body.push_back(case_stmt);
+    auto* ident = Expr("ident");
+    CaseStatementList body;
+    auto* case_stmt = create<CaseStatement>(lit, Block());
+    body.push_back(case_stmt);
 
-  auto* stmt = create<SwitchStatement>(ident, body);
-  EXPECT_EQ(stmt->condition, ident);
-  ASSERT_EQ(stmt->body.size(), 1u);
-  EXPECT_EQ(stmt->body[0], case_stmt);
+    auto* stmt = create<SwitchStatement>(ident, body);
+    EXPECT_EQ(stmt->condition, ident);
+    ASSERT_EQ(stmt->body.size(), 1u);
+    EXPECT_EQ(stmt->body[0], case_stmt);
 }
 
 TEST_F(SwitchStatementTest, Creation_WithSource) {
-  auto* ident = Expr("ident");
+    auto* ident = Expr("ident");
 
-  auto* stmt = create<SwitchStatement>(Source{Source::Location{20, 2}}, ident,
-                                       CaseStatementList());
-  auto src = stmt->source;
-  EXPECT_EQ(src.range.begin.line, 20u);
-  EXPECT_EQ(src.range.begin.column, 2u);
+    auto* stmt =
+        create<SwitchStatement>(Source{Source::Location{20, 2}}, ident, CaseStatementList());
+    auto src = stmt->source;
+    EXPECT_EQ(src.range.begin.line, 20u);
+    EXPECT_EQ(src.range.begin.column, 2u);
 }
 
 TEST_F(SwitchStatementTest, IsSwitch) {
-  CaseSelectorList lit;
-  lit.push_back(create<SintLiteralExpression>(2));
+    CaseSelectorList lit;
+    lit.push_back(Expr(2_i));
 
-  auto* ident = Expr("ident");
-  CaseStatementList body;
-  body.push_back(create<CaseStatement>(lit, Block()));
+    auto* ident = Expr("ident");
+    CaseStatementList body;
+    body.push_back(create<CaseStatement>(lit, Block()));
 
-  auto* stmt = create<SwitchStatement>(ident, body);
-  EXPECT_TRUE(stmt->Is<SwitchStatement>());
+    auto* stmt = create<SwitchStatement>(ident, body);
+    EXPECT_TRUE(stmt->Is<SwitchStatement>());
 }
 
 TEST_F(SwitchStatementTest, Assert_Null_Condition) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        CaseStatementList cases;
-        cases.push_back(
-            b.create<CaseStatement>(CaseSelectorList{b.Expr(1)}, b.Block()));
-        b.create<SwitchStatement>(nullptr, cases);
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            CaseStatementList cases;
+            cases.push_back(b.create<CaseStatement>(CaseSelectorList{b.Expr(1_i)}, b.Block()));
+            b.create<SwitchStatement>(nullptr, cases);
+        },
+        "internal compiler error");
 }
 
 TEST_F(SwitchStatementTest, Assert_Null_CaseStatement) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.create<SwitchStatement>(b.Expr(true), CaseStatementList{nullptr});
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.create<SwitchStatement>(b.Expr(true), CaseStatementList{nullptr});
+        },
+        "internal compiler error");
 }
 
 TEST_F(SwitchStatementTest, Assert_DifferentProgramID_Condition) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.create<SwitchStatement>(b2.Expr(true), CaseStatementList{
-                                                      b1.create<CaseStatement>(
-                                                          CaseSelectorList{
-                                                              b1.Expr(1),
-                                                          },
-                                                          b1.Block()),
-                                                  });
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.create<SwitchStatement>(b2.Expr(true), CaseStatementList{
+                                                          b1.create<CaseStatement>(
+                                                              CaseSelectorList{
+                                                                  b1.Expr(1_i),
+                                                              },
+                                                              b1.Block()),
+                                                      });
+        },
+        "internal compiler error");
 }
 
 TEST_F(SwitchStatementTest, Assert_DifferentProgramID_CaseStatement) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.create<SwitchStatement>(b1.Expr(true), CaseStatementList{
-                                                      b2.create<CaseStatement>(
-                                                          CaseSelectorList{
-                                                              b2.Expr(1),
-                                                          },
-                                                          b2.Block()),
-                                                  });
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.create<SwitchStatement>(b1.Expr(true), CaseStatementList{
+                                                          b2.create<CaseStatement>(
+                                                              CaseSelectorList{
+                                                                  b2.Expr(1_i),
+                                                              },
+                                                              b2.Block()),
+                                                      });
+        },
+        "internal compiler error");
 }
 
 }  // namespace
diff --git a/src/tint/ast/texture.cc b/src/tint/ast/texture.cc
index d88db6e..27eb094 100644
--- a/src/tint/ast/texture.cc
+++ b/src/tint/ast/texture.cc
@@ -19,66 +19,65 @@
 namespace tint::ast {
 
 std::ostream& operator<<(std::ostream& out, TextureDimension dim) {
-  switch (dim) {
-    case TextureDimension::kNone:
-      out << "None";
-      break;
-    case TextureDimension::k1d:
-      out << "1d";
-      break;
-    case TextureDimension::k2d:
-      out << "2d";
-      break;
-    case TextureDimension::k2dArray:
-      out << "2d_array";
-      break;
-    case TextureDimension::k3d:
-      out << "3d";
-      break;
-    case TextureDimension::kCube:
-      out << "cube";
-      break;
-    case TextureDimension::kCubeArray:
-      out << "cube_array";
-      break;
-  }
-  return out;
+    switch (dim) {
+        case TextureDimension::kNone:
+            out << "None";
+            break;
+        case TextureDimension::k1d:
+            out << "1d";
+            break;
+        case TextureDimension::k2d:
+            out << "2d";
+            break;
+        case TextureDimension::k2dArray:
+            out << "2d_array";
+            break;
+        case TextureDimension::k3d:
+            out << "3d";
+            break;
+        case TextureDimension::kCube:
+            out << "cube";
+            break;
+        case TextureDimension::kCubeArray:
+            out << "cube_array";
+            break;
+    }
+    return out;
 }
 
 bool IsTextureArray(TextureDimension dim) {
-  switch (dim) {
-    case TextureDimension::k2dArray:
-    case TextureDimension::kCubeArray:
-      return true;
-    case TextureDimension::k2d:
-    case TextureDimension::kNone:
-    case TextureDimension::k1d:
-    case TextureDimension::k3d:
-    case TextureDimension::kCube:
-      return false;
-  }
-  return false;
+    switch (dim) {
+        case TextureDimension::k2dArray:
+        case TextureDimension::kCubeArray:
+            return true;
+        case TextureDimension::k2d:
+        case TextureDimension::kNone:
+        case TextureDimension::k1d:
+        case TextureDimension::k3d:
+        case TextureDimension::kCube:
+            return false;
+    }
+    return false;
 }
 
 int NumCoordinateAxes(TextureDimension dim) {
-  switch (dim) {
-    case TextureDimension::kNone:
-      return 0;
-    case TextureDimension::k1d:
-      return 1;
-    case TextureDimension::k2d:
-    case TextureDimension::k2dArray:
-      return 2;
-    case TextureDimension::k3d:
-    case TextureDimension::kCube:
-    case TextureDimension::kCubeArray:
-      return 3;
-  }
-  return 0;
+    switch (dim) {
+        case TextureDimension::kNone:
+            return 0;
+        case TextureDimension::k1d:
+            return 1;
+        case TextureDimension::k2d:
+        case TextureDimension::k2dArray:
+            return 2;
+        case TextureDimension::k3d:
+        case TextureDimension::kCube:
+        case TextureDimension::kCubeArray:
+            return 3;
+    }
+    return 0;
 }
 
-Texture::Texture(ProgramID pid, const Source& src, TextureDimension d)
-    : Base(pid, src), dim(d) {}
+Texture::Texture(ProgramID pid, const Source& src, TextureDimension d) : Base(pid, src), dim(d) {}
 
 Texture::Texture(Texture&&) = default;
 
diff --git a/src/tint/ast/texture.h b/src/tint/ast/texture.h
index 716cdf0..9a4199b 100644
--- a/src/tint/ast/texture.h
+++ b/src/tint/ast/texture.h
@@ -21,20 +21,20 @@
 
 /// The dimensionality of the texture
 enum class TextureDimension {
-  /// Invalid texture
-  kNone = -1,
-  /// 1 dimensional texture
-  k1d,
-  /// 2 dimensional texture
-  k2d,
-  /// 2 dimensional array texture
-  k2dArray,
-  /// 3 dimensional texture
-  k3d,
-  /// cube texture
-  kCube,
-  /// cube array texture
-  kCubeArray,
+    /// Invalid texture
+    kNone = -1,
+    /// 1 dimensional texture
+    k1d,
+    /// 2 dimensional texture
+    k2d,
+    /// 2 dimensional array texture
+    k2dArray,
+    /// 3 dimensional texture
+    k3d,
+    /// cube texture
+    kCube,
+    /// cube array texture
+    kCubeArray,
 };
 
 /// @param out the std::ostream to write to
@@ -62,18 +62,18 @@
 
 /// A texture type.
 class Texture : public Castable<Texture, Type> {
- public:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  /// @param dim the dimensionality of the texture
-  Texture(ProgramID pid, const Source& src, TextureDimension dim);
-  /// Move constructor
-  Texture(Texture&&);
-  ~Texture() override;
+  public:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    /// @param dim the dimensionality of the texture
+    Texture(ProgramID pid, const Source& src, TextureDimension dim);
+    /// Move constructor
+    Texture(Texture&&);
+    ~Texture() override;
 
-  /// The texture dimension
-  const TextureDimension dim;
+    /// The texture dimension
+    const TextureDimension dim;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/texture_test.cc b/src/tint/ast/texture_test.cc
index 84298b8..7b7c0b0 100644
--- a/src/tint/ast/texture_test.cc
+++ b/src/tint/ast/texture_test.cc
@@ -33,23 +33,23 @@
 using AstTextureTypeTest = TestHelper;
 
 TEST_F(AstTextureTypeTest, IsTextureArray) {
-  EXPECT_EQ(false, IsTextureArray(TextureDimension::kNone));
-  EXPECT_EQ(false, IsTextureArray(TextureDimension::k1d));
-  EXPECT_EQ(false, IsTextureArray(TextureDimension::k2d));
-  EXPECT_EQ(true, IsTextureArray(TextureDimension::k2dArray));
-  EXPECT_EQ(false, IsTextureArray(TextureDimension::k3d));
-  EXPECT_EQ(false, IsTextureArray(TextureDimension::kCube));
-  EXPECT_EQ(true, IsTextureArray(TextureDimension::kCubeArray));
+    EXPECT_EQ(false, IsTextureArray(TextureDimension::kNone));
+    EXPECT_EQ(false, IsTextureArray(TextureDimension::k1d));
+    EXPECT_EQ(false, IsTextureArray(TextureDimension::k2d));
+    EXPECT_EQ(true, IsTextureArray(TextureDimension::k2dArray));
+    EXPECT_EQ(false, IsTextureArray(TextureDimension::k3d));
+    EXPECT_EQ(false, IsTextureArray(TextureDimension::kCube));
+    EXPECT_EQ(true, IsTextureArray(TextureDimension::kCubeArray));
 }
 
 TEST_F(AstTextureTypeTest, NumCoordinateAxes) {
-  EXPECT_EQ(0, NumCoordinateAxes(TextureDimension::kNone));
-  EXPECT_EQ(1, NumCoordinateAxes(TextureDimension::k1d));
-  EXPECT_EQ(2, NumCoordinateAxes(TextureDimension::k2d));
-  EXPECT_EQ(2, NumCoordinateAxes(TextureDimension::k2dArray));
-  EXPECT_EQ(3, NumCoordinateAxes(TextureDimension::k3d));
-  EXPECT_EQ(3, NumCoordinateAxes(TextureDimension::kCube));
-  EXPECT_EQ(3, NumCoordinateAxes(TextureDimension::kCubeArray));
+    EXPECT_EQ(0, NumCoordinateAxes(TextureDimension::kNone));
+    EXPECT_EQ(1, NumCoordinateAxes(TextureDimension::k1d));
+    EXPECT_EQ(2, NumCoordinateAxes(TextureDimension::k2d));
+    EXPECT_EQ(2, NumCoordinateAxes(TextureDimension::k2dArray));
+    EXPECT_EQ(3, NumCoordinateAxes(TextureDimension::k3d));
+    EXPECT_EQ(3, NumCoordinateAxes(TextureDimension::kCube));
+    EXPECT_EQ(3, NumCoordinateAxes(TextureDimension::kCubeArray));
 }
 
 }  // namespace
diff --git a/src/tint/ast/traverse_expressions.h b/src/tint/ast/traverse_expressions.h
index 77f27a2..650273b 100644
--- a/src/tint/ast/traverse_expressions.h
+++ b/src/tint/ast/traverse_expressions.h
@@ -32,20 +32,20 @@
 /// The action to perform after calling the TraverseExpressions() callback
 /// function.
 enum class TraverseAction {
-  /// Stop traversal immediately.
-  Stop,
-  /// Descend into this expression.
-  Descend,
-  /// Do not descend into this expression.
-  Skip,
+    /// Stop traversal immediately.
+    Stop,
+    /// Descend into this expression.
+    Descend,
+    /// Do not descend into this expression.
+    Skip,
 };
 
 /// The order TraverseExpressions() will traverse expressions
 enum class TraverseOrder {
-  /// Expressions will be traversed from left to right
-  LeftToRight,
-  /// Expressions will be traversed from right to left
-  RightToLeft,
+    /// Expressions will be traversed from left to right
+    LeftToRight,
+    /// Expressions will be traversed from right to left
+    RightToLeft,
 };
 
 /// TraverseExpressions performs a depth-first traversal of the expression nodes
@@ -57,94 +57,89 @@
 ///        `TraverseAction(const T*)` where T is an ast::Expression type.
 /// @return true on success, false on error
 template <TraverseOrder ORDER = TraverseOrder::LeftToRight, typename CALLBACK>
-bool TraverseExpressions(const ast::Expression* root,
-                         diag::List& diags,
-                         CALLBACK&& callback) {
-  using EXPR_TYPE = std::remove_pointer_t<traits::ParameterType<CALLBACK, 0>>;
-  std::vector<const ast::Expression*> to_visit{root};
+bool TraverseExpressions(const ast::Expression* root, diag::List& diags, CALLBACK&& callback) {
+    using EXPR_TYPE = std::remove_pointer_t<traits::ParameterType<CALLBACK, 0>>;
+    std::vector<const ast::Expression*> to_visit{root};
 
-  auto push_pair = [&](const ast::Expression* left,
-                       const ast::Expression* right) {
-    if (ORDER == TraverseOrder::LeftToRight) {
-      to_visit.push_back(right);
-      to_visit.push_back(left);
-    } else {
-      to_visit.push_back(left);
-      to_visit.push_back(right);
-    }
-  };
-  auto push_list = [&](const std::vector<const ast::Expression*>& exprs) {
-    if (ORDER == TraverseOrder::LeftToRight) {
-      for (auto* expr : utils::Reverse(exprs)) {
-        to_visit.push_back(expr);
-      }
-    } else {
-      for (auto* expr : exprs) {
-        to_visit.push_back(expr);
-      }
-    }
-  };
+    auto push_pair = [&](const ast::Expression* left, const ast::Expression* right) {
+        if (ORDER == TraverseOrder::LeftToRight) {
+            to_visit.push_back(right);
+            to_visit.push_back(left);
+        } else {
+            to_visit.push_back(left);
+            to_visit.push_back(right);
+        }
+    };
+    auto push_list = [&](const std::vector<const ast::Expression*>& exprs) {
+        if (ORDER == TraverseOrder::LeftToRight) {
+            for (auto* expr : utils::Reverse(exprs)) {
+                to_visit.push_back(expr);
+            }
+        } else {
+            for (auto* expr : exprs) {
+                to_visit.push_back(expr);
+            }
+        }
+    };
 
-  while (!to_visit.empty()) {
-    auto* expr = to_visit.back();
-    to_visit.pop_back();
+    while (!to_visit.empty()) {
+        auto* expr = to_visit.back();
+        to_visit.pop_back();
 
-    if (auto* filtered = expr->As<EXPR_TYPE>()) {
-      switch (callback(filtered)) {
-        case TraverseAction::Stop:
-          return true;
-        case TraverseAction::Skip:
-          continue;
-        case TraverseAction::Descend:
-          break;
-      }
-    }
+        if (auto* filtered = expr->As<EXPR_TYPE>()) {
+            switch (callback(filtered)) {
+                case TraverseAction::Stop:
+                    return true;
+                case TraverseAction::Skip:
+                    continue;
+                case TraverseAction::Descend:
+                    break;
+            }
+        }
 
-    bool ok = Switch(
-        expr,
-        [&](const IndexAccessorExpression* idx) {
-          push_pair(idx->object, idx->index);
-          return true;
-        },
-        [&](const BinaryExpression* bin_op) {
-          push_pair(bin_op->lhs, bin_op->rhs);
-          return true;
-        },
-        [&](const BitcastExpression* bitcast) {
-          to_visit.push_back(bitcast->expr);
-          return true;
-        },
-        [&](const CallExpression* call) {
-          // TODO(crbug.com/tint/1257): Resolver breaks if we actually include
-          // the function name in the traversal. to_visit.push_back(call->func);
-          push_list(call->args);
-          return true;
-        },
-        [&](const MemberAccessorExpression* member) {
-          // TODO(crbug.com/tint/1257): Resolver breaks if we actually include
-          // the member name in the traversal. push_pair(member->structure,
-          // member->member);
-          to_visit.push_back(member->structure);
-          return true;
-        },
-        [&](const UnaryOpExpression* unary) {
-          to_visit.push_back(unary->expr);
-          return true;
-        },
-        [&](Default) {
-          if (expr->IsAnyOf<LiteralExpression, IdentifierExpression,
-                            PhonyExpression>()) {
-            return true;  // Leaf expression
-          }
-          TINT_ICE(AST, diags)
-              << "unhandled expression type: " << expr->TypeInfo().name;
-          return false;
-        });
-    if (!ok) {
-      return false;
+        bool ok = Switch(
+            expr,
+            [&](const IndexAccessorExpression* idx) {
+                push_pair(idx->object, idx->index);
+                return true;
+            },
+            [&](const BinaryExpression* bin_op) {
+                push_pair(bin_op->lhs, bin_op->rhs);
+                return true;
+            },
+            [&](const BitcastExpression* bitcast) {
+                to_visit.push_back(bitcast->expr);
+                return true;
+            },
+            [&](const CallExpression* call) {
+                // TODO(crbug.com/tint/1257): Resolver breaks if we actually include
+                // the function name in the traversal. to_visit.push_back(call->func);
+                push_list(call->args);
+                return true;
+            },
+            [&](const MemberAccessorExpression* member) {
+                // TODO(crbug.com/tint/1257): Resolver breaks if we actually include
+                // the member name in the traversal. push_pair(member->structure,
+                // member->member);
+                to_visit.push_back(member->structure);
+                return true;
+            },
+            [&](const UnaryOpExpression* unary) {
+                to_visit.push_back(unary->expr);
+                return true;
+            },
+            [&](Default) {
+                if (expr->IsAnyOf<LiteralExpression, IdentifierExpression, PhonyExpression>()) {
+                    return true;  // Leaf expression
+                }
+                TINT_ICE(AST, diags) << "unhandled expression type: " << expr->TypeInfo().name;
+                return false;
+            });
+        if (!ok) {
+            return false;
+        }
     }
-  }
-  return true;
+    return true;
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/traverse_expressions_test.cc b/src/tint/ast/traverse_expressions_test.cc
index cacc93f..622a7ff 100644
--- a/src/tint/ast/traverse_expressions_test.cc
+++ b/src/tint/ast/traverse_expressions_test.cc
@@ -16,219 +16,215 @@
 #include "gmock/gmock.h"
 #include "src/tint/ast/test_helper.h"
 
+using ::testing::ElementsAre;
+
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::ast {
 namespace {
 
-using ::testing::ElementsAre;
-
 using TraverseExpressionsTest = TestHelper;
 
 TEST_F(TraverseExpressionsTest, DescendIndexAccessor) {
-  std::vector<const ast::Expression*> e = {Expr(1), Expr(1), Expr(1), Expr(1)};
-  std::vector<const ast::Expression*> i = {IndexAccessor(e[0], e[1]),
-                                           IndexAccessor(e[2], e[3])};
-  auto* root = IndexAccessor(i[0], i[1]);
-  {
-    std::vector<const ast::Expression*> l2r;
-    TraverseExpressions<TraverseOrder::LeftToRight>(
-        root, Diagnostics(), [&](const ast::Expression* expr) {
-          l2r.push_back(expr);
-          return ast::TraverseAction::Descend;
-        });
-    EXPECT_THAT(l2r, ElementsAre(root, i[0], e[0], e[1], i[1], e[2], e[3]));
-  }
-  {
-    std::vector<const ast::Expression*> r2l;
-    TraverseExpressions<TraverseOrder::RightToLeft>(
-        root, Diagnostics(), [&](const ast::Expression* expr) {
-          r2l.push_back(expr);
-          return ast::TraverseAction::Descend;
-        });
-    EXPECT_THAT(r2l, ElementsAre(root, i[1], e[3], e[2], i[0], e[1], e[0]));
-  }
+    std::vector<const ast::Expression*> e = {Expr(1_i), Expr(1_i), Expr(1_i), Expr(1_i)};
+    std::vector<const ast::Expression*> i = {IndexAccessor(e[0], e[1]), IndexAccessor(e[2], e[3])};
+    auto* root = IndexAccessor(i[0], i[1]);
+    {
+        std::vector<const ast::Expression*> l2r;
+        TraverseExpressions<TraverseOrder::LeftToRight>(root, Diagnostics(),
+                                                        [&](const ast::Expression* expr) {
+                                                            l2r.push_back(expr);
+                                                            return ast::TraverseAction::Descend;
+                                                        });
+        EXPECT_THAT(l2r, ElementsAre(root, i[0], e[0], e[1], i[1], e[2], e[3]));
+    }
+    {
+        std::vector<const ast::Expression*> r2l;
+        TraverseExpressions<TraverseOrder::RightToLeft>(root, Diagnostics(),
+                                                        [&](const ast::Expression* expr) {
+                                                            r2l.push_back(expr);
+                                                            return ast::TraverseAction::Descend;
+                                                        });
+        EXPECT_THAT(r2l, ElementsAre(root, i[1], e[3], e[2], i[0], e[1], e[0]));
+    }
 }
 
 TEST_F(TraverseExpressionsTest, DescendBinaryExpression) {
-  std::vector<const ast::Expression*> e = {Expr(1), Expr(1), Expr(1), Expr(1)};
-  std::vector<const ast::Expression*> i = {Add(e[0], e[1]), Sub(e[2], e[3])};
-  auto* root = Mul(i[0], i[1]);
-  {
-    std::vector<const ast::Expression*> l2r;
-    TraverseExpressions<TraverseOrder::LeftToRight>(
-        root, Diagnostics(), [&](const ast::Expression* expr) {
-          l2r.push_back(expr);
-          return ast::TraverseAction::Descend;
-        });
-    EXPECT_THAT(l2r, ElementsAre(root, i[0], e[0], e[1], i[1], e[2], e[3]));
-  }
-  {
-    std::vector<const ast::Expression*> r2l;
-    TraverseExpressions<TraverseOrder::RightToLeft>(
-        root, Diagnostics(), [&](const ast::Expression* expr) {
-          r2l.push_back(expr);
-          return ast::TraverseAction::Descend;
-        });
-    EXPECT_THAT(r2l, ElementsAre(root, i[1], e[3], e[2], i[0], e[1], e[0]));
-  }
+    std::vector<const ast::Expression*> e = {Expr(1_i), Expr(1_i), Expr(1_i), Expr(1_i)};
+    std::vector<const ast::Expression*> i = {Add(e[0], e[1]), Sub(e[2], e[3])};
+    auto* root = Mul(i[0], i[1]);
+    {
+        std::vector<const ast::Expression*> l2r;
+        TraverseExpressions<TraverseOrder::LeftToRight>(root, Diagnostics(),
+                                                        [&](const ast::Expression* expr) {
+                                                            l2r.push_back(expr);
+                                                            return ast::TraverseAction::Descend;
+                                                        });
+        EXPECT_THAT(l2r, ElementsAre(root, i[0], e[0], e[1], i[1], e[2], e[3]));
+    }
+    {
+        std::vector<const ast::Expression*> r2l;
+        TraverseExpressions<TraverseOrder::RightToLeft>(root, Diagnostics(),
+                                                        [&](const ast::Expression* expr) {
+                                                            r2l.push_back(expr);
+                                                            return ast::TraverseAction::Descend;
+                                                        });
+        EXPECT_THAT(r2l, ElementsAre(root, i[1], e[3], e[2], i[0], e[1], e[0]));
+    }
 }
 
 TEST_F(TraverseExpressionsTest, DescendBitcastExpression) {
-  auto* e = Expr(1);
-  auto* b0 = Bitcast<i32>(e);
-  auto* b1 = Bitcast<i32>(b0);
-  auto* b2 = Bitcast<i32>(b1);
-  auto* root = Bitcast<i32>(b2);
-  {
-    std::vector<const ast::Expression*> l2r;
-    TraverseExpressions<TraverseOrder::LeftToRight>(
-        root, Diagnostics(), [&](const ast::Expression* expr) {
-          l2r.push_back(expr);
-          return ast::TraverseAction::Descend;
-        });
-    EXPECT_THAT(l2r, ElementsAre(root, b2, b1, b0, e));
-  }
-  {
-    std::vector<const ast::Expression*> r2l;
-    TraverseExpressions<TraverseOrder::RightToLeft>(
-        root, Diagnostics(), [&](const ast::Expression* expr) {
-          r2l.push_back(expr);
-          return ast::TraverseAction::Descend;
-        });
-    EXPECT_THAT(r2l, ElementsAre(root, b2, b1, b0, e));
-  }
+    auto* e = Expr(1_i);
+    auto* b0 = Bitcast<i32>(e);
+    auto* b1 = Bitcast<i32>(b0);
+    auto* b2 = Bitcast<i32>(b1);
+    auto* root = Bitcast<i32>(b2);
+    {
+        std::vector<const ast::Expression*> l2r;
+        TraverseExpressions<TraverseOrder::LeftToRight>(root, Diagnostics(),
+                                                        [&](const ast::Expression* expr) {
+                                                            l2r.push_back(expr);
+                                                            return ast::TraverseAction::Descend;
+                                                        });
+        EXPECT_THAT(l2r, ElementsAre(root, b2, b1, b0, e));
+    }
+    {
+        std::vector<const ast::Expression*> r2l;
+        TraverseExpressions<TraverseOrder::RightToLeft>(root, Diagnostics(),
+                                                        [&](const ast::Expression* expr) {
+                                                            r2l.push_back(expr);
+                                                            return ast::TraverseAction::Descend;
+                                                        });
+        EXPECT_THAT(r2l, ElementsAre(root, b2, b1, b0, e));
+    }
 }
 
 TEST_F(TraverseExpressionsTest, DescendCallExpression) {
-  std::vector<const ast::Expression*> e = {Expr(1), Expr(1), Expr(1), Expr(1)};
-  std::vector<const ast::Expression*> c = {Call("a", e[0], e[1]),
-                                           Call("b", e[2], e[3])};
-  auto* root = Call("c", c[0], c[1]);
-  {
-    std::vector<const ast::Expression*> l2r;
-    TraverseExpressions<TraverseOrder::LeftToRight>(
-        root, Diagnostics(), [&](const ast::Expression* expr) {
-          l2r.push_back(expr);
-          return ast::TraverseAction::Descend;
-        });
-    EXPECT_THAT(l2r, ElementsAre(root, c[0], e[0], e[1], c[1], e[2], e[3]));
-  }
-  {
-    std::vector<const ast::Expression*> r2l;
-    TraverseExpressions<TraverseOrder::RightToLeft>(
-        root, Diagnostics(), [&](const ast::Expression* expr) {
-          r2l.push_back(expr);
-          return ast::TraverseAction::Descend;
-        });
-    EXPECT_THAT(r2l, ElementsAre(root, c[1], e[3], e[2], c[0], e[1], e[0]));
-  }
+    std::vector<const ast::Expression*> e = {Expr(1_i), Expr(1_i), Expr(1_i), Expr(1_i)};
+    std::vector<const ast::Expression*> c = {Call("a", e[0], e[1]), Call("b", e[2], e[3])};
+    auto* root = Call("c", c[0], c[1]);
+    {
+        std::vector<const ast::Expression*> l2r;
+        TraverseExpressions<TraverseOrder::LeftToRight>(root, Diagnostics(),
+                                                        [&](const ast::Expression* expr) {
+                                                            l2r.push_back(expr);
+                                                            return ast::TraverseAction::Descend;
+                                                        });
+        EXPECT_THAT(l2r, ElementsAre(root, c[0], e[0], e[1], c[1], e[2], e[3]));
+    }
+    {
+        std::vector<const ast::Expression*> r2l;
+        TraverseExpressions<TraverseOrder::RightToLeft>(root, Diagnostics(),
+                                                        [&](const ast::Expression* expr) {
+                                                            r2l.push_back(expr);
+                                                            return ast::TraverseAction::Descend;
+                                                        });
+        EXPECT_THAT(r2l, ElementsAre(root, c[1], e[3], e[2], c[0], e[1], e[0]));
+    }
 }
 
 // TODO(crbug.com/tint/1257): Test ignores member accessor 'member' field.
 // Replace with the test below when fixed.
 TEST_F(TraverseExpressionsTest, DescendMemberIndexExpression) {
-  auto* e = Expr(1);
-  auto* m = MemberAccessor(e, Expr("a"));
-  auto* root = MemberAccessor(m, Expr("b"));
-  {
-    std::vector<const ast::Expression*> l2r;
-    TraverseExpressions<TraverseOrder::LeftToRight>(
-        root, Diagnostics(), [&](const ast::Expression* expr) {
-          l2r.push_back(expr);
-          return ast::TraverseAction::Descend;
-        });
-    EXPECT_THAT(l2r, ElementsAre(root, m, e));
-  }
-  {
-    std::vector<const ast::Expression*> r2l;
-    TraverseExpressions<TraverseOrder::RightToLeft>(
-        root, Diagnostics(), [&](const ast::Expression* expr) {
-          r2l.push_back(expr);
-          return ast::TraverseAction::Descend;
-        });
-    EXPECT_THAT(r2l, ElementsAre(root, m, e));
-  }
+    auto* e = Expr(1_i);
+    auto* m = MemberAccessor(e, Expr("a"));
+    auto* root = MemberAccessor(m, Expr("b"));
+    {
+        std::vector<const ast::Expression*> l2r;
+        TraverseExpressions<TraverseOrder::LeftToRight>(root, Diagnostics(),
+                                                        [&](const ast::Expression* expr) {
+                                                            l2r.push_back(expr);
+                                                            return ast::TraverseAction::Descend;
+                                                        });
+        EXPECT_THAT(l2r, ElementsAre(root, m, e));
+    }
+    {
+        std::vector<const ast::Expression*> r2l;
+        TraverseExpressions<TraverseOrder::RightToLeft>(root, Diagnostics(),
+                                                        [&](const ast::Expression* expr) {
+                                                            r2l.push_back(expr);
+                                                            return ast::TraverseAction::Descend;
+                                                        });
+        EXPECT_THAT(r2l, ElementsAre(root, m, e));
+    }
 }
 
 // TODO(crbug.com/tint/1257): The correct test for DescendMemberIndexExpression.
 TEST_F(TraverseExpressionsTest, DISABLED_DescendMemberIndexExpression) {
-  auto* e = Expr(1);
-  std::vector<const ast::IdentifierExpression*> i = {Expr("a"), Expr("b")};
-  auto* m = MemberAccessor(e, i[0]);
-  auto* root = MemberAccessor(m, i[1]);
-  {
-    std::vector<const ast::Expression*> l2r;
-    TraverseExpressions<TraverseOrder::LeftToRight>(
-        root, Diagnostics(), [&](const ast::Expression* expr) {
-          l2r.push_back(expr);
-          return ast::TraverseAction::Descend;
-        });
-    EXPECT_THAT(l2r, ElementsAre(root, m, e, i[0], i[1]));
-  }
-  {
-    std::vector<const ast::Expression*> r2l;
-    TraverseExpressions<TraverseOrder::RightToLeft>(
-        root, Diagnostics(), [&](const ast::Expression* expr) {
-          r2l.push_back(expr);
-          return ast::TraverseAction::Descend;
-        });
-    EXPECT_THAT(r2l, ElementsAre(root, i[1], m, i[0], e));
-  }
+    auto* e = Expr(1_i);
+    std::vector<const ast::IdentifierExpression*> i = {Expr("a"), Expr("b")};
+    auto* m = MemberAccessor(e, i[0]);
+    auto* root = MemberAccessor(m, i[1]);
+    {
+        std::vector<const ast::Expression*> l2r;
+        TraverseExpressions<TraverseOrder::LeftToRight>(root, Diagnostics(),
+                                                        [&](const ast::Expression* expr) {
+                                                            l2r.push_back(expr);
+                                                            return ast::TraverseAction::Descend;
+                                                        });
+        EXPECT_THAT(l2r, ElementsAre(root, m, e, i[0], i[1]));
+    }
+    {
+        std::vector<const ast::Expression*> r2l;
+        TraverseExpressions<TraverseOrder::RightToLeft>(root, Diagnostics(),
+                                                        [&](const ast::Expression* expr) {
+                                                            r2l.push_back(expr);
+                                                            return ast::TraverseAction::Descend;
+                                                        });
+        EXPECT_THAT(r2l, ElementsAre(root, i[1], m, i[0], e));
+    }
 }
 
 TEST_F(TraverseExpressionsTest, DescendUnaryExpression) {
-  auto* e = Expr(1);
-  auto* u0 = AddressOf(e);
-  auto* u1 = Deref(u0);
-  auto* u2 = AddressOf(u1);
-  auto* root = Deref(u2);
-  {
-    std::vector<const ast::Expression*> l2r;
-    TraverseExpressions<TraverseOrder::LeftToRight>(
-        root, Diagnostics(), [&](const ast::Expression* expr) {
-          l2r.push_back(expr);
-          return ast::TraverseAction::Descend;
-        });
-    EXPECT_THAT(l2r, ElementsAre(root, u2, u1, u0, e));
-  }
-  {
-    std::vector<const ast::Expression*> r2l;
-    TraverseExpressions<TraverseOrder::RightToLeft>(
-        root, Diagnostics(), [&](const ast::Expression* expr) {
-          r2l.push_back(expr);
-          return ast::TraverseAction::Descend;
-        });
-    EXPECT_THAT(r2l, ElementsAre(root, u2, u1, u0, e));
-  }
+    auto* e = Expr(1_i);
+    auto* u0 = AddressOf(e);
+    auto* u1 = Deref(u0);
+    auto* u2 = AddressOf(u1);
+    auto* root = Deref(u2);
+    {
+        std::vector<const ast::Expression*> l2r;
+        TraverseExpressions<TraverseOrder::LeftToRight>(root, Diagnostics(),
+                                                        [&](const ast::Expression* expr) {
+                                                            l2r.push_back(expr);
+                                                            return ast::TraverseAction::Descend;
+                                                        });
+        EXPECT_THAT(l2r, ElementsAre(root, u2, u1, u0, e));
+    }
+    {
+        std::vector<const ast::Expression*> r2l;
+        TraverseExpressions<TraverseOrder::RightToLeft>(root, Diagnostics(),
+                                                        [&](const ast::Expression* expr) {
+                                                            r2l.push_back(expr);
+                                                            return ast::TraverseAction::Descend;
+                                                        });
+        EXPECT_THAT(r2l, ElementsAre(root, u2, u1, u0, e));
+    }
 }
 
 TEST_F(TraverseExpressionsTest, Skip) {
-  std::vector<const ast::Expression*> e = {Expr(1), Expr(1), Expr(1), Expr(1)};
-  std::vector<const ast::Expression*> i = {IndexAccessor(e[0], e[1]),
-                                           IndexAccessor(e[2], e[3])};
-  auto* root = IndexAccessor(i[0], i[1]);
-  std::vector<const ast::Expression*> order;
-  TraverseExpressions<TraverseOrder::LeftToRight>(
-      root, Diagnostics(), [&](const ast::Expression* expr) {
-        order.push_back(expr);
-        return expr == i[0] ? ast::TraverseAction::Skip
-                            : ast::TraverseAction::Descend;
-      });
-  EXPECT_THAT(order, ElementsAre(root, i[0], i[1], e[2], e[3]));
+    std::vector<const ast::Expression*> e = {Expr(1_i), Expr(1_i), Expr(1_i), Expr(1_i)};
+    std::vector<const ast::Expression*> i = {IndexAccessor(e[0], e[1]), IndexAccessor(e[2], e[3])};
+    auto* root = IndexAccessor(i[0], i[1]);
+    std::vector<const ast::Expression*> order;
+    TraverseExpressions<TraverseOrder::LeftToRight>(
+        root, Diagnostics(), [&](const ast::Expression* expr) {
+            order.push_back(expr);
+            return expr == i[0] ? ast::TraverseAction::Skip : ast::TraverseAction::Descend;
+        });
+    EXPECT_THAT(order, ElementsAre(root, i[0], i[1], e[2], e[3]));
 }
 
 TEST_F(TraverseExpressionsTest, Stop) {
-  std::vector<const ast::Expression*> e = {Expr(1), Expr(1), Expr(1), Expr(1)};
-  std::vector<const ast::Expression*> i = {IndexAccessor(e[0], e[1]),
-                                           IndexAccessor(e[2], e[3])};
-  auto* root = IndexAccessor(i[0], i[1]);
-  std::vector<const ast::Expression*> order;
-  TraverseExpressions<TraverseOrder::LeftToRight>(
-      root, Diagnostics(), [&](const ast::Expression* expr) {
-        order.push_back(expr);
-        return expr == i[0] ? ast::TraverseAction::Stop
-                            : ast::TraverseAction::Descend;
-      });
-  EXPECT_THAT(order, ElementsAre(root, i[0]));
+    std::vector<const ast::Expression*> e = {Expr(1_i), Expr(1_i), Expr(1_i), Expr(1_i)};
+    std::vector<const ast::Expression*> i = {IndexAccessor(e[0], e[1]), IndexAccessor(e[2], e[3])};
+    auto* root = IndexAccessor(i[0], i[1]);
+    std::vector<const ast::Expression*> order;
+    TraverseExpressions<TraverseOrder::LeftToRight>(
+        root, Diagnostics(), [&](const ast::Expression* expr) {
+            order.push_back(expr);
+            return expr == i[0] ? ast::TraverseAction::Stop : ast::TraverseAction::Descend;
+        });
+    EXPECT_THAT(order, ElementsAre(root, i[0]));
 }
 
 }  // namespace
diff --git a/src/tint/ast/type.h b/src/tint/ast/type.h
index f9c8e31..4fee565 100644
--- a/src/tint/ast/type.h
+++ b/src/tint/ast/type.h
@@ -29,21 +29,21 @@
 namespace tint::ast {
 /// Base class for a type in the system
 class Type : public Castable<Type, Node> {
- public:
-  /// Move constructor
-  Type(Type&&);
-  ~Type() override;
+  public:
+    /// Move constructor
+    Type(Type&&);
+    ~Type() override;
 
-  /// @param symbols the program's symbol table
-  /// @returns the name for this type that closely resembles how it would be
-  /// declared in WGSL.
-  virtual std::string FriendlyName(const SymbolTable& symbols) const = 0;
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type that closely resembles how it would be
+    /// declared in WGSL.
+    virtual std::string FriendlyName(const SymbolTable& symbols) const = 0;
 
- protected:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  Type(ProgramID pid, const Source& src);
+  protected:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    Type(ProgramID pid, const Source& src);
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/type_decl.cc b/src/tint/ast/type_decl.cc
index 04c221c..a1a0605 100644
--- a/src/tint/ast/type_decl.cc
+++ b/src/tint/ast/type_decl.cc
@@ -20,9 +20,8 @@
 
 namespace tint::ast {
 
-TypeDecl::TypeDecl(ProgramID pid, const Source& src, Symbol n)
-    : Base(pid, src), name(n) {
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, name, program_id);
+TypeDecl::TypeDecl(ProgramID pid, const Source& src, Symbol n) : Base(pid, src), name(n) {
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, name, program_id);
 }
 
 TypeDecl::TypeDecl(TypeDecl&&) = default;
diff --git a/src/tint/ast/type_decl.h b/src/tint/ast/type_decl.h
index de3bd0a..2b8487a 100644
--- a/src/tint/ast/type_decl.h
+++ b/src/tint/ast/type_decl.h
@@ -23,19 +23,19 @@
 
 /// The base class for type declarations.
 class TypeDecl : public Castable<TypeDecl, Node> {
- public:
-  /// Create a new struct statement
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node for the import statement
-  /// @param name The name of the structure
-  TypeDecl(ProgramID pid, const Source& src, Symbol name);
-  /// Move constructor
-  TypeDecl(TypeDecl&&);
+  public:
+    /// Create a new struct statement
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node for the import statement
+    /// @param name The name of the structure
+    TypeDecl(ProgramID pid, const Source& src, Symbol name);
+    /// Move constructor
+    TypeDecl(TypeDecl&&);
 
-  ~TypeDecl() override;
+    ~TypeDecl() override;
 
-  /// The name of the type declaration
-  const Symbol name;
+    /// The name of the type declaration
+    const Symbol name;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/type_name.cc b/src/tint/ast/type_name.cc
index 8e84a55..8eb7a1a 100644
--- a/src/tint/ast/type_name.cc
+++ b/src/tint/ast/type_name.cc
@@ -20,21 +20,20 @@
 
 namespace tint::ast {
 
-TypeName::TypeName(ProgramID pid, const Source& src, Symbol n)
-    : Base(pid, src), name(n) {}
+TypeName::TypeName(ProgramID pid, const Source& src, Symbol n) : Base(pid, src), name(n) {}
 
 TypeName::~TypeName() = default;
 
 TypeName::TypeName(TypeName&&) = default;
 
 std::string TypeName::FriendlyName(const SymbolTable& symbols) const {
-  return symbols.NameFor(name);
+    return symbols.NameFor(name);
 }
 
 const TypeName* TypeName::Clone(CloneContext* ctx) const {
-  auto src = ctx->Clone(source);
-  auto n = ctx->Clone(name);
-  return ctx->dst->create<TypeName>(src, n);
+    auto src = ctx->Clone(source);
+    auto n = ctx->Clone(name);
+    return ctx->dst->create<TypeName>(src, n);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/type_name.h b/src/tint/ast/type_name.h
index bd3968a..3bb556a 100644
--- a/src/tint/ast/type_name.h
+++ b/src/tint/ast/type_name.h
@@ -23,29 +23,29 @@
 
 /// A named type (i.e. struct or alias)
 class TypeName final : public Castable<TypeName, Type> {
- public:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  /// @param name the type name
-  TypeName(ProgramID pid, const Source& src, Symbol name);
-  /// Move constructor
-  TypeName(TypeName&&);
-  /// Destructor
-  ~TypeName() override;
+  public:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    /// @param name the type name
+    TypeName(ProgramID pid, const Source& src, Symbol name);
+    /// Move constructor
+    TypeName(TypeName&&);
+    /// Destructor
+    ~TypeName() override;
 
-  /// @param symbols the program's symbol table
-  /// @returns the name for this type that closely resembles how it would be
-  /// declared in WGSL.
-  std::string FriendlyName(const SymbolTable& symbols) const override;
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type that closely resembles how it would be
+    /// declared in WGSL.
+    std::string FriendlyName(const SymbolTable& symbols) const override;
 
-  /// Clones this type and all transitive types using the `CloneContext` `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned type
-  const TypeName* Clone(CloneContext* ctx) const override;
+    /// Clones this type and all transitive types using the `CloneContext` `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned type
+    const TypeName* Clone(CloneContext* ctx) const override;
 
-  /// The type name
-  Symbol name;
+    /// The type name
+    Symbol name;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/u32.cc b/src/tint/ast/u32.cc
index 6cabe5b..ac9c490 100644
--- a/src/tint/ast/u32.cc
+++ b/src/tint/ast/u32.cc
@@ -27,12 +27,12 @@
 U32::U32(U32&&) = default;
 
 std::string U32::FriendlyName(const SymbolTable&) const {
-  return "u32";
+    return "u32";
 }
 
 const U32* U32::Clone(CloneContext* ctx) const {
-  auto src = ctx->Clone(source);
-  return ctx->dst->create<U32>(src);
+    auto src = ctx->Clone(source);
+    return ctx->dst->create<U32>(src);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/u32.h b/src/tint/ast/u32.h
index ede477b..8ede11c 100644
--- a/src/tint/ast/u32.h
+++ b/src/tint/ast/u32.h
@@ -23,24 +23,24 @@
 
 /// A unsigned int 32 type.
 class U32 final : public Castable<U32, Type> {
- public:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  U32(ProgramID pid, const Source& src);
-  /// Move constructor
-  U32(U32&&);
-  ~U32() override;
+  public:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    U32(ProgramID pid, const Source& src);
+    /// Move constructor
+    U32(U32&&);
+    ~U32() override;
 
-  /// @param symbols the program's symbol table
-  /// @returns the name for this type that closely resembles how it would be
-  /// declared in WGSL.
-  std::string FriendlyName(const SymbolTable& symbols) const override;
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type that closely resembles how it would be
+    /// declared in WGSL.
+    std::string FriendlyName(const SymbolTable& symbols) const override;
 
-  /// Clones this type and all transitive types using the `CloneContext` `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned type
-  const U32* Clone(CloneContext* ctx) const override;
+    /// Clones this type and all transitive types using the `CloneContext` `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned type
+    const U32* Clone(CloneContext* ctx) const override;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/u32_test.cc b/src/tint/ast/u32_test.cc
index 30a8840..a3a380b 100644
--- a/src/tint/ast/u32_test.cc
+++ b/src/tint/ast/u32_test.cc
@@ -22,8 +22,8 @@
 using AstU32Test = TestHelper;
 
 TEST_F(AstU32Test, FriendlyName) {
-  auto* u = create<U32>();
-  EXPECT_EQ(u->FriendlyName(Symbols()), "u32");
+    auto* u = create<U32>();
+    EXPECT_EQ(u->FriendlyName(Symbols()), "u32");
 }
 
 }  // namespace
diff --git a/src/tint/ast/uint_literal_expression.cc b/src/tint/ast/uint_literal_expression.cc
deleted file mode 100644
index 7af3325..0000000
--- a/src/tint/ast/uint_literal_expression.cc
+++ /dev/null
@@ -1,41 +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/uint_literal_expression.h"
-
-#include "src/tint/program_builder.h"
-
-TINT_INSTANTIATE_TYPEINFO(tint::ast::UintLiteralExpression);
-
-namespace tint::ast {
-
-UintLiteralExpression::UintLiteralExpression(ProgramID pid,
-                                             const Source& src,
-                                             uint32_t val)
-    : Base(pid, src), value(val) {}
-
-UintLiteralExpression::~UintLiteralExpression() = default;
-
-uint32_t UintLiteralExpression::ValueAsU32() const {
-  return value;
-}
-
-const UintLiteralExpression* UintLiteralExpression::Clone(
-    CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  return ctx->dst->create<UintLiteralExpression>(src, value);
-}
-
-}  // namespace tint::ast
diff --git a/src/tint/ast/uint_literal_expression.h b/src/tint/ast/uint_literal_expression.h
deleted file mode 100644
index 35ef5fa..0000000
--- a/src/tint/ast/uint_literal_expression.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_UINT_LITERAL_EXPRESSION_H_
-#define SRC_TINT_AST_UINT_LITERAL_EXPRESSION_H_
-
-#include <string>
-
-#include "src/tint/ast/int_literal_expression.h"
-
-namespace tint::ast {
-
-/// A uint literal
-class UintLiteralExpression final
-    : public Castable<UintLiteralExpression, IntLiteralExpression> {
- public:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  /// @param value the uint literals value
-  UintLiteralExpression(ProgramID pid, const Source& src, uint32_t value);
-  ~UintLiteralExpression() override;
-
-  /// @returns the literal value as a u32
-  uint32_t ValueAsU32() const override;
-
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const UintLiteralExpression* Clone(CloneContext* ctx) const override;
-
-  /// The int literal value
-  const uint32_t value;
-};
-
-}  // namespace tint::ast
-
-#endif  // SRC_TINT_AST_UINT_LITERAL_EXPRESSION_H_
diff --git a/src/tint/ast/uint_literal_expression_test.cc b/src/tint/ast/uint_literal_expression_test.cc
deleted file mode 100644
index f37816f..0000000
--- a/src/tint/ast/uint_literal_expression_test.cc
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2020 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/tint/ast/test_helper.h"
-
-namespace tint::ast {
-namespace {
-
-using UintLiteralExpressionTest = TestHelper;
-
-TEST_F(UintLiteralExpressionTest, Value) {
-  auto* u = create<UintLiteralExpression>(47);
-  ASSERT_TRUE(u->Is<UintLiteralExpression>());
-  EXPECT_EQ(u->value, 47u);
-}
-
-}  // namespace
-}  // namespace tint::ast
diff --git a/src/tint/ast/unary_op.cc b/src/tint/ast/unary_op.cc
index b90c71d..e0afe8d 100644
--- a/src/tint/ast/unary_op.cc
+++ b/src/tint/ast/unary_op.cc
@@ -17,29 +17,29 @@
 namespace tint::ast {
 
 std::ostream& operator<<(std::ostream& out, UnaryOp mod) {
-  switch (mod) {
-    case UnaryOp::kAddressOf: {
-      out << "address-of";
-      break;
+    switch (mod) {
+        case UnaryOp::kAddressOf: {
+            out << "address-of";
+            break;
+        }
+        case UnaryOp::kComplement: {
+            out << "complement";
+            break;
+        }
+        case UnaryOp::kIndirection: {
+            out << "indirection";
+            break;
+        }
+        case UnaryOp::kNegation: {
+            out << "negation";
+            break;
+        }
+        case UnaryOp::kNot: {
+            out << "not";
+            break;
+        }
     }
-    case UnaryOp::kComplement: {
-      out << "complement";
-      break;
-    }
-    case UnaryOp::kIndirection: {
-      out << "indirection";
-      break;
-    }
-    case UnaryOp::kNegation: {
-      out << "negation";
-      break;
-    }
-    case UnaryOp::kNot: {
-      out << "not";
-      break;
-    }
-  }
-  return out;
+    return out;
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/unary_op.h b/src/tint/ast/unary_op.h
index 93b6722..a861af3 100644
--- a/src/tint/ast/unary_op.h
+++ b/src/tint/ast/unary_op.h
@@ -21,11 +21,11 @@
 
 /// The unary op
 enum class UnaryOp {
-  kAddressOf,    // &EXPR
-  kComplement,   // ~EXPR
-  kIndirection,  // *EXPR
-  kNegation,     // -EXPR
-  kNot,          // !EXPR
+    kAddressOf,    // &EXPR
+    kComplement,   // ~EXPR
+    kIndirection,  // *EXPR
+    kNegation,     // -EXPR
+    kNot,          // !EXPR
 };
 
 /// @param out the std::ostream to write to
diff --git a/src/tint/ast/unary_op_expression.cc b/src/tint/ast/unary_op_expression.cc
index 7636a54..80e4e90 100644
--- a/src/tint/ast/unary_op_expression.cc
+++ b/src/tint/ast/unary_op_expression.cc
@@ -25,8 +25,8 @@
                                      UnaryOp o,
                                      const Expression* e)
     : Base(pid, src), op(o), expr(e) {
-  TINT_ASSERT(AST, expr);
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, expr, program_id);
+    TINT_ASSERT(AST, expr);
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, expr, program_id);
 }
 
 UnaryOpExpression::UnaryOpExpression(UnaryOpExpression&&) = default;
@@ -34,10 +34,10 @@
 UnaryOpExpression::~UnaryOpExpression() = default;
 
 const UnaryOpExpression* UnaryOpExpression::Clone(CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  auto* e = ctx->Clone(expr);
-  return ctx->dst->create<UnaryOpExpression>(src, op, e);
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    auto* e = ctx->Clone(expr);
+    return ctx->dst->create<UnaryOpExpression>(src, op, e);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/unary_op_expression.h b/src/tint/ast/unary_op_expression.h
index 1164108..22093fb 100644
--- a/src/tint/ast/unary_op_expression.h
+++ b/src/tint/ast/unary_op_expression.h
@@ -22,31 +22,31 @@
 
 /// A unary op expression
 class UnaryOpExpression final : public Castable<UnaryOpExpression, Expression> {
- public:
-  /// Constructor
-  /// @param program_id the identifier of the program that owns this node
-  /// @param source the unary op expression source
-  /// @param op the op
-  /// @param expr the expr
-  UnaryOpExpression(ProgramID program_id,
-                    const Source& source,
-                    UnaryOp op,
-                    const Expression* expr);
-  /// Move constructor
-  UnaryOpExpression(UnaryOpExpression&&);
-  ~UnaryOpExpression() override;
+  public:
+    /// Constructor
+    /// @param program_id the identifier of the program that owns this node
+    /// @param source the unary op expression source
+    /// @param op the op
+    /// @param expr the expr
+    UnaryOpExpression(ProgramID program_id,
+                      const Source& source,
+                      UnaryOp op,
+                      const Expression* expr);
+    /// Move constructor
+    UnaryOpExpression(UnaryOpExpression&&);
+    ~UnaryOpExpression() override;
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const UnaryOpExpression* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const UnaryOpExpression* Clone(CloneContext* ctx) const override;
 
-  /// The op
-  const UnaryOp op;
+    /// The op
+    const UnaryOp op;
 
-  /// The expression
-  const Expression* const expr;
+    /// The expression
+    const Expression* const expr;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/unary_op_expression_test.cc b/src/tint/ast/unary_op_expression_test.cc
index 5baf5da..e1ec8dd 100644
--- a/src/tint/ast/unary_op_expression_test.cc
+++ b/src/tint/ast/unary_op_expression_test.cc
@@ -23,45 +23,44 @@
 using UnaryOpExpressionTest = TestHelper;
 
 TEST_F(UnaryOpExpressionTest, Creation) {
-  auto* ident = Expr("ident");
+    auto* ident = Expr("ident");
 
-  auto* u = create<UnaryOpExpression>(UnaryOp::kNot, ident);
-  EXPECT_EQ(u->op, UnaryOp::kNot);
-  EXPECT_EQ(u->expr, ident);
+    auto* u = create<UnaryOpExpression>(UnaryOp::kNot, ident);
+    EXPECT_EQ(u->op, UnaryOp::kNot);
+    EXPECT_EQ(u->expr, ident);
 }
 
 TEST_F(UnaryOpExpressionTest, Creation_WithSource) {
-  auto* ident = Expr("ident");
-  auto* u = create<UnaryOpExpression>(Source{Source::Location{20, 2}},
-                                      UnaryOp::kNot, ident);
-  auto src = u->source;
-  EXPECT_EQ(src.range.begin.line, 20u);
-  EXPECT_EQ(src.range.begin.column, 2u);
+    auto* ident = Expr("ident");
+    auto* u = create<UnaryOpExpression>(Source{Source::Location{20, 2}}, UnaryOp::kNot, ident);
+    auto src = u->source;
+    EXPECT_EQ(src.range.begin.line, 20u);
+    EXPECT_EQ(src.range.begin.column, 2u);
 }
 
 TEST_F(UnaryOpExpressionTest, IsUnaryOp) {
-  auto* ident = Expr("ident");
-  auto* u = create<UnaryOpExpression>(UnaryOp::kNot, ident);
-  EXPECT_TRUE(u->Is<UnaryOpExpression>());
+    auto* ident = Expr("ident");
+    auto* u = create<UnaryOpExpression>(UnaryOp::kNot, ident);
+    EXPECT_TRUE(u->Is<UnaryOpExpression>());
 }
 
 TEST_F(UnaryOpExpressionTest, Assert_Null_Expression) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.create<UnaryOpExpression>(UnaryOp::kNot, nullptr);
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.create<UnaryOpExpression>(UnaryOp::kNot, nullptr);
+        },
+        "internal compiler error");
 }
 
 TEST_F(UnaryOpExpressionTest, Assert_DifferentProgramID_Expression) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.create<UnaryOpExpression>(UnaryOp::kNot, b2.Expr(true));
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.create<UnaryOpExpression>(UnaryOp::kNot, b2.Expr(true));
+        },
+        "internal compiler error");
 }
 
 }  // namespace
diff --git a/src/tint/ast/variable.cc b/src/tint/ast/variable.cc
index cea9f84..26991f2 100644
--- a/src/tint/ast/variable.cc
+++ b/src/tint/ast/variable.cc
@@ -40,10 +40,10 @@
       attributes(std::move(attrs)),
       declared_storage_class(dsc),
       declared_access(da) {
-  TINT_ASSERT(AST, symbol.IsValid());
-  TINT_ASSERT(AST, is_overridable ? is_const : true);
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, symbol, program_id);
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, constructor, program_id);
+    TINT_ASSERT(AST, symbol.IsValid());
+    TINT_ASSERT(AST, is_overridable ? is_const : true);
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, symbol, program_id);
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, constructor, program_id);
 }
 
 Variable::Variable(Variable&&) = default;
@@ -51,27 +51,26 @@
 Variable::~Variable() = default;
 
 VariableBindingPoint Variable::BindingPoint() const {
-  const GroupAttribute* group = nullptr;
-  const BindingAttribute* binding = nullptr;
-  for (auto* attr : attributes) {
-    if (auto* g = attr->As<GroupAttribute>()) {
-      group = g;
-    } else if (auto* b = attr->As<BindingAttribute>()) {
-      binding = b;
+    const GroupAttribute* group = nullptr;
+    const BindingAttribute* binding = nullptr;
+    for (auto* attr : attributes) {
+        if (auto* g = attr->As<GroupAttribute>()) {
+            group = g;
+        } else if (auto* b = attr->As<BindingAttribute>()) {
+            binding = b;
+        }
     }
-  }
-  return VariableBindingPoint{group, binding};
+    return VariableBindingPoint{group, binding};
 }
 
 const Variable* Variable::Clone(CloneContext* ctx) const {
-  auto src = ctx->Clone(source);
-  auto sym = ctx->Clone(symbol);
-  auto* ty = ctx->Clone(type);
-  auto* ctor = ctx->Clone(constructor);
-  auto attrs = ctx->Clone(attributes);
-  return ctx->dst->create<Variable>(src, sym, declared_storage_class,
-                                    declared_access, ty, is_const,
-                                    is_overridable, ctor, attrs);
+    auto src = ctx->Clone(source);
+    auto sym = ctx->Clone(symbol);
+    auto* ty = ctx->Clone(type);
+    auto* ctor = ctx->Clone(constructor);
+    auto attrs = ctx->Clone(attributes);
+    return ctx->dst->create<Variable>(src, sym, declared_storage_class, declared_access, ty,
+                                      is_const, is_overridable, ctor, attrs);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/variable.h b/src/tint/ast/variable.h
index 208f0b1..5802255 100644
--- a/src/tint/ast/variable.h
+++ b/src/tint/ast/variable.h
@@ -35,14 +35,14 @@
 
 /// VariableBindingPoint holds a group and binding attribute.
 struct VariableBindingPoint {
-  /// The `@group` part of the binding point
-  const GroupAttribute* group = nullptr;
-  /// The `@binding` part of the binding point
-  const BindingAttribute* binding = nullptr;
+    /// The `@group` part of the binding point
+    const GroupAttribute* group = nullptr;
+    /// The `@binding` part of the binding point
+    const BindingAttribute* binding = nullptr;
 
-  /// @returns true if the BindingPoint has a valid group and binding
-  /// attribute.
-  inline operator bool() const { return group && binding; }
+    /// @returns true if the BindingPoint has a valid group and binding
+    /// attribute.
+    inline operator bool() const { return group && binding; }
 };
 
 /// A Variable statement.
@@ -115,67 +115,67 @@
 ///   - "let" is always StorageClass::kNone.
 ///   - formal parameter is always StorageClass::kNone.
 class Variable final : public Castable<Variable, Node> {
- public:
-  /// Create a variable
-  /// @param program_id the identifier of the program that owns this node
-  /// @param source the variable source
-  /// @param sym the variable symbol
-  /// @param declared_storage_class the declared storage class
-  /// @param declared_access the declared access control
-  /// @param type the declared variable type
-  /// @param is_const true if the variable is const
-  /// @param is_overridable true if the variable is pipeline-overridable
-  /// @param constructor the constructor expression
-  /// @param attributes the variable attributes
-  Variable(ProgramID program_id,
-           const Source& source,
-           const Symbol& sym,
-           StorageClass declared_storage_class,
-           Access declared_access,
-           const ast::Type* type,
-           bool is_const,
-           bool is_overridable,
-           const Expression* constructor,
-           AttributeList attributes);
-  /// Move constructor
-  Variable(Variable&&);
+  public:
+    /// Create a variable
+    /// @param program_id the identifier of the program that owns this node
+    /// @param source the variable source
+    /// @param sym the variable symbol
+    /// @param declared_storage_class the declared storage class
+    /// @param declared_access the declared access control
+    /// @param type the declared variable type
+    /// @param is_const true if the variable is const
+    /// @param is_overridable true if the variable is pipeline-overridable
+    /// @param constructor the constructor expression
+    /// @param attributes the variable attributes
+    Variable(ProgramID program_id,
+             const Source& source,
+             const Symbol& sym,
+             StorageClass declared_storage_class,
+             Access declared_access,
+             const ast::Type* type,
+             bool is_const,
+             bool is_overridable,
+             const Expression* constructor,
+             AttributeList attributes);
+    /// Move constructor
+    Variable(Variable&&);
 
-  ~Variable() override;
+    ~Variable() override;
 
-  /// @returns the binding point information for the variable
-  VariableBindingPoint BindingPoint() const;
+    /// @returns the binding point information for the variable
+    VariableBindingPoint BindingPoint() const;
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const Variable* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const Variable* Clone(CloneContext* ctx) const override;
 
-  /// The variable symbol
-  const Symbol symbol;
+    /// The variable symbol
+    const Symbol symbol;
 
-  /// The declared variable type. This is null if the type is inferred, e.g.:
-  ///   let f = 1.0;
-  ///   var i = 1;
-  const ast::Type* const type;
+    /// The declared variable type. This is null if the type is inferred, e.g.:
+    ///   let f = 1.0;
+    ///   var i = 1;
+    const ast::Type* const type;
 
-  /// True if this is a constant, false otherwise
-  const bool is_const;
+    /// True if this is a constant, false otherwise
+    const bool is_const;
 
-  /// True if this is a pipeline-overridable constant, false otherwise
-  const bool is_overridable;
+    /// True if this is a pipeline-overridable constant, false otherwise
+    const bool is_overridable;
 
-  /// The constructor expression or nullptr if none set
-  const Expression* const constructor;
+    /// The constructor expression or nullptr if none set
+    const Expression* const constructor;
 
-  /// The attributes attached to this variable
-  const AttributeList attributes;
+    /// The attributes attached to this variable
+    const AttributeList attributes;
 
-  /// The declared storage class
-  const StorageClass declared_storage_class;
+    /// The declared storage class
+    const StorageClass declared_storage_class;
 
-  /// The declared access control
-  const Access declared_access;
+    /// The declared access control
+    const Access declared_access;
 };
 
 /// A list of variables
diff --git a/src/tint/ast/variable_decl_statement.cc b/src/tint/ast/variable_decl_statement.cc
index 16d1106..fdde149 100644
--- a/src/tint/ast/variable_decl_statement.cc
+++ b/src/tint/ast/variable_decl_statement.cc
@@ -20,24 +20,21 @@
 
 namespace tint::ast {
 
-VariableDeclStatement::VariableDeclStatement(ProgramID pid,
-                                             const Source& src,
-                                             const Variable* var)
+VariableDeclStatement::VariableDeclStatement(ProgramID pid, const Source& src, const Variable* var)
     : Base(pid, src), variable(var) {
-  TINT_ASSERT(AST, variable);
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, variable, program_id);
+    TINT_ASSERT(AST, variable);
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, variable, program_id);
 }
 
 VariableDeclStatement::VariableDeclStatement(VariableDeclStatement&&) = default;
 
 VariableDeclStatement::~VariableDeclStatement() = default;
 
-const VariableDeclStatement* VariableDeclStatement::Clone(
-    CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  auto* var = ctx->Clone(variable);
-  return ctx->dst->create<VariableDeclStatement>(src, var);
+const VariableDeclStatement* VariableDeclStatement::Clone(CloneContext* ctx) const {
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    auto* var = ctx->Clone(variable);
+    return ctx->dst->create<VariableDeclStatement>(src, var);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/variable_decl_statement.h b/src/tint/ast/variable_decl_statement.h
index 2edee63..3f3ae27 100644
--- a/src/tint/ast/variable_decl_statement.h
+++ b/src/tint/ast/variable_decl_statement.h
@@ -21,28 +21,25 @@
 namespace tint::ast {
 
 /// A variable declaration statement
-class VariableDeclStatement final
-    : public Castable<VariableDeclStatement, Statement> {
- public:
-  /// Constructor
-  /// @param program_id the identifier of the program that owns this node
-  /// @param source the variable statement source
-  /// @param variable the variable
-  VariableDeclStatement(ProgramID program_id,
-                        const Source& source,
-                        const Variable* variable);
-  /// Move constructor
-  VariableDeclStatement(VariableDeclStatement&&);
-  ~VariableDeclStatement() override;
+class VariableDeclStatement final : public Castable<VariableDeclStatement, Statement> {
+  public:
+    /// Constructor
+    /// @param program_id the identifier of the program that owns this node
+    /// @param source the variable statement source
+    /// @param variable the variable
+    VariableDeclStatement(ProgramID program_id, const Source& source, const Variable* variable);
+    /// Move constructor
+    VariableDeclStatement(VariableDeclStatement&&);
+    ~VariableDeclStatement() override;
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const VariableDeclStatement* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const VariableDeclStatement* Clone(CloneContext* ctx) const override;
 
-  /// The variable
-  const Variable* const variable;
+    /// The variable
+    const Variable* const variable;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/variable_decl_statement_test.cc b/src/tint/ast/variable_decl_statement_test.cc
index e628d96..2cd4d4d 100644
--- a/src/tint/ast/variable_decl_statement_test.cc
+++ b/src/tint/ast/variable_decl_statement_test.cc
@@ -23,47 +23,45 @@
 using VariableDeclStatementTest = TestHelper;
 
 TEST_F(VariableDeclStatementTest, Creation) {
-  auto* var = Var("a", ty.f32(), StorageClass::kNone);
+    auto* var = Var("a", ty.f32(), StorageClass::kNone);
 
-  auto* stmt = create<VariableDeclStatement>(var);
-  EXPECT_EQ(stmt->variable, var);
+    auto* stmt = create<VariableDeclStatement>(var);
+    EXPECT_EQ(stmt->variable, var);
 }
 
 TEST_F(VariableDeclStatementTest, Creation_WithSource) {
-  auto* var = Var("a", ty.f32(), StorageClass::kNone);
+    auto* var = Var("a", ty.f32(), StorageClass::kNone);
 
-  auto* stmt =
-      create<VariableDeclStatement>(Source{Source::Location{20, 2}}, var);
-  auto src = stmt->source;
-  EXPECT_EQ(src.range.begin.line, 20u);
-  EXPECT_EQ(src.range.begin.column, 2u);
+    auto* stmt = create<VariableDeclStatement>(Source{Source::Location{20, 2}}, var);
+    auto src = stmt->source;
+    EXPECT_EQ(src.range.begin.line, 20u);
+    EXPECT_EQ(src.range.begin.column, 2u);
 }
 
 TEST_F(VariableDeclStatementTest, IsVariableDecl) {
-  auto* var = Var("a", ty.f32(), StorageClass::kNone);
+    auto* var = Var("a", ty.f32(), StorageClass::kNone);
 
-  auto* stmt = create<VariableDeclStatement>(var);
-  EXPECT_TRUE(stmt->Is<VariableDeclStatement>());
+    auto* stmt = create<VariableDeclStatement>(var);
+    EXPECT_TRUE(stmt->Is<VariableDeclStatement>());
 }
 
 TEST_F(VariableDeclStatementTest, Assert_Null_Variable) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.create<VariableDeclStatement>(nullptr);
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.create<VariableDeclStatement>(nullptr);
+        },
+        "internal compiler error");
 }
 
 TEST_F(VariableDeclStatementTest, Assert_DifferentProgramID_Variable) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.create<VariableDeclStatement>(
-            b2.Var("a", b2.ty.f32(), StorageClass::kNone));
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.create<VariableDeclStatement>(b2.Var("a", b2.ty.f32(), StorageClass::kNone));
+        },
+        "internal compiler error");
 }
 
 }  // namespace
diff --git a/src/tint/ast/variable_test.cc b/src/tint/ast/variable_test.cc
index 334bcb3..b43a19e 100644
--- a/src/tint/ast/variable_test.cc
+++ b/src/tint/ast/variable_test.cc
@@ -23,131 +23,128 @@
 using VariableTest = TestHelper;
 
 TEST_F(VariableTest, Creation) {
-  auto* v = Var("my_var", ty.i32(), StorageClass::kFunction);
+    auto* v = Var("my_var", ty.i32(), StorageClass::kFunction);
 
-  EXPECT_EQ(v->symbol, Symbol(1, ID()));
-  EXPECT_EQ(v->declared_storage_class, StorageClass::kFunction);
-  EXPECT_TRUE(v->type->Is<ast::I32>());
-  EXPECT_EQ(v->source.range.begin.line, 0u);
-  EXPECT_EQ(v->source.range.begin.column, 0u);
-  EXPECT_EQ(v->source.range.end.line, 0u);
-  EXPECT_EQ(v->source.range.end.column, 0u);
+    EXPECT_EQ(v->symbol, Symbol(1, ID()));
+    EXPECT_EQ(v->declared_storage_class, StorageClass::kFunction);
+    EXPECT_TRUE(v->type->Is<ast::I32>());
+    EXPECT_EQ(v->source.range.begin.line, 0u);
+    EXPECT_EQ(v->source.range.begin.column, 0u);
+    EXPECT_EQ(v->source.range.end.line, 0u);
+    EXPECT_EQ(v->source.range.end.column, 0u);
 }
 
 TEST_F(VariableTest, CreationWithSource) {
-  auto* v = Var(
-      Source{Source::Range{Source::Location{27, 4}, Source::Location{27, 5}}},
-      "i", ty.f32(), StorageClass::kPrivate, nullptr, AttributeList{});
+    auto* v = Var(Source{Source::Range{Source::Location{27, 4}, Source::Location{27, 5}}}, "i",
+                  ty.f32(), StorageClass::kPrivate, nullptr, AttributeList{});
 
-  EXPECT_EQ(v->symbol, Symbol(1, ID()));
-  EXPECT_EQ(v->declared_storage_class, StorageClass::kPrivate);
-  EXPECT_TRUE(v->type->Is<ast::F32>());
-  EXPECT_EQ(v->source.range.begin.line, 27u);
-  EXPECT_EQ(v->source.range.begin.column, 4u);
-  EXPECT_EQ(v->source.range.end.line, 27u);
-  EXPECT_EQ(v->source.range.end.column, 5u);
+    EXPECT_EQ(v->symbol, Symbol(1, ID()));
+    EXPECT_EQ(v->declared_storage_class, StorageClass::kPrivate);
+    EXPECT_TRUE(v->type->Is<ast::F32>());
+    EXPECT_EQ(v->source.range.begin.line, 27u);
+    EXPECT_EQ(v->source.range.begin.column, 4u);
+    EXPECT_EQ(v->source.range.end.line, 27u);
+    EXPECT_EQ(v->source.range.end.column, 5u);
 }
 
 TEST_F(VariableTest, CreationEmpty) {
-  auto* v = Var(
-      Source{Source::Range{Source::Location{27, 4}, Source::Location{27, 7}}},
-      "a_var", ty.i32(), StorageClass::kWorkgroup, nullptr, AttributeList{});
+    auto* v = Var(Source{Source::Range{Source::Location{27, 4}, Source::Location{27, 7}}}, "a_var",
+                  ty.i32(), StorageClass::kWorkgroup, nullptr, AttributeList{});
 
-  EXPECT_EQ(v->symbol, Symbol(1, ID()));
-  EXPECT_EQ(v->declared_storage_class, StorageClass::kWorkgroup);
-  EXPECT_TRUE(v->type->Is<ast::I32>());
-  EXPECT_EQ(v->source.range.begin.line, 27u);
-  EXPECT_EQ(v->source.range.begin.column, 4u);
-  EXPECT_EQ(v->source.range.end.line, 27u);
-  EXPECT_EQ(v->source.range.end.column, 7u);
+    EXPECT_EQ(v->symbol, Symbol(1, ID()));
+    EXPECT_EQ(v->declared_storage_class, StorageClass::kWorkgroup);
+    EXPECT_TRUE(v->type->Is<ast::I32>());
+    EXPECT_EQ(v->source.range.begin.line, 27u);
+    EXPECT_EQ(v->source.range.begin.column, 4u);
+    EXPECT_EQ(v->source.range.end.line, 27u);
+    EXPECT_EQ(v->source.range.end.column, 7u);
 }
 
 TEST_F(VariableTest, Assert_MissingSymbol) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.Var("", b.ty.i32(), StorageClass::kNone);
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.Var("", b.ty.i32(), StorageClass::kNone);
+        },
+        "internal compiler error");
 }
 
 TEST_F(VariableTest, Assert_DifferentProgramID_Symbol) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.Var(b2.Sym("x"), b1.ty.f32(), StorageClass::kNone);
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.Var(b2.Sym("x"), b1.ty.f32(), StorageClass::kNone);
+        },
+        "internal compiler error");
 }
 
 TEST_F(VariableTest, Assert_DifferentProgramID_Constructor) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b1;
-        ProgramBuilder b2;
-        b1.Var("x", b1.ty.f32(), StorageClass::kNone, b2.Expr(1.2f));
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b1;
+            ProgramBuilder b2;
+            b1.Var("x", b1.ty.f32(), StorageClass::kNone, b2.Expr(1.2f));
+        },
+        "internal compiler error");
 }
 
 TEST_F(VariableTest, WithAttributes) {
-  auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, nullptr,
-                  AttributeList{
-                      create<LocationAttribute>(1),
-                      create<BuiltinAttribute>(Builtin::kPosition),
-                      create<IdAttribute>(1200),
-                  });
+    auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, nullptr,
+                    AttributeList{
+                        create<LocationAttribute>(1),
+                        create<BuiltinAttribute>(Builtin::kPosition),
+                        create<IdAttribute>(1200),
+                    });
 
-  auto& attributes = var->attributes;
-  EXPECT_TRUE(ast::HasAttribute<ast::LocationAttribute>(attributes));
-  EXPECT_TRUE(ast::HasAttribute<ast::BuiltinAttribute>(attributes));
-  EXPECT_TRUE(ast::HasAttribute<ast::IdAttribute>(attributes));
+    auto& attributes = var->attributes;
+    EXPECT_TRUE(ast::HasAttribute<ast::LocationAttribute>(attributes));
+    EXPECT_TRUE(ast::HasAttribute<ast::BuiltinAttribute>(attributes));
+    EXPECT_TRUE(ast::HasAttribute<ast::IdAttribute>(attributes));
 
-  auto* location = ast::GetAttribute<ast::LocationAttribute>(attributes);
-  ASSERT_NE(nullptr, location);
-  EXPECT_EQ(1u, location->value);
+    auto* location = ast::GetAttribute<ast::LocationAttribute>(attributes);
+    ASSERT_NE(nullptr, location);
+    EXPECT_EQ(1u, location->value);
 }
 
 TEST_F(VariableTest, BindingPoint) {
-  auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, nullptr,
-                  AttributeList{
-                      create<BindingAttribute>(2),
-                      create<GroupAttribute>(1),
-                  });
-  EXPECT_TRUE(var->BindingPoint());
-  ASSERT_NE(var->BindingPoint().binding, nullptr);
-  ASSERT_NE(var->BindingPoint().group, nullptr);
-  EXPECT_EQ(var->BindingPoint().binding->value, 2u);
-  EXPECT_EQ(var->BindingPoint().group->value, 1u);
+    auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, nullptr,
+                    AttributeList{
+                        create<BindingAttribute>(2),
+                        create<GroupAttribute>(1),
+                    });
+    EXPECT_TRUE(var->BindingPoint());
+    ASSERT_NE(var->BindingPoint().binding, nullptr);
+    ASSERT_NE(var->BindingPoint().group, nullptr);
+    EXPECT_EQ(var->BindingPoint().binding->value, 2u);
+    EXPECT_EQ(var->BindingPoint().group->value, 1u);
 }
 
 TEST_F(VariableTest, BindingPointAttributes) {
-  auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, nullptr,
-                  AttributeList{});
-  EXPECT_FALSE(var->BindingPoint());
-  EXPECT_EQ(var->BindingPoint().group, nullptr);
-  EXPECT_EQ(var->BindingPoint().binding, nullptr);
+    auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, nullptr, AttributeList{});
+    EXPECT_FALSE(var->BindingPoint());
+    EXPECT_EQ(var->BindingPoint().group, nullptr);
+    EXPECT_EQ(var->BindingPoint().binding, nullptr);
 }
 
 TEST_F(VariableTest, BindingPointMissingGroupAttribute) {
-  auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, nullptr,
-                  AttributeList{
-                      create<BindingAttribute>(2),
-                  });
-  EXPECT_FALSE(var->BindingPoint());
-  ASSERT_NE(var->BindingPoint().binding, nullptr);
-  EXPECT_EQ(var->BindingPoint().binding->value, 2u);
-  EXPECT_EQ(var->BindingPoint().group, nullptr);
+    auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, nullptr,
+                    AttributeList{
+                        create<BindingAttribute>(2),
+                    });
+    EXPECT_FALSE(var->BindingPoint());
+    ASSERT_NE(var->BindingPoint().binding, nullptr);
+    EXPECT_EQ(var->BindingPoint().binding->value, 2u);
+    EXPECT_EQ(var->BindingPoint().group, nullptr);
 }
 
 TEST_F(VariableTest, BindingPointMissingBindingAttribute) {
-  auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, nullptr,
-                  AttributeList{create<GroupAttribute>(1)});
-  EXPECT_FALSE(var->BindingPoint());
-  ASSERT_NE(var->BindingPoint().group, nullptr);
-  EXPECT_EQ(var->BindingPoint().group->value, 1u);
-  EXPECT_EQ(var->BindingPoint().binding, nullptr);
+    auto* var = Var("my_var", ty.i32(), StorageClass::kFunction, nullptr,
+                    AttributeList{create<GroupAttribute>(1)});
+    EXPECT_FALSE(var->BindingPoint());
+    ASSERT_NE(var->BindingPoint().group, nullptr);
+    EXPECT_EQ(var->BindingPoint().group->value, 1u);
+    EXPECT_EQ(var->BindingPoint().binding, nullptr);
 }
 
 }  // namespace
diff --git a/src/tint/ast/vector.cc b/src/tint/ast/vector.cc
index d47aad3..43478df 100644
--- a/src/tint/ast/vector.cc
+++ b/src/tint/ast/vector.cc
@@ -20,14 +20,11 @@
 
 namespace tint::ast {
 
-Vector::Vector(ProgramID pid,
-               Source const& src,
-               const Type* subtype,
-               uint32_t w)
+Vector::Vector(ProgramID pid, Source const& src, const Type* subtype, uint32_t w)
     : Base(pid, src), type(subtype), width(w) {
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, subtype, program_id);
-  TINT_ASSERT(AST, width > 1);
-  TINT_ASSERT(AST, width < 5);
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(AST, subtype, program_id);
+    TINT_ASSERT(AST, width > 1);
+    TINT_ASSERT(AST, width < 5);
 }
 
 Vector::Vector(Vector&&) = default;
@@ -35,19 +32,19 @@
 Vector::~Vector() = default;
 
 std::string Vector::FriendlyName(const SymbolTable& symbols) const {
-  std::ostringstream out;
-  out << "vec" << width;
-  if (type) {
-    out << "<" << type->FriendlyName(symbols) << ">";
-  }
-  return out.str();
+    std::ostringstream out;
+    out << "vec" << width;
+    if (type) {
+        out << "<" << type->FriendlyName(symbols) << ">";
+    }
+    return out.str();
 }
 
 const Vector* Vector::Clone(CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  auto* ty = ctx->Clone(type);
-  return ctx->dst->create<Vector>(src, ty, width);
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    auto* ty = ctx->Clone(type);
+    return ctx->dst->create<Vector>(src, ty, width);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/vector.h b/src/tint/ast/vector.h
index dfa2ac2..6b2d914 100644
--- a/src/tint/ast/vector.h
+++ b/src/tint/ast/vector.h
@@ -23,36 +23,36 @@
 
 /// A vector type.
 class Vector final : public Castable<Vector, Type> {
- public:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  /// @param subtype the declared type of the vector components. May be null
-  ///        for vector constructors, where the element type will be inferred
-  ///        from the constructor arguments
-  /// @param width the number of elements in the vector
-  Vector(ProgramID pid, Source const& src, const Type* subtype, uint32_t width);
-  /// Move constructor
-  Vector(Vector&&);
-  ~Vector() override;
+  public:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    /// @param subtype the declared type of the vector components. May be null
+    ///        for vector constructors, where the element type will be inferred
+    ///        from the constructor arguments
+    /// @param width the number of elements in the vector
+    Vector(ProgramID pid, Source const& src, const Type* subtype, uint32_t width);
+    /// Move constructor
+    Vector(Vector&&);
+    ~Vector() override;
 
-  /// @param symbols the program's symbol table
-  /// @returns the name for this type that closely resembles how it would be
-  /// declared in WGSL.
-  std::string FriendlyName(const SymbolTable& symbols) const override;
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type that closely resembles how it would be
+    /// declared in WGSL.
+    std::string FriendlyName(const SymbolTable& symbols) const override;
 
-  /// Clones this type and all transitive types using the `CloneContext` `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned type
-  const Vector* Clone(CloneContext* ctx) const override;
+    /// Clones this type and all transitive types using the `CloneContext` `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned type
+    const Vector* Clone(CloneContext* ctx) const override;
 
-  /// The declared type of the vector components. May be null for vector
-  /// constructors, where the element type will be inferred from the constructor
-  /// arguments
-  const Type* const type;
+    /// The declared type of the vector components. May be null for vector
+    /// constructors, where the element type will be inferred from the constructor
+    /// arguments
+    const Type* const type;
 
-  /// The number of elements in the vector
-  const uint32_t width;
+    /// The number of elements in the vector
+    const uint32_t width;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/vector_test.cc b/src/tint/ast/vector_test.cc
index 19c7c4e..a701852 100644
--- a/src/tint/ast/vector_test.cc
+++ b/src/tint/ast/vector_test.cc
@@ -23,16 +23,16 @@
 using AstVectorTest = TestHelper;
 
 TEST_F(AstVectorTest, Creation) {
-  auto* i32 = create<I32>();
-  auto* v = create<Vector>(i32, 2);
-  EXPECT_EQ(v->type, i32);
-  EXPECT_EQ(v->width, 2u);
+    auto* i32 = create<I32>();
+    auto* v = create<Vector>(i32, 2);
+    EXPECT_EQ(v->type, i32);
+    EXPECT_EQ(v->width, 2u);
 }
 
 TEST_F(AstVectorTest, FriendlyName) {
-  auto* f32 = create<F32>();
-  auto* v = create<Vector>(f32, 3);
-  EXPECT_EQ(v->FriendlyName(Symbols()), "vec3<f32>");
+    auto* f32 = create<F32>();
+    auto* v = create<Vector>(f32, 3);
+    EXPECT_EQ(v->FriendlyName(Symbols()), "vec3<f32>");
 }
 
 }  // namespace
diff --git a/src/tint/ast/void.cc b/src/tint/ast/void.cc
index 34314ae..5cc8963 100644
--- a/src/tint/ast/void.cc
+++ b/src/tint/ast/void.cc
@@ -27,12 +27,12 @@
 Void::~Void() = default;
 
 std::string Void::FriendlyName(const SymbolTable&) const {
-  return "void";
+    return "void";
 }
 
 const Void* Void::Clone(CloneContext* ctx) const {
-  auto src = ctx->Clone(source);
-  return ctx->dst->create<Void>(src);
+    auto src = ctx->Clone(source);
+    return ctx->dst->create<Void>(src);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/void.h b/src/tint/ast/void.h
index 55ddb35..33f5b5b 100644
--- a/src/tint/ast/void.h
+++ b/src/tint/ast/void.h
@@ -23,24 +23,24 @@
 
 /// A void type
 class Void final : public Castable<Void, Type> {
- public:
-  /// Constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  Void(ProgramID pid, const Source& src);
-  /// Move constructor
-  Void(Void&&);
-  ~Void() override;
+  public:
+    /// Constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    Void(ProgramID pid, const Source& src);
+    /// Move constructor
+    Void(Void&&);
+    ~Void() override;
 
-  /// @param symbols the program's symbol table
-  /// @returns the name for this type that closely resembles how it would be
-  /// declared in WGSL.
-  std::string FriendlyName(const SymbolTable& symbols) const override;
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type that closely resembles how it would be
+    /// declared in WGSL.
+    std::string FriendlyName(const SymbolTable& symbols) const override;
 
-  /// Clones this type and all transitive types using the `CloneContext` `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned type
-  const Void* Clone(CloneContext* ctx) const override;
+    /// Clones this type and all transitive types using the `CloneContext` `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned type
+    const Void* Clone(CloneContext* ctx) const override;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/workgroup_attribute.cc b/src/tint/ast/workgroup_attribute.cc
index 1f7a112..74ecdbe 100644
--- a/src/tint/ast/workgroup_attribute.cc
+++ b/src/tint/ast/workgroup_attribute.cc
@@ -32,16 +32,16 @@
 WorkgroupAttribute::~WorkgroupAttribute() = default;
 
 std::string WorkgroupAttribute::Name() const {
-  return "workgroup_size";
+    return "workgroup_size";
 }
 
 const WorkgroupAttribute* WorkgroupAttribute::Clone(CloneContext* ctx) const {
-  // Clone arguments outside of create() call to have deterministic ordering
-  auto src = ctx->Clone(source);
-  auto* x_ = ctx->Clone(x);
-  auto* y_ = ctx->Clone(y);
-  auto* z_ = ctx->Clone(z);
-  return ctx->dst->create<WorkgroupAttribute>(src, x_, y_, z_);
+    // Clone arguments outside of create() call to have deterministic ordering
+    auto src = ctx->Clone(source);
+    auto* x_ = ctx->Clone(x);
+    auto* y_ = ctx->Clone(y);
+    auto* z_ = ctx->Clone(z);
+    return ctx->dst->create<WorkgroupAttribute>(src, x_, y_, z_);
 }
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/workgroup_attribute.h b/src/tint/ast/workgroup_attribute.h
index 232201b..536ce15 100644
--- a/src/tint/ast/workgroup_attribute.h
+++ b/src/tint/ast/workgroup_attribute.h
@@ -28,41 +28,40 @@
 namespace tint::ast {
 
 /// A workgroup attribute
-class WorkgroupAttribute final
-    : public Castable<WorkgroupAttribute, Attribute> {
- public:
-  /// constructor
-  /// @param pid the identifier of the program that owns this node
-  /// @param src the source of this node
-  /// @param x the workgroup x dimension expression
-  /// @param y the optional workgroup y dimension expression
-  /// @param z the optional workgroup z dimension expression
-  WorkgroupAttribute(ProgramID pid,
-                     const Source& src,
-                     const ast::Expression* x,
-                     const ast::Expression* y = nullptr,
-                     const ast::Expression* z = nullptr);
+class WorkgroupAttribute final : public Castable<WorkgroupAttribute, Attribute> {
+  public:
+    /// constructor
+    /// @param pid the identifier of the program that owns this node
+    /// @param src the source of this node
+    /// @param x the workgroup x dimension expression
+    /// @param y the optional workgroup y dimension expression
+    /// @param z the optional workgroup z dimension expression
+    WorkgroupAttribute(ProgramID pid,
+                       const Source& src,
+                       const ast::Expression* x,
+                       const ast::Expression* y = nullptr,
+                       const ast::Expression* z = nullptr);
 
-  ~WorkgroupAttribute() override;
+    ~WorkgroupAttribute() override;
 
-  /// @returns the workgroup dimensions
-  std::array<const ast::Expression*, 3> Values() const { return {x, y, z}; }
+    /// @returns the workgroup dimensions
+    std::array<const ast::Expression*, 3> Values() const { return {x, y, z}; }
 
-  /// @returns the WGSL name for the attribute
-  std::string Name() const override;
+    /// @returns the WGSL name for the attribute
+    std::string Name() const override;
 
-  /// Clones this node and all transitive child nodes using the `CloneContext`
-  /// `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned node
-  const WorkgroupAttribute* Clone(CloneContext* ctx) const override;
+    /// Clones this node and all transitive child nodes using the `CloneContext`
+    /// `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned node
+    const WorkgroupAttribute* Clone(CloneContext* ctx) const override;
 
-  /// The workgroup x dimension.
-  const ast::Expression* const x;
-  /// The optional workgroup y dimension. May be null.
-  const ast::Expression* const y = nullptr;
-  /// The optional workgroup z dimension. May be null.
-  const ast::Expression* const z = nullptr;
+    /// The workgroup x dimension.
+    const ast::Expression* const x;
+    /// The optional workgroup y dimension. May be null.
+    const ast::Expression* const y = nullptr;
+    /// The optional workgroup z dimension. May be null.
+    const ast::Expression* const z = nullptr;
 };
 
 }  // namespace tint::ast
diff --git a/src/tint/ast/workgroup_attribute_test.cc b/src/tint/ast/workgroup_attribute_test.cc
index 928b5fe..d4fb6c7 100644
--- a/src/tint/ast/workgroup_attribute_test.cc
+++ b/src/tint/ast/workgroup_attribute_test.cc
@@ -17,61 +17,63 @@
 #include "src/tint/ast/stage_attribute.h"
 #include "src/tint/ast/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::ast {
 namespace {
 
 using WorkgroupAttributeTest = TestHelper;
 
 TEST_F(WorkgroupAttributeTest, Creation_1param) {
-  auto* d = WorkgroupSize(2);
-  auto values = d->Values();
+    auto* d = WorkgroupSize(2_i);
+    auto values = d->Values();
 
-  ASSERT_TRUE(values[0]->Is<ast::IntLiteralExpression>());
-  EXPECT_EQ(values[0]->As<ast::IntLiteralExpression>()->ValueAsU32(), 2u);
+    ASSERT_TRUE(values[0]->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(values[0]->As<ast::IntLiteralExpression>()->value, 2);
 
-  EXPECT_EQ(values[1], nullptr);
-  EXPECT_EQ(values[2], nullptr);
+    EXPECT_EQ(values[1], nullptr);
+    EXPECT_EQ(values[2], nullptr);
 }
 TEST_F(WorkgroupAttributeTest, Creation_2param) {
-  auto* d = WorkgroupSize(2, 4);
-  auto values = d->Values();
+    auto* d = WorkgroupSize(2_i, 4_i);
+    auto values = d->Values();
 
-  ASSERT_TRUE(values[0]->Is<ast::IntLiteralExpression>());
-  EXPECT_EQ(values[0]->As<ast::IntLiteralExpression>()->ValueAsU32(), 2u);
+    ASSERT_TRUE(values[0]->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(values[0]->As<ast::IntLiteralExpression>()->value, 2);
 
-  ASSERT_TRUE(values[1]->Is<ast::IntLiteralExpression>());
-  EXPECT_EQ(values[1]->As<ast::IntLiteralExpression>()->ValueAsU32(), 4u);
+    ASSERT_TRUE(values[1]->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(values[1]->As<ast::IntLiteralExpression>()->value, 4);
 
-  EXPECT_EQ(values[2], nullptr);
+    EXPECT_EQ(values[2], nullptr);
 }
 
 TEST_F(WorkgroupAttributeTest, Creation_3param) {
-  auto* d = WorkgroupSize(2, 4, 6);
-  auto values = d->Values();
+    auto* d = WorkgroupSize(2_i, 4_i, 6_i);
+    auto values = d->Values();
 
-  ASSERT_TRUE(values[0]->Is<ast::IntLiteralExpression>());
-  EXPECT_EQ(values[0]->As<ast::IntLiteralExpression>()->ValueAsU32(), 2u);
+    ASSERT_TRUE(values[0]->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(values[0]->As<ast::IntLiteralExpression>()->value, 2);
 
-  ASSERT_TRUE(values[1]->Is<ast::IntLiteralExpression>());
-  EXPECT_EQ(values[1]->As<ast::IntLiteralExpression>()->ValueAsU32(), 4u);
+    ASSERT_TRUE(values[1]->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(values[1]->As<ast::IntLiteralExpression>()->value, 4);
 
-  ASSERT_TRUE(values[2]->Is<ast::IntLiteralExpression>());
-  EXPECT_EQ(values[2]->As<ast::IntLiteralExpression>()->ValueAsU32(), 6u);
+    ASSERT_TRUE(values[2]->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(values[2]->As<ast::IntLiteralExpression>()->value, 6);
 }
 
 TEST_F(WorkgroupAttributeTest, Creation_WithIdentifier) {
-  auto* d = WorkgroupSize(2, 4, "depth");
-  auto values = d->Values();
+    auto* d = WorkgroupSize(2_i, 4_i, "depth");
+    auto values = d->Values();
 
-  ASSERT_TRUE(values[0]->Is<ast::IntLiteralExpression>());
-  EXPECT_EQ(values[0]->As<ast::IntLiteralExpression>()->ValueAsU32(), 2u);
+    ASSERT_TRUE(values[0]->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(values[0]->As<ast::IntLiteralExpression>()->value, 2);
 
-  ASSERT_TRUE(values[1]->Is<ast::IntLiteralExpression>());
-  EXPECT_EQ(values[1]->As<ast::IntLiteralExpression>()->ValueAsU32(), 4u);
+    ASSERT_TRUE(values[1]->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(values[1]->As<ast::IntLiteralExpression>()->value, 4);
 
-  auto* z_ident = As<ast::IdentifierExpression>(values[2]);
-  ASSERT_TRUE(z_ident);
-  EXPECT_EQ(Symbols().NameFor(z_ident->symbol), "depth");
+    auto* z_ident = As<ast::IdentifierExpression>(values[2]);
+    ASSERT_TRUE(z_ident);
+    EXPECT_EQ(Symbols().NameFor(z_ident->symbol), "depth");
 }
 
 }  // namespace
diff --git a/src/tint/bench/benchmark.cc b/src/tint/bench/benchmark.cc
index 4fd96e2..c00e51f 100644
--- a/src/tint/bench/benchmark.cc
+++ b/src/tint/bench/benchmark.cc
@@ -31,93 +31,93 @@
 /// @returns true if we successfully read the file.
 template <typename T>
 std::variant<std::vector<T>, Error> ReadFile(const std::string& input_file) {
-  FILE* file = nullptr;
+    FILE* file = nullptr;
 #if defined(_MSC_VER)
-  fopen_s(&file, input_file.c_str(), "rb");
+    fopen_s(&file, input_file.c_str(), "rb");
 #else
-  file = fopen(input_file.c_str(), "rb");
+    file = fopen(input_file.c_str(), "rb");
 #endif
-  if (!file) {
-    return Error{"Failed to open " + input_file};
-  }
+    if (!file) {
+        return Error{"Failed to open " + input_file};
+    }
 
-  fseek(file, 0, SEEK_END);
-  const auto file_size = static_cast<size_t>(ftell(file));
-  if (0 != (file_size % sizeof(T))) {
-    std::stringstream err;
-    err << "File " << input_file
-        << " does not contain an integral number of objects: " << file_size
-        << " bytes in the file, require " << sizeof(T) << " bytes per object";
+    fseek(file, 0, SEEK_END);
+    const auto file_size = static_cast<size_t>(ftell(file));
+    if (0 != (file_size % sizeof(T))) {
+        std::stringstream err;
+        err << "File " << input_file
+            << " does not contain an integral number of objects: " << file_size
+            << " bytes in the file, require " << sizeof(T) << " bytes per object";
+        fclose(file);
+        return Error{err.str()};
+    }
+    fseek(file, 0, SEEK_SET);
+
+    std::vector<T> buffer;
+    buffer.resize(file_size / sizeof(T));
+
+    size_t bytes_read = fread(buffer.data(), 1, file_size, file);
     fclose(file);
-    return Error{err.str()};
-  }
-  fseek(file, 0, SEEK_SET);
+    if (bytes_read != file_size) {
+        return Error{"Failed to read " + input_file};
+    }
 
-  std::vector<T> buffer;
-  buffer.resize(file_size / sizeof(T));
-
-  size_t bytes_read = fread(buffer.data(), 1, file_size, file);
-  fclose(file);
-  if (bytes_read != file_size) {
-    return Error{"Failed to read " + input_file};
-  }
-
-  return buffer;
+    return buffer;
 }
 
 bool FindBenchmarkInputDir() {
-  // Attempt to find the benchmark input files by searching up from the current
-  // working directory.
-  auto path = std::filesystem::current_path();
-  while (std::filesystem::is_directory(path)) {
-    auto test = path / "test" / "tint" / "benchmark";
-    if (std::filesystem::is_directory(test)) {
-      kInputFileDir = test;
-      return true;
+    // Attempt to find the benchmark input files by searching up from the current
+    // working directory.
+    auto path = std::filesystem::current_path();
+    while (std::filesystem::is_directory(path)) {
+        auto test = path / "test" / "tint" / "benchmark";
+        if (std::filesystem::is_directory(test)) {
+            kInputFileDir = test;
+            return true;
+        }
+        auto parent = path.parent_path();
+        if (path == parent) {
+            break;
+        }
+        path = parent;
     }
-    auto parent = path.parent_path();
-    if (path == parent) {
-      break;
-    }
-    path = parent;
-  }
-  return false;
+    return false;
 }
 
 }  // namespace
 
 std::variant<tint::Source::File, Error> LoadInputFile(std::string name) {
-  auto path = (kInputFileDir / name).string();
-  auto data = ReadFile<uint8_t>(path);
-  if (auto* buf = std::get_if<std::vector<uint8_t>>(&data)) {
-    return tint::Source::File(path, std::string(buf->begin(), buf->end()));
-  }
-  return std::get<Error>(data);
+    auto path = (kInputFileDir / name).string();
+    auto data = ReadFile<uint8_t>(path);
+    if (auto* buf = std::get_if<std::vector<uint8_t>>(&data)) {
+        return tint::Source::File(path, std::string(buf->begin(), buf->end()));
+    }
+    return std::get<Error>(data);
 }
 
 std::variant<ProgramAndFile, Error> LoadProgram(std::string name) {
-  auto res = bench::LoadInputFile(name);
-  if (auto err = std::get_if<bench::Error>(&res)) {
-    return *err;
-  }
-  auto& file = std::get<Source::File>(res);
-  auto program = reader::wgsl::Parse(&file);
-  if (program.Diagnostics().contains_errors()) {
-    return Error{program.Diagnostics().str()};
-  }
-  return ProgramAndFile{std::move(program), std::move(file)};
+    auto res = bench::LoadInputFile(name);
+    if (auto err = std::get_if<bench::Error>(&res)) {
+        return *err;
+    }
+    auto& file = std::get<Source::File>(res);
+    auto program = reader::wgsl::Parse(&file);
+    if (program.Diagnostics().contains_errors()) {
+        return Error{program.Diagnostics().str()};
+    }
+    return ProgramAndFile{std::move(program), std::move(file)};
 }
 
 }  // namespace tint::bench
 
 int main(int argc, char** argv) {
-  benchmark::Initialize(&argc, argv);
-  if (benchmark::ReportUnrecognizedArguments(argc, argv)) {
-    return 1;
-  }
-  if (!tint::bench::FindBenchmarkInputDir()) {
-    std::cerr << "failed to locate benchmark input files" << std::endl;
-    return 1;
-  }
-  benchmark::RunSpecifiedBenchmarks();
+    benchmark::Initialize(&argc, argv);
+    if (benchmark::ReportUnrecognizedArguments(argc, argv)) {
+        return 1;
+    }
+    if (!tint::bench::FindBenchmarkInputDir()) {
+        std::cerr << "failed to locate benchmark input files" << std::endl;
+        return 1;
+    }
+    benchmark::RunSpecifiedBenchmarks();
 }
diff --git a/src/tint/bench/benchmark.h b/src/tint/bench/benchmark.h
index 22605b2..733b1a7 100644
--- a/src/tint/bench/benchmark.h
+++ b/src/tint/bench/benchmark.h
@@ -28,16 +28,16 @@
 
 /// Error indicates an operation did not complete successfully.
 struct Error {
-  /// The error message.
-  std::string msg;
+    /// The error message.
+    std::string msg;
 };
 
 /// ProgramAndFile holds a Program and a Source::File.
 struct ProgramAndFile {
-  /// The tint program parsed from file.
-  Program program;
-  /// The source file
-  Source::File file;
+    /// The tint program parsed from file.
+    Program program;
+    /// The source file
+    Source::File file;
 };
 
 /// LoadInputFile attempts to load a benchmark input file with the given file
@@ -53,24 +53,23 @@
 std::variant<ProgramAndFile, Error> LoadProgram(std::string name);
 
 /// Declares a benchmark with the given function and WGSL file name
-#define TINT_BENCHMARK_WGSL_PROGRAM(FUNC, WGSL_NAME) \
-  BENCHMARK_CAPTURE(FUNC, WGSL_NAME, WGSL_NAME);
+#define TINT_BENCHMARK_WGSL_PROGRAM(FUNC, WGSL_NAME) BENCHMARK_CAPTURE(FUNC, WGSL_NAME, WGSL_NAME);
 
 /// Declares a set of benchmarks for the given function using a list of WGSL
 /// files in `<tint>/test/benchmark`.
-#define TINT_BENCHMARK_WGSL_PROGRAMS(FUNC)                                 \
-  TINT_BENCHMARK_WGSL_PROGRAM(FUNC, "animometer.wgsl");                    \
-  TINT_BENCHMARK_WGSL_PROGRAM(FUNC, "bloom-vertical-blur.wgsl");           \
-  TINT_BENCHMARK_WGSL_PROGRAM(FUNC, "cluster-lights.wgsl");                \
-  TINT_BENCHMARK_WGSL_PROGRAM(FUNC, "empty.wgsl");                         \
-  TINT_BENCHMARK_WGSL_PROGRAM(FUNC, "metaball-isosurface.wgsl");           \
-  TINT_BENCHMARK_WGSL_PROGRAM(FUNC, "particles.wgsl");                     \
-  TINT_BENCHMARK_WGSL_PROGRAM(FUNC, "shadow-fragment.wgsl");               \
-  TINT_BENCHMARK_WGSL_PROGRAM(FUNC, "simple-compute.wgsl");                \
-  TINT_BENCHMARK_WGSL_PROGRAM(FUNC, "simple-fragment.wgsl");               \
-  TINT_BENCHMARK_WGSL_PROGRAM(FUNC, "simple-vertex.wgsl");                 \
-  TINT_BENCHMARK_WGSL_PROGRAM(FUNC, "skinned-shadowed-pbr-fragment.wgsl"); \
-  TINT_BENCHMARK_WGSL_PROGRAM(FUNC, "skinned-shadowed-pbr-vertex.wgsl");
+#define TINT_BENCHMARK_WGSL_PROGRAMS(FUNC)                                   \
+    TINT_BENCHMARK_WGSL_PROGRAM(FUNC, "animometer.wgsl");                    \
+    TINT_BENCHMARK_WGSL_PROGRAM(FUNC, "bloom-vertical-blur.wgsl");           \
+    TINT_BENCHMARK_WGSL_PROGRAM(FUNC, "cluster-lights.wgsl");                \
+    TINT_BENCHMARK_WGSL_PROGRAM(FUNC, "empty.wgsl");                         \
+    TINT_BENCHMARK_WGSL_PROGRAM(FUNC, "metaball-isosurface.wgsl");           \
+    TINT_BENCHMARK_WGSL_PROGRAM(FUNC, "particles.wgsl");                     \
+    TINT_BENCHMARK_WGSL_PROGRAM(FUNC, "shadow-fragment.wgsl");               \
+    TINT_BENCHMARK_WGSL_PROGRAM(FUNC, "simple-compute.wgsl");                \
+    TINT_BENCHMARK_WGSL_PROGRAM(FUNC, "simple-fragment.wgsl");               \
+    TINT_BENCHMARK_WGSL_PROGRAM(FUNC, "simple-vertex.wgsl");                 \
+    TINT_BENCHMARK_WGSL_PROGRAM(FUNC, "skinned-shadowed-pbr-fragment.wgsl"); \
+    TINT_BENCHMARK_WGSL_PROGRAM(FUNC, "skinned-shadowed-pbr-vertex.wgsl");
 
 }  // namespace tint::bench
 
diff --git a/src/tint/builtin_table.cc b/src/tint/builtin_table.cc
index 13e7c5f..1a3c9cc 100644
--- a/src/tint/builtin_table.cc
+++ b/src/tint/builtin_table.cc
@@ -20,14 +20,14 @@
 #include <utility>
 
 #include "src/tint/program_builder.h"
-#include "src/tint/sem/atomic_type.h"
-#include "src/tint/sem/depth_multisampled_texture_type.h"
-#include "src/tint/sem/depth_texture_type.h"
-#include "src/tint/sem/external_texture_type.h"
-#include "src/tint/sem/multisampled_texture_type.h"
+#include "src/tint/sem/atomic.h"
+#include "src/tint/sem/depth_multisampled_texture.h"
+#include "src/tint/sem/depth_texture.h"
+#include "src/tint/sem/external_texture.h"
+#include "src/tint/sem/multisampled_texture.h"
 #include "src/tint/sem/pipeline_stage_set.h"
-#include "src/tint/sem/sampled_texture_type.h"
-#include "src/tint/sem/storage_texture_type.h"
+#include "src/tint/sem/sampled_texture.h"
+#include "src/tint/sem/storage_texture.h"
 #include "src/tint/utils/hash.h"
 #include "src/tint/utils/map.h"
 #include "src/tint/utils/math.h"
@@ -44,16 +44,14 @@
 
 /// A special type that matches all TypeMatchers
 class Any final : public Castable<Any, sem::Type> {
- public:
-  Any() = default;
-  ~Any() override = default;
+  public:
+    Any() = default;
+    ~Any() override = default;
 
-  // Stub implementations for sem::Type conformance.
-  size_t Hash() const override { return 0; }
-  bool Equals(const sem::Type&) const override { return false; }
-  std::string FriendlyName(const SymbolTable&) const override {
-    return "<any>";
-  }
+    // Stub implementations for sem::Type conformance.
+    size_t Hash() const override { return 0; }
+    bool Equals(const sem::Type&) const override { return false; }
+    std::string FriendlyName(const SymbolTable&) const override { return "<any>"; }
 };
 
 /// Number is an 32 bit unsigned integer, which can be in one of three states:
@@ -61,40 +59,40 @@
 /// * Valid   - a fixed integer value
 /// * Any     - matches any other non-invalid number
 struct Number {
-  static const Number any;
-  static const Number invalid;
+    static const Number any;
+    static const Number invalid;
 
-  /// Constructed as a valid number with the value v
-  explicit Number(uint32_t v) : value_(v), state_(kValid) {}
+    /// Constructed as a valid number with the value v
+    explicit Number(uint32_t v) : value_(v), state_(kValid) {}
 
-  /// @returns the value of the number
-  inline uint32_t Value() const { return value_; }
+    /// @returns the value of the number
+    inline uint32_t Value() const { return value_; }
 
-  /// @returns the true if the number is valid
-  inline bool IsValid() const { return state_ == kValid; }
+    /// @returns the true if the number is valid
+    inline bool IsValid() const { return state_ == kValid; }
 
-  /// @returns the true if the number is any
-  inline bool IsAny() const { return state_ == kAny; }
+    /// @returns the true if the number is any
+    inline bool IsAny() const { return state_ == kAny; }
 
-  /// Assignment operator.
-  /// The number becomes valid, with the value n
-  inline Number& operator=(uint32_t n) {
-    value_ = n;
-    state_ = kValid;
-    return *this;
-  }
+    /// Assignment operator.
+    /// The number becomes valid, with the value n
+    inline Number& operator=(uint32_t n) {
+        value_ = n;
+        state_ = kValid;
+        return *this;
+    }
 
- private:
-  enum State {
-    kInvalid,
-    kValid,
-    kAny,
-  };
+  private:
+    enum State {
+        kInvalid,
+        kValid,
+        kAny,
+    };
 
-  constexpr explicit Number(State state) : state_(state) {}
+    constexpr explicit Number(State state) : state_(state) {}
 
-  uint32_t value_ = 0;
-  State state_ = kInvalid;
+    uint32_t value_ = 0;
+    State state_ = kInvalid;
 };
 
 const Number Number::any{Number::kAny};
@@ -103,54 +101,54 @@
 /// ClosedState holds the state of the open / closed numbers and types.
 /// Used by the MatchState.
 class ClosedState {
- public:
-  explicit ClosedState(ProgramBuilder& b) : builder(b) {}
+  public:
+    explicit ClosedState(ProgramBuilder& b) : builder(b) {}
 
-  /// If the type with index `idx` is open, then it is closed with type `ty` and
-  /// Type() returns true. If the type is closed, then `Type()` returns true iff
-  /// it is equal to `ty`.
-  bool Type(uint32_t idx, const sem::Type* ty) {
-    auto res = types_.emplace(idx, ty);
-    return res.second || res.first->second == ty;
-  }
-
-  /// If the number with index `idx` is open, then it is closed with number
-  /// `number` and Num() returns true. If the number is closed, then `Num()`
-  /// returns true iff it is equal to `ty`.
-  bool Num(uint32_t idx, Number number) {
-    auto res = numbers_.emplace(idx, number.Value());
-    return res.second || res.first->second == number.Value();
-  }
-
-  /// Type returns the closed type with index `idx`.
-  /// An ICE is raised if the type is not closed.
-  const sem::Type* Type(uint32_t idx) const {
-    auto it = types_.find(idx);
-    if (it == types_.end()) {
-      TINT_ICE(Resolver, builder.Diagnostics())
-          << "type with index " << idx << " is not closed";
-      return nullptr;
+    /// If the type with index `idx` is open, then it is closed with type `ty` and
+    /// Type() returns true. If the type is closed, then `Type()` returns true iff
+    /// it is equal to `ty`.
+    bool Type(uint32_t idx, const sem::Type* ty) {
+        auto res = types_.emplace(idx, ty);
+        return res.second || res.first->second == ty;
     }
-    TINT_ASSERT(Resolver, it != types_.end());
-    return it->second;
-  }
 
-  /// Type returns the number type with index `idx`.
-  /// An ICE is raised if the number is not closed.
-  Number Num(uint32_t idx) const {
-    auto it = numbers_.find(idx);
-    if (it == numbers_.end()) {
-      TINT_ICE(Resolver, builder.Diagnostics())
-          << "number with index " << idx << " is not closed";
-      return Number::invalid;
+    /// If the number with index `idx` is open, then it is closed with number
+    /// `number` and Num() returns true. If the number is closed, then `Num()`
+    /// returns true iff it is equal to `ty`.
+    bool Num(uint32_t idx, Number number) {
+        auto res = numbers_.emplace(idx, number.Value());
+        return res.second || res.first->second == number.Value();
     }
-    return Number(it->second);
-  }
 
- private:
-  ProgramBuilder& builder;
-  std::unordered_map<uint32_t, const sem::Type*> types_;
-  std::unordered_map<uint32_t, uint32_t> numbers_;
+    /// Type returns the closed type with index `idx`.
+    /// An ICE is raised if the type is not closed.
+    const sem::Type* Type(uint32_t idx) const {
+        auto it = types_.find(idx);
+        if (it == types_.end()) {
+            TINT_ICE(Resolver, builder.Diagnostics())
+                << "type with index " << idx << " is not closed";
+            return nullptr;
+        }
+        TINT_ASSERT(Resolver, it != types_.end());
+        return it->second;
+    }
+
+    /// Type returns the number type with index `idx`.
+    /// An ICE is raised if the number is not closed.
+    Number Num(uint32_t idx) const {
+        auto it = numbers_.find(idx);
+        if (it == numbers_.end()) {
+            TINT_ICE(Resolver, builder.Diagnostics())
+                << "number with index " << idx << " is not closed";
+            return Number::invalid;
+        }
+        return Number(it->second);
+    }
+
+  private:
+    ProgramBuilder& builder;
+    std::unordered_map<uint32_t, const sem::Type*> types_;
+    std::unordered_map<uint32_t, uint32_t> numbers_;
 };
 
 /// Index type used for matcher indices
@@ -161,131 +159,125 @@
 
 /// MatchState holds the state used to match an overload.
 class MatchState {
- public:
-  MatchState(ProgramBuilder& b,
-             ClosedState& c,
-             const Matchers& m,
-             const OverloadInfo& o,
-             MatcherIndex const* matcher_indices)
-      : builder(b),
-        closed(c),
-        matchers(m),
-        overload(o),
-        matcher_indices_(matcher_indices) {}
+  public:
+    MatchState(ProgramBuilder& b,
+               ClosedState& c,
+               const Matchers& m,
+               const OverloadInfo& o,
+               MatcherIndex const* matcher_indices)
+        : builder(b), closed(c), matchers(m), overload(o), matcher_indices_(matcher_indices) {}
 
-  /// The program builder
-  ProgramBuilder& builder;
-  /// The open / closed types and numbers
-  ClosedState& closed;
-  /// The type and number matchers
-  Matchers const& matchers;
-  /// The current overload being evaluated
-  OverloadInfo const& overload;
+    /// The program builder
+    ProgramBuilder& builder;
+    /// The open / closed types and numbers
+    ClosedState& closed;
+    /// The type and number matchers
+    Matchers const& matchers;
+    /// The current overload being evaluated
+    OverloadInfo const& overload;
 
-  /// Type uses the next TypeMatcher from the matcher indices to match the type
-  /// `ty`. If the type matches, the canonical expected type is returned. If the
-  /// type `ty` does not match, then nullptr is returned.
-  /// @note: The matcher indices are progressed on calling.
-  const sem::Type* Type(const sem::Type* ty);
+    /// Type uses the next TypeMatcher from the matcher indices to match the type
+    /// `ty`. If the type matches, the canonical expected type is returned. If the
+    /// type `ty` does not match, then nullptr is returned.
+    /// @note: The matcher indices are progressed on calling.
+    const sem::Type* Type(const sem::Type* ty);
 
-  /// Num uses the next NumMatcher from the matcher indices to match the number
-  /// `num`. If the number matches, the canonical expected number is returned.
-  /// If the number `num` does not match, then an invalid number is returned.
-  /// @note: The matcher indices are progressed on calling.
-  Number Num(Number num);
+    /// Num uses the next NumMatcher from the matcher indices to match the number
+    /// `num`. If the number matches, the canonical expected number is returned.
+    /// If the number `num` does not match, then an invalid number is returned.
+    /// @note: The matcher indices are progressed on calling.
+    Number Num(Number num);
 
-  /// @returns a string representation of the next TypeMatcher from the matcher
-  /// indices.
-  /// @note: The matcher indices are progressed on calling.
-  std::string TypeName();
+    /// @returns a string representation of the next TypeMatcher from the matcher
+    /// indices.
+    /// @note: The matcher indices are progressed on calling.
+    std::string TypeName();
 
-  /// @returns a string representation of the next NumberMatcher from the
-  /// matcher indices.
-  /// @note: The matcher indices are progressed on calling.
-  std::string NumName();
+    /// @returns a string representation of the next NumberMatcher from the
+    /// matcher indices.
+    /// @note: The matcher indices are progressed on calling.
+    std::string NumName();
 
- private:
-  MatcherIndex const* matcher_indices_ = nullptr;
+  private:
+    MatcherIndex const* matcher_indices_ = nullptr;
 };
 
 /// A TypeMatcher is the interface used to match an type used as part of an
 /// overload's parameter or return type.
 class TypeMatcher {
- public:
-  /// Destructor
-  virtual ~TypeMatcher() = default;
+  public:
+    /// Destructor
+    virtual ~TypeMatcher() = default;
 
-  /// Checks whether the given type matches the matcher rules, and returns the
-  /// expected, canonicalized type on success.
-  /// Match may close open types and numbers in state.
-  /// @param type the type to match
-  /// @returns the canonicalized type on match, otherwise nullptr
-  virtual const sem::Type* Match(MatchState& state,
-                                 const sem::Type* type) const = 0;
+    /// Checks whether the given type matches the matcher rules, and returns the
+    /// expected, canonicalized type on success.
+    /// Match may close open types and numbers in state.
+    /// @param type the type to match
+    /// @returns the canonicalized type on match, otherwise nullptr
+    virtual const sem::Type* Match(MatchState& state, const sem::Type* type) const = 0;
 
-  /// @return a string representation of the matcher. Used for printing error
-  /// messages when no overload is found.
-  virtual std::string String(MatchState& state) const = 0;
+    /// @return a string representation of the matcher. Used for printing error
+    /// messages when no overload is found.
+    virtual std::string String(MatchState& state) const = 0;
 };
 
 /// A NumberMatcher is the interface used to match a number or enumerator used
 /// as part of an overload's parameter or return type.
 class NumberMatcher {
- public:
-  /// Destructor
-  virtual ~NumberMatcher() = default;
+  public:
+    /// Destructor
+    virtual ~NumberMatcher() = default;
 
-  /// Checks whether the given number matches the matcher rules.
-  /// Match may close open numbers in state.
-  /// @param number the number to match
-  /// @returns true if the argument type is as expected.
-  virtual Number Match(MatchState& state, Number number) const = 0;
+    /// Checks whether the given number matches the matcher rules.
+    /// Match may close open numbers in state.
+    /// @param number the number to match
+    /// @returns true if the argument type is as expected.
+    virtual Number Match(MatchState& state, Number number) const = 0;
 
-  /// @return a string representation of the matcher. Used for printing error
-  /// messages when no overload is found.
-  virtual std::string String(MatchState& state) const = 0;
+    /// @return a string representation of the matcher. Used for printing error
+    /// messages when no overload is found.
+    virtual std::string String(MatchState& state) const = 0;
 };
 
 /// OpenTypeMatcher is a Matcher for an open type.
 /// The OpenTypeMatcher will match against any type (so long as it is consistent
 /// across all uses in the overload)
 class OpenTypeMatcher : public TypeMatcher {
- public:
-  /// Constructor
-  explicit OpenTypeMatcher(uint32_t index) : index_(index) {}
+  public:
+    /// Constructor
+    explicit OpenTypeMatcher(uint32_t index) : index_(index) {}
 
-  const sem::Type* Match(MatchState& state,
-                         const sem::Type* type) const override {
-    if (type->Is<Any>()) {
-      return state.closed.Type(index_);
+    const sem::Type* Match(MatchState& state, const sem::Type* type) const override {
+        if (type->Is<Any>()) {
+            return state.closed.Type(index_);
+        }
+        return state.closed.Type(index_, type) ? type : nullptr;
     }
-    return state.closed.Type(index_, type) ? type : nullptr;
-  }
 
-  std::string String(MatchState& state) const override;
+    std::string String(MatchState& state) const override;
 
- private:
-  uint32_t index_;
+  private:
+    uint32_t index_;
 };
 
 /// OpenNumberMatcher is a Matcher for an open number.
 /// The OpenNumberMatcher will match against any number (so long as it is
 /// consistent for the overload)
 class OpenNumberMatcher : public NumberMatcher {
- public:
-  explicit OpenNumberMatcher(uint32_t index) : index_(index) {}
+  public:
+    explicit OpenNumberMatcher(uint32_t index) : index_(index) {}
 
-  Number Match(MatchState& state, Number number) const override {
-    if (number.IsAny()) {
-      return state.closed.Num(index_);
+    Number Match(MatchState& state, Number number) const override {
+        if (number.IsAny()) {
+            return state.closed.Num(index_);
+        }
+        return state.closed.Num(index_, number) ? number : Number::invalid;
     }
-    return state.closed.Num(index_, number) ? number : Number::invalid;
-  }
 
-  std::string String(MatchState& state) const override;
+    std::string String(MatchState& state) const override;
 
- private:
-  uint32_t index_;
+  private:
+    uint32_t index_;
 };
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -301,241 +293,227 @@
 using PipelineStage = ast::PipelineStage;
 
 bool match_bool(const sem::Type* ty) {
-  return ty->IsAnyOf<Any, sem::Bool>();
+    return ty->IsAnyOf<Any, sem::Bool>();
 }
 
 const sem::Bool* build_bool(MatchState& state) {
-  return state.builder.create<sem::Bool>();
+    return state.builder.create<sem::Bool>();
 }
 
 bool match_f32(const sem::Type* ty) {
-  return ty->IsAnyOf<Any, sem::F32>();
+    return ty->IsAnyOf<Any, sem::F32>();
 }
 
 const sem::I32* build_i32(MatchState& state) {
-  return state.builder.create<sem::I32>();
+    return state.builder.create<sem::I32>();
 }
 
 bool match_i32(const sem::Type* ty) {
-  return ty->IsAnyOf<Any, sem::I32>();
+    return ty->IsAnyOf<Any, sem::I32>();
 }
 
 const sem::U32* build_u32(MatchState& state) {
-  return state.builder.create<sem::U32>();
+    return state.builder.create<sem::U32>();
 }
 
 bool match_u32(const sem::Type* ty) {
-  return ty->IsAnyOf<Any, sem::U32>();
+    return ty->IsAnyOf<Any, sem::U32>();
 }
 
 const sem::F32* build_f32(MatchState& state) {
-  return state.builder.create<sem::F32>();
+    return state.builder.create<sem::F32>();
 }
 
 bool match_vec(const sem::Type* ty, Number& N, const sem::Type*& T) {
-  if (ty->Is<Any>()) {
-    N = Number::any;
-    T = ty;
-    return true;
-  }
+    if (ty->Is<Any>()) {
+        N = Number::any;
+        T = ty;
+        return true;
+    }
 
-  if (auto* v = ty->As<sem::Vector>()) {
-    N = v->Width();
-    T = v->type();
-    return true;
-  }
-  return false;
+    if (auto* v = ty->As<sem::Vector>()) {
+        N = v->Width();
+        T = v->type();
+        return true;
+    }
+    return false;
 }
 
 const sem::Vector* build_vec(MatchState& state, Number N, const sem::Type* el) {
-  return state.builder.create<sem::Vector>(el, N.Value());
+    return state.builder.create<sem::Vector>(el, N.Value());
 }
 
 template <int N>
 bool match_vec(const sem::Type* ty, const sem::Type*& T) {
-  if (ty->Is<Any>()) {
-    T = ty;
-    return true;
-  }
-
-  if (auto* v = ty->As<sem::Vector>()) {
-    if (v->Width() == N) {
-      T = v->type();
-      return true;
+    if (ty->Is<Any>()) {
+        T = ty;
+        return true;
     }
-  }
-  return false;
+
+    if (auto* v = ty->As<sem::Vector>()) {
+        if (v->Width() == N) {
+            T = v->type();
+            return true;
+        }
+    }
+    return false;
 }
 
 bool match_vec2(const sem::Type* ty, const sem::Type*& T) {
-  return match_vec<2>(ty, T);
+    return match_vec<2>(ty, T);
 }
 
 const sem::Vector* build_vec2(MatchState& state, const sem::Type* T) {
-  return build_vec(state, Number(2), T);
+    return build_vec(state, Number(2), T);
 }
 
 bool match_vec3(const sem::Type* ty, const sem::Type*& T) {
-  return match_vec<3>(ty, T);
+    return match_vec<3>(ty, T);
 }
 
 const sem::Vector* build_vec3(MatchState& state, const sem::Type* T) {
-  return build_vec(state, Number(3), T);
+    return build_vec(state, Number(3), T);
 }
 
 bool match_vec4(const sem::Type* ty, const sem::Type*& T) {
-  return match_vec<4>(ty, T);
+    return match_vec<4>(ty, T);
 }
 
 const sem::Vector* build_vec4(MatchState& state, const sem::Type* T) {
-  return build_vec(state, Number(4), T);
+    return build_vec(state, Number(4), T);
 }
 
 bool match_mat(const sem::Type* ty, Number& M, Number& N, const sem::Type*& T) {
-  if (ty->Is<Any>()) {
-    M = Number::any;
-    N = Number::any;
-    T = ty;
-    return true;
-  }
-  if (auto* m = ty->As<sem::Matrix>()) {
-    M = m->columns();
-    N = m->ColumnType()->Width();
-    T = m->type();
-    return true;
-  }
-  return false;
+    if (ty->Is<Any>()) {
+        M = Number::any;
+        N = Number::any;
+        T = ty;
+        return true;
+    }
+    if (auto* m = ty->As<sem::Matrix>()) {
+        M = m->columns();
+        N = m->ColumnType()->Width();
+        T = m->type();
+        return true;
+    }
+    return false;
 }
 
-const sem::Matrix* build_mat(MatchState& state,
-                             Number N,
-                             Number M,
-                             const sem::Type* T) {
-  auto* column_type = state.builder.create<sem::Vector>(T, M.Value());
-  return state.builder.create<sem::Matrix>(column_type, N.Value());
+const sem::Matrix* build_mat(MatchState& state, Number N, Number M, const sem::Type* T) {
+    auto* column_type = state.builder.create<sem::Vector>(T, M.Value());
+    return state.builder.create<sem::Matrix>(column_type, N.Value());
 }
 
 bool match_array(const sem::Type* ty, const sem::Type*& T) {
-  if (ty->Is<Any>()) {
-    T = ty;
-    return true;
-  }
-
-  if (auto* a = ty->As<sem::Array>()) {
-    if (a->Count() == 0) {
-      T = a->ElemType();
-      return true;
+    if (ty->Is<Any>()) {
+        T = ty;
+        return true;
     }
-  }
-  return false;
+
+    if (auto* a = ty->As<sem::Array>()) {
+        if (a->Count() == 0) {
+            T = a->ElemType();
+            return true;
+        }
+    }
+    return false;
 }
 
 const sem::Array* build_array(MatchState& state, const sem::Type* el) {
-  return state.builder.create<sem::Array>(el,
-                                          /* count */ 0u,
-                                          /* align */ 0u,
-                                          /* size */ 0u,
-                                          /* stride */ 0u,
-                                          /* stride_implicit */ 0u);
+    return state.builder.create<sem::Array>(el,
+                                            /* count */ 0u,
+                                            /* align */ 0u,
+                                            /* size */ 0u,
+                                            /* stride */ 0u,
+                                            /* stride_implicit */ 0u);
 }
 
 bool match_ptr(const sem::Type* ty, Number& S, const sem::Type*& T, Number& A) {
-  if (ty->Is<Any>()) {
-    S = Number::any;
-    T = ty;
-    A = Number::any;
-    return true;
-  }
+    if (ty->Is<Any>()) {
+        S = Number::any;
+        T = ty;
+        A = Number::any;
+        return true;
+    }
 
-  if (auto* p = ty->As<sem::Pointer>()) {
-    S = Number(static_cast<uint32_t>(p->StorageClass()));
-    T = p->StoreType();
-    A = Number(static_cast<uint32_t>(p->Access()));
-    return true;
-  }
-  return false;
+    if (auto* p = ty->As<sem::Pointer>()) {
+        S = Number(static_cast<uint32_t>(p->StorageClass()));
+        T = p->StoreType();
+        A = Number(static_cast<uint32_t>(p->Access()));
+        return true;
+    }
+    return false;
 }
 
-const sem::Pointer* build_ptr(MatchState& state,
-                              Number S,
-                              const sem::Type* T,
-                              Number& A) {
-  return state.builder.create<sem::Pointer>(
-      T, static_cast<ast::StorageClass>(S.Value()),
-      static_cast<ast::Access>(A.Value()));
+const sem::Pointer* build_ptr(MatchState& state, Number S, const sem::Type* T, Number& A) {
+    return state.builder.create<sem::Pointer>(T, static_cast<ast::StorageClass>(S.Value()),
+                                              static_cast<ast::Access>(A.Value()));
 }
 
 bool match_atomic(const sem::Type* ty, const sem::Type*& T) {
-  if (ty->Is<Any>()) {
-    T = ty;
-    return true;
-  }
+    if (ty->Is<Any>()) {
+        T = ty;
+        return true;
+    }
 
-  if (auto* a = ty->As<sem::Atomic>()) {
-    T = a->Type();
-    return true;
-  }
-  return false;
+    if (auto* a = ty->As<sem::Atomic>()) {
+        T = a->Type();
+        return true;
+    }
+    return false;
 }
 
 const sem::Atomic* build_atomic(MatchState& state, const sem::Type* T) {
-  return state.builder.create<sem::Atomic>(T);
+    return state.builder.create<sem::Atomic>(T);
 }
 
 bool match_sampler(const sem::Type* ty) {
-  if (ty->Is<Any>()) {
-    return true;
-  }
-  return ty->Is([](const sem::Sampler* s) {
-    return s->kind() == ast::SamplerKind::kSampler;
-  });
+    if (ty->Is<Any>()) {
+        return true;
+    }
+    return ty->Is([](const sem::Sampler* s) { return s->kind() == ast::SamplerKind::kSampler; });
 }
 
 const sem::Sampler* build_sampler(MatchState& state) {
-  return state.builder.create<sem::Sampler>(ast::SamplerKind::kSampler);
+    return state.builder.create<sem::Sampler>(ast::SamplerKind::kSampler);
 }
 
 bool match_sampler_comparison(const sem::Type* ty) {
-  if (ty->Is<Any>()) {
-    return true;
-  }
-  return ty->Is([](const sem::Sampler* s) {
-    return s->kind() == ast::SamplerKind::kComparisonSampler;
-  });
+    if (ty->Is<Any>()) {
+        return true;
+    }
+    return ty->Is(
+        [](const sem::Sampler* s) { return s->kind() == ast::SamplerKind::kComparisonSampler; });
 }
 
 const sem::Sampler* build_sampler_comparison(MatchState& state) {
-  return state.builder.create<sem::Sampler>(
-      ast::SamplerKind::kComparisonSampler);
+    return state.builder.create<sem::Sampler>(ast::SamplerKind::kComparisonSampler);
 }
 
-bool match_texture(const sem::Type* ty,
-                   ast::TextureDimension dim,
-                   const sem::Type*& T) {
-  if (ty->Is<Any>()) {
-    T = ty;
-    return true;
-  }
-  if (auto* v = ty->As<sem::SampledTexture>()) {
-    if (v->dim() == dim) {
-      T = v->type();
-      return true;
+bool match_texture(const sem::Type* ty, ast::TextureDimension dim, const sem::Type*& T) {
+    if (ty->Is<Any>()) {
+        T = ty;
+        return true;
     }
-  }
-  return false;
+    if (auto* v = ty->As<sem::SampledTexture>()) {
+        if (v->dim() == dim) {
+            T = v->type();
+            return true;
+        }
+    }
+    return false;
 }
 
 #define JOIN(a, b) a##b
 
-#define DECLARE_SAMPLED_TEXTURE(suffix, dim)                  \
-  bool JOIN(match_texture_, suffix)(const sem::Type* ty,      \
-                                    const sem::Type*& T) {    \
-    return match_texture(ty, dim, T);                         \
-  }                                                           \
-  const sem::SampledTexture* JOIN(build_texture_, suffix)(    \
-      MatchState & state, const sem::Type* T) {               \
-    return state.builder.create<sem::SampledTexture>(dim, T); \
-  }
+#define DECLARE_SAMPLED_TEXTURE(suffix, dim)                                      \
+    bool JOIN(match_texture_, suffix)(const sem::Type* ty, const sem::Type*& T) { \
+        return match_texture(ty, dim, T);                                         \
+    }                                                                             \
+    const sem::SampledTexture* JOIN(build_texture_, suffix)(MatchState & state,   \
+                                                            const sem::Type* T) { \
+        return state.builder.create<sem::SampledTexture>(dim, T);                 \
+    }
 
 DECLARE_SAMPLED_TEXTURE(1d, ast::TextureDimension::k1d)
 DECLARE_SAMPLED_TEXTURE(2d, ast::TextureDimension::k2d)
@@ -548,47 +526,45 @@
 bool match_texture_multisampled(const sem::Type* ty,
                                 ast::TextureDimension dim,
                                 const sem::Type*& T) {
-  if (ty->Is<Any>()) {
-    T = ty;
-    return true;
-  }
-  if (auto* v = ty->As<sem::MultisampledTexture>()) {
-    if (v->dim() == dim) {
-      T = v->type();
-      return true;
+    if (ty->Is<Any>()) {
+        T = ty;
+        return true;
     }
-  }
-  return false;
+    if (auto* v = ty->As<sem::MultisampledTexture>()) {
+        if (v->dim() == dim) {
+            T = v->type();
+            return true;
+        }
+    }
+    return false;
 }
 
-#define DECLARE_MULTISAMPLED_TEXTURE(suffix, dim)                            \
-  bool JOIN(match_texture_multisampled_, suffix)(const sem::Type* ty,        \
-                                                 const sem::Type*& T) {      \
-    return match_texture_multisampled(ty, dim, T);                           \
-  }                                                                          \
-  const sem::MultisampledTexture* JOIN(build_texture_multisampled_, suffix)( \
-      MatchState & state, const sem::Type* T) {                              \
-    return state.builder.create<sem::MultisampledTexture>(dim, T);           \
-  }
+#define DECLARE_MULTISAMPLED_TEXTURE(suffix, dim)                                              \
+    bool JOIN(match_texture_multisampled_, suffix)(const sem::Type* ty, const sem::Type*& T) { \
+        return match_texture_multisampled(ty, dim, T);                                         \
+    }                                                                                          \
+    const sem::MultisampledTexture* JOIN(build_texture_multisampled_, suffix)(                 \
+        MatchState & state, const sem::Type* T) {                                              \
+        return state.builder.create<sem::MultisampledTexture>(dim, T);                         \
+    }
 
 DECLARE_MULTISAMPLED_TEXTURE(2d, ast::TextureDimension::k2d)
 #undef DECLARE_MULTISAMPLED_TEXTURE
 
 bool match_texture_depth(const sem::Type* ty, ast::TextureDimension dim) {
-  if (ty->Is<Any>()) {
-    return true;
-  }
-  return ty->Is([&](const sem::DepthTexture* t) { return t->dim() == dim; });
+    if (ty->Is<Any>()) {
+        return true;
+    }
+    return ty->Is([&](const sem::DepthTexture* t) { return t->dim() == dim; });
 }
 
-#define DECLARE_DEPTH_TEXTURE(suffix, dim)                       \
-  bool JOIN(match_texture_depth_, suffix)(const sem::Type* ty) { \
-    return match_texture_depth(ty, dim);                         \
-  }                                                              \
-  const sem::DepthTexture* JOIN(build_texture_depth_,            \
-                                suffix)(MatchState & state) {    \
-    return state.builder.create<sem::DepthTexture>(dim);         \
-  }
+#define DECLARE_DEPTH_TEXTURE(suffix, dim)                                            \
+    bool JOIN(match_texture_depth_, suffix)(const sem::Type* ty) {                    \
+        return match_texture_depth(ty, dim);                                          \
+    }                                                                                 \
+    const sem::DepthTexture* JOIN(build_texture_depth_, suffix)(MatchState & state) { \
+        return state.builder.create<sem::DepthTexture>(dim);                          \
+    }
 
 DECLARE_DEPTH_TEXTURE(2d, ast::TextureDimension::k2d)
 DECLARE_DEPTH_TEXTURE(2d_array, ast::TextureDimension::k2dArray)
@@ -597,51 +573,45 @@
 #undef DECLARE_DEPTH_TEXTURE
 
 bool match_texture_depth_multisampled_2d(const sem::Type* ty) {
-  if (ty->Is<Any>()) {
-    return true;
-  }
-  return ty->Is([&](const sem::DepthMultisampledTexture* t) {
-    return t->dim() == ast::TextureDimension::k2d;
-  });
-}
-
-sem::DepthMultisampledTexture* build_texture_depth_multisampled_2d(
-    MatchState& state) {
-  return state.builder.create<sem::DepthMultisampledTexture>(
-      ast::TextureDimension::k2d);
-}
-
-bool match_texture_storage(const sem::Type* ty,
-                           ast::TextureDimension dim,
-                           Number& F,
-                           Number& A) {
-  if (ty->Is<Any>()) {
-    F = Number::any;
-    A = Number::any;
-    return true;
-  }
-  if (auto* v = ty->As<sem::StorageTexture>()) {
-    if (v->dim() == dim) {
-      F = Number(static_cast<uint32_t>(v->texel_format()));
-      A = Number(static_cast<uint32_t>(v->access()));
-      return true;
+    if (ty->Is<Any>()) {
+        return true;
     }
-  }
-  return false;
+    return ty->Is([&](const sem::DepthMultisampledTexture* t) {
+        return t->dim() == ast::TextureDimension::k2d;
+    });
 }
 
-#define DECLARE_STORAGE_TEXTURE(suffix, dim)                                  \
-  bool JOIN(match_texture_storage_, suffix)(const sem::Type* ty, Number& F,   \
-                                            Number& A) {                      \
-    return match_texture_storage(ty, dim, F, A);                              \
-  }                                                                           \
-  const sem::StorageTexture* JOIN(build_texture_storage_, suffix)(            \
-      MatchState & state, Number F, Number A) {                               \
-    auto format = static_cast<TexelFormat>(F.Value());                        \
-    auto access = static_cast<Access>(A.Value());                             \
-    auto* T = sem::StorageTexture::SubtypeFor(format, state.builder.Types()); \
-    return state.builder.create<sem::StorageTexture>(dim, format, access, T); \
-  }
+sem::DepthMultisampledTexture* build_texture_depth_multisampled_2d(MatchState& state) {
+    return state.builder.create<sem::DepthMultisampledTexture>(ast::TextureDimension::k2d);
+}
+
+bool match_texture_storage(const sem::Type* ty, ast::TextureDimension dim, Number& F, Number& A) {
+    if (ty->Is<Any>()) {
+        F = Number::any;
+        A = Number::any;
+        return true;
+    }
+    if (auto* v = ty->As<sem::StorageTexture>()) {
+        if (v->dim() == dim) {
+            F = Number(static_cast<uint32_t>(v->texel_format()));
+            A = Number(static_cast<uint32_t>(v->access()));
+            return true;
+        }
+    }
+    return false;
+}
+
+#define DECLARE_STORAGE_TEXTURE(suffix, dim)                                                      \
+    bool JOIN(match_texture_storage_, suffix)(const sem::Type* ty, Number& F, Number& A) {        \
+        return match_texture_storage(ty, dim, F, A);                                              \
+    }                                                                                             \
+    const sem::StorageTexture* JOIN(build_texture_storage_, suffix)(MatchState & state, Number F, \
+                                                                    Number A) {                   \
+        auto format = static_cast<TexelFormat>(F.Value());                                        \
+        auto access = static_cast<Access>(A.Value());                                             \
+        auto* T = sem::StorageTexture::SubtypeFor(format, state.builder.Types());                 \
+        return state.builder.create<sem::StorageTexture>(dim, format, access, T);                 \
+    }
 
 DECLARE_STORAGE_TEXTURE(1d, ast::TextureDimension::k1d)
 DECLARE_STORAGE_TEXTURE(2d, ast::TextureDimension::k2d)
@@ -650,158 +620,154 @@
 #undef DECLARE_STORAGE_TEXTURE
 
 bool match_texture_external(const sem::Type* ty) {
-  return ty->IsAnyOf<Any, sem::ExternalTexture>();
+    return ty->IsAnyOf<Any, sem::ExternalTexture>();
 }
 
 const sem::ExternalTexture* build_texture_external(MatchState& state) {
-  return state.builder.create<sem::ExternalTexture>();
+    return state.builder.create<sem::ExternalTexture>();
 }
 
 // Builtin types starting with a _ prefix cannot be declared in WGSL, so they
 // can only be used as return types. Because of this, they must only match Any,
 // which is used as the return type matcher.
 bool match_modf_result(const sem::Type* ty) {
-  return ty->Is<Any>();
+    return ty->Is<Any>();
 }
 bool match_modf_result_vec(const sem::Type* ty, Number& N) {
-  if (!ty->Is<Any>()) {
-    return false;
-  }
-  N = Number::any;
-  return true;
+    if (!ty->Is<Any>()) {
+        return false;
+    }
+    N = Number::any;
+    return true;
 }
 bool match_frexp_result(const sem::Type* ty) {
-  return ty->Is<Any>();
+    return ty->Is<Any>();
 }
 bool match_frexp_result_vec(const sem::Type* ty, Number& N) {
-  if (!ty->Is<Any>()) {
-    return false;
-  }
-  N = Number::any;
-  return true;
+    if (!ty->Is<Any>()) {
+        return false;
+    }
+    N = Number::any;
+    return true;
 }
 
 struct NameAndType {
-  std::string name;
-  sem::Type* type;
+    std::string name;
+    sem::Type* type;
 };
-const sem::Struct* build_struct(
-    MatchState& state,
-    std::string name,
-    std::initializer_list<NameAndType> member_names_and_types) {
-  uint32_t offset = 0;
-  uint32_t max_align = 0;
-  sem::StructMemberList members;
-  for (auto& m : member_names_and_types) {
-    uint32_t align = m.type->Align();
-    uint32_t size = m.type->Size();
-    offset = utils::RoundUp(align, offset);
-    max_align = std::max(max_align, align);
-    members.emplace_back(state.builder.create<sem::StructMember>(
+const sem::Struct* build_struct(MatchState& state,
+                                std::string name,
+                                std::initializer_list<NameAndType> member_names_and_types) {
+    uint32_t offset = 0;
+    uint32_t max_align = 0;
+    sem::StructMemberList members;
+    for (auto& m : member_names_and_types) {
+        uint32_t align = m.type->Align();
+        uint32_t size = m.type->Size();
+        offset = utils::RoundUp(align, offset);
+        max_align = std::max(max_align, align);
+        members.emplace_back(state.builder.create<sem::StructMember>(
+            /* declaration */ nullptr,
+            /* name */ state.builder.Sym(m.name),
+            /* type */ m.type,
+            /* index */ static_cast<uint32_t>(members.size()),
+            /* offset */ offset,
+            /* align */ align,
+            /* size */ size));
+        offset += size;
+    }
+    uint32_t size_without_padding = offset;
+    uint32_t size_with_padding = utils::RoundUp(max_align, offset);
+    return state.builder.create<sem::Struct>(
         /* declaration */ nullptr,
-        /* name */ state.builder.Sym(m.name),
-        /* type */ m.type,
-        /* index */ static_cast<uint32_t>(members.size()),
-        /* offset */ offset,
-        /* align */ align,
-        /* size */ size));
-    offset += size;
-  }
-  uint32_t size_without_padding = offset;
-  uint32_t size_with_padding = utils::RoundUp(max_align, offset);
-  return state.builder.create<sem::Struct>(
-      /* declaration */ nullptr,
-      /* name */ state.builder.Sym(name),
-      /* members */ members,
-      /* align */ max_align,
-      /* size */ size_with_padding,
-      /* size_no_padding */ size_without_padding);
+        /* name */ state.builder.Sym(name),
+        /* members */ members,
+        /* align */ max_align,
+        /* size */ size_with_padding,
+        /* size_no_padding */ size_without_padding);
 }
 
 const sem::Struct* build_modf_result(MatchState& state) {
-  auto* f32 = state.builder.create<sem::F32>();
-  return build_struct(state, "__modf_result", {{"fract", f32}, {"whole", f32}});
+    auto* f32 = state.builder.create<sem::F32>();
+    return build_struct(state, "__modf_result", {{"fract", f32}, {"whole", f32}});
 }
 const sem::Struct* build_modf_result_vec(MatchState& state, Number& n) {
-  auto* vec_f32 = state.builder.create<sem::Vector>(
-      state.builder.create<sem::F32>(), n.Value());
-  return build_struct(state, "__modf_result_vec" + std::to_string(n.Value()),
-                      {{"fract", vec_f32}, {"whole", vec_f32}});
+    auto* vec_f32 = state.builder.create<sem::Vector>(state.builder.create<sem::F32>(), n.Value());
+    return build_struct(state, "__modf_result_vec" + std::to_string(n.Value()),
+                        {{"fract", vec_f32}, {"whole", vec_f32}});
 }
 const sem::Struct* build_frexp_result(MatchState& state) {
-  auto* f32 = state.builder.create<sem::F32>();
-  auto* i32 = state.builder.create<sem::I32>();
-  return build_struct(state, "__frexp_result", {{"sig", f32}, {"exp", i32}});
+    auto* f32 = state.builder.create<sem::F32>();
+    auto* i32 = state.builder.create<sem::I32>();
+    return build_struct(state, "__frexp_result", {{"sig", f32}, {"exp", i32}});
 }
 const sem::Struct* build_frexp_result_vec(MatchState& state, Number& n) {
-  auto* vec_f32 = state.builder.create<sem::Vector>(
-      state.builder.create<sem::F32>(), n.Value());
-  auto* vec_i32 = state.builder.create<sem::Vector>(
-      state.builder.create<sem::I32>(), n.Value());
-  return build_struct(state, "__frexp_result_vec" + std::to_string(n.Value()),
-                      {{"sig", vec_f32}, {"exp", vec_i32}});
+    auto* vec_f32 = state.builder.create<sem::Vector>(state.builder.create<sem::F32>(), n.Value());
+    auto* vec_i32 = state.builder.create<sem::Vector>(state.builder.create<sem::I32>(), n.Value());
+    return build_struct(state, "__frexp_result_vec" + std::to_string(n.Value()),
+                        {{"sig", vec_f32}, {"exp", vec_i32}});
 }
 
 /// ParameterInfo describes a parameter
 struct ParameterInfo {
-  /// The parameter usage (parameter name in definition file)
-  const ParameterUsage usage;
+    /// The parameter usage (parameter name in definition file)
+    const ParameterUsage usage;
 
-  /// Pointer to a list of indices that are used to match the parameter type.
-  /// The matcher indices index on Matchers::type and / or Matchers::number.
-  /// These indices are consumed by the matchers themselves.
-  /// The first index is always a TypeMatcher.
-  MatcherIndex const* const matcher_indices;
+    /// Pointer to a list of indices that are used to match the parameter type.
+    /// The matcher indices index on Matchers::type and / or Matchers::number.
+    /// These indices are consumed by the matchers themselves.
+    /// The first index is always a TypeMatcher.
+    MatcherIndex const* const matcher_indices;
 };
 
 /// OpenTypeInfo describes an open type
 struct OpenTypeInfo {
-  /// Name of the open type (e.g. 'T')
-  const char* name;
-  /// Optional type matcher constraint.
-  /// Either an index in Matchers::type, or kNoMatcher
-  const MatcherIndex matcher_index;
+    /// Name of the open type (e.g. 'T')
+    const char* name;
+    /// Optional type matcher constraint.
+    /// Either an index in Matchers::type, or kNoMatcher
+    const MatcherIndex matcher_index;
 };
 
 /// OpenNumberInfo describes an open number
 struct OpenNumberInfo {
-  /// Name of the open number (e.g. 'N')
-  const char* name;
-  /// Optional number matcher constraint.
-  /// Either an index in Matchers::number, or kNoMatcher
-  const MatcherIndex matcher_index;
+    /// Name of the open number (e.g. 'N')
+    const char* name;
+    /// Optional number matcher constraint.
+    /// Either an index in Matchers::number, or kNoMatcher
+    const MatcherIndex matcher_index;
 };
 
 /// OverloadInfo describes a single function overload
 struct OverloadInfo {
-  /// Total number of parameters for the overload
-  const uint8_t num_parameters;
-  /// Total number of open types for the overload
-  const uint8_t num_open_types;
-  /// Total number of open numbers for the overload
-  const uint8_t num_open_numbers;
-  /// Pointer to the first open type
-  OpenTypeInfo const* const open_types;
-  /// Pointer to the first open number
-  OpenNumberInfo const* const open_numbers;
-  /// Pointer to the first parameter
-  ParameterInfo const* const parameters;
-  /// Pointer to a list of matcher indices that index on Matchers::type and
-  /// Matchers::number, used to build the return type. If the function has no
-  /// return type then this is null
-  MatcherIndex const* const return_matcher_indices;
-  /// The pipeline stages that this overload can be used in
-  PipelineStageSet supported_stages;
-  /// True if the overload is marked as deprecated
-  bool is_deprecated;
+    /// Total number of parameters for the overload
+    const uint8_t num_parameters;
+    /// Total number of open types for the overload
+    const uint8_t num_open_types;
+    /// Total number of open numbers for the overload
+    const uint8_t num_open_numbers;
+    /// Pointer to the first open type
+    OpenTypeInfo const* const open_types;
+    /// Pointer to the first open number
+    OpenNumberInfo const* const open_numbers;
+    /// Pointer to the first parameter
+    ParameterInfo const* const parameters;
+    /// Pointer to a list of matcher indices that index on Matchers::type and
+    /// Matchers::number, used to build the return type. If the function has no
+    /// return type then this is null
+    MatcherIndex const* const return_matcher_indices;
+    /// The pipeline stages that this overload can be used in
+    PipelineStageSet supported_stages;
+    /// True if the overload is marked as deprecated
+    bool is_deprecated;
 };
 
 /// BuiltinInfo describes a builtin function
 struct BuiltinInfo {
-  /// Number of overloads of the builtin function
-  const uint8_t num_overloads;
-  /// Pointer to the start of the overloads for the function
-  OverloadInfo const* const overloads;
+    /// Number of overloads of the builtin function
+    const uint8_t num_overloads;
+    /// Pointer to the start of the overloads for the function
+    OverloadInfo const* const overloads;
 };
 
 #include "builtin_table.inl"
@@ -809,79 +775,77 @@
 /// BuiltinPrototype describes a fully matched builtin function, which is
 /// used as a lookup for building unique sem::Builtin instances.
 struct BuiltinPrototype {
-  /// Parameter describes a single parameter
-  struct Parameter {
-    /// Parameter type
-    const sem::Type* const type;
-    /// Parameter usage
-    ParameterUsage const usage = ParameterUsage::kNone;
-  };
+    /// Parameter describes a single parameter
+    struct Parameter {
+        /// Parameter type
+        const sem::Type* const type;
+        /// Parameter usage
+        ParameterUsage const usage = ParameterUsage::kNone;
+    };
 
-  /// Hasher provides a hash function for the BuiltinPrototype
-  struct Hasher {
-    /// @param i the BuiltinPrototype to create a hash for
-    /// @return the hash value
-    inline std::size_t operator()(const BuiltinPrototype& i) const {
-      size_t hash = utils::Hash(i.parameters.size());
-      for (auto& p : i.parameters) {
-        utils::HashCombine(&hash, p.type, p.usage);
-      }
-      return utils::Hash(hash, i.type, i.return_type, i.supported_stages,
-                         i.is_deprecated);
-    }
-  };
+    /// Hasher provides a hash function for the BuiltinPrototype
+    struct Hasher {
+        /// @param i the BuiltinPrototype to create a hash for
+        /// @return the hash value
+        inline std::size_t operator()(const BuiltinPrototype& i) const {
+            size_t hash = utils::Hash(i.parameters.size());
+            for (auto& p : i.parameters) {
+                utils::HashCombine(&hash, p.type, p.usage);
+            }
+            return utils::Hash(hash, i.type, i.return_type, i.supported_stages, i.is_deprecated);
+        }
+    };
 
-  sem::BuiltinType type = sem::BuiltinType::kNone;
-  std::vector<Parameter> parameters;
-  sem::Type const* return_type = nullptr;
-  PipelineStageSet supported_stages;
-  bool is_deprecated = false;
+    sem::BuiltinType type = sem::BuiltinType::kNone;
+    std::vector<Parameter> parameters;
+    sem::Type const* return_type = nullptr;
+    PipelineStageSet supported_stages;
+    bool is_deprecated = false;
 };
 
 /// Equality operator for BuiltinPrototype
 bool operator==(const BuiltinPrototype& a, const BuiltinPrototype& b) {
-  if (a.type != b.type || a.supported_stages != b.supported_stages ||
-      a.return_type != b.return_type || a.is_deprecated != b.is_deprecated ||
-      a.parameters.size() != b.parameters.size()) {
-    return false;
-  }
-  for (size_t i = 0; i < a.parameters.size(); i++) {
-    auto& pa = a.parameters[i];
-    auto& pb = b.parameters[i];
-    if (pa.type != pb.type || pa.usage != pb.usage) {
-      return false;
+    if (a.type != b.type || a.supported_stages != b.supported_stages ||
+        a.return_type != b.return_type || a.is_deprecated != b.is_deprecated ||
+        a.parameters.size() != b.parameters.size()) {
+        return false;
     }
-  }
-  return true;
+    for (size_t i = 0; i < a.parameters.size(); i++) {
+        auto& pa = a.parameters[i];
+        auto& pb = b.parameters[i];
+        if (pa.type != pb.type || pa.usage != pb.usage) {
+            return false;
+        }
+    }
+    return true;
 }
 
 /// Impl is the private implementation of the BuiltinTable interface.
 class Impl : public BuiltinTable {
- public:
-  explicit Impl(ProgramBuilder& builder);
+  public:
+    explicit Impl(ProgramBuilder& builder);
 
-  const sem::Builtin* Lookup(sem::BuiltinType builtin_type,
-                             const std::vector<const sem::Type*>& args,
-                             const Source& source) override;
+    const sem::Builtin* Lookup(sem::BuiltinType builtin_type,
+                               const std::vector<const sem::Type*>& args,
+                               const Source& source) override;
 
- private:
-  const sem::Builtin* Match(sem::BuiltinType builtin_type,
-                            const OverloadInfo& overload,
-                            const std::vector<const sem::Type*>& args,
-                            int& match_score);
+  private:
+    const sem::Builtin* Match(sem::BuiltinType builtin_type,
+                              const OverloadInfo& overload,
+                              const std::vector<const sem::Type*>& args,
+                              int& match_score);
 
-  MatchState Match(ClosedState& closed,
-                   const OverloadInfo& overload,
-                   MatcherIndex const* matcher_indices) const;
-
-  void PrintOverload(std::ostream& ss,
+    MatchState Match(ClosedState& closed,
                      const OverloadInfo& overload,
-                     sem::BuiltinType builtin_type) const;
+                     MatcherIndex const* matcher_indices) const;
 
-  ProgramBuilder& builder;
-  Matchers matchers;
-  std::unordered_map<BuiltinPrototype, sem::Builtin*, BuiltinPrototype::Hasher>
-      builtins;
+    void PrintOverload(std::ostream& ss,
+                       const OverloadInfo& overload,
+                       sem::BuiltinType builtin_type) const;
+
+    ProgramBuilder& builder;
+    Matchers matchers;
+    std::unordered_map<BuiltinPrototype, sem::Builtin*, BuiltinPrototype::Hasher> builtins;
 };
 
 /// @return a string representing a call to a builtin with the given argument
@@ -889,29 +853,29 @@
 std::string CallSignature(ProgramBuilder& builder,
                           sem::BuiltinType builtin_type,
                           const std::vector<const sem::Type*>& args) {
-  std::stringstream ss;
-  ss << sem::str(builtin_type) << "(";
-  {
-    bool first = true;
-    for (auto* arg : args) {
-      if (!first) {
-        ss << ", ";
-      }
-      first = false;
-      ss << arg->UnwrapRef()->FriendlyName(builder.Symbols());
+    std::stringstream ss;
+    ss << sem::str(builtin_type) << "(";
+    {
+        bool first = true;
+        for (auto* arg : args) {
+            if (!first) {
+                ss << ", ";
+            }
+            first = false;
+            ss << arg->UnwrapRef()->FriendlyName(builder.Symbols());
+        }
     }
-  }
-  ss << ")";
+    ss << ")";
 
-  return ss.str();
+    return ss.str();
 }
 
 std::string OpenTypeMatcher::String(MatchState& state) const {
-  return state.overload.open_types[index_].name;
+    return state.overload.open_types[index_].name;
 }
 
 std::string OpenNumberMatcher::String(MatchState& state) const {
-  return state.overload.open_numbers[index_].name;
+    return state.overload.open_numbers[index_].name;
 }
 
 Impl::Impl(ProgramBuilder& b) : builder(b) {}
@@ -919,246 +883,241 @@
 const sem::Builtin* Impl::Lookup(sem::BuiltinType builtin_type,
                                  const std::vector<const sem::Type*>& args,
                                  const Source& source) {
-  // Candidate holds information about a mismatched overload that could be what
-  // the user intended to call.
-  struct Candidate {
-    const OverloadInfo* overload;
-    int score;
-  };
+    // Candidate holds information about a mismatched overload that could be what
+    // the user intended to call.
+    struct Candidate {
+        const OverloadInfo* overload;
+        int score;
+    };
 
-  // The list of failed matches that had promise.
-  std::vector<Candidate> candidates;
+    // The list of failed matches that had promise.
+    std::vector<Candidate> candidates;
 
-  auto& builtin = kBuiltins[static_cast<uint32_t>(builtin_type)];
-  for (uint32_t o = 0; o < builtin.num_overloads; o++) {
-    int match_score = 1000;
-    auto& overload = builtin.overloads[o];
-    if (auto* match = Match(builtin_type, overload, args, match_score)) {
-      return match;
+    auto& builtin = kBuiltins[static_cast<uint32_t>(builtin_type)];
+    for (uint32_t o = 0; o < builtin.num_overloads; o++) {
+        int match_score = 1000;
+        auto& overload = builtin.overloads[o];
+        if (auto* match = Match(builtin_type, overload, args, match_score)) {
+            return match;
+        }
+        if (match_score > 0) {
+            candidates.emplace_back(Candidate{&overload, match_score});
+        }
     }
-    if (match_score > 0) {
-      candidates.emplace_back(Candidate{&overload, match_score});
-    }
-  }
 
-  // Sort the candidates with the most promising first
-  std::stable_sort(
-      candidates.begin(), candidates.end(),
-      [](const Candidate& a, const Candidate& b) { return a.score > b.score; });
+    // Sort the candidates with the most promising first
+    std::stable_sort(candidates.begin(), candidates.end(),
+                     [](const Candidate& a, const Candidate& b) { return a.score > b.score; });
 
-  // Generate an error message
-  std::stringstream ss;
-  ss << "no matching call to " << CallSignature(builder, builtin_type, args)
-     << std::endl;
-  if (!candidates.empty()) {
-    ss << std::endl;
-    ss << candidates.size() << " candidate function"
-       << (candidates.size() > 1 ? "s:" : ":") << std::endl;
-    for (auto& candidate : candidates) {
-      ss << "  ";
-      PrintOverload(ss, *candidate.overload, builtin_type);
-      ss << std::endl;
+    // Generate an error message
+    std::stringstream ss;
+    ss << "no matching call to " << CallSignature(builder, builtin_type, args) << std::endl;
+    if (!candidates.empty()) {
+        ss << std::endl;
+        ss << candidates.size() << " candidate function" << (candidates.size() > 1 ? "s:" : ":")
+           << std::endl;
+        for (auto& candidate : candidates) {
+            ss << "  ";
+            PrintOverload(ss, *candidate.overload, builtin_type);
+            ss << std::endl;
+        }
     }
-  }
-  builder.Diagnostics().add_error(diag::System::Resolver, ss.str(), source);
-  return nullptr;
+    builder.Diagnostics().add_error(diag::System::Resolver, ss.str(), source);
+    return nullptr;
 }
 
 const sem::Builtin* Impl::Match(sem::BuiltinType builtin_type,
                                 const OverloadInfo& overload,
                                 const std::vector<const sem::Type*>& args,
                                 int& match_score) {
-  // Score wait for argument <-> parameter count matches / mismatches
-  constexpr int kScorePerParamArgMismatch = -1;
-  constexpr int kScorePerMatchedParam = 2;
-  constexpr int kScorePerMatchedOpenType = 1;
-  constexpr int kScorePerMatchedOpenNumber = 1;
+    // Score wait for argument <-> parameter count matches / mismatches
+    constexpr int kScorePerParamArgMismatch = -1;
+    constexpr int kScorePerMatchedParam = 2;
+    constexpr int kScorePerMatchedOpenType = 1;
+    constexpr int kScorePerMatchedOpenNumber = 1;
 
-  auto num_parameters = overload.num_parameters;
-  auto num_arguments = static_cast<decltype(num_parameters)>(args.size());
+    auto num_parameters = overload.num_parameters;
+    auto num_arguments = static_cast<decltype(num_parameters)>(args.size());
 
-  bool overload_matched = true;
+    bool overload_matched = true;
 
-  if (num_parameters != num_arguments) {
-    match_score +=
-        kScorePerParamArgMismatch * (std::max(num_parameters, num_arguments) -
-                                     std::min(num_parameters, num_arguments));
-    overload_matched = false;
-  }
+    if (num_parameters != num_arguments) {
+        match_score += kScorePerParamArgMismatch * (std::max(num_parameters, num_arguments) -
+                                                    std::min(num_parameters, num_arguments));
+        overload_matched = false;
+    }
 
-  ClosedState closed(builder);
+    ClosedState closed(builder);
 
-  std::vector<BuiltinPrototype::Parameter> parameters;
+    std::vector<BuiltinPrototype::Parameter> parameters;
 
-  auto num_params = std::min(num_parameters, num_arguments);
-  for (uint32_t p = 0; p < num_params; p++) {
-    auto& parameter = overload.parameters[p];
-    auto* indices = parameter.matcher_indices;
-    auto* type = Match(closed, overload, indices).Type(args[p]->UnwrapRef());
-    if (type) {
-      parameters.emplace_back(
-          BuiltinPrototype::Parameter{type, parameter.usage});
-      match_score += kScorePerMatchedParam;
+    auto num_params = std::min(num_parameters, num_arguments);
+    for (uint32_t p = 0; p < num_params; p++) {
+        auto& parameter = overload.parameters[p];
+        auto* indices = parameter.matcher_indices;
+        auto* type = Match(closed, overload, indices).Type(args[p]->UnwrapRef());
+        if (type) {
+            parameters.emplace_back(BuiltinPrototype::Parameter{type, parameter.usage});
+            match_score += kScorePerMatchedParam;
+        } else {
+            overload_matched = false;
+        }
+    }
+
+    if (overload_matched) {
+        // Check all constrained open types matched
+        for (uint32_t ot = 0; ot < overload.num_open_types; ot++) {
+            auto& open_type = overload.open_types[ot];
+            if (open_type.matcher_index != kNoMatcher) {
+                auto* index = &open_type.matcher_index;
+                if (Match(closed, overload, index).Type(closed.Type(ot))) {
+                    match_score += kScorePerMatchedOpenType;
+                } else {
+                    overload_matched = false;
+                }
+            }
+        }
+    }
+
+    if (overload_matched) {
+        // Check all constrained open numbers matched
+        for (uint32_t on = 0; on < overload.num_open_numbers; on++) {
+            auto& open_number = overload.open_numbers[on];
+            if (open_number.matcher_index != kNoMatcher) {
+                auto* index = &open_number.matcher_index;
+                if (Match(closed, overload, index).Num(closed.Num(on)).IsValid()) {
+                    match_score += kScorePerMatchedOpenNumber;
+                } else {
+                    overload_matched = false;
+                }
+            }
+        }
+    }
+
+    if (!overload_matched) {
+        return nullptr;
+    }
+
+    // Build the return type
+    const sem::Type* return_type = nullptr;
+    if (auto* indices = overload.return_matcher_indices) {
+        Any any;
+        return_type = Match(closed, overload, indices).Type(&any);
+        if (!return_type) {
+            std::stringstream ss;
+            PrintOverload(ss, overload, builtin_type);
+            TINT_ICE(Resolver, builder.Diagnostics())
+                << "MatchState.Match() returned null for " << ss.str();
+            return nullptr;
+        }
     } else {
-      overload_matched = false;
+        return_type = builder.create<sem::Void>();
     }
-  }
 
-  if (overload_matched) {
-    // Check all constrained open types matched
-    for (uint32_t ot = 0; ot < overload.num_open_types; ot++) {
-      auto& open_type = overload.open_types[ot];
-      if (open_type.matcher_index != kNoMatcher) {
-        auto* index = &open_type.matcher_index;
-        if (Match(closed, overload, index).Type(closed.Type(ot))) {
-          match_score += kScorePerMatchedOpenType;
-        } else {
-          overload_matched = false;
+    BuiltinPrototype builtin;
+    builtin.type = builtin_type;
+    builtin.return_type = return_type;
+    builtin.parameters = std::move(parameters);
+    builtin.supported_stages = overload.supported_stages;
+    builtin.is_deprecated = overload.is_deprecated;
+
+    // De-duplicate builtins that are identical.
+    return utils::GetOrCreate(builtins, builtin, [&] {
+        std::vector<sem::Parameter*> params;
+        params.reserve(builtin.parameters.size());
+        for (auto& p : builtin.parameters) {
+            params.emplace_back(builder.create<sem::Parameter>(
+                nullptr, static_cast<uint32_t>(params.size()), p.type, ast::StorageClass::kNone,
+                ast::Access::kUndefined, p.usage));
         }
-      }
-    }
-  }
-
-  if (overload_matched) {
-    // Check all constrained open numbers matched
-    for (uint32_t on = 0; on < overload.num_open_numbers; on++) {
-      auto& open_number = overload.open_numbers[on];
-      if (open_number.matcher_index != kNoMatcher) {
-        auto* index = &open_number.matcher_index;
-        if (Match(closed, overload, index).Num(closed.Num(on)).IsValid()) {
-          match_score += kScorePerMatchedOpenNumber;
-        } else {
-          overload_matched = false;
-        }
-      }
-    }
-  }
-
-  if (!overload_matched) {
-    return nullptr;
-  }
-
-  // Build the return type
-  const sem::Type* return_type = nullptr;
-  if (auto* indices = overload.return_matcher_indices) {
-    Any any;
-    return_type = Match(closed, overload, indices).Type(&any);
-    if (!return_type) {
-      std::stringstream ss;
-      PrintOverload(ss, overload, builtin_type);
-      TINT_ICE(Resolver, builder.Diagnostics())
-          << "MatchState.Match() returned null for " << ss.str();
-      return nullptr;
-    }
-  } else {
-    return_type = builder.create<sem::Void>();
-  }
-
-  BuiltinPrototype builtin;
-  builtin.type = builtin_type;
-  builtin.return_type = return_type;
-  builtin.parameters = std::move(parameters);
-  builtin.supported_stages = overload.supported_stages;
-  builtin.is_deprecated = overload.is_deprecated;
-
-  // De-duplicate builtins that are identical.
-  return utils::GetOrCreate(builtins, builtin, [&] {
-    std::vector<sem::Parameter*> params;
-    params.reserve(builtin.parameters.size());
-    for (auto& p : builtin.parameters) {
-      params.emplace_back(builder.create<sem::Parameter>(
-          nullptr, static_cast<uint32_t>(params.size()), p.type,
-          ast::StorageClass::kNone, ast::Access::kUndefined, p.usage));
-    }
-    return builder.create<sem::Builtin>(
-        builtin.type, builtin.return_type, std::move(params),
-        builtin.supported_stages, builtin.is_deprecated);
-  });
+        return builder.create<sem::Builtin>(builtin.type, builtin.return_type, std::move(params),
+                                            builtin.supported_stages, builtin.is_deprecated);
+    });
 }
 
 MatchState Impl::Match(ClosedState& closed,
                        const OverloadInfo& overload,
                        MatcherIndex const* matcher_indices) const {
-  return MatchState(builder, closed, matchers, overload, matcher_indices);
+    return MatchState(builder, closed, matchers, overload, matcher_indices);
 }
 
 void Impl::PrintOverload(std::ostream& ss,
                          const OverloadInfo& overload,
                          sem::BuiltinType builtin_type) const {
-  ClosedState closed(builder);
+    ClosedState closed(builder);
 
-  ss << builtin_type << "(";
-  for (uint32_t p = 0; p < overload.num_parameters; p++) {
-    auto& parameter = overload.parameters[p];
-    if (p > 0) {
-      ss << ", ";
+    ss << builtin_type << "(";
+    for (uint32_t p = 0; p < overload.num_parameters; p++) {
+        auto& parameter = overload.parameters[p];
+        if (p > 0) {
+            ss << ", ";
+        }
+        if (parameter.usage != ParameterUsage::kNone) {
+            ss << sem::str(parameter.usage) << ": ";
+        }
+        auto* indices = parameter.matcher_indices;
+        ss << Match(closed, overload, indices).TypeName();
     }
-    if (parameter.usage != ParameterUsage::kNone) {
-      ss << sem::str(parameter.usage) << ": ";
+    ss << ")";
+    if (overload.return_matcher_indices) {
+        ss << " -> ";
+        auto* indices = overload.return_matcher_indices;
+        ss << Match(closed, overload, indices).TypeName();
     }
-    auto* indices = parameter.matcher_indices;
-    ss << Match(closed, overload, indices).TypeName();
-  }
-  ss << ")";
-  if (overload.return_matcher_indices) {
-    ss << " -> ";
-    auto* indices = overload.return_matcher_indices;
-    ss << Match(closed, overload, indices).TypeName();
-  }
 
-  bool first = true;
-  auto separator = [&] {
-    ss << (first ? "  where: " : ", ");
-    first = false;
-  };
-  for (uint32_t i = 0; i < overload.num_open_types; i++) {
-    auto& open_type = overload.open_types[i];
-    if (open_type.matcher_index != kNoMatcher) {
-      separator();
-      ss << open_type.name;
-      auto* index = &open_type.matcher_index;
-      ss << " is " << Match(closed, overload, index).TypeName();
+    bool first = true;
+    auto separator = [&] {
+        ss << (first ? "  where: " : ", ");
+        first = false;
+    };
+    for (uint32_t i = 0; i < overload.num_open_types; i++) {
+        auto& open_type = overload.open_types[i];
+        if (open_type.matcher_index != kNoMatcher) {
+            separator();
+            ss << open_type.name;
+            auto* index = &open_type.matcher_index;
+            ss << " is " << Match(closed, overload, index).TypeName();
+        }
     }
-  }
-  for (uint32_t i = 0; i < overload.num_open_numbers; i++) {
-    auto& open_number = overload.open_numbers[i];
-    if (open_number.matcher_index != kNoMatcher) {
-      separator();
-      ss << open_number.name;
-      auto* index = &open_number.matcher_index;
-      ss << " is " << Match(closed, overload, index).NumName();
+    for (uint32_t i = 0; i < overload.num_open_numbers; i++) {
+        auto& open_number = overload.open_numbers[i];
+        if (open_number.matcher_index != kNoMatcher) {
+            separator();
+            ss << open_number.name;
+            auto* index = &open_number.matcher_index;
+            ss << " is " << Match(closed, overload, index).NumName();
+        }
     }
-  }
 }
 
 const sem::Type* MatchState::Type(const sem::Type* ty) {
-  MatcherIndex matcher_index = *matcher_indices_++;
-  auto* matcher = matchers.type[matcher_index];
-  return matcher->Match(*this, ty);
+    MatcherIndex matcher_index = *matcher_indices_++;
+    auto* matcher = matchers.type[matcher_index];
+    return matcher->Match(*this, ty);
 }
 
 Number MatchState::Num(Number number) {
-  MatcherIndex matcher_index = *matcher_indices_++;
-  auto* matcher = matchers.number[matcher_index];
-  return matcher->Match(*this, number);
+    MatcherIndex matcher_index = *matcher_indices_++;
+    auto* matcher = matchers.number[matcher_index];
+    return matcher->Match(*this, number);
 }
 
 std::string MatchState::TypeName() {
-  MatcherIndex matcher_index = *matcher_indices_++;
-  auto* matcher = matchers.type[matcher_index];
-  return matcher->String(*this);
+    MatcherIndex matcher_index = *matcher_indices_++;
+    auto* matcher = matchers.type[matcher_index];
+    return matcher->String(*this);
 }
 
 std::string MatchState::NumName() {
-  MatcherIndex matcher_index = *matcher_indices_++;
-  auto* matcher = matchers.number[matcher_index];
-  return matcher->String(*this);
+    MatcherIndex matcher_index = *matcher_indices_++;
+    auto* matcher = matchers.number[matcher_index];
+    return matcher->String(*this);
 }
 
 }  // namespace
 
 std::unique_ptr<BuiltinTable> BuiltinTable::Create(ProgramBuilder& builder) {
-  return std::make_unique<Impl>(builder);
+    return std::make_unique<Impl>(builder);
 }
 
 BuiltinTable::~BuiltinTable() = default;
diff --git a/src/tint/builtin_table.h b/src/tint/builtin_table.h
index 4b1b5dc..89f7e90 100644
--- a/src/tint/builtin_table.h
+++ b/src/tint/builtin_table.h
@@ -30,23 +30,23 @@
 
 /// BuiltinTable is a lookup table of all the WGSL builtin functions
 class BuiltinTable {
- public:
-  /// @param builder the program builder
-  /// @return a pointer to a newly created BuiltinTable
-  static std::unique_ptr<BuiltinTable> Create(ProgramBuilder& builder);
+  public:
+    /// @param builder the program builder
+    /// @return a pointer to a newly created BuiltinTable
+    static std::unique_ptr<BuiltinTable> Create(ProgramBuilder& builder);
 
-  /// Destructor
-  virtual ~BuiltinTable();
+    /// Destructor
+    virtual ~BuiltinTable();
 
-  /// Lookup looks for the builtin overload with the given signature, raising
-  /// an error diagnostic if the builtin was not found.
-  /// @param type the builtin type
-  /// @param args the argument types passed to the builtin function
-  /// @param source the source of the builtin call
-  /// @return the semantic builtin if found, otherwise nullptr
-  virtual const sem::Builtin* Lookup(sem::BuiltinType type,
-                                     const std::vector<const sem::Type*>& args,
-                                     const Source& source) = 0;
+    /// Lookup looks for the builtin overload with the given signature, raising
+    /// an error diagnostic if the builtin was not found.
+    /// @param type the builtin type
+    /// @param args the argument types passed to the builtin function
+    /// @param source the source of the builtin call
+    /// @return the semantic builtin if found, otherwise nullptr
+    virtual const sem::Builtin* Lookup(sem::BuiltinType type,
+                                       const std::vector<const sem::Type*>& args,
+                                       const Source& source) = 0;
 };
 
 }  // namespace tint
diff --git a/src/tint/builtin_table_test.cc b/src/tint/builtin_table_test.cc
index b8454d1..48cdc18 100644
--- a/src/tint/builtin_table_test.cc
+++ b/src/tint/builtin_table_test.cc
@@ -16,14 +16,14 @@
 
 #include "gmock/gmock.h"
 #include "src/tint/program_builder.h"
-#include "src/tint/sem/atomic_type.h"
-#include "src/tint/sem/depth_multisampled_texture_type.h"
-#include "src/tint/sem/depth_texture_type.h"
-#include "src/tint/sem/external_texture_type.h"
-#include "src/tint/sem/multisampled_texture_type.h"
-#include "src/tint/sem/reference_type.h"
-#include "src/tint/sem/sampled_texture_type.h"
-#include "src/tint/sem/storage_texture_type.h"
+#include "src/tint/sem/atomic.h"
+#include "src/tint/sem/depth_multisampled_texture.h"
+#include "src/tint/sem/depth_texture.h"
+#include "src/tint/sem/external_texture.h"
+#include "src/tint/sem/multisampled_texture.h"
+#include "src/tint/sem/reference.h"
+#include "src/tint/sem/sampled_texture.h"
+#include "src/tint/sem/storage_texture.h"
 
 namespace tint {
 namespace {
@@ -35,476 +35,457 @@
 using ParameterUsage = sem::ParameterUsage;
 
 class BuiltinTableTest : public testing::Test, public ProgramBuilder {
- public:
-  std::unique_ptr<BuiltinTable> table = BuiltinTable::Create(*this);
+  public:
+    std::unique_ptr<BuiltinTable> table = BuiltinTable::Create(*this);
 };
 
 TEST_F(BuiltinTableTest, MatchF32) {
-  auto* f32 = create<sem::F32>();
-  auto* result = table->Lookup(BuiltinType::kCos, {f32}, Source{});
-  ASSERT_NE(result, nullptr) << Diagnostics().str();
-  ASSERT_EQ(Diagnostics().str(), "");
-  EXPECT_EQ(result->Type(), BuiltinType::kCos);
-  EXPECT_EQ(result->ReturnType(), f32);
-  ASSERT_EQ(result->Parameters().size(), 1u);
-  EXPECT_EQ(result->Parameters()[0]->Type(), f32);
+    auto* f32 = create<sem::F32>();
+    auto* result = table->Lookup(BuiltinType::kCos, {f32}, Source{});
+    ASSERT_NE(result, nullptr) << Diagnostics().str();
+    ASSERT_EQ(Diagnostics().str(), "");
+    EXPECT_EQ(result->Type(), BuiltinType::kCos);
+    EXPECT_EQ(result->ReturnType(), f32);
+    ASSERT_EQ(result->Parameters().size(), 1u);
+    EXPECT_EQ(result->Parameters()[0]->Type(), f32);
 }
 
 TEST_F(BuiltinTableTest, MismatchF32) {
-  auto* i32 = create<sem::I32>();
-  auto* result = table->Lookup(BuiltinType::kCos, {i32}, Source{});
-  ASSERT_EQ(result, nullptr);
-  ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
+    auto* i32 = create<sem::I32>();
+    auto* result = table->Lookup(BuiltinType::kCos, {i32}, Source{});
+    ASSERT_EQ(result, nullptr);
+    ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
 }
 
 TEST_F(BuiltinTableTest, MatchU32) {
-  auto* f32 = create<sem::F32>();
-  auto* u32 = create<sem::U32>();
-  auto* vec2_f32 = create<sem::Vector>(f32, 2u);
-  auto* result = table->Lookup(BuiltinType::kUnpack2x16float, {u32}, Source{});
-  ASSERT_NE(result, nullptr) << Diagnostics().str();
-  ASSERT_EQ(Diagnostics().str(), "");
-  EXPECT_EQ(result->Type(), BuiltinType::kUnpack2x16float);
-  EXPECT_EQ(result->ReturnType(), vec2_f32);
-  ASSERT_EQ(result->Parameters().size(), 1u);
-  EXPECT_EQ(result->Parameters()[0]->Type(), u32);
+    auto* f32 = create<sem::F32>();
+    auto* u32 = create<sem::U32>();
+    auto* vec2_f32 = create<sem::Vector>(f32, 2u);
+    auto* result = table->Lookup(BuiltinType::kUnpack2x16float, {u32}, Source{});
+    ASSERT_NE(result, nullptr) << Diagnostics().str();
+    ASSERT_EQ(Diagnostics().str(), "");
+    EXPECT_EQ(result->Type(), BuiltinType::kUnpack2x16float);
+    EXPECT_EQ(result->ReturnType(), vec2_f32);
+    ASSERT_EQ(result->Parameters().size(), 1u);
+    EXPECT_EQ(result->Parameters()[0]->Type(), u32);
 }
 
 TEST_F(BuiltinTableTest, MismatchU32) {
-  auto* f32 = create<sem::F32>();
-  auto* result = table->Lookup(BuiltinType::kUnpack2x16float, {f32}, Source{});
-  ASSERT_EQ(result, nullptr);
-  ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
+    auto* f32 = create<sem::F32>();
+    auto* result = table->Lookup(BuiltinType::kUnpack2x16float, {f32}, Source{});
+    ASSERT_EQ(result, nullptr);
+    ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
 }
 
 TEST_F(BuiltinTableTest, MatchI32) {
-  auto* f32 = create<sem::F32>();
-  auto* i32 = create<sem::I32>();
-  auto* vec4_f32 = create<sem::Vector>(f32, 4u);
-  auto* tex = create<sem::SampledTexture>(ast::TextureDimension::k1d, f32);
-  auto* result =
-      table->Lookup(BuiltinType::kTextureLoad, {tex, i32, i32}, Source{});
-  ASSERT_NE(result, nullptr) << Diagnostics().str();
-  ASSERT_EQ(Diagnostics().str(), "");
-  EXPECT_EQ(result->Type(), BuiltinType::kTextureLoad);
-  EXPECT_EQ(result->ReturnType(), vec4_f32);
-  ASSERT_EQ(result->Parameters().size(), 3u);
-  EXPECT_EQ(result->Parameters()[0]->Type(), tex);
-  EXPECT_EQ(result->Parameters()[0]->Usage(), ParameterUsage::kTexture);
-  EXPECT_EQ(result->Parameters()[1]->Type(), i32);
-  EXPECT_EQ(result->Parameters()[1]->Usage(), ParameterUsage::kCoords);
-  EXPECT_EQ(result->Parameters()[2]->Type(), i32);
-  EXPECT_EQ(result->Parameters()[2]->Usage(), ParameterUsage::kLevel);
+    auto* f32 = create<sem::F32>();
+    auto* i32 = create<sem::I32>();
+    auto* vec4_f32 = create<sem::Vector>(f32, 4u);
+    auto* tex = create<sem::SampledTexture>(ast::TextureDimension::k1d, f32);
+    auto* result = table->Lookup(BuiltinType::kTextureLoad, {tex, i32, i32}, Source{});
+    ASSERT_NE(result, nullptr) << Diagnostics().str();
+    ASSERT_EQ(Diagnostics().str(), "");
+    EXPECT_EQ(result->Type(), BuiltinType::kTextureLoad);
+    EXPECT_EQ(result->ReturnType(), vec4_f32);
+    ASSERT_EQ(result->Parameters().size(), 3u);
+    EXPECT_EQ(result->Parameters()[0]->Type(), tex);
+    EXPECT_EQ(result->Parameters()[0]->Usage(), ParameterUsage::kTexture);
+    EXPECT_EQ(result->Parameters()[1]->Type(), i32);
+    EXPECT_EQ(result->Parameters()[1]->Usage(), ParameterUsage::kCoords);
+    EXPECT_EQ(result->Parameters()[2]->Type(), i32);
+    EXPECT_EQ(result->Parameters()[2]->Usage(), ParameterUsage::kLevel);
 }
 
 TEST_F(BuiltinTableTest, MismatchI32) {
-  auto* f32 = create<sem::F32>();
-  auto* tex = create<sem::SampledTexture>(ast::TextureDimension::k1d, f32);
-  auto* result = table->Lookup(BuiltinType::kTextureLoad, {tex, f32}, Source{});
-  ASSERT_EQ(result, nullptr);
-  ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
+    auto* f32 = create<sem::F32>();
+    auto* tex = create<sem::SampledTexture>(ast::TextureDimension::k1d, f32);
+    auto* result = table->Lookup(BuiltinType::kTextureLoad, {tex, f32}, Source{});
+    ASSERT_EQ(result, nullptr);
+    ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
 }
 
 TEST_F(BuiltinTableTest, MatchIU32AsI32) {
-  auto* i32 = create<sem::I32>();
-  auto* result = table->Lookup(BuiltinType::kCountOneBits, {i32}, Source{});
-  ASSERT_NE(result, nullptr) << Diagnostics().str();
-  ASSERT_EQ(Diagnostics().str(), "");
-  EXPECT_EQ(result->Type(), BuiltinType::kCountOneBits);
-  EXPECT_EQ(result->ReturnType(), i32);
-  ASSERT_EQ(result->Parameters().size(), 1u);
-  EXPECT_EQ(result->Parameters()[0]->Type(), i32);
+    auto* i32 = create<sem::I32>();
+    auto* result = table->Lookup(BuiltinType::kCountOneBits, {i32}, Source{});
+    ASSERT_NE(result, nullptr) << Diagnostics().str();
+    ASSERT_EQ(Diagnostics().str(), "");
+    EXPECT_EQ(result->Type(), BuiltinType::kCountOneBits);
+    EXPECT_EQ(result->ReturnType(), i32);
+    ASSERT_EQ(result->Parameters().size(), 1u);
+    EXPECT_EQ(result->Parameters()[0]->Type(), i32);
 }
 
 TEST_F(BuiltinTableTest, MatchIU32AsU32) {
-  auto* u32 = create<sem::U32>();
-  auto* result = table->Lookup(BuiltinType::kCountOneBits, {u32}, Source{});
-  ASSERT_NE(result, nullptr) << Diagnostics().str();
-  ASSERT_EQ(Diagnostics().str(), "");
-  EXPECT_EQ(result->Type(), BuiltinType::kCountOneBits);
-  EXPECT_EQ(result->ReturnType(), u32);
-  ASSERT_EQ(result->Parameters().size(), 1u);
-  EXPECT_EQ(result->Parameters()[0]->Type(), u32);
+    auto* u32 = create<sem::U32>();
+    auto* result = table->Lookup(BuiltinType::kCountOneBits, {u32}, Source{});
+    ASSERT_NE(result, nullptr) << Diagnostics().str();
+    ASSERT_EQ(Diagnostics().str(), "");
+    EXPECT_EQ(result->Type(), BuiltinType::kCountOneBits);
+    EXPECT_EQ(result->ReturnType(), u32);
+    ASSERT_EQ(result->Parameters().size(), 1u);
+    EXPECT_EQ(result->Parameters()[0]->Type(), u32);
 }
 
 TEST_F(BuiltinTableTest, MismatchIU32) {
-  auto* f32 = create<sem::F32>();
-  auto* result = table->Lookup(BuiltinType::kCountOneBits, {f32}, Source{});
-  ASSERT_EQ(result, nullptr);
-  ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
+    auto* f32 = create<sem::F32>();
+    auto* result = table->Lookup(BuiltinType::kCountOneBits, {f32}, Source{});
+    ASSERT_EQ(result, nullptr);
+    ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
 }
 
 TEST_F(BuiltinTableTest, MatchFIU32AsI32) {
-  auto* i32 = create<sem::I32>();
-  auto* result = table->Lookup(BuiltinType::kClamp, {i32, i32, i32}, Source{});
-  ASSERT_NE(result, nullptr) << Diagnostics().str();
-  ASSERT_EQ(Diagnostics().str(), "");
-  EXPECT_EQ(result->Type(), BuiltinType::kClamp);
-  EXPECT_EQ(result->ReturnType(), i32);
-  ASSERT_EQ(result->Parameters().size(), 3u);
-  EXPECT_EQ(result->Parameters()[0]->Type(), i32);
-  EXPECT_EQ(result->Parameters()[1]->Type(), i32);
-  EXPECT_EQ(result->Parameters()[2]->Type(), i32);
+    auto* i32 = create<sem::I32>();
+    auto* result = table->Lookup(BuiltinType::kClamp, {i32, i32, i32}, Source{});
+    ASSERT_NE(result, nullptr) << Diagnostics().str();
+    ASSERT_EQ(Diagnostics().str(), "");
+    EXPECT_EQ(result->Type(), BuiltinType::kClamp);
+    EXPECT_EQ(result->ReturnType(), i32);
+    ASSERT_EQ(result->Parameters().size(), 3u);
+    EXPECT_EQ(result->Parameters()[0]->Type(), i32);
+    EXPECT_EQ(result->Parameters()[1]->Type(), i32);
+    EXPECT_EQ(result->Parameters()[2]->Type(), i32);
 }
 
 TEST_F(BuiltinTableTest, MatchFIU32AsU32) {
-  auto* u32 = create<sem::U32>();
-  auto* result = table->Lookup(BuiltinType::kClamp, {u32, u32, u32}, Source{});
-  ASSERT_NE(result, nullptr) << Diagnostics().str();
-  ASSERT_EQ(Diagnostics().str(), "");
-  EXPECT_EQ(result->Type(), BuiltinType::kClamp);
-  EXPECT_EQ(result->ReturnType(), u32);
-  ASSERT_EQ(result->Parameters().size(), 3u);
-  EXPECT_EQ(result->Parameters()[0]->Type(), u32);
-  EXPECT_EQ(result->Parameters()[1]->Type(), u32);
-  EXPECT_EQ(result->Parameters()[2]->Type(), u32);
+    auto* u32 = create<sem::U32>();
+    auto* result = table->Lookup(BuiltinType::kClamp, {u32, u32, u32}, Source{});
+    ASSERT_NE(result, nullptr) << Diagnostics().str();
+    ASSERT_EQ(Diagnostics().str(), "");
+    EXPECT_EQ(result->Type(), BuiltinType::kClamp);
+    EXPECT_EQ(result->ReturnType(), u32);
+    ASSERT_EQ(result->Parameters().size(), 3u);
+    EXPECT_EQ(result->Parameters()[0]->Type(), u32);
+    EXPECT_EQ(result->Parameters()[1]->Type(), u32);
+    EXPECT_EQ(result->Parameters()[2]->Type(), u32);
 }
 
 TEST_F(BuiltinTableTest, MatchFIU32AsF32) {
-  auto* f32 = create<sem::F32>();
-  auto* result = table->Lookup(BuiltinType::kClamp, {f32, f32, f32}, Source{});
-  ASSERT_NE(result, nullptr) << Diagnostics().str();
-  ASSERT_EQ(Diagnostics().str(), "");
-  EXPECT_EQ(result->Type(), BuiltinType::kClamp);
-  EXPECT_EQ(result->ReturnType(), f32);
-  ASSERT_EQ(result->Parameters().size(), 3u);
-  EXPECT_EQ(result->Parameters()[0]->Type(), f32);
-  EXPECT_EQ(result->Parameters()[1]->Type(), f32);
-  EXPECT_EQ(result->Parameters()[2]->Type(), f32);
+    auto* f32 = create<sem::F32>();
+    auto* result = table->Lookup(BuiltinType::kClamp, {f32, f32, f32}, Source{});
+    ASSERT_NE(result, nullptr) << Diagnostics().str();
+    ASSERT_EQ(Diagnostics().str(), "");
+    EXPECT_EQ(result->Type(), BuiltinType::kClamp);
+    EXPECT_EQ(result->ReturnType(), f32);
+    ASSERT_EQ(result->Parameters().size(), 3u);
+    EXPECT_EQ(result->Parameters()[0]->Type(), f32);
+    EXPECT_EQ(result->Parameters()[1]->Type(), f32);
+    EXPECT_EQ(result->Parameters()[2]->Type(), f32);
 }
 
 TEST_F(BuiltinTableTest, MismatchFIU32) {
-  auto* bool_ = create<sem::Bool>();
-  auto* result =
-      table->Lookup(BuiltinType::kClamp, {bool_, bool_, bool_}, Source{});
-  ASSERT_EQ(result, nullptr);
-  ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
+    auto* bool_ = create<sem::Bool>();
+    auto* result = table->Lookup(BuiltinType::kClamp, {bool_, bool_, bool_}, Source{});
+    ASSERT_EQ(result, nullptr);
+    ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
 }
 
 TEST_F(BuiltinTableTest, MatchBool) {
-  auto* f32 = create<sem::F32>();
-  auto* bool_ = create<sem::Bool>();
-  auto* result =
-      table->Lookup(BuiltinType::kSelect, {f32, f32, bool_}, Source{});
-  ASSERT_NE(result, nullptr) << Diagnostics().str();
-  ASSERT_EQ(Diagnostics().str(), "");
-  EXPECT_EQ(result->Type(), BuiltinType::kSelect);
-  EXPECT_EQ(result->ReturnType(), f32);
-  ASSERT_EQ(result->Parameters().size(), 3u);
-  EXPECT_EQ(result->Parameters()[0]->Type(), f32);
-  EXPECT_EQ(result->Parameters()[1]->Type(), f32);
-  EXPECT_EQ(result->Parameters()[2]->Type(), bool_);
+    auto* f32 = create<sem::F32>();
+    auto* bool_ = create<sem::Bool>();
+    auto* result = table->Lookup(BuiltinType::kSelect, {f32, f32, bool_}, Source{});
+    ASSERT_NE(result, nullptr) << Diagnostics().str();
+    ASSERT_EQ(Diagnostics().str(), "");
+    EXPECT_EQ(result->Type(), BuiltinType::kSelect);
+    EXPECT_EQ(result->ReturnType(), f32);
+    ASSERT_EQ(result->Parameters().size(), 3u);
+    EXPECT_EQ(result->Parameters()[0]->Type(), f32);
+    EXPECT_EQ(result->Parameters()[1]->Type(), f32);
+    EXPECT_EQ(result->Parameters()[2]->Type(), bool_);
 }
 
 TEST_F(BuiltinTableTest, MismatchBool) {
-  auto* f32 = create<sem::F32>();
-  auto* result = table->Lookup(BuiltinType::kSelect, {f32, f32, f32}, Source{});
-  ASSERT_EQ(result, nullptr);
-  ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
+    auto* f32 = create<sem::F32>();
+    auto* result = table->Lookup(BuiltinType::kSelect, {f32, f32, f32}, Source{});
+    ASSERT_EQ(result, nullptr);
+    ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
 }
 
 TEST_F(BuiltinTableTest, MatchPointer) {
-  auto* i32 = create<sem::I32>();
-  auto* atomicI32 = create<sem::Atomic>(i32);
-  auto* ptr = create<sem::Pointer>(atomicI32, ast::StorageClass::kWorkgroup,
-                                   ast::Access::kReadWrite);
-  auto* result = table->Lookup(BuiltinType::kAtomicLoad, {ptr}, Source{});
-  ASSERT_NE(result, nullptr) << Diagnostics().str();
-  ASSERT_EQ(Diagnostics().str(), "");
-  EXPECT_EQ(result->Type(), BuiltinType::kAtomicLoad);
-  EXPECT_EQ(result->ReturnType(), i32);
-  ASSERT_EQ(result->Parameters().size(), 1u);
-  EXPECT_EQ(result->Parameters()[0]->Type(), ptr);
+    auto* i32 = create<sem::I32>();
+    auto* atomicI32 = create<sem::Atomic>(i32);
+    auto* ptr =
+        create<sem::Pointer>(atomicI32, ast::StorageClass::kWorkgroup, ast::Access::kReadWrite);
+    auto* result = table->Lookup(BuiltinType::kAtomicLoad, {ptr}, Source{});
+    ASSERT_NE(result, nullptr) << Diagnostics().str();
+    ASSERT_EQ(Diagnostics().str(), "");
+    EXPECT_EQ(result->Type(), BuiltinType::kAtomicLoad);
+    EXPECT_EQ(result->ReturnType(), i32);
+    ASSERT_EQ(result->Parameters().size(), 1u);
+    EXPECT_EQ(result->Parameters()[0]->Type(), ptr);
 }
 
 TEST_F(BuiltinTableTest, MismatchPointer) {
-  auto* i32 = create<sem::I32>();
-  auto* atomicI32 = create<sem::Atomic>(i32);
-  auto* result = table->Lookup(BuiltinType::kAtomicLoad, {atomicI32}, Source{});
-  ASSERT_EQ(result, nullptr);
-  ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
+    auto* i32 = create<sem::I32>();
+    auto* atomicI32 = create<sem::Atomic>(i32);
+    auto* result = table->Lookup(BuiltinType::kAtomicLoad, {atomicI32}, Source{});
+    ASSERT_EQ(result, nullptr);
+    ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
 }
 
 TEST_F(BuiltinTableTest, MatchArray) {
-  auto* arr = create<sem::Array>(create<sem::U32>(), 0u, 4u, 4u, 4u, 4u);
-  auto* arr_ptr = create<sem::Pointer>(arr, ast::StorageClass::kStorage,
-                                       ast::Access::kReadWrite);
-  auto* result = table->Lookup(BuiltinType::kArrayLength, {arr_ptr}, Source{});
-  ASSERT_NE(result, nullptr) << Diagnostics().str();
-  ASSERT_EQ(Diagnostics().str(), "");
-  EXPECT_EQ(result->Type(), BuiltinType::kArrayLength);
-  EXPECT_TRUE(result->ReturnType()->Is<sem::U32>());
-  ASSERT_EQ(result->Parameters().size(), 1u);
-  auto* param_type = result->Parameters()[0]->Type();
-  ASSERT_TRUE(param_type->Is<sem::Pointer>());
-  EXPECT_TRUE(param_type->As<sem::Pointer>()->StoreType()->Is<sem::Array>());
+    auto* arr = create<sem::Array>(create<sem::U32>(), 0u, 4u, 4u, 4u, 4u);
+    auto* arr_ptr = create<sem::Pointer>(arr, ast::StorageClass::kStorage, ast::Access::kReadWrite);
+    auto* result = table->Lookup(BuiltinType::kArrayLength, {arr_ptr}, Source{});
+    ASSERT_NE(result, nullptr) << Diagnostics().str();
+    ASSERT_EQ(Diagnostics().str(), "");
+    EXPECT_EQ(result->Type(), BuiltinType::kArrayLength);
+    EXPECT_TRUE(result->ReturnType()->Is<sem::U32>());
+    ASSERT_EQ(result->Parameters().size(), 1u);
+    auto* param_type = result->Parameters()[0]->Type();
+    ASSERT_TRUE(param_type->Is<sem::Pointer>());
+    EXPECT_TRUE(param_type->As<sem::Pointer>()->StoreType()->Is<sem::Array>());
 }
 
 TEST_F(BuiltinTableTest, MismatchArray) {
-  auto* f32 = create<sem::F32>();
-  auto* result = table->Lookup(BuiltinType::kArrayLength, {f32}, Source{});
-  ASSERT_EQ(result, nullptr);
-  ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
+    auto* f32 = create<sem::F32>();
+    auto* result = table->Lookup(BuiltinType::kArrayLength, {f32}, Source{});
+    ASSERT_EQ(result, nullptr);
+    ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
 }
 
 TEST_F(BuiltinTableTest, MatchSampler) {
-  auto* f32 = create<sem::F32>();
-  auto* vec2_f32 = create<sem::Vector>(f32, 2u);
-  auto* vec4_f32 = create<sem::Vector>(f32, 4u);
-  auto* tex = create<sem::SampledTexture>(ast::TextureDimension::k2d, f32);
-  auto* sampler = create<sem::Sampler>(ast::SamplerKind::kSampler);
-  auto* result = table->Lookup(BuiltinType::kTextureSample,
-                               {tex, sampler, vec2_f32}, Source{});
-  ASSERT_NE(result, nullptr) << Diagnostics().str();
-  ASSERT_EQ(Diagnostics().str(), "");
-  EXPECT_EQ(result->Type(), BuiltinType::kTextureSample);
-  EXPECT_EQ(result->ReturnType(), vec4_f32);
-  ASSERT_EQ(result->Parameters().size(), 3u);
-  EXPECT_EQ(result->Parameters()[0]->Type(), tex);
-  EXPECT_EQ(result->Parameters()[0]->Usage(), ParameterUsage::kTexture);
-  EXPECT_EQ(result->Parameters()[1]->Type(), sampler);
-  EXPECT_EQ(result->Parameters()[1]->Usage(), ParameterUsage::kSampler);
-  EXPECT_EQ(result->Parameters()[2]->Type(), vec2_f32);
-  EXPECT_EQ(result->Parameters()[2]->Usage(), ParameterUsage::kCoords);
+    auto* f32 = create<sem::F32>();
+    auto* vec2_f32 = create<sem::Vector>(f32, 2u);
+    auto* vec4_f32 = create<sem::Vector>(f32, 4u);
+    auto* tex = create<sem::SampledTexture>(ast::TextureDimension::k2d, f32);
+    auto* sampler = create<sem::Sampler>(ast::SamplerKind::kSampler);
+    auto* result = table->Lookup(BuiltinType::kTextureSample, {tex, sampler, vec2_f32}, Source{});
+    ASSERT_NE(result, nullptr) << Diagnostics().str();
+    ASSERT_EQ(Diagnostics().str(), "");
+    EXPECT_EQ(result->Type(), BuiltinType::kTextureSample);
+    EXPECT_EQ(result->ReturnType(), vec4_f32);
+    ASSERT_EQ(result->Parameters().size(), 3u);
+    EXPECT_EQ(result->Parameters()[0]->Type(), tex);
+    EXPECT_EQ(result->Parameters()[0]->Usage(), ParameterUsage::kTexture);
+    EXPECT_EQ(result->Parameters()[1]->Type(), sampler);
+    EXPECT_EQ(result->Parameters()[1]->Usage(), ParameterUsage::kSampler);
+    EXPECT_EQ(result->Parameters()[2]->Type(), vec2_f32);
+    EXPECT_EQ(result->Parameters()[2]->Usage(), ParameterUsage::kCoords);
 }
 
 TEST_F(BuiltinTableTest, MismatchSampler) {
-  auto* f32 = create<sem::F32>();
-  auto* vec2_f32 = create<sem::Vector>(f32, 2u);
-  auto* tex = create<sem::SampledTexture>(ast::TextureDimension::k2d, f32);
-  auto* result = table->Lookup(BuiltinType::kTextureSample,
-                               {tex, f32, vec2_f32}, Source{});
-  ASSERT_EQ(result, nullptr);
-  ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
+    auto* f32 = create<sem::F32>();
+    auto* vec2_f32 = create<sem::Vector>(f32, 2u);
+    auto* tex = create<sem::SampledTexture>(ast::TextureDimension::k2d, f32);
+    auto* result = table->Lookup(BuiltinType::kTextureSample, {tex, f32, vec2_f32}, Source{});
+    ASSERT_EQ(result, nullptr);
+    ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
 }
 
 TEST_F(BuiltinTableTest, MatchSampledTexture) {
-  auto* i32 = create<sem::I32>();
-  auto* f32 = create<sem::F32>();
-  auto* vec2_i32 = create<sem::Vector>(i32, 2u);
-  auto* vec4_f32 = create<sem::Vector>(f32, 4u);
-  auto* tex = create<sem::SampledTexture>(ast::TextureDimension::k2d, f32);
-  auto* result =
-      table->Lookup(BuiltinType::kTextureLoad, {tex, vec2_i32, i32}, Source{});
-  ASSERT_NE(result, nullptr) << Diagnostics().str();
-  ASSERT_EQ(Diagnostics().str(), "");
-  EXPECT_EQ(result->Type(), BuiltinType::kTextureLoad);
-  EXPECT_EQ(result->ReturnType(), vec4_f32);
-  ASSERT_EQ(result->Parameters().size(), 3u);
-  EXPECT_EQ(result->Parameters()[0]->Type(), tex);
-  EXPECT_EQ(result->Parameters()[0]->Usage(), ParameterUsage::kTexture);
-  EXPECT_EQ(result->Parameters()[1]->Type(), vec2_i32);
-  EXPECT_EQ(result->Parameters()[1]->Usage(), ParameterUsage::kCoords);
-  EXPECT_EQ(result->Parameters()[2]->Type(), i32);
-  EXPECT_EQ(result->Parameters()[2]->Usage(), ParameterUsage::kLevel);
+    auto* i32 = create<sem::I32>();
+    auto* f32 = create<sem::F32>();
+    auto* vec2_i32 = create<sem::Vector>(i32, 2u);
+    auto* vec4_f32 = create<sem::Vector>(f32, 4u);
+    auto* tex = create<sem::SampledTexture>(ast::TextureDimension::k2d, f32);
+    auto* result = table->Lookup(BuiltinType::kTextureLoad, {tex, vec2_i32, i32}, Source{});
+    ASSERT_NE(result, nullptr) << Diagnostics().str();
+    ASSERT_EQ(Diagnostics().str(), "");
+    EXPECT_EQ(result->Type(), BuiltinType::kTextureLoad);
+    EXPECT_EQ(result->ReturnType(), vec4_f32);
+    ASSERT_EQ(result->Parameters().size(), 3u);
+    EXPECT_EQ(result->Parameters()[0]->Type(), tex);
+    EXPECT_EQ(result->Parameters()[0]->Usage(), ParameterUsage::kTexture);
+    EXPECT_EQ(result->Parameters()[1]->Type(), vec2_i32);
+    EXPECT_EQ(result->Parameters()[1]->Usage(), ParameterUsage::kCoords);
+    EXPECT_EQ(result->Parameters()[2]->Type(), i32);
+    EXPECT_EQ(result->Parameters()[2]->Usage(), ParameterUsage::kLevel);
 }
 
 TEST_F(BuiltinTableTest, MatchMultisampledTexture) {
-  auto* i32 = create<sem::I32>();
-  auto* f32 = create<sem::F32>();
-  auto* vec2_i32 = create<sem::Vector>(i32, 2u);
-  auto* vec4_f32 = create<sem::Vector>(f32, 4u);
-  auto* tex = create<sem::MultisampledTexture>(ast::TextureDimension::k2d, f32);
-  auto* result =
-      table->Lookup(BuiltinType::kTextureLoad, {tex, vec2_i32, i32}, Source{});
-  ASSERT_NE(result, nullptr) << Diagnostics().str();
-  ASSERT_EQ(Diagnostics().str(), "");
-  EXPECT_EQ(result->Type(), BuiltinType::kTextureLoad);
-  EXPECT_EQ(result->ReturnType(), vec4_f32);
-  ASSERT_EQ(result->Parameters().size(), 3u);
-  EXPECT_EQ(result->Parameters()[0]->Type(), tex);
-  EXPECT_EQ(result->Parameters()[0]->Usage(), ParameterUsage::kTexture);
-  EXPECT_EQ(result->Parameters()[1]->Type(), vec2_i32);
-  EXPECT_EQ(result->Parameters()[1]->Usage(), ParameterUsage::kCoords);
-  EXPECT_EQ(result->Parameters()[2]->Type(), i32);
-  EXPECT_EQ(result->Parameters()[2]->Usage(), ParameterUsage::kSampleIndex);
+    auto* i32 = create<sem::I32>();
+    auto* f32 = create<sem::F32>();
+    auto* vec2_i32 = create<sem::Vector>(i32, 2u);
+    auto* vec4_f32 = create<sem::Vector>(f32, 4u);
+    auto* tex = create<sem::MultisampledTexture>(ast::TextureDimension::k2d, f32);
+    auto* result = table->Lookup(BuiltinType::kTextureLoad, {tex, vec2_i32, i32}, Source{});
+    ASSERT_NE(result, nullptr) << Diagnostics().str();
+    ASSERT_EQ(Diagnostics().str(), "");
+    EXPECT_EQ(result->Type(), BuiltinType::kTextureLoad);
+    EXPECT_EQ(result->ReturnType(), vec4_f32);
+    ASSERT_EQ(result->Parameters().size(), 3u);
+    EXPECT_EQ(result->Parameters()[0]->Type(), tex);
+    EXPECT_EQ(result->Parameters()[0]->Usage(), ParameterUsage::kTexture);
+    EXPECT_EQ(result->Parameters()[1]->Type(), vec2_i32);
+    EXPECT_EQ(result->Parameters()[1]->Usage(), ParameterUsage::kCoords);
+    EXPECT_EQ(result->Parameters()[2]->Type(), i32);
+    EXPECT_EQ(result->Parameters()[2]->Usage(), ParameterUsage::kSampleIndex);
 }
 
 TEST_F(BuiltinTableTest, MatchDepthTexture) {
-  auto* f32 = create<sem::F32>();
-  auto* i32 = create<sem::I32>();
-  auto* vec2_i32 = create<sem::Vector>(i32, 2u);
-  auto* tex = create<sem::DepthTexture>(ast::TextureDimension::k2d);
-  auto* result =
-      table->Lookup(BuiltinType::kTextureLoad, {tex, vec2_i32, i32}, Source{});
-  ASSERT_NE(result, nullptr) << Diagnostics().str();
-  ASSERT_EQ(Diagnostics().str(), "");
-  EXPECT_EQ(result->Type(), BuiltinType::kTextureLoad);
-  EXPECT_EQ(result->ReturnType(), f32);
-  ASSERT_EQ(result->Parameters().size(), 3u);
-  EXPECT_EQ(result->Parameters()[0]->Type(), tex);
-  EXPECT_EQ(result->Parameters()[0]->Usage(), ParameterUsage::kTexture);
-  EXPECT_EQ(result->Parameters()[1]->Type(), vec2_i32);
-  EXPECT_EQ(result->Parameters()[1]->Usage(), ParameterUsage::kCoords);
-  EXPECT_EQ(result->Parameters()[2]->Type(), i32);
-  EXPECT_EQ(result->Parameters()[2]->Usage(), ParameterUsage::kLevel);
+    auto* f32 = create<sem::F32>();
+    auto* i32 = create<sem::I32>();
+    auto* vec2_i32 = create<sem::Vector>(i32, 2u);
+    auto* tex = create<sem::DepthTexture>(ast::TextureDimension::k2d);
+    auto* result = table->Lookup(BuiltinType::kTextureLoad, {tex, vec2_i32, i32}, Source{});
+    ASSERT_NE(result, nullptr) << Diagnostics().str();
+    ASSERT_EQ(Diagnostics().str(), "");
+    EXPECT_EQ(result->Type(), BuiltinType::kTextureLoad);
+    EXPECT_EQ(result->ReturnType(), f32);
+    ASSERT_EQ(result->Parameters().size(), 3u);
+    EXPECT_EQ(result->Parameters()[0]->Type(), tex);
+    EXPECT_EQ(result->Parameters()[0]->Usage(), ParameterUsage::kTexture);
+    EXPECT_EQ(result->Parameters()[1]->Type(), vec2_i32);
+    EXPECT_EQ(result->Parameters()[1]->Usage(), ParameterUsage::kCoords);
+    EXPECT_EQ(result->Parameters()[2]->Type(), i32);
+    EXPECT_EQ(result->Parameters()[2]->Usage(), ParameterUsage::kLevel);
 }
 
 TEST_F(BuiltinTableTest, MatchDepthMultisampledTexture) {
-  auto* f32 = create<sem::F32>();
-  auto* i32 = create<sem::I32>();
-  auto* vec2_i32 = create<sem::Vector>(i32, 2u);
-  auto* tex = create<sem::DepthMultisampledTexture>(ast::TextureDimension::k2d);
-  auto* result =
-      table->Lookup(BuiltinType::kTextureLoad, {tex, vec2_i32, i32}, Source{});
-  ASSERT_NE(result, nullptr) << Diagnostics().str();
-  ASSERT_EQ(Diagnostics().str(), "");
-  EXPECT_EQ(result->Type(), BuiltinType::kTextureLoad);
-  EXPECT_EQ(result->ReturnType(), f32);
-  ASSERT_EQ(result->Parameters().size(), 3u);
-  EXPECT_EQ(result->Parameters()[0]->Type(), tex);
-  EXPECT_EQ(result->Parameters()[0]->Usage(), ParameterUsage::kTexture);
-  EXPECT_EQ(result->Parameters()[1]->Type(), vec2_i32);
-  EXPECT_EQ(result->Parameters()[1]->Usage(), ParameterUsage::kCoords);
-  EXPECT_EQ(result->Parameters()[2]->Type(), i32);
-  EXPECT_EQ(result->Parameters()[2]->Usage(), ParameterUsage::kSampleIndex);
+    auto* f32 = create<sem::F32>();
+    auto* i32 = create<sem::I32>();
+    auto* vec2_i32 = create<sem::Vector>(i32, 2u);
+    auto* tex = create<sem::DepthMultisampledTexture>(ast::TextureDimension::k2d);
+    auto* result = table->Lookup(BuiltinType::kTextureLoad, {tex, vec2_i32, i32}, Source{});
+    ASSERT_NE(result, nullptr) << Diagnostics().str();
+    ASSERT_EQ(Diagnostics().str(), "");
+    EXPECT_EQ(result->Type(), BuiltinType::kTextureLoad);
+    EXPECT_EQ(result->ReturnType(), f32);
+    ASSERT_EQ(result->Parameters().size(), 3u);
+    EXPECT_EQ(result->Parameters()[0]->Type(), tex);
+    EXPECT_EQ(result->Parameters()[0]->Usage(), ParameterUsage::kTexture);
+    EXPECT_EQ(result->Parameters()[1]->Type(), vec2_i32);
+    EXPECT_EQ(result->Parameters()[1]->Usage(), ParameterUsage::kCoords);
+    EXPECT_EQ(result->Parameters()[2]->Type(), i32);
+    EXPECT_EQ(result->Parameters()[2]->Usage(), ParameterUsage::kSampleIndex);
 }
 
 TEST_F(BuiltinTableTest, MatchExternalTexture) {
-  auto* f32 = create<sem::F32>();
-  auto* i32 = create<sem::I32>();
-  auto* vec2_i32 = create<sem::Vector>(i32, 2u);
-  auto* vec4_f32 = create<sem::Vector>(f32, 4u);
-  auto* tex = create<sem::ExternalTexture>();
-  auto* result =
-      table->Lookup(BuiltinType::kTextureLoad, {tex, vec2_i32}, Source{});
-  ASSERT_NE(result, nullptr) << Diagnostics().str();
-  ASSERT_EQ(Diagnostics().str(), "");
-  EXPECT_EQ(result->Type(), BuiltinType::kTextureLoad);
-  EXPECT_EQ(result->ReturnType(), vec4_f32);
-  ASSERT_EQ(result->Parameters().size(), 2u);
-  EXPECT_EQ(result->Parameters()[0]->Type(), tex);
-  EXPECT_EQ(result->Parameters()[0]->Usage(), ParameterUsage::kTexture);
-  EXPECT_EQ(result->Parameters()[1]->Type(), vec2_i32);
-  EXPECT_EQ(result->Parameters()[1]->Usage(), ParameterUsage::kCoords);
+    auto* f32 = create<sem::F32>();
+    auto* i32 = create<sem::I32>();
+    auto* vec2_i32 = create<sem::Vector>(i32, 2u);
+    auto* vec4_f32 = create<sem::Vector>(f32, 4u);
+    auto* tex = create<sem::ExternalTexture>();
+    auto* result = table->Lookup(BuiltinType::kTextureLoad, {tex, vec2_i32}, Source{});
+    ASSERT_NE(result, nullptr) << Diagnostics().str();
+    ASSERT_EQ(Diagnostics().str(), "");
+    EXPECT_EQ(result->Type(), BuiltinType::kTextureLoad);
+    EXPECT_EQ(result->ReturnType(), vec4_f32);
+    ASSERT_EQ(result->Parameters().size(), 2u);
+    EXPECT_EQ(result->Parameters()[0]->Type(), tex);
+    EXPECT_EQ(result->Parameters()[0]->Usage(), ParameterUsage::kTexture);
+    EXPECT_EQ(result->Parameters()[1]->Type(), vec2_i32);
+    EXPECT_EQ(result->Parameters()[1]->Usage(), ParameterUsage::kCoords);
 }
 
 TEST_F(BuiltinTableTest, MatchWOStorageTexture) {
-  auto* f32 = create<sem::F32>();
-  auto* i32 = create<sem::I32>();
-  auto* vec2_i32 = create<sem::Vector>(i32, 2u);
-  auto* vec4_f32 = create<sem::Vector>(f32, 4u);
-  auto* subtype =
-      sem::StorageTexture::SubtypeFor(ast::TexelFormat::kR32Float, Types());
-  auto* tex = create<sem::StorageTexture>(ast::TextureDimension::k2d,
-                                          ast::TexelFormat::kR32Float,
-                                          ast::Access::kWrite, subtype);
+    auto* f32 = create<sem::F32>();
+    auto* i32 = create<sem::I32>();
+    auto* vec2_i32 = create<sem::Vector>(i32, 2u);
+    auto* vec4_f32 = create<sem::Vector>(f32, 4u);
+    auto* subtype = sem::StorageTexture::SubtypeFor(ast::TexelFormat::kR32Float, Types());
+    auto* tex = create<sem::StorageTexture>(ast::TextureDimension::k2d, ast::TexelFormat::kR32Float,
+                                            ast::Access::kWrite, subtype);
 
-  auto* result = table->Lookup(BuiltinType::kTextureStore,
-                               {tex, vec2_i32, vec4_f32}, Source{});
-  ASSERT_NE(result, nullptr) << Diagnostics().str();
-  ASSERT_EQ(Diagnostics().str(), "");
-  EXPECT_EQ(result->Type(), BuiltinType::kTextureStore);
-  EXPECT_TRUE(result->ReturnType()->Is<sem::Void>());
-  ASSERT_EQ(result->Parameters().size(), 3u);
-  EXPECT_EQ(result->Parameters()[0]->Type(), tex);
-  EXPECT_EQ(result->Parameters()[0]->Usage(), ParameterUsage::kTexture);
-  EXPECT_EQ(result->Parameters()[1]->Type(), vec2_i32);
-  EXPECT_EQ(result->Parameters()[1]->Usage(), ParameterUsage::kCoords);
-  EXPECT_EQ(result->Parameters()[2]->Type(), vec4_f32);
-  EXPECT_EQ(result->Parameters()[2]->Usage(), ParameterUsage::kValue);
+    auto* result = table->Lookup(BuiltinType::kTextureStore, {tex, vec2_i32, vec4_f32}, Source{});
+    ASSERT_NE(result, nullptr) << Diagnostics().str();
+    ASSERT_EQ(Diagnostics().str(), "");
+    EXPECT_EQ(result->Type(), BuiltinType::kTextureStore);
+    EXPECT_TRUE(result->ReturnType()->Is<sem::Void>());
+    ASSERT_EQ(result->Parameters().size(), 3u);
+    EXPECT_EQ(result->Parameters()[0]->Type(), tex);
+    EXPECT_EQ(result->Parameters()[0]->Usage(), ParameterUsage::kTexture);
+    EXPECT_EQ(result->Parameters()[1]->Type(), vec2_i32);
+    EXPECT_EQ(result->Parameters()[1]->Usage(), ParameterUsage::kCoords);
+    EXPECT_EQ(result->Parameters()[2]->Type(), vec4_f32);
+    EXPECT_EQ(result->Parameters()[2]->Usage(), ParameterUsage::kValue);
 }
 
 TEST_F(BuiltinTableTest, MismatchTexture) {
-  auto* f32 = create<sem::F32>();
-  auto* i32 = create<sem::I32>();
-  auto* vec2_i32 = create<sem::Vector>(i32, 2u);
-  auto* result =
-      table->Lookup(BuiltinType::kTextureLoad, {f32, vec2_i32}, Source{});
-  ASSERT_EQ(result, nullptr);
-  ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
+    auto* f32 = create<sem::F32>();
+    auto* i32 = create<sem::I32>();
+    auto* vec2_i32 = create<sem::Vector>(i32, 2u);
+    auto* result = table->Lookup(BuiltinType::kTextureLoad, {f32, vec2_i32}, Source{});
+    ASSERT_EQ(result, nullptr);
+    ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
 }
 
 TEST_F(BuiltinTableTest, ImplicitLoadOnReference) {
-  auto* f32 = create<sem::F32>();
-  auto* result =
-      table->Lookup(BuiltinType::kCos,
-                    {create<sem::Reference>(f32, ast::StorageClass::kFunction,
-                                            ast::Access::kReadWrite)},
-                    Source{});
-  ASSERT_NE(result, nullptr) << Diagnostics().str();
-  ASSERT_EQ(Diagnostics().str(), "");
-  EXPECT_EQ(result->Type(), BuiltinType::kCos);
-  EXPECT_EQ(result->ReturnType(), f32);
-  ASSERT_EQ(result->Parameters().size(), 1u);
-  EXPECT_EQ(result->Parameters()[0]->Type(), f32);
+    auto* f32 = create<sem::F32>();
+    auto* result = table->Lookup(
+        BuiltinType::kCos,
+        {create<sem::Reference>(f32, ast::StorageClass::kFunction, ast::Access::kReadWrite)},
+        Source{});
+    ASSERT_NE(result, nullptr) << Diagnostics().str();
+    ASSERT_EQ(Diagnostics().str(), "");
+    EXPECT_EQ(result->Type(), BuiltinType::kCos);
+    EXPECT_EQ(result->ReturnType(), f32);
+    ASSERT_EQ(result->Parameters().size(), 1u);
+    EXPECT_EQ(result->Parameters()[0]->Type(), f32);
 }
 
 TEST_F(BuiltinTableTest, MatchOpenType) {
-  auto* f32 = create<sem::F32>();
-  auto* result = table->Lookup(BuiltinType::kClamp, {f32, f32, f32}, Source{});
-  ASSERT_NE(result, nullptr) << Diagnostics().str();
-  ASSERT_EQ(Diagnostics().str(), "");
-  EXPECT_EQ(result->Type(), BuiltinType::kClamp);
-  EXPECT_EQ(result->ReturnType(), f32);
-  EXPECT_EQ(result->Parameters()[0]->Type(), f32);
-  EXPECT_EQ(result->Parameters()[1]->Type(), f32);
-  EXPECT_EQ(result->Parameters()[2]->Type(), f32);
+    auto* f32 = create<sem::F32>();
+    auto* result = table->Lookup(BuiltinType::kClamp, {f32, f32, f32}, Source{});
+    ASSERT_NE(result, nullptr) << Diagnostics().str();
+    ASSERT_EQ(Diagnostics().str(), "");
+    EXPECT_EQ(result->Type(), BuiltinType::kClamp);
+    EXPECT_EQ(result->ReturnType(), f32);
+    EXPECT_EQ(result->Parameters()[0]->Type(), f32);
+    EXPECT_EQ(result->Parameters()[1]->Type(), f32);
+    EXPECT_EQ(result->Parameters()[2]->Type(), f32);
 }
 
 TEST_F(BuiltinTableTest, MismatchOpenType) {
-  auto* f32 = create<sem::F32>();
-  auto* u32 = create<sem::U32>();
-  auto* result = table->Lookup(BuiltinType::kClamp, {f32, u32, f32}, Source{});
-  ASSERT_EQ(result, nullptr);
-  ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
+    auto* f32 = create<sem::F32>();
+    auto* u32 = create<sem::U32>();
+    auto* result = table->Lookup(BuiltinType::kClamp, {f32, u32, f32}, Source{});
+    ASSERT_EQ(result, nullptr);
+    ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
 }
 
 TEST_F(BuiltinTableTest, MatchOpenSizeVector) {
-  auto* f32 = create<sem::F32>();
-  auto* vec2_f32 = create<sem::Vector>(f32, 2u);
-  auto* result = table->Lookup(BuiltinType::kClamp,
-                               {vec2_f32, vec2_f32, vec2_f32}, Source{});
-  ASSERT_NE(result, nullptr) << Diagnostics().str();
-  ASSERT_EQ(Diagnostics().str(), "");
-  EXPECT_EQ(result->Type(), BuiltinType::kClamp);
-  EXPECT_EQ(result->ReturnType(), vec2_f32);
-  ASSERT_EQ(result->Parameters().size(), 3u);
-  EXPECT_EQ(result->Parameters()[0]->Type(), vec2_f32);
-  EXPECT_EQ(result->Parameters()[1]->Type(), vec2_f32);
-  EXPECT_EQ(result->Parameters()[2]->Type(), vec2_f32);
+    auto* f32 = create<sem::F32>();
+    auto* vec2_f32 = create<sem::Vector>(f32, 2u);
+    auto* result = table->Lookup(BuiltinType::kClamp, {vec2_f32, vec2_f32, vec2_f32}, Source{});
+    ASSERT_NE(result, nullptr) << Diagnostics().str();
+    ASSERT_EQ(Diagnostics().str(), "");
+    EXPECT_EQ(result->Type(), BuiltinType::kClamp);
+    EXPECT_EQ(result->ReturnType(), vec2_f32);
+    ASSERT_EQ(result->Parameters().size(), 3u);
+    EXPECT_EQ(result->Parameters()[0]->Type(), vec2_f32);
+    EXPECT_EQ(result->Parameters()[1]->Type(), vec2_f32);
+    EXPECT_EQ(result->Parameters()[2]->Type(), vec2_f32);
 }
 
 TEST_F(BuiltinTableTest, MismatchOpenSizeVector) {
-  auto* f32 = create<sem::F32>();
-  auto* u32 = create<sem::U32>();
-  auto* vec2_f32 = create<sem::Vector>(f32, 2u);
-  auto* result =
-      table->Lookup(BuiltinType::kClamp, {vec2_f32, u32, vec2_f32}, Source{});
-  ASSERT_EQ(result, nullptr);
-  ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
+    auto* f32 = create<sem::F32>();
+    auto* u32 = create<sem::U32>();
+    auto* vec2_f32 = create<sem::Vector>(f32, 2u);
+    auto* result = table->Lookup(BuiltinType::kClamp, {vec2_f32, u32, vec2_f32}, Source{});
+    ASSERT_EQ(result, nullptr);
+    ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
 }
 
 TEST_F(BuiltinTableTest, MatchOpenSizeMatrix) {
-  auto* f32 = create<sem::F32>();
-  auto* vec3_f32 = create<sem::Vector>(f32, 3u);
-  auto* mat3_f32 = create<sem::Matrix>(vec3_f32, 3u);
-  auto* result = table->Lookup(BuiltinType::kDeterminant, {mat3_f32}, Source{});
-  ASSERT_NE(result, nullptr) << Diagnostics().str();
-  ASSERT_EQ(Diagnostics().str(), "");
-  EXPECT_EQ(result->Type(), BuiltinType::kDeterminant);
-  EXPECT_EQ(result->ReturnType(), f32);
-  ASSERT_EQ(result->Parameters().size(), 1u);
-  EXPECT_EQ(result->Parameters()[0]->Type(), mat3_f32);
+    auto* f32 = create<sem::F32>();
+    auto* vec3_f32 = create<sem::Vector>(f32, 3u);
+    auto* mat3_f32 = create<sem::Matrix>(vec3_f32, 3u);
+    auto* result = table->Lookup(BuiltinType::kDeterminant, {mat3_f32}, Source{});
+    ASSERT_NE(result, nullptr) << Diagnostics().str();
+    ASSERT_EQ(Diagnostics().str(), "");
+    EXPECT_EQ(result->Type(), BuiltinType::kDeterminant);
+    EXPECT_EQ(result->ReturnType(), f32);
+    ASSERT_EQ(result->Parameters().size(), 1u);
+    EXPECT_EQ(result->Parameters()[0]->Type(), mat3_f32);
 }
 
 TEST_F(BuiltinTableTest, MismatchOpenSizeMatrix) {
-  auto* f32 = create<sem::F32>();
-  auto* vec2_f32 = create<sem::Vector>(f32, 2u);
-  auto* mat3x2_f32 = create<sem::Matrix>(vec2_f32, 3u);
-  auto* result =
-      table->Lookup(BuiltinType::kDeterminant, {mat3x2_f32}, Source{});
-  ASSERT_EQ(result, nullptr);
-  ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
+    auto* f32 = create<sem::F32>();
+    auto* vec2_f32 = create<sem::Vector>(f32, 2u);
+    auto* mat3x2_f32 = create<sem::Matrix>(vec2_f32, 3u);
+    auto* result = table->Lookup(BuiltinType::kDeterminant, {mat3x2_f32}, Source{});
+    ASSERT_EQ(result, nullptr);
+    ASSERT_THAT(Diagnostics().str(), HasSubstr("no matching call"));
 }
 
 TEST_F(BuiltinTableTest, OverloadOrderByNumberOfParameters) {
-  // None of the arguments match, so expect the overloads with 2 parameters to
-  // come first
-  auto* bool_ = create<sem::Bool>();
-  table->Lookup(BuiltinType::kTextureDimensions, {bool_, bool_}, Source{});
-  ASSERT_EQ(Diagnostics().str(),
-            R"(error: no matching call to textureDimensions(bool, bool)
+    // None of the arguments match, so expect the overloads with 2 parameters to
+    // come first
+    auto* bool_ = create<sem::Bool>();
+    table->Lookup(BuiltinType::kTextureDimensions, {bool_, bool_}, Source{});
+    ASSERT_EQ(Diagnostics().str(),
+              R"(error: no matching call to textureDimensions(bool, bool)
 
 27 candidate functions:
   textureDimensions(texture: texture_1d<T>, level: i32) -> i32  where: T is f32, i32 or u32
@@ -538,12 +519,11 @@
 }
 
 TEST_F(BuiltinTableTest, OverloadOrderByMatchingParameter) {
-  auto* tex = create<sem::DepthTexture>(ast::TextureDimension::k2d);
-  auto* bool_ = create<sem::Bool>();
-  table->Lookup(BuiltinType::kTextureDimensions, {tex, bool_}, Source{});
-  ASSERT_EQ(
-      Diagnostics().str(),
-      R"(error: no matching call to textureDimensions(texture_depth_2d, bool)
+    auto* tex = create<sem::DepthTexture>(ast::TextureDimension::k2d);
+    auto* bool_ = create<sem::Bool>();
+    table->Lookup(BuiltinType::kTextureDimensions, {tex, bool_}, Source{});
+    ASSERT_EQ(Diagnostics().str(),
+              R"(error: no matching call to textureDimensions(texture_depth_2d, bool)
 
 27 candidate functions:
   textureDimensions(texture: texture_depth_2d, level: i32) -> vec2<i32>
@@ -577,24 +557,23 @@
 }
 
 TEST_F(BuiltinTableTest, SameOverloadReturnsSameBuiltinPointer) {
-  auto* f32 = create<sem::F32>();
-  auto* vec2_f32 = create<sem::Vector>(create<sem::F32>(), 2u);
-  auto* bool_ = create<sem::Bool>();
-  auto* a = table->Lookup(BuiltinType::kSelect, {f32, f32, bool_}, Source{});
-  ASSERT_NE(a, nullptr) << Diagnostics().str();
+    auto* f32 = create<sem::F32>();
+    auto* vec2_f32 = create<sem::Vector>(create<sem::F32>(), 2u);
+    auto* bool_ = create<sem::Bool>();
+    auto* a = table->Lookup(BuiltinType::kSelect, {f32, f32, bool_}, Source{});
+    ASSERT_NE(a, nullptr) << Diagnostics().str();
 
-  auto* b = table->Lookup(BuiltinType::kSelect, {f32, f32, bool_}, Source{});
-  ASSERT_NE(b, nullptr) << Diagnostics().str();
-  ASSERT_EQ(Diagnostics().str(), "");
+    auto* b = table->Lookup(BuiltinType::kSelect, {f32, f32, bool_}, Source{});
+    ASSERT_NE(b, nullptr) << Diagnostics().str();
+    ASSERT_EQ(Diagnostics().str(), "");
 
-  auto* c = table->Lookup(BuiltinType::kSelect, {vec2_f32, vec2_f32, bool_},
-                          Source{});
-  ASSERT_NE(c, nullptr) << Diagnostics().str();
-  ASSERT_EQ(Diagnostics().str(), "");
+    auto* c = table->Lookup(BuiltinType::kSelect, {vec2_f32, vec2_f32, bool_}, Source{});
+    ASSERT_NE(c, nullptr) << Diagnostics().str();
+    ASSERT_EQ(Diagnostics().str(), "");
 
-  EXPECT_EQ(a, b);
-  EXPECT_NE(a, c);
-  EXPECT_NE(b, c);
+    EXPECT_EQ(a, b);
+    EXPECT_NE(a, c);
+    EXPECT_NE(b, c);
 }
 
 }  // namespace
diff --git a/src/tint/castable.h b/src/tint/castable.h
index 211f2fb..048d1e5 100644
--- a/src/tint/castable.h
+++ b/src/tint/castable.h
@@ -21,24 +21,24 @@
 #include <utility>
 
 #include "src/tint/traits.h"
+#include "src/tint/utils/bitcast.h"
 #include "src/tint/utils/crc32.h"
+#include "src/tint/utils/defer.h"
 
 #if defined(__clang__)
 /// Temporarily disable certain warnings when using Castable API
-#define TINT_CASTABLE_PUSH_DISABLE_WARNINGS()                               \
-  _Pragma("clang diagnostic push")                                     /**/ \
-      _Pragma("clang diagnostic ignored \"-Wundefined-var-template\"") /**/ \
-      static_assert(true, "require extra semicolon")
+#define TINT_CASTABLE_PUSH_DISABLE_WARNINGS()                                 \
+    _Pragma("clang diagnostic push")                                     /**/ \
+        _Pragma("clang diagnostic ignored \"-Wundefined-var-template\"") /**/ \
+        static_assert(true, "require extra semicolon")
 
 /// Restore disabled warnings
 #define TINT_CASTABLE_POP_DISABLE_WARNINGS() \
-  _Pragma("clang diagnostic pop") /**/       \
-      static_assert(true, "require extra semicolon")
+    _Pragma("clang diagnostic pop") /**/     \
+        static_assert(true, "require extra semicolon")
 #else
-#define TINT_CASTABLE_PUSH_DISABLE_WARNINGS() \
-  static_assert(true, "require extra semicolon")
-#define TINT_CASTABLE_POP_DISABLE_WARNINGS() \
-  static_assert(true, "require extra semicolon")
+#define TINT_CASTABLE_PUSH_DISABLE_WARNINGS() static_assert(true, "require extra semicolon")
+#define TINT_CASTABLE_POP_DISABLE_WARNINGS() static_assert(true, "require extra semicolon")
 #endif
 
 TINT_CASTABLE_PUSH_DISABLE_WARNINGS();
@@ -62,190 +62,184 @@
 /// True if all template types that are not Ignore derive from CastableBase
 template <typename... TYPES>
 static constexpr bool IsCastable =
-    ((traits::IsTypeOrDerived<TYPES, CastableBase> ||
-      std::is_same_v<TYPES, Ignore>)&&...) &&
+    ((traits::IsTypeOrDerived<TYPES, CastableBase> || std::is_same_v<TYPES, Ignore>)&&...) &&
     !(std::is_same_v<TYPES, Ignore> && ...);
 
 /// Helper macro to instantiate the TypeInfo<T> template for `CLASS`.
-#define TINT_INSTANTIATE_TYPEINFO(CLASS)                      \
-  TINT_CASTABLE_PUSH_DISABLE_WARNINGS();                      \
-  template <>                                                 \
-  const tint::TypeInfo tint::detail::TypeInfoOf<CLASS>::info{ \
-      &tint::detail::TypeInfoOf<CLASS::TrueBase>::info,       \
-      #CLASS,                                                 \
-      tint::TypeInfo::HashCodeOf<CLASS>(),                    \
-      tint::TypeInfo::FullHashCodeOf<CLASS>(),                \
-  };                                                          \
-  TINT_CASTABLE_POP_DISABLE_WARNINGS()
+#define TINT_INSTANTIATE_TYPEINFO(CLASS)                        \
+    TINT_CASTABLE_PUSH_DISABLE_WARNINGS();                      \
+    template <>                                                 \
+    const tint::TypeInfo tint::detail::TypeInfoOf<CLASS>::info{ \
+        &tint::detail::TypeInfoOf<CLASS::TrueBase>::info,       \
+        #CLASS,                                                 \
+        tint::TypeInfo::HashCodeOf<CLASS>(),                    \
+        tint::TypeInfo::FullHashCodeOf<CLASS>(),                \
+    };                                                          \
+    TINT_CASTABLE_POP_DISABLE_WARNINGS()
 
 /// Bit flags that can be passed to the template parameter `FLAGS` of Is() and
 /// As().
 enum CastFlags {
-  /// Disables the static_assert() inside Is(), that compile-time-verifies that
-  /// the cast is possible. This flag may be useful for highly-generic template
-  /// code that needs to compile for template permutations that generate
-  /// impossible casts.
-  kDontErrorOnImpossibleCast = 1,
+    /// Disables the static_assert() inside Is(), that compile-time-verifies that
+    /// the cast is possible. This flag may be useful for highly-generic template
+    /// code that needs to compile for template permutations that generate
+    /// impossible casts.
+    kDontErrorOnImpossibleCast = 1,
 };
 
 /// TypeInfo holds type information for a Castable type.
 struct TypeInfo {
-  /// The type of a hash code
-  using HashCode = uint64_t;
+    /// The type of a hash code
+    using HashCode = uint64_t;
 
-  /// The base class of this type
-  const TypeInfo* base;
-  /// The type name
-  const char* name;
-  /// The type hash code
-  const HashCode hashcode;
-  /// The type hash code bitwise-or'd with all ancestor's hashcodes.
-  const HashCode full_hashcode;
+    /// The base class of this type
+    const TypeInfo* base;
+    /// The type name
+    const char* name;
+    /// The type hash code
+    const HashCode hashcode;
+    /// The type hash code bitwise-or'd with all ancestor's hashcodes.
+    const HashCode full_hashcode;
 
-  /// @param type the test type info
-  /// @returns true if the class with this TypeInfo is of, or derives from the
-  /// class with the given TypeInfo.
-  inline bool Is(const tint::TypeInfo* type) const {
-    // Optimization: Check whether the all the bits of the type's hashcode can
-    // be found in the full_hashcode. If a single bit is missing, then we
-    // can quickly tell that that this TypeInfo does not derive from `type`.
-    if ((full_hashcode & type->hashcode) != type->hashcode) {
-      return false;
+    /// @param type the test type info
+    /// @returns true if the class with this TypeInfo is of, or derives from the
+    /// class with the given TypeInfo.
+    inline bool Is(const tint::TypeInfo* type) const {
+        // Optimization: Check whether the all the bits of the type's hashcode can
+        // be found in the full_hashcode. If a single bit is missing, then we
+        // can quickly tell that that this TypeInfo does not derive from `type`.
+        if ((full_hashcode & type->hashcode) != type->hashcode) {
+            return false;
+        }
+
+        // Walk the base types, starting with this TypeInfo, to see if any of the
+        // pointers match `type`.
+        for (auto* ti = this; ti != nullptr; ti = ti->base) {
+            if (ti == type) {
+                return true;
+            }
+        }
+        return false;
     }
 
-    // Walk the base types, starting with this TypeInfo, to see if any of the
-    // pointers match `type`.
-    for (auto* ti = this; ti != nullptr; ti = ti->base) {
-      if (ti == type) {
-        return true;
-      }
-    }
-    return false;
-  }
+    /// @returns true if `type` derives from the class `TO`
+    /// @param type the object type to test from, which must be, or derive from
+    /// type `FROM`.
+    /// @see CastFlags
+    template <typename TO, typename FROM, int FLAGS = 0>
+    static inline bool Is(const tint::TypeInfo* type) {
+        constexpr const bool downcast = std::is_base_of<FROM, TO>::value;
+        constexpr const bool upcast = std::is_base_of<TO, FROM>::value;
+        constexpr const bool nocast = std::is_same<FROM, TO>::value;
+        constexpr const bool assert_is_castable = (FLAGS & kDontErrorOnImpossibleCast) == 0;
 
-  /// @returns true if `type` derives from the class `TO`
-  /// @param type the object type to test from, which must be, or derive from
-  /// type `FROM`.
-  /// @see CastFlags
-  template <typename TO, typename FROM, int FLAGS = 0>
-  static inline bool Is(const tint::TypeInfo* type) {
-    constexpr const bool downcast = std::is_base_of<FROM, TO>::value;
-    constexpr const bool upcast = std::is_base_of<TO, FROM>::value;
-    constexpr const bool nocast = std::is_same<FROM, TO>::value;
-    constexpr const bool assert_is_castable =
-        (FLAGS & kDontErrorOnImpossibleCast) == 0;
+        static_assert(upcast || downcast || nocast || !assert_is_castable, "impossible cast");
 
-    static_assert(upcast || downcast || nocast || !assert_is_castable,
-                  "impossible cast");
+        if (upcast || nocast) {
+            return true;
+        }
 
-    if (upcast || nocast) {
-      return true;
+        return type->Is(&Of<std::remove_cv_t<TO>>());
     }
 
-    return type->Is(&Of<std::remove_cv_t<TO>>());
-  }
+    /// @returns the static TypeInfo for the type T
+    template <typename T>
+    static const TypeInfo& Of() {
+        return detail::TypeInfoOf<std::remove_cv_t<T>>::info;
+    }
 
-  /// @returns the static TypeInfo for the type T
-  template <typename T>
-  static const TypeInfo& Of() {
-    return detail::TypeInfoOf<std::remove_cv_t<T>>::info;
-  }
-
-  /// @returns a compile-time hashcode for the type `T`.
-  /// @note the returned hashcode will have at most 2 bits set, as the hashes
-  /// are expected to be used in bloom-filters which will quickly saturate when
-  /// multiple hashcodes are bitwise-or'd together.
-  template <typename T>
-  static constexpr HashCode HashCodeOf() {
-    static_assert(IsCastable<T>, "T is not Castable");
-    static_assert(
-        std::is_same_v<T, std::remove_cv_t<T>>,
-        "Strip const / volatile decorations before calling HashCodeOf");
-    /// Use the compiler's "pretty" function name, which includes the template
-    /// type, to obtain a unique hash value.
+    /// @returns a compile-time hashcode for the type `T`.
+    /// @note the returned hashcode will have at most 2 bits set, as the hashes
+    /// are expected to be used in bloom-filters which will quickly saturate when
+    /// multiple hashcodes are bitwise-or'd together.
+    template <typename T>
+    static constexpr HashCode HashCodeOf() {
+        static_assert(IsCastable<T>, "T is not Castable");
+        static_assert(std::is_same_v<T, std::remove_cv_t<T>>,
+                      "Strip const / volatile decorations before calling HashCodeOf");
+        /// Use the compiler's "pretty" function name, which includes the template
+        /// type, to obtain a unique hash value.
 #ifdef _MSC_VER
-    constexpr uint32_t crc = utils::CRC32(__FUNCSIG__);
+        constexpr uint32_t crc = utils::CRC32(__FUNCSIG__);
 #else
-    constexpr uint32_t crc = utils::CRC32(__PRETTY_FUNCTION__);
+        constexpr uint32_t crc = utils::CRC32(__PRETTY_FUNCTION__);
 #endif
-    constexpr uint32_t bit_a = (crc & 63);
-    constexpr uint32_t bit_b = ((crc >> 6) & 63);
-    return (static_cast<HashCode>(1) << bit_a) |
-           (static_cast<HashCode>(1) << bit_b);
-  }
-
-  /// @returns the hashcode of the given type, bitwise-or'd with the hashcodes
-  /// of all base classes.
-  template <typename T>
-  static constexpr HashCode FullHashCodeOf() {
-    if constexpr (std::is_same_v<T, CastableBase>) {
-      return HashCodeOf<CastableBase>();
-    } else {
-      return HashCodeOf<T>() | FullHashCodeOf<typename T::TrueBase>();
+        constexpr uint32_t bit_a = (crc & 63);
+        constexpr uint32_t bit_b = ((crc >> 6) & 63);
+        return (static_cast<HashCode>(1) << bit_a) | (static_cast<HashCode>(1) << bit_b);
     }
-  }
 
-  /// @returns the bitwise-or'd hashcodes of all the types of the tuple `TUPLE`.
-  /// @see HashCodeOf
-  template <typename TUPLE>
-  static constexpr HashCode CombinedHashCodeOfTuple() {
-    constexpr auto kCount = std::tuple_size_v<TUPLE>;
-    if constexpr (kCount == 0) {
-      return 0;
-    } else if constexpr (kCount == 1) {
-      return HashCodeOf<std::remove_cv_t<std::tuple_element_t<0, TUPLE>>>();
-    } else {
-      constexpr auto kMid = kCount / 2;
-      return CombinedHashCodeOfTuple<traits::SliceTuple<0, kMid, TUPLE>>() |
-             CombinedHashCodeOfTuple<
-                 traits::SliceTuple<kMid, kCount - kMid, TUPLE>>();
+    /// @returns the hashcode of the given type, bitwise-or'd with the hashcodes
+    /// of all base classes.
+    template <typename T>
+    static constexpr HashCode FullHashCodeOf() {
+        if constexpr (std::is_same_v<T, CastableBase>) {
+            return HashCodeOf<CastableBase>();
+        } else {
+            return HashCodeOf<T>() | FullHashCodeOf<typename T::TrueBase>();
+        }
     }
-  }
 
-  /// @returns the bitwise-or'd hashcodes of all the template parameter types.
-  /// @see HashCodeOf
-  template <typename... TYPES>
-  static constexpr HashCode CombinedHashCodeOf() {
-    return CombinedHashCodeOfTuple<std::tuple<TYPES...>>();
-  }
-
-  /// @returns true if this TypeInfo is of, or derives from any of the types in
-  /// `TUPLE`.
-  template <typename TUPLE>
-  inline bool IsAnyOfTuple() const {
-    constexpr auto kCount = std::tuple_size_v<TUPLE>;
-    if constexpr (kCount == 0) {
-      return false;
-    } else if constexpr (kCount == 1) {
-      return Is(&Of<std::tuple_element_t<0, TUPLE>>());
-    } else if constexpr (kCount == 2) {
-      return Is(&Of<std::tuple_element_t<0, TUPLE>>()) ||
-             Is(&Of<std::tuple_element_t<1, TUPLE>>());
-    } else if constexpr (kCount == 3) {
-      return Is(&Of<std::tuple_element_t<0, TUPLE>>()) ||
-             Is(&Of<std::tuple_element_t<1, TUPLE>>()) ||
-             Is(&Of<std::tuple_element_t<2, TUPLE>>());
-    } else {
-      // Optimization: Compare the object's hashcode to the bitwise-or of all
-      // the tested type's hashcodes. If there's no intersection of bits in
-      // the two masks, then we can guarantee that the type is not in `TO`.
-      if (full_hashcode & TypeInfo::CombinedHashCodeOfTuple<TUPLE>()) {
-        // Possibly one of the types in `TUPLE`.
-        // Split the search in two, and scan each block.
-        static constexpr auto kMid = kCount / 2;
-        return IsAnyOfTuple<traits::SliceTuple<0, kMid, TUPLE>>() ||
-               IsAnyOfTuple<traits::SliceTuple<kMid, kCount - kMid, TUPLE>>();
-      }
-      return false;
+    /// @returns the bitwise-or'd hashcodes of all the types of the tuple `TUPLE`.
+    /// @see HashCodeOf
+    template <typename TUPLE>
+    static constexpr HashCode CombinedHashCodeOfTuple() {
+        constexpr auto kCount = std::tuple_size_v<TUPLE>;
+        if constexpr (kCount == 0) {
+            return 0;
+        } else if constexpr (kCount == 1) {
+            return HashCodeOf<std::remove_cv_t<std::tuple_element_t<0, TUPLE>>>();
+        } else {
+            constexpr auto kMid = kCount / 2;
+            return CombinedHashCodeOfTuple<traits::SliceTuple<0, kMid, TUPLE>>() |
+                   CombinedHashCodeOfTuple<traits::SliceTuple<kMid, kCount - kMid, TUPLE>>();
+        }
     }
-  }
 
-  /// @returns true if this TypeInfo is of, or derives from any of the types in
-  /// `TYPES`.
-  template <typename... TYPES>
-  inline bool IsAnyOf() const {
-    return IsAnyOfTuple<std::tuple<TYPES...>>();
-  }
+    /// @returns the bitwise-or'd hashcodes of all the template parameter types.
+    /// @see HashCodeOf
+    template <typename... TYPES>
+    static constexpr HashCode CombinedHashCodeOf() {
+        return CombinedHashCodeOfTuple<std::tuple<TYPES...>>();
+    }
+
+    /// @returns true if this TypeInfo is of, or derives from any of the types in
+    /// `TUPLE`.
+    template <typename TUPLE>
+    inline bool IsAnyOfTuple() const {
+        constexpr auto kCount = std::tuple_size_v<TUPLE>;
+        if constexpr (kCount == 0) {
+            return false;
+        } else if constexpr (kCount == 1) {
+            return Is(&Of<std::tuple_element_t<0, TUPLE>>());
+        } else if constexpr (kCount == 2) {
+            return Is(&Of<std::tuple_element_t<0, TUPLE>>()) ||
+                   Is(&Of<std::tuple_element_t<1, TUPLE>>());
+        } else if constexpr (kCount == 3) {
+            return Is(&Of<std::tuple_element_t<0, TUPLE>>()) ||
+                   Is(&Of<std::tuple_element_t<1, TUPLE>>()) ||
+                   Is(&Of<std::tuple_element_t<2, TUPLE>>());
+        } else {
+            // Optimization: Compare the object's hashcode to the bitwise-or of all
+            // the tested type's hashcodes. If there's no intersection of bits in
+            // the two masks, then we can guarantee that the type is not in `TO`.
+            if (full_hashcode & TypeInfo::CombinedHashCodeOfTuple<TUPLE>()) {
+                // Possibly one of the types in `TUPLE`.
+                // Split the search in two, and scan each block.
+                static constexpr auto kMid = kCount / 2;
+                return IsAnyOfTuple<traits::SliceTuple<0, kMid, TUPLE>>() ||
+                       IsAnyOfTuple<traits::SliceTuple<kMid, kCount - kMid, TUPLE>>();
+            }
+            return false;
+        }
+    }
+
+    /// @returns true if this TypeInfo is of, or derives from any of the types in
+    /// `TYPES`.
+    template <typename... TYPES>
+    inline bool IsAnyOf() const {
+        return IsAnyOfTuple<std::tuple<TYPES...>>();
+    }
 };
 
 namespace detail {
@@ -255,8 +249,8 @@
 /// `T`.
 template <typename T>
 struct TypeInfoOf {
-  /// The unique TypeInfo for the type T.
-  static const TypeInfo info;
+    /// The unique TypeInfo for the type T.
+    static const TypeInfo info;
 };
 
 /// A placeholder structure used for template parameters that need a default
@@ -271,10 +265,10 @@
 /// @see CastFlags
 template <typename TO, int FLAGS = 0, typename FROM = detail::Infer>
 inline bool Is(FROM* obj) {
-  if (obj == nullptr) {
-    return false;
-  }
-  return TypeInfo::Is<TO, FROM, FLAGS>(&obj->TypeInfo());
+    if (obj == nullptr) {
+        return false;
+    }
+    return TypeInfo::Is<TO, FROM, FLAGS>(&obj->TypeInfo());
 }
 
 /// @returns true if `obj` is a valid pointer, and is of, or derives from the
@@ -283,13 +277,9 @@
 /// @param pred predicate function with signature `bool(const TYPE*)` called iff
 /// object is of, or derives from the class `TYPE`.
 /// @see CastFlags
-template <typename TYPE,
-          int FLAGS = 0,
-          typename OBJ = detail::Infer,
-          typename Pred = detail::Infer>
+template <typename TYPE, int FLAGS = 0, typename OBJ = detail::Infer, typename Pred = detail::Infer>
 inline bool Is(OBJ* obj, Pred&& pred) {
-  return Is<TYPE, FLAGS, OBJ>(obj) &&
-         pred(static_cast<std::add_const_t<TYPE>*>(obj));
+    return Is<TYPE, FLAGS, OBJ>(obj) && pred(static_cast<std::add_const_t<TYPE>*>(obj));
 }
 
 /// @returns true if `obj` is a valid pointer, and is of, or derives from any of
@@ -297,10 +287,10 @@
 /// @param obj the object to query.
 template <typename... TYPES, typename OBJ>
 inline bool IsAnyOf(OBJ* obj) {
-  if (!obj) {
-    return false;
-  }
-  return obj->TypeInfo().template IsAnyOf<TYPES...>();
+    if (!obj) {
+        return false;
+    }
+    return obj->TypeInfo().template IsAnyOf<TYPES...>();
 }
 
 /// @returns obj dynamically cast to the type `TO` or `nullptr` if
@@ -309,8 +299,8 @@
 /// @see CastFlags
 template <typename TO, int FLAGS = 0, typename FROM = detail::Infer>
 inline TO* As(FROM* obj) {
-  auto* as_castable = static_cast<CastableBase*>(obj);
-  return Is<TO, FLAGS>(obj) ? static_cast<TO*>(as_castable) : nullptr;
+    auto* as_castable = static_cast<CastableBase*>(obj);
+    return Is<TO, FLAGS>(obj) ? static_cast<TO*>(as_castable) : nullptr;
 }
 
 /// @returns obj dynamically cast to the type `TO` or `nullptr` if
@@ -319,8 +309,8 @@
 /// @see CastFlags
 template <typename TO, int FLAGS = 0, typename FROM = detail::Infer>
 inline const TO* As(const FROM* obj) {
-  auto* as_castable = static_cast<const CastableBase*>(obj);
-  return Is<TO, FLAGS>(obj) ? static_cast<const TO*>(as_castable) : nullptr;
+    auto* as_castable = static_cast<const CastableBase*>(obj);
+    return Is<TO, FLAGS>(obj) ? static_cast<const TO*>(as_castable) : nullptr;
 }
 
 /// CastableBase is the base class for all Castable objects.
@@ -328,61 +318,61 @@
 /// Castable helper template.
 /// @see Castable
 class CastableBase {
- public:
-  /// Copy constructor
-  CastableBase(const CastableBase&) = default;
+  public:
+    /// Copy constructor
+    CastableBase(const CastableBase&) = default;
 
-  /// Destructor
-  virtual ~CastableBase() = default;
+    /// Destructor
+    virtual ~CastableBase() = default;
 
-  /// Copy assignment
-  /// @param other the CastableBase to copy
-  /// @returns the new CastableBase
-  CastableBase& operator=(const CastableBase& other) = default;
+    /// Copy assignment
+    /// @param other the CastableBase to copy
+    /// @returns the new CastableBase
+    CastableBase& operator=(const CastableBase& other) = default;
 
-  /// @returns the TypeInfo of the object
-  virtual const tint::TypeInfo& TypeInfo() const = 0;
+    /// @returns the TypeInfo of the object
+    virtual const tint::TypeInfo& TypeInfo() const = 0;
 
-  /// @returns true if this object is of, or derives from the class `TO`
-  template <typename TO>
-  inline bool Is() const {
-    return tint::Is<TO>(this);
-  }
+    /// @returns true if this object is of, or derives from the class `TO`
+    template <typename TO>
+    inline bool Is() const {
+        return tint::Is<TO>(this);
+    }
 
-  /// @returns true if this object is of, or derives from the class `TO` and
-  /// pred(const TO*) returns true
-  /// @param pred predicate function with signature `bool(const TO*)` called iff
-  /// object is of, or derives from the class `TO`.
-  template <typename TO, int FLAGS = 0, typename Pred = detail::Infer>
-  inline bool Is(Pred&& pred) const {
-    return tint::Is<TO, FLAGS>(this, std::forward<Pred>(pred));
-  }
+    /// @returns true if this object is of, or derives from the class `TO` and
+    /// pred(const TO*) returns true
+    /// @param pred predicate function with signature `bool(const TO*)` called iff
+    /// object is of, or derives from the class `TO`.
+    template <typename TO, int FLAGS = 0, typename Pred = detail::Infer>
+    inline bool Is(Pred&& pred) const {
+        return tint::Is<TO, FLAGS>(this, std::forward<Pred>(pred));
+    }
 
-  /// @returns true if this object is of, or derives from any of the `TO`
-  /// classes.
-  template <typename... TO>
-  inline bool IsAnyOf() const {
-    return tint::IsAnyOf<TO...>(this);
-  }
+    /// @returns true if this object is of, or derives from any of the `TO`
+    /// classes.
+    template <typename... TO>
+    inline bool IsAnyOf() const {
+        return tint::IsAnyOf<TO...>(this);
+    }
 
-  /// @returns this object dynamically cast to the type `TO` or `nullptr` if
-  /// this object does not derive from `TO`.
-  /// @see CastFlags
-  template <typename TO, int FLAGS = 0>
-  inline TO* As() {
-    return tint::As<TO, FLAGS>(this);
-  }
+    /// @returns this object dynamically cast to the type `TO` or `nullptr` if
+    /// this object does not derive from `TO`.
+    /// @see CastFlags
+    template <typename TO, int FLAGS = 0>
+    inline TO* As() {
+        return tint::As<TO, FLAGS>(this);
+    }
 
-  /// @returns this object dynamically cast to the type `TO` or `nullptr` if
-  /// this object does not derive from `TO`.
-  /// @see CastFlags
-  template <typename TO, int FLAGS = 0>
-  inline const TO* As() const {
-    return tint::As<const TO, FLAGS>(this);
-  }
+    /// @returns this object dynamically cast to the type `TO` or `nullptr` if
+    /// this object does not derive from `TO`.
+    /// @see CastFlags
+    template <typename TO, int FLAGS = 0>
+    inline const TO* As() const {
+        return tint::As<const TO, FLAGS>(this);
+    }
 
- protected:
-  CastableBase() = default;
+  protected:
+    CastableBase() = default;
 };
 
 /// Castable is a helper to derive `CLASS` from `BASE`, automatically
@@ -406,64 +396,60 @@
 /// ```
 template <typename CLASS, typename BASE = CastableBase>
 class Castable : public BASE {
- public:
-  // Inherit the `BASE` class constructors.
-  using BASE::BASE;
+  public:
+    // Inherit the `BASE` class constructors.
+    using BASE::BASE;
 
-  /// A type alias for `CLASS` to easily access the `BASE` class members.
-  /// Base actually aliases to the Castable instead of `BASE` so that you can
-  /// use Base in the `CLASS` constructor.
-  using Base = Castable;
+    /// A type alias for `CLASS` to easily access the `BASE` class members.
+    /// Base actually aliases to the Castable instead of `BASE` so that you can
+    /// use Base in the `CLASS` constructor.
+    using Base = Castable;
 
-  /// A type alias for `BASE`.
-  using TrueBase = BASE;
+    /// A type alias for `BASE`.
+    using TrueBase = BASE;
 
-  /// @returns the TypeInfo of the object
-  const tint::TypeInfo& TypeInfo() const override {
-    return TypeInfo::Of<CLASS>();
-  }
+    /// @returns the TypeInfo of the object
+    const tint::TypeInfo& TypeInfo() const override { return TypeInfo::Of<CLASS>(); }
 
-  /// @returns true if this object is of, or derives from the class `TO`
-  /// @see CastFlags
-  template <typename TO, int FLAGS = 0>
-  inline bool Is() const {
-    return tint::Is<TO, FLAGS>(static_cast<const CLASS*>(this));
-  }
+    /// @returns true if this object is of, or derives from the class `TO`
+    /// @see CastFlags
+    template <typename TO, int FLAGS = 0>
+    inline bool Is() const {
+        return tint::Is<TO, FLAGS>(static_cast<const CLASS*>(this));
+    }
 
-  /// @returns true if this object is of, or derives from the class `TO` and
-  /// pred(const TO*) returns true
-  /// @param pred predicate function with signature `bool(const TO*)` called iff
-  /// object is of, or derives from the class `TO`.
-  template <int FLAGS = 0, typename Pred = detail::Infer>
-  inline bool Is(Pred&& pred) const {
-    using TO =
-        typename std::remove_pointer<traits::ParameterType<Pred, 0>>::type;
-    return tint::Is<TO, FLAGS>(static_cast<const CLASS*>(this),
-                               std::forward<Pred>(pred));
-  }
+    /// @returns true if this object is of, or derives from the class `TO` and
+    /// pred(const TO*) returns true
+    /// @param pred predicate function with signature `bool(const TO*)` called iff
+    /// object is of, or derives from the class `TO`.
+    template <int FLAGS = 0, typename Pred = detail::Infer>
+    inline bool Is(Pred&& pred) const {
+        using TO = typename std::remove_pointer<traits::ParameterType<Pred, 0>>::type;
+        return tint::Is<TO, FLAGS>(static_cast<const CLASS*>(this), std::forward<Pred>(pred));
+    }
 
-  /// @returns true if this object is of, or derives from any of the `TO`
-  /// classes.
-  template <typename... TO>
-  inline bool IsAnyOf() const {
-    return tint::IsAnyOf<TO...>(static_cast<const CLASS*>(this));
-  }
+    /// @returns true if this object is of, or derives from any of the `TO`
+    /// classes.
+    template <typename... TO>
+    inline bool IsAnyOf() const {
+        return tint::IsAnyOf<TO...>(static_cast<const CLASS*>(this));
+    }
 
-  /// @returns this object dynamically cast to the type `TO` or `nullptr` if
-  /// this object does not derive from `TO`.
-  /// @see CastFlags
-  template <typename TO, int FLAGS = 0>
-  inline TO* As() {
-    return tint::As<TO, FLAGS>(this);
-  }
+    /// @returns this object dynamically cast to the type `TO` or `nullptr` if
+    /// this object does not derive from `TO`.
+    /// @see CastFlags
+    template <typename TO, int FLAGS = 0>
+    inline TO* As() {
+        return tint::As<TO, FLAGS>(this);
+    }
 
-  /// @returns this object dynamically cast to the type `TO` or `nullptr` if
-  /// this object does not derive from `TO`.
-  /// @see CastFlags
-  template <typename TO, int FLAGS = 0>
-  inline const TO* As() const {
-    return tint::As<const TO, FLAGS>(this);
-  }
+    /// @returns this object dynamically cast to the type `TO` or `nullptr` if
+    /// this object does not derive from `TO`.
+    /// @see CastFlags
+    template <typename TO, int FLAGS = 0>
+    inline const TO* As() const {
+        return tint::As<const TO, FLAGS>(this);
+    }
 };
 
 namespace detail {
@@ -474,51 +460,50 @@
 
 /// Alias to typename CastableCommonBaseImpl<TYPES>::type
 template <typename... TYPES>
-using CastableCommonBase =
-    typename detail::CastableCommonBaseImpl<TYPES...>::type;
+using CastableCommonBase = typename detail::CastableCommonBaseImpl<TYPES...>::type;
 
 /// CastableCommonBaseImpl template specialization for a single type
 template <typename T>
 struct CastableCommonBaseImpl<T> {
-  /// Common base class of a single type is itself
-  using type = T;
+    /// Common base class of a single type is itself
+    using type = T;
 };
 
 /// CastableCommonBaseImpl A <-> CastableBase specialization
 template <typename A>
 struct CastableCommonBaseImpl<A, CastableBase> {
-  /// Common base class for A and CastableBase is CastableBase
-  using type = CastableBase;
+    /// Common base class for A and CastableBase is CastableBase
+    using type = CastableBase;
 };
 
 /// CastableCommonBaseImpl T <-> Ignore specialization
 template <typename T>
 struct CastableCommonBaseImpl<T, Ignore> {
-  /// Resolves to T as the other type is ignored
-  using type = T;
+    /// Resolves to T as the other type is ignored
+    using type = T;
 };
 
 /// CastableCommonBaseImpl Ignore <-> T specialization
 template <typename T>
 struct CastableCommonBaseImpl<Ignore, T> {
-  /// Resolves to T as the other type is ignored
-  using type = T;
+    /// Resolves to T as the other type is ignored
+    using type = T;
 };
 
 /// CastableCommonBaseImpl A <-> B specialization
 template <typename A, typename B>
 struct CastableCommonBaseImpl<A, B> {
-  /// The common base class for A, B and OTHERS
-  using type = std::conditional_t<traits::IsTypeOrDerived<A, B>,
-                                  B,  // A derives from B
-                                  CastableCommonBase<A, typename B::TrueBase>>;
+    /// The common base class for A, B and OTHERS
+    using type = std::conditional_t<traits::IsTypeOrDerived<A, B>,
+                                    B,  // A derives from B
+                                    CastableCommonBase<A, typename B::TrueBase>>;
 };
 
 /// CastableCommonBaseImpl 3+ types specialization
 template <typename A, typename B, typename... OTHERS>
 struct CastableCommonBaseImpl<A, B, OTHERS...> {
-  /// The common base class for A, B and OTHERS
-  using type = CastableCommonBase<CastableCommonBase<A, B>, OTHERS...>;
+    /// The common base class for A, B and OTHERS
+    using type = CastableCommonBase<CastableCommonBase<A, B>, OTHERS...>;
 };
 
 }  // namespace detail
@@ -547,29 +532,27 @@
 /// @note does not handle the Default case
 /// @see Switch().
 template <typename FN>
-using SwitchCaseType = std::remove_pointer_t<
-    traits::ParameterType<std::remove_reference_t<FN>, 0>>;
+using SwitchCaseType = std::remove_pointer_t<traits::ParameterType<std::remove_reference_t<FN>, 0>>;
 
 /// Evaluates to true if the function `FN` has the signature of a Default case
 /// in a Switch().
 /// @see Switch().
 template <typename FN>
 inline constexpr bool IsDefaultCase =
-    std::is_same_v<traits::ParameterType<std::remove_reference_t<FN>, 0>,
-                   Default>;
+    std::is_same_v<traits::ParameterType<std::remove_reference_t<FN>, 0>, Default>;
 
 /// Searches the list of Switch cases for a Default case, returning the index of
 /// the Default case. If the a Default case is not found in the tuple, then -1
 /// is returned.
 template <typename TUPLE, std::size_t START_IDX = 0>
 constexpr int IndexOfDefaultCase() {
-  if constexpr (START_IDX < std::tuple_size_v<TUPLE>) {
-    return IsDefaultCase<std::tuple_element_t<START_IDX, TUPLE>>
-               ? static_cast<int>(START_IDX)
-               : IndexOfDefaultCase<TUPLE, START_IDX + 1>();
-  } else {
-    return -1;
-  }
+    if constexpr (START_IDX < std::tuple_size_v<TUPLE>) {
+        return IsDefaultCase<std::tuple_element_t<START_IDX, TUPLE>>
+                   ? static_cast<int>(START_IDX)
+                   : IndexOfDefaultCase<TUPLE, START_IDX + 1>();
+    } else {
+        return -1;
+    }
 }
 
 /// The implementation of Switch() for non-Default cases.
@@ -586,102 +569,119 @@
                             const TypeInfo* type,
                             RETURN_TYPE* result,
                             std::tuple<CASES...>&& cases) {
-  using Cases = std::tuple<CASES...>;
+    using Cases = std::tuple<CASES...>;
 
-  (void)result;  // Not always used, avoid warning.
+    (void)result;  // Not always used, avoid warning.
 
-  static constexpr bool kHasReturnType = !std::is_same_v<RETURN_TYPE, void>;
-  static constexpr size_t kNumCases = sizeof...(CASES);
+    static constexpr bool kHasReturnType = !std::is_same_v<RETURN_TYPE, void>;
+    static constexpr size_t kNumCases = sizeof...(CASES);
 
-  if constexpr (kNumCases == 0) {
-    // No cases. Nothing to do.
-    return false;
-  } else if constexpr (kNumCases == 1) {  // NOLINT: cpplint doesn't understand
-                                          // `else if constexpr`
-    // Single case.
-    using CaseFunc = std::tuple_element_t<0, Cases>;
-    static_assert(!IsDefaultCase<CaseFunc>,
-                  "NonDefaultCases called with a Default case");
-    // Attempt to dynamically cast the object to the handler type. If that
-    // succeeds, call the case handler with the cast object.
-    using CaseType = SwitchCaseType<CaseFunc>;
-    if (type->Is(&TypeInfo::Of<CaseType>())) {
-      auto* ptr = static_cast<CaseType*>(object);
-      if constexpr (kHasReturnType) {
-        *result = static_cast<RETURN_TYPE>(std::get<0>(cases)(ptr));
-      } else {
-        std::get<0>(cases)(ptr);
-      }
-      return true;
-    }
-    return false;
-  } else {
-    // Multiple cases.
-    // Check the hashcode bits to see if there's any possibility of a case
-    // matching in these cases. If there isn't, we can skip all these cases.
-    if (type->full_hashcode &
-        TypeInfo::CombinedHashCodeOf<SwitchCaseType<CASES>...>()) {
-      // There's a possibility. We need to scan further.
-      // Split the cases into two, and recurse.
-      constexpr size_t kMid = kNumCases / 2;
-      return NonDefaultCases(object, type, result,
-                             traits::Slice<0, kMid>(cases)) ||
-             NonDefaultCases(object, type, result,
-                             traits::Slice<kMid, kNumCases - kMid>(cases));
+    if constexpr (kNumCases == 0) {
+        // No cases. Nothing to do.
+        return false;
+    } else if constexpr (kNumCases == 1) {  // NOLINT: cpplint doesn't understand
+                                            // `else if constexpr`
+        // Single case.
+        using CaseFunc = std::tuple_element_t<0, Cases>;
+        static_assert(!IsDefaultCase<CaseFunc>, "NonDefaultCases called with a Default case");
+        // Attempt to dynamically cast the object to the handler type. If that
+        // succeeds, call the case handler with the cast object.
+        using CaseType = SwitchCaseType<CaseFunc>;
+        if (type->Is(&TypeInfo::Of<CaseType>())) {
+            auto* ptr = static_cast<CaseType*>(object);
+            if constexpr (kHasReturnType) {
+                new (result) RETURN_TYPE(static_cast<RETURN_TYPE>(std::get<0>(cases)(ptr)));
+            } else {
+                std::get<0>(cases)(ptr);
+            }
+            return true;
+        }
+        return false;
     } else {
-      return false;
+        // Multiple cases.
+        // Check the hashcode bits to see if there's any possibility of a case
+        // matching in these cases. If there isn't, we can skip all these cases.
+        if (type->full_hashcode & TypeInfo::CombinedHashCodeOf<SwitchCaseType<CASES>...>()) {
+            // There's a possibility. We need to scan further.
+            // Split the cases into two, and recurse.
+            constexpr size_t kMid = kNumCases / 2;
+            return NonDefaultCases(object, type, result, traits::Slice<0, kMid>(cases)) ||
+                   NonDefaultCases(object, type, result,
+                                   traits::Slice<kMid, kNumCases - kMid>(cases));
+        } else {
+            return false;
+        }
     }
-  }
 }
 
 /// The implementation of Switch() for all cases.
 /// @see NonDefaultCases
 template <typename T, typename RETURN_TYPE, typename... CASES>
-inline void SwitchCases(T* object,
-                        RETURN_TYPE* result,
-                        std::tuple<CASES...>&& cases) {
-  using Cases = std::tuple<CASES...>;
-  static constexpr int kDefaultIndex = detail::IndexOfDefaultCase<Cases>();
-  static_assert(
-      kDefaultIndex == -1 || kDefaultIndex == std::tuple_size_v<Cases> - 1,
-      "Default case must be last in Switch()");
-  static constexpr bool kHasDefaultCase = kDefaultIndex >= 0;
-  static constexpr bool kHasReturnType = !std::is_same_v<RETURN_TYPE, void>;
+inline void SwitchCases(T* object, RETURN_TYPE* result, std::tuple<CASES...>&& cases) {
+    using Cases = std::tuple<CASES...>;
 
-  if (object) {
-    auto* type = &object->TypeInfo();
-    if constexpr (kHasDefaultCase) {
-      // Evaluate non-default cases.
-      if (!detail::NonDefaultCases<T>(object, type, result,
-                                      traits::Slice<0, kDefaultIndex>(cases))) {
-        // Nothing matched. Evaluate default case.
-        if constexpr (kHasReturnType) {
-          *result =
-              static_cast<RETURN_TYPE>(std::get<kDefaultIndex>(cases)({}));
+    static constexpr int kDefaultIndex = detail::IndexOfDefaultCase<Cases>();
+    static constexpr bool kHasDefaultCase = kDefaultIndex >= 0;
+    static constexpr bool kHasReturnType = !std::is_same_v<RETURN_TYPE, void>;
+
+    // Static assertions
+    static constexpr bool kDefaultIsOK =
+        kDefaultIndex == -1 || kDefaultIndex == std::tuple_size_v<Cases> - 1;
+    static constexpr bool kReturnIsOK =
+        kHasDefaultCase || !kHasReturnType || std::is_constructible_v<RETURN_TYPE>;
+    static_assert(kDefaultIsOK, "Default case must be last in Switch()");
+    static_assert(kReturnIsOK,
+                  "Switch() requires either a Default case or a return type that is either void or "
+                  "default-constructable");
+
+    // If the static asserts have fired, don't bother spewing more errors below
+    static constexpr bool kAllOK = kDefaultIsOK && kReturnIsOK;
+    if constexpr (kAllOK) {
+        if (object) {
+            auto* type = &object->TypeInfo();
+            if constexpr (kHasDefaultCase) {
+                // Evaluate non-default cases.
+                if (!detail::NonDefaultCases<T>(object, type, result,
+                                                traits::Slice<0, kDefaultIndex>(cases))) {
+                    // Nothing matched. Evaluate default case.
+                    if constexpr (kHasReturnType) {
+                        new (result) RETURN_TYPE(
+                            static_cast<RETURN_TYPE>(std::get<kDefaultIndex>(cases)({})));
+                    } else {
+                        std::get<kDefaultIndex>(cases)({});
+                    }
+                }
+            } else {
+                if (!detail::NonDefaultCases<T>(object, type, result, std::move(cases))) {
+                    // Nothing matched. No default case.
+                    if constexpr (kHasReturnType) {
+                        new (result) RETURN_TYPE();
+                    }
+                }
+            }
         } else {
-          std::get<kDefaultIndex>(cases)({});
+            // Object is nullptr, so no cases can match
+            if constexpr (kHasDefaultCase) {
+                // Evaluate default case.
+                if constexpr (kHasReturnType) {
+                    new (result)
+                        RETURN_TYPE(static_cast<RETURN_TYPE>(std::get<kDefaultIndex>(cases)({})));
+                } else {
+                    std::get<kDefaultIndex>(cases)({});
+                }
+            } else {
+                // No default case, no case can match.
+                if constexpr (kHasReturnType) {
+                    new (result) RETURN_TYPE();
+                }
+            }
         }
-      }
-    } else {
-      detail::NonDefaultCases<T>(object, type, result, std::move(cases));
     }
-  } else {
-    // Object is nullptr, so no cases can match
-    if constexpr (kHasDefaultCase) {
-      // Evaluate default case.
-      if constexpr (kHasReturnType) {
-        *result = static_cast<RETURN_TYPE>(std::get<kDefaultIndex>(cases)({}));
-      } else {
-        std::get<kDefaultIndex>(cases)({});
-      }
-    }
-  }
 }
 
 /// Resolves to T if T is not nullptr_t, otherwise resolves to Ignore.
 template <typename T>
-using NullptrToIgnore =
-    std::conditional_t<std::is_same_v<T, std::nullptr_t>, Ignore, T>;
+using NullptrToIgnore = std::conditional_t<std::is_same_v<T, std::nullptr_t>, Ignore, T>;
 
 /// Resolves to `const TYPE` if any of `CASE_RETURN_TYPES` are const or
 /// pointer-to-const, otherwise resolves to TYPE.
@@ -693,55 +693,46 @@
     TYPE>;       // No:  Passthrough
 
 /// SwitchReturnTypeImpl is the implementation of SwitchReturnType
-template <bool IS_CASTABLE,
-          typename REQUESTED_TYPE,
-          typename... CASE_RETURN_TYPES>
+template <bool IS_CASTABLE, typename REQUESTED_TYPE, typename... CASE_RETURN_TYPES>
 struct SwitchReturnTypeImpl;
 
 /// SwitchReturnTypeImpl specialization for non-castable case types and an
 /// explicitly specified return type.
 template <typename REQUESTED_TYPE, typename... CASE_RETURN_TYPES>
-struct SwitchReturnTypeImpl</*IS_CASTABLE*/ false,
-                            REQUESTED_TYPE,
-                            CASE_RETURN_TYPES...> {
-  /// Resolves to `REQUESTED_TYPE`
-  using type = REQUESTED_TYPE;
+struct SwitchReturnTypeImpl</*IS_CASTABLE*/ false, REQUESTED_TYPE, CASE_RETURN_TYPES...> {
+    /// Resolves to `REQUESTED_TYPE`
+    using type = REQUESTED_TYPE;
 };
 
 /// SwitchReturnTypeImpl specialization for non-castable case types and an
 /// inferred return type.
 template <typename... CASE_RETURN_TYPES>
-struct SwitchReturnTypeImpl</*IS_CASTABLE*/ false,
-                            Infer,
-                            CASE_RETURN_TYPES...> {
-  /// Resolves to the common type for all the cases return types.
-  using type = std::common_type_t<CASE_RETURN_TYPES...>;
+struct SwitchReturnTypeImpl</*IS_CASTABLE*/ false, Infer, CASE_RETURN_TYPES...> {
+    /// Resolves to the common type for all the cases return types.
+    using type = std::common_type_t<CASE_RETURN_TYPES...>;
 };
 
 /// SwitchReturnTypeImpl specialization for castable case types and an
 /// explicitly specified return type.
 template <typename REQUESTED_TYPE, typename... CASE_RETURN_TYPES>
-struct SwitchReturnTypeImpl</*IS_CASTABLE*/ true,
-                            REQUESTED_TYPE,
-                            CASE_RETURN_TYPES...> {
- public:
-  /// Resolves to `const REQUESTED_TYPE*` or `REQUESTED_TYPE*`
-  using type = PropagateReturnConst<std::remove_pointer_t<REQUESTED_TYPE>,
-                                    CASE_RETURN_TYPES...>*;
+struct SwitchReturnTypeImpl</*IS_CASTABLE*/ true, REQUESTED_TYPE, CASE_RETURN_TYPES...> {
+  public:
+    /// Resolves to `const REQUESTED_TYPE*` or `REQUESTED_TYPE*`
+    using type = PropagateReturnConst<std::remove_pointer_t<REQUESTED_TYPE>, CASE_RETURN_TYPES...>*;
 };
 
 /// SwitchReturnTypeImpl specialization for castable case types and an infered
 /// return type.
 template <typename... CASE_RETURN_TYPES>
 struct SwitchReturnTypeImpl</*IS_CASTABLE*/ true, Infer, CASE_RETURN_TYPES...> {
- private:
-  using InferredType = CastableCommonBase<
-      detail::NullptrToIgnore<std::remove_pointer_t<CASE_RETURN_TYPES>>...>;
+  private:
+    using InferredType =
+        CastableCommonBase<detail::NullptrToIgnore<std::remove_pointer_t<CASE_RETURN_TYPES>>...>;
 
- public:
-  /// `const T*` or `T*`, where T is the common base type for all the castable
-  /// case types.
-  using type = PropagateReturnConst<InferredType, CASE_RETURN_TYPES...>*;
+  public:
+    /// `const T*` or `T*`, where T is the common base type for all the castable
+    /// case types.
+    using type = PropagateReturnConst<InferredType, CASE_RETURN_TYPES...>*;
 };
 
 /// Resolves to the return type for a Switch() with the requested return type
@@ -790,23 +781,25 @@
 /// @param cases the switch cases
 /// @return the value returned by the called case. If no cases matched, then the
 /// zero value for the consistent case type.
-template <typename RETURN_TYPE = detail::Infer,
-          typename T = CastableBase,
-          typename... CASES>
+template <typename RETURN_TYPE = detail::Infer, typename T = CastableBase, typename... CASES>
 inline auto Switch(T* object, CASES&&... cases) {
-  using ReturnType =
-      detail::SwitchReturnType<RETURN_TYPE, traits::ReturnType<CASES>...>;
-  static constexpr bool kHasReturnType = !std::is_same_v<ReturnType, void>;
+    using ReturnType = detail::SwitchReturnType<RETURN_TYPE, traits::ReturnType<CASES>...>;
+    static constexpr bool kHasReturnType = !std::is_same_v<ReturnType, void>;
 
-  if constexpr (kHasReturnType) {
-    ReturnType res = {};
-    detail::SwitchCases(object, &res,
-                        std::forward_as_tuple(std::forward<CASES>(cases)...));
-    return res;
-  } else {
-    detail::SwitchCases<T, void>(
-        object, nullptr, std::forward_as_tuple(std::forward<CASES>(cases)...));
-  }
+    if constexpr (kHasReturnType) {
+        // Replacement for std::aligned_storage as this is broken on earlier versions of MSVC.
+        struct alignas(alignof(ReturnType)) ReturnStorage {
+            uint8_t data[sizeof(ReturnType)];
+        };
+        ReturnStorage storage;
+        auto* res = utils::Bitcast<ReturnType*>(&storage);
+        TINT_DEFER(res->~ReturnType());
+        detail::SwitchCases(object, res, std::forward_as_tuple(std::forward<CASES>(cases)...));
+        return *res;
+    } else {
+        detail::SwitchCases<T, void>(object, nullptr,
+                                     std::forward_as_tuple(std::forward<CASES>(cases)...));
+    }
 }
 
 }  // namespace tint
diff --git a/src/tint/castable_bench.cc b/src/tint/castable_bench.cc
index 839a932..7c7e0ef 100644
--- a/src/tint/castable_bench.cc
+++ b/src/tint/castable_bench.cc
@@ -100,127 +100,127 @@
                             CCC>;
 
 std::vector<std::unique_ptr<Base>> MakeObjects() {
-  std::vector<std::unique_ptr<Base>> out;
-  out.emplace_back(std::make_unique<Base>());
-  out.emplace_back(std::make_unique<A>());
-  out.emplace_back(std::make_unique<AA>());
-  out.emplace_back(std::make_unique<AAA>());
-  out.emplace_back(std::make_unique<AAB>());
-  out.emplace_back(std::make_unique<AAC>());
-  out.emplace_back(std::make_unique<AB>());
-  out.emplace_back(std::make_unique<ABA>());
-  out.emplace_back(std::make_unique<ABB>());
-  out.emplace_back(std::make_unique<ABC>());
-  out.emplace_back(std::make_unique<AC>());
-  out.emplace_back(std::make_unique<ACA>());
-  out.emplace_back(std::make_unique<ACB>());
-  out.emplace_back(std::make_unique<ACC>());
-  out.emplace_back(std::make_unique<B>());
-  out.emplace_back(std::make_unique<BA>());
-  out.emplace_back(std::make_unique<BAA>());
-  out.emplace_back(std::make_unique<BAB>());
-  out.emplace_back(std::make_unique<BAC>());
-  out.emplace_back(std::make_unique<BB>());
-  out.emplace_back(std::make_unique<BBA>());
-  out.emplace_back(std::make_unique<BBB>());
-  out.emplace_back(std::make_unique<BBC>());
-  out.emplace_back(std::make_unique<BC>());
-  out.emplace_back(std::make_unique<BCA>());
-  out.emplace_back(std::make_unique<BCB>());
-  out.emplace_back(std::make_unique<BCC>());
-  out.emplace_back(std::make_unique<C>());
-  out.emplace_back(std::make_unique<CA>());
-  out.emplace_back(std::make_unique<CAA>());
-  out.emplace_back(std::make_unique<CAB>());
-  out.emplace_back(std::make_unique<CAC>());
-  out.emplace_back(std::make_unique<CB>());
-  out.emplace_back(std::make_unique<CBA>());
-  out.emplace_back(std::make_unique<CBB>());
-  out.emplace_back(std::make_unique<CBC>());
-  out.emplace_back(std::make_unique<CC>());
-  out.emplace_back(std::make_unique<CCA>());
-  out.emplace_back(std::make_unique<CCB>());
-  out.emplace_back(std::make_unique<CCC>());
-  return out;
+    std::vector<std::unique_ptr<Base>> out;
+    out.emplace_back(std::make_unique<Base>());
+    out.emplace_back(std::make_unique<A>());
+    out.emplace_back(std::make_unique<AA>());
+    out.emplace_back(std::make_unique<AAA>());
+    out.emplace_back(std::make_unique<AAB>());
+    out.emplace_back(std::make_unique<AAC>());
+    out.emplace_back(std::make_unique<AB>());
+    out.emplace_back(std::make_unique<ABA>());
+    out.emplace_back(std::make_unique<ABB>());
+    out.emplace_back(std::make_unique<ABC>());
+    out.emplace_back(std::make_unique<AC>());
+    out.emplace_back(std::make_unique<ACA>());
+    out.emplace_back(std::make_unique<ACB>());
+    out.emplace_back(std::make_unique<ACC>());
+    out.emplace_back(std::make_unique<B>());
+    out.emplace_back(std::make_unique<BA>());
+    out.emplace_back(std::make_unique<BAA>());
+    out.emplace_back(std::make_unique<BAB>());
+    out.emplace_back(std::make_unique<BAC>());
+    out.emplace_back(std::make_unique<BB>());
+    out.emplace_back(std::make_unique<BBA>());
+    out.emplace_back(std::make_unique<BBB>());
+    out.emplace_back(std::make_unique<BBC>());
+    out.emplace_back(std::make_unique<BC>());
+    out.emplace_back(std::make_unique<BCA>());
+    out.emplace_back(std::make_unique<BCB>());
+    out.emplace_back(std::make_unique<BCC>());
+    out.emplace_back(std::make_unique<C>());
+    out.emplace_back(std::make_unique<CA>());
+    out.emplace_back(std::make_unique<CAA>());
+    out.emplace_back(std::make_unique<CAB>());
+    out.emplace_back(std::make_unique<CAC>());
+    out.emplace_back(std::make_unique<CB>());
+    out.emplace_back(std::make_unique<CBA>());
+    out.emplace_back(std::make_unique<CBB>());
+    out.emplace_back(std::make_unique<CBC>());
+    out.emplace_back(std::make_unique<CC>());
+    out.emplace_back(std::make_unique<CCA>());
+    out.emplace_back(std::make_unique<CCB>());
+    out.emplace_back(std::make_unique<CCC>());
+    return out;
 }
 
 void CastableLargeSwitch(::benchmark::State& state) {
-  auto objects = MakeObjects();
-  size_t i = 0;
-  for (auto _ : state) {
-    auto* object = objects[i % objects.size()].get();
-    Switch(
-        object,  //
-        [&](const AAA*) { ::benchmark::DoNotOptimize(i += 40); },
-        [&](const AAB*) { ::benchmark::DoNotOptimize(i += 50); },
-        [&](const AAC*) { ::benchmark::DoNotOptimize(i += 60); },
-        [&](const ABA*) { ::benchmark::DoNotOptimize(i += 80); },
-        [&](const ABB*) { ::benchmark::DoNotOptimize(i += 90); },
-        [&](const ABC*) { ::benchmark::DoNotOptimize(i += 100); },
-        [&](const ACA*) { ::benchmark::DoNotOptimize(i += 120); },
-        [&](const ACB*) { ::benchmark::DoNotOptimize(i += 130); },
-        [&](const ACC*) { ::benchmark::DoNotOptimize(i += 140); },
-        [&](const BAA*) { ::benchmark::DoNotOptimize(i += 170); },
-        [&](const BAB*) { ::benchmark::DoNotOptimize(i += 180); },
-        [&](const BAC*) { ::benchmark::DoNotOptimize(i += 190); },
-        [&](const BBA*) { ::benchmark::DoNotOptimize(i += 210); },
-        [&](const BBB*) { ::benchmark::DoNotOptimize(i += 220); },
-        [&](const BBC*) { ::benchmark::DoNotOptimize(i += 230); },
-        [&](const BCA*) { ::benchmark::DoNotOptimize(i += 250); },
-        [&](const BCB*) { ::benchmark::DoNotOptimize(i += 260); },
-        [&](const BCC*) { ::benchmark::DoNotOptimize(i += 270); },
-        [&](const CA*) { ::benchmark::DoNotOptimize(i += 290); },
-        [&](const CAA*) { ::benchmark::DoNotOptimize(i += 300); },
-        [&](const CAB*) { ::benchmark::DoNotOptimize(i += 310); },
-        [&](const CAC*) { ::benchmark::DoNotOptimize(i += 320); },
-        [&](const CBA*) { ::benchmark::DoNotOptimize(i += 340); },
-        [&](const CBB*) { ::benchmark::DoNotOptimize(i += 350); },
-        [&](const CBC*) { ::benchmark::DoNotOptimize(i += 360); },
-        [&](const CCA*) { ::benchmark::DoNotOptimize(i += 380); },
-        [&](const CCB*) { ::benchmark::DoNotOptimize(i += 390); },
-        [&](const CCC*) { ::benchmark::DoNotOptimize(i += 400); },
-        [&](Default) { ::benchmark::DoNotOptimize(i += 123); });
-    i = (i * 31) ^ (i << 5);
-  }
+    auto objects = MakeObjects();
+    size_t i = 0;
+    for (auto _ : state) {
+        auto* object = objects[i % objects.size()].get();
+        Switch(
+            object,  //
+            [&](const AAA*) { ::benchmark::DoNotOptimize(i += 40); },
+            [&](const AAB*) { ::benchmark::DoNotOptimize(i += 50); },
+            [&](const AAC*) { ::benchmark::DoNotOptimize(i += 60); },
+            [&](const ABA*) { ::benchmark::DoNotOptimize(i += 80); },
+            [&](const ABB*) { ::benchmark::DoNotOptimize(i += 90); },
+            [&](const ABC*) { ::benchmark::DoNotOptimize(i += 100); },
+            [&](const ACA*) { ::benchmark::DoNotOptimize(i += 120); },
+            [&](const ACB*) { ::benchmark::DoNotOptimize(i += 130); },
+            [&](const ACC*) { ::benchmark::DoNotOptimize(i += 140); },
+            [&](const BAA*) { ::benchmark::DoNotOptimize(i += 170); },
+            [&](const BAB*) { ::benchmark::DoNotOptimize(i += 180); },
+            [&](const BAC*) { ::benchmark::DoNotOptimize(i += 190); },
+            [&](const BBA*) { ::benchmark::DoNotOptimize(i += 210); },
+            [&](const BBB*) { ::benchmark::DoNotOptimize(i += 220); },
+            [&](const BBC*) { ::benchmark::DoNotOptimize(i += 230); },
+            [&](const BCA*) { ::benchmark::DoNotOptimize(i += 250); },
+            [&](const BCB*) { ::benchmark::DoNotOptimize(i += 260); },
+            [&](const BCC*) { ::benchmark::DoNotOptimize(i += 270); },
+            [&](const CA*) { ::benchmark::DoNotOptimize(i += 290); },
+            [&](const CAA*) { ::benchmark::DoNotOptimize(i += 300); },
+            [&](const CAB*) { ::benchmark::DoNotOptimize(i += 310); },
+            [&](const CAC*) { ::benchmark::DoNotOptimize(i += 320); },
+            [&](const CBA*) { ::benchmark::DoNotOptimize(i += 340); },
+            [&](const CBB*) { ::benchmark::DoNotOptimize(i += 350); },
+            [&](const CBC*) { ::benchmark::DoNotOptimize(i += 360); },
+            [&](const CCA*) { ::benchmark::DoNotOptimize(i += 380); },
+            [&](const CCB*) { ::benchmark::DoNotOptimize(i += 390); },
+            [&](const CCC*) { ::benchmark::DoNotOptimize(i += 400); },
+            [&](Default) { ::benchmark::DoNotOptimize(i += 123); });
+        i = (i * 31) ^ (i << 5);
+    }
 }
 
 BENCHMARK(CastableLargeSwitch);
 
 void CastableMediumSwitch(::benchmark::State& state) {
-  auto objects = MakeObjects();
-  size_t i = 0;
-  for (auto _ : state) {
-    auto* object = objects[i % objects.size()].get();
-    Switch(
-        object,  //
-        [&](const ACB*) { ::benchmark::DoNotOptimize(i += 130); },
-        [&](const BAA*) { ::benchmark::DoNotOptimize(i += 170); },
-        [&](const BAB*) { ::benchmark::DoNotOptimize(i += 180); },
-        [&](const BBA*) { ::benchmark::DoNotOptimize(i += 210); },
-        [&](const BBB*) { ::benchmark::DoNotOptimize(i += 220); },
-        [&](const CAA*) { ::benchmark::DoNotOptimize(i += 300); },
-        [&](const CCA*) { ::benchmark::DoNotOptimize(i += 380); },
-        [&](const CCB*) { ::benchmark::DoNotOptimize(i += 390); },
-        [&](const CCC*) { ::benchmark::DoNotOptimize(i += 400); },
-        [&](Default) { ::benchmark::DoNotOptimize(i += 123); });
-    i = (i * 31) ^ (i << 5);
-  }
+    auto objects = MakeObjects();
+    size_t i = 0;
+    for (auto _ : state) {
+        auto* object = objects[i % objects.size()].get();
+        Switch(
+            object,  //
+            [&](const ACB*) { ::benchmark::DoNotOptimize(i += 130); },
+            [&](const BAA*) { ::benchmark::DoNotOptimize(i += 170); },
+            [&](const BAB*) { ::benchmark::DoNotOptimize(i += 180); },
+            [&](const BBA*) { ::benchmark::DoNotOptimize(i += 210); },
+            [&](const BBB*) { ::benchmark::DoNotOptimize(i += 220); },
+            [&](const CAA*) { ::benchmark::DoNotOptimize(i += 300); },
+            [&](const CCA*) { ::benchmark::DoNotOptimize(i += 380); },
+            [&](const CCB*) { ::benchmark::DoNotOptimize(i += 390); },
+            [&](const CCC*) { ::benchmark::DoNotOptimize(i += 400); },
+            [&](Default) { ::benchmark::DoNotOptimize(i += 123); });
+        i = (i * 31) ^ (i << 5);
+    }
 }
 
 BENCHMARK(CastableMediumSwitch);
 
 void CastableSmallSwitch(::benchmark::State& state) {
-  auto objects = MakeObjects();
-  size_t i = 0;
-  for (auto _ : state) {
-    auto* object = objects[i % objects.size()].get();
-    Switch(
-        object,  //
-        [&](const AAB*) { ::benchmark::DoNotOptimize(i += 30); },
-        [&](const CAC*) { ::benchmark::DoNotOptimize(i += 290); },
-        [&](const CAA*) { ::benchmark::DoNotOptimize(i += 300); });
-    i = (i * 31) ^ (i << 5);
-  }
+    auto objects = MakeObjects();
+    size_t i = 0;
+    for (auto _ : state) {
+        auto* object = objects[i % objects.size()].get();
+        Switch(
+            object,  //
+            [&](const AAB*) { ::benchmark::DoNotOptimize(i += 30); },
+            [&](const CAC*) { ::benchmark::DoNotOptimize(i += 290); },
+            [&](const CAA*) { ::benchmark::DoNotOptimize(i += 300); });
+        i = (i * 31) ^ (i << 5);
+    }
 }
 
 BENCHMARK(CastableSmallSwitch);
diff --git a/src/tint/castable_test.cc b/src/tint/castable_test.cc
index 7ed66cb..52efd80 100644
--- a/src/tint/castable_test.cc
+++ b/src/tint/castable_test.cc
@@ -34,684 +34,706 @@
 namespace {
 
 TEST(CastableBase, Is) {
-  std::unique_ptr<CastableBase> frog = std::make_unique<Frog>();
-  std::unique_ptr<CastableBase> bear = std::make_unique<Bear>();
-  std::unique_ptr<CastableBase> gecko = std::make_unique<Gecko>();
+    std::unique_ptr<CastableBase> frog = std::make_unique<Frog>();
+    std::unique_ptr<CastableBase> bear = std::make_unique<Bear>();
+    std::unique_ptr<CastableBase> gecko = std::make_unique<Gecko>();
 
-  ASSERT_TRUE(frog->Is<Animal>());
-  ASSERT_TRUE(bear->Is<Animal>());
-  ASSERT_TRUE(gecko->Is<Animal>());
+    ASSERT_TRUE(frog->Is<Animal>());
+    ASSERT_TRUE(bear->Is<Animal>());
+    ASSERT_TRUE(gecko->Is<Animal>());
 
-  ASSERT_TRUE(frog->Is<Amphibian>());
-  ASSERT_FALSE(bear->Is<Amphibian>());
-  ASSERT_FALSE(gecko->Is<Amphibian>());
+    ASSERT_TRUE(frog->Is<Amphibian>());
+    ASSERT_FALSE(bear->Is<Amphibian>());
+    ASSERT_FALSE(gecko->Is<Amphibian>());
 
-  ASSERT_FALSE(frog->Is<Mammal>());
-  ASSERT_TRUE(bear->Is<Mammal>());
-  ASSERT_FALSE(gecko->Is<Mammal>());
+    ASSERT_FALSE(frog->Is<Mammal>());
+    ASSERT_TRUE(bear->Is<Mammal>());
+    ASSERT_FALSE(gecko->Is<Mammal>());
 
-  ASSERT_FALSE(frog->Is<Reptile>());
-  ASSERT_FALSE(bear->Is<Reptile>());
-  ASSERT_TRUE(gecko->Is<Reptile>());
+    ASSERT_FALSE(frog->Is<Reptile>());
+    ASSERT_FALSE(bear->Is<Reptile>());
+    ASSERT_TRUE(gecko->Is<Reptile>());
 }
 
 TEST(CastableBase, Is_kDontErrorOnImpossibleCast) {
-  // Unlike TEST(CastableBase, Is), we're dynamically querying [A -> B] without
-  // going via CastableBase.
-  auto frog = std::make_unique<Frog>();
-  auto bear = std::make_unique<Bear>();
-  auto gecko = std::make_unique<Gecko>();
+    // Unlike TEST(CastableBase, Is), we're dynamically querying [A -> B] without
+    // going via CastableBase.
+    auto frog = std::make_unique<Frog>();
+    auto bear = std::make_unique<Bear>();
+    auto gecko = std::make_unique<Gecko>();
 
-  ASSERT_TRUE((frog->Is<Animal, kDontErrorOnImpossibleCast>()));
-  ASSERT_TRUE((bear->Is<Animal, kDontErrorOnImpossibleCast>()));
-  ASSERT_TRUE((gecko->Is<Animal, kDontErrorOnImpossibleCast>()));
+    ASSERT_TRUE((frog->Is<Animal, kDontErrorOnImpossibleCast>()));
+    ASSERT_TRUE((bear->Is<Animal, kDontErrorOnImpossibleCast>()));
+    ASSERT_TRUE((gecko->Is<Animal, kDontErrorOnImpossibleCast>()));
 
-  ASSERT_TRUE((frog->Is<Amphibian, kDontErrorOnImpossibleCast>()));
-  ASSERT_FALSE((bear->Is<Amphibian, kDontErrorOnImpossibleCast>()));
-  ASSERT_FALSE((gecko->Is<Amphibian, kDontErrorOnImpossibleCast>()));
+    ASSERT_TRUE((frog->Is<Amphibian, kDontErrorOnImpossibleCast>()));
+    ASSERT_FALSE((bear->Is<Amphibian, kDontErrorOnImpossibleCast>()));
+    ASSERT_FALSE((gecko->Is<Amphibian, kDontErrorOnImpossibleCast>()));
 
-  ASSERT_FALSE((frog->Is<Mammal, kDontErrorOnImpossibleCast>()));
-  ASSERT_TRUE((bear->Is<Mammal, kDontErrorOnImpossibleCast>()));
-  ASSERT_FALSE((gecko->Is<Mammal, kDontErrorOnImpossibleCast>()));
+    ASSERT_FALSE((frog->Is<Mammal, kDontErrorOnImpossibleCast>()));
+    ASSERT_TRUE((bear->Is<Mammal, kDontErrorOnImpossibleCast>()));
+    ASSERT_FALSE((gecko->Is<Mammal, kDontErrorOnImpossibleCast>()));
 
-  ASSERT_FALSE((frog->Is<Reptile, kDontErrorOnImpossibleCast>()));
-  ASSERT_FALSE((bear->Is<Reptile, kDontErrorOnImpossibleCast>()));
-  ASSERT_TRUE((gecko->Is<Reptile, kDontErrorOnImpossibleCast>()));
+    ASSERT_FALSE((frog->Is<Reptile, kDontErrorOnImpossibleCast>()));
+    ASSERT_FALSE((bear->Is<Reptile, kDontErrorOnImpossibleCast>()));
+    ASSERT_TRUE((gecko->Is<Reptile, kDontErrorOnImpossibleCast>()));
 }
 
 TEST(CastableBase, IsWithPredicate) {
-  std::unique_ptr<CastableBase> frog = std::make_unique<Frog>();
+    std::unique_ptr<CastableBase> frog = std::make_unique<Frog>();
 
-  frog->Is<Animal>([&frog](const Animal* a) {
-    EXPECT_EQ(a, frog.get());
-    return true;
-  });
+    frog->Is<Animal>([&frog](const Animal* a) {
+        EXPECT_EQ(a, frog.get());
+        return true;
+    });
 
-  ASSERT_TRUE((frog->Is<Animal>([](const Animal*) { return true; })));
-  ASSERT_FALSE((frog->Is<Animal>([](const Animal*) { return false; })));
+    ASSERT_TRUE((frog->Is<Animal>([](const Animal*) { return true; })));
+    ASSERT_FALSE((frog->Is<Animal>([](const Animal*) { return false; })));
 
-  // Predicate not called if cast is invalid
-  auto expect_not_called = [] { FAIL() << "Should not be called"; };
-  ASSERT_FALSE((frog->Is<Bear>([&](const Animal*) {
-    expect_not_called();
-    return true;
-  })));
+    // Predicate not called if cast is invalid
+    auto expect_not_called = [] { FAIL() << "Should not be called"; };
+    ASSERT_FALSE((frog->Is<Bear>([&](const Animal*) {
+        expect_not_called();
+        return true;
+    })));
 }
 
 TEST(CastableBase, IsAnyOf) {
-  std::unique_ptr<CastableBase> frog = std::make_unique<Frog>();
-  std::unique_ptr<CastableBase> bear = std::make_unique<Bear>();
-  std::unique_ptr<CastableBase> gecko = std::make_unique<Gecko>();
+    std::unique_ptr<CastableBase> frog = std::make_unique<Frog>();
+    std::unique_ptr<CastableBase> bear = std::make_unique<Bear>();
+    std::unique_ptr<CastableBase> gecko = std::make_unique<Gecko>();
 
-  ASSERT_TRUE((frog->IsAnyOf<Animal, Mammal, Amphibian, Reptile>()));
-  ASSERT_TRUE((frog->IsAnyOf<Mammal, Amphibian>()));
-  ASSERT_TRUE((frog->IsAnyOf<Amphibian, Reptile>()));
-  ASSERT_FALSE((frog->IsAnyOf<Mammal, Reptile>()));
+    ASSERT_TRUE((frog->IsAnyOf<Animal, Mammal, Amphibian, Reptile>()));
+    ASSERT_TRUE((frog->IsAnyOf<Mammal, Amphibian>()));
+    ASSERT_TRUE((frog->IsAnyOf<Amphibian, Reptile>()));
+    ASSERT_FALSE((frog->IsAnyOf<Mammal, Reptile>()));
 
-  ASSERT_TRUE((bear->IsAnyOf<Animal, Mammal, Amphibian, Reptile>()));
-  ASSERT_TRUE((bear->IsAnyOf<Mammal, Amphibian>()));
-  ASSERT_TRUE((bear->IsAnyOf<Mammal, Reptile>()));
-  ASSERT_FALSE((bear->IsAnyOf<Amphibian, Reptile>()));
+    ASSERT_TRUE((bear->IsAnyOf<Animal, Mammal, Amphibian, Reptile>()));
+    ASSERT_TRUE((bear->IsAnyOf<Mammal, Amphibian>()));
+    ASSERT_TRUE((bear->IsAnyOf<Mammal, Reptile>()));
+    ASSERT_FALSE((bear->IsAnyOf<Amphibian, Reptile>()));
 
-  ASSERT_TRUE((gecko->IsAnyOf<Animal, Mammal, Amphibian, Reptile>()));
-  ASSERT_TRUE((gecko->IsAnyOf<Mammal, Reptile>()));
-  ASSERT_TRUE((gecko->IsAnyOf<Amphibian, Reptile>()));
-  ASSERT_FALSE((gecko->IsAnyOf<Mammal, Amphibian>()));
+    ASSERT_TRUE((gecko->IsAnyOf<Animal, Mammal, Amphibian, Reptile>()));
+    ASSERT_TRUE((gecko->IsAnyOf<Mammal, Reptile>()));
+    ASSERT_TRUE((gecko->IsAnyOf<Amphibian, Reptile>()));
+    ASSERT_FALSE((gecko->IsAnyOf<Mammal, Amphibian>()));
 }
 
 TEST(CastableBase, As) {
-  std::unique_ptr<CastableBase> frog = std::make_unique<Frog>();
-  std::unique_ptr<CastableBase> bear = std::make_unique<Bear>();
-  std::unique_ptr<CastableBase> gecko = std::make_unique<Gecko>();
+    std::unique_ptr<CastableBase> frog = std::make_unique<Frog>();
+    std::unique_ptr<CastableBase> bear = std::make_unique<Bear>();
+    std::unique_ptr<CastableBase> gecko = std::make_unique<Gecko>();
 
-  ASSERT_EQ(frog->As<Animal>(), static_cast<Animal*>(frog.get()));
-  ASSERT_EQ(bear->As<Animal>(), static_cast<Animal*>(bear.get()));
-  ASSERT_EQ(gecko->As<Animal>(), static_cast<Animal*>(gecko.get()));
+    ASSERT_EQ(frog->As<Animal>(), static_cast<Animal*>(frog.get()));
+    ASSERT_EQ(bear->As<Animal>(), static_cast<Animal*>(bear.get()));
+    ASSERT_EQ(gecko->As<Animal>(), static_cast<Animal*>(gecko.get()));
 
-  ASSERT_EQ(frog->As<Amphibian>(), static_cast<Amphibian*>(frog.get()));
-  ASSERT_EQ(bear->As<Amphibian>(), nullptr);
-  ASSERT_EQ(gecko->As<Amphibian>(), nullptr);
+    ASSERT_EQ(frog->As<Amphibian>(), static_cast<Amphibian*>(frog.get()));
+    ASSERT_EQ(bear->As<Amphibian>(), nullptr);
+    ASSERT_EQ(gecko->As<Amphibian>(), nullptr);
 
-  ASSERT_EQ(frog->As<Mammal>(), nullptr);
-  ASSERT_EQ(bear->As<Mammal>(), static_cast<Mammal*>(bear.get()));
-  ASSERT_EQ(gecko->As<Mammal>(), nullptr);
+    ASSERT_EQ(frog->As<Mammal>(), nullptr);
+    ASSERT_EQ(bear->As<Mammal>(), static_cast<Mammal*>(bear.get()));
+    ASSERT_EQ(gecko->As<Mammal>(), nullptr);
 
-  ASSERT_EQ(frog->As<Reptile>(), nullptr);
-  ASSERT_EQ(bear->As<Reptile>(), nullptr);
-  ASSERT_EQ(gecko->As<Reptile>(), static_cast<Reptile*>(gecko.get()));
+    ASSERT_EQ(frog->As<Reptile>(), nullptr);
+    ASSERT_EQ(bear->As<Reptile>(), nullptr);
+    ASSERT_EQ(gecko->As<Reptile>(), static_cast<Reptile*>(gecko.get()));
 }
 
 TEST(CastableBase, As_kDontErrorOnImpossibleCast) {
-  // Unlike TEST(CastableBase, As), we're dynamically casting [A -> B] without
-  // going via CastableBase.
-  auto frog = std::make_unique<Frog>();
-  auto bear = std::make_unique<Bear>();
-  auto gecko = std::make_unique<Gecko>();
+    // Unlike TEST(CastableBase, As), we're dynamically casting [A -> B] without
+    // going via CastableBase.
+    auto frog = std::make_unique<Frog>();
+    auto bear = std::make_unique<Bear>();
+    auto gecko = std::make_unique<Gecko>();
 
-  ASSERT_EQ((frog->As<Animal, kDontErrorOnImpossibleCast>()),
-            static_cast<Animal*>(frog.get()));
-  ASSERT_EQ((bear->As<Animal, kDontErrorOnImpossibleCast>()),
-            static_cast<Animal*>(bear.get()));
-  ASSERT_EQ((gecko->As<Animal, kDontErrorOnImpossibleCast>()),
-            static_cast<Animal*>(gecko.get()));
+    ASSERT_EQ((frog->As<Animal, kDontErrorOnImpossibleCast>()), static_cast<Animal*>(frog.get()));
+    ASSERT_EQ((bear->As<Animal, kDontErrorOnImpossibleCast>()), static_cast<Animal*>(bear.get()));
+    ASSERT_EQ((gecko->As<Animal, kDontErrorOnImpossibleCast>()), static_cast<Animal*>(gecko.get()));
 
-  ASSERT_EQ((frog->As<Amphibian, kDontErrorOnImpossibleCast>()),
-            static_cast<Amphibian*>(frog.get()));
-  ASSERT_EQ((bear->As<Amphibian, kDontErrorOnImpossibleCast>()), nullptr);
-  ASSERT_EQ((gecko->As<Amphibian, kDontErrorOnImpossibleCast>()), nullptr);
+    ASSERT_EQ((frog->As<Amphibian, kDontErrorOnImpossibleCast>()),
+              static_cast<Amphibian*>(frog.get()));
+    ASSERT_EQ((bear->As<Amphibian, kDontErrorOnImpossibleCast>()), nullptr);
+    ASSERT_EQ((gecko->As<Amphibian, kDontErrorOnImpossibleCast>()), nullptr);
 
-  ASSERT_EQ((frog->As<Mammal, kDontErrorOnImpossibleCast>()), nullptr);
-  ASSERT_EQ((bear->As<Mammal, kDontErrorOnImpossibleCast>()),
-            static_cast<Mammal*>(bear.get()));
-  ASSERT_EQ((gecko->As<Mammal, kDontErrorOnImpossibleCast>()), nullptr);
+    ASSERT_EQ((frog->As<Mammal, kDontErrorOnImpossibleCast>()), nullptr);
+    ASSERT_EQ((bear->As<Mammal, kDontErrorOnImpossibleCast>()), static_cast<Mammal*>(bear.get()));
+    ASSERT_EQ((gecko->As<Mammal, kDontErrorOnImpossibleCast>()), nullptr);
 
-  ASSERT_EQ((frog->As<Reptile, kDontErrorOnImpossibleCast>()), nullptr);
-  ASSERT_EQ((bear->As<Reptile, kDontErrorOnImpossibleCast>()), nullptr);
-  ASSERT_EQ((gecko->As<Reptile, kDontErrorOnImpossibleCast>()),
-            static_cast<Reptile*>(gecko.get()));
+    ASSERT_EQ((frog->As<Reptile, kDontErrorOnImpossibleCast>()), nullptr);
+    ASSERT_EQ((bear->As<Reptile, kDontErrorOnImpossibleCast>()), nullptr);
+    ASSERT_EQ((gecko->As<Reptile, kDontErrorOnImpossibleCast>()),
+              static_cast<Reptile*>(gecko.get()));
 }
 
 TEST(Castable, Is) {
-  std::unique_ptr<Animal> frog = std::make_unique<Frog>();
-  std::unique_ptr<Animal> bear = std::make_unique<Bear>();
-  std::unique_ptr<Animal> gecko = std::make_unique<Gecko>();
+    std::unique_ptr<Animal> frog = std::make_unique<Frog>();
+    std::unique_ptr<Animal> bear = std::make_unique<Bear>();
+    std::unique_ptr<Animal> gecko = std::make_unique<Gecko>();
 
-  ASSERT_TRUE(frog->Is<Animal>());
-  ASSERT_TRUE(bear->Is<Animal>());
-  ASSERT_TRUE(gecko->Is<Animal>());
+    ASSERT_TRUE(frog->Is<Animal>());
+    ASSERT_TRUE(bear->Is<Animal>());
+    ASSERT_TRUE(gecko->Is<Animal>());
 
-  ASSERT_TRUE(frog->Is<Amphibian>());
-  ASSERT_FALSE(bear->Is<Amphibian>());
-  ASSERT_FALSE(gecko->Is<Amphibian>());
+    ASSERT_TRUE(frog->Is<Amphibian>());
+    ASSERT_FALSE(bear->Is<Amphibian>());
+    ASSERT_FALSE(gecko->Is<Amphibian>());
 
-  ASSERT_FALSE(frog->Is<Mammal>());
-  ASSERT_TRUE(bear->Is<Mammal>());
-  ASSERT_FALSE(gecko->Is<Mammal>());
+    ASSERT_FALSE(frog->Is<Mammal>());
+    ASSERT_TRUE(bear->Is<Mammal>());
+    ASSERT_FALSE(gecko->Is<Mammal>());
 
-  ASSERT_FALSE(frog->Is<Reptile>());
-  ASSERT_FALSE(bear->Is<Reptile>());
-  ASSERT_TRUE(gecko->Is<Reptile>());
+    ASSERT_FALSE(frog->Is<Reptile>());
+    ASSERT_FALSE(bear->Is<Reptile>());
+    ASSERT_TRUE(gecko->Is<Reptile>());
 }
 
 TEST(Castable, IsWithPredicate) {
-  std::unique_ptr<Animal> frog = std::make_unique<Frog>();
+    std::unique_ptr<Animal> frog = std::make_unique<Frog>();
 
-  frog->Is([&frog](const Animal* a) {
-    EXPECT_EQ(a, frog.get());
-    return true;
-  });
+    frog->Is([&frog](const Animal* a) {
+        EXPECT_EQ(a, frog.get());
+        return true;
+    });
 
-  ASSERT_TRUE((frog->Is([](const Animal*) { return true; })));
-  ASSERT_FALSE((frog->Is([](const Animal*) { return false; })));
+    ASSERT_TRUE((frog->Is([](const Animal*) { return true; })));
+    ASSERT_FALSE((frog->Is([](const Animal*) { return false; })));
 
-  // Predicate not called if cast is invalid
-  auto expect_not_called = [] { FAIL() << "Should not be called"; };
-  ASSERT_FALSE((frog->Is([&](const Bear*) {
-    expect_not_called();
-    return true;
-  })));
+    // Predicate not called if cast is invalid
+    auto expect_not_called = [] { FAIL() << "Should not be called"; };
+    ASSERT_FALSE((frog->Is([&](const Bear*) {
+        expect_not_called();
+        return true;
+    })));
 }
 
 TEST(Castable, As) {
-  std::unique_ptr<Animal> frog = std::make_unique<Frog>();
-  std::unique_ptr<Animal> bear = std::make_unique<Bear>();
-  std::unique_ptr<Animal> gecko = std::make_unique<Gecko>();
+    std::unique_ptr<Animal> frog = std::make_unique<Frog>();
+    std::unique_ptr<Animal> bear = std::make_unique<Bear>();
+    std::unique_ptr<Animal> gecko = std::make_unique<Gecko>();
 
-  ASSERT_EQ(frog->As<Animal>(), static_cast<Animal*>(frog.get()));
-  ASSERT_EQ(bear->As<Animal>(), static_cast<Animal*>(bear.get()));
-  ASSERT_EQ(gecko->As<Animal>(), static_cast<Animal*>(gecko.get()));
+    ASSERT_EQ(frog->As<Animal>(), static_cast<Animal*>(frog.get()));
+    ASSERT_EQ(bear->As<Animal>(), static_cast<Animal*>(bear.get()));
+    ASSERT_EQ(gecko->As<Animal>(), static_cast<Animal*>(gecko.get()));
 
-  ASSERT_EQ(frog->As<Amphibian>(), static_cast<Amphibian*>(frog.get()));
-  ASSERT_EQ(bear->As<Amphibian>(), nullptr);
-  ASSERT_EQ(gecko->As<Amphibian>(), nullptr);
+    ASSERT_EQ(frog->As<Amphibian>(), static_cast<Amphibian*>(frog.get()));
+    ASSERT_EQ(bear->As<Amphibian>(), nullptr);
+    ASSERT_EQ(gecko->As<Amphibian>(), nullptr);
 
-  ASSERT_EQ(frog->As<Mammal>(), nullptr);
-  ASSERT_EQ(bear->As<Mammal>(), static_cast<Mammal*>(bear.get()));
-  ASSERT_EQ(gecko->As<Mammal>(), nullptr);
+    ASSERT_EQ(frog->As<Mammal>(), nullptr);
+    ASSERT_EQ(bear->As<Mammal>(), static_cast<Mammal*>(bear.get()));
+    ASSERT_EQ(gecko->As<Mammal>(), nullptr);
 
-  ASSERT_EQ(frog->As<Reptile>(), nullptr);
-  ASSERT_EQ(bear->As<Reptile>(), nullptr);
-  ASSERT_EQ(gecko->As<Reptile>(), static_cast<Reptile*>(gecko.get()));
+    ASSERT_EQ(frog->As<Reptile>(), nullptr);
+    ASSERT_EQ(bear->As<Reptile>(), nullptr);
+    ASSERT_EQ(gecko->As<Reptile>(), static_cast<Reptile*>(gecko.get()));
 }
 
 TEST(Castable, SwitchNoDefault) {
-  std::unique_ptr<Animal> frog = std::make_unique<Frog>();
-  std::unique_ptr<Animal> bear = std::make_unique<Bear>();
-  std::unique_ptr<Animal> gecko = std::make_unique<Gecko>();
-  {
-    bool frog_matched_amphibian = false;
-    Switch(
-        frog.get(),  //
-        [&](Reptile*) { FAIL() << "frog is not reptile"; },
-        [&](Mammal*) { FAIL() << "frog is not mammal"; },
-        [&](Amphibian* amphibian) {
-          EXPECT_EQ(amphibian, frog.get());
-          frog_matched_amphibian = true;
-        });
-    EXPECT_TRUE(frog_matched_amphibian);
-  }
-  {
-    bool bear_matched_mammal = false;
-    Switch(
-        bear.get(),  //
-        [&](Reptile*) { FAIL() << "bear is not reptile"; },
-        [&](Amphibian*) { FAIL() << "bear is not amphibian"; },
-        [&](Mammal* mammal) {
-          EXPECT_EQ(mammal, bear.get());
-          bear_matched_mammal = true;
-        });
-    EXPECT_TRUE(bear_matched_mammal);
-  }
-  {
-    bool gecko_matched_reptile = false;
-    Switch(
-        gecko.get(),  //
-        [&](Mammal*) { FAIL() << "gecko is not mammal"; },
-        [&](Amphibian*) { FAIL() << "gecko is not amphibian"; },
-        [&](Reptile* reptile) {
-          EXPECT_EQ(reptile, gecko.get());
-          gecko_matched_reptile = true;
-        });
-    EXPECT_TRUE(gecko_matched_reptile);
-  }
+    std::unique_ptr<Animal> frog = std::make_unique<Frog>();
+    std::unique_ptr<Animal> bear = std::make_unique<Bear>();
+    std::unique_ptr<Animal> gecko = std::make_unique<Gecko>();
+    {
+        bool frog_matched_amphibian = false;
+        Switch(
+            frog.get(),  //
+            [&](Reptile*) { FAIL() << "frog is not reptile"; },
+            [&](Mammal*) { FAIL() << "frog is not mammal"; },
+            [&](Amphibian* amphibian) {
+                EXPECT_EQ(amphibian, frog.get());
+                frog_matched_amphibian = true;
+            });
+        EXPECT_TRUE(frog_matched_amphibian);
+    }
+    {
+        bool bear_matched_mammal = false;
+        Switch(
+            bear.get(),  //
+            [&](Reptile*) { FAIL() << "bear is not reptile"; },
+            [&](Amphibian*) { FAIL() << "bear is not amphibian"; },
+            [&](Mammal* mammal) {
+                EXPECT_EQ(mammal, bear.get());
+                bear_matched_mammal = true;
+            });
+        EXPECT_TRUE(bear_matched_mammal);
+    }
+    {
+        bool gecko_matched_reptile = false;
+        Switch(
+            gecko.get(),  //
+            [&](Mammal*) { FAIL() << "gecko is not mammal"; },
+            [&](Amphibian*) { FAIL() << "gecko is not amphibian"; },
+            [&](Reptile* reptile) {
+                EXPECT_EQ(reptile, gecko.get());
+                gecko_matched_reptile = true;
+            });
+        EXPECT_TRUE(gecko_matched_reptile);
+    }
 }
 
 TEST(Castable, SwitchWithUnusedDefault) {
-  std::unique_ptr<Animal> frog = std::make_unique<Frog>();
-  std::unique_ptr<Animal> bear = std::make_unique<Bear>();
-  std::unique_ptr<Animal> gecko = std::make_unique<Gecko>();
-  {
-    bool frog_matched_amphibian = false;
-    Switch(
-        frog.get(),  //
-        [&](Reptile*) { FAIL() << "frog is not reptile"; },
-        [&](Mammal*) { FAIL() << "frog is not mammal"; },
-        [&](Amphibian* amphibian) {
-          EXPECT_EQ(amphibian, frog.get());
-          frog_matched_amphibian = true;
-        },
-        [&](Default) { FAIL() << "default should not have been selected"; });
-    EXPECT_TRUE(frog_matched_amphibian);
-  }
-  {
-    bool bear_matched_mammal = false;
-    Switch(
-        bear.get(),  //
-        [&](Reptile*) { FAIL() << "bear is not reptile"; },
-        [&](Amphibian*) { FAIL() << "bear is not amphibian"; },
-        [&](Mammal* mammal) {
-          EXPECT_EQ(mammal, bear.get());
-          bear_matched_mammal = true;
-        },
-        [&](Default) { FAIL() << "default should not have been selected"; });
-    EXPECT_TRUE(bear_matched_mammal);
-  }
-  {
-    bool gecko_matched_reptile = false;
-    Switch(
-        gecko.get(),  //
-        [&](Mammal*) { FAIL() << "gecko is not mammal"; },
-        [&](Amphibian*) { FAIL() << "gecko is not amphibian"; },
-        [&](Reptile* reptile) {
-          EXPECT_EQ(reptile, gecko.get());
-          gecko_matched_reptile = true;
-        },
-        [&](Default) { FAIL() << "default should not have been selected"; });
-    EXPECT_TRUE(gecko_matched_reptile);
-  }
+    std::unique_ptr<Animal> frog = std::make_unique<Frog>();
+    std::unique_ptr<Animal> bear = std::make_unique<Bear>();
+    std::unique_ptr<Animal> gecko = std::make_unique<Gecko>();
+    {
+        bool frog_matched_amphibian = false;
+        Switch(
+            frog.get(),  //
+            [&](Reptile*) { FAIL() << "frog is not reptile"; },
+            [&](Mammal*) { FAIL() << "frog is not mammal"; },
+            [&](Amphibian* amphibian) {
+                EXPECT_EQ(amphibian, frog.get());
+                frog_matched_amphibian = true;
+            },
+            [&](Default) { FAIL() << "default should not have been selected"; });
+        EXPECT_TRUE(frog_matched_amphibian);
+    }
+    {
+        bool bear_matched_mammal = false;
+        Switch(
+            bear.get(),  //
+            [&](Reptile*) { FAIL() << "bear is not reptile"; },
+            [&](Amphibian*) { FAIL() << "bear is not amphibian"; },
+            [&](Mammal* mammal) {
+                EXPECT_EQ(mammal, bear.get());
+                bear_matched_mammal = true;
+            },
+            [&](Default) { FAIL() << "default should not have been selected"; });
+        EXPECT_TRUE(bear_matched_mammal);
+    }
+    {
+        bool gecko_matched_reptile = false;
+        Switch(
+            gecko.get(),  //
+            [&](Mammal*) { FAIL() << "gecko is not mammal"; },
+            [&](Amphibian*) { FAIL() << "gecko is not amphibian"; },
+            [&](Reptile* reptile) {
+                EXPECT_EQ(reptile, gecko.get());
+                gecko_matched_reptile = true;
+            },
+            [&](Default) { FAIL() << "default should not have been selected"; });
+        EXPECT_TRUE(gecko_matched_reptile);
+    }
 }
 
 TEST(Castable, SwitchDefault) {
-  std::unique_ptr<Animal> frog = std::make_unique<Frog>();
-  std::unique_ptr<Animal> bear = std::make_unique<Bear>();
-  std::unique_ptr<Animal> gecko = std::make_unique<Gecko>();
-  {
-    bool frog_matched_default = false;
-    Switch(
-        frog.get(),  //
-        [&](Reptile*) { FAIL() << "frog is not reptile"; },
-        [&](Mammal*) { FAIL() << "frog is not mammal"; },
-        [&](Default) { frog_matched_default = true; });
-    EXPECT_TRUE(frog_matched_default);
-  }
-  {
-    bool bear_matched_default = false;
-    Switch(
-        bear.get(),  //
-        [&](Reptile*) { FAIL() << "bear is not reptile"; },
-        [&](Amphibian*) { FAIL() << "bear is not amphibian"; },
-        [&](Default) { bear_matched_default = true; });
-    EXPECT_TRUE(bear_matched_default);
-  }
-  {
-    bool gecko_matched_default = false;
-    Switch(
-        gecko.get(),  //
-        [&](Mammal*) { FAIL() << "gecko is not mammal"; },
-        [&](Amphibian*) { FAIL() << "gecko is not amphibian"; },
-        [&](Default) { gecko_matched_default = true; });
-    EXPECT_TRUE(gecko_matched_default);
-  }
+    std::unique_ptr<Animal> frog = std::make_unique<Frog>();
+    std::unique_ptr<Animal> bear = std::make_unique<Bear>();
+    std::unique_ptr<Animal> gecko = std::make_unique<Gecko>();
+    {
+        bool frog_matched_default = false;
+        Switch(
+            frog.get(),  //
+            [&](Reptile*) { FAIL() << "frog is not reptile"; },
+            [&](Mammal*) { FAIL() << "frog is not mammal"; },
+            [&](Default) { frog_matched_default = true; });
+        EXPECT_TRUE(frog_matched_default);
+    }
+    {
+        bool bear_matched_default = false;
+        Switch(
+            bear.get(),  //
+            [&](Reptile*) { FAIL() << "bear is not reptile"; },
+            [&](Amphibian*) { FAIL() << "bear is not amphibian"; },
+            [&](Default) { bear_matched_default = true; });
+        EXPECT_TRUE(bear_matched_default);
+    }
+    {
+        bool gecko_matched_default = false;
+        Switch(
+            gecko.get(),  //
+            [&](Mammal*) { FAIL() << "gecko is not mammal"; },
+            [&](Amphibian*) { FAIL() << "gecko is not amphibian"; },
+            [&](Default) { gecko_matched_default = true; });
+        EXPECT_TRUE(gecko_matched_default);
+    }
 }
 
 TEST(Castable, SwitchMatchFirst) {
-  std::unique_ptr<Animal> frog = std::make_unique<Frog>();
-  {
-    bool frog_matched_animal = false;
-    Switch(
-        frog.get(),
-        [&](Animal* animal) {
-          EXPECT_EQ(animal, frog.get());
-          frog_matched_animal = true;
-        },
-        [&](Amphibian*) { FAIL() << "animal should have been matched first"; });
-    EXPECT_TRUE(frog_matched_animal);
-  }
-  {
-    bool frog_matched_amphibian = false;
-    Switch(
-        frog.get(),
-        [&](Amphibian* amphibain) {
-          EXPECT_EQ(amphibain, frog.get());
-          frog_matched_amphibian = true;
-        },
-        [&](Animal*) { FAIL() << "amphibian should have been matched first"; });
-    EXPECT_TRUE(frog_matched_amphibian);
-  }
+    std::unique_ptr<Animal> frog = std::make_unique<Frog>();
+    {
+        bool frog_matched_animal = false;
+        Switch(
+            frog.get(),
+            [&](Animal* animal) {
+                EXPECT_EQ(animal, frog.get());
+                frog_matched_animal = true;
+            },
+            [&](Amphibian*) { FAIL() << "animal should have been matched first"; });
+        EXPECT_TRUE(frog_matched_animal);
+    }
+    {
+        bool frog_matched_amphibian = false;
+        Switch(
+            frog.get(),
+            [&](Amphibian* amphibain) {
+                EXPECT_EQ(amphibain, frog.get());
+                frog_matched_amphibian = true;
+            },
+            [&](Animal*) { FAIL() << "amphibian should have been matched first"; });
+        EXPECT_TRUE(frog_matched_amphibian);
+    }
 }
 
 TEST(Castable, SwitchReturnValueWithDefault) {
-  std::unique_ptr<Animal> frog = std::make_unique<Frog>();
-  std::unique_ptr<Animal> bear = std::make_unique<Bear>();
-  std::unique_ptr<Animal> gecko = std::make_unique<Gecko>();
-  {
-    const char* result = Switch(
-        frog.get(),                              //
-        [](Mammal*) { return "mammal"; },        //
-        [](Amphibian*) { return "amphibian"; },  //
-        [](Default) { return "unknown"; });
-    static_assert(std::is_same_v<decltype(result), const char*>);
-    EXPECT_EQ(std::string(result), "amphibian");
-  }
-  {
-    const char* result = Switch(
-        bear.get(),                              //
-        [](Mammal*) { return "mammal"; },        //
-        [](Amphibian*) { return "amphibian"; },  //
-        [](Default) { return "unknown"; });
-    static_assert(std::is_same_v<decltype(result), const char*>);
-    EXPECT_EQ(std::string(result), "mammal");
-  }
-  {
-    const char* result = Switch(
-        gecko.get(),                             //
-        [](Mammal*) { return "mammal"; },        //
-        [](Amphibian*) { return "amphibian"; },  //
-        [](Default) { return "unknown"; });
-    static_assert(std::is_same_v<decltype(result), const char*>);
-    EXPECT_EQ(std::string(result), "unknown");
-  }
+    std::unique_ptr<Animal> frog = std::make_unique<Frog>();
+    std::unique_ptr<Animal> bear = std::make_unique<Bear>();
+    std::unique_ptr<Animal> gecko = std::make_unique<Gecko>();
+    {
+        const char* result = Switch(
+            frog.get(),                              //
+            [](Mammal*) { return "mammal"; },        //
+            [](Amphibian*) { return "amphibian"; },  //
+            [](Default) { return "unknown"; });
+        static_assert(std::is_same_v<decltype(result), const char*>);
+        EXPECT_EQ(std::string(result), "amphibian");
+    }
+    {
+        const char* result = Switch(
+            bear.get(),                              //
+            [](Mammal*) { return "mammal"; },        //
+            [](Amphibian*) { return "amphibian"; },  //
+            [](Default) { return "unknown"; });
+        static_assert(std::is_same_v<decltype(result), const char*>);
+        EXPECT_EQ(std::string(result), "mammal");
+    }
+    {
+        const char* result = Switch(
+            gecko.get(),                             //
+            [](Mammal*) { return "mammal"; },        //
+            [](Amphibian*) { return "amphibian"; },  //
+            [](Default) { return "unknown"; });
+        static_assert(std::is_same_v<decltype(result), const char*>);
+        EXPECT_EQ(std::string(result), "unknown");
+    }
 }
 
 TEST(Castable, SwitchReturnValueWithoutDefault) {
-  std::unique_ptr<Animal> frog = std::make_unique<Frog>();
-  std::unique_ptr<Animal> bear = std::make_unique<Bear>();
-  std::unique_ptr<Animal> gecko = std::make_unique<Gecko>();
-  {
-    const char* result = Switch(
-        frog.get(),                        //
-        [](Mammal*) { return "mammal"; },  //
-        [](Amphibian*) { return "amphibian"; });
-    static_assert(std::is_same_v<decltype(result), const char*>);
-    EXPECT_EQ(std::string(result), "amphibian");
-  }
-  {
-    const char* result = Switch(
-        bear.get(),                        //
-        [](Mammal*) { return "mammal"; },  //
-        [](Amphibian*) { return "amphibian"; });
-    static_assert(std::is_same_v<decltype(result), const char*>);
-    EXPECT_EQ(std::string(result), "mammal");
-  }
-  {
-    auto* result = Switch(
-        gecko.get(),                       //
-        [](Mammal*) { return "mammal"; },  //
-        [](Amphibian*) { return "amphibian"; });
-    static_assert(std::is_same_v<decltype(result), const char*>);
-    EXPECT_EQ(result, nullptr);
-  }
+    std::unique_ptr<Animal> frog = std::make_unique<Frog>();
+    std::unique_ptr<Animal> bear = std::make_unique<Bear>();
+    std::unique_ptr<Animal> gecko = std::make_unique<Gecko>();
+    {
+        const char* result = Switch(
+            frog.get(),                        //
+            [](Mammal*) { return "mammal"; },  //
+            [](Amphibian*) { return "amphibian"; });
+        static_assert(std::is_same_v<decltype(result), const char*>);
+        EXPECT_EQ(std::string(result), "amphibian");
+    }
+    {
+        const char* result = Switch(
+            bear.get(),                        //
+            [](Mammal*) { return "mammal"; },  //
+            [](Amphibian*) { return "amphibian"; });
+        static_assert(std::is_same_v<decltype(result), const char*>);
+        EXPECT_EQ(std::string(result), "mammal");
+    }
+    {
+        auto* result = Switch(
+            gecko.get(),                       //
+            [](Mammal*) { return "mammal"; },  //
+            [](Amphibian*) { return "amphibian"; });
+        static_assert(std::is_same_v<decltype(result), const char*>);
+        EXPECT_EQ(result, nullptr);
+    }
 }
 
 TEST(Castable, SwitchInferPODReturnTypeWithDefault) {
-  std::unique_ptr<Animal> frog = std::make_unique<Frog>();
-  std::unique_ptr<Animal> bear = std::make_unique<Bear>();
-  std::unique_ptr<Animal> gecko = std::make_unique<Gecko>();
-  {
-    auto result = Switch(
-        frog.get(),                       //
-        [](Mammal*) { return 1; },        //
-        [](Amphibian*) { return 2.0f; },  //
-        [](Default) { return 3.0; });
-    static_assert(std::is_same_v<decltype(result), double>);
-    EXPECT_EQ(result, 2.0);
-  }
-  {
-    auto result = Switch(
-        bear.get(),                       //
-        [](Mammal*) { return 1.0; },      //
-        [](Amphibian*) { return 2.0f; },  //
-        [](Default) { return 3; });
-    static_assert(std::is_same_v<decltype(result), double>);
-    EXPECT_EQ(result, 1.0);
-  }
-  {
-    auto result = Switch(
-        gecko.get(),                   //
-        [](Mammal*) { return 1.0f; },  //
-        [](Amphibian*) { return 2; },  //
-        [](Default) { return 3.0; });
-    static_assert(std::is_same_v<decltype(result), double>);
-    EXPECT_EQ(result, 3.0);
-  }
+    std::unique_ptr<Animal> frog = std::make_unique<Frog>();
+    std::unique_ptr<Animal> bear = std::make_unique<Bear>();
+    std::unique_ptr<Animal> gecko = std::make_unique<Gecko>();
+    {
+        auto result = Switch(
+            frog.get(),                       //
+            [](Mammal*) { return 1; },        //
+            [](Amphibian*) { return 2.0f; },  //
+            [](Default) { return 3.0; });
+        static_assert(std::is_same_v<decltype(result), double>);
+        EXPECT_EQ(result, 2.0);
+    }
+    {
+        auto result = Switch(
+            bear.get(),                       //
+            [](Mammal*) { return 1.0; },      //
+            [](Amphibian*) { return 2.0f; },  //
+            [](Default) { return 3; });
+        static_assert(std::is_same_v<decltype(result), double>);
+        EXPECT_EQ(result, 1.0);
+    }
+    {
+        auto result = Switch(
+            gecko.get(),                   //
+            [](Mammal*) { return 1.0f; },  //
+            [](Amphibian*) { return 2; },  //
+            [](Default) { return 3.0; });
+        static_assert(std::is_same_v<decltype(result), double>);
+        EXPECT_EQ(result, 3.0);
+    }
 }
 
 TEST(Castable, SwitchInferPODReturnTypeWithoutDefault) {
-  std::unique_ptr<Animal> frog = std::make_unique<Frog>();
-  std::unique_ptr<Animal> bear = std::make_unique<Bear>();
-  std::unique_ptr<Animal> gecko = std::make_unique<Gecko>();
-  {
-    auto result = Switch(
-        frog.get(),                 //
-        [](Mammal*) { return 1; },  //
-        [](Amphibian*) { return 2.0f; });
-    static_assert(std::is_same_v<decltype(result), float>);
-    EXPECT_EQ(result, 2.0f);
-  }
-  {
-    auto result = Switch(
-        bear.get(),                    //
-        [](Mammal*) { return 1.0f; },  //
-        [](Amphibian*) { return 2; });
-    static_assert(std::is_same_v<decltype(result), float>);
-    EXPECT_EQ(result, 1.0f);
-  }
-  {
-    auto result = Switch(
-        gecko.get(),                  //
-        [](Mammal*) { return 1.0; },  //
-        [](Amphibian*) { return 2.0f; });
-    static_assert(std::is_same_v<decltype(result), double>);
-    EXPECT_EQ(result, 0.0);
-  }
+    std::unique_ptr<Animal> frog = std::make_unique<Frog>();
+    std::unique_ptr<Animal> bear = std::make_unique<Bear>();
+    std::unique_ptr<Animal> gecko = std::make_unique<Gecko>();
+    {
+        auto result = Switch(
+            frog.get(),                 //
+            [](Mammal*) { return 1; },  //
+            [](Amphibian*) { return 2.0f; });
+        static_assert(std::is_same_v<decltype(result), float>);
+        EXPECT_EQ(result, 2.0f);
+    }
+    {
+        auto result = Switch(
+            bear.get(),                    //
+            [](Mammal*) { return 1.0f; },  //
+            [](Amphibian*) { return 2; });
+        static_assert(std::is_same_v<decltype(result), float>);
+        EXPECT_EQ(result, 1.0f);
+    }
+    {
+        auto result = Switch(
+            gecko.get(),                  //
+            [](Mammal*) { return 1.0; },  //
+            [](Amphibian*) { return 2.0f; });
+        static_assert(std::is_same_v<decltype(result), double>);
+        EXPECT_EQ(result, 0.0);
+    }
 }
 
 TEST(Castable, SwitchInferCastableReturnTypeWithDefault) {
-  std::unique_ptr<Animal> frog = std::make_unique<Frog>();
-  std::unique_ptr<Animal> bear = std::make_unique<Bear>();
-  std::unique_ptr<Animal> gecko = std::make_unique<Gecko>();
-  {
-    auto* result = Switch(
-        frog.get(),                          //
-        [](Mammal* p) { return p; },         //
-        [](Amphibian*) { return nullptr; },  //
-        [](Default) { return nullptr; });
-    static_assert(std::is_same_v<decltype(result), Mammal*>);
-    EXPECT_EQ(result, nullptr);
-  }
-  {
-    auto* result = Switch(
-        bear.get(),                   //
-        [](Mammal* p) { return p; },  //
-        [](Amphibian* p) { return const_cast<const Amphibian*>(p); },
-        [](Default) { return nullptr; });
-    static_assert(std::is_same_v<decltype(result), const Animal*>);
-    EXPECT_EQ(result, bear.get());
-  }
-  {
-    auto* result = Switch(
-        gecko.get(),                     //
-        [](Mammal* p) { return p; },     //
-        [](Amphibian* p) { return p; },  //
-        [](Default) -> CastableBase* { return nullptr; });
-    static_assert(std::is_same_v<decltype(result), CastableBase*>);
-    EXPECT_EQ(result, nullptr);
-  }
+    std::unique_ptr<Animal> frog = std::make_unique<Frog>();
+    std::unique_ptr<Animal> bear = std::make_unique<Bear>();
+    std::unique_ptr<Animal> gecko = std::make_unique<Gecko>();
+    {
+        auto* result = Switch(
+            frog.get(),                          //
+            [](Mammal* p) { return p; },         //
+            [](Amphibian*) { return nullptr; },  //
+            [](Default) { return nullptr; });
+        static_assert(std::is_same_v<decltype(result), Mammal*>);
+        EXPECT_EQ(result, nullptr);
+    }
+    {
+        auto* result = Switch(
+            bear.get(),                   //
+            [](Mammal* p) { return p; },  //
+            [](Amphibian* p) { return const_cast<const Amphibian*>(p); },
+            [](Default) { return nullptr; });
+        static_assert(std::is_same_v<decltype(result), const Animal*>);
+        EXPECT_EQ(result, bear.get());
+    }
+    {
+        auto* result = Switch(
+            gecko.get(),                     //
+            [](Mammal* p) { return p; },     //
+            [](Amphibian* p) { return p; },  //
+            [](Default) -> CastableBase* { return nullptr; });
+        static_assert(std::is_same_v<decltype(result), CastableBase*>);
+        EXPECT_EQ(result, nullptr);
+    }
 }
 
 TEST(Castable, SwitchInferCastableReturnTypeWithoutDefault) {
-  std::unique_ptr<Animal> frog = std::make_unique<Frog>();
-  std::unique_ptr<Animal> bear = std::make_unique<Bear>();
-  std::unique_ptr<Animal> gecko = std::make_unique<Gecko>();
-  {
-    auto* result = Switch(
-        frog.get(),                   //
-        [](Mammal* p) { return p; },  //
-        [](Amphibian*) { return nullptr; });
-    static_assert(std::is_same_v<decltype(result), Mammal*>);
-    EXPECT_EQ(result, nullptr);
-  }
-  {
-    auto* result = Switch(
-        bear.get(),                                                     //
-        [](Mammal* p) { return p; },                                    //
-        [](Amphibian* p) { return const_cast<const Amphibian*>(p); });  //
-    static_assert(std::is_same_v<decltype(result), const Animal*>);
-    EXPECT_EQ(result, bear.get());
-  }
-  {
-    auto* result = Switch(
-        gecko.get(),                  //
-        [](Mammal* p) { return p; },  //
-        [](Amphibian* p) { return p; });
-    static_assert(std::is_same_v<decltype(result), Animal*>);
-    EXPECT_EQ(result, nullptr);
-  }
+    std::unique_ptr<Animal> frog = std::make_unique<Frog>();
+    std::unique_ptr<Animal> bear = std::make_unique<Bear>();
+    std::unique_ptr<Animal> gecko = std::make_unique<Gecko>();
+    {
+        auto* result = Switch(
+            frog.get(),                   //
+            [](Mammal* p) { return p; },  //
+            [](Amphibian*) { return nullptr; });
+        static_assert(std::is_same_v<decltype(result), Mammal*>);
+        EXPECT_EQ(result, nullptr);
+    }
+    {
+        auto* result = Switch(
+            bear.get(),                                                     //
+            [](Mammal* p) { return p; },                                    //
+            [](Amphibian* p) { return const_cast<const Amphibian*>(p); });  //
+        static_assert(std::is_same_v<decltype(result), const Animal*>);
+        EXPECT_EQ(result, bear.get());
+    }
+    {
+        auto* result = Switch(
+            gecko.get(),                  //
+            [](Mammal* p) { return p; },  //
+            [](Amphibian* p) { return p; });
+        static_assert(std::is_same_v<decltype(result), Animal*>);
+        EXPECT_EQ(result, nullptr);
+    }
 }
 
 TEST(Castable, SwitchExplicitPODReturnTypeWithDefault) {
-  std::unique_ptr<Animal> frog = std::make_unique<Frog>();
-  std::unique_ptr<Animal> bear = std::make_unique<Bear>();
-  std::unique_ptr<Animal> gecko = std::make_unique<Gecko>();
-  {
-    auto result = Switch<double>(
-        frog.get(),                       //
-        [](Mammal*) { return 1; },        //
-        [](Amphibian*) { return 2.0f; },  //
-        [](Default) { return 3.0; });
-    static_assert(std::is_same_v<decltype(result), double>);
-    EXPECT_EQ(result, 2.0f);
-  }
-  {
-    auto result = Switch<double>(
-        bear.get(),                    //
-        [](Mammal*) { return 1; },     //
-        [](Amphibian*) { return 2; },  //
-        [](Default) { return 3; });
-    static_assert(std::is_same_v<decltype(result), double>);
-    EXPECT_EQ(result, 1.0f);
-  }
-  {
-    auto result = Switch<double>(
-        gecko.get(),                      //
-        [](Mammal*) { return 1.0f; },     //
-        [](Amphibian*) { return 2.0f; },  //
-        [](Default) { return 3.0f; });
-    static_assert(std::is_same_v<decltype(result), double>);
-    EXPECT_EQ(result, 3.0f);
-  }
+    std::unique_ptr<Animal> frog = std::make_unique<Frog>();
+    std::unique_ptr<Animal> bear = std::make_unique<Bear>();
+    std::unique_ptr<Animal> gecko = std::make_unique<Gecko>();
+    {
+        auto result = Switch<double>(
+            frog.get(),                       //
+            [](Mammal*) { return 1; },        //
+            [](Amphibian*) { return 2.0f; },  //
+            [](Default) { return 3.0; });
+        static_assert(std::is_same_v<decltype(result), double>);
+        EXPECT_EQ(result, 2.0f);
+    }
+    {
+        auto result = Switch<double>(
+            bear.get(),                    //
+            [](Mammal*) { return 1; },     //
+            [](Amphibian*) { return 2; },  //
+            [](Default) { return 3; });
+        static_assert(std::is_same_v<decltype(result), double>);
+        EXPECT_EQ(result, 1.0f);
+    }
+    {
+        auto result = Switch<double>(
+            gecko.get(),                      //
+            [](Mammal*) { return 1.0f; },     //
+            [](Amphibian*) { return 2.0f; },  //
+            [](Default) { return 3.0f; });
+        static_assert(std::is_same_v<decltype(result), double>);
+        EXPECT_EQ(result, 3.0f);
+    }
 }
 
 TEST(Castable, SwitchExplicitPODReturnTypeWithoutDefault) {
-  std::unique_ptr<Animal> frog = std::make_unique<Frog>();
-  std::unique_ptr<Animal> bear = std::make_unique<Bear>();
-  std::unique_ptr<Animal> gecko = std::make_unique<Gecko>();
-  {
-    auto result = Switch<double>(
-        frog.get(),                 //
-        [](Mammal*) { return 1; },  //
-        [](Amphibian*) { return 2.0f; });
-    static_assert(std::is_same_v<decltype(result), double>);
-    EXPECT_EQ(result, 2.0f);
-  }
-  {
-    auto result = Switch<double>(
-        bear.get(),                    //
-        [](Mammal*) { return 1.0f; },  //
-        [](Amphibian*) { return 2; });
-    static_assert(std::is_same_v<decltype(result), double>);
-    EXPECT_EQ(result, 1.0f);
-  }
-  {
-    auto result = Switch<double>(
-        gecko.get(),                  //
-        [](Mammal*) { return 1.0; },  //
-        [](Amphibian*) { return 2.0f; });
-    static_assert(std::is_same_v<decltype(result), double>);
-    EXPECT_EQ(result, 0.0);
-  }
+    std::unique_ptr<Animal> frog = std::make_unique<Frog>();
+    std::unique_ptr<Animal> bear = std::make_unique<Bear>();
+    std::unique_ptr<Animal> gecko = std::make_unique<Gecko>();
+    {
+        auto result = Switch<double>(
+            frog.get(),                 //
+            [](Mammal*) { return 1; },  //
+            [](Amphibian*) { return 2.0f; });
+        static_assert(std::is_same_v<decltype(result), double>);
+        EXPECT_EQ(result, 2.0f);
+    }
+    {
+        auto result = Switch<double>(
+            bear.get(),                    //
+            [](Mammal*) { return 1.0f; },  //
+            [](Amphibian*) { return 2; });
+        static_assert(std::is_same_v<decltype(result), double>);
+        EXPECT_EQ(result, 1.0f);
+    }
+    {
+        auto result = Switch<double>(
+            gecko.get(),                  //
+            [](Mammal*) { return 1.0; },  //
+            [](Amphibian*) { return 2.0f; });
+        static_assert(std::is_same_v<decltype(result), double>);
+        EXPECT_EQ(result, 0.0);
+    }
 }
 
 TEST(Castable, SwitchExplicitCastableReturnTypeWithDefault) {
-  std::unique_ptr<Animal> frog = std::make_unique<Frog>();
-  std::unique_ptr<Animal> bear = std::make_unique<Bear>();
-  std::unique_ptr<Animal> gecko = std::make_unique<Gecko>();
-  {
-    auto* result = Switch<Animal>(
-        frog.get(),                          //
-        [](Mammal* p) { return p; },         //
-        [](Amphibian*) { return nullptr; },  //
-        [](Default) { return nullptr; });
-    static_assert(std::is_same_v<decltype(result), Animal*>);
-    EXPECT_EQ(result, nullptr);
-  }
-  {
-    auto* result = Switch<CastableBase>(
-        bear.get(),                   //
-        [](Mammal* p) { return p; },  //
-        [](Amphibian* p) { return const_cast<const Amphibian*>(p); },
-        [](Default) { return nullptr; });
-    static_assert(std::is_same_v<decltype(result), const CastableBase*>);
-    EXPECT_EQ(result, bear.get());
-  }
-  {
-    auto* result = Switch<const Animal>(
-        gecko.get(),                     //
-        [](Mammal* p) { return p; },     //
-        [](Amphibian* p) { return p; },  //
-        [](Default) { return nullptr; });
-    static_assert(std::is_same_v<decltype(result), const Animal*>);
-    EXPECT_EQ(result, nullptr);
-  }
+    std::unique_ptr<Animal> frog = std::make_unique<Frog>();
+    std::unique_ptr<Animal> bear = std::make_unique<Bear>();
+    std::unique_ptr<Animal> gecko = std::make_unique<Gecko>();
+    {
+        auto* result = Switch<Animal>(
+            frog.get(),                          //
+            [](Mammal* p) { return p; },         //
+            [](Amphibian*) { return nullptr; },  //
+            [](Default) { return nullptr; });
+        static_assert(std::is_same_v<decltype(result), Animal*>);
+        EXPECT_EQ(result, nullptr);
+    }
+    {
+        auto* result = Switch<CastableBase>(
+            bear.get(),                   //
+            [](Mammal* p) { return p; },  //
+            [](Amphibian* p) { return const_cast<const Amphibian*>(p); },
+            [](Default) { return nullptr; });
+        static_assert(std::is_same_v<decltype(result), const CastableBase*>);
+        EXPECT_EQ(result, bear.get());
+    }
+    {
+        auto* result = Switch<const Animal>(
+            gecko.get(),                     //
+            [](Mammal* p) { return p; },     //
+            [](Amphibian* p) { return p; },  //
+            [](Default) { return nullptr; });
+        static_assert(std::is_same_v<decltype(result), const Animal*>);
+        EXPECT_EQ(result, nullptr);
+    }
 }
 
 TEST(Castable, SwitchExplicitCastableReturnTypeWithoutDefault) {
-  std::unique_ptr<Animal> frog = std::make_unique<Frog>();
-  std::unique_ptr<Animal> bear = std::make_unique<Bear>();
-  std::unique_ptr<Animal> gecko = std::make_unique<Gecko>();
-  {
-    auto* result = Switch<Animal>(
-        frog.get(),                   //
-        [](Mammal* p) { return p; },  //
-        [](Amphibian*) { return nullptr; });
-    static_assert(std::is_same_v<decltype(result), Animal*>);
-    EXPECT_EQ(result, nullptr);
-  }
-  {
-    auto* result = Switch<CastableBase>(
-        bear.get(),                                                     //
-        [](Mammal* p) { return p; },                                    //
-        [](Amphibian* p) { return const_cast<const Amphibian*>(p); });  //
-    static_assert(std::is_same_v<decltype(result), const CastableBase*>);
-    EXPECT_EQ(result, bear.get());
-  }
-  {
-    auto* result = Switch<const Animal*>(
-        gecko.get(),                  //
-        [](Mammal* p) { return p; },  //
-        [](Amphibian* p) { return p; });
-    static_assert(std::is_same_v<decltype(result), const Animal*>);
-    EXPECT_EQ(result, nullptr);
-  }
+    std::unique_ptr<Animal> frog = std::make_unique<Frog>();
+    std::unique_ptr<Animal> bear = std::make_unique<Bear>();
+    std::unique_ptr<Animal> gecko = std::make_unique<Gecko>();
+    {
+        auto* result = Switch<Animal>(
+            frog.get(),                   //
+            [](Mammal* p) { return p; },  //
+            [](Amphibian*) { return nullptr; });
+        static_assert(std::is_same_v<decltype(result), Animal*>);
+        EXPECT_EQ(result, nullptr);
+    }
+    {
+        auto* result = Switch<CastableBase>(
+            bear.get(),                                                     //
+            [](Mammal* p) { return p; },                                    //
+            [](Amphibian* p) { return const_cast<const Amphibian*>(p); });  //
+        static_assert(std::is_same_v<decltype(result), const CastableBase*>);
+        EXPECT_EQ(result, bear.get());
+    }
+    {
+        auto* result = Switch<const Animal*>(
+            gecko.get(),                  //
+            [](Mammal* p) { return p; },  //
+            [](Amphibian* p) { return p; });
+        static_assert(std::is_same_v<decltype(result), const Animal*>);
+        EXPECT_EQ(result, nullptr);
+    }
 }
 
 TEST(Castable, SwitchNull) {
-  Animal* null = nullptr;
-  Switch(
-      null,  //
-      [&](Amphibian*) { FAIL() << "should not be called"; },
-      [&](Animal*) { FAIL() << "should not be called"; });
+    Animal* null = nullptr;
+    Switch(
+        null,  //
+        [&](Amphibian*) { FAIL() << "should not be called"; },
+        [&](Animal*) { FAIL() << "should not be called"; });
 }
 
 TEST(Castable, SwitchNullNoDefault) {
-  Animal* null = nullptr;
-  bool default_called = false;
-  Switch(
-      null,  //
-      [&](Amphibian*) { FAIL() << "should not be called"; },
-      [&](Animal*) { FAIL() << "should not be called"; },
-      [&](Default) { default_called = true; });
-  EXPECT_TRUE(default_called);
+    Animal* null = nullptr;
+    bool default_called = false;
+    Switch(
+        null,  //
+        [&](Amphibian*) { FAIL() << "should not be called"; },
+        [&](Animal*) { FAIL() << "should not be called"; },
+        [&](Default) { default_called = true; });
+    EXPECT_TRUE(default_called);
+}
+
+TEST(Castable, SwitchReturnNoDefaultConstructor) {
+    struct Object {
+        explicit Object(int v) : value(v) {}
+        int value;
+    };
+
+    std::unique_ptr<Animal> frog = std::make_unique<Frog>();
+    {
+        auto result = Switch(
+            frog.get(),                            //
+            [](Mammal*) { return Object(1); },     //
+            [](Amphibian*) { return Object(2); },  //
+            [](Default) { return Object(3); });
+        static_assert(std::is_same_v<decltype(result), Object>);
+        EXPECT_EQ(result.value, 2);
+    }
+    {
+        auto result = Switch(
+            frog.get(),                         //
+            [](Mammal*) { return Object(1); },  //
+            [](Default) { return Object(3); });
+        static_assert(std::is_same_v<decltype(result), Object>);
+        EXPECT_EQ(result.value, 3);
+    }
 }
 
 // IsCastable static tests
@@ -736,8 +758,7 @@
 static_assert(std::is_same_v<Iguana, CastableCommonBase<Iguana>>);
 
 static_assert(std::is_same_v<Animal, CastableCommonBase<Animal, Animal>>);
-static_assert(
-    std::is_same_v<Amphibian, CastableCommonBase<Amphibian, Amphibian>>);
+static_assert(std::is_same_v<Amphibian, CastableCommonBase<Amphibian, Amphibian>>);
 static_assert(std::is_same_v<Mammal, CastableCommonBase<Mammal, Mammal>>);
 static_assert(std::is_same_v<Reptile, CastableCommonBase<Reptile, Reptile>>);
 static_assert(std::is_same_v<Frog, CastableCommonBase<Frog, Frog>>);
@@ -746,10 +767,8 @@
 static_assert(std::is_same_v<Gecko, CastableCommonBase<Gecko, Gecko>>);
 static_assert(std::is_same_v<Iguana, CastableCommonBase<Iguana, Iguana>>);
 
-static_assert(
-    std::is_same_v<CastableBase, CastableCommonBase<CastableBase, Animal>>);
-static_assert(
-    std::is_same_v<CastableBase, CastableCommonBase<Animal, CastableBase>>);
+static_assert(std::is_same_v<CastableBase, CastableCommonBase<CastableBase, Animal>>);
+static_assert(std::is_same_v<CastableBase, CastableCommonBase<Animal, CastableBase>>);
 static_assert(std::is_same_v<Amphibian, CastableCommonBase<Amphibian, Frog>>);
 static_assert(std::is_same_v<Amphibian, CastableCommonBase<Frog, Amphibian>>);
 static_assert(std::is_same_v<Animal, CastableCommonBase<Reptile, Frog>>);
@@ -759,19 +778,14 @@
 static_assert(std::is_same_v<Lizard, CastableCommonBase<Gecko, Iguana>>);
 
 static_assert(std::is_same_v<Animal, CastableCommonBase<Bear, Frog, Iguana>>);
-static_assert(
-    std::is_same_v<Lizard, CastableCommonBase<Lizard, Gecko, Iguana>>);
-static_assert(
-    std::is_same_v<Lizard, CastableCommonBase<Gecko, Iguana, Lizard>>);
-static_assert(
-    std::is_same_v<Lizard, CastableCommonBase<Gecko, Lizard, Iguana>>);
+static_assert(std::is_same_v<Lizard, CastableCommonBase<Lizard, Gecko, Iguana>>);
+static_assert(std::is_same_v<Lizard, CastableCommonBase<Gecko, Iguana, Lizard>>);
+static_assert(std::is_same_v<Lizard, CastableCommonBase<Gecko, Lizard, Iguana>>);
 static_assert(std::is_same_v<Animal, CastableCommonBase<Frog, Gecko, Iguana>>);
 static_assert(std::is_same_v<Animal, CastableCommonBase<Gecko, Iguana, Frog>>);
 static_assert(std::is_same_v<Animal, CastableCommonBase<Gecko, Frog, Iguana>>);
 
-static_assert(
-    std::is_same_v<CastableBase,
-                   CastableCommonBase<Bear, Frog, Iguana, CastableBase>>);
+static_assert(std::is_same_v<CastableBase, CastableCommonBase<Bear, Frog, Iguana, CastableBase>>);
 
 }  // namespace
 
diff --git a/src/tint/clone_context.cc b/src/tint/clone_context.cc
index afdf488..0a9e606 100644
--- a/src/tint/clone_context.cc
+++ b/src/tint/clone_context.cc
@@ -26,91 +26,85 @@
 CloneContext::ListTransforms::ListTransforms() = default;
 CloneContext::ListTransforms::~ListTransforms() = default;
 
-CloneContext::CloneContext(ProgramBuilder* to,
-                           Program const* from,
-                           bool auto_clone_symbols)
+CloneContext::CloneContext(ProgramBuilder* to, Program const* from, bool auto_clone_symbols)
     : dst(to), src(from) {
-  if (auto_clone_symbols) {
-    // Almost all transforms will want to clone all symbols before doing any
-    // work, to avoid any newly created symbols clashing with existing symbols
-    // in the source program and causing them to be renamed.
-    from->Symbols().Foreach([&](Symbol s, const std::string&) { Clone(s); });
-  }
+    if (auto_clone_symbols) {
+        // Almost all transforms will want to clone all symbols before doing any
+        // work, to avoid any newly created symbols clashing with existing symbols
+        // in the source program and causing them to be renamed.
+        from->Symbols().Foreach([&](Symbol s, const std::string&) { Clone(s); });
+    }
 }
 
-CloneContext::CloneContext(ProgramBuilder* builder)
-    : CloneContext(builder, nullptr, false) {}
+CloneContext::CloneContext(ProgramBuilder* builder) : CloneContext(builder, nullptr, false) {}
 
 CloneContext::~CloneContext() = default;
 
 Symbol CloneContext::Clone(Symbol s) {
-  if (!src) {
-    return s;  // In-place clone
-  }
-  return utils::GetOrCreate(cloned_symbols_, s, [&]() -> Symbol {
-    if (symbol_transform_) {
-      return symbol_transform_(s);
+    if (!src) {
+        return s;  // In-place clone
     }
-    return dst->Symbols().New(src->Symbols().NameFor(s));
-  });
+    return utils::GetOrCreate(cloned_symbols_, s, [&]() -> Symbol {
+        if (symbol_transform_) {
+            return symbol_transform_(s);
+        }
+        return dst->Symbols().New(src->Symbols().NameFor(s));
+    });
 }
 
 void CloneContext::Clone() {
-  dst->AST().Copy(this, &src->AST());
+    dst->AST().Copy(this, &src->AST());
 }
 
 ast::FunctionList CloneContext::Clone(const ast::FunctionList& v) {
-  ast::FunctionList out;
-  out.reserve(v.size());
-  for (const ast::Function* el : v) {
-    out.Add(Clone(el));
-  }
-  return out;
+    ast::FunctionList out;
+    out.reserve(v.size());
+    for (const ast::Function* el : v) {
+        out.Add(Clone(el));
+    }
+    return out;
 }
 
 const tint::Cloneable* CloneContext::CloneCloneable(const Cloneable* object) {
-  // If the input is nullptr, there's nothing to clone - just return nullptr.
-  if (object == nullptr) {
-    return nullptr;
-  }
-
-  // Was Replace() called for this object?
-  auto it = replacements_.find(object);
-  if (it != replacements_.end()) {
-    return it->second();
-  }
-
-  // Attempt to clone using the registered replacer functions.
-  auto& typeinfo = object->TypeInfo();
-  for (auto& transform : transforms_) {
-    if (typeinfo.Is(transform.typeinfo)) {
-      if (auto* transformed = transform.function(object)) {
-        return transformed;
-      }
-      break;
+    // If the input is nullptr, there's nothing to clone - just return nullptr.
+    if (object == nullptr) {
+        return nullptr;
     }
-  }
 
-  // No transform for this type, or the transform returned nullptr.
-  // Clone with T::Clone().
-  return object->Clone(this);
+    // Was Replace() called for this object?
+    auto it = replacements_.find(object);
+    if (it != replacements_.end()) {
+        return it->second();
+    }
+
+    // Attempt to clone using the registered replacer functions.
+    auto& typeinfo = object->TypeInfo();
+    for (auto& transform : transforms_) {
+        if (typeinfo.Is(transform.typeinfo)) {
+            if (auto* transformed = transform.function(object)) {
+                return transformed;
+            }
+            break;
+        }
+    }
+
+    // No transform for this type, or the transform returned nullptr.
+    // Clone with T::Clone().
+    return object->Clone(this);
 }
 
-void CloneContext::CheckedCastFailure(const Cloneable* got,
-                                      const TypeInfo& expected) {
-  TINT_ICE(Clone, Diagnostics())
-      << "Cloned object was not of the expected type\n"
-      << "got:      " << got->TypeInfo().name << "\n"
-      << "expected: " << expected.name;
+void CloneContext::CheckedCastFailure(const Cloneable* got, const TypeInfo& expected) {
+    TINT_ICE(Clone, Diagnostics()) << "Cloned object was not of the expected type\n"
+                                   << "got:      " << got->TypeInfo().name << "\n"
+                                   << "expected: " << expected.name;
 }
 
 diag::List& CloneContext::Diagnostics() const {
-  return dst->Diagnostics();
+    return dst->Diagnostics();
 }
 
 CloneContext::CloneableTransform::CloneableTransform() = default;
-CloneContext::CloneableTransform::CloneableTransform(
-    const CloneableTransform&) = default;
+CloneContext::CloneableTransform::CloneableTransform(const CloneableTransform&) = default;
 CloneContext::CloneableTransform::~CloneableTransform() = default;
 
 }  // namespace tint
diff --git a/src/tint/clone_context.h b/src/tint/clone_context.h
index 35bb231..e027565 100644
--- a/src/tint/clone_context.h
+++ b/src/tint/clone_context.h
@@ -17,6 +17,7 @@
 
 #include <algorithm>
 #include <functional>
+#include <type_traits>
 #include <unordered_map>
 #include <unordered_set>
 #include <utility>
@@ -46,539 +47,528 @@
 
 /// Cloneable is the base class for all objects that can be cloned
 class Cloneable : public Castable<Cloneable> {
- public:
-  /// Performs a deep clone of this object using the CloneContext `ctx`.
-  /// @param ctx the clone context
-  /// @return the newly cloned object
-  virtual const Cloneable* Clone(CloneContext* ctx) const = 0;
+  public:
+    /// Performs a deep clone of this object using the CloneContext `ctx`.
+    /// @param ctx the clone context
+    /// @return the newly cloned object
+    virtual const Cloneable* Clone(CloneContext* ctx) const = 0;
 };
 
 /// @returns an invalid ProgramID
 inline ProgramID ProgramIDOf(const Cloneable*) {
-  return ProgramID();
+    return ProgramID();
 }
 
 /// CloneContext holds the state used while cloning AST nodes.
 class CloneContext {
-  /// ParamTypeIsPtrOf<F, T> is true iff the first parameter of
-  /// F is a pointer of (or derives from) type T.
-  template <typename F, typename T>
-  static constexpr bool ParamTypeIsPtrOf = traits::IsTypeOrDerived<
-      typename std::remove_pointer<traits::ParameterType<F, 0>>::type,
-      T>;
+    /// ParamTypeIsPtrOf<F, T> is true iff the first parameter of
+    /// F is a pointer of (or derives from) type T.
+    template <typename F, typename T>
+    static constexpr bool ParamTypeIsPtrOf =
+        traits::IsTypeOrDerived<typename std::remove_pointer<traits::ParameterType<F, 0>>::type, T>;
 
- public:
-  /// SymbolTransform is a function that takes a symbol and returns a new
-  /// symbol.
-  using SymbolTransform = std::function<Symbol(Symbol)>;
+  public:
+    /// SymbolTransform is a function that takes a symbol and returns a new
+    /// symbol.
+    using SymbolTransform = std::function<Symbol(Symbol)>;
 
-  /// Constructor for cloning objects from `from` into `to`.
-  /// @param to the target ProgramBuilder to clone into
-  /// @param from the source Program to clone from
-  /// @param auto_clone_symbols clone all symbols in `from` before returning
-  CloneContext(ProgramBuilder* to,
-               Program const* from,
-               bool auto_clone_symbols = true);
+    /// Constructor for cloning objects from `from` into `to`.
+    /// @param to the target ProgramBuilder to clone into
+    /// @param from the source Program to clone from
+    /// @param auto_clone_symbols clone all symbols in `from` before returning
+    CloneContext(ProgramBuilder* to, Program const* from, bool auto_clone_symbols = true);
 
-  /// Constructor for cloning objects from and to the ProgramBuilder `builder`.
-  /// @param builder the ProgramBuilder
-  explicit CloneContext(ProgramBuilder* builder);
+    /// Constructor for cloning objects from and to the ProgramBuilder `builder`.
+    /// @param builder the ProgramBuilder
+    explicit CloneContext(ProgramBuilder* builder);
 
-  /// Destructor
-  ~CloneContext();
+    /// Destructor
+    ~CloneContext();
 
-  /// Clones the Node or sem::Type `a` into the ProgramBuilder #dst if `a` is
-  /// not null. If `a` is null, then Clone() returns null.
-  ///
-  /// Clone() may use a function registered with ReplaceAll() to create a
-  /// transformed version of the object. See ReplaceAll() for more information.
-  ///
-  /// If the CloneContext is cloning from a Program to a ProgramBuilder, then
-  /// the Node or sem::Type `a` must be owned by the Program #src.
-  ///
-  /// @param object the type deriving from Cloneable to clone
-  /// @return the cloned node
-  template <typename T>
-  const T* Clone(const T* object) {
-    if (src) {
-      TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, src, object);
-    }
-    if (auto* cloned = CloneCloneable(object)) {
-      auto* out = CheckedCast<T>(cloned);
-      TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, dst, out);
-      return out;
-    }
-    return nullptr;
-  }
-
-  /// Clones the Node or sem::Type `a` into the ProgramBuilder #dst if `a` is
-  /// not null. If `a` is null, then Clone() returns null.
-  ///
-  /// Unlike Clone(), this method does not invoke or use any transformations
-  /// registered by ReplaceAll().
-  ///
-  /// If the CloneContext is cloning from a Program to a ProgramBuilder, then
-  /// the Node or sem::Type `a` must be owned by the Program #src.
-  ///
-  /// @param a the type deriving from Cloneable to clone
-  /// @return the cloned node
-  template <typename T>
-  const T* CloneWithoutTransform(const T* a) {
-    // If the input is nullptr, there's nothing to clone - just return nullptr.
-    if (a == nullptr) {
-      return nullptr;
-    }
-    if (src) {
-      TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, src, a);
-    }
-    auto* c = a->Clone(this);
-    return CheckedCast<T>(c);
-  }
-
-  /// Clones the Source `s` into #dst
-  /// TODO(bclayton) - Currently this 'clone' is a shallow copy. If/when
-  /// `Source.File`s are owned by the Program this should make a copy of the
-  /// file.
-  /// @param s the `Source` to clone
-  /// @return the cloned source
-  Source Clone(const Source& s) const { return s; }
-
-  /// Clones the Symbol `s` into #dst
-  ///
-  /// The Symbol `s` must be owned by the Program #src.
-  ///
-  /// @param s the Symbol to clone
-  /// @return the cloned source
-  Symbol Clone(Symbol s);
-
-  /// Clones each of the elements of the vector `v` into the ProgramBuilder
-  /// #dst.
-  ///
-  /// All the elements of the vector `v` must be owned by the Program #src.
-  ///
-  /// @param v the vector to clone
-  /// @return the cloned vector
-  template <typename T>
-  std::vector<T> Clone(const std::vector<T>& v) {
-    std::vector<T> out;
-    out.reserve(v.size());
-    for (auto& el : v) {
-      out.emplace_back(Clone(el));
-    }
-    return out;
-  }
-
-  /// Clones each of the elements of the vector `v` using the ProgramBuilder
-  /// #dst, inserting any additional elements into the list that were registered
-  /// with calls to InsertBefore().
-  ///
-  /// All the elements of the vector `v` must be owned by the Program #src.
-  ///
-  /// @param v the vector to clone
-  /// @return the cloned vector
-  template <typename T>
-  std::vector<T*> Clone(const std::vector<T*>& v) {
-    std::vector<T*> out;
-    Clone(out, v);
-    return out;
-  }
-
-  /// Clones each of the elements of the vector `from` into the vector `to`,
-  /// inserting any additional elements into the list that were registered with
-  /// calls to InsertBefore().
-  ///
-  /// All the elements of the vector `from` must be owned by the Program #src.
-  ///
-  /// @param from the vector to clone
-  /// @param to the cloned result
-  template <typename T>
-  void Clone(std::vector<T*>& to, const std::vector<T*>& from) {
-    to.reserve(from.size());
-
-    auto list_transform_it = list_transforms_.find(&from);
-    if (list_transform_it != list_transforms_.end()) {
-      const auto& transforms = list_transform_it->second;
-      for (auto* o : transforms.insert_front_) {
-        to.emplace_back(CheckedCast<T>(o));
-      }
-      for (auto& el : from) {
-        auto insert_before_it = transforms.insert_before_.find(el);
-        if (insert_before_it != transforms.insert_before_.end()) {
-          for (auto insert : insert_before_it->second) {
-            to.emplace_back(CheckedCast<T>(insert));
-          }
+    /// Clones the Node or sem::Type `a` into the ProgramBuilder #dst if `a` is
+    /// not null. If `a` is null, then Clone() returns null.
+    ///
+    /// Clone() may use a function registered with ReplaceAll() to create a
+    /// transformed version of the object. See ReplaceAll() for more information.
+    ///
+    /// If the CloneContext is cloning from a Program to a ProgramBuilder, then
+    /// the Node or sem::Type `a` must be owned by the Program #src.
+    ///
+    /// @param object the type deriving from Cloneable to clone
+    /// @return the cloned node
+    template <typename T>
+    const T* Clone(const T* object) {
+        if (src) {
+            TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, src, object);
         }
-        if (transforms.remove_.count(el) == 0) {
-          to.emplace_back(Clone(el));
+        if (auto* cloned = CloneCloneable(object)) {
+            auto* out = CheckedCast<T>(cloned);
+            TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, dst, out);
+            return out;
         }
-        auto insert_after_it = transforms.insert_after_.find(el);
-        if (insert_after_it != transforms.insert_after_.end()) {
-          for (auto insert : insert_after_it->second) {
-            to.emplace_back(CheckedCast<T>(insert));
-          }
-        }
-      }
-      for (auto* o : transforms.insert_back_) {
-        to.emplace_back(CheckedCast<T>(o));
-      }
-    } else {
-      for (auto& el : from) {
-        to.emplace_back(Clone(el));
+        return nullptr;
+    }
 
-        // Clone(el) may have inserted after
-        list_transform_it = list_transforms_.find(&from);
+    /// Clones the Node or sem::Type `a` into the ProgramBuilder #dst if `a` is
+    /// not null. If `a` is null, then Clone() returns null.
+    ///
+    /// Unlike Clone(), this method does not invoke or use any transformations
+    /// registered by ReplaceAll().
+    ///
+    /// If the CloneContext is cloning from a Program to a ProgramBuilder, then
+    /// the Node or sem::Type `a` must be owned by the Program #src.
+    ///
+    /// @param a the type deriving from Cloneable to clone
+    /// @return the cloned node
+    template <typename T>
+    const T* CloneWithoutTransform(const T* a) {
+        // If the input is nullptr, there's nothing to clone - just return nullptr.
+        if (a == nullptr) {
+            return nullptr;
+        }
+        if (src) {
+            TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, src, a);
+        }
+        auto* c = a->Clone(this);
+        return CheckedCast<T>(c);
+    }
+
+    /// Clones the Source `s` into #dst
+    /// TODO(bclayton) - Currently this 'clone' is a shallow copy. If/when
+    /// `Source.File`s are owned by the Program this should make a copy of the
+    /// file.
+    /// @param s the `Source` to clone
+    /// @return the cloned source
+    Source Clone(const Source& s) const { return s; }
+
+    /// Clones the Symbol `s` into #dst
+    ///
+    /// The Symbol `s` must be owned by the Program #src.
+    ///
+    /// @param s the Symbol to clone
+    /// @return the cloned source
+    Symbol Clone(Symbol s);
+
+    /// Clones each of the elements of the vector `v` into the ProgramBuilder
+    /// #dst.
+    ///
+    /// All the elements of the vector `v` must be owned by the Program #src.
+    ///
+    /// @param v the vector to clone
+    /// @return the cloned vector
+    template <typename T>
+    std::vector<T> Clone(const std::vector<T>& v) {
+        std::vector<T> out;
+        out.reserve(v.size());
+        for (auto& el : v) {
+            out.emplace_back(Clone(el));
+        }
+        return out;
+    }
+
+    /// Clones each of the elements of the vector `v` using the ProgramBuilder
+    /// #dst, inserting any additional elements into the list that were registered
+    /// with calls to InsertBefore().
+    ///
+    /// All the elements of the vector `v` must be owned by the Program #src.
+    ///
+    /// @param v the vector to clone
+    /// @return the cloned vector
+    template <typename T>
+    std::vector<T*> Clone(const std::vector<T*>& v) {
+        std::vector<T*> out;
+        Clone(out, v);
+        return out;
+    }
+
+    /// Clones each of the elements of the vector `from` into the vector `to`,
+    /// inserting any additional elements into the list that were registered with
+    /// calls to InsertBefore().
+    ///
+    /// All the elements of the vector `from` must be owned by the Program #src.
+    ///
+    /// @param from the vector to clone
+    /// @param to the cloned result
+    template <typename T>
+    void Clone(std::vector<T*>& to, const std::vector<T*>& from) {
+        to.reserve(from.size());
+
+        auto list_transform_it = list_transforms_.find(&from);
         if (list_transform_it != list_transforms_.end()) {
-          const auto& transforms = list_transform_it->second;
-
-          auto insert_after_it = transforms.insert_after_.find(el);
-          if (insert_after_it != transforms.insert_after_.end()) {
-            for (auto insert : insert_after_it->second) {
-              to.emplace_back(CheckedCast<T>(insert));
+            const auto& transforms = list_transform_it->second;
+            for (auto* o : transforms.insert_front_) {
+                to.emplace_back(CheckedCast<T>(o));
             }
-          }
-        }
-      }
+            for (auto& el : from) {
+                auto insert_before_it = transforms.insert_before_.find(el);
+                if (insert_before_it != transforms.insert_before_.end()) {
+                    for (auto insert : insert_before_it->second) {
+                        to.emplace_back(CheckedCast<T>(insert));
+                    }
+                }
+                if (transforms.remove_.count(el) == 0) {
+                    to.emplace_back(Clone(el));
+                }
+                auto insert_after_it = transforms.insert_after_.find(el);
+                if (insert_after_it != transforms.insert_after_.end()) {
+                    for (auto insert : insert_after_it->second) {
+                        to.emplace_back(CheckedCast<T>(insert));
+                    }
+                }
+            }
+            for (auto* o : transforms.insert_back_) {
+                to.emplace_back(CheckedCast<T>(o));
+            }
+        } else {
+            for (auto& el : from) {
+                to.emplace_back(Clone(el));
 
-      // Clone(el)s may have inserted back
-      list_transform_it = list_transforms_.find(&from);
-      if (list_transform_it != list_transforms_.end()) {
-        const auto& transforms = list_transform_it->second;
+                // Clone(el) may have inserted after
+                list_transform_it = list_transforms_.find(&from);
+                if (list_transform_it != list_transforms_.end()) {
+                    const auto& transforms = list_transform_it->second;
 
-        for (auto* o : transforms.insert_back_) {
-          to.emplace_back(CheckedCast<T>(o));
+                    auto insert_after_it = transforms.insert_after_.find(el);
+                    if (insert_after_it != transforms.insert_after_.end()) {
+                        for (auto insert : insert_after_it->second) {
+                            to.emplace_back(CheckedCast<T>(insert));
+                        }
+                    }
+                }
+            }
+
+            // Clone(el)s may have inserted back
+            list_transform_it = list_transforms_.find(&from);
+            if (list_transform_it != list_transforms_.end()) {
+                const auto& transforms = list_transform_it->second;
+
+                for (auto* o : transforms.insert_back_) {
+                    to.emplace_back(CheckedCast<T>(o));
+                }
+            }
         }
-      }
     }
-  }
 
-  /// Clones each of the elements of the vector `v` into the ProgramBuilder
-  /// #dst.
-  ///
-  /// All the elements of the vector `v` must be owned by the Program #src.
-  ///
-  /// @param v the vector to clone
-  /// @return the cloned vector
-  ast::FunctionList Clone(const ast::FunctionList& v);
+    /// Clones each of the elements of the vector `v` into the ProgramBuilder
+    /// #dst.
+    ///
+    /// All the elements of the vector `v` must be owned by the Program #src.
+    ///
+    /// @param v the vector to clone
+    /// @return the cloned vector
+    ast::FunctionList Clone(const ast::FunctionList& v);
 
-  /// ReplaceAll() registers `replacer` to be called whenever the Clone() method
-  /// is called with a Cloneable type that matches (or derives from) the type of
-  /// the single parameter of `replacer`.
-  /// The returned Cloneable of `replacer` will be used as the replacement for
-  /// all references to the object that's being cloned. This returned Cloneable
-  /// must be owned by the Program #dst.
-  ///
-  /// `replacer` must be function-like with the signature: `T* (T*)`
-  ///  where `T` is a type deriving from Cloneable.
-  ///
-  /// If `replacer` returns a nullptr then Clone() will call `T::Clone()` to
-  /// clone the object.
-  ///
-  /// Example:
-  ///
-  /// ```
-  ///   // Replace all ast::UintLiteralExpressions with the number 42
-  ///   CloneCtx ctx(&out, in);
-  ///   ctx.ReplaceAll([&] (ast::UintLiteralExpression* l) {
-  ///       return ctx->dst->create<ast::UintLiteralExpression>(
-  ///           ctx->Clone(l->source),
-  ///           ctx->Clone(l->type),
-  ///           42);
-  ///     });
-  ///   ctx.Clone();
-  /// ```
-  ///
-  /// @warning a single handler can only be registered for any given type.
-  /// Attempting to register two handlers for the same type will result in an
-  /// ICE.
-  /// @warning The replacement object must be of the correct type for all
-  /// references of the original object. A type mismatch will result in an
-  /// assertion in debug builds, and undefined behavior in release builds.
-  /// @param replacer a function or function-like object with the signature
-  ///        `T* (T*)`, where `T` derives from Cloneable
-  /// @returns this CloneContext so calls can be chained
-  template <typename F>
-  traits::EnableIf<ParamTypeIsPtrOf<F, Cloneable>, CloneContext>& ReplaceAll(
-      F&& replacer) {
-    using TPtr = traits::ParameterType<F, 0>;
-    using T = typename std::remove_pointer<TPtr>::type;
-    for (auto& transform : transforms_) {
-      if (transform.typeinfo->Is(&TypeInfo::Of<T>()) ||
-          TypeInfo::Of<T>().Is(transform.typeinfo)) {
-        TINT_ICE(Clone, Diagnostics())
-            << "ReplaceAll() called with a handler for type "
-            << TypeInfo::Of<T>().name
-            << " that is already handled by a handler for type "
-            << transform.typeinfo->name;
+    /// ReplaceAll() registers `replacer` to be called whenever the Clone() method
+    /// is called with a Cloneable type that matches (or derives from) the type of
+    /// the single parameter of `replacer`.
+    /// The returned Cloneable of `replacer` will be used as the replacement for
+    /// all references to the object that's being cloned. This returned Cloneable
+    /// must be owned by the Program #dst.
+    ///
+    /// `replacer` must be function-like with the signature: `T* (T*)`
+    ///  where `T` is a type deriving from Cloneable.
+    ///
+    /// If `replacer` returns a nullptr then Clone() will call `T::Clone()` to
+    /// clone the object.
+    ///
+    /// Example:
+    ///
+    /// ```
+    ///   // Replace all ast::UintLiteralExpressions with the number 42
+    ///   CloneCtx ctx(&out, in);
+    ///   ctx.ReplaceAll([&] (ast::UintLiteralExpression* l) {
+    ///       return ctx->dst->create<ast::UintLiteralExpression>(
+    ///           ctx->Clone(l->source),
+    ///           ctx->Clone(l->type),
+    ///           42);
+    ///     });
+    ///   ctx.Clone();
+    /// ```
+    ///
+    /// @warning a single handler can only be registered for any given type.
+    /// Attempting to register two handlers for the same type will result in an
+    /// ICE.
+    /// @warning The replacement object must be of the correct type for all
+    /// references of the original object. A type mismatch will result in an
+    /// assertion in debug builds, and undefined behavior in release builds.
+    /// @param replacer a function or function-like object with the signature
+    ///        `T* (T*)`, where `T` derives from Cloneable
+    /// @returns this CloneContext so calls can be chained
+    template <typename F>
+    traits::EnableIf<ParamTypeIsPtrOf<F, Cloneable>, CloneContext>& ReplaceAll(F&& replacer) {
+        using TPtr = traits::ParameterType<F, 0>;
+        using T = typename std::remove_pointer<TPtr>::type;
+        for (auto& transform : transforms_) {
+            if (transform.typeinfo->Is(&TypeInfo::Of<T>()) ||
+                TypeInfo::Of<T>().Is(transform.typeinfo)) {
+                TINT_ICE(Clone, Diagnostics())
+                    << "ReplaceAll() called with a handler for type " << TypeInfo::Of<T>().name
+                    << " that is already handled by a handler for type "
+                    << transform.typeinfo->name;
+                return *this;
+            }
+        }
+        CloneableTransform transform;
+        transform.typeinfo = &TypeInfo::Of<T>();
+        transform.function = [=](const Cloneable* in) { return replacer(in->As<T>()); };
+        transforms_.emplace_back(std::move(transform));
         return *this;
-      }
     }
-    CloneableTransform transform;
-    transform.typeinfo = &TypeInfo::Of<T>();
-    transform.function = [=](const Cloneable* in) {
-      return replacer(in->As<T>());
+
+    /// ReplaceAll() registers `replacer` to be called whenever the Clone() method
+    /// is called with a Symbol.
+    /// The returned symbol of `replacer` will be used as the replacement for
+    /// all references to the symbol that's being cloned. This returned Symbol
+    /// must be owned by the Program #dst.
+    /// @param replacer a function the signature `Symbol(Symbol)`.
+    /// @warning a SymbolTransform can only be registered once. Attempting to
+    /// register a SymbolTransform more than once will result in an ICE.
+    /// @returns this CloneContext so calls can be chained
+    CloneContext& ReplaceAll(const SymbolTransform& replacer) {
+        if (symbol_transform_) {
+            TINT_ICE(Clone, Diagnostics()) << "ReplaceAll(const SymbolTransform&) called "
+                                              "multiple times on the same CloneContext";
+            return *this;
+        }
+        symbol_transform_ = replacer;
+        return *this;
+    }
+
+    /// Replace replaces all occurrences of `what` in #src with the pointer `with`
+    /// in #dst when calling Clone().
+    /// [DEPRECATED]: This function cannot handle nested replacements. Use the
+    /// overload of Replace() that take a function for the `WITH` argument.
+    /// @param what a pointer to the object in #src that will be replaced with
+    /// `with`
+    /// @param with a pointer to the replacement object owned by #dst that will be
+    /// used as a replacement for `what`
+    /// @warning The replacement object must be of the correct type for all
+    /// references of the original object. A type mismatch will result in an
+    /// assertion in debug builds, and undefined behavior in release builds.
+    /// @returns this CloneContext so calls can be chained
+    template <typename WHAT, typename WITH, typename = traits::EnableIfIsType<WITH, Cloneable>>
+    CloneContext& Replace(const WHAT* what, const WITH* with) {
+        TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, src, what);
+        TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, dst, with);
+        replacements_[what] = [with]() -> const Cloneable* { return with; };
+        return *this;
+    }
+
+    /// Replace replaces all occurrences of `what` in #src with the result of the
+    /// function `with` in #dst when calling Clone(). `with` will be called each
+    /// time `what` is cloned by this context. If `what` is not cloned, then
+    /// `with` may never be called.
+    /// @param what a pointer to the object in #src that will be replaced with
+    /// `with`
+    /// @param with a function that takes no arguments and returns a pointer to
+    /// the replacement object owned by #dst. The returned pointer will be used as
+    /// a replacement for `what`.
+    /// @warning The replacement object must be of the correct type for all
+    /// references of the original object. A type mismatch will result in an
+    /// assertion in debug builds, and undefined behavior in release builds.
+    /// @returns this CloneContext so calls can be chained
+    template <typename WHAT, typename WITH, typename = std::invoke_result_t<WITH>>
+    CloneContext& Replace(const WHAT* what, WITH&& with) {
+        TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, src, what);
+        replacements_[what] = with;
+        return *this;
+    }
+
+    /// Removes `object` from the cloned copy of `vector`.
+    /// @param vector the vector in #src
+    /// @param object a pointer to the object in #src that will be omitted from
+    /// the cloned vector.
+    /// @returns this CloneContext so calls can be chained
+    template <typename T, typename OBJECT>
+    CloneContext& Remove(const std::vector<T>& vector, OBJECT* object) {
+        TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, src, object);
+        if (std::find(vector.begin(), vector.end(), object) == vector.end()) {
+            TINT_ICE(Clone, Diagnostics())
+                << "CloneContext::Remove() vector does not contain object";
+            return *this;
+        }
+
+        list_transforms_[&vector].remove_.emplace(object);
+        return *this;
+    }
+
+    /// Inserts `object` before any other objects of `vector`, when it is cloned.
+    /// @param vector the vector in #src
+    /// @param object a pointer to the object in #dst that will be inserted at the
+    /// front of the vector
+    /// @returns this CloneContext so calls can be chained
+    template <typename T, typename OBJECT>
+    CloneContext& InsertFront(const std::vector<T>& vector, OBJECT* object) {
+        TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, dst, object);
+        auto& transforms = list_transforms_[&vector];
+        auto& list = transforms.insert_front_;
+        list.emplace_back(object);
+        return *this;
+    }
+
+    /// Inserts `object` after any other objects of `vector`, when it is cloned.
+    /// @param vector the vector in #src
+    /// @param object a pointer to the object in #dst that will be inserted at the
+    /// end of the vector
+    /// @returns this CloneContext so calls can be chained
+    template <typename T, typename OBJECT>
+    CloneContext& InsertBack(const std::vector<T>& vector, OBJECT* object) {
+        TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, dst, object);
+        auto& transforms = list_transforms_[&vector];
+        auto& list = transforms.insert_back_;
+        list.emplace_back(object);
+        return *this;
+    }
+
+    /// Inserts `object` before `before` whenever `vector` is cloned.
+    /// @param vector the vector in #src
+    /// @param before a pointer to the object in #src
+    /// @param object a pointer to the object in #dst that will be inserted before
+    /// any occurrence of the clone of `before`
+    /// @returns this CloneContext so calls can be chained
+    template <typename T, typename BEFORE, typename OBJECT>
+    CloneContext& InsertBefore(const std::vector<T>& vector,
+                               const BEFORE* before,
+                               const OBJECT* object) {
+        TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, src, before);
+        TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, dst, object);
+        if (std::find(vector.begin(), vector.end(), before) == vector.end()) {
+            TINT_ICE(Clone, Diagnostics())
+                << "CloneContext::InsertBefore() vector does not contain before";
+            return *this;
+        }
+
+        auto& transforms = list_transforms_[&vector];
+        auto& list = transforms.insert_before_[before];
+        list.emplace_back(object);
+        return *this;
+    }
+
+    /// Inserts `object` after `after` whenever `vector` is cloned.
+    /// @param vector the vector in #src
+    /// @param after a pointer to the object in #src
+    /// @param object a pointer to the object in #dst that will be inserted after
+    /// any occurrence of the clone of `after`
+    /// @returns this CloneContext so calls can be chained
+    template <typename T, typename AFTER, typename OBJECT>
+    CloneContext& InsertAfter(const std::vector<T>& vector,
+                              const AFTER* after,
+                              const OBJECT* object) {
+        TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, src, after);
+        TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, dst, object);
+        if (std::find(vector.begin(), vector.end(), after) == vector.end()) {
+            TINT_ICE(Clone, Diagnostics())
+                << "CloneContext::InsertAfter() vector does not contain after";
+            return *this;
+        }
+
+        auto& transforms = list_transforms_[&vector];
+        auto& list = transforms.insert_after_[after];
+        list.emplace_back(object);
+        return *this;
+    }
+
+    /// Clone performs the clone of the Program's AST nodes, types and symbols
+    /// from #src to #dst. Semantic nodes are not cloned, as these will be rebuilt
+    /// when the ProgramBuilder #dst builds its Program.
+    void Clone();
+
+    /// The target ProgramBuilder to clone into.
+    ProgramBuilder* const dst;
+
+    /// The source Program to clone from.
+    Program const* const src;
+
+  private:
+    struct CloneableTransform {
+        /// Constructor
+        CloneableTransform();
+        /// Copy constructor
+        /// @param other the CloneableTransform to copy
+        CloneableTransform(const CloneableTransform& other);
+        /// Destructor
+        ~CloneableTransform();
+
+        // TypeInfo of the Cloneable that the transform operates on
+        const TypeInfo* typeinfo;
+        std::function<const Cloneable*(const Cloneable*)> function;
     };
-    transforms_.emplace_back(std::move(transform));
-    return *this;
-  }
 
-  /// ReplaceAll() registers `replacer` to be called whenever the Clone() method
-  /// is called with a Symbol.
-  /// The returned symbol of `replacer` will be used as the replacement for
-  /// all references to the symbol that's being cloned. This returned Symbol
-  /// must be owned by the Program #dst.
-  /// @param replacer a function the signature `Symbol(Symbol)`.
-  /// @warning a SymbolTransform can only be registered once. Attempting to
-  /// register a SymbolTransform more than once will result in an ICE.
-  /// @returns this CloneContext so calls can be chained
-  CloneContext& ReplaceAll(const SymbolTransform& replacer) {
-    if (symbol_transform_) {
-      TINT_ICE(Clone, Diagnostics())
-          << "ReplaceAll(const SymbolTransform&) called "
-             "multiple times on the same CloneContext";
-      return *this;
-    }
-    symbol_transform_ = replacer;
-    return *this;
-  }
+    CloneContext(const CloneContext&) = delete;
+    CloneContext& operator=(const CloneContext&) = delete;
 
-  /// Replace replaces all occurrences of `what` in #src with the pointer `with`
-  /// in #dst when calling Clone().
-  /// [DEPRECATED]: This function cannot handle nested replacements. Use the
-  /// overload of Replace() that take a function for the `WITH` argument.
-  /// @param what a pointer to the object in #src that will be replaced with
-  /// `with`
-  /// @param with a pointer to the replacement object owned by #dst that will be
-  /// used as a replacement for `what`
-  /// @warning The replacement object must be of the correct type for all
-  /// references of the original object. A type mismatch will result in an
-  /// assertion in debug builds, and undefined behavior in release builds.
-  /// @returns this CloneContext so calls can be chained
-  template <typename WHAT,
-            typename WITH,
-            typename = traits::EnableIfIsType<WITH, Cloneable>>
-  CloneContext& Replace(const WHAT* what, const WITH* with) {
-    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, src, what);
-    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, dst, with);
-    replacements_[what] = [with]() -> const Cloneable* { return with; };
-    return *this;
-  }
-
-  /// Replace replaces all occurrences of `what` in #src with the result of the
-  /// function `with` in #dst when calling Clone(). `with` will be called each
-  /// time `what` is cloned by this context. If `what` is not cloned, then
-  /// `with` may never be called.
-  /// @param what a pointer to the object in #src that will be replaced with
-  /// `with`
-  /// @param with a function that takes no arguments and returns a pointer to
-  /// the replacement object owned by #dst. The returned pointer will be used as
-  /// a replacement for `what`.
-  /// @warning The replacement object must be of the correct type for all
-  /// references of the original object. A type mismatch will result in an
-  /// assertion in debug builds, and undefined behavior in release builds.
-  /// @returns this CloneContext so calls can be chained
-  template <typename WHAT, typename WITH, typename = std::result_of_t<WITH()>>
-  CloneContext& Replace(const WHAT* what, WITH&& with) {
-    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, src, what);
-    replacements_[what] = with;
-    return *this;
-  }
-
-  /// Removes `object` from the cloned copy of `vector`.
-  /// @param vector the vector in #src
-  /// @param object a pointer to the object in #src that will be omitted from
-  /// the cloned vector.
-  /// @returns this CloneContext so calls can be chained
-  template <typename T, typename OBJECT>
-  CloneContext& Remove(const std::vector<T>& vector, OBJECT* object) {
-    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, src, object);
-    if (std::find(vector.begin(), vector.end(), object) == vector.end()) {
-      TINT_ICE(Clone, Diagnostics())
-          << "CloneContext::Remove() vector does not contain object";
-      return *this;
+    /// Cast `obj` from type `FROM` to type `TO`, returning the cast object.
+    /// Reports an internal compiler error if the cast failed.
+    template <typename TO, typename FROM>
+    const TO* CheckedCast(const FROM* obj) {
+        if (obj == nullptr) {
+            return nullptr;
+        }
+        if (const TO* cast = obj->template As<TO>()) {
+            return cast;
+        }
+        CheckedCastFailure(obj, TypeInfo::Of<TO>());
+        return nullptr;
     }
 
-    list_transforms_[&vector].remove_.emplace(object);
-    return *this;
-  }
+    /// Clones a Cloneable object, using any replacements or transforms that have
+    /// been configured.
+    const Cloneable* CloneCloneable(const Cloneable* object);
 
-  /// Inserts `object` before any other objects of `vector`, when it is cloned.
-  /// @param vector the vector in #src
-  /// @param object a pointer to the object in #dst that will be inserted at the
-  /// front of the vector
-  /// @returns this CloneContext so calls can be chained
-  template <typename T, typename OBJECT>
-  CloneContext& InsertFront(const std::vector<T>& vector, OBJECT* object) {
-    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, dst, object);
-    auto& transforms = list_transforms_[&vector];
-    auto& list = transforms.insert_front_;
-    list.emplace_back(object);
-    return *this;
-  }
+    /// Adds an error diagnostic to Diagnostics() that the cloned object was not
+    /// of the expected type.
+    void CheckedCastFailure(const Cloneable* got, const TypeInfo& expected);
 
-  /// Inserts `object` after any other objects of `vector`, when it is cloned.
-  /// @param vector the vector in #src
-  /// @param object a pointer to the object in #dst that will be inserted at the
-  /// end of the vector
-  /// @returns this CloneContext so calls can be chained
-  template <typename T, typename OBJECT>
-  CloneContext& InsertBack(const std::vector<T>& vector, OBJECT* object) {
-    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, dst, object);
-    auto& transforms = list_transforms_[&vector];
-    auto& list = transforms.insert_back_;
-    list.emplace_back(object);
-    return *this;
-  }
+    /// @returns the diagnostic list of #dst
+    diag::List& Diagnostics() const;
 
-  /// Inserts `object` before `before` whenever `vector` is cloned.
-  /// @param vector the vector in #src
-  /// @param before a pointer to the object in #src
-  /// @param object a pointer to the object in #dst that will be inserted before
-  /// any occurrence of the clone of `before`
-  /// @returns this CloneContext so calls can be chained
-  template <typename T, typename BEFORE, typename OBJECT>
-  CloneContext& InsertBefore(const std::vector<T>& vector,
-                             const BEFORE* before,
-                             const OBJECT* object) {
-    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, src, before);
-    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, dst, object);
-    if (std::find(vector.begin(), vector.end(), before) == vector.end()) {
-      TINT_ICE(Clone, Diagnostics())
-          << "CloneContext::InsertBefore() vector does not contain before";
-      return *this;
-    }
+    /// A vector of const Cloneable*
+    using CloneableList = std::vector<const Cloneable*>;
 
-    auto& transforms = list_transforms_[&vector];
-    auto& list = transforms.insert_before_[before];
-    list.emplace_back(object);
-    return *this;
-  }
+    /// Transformations to be applied to a list (vector)
+    struct ListTransforms {
+        /// Constructor
+        ListTransforms();
+        /// Destructor
+        ~ListTransforms();
 
-  /// Inserts `object` after `after` whenever `vector` is cloned.
-  /// @param vector the vector in #src
-  /// @param after a pointer to the object in #src
-  /// @param object a pointer to the object in #dst that will be inserted after
-  /// any occurrence of the clone of `after`
-  /// @returns this CloneContext so calls can be chained
-  template <typename T, typename AFTER, typename OBJECT>
-  CloneContext& InsertAfter(const std::vector<T>& vector,
-                            const AFTER* after,
-                            const OBJECT* object) {
-    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, src, after);
-    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, dst, object);
-    if (std::find(vector.begin(), vector.end(), after) == vector.end()) {
-      TINT_ICE(Clone, Diagnostics())
-          << "CloneContext::InsertAfter() vector does not contain after";
-      return *this;
-    }
+        /// A map of object in #src to omit when cloned into #dst.
+        std::unordered_set<const Cloneable*> remove_;
 
-    auto& transforms = list_transforms_[&vector];
-    auto& list = transforms.insert_after_[after];
-    list.emplace_back(object);
-    return *this;
-  }
+        /// A list of objects in #dst to insert before any others when the vector is
+        /// cloned.
+        CloneableList insert_front_;
 
-  /// Clone performs the clone of the Program's AST nodes, types and symbols
-  /// from #src to #dst. Semantic nodes are not cloned, as these will be rebuilt
-  /// when the ProgramBuilder #dst builds its Program.
-  void Clone();
+        /// A list of objects in #dst to insert befor after any others when the
+        /// vector is cloned.
+        CloneableList insert_back_;
 
-  /// The target ProgramBuilder to clone into.
-  ProgramBuilder* const dst;
+        /// A map of object in #src to the list of cloned objects in #dst.
+        /// Clone(const std::vector<T*>& v) will use this to insert the map-value
+        /// list into the target vector before cloning and inserting the map-key.
+        std::unordered_map<const Cloneable*, CloneableList> insert_before_;
 
-  /// The source Program to clone from.
-  Program const* const src;
+        /// A map of object in #src to the list of cloned objects in #dst.
+        /// Clone(const std::vector<T*>& v) will use this to insert the map-value
+        /// list into the target vector after cloning and inserting the map-key.
+        std::unordered_map<const Cloneable*, CloneableList> insert_after_;
+    };
 
- private:
-  struct CloneableTransform {
-    /// Constructor
-    CloneableTransform();
-    /// Copy constructor
-    /// @param other the CloneableTransform to copy
-    CloneableTransform(const CloneableTransform& other);
-    /// Destructor
-    ~CloneableTransform();
+    /// A map of object in #src to functions that create their replacement in
+    /// #dst
+    std::unordered_map<const Cloneable*, std::function<const Cloneable*()>> replacements_;
 
-    // TypeInfo of the Cloneable that the transform operates on
-    const TypeInfo* typeinfo;
-    std::function<const Cloneable*(const Cloneable*)> function;
-  };
+    /// A map of symbol in #src to their cloned equivalent in #dst
+    std::unordered_map<Symbol, Symbol> cloned_symbols_;
 
-  CloneContext(const CloneContext&) = delete;
-  CloneContext& operator=(const CloneContext&) = delete;
+    /// Cloneable transform functions registered with ReplaceAll()
+    std::vector<CloneableTransform> transforms_;
 
-  /// Cast `obj` from type `FROM` to type `TO`, returning the cast object.
-  /// Reports an internal compiler error if the cast failed.
-  template <typename TO, typename FROM>
-  const TO* CheckedCast(const FROM* obj) {
-    if (obj == nullptr) {
-      return nullptr;
-    }
-    if (const TO* cast = obj->template As<TO>()) {
-      return cast;
-    }
-    CheckedCastFailure(obj, TypeInfo::Of<TO>());
-    return nullptr;
-  }
+    /// Map of std::vector pointer to transforms for that list
+    std::unordered_map<const void*, ListTransforms> list_transforms_;
 
-  /// Clones a Cloneable object, using any replacements or transforms that have
-  /// been configured.
-  const Cloneable* CloneCloneable(const Cloneable* object);
-
-  /// Adds an error diagnostic to Diagnostics() that the cloned object was not
-  /// of the expected type.
-  void CheckedCastFailure(const Cloneable* got, const TypeInfo& expected);
-
-  /// @returns the diagnostic list of #dst
-  diag::List& Diagnostics() const;
-
-  /// A vector of const Cloneable*
-  using CloneableList = std::vector<const Cloneable*>;
-
-  /// Transformations to be applied to a list (vector)
-  struct ListTransforms {
-    /// Constructor
-    ListTransforms();
-    /// Destructor
-    ~ListTransforms();
-
-    /// A map of object in #src to omit when cloned into #dst.
-    std::unordered_set<const Cloneable*> remove_;
-
-    /// A list of objects in #dst to insert before any others when the vector is
-    /// cloned.
-    CloneableList insert_front_;
-
-    /// A list of objects in #dst to insert befor after any others when the
-    /// vector is cloned.
-    CloneableList insert_back_;
-
-    /// A map of object in #src to the list of cloned objects in #dst.
-    /// Clone(const std::vector<T*>& v) will use this to insert the map-value
-    /// list into the target vector before cloning and inserting the map-key.
-    std::unordered_map<const Cloneable*, CloneableList> insert_before_;
-
-    /// A map of object in #src to the list of cloned objects in #dst.
-    /// Clone(const std::vector<T*>& v) will use this to insert the map-value
-    /// list into the target vector after cloning and inserting the map-key.
-    std::unordered_map<const Cloneable*, CloneableList> insert_after_;
-  };
-
-  /// A map of object in #src to functions that create their replacement in
-  /// #dst
-  std::unordered_map<const Cloneable*, std::function<const Cloneable*()>>
-      replacements_;
-
-  /// A map of symbol in #src to their cloned equivalent in #dst
-  std::unordered_map<Symbol, Symbol> cloned_symbols_;
-
-  /// Cloneable transform functions registered with ReplaceAll()
-  std::vector<CloneableTransform> transforms_;
-
-  /// Map of std::vector pointer to transforms for that list
-  std::unordered_map<const void*, ListTransforms> list_transforms_;
-
-  /// Symbol transform registered with ReplaceAll()
-  SymbolTransform symbol_transform_;
+    /// Symbol transform registered with ReplaceAll()
+    SymbolTransform symbol_transform_;
 };
 
 }  // namespace tint
diff --git a/src/tint/clone_context_test.cc b/src/tint/clone_context_test.cc
index 3a5a8c9..46cc720 100644
--- a/src/tint/clone_context_test.cc
+++ b/src/tint/clone_context_test.cc
@@ -21,922 +21,904 @@
 namespace {
 
 struct Allocator {
-  template <typename T, typename... ARGS>
-  T* Create(ARGS&&... args) {
-    return alloc.Create<T>(this, std::forward<ARGS>(args)...);
-  }
+    template <typename T, typename... ARGS>
+    T* Create(ARGS&&... args) {
+        return alloc.Create<T>(this, std::forward<ARGS>(args)...);
+    }
 
- private:
-  utils::BlockAllocator<Cloneable> alloc;
+  private:
+    utils::BlockAllocator<Cloneable> alloc;
 };
 
 struct Node : public Castable<Node, Cloneable> {
-  Node(Allocator* alloc,
-       Symbol n,
-       const Node* node_a = nullptr,
-       const Node* node_b = nullptr,
-       const Node* node_c = nullptr)
-      : allocator(alloc), name(n), a(node_a), b(node_b), c(node_c) {}
-  Allocator* const allocator;
-  Symbol name;
-  const Node* a = nullptr;
-  const Node* b = nullptr;
-  const Node* c = nullptr;
-  std::vector<const Node*> vec;
+    Node(Allocator* alloc,
+         Symbol n,
+         const Node* node_a = nullptr,
+         const Node* node_b = nullptr,
+         const Node* node_c = nullptr)
+        : allocator(alloc), name(n), a(node_a), b(node_b), c(node_c) {}
+    Allocator* const allocator;
+    Symbol name;
+    const Node* a = nullptr;
+    const Node* b = nullptr;
+    const Node* c = nullptr;
+    std::vector<const Node*> vec;
 
-  Node* Clone(CloneContext* ctx) const override {
-    auto* out = allocator->Create<Node>(ctx->Clone(name));
-    out->a = ctx->Clone(a);
-    out->b = ctx->Clone(b);
-    out->c = ctx->Clone(c);
-    out->vec = ctx->Clone(vec);
-    return out;
-  }
+    Node* Clone(CloneContext* ctx) const override {
+        auto* out = allocator->Create<Node>(ctx->Clone(name));
+        out->a = ctx->Clone(a);
+        out->b = ctx->Clone(b);
+        out->c = ctx->Clone(c);
+        out->vec = ctx->Clone(vec);
+        return out;
+    }
 };
 
 struct Replaceable : public Castable<Replaceable, Node> {
-  Replaceable(Allocator* alloc,
-              Symbol n,
-              const Node* node_a = nullptr,
-              const Node* node_b = nullptr,
-              const Node* node_c = nullptr)
-      : Base(alloc, n, node_a, node_b, node_c) {}
+    Replaceable(Allocator* alloc,
+                Symbol n,
+                const Node* node_a = nullptr,
+                const Node* node_b = nullptr,
+                const Node* node_c = nullptr)
+        : Base(alloc, n, node_a, node_b, node_c) {}
 };
 
 struct Replacement : public Castable<Replacement, Replaceable> {
-  Replacement(Allocator* alloc, Symbol n) : Base(alloc, n) {}
+    Replacement(Allocator* alloc, Symbol n) : Base(alloc, n) {}
 };
 
 struct NotANode : public Castable<NotANode, Cloneable> {
-  explicit NotANode(Allocator* alloc) : allocator(alloc) {}
+    explicit NotANode(Allocator* alloc) : allocator(alloc) {}
 
-  Allocator* const allocator;
-  NotANode* Clone(CloneContext*) const override {
-    return allocator->Create<NotANode>();
-  }
+    Allocator* const allocator;
+    NotANode* Clone(CloneContext*) const override { return allocator->Create<NotANode>(); }
 };
 
 struct ProgramNode : public Castable<ProgramNode, Cloneable> {
-  ProgramNode(Allocator* alloc, ProgramID id, ProgramID cloned_id)
-      : allocator(alloc), program_id(id), cloned_program_id(cloned_id) {}
+    ProgramNode(Allocator* alloc, ProgramID id, ProgramID cloned_id)
+        : allocator(alloc), program_id(id), cloned_program_id(cloned_id) {}
 
-  Allocator* const allocator;
-  const ProgramID program_id;
-  const ProgramID cloned_program_id;
+    Allocator* const allocator;
+    const ProgramID program_id;
+    const ProgramID cloned_program_id;
 
-  ProgramNode* Clone(CloneContext*) const override {
-    return allocator->Create<ProgramNode>(cloned_program_id, cloned_program_id);
-  }
+    ProgramNode* Clone(CloneContext*) const override {
+        return allocator->Create<ProgramNode>(cloned_program_id, cloned_program_id);
+    }
 };
 
 ProgramID ProgramIDOf(const ProgramNode* node) {
-  return node->program_id;
+    return node->program_id;
 }
 
 using CloneContextNodeTest = ::testing::Test;
 
 TEST_F(CloneContextNodeTest, Clone) {
-  Allocator alloc;
+    Allocator alloc;
 
-  ProgramBuilder builder;
-  Node* original_root;
-  {
-    auto* a_b = alloc.Create<Node>(builder.Symbols().New("a->b"));
-    auto* a = alloc.Create<Node>(builder.Symbols().New("a"), nullptr, a_b);
-    auto* b_a = a;  // Aliased
-    auto* b_b = alloc.Create<Node>(builder.Symbols().New("b->b"));
-    auto* b = alloc.Create<Node>(builder.Symbols().New("b"), b_a, b_b);
-    auto* c = b;  // Aliased
-    original_root = alloc.Create<Node>(builder.Symbols().New("root"), a, b, c);
-  }
-  Program original(std::move(builder));
+    ProgramBuilder builder;
+    Node* original_root;
+    {
+        auto* a_b = alloc.Create<Node>(builder.Symbols().New("a->b"));
+        auto* a = alloc.Create<Node>(builder.Symbols().New("a"), nullptr, a_b);
+        auto* b_a = a;  // Aliased
+        auto* b_b = alloc.Create<Node>(builder.Symbols().New("b->b"));
+        auto* b = alloc.Create<Node>(builder.Symbols().New("b"), b_a, b_b);
+        auto* c = b;  // Aliased
+        original_root = alloc.Create<Node>(builder.Symbols().New("root"), a, b, c);
+    }
+    Program original(std::move(builder));
 
-  //                          root
-  //        ╭──────────────────┼──────────────────╮
-  //       (a)                (b)                (c)
-  //        N  <──────┐        N  <───────────────┘
-  //   ╭────┼────╮    │   ╭────┼────╮
-  //  (a)  (b)  (c)   │  (a)  (b)  (c)
-  //        N         └───┘    N
-  //
-  // N: Node
+    //                          root
+    //        ╭──────────────────┼──────────────────╮
+    //       (a)                (b)                (c)
+    //        N  <──────┐        N  <───────────────┘
+    //   ╭────┼────╮    │   ╭────┼────╮
+    //  (a)  (b)  (c)   │  (a)  (b)  (c)
+    //        N         └───┘    N
+    //
+    // N: Node
 
-  ProgramBuilder cloned;
-  auto* cloned_root = CloneContext(&cloned, &original).Clone(original_root);
+    ProgramBuilder cloned;
+    auto* cloned_root = CloneContext(&cloned, &original).Clone(original_root);
 
-  EXPECT_NE(cloned_root->a, nullptr);
-  EXPECT_EQ(cloned_root->a->a, nullptr);
-  EXPECT_NE(cloned_root->a->b, nullptr);
-  EXPECT_EQ(cloned_root->a->c, nullptr);
-  EXPECT_NE(cloned_root->b, nullptr);
-  EXPECT_NE(cloned_root->b->a, nullptr);
-  EXPECT_NE(cloned_root->b->b, nullptr);
-  EXPECT_EQ(cloned_root->b->c, nullptr);
-  EXPECT_NE(cloned_root->c, nullptr);
+    EXPECT_NE(cloned_root->a, nullptr);
+    EXPECT_EQ(cloned_root->a->a, nullptr);
+    EXPECT_NE(cloned_root->a->b, nullptr);
+    EXPECT_EQ(cloned_root->a->c, nullptr);
+    EXPECT_NE(cloned_root->b, nullptr);
+    EXPECT_NE(cloned_root->b->a, nullptr);
+    EXPECT_NE(cloned_root->b->b, nullptr);
+    EXPECT_EQ(cloned_root->b->c, nullptr);
+    EXPECT_NE(cloned_root->c, nullptr);
 
-  EXPECT_NE(cloned_root->a, original_root->a);
-  EXPECT_NE(cloned_root->a->b, original_root->a->b);
-  EXPECT_NE(cloned_root->b, original_root->b);
-  EXPECT_NE(cloned_root->b->a, original_root->b->a);
-  EXPECT_NE(cloned_root->b->b, original_root->b->b);
-  EXPECT_NE(cloned_root->c, original_root->c);
+    EXPECT_NE(cloned_root->a, original_root->a);
+    EXPECT_NE(cloned_root->a->b, original_root->a->b);
+    EXPECT_NE(cloned_root->b, original_root->b);
+    EXPECT_NE(cloned_root->b->a, original_root->b->a);
+    EXPECT_NE(cloned_root->b->b, original_root->b->b);
+    EXPECT_NE(cloned_root->c, original_root->c);
 
-  EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
-  EXPECT_EQ(cloned_root->a->name, cloned.Symbols().Get("a"));
-  EXPECT_EQ(cloned_root->a->b->name, cloned.Symbols().Get("a->b"));
-  EXPECT_EQ(cloned_root->b->name, cloned.Symbols().Get("b"));
-  EXPECT_EQ(cloned_root->b->b->name, cloned.Symbols().Get("b->b"));
+    EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
+    EXPECT_EQ(cloned_root->a->name, cloned.Symbols().Get("a"));
+    EXPECT_EQ(cloned_root->a->b->name, cloned.Symbols().Get("a->b"));
+    EXPECT_EQ(cloned_root->b->name, cloned.Symbols().Get("b"));
+    EXPECT_EQ(cloned_root->b->b->name, cloned.Symbols().Get("b->b"));
 
-  EXPECT_NE(cloned_root->b->a, cloned_root->a);  // De-aliased
-  EXPECT_NE(cloned_root->c, cloned_root->b);     // De-aliased
+    EXPECT_NE(cloned_root->b->a, cloned_root->a);  // De-aliased
+    EXPECT_NE(cloned_root->c, cloned_root->b);     // De-aliased
 
-  EXPECT_EQ(cloned_root->b->a->name, cloned_root->a->name);
-  EXPECT_EQ(cloned_root->c->name, cloned_root->b->name);
+    EXPECT_EQ(cloned_root->b->a->name, cloned_root->a->name);
+    EXPECT_EQ(cloned_root->c->name, cloned_root->b->name);
 }
 
 TEST_F(CloneContextNodeTest, CloneWithReplaceAll_Cloneable) {
-  Allocator alloc;
+    Allocator alloc;
 
-  ProgramBuilder builder;
-  Node* original_root;
-  {
-    auto* a_b = alloc.Create<Replaceable>(builder.Symbols().New("a->b"));
-    auto* a = alloc.Create<Node>(builder.Symbols().New("a"), nullptr, a_b);
-    auto* b_a = a;  // Aliased
-    auto* b =
-        alloc.Create<Replaceable>(builder.Symbols().New("b"), b_a, nullptr);
-    auto* c = b;  // Aliased
-    original_root = alloc.Create<Node>(builder.Symbols().New("root"), a, b, c);
-  }
-  Program original(std::move(builder));
+    ProgramBuilder builder;
+    Node* original_root;
+    {
+        auto* a_b = alloc.Create<Replaceable>(builder.Symbols().New("a->b"));
+        auto* a = alloc.Create<Node>(builder.Symbols().New("a"), nullptr, a_b);
+        auto* b_a = a;  // Aliased
+        auto* b = alloc.Create<Replaceable>(builder.Symbols().New("b"), b_a, nullptr);
+        auto* c = b;  // Aliased
+        original_root = alloc.Create<Node>(builder.Symbols().New("root"), a, b, c);
+    }
+    Program original(std::move(builder));
 
-  //                          root
-  //        ╭──────────────────┼──────────────────╮
-  //       (a)                (b)                (c)
-  //        N  <──────┐        R  <───────────────┘
-  //   ╭────┼────╮    │   ╭────┼────╮
-  //  (a)  (b)  (c)   │  (a)  (b)  (c)
-  //        R         └───┘
-  //
-  // N: Node
-  // R: Replaceable
+    //                          root
+    //        ╭──────────────────┼──────────────────╮
+    //       (a)                (b)                (c)
+    //        N  <──────┐        R  <───────────────┘
+    //   ╭────┼────╮    │   ╭────┼────╮
+    //  (a)  (b)  (c)   │  (a)  (b)  (c)
+    //        R         └───┘
+    //
+    // N: Node
+    // R: Replaceable
 
-  ProgramBuilder cloned;
+    ProgramBuilder cloned;
 
-  CloneContext ctx(&cloned, &original);
-  ctx.ReplaceAll([&](const Replaceable* in) {
-    auto out_name = cloned.Symbols().Register(
-        "replacement:" + original.Symbols().NameFor(in->name));
-    auto b_name = cloned.Symbols().Register(
-        "replacement-child:" + original.Symbols().NameFor(in->name));
-    auto* out = alloc.Create<Replacement>(out_name);
-    out->b = alloc.Create<Node>(b_name);
-    out->c = ctx.Clone(in->a);
-    return out;
-  });
-  auto* cloned_root = ctx.Clone(original_root);
+    CloneContext ctx(&cloned, &original);
+    ctx.ReplaceAll([&](const Replaceable* in) {
+        auto out_name =
+            cloned.Symbols().Register("replacement:" + original.Symbols().NameFor(in->name));
+        auto b_name =
+            cloned.Symbols().Register("replacement-child:" + original.Symbols().NameFor(in->name));
+        auto* out = alloc.Create<Replacement>(out_name);
+        out->b = alloc.Create<Node>(b_name);
+        out->c = ctx.Clone(in->a);
+        return out;
+    });
+    auto* cloned_root = ctx.Clone(original_root);
 
-  //                         root
-  //        ╭─────────────────┼──────────────────╮
-  //       (a)               (b)                (c)
-  //        N  <──────┐       R  <───────────────┘
-  //   ╭────┼────╮    │  ╭────┼────╮
-  //  (a)  (b)  (c)   │ (a)  (b)  (c)
-  //        R         │       N    |
-  //   ╭────┼────╮    └────────────┘
-  //  (a)  (b)  (c)
-  //        N
-  //
-  // N: Node
-  // R: Replacement
+    //                         root
+    //        ╭─────────────────┼──────────────────╮
+    //       (a)               (b)                (c)
+    //        N  <──────┐       R  <───────────────┘
+    //   ╭────┼────╮    │  ╭────┼────╮
+    //  (a)  (b)  (c)   │ (a)  (b)  (c)
+    //        R         │       N    |
+    //   ╭────┼────╮    └────────────┘
+    //  (a)  (b)  (c)
+    //        N
+    //
+    // N: Node
+    // R: Replacement
 
-  EXPECT_NE(cloned_root->a, nullptr);
-  EXPECT_EQ(cloned_root->a->a, nullptr);
-  EXPECT_NE(cloned_root->a->b, nullptr);     // Replaced
-  EXPECT_EQ(cloned_root->a->b->a, nullptr);  // From replacement
-  EXPECT_NE(cloned_root->a->b->b, nullptr);  // From replacement
-  EXPECT_EQ(cloned_root->a->b->c, nullptr);  // From replacement
-  EXPECT_EQ(cloned_root->a->c, nullptr);
-  EXPECT_NE(cloned_root->b, nullptr);
-  EXPECT_EQ(cloned_root->b->a, nullptr);  // From replacement
-  EXPECT_NE(cloned_root->b->b, nullptr);  // From replacement
-  EXPECT_NE(cloned_root->b->c, nullptr);  // From replacement
-  EXPECT_NE(cloned_root->c, nullptr);
+    EXPECT_NE(cloned_root->a, nullptr);
+    EXPECT_EQ(cloned_root->a->a, nullptr);
+    EXPECT_NE(cloned_root->a->b, nullptr);     // Replaced
+    EXPECT_EQ(cloned_root->a->b->a, nullptr);  // From replacement
+    EXPECT_NE(cloned_root->a->b->b, nullptr);  // From replacement
+    EXPECT_EQ(cloned_root->a->b->c, nullptr);  // From replacement
+    EXPECT_EQ(cloned_root->a->c, nullptr);
+    EXPECT_NE(cloned_root->b, nullptr);
+    EXPECT_EQ(cloned_root->b->a, nullptr);  // From replacement
+    EXPECT_NE(cloned_root->b->b, nullptr);  // From replacement
+    EXPECT_NE(cloned_root->b->c, nullptr);  // From replacement
+    EXPECT_NE(cloned_root->c, nullptr);
 
-  EXPECT_NE(cloned_root->a, original_root->a);
-  EXPECT_NE(cloned_root->a->b, original_root->a->b);
-  EXPECT_NE(cloned_root->b, original_root->b);
-  EXPECT_NE(cloned_root->b->a, original_root->b->a);
-  EXPECT_NE(cloned_root->c, original_root->c);
+    EXPECT_NE(cloned_root->a, original_root->a);
+    EXPECT_NE(cloned_root->a->b, original_root->a->b);
+    EXPECT_NE(cloned_root->b, original_root->b);
+    EXPECT_NE(cloned_root->b->a, original_root->b->a);
+    EXPECT_NE(cloned_root->c, original_root->c);
 
-  EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
-  EXPECT_EQ(cloned_root->a->name, cloned.Symbols().Get("a"));
-  EXPECT_EQ(cloned_root->a->b->name, cloned.Symbols().Get("replacement:a->b"));
-  EXPECT_EQ(cloned_root->a->b->b->name,
-            cloned.Symbols().Get("replacement-child:a->b"));
-  EXPECT_EQ(cloned_root->b->name, cloned.Symbols().Get("replacement:b"));
-  EXPECT_EQ(cloned_root->b->b->name,
-            cloned.Symbols().Get("replacement-child:b"));
+    EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
+    EXPECT_EQ(cloned_root->a->name, cloned.Symbols().Get("a"));
+    EXPECT_EQ(cloned_root->a->b->name, cloned.Symbols().Get("replacement:a->b"));
+    EXPECT_EQ(cloned_root->a->b->b->name, cloned.Symbols().Get("replacement-child:a->b"));
+    EXPECT_EQ(cloned_root->b->name, cloned.Symbols().Get("replacement:b"));
+    EXPECT_EQ(cloned_root->b->b->name, cloned.Symbols().Get("replacement-child:b"));
 
-  EXPECT_NE(cloned_root->b->c, cloned_root->a);  // De-aliased
-  EXPECT_NE(cloned_root->c, cloned_root->b);     // De-aliased
+    EXPECT_NE(cloned_root->b->c, cloned_root->a);  // De-aliased
+    EXPECT_NE(cloned_root->c, cloned_root->b);     // De-aliased
 
-  EXPECT_EQ(cloned_root->b->c->name, cloned_root->a->name);
-  EXPECT_EQ(cloned_root->c->name, cloned_root->b->name);
+    EXPECT_EQ(cloned_root->b->c->name, cloned_root->a->name);
+    EXPECT_EQ(cloned_root->c->name, cloned_root->b->name);
 
-  EXPECT_FALSE(Is<Replacement>(cloned_root->a));
-  EXPECT_TRUE(Is<Replacement>(cloned_root->a->b));
-  EXPECT_FALSE(Is<Replacement>(cloned_root->a->b->b));
-  EXPECT_TRUE(Is<Replacement>(cloned_root->b));
-  EXPECT_FALSE(Is<Replacement>(cloned_root->b->b));
+    EXPECT_FALSE(Is<Replacement>(cloned_root->a));
+    EXPECT_TRUE(Is<Replacement>(cloned_root->a->b));
+    EXPECT_FALSE(Is<Replacement>(cloned_root->a->b->b));
+    EXPECT_TRUE(Is<Replacement>(cloned_root->b));
+    EXPECT_FALSE(Is<Replacement>(cloned_root->b->b));
 }
 
 TEST_F(CloneContextNodeTest, CloneWithReplaceAll_Symbols) {
-  Allocator alloc;
+    Allocator alloc;
 
-  ProgramBuilder builder;
-  Node* original_root;
-  {
-    auto* a_b = alloc.Create<Node>(builder.Symbols().New("a->b"));
-    auto* a = alloc.Create<Node>(builder.Symbols().New("a"), nullptr, a_b);
-    auto* b_a = a;  // Aliased
-    auto* b_b = alloc.Create<Node>(builder.Symbols().New("b->b"));
-    auto* b = alloc.Create<Node>(builder.Symbols().New("b"), b_a, b_b);
-    auto* c = b;  // Aliased
-    original_root = alloc.Create<Node>(builder.Symbols().New("root"), a, b, c);
-  }
-  Program original(std::move(builder));
+    ProgramBuilder builder;
+    Node* original_root;
+    {
+        auto* a_b = alloc.Create<Node>(builder.Symbols().New("a->b"));
+        auto* a = alloc.Create<Node>(builder.Symbols().New("a"), nullptr, a_b);
+        auto* b_a = a;  // Aliased
+        auto* b_b = alloc.Create<Node>(builder.Symbols().New("b->b"));
+        auto* b = alloc.Create<Node>(builder.Symbols().New("b"), b_a, b_b);
+        auto* c = b;  // Aliased
+        original_root = alloc.Create<Node>(builder.Symbols().New("root"), a, b, c);
+    }
+    Program original(std::move(builder));
 
-  //                          root
-  //        ╭──────────────────┼──────────────────╮
-  //       (a)                (b)                (c)
-  //        N  <──────┐        N  <───────────────┘
-  //   ╭────┼────╮    │   ╭────┼────╮
-  //  (a)  (b)  (c)   │  (a)  (b)  (c)
-  //        N         └───┘    N
-  //
-  // N: Node
+    //                          root
+    //        ╭──────────────────┼──────────────────╮
+    //       (a)                (b)                (c)
+    //        N  <──────┐        N  <───────────────┘
+    //   ╭────┼────╮    │   ╭────┼────╮
+    //  (a)  (b)  (c)   │  (a)  (b)  (c)
+    //        N         └───┘    N
+    //
+    // N: Node
 
-  ProgramBuilder cloned;
-  auto* cloned_root = CloneContext(&cloned, &original, false)
-                          .ReplaceAll([&](Symbol sym) {
-                            auto in = original.Symbols().NameFor(sym);
-                            auto out = "transformed<" + in + ">";
-                            return cloned.Symbols().New(out);
-                          })
-                          .Clone(original_root);
+    ProgramBuilder cloned;
+    auto* cloned_root = CloneContext(&cloned, &original, false)
+                            .ReplaceAll([&](Symbol sym) {
+                                auto in = original.Symbols().NameFor(sym);
+                                auto out = "transformed<" + in + ">";
+                                return cloned.Symbols().New(out);
+                            })
+                            .Clone(original_root);
 
-  EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("transformed<root>"));
-  EXPECT_EQ(cloned_root->a->name, cloned.Symbols().Get("transformed<a>"));
-  EXPECT_EQ(cloned_root->a->b->name, cloned.Symbols().Get("transformed<a->b>"));
-  EXPECT_EQ(cloned_root->b->name, cloned.Symbols().Get("transformed<b>"));
-  EXPECT_EQ(cloned_root->b->b->name, cloned.Symbols().Get("transformed<b->b>"));
+    EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("transformed<root>"));
+    EXPECT_EQ(cloned_root->a->name, cloned.Symbols().Get("transformed<a>"));
+    EXPECT_EQ(cloned_root->a->b->name, cloned.Symbols().Get("transformed<a->b>"));
+    EXPECT_EQ(cloned_root->b->name, cloned.Symbols().Get("transformed<b>"));
+    EXPECT_EQ(cloned_root->b->b->name, cloned.Symbols().Get("transformed<b->b>"));
 }
 
 TEST_F(CloneContextNodeTest, CloneWithoutTransform) {
-  Allocator a;
+    Allocator a;
 
-  ProgramBuilder builder;
-  auto* original_node = a.Create<Node>(builder.Symbols().New("root"));
-  Program original(std::move(builder));
+    ProgramBuilder builder;
+    auto* original_node = a.Create<Node>(builder.Symbols().New("root"));
+    Program original(std::move(builder));
 
-  ProgramBuilder cloned;
-  CloneContext ctx(&cloned, &original);
-  ctx.ReplaceAll([&](const Node*) {
-    return a.Create<Replacement>(builder.Symbols().New("<unexpected-node>"));
-  });
+    ProgramBuilder cloned;
+    CloneContext ctx(&cloned, &original);
+    ctx.ReplaceAll([&](const Node*) {
+        return a.Create<Replacement>(builder.Symbols().New("<unexpected-node>"));
+    });
 
-  auto* cloned_node = ctx.CloneWithoutTransform(original_node);
-  EXPECT_NE(cloned_node, original_node);
-  EXPECT_EQ(cloned_node->name, cloned.Symbols().Get("root"));
+    auto* cloned_node = ctx.CloneWithoutTransform(original_node);
+    EXPECT_NE(cloned_node, original_node);
+    EXPECT_EQ(cloned_node->name, cloned.Symbols().Get("root"));
 }
 
 TEST_F(CloneContextNodeTest, CloneWithReplacePointer) {
-  Allocator a;
+    Allocator a;
 
-  ProgramBuilder builder;
-  auto* original_root = a.Create<Node>(builder.Symbols().New("root"));
-  original_root->a = a.Create<Node>(builder.Symbols().New("a"));
-  original_root->b = a.Create<Node>(builder.Symbols().New("b"));
-  original_root->c = a.Create<Node>(builder.Symbols().New("c"));
-  Program original(std::move(builder));
+    ProgramBuilder builder;
+    auto* original_root = a.Create<Node>(builder.Symbols().New("root"));
+    original_root->a = a.Create<Node>(builder.Symbols().New("a"));
+    original_root->b = a.Create<Node>(builder.Symbols().New("b"));
+    original_root->c = a.Create<Node>(builder.Symbols().New("c"));
+    Program original(std::move(builder));
 
-  //                          root
-  //        ╭──────────────────┼──────────────────╮
-  //       (a)                (b)                (c)
-  //                        Replaced
+    //                          root
+    //        ╭──────────────────┼──────────────────╮
+    //       (a)                (b)                (c)
+    //                        Replaced
 
-  ProgramBuilder cloned;
-  auto* replacement = a.Create<Node>(cloned.Symbols().New("replacement"));
+    ProgramBuilder cloned;
+    auto* replacement = a.Create<Node>(cloned.Symbols().New("replacement"));
 
-  auto* cloned_root = CloneContext(&cloned, &original)
-                          .Replace(original_root->b, replacement)
-                          .Clone(original_root);
+    auto* cloned_root = CloneContext(&cloned, &original)
+                            .Replace(original_root->b, replacement)
+                            .Clone(original_root);
 
-  EXPECT_NE(cloned_root->a, replacement);
-  EXPECT_EQ(cloned_root->b, replacement);
-  EXPECT_NE(cloned_root->c, replacement);
+    EXPECT_NE(cloned_root->a, replacement);
+    EXPECT_EQ(cloned_root->b, replacement);
+    EXPECT_NE(cloned_root->c, replacement);
 
-  EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
-  EXPECT_EQ(cloned_root->a->name, cloned.Symbols().Get("a"));
-  EXPECT_EQ(cloned_root->b->name, cloned.Symbols().Get("replacement"));
-  EXPECT_EQ(cloned_root->c->name, cloned.Symbols().Get("c"));
+    EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
+    EXPECT_EQ(cloned_root->a->name, cloned.Symbols().Get("a"));
+    EXPECT_EQ(cloned_root->b->name, cloned.Symbols().Get("replacement"));
+    EXPECT_EQ(cloned_root->c->name, cloned.Symbols().Get("c"));
 }
 
 TEST_F(CloneContextNodeTest, CloneWithReplaceFunction) {
-  Allocator a;
+    Allocator a;
 
-  ProgramBuilder builder;
-  auto* original_root = a.Create<Node>(builder.Symbols().New("root"));
-  original_root->a = a.Create<Node>(builder.Symbols().New("a"));
-  original_root->b = a.Create<Node>(builder.Symbols().New("b"));
-  original_root->c = a.Create<Node>(builder.Symbols().New("c"));
-  Program original(std::move(builder));
+    ProgramBuilder builder;
+    auto* original_root = a.Create<Node>(builder.Symbols().New("root"));
+    original_root->a = a.Create<Node>(builder.Symbols().New("a"));
+    original_root->b = a.Create<Node>(builder.Symbols().New("b"));
+    original_root->c = a.Create<Node>(builder.Symbols().New("c"));
+    Program original(std::move(builder));
 
-  //                          root
-  //        ╭──────────────────┼──────────────────╮
-  //       (a)                (b)                (c)
-  //                        Replaced
+    //                          root
+    //        ╭──────────────────┼──────────────────╮
+    //       (a)                (b)                (c)
+    //                        Replaced
 
-  ProgramBuilder cloned;
-  auto* replacement = a.Create<Node>(cloned.Symbols().New("replacement"));
+    ProgramBuilder cloned;
+    auto* replacement = a.Create<Node>(cloned.Symbols().New("replacement"));
 
-  auto* cloned_root =
-      CloneContext(&cloned, &original)
-          .Replace(original_root->b, [=] { return replacement; })
-          .Clone(original_root);
+    auto* cloned_root = CloneContext(&cloned, &original)
+                            .Replace(original_root->b, [=] { return replacement; })
+                            .Clone(original_root);
 
-  EXPECT_NE(cloned_root->a, replacement);
-  EXPECT_EQ(cloned_root->b, replacement);
-  EXPECT_NE(cloned_root->c, replacement);
+    EXPECT_NE(cloned_root->a, replacement);
+    EXPECT_EQ(cloned_root->b, replacement);
+    EXPECT_NE(cloned_root->c, replacement);
 
-  EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
-  EXPECT_EQ(cloned_root->a->name, cloned.Symbols().Get("a"));
-  EXPECT_EQ(cloned_root->b->name, cloned.Symbols().Get("replacement"));
-  EXPECT_EQ(cloned_root->c->name, cloned.Symbols().Get("c"));
+    EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
+    EXPECT_EQ(cloned_root->a->name, cloned.Symbols().Get("a"));
+    EXPECT_EQ(cloned_root->b->name, cloned.Symbols().Get("replacement"));
+    EXPECT_EQ(cloned_root->c->name, cloned.Symbols().Get("c"));
 }
 
 TEST_F(CloneContextNodeTest, CloneWithRemove) {
-  Allocator a;
+    Allocator a;
 
-  ProgramBuilder builder;
-  auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
-  original_root->vec = {
-      a.Create<Node>(builder.Symbols().Register("a")),
-      a.Create<Node>(builder.Symbols().Register("b")),
-      a.Create<Node>(builder.Symbols().Register("c")),
-  };
-  Program original(std::move(builder));
+    ProgramBuilder builder;
+    auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
+    original_root->vec = {
+        a.Create<Node>(builder.Symbols().Register("a")),
+        a.Create<Node>(builder.Symbols().Register("b")),
+        a.Create<Node>(builder.Symbols().Register("c")),
+    };
+    Program original(std::move(builder));
 
-  ProgramBuilder cloned;
-  auto* cloned_root = CloneContext(&cloned, &original)
-                          .Remove(original_root->vec, original_root->vec[1])
-                          .Clone(original_root);
+    ProgramBuilder cloned;
+    auto* cloned_root = CloneContext(&cloned, &original)
+                            .Remove(original_root->vec, original_root->vec[1])
+                            .Clone(original_root);
 
-  EXPECT_EQ(cloned_root->vec.size(), 2u);
+    EXPECT_EQ(cloned_root->vec.size(), 2u);
 
-  EXPECT_NE(cloned_root->vec[0], cloned_root->a);
-  EXPECT_NE(cloned_root->vec[1], cloned_root->c);
+    EXPECT_NE(cloned_root->vec[0], cloned_root->a);
+    EXPECT_NE(cloned_root->vec[1], cloned_root->c);
 
-  EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
-  EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
-  EXPECT_EQ(cloned_root->vec[1]->name, cloned.Symbols().Get("c"));
+    EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
+    EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
+    EXPECT_EQ(cloned_root->vec[1]->name, cloned.Symbols().Get("c"));
 }
 
 TEST_F(CloneContextNodeTest, CloneWithInsertFront) {
-  Allocator a;
+    Allocator a;
 
-  ProgramBuilder builder;
-  auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
-  original_root->vec = {
-      a.Create<Node>(builder.Symbols().Register("a")),
-      a.Create<Node>(builder.Symbols().Register("b")),
-      a.Create<Node>(builder.Symbols().Register("c")),
-  };
-  Program original(std::move(builder));
+    ProgramBuilder builder;
+    auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
+    original_root->vec = {
+        a.Create<Node>(builder.Symbols().Register("a")),
+        a.Create<Node>(builder.Symbols().Register("b")),
+        a.Create<Node>(builder.Symbols().Register("c")),
+    };
+    Program original(std::move(builder));
 
-  ProgramBuilder cloned;
-  auto* insertion = a.Create<Node>(cloned.Symbols().New("insertion"));
+    ProgramBuilder cloned;
+    auto* insertion = a.Create<Node>(cloned.Symbols().New("insertion"));
 
-  auto* cloned_root = CloneContext(&cloned, &original)
-                          .InsertFront(original_root->vec, insertion)
-                          .Clone(original_root);
+    auto* cloned_root = CloneContext(&cloned, &original)
+                            .InsertFront(original_root->vec, insertion)
+                            .Clone(original_root);
 
-  EXPECT_EQ(cloned_root->vec.size(), 4u);
+    EXPECT_EQ(cloned_root->vec.size(), 4u);
 
-  EXPECT_NE(cloned_root->vec[0], cloned_root->a);
-  EXPECT_NE(cloned_root->vec[1], cloned_root->b);
-  EXPECT_NE(cloned_root->vec[2], cloned_root->c);
+    EXPECT_NE(cloned_root->vec[0], cloned_root->a);
+    EXPECT_NE(cloned_root->vec[1], cloned_root->b);
+    EXPECT_NE(cloned_root->vec[2], cloned_root->c);
 
-  EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
-  EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("insertion"));
-  EXPECT_EQ(cloned_root->vec[1]->name, cloned.Symbols().Get("a"));
-  EXPECT_EQ(cloned_root->vec[2]->name, cloned.Symbols().Get("b"));
-  EXPECT_EQ(cloned_root->vec[3]->name, cloned.Symbols().Get("c"));
+    EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
+    EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("insertion"));
+    EXPECT_EQ(cloned_root->vec[1]->name, cloned.Symbols().Get("a"));
+    EXPECT_EQ(cloned_root->vec[2]->name, cloned.Symbols().Get("b"));
+    EXPECT_EQ(cloned_root->vec[3]->name, cloned.Symbols().Get("c"));
 }
 
 TEST_F(CloneContextNodeTest, CloneWithInsertFront_Empty) {
-  Allocator a;
+    Allocator a;
 
-  ProgramBuilder builder;
-  auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
-  original_root->vec = {};
-  Program original(std::move(builder));
+    ProgramBuilder builder;
+    auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
+    original_root->vec = {};
+    Program original(std::move(builder));
 
-  ProgramBuilder cloned;
-  auto* insertion = a.Create<Node>(cloned.Symbols().New("insertion"));
+    ProgramBuilder cloned;
+    auto* insertion = a.Create<Node>(cloned.Symbols().New("insertion"));
 
-  auto* cloned_root = CloneContext(&cloned, &original)
-                          .InsertFront(original_root->vec, insertion)
-                          .Clone(original_root);
+    auto* cloned_root = CloneContext(&cloned, &original)
+                            .InsertFront(original_root->vec, insertion)
+                            .Clone(original_root);
 
-  EXPECT_EQ(cloned_root->vec.size(), 1u);
+    EXPECT_EQ(cloned_root->vec.size(), 1u);
 
-  EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
-  EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("insertion"));
+    EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
+    EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("insertion"));
 }
 
 TEST_F(CloneContextNodeTest, CloneWithInsertBack) {
-  Allocator a;
+    Allocator a;
 
-  ProgramBuilder builder;
-  auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
-  original_root->vec = {
-      a.Create<Node>(builder.Symbols().Register("a")),
-      a.Create<Node>(builder.Symbols().Register("b")),
-      a.Create<Node>(builder.Symbols().Register("c")),
-  };
-  Program original(std::move(builder));
+    ProgramBuilder builder;
+    auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
+    original_root->vec = {
+        a.Create<Node>(builder.Symbols().Register("a")),
+        a.Create<Node>(builder.Symbols().Register("b")),
+        a.Create<Node>(builder.Symbols().Register("c")),
+    };
+    Program original(std::move(builder));
 
-  ProgramBuilder cloned;
-  auto* insertion = a.Create<Node>(cloned.Symbols().New("insertion"));
+    ProgramBuilder cloned;
+    auto* insertion = a.Create<Node>(cloned.Symbols().New("insertion"));
 
-  auto* cloned_root = CloneContext(&cloned, &original)
-                          .InsertBack(original_root->vec, insertion)
-                          .Clone(original_root);
+    auto* cloned_root = CloneContext(&cloned, &original)
+                            .InsertBack(original_root->vec, insertion)
+                            .Clone(original_root);
 
-  EXPECT_EQ(cloned_root->vec.size(), 4u);
+    EXPECT_EQ(cloned_root->vec.size(), 4u);
 
-  EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
-  EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
-  EXPECT_EQ(cloned_root->vec[1]->name, cloned.Symbols().Get("b"));
-  EXPECT_EQ(cloned_root->vec[2]->name, cloned.Symbols().Get("c"));
-  EXPECT_EQ(cloned_root->vec[3]->name, cloned.Symbols().Get("insertion"));
+    EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
+    EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
+    EXPECT_EQ(cloned_root->vec[1]->name, cloned.Symbols().Get("b"));
+    EXPECT_EQ(cloned_root->vec[2]->name, cloned.Symbols().Get("c"));
+    EXPECT_EQ(cloned_root->vec[3]->name, cloned.Symbols().Get("insertion"));
 }
 
 TEST_F(CloneContextNodeTest, CloneWithInsertBack_Empty) {
-  Allocator a;
+    Allocator a;
 
-  ProgramBuilder builder;
-  auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
-  original_root->vec = {};
-  Program original(std::move(builder));
+    ProgramBuilder builder;
+    auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
+    original_root->vec = {};
+    Program original(std::move(builder));
 
-  ProgramBuilder cloned;
-  auto* insertion = a.Create<Node>(cloned.Symbols().New("insertion"));
+    ProgramBuilder cloned;
+    auto* insertion = a.Create<Node>(cloned.Symbols().New("insertion"));
 
-  auto* cloned_root = CloneContext(&cloned, &original)
-                          .InsertBack(original_root->vec, insertion)
-                          .Clone(original_root);
+    auto* cloned_root = CloneContext(&cloned, &original)
+                            .InsertBack(original_root->vec, insertion)
+                            .Clone(original_root);
 
-  EXPECT_EQ(cloned_root->vec.size(), 1u);
+    EXPECT_EQ(cloned_root->vec.size(), 1u);
 
-  EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
-  EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("insertion"));
+    EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
+    EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("insertion"));
 }
 
 TEST_F(CloneContextNodeTest, CloneWithInsertFrontAndBack_Empty) {
-  Allocator a;
+    Allocator a;
 
-  ProgramBuilder builder;
-  auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
-  original_root->vec = {};
-  Program original(std::move(builder));
+    ProgramBuilder builder;
+    auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
+    original_root->vec = {};
+    Program original(std::move(builder));
 
-  ProgramBuilder cloned;
-  auto* insertion_front =
-      a.Create<Node>(cloned.Symbols().New("insertion_front"));
-  auto* insertion_back = a.Create<Node>(cloned.Symbols().New("insertion_back"));
+    ProgramBuilder cloned;
+    auto* insertion_front = a.Create<Node>(cloned.Symbols().New("insertion_front"));
+    auto* insertion_back = a.Create<Node>(cloned.Symbols().New("insertion_back"));
 
-  auto* cloned_root = CloneContext(&cloned, &original)
-                          .InsertBack(original_root->vec, insertion_back)
-                          .InsertFront(original_root->vec, insertion_front)
-                          .Clone(original_root);
+    auto* cloned_root = CloneContext(&cloned, &original)
+                            .InsertBack(original_root->vec, insertion_back)
+                            .InsertFront(original_root->vec, insertion_front)
+                            .Clone(original_root);
 
-  EXPECT_EQ(cloned_root->vec.size(), 2u);
+    EXPECT_EQ(cloned_root->vec.size(), 2u);
 
-  EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
-  EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("insertion_front"));
-  EXPECT_EQ(cloned_root->vec[1]->name, cloned.Symbols().Get("insertion_back"));
+    EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
+    EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("insertion_front"));
+    EXPECT_EQ(cloned_root->vec[1]->name, cloned.Symbols().Get("insertion_back"));
 }
 
 TEST_F(CloneContextNodeTest, CloneWithInsertBefore) {
-  Allocator a;
+    Allocator a;
 
-  ProgramBuilder builder;
-  auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
-  original_root->vec = {
-      a.Create<Node>(builder.Symbols().Register("a")),
-      a.Create<Node>(builder.Symbols().Register("b")),
-      a.Create<Node>(builder.Symbols().Register("c")),
-  };
-  Program original(std::move(builder));
+    ProgramBuilder builder;
+    auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
+    original_root->vec = {
+        a.Create<Node>(builder.Symbols().Register("a")),
+        a.Create<Node>(builder.Symbols().Register("b")),
+        a.Create<Node>(builder.Symbols().Register("c")),
+    };
+    Program original(std::move(builder));
 
-  ProgramBuilder cloned;
-  auto* insertion = a.Create<Node>(cloned.Symbols().New("insertion"));
+    ProgramBuilder cloned;
+    auto* insertion = a.Create<Node>(cloned.Symbols().New("insertion"));
 
-  auto* cloned_root =
-      CloneContext(&cloned, &original)
-          .InsertBefore(original_root->vec, original_root->vec[1], insertion)
-          .Clone(original_root);
+    auto* cloned_root = CloneContext(&cloned, &original)
+                            .InsertBefore(original_root->vec, original_root->vec[1], insertion)
+                            .Clone(original_root);
 
-  EXPECT_EQ(cloned_root->vec.size(), 4u);
+    EXPECT_EQ(cloned_root->vec.size(), 4u);
 
-  EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
-  EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
-  EXPECT_EQ(cloned_root->vec[1]->name, cloned.Symbols().Get("insertion"));
-  EXPECT_EQ(cloned_root->vec[2]->name, cloned.Symbols().Get("b"));
-  EXPECT_EQ(cloned_root->vec[3]->name, cloned.Symbols().Get("c"));
+    EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
+    EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
+    EXPECT_EQ(cloned_root->vec[1]->name, cloned.Symbols().Get("insertion"));
+    EXPECT_EQ(cloned_root->vec[2]->name, cloned.Symbols().Get("b"));
+    EXPECT_EQ(cloned_root->vec[3]->name, cloned.Symbols().Get("c"));
 }
 
 TEST_F(CloneContextNodeTest, CloneWithInsertAfter) {
-  Allocator a;
+    Allocator a;
 
-  ProgramBuilder builder;
-  auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
-  original_root->vec = {
-      a.Create<Node>(builder.Symbols().Register("a")),
-      a.Create<Node>(builder.Symbols().Register("b")),
-      a.Create<Node>(builder.Symbols().Register("c")),
-  };
-  Program original(std::move(builder));
+    ProgramBuilder builder;
+    auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
+    original_root->vec = {
+        a.Create<Node>(builder.Symbols().Register("a")),
+        a.Create<Node>(builder.Symbols().Register("b")),
+        a.Create<Node>(builder.Symbols().Register("c")),
+    };
+    Program original(std::move(builder));
 
-  ProgramBuilder cloned;
-  auto* insertion = a.Create<Node>(cloned.Symbols().New("insertion"));
+    ProgramBuilder cloned;
+    auto* insertion = a.Create<Node>(cloned.Symbols().New("insertion"));
 
-  auto* cloned_root =
-      CloneContext(&cloned, &original)
-          .InsertAfter(original_root->vec, original_root->vec[1], insertion)
-          .Clone(original_root);
+    auto* cloned_root = CloneContext(&cloned, &original)
+                            .InsertAfter(original_root->vec, original_root->vec[1], insertion)
+                            .Clone(original_root);
 
-  EXPECT_EQ(cloned_root->vec.size(), 4u);
+    EXPECT_EQ(cloned_root->vec.size(), 4u);
 
-  EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
-  EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
-  EXPECT_EQ(cloned_root->vec[1]->name, cloned.Symbols().Get("b"));
-  EXPECT_EQ(cloned_root->vec[2]->name, cloned.Symbols().Get("insertion"));
-  EXPECT_EQ(cloned_root->vec[3]->name, cloned.Symbols().Get("c"));
+    EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
+    EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
+    EXPECT_EQ(cloned_root->vec[1]->name, cloned.Symbols().Get("b"));
+    EXPECT_EQ(cloned_root->vec[2]->name, cloned.Symbols().Get("insertion"));
+    EXPECT_EQ(cloned_root->vec[3]->name, cloned.Symbols().Get("c"));
 }
 
 TEST_F(CloneContextNodeTest, CloneWithInsertAfterInVectorNodeClone) {
-  Allocator a;
+    Allocator a;
 
-  ProgramBuilder builder;
-  auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
-  original_root->vec = {
-      a.Create<Node>(builder.Symbols().Register("a")),
-      a.Create<Replaceable>(builder.Symbols().Register("b")),
-      a.Create<Node>(builder.Symbols().Register("c")),
-  };
+    ProgramBuilder builder;
+    auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
+    original_root->vec = {
+        a.Create<Node>(builder.Symbols().Register("a")),
+        a.Create<Replaceable>(builder.Symbols().Register("b")),
+        a.Create<Node>(builder.Symbols().Register("c")),
+    };
 
-  Program original(std::move(builder));
+    Program original(std::move(builder));
 
-  ProgramBuilder cloned;
-  CloneContext ctx(&cloned, &original);
-  ctx.ReplaceAll([&](const Replaceable* r) {
-    auto* insertion = a.Create<Node>(cloned.Symbols().New("insertion"));
-    ctx.InsertAfter(original_root->vec, r, insertion);
-    return nullptr;
-  });
+    ProgramBuilder cloned;
+    CloneContext ctx(&cloned, &original);
+    ctx.ReplaceAll([&](const Replaceable* r) {
+        auto* insertion = a.Create<Node>(cloned.Symbols().New("insertion"));
+        ctx.InsertAfter(original_root->vec, r, insertion);
+        return nullptr;
+    });
 
-  auto* cloned_root = ctx.Clone(original_root);
+    auto* cloned_root = ctx.Clone(original_root);
 
-  EXPECT_EQ(cloned_root->vec.size(), 4u);
+    EXPECT_EQ(cloned_root->vec.size(), 4u);
 
-  EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
-  EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
-  EXPECT_EQ(cloned_root->vec[1]->name, cloned.Symbols().Get("b"));
-  EXPECT_EQ(cloned_root->vec[2]->name, cloned.Symbols().Get("insertion"));
-  EXPECT_EQ(cloned_root->vec[3]->name, cloned.Symbols().Get("c"));
+    EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
+    EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
+    EXPECT_EQ(cloned_root->vec[1]->name, cloned.Symbols().Get("b"));
+    EXPECT_EQ(cloned_root->vec[2]->name, cloned.Symbols().Get("insertion"));
+    EXPECT_EQ(cloned_root->vec[3]->name, cloned.Symbols().Get("c"));
 }
 
 TEST_F(CloneContextNodeTest, CloneWithInsertBackInVectorNodeClone) {
-  Allocator a;
+    Allocator a;
 
-  ProgramBuilder builder;
-  auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
-  original_root->vec = {
-      a.Create<Node>(builder.Symbols().Register("a")),
-      a.Create<Replaceable>(builder.Symbols().Register("b")),
-      a.Create<Node>(builder.Symbols().Register("c")),
-  };
+    ProgramBuilder builder;
+    auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
+    original_root->vec = {
+        a.Create<Node>(builder.Symbols().Register("a")),
+        a.Create<Replaceable>(builder.Symbols().Register("b")),
+        a.Create<Node>(builder.Symbols().Register("c")),
+    };
 
-  Program original(std::move(builder));
+    Program original(std::move(builder));
 
-  ProgramBuilder cloned;
-  CloneContext ctx(&cloned, &original);
-  ctx.ReplaceAll([&](const Replaceable* /*r*/) {
-    auto* insertion = a.Create<Node>(cloned.Symbols().New("insertion"));
-    ctx.InsertBack(original_root->vec, insertion);
-    return nullptr;
-  });
+    ProgramBuilder cloned;
+    CloneContext ctx(&cloned, &original);
+    ctx.ReplaceAll([&](const Replaceable* /*r*/) {
+        auto* insertion = a.Create<Node>(cloned.Symbols().New("insertion"));
+        ctx.InsertBack(original_root->vec, insertion);
+        return nullptr;
+    });
 
-  auto* cloned_root = ctx.Clone(original_root);
+    auto* cloned_root = ctx.Clone(original_root);
 
-  EXPECT_EQ(cloned_root->vec.size(), 4u);
+    EXPECT_EQ(cloned_root->vec.size(), 4u);
 
-  EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
-  EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
-  EXPECT_EQ(cloned_root->vec[1]->name, cloned.Symbols().Get("b"));
-  EXPECT_EQ(cloned_root->vec[2]->name, cloned.Symbols().Get("c"));
-  EXPECT_EQ(cloned_root->vec[3]->name, cloned.Symbols().Get("insertion"));
+    EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
+    EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
+    EXPECT_EQ(cloned_root->vec[1]->name, cloned.Symbols().Get("b"));
+    EXPECT_EQ(cloned_root->vec[2]->name, cloned.Symbols().Get("c"));
+    EXPECT_EQ(cloned_root->vec[3]->name, cloned.Symbols().Get("insertion"));
 }
 
 TEST_F(CloneContextNodeTest, CloneWithInsertBeforeAndAfterRemoved) {
-  Allocator a;
+    Allocator a;
 
-  ProgramBuilder builder;
-  auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
-  original_root->vec = {
-      a.Create<Node>(builder.Symbols().Register("a")),
-      a.Create<Node>(builder.Symbols().Register("b")),
-      a.Create<Node>(builder.Symbols().Register("c")),
-  };
-  Program original(std::move(builder));
+    ProgramBuilder builder;
+    auto* original_root = a.Create<Node>(builder.Symbols().Register("root"));
+    original_root->vec = {
+        a.Create<Node>(builder.Symbols().Register("a")),
+        a.Create<Node>(builder.Symbols().Register("b")),
+        a.Create<Node>(builder.Symbols().Register("c")),
+    };
+    Program original(std::move(builder));
 
-  ProgramBuilder cloned;
-  auto* insertion_before =
-      a.Create<Node>(cloned.Symbols().New("insertion_before"));
-  auto* insertion_after =
-      a.Create<Node>(cloned.Symbols().New("insertion_after"));
+    ProgramBuilder cloned;
+    auto* insertion_before = a.Create<Node>(cloned.Symbols().New("insertion_before"));
+    auto* insertion_after = a.Create<Node>(cloned.Symbols().New("insertion_after"));
 
-  auto* cloned_root = CloneContext(&cloned, &original)
-                          .InsertBefore(original_root->vec,
-                                        original_root->vec[1], insertion_before)
-                          .InsertAfter(original_root->vec,
-                                       original_root->vec[1], insertion_after)
-                          .Remove(original_root->vec, original_root->vec[1])
-                          .Clone(original_root);
+    auto* cloned_root =
+        CloneContext(&cloned, &original)
+            .InsertBefore(original_root->vec, original_root->vec[1], insertion_before)
+            .InsertAfter(original_root->vec, original_root->vec[1], insertion_after)
+            .Remove(original_root->vec, original_root->vec[1])
+            .Clone(original_root);
 
-  EXPECT_EQ(cloned_root->vec.size(), 4u);
+    EXPECT_EQ(cloned_root->vec.size(), 4u);
 
-  EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
-  EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
-  EXPECT_EQ(cloned_root->vec[1]->name,
-            cloned.Symbols().Get("insertion_before"));
-  EXPECT_EQ(cloned_root->vec[2]->name, cloned.Symbols().Get("insertion_after"));
-  EXPECT_EQ(cloned_root->vec[3]->name, cloned.Symbols().Get("c"));
+    EXPECT_EQ(cloned_root->name, cloned.Symbols().Get("root"));
+    EXPECT_EQ(cloned_root->vec[0]->name, cloned.Symbols().Get("a"));
+    EXPECT_EQ(cloned_root->vec[1]->name, cloned.Symbols().Get("insertion_before"));
+    EXPECT_EQ(cloned_root->vec[2]->name, cloned.Symbols().Get("insertion_after"));
+    EXPECT_EQ(cloned_root->vec[3]->name, cloned.Symbols().Get("c"));
 }
 
 TEST_F(CloneContextNodeTest, CloneIntoSameBuilder) {
-  ProgramBuilder builder;
-  CloneContext ctx(&builder);
-  Allocator allocator;
-  auto* original = allocator.Create<Node>(builder.Symbols().New());
-  auto* cloned_a = ctx.Clone(original);
-  auto* cloned_b = ctx.Clone(original);
-  EXPECT_NE(original, cloned_a);
-  EXPECT_NE(original, cloned_b);
+    ProgramBuilder builder;
+    CloneContext ctx(&builder);
+    Allocator allocator;
+    auto* original = allocator.Create<Node>(builder.Symbols().New());
+    auto* cloned_a = ctx.Clone(original);
+    auto* cloned_b = ctx.Clone(original);
+    EXPECT_NE(original, cloned_a);
+    EXPECT_NE(original, cloned_b);
 
-  EXPECT_NE(cloned_a, cloned_b);
+    EXPECT_NE(cloned_a, cloned_b);
 }
 
 TEST_F(CloneContextNodeTest, CloneWithReplaceAll_SameTypeTwice) {
-  std::string node_name = TypeInfo::Of<Node>().name;
+    std::string node_name = TypeInfo::Of<Node>().name;
 
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder cloned;
-        Program original;
-        CloneContext ctx(&cloned, &original);
-        ctx.ReplaceAll([](const Node*) { return nullptr; });
-        ctx.ReplaceAll([](const Node*) { return nullptr; });
-      },
-      "internal compiler error: ReplaceAll() called with a handler for type " +
-          node_name + " that is already handled by a handler for type " +
-          node_name);
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder cloned;
+            Program original;
+            CloneContext ctx(&cloned, &original);
+            ctx.ReplaceAll([](const Node*) { return nullptr; });
+            ctx.ReplaceAll([](const Node*) { return nullptr; });
+        },
+        "internal compiler error: ReplaceAll() called with a handler for type " + node_name +
+            " that is already handled by a handler for type " + node_name);
 }
 
 TEST_F(CloneContextNodeTest, CloneWithReplaceAll_BaseThenDerived) {
-  std::string node_name = TypeInfo::Of<Node>().name;
-  std::string replaceable_name = TypeInfo::Of<Replaceable>().name;
+    std::string node_name = TypeInfo::Of<Node>().name;
+    std::string replaceable_name = TypeInfo::Of<Replaceable>().name;
 
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder cloned;
-        Program original;
-        CloneContext ctx(&cloned, &original);
-        ctx.ReplaceAll([](const Node*) { return nullptr; });
-        ctx.ReplaceAll([](const Replaceable*) { return nullptr; });
-      },
-      "internal compiler error: ReplaceAll() called with a handler for type " +
-          replaceable_name + " that is already handled by a handler for type " +
-          node_name);
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder cloned;
+            Program original;
+            CloneContext ctx(&cloned, &original);
+            ctx.ReplaceAll([](const Node*) { return nullptr; });
+            ctx.ReplaceAll([](const Replaceable*) { return nullptr; });
+        },
+        "internal compiler error: ReplaceAll() called with a handler for type " + replaceable_name +
+            " that is already handled by a handler for type " + node_name);
 }
 
 TEST_F(CloneContextNodeTest, CloneWithReplaceAll_DerivedThenBase) {
-  std::string node_name = TypeInfo::Of<Node>().name;
-  std::string replaceable_name = TypeInfo::Of<Replaceable>().name;
+    std::string node_name = TypeInfo::Of<Node>().name;
+    std::string replaceable_name = TypeInfo::Of<Replaceable>().name;
 
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder cloned;
-        Program original;
-        CloneContext ctx(&cloned, &original);
-        ctx.ReplaceAll([](const Replaceable*) { return nullptr; });
-        ctx.ReplaceAll([](const Node*) { return nullptr; });
-      },
-      "internal compiler error: ReplaceAll() called with a handler for type " +
-          node_name + " that is already handled by a handler for type " +
-          replaceable_name);
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder cloned;
+            Program original;
+            CloneContext ctx(&cloned, &original);
+            ctx.ReplaceAll([](const Replaceable*) { return nullptr; });
+            ctx.ReplaceAll([](const Node*) { return nullptr; });
+        },
+        "internal compiler error: ReplaceAll() called with a handler for type " + node_name +
+            " that is already handled by a handler for type " + replaceable_name);
 }
 
 TEST_F(CloneContextNodeTest, CloneWithReplacePointer_WithNotANode) {
-  EXPECT_FATAL_FAILURE(
-      {
-        Allocator allocator;
-        ProgramBuilder builder;
-        auto* original_root =
-            allocator.Create<Node>(builder.Symbols().New("root"));
-        original_root->a = allocator.Create<Node>(builder.Symbols().New("a"));
-        original_root->b = allocator.Create<Node>(builder.Symbols().New("b"));
-        original_root->c = allocator.Create<Node>(builder.Symbols().New("c"));
-        Program original(std::move(builder));
+    EXPECT_FATAL_FAILURE(
+        {
+            Allocator allocator;
+            ProgramBuilder builder;
+            auto* original_root = allocator.Create<Node>(builder.Symbols().New("root"));
+            original_root->a = allocator.Create<Node>(builder.Symbols().New("a"));
+            original_root->b = allocator.Create<Node>(builder.Symbols().New("b"));
+            original_root->c = allocator.Create<Node>(builder.Symbols().New("c"));
+            Program original(std::move(builder));
 
-        //                          root
-        //        ╭──────────────────┼──────────────────╮
-        //       (a)                (b)                (c)
-        //                        Replaced
+            //                          root
+            //        ╭──────────────────┼──────────────────╮
+            //       (a)                (b)                (c)
+            //                        Replaced
 
-        ProgramBuilder cloned;
-        auto* replacement = allocator.Create<NotANode>();
+            ProgramBuilder cloned;
+            auto* replacement = allocator.Create<NotANode>();
 
-        CloneContext ctx(&cloned, &original);
-        ctx.Replace(original_root->b, replacement);
+            CloneContext ctx(&cloned, &original);
+            ctx.Replace(original_root->b, replacement);
 
-        ctx.Clone(original_root);
-      },
-      "internal compiler error");
+            ctx.Clone(original_root);
+        },
+        "internal compiler error");
 }
 
 TEST_F(CloneContextNodeTest, CloneWithReplaceFunction_WithNotANode) {
-  EXPECT_FATAL_FAILURE(
-      {
-        Allocator allocator;
-        ProgramBuilder builder;
-        auto* original_root =
-            allocator.Create<Node>(builder.Symbols().New("root"));
-        original_root->a = allocator.Create<Node>(builder.Symbols().New("a"));
-        original_root->b = allocator.Create<Node>(builder.Symbols().New("b"));
-        original_root->c = allocator.Create<Node>(builder.Symbols().New("c"));
-        Program original(std::move(builder));
+    EXPECT_FATAL_FAILURE(
+        {
+            Allocator allocator;
+            ProgramBuilder builder;
+            auto* original_root = allocator.Create<Node>(builder.Symbols().New("root"));
+            original_root->a = allocator.Create<Node>(builder.Symbols().New("a"));
+            original_root->b = allocator.Create<Node>(builder.Symbols().New("b"));
+            original_root->c = allocator.Create<Node>(builder.Symbols().New("c"));
+            Program original(std::move(builder));
 
-        //                          root
-        //        ╭──────────────────┼──────────────────╮
-        //       (a)                (b)                (c)
-        //                        Replaced
+            //                          root
+            //        ╭──────────────────┼──────────────────╮
+            //       (a)                (b)                (c)
+            //                        Replaced
 
-        ProgramBuilder cloned;
-        auto* replacement = allocator.Create<NotANode>();
+            ProgramBuilder cloned;
+            auto* replacement = allocator.Create<NotANode>();
 
-        CloneContext ctx(&cloned, &original);
-        ctx.Replace(original_root->b, [=] { return replacement; });
+            CloneContext ctx(&cloned, &original);
+            ctx.Replace(original_root->b, [=] { return replacement; });
 
-        ctx.Clone(original_root);
-      },
-      "internal compiler error");
+            ctx.Clone(original_root);
+        },
+        "internal compiler error");
 }
 
 using CloneContextTest = ::testing::Test;
 
 TEST_F(CloneContextTest, CloneWithReplaceAll_SymbolsTwice) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder cloned;
-        Program original;
-        CloneContext ctx(&cloned, &original);
-        ctx.ReplaceAll([](const Symbol s) { return s; });
-        ctx.ReplaceAll([](const Symbol s) { return s; });
-      },
-      "internal compiler error: ReplaceAll(const SymbolTransform&) called "
-      "multiple times on the same CloneContext");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder cloned;
+            Program original;
+            CloneContext ctx(&cloned, &original);
+            ctx.ReplaceAll([](const Symbol s) { return s; });
+            ctx.ReplaceAll([](const Symbol s) { return s; });
+        },
+        "internal compiler error: ReplaceAll(const SymbolTransform&) called "
+        "multiple times on the same CloneContext");
 }
 
 TEST_F(CloneContextTest, CloneNewUnnamedSymbols) {
-  ProgramBuilder builder;
-  Symbol old_a = builder.Symbols().New();
-  Symbol old_b = builder.Symbols().New();
-  Symbol old_c = builder.Symbols().New();
-  EXPECT_EQ(builder.Symbols().NameFor(old_a), "tint_symbol");
-  EXPECT_EQ(builder.Symbols().NameFor(old_b), "tint_symbol_1");
-  EXPECT_EQ(builder.Symbols().NameFor(old_c), "tint_symbol_2");
+    ProgramBuilder builder;
+    Symbol old_a = builder.Symbols().New();
+    Symbol old_b = builder.Symbols().New();
+    Symbol old_c = builder.Symbols().New();
+    EXPECT_EQ(builder.Symbols().NameFor(old_a), "tint_symbol");
+    EXPECT_EQ(builder.Symbols().NameFor(old_b), "tint_symbol_1");
+    EXPECT_EQ(builder.Symbols().NameFor(old_c), "tint_symbol_2");
 
-  Program original(std::move(builder));
+    Program original(std::move(builder));
 
-  ProgramBuilder cloned;
-  CloneContext ctx(&cloned, &original, false);
-  Symbol new_x = cloned.Symbols().New();
-  Symbol new_a = ctx.Clone(old_a);
-  Symbol new_y = cloned.Symbols().New();
-  Symbol new_b = ctx.Clone(old_b);
-  Symbol new_z = cloned.Symbols().New();
-  Symbol new_c = ctx.Clone(old_c);
+    ProgramBuilder cloned;
+    CloneContext ctx(&cloned, &original, false);
+    Symbol new_x = cloned.Symbols().New();
+    Symbol new_a = ctx.Clone(old_a);
+    Symbol new_y = cloned.Symbols().New();
+    Symbol new_b = ctx.Clone(old_b);
+    Symbol new_z = cloned.Symbols().New();
+    Symbol new_c = ctx.Clone(old_c);
 
-  EXPECT_EQ(cloned.Symbols().NameFor(new_x), "tint_symbol");
-  EXPECT_EQ(cloned.Symbols().NameFor(new_a), "tint_symbol_1");
-  EXPECT_EQ(cloned.Symbols().NameFor(new_y), "tint_symbol_2");
-  EXPECT_EQ(cloned.Symbols().NameFor(new_b), "tint_symbol_1_1");
-  EXPECT_EQ(cloned.Symbols().NameFor(new_z), "tint_symbol_3");
-  EXPECT_EQ(cloned.Symbols().NameFor(new_c), "tint_symbol_2_1");
+    EXPECT_EQ(cloned.Symbols().NameFor(new_x), "tint_symbol");
+    EXPECT_EQ(cloned.Symbols().NameFor(new_a), "tint_symbol_1");
+    EXPECT_EQ(cloned.Symbols().NameFor(new_y), "tint_symbol_2");
+    EXPECT_EQ(cloned.Symbols().NameFor(new_b), "tint_symbol_1_1");
+    EXPECT_EQ(cloned.Symbols().NameFor(new_z), "tint_symbol_3");
+    EXPECT_EQ(cloned.Symbols().NameFor(new_c), "tint_symbol_2_1");
 }
 
 TEST_F(CloneContextTest, CloneNewSymbols) {
-  ProgramBuilder builder;
-  Symbol old_a = builder.Symbols().New("a");
-  Symbol old_b = builder.Symbols().New("b");
-  Symbol old_c = builder.Symbols().New("c");
-  EXPECT_EQ(builder.Symbols().NameFor(old_a), "a");
-  EXPECT_EQ(builder.Symbols().NameFor(old_b), "b");
-  EXPECT_EQ(builder.Symbols().NameFor(old_c), "c");
+    ProgramBuilder builder;
+    Symbol old_a = builder.Symbols().New("a");
+    Symbol old_b = builder.Symbols().New("b");
+    Symbol old_c = builder.Symbols().New("c");
+    EXPECT_EQ(builder.Symbols().NameFor(old_a), "a");
+    EXPECT_EQ(builder.Symbols().NameFor(old_b), "b");
+    EXPECT_EQ(builder.Symbols().NameFor(old_c), "c");
 
-  Program original(std::move(builder));
+    Program original(std::move(builder));
 
-  ProgramBuilder cloned;
-  CloneContext ctx(&cloned, &original, false);
-  Symbol new_x = cloned.Symbols().New("a");
-  Symbol new_a = ctx.Clone(old_a);
-  Symbol new_y = cloned.Symbols().New("b");
-  Symbol new_b = ctx.Clone(old_b);
-  Symbol new_z = cloned.Symbols().New("c");
-  Symbol new_c = ctx.Clone(old_c);
+    ProgramBuilder cloned;
+    CloneContext ctx(&cloned, &original, false);
+    Symbol new_x = cloned.Symbols().New("a");
+    Symbol new_a = ctx.Clone(old_a);
+    Symbol new_y = cloned.Symbols().New("b");
+    Symbol new_b = ctx.Clone(old_b);
+    Symbol new_z = cloned.Symbols().New("c");
+    Symbol new_c = ctx.Clone(old_c);
 
-  EXPECT_EQ(cloned.Symbols().NameFor(new_x), "a");
-  EXPECT_EQ(cloned.Symbols().NameFor(new_a), "a_1");
-  EXPECT_EQ(cloned.Symbols().NameFor(new_y), "b");
-  EXPECT_EQ(cloned.Symbols().NameFor(new_b), "b_1");
-  EXPECT_EQ(cloned.Symbols().NameFor(new_z), "c");
-  EXPECT_EQ(cloned.Symbols().NameFor(new_c), "c_1");
+    EXPECT_EQ(cloned.Symbols().NameFor(new_x), "a");
+    EXPECT_EQ(cloned.Symbols().NameFor(new_a), "a_1");
+    EXPECT_EQ(cloned.Symbols().NameFor(new_y), "b");
+    EXPECT_EQ(cloned.Symbols().NameFor(new_b), "b_1");
+    EXPECT_EQ(cloned.Symbols().NameFor(new_z), "c");
+    EXPECT_EQ(cloned.Symbols().NameFor(new_c), "c_1");
 }
 
 TEST_F(CloneContextTest, CloneNewSymbols_AfterCloneSymbols) {
-  ProgramBuilder builder;
-  Symbol old_a = builder.Symbols().New("a");
-  Symbol old_b = builder.Symbols().New("b");
-  Symbol old_c = builder.Symbols().New("c");
-  EXPECT_EQ(builder.Symbols().NameFor(old_a), "a");
-  EXPECT_EQ(builder.Symbols().NameFor(old_b), "b");
-  EXPECT_EQ(builder.Symbols().NameFor(old_c), "c");
+    ProgramBuilder builder;
+    Symbol old_a = builder.Symbols().New("a");
+    Symbol old_b = builder.Symbols().New("b");
+    Symbol old_c = builder.Symbols().New("c");
+    EXPECT_EQ(builder.Symbols().NameFor(old_a), "a");
+    EXPECT_EQ(builder.Symbols().NameFor(old_b), "b");
+    EXPECT_EQ(builder.Symbols().NameFor(old_c), "c");
 
-  Program original(std::move(builder));
+    Program original(std::move(builder));
 
-  ProgramBuilder cloned;
-  CloneContext ctx(&cloned, &original);
-  Symbol new_x = cloned.Symbols().New("a");
-  Symbol new_a = ctx.Clone(old_a);
-  Symbol new_y = cloned.Symbols().New("b");
-  Symbol new_b = ctx.Clone(old_b);
-  Symbol new_z = cloned.Symbols().New("c");
-  Symbol new_c = ctx.Clone(old_c);
+    ProgramBuilder cloned;
+    CloneContext ctx(&cloned, &original);
+    Symbol new_x = cloned.Symbols().New("a");
+    Symbol new_a = ctx.Clone(old_a);
+    Symbol new_y = cloned.Symbols().New("b");
+    Symbol new_b = ctx.Clone(old_b);
+    Symbol new_z = cloned.Symbols().New("c");
+    Symbol new_c = ctx.Clone(old_c);
 
-  EXPECT_EQ(cloned.Symbols().NameFor(new_x), "a_1");
-  EXPECT_EQ(cloned.Symbols().NameFor(new_a), "a");
-  EXPECT_EQ(cloned.Symbols().NameFor(new_y), "b_1");
-  EXPECT_EQ(cloned.Symbols().NameFor(new_b), "b");
-  EXPECT_EQ(cloned.Symbols().NameFor(new_z), "c_1");
-  EXPECT_EQ(cloned.Symbols().NameFor(new_c), "c");
+    EXPECT_EQ(cloned.Symbols().NameFor(new_x), "a_1");
+    EXPECT_EQ(cloned.Symbols().NameFor(new_a), "a");
+    EXPECT_EQ(cloned.Symbols().NameFor(new_y), "b_1");
+    EXPECT_EQ(cloned.Symbols().NameFor(new_b), "b");
+    EXPECT_EQ(cloned.Symbols().NameFor(new_z), "c_1");
+    EXPECT_EQ(cloned.Symbols().NameFor(new_c), "c");
 }
 
 TEST_F(CloneContextTest, ProgramIDs) {
-  ProgramBuilder dst;
-  Program src(ProgramBuilder{});
-  CloneContext ctx(&dst, &src);
-  Allocator allocator;
-  auto* cloned = ctx.Clone(allocator.Create<ProgramNode>(src.ID(), dst.ID()));
-  EXPECT_EQ(cloned->program_id, dst.ID());
+    ProgramBuilder dst;
+    Program src(ProgramBuilder{});
+    CloneContext ctx(&dst, &src);
+    Allocator allocator;
+    auto* cloned = ctx.Clone(allocator.Create<ProgramNode>(src.ID(), dst.ID()));
+    EXPECT_EQ(cloned->program_id, dst.ID());
 }
 
 TEST_F(CloneContextTest, ProgramIDs_Clone_ObjectNotOwnedBySrc) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder dst;
-        Program src(ProgramBuilder{});
-        CloneContext ctx(&dst, &src);
-        Allocator allocator;
-        ctx.Clone(allocator.Create<ProgramNode>(ProgramID::New(), dst.ID()));
-      },
-      R"(internal compiler error: TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, src, object))");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder dst;
+            Program src(ProgramBuilder{});
+            CloneContext ctx(&dst, &src);
+            Allocator allocator;
+            ctx.Clone(allocator.Create<ProgramNode>(ProgramID::New(), dst.ID()));
+        },
+        R"(internal compiler error: TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, src, object))");
 }
 
 TEST_F(CloneContextTest, ProgramIDs_Clone_ObjectNotOwnedByDst) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder dst;
-        Program src(ProgramBuilder{});
-        CloneContext ctx(&dst, &src);
-        Allocator allocator;
-        ctx.Clone(allocator.Create<ProgramNode>(src.ID(), ProgramID::New()));
-      },
-      R"(internal compiler error: TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, dst, out))");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder dst;
+            Program src(ProgramBuilder{});
+            CloneContext ctx(&dst, &src);
+            Allocator allocator;
+            ctx.Clone(allocator.Create<ProgramNode>(src.ID(), ProgramID::New()));
+        },
+        R"(internal compiler error: TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, dst, out))");
 }
 
 }  // namespace
diff --git a/src/tint/cmd/main.cc b/src/tint/cmd/main.cc
index 8a0d293..52dfd70 100644
--- a/src/tint/cmd/main.cc
+++ b/src/tint/cmd/main.cc
@@ -32,16 +32,16 @@
 #include "src/tint/utils/io/command.h"
 #include "src/tint/utils/string.h"
 #include "src/tint/val/val.h"
+#include "src/tint/writer/flatten_bindings.h"
 #include "tint/tint.h"
 
 namespace {
 
-[[noreturn]] void TintInternalCompilerErrorReporter(
-    const tint::diag::List& diagnostics) {
-  auto printer = tint::diag::Printer::create(stderr, true);
-  tint::diag::Formatter{}.format(diagnostics, printer.get());
-  tint::diag::Style bold_red{tint::diag::Color::kRed, true};
-  constexpr const char* please_file_bug = R"(
+[[noreturn]] void TintInternalCompilerErrorReporter(const tint::diag::List& diagnostics) {
+    auto printer = tint::diag::Printer::create(stderr, true);
+    tint::diag::Formatter{}.format(diagnostics, printer.get());
+    tint::diag::Style bold_red{tint::diag::Color::kRed, true};
+    constexpr const char* please_file_bug = R"(
 ********************************************************************
 *  The tint shader compiler has encountered an unexpected error.   *
 *                                                                  *
@@ -49,42 +49,43 @@
 *  crbug.com/tint with the source program that triggered the bug.  *
 ********************************************************************
 )";
-  printer->write(please_file_bug, bold_red);
-  exit(1);
+    printer->write(please_file_bug, bold_red);
+    exit(1);
 }
 
 enum class Format {
-  kNone = -1,
-  kSpirv,
-  kSpvAsm,
-  kWgsl,
-  kMsl,
-  kHlsl,
-  kGlsl,
+    kNone = -1,
+    kSpirv,
+    kSpvAsm,
+    kWgsl,
+    kMsl,
+    kHlsl,
+    kGlsl,
 };
 
 struct Options {
-  bool show_help = false;
+    bool show_help = false;
 
-  std::string input_filename;
-  std::string output_file = "-";  // Default to stdout
+    std::string input_filename;
+    std::string output_file = "-";  // Default to stdout
 
-  bool parse_only = false;
-  bool disable_workgroup_init = false;
-  bool validate = false;
-  bool demangle = false;
-  bool dump_inspector_bindings = false;
+    bool parse_only = false;
+    bool disable_workgroup_init = false;
+    bool validate = false;
+    bool demangle = false;
+    bool dump_inspector_bindings = false;
 
-  Format format = Format::kNone;
+    Format format = Format::kNone;
 
-  bool emit_single_entry_point = false;
-  std::string ep_name;
+    bool emit_single_entry_point = false;
+    std::string ep_name;
 
-  std::vector<std::string> transforms;
+    std::vector<std::string> transforms;
 
-  bool use_fxc = false;
-  std::string dxc_path;
-  std::string xcrun_path;
+    bool use_fxc = false;
+    std::string dxc_path;
+    std::string xcrun_path;
+    std::vector<std::string> overrides;
 };
 
 const char kUsage[] = R"(Usage: tint [options] <input-file>
@@ -117,298 +118,298 @@
   --dxc                     -- Path to DXC executable, used to validate HLSL output.
                                When specified, automatically enables --validate
   --xcrun                   -- Path to xcrun executable, used to validate MSL output.
-                               When specified, automatically enables --validate)";
+                               When specified, automatically enables --validate
+  --overrides               -- Pipeline overrides as NAME=VALUE, comma-separated.)";
 
 Format parse_format(const std::string& fmt) {
-  (void)fmt;
+    (void)fmt;
 
 #if TINT_BUILD_SPV_WRITER
-  if (fmt == "spirv")
-    return Format::kSpirv;
-  if (fmt == "spvasm")
-    return Format::kSpvAsm;
+    if (fmt == "spirv")
+        return Format::kSpirv;
+    if (fmt == "spvasm")
+        return Format::kSpvAsm;
 #endif  // TINT_BUILD_SPV_WRITER
 
 #if TINT_BUILD_WGSL_WRITER
-  if (fmt == "wgsl")
-    return Format::kWgsl;
+    if (fmt == "wgsl")
+        return Format::kWgsl;
 #endif  // TINT_BUILD_WGSL_WRITER
 
 #if TINT_BUILD_MSL_WRITER
-  if (fmt == "msl")
-    return Format::kMsl;
+    if (fmt == "msl")
+        return Format::kMsl;
 #endif  // TINT_BUILD_MSL_WRITER
 
 #if TINT_BUILD_HLSL_WRITER
-  if (fmt == "hlsl")
-    return Format::kHlsl;
+    if (fmt == "hlsl")
+        return Format::kHlsl;
 #endif  // TINT_BUILD_HLSL_WRITER
 
 #if TINT_BUILD_GLSL_WRITER
-  if (fmt == "glsl")
-    return Format::kGlsl;
+    if (fmt == "glsl")
+        return Format::kGlsl;
 #endif  // TINT_BUILD_GLSL_WRITER
 
-  return Format::kNone;
+    return Format::kNone;
 }
 
-#if TINT_BUILD_SPV_WRITER || TINT_BUILD_WGSL_WRITER || \
-    TINT_BUILD_MSL_WRITER || TINT_BUILD_HLSL_WRITER
+#if TINT_BUILD_SPV_WRITER || TINT_BUILD_WGSL_WRITER || TINT_BUILD_MSL_WRITER || \
+    TINT_BUILD_HLSL_WRITER
 /// @param input input string
 /// @param suffix potential suffix string
 /// @returns true if input ends with the given suffix.
 bool ends_with(const std::string& input, const std::string& suffix) {
-  const auto input_len = input.size();
-  const auto suffix_len = suffix.size();
-  // Avoid integer overflow.
-  return (input_len >= suffix_len) &&
-         (input_len - suffix_len == input.rfind(suffix));
+    const auto input_len = input.size();
+    const auto suffix_len = suffix.size();
+    // Avoid integer overflow.
+    return (input_len >= suffix_len) && (input_len - suffix_len == input.rfind(suffix));
 }
 #endif
 
 /// @param filename the filename to inspect
 /// @returns the inferred format for the filename suffix
 Format infer_format(const std::string& filename) {
-  (void)filename;
+    (void)filename;
 
 #if TINT_BUILD_SPV_WRITER
-  if (ends_with(filename, ".spv")) {
-    return Format::kSpirv;
-  }
-  if (ends_with(filename, ".spvasm")) {
-    return Format::kSpvAsm;
-  }
+    if (ends_with(filename, ".spv")) {
+        return Format::kSpirv;
+    }
+    if (ends_with(filename, ".spvasm")) {
+        return Format::kSpvAsm;
+    }
 #endif  // TINT_BUILD_SPV_WRITER
 
 #if TINT_BUILD_WGSL_WRITER
-  if (ends_with(filename, ".wgsl")) {
-    return Format::kWgsl;
-  }
+    if (ends_with(filename, ".wgsl")) {
+        return Format::kWgsl;
+    }
 #endif  // TINT_BUILD_WGSL_WRITER
 
 #if TINT_BUILD_MSL_WRITER
-  if (ends_with(filename, ".metal")) {
-    return Format::kMsl;
-  }
+    if (ends_with(filename, ".metal")) {
+        return Format::kMsl;
+    }
 #endif  // TINT_BUILD_MSL_WRITER
 
 #if TINT_BUILD_HLSL_WRITER
-  if (ends_with(filename, ".hlsl")) {
-    return Format::kHlsl;
-  }
+    if (ends_with(filename, ".hlsl")) {
+        return Format::kHlsl;
+    }
 #endif  // TINT_BUILD_HLSL_WRITER
 
-  return Format::kNone;
+    return Format::kNone;
 }
 
-std::vector<std::string> split_transform_names(std::string list) {
-  std::vector<std::string> res;
+std::vector<std::string> split_on_comma(std::string list) {
+    std::vector<std::string> res;
 
-  std::stringstream str(list);
-  while (str.good()) {
-    std::string substr;
-    getline(str, substr, ',');
-    res.push_back(substr);
-  }
-  return res;
+    std::stringstream str(list);
+    while (str.good()) {
+        std::string substr;
+        getline(str, substr, ',');
+        res.push_back(substr);
+    }
+    return res;
 }
 
-std::string TextureDimensionToString(
-    tint::inspector::ResourceBinding::TextureDimension dim) {
-  switch (dim) {
-    case tint::inspector::ResourceBinding::TextureDimension::kNone:
-      return "None";
-    case tint::inspector::ResourceBinding::TextureDimension::k1d:
-      return "1d";
-    case tint::inspector::ResourceBinding::TextureDimension::k2d:
-      return "2d";
-    case tint::inspector::ResourceBinding::TextureDimension::k2dArray:
-      return "2dArray";
-    case tint::inspector::ResourceBinding::TextureDimension::k3d:
-      return "3d";
-    case tint::inspector::ResourceBinding::TextureDimension::kCube:
-      return "Cube";
-    case tint::inspector::ResourceBinding::TextureDimension::kCubeArray:
-      return "CubeArray";
-  }
+std::string TextureDimensionToString(tint::inspector::ResourceBinding::TextureDimension dim) {
+    switch (dim) {
+        case tint::inspector::ResourceBinding::TextureDimension::kNone:
+            return "None";
+        case tint::inspector::ResourceBinding::TextureDimension::k1d:
+            return "1d";
+        case tint::inspector::ResourceBinding::TextureDimension::k2d:
+            return "2d";
+        case tint::inspector::ResourceBinding::TextureDimension::k2dArray:
+            return "2dArray";
+        case tint::inspector::ResourceBinding::TextureDimension::k3d:
+            return "3d";
+        case tint::inspector::ResourceBinding::TextureDimension::kCube:
+            return "Cube";
+        case tint::inspector::ResourceBinding::TextureDimension::kCubeArray:
+            return "CubeArray";
+    }
 
-  return "Unknown";
+    return "Unknown";
 }
 
-std::string SampledKindToString(
-    tint::inspector::ResourceBinding::SampledKind kind) {
-  switch (kind) {
-    case tint::inspector::ResourceBinding::SampledKind::kFloat:
-      return "Float";
-    case tint::inspector::ResourceBinding::SampledKind::kUInt:
-      return "UInt";
-    case tint::inspector::ResourceBinding::SampledKind::kSInt:
-      return "SInt";
-    case tint::inspector::ResourceBinding::SampledKind::kUnknown:
-      break;
-  }
+std::string SampledKindToString(tint::inspector::ResourceBinding::SampledKind kind) {
+    switch (kind) {
+        case tint::inspector::ResourceBinding::SampledKind::kFloat:
+            return "Float";
+        case tint::inspector::ResourceBinding::SampledKind::kUInt:
+            return "UInt";
+        case tint::inspector::ResourceBinding::SampledKind::kSInt:
+            return "SInt";
+        case tint::inspector::ResourceBinding::SampledKind::kUnknown:
+            break;
+    }
 
-  return "Unknown";
+    return "Unknown";
 }
 
-std::string TexelFormatToString(
-    tint::inspector::ResourceBinding::TexelFormat format) {
-  switch (format) {
-    case tint::inspector::ResourceBinding::TexelFormat::kR32Uint:
-      return "R32Uint";
-    case tint::inspector::ResourceBinding::TexelFormat::kR32Sint:
-      return "R32Sint";
-    case tint::inspector::ResourceBinding::TexelFormat::kR32Float:
-      return "R32Float";
-    case tint::inspector::ResourceBinding::TexelFormat::kRgba8Unorm:
-      return "Rgba8Unorm";
-    case tint::inspector::ResourceBinding::TexelFormat::kRgba8Snorm:
-      return "Rgba8Snorm";
-    case tint::inspector::ResourceBinding::TexelFormat::kRgba8Uint:
-      return "Rgba8Uint";
-    case tint::inspector::ResourceBinding::TexelFormat::kRgba8Sint:
-      return "Rgba8Sint";
-    case tint::inspector::ResourceBinding::TexelFormat::kRg32Uint:
-      return "Rg32Uint";
-    case tint::inspector::ResourceBinding::TexelFormat::kRg32Sint:
-      return "Rg32Sint";
-    case tint::inspector::ResourceBinding::TexelFormat::kRg32Float:
-      return "Rg32Float";
-    case tint::inspector::ResourceBinding::TexelFormat::kRgba16Uint:
-      return "Rgba16Uint";
-    case tint::inspector::ResourceBinding::TexelFormat::kRgba16Sint:
-      return "Rgba16Sint";
-    case tint::inspector::ResourceBinding::TexelFormat::kRgba16Float:
-      return "Rgba16Float";
-    case tint::inspector::ResourceBinding::TexelFormat::kRgba32Uint:
-      return "Rgba32Uint";
-    case tint::inspector::ResourceBinding::TexelFormat::kRgba32Sint:
-      return "Rgba32Sint";
-    case tint::inspector::ResourceBinding::TexelFormat::kRgba32Float:
-      return "Rgba32Float";
-    case tint::inspector::ResourceBinding::TexelFormat::kNone:
-      return "None";
-  }
-  return "Unknown";
+std::string TexelFormatToString(tint::inspector::ResourceBinding::TexelFormat format) {
+    switch (format) {
+        case tint::inspector::ResourceBinding::TexelFormat::kR32Uint:
+            return "R32Uint";
+        case tint::inspector::ResourceBinding::TexelFormat::kR32Sint:
+            return "R32Sint";
+        case tint::inspector::ResourceBinding::TexelFormat::kR32Float:
+            return "R32Float";
+        case tint::inspector::ResourceBinding::TexelFormat::kRgba8Unorm:
+            return "Rgba8Unorm";
+        case tint::inspector::ResourceBinding::TexelFormat::kRgba8Snorm:
+            return "Rgba8Snorm";
+        case tint::inspector::ResourceBinding::TexelFormat::kRgba8Uint:
+            return "Rgba8Uint";
+        case tint::inspector::ResourceBinding::TexelFormat::kRgba8Sint:
+            return "Rgba8Sint";
+        case tint::inspector::ResourceBinding::TexelFormat::kRg32Uint:
+            return "Rg32Uint";
+        case tint::inspector::ResourceBinding::TexelFormat::kRg32Sint:
+            return "Rg32Sint";
+        case tint::inspector::ResourceBinding::TexelFormat::kRg32Float:
+            return "Rg32Float";
+        case tint::inspector::ResourceBinding::TexelFormat::kRgba16Uint:
+            return "Rgba16Uint";
+        case tint::inspector::ResourceBinding::TexelFormat::kRgba16Sint:
+            return "Rgba16Sint";
+        case tint::inspector::ResourceBinding::TexelFormat::kRgba16Float:
+            return "Rgba16Float";
+        case tint::inspector::ResourceBinding::TexelFormat::kRgba32Uint:
+            return "Rgba32Uint";
+        case tint::inspector::ResourceBinding::TexelFormat::kRgba32Sint:
+            return "Rgba32Sint";
+        case tint::inspector::ResourceBinding::TexelFormat::kRgba32Float:
+            return "Rgba32Float";
+        case tint::inspector::ResourceBinding::TexelFormat::kNone:
+            return "None";
+    }
+    return "Unknown";
 }
 
-std::string ResourceTypeToString(
-    tint::inspector::ResourceBinding::ResourceType type) {
-  switch (type) {
-    case tint::inspector::ResourceBinding::ResourceType::kUniformBuffer:
-      return "UniformBuffer";
-    case tint::inspector::ResourceBinding::ResourceType::kStorageBuffer:
-      return "StorageBuffer";
-    case tint::inspector::ResourceBinding::ResourceType::kReadOnlyStorageBuffer:
-      return "ReadOnlyStorageBuffer";
-    case tint::inspector::ResourceBinding::ResourceType::kSampler:
-      return "Sampler";
-    case tint::inspector::ResourceBinding::ResourceType::kComparisonSampler:
-      return "ComparisonSampler";
-    case tint::inspector::ResourceBinding::ResourceType::kSampledTexture:
-      return "SampledTexture";
-    case tint::inspector::ResourceBinding::ResourceType::kMultisampledTexture:
-      return "MultisampledTexture";
-    case tint::inspector::ResourceBinding::ResourceType::
-        kWriteOnlyStorageTexture:
-      return "WriteOnlyStorageTexture";
-    case tint::inspector::ResourceBinding::ResourceType::kDepthTexture:
-      return "DepthTexture";
-    case tint::inspector::ResourceBinding::ResourceType::
-        kDepthMultisampledTexture:
-      return "DepthMultisampledTexture";
-    case tint::inspector::ResourceBinding::ResourceType::kExternalTexture:
-      return "ExternalTexture";
-  }
+std::string ResourceTypeToString(tint::inspector::ResourceBinding::ResourceType type) {
+    switch (type) {
+        case tint::inspector::ResourceBinding::ResourceType::kUniformBuffer:
+            return "UniformBuffer";
+        case tint::inspector::ResourceBinding::ResourceType::kStorageBuffer:
+            return "StorageBuffer";
+        case tint::inspector::ResourceBinding::ResourceType::kReadOnlyStorageBuffer:
+            return "ReadOnlyStorageBuffer";
+        case tint::inspector::ResourceBinding::ResourceType::kSampler:
+            return "Sampler";
+        case tint::inspector::ResourceBinding::ResourceType::kComparisonSampler:
+            return "ComparisonSampler";
+        case tint::inspector::ResourceBinding::ResourceType::kSampledTexture:
+            return "SampledTexture";
+        case tint::inspector::ResourceBinding::ResourceType::kMultisampledTexture:
+            return "MultisampledTexture";
+        case tint::inspector::ResourceBinding::ResourceType::kWriteOnlyStorageTexture:
+            return "WriteOnlyStorageTexture";
+        case tint::inspector::ResourceBinding::ResourceType::kDepthTexture:
+            return "DepthTexture";
+        case tint::inspector::ResourceBinding::ResourceType::kDepthMultisampledTexture:
+            return "DepthMultisampledTexture";
+        case tint::inspector::ResourceBinding::ResourceType::kExternalTexture:
+            return "ExternalTexture";
+    }
 
-  return "Unknown";
+    return "Unknown";
 }
 
 bool ParseArgs(const std::vector<std::string>& args, Options* opts) {
-  for (size_t i = 1; i < args.size(); ++i) {
-    const std::string& arg = args[i];
-    if (arg == "--format") {
-      ++i;
-      if (i >= args.size()) {
-        std::cerr << "Missing value for --format argument." << std::endl;
-        return false;
-      }
-      opts->format = parse_format(args[i]);
+    for (size_t i = 1; i < args.size(); ++i) {
+        const std::string& arg = args[i];
+        if (arg == "--format") {
+            ++i;
+            if (i >= args.size()) {
+                std::cerr << "Missing value for --format argument." << std::endl;
+                return false;
+            }
+            opts->format = parse_format(args[i]);
 
-      if (opts->format == Format::kNone) {
-        std::cerr << "Unknown output format: " << args[i] << std::endl;
-        return false;
-      }
-    } else if (arg == "-ep") {
-      if (i + 1 >= args.size()) {
-        std::cerr << "Missing value for -ep" << std::endl;
-        return false;
-      }
-      i++;
-      opts->ep_name = args[i];
-      opts->emit_single_entry_point = true;
+            if (opts->format == Format::kNone) {
+                std::cerr << "Unknown output format: " << args[i] << std::endl;
+                return false;
+            }
+        } else if (arg == "-ep") {
+            if (i + 1 >= args.size()) {
+                std::cerr << "Missing value for -ep" << std::endl;
+                return false;
+            }
+            i++;
+            opts->ep_name = args[i];
+            opts->emit_single_entry_point = true;
 
-    } else if (arg == "-o" || arg == "--output-name") {
-      ++i;
-      if (i >= args.size()) {
-        std::cerr << "Missing value for " << arg << std::endl;
-        return false;
-      }
-      opts->output_file = args[i];
+        } else if (arg == "-o" || arg == "--output-name") {
+            ++i;
+            if (i >= args.size()) {
+                std::cerr << "Missing value for " << arg << std::endl;
+                return false;
+            }
+            opts->output_file = args[i];
 
-    } else if (arg == "-h" || arg == "--help") {
-      opts->show_help = true;
-    } else if (arg == "--transform") {
-      ++i;
-      if (i >= args.size()) {
-        std::cerr << "Missing value for " << arg << std::endl;
-        return false;
-      }
-      opts->transforms = split_transform_names(args[i]);
-    } else if (arg == "--parse-only") {
-      opts->parse_only = true;
-    } else if (arg == "--disable-workgroup-init") {
-      opts->disable_workgroup_init = true;
-    } else if (arg == "--demangle") {
-      opts->demangle = true;
-    } else if (arg == "--dump-inspector-bindings") {
-      opts->dump_inspector_bindings = true;
-    } else if (arg == "--validate") {
-      opts->validate = true;
-    } else if (arg == "--fxc") {
-      opts->validate = true;
-      opts->use_fxc = true;
-    } else if (arg == "--dxc") {
-      ++i;
-      if (i >= args.size()) {
-        std::cerr << "Missing value for " << arg << std::endl;
-        return false;
-      }
-      opts->dxc_path = args[i];
-      opts->validate = true;
-    } else if (arg == "--xcrun") {
-      ++i;
-      if (i >= args.size()) {
-        std::cerr << "Missing value for " << arg << std::endl;
-        return false;
-      }
-      opts->xcrun_path = args[i];
-      opts->validate = true;
-    } else if (!arg.empty()) {
-      if (arg[0] == '-') {
-        std::cerr << "Unrecognized option: " << arg << std::endl;
-        return false;
-      }
-      if (!opts->input_filename.empty()) {
-        std::cerr << "More than one input file specified: '"
-                  << opts->input_filename << "' and '" << arg << "'"
-                  << std::endl;
-        return false;
-      }
-      opts->input_filename = arg;
+        } else if (arg == "-h" || arg == "--help") {
+            opts->show_help = true;
+        } else if (arg == "--transform") {
+            ++i;
+            if (i >= args.size()) {
+                std::cerr << "Missing value for " << arg << std::endl;
+                return false;
+            }
+            opts->transforms = split_on_comma(args[i]);
+        } else if (arg == "--parse-only") {
+            opts->parse_only = true;
+        } else if (arg == "--disable-workgroup-init") {
+            opts->disable_workgroup_init = true;
+        } else if (arg == "--demangle") {
+            opts->demangle = true;
+        } else if (arg == "--dump-inspector-bindings") {
+            opts->dump_inspector_bindings = true;
+        } else if (arg == "--validate") {
+            opts->validate = true;
+        } else if (arg == "--fxc") {
+            opts->validate = true;
+            opts->use_fxc = true;
+        } else if (arg == "--dxc") {
+            ++i;
+            if (i >= args.size()) {
+                std::cerr << "Missing value for " << arg << std::endl;
+                return false;
+            }
+            opts->dxc_path = args[i];
+            opts->validate = true;
+        } else if (arg == "--xcrun") {
+            ++i;
+            if (i >= args.size()) {
+                std::cerr << "Missing value for " << arg << std::endl;
+                return false;
+            }
+            opts->xcrun_path = args[i];
+            opts->validate = true;
+        } else if (arg == "--overrides") {
+            ++i;
+            if (i >= args.size()) {
+                std::cerr << "Missing value for " << arg << std::endl;
+                return false;
+            }
+            opts->overrides = split_on_comma(args[i]);
+        } else if (!arg.empty()) {
+            if (arg[0] == '-') {
+                std::cerr << "Unrecognized option: " << arg << std::endl;
+                return false;
+            }
+            if (!opts->input_filename.empty()) {
+                std::cerr << "More than one input file specified: '" << opts->input_filename
+                          << "' and '" << arg << "'" << std::endl;
+                return false;
+            }
+            opts->input_filename = arg;
+        }
     }
-  }
-  return true;
+    return true;
 }
 
 /// Copies the content from the file named `input_file` to `buffer`,
@@ -418,45 +419,45 @@
 /// @returns true if we successfully read the file.
 template <typename T>
 bool ReadFile(const std::string& input_file, std::vector<T>* buffer) {
-  if (!buffer) {
-    std::cerr << "The buffer pointer was null" << std::endl;
-    return false;
-  }
+    if (!buffer) {
+        std::cerr << "The buffer pointer was null" << std::endl;
+        return false;
+    }
 
-  FILE* file = nullptr;
+    FILE* file = nullptr;
 #if defined(_MSC_VER)
-  fopen_s(&file, input_file.c_str(), "rb");
+    fopen_s(&file, input_file.c_str(), "rb");
 #else
-  file = fopen(input_file.c_str(), "rb");
+    file = fopen(input_file.c_str(), "rb");
 #endif
-  if (!file) {
-    std::cerr << "Failed to open " << input_file << std::endl;
-    return false;
-  }
+    if (!file) {
+        std::cerr << "Failed to open " << input_file << std::endl;
+        return false;
+    }
 
-  fseek(file, 0, SEEK_END);
-  const auto file_size = static_cast<size_t>(ftell(file));
-  if (0 != (file_size % sizeof(T))) {
-    std::cerr << "File " << input_file
-              << " does not contain an integral number of objects: "
-              << file_size << " bytes in the file, require " << sizeof(T)
-              << " bytes per object" << std::endl;
+    fseek(file, 0, SEEK_END);
+    const auto file_size = static_cast<size_t>(ftell(file));
+    if (0 != (file_size % sizeof(T))) {
+        std::cerr << "File " << input_file
+                  << " does not contain an integral number of objects: " << file_size
+                  << " bytes in the file, require " << sizeof(T) << " bytes per object"
+                  << std::endl;
+        fclose(file);
+        return false;
+    }
+    fseek(file, 0, SEEK_SET);
+
+    buffer->clear();
+    buffer->resize(file_size / sizeof(T));
+
+    size_t bytes_read = fread(buffer->data(), 1, file_size, file);
     fclose(file);
-    return false;
-  }
-  fseek(file, 0, SEEK_SET);
+    if (bytes_read != file_size) {
+        std::cerr << "Failed to read " << input_file << std::endl;
+        return false;
+    }
 
-  buffer->clear();
-  buffer->resize(file_size / sizeof(T));
-
-  size_t bytes_read = fread(buffer->data(), 1, file_size, file);
-  fclose(file);
-  if (bytes_read != file_size) {
-    std::cerr << "Failed to read " << input_file << std::endl;
-    return false;
-  }
-
-  return true;
+    return true;
 }
 
 /// Writes the given `buffer` into the file named as `output_file` using the
@@ -466,82 +467,77 @@
 /// like `std::string` and `std::vector` do.
 /// @returns true on success
 template <typename ContainerT>
-bool WriteFile(const std::string& output_file,
-               const std::string mode,
-               const ContainerT& buffer) {
-  const bool use_stdout = output_file.empty() || output_file == "-";
-  FILE* file = stdout;
+bool WriteFile(const std::string& output_file, const std::string mode, const ContainerT& buffer) {
+    const bool use_stdout = output_file.empty() || output_file == "-";
+    FILE* file = stdout;
 
-  if (!use_stdout) {
+    if (!use_stdout) {
 #if defined(_MSC_VER)
-    fopen_s(&file, output_file.c_str(), mode.c_str());
+        fopen_s(&file, output_file.c_str(), mode.c_str());
 #else
-    file = fopen(output_file.c_str(), mode.c_str());
+        file = fopen(output_file.c_str(), mode.c_str());
 #endif
-    if (!file) {
-      std::cerr << "Could not open file " << output_file << " for writing"
-                << std::endl;
-      return false;
+        if (!file) {
+            std::cerr << "Could not open file " << output_file << " for writing" << std::endl;
+            return false;
+        }
     }
-  }
 
-  size_t written =
-      fwrite(buffer.data(), sizeof(typename ContainerT::value_type),
-             buffer.size(), file);
-  if (buffer.size() != written) {
-    if (use_stdout) {
-      std::cerr << "Could not write all output to standard output" << std::endl;
-    } else {
-      std::cerr << "Could not write to file " << output_file << std::endl;
-      fclose(file);
+    size_t written =
+        fwrite(buffer.data(), sizeof(typename ContainerT::value_type), buffer.size(), file);
+    if (buffer.size() != written) {
+        if (use_stdout) {
+            std::cerr << "Could not write all output to standard output" << std::endl;
+        } else {
+            std::cerr << "Could not write to file " << output_file << std::endl;
+            fclose(file);
+        }
+        return false;
     }
-    return false;
-  }
-  if (!use_stdout) {
-    fclose(file);
-  }
+    if (!use_stdout) {
+        fclose(file);
+    }
 
-  return true;
+    return true;
 }
 
 #if TINT_BUILD_SPV_WRITER
 std::string Disassemble(const std::vector<uint32_t>& data) {
-  std::string spv_errors;
-  spv_target_env target_env = SPV_ENV_UNIVERSAL_1_0;
+    std::string spv_errors;
+    spv_target_env target_env = SPV_ENV_UNIVERSAL_1_0;
 
-  auto msg_consumer = [&spv_errors](spv_message_level_t level, const char*,
-                                    const spv_position_t& position,
-                                    const char* message) {
-    switch (level) {
-      case SPV_MSG_FATAL:
-      case SPV_MSG_INTERNAL_ERROR:
-      case SPV_MSG_ERROR:
-        spv_errors += "error: line " + std::to_string(position.index) + ": " +
-                      message + "\n";
-        break;
-      case SPV_MSG_WARNING:
-        spv_errors += "warning: line " + std::to_string(position.index) + ": " +
-                      message + "\n";
-        break;
-      case SPV_MSG_INFO:
-        spv_errors += "info: line " + std::to_string(position.index) + ": " +
-                      message + "\n";
-        break;
-      case SPV_MSG_DEBUG:
-        break;
+    auto msg_consumer = [&spv_errors](spv_message_level_t level, const char*,
+                                      const spv_position_t& position, const char* message) {
+        switch (level) {
+            case SPV_MSG_FATAL:
+            case SPV_MSG_INTERNAL_ERROR:
+            case SPV_MSG_ERROR:
+                spv_errors +=
+                    "error: line " + std::to_string(position.index) + ": " + message + "\n";
+                break;
+            case SPV_MSG_WARNING:
+                spv_errors +=
+                    "warning: line " + std::to_string(position.index) + ": " + message + "\n";
+                break;
+            case SPV_MSG_INFO:
+                spv_errors +=
+                    "info: line " + std::to_string(position.index) + ": " + message + "\n";
+                break;
+            case SPV_MSG_DEBUG:
+                break;
+        }
+    };
+
+    spvtools::SpirvTools tools(target_env);
+    tools.SetMessageConsumer(msg_consumer);
+
+    std::string result;
+    if (!tools.Disassemble(
+            data, &result,
+            SPV_BINARY_TO_TEXT_OPTION_INDENT | SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES)) {
+        std::cerr << spv_errors << std::endl;
     }
-  };
-
-  spvtools::SpirvTools tools(target_env);
-  tools.SetMessageConsumer(msg_consumer);
-
-  std::string result;
-  if (!tools.Disassemble(data, &result,
-                         SPV_BINARY_TO_TEXT_OPTION_INDENT |
-                             SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES)) {
-    std::cerr << spv_errors << std::endl;
-  }
-  return result;
+    return result;
 }
 #endif  // TINT_BUILD_SPV_WRITER
 
@@ -551,12 +547,12 @@
 /// @param program the program
 void PrintWGSL(std::ostream& out, const tint::Program& program) {
 #if TINT_BUILD_WGSL_WRITER
-  tint::writer::wgsl::Options options;
-  auto result = tint::writer::wgsl::Generate(&program, options);
-  out << std::endl << result.wgsl << std::endl;
+    tint::writer::wgsl::Options options;
+    auto result = tint::writer::wgsl::Generate(&program, options);
+    out << std::endl << result.wgsl << std::endl;
 #else
-  (void)out;
-  (void)program;
+    (void)out;
+    (void)program;
 #endif
 }
 
@@ -566,47 +562,46 @@
 /// @returns true on success
 bool GenerateSpirv(const tint::Program* program, const Options& options) {
 #if TINT_BUILD_SPV_WRITER
-  // TODO(jrprice): Provide a way for the user to set non-default options.
-  tint::writer::spirv::Options gen_options;
-  gen_options.disable_workgroup_init = options.disable_workgroup_init;
-  gen_options.generate_external_texture_bindings = true;
-  auto result = tint::writer::spirv::Generate(program, gen_options);
-  if (!result.success) {
-    PrintWGSL(std::cerr, *program);
-    std::cerr << "Failed to generate: " << result.error << std::endl;
-    return false;
-  }
-
-  if (options.format == Format::kSpvAsm) {
-    if (!WriteFile(options.output_file, "w", Disassemble(result.spirv))) {
-      return false;
+    // TODO(jrprice): Provide a way for the user to set non-default options.
+    tint::writer::spirv::Options gen_options;
+    gen_options.disable_workgroup_init = options.disable_workgroup_init;
+    gen_options.generate_external_texture_bindings = true;
+    auto result = tint::writer::spirv::Generate(program, gen_options);
+    if (!result.success) {
+        PrintWGSL(std::cerr, *program);
+        std::cerr << "Failed to generate: " << result.error << std::endl;
+        return false;
     }
-  } else {
-    if (!WriteFile(options.output_file, "wb", result.spirv)) {
-      return false;
-    }
-  }
 
-  if (options.validate) {
-    // Use Vulkan 1.1, since this is what Tint, internally, uses.
-    spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_1);
-    tools.SetMessageConsumer([](spv_message_level_t, const char*,
-                                const spv_position_t& pos, const char* msg) {
-      std::cerr << (pos.line + 1) << ":" << (pos.column + 1) << ": " << msg
-                << std::endl;
-    });
-    if (!tools.Validate(result.spirv.data(), result.spirv.size(),
-                        spvtools::ValidatorOptions())) {
-      return false;
+    if (options.format == Format::kSpvAsm) {
+        if (!WriteFile(options.output_file, "w", Disassemble(result.spirv))) {
+            return false;
+        }
+    } else {
+        if (!WriteFile(options.output_file, "wb", result.spirv)) {
+            return false;
+        }
     }
-  }
 
-  return true;
+    if (options.validate) {
+        // Use Vulkan 1.1, since this is what Tint, internally, uses.
+        spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_1);
+        tools.SetMessageConsumer(
+            [](spv_message_level_t, const char*, const spv_position_t& pos, const char* msg) {
+                std::cerr << (pos.line + 1) << ":" << (pos.column + 1) << ": " << msg << std::endl;
+            });
+        if (!tools.Validate(result.spirv.data(), result.spirv.size(),
+                            spvtools::ValidatorOptions())) {
+            return false;
+        }
+    }
+
+    return true;
 #else
-  (void)program;
-  (void)options;
-  std::cerr << "SPIR-V writer not enabled in tint build" << std::endl;
-  return false;
+    (void)program;
+    (void)options;
+    std::cerr << "SPIR-V writer not enabled in tint build" << std::endl;
+    return false;
 #endif  // TINT_BUILD_SPV_WRITER
 }
 
@@ -616,37 +611,36 @@
 /// @returns true on success
 bool GenerateWgsl(const tint::Program* program, const Options& options) {
 #if TINT_BUILD_WGSL_WRITER
-  // TODO(jrprice): Provide a way for the user to set non-default options.
-  tint::writer::wgsl::Options gen_options;
-  auto result = tint::writer::wgsl::Generate(program, gen_options);
-  if (!result.success) {
-    std::cerr << "Failed to generate: " << result.error << std::endl;
-    return false;
-  }
-
-  if (!WriteFile(options.output_file, "w", result.wgsl)) {
-    return false;
-  }
-
-  if (options.validate) {
-    // Attempt to re-parse the output program with Tint's WGSL reader.
-    auto source = std::make_unique<tint::Source::File>(options.input_filename,
-                                                       result.wgsl);
-    auto reparsed_program = tint::reader::wgsl::Parse(source.get());
-    if (!reparsed_program.IsValid()) {
-      auto diag_printer = tint::diag::Printer::create(stderr, true);
-      tint::diag::Formatter diag_formatter;
-      diag_formatter.format(reparsed_program.Diagnostics(), diag_printer.get());
-      return false;
+    // TODO(jrprice): Provide a way for the user to set non-default options.
+    tint::writer::wgsl::Options gen_options;
+    auto result = tint::writer::wgsl::Generate(program, gen_options);
+    if (!result.success) {
+        std::cerr << "Failed to generate: " << result.error << std::endl;
+        return false;
     }
-  }
 
-  return true;
+    if (!WriteFile(options.output_file, "w", result.wgsl)) {
+        return false;
+    }
+
+    if (options.validate) {
+        // Attempt to re-parse the output program with Tint's WGSL reader.
+        auto source = std::make_unique<tint::Source::File>(options.input_filename, result.wgsl);
+        auto reparsed_program = tint::reader::wgsl::Parse(source.get());
+        if (!reparsed_program.IsValid()) {
+            auto diag_printer = tint::diag::Printer::create(stderr, true);
+            tint::diag::Formatter diag_formatter;
+            diag_formatter.format(reparsed_program.Diagnostics(), diag_printer.get());
+            return false;
+        }
+    }
+
+    return true;
 #else
-  (void)program;
-  (void)options;
-  std::cerr << "WGSL writer not enabled in tint build" << std::endl;
-  return false;
+    (void)program;
+    (void)options;
+    std::cerr << "WGSL writer not enabled in tint build" << std::endl;
+    return false;
 #endif  // TINT_BUILD_WGSL_WRITER
 }
 
@@ -656,111 +650,60 @@
 /// @returns true on success
 bool GenerateMsl(const tint::Program* program, const Options& options) {
 #if TINT_BUILD_MSL_WRITER
-  const tint::Program* input_program = program;
-
-  // Remap resource numbers to a flat namespace.
-  // TODO(crbug.com/tint/1101): Make this more robust for multiple entry points.
-  using BindingPoint = tint::transform::BindingPoint;
-  tint::transform::BindingRemapper::BindingPoints binding_points;
-  uint32_t next_buffer_idx = 0;
-  uint32_t next_sampler_idx = 0;
-  uint32_t next_texture_idx = 0;
-
-  tint::inspector::Inspector inspector(program);
-  auto entry_points = inspector.GetEntryPoints();
-  for (auto& entry_point : entry_points) {
-    auto bindings = inspector.GetResourceBindings(entry_point.name);
-    for (auto& binding : bindings) {
-      BindingPoint src = {binding.bind_group, binding.binding};
-      if (binding_points.count(src)) {
-        continue;
-      }
-      switch (binding.resource_type) {
-        case tint::inspector::ResourceBinding::ResourceType::kUniformBuffer:
-        case tint::inspector::ResourceBinding::ResourceType::kStorageBuffer:
-        case tint::inspector::ResourceBinding::ResourceType::
-            kReadOnlyStorageBuffer:
-          binding_points.emplace(src, BindingPoint{0, next_buffer_idx++});
-          break;
-        case tint::inspector::ResourceBinding::ResourceType::kSampler:
-        case tint::inspector::ResourceBinding::ResourceType::kComparisonSampler:
-          binding_points.emplace(src, BindingPoint{0, next_sampler_idx++});
-          break;
-        case tint::inspector::ResourceBinding::ResourceType::kSampledTexture:
-        case tint::inspector::ResourceBinding::ResourceType::
-            kMultisampledTexture:
-        case tint::inspector::ResourceBinding::ResourceType::
-            kWriteOnlyStorageTexture:
-        case tint::inspector::ResourceBinding::ResourceType::kDepthTexture:
-        case tint::inspector::ResourceBinding::ResourceType::
-            kDepthMultisampledTexture:
-        case tint::inspector::ResourceBinding::ResourceType::kExternalTexture:
-          binding_points.emplace(src, BindingPoint{0, next_texture_idx++});
-          break;
-      }
+    // Remap resource numbers to a flat namespace.
+    // TODO(crbug.com/tint/1501): Do this via Options::BindingMap.
+    const tint::Program* input_program = program;
+    auto flattened = tint::writer::FlattenBindings(program);
+    if (flattened) {
+        input_program = &*flattened;
     }
-  }
 
-  // Run the binding remapper transform.
-  tint::transform::Output transform_output;
-  if (!binding_points.empty()) {
-    tint::transform::Manager manager;
-    tint::transform::DataMap inputs;
-    inputs.Add<tint::transform::BindingRemapper::Remappings>(
-        std::move(binding_points),
-        tint::transform::BindingRemapper::AccessControls{},
-        /* mayCollide */ true);
-    manager.Add<tint::transform::BindingRemapper>();
-    transform_output = manager.Run(program, inputs);
-    input_program = &transform_output.program;
-  }
+    // TODO(jrprice): Provide a way for the user to set non-default options.
+    tint::writer::msl::Options gen_options;
+    gen_options.disable_workgroup_init = options.disable_workgroup_init;
+    gen_options.generate_external_texture_bindings = true;
+    auto result = tint::writer::msl::Generate(input_program, gen_options);
+    if (!result.success) {
+        PrintWGSL(std::cerr, *program);
+        std::cerr << "Failed to generate: " << result.error << std::endl;
+        return false;
+    }
 
-  // TODO(jrprice): Provide a way for the user to set non-default options.
-  tint::writer::msl::Options gen_options;
-  gen_options.disable_workgroup_init = options.disable_workgroup_init;
-  gen_options.generate_external_texture_bindings = true;
-  auto result = tint::writer::msl::Generate(input_program, gen_options);
-  if (!result.success) {
-    PrintWGSL(std::cerr, *program);
-    std::cerr << "Failed to generate: " << result.error << std::endl;
-    return false;
-  }
+    if (!WriteFile(options.output_file, "w", result.msl)) {
+        return false;
+    }
 
-  if (!WriteFile(options.output_file, "w", result.msl)) {
-    return false;
-  }
-
-  if (options.validate) {
-    tint::val::Result res;
+    if (options.validate) {
+        tint::val::Result res;
 #ifdef TINT_ENABLE_MSL_VALIDATION_USING_METAL_API
-    res = tint::val::MslUsingMetalAPI(result.msl);
+        res = tint::val::MslUsingMetalAPI(result.msl);
 #else
 #ifdef _WIN32
-    const char* default_xcrun_exe = "metal.exe";
+        const char* default_xcrun_exe = "metal.exe";
 #else
-    const char* default_xcrun_exe = "xcrun";
+        const char* default_xcrun_exe = "xcrun";
 #endif
-    auto xcrun = tint::utils::Command::LookPath(
-        options.xcrun_path.empty() ? default_xcrun_exe : options.xcrun_path);
-    if (xcrun.Found()) {
-      res = tint::val::Msl(xcrun.Path(), result.msl);
-    } else {
-      res.output = "xcrun executable not found. Cannot validate.";
-      res.failed = true;
-    }
+        auto xcrun = tint::utils::Command::LookPath(
+            options.xcrun_path.empty() ? default_xcrun_exe : options.xcrun_path);
+        if (xcrun.Found()) {
+            res = tint::val::Msl(xcrun.Path(), result.msl);
+        } else {
+            res.output = "xcrun executable not found. Cannot validate.";
+            res.failed = true;
+        }
 #endif  // TINT_ENABLE_MSL_VALIDATION_USING_METAL_API
-    if (res.failed) {
-      std::cerr << res.output << std::endl;
-      return false;
+        if (res.failed) {
+            std::cerr << res.output << std::endl;
+            return false;
+        }
     }
-  }
 
-  return true;
+    return true;
 #else
-  (void)program;
-  (void)options;
-  std::cerr << "MSL writer not enabled in tint build" << std::endl;
-  return false;
+    (void)program;
+    (void)options;
+    std::cerr << "MSL writer not enabled in tint build" << std::endl;
+    return false;
 #endif  // TINT_BUILD_MSL_WRITER
 }
 
@@ -770,69 +713,69 @@
 /// @returns true on success
 bool GenerateHlsl(const tint::Program* program, const Options& options) {
 #if TINT_BUILD_HLSL_WRITER
-  // TODO(jrprice): Provide a way for the user to set non-default options.
-  tint::writer::hlsl::Options gen_options;
-  gen_options.disable_workgroup_init = options.disable_workgroup_init;
-  gen_options.generate_external_texture_bindings = true;
-  auto result = tint::writer::hlsl::Generate(program, gen_options);
-  if (!result.success) {
-    PrintWGSL(std::cerr, *program);
-    std::cerr << "Failed to generate: " << result.error << std::endl;
-    return false;
-  }
+    // TODO(jrprice): Provide a way for the user to set non-default options.
+    tint::writer::hlsl::Options gen_options;
+    gen_options.disable_workgroup_init = options.disable_workgroup_init;
+    gen_options.generate_external_texture_bindings = true;
+    auto result = tint::writer::hlsl::Generate(program, gen_options);
+    if (!result.success) {
+        PrintWGSL(std::cerr, *program);
+        std::cerr << "Failed to generate: " << result.error << std::endl;
+        return false;
+    }
 
-  if (!WriteFile(options.output_file, "w", result.hlsl)) {
-    return false;
-  }
+    if (!WriteFile(options.output_file, "w", result.hlsl)) {
+        return false;
+    }
 
-  if (options.validate) {
-    tint::val::Result res;
-    if (options.use_fxc) {
+    if (options.validate) {
+        tint::val::Result res;
+        if (options.use_fxc) {
 #ifdef _WIN32
-      res = tint::val::HlslUsingFXC(result.hlsl, result.entry_points);
+            res = tint::val::HlslUsingFXC(result.hlsl, result.entry_points, options.overrides);
 #else
-      res.failed = true;
-      res.output = "FXC can only be used on Windows. Sorry :X";
+            res.failed = true;
+            res.output = "FXC can only be used on Windows. Sorry :X";
 #endif  // _WIN32
-    } else {
-      auto dxc = tint::utils::Command::LookPath(
-          options.dxc_path.empty() ? "dxc" : options.dxc_path);
-      if (dxc.Found()) {
-        res = tint::val::HlslUsingDXC(dxc.Path(), result.hlsl,
-                                      result.entry_points);
-      } else {
-        res.failed = true;
-        res.output = "DXC executable not found. Cannot validate";
-      }
+        } else {
+            auto dxc =
+                tint::utils::Command::LookPath(options.dxc_path.empty() ? "dxc" : options.dxc_path);
+            if (dxc.Found()) {
+                res = tint::val::HlslUsingDXC(dxc.Path(), result.hlsl, result.entry_points,
+                                              options.overrides);
+            } else {
+                res.failed = true;
+                res.output = "DXC executable not found. Cannot validate";
+            }
+        }
+        if (res.failed) {
+            std::cerr << res.output << std::endl;
+            return false;
+        }
     }
-    if (res.failed) {
-      std::cerr << res.output << std::endl;
-      return false;
-    }
-  }
 
-  return true;
+    return true;
 #else
-  (void)program;
-  (void)options;
-  std::cerr << "HLSL writer not enabled in tint build" << std::endl;
-  return false;
+    (void)program;
+    (void)options;
+    std::cerr << "HLSL writer not enabled in tint build" << std::endl;
+    return false;
 #endif  // TINT_BUILD_HLSL_WRITER
 }
 
 #if TINT_BUILD_GLSL_WRITER
 EShLanguage pipeline_stage_to_esh_language(tint::ast::PipelineStage stage) {
-  switch (stage) {
-    case tint::ast::PipelineStage::kFragment:
-      return EShLangFragment;
-    case tint::ast::PipelineStage::kVertex:
-      return EShLangVertex;
-    case tint::ast::PipelineStage::kCompute:
-      return EShLangCompute;
-    default:
-      TINT_ASSERT(AST, false);
-      return EShLangVertex;
-  }
+    switch (stage) {
+        case tint::ast::PipelineStage::kFragment:
+            return EShLangFragment;
+        case tint::ast::PipelineStage::kVertex:
+            return EShLangVertex;
+        case tint::ast::PipelineStage::kCompute:
+            return EShLangCompute;
+        default:
+            TINT_ASSERT(AST, false);
+            return EShLangVertex;
+    }
 }
 #endif
 
@@ -842,379 +785,359 @@
 /// @returns true on success
 bool GenerateGlsl(const tint::Program* program, const Options& options) {
 #if TINT_BUILD_GLSL_WRITER
-  if (options.validate) {
-    glslang::InitializeProcess();
-  }
-
-  auto generate = [&](const tint::Program* prg,
-                      const std::string entry_point_name) -> bool {
-    tint::writer::glsl::Options gen_options;
-    gen_options.generate_external_texture_bindings = true;
-    auto result =
-        tint::writer::glsl::Generate(prg, gen_options, entry_point_name);
-    if (!result.success) {
-      PrintWGSL(std::cerr, *prg);
-      std::cerr << "Failed to generate: " << result.error << std::endl;
-      return false;
-    }
-
-    if (!WriteFile(options.output_file, "w", result.glsl)) {
-      return false;
-    }
-
     if (options.validate) {
-      for (auto entry_pt : result.entry_points) {
-        EShLanguage lang = pipeline_stage_to_esh_language(entry_pt.second);
-        glslang::TShader shader(lang);
-        const char* strings[1] = {result.glsl.c_str()};
-        int lengths[1] = {static_cast<int>(result.glsl.length())};
-        shader.setStringsWithLengths(strings, lengths, 1);
-        shader.setEntryPoint("main");
-        bool glslang_result =
-            shader.parse(&glslang::DefaultTBuiltInResource, 310, EEsProfile,
-                         false, false, EShMsgDefault);
-        if (!glslang_result) {
-          std::cerr << "Error parsing GLSL shader:\n"
-                    << shader.getInfoLog() << "\n"
-                    << shader.getInfoDebugLog() << "\n";
-          return false;
-        }
-      }
+        glslang::InitializeProcess();
     }
-    return true;
-  };
 
-  tint::inspector::Inspector inspector(program);
+    auto generate = [&](const tint::Program* prg, const std::string entry_point_name) -> bool {
+        tint::writer::glsl::Options gen_options;
+        gen_options.generate_external_texture_bindings = true;
+        auto result = tint::writer::glsl::Generate(prg, gen_options, entry_point_name);
+        if (!result.success) {
+            PrintWGSL(std::cerr, *prg);
+            std::cerr << "Failed to generate: " << result.error << std::endl;
+            return false;
+        }
 
-  if (inspector.GetEntryPoints().empty()) {
-    // Pass empty string here so that the GLSL generator will generate
-    // code for all functions, reachable or not.
-    return generate(program, "");
-  }
+        if (!WriteFile(options.output_file, "w", result.glsl)) {
+            return false;
+        }
 
-  bool success = true;
-  for (auto& entry_point : inspector.GetEntryPoints()) {
-    success &= generate(program, entry_point.name);
-  }
-  return success;
+        if (options.validate) {
+            for (auto entry_pt : result.entry_points) {
+                EShLanguage lang = pipeline_stage_to_esh_language(entry_pt.second);
+                glslang::TShader shader(lang);
+                const char* strings[1] = {result.glsl.c_str()};
+                int lengths[1] = {static_cast<int>(result.glsl.length())};
+                shader.setStringsWithLengths(strings, lengths, 1);
+                shader.setEntryPoint("main");
+                bool glslang_result = shader.parse(&glslang::DefaultTBuiltInResource, 310,
+                                                   EEsProfile, false, false, EShMsgDefault);
+                if (!glslang_result) {
+                    std::cerr << "Error parsing GLSL shader:\n"
+                              << shader.getInfoLog() << "\n"
+                              << shader.getInfoDebugLog() << "\n";
+                    return false;
+                }
+            }
+        }
+        return true;
+    };
+
+    tint::inspector::Inspector inspector(program);
+
+    if (inspector.GetEntryPoints().empty()) {
+        // Pass empty string here so that the GLSL generator will generate
+        // code for all functions, reachable or not.
+        return generate(program, "");
+    }
+
+    bool success = true;
+    for (auto& entry_point : inspector.GetEntryPoints()) {
+        success &= generate(program, entry_point.name);
+    }
+    return success;
 #else
-  (void)program;
-  (void)options;
-  std::cerr << "GLSL writer not enabled in tint build" << std::endl;
-  return false;
+    (void)program;
+    (void)options;
+    std::cerr << "GLSL writer not enabled in tint build" << std::endl;
+    return false;
 #endif  // TINT_BUILD_GLSL_WRITER
 }
 
 }  // namespace
 
 int main(int argc, const char** argv) {
-  std::vector<std::string> args(argv, argv + argc);
-  Options options;
+    std::vector<std::string> args(argv, argv + argc);
+    Options options;
 
-  tint::SetInternalCompilerErrorReporter(&TintInternalCompilerErrorReporter);
+    tint::SetInternalCompilerErrorReporter(&TintInternalCompilerErrorReporter);
 
 #if TINT_BUILD_WGSL_WRITER
-  tint::Program::printer = [](const tint::Program* program) {
-    auto result = tint::writer::wgsl::Generate(program, {});
-    if (!result.error.empty()) {
-      return "error: " + result.error;
-    }
-    return result.wgsl;
-  };
+    tint::Program::printer = [](const tint::Program* program) {
+        auto result = tint::writer::wgsl::Generate(program, {});
+        if (!result.error.empty()) {
+            return "error: " + result.error;
+        }
+        return result.wgsl;
+    };
 #endif  // TINT_BUILD_WGSL_WRITER
 
-  if (!ParseArgs(args, &options)) {
-    std::cerr << "Failed to parse arguments." << std::endl;
-    return 1;
-  }
-
-  struct TransformFactory {
-    const char* name;
-    std::function<void(tint::transform::Manager& manager,
-                       tint::transform::DataMap& inputs)>
-        make;
-  };
-  std::vector<TransformFactory> transforms = {
-      {"first_index_offset",
-       [](tint::transform::Manager& m, tint::transform::DataMap& i) {
-         i.Add<tint::transform::FirstIndexOffset::BindingPoint>(0, 0);
-         m.Add<tint::transform::FirstIndexOffset>();
-       }},
-      {"fold_trivial_single_use_lets",
-       [](tint::transform::Manager& m, tint::transform::DataMap&) {
-         m.Add<tint::transform::FoldTrivialSingleUseLets>();
-       }},
-      {"renamer",
-       [](tint::transform::Manager& m, tint::transform::DataMap&) {
-         m.Add<tint::transform::Renamer>();
-       }},
-      {"robustness",
-       [](tint::transform::Manager& m, tint::transform::DataMap&) {
-         m.Add<tint::transform::Robustness>();
-       }},
-  };
-  auto transform_names = [&] {
-    std::stringstream names;
-    for (auto& t : transforms) {
-      names << "   " << t.name << std::endl;
+    if (!ParseArgs(args, &options)) {
+        std::cerr << "Failed to parse arguments." << std::endl;
+        return 1;
     }
-    return names.str();
-  };
 
-  if (options.show_help) {
-    std::string usage =
-        tint::utils::ReplaceAll(kUsage, "${transforms}", transform_names());
-    std::cout << usage << std::endl;
-    return 0;
-  }
+    struct TransformFactory {
+        const char* name;
+        std::function<void(tint::transform::Manager& manager, tint::transform::DataMap& inputs)>
+            make;
+    };
+    std::vector<TransformFactory> transforms = {
+        {"first_index_offset",
+         [](tint::transform::Manager& m, tint::transform::DataMap& i) {
+             i.Add<tint::transform::FirstIndexOffset::BindingPoint>(0, 0);
+             m.Add<tint::transform::FirstIndexOffset>();
+         }},
+        {"fold_trivial_single_use_lets",
+         [](tint::transform::Manager& m, tint::transform::DataMap&) {
+             m.Add<tint::transform::FoldTrivialSingleUseLets>();
+         }},
+        {"renamer", [](tint::transform::Manager& m,
+                       tint::transform::DataMap&) { m.Add<tint::transform::Renamer>(); }},
+        {"robustness", [](tint::transform::Manager& m,
+                          tint::transform::DataMap&) { m.Add<tint::transform::Robustness>(); }},
+    };
+    auto transform_names = [&] {
+        std::stringstream names;
+        for (auto& t : transforms) {
+            names << "   " << t.name << std::endl;
+        }
+        return names.str();
+    };
 
-  // Implement output format defaults.
-  if (options.format == Format::kNone) {
-    // Try inferring from filename.
-    options.format = infer_format(options.output_file);
-  }
-  if (options.format == Format::kNone) {
-    // Ultimately, default to SPIR-V assembly. That's nice for interactive use.
-    options.format = Format::kSpvAsm;
-  }
-
-  auto diag_printer = tint::diag::Printer::create(stderr, true);
-  tint::diag::Formatter diag_formatter;
-
-  std::unique_ptr<tint::Program> program;
-  std::unique_ptr<tint::Source::File> source_file;
-
-  enum class InputFormat {
-    kUnknown,
-    kWgsl,
-    kSpirvBin,
-    kSpirvAsm,
-  };
-  auto input_format = InputFormat::kUnknown;
-
-  if (options.input_filename.size() > 5 &&
-      options.input_filename.substr(options.input_filename.size() - 5) ==
-          ".wgsl") {
-    input_format = InputFormat::kWgsl;
-  } else if (options.input_filename.size() > 4 &&
-             options.input_filename.substr(options.input_filename.size() - 4) ==
-                 ".spv") {
-    input_format = InputFormat::kSpirvBin;
-  } else if (options.input_filename.size() > 7 &&
-             options.input_filename.substr(options.input_filename.size() - 7) ==
-                 ".spvasm") {
-    input_format = InputFormat::kSpirvAsm;
-  }
-
-  switch (input_format) {
-    case InputFormat::kUnknown: {
-      std::cerr << "Unknown input format" << std::endl;
-      return 1;
+    if (options.show_help) {
+        std::string usage = tint::utils::ReplaceAll(kUsage, "${transforms}", transform_names());
+        std::cout << usage << std::endl;
+        return 0;
     }
-    case InputFormat::kWgsl: {
+
+    // Implement output format defaults.
+    if (options.format == Format::kNone) {
+        // Try inferring from filename.
+        options.format = infer_format(options.output_file);
+    }
+    if (options.format == Format::kNone) {
+        // Ultimately, default to SPIR-V assembly. That's nice for interactive use.
+        options.format = Format::kSpvAsm;
+    }
+
+    auto diag_printer = tint::diag::Printer::create(stderr, true);
+    tint::diag::Formatter diag_formatter;
+
+    std::unique_ptr<tint::Program> program;
+    std::unique_ptr<tint::Source::File> source_file;
+
+    enum class InputFormat {
+        kUnknown,
+        kWgsl,
+        kSpirvBin,
+        kSpirvAsm,
+    };
+    auto input_format = InputFormat::kUnknown;
+
+    if (options.input_filename.size() > 5 &&
+        options.input_filename.substr(options.input_filename.size() - 5) == ".wgsl") {
+        input_format = InputFormat::kWgsl;
+    } else if (options.input_filename.size() > 4 &&
+               options.input_filename.substr(options.input_filename.size() - 4) == ".spv") {
+        input_format = InputFormat::kSpirvBin;
+    } else if (options.input_filename.size() > 7 &&
+               options.input_filename.substr(options.input_filename.size() - 7) == ".spvasm") {
+        input_format = InputFormat::kSpirvAsm;
+    }
+
+    switch (input_format) {
+        case InputFormat::kUnknown: {
+            std::cerr << "Unknown input format" << std::endl;
+            return 1;
+        }
+        case InputFormat::kWgsl: {
 #if TINT_BUILD_WGSL_READER
-      std::vector<uint8_t> data;
-      if (!ReadFile<uint8_t>(options.input_filename, &data)) {
-        return 1;
-      }
-      source_file = std::make_unique<tint::Source::File>(
-          options.input_filename, std::string(data.begin(), data.end()));
-      program = std::make_unique<tint::Program>(
-          tint::reader::wgsl::Parse(source_file.get()));
-      break;
+            std::vector<uint8_t> data;
+            if (!ReadFile<uint8_t>(options.input_filename, &data)) {
+                return 1;
+            }
+            source_file = std::make_unique<tint::Source::File>(
+                options.input_filename, std::string(data.begin(), data.end()));
+            program = std::make_unique<tint::Program>(tint::reader::wgsl::Parse(source_file.get()));
+            break;
 #else
-      std::cerr << "Tint not built with the WGSL reader enabled" << std::endl;
-      return 1;
+            std::cerr << "Tint not built with the WGSL reader enabled" << std::endl;
+            return 1;
 #endif  // TINT_BUILD_WGSL_READER
-    }
-    case InputFormat::kSpirvBin: {
+        }
+        case InputFormat::kSpirvBin: {
 #if TINT_BUILD_SPV_READER
-      std::vector<uint32_t> data;
-      if (!ReadFile<uint32_t>(options.input_filename, &data)) {
-        return 1;
-      }
-      program =
-          std::make_unique<tint::Program>(tint::reader::spirv::Parse(data));
-      break;
+            std::vector<uint32_t> data;
+            if (!ReadFile<uint32_t>(options.input_filename, &data)) {
+                return 1;
+            }
+            program = std::make_unique<tint::Program>(tint::reader::spirv::Parse(data));
+            break;
 #else
-      std::cerr << "Tint not built with the SPIR-V reader enabled" << std::endl;
-      return 1;
+            std::cerr << "Tint not built with the SPIR-V reader enabled" << std::endl;
+            return 1;
 #endif  // TINT_BUILD_SPV_READER
-    }
-    case InputFormat::kSpirvAsm: {
+        }
+        case InputFormat::kSpirvAsm: {
 #if TINT_BUILD_SPV_READER
-      std::vector<char> text;
-      if (!ReadFile<char>(options.input_filename, &text)) {
-        return 1;
-      }
-      // Use Vulkan 1.1, since this is what Tint, internally, is expecting.
-      spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_1);
-      tools.SetMessageConsumer([](spv_message_level_t, const char*,
-                                  const spv_position_t& pos, const char* msg) {
-        std::cerr << (pos.line + 1) << ":" << (pos.column + 1) << ": " << msg
-                  << std::endl;
-      });
-      std::vector<uint32_t> data;
-      if (!tools.Assemble(text.data(), text.size(), &data,
-                          SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS)) {
-        return 1;
-      }
-      program =
-          std::make_unique<tint::Program>(tint::reader::spirv::Parse(data));
-      break;
+            std::vector<char> text;
+            if (!ReadFile<char>(options.input_filename, &text)) {
+                return 1;
+            }
+            // Use Vulkan 1.1, since this is what Tint, internally, is expecting.
+            spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_1);
+            tools.SetMessageConsumer([](spv_message_level_t, const char*, const spv_position_t& pos,
+                                        const char* msg) {
+                std::cerr << (pos.line + 1) << ":" << (pos.column + 1) << ": " << msg << std::endl;
+            });
+            std::vector<uint32_t> data;
+            if (!tools.Assemble(text.data(), text.size(), &data,
+                                SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS)) {
+                return 1;
+            }
+            program = std::make_unique<tint::Program>(tint::reader::spirv::Parse(data));
+            break;
 #else
-      std::cerr << "Tint not built with the SPIR-V reader enabled" << std::endl;
-      return 1;
+            std::cerr << "Tint not built with the SPIR-V reader enabled" << std::endl;
+            return 1;
 #endif  // TINT_BUILD_SPV_READER
+        }
     }
-  }
 
-  if (!program) {
-    std::cerr << "Failed to parse input file: " << options.input_filename
-              << std::endl;
-    return 1;
-  }
-  if (program->Diagnostics().count() > 0) {
-    if (!program->IsValid() && input_format != InputFormat::kWgsl) {
-      // Invalid program from a non-wgsl source. Print the WGSL, to help
-      // understand the diagnostics.
-      PrintWGSL(std::cout, *program);
+    if (!program) {
+        std::cerr << "Failed to parse input file: " << options.input_filename << std::endl;
+        return 1;
     }
-    diag_formatter.format(program->Diagnostics(), diag_printer.get());
-  }
-
-  if (!program->IsValid()) {
-    return 1;
-  }
-  if (options.parse_only) {
-    return 1;
-  }
-
-  tint::transform::Manager transform_manager;
-  tint::transform::DataMap transform_inputs;
-  for (const auto& name : options.transforms) {
-    // TODO(dsinclair): The vertex pulling transform requires setup code to
-    // be run that needs user input. Should we find a way to support that here
-    // maybe through a provided file?
-
-    bool found = false;
-    for (auto& t : transforms) {
-      if (t.name == name) {
-        t.make(transform_manager, transform_inputs);
-        found = true;
-        break;
-      }
+    if (program->Diagnostics().count() > 0) {
+        if (!program->IsValid() && input_format != InputFormat::kWgsl) {
+            // Invalid program from a non-wgsl source. Print the WGSL, to help
+            // understand the diagnostics.
+            PrintWGSL(std::cout, *program);
+        }
+        diag_formatter.format(program->Diagnostics(), diag_printer.get());
     }
-    if (!found) {
-      std::cerr << "Unknown transform: " << name << std::endl;
-      std::cerr << "Available transforms: " << std::endl << transform_names();
-      return 1;
+
+    if (!program->IsValid()) {
+        return 1;
     }
-  }
+    if (options.parse_only) {
+        return 1;
+    }
 
-  if (options.emit_single_entry_point) {
-    transform_manager.append(
-        std::make_unique<tint::transform::SingleEntryPoint>());
-    transform_inputs.Add<tint::transform::SingleEntryPoint::Config>(
-        options.ep_name);
-  }
+    tint::transform::Manager transform_manager;
+    tint::transform::DataMap transform_inputs;
+    for (const auto& name : options.transforms) {
+        // TODO(dsinclair): The vertex pulling transform requires setup code to
+        // be run that needs user input. Should we find a way to support that here
+        // maybe through a provided file?
 
-  switch (options.format) {
-    case Format::kMsl: {
+        bool found = false;
+        for (auto& t : transforms) {
+            if (t.name == name) {
+                t.make(transform_manager, transform_inputs);
+                found = true;
+                break;
+            }
+        }
+        if (!found) {
+            std::cerr << "Unknown transform: " << name << std::endl;
+            std::cerr << "Available transforms: " << std::endl << transform_names();
+            return 1;
+        }
+    }
+
+    if (options.emit_single_entry_point) {
+        transform_manager.append(std::make_unique<tint::transform::SingleEntryPoint>());
+        transform_inputs.Add<tint::transform::SingleEntryPoint::Config>(options.ep_name);
+    }
+
+    switch (options.format) {
+        case Format::kMsl: {
 #if TINT_BUILD_MSL_WRITER
-      transform_inputs.Add<tint::transform::Renamer::Config>(
-          tint::transform::Renamer::Target::kMslKeywords,
-          /* preserve_unicode */ false);
-      transform_manager.Add<tint::transform::Renamer>();
+            transform_inputs.Add<tint::transform::Renamer::Config>(
+                tint::transform::Renamer::Target::kMslKeywords,
+                /* preserve_unicode */ false);
+            transform_manager.Add<tint::transform::Renamer>();
 #endif  // TINT_BUILD_MSL_WRITER
-      break;
-    }
+            break;
+        }
 #if TINT_BUILD_GLSL_WRITER
-    case Format::kGlsl: {
-      break;
-    }
+        case Format::kGlsl: {
+            break;
+        }
 #endif  // TINT_BUILD_GLSL_WRITER
-    case Format::kHlsl: {
+        case Format::kHlsl: {
 #if TINT_BUILD_HLSL_WRITER
-      transform_inputs.Add<tint::transform::Renamer::Config>(
-          tint::transform::Renamer::Target::kHlslKeywords,
-          /* preserve_unicode */ false);
-      transform_manager.Add<tint::transform::Renamer>();
+            transform_inputs.Add<tint::transform::Renamer::Config>(
+                tint::transform::Renamer::Target::kHlslKeywords,
+                /* preserve_unicode */ false);
+            transform_manager.Add<tint::transform::Renamer>();
 #endif  // TINT_BUILD_HLSL_WRITER
-      break;
-    }
-    default:
-      break;
-  }
-
-  auto out = transform_manager.Run(program.get(), std::move(transform_inputs));
-  if (!out.program.IsValid()) {
-    PrintWGSL(std::cerr, out.program);
-    diag_formatter.format(out.program.Diagnostics(), diag_printer.get());
-    return 1;
-  }
-
-  *program = std::move(out.program);
-
-  if (options.dump_inspector_bindings) {
-    std::cout << std::string(80, '-') << std::endl;
-    tint::inspector::Inspector inspector(program.get());
-    auto entry_points = inspector.GetEntryPoints();
-    if (!inspector.error().empty()) {
-      std::cerr << "Failed to get entry points from Inspector: "
-                << inspector.error() << std::endl;
-      return 1;
+            break;
+        }
+        default:
+            break;
     }
 
-    for (auto& entry_point : entry_points) {
-      auto bindings = inspector.GetResourceBindings(entry_point.name);
-      if (!inspector.error().empty()) {
-        std::cerr << "Failed to get bindings from Inspector: "
-                  << inspector.error() << std::endl;
+    auto out = transform_manager.Run(program.get(), std::move(transform_inputs));
+    if (!out.program.IsValid()) {
+        PrintWGSL(std::cerr, out.program);
+        diag_formatter.format(out.program.Diagnostics(), diag_printer.get());
         return 1;
-      }
-      std::cout << "Entry Point = " << entry_point.name << std::endl;
-      for (auto& binding : bindings) {
-        std::cout << "\t[" << binding.bind_group << "][" << binding.binding
-                  << "]:" << std::endl;
-        std::cout << "\t\t resource_type = "
-                  << ResourceTypeToString(binding.resource_type) << std::endl;
-        std::cout << "\t\t dim = " << TextureDimensionToString(binding.dim)
-                  << std::endl;
-        std::cout << "\t\t sampled_kind = "
-                  << SampledKindToString(binding.sampled_kind) << std::endl;
-        std::cout << "\t\t image_format = "
-                  << TexelFormatToString(binding.image_format) << std::endl;
-      }
     }
-    std::cout << std::string(80, '-') << std::endl;
-  }
 
-  bool success = false;
-  switch (options.format) {
-    case Format::kSpirv:
-    case Format::kSpvAsm:
-      success = GenerateSpirv(program.get(), options);
-      break;
-    case Format::kWgsl:
-      success = GenerateWgsl(program.get(), options);
-      break;
-    case Format::kMsl:
-      success = GenerateMsl(program.get(), options);
-      break;
-    case Format::kHlsl:
-      success = GenerateHlsl(program.get(), options);
-      break;
-    case Format::kGlsl:
-      success = GenerateGlsl(program.get(), options);
-      break;
-    default:
-      std::cerr << "Unknown output format specified" << std::endl;
-      return 1;
-  }
-  if (!success) {
-    return 1;
-  }
+    *program = std::move(out.program);
 
-  return 0;
+    if (options.dump_inspector_bindings) {
+        std::cout << std::string(80, '-') << std::endl;
+        tint::inspector::Inspector inspector(program.get());
+        auto entry_points = inspector.GetEntryPoints();
+        if (!inspector.error().empty()) {
+            std::cerr << "Failed to get entry points from Inspector: " << inspector.error()
+                      << std::endl;
+            return 1;
+        }
+
+        for (auto& entry_point : entry_points) {
+            auto bindings = inspector.GetResourceBindings(entry_point.name);
+            if (!inspector.error().empty()) {
+                std::cerr << "Failed to get bindings from Inspector: " << inspector.error()
+                          << std::endl;
+                return 1;
+            }
+            std::cout << "Entry Point = " << entry_point.name << std::endl;
+            for (auto& binding : bindings) {
+                std::cout << "\t[" << binding.bind_group << "][" << binding.binding
+                          << "]:" << std::endl;
+                std::cout << "\t\t resource_type = " << ResourceTypeToString(binding.resource_type)
+                          << std::endl;
+                std::cout << "\t\t dim = " << TextureDimensionToString(binding.dim) << std::endl;
+                std::cout << "\t\t sampled_kind = " << SampledKindToString(binding.sampled_kind)
+                          << std::endl;
+                std::cout << "\t\t image_format = " << TexelFormatToString(binding.image_format)
+                          << std::endl;
+            }
+        }
+        std::cout << std::string(80, '-') << std::endl;
+    }
+
+    bool success = false;
+    switch (options.format) {
+        case Format::kSpirv:
+        case Format::kSpvAsm:
+            success = GenerateSpirv(program.get(), options);
+            break;
+        case Format::kWgsl:
+            success = GenerateWgsl(program.get(), options);
+            break;
+        case Format::kMsl:
+            success = GenerateMsl(program.get(), options);
+            break;
+        case Format::kHlsl:
+            success = GenerateHlsl(program.get(), options);
+            break;
+        case Format::kGlsl:
+            success = GenerateGlsl(program.get(), options);
+            break;
+        default:
+            std::cerr << "Unknown output format specified" << std::endl;
+            return 1;
+    }
+    if (!success) {
+        return 1;
+    }
+
+    return 0;
 }
diff --git a/src/tint/debug.cc b/src/tint/debug.cc
index c51cf3f..72da293 100644
--- a/src/tint/debug.cc
+++ b/src/tint/debug.cc
@@ -26,7 +26,7 @@
 }  // namespace
 
 void SetInternalCompilerErrorReporter(InternalCompilerErrorReporter* reporter) {
-  ice_reporter = reporter;
+    ice_reporter = reporter;
 }
 
 InternalCompilerError::InternalCompilerError(const char* file,
@@ -36,15 +36,15 @@
     : file_(file), line_(line), system_(system), diagnostics_(diagnostics) {}
 
 InternalCompilerError::~InternalCompilerError() {
-  auto file = std::make_shared<Source::File>(file_, "");
-  Source source{Source::Range{{line_}}, file.get()};
-  diagnostics_.add_ice(system_, msg_.str(), source, std::move(file));
+    auto file = std::make_shared<Source::File>(file_, "");
+    Source source{Source::Range{{line_}}, file.get()};
+    diagnostics_.add_ice(system_, msg_.str(), source, std::move(file));
 
-  if (ice_reporter) {
-    ice_reporter(diagnostics_);
-  }
+    if (ice_reporter) {
+        ice_reporter(diagnostics_);
+    }
 
-  debugger::Break();
+    debugger::Break();
 }
 
 }  // namespace tint
diff --git a/src/tint/debug.h b/src/tint/debug.h
index 90e6b66..86186ac 100644
--- a/src/tint/debug.h
+++ b/src/tint/debug.h
@@ -40,37 +40,37 @@
 /// InternalCompilerErrorReporter is set, then it is called with the diagnostic
 /// list.
 class InternalCompilerError {
- public:
-  /// Constructor
-  /// @param file the file containing the ICE
-  /// @param line the line containing the ICE
-  /// @param system the Tint system that has raised the ICE
-  /// @param diagnostics the list of diagnostics to append the ICE message to
-  InternalCompilerError(const char* file,
-                        size_t line,
-                        diag::System system,
-                        diag::List& diagnostics);
+  public:
+    /// Constructor
+    /// @param file the file containing the ICE
+    /// @param line the line containing the ICE
+    /// @param system the Tint system that has raised the ICE
+    /// @param diagnostics the list of diagnostics to append the ICE message to
+    InternalCompilerError(const char* file,
+                          size_t line,
+                          diag::System system,
+                          diag::List& diagnostics);
 
-  /// Destructor.
-  /// Adds the internal compiler error message to the diagnostics list, and then
-  /// calls the InternalCompilerErrorReporter if one is set.
-  ~InternalCompilerError();
+    /// Destructor.
+    /// Adds the internal compiler error message to the diagnostics list, and then
+    /// calls the InternalCompilerErrorReporter if one is set.
+    ~InternalCompilerError();
 
-  /// Appends `arg` to the ICE message.
-  /// @param arg the argument to append to the ICE message
-  /// @returns this object so calls can be chained
-  template <typename T>
-  InternalCompilerError& operator<<(T&& arg) {
-    msg_ << std::forward<T>(arg);
-    return *this;
-  }
+    /// Appends `arg` to the ICE message.
+    /// @param arg the argument to append to the ICE message
+    /// @returns this object so calls can be chained
+    template <typename T>
+    InternalCompilerError& operator<<(T&& arg) {
+        msg_ << std::forward<T>(arg);
+        return *this;
+    }
 
- private:
-  char const* const file_;
-  const size_t line_;
-  diag::System system_;
-  diag::List& diagnostics_;
-  std::stringstream msg_;
+  private:
+    char const* const file_;
+    const size_t line_;
+    diag::System system_;
+    diag::List& diagnostics_;
+    std::stringstream msg_;
 };
 
 }  // namespace tint
@@ -81,9 +81,8 @@
 /// set.
 /// The ICE message contains the callsite's file and line.
 /// Use the `<<` operator to append an error message to the ICE.
-#define TINT_ICE(system, diagnostics)             \
-  tint::InternalCompilerError(__FILE__, __LINE__, \
-                              ::tint::diag::System::system, diagnostics)
+#define TINT_ICE(system, diagnostics) \
+    tint::InternalCompilerError(__FILE__, __LINE__, ::tint::diag::System::system, diagnostics)
 
 /// TINT_UNREACHABLE() is a macro for appending a "TINT_UNREACHABLE"
 /// internal compiler error message to the diagnostics list `diagnostics`, and
@@ -91,8 +90,7 @@
 /// reporter is set.
 /// The ICE message contains the callsite's file and line.
 /// Use the `<<` operator to append an error message to the ICE.
-#define TINT_UNREACHABLE(system, diagnostics) \
-  TINT_ICE(system, diagnostics) << "TINT_UNREACHABLE "
+#define TINT_UNREACHABLE(system, diagnostics) TINT_ICE(system, diagnostics) << "TINT_UNREACHABLE "
 
 /// TINT_UNIMPLEMENTED() is a macro for appending a "TINT_UNIMPLEMENTED"
 /// internal compiler error message to the diagnostics list `diagnostics`, and
@@ -101,7 +99,7 @@
 /// The ICE message contains the callsite's file and line.
 /// Use the `<<` operator to append an error message to the ICE.
 #define TINT_UNIMPLEMENTED(system, diagnostics) \
-  TINT_ICE(system, diagnostics) << "TINT_UNIMPLEMENTED "
+    TINT_ICE(system, diagnostics) << "TINT_UNIMPLEMENTED "
 
 /// TINT_ASSERT() is a macro for checking the expression is true, triggering a
 /// TINT_ICE if it is not.
@@ -111,13 +109,12 @@
 /// may silently fail in builds where SetInternalCompilerErrorReporter() is not
 /// called. Only use in places where there's no sensible place to put proper
 /// error handling.
-#define TINT_ASSERT(system, condition)                   \
-  do {                                                   \
-    if (!(condition)) {                                  \
-      tint::diag::List diagnostics;                      \
-      TINT_ICE(system, diagnostics)                      \
-          << "TINT_ASSERT(" #system ", " #condition ")"; \
-    }                                                    \
-  } while (false)
+#define TINT_ASSERT(system, condition)                                                   \
+    do {                                                                                 \
+        if (!(condition)) {                                                              \
+            tint::diag::List diagnostics;                                                \
+            TINT_ICE(system, diagnostics) << "TINT_ASSERT(" #system ", " #condition ")"; \
+        }                                                                                \
+    } while (false)
 
 #endif  // SRC_TINT_DEBUG_H_
diff --git a/src/tint/debug_test.cc b/src/tint/debug_test.cc
index 257b312..2d21277 100644
--- a/src/tint/debug_test.cc
+++ b/src/tint/debug_test.cc
@@ -20,21 +20,20 @@
 namespace {
 
 TEST(DebugTest, Unreachable) {
-  EXPECT_FATAL_FAILURE(
-      {
-        diag::List diagnostics;
-        TINT_UNREACHABLE(Test, diagnostics);
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            diag::List diagnostics;
+            TINT_UNREACHABLE(Test, diagnostics);
+        },
+        "internal compiler error");
 }
 
 TEST(DebugTest, AssertTrue) {
-  TINT_ASSERT(Test, true);
+    TINT_ASSERT(Test, true);
 }
 
 TEST(DebugTest, AssertFalse) {
-  EXPECT_FATAL_FAILURE({ TINT_ASSERT(Test, false); },
-                       "internal compiler error");
+    EXPECT_FATAL_FAILURE({ TINT_ASSERT(Test, false); }, "internal compiler error");
 }
 
 }  // namespace
diff --git a/src/tint/demangler.cc b/src/tint/demangler.cc
index cf5e4d6..0116be0 100644
--- a/src/tint/demangler.cc
+++ b/src/tint/demangler.cc
@@ -28,35 +28,34 @@
 
 Demangler::~Demangler() = default;
 
-std::string Demangler::Demangle(const SymbolTable& symbols,
-                                const std::string& str) const {
-  std::stringstream out;
+std::string Demangler::Demangle(const SymbolTable& symbols, const std::string& str) const {
+    std::stringstream out;
 
-  size_t pos = 0;
-  for (;;) {
-    auto idx = str.find(kSymbol, pos);
-    if (idx == std::string::npos) {
-      out << str.substr(pos);
-      break;
+    size_t pos = 0;
+    for (;;) {
+        auto idx = str.find(kSymbol, pos);
+        if (idx == std::string::npos) {
+            out << str.substr(pos);
+            break;
+        }
+
+        out << str.substr(pos, idx - pos);
+
+        auto start_idx = idx + kSymbolLen;
+        auto end_idx = start_idx;
+        while (str[end_idx] >= '0' && str[end_idx] <= '9') {
+            end_idx++;
+        }
+        auto len = end_idx - start_idx;
+
+        auto id = str.substr(start_idx, len);
+        Symbol sym(std::stoi(id), symbols.ProgramID());
+        out << symbols.NameFor(sym);
+
+        pos = end_idx;
     }
 
-    out << str.substr(pos, idx - pos);
-
-    auto start_idx = idx + kSymbolLen;
-    auto end_idx = start_idx;
-    while (str[end_idx] >= '0' && str[end_idx] <= '9') {
-      end_idx++;
-    }
-    auto len = end_idx - start_idx;
-
-    auto id = str.substr(start_idx, len);
-    Symbol sym(std::stoi(id), symbols.ProgramID());
-    out << symbols.NameFor(sym);
-
-    pos = end_idx;
-  }
-
-  return out.str();
+    return out.str();
 }
 
 }  // namespace tint
diff --git a/src/tint/demangler.h b/src/tint/demangler.h
index 8c0c964..c187d48 100644
--- a/src/tint/demangler.h
+++ b/src/tint/demangler.h
@@ -23,18 +23,17 @@
 
 /// Helper to demangle strings and replace symbols with original names
 class Demangler {
- public:
-  /// Constructor
-  Demangler();
-  /// Destructor
-  ~Demangler();
+  public:
+    /// Constructor
+    Demangler();
+    /// Destructor
+    ~Demangler();
 
-  /// Transforms given string and replaces any symbols with original names
-  /// @param symbols the symbol table
-  /// @param str the string to replace
-  /// @returns the string with any symbol replacements performed.
-  std::string Demangle(const SymbolTable& symbols,
-                       const std::string& str) const;
+    /// Transforms given string and replaces any symbols with original names
+    /// @param symbols the symbol table
+    /// @param str the string to replace
+    /// @returns the string with any symbol replacements performed.
+    std::string Demangle(const SymbolTable& symbols, const std::string& str) const;
 };
 
 }  // namespace tint
diff --git a/src/tint/demangler_test.cc b/src/tint/demangler_test.cc
index f2c7658..8f7627a 100644
--- a/src/tint/demangler_test.cc
+++ b/src/tint/demangler_test.cc
@@ -23,28 +23,28 @@
 using DemanglerTest = testing::Test;
 
 TEST_F(DemanglerTest, NoSymbols) {
-  SymbolTable t{ProgramID::New()};
-  t.Register("sym1");
+    SymbolTable t{ProgramID::New()};
+    t.Register("sym1");
 
-  Demangler d;
-  EXPECT_EQ("test str", d.Demangle(t, "test str"));
+    Demangler d;
+    EXPECT_EQ("test str", d.Demangle(t, "test str"));
 }
 
 TEST_F(DemanglerTest, Symbol) {
-  SymbolTable t{ProgramID::New()};
-  t.Register("sym1");
+    SymbolTable t{ProgramID::New()};
+    t.Register("sym1");
 
-  Demangler d;
-  EXPECT_EQ("test sym1 str", d.Demangle(t, "test $1 str"));
+    Demangler d;
+    EXPECT_EQ("test sym1 str", d.Demangle(t, "test $1 str"));
 }
 
 TEST_F(DemanglerTest, MultipleSymbols) {
-  SymbolTable t{ProgramID::New()};
-  t.Register("sym1");
-  t.Register("sym2");
+    SymbolTable t{ProgramID::New()};
+    t.Register("sym1");
+    t.Register("sym2");
 
-  Demangler d;
-  EXPECT_EQ("test sym1 sym2 sym1 str", d.Demangle(t, "test $1 $2 $1 str"));
+    Demangler d;
+    EXPECT_EQ("test sym1 sym2 sym1 str", d.Demangle(t, "test $1 $2 $1 str"));
 }
 
 }  // namespace
diff --git a/src/tint/diagnostic/diagnostic.cc b/src/tint/diagnostic/diagnostic.cc
index bd3f297..a87e43b 100644
--- a/src/tint/diagnostic/diagnostic.cc
+++ b/src/tint/diagnostic/diagnostic.cc
@@ -38,9 +38,9 @@
 List& List::operator=(List&& rhs) = default;
 
 std::string List::str() const {
-  diag::Formatter::Style style;
-  style.print_newline_at_end = false;
-  return Formatter{style}.format(*this);
+    diag::Formatter::Style style;
+    style.print_newline_at_end = false;
+    return Formatter{style}.format(*this);
 }
 
 }  // namespace tint::diag
diff --git a/src/tint/diagnostic/diagnostic.h b/src/tint/diagnostic/diagnostic.h
index 95df553..de57c99 100644
--- a/src/tint/diagnostic/diagnostic.h
+++ b/src/tint/diagnostic/diagnostic.h
@@ -29,220 +29,213 @@
 
 /// @return true iff `a` is more than, or of equal severity to `b`
 inline bool operator>=(Severity a, Severity b) {
-  return static_cast<int>(a) >= static_cast<int>(b);
+    return static_cast<int>(a) >= static_cast<int>(b);
 }
 
 /// System is an enumerator of Tint systems that can be the originator of a
 /// diagnostic message.
 enum class System {
-  AST,
-  Clone,
-  Inspector,
-  Program,
-  ProgramBuilder,
-  Reader,
-  Resolver,
-  Semantic,
-  Symbol,
-  Test,
-  Transform,
-  Utils,
-  Writer,
+    AST,
+    Clone,
+    Inspector,
+    Program,
+    ProgramBuilder,
+    Reader,
+    Resolver,
+    Semantic,
+    Symbol,
+    Test,
+    Transform,
+    Utils,
+    Writer,
 };
 
 /// Diagnostic holds all the information for a single compiler diagnostic
 /// message.
 class Diagnostic {
- public:
-  /// Constructor
-  Diagnostic();
-  /// Copy constructor
-  Diagnostic(const Diagnostic&);
-  /// Destructor
-  ~Diagnostic();
+  public:
+    /// Constructor
+    Diagnostic();
+    /// Copy constructor
+    Diagnostic(const Diagnostic&);
+    /// Destructor
+    ~Diagnostic();
 
-  /// Copy assignment operator
-  /// @return this diagnostic
-  Diagnostic& operator=(const Diagnostic&);
+    /// Copy assignment operator
+    /// @return this diagnostic
+    Diagnostic& operator=(const Diagnostic&);
 
-  /// severity is the severity of the diagnostic message.
-  Severity severity = Severity::Error;
-  /// source is the location of the diagnostic.
-  Source source;
-  /// message is the text associated with the diagnostic.
-  std::string message;
-  /// system is the Tint system that raised the diagnostic.
-  System system;
-  /// code is the error code, for example a validation error might have the code
-  /// `"v-0001"`.
-  const char* code = nullptr;
-  /// A shared pointer to a Source::File. Only used if the diagnostic Source
-  /// points to a file that was created specifically for this diagnostic
-  /// (usually an ICE).
-  std::shared_ptr<Source::File> owned_file = nullptr;
+    /// severity is the severity of the diagnostic message.
+    Severity severity = Severity::Error;
+    /// source is the location of the diagnostic.
+    Source source;
+    /// message is the text associated with the diagnostic.
+    std::string message;
+    /// system is the Tint system that raised the diagnostic.
+    System system;
+    /// code is the error code, for example a validation error might have the code
+    /// `"v-0001"`.
+    const char* code = nullptr;
+    /// A shared pointer to a Source::File. Only used if the diagnostic Source
+    /// points to a file that was created specifically for this diagnostic
+    /// (usually an ICE).
+    std::shared_ptr<Source::File> owned_file = nullptr;
 };
 
 /// List is a container of Diagnostic messages.
 class List {
- public:
-  /// iterator is the type used for range based iteration.
-  using iterator = std::vector<Diagnostic>::const_iterator;
+  public:
+    /// iterator is the type used for range based iteration.
+    using iterator = std::vector<Diagnostic>::const_iterator;
 
-  /// Constructs the list with no elements.
-  List();
+    /// Constructs the list with no elements.
+    List();
 
-  /// Copy constructor. Copies the diagnostics from `list` into this list.
-  /// @param list the list of diagnostics to copy into this list.
-  List(std::initializer_list<Diagnostic> list);
+    /// Copy constructor. Copies the diagnostics from `list` into this list.
+    /// @param list the list of diagnostics to copy into this list.
+    List(std::initializer_list<Diagnostic> list);
 
-  /// Copy constructor. Copies the diagnostics from `list` into this list.
-  /// @param list the list of diagnostics to copy into this list.
-  List(const List& list);
+    /// Copy constructor. Copies the diagnostics from `list` into this list.
+    /// @param list the list of diagnostics to copy into this list.
+    List(const List& list);
 
-  /// Move constructor. Moves the diagnostics from `list` into this list.
-  /// @param list the list of diagnostics to move into this list.
-  List(List&& list);
+    /// Move constructor. Moves the diagnostics from `list` into this list.
+    /// @param list the list of diagnostics to move into this list.
+    List(List&& list);
 
-  /// Destructor
-  ~List();
+    /// Destructor
+    ~List();
 
-  /// Assignment operator. Copies the diagnostics from `list` into this list.
-  /// @param list the list to copy into this list.
-  /// @return this list.
-  List& operator=(const List& list);
+    /// Assignment operator. Copies the diagnostics from `list` into this list.
+    /// @param list the list to copy into this list.
+    /// @return this list.
+    List& operator=(const List& list);
 
-  /// Assignment move operator. Moves the diagnostics from `list` into this
-  /// list.
-  /// @param list the list to move into this list.
-  /// @return this list.
-  List& operator=(List&& list);
+    /// Assignment move operator. Moves the diagnostics from `list` into this
+    /// list.
+    /// @param list the list to move into this list.
+    /// @return this list.
+    List& operator=(List&& list);
 
-  /// adds a diagnostic to the end of this list.
-  /// @param diag the diagnostic to append to this list.
-  void add(Diagnostic&& diag) {
-    if (diag.severity >= Severity::Error) {
-      error_count_++;
+    /// adds a diagnostic to the end of this list.
+    /// @param diag the diagnostic to append to this list.
+    void add(Diagnostic&& diag) {
+        if (diag.severity >= Severity::Error) {
+            error_count_++;
+        }
+        entries_.emplace_back(std::move(diag));
     }
-    entries_.emplace_back(std::move(diag));
-  }
 
-  /// adds a list of diagnostics to the end of this list.
-  /// @param list the diagnostic to append to this list.
-  void add(const List& list) {
-    for (auto diag : list) {
-      add(std::move(diag));
+    /// adds a list of diagnostics to the end of this list.
+    /// @param list the diagnostic to append to this list.
+    void add(const List& list) {
+        for (auto diag : list) {
+            add(std::move(diag));
+        }
     }
-  }
 
-  /// adds the note message with the given Source to the end of this list.
-  /// @param system the system raising the note message
-  /// @param note_msg the note message
-  /// @param source the source of the note diagnostic
-  void add_note(System system,
-                const std::string& note_msg,
-                const Source& source) {
-    diag::Diagnostic note{};
-    note.severity = diag::Severity::Note;
-    note.system = system;
-    note.source = source;
-    note.message = note_msg;
-    add(std::move(note));
-  }
+    /// adds the note message with the given Source to the end of this list.
+    /// @param system the system raising the note message
+    /// @param note_msg the note message
+    /// @param source the source of the note diagnostic
+    void add_note(System system, const std::string& note_msg, const Source& source) {
+        diag::Diagnostic note{};
+        note.severity = diag::Severity::Note;
+        note.system = system;
+        note.source = source;
+        note.message = note_msg;
+        add(std::move(note));
+    }
 
-  /// adds the warning message with the given Source to the end of this list.
-  /// @param system the system raising the warning message
-  /// @param warning_msg the warning message
-  /// @param source the source of the warning diagnostic
-  void add_warning(System system,
-                   const std::string& warning_msg,
-                   const Source& source) {
-    diag::Diagnostic warning{};
-    warning.severity = diag::Severity::Warning;
-    warning.system = system;
-    warning.source = source;
-    warning.message = warning_msg;
-    add(std::move(warning));
-  }
+    /// adds the warning message with the given Source to the end of this list.
+    /// @param system the system raising the warning message
+    /// @param warning_msg the warning message
+    /// @param source the source of the warning diagnostic
+    void add_warning(System system, const std::string& warning_msg, const Source& source) {
+        diag::Diagnostic warning{};
+        warning.severity = diag::Severity::Warning;
+        warning.system = system;
+        warning.source = source;
+        warning.message = warning_msg;
+        add(std::move(warning));
+    }
 
-  /// adds the error message without a source to the end of this list.
-  /// @param system the system raising the error message
-  /// @param err_msg the error message
-  void add_error(System system, std::string err_msg) {
-    diag::Diagnostic error{};
-    error.severity = diag::Severity::Error;
-    error.system = system;
-    error.message = std::move(err_msg);
-    add(std::move(error));
-  }
+    /// adds the error message without a source to the end of this list.
+    /// @param system the system raising the error message
+    /// @param err_msg the error message
+    void add_error(System system, std::string err_msg) {
+        diag::Diagnostic error{};
+        error.severity = diag::Severity::Error;
+        error.system = system;
+        error.message = std::move(err_msg);
+        add(std::move(error));
+    }
 
-  /// adds the error message with the given Source to the end of this list.
-  /// @param system the system raising the error message
-  /// @param err_msg the error message
-  /// @param source the source of the error diagnostic
-  void add_error(System system, std::string err_msg, const Source& source) {
-    diag::Diagnostic error{};
-    error.severity = diag::Severity::Error;
-    error.system = system;
-    error.source = source;
-    error.message = std::move(err_msg);
-    add(std::move(error));
-  }
+    /// adds the error message with the given Source to the end of this list.
+    /// @param system the system raising the error message
+    /// @param err_msg the error message
+    /// @param source the source of the error diagnostic
+    void add_error(System system, std::string err_msg, const Source& source) {
+        diag::Diagnostic error{};
+        error.severity = diag::Severity::Error;
+        error.system = system;
+        error.source = source;
+        error.message = std::move(err_msg);
+        add(std::move(error));
+    }
 
-  /// adds the error message with the given code and Source to the end of this
-  /// list.
-  /// @param system the system raising the error message
-  /// @param code the error code
-  /// @param err_msg the error message
-  /// @param source the source of the error diagnostic
-  void add_error(System system,
-                 const char* code,
-                 std::string err_msg,
-                 const Source& source) {
-    diag::Diagnostic error{};
-    error.code = code;
-    error.severity = diag::Severity::Error;
-    error.system = system;
-    error.source = source;
-    error.message = std::move(err_msg);
-    add(std::move(error));
-  }
+    /// adds the error message with the given code and Source to the end of this
+    /// list.
+    /// @param system the system raising the error message
+    /// @param code the error code
+    /// @param err_msg the error message
+    /// @param source the source of the error diagnostic
+    void add_error(System system, const char* code, std::string err_msg, const Source& source) {
+        diag::Diagnostic error{};
+        error.code = code;
+        error.severity = diag::Severity::Error;
+        error.system = system;
+        error.source = source;
+        error.message = std::move(err_msg);
+        add(std::move(error));
+    }
 
-  /// adds an internal compiler error message to the end of this list.
-  /// @param system the system raising the error message
-  /// @param err_msg the error message
-  /// @param source the source of the internal compiler error
-  /// @param file the Source::File owned by this diagnostic
-  void add_ice(System system,
-               const std::string& err_msg,
-               const Source& source,
-               std::shared_ptr<Source::File> file) {
-    diag::Diagnostic ice{};
-    ice.severity = diag::Severity::InternalCompilerError;
-    ice.system = system;
-    ice.source = source;
-    ice.message = err_msg;
-    ice.owned_file = std::move(file);
-    add(std::move(ice));
-  }
+    /// adds an internal compiler error message to the end of this list.
+    /// @param system the system raising the error message
+    /// @param err_msg the error message
+    /// @param source the source of the internal compiler error
+    /// @param file the Source::File owned by this diagnostic
+    void add_ice(System system,
+                 const std::string& err_msg,
+                 const Source& source,
+                 std::shared_ptr<Source::File> file) {
+        diag::Diagnostic ice{};
+        ice.severity = diag::Severity::InternalCompilerError;
+        ice.system = system;
+        ice.source = source;
+        ice.message = err_msg;
+        ice.owned_file = std::move(file);
+        add(std::move(ice));
+    }
 
-  /// @returns true iff the diagnostic list contains errors diagnostics (or of
-  /// higher severity).
-  bool contains_errors() const { return error_count_ > 0; }
-  /// @returns the number of error diagnostics (or of higher severity).
-  size_t error_count() const { return error_count_; }
-  /// @returns the number of entries in the list.
-  size_t count() const { return entries_.size(); }
-  /// @returns the first diagnostic in the list.
-  iterator begin() const { return entries_.begin(); }
-  /// @returns the last diagnostic in the list.
-  iterator end() const { return entries_.end(); }
+    /// @returns true iff the diagnostic list contains errors diagnostics (or of
+    /// higher severity).
+    bool contains_errors() const { return error_count_ > 0; }
+    /// @returns the number of error diagnostics (or of higher severity).
+    size_t error_count() const { return error_count_; }
+    /// @returns the number of entries in the list.
+    size_t count() const { return entries_.size(); }
+    /// @returns the first diagnostic in the list.
+    iterator begin() const { return entries_.begin(); }
+    /// @returns the last diagnostic in the list.
+    iterator end() const { return entries_.end(); }
 
-  /// @returns a formatted string of all the diagnostics in this list.
-  std::string str() const;
+    /// @returns a formatted string of all the diagnostics in this list.
+    std::string str() const;
 
- private:
-  std::vector<Diagnostic> entries_;
-  size_t error_count_ = 0;
+  private:
+    std::vector<Diagnostic> entries_;
+    size_t error_count_ = 0;
 };
 
 }  // namespace tint::diag
diff --git a/src/tint/diagnostic/diagnostic_test.cc b/src/tint/diagnostic/diagnostic_test.cc
index 8bf65e6..0494e76 100644
--- a/src/tint/diagnostic/diagnostic_test.cc
+++ b/src/tint/diagnostic/diagnostic_test.cc
@@ -21,19 +21,19 @@
 namespace {
 
 TEST(DiagListTest, OwnedFilesShared) {
-  auto file = std::make_shared<Source::File>("path", "content");
+    auto file = std::make_shared<Source::File>("path", "content");
 
-  diag::List list_a, list_b;
-  {
-    diag::Diagnostic diag{};
-    diag.source = Source{Source::Range{{0, 0}}, file.get()};
-    list_a.add(std::move(diag));
-  }
+    diag::List list_a, list_b;
+    {
+        diag::Diagnostic diag{};
+        diag.source = Source{Source::Range{{0, 0}}, file.get()};
+        list_a.add(std::move(diag));
+    }
 
-  list_b = list_a;
+    list_b = list_a;
 
-  ASSERT_EQ(list_b.count(), list_a.count());
-  EXPECT_EQ(list_b.begin()->source.file, file.get());
+    ASSERT_EQ(list_b.count(), list_a.count());
+    EXPECT_EQ(list_b.begin()->source.file, file.get());
 }
 
 }  // namespace
diff --git a/src/tint/diagnostic/formatter.cc b/src/tint/diagnostic/formatter.cc
index 262be86..db69397 100644
--- a/src/tint/diagnostic/formatter.cc
+++ b/src/tint/diagnostic/formatter.cc
@@ -25,243 +25,239 @@
 namespace {
 
 const char* to_str(Severity severity) {
-  switch (severity) {
-    case Severity::Note:
-      return "note";
-    case Severity::Warning:
-      return "warning";
-    case Severity::Error:
-      return "error";
-    case Severity::InternalCompilerError:
-      return "internal compiler error";
-    case Severity::Fatal:
-      return "fatal";
-  }
-  return "";
+    switch (severity) {
+        case Severity::Note:
+            return "note";
+        case Severity::Warning:
+            return "warning";
+        case Severity::Error:
+            return "error";
+        case Severity::InternalCompilerError:
+            return "internal compiler error";
+        case Severity::Fatal:
+            return "fatal";
+    }
+    return "";
 }
 
 std::string to_str(const Source::Location& location) {
-  std::stringstream ss;
-  if (location.line > 0) {
-    ss << location.line;
-    if (location.column > 0) {
-      ss << ":" << location.column;
+    std::stringstream ss;
+    if (location.line > 0) {
+        ss << location.line;
+        if (location.column > 0) {
+            ss << ":" << location.column;
+        }
     }
-  }
-  return ss.str();
+    return ss.str();
 }
 
 }  // namespace
 
 /// State holds the internal formatter state for a format() call.
 struct Formatter::State {
-  /// Constructs a State associated with the given printer.
-  /// @param p the printer to write formatted messages to.
-  explicit State(Printer* p) : printer(p) {}
-  ~State() { flush(); }
+    /// Constructs a State associated with the given printer.
+    /// @param p the printer to write formatted messages to.
+    explicit State(Printer* p) : printer(p) {}
+    ~State() { flush(); }
 
-  /// set_style() sets the current style to new_style, flushing any pending
-  /// messages to the printer if the style changed.
-  /// @param new_style the new style to apply for future written messages.
-  void set_style(const diag::Style& new_style) {
-    if (style.color != new_style.color || style.bold != new_style.bold) {
-      flush();
-      style = new_style;
+    /// set_style() sets the current style to new_style, flushing any pending
+    /// messages to the printer if the style changed.
+    /// @param new_style the new style to apply for future written messages.
+    void set_style(const diag::Style& new_style) {
+        if (style.color != new_style.color || style.bold != new_style.bold) {
+            flush();
+            style = new_style;
+        }
     }
-  }
 
-  /// flush writes any pending messages to the printer, clearing the buffer.
-  void flush() {
-    auto str = stream.str();
-    if (str.length() > 0) {
-      printer->write(str, style);
-      std::stringstream reset;
-      stream.swap(reset);
+    /// flush writes any pending messages to the printer, clearing the buffer.
+    void flush() {
+        auto str = stream.str();
+        if (str.length() > 0) {
+            printer->write(str, style);
+            std::stringstream reset;
+            stream.swap(reset);
+        }
     }
-  }
 
-  /// operator<< queues msg to be written to the printer.
-  /// @param msg the value or string to write to the printer
-  /// @returns this State so that calls can be chained
-  template <typename T>
-  State& operator<<(const T& msg) {
-    stream << msg;
-    return *this;
-  }
+    /// operator<< queues msg to be written to the printer.
+    /// @param msg the value or string to write to the printer
+    /// @returns this State so that calls can be chained
+    template <typename T>
+    State& operator<<(const T& msg) {
+        stream << msg;
+        return *this;
+    }
 
-  /// newline queues a newline to be written to the printer.
-  void newline() { stream << std::endl; }
+    /// newline queues a newline to be written to the printer.
+    void newline() { stream << std::endl; }
 
-  /// repeat queues the character c to be written to the printer n times.
-  /// @param c the character to print `n` times
-  /// @param n the number of times to print character `c`
-  void repeat(char c, size_t n) {
-    std::fill_n(std::ostream_iterator<char>(stream), n, c);
-  }
+    /// repeat queues the character c to be written to the printer n times.
+    /// @param c the character to print `n` times
+    /// @param n the number of times to print character `c`
+    void repeat(char c, size_t n) { std::fill_n(std::ostream_iterator<char>(stream), n, c); }
 
- private:
-  Printer* printer;
-  diag::Style style;
-  std::stringstream stream;
+  private:
+    Printer* printer;
+    diag::Style style;
+    std::stringstream stream;
 };
 
 Formatter::Formatter() {}
 Formatter::Formatter(const Style& style) : style_(style) {}
 
 void Formatter::format(const List& list, Printer* printer) const {
-  State state{printer};
+    State state{printer};
 
-  bool first = true;
-  for (auto diag : list) {
-    state.set_style({});
-    if (!first) {
-      state.newline();
+    bool first = true;
+    for (auto diag : list) {
+        state.set_style({});
+        if (!first) {
+            state.newline();
+        }
+        format(diag, state);
+        first = false;
     }
-    format(diag, state);
-    first = false;
-  }
 
-  if (style_.print_newline_at_end) {
-    state.newline();
-  }
+    if (style_.print_newline_at_end) {
+        state.newline();
+    }
 }
 
 void Formatter::format(const Diagnostic& diag, State& state) const {
-  auto const& src = diag.source;
-  auto const& rng = src.range;
-  bool has_code = diag.code != nullptr && diag.code[0] != '\0';
+    auto const& src = diag.source;
+    auto const& rng = src.range;
+    bool has_code = diag.code != nullptr && diag.code[0] != '\0';
 
-  state.set_style({Color::kDefault, true});
+    state.set_style({Color::kDefault, true});
 
-  struct TextAndColor {
-    std::string text;
-    Color color;
-    bool bold = false;
-  };
-  std::vector<TextAndColor> prefix;
-  prefix.reserve(6);
+    struct TextAndColor {
+        std::string text;
+        Color color;
+        bool bold = false;
+    };
+    std::vector<TextAndColor> prefix;
+    prefix.reserve(6);
 
-  if (style_.print_file && src.file != nullptr) {
-    if (rng.begin.line > 0) {
-      prefix.emplace_back(TextAndColor{src.file->path + ":" + to_str(rng.begin),
-                                       Color::kDefault});
-    } else {
-      prefix.emplace_back(TextAndColor{src.file->path, Color::kDefault});
-    }
-  } else if (rng.begin.line > 0) {
-    prefix.emplace_back(TextAndColor{to_str(rng.begin), Color::kDefault});
-  }
-
-  Color severity_color = Color::kDefault;
-  switch (diag.severity) {
-    case Severity::Note:
-      break;
-    case Severity::Warning:
-      severity_color = Color::kYellow;
-      break;
-    case Severity::Error:
-      severity_color = Color::kRed;
-      break;
-    case Severity::Fatal:
-    case Severity::InternalCompilerError:
-      severity_color = Color::kMagenta;
-      break;
-  }
-  if (style_.print_severity) {
-    prefix.emplace_back(
-        TextAndColor{to_str(diag.severity), severity_color, true});
-  }
-  if (has_code) {
-    prefix.emplace_back(TextAndColor{diag.code, severity_color});
-  }
-
-  for (size_t i = 0; i < prefix.size(); i++) {
-    if (i > 0) {
-      state << " ";
-    }
-    state.set_style({prefix[i].color, prefix[i].bold});
-    state << prefix[i].text;
-  }
-
-  state.set_style({Color::kDefault, true});
-  if (!prefix.empty()) {
-    state << ": ";
-  }
-  state << diag.message;
-
-  if (style_.print_line && src.file && rng.begin.line > 0) {
-    state.newline();
-    state.set_style({Color::kDefault, false});
-
-    for (size_t line_num = rng.begin.line;
-         (line_num <= rng.end.line) &&
-         (line_num <= src.file->content.lines.size());
-         line_num++) {
-      auto& line = src.file->content.lines[line_num - 1];
-      auto line_len = line.size();
-
-      bool is_ascii = true;
-      for (auto c : line) {
-        if (c == '\t') {
-          state.repeat(' ', style_.tab_width);
+    if (style_.print_file && src.file != nullptr) {
+        if (rng.begin.line > 0) {
+            prefix.emplace_back(
+                TextAndColor{src.file->path + ":" + to_str(rng.begin), Color::kDefault});
         } else {
-          state << c;
+            prefix.emplace_back(TextAndColor{src.file->path, Color::kDefault});
         }
-        if (c & 0x80) {
-          is_ascii = false;
-        }
-      }
-
-      state.newline();
-
-      // If the line contains non-ascii characters, then we cannot assume that
-      // a single utf8 code unit represents a single glyph, so don't attempt to
-      // draw squiggles.
-      if (!is_ascii) {
-        continue;
-      }
-
-      state.set_style({Color::kCyan, false});
-
-      // Count the number of glyphs in the line span.
-      // start and end use 1-based indexing.
-      auto num_glyphs = [&](size_t start, size_t end) {
-        size_t count = 0;
-        start = (start > 0) ? (start - 1) : 0;
-        end = (end > 0) ? (end - 1) : 0;
-        for (size_t i = start; (i < end) && (i < line_len); i++) {
-          count += (line[i] == '\t') ? style_.tab_width : 1;
-        }
-        return count;
-      };
-
-      if (line_num == rng.begin.line && line_num == rng.end.line) {
-        // Single line
-        state.repeat(' ', num_glyphs(1, rng.begin.column));
-        state.repeat('^', std::max<size_t>(
-                              num_glyphs(rng.begin.column, rng.end.column), 1));
-      } else if (line_num == rng.begin.line) {
-        // Start of multi-line
-        state.repeat(' ', num_glyphs(1, rng.begin.column));
-        state.repeat('^', num_glyphs(rng.begin.column, line_len + 1));
-      } else if (line_num == rng.end.line) {
-        // End of multi-line
-        state.repeat('^', num_glyphs(1, rng.end.column));
-      } else {
-        // Middle of multi-line
-        state.repeat('^', num_glyphs(1, line_len + 1));
-      }
-      state.newline();
+    } else if (rng.begin.line > 0) {
+        prefix.emplace_back(TextAndColor{to_str(rng.begin), Color::kDefault});
     }
 
-    state.set_style({});
-  }
+    Color severity_color = Color::kDefault;
+    switch (diag.severity) {
+        case Severity::Note:
+            break;
+        case Severity::Warning:
+            severity_color = Color::kYellow;
+            break;
+        case Severity::Error:
+            severity_color = Color::kRed;
+            break;
+        case Severity::Fatal:
+        case Severity::InternalCompilerError:
+            severity_color = Color::kMagenta;
+            break;
+    }
+    if (style_.print_severity) {
+        prefix.emplace_back(TextAndColor{to_str(diag.severity), severity_color, true});
+    }
+    if (has_code) {
+        prefix.emplace_back(TextAndColor{diag.code, severity_color});
+    }
+
+    for (size_t i = 0; i < prefix.size(); i++) {
+        if (i > 0) {
+            state << " ";
+        }
+        state.set_style({prefix[i].color, prefix[i].bold});
+        state << prefix[i].text;
+    }
+
+    state.set_style({Color::kDefault, true});
+    if (!prefix.empty()) {
+        state << ": ";
+    }
+    state << diag.message;
+
+    if (style_.print_line && src.file && rng.begin.line > 0) {
+        state.newline();
+        state.set_style({Color::kDefault, false});
+
+        for (size_t line_num = rng.begin.line;
+             (line_num <= rng.end.line) && (line_num <= src.file->content.lines.size());
+             line_num++) {
+            auto& line = src.file->content.lines[line_num - 1];
+            auto line_len = line.size();
+
+            bool is_ascii = true;
+            for (auto c : line) {
+                if (c == '\t') {
+                    state.repeat(' ', style_.tab_width);
+                } else {
+                    state << c;
+                }
+                if (c & 0x80) {
+                    is_ascii = false;
+                }
+            }
+
+            state.newline();
+
+            // If the line contains non-ascii characters, then we cannot assume that
+            // a single utf8 code unit represents a single glyph, so don't attempt to
+            // draw squiggles.
+            if (!is_ascii) {
+                continue;
+            }
+
+            state.set_style({Color::kCyan, false});
+
+            // Count the number of glyphs in the line span.
+            // start and end use 1-based indexing.
+            auto num_glyphs = [&](size_t start, size_t end) {
+                size_t count = 0;
+                start = (start > 0) ? (start - 1) : 0;
+                end = (end > 0) ? (end - 1) : 0;
+                for (size_t i = start; (i < end) && (i < line_len); i++) {
+                    count += (line[i] == '\t') ? style_.tab_width : 1;
+                }
+                return count;
+            };
+
+            if (line_num == rng.begin.line && line_num == rng.end.line) {
+                // Single line
+                state.repeat(' ', num_glyphs(1, rng.begin.column));
+                state.repeat('^',
+                             std::max<size_t>(num_glyphs(rng.begin.column, rng.end.column), 1));
+            } else if (line_num == rng.begin.line) {
+                // Start of multi-line
+                state.repeat(' ', num_glyphs(1, rng.begin.column));
+                state.repeat('^', num_glyphs(rng.begin.column, line_len + 1));
+            } else if (line_num == rng.end.line) {
+                // End of multi-line
+                state.repeat('^', num_glyphs(1, rng.end.column));
+            } else {
+                // Middle of multi-line
+                state.repeat('^', num_glyphs(1, line_len + 1));
+            }
+            state.newline();
+        }
+
+        state.set_style({});
+    }
 }
 
 std::string Formatter::format(const List& list) const {
-  StringPrinter printer;
-  format(list, &printer);
-  return printer.str();
+    StringPrinter printer;
+    format(list, &printer);
+    return printer.str();
 }
 
 Formatter::~Formatter() = default;
diff --git a/src/tint/diagnostic/formatter.h b/src/tint/diagnostic/formatter.h
index 179bb2d..5810f0b 100644
--- a/src/tint/diagnostic/formatter.h
+++ b/src/tint/diagnostic/formatter.h
@@ -25,44 +25,44 @@
 
 /// Formatter are used to print a list of diagnostics messages.
 class Formatter {
- public:
-  /// Style controls the formatter's output style.
-  struct Style {
-    /// include the file path for each diagnostic
-    bool print_file = true;
-    /// include the severity for each diagnostic
-    bool print_severity = true;
-    /// include the source line(s) for the diagnostic
-    bool print_line = true;
-    /// print a newline at the end of a diagnostic list
-    bool print_newline_at_end = true;
-    /// width of a tab character
-    size_t tab_width = 2u;
-  };
+  public:
+    /// Style controls the formatter's output style.
+    struct Style {
+        /// include the file path for each diagnostic
+        bool print_file = true;
+        /// include the severity for each diagnostic
+        bool print_severity = true;
+        /// include the source line(s) for the diagnostic
+        bool print_line = true;
+        /// print a newline at the end of a diagnostic list
+        bool print_newline_at_end = true;
+        /// width of a tab character
+        size_t tab_width = 2u;
+    };
 
-  /// Constructor for the formatter using a default style.
-  Formatter();
+    /// Constructor for the formatter using a default style.
+    Formatter();
 
-  /// Constructor for the formatter using the custom style.
-  /// @param style the style used for the formatter.
-  explicit Formatter(const Style& style);
+    /// Constructor for the formatter using the custom style.
+    /// @param style the style used for the formatter.
+    explicit Formatter(const Style& style);
 
-  ~Formatter();
+    ~Formatter();
 
-  /// @param list the list of diagnostic messages to format
-  /// @param printer the printer used to display the formatted diagnostics
-  void format(const List& list, Printer* printer) const;
+    /// @param list the list of diagnostic messages to format
+    /// @param printer the printer used to display the formatted diagnostics
+    void format(const List& list, Printer* printer) const;
 
-  /// @return the list of diagnostics `list` formatted to a string.
-  /// @param list the list of diagnostic messages to format
-  std::string format(const List& list) const;
+    /// @return the list of diagnostics `list` formatted to a string.
+    /// @param list the list of diagnostic messages to format
+    std::string format(const List& list) const;
 
- private:
-  struct State;
+  private:
+    struct State;
 
-  void format(const Diagnostic& diag, State& state) const;
+    void format(const Diagnostic& diag, State& state) const;
 
-  const Style style_;
+    const Style style_;
 };
 
 }  // namespace tint::diag
diff --git a/src/tint/diagnostic/formatter_test.cc b/src/tint/diagnostic/formatter_test.cc
index fc342fb..df11d74 100644
--- a/src/tint/diagnostic/formatter_test.cc
+++ b/src/tint/diagnostic/formatter_test.cc
@@ -27,13 +27,13 @@
                 std::string message,
                 System system,
                 const char* code = nullptr) {
-  Diagnostic d;
-  d.severity = severity;
-  d.source = source;
-  d.message = std::move(message);
-  d.system = system;
-  d.code = code;
-  return d;
+    Diagnostic d;
+    d.severity = severity;
+    d.source = source;
+    d.message = std::move(message);
+    d.system = system;
+    d.code = code;
+    return d;
 }
 
 constexpr const char* ascii_content =  // Note: words are tab-delimited
@@ -43,120 +43,110 @@
 the	snail	says	???
 )";
 
-constexpr const char* utf8_content =  // Note: words are tab-delimited
+constexpr const char* utf8_content =                      // Note: words are tab-delimited
     "the	\xf0\x9f\x90\xb1	says	meow\n"   // NOLINT: tabs
     "the	\xf0\x9f\x90\x95	says	woof\n"   // NOLINT: tabs
     "the	\xf0\x9f\x90\x8d	says	quack\n"  // NOLINT: tabs
     "the	\xf0\x9f\x90\x8c	says	???\n";   // NOLINT: tabs
 
 class DiagFormatterTest : public testing::Test {
- public:
-  Source::File ascii_file{"file.name", ascii_content};
-  Source::File utf8_file{"file.name", utf8_content};
-  Diagnostic ascii_diag_note =
-      Diag(Severity::Note,
-           Source{Source::Range{Source::Location{1, 14}}, &ascii_file},
-           "purr",
-           System::Test);
-  Diagnostic ascii_diag_warn =
-      Diag(Severity::Warning,
-           Source{Source::Range{{2, 14}, {2, 18}}, &ascii_file},
-           "grrr",
-           System::Test);
-  Diagnostic ascii_diag_err =
-      Diag(Severity::Error,
-           Source{Source::Range{{3, 16}, {3, 21}}, &ascii_file},
-           "hiss",
-           System::Test,
-           "abc123");
-  Diagnostic ascii_diag_ice =
-      Diag(Severity::InternalCompilerError,
-           Source{Source::Range{{4, 16}, {4, 19}}, &ascii_file},
-           "unreachable",
-           System::Test);
-  Diagnostic ascii_diag_fatal =
-      Diag(Severity::Fatal,
-           Source{Source::Range{{4, 16}, {4, 19}}, &ascii_file},
-           "nothing",
-           System::Test);
+  public:
+    Source::File ascii_file{"file.name", ascii_content};
+    Source::File utf8_file{"file.name", utf8_content};
+    Diagnostic ascii_diag_note = Diag(Severity::Note,
+                                      Source{Source::Range{Source::Location{1, 14}}, &ascii_file},
+                                      "purr",
+                                      System::Test);
+    Diagnostic ascii_diag_warn = Diag(Severity::Warning,
+                                      Source{Source::Range{{2, 14}, {2, 18}}, &ascii_file},
+                                      "grrr",
+                                      System::Test);
+    Diagnostic ascii_diag_err = Diag(Severity::Error,
+                                     Source{Source::Range{{3, 16}, {3, 21}}, &ascii_file},
+                                     "hiss",
+                                     System::Test,
+                                     "abc123");
+    Diagnostic ascii_diag_ice = Diag(Severity::InternalCompilerError,
+                                     Source{Source::Range{{4, 16}, {4, 19}}, &ascii_file},
+                                     "unreachable",
+                                     System::Test);
+    Diagnostic ascii_diag_fatal = Diag(Severity::Fatal,
+                                       Source{Source::Range{{4, 16}, {4, 19}}, &ascii_file},
+                                       "nothing",
+                                       System::Test);
 
-  Diagnostic utf8_diag_note =
-      Diag(Severity::Note,
-           Source{Source::Range{Source::Location{1, 15}}, &utf8_file},
-           "purr",
-           System::Test);
-  Diagnostic utf8_diag_warn =
-      Diag(Severity::Warning,
-           Source{Source::Range{{2, 15}, {2, 19}}, &utf8_file},
-           "grrr",
-           System::Test);
-  Diagnostic utf8_diag_err =
-      Diag(Severity::Error,
-           Source{Source::Range{{3, 15}, {3, 20}}, &utf8_file},
-           "hiss",
-           System::Test,
-           "abc123");
-  Diagnostic utf8_diag_ice =
-      Diag(Severity::InternalCompilerError,
-           Source{Source::Range{{4, 15}, {4, 18}}, &utf8_file},
-           "unreachable",
-           System::Test);
-  Diagnostic utf8_diag_fatal =
-      Diag(Severity::Fatal,
-           Source{Source::Range{{4, 15}, {4, 18}}, &utf8_file},
-           "nothing",
-           System::Test);
+    Diagnostic utf8_diag_note = Diag(Severity::Note,
+                                     Source{Source::Range{Source::Location{1, 15}}, &utf8_file},
+                                     "purr",
+                                     System::Test);
+    Diagnostic utf8_diag_warn = Diag(Severity::Warning,
+                                     Source{Source::Range{{2, 15}, {2, 19}}, &utf8_file},
+                                     "grrr",
+                                     System::Test);
+    Diagnostic utf8_diag_err = Diag(Severity::Error,
+                                    Source{Source::Range{{3, 15}, {3, 20}}, &utf8_file},
+                                    "hiss",
+                                    System::Test,
+                                    "abc123");
+    Diagnostic utf8_diag_ice = Diag(Severity::InternalCompilerError,
+                                    Source{Source::Range{{4, 15}, {4, 18}}, &utf8_file},
+                                    "unreachable",
+                                    System::Test);
+    Diagnostic utf8_diag_fatal = Diag(Severity::Fatal,
+                                      Source{Source::Range{{4, 15}, {4, 18}}, &utf8_file},
+                                      "nothing",
+                                      System::Test);
 };
 
 TEST_F(DiagFormatterTest, Simple) {
-  Formatter fmt{{false, false, false, false}};
-  auto got = fmt.format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err});
-  auto* expect = R"(1:14: purr
+    Formatter fmt{{false, false, false, false}};
+    auto got = fmt.format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err});
+    auto* expect = R"(1:14: purr
 2:14: grrr
 3:16 abc123: hiss)";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(DiagFormatterTest, SimpleNewlineAtEnd) {
-  Formatter fmt{{false, false, false, true}};
-  auto got = fmt.format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err});
-  auto* expect = R"(1:14: purr
+    Formatter fmt{{false, false, false, true}};
+    auto got = fmt.format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err});
+    auto* expect = R"(1:14: purr
 2:14: grrr
 3:16 abc123: hiss
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(DiagFormatterTest, SimpleNoSource) {
-  Formatter fmt{{false, false, false, false}};
-  auto diag = Diag(Severity::Note, Source{}, "no source!", System::Test);
-  auto got = fmt.format(List{diag});
-  auto* expect = "no source!";
-  ASSERT_EQ(expect, got);
+    Formatter fmt{{false, false, false, false}};
+    auto diag = Diag(Severity::Note, Source{}, "no source!", System::Test);
+    auto got = fmt.format(List{diag});
+    auto* expect = "no source!";
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(DiagFormatterTest, WithFile) {
-  Formatter fmt{{true, false, false, false}};
-  auto got = fmt.format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err});
-  auto* expect = R"(file.name:1:14: purr
+    Formatter fmt{{true, false, false, false}};
+    auto got = fmt.format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err});
+    auto* expect = R"(file.name:1:14: purr
 file.name:2:14: grrr
 file.name:3:16 abc123: hiss)";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(DiagFormatterTest, WithSeverity) {
-  Formatter fmt{{false, true, false, false}};
-  auto got = fmt.format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err});
-  auto* expect = R"(1:14 note: purr
+    Formatter fmt{{false, true, false, false}};
+    auto got = fmt.format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err});
+    auto* expect = R"(1:14 note: purr
 2:14 warning: grrr
 3:16 error abc123: hiss)";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(DiagFormatterTest, WithLine) {
-  Formatter fmt{{false, false, true, false}};
-  auto got = fmt.format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err});
-  auto* expect = R"(1:14: purr
+    Formatter fmt{{false, false, true, false}};
+    auto got = fmt.format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err});
+    auto* expect = R"(1:14: purr
 the  cat  says  meow
                 ^
 
@@ -168,28 +158,28 @@
 the  snake  says  quack
                   ^^^^^
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(DiagFormatterTest, UnicodeWithLine) {
-  Formatter fmt{{false, false, true, false}};
-  auto got = fmt.format(List{utf8_diag_note, utf8_diag_warn, utf8_diag_err});
-  auto* expect =
-      "1:15: purr\n"
-      "the  \xf0\x9f\x90\xb1  says  meow\n"
-      "\n"
-      "2:15: grrr\n"
-      "the  \xf0\x9f\x90\x95  says  woof\n"
-      "\n"
-      "3:15 abc123: hiss\n"
-      "the  \xf0\x9f\x90\x8d  says  quack\n";
-  ASSERT_EQ(expect, got);
+    Formatter fmt{{false, false, true, false}};
+    auto got = fmt.format(List{utf8_diag_note, utf8_diag_warn, utf8_diag_err});
+    auto* expect =
+        "1:15: purr\n"
+        "the  \xf0\x9f\x90\xb1  says  meow\n"
+        "\n"
+        "2:15: grrr\n"
+        "the  \xf0\x9f\x90\x95  says  woof\n"
+        "\n"
+        "3:15 abc123: hiss\n"
+        "the  \xf0\x9f\x90\x8d  says  quack\n";
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(DiagFormatterTest, BasicWithFileSeverityLine) {
-  Formatter fmt{{true, true, true, false}};
-  auto got = fmt.format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err});
-  auto* expect = R"(file.name:1:14 note: purr
+    Formatter fmt{{true, true, true, false}};
+    auto got = fmt.format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err});
+    auto* expect = R"(file.name:1:14 note: purr
 the  cat  says  meow
                 ^
 
@@ -201,16 +191,15 @@
 the  snake  says  quack
                   ^^^^^
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(DiagFormatterTest, BasicWithMultiLine) {
-  auto multiline = Diag(Severity::Warning,
-                        Source{Source::Range{{2, 9}, {4, 15}}, &ascii_file},
-                        "multiline", System::Test);
-  Formatter fmt{{false, false, true, false}};
-  auto got = fmt.format(List{multiline});
-  auto* expect = R"(2:9: multiline
+    auto multiline = Diag(Severity::Warning, Source{Source::Range{{2, 9}, {4, 15}}, &ascii_file},
+                          "multiline", System::Test);
+    Formatter fmt{{false, false, true, false}};
+    auto got = fmt.format(List{multiline});
+    auto* expect = R"(2:9: multiline
 the  dog  says  woof
           ^^^^^^^^^^
 the  snake  says  quack
@@ -218,27 +207,26 @@
 the  snail  says  ???
 ^^^^^^^^^^^^^^^^
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(DiagFormatterTest, UnicodeWithMultiLine) {
-  auto multiline = Diag(Severity::Warning,
-                        Source{Source::Range{{2, 9}, {4, 15}}, &utf8_file},
-                        "multiline", System::Test);
-  Formatter fmt{{false, false, true, false}};
-  auto got = fmt.format(List{multiline});
-  auto* expect =
-      "2:9: multiline\n"
-      "the  \xf0\x9f\x90\x95  says  woof\n"
-      "the  \xf0\x9f\x90\x8d  says  quack\n"
-      "the  \xf0\x9f\x90\x8c  says  ???\n";
-  ASSERT_EQ(expect, got);
+    auto multiline = Diag(Severity::Warning, Source{Source::Range{{2, 9}, {4, 15}}, &utf8_file},
+                          "multiline", System::Test);
+    Formatter fmt{{false, false, true, false}};
+    auto got = fmt.format(List{multiline});
+    auto* expect =
+        "2:9: multiline\n"
+        "the  \xf0\x9f\x90\x95  says  woof\n"
+        "the  \xf0\x9f\x90\x8d  says  quack\n"
+        "the  \xf0\x9f\x90\x8c  says  ???\n";
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(DiagFormatterTest, BasicWithFileSeverityLineTab4) {
-  Formatter fmt{{true, true, true, false, 4u}};
-  auto got = fmt.format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err});
-  auto* expect = R"(file.name:1:14 note: purr
+    Formatter fmt{{true, true, true, false, 4u}};
+    auto got = fmt.format(List{ascii_diag_note, ascii_diag_warn, ascii_diag_err});
+    auto* expect = R"(file.name:1:14 note: purr
 the    cat    says    meow
                       ^
 
@@ -250,16 +238,15 @@
 the    snake    says    quack
                         ^^^^^
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(DiagFormatterTest, BasicWithMultiLineTab4) {
-  auto multiline = Diag(Severity::Warning,
-                        Source{Source::Range{{2, 9}, {4, 15}}, &ascii_file},
-                        "multiline", System::Test);
-  Formatter fmt{{false, false, true, false, 4u}};
-  auto got = fmt.format(List{multiline});
-  auto* expect = R"(2:9: multiline
+    auto multiline = Diag(Severity::Warning, Source{Source::Range{{2, 9}, {4, 15}}, &ascii_file},
+                          "multiline", System::Test);
+    Formatter fmt{{false, false, true, false, 4u}};
+    auto got = fmt.format(List{multiline});
+    auto* expect = R"(2:9: multiline
 the    dog    says    woof
               ^^^^^^^^^^^^
 the    snake    says    quack
@@ -267,41 +254,40 @@
 the    snail    says    ???
 ^^^^^^^^^^^^^^^^^^^^
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(DiagFormatterTest, ICE) {
-  Formatter fmt{{}};
-  auto got = fmt.format(List{ascii_diag_ice});
-  auto* expect = R"(file.name:4:16 internal compiler error: unreachable
+    Formatter fmt{{}};
+    auto got = fmt.format(List{ascii_diag_ice});
+    auto* expect = R"(file.name:4:16 internal compiler error: unreachable
 the  snail  says  ???
                   ^^^
 
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(DiagFormatterTest, Fatal) {
-  Formatter fmt{{}};
-  auto got = fmt.format(List{ascii_diag_fatal});
-  auto* expect = R"(file.name:4:16 fatal: nothing
+    Formatter fmt{{}};
+    auto got = fmt.format(List{ascii_diag_fatal});
+    auto* expect = R"(file.name:4:16 fatal: nothing
 the  snail  says  ???
                   ^^^
 
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(DiagFormatterTest, RangeOOB) {
-  Formatter fmt{{true, true, true, true}};
-  diag::List list;
-  list.add_error(System::Test, "oob",
-                 Source{{{10, 20}, {30, 20}}, &ascii_file});
-  auto got = fmt.format(list);
-  auto* expect = R"(file.name:10:20 error: oob
+    Formatter fmt{{true, true, true, true}};
+    diag::List list;
+    list.add_error(System::Test, "oob", Source{{{10, 20}, {30, 20}}, &ascii_file});
+    auto got = fmt.format(list);
+    auto* expect = R"(file.name:10:20 error: oob
 
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 }  // namespace
diff --git a/src/tint/diagnostic/printer.cc b/src/tint/diagnostic/printer.cc
index a3e93bc..a95d9f0 100644
--- a/src/tint/diagnostic/printer.cc
+++ b/src/tint/diagnostic/printer.cc
@@ -22,11 +22,11 @@
 StringPrinter::~StringPrinter() = default;
 
 std::string StringPrinter::str() const {
-  return stream.str();
+    return stream.str();
 }
 
 void StringPrinter::write(const std::string& str, const Style&) {
-  stream << str;
+    stream << str;
 }
 
 }  // namespace tint::diag
diff --git a/src/tint/diagnostic/printer.h b/src/tint/diagnostic/printer.h
index cb38ac8..b2ac105 100644
--- a/src/tint/diagnostic/printer.h
+++ b/src/tint/diagnostic/printer.h
@@ -25,55 +25,55 @@
 
 /// Color is an enumerator of colors used by Style.
 enum class Color {
-  kDefault,
-  kBlack,
-  kRed,
-  kGreen,
-  kYellow,
-  kBlue,
-  kMagenta,
-  kCyan,
-  kWhite,
+    kDefault,
+    kBlack,
+    kRed,
+    kGreen,
+    kYellow,
+    kBlue,
+    kMagenta,
+    kCyan,
+    kWhite,
 };
 
 /// Style describes how a diagnostic message should be printed.
 struct Style {
-  /// The foreground text color
-  Color color = Color::kDefault;
-  /// If true the text will be displayed with a strong weight
-  bool bold = false;
+    /// The foreground text color
+    Color color = Color::kDefault;
+    /// If true the text will be displayed with a strong weight
+    bool bold = false;
 };
 
 /// Printers are used to print formatted diagnostic messages to a terminal.
 class Printer {
- public:
-  /// @returns a diagnostic Printer
-  /// @param out the file to print to.
-  /// @param use_colors if true, the printer will use colors if `out` is a
-  /// terminal and supports them.
-  static std::unique_ptr<Printer> create(FILE* out, bool use_colors);
+  public:
+    /// @returns a diagnostic Printer
+    /// @param out the file to print to.
+    /// @param use_colors if true, the printer will use colors if `out` is a
+    /// terminal and supports them.
+    static std::unique_ptr<Printer> create(FILE* out, bool use_colors);
 
-  virtual ~Printer();
+    virtual ~Printer();
 
-  /// writes the string str to the printer with the given style.
-  /// @param str the string to write to the printer
-  /// @param style the style used to print `str`
-  virtual void write(const std::string& str, const Style& style) = 0;
+    /// writes the string str to the printer with the given style.
+    /// @param str the string to write to the printer
+    /// @param style the style used to print `str`
+    virtual void write(const std::string& str, const Style& style) = 0;
 };
 
 /// StringPrinter is an implementation of Printer that writes to a std::string.
 class StringPrinter : public Printer {
- public:
-  StringPrinter();
-  ~StringPrinter() override;
+  public:
+    StringPrinter();
+    ~StringPrinter() override;
 
-  /// @returns the printed string.
-  std::string str() const;
+    /// @returns the printed string.
+    std::string str() const;
 
-  void write(const std::string& str, const Style&) override;
+    void write(const std::string& str, const Style&) override;
 
- private:
-  std::stringstream stream;
+  private:
+    std::stringstream stream;
 };
 
 }  // namespace tint::diag
diff --git a/src/tint/diagnostic/printer_linux.cc b/src/tint/diagnostic/printer_linux.cc
index 9d0e315..56d77b9 100644
--- a/src/tint/diagnostic/printer_linux.cc
+++ b/src/tint/diagnostic/printer_linux.cc
@@ -22,77 +22,76 @@
 namespace {
 
 bool supports_colors(FILE* f) {
-  if (!isatty(fileno(f))) {
-    return false;
-  }
+    if (!isatty(fileno(f))) {
+        return false;
+    }
 
-  const char* cterm = getenv("TERM");
-  if (cterm == nullptr) {
-    return false;
-  }
+    const char* cterm = getenv("TERM");
+    if (cterm == nullptr) {
+        return false;
+    }
 
-  std::string term = getenv("TERM");
-  if (term != "cygwin" && term != "linux" && term != "rxvt-unicode-256color" &&
-      term != "rxvt-unicode" && term != "screen-256color" && term != "screen" &&
-      term != "tmux-256color" && term != "tmux" && term != "xterm-256color" &&
-      term != "xterm-color" && term != "xterm") {
-    return false;
-  }
+    std::string term = getenv("TERM");
+    if (term != "cygwin" && term != "linux" && term != "rxvt-unicode-256color" &&
+        term != "rxvt-unicode" && term != "screen-256color" && term != "screen" &&
+        term != "tmux-256color" && term != "tmux" && term != "xterm-256color" &&
+        term != "xterm-color" && term != "xterm") {
+        return false;
+    }
 
-  return true;
+    return true;
 }
 
 class PrinterLinux : public Printer {
- public:
-  PrinterLinux(FILE* f, bool colors)
-      : file(f), use_colors(colors && supports_colors(f)) {}
+  public:
+    PrinterLinux(FILE* f, bool colors) : file(f), use_colors(colors && supports_colors(f)) {}
 
-  void write(const std::string& str, const Style& style) override {
-    write_color(style.color, style.bold);
-    fwrite(str.data(), 1, str.size(), file);
-    write_color(Color::kDefault, false);
-  }
-
- private:
-  constexpr const char* color_code(Color color, bool bold) {
-    switch (color) {
-      case Color::kDefault:
-        return bold ? "\u001b[1m" : "\u001b[0m";
-      case Color::kBlack:
-        return bold ? "\u001b[30;1m" : "\u001b[30m";
-      case Color::kRed:
-        return bold ? "\u001b[31;1m" : "\u001b[31m";
-      case Color::kGreen:
-        return bold ? "\u001b[32;1m" : "\u001b[32m";
-      case Color::kYellow:
-        return bold ? "\u001b[33;1m" : "\u001b[33m";
-      case Color::kBlue:
-        return bold ? "\u001b[34;1m" : "\u001b[34m";
-      case Color::kMagenta:
-        return bold ? "\u001b[35;1m" : "\u001b[35m";
-      case Color::kCyan:
-        return bold ? "\u001b[36;1m" : "\u001b[36m";
-      case Color::kWhite:
-        return bold ? "\u001b[37;1m" : "\u001b[37m";
+    void write(const std::string& str, const Style& style) override {
+        write_color(style.color, style.bold);
+        fwrite(str.data(), 1, str.size(), file);
+        write_color(Color::kDefault, false);
     }
-    return "";  // unreachable
-  }
 
-  void write_color(Color color, bool bold) {
-    if (use_colors) {
-      auto* code = color_code(color, bold);
-      fwrite(code, 1, strlen(code), file);
+  private:
+    constexpr const char* color_code(Color color, bool bold) {
+        switch (color) {
+            case Color::kDefault:
+                return bold ? "\u001b[1m" : "\u001b[0m";
+            case Color::kBlack:
+                return bold ? "\u001b[30;1m" : "\u001b[30m";
+            case Color::kRed:
+                return bold ? "\u001b[31;1m" : "\u001b[31m";
+            case Color::kGreen:
+                return bold ? "\u001b[32;1m" : "\u001b[32m";
+            case Color::kYellow:
+                return bold ? "\u001b[33;1m" : "\u001b[33m";
+            case Color::kBlue:
+                return bold ? "\u001b[34;1m" : "\u001b[34m";
+            case Color::kMagenta:
+                return bold ? "\u001b[35;1m" : "\u001b[35m";
+            case Color::kCyan:
+                return bold ? "\u001b[36;1m" : "\u001b[36m";
+            case Color::kWhite:
+                return bold ? "\u001b[37;1m" : "\u001b[37m";
+        }
+        return "";  // unreachable
     }
-  }
 
-  FILE* const file;
-  const bool use_colors;
+    void write_color(Color color, bool bold) {
+        if (use_colors) {
+            auto* code = color_code(color, bold);
+            fwrite(code, 1, strlen(code), file);
+        }
+    }
+
+    FILE* const file;
+    const bool use_colors;
 };
 
 }  // namespace
 
 std::unique_ptr<Printer> Printer::create(FILE* out, bool use_colors) {
-  return std::make_unique<PrinterLinux>(out, use_colors);
+    return std::make_unique<PrinterLinux>(out, use_colors);
 }
 
 }  // namespace tint::diag
diff --git a/src/tint/diagnostic/printer_other.cc b/src/tint/diagnostic/printer_other.cc
index 65ef0ac..9a814fd 100644
--- a/src/tint/diagnostic/printer_other.cc
+++ b/src/tint/diagnostic/printer_other.cc
@@ -20,21 +20,21 @@
 namespace {
 
 class PrinterOther : public Printer {
- public:
-  explicit PrinterOther(FILE* f) : file(f) {}
+  public:
+    explicit PrinterOther(FILE* f) : file(f) {}
 
-  void write(const std::string& str, const Style&) override {
-    fwrite(str.data(), 1, str.size(), file);
-  }
+    void write(const std::string& str, const Style&) override {
+        fwrite(str.data(), 1, str.size(), file);
+    }
 
- private:
-  FILE* file;
+  private:
+    FILE* file;
 };
 
 }  // namespace
 
 std::unique_ptr<Printer> Printer::create(FILE* out, bool) {
-  return std::make_unique<PrinterOther>(out);
+    return std::make_unique<PrinterOther>(out);
 }
 
 }  // namespace tint::diag
diff --git a/src/tint/diagnostic/printer_test.cc b/src/tint/diagnostic/printer_test.cc
index bfc9d43..8f117e9 100644
--- a/src/tint/diagnostic/printer_test.cc
+++ b/src/tint/diagnostic/printer_test.cc
@@ -36,59 +36,59 @@
 using PrinterTest = testing::Test;
 
 TEST_F(PrinterTest, WithColors) {
-  auto printer = Printer::create(stdout, true);
-  printer->write("Default", Style{Color::kDefault, false});
-  printer->write("Black", Style{Color::kBlack, false});
-  printer->write("Red", Style{Color::kRed, false});
-  printer->write("Green", Style{Color::kGreen, false});
-  printer->write("Yellow", Style{Color::kYellow, false});
-  printer->write("Blue", Style{Color::kBlue, false});
-  printer->write("Magenta", Style{Color::kMagenta, false});
-  printer->write("Cyan", Style{Color::kCyan, false});
-  printer->write("White", Style{Color::kWhite, false});
-  printf("\n");
+    auto printer = Printer::create(stdout, true);
+    printer->write("Default", Style{Color::kDefault, false});
+    printer->write("Black", Style{Color::kBlack, false});
+    printer->write("Red", Style{Color::kRed, false});
+    printer->write("Green", Style{Color::kGreen, false});
+    printer->write("Yellow", Style{Color::kYellow, false});
+    printer->write("Blue", Style{Color::kBlue, false});
+    printer->write("Magenta", Style{Color::kMagenta, false});
+    printer->write("Cyan", Style{Color::kCyan, false});
+    printer->write("White", Style{Color::kWhite, false});
+    printf("\n");
 }
 
 TEST_F(PrinterTest, BoldWithColors) {
-  auto printer = Printer::create(stdout, true);
-  printer->write("Default", Style{Color::kDefault, true});
-  printer->write("Black", Style{Color::kBlack, true});
-  printer->write("Red", Style{Color::kRed, true});
-  printer->write("Green", Style{Color::kGreen, true});
-  printer->write("Yellow", Style{Color::kYellow, true});
-  printer->write("Blue", Style{Color::kBlue, true});
-  printer->write("Magenta", Style{Color::kMagenta, true});
-  printer->write("Cyan", Style{Color::kCyan, true});
-  printer->write("White", Style{Color::kWhite, true});
-  printf("\n");
+    auto printer = Printer::create(stdout, true);
+    printer->write("Default", Style{Color::kDefault, true});
+    printer->write("Black", Style{Color::kBlack, true});
+    printer->write("Red", Style{Color::kRed, true});
+    printer->write("Green", Style{Color::kGreen, true});
+    printer->write("Yellow", Style{Color::kYellow, true});
+    printer->write("Blue", Style{Color::kBlue, true});
+    printer->write("Magenta", Style{Color::kMagenta, true});
+    printer->write("Cyan", Style{Color::kCyan, true});
+    printer->write("White", Style{Color::kWhite, true});
+    printf("\n");
 }
 
 TEST_F(PrinterTest, WithoutColors) {
-  auto printer = Printer::create(stdout, false);
-  printer->write("Default", Style{Color::kDefault, false});
-  printer->write("Black", Style{Color::kBlack, false});
-  printer->write("Red", Style{Color::kRed, false});
-  printer->write("Green", Style{Color::kGreen, false});
-  printer->write("Yellow", Style{Color::kYellow, false});
-  printer->write("Blue", Style{Color::kBlue, false});
-  printer->write("Magenta", Style{Color::kMagenta, false});
-  printer->write("Cyan", Style{Color::kCyan, false});
-  printer->write("White", Style{Color::kWhite, false});
-  printf("\n");
+    auto printer = Printer::create(stdout, false);
+    printer->write("Default", Style{Color::kDefault, false});
+    printer->write("Black", Style{Color::kBlack, false});
+    printer->write("Red", Style{Color::kRed, false});
+    printer->write("Green", Style{Color::kGreen, false});
+    printer->write("Yellow", Style{Color::kYellow, false});
+    printer->write("Blue", Style{Color::kBlue, false});
+    printer->write("Magenta", Style{Color::kMagenta, false});
+    printer->write("Cyan", Style{Color::kCyan, false});
+    printer->write("White", Style{Color::kWhite, false});
+    printf("\n");
 }
 
 TEST_F(PrinterTest, BoldWithoutColors) {
-  auto printer = Printer::create(stdout, false);
-  printer->write("Default", Style{Color::kDefault, true});
-  printer->write("Black", Style{Color::kBlack, true});
-  printer->write("Red", Style{Color::kRed, true});
-  printer->write("Green", Style{Color::kGreen, true});
-  printer->write("Yellow", Style{Color::kYellow, true});
-  printer->write("Blue", Style{Color::kBlue, true});
-  printer->write("Magenta", Style{Color::kMagenta, true});
-  printer->write("Cyan", Style{Color::kCyan, true});
-  printer->write("White", Style{Color::kWhite, true});
-  printf("\n");
+    auto printer = Printer::create(stdout, false);
+    printer->write("Default", Style{Color::kDefault, true});
+    printer->write("Black", Style{Color::kBlack, true});
+    printer->write("Red", Style{Color::kRed, true});
+    printer->write("Green", Style{Color::kGreen, true});
+    printer->write("Yellow", Style{Color::kYellow, true});
+    printer->write("Blue", Style{Color::kBlue, true});
+    printer->write("Magenta", Style{Color::kMagenta, true});
+    printer->write("Cyan", Style{Color::kCyan, true});
+    printer->write("White", Style{Color::kWhite, true});
+    printf("\n");
 }
 
 #endif  // ENABLE_PRINTER_TESTS
diff --git a/src/tint/diagnostic/printer_windows.cc b/src/tint/diagnostic/printer_windows.cc
index e8ebc19..fff3db5 100644
--- a/src/tint/diagnostic/printer_windows.cc
+++ b/src/tint/diagnostic/printer_windows.cc
@@ -23,89 +23,86 @@
 namespace {
 
 struct ConsoleInfo {
-  HANDLE handle = INVALID_HANDLE_VALUE;
-  WORD default_attributes = 0;
-  operator bool() const { return handle != INVALID_HANDLE_VALUE; }
+    HANDLE handle = INVALID_HANDLE_VALUE;
+    WORD default_attributes = 0;
+    operator bool() const { return handle != INVALID_HANDLE_VALUE; }
 };
 
 ConsoleInfo console_info(FILE* file) {
-  if (file == nullptr) {
-    return {};
-  }
+    if (file == nullptr) {
+        return {};
+    }
 
-  ConsoleInfo console{};
-  if (file == stdout) {
-    console.handle = GetStdHandle(STD_OUTPUT_HANDLE);
-  } else if (file == stderr) {
-    console.handle = GetStdHandle(STD_ERROR_HANDLE);
-  } else {
-    return {};
-  }
+    ConsoleInfo console{};
+    if (file == stdout) {
+        console.handle = GetStdHandle(STD_OUTPUT_HANDLE);
+    } else if (file == stderr) {
+        console.handle = GetStdHandle(STD_ERROR_HANDLE);
+    } else {
+        return {};
+    }
 
-  CONSOLE_SCREEN_BUFFER_INFO info{};
-  if (GetConsoleScreenBufferInfo(console.handle, &info) == 0) {
-    return {};
-  }
+    CONSOLE_SCREEN_BUFFER_INFO info{};
+    if (GetConsoleScreenBufferInfo(console.handle, &info) == 0) {
+        return {};
+    }
 
-  console.default_attributes = info.wAttributes;
-  return console;
+    console.default_attributes = info.wAttributes;
+    return console;
 }
 
 class PrinterWindows : public Printer {
- public:
-  PrinterWindows(FILE* f, bool use_colors)
-      : file(f), console(console_info(use_colors ? f : nullptr)) {}
+  public:
+    PrinterWindows(FILE* f, bool use_colors)
+        : file(f), console(console_info(use_colors ? f : nullptr)) {}
 
-  void write(const std::string& str, const Style& style) override {
-    write_color(style.color, style.bold);
-    fwrite(str.data(), 1, str.size(), file);
-    write_color(Color::kDefault, false);
-  }
-
- private:
-  WORD attributes(Color color, bool bold) {
-    switch (color) {
-      case Color::kDefault:
-        return console.default_attributes;
-      case Color::kBlack:
-        return 0;
-      case Color::kRed:
-        return FOREGROUND_RED | (bold ? FOREGROUND_INTENSITY : 0);
-      case Color::kGreen:
-        return FOREGROUND_GREEN | (bold ? FOREGROUND_INTENSITY : 0);
-      case Color::kYellow:
-        return FOREGROUND_RED | FOREGROUND_GREEN |
-               (bold ? FOREGROUND_INTENSITY : 0);
-      case Color::kBlue:
-        return FOREGROUND_BLUE | (bold ? FOREGROUND_INTENSITY : 0);
-      case Color::kMagenta:
-        return FOREGROUND_RED | FOREGROUND_BLUE |
-               (bold ? FOREGROUND_INTENSITY : 0);
-      case Color::kCyan:
-        return FOREGROUND_GREEN | FOREGROUND_BLUE |
-               (bold ? FOREGROUND_INTENSITY : 0);
-      case Color::kWhite:
-        return FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE |
-               (bold ? FOREGROUND_INTENSITY : 0);
+    void write(const std::string& str, const Style& style) override {
+        write_color(style.color, style.bold);
+        fwrite(str.data(), 1, str.size(), file);
+        write_color(Color::kDefault, false);
     }
-    return 0;  // unreachable
-  }
 
-  void write_color(Color color, bool bold) {
-    if (console) {
-      SetConsoleTextAttribute(console.handle, attributes(color, bold));
-      fflush(file);
+  private:
+    WORD attributes(Color color, bool bold) {
+        switch (color) {
+            case Color::kDefault:
+                return console.default_attributes;
+            case Color::kBlack:
+                return 0;
+            case Color::kRed:
+                return FOREGROUND_RED | (bold ? FOREGROUND_INTENSITY : 0);
+            case Color::kGreen:
+                return FOREGROUND_GREEN | (bold ? FOREGROUND_INTENSITY : 0);
+            case Color::kYellow:
+                return FOREGROUND_RED | FOREGROUND_GREEN | (bold ? FOREGROUND_INTENSITY : 0);
+            case Color::kBlue:
+                return FOREGROUND_BLUE | (bold ? FOREGROUND_INTENSITY : 0);
+            case Color::kMagenta:
+                return FOREGROUND_RED | FOREGROUND_BLUE | (bold ? FOREGROUND_INTENSITY : 0);
+            case Color::kCyan:
+                return FOREGROUND_GREEN | FOREGROUND_BLUE | (bold ? FOREGROUND_INTENSITY : 0);
+            case Color::kWhite:
+                return FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE |
+                       (bold ? FOREGROUND_INTENSITY : 0);
+        }
+        return 0;  // unreachable
     }
-  }
 
-  FILE* const file;
-  const ConsoleInfo console;
+    void write_color(Color color, bool bold) {
+        if (console) {
+            SetConsoleTextAttribute(console.handle, attributes(color, bold));
+            fflush(file);
+        }
+    }
+
+    FILE* const file;
+    const ConsoleInfo console;
 };
 
 }  // namespace
 
 std::unique_ptr<Printer> Printer::create(FILE* out, bool use_colors) {
-  return std::make_unique<PrinterWindows>(out, use_colors);
+    return std::make_unique<PrinterWindows>(out, use_colors);
 }
 
 }  // namespace tint::diag
diff --git a/src/tint/fuzzers/BUILD.gn b/src/tint/fuzzers/BUILD.gn
index 0934ab2..2b47762 100644
--- a/src/tint/fuzzers/BUILD.gn
+++ b/src/tint/fuzzers/BUILD.gn
@@ -20,6 +20,7 @@
 
 if (build_with_chromium) {
   import("//testing/libfuzzer/fuzzer_test.gni")
+  import("../../../scripts/dawn_overrides_with_defaults.gni")
 
   fuzzer_corpus_wgsl_dir = "${target_gen_dir}/fuzzer_corpus_wgsl"
   fuzzer_corpus_wgsl_stamp = "${fuzzer_corpus_wgsl_dir}.stamp"
@@ -32,6 +33,8 @@
       rebase_path(fuzzer_corpus_wgsl_dir, root_build_dir),
     ]
     outputs = [ fuzzer_corpus_wgsl_stamp ]
+
+    deps = [ "${dawn_root}/generator:remove_stale_autogen_files" ]
   }
 
   tint_fuzzer_common_libfuzzer_options = [
diff --git a/src/tint/fuzzers/cli.cc b/src/tint/fuzzers/cli.cc
index b8abbf3..11ce281 100644
--- a/src/tint/fuzzers/cli.cc
+++ b/src/tint/fuzzers/cli.cc
@@ -48,67 +48,66 @@
 )";
 
 [[noreturn]] void InvalidParam(const std::string& param) {
-  std::cout << "Invalid value for " << param << std::endl;
-  std::cout << kHelpMessage << std::endl;
-  exit(1);
+    std::cout << "Invalid value for " << param << std::endl;
+    std::cout << kHelpMessage << std::endl;
+    exit(1);
 }
 
 bool ParseBool(const std::string& value, bool* out) {
-  if (value.compare("true") == 0) {
-    *out = true;
-  } else if (value.compare("false") == 0) {
-    *out = false;
-  } else {
-    return false;
-  }
-  return true;
+    if (value.compare("true") == 0) {
+        *out = true;
+    } else if (value.compare("false") == 0) {
+        *out = false;
+    } else {
+        return false;
+    }
+    return true;
 }
 
 }  // namespace
 
 CliParams ParseCliParams(int* argc, char** argv) {
-  CliParams cli_params;
-  auto help = false;
+    CliParams cli_params;
+    auto help = false;
 
-  for (int i = *argc - 1; i > 0; --i) {
-    std::string param(argv[i]);
-    auto recognized_parameter = true;
+    for (int i = *argc - 1; i > 0; --i) {
+        std::string param(argv[i]);
+        auto recognized_parameter = true;
 
-    if (std::string::npos != param.find("-tint_dump_input=")) {
-      if (!ParseBool(param.substr(std::string("-tint_dump_input=").length()),
-                     &cli_params.dump_input)) {
-        InvalidParam(param);
-      }
-    } else if (std::string::npos != param.find("-tint_help")) {
-      help = true;
-    } else if (std::string::npos != param.find("-tint_enforce_validity=")) {
-      if (!ParseBool(
-              param.substr(std::string("-tint_enforce_validity=").length()),
-              &cli_params.enforce_validity)) {
-        InvalidParam(param);
-      }
-    } else {
-      recognized_parameter = false;
+        if (std::string::npos != param.find("-tint_dump_input=")) {
+            if (!ParseBool(param.substr(std::string("-tint_dump_input=").length()),
+                           &cli_params.dump_input)) {
+                InvalidParam(param);
+            }
+        } else if (std::string::npos != param.find("-tint_help")) {
+            help = true;
+        } else if (std::string::npos != param.find("-tint_enforce_validity=")) {
+            if (!ParseBool(param.substr(std::string("-tint_enforce_validity=").length()),
+                           &cli_params.enforce_validity)) {
+                InvalidParam(param);
+            }
+        } else {
+            recognized_parameter = false;
+        }
+
+        if (recognized_parameter) {
+            // Remove the recognized parameter from the list of all parameters by
+            // swapping it with the last one. This will suppress warnings in the
+            // libFuzzer about unrecognized parameters. By default, libFuzzer thinks
+            // that all user-defined parameters start with two dashes. However, we are
+            // forced to use a single one to make the fuzzer compatible with the
+            // ClusterFuzz.
+            std::swap(argv[i], argv[*argc - 1]);
+            *argc -= 1;
+        }
     }
 
-    if (recognized_parameter) {
-      // Remove the recognized parameter from the list of all parameters by
-      // swapping it with the last one. This will suppress warnings in the
-      // libFuzzer about unrecognized parameters. By default, libFuzzer thinks
-      // that all user-defined parameters start with two dashes. However, we are
-      // forced to use a single one to make the fuzzer compatible with the
-      // ClusterFuzz.
-      std::swap(argv[i], argv[*argc - 1]);
-      *argc -= 1;
+    if (help) {
+        std::cout << kHelpMessage << std::endl;
+        exit(0);
     }
-  }
 
-  if (help) {
-    std::cout << kHelpMessage << std::endl;
-    exit(0);
-  }
-
-  return cli_params;
+    return cli_params;
 }
 
 }  // namespace tint::fuzzers
diff --git a/src/tint/fuzzers/cli.h b/src/tint/fuzzers/cli.h
index df50042..50940a0 100644
--- a/src/tint/fuzzers/cli.h
+++ b/src/tint/fuzzers/cli.h
@@ -22,10 +22,10 @@
 /// CLI parameters accepted by the fuzzer. Type -tint_help in the CLI to see the
 /// help message
 struct CliParams {
-  /// Log contents of input shader
-  bool dump_input = false;
-  /// Throw error if shader becomes invalid during run
-  bool enforce_validity = false;
+    /// Log contents of input shader
+    bool dump_input = false;
+    /// Throw error if shader becomes invalid during run
+    bool enforce_validity = false;
 };
 
 /// @brief Parses CLI parameters.
diff --git a/src/tint/fuzzers/data_builder.h b/src/tint/fuzzers/data_builder.h
index a2292ab..92a565f 100644
--- a/src/tint/fuzzers/data_builder.h
+++ b/src/tint/fuzzers/data_builder.h
@@ -29,214 +29,214 @@
 
 /// Builder for generic pseudo-random data
 class DataBuilder {
- public:
-  /// @brief Initializes the internal engine using a seed value
-  /// @param seed - seed value passed to engine
-  explicit DataBuilder(uint64_t seed) : generator_(seed) {}
+  public:
+    /// @brief Initializes the internal engine using a seed value
+    /// @param seed - seed value passed to engine
+    explicit DataBuilder(uint64_t seed) : generator_(seed) {}
 
-  /// @brief Initializes the internal engine using seed data
-  /// @param data - data fuzzer to calculate seed from
-  /// @param size - size of data buffer
-  explicit DataBuilder(const uint8_t* data, size_t size)
-      : generator_(RandomGenerator::CalculateSeed(data, size)) {
-    assert(data != nullptr && "|data| must be !nullptr");
-  }
-
-  /// Destructor
-  ~DataBuilder() = default;
-
-  /// Move Constructor
-  DataBuilder(DataBuilder&&) = default;
-
-  /// Generate pseudo-random data of a specific type
-  /// @tparam T - type of data to produce
-  /// @returns pseudo-random data of type T
-  template <typename T>
-  T build() {
-    return BuildImpl<T>::impl(this);
-  }
-
-  /// Generate pseudo-random data of a specific type in a vector
-  /// @tparam T - data type held vector
-  /// @returns pseudo-random data of type std::vector<T>
-  template <typename T>
-  std::vector<T> vector() {
-    auto count = build<uint8_t>();
-    std::vector<T> out(count);
-    for (uint8_t i = 0; i < count; i++) {
-      out[i] = build<T>();
+    /// @brief Initializes the internal engine using seed data
+    /// @param data - data fuzzer to calculate seed from
+    /// @param size - size of data buffer
+    explicit DataBuilder(const uint8_t* data, size_t size)
+        : generator_(RandomGenerator::CalculateSeed(data, size)) {
+        assert(data != nullptr && "|data| must be !nullptr");
     }
-    return out;
-  }
 
-  /// Generate complex pseudo-random data of a specific type in a vector
-  /// @tparam T - data type held vector
-  /// @tparam Callback - callback that takes in a DataBuilder* and returns a T
-  /// @param generate - callback for generating each instance of T
-  /// @returns pseudo-random data of type std::vector<T>
-  template <typename T, typename Callback>
-  std::vector<T> vector(Callback generate) {
-    auto count = build<uint8_t>();
-    std::vector<T> out(count);
-    for (size_t i = 0; i < count; i++) {
-      out[i] = generate(this);
+    /// Destructor
+    ~DataBuilder() = default;
+
+    /// Move Constructor
+    DataBuilder(DataBuilder&&) = default;
+
+    /// Generate pseudo-random data of a specific type
+    /// @tparam T - type of data to produce
+    /// @returns pseudo-random data of type T
+    template <typename T>
+    T build() {
+        return BuildImpl<T>::impl(this);
     }
-    return out;
-  }
 
-  /// Generate an pseudo-random entry to a enum class.
-  /// Assumes enum is tightly packed starting at 0.
-  /// @tparam T - type of enum class
-  /// @param count - number of entries in enum class
-  /// @returns a random enum class entry
-  template <typename T>
-  T enum_class(uint32_t count) {
-    return static_cast<T>(generator_.Get4Bytes() % count);
-  }
-
- private:
-  RandomGenerator generator_;
-
-  // Disallow copy & assign
-  DataBuilder(const DataBuilder&) = delete;
-  DataBuilder& operator=(const DataBuilder&) = delete;
-
-  /// Get N bytes of pseudo-random data
-  /// @param out - pointer to location to save data
-  /// @param n - number of bytes to get
-  void build(void* out, size_t n) {
-    assert(out != nullptr && "|out| cannot be nullptr");
-    assert(n > 0 && "|n| must be > 0");
-
-    generator_.GetNBytes(reinterpret_cast<uint8_t*>(out), n);
-  }
-
-  /// Generate pseudo-random data of a specific type into an output var
-  /// @tparam T - type of data to produce
-  /// @param out - output var to generate into
-  template <typename T>
-  void build(T& out) {
-    out = build<T>();
-  }
-
-  /// Implementation of ::build<T>()
-  /// @tparam T - type of data to produce
-  template <typename T>
-  struct BuildImpl {
-    /// Generate a pseudo-random variable of type T
-    /// @param b - data builder to use
-    /// @returns a variable of type T filled with pseudo-random data
-    static T impl(DataBuilder* b) {
-      T out{};
-      b->build(&out, sizeof(T));
-      return out;
+    /// Generate pseudo-random data of a specific type in a vector
+    /// @tparam T - data type held vector
+    /// @returns pseudo-random data of type std::vector<T>
+    template <typename T>
+    std::vector<T> vector() {
+        auto count = build<uint8_t>();
+        std::vector<T> out(count);
+        for (uint8_t i = 0; i < count; i++) {
+            out[i] = build<T>();
+        }
+        return out;
     }
-  };
 
-  /// Specialization for std::string
-  template <>
-  struct BuildImpl<std::string> {
-    /// Generate a pseudo-random string
-    /// @param b - data builder to use
-    /// @returns a string filled with pseudo-random data
-    static std::string impl(DataBuilder* b) {
-      auto count = b->build<uint8_t>();
-      if (count == 0) {
-        return "";
-      }
-      std::vector<uint8_t> source(count);
-      b->build(source.data(), count);
-      return {source.begin(), source.end()};
+    /// Generate complex pseudo-random data of a specific type in a vector
+    /// @tparam T - data type held vector
+    /// @tparam Callback - callback that takes in a DataBuilder* and returns a T
+    /// @param generate - callback for generating each instance of T
+    /// @returns pseudo-random data of type std::vector<T>
+    template <typename T, typename Callback>
+    std::vector<T> vector(Callback generate) {
+        auto count = build<uint8_t>();
+        std::vector<T> out(count);
+        for (size_t i = 0; i < count; i++) {
+            out[i] = generate(this);
+        }
+        return out;
     }
-  };
 
-  /// Specialization for bool
-  template <>
-  struct BuildImpl<bool> {
-    /// Generate a pseudo-random bool
-    /// @param b - data builder to use
-    /// @returns a boolean with even odds of being true or false
-    static bool impl(DataBuilder* b) { return b->generator_.GetBool(); }
-  };
-
-  /// Specialization for writer::msl::Options
-  template <>
-  struct BuildImpl<writer::msl::Options> {
-    /// Generate a pseudo-random writer::msl::Options struct
-    /// @param b - data builder to use
-    /// @returns writer::msl::Options filled with pseudo-random data
-    static writer::msl::Options impl(DataBuilder* b) {
-      writer::msl::Options out{};
-      b->build(out.buffer_size_ubo_index);
-      b->build(out.fixed_sample_mask);
-      b->build(out.emit_vertex_point_size);
-      b->build(out.disable_workgroup_init);
-      b->build(out.generate_external_texture_bindings);
-      b->build(out.array_length_from_uniform);
-      return out;
+    /// Generate an pseudo-random entry to a enum class.
+    /// Assumes enum is tightly packed starting at 0.
+    /// @tparam T - type of enum class
+    /// @param count - number of entries in enum class
+    /// @returns a random enum class entry
+    template <typename T>
+    T enum_class(uint32_t count) {
+        return static_cast<T>(generator_.Get4Bytes() % count);
     }
-  };
 
-  /// Specialization for writer::hlsl::Options
-  template <>
-  struct BuildImpl<writer::hlsl::Options> {
-    /// Generate a pseudo-random writer::hlsl::Options struct
-    /// @param b - data builder to use
-    /// @returns writer::hlsl::Options filled with pseudo-random data
-    static writer::hlsl::Options impl(DataBuilder* b) {
-      writer::hlsl::Options out{};
-      b->build(out.root_constant_binding_point);
-      b->build(out.disable_workgroup_init);
-      b->build(out.array_length_from_uniform);
-      return out;
-    }
-  };
+  private:
+    RandomGenerator generator_;
 
-  /// Specialization for writer::spirv::Options
-  template <>
-  struct BuildImpl<writer::spirv::Options> {
-    /// Generate a pseudo-random writer::spirv::Options struct
-    /// @param b - data builder to use
-    /// @returns writer::spirv::Options filled with pseudo-random data
-    static writer::spirv::Options impl(DataBuilder* b) {
-      writer::spirv::Options out{};
-      b->build(out.emit_vertex_point_size);
-      b->build(out.disable_workgroup_init);
-      return out;
-    }
-  };
+    // Disallow copy & assign
+    DataBuilder(const DataBuilder&) = delete;
+    DataBuilder& operator=(const DataBuilder&) = delete;
 
-  /// Specialization for writer::ArrayLengthFromUniformOptions
-  template <>
-  struct BuildImpl<writer::ArrayLengthFromUniformOptions> {
-    /// Generate a pseudo-random writer::ArrayLengthFromUniformOptions struct
-    /// @param b - data builder to use
-    /// @returns writer::ArrayLengthFromUniformOptions filled with pseudo-random
-    /// data
-    static writer::ArrayLengthFromUniformOptions impl(DataBuilder* b) {
-      writer::ArrayLengthFromUniformOptions out{};
-      b->build(out.ubo_binding);
-      b->build(out.bindpoint_to_size_index);
-      return out;
-    }
-  };
+    /// Get N bytes of pseudo-random data
+    /// @param out - pointer to location to save data
+    /// @param n - number of bytes to get
+    void build(void* out, size_t n) {
+        assert(out != nullptr && "|out| cannot be nullptr");
+        assert(n > 0 && "|n| must be > 0");
 
-  /// Specialization for std::unordered_map<K, V>
-  template <typename K, typename V>
-  struct BuildImpl<std::unordered_map<K, V>> {
-    /// Generate a pseudo-random std::unordered_map<K, V>
-    /// @param b - data builder to use
-    /// @returns std::unordered_map<K, V> filled with
-    /// pseudo-random data
-    static std::unordered_map<K, V> impl(DataBuilder* b) {
-      std::unordered_map<K, V> out;
-      uint8_t count = b->build<uint8_t>();
-      for (uint8_t i = 0; i < count; ++i) {
-        out.emplace(b->build<K>(), b->build<V>());
-      }
-      return out;
+        generator_.GetNBytes(reinterpret_cast<uint8_t*>(out), n);
     }
-  };
+
+    /// Generate pseudo-random data of a specific type into an output var
+    /// @tparam T - type of data to produce
+    /// @param out - output var to generate into
+    template <typename T>
+    void build(T& out) {
+        out = build<T>();
+    }
+
+    /// Implementation of ::build<T>()
+    /// @tparam T - type of data to produce
+    template <typename T>
+    struct BuildImpl {
+        /// Generate a pseudo-random variable of type T
+        /// @param b - data builder to use
+        /// @returns a variable of type T filled with pseudo-random data
+        static T impl(DataBuilder* b) {
+            T out{};
+            b->build(&out, sizeof(T));
+            return out;
+        }
+    };
+
+    /// Specialization for std::string
+    template <>
+    struct BuildImpl<std::string> {
+        /// Generate a pseudo-random string
+        /// @param b - data builder to use
+        /// @returns a string filled with pseudo-random data
+        static std::string impl(DataBuilder* b) {
+            auto count = b->build<uint8_t>();
+            if (count == 0) {
+                return "";
+            }
+            std::vector<uint8_t> source(count);
+            b->build(source.data(), count);
+            return {source.begin(), source.end()};
+        }
+    };
+
+    /// Specialization for bool
+    template <>
+    struct BuildImpl<bool> {
+        /// Generate a pseudo-random bool
+        /// @param b - data builder to use
+        /// @returns a boolean with even odds of being true or false
+        static bool impl(DataBuilder* b) { return b->generator_.GetBool(); }
+    };
+
+    /// Specialization for writer::msl::Options
+    template <>
+    struct BuildImpl<writer::msl::Options> {
+        /// Generate a pseudo-random writer::msl::Options struct
+        /// @param b - data builder to use
+        /// @returns writer::msl::Options filled with pseudo-random data
+        static writer::msl::Options impl(DataBuilder* b) {
+            writer::msl::Options out{};
+            b->build(out.buffer_size_ubo_index);
+            b->build(out.fixed_sample_mask);
+            b->build(out.emit_vertex_point_size);
+            b->build(out.disable_workgroup_init);
+            b->build(out.generate_external_texture_bindings);
+            b->build(out.array_length_from_uniform);
+            return out;
+        }
+    };
+
+    /// Specialization for writer::hlsl::Options
+    template <>
+    struct BuildImpl<writer::hlsl::Options> {
+        /// Generate a pseudo-random writer::hlsl::Options struct
+        /// @param b - data builder to use
+        /// @returns writer::hlsl::Options filled with pseudo-random data
+        static writer::hlsl::Options impl(DataBuilder* b) {
+            writer::hlsl::Options out{};
+            b->build(out.root_constant_binding_point);
+            b->build(out.disable_workgroup_init);
+            b->build(out.array_length_from_uniform);
+            return out;
+        }
+    };
+
+    /// Specialization for writer::spirv::Options
+    template <>
+    struct BuildImpl<writer::spirv::Options> {
+        /// Generate a pseudo-random writer::spirv::Options struct
+        /// @param b - data builder to use
+        /// @returns writer::spirv::Options filled with pseudo-random data
+        static writer::spirv::Options impl(DataBuilder* b) {
+            writer::spirv::Options out{};
+            b->build(out.emit_vertex_point_size);
+            b->build(out.disable_workgroup_init);
+            return out;
+        }
+    };
+
+    /// Specialization for writer::ArrayLengthFromUniformOptions
+    template <>
+    struct BuildImpl<writer::ArrayLengthFromUniformOptions> {
+        /// Generate a pseudo-random writer::ArrayLengthFromUniformOptions struct
+        /// @param b - data builder to use
+        /// @returns writer::ArrayLengthFromUniformOptions filled with pseudo-random
+        /// data
+        static writer::ArrayLengthFromUniformOptions impl(DataBuilder* b) {
+            writer::ArrayLengthFromUniformOptions out{};
+            b->build(out.ubo_binding);
+            b->build(out.bindpoint_to_size_index);
+            return out;
+        }
+    };
+
+    /// Specialization for std::unordered_map<K, V>
+    template <typename K, typename V>
+    struct BuildImpl<std::unordered_map<K, V>> {
+        /// Generate a pseudo-random std::unordered_map<K, V>
+        /// @param b - data builder to use
+        /// @returns std::unordered_map<K, V> filled with
+        /// pseudo-random data
+        static std::unordered_map<K, V> impl(DataBuilder* b) {
+            std::unordered_map<K, V> out;
+            uint8_t count = b->build<uint8_t>();
+            for (uint8_t i = 0; i < count; ++i) {
+                out.emplace(b->build<K>(), b->build<V>());
+            }
+            return out;
+        }
+    };
 };
 
 }  // namespace tint::fuzzers
diff --git a/src/tint/fuzzers/fuzzer_init.cc b/src/tint/fuzzers/fuzzer_init.cc
index 1fc5e52..3d3f692 100644
--- a/src/tint/fuzzers/fuzzer_init.cc
+++ b/src/tint/fuzzers/fuzzer_init.cc
@@ -22,12 +22,12 @@
 }
 
 const CliParams& GetCliParams() {
-  return cli_params;
+    return cli_params;
 }
 
 extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) {
-  cli_params = ParseCliParams(argc, *argv);
-  return 0;
+    cli_params = ParseCliParams(argc, *argv);
+    return 0;
 }
 
 }  // namespace tint::fuzzers
diff --git a/src/tint/fuzzers/mersenne_twister_engine.cc b/src/tint/fuzzers/mersenne_twister_engine.cc
index 2f55cff..6a011ac 100644
--- a/src/tint/fuzzers/mersenne_twister_engine.cc
+++ b/src/tint/fuzzers/mersenne_twister_engine.cc
@@ -31,8 +31,8 @@
 /// @returns i, where lower <= i < upper
 template <typename I>
 I RandomInteger(std::mt19937_64* engine, I lower, I upper) {
-  assert(lower < upper && "|lower| must be strictly less than |upper|");
-  return std::uniform_int_distribution<I>(lower, upper - 1)(*engine);
+    assert(lower < upper && "|lower| must be strictly less than |upper|");
+    return std::uniform_int_distribution<I>(lower, upper - 1)(*engine);
 }
 
 }  // namespace
@@ -40,18 +40,17 @@
 MersenneTwisterEngine::MersenneTwisterEngine(uint64_t seed) : engine_(seed) {}
 
 uint32_t MersenneTwisterEngine::RandomUInt32(uint32_t lower, uint32_t upper) {
-  return RandomInteger(&engine_, lower, upper);
+    return RandomInteger(&engine_, lower, upper);
 }
 
 uint64_t MersenneTwisterEngine::RandomUInt64(uint64_t lower, uint64_t upper) {
-  return RandomInteger(&engine_, lower, upper);
+    return RandomInteger(&engine_, lower, upper);
 }
 
 void MersenneTwisterEngine::RandomNBytes(uint8_t* dest, size_t n) {
-  assert(dest && "|dest| must not be nullptr");
-  std::generate(
-      dest, dest + n,
-      std::independent_bits_engine<std::mt19937_64, 8, uint8_t>(engine_));
+    assert(dest && "|dest| must not be nullptr");
+    std::generate(dest, dest + n,
+                  std::independent_bits_engine<std::mt19937_64, 8, uint8_t>(engine_));
 }
 
 }  // namespace tint::fuzzers
diff --git a/src/tint/fuzzers/mersenne_twister_engine.h b/src/tint/fuzzers/mersenne_twister_engine.h
index 9308d33..565140b 100644
--- a/src/tint/fuzzers/mersenne_twister_engine.h
+++ b/src/tint/fuzzers/mersenne_twister_engine.h
@@ -23,35 +23,35 @@
 
 /// Standard MT based random number generation
 class MersenneTwisterEngine : public RandomGeneratorEngine {
- public:
-  /// @brief Initializes using provided seed
-  /// @param seed - seed value to use
-  explicit MersenneTwisterEngine(uint64_t seed);
-  ~MersenneTwisterEngine() override = default;
+  public:
+    /// @brief Initializes using provided seed
+    /// @param seed - seed value to use
+    explicit MersenneTwisterEngine(uint64_t seed);
+    ~MersenneTwisterEngine() override = default;
 
-  /// Generate random uint32_t value from uniform distribution.
-  /// @param lower - lower bound of integer generated
-  /// @param upper - upper bound of integer generated
-  /// @returns i, where lower <= i < upper
-  uint32_t RandomUInt32(uint32_t lower, uint32_t upper) override;
+    /// Generate random uint32_t value from uniform distribution.
+    /// @param lower - lower bound of integer generated
+    /// @param upper - upper bound of integer generated
+    /// @returns i, where lower <= i < upper
+    uint32_t RandomUInt32(uint32_t lower, uint32_t upper) override;
 
-  /// Get random uint64_t value from uniform distribution.
-  /// @param lower - lower bound of integer generated
-  /// @param upper - upper bound of integer generated
-  /// @returns i, where lower <= i < upper
-  uint64_t RandomUInt64(uint64_t lower, uint64_t upper) override;
+    /// Get random uint64_t value from uniform distribution.
+    /// @param lower - lower bound of integer generated
+    /// @param upper - upper bound of integer generated
+    /// @returns i, where lower <= i < upper
+    uint64_t RandomUInt64(uint64_t lower, uint64_t upper) override;
 
-  /// Get N bytes of pseudo-random data
-  /// @param dest - memory location to store data
-  /// @param n - number of bytes of data to generate
-  void RandomNBytes(uint8_t* dest, size_t n) override;
+    /// Get N bytes of pseudo-random data
+    /// @param dest - memory location to store data
+    /// @param n - number of bytes of data to generate
+    void RandomNBytes(uint8_t* dest, size_t n) override;
 
- private:
-  // Disallow copy & assign
-  MersenneTwisterEngine(const MersenneTwisterEngine&) = delete;
-  MersenneTwisterEngine& operator=(const MersenneTwisterEngine&) = delete;
+  private:
+    // Disallow copy & assign
+    MersenneTwisterEngine(const MersenneTwisterEngine&) = delete;
+    MersenneTwisterEngine& operator=(const MersenneTwisterEngine&) = delete;
 
-  std::mt19937_64 engine_;
+    std::mt19937_64 engine_;
 };  // class MersenneTwisterEngine
 
 }  // namespace tint::fuzzers
diff --git a/src/tint/fuzzers/random_generator.cc b/src/tint/fuzzers/random_generator.cc
index 8ad211f..186ce1c 100644
--- a/src/tint/fuzzers/random_generator.cc
+++ b/src/tint/fuzzers/random_generator.cc
@@ -34,12 +34,12 @@
 /// @param size - number of elements in buffer
 /// @returns hash of the data in the buffer
 size_t HashBuffer(const uint8_t* data, const size_t size) {
-  size_t hash = 102931;
-  utils::HashCombine(&hash, size);
-  for (size_t i = 0; i < size; i++) {
-    utils::HashCombine(&hash, data[i]);
-  }
-  return hash;
+    size_t hash = 102931;
+    utils::HashCombine(&hash, size);
+    for (size_t i = 0; i < size; i++) {
+        utils::HashCombine(&hash, data[i]);
+    }
+    return hash;
 }
 
 }  // namespace
@@ -51,72 +51,70 @@
     : RandomGenerator(std::make_unique<MersenneTwisterEngine>(seed)) {}
 
 uint32_t RandomGenerator::GetUInt32(uint32_t lower, uint32_t upper) {
-  assert(lower < upper && "|lower| must be strictly less than |upper|");
-  return engine_->RandomUInt32(lower, upper);
+    assert(lower < upper && "|lower| must be strictly less than |upper|");
+    return engine_->RandomUInt32(lower, upper);
 }
 
 uint32_t RandomGenerator::GetUInt32(uint32_t bound) {
-  assert(bound > 0 && "|bound| must be greater than 0");
-  return engine_->RandomUInt32(0u, bound);
+    assert(bound > 0 && "|bound| must be greater than 0");
+    return engine_->RandomUInt32(0u, bound);
 }
 
 uint64_t RandomGenerator::GetUInt64(uint64_t lower, uint64_t upper) {
-  assert(lower < upper && "|lower| must be strictly less than |upper|");
-  return engine_->RandomUInt64(lower, upper);
+    assert(lower < upper && "|lower| must be strictly less than |upper|");
+    return engine_->RandomUInt64(lower, upper);
 }
 
 uint64_t RandomGenerator::GetUInt64(uint64_t bound) {
-  assert(bound > 0 && "|bound| must be greater than 0");
-  return engine_->RandomUInt64(static_cast<uint64_t>(0), bound);
+    assert(bound > 0 && "|bound| must be greater than 0");
+    return engine_->RandomUInt64(static_cast<uint64_t>(0), bound);
 }
 
 uint8_t RandomGenerator::GetByte() {
-  uint8_t result;
-  engine_->RandomNBytes(&result, 1);
-  return result;
+    uint8_t result;
+    engine_->RandomNBytes(&result, 1);
+    return result;
 }
 
 uint32_t RandomGenerator::Get4Bytes() {
-  uint32_t result;
-  engine_->RandomNBytes(reinterpret_cast<uint8_t*>(&result), 4);
-  return result;
+    uint32_t result;
+    engine_->RandomNBytes(reinterpret_cast<uint8_t*>(&result), 4);
+    return result;
 }
 
 void RandomGenerator::GetNBytes(uint8_t* dest, size_t n) {
-  assert(dest && "|dest| must not be nullptr");
-  engine_->RandomNBytes(dest, n);
+    assert(dest && "|dest| must not be nullptr");
+    engine_->RandomNBytes(dest, n);
 }
 
 bool RandomGenerator::GetBool() {
-  return engine_->RandomUInt32(0u, 2u);
+    return engine_->RandomUInt32(0u, 2u);
 }
 
 bool RandomGenerator::GetWeightedBool(uint32_t percentage) {
-  static const uint32_t kMaxPercentage = 100;
-  assert(percentage <= kMaxPercentage &&
-         "|percentage| needs to be within [0, 100]");
-  return engine_->RandomUInt32(0u, kMaxPercentage) < percentage;
+    static const uint32_t kMaxPercentage = 100;
+    assert(percentage <= kMaxPercentage && "|percentage| needs to be within [0, 100]");
+    return engine_->RandomUInt32(0u, kMaxPercentage) < percentage;
 }
 
 uint64_t RandomGenerator::CalculateSeed(const uint8_t* data, size_t size) {
-  assert(data != nullptr && "|data| must be !nullptr");
+    assert(data != nullptr && "|data| must be !nullptr");
 
-  // Number of bytes we want to skip at the start of data for the hash.
-  // Fewer bytes may be skipped when `size` is small.
-  // Has lower precedence than kHashDesiredMinBytes.
-  static const int64_t kHashDesiredLeadingSkipBytes = 5;
-  // Minimum number of bytes we want to use in the hash.
-  // Used for short buffers.
-  static const int64_t kHashDesiredMinBytes = 4;
-  // Maximum number of bytes we want to use in the hash.
-  static const int64_t kHashDesiredMaxBytes = 32;
-  auto size_i64 = static_cast<int64_t>(size);
-  auto hash_begin_i64 =
-      std::min(kHashDesiredLeadingSkipBytes,
-               std::max<int64_t>(size_i64 - kHashDesiredMinBytes, 0));
-  auto hash_end_i64 = std::min(hash_begin_i64 + kHashDesiredMaxBytes, size_i64);
-  auto hash_begin = static_cast<size_t>(hash_begin_i64);
-  auto hash_size = static_cast<size_t>(hash_end_i64) - hash_begin;
-  return HashBuffer(data + hash_begin, hash_size);
+    // Number of bytes we want to skip at the start of data for the hash.
+    // Fewer bytes may be skipped when `size` is small.
+    // Has lower precedence than kHashDesiredMinBytes.
+    static const int64_t kHashDesiredLeadingSkipBytes = 5;
+    // Minimum number of bytes we want to use in the hash.
+    // Used for short buffers.
+    static const int64_t kHashDesiredMinBytes = 4;
+    // Maximum number of bytes we want to use in the hash.
+    static const int64_t kHashDesiredMaxBytes = 32;
+    auto size_i64 = static_cast<int64_t>(size);
+    auto hash_begin_i64 = std::min(kHashDesiredLeadingSkipBytes,
+                                   std::max<int64_t>(size_i64 - kHashDesiredMinBytes, 0));
+    auto hash_end_i64 = std::min(hash_begin_i64 + kHashDesiredMaxBytes, size_i64);
+    auto hash_begin = static_cast<size_t>(hash_begin_i64);
+    auto hash_size = static_cast<size_t>(hash_end_i64) - hash_begin;
+    return HashBuffer(data + hash_begin, hash_size);
 }
 }  // namespace tint::fuzzers
diff --git a/src/tint/fuzzers/random_generator.h b/src/tint/fuzzers/random_generator.h
index bbdacfd..3c9d86cb 100644
--- a/src/tint/fuzzers/random_generator.h
+++ b/src/tint/fuzzers/random_generator.h
@@ -25,90 +25,90 @@
 
 /// Pseudo random generator utility class for fuzzing
 class RandomGenerator {
- public:
-  /// @brief Initializes using provided engine
-  /// @param engine - engine implementation to use
-  explicit RandomGenerator(std::unique_ptr<RandomGeneratorEngine> engine);
+  public:
+    /// @brief Initializes using provided engine
+    /// @param engine - engine implementation to use
+    explicit RandomGenerator(std::unique_ptr<RandomGeneratorEngine> engine);
 
-  /// @brief Creates a MersenneTwisterEngine and initializes using that
-  /// @param seed - seed value to use for engine
-  explicit RandomGenerator(uint64_t seed);
+    /// @brief Creates a MersenneTwisterEngine and initializes using that
+    /// @param seed - seed value to use for engine
+    explicit RandomGenerator(uint64_t seed);
 
-  /// Destructor
-  ~RandomGenerator() = default;
+    /// Destructor
+    ~RandomGenerator() = default;
 
-  /// Move Constructor
-  RandomGenerator(RandomGenerator&&) = default;
+    /// Move Constructor
+    RandomGenerator(RandomGenerator&&) = default;
 
-  /// Get uint32_t value from uniform distribution.
-  /// @param lower - lower bound of integer generated
-  /// @param upper - upper bound of integer generated
-  /// @returns i, where lower <= i < upper
-  uint32_t GetUInt32(uint32_t lower, uint32_t upper);
+    /// Get uint32_t value from uniform distribution.
+    /// @param lower - lower bound of integer generated
+    /// @param upper - upper bound of integer generated
+    /// @returns i, where lower <= i < upper
+    uint32_t GetUInt32(uint32_t lower, uint32_t upper);
 
-  /// Get uint32_t value from uniform distribution.
-  /// @param bound - Upper bound of integer generated
-  /// @returns i, where 0 <= i < bound
-  uint32_t GetUInt32(uint32_t bound);
+    /// Get uint32_t value from uniform distribution.
+    /// @param bound - Upper bound of integer generated
+    /// @returns i, where 0 <= i < bound
+    uint32_t GetUInt32(uint32_t bound);
 
-  /// Get uint32_t value from uniform distribution.
-  /// @param lower - lower bound of integer generated
-  /// @param upper - upper bound of integer generated
-  /// @returns i, where lower <= i < upper
-  uint64_t GetUInt64(uint64_t lower, uint64_t upper);
+    /// Get uint32_t value from uniform distribution.
+    /// @param lower - lower bound of integer generated
+    /// @param upper - upper bound of integer generated
+    /// @returns i, where lower <= i < upper
+    uint64_t GetUInt64(uint64_t lower, uint64_t upper);
 
-  /// Get uint64_t value from uniform distribution.
-  /// @param bound - Upper bound of integer generated
-  /// @returns i, where 0 <= i < bound
-  uint64_t GetUInt64(uint64_t bound);
+    /// Get uint64_t value from uniform distribution.
+    /// @param bound - Upper bound of integer generated
+    /// @returns i, where 0 <= i < bound
+    uint64_t GetUInt64(uint64_t bound);
 
-  /// Get 1 byte of pseudo-random data
-  /// Should be more efficient then calling GetNBytes(1);
-  /// @returns 1-byte of random data
-  uint8_t GetByte();
+    /// Get 1 byte of pseudo-random data
+    /// Should be more efficient then calling GetNBytes(1);
+    /// @returns 1-byte of random data
+    uint8_t GetByte();
 
-  /// Get 4 bytes of pseudo-random data
-  /// Should be more efficient then calling GetNBytes(4);
-  /// @returns 4-bytes of random data
-  uint32_t Get4Bytes();
+    /// Get 4 bytes of pseudo-random data
+    /// Should be more efficient then calling GetNBytes(4);
+    /// @returns 4-bytes of random data
+    uint32_t Get4Bytes();
 
-  /// Get N bytes of pseudo-random data
-  /// @param dest - memory location to store data
-  /// @param n - number of bytes of data to get
-  void GetNBytes(uint8_t* dest, size_t n);
+    /// Get N bytes of pseudo-random data
+    /// @param dest - memory location to store data
+    /// @param n - number of bytes of data to get
+    void GetNBytes(uint8_t* dest, size_t n);
 
-  /// Get random bool with even odds
-  /// @returns true 50% of the time and false %50 of time.
-  bool GetBool();
+    /// Get random bool with even odds
+    /// @returns true 50% of the time and false %50 of time.
+    bool GetBool();
 
-  /// Get random bool with weighted odds
-  /// @param percentage - likelihood of true being returned
-  /// @returns true |percentage|% of the time, and false (100 - |percentage|)%
-  /// of the time.
-  bool GetWeightedBool(uint32_t percentage);
+    /// Get random bool with weighted odds
+    /// @param percentage - likelihood of true being returned
+    /// @returns true |percentage|% of the time, and false (100 - |percentage|)%
+    /// of the time.
+    bool GetWeightedBool(uint32_t percentage);
 
-  /// Returns a randomly-chosen element from vector v.
-  /// @param v - the vector from which the random element will be selected.
-  /// @return a random element of vector v.
-  template <typename T>
-  inline T GetRandomElement(const std::vector<T>& v) {
-    return v[GetUInt64(0, v.size())];
-  }
+    /// Returns a randomly-chosen element from vector v.
+    /// @param v - the vector from which the random element will be selected.
+    /// @return a random element of vector v.
+    template <typename T>
+    inline T GetRandomElement(const std::vector<T>& v) {
+        return v[GetUInt64(0, v.size())];
+    }
 
-  /// Calculate a seed value based on a blob of data.
-  /// Currently hashes bytes near the front of the buffer, after skipping N
-  /// bytes.
-  /// @param data - pointer to data to base calculation off of, must be !nullptr
-  /// @param size - number of elements in |data|, must be > 0
-  /// @returns calculated seed value
-  static uint64_t CalculateSeed(const uint8_t* data, size_t size);
+    /// Calculate a seed value based on a blob of data.
+    /// Currently hashes bytes near the front of the buffer, after skipping N
+    /// bytes.
+    /// @param data - pointer to data to base calculation off of, must be !nullptr
+    /// @param size - number of elements in |data|, must be > 0
+    /// @returns calculated seed value
+    static uint64_t CalculateSeed(const uint8_t* data, size_t size);
 
- private:
-  // Disallow copy & assign
-  RandomGenerator(const RandomGenerator&) = delete;
-  RandomGenerator& operator=(const RandomGenerator&) = delete;
+  private:
+    // Disallow copy & assign
+    RandomGenerator(const RandomGenerator&) = delete;
+    RandomGenerator& operator=(const RandomGenerator&) = delete;
 
-  std::unique_ptr<RandomGeneratorEngine> engine_;
+    std::unique_ptr<RandomGeneratorEngine> engine_;
 };  // class RandomGenerator
 
 }  // namespace tint::fuzzers
diff --git a/src/tint/fuzzers/random_generator_engine.h b/src/tint/fuzzers/random_generator_engine.h
index 9804727..9dc984f 100644
--- a/src/tint/fuzzers/random_generator_engine.h
+++ b/src/tint/fuzzers/random_generator_engine.h
@@ -23,37 +23,37 @@
 
 /// Wrapper interface around STL random number engine
 class RandomGeneratorEngine {
- public:
-  /// Constructor
-  RandomGeneratorEngine();
+  public:
+    /// Constructor
+    RandomGeneratorEngine();
 
-  /// Destructor
-  virtual ~RandomGeneratorEngine();
+    /// Destructor
+    virtual ~RandomGeneratorEngine();
 
-  /// Move Constructor
-  RandomGeneratorEngine(RandomGeneratorEngine&&);
+    /// Move Constructor
+    RandomGeneratorEngine(RandomGeneratorEngine&&);
 
-  /// Generates a random uint32_t value from uniform distribution.
-  /// @param lower - lower bound of integer generated
-  /// @param upper - upper bound of integer generated
-  /// @returns i, where lower <= i < upper
-  virtual uint32_t RandomUInt32(uint32_t lower, uint32_t upper) = 0;
+    /// Generates a random uint32_t value from uniform distribution.
+    /// @param lower - lower bound of integer generated
+    /// @param upper - upper bound of integer generated
+    /// @returns i, where lower <= i < upper
+    virtual uint32_t RandomUInt32(uint32_t lower, uint32_t upper) = 0;
 
-  /// Generates a random uint64_t value from uniform distribution.
-  /// @param lower - lower bound of integer generated
-  /// @param upper - upper bound of integer generated
-  /// @returns i, where lower <= i < upper
-  virtual uint64_t RandomUInt64(uint64_t lower, uint64_t upper) = 0;
+    /// Generates a random uint64_t value from uniform distribution.
+    /// @param lower - lower bound of integer generated
+    /// @param upper - upper bound of integer generated
+    /// @returns i, where lower <= i < upper
+    virtual uint64_t RandomUInt64(uint64_t lower, uint64_t upper) = 0;
 
-  /// Generates N bytes of pseudo-random data
-  /// @param dest - memory location to store data
-  /// @param n - number of bytes of data to generate
-  virtual void RandomNBytes(uint8_t* dest, size_t n) = 0;
+    /// Generates N bytes of pseudo-random data
+    /// @param dest - memory location to store data
+    /// @param n - number of bytes of data to generate
+    virtual void RandomNBytes(uint8_t* dest, size_t n) = 0;
 
- private:
-  // Disallow copy & assign
-  RandomGeneratorEngine(const RandomGeneratorEngine&) = delete;
-  RandomGeneratorEngine& operator=(const RandomGeneratorEngine&) = delete;
+  private:
+    // Disallow copy & assign
+    RandomGeneratorEngine(const RandomGeneratorEngine&) = delete;
+    RandomGeneratorEngine& operator=(const RandomGeneratorEngine&) = delete;
 };  // class RandomGeneratorEngine
 
 }  // namespace tint::fuzzers
diff --git a/src/tint/fuzzers/random_generator_test.cc b/src/tint/fuzzers/random_generator_test.cc
index 95916cb..de88868 100644
--- a/src/tint/fuzzers/random_generator_test.cc
+++ b/src/tint/fuzzers/random_generator_test.cc
@@ -26,174 +26,172 @@
 /// Implementation of RandomGeneratorEngine that just returns a stream of
 /// monotonically increasing numbers.
 class MonotonicEngine : public RandomGeneratorEngine {
- public:
-  uint32_t RandomUInt32(uint32_t, uint32_t) override { return next_++; }
+  public:
+    uint32_t RandomUInt32(uint32_t, uint32_t) override { return next_++; }
 
-  uint64_t RandomUInt64(uint64_t, uint64_t) override { return next_++; }
+    uint64_t RandomUInt64(uint64_t, uint64_t) override { return next_++; }
 
-  void RandomNBytes(uint8_t*, size_t) override {
-    assert(false && "MonotonicDelegate does not implement RandomNBytes");
-  }
+    void RandomNBytes(uint8_t*, size_t) override {
+        assert(false && "MonotonicDelegate does not implement RandomNBytes");
+    }
 
- private:
-  uint32_t next_ = 0;
+  private:
+    uint32_t next_ = 0;
 };
 
 class RandomGeneratorTest : public testing::Test {
- public:
-  void SetUp() override { rng_ = std::make_unique<RandomGenerator>(0); }
+  public:
+    void SetUp() override { rng_ = std::make_unique<RandomGenerator>(0); }
 
-  void TearDown() override {}
+    void TearDown() override {}
 
- protected:
-  std::unique_ptr<RandomGenerator> rng_;
+  protected:
+    std::unique_ptr<RandomGenerator> rng_;
 };
 
 #ifndef NDEBUG
 TEST_F(RandomGeneratorTest, GetUInt32ReversedBoundsCrashes) {
-  EXPECT_DEATH(rng_->GetUInt32(10, 5), ".*");
+    EXPECT_DEATH(rng_->GetUInt32(10, 5), ".*");
 }
 
 TEST_F(RandomGeneratorTest, GetUInt32EmptyBoundsCrashes) {
-  EXPECT_DEATH(rng_->GetUInt32(5, 5), ".*");
+    EXPECT_DEATH(rng_->GetUInt32(5, 5), ".*");
 }
 
 TEST_F(RandomGeneratorTest, GetUInt32ZeroBoundCrashes) {
-  EXPECT_DEATH(rng_->GetUInt32(0u), ".*");
+    EXPECT_DEATH(rng_->GetUInt32(0u), ".*");
 }
 #endif  // NDEBUG
 
 TEST_F(RandomGeneratorTest, GetUInt32SingularReturnsOneValue) {
-  {
-    uint32_t result = rng_->GetUInt32(5u, 6u);
-    ASSERT_EQ(5u, result);
-  }
-  {
-    uint32_t result = rng_->GetUInt32(1u);
-    ASSERT_EQ(0u, result);
-  }
+    {
+        uint32_t result = rng_->GetUInt32(5u, 6u);
+        ASSERT_EQ(5u, result);
+    }
+    {
+        uint32_t result = rng_->GetUInt32(1u);
+        ASSERT_EQ(0u, result);
+    }
 }
 
 TEST_F(RandomGeneratorTest, GetUInt32StaysInBounds) {
-  {
-    uint32_t result = rng_->GetUInt32(5u, 10u);
-    ASSERT_LE(5u, result);
-    ASSERT_GT(10u, result);
-  }
-  {
-    uint32_t result = rng_->GetUInt32(10u);
-    ASSERT_LE(0u, result);
-    ASSERT_GT(10u, result);
-  }
+    {
+        uint32_t result = rng_->GetUInt32(5u, 10u);
+        ASSERT_LE(5u, result);
+        ASSERT_GT(10u, result);
+    }
+    {
+        uint32_t result = rng_->GetUInt32(10u);
+        ASSERT_LE(0u, result);
+        ASSERT_GT(10u, result);
+    }
 }
 
 #ifndef NDEBUG
 TEST_F(RandomGeneratorTest, GetUInt64ReversedBoundsCrashes) {
-  EXPECT_DEATH(rng_->GetUInt64(10, 5), ".*");
+    EXPECT_DEATH(rng_->GetUInt64(10, 5), ".*");
 }
 
 TEST_F(RandomGeneratorTest, GetUInt64EmptyBoundsCrashes) {
-  EXPECT_DEATH(rng_->GetUInt64(5, 5), ".*");
+    EXPECT_DEATH(rng_->GetUInt64(5, 5), ".*");
 }
 
 TEST_F(RandomGeneratorTest, GetUInt64ZeroBoundCrashes) {
-  EXPECT_DEATH(rng_->GetUInt64(0u), ".*");
+    EXPECT_DEATH(rng_->GetUInt64(0u), ".*");
 }
 #endif  // NDEBUG
 
 TEST_F(RandomGeneratorTest, GetUInt64SingularReturnsOneValue) {
-  {
-    uint64_t result = rng_->GetUInt64(5u, 6u);
-    ASSERT_EQ(5u, result);
-  }
-  {
-    uint64_t result = rng_->GetUInt64(1u);
-    ASSERT_EQ(0u, result);
-  }
+    {
+        uint64_t result = rng_->GetUInt64(5u, 6u);
+        ASSERT_EQ(5u, result);
+    }
+    {
+        uint64_t result = rng_->GetUInt64(1u);
+        ASSERT_EQ(0u, result);
+    }
 }
 
 TEST_F(RandomGeneratorTest, GetUInt64StaysInBounds) {
-  {
-    uint64_t result = rng_->GetUInt64(5u, 10u);
-    ASSERT_LE(5u, result);
-    ASSERT_GT(10u, result);
-  }
-  {
-    uint64_t result = rng_->GetUInt64(10u);
-    ASSERT_LE(0u, result);
-    ASSERT_GT(10u, result);
-  }
+    {
+        uint64_t result = rng_->GetUInt64(5u, 10u);
+        ASSERT_LE(5u, result);
+        ASSERT_GT(10u, result);
+    }
+    {
+        uint64_t result = rng_->GetUInt64(10u);
+        ASSERT_LE(0u, result);
+        ASSERT_GT(10u, result);
+    }
 }
 
 TEST_F(RandomGeneratorTest, GetByte) {
-  rng_->GetByte();
+    rng_->GetByte();
 }
 
 #ifndef NDEBUG
 TEST_F(RandomGeneratorTest, GetNBytesNullDataBufferCrashes) {
-  EXPECT_DEATH(rng_->GetNBytes(nullptr, 5), ".*");
+    EXPECT_DEATH(rng_->GetNBytes(nullptr, 5), ".*");
 }
 #endif  // NDEBUG
 
 TEST_F(RandomGeneratorTest, GetNBytes) {
-  std::vector<uint8_t> data;
-  for (uint32_t i = 25; i < 1000u; i = i + 25) {
-    data.resize(i);
-    rng_->GetNBytes(data.data(), data.size());
-  }
+    std::vector<uint8_t> data;
+    for (uint32_t i = 25; i < 1000u; i = i + 25) {
+        data.resize(i);
+        rng_->GetNBytes(data.data(), data.size());
+    }
 }
 
 TEST_F(RandomGeneratorTest, GetBool) {
-  rng_->GetBool();
+    rng_->GetBool();
 }
 
 TEST_F(RandomGeneratorTest, GetWeightedBoolZeroAlwaysFalse) {
-  ASSERT_FALSE(rng_->GetWeightedBool(0));
+    ASSERT_FALSE(rng_->GetWeightedBool(0));
 }
 
 TEST_F(RandomGeneratorTest, GetWeightedBoolHundredAlwaysTrue) {
-  ASSERT_TRUE(rng_->GetWeightedBool(100));
+    ASSERT_TRUE(rng_->GetWeightedBool(100));
 }
 
 #ifndef NDEBUG
 TEST_F(RandomGeneratorTest, GetWeightedBoolAboveHundredCrashes) {
-  EXPECT_DEATH(rng_->GetWeightedBool(101), ".*");
-  EXPECT_DEATH(rng_->GetWeightedBool(500), ".*");
+    EXPECT_DEATH(rng_->GetWeightedBool(101), ".*");
+    EXPECT_DEATH(rng_->GetWeightedBool(500), ".*");
 }
 #endif  // NDEBUG
 
 TEST_F(RandomGeneratorTest, GetWeightedBool) {
-  for (uint32_t i = 0; i <= 100; i++) {
-    rng_ =
-        std::make_unique<RandomGenerator>(std::make_unique<MonotonicEngine>());
-    for (uint32_t j = 0; j <= 100; j++) {
-      if (j < i) {
-        ASSERT_TRUE(rng_->GetWeightedBool(i));
-      } else {
-        ASSERT_FALSE(rng_->GetWeightedBool(i));
-      }
+    for (uint32_t i = 0; i <= 100; i++) {
+        rng_ = std::make_unique<RandomGenerator>(std::make_unique<MonotonicEngine>());
+        for (uint32_t j = 0; j <= 100; j++) {
+            if (j < i) {
+                ASSERT_TRUE(rng_->GetWeightedBool(i));
+            } else {
+                ASSERT_FALSE(rng_->GetWeightedBool(i));
+            }
+        }
     }
-  }
 }
 
 #ifndef NDEBUG
 TEST_F(RandomGeneratorTest, GetRandomElementEmptyVectorCrashes) {
-  std::vector<uint8_t> v;
-  EXPECT_DEATH(rng_->GetRandomElement(v), ".*");
+    std::vector<uint8_t> v;
+    EXPECT_DEATH(rng_->GetRandomElement(v), ".*");
 }
 #endif  // NDEBUG
 
 TEST_F(RandomGeneratorTest, GetRandomElement) {
-  std::vector<uint32_t> v;
-  for (uint32_t i = 25; i < 100u; i = i + 25) {
-    rng_ =
-        std::make_unique<RandomGenerator>(std::make_unique<MonotonicEngine>());
-    v.resize(i);
-    std::iota(v.begin(), v.end(), 0);
-    for (uint32_t j = 0; j < i; j++) {
-      EXPECT_EQ(j, rng_->GetRandomElement(v));
+    std::vector<uint32_t> v;
+    for (uint32_t i = 25; i < 100u; i = i + 25) {
+        rng_ = std::make_unique<RandomGenerator>(std::make_unique<MonotonicEngine>());
+        v.resize(i);
+        std::iota(v.begin(), v.end(), 0);
+        for (uint32_t j = 0; j < i; j++) {
+            EXPECT_EQ(j, rng_->GetRandomElement(v));
+        }
     }
-  }
 }
 
 }  // namespace
diff --git a/src/tint/fuzzers/shuffle_transform.cc b/src/tint/fuzzers/shuffle_transform.cc
index b2752b9..5f5f6e6 100644
--- a/src/tint/fuzzers/shuffle_transform.cc
+++ b/src/tint/fuzzers/shuffle_transform.cc
@@ -25,12 +25,12 @@
 void ShuffleTransform::Run(CloneContext& ctx,
                            const tint::transform::DataMap&,
                            tint::transform::DataMap&) const {
-  auto decls = ctx.src->AST().GlobalDeclarations();
-  auto rng = std::mt19937_64{seed_};
-  std::shuffle(std::begin(decls), std::end(decls), rng);
-  for (auto* decl : decls) {
-    ctx.dst->AST().AddGlobalDeclaration(ctx.Clone(decl));
-  }
+    auto decls = ctx.src->AST().GlobalDeclarations();
+    auto rng = std::mt19937_64{seed_};
+    std::shuffle(std::begin(decls), std::end(decls), rng);
+    for (auto* decl : decls) {
+        ctx.dst->AST().AddGlobalDeclaration(ctx.Clone(decl));
+    }
 }
 
 }  // namespace tint::fuzzers
diff --git a/src/tint/fuzzers/shuffle_transform.h b/src/tint/fuzzers/shuffle_transform.h
index 5df6bdd..0a64fe3 100644
--- a/src/tint/fuzzers/shuffle_transform.h
+++ b/src/tint/fuzzers/shuffle_transform.h
@@ -21,18 +21,18 @@
 
 /// ShuffleTransform reorders the module scope declarations into a random order
 class ShuffleTransform : public tint::transform::Transform {
- public:
-  /// Constructor
-  /// @param seed the random seed to use for the shuffling
-  explicit ShuffleTransform(size_t seed);
+  public:
+    /// Constructor
+    /// @param seed the random seed to use for the shuffling
+    explicit ShuffleTransform(size_t seed);
 
- protected:
-  void Run(CloneContext& ctx,
-           const tint::transform::DataMap&,
-           tint::transform::DataMap&) const override;
+  protected:
+    void Run(CloneContext& ctx,
+             const tint::transform::DataMap&,
+             tint::transform::DataMap&) const override;
 
- private:
-  size_t seed_;
+  private:
+    size_t seed_;
 };
 
 }  // namespace tint::fuzzers
diff --git a/src/tint/fuzzers/tint_all_transforms_fuzzer.cc b/src/tint/fuzzers/tint_all_transforms_fuzzer.cc
index d2e866f..969ae83 100644
--- a/src/tint/fuzzers/tint_all_transforms_fuzzer.cc
+++ b/src/tint/fuzzers/tint_all_transforms_fuzzer.cc
@@ -20,64 +20,64 @@
 namespace tint::fuzzers {
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  {
-    TransformBuilder tb(data, size);
-    tb.AddTransform<ShuffleTransform>();
-    tb.AddPlatformIndependentPasses();
+    {
+        TransformBuilder tb(data, size);
+        tb.AddTransform<ShuffleTransform>();
+        tb.AddPlatformIndependentPasses();
 
-    fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kSpv);
-    fuzzer.SetTransformManager(tb.manager(), tb.data_map());
-    fuzzer.SetDumpInput(GetCliParams().dump_input);
-    fuzzer.SetEnforceValidity(GetCliParams().enforce_validity);
+        fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kSpv);
+        fuzzer.SetTransformManager(tb.manager(), tb.data_map());
+        fuzzer.SetDumpInput(GetCliParams().dump_input);
+        fuzzer.SetEnforceValidity(GetCliParams().enforce_validity);
 
-    fuzzer.Run(data, size);
-  }
+        fuzzer.Run(data, size);
+    }
 
 #if TINT_BUILD_HLSL_WRITER
-  {
-    TransformBuilder tb(data, size);
-    tb.AddTransform<ShuffleTransform>();
-    tb.AddPlatformIndependentPasses();
+    {
+        TransformBuilder tb(data, size);
+        tb.AddTransform<ShuffleTransform>();
+        tb.AddPlatformIndependentPasses();
 
-    fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kHLSL);
-    fuzzer.SetTransformManager(tb.manager(), tb.data_map());
-    fuzzer.SetDumpInput(GetCliParams().dump_input);
-    fuzzer.SetEnforceValidity(GetCliParams().enforce_validity);
+        fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kHLSL);
+        fuzzer.SetTransformManager(tb.manager(), tb.data_map());
+        fuzzer.SetDumpInput(GetCliParams().dump_input);
+        fuzzer.SetEnforceValidity(GetCliParams().enforce_validity);
 
-    fuzzer.Run(data, size);
-  }
+        fuzzer.Run(data, size);
+    }
 #endif  // TINT_BUILD_HLSL_WRITER
 
 #if TINT_BUILD_MSL_WRITER
-  {
-    TransformBuilder tb(data, size);
-    tb.AddTransform<ShuffleTransform>();
-    tb.AddPlatformIndependentPasses();
+    {
+        TransformBuilder tb(data, size);
+        tb.AddTransform<ShuffleTransform>();
+        tb.AddPlatformIndependentPasses();
 
-    fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kMSL);
-    fuzzer.SetTransformManager(tb.manager(), tb.data_map());
-    fuzzer.SetDumpInput(GetCliParams().dump_input);
-    fuzzer.SetEnforceValidity(GetCliParams().enforce_validity);
+        fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kMSL);
+        fuzzer.SetTransformManager(tb.manager(), tb.data_map());
+        fuzzer.SetDumpInput(GetCliParams().dump_input);
+        fuzzer.SetEnforceValidity(GetCliParams().enforce_validity);
 
-    fuzzer.Run(data, size);
-  }
+        fuzzer.Run(data, size);
+    }
 #endif  // TINT_BUILD_MSL_WRITER
 #if TINT_BUILD_SPV_WRITER
-  {
-    TransformBuilder tb(data, size);
-    tb.AddTransform<ShuffleTransform>();
-    tb.AddPlatformIndependentPasses();
+    {
+        TransformBuilder tb(data, size);
+        tb.AddTransform<ShuffleTransform>();
+        tb.AddPlatformIndependentPasses();
 
-    fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kSpv);
-    fuzzer.SetTransformManager(tb.manager(), tb.data_map());
-    fuzzer.SetDumpInput(GetCliParams().dump_input);
-    fuzzer.SetEnforceValidity(GetCliParams().enforce_validity);
+        fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kSpv);
+        fuzzer.SetTransformManager(tb.manager(), tb.data_map());
+        fuzzer.SetDumpInput(GetCliParams().dump_input);
+        fuzzer.SetEnforceValidity(GetCliParams().enforce_validity);
 
-    fuzzer.Run(data, size);
-  }
+        fuzzer.Run(data, size);
+    }
 #endif  // TINT_BUILD_SPV_WRITER
 
-  return 0;
+    return 0;
 }
 
 }  // namespace tint::fuzzers
diff --git a/src/tint/fuzzers/tint_ast_clone_fuzzer.cc b/src/tint/fuzzers/tint_ast_clone_fuzzer.cc
index 5382f24..33db8e2 100644
--- a/src/tint/fuzzers/tint_ast_clone_fuzzer.cc
+++ b/src/tint/fuzzers/tint_ast_clone_fuzzer.cc
@@ -19,98 +19,96 @@
 #include "src/tint/reader/wgsl/parser_impl.h"
 #include "src/tint/writer/wgsl/generator.h"
 
-#define ASSERT_EQ(A, B)                                  \
-  do {                                                   \
-    decltype(A) assert_a = (A);                          \
-    decltype(B) assert_b = (B);                          \
-    if (assert_a != assert_b) {                          \
-      std::cerr << "ASSERT_EQ(" #A ", " #B ") failed:\n" \
-                << #A << " was: " << assert_a << "\n"    \
-                << #B << " was: " << assert_b << "\n";   \
-      __builtin_trap();                                  \
-    }                                                    \
-  } while (false)
+#define ASSERT_EQ(A, B)                                        \
+    do {                                                       \
+        decltype(A) assert_a = (A);                            \
+        decltype(B) assert_b = (B);                            \
+        if (assert_a != assert_b) {                            \
+            std::cerr << "ASSERT_EQ(" #A ", " #B ") failed:\n" \
+                      << #A << " was: " << assert_a << "\n"    \
+                      << #B << " was: " << assert_b << "\n";   \
+            __builtin_trap();                                  \
+        }                                                      \
+    } while (false)
 
-#define ASSERT_TRUE(A)                                 \
-  do {                                                 \
-    decltype(A) assert_a = (A);                        \
-    if (!assert_a) {                                   \
-      std::cerr << "ASSERT_TRUE(" #A ") failed:\n"     \
-                << #A << " was: " << assert_a << "\n"; \
-      __builtin_trap();                                \
-    }                                                  \
-  } while (false)
+#define ASSERT_TRUE(A)                                                                          \
+    do {                                                                                        \
+        decltype(A) assert_a = (A);                                                             \
+        if (!assert_a) {                                                                        \
+            std::cerr << "ASSERT_TRUE(" #A ") failed:\n" << #A << " was: " << assert_a << "\n"; \
+            __builtin_trap();                                                                   \
+        }                                                                                       \
+    } while (false)
 
-[[noreturn]] void TintInternalCompilerErrorReporter(
-    const tint::diag::List& diagnostics) {
-  auto printer = tint::diag::Printer::create(stderr, true);
-  tint::diag::Formatter{}.format(diagnostics, printer.get());
-  __builtin_trap();
+[[noreturn]] void TintInternalCompilerErrorReporter(const tint::diag::List& diagnostics) {
+    auto printer = tint::diag::Printer::create(stderr, true);
+    tint::diag::Formatter{}.format(diagnostics, printer.get());
+    __builtin_trap();
 }
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  std::string str(reinterpret_cast<const char*>(data), size);
+    std::string str(reinterpret_cast<const char*>(data), size);
 
-  tint::SetInternalCompilerErrorReporter(&TintInternalCompilerErrorReporter);
+    tint::SetInternalCompilerErrorReporter(&TintInternalCompilerErrorReporter);
 
-  tint::Source::File file("test.wgsl", str);
+    tint::Source::File file("test.wgsl", str);
 
-  // Parse the wgsl, create the src program
-  tint::reader::wgsl::ParserImpl parser(&file);
-  parser.set_max_errors(1);
-  if (!parser.Parse()) {
-    return 0;
-  }
-  auto src = parser.program();
-  if (!src.IsValid()) {
-    return 0;
-  }
+    // Parse the wgsl, create the src program
+    tint::reader::wgsl::ParserImpl parser(&file);
+    parser.set_max_errors(1);
+    if (!parser.Parse()) {
+        return 0;
+    }
+    auto src = parser.program();
+    if (!src.IsValid()) {
+        return 0;
+    }
 
-  // Clone the src program to dst
-  tint::Program dst(src.Clone());
+    // Clone the src program to dst
+    tint::Program dst(src.Clone());
 
-  // Expect the printed strings to match
-  ASSERT_EQ(tint::Program::printer(&src), tint::Program::printer(&dst));
+    // Expect the printed strings to match
+    ASSERT_EQ(tint::Program::printer(&src), tint::Program::printer(&dst));
 
-  // Check that none of the AST nodes or type pointers in dst are found in src
-  std::unordered_set<const tint::ast::Node*> src_nodes;
-  for (auto* src_node : src.ASTNodes().Objects()) {
-    src_nodes.emplace(src_node);
-  }
-  std::unordered_set<const tint::sem::Type*> src_types;
-  for (auto* src_type : src.Types()) {
-    src_types.emplace(src_type);
-  }
-  for (auto* dst_node : dst.ASTNodes().Objects()) {
-    ASSERT_EQ(src_nodes.count(dst_node), 0u);
-  }
-  for (auto* dst_type : dst.Types()) {
-    ASSERT_EQ(src_types.count(dst_type), 0u);
-  }
+    // Check that none of the AST nodes or type pointers in dst are found in src
+    std::unordered_set<const tint::ast::Node*> src_nodes;
+    for (auto* src_node : src.ASTNodes().Objects()) {
+        src_nodes.emplace(src_node);
+    }
+    std::unordered_set<const tint::sem::Type*> src_types;
+    for (auto* src_type : src.Types()) {
+        src_types.emplace(src_type);
+    }
+    for (auto* dst_node : dst.ASTNodes().Objects()) {
+        ASSERT_EQ(src_nodes.count(dst_node), 0u);
+    }
+    for (auto* dst_type : dst.Types()) {
+        ASSERT_EQ(src_types.count(dst_type), 0u);
+    }
 
-  // Regenerate the wgsl for the src program. We use this instead of the
-  // original source so that reformatting doesn't impact the final wgsl
-  // comparison.
-  std::string src_wgsl;
-  tint::writer::wgsl::Options wgsl_options;
-  {
-    auto result = tint::writer::wgsl::Generate(&src, wgsl_options);
+    // Regenerate the wgsl for the src program. We use this instead of the
+    // original source so that reformatting doesn't impact the final wgsl
+    // comparison.
+    std::string src_wgsl;
+    tint::writer::wgsl::Options wgsl_options;
+    {
+        auto result = tint::writer::wgsl::Generate(&src, wgsl_options);
+        ASSERT_TRUE(result.success);
+        src_wgsl = result.wgsl;
+
+        // Move the src program to a temporary that'll be dropped, so that the src
+        // program is released before we attempt to print the dst program. This
+        // guarantee that all the source program nodes and types are destructed and
+        // freed. ASAN should error if there's any remaining references in dst when
+        // we try to reconstruct the WGSL.
+        auto tmp = std::move(src);
+    }
+
+    // Print the dst program, check it matches the original source
+    auto result = tint::writer::wgsl::Generate(&dst, wgsl_options);
     ASSERT_TRUE(result.success);
-    src_wgsl = result.wgsl;
+    auto dst_wgsl = result.wgsl;
+    ASSERT_EQ(src_wgsl, dst_wgsl);
 
-    // Move the src program to a temporary that'll be dropped, so that the src
-    // program is released before we attempt to print the dst program. This
-    // guarantee that all the source program nodes and types are destructed and
-    // freed. ASAN should error if there's any remaining references in dst when
-    // we try to reconstruct the WGSL.
-    auto tmp = std::move(src);
-  }
-
-  // Print the dst program, check it matches the original source
-  auto result = tint::writer::wgsl::Generate(&dst, wgsl_options);
-  ASSERT_TRUE(result.success);
-  auto dst_wgsl = result.wgsl;
-  ASSERT_EQ(src_wgsl, dst_wgsl);
-
-  return 0;
+    return 0;
 }
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/BUILD.gn b/src/tint/fuzzers/tint_ast_fuzzer/BUILD.gn
index 4c63bab..69ef3fe 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/BUILD.gn
+++ b/src/tint/fuzzers/tint_ast_fuzzer/BUILD.gn
@@ -17,11 +17,13 @@
 
 if (build_with_chromium) {
   import("//third_party/protobuf/proto_library.gni")
+  import("../../../../scripts/dawn_overrides_with_defaults.gni")
 
   proto_library("tint_ast_fuzzer_proto") {
     sources = [ "protobufs/tint_ast_fuzzer.proto" ]
     generate_python = false
     use_protobuf_full = true
+    deps = [ "${dawn_root}/generator:remove_stale_autogen_files" ]
   }
 
   source_set("tint_ast_fuzzer") {
@@ -50,12 +52,16 @@
       "mutation_finder.h",
       "mutation_finders/change_binary_operators.cc",
       "mutation_finders/change_binary_operators.h",
+      "mutation_finders/change_unary_operators.cc",
+      "mutation_finders/change_unary_operators.h",
       "mutation_finders/replace_identifiers.cc",
       "mutation_finders/replace_identifiers.h",
       "mutation_finders/wrap_unary_operators.cc",
       "mutation_finders/wrap_unary_operators.h",
       "mutations/change_binary_operator.cc",
       "mutations/change_binary_operator.h",
+      "mutations/change_unary_operator.cc",
+      "mutations/change_unary_operator.h",
       "mutations/replace_identifier.cc",
       "mutations/replace_identifier.h",
       "mutations/wrap_unary_operator.cc",
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/CMakeLists.txt b/src/tint/fuzzers/tint_ast_fuzzer/CMakeLists.txt
index 1a45897..5bd8c50 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/CMakeLists.txt
+++ b/src/tint/fuzzers/tint_ast_fuzzer/CMakeLists.txt
@@ -42,9 +42,11 @@
         mutation.h
         mutation_finder.h
         mutation_finders/change_binary_operators.h
+        mutation_finders/change_unary_operators.h
         mutation_finders/replace_identifiers.h
         mutation_finders/wrap_unary_operators.h
         mutations/change_binary_operator.h
+        mutations/change_unary_operator.h
         mutations/replace_identifier.h
         mutations/wrap_unary_operator.h
         mutator.h
@@ -62,9 +64,11 @@
         mutation.cc
         mutation_finder.cc
         mutation_finders/change_binary_operators.cc
+        mutation_finders/change_unary_operators.cc
         mutation_finders/replace_identifiers.cc
         mutation_finders/wrap_unary_operators.cc
         mutations/change_binary_operator.cc
+        mutations/change_unary_operator.cc
         mutations/replace_identifier.cc
         mutations/wrap_unary_operator.cc
         mutator.cc
@@ -104,8 +108,9 @@
     set(TEST_SOURCES
             expression_size_test.cc
             mutations/change_binary_operator_test.cc
+            mutations/change_unary_operator_test.cc
             mutations/replace_identifier_test.cc
-	        mutations/wrap_unary_operator_test.cc)
+            mutations/wrap_unary_operator_test.cc)
 
     add_executable(tint_ast_fuzzer_unittests ${TEST_SOURCES})
 
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/cli.cc b/src/tint/fuzzers/tint_ast_fuzzer/cli.cc
index ace19d6..f01ca83 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/cli.cc
+++ b/src/tint/fuzzers/tint_ast_fuzzer/cli.cc
@@ -53,111 +53,111 @@
 )";
 
 bool HasPrefix(const char* str, const char* prefix) {
-  return strncmp(str, prefix, strlen(prefix)) == 0;
+    return strncmp(str, prefix, strlen(prefix)) == 0;
 }
 
 [[noreturn]] void InvalidParam(const char* param) {
-  std::cout << "Invalid value for " << param << std::endl;
-  std::cout << kHelpMessage << std::endl;
-  exit(1);
+    std::cout << "Invalid value for " << param << std::endl;
+    std::cout << kHelpMessage << std::endl;
+    exit(1);
 }
 
 bool ParseBool(const char* value, bool* out) {
-  if (!strcmp(value, "true")) {
-    *out = true;
-  } else if (!strcmp(value, "false")) {
-    *out = false;
-  } else {
-    return false;
-  }
-  return true;
+    if (!strcmp(value, "true")) {
+        *out = true;
+    } else if (!strcmp(value, "false")) {
+        *out = false;
+    } else {
+        return false;
+    }
+    return true;
 }
 
 bool ParseUint32(const char* value, uint32_t* out) {
-  auto parsed = strtoul(value, nullptr, 10);
-  if (parsed > std::numeric_limits<uint32_t>::max()) {
-    return false;
-  }
-  *out = static_cast<uint32_t>(parsed);
-  return true;
+    auto parsed = strtoul(value, nullptr, 10);
+    if (parsed > std::numeric_limits<uint32_t>::max()) {
+        return false;
+    }
+    *out = static_cast<uint32_t>(parsed);
+    return true;
 }
 
 bool ParseFuzzingTarget(const char* value, FuzzingTarget* out) {
-  if (!strcmp(value, "wgsl")) {
-    *out = FuzzingTarget::kWgsl;
-  } else if (!strcmp(value, "spv")) {
-    *out = FuzzingTarget::kSpv;
-  } else if (!strcmp(value, "msl")) {
-    *out = FuzzingTarget::kMsl;
-  } else if (!strcmp(value, "hlsl")) {
-    *out = FuzzingTarget::kHlsl;
-  } else {
-    return false;
-  }
-  return true;
+    if (!strcmp(value, "wgsl")) {
+        *out = FuzzingTarget::kWgsl;
+    } else if (!strcmp(value, "spv")) {
+        *out = FuzzingTarget::kSpv;
+    } else if (!strcmp(value, "msl")) {
+        *out = FuzzingTarget::kMsl;
+    } else if (!strcmp(value, "hlsl")) {
+        *out = FuzzingTarget::kHlsl;
+    } else {
+        return false;
+    }
+    return true;
 }
 
 }  // namespace
 
 CliParams ParseCliParams(int* argc, char** argv) {
-  CliParams cli_params;
-  auto help = false;
+    CliParams cli_params;
+    auto help = false;
 
-  for (int i = *argc - 1; i > 0; --i) {
-    auto param = argv[i];
-    auto recognized_parameter = true;
+    for (int i = *argc - 1; i > 0; --i) {
+        auto param = argv[i];
+        auto recognized_parameter = true;
 
-    if (HasPrefix(param, "-tint_enable_all_mutations=")) {
-      if (!ParseBool(param + sizeof("-tint_enable_all_mutations=") - 1,
-                     &cli_params.enable_all_mutations)) {
-        InvalidParam(param);
-      }
-    } else if (HasPrefix(param, "-tint_mutation_batch_size=")) {
-      if (!ParseUint32(param + sizeof("-tint_mutation_batch_size=") - 1,
-                       &cli_params.mutation_batch_size)) {
-        InvalidParam(param);
-      }
-    } else if (HasPrefix(param, "-tint_fuzzing_target=")) {
-      auto result = FuzzingTarget::kNone;
+        if (HasPrefix(param, "-tint_enable_all_mutations=")) {
+            if (!ParseBool(param + sizeof("-tint_enable_all_mutations=") - 1,
+                           &cli_params.enable_all_mutations)) {
+                InvalidParam(param);
+            }
+        } else if (HasPrefix(param, "-tint_mutation_batch_size=")) {
+            if (!ParseUint32(param + sizeof("-tint_mutation_batch_size=") - 1,
+                             &cli_params.mutation_batch_size)) {
+                InvalidParam(param);
+            }
+        } else if (HasPrefix(param, "-tint_fuzzing_target=")) {
+            auto result = FuzzingTarget::kNone;
 
-      std::stringstream ss(param + sizeof("-tint_fuzzing_target=") - 1);
-      for (std::string value; std::getline(ss, value, ',');) {
-        auto tmp = FuzzingTarget::kNone;
-        if (!ParseFuzzingTarget(value.c_str(), &tmp)) {
-          InvalidParam(param);
+            std::stringstream ss(param + sizeof("-tint_fuzzing_target=") - 1);
+            for (std::string value; std::getline(ss, value, ',');) {
+                auto tmp = FuzzingTarget::kNone;
+                if (!ParseFuzzingTarget(value.c_str(), &tmp)) {
+                    InvalidParam(param);
+                }
+                result = result | tmp;
+            }
+
+            if (result == FuzzingTarget::kNone) {
+                InvalidParam(param);
+            }
+
+            cli_params.fuzzing_target = result;
+        } else if (!strcmp(param, "-tint_help")) {
+            help = true;
+        } else {
+            recognized_parameter = false;
         }
-        result = result | tmp;
-      }
 
-      if (result == FuzzingTarget::kNone) {
-        InvalidParam(param);
-      }
-
-      cli_params.fuzzing_target = result;
-    } else if (!strcmp(param, "-tint_help")) {
-      help = true;
-    } else {
-      recognized_parameter = false;
+        if (recognized_parameter) {
+            // Remove the recognized parameter from the list of all parameters by
+            // swapping it with the last one. This will suppress warnings in the
+            // libFuzzer about unrecognized parameters. By default, libFuzzer thinks
+            // that all user-defined parameters start with two dashes. However, we are
+            // forced to use a single one to make the fuzzer compatible with the
+            // ClusterFuzz.
+            std::swap(argv[i], argv[*argc - 1]);
+            *argc -= 1;
+        }
     }
 
-    if (recognized_parameter) {
-      // Remove the recognized parameter from the list of all parameters by
-      // swapping it with the last one. This will suppress warnings in the
-      // libFuzzer about unrecognized parameters. By default, libFuzzer thinks
-      // that all user-defined parameters start with two dashes. However, we are
-      // forced to use a single one to make the fuzzer compatible with the
-      // ClusterFuzz.
-      std::swap(argv[i], argv[*argc - 1]);
-      *argc -= 1;
+    if (help) {
+        std::cout << kHelpMessage << std::endl;
+        exit(0);
     }
-  }
 
-  if (help) {
-    std::cout << kHelpMessage << std::endl;
-    exit(0);
-  }
-
-  return cli_params;
+    return cli_params;
 }
 
 }  // namespace tint::fuzzers::ast_fuzzer
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/cli.h b/src/tint/fuzzers/tint_ast_fuzzer/cli.h
index ccdf2f2..088e0ad 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/cli.h
+++ b/src/tint/fuzzers/tint_ast_fuzzer/cli.h
@@ -21,35 +21,35 @@
 
 /// The backend this fuzzer will test.
 enum class FuzzingTarget {
-  kNone = 0,
-  kHlsl = 1 << 0,
-  kMsl = 1 << 1,
-  kSpv = 1 << 2,
-  kWgsl = 1 << 3,
-  kAll = kHlsl | kMsl | kSpv | kWgsl
+    kNone = 0,
+    kHlsl = 1 << 0,
+    kMsl = 1 << 1,
+    kSpv = 1 << 2,
+    kWgsl = 1 << 3,
+    kAll = kHlsl | kMsl | kSpv | kWgsl
 };
 
 inline FuzzingTarget operator|(FuzzingTarget a, FuzzingTarget b) {
-  return static_cast<FuzzingTarget>(static_cast<int>(a) | static_cast<int>(b));
+    return static_cast<FuzzingTarget>(static_cast<int>(a) | static_cast<int>(b));
 }
 
 inline FuzzingTarget operator&(FuzzingTarget a, FuzzingTarget b) {
-  return static_cast<FuzzingTarget>(static_cast<int>(a) & static_cast<int>(b));
+    return static_cast<FuzzingTarget>(static_cast<int>(a) & static_cast<int>(b));
 }
 
 /// CLI parameters accepted by the fuzzer. Type -tint_help in the CLI to see the
 /// help message
 struct CliParams {
-  /// Whether to use all mutation finders or only a randomly selected subset of
-  /// them.
-  bool enable_all_mutations = false;
+    /// Whether to use all mutation finders or only a randomly selected subset of
+    /// them.
+    bool enable_all_mutations = false;
 
-  /// The maximum number of mutations applied during a single mutation session
-  /// (i.e. a call to `ast_fuzzer::Mutate` function).
-  uint32_t mutation_batch_size = 5;
+    /// The maximum number of mutations applied during a single mutation session
+    /// (i.e. a call to `ast_fuzzer::Mutate` function).
+    uint32_t mutation_batch_size = 5;
 
-  /// Compiler backends we want to fuzz.
-  FuzzingTarget fuzzing_target = FuzzingTarget::kAll;
+    /// Compiler backends we want to fuzz.
+    FuzzingTarget fuzzing_target = FuzzingTarget::kAll;
 };
 
 /// @brief Parses CLI parameters.
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/expression_size.cc b/src/tint/fuzzers/tint_ast_fuzzer/expression_size.cc
index fe4a5c4..f6f893f 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/expression_size.cc
+++ b/src/tint/fuzzers/tint_ast_fuzzer/expression_size.cc
@@ -19,28 +19,27 @@
 namespace tint::fuzzers::ast_fuzzer {
 
 ExpressionSize::ExpressionSize(const Program& program) {
-  // By construction, all the children of an AST node are encountered before the
-  // node itself when iterating through a program's AST nodes. Computing
-  // expression sizes exploits this property: the size of a compound expression
-  // is computed based on the already-computed sizes of its sub-expressions.
-  for (const auto* node : program.ASTNodes().Objects()) {
-    const auto* expr_ast_node = node->As<ast::Expression>();
-    if (expr_ast_node == nullptr) {
-      continue;
+    // By construction, all the children of an AST node are encountered before the
+    // node itself when iterating through a program's AST nodes. Computing
+    // expression sizes exploits this property: the size of a compound expression
+    // is computed based on the already-computed sizes of its sub-expressions.
+    for (const auto* node : program.ASTNodes().Objects()) {
+        const auto* expr_ast_node = node->As<ast::Expression>();
+        if (expr_ast_node == nullptr) {
+            continue;
+        }
+        size_t expr_size = 0;
+        diag::List empty;
+        ast::TraverseExpressions(expr_ast_node, empty, [&](const ast::Expression* expression) {
+            if (expression == expr_ast_node) {
+                expr_size++;
+                return ast::TraverseAction::Descend;
+            }
+            expr_size += expr_to_size_.at(expression);
+            return ast::TraverseAction::Skip;
+        });
+        expr_to_size_[expr_ast_node] = expr_size;
     }
-    size_t expr_size = 0;
-    diag::List empty;
-    ast::TraverseExpressions(expr_ast_node, empty,
-                             [&](const ast::Expression* expression) {
-                               if (expression == expr_ast_node) {
-                                 expr_size++;
-                                 return ast::TraverseAction::Descend;
-                               }
-                               expr_size += expr_to_size_.at(expression);
-                               return ast::TraverseAction::Skip;
-                             });
-    expr_to_size_[expr_ast_node] = expr_size;
-  }
 }
 
 }  // namespace tint::fuzzers::ast_fuzzer
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/expression_size.h b/src/tint/fuzzers/tint_ast_fuzzer/expression_size.h
index 5a6d3dd..e03e692 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/expression_size.h
+++ b/src/tint/fuzzers/tint_ast_fuzzer/expression_size.h
@@ -25,21 +25,21 @@
 /// This class computes the size of the subtree rooted at each expression in a
 /// program, and allows these sizes to be subsequently queried.
 class ExpressionSize {
- public:
-  /// Initializes expression size information for the given program.
-  /// @param program - the program for which expression sizes will be computed;
-  ///     must remain in scope as long as this instance exists.
-  explicit ExpressionSize(const Program& program);
+  public:
+    /// Initializes expression size information for the given program.
+    /// @param program - the program for which expression sizes will be computed;
+    ///     must remain in scope as long as this instance exists.
+    explicit ExpressionSize(const Program& program);
 
-  /// Returns the size of the subtree rooted at the given expression.
-  /// @param expression - the expression whose size should be returned.
-  /// @return the size of the subtree rooted at `expression`.
-  size_t operator()(const ast::Expression* expression) const {
-    return expr_to_size_.at(expression);
-  }
+    /// Returns the size of the subtree rooted at the given expression.
+    /// @param expression - the expression whose size should be returned.
+    /// @return the size of the subtree rooted at `expression`.
+    size_t operator()(const ast::Expression* expression) const {
+        return expr_to_size_.at(expression);
+    }
 
- private:
-  std::unordered_map<const ast::Expression*, size_t> expr_to_size_;
+  private:
+    std::unordered_map<const ast::Expression*, size_t> expr_to_size_;
 };
 
 }  // namespace tint::fuzzers::ast_fuzzer
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/expression_size_test.cc b/src/tint/fuzzers/tint_ast_fuzzer/expression_size_test.cc
index b5118d9..ce0a189 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/expression_size_test.cc
+++ b/src/tint/fuzzers/tint_ast_fuzzer/expression_size_test.cc
@@ -28,38 +28,38 @@
 namespace {
 
 TEST(ExpressionSizeTest, Basic) {
-  std::string content = R"(
+    std::string content = R"(
     fn main() {
       let a = (0 + 0) * (0 + 0);
     }
   )";
-  Source::File file("test.wgsl", content);
-  auto program = reader::wgsl::Parse(&file);
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    Source::File file("test.wgsl", content);
+    auto program = reader::wgsl::Parse(&file);
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  ExpressionSize expression_size(program);
-  for (const auto* node : program.ASTNodes().Objects()) {
-    const auto* expr = node->As<ast::Expression>();
-    if (expr == nullptr) {
-      continue;
+    ExpressionSize expression_size(program);
+    for (const auto* node : program.ASTNodes().Objects()) {
+        const auto* expr = node->As<ast::Expression>();
+        if (expr == nullptr) {
+            continue;
+        }
+        if (expr->Is<ast::IntLiteralExpression>()) {
+            ASSERT_EQ(1, expression_size(expr));
+        } else {
+            const auto* binary_expr = expr->As<ast::BinaryExpression>();
+            ASSERT_TRUE(binary_expr != nullptr);
+            switch (binary_expr->op) {
+                case ast::BinaryOp::kAdd:
+                    ASSERT_EQ(3, expression_size(expr));
+                    break;
+                case ast::BinaryOp::kMultiply:
+                    ASSERT_EQ(7, expression_size(expr));
+                    break;
+                default:
+                    FAIL();
+            }
+        }
     }
-    if (expr->Is<ast::IntLiteralExpression>()) {
-      ASSERT_EQ(1, expression_size(expr));
-    } else {
-      const auto* binary_expr = expr->As<ast::BinaryExpression>();
-      ASSERT_TRUE(binary_expr != nullptr);
-      switch (binary_expr->op) {
-        case ast::BinaryOp::kAdd:
-          ASSERT_EQ(3, expression_size(expr));
-          break;
-        case ast::BinaryOp::kMultiply:
-          ASSERT_EQ(7, expression_size(expr));
-          break;
-        default:
-          FAIL();
-      }
-    }
-  }
 }
 
 }  // namespace
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/fuzzer.cc b/src/tint/fuzzers/tint_ast_fuzzer/fuzzer.cc
index e2561da..20601df 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/fuzzer.cc
+++ b/src/tint/fuzzers/tint_ast_fuzzer/fuzzer.cc
@@ -31,99 +31,96 @@
 CliParams cli_params{};
 
 extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) {
-  // Parse CLI parameters. `ParseCliParams` will call `exit` if some parameter
-  // is invalid.
-  cli_params = ParseCliParams(argc, *argv);
-  // For some fuzz targets it is desirable to force the values of certain CLI
-  // parameters after parsing.
-  OverrideCliParams(cli_params);
-  return 0;
+    // Parse CLI parameters. `ParseCliParams` will call `exit` if some parameter
+    // is invalid.
+    cli_params = ParseCliParams(argc, *argv);
+    // For some fuzz targets it is desirable to force the values of certain CLI
+    // parameters after parsing.
+    OverrideCliParams(cli_params);
+    return 0;
 }
 
 extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data,
                                           size_t size,
                                           size_t max_size,
                                           unsigned seed) {
-  Source::File file("test.wgsl", {reinterpret_cast<char*>(data), size});
-  auto program = reader::wgsl::Parse(&file);
-  if (!program.IsValid()) {
-    std::cout << "Trying to mutate an invalid program:" << std::endl
-              << program.Diagnostics().str() << std::endl;
-    return 0;
-  }
+    Source::File file("test.wgsl", {reinterpret_cast<char*>(data), size});
+    auto program = reader::wgsl::Parse(&file);
+    if (!program.IsValid()) {
+        std::cout << "Trying to mutate an invalid program:" << std::endl
+                  << program.Diagnostics().str() << std::endl;
+        return 0;
+    }
 
-  // Run the mutator.
-  RandomGenerator generator(seed);
-  ProbabilityContext probability_context(&generator);
-  program = Mutate(std::move(program), &probability_context,
-                   cli_params.enable_all_mutations,
-                   cli_params.mutation_batch_size, nullptr);
+    // Run the mutator.
+    RandomGenerator generator(seed);
+    ProbabilityContext probability_context(&generator);
+    program = Mutate(std::move(program), &probability_context, cli_params.enable_all_mutations,
+                     cli_params.mutation_batch_size, nullptr);
 
-  if (!program.IsValid()) {
-    std::cout << "Mutator produced invalid WGSL:" << std::endl
-              << "  seed: " << seed << std::endl
-              << program.Diagnostics().str() << std::endl;
-    return 0;
-  }
+    if (!program.IsValid()) {
+        std::cout << "Mutator produced invalid WGSL:" << std::endl
+                  << "  seed: " << seed << std::endl
+                  << program.Diagnostics().str() << std::endl;
+        return 0;
+    }
 
-  auto result = writer::wgsl::Generate(&program, writer::wgsl::Options());
-  if (!result.success) {
-    std::cout << "Can't generate WGSL for a valid tint::Program:" << std::endl
-              << result.error << std::endl;
-    return 0;
-  }
+    auto result = writer::wgsl::Generate(&program, writer::wgsl::Options());
+    if (!result.success) {
+        std::cout << "Can't generate WGSL for a valid tint::Program:" << std::endl
+                  << result.error << std::endl;
+        return 0;
+    }
 
-  if (result.wgsl.size() > max_size) {
-    return 0;
-  }
+    if (result.wgsl.size() > max_size) {
+        return 0;
+    }
 
-  // No need to worry about the \0 here. The reason is that if \0 is included by
-  // developer by mistake, it will be considered a part of the string and will
-  // cause all sorts of strange bugs. Thus, unless `data` below is used as a raw
-  // C string, the \0 symbol should be ignored.
-  std::memcpy(  // NOLINT - clang-tidy warns about lack of null termination.
-      data, result.wgsl.data(), result.wgsl.size());
-  return result.wgsl.size();
+    // No need to worry about the \0 here. The reason is that if \0 is included by
+    // developer by mistake, it will be considered a part of the string and will
+    // cause all sorts of strange bugs. Thus, unless `data` below is used as a raw
+    // C string, the \0 symbol should be ignored.
+    std::memcpy(  // NOLINT - clang-tidy warns about lack of null termination.
+        data, result.wgsl.data(), result.wgsl.size());
+    return result.wgsl.size();
 }
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  if (size == 0) {
+    if (size == 0) {
+        return 0;
+    }
+
+    struct Target {
+        FuzzingTarget fuzzing_target;
+        OutputFormat output_format;
+        const char* name;
+    };
+
+    Target targets[] = {{FuzzingTarget::kWgsl, OutputFormat::kWGSL, "WGSL"},
+                        {FuzzingTarget::kHlsl, OutputFormat::kHLSL, "HLSL"},
+                        {FuzzingTarget::kMsl, OutputFormat::kMSL, "MSL"},
+                        {FuzzingTarget::kSpv, OutputFormat::kSpv, "SPV"}};
+
+    for (auto target : targets) {
+        if ((target.fuzzing_target & cli_params.fuzzing_target) != target.fuzzing_target) {
+            continue;
+        }
+
+        TransformBuilder tb(data, size);
+        tb.AddTransform<tint::transform::Robustness>();
+
+        CommonFuzzer fuzzer(InputFormat::kWGSL, target.output_format);
+        fuzzer.SetTransformManager(tb.manager(), tb.data_map());
+
+        fuzzer.Run(data, size);
+        if (fuzzer.HasErrors()) {
+            std::cout << "Fuzzing " << target.name << " produced an error" << std::endl;
+            auto printer = tint::diag::Printer::create(stderr, true);
+            tint::diag::Formatter{}.format(fuzzer.Diagnostics(), printer.get());
+        }
+    }
+
     return 0;
-  }
-
-  struct Target {
-    FuzzingTarget fuzzing_target;
-    OutputFormat output_format;
-    const char* name;
-  };
-
-  Target targets[] = {{FuzzingTarget::kWgsl, OutputFormat::kWGSL, "WGSL"},
-                      {FuzzingTarget::kHlsl, OutputFormat::kHLSL, "HLSL"},
-                      {FuzzingTarget::kMsl, OutputFormat::kMSL, "MSL"},
-                      {FuzzingTarget::kSpv, OutputFormat::kSpv, "SPV"}};
-
-  for (auto target : targets) {
-    if ((target.fuzzing_target & cli_params.fuzzing_target) !=
-        target.fuzzing_target) {
-      continue;
-    }
-
-    TransformBuilder tb(data, size);
-    tb.AddTransform<tint::transform::Robustness>();
-
-    CommonFuzzer fuzzer(InputFormat::kWGSL, target.output_format);
-    fuzzer.SetTransformManager(tb.manager(), tb.data_map());
-
-    fuzzer.Run(data, size);
-    if (fuzzer.HasErrors()) {
-      std::cout << "Fuzzing " << target.name << " produced an error"
-                << std::endl;
-      auto printer = tint::diag::Printer::create(stderr, true);
-      tint::diag::Formatter{}.format(fuzzer.Diagnostics(), printer.get());
-    }
-  }
-
-  return 0;
 }
 
 }  // namespace
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/mutation.cc b/src/tint/fuzzers/tint_ast_fuzzer/mutation.cc
index 1ea3948..6f60fc3 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/mutation.cc
+++ b/src/tint/fuzzers/tint_ast_fuzzer/mutation.cc
@@ -17,6 +17,7 @@
 #include <cassert>
 
 #include "src/tint/fuzzers/tint_ast_fuzzer/mutations/change_binary_operator.h"
+#include "src/tint/fuzzers/tint_ast_fuzzer/mutations/change_unary_operator.h"
 #include "src/tint/fuzzers/tint_ast_fuzzer/mutations/replace_identifier.h"
 #include "src/tint/fuzzers/tint_ast_fuzzer/mutations/wrap_unary_operator.h"
 
@@ -24,23 +25,21 @@
 
 Mutation::~Mutation() = default;
 
-std::unique_ptr<Mutation> Mutation::FromMessage(
-    const protobufs::Mutation& message) {
-  switch (message.mutation_case()) {
-    case protobufs::Mutation::kReplaceIdentifier:
-      return std::make_unique<MutationReplaceIdentifier>(
-          message.replace_identifier());
-    case protobufs::Mutation::kChangeBinaryOperator:
-      return std::make_unique<MutationChangeBinaryOperator>(
-          message.change_binary_operator());
-    case protobufs::Mutation::kWrapUnaryOperator:
-      return std::make_unique<MutationWrapUnaryOperator>(
-          message.wrap_unary_operator());
-    case protobufs::Mutation::MUTATION_NOT_SET:
-      assert(false && "Mutation is not set");
-      break;
-  }
-  return nullptr;
+std::unique_ptr<Mutation> Mutation::FromMessage(const protobufs::Mutation& message) {
+    switch (message.mutation_case()) {
+        case protobufs::Mutation::kChangeUnaryOperator:
+            return std::make_unique<MutationChangeUnaryOperator>(message.change_unary_operator());
+        case protobufs::Mutation::kReplaceIdentifier:
+            return std::make_unique<MutationReplaceIdentifier>(message.replace_identifier());
+        case protobufs::Mutation::kChangeBinaryOperator:
+            return std::make_unique<MutationChangeBinaryOperator>(message.change_binary_operator());
+        case protobufs::Mutation::kWrapUnaryOperator:
+            return std::make_unique<MutationWrapUnaryOperator>(message.wrap_unary_operator());
+        case protobufs::Mutation::MUTATION_NOT_SET:
+            assert(false && "Mutation is not set");
+            break;
+    }
+    return nullptr;
 }
 
 }  // namespace tint::fuzzers::ast_fuzzer
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/mutation.h b/src/tint/fuzzers/tint_ast_fuzzer/mutation.h
index 405f7bd..0bdc551 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/mutation.h
+++ b/src/tint/fuzzers/tint_ast_fuzzer/mutation.h
@@ -33,46 +33,44 @@
 /// - `Apply` - applies the mutation.
 /// - `ToMessage` - converts the mutation data into a protobuf message.
 class Mutation {
- public:
-  /// Virtual destructor.
-  virtual ~Mutation();
+  public:
+    /// Virtual destructor.
+    virtual ~Mutation();
 
-  /// @brief Determines whether this mutation is applicable to the `program`.
-  ///
-  /// @param program - the program this mutation will be applied to. The program
-  ///     must be valid.
-  /// @param node_id_map - the map from `tint::ast::` nodes to their ids.
-  /// @return `true` if `Apply` method can be called without breaking the
-  ///     semantics of the `program`.
-  /// @return `false` otherwise.
-  virtual bool IsApplicable(const tint::Program& program,
-                            const NodeIdMap& node_id_map) const = 0;
+    /// @brief Determines whether this mutation is applicable to the `program`.
+    ///
+    /// @param program - the program this mutation will be applied to. The program
+    ///     must be valid.
+    /// @param node_id_map - the map from `tint::ast::` nodes to their ids.
+    /// @return `true` if `Apply` method can be called without breaking the
+    ///     semantics of the `program`.
+    /// @return `false` otherwise.
+    virtual bool IsApplicable(const tint::Program& program, const NodeIdMap& node_id_map) const = 0;
 
-  /// @brief Applies this mutation to the `clone_context`.
-  ///
-  /// Precondition: `IsApplicable` must return `true` when invoked on the same
-  /// `node_id_map` and `clone_context->src` instance of `tint::Program`. A new
-  /// `tint::Program` that arises in `clone_context` must be valid.
-  ///
-  /// @param node_id_map - the map from `tint::ast::` nodes to their ids.
-  /// @param clone_context - the context that will clone the program with some
-  ///     changes introduced by this mutation.
-  /// @param new_node_id_map - this map will store ids for the mutated and
-  ///     cloned program. This argument cannot be a `nullptr` nor can it point
-  ///     to the same object as `node_id_map`.
-  virtual void Apply(const NodeIdMap& node_id_map,
-                     tint::CloneContext* clone_context,
-                     NodeIdMap* new_node_id_map) const = 0;
+    /// @brief Applies this mutation to the `clone_context`.
+    ///
+    /// Precondition: `IsApplicable` must return `true` when invoked on the same
+    /// `node_id_map` and `clone_context->src` instance of `tint::Program`. A new
+    /// `tint::Program` that arises in `clone_context` must be valid.
+    ///
+    /// @param node_id_map - the map from `tint::ast::` nodes to their ids.
+    /// @param clone_context - the context that will clone the program with some
+    ///     changes introduced by this mutation.
+    /// @param new_node_id_map - this map will store ids for the mutated and
+    ///     cloned program. This argument cannot be a `nullptr` nor can it point
+    ///     to the same object as `node_id_map`.
+    virtual void Apply(const NodeIdMap& node_id_map,
+                       tint::CloneContext* clone_context,
+                       NodeIdMap* new_node_id_map) const = 0;
 
-  /// @return a protobuf message for this mutation.
-  virtual protobufs::Mutation ToMessage() const = 0;
+    /// @return a protobuf message for this mutation.
+    virtual protobufs::Mutation ToMessage() const = 0;
 
-  /// @brief Converts a protobuf message into the mutation instance.
-  ///
-  /// @param message - a protobuf message.
-  /// @return the instance of this class.
-  static std::unique_ptr<Mutation> FromMessage(
-      const protobufs::Mutation& message);
+    /// @brief Converts a protobuf message into the mutation instance.
+    ///
+    /// @param message - a protobuf message.
+    /// @return the instance of this class.
+    static std::unique_ptr<Mutation> FromMessage(const protobufs::Mutation& message);
 };
 
 using MutationList = std::vector<std::unique_ptr<Mutation>>;
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/mutation_finder.h b/src/tint/fuzzers/tint_ast_fuzzer/mutation_finder.h
index 0d082c1..36f4c63 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/mutation_finder.h
+++ b/src/tint/fuzzers/tint_ast_fuzzer/mutation_finder.h
@@ -37,33 +37,31 @@
 /// it would make sense to apply only a probabilistically selected subset of
 /// them.
 class MutationFinder {
- public:
-  /// Virtual destructor.
-  virtual ~MutationFinder();
+  public:
+    /// Virtual destructor.
+    virtual ~MutationFinder();
 
-  /// @brief Traverses the `program`, looking for opportunities to apply
-  /// mutations.
-  ///
-  /// @param program - the program being fuzzed.
-  /// @param node_id_map - a map from `tint::ast::` nodes in the `program` to
-  ///     their unique ids.
-  /// @param probability_context - determines various probabilistic stuff in the
-  ///     mutator. This should ideally be used as less as possible.
-  /// @return all the found mutations.
-  virtual MutationList FindMutations(
-      const tint::Program& program,
-      NodeIdMap* node_id_map,
-      ProbabilityContext* probability_context) const = 0;
+    /// @brief Traverses the `program`, looking for opportunities to apply
+    /// mutations.
+    ///
+    /// @param program - the program being fuzzed.
+    /// @param node_id_map - a map from `tint::ast::` nodes in the `program` to
+    ///     their unique ids.
+    /// @param probability_context - determines various probabilistic stuff in the
+    ///     mutator. This should ideally be used as less as possible.
+    /// @return all the found mutations.
+    virtual MutationList FindMutations(const tint::Program& program,
+                                       NodeIdMap* node_id_map,
+                                       ProbabilityContext* probability_context) const = 0;
 
-  /// @brief Compute a probability of applying a single mutation, returned by
-  /// this class.
-  ///
-  /// @param probability_context - contains information about various
-  ///     non-deterministic stuff in the fuzzer.
-  /// @return a number in the range [0; 100] which is a chance of applying a
-  ///     mutation.
-  virtual uint32_t GetChanceOfApplyingMutation(
-      ProbabilityContext* probability_context) const = 0;
+    /// @brief Compute a probability of applying a single mutation, returned by
+    /// this class.
+    ///
+    /// @param probability_context - contains information about various
+    ///     non-deterministic stuff in the fuzzer.
+    /// @return a number in the range [0; 100] which is a chance of applying a
+    ///     mutation.
+    virtual uint32_t GetChanceOfApplyingMutation(ProbabilityContext* probability_context) const = 0;
 };
 
 using MutationFinderList = std::vector<std::unique_ptr<MutationFinder>>;
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/mutation_finders/change_binary_operators.cc b/src/tint/fuzzers/tint_ast_fuzzer/mutation_finders/change_binary_operators.cc
index 737c39f..5dab56f 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/mutation_finders/change_binary_operators.cc
+++ b/src/tint/fuzzers/tint_ast_fuzzer/mutation_finders/change_binary_operators.cc
@@ -26,63 +26,61 @@
     const tint::Program& program,
     NodeIdMap* node_id_map,
     ProbabilityContext* probability_context) const {
-  MutationList result;
+    MutationList result;
 
-  // Go through each binary expression in the AST and add a mutation that
-  // replaces its operator with some other type-compatible operator.
+    // Go through each binary expression in the AST and add a mutation that
+    // replaces its operator with some other type-compatible operator.
 
-  const std::vector<ast::BinaryOp> all_binary_operators = {
-      ast::BinaryOp::kAnd,
-      ast::BinaryOp::kOr,
-      ast::BinaryOp::kXor,
-      ast::BinaryOp::kLogicalAnd,
-      ast::BinaryOp::kLogicalOr,
-      ast::BinaryOp::kEqual,
-      ast::BinaryOp::kNotEqual,
-      ast::BinaryOp::kLessThan,
-      ast::BinaryOp::kGreaterThan,
-      ast::BinaryOp::kLessThanEqual,
-      ast::BinaryOp::kGreaterThanEqual,
-      ast::BinaryOp::kShiftLeft,
-      ast::BinaryOp::kShiftRight,
-      ast::BinaryOp::kAdd,
-      ast::BinaryOp::kSubtract,
-      ast::BinaryOp::kMultiply,
-      ast::BinaryOp::kDivide,
-      ast::BinaryOp::kModulo};
+    const std::vector<ast::BinaryOp> all_binary_operators = {ast::BinaryOp::kAnd,
+                                                             ast::BinaryOp::kOr,
+                                                             ast::BinaryOp::kXor,
+                                                             ast::BinaryOp::kLogicalAnd,
+                                                             ast::BinaryOp::kLogicalOr,
+                                                             ast::BinaryOp::kEqual,
+                                                             ast::BinaryOp::kNotEqual,
+                                                             ast::BinaryOp::kLessThan,
+                                                             ast::BinaryOp::kGreaterThan,
+                                                             ast::BinaryOp::kLessThanEqual,
+                                                             ast::BinaryOp::kGreaterThanEqual,
+                                                             ast::BinaryOp::kShiftLeft,
+                                                             ast::BinaryOp::kShiftRight,
+                                                             ast::BinaryOp::kAdd,
+                                                             ast::BinaryOp::kSubtract,
+                                                             ast::BinaryOp::kMultiply,
+                                                             ast::BinaryOp::kDivide,
+                                                             ast::BinaryOp::kModulo};
 
-  for (const auto* node : program.ASTNodes().Objects()) {
-    const auto* binary_expr = As<ast::BinaryExpression>(node);
-    if (!binary_expr) {
-      continue;
+    for (const auto* node : program.ASTNodes().Objects()) {
+        const auto* binary_expr = As<ast::BinaryExpression>(node);
+        if (!binary_expr) {
+            continue;
+        }
+
+        // Get vector of all operators this could be replaced with.
+        std::vector<ast::BinaryOp> allowed_replacements;
+        for (auto candidate_op : all_binary_operators) {
+            if (MutationChangeBinaryOperator::CanReplaceBinaryOperator(program, *binary_expr,
+                                                                       candidate_op)) {
+                allowed_replacements.push_back(candidate_op);
+            }
+        }
+
+        if (!allowed_replacements.empty()) {
+            // Choose an available replacement operator at random.
+            const ast::BinaryOp replacement =
+                allowed_replacements[probability_context->GetRandomIndex(allowed_replacements)];
+            // Add a mutation according to the chosen replacement.
+            result.push_back(std::make_unique<MutationChangeBinaryOperator>(
+                node_id_map->GetId(binary_expr), replacement));
+        }
     }
 
-    // Get vector of all operators this could be replaced with.
-    std::vector<ast::BinaryOp> allowed_replacements;
-    for (auto candidate_op : all_binary_operators) {
-      if (MutationChangeBinaryOperator::CanReplaceBinaryOperator(
-              program, *binary_expr, candidate_op)) {
-        allowed_replacements.push_back(candidate_op);
-      }
-    }
-
-    if (!allowed_replacements.empty()) {
-      // Choose an available replacement operator at random.
-      const ast::BinaryOp replacement =
-          allowed_replacements[probability_context->GetRandomIndex(
-              allowed_replacements)];
-      // Add a mutation according to the chosen replacement.
-      result.push_back(std::make_unique<MutationChangeBinaryOperator>(
-          node_id_map->GetId(binary_expr), replacement));
-    }
-  }
-
-  return result;
+    return result;
 }
 
 uint32_t MutationFinderChangeBinaryOperators::GetChanceOfApplyingMutation(
     ProbabilityContext* probability_context) const {
-  return probability_context->GetChanceOfChangingBinaryOperators();
+    return probability_context->GetChanceOfChangingBinaryOperators();
 }
 
 }  // namespace tint::fuzzers::ast_fuzzer
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/mutation_finders/change_binary_operators.h b/src/tint/fuzzers/tint_ast_fuzzer/mutation_finders/change_binary_operators.h
index e494dae..df63cca 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/mutation_finders/change_binary_operators.h
+++ b/src/tint/fuzzers/tint_ast_fuzzer/mutation_finders/change_binary_operators.h
@@ -24,13 +24,11 @@
 /// Concretely, for each binary expression in the module, tries to replace it
 /// with a different, type-compatible operator.
 class MutationFinderChangeBinaryOperators : public MutationFinder {
- public:
-  MutationList FindMutations(
-      const tint::Program& program,
-      NodeIdMap* node_id_map,
-      ProbabilityContext* probability_context) const override;
-  uint32_t GetChanceOfApplyingMutation(
-      ProbabilityContext* probability_context) const override;
+  public:
+    MutationList FindMutations(const tint::Program& program,
+                               NodeIdMap* node_id_map,
+                               ProbabilityContext* probability_context) const override;
+    uint32_t GetChanceOfApplyingMutation(ProbabilityContext* probability_context) const override;
 };
 
 }  // namespace tint::fuzzers::ast_fuzzer
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/mutation_finders/change_unary_operators.cc b/src/tint/fuzzers/tint_ast_fuzzer/mutation_finders/change_unary_operators.cc
new file mode 100644
index 0000000..ed2f442
--- /dev/null
+++ b/src/tint/fuzzers/tint_ast_fuzzer/mutation_finders/change_unary_operators.cc
@@ -0,0 +1,65 @@
+// Copyright 2021 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/fuzzers/tint_ast_fuzzer/mutation_finders/change_unary_operators.h"
+
+#include <memory>
+
+#include "src/tint/fuzzers/tint_ast_fuzzer/mutations/change_unary_operator.h"
+#include "src/tint/fuzzers/tint_ast_fuzzer/util.h"
+#include "src/tint/sem/reference.h"
+
+namespace tint::fuzzers::ast_fuzzer {
+
+MutationList MutationFinderChangeUnaryOperators::FindMutations(
+    const tint::Program& program,
+    NodeIdMap* node_id_map,
+    ProbabilityContext* /*unused*/) const {
+    MutationList result;
+
+    // Iterate through all AST nodes and for each valid unary op expression node,
+    // try to replace the node's unary operator.
+    for (const auto* node : program.ASTNodes().Objects()) {
+        const auto* unary_expr = tint::As<ast::UnaryOpExpression>(node);
+
+        // Transformation applies only when the node represents a valid unary
+        // expression.
+        if (!unary_expr) {
+            continue;
+        }
+
+        // Get the type of the unary expression.
+        const auto* type = program.Sem().Get(unary_expr)->Type();
+        const auto* basic_type =
+            type->Is<sem::Reference>() ? type->As<sem::Reference>()->StoreType() : type;
+
+        // Only signed integer or vector of signed integer can be mutated.
+        if (!basic_type->is_signed_scalar_or_vector()) {
+            continue;
+        }
+
+        result.push_back(std::make_unique<MutationChangeUnaryOperator>(
+            node_id_map->GetId(unary_expr),
+            MutationChangeUnaryOperator::ToggleOperator(unary_expr->op)));
+    }
+
+    return result;
+}
+
+uint32_t MutationFinderChangeUnaryOperators::GetChanceOfApplyingMutation(
+    ProbabilityContext* probability_context) const {
+    return probability_context->GetChanceOfChangingUnaryOperators();
+}
+
+}  // namespace tint::fuzzers::ast_fuzzer
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/mutation_finders/change_unary_operators.h b/src/tint/fuzzers/tint_ast_fuzzer/mutation_finders/change_unary_operators.h
new file mode 100644
index 0000000..5a86b5d
--- /dev/null
+++ b/src/tint/fuzzers/tint_ast_fuzzer/mutation_finders/change_unary_operators.h
@@ -0,0 +1,37 @@
+// Copyright 2021 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_FUZZERS_TINT_AST_FUZZER_MUTATION_FINDERS_CHANGE_UNARY_OPERATORS_H_
+#define SRC_TINT_FUZZERS_TINT_AST_FUZZER_MUTATION_FINDERS_CHANGE_UNARY_OPERATORS_H_
+
+#include "src/tint/fuzzers/tint_ast_fuzzer/mutation_finder.h"
+
+namespace tint::fuzzers::ast_fuzzer {
+
+/// Looks for opportunities to apply
+/// `MutationFinderChangeUnaryOperators`.
+///
+/// Concretely, for each unary expression in the module, try to change its
+/// operator with a permitted one.
+class MutationFinderChangeUnaryOperators : public MutationFinder {
+  public:
+    MutationList FindMutations(const tint::Program& program,
+                               NodeIdMap* node_id_map,
+                               ProbabilityContext* probability_context) const override;
+    uint32_t GetChanceOfApplyingMutation(ProbabilityContext* probability_context) const override;
+};
+
+}  // namespace tint::fuzzers::ast_fuzzer
+
+#endif  // SRC_TINT_FUZZERS_TINT_AST_FUZZER_MUTATION_FINDERS_CHANGE_UNARY_OPERATORS_H_
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/mutation_finders/replace_identifiers.cc b/src/tint/fuzzers/tint_ast_fuzzer/mutation_finders/replace_identifiers.cc
index e3269da..8146aa4 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/mutation_finders/replace_identifiers.cc
+++ b/src/tint/fuzzers/tint_ast_fuzzer/mutation_finders/replace_identifiers.cc
@@ -29,47 +29,46 @@
     const tint::Program& program,
     NodeIdMap* node_id_map,
     ProbabilityContext* probability_context) const {
-  MutationList result;
+    MutationList result;
 
-  // Go through each variable in the AST and for each user of that variable, try
-  // to replace it with some other variable usage.
+    // Go through each variable in the AST and for each user of that variable, try
+    // to replace it with some other variable usage.
 
-  for (const auto* node : program.SemNodes().Objects()) {
-    const auto* sem_variable = tint::As<sem::Variable>(node);
-    if (!sem_variable) {
-      continue;
+    for (const auto* node : program.SemNodes().Objects()) {
+        const auto* sem_variable = tint::As<sem::Variable>(node);
+        if (!sem_variable) {
+            continue;
+        }
+
+        // Iterate over all users of `sem_variable`.
+        for (const auto* user : sem_variable->Users()) {
+            // Get all variables that can be used to replace the `user` of
+            // `sem_variable`.
+            auto candidate_variables =
+                util::GetAllVarsInScope(program, user->Stmt(), [user](const sem::Variable* var) {
+                    return var != user->Variable() && var->Type() == user->Type();
+                });
+
+            if (candidate_variables.empty()) {
+                // No suitable replacements have been found.
+                continue;
+            }
+
+            const auto* replacement =
+                candidate_variables[probability_context->GetRandomIndex(candidate_variables)];
+
+            result.push_back(std::make_unique<MutationReplaceIdentifier>(
+                node_id_map->GetId(user->Declaration()),
+                node_id_map->GetId(replacement->Declaration())));
+        }
     }
 
-    // Iterate over all users of `sem_variable`.
-    for (const auto* user : sem_variable->Users()) {
-      // Get all variables that can be used to replace the `user` of
-      // `sem_variable`.
-      auto candidate_variables = util::GetAllVarsInScope(
-          program, user->Stmt(), [user](const sem::Variable* var) {
-            return var != user->Variable() && var->Type() == user->Type();
-          });
-
-      if (candidate_variables.empty()) {
-        // No suitable replacements have been found.
-        continue;
-      }
-
-      const auto* replacement =
-          candidate_variables[probability_context->GetRandomIndex(
-              candidate_variables)];
-
-      result.push_back(std::make_unique<MutationReplaceIdentifier>(
-          node_id_map->GetId(user->Declaration()),
-          node_id_map->GetId(replacement->Declaration())));
-    }
-  }
-
-  return result;
+    return result;
 }
 
 uint32_t MutationFinderReplaceIdentifiers::GetChanceOfApplyingMutation(
     ProbabilityContext* probability_context) const {
-  return probability_context->GetChanceOfReplacingIdentifiers();
+    return probability_context->GetChanceOfReplacingIdentifiers();
 }
 
 }  // namespace tint::fuzzers::ast_fuzzer
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/mutation_finders/replace_identifiers.h b/src/tint/fuzzers/tint_ast_fuzzer/mutation_finders/replace_identifiers.h
index 8e760c6..a4f9f3e 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/mutation_finders/replace_identifiers.h
+++ b/src/tint/fuzzers/tint_ast_fuzzer/mutation_finders/replace_identifiers.h
@@ -24,13 +24,11 @@
 /// Concretely, for each variable in the module, tries to replace its users with
 /// the uses of some other variables.
 class MutationFinderReplaceIdentifiers : public MutationFinder {
- public:
-  MutationList FindMutations(
-      const tint::Program& program,
-      NodeIdMap* node_id_map,
-      ProbabilityContext* probability_context) const override;
-  uint32_t GetChanceOfApplyingMutation(
-      ProbabilityContext* probability_context) const override;
+  public:
+    MutationList FindMutations(const tint::Program& program,
+                               NodeIdMap* node_id_map,
+                               ProbabilityContext* probability_context) const override;
+    uint32_t GetChanceOfApplyingMutation(ProbabilityContext* probability_context) const override;
 };
 
 }  // namespace tint::fuzzers::ast_fuzzer
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/mutation_finders/wrap_unary_operators.cc b/src/tint/fuzzers/tint_ast_fuzzer/mutation_finders/wrap_unary_operators.cc
index c34c6fb..12fe82c 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/mutation_finders/wrap_unary_operators.cc
+++ b/src/tint/fuzzers/tint_ast_fuzzer/mutation_finders/wrap_unary_operators.cc
@@ -33,56 +33,54 @@
     const tint::Program& program,
     NodeIdMap* node_id_map,
     ProbabilityContext* probability_context) const {
-  MutationList result;
+    MutationList result;
 
-  ExpressionSize expression_size(program);
+    ExpressionSize expression_size(program);
 
-  // Iterate through all ast nodes and for each expression node, try to wrap
-  // the inside a valid unary operator based on the type of the expression.
-  for (const auto* node : program.ASTNodes().Objects()) {
-    const auto* expr_ast_node = tint::As<ast::Expression>(node);
+    // Iterate through all ast nodes and for each expression node, try to wrap
+    // the inside a valid unary operator based on the type of the expression.
+    for (const auto* node : program.ASTNodes().Objects()) {
+        const auto* expr_ast_node = tint::As<ast::Expression>(node);
 
-    // Transformation applies only when the node represents a valid expression.
-    if (!expr_ast_node) {
-      continue;
+        // Transformation applies only when the node represents a valid expression.
+        if (!expr_ast_node) {
+            continue;
+        }
+
+        if (expression_size(expr_ast_node) > kMaxExpressionSize) {
+            continue;
+        }
+
+        const auto* expr_sem_node = tint::As<sem::Expression>(program.Sem().Get(expr_ast_node));
+
+        // Transformation applies only when the semantic node for the given
+        // expression is present.
+        if (!expr_sem_node) {
+            continue;
+        }
+
+        std::vector<ast::UnaryOp> valid_operators =
+            MutationWrapUnaryOperator::GetValidUnaryWrapper(*expr_sem_node);
+
+        // Transformation only applies when there are available unary operators
+        // for the given expression.
+        if (valid_operators.empty()) {
+            continue;
+        }
+
+        ast::UnaryOp unary_op_wrapper =
+            valid_operators[probability_context->GetRandomIndex(valid_operators)];
+
+        result.push_back(std::make_unique<MutationWrapUnaryOperator>(
+            node_id_map->GetId(expr_ast_node), node_id_map->TakeFreshId(), unary_op_wrapper));
     }
 
-    if (expression_size(expr_ast_node) > kMaxExpressionSize) {
-      continue;
-    }
-
-    const auto* expr_sem_node =
-        tint::As<sem::Expression>(program.Sem().Get(expr_ast_node));
-
-    // Transformation applies only when the semantic node for the given
-    // expression is present.
-    if (!expr_sem_node) {
-      continue;
-    }
-
-    std::vector<ast::UnaryOp> valid_operators =
-        MutationWrapUnaryOperator::GetValidUnaryWrapper(*expr_sem_node);
-
-    // Transformation only applies when there are available unary operators
-    // for the given expression.
-    if (valid_operators.empty()) {
-      continue;
-    }
-
-    ast::UnaryOp unary_op_wrapper =
-        valid_operators[probability_context->GetRandomIndex(valid_operators)];
-
-    result.push_back(std::make_unique<MutationWrapUnaryOperator>(
-        node_id_map->GetId(expr_ast_node), node_id_map->TakeFreshId(),
-        unary_op_wrapper));
-  }
-
-  return result;
+    return result;
 }
 
 uint32_t MutationFinderWrapUnaryOperators::GetChanceOfApplyingMutation(
     ProbabilityContext* probability_context) const {
-  return probability_context->GetChanceOfWrappingUnaryOperators();
+    return probability_context->GetChanceOfWrappingUnaryOperators();
 }
 
 }  // namespace tint::fuzzers::ast_fuzzer
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/mutation_finders/wrap_unary_operators.h b/src/tint/fuzzers/tint_ast_fuzzer/mutation_finders/wrap_unary_operators.h
index fe70bf5..6e2cada 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/mutation_finders/wrap_unary_operators.h
+++ b/src/tint/fuzzers/tint_ast_fuzzer/mutation_finders/wrap_unary_operators.h
@@ -25,13 +25,11 @@
 /// For each expression in the module, try to wrap it within
 /// a unary operator.
 class MutationFinderWrapUnaryOperators : public MutationFinder {
- public:
-  MutationList FindMutations(
-      const tint::Program& program,
-      NodeIdMap* node_id_map,
-      ProbabilityContext* probability_context) const override;
-  uint32_t GetChanceOfApplyingMutation(
-      ProbabilityContext* probability_context) const override;
+  public:
+    MutationList FindMutations(const tint::Program& program,
+                               NodeIdMap* node_id_map,
+                               ProbabilityContext* probability_context) const override;
+    uint32_t GetChanceOfApplyingMutation(ProbabilityContext* probability_context) const override;
 };
 
 }  // namespace tint::fuzzers::ast_fuzzer
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/mutations/change_binary_operator.cc b/src/tint/fuzzers/tint_ast_fuzzer/mutations/change_binary_operator.cc
index 4b4888b..d27fa7f 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/mutations/change_binary_operator.cc
+++ b/src/tint/fuzzers/tint_ast_fuzzer/mutations/change_binary_operator.cc
@@ -16,265 +16,262 @@
 
 #include <utility>
 
-#include "src/tint/sem/reference_type.h"
+#include "src/tint/sem/reference.h"
 
 namespace tint::fuzzers::ast_fuzzer {
 
 namespace {
 
 bool IsSuitableForShift(const sem::Type* lhs_type, const sem::Type* rhs_type) {
-  // `a << b` requires b to be an unsigned scalar or vector, and `a` to be an
-  // integer scalar or vector with the same width as `b`. Similar for `a >> b`.
+    // `a << b` requires b to be an unsigned scalar or vector, and `a` to be an
+    // integer scalar or vector with the same width as `b`. Similar for `a >> b`.
 
-  if (rhs_type->is_unsigned_integer_scalar()) {
-    return lhs_type->is_integer_scalar();
-  }
-  if (rhs_type->is_unsigned_integer_vector()) {
-    return lhs_type->is_unsigned_integer_vector();
-  }
-  return false;
+    if (rhs_type->is_unsigned_integer_scalar()) {
+        return lhs_type->is_integer_scalar();
+    }
+    if (rhs_type->is_unsigned_integer_vector()) {
+        return lhs_type->is_unsigned_integer_vector();
+    }
+    return false;
 }
 
 bool CanReplaceAddSubtractWith(const sem::Type* lhs_type,
                                const sem::Type* rhs_type,
                                ast::BinaryOp new_operator) {
-  // The program is assumed to be well-typed, so this method determines when
-  // 'new_operator' can be used as a type-preserving replacement in an '+' or
-  // '-' expression.
-  switch (new_operator) {
-    case ast::BinaryOp::kAdd:
-    case ast::BinaryOp::kSubtract:
-      // '+' and '-' are fully type compatible.
-      return true;
-    case ast::BinaryOp::kAnd:
-    case ast::BinaryOp::kOr:
-    case ast::BinaryOp::kXor:
-      // These operators do not have a mixed vector-scalar form, and only work
-      // on integer types.
-      return lhs_type == rhs_type && lhs_type->is_integer_scalar_or_vector();
-    case ast::BinaryOp::kMultiply:
-      // '+' and '*' are largely type-compatible, but for matrices they are only
-      // type-compatible if the matrices are square.
-      return !lhs_type->is_float_matrix() || lhs_type->is_square_float_matrix();
-    case ast::BinaryOp::kDivide:
-    case ast::BinaryOp::kModulo:
-      // '/' is not defined for matrices.
-      return lhs_type->is_numeric_scalar_or_vector() &&
-             rhs_type->is_numeric_scalar_or_vector();
-    case ast::BinaryOp::kShiftLeft:
-    case ast::BinaryOp::kShiftRight:
-      return IsSuitableForShift(lhs_type, rhs_type);
-    default:
-      return false;
-  }
+    // The program is assumed to be well-typed, so this method determines when
+    // 'new_operator' can be used as a type-preserving replacement in an '+' or
+    // '-' expression.
+    switch (new_operator) {
+        case ast::BinaryOp::kAdd:
+        case ast::BinaryOp::kSubtract:
+            // '+' and '-' are fully type compatible.
+            return true;
+        case ast::BinaryOp::kAnd:
+        case ast::BinaryOp::kOr:
+        case ast::BinaryOp::kXor:
+            // These operators do not have a mixed vector-scalar form, and only work
+            // on integer types.
+            return lhs_type == rhs_type && lhs_type->is_integer_scalar_or_vector();
+        case ast::BinaryOp::kMultiply:
+            // '+' and '*' are largely type-compatible, but for matrices they are only
+            // type-compatible if the matrices are square.
+            return !lhs_type->is_float_matrix() || lhs_type->is_square_float_matrix();
+        case ast::BinaryOp::kDivide:
+        case ast::BinaryOp::kModulo:
+            // '/' is not defined for matrices.
+            return lhs_type->is_numeric_scalar_or_vector() &&
+                   rhs_type->is_numeric_scalar_or_vector();
+        case ast::BinaryOp::kShiftLeft:
+        case ast::BinaryOp::kShiftRight:
+            return IsSuitableForShift(lhs_type, rhs_type);
+        default:
+            return false;
+    }
 }
 
 bool CanReplaceMultiplyWith(const sem::Type* lhs_type,
                             const sem::Type* rhs_type,
                             ast::BinaryOp new_operator) {
-  // The program is assumed to be well-typed, so this method determines when
-  // 'new_operator' can be used as a type-preserving replacement in a '*'
-  // expression.
-  switch (new_operator) {
-    case ast::BinaryOp::kMultiply:
-      return true;
-    case ast::BinaryOp::kAdd:
-    case ast::BinaryOp::kSubtract:
-      // '*' is type-compatible with '+' and '-' for square matrices, and for
-      // numeric scalars/vectors.
-      if (lhs_type->is_square_float_matrix() &&
-          rhs_type->is_square_float_matrix()) {
-        return true;
-      }
-      return lhs_type->is_numeric_scalar_or_vector() &&
-             rhs_type->is_numeric_scalar_or_vector();
-    case ast::BinaryOp::kAnd:
-    case ast::BinaryOp::kOr:
-    case ast::BinaryOp::kXor:
-      // These operators require homogeneous integer types.
-      return lhs_type == rhs_type && lhs_type->is_integer_scalar_or_vector();
-    case ast::BinaryOp::kDivide:
-    case ast::BinaryOp::kModulo:
-      // '/' is not defined for matrices.
-      return lhs_type->is_numeric_scalar_or_vector() &&
-             rhs_type->is_numeric_scalar_or_vector();
-    case ast::BinaryOp::kShiftLeft:
-    case ast::BinaryOp::kShiftRight:
-      return IsSuitableForShift(lhs_type, rhs_type);
-    default:
-      return false;
-  }
+    // The program is assumed to be well-typed, so this method determines when
+    // 'new_operator' can be used as a type-preserving replacement in a '*'
+    // expression.
+    switch (new_operator) {
+        case ast::BinaryOp::kMultiply:
+            return true;
+        case ast::BinaryOp::kAdd:
+        case ast::BinaryOp::kSubtract:
+            // '*' is type-compatible with '+' and '-' for square matrices, and for
+            // numeric scalars/vectors.
+            if (lhs_type->is_square_float_matrix() && rhs_type->is_square_float_matrix()) {
+                return true;
+            }
+            return lhs_type->is_numeric_scalar_or_vector() &&
+                   rhs_type->is_numeric_scalar_or_vector();
+        case ast::BinaryOp::kAnd:
+        case ast::BinaryOp::kOr:
+        case ast::BinaryOp::kXor:
+            // These operators require homogeneous integer types.
+            return lhs_type == rhs_type && lhs_type->is_integer_scalar_or_vector();
+        case ast::BinaryOp::kDivide:
+        case ast::BinaryOp::kModulo:
+            // '/' is not defined for matrices.
+            return lhs_type->is_numeric_scalar_or_vector() &&
+                   rhs_type->is_numeric_scalar_or_vector();
+        case ast::BinaryOp::kShiftLeft:
+        case ast::BinaryOp::kShiftRight:
+            return IsSuitableForShift(lhs_type, rhs_type);
+        default:
+            return false;
+    }
 }
 
 bool CanReplaceDivideOrModuloWith(const sem::Type* lhs_type,
                                   const sem::Type* rhs_type,
                                   ast::BinaryOp new_operator) {
-  // The program is assumed to be well-typed, so this method determines when
-  // 'new_operator' can be used as a type-preserving replacement in a '/'
-  // expression.
-  switch (new_operator) {
-    case ast::BinaryOp::kAdd:
-    case ast::BinaryOp::kSubtract:
-    case ast::BinaryOp::kMultiply:
-    case ast::BinaryOp::kDivide:
-    case ast::BinaryOp::kModulo:
-      // These operators work in all contexts where '/' works.
-      return true;
-    case ast::BinaryOp::kAnd:
-    case ast::BinaryOp::kOr:
-    case ast::BinaryOp::kXor:
-      // These operators require homogeneous integer types.
-      return lhs_type == rhs_type && lhs_type->is_integer_scalar_or_vector();
-    case ast::BinaryOp::kShiftLeft:
-    case ast::BinaryOp::kShiftRight:
-      return IsSuitableForShift(lhs_type, rhs_type);
-    default:
-      return false;
-  }
+    // The program is assumed to be well-typed, so this method determines when
+    // 'new_operator' can be used as a type-preserving replacement in a '/'
+    // expression.
+    switch (new_operator) {
+        case ast::BinaryOp::kAdd:
+        case ast::BinaryOp::kSubtract:
+        case ast::BinaryOp::kMultiply:
+        case ast::BinaryOp::kDivide:
+        case ast::BinaryOp::kModulo:
+            // These operators work in all contexts where '/' works.
+            return true;
+        case ast::BinaryOp::kAnd:
+        case ast::BinaryOp::kOr:
+        case ast::BinaryOp::kXor:
+            // These operators require homogeneous integer types.
+            return lhs_type == rhs_type && lhs_type->is_integer_scalar_or_vector();
+        case ast::BinaryOp::kShiftLeft:
+        case ast::BinaryOp::kShiftRight:
+            return IsSuitableForShift(lhs_type, rhs_type);
+        default:
+            return false;
+    }
 }
 
 bool CanReplaceLogicalAndLogicalOrWith(ast::BinaryOp new_operator) {
-  switch (new_operator) {
-    case ast::BinaryOp::kLogicalAnd:
-    case ast::BinaryOp::kLogicalOr:
-    case ast::BinaryOp::kAnd:
-    case ast::BinaryOp::kOr:
-    case ast::BinaryOp::kEqual:
-    case ast::BinaryOp::kNotEqual:
-      // These operators all work whenever '&&' and '||' work.
-      return true;
-    default:
-      return false;
-  }
+    switch (new_operator) {
+        case ast::BinaryOp::kLogicalAnd:
+        case ast::BinaryOp::kLogicalOr:
+        case ast::BinaryOp::kAnd:
+        case ast::BinaryOp::kOr:
+        case ast::BinaryOp::kEqual:
+        case ast::BinaryOp::kNotEqual:
+            // These operators all work whenever '&&' and '||' work.
+            return true;
+        default:
+            return false;
+    }
 }
 
 bool CanReplaceAndOrWith(const sem::Type* lhs_type,
                          const sem::Type* rhs_type,
                          ast::BinaryOp new_operator) {
-  switch (new_operator) {
-    case ast::BinaryOp::kAnd:
-    case ast::BinaryOp::kOr:
-      // '&' and '|' work in all the same contexts.
-      return true;
-    case ast::BinaryOp::kAdd:
-    case ast::BinaryOp::kSubtract:
-    case ast::BinaryOp::kMultiply:
-    case ast::BinaryOp::kDivide:
-    case ast::BinaryOp::kModulo:
-    case ast::BinaryOp::kXor:
-      // '&' and '|' can be applied to booleans. In all other contexts,
-      // integer numeric operators work.
-      return !lhs_type->is_bool_scalar_or_vector();
-    case ast::BinaryOp::kShiftLeft:
-    case ast::BinaryOp::kShiftRight:
-      return IsSuitableForShift(lhs_type, rhs_type);
-    case ast::BinaryOp::kLogicalAnd:
-    case ast::BinaryOp::kLogicalOr:
-      // '&' and '|' can be applied to booleans, and for boolean scalar
-      // scalar contexts, their logical counterparts work.
-      return lhs_type->Is<sem::Bool>();
-    case ast::BinaryOp::kEqual:
-    case ast::BinaryOp::kNotEqual:
-      // '&' and '|' can be applied to booleans, and in these contexts equality
-      // comparison operators also work.
-      return lhs_type->is_bool_scalar_or_vector();
-    default:
-      return false;
-  }
+    switch (new_operator) {
+        case ast::BinaryOp::kAnd:
+        case ast::BinaryOp::kOr:
+            // '&' and '|' work in all the same contexts.
+            return true;
+        case ast::BinaryOp::kAdd:
+        case ast::BinaryOp::kSubtract:
+        case ast::BinaryOp::kMultiply:
+        case ast::BinaryOp::kDivide:
+        case ast::BinaryOp::kModulo:
+        case ast::BinaryOp::kXor:
+            // '&' and '|' can be applied to booleans. In all other contexts,
+            // integer numeric operators work.
+            return !lhs_type->is_bool_scalar_or_vector();
+        case ast::BinaryOp::kShiftLeft:
+        case ast::BinaryOp::kShiftRight:
+            return IsSuitableForShift(lhs_type, rhs_type);
+        case ast::BinaryOp::kLogicalAnd:
+        case ast::BinaryOp::kLogicalOr:
+            // '&' and '|' can be applied to booleans, and for boolean scalar
+            // scalar contexts, their logical counterparts work.
+            return lhs_type->Is<sem::Bool>();
+        case ast::BinaryOp::kEqual:
+        case ast::BinaryOp::kNotEqual:
+            // '&' and '|' can be applied to booleans, and in these contexts equality
+            // comparison operators also work.
+            return lhs_type->is_bool_scalar_or_vector();
+        default:
+            return false;
+    }
 }
 
 bool CanReplaceXorWith(const sem::Type* lhs_type,
                        const sem::Type* rhs_type,
                        ast::BinaryOp new_operator) {
-  switch (new_operator) {
-    case ast::BinaryOp::kAdd:
-    case ast::BinaryOp::kSubtract:
-    case ast::BinaryOp::kMultiply:
-    case ast::BinaryOp::kDivide:
-    case ast::BinaryOp::kModulo:
-    case ast::BinaryOp::kAnd:
-    case ast::BinaryOp::kOr:
-    case ast::BinaryOp::kXor:
-      // '^' only works on integer types, and in any such context, all other
-      // integer operators also work.
-      return true;
-    case ast::BinaryOp::kShiftLeft:
-    case ast::BinaryOp::kShiftRight:
-      return IsSuitableForShift(lhs_type, rhs_type);
-    default:
-      return false;
-  }
+    switch (new_operator) {
+        case ast::BinaryOp::kAdd:
+        case ast::BinaryOp::kSubtract:
+        case ast::BinaryOp::kMultiply:
+        case ast::BinaryOp::kDivide:
+        case ast::BinaryOp::kModulo:
+        case ast::BinaryOp::kAnd:
+        case ast::BinaryOp::kOr:
+        case ast::BinaryOp::kXor:
+            // '^' only works on integer types, and in any such context, all other
+            // integer operators also work.
+            return true;
+        case ast::BinaryOp::kShiftLeft:
+        case ast::BinaryOp::kShiftRight:
+            return IsSuitableForShift(lhs_type, rhs_type);
+        default:
+            return false;
+    }
 }
 
 bool CanReplaceShiftLeftShiftRightWith(const sem::Type* lhs_type,
                                        const sem::Type* rhs_type,
                                        ast::BinaryOp new_operator) {
-  switch (new_operator) {
-    case ast::BinaryOp::kShiftLeft:
-    case ast::BinaryOp::kShiftRight:
-      // These operators are type-compatible.
-      return true;
-    case ast::BinaryOp::kAdd:
-    case ast::BinaryOp::kSubtract:
-    case ast::BinaryOp::kMultiply:
-    case ast::BinaryOp::kDivide:
-    case ast::BinaryOp::kModulo:
-    case ast::BinaryOp::kAnd:
-    case ast::BinaryOp::kOr:
-    case ast::BinaryOp::kXor:
-      // Shift operators allow mixing of signed and unsigned arguments, but in
-      // the case where the arguments are homogeneous, they are type-compatible
-      // with other numeric operators.
-      return lhs_type == rhs_type;
-    default:
-      return false;
-  }
+    switch (new_operator) {
+        case ast::BinaryOp::kShiftLeft:
+        case ast::BinaryOp::kShiftRight:
+            // These operators are type-compatible.
+            return true;
+        case ast::BinaryOp::kAdd:
+        case ast::BinaryOp::kSubtract:
+        case ast::BinaryOp::kMultiply:
+        case ast::BinaryOp::kDivide:
+        case ast::BinaryOp::kModulo:
+        case ast::BinaryOp::kAnd:
+        case ast::BinaryOp::kOr:
+        case ast::BinaryOp::kXor:
+            // Shift operators allow mixing of signed and unsigned arguments, but in
+            // the case where the arguments are homogeneous, they are type-compatible
+            // with other numeric operators.
+            return lhs_type == rhs_type;
+        default:
+            return false;
+    }
 }
 
-bool CanReplaceEqualNotEqualWith(const sem::Type* lhs_type,
-                                 ast::BinaryOp new_operator) {
-  switch (new_operator) {
-    case ast::BinaryOp::kEqual:
-    case ast::BinaryOp::kNotEqual:
-      // These operators are type-compatible.
-      return true;
-    case ast::BinaryOp::kLessThan:
-    case ast::BinaryOp::kLessThanEqual:
-    case ast::BinaryOp::kGreaterThan:
-    case ast::BinaryOp::kGreaterThanEqual:
-      // An equality comparison between numeric types can be changed to an
-      // ordered comparison.
-      return lhs_type->is_numeric_scalar_or_vector();
-    case ast::BinaryOp::kLogicalAnd:
-    case ast::BinaryOp::kLogicalOr:
-      // An equality comparison between boolean scalars can be turned into a
-      // logical operation.
-      return lhs_type->Is<sem::Bool>();
-    case ast::BinaryOp::kAnd:
-    case ast::BinaryOp::kOr:
-      // An equality comparison between boolean scalars or vectors can be turned
-      // into a component-wise non-short-circuit logical operation.
-      return lhs_type->is_bool_scalar_or_vector();
-    default:
-      return false;
-  }
+bool CanReplaceEqualNotEqualWith(const sem::Type* lhs_type, ast::BinaryOp new_operator) {
+    switch (new_operator) {
+        case ast::BinaryOp::kEqual:
+        case ast::BinaryOp::kNotEqual:
+            // These operators are type-compatible.
+            return true;
+        case ast::BinaryOp::kLessThan:
+        case ast::BinaryOp::kLessThanEqual:
+        case ast::BinaryOp::kGreaterThan:
+        case ast::BinaryOp::kGreaterThanEqual:
+            // An equality comparison between numeric types can be changed to an
+            // ordered comparison.
+            return lhs_type->is_numeric_scalar_or_vector();
+        case ast::BinaryOp::kLogicalAnd:
+        case ast::BinaryOp::kLogicalOr:
+            // An equality comparison between boolean scalars can be turned into a
+            // logical operation.
+            return lhs_type->Is<sem::Bool>();
+        case ast::BinaryOp::kAnd:
+        case ast::BinaryOp::kOr:
+            // An equality comparison between boolean scalars or vectors can be turned
+            // into a component-wise non-short-circuit logical operation.
+            return lhs_type->is_bool_scalar_or_vector();
+        default:
+            return false;
+    }
 }
 
-bool CanReplaceLessThanLessThanEqualGreaterThanGreaterThanEqualWith(
-    ast::BinaryOp new_operator) {
-  switch (new_operator) {
-    case ast::BinaryOp::kEqual:
-    case ast::BinaryOp::kNotEqual:
-    case ast::BinaryOp::kLessThan:
-    case ast::BinaryOp::kLessThanEqual:
-    case ast::BinaryOp::kGreaterThan:
-    case ast::BinaryOp::kGreaterThanEqual:
-      // Ordered comparison operators can be interchanged, and equality
-      // operators can be used in their place.
-      return true;
-    default:
-      return false;
-  }
+bool CanReplaceLessThanLessThanEqualGreaterThanGreaterThanEqualWith(ast::BinaryOp new_operator) {
+    switch (new_operator) {
+        case ast::BinaryOp::kEqual:
+        case ast::BinaryOp::kNotEqual:
+        case ast::BinaryOp::kLessThan:
+        case ast::BinaryOp::kLessThanEqual:
+        case ast::BinaryOp::kGreaterThan:
+        case ast::BinaryOp::kGreaterThanEqual:
+            // Ordered comparison operators can be interchanged, and equality
+            // operators can be used in their place.
+            return true;
+        default:
+            return false;
+    }
 }
 }  // namespace
 
@@ -282,204 +279,193 @@
     protobufs::MutationChangeBinaryOperator message)
     : message_(std::move(message)) {}
 
-MutationChangeBinaryOperator::MutationChangeBinaryOperator(
-    uint32_t binary_expr_id,
-    ast::BinaryOp new_operator) {
-  message_.set_binary_expr_id(binary_expr_id);
-  message_.set_new_operator(static_cast<uint32_t>(new_operator));
+MutationChangeBinaryOperator::MutationChangeBinaryOperator(uint32_t binary_expr_id,
+                                                           ast::BinaryOp new_operator) {
+    message_.set_binary_expr_id(binary_expr_id);
+    message_.set_new_operator(static_cast<uint32_t>(new_operator));
 }
 
 bool MutationChangeBinaryOperator::CanReplaceBinaryOperator(
     const Program& program,
     const ast::BinaryExpression& binary_expr,
     ast::BinaryOp new_operator) {
-  if (new_operator == binary_expr.op) {
-    // An operator should not be replaced with itself, as this would be a no-op.
-    return false;
-  }
+    if (new_operator == binary_expr.op) {
+        // An operator should not be replaced with itself, as this would be a no-op.
+        return false;
+    }
 
-  // Get the types of the operators.
-  const auto* lhs_type = program.Sem().Get(binary_expr.lhs)->Type();
-  const auto* rhs_type = program.Sem().Get(binary_expr.rhs)->Type();
+    // Get the types of the operators.
+    const auto* lhs_type = program.Sem().Get(binary_expr.lhs)->Type();
+    const auto* rhs_type = program.Sem().Get(binary_expr.rhs)->Type();
 
-  // If these are reference types, unwrap them to get the pointee type.
-  const sem::Type* lhs_basic_type =
-      lhs_type->Is<sem::Reference>()
-          ? lhs_type->As<sem::Reference>()->StoreType()
-          : lhs_type;
-  const sem::Type* rhs_basic_type =
-      rhs_type->Is<sem::Reference>()
-          ? rhs_type->As<sem::Reference>()->StoreType()
-          : rhs_type;
+    // If these are reference types, unwrap them to get the pointee type.
+    const sem::Type* lhs_basic_type =
+        lhs_type->Is<sem::Reference>() ? lhs_type->As<sem::Reference>()->StoreType() : lhs_type;
+    const sem::Type* rhs_basic_type =
+        rhs_type->Is<sem::Reference>() ? rhs_type->As<sem::Reference>()->StoreType() : rhs_type;
 
-  switch (binary_expr.op) {
-    case ast::BinaryOp::kAdd:
-    case ast::BinaryOp::kSubtract:
-      return CanReplaceAddSubtractWith(lhs_basic_type, rhs_basic_type,
-                                       new_operator);
-    case ast::BinaryOp::kMultiply:
-      return CanReplaceMultiplyWith(lhs_basic_type, rhs_basic_type,
-                                    new_operator);
-    case ast::BinaryOp::kDivide:
-    case ast::BinaryOp::kModulo:
-      return CanReplaceDivideOrModuloWith(lhs_basic_type, rhs_basic_type,
-                                          new_operator);
-    case ast::BinaryOp::kAnd:
-    case ast::BinaryOp::kOr:
-      return CanReplaceAndOrWith(lhs_basic_type, rhs_basic_type, new_operator);
-    case ast::BinaryOp::kXor:
-      return CanReplaceXorWith(lhs_basic_type, rhs_basic_type, new_operator);
-    case ast::BinaryOp::kShiftLeft:
-    case ast::BinaryOp::kShiftRight:
-      return CanReplaceShiftLeftShiftRightWith(lhs_basic_type, rhs_basic_type,
-                                               new_operator);
-    case ast::BinaryOp::kLogicalAnd:
-    case ast::BinaryOp::kLogicalOr:
-      return CanReplaceLogicalAndLogicalOrWith(new_operator);
-    case ast::BinaryOp::kEqual:
-    case ast::BinaryOp::kNotEqual:
-      return CanReplaceEqualNotEqualWith(lhs_basic_type, new_operator);
-    case ast::BinaryOp::kLessThan:
-    case ast::BinaryOp::kLessThanEqual:
-    case ast::BinaryOp::kGreaterThan:
-    case ast::BinaryOp::kGreaterThanEqual:
-    case ast::BinaryOp::kNone:
-      return CanReplaceLessThanLessThanEqualGreaterThanGreaterThanEqualWith(
-          new_operator);
-      assert(false && "Unreachable");
-      return false;
-  }
+    switch (binary_expr.op) {
+        case ast::BinaryOp::kAdd:
+        case ast::BinaryOp::kSubtract:
+            return CanReplaceAddSubtractWith(lhs_basic_type, rhs_basic_type, new_operator);
+        case ast::BinaryOp::kMultiply:
+            return CanReplaceMultiplyWith(lhs_basic_type, rhs_basic_type, new_operator);
+        case ast::BinaryOp::kDivide:
+        case ast::BinaryOp::kModulo:
+            return CanReplaceDivideOrModuloWith(lhs_basic_type, rhs_basic_type, new_operator);
+        case ast::BinaryOp::kAnd:
+        case ast::BinaryOp::kOr:
+            return CanReplaceAndOrWith(lhs_basic_type, rhs_basic_type, new_operator);
+        case ast::BinaryOp::kXor:
+            return CanReplaceXorWith(lhs_basic_type, rhs_basic_type, new_operator);
+        case ast::BinaryOp::kShiftLeft:
+        case ast::BinaryOp::kShiftRight:
+            return CanReplaceShiftLeftShiftRightWith(lhs_basic_type, rhs_basic_type, new_operator);
+        case ast::BinaryOp::kLogicalAnd:
+        case ast::BinaryOp::kLogicalOr:
+            return CanReplaceLogicalAndLogicalOrWith(new_operator);
+        case ast::BinaryOp::kEqual:
+        case ast::BinaryOp::kNotEqual:
+            return CanReplaceEqualNotEqualWith(lhs_basic_type, new_operator);
+        case ast::BinaryOp::kLessThan:
+        case ast::BinaryOp::kLessThanEqual:
+        case ast::BinaryOp::kGreaterThan:
+        case ast::BinaryOp::kGreaterThanEqual:
+        case ast::BinaryOp::kNone:
+            return CanReplaceLessThanLessThanEqualGreaterThanGreaterThanEqualWith(new_operator);
+            assert(false && "Unreachable");
+            return false;
+    }
 }
 
-bool MutationChangeBinaryOperator::IsApplicable(
-    const Program& program,
-    const NodeIdMap& node_id_map) const {
-  const auto* binary_expr_node =
-      As<ast::BinaryExpression>(node_id_map.GetNode(message_.binary_expr_id()));
-  if (binary_expr_node == nullptr) {
-    // Either the id does not exist, or does not correspond to a binary
-    // expression.
-    return false;
-  }
-  // Check whether the replacement is acceptable.
-  const auto new_operator = static_cast<ast::BinaryOp>(message_.new_operator());
-  return CanReplaceBinaryOperator(program, *binary_expr_node, new_operator);
+bool MutationChangeBinaryOperator::IsApplicable(const Program& program,
+                                                const NodeIdMap& node_id_map) const {
+    const auto* binary_expr_node =
+        As<ast::BinaryExpression>(node_id_map.GetNode(message_.binary_expr_id()));
+    if (binary_expr_node == nullptr) {
+        // Either the id does not exist, or does not correspond to a binary
+        // expression.
+        return false;
+    }
+    // Check whether the replacement is acceptable.
+    const auto new_operator = static_cast<ast::BinaryOp>(message_.new_operator());
+    return CanReplaceBinaryOperator(program, *binary_expr_node, new_operator);
 }
 
 void MutationChangeBinaryOperator::Apply(const NodeIdMap& node_id_map,
                                          CloneContext* clone_context,
                                          NodeIdMap* new_node_id_map) const {
-  // Get the node whose operator is to be replaced.
-  const auto* binary_expr_node =
-      As<ast::BinaryExpression>(node_id_map.GetNode(message_.binary_expr_id()));
+    // Get the node whose operator is to be replaced.
+    const auto* binary_expr_node =
+        As<ast::BinaryExpression>(node_id_map.GetNode(message_.binary_expr_id()));
 
-  // Clone the binary expression, with the appropriate new operator.
-  const ast::BinaryExpression* cloned_replacement;
-  switch (static_cast<ast::BinaryOp>(message_.new_operator())) {
-    case ast::BinaryOp::kAnd:
-      cloned_replacement =
-          clone_context->dst->And(clone_context->Clone(binary_expr_node->lhs),
-                                  clone_context->Clone(binary_expr_node->rhs));
-      break;
-    case ast::BinaryOp::kOr:
-      cloned_replacement =
-          clone_context->dst->Or(clone_context->Clone(binary_expr_node->lhs),
-                                 clone_context->Clone(binary_expr_node->rhs));
-      break;
-    case ast::BinaryOp::kXor:
-      cloned_replacement =
-          clone_context->dst->Xor(clone_context->Clone(binary_expr_node->lhs),
-                                  clone_context->Clone(binary_expr_node->rhs));
-      break;
-    case ast::BinaryOp::kLogicalAnd:
-      cloned_replacement = clone_context->dst->LogicalAnd(
-          clone_context->Clone(binary_expr_node->lhs),
-          clone_context->Clone(binary_expr_node->rhs));
-      break;
-    case ast::BinaryOp::kLogicalOr:
-      cloned_replacement = clone_context->dst->LogicalOr(
-          clone_context->Clone(binary_expr_node->lhs),
-          clone_context->Clone(binary_expr_node->rhs));
-      break;
-    case ast::BinaryOp::kEqual:
-      cloned_replacement = clone_context->dst->Equal(
-          clone_context->Clone(binary_expr_node->lhs),
-          clone_context->Clone(binary_expr_node->rhs));
-      break;
-    case ast::BinaryOp::kNotEqual:
-      cloned_replacement = clone_context->dst->NotEqual(
-          clone_context->Clone(binary_expr_node->lhs),
-          clone_context->Clone(binary_expr_node->rhs));
-      break;
-    case ast::BinaryOp::kLessThan:
-      cloned_replacement = clone_context->dst->LessThan(
-          clone_context->Clone(binary_expr_node->lhs),
-          clone_context->Clone(binary_expr_node->rhs));
-      break;
-    case ast::BinaryOp::kGreaterThan:
-      cloned_replacement = clone_context->dst->GreaterThan(
-          clone_context->Clone(binary_expr_node->lhs),
-          clone_context->Clone(binary_expr_node->rhs));
-      break;
-    case ast::BinaryOp::kLessThanEqual:
-      cloned_replacement = clone_context->dst->LessThanEqual(
-          clone_context->Clone(binary_expr_node->lhs),
-          clone_context->Clone(binary_expr_node->rhs));
-      break;
-    case ast::BinaryOp::kGreaterThanEqual:
-      cloned_replacement = clone_context->dst->GreaterThanEqual(
-          clone_context->Clone(binary_expr_node->lhs),
-          clone_context->Clone(binary_expr_node->rhs));
-      break;
-    case ast::BinaryOp::kShiftLeft:
-      cloned_replacement =
-          clone_context->dst->Shl(clone_context->Clone(binary_expr_node->lhs),
-                                  clone_context->Clone(binary_expr_node->rhs));
-      break;
-    case ast::BinaryOp::kShiftRight:
-      cloned_replacement =
-          clone_context->dst->Shr(clone_context->Clone(binary_expr_node->lhs),
-                                  clone_context->Clone(binary_expr_node->rhs));
-      break;
-    case ast::BinaryOp::kAdd:
-      cloned_replacement =
-          clone_context->dst->Add(clone_context->Clone(binary_expr_node->lhs),
-                                  clone_context->Clone(binary_expr_node->rhs));
-      break;
-    case ast::BinaryOp::kSubtract:
-      cloned_replacement =
-          clone_context->dst->Sub(clone_context->Clone(binary_expr_node->lhs),
-                                  clone_context->Clone(binary_expr_node->rhs));
-      break;
-    case ast::BinaryOp::kMultiply:
-      cloned_replacement =
-          clone_context->dst->Mul(clone_context->Clone(binary_expr_node->lhs),
-                                  clone_context->Clone(binary_expr_node->rhs));
-      break;
-    case ast::BinaryOp::kDivide:
-      cloned_replacement =
-          clone_context->dst->Div(clone_context->Clone(binary_expr_node->lhs),
-                                  clone_context->Clone(binary_expr_node->rhs));
-      break;
-    case ast::BinaryOp::kModulo:
-      cloned_replacement =
-          clone_context->dst->Mod(clone_context->Clone(binary_expr_node->lhs),
-                                  clone_context->Clone(binary_expr_node->rhs));
-      break;
-    case ast::BinaryOp::kNone:
-      cloned_replacement = nullptr;
-      assert(false && "Unreachable");
-  }
-  // Set things up so that the original binary expression will be replaced with
-  // its clone, and update the id mapping.
-  clone_context->Replace(binary_expr_node, cloned_replacement);
-  new_node_id_map->Add(cloned_replacement, message_.binary_expr_id());
+    // Clone the binary expression, with the appropriate new operator.
+    const ast::BinaryExpression* cloned_replacement;
+    switch (static_cast<ast::BinaryOp>(message_.new_operator())) {
+        case ast::BinaryOp::kAnd:
+            cloned_replacement =
+                clone_context->dst->And(clone_context->Clone(binary_expr_node->lhs),
+                                        clone_context->Clone(binary_expr_node->rhs));
+            break;
+        case ast::BinaryOp::kOr:
+            cloned_replacement =
+                clone_context->dst->Or(clone_context->Clone(binary_expr_node->lhs),
+                                       clone_context->Clone(binary_expr_node->rhs));
+            break;
+        case ast::BinaryOp::kXor:
+            cloned_replacement =
+                clone_context->dst->Xor(clone_context->Clone(binary_expr_node->lhs),
+                                        clone_context->Clone(binary_expr_node->rhs));
+            break;
+        case ast::BinaryOp::kLogicalAnd:
+            cloned_replacement =
+                clone_context->dst->LogicalAnd(clone_context->Clone(binary_expr_node->lhs),
+                                               clone_context->Clone(binary_expr_node->rhs));
+            break;
+        case ast::BinaryOp::kLogicalOr:
+            cloned_replacement =
+                clone_context->dst->LogicalOr(clone_context->Clone(binary_expr_node->lhs),
+                                              clone_context->Clone(binary_expr_node->rhs));
+            break;
+        case ast::BinaryOp::kEqual:
+            cloned_replacement =
+                clone_context->dst->Equal(clone_context->Clone(binary_expr_node->lhs),
+                                          clone_context->Clone(binary_expr_node->rhs));
+            break;
+        case ast::BinaryOp::kNotEqual:
+            cloned_replacement =
+                clone_context->dst->NotEqual(clone_context->Clone(binary_expr_node->lhs),
+                                             clone_context->Clone(binary_expr_node->rhs));
+            break;
+        case ast::BinaryOp::kLessThan:
+            cloned_replacement =
+                clone_context->dst->LessThan(clone_context->Clone(binary_expr_node->lhs),
+                                             clone_context->Clone(binary_expr_node->rhs));
+            break;
+        case ast::BinaryOp::kGreaterThan:
+            cloned_replacement =
+                clone_context->dst->GreaterThan(clone_context->Clone(binary_expr_node->lhs),
+                                                clone_context->Clone(binary_expr_node->rhs));
+            break;
+        case ast::BinaryOp::kLessThanEqual:
+            cloned_replacement =
+                clone_context->dst->LessThanEqual(clone_context->Clone(binary_expr_node->lhs),
+                                                  clone_context->Clone(binary_expr_node->rhs));
+            break;
+        case ast::BinaryOp::kGreaterThanEqual:
+            cloned_replacement =
+                clone_context->dst->GreaterThanEqual(clone_context->Clone(binary_expr_node->lhs),
+                                                     clone_context->Clone(binary_expr_node->rhs));
+            break;
+        case ast::BinaryOp::kShiftLeft:
+            cloned_replacement =
+                clone_context->dst->Shl(clone_context->Clone(binary_expr_node->lhs),
+                                        clone_context->Clone(binary_expr_node->rhs));
+            break;
+        case ast::BinaryOp::kShiftRight:
+            cloned_replacement =
+                clone_context->dst->Shr(clone_context->Clone(binary_expr_node->lhs),
+                                        clone_context->Clone(binary_expr_node->rhs));
+            break;
+        case ast::BinaryOp::kAdd:
+            cloned_replacement =
+                clone_context->dst->Add(clone_context->Clone(binary_expr_node->lhs),
+                                        clone_context->Clone(binary_expr_node->rhs));
+            break;
+        case ast::BinaryOp::kSubtract:
+            cloned_replacement =
+                clone_context->dst->Sub(clone_context->Clone(binary_expr_node->lhs),
+                                        clone_context->Clone(binary_expr_node->rhs));
+            break;
+        case ast::BinaryOp::kMultiply:
+            cloned_replacement =
+                clone_context->dst->Mul(clone_context->Clone(binary_expr_node->lhs),
+                                        clone_context->Clone(binary_expr_node->rhs));
+            break;
+        case ast::BinaryOp::kDivide:
+            cloned_replacement =
+                clone_context->dst->Div(clone_context->Clone(binary_expr_node->lhs),
+                                        clone_context->Clone(binary_expr_node->rhs));
+            break;
+        case ast::BinaryOp::kModulo:
+            cloned_replacement =
+                clone_context->dst->Mod(clone_context->Clone(binary_expr_node->lhs),
+                                        clone_context->Clone(binary_expr_node->rhs));
+            break;
+        case ast::BinaryOp::kNone:
+            cloned_replacement = nullptr;
+            assert(false && "Unreachable");
+    }
+    // Set things up so that the original binary expression will be replaced with
+    // its clone, and update the id mapping.
+    clone_context->Replace(binary_expr_node, cloned_replacement);
+    new_node_id_map->Add(cloned_replacement, message_.binary_expr_id());
 }
 
 protobufs::Mutation MutationChangeBinaryOperator::ToMessage() const {
-  protobufs::Mutation mutation;
-  *mutation.mutable_change_binary_operator() = message_;
-  return mutation;
+    protobufs::Mutation mutation;
+    *mutation.mutable_change_binary_operator() = message_;
+    return mutation;
 }
 
 }  // namespace tint::fuzzers::ast_fuzzer
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/mutations/change_binary_operator.h b/src/tint/fuzzers/tint_ast_fuzzer/mutations/change_binary_operator.h
index 9ce3890..cc80da3 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/mutations/change_binary_operator.h
+++ b/src/tint/fuzzers/tint_ast_fuzzer/mutations/change_binary_operator.h
@@ -25,55 +25,52 @@
 
 /// @see MutationChangeBinaryOperator::Apply
 class MutationChangeBinaryOperator : public Mutation {
- public:
-  /// @brief Constructs an instance of this mutation from a protobuf message.
-  /// @param message - protobuf message
-  explicit MutationChangeBinaryOperator(
-      protobufs::MutationChangeBinaryOperator message);
+  public:
+    /// @brief Constructs an instance of this mutation from a protobuf message.
+    /// @param message - protobuf message
+    explicit MutationChangeBinaryOperator(protobufs::MutationChangeBinaryOperator message);
 
-  /// @brief Constructor.
-  /// @param binary_expr_id - the id of a binary expression.
-  /// @param new_operator - a new binary operator to replace the one used in the
-  /// expression.
-  MutationChangeBinaryOperator(uint32_t binary_expr_id,
-                               ast::BinaryOp new_operator);
+    /// @brief Constructor.
+    /// @param binary_expr_id - the id of a binary expression.
+    /// @param new_operator - a new binary operator to replace the one used in the
+    /// expression.
+    MutationChangeBinaryOperator(uint32_t binary_expr_id, ast::BinaryOp new_operator);
 
-  /// @copybrief Mutation::IsApplicable
-  ///
-  /// The mutation is applicable iff:
-  /// - `binary_expr_id` is a valid id of an `ast::BinaryExpression`.
-  /// - `new_operator` is type-compatible with the arguments of the binary
-  /// expression.
-  ///
-  /// @copydetails Mutation::IsApplicable
-  bool IsApplicable(const tint::Program& program,
-                    const NodeIdMap& node_id_map) const override;
+    /// @copybrief Mutation::IsApplicable
+    ///
+    /// The mutation is applicable iff:
+    /// - `binary_expr_id` is a valid id of an `ast::BinaryExpression`.
+    /// - `new_operator` is type-compatible with the arguments of the binary
+    /// expression.
+    ///
+    /// @copydetails Mutation::IsApplicable
+    bool IsApplicable(const tint::Program& program, const NodeIdMap& node_id_map) const override;
 
-  /// @copybrief Mutation::Apply
-  ///
-  /// Replaces binary operator in the binary expression corresponding to
-  /// `binary_expr_id` with `new_operator`.
-  ///
-  /// @copydetails Mutation::Apply
-  void Apply(const NodeIdMap& node_id_map,
-             tint::CloneContext* clone_context,
-             NodeIdMap* new_node_id_map) const override;
+    /// @copybrief Mutation::Apply
+    ///
+    /// Replaces binary operator in the binary expression corresponding to
+    /// `binary_expr_id` with `new_operator`.
+    ///
+    /// @copydetails Mutation::Apply
+    void Apply(const NodeIdMap& node_id_map,
+               tint::CloneContext* clone_context,
+               NodeIdMap* new_node_id_map) const override;
 
-  protobufs::Mutation ToMessage() const override;
+    protobufs::Mutation ToMessage() const override;
 
-  /// @brief Determines whether replacing the operator of a binary expression
-  ///     with another operator would preserve well-typedness.
-  /// @param program - the program that owns the binary expression.
-  /// @param binary_expr - the binary expression being considered for mutation.
-  /// @param new_operator - a new binary operator to be checked as a candidate
-  ///     replacement for the binary expression's operator.
-  /// @return `true` if and only if the replacement would be well-typed.
-  static bool CanReplaceBinaryOperator(const Program& program,
-                                       const ast::BinaryExpression& binary_expr,
-                                       ast::BinaryOp new_operator);
+    /// @brief Determines whether replacing the operator of a binary expression
+    ///     with another operator would preserve well-typedness.
+    /// @param program - the program that owns the binary expression.
+    /// @param binary_expr - the binary expression being considered for mutation.
+    /// @param new_operator - a new binary operator to be checked as a candidate
+    ///     replacement for the binary expression's operator.
+    /// @return `true` if and only if the replacement would be well-typed.
+    static bool CanReplaceBinaryOperator(const Program& program,
+                                         const ast::BinaryExpression& binary_expr,
+                                         ast::BinaryOp new_operator);
 
- private:
-  protobufs::MutationChangeBinaryOperator message_;
+  private:
+    protobufs::MutationChangeBinaryOperator message_;
 };
 
 }  // namespace tint::fuzzers::ast_fuzzer
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/mutations/change_binary_operator_test.cc b/src/tint/fuzzers/tint_ast_fuzzer/mutations/change_binary_operator_test.cc
index f8a9d90..1de527c 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/mutations/change_binary_operator_test.cc
+++ b/src/tint/fuzzers/tint_ast_fuzzer/mutations/change_binary_operator_test.cc
@@ -30,690 +30,599 @@
 namespace {
 
 std::string OpToString(ast::BinaryOp op) {
-  switch (op) {
-    case ast::BinaryOp::kNone:
-      assert(false && "Unreachable");
-      return "";
-    case ast::BinaryOp::kAnd:
-      return "&";
-    case ast::BinaryOp::kOr:
-      return "|";
-    case ast::BinaryOp::kXor:
-      return "^";
-    case ast::BinaryOp::kLogicalAnd:
-      return "&&";
-    case ast::BinaryOp::kLogicalOr:
-      return "||";
-    case ast::BinaryOp::kEqual:
-      return "==";
-    case ast::BinaryOp::kNotEqual:
-      return "!=";
-    case ast::BinaryOp::kLessThan:
-      return "<";
-    case ast::BinaryOp::kGreaterThan:
-      return ">";
-    case ast::BinaryOp::kLessThanEqual:
-      return "<=";
-    case ast::BinaryOp::kGreaterThanEqual:
-      return ">=";
-    case ast::BinaryOp::kShiftLeft:
-      return "<<";
-    case ast::BinaryOp::kShiftRight:
-      return ">>";
-    case ast::BinaryOp::kAdd:
-      return "+";
-    case ast::BinaryOp::kSubtract:
-      return "-";
-    case ast::BinaryOp::kMultiply:
-      return "*";
-    case ast::BinaryOp::kDivide:
-      return "/";
-    case ast::BinaryOp::kModulo:
-      return "%";
-  }
+    switch (op) {
+        case ast::BinaryOp::kNone:
+            assert(false && "Unreachable");
+            return "";
+        case ast::BinaryOp::kAnd:
+            return "&";
+        case ast::BinaryOp::kOr:
+            return "|";
+        case ast::BinaryOp::kXor:
+            return "^";
+        case ast::BinaryOp::kLogicalAnd:
+            return "&&";
+        case ast::BinaryOp::kLogicalOr:
+            return "||";
+        case ast::BinaryOp::kEqual:
+            return "==";
+        case ast::BinaryOp::kNotEqual:
+            return "!=";
+        case ast::BinaryOp::kLessThan:
+            return "<";
+        case ast::BinaryOp::kGreaterThan:
+            return ">";
+        case ast::BinaryOp::kLessThanEqual:
+            return "<=";
+        case ast::BinaryOp::kGreaterThanEqual:
+            return ">=";
+        case ast::BinaryOp::kShiftLeft:
+            return "<<";
+        case ast::BinaryOp::kShiftRight:
+            return ">>";
+        case ast::BinaryOp::kAdd:
+            return "+";
+        case ast::BinaryOp::kSubtract:
+            return "-";
+        case ast::BinaryOp::kMultiply:
+            return "*";
+        case ast::BinaryOp::kDivide:
+            return "/";
+        case ast::BinaryOp::kModulo:
+            return "%";
+    }
 }
 
 TEST(ChangeBinaryOperatorTest, NotApplicable_Simple) {
-  std::string content = R"(
+    std::string content = R"(
     fn main() {
       let a : i32 = 1 + 2;
     }
   )";
-  Source::File file("test.wgsl", content);
-  auto program = reader::wgsl::Parse(&file);
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
-
-  NodeIdMap node_id_map(program);
-
-  const auto& main_fn_stmts = program.AST().Functions()[0]->body->statements;
-
-  const auto* a_var =
-      main_fn_stmts[0]->As<ast::VariableDeclStatement>()->variable;
-  ASSERT_NE(a_var, nullptr);
-
-  auto a_var_id = node_id_map.GetId(a_var);
-
-  const auto* sum_expr = a_var->constructor->As<ast::BinaryExpression>();
-  ASSERT_NE(sum_expr, nullptr);
-
-  auto sum_expr_id = node_id_map.GetId(sum_expr);
-  ASSERT_NE(sum_expr_id, 0);
-
-  // binary_expr_id is invalid.
-  EXPECT_FALSE(MutationChangeBinaryOperator(0, ast::BinaryOp::kSubtract)
-                   .IsApplicable(program, node_id_map));
-
-  // binary_expr_id is not a binary expression.
-  EXPECT_FALSE(MutationChangeBinaryOperator(a_var_id, ast::BinaryOp::kSubtract)
-                   .IsApplicable(program, node_id_map));
-
-  // new_operator is applicable to the argument types.
-  EXPECT_FALSE(MutationChangeBinaryOperator(0, ast::BinaryOp::kLogicalAnd)
-                   .IsApplicable(program, node_id_map));
-
-  // new_operator does not have the right result type.
-  EXPECT_FALSE(MutationChangeBinaryOperator(0, ast::BinaryOp::kLessThan)
-                   .IsApplicable(program, node_id_map));
-}
-
-TEST(ChangeBinaryOperatorTest, Applicable_Simple) {
-  std::string shader = R"(fn main() {
-  let a : i32 = (1 + 2);
-}
-)";
-  Source::File file("test.wgsl", shader);
-  auto program = reader::wgsl::Parse(&file);
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
-
-  NodeIdMap node_id_map(program);
-
-  const auto& main_fn_stmts = program.AST().Functions()[0]->body->statements;
-
-  const auto* a_var =
-      main_fn_stmts[0]->As<ast::VariableDeclStatement>()->variable;
-  ASSERT_NE(a_var, nullptr);
-
-  const auto* sum_expr = a_var->constructor->As<ast::BinaryExpression>();
-  ASSERT_NE(sum_expr, nullptr);
-
-  auto sum_expr_id = node_id_map.GetId(sum_expr);
-  ASSERT_NE(sum_expr_id, 0);
-
-  ASSERT_TRUE(MaybeApplyMutation(
-      program,
-      MutationChangeBinaryOperator(sum_expr_id, ast::BinaryOp::kSubtract),
-      node_id_map, &program, &node_id_map, nullptr));
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
-
-  writer::wgsl::Options options;
-  auto result = writer::wgsl::Generate(&program, options);
-  ASSERT_TRUE(result.success) << result.error;
-
-  std::string expected_shader = R"(fn main() {
-  let a : i32 = (1 - 2);
-}
-)";
-  ASSERT_EQ(expected_shader, result.wgsl);
-}
-
-void CheckMutations(
-    const std::string& lhs_type,
-    const std::string& rhs_type,
-    const std::string& result_type,
-    ast::BinaryOp original_operator,
-    const std::unordered_set<ast::BinaryOp>& allowed_replacement_operators) {
-  std::stringstream shader;
-  shader << "fn foo(a : " << lhs_type << ", b : " << rhs_type + ") {\n"
-         << "  let r : " << result_type
-         << " = (a " + OpToString(original_operator) << " b);\n}\n";
-
-  const std::vector<ast::BinaryOp> all_operators = {
-      ast::BinaryOp::kAnd,
-      ast::BinaryOp::kOr,
-      ast::BinaryOp::kXor,
-      ast::BinaryOp::kLogicalAnd,
-      ast::BinaryOp::kLogicalOr,
-      ast::BinaryOp::kEqual,
-      ast::BinaryOp::kNotEqual,
-      ast::BinaryOp::kLessThan,
-      ast::BinaryOp::kGreaterThan,
-      ast::BinaryOp::kLessThanEqual,
-      ast::BinaryOp::kGreaterThanEqual,
-      ast::BinaryOp::kShiftLeft,
-      ast::BinaryOp::kShiftRight,
-      ast::BinaryOp::kAdd,
-      ast::BinaryOp::kSubtract,
-      ast::BinaryOp::kMultiply,
-      ast::BinaryOp::kDivide,
-      ast::BinaryOp::kModulo};
-
-  for (auto new_operator : all_operators) {
-    Source::File file("test.wgsl", shader.str());
+    Source::File file("test.wgsl", content);
     auto program = reader::wgsl::Parse(&file);
     ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
     NodeIdMap node_id_map(program);
 
-    const auto& stmts = program.AST().Functions()[0]->body->statements;
+    const auto& main_fn_stmts = program.AST().Functions()[0]->body->statements;
 
-    const auto* r_var = stmts[0]->As<ast::VariableDeclStatement>()->variable;
-    ASSERT_NE(r_var, nullptr);
+    const auto* a_var = main_fn_stmts[0]->As<ast::VariableDeclStatement>()->variable;
+    ASSERT_NE(a_var, nullptr);
 
-    const auto* binary_expr = r_var->constructor->As<ast::BinaryExpression>();
-    ASSERT_NE(binary_expr, nullptr);
+    auto a_var_id = node_id_map.GetId(a_var);
 
-    auto binary_expr_id = node_id_map.GetId(binary_expr);
-    ASSERT_NE(binary_expr_id, 0);
+    const auto* sum_expr = a_var->constructor->As<ast::BinaryExpression>();
+    ASSERT_NE(sum_expr, nullptr);
 
-    MutationChangeBinaryOperator mutation(binary_expr_id, new_operator);
+    auto sum_expr_id = node_id_map.GetId(sum_expr);
+    ASSERT_NE(sum_expr_id, 0);
 
-    std::stringstream expected_shader;
-    expected_shader << "fn foo(a : " << lhs_type << ", b : " << rhs_type
-                    << ") {\n"
-                    << "  let r : " << result_type << " = (a "
-                    << OpToString(new_operator) << " b);\n}\n";
+    // binary_expr_id is invalid.
+    EXPECT_FALSE(MutationChangeBinaryOperator(0, ast::BinaryOp::kSubtract)
+                     .IsApplicable(program, node_id_map));
 
-    if (allowed_replacement_operators.count(new_operator) == 0) {
-      ASSERT_FALSE(mutation.IsApplicable(program, node_id_map));
-      if (new_operator != binary_expr->op) {
-        Source::File invalid_file("test.wgsl", expected_shader.str());
-        auto invalid_program = reader::wgsl::Parse(&invalid_file);
-        ASSERT_FALSE(invalid_program.IsValid()) << program.Diagnostics().str();
-      }
-    } else {
-      ASSERT_TRUE(MaybeApplyMutation(program, mutation, node_id_map, &program,
-                                     &node_id_map, nullptr));
-      ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    // binary_expr_id is not a binary expression.
+    EXPECT_FALSE(MutationChangeBinaryOperator(a_var_id, ast::BinaryOp::kSubtract)
+                     .IsApplicable(program, node_id_map));
 
-      writer::wgsl::Options options;
-      auto result = writer::wgsl::Generate(&program, options);
-      ASSERT_TRUE(result.success) << result.error;
+    // new_operator is applicable to the argument types.
+    EXPECT_FALSE(MutationChangeBinaryOperator(0, ast::BinaryOp::kLogicalAnd)
+                     .IsApplicable(program, node_id_map));
 
-      ASSERT_EQ(expected_shader.str(), result.wgsl);
+    // new_operator does not have the right result type.
+    EXPECT_FALSE(MutationChangeBinaryOperator(0, ast::BinaryOp::kLessThan)
+                     .IsApplicable(program, node_id_map));
+}
+
+TEST(ChangeBinaryOperatorTest, Applicable_Simple) {
+    std::string shader = R"(fn main() {
+  let a : i32 = (1 + 2);
+}
+)";
+    Source::File file("test.wgsl", shader);
+    auto program = reader::wgsl::Parse(&file);
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+
+    NodeIdMap node_id_map(program);
+
+    const auto& main_fn_stmts = program.AST().Functions()[0]->body->statements;
+
+    const auto* a_var = main_fn_stmts[0]->As<ast::VariableDeclStatement>()->variable;
+    ASSERT_NE(a_var, nullptr);
+
+    const auto* sum_expr = a_var->constructor->As<ast::BinaryExpression>();
+    ASSERT_NE(sum_expr, nullptr);
+
+    auto sum_expr_id = node_id_map.GetId(sum_expr);
+    ASSERT_NE(sum_expr_id, 0);
+
+    ASSERT_TRUE(MaybeApplyMutation(
+        program, MutationChangeBinaryOperator(sum_expr_id, ast::BinaryOp::kSubtract), node_id_map,
+        &program, &node_id_map, nullptr));
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+
+    writer::wgsl::Options options;
+    auto result = writer::wgsl::Generate(&program, options);
+    ASSERT_TRUE(result.success) << result.error;
+
+    std::string expected_shader = R"(fn main() {
+  let a : i32 = (1 - 2);
+}
+)";
+    ASSERT_EQ(expected_shader, result.wgsl);
+}
+
+void CheckMutations(const std::string& lhs_type,
+                    const std::string& rhs_type,
+                    const std::string& result_type,
+                    ast::BinaryOp original_operator,
+                    const std::unordered_set<ast::BinaryOp>& allowed_replacement_operators) {
+    std::stringstream shader;
+    shader << "fn foo(a : " << lhs_type << ", b : " << rhs_type + ") {\n"
+           << "  let r : " << result_type << " = (a " + OpToString(original_operator)
+           << " b);\n}\n";
+
+    const std::vector<ast::BinaryOp> all_operators = {ast::BinaryOp::kAnd,
+                                                      ast::BinaryOp::kOr,
+                                                      ast::BinaryOp::kXor,
+                                                      ast::BinaryOp::kLogicalAnd,
+                                                      ast::BinaryOp::kLogicalOr,
+                                                      ast::BinaryOp::kEqual,
+                                                      ast::BinaryOp::kNotEqual,
+                                                      ast::BinaryOp::kLessThan,
+                                                      ast::BinaryOp::kGreaterThan,
+                                                      ast::BinaryOp::kLessThanEqual,
+                                                      ast::BinaryOp::kGreaterThanEqual,
+                                                      ast::BinaryOp::kShiftLeft,
+                                                      ast::BinaryOp::kShiftRight,
+                                                      ast::BinaryOp::kAdd,
+                                                      ast::BinaryOp::kSubtract,
+                                                      ast::BinaryOp::kMultiply,
+                                                      ast::BinaryOp::kDivide,
+                                                      ast::BinaryOp::kModulo};
+
+    for (auto new_operator : all_operators) {
+        Source::File file("test.wgsl", shader.str());
+        auto program = reader::wgsl::Parse(&file);
+        ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+
+        NodeIdMap node_id_map(program);
+
+        const auto& stmts = program.AST().Functions()[0]->body->statements;
+
+        const auto* r_var = stmts[0]->As<ast::VariableDeclStatement>()->variable;
+        ASSERT_NE(r_var, nullptr);
+
+        const auto* binary_expr = r_var->constructor->As<ast::BinaryExpression>();
+        ASSERT_NE(binary_expr, nullptr);
+
+        auto binary_expr_id = node_id_map.GetId(binary_expr);
+        ASSERT_NE(binary_expr_id, 0);
+
+        MutationChangeBinaryOperator mutation(binary_expr_id, new_operator);
+
+        std::stringstream expected_shader;
+        expected_shader << "fn foo(a : " << lhs_type << ", b : " << rhs_type << ") {\n"
+                        << "  let r : " << result_type << " = (a " << OpToString(new_operator)
+                        << " b);\n}\n";
+
+        if (allowed_replacement_operators.count(new_operator) == 0) {
+            ASSERT_FALSE(mutation.IsApplicable(program, node_id_map));
+            if (new_operator != binary_expr->op) {
+                Source::File invalid_file("test.wgsl", expected_shader.str());
+                auto invalid_program = reader::wgsl::Parse(&invalid_file);
+                ASSERT_FALSE(invalid_program.IsValid()) << program.Diagnostics().str();
+            }
+        } else {
+            ASSERT_TRUE(MaybeApplyMutation(program, mutation, node_id_map, &program, &node_id_map,
+                                           nullptr));
+            ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+
+            writer::wgsl::Options options;
+            auto result = writer::wgsl::Generate(&program, options);
+            ASSERT_TRUE(result.success) << result.error;
+
+            ASSERT_EQ(expected_shader.str(), result.wgsl);
+        }
     }
-  }
 }
 
 TEST(ChangeBinaryOperatorTest, AddSubtract) {
-  for (auto op : {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract}) {
-    const ast::BinaryOp other_op = op == ast::BinaryOp::kAdd
-                                       ? ast::BinaryOp::kSubtract
-                                       : ast::BinaryOp::kAdd;
-    for (std::string type : {"i32", "vec2<i32>", "vec3<i32>", "vec4<i32>"}) {
-      CheckMutations(
-          type, type, type, op,
-          {other_op, ast::BinaryOp::kMultiply, ast::BinaryOp::kDivide,
-           ast::BinaryOp::kModulo, ast::BinaryOp::kAnd, ast::BinaryOp::kOr,
-           ast::BinaryOp::kXor});
+    for (auto op : {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract}) {
+        const ast::BinaryOp other_op =
+            op == ast::BinaryOp::kAdd ? ast::BinaryOp::kSubtract : ast::BinaryOp::kAdd;
+        for (std::string type : {"i32", "vec2<i32>", "vec3<i32>", "vec4<i32>"}) {
+            CheckMutations(
+                type, type, type, op,
+                {other_op, ast::BinaryOp::kMultiply, ast::BinaryOp::kDivide, ast::BinaryOp::kModulo,
+                 ast::BinaryOp::kAnd, ast::BinaryOp::kOr, ast::BinaryOp::kXor});
+        }
+        for (std::string type : {"u32", "vec2<u32>", "vec3<u32>", "vec4<u32>"}) {
+            CheckMutations(
+                type, type, type, op,
+                {other_op, ast::BinaryOp::kMultiply, ast::BinaryOp::kDivide, ast::BinaryOp::kModulo,
+                 ast::BinaryOp::kAnd, ast::BinaryOp::kOr, ast::BinaryOp::kXor,
+                 ast::BinaryOp::kShiftLeft, ast::BinaryOp::kShiftRight});
+        }
+        for (std::string type : {"f32", "vec2<f32>", "vec3<f32>", "vec4<f32>"}) {
+            CheckMutations(type, type, type, op,
+                           {other_op, ast::BinaryOp::kMultiply, ast::BinaryOp::kDivide,
+                            ast::BinaryOp::kModulo});
+        }
+        for (std::string vector_type : {"vec2<i32>", "vec3<i32>", "vec4<i32>"}) {
+            std::string scalar_type = "i32";
+            CheckMutations(vector_type, scalar_type, vector_type, op,
+                           {other_op, ast::BinaryOp::kMultiply, ast::BinaryOp::kDivide,
+                            ast::BinaryOp::kModulo});
+            CheckMutations(scalar_type, vector_type, vector_type, op,
+                           {other_op, ast::BinaryOp::kMultiply, ast::BinaryOp::kDivide,
+                            ast::BinaryOp::kModulo});
+        }
+        for (std::string vector_type : {"vec2<u32>", "vec3<u32>", "vec4<u32>"}) {
+            std::string scalar_type = "u32";
+            CheckMutations(vector_type, scalar_type, vector_type, op,
+                           {other_op, ast::BinaryOp::kMultiply, ast::BinaryOp::kDivide,
+                            ast::BinaryOp::kModulo});
+            CheckMutations(scalar_type, vector_type, vector_type, op,
+                           {other_op, ast::BinaryOp::kMultiply, ast::BinaryOp::kDivide,
+                            ast::BinaryOp::kModulo});
+        }
+        for (std::string vector_type : {"vec2<f32>", "vec3<f32>", "vec4<f32>"}) {
+            std::string scalar_type = "f32";
+            CheckMutations(vector_type, scalar_type, vector_type, op,
+                           {other_op, ast::BinaryOp::kMultiply, ast::BinaryOp::kDivide,
+                            ast::BinaryOp::kModulo});
+            CheckMutations(scalar_type, vector_type, vector_type, op,
+                           {other_op, ast::BinaryOp::kMultiply, ast::BinaryOp::kDivide,
+                            ast::BinaryOp::kModulo});
+        }
+        for (std::string square_matrix_type : {"mat2x2<f32>", "mat3x3<f32>", "mat4x4<f32>"}) {
+            CheckMutations(square_matrix_type, square_matrix_type, square_matrix_type, op,
+                           {other_op, ast::BinaryOp::kMultiply});
+        }
+        for (std::string non_square_matrix_type : {"mat2x3<f32>", "mat2x4<f32>", "mat3x2<f32>",
+                                                   "mat3x4<f32>", "mat4x2<f32>", "mat4x3<f32>"}) {
+            CheckMutations(non_square_matrix_type, non_square_matrix_type, non_square_matrix_type,
+                           op, {other_op});
+        }
     }
-    for (std::string type : {"u32", "vec2<u32>", "vec3<u32>", "vec4<u32>"}) {
-      CheckMutations(
-          type, type, type, op,
-          {other_op, ast::BinaryOp::kMultiply, ast::BinaryOp::kDivide,
-           ast::BinaryOp::kModulo, ast::BinaryOp::kAnd, ast::BinaryOp::kOr,
-           ast::BinaryOp::kXor, ast::BinaryOp::kShiftLeft,
-           ast::BinaryOp::kShiftRight});
-    }
-    for (std::string type : {"f32", "vec2<f32>", "vec3<f32>", "vec4<f32>"}) {
-      CheckMutations(type, type, type, op,
-                     {other_op, ast::BinaryOp::kMultiply,
-                      ast::BinaryOp::kDivide, ast::BinaryOp::kModulo});
-    }
-    for (std::string vector_type : {"vec2<i32>", "vec3<i32>", "vec4<i32>"}) {
-      std::string scalar_type = "i32";
-      CheckMutations(vector_type, scalar_type, vector_type, op,
-                     {other_op, ast::BinaryOp::kMultiply,
-                      ast::BinaryOp::kDivide, ast::BinaryOp::kModulo});
-      CheckMutations(scalar_type, vector_type, vector_type, op,
-                     {other_op, ast::BinaryOp::kMultiply,
-                      ast::BinaryOp::kDivide, ast::BinaryOp::kModulo});
-    }
-    for (std::string vector_type : {"vec2<u32>", "vec3<u32>", "vec4<u32>"}) {
-      std::string scalar_type = "u32";
-      CheckMutations(vector_type, scalar_type, vector_type, op,
-                     {other_op, ast::BinaryOp::kMultiply,
-                      ast::BinaryOp::kDivide, ast::BinaryOp::kModulo});
-      CheckMutations(scalar_type, vector_type, vector_type, op,
-                     {other_op, ast::BinaryOp::kMultiply,
-                      ast::BinaryOp::kDivide, ast::BinaryOp::kModulo});
-    }
-    for (std::string vector_type : {"vec2<f32>", "vec3<f32>", "vec4<f32>"}) {
-      std::string scalar_type = "f32";
-      CheckMutations(vector_type, scalar_type, vector_type, op,
-                     {other_op, ast::BinaryOp::kMultiply,
-                      ast::BinaryOp::kDivide, ast::BinaryOp::kModulo});
-      CheckMutations(scalar_type, vector_type, vector_type, op,
-                     {other_op, ast::BinaryOp::kMultiply,
-                      ast::BinaryOp::kDivide, ast::BinaryOp::kModulo});
-    }
-    for (std::string square_matrix_type :
-         {"mat2x2<f32>", "mat3x3<f32>", "mat4x4<f32>"}) {
-      CheckMutations(square_matrix_type, square_matrix_type, square_matrix_type,
-                     op, {other_op, ast::BinaryOp::kMultiply});
-    }
-    for (std::string non_square_matrix_type :
-         {"mat2x3<f32>", "mat2x4<f32>", "mat3x2<f32>", "mat3x4<f32>",
-          "mat4x2<f32>", "mat4x3<f32>"}) {
-      CheckMutations(non_square_matrix_type, non_square_matrix_type,
-                     non_square_matrix_type, op, {other_op});
-    }
-  }
 }
 
 TEST(ChangeBinaryOperatorTest, Mul) {
-  for (std::string type : {"i32", "vec2<i32>", "vec3<i32>", "vec4<i32>"}) {
-    CheckMutations(
-        type, type, type, ast::BinaryOp::kMultiply,
-        {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract, ast::BinaryOp::kDivide,
-         ast::BinaryOp::kModulo, ast::BinaryOp::kAnd, ast::BinaryOp::kOr,
-         ast::BinaryOp::kXor});
-  }
-  for (std::string type : {"u32", "vec2<u32>", "vec3<u32>", "vec4<u32>"}) {
-    CheckMutations(
-        type, type, type, ast::BinaryOp::kMultiply,
-        {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract, ast::BinaryOp::kDivide,
-         ast::BinaryOp::kModulo, ast::BinaryOp::kAnd, ast::BinaryOp::kOr,
-         ast::BinaryOp::kXor, ast::BinaryOp::kShiftLeft,
-         ast::BinaryOp::kShiftRight});
-  }
-  for (std::string type : {"f32", "vec2<f32>", "vec3<f32>", "vec4<f32>"}) {
-    CheckMutations(type, type, type, ast::BinaryOp::kMultiply,
-                   {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract,
-                    ast::BinaryOp::kDivide, ast::BinaryOp::kModulo});
-  }
-  for (std::string vector_type : {"vec2<i32>", "vec3<i32>", "vec4<i32>"}) {
-    std::string scalar_type = "i32";
-    CheckMutations(vector_type, scalar_type, vector_type,
-                   ast::BinaryOp::kMultiply,
-                   {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract,
-                    ast::BinaryOp::kDivide, ast::BinaryOp::kModulo});
-    CheckMutations(scalar_type, vector_type, vector_type,
-                   ast::BinaryOp::kMultiply,
-                   {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract,
-                    ast::BinaryOp::kDivide, ast::BinaryOp::kModulo});
-  }
-  for (std::string vector_type : {"vec2<u32>", "vec3<u32>", "vec4<u32>"}) {
-    std::string scalar_type = "u32";
-    CheckMutations(vector_type, scalar_type, vector_type,
-                   ast::BinaryOp::kMultiply,
-                   {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract,
-                    ast::BinaryOp::kDivide, ast::BinaryOp::kModulo});
-    CheckMutations(scalar_type, vector_type, vector_type,
-                   ast::BinaryOp::kMultiply,
-                   {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract,
-                    ast::BinaryOp::kDivide, ast::BinaryOp::kModulo});
-  }
-  for (std::string vector_type : {"vec2<f32>", "vec3<f32>", "vec4<f32>"}) {
-    std::string scalar_type = "f32";
-    CheckMutations(vector_type, scalar_type, vector_type,
-                   ast::BinaryOp::kMultiply,
-                   {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract,
-                    ast::BinaryOp::kDivide, ast::BinaryOp::kModulo});
-    CheckMutations(scalar_type, vector_type, vector_type,
-                   ast::BinaryOp::kMultiply,
-                   {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract,
-                    ast::BinaryOp::kDivide, ast::BinaryOp::kModulo});
-  }
-  for (std::string square_matrix_type :
-       {"mat2x2<f32>", "mat3x3<f32>", "mat4x4<f32>"}) {
-    CheckMutations(square_matrix_type, square_matrix_type, square_matrix_type,
-                   ast::BinaryOp::kMultiply,
-                   {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract});
-  }
+    for (std::string type : {"i32", "vec2<i32>", "vec3<i32>", "vec4<i32>"}) {
+        CheckMutations(
+            type, type, type, ast::BinaryOp::kMultiply,
+            {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract, ast::BinaryOp::kDivide,
+             ast::BinaryOp::kModulo, ast::BinaryOp::kAnd, ast::BinaryOp::kOr, ast::BinaryOp::kXor});
+    }
+    for (std::string type : {"u32", "vec2<u32>", "vec3<u32>", "vec4<u32>"}) {
+        CheckMutations(
+            type, type, type, ast::BinaryOp::kMultiply,
+            {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract, ast::BinaryOp::kDivide,
+             ast::BinaryOp::kModulo, ast::BinaryOp::kAnd, ast::BinaryOp::kOr, ast::BinaryOp::kXor,
+             ast::BinaryOp::kShiftLeft, ast::BinaryOp::kShiftRight});
+    }
+    for (std::string type : {"f32", "vec2<f32>", "vec3<f32>", "vec4<f32>"}) {
+        CheckMutations(type, type, type, ast::BinaryOp::kMultiply,
+                       {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract, ast::BinaryOp::kDivide,
+                        ast::BinaryOp::kModulo});
+    }
+    for (std::string vector_type : {"vec2<i32>", "vec3<i32>", "vec4<i32>"}) {
+        std::string scalar_type = "i32";
+        CheckMutations(vector_type, scalar_type, vector_type, ast::BinaryOp::kMultiply,
+                       {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract, ast::BinaryOp::kDivide,
+                        ast::BinaryOp::kModulo});
+        CheckMutations(scalar_type, vector_type, vector_type, ast::BinaryOp::kMultiply,
+                       {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract, ast::BinaryOp::kDivide,
+                        ast::BinaryOp::kModulo});
+    }
+    for (std::string vector_type : {"vec2<u32>", "vec3<u32>", "vec4<u32>"}) {
+        std::string scalar_type = "u32";
+        CheckMutations(vector_type, scalar_type, vector_type, ast::BinaryOp::kMultiply,
+                       {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract, ast::BinaryOp::kDivide,
+                        ast::BinaryOp::kModulo});
+        CheckMutations(scalar_type, vector_type, vector_type, ast::BinaryOp::kMultiply,
+                       {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract, ast::BinaryOp::kDivide,
+                        ast::BinaryOp::kModulo});
+    }
+    for (std::string vector_type : {"vec2<f32>", "vec3<f32>", "vec4<f32>"}) {
+        std::string scalar_type = "f32";
+        CheckMutations(vector_type, scalar_type, vector_type, ast::BinaryOp::kMultiply,
+                       {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract, ast::BinaryOp::kDivide,
+                        ast::BinaryOp::kModulo});
+        CheckMutations(scalar_type, vector_type, vector_type, ast::BinaryOp::kMultiply,
+                       {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract, ast::BinaryOp::kDivide,
+                        ast::BinaryOp::kModulo});
+    }
+    for (std::string square_matrix_type : {"mat2x2<f32>", "mat3x3<f32>", "mat4x4<f32>"}) {
+        CheckMutations(square_matrix_type, square_matrix_type, square_matrix_type,
+                       ast::BinaryOp::kMultiply, {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract});
+    }
 
-  CheckMutations("vec2<f32>", "mat2x2<f32>", "vec2<f32>",
-                 ast::BinaryOp::kMultiply, {});
-  CheckMutations("vec2<f32>", "mat3x2<f32>", "vec3<f32>",
-                 ast::BinaryOp::kMultiply, {});
-  CheckMutations("vec2<f32>", "mat4x2<f32>", "vec4<f32>",
-                 ast::BinaryOp::kMultiply, {});
+    CheckMutations("vec2<f32>", "mat2x2<f32>", "vec2<f32>", ast::BinaryOp::kMultiply, {});
+    CheckMutations("vec2<f32>", "mat3x2<f32>", "vec3<f32>", ast::BinaryOp::kMultiply, {});
+    CheckMutations("vec2<f32>", "mat4x2<f32>", "vec4<f32>", ast::BinaryOp::kMultiply, {});
 
-  CheckMutations("mat2x2<f32>", "vec2<f32>", "vec2<f32>",
-                 ast::BinaryOp::kMultiply, {});
-  CheckMutations("mat2x2<f32>", "mat3x2<f32>", "mat3x2<f32>",
-                 ast::BinaryOp::kMultiply, {});
-  CheckMutations("mat2x2<f32>", "mat4x2<f32>", "mat4x2<f32>",
-                 ast::BinaryOp::kMultiply, {});
+    CheckMutations("mat2x2<f32>", "vec2<f32>", "vec2<f32>", ast::BinaryOp::kMultiply, {});
+    CheckMutations("mat2x2<f32>", "mat3x2<f32>", "mat3x2<f32>", ast::BinaryOp::kMultiply, {});
+    CheckMutations("mat2x2<f32>", "mat4x2<f32>", "mat4x2<f32>", ast::BinaryOp::kMultiply, {});
 
-  CheckMutations("mat2x3<f32>", "vec2<f32>", "vec3<f32>",
-                 ast::BinaryOp::kMultiply, {});
-  CheckMutations("mat2x3<f32>", "mat2x2<f32>", "mat2x3<f32>",
-                 ast::BinaryOp::kMultiply, {});
-  CheckMutations("mat2x3<f32>", "mat3x2<f32>", "mat3x3<f32>",
-                 ast::BinaryOp::kMultiply, {});
-  CheckMutations("mat2x3<f32>", "mat4x2<f32>", "mat4x3<f32>",
-                 ast::BinaryOp::kMultiply, {});
+    CheckMutations("mat2x3<f32>", "vec2<f32>", "vec3<f32>", ast::BinaryOp::kMultiply, {});
+    CheckMutations("mat2x3<f32>", "mat2x2<f32>", "mat2x3<f32>", ast::BinaryOp::kMultiply, {});
+    CheckMutations("mat2x3<f32>", "mat3x2<f32>", "mat3x3<f32>", ast::BinaryOp::kMultiply, {});
+    CheckMutations("mat2x3<f32>", "mat4x2<f32>", "mat4x3<f32>", ast::BinaryOp::kMultiply, {});
 
-  CheckMutations("mat2x4<f32>", "vec2<f32>", "vec4<f32>",
-                 ast::BinaryOp::kMultiply, {});
-  CheckMutations("mat2x4<f32>", "mat2x2<f32>", "mat2x4<f32>",
-                 ast::BinaryOp::kMultiply, {});
-  CheckMutations("mat2x4<f32>", "mat3x2<f32>", "mat3x4<f32>",
-                 ast::BinaryOp::kMultiply, {});
-  CheckMutations("mat2x4<f32>", "mat4x2<f32>", "mat4x4<f32>",
-                 ast::BinaryOp::kMultiply, {});
+    CheckMutations("mat2x4<f32>", "vec2<f32>", "vec4<f32>", ast::BinaryOp::kMultiply, {});
+    CheckMutations("mat2x4<f32>", "mat2x2<f32>", "mat2x4<f32>", ast::BinaryOp::kMultiply, {});
+    CheckMutations("mat2x4<f32>", "mat3x2<f32>", "mat3x4<f32>", ast::BinaryOp::kMultiply, {});
+    CheckMutations("mat2x4<f32>", "mat4x2<f32>", "mat4x4<f32>", ast::BinaryOp::kMultiply, {});
 
-  CheckMutations("vec3<f32>", "mat2x3<f32>", "vec2<f32>",
-                 ast::BinaryOp::kMultiply, {});
-  CheckMutations("vec3<f32>", "mat3x3<f32>", "vec3<f32>",
-                 ast::BinaryOp::kMultiply, {});
-  CheckMutations("vec3<f32>", "mat4x3<f32>", "vec4<f32>",
-                 ast::BinaryOp::kMultiply, {});
+    CheckMutations("vec3<f32>", "mat2x3<f32>", "vec2<f32>", ast::BinaryOp::kMultiply, {});
+    CheckMutations("vec3<f32>", "mat3x3<f32>", "vec3<f32>", ast::BinaryOp::kMultiply, {});
+    CheckMutations("vec3<f32>", "mat4x3<f32>", "vec4<f32>", ast::BinaryOp::kMultiply, {});
 
-  CheckMutations("mat3x2<f32>", "vec3<f32>", "vec2<f32>",
-                 ast::BinaryOp::kMultiply, {});
-  CheckMutations("mat3x2<f32>", "mat2x3<f32>", "mat2x2<f32>",
-                 ast::BinaryOp::kMultiply, {});
-  CheckMutations("mat3x2<f32>", "mat3x3<f32>", "mat3x2<f32>",
-                 ast::BinaryOp::kMultiply, {});
-  CheckMutations("mat3x2<f32>", "mat4x3<f32>", "mat4x2<f32>",
-                 ast::BinaryOp::kMultiply, {});
+    CheckMutations("mat3x2<f32>", "vec3<f32>", "vec2<f32>", ast::BinaryOp::kMultiply, {});
+    CheckMutations("mat3x2<f32>", "mat2x3<f32>", "mat2x2<f32>", ast::BinaryOp::kMultiply, {});
+    CheckMutations("mat3x2<f32>", "mat3x3<f32>", "mat3x2<f32>", ast::BinaryOp::kMultiply, {});
+    CheckMutations("mat3x2<f32>", "mat4x3<f32>", "mat4x2<f32>", ast::BinaryOp::kMultiply, {});
 
-  CheckMutations("mat3x3<f32>", "vec3<f32>", "vec3<f32>",
-                 ast::BinaryOp::kMultiply, {});
-  CheckMutations("mat3x3<f32>", "mat2x3<f32>", "mat2x3<f32>",
-                 ast::BinaryOp::kMultiply, {});
-  CheckMutations("mat3x3<f32>", "mat4x3<f32>", "mat4x3<f32>",
-                 ast::BinaryOp::kMultiply, {});
+    CheckMutations("mat3x3<f32>", "vec3<f32>", "vec3<f32>", ast::BinaryOp::kMultiply, {});
+    CheckMutations("mat3x3<f32>", "mat2x3<f32>", "mat2x3<f32>", ast::BinaryOp::kMultiply, {});
+    CheckMutations("mat3x3<f32>", "mat4x3<f32>", "mat4x3<f32>", ast::BinaryOp::kMultiply, {});
 
-  CheckMutations("mat3x4<f32>", "vec3<f32>", "vec4<f32>",
-                 ast::BinaryOp::kMultiply, {});
-  CheckMutations("mat3x4<f32>", "mat2x3<f32>", "mat2x4<f32>",
-                 ast::BinaryOp::kMultiply, {});
-  CheckMutations("mat3x4<f32>", "mat3x3<f32>", "mat3x4<f32>",
-                 ast::BinaryOp::kMultiply, {});
-  CheckMutations("mat3x4<f32>", "mat4x3<f32>", "mat4x4<f32>",
-                 ast::BinaryOp::kMultiply, {});
+    CheckMutations("mat3x4<f32>", "vec3<f32>", "vec4<f32>", ast::BinaryOp::kMultiply, {});
+    CheckMutations("mat3x4<f32>", "mat2x3<f32>", "mat2x4<f32>", ast::BinaryOp::kMultiply, {});
+    CheckMutations("mat3x4<f32>", "mat3x3<f32>", "mat3x4<f32>", ast::BinaryOp::kMultiply, {});
+    CheckMutations("mat3x4<f32>", "mat4x3<f32>", "mat4x4<f32>", ast::BinaryOp::kMultiply, {});
 
-  CheckMutations("vec4<f32>", "mat2x4<f32>", "vec2<f32>",
-                 ast::BinaryOp::kMultiply, {});
-  CheckMutations("vec4<f32>", "mat3x4<f32>", "vec3<f32>",
-                 ast::BinaryOp::kMultiply, {});
-  CheckMutations("vec4<f32>", "mat4x4<f32>", "vec4<f32>",
-                 ast::BinaryOp::kMultiply, {});
+    CheckMutations("vec4<f32>", "mat2x4<f32>", "vec2<f32>", ast::BinaryOp::kMultiply, {});
+    CheckMutations("vec4<f32>", "mat3x4<f32>", "vec3<f32>", ast::BinaryOp::kMultiply, {});
+    CheckMutations("vec4<f32>", "mat4x4<f32>", "vec4<f32>", ast::BinaryOp::kMultiply, {});
 
-  CheckMutations("mat4x2<f32>", "vec4<f32>", "vec2<f32>",
-                 ast::BinaryOp::kMultiply, {});
-  CheckMutations("mat4x2<f32>", "mat2x4<f32>", "mat2x2<f32>",
-                 ast::BinaryOp::kMultiply, {});
-  CheckMutations("mat4x2<f32>", "mat3x4<f32>", "mat3x2<f32>",
-                 ast::BinaryOp::kMultiply, {});
-  CheckMutations("mat4x2<f32>", "mat4x4<f32>", "mat4x2<f32>",
-                 ast::BinaryOp::kMultiply, {});
+    CheckMutations("mat4x2<f32>", "vec4<f32>", "vec2<f32>", ast::BinaryOp::kMultiply, {});
+    CheckMutations("mat4x2<f32>", "mat2x4<f32>", "mat2x2<f32>", ast::BinaryOp::kMultiply, {});
+    CheckMutations("mat4x2<f32>", "mat3x4<f32>", "mat3x2<f32>", ast::BinaryOp::kMultiply, {});
+    CheckMutations("mat4x2<f32>", "mat4x4<f32>", "mat4x2<f32>", ast::BinaryOp::kMultiply, {});
 
-  CheckMutations("mat4x3<f32>", "vec4<f32>", "vec3<f32>",
-                 ast::BinaryOp::kMultiply, {});
-  CheckMutations("mat4x3<f32>", "mat2x4<f32>", "mat2x3<f32>",
-                 ast::BinaryOp::kMultiply, {});
-  CheckMutations("mat4x3<f32>", "mat3x4<f32>", "mat3x3<f32>",
-                 ast::BinaryOp::kMultiply, {});
-  CheckMutations("mat4x3<f32>", "mat4x4<f32>", "mat4x3<f32>",
-                 ast::BinaryOp::kMultiply, {});
+    CheckMutations("mat4x3<f32>", "vec4<f32>", "vec3<f32>", ast::BinaryOp::kMultiply, {});
+    CheckMutations("mat4x3<f32>", "mat2x4<f32>", "mat2x3<f32>", ast::BinaryOp::kMultiply, {});
+    CheckMutations("mat4x3<f32>", "mat3x4<f32>", "mat3x3<f32>", ast::BinaryOp::kMultiply, {});
+    CheckMutations("mat4x3<f32>", "mat4x4<f32>", "mat4x3<f32>", ast::BinaryOp::kMultiply, {});
 
-  CheckMutations("mat4x4<f32>", "vec4<f32>", "vec4<f32>",
-                 ast::BinaryOp::kMultiply, {});
-  CheckMutations("mat4x4<f32>", "mat2x4<f32>", "mat2x4<f32>",
-                 ast::BinaryOp::kMultiply, {});
-  CheckMutations("mat4x4<f32>", "mat3x4<f32>", "mat3x4<f32>",
-                 ast::BinaryOp::kMultiply, {});
+    CheckMutations("mat4x4<f32>", "vec4<f32>", "vec4<f32>", ast::BinaryOp::kMultiply, {});
+    CheckMutations("mat4x4<f32>", "mat2x4<f32>", "mat2x4<f32>", ast::BinaryOp::kMultiply, {});
+    CheckMutations("mat4x4<f32>", "mat3x4<f32>", "mat3x4<f32>", ast::BinaryOp::kMultiply, {});
 }
 
 TEST(ChangeBinaryOperatorTest, DivideAndModulo) {
-  for (std::string type : {"i32", "vec2<i32>", "vec3<i32>", "vec4<i32>"}) {
-    CheckMutations(
-        type, type, type, ast::BinaryOp::kDivide,
-        {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract,
-         ast::BinaryOp::kMultiply, ast::BinaryOp::kModulo, ast::BinaryOp::kAnd,
-         ast::BinaryOp::kOr, ast::BinaryOp::kXor});
-  }
-  for (std::string type : {"u32", "vec2<u32>", "vec3<u32>", "vec4<u32>"}) {
-    CheckMutations(
-        type, type, type, ast::BinaryOp::kDivide,
-        {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract,
-         ast::BinaryOp::kMultiply, ast::BinaryOp::kModulo, ast::BinaryOp::kAnd,
-         ast::BinaryOp::kOr, ast::BinaryOp::kXor, ast::BinaryOp::kShiftLeft,
-         ast::BinaryOp::kShiftRight});
-  }
-  for (std::string type : {"f32", "vec2<f32>", "vec3<f32>", "vec4<f32>"}) {
-    CheckMutations(type, type, type, ast::BinaryOp::kDivide,
-                   {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract,
-                    ast::BinaryOp::kMultiply, ast::BinaryOp::kModulo});
-  }
-  for (std::string vector_type : {"vec2<i32>", "vec3<i32>", "vec4<i32>"}) {
-    std::string scalar_type = "i32";
-    CheckMutations(vector_type, scalar_type, vector_type,
-                   ast::BinaryOp::kDivide,
-                   {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract,
-                    ast::BinaryOp::kMultiply, ast::BinaryOp::kModulo});
-    CheckMutations(scalar_type, vector_type, vector_type,
-                   ast::BinaryOp::kDivide,
-                   {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract,
-                    ast::BinaryOp::kMultiply, ast::BinaryOp::kModulo});
-  }
-  for (std::string vector_type : {"vec2<u32>", "vec3<u32>", "vec4<u32>"}) {
-    std::string scalar_type = "u32";
-    CheckMutations(vector_type, scalar_type, vector_type,
-                   ast::BinaryOp::kDivide,
-                   {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract,
-                    ast::BinaryOp::kMultiply, ast::BinaryOp::kModulo});
-    CheckMutations(scalar_type, vector_type, vector_type,
-                   ast::BinaryOp::kDivide,
-                   {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract,
-                    ast::BinaryOp::kMultiply, ast::BinaryOp::kModulo});
-  }
-  for (std::string vector_type : {"vec2<f32>", "vec3<f32>", "vec4<f32>"}) {
-    std::string scalar_type = "f32";
-    CheckMutations(vector_type, scalar_type, vector_type,
-                   ast::BinaryOp::kDivide,
-                   {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract,
-                    ast::BinaryOp::kMultiply, ast::BinaryOp::kModulo});
-    CheckMutations(scalar_type, vector_type, vector_type,
-                   ast::BinaryOp::kDivide,
-                   {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract,
-                    ast::BinaryOp::kMultiply, ast::BinaryOp::kModulo});
-  }
-  for (std::string type : {"i32", "vec2<i32>", "vec3<i32>", "vec4<i32>"}) {
-    CheckMutations(
-        type, type, type, ast::BinaryOp::kModulo,
-        {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract,
-         ast::BinaryOp::kMultiply, ast::BinaryOp::kDivide, ast::BinaryOp::kAnd,
-         ast::BinaryOp::kOr, ast::BinaryOp::kXor});
-  }
-  for (std::string type : {"u32", "vec2<u32>", "vec3<u32>", "vec4<u32>"}) {
-    CheckMutations(
-        type, type, type, ast::BinaryOp::kModulo,
-        {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract,
-         ast::BinaryOp::kMultiply, ast::BinaryOp::kDivide, ast::BinaryOp::kAnd,
-         ast::BinaryOp::kOr, ast::BinaryOp::kXor, ast::BinaryOp::kShiftLeft,
-         ast::BinaryOp::kShiftRight});
-  }
-  for (std::string type : {"f32", "vec2<f32>", "vec3<f32>", "vec4<f32>"}) {
-    CheckMutations(type, type, type, ast::BinaryOp::kModulo,
-                   {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract,
-                    ast::BinaryOp::kMultiply, ast::BinaryOp::kDivide});
-  }
-  for (std::string vector_type : {"vec2<i32>", "vec3<i32>", "vec4<i32>"}) {
-    std::string scalar_type = "i32";
-    CheckMutations(vector_type, scalar_type, vector_type,
-                   ast::BinaryOp::kModulo,
-                   {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract,
-                    ast::BinaryOp::kMultiply, ast::BinaryOp::kDivide});
-    CheckMutations(scalar_type, vector_type, vector_type,
-                   ast::BinaryOp::kModulo,
-                   {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract,
-                    ast::BinaryOp::kMultiply, ast::BinaryOp::kDivide});
-  }
-  for (std::string vector_type : {"vec2<u32>", "vec3<u32>", "vec4<u32>"}) {
-    std::string scalar_type = "u32";
-    CheckMutations(vector_type, scalar_type, vector_type,
-                   ast::BinaryOp::kModulo,
-                   {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract,
-                    ast::BinaryOp::kMultiply, ast::BinaryOp::kDivide});
-    CheckMutations(scalar_type, vector_type, vector_type,
-                   ast::BinaryOp::kModulo,
-                   {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract,
-                    ast::BinaryOp::kMultiply, ast::BinaryOp::kDivide});
-  }
+    for (std::string type : {"i32", "vec2<i32>", "vec3<i32>", "vec4<i32>"}) {
+        CheckMutations(
+            type, type, type, ast::BinaryOp::kDivide,
+            {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract, ast::BinaryOp::kMultiply,
+             ast::BinaryOp::kModulo, ast::BinaryOp::kAnd, ast::BinaryOp::kOr, ast::BinaryOp::kXor});
+    }
+    for (std::string type : {"u32", "vec2<u32>", "vec3<u32>", "vec4<u32>"}) {
+        CheckMutations(
+            type, type, type, ast::BinaryOp::kDivide,
+            {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract, ast::BinaryOp::kMultiply,
+             ast::BinaryOp::kModulo, ast::BinaryOp::kAnd, ast::BinaryOp::kOr, ast::BinaryOp::kXor,
+             ast::BinaryOp::kShiftLeft, ast::BinaryOp::kShiftRight});
+    }
+    for (std::string type : {"f32", "vec2<f32>", "vec3<f32>", "vec4<f32>"}) {
+        CheckMutations(type, type, type, ast::BinaryOp::kDivide,
+                       {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract, ast::BinaryOp::kMultiply,
+                        ast::BinaryOp::kModulo});
+    }
+    for (std::string vector_type : {"vec2<i32>", "vec3<i32>", "vec4<i32>"}) {
+        std::string scalar_type = "i32";
+        CheckMutations(vector_type, scalar_type, vector_type, ast::BinaryOp::kDivide,
+                       {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract, ast::BinaryOp::kMultiply,
+                        ast::BinaryOp::kModulo});
+        CheckMutations(scalar_type, vector_type, vector_type, ast::BinaryOp::kDivide,
+                       {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract, ast::BinaryOp::kMultiply,
+                        ast::BinaryOp::kModulo});
+    }
+    for (std::string vector_type : {"vec2<u32>", "vec3<u32>", "vec4<u32>"}) {
+        std::string scalar_type = "u32";
+        CheckMutations(vector_type, scalar_type, vector_type, ast::BinaryOp::kDivide,
+                       {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract, ast::BinaryOp::kMultiply,
+                        ast::BinaryOp::kModulo});
+        CheckMutations(scalar_type, vector_type, vector_type, ast::BinaryOp::kDivide,
+                       {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract, ast::BinaryOp::kMultiply,
+                        ast::BinaryOp::kModulo});
+    }
+    for (std::string vector_type : {"vec2<f32>", "vec3<f32>", "vec4<f32>"}) {
+        std::string scalar_type = "f32";
+        CheckMutations(vector_type, scalar_type, vector_type, ast::BinaryOp::kDivide,
+                       {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract, ast::BinaryOp::kMultiply,
+                        ast::BinaryOp::kModulo});
+        CheckMutations(scalar_type, vector_type, vector_type, ast::BinaryOp::kDivide,
+                       {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract, ast::BinaryOp::kMultiply,
+                        ast::BinaryOp::kModulo});
+    }
+    for (std::string type : {"i32", "vec2<i32>", "vec3<i32>", "vec4<i32>"}) {
+        CheckMutations(
+            type, type, type, ast::BinaryOp::kModulo,
+            {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract, ast::BinaryOp::kMultiply,
+             ast::BinaryOp::kDivide, ast::BinaryOp::kAnd, ast::BinaryOp::kOr, ast::BinaryOp::kXor});
+    }
+    for (std::string type : {"u32", "vec2<u32>", "vec3<u32>", "vec4<u32>"}) {
+        CheckMutations(
+            type, type, type, ast::BinaryOp::kModulo,
+            {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract, ast::BinaryOp::kMultiply,
+             ast::BinaryOp::kDivide, ast::BinaryOp::kAnd, ast::BinaryOp::kOr, ast::BinaryOp::kXor,
+             ast::BinaryOp::kShiftLeft, ast::BinaryOp::kShiftRight});
+    }
+    for (std::string type : {"f32", "vec2<f32>", "vec3<f32>", "vec4<f32>"}) {
+        CheckMutations(type, type, type, ast::BinaryOp::kModulo,
+                       {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract, ast::BinaryOp::kMultiply,
+                        ast::BinaryOp::kDivide});
+    }
+    for (std::string vector_type : {"vec2<i32>", "vec3<i32>", "vec4<i32>"}) {
+        std::string scalar_type = "i32";
+        CheckMutations(vector_type, scalar_type, vector_type, ast::BinaryOp::kModulo,
+                       {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract, ast::BinaryOp::kMultiply,
+                        ast::BinaryOp::kDivide});
+        CheckMutations(scalar_type, vector_type, vector_type, ast::BinaryOp::kModulo,
+                       {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract, ast::BinaryOp::kMultiply,
+                        ast::BinaryOp::kDivide});
+    }
+    for (std::string vector_type : {"vec2<u32>", "vec3<u32>", "vec4<u32>"}) {
+        std::string scalar_type = "u32";
+        CheckMutations(vector_type, scalar_type, vector_type, ast::BinaryOp::kModulo,
+                       {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract, ast::BinaryOp::kMultiply,
+                        ast::BinaryOp::kDivide});
+        CheckMutations(scalar_type, vector_type, vector_type, ast::BinaryOp::kModulo,
+                       {ast::BinaryOp::kAdd, ast::BinaryOp::kSubtract, ast::BinaryOp::kMultiply,
+                        ast::BinaryOp::kDivide});
+    }
 }
 
 TEST(ChangeBinaryOperatorTest, AndOrXor) {
-  for (auto op :
-       {ast::BinaryOp::kAnd, ast::BinaryOp::kOr, ast::BinaryOp::kXor}) {
-    std::unordered_set<ast::BinaryOp> allowed_replacement_operators_signed{
-        ast::BinaryOp::kAdd,      ast::BinaryOp::kSubtract,
-        ast::BinaryOp::kMultiply, ast::BinaryOp::kDivide,
-        ast::BinaryOp::kModulo,   ast::BinaryOp::kAnd,
-        ast::BinaryOp::kOr,       ast::BinaryOp::kXor};
-    allowed_replacement_operators_signed.erase(op);
-    for (std::string type : {"i32", "vec2<i32>", "vec3<i32>", "vec4<i32>"}) {
-      CheckMutations(type, type, type, op,
-                     allowed_replacement_operators_signed);
-    }
-    std::unordered_set<ast::BinaryOp> allowed_replacement_operators_unsigned{
-        ast::BinaryOp::kAdd,        ast::BinaryOp::kSubtract,
-        ast::BinaryOp::kMultiply,   ast::BinaryOp::kDivide,
-        ast::BinaryOp::kModulo,     ast::BinaryOp::kShiftLeft,
-        ast::BinaryOp::kShiftRight, ast::BinaryOp::kAnd,
-        ast::BinaryOp::kOr,         ast::BinaryOp::kXor};
-    allowed_replacement_operators_unsigned.erase(op);
-    for (std::string type : {"u32", "vec2<u32>", "vec3<u32>", "vec4<u32>"}) {
-      CheckMutations(type, type, type, op,
-                     allowed_replacement_operators_unsigned);
-    }
-    if (op != ast::BinaryOp::kXor) {
-      for (std::string type :
-           {"bool", "vec2<bool>", "vec3<bool>", "vec4<bool>"}) {
-        std::unordered_set<ast::BinaryOp> allowed_replacement_operators_bool{
-            ast::BinaryOp::kAnd, ast::BinaryOp::kOr, ast::BinaryOp::kEqual,
-            ast::BinaryOp::kNotEqual};
-        allowed_replacement_operators_bool.erase(op);
-        if (type == "bool") {
-          allowed_replacement_operators_bool.insert(ast::BinaryOp::kLogicalAnd);
-          allowed_replacement_operators_bool.insert(ast::BinaryOp::kLogicalOr);
+    for (auto op : {ast::BinaryOp::kAnd, ast::BinaryOp::kOr, ast::BinaryOp::kXor}) {
+        std::unordered_set<ast::BinaryOp> allowed_replacement_operators_signed{
+            ast::BinaryOp::kAdd,    ast::BinaryOp::kSubtract, ast::BinaryOp::kMultiply,
+            ast::BinaryOp::kDivide, ast::BinaryOp::kModulo,   ast::BinaryOp::kAnd,
+            ast::BinaryOp::kOr,     ast::BinaryOp::kXor};
+        allowed_replacement_operators_signed.erase(op);
+        for (std::string type : {"i32", "vec2<i32>", "vec3<i32>", "vec4<i32>"}) {
+            CheckMutations(type, type, type, op, allowed_replacement_operators_signed);
         }
-        CheckMutations(type, type, type, op,
-                       allowed_replacement_operators_bool);
-      }
+        std::unordered_set<ast::BinaryOp> allowed_replacement_operators_unsigned{
+            ast::BinaryOp::kAdd,        ast::BinaryOp::kSubtract, ast::BinaryOp::kMultiply,
+            ast::BinaryOp::kDivide,     ast::BinaryOp::kModulo,   ast::BinaryOp::kShiftLeft,
+            ast::BinaryOp::kShiftRight, ast::BinaryOp::kAnd,      ast::BinaryOp::kOr,
+            ast::BinaryOp::kXor};
+        allowed_replacement_operators_unsigned.erase(op);
+        for (std::string type : {"u32", "vec2<u32>", "vec3<u32>", "vec4<u32>"}) {
+            CheckMutations(type, type, type, op, allowed_replacement_operators_unsigned);
+        }
+        if (op != ast::BinaryOp::kXor) {
+            for (std::string type : {"bool", "vec2<bool>", "vec3<bool>", "vec4<bool>"}) {
+                std::unordered_set<ast::BinaryOp> allowed_replacement_operators_bool{
+                    ast::BinaryOp::kAnd, ast::BinaryOp::kOr, ast::BinaryOp::kEqual,
+                    ast::BinaryOp::kNotEqual};
+                allowed_replacement_operators_bool.erase(op);
+                if (type == "bool") {
+                    allowed_replacement_operators_bool.insert(ast::BinaryOp::kLogicalAnd);
+                    allowed_replacement_operators_bool.insert(ast::BinaryOp::kLogicalOr);
+                }
+                CheckMutations(type, type, type, op, allowed_replacement_operators_bool);
+            }
+        }
     }
-  }
 }
 
 TEST(ChangeBinaryOperatorTest, EqualNotEqual) {
-  for (auto op : {ast::BinaryOp::kEqual, ast::BinaryOp::kNotEqual}) {
-    for (std::string element_type : {"i32", "u32", "f32"}) {
-      for (size_t element_count = 1; element_count <= 4; element_count++) {
-        std::stringstream argument_type;
-        std::stringstream result_type;
-        if (element_count == 1) {
-          argument_type << element_type;
-          result_type << "bool";
-        } else {
-          argument_type << "vec" << element_count << "<" << element_type << ">";
-          result_type << "vec" << element_count << "<bool>";
+    for (auto op : {ast::BinaryOp::kEqual, ast::BinaryOp::kNotEqual}) {
+        for (std::string element_type : {"i32", "u32", "f32"}) {
+            for (size_t element_count = 1; element_count <= 4; element_count++) {
+                std::stringstream argument_type;
+                std::stringstream result_type;
+                if (element_count == 1) {
+                    argument_type << element_type;
+                    result_type << "bool";
+                } else {
+                    argument_type << "vec" << element_count << "<" << element_type << ">";
+                    result_type << "vec" << element_count << "<bool>";
+                }
+                std::unordered_set<ast::BinaryOp> allowed_replacement_operators{
+                    ast::BinaryOp::kLessThan,    ast::BinaryOp::kLessThanEqual,
+                    ast::BinaryOp::kGreaterThan, ast::BinaryOp::kGreaterThanEqual,
+                    ast::BinaryOp::kEqual,       ast::BinaryOp::kNotEqual};
+                allowed_replacement_operators.erase(op);
+                CheckMutations(argument_type.str(), argument_type.str(), result_type.str(), op,
+                               allowed_replacement_operators);
+            }
         }
-        std::unordered_set<ast::BinaryOp> allowed_replacement_operators{
-            ast::BinaryOp::kLessThan,    ast::BinaryOp::kLessThanEqual,
-            ast::BinaryOp::kGreaterThan, ast::BinaryOp::kGreaterThanEqual,
-            ast::BinaryOp::kEqual,       ast::BinaryOp::kNotEqual};
-        allowed_replacement_operators.erase(op);
-        CheckMutations(argument_type.str(), argument_type.str(),
-                       result_type.str(), op, allowed_replacement_operators);
-      }
+        {
+            std::unordered_set<ast::BinaryOp> allowed_replacement_operators{
+                ast::BinaryOp::kLogicalAnd, ast::BinaryOp::kLogicalOr, ast::BinaryOp::kAnd,
+                ast::BinaryOp::kOr,         ast::BinaryOp::kEqual,     ast::BinaryOp::kNotEqual};
+            allowed_replacement_operators.erase(op);
+            CheckMutations("bool", "bool", "bool", op, allowed_replacement_operators);
+        }
+        for (size_t element_count = 2; element_count <= 4; element_count++) {
+            std::stringstream argument_and_result_type;
+            argument_and_result_type << "vec" << element_count << "<bool>";
+            std::unordered_set<ast::BinaryOp> allowed_replacement_operators{
+                ast::BinaryOp::kAnd, ast::BinaryOp::kOr, ast::BinaryOp::kEqual,
+                ast::BinaryOp::kNotEqual};
+            allowed_replacement_operators.erase(op);
+            CheckMutations(argument_and_result_type.str(), argument_and_result_type.str(),
+                           argument_and_result_type.str(), op, allowed_replacement_operators);
+        }
     }
-    {
-      std::unordered_set<ast::BinaryOp> allowed_replacement_operators{
-          ast::BinaryOp::kLogicalAnd, ast::BinaryOp::kLogicalOr,
-          ast::BinaryOp::kAnd,        ast::BinaryOp::kOr,
-          ast::BinaryOp::kEqual,      ast::BinaryOp::kNotEqual};
-      allowed_replacement_operators.erase(op);
-      CheckMutations("bool", "bool", "bool", op, allowed_replacement_operators);
-    }
-    for (size_t element_count = 2; element_count <= 4; element_count++) {
-      std::stringstream argument_and_result_type;
-      argument_and_result_type << "vec" << element_count << "<bool>";
-      std::unordered_set<ast::BinaryOp> allowed_replacement_operators{
-          ast::BinaryOp::kAnd, ast::BinaryOp::kOr, ast::BinaryOp::kEqual,
-          ast::BinaryOp::kNotEqual};
-      allowed_replacement_operators.erase(op);
-      CheckMutations(
-          argument_and_result_type.str(), argument_and_result_type.str(),
-          argument_and_result_type.str(), op, allowed_replacement_operators);
-    }
-  }
 }
 
-TEST(ChangeBinaryOperatorTest,
-     LessThanLessThanEqualGreaterThanGreaterThanEqual) {
-  for (auto op :
-       {ast::BinaryOp::kLessThan, ast::BinaryOp::kLessThanEqual,
-        ast::BinaryOp::kGreaterThan, ast::BinaryOp::kGreaterThanEqual}) {
-    for (std::string element_type : {"i32", "u32", "f32"}) {
-      for (size_t element_count = 1; element_count <= 4; element_count++) {
-        std::stringstream argument_type;
-        std::stringstream result_type;
-        if (element_count == 1) {
-          argument_type << element_type;
-          result_type << "bool";
-        } else {
-          argument_type << "vec" << element_count << "<" << element_type << ">";
-          result_type << "vec" << element_count << "<bool>";
+TEST(ChangeBinaryOperatorTest, LessThanLessThanEqualGreaterThanGreaterThanEqual) {
+    for (auto op : {ast::BinaryOp::kLessThan, ast::BinaryOp::kLessThanEqual,
+                    ast::BinaryOp::kGreaterThan, ast::BinaryOp::kGreaterThanEqual}) {
+        for (std::string element_type : {"i32", "u32", "f32"}) {
+            for (size_t element_count = 1; element_count <= 4; element_count++) {
+                std::stringstream argument_type;
+                std::stringstream result_type;
+                if (element_count == 1) {
+                    argument_type << element_type;
+                    result_type << "bool";
+                } else {
+                    argument_type << "vec" << element_count << "<" << element_type << ">";
+                    result_type << "vec" << element_count << "<bool>";
+                }
+                std::unordered_set<ast::BinaryOp> allowed_replacement_operators{
+                    ast::BinaryOp::kLessThan,    ast::BinaryOp::kLessThanEqual,
+                    ast::BinaryOp::kGreaterThan, ast::BinaryOp::kGreaterThanEqual,
+                    ast::BinaryOp::kEqual,       ast::BinaryOp::kNotEqual};
+                allowed_replacement_operators.erase(op);
+                CheckMutations(argument_type.str(), argument_type.str(), result_type.str(), op,
+                               allowed_replacement_operators);
+            }
         }
-        std::unordered_set<ast::BinaryOp> allowed_replacement_operators{
-            ast::BinaryOp::kLessThan,    ast::BinaryOp::kLessThanEqual,
-            ast::BinaryOp::kGreaterThan, ast::BinaryOp::kGreaterThanEqual,
-            ast::BinaryOp::kEqual,       ast::BinaryOp::kNotEqual};
-        allowed_replacement_operators.erase(op);
-        CheckMutations(argument_type.str(), argument_type.str(),
-                       result_type.str(), op, allowed_replacement_operators);
-      }
     }
-  }
 }
 
 TEST(ChangeBinaryOperatorTest, LogicalAndLogicalOr) {
-  for (auto op : {ast::BinaryOp::kLogicalAnd, ast::BinaryOp::kLogicalOr}) {
-    std::unordered_set<ast::BinaryOp> allowed_replacement_operators{
-        ast::BinaryOp::kLogicalAnd, ast::BinaryOp::kLogicalOr,
-        ast::BinaryOp::kAnd,        ast::BinaryOp::kOr,
-        ast::BinaryOp::kEqual,      ast::BinaryOp::kNotEqual};
-    allowed_replacement_operators.erase(op);
-    CheckMutations("bool", "bool", "bool", op, allowed_replacement_operators);
-  }
+    for (auto op : {ast::BinaryOp::kLogicalAnd, ast::BinaryOp::kLogicalOr}) {
+        std::unordered_set<ast::BinaryOp> allowed_replacement_operators{
+            ast::BinaryOp::kLogicalAnd, ast::BinaryOp::kLogicalOr, ast::BinaryOp::kAnd,
+            ast::BinaryOp::kOr,         ast::BinaryOp::kEqual,     ast::BinaryOp::kNotEqual};
+        allowed_replacement_operators.erase(op);
+        CheckMutations("bool", "bool", "bool", op, allowed_replacement_operators);
+    }
 }
 
 TEST(ChangeBinaryOperatorTest, ShiftLeftShiftRight) {
-  for (auto op : {ast::BinaryOp::kShiftLeft, ast::BinaryOp::kShiftRight}) {
-    for (std::string lhs_element_type : {"i32", "u32"}) {
-      for (size_t element_count = 1; element_count <= 4; element_count++) {
-        std::stringstream lhs_and_result_type;
-        std::stringstream rhs_type;
-        if (element_count == 1) {
-          lhs_and_result_type << lhs_element_type;
-          rhs_type << "u32";
-        } else {
-          lhs_and_result_type << "vec" << element_count << "<"
-                              << lhs_element_type << ">";
-          rhs_type << "vec" << element_count << "<u32>";
+    for (auto op : {ast::BinaryOp::kShiftLeft, ast::BinaryOp::kShiftRight}) {
+        for (std::string lhs_element_type : {"i32", "u32"}) {
+            for (size_t element_count = 1; element_count <= 4; element_count++) {
+                std::stringstream lhs_and_result_type;
+                std::stringstream rhs_type;
+                if (element_count == 1) {
+                    lhs_and_result_type << lhs_element_type;
+                    rhs_type << "u32";
+                } else {
+                    lhs_and_result_type << "vec" << element_count << "<" << lhs_element_type << ">";
+                    rhs_type << "vec" << element_count << "<u32>";
+                }
+                std::unordered_set<ast::BinaryOp> allowed_replacement_operators{
+                    ast::BinaryOp::kShiftLeft, ast::BinaryOp::kShiftRight};
+                allowed_replacement_operators.erase(op);
+                if (lhs_element_type == "u32") {
+                    allowed_replacement_operators.insert(ast::BinaryOp::kAdd);
+                    allowed_replacement_operators.insert(ast::BinaryOp::kSubtract);
+                    allowed_replacement_operators.insert(ast::BinaryOp::kMultiply);
+                    allowed_replacement_operators.insert(ast::BinaryOp::kDivide);
+                    allowed_replacement_operators.insert(ast::BinaryOp::kModulo);
+                    allowed_replacement_operators.insert(ast::BinaryOp::kAnd);
+                    allowed_replacement_operators.insert(ast::BinaryOp::kOr);
+                    allowed_replacement_operators.insert(ast::BinaryOp::kXor);
+                }
+                CheckMutations(lhs_and_result_type.str(), rhs_type.str(), lhs_and_result_type.str(),
+                               op, allowed_replacement_operators);
+            }
         }
-        std::unordered_set<ast::BinaryOp> allowed_replacement_operators{
-            ast::BinaryOp::kShiftLeft, ast::BinaryOp::kShiftRight};
-        allowed_replacement_operators.erase(op);
-        if (lhs_element_type == "u32") {
-          allowed_replacement_operators.insert(ast::BinaryOp::kAdd);
-          allowed_replacement_operators.insert(ast::BinaryOp::kSubtract);
-          allowed_replacement_operators.insert(ast::BinaryOp::kMultiply);
-          allowed_replacement_operators.insert(ast::BinaryOp::kDivide);
-          allowed_replacement_operators.insert(ast::BinaryOp::kModulo);
-          allowed_replacement_operators.insert(ast::BinaryOp::kAnd);
-          allowed_replacement_operators.insert(ast::BinaryOp::kOr);
-          allowed_replacement_operators.insert(ast::BinaryOp::kXor);
-        }
-        CheckMutations(lhs_and_result_type.str(), rhs_type.str(),
-                       lhs_and_result_type.str(), op,
-                       allowed_replacement_operators);
-      }
     }
-  }
 }
 
 }  // namespace
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/mutations/change_unary_operator.cc b/src/tint/fuzzers/tint_ast_fuzzer/mutations/change_unary_operator.cc
new file mode 100644
index 0000000..d32d569
--- /dev/null
+++ b/src/tint/fuzzers/tint_ast_fuzzer/mutations/change_unary_operator.cc
@@ -0,0 +1,107 @@
+// Copyright 2021 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/fuzzers/tint_ast_fuzzer/mutations/change_unary_operator.h"
+
+#include <utility>
+
+#include "src/tint/fuzzers/tint_ast_fuzzer/util.h"
+#include "src/tint/program_builder.h"
+#include "src/tint/sem/reference.h"
+
+namespace tint::fuzzers::ast_fuzzer {
+
+MutationChangeUnaryOperator::MutationChangeUnaryOperator(
+    protobufs::MutationChangeUnaryOperator message)
+    : message_(std::move(message)) {}
+
+MutationChangeUnaryOperator::MutationChangeUnaryOperator(uint32_t unary_expr_id,
+                                                         ast::UnaryOp new_operator) {
+    message_.set_unary_expr_id(unary_expr_id);
+    message_.set_new_operator(static_cast<uint32_t>(new_operator));
+}
+
+bool MutationChangeUnaryOperator::IsApplicable(const tint::Program& program,
+                                               const NodeIdMap& node_id_map) const {
+    const auto* unary_expr_node =
+        tint::As<ast::UnaryOpExpression>(node_id_map.GetNode(message_.unary_expr_id()));
+
+    if (!unary_expr_node) {
+        // Either the id does not exist, or does not correspond to a unary
+        // expression.
+        return false;
+    }
+
+    auto new_unary_operator = static_cast<ast::UnaryOp>(message_.new_operator());
+
+    // Get the type of the unary expression.
+    const auto* type = program.Sem().Get(unary_expr_node)->Type();
+    const auto* basic_type =
+        type->Is<sem::Reference>() ? type->As<sem::Reference>()->StoreType() : type;
+
+    // Only signed integer or vector of signed integer has more than 1
+    // unary operators to change between.
+    if (!basic_type->is_signed_scalar_or_vector()) {
+        return false;
+    }
+
+    // The new unary operator must not be the same as the original one.
+    if (new_unary_operator != ToggleOperator(unary_expr_node->op)) {
+        return false;
+    }
+
+    return true;
+}
+
+void MutationChangeUnaryOperator::Apply(const NodeIdMap& node_id_map,
+                                        tint::CloneContext* clone_context,
+                                        NodeIdMap* new_node_id_map) const {
+    const auto* unary_expr_node =
+        tint::As<ast::UnaryOpExpression>(node_id_map.GetNode(message_.unary_expr_id()));
+
+    const ast::UnaryOpExpression* cloned_replacement;
+    switch (static_cast<ast::UnaryOp>(message_.new_operator())) {
+        case ast::UnaryOp::kComplement:
+            cloned_replacement =
+                clone_context->dst->Complement(clone_context->Clone(unary_expr_node->expr));
+            break;
+        case ast::UnaryOp::kNegation:
+            cloned_replacement =
+                clone_context->dst->Negation(clone_context->Clone(unary_expr_node->expr));
+            break;
+        default:
+            cloned_replacement = nullptr;
+            assert(false && "Unreachable");
+    }
+    // Set things up so that the original unary expression will be replaced with
+    // its clone, and update the id mapping.
+    clone_context->Replace(unary_expr_node, cloned_replacement);
+    new_node_id_map->Add(cloned_replacement, message_.unary_expr_id());
+}
+
+protobufs::Mutation MutationChangeUnaryOperator::ToMessage() const {
+    protobufs::Mutation mutation;
+    *mutation.mutable_change_unary_operator() = message_;
+    return mutation;
+}
+
+ast::UnaryOp MutationChangeUnaryOperator::ToggleOperator(const ast::UnaryOp& original_op) {
+    if (original_op == ast::UnaryOp::kComplement) {
+        return ast::UnaryOp::kNegation;
+    }
+    assert(original_op == ast::UnaryOp::kNegation && "Unexpected operator.");
+    return ast::UnaryOp::kComplement;
+}
+
+}  // namespace tint::fuzzers::ast_fuzzer
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/mutations/change_unary_operator.h b/src/tint/fuzzers/tint_ast_fuzzer/mutations/change_unary_operator.h
new file mode 100644
index 0000000..d80ec3f
--- /dev/null
+++ b/src/tint/fuzzers/tint_ast_fuzzer/mutations/change_unary_operator.h
@@ -0,0 +1,72 @@
+// Copyright 2021 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_FUZZERS_TINT_AST_FUZZER_MUTATIONS_CHANGE_UNARY_OPERATOR_H_
+#define SRC_TINT_FUZZERS_TINT_AST_FUZZER_MUTATIONS_CHANGE_UNARY_OPERATOR_H_
+
+#include "src/tint/fuzzers/tint_ast_fuzzer/mutation.h"
+#include "src/tint/sem/variable.h"
+
+namespace tint::fuzzers::ast_fuzzer {
+
+/// @see MutationChangeUnaryOperator::Apply
+class MutationChangeUnaryOperator : public Mutation {
+  public:
+    /// @brief Constructs an instance of this mutation from a protobuf message.
+    /// @param message - protobuf message
+    explicit MutationChangeUnaryOperator(protobufs::MutationChangeUnaryOperator message);
+
+    /// @brief Constructor.
+    /// @param unary_expr_id - the id of the `ast::UnaryOpExpression` instance
+    /// to change its operator.
+    /// @param new_operator - A new unary operator for the unary expression
+    /// specified by `expression_id`.
+    MutationChangeUnaryOperator(uint32_t unary_expr_id, ast::UnaryOp new_operator);
+
+    /// @copybrief Mutation::IsApplicable
+    ///
+    /// The mutation is applicable if and only if:
+    /// - `expression_id` is an id of an `ast::UnaryOpExpression`, that references
+    ///   a valid unary expression.
+    /// - `new_unary_op` is a valid unary operator of type `ast::UnaryOp`
+    ///   to the target expression.
+    ///
+    /// @copydetails Mutation::IsApplicable
+    bool IsApplicable(const tint::Program& program, const NodeIdMap& node_id_map) const override;
+
+    /// @copybrief Mutation::Apply
+    ///
+    /// Replaces the operator of an unary op expression with `expression_id`
+    /// with a new unary operator specified by `new_unary_op'. The modified
+    /// expression preserves the same type as the original expression.
+    ///
+    /// @copydetails Mutation::Apply
+    void Apply(const NodeIdMap& node_id_map,
+               tint::CloneContext* clone_context,
+               NodeIdMap* new_node_id_map) const override;
+
+    protobufs::Mutation ToMessage() const override;
+
+    /// Toggles between the complement and negate unary operators.
+    /// @param original_op - a complement or negation unary operator.
+    /// @return the other operator.
+    static ast::UnaryOp ToggleOperator(const ast::UnaryOp& original_op);
+
+  private:
+    protobufs::MutationChangeUnaryOperator message_;
+};
+
+}  // namespace tint::fuzzers::ast_fuzzer
+
+#endif  // SRC_TINT_FUZZERS_TINT_AST_FUZZER_MUTATIONS_CHANGE_UNARY_OPERATOR_H_
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/mutations/change_unary_operator_test.cc b/src/tint/fuzzers/tint_ast_fuzzer/mutations/change_unary_operator_test.cc
new file mode 100644
index 0000000..511af4f
--- /dev/null
+++ b/src/tint/fuzzers/tint_ast_fuzzer/mutations/change_unary_operator_test.cc
@@ -0,0 +1,299 @@
+// Copyright 2021 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <string>
+
+#include "gtest/gtest.h"
+
+#include "src/tint/ast/call_statement.h"
+#include "src/tint/fuzzers/tint_ast_fuzzer/mutations/change_unary_operator.h"
+#include "src/tint/fuzzers/tint_ast_fuzzer/mutator.h"
+#include "src/tint/fuzzers/tint_ast_fuzzer/node_id_map.h"
+#include "src/tint/fuzzers/tint_ast_fuzzer/probability_context.h"
+#include "src/tint/program_builder.h"
+#include "src/tint/reader/wgsl/parser.h"
+#include "src/tint/writer/wgsl/generator.h"
+
+namespace tint::fuzzers::ast_fuzzer {
+namespace {
+
+TEST(ChangeUnaryOperatorTest, Operator_Not_Applicable) {
+    std::string content = R"(
+    fn main() {
+      let a : f32 = 1.1;
+      let b = vec2<i32>(1, -1);
+      let c : u32 = 0u;
+      let d : vec3<bool> = vec3<bool> (false, false, true);
+
+      var neg_a = -a;
+      var not_b = ~b;
+      var not_c = ~c;
+      var neg_d = !d;
+    }
+  )";
+    Source::File file("test.wgsl", content);
+    auto program = reader::wgsl::Parse(&file);
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+
+    NodeIdMap node_id_map(program);
+
+    const auto& main_fn_statements = program.AST().Functions()[0]->body->statements;
+
+    // Get variable from statements.
+    const auto* neg_a_var = main_fn_statements[4]->As<ast::VariableDeclStatement>()->variable;
+    ASSERT_NE(neg_a_var, nullptr);
+
+    const auto* not_b_var = main_fn_statements[5]->As<ast::VariableDeclStatement>()->variable;
+    ASSERT_NE(not_b_var, nullptr);
+
+    const auto* not_c_var = main_fn_statements[6]->As<ast::VariableDeclStatement>()->variable;
+    ASSERT_NE(not_c_var, nullptr);
+
+    const auto* neg_d_var = main_fn_statements[7]->As<ast::VariableDeclStatement>()->variable;
+    ASSERT_NE(neg_d_var, nullptr);
+
+    // Get the expression from variable declaration.
+    const auto* neg_a_expr = neg_a_var->constructor->As<ast::UnaryOpExpression>();
+    ASSERT_NE(neg_a_expr, nullptr);
+
+    const auto* not_b_expr = not_b_var->constructor->As<ast::UnaryOpExpression>();
+    ASSERT_NE(not_b_expr, nullptr);
+
+    const auto* not_c_expr = not_c_var->constructor->As<ast::UnaryOpExpression>();
+    ASSERT_NE(not_c_expr, nullptr);
+
+    const auto* neg_d_expr = neg_d_var->constructor->As<ast::UnaryOpExpression>();
+    ASSERT_NE(neg_d_expr, nullptr);
+
+    // The following mutations are not applicable.
+    auto neg_a_id = node_id_map.GetId(neg_a_expr);
+    // Only negation is allowed for float type. Cannot change
+    // the operator of float types to any other.
+    ASSERT_FALSE(MaybeApplyMutation(
+        program, MutationChangeUnaryOperator(neg_a_id, ast::UnaryOp::kComplement), node_id_map,
+        &program, &node_id_map, nullptr));
+    ASSERT_FALSE(MaybeApplyMutation(program,
+                                    MutationChangeUnaryOperator(neg_a_id, ast::UnaryOp::kNot),
+                                    node_id_map, &program, &node_id_map, nullptr));
+    ASSERT_FALSE(MaybeApplyMutation(program,
+                                    MutationChangeUnaryOperator(neg_a_id, ast::UnaryOp::kNegation),
+                                    node_id_map, &program, &node_id_map, nullptr));
+
+    auto not_b_id = node_id_map.GetId(not_b_expr);
+    // Only complement and negation is allowed for signed integer type.
+    ASSERT_FALSE(MaybeApplyMutation(program,
+                                    MutationChangeUnaryOperator(not_b_id, ast::UnaryOp::kNot),
+                                    node_id_map, &program, &node_id_map, nullptr));
+    // Cannot change to the same unary operator.
+    ASSERT_FALSE(MaybeApplyMutation(
+        program, MutationChangeUnaryOperator(not_b_id, ast::UnaryOp::kComplement), node_id_map,
+        &program, &node_id_map, nullptr));
+
+    auto not_c_id = node_id_map.GetId(not_c_expr);
+    // Only complement is allowed for unsigned integer.Cannot change
+    //  // the operator of float types to any other.
+    ASSERT_FALSE(MaybeApplyMutation(program,
+                                    MutationChangeUnaryOperator(not_c_id, ast::UnaryOp::kNot),
+                                    node_id_map, &program, &node_id_map, nullptr));
+    ASSERT_FALSE(MaybeApplyMutation(program,
+                                    MutationChangeUnaryOperator(not_c_id, ast::UnaryOp::kNegation),
+                                    node_id_map, &program, &node_id_map, nullptr));
+    ASSERT_FALSE(MaybeApplyMutation(
+        program, MutationChangeUnaryOperator(not_c_id, ast::UnaryOp::kComplement), node_id_map,
+        &program, &node_id_map, nullptr));
+
+    auto neg_d_id = node_id_map.GetId(neg_d_expr);
+    // Only logical negation (not) is allowed for bool type.  Cannot change
+    // the operator of float types to any other.
+    ASSERT_FALSE(MaybeApplyMutation(
+        program, MutationChangeUnaryOperator(neg_d_id, ast::UnaryOp::kComplement), node_id_map,
+        &program, &node_id_map, nullptr));
+    ASSERT_FALSE(MaybeApplyMutation(program,
+                                    MutationChangeUnaryOperator(neg_d_id, ast::UnaryOp::kNegation),
+                                    node_id_map, &program, &node_id_map, nullptr));
+    ASSERT_FALSE(MaybeApplyMutation(program,
+                                    MutationChangeUnaryOperator(neg_d_id, ast::UnaryOp::kNot),
+                                    node_id_map, &program, &node_id_map, nullptr));
+}
+
+TEST(ChangeUnaryOperatorTest, Signed_Integer_Types_Applicable1) {
+    std::string content = R"(
+    fn main() {
+      let a : i32 = 5;
+      let comp_a = ~a;
+    }
+  )";
+    Source::File file("test.wgsl", content);
+    auto program = reader::wgsl::Parse(&file);
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+
+    NodeIdMap node_id_map(program);
+
+    const auto& main_fn_statements = program.AST().Functions()[0]->body->statements;
+
+    // Get variable from statements.
+    const auto* comp_a_var = main_fn_statements[1]->As<ast::VariableDeclStatement>()->variable;
+    ASSERT_NE(comp_a_var, nullptr);
+
+    // Get the expression from variable declaration.
+    const auto* comp_a_expr = comp_a_var->constructor->As<ast::UnaryOpExpression>();
+    ASSERT_NE(comp_a_expr, nullptr);
+
+    // Assert mutation to be applicable and apply mutation.
+    auto comp_a_id = node_id_map.GetId(comp_a_expr);
+    ASSERT_TRUE(MaybeApplyMutation(program,
+                                   MutationChangeUnaryOperator(comp_a_id, ast::UnaryOp::kNegation),
+                                   node_id_map, &program, &node_id_map, nullptr));
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+
+    writer::wgsl::Options options;
+    auto result = writer::wgsl::Generate(&program, options);
+    ASSERT_TRUE(result.success) << result.error;
+
+    std::string expected_shader = R"(fn main() {
+  let a : i32 = 5;
+  let comp_a = -(a);
+}
+)";
+    ASSERT_EQ(expected_shader, result.wgsl);
+}
+
+TEST(ChangeUnaryOperatorTest, Signed_Integer_Types_Applicable2) {
+    std::string content = R"(
+    fn main() {
+      let b : vec3<i32> = vec3<i32>(1, 3, -1);
+      var comp_b : vec3<i32> = ~b;
+    })";
+    Source::File file("test.wgsl", content);
+    auto program = reader::wgsl::Parse(&file);
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+
+    NodeIdMap node_id_map(program);
+
+    const auto& main_fn_statements = program.AST().Functions()[0]->body->statements;
+
+    // Get variable from statements.
+    const auto* comp_b_var = main_fn_statements[1]->As<ast::VariableDeclStatement>()->variable;
+    ASSERT_NE(comp_b_var, nullptr);
+
+    // Get the expression from variable declaration.
+    const auto* comp_b_expr = comp_b_var->constructor->As<ast::UnaryOpExpression>();
+    ASSERT_NE(comp_b_expr, nullptr);
+
+    // Assert mutation to be applicable and apply mutation.
+    auto comp_b_id = node_id_map.GetId(comp_b_expr);
+    ASSERT_TRUE(MaybeApplyMutation(program,
+                                   MutationChangeUnaryOperator(comp_b_id, ast::UnaryOp::kNegation),
+                                   node_id_map, &program, &node_id_map, nullptr));
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+
+    writer::wgsl::Options options;
+    auto result = writer::wgsl::Generate(&program, options);
+    ASSERT_TRUE(result.success) << result.error;
+
+    std::string expected_shader = R"(fn main() {
+  let b : vec3<i32> = vec3<i32>(1, 3, -1);
+  var comp_b : vec3<i32> = -(b);
+}
+)";
+    ASSERT_EQ(expected_shader, result.wgsl);
+}
+
+TEST(ChangeUnaryOperatorTest, Signed_Integer_Types_Applicable3) {
+    std::string content = R"(
+    fn main() {
+      var a = -5;
+
+      var neg_a = -(a);
+    }
+  )";
+    Source::File file("test.wgsl", content);
+    auto program = reader::wgsl::Parse(&file);
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+
+    NodeIdMap node_id_map(program);
+
+    const auto& main_fn_statements = program.AST().Functions()[0]->body->statements;
+
+    // Get variable from statements.
+    const auto* neg_a_var = main_fn_statements[1]->As<ast::VariableDeclStatement>()->variable;
+    ASSERT_NE(neg_a_var, nullptr);
+
+    // Get the expression from variable declaration.
+    const auto* neg_a_expr = neg_a_var->constructor->As<ast::UnaryOpExpression>();
+    ASSERT_NE(neg_a_expr, nullptr);
+
+    // Assert mutation to be applicable and apply mutation.
+    auto neg_a_id = node_id_map.GetId(neg_a_expr);
+    ASSERT_TRUE(MaybeApplyMutation(program,
+                                   MutationChangeUnaryOperator(neg_a_id, ast::UnaryOp::kComplement),
+                                   node_id_map, &program, &node_id_map, nullptr));
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+
+    writer::wgsl::Options options;
+    auto result = writer::wgsl::Generate(&program, options);
+    ASSERT_TRUE(result.success) << result.error;
+
+    std::string expected_shader = R"(fn main() {
+  var a = -5;
+  var neg_a = ~(a);
+}
+)";
+    ASSERT_EQ(expected_shader, result.wgsl);
+}
+
+TEST(ChangeUnaryOperatorTest, Signed_Integer_Types_Applicable4) {
+    std::string content = R"(
+    fn main() {
+      var b : vec3<i32> = vec3<i32>(1, 3, -1);
+      let neg_b : vec3<i32> = -b;
+    }
+  )";
+    Source::File file("test.wgsl", content);
+    auto program = reader::wgsl::Parse(&file);
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+
+    NodeIdMap node_id_map(program);
+
+    const auto& main_fn_statements = program.AST().Functions()[0]->body->statements;
+
+    // Get variable from statements.
+    const auto* neg_b_var = main_fn_statements[1]->As<ast::VariableDeclStatement>()->variable;
+    ASSERT_NE(neg_b_var, nullptr);
+
+    // Get the expression from variable declaration.
+    const auto* neg_b_expr = neg_b_var->constructor->As<ast::UnaryOpExpression>();
+    ASSERT_NE(neg_b_expr, nullptr);
+
+    // Assert mutation to be applicable and apply mutation.
+    auto neg_b_id = node_id_map.GetId(neg_b_expr);
+    ASSERT_TRUE(MaybeApplyMutation(program,
+                                   MutationChangeUnaryOperator(neg_b_id, ast::UnaryOp::kComplement),
+                                   node_id_map, &program, &node_id_map, nullptr));
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+
+    writer::wgsl::Options options;
+    auto result = writer::wgsl::Generate(&program, options);
+    ASSERT_TRUE(result.success) << result.error;
+
+    std::string expected_shader = R"(fn main() {
+  var b : vec3<i32> = vec3<i32>(1, 3, -1);
+  let neg_b : vec3<i32> = ~(b);
+}
+)";
+    ASSERT_EQ(expected_shader, result.wgsl);
+}
+
+}  // namespace
+}  // namespace tint::fuzzers::ast_fuzzer
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/mutations/replace_identifier.cc b/src/tint/fuzzers/tint_ast_fuzzer/mutations/replace_identifier.cc
index 0daa82a..a4dad15 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/mutations/replace_identifier.cc
+++ b/src/tint/fuzzers/tint_ast_fuzzer/mutations/replace_identifier.cc
@@ -21,82 +21,75 @@
 
 namespace tint::fuzzers::ast_fuzzer {
 
-MutationReplaceIdentifier::MutationReplaceIdentifier(
-    protobufs::MutationReplaceIdentifier message)
+MutationReplaceIdentifier::MutationReplaceIdentifier(protobufs::MutationReplaceIdentifier message)
     : message_(std::move(message)) {}
 
-MutationReplaceIdentifier::MutationReplaceIdentifier(uint32_t use_id,
-                                                     uint32_t replacement_id) {
-  message_.set_use_id(use_id);
-  message_.set_replacement_id(replacement_id);
+MutationReplaceIdentifier::MutationReplaceIdentifier(uint32_t use_id, uint32_t replacement_id) {
+    message_.set_use_id(use_id);
+    message_.set_replacement_id(replacement_id);
 }
 
-bool MutationReplaceIdentifier::IsApplicable(
-    const tint::Program& program,
-    const NodeIdMap& node_id_map) const {
-  const auto* use_ast_node = tint::As<ast::IdentifierExpression>(
-      node_id_map.GetNode(message_.use_id()));
-  if (!use_ast_node) {
-    // Either the `use_id` is invalid or the node is not an
-    // `IdentifierExpression`.
-    return false;
-  }
+bool MutationReplaceIdentifier::IsApplicable(const tint::Program& program,
+                                             const NodeIdMap& node_id_map) const {
+    const auto* use_ast_node =
+        tint::As<ast::IdentifierExpression>(node_id_map.GetNode(message_.use_id()));
+    if (!use_ast_node) {
+        // Either the `use_id` is invalid or the node is not an
+        // `IdentifierExpression`.
+        return false;
+    }
 
-  const auto* use_sem_node =
-      tint::As<sem::VariableUser>(program.Sem().Get(use_ast_node));
-  if (!use_sem_node) {
-    // Either the semantic information is not present for a `use_node` or that
-    // node is not a variable user.
-    return false;
-  }
+    const auto* use_sem_node = tint::As<sem::VariableUser>(program.Sem().Get(use_ast_node));
+    if (!use_sem_node) {
+        // Either the semantic information is not present for a `use_node` or that
+        // node is not a variable user.
+        return false;
+    }
 
-  const auto* replacement_ast_node =
-      tint::As<ast::Variable>(node_id_map.GetNode(message_.replacement_id()));
-  if (!replacement_ast_node) {
-    // Either the `replacement_id` is invalid or is not an id of a variable.
-    return false;
-  }
+    const auto* replacement_ast_node =
+        tint::As<ast::Variable>(node_id_map.GetNode(message_.replacement_id()));
+    if (!replacement_ast_node) {
+        // Either the `replacement_id` is invalid or is not an id of a variable.
+        return false;
+    }
 
-  const auto* replacement_sem_node = program.Sem().Get(replacement_ast_node);
-  if (!replacement_sem_node) {
-    return false;
-  }
+    const auto* replacement_sem_node = program.Sem().Get(replacement_ast_node);
+    if (!replacement_sem_node) {
+        return false;
+    }
 
-  if (replacement_sem_node == use_sem_node->Variable()) {
-    return false;
-  }
+    if (replacement_sem_node == use_sem_node->Variable()) {
+        return false;
+    }
 
-  auto in_scope =
-      util::GetAllVarsInScope(program, use_sem_node->Stmt(),
-                              [replacement_sem_node](const sem::Variable* var) {
-                                return var == replacement_sem_node;
-                              });
-  if (in_scope.empty()) {
-    // The replacement variable is not in scope.
-    return false;
-  }
+    auto in_scope = util::GetAllVarsInScope(
+        program, use_sem_node->Stmt(),
+        [replacement_sem_node](const sem::Variable* var) { return var == replacement_sem_node; });
+    if (in_scope.empty()) {
+        // The replacement variable is not in scope.
+        return false;
+    }
 
-  return use_sem_node->Type() == replacement_sem_node->Type();
+    return use_sem_node->Type() == replacement_sem_node->Type();
 }
 
 void MutationReplaceIdentifier::Apply(const NodeIdMap& node_id_map,
                                       tint::CloneContext* clone_context,
                                       NodeIdMap* new_node_id_map) const {
-  const auto* use_node = node_id_map.GetNode(message_.use_id());
-  const auto* replacement_var =
-      tint::As<ast::Variable>(node_id_map.GetNode(message_.replacement_id()));
+    const auto* use_node = node_id_map.GetNode(message_.use_id());
+    const auto* replacement_var =
+        tint::As<ast::Variable>(node_id_map.GetNode(message_.replacement_id()));
 
-  auto* cloned_replacement =
-      clone_context->dst->Expr(clone_context->Clone(use_node->source),
-                               clone_context->Clone(replacement_var->symbol));
-  clone_context->Replace(use_node, cloned_replacement);
-  new_node_id_map->Add(cloned_replacement, message_.use_id());
+    auto* cloned_replacement = clone_context->dst->Expr(
+        clone_context->Clone(use_node->source), clone_context->Clone(replacement_var->symbol));
+    clone_context->Replace(use_node, cloned_replacement);
+    new_node_id_map->Add(cloned_replacement, message_.use_id());
 }
 
 protobufs::Mutation MutationReplaceIdentifier::ToMessage() const {
-  protobufs::Mutation mutation;
-  *mutation.mutable_replace_identifier() = message_;
-  return mutation;
+    protobufs::Mutation mutation;
+    *mutation.mutable_replace_identifier() = message_;
+    return mutation;
 }
 
 }  // namespace tint::fuzzers::ast_fuzzer
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/mutations/replace_identifier.h b/src/tint/fuzzers/tint_ast_fuzzer/mutations/replace_identifier.h
index 2d50c30..66490ad 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/mutations/replace_identifier.h
+++ b/src/tint/fuzzers/tint_ast_fuzzer/mutations/replace_identifier.h
@@ -23,49 +23,47 @@
 
 /// @see MutationReplaceIdentifier::Apply
 class MutationReplaceIdentifier : public Mutation {
- public:
-  /// @brief Constructs an instance of this mutation from a protobuf message.
-  /// @param message - protobuf message
-  explicit MutationReplaceIdentifier(
-      protobufs::MutationReplaceIdentifier message);
+  public:
+    /// @brief Constructs an instance of this mutation from a protobuf message.
+    /// @param message - protobuf message
+    explicit MutationReplaceIdentifier(protobufs::MutationReplaceIdentifier message);
 
-  /// @brief Constructor.
-  /// @param use_id - the id of a variable user.
-  /// @param replacement_id - the id of a variable to replace the `use_id`.
-  MutationReplaceIdentifier(uint32_t use_id, uint32_t replacement_id);
+    /// @brief Constructor.
+    /// @param use_id - the id of a variable user.
+    /// @param replacement_id - the id of a variable to replace the `use_id`.
+    MutationReplaceIdentifier(uint32_t use_id, uint32_t replacement_id);
 
-  /// @copybrief Mutation::IsApplicable
-  ///
-  /// The mutation is applicable iff:
-  /// - `use_id` is a valid id of an `ast::IdentifierExpression`, that
-  ///   references a variable.
-  /// - `replacement_id` is a valid id of an `ast::Variable`.
-  /// - The identifier expression doesn't reference the variable of a
-  ///   `replacement_id`.
-  /// - The variable with `replacement_id` is in scope of an identifier
-  ///   expression with `use_id`.
-  /// - The identifier expression and the variable have the same type.
-  ///
-  /// @copydetails Mutation::IsApplicable
-  bool IsApplicable(const tint::Program& program,
-                    const NodeIdMap& node_id_map) const override;
+    /// @copybrief Mutation::IsApplicable
+    ///
+    /// The mutation is applicable iff:
+    /// - `use_id` is a valid id of an `ast::IdentifierExpression`, that
+    ///   references a variable.
+    /// - `replacement_id` is a valid id of an `ast::Variable`.
+    /// - The identifier expression doesn't reference the variable of a
+    ///   `replacement_id`.
+    /// - The variable with `replacement_id` is in scope of an identifier
+    ///   expression with `use_id`.
+    /// - The identifier expression and the variable have the same type.
+    ///
+    /// @copydetails Mutation::IsApplicable
+    bool IsApplicable(const tint::Program& program, const NodeIdMap& node_id_map) const override;
 
-  /// @copybrief Mutation::Apply
-  ///
-  /// Replaces the use of an identifier expression with `use_id` with a newly
-  /// created identifier expression, that references a variable with
-  /// `replacement_id`. The newly created identifier expression will have the
-  /// same id as the old one (i.e. `use_id`).
-  ///
-  /// @copydetails Mutation::Apply
-  void Apply(const NodeIdMap& node_id_map,
-             tint::CloneContext* clone_context,
-             NodeIdMap* new_node_id_map) const override;
+    /// @copybrief Mutation::Apply
+    ///
+    /// Replaces the use of an identifier expression with `use_id` with a newly
+    /// created identifier expression, that references a variable with
+    /// `replacement_id`. The newly created identifier expression will have the
+    /// same id as the old one (i.e. `use_id`).
+    ///
+    /// @copydetails Mutation::Apply
+    void Apply(const NodeIdMap& node_id_map,
+               tint::CloneContext* clone_context,
+               NodeIdMap* new_node_id_map) const override;
 
-  protobufs::Mutation ToMessage() const override;
+    protobufs::Mutation ToMessage() const override;
 
- private:
-  protobufs::MutationReplaceIdentifier message_;
+  private:
+    protobufs::MutationReplaceIdentifier message_;
 };
 
 }  // namespace tint::fuzzers::ast_fuzzer
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/mutations/replace_identifier_test.cc b/src/tint/fuzzers/tint_ast_fuzzer/mutations/replace_identifier_test.cc
index 9e82e11..737cb07 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/mutations/replace_identifier_test.cc
+++ b/src/tint/fuzzers/tint_ast_fuzzer/mutations/replace_identifier_test.cc
@@ -29,7 +29,7 @@
 namespace {
 
 TEST(ReplaceIdentifierTest, NotApplicable_Simple) {
-  std::string content = R"(
+    std::string content = R"(
     fn main() {
       let a = 5;
       let c = 6;
@@ -39,82 +39,77 @@
       let e = d.x;
     }
   )";
-  Source::File file("test.wgsl", content);
-  auto program = reader::wgsl::Parse(&file);
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    Source::File file("test.wgsl", content);
+    auto program = reader::wgsl::Parse(&file);
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  NodeIdMap node_id_map(program);
+    NodeIdMap node_id_map(program);
 
-  const auto& main_fn_stmts = program.AST().Functions()[0]->body->statements;
+    const auto& main_fn_stmts = program.AST().Functions()[0]->body->statements;
 
-  const auto* a_var =
-      main_fn_stmts[0]->As<ast::VariableDeclStatement>()->variable;
-  ASSERT_NE(a_var, nullptr);
+    const auto* a_var = main_fn_stmts[0]->As<ast::VariableDeclStatement>()->variable;
+    ASSERT_NE(a_var, nullptr);
 
-  const auto* b_var =
-      main_fn_stmts[2]->As<ast::VariableDeclStatement>()->variable;
-  ASSERT_NE(b_var, nullptr);
+    const auto* b_var = main_fn_stmts[2]->As<ast::VariableDeclStatement>()->variable;
+    ASSERT_NE(b_var, nullptr);
 
-  const auto* e_var =
-      main_fn_stmts[4]->As<ast::VariableDeclStatement>()->variable;
-  ASSERT_NE(e_var, nullptr);
+    const auto* e_var = main_fn_stmts[4]->As<ast::VariableDeclStatement>()->variable;
+    ASSERT_NE(e_var, nullptr);
 
-  auto a_var_id = node_id_map.GetId(a_var);
-  ASSERT_NE(a_var_id, 0);
+    auto a_var_id = node_id_map.GetId(a_var);
+    ASSERT_NE(a_var_id, 0);
 
-  auto b_var_id = node_id_map.GetId(b_var);
-  ASSERT_NE(b_var_id, 0);
+    auto b_var_id = node_id_map.GetId(b_var);
+    ASSERT_NE(b_var_id, 0);
 
-  const auto* sum_expr = b_var->constructor->As<ast::BinaryExpression>();
-  ASSERT_NE(sum_expr, nullptr);
+    const auto* sum_expr = b_var->constructor->As<ast::BinaryExpression>();
+    ASSERT_NE(sum_expr, nullptr);
 
-  auto a_ident_id = node_id_map.GetId(sum_expr->lhs);
-  ASSERT_NE(a_ident_id, 0);
+    auto a_ident_id = node_id_map.GetId(sum_expr->lhs);
+    ASSERT_NE(a_ident_id, 0);
 
-  auto sum_expr_id = node_id_map.GetId(sum_expr);
-  ASSERT_NE(sum_expr_id, 0);
+    auto sum_expr_id = node_id_map.GetId(sum_expr);
+    ASSERT_NE(sum_expr_id, 0);
 
-  auto e_var_id = node_id_map.GetId(e_var);
-  ASSERT_NE(e_var_id, 0);
+    auto e_var_id = node_id_map.GetId(e_var);
+    ASSERT_NE(e_var_id, 0);
 
-  auto vec_member_access_id = node_id_map.GetId(
-      e_var->constructor->As<ast::MemberAccessorExpression>()->member);
-  ASSERT_NE(vec_member_access_id, 0);
+    auto vec_member_access_id =
+        node_id_map.GetId(e_var->constructor->As<ast::MemberAccessorExpression>()->member);
+    ASSERT_NE(vec_member_access_id, 0);
 
-  // use_id is invalid.
-  EXPECT_FALSE(MutationReplaceIdentifier(0, a_var_id)
-                   .IsApplicable(program, node_id_map));
+    // use_id is invalid.
+    EXPECT_FALSE(MutationReplaceIdentifier(0, a_var_id).IsApplicable(program, node_id_map));
 
-  // use_id is not an identifier expression.
-  EXPECT_FALSE(MutationReplaceIdentifier(sum_expr_id, a_var_id)
-                   .IsApplicable(program, node_id_map));
+    // use_id is not an identifier expression.
+    EXPECT_FALSE(
+        MutationReplaceIdentifier(sum_expr_id, a_var_id).IsApplicable(program, node_id_map));
 
-  // use_id is an identifier but not a variable user.
-  EXPECT_FALSE(MutationReplaceIdentifier(vec_member_access_id, a_var_id)
-                   .IsApplicable(program, node_id_map));
+    // use_id is an identifier but not a variable user.
+    EXPECT_FALSE(MutationReplaceIdentifier(vec_member_access_id, a_var_id)
+                     .IsApplicable(program, node_id_map));
 
-  // replacement_id is invalid.
-  EXPECT_FALSE(MutationReplaceIdentifier(a_ident_id, 0)
-                   .IsApplicable(program, node_id_map));
+    // replacement_id is invalid.
+    EXPECT_FALSE(MutationReplaceIdentifier(a_ident_id, 0).IsApplicable(program, node_id_map));
 
-  // replacement_id is not a variable.
-  EXPECT_FALSE(MutationReplaceIdentifier(a_ident_id, sum_expr_id)
-                   .IsApplicable(program, node_id_map));
+    // replacement_id is not a variable.
+    EXPECT_FALSE(
+        MutationReplaceIdentifier(a_ident_id, sum_expr_id).IsApplicable(program, node_id_map));
 
-  // Can't replace a variable with itself.
-  EXPECT_FALSE(MutationReplaceIdentifier(a_ident_id, a_var_id)
-                   .IsApplicable(program, node_id_map));
+    // Can't replace a variable with itself.
+    EXPECT_FALSE(
+        MutationReplaceIdentifier(a_ident_id, a_var_id).IsApplicable(program, node_id_map));
 
-  // Replacement is not in scope.
-  EXPECT_FALSE(MutationReplaceIdentifier(a_ident_id, b_var_id)
-                   .IsApplicable(program, node_id_map));
-  EXPECT_FALSE(MutationReplaceIdentifier(a_ident_id, e_var_id)
-                   .IsApplicable(program, node_id_map));
+    // Replacement is not in scope.
+    EXPECT_FALSE(
+        MutationReplaceIdentifier(a_ident_id, b_var_id).IsApplicable(program, node_id_map));
+    EXPECT_FALSE(
+        MutationReplaceIdentifier(a_ident_id, e_var_id).IsApplicable(program, node_id_map));
 }
 
 TEST(ReplaceIdentifierTest, GlobalVarNotInScope) {
-  // Can't use the global variable if it's not in scope.
-  std::string shader = R"(
+    // Can't use the global variable if it's not in scope.
+    std::string shader = R"(
 var<private> a: i32;
 
 fn f() {
@@ -123,166 +118,162 @@
 
 var<private> b: i32;
 )";
-  Source::File file("test.wgsl", shader);
-  auto program = reader::wgsl::Parse(&file);
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    Source::File file("test.wgsl", shader);
+    auto program = reader::wgsl::Parse(&file);
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  NodeIdMap node_id_map(program);
+    NodeIdMap node_id_map(program);
 
-  auto use_id = node_id_map.GetId(program.AST()
-                                      .Functions()[0]
-                                      ->body->statements[0]
-                                      ->As<ast::AssignmentStatement>()
-                                      ->lhs);
-  ASSERT_NE(use_id, 0);
+    auto use_id = node_id_map.GetId(
+        program.AST().Functions()[0]->body->statements[0]->As<ast::AssignmentStatement>()->lhs);
+    ASSERT_NE(use_id, 0);
 
-  auto replacement_id = node_id_map.GetId(program.AST().GlobalVariables()[1]);
-  ASSERT_NE(replacement_id, 0);
+    auto replacement_id = node_id_map.GetId(program.AST().GlobalVariables()[1]);
+    ASSERT_NE(replacement_id, 0);
 
-  ASSERT_FALSE(MutationReplaceIdentifier(use_id, replacement_id)
-                   .IsApplicable(program, node_id_map));
+    ASSERT_FALSE(
+        MutationReplaceIdentifier(use_id, replacement_id).IsApplicable(program, node_id_map));
 }
 
 TEST(ReplaceIdentifierTest, NotApplicable1) {
-  // Can't replace `a` with `b` since the store type is wrong (the same storage
-  // class though).
-  std::string shader = R"(
+    // Can't replace `a` with `b` since the store type is wrong (the same storage
+    // class though).
+    std::string shader = R"(
 var<private> a: i32;
 var<private> b: u32;
 fn f() {
   *&a = 4;
 }
 )";
-  Source::File file("test.wgsl", shader);
-  auto program = reader::wgsl::Parse(&file);
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    Source::File file("test.wgsl", shader);
+    auto program = reader::wgsl::Parse(&file);
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  NodeIdMap node_id_map(program);
+    NodeIdMap node_id_map(program);
 
-  auto replacement_id = node_id_map.GetId(program.AST().GlobalVariables()[1]);
-  ASSERT_NE(replacement_id, 0);
+    auto replacement_id = node_id_map.GetId(program.AST().GlobalVariables()[1]);
+    ASSERT_NE(replacement_id, 0);
 
-  auto use_id = node_id_map.GetId(program.AST()
-                                      .Functions()[0]
-                                      ->body->statements[0]
-                                      ->As<ast::AssignmentStatement>()
-                                      ->lhs->As<ast::UnaryOpExpression>()
-                                      ->expr->As<ast::UnaryOpExpression>()
-                                      ->expr);
-  ASSERT_NE(use_id, 0);
+    auto use_id = node_id_map.GetId(program.AST()
+                                        .Functions()[0]
+                                        ->body->statements[0]
+                                        ->As<ast::AssignmentStatement>()
+                                        ->lhs->As<ast::UnaryOpExpression>()
+                                        ->expr->As<ast::UnaryOpExpression>()
+                                        ->expr);
+    ASSERT_NE(use_id, 0);
 
-  ASSERT_FALSE(MutationReplaceIdentifier(use_id, replacement_id)
-                   .IsApplicable(program, node_id_map));
+    ASSERT_FALSE(
+        MutationReplaceIdentifier(use_id, replacement_id).IsApplicable(program, node_id_map));
 }
 
 TEST(ReplaceIdentifierTest, NotApplicable2) {
-  // Can't replace `a` with `b` since the store type is wrong (the storage
-  // class is different though).
-  std::string shader = R"(
+    // Can't replace `a` with `b` since the store type is wrong (the storage
+    // class is different though).
+    std::string shader = R"(
 var<private> a: i32;
 fn f() {
   var b: u32;
   *&a = 4;
 }
 )";
-  Source::File file("test.wgsl", shader);
-  auto program = reader::wgsl::Parse(&file);
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    Source::File file("test.wgsl", shader);
+    auto program = reader::wgsl::Parse(&file);
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  NodeIdMap node_id_map(program);
+    NodeIdMap node_id_map(program);
 
-  auto replacement_id = node_id_map.GetId(program.AST()
-                                              .Functions()[0]
-                                              ->body->statements[0]
-                                              ->As<ast::VariableDeclStatement>()
-                                              ->variable);
-  ASSERT_NE(replacement_id, 0);
+    auto replacement_id = node_id_map.GetId(program.AST()
+                                                .Functions()[0]
+                                                ->body->statements[0]
+                                                ->As<ast::VariableDeclStatement>()
+                                                ->variable);
+    ASSERT_NE(replacement_id, 0);
 
-  auto use_id = node_id_map.GetId(program.AST()
-                                      .Functions()[0]
-                                      ->body->statements[1]
-                                      ->As<ast::AssignmentStatement>()
-                                      ->lhs->As<ast::UnaryOpExpression>()
-                                      ->expr->As<ast::UnaryOpExpression>()
-                                      ->expr);
-  ASSERT_NE(use_id, 0);
+    auto use_id = node_id_map.GetId(program.AST()
+                                        .Functions()[0]
+                                        ->body->statements[1]
+                                        ->As<ast::AssignmentStatement>()
+                                        ->lhs->As<ast::UnaryOpExpression>()
+                                        ->expr->As<ast::UnaryOpExpression>()
+                                        ->expr);
+    ASSERT_NE(use_id, 0);
 
-  ASSERT_FALSE(MutationReplaceIdentifier(use_id, replacement_id)
-                   .IsApplicable(program, node_id_map));
+    ASSERT_FALSE(
+        MutationReplaceIdentifier(use_id, replacement_id).IsApplicable(program, node_id_map));
 }
 
 TEST(ReplaceIdentifierTest, NotApplicable3) {
-  // Can't replace `a` with `b` since the latter is not a reference (the store
-  // type is the same, though).
-  std::string shader = R"(
+    // Can't replace `a` with `b` since the latter is not a reference (the store
+    // type is the same, though).
+    std::string shader = R"(
 var<private> a: i32;
 fn f() {
   let b = 45;
   *&a = 4;
 }
 )";
-  Source::File file("test.wgsl", shader);
-  auto program = reader::wgsl::Parse(&file);
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    Source::File file("test.wgsl", shader);
+    auto program = reader::wgsl::Parse(&file);
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  NodeIdMap node_id_map(program);
+    NodeIdMap node_id_map(program);
 
-  auto replacement_id = node_id_map.GetId(program.AST()
-                                              .Functions()[0]
-                                              ->body->statements[0]
-                                              ->As<ast::VariableDeclStatement>()
-                                              ->variable);
-  ASSERT_NE(replacement_id, 0);
+    auto replacement_id = node_id_map.GetId(program.AST()
+                                                .Functions()[0]
+                                                ->body->statements[0]
+                                                ->As<ast::VariableDeclStatement>()
+                                                ->variable);
+    ASSERT_NE(replacement_id, 0);
 
-  auto use_id = node_id_map.GetId(program.AST()
-                                      .Functions()[0]
-                                      ->body->statements[1]
-                                      ->As<ast::AssignmentStatement>()
-                                      ->lhs->As<ast::UnaryOpExpression>()
-                                      ->expr->As<ast::UnaryOpExpression>()
-                                      ->expr);
-  ASSERT_NE(use_id, 0);
+    auto use_id = node_id_map.GetId(program.AST()
+                                        .Functions()[0]
+                                        ->body->statements[1]
+                                        ->As<ast::AssignmentStatement>()
+                                        ->lhs->As<ast::UnaryOpExpression>()
+                                        ->expr->As<ast::UnaryOpExpression>()
+                                        ->expr);
+    ASSERT_NE(use_id, 0);
 
-  ASSERT_FALSE(MutationReplaceIdentifier(use_id, replacement_id)
-                   .IsApplicable(program, node_id_map));
+    ASSERT_FALSE(
+        MutationReplaceIdentifier(use_id, replacement_id).IsApplicable(program, node_id_map));
 }
 
 TEST(ReplaceIdentifierTest, NotApplicable4) {
-  // Can't replace `a` with `b` since the latter is not a reference (the store
-  // type is the same, though).
-  std::string shader = R"(
+    // Can't replace `a` with `b` since the latter is not a reference (the store
+    // type is the same, though).
+    std::string shader = R"(
 var<private> a: i32;
 fn f(b: i32) {
   *&a = 4;
 }
 )";
-  Source::File file("test.wgsl", shader);
-  auto program = reader::wgsl::Parse(&file);
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    Source::File file("test.wgsl", shader);
+    auto program = reader::wgsl::Parse(&file);
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  NodeIdMap node_id_map(program);
+    NodeIdMap node_id_map(program);
 
-  auto replacement_id =
-      node_id_map.GetId(program.AST().Functions()[0]->params[0]);
-  ASSERT_NE(replacement_id, 0);
+    auto replacement_id = node_id_map.GetId(program.AST().Functions()[0]->params[0]);
+    ASSERT_NE(replacement_id, 0);
 
-  auto use_id = node_id_map.GetId(program.AST()
-                                      .Functions()[0]
-                                      ->body->statements[0]
-                                      ->As<ast::AssignmentStatement>()
-                                      ->lhs->As<ast::UnaryOpExpression>()
-                                      ->expr->As<ast::UnaryOpExpression>()
-                                      ->expr);
-  ASSERT_NE(use_id, 0);
+    auto use_id = node_id_map.GetId(program.AST()
+                                        .Functions()[0]
+                                        ->body->statements[0]
+                                        ->As<ast::AssignmentStatement>()
+                                        ->lhs->As<ast::UnaryOpExpression>()
+                                        ->expr->As<ast::UnaryOpExpression>()
+                                        ->expr);
+    ASSERT_NE(use_id, 0);
 
-  ASSERT_FALSE(MutationReplaceIdentifier(use_id, replacement_id)
-                   .IsApplicable(program, node_id_map));
+    ASSERT_FALSE(
+        MutationReplaceIdentifier(use_id, replacement_id).IsApplicable(program, node_id_map));
 }
 
 TEST(ReplaceIdentifierTest, NotApplicable5) {
-  // Can't replace `a` with `b` since the latter has a wrong access mode
-  // (`read` for uniform storage class).
-  std::string shader = R"(
+    // Can't replace `a` with `b` since the latter has a wrong access mode
+    // (`read` for uniform storage class).
+    std::string shader = R"(
 struct S {
   a: i32;
 };
@@ -293,31 +284,31 @@
   *&a = S(4);
 }
 )";
-  Source::File file("test.wgsl", shader);
-  auto program = reader::wgsl::Parse(&file);
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    Source::File file("test.wgsl", shader);
+    auto program = reader::wgsl::Parse(&file);
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  NodeIdMap node_id_map(program);
+    NodeIdMap node_id_map(program);
 
-  auto replacement_id = node_id_map.GetId(program.AST().GlobalVariables()[1]);
-  ASSERT_NE(replacement_id, 0);
+    auto replacement_id = node_id_map.GetId(program.AST().GlobalVariables()[1]);
+    ASSERT_NE(replacement_id, 0);
 
-  auto use_id = node_id_map.GetId(program.AST()
-                                      .Functions()[0]
-                                      ->body->statements[0]
-                                      ->As<ast::AssignmentStatement>()
-                                      ->lhs->As<ast::UnaryOpExpression>()
-                                      ->expr->As<ast::UnaryOpExpression>()
-                                      ->expr);
-  ASSERT_NE(use_id, 0);
+    auto use_id = node_id_map.GetId(program.AST()
+                                        .Functions()[0]
+                                        ->body->statements[0]
+                                        ->As<ast::AssignmentStatement>()
+                                        ->lhs->As<ast::UnaryOpExpression>()
+                                        ->expr->As<ast::UnaryOpExpression>()
+                                        ->expr);
+    ASSERT_NE(use_id, 0);
 
-  ASSERT_FALSE(MutationReplaceIdentifier(use_id, replacement_id)
-                   .IsApplicable(program, node_id_map));
+    ASSERT_FALSE(
+        MutationReplaceIdentifier(use_id, replacement_id).IsApplicable(program, node_id_map));
 }
 
 TEST(ReplaceIdentifierTest, NotApplicable6) {
-  // Can't replace `ptr_b` with `a` since the latter is not a pointer.
-  std::string shader = R"(
+    // Can't replace `ptr_b` with `a` since the latter is not a pointer.
+    std::string shader = R"(
 struct S {
   a: i32;
 };
@@ -329,31 +320,31 @@
   *&a = *ptr_b;
 }
 )";
-  Source::File file("test.wgsl", shader);
-  auto program = reader::wgsl::Parse(&file);
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    Source::File file("test.wgsl", shader);
+    auto program = reader::wgsl::Parse(&file);
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  NodeIdMap node_id_map(program);
+    NodeIdMap node_id_map(program);
 
-  auto replacement_id = node_id_map.GetId(program.AST().GlobalVariables()[0]);
-  ASSERT_NE(replacement_id, 0);
+    auto replacement_id = node_id_map.GetId(program.AST().GlobalVariables()[0]);
+    ASSERT_NE(replacement_id, 0);
 
-  auto use_id = node_id_map.GetId(program.AST()
-                                      .Functions()[0]
-                                      ->body->statements[1]
-                                      ->As<ast::AssignmentStatement>()
-                                      ->rhs->As<ast::UnaryOpExpression>()
-                                      ->expr);
-  ASSERT_NE(use_id, 0);
+    auto use_id = node_id_map.GetId(program.AST()
+                                        .Functions()[0]
+                                        ->body->statements[1]
+                                        ->As<ast::AssignmentStatement>()
+                                        ->rhs->As<ast::UnaryOpExpression>()
+                                        ->expr);
+    ASSERT_NE(use_id, 0);
 
-  ASSERT_FALSE(MutationReplaceIdentifier(use_id, replacement_id)
-                   .IsApplicable(program, node_id_map));
+    ASSERT_FALSE(
+        MutationReplaceIdentifier(use_id, replacement_id).IsApplicable(program, node_id_map));
 }
 
 TEST(ReplaceIdentifierTest, NotApplicable8) {
-  // Can't replace `ptr_b` with `c` since the latter has a wrong access mode and
-  // storage class.
-  std::string shader = R"(
+    // Can't replace `ptr_b` with `c` since the latter has a wrong access mode and
+    // storage class.
+    std::string shader = R"(
 struct S {
   a: i32;
 };
@@ -366,30 +357,30 @@
   *&a = *ptr_b;
 }
 )";
-  Source::File file("test.wgsl", shader);
-  auto program = reader::wgsl::Parse(&file);
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    Source::File file("test.wgsl", shader);
+    auto program = reader::wgsl::Parse(&file);
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  NodeIdMap node_id_map(program);
+    NodeIdMap node_id_map(program);
 
-  auto replacement_id = node_id_map.GetId(program.AST().GlobalVariables()[2]);
-  ASSERT_NE(replacement_id, 0);
+    auto replacement_id = node_id_map.GetId(program.AST().GlobalVariables()[2]);
+    ASSERT_NE(replacement_id, 0);
 
-  auto use_id = node_id_map.GetId(program.AST()
-                                      .Functions()[0]
-                                      ->body->statements[1]
-                                      ->As<ast::AssignmentStatement>()
-                                      ->rhs->As<ast::UnaryOpExpression>()
-                                      ->expr);
-  ASSERT_NE(use_id, 0);
+    auto use_id = node_id_map.GetId(program.AST()
+                                        .Functions()[0]
+                                        ->body->statements[1]
+                                        ->As<ast::AssignmentStatement>()
+                                        ->rhs->As<ast::UnaryOpExpression>()
+                                        ->expr);
+    ASSERT_NE(use_id, 0);
 
-  ASSERT_FALSE(MutationReplaceIdentifier(use_id, replacement_id)
-                   .IsApplicable(program, node_id_map));
+    ASSERT_FALSE(
+        MutationReplaceIdentifier(use_id, replacement_id).IsApplicable(program, node_id_map));
 }
 
 TEST(ReplaceIdentifierTest, NotApplicable9) {
-  // Can't replace `b` with `e` since the latter is not a reference.
-  std::string shader = R"(
+    // Can't replace `b` with `e` since the latter is not a reference.
+    std::string shader = R"(
 struct S {
   a: i32;
 };
@@ -401,31 +392,31 @@
   *&a = *&b;
 }
 )";
-  Source::File file("test.wgsl", shader);
-  auto program = reader::wgsl::Parse(&file);
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    Source::File file("test.wgsl", shader);
+    auto program = reader::wgsl::Parse(&file);
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  NodeIdMap node_id_map(program);
+    NodeIdMap node_id_map(program);
 
-  auto replacement_id = node_id_map.GetId(program.AST().GlobalVariables()[1]);
-  ASSERT_NE(replacement_id, 0);
+    auto replacement_id = node_id_map.GetId(program.AST().GlobalVariables()[1]);
+    ASSERT_NE(replacement_id, 0);
 
-  auto use_id = node_id_map.GetId(program.AST()
-                                      .Functions()[0]
-                                      ->body->statements[0]
-                                      ->As<ast::AssignmentStatement>()
-                                      ->rhs->As<ast::UnaryOpExpression>()
-                                      ->expr->As<ast::UnaryOpExpression>()
-                                      ->expr);
-  ASSERT_NE(use_id, 0);
+    auto use_id = node_id_map.GetId(program.AST()
+                                        .Functions()[0]
+                                        ->body->statements[0]
+                                        ->As<ast::AssignmentStatement>()
+                                        ->rhs->As<ast::UnaryOpExpression>()
+                                        ->expr->As<ast::UnaryOpExpression>()
+                                        ->expr);
+    ASSERT_NE(use_id, 0);
 
-  ASSERT_FALSE(MutationReplaceIdentifier(use_id, replacement_id)
-                   .IsApplicable(program, node_id_map));
+    ASSERT_FALSE(
+        MutationReplaceIdentifier(use_id, replacement_id).IsApplicable(program, node_id_map));
 }
 
 TEST(ReplaceIdentifierTest, NotApplicable10) {
-  // Can't replace `b` with `e` since the latter has a wrong access mode.
-  std::string shader = R"(
+    // Can't replace `b` with `e` since the latter has a wrong access mode.
+    std::string shader = R"(
 struct S {
   a: i32;
 };
@@ -437,195 +428,191 @@
   *&a = *&b;
 }
 )";
-  Source::File file("test.wgsl", shader);
-  auto program = reader::wgsl::Parse(&file);
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    Source::File file("test.wgsl", shader);
+    auto program = reader::wgsl::Parse(&file);
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  NodeIdMap node_id_map(program);
+    NodeIdMap node_id_map(program);
 
-  auto replacement_id = node_id_map.GetId(program.AST().GlobalVariables()[1]);
-  ASSERT_NE(replacement_id, 0);
+    auto replacement_id = node_id_map.GetId(program.AST().GlobalVariables()[1]);
+    ASSERT_NE(replacement_id, 0);
 
-  auto use_id = node_id_map.GetId(program.AST()
-                                      .Functions()[0]
-                                      ->body->statements[0]
-                                      ->As<ast::AssignmentStatement>()
-                                      ->rhs->As<ast::UnaryOpExpression>()
-                                      ->expr->As<ast::UnaryOpExpression>()
-                                      ->expr);
-  ASSERT_NE(use_id, 0);
+    auto use_id = node_id_map.GetId(program.AST()
+                                        .Functions()[0]
+                                        ->body->statements[0]
+                                        ->As<ast::AssignmentStatement>()
+                                        ->rhs->As<ast::UnaryOpExpression>()
+                                        ->expr->As<ast::UnaryOpExpression>()
+                                        ->expr);
+    ASSERT_NE(use_id, 0);
 
-  ASSERT_FALSE(MutationReplaceIdentifier(use_id, replacement_id)
-                   .IsApplicable(program, node_id_map));
+    ASSERT_FALSE(
+        MutationReplaceIdentifier(use_id, replacement_id).IsApplicable(program, node_id_map));
 }
 
 TEST(ReplaceIdentifierTest, Applicable1) {
-  // Can replace `a` with `b` (same storage class).
-  std::string shader = R"(
+    // Can replace `a` with `b` (same storage class).
+    std::string shader = R"(
 fn f() {
   var b : vec2<u32>;
   var a = vec2<u32>(34u, 45u);
   (*&a)[1] = 3u;
 }
 )";
-  Source::File file("test.wgsl", shader);
-  auto program = reader::wgsl::Parse(&file);
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    Source::File file("test.wgsl", shader);
+    auto program = reader::wgsl::Parse(&file);
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  NodeIdMap node_id_map(program);
+    NodeIdMap node_id_map(program);
 
-  auto use_id = node_id_map.GetId(program.AST()
-                                      .Functions()[0]
-                                      ->body->statements[2]
-                                      ->As<ast::AssignmentStatement>()
-                                      ->lhs->As<ast::IndexAccessorExpression>()
-                                      ->object->As<ast::UnaryOpExpression>()
-                                      ->expr->As<ast::UnaryOpExpression>()
-                                      ->expr);
-  ASSERT_NE(use_id, 0);
+    auto use_id = node_id_map.GetId(program.AST()
+                                        .Functions()[0]
+                                        ->body->statements[2]
+                                        ->As<ast::AssignmentStatement>()
+                                        ->lhs->As<ast::IndexAccessorExpression>()
+                                        ->object->As<ast::UnaryOpExpression>()
+                                        ->expr->As<ast::UnaryOpExpression>()
+                                        ->expr);
+    ASSERT_NE(use_id, 0);
 
-  auto replacement_id = node_id_map.GetId(program.AST()
-                                              .Functions()[0]
-                                              ->body->statements[0]
-                                              ->As<ast::VariableDeclStatement>()
-                                              ->variable);
-  ASSERT_NE(replacement_id, 0);
+    auto replacement_id = node_id_map.GetId(program.AST()
+                                                .Functions()[0]
+                                                ->body->statements[0]
+                                                ->As<ast::VariableDeclStatement>()
+                                                ->variable);
+    ASSERT_NE(replacement_id, 0);
 
-  ASSERT_TRUE(MaybeApplyMutation(
-      program, MutationReplaceIdentifier(use_id, replacement_id), node_id_map,
-      &program, &node_id_map, nullptr));
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    ASSERT_TRUE(MaybeApplyMutation(program, MutationReplaceIdentifier(use_id, replacement_id),
+                                   node_id_map, &program, &node_id_map, nullptr));
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  writer::wgsl::Options options;
-  auto result = writer::wgsl::Generate(&program, options);
-  ASSERT_TRUE(result.success) << result.error;
+    writer::wgsl::Options options;
+    auto result = writer::wgsl::Generate(&program, options);
+    ASSERT_TRUE(result.success) << result.error;
 
-  std::string expected_shader = R"(fn f() {
+    std::string expected_shader = R"(fn f() {
   var b : vec2<u32>;
   var a = vec2<u32>(34u, 45u);
   (*(&(b)))[1] = 3u;
 }
 )";
-  ASSERT_EQ(expected_shader, result.wgsl);
+    ASSERT_EQ(expected_shader, result.wgsl);
 }
 
 TEST(ReplaceIdentifierTest, Applicable2) {
-  // Can replace `ptr_a` with `b` - the function parameter.
-  std::string shader = R"(
+    // Can replace `ptr_a` with `b` - the function parameter.
+    std::string shader = R"(
 fn f(b: ptr<function, vec2<u32>>) {
   var a = vec2<u32>(34u, 45u);
   let ptr_a = &a;
   (*ptr_a)[1] = 3u;
 }
 )";
-  Source::File file("test.wgsl", shader);
-  auto program = reader::wgsl::Parse(&file);
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    Source::File file("test.wgsl", shader);
+    auto program = reader::wgsl::Parse(&file);
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  NodeIdMap node_id_map(program);
+    NodeIdMap node_id_map(program);
 
-  auto use_id = node_id_map.GetId(program.AST()
-                                      .Functions()[0]
-                                      ->body->statements[2]
-                                      ->As<ast::AssignmentStatement>()
-                                      ->lhs->As<ast::IndexAccessorExpression>()
-                                      ->object->As<ast::UnaryOpExpression>()
-                                      ->expr);
-  ASSERT_NE(use_id, 0);
+    auto use_id = node_id_map.GetId(program.AST()
+                                        .Functions()[0]
+                                        ->body->statements[2]
+                                        ->As<ast::AssignmentStatement>()
+                                        ->lhs->As<ast::IndexAccessorExpression>()
+                                        ->object->As<ast::UnaryOpExpression>()
+                                        ->expr);
+    ASSERT_NE(use_id, 0);
 
-  auto replacement_id =
-      node_id_map.GetId(program.AST().Functions()[0]->params[0]);
-  ASSERT_NE(replacement_id, 0);
+    auto replacement_id = node_id_map.GetId(program.AST().Functions()[0]->params[0]);
+    ASSERT_NE(replacement_id, 0);
 
-  ASSERT_TRUE(MaybeApplyMutation(
-      program, MutationReplaceIdentifier(use_id, replacement_id), node_id_map,
-      &program, &node_id_map, nullptr));
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    ASSERT_TRUE(MaybeApplyMutation(program, MutationReplaceIdentifier(use_id, replacement_id),
+                                   node_id_map, &program, &node_id_map, nullptr));
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  writer::wgsl::Options options;
-  auto result = writer::wgsl::Generate(&program, options);
-  ASSERT_TRUE(result.success) << result.error;
+    writer::wgsl::Options options;
+    auto result = writer::wgsl::Generate(&program, options);
+    ASSERT_TRUE(result.success) << result.error;
 
-  std::string expected_shader = R"(fn f(b : ptr<function, vec2<u32>>) {
+    std::string expected_shader = R"(fn f(b : ptr<function, vec2<u32>>) {
   var a = vec2<u32>(34u, 45u);
   let ptr_a = &(a);
   (*(b))[1] = 3u;
 }
 )";
-  ASSERT_EQ(expected_shader, result.wgsl);
+    ASSERT_EQ(expected_shader, result.wgsl);
 }
 
 TEST(ReplaceIdentifierTest, NotApplicable12) {
-  // Can't replace `a` with `b` (both are references with different storage
-  // class).
-  std::string shader = R"(
+    // Can't replace `a` with `b` (both are references with different storage
+    // class).
+    std::string shader = R"(
 var<private> b : vec2<u32>;
 fn f() {
   var a = vec2<u32>(34u, 45u);
   (*&a)[1] = 3u;
 }
 )";
-  Source::File file("test.wgsl", shader);
-  auto program = reader::wgsl::Parse(&file);
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    Source::File file("test.wgsl", shader);
+    auto program = reader::wgsl::Parse(&file);
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  NodeIdMap node_id_map(program);
+    NodeIdMap node_id_map(program);
 
-  auto use_id = node_id_map.GetId(program.AST()
-                                      .Functions()[0]
-                                      ->body->statements[1]
-                                      ->As<ast::AssignmentStatement>()
-                                      ->lhs->As<ast::IndexAccessorExpression>()
-                                      ->object->As<ast::UnaryOpExpression>()
-                                      ->expr->As<ast::UnaryOpExpression>()
-                                      ->expr);
-  ASSERT_NE(use_id, 0);
+    auto use_id = node_id_map.GetId(program.AST()
+                                        .Functions()[0]
+                                        ->body->statements[1]
+                                        ->As<ast::AssignmentStatement>()
+                                        ->lhs->As<ast::IndexAccessorExpression>()
+                                        ->object->As<ast::UnaryOpExpression>()
+                                        ->expr->As<ast::UnaryOpExpression>()
+                                        ->expr);
+    ASSERT_NE(use_id, 0);
 
-  auto replacement_id = node_id_map.GetId(program.AST().GlobalVariables()[0]);
-  ASSERT_NE(replacement_id, 0);
+    auto replacement_id = node_id_map.GetId(program.AST().GlobalVariables()[0]);
+    ASSERT_NE(replacement_id, 0);
 
-  ASSERT_FALSE(MutationReplaceIdentifier(use_id, replacement_id)
-                   .IsApplicable(program, node_id_map));
+    ASSERT_FALSE(
+        MutationReplaceIdentifier(use_id, replacement_id).IsApplicable(program, node_id_map));
 }
 
 TEST(ReplaceIdentifierTest, NotApplicable13) {
-  // Can't replace `a` with `b` (both are references with different storage
-  // class).
-  std::string shader = R"(
+    // Can't replace `a` with `b` (both are references with different storage
+    // class).
+    std::string shader = R"(
 var<private> b : vec2<u32>;
 fn f() {
   var a = vec2<u32>(34u, 45u);
   let c = (*&a)[1];
 }
 )";
-  Source::File file("test.wgsl", shader);
-  auto program = reader::wgsl::Parse(&file);
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    Source::File file("test.wgsl", shader);
+    auto program = reader::wgsl::Parse(&file);
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  NodeIdMap node_id_map(program);
+    NodeIdMap node_id_map(program);
 
-  auto use_id = node_id_map.GetId(
-      program.AST()
-          .Functions()[0]
-          ->body->statements[1]
-          ->As<ast::VariableDeclStatement>()
-          ->variable->constructor->As<ast::IndexAccessorExpression>()
-          ->object->As<ast::UnaryOpExpression>()
-          ->expr->As<ast::UnaryOpExpression>()
-          ->expr);
-  ASSERT_NE(use_id, 0);
+    auto use_id = node_id_map.GetId(program.AST()
+                                        .Functions()[0]
+                                        ->body->statements[1]
+                                        ->As<ast::VariableDeclStatement>()
+                                        ->variable->constructor->As<ast::IndexAccessorExpression>()
+                                        ->object->As<ast::UnaryOpExpression>()
+                                        ->expr->As<ast::UnaryOpExpression>()
+                                        ->expr);
+    ASSERT_NE(use_id, 0);
 
-  auto replacement_id = node_id_map.GetId(program.AST().GlobalVariables()[0]);
-  ASSERT_NE(replacement_id, 0);
+    auto replacement_id = node_id_map.GetId(program.AST().GlobalVariables()[0]);
+    ASSERT_NE(replacement_id, 0);
 
-  ASSERT_FALSE(MutationReplaceIdentifier(use_id, replacement_id)
-                   .IsApplicable(program, node_id_map));
+    ASSERT_FALSE(
+        MutationReplaceIdentifier(use_id, replacement_id).IsApplicable(program, node_id_map));
 }
 
 TEST(ReplaceIdentifierTest, NotApplicable14) {
-  // Can't replace `ptr_a` with `ptr_b` (both are pointers with different
-  // storage class).
-  std::string shader = R"(
+    // Can't replace `ptr_a` with `ptr_b` (both are pointers with different
+    // storage class).
+    std::string shader = R"(
 var<private> b: vec2<u32>;
 fn f() {
   var a = vec2<u32>(34u, 45u);
@@ -634,30 +621,29 @@
   let c = (*ptr_a)[1];
 }
 )";
-  Source::File file("test.wgsl", shader);
-  auto program = reader::wgsl::Parse(&file);
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    Source::File file("test.wgsl", shader);
+    auto program = reader::wgsl::Parse(&file);
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  NodeIdMap node_id_map(program);
+    NodeIdMap node_id_map(program);
 
-  auto use_id = node_id_map.GetId(
-      program.AST()
-          .Functions()[0]
-          ->body->statements[3]
-          ->As<ast::VariableDeclStatement>()
-          ->variable->constructor->As<ast::IndexAccessorExpression>()
-          ->object->As<ast::UnaryOpExpression>()
-          ->expr);
-  ASSERT_NE(use_id, 0);
+    auto use_id = node_id_map.GetId(program.AST()
+                                        .Functions()[0]
+                                        ->body->statements[3]
+                                        ->As<ast::VariableDeclStatement>()
+                                        ->variable->constructor->As<ast::IndexAccessorExpression>()
+                                        ->object->As<ast::UnaryOpExpression>()
+                                        ->expr);
+    ASSERT_NE(use_id, 0);
 
-  auto replacement_id = node_id_map.GetId(program.AST()
-                                              .Functions()[0]
-                                              ->body->statements[2]
-                                              ->As<ast::VariableDeclStatement>()
-                                              ->variable);
-  ASSERT_NE(replacement_id, 0);
-  ASSERT_FALSE(MutationReplaceIdentifier(use_id, replacement_id)
-                   .IsApplicable(program, node_id_map));
+    auto replacement_id = node_id_map.GetId(program.AST()
+                                                .Functions()[0]
+                                                ->body->statements[2]
+                                                ->As<ast::VariableDeclStatement>()
+                                                ->variable);
+    ASSERT_NE(replacement_id, 0);
+    ASSERT_FALSE(
+        MutationReplaceIdentifier(use_id, replacement_id).IsApplicable(program, node_id_map));
 }
 
 }  // namespace
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/mutations/wrap_unary_operator.cc b/src/tint/fuzzers/tint_ast_fuzzer/mutations/wrap_unary_operator.cc
index d9db3e3..8b52732 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/mutations/wrap_unary_operator.cc
+++ b/src/tint/fuzzers/tint_ast_fuzzer/mutations/wrap_unary_operator.cc
@@ -21,103 +21,96 @@
 
 namespace tint::fuzzers::ast_fuzzer {
 
-MutationWrapUnaryOperator::MutationWrapUnaryOperator(
-    protobufs::MutationWrapUnaryOperator message)
+MutationWrapUnaryOperator::MutationWrapUnaryOperator(protobufs::MutationWrapUnaryOperator message)
     : message_(std::move(message)) {}
 
-MutationWrapUnaryOperator::MutationWrapUnaryOperator(
-    uint32_t expression_id,
-    uint32_t fresh_id,
-    ast::UnaryOp unary_op_wrapper) {
-  message_.set_expression_id(expression_id);
-  message_.set_fresh_id(fresh_id);
-  message_.set_unary_op_wrapper(static_cast<uint32_t>(unary_op_wrapper));
+MutationWrapUnaryOperator::MutationWrapUnaryOperator(uint32_t expression_id,
+                                                     uint32_t fresh_id,
+                                                     ast::UnaryOp unary_op_wrapper) {
+    message_.set_expression_id(expression_id);
+    message_.set_fresh_id(fresh_id);
+    message_.set_unary_op_wrapper(static_cast<uint32_t>(unary_op_wrapper));
 }
 
-bool MutationWrapUnaryOperator::IsApplicable(
-    const tint::Program& program,
-    const NodeIdMap& node_id_map) const {
-  // Check if id that will be assigned is fresh.
-  if (!node_id_map.IdIsFreshAndValid(message_.fresh_id())) {
-    return false;
-  }
+bool MutationWrapUnaryOperator::IsApplicable(const tint::Program& program,
+                                             const NodeIdMap& node_id_map) const {
+    // Check if id that will be assigned is fresh.
+    if (!node_id_map.IdIsFreshAndValid(message_.fresh_id())) {
+        return false;
+    }
 
-  const auto* expression_ast_node =
-      tint::As<ast::Expression>(node_id_map.GetNode(message_.expression_id()));
+    const auto* expression_ast_node =
+        tint::As<ast::Expression>(node_id_map.GetNode(message_.expression_id()));
 
-  if (!expression_ast_node) {
-    // Either the node is not present with the given id or
-    // the node is not a valid expression type.
-    return false;
-  }
+    if (!expression_ast_node) {
+        // Either the node is not present with the given id or
+        // the node is not a valid expression type.
+        return false;
+    }
 
-  const auto* expression_sem_node =
-      tint::As<sem::Expression>(program.Sem().Get(expression_ast_node));
+    const auto* expression_sem_node =
+        tint::As<sem::Expression>(program.Sem().Get(expression_ast_node));
 
-  if (!expression_sem_node) {
-    // Semantic information for the expression ast node is not present
-    // or the semantic node is not a valid expression type node.
-    return false;
-  }
+    if (!expression_sem_node) {
+        // Semantic information for the expression ast node is not present
+        // or the semantic node is not a valid expression type node.
+        return false;
+    }
 
-  ast::UnaryOp unary_op_wrapper =
-      static_cast<ast::UnaryOp>(message_.unary_op_wrapper());
+    ast::UnaryOp unary_op_wrapper = static_cast<ast::UnaryOp>(message_.unary_op_wrapper());
 
-  std::vector<ast::UnaryOp> valid_ops =
-      GetValidUnaryWrapper(*expression_sem_node);
+    std::vector<ast::UnaryOp> valid_ops = GetValidUnaryWrapper(*expression_sem_node);
 
-  // There is no available unary operator or |unary_op_wrapper| is a
-  // type that is not allowed for the given expression.
-  if (std::find(valid_ops.begin(), valid_ops.end(), unary_op_wrapper) ==
-      valid_ops.end()) {
-    return false;
-  }
+    // There is no available unary operator or |unary_op_wrapper| is a
+    // type that is not allowed for the given expression.
+    if (std::find(valid_ops.begin(), valid_ops.end(), unary_op_wrapper) == valid_ops.end()) {
+        return false;
+    }
 
-  return true;
+    return true;
 }
 
 void MutationWrapUnaryOperator::Apply(const NodeIdMap& node_id_map,
                                       tint::CloneContext* clone_context,
                                       NodeIdMap* new_node_id_map) const {
-  auto* expression_node =
-      tint::As<ast::Expression>(node_id_map.GetNode(message_.expression_id()));
+    auto* expression_node =
+        tint::As<ast::Expression>(node_id_map.GetNode(message_.expression_id()));
 
-  auto* replacement_expression_node =
-      clone_context->dst->create<ast::UnaryOpExpression>(
-          static_cast<ast::UnaryOp>(message_.unary_op_wrapper()),
-          clone_context->Clone(expression_node));
+    auto* replacement_expression_node = clone_context->dst->create<ast::UnaryOpExpression>(
+        static_cast<ast::UnaryOp>(message_.unary_op_wrapper()),
+        clone_context->Clone(expression_node));
 
-  clone_context->Replace(expression_node, replacement_expression_node);
+    clone_context->Replace(expression_node, replacement_expression_node);
 
-  new_node_id_map->Add(replacement_expression_node, message_.fresh_id());
+    new_node_id_map->Add(replacement_expression_node, message_.fresh_id());
 }
 
 protobufs::Mutation MutationWrapUnaryOperator::ToMessage() const {
-  protobufs::Mutation mutation;
-  *mutation.mutable_wrap_unary_operator() = message_;
-  return mutation;
+    protobufs::Mutation mutation;
+    *mutation.mutable_wrap_unary_operator() = message_;
+    return mutation;
 }
 
 std::vector<ast::UnaryOp> MutationWrapUnaryOperator::GetValidUnaryWrapper(
     const sem::Expression& expr) {
-  const auto* expr_type = expr.Type();
-  if (expr_type->is_bool_scalar_or_vector()) {
-    return {ast::UnaryOp::kNot};
-  }
+    const auto* expr_type = expr.Type();
+    if (expr_type->is_bool_scalar_or_vector()) {
+        return {ast::UnaryOp::kNot};
+    }
 
-  if (expr_type->is_signed_scalar_or_vector()) {
-    return {ast::UnaryOp::kNegation, ast::UnaryOp::kComplement};
-  }
+    if (expr_type->is_signed_scalar_or_vector()) {
+        return {ast::UnaryOp::kNegation, ast::UnaryOp::kComplement};
+    }
 
-  if (expr_type->is_unsigned_scalar_or_vector()) {
-    return {ast::UnaryOp::kComplement};
-  }
+    if (expr_type->is_unsigned_scalar_or_vector()) {
+        return {ast::UnaryOp::kComplement};
+    }
 
-  if (expr_type->is_float_scalar_or_vector()) {
-    return {ast::UnaryOp::kNegation};
-  }
+    if (expr_type->is_float_scalar_or_vector()) {
+        return {ast::UnaryOp::kNegation};
+    }
 
-  return {};
+    return {};
 }
 
 }  // namespace tint::fuzzers::ast_fuzzer
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/mutations/wrap_unary_operator.h b/src/tint/fuzzers/tint_ast_fuzzer/mutations/wrap_unary_operator.h
index 85293ee..ec28bf9 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/mutations/wrap_unary_operator.h
+++ b/src/tint/fuzzers/tint_ast_fuzzer/mutations/wrap_unary_operator.h
@@ -25,55 +25,52 @@
 
 /// @see MutationWrapUnaryOperator::Apply
 class MutationWrapUnaryOperator : public Mutation {
- public:
-  /// @brief Constructs an instance of this mutation from a protobuf message.
-  /// @param message - protobuf message
-  explicit MutationWrapUnaryOperator(
-      protobufs::MutationWrapUnaryOperator message);
+  public:
+    /// @brief Constructs an instance of this mutation from a protobuf message.
+    /// @param message - protobuf message
+    explicit MutationWrapUnaryOperator(protobufs::MutationWrapUnaryOperator message);
 
-  /// @brief Constructor.
-  /// @param expression_id - the id of an expression.
-  /// @param fresh_id - a fresh id for the created expression node with
-  /// unary operator wrapper.
-  /// @param unary_op_wrapper - a `ast::UnaryOp` instance.
-  MutationWrapUnaryOperator(uint32_t expression_id,
-                            uint32_t fresh_id,
-                            ast::UnaryOp unary_op_wrapper);
+    /// @brief Constructor.
+    /// @param expression_id - the id of an expression.
+    /// @param fresh_id - a fresh id for the created expression node with
+    /// unary operator wrapper.
+    /// @param unary_op_wrapper - a `ast::UnaryOp` instance.
+    MutationWrapUnaryOperator(uint32_t expression_id,
+                              uint32_t fresh_id,
+                              ast::UnaryOp unary_op_wrapper);
 
-  /// @copybrief Mutation::IsApplicable
-  ///
-  /// The mutation is applicable iff:
-  /// - `expression_id` must refer to a valid expression that can be wrapped
-  ///    with unary operator.
-  /// - `fresh_id` must be fresh.
-  /// - `unary_op_wrapper` is a unary expression that is valid based on the
-  ///   type of the given expression.
-  ///
-  /// @copydetails Mutation::IsApplicable
-  bool IsApplicable(const tint::Program& program,
-                    const NodeIdMap& node_id_map) const override;
+    /// @copybrief Mutation::IsApplicable
+    ///
+    /// The mutation is applicable iff:
+    /// - `expression_id` must refer to a valid expression that can be wrapped
+    ///    with unary operator.
+    /// - `fresh_id` must be fresh.
+    /// - `unary_op_wrapper` is a unary expression that is valid based on the
+    ///   type of the given expression.
+    ///
+    /// @copydetails Mutation::IsApplicable
+    bool IsApplicable(const tint::Program& program, const NodeIdMap& node_id_map) const override;
 
-  /// @copybrief Mutation::Apply
-  ///
-  /// Wrap an expression in a unary operator that is valid based on
-  /// the type of the expression.
-  ///
-  /// @copydetails Mutation::Apply
-  void Apply(const NodeIdMap& node_id_map,
-             tint::CloneContext* clone_context,
-             NodeIdMap* new_node_id_map) const override;
+    /// @copybrief Mutation::Apply
+    ///
+    /// Wrap an expression in a unary operator that is valid based on
+    /// the type of the expression.
+    ///
+    /// @copydetails Mutation::Apply
+    void Apply(const NodeIdMap& node_id_map,
+               tint::CloneContext* clone_context,
+               NodeIdMap* new_node_id_map) const override;
 
-  protobufs::Mutation ToMessage() const override;
+    protobufs::Mutation ToMessage() const override;
 
-  /// Return list of unary operator wrappers allowed for the given
-  /// expression.
-  /// @param expr - an `ast::Expression` instance from node id map.
-  /// @return a list of unary operators.
-  static std::vector<ast::UnaryOp> GetValidUnaryWrapper(
-      const sem::Expression& expr);
+    /// Return list of unary operator wrappers allowed for the given
+    /// expression.
+    /// @param expr - an `ast::Expression` instance from node id map.
+    /// @return a list of unary operators.
+    static std::vector<ast::UnaryOp> GetValidUnaryWrapper(const sem::Expression& expr);
 
- private:
-  protobufs::MutationWrapUnaryOperator message_;
+  private:
+    protobufs::MutationWrapUnaryOperator message_;
 };
 
 }  // namespace tint::fuzzers::ast_fuzzer
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/mutations/wrap_unary_operator_test.cc b/src/tint/fuzzers/tint_ast_fuzzer/mutations/wrap_unary_operator_test.cc
index bbbe7a0..a22e2b9 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/mutations/wrap_unary_operator_test.cc
+++ b/src/tint/fuzzers/tint_ast_fuzzer/mutations/wrap_unary_operator_test.cc
@@ -28,7 +28,7 @@
 namespace {
 
 TEST(WrapUnaryOperatorTest, Applicable1) {
-  std::string content = R"(
+    std::string content = R"(
     fn main() {
       var a = 5;
       if (a < 5) {
@@ -36,246 +36,238 @@
       }
     }
   )";
-  Source::File file("test.wgsl", content);
-  auto program = reader::wgsl::Parse(&file);
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    Source::File file("test.wgsl", content);
+    auto program = reader::wgsl::Parse(&file);
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  NodeIdMap node_id_map(program);
+    NodeIdMap node_id_map(program);
 
-  const auto& main_fn_statements =
-      program.AST().Functions()[0]->body->statements;
+    const auto& main_fn_statements = program.AST().Functions()[0]->body->statements;
 
-  auto expression_id = node_id_map.GetId(
-      main_fn_statements[1]->As<ast::IfStatement>()->condition);
-  ASSERT_NE(expression_id, 0);
+    auto expression_id =
+        node_id_map.GetId(main_fn_statements[1]->As<ast::IfStatement>()->condition);
+    ASSERT_NE(expression_id, 0);
 
-  ASSERT_TRUE(MaybeApplyMutation(
-      program,
-      MutationWrapUnaryOperator(expression_id, node_id_map.TakeFreshId(),
-                                ast::UnaryOp::kNot),
-      node_id_map, &program, &node_id_map, nullptr));
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    ASSERT_TRUE(MaybeApplyMutation(
+        program,
+        MutationWrapUnaryOperator(expression_id, node_id_map.TakeFreshId(), ast::UnaryOp::kNot),
+        node_id_map, &program, &node_id_map, nullptr));
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  writer::wgsl::Options options;
-  auto result = writer::wgsl::Generate(&program, options);
-  ASSERT_TRUE(result.success) << result.error;
+    writer::wgsl::Options options;
+    auto result = writer::wgsl::Generate(&program, options);
+    ASSERT_TRUE(result.success) << result.error;
 
-  std::string expected_shader = R"(fn main() {
+    std::string expected_shader = R"(fn main() {
   var a = 5;
   if (!((a < 5))) {
     a = 6;
   }
 }
 )";
-  ASSERT_EQ(expected_shader, result.wgsl);
+    ASSERT_EQ(expected_shader, result.wgsl);
 }
 
 TEST(WrapUnaryOperatorTest, Applicable2) {
-  std::string content = R"(
+    std::string content = R"(
     fn main() {
       let a = vec3<bool>(true, false, true);
     }
   )";
-  Source::File file("test.wgsl", content);
-  auto program = reader::wgsl::Parse(&file);
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    Source::File file("test.wgsl", content);
+    auto program = reader::wgsl::Parse(&file);
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  NodeIdMap node_id_map(program);
+    NodeIdMap node_id_map(program);
 
-  const auto& main_fn_statements =
-      program.AST().Functions()[0]->body->statements;
+    const auto& main_fn_statements = program.AST().Functions()[0]->body->statements;
 
-  const auto* expr = main_fn_statements[0]
-                         ->As<ast::VariableDeclStatement>()
-                         ->variable->constructor->As<ast::Expression>();
+    const auto* expr = main_fn_statements[0]
+                           ->As<ast::VariableDeclStatement>()
+                           ->variable->constructor->As<ast::Expression>();
 
-  const auto expression_id = node_id_map.GetId(expr);
-  ASSERT_NE(expression_id, 0);
+    const auto expression_id = node_id_map.GetId(expr);
+    ASSERT_NE(expression_id, 0);
 
-  ASSERT_TRUE(MaybeApplyMutation(
-      program,
-      MutationWrapUnaryOperator(expression_id, node_id_map.TakeFreshId(),
-                                ast::UnaryOp::kNot),
-      node_id_map, &program, &node_id_map, nullptr));
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    ASSERT_TRUE(MaybeApplyMutation(
+        program,
+        MutationWrapUnaryOperator(expression_id, node_id_map.TakeFreshId(), ast::UnaryOp::kNot),
+        node_id_map, &program, &node_id_map, nullptr));
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  writer::wgsl::Options options;
-  auto result = writer::wgsl::Generate(&program, options);
-  ASSERT_TRUE(result.success) << result.error;
+    writer::wgsl::Options options;
+    auto result = writer::wgsl::Generate(&program, options);
+    ASSERT_TRUE(result.success) << result.error;
 
-  std::string expected_shader = R"(fn main() {
+    std::string expected_shader = R"(fn main() {
   let a = !(vec3<bool>(true, false, true));
 }
 )";
-  ASSERT_EQ(expected_shader, result.wgsl);
+    ASSERT_EQ(expected_shader, result.wgsl);
 }
 
 TEST(WrapUnaryOperatorTest, Applicable3) {
-  std::string content = R"(
+    std::string content = R"(
     fn main() {
       var a : u32;
       a = 6u;
     }
   )";
-  Source::File file("test.wgsl", content);
-  auto program = reader::wgsl::Parse(&file);
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    Source::File file("test.wgsl", content);
+    auto program = reader::wgsl::Parse(&file);
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  NodeIdMap node_id_map(program);
+    NodeIdMap node_id_map(program);
 
-  const auto& main_fn_statements =
-      program.AST().Functions()[0]->body->statements;
+    const auto& main_fn_statements = program.AST().Functions()[0]->body->statements;
 
-  const auto* expr = main_fn_statements[1]->As<ast::AssignmentStatement>()->rhs;
+    const auto* expr = main_fn_statements[1]->As<ast::AssignmentStatement>()->rhs;
 
-  const auto expression_id = node_id_map.GetId(expr);
-  ASSERT_NE(expression_id, 0);
+    const auto expression_id = node_id_map.GetId(expr);
+    ASSERT_NE(expression_id, 0);
 
-  ASSERT_TRUE(MaybeApplyMutation(
-      program,
-      MutationWrapUnaryOperator(expression_id, node_id_map.TakeFreshId(),
-                                ast::UnaryOp::kComplement),
-      node_id_map, &program, &node_id_map, nullptr));
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    ASSERT_TRUE(
+        MaybeApplyMutation(program,
+                           MutationWrapUnaryOperator(expression_id, node_id_map.TakeFreshId(),
+                                                     ast::UnaryOp::kComplement),
+                           node_id_map, &program, &node_id_map, nullptr));
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  writer::wgsl::Options options;
-  auto result = writer::wgsl::Generate(&program, options);
-  ASSERT_TRUE(result.success) << result.error;
+    writer::wgsl::Options options;
+    auto result = writer::wgsl::Generate(&program, options);
+    ASSERT_TRUE(result.success) << result.error;
 
-  std::string expected_shader = R"(fn main() {
+    std::string expected_shader = R"(fn main() {
   var a : u32;
   a = ~(6u);
 }
 )";
-  ASSERT_EQ(expected_shader, result.wgsl);
+    ASSERT_EQ(expected_shader, result.wgsl);
 }
 
 TEST(WrapUnaryOperatorTest, Applicable4) {
-  std::string content = R"(
+    std::string content = R"(
     fn main() -> vec2<bool> {
       var a = (vec2<u32> (1u, 2u) == vec2<u32> (1u, 2u));
       return a;
     }
   )";
-  Source::File file("test.wgsl", content);
-  auto program = reader::wgsl::Parse(&file);
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    Source::File file("test.wgsl", content);
+    auto program = reader::wgsl::Parse(&file);
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  NodeIdMap node_id_map(program);
+    NodeIdMap node_id_map(program);
 
-  const auto& main_fn_statements =
-      program.AST().Functions()[0]->body->statements;
+    const auto& main_fn_statements = program.AST().Functions()[0]->body->statements;
 
-  const auto* expr = main_fn_statements[0]
-                         ->As<ast::VariableDeclStatement>()
-                         ->variable->constructor->As<ast::BinaryExpression>()
-                         ->lhs;
+    const auto* expr = main_fn_statements[0]
+                           ->As<ast::VariableDeclStatement>()
+                           ->variable->constructor->As<ast::BinaryExpression>()
+                           ->lhs;
 
-  const auto expression_id = node_id_map.GetId(expr);
-  ASSERT_NE(expression_id, 0);
+    const auto expression_id = node_id_map.GetId(expr);
+    ASSERT_NE(expression_id, 0);
 
-  ASSERT_TRUE(MaybeApplyMutation(
-      program,
-      MutationWrapUnaryOperator(expression_id, node_id_map.TakeFreshId(),
-                                ast::UnaryOp::kComplement),
-      node_id_map, &program, &node_id_map, nullptr));
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    ASSERT_TRUE(
+        MaybeApplyMutation(program,
+                           MutationWrapUnaryOperator(expression_id, node_id_map.TakeFreshId(),
+                                                     ast::UnaryOp::kComplement),
+                           node_id_map, &program, &node_id_map, nullptr));
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  writer::wgsl::Options options;
-  auto result = writer::wgsl::Generate(&program, options);
-  ASSERT_TRUE(result.success) << result.error;
+    writer::wgsl::Options options;
+    auto result = writer::wgsl::Generate(&program, options);
+    ASSERT_TRUE(result.success) << result.error;
 
-  std::string expected_shader = R"(fn main() -> vec2<bool> {
+    std::string expected_shader = R"(fn main() -> vec2<bool> {
   var a = (~(vec2<u32>(1u, 2u)) == vec2<u32>(1u, 2u));
   return a;
 }
 )";
-  ASSERT_EQ(expected_shader, result.wgsl);
+    ASSERT_EQ(expected_shader, result.wgsl);
 }
 
 TEST(WrapUnaryOperatorTest, Applicable5) {
-  std::string content = R"(
+    std::string content = R"(
     fn main() {
       let a : f32 = -(1.0);
     }
   )";
-  Source::File file("test.wgsl", content);
-  auto program = reader::wgsl::Parse(&file);
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    Source::File file("test.wgsl", content);
+    auto program = reader::wgsl::Parse(&file);
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  NodeIdMap node_id_map(program);
+    NodeIdMap node_id_map(program);
 
-  const auto& main_fn_statements =
-      program.AST().Functions()[0]->body->statements;
+    const auto& main_fn_statements = program.AST().Functions()[0]->body->statements;
 
-  const auto* expr = main_fn_statements[0]
-                         ->As<ast::VariableDeclStatement>()
-                         ->variable->constructor->As<ast::UnaryOpExpression>()
-                         ->expr;
+    const auto* expr = main_fn_statements[0]
+                           ->As<ast::VariableDeclStatement>()
+                           ->variable->constructor->As<ast::UnaryOpExpression>()
+                           ->expr;
 
-  const auto expression_id = node_id_map.GetId(expr);
-  ASSERT_NE(expression_id, 0);
+    const auto expression_id = node_id_map.GetId(expr);
+    ASSERT_NE(expression_id, 0);
 
-  ASSERT_TRUE(MaybeApplyMutation(
-      program,
-      MutationWrapUnaryOperator(expression_id, node_id_map.TakeFreshId(),
-                                ast::UnaryOp::kNegation),
-      node_id_map, &program, &node_id_map, nullptr));
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    ASSERT_TRUE(
+        MaybeApplyMutation(program,
+                           MutationWrapUnaryOperator(expression_id, node_id_map.TakeFreshId(),
+                                                     ast::UnaryOp::kNegation),
+                           node_id_map, &program, &node_id_map, nullptr));
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  writer::wgsl::Options options;
-  auto result = writer::wgsl::Generate(&program, options);
-  ASSERT_TRUE(result.success) << result.error;
+    writer::wgsl::Options options;
+    auto result = writer::wgsl::Generate(&program, options);
+    ASSERT_TRUE(result.success) << result.error;
 
-  std::string expected_shader = R"(fn main() {
+    std::string expected_shader = R"(fn main() {
   let a : f32 = -(-(1.0));
 }
 )";
-  ASSERT_EQ(expected_shader, result.wgsl);
+    ASSERT_EQ(expected_shader, result.wgsl);
 }
 
 TEST(WrapUnaryOperatorTest, Applicable6) {
-  std::string content = R"(
+    std::string content = R"(
     fn main() {
       var a : vec4<f32> = vec4<f32>(-1.0, -1.0, -1.0, -1.0);
     }
   )";
-  Source::File file("test.wgsl", content);
-  auto program = reader::wgsl::Parse(&file);
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    Source::File file("test.wgsl", content);
+    auto program = reader::wgsl::Parse(&file);
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  NodeIdMap node_id_map(program);
+    NodeIdMap node_id_map(program);
 
-  const auto& main_fn_statements =
-      program.AST().Functions()[0]->body->statements;
+    const auto& main_fn_statements = program.AST().Functions()[0]->body->statements;
 
-  const auto* expr = main_fn_statements[0]
-                         ->As<ast::VariableDeclStatement>()
-                         ->variable->constructor->As<ast::Expression>();
+    const auto* expr = main_fn_statements[0]
+                           ->As<ast::VariableDeclStatement>()
+                           ->variable->constructor->As<ast::Expression>();
 
-  const auto expression_id = node_id_map.GetId(expr);
-  ASSERT_NE(expression_id, 0);
+    const auto expression_id = node_id_map.GetId(expr);
+    ASSERT_NE(expression_id, 0);
 
-  ASSERT_TRUE(MaybeApplyMutation(
-      program,
-      MutationWrapUnaryOperator(expression_id, node_id_map.TakeFreshId(),
-                                ast::UnaryOp::kNegation),
-      node_id_map, &program, &node_id_map, nullptr));
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    ASSERT_TRUE(
+        MaybeApplyMutation(program,
+                           MutationWrapUnaryOperator(expression_id, node_id_map.TakeFreshId(),
+                                                     ast::UnaryOp::kNegation),
+                           node_id_map, &program, &node_id_map, nullptr));
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  writer::wgsl::Options options;
-  auto result = writer::wgsl::Generate(&program, options);
-  ASSERT_TRUE(result.success) << result.error;
+    writer::wgsl::Options options;
+    auto result = writer::wgsl::Generate(&program, options);
+    ASSERT_TRUE(result.success) << result.error;
 
-  std::string expected_shader = R"(fn main() {
+    std::string expected_shader = R"(fn main() {
   var a : vec4<f32> = -(vec4<f32>(-1.0, -1.0, -1.0, -1.0));
 }
 )";
-  ASSERT_EQ(expected_shader, result.wgsl);
+    ASSERT_EQ(expected_shader, result.wgsl);
 }
 
 TEST(WrapUnaryOperatorTest, Applicable7) {
-  std::string content = R"(
+    std::string content = R"(
     fn main() {
       var a = 1;
       for(var i : i32 = 1; i < 5; i = i + 1) {
@@ -283,261 +275,248 @@
       }
     }
   )";
-  Source::File file("test.wgsl", content);
-  auto program = reader::wgsl::Parse(&file);
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    Source::File file("test.wgsl", content);
+    auto program = reader::wgsl::Parse(&file);
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  NodeIdMap node_id_map(program);
+    NodeIdMap node_id_map(program);
 
-  const auto& main_fn_statements =
-      program.AST().Functions()[0]->body->statements;
+    const auto& main_fn_statements = program.AST().Functions()[0]->body->statements;
 
-  const auto* expr = main_fn_statements[1]
-                         ->As<ast::ForLoopStatement>()
-                         ->initializer->As<ast::VariableDeclStatement>()
-                         ->variable->constructor->As<ast::Expression>();
+    const auto* expr = main_fn_statements[1]
+                           ->As<ast::ForLoopStatement>()
+                           ->initializer->As<ast::VariableDeclStatement>()
+                           ->variable->constructor->As<ast::Expression>();
 
-  const auto expression_id = node_id_map.GetId(expr);
-  ASSERT_NE(expression_id, 0);
+    const auto expression_id = node_id_map.GetId(expr);
+    ASSERT_NE(expression_id, 0);
 
-  ASSERT_TRUE(MaybeApplyMutation(
-      program,
-      MutationWrapUnaryOperator(expression_id, node_id_map.TakeFreshId(),
-                                ast::UnaryOp::kNegation),
-      node_id_map, &program, &node_id_map, nullptr));
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    ASSERT_TRUE(
+        MaybeApplyMutation(program,
+                           MutationWrapUnaryOperator(expression_id, node_id_map.TakeFreshId(),
+                                                     ast::UnaryOp::kNegation),
+                           node_id_map, &program, &node_id_map, nullptr));
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  writer::wgsl::Options options;
-  auto result = writer::wgsl::Generate(&program, options);
-  ASSERT_TRUE(result.success) << result.error;
+    writer::wgsl::Options options;
+    auto result = writer::wgsl::Generate(&program, options);
+    ASSERT_TRUE(result.success) << result.error;
 
-  std::string expected_shader = R"(fn main() {
+    std::string expected_shader = R"(fn main() {
   var a = 1;
   for(var i : i32 = -(1); (i < 5); i = (i + 1)) {
     a = (a + 1);
   }
 }
 )";
-  ASSERT_EQ(expected_shader, result.wgsl);
+    ASSERT_EQ(expected_shader, result.wgsl);
 }
 
 TEST(WrapUnaryOperatorTest, Applicable8) {
-  std::string content = R"(
+    std::string content = R"(
     fn main() {
       var a : vec4<i32> = vec4<i32>(1, 0, -1, 0);
     }
   )";
-  Source::File file("test.wgsl", content);
-  auto program = reader::wgsl::Parse(&file);
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    Source::File file("test.wgsl", content);
+    auto program = reader::wgsl::Parse(&file);
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  NodeIdMap node_id_map(program);
+    NodeIdMap node_id_map(program);
 
-  const auto& main_fn_statements =
-      program.AST().Functions()[0]->body->statements;
+    const auto& main_fn_statements = program.AST().Functions()[0]->body->statements;
 
-  const auto* expr = main_fn_statements[0]
-                         ->As<ast::VariableDeclStatement>()
-                         ->variable->constructor->As<ast::Expression>();
+    const auto* expr = main_fn_statements[0]
+                           ->As<ast::VariableDeclStatement>()
+                           ->variable->constructor->As<ast::Expression>();
 
-  const auto expression_id = node_id_map.GetId(expr);
-  ASSERT_NE(expression_id, 0);
+    const auto expression_id = node_id_map.GetId(expr);
+    ASSERT_NE(expression_id, 0);
 
-  ASSERT_TRUE(MaybeApplyMutation(
-      program,
-      MutationWrapUnaryOperator(expression_id, node_id_map.TakeFreshId(),
-                                ast::UnaryOp::kComplement),
-      node_id_map, &program, &node_id_map, nullptr));
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    ASSERT_TRUE(
+        MaybeApplyMutation(program,
+                           MutationWrapUnaryOperator(expression_id, node_id_map.TakeFreshId(),
+                                                     ast::UnaryOp::kComplement),
+                           node_id_map, &program, &node_id_map, nullptr));
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  writer::wgsl::Options options;
-  auto result = writer::wgsl::Generate(&program, options);
-  ASSERT_TRUE(result.success) << result.error;
+    writer::wgsl::Options options;
+    auto result = writer::wgsl::Generate(&program, options);
+    ASSERT_TRUE(result.success) << result.error;
 
-  std::string expected_shader = R"(fn main() {
+    std::string expected_shader = R"(fn main() {
   var a : vec4<i32> = ~(vec4<i32>(1, 0, -1, 0));
 }
 )";
-  ASSERT_EQ(expected_shader, result.wgsl);
+    ASSERT_EQ(expected_shader, result.wgsl);
 }
 
 TEST(WrapUnaryOperatorTest, NotApplicable1) {
-  std::string content = R"(
+    std::string content = R"(
     fn main() {
       let a = mat2x3<f32>(vec3<f32>(1.,0.,1.), vec3<f32>(0.,1.,0.));
     }
   )";
-  Source::File file("test.wgsl", content);
-  auto program = reader::wgsl::Parse(&file);
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    Source::File file("test.wgsl", content);
+    auto program = reader::wgsl::Parse(&file);
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  NodeIdMap node_id_map(program);
+    NodeIdMap node_id_map(program);
 
-  const auto& main_fn_statements =
-      program.AST().Functions()[0]->body->statements;
+    const auto& main_fn_statements = program.AST().Functions()[0]->body->statements;
 
-  const auto* expr = main_fn_statements[0]
-                         ->As<ast::VariableDeclStatement>()
-                         ->variable->constructor->As<ast::Expression>();
+    const auto* expr = main_fn_statements[0]
+                           ->As<ast::VariableDeclStatement>()
+                           ->variable->constructor->As<ast::Expression>();
 
-  const auto expression_id = node_id_map.GetId(expr);
-  ASSERT_NE(expression_id, 0);
+    const auto expression_id = node_id_map.GetId(expr);
+    ASSERT_NE(expression_id, 0);
 
-  // There is no unary operator that can be applied to matrix type.
-  ASSERT_FALSE(MaybeApplyMutation(
-      program,
-      MutationWrapUnaryOperator(expression_id, node_id_map.TakeFreshId(),
-                                ast::UnaryOp::kNegation),
-      node_id_map, &program, &node_id_map, nullptr));
+    // There is no unary operator that can be applied to matrix type.
+    ASSERT_FALSE(
+        MaybeApplyMutation(program,
+                           MutationWrapUnaryOperator(expression_id, node_id_map.TakeFreshId(),
+                                                     ast::UnaryOp::kNegation),
+                           node_id_map, &program, &node_id_map, nullptr));
 }
 
 TEST(WrapUnaryOperatorTest, NotApplicable2) {
-  std::string content = R"(
+    std::string content = R"(
     fn main() {
       let a = 1;
     }
   )";
-  Source::File file("test.wgsl", content);
-  auto program = reader::wgsl::Parse(&file);
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    Source::File file("test.wgsl", content);
+    auto program = reader::wgsl::Parse(&file);
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  NodeIdMap node_id_map(program);
+    NodeIdMap node_id_map(program);
 
-  const auto& main_fn_statements =
-      program.AST().Functions()[0]->body->statements;
+    const auto& main_fn_statements = program.AST().Functions()[0]->body->statements;
 
-  const auto* expr = main_fn_statements[0]
-                         ->As<ast::VariableDeclStatement>()
-                         ->variable->constructor->As<ast::Expression>();
+    const auto* expr = main_fn_statements[0]
+                           ->As<ast::VariableDeclStatement>()
+                           ->variable->constructor->As<ast::Expression>();
 
-  const auto expression_id = node_id_map.GetId(expr);
-  ASSERT_NE(expression_id, 0);
+    const auto expression_id = node_id_map.GetId(expr);
+    ASSERT_NE(expression_id, 0);
 
-  // Not cannot be applied to integer types.
-  ASSERT_FALSE(MaybeApplyMutation(
-      program,
-      MutationWrapUnaryOperator(expression_id, node_id_map.TakeFreshId(),
-                                ast::UnaryOp::kNot),
-      node_id_map, &program, &node_id_map, nullptr));
+    // Not cannot be applied to integer types.
+    ASSERT_FALSE(MaybeApplyMutation(
+        program,
+        MutationWrapUnaryOperator(expression_id, node_id_map.TakeFreshId(), ast::UnaryOp::kNot),
+        node_id_map, &program, &node_id_map, nullptr));
 }
 
 TEST(WrapUnaryOperatorTest, NotApplicable3) {
-  std::string content = R"(
+    std::string content = R"(
     fn main() {
       let a = vec2<u32>(1u, 2u);
     }
   )";
-  Source::File file("test.wgsl", content);
-  auto program = reader::wgsl::Parse(&file);
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    Source::File file("test.wgsl", content);
+    auto program = reader::wgsl::Parse(&file);
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  NodeIdMap node_id_map(program);
+    NodeIdMap node_id_map(program);
 
-  const auto& main_fn_statements =
-      program.AST().Functions()[0]->body->statements;
+    const auto& main_fn_statements = program.AST().Functions()[0]->body->statements;
 
-  const auto* expr = main_fn_statements[0]
-                         ->As<ast::VariableDeclStatement>()
-                         ->variable->constructor->As<ast::Expression>();
+    const auto* expr = main_fn_statements[0]
+                           ->As<ast::VariableDeclStatement>()
+                           ->variable->constructor->As<ast::Expression>();
 
-  const auto expression_id = node_id_map.GetId(expr);
-  ASSERT_NE(expression_id, 0);
+    const auto expression_id = node_id_map.GetId(expr);
+    ASSERT_NE(expression_id, 0);
 
-  // Negation cannot be applied to unsigned integer scalar or vectors.
-  ASSERT_FALSE(MaybeApplyMutation(
-      program,
-      MutationWrapUnaryOperator(expression_id, node_id_map.TakeFreshId(),
-                                ast::UnaryOp::kNegation),
-      node_id_map, &program, &node_id_map, nullptr));
+    // Negation cannot be applied to unsigned integer scalar or vectors.
+    ASSERT_FALSE(
+        MaybeApplyMutation(program,
+                           MutationWrapUnaryOperator(expression_id, node_id_map.TakeFreshId(),
+                                                     ast::UnaryOp::kNegation),
+                           node_id_map, &program, &node_id_map, nullptr));
 }
 
 TEST(WrapUnaryOperatorTest, NotApplicable4) {
-  std::string content = R"(
+    std::string content = R"(
     fn main() {
       let a = 1.5;
     }
   )";
-  Source::File file("test.wgsl", content);
-  auto program = reader::wgsl::Parse(&file);
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    Source::File file("test.wgsl", content);
+    auto program = reader::wgsl::Parse(&file);
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  NodeIdMap node_id_map(program);
+    NodeIdMap node_id_map(program);
 
-  const auto& main_fn_statements =
-      program.AST().Functions()[0]->body->statements;
+    const auto& main_fn_statements = program.AST().Functions()[0]->body->statements;
 
-  const auto* expr = main_fn_statements[0]
-                         ->As<ast::VariableDeclStatement>()
-                         ->variable->constructor->As<ast::Expression>();
+    const auto* expr = main_fn_statements[0]
+                           ->As<ast::VariableDeclStatement>()
+                           ->variable->constructor->As<ast::Expression>();
 
-  const auto expression_id = node_id_map.GetId(expr);
-  ASSERT_NE(expression_id, 0);
+    const auto expression_id = node_id_map.GetId(expr);
+    ASSERT_NE(expression_id, 0);
 
-  // Cannot wrap float types with complement operator.
-  ASSERT_FALSE(MaybeApplyMutation(
-      program,
-      MutationWrapUnaryOperator(expression_id, node_id_map.TakeFreshId(),
-                                ast::UnaryOp::kComplement),
-      node_id_map, &program, &node_id_map, nullptr));
+    // Cannot wrap float types with complement operator.
+    ASSERT_FALSE(
+        MaybeApplyMutation(program,
+                           MutationWrapUnaryOperator(expression_id, node_id_map.TakeFreshId(),
+                                                     ast::UnaryOp::kComplement),
+                           node_id_map, &program, &node_id_map, nullptr));
 }
 
 TEST(WrapUnaryOperatorTest, NotApplicable5) {
-  std::string content = R"(
+    std::string content = R"(
     fn main() {
       let a = 1.5;
     }
   )";
-  Source::File file("test.wgsl", content);
-  auto program = reader::wgsl::Parse(&file);
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    Source::File file("test.wgsl", content);
+    auto program = reader::wgsl::Parse(&file);
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  NodeIdMap node_id_map(program);
+    NodeIdMap node_id_map(program);
 
-  const auto& main_fn_statements =
-      program.AST().Functions()[0]->body->statements;
+    const auto& main_fn_statements = program.AST().Functions()[0]->body->statements;
 
-  const auto* expr = main_fn_statements[0]
-                         ->As<ast::VariableDeclStatement>()
-                         ->variable->constructor->As<ast::Expression>();
+    const auto* expr = main_fn_statements[0]
+                           ->As<ast::VariableDeclStatement>()
+                           ->variable->constructor->As<ast::Expression>();
 
-  const auto expression_id = node_id_map.GetId(expr);
-  ASSERT_NE(expression_id, 0);
+    const auto expression_id = node_id_map.GetId(expr);
+    ASSERT_NE(expression_id, 0);
 
-  // Id for the replacement expression is not fresh.
-  ASSERT_FALSE(
-      MaybeApplyMutation(program,
-                         MutationWrapUnaryOperator(expression_id, expression_id,
-                                                   ast::UnaryOp::kNegation),
-                         node_id_map, &program, &node_id_map, nullptr));
+    // Id for the replacement expression is not fresh.
+    ASSERT_FALSE(MaybeApplyMutation(
+        program, MutationWrapUnaryOperator(expression_id, expression_id, ast::UnaryOp::kNegation),
+        node_id_map, &program, &node_id_map, nullptr));
 }
 
 TEST(WrapUnaryOperatorTest, NotApplicable6) {
-  std::string content = R"(
+    std::string content = R"(
     fn main() {
       let a = 1.5;
     }
   )";
-  Source::File file("test.wgsl", content);
-  auto program = reader::wgsl::Parse(&file);
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    Source::File file("test.wgsl", content);
+    auto program = reader::wgsl::Parse(&file);
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
 
-  NodeIdMap node_id_map(program);
+    NodeIdMap node_id_map(program);
 
-  const auto& main_fn_statements =
-      program.AST().Functions()[0]->body->statements;
+    const auto& main_fn_statements = program.AST().Functions()[0]->body->statements;
 
-  const auto* statement =
-      main_fn_statements[0]->As<ast::VariableDeclStatement>();
+    const auto* statement = main_fn_statements[0]->As<ast::VariableDeclStatement>();
 
-  const auto statement_id = node_id_map.GetId(statement);
-  ASSERT_NE(statement_id, 0);
+    const auto statement_id = node_id_map.GetId(statement);
+    ASSERT_NE(statement_id, 0);
 
-  // The id provided for the expression is not a valid expression type.
-  ASSERT_FALSE(MaybeApplyMutation(
-      program,
-      MutationWrapUnaryOperator(statement_id, node_id_map.TakeFreshId(),
-                                ast::UnaryOp::kNegation),
-      node_id_map, &program, &node_id_map, nullptr));
+    // The id provided for the expression is not a valid expression type.
+    ASSERT_FALSE(MaybeApplyMutation(
+        program,
+        MutationWrapUnaryOperator(statement_id, node_id_map.TakeFreshId(), ast::UnaryOp::kNegation),
+        node_id_map, &program, &node_id_map, nullptr));
 }
 
 }  // namespace
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/mutator.cc b/src/tint/fuzzers/tint_ast_fuzzer/mutator.cc
index e4915c6..f70a947 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/mutator.cc
+++ b/src/tint/fuzzers/tint_ast_fuzzer/mutator.cc
@@ -21,6 +21,7 @@
 #include <vector>
 
 #include "src/tint/fuzzers/tint_ast_fuzzer/mutation_finders/change_binary_operators.h"
+#include "src/tint/fuzzers/tint_ast_fuzzer/mutation_finders/change_unary_operators.h"
 #include "src/tint/fuzzers/tint_ast_fuzzer/mutation_finders/replace_identifiers.h"
 #include "src/tint/fuzzers/tint_ast_fuzzer/mutation_finders/wrap_unary_operators.h"
 #include "src/tint/fuzzers/tint_ast_fuzzer/node_id_map.h"
@@ -34,24 +35,25 @@
                     ProbabilityContext* probability_context,
                     MutationFinderList* finders,
                     Args&&... args) {
-  if (enable_all_mutations || probability_context->RandomBool()) {
-    finders->push_back(std::make_unique<T>(std::forward<Args>(args)...));
-  }
+    if (enable_all_mutations || probability_context->RandomBool()) {
+        finders->push_back(std::make_unique<T>(std::forward<Args>(args)...));
+    }
 }
 
-MutationFinderList CreateMutationFinders(
-    ProbabilityContext* probability_context,
-    bool enable_all_mutations) {
-  MutationFinderList result;
-  do {
-    MaybeAddFinder<MutationFinderChangeBinaryOperators>(
-        enable_all_mutations, probability_context, &result);
-    MaybeAddFinder<MutationFinderReplaceIdentifiers>(
-        enable_all_mutations, probability_context, &result);
-    MaybeAddFinder<MutationFinderWrapUnaryOperators>(
-        enable_all_mutations, probability_context, &result);
-  } while (result.empty());
-  return result;
+MutationFinderList CreateMutationFinders(ProbabilityContext* probability_context,
+                                         bool enable_all_mutations) {
+    MutationFinderList result;
+    do {
+        MaybeAddFinder<MutationFinderChangeBinaryOperators>(enable_all_mutations,
+                                                            probability_context, &result);
+        MaybeAddFinder<MutationFinderChangeUnaryOperators>(enable_all_mutations,
+                                                           probability_context, &result);
+        MaybeAddFinder<MutationFinderReplaceIdentifiers>(enable_all_mutations, probability_context,
+                                                         &result);
+        MaybeAddFinder<MutationFinderWrapUnaryOperators>(enable_all_mutations, probability_context,
+                                                         &result);
+    } while (result.empty());
+    return result;
 }
 
 }  // namespace
@@ -62,54 +64,53 @@
                         tint::Program* out_program,
                         NodeIdMap* out_node_id_map,
                         protobufs::MutationSequence* mutation_sequence) {
-  assert(out_program && "`out_program` may not be a nullptr");
-  assert(out_node_id_map && "`out_node_id_map` may not be a nullptr");
+    assert(out_program && "`out_program` may not be a nullptr");
+    assert(out_node_id_map && "`out_node_id_map` may not be a nullptr");
 
-  if (!mutation.IsApplicable(program, node_id_map)) {
-    return false;
-  }
+    if (!mutation.IsApplicable(program, node_id_map)) {
+        return false;
+    }
 
-  // The mutated `program` will be copied into the `mutated` program builder.
-  tint::ProgramBuilder mutated;
-  tint::CloneContext clone_context(&mutated, &program);
-  NodeIdMap new_node_id_map;
-  clone_context.ReplaceAll(
-      [&node_id_map, &new_node_id_map, &clone_context](const ast::Node* node) {
-        // Make sure all `tint::ast::` nodes' ids are preserved.
-        auto* cloned = tint::As<ast::Node>(node->Clone(&clone_context));
-        new_node_id_map.Add(cloned, node_id_map.GetId(node));
-        return cloned;
-      });
+    // The mutated `program` will be copied into the `mutated` program builder.
+    tint::ProgramBuilder mutated;
+    tint::CloneContext clone_context(&mutated, &program);
+    NodeIdMap new_node_id_map;
+    clone_context.ReplaceAll(
+        [&node_id_map, &new_node_id_map, &clone_context](const ast::Node* node) {
+            // Make sure all `tint::ast::` nodes' ids are preserved.
+            auto* cloned = tint::As<ast::Node>(node->Clone(&clone_context));
+            new_node_id_map.Add(cloned, node_id_map.GetId(node));
+            return cloned;
+        });
 
-  mutation.Apply(node_id_map, &clone_context, &new_node_id_map);
-  if (mutation_sequence) {
-    *mutation_sequence->add_mutation() = mutation.ToMessage();
-  }
+    mutation.Apply(node_id_map, &clone_context, &new_node_id_map);
+    if (mutation_sequence) {
+        *mutation_sequence->add_mutation() = mutation.ToMessage();
+    }
 
-  clone_context.Clone();
-  *out_program = tint::Program(std::move(mutated));
-  *out_node_id_map = std::move(new_node_id_map);
-  return true;
+    clone_context.Clone();
+    *out_program = tint::Program(std::move(mutated));
+    *out_node_id_map = std::move(new_node_id_map);
+    return true;
 }
 
-tint::Program Replay(tint::Program program,
-                     const protobufs::MutationSequence& mutation_sequence) {
-  assert(program.IsValid() && "Initial program is invalid");
+tint::Program Replay(tint::Program program, const protobufs::MutationSequence& mutation_sequence) {
+    assert(program.IsValid() && "Initial program is invalid");
 
-  NodeIdMap node_id_map(program);
-  for (const auto& mutation_message : mutation_sequence.mutation()) {
-    auto mutation = Mutation::FromMessage(mutation_message);
-    auto status = MaybeApplyMutation(program, *mutation, node_id_map, &program,
-                                     &node_id_map, nullptr);
-    (void)status;  // `status` will be unused in release mode.
-    assert(status && "`mutation` is inapplicable - it's most likely a bug");
-    if (!program.IsValid()) {
-      // `mutation` has a bug.
-      break;
+    NodeIdMap node_id_map(program);
+    for (const auto& mutation_message : mutation_sequence.mutation()) {
+        auto mutation = Mutation::FromMessage(mutation_message);
+        auto status =
+            MaybeApplyMutation(program, *mutation, node_id_map, &program, &node_id_map, nullptr);
+        (void)status;  // `status` will be unused in release mode.
+        assert(status && "`mutation` is inapplicable - it's most likely a bug");
+        if (!program.IsValid()) {
+            // `mutation` has a bug.
+            break;
+        }
     }
-  }
 
-  return program;
+    return program;
 }
 
 tint::Program Mutate(tint::Program program,
@@ -117,69 +118,64 @@
                      bool enable_all_mutations,
                      uint32_t max_applied_mutations,
                      protobufs::MutationSequence* mutation_sequence) {
-  assert(max_applied_mutations != 0 &&
-         "Maximum number of mutations is invalid");
-  assert(program.IsValid() && "Initial program is invalid");
+    assert(max_applied_mutations != 0 && "Maximum number of mutations is invalid");
+    assert(program.IsValid() && "Initial program is invalid");
 
-  // The number of allowed failed attempts to apply mutations. If this number is
-  // exceeded, the mutator is considered stuck and the mutation session is
-  // stopped.
-  const uint32_t kMaxFailureToApply = 10;
+    // The number of allowed failed attempts to apply mutations. If this number is
+    // exceeded, the mutator is considered stuck and the mutation session is
+    // stopped.
+    const uint32_t kMaxFailureToApply = 10;
 
-  auto finders =
-      CreateMutationFinders(probability_context, enable_all_mutations);
-  NodeIdMap node_id_map(program);
+    auto finders = CreateMutationFinders(probability_context, enable_all_mutations);
+    NodeIdMap node_id_map(program);
 
-  // Total number of applied mutations during this call to `Mutate`.
-  uint32_t applied_mutations = 0;
+    // Total number of applied mutations during this call to `Mutate`.
+    uint32_t applied_mutations = 0;
 
-  // The number of consecutively failed attempts to apply mutations.
-  uint32_t failure_to_apply = 0;
+    // The number of consecutively failed attempts to apply mutations.
+    uint32_t failure_to_apply = 0;
 
-  // Apply mutations as long as the `program` is valid, the limit on the number
-  // of mutations is not reached and the mutator is not stuck (i.e. unable to
-  // apply any mutations for some time).
-  while (program.IsValid() && applied_mutations < max_applied_mutations &&
-         failure_to_apply < kMaxFailureToApply) {
-    // Get all applicable mutations from some mutation finder.
-    const auto& mutation_finder =
-        finders[probability_context->GetRandomIndex(finders)];
-    auto mutations = mutation_finder->FindMutations(program, &node_id_map,
-                                                    probability_context);
+    // Apply mutations as long as the `program` is valid, the limit on the number
+    // of mutations is not reached and the mutator is not stuck (i.e. unable to
+    // apply any mutations for some time).
+    while (program.IsValid() && applied_mutations < max_applied_mutations &&
+           failure_to_apply < kMaxFailureToApply) {
+        // Get all applicable mutations from some mutation finder.
+        const auto& mutation_finder = finders[probability_context->GetRandomIndex(finders)];
+        auto mutations = mutation_finder->FindMutations(program, &node_id_map, probability_context);
 
-    const auto old_applied_mutations = applied_mutations;
-    for (const auto& mutation : mutations) {
-      if (!probability_context->ChoosePercentage(
-              mutation_finder->GetChanceOfApplyingMutation(
-                  probability_context))) {
-        // Skip this `mutation` probabilistically.
-        continue;
-      }
+        const auto old_applied_mutations = applied_mutations;
+        for (const auto& mutation : mutations) {
+            if (!probability_context->ChoosePercentage(
+                    mutation_finder->GetChanceOfApplyingMutation(probability_context))) {
+                // Skip this `mutation` probabilistically.
+                continue;
+            }
 
-      if (!MaybeApplyMutation(program, *mutation, node_id_map, &program,
-                              &node_id_map, mutation_sequence)) {
-        // This `mutation` is inapplicable. This may happen if some of the
-        // earlier mutations cancelled this one.
-        continue;
-      }
+            if (!MaybeApplyMutation(program, *mutation, node_id_map, &program, &node_id_map,
+                                    mutation_sequence)) {
+                // This `mutation` is inapplicable. This may happen if some of the
+                // earlier mutations cancelled this one.
+                continue;
+            }
 
-      applied_mutations++;
-      if (!program.IsValid()) {
-        // This `mutation` has a bug.
-        return program;
-      }
+            applied_mutations++;
+            if (!program.IsValid()) {
+                // This `mutation` has a bug.
+                return program;
+            }
+        }
+
+        if (old_applied_mutations == applied_mutations) {
+            // No mutation was applied. Increase the counter to prevent an infinite
+            // loop.
+            failure_to_apply++;
+        } else {
+            failure_to_apply = 0;
+        }
     }
 
-    if (old_applied_mutations == applied_mutations) {
-      // No mutation was applied. Increase the counter to prevent an infinite
-      // loop.
-      failure_to_apply++;
-    } else {
-      failure_to_apply = 0;
-    }
-  }
-
-  return program;
+    return program;
 }
 
 }  // namespace tint::fuzzers::ast_fuzzer
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/mutator.h b/src/tint/fuzzers/tint_ast_fuzzer/mutator.h
index 7b9dd74..747f1ba 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/mutator.h
+++ b/src/tint/fuzzers/tint_ast_fuzzer/mutator.h
@@ -65,8 +65,7 @@
 /// @param program - the initial program - must be valid.
 /// @param mutation_sequence - a sequence of mutations.
 /// @return the mutated program.
-tint::Program Replay(tint::Program program,
-                     const protobufs::MutationSequence& mutation_sequence);
+tint::Program Replay(tint::Program program, const protobufs::MutationSequence& mutation_sequence);
 
 /// @brief Applies up to `max_applied_mutations` mutations to the `program`.
 ///
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/node_id_map.cc b/src/tint/fuzzers/tint_ast_fuzzer/node_id_map.cc
index de6b4be..454d3bb 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/node_id_map.cc
+++ b/src/tint/fuzzers/tint_ast_fuzzer/node_id_map.cc
@@ -21,41 +21,41 @@
 NodeIdMap::NodeIdMap() = default;
 
 NodeIdMap::NodeIdMap(const Program& program) : NodeIdMap() {
-  for (const auto* node : program.ASTNodes().Objects()) {
-    Add(node, TakeFreshId());
-  }
+    for (const auto* node : program.ASTNodes().Objects()) {
+        Add(node, TakeFreshId());
+    }
 }
 
 NodeIdMap::IdType NodeIdMap::GetId(const ast::Node* node) const {
-  auto it = node_to_id_.find(node);
-  return it == node_to_id_.end() ? 0 : it->second;
+    auto it = node_to_id_.find(node);
+    return it == node_to_id_.end() ? 0 : it->second;
 }
 
 const ast::Node* NodeIdMap::GetNode(IdType id) const {
-  auto it = id_to_node_.find(id);
-  return it == id_to_node_.end() ? nullptr : it->second;
+    auto it = id_to_node_.find(id);
+    return it == id_to_node_.end() ? nullptr : it->second;
 }
 
 void NodeIdMap::Add(const ast::Node* node, IdType id) {
-  assert(!node_to_id_.count(node) && "The node already exists in the map");
-  assert(IdIsFreshAndValid(id) && "Id already exists in the map or Id is zero");
-  assert(node && "`node` can't be a nullptr");
+    assert(!node_to_id_.count(node) && "The node already exists in the map");
+    assert(IdIsFreshAndValid(id) && "Id already exists in the map or Id is zero");
+    assert(node && "`node` can't be a nullptr");
 
-  node_to_id_[node] = id;
-  id_to_node_[id] = node;
+    node_to_id_[node] = id;
+    id_to_node_[id] = node;
 
-  if (id >= fresh_id_) {
-    fresh_id_ = id + 1;
-  }
+    if (id >= fresh_id_) {
+        fresh_id_ = id + 1;
+    }
 }
 
 bool NodeIdMap::IdIsFreshAndValid(IdType id) const {
-  return id && !id_to_node_.count(id);
+    return id && !id_to_node_.count(id);
 }
 
 NodeIdMap::IdType NodeIdMap::TakeFreshId() {
-  assert(fresh_id_ != 0 && "`NodeIdMap` id has overflowed");
-  return fresh_id_++;
+    assert(fresh_id_ != 0 && "`NodeIdMap` id has overflowed");
+    return fresh_id_++;
 }
 
 }  // namespace tint::fuzzers::ast_fuzzer
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/node_id_map.h b/src/tint/fuzzers/tint_ast_fuzzer/node_id_map.h
index 4fee370..114e765 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/node_id_map.h
+++ b/src/tint/fuzzers/tint_ast_fuzzer/node_id_map.h
@@ -37,54 +37,54 @@
 /// are used in this class. To overcome this, a new instance of this class is
 /// created with all the cloned nodes and the old instance is discarded.
 class NodeIdMap {
- public:
-  /// Type of the id used by this map.
-  using IdType = uint32_t;
+  public:
+    /// Type of the id used by this map.
+    using IdType = uint32_t;
 
-  /// Creates an empty map.
-  NodeIdMap();
+    /// Creates an empty map.
+    NodeIdMap();
 
-  /// @brief Initializes this instance with all the nodes in the `program`.
-  /// @param program - must be valid.
-  explicit NodeIdMap(const Program& program);
+    /// @brief Initializes this instance with all the nodes in the `program`.
+    /// @param program - must be valid.
+    explicit NodeIdMap(const Program& program);
 
-  /// @brief Returns a node for the given `id`.
-  /// @param id - any value is accepted.
-  /// @return a pointer to some node if `id` exists in this map.
-  /// @return `nullptr` otherwise.
-  const ast::Node* GetNode(IdType id) const;
+    /// @brief Returns a node for the given `id`.
+    /// @param id - any value is accepted.
+    /// @return a pointer to some node if `id` exists in this map.
+    /// @return `nullptr` otherwise.
+    const ast::Node* GetNode(IdType id) const;
 
-  /// @brief Returns an id of the given `node`.
-  /// @param node - can be a `nullptr`.
-  /// @return not equal to 0 if `node` exists in this map.
-  /// @return 0 otherwise.
-  IdType GetId(const ast::Node* node) const;
+    /// @brief Returns an id of the given `node`.
+    /// @param node - can be a `nullptr`.
+    /// @return not equal to 0 if `node` exists in this map.
+    /// @return 0 otherwise.
+    IdType GetId(const ast::Node* node) const;
 
-  /// @brief Adds a mapping from `node` to `id` to this map.
-  /// @param node - may not be a `nullptr` and can't be present in this map.
-  /// @param id - may not be 0 and can't be present in this map.
-  void Add(const ast::Node* node, IdType id);
+    /// @brief Adds a mapping from `node` to `id` to this map.
+    /// @param node - may not be a `nullptr` and can't be present in this map.
+    /// @param id - may not be 0 and can't be present in this map.
+    void Add(const ast::Node* node, IdType id);
 
-  /// @brief Returns whether the id is fresh by checking if it exists in
-  /// the id map and the id is not 0.
-  /// @param id - an id that is used to check in the map.
-  /// @return true the given id is fresh and valid (non-zero).
-  /// @return false otherwise.
-  bool IdIsFreshAndValid(IdType id) const;
+    /// @brief Returns whether the id is fresh by checking if it exists in
+    /// the id map and the id is not 0.
+    /// @param id - an id that is used to check in the map.
+    /// @return true the given id is fresh and valid (non-zero).
+    /// @return false otherwise.
+    bool IdIsFreshAndValid(IdType id) const;
 
-  /// @brief Returns an id that is guaranteed to be unoccupied in this map.
-  ///
-  /// This will effectively increase the counter. This means that two
-  /// consecutive calls to this method will return different ids.
-  ///
-  /// @return an unoccupied id.
-  IdType TakeFreshId();
+    /// @brief Returns an id that is guaranteed to be unoccupied in this map.
+    ///
+    /// This will effectively increase the counter. This means that two
+    /// consecutive calls to this method will return different ids.
+    ///
+    /// @return an unoccupied id.
+    IdType TakeFreshId();
 
- private:
-  IdType fresh_id_ = 1;
+  private:
+    IdType fresh_id_ = 1;
 
-  std::unordered_map<const ast::Node*, IdType> node_to_id_;
-  std::unordered_map<IdType, const ast::Node*> id_to_node_;
+    std::unordered_map<const ast::Node*, IdType> node_to_id_;
+    std::unordered_map<IdType, const ast::Node*> id_to_node_;
 };
 
 }  // namespace tint::fuzzers::ast_fuzzer
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/probability_context.cc b/src/tint/fuzzers/tint_ast_fuzzer/probability_context.cc
index 596e056..639bd60 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/probability_context.cc
+++ b/src/tint/fuzzers/tint_ast_fuzzer/probability_context.cc
@@ -20,6 +20,7 @@
 namespace {
 
 const std::pair<uint32_t, uint32_t> kChanceOfChangingBinaryOperators = {30, 90};
+const std::pair<uint32_t, uint32_t> kChanceOfChangingUnaryOperators = {30, 70};
 const std::pair<uint32_t, uint32_t> kChanceOfReplacingIdentifiers = {30, 70};
 const std::pair<uint32_t, uint32_t> kChanceOfWrappingUnaryOperators = {30, 70};
 
@@ -27,20 +28,17 @@
 
 ProbabilityContext::ProbabilityContext(RandomGenerator* generator)
     : generator_(generator),
-      chance_of_changing_binary_operators_(
-          RandomFromRange(kChanceOfChangingBinaryOperators)),
-      chance_of_replacing_identifiers_(
-          RandomFromRange(kChanceOfReplacingIdentifiers)),
-      chance_of_wrapping_unary_operators_(
-          RandomFromRange(kChanceOfWrappingUnaryOperators)) {
-  assert(generator != nullptr && "generator must not be nullptr");
+      chance_of_changing_binary_operators_(RandomFromRange(kChanceOfChangingBinaryOperators)),
+      chance_of_changing_unary_operators_(RandomFromRange(kChanceOfChangingUnaryOperators)),
+      chance_of_replacing_identifiers_(RandomFromRange(kChanceOfReplacingIdentifiers)),
+      chance_of_wrapping_unary_operators_(RandomFromRange(kChanceOfWrappingUnaryOperators)) {
+    assert(generator != nullptr && "generator must not be nullptr");
 }
 
-uint32_t ProbabilityContext::RandomFromRange(
-    std::pair<uint32_t, uint32_t> range) {
-  assert(range.first <= range.second && "Range must be non-decreasing");
-  return generator_->GetUInt32(
-      range.first, range.second + 1);  // + 1 need since range is inclusive.
+uint32_t ProbabilityContext::RandomFromRange(std::pair<uint32_t, uint32_t> range) {
+    assert(range.first <= range.second && "Range must be non-decreasing");
+    return generator_->GetUInt32(range.first,
+                                 range.second + 1);  // + 1 need since range is inclusive.
 }
 
 }  // namespace tint::fuzzers::ast_fuzzer
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/probability_context.h b/src/tint/fuzzers/tint_ast_fuzzer/probability_context.h
index 6d9a4ec..ce46738 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/probability_context.h
+++ b/src/tint/fuzzers/tint_ast_fuzzer/probability_context.h
@@ -25,59 +25,61 @@
 /// This class is intended to be used by the `MutationFinder`s to introduce some
 /// variance to the mutation process.
 class ProbabilityContext {
- public:
-  /// Initializes this instance with a random number generator.
-  /// @param generator - must not be a `nullptr`. Must remain in scope as long
-  /// as this
-  ///     instance exists.
-  explicit ProbabilityContext(RandomGenerator* generator);
+  public:
+    /// Initializes this instance with a random number generator.
+    /// @param generator - must not be a `nullptr`. Must remain in scope as long
+    /// as this
+    ///     instance exists.
+    explicit ProbabilityContext(RandomGenerator* generator);
 
-  /// Get random bool with even odds
-  /// @returns true 50% of the time and false %50 of time.
-  bool RandomBool() { return generator_->GetBool(); }
+    /// Get random bool with even odds
+    /// @returns true 50% of the time and false %50 of time.
+    bool RandomBool() { return generator_->GetBool(); }
 
-  /// Get random bool with weighted odds
-  /// @param percentage - likelihood of true being returned
-  /// @returns true |percentage|% of the time, and false (100 - |percentage|)%
-  /// of the time.
-  bool ChoosePercentage(uint32_t percentage) {
-    return generator_->GetWeightedBool(percentage);
-  }
+    /// Get random bool with weighted odds
+    /// @param percentage - likelihood of true being returned
+    /// @returns true |percentage|% of the time, and false (100 - |percentage|)%
+    /// of the time.
+    bool ChoosePercentage(uint32_t percentage) { return generator_->GetWeightedBool(percentage); }
 
-  /// Returns a random value in the range `[0; arr.size())`.
-  /// @tparam T - type of the elements in the vector.
-  /// @param arr - may not be empty.
-  /// @return the random index in the `arr`.
-  template <typename T>
-  size_t GetRandomIndex(const std::vector<T>& arr) {
-    return static_cast<size_t>(generator_->GetUInt64(arr.size()));
-  }
+    /// Returns a random value in the range `[0; arr.size())`.
+    /// @tparam T - type of the elements in the vector.
+    /// @param arr - may not be empty.
+    /// @return the random index in the `arr`.
+    template <typename T>
+    size_t GetRandomIndex(const std::vector<T>& arr) {
+        return static_cast<size_t>(generator_->GetUInt64(arr.size()));
+    }
 
-  /// @return the probability of replacing some binary operator with another.
-  uint32_t GetChanceOfChangingBinaryOperators() const {
-    return chance_of_changing_binary_operators_;
-  }
+    /// @return the probability of replacing some binary operator with another.
+    uint32_t GetChanceOfChangingBinaryOperators() const {
+        return chance_of_changing_binary_operators_;
+    }
 
-  /// @return the probability of replacing some identifier with some other one.
-  uint32_t GetChanceOfReplacingIdentifiers() const {
-    return chance_of_replacing_identifiers_;
-  }
+    /// @return the probability of changing operator for an unary expression.
+    uint32_t GetChanceOfChangingUnaryOperators() const {
+        return chance_of_changing_unary_operators_;
+    }
 
-  /// @return the probability of wrapping an expression in a unary operator.
-  uint32_t GetChanceOfWrappingUnaryOperators() const {
-    return chance_of_wrapping_unary_operators_;
-  }
+    /// @return the probability of replacing some identifier with some other one.
+    uint32_t GetChanceOfReplacingIdentifiers() const { return chance_of_replacing_identifiers_; }
 
- private:
-  /// @param range - a pair of integers `a` and `b` s.t. `a <= b`.
-  /// @return an random number in the range `[a; b]`.
-  uint32_t RandomFromRange(std::pair<uint32_t, uint32_t> range);
+    /// @return the probability of wrapping an expression in a unary operator.
+    uint32_t GetChanceOfWrappingUnaryOperators() const {
+        return chance_of_wrapping_unary_operators_;
+    }
 
-  RandomGenerator* generator_;
+  private:
+    /// @param range - a pair of integers `a` and `b` s.t. `a <= b`.
+    /// @return an random number in the range `[a; b]`.
+    uint32_t RandomFromRange(std::pair<uint32_t, uint32_t> range);
 
-  uint32_t chance_of_changing_binary_operators_;
-  uint32_t chance_of_replacing_identifiers_;
-  uint32_t chance_of_wrapping_unary_operators_;
+    RandomGenerator* generator_;
+
+    uint32_t chance_of_changing_binary_operators_;
+    uint32_t chance_of_changing_unary_operators_;
+    uint32_t chance_of_replacing_identifiers_;
+    uint32_t chance_of_wrapping_unary_operators_;
 };
 
 }  // namespace tint::fuzzers::ast_fuzzer
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/protobufs/tint_ast_fuzzer.proto b/src/tint/fuzzers/tint_ast_fuzzer/protobufs/tint_ast_fuzzer.proto
index 0a5951f..fd3cd81 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/protobufs/tint_ast_fuzzer.proto
+++ b/src/tint/fuzzers/tint_ast_fuzzer/protobufs/tint_ast_fuzzer.proto
@@ -21,6 +21,7 @@
     MutationReplaceIdentifier replace_identifier = 1;
     MutationChangeBinaryOperator change_binary_operator = 2;
     MutationWrapUnaryOperator wrap_unary_operator = 3;
+    MutationChangeUnaryOperator change_unary_operator = 4;
   };
 }
 
@@ -41,15 +42,7 @@
   MutationSequence mutation_sequence = 2;
 }
 
-message MutationReplaceIdentifier {
-  // This transformation replaces a use of one variable with another.
-
-  // The id of the use of a variable in the AST.
-  uint32 use_id = 1;
-
-  // The id of a definition of a variable to replace the use with.
-  uint32 replacement_id = 2;
-}
+// Keep mutation messages in alphabetical order.
 
 message MutationChangeBinaryOperator {
   // This transformation replaces one binary operator with another.
@@ -61,6 +54,26 @@
   uint32 new_operator = 2;
 }
 
+message MutationChangeUnaryOperator {
+    // This transformation replaces one unary operator with another.
+
+    // The id of a unary expression in the AST.
+    uint32 unary_expr_id = 1;
+
+    // A UnaryOp representing the new unary operator.
+    uint32 new_operator = 2;
+}
+
+message MutationReplaceIdentifier {
+    // This transformation replaces a use of one variable with another.
+
+    // The id of the use of a variable in the AST.
+    uint32 use_id = 1;
+
+    // The id of a definition of a variable to replace the use with.
+    uint32 replacement_id = 2;
+}
+
 message MutationWrapUnaryOperator {
   // This transformation wraps an expression with a allowed unary
   // expression operator.
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/tint_ast_fuzzer.cc b/src/tint/fuzzers/tint_ast_fuzzer/tint_ast_fuzzer.cc
index 939fb4e..938a20c 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/tint_ast_fuzzer.cc
+++ b/src/tint/fuzzers/tint_ast_fuzzer/tint_ast_fuzzer.cc
@@ -18,7 +18,7 @@
 namespace tint::fuzzers::ast_fuzzer {
 
 void OverrideCliParams(CliParams& /*unused*/) {
-  // Leave the CLI parameters unchanged.
+    // Leave the CLI parameters unchanged.
 }
 
 }  // namespace tint::fuzzers::ast_fuzzer
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/tint_ast_hlsl_writer_fuzzer.cc b/src/tint/fuzzers/tint_ast_fuzzer/tint_ast_hlsl_writer_fuzzer.cc
index 1123cf0..bc10a43 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/tint_ast_hlsl_writer_fuzzer.cc
+++ b/src/tint/fuzzers/tint_ast_fuzzer/tint_ast_hlsl_writer_fuzzer.cc
@@ -20,10 +20,10 @@
 namespace tint::fuzzers::ast_fuzzer {
 
 void OverrideCliParams(CliParams& cli_params) {
-  assert(cli_params.fuzzing_target == FuzzingTarget::kAll &&
-         "The fuzzing target should not have been set by a CLI parameter: it "
-         "should have its default value.");
-  cli_params.fuzzing_target = FuzzingTarget::kHlsl;
+    assert(cli_params.fuzzing_target == FuzzingTarget::kAll &&
+           "The fuzzing target should not have been set by a CLI parameter: it "
+           "should have its default value.");
+    cli_params.fuzzing_target = FuzzingTarget::kHlsl;
 }
 
 }  // namespace tint::fuzzers::ast_fuzzer
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/tint_ast_msl_writer_fuzzer.cc b/src/tint/fuzzers/tint_ast_fuzzer/tint_ast_msl_writer_fuzzer.cc
index 2b97cd5..9124c87 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/tint_ast_msl_writer_fuzzer.cc
+++ b/src/tint/fuzzers/tint_ast_fuzzer/tint_ast_msl_writer_fuzzer.cc
@@ -20,10 +20,10 @@
 namespace tint::fuzzers::ast_fuzzer {
 
 void OverrideCliParams(CliParams& cli_params) {
-  assert(cli_params.fuzzing_target == FuzzingTarget::kAll &&
-         "The fuzzing target should not have been set by a CLI parameter: it "
-         "should have its default value.");
-  cli_params.fuzzing_target = FuzzingTarget::kMsl;
+    assert(cli_params.fuzzing_target == FuzzingTarget::kAll &&
+           "The fuzzing target should not have been set by a CLI parameter: it "
+           "should have its default value.");
+    cli_params.fuzzing_target = FuzzingTarget::kMsl;
 }
 
 }  // namespace tint::fuzzers::ast_fuzzer
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/tint_ast_spv_writer_fuzzer.cc b/src/tint/fuzzers/tint_ast_fuzzer/tint_ast_spv_writer_fuzzer.cc
index e776b6c..b556051 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/tint_ast_spv_writer_fuzzer.cc
+++ b/src/tint/fuzzers/tint_ast_fuzzer/tint_ast_spv_writer_fuzzer.cc
@@ -20,10 +20,10 @@
 namespace tint::fuzzers::ast_fuzzer {
 
 void OverrideCliParams(CliParams& cli_params) {
-  assert(cli_params.fuzzing_target == FuzzingTarget::kAll &&
-         "The fuzzing target should not have been set by a CLI parameter: it "
-         "should have its default value.");
-  cli_params.fuzzing_target = FuzzingTarget::kSpv;
+    assert(cli_params.fuzzing_target == FuzzingTarget::kAll &&
+           "The fuzzing target should not have been set by a CLI parameter: it "
+           "should have its default value.");
+    cli_params.fuzzing_target = FuzzingTarget::kSpv;
 }
 
 }  // namespace tint::fuzzers::ast_fuzzer
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/tint_ast_wgsl_writer_fuzzer.cc b/src/tint/fuzzers/tint_ast_fuzzer/tint_ast_wgsl_writer_fuzzer.cc
index 9d0a899..9377c6d 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/tint_ast_wgsl_writer_fuzzer.cc
+++ b/src/tint/fuzzers/tint_ast_fuzzer/tint_ast_wgsl_writer_fuzzer.cc
@@ -20,10 +20,10 @@
 namespace tint::fuzzers::ast_fuzzer {
 
 void OverrideCliParams(CliParams& cli_params) {
-  assert(cli_params.fuzzing_target == FuzzingTarget::kAll &&
-         "The fuzzing target should not have been set by a CLI parameter: it "
-         "should have its default value.");
-  cli_params.fuzzing_target = FuzzingTarget::kWgsl;
+    assert(cli_params.fuzzing_target == FuzzingTarget::kAll &&
+           "The fuzzing target should not have been set by a CLI parameter: it "
+           "should have its default value.");
+    cli_params.fuzzing_target = FuzzingTarget::kWgsl;
 }
 
 }  // namespace tint::fuzzers::ast_fuzzer
diff --git a/src/tint/fuzzers/tint_ast_fuzzer/util.h b/src/tint/fuzzers/tint_ast_fuzzer/util.h
index c2482a3..fe114f4 100644
--- a/src/tint/fuzzers/tint_ast_fuzzer/util.h
+++ b/src/tint/fuzzers/tint_ast_fuzzer/util.h
@@ -43,59 +43,58 @@
 ///     type `Pred`.
 /// @return a vector of all variables that can be accessed from `curr_stmt`.
 template <typename Pred>
-std::vector<const sem::Variable*> GetAllVarsInScope(
-    const tint::Program& program,
-    const sem::Statement* curr_stmt,
-    Pred&& pred) {
-  std::vector<const sem::Variable*> result;
+std::vector<const sem::Variable*> GetAllVarsInScope(const tint::Program& program,
+                                                    const sem::Statement* curr_stmt,
+                                                    Pred&& pred) {
+    std::vector<const sem::Variable*> result;
 
-  // Walk up the hierarchy of blocks in which `curr_stmt` is contained.
-  for (const auto* block = curr_stmt->Block(); block;
-       block = tint::As<sem::BlockStatement>(block->Parent())) {
-    for (const auto* stmt : block->Declaration()->statements) {
-      if (stmt == curr_stmt->Declaration()) {
-        // `curr_stmt` was found. This is only possible if `block is the
-        // enclosing block of `curr_stmt` since the AST nodes are not shared.
-        // Because of all this, skip the iteration of the inner loop since
-        // the rest of the instructions in the `block` are not visible from the
-        // `curr_stmt`.
-        break;
-      }
+    // Walk up the hierarchy of blocks in which `curr_stmt` is contained.
+    for (const auto* block = curr_stmt->Block(); block;
+         block = tint::As<sem::BlockStatement>(block->Parent())) {
+        for (const auto* stmt : block->Declaration()->statements) {
+            if (stmt == curr_stmt->Declaration()) {
+                // `curr_stmt` was found. This is only possible if `block is the
+                // enclosing block of `curr_stmt` since the AST nodes are not shared.
+                // Because of all this, skip the iteration of the inner loop since
+                // the rest of the instructions in the `block` are not visible from the
+                // `curr_stmt`.
+                break;
+            }
 
-      if (const auto* var_node = tint::As<ast::VariableDeclStatement>(stmt)) {
-        const auto* sem_var = program.Sem().Get(var_node->variable);
-        if (pred(sem_var)) {
-          result.push_back(sem_var);
+            if (const auto* var_node = tint::As<ast::VariableDeclStatement>(stmt)) {
+                const auto* sem_var = program.Sem().Get(var_node->variable);
+                if (pred(sem_var)) {
+                    result.push_back(sem_var);
+                }
+            }
         }
-      }
-    }
-  }
-
-  // Process function parameters.
-  for (const auto* param : curr_stmt->Function()->Parameters()) {
-    if (pred(param)) {
-      result.push_back(param);
-    }
-  }
-
-  // Global variables do not belong to any ast::BlockStatement.
-  for (const auto* global_decl : program.AST().GlobalDeclarations()) {
-    if (global_decl == curr_stmt->Function()->Declaration()) {
-      // The same situation as in the previous loop. The current function has
-      // been reached. If there are any variables declared below, they won't be
-      // visible in this function. Thus, exit the loop.
-      break;
     }
 
-    if (const auto* global_var = tint::As<ast::Variable>(global_decl)) {
-      const auto* sem_node = program.Sem().Get(global_var);
-      if (pred(sem_node)) {
-        result.push_back(sem_node);
-      }
+    // Process function parameters.
+    for (const auto* param : curr_stmt->Function()->Parameters()) {
+        if (pred(param)) {
+            result.push_back(param);
+        }
     }
-  }
 
-  return result;
+    // Global variables do not belong to any ast::BlockStatement.
+    for (const auto* global_decl : program.AST().GlobalDeclarations()) {
+        if (global_decl == curr_stmt->Function()->Declaration()) {
+            // The same situation as in the previous loop. The current function has
+            // been reached. If there are any variables declared below, they won't be
+            // visible in this function. Thus, exit the loop.
+            break;
+        }
+
+        if (const auto* global_var = tint::As<ast::Variable>(global_decl)) {
+            const auto* sem_node = program.Sem().Get(global_var);
+            if (pred(sem_node)) {
+                result.push_back(sem_node);
+            }
+        }
+    }
+
+    return result;
 }
 
 }  // namespace tint::fuzzers::ast_fuzzer::util
diff --git a/src/tint/fuzzers/tint_binding_remapper_fuzzer.cc b/src/tint/fuzzers/tint_binding_remapper_fuzzer.cc
index 30f4c66..2e62194 100644
--- a/src/tint/fuzzers/tint_binding_remapper_fuzzer.cc
+++ b/src/tint/fuzzers/tint_binding_remapper_fuzzer.cc
@@ -19,15 +19,15 @@
 namespace tint::fuzzers {
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  TransformBuilder tb(data, size);
-  tb.AddTransform<transform::BindingRemapper>();
+    TransformBuilder tb(data, size);
+    tb.AddTransform<transform::BindingRemapper>();
 
-  fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kWGSL);
-  fuzzer.SetTransformManager(tb.manager(), tb.data_map());
-  fuzzer.SetDumpInput(GetCliParams().dump_input);
-  fuzzer.SetEnforceValidity(GetCliParams().enforce_validity);
+    fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kWGSL);
+    fuzzer.SetTransformManager(tb.manager(), tb.data_map());
+    fuzzer.SetDumpInput(GetCliParams().dump_input);
+    fuzzer.SetEnforceValidity(GetCliParams().enforce_validity);
 
-  return fuzzer.Run(data, size);
+    return fuzzer.Run(data, size);
 }
 
 }  // namespace tint::fuzzers
diff --git a/src/tint/fuzzers/tint_black_box_fuzz_target.cc b/src/tint/fuzzers/tint_black_box_fuzz_target.cc
index 426b58a..7a2f48b 100644
--- a/src/tint/fuzzers/tint_black_box_fuzz_target.cc
+++ b/src/tint/fuzzers/tint_black_box_fuzz_target.cc
@@ -25,11 +25,11 @@
 
 /// Controls the target language in which code will be generated.
 enum class TargetLanguage {
-  kHlsl,
-  kMsl,
-  kSpv,
-  kWgsl,
-  kTargetLanguageMax,
+    kHlsl,
+    kMsl,
+    kSpv,
+    kWgsl,
+    kTargetLanguageMax,
 };
 
 /// Copies the content from the file named `input_file` to `buffer`,
@@ -39,119 +39,118 @@
 /// @returns true if we successfully read the file.
 template <typename T>
 bool ReadFile(const std::string& input_file, std::vector<T>* buffer) {
-  if (!buffer) {
-    std::cerr << "The buffer pointer was null" << std::endl;
-    return false;
-  }
+    if (!buffer) {
+        std::cerr << "The buffer pointer was null" << std::endl;
+        return false;
+    }
 
-  FILE* file = nullptr;
+    FILE* file = nullptr;
 #if defined(_MSC_VER)
-  fopen_s(&file, input_file.c_str(), "rb");
+    fopen_s(&file, input_file.c_str(), "rb");
 #else
-  file = fopen(input_file.c_str(), "rb");
+    file = fopen(input_file.c_str(), "rb");
 #endif
-  if (!file) {
-    std::cerr << "Failed to open " << input_file << std::endl;
-    return false;
-  }
+    if (!file) {
+        std::cerr << "Failed to open " << input_file << std::endl;
+        return false;
+    }
 
-  fseek(file, 0, SEEK_END);
-  const auto file_size = static_cast<size_t>(ftell(file));
-  if (0 != (file_size % sizeof(T))) {
-    std::cerr << "File " << input_file
-              << " does not contain an integral number of objects: "
-              << file_size << " bytes in the file, require " << sizeof(T)
-              << " bytes per object" << std::endl;
+    fseek(file, 0, SEEK_END);
+    const auto file_size = static_cast<size_t>(ftell(file));
+    if (0 != (file_size % sizeof(T))) {
+        std::cerr << "File " << input_file
+                  << " does not contain an integral number of objects: " << file_size
+                  << " bytes in the file, require " << sizeof(T) << " bytes per object"
+                  << std::endl;
+        fclose(file);
+        return false;
+    }
+    fseek(file, 0, SEEK_SET);
+
+    buffer->clear();
+    buffer->resize(file_size / sizeof(T));
+
+    size_t bytes_read = fread(buffer->data(), 1, file_size, file);
     fclose(file);
-    return false;
-  }
-  fseek(file, 0, SEEK_SET);
+    if (bytes_read != file_size) {
+        std::cerr << "Failed to read " << input_file << std::endl;
+        return false;
+    }
 
-  buffer->clear();
-  buffer->resize(file_size / sizeof(T));
-
-  size_t bytes_read = fread(buffer->data(), 1, file_size, file);
-  fclose(file);
-  if (bytes_read != file_size) {
-    std::cerr << "Failed to read " << input_file << std::endl;
-    return false;
-  }
-
-  return true;
+    return true;
 }
 
 }  // namespace
 
 int main(int argc, const char** argv) {
-  if (argc < 2 || argc > 3) {
-    std::cerr << "Usage: " << argv[0] << " <input file> [hlsl|msl|spv|wgsl]"
-              << std::endl;
-    return 1;
-  }
+    if (argc < 2 || argc > 3) {
+        std::cerr << "Usage: " << argv[0] << " <input file> [hlsl|msl|spv|wgsl]" << std::endl;
+        return 1;
+    }
 
-  std::string input_filename(argv[1]);
+    std::string input_filename(argv[1]);
 
-  std::vector<uint8_t> data;
-  if (!ReadFile<uint8_t>(input_filename, &data)) {
-    return 1;
-  }
+    std::vector<uint8_t> data;
+    if (!ReadFile<uint8_t>(input_filename, &data)) {
+        return 1;
+    }
 
-  if (data.empty()) {
-    return 0;
-  }
+    if (data.empty()) {
+        return 0;
+    }
 
-  tint::fuzzers::DataBuilder builder(data.data(), data.size());
+    tint::fuzzers::DataBuilder builder(data.data(), data.size());
 
-  TargetLanguage target_language;
+    TargetLanguage target_language;
 
-  if (argc == 3) {
-    std::string target_language_string = argv[2];
-    if (target_language_string == "hlsl") {
-      target_language = TargetLanguage::kHlsl;
-    } else if (target_language_string == "msl") {
-      target_language = TargetLanguage::kMsl;
-    } else if (target_language_string == "spv") {
-      target_language = TargetLanguage::kSpv;
+    if (argc == 3) {
+        std::string target_language_string = argv[2];
+        if (target_language_string == "hlsl") {
+            target_language = TargetLanguage::kHlsl;
+        } else if (target_language_string == "msl") {
+            target_language = TargetLanguage::kMsl;
+        } else if (target_language_string == "spv") {
+            target_language = TargetLanguage::kSpv;
+        } else {
+            assert(target_language_string == "wgsl" && "Unknown target language.");
+            target_language = TargetLanguage::kWgsl;
+        }
     } else {
-      assert(target_language_string == "wgsl" && "Unknown target language.");
-      target_language = TargetLanguage::kWgsl;
+        target_language = builder.enum_class<TargetLanguage>(
+            static_cast<uint32_t>(TargetLanguage::kTargetLanguageMax));
     }
-  } else {
-    target_language = builder.enum_class<TargetLanguage>(
-        static_cast<uint32_t>(TargetLanguage::kTargetLanguageMax));
-  }
 
-  switch (target_language) {
-    case TargetLanguage::kHlsl: {
-      tint::fuzzers::CommonFuzzer fuzzer(tint::fuzzers::InputFormat::kWGSL,
-                                         tint::fuzzers::OutputFormat::kHLSL);
-      return fuzzer.Run(data.data(), data.size());
+    switch (target_language) {
+        case TargetLanguage::kHlsl: {
+            tint::fuzzers::CommonFuzzer fuzzer(tint::fuzzers::InputFormat::kWGSL,
+                                               tint::fuzzers::OutputFormat::kHLSL);
+            return fuzzer.Run(data.data(), data.size());
+        }
+        case TargetLanguage::kMsl: {
+            tint::writer::msl::Options options;
+            GenerateMslOptions(&builder, &options);
+            tint::fuzzers::CommonFuzzer fuzzer(tint::fuzzers::InputFormat::kWGSL,
+                                               tint::fuzzers::OutputFormat::kMSL);
+            fuzzer.SetOptionsMsl(options);
+            return fuzzer.Run(data.data(), data.size());
+        }
+        case TargetLanguage::kSpv: {
+            tint::writer::spirv::Options options;
+            GenerateSpirvOptions(&builder, &options);
+            tint::fuzzers::CommonFuzzer fuzzer(tint::fuzzers::InputFormat::kWGSL,
+                                               tint::fuzzers::OutputFormat::kSpv);
+            fuzzer.SetOptionsSpirv(options);
+            return fuzzer.Run(data.data(), data.size());
+        }
+        case TargetLanguage::kWgsl: {
+            tint::fuzzers::CommonFuzzer fuzzer(tint::fuzzers::InputFormat::kWGSL,
+                                               tint::fuzzers::OutputFormat::kWGSL);
+            return fuzzer.Run(data.data(), data.size());
+        }
+        default:
+            std::cerr << "Aborting due to unknown target language; fuzzer must be "
+                         "misconfigured."
+                      << std::endl;
+            abort();
     }
-    case TargetLanguage::kMsl: {
-      tint::writer::msl::Options options;
-      GenerateMslOptions(&builder, &options);
-      tint::fuzzers::CommonFuzzer fuzzer(tint::fuzzers::InputFormat::kWGSL,
-                                         tint::fuzzers::OutputFormat::kMSL);
-      fuzzer.SetOptionsMsl(options);
-      return fuzzer.Run(data.data(), data.size());
-    }
-    case TargetLanguage::kSpv: {
-      tint::writer::spirv::Options options;
-      GenerateSpirvOptions(&builder, &options);
-      tint::fuzzers::CommonFuzzer fuzzer(tint::fuzzers::InputFormat::kWGSL,
-                                         tint::fuzzers::OutputFormat::kSpv);
-      fuzzer.SetOptionsSpirv(options);
-      return fuzzer.Run(data.data(), data.size());
-    }
-    case TargetLanguage::kWgsl: {
-      tint::fuzzers::CommonFuzzer fuzzer(tint::fuzzers::InputFormat::kWGSL,
-                                         tint::fuzzers::OutputFormat::kWGSL);
-      return fuzzer.Run(data.data(), data.size());
-    }
-    default:
-      std::cerr << "Aborting due to unknown target language; fuzzer must be "
-                   "misconfigured."
-                << std::endl;
-      abort();
-  }
 }
diff --git a/src/tint/fuzzers/tint_common_fuzzer.cc b/src/tint/fuzzers/tint_common_fuzzer.cc
index a8bc4cd..bbea6fc 100644
--- a/src/tint/fuzzers/tint_common_fuzzer.cc
+++ b/src/tint/fuzzers/tint_common_fuzzer.cc
@@ -31,6 +31,7 @@
 #include "src/tint/diagnostic/formatter.h"
 #include "src/tint/program.h"
 #include "src/tint/utils/hash.h"
+#include "src/tint/writer/flatten_bindings.h"
 
 namespace tint::fuzzers {
 
@@ -40,81 +41,76 @@
 // to better de-duplication of bug reports, because ClusterFuzz only uses the
 // top few stack frames for de-duplication, and a FATAL_ERROR stack frame
 // provides no useful information.
-#define FATAL_ERROR(diags, msg_string)                        \
-  do {                                                        \
-    std::string msg = msg_string;                             \
-    auto printer = tint::diag::Printer::create(stderr, true); \
-    if (!msg.empty()) {                                       \
-      printer->write(msg + "\n", {diag::Color::kRed, true});  \
-    }                                                         \
-    tint::diag::Formatter().format(diags, printer.get());     \
-    __builtin_trap();                                         \
-  } while (false)
+#define FATAL_ERROR(diags, msg_string)                             \
+    do {                                                           \
+        std::string msg = msg_string;                              \
+        auto printer = tint::diag::Printer::create(stderr, true);  \
+        if (!msg.empty()) {                                        \
+            printer->write(msg + "\n", {diag::Color::kRed, true}); \
+        }                                                          \
+        tint::diag::Formatter().format(diags, printer.get());      \
+        __builtin_trap();                                          \
+    } while (false)
 
-[[noreturn]] void TintInternalCompilerErrorReporter(
-    const tint::diag::List& diagnostics) {
-  FATAL_ERROR(diagnostics, "");
+[[noreturn]] void TintInternalCompilerErrorReporter(const tint::diag::List& diagnostics) {
+    FATAL_ERROR(diagnostics, "");
 }
 
 // Wrapping in a macro, so it can be a one-liner in the code, but not
 // introduce another level in the stack trace. This will help with de-duping
 // ClusterFuzz issues.
-#define CHECK_INSPECTOR(program, inspector)                    \
-  do {                                                         \
-    if ((inspector).has_error()) {                             \
-      if (!enforce_validity) {                                 \
-        return;                                                \
-      }                                                        \
-      FATAL_ERROR((program)->Diagnostics(),                    \
-                  "Inspector failed: " + (inspector).error()); \
-    }                                                          \
-  } while (false)
+#define CHECK_INSPECTOR(program, inspector)                                                    \
+    do {                                                                                       \
+        if ((inspector).has_error()) {                                                         \
+            if (!enforce_validity) {                                                           \
+                return;                                                                        \
+            }                                                                                  \
+            FATAL_ERROR((program)->Diagnostics(), "Inspector failed: " + (inspector).error()); \
+        }                                                                                      \
+    } while (false)
 
 // Wrapping in a macro to make code more readable and help with issue de-duping.
 #define VALIDITY_ERROR(diags, msg_string) \
-  do {                                    \
-    if (!enforce_validity) {              \
-      return 0;                           \
-    }                                     \
-    FATAL_ERROR(diags, msg_string);       \
-  } while (false)
+    do {                                  \
+        if (!enforce_validity) {          \
+            return 0;                     \
+        }                                 \
+        FATAL_ERROR(diags, msg_string);   \
+    } while (false)
 
-bool SPIRVToolsValidationCheck(const tint::Program& program,
-                               const std::vector<uint32_t>& spirv) {
-  spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_1);
-  const tint::diag::List& diags = program.Diagnostics();
-  tools.SetMessageConsumer([diags](spv_message_level_t, const char*,
-                                   const spv_position_t& pos, const char* msg) {
-    std::stringstream out;
-    out << "Unexpected spirv-val error:\n"
-        << (pos.line + 1) << ":" << (pos.column + 1) << ": " << msg
-        << std::endl;
+bool SPIRVToolsValidationCheck(const tint::Program& program, const std::vector<uint32_t>& spirv) {
+    spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_1);
+    const tint::diag::List& diags = program.Diagnostics();
+    tools.SetMessageConsumer(
+        [diags](spv_message_level_t, const char*, const spv_position_t& pos, const char* msg) {
+            std::stringstream out;
+            out << "Unexpected spirv-val error:\n"
+                << (pos.line + 1) << ":" << (pos.column + 1) << ": " << msg << std::endl;
 
-    auto printer = tint::diag::Printer::create(stderr, true);
-    printer->write(out.str(), {diag::Color::kYellow, false});
-    tint::diag::Formatter().format(diags, printer.get());
-  });
+            auto printer = tint::diag::Printer::create(stderr, true);
+            printer->write(out.str(), {diag::Color::kYellow, false});
+            tint::diag::Formatter().format(diags, printer.get());
+        });
 
-  return tools.Validate(spirv.data(), spirv.size(),
-                        spvtools::ValidatorOptions());
+    return tools.Validate(spirv.data(), spirv.size(), spvtools::ValidatorOptions());
 }
 
 }  // namespace
 
 void GenerateSpirvOptions(DataBuilder* b, writer::spirv::Options* options) {
-  *options = b->build<writer::spirv::Options>();
+    *options = b->build<writer::spirv::Options>();
 }
 
 void GenerateWgslOptions(DataBuilder* b, writer::wgsl::Options* options) {
-  *options = b->build<writer::wgsl::Options>();
+    *options = b->build<writer::wgsl::Options>();
 }
 
 void GenerateHlslOptions(DataBuilder* b, writer::hlsl::Options* options) {
-  *options = b->build<writer::hlsl::Options>();
+    *options = b->build<writer::hlsl::Options>();
 }
 
 void GenerateMslOptions(DataBuilder* b, writer::msl::Options* options) {
-  *options = b->build<writer::msl::Options>();
+    *options = b->build<writer::msl::Options>();
 }
 
 CommonFuzzer::CommonFuzzer(InputFormat input, OutputFormat output)
@@ -123,226 +119,226 @@
 CommonFuzzer::~CommonFuzzer() = default;
 
 int CommonFuzzer::Run(const uint8_t* data, size_t size) {
-  tint::SetInternalCompilerErrorReporter(&TintInternalCompilerErrorReporter);
+    tint::SetInternalCompilerErrorReporter(&TintInternalCompilerErrorReporter);
 
 #if TINT_BUILD_WGSL_WRITER
-  tint::Program::printer = [](const tint::Program* program) {
-    auto result = tint::writer::wgsl::Generate(program, {});
-    if (!result.error.empty()) {
-      return "error: " + result.error;
-    }
-    return result.wgsl;
-  };
+    tint::Program::printer = [](const tint::Program* program) {
+        auto result = tint::writer::wgsl::Generate(program, {});
+        if (!result.error.empty()) {
+            return "error: " + result.error;
+        }
+        return result.wgsl;
+    };
 #endif  // TINT_BUILD_WGSL_WRITER
 
-  Program program;
+    Program program;
 
 #if TINT_BUILD_SPV_READER
-  std::vector<uint32_t> spirv_input(size / sizeof(uint32_t));
+    std::vector<uint32_t> spirv_input(size / sizeof(uint32_t));
 
 #endif  // TINT_BUILD_SPV_READER
 
 #if TINT_BUILD_WGSL_READER || TINT_BUILD_SPV_READER
-  auto dump_input_data = [&](auto& content, const char* extension) {
-    size_t hash = utils::Hash(content);
-    auto filename = "fuzzer_input_" + std::to_string(hash) + extension;  //
-    std::ofstream fout(filename, std::ios::binary);
-    fout.write(reinterpret_cast<const char*>(data),
-               static_cast<std::streamsize>(size));
-    std::cout << "Dumped input data to " << filename << std::endl;
-  };
+    auto dump_input_data = [&](auto& content, const char* extension) {
+        size_t hash = utils::Hash(content);
+        auto filename = "fuzzer_input_" + std::to_string(hash) + extension;  //
+        std::ofstream fout(filename, std::ios::binary);
+        fout.write(reinterpret_cast<const char*>(data), static_cast<std::streamsize>(size));
+        std::cout << "Dumped input data to " << filename << std::endl;
+    };
 #endif
 
-  switch (input_) {
+    switch (input_) {
 #if TINT_BUILD_WGSL_READER
-    case InputFormat::kWGSL: {
-      // Clear any existing diagnostics, as these will hold pointers to file_,
-      // which we are about to release.
-      diagnostics_ = {};
-      std::string str(reinterpret_cast<const char*>(data), size);
-      file_ = std::make_unique<Source::File>("test.wgsl", str);
-      if (dump_input_) {
-        dump_input_data(str, ".wgsl");
-      }
-      program = reader::wgsl::Parse(file_.get());
-      break;
-    }
+        case InputFormat::kWGSL: {
+            // Clear any existing diagnostics, as these will hold pointers to file_,
+            // which we are about to release.
+            diagnostics_ = {};
+            std::string str(reinterpret_cast<const char*>(data), size);
+            file_ = std::make_unique<Source::File>("test.wgsl", str);
+            if (dump_input_) {
+                dump_input_data(str, ".wgsl");
+            }
+            program = reader::wgsl::Parse(file_.get());
+            break;
+        }
 #endif  // TINT_BUILD_WGSL_READER
 #if TINT_BUILD_SPV_READER
-    case InputFormat::kSpv: {
-      // `spirv_input` has been initialized with the capacity to store `size /
-      // sizeof(uint32_t)` uint32_t values. If `size` is not a multiple of
-      // sizeof(uint32_t) then not all of `data` can be copied into
-      // `spirv_input`, and any trailing bytes are discarded.
-      std::memcpy(spirv_input.data(), data,
-                  spirv_input.size() * sizeof(uint32_t));
-      if (spirv_input.empty()) {
-        return 0;
-      }
-      if (dump_input_) {
-        dump_input_data(spirv_input, ".spv");
-      }
-      program = reader::spirv::Parse(spirv_input);
-      break;
-    }
+        case InputFormat::kSpv: {
+            // `spirv_input` has been initialized with the capacity to store `size /
+            // sizeof(uint32_t)` uint32_t values. If `size` is not a multiple of
+            // sizeof(uint32_t) then not all of `data` can be copied into
+            // `spirv_input`, and any trailing bytes are discarded.
+            std::memcpy(spirv_input.data(), data, spirv_input.size() * sizeof(uint32_t));
+            if (spirv_input.empty()) {
+                return 0;
+            }
+            if (dump_input_) {
+                dump_input_data(spirv_input, ".spv");
+            }
+            program = reader::spirv::Parse(spirv_input);
+            break;
+        }
 #endif  // TINT_BUILD_SPV_READER
-  }
+    }
 
-  if (!program.IsValid()) {
-    diagnostics_ = program.Diagnostics();
-    return 0;
-  }
+    if (!program.IsValid()) {
+        diagnostics_ = program.Diagnostics();
+        return 0;
+    }
 
 #if TINT_BUILD_SPV_READER
-  if (input_ == InputFormat::kSpv &&
-      !SPIRVToolsValidationCheck(program, spirv_input)) {
-    FATAL_ERROR(
-        program.Diagnostics(),
-        "Fuzzing detected invalid input spirv not being caught by Tint");
-  }
+    if (input_ == InputFormat::kSpv && !SPIRVToolsValidationCheck(program, spirv_input)) {
+        FATAL_ERROR(program.Diagnostics(),
+                    "Fuzzing detected invalid input spirv not being caught by Tint");
+    }
 #endif  // TINT_BUILD_SPV_READER
 
-  RunInspector(&program);
-  diagnostics_ = program.Diagnostics();
-
-  if (transform_manager_) {
-    auto out = transform_manager_->Run(&program, *transform_inputs_);
-    if (!out.program.IsValid()) {
-      // Transforms can produce error messages for bad input.
-      // Catch ICEs and errors from non transform systems.
-      for (const auto& diag : out.program.Diagnostics()) {
-        if (diag.severity > diag::Severity::Error ||
-            diag.system != diag::System::Transform) {
-          VALIDITY_ERROR(program.Diagnostics(),
-                         "Fuzzing detected valid input program being "
-                         "transformed into an invalid output program");
-        }
-      }
-    }
-
-    program = std::move(out.program);
     RunInspector(&program);
-  }
+    diagnostics_ = program.Diagnostics();
 
-  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);
-      }
-#endif  // TINT_BUILD_WGSL_WRITER
-      break;
+    if (transform_manager_) {
+        auto out = transform_manager_->Run(&program, *transform_inputs_);
+        if (!out.program.IsValid()) {
+            // Transforms can produce error messages for bad input.
+            // Catch ICEs and errors from non transform systems.
+            for (const auto& diag : out.program.Diagnostics()) {
+                if (diag.severity > diag::Severity::Error ||
+                    diag.system != diag::System::Transform) {
+                    VALIDITY_ERROR(program.Diagnostics(),
+                                   "Fuzzing detected valid input program being "
+                                   "transformed into an invalid output program");
+                }
+            }
+        }
+
+        program = std::move(out.program);
+        RunInspector(&program);
     }
-    case OutputFormat::kSpv: {
-#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(),
-                       "Fuzzing detected invalid spirv being emitted by Tint");
-      }
+    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);
+            }
+#endif  // TINT_BUILD_WGSL_WRITER
+            break;
+        }
+        case OutputFormat::kSpv: {
+#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(),
+                               "Fuzzing detected invalid spirv being emitted by Tint");
+            }
 
 #endif  // TINT_BUILD_SPV_WRITER
-      break;
-    }
-    case OutputFormat::kHLSL: {
+            break;
+        }
+        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);
-      }
+            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);
+            }
 #endif  // TINT_BUILD_HLSL_WRITER
-      break;
-    }
-    case OutputFormat::kMSL: {
+            break;
+        }
+        case OutputFormat::kMSL: {
 #if TINT_BUILD_MSL_WRITER
-      auto result = writer::msl::Generate(&program, options_msl_);
-      generated_msl_ = std::move(result.msl);
-      if (!result.success) {
-        VALIDITY_ERROR(
-            program.Diagnostics(),
-            "MSL writer errored on validated input:\n" + result.error);
-      }
-#endif  // TINT_BUILD_MSL_WRITER
-      break;
-    }
-  }
+            // Remap resource numbers to a flat namespace.
+            // TODO(crbug.com/tint/1501): Do this via Options::BindingMap.
+            auto input_program = &program;
+            auto flattened = tint::writer::FlattenBindings(&program);
+            if (flattened) {
+                input_program = &*flattened;
+            }
 
-  return 0;
+            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);
+            }
+#endif  // TINT_BUILD_MSL_WRITER
+            break;
+        }
+    }
+
+    return 0;
 }
 
 void CommonFuzzer::RunInspector(Program* program) {
-  inspector::Inspector inspector(program);
-  diagnostics_ = program->Diagnostics();
+    inspector::Inspector inspector(program);
+    diagnostics_ = program->Diagnostics();
 
-  auto entry_points = inspector.GetEntryPoints();
-  CHECK_INSPECTOR(program, inspector);
-
-  auto constant_ids = inspector.GetConstantIDs();
-  CHECK_INSPECTOR(program, inspector);
-
-  auto constant_name_to_id = inspector.GetConstantNameToIdMap();
-  CHECK_INSPECTOR(program, inspector);
-
-  for (auto& ep : entry_points) {
-    inspector.GetStorageSize(ep.name);
+    auto entry_points = inspector.GetEntryPoints();
     CHECK_INSPECTOR(program, inspector);
 
-    inspector.GetResourceBindings(ep.name);
+    auto constant_ids = inspector.GetConstantIDs();
     CHECK_INSPECTOR(program, inspector);
 
-    inspector.GetUniformBufferResourceBindings(ep.name);
+    auto constant_name_to_id = inspector.GetConstantNameToIdMap();
     CHECK_INSPECTOR(program, inspector);
 
-    inspector.GetStorageBufferResourceBindings(ep.name);
-    CHECK_INSPECTOR(program, inspector);
+    for (auto& ep : entry_points) {
+        inspector.GetStorageSize(ep.name);
+        CHECK_INSPECTOR(program, inspector);
 
-    inspector.GetReadOnlyStorageBufferResourceBindings(ep.name);
-    CHECK_INSPECTOR(program, inspector);
+        inspector.GetResourceBindings(ep.name);
+        CHECK_INSPECTOR(program, inspector);
 
-    inspector.GetSamplerResourceBindings(ep.name);
-    CHECK_INSPECTOR(program, inspector);
+        inspector.GetUniformBufferResourceBindings(ep.name);
+        CHECK_INSPECTOR(program, inspector);
 
-    inspector.GetComparisonSamplerResourceBindings(ep.name);
-    CHECK_INSPECTOR(program, inspector);
+        inspector.GetStorageBufferResourceBindings(ep.name);
+        CHECK_INSPECTOR(program, inspector);
 
-    inspector.GetSampledTextureResourceBindings(ep.name);
-    CHECK_INSPECTOR(program, inspector);
+        inspector.GetReadOnlyStorageBufferResourceBindings(ep.name);
+        CHECK_INSPECTOR(program, inspector);
 
-    inspector.GetMultisampledTextureResourceBindings(ep.name);
-    CHECK_INSPECTOR(program, inspector);
+        inspector.GetSamplerResourceBindings(ep.name);
+        CHECK_INSPECTOR(program, inspector);
 
-    inspector.GetWriteOnlyStorageTextureResourceBindings(ep.name);
-    CHECK_INSPECTOR(program, inspector);
+        inspector.GetComparisonSamplerResourceBindings(ep.name);
+        CHECK_INSPECTOR(program, inspector);
 
-    inspector.GetDepthTextureResourceBindings(ep.name);
-    CHECK_INSPECTOR(program, inspector);
+        inspector.GetSampledTextureResourceBindings(ep.name);
+        CHECK_INSPECTOR(program, inspector);
 
-    inspector.GetDepthMultisampledTextureResourceBindings(ep.name);
-    CHECK_INSPECTOR(program, inspector);
+        inspector.GetMultisampledTextureResourceBindings(ep.name);
+        CHECK_INSPECTOR(program, inspector);
 
-    inspector.GetExternalTextureResourceBindings(ep.name);
-    CHECK_INSPECTOR(program, inspector);
+        inspector.GetWriteOnlyStorageTextureResourceBindings(ep.name);
+        CHECK_INSPECTOR(program, inspector);
 
-    inspector.GetSamplerTextureUses(ep.name);
-    CHECK_INSPECTOR(program, inspector);
+        inspector.GetDepthTextureResourceBindings(ep.name);
+        CHECK_INSPECTOR(program, inspector);
 
-    inspector.GetWorkgroupStorageSize(ep.name);
-    CHECK_INSPECTOR(program, inspector);
-  }
+        inspector.GetDepthMultisampledTextureResourceBindings(ep.name);
+        CHECK_INSPECTOR(program, inspector);
+
+        inspector.GetExternalTextureResourceBindings(ep.name);
+        CHECK_INSPECTOR(program, inspector);
+
+        inspector.GetSamplerTextureUses(ep.name);
+        CHECK_INSPECTOR(program, inspector);
+
+        inspector.GetWorkgroupStorageSize(ep.name);
+        CHECK_INSPECTOR(program, inspector);
+    }
 }
 
 }  // namespace tint::fuzzers
diff --git a/src/tint/fuzzers/tint_common_fuzzer.h b/src/tint/fuzzers/tint_common_fuzzer.h
index 9ea7513..c1cb656 100644
--- a/src/tint/fuzzers/tint_common_fuzzer.h
+++ b/src/tint/fuzzers/tint_common_fuzzer.h
@@ -52,107 +52,97 @@
 /// Generic runner for reading and emitting shaders using Tint, used by most
 /// fuzzers to share common code.
 class CommonFuzzer {
- public:
-  /// Constructor
-  /// @param input shader language being read
-  /// @param output shader language being emitted
-  CommonFuzzer(InputFormat input, OutputFormat output);
+  public:
+    /// Constructor
+    /// @param input shader language being read
+    /// @param output shader language being emitted
+    CommonFuzzer(InputFormat input, OutputFormat output);
 
-  /// Destructor
-  ~CommonFuzzer();
+    /// Destructor
+    ~CommonFuzzer();
 
-  /// @param tm manager for transforms to run
-  /// @param inputs data for transforms to run
-  void SetTransformManager(transform::Manager* tm, transform::DataMap* inputs) {
-    assert((!tm || inputs) && "DataMap must be !nullptr if Manager !nullptr");
-    transform_manager_ = tm;
-    transform_inputs_ = inputs;
-  }
+    /// @param tm manager for transforms to run
+    /// @param inputs data for transforms to run
+    void SetTransformManager(transform::Manager* tm, transform::DataMap* inputs) {
+        assert((!tm || inputs) && "DataMap must be !nullptr if Manager !nullptr");
+        transform_manager_ = tm;
+        transform_inputs_ = inputs;
+    }
 
-  /// @param enabled if the input shader for run should be outputted to the log
-  void SetDumpInput(bool enabled) { dump_input_ = enabled; }
+    /// @param enabled if the input shader for run should be outputted to the log
+    void SetDumpInput(bool enabled) { dump_input_ = enabled; }
 
-  /// @param enabled if the shader being valid after parsing is being enforced.
-  /// If false, invalidation of the shader will cause an early exit, but not
-  /// throw an error.
-  /// If true invalidation will throw an error that is caught by libFuzzer and
-  /// will generate a crash report.
-  void SetEnforceValidity(bool enabled) { enforce_validity = enabled; }
+    /// @param enabled if the shader being valid after parsing is being enforced.
+    /// If false, invalidation of the shader will cause an early exit, but not
+    /// throw an error.
+    /// If true invalidation will throw an error that is caught by libFuzzer and
+    /// will generate a crash report.
+    void SetEnforceValidity(bool enabled) { enforce_validity = enabled; }
 
-  /// Convert given shader from input to output format.
-  /// Will also apply provided transforms and run the inspector over the result.
-  /// @param data buffer of data that will interpreted as a byte array or string
-  ///             depending on the shader input format.
-  /// @param size number of elements in buffer
-  /// @returns 0, this is what libFuzzer expects
-  int Run(const uint8_t* data, size_t size);
+    /// Convert given shader from input to output format.
+    /// Will also apply provided transforms and run the inspector over the result.
+    /// @param data buffer of data that will interpreted as a byte array or string
+    ///             depending on the shader input format.
+    /// @param size number of elements in buffer
+    /// @returns 0, this is what libFuzzer expects
+    int Run(const uint8_t* data, size_t size);
 
-  /// @returns diagnostic messages generated while Run() is executed.
-  const tint::diag::List& Diagnostics() const { return diagnostics_; }
+    /// @returns diagnostic messages generated while Run() is executed.
+    const tint::diag::List& Diagnostics() const { return diagnostics_; }
 
-  /// @returns if there are any errors in the diagnostic messages
-  bool HasErrors() const { return diagnostics_.contains_errors(); }
+    /// @returns if there are any errors in the diagnostic messages
+    bool HasErrors() const { return diagnostics_.contains_errors(); }
 
-  /// @returns generated SPIR-V binary, if SPIR-V was emitted.
-  const std::vector<uint32_t>& GetGeneratedSpirv() const {
-    return generated_spirv_;
-  }
+    /// @returns generated SPIR-V binary, if SPIR-V was emitted.
+    const std::vector<uint32_t>& GetGeneratedSpirv() const { return generated_spirv_; }
 
-  /// @returns generated WGSL string, if WGSL was emitted.
-  const std::string& GetGeneratedWgsl() const { return generated_wgsl_; }
+    /// @returns generated WGSL string, if WGSL was emitted.
+    const std::string& GetGeneratedWgsl() const { return generated_wgsl_; }
 
-  /// @returns generated HLSL string, if HLSL was emitted.
-  const std::string& GetGeneratedHlsl() const { return generated_hlsl_; }
+    /// @returns generated HLSL string, if HLSL was emitted.
+    const std::string& GetGeneratedHlsl() const { return generated_hlsl_; }
 
-  /// @returns generated MSL string, if HLSL was emitted.
-  const std::string& GetGeneratedMsl() const { return generated_msl_; }
+    /// @returns generated MSL string, if HLSL was emitted.
+    const std::string& GetGeneratedMsl() const { return generated_msl_; }
 
-  /// @param options SPIR-V emission options
-  void SetOptionsSpirv(const writer::spirv::Options& options) {
-    options_spirv_ = options;
-  }
+    /// @param options SPIR-V emission options
+    void SetOptionsSpirv(const writer::spirv::Options& options) { options_spirv_ = options; }
 
-  /// @param options WGSL emission options
-  void SetOptionsWgsl(const writer::wgsl::Options& options) {
-    options_wgsl_ = options;
-  }
+    /// @param options WGSL emission options
+    void SetOptionsWgsl(const writer::wgsl::Options& options) { options_wgsl_ = options; }
 
-  /// @param options HLSL emission options
-  void SetOptionsHlsl(const writer::hlsl::Options& options) {
-    options_hlsl_ = options;
-  }
+    /// @param options HLSL emission options
+    void SetOptionsHlsl(const writer::hlsl::Options& options) { options_hlsl_ = options; }
 
-  /// @param options MSL emission options
-  void SetOptionsMsl(const writer::msl::Options& options) {
-    options_msl_ = options;
-  }
+    /// @param options MSL emission options
+    void SetOptionsMsl(const writer::msl::Options& options) { options_msl_ = options; }
 
- private:
-  InputFormat input_;
-  OutputFormat output_;
-  transform::Manager* transform_manager_ = nullptr;
-  transform::DataMap* transform_inputs_ = nullptr;
-  bool dump_input_ = false;
-  tint::diag::List diagnostics_;
-  bool enforce_validity = false;
+  private:
+    InputFormat input_;
+    OutputFormat output_;
+    transform::Manager* transform_manager_ = nullptr;
+    transform::DataMap* transform_inputs_ = nullptr;
+    bool dump_input_ = false;
+    tint::diag::List diagnostics_;
+    bool enforce_validity = false;
 
-  std::vector<uint32_t> generated_spirv_;
-  std::string generated_wgsl_;
-  std::string generated_hlsl_;
-  std::string generated_msl_;
+    std::vector<uint32_t> generated_spirv_;
+    std::string generated_wgsl_;
+    std::string generated_hlsl_;
+    std::string generated_msl_;
 
-  writer::spirv::Options options_spirv_;
-  writer::wgsl::Options options_wgsl_;
-  writer::hlsl::Options options_hlsl_;
-  writer::msl::Options options_msl_;
+    writer::spirv::Options options_spirv_;
+    writer::wgsl::Options options_wgsl_;
+    writer::hlsl::Options options_hlsl_;
+    writer::msl::Options options_msl_;
 
 #if TINT_BUILD_WGSL_READER
-  /// The source file needs to live at least as long as #diagnostics_
-  std::unique_ptr<Source::File> file_;
+    /// The source file needs to live at least as long as #diagnostics_
+    std::unique_ptr<Source::File> file_;
 #endif  // TINT_BUILD_WGSL_READER
 
-  /// Runs a series of reflection operations to exercise the Inspector API.
-  void RunInspector(Program* program);
+    /// Runs a series of reflection operations to exercise the Inspector API.
+    void RunInspector(Program* program);
 };
 
 }  // namespace tint::fuzzers
diff --git a/src/tint/fuzzers/tint_first_index_offset_fuzzer.cc b/src/tint/fuzzers/tint_first_index_offset_fuzzer.cc
index b5e79d1..9721798 100644
--- a/src/tint/fuzzers/tint_first_index_offset_fuzzer.cc
+++ b/src/tint/fuzzers/tint_first_index_offset_fuzzer.cc
@@ -19,15 +19,15 @@
 namespace tint::fuzzers {
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  TransformBuilder tb(data, size);
-  tb.AddTransform<transform::FirstIndexOffset>();
+    TransformBuilder tb(data, size);
+    tb.AddTransform<transform::FirstIndexOffset>();
 
-  fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kWGSL);
-  fuzzer.SetTransformManager(tb.manager(), tb.data_map());
-  fuzzer.SetDumpInput(GetCliParams().dump_input);
-  fuzzer.SetEnforceValidity(GetCliParams().enforce_validity);
+    fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kWGSL);
+    fuzzer.SetTransformManager(tb.manager(), tb.data_map());
+    fuzzer.SetDumpInput(GetCliParams().dump_input);
+    fuzzer.SetEnforceValidity(GetCliParams().enforce_validity);
 
-  return fuzzer.Run(data, size);
+    return fuzzer.Run(data, size);
 }
 
 }  // namespace tint::fuzzers
diff --git a/src/tint/fuzzers/tint_reader_writer_fuzzer.h b/src/tint/fuzzers/tint_reader_writer_fuzzer.h
index 8da4cff..0104c9d 100644
--- a/src/tint/fuzzers/tint_reader_writer_fuzzer.h
+++ b/src/tint/fuzzers/tint_reader_writer_fuzzer.h
@@ -24,45 +24,44 @@
 
 /// Wrapper around the common fuzzing class for tint_*_reader_*_writter fuzzers
 class ReaderWriterFuzzer : public CommonFuzzer {
- public:
-  /// Constructor
-  /// Pass through to the CommonFuzzer constructor
-  /// @param input shader language being read
-  /// @param output shader language being emitted
-  ReaderWriterFuzzer(InputFormat input, OutputFormat output)
-      : CommonFuzzer(input, output) {}
+  public:
+    /// Constructor
+    /// Pass through to the CommonFuzzer constructor
+    /// @param input shader language being read
+    /// @param output shader language being emitted
+    ReaderWriterFuzzer(InputFormat input, OutputFormat output) : CommonFuzzer(input, output) {}
 
-  /// Destructor
-  ~ReaderWriterFuzzer() {}
+    /// Destructor
+    ~ReaderWriterFuzzer() {}
 
-  /// Pass through to the CommonFuzzer setter, but records if it has been
-  /// invoked.
-  /// @param tm manager for transforms to run
-  /// @param inputs data for transforms to run
-  void SetTransformManager(transform::Manager* tm, transform::DataMap* inputs) {
-    tm_set_ = true;
-    CommonFuzzer::SetTransformManager(tm, inputs);
-  }
-
-  /// Pass through to the CommonFuzzer implementation, but will setup a
-  /// robustness transform, if no other transforms have been set.
-  /// @param data buffer of data that will interpreted as a byte array or string
-  ///             depending on the shader input format.
-  /// @param size number of elements in buffer
-  /// @returns 0, this is what libFuzzer expects
-  int Run(const uint8_t* data, size_t size) {
-    if (!tm_set_) {
-      tb_ = std::make_unique<TransformBuilder>(data, size);
-      tb_->AddTransform<tint::transform::Robustness>();
-      SetTransformManager(tb_->manager(), tb_->data_map());
+    /// Pass through to the CommonFuzzer setter, but records if it has been
+    /// invoked.
+    /// @param tm manager for transforms to run
+    /// @param inputs data for transforms to run
+    void SetTransformManager(transform::Manager* tm, transform::DataMap* inputs) {
+        tm_set_ = true;
+        CommonFuzzer::SetTransformManager(tm, inputs);
     }
 
-    return CommonFuzzer::Run(data, size);
-  }
+    /// Pass through to the CommonFuzzer implementation, but will setup a
+    /// robustness transform, if no other transforms have been set.
+    /// @param data buffer of data that will interpreted as a byte array or string
+    ///             depending on the shader input format.
+    /// @param size number of elements in buffer
+    /// @returns 0, this is what libFuzzer expects
+    int Run(const uint8_t* data, size_t size) {
+        if (!tm_set_) {
+            tb_ = std::make_unique<TransformBuilder>(data, size);
+            tb_->AddTransform<tint::transform::Robustness>();
+            SetTransformManager(tb_->manager(), tb_->data_map());
+        }
 
- private:
-  bool tm_set_ = false;
-  std::unique_ptr<TransformBuilder> tb_;
+        return CommonFuzzer::Run(data, size);
+    }
+
+  private:
+    bool tm_set_ = false;
+    std::unique_ptr<TransformBuilder> tb_;
 };
 
 }  // namespace tint::fuzzers
diff --git a/src/tint/fuzzers/tint_regex_fuzzer/cli.cc b/src/tint/fuzzers/tint_regex_fuzzer/cli.cc
index 2aeaf71..8da3b65 100644
--- a/src/tint/fuzzers/tint_regex_fuzzer/cli.cc
+++ b/src/tint/fuzzers/tint_regex_fuzzer/cli.cc
@@ -42,81 +42,81 @@
 )";
 
 bool HasPrefix(const char* str, const char* prefix) {
-  return strncmp(str, prefix, strlen(prefix)) == 0;
+    return strncmp(str, prefix, strlen(prefix)) == 0;
 }
 
 [[noreturn]] void InvalidParam(const char* param) {
-  std::cout << "Invalid value for " << param << std::endl;
-  std::cout << kHelpMessage << std::endl;
-  exit(1);
+    std::cout << "Invalid value for " << param << std::endl;
+    std::cout << kHelpMessage << std::endl;
+    exit(1);
 }
 
 bool ParseFuzzingTarget(const char* value, FuzzingTarget* out) {
-  if (!strcmp(value, "wgsl")) {
-    *out = FuzzingTarget::kWgsl;
-  } else if (!strcmp(value, "spv")) {
-    *out = FuzzingTarget::kSpv;
-  } else if (!strcmp(value, "msl")) {
-    *out = FuzzingTarget::kMsl;
-  } else if (!strcmp(value, "hlsl")) {
-    *out = FuzzingTarget::kHlsl;
-  } else {
-    return false;
-  }
-  return true;
+    if (!strcmp(value, "wgsl")) {
+        *out = FuzzingTarget::kWgsl;
+    } else if (!strcmp(value, "spv")) {
+        *out = FuzzingTarget::kSpv;
+    } else if (!strcmp(value, "msl")) {
+        *out = FuzzingTarget::kMsl;
+    } else if (!strcmp(value, "hlsl")) {
+        *out = FuzzingTarget::kHlsl;
+    } else {
+        return false;
+    }
+    return true;
 }
 
 }  // namespace
 
 CliParams ParseCliParams(int* argc, char** argv) {
-  CliParams cli_params;
-  auto help = false;
+    CliParams cli_params;
+    auto help = false;
 
-  for (int i = *argc - 1; i > 0; --i) {
-    auto param = argv[i];
-    auto recognized_parameter = true;
+    for (int i = *argc - 1; i > 0; --i) {
+        auto param = argv[i];
+        auto recognized_parameter = true;
 
-    if (HasPrefix(param, "-tint_fuzzing_target=")) {
-      auto result = FuzzingTarget::kNone;
+        if (HasPrefix(param, "-tint_fuzzing_target=")) {
+            auto result = FuzzingTarget::kNone;
 
-      std::stringstream ss(param + sizeof("-tint_fuzzing_target=") - 1);
-      for (std::string value; std::getline(ss, value, ',');) {
-        auto tmp = FuzzingTarget::kNone;
-        if (!ParseFuzzingTarget(value.c_str(), &tmp)) {
-          InvalidParam(param);
+            std::stringstream ss(param + sizeof("-tint_fuzzing_target=") - 1);
+            for (std::string value; std::getline(ss, value, ',');) {
+                auto tmp = FuzzingTarget::kNone;
+                if (!ParseFuzzingTarget(value.c_str(), &tmp)) {
+                    InvalidParam(param);
+                }
+                result = result | tmp;
+            }
+
+            if (result == FuzzingTarget::kNone) {
+                InvalidParam(param);
+            }
+
+            cli_params.fuzzing_target = result;
+        } else if (!strcmp(param, "-tint_help")) {
+            help = true;
+        } else {
+            recognized_parameter = false;
         }
-        result = result | tmp;
-      }
 
-      if (result == FuzzingTarget::kNone) {
-        InvalidParam(param);
-      }
-
-      cli_params.fuzzing_target = result;
-    } else if (!strcmp(param, "-tint_help")) {
-      help = true;
-    } else {
-      recognized_parameter = false;
+        if (recognized_parameter) {
+            // Remove the recognized parameter from the list of all parameters by
+            // swapping it with the last one. This will suppress warnings in the
+            // libFuzzer about unrecognized parameters. By default, libFuzzer thinks
+            // that all user-defined parameters start with two dashes. However, we are
+            // forced to use a single one to make the fuzzer compatible with the
+            // ClusterFuzz.
+            std::swap(argv[i], argv[*argc - 1]);
+            *argc -= 1;
+        }
     }
 
-    if (recognized_parameter) {
-      // Remove the recognized parameter from the list of all parameters by
-      // swapping it with the last one. This will suppress warnings in the
-      // libFuzzer about unrecognized parameters. By default, libFuzzer thinks
-      // that all user-defined parameters start with two dashes. However, we are
-      // forced to use a single one to make the fuzzer compatible with the
-      // ClusterFuzz.
-      std::swap(argv[i], argv[*argc - 1]);
-      *argc -= 1;
+    if (help) {
+        std::cout << kHelpMessage << std::endl;
+        exit(0);
     }
-  }
 
-  if (help) {
-    std::cout << kHelpMessage << std::endl;
-    exit(0);
-  }
-
-  return cli_params;
+    return cli_params;
 }
 
 }  // namespace tint::fuzzers::regex_fuzzer
diff --git a/src/tint/fuzzers/tint_regex_fuzzer/cli.h b/src/tint/fuzzers/tint_regex_fuzzer/cli.h
index 685f66d..0e28f59 100644
--- a/src/tint/fuzzers/tint_regex_fuzzer/cli.h
+++ b/src/tint/fuzzers/tint_regex_fuzzer/cli.h
@@ -21,27 +21,27 @@
 
 /// The backend this fuzzer will test.
 enum class FuzzingTarget {
-  kNone = 0,
-  kHlsl = 1 << 0,
-  kMsl = 1 << 1,
-  kSpv = 1 << 2,
-  kWgsl = 1 << 3,
-  kAll = kHlsl | kMsl | kSpv | kWgsl
+    kNone = 0,
+    kHlsl = 1 << 0,
+    kMsl = 1 << 1,
+    kSpv = 1 << 2,
+    kWgsl = 1 << 3,
+    kAll = kHlsl | kMsl | kSpv | kWgsl
 };
 
 inline FuzzingTarget operator|(FuzzingTarget a, FuzzingTarget b) {
-  return static_cast<FuzzingTarget>(static_cast<int>(a) | static_cast<int>(b));
+    return static_cast<FuzzingTarget>(static_cast<int>(a) | static_cast<int>(b));
 }
 
 inline FuzzingTarget operator&(FuzzingTarget a, FuzzingTarget b) {
-  return static_cast<FuzzingTarget>(static_cast<int>(a) & static_cast<int>(b));
+    return static_cast<FuzzingTarget>(static_cast<int>(a) & static_cast<int>(b));
 }
 
 /// CLI parameters accepted by the fuzzer. Type -tint_help in the CLI to see the
 /// help message
 struct CliParams {
-  /// Compiler backends we want to fuzz.
-  FuzzingTarget fuzzing_target = FuzzingTarget::kAll;
+    /// Compiler backends we want to fuzz.
+    FuzzingTarget fuzzing_target = FuzzingTarget::kAll;
 };
 
 /// @brief Parses CLI parameters.
diff --git a/src/tint/fuzzers/tint_regex_fuzzer/fuzzer.cc b/src/tint/fuzzers/tint_regex_fuzzer/fuzzer.cc
index c74c508..ac34684 100644
--- a/src/tint/fuzzers/tint_regex_fuzzer/fuzzer.cc
+++ b/src/tint/fuzzers/tint_regex_fuzzer/fuzzer.cc
@@ -31,121 +31,120 @@
 CliParams cli_params{};
 
 enum class MutationKind {
-  kSwapIntervals,
-  kDeleteInterval,
-  kDuplicateInterval,
-  kReplaceIdentifier,
-  kReplaceLiteral,
-  kInsertReturnStatement,
-  kNumMutationKinds
+    kSwapIntervals,
+    kDeleteInterval,
+    kDuplicateInterval,
+    kReplaceIdentifier,
+    kReplaceLiteral,
+    kInsertReturnStatement,
+    kNumMutationKinds
 };
 
 extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) {
-  // Parse CLI parameters. `ParseCliParams` will call `exit` if some parameter
-  // is invalid.
-  cli_params = ParseCliParams(argc, *argv);
-  // For some fuzz targets it is desirable to force the values of certain CLI
-  // parameters after parsing.
-  OverrideCliParams(cli_params);
-  return 0;
+    // Parse CLI parameters. `ParseCliParams` will call `exit` if some parameter
+    // is invalid.
+    cli_params = ParseCliParams(argc, *argv);
+    // For some fuzz targets it is desirable to force the values of certain CLI
+    // parameters after parsing.
+    OverrideCliParams(cli_params);
+    return 0;
 }
 
 extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data,
                                           size_t size,
                                           size_t max_size,
                                           unsigned seed) {
-  std::string wgsl_code(data, data + size);
-  const std::vector<std::string> delimiters{";"};
-  RandomGenerator generator(seed);
+    std::string wgsl_code(data, data + size);
+    const std::vector<std::string> delimiters{";"};
+    RandomGenerator generator(seed);
 
-  std::string delimiter =
-      delimiters[generator.GetUInt32(static_cast<uint32_t>(delimiters.size()))];
+    std::string delimiter =
+        delimiters[generator.GetUInt32(static_cast<uint32_t>(delimiters.size()))];
 
-  MutationKind mutation_kind = static_cast<MutationKind>(generator.GetUInt32(
-      static_cast<uint32_t>(MutationKind::kNumMutationKinds)));
+    MutationKind mutation_kind = static_cast<MutationKind>(
+        generator.GetUInt32(static_cast<uint32_t>(MutationKind::kNumMutationKinds)));
 
-  switch (mutation_kind) {
-    case MutationKind::kSwapIntervals:
-      if (!SwapRandomIntervals(delimiter, wgsl_code, generator)) {
+    switch (mutation_kind) {
+        case MutationKind::kSwapIntervals:
+            if (!SwapRandomIntervals(delimiter, wgsl_code, generator)) {
+                return 0;
+            }
+            break;
+
+        case MutationKind::kDeleteInterval:
+            if (!DeleteRandomInterval(delimiter, wgsl_code, generator)) {
+                return 0;
+            }
+            break;
+
+        case MutationKind::kDuplicateInterval:
+            if (!DuplicateRandomInterval(delimiter, wgsl_code, generator)) {
+                return 0;
+            }
+            break;
+
+        case MutationKind::kReplaceIdentifier:
+            if (!ReplaceRandomIdentifier(wgsl_code, generator)) {
+                return 0;
+            }
+            break;
+
+        case MutationKind::kReplaceLiteral:
+            if (!ReplaceRandomIntLiteral(wgsl_code, generator)) {
+                return 0;
+            }
+            break;
+
+        case MutationKind::kInsertReturnStatement:
+            if (!InsertReturnStatement(wgsl_code, generator)) {
+                return 0;
+            }
+            break;
+
+        default:
+            assert(false && "Unreachable");
+            return 0;
+    }
+
+    if (wgsl_code.size() > max_size) {
         return 0;
-      }
-      break;
+    }
 
-    case MutationKind::kDeleteInterval:
-      if (!DeleteRandomInterval(delimiter, wgsl_code, generator)) {
-        return 0;
-      }
-      break;
-
-    case MutationKind::kDuplicateInterval:
-      if (!DuplicateRandomInterval(delimiter, wgsl_code, generator)) {
-        return 0;
-      }
-      break;
-
-    case MutationKind::kReplaceIdentifier:
-      if (!ReplaceRandomIdentifier(wgsl_code, generator)) {
-        return 0;
-      }
-      break;
-
-    case MutationKind::kReplaceLiteral:
-      if (!ReplaceRandomIntLiteral(wgsl_code, generator)) {
-        return 0;
-      }
-      break;
-
-    case MutationKind::kInsertReturnStatement:
-      if (!InsertReturnStatement(wgsl_code, generator)) {
-        return 0;
-      }
-      break;
-
-    default:
-      assert(false && "Unreachable");
-      return 0;
-  }
-
-  if (wgsl_code.size() > max_size) {
-    return 0;
-  }
-
-  memcpy(data, wgsl_code.c_str(), wgsl_code.size());
-  return wgsl_code.size();
+    memcpy(data, wgsl_code.c_str(), wgsl_code.size());
+    return wgsl_code.size();
 }
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  if (size == 0) {
-    return 0;
-  }
-
-  struct Target {
-    FuzzingTarget fuzzing_target;
-    OutputFormat output_format;
-    const char* name;
-  };
-
-  Target targets[] = {{FuzzingTarget::kWgsl, OutputFormat::kWGSL, "WGSL"},
-                      {FuzzingTarget::kHlsl, OutputFormat::kHLSL, "HLSL"},
-                      {FuzzingTarget::kMsl, OutputFormat::kMSL, "MSL"},
-                      {FuzzingTarget::kSpv, OutputFormat::kSpv, "SPV"}};
-
-  for (auto target : targets) {
-    if ((target.fuzzing_target & cli_params.fuzzing_target) !=
-        target.fuzzing_target) {
-      continue;
+    if (size == 0) {
+        return 0;
     }
 
-    TransformBuilder tb(data, size);
-    tb.AddTransform<tint::transform::Robustness>();
+    struct Target {
+        FuzzingTarget fuzzing_target;
+        OutputFormat output_format;
+        const char* name;
+    };
 
-    CommonFuzzer fuzzer(InputFormat::kWGSL, target.output_format);
-    fuzzer.SetTransformManager(tb.manager(), tb.data_map());
+    Target targets[] = {{FuzzingTarget::kWgsl, OutputFormat::kWGSL, "WGSL"},
+                        {FuzzingTarget::kHlsl, OutputFormat::kHLSL, "HLSL"},
+                        {FuzzingTarget::kMsl, OutputFormat::kMSL, "MSL"},
+                        {FuzzingTarget::kSpv, OutputFormat::kSpv, "SPV"}};
 
-    fuzzer.Run(data, size);
-  }
+    for (auto target : targets) {
+        if ((target.fuzzing_target & cli_params.fuzzing_target) != target.fuzzing_target) {
+            continue;
+        }
 
-  return 0;
+        TransformBuilder tb(data, size);
+        tb.AddTransform<tint::transform::Robustness>();
+
+        CommonFuzzer fuzzer(InputFormat::kWGSL, target.output_format);
+        fuzzer.SetTransformManager(tb.manager(), tb.data_map());
+
+        fuzzer.Run(data, size);
+    }
+
+    return 0;
 }
 
 }  // namespace
diff --git a/src/tint/fuzzers/tint_regex_fuzzer/regex_fuzzer_tests.cc b/src/tint/fuzzers/tint_regex_fuzzer/regex_fuzzer_tests.cc
index 33d3c8d..b344a69 100644
--- a/src/tint/fuzzers/tint_regex_fuzzer/regex_fuzzer_tests.cc
+++ b/src/tint/fuzzers/tint_regex_fuzzer/regex_fuzzer_tests.cc
@@ -23,177 +23,153 @@
 
 // Swaps two non-consecutive regions in the edge
 TEST(SwapRegionsTest, SwapIntervalsEdgeNonConsecutive) {
-  std::string R1 = ";region1;", R2 = ";regionregion2;",
-              R3 = ";regionregionregion3;";
-  std::string all_regions = R1 + R2 + R3;
+    std::string R1 = ";region1;", R2 = ";regionregion2;", R3 = ";regionregionregion3;";
+    std::string all_regions = R1 + R2 + R3;
 
-  // this call should swap R1 with R3.
-  SwapIntervals(0, R1.length(), R1.length() + R2.length(), R3.length(),
-                all_regions);
+    // this call should swap R1 with R3.
+    SwapIntervals(0, R1.length(), R1.length() + R2.length(), R3.length(), all_regions);
 
-  ASSERT_EQ(R3 + R2 + R1, all_regions);
+    ASSERT_EQ(R3 + R2 + R1, all_regions);
 }
 
 // Swaps two non-consecutive regions not in the edge
 TEST(SwapRegionsTest, SwapIntervalsNonConsecutiveNonEdge) {
-  std::string R1 = ";region1;", R2 = ";regionregion2;",
-              R3 = ";regionregionregion3;", R4 = ";regionregionregionregion4;",
-              R5 = ";regionregionregionregionregion5;";
-  std::string all_regions = R1 + R2 + R3 + R4 + R5;
+    std::string R1 = ";region1;", R2 = ";regionregion2;", R3 = ";regionregionregion3;",
+                R4 = ";regionregionregionregion4;", R5 = ";regionregionregionregionregion5;";
+    std::string all_regions = R1 + R2 + R3 + R4 + R5;
 
-  // this call should swap R2 with R4.
-  SwapIntervals(R1.length(), R2.length(),
-                R1.length() + R2.length() + R3.length(), R4.length(),
-                all_regions);
+    // this call should swap R2 with R4.
+    SwapIntervals(R1.length(), R2.length(), R1.length() + R2.length() + R3.length(), R4.length(),
+                  all_regions);
 
-  ASSERT_EQ(R1 + R4 + R3 + R2 + R5, all_regions);
+    ASSERT_EQ(R1 + R4 + R3 + R2 + R5, all_regions);
 }
 
 // Swaps two consecutive regions not in the edge (sorrounded by other
 // regions)
 TEST(SwapRegionsTest, SwapIntervalsConsecutiveEdge) {
-  std::string R1 = ";region1;", R2 = ";regionregion2;",
-              R3 = ";regionregionregion3;", R4 = ";regionregionregionregion4;",
-              R5 = ";regionregionregionregionregion5;";
-  std::string all_regions = R1 + R2 + R3 + R4;
+    std::string R1 = ";region1;", R2 = ";regionregion2;", R3 = ";regionregionregion3;",
+                R4 = ";regionregionregionregion4;", R5 = ";regionregionregionregionregion5;";
+    std::string all_regions = R1 + R2 + R3 + R4;
 
-  // this call should swap R2 with R3.
-  SwapIntervals(R1.length(), R2.length(), R1.length() + R2.length(),
-                R3.length(), all_regions);
+    // this call should swap R2 with R3.
+    SwapIntervals(R1.length(), R2.length(), R1.length() + R2.length(), R3.length(), all_regions);
 
-  ASSERT_EQ(R1 + R3 + R2 + R4, all_regions);
+    ASSERT_EQ(R1 + R3 + R2 + R4, all_regions);
 }
 
 // Swaps two consecutive regions not in the edge (not sorrounded by other
 // regions)
 TEST(SwapRegionsTest, SwapIntervalsConsecutiveNonEdge) {
-  std::string R1 = ";region1;", R2 = ";regionregion2;",
-              R3 = ";regionregionregion3;", R4 = ";regionregionregionregion4;",
-              R5 = ";regionregionregionregionregion5;";
-  std::string all_regions = R1 + R2 + R3 + R4 + R5;
+    std::string R1 = ";region1;", R2 = ";regionregion2;", R3 = ";regionregionregion3;",
+                R4 = ";regionregionregionregion4;", R5 = ";regionregionregionregionregion5;";
+    std::string all_regions = R1 + R2 + R3 + R4 + R5;
 
-  // this call should swap R4 with R5.
-  SwapIntervals(R1.length() + R2.length() + R3.length(), R4.length(),
-                R1.length() + R2.length() + R3.length() + R4.length(),
-                R5.length(), all_regions);
+    // this call should swap R4 with R5.
+    SwapIntervals(R1.length() + R2.length() + R3.length(), R4.length(),
+                  R1.length() + R2.length() + R3.length() + R4.length(), R5.length(), all_regions);
 
-  ASSERT_EQ(R1 + R2 + R3 + R5 + R4, all_regions);
+    ASSERT_EQ(R1 + R2 + R3 + R5 + R4, all_regions);
 }
 
 // Deletes the first region.
 TEST(DeleteRegionTest, DeleteFirstRegion) {
-  std::string R1 = ";region1;", R2 = ";regionregion2;",
-              R3 = ";regionregionregion3;", R4 = ";regionregionregionregion4;",
-              R5 = ";regionregionregionregionregion5;";
-  std::string all_regions = R1 + R2 + R3 + R4 + R5;
+    std::string R1 = ";region1;", R2 = ";regionregion2;", R3 = ";regionregionregion3;",
+                R4 = ";regionregionregionregion4;", R5 = ";regionregionregionregionregion5;";
+    std::string all_regions = R1 + R2 + R3 + R4 + R5;
 
-  // This call should delete R1.
-  DeleteInterval(0, R1.length(), all_regions);
+    // This call should delete R1.
+    DeleteInterval(0, R1.length(), all_regions);
 
-  ASSERT_EQ(";" + R2 + R3 + R4 + R5, all_regions);
+    ASSERT_EQ(";" + R2 + R3 + R4 + R5, all_regions);
 }
 
 // Deletes the last region.
 TEST(DeleteRegionTest, DeleteLastRegion) {
-  std::string R1 = ";region1;", R2 = ";regionregion2;",
-              R3 = ";regionregionregion3;", R4 = ";regionregionregionregion4;",
-              R5 = ";regionregionregionregionregion5;";
-  std::string all_regions = R1 + R2 + R3 + R4 + R5;
+    std::string R1 = ";region1;", R2 = ";regionregion2;", R3 = ";regionregionregion3;",
+                R4 = ";regionregionregionregion4;", R5 = ";regionregionregionregionregion5;";
+    std::string all_regions = R1 + R2 + R3 + R4 + R5;
 
-  // This call should delete R5.
-  DeleteInterval(R1.length() + R2.length() + R3.length() + R4.length(),
-                 R5.length(), all_regions);
+    // This call should delete R5.
+    DeleteInterval(R1.length() + R2.length() + R3.length() + R4.length(), R5.length(), all_regions);
 
-  ASSERT_EQ(R1 + R2 + R3 + R4 + ";", all_regions);
+    ASSERT_EQ(R1 + R2 + R3 + R4 + ";", all_regions);
 }
 
 // Deletes the middle region.
 TEST(DeleteRegionTest, DeleteMiddleRegion) {
-  std::string R1 = ";region1;", R2 = ";regionregion2;",
-              R3 = ";regionregionregion3;", R4 = ";regionregionregionregion4;",
-              R5 = ";regionregionregionregionregion5;";
-  std::string all_regions = R1 + R2 + R3 + R4 + R5;
+    std::string R1 = ";region1;", R2 = ";regionregion2;", R3 = ";regionregionregion3;",
+                R4 = ";regionregionregionregion4;", R5 = ";regionregionregionregionregion5;";
+    std::string all_regions = R1 + R2 + R3 + R4 + R5;
 
-  // This call should delete R3.
-  DeleteInterval(R1.length() + R2.length(), R3.length(), all_regions);
+    // This call should delete R3.
+    DeleteInterval(R1.length() + R2.length(), R3.length(), all_regions);
 
-  ASSERT_EQ(R1 + R2 + ";" + R4 + R5, all_regions);
+    ASSERT_EQ(R1 + R2 + ";" + R4 + R5, all_regions);
 }
 
 TEST(InsertRegionTest, InsertRegionTest1) {
-  std::string R1 = ";region1;", R2 = ";regionregion2;",
-              R3 = ";regionregionregion3;", R4 = ";regionregionregionregion4;",
-              R5 = ";regionregionregionregionregion5;";
-  std::string all_regions = R1 + R2 + R3 + R4 + R5;
+    std::string R1 = ";region1;", R2 = ";regionregion2;", R3 = ";regionregionregion3;",
+                R4 = ";regionregionregionregion4;", R5 = ";regionregionregionregionregion5;";
+    std::string all_regions = R1 + R2 + R3 + R4 + R5;
 
-  // This call should insert R2 after R4.
-  DuplicateInterval(R1.length(), R2.length(),
-                    R1.length() + R2.length() + R3.length() + R4.length() - 1,
-                    all_regions);
+    // This call should insert R2 after R4.
+    DuplicateInterval(R1.length(), R2.length(),
+                      R1.length() + R2.length() + R3.length() + R4.length() - 1, all_regions);
 
-  ASSERT_EQ(R1 + R2 + R3 + R4 + R2.substr(1, R2.size() - 1) + R5, all_regions);
+    ASSERT_EQ(R1 + R2 + R3 + R4 + R2.substr(1, R2.size() - 1) + R5, all_regions);
 }
 
 TEST(InsertRegionTest, InsertRegionTest2) {
-  std::string R1 = ";region1;", R2 = ";regionregion2;",
-              R3 = ";regionregionregion3;", R4 = ";regionregionregionregion4;",
-              R5 = ";regionregionregionregionregion5;";
+    std::string R1 = ";region1;", R2 = ";regionregion2;", R3 = ";regionregionregion3;",
+                R4 = ";regionregionregionregion4;", R5 = ";regionregionregionregionregion5;";
 
-  std::string all_regions = R1 + R2 + R3 + R4 + R5;
+    std::string all_regions = R1 + R2 + R3 + R4 + R5;
 
-  // This call should insert R3 after R1.
-  DuplicateInterval(R1.length() + R2.length(), R3.length(), R1.length() - 1,
-                    all_regions);
+    // This call should insert R3 after R1.
+    DuplicateInterval(R1.length() + R2.length(), R3.length(), R1.length() - 1, all_regions);
 
-  ASSERT_EQ(R1 + R3.substr(1, R3.length() - 1) + R2 + R3 + R4 + R5,
-            all_regions);
+    ASSERT_EQ(R1 + R3.substr(1, R3.length() - 1) + R2 + R3 + R4 + R5, all_regions);
 }
 
 TEST(InsertRegionTest, InsertRegionTest3) {
-  std::string R1 = ";region1;", R2 = ";regionregion2;",
-              R3 = ";regionregionregion3;", R4 = ";regionregionregionregion4;",
-              R5 = ";regionregionregionregionregion5;";
+    std::string R1 = ";region1;", R2 = ";regionregion2;", R3 = ";regionregionregion3;",
+                R4 = ";regionregionregionregion4;", R5 = ";regionregionregionregionregion5;";
 
-  std::string all_regions = R1 + R2 + R3 + R4 + R5;
+    std::string all_regions = R1 + R2 + R3 + R4 + R5;
 
-  // This call should insert R2 after R5.
-  DuplicateInterval(R1.length(), R2.length(), all_regions.length() - 1,
-                    all_regions);
+    // This call should insert R2 after R5.
+    DuplicateInterval(R1.length(), R2.length(), all_regions.length() - 1, all_regions);
 
-  ASSERT_EQ(R1 + R2 + R3 + R4 + R5 + R2.substr(1, R2.length() - 1),
-            all_regions);
+    ASSERT_EQ(R1 + R2 + R3 + R4 + R5 + R2.substr(1, R2.length() - 1), all_regions);
 }
 
 TEST(ReplaceIdentifierTest, ReplaceIdentifierTest1) {
-  std::string R1 = "|region1|", R2 = "; region2;",
-              R3 = "---------region3---------", R4 = "++region4++",
-              R5 = "***region5***";
-  std::string all_regions = R1 + R2 + R3 + R4 + R5;
+    std::string R1 = "|region1|", R2 = "; region2;", R3 = "---------region3---------",
+                R4 = "++region4++", R5 = "***region5***";
+    std::string all_regions = R1 + R2 + R3 + R4 + R5;
 
-  // Replaces R3 with R1.
-  ReplaceRegion(0, R1.length(), R1.length() + R2.length(), R3.length(),
-                all_regions);
+    // Replaces R3 with R1.
+    ReplaceRegion(0, R1.length(), R1.length() + R2.length(), R3.length(), all_regions);
 
-  ASSERT_EQ(R1 + R2 + R1 + R4 + R5, all_regions);
+    ASSERT_EQ(R1 + R2 + R1 + R4 + R5, all_regions);
 }
 
 TEST(ReplaceIdentifierTest, ReplaceIdentifierTest2) {
-  std::string R1 = "|region1|", R2 = "; region2;",
-              R3 = "---------region3---------", R4 = "++region4++",
-              R5 = "***region5***";
-  std::string all_regions = R1 + R2 + R3 + R4 + R5;
+    std::string R1 = "|region1|", R2 = "; region2;", R3 = "---------region3---------",
+                R4 = "++region4++", R5 = "***region5***";
+    std::string all_regions = R1 + R2 + R3 + R4 + R5;
 
-  // Replaces R5 with R3.
-  ReplaceRegion(R1.length() + R2.length(), R3.length(),
-                R1.length() + R2.length() + R3.length() + R4.length(),
-                R5.length(), all_regions);
+    // Replaces R5 with R3.
+    ReplaceRegion(R1.length() + R2.length(), R3.length(),
+                  R1.length() + R2.length() + R3.length() + R4.length(), R5.length(), all_regions);
 
-  ASSERT_EQ(R1 + R2 + R3 + R4 + R3, all_regions);
+    ASSERT_EQ(R1 + R2 + R3 + R4 + R3, all_regions);
 }
 
 TEST(GetIdentifierTest, GetIdentifierTest1) {
-  std::string wgsl_code =
-      R"(fn clamp_0acf8f() {
+    std::string wgsl_code =
+        R"(fn clamp_0acf8f() {
         var res: vec2<f32> = clamp(vec2<f32>(), vec2<f32>(), vec2<f32>());
       }
       @stage(vertex)
@@ -211,26 +187,25 @@
         clamp_0acf8f();
       })";
 
-  std::vector<std::pair<size_t, size_t>> identifiers_pos =
-      GetIdentifiers(wgsl_code);
+    std::vector<std::pair<size_t, size_t>> identifiers_pos = GetIdentifiers(wgsl_code);
 
-  std::vector<std::pair<size_t, size_t>> ground_truth = {
-      std::make_pair(3, 12),   std::make_pair(28, 3),  std::make_pair(37, 4),
-      std::make_pair(49, 5),   std::make_pair(60, 3),  std::make_pair(68, 4),
-      std::make_pair(81, 4),   std::make_pair(110, 5), std::make_pair(130, 2),
-      std::make_pair(140, 4),  std::make_pair(151, 7), std::make_pair(169, 4),
-      std::make_pair(190, 12), std::make_pair(216, 6), std::make_pair(228, 3),
-      std::make_pair(251, 5),  std::make_pair(273, 2), std::make_pair(285, 4),
-      std::make_pair(302, 12), std::make_pair(333, 5), std::make_pair(349, 14),
-      std::make_pair(373, 2),  std::make_pair(384, 4), std::make_pair(402, 3),
-      std::make_pair(415, 3),  std::make_pair(420, 3), std::make_pair(439, 12)};
+    std::vector<std::pair<size_t, size_t>> ground_truth = {
+        std::make_pair(3, 12),   std::make_pair(28, 3),  std::make_pair(37, 4),
+        std::make_pair(49, 5),   std::make_pair(60, 3),  std::make_pair(68, 4),
+        std::make_pair(81, 4),   std::make_pair(110, 5), std::make_pair(130, 2),
+        std::make_pair(140, 4),  std::make_pair(151, 7), std::make_pair(169, 4),
+        std::make_pair(190, 12), std::make_pair(216, 6), std::make_pair(228, 3),
+        std::make_pair(251, 5),  std::make_pair(273, 2), std::make_pair(285, 4),
+        std::make_pair(302, 12), std::make_pair(333, 5), std::make_pair(349, 14),
+        std::make_pair(373, 2),  std::make_pair(384, 4), std::make_pair(402, 3),
+        std::make_pair(415, 3),  std::make_pair(420, 3), std::make_pair(439, 12)};
 
-  ASSERT_EQ(ground_truth, identifiers_pos);
+    ASSERT_EQ(ground_truth, identifiers_pos);
 }
 
 TEST(TestGetLiteralsValues, TestGetLiteralsValues1) {
-  std::string wgsl_code =
-      R"(fn clamp_0acf8f() {
+    std::string wgsl_code =
+        R"(fn clamp_0acf8f() {
         var res: vec2<f32> = clamp(vec2<f32>(), vec2<f32>(), vec2<f32>());
       }
       @stage(vertex)
@@ -252,23 +227,22 @@
       foo_1 = 5 + 7;
       var foo_3 : i32 = -20;)";
 
-  std::vector<std::pair<size_t, size_t>> literals_pos =
-      GetIntLiterals(wgsl_code);
+    std::vector<std::pair<size_t, size_t>> literals_pos = GetIntLiterals(wgsl_code);
 
-  std::vector<std::string> ground_truth = {"3", "10", "5", "7", "-20"};
+    std::vector<std::string> ground_truth = {"3", "10", "5", "7", "-20"};
 
-  std::vector<std::string> result;
+    std::vector<std::string> result;
 
-  for (auto pos : literals_pos) {
-    result.push_back(wgsl_code.substr(pos.first, pos.second));
-  }
+    for (auto pos : literals_pos) {
+        result.push_back(wgsl_code.substr(pos.first, pos.second));
+    }
 
-  ASSERT_EQ(ground_truth, result);
+    ASSERT_EQ(ground_truth, result);
 }
 
 TEST(InsertReturnTest, FindClosingBrace) {
-  std::string wgsl_code =
-      R"(fn clamp_0acf8f() {
+    std::string wgsl_code =
+        R"(fn clamp_0acf8f() {
         if(false){
 
         } else{
@@ -294,26 +268,26 @@
         foo_1 = 5 + 7;
         var foo_3 : i32 = -20;
       )";
-  size_t opening_bracket_pos = 18;
-  size_t closing_bracket_pos = FindClosingBrace(opening_bracket_pos, wgsl_code);
+    size_t opening_bracket_pos = 18;
+    size_t closing_bracket_pos = FindClosingBrace(opening_bracket_pos, wgsl_code);
 
-  // The -1 is needed since the function body starts after the left bracket.
-  std::string function_body = wgsl_code.substr(
-      opening_bracket_pos + 1, closing_bracket_pos - opening_bracket_pos - 1);
-  std::string expected =
-      R"(
+    // The -1 is needed since the function body starts after the left bracket.
+    std::string function_body =
+        wgsl_code.substr(opening_bracket_pos + 1, closing_bracket_pos - opening_bracket_pos - 1);
+    std::string expected =
+        R"(
         if(false){
 
         } else{
           var res: vec2<f32> = clamp(vec2<f32>(), vec2<f32>(), vec2<f32>());
           }
         )";
-  ASSERT_EQ(expected, function_body);
+    ASSERT_EQ(expected, function_body);
 }
 
 TEST(InsertReturnTest, FindClosingBraceFailing) {
-  std::string wgsl_code =
-      R"(fn clamp_0acf8f() {
+    std::string wgsl_code =
+        R"(fn clamp_0acf8f() {
       // This comment } causes the test to fail.
       "if(false){
 
@@ -339,25 +313,25 @@
       }
       foo_1 = 5 + 7;
       var foo_3 : i32 = -20;)";
-  size_t opening_bracket_pos = 18;
-  size_t closing_bracket_pos = FindClosingBrace(opening_bracket_pos, wgsl_code);
+    size_t opening_bracket_pos = 18;
+    size_t closing_bracket_pos = FindClosingBrace(opening_bracket_pos, wgsl_code);
 
-  // The -1 is needed since the function body starts after the left bracket.
-  std::string function_body = wgsl_code.substr(
-      opening_bracket_pos + 1, closing_bracket_pos - opening_bracket_pos - 1);
-  std::string expected =
-      R"(// This comment } causes the test to fail.
+    // The -1 is needed since the function body starts after the left bracket.
+    std::string function_body =
+        wgsl_code.substr(opening_bracket_pos + 1, closing_bracket_pos - opening_bracket_pos - 1);
+    std::string expected =
+        R"(// This comment } causes the test to fail.
       "if(false){
 
       } else{
         var res: vec2<f32> = clamp(vec2<f32>(), vec2<f32>(), vec2<f32>());
         })";
-  ASSERT_NE(expected, function_body);
+    ASSERT_NE(expected, function_body);
 }
 
 TEST(TestInsertReturn, TestInsertReturn1) {
-  std::string wgsl_code =
-      R"(fn clamp_0acf8f() {
+    std::string wgsl_code =
+        R"(fn clamp_0acf8f() {
         var res: vec2<f32> = clamp(vec2<f32>(), vec2<f32>(), vec2<f32>());
       }
       @stage(vertex)
@@ -379,18 +353,18 @@
       foo_1 = 5 + 7;
       var foo_3 : i32 = -20;)";
 
-  std::vector<size_t> semicolon_pos;
-  for (size_t pos = wgsl_code.find(";", 0); pos != std::string::npos;
-       pos = wgsl_code.find(";", pos + 1)) {
-    semicolon_pos.push_back(pos);
-  }
+    std::vector<size_t> semicolon_pos;
+    for (size_t pos = wgsl_code.find(";", 0); pos != std::string::npos;
+         pos = wgsl_code.find(";", pos + 1)) {
+        semicolon_pos.push_back(pos);
+    }
 
-  // should insert a return true statement after the first semicolon of the
-  // first function the the WGSL-like string above.
-  wgsl_code.insert(semicolon_pos[0] + 1, "return true;");
+    // should insert a return true statement after the first semicolon of the
+    // first function the the WGSL-like string above.
+    wgsl_code.insert(semicolon_pos[0] + 1, "return true;");
 
-  std::string expected_wgsl_code =
-      R"(fn clamp_0acf8f() {
+    std::string expected_wgsl_code =
+        R"(fn clamp_0acf8f() {
         var res: vec2<f32> = clamp(vec2<f32>(), vec2<f32>(), vec2<f32>());return true;
       }
       @stage(vertex)
@@ -412,12 +386,12 @@
       foo_1 = 5 + 7;
       var foo_3 : i32 = -20;)";
 
-  ASSERT_EQ(expected_wgsl_code, wgsl_code);
+    ASSERT_EQ(expected_wgsl_code, wgsl_code);
 }
 
 TEST(TestInsertReturn, TestFunctionPositions) {
-  std::string wgsl_code =
-      R"(fn clamp_0acf8f() {
+    std::string wgsl_code =
+        R"(fn clamp_0acf8f() {
           var res: vec2<f32> = clamp(vec2<f32>(), vec2<f32>(), vec2<f32>());
         }
         @stage(vertex)
@@ -444,14 +418,14 @@
         foo_1 = 5 + 7;
         var foo_3 : i32 = -20;)";
 
-  std::vector<size_t> function_positions = GetFunctionBodyPositions(wgsl_code);
-  std::vector<size_t> expected_positions = {187, 607};
-  ASSERT_EQ(expected_positions, function_positions);
+    std::vector<size_t> function_positions = GetFunctionBodyPositions(wgsl_code);
+    std::vector<size_t> expected_positions = {187, 607};
+    ASSERT_EQ(expected_positions, function_positions);
 }
 
 TEST(TestInsertReturn, TestMissingSemicolon) {
-  std::string wgsl_code =
-      R"(fn clamp_0acf8f() {
+    std::string wgsl_code =
+        R"(fn clamp_0acf8f() {
           var res: vec2<f32> = clamp(vec2<f32>(), vec2<f32>(), vec2<f32>())
         }
         @stage(vertex)
@@ -478,13 +452,13 @@
         foo_1 = 5 + 7;
         var foo_3 : i32 = -20;)";
 
-  RandomGenerator generator(0);
-  InsertReturnStatement(wgsl_code, generator);
+    RandomGenerator generator(0);
+    InsertReturnStatement(wgsl_code, generator);
 
-  // No semicolons found in the function's body, so wgsl_code
-  // should remain unchanged.
-  std::string expected_wgsl_code =
-      R"(fn clamp_0acf8f() {
+    // No semicolons found in the function's body, so wgsl_code
+    // should remain unchanged.
+    std::string expected_wgsl_code =
+        R"(fn clamp_0acf8f() {
           var res: vec2<f32> = clamp(vec2<f32>(), vec2<f32>(), vec2<f32>())
         }
         @stage(vertex)
@@ -510,7 +484,7 @@
         }
         foo_1 = 5 + 7;
         var foo_3 : i32 = -20;)";
-  ASSERT_EQ(expected_wgsl_code, wgsl_code);
+    ASSERT_EQ(expected_wgsl_code, wgsl_code);
 }
 
 }  // namespace
diff --git a/src/tint/fuzzers/tint_regex_fuzzer/tint_regex_fuzzer.cc b/src/tint/fuzzers/tint_regex_fuzzer/tint_regex_fuzzer.cc
index 77c145c..58ba639 100644
--- a/src/tint/fuzzers/tint_regex_fuzzer/tint_regex_fuzzer.cc
+++ b/src/tint/fuzzers/tint_regex_fuzzer/tint_regex_fuzzer.cc
@@ -18,7 +18,7 @@
 namespace tint::fuzzers::regex_fuzzer {
 
 void OverrideCliParams(CliParams& /*unused*/) {
-  // Leave the CLI parameters unchanged.
+    // Leave the CLI parameters unchanged.
 }
 
 }  // namespace tint::fuzzers::regex_fuzzer
diff --git a/src/tint/fuzzers/tint_regex_fuzzer/tint_regex_hlsl_writer_fuzzer.cc b/src/tint/fuzzers/tint_regex_fuzzer/tint_regex_hlsl_writer_fuzzer.cc
index dea4e11..bb84c28 100644
--- a/src/tint/fuzzers/tint_regex_fuzzer/tint_regex_hlsl_writer_fuzzer.cc
+++ b/src/tint/fuzzers/tint_regex_fuzzer/tint_regex_hlsl_writer_fuzzer.cc
@@ -20,10 +20,10 @@
 namespace tint::fuzzers::regex_fuzzer {
 
 void OverrideCliParams(CliParams& cli_params) {
-  assert(cli_params.fuzzing_target == FuzzingTarget::kAll &&
-         "The fuzzing target should not have been set by a CLI parameter: it "
-         "should have its default value.");
-  cli_params.fuzzing_target = FuzzingTarget::kHlsl;
+    assert(cli_params.fuzzing_target == FuzzingTarget::kAll &&
+           "The fuzzing target should not have been set by a CLI parameter: it "
+           "should have its default value.");
+    cli_params.fuzzing_target = FuzzingTarget::kHlsl;
 }
 
 }  // namespace tint::fuzzers::regex_fuzzer
diff --git a/src/tint/fuzzers/tint_regex_fuzzer/tint_regex_msl_writer_fuzzer.cc b/src/tint/fuzzers/tint_regex_fuzzer/tint_regex_msl_writer_fuzzer.cc
index 07b59c5..297cae0 100644
--- a/src/tint/fuzzers/tint_regex_fuzzer/tint_regex_msl_writer_fuzzer.cc
+++ b/src/tint/fuzzers/tint_regex_fuzzer/tint_regex_msl_writer_fuzzer.cc
@@ -20,10 +20,10 @@
 namespace tint::fuzzers::regex_fuzzer {
 
 void OverrideCliParams(CliParams& cli_params) {
-  assert(cli_params.fuzzing_target == FuzzingTarget::kAll &&
-         "The fuzzing target should not have been set by a CLI parameter: it "
-         "should have its default value.");
-  cli_params.fuzzing_target = FuzzingTarget::kMsl;
+    assert(cli_params.fuzzing_target == FuzzingTarget::kAll &&
+           "The fuzzing target should not have been set by a CLI parameter: it "
+           "should have its default value.");
+    cli_params.fuzzing_target = FuzzingTarget::kMsl;
 }
 
 }  // namespace tint::fuzzers::regex_fuzzer
diff --git a/src/tint/fuzzers/tint_regex_fuzzer/tint_regex_spv_writer_fuzzer.cc b/src/tint/fuzzers/tint_regex_fuzzer/tint_regex_spv_writer_fuzzer.cc
index 95fec21..75a359e 100644
--- a/src/tint/fuzzers/tint_regex_fuzzer/tint_regex_spv_writer_fuzzer.cc
+++ b/src/tint/fuzzers/tint_regex_fuzzer/tint_regex_spv_writer_fuzzer.cc
@@ -20,10 +20,10 @@
 namespace tint::fuzzers::regex_fuzzer {
 
 void OverrideCliParams(CliParams& cli_params) {
-  assert(cli_params.fuzzing_target == FuzzingTarget::kAll &&
-         "The fuzzing target should not have been set by a CLI parameter: it "
-         "should have its default value.");
-  cli_params.fuzzing_target = FuzzingTarget::kSpv;
+    assert(cli_params.fuzzing_target == FuzzingTarget::kAll &&
+           "The fuzzing target should not have been set by a CLI parameter: it "
+           "should have its default value.");
+    cli_params.fuzzing_target = FuzzingTarget::kSpv;
 }
 
 }  // namespace tint::fuzzers::regex_fuzzer
diff --git a/src/tint/fuzzers/tint_regex_fuzzer/tint_regex_wgsl_writer_fuzzer.cc b/src/tint/fuzzers/tint_regex_fuzzer/tint_regex_wgsl_writer_fuzzer.cc
index dfaf3a3..21621d0 100644
--- a/src/tint/fuzzers/tint_regex_fuzzer/tint_regex_wgsl_writer_fuzzer.cc
+++ b/src/tint/fuzzers/tint_regex_fuzzer/tint_regex_wgsl_writer_fuzzer.cc
@@ -20,10 +20,10 @@
 namespace tint::fuzzers::regex_fuzzer {
 
 void OverrideCliParams(CliParams& cli_params) {
-  assert(cli_params.fuzzing_target == FuzzingTarget::kAll &&
-         "The fuzzing target should not have been set by a CLI parameter: it "
-         "should have its default value.");
-  cli_params.fuzzing_target = FuzzingTarget::kWgsl;
+    assert(cli_params.fuzzing_target == FuzzingTarget::kAll &&
+           "The fuzzing target should not have been set by a CLI parameter: it "
+           "should have its default value.");
+    cli_params.fuzzing_target = FuzzingTarget::kWgsl;
 }
 
 }  // namespace tint::fuzzers::regex_fuzzer
diff --git a/src/tint/fuzzers/tint_regex_fuzzer/wgsl_mutator.cc b/src/tint/fuzzers/tint_regex_fuzzer/wgsl_mutator.cc
index 2397e7f..677560b 100644
--- a/src/tint/fuzzers/tint_regex_fuzzer/wgsl_mutator.cc
+++ b/src/tint/fuzzers/tint_regex_fuzzer/wgsl_mutator.cc
@@ -28,146 +28,133 @@
 
 std::vector<size_t> FindDelimiterIndices(const std::string& delimiter,
                                          const std::string& wgsl_code) {
-  std::vector<size_t> result;
-  for (size_t pos = wgsl_code.find(delimiter, 0); pos != std::string::npos;
-       pos = wgsl_code.find(delimiter, pos + 1)) {
-    result.push_back(pos);
-  }
+    std::vector<size_t> result;
+    for (size_t pos = wgsl_code.find(delimiter, 0); pos != std::string::npos;
+         pos = wgsl_code.find(delimiter, pos + 1)) {
+        result.push_back(pos);
+    }
 
-  return result;
+    return result;
 }
 
-std::vector<std::pair<size_t, size_t>> GetIdentifiers(
-    const std::string& wgsl_code) {
-  std::vector<std::pair<size_t, size_t>> result;
+std::vector<std::pair<size_t, size_t>> GetIdentifiers(const std::string& wgsl_code) {
+    std::vector<std::pair<size_t, size_t>> result;
 
-  // This regular expression works by looking for a character that
-  // is not part of an identifier followed by a WGSL identifier, followed
-  // by a character which cannot be part of a WGSL identifer. The regex
-  // for the WGSL identifier is obtained from:
-  // https://www.w3.org/TR/WGSL/#identifiers.
-  std::regex wgsl_identifier_regex(
-      "[^a-zA-Z]([a-zA-Z][0-9a-zA-Z_]*)[^0-9a-zA-Z_]");
+    // This regular expression works by looking for a character that
+    // is not part of an identifier followed by a WGSL identifier, followed
+    // by a character which cannot be part of a WGSL identifer. The regex
+    // for the WGSL identifier is obtained from:
+    // https://www.w3.org/TR/WGSL/#identifiers.
+    std::regex wgsl_identifier_regex("[^a-zA-Z]([a-zA-Z][0-9a-zA-Z_]*)[^0-9a-zA-Z_]");
 
-  std::smatch match;
+    std::smatch match;
 
-  std::string::const_iterator search_start(wgsl_code.cbegin());
-  std::string prefix;
+    std::string::const_iterator search_start(wgsl_code.cbegin());
+    std::string prefix;
 
-  while (regex_search(search_start, wgsl_code.cend(), match,
-                      wgsl_identifier_regex) == true) {
-    prefix += match.prefix();
-    result.push_back(std::make_pair(prefix.size() + 1, match.str(1).size()));
-    prefix += match.str(0);
-    search_start = match.suffix().first;
-  }
-  return result;
+    while (regex_search(search_start, wgsl_code.cend(), match, wgsl_identifier_regex) == true) {
+        prefix += match.prefix();
+        result.push_back(std::make_pair(prefix.size() + 1, match.str(1).size()));
+        prefix += match.str(0);
+        search_start = match.suffix().first;
+    }
+    return result;
 }
 
 std::vector<std::pair<size_t, size_t>> GetIntLiterals(const std::string& s) {
-  std::vector<std::pair<size_t, size_t>> result;
+    std::vector<std::pair<size_t, size_t>> result;
 
-  // Looks for integer literals in decimal or hexadecimal form.
-  // Regex obtained here: https://www.w3.org/TR/WGSL/#literals
-  std::regex int_literal_regex("-?0x[0-9a-fA-F]+ | 0 | -?[1-9][0-9]*");
-  std::regex uint_literal_regex("0x[0-9a-fA-F]+u | 0u | [1-9][0-9]*u");
-  std::smatch match;
+    // Looks for integer literals in decimal or hexadecimal form.
+    // Regex obtained here: https://www.w3.org/TR/WGSL/#literals
+    std::regex int_literal_regex("-?0x[0-9a-fA-F]+ | 0 | -?[1-9][0-9]*");
+    std::regex uint_literal_regex("0x[0-9a-fA-F]+u | 0u | [1-9][0-9]*u");
+    std::smatch match;
 
-  std::string::const_iterator search_start(s.cbegin());
-  std::string prefix = "";
+    std::string::const_iterator search_start(s.cbegin());
+    std::string prefix = "";
 
-  while (regex_search(search_start, s.cend(), match, int_literal_regex) ||
-         regex_search(search_start, s.cend(), match, uint_literal_regex)) {
-    prefix += match.prefix();
-    result.push_back(
-        std::make_pair(prefix.size() + 1, match.str(0).size() - 1));
-    prefix += match.str(0);
-    search_start = match.suffix().first;
-  }
-  return result;
+    while (regex_search(search_start, s.cend(), match, int_literal_regex) ||
+           regex_search(search_start, s.cend(), match, uint_literal_regex)) {
+        prefix += match.prefix();
+        result.push_back(std::make_pair(prefix.size() + 1, match.str(0).size() - 1));
+        prefix += match.str(0);
+        search_start = match.suffix().first;
+    }
+    return result;
 }
 
-size_t FindClosingBrace(size_t opening_bracket_pos,
-                        const std::string& wgsl_code) {
-  size_t open_bracket_count = 1;
-  size_t pos = opening_bracket_pos + 1;
-  while (open_bracket_count >= 1 && pos < wgsl_code.size()) {
-    if (wgsl_code[pos] == '{') {
-      ++open_bracket_count;
-    } else if (wgsl_code[pos] == '}') {
-      --open_bracket_count;
+size_t FindClosingBrace(size_t opening_bracket_pos, const std::string& wgsl_code) {
+    size_t open_bracket_count = 1;
+    size_t pos = opening_bracket_pos + 1;
+    while (open_bracket_count >= 1 && pos < wgsl_code.size()) {
+        if (wgsl_code[pos] == '{') {
+            ++open_bracket_count;
+        } else if (wgsl_code[pos] == '}') {
+            --open_bracket_count;
+        }
+        ++pos;
     }
-    ++pos;
-  }
-  return (pos == wgsl_code.size() && open_bracket_count >= 1) ? 0 : pos - 1;
+    return (pos == wgsl_code.size() && open_bracket_count >= 1) ? 0 : pos - 1;
 }
 
 std::vector<size_t> GetFunctionBodyPositions(const std::string& wgsl_code) {
-  // Finds all the functions with a non-void return value.
-  std::regex function_regex("fn.*?->.*?\\{");
-  std::smatch match;
-  std::vector<size_t> result;
+    // Finds all the functions with a non-void return value.
+    std::regex function_regex("fn.*?->.*?\\{");
+    std::smatch match;
+    std::vector<size_t> result;
 
-  auto search_start(wgsl_code.cbegin());
-  std::string prefix = "";
+    auto search_start(wgsl_code.cbegin());
+    std::string prefix = "";
 
-  while (std::regex_search(search_start, wgsl_code.cend(), match,
-                           function_regex)) {
-    result.push_back(
-        static_cast<size_t>(match.suffix().first - wgsl_code.cbegin() - 1L));
-    search_start = match.suffix().first;
-  }
-  return result;
+    while (std::regex_search(search_start, wgsl_code.cend(), match, function_regex)) {
+        result.push_back(static_cast<size_t>(match.suffix().first - wgsl_code.cbegin() - 1L));
+        search_start = match.suffix().first;
+    }
+    return result;
 }
 
 bool InsertReturnStatement(std::string& wgsl_code, RandomGenerator& generator) {
-  std::vector<size_t> function_body_positions =
-      GetFunctionBodyPositions(wgsl_code);
+    std::vector<size_t> function_body_positions = GetFunctionBodyPositions(wgsl_code);
 
-  // No function was found in wgsl_code.
-  if (function_body_positions.empty()) {
-    return false;
-  }
+    // No function was found in wgsl_code.
+    if (function_body_positions.empty()) {
+        return false;
+    }
 
-  // Pick a random function's opening bracket, find the corresponding closing
-  // bracket, and find a semi-colon within the function body.
-  size_t left_bracket_pos = generator.GetRandomElement(function_body_positions);
+    // Pick a random function's opening bracket, find the corresponding closing
+    // bracket, and find a semi-colon within the function body.
+    size_t left_bracket_pos = generator.GetRandomElement(function_body_positions);
 
-  size_t right_bracket_pos = FindClosingBrace(left_bracket_pos, wgsl_code);
+    size_t right_bracket_pos = FindClosingBrace(left_bracket_pos, wgsl_code);
 
-  if (right_bracket_pos == 0) {
-    return false;
-  }
+    if (right_bracket_pos == 0) {
+        return false;
+    }
 
-  std::vector<size_t> semicolon_positions;
-  for (size_t pos = wgsl_code.find(";", left_bracket_pos + 1);
-       pos < right_bracket_pos; pos = wgsl_code.find(";", pos + 1)) {
-    semicolon_positions.push_back(pos);
-  }
+    std::vector<size_t> semicolon_positions;
+    for (size_t pos = wgsl_code.find(";", left_bracket_pos + 1); pos < right_bracket_pos;
+         pos = wgsl_code.find(";", pos + 1)) {
+        semicolon_positions.push_back(pos);
+    }
 
-  if (semicolon_positions.empty()) {
-    return false;
-  }
+    if (semicolon_positions.empty()) {
+        return false;
+    }
 
-  size_t semicolon_position = generator.GetRandomElement(semicolon_positions);
+    size_t semicolon_position = generator.GetRandomElement(semicolon_positions);
 
-  // Get all identifiers and integer literals to use as potential return values.
-  std::vector<std::pair<size_t, size_t>> identifiers =
-      GetIdentifiers(wgsl_code);
-  auto return_values = identifiers;
-  std::vector<std::pair<size_t, size_t>> int_literals =
-      GetIntLiterals(wgsl_code);
-  return_values.insert(return_values.end(), int_literals.begin(),
-                       int_literals.end());
-  std::pair<size_t, size_t> return_value =
-      generator.GetRandomElement(return_values);
-  std::string return_statement =
-      "return " + wgsl_code.substr(return_value.first, return_value.second) +
-      ";";
+    // Get all identifiers and integer literals to use as potential return values.
+    std::vector<std::pair<size_t, size_t>> identifiers = GetIdentifiers(wgsl_code);
+    auto return_values = identifiers;
+    std::vector<std::pair<size_t, size_t>> int_literals = GetIntLiterals(wgsl_code);
+    return_values.insert(return_values.end(), int_literals.begin(), int_literals.end());
+    std::pair<size_t, size_t> return_value = generator.GetRandomElement(return_values);
+    std::string return_statement =
+        "return " + wgsl_code.substr(return_value.first, return_value.second) + ";";
 
-  // Insert the return statement immediately after the semicolon.
-  wgsl_code.insert(semicolon_position + 1, return_statement);
-  return true;
+    // Insert the return statement immediately after the semicolon.
+    wgsl_code.insert(semicolon_position + 1, return_statement);
+    return true;
 }
 
 void SwapIntervals(size_t idx1,
@@ -175,26 +162,23 @@
                    size_t idx2,
                    size_t reg2_len,
                    std::string& wgsl_code) {
-  std::string region_1 = wgsl_code.substr(idx1 + 1, reg1_len - 1);
+    std::string region_1 = wgsl_code.substr(idx1 + 1, reg1_len - 1);
 
-  std::string region_2 = wgsl_code.substr(idx2 + 1, reg2_len - 1);
+    std::string region_2 = wgsl_code.substr(idx2 + 1, reg2_len - 1);
 
-  // The second transformation is done first as it doesn't affect idx2.
-  wgsl_code.replace(idx2 + 1, region_2.size(), region_1);
+    // The second transformation is done first as it doesn't affect idx2.
+    wgsl_code.replace(idx2 + 1, region_2.size(), region_1);
 
-  wgsl_code.replace(idx1 + 1, region_1.size(), region_2);
+    wgsl_code.replace(idx1 + 1, region_1.size(), region_2);
 }
 
 void DeleteInterval(size_t idx1, size_t reg_len, std::string& wgsl_code) {
-  wgsl_code.erase(idx1 + 1, reg_len - 1);
+    wgsl_code.erase(idx1 + 1, reg_len - 1);
 }
 
-void DuplicateInterval(size_t idx1,
-                       size_t reg1_len,
-                       size_t idx2,
-                       std::string& wgsl_code) {
-  std::string region = wgsl_code.substr(idx1 + 1, reg1_len - 1);
-  wgsl_code.insert(idx2 + 1, region);
+void DuplicateInterval(size_t idx1, size_t reg1_len, size_t idx2, std::string& wgsl_code) {
+    std::string region = wgsl_code.substr(idx1 + 1, reg1_len - 1);
+    wgsl_code.insert(idx2 + 1, region);
 }
 
 void ReplaceRegion(size_t idx1,
@@ -202,153 +186,137 @@
                    size_t idx2,
                    size_t id2_len,
                    std::string& wgsl_code) {
-  std::string region_1 = wgsl_code.substr(idx1, id1_len);
-  std::string region_2 = wgsl_code.substr(idx2, id2_len);
-  wgsl_code.replace(idx2, region_2.size(), region_1);
+    std::string region_1 = wgsl_code.substr(idx1, id1_len);
+    std::string region_2 = wgsl_code.substr(idx2, id2_len);
+    wgsl_code.replace(idx2, region_2.size(), region_1);
 }
 
 void ReplaceInterval(size_t start_index,
                      size_t length,
                      std::string replacement_text,
                      std::string& wgsl_code) {
-  std::string region_1 = wgsl_code.substr(start_index, length);
-  wgsl_code.replace(start_index, length, replacement_text);
+    std::string region_1 = wgsl_code.substr(start_index, length);
+    wgsl_code.replace(start_index, length, replacement_text);
 }
 
 bool SwapRandomIntervals(const std::string& delimiter,
                          std::string& wgsl_code,
                          RandomGenerator& generator) {
-  std::vector<size_t> delimiter_positions =
-      FindDelimiterIndices(delimiter, wgsl_code);
+    std::vector<size_t> delimiter_positions = FindDelimiterIndices(delimiter, wgsl_code);
 
-  // Need to have at least 3 indices.
-  if (delimiter_positions.size() < 3) {
-    return false;
-  }
+    // Need to have at least 3 indices.
+    if (delimiter_positions.size() < 3) {
+        return false;
+    }
 
-  // Choose indices:
-  //   interval_1_start < interval_1_end <= interval_2_start < interval_2_end
-  uint32_t interval_1_start = generator.GetUInt32(
-      static_cast<uint32_t>(delimiter_positions.size()) - 2u);
-  uint32_t interval_1_end = generator.GetUInt32(
-      interval_1_start + 1u,
-      static_cast<uint32_t>(delimiter_positions.size()) - 1u);
-  uint32_t interval_2_start = generator.GetUInt32(
-      interval_1_end, static_cast<uint32_t>(delimiter_positions.size()) - 1u);
-  uint32_t interval_2_end = generator.GetUInt32(
-      interval_2_start + 1u, static_cast<uint32_t>(delimiter_positions.size()));
+    // Choose indices:
+    //   interval_1_start < interval_1_end <= interval_2_start < interval_2_end
+    uint32_t interval_1_start =
+        generator.GetUInt32(static_cast<uint32_t>(delimiter_positions.size()) - 2u);
+    uint32_t interval_1_end = generator.GetUInt32(
+        interval_1_start + 1u, static_cast<uint32_t>(delimiter_positions.size()) - 1u);
+    uint32_t interval_2_start =
+        generator.GetUInt32(interval_1_end, static_cast<uint32_t>(delimiter_positions.size()) - 1u);
+    uint32_t interval_2_end = generator.GetUInt32(
+        interval_2_start + 1u, static_cast<uint32_t>(delimiter_positions.size()));
 
-  SwapIntervals(delimiter_positions[interval_1_start],
-                delimiter_positions[interval_1_end] -
-                    delimiter_positions[interval_1_start],
-                delimiter_positions[interval_2_start],
-                delimiter_positions[interval_2_end] -
-                    delimiter_positions[interval_2_start],
-                wgsl_code);
+    SwapIntervals(delimiter_positions[interval_1_start],
+                  delimiter_positions[interval_1_end] - delimiter_positions[interval_1_start],
+                  delimiter_positions[interval_2_start],
+                  delimiter_positions[interval_2_end] - delimiter_positions[interval_2_start],
+                  wgsl_code);
 
-  return true;
+    return true;
 }
 
 bool DeleteRandomInterval(const std::string& delimiter,
                           std::string& wgsl_code,
                           RandomGenerator& generator) {
-  std::vector<size_t> delimiter_positions =
-      FindDelimiterIndices(delimiter, wgsl_code);
+    std::vector<size_t> delimiter_positions = FindDelimiterIndices(delimiter, wgsl_code);
 
-  // Need to have at least 2 indices.
-  if (delimiter_positions.size() < 2) {
-    return false;
-  }
+    // Need to have at least 2 indices.
+    if (delimiter_positions.size() < 2) {
+        return false;
+    }
 
-  uint32_t interval_start = generator.GetUInt32(
-      static_cast<uint32_t>(delimiter_positions.size()) - 1u);
-  uint32_t interval_end = generator.GetUInt32(
-      interval_start + 1u, static_cast<uint32_t>(delimiter_positions.size()));
+    uint32_t interval_start =
+        generator.GetUInt32(static_cast<uint32_t>(delimiter_positions.size()) - 1u);
+    uint32_t interval_end =
+        generator.GetUInt32(interval_start + 1u, static_cast<uint32_t>(delimiter_positions.size()));
 
-  DeleteInterval(
-      delimiter_positions[interval_start],
-      delimiter_positions[interval_end] - delimiter_positions[interval_start],
-      wgsl_code);
+    DeleteInterval(delimiter_positions[interval_start],
+                   delimiter_positions[interval_end] - delimiter_positions[interval_start],
+                   wgsl_code);
 
-  return true;
+    return true;
 }
 
 bool DuplicateRandomInterval(const std::string& delimiter,
                              std::string& wgsl_code,
                              RandomGenerator& generator) {
-  std::vector<size_t> delimiter_positions =
-      FindDelimiterIndices(delimiter, wgsl_code);
+    std::vector<size_t> delimiter_positions = FindDelimiterIndices(delimiter, wgsl_code);
 
-  // Need to have at least 2 indices
-  if (delimiter_positions.size() < 2) {
-    return false;
-  }
+    // Need to have at least 2 indices
+    if (delimiter_positions.size() < 2) {
+        return false;
+    }
 
-  uint32_t interval_start = generator.GetUInt32(
-      static_cast<uint32_t>(delimiter_positions.size()) - 1u);
-  uint32_t interval_end = generator.GetUInt32(
-      interval_start + 1u, static_cast<uint32_t>(delimiter_positions.size()));
-  uint32_t duplication_point =
-      generator.GetUInt32(static_cast<uint32_t>(delimiter_positions.size()));
+    uint32_t interval_start =
+        generator.GetUInt32(static_cast<uint32_t>(delimiter_positions.size()) - 1u);
+    uint32_t interval_end =
+        generator.GetUInt32(interval_start + 1u, static_cast<uint32_t>(delimiter_positions.size()));
+    uint32_t duplication_point =
+        generator.GetUInt32(static_cast<uint32_t>(delimiter_positions.size()));
 
-  DuplicateInterval(
-      delimiter_positions[interval_start],
-      delimiter_positions[interval_end] - delimiter_positions[interval_start],
-      delimiter_positions[duplication_point], wgsl_code);
+    DuplicateInterval(delimiter_positions[interval_start],
+                      delimiter_positions[interval_end] - delimiter_positions[interval_start],
+                      delimiter_positions[duplication_point], wgsl_code);
 
-  return true;
+    return true;
 }
 
-bool ReplaceRandomIdentifier(std::string& wgsl_code,
-                             RandomGenerator& generator) {
-  std::vector<std::pair<size_t, size_t>> identifiers =
-      GetIdentifiers(wgsl_code);
+bool ReplaceRandomIdentifier(std::string& wgsl_code, RandomGenerator& generator) {
+    std::vector<std::pair<size_t, size_t>> identifiers = GetIdentifiers(wgsl_code);
 
-  // Need at least 2 identifiers
-  if (identifiers.size() < 2) {
-    return false;
-  }
+    // Need at least 2 identifiers
+    if (identifiers.size() < 2) {
+        return false;
+    }
 
-  uint32_t id1_index =
-      generator.GetUInt32(static_cast<uint32_t>(identifiers.size()));
-  uint32_t id2_index =
-      generator.GetUInt32(static_cast<uint32_t>(identifiers.size()));
+    uint32_t id1_index = generator.GetUInt32(static_cast<uint32_t>(identifiers.size()));
+    uint32_t id2_index = generator.GetUInt32(static_cast<uint32_t>(identifiers.size()));
 
-  // The two identifiers must be different
-  while (id1_index == id2_index) {
-    id2_index = generator.GetUInt32(static_cast<uint32_t>(identifiers.size()));
-  }
+    // The two identifiers must be different
+    while (id1_index == id2_index) {
+        id2_index = generator.GetUInt32(static_cast<uint32_t>(identifiers.size()));
+    }
 
-  ReplaceRegion(identifiers[id1_index].first, identifiers[id1_index].second,
-                identifiers[id2_index].first, identifiers[id2_index].second,
-                wgsl_code);
+    ReplaceRegion(identifiers[id1_index].first, identifiers[id1_index].second,
+                  identifiers[id2_index].first, identifiers[id2_index].second, wgsl_code);
 
-  return true;
+    return true;
 }
 
-bool ReplaceRandomIntLiteral(std::string& wgsl_code,
-                             RandomGenerator& generator) {
-  std::vector<std::pair<size_t, size_t>> literals = GetIntLiterals(wgsl_code);
+bool ReplaceRandomIntLiteral(std::string& wgsl_code, RandomGenerator& generator) {
+    std::vector<std::pair<size_t, size_t>> literals = GetIntLiterals(wgsl_code);
 
-  // Need at least one integer literal
-  if (literals.size() < 1) {
-    return false;
-  }
+    // Need at least one integer literal
+    if (literals.size() < 1) {
+        return false;
+    }
 
-  uint32_t literal_index =
-      generator.GetUInt32(static_cast<uint32_t>(literals.size()));
+    uint32_t literal_index = generator.GetUInt32(static_cast<uint32_t>(literals.size()));
 
-  // INT_MAX = 2147483647, INT_MIN = -2147483648
-  std::vector<std::string> boundary_values = {
-      "2147483647", "-2147483648", "1", "-1", "0", "4294967295"};
+    // INT_MAX = 2147483647, INT_MIN = -2147483648
+    std::vector<std::string> boundary_values = {"2147483647", "-2147483648", "1",
+                                                "-1",         "0",           "4294967295"};
 
-  uint32_t boundary_index =
-      generator.GetUInt32(static_cast<uint32_t>(boundary_values.size()));
+    uint32_t boundary_index = generator.GetUInt32(static_cast<uint32_t>(boundary_values.size()));
 
-  ReplaceInterval(literals[literal_index].first, literals[literal_index].second,
-                  boundary_values[boundary_index], wgsl_code);
+    ReplaceInterval(literals[literal_index].first, literals[literal_index].second,
+                    boundary_values[boundary_index], wgsl_code);
 
-  return true;
+    return true;
 }
 
 }  // namespace tint::fuzzers::regex_fuzzer
diff --git a/src/tint/fuzzers/tint_regex_fuzzer/wgsl_mutator.h b/src/tint/fuzzers/tint_regex_fuzzer/wgsl_mutator.h
index ec3bbef..23c45bb 100644
--- a/src/tint/fuzzers/tint_regex_fuzzer/wgsl_mutator.h
+++ b/src/tint/fuzzers/tint_regex_fuzzer/wgsl_mutator.h
@@ -35,8 +35,7 @@
 /// @param wgsl_code - the WGSL-like string where the identifiers will be found.
 /// @return a vector with the positions and the length of all the
 /// identifiers in wgsl_code.
-std::vector<std::pair<size_t, size_t>> GetIdentifiers(
-    const std::string& wgsl_code);
+std::vector<std::pair<size_t, size_t>> GetIdentifiers(const std::string& wgsl_code);
 
 /// A function that returns returns the starting position
 /// and the length of all the integer literals in a WGSL-like string.
@@ -44,8 +43,7 @@
 /// will be found.
 /// @return a vector with the starting positions and the length
 /// of all the integer literals.
-std::vector<std::pair<size_t, size_t>> GetIntLiterals(
-    const std::string& wgsl_code);
+std::vector<std::pair<size_t, size_t>> GetIntLiterals(const std::string& wgsl_code);
 
 /// Finds a possible closing brace corresponding to the opening
 /// brace at position opening_bracket_pos.
@@ -53,8 +51,7 @@
 /// @param wgsl_code - the WGSL-like string where the closing brace.
 /// @return the position of the closing bracket or 0 if there is no closing
 /// brace.
-size_t FindClosingBrace(size_t opening_bracket_pos,
-                        const std::string& wgsl_code);
+size_t FindClosingBrace(size_t opening_bracket_pos, const std::string& wgsl_code);
 
 /// Returns the starting_position of the bodies of the functions
 /// that follow the regular expression: fn.*?->.*?\\{, which searches for the
@@ -92,10 +89,7 @@
 /// @param reg1_len - length of the region.
 /// @param idx2 - the position where the region will be inserted.
 /// @param wgsl_code - the string where the swap will occur.
-void DuplicateInterval(size_t idx1,
-                       size_t reg1_len,
-                       size_t idx2,
-                       std::string& wgsl_code);
+void DuplicateInterval(size_t idx1, size_t reg1_len, size_t idx2, std::string& wgsl_code);
 
 /// Replaces a region of a WGSL-like string of length id2_len starting
 /// at position idx2 with a region of length id1_len starting at
@@ -159,16 +153,14 @@
 /// @param wgsl_code - WGSL-like string where the replacement will occur.
 /// @param generator - the random number generator.
 /// @return true if a replacement happened or false otherwise.
-bool ReplaceRandomIdentifier(std::string& wgsl_code,
-                             RandomGenerator& generator);
+bool ReplaceRandomIdentifier(std::string& wgsl_code, RandomGenerator& generator);
 
 /// Replaces the value of a randomly-chosen integer with one of
 /// the values in the set {INT_MAX, INT_MIN, 0, -1}.
 /// @param wgsl_code - WGSL-like string where the replacement will occur.
 /// @param generator - the random number generator.
 /// @return true if a replacement happened or false otherwise.
-bool ReplaceRandomIntLiteral(std::string& wgsl_code,
-                             RandomGenerator& generator);
+bool ReplaceRandomIntLiteral(std::string& wgsl_code, RandomGenerator& generator);
 
 /// Inserts a return statement in a randomly chosen function of a
 /// WGSL-like string. The return value is a randomly-chosen identifier
diff --git a/src/tint/fuzzers/tint_renamer_fuzzer.cc b/src/tint/fuzzers/tint_renamer_fuzzer.cc
index 26a3f65..467eb68 100644
--- a/src/tint/fuzzers/tint_renamer_fuzzer.cc
+++ b/src/tint/fuzzers/tint_renamer_fuzzer.cc
@@ -19,15 +19,15 @@
 namespace tint::fuzzers {
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  TransformBuilder tb(data, size);
-  tb.AddTransform<transform::Renamer>();
+    TransformBuilder tb(data, size);
+    tb.AddTransform<transform::Renamer>();
 
-  fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kWGSL);
-  fuzzer.SetTransformManager(tb.manager(), tb.data_map());
-  fuzzer.SetDumpInput(GetCliParams().dump_input);
-  fuzzer.SetEnforceValidity(GetCliParams().enforce_validity);
+    fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kWGSL);
+    fuzzer.SetTransformManager(tb.manager(), tb.data_map());
+    fuzzer.SetDumpInput(GetCliParams().dump_input);
+    fuzzer.SetEnforceValidity(GetCliParams().enforce_validity);
 
-  return fuzzer.Run(data, size);
+    return fuzzer.Run(data, size);
 }
 
 }  // namespace tint::fuzzers
diff --git a/src/tint/fuzzers/tint_robustness_fuzzer.cc b/src/tint/fuzzers/tint_robustness_fuzzer.cc
index 8fd049a..dfc9a03 100644
--- a/src/tint/fuzzers/tint_robustness_fuzzer.cc
+++ b/src/tint/fuzzers/tint_robustness_fuzzer.cc
@@ -19,15 +19,15 @@
 namespace tint::fuzzers {
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  TransformBuilder tb(data, size);
-  tb.AddTransform<tint::transform::Robustness>();
+    TransformBuilder tb(data, size);
+    tb.AddTransform<tint::transform::Robustness>();
 
-  tint::fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kWGSL);
-  fuzzer.SetTransformManager(tb.manager(), tb.data_map());
-  fuzzer.SetDumpInput(GetCliParams().dump_input);
-  fuzzer.SetEnforceValidity(GetCliParams().enforce_validity);
+    tint::fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kWGSL);
+    fuzzer.SetTransformManager(tb.manager(), tb.data_map());
+    fuzzer.SetDumpInput(GetCliParams().dump_input);
+    fuzzer.SetEnforceValidity(GetCliParams().enforce_validity);
 
-  return fuzzer.Run(data, size);
+    return fuzzer.Run(data, size);
 }
 
 }  // namespace tint::fuzzers
diff --git a/src/tint/fuzzers/tint_single_entry_point_fuzzer.cc b/src/tint/fuzzers/tint_single_entry_point_fuzzer.cc
index 3d62c65..c0f076a 100644
--- a/src/tint/fuzzers/tint_single_entry_point_fuzzer.cc
+++ b/src/tint/fuzzers/tint_single_entry_point_fuzzer.cc
@@ -19,15 +19,15 @@
 namespace tint::fuzzers {
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  TransformBuilder tb(data, size);
-  tb.AddTransform<transform::SingleEntryPoint>();
+    TransformBuilder tb(data, size);
+    tb.AddTransform<transform::SingleEntryPoint>();
 
-  fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kWGSL);
-  fuzzer.SetTransformManager(tb.manager(), tb.data_map());
-  fuzzer.SetDumpInput(GetCliParams().dump_input);
-  fuzzer.SetEnforceValidity(GetCliParams().enforce_validity);
+    fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kWGSL);
+    fuzzer.SetTransformManager(tb.manager(), tb.data_map());
+    fuzzer.SetDumpInput(GetCliParams().dump_input);
+    fuzzer.SetEnforceValidity(GetCliParams().enforce_validity);
 
-  return fuzzer.Run(data, size);
+    return fuzzer.Run(data, size);
 }
 
 }  // namespace tint::fuzzers
diff --git a/src/tint/fuzzers/tint_spirv_tools_fuzzer/cli.cc b/src/tint/fuzzers/tint_spirv_tools_fuzzer/cli.cc
index b5e46fd..9e7c973 100644
--- a/src/tint/fuzzers/tint_spirv_tools_fuzzer/cli.cc
+++ b/src/tint/fuzzers/tint_spirv_tools_fuzzer/cli.cc
@@ -178,303 +178,293 @@
 )";
 
 void PrintHelpMessage(const char* help_message) {
-  std::cout << help_message << std::endl << kMutatorParameters << std::endl;
+    std::cout << help_message << std::endl << kMutatorParameters << std::endl;
 }
 
-[[noreturn]] void InvalidParameter(const char* help_message,
-                                   const char* param) {
-  std::cout << "Invalid value for " << param << std::endl;
-  PrintHelpMessage(help_message);
-  exit(1);
+[[noreturn]] void InvalidParameter(const char* help_message, const char* param) {
+    std::cout << "Invalid value for " << param << std::endl;
+    PrintHelpMessage(help_message);
+    exit(1);
 }
 
 bool ParseUint32(const char* param, uint32_t* out) {
-  uint64_t value = static_cast<uint64_t>(strtoul(param, nullptr, 10));
-  if (value > static_cast<uint64_t>(std::numeric_limits<uint32_t>::max())) {
-    return false;
-  }
-  *out = static_cast<uint32_t>(value);
-  return true;
+    uint64_t value = static_cast<uint64_t>(strtoul(param, nullptr, 10));
+    if (value > static_cast<uint64_t>(std::numeric_limits<uint32_t>::max())) {
+        return false;
+    }
+    *out = static_cast<uint32_t>(value);
+    return true;
 }
 
-std::vector<spvtools::fuzz::fuzzerutil::ModuleSupplier> ParseDonors(
-    const char* file_name) {
-  std::ifstream fin(file_name);
-  if (!fin) {
-    std::cout << "Can't open donors list file: " << file_name << std::endl;
-    exit(1);
-  }
-
-  std::vector<spvtools::fuzz::fuzzerutil::ModuleSupplier> result;
-  for (std::string donor_file_name; fin >> donor_file_name;) {
-    if (!std::ifstream(donor_file_name)) {
-      std::cout << "Can't open donor file: " << donor_file_name << std::endl;
-      exit(1);
+std::vector<spvtools::fuzz::fuzzerutil::ModuleSupplier> ParseDonors(const char* file_name) {
+    std::ifstream fin(file_name);
+    if (!fin) {
+        std::cout << "Can't open donors list file: " << file_name << std::endl;
+        exit(1);
     }
 
-    result.emplace_back([donor_file_name] {
-      std::vector<uint32_t> binary;
-      if (!util::ReadBinary(donor_file_name, &binary)) {
-        std::cout << "Failed to read donor from: " << donor_file_name
-                  << std::endl;
-        exit(1);
-      }
-      return spvtools::BuildModule(
-          kDefaultTargetEnv, spvtools::fuzz::fuzzerutil::kSilentMessageConsumer,
-          binary.data(), binary.size());
-    });
-  }
+    std::vector<spvtools::fuzz::fuzzerutil::ModuleSupplier> result;
+    for (std::string donor_file_name; fin >> donor_file_name;) {
+        if (!std::ifstream(donor_file_name)) {
+            std::cout << "Can't open donor file: " << donor_file_name << std::endl;
+            exit(1);
+        }
 
-  return result;
+        result.emplace_back([donor_file_name] {
+            std::vector<uint32_t> binary;
+            if (!util::ReadBinary(donor_file_name, &binary)) {
+                std::cout << "Failed to read donor from: " << donor_file_name << std::endl;
+                exit(1);
+            }
+            return spvtools::BuildModule(kDefaultTargetEnv,
+                                         spvtools::fuzz::fuzzerutil::kSilentMessageConsumer,
+                                         binary.data(), binary.size());
+        });
+    }
+
+    return result;
 }
 
-bool ParseRepeatedPassStrategy(const char* param,
-                               spvtools::fuzz::RepeatedPassStrategy* out) {
-  if (!strcmp(param, "simple")) {
-    *out = spvtools::fuzz::RepeatedPassStrategy::kSimple;
-  } else if (!strcmp(param, "looped")) {
-    *out = spvtools::fuzz::RepeatedPassStrategy::kLoopedWithRecommendations;
-  } else if (!strcmp(param, "random")) {
-    *out = spvtools::fuzz::RepeatedPassStrategy::kRandomWithRecommendations;
-  } else {
-    return false;
-  }
-  return true;
+bool ParseRepeatedPassStrategy(const char* param, spvtools::fuzz::RepeatedPassStrategy* out) {
+    if (!strcmp(param, "simple")) {
+        *out = spvtools::fuzz::RepeatedPassStrategy::kSimple;
+    } else if (!strcmp(param, "looped")) {
+        *out = spvtools::fuzz::RepeatedPassStrategy::kLoopedWithRecommendations;
+    } else if (!strcmp(param, "random")) {
+        *out = spvtools::fuzz::RepeatedPassStrategy::kRandomWithRecommendations;
+    } else {
+        return false;
+    }
+    return true;
 }
 
 bool ParseBool(const char* param, bool* out) {
-  if (!strcmp(param, "true")) {
-    *out = true;
-  } else if (!strcmp(param, "false")) {
-    *out = false;
-  } else {
-    return false;
-  }
-  return true;
+    if (!strcmp(param, "true")) {
+        *out = true;
+    } else if (!strcmp(param, "false")) {
+        *out = false;
+    } else {
+        return false;
+    }
+    return true;
 }
 
 bool ParseMutatorType(const char* param, MutatorType* out) {
-  if (!strcmp(param, "fuzz")) {
-    *out = MutatorType::kFuzz;
-  } else if (!strcmp(param, "opt")) {
-    *out = MutatorType::kOpt;
-  } else if (!strcmp(param, "reduce")) {
-    *out = MutatorType::kReduce;
-  } else {
-    return false;
-  }
-  return true;
+    if (!strcmp(param, "fuzz")) {
+        *out = MutatorType::kFuzz;
+    } else if (!strcmp(param, "opt")) {
+        *out = MutatorType::kOpt;
+    } else if (!strcmp(param, "reduce")) {
+        *out = MutatorType::kReduce;
+    } else {
+        return false;
+    }
+    return true;
 }
 
 bool ParseFuzzingTarget(const char* param, FuzzingTarget* out) {
-  if (!strcmp(param, "wgsl")) {
-    *out = FuzzingTarget::kWgsl;
-  } else if (!strcmp(param, "spv")) {
-    *out = FuzzingTarget::kSpv;
-  } else if (!strcmp(param, "msl")) {
-    *out = FuzzingTarget::kMsl;
-  } else if (!strcmp(param, "hlsl")) {
-    *out = FuzzingTarget::kHlsl;
-  } else {
-    return false;
-  }
-  return true;
+    if (!strcmp(param, "wgsl")) {
+        *out = FuzzingTarget::kWgsl;
+    } else if (!strcmp(param, "spv")) {
+        *out = FuzzingTarget::kSpv;
+    } else if (!strcmp(param, "msl")) {
+        *out = FuzzingTarget::kMsl;
+    } else if (!strcmp(param, "hlsl")) {
+        *out = FuzzingTarget::kHlsl;
+    } else {
+        return false;
+    }
+    return true;
 }
 
 bool HasPrefix(const char* str, const char* prefix) {
-  return strncmp(str, prefix, strlen(prefix)) == 0;
+    return strncmp(str, prefix, strlen(prefix)) == 0;
 }
 
-bool ParseMutatorCliParam(const char* param,
-                          const char* help_message,
-                          MutatorCliParams* out) {
-  if (HasPrefix(param, "-tint_transformation_batch_size=")) {
-    if (!ParseUint32(param + sizeof("-tint_transformation_batch_size=") - 1,
-                     &out->transformation_batch_size)) {
-      InvalidParameter(help_message, param);
+bool ParseMutatorCliParam(const char* param, const char* help_message, MutatorCliParams* out) {
+    if (HasPrefix(param, "-tint_transformation_batch_size=")) {
+        if (!ParseUint32(param + sizeof("-tint_transformation_batch_size=") - 1,
+                         &out->transformation_batch_size)) {
+            InvalidParameter(help_message, param);
+        }
+    } else if (HasPrefix(param, "-tint_reduction_batch_size=")) {
+        if (!ParseUint32(param + sizeof("-tint_reduction_batch_size=") - 1,
+                         &out->reduction_batch_size)) {
+            InvalidParameter(help_message, param);
+        }
+    } else if (HasPrefix(param, "-tint_opt_batch_size=")) {
+        if (!ParseUint32(param + sizeof("-tint_opt_batch_size=") - 1, &out->opt_batch_size)) {
+            InvalidParameter(help_message, param);
+        }
+    } else if (HasPrefix(param, "-tint_donors=")) {
+        out->donors = ParseDonors(param + sizeof("-tint_donors=") - 1);
+    } else if (HasPrefix(param, "-tint_repeated_pass_strategy=")) {
+        if (!ParseRepeatedPassStrategy(param + sizeof("-tint_repeated_pass_strategy=") - 1,
+                                       &out->repeated_pass_strategy)) {
+            InvalidParameter(help_message, param);
+        }
+    } else if (HasPrefix(param, "-tint_enable_all_fuzzer_passes=")) {
+        if (!ParseBool(param + sizeof("-tint_enable_all_fuzzer_passes=") - 1,
+                       &out->enable_all_fuzzer_passes)) {
+            InvalidParameter(help_message, param);
+        }
+    } else if (HasPrefix(param, "-tint_enable_all_reduce_passes=")) {
+        if (!ParseBool(param + sizeof("-tint_enable_all_reduce_passes=") - 1,
+                       &out->enable_all_reduce_passes)) {
+            InvalidParameter(help_message, param);
+        }
+    } else if (HasPrefix(param, "-tint_validate_after_each_opt_pass=")) {
+        if (!ParseBool(param + sizeof("-tint_validate_after_each_opt_pass=") - 1,
+                       &out->validate_after_each_opt_pass)) {
+            InvalidParameter(help_message, param);
+        }
+    } else if (HasPrefix(param, "-tint_validate_after_each_fuzzer_pass=")) {
+        if (!ParseBool(param + sizeof("-tint_validate_after_each_fuzzer_pass=") - 1,
+                       &out->validate_after_each_fuzzer_pass)) {
+            InvalidParameter(help_message, param);
+        }
+    } else if (HasPrefix(param, "-tint_validate_after_each_reduce_pass=")) {
+        if (!ParseBool(param + sizeof("-tint_validate_after_each_reduce_pass=") - 1,
+                       &out->validate_after_each_reduce_pass)) {
+            InvalidParameter(help_message, param);
+        }
+    } else {
+        return false;
     }
-  } else if (HasPrefix(param, "-tint_reduction_batch_size=")) {
-    if (!ParseUint32(param + sizeof("-tint_reduction_batch_size=") - 1,
-                     &out->reduction_batch_size)) {
-      InvalidParameter(help_message, param);
-    }
-  } else if (HasPrefix(param, "-tint_opt_batch_size=")) {
-    if (!ParseUint32(param + sizeof("-tint_opt_batch_size=") - 1,
-                     &out->opt_batch_size)) {
-      InvalidParameter(help_message, param);
-    }
-  } else if (HasPrefix(param, "-tint_donors=")) {
-    out->donors = ParseDonors(param + sizeof("-tint_donors=") - 1);
-  } else if (HasPrefix(param, "-tint_repeated_pass_strategy=")) {
-    if (!ParseRepeatedPassStrategy(
-            param + sizeof("-tint_repeated_pass_strategy=") - 1,
-            &out->repeated_pass_strategy)) {
-      InvalidParameter(help_message, param);
-    }
-  } else if (HasPrefix(param, "-tint_enable_all_fuzzer_passes=")) {
-    if (!ParseBool(param + sizeof("-tint_enable_all_fuzzer_passes=") - 1,
-                   &out->enable_all_fuzzer_passes)) {
-      InvalidParameter(help_message, param);
-    }
-  } else if (HasPrefix(param, "-tint_enable_all_reduce_passes=")) {
-    if (!ParseBool(param + sizeof("-tint_enable_all_reduce_passes=") - 1,
-                   &out->enable_all_reduce_passes)) {
-      InvalidParameter(help_message, param);
-    }
-  } else if (HasPrefix(param, "-tint_validate_after_each_opt_pass=")) {
-    if (!ParseBool(param + sizeof("-tint_validate_after_each_opt_pass=") - 1,
-                   &out->validate_after_each_opt_pass)) {
-      InvalidParameter(help_message, param);
-    }
-  } else if (HasPrefix(param, "-tint_validate_after_each_fuzzer_pass=")) {
-    if (!ParseBool(param + sizeof("-tint_validate_after_each_fuzzer_pass=") - 1,
-                   &out->validate_after_each_fuzzer_pass)) {
-      InvalidParameter(help_message, param);
-    }
-  } else if (HasPrefix(param, "-tint_validate_after_each_reduce_pass=")) {
-    if (!ParseBool(param + sizeof("-tint_validate_after_each_reduce_pass=") - 1,
-                   &out->validate_after_each_reduce_pass)) {
-      InvalidParameter(help_message, param);
-    }
-  } else {
-    return false;
-  }
-  return true;
+    return true;
 }
 
 }  // namespace
 
 FuzzerCliParams ParseFuzzerCliParams(int* argc, char** argv) {
-  FuzzerCliParams cli_params;
-  const auto* help_message = kFuzzerHelpMessage;
-  auto help = false;
+    FuzzerCliParams cli_params;
+    const auto* help_message = kFuzzerHelpMessage;
+    auto help = false;
 
-  for (int i = *argc - 1; i > 0; --i) {
-    auto param = argv[i];
-    auto recognized_param = true;
+    for (int i = *argc - 1; i > 0; --i) {
+        auto param = argv[i];
+        auto recognized_param = true;
 
-    if (HasPrefix(param, "-tint_mutator_cache_size=")) {
-      if (!ParseUint32(param + sizeof("-tint_mutator_cache_size=") - 1,
-                       &cli_params.mutator_cache_size)) {
-        InvalidParameter(help_message, param);
-      }
-    } else if (HasPrefix(param, "-tint_mutator_type=")) {
-      auto result = MutatorType::kNone;
+        if (HasPrefix(param, "-tint_mutator_cache_size=")) {
+            if (!ParseUint32(param + sizeof("-tint_mutator_cache_size=") - 1,
+                             &cli_params.mutator_cache_size)) {
+                InvalidParameter(help_message, param);
+            }
+        } else if (HasPrefix(param, "-tint_mutator_type=")) {
+            auto result = MutatorType::kNone;
 
-      std::stringstream ss(param + sizeof("-tint_mutator_type=") - 1);
-      for (std::string value; std::getline(ss, value, ',');) {
-        auto out = MutatorType::kNone;
-        if (!ParseMutatorType(value.c_str(), &out)) {
-          InvalidParameter(help_message, param);
+            std::stringstream ss(param + sizeof("-tint_mutator_type=") - 1);
+            for (std::string value; std::getline(ss, value, ',');) {
+                auto out = MutatorType::kNone;
+                if (!ParseMutatorType(value.c_str(), &out)) {
+                    InvalidParameter(help_message, param);
+                }
+                result = result | out;
+            }
+
+            if (result == MutatorType::kNone) {
+                InvalidParameter(help_message, param);
+            }
+
+            cli_params.mutator_type = result;
+        } else if (HasPrefix(param, "-tint_fuzzing_target=")) {
+            auto result = FuzzingTarget::kNone;
+
+            std::stringstream ss(param + sizeof("-tint_fuzzing_target=") - 1);
+            for (std::string value; std::getline(ss, value, ',');) {
+                auto tmp = FuzzingTarget::kNone;
+                if (!ParseFuzzingTarget(value.c_str(), &tmp)) {
+                    InvalidParameter(help_message, param);
+                }
+                result = result | tmp;
+            }
+
+            if (result == FuzzingTarget::kNone) {
+                InvalidParameter(help_message, param);
+            }
+
+            cli_params.fuzzing_target = result;
+        } else if (HasPrefix(param, "-tint_error_dir=")) {
+            cli_params.error_dir = param + sizeof("-tint_error_dir=") - 1;
+        } else if (!strcmp(param, "-tint_help")) {
+            help = true;
+        } else {
+            recognized_param =
+                ParseMutatorCliParam(param, help_message, &cli_params.mutator_params);
         }
-        result = result | out;
-      }
 
-      if (result == MutatorType::kNone) {
-        InvalidParameter(help_message, param);
-      }
-
-      cli_params.mutator_type = result;
-    } else if (HasPrefix(param, "-tint_fuzzing_target=")) {
-      auto result = FuzzingTarget::kNone;
-
-      std::stringstream ss(param + sizeof("-tint_fuzzing_target=") - 1);
-      for (std::string value; std::getline(ss, value, ',');) {
-        auto tmp = FuzzingTarget::kNone;
-        if (!ParseFuzzingTarget(value.c_str(), &tmp)) {
-          InvalidParameter(help_message, param);
+        if (recognized_param) {
+            // Remove the recognized parameter from the list of all parameters by
+            // swapping it with the last one. This will suppress warnings in the
+            // libFuzzer about unrecognized parameters. By default, libFuzzer thinks
+            // that all user-defined parameters start with two dashes. However, we are
+            // forced to use a single one to make the fuzzer compatible with the
+            // ClusterFuzz.
+            std::swap(argv[i], argv[*argc - 1]);
+            *argc -= 1;
         }
-        result = result | tmp;
-      }
-
-      if (result == FuzzingTarget::kNone) {
-        InvalidParameter(help_message, param);
-      }
-
-      cli_params.fuzzing_target = result;
-    } else if (HasPrefix(param, "-tint_error_dir=")) {
-      cli_params.error_dir = param + sizeof("-tint_error_dir=") - 1;
-    } else if (!strcmp(param, "-tint_help")) {
-      help = true;
-    } else {
-      recognized_param =
-          ParseMutatorCliParam(param, help_message, &cli_params.mutator_params);
     }
 
-    if (recognized_param) {
-      // Remove the recognized parameter from the list of all parameters by
-      // swapping it with the last one. This will suppress warnings in the
-      // libFuzzer about unrecognized parameters. By default, libFuzzer thinks
-      // that all user-defined parameters start with two dashes. However, we are
-      // forced to use a single one to make the fuzzer compatible with the
-      // ClusterFuzz.
-      std::swap(argv[i], argv[*argc - 1]);
-      *argc -= 1;
+    if (help) {
+        PrintHelpMessage(help_message);
+        exit(0);
     }
-  }
 
-  if (help) {
-    PrintHelpMessage(help_message);
-    exit(0);
-  }
-
-  return cli_params;
+    return cli_params;
 }
 
-MutatorDebuggerCliParams ParseMutatorDebuggerCliParams(
-    int argc,
-    const char* const* argv) {
-  MutatorDebuggerCliParams cli_params;
-  bool seed_param_present = false;
-  bool original_binary_param_present = false;
-  bool mutator_type_param_present = false;
-  const auto* help_message = kMutatorDebuggerHelpMessage;
-  auto help = false;
+MutatorDebuggerCliParams ParseMutatorDebuggerCliParams(int argc, const char* const* argv) {
+    MutatorDebuggerCliParams cli_params;
+    bool seed_param_present = false;
+    bool original_binary_param_present = false;
+    bool mutator_type_param_present = false;
+    const auto* help_message = kMutatorDebuggerHelpMessage;
+    auto help = false;
 
-  for (int i = 0; i < argc; ++i) {
-    auto param = argv[i];
-    ParseMutatorCliParam(param, help_message, &cli_params.mutator_params);
+    for (int i = 0; i < argc; ++i) {
+        auto param = argv[i];
+        ParseMutatorCliParam(param, help_message, &cli_params.mutator_params);
 
-    if (HasPrefix(param, "--mutator_type=")) {
-      if (!ParseMutatorType(param + sizeof("--mutator_type=") - 1,
-                            &cli_params.mutator_type)) {
-        InvalidParameter(help_message, param);
-      }
-      mutator_type_param_present = true;
-    } else if (HasPrefix(param, "--original_binary=")) {
-      if (!util::ReadBinary(param + sizeof("--original_binary=") - 1,
-                            &cli_params.original_binary)) {
-        InvalidParameter(help_message, param);
-      }
-      original_binary_param_present = true;
-    } else if (HasPrefix(param, "--seed=")) {
-      if (!ParseUint32(param + sizeof("--seed=") - 1, &cli_params.seed)) {
-        InvalidParameter(help_message, param);
-      }
-      seed_param_present = true;
-    } else if (!strcmp(param, "--help")) {
-      help = true;
+        if (HasPrefix(param, "--mutator_type=")) {
+            if (!ParseMutatorType(param + sizeof("--mutator_type=") - 1,
+                                  &cli_params.mutator_type)) {
+                InvalidParameter(help_message, param);
+            }
+            mutator_type_param_present = true;
+        } else if (HasPrefix(param, "--original_binary=")) {
+            if (!util::ReadBinary(param + sizeof("--original_binary=") - 1,
+                                  &cli_params.original_binary)) {
+                InvalidParameter(help_message, param);
+            }
+            original_binary_param_present = true;
+        } else if (HasPrefix(param, "--seed=")) {
+            if (!ParseUint32(param + sizeof("--seed=") - 1, &cli_params.seed)) {
+                InvalidParameter(help_message, param);
+            }
+            seed_param_present = true;
+        } else if (!strcmp(param, "--help")) {
+            help = true;
+        }
     }
-  }
 
-  if (help) {
-    PrintHelpMessage(help_message);
-    exit(0);
-  }
-
-  std::pair<bool, const char*> required_params[] = {
-      {seed_param_present, "--seed"},
-      {original_binary_param_present, "--original_binary"},
-      {mutator_type_param_present, "--mutator_type"}};
-
-  for (auto required_param : required_params) {
-    if (!required_param.first) {
-      std::cout << required_param.second << " is missing" << std::endl;
-      exit(1);
+    if (help) {
+        PrintHelpMessage(help_message);
+        exit(0);
     }
-  }
 
-  return cli_params;
+    std::pair<bool, const char*> required_params[] = {
+        {seed_param_present, "--seed"},
+        {original_binary_param_present, "--original_binary"},
+        {mutator_type_param_present, "--mutator_type"}};
+
+    for (auto required_param : required_params) {
+        if (!required_param.first) {
+            std::cout << required_param.second << " is missing" << std::endl;
+            exit(1);
+        }
+    }
+
+    return cli_params;
 }
 
 }  // namespace tint::fuzzers::spvtools_fuzzer
diff --git a/src/tint/fuzzers/tint_spirv_tools_fuzzer/cli.h b/src/tint/fuzzers/tint_spirv_tools_fuzzer/cli.h
index 2ab26c6..c10c1a7 100644
--- a/src/tint/fuzzers/tint_spirv_tools_fuzzer/cli.h
+++ b/src/tint/fuzzers/tint_spirv_tools_fuzzer/cli.h
@@ -27,112 +27,112 @@
 
 /// The type of the mutator to run.
 enum class MutatorType {
-  kNone = 0,
-  kFuzz = 1 << 0,
-  kReduce = 1 << 1,
-  kOpt = 1 << 2,
-  kAll = kFuzz | kReduce | kOpt
+    kNone = 0,
+    kFuzz = 1 << 0,
+    kReduce = 1 << 1,
+    kOpt = 1 << 2,
+    kAll = kFuzz | kReduce | kOpt
 };
 
 inline MutatorType operator|(MutatorType a, MutatorType b) {
-  return static_cast<MutatorType>(static_cast<int>(a) | static_cast<int>(b));
+    return static_cast<MutatorType>(static_cast<int>(a) | static_cast<int>(b));
 }
 
 inline MutatorType operator&(MutatorType a, MutatorType b) {
-  return static_cast<MutatorType>(static_cast<int>(a) & static_cast<int>(b));
+    return static_cast<MutatorType>(static_cast<int>(a) & static_cast<int>(b));
 }
 
 /// Shading language to target during fuzzing.
 enum class FuzzingTarget {
-  kNone = 0,
-  kHlsl = 1 << 0,
-  kMsl = 1 << 1,
-  kSpv = 1 << 2,
-  kWgsl = 1 << 3,
-  kAll = kHlsl | kMsl | kSpv | kWgsl
+    kNone = 0,
+    kHlsl = 1 << 0,
+    kMsl = 1 << 1,
+    kSpv = 1 << 2,
+    kWgsl = 1 << 3,
+    kAll = kHlsl | kMsl | kSpv | kWgsl
 };
 
 inline FuzzingTarget operator|(FuzzingTarget a, FuzzingTarget b) {
-  return static_cast<FuzzingTarget>(static_cast<int>(a) | static_cast<int>(b));
+    return static_cast<FuzzingTarget>(static_cast<int>(a) | static_cast<int>(b));
 }
 
 inline FuzzingTarget operator&(FuzzingTarget a, FuzzingTarget b) {
-  return static_cast<FuzzingTarget>(static_cast<int>(a) & static_cast<int>(b));
+    return static_cast<FuzzingTarget>(static_cast<int>(a) & static_cast<int>(b));
 }
 
 /// These parameters are accepted by various mutators and thus they are accepted
 /// by both the fuzzer and the mutator debugger.
 struct MutatorCliParams {
-  /// SPIR-V target environment for fuzzing.
-  spv_target_env target_env = kDefaultTargetEnv;
+    /// SPIR-V target environment for fuzzing.
+    spv_target_env target_env = kDefaultTargetEnv;
 
-  /// The number of spirv-fuzz transformations to apply at a time.
-  uint32_t transformation_batch_size = 3;
+    /// The number of spirv-fuzz transformations to apply at a time.
+    uint32_t transformation_batch_size = 3;
 
-  /// The number of spirv-reduce reductions to apply at a time.
-  uint32_t reduction_batch_size = 3;
+    /// The number of spirv-reduce reductions to apply at a time.
+    uint32_t reduction_batch_size = 3;
 
-  /// The number of spirv-opt optimizations to apply at a time.
-  uint32_t opt_batch_size = 6;
+    /// The number of spirv-opt optimizations to apply at a time.
+    uint32_t opt_batch_size = 6;
 
-  /// The vector of donors to use in spirv-fuzz (see the doc for spirv-fuzz to
-  /// learn more).
-  std::vector<spvtools::fuzz::fuzzerutil::ModuleSupplier> donors = {};
+    /// The vector of donors to use in spirv-fuzz (see the doc for spirv-fuzz to
+    /// learn more).
+    std::vector<spvtools::fuzz::fuzzerutil::ModuleSupplier> donors = {};
 
-  /// The strategy to use during fuzzing in spirv-fuzz (see the doc for
-  /// spirv-fuzz to learn more).
-  spvtools::fuzz::RepeatedPassStrategy repeated_pass_strategy =
-      spvtools::fuzz::RepeatedPassStrategy::kSimple;
+    /// The strategy to use during fuzzing in spirv-fuzz (see the doc for
+    /// spirv-fuzz to learn more).
+    spvtools::fuzz::RepeatedPassStrategy repeated_pass_strategy =
+        spvtools::fuzz::RepeatedPassStrategy::kSimple;
 
-  /// Whether to use all fuzzer passes or a randomly selected subset of them.
-  bool enable_all_fuzzer_passes = false;
+    /// Whether to use all fuzzer passes or a randomly selected subset of them.
+    bool enable_all_fuzzer_passes = false;
 
-  /// Whether to use all reduction passes or a randomly selected subset of them.
-  bool enable_all_reduce_passes = false;
+    /// Whether to use all reduction passes or a randomly selected subset of them.
+    bool enable_all_reduce_passes = false;
 
-  /// Whether to validate the SPIR-V binary after each optimization pass.
-  bool validate_after_each_opt_pass = true;
+    /// Whether to validate the SPIR-V binary after each optimization pass.
+    bool validate_after_each_opt_pass = true;
 
-  /// Whether to validate the SPIR-V binary after each fuzzer pass.
-  bool validate_after_each_fuzzer_pass = true;
+    /// Whether to validate the SPIR-V binary after each fuzzer pass.
+    bool validate_after_each_fuzzer_pass = true;
 
-  /// Whether to validate the SPIR-V binary after each reduction pass.
-  bool validate_after_each_reduce_pass = true;
+    /// Whether to validate the SPIR-V binary after each reduction pass.
+    bool validate_after_each_reduce_pass = true;
 };
 
 /// Parameters specific to the fuzzer. Type `-tint_help` in the CLI to learn
 /// more.
 struct FuzzerCliParams {
-  /// The size of the cache that records ongoing mutation sessions.
-  uint32_t mutator_cache_size = 20;
+    /// The size of the cache that records ongoing mutation sessions.
+    uint32_t mutator_cache_size = 20;
 
-  /// The type of the mutator to run.
-  MutatorType mutator_type = MutatorType::kAll;
+    /// The type of the mutator to run.
+    MutatorType mutator_type = MutatorType::kAll;
 
-  /// Tint backend to fuzz.
-  FuzzingTarget fuzzing_target = FuzzingTarget::kAll;
+    /// Tint backend to fuzz.
+    FuzzingTarget fuzzing_target = FuzzingTarget::kAll;
 
-  /// The path to the directory, that will be used to output buggy shaders.
-  std::string error_dir = "";
+    /// The path to the directory, that will be used to output buggy shaders.
+    std::string error_dir = "";
 
-  /// Parameters for various mutators.
-  MutatorCliParams mutator_params;
+    /// Parameters for various mutators.
+    MutatorCliParams mutator_params;
 };
 
 /// Parameters specific to the mutator debugger. Type `--help` in the CLI to
 /// learn more.
 struct MutatorDebuggerCliParams {
-  /// The type of the mutator to debug.
-  MutatorType mutator_type = MutatorType::kNone;
+    /// The type of the mutator to debug.
+    MutatorType mutator_type = MutatorType::kNone;
 
-  /// The seed that was used to initialize the mutator.
-  uint32_t seed = 0;
+    /// The seed that was used to initialize the mutator.
+    uint32_t seed = 0;
 
-  /// The binary that triggered a bug in the mutator.
-  std::vector<uint32_t> original_binary;
+    /// The binary that triggered a bug in the mutator.
+    std::vector<uint32_t> original_binary;
 
-  /// Parameters for various mutators.
-  MutatorCliParams mutator_params;
+    /// Parameters for various mutators.
+    MutatorCliParams mutator_params;
 };
 
 /// Parses CLI parameters for the fuzzer. This function exits with an error code
@@ -155,8 +155,7 @@
 ///     function).
 /// @param argv - array of C strings of parameters.
 /// @return the parsed parameters.
-MutatorDebuggerCliParams ParseMutatorDebuggerCliParams(int argc,
-                                                       const char* const* argv);
+MutatorDebuggerCliParams ParseMutatorDebuggerCliParams(int argc, const char* const* argv);
 
 }  // namespace tint::fuzzers::spvtools_fuzzer
 
diff --git a/src/tint/fuzzers/tint_spirv_tools_fuzzer/fuzzer.cc b/src/tint/fuzzers/tint_spirv_tools_fuzzer/fuzzer.cc
index dd2e9d3..c35e0ce 100644
--- a/src/tint/fuzzers/tint_spirv_tools_fuzzer/fuzzer.cc
+++ b/src/tint/fuzzers/tint_spirv_tools_fuzzer/fuzzer.cc
@@ -32,227 +32,216 @@
 namespace {
 
 struct Context {
-  FuzzerCliParams params;
-  std::unique_ptr<MutatorCache> mutator_cache;
+    FuzzerCliParams params;
+    std::unique_ptr<MutatorCache> mutator_cache;
 };
 
 Context* context = nullptr;
 
 extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) {
-  auto params = ParseFuzzerCliParams(argc, *argv);
-  auto mutator_cache =
-      params.mutator_cache_size
-          ? std::make_unique<MutatorCache>(params.mutator_cache_size)
-          : nullptr;
-  context = new Context{std::move(params), std::move(mutator_cache)};
-  OverrideCliParams(context->params);
-  return 0;
+    auto params = ParseFuzzerCliParams(argc, *argv);
+    auto mutator_cache = params.mutator_cache_size
+                             ? std::make_unique<MutatorCache>(params.mutator_cache_size)
+                             : nullptr;
+    context = new Context{std::move(params), std::move(mutator_cache)};
+    OverrideCliParams(context->params);
+    return 0;
 }
 
-std::unique_ptr<Mutator> CreateMutator(const std::vector<uint32_t>& binary,
-                                       unsigned seed) {
-  std::vector<MutatorType> types;
-  types.reserve(3);
+std::unique_ptr<Mutator> CreateMutator(const std::vector<uint32_t>& binary, unsigned seed) {
+    std::vector<MutatorType> types;
+    types.reserve(3);
 
-  // Determine which mutator we will be using for `binary` at random.
-  auto cli_mutator_type = context->params.mutator_type;
-  if ((MutatorType::kFuzz & cli_mutator_type) == MutatorType::kFuzz) {
-    types.push_back(MutatorType::kFuzz);
-  }
-  if ((MutatorType::kReduce & cli_mutator_type) == MutatorType::kReduce) {
-    types.push_back(MutatorType::kReduce);
-  }
-  if ((MutatorType::kOpt & cli_mutator_type) == MutatorType::kOpt) {
-    types.push_back(MutatorType::kOpt);
-  }
+    // Determine which mutator we will be using for `binary` at random.
+    auto cli_mutator_type = context->params.mutator_type;
+    if ((MutatorType::kFuzz & cli_mutator_type) == MutatorType::kFuzz) {
+        types.push_back(MutatorType::kFuzz);
+    }
+    if ((MutatorType::kReduce & cli_mutator_type) == MutatorType::kReduce) {
+        types.push_back(MutatorType::kReduce);
+    }
+    if ((MutatorType::kOpt & cli_mutator_type) == MutatorType::kOpt) {
+        types.push_back(MutatorType::kOpt);
+    }
 
-  assert(!types.empty() && "At least one mutator type must be specified");
-  RandomGenerator generator(seed);
-  auto mutator_type =
-      types[generator.GetUInt32(static_cast<uint32_t>(types.size()))];
+    assert(!types.empty() && "At least one mutator type must be specified");
+    RandomGenerator generator(seed);
+    auto mutator_type = types[generator.GetUInt32(static_cast<uint32_t>(types.size()))];
 
-  const auto& mutator_params = context->params.mutator_params;
-  switch (mutator_type) {
-    case MutatorType::kFuzz:
-      return std::make_unique<SpirvFuzzMutator>(
-          mutator_params.target_env, binary, seed, mutator_params.donors,
-          mutator_params.enable_all_fuzzer_passes,
-          mutator_params.repeated_pass_strategy,
-          mutator_params.validate_after_each_fuzzer_pass,
-          mutator_params.transformation_batch_size);
-    case MutatorType::kReduce:
-      return std::make_unique<SpirvReduceMutator>(
-          mutator_params.target_env, binary, seed,
-          mutator_params.reduction_batch_size,
-          mutator_params.enable_all_reduce_passes,
-          mutator_params.validate_after_each_reduce_pass);
-    case MutatorType::kOpt:
-      return std::make_unique<SpirvOptMutator>(
-          mutator_params.target_env, seed, binary,
-          mutator_params.validate_after_each_opt_pass,
-          mutator_params.opt_batch_size);
-    default:
-      assert(false && "All mutator types must be handled above");
-      return nullptr;
-  }
+    const auto& mutator_params = context->params.mutator_params;
+    switch (mutator_type) {
+        case MutatorType::kFuzz:
+            return std::make_unique<SpirvFuzzMutator>(
+                mutator_params.target_env, binary, seed, mutator_params.donors,
+                mutator_params.enable_all_fuzzer_passes, mutator_params.repeated_pass_strategy,
+                mutator_params.validate_after_each_fuzzer_pass,
+                mutator_params.transformation_batch_size);
+        case MutatorType::kReduce:
+            return std::make_unique<SpirvReduceMutator>(
+                mutator_params.target_env, binary, seed, mutator_params.reduction_batch_size,
+                mutator_params.enable_all_reduce_passes,
+                mutator_params.validate_after_each_reduce_pass);
+        case MutatorType::kOpt:
+            return std::make_unique<SpirvOptMutator>(mutator_params.target_env, seed, binary,
+                                                     mutator_params.validate_after_each_opt_pass,
+                                                     mutator_params.opt_batch_size);
+        default:
+            assert(false && "All mutator types must be handled above");
+            return nullptr;
+    }
 }
 
 void CLIMessageConsumer(spv_message_level_t level,
                         const char*,
                         const spv_position_t& position,
                         const char* message) {
-  switch (level) {
-    case SPV_MSG_FATAL:
-    case SPV_MSG_INTERNAL_ERROR:
-    case SPV_MSG_ERROR:
-      std::cerr << "error: line " << position.index << ": " << message
-                << std::endl;
-      break;
-    case SPV_MSG_WARNING:
-      std::cout << "warning: line " << position.index << ": " << message
-                << std::endl;
-      break;
-    case SPV_MSG_INFO:
-      std::cout << "info: line " << position.index << ": " << message
-                << std::endl;
-      break;
-    default:
-      break;
-  }
+    switch (level) {
+        case SPV_MSG_FATAL:
+        case SPV_MSG_INTERNAL_ERROR:
+        case SPV_MSG_ERROR:
+            std::cerr << "error: line " << position.index << ": " << message << std::endl;
+            break;
+        case SPV_MSG_WARNING:
+            std::cout << "warning: line " << position.index << ": " << message << std::endl;
+            break;
+        case SPV_MSG_INFO:
+            std::cout << "info: line " << position.index << ": " << message << std::endl;
+            break;
+        default:
+            break;
+    }
 }
 
 bool IsValid(const std::vector<uint32_t>& binary) {
-  spvtools::SpirvTools tools(context->params.mutator_params.target_env);
-  tools.SetMessageConsumer(CLIMessageConsumer);
-  return tools.IsValid() && tools.Validate(binary.data(), binary.size(),
-                                           spvtools::ValidatorOptions());
+    spvtools::SpirvTools tools(context->params.mutator_params.target_env);
+    tools.SetMessageConsumer(CLIMessageConsumer);
+    return tools.IsValid() &&
+           tools.Validate(binary.data(), binary.size(), spvtools::ValidatorOptions());
 }
 
 extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* data,
                                           size_t size,
                                           size_t max_size,
                                           unsigned seed) {
-  if ((size % sizeof(uint32_t)) != 0) {
-    // A valid SPIR-V binary's size must be a multiple of the size of a 32-bit
-    // word, and the SPIR-V Tools fuzzer is only designed to work with valid
-    // binaries.
-    return 0;
-  }
-
-  std::vector<uint32_t> binary(size / sizeof(uint32_t));
-  std::memcpy(binary.data(), data, size);
-
-  MutatorCache placeholder_cache(1);
-  auto* mutator_cache = context->mutator_cache.get();
-  if (!mutator_cache) {
-    // Use a placeholder cache if the user has decided not to use a real cache.
-    // The placeholder cache will be destroyed when we return from this function
-    // but it will save us from writing all the `if (mutator_cache)` below.
-    mutator_cache = &placeholder_cache;
-  }
-
-  if (!mutator_cache->Get(binary)) {
-    // This is an unknown binary, so its validity must be checked before
-    // proceeding.
-    if (!IsValid(binary)) {
-      return 0;
+    if ((size % sizeof(uint32_t)) != 0) {
+        // A valid SPIR-V binary's size must be a multiple of the size of a 32-bit
+        // word, and the SPIR-V Tools fuzzer is only designed to work with valid
+        // binaries.
+        return 0;
     }
-    // Assign a mutator to the binary if it doesn't have one yet.
-    mutator_cache->Put(binary, CreateMutator(binary, seed));
-  }
 
-  auto* mutator = mutator_cache->Get(binary);
-  assert(mutator && "Mutator must be present in the cache");
+    std::vector<uint32_t> binary(size / sizeof(uint32_t));
+    std::memcpy(binary.data(), data, size);
 
-  auto result = mutator->Mutate();
+    MutatorCache placeholder_cache(1);
+    auto* mutator_cache = context->mutator_cache.get();
+    if (!mutator_cache) {
+        // Use a placeholder cache if the user has decided not to use a real cache.
+        // The placeholder cache will be destroyed when we return from this function
+        // but it will save us from writing all the `if (mutator_cache)` below.
+        mutator_cache = &placeholder_cache;
+    }
 
-  if (result.GetStatus() == Mutator::Status::kInvalid) {
-    // The binary is invalid - log the error and remove the mutator from the
-    // cache.
-    util::LogMutatorError(*mutator, context->params.error_dir);
-    mutator_cache->Remove(binary);
-    return 0;
-  }
+    if (!mutator_cache->Get(binary)) {
+        // This is an unknown binary, so its validity must be checked before
+        // proceeding.
+        if (!IsValid(binary)) {
+            return 0;
+        }
+        // Assign a mutator to the binary if it doesn't have one yet.
+        mutator_cache->Put(binary, CreateMutator(binary, seed));
+    }
 
-  if (!result.IsChanged()) {
-    // The mutator didn't change the binary this time. This could be due to the
-    // fact that we've reached the number of mutations we can apply (e.g. the
-    // number of transformations in spirv-fuzz) or the mutator was just unlucky.
-    // Either way, there is no harm in destroying mutator and maybe trying again
-    // later (i.e. if libfuzzer decides to do so).
-    mutator_cache->Remove(binary);
-    return 0;
-  }
+    auto* mutator = mutator_cache->Get(binary);
+    assert(mutator && "Mutator must be present in the cache");
 
-  // At this point the binary is valid and was changed by the mutator.
+    auto result = mutator->Mutate();
 
-  auto mutated = mutator->GetBinary();
-  auto mutated_bytes_size = mutated.size() * sizeof(uint32_t);
-  if (mutated_bytes_size > max_size) {
-    // The binary is too big. It's unlikely that we'll reduce its size by
-    // applying the mutator one more time.
-    mutator_cache->Remove(binary);
-    return 0;
-  }
+    if (result.GetStatus() == Mutator::Status::kInvalid) {
+        // The binary is invalid - log the error and remove the mutator from the
+        // cache.
+        util::LogMutatorError(*mutator, context->params.error_dir);
+        mutator_cache->Remove(binary);
+        return 0;
+    }
 
-  if (result.GetStatus() == Mutator::Status::kComplete) {
-    // Reassign the mutator to the mutated binary in the cache so that we can
-    // access later.
-    mutator_cache->Put(mutated, mutator_cache->Remove(binary));
-  } else {
-    // If the binary is valid and was changed but is not `kComplete`, then the
-    // mutator has reached some limit on the number of mutations.
-    mutator_cache->Remove(binary);
-  }
+    if (!result.IsChanged()) {
+        // The mutator didn't change the binary this time. This could be due to the
+        // fact that we've reached the number of mutations we can apply (e.g. the
+        // number of transformations in spirv-fuzz) or the mutator was just unlucky.
+        // Either way, there is no harm in destroying mutator and maybe trying again
+        // later (i.e. if libfuzzer decides to do so).
+        mutator_cache->Remove(binary);
+        return 0;
+    }
 
-  std::memcpy(data, mutated.data(), mutated_bytes_size);
-  return mutated_bytes_size;
+    // At this point the binary is valid and was changed by the mutator.
+
+    auto mutated = mutator->GetBinary();
+    auto mutated_bytes_size = mutated.size() * sizeof(uint32_t);
+    if (mutated_bytes_size > max_size) {
+        // The binary is too big. It's unlikely that we'll reduce its size by
+        // applying the mutator one more time.
+        mutator_cache->Remove(binary);
+        return 0;
+    }
+
+    if (result.GetStatus() == Mutator::Status::kComplete) {
+        // Reassign the mutator to the mutated binary in the cache so that we can
+        // access later.
+        mutator_cache->Put(mutated, mutator_cache->Remove(binary));
+    } else {
+        // If the binary is valid and was changed but is not `kComplete`, then the
+        // mutator has reached some limit on the number of mutations.
+        mutator_cache->Remove(binary);
+    }
+
+    std::memcpy(data, mutated.data(), mutated_bytes_size);
+    return mutated_bytes_size;
 }
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  if (size == 0) {
-    return 0;
-  }
-
-  if ((size % sizeof(uint32_t)) != 0) {
-    // The SPIR-V Tools fuzzer has been designed to work with valid
-    // SPIR-V binaries, whose sizes should be multiples of the size of a 32-bit
-    // word.
-    return 0;
-  }
-
-  CommonFuzzer spv_to_wgsl(InputFormat::kSpv, OutputFormat::kWGSL);
-  spv_to_wgsl.Run(data, size);
-  if (spv_to_wgsl.HasErrors()) {
-    auto error = spv_to_wgsl.Diagnostics().str();
-    util::LogSpvError(error, data, size,
-                      context ? context->params.error_dir : "");
-    return 0;
-  }
-
-  const auto& wgsl = spv_to_wgsl.GetGeneratedWgsl();
-
-  std::pair<FuzzingTarget, OutputFormat> targets[] = {
-      {FuzzingTarget::kHlsl, OutputFormat::kHLSL},
-      {FuzzingTarget::kMsl, OutputFormat::kMSL},
-      {FuzzingTarget::kSpv, OutputFormat::kSpv},
-      {FuzzingTarget::kWgsl, OutputFormat::kWGSL}};
-
-  for (auto target : targets) {
-    if ((target.first & context->params.fuzzing_target) != target.first) {
-      continue;
+    if (size == 0) {
+        return 0;
     }
 
-    CommonFuzzer fuzzer(InputFormat::kWGSL, target.second);
-    fuzzer.Run(reinterpret_cast<const uint8_t*>(wgsl.data()), wgsl.size());
-    if (fuzzer.HasErrors()) {
-      auto error = spv_to_wgsl.Diagnostics().str();
-      util::LogWgslError(error, data, size, wgsl, target.second,
-                         context->params.error_dir);
+    if ((size % sizeof(uint32_t)) != 0) {
+        // The SPIR-V Tools fuzzer has been designed to work with valid
+        // SPIR-V binaries, whose sizes should be multiples of the size of a 32-bit
+        // word.
+        return 0;
     }
-  }
 
-  return 0;
+    CommonFuzzer spv_to_wgsl(InputFormat::kSpv, OutputFormat::kWGSL);
+    spv_to_wgsl.Run(data, size);
+    if (spv_to_wgsl.HasErrors()) {
+        auto error = spv_to_wgsl.Diagnostics().str();
+        util::LogSpvError(error, data, size, context ? context->params.error_dir : "");
+        return 0;
+    }
+
+    const auto& wgsl = spv_to_wgsl.GetGeneratedWgsl();
+
+    std::pair<FuzzingTarget, OutputFormat> targets[] = {
+        {FuzzingTarget::kHlsl, OutputFormat::kHLSL},
+        {FuzzingTarget::kMsl, OutputFormat::kMSL},
+        {FuzzingTarget::kSpv, OutputFormat::kSpv},
+        {FuzzingTarget::kWgsl, OutputFormat::kWGSL}};
+
+    for (auto target : targets) {
+        if ((target.first & context->params.fuzzing_target) != target.first) {
+            continue;
+        }
+
+        CommonFuzzer fuzzer(InputFormat::kWGSL, target.second);
+        fuzzer.Run(reinterpret_cast<const uint8_t*>(wgsl.data()), wgsl.size());
+        if (fuzzer.HasErrors()) {
+            auto error = spv_to_wgsl.Diagnostics().str();
+            util::LogWgslError(error, data, size, wgsl, target.second, context->params.error_dir);
+        }
+    }
+
+    return 0;
 }
 
 }  // namespace
diff --git a/src/tint/fuzzers/tint_spirv_tools_fuzzer/mutator.cc b/src/tint/fuzzers/tint_spirv_tools_fuzzer/mutator.cc
index cba5e52..241143f 100644
--- a/src/tint/fuzzers/tint_spirv_tools_fuzzer/mutator.cc
+++ b/src/tint/fuzzers/tint_spirv_tools_fuzzer/mutator.cc
@@ -20,11 +20,9 @@
 // translation unit (see -Wweak-vtables clang flag).
 Mutator::~Mutator() = default;
 
-Mutator::Result::Result(Status status, bool is_changed)
-    : status_(status), is_changed_(is_changed) {
-  assert((is_changed || status == Status::kStuck ||
-          status == Status::kLimitReached) &&
-         "Returning invalid result state");
+Mutator::Result::Result(Status status, bool is_changed) : status_(status), is_changed_(is_changed) {
+    assert((is_changed || status == Status::kStuck || status == Status::kLimitReached) &&
+           "Returning invalid result state");
 }
 
 }  // namespace tint::fuzzers::spvtools_fuzzer
diff --git a/src/tint/fuzzers/tint_spirv_tools_fuzzer/mutator.h b/src/tint/fuzzers/tint_spirv_tools_fuzzer/mutator.h
index faee9b7..1e81dff 100644
--- a/src/tint/fuzzers/tint_spirv_tools_fuzzer/mutator.h
+++ b/src/tint/fuzzers/tint_spirv_tools_fuzzer/mutator.h
@@ -25,78 +25,78 @@
 /// This is an interface that is used to define custom mutators based on the
 /// SPIR-V tools.
 class Mutator {
- public:
-  /// The status of the mutation.
-  enum class Status {
-    /// Binary is valid, the limit is not reached - can mutate further.
-    kComplete,
+  public:
+    /// The status of the mutation.
+    enum class Status {
+        /// Binary is valid, the limit is not reached - can mutate further.
+        kComplete,
 
-    /// The binary is valid, the limit of mutations has been reached -
-    /// can't mutate further.
-    kLimitReached,
+        /// The binary is valid, the limit of mutations has been reached -
+        /// can't mutate further.
+        kLimitReached,
 
-    /// The binary is valid, the limit is not reached but the mutator has spent
-    /// too much time without mutating anything - better to restart to make sure
-    /// we can make any progress.
-    kStuck,
+        /// The binary is valid, the limit is not reached but the mutator has spent
+        /// too much time without mutating anything - better to restart to make sure
+        /// we can make any progress.
+        kStuck,
 
-    /// The binary is invalid - this is likely a bug in the mutator - must
-    /// abort.
-    kInvalid
-  };
+        /// The binary is invalid - this is likely a bug in the mutator - must
+        /// abort.
+        kInvalid
+    };
 
-  /// Represents the result of the mutation. The following states are possible:
-  /// - if `IsChanged() == false`, then `GetStatus()` can be either
-  ///   `kLimitReached` or `kStuck`.
-  /// - otherwise, any value of `Status` is possible.
-  class Result {
-   public:
-    /// Constructor.
-    /// @param status - the status of the mutation.
-    /// @param is_changed - whether the module was changed during mutation.
-    Result(Status status, bool is_changed);
+    /// Represents the result of the mutation. The following states are possible:
+    /// - if `IsChanged() == false`, then `GetStatus()` can be either
+    ///   `kLimitReached` or `kStuck`.
+    /// - otherwise, any value of `Status` is possible.
+    class Result {
+      public:
+        /// Constructor.
+        /// @param status - the status of the mutation.
+        /// @param is_changed - whether the module was changed during mutation.
+        Result(Status status, bool is_changed);
 
-    /// @return the status of the mutation.
-    Status GetStatus() const { return status_; }
+        /// @return the status of the mutation.
+        Status GetStatus() const { return status_; }
 
-    /// @return whether the module was changed during mutation.
-    bool IsChanged() const { return is_changed_; }
+        /// @return whether the module was changed during mutation.
+        bool IsChanged() const { return is_changed_; }
 
-   private:
-    Status status_;
-    bool is_changed_;
-  };
+      private:
+        Status status_;
+        bool is_changed_;
+    };
 
-  /// Virtual destructor.
-  virtual ~Mutator();
+    /// Virtual destructor.
+    virtual ~Mutator();
 
-  /// Causes the mutator to apply a mutation. This method can be called
-  /// multiple times as long as the previous call didn't return
-  /// `Status::kInvalid`.
-  ///
-  /// @return the status of the mutation (e.g. success, error etc) and whether
-  ///     the binary was changed during mutation.
-  virtual Result Mutate() = 0;
+    /// Causes the mutator to apply a mutation. This method can be called
+    /// multiple times as long as the previous call didn't return
+    /// `Status::kInvalid`.
+    ///
+    /// @return the status of the mutation (e.g. success, error etc) and whether
+    ///     the binary was changed during mutation.
+    virtual Result Mutate() = 0;
 
-  /// Returns the mutated binary. The returned binary is guaranteed to be valid
-  /// iff the previous call to the `Mutate` method returned didn't return
-  /// `Status::kInvalid`.
-  ///
-  /// @return the mutated SPIR-V binary. It might be identical to the original
-  ///     binary if `Result::IsChanged` returns `false`.
-  virtual std::vector<uint32_t> GetBinary() const = 0;
+    /// Returns the mutated binary. The returned binary is guaranteed to be valid
+    /// iff the previous call to the `Mutate` method returned didn't return
+    /// `Status::kInvalid`.
+    ///
+    /// @return the mutated SPIR-V binary. It might be identical to the original
+    ///     binary if `Result::IsChanged` returns `false`.
+    virtual std::vector<uint32_t> GetBinary() const = 0;
 
-  /// Returns errors, produced by the mutator.
-  ///
-  /// @param path - the directory to which the errors are printed to. No files
-  ///     are created if the `path` is nullptr.
-  /// @param count - the number of the error. Files for this error will be
-  ///     prefixed with `count`.
-  virtual void LogErrors(const std::string* path, uint32_t count) const = 0;
+    /// Returns errors, produced by the mutator.
+    ///
+    /// @param path - the directory to which the errors are printed to. No files
+    ///     are created if the `path` is nullptr.
+    /// @param count - the number of the error. Files for this error will be
+    ///     prefixed with `count`.
+    virtual void LogErrors(const std::string* path, uint32_t count) const = 0;
 
-  /// @return errors encountered during the mutation. The returned string is
-  ///     if there were no errors during mutation.
-  virtual std::string GetErrors() const = 0;
+    /// @return errors encountered during the mutation. The returned string is
+    ///     if there were no errors during mutation.
+    virtual std::string GetErrors() const = 0;
 };
 
 }  // namespace tint::fuzzers::spvtools_fuzzer
diff --git a/src/tint/fuzzers/tint_spirv_tools_fuzzer/mutator_cache.cc b/src/tint/fuzzers/tint_spirv_tools_fuzzer/mutator_cache.cc
index 82afcce..b85bdc1 100644
--- a/src/tint/fuzzers/tint_spirv_tools_fuzzer/mutator_cache.cc
+++ b/src/tint/fuzzers/tint_spirv_tools_fuzzer/mutator_cache.cc
@@ -16,59 +16,57 @@
 
 namespace tint::fuzzers::spvtools_fuzzer {
 
-MutatorCache::MutatorCache(size_t max_size)
-    : map_(), entries_(), max_size_(max_size) {
-  assert(max_size && "`max_size` may not be 0");
+MutatorCache::MutatorCache(size_t max_size) : map_(), entries_(), max_size_(max_size) {
+    assert(max_size && "`max_size` may not be 0");
 }
 
 MutatorCache::Value::pointer MutatorCache::Get(const Key& key) {
-  auto it = map_.find(key);
-  if (it == map_.end()) {
-    return nullptr;
-  }
-  UpdateUsage(it);
-  return entries_.front().second.get();
+    auto it = map_.find(key);
+    if (it == map_.end()) {
+        return nullptr;
+    }
+    UpdateUsage(it);
+    return entries_.front().second.get();
 }
 
 void MutatorCache::Put(const Key& key, Value value) {
-  assert(value && "Mutator cache can't have nullptr unique_ptr");
-  auto it = map_.find(key);
-  if (it != map_.end()) {
-    it->second->second = std::move(value);
-    UpdateUsage(it);
-  } else {
-    if (map_.size() == max_size_) {
-      Remove(*entries_.back().first);
-    }
+    assert(value && "Mutator cache can't have nullptr unique_ptr");
+    auto it = map_.find(key);
+    if (it != map_.end()) {
+        it->second->second = std::move(value);
+        UpdateUsage(it);
+    } else {
+        if (map_.size() == max_size_) {
+            Remove(*entries_.back().first);
+        }
 
-    entries_.emplace_front(nullptr, std::move(value));
-    auto pair = map_.emplace(key, entries_.begin());
-    assert(pair.second && "The key must be unique");
-    entries_.front().first = &pair.first->first;
-  }
+        entries_.emplace_front(nullptr, std::move(value));
+        auto pair = map_.emplace(key, entries_.begin());
+        assert(pair.second && "The key must be unique");
+        entries_.front().first = &pair.first->first;
+    }
 }
 
 MutatorCache::Value MutatorCache::Remove(const Key& key) {
-  auto it = map_.find(key);
-  if (it == map_.end()) {
-    return nullptr;
-  }
-  auto result = std::move(it->second->second);
-  entries_.erase(it->second);
-  map_.erase(it);
-  return result;
+    auto it = map_.find(key);
+    if (it == map_.end()) {
+        return nullptr;
+    }
+    auto result = std::move(it->second->second);
+    entries_.erase(it->second);
+    map_.erase(it);
+    return result;
 }
 
-size_t MutatorCache::KeyHash::operator()(
-    const std::vector<uint32_t>& vec) const {
-  return std::hash<std::u32string>()({vec.begin(), vec.end()});
+size_t MutatorCache::KeyHash::operator()(const std::vector<uint32_t>& vec) const {
+    return std::hash<std::u32string>()({vec.begin(), vec.end()});
 }
 
 void MutatorCache::UpdateUsage(Map::iterator it) {
-  auto entry = std::move(*it->second);
-  entries_.erase(it->second);
-  entries_.push_front(std::move(entry));
-  it->second = entries_.begin();
+    auto entry = std::move(*it->second);
+    entries_.erase(it->second);
+    entries_.push_front(std::move(entry));
+    it->second = entries_.begin();
 }
 
 }  // namespace tint::fuzzers::spvtools_fuzzer
diff --git a/src/tint/fuzzers/tint_spirv_tools_fuzzer/mutator_cache.h b/src/tint/fuzzers/tint_spirv_tools_fuzzer/mutator_cache.h
index b8e7cd8..cf9b148 100644
--- a/src/tint/fuzzers/tint_spirv_tools_fuzzer/mutator_cache.h
+++ b/src/tint/fuzzers/tint_spirv_tools_fuzzer/mutator_cache.h
@@ -31,63 +31,63 @@
 /// longest period of time is removed from the cache when a new element is
 /// inserted. All operations have amortized constant time complexity.
 class MutatorCache {
- public:
-  /// SPIR-V binary that is being mutated.
-  using Key = std::vector<uint32_t>;
+  public:
+    /// SPIR-V binary that is being mutated.
+    using Key = std::vector<uint32_t>;
 
-  /// Mutator that is used to mutate the `Key`.
-  using Value = std::unique_ptr<Mutator>;
+    /// Mutator that is used to mutate the `Key`.
+    using Value = std::unique_ptr<Mutator>;
 
-  /// Constructor.
-  /// @param max_size - the maximum number of elements the cache can store. May
-  ///     not be equal to 0.
-  explicit MutatorCache(size_t max_size);
+    /// Constructor.
+    /// @param max_size - the maximum number of elements the cache can store. May
+    ///     not be equal to 0.
+    explicit MutatorCache(size_t max_size);
 
-  /// Retrieves a pointer to a value, associated with a given `key`.
-  ///
-  /// If the key is present in the cache, its usage is updated and the
-  /// (non-null) pointer to the value is returned. Otherwise, `nullptr` is
-  /// returned.
-  ///
-  /// @param key - may not exist in this cache.
-  /// @return non-`nullptr` pointer to a value if `key` exists in the cache.
-  /// @return `nullptr` if `key` doesn't exist in this cache.
-  Value::pointer Get(const Key& key);
+    /// Retrieves a pointer to a value, associated with a given `key`.
+    ///
+    /// If the key is present in the cache, its usage is updated and the
+    /// (non-null) pointer to the value is returned. Otherwise, `nullptr` is
+    /// returned.
+    ///
+    /// @param key - may not exist in this cache.
+    /// @return non-`nullptr` pointer to a value if `key` exists in the cache.
+    /// @return `nullptr` if `key` doesn't exist in this cache.
+    Value::pointer Get(const Key& key);
 
-  /// Inserts a `key`-`value` pair into the cache.
-  ///
-  /// If the `key` is already present, the `value` replaces the old value and
-  /// the usage of `key` is updated. If the `key` is not present, then:
-  /// - if the number of elements in the cache is equal to `max_size`, the
-  ///   key-value pair, where the usage of the key wasn't updated for the
-  ///   longest period of time, is removed from the cache.
-  /// - a new `key`-`value` pair is inserted into the cache.
-  ///
-  /// @param key - a key.
-  /// @param value - may not be a `nullptr`.
-  void Put(const Key& key, Value value);
+    /// Inserts a `key`-`value` pair into the cache.
+    ///
+    /// If the `key` is already present, the `value` replaces the old value and
+    /// the usage of `key` is updated. If the `key` is not present, then:
+    /// - if the number of elements in the cache is equal to `max_size`, the
+    ///   key-value pair, where the usage of the key wasn't updated for the
+    ///   longest period of time, is removed from the cache.
+    /// - a new `key`-`value` pair is inserted into the cache.
+    ///
+    /// @param key - a key.
+    /// @param value - may not be a `nullptr`.
+    void Put(const Key& key, Value value);
 
-  /// Removes `key` and an associated value from the cache.
-  ///
-  /// @param key - a key.
-  /// @return a non-`nullptr` pointer to the removed value, associated with
-  ///     `key`.
-  /// @return `nullptr` if `key` is not present in the cache.
-  Value Remove(const Key& key);
+    /// Removes `key` and an associated value from the cache.
+    ///
+    /// @param key - a key.
+    /// @return a non-`nullptr` pointer to the removed value, associated with
+    ///     `key`.
+    /// @return `nullptr` if `key` is not present in the cache.
+    Value Remove(const Key& key);
 
- private:
-  struct KeyHash {
-    size_t operator()(const std::vector<uint32_t>& vec) const;
-  };
+  private:
+    struct KeyHash {
+        size_t operator()(const std::vector<uint32_t>& vec) const;
+    };
 
-  using Entry = std::pair<const Key*, Value>;
-  using Map = std::unordered_map<Key, std::list<Entry>::iterator, KeyHash>;
+    using Entry = std::pair<const Key*, Value>;
+    using Map = std::unordered_map<Key, std::list<Entry>::iterator, KeyHash>;
 
-  void UpdateUsage(Map::iterator it);
+    void UpdateUsage(Map::iterator it);
 
-  Map map_;
-  std::list<Entry> entries_;
-  const size_t max_size_;
+    Map map_;
+    std::list<Entry> entries_;
+    const size_t max_size_;
 };
 
 }  // namespace tint::fuzzers::spvtools_fuzzer
diff --git a/src/tint/fuzzers/tint_spirv_tools_fuzzer/mutator_debugger.cc b/src/tint/fuzzers/tint_spirv_tools_fuzzer/mutator_debugger.cc
index aaa85fa..d8d6550 100644
--- a/src/tint/fuzzers/tint_spirv_tools_fuzzer/mutator_debugger.cc
+++ b/src/tint/fuzzers/tint_spirv_tools_fuzzer/mutator_debugger.cc
@@ -34,51 +34,43 @@
 /// tool is useful when one of the spirv-tools mutators crashes or produces an
 /// invalid binary in LLVMFuzzerCustomMutator.
 int main(int argc, const char** argv) {
-  auto params =
-      tint::fuzzers::spvtools_fuzzer::ParseMutatorDebuggerCliParams(argc, argv);
+    auto params = tint::fuzzers::spvtools_fuzzer::ParseMutatorDebuggerCliParams(argc, argv);
 
-  std::unique_ptr<tint::fuzzers::spvtools_fuzzer::Mutator> mutator;
-  const auto& mutator_params = params.mutator_params;
-  switch (params.mutator_type) {
-    case tint::fuzzers::spvtools_fuzzer::MutatorType::kFuzz:
-      mutator =
-          std::make_unique<tint::fuzzers::spvtools_fuzzer::SpirvFuzzMutator>(
-              mutator_params.target_env, params.original_binary, params.seed,
-              mutator_params.donors, mutator_params.enable_all_fuzzer_passes,
-              mutator_params.repeated_pass_strategy,
-              mutator_params.validate_after_each_fuzzer_pass,
-              mutator_params.transformation_batch_size);
-      break;
-    case tint::fuzzers::spvtools_fuzzer::MutatorType::kReduce:
-      mutator =
-          std::make_unique<tint::fuzzers::spvtools_fuzzer::SpirvReduceMutator>(
-              mutator_params.target_env, params.original_binary, params.seed,
-              mutator_params.reduction_batch_size,
-              mutator_params.enable_all_reduce_passes,
-              mutator_params.validate_after_each_reduce_pass);
-      break;
-    case tint::fuzzers::spvtools_fuzzer::MutatorType::kOpt:
-      mutator =
-          std::make_unique<tint::fuzzers::spvtools_fuzzer::SpirvOptMutator>(
-              mutator_params.target_env, params.seed, params.original_binary,
-              mutator_params.validate_after_each_opt_pass,
-              mutator_params.opt_batch_size);
-      break;
-    default:
-      assert(false && "All mutator types must've been handled");
-      return 1;
-  }
+    std::unique_ptr<tint::fuzzers::spvtools_fuzzer::Mutator> mutator;
+    const auto& mutator_params = params.mutator_params;
+    switch (params.mutator_type) {
+        case tint::fuzzers::spvtools_fuzzer::MutatorType::kFuzz:
+            mutator = std::make_unique<tint::fuzzers::spvtools_fuzzer::SpirvFuzzMutator>(
+                mutator_params.target_env, params.original_binary, params.seed,
+                mutator_params.donors, mutator_params.enable_all_fuzzer_passes,
+                mutator_params.repeated_pass_strategy,
+                mutator_params.validate_after_each_fuzzer_pass,
+                mutator_params.transformation_batch_size);
+            break;
+        case tint::fuzzers::spvtools_fuzzer::MutatorType::kReduce:
+            mutator = std::make_unique<tint::fuzzers::spvtools_fuzzer::SpirvReduceMutator>(
+                mutator_params.target_env, params.original_binary, params.seed,
+                mutator_params.reduction_batch_size, mutator_params.enable_all_reduce_passes,
+                mutator_params.validate_after_each_reduce_pass);
+            break;
+        case tint::fuzzers::spvtools_fuzzer::MutatorType::kOpt:
+            mutator = std::make_unique<tint::fuzzers::spvtools_fuzzer::SpirvOptMutator>(
+                mutator_params.target_env, params.seed, params.original_binary,
+                mutator_params.validate_after_each_opt_pass, mutator_params.opt_batch_size);
+            break;
+        default:
+            assert(false && "All mutator types must've been handled");
+            return 1;
+    }
 
-  while (true) {
-    auto result = mutator->Mutate();
-    if (result.GetStatus() ==
-        tint::fuzzers::spvtools_fuzzer::Mutator::Status::kInvalid) {
-      std::cerr << mutator->GetErrors() << std::endl;
-      return 0;
+    while (true) {
+        auto result = mutator->Mutate();
+        if (result.GetStatus() == tint::fuzzers::spvtools_fuzzer::Mutator::Status::kInvalid) {
+            std::cerr << mutator->GetErrors() << std::endl;
+            return 0;
+        }
+        if (result.GetStatus() == tint::fuzzers::spvtools_fuzzer::Mutator::Status::kLimitReached) {
+            break;
+        }
     }
-    if (result.GetStatus() ==
-        tint::fuzzers::spvtools_fuzzer::Mutator::Status::kLimitReached) {
-      break;
-    }
-  }
 }
diff --git a/src/tint/fuzzers/tint_spirv_tools_fuzzer/spirv_fuzz_mutator.cc b/src/tint/fuzzers/tint_spirv_tools_fuzzer/spirv_fuzz_mutator.cc
index ea2f89e..b726ec3 100644
--- a/src/tint/fuzzers/tint_spirv_tools_fuzzer/spirv_fuzz_mutator.cc
+++ b/src/tint/fuzzers/tint_spirv_tools_fuzzer/spirv_fuzz_mutator.cc
@@ -37,87 +37,80 @@
       validator_options_(),
       original_binary_(std::move(binary)),
       seed_(seed) {
-  auto ir_context = spvtools::BuildModule(
-      target_env, spvtools::fuzz::fuzzerutil::kSilentMessageConsumer,
-      original_binary_.data(), original_binary_.size());
-  assert(ir_context && "|binary| is invalid");
+    auto ir_context =
+        spvtools::BuildModule(target_env, spvtools::fuzz::fuzzerutil::kSilentMessageConsumer,
+                              original_binary_.data(), original_binary_.size());
+    assert(ir_context && "|binary| is invalid");
 
-  auto transformation_context =
-      std::make_unique<spvtools::fuzz::TransformationContext>(
-          std::make_unique<spvtools::fuzz::FactManager>(ir_context.get()),
-          validator_options_);
+    auto transformation_context = std::make_unique<spvtools::fuzz::TransformationContext>(
+        std::make_unique<spvtools::fuzz::FactManager>(ir_context.get()), validator_options_);
 
-  auto fuzzer_context = std::make_unique<spvtools::fuzz::FuzzerContext>(
-      std::make_unique<spvtools::fuzz::PseudoRandomGenerator>(seed),
-      spvtools::fuzz::FuzzerContext::GetMinFreshId(ir_context.get()), false);
-  fuzzer_ = std::make_unique<spvtools::fuzz::Fuzzer>(
-      std::move(ir_context), std::move(transformation_context),
-      std::move(fuzzer_context), util::GetBufferMessageConsumer(errors_.get()),
-      donors, enable_all_passes, repeated_pass_strategy,
-      validate_after_each_pass, validator_options_);
+    auto fuzzer_context = std::make_unique<spvtools::fuzz::FuzzerContext>(
+        std::make_unique<spvtools::fuzz::PseudoRandomGenerator>(seed),
+        spvtools::fuzz::FuzzerContext::GetMinFreshId(ir_context.get()), false);
+    fuzzer_ = std::make_unique<spvtools::fuzz::Fuzzer>(
+        std::move(ir_context), std::move(transformation_context), std::move(fuzzer_context),
+        util::GetBufferMessageConsumer(errors_.get()), donors, enable_all_passes,
+        repeated_pass_strategy, validate_after_each_pass, validator_options_);
 }
 
 Mutator::Result SpirvFuzzMutator::Mutate() {
-  // The assertion will fail in |fuzzer_->Run| if the previous fuzzing led to
-  // invalid module.
-  auto result = fuzzer_->Run(transformation_batch_size_);
-  switch (result.status) {
-    case spvtools::fuzz::Fuzzer::Status::kComplete:
-      return {Mutator::Status::kComplete, result.is_changed};
-    case spvtools::fuzz::Fuzzer::Status::kModuleTooBig:
-    case spvtools::fuzz::Fuzzer::Status::kTransformationLimitReached:
-      return {Mutator::Status::kLimitReached, result.is_changed};
-    case spvtools::fuzz::Fuzzer::Status::kFuzzerStuck:
-      return {Mutator::Status::kStuck, result.is_changed};
-    case spvtools::fuzz::Fuzzer::Status::kFuzzerPassLedToInvalidModule:
-      return {Mutator::Status::kInvalid, result.is_changed};
-  }
+    // The assertion will fail in |fuzzer_->Run| if the previous fuzzing led to
+    // invalid module.
+    auto result = fuzzer_->Run(transformation_batch_size_);
+    switch (result.status) {
+        case spvtools::fuzz::Fuzzer::Status::kComplete:
+            return {Mutator::Status::kComplete, result.is_changed};
+        case spvtools::fuzz::Fuzzer::Status::kModuleTooBig:
+        case spvtools::fuzz::Fuzzer::Status::kTransformationLimitReached:
+            return {Mutator::Status::kLimitReached, result.is_changed};
+        case spvtools::fuzz::Fuzzer::Status::kFuzzerStuck:
+            return {Mutator::Status::kStuck, result.is_changed};
+        case spvtools::fuzz::Fuzzer::Status::kFuzzerPassLedToInvalidModule:
+            return {Mutator::Status::kInvalid, result.is_changed};
+    }
 }
 
 std::vector<uint32_t> SpirvFuzzMutator::GetBinary() const {
-  std::vector<uint32_t> result;
-  fuzzer_->GetIRContext()->module()->ToBinary(&result, true);
-  return result;
+    std::vector<uint32_t> result;
+    fuzzer_->GetIRContext()->module()->ToBinary(&result, true);
+    return result;
 }
 
 std::string SpirvFuzzMutator::GetErrors() const {
-  return errors_->str();
+    return errors_->str();
 }
 
-void SpirvFuzzMutator::LogErrors(const std::string* path,
-                                 uint32_t count) const {
-  auto message = GetErrors();
-  std::cout << count << " | SpirvFuzzMutator (seed: " << seed_ << ")"
-            << std::endl;
-  std::cout << message << std::endl;
+void SpirvFuzzMutator::LogErrors(const std::string* path, uint32_t count) const {
+    auto message = GetErrors();
+    std::cout << count << " | SpirvFuzzMutator (seed: " << seed_ << ")" << std::endl;
+    std::cout << message << std::endl;
 
-  if (path) {
-    auto prefix = *path + std::to_string(count);
+    if (path) {
+        auto prefix = *path + std::to_string(count);
 
-    // Write errors to file.
-    std::ofstream(prefix + ".fuzzer.log") << "seed: " << seed_ << std::endl
-                                          << message << std::endl;
+        // Write errors to file.
+        std::ofstream(prefix + ".fuzzer.log") << "seed: " << seed_ << std::endl
+                                              << message << std::endl;
 
-    // Write the invalid SPIR-V binary.
-    util::WriteBinary(prefix + ".fuzzer.invalid.spv", GetBinary());
+        // Write the invalid SPIR-V binary.
+        util::WriteBinary(prefix + ".fuzzer.invalid.spv", GetBinary());
 
-    // Write the original SPIR-V binary.
-    util::WriteBinary(prefix + ".fuzzer.original.spv", original_binary_);
+        // Write the original SPIR-V binary.
+        util::WriteBinary(prefix + ".fuzzer.original.spv", original_binary_);
 
-    // Write transformations.
-    google::protobuf::util::JsonOptions options;
-    options.add_whitespace = true;
-    std::string json;
-    google::protobuf::util::MessageToJsonString(
-        fuzzer_->GetTransformationSequence(), &json, options);
-    std::ofstream(prefix + ".fuzzer.transformations.json") << json << std::endl;
+        // Write transformations.
+        google::protobuf::util::JsonOptions options;
+        options.add_whitespace = true;
+        std::string json;
+        google::protobuf::util::MessageToJsonString(fuzzer_->GetTransformationSequence(), &json,
+                                                    options);
+        std::ofstream(prefix + ".fuzzer.transformations.json") << json << std::endl;
 
-    std::ofstream binary_transformations(
-        prefix + ".fuzzer.transformations.binary",
-        std::ios::binary | std::ios::out);
-    fuzzer_->GetTransformationSequence().SerializeToOstream(
-        &binary_transformations);
-  }
+        std::ofstream binary_transformations(prefix + ".fuzzer.transformations.binary",
+                                             std::ios::binary | std::ios::out);
+        fuzzer_->GetTransformationSequence().SerializeToOstream(&binary_transformations);
+    }
 }
 
 }  // namespace tint::fuzzers::spvtools_fuzzer
diff --git a/src/tint/fuzzers/tint_spirv_tools_fuzzer/spirv_fuzz_mutator.h b/src/tint/fuzzers/tint_spirv_tools_fuzzer/spirv_fuzz_mutator.h
index 1db79f4..1f94111 100644
--- a/src/tint/fuzzers/tint_spirv_tools_fuzzer/spirv_fuzz_mutator.h
+++ b/src/tint/fuzzers/tint_spirv_tools_fuzzer/spirv_fuzz_mutator.h
@@ -34,56 +34,55 @@
 /// parameters (except for the `seed` which just initializes the RNG) are from
 /// the `spvtools::fuzz::Fuzzer` class.
 class SpirvFuzzMutator : public Mutator {
- public:
-  /// Constructor.
-  /// @param target_env - the target environment for the `binary`.
-  /// @param binary - the SPIR-V binary. Must be valid.
-  /// @param seed - seed for the RNG.
-  /// @param donors - vector of donor suppliers.
-  /// @param enable_all_passes - whether to use all fuzzer passes.
-  /// @param repeated_pass_strategy - the strategy to use when selecting the
-  ///     next fuzzer pass.
-  /// @param validate_after_each_pass - whether to validate the binary after
-  ///     each fuzzer pass.
-  /// @param transformation_batch_size - the maximum number of transformations
-  ///     that will be applied during a single call to `Mutate`. It it's equal
-  ///     to 0 then we apply as much transformations as we can until the
-  ///     threshold in the spvtools::fuzz::Fuzzer is reached (see the doc for
-  ///     that class for more info).
-  SpirvFuzzMutator(
-      spv_target_env target_env,
-      std::vector<uint32_t> binary,
-      uint32_t seed,
-      const std::vector<spvtools::fuzz::fuzzerutil::ModuleSupplier>& donors,
-      bool enable_all_passes,
-      spvtools::fuzz::RepeatedPassStrategy repeated_pass_strategy,
-      bool validate_after_each_pass,
-      uint32_t transformation_batch_size);
+  public:
+    /// Constructor.
+    /// @param target_env - the target environment for the `binary`.
+    /// @param binary - the SPIR-V binary. Must be valid.
+    /// @param seed - seed for the RNG.
+    /// @param donors - vector of donor suppliers.
+    /// @param enable_all_passes - whether to use all fuzzer passes.
+    /// @param repeated_pass_strategy - the strategy to use when selecting the
+    ///     next fuzzer pass.
+    /// @param validate_after_each_pass - whether to validate the binary after
+    ///     each fuzzer pass.
+    /// @param transformation_batch_size - the maximum number of transformations
+    ///     that will be applied during a single call to `Mutate`. It it's equal
+    ///     to 0 then we apply as much transformations as we can until the
+    ///     threshold in the spvtools::fuzz::Fuzzer is reached (see the doc for
+    ///     that class for more info).
+    SpirvFuzzMutator(spv_target_env target_env,
+                     std::vector<uint32_t> binary,
+                     uint32_t seed,
+                     const std::vector<spvtools::fuzz::fuzzerutil::ModuleSupplier>& donors,
+                     bool enable_all_passes,
+                     spvtools::fuzz::RepeatedPassStrategy repeated_pass_strategy,
+                     bool validate_after_each_pass,
+                     uint32_t transformation_batch_size);
 
-  Result Mutate() override;
-  std::vector<uint32_t> GetBinary() const override;
-  void LogErrors(const std::string* path, uint32_t count) const override;
-  std::string GetErrors() const override;
+    Result Mutate() override;
+    std::vector<uint32_t> GetBinary() const override;
+    void LogErrors(const std::string* path, uint32_t count) const override;
+    std::string GetErrors() const override;
 
- private:
-  // The number of transformations that will be applied during a single call to
-  // the `Mutate` method. Is this only a lower bound since transformations are
-  // applied in batches by fuzzer passes (see docs for the
-  // `spvtools::fuzz::Fuzzer` for more info).
-  const uint32_t transformation_batch_size_;
+  private:
+    // The number of transformations that will be applied during a single call to
+    // the `Mutate` method. Is this only a lower bound since transformations are
+    // applied in batches by fuzzer passes (see docs for the
+    // `spvtools::fuzz::Fuzzer` for more info).
+    const uint32_t transformation_batch_size_;
 
-  // The errors produced by the `spvtools::fuzz::Fuzzer`.
-  std::unique_ptr<std::stringstream> errors_;
-  std::unique_ptr<spvtools::fuzz::Fuzzer> fuzzer_;
-  spvtools::ValidatorOptions validator_options_;
+    // The errors produced by the `spvtools::fuzz::Fuzzer`.
+    std::unique_ptr<std::stringstream> errors_;
+    std::unique_ptr<spvtools::fuzz::Fuzzer> fuzzer_;
+    spvtools::ValidatorOptions validator_options_;
 
-  // The following fields are useful for debugging.
+    // The following fields are useful for debugging.
 
-  // The binary that the mutator is constructed with.
-  const std::vector<uint32_t> original_binary_;
+    // The binary that the mutator is constructed with.
+    const std::vector<uint32_t> original_binary_;
 
-  // The seed that the mutator is constructed with.
-  const uint32_t seed_;
+    // The seed that the mutator is constructed with.
+    const uint32_t seed_;
 };
 
 }  // namespace tint::fuzzers::spvtools_fuzzer
diff --git a/src/tint/fuzzers/tint_spirv_tools_fuzzer/spirv_opt_mutator.cc b/src/tint/fuzzers/tint_spirv_tools_fuzzer/spirv_opt_mutator.cc
index 0c375aa..22fc517 100644
--- a/src/tint/fuzzers/tint_spirv_tools_fuzzer/spirv_opt_mutator.cc
+++ b/src/tint/fuzzers/tint_spirv_tools_fuzzer/spirv_opt_mutator.cc
@@ -65,91 +65,89 @@
       validate_after_each_opt_(validate_after_each_opt),
       opt_batch_size_(opt_batch_size),
       generator_(seed) {
-  assert(spvtools::SpirvTools(target_env).Validate(original_binary_) &&
-         "Initial binary is invalid");
-  assert(!opt_passes_.empty() && "Must be at least one pass");
+    assert(spvtools::SpirvTools(target_env).Validate(original_binary_) &&
+           "Initial binary is invalid");
+    assert(!opt_passes_.empty() && "Must be at least one pass");
 }
 
 SpirvOptMutator::Result SpirvOptMutator::Mutate() {
-  assert(is_valid_ && "The optimizer is not longer valid");
+    assert(is_valid_ && "The optimizer is not longer valid");
 
-  const uint32_t kMaxNumExecutions = 100;
-  const uint32_t kMaxNumStuck = 10;
+    const uint32_t kMaxNumExecutions = 100;
+    const uint32_t kMaxNumStuck = 10;
 
-  if (num_executions_ == kMaxNumExecutions) {
-    // We've applied this mutator many times already. Indicate to the user that
-    // it might be better to try a different mutator.
-    return {Status::kLimitReached, false};
-  }
-
-  num_executions_++;
-
-  // Get the input binary. If this is the first time we run this mutator, use
-  // the `original_binary_`. Otherwise, one of the following will be true:
-  // - the `optimized_binary_` is not empty.
-  // - the previous call to the `Mutate` method returned `kStuck`.
-  auto binary = num_executions_ == 1 ? original_binary_ : optimized_binary_;
-  optimized_binary_.clear();
-
-  assert(!binary.empty() && "Can't run the optimizer on an empty binary");
-
-  // Number of times spirv-opt wasn't able to produce any new result.
-  uint32_t num_stuck = 0;
-  do {
-    // Randomly select `opt_batch_size` optimization passes. If `opt_batch_size`
-    // is equal to 0, we will use the number of passes equal to the number of
-    // all available passes.
-    auto num_of_passes = opt_batch_size_ ? opt_batch_size_ : opt_passes_.size();
-    std::vector<std::string> passes;
-
-    while (passes.size() < num_of_passes) {
-      auto idx =
-          generator_.GetUInt32(static_cast<uint32_t>(opt_passes_.size()));
-      passes.push_back(opt_passes_[idx]);
+    if (num_executions_ == kMaxNumExecutions) {
+        // We've applied this mutator many times already. Indicate to the user that
+        // it might be better to try a different mutator.
+        return {Status::kLimitReached, false};
     }
 
-    // Run the `binary` into the `optimized_binary_`.
-    spvtools::Optimizer optimizer(target_env_);
-    optimizer.SetMessageConsumer(util::GetBufferMessageConsumer(&errors_));
-    optimizer.SetValidateAfterAll(validate_after_each_opt_);
-    optimizer.RegisterPassesFromFlags(passes);
-    if (!optimizer.Run(binary.data(), binary.size(), &optimized_binary_)) {
-      is_valid_ = false;
-      return {Status::kInvalid, true};
-    }
-  } while (optimized_binary_.empty() && ++num_stuck < kMaxNumStuck);
+    num_executions_++;
 
-  return {optimized_binary_.empty() ? Status::kStuck : Status::kComplete,
-          !optimized_binary_.empty()};
+    // Get the input binary. If this is the first time we run this mutator, use
+    // the `original_binary_`. Otherwise, one of the following will be true:
+    // - the `optimized_binary_` is not empty.
+    // - the previous call to the `Mutate` method returned `kStuck`.
+    auto binary = num_executions_ == 1 ? original_binary_ : optimized_binary_;
+    optimized_binary_.clear();
+
+    assert(!binary.empty() && "Can't run the optimizer on an empty binary");
+
+    // Number of times spirv-opt wasn't able to produce any new result.
+    uint32_t num_stuck = 0;
+    do {
+        // Randomly select `opt_batch_size` optimization passes. If `opt_batch_size`
+        // is equal to 0, we will use the number of passes equal to the number of
+        // all available passes.
+        auto num_of_passes = opt_batch_size_ ? opt_batch_size_ : opt_passes_.size();
+        std::vector<std::string> passes;
+
+        while (passes.size() < num_of_passes) {
+            auto idx = generator_.GetUInt32(static_cast<uint32_t>(opt_passes_.size()));
+            passes.push_back(opt_passes_[idx]);
+        }
+
+        // Run the `binary` into the `optimized_binary_`.
+        spvtools::Optimizer optimizer(target_env_);
+        optimizer.SetMessageConsumer(util::GetBufferMessageConsumer(&errors_));
+        optimizer.SetValidateAfterAll(validate_after_each_opt_);
+        optimizer.RegisterPassesFromFlags(passes);
+        if (!optimizer.Run(binary.data(), binary.size(), &optimized_binary_)) {
+            is_valid_ = false;
+            return {Status::kInvalid, true};
+        }
+    } while (optimized_binary_.empty() && ++num_stuck < kMaxNumStuck);
+
+    return {optimized_binary_.empty() ? Status::kStuck : Status::kComplete,
+            !optimized_binary_.empty()};
 }
 
 std::vector<uint32_t> SpirvOptMutator::GetBinary() const {
-  return optimized_binary_;
+    return optimized_binary_;
 }
 
 std::string SpirvOptMutator::GetErrors() const {
-  return errors_.str();
+    return errors_.str();
 }
 
 void SpirvOptMutator::LogErrors(const std::string* path, uint32_t count) const {
-  auto message = GetErrors();
-  std::cout << count << " | SpirvOptMutator (seed: " << seed_ << ")"
-            << std::endl;
-  std::cout << message << std::endl;
+    auto message = GetErrors();
+    std::cout << count << " | SpirvOptMutator (seed: " << seed_ << ")" << std::endl;
+    std::cout << message << std::endl;
 
-  if (path) {
-    auto prefix = *path + std::to_string(count);
+    if (path) {
+        auto prefix = *path + std::to_string(count);
 
-    // Write errors to file.
-    std::ofstream(prefix + ".opt.log") << "seed: " << seed_ << std::endl
-                                       << message << std::endl;
+        // Write errors to file.
+        std::ofstream(prefix + ".opt.log") << "seed: " << seed_ << std::endl
+                                           << message << std::endl;
 
-    // Write the invalid SPIR-V binary.
-    util::WriteBinary(prefix + ".opt.invalid.spv", optimized_binary_);
+        // Write the invalid SPIR-V binary.
+        util::WriteBinary(prefix + ".opt.invalid.spv", optimized_binary_);
 
-    // Write the original SPIR-V binary.
-    util::WriteBinary(prefix + ".opt.original.spv", original_binary_);
-  }
+        // Write the original SPIR-V binary.
+        util::WriteBinary(prefix + ".opt.original.spv", original_binary_);
+    }
 }
 
 }  // namespace tint::fuzzers::spvtools_fuzzer
diff --git a/src/tint/fuzzers/tint_spirv_tools_fuzzer/spirv_opt_mutator.h b/src/tint/fuzzers/tint_spirv_tools_fuzzer/spirv_opt_mutator.h
index bb2c047..b8e15f0 100644
--- a/src/tint/fuzzers/tint_spirv_tools_fuzzer/spirv_opt_mutator.h
+++ b/src/tint/fuzzers/tint_spirv_tools_fuzzer/spirv_opt_mutator.h
@@ -31,60 +31,60 @@
 /// to the `Mutate` method the mutator selects `opt_batch_size` random
 /// optimization passes (with substitutions) and applies them to the binary.
 class SpirvOptMutator : public Mutator {
- public:
-  /// Constructor.
-  /// @param target_env - target environment for the `binary`.
-  /// @param seed - seed for the RNG.
-  /// @param binary - SPIR-V binary. Must be valid.
-  /// @param validate_after_each_opt - whether to validate the binary after each
-  ///     optimization pass.
-  /// @param opt_batch_size - the maximum number of optimization passes that
-  ///     will be applied in a single call to `Mutate`. If it's equal to 0 then
-  ///     all available optimization passes are applied.
-  SpirvOptMutator(spv_target_env target_env,
-                  uint32_t seed,
-                  std::vector<uint32_t> binary,
-                  bool validate_after_each_opt,
-                  uint32_t opt_batch_size);
+  public:
+    /// Constructor.
+    /// @param target_env - target environment for the `binary`.
+    /// @param seed - seed for the RNG.
+    /// @param binary - SPIR-V binary. Must be valid.
+    /// @param validate_after_each_opt - whether to validate the binary after each
+    ///     optimization pass.
+    /// @param opt_batch_size - the maximum number of optimization passes that
+    ///     will be applied in a single call to `Mutate`. If it's equal to 0 then
+    ///     all available optimization passes are applied.
+    SpirvOptMutator(spv_target_env target_env,
+                    uint32_t seed,
+                    std::vector<uint32_t> binary,
+                    bool validate_after_each_opt,
+                    uint32_t opt_batch_size);
 
-  Result Mutate() override;
-  std::vector<uint32_t> GetBinary() const override;
-  void LogErrors(const std::string* path, uint32_t count) const override;
-  std::string GetErrors() const override;
+    Result Mutate() override;
+    std::vector<uint32_t> GetBinary() const override;
+    void LogErrors(const std::string* path, uint32_t count) const override;
+    std::string GetErrors() const override;
 
- private:
-  // Number of times this mutator was executed.
-  uint32_t num_executions_;
+  private:
+    // Number of times this mutator was executed.
+    uint32_t num_executions_;
 
-  // Whether the last execution left it in a valid state.
-  bool is_valid_;
+    // Whether the last execution left it in a valid state.
+    bool is_valid_;
 
-  // Target environment for the SPIR-V binary.
-  const spv_target_env target_env_;
+    // Target environment for the SPIR-V binary.
+    const spv_target_env target_env_;
 
-  // The original SPIR-V binary. Useful for debugging.
-  const std::vector<uint32_t> original_binary_;
+    // The original SPIR-V binary. Useful for debugging.
+    const std::vector<uint32_t> original_binary_;
 
-  // The seed for the RNG. Useful for debugging.
-  const uint32_t seed_;
+    // The seed for the RNG. Useful for debugging.
+    const uint32_t seed_;
 
-  // All the optimization passes available.
-  const std::vector<std::string> opt_passes_;
+    // All the optimization passes available.
+    const std::vector<std::string> opt_passes_;
 
-  // The result of the optimization.
-  std::vector<uint32_t> optimized_binary_;
+    // The result of the optimization.
+    std::vector<uint32_t> optimized_binary_;
 
-  // Whether we need to validate the binary after each optimization pass.
-  const bool validate_after_each_opt_;
+    // Whether we need to validate the binary after each optimization pass.
+    const bool validate_after_each_opt_;
 
-  // The number of optimization passes to apply at once.
-  const uint32_t opt_batch_size_;
+    // The number of optimization passes to apply at once.
+    const uint32_t opt_batch_size_;
 
-  // All the errors produced by the optimizer.
-  std::stringstream errors_;
+    // All the errors produced by the optimizer.
+    std::stringstream errors_;
 
-  // The random number generator initialized with `seed_`.
-  RandomGenerator generator_;
+    // The random number generator initialized with `seed_`.
+    RandomGenerator generator_;
 };
 
 }  // namespace tint::fuzzers::spvtools_fuzzer
diff --git a/src/tint/fuzzers/tint_spirv_tools_fuzzer/spirv_reduce_mutator.cc b/src/tint/fuzzers/tint_spirv_tools_fuzzer/spirv_reduce_mutator.cc
index 07b3e9e..221799c 100644
--- a/src/tint/fuzzers/tint_spirv_tools_fuzzer/spirv_reduce_mutator.cc
+++ b/src/tint/fuzzers/tint_spirv_tools_fuzzer/spirv_reduce_mutator.cc
@@ -51,136 +51,120 @@
       validate_after_each_reduction_(validate_after_each_reduction),
       original_binary_(std::move(binary)),
       seed_(seed) {
-  ir_context_ = spvtools::BuildModule(
-      target_env, spvtools::fuzz::fuzzerutil::kSilentMessageConsumer,
-      original_binary_.data(), original_binary_.size());
-  assert(ir_context_ && "|binary| is invalid");
+    ir_context_ =
+        spvtools::BuildModule(target_env, spvtools::fuzz::fuzzerutil::kSilentMessageConsumer,
+                              original_binary_.data(), original_binary_.size());
+    assert(ir_context_ && "|binary| is invalid");
 
-  do {
-    MaybeAddFinder<
-        spvtools::reduce::
-            ConditionalBranchToSimpleConditionalBranchOpportunityFinder>();
-    MaybeAddFinder<spvtools::reduce::MergeBlocksReductionOpportunityFinder>();
-    MaybeAddFinder<
-        spvtools::reduce::OperandToConstReductionOpportunityFinder>();
-    MaybeAddFinder<
-        spvtools::reduce::OperandToDominatingIdReductionOpportunityFinder>();
-    MaybeAddFinder<
-        spvtools::reduce::OperandToUndefReductionOpportunityFinder>();
-    MaybeAddFinder<spvtools::reduce::RemoveBlockReductionOpportunityFinder>();
-    MaybeAddFinder<
-        spvtools::reduce::RemoveFunctionReductionOpportunityFinder>();
-    MaybeAddFinder<
-        spvtools::reduce::RemoveSelectionReductionOpportunityFinder>();
-    MaybeAddFinder<
-        spvtools::reduce::RemoveUnusedInstructionReductionOpportunityFinder>(
-        true);
-    MaybeAddFinder<
-        spvtools::reduce::RemoveUnusedStructMemberReductionOpportunityFinder>();
-    MaybeAddFinder<
-        spvtools::reduce::SimpleConditionalBranchToBranchOpportunityFinder>();
-    MaybeAddFinder<spvtools::reduce::
-                       StructuredLoopToSelectionReductionOpportunityFinder>();
-  } while (finders_.empty());
+    do {
+        MaybeAddFinder<
+            spvtools::reduce::ConditionalBranchToSimpleConditionalBranchOpportunityFinder>();
+        MaybeAddFinder<spvtools::reduce::MergeBlocksReductionOpportunityFinder>();
+        MaybeAddFinder<spvtools::reduce::OperandToConstReductionOpportunityFinder>();
+        MaybeAddFinder<spvtools::reduce::OperandToDominatingIdReductionOpportunityFinder>();
+        MaybeAddFinder<spvtools::reduce::OperandToUndefReductionOpportunityFinder>();
+        MaybeAddFinder<spvtools::reduce::RemoveBlockReductionOpportunityFinder>();
+        MaybeAddFinder<spvtools::reduce::RemoveFunctionReductionOpportunityFinder>();
+        MaybeAddFinder<spvtools::reduce::RemoveSelectionReductionOpportunityFinder>();
+        MaybeAddFinder<spvtools::reduce::RemoveUnusedInstructionReductionOpportunityFinder>(true);
+        MaybeAddFinder<spvtools::reduce::RemoveUnusedStructMemberReductionOpportunityFinder>();
+        MaybeAddFinder<spvtools::reduce::SimpleConditionalBranchToBranchOpportunityFinder>();
+        MaybeAddFinder<spvtools::reduce::StructuredLoopToSelectionReductionOpportunityFinder>();
+    } while (finders_.empty());
 }
 
 Mutator::Result SpirvReduceMutator::Mutate() {
-  assert(is_valid_ && "Can't mutate invalid module");
+    assert(is_valid_ && "Can't mutate invalid module");
 
-  // The upper limit on the number of applied reduction passes.
-  const uint32_t kMaxAppliedReductions = 500;
-  const auto old_applied_reductions = total_applied_reductions_;
+    // The upper limit on the number of applied reduction passes.
+    const uint32_t kMaxAppliedReductions = 500;
+    const auto old_applied_reductions = total_applied_reductions_;
 
-  // The upper limit on the number of failed attempts to apply reductions (i.e.
-  // when no reduction was returned by the reduction finder).
-  const uint32_t kMaxConsecutiveFailures = 10;
-  uint32_t num_consecutive_failures = 0;
+    // The upper limit on the number of failed attempts to apply reductions (i.e.
+    // when no reduction was returned by the reduction finder).
+    const uint32_t kMaxConsecutiveFailures = 10;
+    uint32_t num_consecutive_failures = 0;
 
-  // Iterate while we haven't exceeded the limit on the total number of applied
-  // reductions, the limit on the number of reductions applied at once and limit
-  // on the number of consecutive failed attempts.
-  while (total_applied_reductions_ < kMaxAppliedReductions &&
-         (reductions_batch_size_ == 0 ||
-          total_applied_reductions_ - old_applied_reductions <
-              reductions_batch_size_) &&
-         num_consecutive_failures < kMaxConsecutiveFailures) {
-    // Select an opportunity finder and get some reduction opportunities from
-    // it.
-    auto finder = GetRandomElement(&finders_);
-    auto reduction_opportunities =
-        finder->GetAvailableOpportunities(ir_context_.get(), 0);
+    // Iterate while we haven't exceeded the limit on the total number of applied
+    // reductions, the limit on the number of reductions applied at once and limit
+    // on the number of consecutive failed attempts.
+    while (total_applied_reductions_ < kMaxAppliedReductions &&
+           (reductions_batch_size_ == 0 ||
+            total_applied_reductions_ - old_applied_reductions < reductions_batch_size_) &&
+           num_consecutive_failures < kMaxConsecutiveFailures) {
+        // Select an opportunity finder and get some reduction opportunities from
+        // it.
+        auto finder = GetRandomElement(&finders_);
+        auto reduction_opportunities = finder->GetAvailableOpportunities(ir_context_.get(), 0);
 
-    if (reduction_opportunities.empty()) {
-      // There is nothing to reduce. We increase the counter to make sure we
-      // don't stuck in this situation.
-      num_consecutive_failures++;
-    } else {
-      // Apply a random reduction opportunity. The latter should be applicable.
-      auto opportunity = GetRandomElement(&reduction_opportunities);
-      assert(opportunity->PreconditionHolds() && "Preconditions should hold");
-      total_applied_reductions_++;
-      num_consecutive_failures = 0;
-      if (!ApplyReduction(opportunity)) {
-        // The module became invalid as a result of the applied reduction.
-        is_valid_ = false;
-        return {Mutator::Status::kInvalid,
-                total_applied_reductions_ != old_applied_reductions};
-      }
+        if (reduction_opportunities.empty()) {
+            // There is nothing to reduce. We increase the counter to make sure we
+            // don't stuck in this situation.
+            num_consecutive_failures++;
+        } else {
+            // Apply a random reduction opportunity. The latter should be applicable.
+            auto opportunity = GetRandomElement(&reduction_opportunities);
+            assert(opportunity->PreconditionHolds() && "Preconditions should hold");
+            total_applied_reductions_++;
+            num_consecutive_failures = 0;
+            if (!ApplyReduction(opportunity)) {
+                // The module became invalid as a result of the applied reduction.
+                is_valid_ = false;
+                return {Mutator::Status::kInvalid,
+                        total_applied_reductions_ != old_applied_reductions};
+            }
+        }
     }
-  }
 
-  auto is_changed = total_applied_reductions_ != old_applied_reductions;
-  if (total_applied_reductions_ == kMaxAppliedReductions) {
-    return {Mutator::Status::kLimitReached, is_changed};
-  }
+    auto is_changed = total_applied_reductions_ != old_applied_reductions;
+    if (total_applied_reductions_ == kMaxAppliedReductions) {
+        return {Mutator::Status::kLimitReached, is_changed};
+    }
 
-  if (num_consecutive_failures == kMaxConsecutiveFailures) {
-    return {Mutator::Status::kStuck, is_changed};
-  }
+    if (num_consecutive_failures == kMaxConsecutiveFailures) {
+        return {Mutator::Status::kStuck, is_changed};
+    }
 
-  assert(is_changed && "This is the only way left to break the loop");
-  return {Mutator::Status::kComplete, is_changed};
+    assert(is_changed && "This is the only way left to break the loop");
+    return {Mutator::Status::kComplete, is_changed};
 }
 
 bool SpirvReduceMutator::ApplyReduction(
     spvtools::reduce::ReductionOpportunity* reduction_opportunity) {
-  reduction_opportunity->TryToApply();
-  return !validate_after_each_reduction_ ||
-         spvtools::fuzz::fuzzerutil::IsValidAndWellFormed(
-             ir_context_.get(), spvtools::ValidatorOptions(),
-             util::GetBufferMessageConsumer(&errors_));
+    reduction_opportunity->TryToApply();
+    return !validate_after_each_reduction_ || spvtools::fuzz::fuzzerutil::IsValidAndWellFormed(
+                                                  ir_context_.get(), spvtools::ValidatorOptions(),
+                                                  util::GetBufferMessageConsumer(&errors_));
 }
 
 std::vector<uint32_t> SpirvReduceMutator::GetBinary() const {
-  std::vector<uint32_t> result;
-  ir_context_->module()->ToBinary(&result, true);
-  return result;
+    std::vector<uint32_t> result;
+    ir_context_->module()->ToBinary(&result, true);
+    return result;
 }
 
 std::string SpirvReduceMutator::GetErrors() const {
-  return errors_.str();
+    return errors_.str();
 }
 
-void SpirvReduceMutator::LogErrors(const std::string* path,
-                                   uint32_t count) const {
-  auto message = GetErrors();
-  std::cout << count << " | SpirvReduceMutator (seed: " << seed_ << ")"
-            << std::endl;
-  std::cout << message << std::endl;
+void SpirvReduceMutator::LogErrors(const std::string* path, uint32_t count) const {
+    auto message = GetErrors();
+    std::cout << count << " | SpirvReduceMutator (seed: " << seed_ << ")" << std::endl;
+    std::cout << message << std::endl;
 
-  if (path) {
-    auto prefix = *path + std::to_string(count);
+    if (path) {
+        auto prefix = *path + std::to_string(count);
 
-    // Write errors to file.
-    std::ofstream(prefix + ".reducer.log") << "seed: " << seed_ << std::endl
-                                           << message << std::endl;
+        // Write errors to file.
+        std::ofstream(prefix + ".reducer.log") << "seed: " << seed_ << std::endl
+                                               << message << std::endl;
 
-    // Write the invalid SPIR-V binary.
-    util::WriteBinary(prefix + ".reducer.invalid.spv", GetBinary());
+        // Write the invalid SPIR-V binary.
+        util::WriteBinary(prefix + ".reducer.invalid.spv", GetBinary());
 
-    // Write the original SPIR-V binary.
-    util::WriteBinary(prefix + ".reducer.original.spv", original_binary_);
-  }
+        // Write the original SPIR-V binary.
+        util::WriteBinary(prefix + ".reducer.original.spv", original_binary_);
+    }
 }
 
 }  // namespace tint::fuzzers::spvtools_fuzzer
diff --git a/src/tint/fuzzers/tint_spirv_tools_fuzzer/spirv_reduce_mutator.h b/src/tint/fuzzers/tint_spirv_tools_fuzzer/spirv_reduce_mutator.h
index fc36701..ba7bef4 100644
--- a/src/tint/fuzzers/tint_spirv_tools_fuzzer/spirv_reduce_mutator.h
+++ b/src/tint/fuzzers/tint_spirv_tools_fuzzer/spirv_reduce_mutator.h
@@ -35,92 +35,90 @@
 /// if its value is 0. Uses a random subset of reduction opportunity finders by
 /// default. This can be overridden with the `enable_all_reductions` parameter.
 class SpirvReduceMutator : public Mutator {
- public:
-  /// Constructor.
-  /// @param target_env - the target environment for the `binary`.
-  /// @param binary - SPIR-V binary. Must be valid.
-  /// @param seed - the seed for the RNG.
-  /// @param reductions_batch_size - the number of reduction passes that will be
-  ///     applied during a single call to `Mutate`. If it's equal to 0 then we
-  ///     apply the passes until we reach the threshold for the total number of
-  ///     applied passes.
-  /// @param enable_all_reductions - whether to use all reduction passes or only
-  ///     a randomly selected subset of them.
-  /// @param validate_after_each_reduction - whether to validate after each
-  ///     applied reduction.
-  SpirvReduceMutator(spv_target_env target_env,
-                     std::vector<uint32_t> binary,
-                     uint32_t seed,
-                     uint32_t reductions_batch_size,
-                     bool enable_all_reductions,
-                     bool validate_after_each_reduction);
+  public:
+    /// Constructor.
+    /// @param target_env - the target environment for the `binary`.
+    /// @param binary - SPIR-V binary. Must be valid.
+    /// @param seed - the seed for the RNG.
+    /// @param reductions_batch_size - the number of reduction passes that will be
+    ///     applied during a single call to `Mutate`. If it's equal to 0 then we
+    ///     apply the passes until we reach the threshold for the total number of
+    ///     applied passes.
+    /// @param enable_all_reductions - whether to use all reduction passes or only
+    ///     a randomly selected subset of them.
+    /// @param validate_after_each_reduction - whether to validate after each
+    ///     applied reduction.
+    SpirvReduceMutator(spv_target_env target_env,
+                       std::vector<uint32_t> binary,
+                       uint32_t seed,
+                       uint32_t reductions_batch_size,
+                       bool enable_all_reductions,
+                       bool validate_after_each_reduction);
 
-  Result Mutate() override;
-  std::vector<uint32_t> GetBinary() const override;
-  void LogErrors(const std::string* path, uint32_t count) const override;
-  std::string GetErrors() const override;
+    Result Mutate() override;
+    std::vector<uint32_t> GetBinary() const override;
+    void LogErrors(const std::string* path, uint32_t count) const override;
+    std::string GetErrors() const override;
 
- private:
-  template <typename T, typename... Args>
-  void MaybeAddFinder(Args&&... args) {
-    if (enable_all_reductions_ || generator_.GetBool()) {
-      finders_.push_back(std::make_unique<T>(std::forward<Args>(args)...));
+  private:
+    template <typename T, typename... Args>
+    void MaybeAddFinder(Args&&... args) {
+        if (enable_all_reductions_ || generator_.GetBool()) {
+            finders_.push_back(std::make_unique<T>(std::forward<Args>(args)...));
+        }
     }
-  }
 
-  template <typename T>
-  T* GetRandomElement(std::vector<T>* arr) {
-    assert(!arr->empty() && "Can't get random element from an empty vector");
-    auto index = generator_.GetUInt32(static_cast<uint32_t>(arr->size()));
-    return &(*arr)[index];
-  }
+    template <typename T>
+    T* GetRandomElement(std::vector<T>* arr) {
+        assert(!arr->empty() && "Can't get random element from an empty vector");
+        auto index = generator_.GetUInt32(static_cast<uint32_t>(arr->size()));
+        return &(*arr)[index];
+    }
 
-  template <typename T>
-  T* GetRandomElement(std::vector<std::unique_ptr<T>>* arr) {
-    assert(!arr->empty() && "Can't get random element from an empty vector");
-    auto index = generator_.GetUInt32(static_cast<uint32_t>(arr->size()));
-    return (*arr)[index].get();
-  }
+    template <typename T>
+    T* GetRandomElement(std::vector<std::unique_ptr<T>>* arr) {
+        assert(!arr->empty() && "Can't get random element from an empty vector");
+        auto index = generator_.GetUInt32(static_cast<uint32_t>(arr->size()));
+        return (*arr)[index].get();
+    }
 
-  bool ApplyReduction(
-      spvtools::reduce::ReductionOpportunity* reduction_opportunity);
+    bool ApplyReduction(spvtools::reduce::ReductionOpportunity* reduction_opportunity);
 
-  // The SPIR-V binary that is being reduced.
-  std::unique_ptr<spvtools::opt::IRContext> ir_context_;
+    // The SPIR-V binary that is being reduced.
+    std::unique_ptr<spvtools::opt::IRContext> ir_context_;
 
-  // The selected subset of reduction opportunity finders.
-  std::vector<std::unique_ptr<spvtools::reduce::ReductionOpportunityFinder>>
-      finders_;
+    // The selected subset of reduction opportunity finders.
+    std::vector<std::unique_ptr<spvtools::reduce::ReductionOpportunityFinder>> finders_;
 
-  // Random number generator initialized with `seed_`.
-  RandomGenerator generator_;
+    // Random number generator initialized with `seed_`.
+    RandomGenerator generator_;
 
-  // All the errors produced by the reducer.
-  std::stringstream errors_;
+    // All the errors produced by the reducer.
+    std::stringstream errors_;
 
-  // Whether the last call to the `Mutate` method produced the valid binary.
-  bool is_valid_;
+    // Whether the last call to the `Mutate` method produced the valid binary.
+    bool is_valid_;
 
-  // The number of reductions to apply on a single call to `Mutate`.
-  const uint32_t reductions_batch_size_;
+    // The number of reductions to apply on a single call to `Mutate`.
+    const uint32_t reductions_batch_size_;
 
-  // The total number of applied reductions.
-  uint32_t total_applied_reductions_;
+    // The total number of applied reductions.
+    uint32_t total_applied_reductions_;
 
-  // Whether we want to use all the reduction opportunity finders and not just a
-  // subset of them.
-  const bool enable_all_reductions_;
+    // Whether we want to use all the reduction opportunity finders and not just a
+    // subset of them.
+    const bool enable_all_reductions_;
 
-  // Whether we want to validate all the binary after each reduction.
-  const bool validate_after_each_reduction_;
+    // Whether we want to validate all the binary after each reduction.
+    const bool validate_after_each_reduction_;
 
-  // The original binary that was used to initialize this mutator.
-  // Useful for debugging.
-  const std::vector<uint32_t> original_binary_;
+    // The original binary that was used to initialize this mutator.
+    // Useful for debugging.
+    const std::vector<uint32_t> original_binary_;
 
-  // The seed that was used to initialize the random number generator.
-  // Useful for debugging.
-  const uint32_t seed_;
+    // The seed that was used to initialize the random number generator.
+    // Useful for debugging.
+    const uint32_t seed_;
 };
 
 }  // namespace tint::fuzzers::spvtools_fuzzer
diff --git a/src/tint/fuzzers/tint_spirv_tools_fuzzer/tint_spirv_tools_fuzzer.cc b/src/tint/fuzzers/tint_spirv_tools_fuzzer/tint_spirv_tools_fuzzer.cc
index 7958634..6ba973a 100644
--- a/src/tint/fuzzers/tint_spirv_tools_fuzzer/tint_spirv_tools_fuzzer.cc
+++ b/src/tint/fuzzers/tint_spirv_tools_fuzzer/tint_spirv_tools_fuzzer.cc
@@ -20,7 +20,7 @@
 namespace tint::fuzzers::spvtools_fuzzer {
 
 void OverrideCliParams(FuzzerCliParams& /*unused*/) {
-  // Leave the CLI parameters unchanged.
+    // Leave the CLI parameters unchanged.
 }
 
 }  // namespace tint::fuzzers::spvtools_fuzzer
diff --git a/src/tint/fuzzers/tint_spirv_tools_fuzzer/tint_spirv_tools_hlsl_writer_fuzzer.cc b/src/tint/fuzzers/tint_spirv_tools_fuzzer/tint_spirv_tools_hlsl_writer_fuzzer.cc
index 58a7fab..2c76157 100644
--- a/src/tint/fuzzers/tint_spirv_tools_fuzzer/tint_spirv_tools_hlsl_writer_fuzzer.cc
+++ b/src/tint/fuzzers/tint_spirv_tools_fuzzer/tint_spirv_tools_hlsl_writer_fuzzer.cc
@@ -20,10 +20,10 @@
 namespace tint::fuzzers::spvtools_fuzzer {
 
 void OverrideCliParams(FuzzerCliParams& cli_params) {
-  assert(cli_params.fuzzing_target == FuzzingTarget::kAll &&
-         "The fuzzing target should not have been set by a CLI parameter: it "
-         "should have its default value.");
-  cli_params.fuzzing_target = FuzzingTarget::kHlsl;
+    assert(cli_params.fuzzing_target == FuzzingTarget::kAll &&
+           "The fuzzing target should not have been set by a CLI parameter: it "
+           "should have its default value.");
+    cli_params.fuzzing_target = FuzzingTarget::kHlsl;
 }
 
 }  // namespace tint::fuzzers::spvtools_fuzzer
diff --git a/src/tint/fuzzers/tint_spirv_tools_fuzzer/tint_spirv_tools_msl_writer_fuzzer.cc b/src/tint/fuzzers/tint_spirv_tools_fuzzer/tint_spirv_tools_msl_writer_fuzzer.cc
index 69edf44..5d70ad3 100644
--- a/src/tint/fuzzers/tint_spirv_tools_fuzzer/tint_spirv_tools_msl_writer_fuzzer.cc
+++ b/src/tint/fuzzers/tint_spirv_tools_fuzzer/tint_spirv_tools_msl_writer_fuzzer.cc
@@ -20,10 +20,10 @@
 namespace tint::fuzzers::spvtools_fuzzer {
 
 void OverrideCliParams(FuzzerCliParams& cli_params) {
-  assert(cli_params.fuzzing_target == FuzzingTarget::kAll &&
-         "The fuzzing target should not have been set by a CLI parameter: it "
-         "should have its default value.");
-  cli_params.fuzzing_target = FuzzingTarget::kMsl;
+    assert(cli_params.fuzzing_target == FuzzingTarget::kAll &&
+           "The fuzzing target should not have been set by a CLI parameter: it "
+           "should have its default value.");
+    cli_params.fuzzing_target = FuzzingTarget::kMsl;
 }
 
 }  // namespace tint::fuzzers::spvtools_fuzzer
diff --git a/src/tint/fuzzers/tint_spirv_tools_fuzzer/tint_spirv_tools_spv_writer_fuzzer.cc b/src/tint/fuzzers/tint_spirv_tools_fuzzer/tint_spirv_tools_spv_writer_fuzzer.cc
index 2e583c7..53b4e45 100644
--- a/src/tint/fuzzers/tint_spirv_tools_fuzzer/tint_spirv_tools_spv_writer_fuzzer.cc
+++ b/src/tint/fuzzers/tint_spirv_tools_fuzzer/tint_spirv_tools_spv_writer_fuzzer.cc
@@ -20,10 +20,10 @@
 namespace tint::fuzzers::spvtools_fuzzer {
 
 void OverrideCliParams(FuzzerCliParams& cli_params) {
-  assert(cli_params.fuzzing_target == FuzzingTarget::kAll &&
-         "The fuzzing target should not have been set by a CLI parameter: it "
-         "should have its default value.");
-  cli_params.fuzzing_target = FuzzingTarget::kSpv;
+    assert(cli_params.fuzzing_target == FuzzingTarget::kAll &&
+           "The fuzzing target should not have been set by a CLI parameter: it "
+           "should have its default value.");
+    cli_params.fuzzing_target = FuzzingTarget::kSpv;
 }
 
 }  // namespace tint::fuzzers::spvtools_fuzzer
diff --git a/src/tint/fuzzers/tint_spirv_tools_fuzzer/tint_spirv_tools_wgsl_writer_fuzzer.cc b/src/tint/fuzzers/tint_spirv_tools_fuzzer/tint_spirv_tools_wgsl_writer_fuzzer.cc
index a25dff3..0593f6e 100644
--- a/src/tint/fuzzers/tint_spirv_tools_fuzzer/tint_spirv_tools_wgsl_writer_fuzzer.cc
+++ b/src/tint/fuzzers/tint_spirv_tools_fuzzer/tint_spirv_tools_wgsl_writer_fuzzer.cc
@@ -20,10 +20,10 @@
 namespace tint::fuzzers::spvtools_fuzzer {
 
 void OverrideCliParams(FuzzerCliParams& cli_params) {
-  assert(cli_params.fuzzing_target == FuzzingTarget::kAll &&
-         "The fuzzing target should not have been set by a CLI parameter: it "
-         "should have its default value.");
-  cli_params.fuzzing_target = FuzzingTarget::kWgsl;
+    assert(cli_params.fuzzing_target == FuzzingTarget::kAll &&
+           "The fuzzing target should not have been set by a CLI parameter: it "
+           "should have its default value.");
+    cli_params.fuzzing_target = FuzzingTarget::kWgsl;
 }
 
 }  // namespace tint::fuzzers::spvtools_fuzzer
diff --git a/src/tint/fuzzers/tint_spirv_tools_fuzzer/util.cc b/src/tint/fuzzers/tint_spirv_tools_fuzzer/util.cc
index 1117821..a9e9e2b 100644
--- a/src/tint/fuzzers/tint_spirv_tools_fuzzer/util.cc
+++ b/src/tint/fuzzers/tint_spirv_tools_fuzzer/util.cc
@@ -21,9 +21,9 @@
 namespace {
 
 bool WriteBinary(const std::string& path, const uint8_t* data, size_t size) {
-  std::ofstream spv(path, std::ios::binary);
-  return spv && spv.write(reinterpret_cast<const char*>(data),
-                          static_cast<std::streamsize>(size));
+    std::ofstream spv(path, std::ios::binary);
+    return spv &&
+           spv.write(reinterpret_cast<const char*>(data), static_cast<std::streamsize>(size));
 }
 
 void LogError(uint32_t index,
@@ -33,47 +33,47 @@
               const uint8_t* data,
               size_t size,
               const std::string* wgsl) {
-  std::cout << index << " | " << type << ": " << message << std::endl;
+    std::cout << index << " | " << type << ": " << message << std::endl;
 
-  if (path) {
-    auto prefix = *path + std::to_string(index);
-    std::ofstream(prefix + ".log") << message << std::endl;
+    if (path) {
+        auto prefix = *path + std::to_string(index);
+        std::ofstream(prefix + ".log") << message << std::endl;
 
-    WriteBinary(prefix + ".spv", data, size);
+        WriteBinary(prefix + ".spv", data, size);
 
-    if (wgsl) {
-      std::ofstream(prefix + ".wgsl") << *wgsl << std::endl;
+        if (wgsl) {
+            std::ofstream(prefix + ".wgsl") << *wgsl << std::endl;
+        }
     }
-  }
 }
 
 }  // namespace
 
 spvtools::MessageConsumer GetBufferMessageConsumer(std::stringstream* buffer) {
-  return [buffer](spv_message_level_t level, const char*,
-                  const spv_position_t& position, const char* message) {
-    std::string status;
-    switch (level) {
-      case SPV_MSG_FATAL:
-      case SPV_MSG_INTERNAL_ERROR:
-      case SPV_MSG_ERROR:
-        status = "ERROR";
-        break;
-      case SPV_MSG_WARNING:
-      case SPV_MSG_INFO:
-      case SPV_MSG_DEBUG:
-        status = "INFO";
-        break;
-    }
-    *buffer << status << " " << position.line << ":" << position.column << ":"
-            << position.index << ": " << message << std::endl;
-  };
+    return [buffer](spv_message_level_t level, const char*, const spv_position_t& position,
+                    const char* message) {
+        std::string status;
+        switch (level) {
+            case SPV_MSG_FATAL:
+            case SPV_MSG_INTERNAL_ERROR:
+            case SPV_MSG_ERROR:
+                status = "ERROR";
+                break;
+            case SPV_MSG_WARNING:
+            case SPV_MSG_INFO:
+            case SPV_MSG_DEBUG:
+                status = "INFO";
+                break;
+        }
+        *buffer << status << " " << position.line << ":" << position.column << ":" << position.index
+                << ": " << message << std::endl;
+    };
 }
 
 void LogMutatorError(const Mutator& mutator, const std::string& error_dir) {
-  static uint32_t mutator_count = 0;
-  auto error_path = error_dir.empty() ? error_dir : error_dir + "/mutator/";
-  mutator.LogErrors(error_dir.empty() ? nullptr : &error_path, mutator_count++);
+    static uint32_t mutator_count = 0;
+    auto error_path = error_dir.empty() ? error_dir : error_dir + "/mutator/";
+    mutator.LogErrors(error_dir.empty() ? nullptr : &error_path, mutator_count++);
 }
 
 void LogWgslError(const std::string& message,
@@ -82,70 +82,70 @@
                   const std::string& wgsl,
                   OutputFormat output_format,
                   const std::string& error_dir) {
-  static uint32_t wgsl_count = 0;
-  std::string error_type;
-  switch (output_format) {
-    case OutputFormat::kSpv:
-      error_type = "WGSL -> SPV";
-      break;
-    case OutputFormat::kMSL:
-      error_type = "WGSL -> MSL";
-      break;
-    case OutputFormat::kHLSL:
-      error_type = "WGSL -> HLSL";
-      break;
-    case OutputFormat::kWGSL:
-      error_type = "WGSL -> WGSL";
-      break;
-  }
-  auto error_path = error_dir.empty() ? error_dir : error_dir + "/wgsl/";
-  LogError(wgsl_count++, error_type, message,
-           error_dir.empty() ? nullptr : &error_path, data, size, &wgsl);
+    static uint32_t wgsl_count = 0;
+    std::string error_type;
+    switch (output_format) {
+        case OutputFormat::kSpv:
+            error_type = "WGSL -> SPV";
+            break;
+        case OutputFormat::kMSL:
+            error_type = "WGSL -> MSL";
+            break;
+        case OutputFormat::kHLSL:
+            error_type = "WGSL -> HLSL";
+            break;
+        case OutputFormat::kWGSL:
+            error_type = "WGSL -> WGSL";
+            break;
+    }
+    auto error_path = error_dir.empty() ? error_dir : error_dir + "/wgsl/";
+    LogError(wgsl_count++, error_type, message, error_dir.empty() ? nullptr : &error_path, data,
+             size, &wgsl);
 }
 
 void LogSpvError(const std::string& message,
                  const uint8_t* data,
                  size_t size,
                  const std::string& error_dir) {
-  static uint32_t spv_count = 0;
-  auto error_path = error_dir.empty() ? error_dir : error_dir + "/spv/";
-  LogError(spv_count++, "SPV -> WGSL", message,
-           error_dir.empty() ? nullptr : &error_path, data, size, nullptr);
+    static uint32_t spv_count = 0;
+    auto error_path = error_dir.empty() ? error_dir : error_dir + "/spv/";
+    LogError(spv_count++, "SPV -> WGSL", message, error_dir.empty() ? nullptr : &error_path, data,
+             size, nullptr);
 }
 
 bool ReadBinary(const std::string& path, std::vector<uint32_t>* out) {
-  if (!out) {
-    return false;
-  }
+    if (!out) {
+        return false;
+    }
 
-  std::ifstream file(path, std::ios::binary | std::ios::ate);
-  if (!file) {
-    return false;
-  }
+    std::ifstream file(path, std::ios::binary | std::ios::ate);
+    if (!file) {
+        return false;
+    }
 
-  size_t size = static_cast<size_t>(file.tellg());
-  if (!file) {
-    return false;
-  }
+    size_t size = static_cast<size_t>(file.tellg());
+    if (!file) {
+        return false;
+    }
 
-  file.seekg(0);
-  if (!file) {
-    return false;
-  }
+    file.seekg(0);
+    if (!file) {
+        return false;
+    }
 
-  std::vector<char> binary(size);
-  if (!file.read(binary.data(), size)) {
-    return false;
-  }
+    std::vector<char> binary(size);
+    if (!file.read(binary.data(), size)) {
+        return false;
+    }
 
-  out->resize(binary.size() / sizeof(uint32_t));
-  std::memcpy(out->data(), binary.data(), binary.size());
-  return true;
+    out->resize(binary.size() / sizeof(uint32_t));
+    std::memcpy(out->data(), binary.data(), binary.size());
+    return true;
 }
 
 bool WriteBinary(const std::string& path, const std::vector<uint32_t>& binary) {
-  return WriteBinary(path, reinterpret_cast<const uint8_t*>(binary.data()),
-                     binary.size() * sizeof(uint32_t));
+    return WriteBinary(path, reinterpret_cast<const uint8_t*>(binary.data()),
+                       binary.size() * sizeof(uint32_t));
 }
 
 }  // namespace tint::fuzzers::spvtools_fuzzer::util
diff --git a/src/tint/fuzzers/tint_spv_reader_fuzzer.cc b/src/tint/fuzzers/tint_spv_reader_fuzzer.cc
index 3d8bdd4..64980f7 100644
--- a/src/tint/fuzzers/tint_spv_reader_fuzzer.cc
+++ b/src/tint/fuzzers/tint_spv_reader_fuzzer.cc
@@ -20,9 +20,9 @@
 namespace tint::fuzzers {
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  tint::fuzzers::CommonFuzzer fuzzer(InputFormat::kSpv, OutputFormat::kNone);
-  fuzzer.SetDumpInput(GetCliParams().dump_input);
-  return fuzzer.Run(data, size);
+    tint::fuzzers::CommonFuzzer fuzzer(InputFormat::kSpv, OutputFormat::kNone);
+    fuzzer.SetDumpInput(GetCliParams().dump_input);
+    return fuzzer.Run(data, size);
 }
 
 }  // namespace tint::fuzzers
diff --git a/src/tint/fuzzers/tint_spv_reader_hlsl_writer_fuzzer.cc b/src/tint/fuzzers/tint_spv_reader_hlsl_writer_fuzzer.cc
index 8e84e5d..2eeecfc 100644
--- a/src/tint/fuzzers/tint_spv_reader_hlsl_writer_fuzzer.cc
+++ b/src/tint/fuzzers/tint_spv_reader_hlsl_writer_fuzzer.cc
@@ -20,12 +20,11 @@
 namespace tint::fuzzers {
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  tint::fuzzers::ReaderWriterFuzzer fuzzer(InputFormat::kSpv,
-                                           OutputFormat::kHLSL);
-  fuzzer.SetDumpInput(GetCliParams().dump_input);
-  fuzzer.SetEnforceValidity(GetCliParams().enforce_validity);
+    tint::fuzzers::ReaderWriterFuzzer fuzzer(InputFormat::kSpv, OutputFormat::kHLSL);
+    fuzzer.SetDumpInput(GetCliParams().dump_input);
+    fuzzer.SetEnforceValidity(GetCliParams().enforce_validity);
 
-  return fuzzer.Run(data, size);
+    return fuzzer.Run(data, size);
 }
 
 }  // namespace tint::fuzzers
diff --git a/src/tint/fuzzers/tint_spv_reader_msl_writer_fuzzer.cc b/src/tint/fuzzers/tint_spv_reader_msl_writer_fuzzer.cc
index 0bc7c85..4a06bc7 100644
--- a/src/tint/fuzzers/tint_spv_reader_msl_writer_fuzzer.cc
+++ b/src/tint/fuzzers/tint_spv_reader_msl_writer_fuzzer.cc
@@ -20,16 +20,15 @@
 namespace tint::fuzzers {
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  DataBuilder db(data, size);
-  writer::msl::Options options;
-  GenerateMslOptions(&db, &options);
-  tint::fuzzers::ReaderWriterFuzzer fuzzer(InputFormat::kSpv,
-                                           OutputFormat::kMSL);
-  fuzzer.SetOptionsMsl(options);
-  fuzzer.SetDumpInput(GetCliParams().dump_input);
-  fuzzer.SetEnforceValidity(GetCliParams().enforce_validity);
+    DataBuilder db(data, size);
+    writer::msl::Options options;
+    GenerateMslOptions(&db, &options);
+    tint::fuzzers::ReaderWriterFuzzer fuzzer(InputFormat::kSpv, OutputFormat::kMSL);
+    fuzzer.SetOptionsMsl(options);
+    fuzzer.SetDumpInput(GetCliParams().dump_input);
+    fuzzer.SetEnforceValidity(GetCliParams().enforce_validity);
 
-  return fuzzer.Run(data, size);
+    return fuzzer.Run(data, size);
 }
 
 }  // namespace tint::fuzzers
diff --git a/src/tint/fuzzers/tint_spv_reader_spv_writer_fuzzer.cc b/src/tint/fuzzers/tint_spv_reader_spv_writer_fuzzer.cc
index c95034a..efe5377 100644
--- a/src/tint/fuzzers/tint_spv_reader_spv_writer_fuzzer.cc
+++ b/src/tint/fuzzers/tint_spv_reader_spv_writer_fuzzer.cc
@@ -20,16 +20,15 @@
 namespace tint::fuzzers {
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  DataBuilder db(data, size);
-  writer::spirv::Options options;
-  GenerateSpirvOptions(&db, &options);
-  tint::fuzzers::ReaderWriterFuzzer fuzzer(InputFormat::kSpv,
-                                           OutputFormat::kSpv);
-  fuzzer.SetOptionsSpirv(options);
-  fuzzer.SetDumpInput(GetCliParams().dump_input);
-  fuzzer.SetEnforceValidity(GetCliParams().enforce_validity);
+    DataBuilder db(data, size);
+    writer::spirv::Options options;
+    GenerateSpirvOptions(&db, &options);
+    tint::fuzzers::ReaderWriterFuzzer fuzzer(InputFormat::kSpv, OutputFormat::kSpv);
+    fuzzer.SetOptionsSpirv(options);
+    fuzzer.SetDumpInput(GetCliParams().dump_input);
+    fuzzer.SetEnforceValidity(GetCliParams().enforce_validity);
 
-  return fuzzer.Run(data, size);
+    return fuzzer.Run(data, size);
 }
 
 }  // namespace tint::fuzzers
diff --git a/src/tint/fuzzers/tint_spv_reader_wgsl_writer_fuzzer.cc b/src/tint/fuzzers/tint_spv_reader_wgsl_writer_fuzzer.cc
index 579b89c..24fe6b6 100644
--- a/src/tint/fuzzers/tint_spv_reader_wgsl_writer_fuzzer.cc
+++ b/src/tint/fuzzers/tint_spv_reader_wgsl_writer_fuzzer.cc
@@ -20,12 +20,11 @@
 namespace tint::fuzzers {
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  tint::fuzzers::ReaderWriterFuzzer fuzzer(InputFormat::kSpv,
-                                           OutputFormat::kWGSL);
-  fuzzer.SetDumpInput(GetCliParams().dump_input);
-  fuzzer.SetEnforceValidity(GetCliParams().enforce_validity);
+    tint::fuzzers::ReaderWriterFuzzer fuzzer(InputFormat::kSpv, OutputFormat::kWGSL);
+    fuzzer.SetDumpInput(GetCliParams().dump_input);
+    fuzzer.SetEnforceValidity(GetCliParams().enforce_validity);
 
-  return fuzzer.Run(data, size);
+    return fuzzer.Run(data, size);
 }
 
 }  // namespace tint::fuzzers
diff --git a/src/tint/fuzzers/tint_vertex_pulling_fuzzer.cc b/src/tint/fuzzers/tint_vertex_pulling_fuzzer.cc
index 9184710..ab0fcf9 100644
--- a/src/tint/fuzzers/tint_vertex_pulling_fuzzer.cc
+++ b/src/tint/fuzzers/tint_vertex_pulling_fuzzer.cc
@@ -19,15 +19,15 @@
 namespace tint::fuzzers {
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  TransformBuilder tb(data, size);
-  tb.AddTransform<transform::VertexPulling>();
+    TransformBuilder tb(data, size);
+    tb.AddTransform<transform::VertexPulling>();
 
-  tint::fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kWGSL);
-  fuzzer.SetTransformManager(tb.manager(), tb.data_map());
-  fuzzer.SetDumpInput(GetCliParams().dump_input);
-  fuzzer.SetEnforceValidity(GetCliParams().enforce_validity);
+    tint::fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kWGSL);
+    fuzzer.SetTransformManager(tb.manager(), tb.data_map());
+    fuzzer.SetDumpInput(GetCliParams().dump_input);
+    fuzzer.SetEnforceValidity(GetCliParams().enforce_validity);
 
-  return fuzzer.Run(data, size);
+    return fuzzer.Run(data, size);
 }
 
 }  // namespace tint::fuzzers
diff --git a/src/tint/fuzzers/tint_wgsl_reader_fuzzer.cc b/src/tint/fuzzers/tint_wgsl_reader_fuzzer.cc
index 2e64c36..2bff468 100644
--- a/src/tint/fuzzers/tint_wgsl_reader_fuzzer.cc
+++ b/src/tint/fuzzers/tint_wgsl_reader_fuzzer.cc
@@ -20,9 +20,9 @@
 namespace tint::fuzzers {
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  tint::fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kNone);
-  fuzzer.SetDumpInput(GetCliParams().dump_input);
-  return fuzzer.Run(data, size);
+    tint::fuzzers::CommonFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kNone);
+    fuzzer.SetDumpInput(GetCliParams().dump_input);
+    return fuzzer.Run(data, size);
 }
 
 }  // namespace tint::fuzzers
diff --git a/src/tint/fuzzers/tint_wgsl_reader_hlsl_writer_fuzzer.cc b/src/tint/fuzzers/tint_wgsl_reader_hlsl_writer_fuzzer.cc
index 1fc85b7..d5e56ad 100644
--- a/src/tint/fuzzers/tint_wgsl_reader_hlsl_writer_fuzzer.cc
+++ b/src/tint/fuzzers/tint_wgsl_reader_hlsl_writer_fuzzer.cc
@@ -20,12 +20,11 @@
 namespace tint::fuzzers {
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  tint::fuzzers::ReaderWriterFuzzer fuzzer(InputFormat::kWGSL,
-                                           OutputFormat::kHLSL);
-  fuzzer.SetDumpInput(GetCliParams().dump_input);
-  fuzzer.SetEnforceValidity(GetCliParams().enforce_validity);
+    tint::fuzzers::ReaderWriterFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kHLSL);
+    fuzzer.SetDumpInput(GetCliParams().dump_input);
+    fuzzer.SetEnforceValidity(GetCliParams().enforce_validity);
 
-  return fuzzer.Run(data, size);
+    return fuzzer.Run(data, size);
 }
 
 }  // namespace tint::fuzzers
diff --git a/src/tint/fuzzers/tint_wgsl_reader_msl_writer_fuzzer.cc b/src/tint/fuzzers/tint_wgsl_reader_msl_writer_fuzzer.cc
index 85d9e3d..fecd8e8 100644
--- a/src/tint/fuzzers/tint_wgsl_reader_msl_writer_fuzzer.cc
+++ b/src/tint/fuzzers/tint_wgsl_reader_msl_writer_fuzzer.cc
@@ -20,16 +20,15 @@
 namespace tint::fuzzers {
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  DataBuilder db(data, size);
-  writer::msl::Options options;
-  GenerateMslOptions(&db, &options);
-  tint::fuzzers::ReaderWriterFuzzer fuzzer(InputFormat::kWGSL,
-                                           OutputFormat::kMSL);
-  fuzzer.SetOptionsMsl(options);
-  fuzzer.SetDumpInput(GetCliParams().dump_input);
-  fuzzer.SetEnforceValidity(GetCliParams().enforce_validity);
+    DataBuilder db(data, size);
+    writer::msl::Options options;
+    GenerateMslOptions(&db, &options);
+    tint::fuzzers::ReaderWriterFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kMSL);
+    fuzzer.SetOptionsMsl(options);
+    fuzzer.SetDumpInput(GetCliParams().dump_input);
+    fuzzer.SetEnforceValidity(GetCliParams().enforce_validity);
 
-  return fuzzer.Run(data, size);
+    return fuzzer.Run(data, size);
 }
 
 }  // namespace tint::fuzzers
diff --git a/src/tint/fuzzers/tint_wgsl_reader_spv_writer_fuzzer.cc b/src/tint/fuzzers/tint_wgsl_reader_spv_writer_fuzzer.cc
index 9a31dd5..386508a 100644
--- a/src/tint/fuzzers/tint_wgsl_reader_spv_writer_fuzzer.cc
+++ b/src/tint/fuzzers/tint_wgsl_reader_spv_writer_fuzzer.cc
@@ -20,16 +20,15 @@
 namespace tint::fuzzers {
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  DataBuilder db(data, size);
-  writer::spirv::Options options;
-  GenerateSpirvOptions(&db, &options);
-  tint::fuzzers::ReaderWriterFuzzer fuzzer(InputFormat::kWGSL,
-                                           OutputFormat::kSpv);
-  fuzzer.SetOptionsSpirv(options);
-  fuzzer.SetDumpInput(GetCliParams().dump_input);
-  fuzzer.SetEnforceValidity(GetCliParams().enforce_validity);
+    DataBuilder db(data, size);
+    writer::spirv::Options options;
+    GenerateSpirvOptions(&db, &options);
+    tint::fuzzers::ReaderWriterFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kSpv);
+    fuzzer.SetOptionsSpirv(options);
+    fuzzer.SetDumpInput(GetCliParams().dump_input);
+    fuzzer.SetEnforceValidity(GetCliParams().enforce_validity);
 
-  return fuzzer.Run(data, size);
+    return fuzzer.Run(data, size);
 }
 
 }  // namespace tint::fuzzers
diff --git a/src/tint/fuzzers/tint_wgsl_reader_wgsl_writer_fuzzer.cc b/src/tint/fuzzers/tint_wgsl_reader_wgsl_writer_fuzzer.cc
index 33a0579..e4392ea 100644
--- a/src/tint/fuzzers/tint_wgsl_reader_wgsl_writer_fuzzer.cc
+++ b/src/tint/fuzzers/tint_wgsl_reader_wgsl_writer_fuzzer.cc
@@ -20,12 +20,11 @@
 namespace tint::fuzzers {
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
-  tint::fuzzers::ReaderWriterFuzzer fuzzer(InputFormat::kWGSL,
-                                           OutputFormat::kWGSL);
-  fuzzer.SetDumpInput(GetCliParams().dump_input);
-  fuzzer.SetEnforceValidity(GetCliParams().enforce_validity);
+    tint::fuzzers::ReaderWriterFuzzer fuzzer(InputFormat::kWGSL, OutputFormat::kWGSL);
+    fuzzer.SetDumpInput(GetCliParams().dump_input);
+    fuzzer.SetEnforceValidity(GetCliParams().enforce_validity);
 
-  return fuzzer.Run(data, size);
+    return fuzzer.Run(data, size);
 }
 
 }  // namespace tint::fuzzers
diff --git a/src/tint/fuzzers/transform_builder.h b/src/tint/fuzzers/transform_builder.h
index ff64e5a..d2c0f61 100644
--- a/src/tint/fuzzers/transform_builder.h
+++ b/src/tint/fuzzers/transform_builder.h
@@ -28,197 +28,191 @@
 /// Fuzzer utility class to build inputs for transforms and setup the transform
 /// manager.
 class TransformBuilder {
- public:
-  /// @brief Initializes the internal builder using a seed value
-  /// @param seed - seed value passed to engine
-  explicit TransformBuilder(uint64_t seed) : builder_(seed) {}
+  public:
+    /// @brief Initializes the internal builder using a seed value
+    /// @param seed - seed value passed to engine
+    explicit TransformBuilder(uint64_t seed) : builder_(seed) {}
 
-  /// @brief Initializes the internal builder using seed data
-  /// @param data - data fuzzer to calculate seed from
-  /// @param size - size of data buffer
-  explicit TransformBuilder(const uint8_t* data, size_t size)
-      : builder_(data, size) {
-    assert(data != nullptr && "|data| must be !nullptr");
-  }
-
-  ~TransformBuilder() = default;
-
-  /// @returns manager for transforms
-  transform::Manager* manager() { return &manager_; }
-
-  /// @returns data for transforms
-  transform::DataMap* data_map() { return &data_map_; }
-
-  /// Adds a transform and needed data to |manager_| and |data_map_|.
-  /// @tparam T - A class that inherits from transform::Transform and has an
-  ///             explicit specialization in AddTransformImpl.
-  template <typename T>
-  void AddTransform() {
-    static_assert(std::is_base_of<transform::Transform, T>::value,
-                  "T is not a transform::Transform");
-    AddTransformImpl<T>::impl(this);
-  }
-
-  /// Helper that invokes Add*Transform for all of the platform independent
-  /// passes.
-  void AddPlatformIndependentPasses() {
-    AddTransform<transform::Robustness>();
-    AddTransform<transform::FirstIndexOffset>();
-    AddTransform<transform::BindingRemapper>();
-    AddTransform<transform::Renamer>();
-    AddTransform<transform::SingleEntryPoint>();
-    AddTransform<transform::VertexPulling>();
-  }
-
- private:
-  DataBuilder builder_;
-  transform::Manager manager_;
-  transform::DataMap data_map_;
-
-  DataBuilder* builder() { return &builder_; }
-
-  /// Implementation of AddTransform, specialized for each transform that is
-  /// implemented. Default implementation intentionally deleted to cause compile
-  /// error if unimplemented type passed in.
-  /// @tparam T - A fuzzer transform
-  template <typename T>
-  struct AddTransformImpl;
-
-  /// Implementation of AddTransform for ShuffleTransform
-  template <>
-  struct AddTransformImpl<ShuffleTransform> {
-    /// Add instance of ShuffleTransform to TransformBuilder
-    /// @param tb - TransformBuilder to add transform to
-    static void impl(TransformBuilder* tb) {
-      tb->manager()->Add<ShuffleTransform>(tb->builder_.build<size_t>());
-    }
-  };
-
-  /// Implementation of AddTransform for transform::Robustness
-  template <>
-  struct AddTransformImpl<transform::Robustness> {
-    /// Add instance of transform::Robustness to TransformBuilder
-    /// @param tb - TransformBuilder to add transform to
-    static void impl(TransformBuilder* tb) {
-      tb->manager()->Add<transform::Robustness>();
-    }
-  };
-
-  /// Implementation of AddTransform for transform::FirstIndexOffset
-  template <>
-  struct AddTransformImpl<transform::FirstIndexOffset> {
-    /// Add instance of transform::FirstIndexOffset to TransformBuilder
-    /// @param tb - TransformBuilder to add transform to
-    static void impl(TransformBuilder* tb) {
-      struct Config {
-        uint32_t group;
-        uint32_t binding;
-      };
-
-      Config config = tb->builder()->build<Config>();
-
-      tb->data_map()->Add<tint::transform::FirstIndexOffset::BindingPoint>(
-          config.binding, config.group);
-      tb->manager()->Add<transform::FirstIndexOffset>();
-    }
-  };
-
-  /// Implementation of AddTransform for transform::BindingRemapper
-  template <>
-  struct AddTransformImpl<transform::BindingRemapper> {
-    /// Add instance of transform::BindingRemapper to TransformBuilder
-    /// @param tb - TransformBuilder to add transform to
-    static void impl(TransformBuilder* tb) {
-      struct Config {
-        uint8_t old_group;
-        uint8_t old_binding;
-        uint8_t new_group;
-        uint8_t new_binding;
-        ast::Access new_access;
-      };
-
-      std::vector<Config> configs = tb->builder()->vector<Config>();
-      transform::BindingRemapper::BindingPoints binding_points;
-      transform::BindingRemapper::AccessControls accesses;
-      for (const auto& config : configs) {
-        binding_points[{config.old_binding, config.old_group}] = {
-            config.new_binding, config.new_group};
-        accesses[{config.old_binding, config.old_group}] = config.new_access;
-      }
-
-      tb->data_map()->Add<transform::BindingRemapper::Remappings>(
-          binding_points, accesses, tb->builder()->build<bool>());
-      tb->manager()->Add<transform::BindingRemapper>();
-    }
-  };
-
-  /// Implementation of AddTransform for transform::Renamer
-  template <>
-  struct AddTransformImpl<transform::Renamer> {
-    /// Add instance of transform::Renamer to TransformBuilder
-    /// @param tb - TransformBuilder to add transform to
-    static void impl(TransformBuilder* tb) {
-      tb->manager()->Add<transform::Renamer>();
-    }
-  };
-
-  /// Implementation of AddTransform for transform::SingleEntryPoint
-  template <>
-  struct AddTransformImpl<transform::SingleEntryPoint> {
-    /// Add instance of transform::SingleEntryPoint to TransformBuilder
-    /// @param tb - TransformBuilder to add transform to
-    static void impl(TransformBuilder* tb) {
-      auto input = tb->builder()->build<std::string>();
-      transform::SingleEntryPoint::Config cfg(input);
-
-      tb->data_map()->Add<transform::SingleEntryPoint::Config>(cfg);
-      tb->manager()->Add<transform::SingleEntryPoint>();
-    }
-  };  // struct AddTransformImpl<transform::SingleEntryPoint>
-
-  /// Implementation of AddTransform for transform::VertexPulling
-  template <>
-  struct AddTransformImpl<transform::VertexPulling> {
-    /// Add instance of transform::VertexPulling to TransformBuilder
-    /// @param tb - TransformBuilder to add transform to
-    static void impl(TransformBuilder* tb) {
-      transform::VertexPulling::Config cfg;
-      cfg.entry_point_name = tb->builder()->build<std::string>();
-      cfg.vertex_state =
-          tb->builder()->vector<transform::VertexBufferLayoutDescriptor>(
-              GenerateVertexBufferLayoutDescriptor);
-      cfg.pulling_group = tb->builder()->build<uint32_t>();
-
-      tb->data_map()->Add<transform::VertexPulling::Config>(cfg);
-      tb->manager()->Add<transform::VertexPulling>();
+    /// @brief Initializes the internal builder using seed data
+    /// @param data - data fuzzer to calculate seed from
+    /// @param size - size of data buffer
+    explicit TransformBuilder(const uint8_t* data, size_t size) : builder_(data, size) {
+        assert(data != nullptr && "|data| must be !nullptr");
     }
 
-   private:
-    /// Generate an instance of transform::VertexAttributeDescriptor
-    /// @param b - DataBuilder to use
-    static transform::VertexAttributeDescriptor
-    GenerateVertexAttributeDescriptor(DataBuilder* b) {
-      transform::VertexAttributeDescriptor desc{};
-      desc.format = b->enum_class<transform::VertexFormat>(
-          static_cast<uint8_t>(transform::VertexFormat::kLastEntry) + 1);
-      desc.offset = b->build<uint32_t>();
-      desc.shader_location = b->build<uint32_t>();
-      return desc;
+    ~TransformBuilder() = default;
+
+    /// @returns manager for transforms
+    transform::Manager* manager() { return &manager_; }
+
+    /// @returns data for transforms
+    transform::DataMap* data_map() { return &data_map_; }
+
+    /// Adds a transform and needed data to |manager_| and |data_map_|.
+    /// @tparam T - A class that inherits from transform::Transform and has an
+    ///             explicit specialization in AddTransformImpl.
+    template <typename T>
+    void AddTransform() {
+        static_assert(std::is_base_of<transform::Transform, T>::value,
+                      "T is not a transform::Transform");
+        AddTransformImpl<T>::impl(this);
     }
 
-    /// Generate an instance of VertexBufferLayoutDescriptor
-    /// @param b - DataBuilder to use
-    static transform::VertexBufferLayoutDescriptor
-    GenerateVertexBufferLayoutDescriptor(DataBuilder* b) {
-      transform::VertexBufferLayoutDescriptor desc;
-      desc.array_stride = b->build<uint32_t>();
-      desc.step_mode = b->enum_class<transform::VertexStepMode>(
-          static_cast<uint8_t>(transform::VertexStepMode::kLastEntry) + 1);
-      desc.attributes = b->vector<transform::VertexAttributeDescriptor>(
-          GenerateVertexAttributeDescriptor);
-      return desc;
+    /// Helper that invokes Add*Transform for all of the platform independent
+    /// passes.
+    void AddPlatformIndependentPasses() {
+        AddTransform<transform::Robustness>();
+        AddTransform<transform::FirstIndexOffset>();
+        AddTransform<transform::BindingRemapper>();
+        AddTransform<transform::Renamer>();
+        AddTransform<transform::SingleEntryPoint>();
+        AddTransform<transform::VertexPulling>();
     }
-  };
+
+  private:
+    DataBuilder builder_;
+    transform::Manager manager_;
+    transform::DataMap data_map_;
+
+    DataBuilder* builder() { return &builder_; }
+
+    /// Implementation of AddTransform, specialized for each transform that is
+    /// implemented. Default implementation intentionally deleted to cause compile
+    /// error if unimplemented type passed in.
+    /// @tparam T - A fuzzer transform
+    template <typename T>
+    struct AddTransformImpl;
+
+    /// Implementation of AddTransform for ShuffleTransform
+    template <>
+    struct AddTransformImpl<ShuffleTransform> {
+        /// Add instance of ShuffleTransform to TransformBuilder
+        /// @param tb - TransformBuilder to add transform to
+        static void impl(TransformBuilder* tb) {
+            tb->manager()->Add<ShuffleTransform>(tb->builder_.build<size_t>());
+        }
+    };
+
+    /// Implementation of AddTransform for transform::Robustness
+    template <>
+    struct AddTransformImpl<transform::Robustness> {
+        /// Add instance of transform::Robustness to TransformBuilder
+        /// @param tb - TransformBuilder to add transform to
+        static void impl(TransformBuilder* tb) { tb->manager()->Add<transform::Robustness>(); }
+    };
+
+    /// Implementation of AddTransform for transform::FirstIndexOffset
+    template <>
+    struct AddTransformImpl<transform::FirstIndexOffset> {
+        /// Add instance of transform::FirstIndexOffset to TransformBuilder
+        /// @param tb - TransformBuilder to add transform to
+        static void impl(TransformBuilder* tb) {
+            struct Config {
+                uint32_t group;
+                uint32_t binding;
+            };
+
+            Config config = tb->builder()->build<Config>();
+
+            tb->data_map()->Add<tint::transform::FirstIndexOffset::BindingPoint>(config.binding,
+                                                                                 config.group);
+            tb->manager()->Add<transform::FirstIndexOffset>();
+        }
+    };
+
+    /// Implementation of AddTransform for transform::BindingRemapper
+    template <>
+    struct AddTransformImpl<transform::BindingRemapper> {
+        /// Add instance of transform::BindingRemapper to TransformBuilder
+        /// @param tb - TransformBuilder to add transform to
+        static void impl(TransformBuilder* tb) {
+            struct Config {
+                uint8_t old_group;
+                uint8_t old_binding;
+                uint8_t new_group;
+                uint8_t new_binding;
+                ast::Access new_access;
+            };
+
+            std::vector<Config> configs = tb->builder()->vector<Config>();
+            transform::BindingRemapper::BindingPoints binding_points;
+            transform::BindingRemapper::AccessControls accesses;
+            for (const auto& config : configs) {
+                binding_points[{config.old_binding, config.old_group}] = {config.new_binding,
+                                                                          config.new_group};
+                accesses[{config.old_binding, config.old_group}] = config.new_access;
+            }
+
+            tb->data_map()->Add<transform::BindingRemapper::Remappings>(
+                binding_points, accesses, tb->builder()->build<bool>());
+            tb->manager()->Add<transform::BindingRemapper>();
+        }
+    };
+
+    /// Implementation of AddTransform for transform::Renamer
+    template <>
+    struct AddTransformImpl<transform::Renamer> {
+        /// Add instance of transform::Renamer to TransformBuilder
+        /// @param tb - TransformBuilder to add transform to
+        static void impl(TransformBuilder* tb) { tb->manager()->Add<transform::Renamer>(); }
+    };
+
+    /// Implementation of AddTransform for transform::SingleEntryPoint
+    template <>
+    struct AddTransformImpl<transform::SingleEntryPoint> {
+        /// Add instance of transform::SingleEntryPoint to TransformBuilder
+        /// @param tb - TransformBuilder to add transform to
+        static void impl(TransformBuilder* tb) {
+            auto input = tb->builder()->build<std::string>();
+            transform::SingleEntryPoint::Config cfg(input);
+
+            tb->data_map()->Add<transform::SingleEntryPoint::Config>(cfg);
+            tb->manager()->Add<transform::SingleEntryPoint>();
+        }
+    };  // struct AddTransformImpl<transform::SingleEntryPoint>
+
+    /// Implementation of AddTransform for transform::VertexPulling
+    template <>
+    struct AddTransformImpl<transform::VertexPulling> {
+        /// Add instance of transform::VertexPulling to TransformBuilder
+        /// @param tb - TransformBuilder to add transform to
+        static void impl(TransformBuilder* tb) {
+            transform::VertexPulling::Config cfg;
+            cfg.entry_point_name = tb->builder()->build<std::string>();
+            cfg.vertex_state = tb->builder()->vector<transform::VertexBufferLayoutDescriptor>(
+                GenerateVertexBufferLayoutDescriptor);
+            cfg.pulling_group = tb->builder()->build<uint32_t>();
+
+            tb->data_map()->Add<transform::VertexPulling::Config>(cfg);
+            tb->manager()->Add<transform::VertexPulling>();
+        }
+
+      private:
+        /// Generate an instance of transform::VertexAttributeDescriptor
+        /// @param b - DataBuilder to use
+        static transform::VertexAttributeDescriptor GenerateVertexAttributeDescriptor(
+            DataBuilder* b) {
+            transform::VertexAttributeDescriptor desc{};
+            desc.format = b->enum_class<transform::VertexFormat>(
+                static_cast<uint8_t>(transform::VertexFormat::kLastEntry) + 1);
+            desc.offset = b->build<uint32_t>();
+            desc.shader_location = b->build<uint32_t>();
+            return desc;
+        }
+
+        /// Generate an instance of VertexBufferLayoutDescriptor
+        /// @param b - DataBuilder to use
+        static transform::VertexBufferLayoutDescriptor GenerateVertexBufferLayoutDescriptor(
+            DataBuilder* b) {
+            transform::VertexBufferLayoutDescriptor desc;
+            desc.array_stride = b->build<uint32_t>();
+            desc.step_mode = b->enum_class<transform::VertexStepMode>(
+                static_cast<uint8_t>(transform::VertexStepMode::kLastEntry) + 1);
+            desc.attributes =
+                b->vector<transform::VertexAttributeDescriptor>(GenerateVertexAttributeDescriptor);
+            return desc;
+        }
+    };
 };  // class TransformBuilder
 
 }  // namespace tint::fuzzers
diff --git a/src/tint/inspector/entry_point.cc b/src/tint/inspector/entry_point.cc
index 623d22a..6d3419f 100644
--- a/src/tint/inspector/entry_point.cc
+++ b/src/tint/inspector/entry_point.cc
@@ -35,34 +35,32 @@
 EntryPoint::EntryPoint(EntryPoint&&) = default;
 EntryPoint::~EntryPoint() = default;
 
-InterpolationType ASTToInspectorInterpolationType(
-    ast::InterpolationType ast_type) {
-  switch (ast_type) {
-    case ast::InterpolationType::kPerspective:
-      return InterpolationType::kPerspective;
-    case ast::InterpolationType::kLinear:
-      return InterpolationType::kLinear;
-    case ast::InterpolationType::kFlat:
-      return InterpolationType::kFlat;
-  }
+InterpolationType ASTToInspectorInterpolationType(ast::InterpolationType ast_type) {
+    switch (ast_type) {
+        case ast::InterpolationType::kPerspective:
+            return InterpolationType::kPerspective;
+        case ast::InterpolationType::kLinear:
+            return InterpolationType::kLinear;
+        case ast::InterpolationType::kFlat:
+            return InterpolationType::kFlat;
+    }
 
-  return InterpolationType::kUnknown;
+    return InterpolationType::kUnknown;
 }
 
-InterpolationSampling ASTToInspectorInterpolationSampling(
-    ast::InterpolationSampling sampling) {
-  switch (sampling) {
-    case ast::InterpolationSampling::kNone:
-      return InterpolationSampling::kNone;
-    case ast::InterpolationSampling::kCenter:
-      return InterpolationSampling::kCenter;
-    case ast::InterpolationSampling::kCentroid:
-      return InterpolationSampling::kCentroid;
-    case ast::InterpolationSampling::kSample:
-      return InterpolationSampling::kSample;
-  }
+InterpolationSampling ASTToInspectorInterpolationSampling(ast::InterpolationSampling sampling) {
+    switch (sampling) {
+        case ast::InterpolationSampling::kNone:
+            return InterpolationSampling::kNone;
+        case ast::InterpolationSampling::kCenter:
+            return InterpolationSampling::kCenter;
+        case ast::InterpolationSampling::kCentroid:
+            return InterpolationSampling::kCentroid;
+        case ast::InterpolationSampling::kSample:
+            return InterpolationSampling::kSample;
+    }
 
-  return InterpolationSampling::kUnknown;
+    return InterpolationSampling::kUnknown;
 }
 
 }  // namespace tint::inspector
diff --git a/src/tint/inspector/entry_point.h b/src/tint/inspector/entry_point.h
index d64a8eb..b9ac4e4 100644
--- a/src/tint/inspector/entry_point.h
+++ b/src/tint/inspector/entry_point.h
@@ -26,158 +26,149 @@
 
 /// Base component type of a stage variable.
 enum class ComponentType {
-  kUnknown = -1,
-  kFloat,
-  kUInt,
-  kSInt,
+    kUnknown = -1,
+    kFloat,
+    kUInt,
+    kSInt,
 };
 
 /// Composition of components of a stage variable.
 enum class CompositionType {
-  kUnknown = -1,
-  kScalar,
-  kVec2,
-  kVec3,
-  kVec4,
+    kUnknown = -1,
+    kScalar,
+    kVec2,
+    kVec3,
+    kVec4,
 };
 
 /// Type of interpolation of a stage variable.
 enum class InterpolationType { kUnknown = -1, kPerspective, kLinear, kFlat };
 
 /// Type of interpolation sampling of a stage variable.
-enum class InterpolationSampling {
-  kUnknown = -1,
-  kNone,
-  kCenter,
-  kCentroid,
-  kSample
-};
+enum class InterpolationSampling { kUnknown = -1, kNone, kCenter, kCentroid, kSample };
 
 /// Reflection data about an entry point input or output.
 struct StageVariable {
-  /// Constructor
-  StageVariable();
-  /// Copy constructor
-  /// @param other the StageVariable to copy
-  StageVariable(const StageVariable& other);
-  /// Destructor
-  ~StageVariable();
+    /// Constructor
+    StageVariable();
+    /// Copy constructor
+    /// @param other the StageVariable to copy
+    StageVariable(const StageVariable& other);
+    /// Destructor
+    ~StageVariable();
 
-  /// Name of the variable in the shader.
-  std::string name;
-  /// Is location attribute present
-  bool has_location_attribute = false;
-  /// Value of the location attribute, only valid if #has_location_attribute is
-  /// true.
-  uint32_t location_attribute;
-  /// Is Location attribute present
-  /// [DEPRECATED]: Use #has_location_attribute
-  bool& has_location_decoration = has_location_attribute;
-  /// Value of Location Decoration, only valid if #has_location_decoration is
-  /// true.
-  /// [DEPRECATED]: Use #location_attribute
-  uint32_t& location_decoration = location_attribute;
-  /// Scalar type that the variable is composed of.
-  ComponentType component_type = ComponentType::kUnknown;
-  /// How the scalars are composed for the variable.
-  CompositionType composition_type = CompositionType::kUnknown;
-  /// Interpolation type of the variable.
-  InterpolationType interpolation_type = InterpolationType::kUnknown;
-  /// Interpolation sampling of the variable.
-  InterpolationSampling interpolation_sampling =
-      InterpolationSampling::kUnknown;
+    /// Name of the variable in the shader.
+    std::string name;
+    /// Is location attribute present
+    bool has_location_attribute = false;
+    /// Value of the location attribute, only valid if #has_location_attribute is
+    /// true.
+    uint32_t location_attribute;
+    /// Is Location attribute present
+    /// [DEPRECATED]: Use #has_location_attribute
+    bool& has_location_decoration = has_location_attribute;
+    /// Value of Location Decoration, only valid if #has_location_decoration is
+    /// true.
+    /// [DEPRECATED]: Use #location_attribute
+    uint32_t& location_decoration = location_attribute;
+    /// Scalar type that the variable is composed of.
+    ComponentType component_type = ComponentType::kUnknown;
+    /// How the scalars are composed for the variable.
+    CompositionType composition_type = CompositionType::kUnknown;
+    /// Interpolation type of the variable.
+    InterpolationType interpolation_type = InterpolationType::kUnknown;
+    /// Interpolation sampling of the variable.
+    InterpolationSampling interpolation_sampling = InterpolationSampling::kUnknown;
 };
 
 /// Convert from internal ast::InterpolationType to public ::InterpolationType.
 /// @param ast_type internal value to convert from
 /// @returns the publicly visible equivalent
-InterpolationType ASTToInspectorInterpolationType(
-    ast::InterpolationType ast_type);
+InterpolationType ASTToInspectorInterpolationType(ast::InterpolationType ast_type);
 
 /// Convert from internal ast::InterpolationSampling to public
 /// ::InterpolationSampling
 /// @param sampling internal value to convert from
 /// @returns the publicly visible equivalent
-InterpolationSampling ASTToInspectorInterpolationSampling(
-    ast::InterpolationSampling sampling);
+InterpolationSampling ASTToInspectorInterpolationSampling(ast::InterpolationSampling sampling);
 
 /// Reflection data about a pipeline overridable constant referenced by an entry
 /// point
 struct OverridableConstant {
-  /// Name of the constant
-  std::string name;
+    /// Name of the constant
+    std::string name;
 
-  /// ID of the constant
-  uint16_t numeric_id;
+    /// ID of the constant
+    uint16_t numeric_id;
 
-  /// Type of the scalar
-  enum class Type {
-    kBool,
-    kFloat32,
-    kUint32,
-    kInt32,
-  };
+    /// Type of the scalar
+    enum class Type {
+        kBool,
+        kFloat32,
+        kUint32,
+        kInt32,
+    };
 
-  /// Type of the scalar
-  Type type;
+    /// Type of the scalar
+    Type type;
 
-  /// Does this pipeline overridable constant have an initializer?
-  bool is_initialized = false;
+    /// Does this pipeline overridable constant 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 pipeline overridable constant have a numeric ID specified
+    /// explicitly?
+    bool is_numeric_id_specified = false;
 };
 
 /// Reflection data for an entry point in the shader.
 struct EntryPoint {
-  /// Constructors
-  EntryPoint();
-  /// Copy Constructor
-  EntryPoint(EntryPoint&);
-  /// Move Constructor
-  EntryPoint(EntryPoint&&);
-  ~EntryPoint();
+    /// Constructors
+    EntryPoint();
+    /// Copy Constructor
+    EntryPoint(EntryPoint&);
+    /// Move Constructor
+    EntryPoint(EntryPoint&&);
+    ~EntryPoint();
 
-  /// The entry point name
-  std::string name;
-  /// Remapped entry point name in the backend
-  std::string remapped_name;
-  /// The entry point stage
-  ast::PipelineStage stage = ast::PipelineStage::kNone;
-  /// 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;
-  /// 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;
-  /// Does the entry point use the sample_mask builtin as an input builtin
-  /// variable.
-  bool input_sample_mask_used = false;
-  /// Does the entry point use the sample_mask builtin as an output builtin
-  /// variable.
-  bool output_sample_mask_used = false;
-  /// Does the entry point use the position builtin as an input builtin
-  /// variable.
-  bool input_position_used = false;
-  /// Does the entry point use the front_facing builtin
-  bool front_facing_used = false;
-  /// Does the entry point use the sample_index builtin
-  bool sample_index_used = false;
-  /// Does the entry point use the num_workgroups builtin
-  bool num_workgroups_used = false;
+    /// The entry point name
+    std::string name;
+    /// Remapped entry point name in the backend
+    std::string remapped_name;
+    /// The entry point stage
+    ast::PipelineStage stage = ast::PipelineStage::kNone;
+    /// 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;
+    /// 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;
+    /// Does the entry point use the sample_mask builtin as an input builtin
+    /// variable.
+    bool input_sample_mask_used = false;
+    /// Does the entry point use the sample_mask builtin as an output builtin
+    /// variable.
+    bool output_sample_mask_used = false;
+    /// Does the entry point use the position builtin as an input builtin
+    /// variable.
+    bool input_position_used = false;
+    /// Does the entry point use the front_facing builtin
+    bool front_facing_used = false;
+    /// Does the entry point use the sample_index builtin
+    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);
-  }
+    /// @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 fd2185c..bdc14b0 100644
--- a/src/tint/inspector/inspector.cc
+++ b/src/tint/inspector/inspector.cc
@@ -24,24 +24,22 @@
 #include "src/tint/ast/interpolate_attribute.h"
 #include "src/tint/ast/location_attribute.h"
 #include "src/tint/ast/module.h"
-#include "src/tint/ast/sint_literal_expression.h"
-#include "src/tint/ast/uint_literal_expression.h"
 #include "src/tint/sem/array.h"
 #include "src/tint/sem/call.h"
-#include "src/tint/sem/depth_multisampled_texture_type.h"
-#include "src/tint/sem/f32_type.h"
+#include "src/tint/sem/depth_multisampled_texture.h"
+#include "src/tint/sem/f32.h"
 #include "src/tint/sem/function.h"
-#include "src/tint/sem/i32_type.h"
-#include "src/tint/sem/matrix_type.h"
-#include "src/tint/sem/multisampled_texture_type.h"
-#include "src/tint/sem/sampled_texture_type.h"
+#include "src/tint/sem/i32.h"
+#include "src/tint/sem/matrix.h"
+#include "src/tint/sem/multisampled_texture.h"
+#include "src/tint/sem/sampled_texture.h"
 #include "src/tint/sem/statement.h"
-#include "src/tint/sem/storage_texture_type.h"
+#include "src/tint/sem/storage_texture.h"
 #include "src/tint/sem/struct.h"
-#include "src/tint/sem/u32_type.h"
+#include "src/tint/sem/u32.h"
 #include "src/tint/sem/variable.h"
-#include "src/tint/sem/vector_type.h"
-#include "src/tint/sem/void_type.h"
+#include "src/tint/sem/vector.h"
+#include "src/tint/sem/void.h"
 #include "src/tint/utils/math.h"
 #include "src/tint/utils/unique_vector.h"
 
@@ -51,75 +49,73 @@
 
 void AppendResourceBindings(std::vector<ResourceBinding>* dest,
                             const std::vector<ResourceBinding>& orig) {
-  TINT_ASSERT(Inspector, dest);
-  if (!dest) {
-    return;
-  }
+    TINT_ASSERT(Inspector, dest);
+    if (!dest) {
+        return;
+    }
 
-  dest->reserve(dest->size() + orig.size());
-  dest->insert(dest->end(), orig.begin(), orig.end());
+    dest->reserve(dest->size() + orig.size());
+    dest->insert(dest->end(), orig.begin(), orig.end());
 }
 
-std::tuple<ComponentType, CompositionType> CalculateComponentAndComposition(
-    const sem::Type* type) {
-  if (type->is_float_scalar()) {
-    return {ComponentType::kFloat, CompositionType::kScalar};
-  } else if (type->is_float_vector()) {
-    auto* vec = type->As<sem::Vector>();
-    if (vec->Width() == 2) {
-      return {ComponentType::kFloat, CompositionType::kVec2};
-    } else if (vec->Width() == 3) {
-      return {ComponentType::kFloat, CompositionType::kVec3};
-    } else if (vec->Width() == 4) {
-      return {ComponentType::kFloat, CompositionType::kVec4};
+std::tuple<ComponentType, CompositionType> CalculateComponentAndComposition(const sem::Type* type) {
+    if (type->is_float_scalar()) {
+        return {ComponentType::kFloat, CompositionType::kScalar};
+    } else if (type->is_float_vector()) {
+        auto* vec = type->As<sem::Vector>();
+        if (vec->Width() == 2) {
+            return {ComponentType::kFloat, CompositionType::kVec2};
+        } else if (vec->Width() == 3) {
+            return {ComponentType::kFloat, CompositionType::kVec3};
+        } else if (vec->Width() == 4) {
+            return {ComponentType::kFloat, CompositionType::kVec4};
+        }
+    } else if (type->is_unsigned_integer_scalar()) {
+        return {ComponentType::kUInt, CompositionType::kScalar};
+    } else if (type->is_unsigned_integer_vector()) {
+        auto* vec = type->As<sem::Vector>();
+        if (vec->Width() == 2) {
+            return {ComponentType::kUInt, CompositionType::kVec2};
+        } else if (vec->Width() == 3) {
+            return {ComponentType::kUInt, CompositionType::kVec3};
+        } else if (vec->Width() == 4) {
+            return {ComponentType::kUInt, CompositionType::kVec4};
+        }
+    } else if (type->is_signed_integer_scalar()) {
+        return {ComponentType::kSInt, CompositionType::kScalar};
+    } else if (type->is_signed_integer_vector()) {
+        auto* vec = type->As<sem::Vector>();
+        if (vec->Width() == 2) {
+            return {ComponentType::kSInt, CompositionType::kVec2};
+        } else if (vec->Width() == 3) {
+            return {ComponentType::kSInt, CompositionType::kVec3};
+        } else if (vec->Width() == 4) {
+            return {ComponentType::kSInt, CompositionType::kVec4};
+        }
     }
-  } else if (type->is_unsigned_integer_scalar()) {
-    return {ComponentType::kUInt, CompositionType::kScalar};
-  } else if (type->is_unsigned_integer_vector()) {
-    auto* vec = type->As<sem::Vector>();
-    if (vec->Width() == 2) {
-      return {ComponentType::kUInt, CompositionType::kVec2};
-    } else if (vec->Width() == 3) {
-      return {ComponentType::kUInt, CompositionType::kVec3};
-    } else if (vec->Width() == 4) {
-      return {ComponentType::kUInt, CompositionType::kVec4};
-    }
-  } else if (type->is_signed_integer_scalar()) {
-    return {ComponentType::kSInt, CompositionType::kScalar};
-  } else if (type->is_signed_integer_vector()) {
-    auto* vec = type->As<sem::Vector>();
-    if (vec->Width() == 2) {
-      return {ComponentType::kSInt, CompositionType::kVec2};
-    } else if (vec->Width() == 3) {
-      return {ComponentType::kSInt, CompositionType::kVec3};
-    } else if (vec->Width() == 4) {
-      return {ComponentType::kSInt, CompositionType::kVec4};
-    }
-  }
-  return {ComponentType::kUnknown, CompositionType::kUnknown};
+    return {ComponentType::kUnknown, CompositionType::kUnknown};
 }
 
 std::tuple<InterpolationType, InterpolationSampling> CalculateInterpolationData(
     const sem::Type* type,
     const ast::AttributeList& attributes) {
-  auto* interpolation_attribute =
-      ast::GetAttribute<ast::InterpolateAttribute>(attributes);
-  if (type->is_integer_scalar_or_vector()) {
-    return {InterpolationType::kFlat, InterpolationSampling::kNone};
-  }
+    auto* interpolation_attribute = ast::GetAttribute<ast::InterpolateAttribute>(attributes);
+    if (type->is_integer_scalar_or_vector()) {
+        return {InterpolationType::kFlat, InterpolationSampling::kNone};
+    }
 
-  if (!interpolation_attribute) {
-    return {InterpolationType::kPerspective, InterpolationSampling::kCenter};
-  }
+    if (!interpolation_attribute) {
+        return {InterpolationType::kPerspective, InterpolationSampling::kCenter};
+    }
 
-  auto interpolation_type = interpolation_attribute->type;
-  auto sampling = interpolation_attribute->sampling;
-  if (interpolation_type != ast::InterpolationType::kFlat &&
-      sampling == ast::InterpolationSampling::kNone) {
-    sampling = ast::InterpolationSampling::kCenter;
-  }
-  return {ASTToInspectorInterpolationType(interpolation_type),
-          ASTToInspectorInterpolationSampling(sampling)};
+    auto interpolation_type = interpolation_attribute->type;
+    auto sampling = interpolation_attribute->sampling;
+    if (interpolation_type != ast::InterpolationType::kFlat &&
+        sampling == ast::InterpolationSampling::kNone) {
+        sampling = ast::InterpolationSampling::kCenter;
+    }
+    return {ASTToInspectorInterpolationType(interpolation_type),
+            ASTToInspectorInterpolationSampling(sampling)};
 }
 
 }  // namespace
@@ -129,826 +125,770 @@
 Inspector::~Inspector() = default;
 
 std::vector<EntryPoint> Inspector::GetEntryPoints() {
-  std::vector<EntryPoint> result;
+    std::vector<EntryPoint> result;
 
-  for (auto* func : program_->AST().Functions()) {
-    if (!func->IsEntryPoint()) {
-      continue;
-    }
-
-    auto* sem = program_->Sem().Get(func);
-
-    EntryPoint entry_point;
-    entry_point.name = program_->Symbols().NameFor(func->symbol);
-    entry_point.remapped_name = program_->Symbols().NameFor(func->symbol);
-    entry_point.stage = func->PipelineStage();
-
-    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()) {
-      AddEntryPointInOutVariables(
-          program_->Symbols().NameFor(param->Declaration()->symbol),
-          param->Type(), param->Declaration()->attributes,
-          entry_point.input_variables);
-
-      entry_point.input_position_used |=
-          ContainsBuiltin(ast::Builtin::kPosition, param->Type(),
-                          param->Declaration()->attributes);
-      entry_point.front_facing_used |=
-          ContainsBuiltin(ast::Builtin::kFrontFacing, param->Type(),
-                          param->Declaration()->attributes);
-      entry_point.sample_index_used |=
-          ContainsBuiltin(ast::Builtin::kSampleIndex, param->Type(),
-                          param->Declaration()->attributes);
-      entry_point.input_sample_mask_used |=
-          ContainsBuiltin(ast::Builtin::kSampleMask, param->Type(),
-                          param->Declaration()->attributes);
-      entry_point.num_workgroups_used |=
-          ContainsBuiltin(ast::Builtin::kNumWorkgroups, param->Type(),
-                          param->Declaration()->attributes);
-    }
-
-    if (!sem->ReturnType()->Is<sem::Void>()) {
-      AddEntryPointInOutVariables("<retval>", sem->ReturnType(),
-                                  func->return_type_attributes,
-                                  entry_point.output_variables);
-
-      entry_point.output_sample_mask_used =
-          ContainsBuiltin(ast::Builtin::kSampleMask, sem->ReturnType(),
-                          func->return_type_attributes);
-    }
-
-    for (auto* var : sem->TransitivelyReferencedGlobals()) {
-      auto* decl = var->Declaration();
-
-      auto name = program_->Symbols().NameFor(decl->symbol);
-
-      auto* global = var->As<sem::GlobalVariable>();
-      if (global && global->IsOverridable()) {
-        OverridableConstant overridable_constant;
-        overridable_constant.name = name;
-        overridable_constant.numeric_id = global->ConstantId();
-        auto* type = var->Type();
-        TINT_ASSERT(Inspector, type->is_scalar());
-        if (type->is_bool_scalar_or_vector()) {
-          overridable_constant.type = OverridableConstant::Type::kBool;
-        } else if (type->is_float_scalar()) {
-          overridable_constant.type = OverridableConstant::Type::kFloat32;
-        } else if (type->is_signed_integer_scalar()) {
-          overridable_constant.type = OverridableConstant::Type::kInt32;
-        } else if (type->is_unsigned_integer_scalar()) {
-          overridable_constant.type = OverridableConstant::Type::kUint32;
-        } else {
-          TINT_UNREACHABLE(Inspector, diagnostics_);
+    for (auto* func : program_->AST().Functions()) {
+        if (!func->IsEntryPoint()) {
+            continue;
         }
 
-        overridable_constant.is_initialized =
-            global->Declaration()->constructor;
-        overridable_constant.is_numeric_id_specified =
-            ast::HasAttribute<ast::IdAttribute>(
-                global->Declaration()->attributes);
+        auto* sem = program_->Sem().Get(func);
 
-        entry_point.overridable_constants.push_back(overridable_constant);
-      }
+        EntryPoint entry_point;
+        entry_point.name = program_->Symbols().NameFor(func->symbol);
+        entry_point.remapped_name = program_->Symbols().NameFor(func->symbol);
+        entry_point.stage = func->PipelineStage();
+
+        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()) {
+            AddEntryPointInOutVariables(program_->Symbols().NameFor(param->Declaration()->symbol),
+                                        param->Type(), param->Declaration()->attributes,
+                                        entry_point.input_variables);
+
+            entry_point.input_position_used |= ContainsBuiltin(
+                ast::Builtin::kPosition, param->Type(), param->Declaration()->attributes);
+            entry_point.front_facing_used |= ContainsBuiltin(
+                ast::Builtin::kFrontFacing, param->Type(), param->Declaration()->attributes);
+            entry_point.sample_index_used |= ContainsBuiltin(
+                ast::Builtin::kSampleIndex, param->Type(), param->Declaration()->attributes);
+            entry_point.input_sample_mask_used |= ContainsBuiltin(
+                ast::Builtin::kSampleMask, param->Type(), param->Declaration()->attributes);
+            entry_point.num_workgroups_used |= ContainsBuiltin(
+                ast::Builtin::kNumWorkgroups, param->Type(), param->Declaration()->attributes);
+        }
+
+        if (!sem->ReturnType()->Is<sem::Void>()) {
+            AddEntryPointInOutVariables("<retval>", sem->ReturnType(), func->return_type_attributes,
+                                        entry_point.output_variables);
+
+            entry_point.output_sample_mask_used = ContainsBuiltin(
+                ast::Builtin::kSampleMask, sem->ReturnType(), func->return_type_attributes);
+        }
+
+        for (auto* var : sem->TransitivelyReferencedGlobals()) {
+            auto* decl = var->Declaration();
+
+            auto name = program_->Symbols().NameFor(decl->symbol);
+
+            auto* global = var->As<sem::GlobalVariable>();
+            if (global && global->IsOverridable()) {
+                OverridableConstant overridable_constant;
+                overridable_constant.name = name;
+                overridable_constant.numeric_id = global->ConstantId();
+                auto* type = var->Type();
+                TINT_ASSERT(Inspector, type->is_scalar());
+                if (type->is_bool_scalar_or_vector()) {
+                    overridable_constant.type = OverridableConstant::Type::kBool;
+                } else if (type->is_float_scalar()) {
+                    overridable_constant.type = OverridableConstant::Type::kFloat32;
+                } else if (type->is_signed_integer_scalar()) {
+                    overridable_constant.type = OverridableConstant::Type::kInt32;
+                } else if (type->is_unsigned_integer_scalar()) {
+                    overridable_constant.type = OverridableConstant::Type::kUint32;
+                } else {
+                    TINT_UNREACHABLE(Inspector, diagnostics_);
+                }
+
+                overridable_constant.is_initialized = global->Declaration()->constructor;
+                overridable_constant.is_numeric_id_specified =
+                    ast::HasAttribute<ast::IdAttribute>(global->Declaration()->attributes);
+
+                entry_point.overridable_constants.push_back(overridable_constant);
+            }
+        }
+
+        result.push_back(std::move(entry_point));
     }
 
-    result.push_back(std::move(entry_point));
-  }
-
-  return result;
+    return result;
 }
 
 std::map<uint32_t, Scalar> Inspector::GetConstantIDs() {
-  std::map<uint32_t, Scalar> result;
-  for (auto* var : program_->AST().GlobalVariables()) {
-    auto* global = program_->Sem().Get<sem::GlobalVariable>(var);
-    if (!global || !global->IsOverridable()) {
-      continue;
+    std::map<uint32_t, Scalar> result;
+    for (auto* var : program_->AST().GlobalVariables()) {
+        auto* global = program_->Sem().Get<sem::GlobalVariable>(var);
+        if (!global || !global->IsOverridable()) {
+            continue;
+        }
+
+        // If there are conflicting defintions for a constant 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()) {
+            continue;
+        }
+
+        if (!var->constructor) {
+            result[constant_id] = Scalar();
+            continue;
+        }
+
+        auto* literal = var->constructor->As<ast::LiteralExpression>();
+        if (!literal) {
+            // This is invalid WGSL, but handling gracefully.
+            result[constant_id] = Scalar();
+            continue;
+        }
+
+        if (auto* l = literal->As<ast::BoolLiteralExpression>()) {
+            result[constant_id] = Scalar(l->value);
+            continue;
+        }
+
+        if (auto* l = literal->As<ast::IntLiteralExpression>()) {
+            switch (l->suffix) {
+                case ast::IntLiteralExpression::Suffix::kNone:
+                case ast::IntLiteralExpression::Suffix::kI:
+                    result[constant_id] = Scalar(static_cast<int32_t>(l->value));
+                    continue;
+                case ast::IntLiteralExpression::Suffix::kU:
+                    result[constant_id] = Scalar(static_cast<uint32_t>(l->value));
+                    continue;
+            }
+        }
+
+        if (auto* l = literal->As<ast::FloatLiteralExpression>()) {
+            result[constant_id] = Scalar(l->value);
+            continue;
+        }
+
+        result[constant_id] = Scalar();
     }
 
-    // If there are conflicting defintions for a constant 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()) {
-      continue;
-    }
-
-    if (!var->constructor) {
-      result[constant_id] = Scalar();
-      continue;
-    }
-
-    auto* literal = var->constructor->As<ast::LiteralExpression>();
-    if (!literal) {
-      // This is invalid WGSL, but handling gracefully.
-      result[constant_id] = Scalar();
-      continue;
-    }
-
-    if (auto* l = literal->As<ast::BoolLiteralExpression>()) {
-      result[constant_id] = Scalar(l->value);
-      continue;
-    }
-
-    if (auto* l = literal->As<ast::UintLiteralExpression>()) {
-      result[constant_id] = Scalar(l->value);
-      continue;
-    }
-
-    if (auto* l = literal->As<ast::SintLiteralExpression>()) {
-      result[constant_id] = Scalar(l->value);
-      continue;
-    }
-
-    if (auto* l = literal->As<ast::FloatLiteralExpression>()) {
-      result[constant_id] = Scalar(l->value);
-      continue;
-    }
-
-    result[constant_id] = Scalar();
-  }
-
-  return result;
+    return result;
 }
 
 std::map<std::string, uint32_t> Inspector::GetConstantNameToIdMap() {
-  std::map<std::string, uint32_t> result;
-  for (auto* var : program_->AST().GlobalVariables()) {
-    auto* global = program_->Sem().Get<sem::GlobalVariable>(var);
-    if (global && global->IsOverridable()) {
-      auto name = program_->Symbols().NameFor(var->symbol);
-      result[name] = global->ConstantId();
+    std::map<std::string, uint32_t> result;
+    for (auto* var : program_->AST().GlobalVariables()) {
+        auto* global = program_->Sem().Get<sem::GlobalVariable>(var);
+        if (global && global->IsOverridable()) {
+            auto name = program_->Symbols().NameFor(var->symbol);
+            result[name] = global->ConstantId();
+        }
     }
-  }
-  return result;
+    return result;
 }
 
 uint32_t Inspector::GetStorageSize(const std::string& entry_point) {
-  auto* func = FindEntryPointByName(entry_point);
-  if (!func) {
-    return 0;
-  }
+    auto* func = FindEntryPointByName(entry_point);
+    if (!func) {
+        return 0;
+    }
 
-  size_t size = 0;
-  auto* func_sem = program_->Sem().Get(func);
-  for (auto& ruv : func_sem->TransitivelyReferencedUniformVariables()) {
-    size += ruv.first->Type()->UnwrapRef()->Size();
-  }
-  for (auto& rsv : func_sem->TransitivelyReferencedStorageBufferVariables()) {
-    size += rsv.first->Type()->UnwrapRef()->Size();
-  }
+    size_t size = 0;
+    auto* func_sem = program_->Sem().Get(func);
+    for (auto& ruv : func_sem->TransitivelyReferencedUniformVariables()) {
+        size += ruv.first->Type()->UnwrapRef()->Size();
+    }
+    for (auto& rsv : func_sem->TransitivelyReferencedStorageBufferVariables()) {
+        size += rsv.first->Type()->UnwrapRef()->Size();
+    }
 
-  if (static_cast<uint64_t>(size) >
-      static_cast<uint64_t>(std::numeric_limits<uint32_t>::max())) {
-    return std::numeric_limits<uint32_t>::max();
-  }
-  return static_cast<uint32_t>(size);
+    if (static_cast<uint64_t>(size) > static_cast<uint64_t>(std::numeric_limits<uint32_t>::max())) {
+        return std::numeric_limits<uint32_t>::max();
+    }
+    return static_cast<uint32_t>(size);
 }
 
-std::vector<ResourceBinding> Inspector::GetResourceBindings(
-    const std::string& entry_point) {
-  auto* func = FindEntryPointByName(entry_point);
-  if (!func) {
-    return {};
-  }
+std::vector<ResourceBinding> Inspector::GetResourceBindings(const std::string& entry_point) {
+    auto* func = FindEntryPointByName(entry_point);
+    if (!func) {
+        return {};
+    }
 
-  std::vector<ResourceBinding> result;
-  for (auto fn : {
-           &Inspector::GetUniformBufferResourceBindings,
-           &Inspector::GetStorageBufferResourceBindings,
-           &Inspector::GetReadOnlyStorageBufferResourceBindings,
-           &Inspector::GetSamplerResourceBindings,
-           &Inspector::GetComparisonSamplerResourceBindings,
-           &Inspector::GetSampledTextureResourceBindings,
-           &Inspector::GetMultisampledTextureResourceBindings,
-           &Inspector::GetWriteOnlyStorageTextureResourceBindings,
-           &Inspector::GetDepthTextureResourceBindings,
-           &Inspector::GetDepthMultisampledTextureResourceBindings,
-           &Inspector::GetExternalTextureResourceBindings,
-       }) {
-    AppendResourceBindings(&result, (this->*fn)(entry_point));
-  }
-  return result;
+    std::vector<ResourceBinding> result;
+    for (auto fn : {
+             &Inspector::GetUniformBufferResourceBindings,
+             &Inspector::GetStorageBufferResourceBindings,
+             &Inspector::GetReadOnlyStorageBufferResourceBindings,
+             &Inspector::GetSamplerResourceBindings,
+             &Inspector::GetComparisonSamplerResourceBindings,
+             &Inspector::GetSampledTextureResourceBindings,
+             &Inspector::GetMultisampledTextureResourceBindings,
+             &Inspector::GetWriteOnlyStorageTextureResourceBindings,
+             &Inspector::GetDepthTextureResourceBindings,
+             &Inspector::GetDepthMultisampledTextureResourceBindings,
+             &Inspector::GetExternalTextureResourceBindings,
+         }) {
+        AppendResourceBindings(&result, (this->*fn)(entry_point));
+    }
+    return result;
 }
 
 std::vector<ResourceBinding> Inspector::GetUniformBufferResourceBindings(
     const std::string& entry_point) {
-  auto* func = FindEntryPointByName(entry_point);
-  if (!func) {
-    return {};
-  }
-
-  std::vector<ResourceBinding> result;
-
-  auto* func_sem = program_->Sem().Get(func);
-  for (auto& ruv : func_sem->TransitivelyReferencedUniformVariables()) {
-    auto* var = ruv.first;
-    auto binding_info = ruv.second;
-
-    auto* unwrapped_type = var->Type()->UnwrapRef();
-
-    ResourceBinding entry;
-    entry.resource_type = ResourceBinding::ResourceType::kUniformBuffer;
-    entry.bind_group = binding_info.group->value;
-    entry.binding = binding_info.binding->value;
-    entry.size = unwrapped_type->Size();
-    entry.size_no_padding = entry.size;
-    if (auto* str = unwrapped_type->As<sem::Struct>()) {
-      entry.size_no_padding = str->SizeNoPadding();
-    } else {
-      entry.size_no_padding = entry.size;
+    auto* func = FindEntryPointByName(entry_point);
+    if (!func) {
+        return {};
     }
 
-    result.push_back(entry);
-  }
+    std::vector<ResourceBinding> result;
 
-  return result;
+    auto* func_sem = program_->Sem().Get(func);
+    for (auto& ruv : func_sem->TransitivelyReferencedUniformVariables()) {
+        auto* var = ruv.first;
+        auto binding_info = ruv.second;
+
+        auto* unwrapped_type = var->Type()->UnwrapRef();
+
+        ResourceBinding entry;
+        entry.resource_type = ResourceBinding::ResourceType::kUniformBuffer;
+        entry.bind_group = binding_info.group->value;
+        entry.binding = binding_info.binding->value;
+        entry.size = unwrapped_type->Size();
+        entry.size_no_padding = entry.size;
+        if (auto* str = unwrapped_type->As<sem::Struct>()) {
+            entry.size_no_padding = str->SizeNoPadding();
+        } else {
+            entry.size_no_padding = entry.size;
+        }
+
+        result.push_back(entry);
+    }
+
+    return result;
 }
 
 std::vector<ResourceBinding> Inspector::GetStorageBufferResourceBindings(
     const std::string& entry_point) {
-  return GetStorageBufferResourceBindingsImpl(entry_point, false);
+    return GetStorageBufferResourceBindingsImpl(entry_point, false);
 }
 
-std::vector<ResourceBinding>
-Inspector::GetReadOnlyStorageBufferResourceBindings(
+std::vector<ResourceBinding> Inspector::GetReadOnlyStorageBufferResourceBindings(
     const std::string& entry_point) {
-  return GetStorageBufferResourceBindingsImpl(entry_point, true);
+    return GetStorageBufferResourceBindingsImpl(entry_point, true);
 }
 
-std::vector<ResourceBinding> Inspector::GetSamplerResourceBindings(
-    const std::string& entry_point) {
-  auto* func = FindEntryPointByName(entry_point);
-  if (!func) {
-    return {};
-  }
+std::vector<ResourceBinding> Inspector::GetSamplerResourceBindings(const std::string& entry_point) {
+    auto* func = FindEntryPointByName(entry_point);
+    if (!func) {
+        return {};
+    }
 
-  std::vector<ResourceBinding> result;
+    std::vector<ResourceBinding> result;
 
-  auto* func_sem = program_->Sem().Get(func);
-  for (auto& rs : func_sem->TransitivelyReferencedSamplerVariables()) {
-    auto binding_info = rs.second;
+    auto* func_sem = program_->Sem().Get(func);
+    for (auto& rs : func_sem->TransitivelyReferencedSamplerVariables()) {
+        auto binding_info = rs.second;
 
-    ResourceBinding entry;
-    entry.resource_type = ResourceBinding::ResourceType::kSampler;
-    entry.bind_group = binding_info.group->value;
-    entry.binding = binding_info.binding->value;
+        ResourceBinding entry;
+        entry.resource_type = ResourceBinding::ResourceType::kSampler;
+        entry.bind_group = binding_info.group->value;
+        entry.binding = binding_info.binding->value;
 
-    result.push_back(entry);
-  }
+        result.push_back(entry);
+    }
 
-  return result;
+    return result;
 }
 
 std::vector<ResourceBinding> Inspector::GetComparisonSamplerResourceBindings(
     const std::string& entry_point) {
-  auto* func = FindEntryPointByName(entry_point);
-  if (!func) {
-    return {};
-  }
+    auto* func = FindEntryPointByName(entry_point);
+    if (!func) {
+        return {};
+    }
 
-  std::vector<ResourceBinding> result;
+    std::vector<ResourceBinding> result;
 
-  auto* func_sem = program_->Sem().Get(func);
-  for (auto& rcs :
-       func_sem->TransitivelyReferencedComparisonSamplerVariables()) {
-    auto binding_info = rcs.second;
+    auto* func_sem = program_->Sem().Get(func);
+    for (auto& rcs : func_sem->TransitivelyReferencedComparisonSamplerVariables()) {
+        auto binding_info = rcs.second;
 
-    ResourceBinding entry;
-    entry.resource_type = ResourceBinding::ResourceType::kComparisonSampler;
-    entry.bind_group = binding_info.group->value;
-    entry.binding = binding_info.binding->value;
+        ResourceBinding entry;
+        entry.resource_type = ResourceBinding::ResourceType::kComparisonSampler;
+        entry.bind_group = binding_info.group->value;
+        entry.binding = binding_info.binding->value;
 
-    result.push_back(entry);
-  }
+        result.push_back(entry);
+    }
 
-  return result;
+    return result;
 }
 
 std::vector<ResourceBinding> Inspector::GetSampledTextureResourceBindings(
     const std::string& entry_point) {
-  return GetSampledTextureResourceBindingsImpl(entry_point, false);
+    return GetSampledTextureResourceBindingsImpl(entry_point, false);
 }
 
 std::vector<ResourceBinding> Inspector::GetMultisampledTextureResourceBindings(
     const std::string& entry_point) {
-  return GetSampledTextureResourceBindingsImpl(entry_point, true);
+    return GetSampledTextureResourceBindingsImpl(entry_point, true);
 }
 
-std::vector<ResourceBinding>
-Inspector::GetWriteOnlyStorageTextureResourceBindings(
+std::vector<ResourceBinding> Inspector::GetWriteOnlyStorageTextureResourceBindings(
     const std::string& entry_point) {
-  return GetStorageTextureResourceBindingsImpl(entry_point);
+    return GetStorageTextureResourceBindingsImpl(entry_point);
 }
 
 std::vector<ResourceBinding> Inspector::GetTextureResourceBindings(
     const std::string& entry_point,
     const tint::TypeInfo* texture_type,
     ResourceBinding::ResourceType resource_type) {
-  auto* func = FindEntryPointByName(entry_point);
-  if (!func) {
-    return {};
-  }
+    auto* func = FindEntryPointByName(entry_point);
+    if (!func) {
+        return {};
+    }
 
-  std::vector<ResourceBinding> result;
-  auto* func_sem = program_->Sem().Get(func);
-  for (auto& ref :
-       func_sem->TransitivelyReferencedVariablesOfType(texture_type)) {
-    auto* var = ref.first;
-    auto binding_info = ref.second;
+    std::vector<ResourceBinding> result;
+    auto* func_sem = program_->Sem().Get(func);
+    for (auto& ref : func_sem->TransitivelyReferencedVariablesOfType(texture_type)) {
+        auto* var = ref.first;
+        auto binding_info = ref.second;
 
-    ResourceBinding entry;
-    entry.resource_type = resource_type;
-    entry.bind_group = binding_info.group->value;
-    entry.binding = binding_info.binding->value;
+        ResourceBinding entry;
+        entry.resource_type = resource_type;
+        entry.bind_group = binding_info.group->value;
+        entry.binding = binding_info.binding->value;
 
-    auto* tex = var->Type()->UnwrapRef()->As<sem::Texture>();
-    entry.dim =
-        TypeTextureDimensionToResourceBindingTextureDimension(tex->dim());
+        auto* tex = var->Type()->UnwrapRef()->As<sem::Texture>();
+        entry.dim = TypeTextureDimensionToResourceBindingTextureDimension(tex->dim());
 
-    result.push_back(entry);
-  }
+        result.push_back(entry);
+    }
 
-  return result;
+    return result;
 }
 
 std::vector<ResourceBinding> Inspector::GetDepthTextureResourceBindings(
     const std::string& entry_point) {
-  return GetTextureResourceBindings(
-      entry_point, &TypeInfo::Of<sem::DepthTexture>(),
-      ResourceBinding::ResourceType::kDepthTexture);
+    return GetTextureResourceBindings(entry_point, &TypeInfo::Of<sem::DepthTexture>(),
+                                      ResourceBinding::ResourceType::kDepthTexture);
 }
 
-std::vector<ResourceBinding>
-Inspector::GetDepthMultisampledTextureResourceBindings(
+std::vector<ResourceBinding> Inspector::GetDepthMultisampledTextureResourceBindings(
     const std::string& entry_point) {
-  return GetTextureResourceBindings(
-      entry_point, &TypeInfo::Of<sem::DepthMultisampledTexture>(),
-      ResourceBinding::ResourceType::kDepthMultisampledTexture);
+    return GetTextureResourceBindings(entry_point, &TypeInfo::Of<sem::DepthMultisampledTexture>(),
+                                      ResourceBinding::ResourceType::kDepthMultisampledTexture);
 }
 
 std::vector<ResourceBinding> Inspector::GetExternalTextureResourceBindings(
     const std::string& entry_point) {
-  return GetTextureResourceBindings(
-      entry_point, &TypeInfo::Of<sem::ExternalTexture>(),
-      ResourceBinding::ResourceType::kExternalTexture);
+    return GetTextureResourceBindings(entry_point, &TypeInfo::Of<sem::ExternalTexture>(),
+                                      ResourceBinding::ResourceType::kExternalTexture);
 }
 
 std::vector<sem::SamplerTexturePair> Inspector::GetSamplerTextureUses(
     const std::string& entry_point) {
-  auto* func = FindEntryPointByName(entry_point);
-  if (!func) {
-    return {};
-  }
+    auto* func = FindEntryPointByName(entry_point);
+    if (!func) {
+        return {};
+    }
 
-  GenerateSamplerTargets();
+    GenerateSamplerTargets();
 
-  auto it = sampler_targets_->find(entry_point);
-  if (it == sampler_targets_->end()) {
-    return {};
-  }
-  return it->second;
+    auto it = sampler_targets_->find(entry_point);
+    if (it == sampler_targets_->end()) {
+        return {};
+    }
+    return it->second;
 }
 
 std::vector<sem::SamplerTexturePair> Inspector::GetSamplerTextureUses(
     const std::string& entry_point,
     const sem::BindingPoint& placeholder) {
-  auto* func = FindEntryPointByName(entry_point);
-  if (!func) {
-    return {};
-  }
-  auto* func_sem = program_->Sem().Get(func);
+    auto* func = FindEntryPointByName(entry_point);
+    if (!func) {
+        return {};
+    }
+    auto* func_sem = program_->Sem().Get(func);
 
-  std::vector<sem::SamplerTexturePair> new_pairs;
-  for (auto pair : func_sem->TextureSamplerPairs()) {
-    auto* texture = pair.first->As<sem::GlobalVariable>();
-    auto* sampler =
-        pair.second ? pair.second->As<sem::GlobalVariable>() : nullptr;
-    SamplerTexturePair new_pair;
-    new_pair.sampler_binding_point =
-        sampler ? sampler->BindingPoint() : placeholder;
-    new_pair.texture_binding_point = texture->BindingPoint();
-    new_pairs.push_back(new_pair);
-  }
-  return new_pairs;
+    std::vector<sem::SamplerTexturePair> new_pairs;
+    for (auto pair : func_sem->TextureSamplerPairs()) {
+        auto* texture = pair.first->As<sem::GlobalVariable>();
+        auto* sampler = pair.second ? pair.second->As<sem::GlobalVariable>() : nullptr;
+        SamplerTexturePair new_pair;
+        new_pair.sampler_binding_point = sampler ? sampler->BindingPoint() : placeholder;
+        new_pair.texture_binding_point = texture->BindingPoint();
+        new_pairs.push_back(new_pair);
+    }
+    return new_pairs;
 }
 
 uint32_t Inspector::GetWorkgroupStorageSize(const std::string& entry_point) {
-  auto* func = FindEntryPointByName(entry_point);
-  if (!func) {
-    return 0;
-  }
-
-  uint32_t total_size = 0;
-  auto* func_sem = program_->Sem().Get(func);
-  for (const sem::Variable* var : func_sem->TransitivelyReferencedGlobals()) {
-    if (var->StorageClass() == ast::StorageClass::kWorkgroup) {
-      auto* ty = var->Type()->UnwrapRef();
-      uint32_t align = ty->Align();
-      uint32_t size = ty->Size();
-
-      // This essentially matches std430 layout rules from GLSL, which are in
-      // turn specified as an upper bound for Vulkan layout sizing. Since D3D
-      // and Metal are even less specific, we assume Vulkan behavior as a
-      // good-enough approximation everywhere.
-      total_size += utils::RoundUp(align, size);
+    auto* func = FindEntryPointByName(entry_point);
+    if (!func) {
+        return 0;
     }
-  }
 
-  return total_size;
+    uint32_t total_size = 0;
+    auto* func_sem = program_->Sem().Get(func);
+    for (const sem::Variable* var : func_sem->TransitivelyReferencedGlobals()) {
+        if (var->StorageClass() == ast::StorageClass::kWorkgroup) {
+            auto* ty = var->Type()->UnwrapRef();
+            uint32_t align = ty->Align();
+            uint32_t size = ty->Size();
+
+            // This essentially matches std430 layout rules from GLSL, which are in
+            // turn specified as an upper bound for Vulkan layout sizing. Since D3D
+            // and Metal are even less specific, we assume Vulkan behavior as a
+            // good-enough approximation everywhere.
+            total_size += utils::RoundUp(align, size);
+        }
+    }
+
+    return total_size;
+}
+
+std::vector<std::string> Inspector::GetUsedExtensionNames() {
+    std::vector<std::string> result;
+
+    ast::ExtensionSet set = program_->AST().Extensions();
+    result.reserve(set.size());
+    for (auto kind : set) {
+        std::string name = ast::Enable::KindToName(kind);
+        result.push_back(name);
+    }
+
+    return result;
+}
+
+std::vector<std::pair<std::string, Source>> Inspector::GetEnableDirectives() {
+    std::vector<std::pair<std::string, Source>> result;
+
+    // Ast nodes for enable directive are stored within global declarations list
+    auto global_decls = program_->AST().GlobalDeclarations();
+    for (auto* node : global_decls) {
+        if (auto* ext = node->As<ast::Enable>()) {
+            result.push_back({ext->name, ext->source});
+        }
+    }
+
+    return result;
 }
 
 const ast::Function* Inspector::FindEntryPointByName(const std::string& name) {
-  auto* func = program_->AST().Functions().Find(program_->Symbols().Get(name));
-  if (!func) {
-    diagnostics_.add_error(diag::System::Inspector, name + " was not found!");
-    return nullptr;
-  }
+    auto* func = program_->AST().Functions().Find(program_->Symbols().Get(name));
+    if (!func) {
+        diagnostics_.add_error(diag::System::Inspector, name + " was not found!");
+        return nullptr;
+    }
 
-  if (!func->IsEntryPoint()) {
-    diagnostics_.add_error(diag::System::Inspector,
-                           name + " is not an entry point!");
-    return nullptr;
-  }
+    if (!func->IsEntryPoint()) {
+        diagnostics_.add_error(diag::System::Inspector, name + " is not an entry point!");
+        return nullptr;
+    }
 
-  return func;
+    return func;
 }
 
-void Inspector::AddEntryPointInOutVariables(
-    std::string name,
-    const sem::Type* type,
-    const ast::AttributeList& attributes,
-    std::vector<StageVariable>& variables) const {
-  // Skip builtins.
-  if (ast::HasAttribute<ast::BuiltinAttribute>(attributes)) {
-    return;
-  }
-
-  auto* unwrapped_type = type->UnwrapRef();
-
-  if (auto* struct_ty = unwrapped_type->As<sem::Struct>()) {
-    // Recurse into members.
-    for (auto* member : struct_ty->Members()) {
-      AddEntryPointInOutVariables(
-          name + "." +
-              program_->Symbols().NameFor(member->Declaration()->symbol),
-          member->Type(), member->Declaration()->attributes, variables);
+void Inspector::AddEntryPointInOutVariables(std::string name,
+                                            const sem::Type* type,
+                                            const ast::AttributeList& attributes,
+                                            std::vector<StageVariable>& variables) const {
+    // Skip builtins.
+    if (ast::HasAttribute<ast::BuiltinAttribute>(attributes)) {
+        return;
     }
-    return;
-  }
 
-  // Base case: add the variable.
+    auto* unwrapped_type = type->UnwrapRef();
 
-  StageVariable stage_variable;
-  stage_variable.name = name;
-  std::tie(stage_variable.component_type, stage_variable.composition_type) =
-      CalculateComponentAndComposition(type);
+    if (auto* struct_ty = unwrapped_type->As<sem::Struct>()) {
+        // Recurse into members.
+        for (auto* member : struct_ty->Members()) {
+            AddEntryPointInOutVariables(
+                name + "." + program_->Symbols().NameFor(member->Declaration()->symbol),
+                member->Type(), member->Declaration()->attributes, variables);
+        }
+        return;
+    }
 
-  auto* location = ast::GetAttribute<ast::LocationAttribute>(attributes);
-  TINT_ASSERT(Inspector, location != nullptr);
-  stage_variable.has_location_attribute = true;
-  stage_variable.location_attribute = location->value;
+    // Base case: add the variable.
 
-  std::tie(stage_variable.interpolation_type,
-           stage_variable.interpolation_sampling) =
-      CalculateInterpolationData(type, attributes);
+    StageVariable stage_variable;
+    stage_variable.name = name;
+    std::tie(stage_variable.component_type, stage_variable.composition_type) =
+        CalculateComponentAndComposition(type);
 
-  variables.push_back(stage_variable);
+    auto* location = ast::GetAttribute<ast::LocationAttribute>(attributes);
+    TINT_ASSERT(Inspector, location != nullptr);
+    stage_variable.has_location_attribute = true;
+    stage_variable.location_attribute = location->value;
+
+    std::tie(stage_variable.interpolation_type, stage_variable.interpolation_sampling) =
+        CalculateInterpolationData(type, attributes);
+
+    variables.push_back(stage_variable);
 }
 
 bool Inspector::ContainsBuiltin(ast::Builtin builtin,
                                 const sem::Type* type,
                                 const ast::AttributeList& attributes) const {
-  auto* unwrapped_type = type->UnwrapRef();
+    auto* unwrapped_type = type->UnwrapRef();
 
-  if (auto* struct_ty = unwrapped_type->As<sem::Struct>()) {
-    // Recurse into members.
-    for (auto* member : struct_ty->Members()) {
-      if (ContainsBuiltin(builtin, member->Type(),
-                          member->Declaration()->attributes)) {
-        return true;
-      }
+    if (auto* struct_ty = unwrapped_type->As<sem::Struct>()) {
+        // Recurse into members.
+        for (auto* member : struct_ty->Members()) {
+            if (ContainsBuiltin(builtin, member->Type(), member->Declaration()->attributes)) {
+                return true;
+            }
+        }
+        return false;
     }
-    return false;
-  }
 
-  // Base case: check for builtin
-  auto* builtin_declaration =
-      ast::GetAttribute<ast::BuiltinAttribute>(attributes);
-  if (!builtin_declaration || builtin_declaration->builtin != builtin) {
-    return false;
-  }
+    // Base case: check for builtin
+    auto* builtin_declaration = ast::GetAttribute<ast::BuiltinAttribute>(attributes);
+    if (!builtin_declaration || builtin_declaration->builtin != builtin) {
+        return false;
+    }
 
-  return true;
+    return true;
 }
 
 std::vector<ResourceBinding> Inspector::GetStorageBufferResourceBindingsImpl(
     const std::string& entry_point,
     bool read_only) {
-  auto* func = FindEntryPointByName(entry_point);
-  if (!func) {
-    return {};
-  }
-
-  auto* func_sem = program_->Sem().Get(func);
-  std::vector<ResourceBinding> result;
-  for (auto& rsv : func_sem->TransitivelyReferencedStorageBufferVariables()) {
-    auto* var = rsv.first;
-    auto binding_info = rsv.second;
-
-    if (read_only != (var->Access() == ast::Access::kRead)) {
-      continue;
+    auto* func = FindEntryPointByName(entry_point);
+    if (!func) {
+        return {};
     }
 
-    auto* unwrapped_type = var->Type()->UnwrapRef();
+    auto* func_sem = program_->Sem().Get(func);
+    std::vector<ResourceBinding> result;
+    for (auto& rsv : func_sem->TransitivelyReferencedStorageBufferVariables()) {
+        auto* var = rsv.first;
+        auto binding_info = rsv.second;
 
-    ResourceBinding entry;
-    entry.resource_type =
-        read_only ? ResourceBinding::ResourceType::kReadOnlyStorageBuffer
-                  : ResourceBinding::ResourceType::kStorageBuffer;
-    entry.bind_group = binding_info.group->value;
-    entry.binding = binding_info.binding->value;
-    entry.size = unwrapped_type->Size();
-    if (auto* str = unwrapped_type->As<sem::Struct>()) {
-      entry.size_no_padding = str->SizeNoPadding();
-    } else {
-      entry.size_no_padding = entry.size;
+        if (read_only != (var->Access() == ast::Access::kRead)) {
+            continue;
+        }
+
+        auto* unwrapped_type = var->Type()->UnwrapRef();
+
+        ResourceBinding entry;
+        entry.resource_type = read_only ? ResourceBinding::ResourceType::kReadOnlyStorageBuffer
+                                        : ResourceBinding::ResourceType::kStorageBuffer;
+        entry.bind_group = binding_info.group->value;
+        entry.binding = binding_info.binding->value;
+        entry.size = unwrapped_type->Size();
+        if (auto* str = unwrapped_type->As<sem::Struct>()) {
+            entry.size_no_padding = str->SizeNoPadding();
+        } else {
+            entry.size_no_padding = entry.size;
+        }
+
+        result.push_back(entry);
     }
 
-    result.push_back(entry);
-  }
-
-  return result;
+    return result;
 }
 
 std::vector<ResourceBinding> Inspector::GetSampledTextureResourceBindingsImpl(
     const std::string& entry_point,
     bool multisampled_only) {
-  auto* func = FindEntryPointByName(entry_point);
-  if (!func) {
-    return {};
-  }
-
-  std::vector<ResourceBinding> result;
-  auto* func_sem = program_->Sem().Get(func);
-  auto referenced_variables =
-      multisampled_only
-          ? func_sem->TransitivelyReferencedMultisampledTextureVariables()
-          : func_sem->TransitivelyReferencedSampledTextureVariables();
-  for (auto& ref : referenced_variables) {
-    auto* var = ref.first;
-    auto binding_info = ref.second;
-
-    ResourceBinding entry;
-    entry.resource_type =
-        multisampled_only ? ResourceBinding::ResourceType::kMultisampledTexture
-                          : ResourceBinding::ResourceType::kSampledTexture;
-    entry.bind_group = binding_info.group->value;
-    entry.binding = binding_info.binding->value;
-
-    auto* texture_type = var->Type()->UnwrapRef()->As<sem::Texture>();
-    entry.dim = TypeTextureDimensionToResourceBindingTextureDimension(
-        texture_type->dim());
-
-    const sem::Type* base_type = nullptr;
-    if (multisampled_only) {
-      base_type = texture_type->As<sem::MultisampledTexture>()->type();
-    } else {
-      base_type = texture_type->As<sem::SampledTexture>()->type();
+    auto* func = FindEntryPointByName(entry_point);
+    if (!func) {
+        return {};
     }
-    entry.sampled_kind = BaseTypeToSampledKind(base_type);
 
-    result.push_back(entry);
-  }
+    std::vector<ResourceBinding> result;
+    auto* func_sem = program_->Sem().Get(func);
+    auto referenced_variables = multisampled_only
+                                    ? func_sem->TransitivelyReferencedMultisampledTextureVariables()
+                                    : func_sem->TransitivelyReferencedSampledTextureVariables();
+    for (auto& ref : referenced_variables) {
+        auto* var = ref.first;
+        auto binding_info = ref.second;
 
-  return result;
+        ResourceBinding entry;
+        entry.resource_type = multisampled_only
+                                  ? ResourceBinding::ResourceType::kMultisampledTexture
+                                  : ResourceBinding::ResourceType::kSampledTexture;
+        entry.bind_group = binding_info.group->value;
+        entry.binding = binding_info.binding->value;
+
+        auto* texture_type = var->Type()->UnwrapRef()->As<sem::Texture>();
+        entry.dim = TypeTextureDimensionToResourceBindingTextureDimension(texture_type->dim());
+
+        const sem::Type* base_type = nullptr;
+        if (multisampled_only) {
+            base_type = texture_type->As<sem::MultisampledTexture>()->type();
+        } else {
+            base_type = texture_type->As<sem::SampledTexture>()->type();
+        }
+        entry.sampled_kind = BaseTypeToSampledKind(base_type);
+
+        result.push_back(entry);
+    }
+
+    return result;
 }
 
 std::vector<ResourceBinding> Inspector::GetStorageTextureResourceBindingsImpl(
     const std::string& entry_point) {
-  auto* func = FindEntryPointByName(entry_point);
-  if (!func) {
-    return {};
-  }
+    auto* func = FindEntryPointByName(entry_point);
+    if (!func) {
+        return {};
+    }
 
-  auto* func_sem = program_->Sem().Get(func);
-  std::vector<ResourceBinding> result;
-  for (auto& ref :
-       func_sem->TransitivelyReferencedVariablesOfType<sem::StorageTexture>()) {
-    auto* var = ref.first;
-    auto binding_info = ref.second;
+    auto* func_sem = program_->Sem().Get(func);
+    std::vector<ResourceBinding> result;
+    for (auto& ref : func_sem->TransitivelyReferencedVariablesOfType<sem::StorageTexture>()) {
+        auto* var = ref.first;
+        auto binding_info = ref.second;
 
-    auto* texture_type = var->Type()->UnwrapRef()->As<sem::StorageTexture>();
+        auto* texture_type = var->Type()->UnwrapRef()->As<sem::StorageTexture>();
 
-    ResourceBinding entry;
-    entry.resource_type =
-        ResourceBinding::ResourceType::kWriteOnlyStorageTexture;
-    entry.bind_group = binding_info.group->value;
-    entry.binding = binding_info.binding->value;
+        ResourceBinding entry;
+        entry.resource_type = ResourceBinding::ResourceType::kWriteOnlyStorageTexture;
+        entry.bind_group = binding_info.group->value;
+        entry.binding = binding_info.binding->value;
 
-    entry.dim = TypeTextureDimensionToResourceBindingTextureDimension(
-        texture_type->dim());
+        entry.dim = TypeTextureDimensionToResourceBindingTextureDimension(texture_type->dim());
 
-    auto* base_type = texture_type->type();
-    entry.sampled_kind = BaseTypeToSampledKind(base_type);
-    entry.image_format = TypeTexelFormatToResourceBindingTexelFormat(
-        texture_type->texel_format());
+        auto* base_type = texture_type->type();
+        entry.sampled_kind = BaseTypeToSampledKind(base_type);
+        entry.image_format =
+            TypeTexelFormatToResourceBindingTexelFormat(texture_type->texel_format());
 
-    result.push_back(entry);
-  }
+        result.push_back(entry);
+    }
 
-  return result;
+    return result;
 }
 
 void Inspector::GenerateSamplerTargets() {
-  // Do not re-generate, since |program_| should not change during the lifetime
-  // of the inspector.
-  if (sampler_targets_ != nullptr) {
-    return;
-  }
-
-  sampler_targets_ = std::make_unique<std::unordered_map<
-      std::string, utils::UniqueVector<sem::SamplerTexturePair>>>();
-
-  auto& sem = program_->Sem();
-
-  for (auto* node : program_->ASTNodes().Objects()) {
-    auto* c = node->As<ast::CallExpression>();
-    if (!c) {
-      continue;
+    // Do not re-generate, since |program_| should not change during the lifetime
+    // of the inspector.
+    if (sampler_targets_ != nullptr) {
+        return;
     }
 
-    auto* call = sem.Get(c);
-    if (!call) {
-      continue;
+    sampler_targets_ = std::make_unique<
+        std::unordered_map<std::string, utils::UniqueVector<sem::SamplerTexturePair>>>();
+
+    auto& sem = program_->Sem();
+
+    for (auto* node : program_->ASTNodes().Objects()) {
+        auto* c = node->As<ast::CallExpression>();
+        if (!c) {
+            continue;
+        }
+
+        auto* call = sem.Get(c);
+        if (!call) {
+            continue;
+        }
+
+        auto* i = call->Target()->As<sem::Builtin>();
+        if (!i) {
+            continue;
+        }
+
+        const auto& signature = i->Signature();
+        int sampler_index = signature.IndexOf(sem::ParameterUsage::kSampler);
+        if (sampler_index == -1) {
+            continue;
+        }
+
+        int texture_index = signature.IndexOf(sem::ParameterUsage::kTexture);
+        if (texture_index == -1) {
+            continue;
+        }
+
+        auto* call_func = call->Stmt()->Function();
+        std::vector<const sem::Function*> entry_points;
+        if (call_func->Declaration()->IsEntryPoint()) {
+            entry_points = {call_func};
+        } else {
+            entry_points = call_func->AncestorEntryPoints();
+        }
+
+        if (entry_points.empty()) {
+            continue;
+        }
+
+        auto* t = c->args[texture_index];
+        auto* s = c->args[sampler_index];
+
+        GetOriginatingResources(std::array<const ast::Expression*, 2>{t, s},
+                                [&](std::array<const sem::GlobalVariable*, 2> globals) {
+                                    auto* texture = globals[0];
+                                    sem::BindingPoint texture_binding_point = {
+                                        texture->Declaration()->BindingPoint().group->value,
+                                        texture->Declaration()->BindingPoint().binding->value};
+
+                                    auto* sampler = globals[1];
+                                    sem::BindingPoint sampler_binding_point = {
+                                        sampler->Declaration()->BindingPoint().group->value,
+                                        sampler->Declaration()->BindingPoint().binding->value};
+
+                                    for (auto* entry_point : entry_points) {
+                                        const auto& ep_name = program_->Symbols().NameFor(
+                                            entry_point->Declaration()->symbol);
+                                        (*sampler_targets_)[ep_name].add(
+                                            {sampler_binding_point, texture_binding_point});
+                                    }
+                                });
     }
-
-    auto* i = call->Target()->As<sem::Builtin>();
-    if (!i) {
-      continue;
-    }
-
-    const auto& signature = i->Signature();
-    int sampler_index = signature.IndexOf(sem::ParameterUsage::kSampler);
-    if (sampler_index == -1) {
-      continue;
-    }
-
-    int texture_index = signature.IndexOf(sem::ParameterUsage::kTexture);
-    if (texture_index == -1) {
-      continue;
-    }
-
-    auto* call_func = call->Stmt()->Function();
-    std::vector<const sem::Function*> entry_points;
-    if (call_func->Declaration()->IsEntryPoint()) {
-      entry_points = {call_func};
-    } else {
-      entry_points = call_func->AncestorEntryPoints();
-    }
-
-    if (entry_points.empty()) {
-      continue;
-    }
-
-    auto* t = c->args[texture_index];
-    auto* s = c->args[sampler_index];
-
-    GetOriginatingResources(
-        std::array<const ast::Expression*, 2>{t, s},
-        [&](std::array<const sem::GlobalVariable*, 2> globals) {
-          auto* texture = globals[0];
-          sem::BindingPoint texture_binding_point = {
-              texture->Declaration()->BindingPoint().group->value,
-              texture->Declaration()->BindingPoint().binding->value};
-
-          auto* sampler = globals[1];
-          sem::BindingPoint sampler_binding_point = {
-              sampler->Declaration()->BindingPoint().group->value,
-              sampler->Declaration()->BindingPoint().binding->value};
-
-          for (auto* entry_point : entry_points) {
-            const auto& ep_name =
-                program_->Symbols().NameFor(entry_point->Declaration()->symbol);
-            (*sampler_targets_)[ep_name].add(
-                {sampler_binding_point, texture_binding_point});
-          }
-        });
-  }
 }
 
 template <size_t N, typename F>
-void Inspector::GetOriginatingResources(
-    std::array<const ast::Expression*, N> exprs,
-    F&& callback) {
-  if (!program_->IsValid()) {
-    TINT_ICE(Inspector, diagnostics_)
-        << "attempting to get originating resources in invalid program";
-    return;
-  }
-
-  auto& sem = program_->Sem();
-
-  std::array<const sem::GlobalVariable*, N> globals{};
-  std::array<const sem::Parameter*, N> parameters{};
-  utils::UniqueVector<const ast::CallExpression*> callsites;
-
-  for (size_t i = 0; i < N; i++) {
-    auto*& expr = exprs[i];
-    // Resolve each of the expressions
-    while (true) {
-      if (auto* user = sem.Get<sem::VariableUser>(expr)) {
-        auto* var = user->Variable();
-
-        if (auto* global = tint::As<sem::GlobalVariable>(var)) {
-          // Found the global resource declaration.
-          globals[i] = global;
-          break;  // Done with this expression.
-        }
-
-        if (auto* local = tint::As<sem::LocalVariable>(var)) {
-          // Chase the variable
-          expr = local->Declaration()->constructor;
-          if (!expr) {
-            TINT_ICE(Inspector, diagnostics_)
-                << "resource variable had no initializer";
-            return;
-          }
-          continue;  // Continue chasing the expression in this function
-        }
-
-        if (auto* param = tint::As<sem::Parameter>(var)) {
-          // Gather each of the callers of this function
-          auto* func = tint::As<sem::Function>(param->Owner());
-          if (func->CallSites().empty()) {
-            // One or more of the expressions is a parameter, but this function
-            // is not called. Ignore.
-            return;
-          }
-          for (auto* call : func->CallSites()) {
-            callsites.add(call->Declaration());
-          }
-          // Need to evaluate each function call with the group of
-          // expressions, so move on to the next expression.
-          parameters[i] = param;
-          break;
-        }
-
+void Inspector::GetOriginatingResources(std::array<const ast::Expression*, N> exprs, F&& callback) {
+    if (!program_->IsValid()) {
         TINT_ICE(Inspector, diagnostics_)
-            << "unexpected variable type " << var->TypeInfo().name;
-      }
+            << "attempting to get originating resources in invalid program";
+        return;
+    }
 
-      if (auto* unary = tint::As<ast::UnaryOpExpression>(expr)) {
-        switch (unary->op) {
-          case ast::UnaryOp::kAddressOf:
-          case ast::UnaryOp::kIndirection:
-            // `*` and `&` are the only valid unary ops for a resource type,
-            // and must be balanced in order for the program to have passed
-            // validation. Just skip past these.
-            expr = unary->expr;
-            continue;
-          default: {
+    auto& sem = program_->Sem();
+
+    std::array<const sem::GlobalVariable*, N> globals{};
+    std::array<const sem::Parameter*, N> parameters{};
+    utils::UniqueVector<const ast::CallExpression*> callsites;
+
+    for (size_t i = 0; i < N; i++) {
+        const sem::Variable* source_var = sem.Get(exprs[i])->SourceVariable();
+        if (auto* global = source_var->As<sem::GlobalVariable>()) {
+            globals[i] = global;
+        } else if (auto* param = source_var->As<sem::Parameter>()) {
+            auto* func = tint::As<sem::Function>(param->Owner());
+            if (func->CallSites().empty()) {
+                // One or more of the expressions is a parameter, but this function
+                // is not called. Ignore.
+                return;
+            }
+            for (auto* call : func->CallSites()) {
+                callsites.add(call->Declaration());
+            }
+            parameters[i] = param;
+        } else {
             TINT_ICE(Inspector, diagnostics_)
-                << "unexpected unary op on resource: " << unary->op;
+                << "cannot resolve originating resource with expression type "
+                << exprs[i]->TypeInfo().name;
             return;
-          }
         }
-      }
-
-      TINT_ICE(Inspector, diagnostics_)
-          << "cannot resolve originating resource with expression type "
-          << expr->TypeInfo().name;
-      return;
     }
-  }
 
-  if (callsites.size()) {
-    for (auto* call_expr : callsites) {
-      // Make a copy of the expressions for this callsite
-      std::array<const ast::Expression*, N> call_exprs = exprs;
-      // Patch all the parameter expressions with their argument
-      for (size_t i = 0; i < N; i++) {
-        if (auto* param = parameters[i]) {
-          call_exprs[i] = call_expr->args[param->Index()];
+    if (callsites.size()) {
+        for (auto* call_expr : callsites) {
+            // Make a copy of the expressions for this callsite
+            std::array<const ast::Expression*, N> call_exprs = exprs;
+            // Patch all the parameter expressions with their argument
+            for (size_t i = 0; i < N; i++) {
+                if (auto* param = parameters[i]) {
+                    call_exprs[i] = call_expr->args[param->Index()];
+                }
+            }
+            // Now call GetOriginatingResources() with from the callsite
+            GetOriginatingResources(call_exprs, callback);
         }
-      }
-      // Now call GetOriginatingResources() with from the callsite
-      GetOriginatingResources(call_exprs, callback);
+    } else {
+        // All the expressions resolved to globals
+        callback(globals);
     }
-  } else {
-    // All the expressions resolved to globals
-    callback(globals);
-  }
 }
 
 }  // namespace tint::inspector
diff --git a/src/tint/inspector/inspector.h b/src/tint/inspector/inspector.h
index 49896df..a5aee17 100644
--- a/src/tint/inspector/inspector.h
+++ b/src/tint/inspector/inspector.h
@@ -20,6 +20,7 @@
 #include <string>
 #include <tuple>
 #include <unordered_map>
+#include <utility>
 #include <vector>
 
 #include "src/tint/inspector/entry_point.h"
@@ -36,195 +37,196 @@
 
 /// Extracts information from a program
 class Inspector {
- public:
-  /// Constructor
-  /// @param program Shader program to extract information from.
-  explicit Inspector(const Program* program);
+  public:
+    /// Constructor
+    /// @param program Shader program to extract information from.
+    explicit Inspector(const Program* program);
 
-  /// Destructor
-  ~Inspector();
+    /// Destructor
+    ~Inspector();
 
-  /// @returns error messages from the Inspector
-  std::string error() { return diagnostics_.str(); }
-  /// @returns true if an error was encountered
-  bool has_error() const { return diagnostics_.contains_errors(); }
+    /// @returns error messages from the Inspector
+    std::string error() { return diagnostics_.str(); }
+    /// @returns true if an error was encountered
+    bool has_error() const { return diagnostics_.contains_errors(); }
 
-  /// @returns vector of entry point information
-  std::vector<EntryPoint> GetEntryPoints();
+    /// @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 const_id to initial value
+    std::map<uint32_t, Scalar> GetConstantIDs();
 
-  /// @returns map of module-constant name to pipeline constant ID
-  std::map<std::string, uint32_t> GetConstantNameToIdMap();
+    /// @returns map of module-constant name to pipeline constant ID
+    std::map<std::string, uint32_t> GetConstantNameToIdMap();
 
-  /// @param entry_point name of the entry point to get information about.
-  /// @returns the total size of shared storage required by an entry point,
-  ///          including all uniform storage buffers.
-  uint32_t GetStorageSize(const std::string& entry_point);
+    /// @param entry_point name of the entry point to get information about.
+    /// @returns the total size of shared storage required by an entry point,
+    ///          including all uniform storage buffers.
+    uint32_t GetStorageSize(const std::string& entry_point);
 
-  /// @param entry_point name of the entry point to get information about.
-  /// @returns vector of all of the resource bindings.
-  std::vector<ResourceBinding> GetResourceBindings(
-      const std::string& entry_point);
+    /// @param entry_point name of the entry point to get information about.
+    /// @returns vector of all of the resource bindings.
+    std::vector<ResourceBinding> GetResourceBindings(const std::string& entry_point);
 
-  /// @param entry_point name of the entry point to get information about.
-  /// @returns vector of all of the bindings for uniform buffers.
-  std::vector<ResourceBinding> GetUniformBufferResourceBindings(
-      const std::string& entry_point);
+    /// @param entry_point name of the entry point to get information about.
+    /// @returns vector of all of the bindings for uniform buffers.
+    std::vector<ResourceBinding> GetUniformBufferResourceBindings(const std::string& entry_point);
 
-  /// @param entry_point name of the entry point to get information about.
-  /// @returns vector of all of the bindings for storage buffers.
-  std::vector<ResourceBinding> GetStorageBufferResourceBindings(
-      const std::string& entry_point);
+    /// @param entry_point name of the entry point to get information about.
+    /// @returns vector of all of the bindings for storage buffers.
+    std::vector<ResourceBinding> GetStorageBufferResourceBindings(const std::string& entry_point);
 
-  /// @param entry_point name of the entry point to get information about.
-  /// @returns vector of all of the bindings for read-only storage buffers.
-  std::vector<ResourceBinding> GetReadOnlyStorageBufferResourceBindings(
-      const std::string& entry_point);
+    /// @param entry_point name of the entry point to get information about.
+    /// @returns vector of all of the bindings for read-only storage buffers.
+    std::vector<ResourceBinding> GetReadOnlyStorageBufferResourceBindings(
+        const std::string& entry_point);
 
-  /// @param entry_point name of the entry point to get information about.
-  /// @returns vector of all of the bindings for regular samplers.
-  std::vector<ResourceBinding> GetSamplerResourceBindings(
-      const std::string& entry_point);
+    /// @param entry_point name of the entry point to get information about.
+    /// @returns vector of all of the bindings for regular samplers.
+    std::vector<ResourceBinding> GetSamplerResourceBindings(const std::string& entry_point);
 
-  /// @param entry_point name of the entry point to get information about.
-  /// @returns vector of all of the bindings for comparison samplers.
-  std::vector<ResourceBinding> GetComparisonSamplerResourceBindings(
-      const std::string& entry_point);
+    /// @param entry_point name of the entry point to get information about.
+    /// @returns vector of all of the bindings for comparison samplers.
+    std::vector<ResourceBinding> GetComparisonSamplerResourceBindings(
+        const std::string& entry_point);
 
-  /// @param entry_point name of the entry point to get information about.
-  /// @returns vector of all of the bindings for sampled textures.
-  std::vector<ResourceBinding> GetSampledTextureResourceBindings(
-      const std::string& entry_point);
+    /// @param entry_point name of the entry point to get information about.
+    /// @returns vector of all of the bindings for sampled textures.
+    std::vector<ResourceBinding> GetSampledTextureResourceBindings(const std::string& entry_point);
 
-  /// @param entry_point name of the entry point to get information about.
-  /// @returns vector of all of the bindings for multisampled textures.
-  std::vector<ResourceBinding> GetMultisampledTextureResourceBindings(
-      const std::string& entry_point);
+    /// @param entry_point name of the entry point to get information about.
+    /// @returns vector of all of the bindings for multisampled textures.
+    std::vector<ResourceBinding> GetMultisampledTextureResourceBindings(
+        const std::string& entry_point);
 
-  /// @param entry_point name of the entry point to get information about.
-  /// @returns vector of all of the bindings for write-only storage textures.
-  std::vector<ResourceBinding> GetWriteOnlyStorageTextureResourceBindings(
-      const std::string& entry_point);
+    /// @param entry_point name of the entry point to get information about.
+    /// @returns vector of all of the bindings for write-only storage textures.
+    std::vector<ResourceBinding> GetWriteOnlyStorageTextureResourceBindings(
+        const std::string& entry_point);
 
-  /// @param entry_point name of the entry point to get information about.
-  /// @returns vector of all of the bindings for depth textures.
-  std::vector<ResourceBinding> GetDepthTextureResourceBindings(
-      const std::string& entry_point);
+    /// @param entry_point name of the entry point to get information about.
+    /// @returns vector of all of the bindings for depth textures.
+    std::vector<ResourceBinding> GetDepthTextureResourceBindings(const std::string& entry_point);
 
-  /// @param entry_point name of the entry point to get information about.
-  /// @returns vector of all of the bindings for depth textures.
-  std::vector<ResourceBinding> GetDepthMultisampledTextureResourceBindings(
-      const std::string& entry_point);
+    /// @param entry_point name of the entry point to get information about.
+    /// @returns vector of all of the bindings for depth textures.
+    std::vector<ResourceBinding> GetDepthMultisampledTextureResourceBindings(
+        const std::string& entry_point);
 
-  /// @param entry_point name of the entry point to get information about.
-  /// @returns vector of all of the bindings for external textures.
-  std::vector<ResourceBinding> GetExternalTextureResourceBindings(
-      const std::string& entry_point);
+    /// @param entry_point name of the entry point to get information about.
+    /// @returns vector of all of the bindings for external textures.
+    std::vector<ResourceBinding> GetExternalTextureResourceBindings(const std::string& entry_point);
 
-  /// @param entry_point name of the entry point to get information about.
-  /// @returns vector of all of the sampler/texture sampling pairs that are used
-  /// by that entry point.
-  std::vector<sem::SamplerTexturePair> GetSamplerTextureUses(
-      const std::string& entry_point);
+    /// @param entry_point name of the entry point to get information about.
+    /// @returns vector of all of the sampler/texture sampling pairs that are used
+    /// by that entry point.
+    std::vector<sem::SamplerTexturePair> GetSamplerTextureUses(const std::string& entry_point);
 
-  /// @param entry_point name of the entry point to get information about.
-  /// @param placeholder the sampler binding point to use for texture-only
-  /// access (e.g., textureLoad)
-  /// @returns vector of all of the sampler/texture sampling pairs that are used
-  /// by that entry point.
-  std::vector<sem::SamplerTexturePair> GetSamplerTextureUses(
-      const std::string& entry_point,
-      const sem::BindingPoint& placeholder);
+    /// @param entry_point name of the entry point to get information about.
+    /// @param placeholder the sampler binding point to use for texture-only
+    /// access (e.g., textureLoad)
+    /// @returns vector of all of the sampler/texture sampling pairs that are used
+    /// by that entry point.
+    std::vector<sem::SamplerTexturePair> GetSamplerTextureUses(
+        const std::string& entry_point,
+        const sem::BindingPoint& placeholder);
 
-  /// @param entry_point name of the entry point to get information about.
-  /// @returns the total size in bytes of all Workgroup storage-class storage
-  /// referenced transitively by the entry point.
-  uint32_t GetWorkgroupStorageSize(const std::string& entry_point);
+    /// @param entry_point name of the entry point to get information about.
+    /// @returns the total size in bytes of all Workgroup storage-class storage
+    /// referenced transitively by the entry point.
+    uint32_t GetWorkgroupStorageSize(const std::string& entry_point);
 
- private:
-  const Program* program_;
-  diag::List diagnostics_;
-  std::unique_ptr<
-      std::unordered_map<std::string,
-                         utils::UniqueVector<sem::SamplerTexturePair>>>
-      sampler_targets_;
+    /// @returns vector of all valid extension names used by the program. There
+    /// will be no duplicated names in the returned vector even if an extension
+    /// is enabled multiple times.
+    std::vector<std::string> GetUsedExtensionNames();
 
-  /// @param name name of the entry point to find
-  /// @returns a pointer to the entry point if it exists, otherwise returns
-  ///          nullptr and sets the error string.
-  const ast::Function* FindEntryPointByName(const std::string& name);
+    /// @returns vector of all enable directives used by the program, each
+    /// enable directive represented by a std::pair<std::string,
+    /// tint::Source::Range> for its extension name and its location of the
+    /// extension name. There may be multiple enable directives for a same
+    /// extension.
+    std::vector<std::pair<std::string, Source>> GetEnableDirectives();
 
-  /// Recursively add entry point IO variables.
-  /// If `type` is a struct, recurse into members, appending the member name.
-  /// Otherwise, add the variable unless it is a builtin.
-  /// @param name the name of the variable being added
-  /// @param type the type of the variable
-  /// @param attributes the variable attributes
-  /// @param variables the list to add the variables to
-  void AddEntryPointInOutVariables(std::string name,
-                                   const sem::Type* type,
-                                   const ast::AttributeList& attributes,
-                                   std::vector<StageVariable>& variables) const;
+  private:
+    const Program* program_;
+    diag::List diagnostics_;
+    std::unique_ptr<std::unordered_map<std::string, utils::UniqueVector<sem::SamplerTexturePair>>>
+        sampler_targets_;
 
-  /// 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,
-                       const sem::Type* type,
-                       const ast::AttributeList& attributes) const;
+    /// @param name name of the entry point to find
+    /// @returns a pointer to the entry point if it exists, otherwise returns
+    ///          nullptr and sets the error string.
+    const ast::Function* FindEntryPointByName(const std::string& name);
 
-  /// Gathers all the texture resource bindings of the given type for the given
-  /// entry point.
-  /// @param entry_point name of the entry point to get information about.
-  /// @param texture_type the type of the textures to gather.
-  /// @param resource_type the ResourceBinding::ResourceType for the given
-  /// texture type.
-  /// @returns vector of all of the bindings for depth textures.
-  std::vector<ResourceBinding> GetTextureResourceBindings(
-      const std::string& entry_point,
-      const tint::TypeInfo* texture_type,
-      ResourceBinding::ResourceType resource_type);
+    /// Recursively add entry point IO variables.
+    /// If `type` is a struct, recurse into members, appending the member name.
+    /// Otherwise, add the variable unless it is a builtin.
+    /// @param name the name of the variable being added
+    /// @param type the type of the variable
+    /// @param attributes the variable attributes
+    /// @param variables the list to add the variables to
+    void AddEntryPointInOutVariables(std::string name,
+                                     const sem::Type* type,
+                                     const ast::AttributeList& attributes,
+                                     std::vector<StageVariable>& variables) const;
 
-  /// @param entry_point name of the entry point to get information about.
-  /// @param read_only if true get only read-only bindings, if false get
-  ///                  write-only bindings.
-  /// @returns vector of all of the bindings for the requested storage buffers.
-  std::vector<ResourceBinding> GetStorageBufferResourceBindingsImpl(
-      const std::string& entry_point,
-      bool read_only);
+    /// 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,
+                         const sem::Type* type,
+                         const ast::AttributeList& attributes) const;
 
-  /// @param entry_point name of the entry point to get information about.
-  /// @param multisampled_only only get multisampled textures if true, otherwise
-  ///                          only get sampled textures.
-  /// @returns vector of all of the bindings for the request storage buffers.
-  std::vector<ResourceBinding> GetSampledTextureResourceBindingsImpl(
-      const std::string& entry_point,
-      bool multisampled_only);
+    /// Gathers all the texture resource bindings of the given type for the given
+    /// entry point.
+    /// @param entry_point name of the entry point to get information about.
+    /// @param texture_type the type of the textures to gather.
+    /// @param resource_type the ResourceBinding::ResourceType for the given
+    /// texture type.
+    /// @returns vector of all of the bindings for depth textures.
+    std::vector<ResourceBinding> GetTextureResourceBindings(
+        const std::string& entry_point,
+        const tint::TypeInfo* texture_type,
+        ResourceBinding::ResourceType resource_type);
 
-  /// @param entry_point name of the entry point to get information about.
-  /// @returns vector of all of the bindings for the requested storage textures.
-  std::vector<ResourceBinding> GetStorageTextureResourceBindingsImpl(
-      const std::string& entry_point);
+    /// @param entry_point name of the entry point to get information about.
+    /// @param read_only if true get only read-only bindings, if false get
+    ///                  write-only bindings.
+    /// @returns vector of all of the bindings for the requested storage buffers.
+    std::vector<ResourceBinding> GetStorageBufferResourceBindingsImpl(
+        const std::string& entry_point,
+        bool read_only);
 
-  /// Constructs |sampler_targets_| if it hasn't already been instantiated.
-  void GenerateSamplerTargets();
+    /// @param entry_point name of the entry point to get information about.
+    /// @param multisampled_only only get multisampled textures if true, otherwise
+    ///                          only get sampled textures.
+    /// @returns vector of all of the bindings for the request storage buffers.
+    std::vector<ResourceBinding> GetSampledTextureResourceBindingsImpl(
+        const std::string& entry_point,
+        bool multisampled_only);
 
-  /// For a N-uple of expressions, resolve to the appropriate global resources
-  /// and call 'cb'.
-  /// 'cb' may be called multiple times.
-  /// Assumes that not being able to resolve the resources is an error, so will
-  /// invoke TINT_ICE when that occurs.
-  /// @tparam N number of expressions in the n-uple
-  /// @tparam F type of the callback provided.
-  /// @param exprs N-uple of expressions to resolve.
-  /// @param cb is a callback function with the signature:
-  /// `void(std::array<const sem::GlobalVariable*, N>)`, which is invoked
-  /// whenever a set of expressions are resolved to globals.
-  template <size_t N, typename F>
-  void GetOriginatingResources(std::array<const ast::Expression*, N> exprs,
-                               F&& cb);
+    /// @param entry_point name of the entry point to get information about.
+    /// @returns vector of all of the bindings for the requested storage textures.
+    std::vector<ResourceBinding> GetStorageTextureResourceBindingsImpl(
+        const std::string& entry_point);
+
+    /// Constructs |sampler_targets_| if it hasn't already been instantiated.
+    void GenerateSamplerTargets();
+
+    /// For a N-uple of expressions, resolve to the appropriate global resources
+    /// and call 'cb'.
+    /// 'cb' may be called multiple times.
+    /// Assumes that not being able to resolve the resources is an error, so will
+    /// invoke TINT_ICE when that occurs.
+    /// @tparam N number of expressions in the n-uple
+    /// @tparam F type of the callback provided.
+    /// @param exprs N-uple of expressions to resolve.
+    /// @param cb is a callback function with the signature:
+    /// `void(std::array<const sem::GlobalVariable*, N>)`, which is invoked
+    /// whenever a set of expressions are resolved to globals.
+    template <size_t N, typename F>
+    void GetOriginatingResources(std::array<const ast::Expression*, N> exprs, F&& cb);
 };
 
 }  // namespace tint::inspector
diff --git a/src/tint/inspector/inspector_test.cc b/src/tint/inspector/inspector_test.cc
index 6e3ecb3..8e3662b 100644
--- a/src/tint/inspector/inspector_test.cc
+++ b/src/tint/inspector/inspector_test.cc
@@ -21,13 +21,15 @@
 #include "src/tint/inspector/test_inspector_builder.h"
 #include "src/tint/inspector/test_inspector_runner.h"
 #include "src/tint/program_builder.h"
-#include "src/tint/sem/depth_texture_type.h"
-#include "src/tint/sem/external_texture_type.h"
-#include "src/tint/sem/multisampled_texture_type.h"
-#include "src/tint/sem/sampled_texture_type.h"
+#include "src/tint/sem/depth_texture.h"
+#include "src/tint/sem/external_texture.h"
+#include "src/tint/sem/multisampled_texture.h"
+#include "src/tint/sem/sampled_texture.h"
 #include "src/tint/sem/variable.h"
 #include "tint/tint.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::inspector {
 namespace {
 
@@ -42,54 +44,43 @@
 // The returned Inspector from ::Initialize can then be used to test
 // expecations.
 
-class InspectorGetEntryPointTest : public InspectorBuilder,
-                                   public testing::Test {};
+class InspectorGetEntryPointTest : public InspectorBuilder, public testing::Test {};
 
 typedef std::tuple<inspector::ComponentType, inspector::CompositionType>
     InspectorGetEntryPointComponentAndCompositionTestParams;
 class InspectorGetEntryPointComponentAndCompositionTest
     : public InspectorBuilder,
-      public testing::TestWithParam<
-          InspectorGetEntryPointComponentAndCompositionTestParams> {};
+      public testing::TestWithParam<InspectorGetEntryPointComponentAndCompositionTestParams> {};
 struct InspectorGetEntryPointInterpolateTestParams {
-  ast::InterpolationType in_type;
-  ast::InterpolationSampling in_sampling;
-  inspector::InterpolationType out_type;
-  inspector::InterpolationSampling out_sampling;
+    ast::InterpolationType in_type;
+    ast::InterpolationSampling in_sampling;
+    inspector::InterpolationType out_type;
+    inspector::InterpolationSampling out_sampling;
 };
 class InspectorGetEntryPointInterpolateTest
     : public InspectorBuilder,
-      public testing::TestWithParam<
-          InspectorGetEntryPointInterpolateTestParams> {};
-class InspectorGetConstantIDsTest : 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 {};
+      public testing::TestWithParam<InspectorGetEntryPointInterpolateTestParams> {};
+class InspectorGetConstantIDsTest : 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 {};
 class InspectorGetUniformBufferResourceBindingsTest : public InspectorBuilder,
                                                       public testing::Test {};
 class InspectorGetStorageBufferResourceBindingsTest : public InspectorBuilder,
                                                       public testing::Test {};
-class InspectorGetReadOnlyStorageBufferResourceBindingsTest
-    : public InspectorBuilder,
-      public testing::Test {};
-class InspectorGetSamplerResourceBindingsTest : public InspectorBuilder,
-                                                public testing::Test {};
-class InspectorGetComparisonSamplerResourceBindingsTest
-    : public InspectorBuilder,
-      public testing::Test {};
+class InspectorGetReadOnlyStorageBufferResourceBindingsTest : public InspectorBuilder,
+                                                              public testing::Test {};
+class InspectorGetSamplerResourceBindingsTest : public InspectorBuilder, public testing::Test {};
+class InspectorGetComparisonSamplerResourceBindingsTest : public InspectorBuilder,
+                                                          public testing::Test {};
 class InspectorGetSampledTextureResourceBindingsTest : public InspectorBuilder,
                                                        public testing::Test {};
-class InspectorGetSampledArrayTextureResourceBindingsTest
-    : public InspectorBuilder,
-      public testing::Test {};
+class InspectorGetSampledArrayTextureResourceBindingsTest : public InspectorBuilder,
+                                                            public testing::Test {};
 struct GetSampledTextureTestParams {
-  ast::TextureDimension type_dim;
-  inspector::ResourceBinding::TextureDimension inspector_dim;
-  inspector::ResourceBinding::SampledKind sampled_kind;
+    ast::TextureDimension type_dim;
+    inspector::ResourceBinding::TextureDimension inspector_dim;
+    inspector::ResourceBinding::SampledKind sampled_kind;
 };
 class InspectorGetSampledTextureResourceBindingsTestWithParam
     : public InspectorBuilder,
@@ -97,12 +88,10 @@
 class InspectorGetSampledArrayTextureResourceBindingsTestWithParam
     : public InspectorBuilder,
       public testing::TestWithParam<GetSampledTextureTestParams> {};
-class InspectorGetMultisampledTextureResourceBindingsTest
-    : public InspectorBuilder,
-      public testing::Test {};
-class InspectorGetMultisampledArrayTextureResourceBindingsTest
-    : public InspectorBuilder,
-      public testing::Test {};
+class InspectorGetMultisampledTextureResourceBindingsTest : public InspectorBuilder,
+                                                            public testing::Test {};
+class InspectorGetMultisampledArrayTextureResourceBindingsTest : public InspectorBuilder,
+                                                                 public testing::Test {};
 typedef GetSampledTextureTestParams GetMultisampledTextureTestParams;
 class InspectorGetMultisampledArrayTextureResourceBindingsTestWithParam
     : public InspectorBuilder,
@@ -113,25 +102,20 @@
 class InspectorGetStorageTextureResourceBindingsTest : public InspectorBuilder,
                                                        public testing::Test {};
 struct GetDepthTextureTestParams {
-  ast::TextureDimension type_dim;
-  inspector::ResourceBinding::TextureDimension inspector_dim;
+    ast::TextureDimension type_dim;
+    inspector::ResourceBinding::TextureDimension inspector_dim;
 };
 class InspectorGetDepthTextureResourceBindingsTestWithParam
     : public InspectorBuilder,
       public testing::TestWithParam<GetDepthTextureTestParams> {};
 
-class InspectorGetDepthMultisampledTextureResourceBindingsTest
-    : public InspectorBuilder,
-      public testing::Test {};
+class InspectorGetDepthMultisampledTextureResourceBindingsTest : public InspectorBuilder,
+                                                                 public testing::Test {};
 
-typedef std::tuple<ast::TextureDimension, ResourceBinding::TextureDimension>
-    DimensionParams;
-typedef std::tuple<ast::TexelFormat,
-                   ResourceBinding::TexelFormat,
-                   ResourceBinding::SampledKind>
+typedef std::tuple<ast::TextureDimension, ResourceBinding::TextureDimension> DimensionParams;
+typedef std::tuple<ast::TexelFormat, ResourceBinding::TexelFormat, ResourceBinding::SampledKind>
     TexelFormatParams;
-typedef std::tuple<DimensionParams, TexelFormatParams>
-    GetStorageTextureTestParams;
+typedef std::tuple<DimensionParams, TexelFormatParams> GetStorageTextureTestParams;
 class InspectorGetStorageTextureResourceBindingsTestWithParam
     : public InspectorBuilder,
       public testing::TestWithParam<GetStorageTextureTestParams> {};
@@ -139,846 +123,799 @@
 class InspectorGetExternalTextureResourceBindingsTest : public InspectorBuilder,
                                                         public testing::Test {};
 
-class InspectorGetSamplerTextureUsesTest : public InspectorRunner,
-                                           public testing::Test {};
+class InspectorGetSamplerTextureUsesTest : public InspectorRunner, public testing::Test {};
 
-class InspectorGetWorkgroupStorageSizeTest : public InspectorBuilder,
-                                             public testing::Test {};
+class InspectorGetWorkgroupStorageSizeTest : public InspectorBuilder, public testing::Test {};
+
+class InspectorGetUsedExtensionNamesTest : public InspectorRunner, public testing::Test {};
+
+class InspectorGetEnableDirectivesTest : public InspectorRunner, public testing::Test {};
 
 // This is a catch all for shaders that have demonstrated regressions/crashes in
 // the wild.
 class InspectorRegressionTest : public InspectorRunner, public testing::Test {};
 
 TEST_F(InspectorGetEntryPointTest, NoFunctions) {
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetEntryPoints();
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    auto result = inspector.GetEntryPoints();
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
-  EXPECT_EQ(0u, result.size());
+    EXPECT_EQ(0u, result.size());
 }
 
 TEST_F(InspectorGetEntryPointTest, NoEntryPoints) {
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetEntryPoints();
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    auto result = inspector.GetEntryPoints();
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
-  EXPECT_EQ(0u, result.size());
+    EXPECT_EQ(0u, result.size());
 }
 
 TEST_F(InspectorGetEntryPointTest, OneEntryPoint) {
-  MakeEmptyBodyFunction("foo", ast::AttributeList{
-                                   Stage(ast::PipelineStage::kFragment),
-                               });
+    MakeEmptyBodyFunction("foo", ast::AttributeList{
+                                     Stage(ast::PipelineStage::kFragment),
+                                 });
 
-  // TODO(dsinclair): Update to run the namer transform when available.
+    // TODO(dsinclair): Update to run the namer transform when available.
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetEntryPoints();
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    auto result = inspector.GetEntryPoints();
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
-  ASSERT_EQ(1u, result.size());
-  EXPECT_EQ("foo", result[0].name);
-  EXPECT_EQ("foo", result[0].remapped_name);
-  EXPECT_EQ(ast::PipelineStage::kFragment, result[0].stage);
+    ASSERT_EQ(1u, result.size());
+    EXPECT_EQ("foo", result[0].name);
+    EXPECT_EQ("foo", result[0].remapped_name);
+    EXPECT_EQ(ast::PipelineStage::kFragment, result[0].stage);
 }
 
 TEST_F(InspectorGetEntryPointTest, MultipleEntryPoints) {
-  MakeEmptyBodyFunction("foo", ast::AttributeList{
-                                   Stage(ast::PipelineStage::kFragment),
-                               });
+    MakeEmptyBodyFunction("foo", ast::AttributeList{
+                                     Stage(ast::PipelineStage::kFragment),
+                                 });
 
-  MakeEmptyBodyFunction("bar",
-                        ast::AttributeList{Stage(ast::PipelineStage::kCompute),
-                                           WorkgroupSize(1)});
+    MakeEmptyBodyFunction(
+        "bar", ast::AttributeList{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
 
-  // TODO(dsinclair): Update to run the namer transform when available.
+    // TODO(dsinclair): Update to run the namer transform when available.
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetEntryPoints();
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    auto result = inspector.GetEntryPoints();
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
-  ASSERT_EQ(2u, result.size());
-  EXPECT_EQ("foo", result[0].name);
-  EXPECT_EQ("foo", result[0].remapped_name);
-  EXPECT_EQ(ast::PipelineStage::kFragment, result[0].stage);
-  EXPECT_EQ("bar", result[1].name);
-  EXPECT_EQ("bar", result[1].remapped_name);
-  EXPECT_EQ(ast::PipelineStage::kCompute, result[1].stage);
+    ASSERT_EQ(2u, result.size());
+    EXPECT_EQ("foo", result[0].name);
+    EXPECT_EQ("foo", result[0].remapped_name);
+    EXPECT_EQ(ast::PipelineStage::kFragment, result[0].stage);
+    EXPECT_EQ("bar", result[1].name);
+    EXPECT_EQ("bar", result[1].remapped_name);
+    EXPECT_EQ(ast::PipelineStage::kCompute, result[1].stage);
 }
 
 TEST_F(InspectorGetEntryPointTest, MixFunctionsAndEntryPoints) {
-  MakeEmptyBodyFunction("func", {});
+    MakeEmptyBodyFunction("func", {});
 
-  MakeCallerBodyFunction("foo", {"func"},
-                         ast::AttributeList{Stage(ast::PipelineStage::kCompute),
-                                            WorkgroupSize(1)});
+    MakeCallerBodyFunction(
+        "foo", {"func"},
+        ast::AttributeList{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
 
-  MakeCallerBodyFunction("bar", {"func"},
-                         ast::AttributeList{
-                             Stage(ast::PipelineStage::kFragment),
-                         });
+    MakeCallerBodyFunction("bar", {"func"},
+                           ast::AttributeList{
+                               Stage(ast::PipelineStage::kFragment),
+                           });
 
-  // TODO(dsinclair): Update to run the namer transform when available.
+    // TODO(dsinclair): Update to run the namer transform when available.
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetEntryPoints();
-  EXPECT_FALSE(inspector.has_error());
+    auto result = inspector.GetEntryPoints();
+    EXPECT_FALSE(inspector.has_error());
 
-  ASSERT_EQ(2u, result.size());
-  EXPECT_EQ("foo", result[0].name);
-  EXPECT_EQ("foo", result[0].remapped_name);
-  EXPECT_EQ(ast::PipelineStage::kCompute, result[0].stage);
-  EXPECT_EQ("bar", result[1].name);
-  EXPECT_EQ("bar", result[1].remapped_name);
-  EXPECT_EQ(ast::PipelineStage::kFragment, result[1].stage);
+    ASSERT_EQ(2u, result.size());
+    EXPECT_EQ("foo", result[0].name);
+    EXPECT_EQ("foo", result[0].remapped_name);
+    EXPECT_EQ(ast::PipelineStage::kCompute, result[0].stage);
+    EXPECT_EQ("bar", result[1].name);
+    EXPECT_EQ("bar", result[1].remapped_name);
+    EXPECT_EQ(ast::PipelineStage::kFragment, result[1].stage);
 }
 
 TEST_F(InspectorGetEntryPointTest, DefaultWorkgroupSize) {
-  MakeEmptyBodyFunction("foo",
-                        ast::AttributeList{Stage(ast::PipelineStage::kCompute),
-                                           WorkgroupSize(8, 2, 1)});
+    MakeEmptyBodyFunction("foo", ast::AttributeList{Stage(ast::PipelineStage::kCompute),
+                                                    WorkgroupSize(8_i, 2_i, 1_i)});
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetEntryPoints();
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    auto result = inspector.GetEntryPoints();
+    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);
+    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);
 }
 
 TEST_F(InspectorGetEntryPointTest, NonDefaultWorkgroupSize) {
-  MakeEmptyBodyFunction(
-      "foo", {Stage(ast::PipelineStage::kCompute), WorkgroupSize(8, 2, 1)});
+    MakeEmptyBodyFunction("foo",
+                          {Stage(ast::PipelineStage::kCompute), WorkgroupSize(8_i, 2_i, 1_i)});
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetEntryPoints();
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    auto result = inspector.GetEntryPoints();
+    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);
+    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);
 }
 
 TEST_F(InspectorGetEntryPointTest, NoInOutVariables) {
-  MakeEmptyBodyFunction("func", {});
+    MakeEmptyBodyFunction("func", {});
 
-  MakeCallerBodyFunction("foo", {"func"},
-                         ast::AttributeList{
-                             Stage(ast::PipelineStage::kFragment),
-                         });
+    MakeCallerBodyFunction("foo", {"func"},
+                           ast::AttributeList{
+                               Stage(ast::PipelineStage::kFragment),
+                           });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetEntryPoints();
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    auto result = inspector.GetEntryPoints();
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
-  ASSERT_EQ(1u, result.size());
-  EXPECT_EQ(0u, result[0].input_variables.size());
-  EXPECT_EQ(0u, result[0].output_variables.size());
+    ASSERT_EQ(1u, result.size());
+    EXPECT_EQ(0u, result[0].input_variables.size());
+    EXPECT_EQ(0u, result[0].output_variables.size());
 }
 
 TEST_P(InspectorGetEntryPointComponentAndCompositionTest, Test) {
-  ComponentType component;
-  CompositionType composition;
-  std::tie(component, composition) = GetParam();
-  std::function<const ast::Type*()> tint_type =
-      GetTypeFunction(component, composition);
+    ComponentType component;
+    CompositionType composition;
+    std::tie(component, composition) = GetParam();
+    std::function<const ast::Type*()> tint_type = GetTypeFunction(component, composition);
 
-  auto* in_var = Param("in_var", tint_type(), {Location(0u), Flat()});
-  Func("foo", {in_var}, tint_type(), {Return("in_var")},
-       {Stage(ast::PipelineStage::kFragment)}, {Location(0u)});
-  Inspector& inspector = Build();
+    auto* in_var = Param("in_var", tint_type(), {Location(0u), Flat()});
+    Func("foo", {in_var}, tint_type(), {Return("in_var")}, {Stage(ast::PipelineStage::kFragment)},
+         {Location(0u)});
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetEntryPoints();
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    auto result = inspector.GetEntryPoints();
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
-  ASSERT_EQ(1u, result.size());
+    ASSERT_EQ(1u, result.size());
 
-  ASSERT_EQ(1u, result[0].input_variables.size());
-  EXPECT_EQ("in_var", result[0].input_variables[0].name);
-  EXPECT_TRUE(result[0].input_variables[0].has_location_attribute);
-  EXPECT_EQ(0u, result[0].input_variables[0].location_attribute);
-  EXPECT_EQ(component, result[0].input_variables[0].component_type);
+    ASSERT_EQ(1u, result[0].input_variables.size());
+    EXPECT_EQ("in_var", result[0].input_variables[0].name);
+    EXPECT_TRUE(result[0].input_variables[0].has_location_attribute);
+    EXPECT_EQ(0u, result[0].input_variables[0].location_attribute);
+    EXPECT_EQ(component, result[0].input_variables[0].component_type);
 
-  ASSERT_EQ(1u, result[0].output_variables.size());
-  EXPECT_EQ("<retval>", result[0].output_variables[0].name);
-  EXPECT_TRUE(result[0].output_variables[0].has_location_attribute);
-  EXPECT_EQ(0u, result[0].output_variables[0].location_attribute);
-  EXPECT_EQ(component, result[0].output_variables[0].component_type);
+    ASSERT_EQ(1u, result[0].output_variables.size());
+    EXPECT_EQ("<retval>", result[0].output_variables[0].name);
+    EXPECT_TRUE(result[0].output_variables[0].has_location_attribute);
+    EXPECT_EQ(0u, result[0].output_variables[0].location_attribute);
+    EXPECT_EQ(component, result[0].output_variables[0].component_type);
 }
-INSTANTIATE_TEST_SUITE_P(
-    InspectorGetEntryPointTest,
-    InspectorGetEntryPointComponentAndCompositionTest,
-    testing::Combine(testing::Values(ComponentType::kFloat,
-                                     ComponentType::kSInt,
-                                     ComponentType::kUInt),
-                     testing::Values(CompositionType::kScalar,
-                                     CompositionType::kVec2,
-                                     CompositionType::kVec3,
-                                     CompositionType::kVec4)));
+INSTANTIATE_TEST_SUITE_P(InspectorGetEntryPointTest,
+                         InspectorGetEntryPointComponentAndCompositionTest,
+                         testing::Combine(testing::Values(ComponentType::kFloat,
+                                                          ComponentType::kSInt,
+                                                          ComponentType::kUInt),
+                                          testing::Values(CompositionType::kScalar,
+                                                          CompositionType::kVec2,
+                                                          CompositionType::kVec3,
+                                                          CompositionType::kVec4)));
 
 TEST_F(InspectorGetEntryPointTest, MultipleInOutVariables) {
-  auto* in_var0 = Param("in_var0", ty.u32(), {Location(0u), Flat()});
-  auto* in_var1 = Param("in_var1", ty.u32(), {Location(1u), Flat()});
-  auto* in_var4 = Param("in_var4", ty.u32(), {Location(4u), Flat()});
-  Func("foo", {in_var0, in_var1, in_var4}, ty.u32(), {Return("in_var0")},
-       {Stage(ast::PipelineStage::kFragment)}, {Location(0u)});
-  Inspector& inspector = Build();
+    auto* in_var0 = Param("in_var0", ty.u32(), {Location(0u), Flat()});
+    auto* in_var1 = Param("in_var1", ty.u32(), {Location(1u), Flat()});
+    auto* in_var4 = Param("in_var4", ty.u32(), {Location(4u), Flat()});
+    Func("foo", {in_var0, in_var1, in_var4}, ty.u32(), {Return("in_var0")},
+         {Stage(ast::PipelineStage::kFragment)}, {Location(0u)});
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetEntryPoints();
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    auto result = inspector.GetEntryPoints();
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
-  ASSERT_EQ(1u, result.size());
+    ASSERT_EQ(1u, result.size());
 
-  ASSERT_EQ(3u, result[0].input_variables.size());
-  EXPECT_EQ("in_var0", result[0].input_variables[0].name);
-  EXPECT_TRUE(result[0].input_variables[0].has_location_attribute);
-  EXPECT_EQ(0u, result[0].input_variables[0].location_attribute);
-  EXPECT_EQ(InterpolationType::kFlat,
-            result[0].input_variables[0].interpolation_type);
-  EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[0].component_type);
-  EXPECT_EQ("in_var1", result[0].input_variables[1].name);
-  EXPECT_TRUE(result[0].input_variables[1].has_location_attribute);
-  EXPECT_EQ(1u, result[0].input_variables[1].location_attribute);
-  EXPECT_EQ(InterpolationType::kFlat,
-            result[0].input_variables[1].interpolation_type);
-  EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[1].component_type);
-  EXPECT_EQ("in_var4", result[0].input_variables[2].name);
-  EXPECT_TRUE(result[0].input_variables[2].has_location_attribute);
-  EXPECT_EQ(4u, result[0].input_variables[2].location_attribute);
-  EXPECT_EQ(InterpolationType::kFlat,
-            result[0].input_variables[2].interpolation_type);
-  EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[2].component_type);
+    ASSERT_EQ(3u, result[0].input_variables.size());
+    EXPECT_EQ("in_var0", result[0].input_variables[0].name);
+    EXPECT_TRUE(result[0].input_variables[0].has_location_attribute);
+    EXPECT_EQ(0u, result[0].input_variables[0].location_attribute);
+    EXPECT_EQ(InterpolationType::kFlat, result[0].input_variables[0].interpolation_type);
+    EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[0].component_type);
+    EXPECT_EQ("in_var1", result[0].input_variables[1].name);
+    EXPECT_TRUE(result[0].input_variables[1].has_location_attribute);
+    EXPECT_EQ(1u, result[0].input_variables[1].location_attribute);
+    EXPECT_EQ(InterpolationType::kFlat, result[0].input_variables[1].interpolation_type);
+    EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[1].component_type);
+    EXPECT_EQ("in_var4", result[0].input_variables[2].name);
+    EXPECT_TRUE(result[0].input_variables[2].has_location_attribute);
+    EXPECT_EQ(4u, result[0].input_variables[2].location_attribute);
+    EXPECT_EQ(InterpolationType::kFlat, result[0].input_variables[2].interpolation_type);
+    EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[2].component_type);
 
-  ASSERT_EQ(1u, result[0].output_variables.size());
-  EXPECT_EQ("<retval>", result[0].output_variables[0].name);
-  EXPECT_TRUE(result[0].output_variables[0].has_location_attribute);
-  EXPECT_EQ(0u, result[0].output_variables[0].location_attribute);
-  EXPECT_EQ(ComponentType::kUInt, result[0].output_variables[0].component_type);
+    ASSERT_EQ(1u, result[0].output_variables.size());
+    EXPECT_EQ("<retval>", result[0].output_variables[0].name);
+    EXPECT_TRUE(result[0].output_variables[0].has_location_attribute);
+    EXPECT_EQ(0u, result[0].output_variables[0].location_attribute);
+    EXPECT_EQ(ComponentType::kUInt, result[0].output_variables[0].component_type);
 }
 
 TEST_F(InspectorGetEntryPointTest, MultipleEntryPointsInOutVariables) {
-  auto* in_var_foo = Param("in_var_foo", ty.u32(), {Location(0u), Flat()});
-  Func("foo", {in_var_foo}, ty.u32(), {Return("in_var_foo")},
-       {Stage(ast::PipelineStage::kFragment)}, {Location(0u)});
+    auto* in_var_foo = Param("in_var_foo", ty.u32(), {Location(0u), Flat()});
+    Func("foo", {in_var_foo}, ty.u32(), {Return("in_var_foo")},
+         {Stage(ast::PipelineStage::kFragment)}, {Location(0u)});
 
-  auto* in_var_bar = Param("in_var_bar", ty.u32(), {Location(0u), Flat()});
-  Func("bar", {in_var_bar}, ty.u32(), {Return("in_var_bar")},
-       {Stage(ast::PipelineStage::kFragment)}, {Location(1u)});
+    auto* in_var_bar = Param("in_var_bar", ty.u32(), {Location(0u), Flat()});
+    Func("bar", {in_var_bar}, ty.u32(), {Return("in_var_bar")},
+         {Stage(ast::PipelineStage::kFragment)}, {Location(1u)});
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetEntryPoints();
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    auto result = inspector.GetEntryPoints();
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
-  ASSERT_EQ(2u, result.size());
+    ASSERT_EQ(2u, result.size());
 
-  ASSERT_EQ(1u, result[0].input_variables.size());
-  EXPECT_EQ("in_var_foo", result[0].input_variables[0].name);
-  EXPECT_TRUE(result[0].input_variables[0].has_location_attribute);
-  EXPECT_EQ(0u, result[0].input_variables[0].location_attribute);
-  EXPECT_EQ(InterpolationType::kFlat,
-            result[0].input_variables[0].interpolation_type);
-  EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[0].component_type);
+    ASSERT_EQ(1u, result[0].input_variables.size());
+    EXPECT_EQ("in_var_foo", result[0].input_variables[0].name);
+    EXPECT_TRUE(result[0].input_variables[0].has_location_attribute);
+    EXPECT_EQ(0u, result[0].input_variables[0].location_attribute);
+    EXPECT_EQ(InterpolationType::kFlat, result[0].input_variables[0].interpolation_type);
+    EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[0].component_type);
 
-  ASSERT_EQ(1u, result[0].output_variables.size());
-  EXPECT_EQ("<retval>", result[0].output_variables[0].name);
-  EXPECT_TRUE(result[0].output_variables[0].has_location_attribute);
-  EXPECT_EQ(0u, result[0].output_variables[0].location_attribute);
-  EXPECT_EQ(ComponentType::kUInt, result[0].output_variables[0].component_type);
+    ASSERT_EQ(1u, result[0].output_variables.size());
+    EXPECT_EQ("<retval>", result[0].output_variables[0].name);
+    EXPECT_TRUE(result[0].output_variables[0].has_location_attribute);
+    EXPECT_EQ(0u, result[0].output_variables[0].location_attribute);
+    EXPECT_EQ(ComponentType::kUInt, result[0].output_variables[0].component_type);
 
-  ASSERT_EQ(1u, result[1].input_variables.size());
-  EXPECT_EQ("in_var_bar", result[1].input_variables[0].name);
-  EXPECT_TRUE(result[1].input_variables[0].has_location_attribute);
-  EXPECT_EQ(0u, result[1].input_variables[0].location_attribute);
-  EXPECT_EQ(InterpolationType::kFlat,
-            result[1].input_variables[0].interpolation_type);
-  EXPECT_EQ(ComponentType::kUInt, result[1].input_variables[0].component_type);
+    ASSERT_EQ(1u, result[1].input_variables.size());
+    EXPECT_EQ("in_var_bar", result[1].input_variables[0].name);
+    EXPECT_TRUE(result[1].input_variables[0].has_location_attribute);
+    EXPECT_EQ(0u, result[1].input_variables[0].location_attribute);
+    EXPECT_EQ(InterpolationType::kFlat, result[1].input_variables[0].interpolation_type);
+    EXPECT_EQ(ComponentType::kUInt, result[1].input_variables[0].component_type);
 
-  ASSERT_EQ(1u, result[1].output_variables.size());
-  EXPECT_EQ("<retval>", result[1].output_variables[0].name);
-  EXPECT_TRUE(result[1].output_variables[0].has_location_attribute);
-  EXPECT_EQ(1u, result[1].output_variables[0].location_attribute);
-  EXPECT_EQ(ComponentType::kUInt, result[1].output_variables[0].component_type);
+    ASSERT_EQ(1u, result[1].output_variables.size());
+    EXPECT_EQ("<retval>", result[1].output_variables[0].name);
+    EXPECT_TRUE(result[1].output_variables[0].has_location_attribute);
+    EXPECT_EQ(1u, result[1].output_variables[0].location_attribute);
+    EXPECT_EQ(ComponentType::kUInt, result[1].output_variables[0].component_type);
 }
 
 TEST_F(InspectorGetEntryPointTest, BuiltInsNotStageVariables) {
-  auto* in_var0 =
-      Param("in_var0", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)});
-  auto* in_var1 = Param("in_var1", ty.f32(), {Location(0u)});
-  Func("foo", {in_var0, in_var1}, ty.f32(), {Return("in_var1")},
-       {Stage(ast::PipelineStage::kFragment)},
-       {Builtin(ast::Builtin::kFragDepth)});
-  Inspector& inspector = Build();
+    auto* in_var0 = Param("in_var0", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)});
+    auto* in_var1 = Param("in_var1", ty.f32(), {Location(0u)});
+    Func("foo", {in_var0, in_var1}, ty.f32(), {Return("in_var1")},
+         {Stage(ast::PipelineStage::kFragment)}, {Builtin(ast::Builtin::kFragDepth)});
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetEntryPoints();
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    auto result = inspector.GetEntryPoints();
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
-  ASSERT_EQ(1u, result.size());
+    ASSERT_EQ(1u, result.size());
 
-  ASSERT_EQ(1u, result[0].input_variables.size());
-  EXPECT_EQ("in_var1", result[0].input_variables[0].name);
-  EXPECT_TRUE(result[0].input_variables[0].has_location_attribute);
-  EXPECT_EQ(0u, result[0].input_variables[0].location_attribute);
-  EXPECT_EQ(ComponentType::kFloat, result[0].input_variables[0].component_type);
+    ASSERT_EQ(1u, result[0].input_variables.size());
+    EXPECT_EQ("in_var1", result[0].input_variables[0].name);
+    EXPECT_TRUE(result[0].input_variables[0].has_location_attribute);
+    EXPECT_EQ(0u, result[0].input_variables[0].location_attribute);
+    EXPECT_EQ(ComponentType::kFloat, result[0].input_variables[0].component_type);
 
-  ASSERT_EQ(0u, result[0].output_variables.size());
+    ASSERT_EQ(0u, result[0].output_variables.size());
 }
 
 TEST_F(InspectorGetEntryPointTest, InOutStruct) {
-  auto* interface = MakeInOutStruct("interface", {{"a", 0u}, {"b", 1u}});
-  Func("foo", {Param("param", ty.Of(interface))}, ty.Of(interface),
-       {Return("param")}, {Stage(ast::PipelineStage::kFragment)});
-  Inspector& inspector = Build();
+    auto* interface = MakeInOutStruct("interface", {{"a", 0u}, {"b", 1u}});
+    Func("foo", {Param("param", ty.Of(interface))}, ty.Of(interface), {Return("param")},
+         {Stage(ast::PipelineStage::kFragment)});
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetEntryPoints();
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    auto result = inspector.GetEntryPoints();
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
-  ASSERT_EQ(1u, result.size());
+    ASSERT_EQ(1u, result.size());
 
-  ASSERT_EQ(2u, result[0].input_variables.size());
-  EXPECT_EQ("param.a", result[0].input_variables[0].name);
-  EXPECT_TRUE(result[0].input_variables[0].has_location_attribute);
-  EXPECT_EQ(0u, result[0].input_variables[0].location_attribute);
-  EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[0].component_type);
-  EXPECT_EQ("param.b", result[0].input_variables[1].name);
-  EXPECT_TRUE(result[0].input_variables[1].has_location_attribute);
-  EXPECT_EQ(1u, result[0].input_variables[1].location_attribute);
-  EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[1].component_type);
+    ASSERT_EQ(2u, result[0].input_variables.size());
+    EXPECT_EQ("param.a", result[0].input_variables[0].name);
+    EXPECT_TRUE(result[0].input_variables[0].has_location_attribute);
+    EXPECT_EQ(0u, result[0].input_variables[0].location_attribute);
+    EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[0].component_type);
+    EXPECT_EQ("param.b", result[0].input_variables[1].name);
+    EXPECT_TRUE(result[0].input_variables[1].has_location_attribute);
+    EXPECT_EQ(1u, result[0].input_variables[1].location_attribute);
+    EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[1].component_type);
 
-  ASSERT_EQ(2u, result[0].output_variables.size());
-  EXPECT_EQ("<retval>.a", result[0].output_variables[0].name);
-  EXPECT_TRUE(result[0].output_variables[0].has_location_attribute);
-  EXPECT_EQ(0u, result[0].output_variables[0].location_attribute);
-  EXPECT_EQ(ComponentType::kUInt, result[0].output_variables[0].component_type);
-  EXPECT_EQ("<retval>.b", result[0].output_variables[1].name);
-  EXPECT_TRUE(result[0].output_variables[1].has_location_attribute);
-  EXPECT_EQ(1u, result[0].output_variables[1].location_attribute);
-  EXPECT_EQ(ComponentType::kUInt, result[0].output_variables[1].component_type);
+    ASSERT_EQ(2u, result[0].output_variables.size());
+    EXPECT_EQ("<retval>.a", result[0].output_variables[0].name);
+    EXPECT_TRUE(result[0].output_variables[0].has_location_attribute);
+    EXPECT_EQ(0u, result[0].output_variables[0].location_attribute);
+    EXPECT_EQ(ComponentType::kUInt, result[0].output_variables[0].component_type);
+    EXPECT_EQ("<retval>.b", result[0].output_variables[1].name);
+    EXPECT_TRUE(result[0].output_variables[1].has_location_attribute);
+    EXPECT_EQ(1u, result[0].output_variables[1].location_attribute);
+    EXPECT_EQ(ComponentType::kUInt, result[0].output_variables[1].component_type);
 }
 
 TEST_F(InspectorGetEntryPointTest, MultipleEntryPointsInOutSharedStruct) {
-  auto* interface = MakeInOutStruct("interface", {{"a", 0u}, {"b", 1u}});
-  Func("foo", {}, ty.Of(interface), {Return(Construct(ty.Of(interface)))},
-       {Stage(ast::PipelineStage::kFragment)});
-  Func("bar", {Param("param", ty.Of(interface))}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kFragment)});
-  Inspector& inspector = Build();
+    auto* interface = MakeInOutStruct("interface", {{"a", 0u}, {"b", 1u}});
+    Func("foo", {}, ty.Of(interface), {Return(Construct(ty.Of(interface)))},
+         {Stage(ast::PipelineStage::kFragment)});
+    Func("bar", {Param("param", ty.Of(interface))}, ty.void_(), {},
+         {Stage(ast::PipelineStage::kFragment)});
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetEntryPoints();
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    auto result = inspector.GetEntryPoints();
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
-  ASSERT_EQ(2u, result.size());
+    ASSERT_EQ(2u, result.size());
 
-  ASSERT_EQ(0u, result[0].input_variables.size());
+    ASSERT_EQ(0u, result[0].input_variables.size());
 
-  ASSERT_EQ(2u, result[0].output_variables.size());
-  EXPECT_EQ("<retval>.a", result[0].output_variables[0].name);
-  EXPECT_TRUE(result[0].output_variables[0].has_location_attribute);
-  EXPECT_EQ(0u, result[0].output_variables[0].location_attribute);
-  EXPECT_EQ(ComponentType::kUInt, result[0].output_variables[0].component_type);
-  EXPECT_EQ("<retval>.b", result[0].output_variables[1].name);
-  EXPECT_TRUE(result[0].output_variables[1].has_location_attribute);
-  EXPECT_EQ(1u, result[0].output_variables[1].location_attribute);
-  EXPECT_EQ(ComponentType::kUInt, result[0].output_variables[1].component_type);
+    ASSERT_EQ(2u, result[0].output_variables.size());
+    EXPECT_EQ("<retval>.a", result[0].output_variables[0].name);
+    EXPECT_TRUE(result[0].output_variables[0].has_location_attribute);
+    EXPECT_EQ(0u, result[0].output_variables[0].location_attribute);
+    EXPECT_EQ(ComponentType::kUInt, result[0].output_variables[0].component_type);
+    EXPECT_EQ("<retval>.b", result[0].output_variables[1].name);
+    EXPECT_TRUE(result[0].output_variables[1].has_location_attribute);
+    EXPECT_EQ(1u, result[0].output_variables[1].location_attribute);
+    EXPECT_EQ(ComponentType::kUInt, result[0].output_variables[1].component_type);
 
-  ASSERT_EQ(2u, result[1].input_variables.size());
-  EXPECT_EQ("param.a", result[1].input_variables[0].name);
-  EXPECT_TRUE(result[1].input_variables[0].has_location_attribute);
-  EXPECT_EQ(0u, result[1].input_variables[0].location_attribute);
-  EXPECT_EQ(ComponentType::kUInt, result[1].input_variables[0].component_type);
-  EXPECT_EQ("param.b", result[1].input_variables[1].name);
-  EXPECT_TRUE(result[1].input_variables[1].has_location_attribute);
-  EXPECT_EQ(1u, result[1].input_variables[1].location_attribute);
-  EXPECT_EQ(ComponentType::kUInt, result[1].input_variables[1].component_type);
+    ASSERT_EQ(2u, result[1].input_variables.size());
+    EXPECT_EQ("param.a", result[1].input_variables[0].name);
+    EXPECT_TRUE(result[1].input_variables[0].has_location_attribute);
+    EXPECT_EQ(0u, result[1].input_variables[0].location_attribute);
+    EXPECT_EQ(ComponentType::kUInt, result[1].input_variables[0].component_type);
+    EXPECT_EQ("param.b", result[1].input_variables[1].name);
+    EXPECT_TRUE(result[1].input_variables[1].has_location_attribute);
+    EXPECT_EQ(1u, result[1].input_variables[1].location_attribute);
+    EXPECT_EQ(ComponentType::kUInt, result[1].input_variables[1].component_type);
 
-  ASSERT_EQ(0u, result[1].output_variables.size());
+    ASSERT_EQ(0u, result[1].output_variables.size());
 }
 
 TEST_F(InspectorGetEntryPointTest, MixInOutVariablesAndStruct) {
-  auto* struct_a = MakeInOutStruct("struct_a", {{"a", 0u}, {"b", 1u}});
-  auto* struct_b = MakeInOutStruct("struct_b", {{"a", 2u}});
-  Func("foo",
-       {Param("param_a", ty.Of(struct_a)), Param("param_b", ty.Of(struct_b)),
-        Param("param_c", ty.f32(), {Location(3u)}),
-        Param("param_d", ty.f32(), {Location(4u)})},
-       ty.Of(struct_a), {Return("param_a")},
-       {Stage(ast::PipelineStage::kFragment)});
-  Inspector& inspector = Build();
+    auto* struct_a = MakeInOutStruct("struct_a", {{"a", 0u}, {"b", 1u}});
+    auto* struct_b = MakeInOutStruct("struct_b", {{"a", 2u}});
+    Func("foo",
+         {Param("param_a", ty.Of(struct_a)), Param("param_b", ty.Of(struct_b)),
+          Param("param_c", ty.f32(), {Location(3u)}), Param("param_d", ty.f32(), {Location(4u)})},
+         ty.Of(struct_a), {Return("param_a")}, {Stage(ast::PipelineStage::kFragment)});
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetEntryPoints();
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    auto result = inspector.GetEntryPoints();
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
-  ASSERT_EQ(1u, result.size());
+    ASSERT_EQ(1u, result.size());
 
-  ASSERT_EQ(5u, result[0].input_variables.size());
-  EXPECT_EQ("param_a.a", result[0].input_variables[0].name);
-  EXPECT_TRUE(result[0].input_variables[0].has_location_attribute);
-  EXPECT_EQ(0u, result[0].input_variables[0].location_attribute);
-  EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[0].component_type);
-  EXPECT_EQ("param_a.b", result[0].input_variables[1].name);
-  EXPECT_TRUE(result[0].input_variables[1].has_location_attribute);
-  EXPECT_EQ(1u, result[0].input_variables[1].location_attribute);
-  EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[1].component_type);
-  EXPECT_EQ("param_b.a", result[0].input_variables[2].name);
-  EXPECT_TRUE(result[0].input_variables[2].has_location_attribute);
-  EXPECT_EQ(2u, result[0].input_variables[2].location_attribute);
-  EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[2].component_type);
-  EXPECT_EQ("param_c", result[0].input_variables[3].name);
-  EXPECT_TRUE(result[0].input_variables[3].has_location_attribute);
-  EXPECT_EQ(3u, result[0].input_variables[3].location_attribute);
-  EXPECT_EQ(ComponentType::kFloat, result[0].input_variables[3].component_type);
-  EXPECT_EQ("param_d", result[0].input_variables[4].name);
-  EXPECT_TRUE(result[0].input_variables[4].has_location_attribute);
-  EXPECT_EQ(4u, result[0].input_variables[4].location_attribute);
-  EXPECT_EQ(ComponentType::kFloat, result[0].input_variables[4].component_type);
+    ASSERT_EQ(5u, result[0].input_variables.size());
+    EXPECT_EQ("param_a.a", result[0].input_variables[0].name);
+    EXPECT_TRUE(result[0].input_variables[0].has_location_attribute);
+    EXPECT_EQ(0u, result[0].input_variables[0].location_attribute);
+    EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[0].component_type);
+    EXPECT_EQ("param_a.b", result[0].input_variables[1].name);
+    EXPECT_TRUE(result[0].input_variables[1].has_location_attribute);
+    EXPECT_EQ(1u, result[0].input_variables[1].location_attribute);
+    EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[1].component_type);
+    EXPECT_EQ("param_b.a", result[0].input_variables[2].name);
+    EXPECT_TRUE(result[0].input_variables[2].has_location_attribute);
+    EXPECT_EQ(2u, result[0].input_variables[2].location_attribute);
+    EXPECT_EQ(ComponentType::kUInt, result[0].input_variables[2].component_type);
+    EXPECT_EQ("param_c", result[0].input_variables[3].name);
+    EXPECT_TRUE(result[0].input_variables[3].has_location_attribute);
+    EXPECT_EQ(3u, result[0].input_variables[3].location_attribute);
+    EXPECT_EQ(ComponentType::kFloat, result[0].input_variables[3].component_type);
+    EXPECT_EQ("param_d", result[0].input_variables[4].name);
+    EXPECT_TRUE(result[0].input_variables[4].has_location_attribute);
+    EXPECT_EQ(4u, result[0].input_variables[4].location_attribute);
+    EXPECT_EQ(ComponentType::kFloat, result[0].input_variables[4].component_type);
 
-  ASSERT_EQ(2u, result[0].output_variables.size());
-  EXPECT_EQ("<retval>.a", result[0].output_variables[0].name);
-  EXPECT_TRUE(result[0].output_variables[0].has_location_attribute);
-  EXPECT_EQ(0u, result[0].output_variables[0].location_attribute);
-  EXPECT_EQ(ComponentType::kUInt, result[0].output_variables[0].component_type);
-  EXPECT_EQ("<retval>.b", result[0].output_variables[1].name);
-  EXPECT_TRUE(result[0].output_variables[1].has_location_attribute);
-  EXPECT_EQ(1u, result[0].output_variables[1].location_attribute);
-  EXPECT_EQ(ComponentType::kUInt, result[0].output_variables[1].component_type);
+    ASSERT_EQ(2u, result[0].output_variables.size());
+    EXPECT_EQ("<retval>.a", result[0].output_variables[0].name);
+    EXPECT_TRUE(result[0].output_variables[0].has_location_attribute);
+    EXPECT_EQ(0u, result[0].output_variables[0].location_attribute);
+    EXPECT_EQ(ComponentType::kUInt, result[0].output_variables[0].component_type);
+    EXPECT_EQ("<retval>.b", result[0].output_variables[1].name);
+    EXPECT_TRUE(result[0].output_variables[1].has_location_attribute);
+    EXPECT_EQ(1u, result[0].output_variables[1].location_attribute);
+    EXPECT_EQ(ComponentType::kUInt, result[0].output_variables[1].component_type);
 }
 
 TEST_F(InspectorGetEntryPointTest, OverridableConstantUnreferenced) {
-  AddOverridableConstantWithoutID("foo", ty.f32(), nullptr);
-  MakeEmptyBodyFunction(
-      "ep_func", {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
+    AddOverridableConstantWithoutID("foo", ty.f32(), nullptr);
+    MakeEmptyBodyFunction("ep_func", {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetEntryPoints();
+    auto result = inspector.GetEntryPoints();
 
-  ASSERT_EQ(1u, result.size());
-  EXPECT_EQ(0u, result[0].overridable_constants.size());
+    ASSERT_EQ(1u, result.size());
+    EXPECT_EQ(0u, result[0].overridable_constants.size());
 }
 
 TEST_F(InspectorGetEntryPointTest, OverridableConstantReferencedByEntryPoint) {
-  AddOverridableConstantWithoutID("foo", ty.f32(), nullptr);
-  MakePlainGlobalReferenceBodyFunction(
-      "ep_func", "foo", ty.f32(),
-      {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
+    AddOverridableConstantWithoutID("foo", ty.f32(), nullptr);
+    MakePlainGlobalReferenceBodyFunction("ep_func", "foo", ty.f32(),
+                                         {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetEntryPoints();
+    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.size());
+    ASSERT_EQ(1u, result[0].overridable_constants.size());
+    EXPECT_EQ("foo", result[0].overridable_constants[0].name);
 }
 
 TEST_F(InspectorGetEntryPointTest, OverridableConstantReferencedByCallee) {
-  AddOverridableConstantWithoutID("foo", ty.f32(), nullptr);
-  MakePlainGlobalReferenceBodyFunction("callee_func", "foo", ty.f32(), {});
-  MakeCallerBodyFunction(
-      "ep_func", {"callee_func"},
-      {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
+    AddOverridableConstantWithoutID("foo", ty.f32(), nullptr);
+    MakePlainGlobalReferenceBodyFunction("callee_func", "foo", ty.f32(), {});
+    MakeCallerBodyFunction("ep_func", {"callee_func"},
+                           {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetEntryPoints();
+    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.size());
+    ASSERT_EQ(1u, result[0].overridable_constants.size());
+    EXPECT_EQ("foo", result[0].overridable_constants[0].name);
 }
 
 TEST_F(InspectorGetEntryPointTest, OverridableConstantSomeReferenced) {
-  AddOverridableConstantWithID("foo", 1, ty.f32(), nullptr);
-  AddOverridableConstantWithID("bar", 2, ty.f32(), nullptr);
-  MakePlainGlobalReferenceBodyFunction("callee_func", "foo", ty.f32(), {});
-  MakeCallerBodyFunction(
-      "ep_func", {"callee_func"},
-      {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
+    AddOverridableConstantWithID("foo", 1, ty.f32(), nullptr);
+    AddOverridableConstantWithID("bar", 2, ty.f32(), nullptr);
+    MakePlainGlobalReferenceBodyFunction("callee_func", "foo", ty.f32(), {});
+    MakeCallerBodyFunction("ep_func", {"callee_func"},
+                           {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetEntryPoints();
+    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.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);
 }
 
 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);
+    AddOverridableConstantWithoutID("bool_var", ty.bool_(), nullptr);
+    AddOverridableConstantWithoutID("float_var", ty.f32(), nullptr);
+    AddOverridableConstantWithoutID("u32_var", ty.u32(), nullptr);
+    AddOverridableConstantWithoutID("i32_var", ty.i32(), nullptr);
 
-  MakePlainGlobalReferenceBodyFunction("bool_func", "bool_var", ty.bool_(), {});
-  MakePlainGlobalReferenceBodyFunction("float_func", "float_var", ty.f32(), {});
-  MakePlainGlobalReferenceBodyFunction("u32_func", "u32_var", ty.u32(), {});
-  MakePlainGlobalReferenceBodyFunction("i32_func", "i32_var", ty.i32(), {});
+    MakePlainGlobalReferenceBodyFunction("bool_func", "bool_var", ty.bool_(), {});
+    MakePlainGlobalReferenceBodyFunction("float_func", "float_var", ty.f32(), {});
+    MakePlainGlobalReferenceBodyFunction("u32_func", "u32_var", ty.u32(), {});
+    MakePlainGlobalReferenceBodyFunction("i32_func", "i32_var", ty.i32(), {});
 
-  MakeCallerBodyFunction(
-      "ep_func", {"bool_func", "float_func", "u32_func", "i32_func"},
-      {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
+    MakeCallerBodyFunction("ep_func", {"bool_func", "float_func", "u32_func", "i32_func"},
+                           {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetEntryPoints();
+    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(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);
 }
 
 TEST_F(InspectorGetEntryPointTest, OverridableConstantInitialized) {
-  AddOverridableConstantWithoutID("foo", ty.f32(), Expr(0.0f));
-  MakePlainGlobalReferenceBodyFunction(
-      "ep_func", "foo", ty.f32(),
-      {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
+    AddOverridableConstantWithoutID("foo", ty.f32(), Expr(0.0f));
+    MakePlainGlobalReferenceBodyFunction("ep_func", "foo", ty.f32(),
+                                         {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetEntryPoints();
+    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.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);
 }
 
 TEST_F(InspectorGetEntryPointTest, OverridableConstantUninitialized) {
-  AddOverridableConstantWithoutID("foo", ty.f32(), nullptr);
-  MakePlainGlobalReferenceBodyFunction(
-      "ep_func", "foo", ty.f32(),
-      {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
+    AddOverridableConstantWithoutID("foo", ty.f32(), nullptr);
+    MakePlainGlobalReferenceBodyFunction("ep_func", "foo", ty.f32(),
+                                         {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetEntryPoints();
+    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.size());
+    ASSERT_EQ(1u, result[0].overridable_constants.size());
+    EXPECT_EQ("foo", result[0].overridable_constants[0].name);
 
-  EXPECT_FALSE(result[0].overridable_constants[0].is_initialized);
+    EXPECT_FALSE(result[0].overridable_constants[0].is_initialized);
 }
 
 TEST_F(InspectorGetEntryPointTest, OverridableConstantNumericIDSpecified) {
-  AddOverridableConstantWithoutID("foo_no_id", ty.f32(), nullptr);
-  AddOverridableConstantWithID("foo_id", 1234, ty.f32(), nullptr);
+    AddOverridableConstantWithoutID("foo_no_id", ty.f32(), nullptr);
+    AddOverridableConstantWithID("foo_id", 1234, ty.f32(), nullptr);
 
-  MakePlainGlobalReferenceBodyFunction("no_id_func", "foo_no_id", ty.f32(), {});
-  MakePlainGlobalReferenceBodyFunction("id_func", "foo_id", ty.f32(), {});
+    MakePlainGlobalReferenceBodyFunction("no_id_func", "foo_no_id", ty.f32(), {});
+    MakePlainGlobalReferenceBodyFunction("id_func", "foo_id", ty.f32(), {});
 
-  MakeCallerBodyFunction(
-      "ep_func", {"no_id_func", "id_func"},
-      {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
+    MakeCallerBodyFunction("ep_func", {"no_id_func", "id_func"},
+                           {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetEntryPoints();
+    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(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);
 
-  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].overridable_constants[0].is_numeric_id_specified);
+    EXPECT_TRUE(result[0].overridable_constants[1].is_numeric_id_specified);
 }
 
 TEST_F(InspectorGetEntryPointTest, NonOverridableConstantSkipped) {
-  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()}});
-  MakeCallerBodyFunction("ep_func", {"ub_func"},
-                         {Stage(ast::PipelineStage::kFragment)});
+    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()}});
+    MakeCallerBodyFunction("ep_func", {"ub_func"}, {Stage(ast::PipelineStage::kFragment)});
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetEntryPoints();
+    auto result = inspector.GetEntryPoints();
 
-  ASSERT_EQ(1u, result.size());
-  EXPECT_EQ(0u, result[0].overridable_constants.size());
+    ASSERT_EQ(1u, result.size());
+    EXPECT_EQ(0u, result[0].overridable_constants.size());
 }
 
 TEST_F(InspectorGetEntryPointTest, BuiltinNotReferenced) {
-  MakeEmptyBodyFunction("ep_func", {Stage(ast::PipelineStage::kFragment)});
+    MakeEmptyBodyFunction("ep_func", {Stage(ast::PipelineStage::kFragment)});
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetEntryPoints();
+    auto result = inspector.GetEntryPoints();
 
-  ASSERT_EQ(1u, result.size());
-  EXPECT_FALSE(result[0].input_sample_mask_used);
-  EXPECT_FALSE(result[0].output_sample_mask_used);
-  EXPECT_FALSE(result[0].input_position_used);
-  EXPECT_FALSE(result[0].front_facing_used);
-  EXPECT_FALSE(result[0].sample_index_used);
-  EXPECT_FALSE(result[0].num_workgroups_used);
+    ASSERT_EQ(1u, result.size());
+    EXPECT_FALSE(result[0].input_sample_mask_used);
+    EXPECT_FALSE(result[0].output_sample_mask_used);
+    EXPECT_FALSE(result[0].input_position_used);
+    EXPECT_FALSE(result[0].front_facing_used);
+    EXPECT_FALSE(result[0].sample_index_used);
+    EXPECT_FALSE(result[0].num_workgroups_used);
 }
 
 TEST_F(InspectorGetEntryPointTest, InputSampleMaskSimpleReferenced) {
-  auto* in_var =
-      Param("in_var", ty.u32(), {Builtin(ast::Builtin::kSampleMask)});
-  Func("ep_func", {in_var}, ty.void_(), {Return()},
-       {Stage(ast::PipelineStage::kFragment)}, {});
+    auto* in_var = Param("in_var", ty.u32(), {Builtin(ast::Builtin::kSampleMask)});
+    Func("ep_func", {in_var}, ty.void_(), {Return()}, {Stage(ast::PipelineStage::kFragment)}, {});
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetEntryPoints();
+    auto result = inspector.GetEntryPoints();
 
-  ASSERT_EQ(1u, result.size());
-  EXPECT_TRUE(result[0].input_sample_mask_used);
+    ASSERT_EQ(1u, result.size());
+    EXPECT_TRUE(result[0].input_sample_mask_used);
 }
 
 TEST_F(InspectorGetEntryPointTest, InputSampleMaskStructReferenced) {
-  ast::StructMemberList members;
-  members.push_back(
-      Member("inner_position", ty.u32(), {Builtin(ast::Builtin::kSampleMask)}));
-  Structure("in_struct", members);
-  auto* in_var = Param("in_var", ty.type_name("in_struct"), {});
+    ast::StructMemberList members;
+    members.push_back(Member("inner_position", ty.u32(), {Builtin(ast::Builtin::kSampleMask)}));
+    Structure("in_struct", members);
+    auto* in_var = Param("in_var", ty.type_name("in_struct"), {});
 
-  Func("ep_func", {in_var}, ty.void_(), {Return()},
-       {Stage(ast::PipelineStage::kFragment)}, {});
+    Func("ep_func", {in_var}, ty.void_(), {Return()}, {Stage(ast::PipelineStage::kFragment)}, {});
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetEntryPoints();
+    auto result = inspector.GetEntryPoints();
 
-  ASSERT_EQ(1u, result.size());
-  EXPECT_TRUE(result[0].input_sample_mask_used);
+    ASSERT_EQ(1u, result.size());
+    EXPECT_TRUE(result[0].input_sample_mask_used);
 }
 
 TEST_F(InspectorGetEntryPointTest, OutputSampleMaskSimpleReferenced) {
-  auto* in_var =
-      Param("in_var", ty.u32(), {Builtin(ast::Builtin::kSampleMask)});
-  Func("ep_func", {in_var}, ty.u32(), {Return("in_var")},
-       {Stage(ast::PipelineStage::kFragment)},
-       {Builtin(ast::Builtin::kSampleMask)});
+    auto* in_var = Param("in_var", ty.u32(), {Builtin(ast::Builtin::kSampleMask)});
+    Func("ep_func", {in_var}, ty.u32(), {Return("in_var")}, {Stage(ast::PipelineStage::kFragment)},
+         {Builtin(ast::Builtin::kSampleMask)});
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetEntryPoints();
+    auto result = inspector.GetEntryPoints();
 
-  ASSERT_EQ(1u, result.size());
-  EXPECT_TRUE(result[0].output_sample_mask_used);
+    ASSERT_EQ(1u, result.size());
+    EXPECT_TRUE(result[0].output_sample_mask_used);
 }
 
 TEST_F(InspectorGetEntryPointTest, OutputSampleMaskStructReferenced) {
-  ast::StructMemberList members;
-  members.push_back(Member("inner_sample_mask", ty.u32(),
-                           {Builtin(ast::Builtin::kSampleMask)}));
-  Structure("out_struct", members);
+    ast::StructMemberList members;
+    members.push_back(Member("inner_sample_mask", ty.u32(), {Builtin(ast::Builtin::kSampleMask)}));
+    Structure("out_struct", members);
 
-  Func("ep_func", {}, ty.type_name("out_struct"),
-       {Decl(Var("out_var", ty.type_name("out_struct"))), Return("out_var")},
-       {Stage(ast::PipelineStage::kFragment)}, {});
+    Func("ep_func", {}, ty.type_name("out_struct"),
+         {Decl(Var("out_var", ty.type_name("out_struct"))), Return("out_var")},
+         {Stage(ast::PipelineStage::kFragment)}, {});
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetEntryPoints();
+    auto result = inspector.GetEntryPoints();
 
-  ASSERT_EQ(1u, result.size());
-  EXPECT_TRUE(result[0].output_sample_mask_used);
+    ASSERT_EQ(1u, result.size());
+    EXPECT_TRUE(result[0].output_sample_mask_used);
 }
 
 TEST_F(InspectorGetEntryPointTest, InputPositionSimpleReferenced) {
-  auto* in_var =
-      Param("in_var", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)});
-  Func("ep_func", {in_var}, ty.void_(), {Return()},
-       {Stage(ast::PipelineStage::kFragment)}, {});
+    auto* in_var = Param("in_var", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)});
+    Func("ep_func", {in_var}, ty.void_(), {Return()}, {Stage(ast::PipelineStage::kFragment)}, {});
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetEntryPoints();
+    auto result = inspector.GetEntryPoints();
 
-  ASSERT_EQ(1u, result.size());
-  EXPECT_TRUE(result[0].input_position_used);
+    ASSERT_EQ(1u, result.size());
+    EXPECT_TRUE(result[0].input_position_used);
 }
 
 TEST_F(InspectorGetEntryPointTest, InputPositionStructReferenced) {
-  ast::StructMemberList members;
-  members.push_back(Member("inner_position", ty.vec4<f32>(),
-                           {Builtin(ast::Builtin::kPosition)}));
-  Structure("in_struct", members);
-  auto* in_var = Param("in_var", ty.type_name("in_struct"), {});
+    ast::StructMemberList members;
+    members.push_back(Member("inner_position", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)}));
+    Structure("in_struct", members);
+    auto* in_var = Param("in_var", ty.type_name("in_struct"), {});
 
-  Func("ep_func", {in_var}, ty.void_(), {Return()},
-       {Stage(ast::PipelineStage::kFragment)}, {});
+    Func("ep_func", {in_var}, ty.void_(), {Return()}, {Stage(ast::PipelineStage::kFragment)}, {});
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetEntryPoints();
+    auto result = inspector.GetEntryPoints();
 
-  ASSERT_EQ(1u, result.size());
-  EXPECT_TRUE(result[0].input_position_used);
+    ASSERT_EQ(1u, result.size());
+    EXPECT_TRUE(result[0].input_position_used);
 }
 
 TEST_F(InspectorGetEntryPointTest, FrontFacingSimpleReferenced) {
-  auto* in_var =
-      Param("in_var", ty.bool_(), {Builtin(ast::Builtin::kFrontFacing)});
-  Func("ep_func", {in_var}, ty.void_(), {Return()},
-       {Stage(ast::PipelineStage::kFragment)}, {});
+    auto* in_var = Param("in_var", ty.bool_(), {Builtin(ast::Builtin::kFrontFacing)});
+    Func("ep_func", {in_var}, ty.void_(), {Return()}, {Stage(ast::PipelineStage::kFragment)}, {});
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetEntryPoints();
+    auto result = inspector.GetEntryPoints();
 
-  ASSERT_EQ(1u, result.size());
-  EXPECT_TRUE(result[0].front_facing_used);
+    ASSERT_EQ(1u, result.size());
+    EXPECT_TRUE(result[0].front_facing_used);
 }
 
 TEST_F(InspectorGetEntryPointTest, FrontFacingStructReferenced) {
-  ast::StructMemberList members;
-  members.push_back(Member("inner_position", ty.bool_(),
-                           {Builtin(ast::Builtin::kFrontFacing)}));
-  Structure("in_struct", members);
-  auto* in_var = Param("in_var", ty.type_name("in_struct"), {});
+    ast::StructMemberList members;
+    members.push_back(Member("inner_position", ty.bool_(), {Builtin(ast::Builtin::kFrontFacing)}));
+    Structure("in_struct", members);
+    auto* in_var = Param("in_var", ty.type_name("in_struct"), {});
 
-  Func("ep_func", {in_var}, ty.void_(), {Return()},
-       {Stage(ast::PipelineStage::kFragment)}, {});
+    Func("ep_func", {in_var}, ty.void_(), {Return()}, {Stage(ast::PipelineStage::kFragment)}, {});
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetEntryPoints();
+    auto result = inspector.GetEntryPoints();
 
-  ASSERT_EQ(1u, result.size());
-  EXPECT_TRUE(result[0].front_facing_used);
+    ASSERT_EQ(1u, result.size());
+    EXPECT_TRUE(result[0].front_facing_used);
 }
 
 TEST_F(InspectorGetEntryPointTest, SampleIndexSimpleReferenced) {
-  auto* in_var =
-      Param("in_var", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)});
-  Func("ep_func", {in_var}, ty.void_(), {Return()},
-       {Stage(ast::PipelineStage::kFragment)}, {});
+    auto* in_var = Param("in_var", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)});
+    Func("ep_func", {in_var}, ty.void_(), {Return()}, {Stage(ast::PipelineStage::kFragment)}, {});
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetEntryPoints();
+    auto result = inspector.GetEntryPoints();
 
-  ASSERT_EQ(1u, result.size());
-  EXPECT_TRUE(result[0].sample_index_used);
+    ASSERT_EQ(1u, result.size());
+    EXPECT_TRUE(result[0].sample_index_used);
 }
 
 TEST_F(InspectorGetEntryPointTest, SampleIndexStructReferenced) {
-  ast::StructMemberList members;
-  members.push_back(Member("inner_position", ty.u32(),
-                           {Builtin(ast::Builtin::kSampleIndex)}));
-  Structure("in_struct", members);
-  auto* in_var = Param("in_var", ty.type_name("in_struct"), {});
+    ast::StructMemberList members;
+    members.push_back(Member("inner_position", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)}));
+    Structure("in_struct", members);
+    auto* in_var = Param("in_var", ty.type_name("in_struct"), {});
 
-  Func("ep_func", {in_var}, ty.void_(), {Return()},
-       {Stage(ast::PipelineStage::kFragment)}, {});
+    Func("ep_func", {in_var}, ty.void_(), {Return()}, {Stage(ast::PipelineStage::kFragment)}, {});
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetEntryPoints();
+    auto result = inspector.GetEntryPoints();
 
-  ASSERT_EQ(1u, result.size());
-  EXPECT_TRUE(result[0].sample_index_used);
+    ASSERT_EQ(1u, result.size());
+    EXPECT_TRUE(result[0].sample_index_used);
 }
 
 TEST_F(InspectorGetEntryPointTest, NumWorkgroupsSimpleReferenced) {
-  auto* in_var =
-      Param("in_var", ty.vec3<u32>(), {Builtin(ast::Builtin::kNumWorkgroups)});
-  Func("ep_func", {in_var}, ty.void_(), {Return()},
-       {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)}, {});
+    auto* in_var = Param("in_var", ty.vec3<u32>(), {Builtin(ast::Builtin::kNumWorkgroups)});
+    Func("ep_func", {in_var}, ty.void_(), {Return()},
+         {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)}, {});
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetEntryPoints();
+    auto result = inspector.GetEntryPoints();
 
-  ASSERT_EQ(1u, result.size());
-  EXPECT_TRUE(result[0].num_workgroups_used);
+    ASSERT_EQ(1u, result.size());
+    EXPECT_TRUE(result[0].num_workgroups_used);
 }
 
 TEST_F(InspectorGetEntryPointTest, NumWorkgroupsStructReferenced) {
-  ast::StructMemberList members;
-  members.push_back(Member("inner_position", ty.vec3<u32>(),
-                           {Builtin(ast::Builtin::kNumWorkgroups)}));
-  Structure("in_struct", members);
-  auto* in_var = Param("in_var", ty.type_name("in_struct"), {});
+    ast::StructMemberList members;
+    members.push_back(
+        Member("inner_position", ty.vec3<u32>(), {Builtin(ast::Builtin::kNumWorkgroups)}));
+    Structure("in_struct", members);
+    auto* in_var = Param("in_var", ty.type_name("in_struct"), {});
 
-  Func("ep_func", {in_var}, ty.void_(), {Return()},
-       {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)}, {});
+    Func("ep_func", {in_var}, ty.void_(), {Return()},
+         {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)}, {});
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetEntryPoints();
+    auto result = inspector.GetEntryPoints();
 
-  ASSERT_EQ(1u, result.size());
-  EXPECT_TRUE(result[0].num_workgroups_used);
+    ASSERT_EQ(1u, result.size());
+    EXPECT_TRUE(result[0].num_workgroups_used);
 }
 
 TEST_F(InspectorGetEntryPointTest, ImplicitInterpolate) {
-  ast::StructMemberList members;
-  members.push_back(Member("struct_inner", ty.f32(), {Location(0)}));
-  Structure("in_struct", members);
-  auto* in_var = Param("in_var", ty.type_name("in_struct"), {});
+    ast::StructMemberList members;
+    members.push_back(Member("struct_inner", ty.f32(), {Location(0)}));
+    Structure("in_struct", members);
+    auto* in_var = Param("in_var", ty.type_name("in_struct"), {});
 
-  Func("ep_func", {in_var}, ty.void_(), {Return()},
-       {Stage(ast::PipelineStage::kFragment)}, {});
+    Func("ep_func", {in_var}, ty.void_(), {Return()}, {Stage(ast::PipelineStage::kFragment)}, {});
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetEntryPoints();
+    auto result = inspector.GetEntryPoints();
 
-  ASSERT_EQ(1u, result.size());
-  ASSERT_EQ(1u, result[0].input_variables.size());
-  EXPECT_EQ(InterpolationType::kPerspective,
-            result[0].input_variables[0].interpolation_type);
-  EXPECT_EQ(InterpolationSampling::kCenter,
-            result[0].input_variables[0].interpolation_sampling);
+    ASSERT_EQ(1u, result.size());
+    ASSERT_EQ(1u, result[0].input_variables.size());
+    EXPECT_EQ(InterpolationType::kPerspective, result[0].input_variables[0].interpolation_type);
+    EXPECT_EQ(InterpolationSampling::kCenter, result[0].input_variables[0].interpolation_sampling);
 }
 
 TEST_P(InspectorGetEntryPointInterpolateTest, Test) {
-  auto& params = GetParam();
-  ast::StructMemberList members;
-  members.push_back(
-      Member("struct_inner", ty.f32(),
-             {Interpolate(params.in_type, params.in_sampling), Location(0)}));
-  Structure("in_struct", members);
-  auto* in_var = Param("in_var", ty.type_name("in_struct"), {});
+    auto& params = GetParam();
+    ast::StructMemberList members;
+    members.push_back(Member("struct_inner", ty.f32(),
+                             {Interpolate(params.in_type, params.in_sampling), Location(0)}));
+    Structure("in_struct", members);
+    auto* in_var = Param("in_var", ty.type_name("in_struct"), {});
 
-  Func("ep_func", {in_var}, ty.void_(), {Return()},
-       {Stage(ast::PipelineStage::kFragment)}, {});
+    Func("ep_func", {in_var}, ty.void_(), {Return()}, {Stage(ast::PipelineStage::kFragment)}, {});
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetEntryPoints();
+    auto result = inspector.GetEntryPoints();
 
-  ASSERT_EQ(1u, result.size());
-  ASSERT_EQ(1u, result[0].input_variables.size());
-  EXPECT_EQ(params.out_type, result[0].input_variables[0].interpolation_type);
-  EXPECT_EQ(params.out_sampling,
-            result[0].input_variables[0].interpolation_sampling);
+    ASSERT_EQ(1u, result.size());
+    ASSERT_EQ(1u, result[0].input_variables.size());
+    EXPECT_EQ(params.out_type, result[0].input_variables[0].interpolation_type);
+    EXPECT_EQ(params.out_sampling, result[0].input_variables[0].interpolation_sampling);
 }
 
 INSTANTIATE_TEST_SUITE_P(
@@ -986,33 +923,26 @@
     InspectorGetEntryPointInterpolateTest,
     testing::Values(
         InspectorGetEntryPointInterpolateTestParams{
-            ast::InterpolationType::kPerspective,
-            ast::InterpolationSampling::kCenter,
+            ast::InterpolationType::kPerspective, ast::InterpolationSampling::kCenter,
             InterpolationType::kPerspective, InterpolationSampling::kCenter},
         InspectorGetEntryPointInterpolateTestParams{
-            ast::InterpolationType::kPerspective,
-            ast::InterpolationSampling::kCentroid,
+            ast::InterpolationType::kPerspective, ast::InterpolationSampling::kCentroid,
             InterpolationType::kPerspective, InterpolationSampling::kCentroid},
         InspectorGetEntryPointInterpolateTestParams{
-            ast::InterpolationType::kPerspective,
-            ast::InterpolationSampling::kSample,
+            ast::InterpolationType::kPerspective, ast::InterpolationSampling::kSample,
             InterpolationType::kPerspective, InterpolationSampling::kSample},
         InspectorGetEntryPointInterpolateTestParams{
-            ast::InterpolationType::kPerspective,
-            ast::InterpolationSampling::kNone, InterpolationType::kPerspective,
-            InterpolationSampling::kCenter},
+            ast::InterpolationType::kPerspective, ast::InterpolationSampling::kNone,
+            InterpolationType::kPerspective, InterpolationSampling::kCenter},
         InspectorGetEntryPointInterpolateTestParams{
-            ast::InterpolationType::kLinear,
-            ast::InterpolationSampling::kCenter, InterpolationType::kLinear,
-            InterpolationSampling::kCenter},
+            ast::InterpolationType::kLinear, ast::InterpolationSampling::kCenter,
+            InterpolationType::kLinear, InterpolationSampling::kCenter},
         InspectorGetEntryPointInterpolateTestParams{
-            ast::InterpolationType::kLinear,
-            ast::InterpolationSampling::kCentroid, InterpolationType::kLinear,
-            InterpolationSampling::kCentroid},
+            ast::InterpolationType::kLinear, ast::InterpolationSampling::kCentroid,
+            InterpolationType::kLinear, InterpolationSampling::kCentroid},
         InspectorGetEntryPointInterpolateTestParams{
-            ast::InterpolationType::kLinear,
-            ast::InterpolationSampling::kSample, InterpolationType::kLinear,
-            InterpolationSampling::kSample},
+            ast::InterpolationType::kLinear, ast::InterpolationSampling::kSample,
+            InterpolationType::kLinear, InterpolationSampling::kSample},
         InspectorGetEntryPointInterpolateTestParams{
             ast::InterpolationType::kLinear, ast::InterpolationSampling::kNone,
             InterpolationType::kLinear, InterpolationSampling::kCenter},
@@ -1021,1659 +951,1553 @@
             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));
+    AddOverridableConstantWithID("foo", 1, ty.bool_(), nullptr);
+    AddOverridableConstantWithID("bar", 20, ty.bool_(), Expr(true));
+    AddOverridableConstantWithID("baz", 300, ty.bool_(), Expr(false));
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetConstantIDs();
-  ASSERT_EQ(3u, result.size());
+    auto result = inspector.GetConstantIDs();
+    ASSERT_EQ(3u, result.size());
 
-  ASSERT_TRUE(result.find(1) != result.end());
-  EXPECT_TRUE(result[1].IsNull());
+    ASSERT_TRUE(result.find(1) != result.end());
+    EXPECT_TRUE(result[1].IsNull());
 
-  ASSERT_TRUE(result.find(20) != result.end());
-  EXPECT_TRUE(result[20].IsBool());
-  EXPECT_TRUE(result[20].AsBool());
+    ASSERT_TRUE(result.find(20) != result.end());
+    EXPECT_TRUE(result[20].IsBool());
+    EXPECT_TRUE(result[20].AsBool());
 
-  ASSERT_TRUE(result.find(300) != result.end());
-  EXPECT_TRUE(result[300].IsBool());
-  EXPECT_FALSE(result[300].AsBool());
+    ASSERT_TRUE(result.find(300) != result.end());
+    EXPECT_TRUE(result[300].IsBool());
+    EXPECT_FALSE(result[300].AsBool());
 }
 
 TEST_F(InspectorGetConstantIDsTest, U32) {
-  AddOverridableConstantWithID("foo", 1, ty.u32(), nullptr);
-  AddOverridableConstantWithID("bar", 20, ty.u32(), Expr(42u));
+    AddOverridableConstantWithID("foo", 1, ty.u32(), nullptr);
+    AddOverridableConstantWithID("bar", 20, ty.u32(), Expr(42_u));
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetConstantIDs();
-  ASSERT_EQ(2u, result.size());
+    auto result = inspector.GetConstantIDs();
+    ASSERT_EQ(2u, result.size());
 
-  ASSERT_TRUE(result.find(1) != result.end());
-  EXPECT_TRUE(result[1].IsNull());
+    ASSERT_TRUE(result.find(1) != result.end());
+    EXPECT_TRUE(result[1].IsNull());
 
-  ASSERT_TRUE(result.find(20) != result.end());
-  EXPECT_TRUE(result[20].IsU32());
-  EXPECT_EQ(42u, result[20].AsU32());
+    ASSERT_TRUE(result.find(20) != result.end());
+    EXPECT_TRUE(result[20].IsU32());
+    EXPECT_EQ(42u, result[20].AsU32());
 }
 
 TEST_F(InspectorGetConstantIDsTest, I32) {
-  AddOverridableConstantWithID("foo", 1, ty.i32(), nullptr);
-  AddOverridableConstantWithID("bar", 20, ty.i32(), Expr(-42));
-  AddOverridableConstantWithID("baz", 300, ty.i32(), Expr(42));
+    AddOverridableConstantWithID("foo", 1, ty.i32(), nullptr);
+    AddOverridableConstantWithID("bar", 20, ty.i32(), Expr(i32(-42)));
+    AddOverridableConstantWithID("baz", 300, ty.i32(), Expr(42_i));
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetConstantIDs();
-  ASSERT_EQ(3u, result.size());
+    auto result = inspector.GetConstantIDs();
+    ASSERT_EQ(3u, result.size());
 
-  ASSERT_TRUE(result.find(1) != result.end());
-  EXPECT_TRUE(result[1].IsNull());
+    ASSERT_TRUE(result.find(1) != result.end());
+    EXPECT_TRUE(result[1].IsNull());
 
-  ASSERT_TRUE(result.find(20) != result.end());
-  EXPECT_TRUE(result[20].IsI32());
-  EXPECT_EQ(-42, result[20].AsI32());
+    ASSERT_TRUE(result.find(20) != result.end());
+    EXPECT_TRUE(result[20].IsI32());
+    EXPECT_EQ(-42, result[20].AsI32());
 
-  ASSERT_TRUE(result.find(300) != result.end());
-  EXPECT_TRUE(result[300].IsI32());
-  EXPECT_EQ(42, result[300].AsI32());
+    ASSERT_TRUE(result.find(300) != result.end());
+    EXPECT_TRUE(result[300].IsI32());
+    EXPECT_EQ(42, result[300].AsI32());
 }
 
 TEST_F(InspectorGetConstantIDsTest, Float) {
-  AddOverridableConstantWithID("foo", 1, ty.f32(), nullptr);
-  AddOverridableConstantWithID("bar", 20, ty.f32(), Expr(0.0f));
-  AddOverridableConstantWithID("baz", 300, ty.f32(), Expr(-10.0f));
-  AddOverridableConstantWithID("x", 4000, ty.f32(), Expr(15.0f));
+    AddOverridableConstantWithID("foo", 1, ty.f32(), nullptr);
+    AddOverridableConstantWithID("bar", 20, ty.f32(), Expr(0.0f));
+    AddOverridableConstantWithID("baz", 300, ty.f32(), Expr(-10.0f));
+    AddOverridableConstantWithID("x", 4000, ty.f32(), Expr(15.0f));
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetConstantIDs();
-  ASSERT_EQ(4u, result.size());
+    auto result = inspector.GetConstantIDs();
+    ASSERT_EQ(4u, result.size());
 
-  ASSERT_TRUE(result.find(1) != result.end());
-  EXPECT_TRUE(result[1].IsNull());
+    ASSERT_TRUE(result.find(1) != result.end());
+    EXPECT_TRUE(result[1].IsNull());
 
-  ASSERT_TRUE(result.find(20) != result.end());
-  EXPECT_TRUE(result[20].IsFloat());
-  EXPECT_FLOAT_EQ(0.0, result[20].AsFloat());
+    ASSERT_TRUE(result.find(20) != result.end());
+    EXPECT_TRUE(result[20].IsFloat());
+    EXPECT_FLOAT_EQ(0.0, result[20].AsFloat());
 
-  ASSERT_TRUE(result.find(300) != result.end());
-  EXPECT_TRUE(result[300].IsFloat());
-  EXPECT_FLOAT_EQ(-10.0, result[300].AsFloat());
+    ASSERT_TRUE(result.find(300) != result.end());
+    EXPECT_TRUE(result[300].IsFloat());
+    EXPECT_FLOAT_EQ(-10.0, result[300].AsFloat());
 
-  ASSERT_TRUE(result.find(4000) != result.end());
-  EXPECT_TRUE(result[4000].IsFloat());
-  EXPECT_FLOAT_EQ(15.0, result[4000].AsFloat());
+    ASSERT_TRUE(result.find(4000) != result.end());
+    EXPECT_TRUE(result[4000].IsFloat());
+    EXPECT_FLOAT_EQ(15.0, result[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);
+    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);
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetConstantNameToIdMap();
-  ASSERT_EQ(6u, result.size());
+    auto result = inspector.GetConstantNameToIdMap();
+    ASSERT_EQ(6u, result.size());
 
-  ASSERT_TRUE(result.count("v1"));
-  EXPECT_EQ(result["v1"], 1u);
+    ASSERT_TRUE(result.count("v1"));
+    EXPECT_EQ(result["v1"], 1u);
 
-  ASSERT_TRUE(result.count("v20"));
-  EXPECT_EQ(result["v20"], 20u);
+    ASSERT_TRUE(result.count("v20"));
+    EXPECT_EQ(result["v20"], 20u);
 
-  ASSERT_TRUE(result.count("v300"));
-  EXPECT_EQ(result["v300"], 300u);
+    ASSERT_TRUE(result.count("v300"));
+    EXPECT_EQ(result["v300"], 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());
+    ASSERT_TRUE(result.count("a"));
+    ASSERT_TRUE(program_->Sem().Get<sem::GlobalVariable>(a));
+    EXPECT_EQ(result["a"], program_->Sem().Get<sem::GlobalVariable>(a)->ConstantId());
 
-  ASSERT_TRUE(result.count("b"));
-  ASSERT_TRUE(program_->Sem().Get<sem::GlobalVariable>(b));
-  EXPECT_EQ(result["b"],
-            program_->Sem().Get<sem::GlobalVariable>(b)->ConstantId());
+    ASSERT_TRUE(result.count("b"));
+    ASSERT_TRUE(program_->Sem().Get<sem::GlobalVariable>(b));
+    EXPECT_EQ(result["b"], program_->Sem().Get<sem::GlobalVariable>(b)->ConstantId());
 
-  ASSERT_TRUE(result.count("c"));
-  ASSERT_TRUE(program_->Sem().Get<sem::GlobalVariable>(c));
-  EXPECT_EQ(result["c"],
-            program_->Sem().Get<sem::GlobalVariable>(c)->ConstantId());
+    ASSERT_TRUE(result.count("c"));
+    ASSERT_TRUE(program_->Sem().Get<sem::GlobalVariable>(c));
+    EXPECT_EQ(result["c"], program_->Sem().Get<sem::GlobalVariable>(c)->ConstantId());
 }
 
 TEST_F(InspectorGetStorageSizeTest, Empty) {
-  MakeEmptyBodyFunction("ep_func",
-                        ast::AttributeList{Stage(ast::PipelineStage::kCompute),
-                                           WorkgroupSize(1)});
-  Inspector& inspector = Build();
-  EXPECT_EQ(0u, inspector.GetStorageSize("ep_func"));
+    MakeEmptyBodyFunction(
+        "ep_func", ast::AttributeList{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+    Inspector& inspector = Build();
+    EXPECT_EQ(0u, inspector.GetStorageSize("ep_func"));
 }
 
 TEST_F(InspectorGetStorageSizeTest, Simple_NonStruct) {
-  AddUniformBuffer("ub_var", ty.i32(), 0, 0);
-  AddStorageBuffer("sb_var", ty.i32(), ast::Access::kReadWrite, 1, 0);
-  AddStorageBuffer("rosb_var", ty.i32(), ast::Access::kRead, 1, 1);
-  Func("ep_func", {}, ty.void_(),
-       {
-           Decl(Const("ub", nullptr, Expr("ub_var"))),
-           Decl(Const("sb", nullptr, Expr("sb_var"))),
-           Decl(Const("rosb", nullptr, Expr("rosb_var"))),
-       },
-       {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
+    AddUniformBuffer("ub_var", ty.i32(), 0, 0);
+    AddStorageBuffer("sb_var", ty.i32(), ast::Access::kReadWrite, 1, 0);
+    AddStorageBuffer("rosb_var", ty.i32(), ast::Access::kRead, 1, 1);
+    Func("ep_func", {}, ty.void_(),
+         {
+             Decl(Let("ub", nullptr, Expr("ub_var"))),
+             Decl(Let("sb", nullptr, Expr("sb_var"))),
+             Decl(Let("rosb", nullptr, Expr("rosb_var"))),
+         },
+         {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  EXPECT_EQ(12u, inspector.GetStorageSize("ep_func"));
+    EXPECT_EQ(12u, inspector.GetStorageSize("ep_func"));
 }
 
 TEST_F(InspectorGetStorageSizeTest, Simple_Struct) {
-  auto* ub_struct_type = MakeUniformBufferType("ub_type", {ty.i32(), ty.i32()});
-  AddUniformBuffer("ub_var", ty.Of(ub_struct_type), 0, 0);
-  MakeStructVariableReferenceBodyFunction("ub_func", "ub_var", {{0, ty.i32()}});
+    auto* ub_struct_type = MakeUniformBufferType("ub_type", {ty.i32(), ty.i32()});
+    AddUniformBuffer("ub_var", ty.Of(ub_struct_type), 0, 0);
+    MakeStructVariableReferenceBodyFunction("ub_func", "ub_var", {{0, ty.i32()}});
 
-  auto sb = MakeStorageBufferTypes("sb_type", {ty.i32()});
-  AddStorageBuffer("sb_var", sb(), ast::Access::kReadWrite, 1, 0);
-  MakeStructVariableReferenceBodyFunction("sb_func", "sb_var", {{0, ty.i32()}});
+    auto sb = MakeStorageBufferTypes("sb_type", {ty.i32()});
+    AddStorageBuffer("sb_var", sb(), ast::Access::kReadWrite, 1, 0);
+    MakeStructVariableReferenceBodyFunction("sb_func", "sb_var", {{0, ty.i32()}});
 
-  auto ro_sb = MakeStorageBufferTypes("rosb_type", {ty.i32()});
-  AddStorageBuffer("rosb_var", ro_sb(), ast::Access::kRead, 1, 1);
-  MakeStructVariableReferenceBodyFunction("rosb_func", "rosb_var",
-                                          {{0, ty.i32()}});
+    auto ro_sb = MakeStorageBufferTypes("rosb_type", {ty.i32()});
+    AddStorageBuffer("rosb_var", ro_sb(), ast::Access::kRead, 1, 1);
+    MakeStructVariableReferenceBodyFunction("rosb_func", "rosb_var", {{0, ty.i32()}});
 
-  MakeCallerBodyFunction("ep_func", {"ub_func", "sb_func", "rosb_func"},
-                         ast::AttributeList{
-                             Stage(ast::PipelineStage::kCompute),
-                             WorkgroupSize(1),
-                         });
+    MakeCallerBodyFunction("ep_func", {"ub_func", "sb_func", "rosb_func"},
+                           ast::AttributeList{
+                               Stage(ast::PipelineStage::kCompute),
+                               WorkgroupSize(1_i),
+                           });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  EXPECT_EQ(16u, inspector.GetStorageSize("ep_func"));
+    EXPECT_EQ(16u, inspector.GetStorageSize("ep_func"));
 }
 
 TEST_F(InspectorGetStorageSizeTest, NonStructVec3) {
-  AddUniformBuffer("ub_var", ty.vec3<f32>(), 0, 0);
-  Func("ep_func", {}, ty.void_(),
-       {
-           Decl(Const("ub", nullptr, Expr("ub_var"))),
-       },
-       {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
+    AddUniformBuffer("ub_var", ty.vec3<f32>(), 0, 0);
+    Func("ep_func", {}, ty.void_(),
+         {
+             Decl(Let("ub", nullptr, Expr("ub_var"))),
+         },
+         {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  EXPECT_EQ(12u, inspector.GetStorageSize("ep_func"));
+    EXPECT_EQ(12u, inspector.GetStorageSize("ep_func"));
 }
 
 TEST_F(InspectorGetStorageSizeTest, StructVec3) {
-  auto* ub_struct_type = MakeUniformBufferType("ub_type", {ty.vec3<f32>()});
-  AddUniformBuffer("ub_var", ty.Of(ub_struct_type), 0, 0);
-  Func("ep_func", {}, ty.void_(),
-       {
-           Decl(Const("ub", nullptr, Expr("ub_var"))),
-       },
-       {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
+    auto* ub_struct_type = MakeUniformBufferType("ub_type", {ty.vec3<f32>()});
+    AddUniformBuffer("ub_var", ty.Of(ub_struct_type), 0, 0);
+    Func("ep_func", {}, ty.void_(),
+         {
+             Decl(Let("ub", nullptr, Expr("ub_var"))),
+         },
+         {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  EXPECT_EQ(16u, inspector.GetStorageSize("ep_func"));
+    EXPECT_EQ(16u, inspector.GetStorageSize("ep_func"));
 }
 
 TEST_F(InspectorGetResourceBindingsTest, Empty) {
-  MakeCallerBodyFunction("ep_func", {},
-                         ast::AttributeList{
-                             Stage(ast::PipelineStage::kFragment),
-                         });
+    MakeCallerBodyFunction("ep_func", {},
+                           ast::AttributeList{
+                               Stage(ast::PipelineStage::kFragment),
+                           });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetResourceBindings("ep_func");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
-  ASSERT_EQ(0u, result.size());
+    auto result = inspector.GetResourceBindings("ep_func");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    ASSERT_EQ(0u, result.size());
 }
 
 TEST_F(InspectorGetResourceBindingsTest, Simple) {
-  auto* ub_struct_type = MakeUniformBufferType("ub_type", {ty.i32()});
-  AddUniformBuffer("ub_var", ty.Of(ub_struct_type), 0, 0);
-  MakeStructVariableReferenceBodyFunction("ub_func", "ub_var", {{0, ty.i32()}});
+    auto* ub_struct_type = MakeUniformBufferType("ub_type", {ty.i32()});
+    AddUniformBuffer("ub_var", ty.Of(ub_struct_type), 0, 0);
+    MakeStructVariableReferenceBodyFunction("ub_func", "ub_var", {{0, ty.i32()}});
 
-  auto sb = MakeStorageBufferTypes("sb_type", {ty.i32()});
-  AddStorageBuffer("sb_var", sb(), ast::Access::kReadWrite, 1, 0);
-  MakeStructVariableReferenceBodyFunction("sb_func", "sb_var", {{0, ty.i32()}});
+    auto sb = MakeStorageBufferTypes("sb_type", {ty.i32()});
+    AddStorageBuffer("sb_var", sb(), ast::Access::kReadWrite, 1, 0);
+    MakeStructVariableReferenceBodyFunction("sb_func", "sb_var", {{0, ty.i32()}});
 
-  auto ro_sb = MakeStorageBufferTypes("rosb_type", {ty.i32()});
-  AddStorageBuffer("rosb_var", ro_sb(), ast::Access::kRead, 1, 1);
-  MakeStructVariableReferenceBodyFunction("rosb_func", "rosb_var",
-                                          {{0, ty.i32()}});
+    auto ro_sb = MakeStorageBufferTypes("rosb_type", {ty.i32()});
+    AddStorageBuffer("rosb_var", ro_sb(), ast::Access::kRead, 1, 1);
+    MakeStructVariableReferenceBodyFunction("rosb_func", "rosb_var", {{0, ty.i32()}});
 
-  auto* s_texture_type =
-      ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
-  AddResource("s_texture", s_texture_type, 2, 0);
-  AddSampler("s_var", 3, 0);
-  AddGlobalVariable("s_coords", ty.f32());
-  MakeSamplerReferenceBodyFunction("s_func", "s_texture", "s_var", "s_coords",
-                                   ty.f32(), {});
+    auto* s_texture_type = ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
+    AddResource("s_texture", s_texture_type, 2, 0);
+    AddSampler("s_var", 3, 0);
+    AddGlobalVariable("s_coords", ty.f32());
+    MakeSamplerReferenceBodyFunction("s_func", "s_texture", "s_var", "s_coords", ty.f32(), {});
 
-  auto* cs_depth_texture_type = ty.depth_texture(ast::TextureDimension::k2d);
-  AddResource("cs_texture", cs_depth_texture_type, 3, 1);
-  AddComparisonSampler("cs_var", 3, 2);
-  AddGlobalVariable("cs_coords", ty.vec2<f32>());
-  AddGlobalVariable("cs_depth", ty.f32());
-  MakeComparisonSamplerReferenceBodyFunction(
-      "cs_func", "cs_texture", "cs_var", "cs_coords", "cs_depth", ty.f32(), {});
+    auto* cs_depth_texture_type = ty.depth_texture(ast::TextureDimension::k2d);
+    AddResource("cs_texture", cs_depth_texture_type, 3, 1);
+    AddComparisonSampler("cs_var", 3, 2);
+    AddGlobalVariable("cs_coords", ty.vec2<f32>());
+    AddGlobalVariable("cs_depth", ty.f32());
+    MakeComparisonSamplerReferenceBodyFunction("cs_func", "cs_texture", "cs_var", "cs_coords",
+                                               "cs_depth", ty.f32(), {});
 
-  auto* depth_ms_texture_type =
-      ty.depth_multisampled_texture(ast::TextureDimension::k2d);
-  AddResource("depth_ms_texture", depth_ms_texture_type, 3, 3);
-  Func("depth_ms_func", {}, ty.void_(), {Ignore("depth_ms_texture")});
+    auto* depth_ms_texture_type = ty.depth_multisampled_texture(ast::TextureDimension::k2d);
+    AddResource("depth_ms_texture", depth_ms_texture_type, 3, 3);
+    Func("depth_ms_func", {}, ty.void_(), {Ignore("depth_ms_texture")});
 
-  auto* st_type = MakeStorageTextureTypes(ast::TextureDimension::k2d,
-                                          ast::TexelFormat::kR32Uint);
-  AddStorageTexture("st_var", st_type, 4, 0);
-  MakeStorageTextureBodyFunction("st_func", "st_var", ty.vec2<i32>(), {});
+    auto* st_type = MakeStorageTextureTypes(ast::TextureDimension::k2d, ast::TexelFormat::kR32Uint);
+    AddStorageTexture("st_var", st_type, 4, 0);
+    MakeStorageTextureBodyFunction("st_func", "st_var", ty.vec2<i32>(), {});
 
-  MakeCallerBodyFunction("ep_func",
-                         {"ub_func", "sb_func", "rosb_func", "s_func",
-                          "cs_func", "depth_ms_func", "st_func"},
-                         ast::AttributeList{
-                             Stage(ast::PipelineStage::kFragment),
-                         });
+    MakeCallerBodyFunction(
+        "ep_func",
+        {"ub_func", "sb_func", "rosb_func", "s_func", "cs_func", "depth_ms_func", "st_func"},
+        ast::AttributeList{
+            Stage(ast::PipelineStage::kFragment),
+        });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetResourceBindings("ep_func");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
-  ASSERT_EQ(9u, result.size());
+    auto result = inspector.GetResourceBindings("ep_func");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    ASSERT_EQ(9u, result.size());
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kUniformBuffer,
-            result[0].resource_type);
-  EXPECT_EQ(0u, result[0].bind_group);
-  EXPECT_EQ(0u, result[0].binding);
+    EXPECT_EQ(ResourceBinding::ResourceType::kUniformBuffer, result[0].resource_type);
+    EXPECT_EQ(0u, result[0].bind_group);
+    EXPECT_EQ(0u, result[0].binding);
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer,
-            result[1].resource_type);
-  EXPECT_EQ(1u, result[1].bind_group);
-  EXPECT_EQ(0u, result[1].binding);
+    EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer, result[1].resource_type);
+    EXPECT_EQ(1u, result[1].bind_group);
+    EXPECT_EQ(0u, result[1].binding);
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kReadOnlyStorageBuffer,
-            result[2].resource_type);
-  EXPECT_EQ(1u, result[2].bind_group);
-  EXPECT_EQ(1u, result[2].binding);
+    EXPECT_EQ(ResourceBinding::ResourceType::kReadOnlyStorageBuffer, result[2].resource_type);
+    EXPECT_EQ(1u, result[2].bind_group);
+    EXPECT_EQ(1u, result[2].binding);
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kSampler, result[3].resource_type);
-  EXPECT_EQ(3u, result[3].bind_group);
-  EXPECT_EQ(0u, result[3].binding);
+    EXPECT_EQ(ResourceBinding::ResourceType::kSampler, result[3].resource_type);
+    EXPECT_EQ(3u, result[3].bind_group);
+    EXPECT_EQ(0u, result[3].binding);
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kComparisonSampler,
-            result[4].resource_type);
-  EXPECT_EQ(3u, result[4].bind_group);
-  EXPECT_EQ(2u, result[4].binding);
+    EXPECT_EQ(ResourceBinding::ResourceType::kComparisonSampler, result[4].resource_type);
+    EXPECT_EQ(3u, result[4].bind_group);
+    EXPECT_EQ(2u, result[4].binding);
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kSampledTexture,
-            result[5].resource_type);
-  EXPECT_EQ(2u, result[5].bind_group);
-  EXPECT_EQ(0u, result[5].binding);
+    EXPECT_EQ(ResourceBinding::ResourceType::kSampledTexture, result[5].resource_type);
+    EXPECT_EQ(2u, result[5].bind_group);
+    EXPECT_EQ(0u, result[5].binding);
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kWriteOnlyStorageTexture,
-            result[6].resource_type);
-  EXPECT_EQ(4u, result[6].bind_group);
-  EXPECT_EQ(0u, result[6].binding);
+    EXPECT_EQ(ResourceBinding::ResourceType::kWriteOnlyStorageTexture, result[6].resource_type);
+    EXPECT_EQ(4u, result[6].bind_group);
+    EXPECT_EQ(0u, result[6].binding);
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kDepthTexture,
-            result[7].resource_type);
-  EXPECT_EQ(3u, result[7].bind_group);
-  EXPECT_EQ(1u, result[7].binding);
+    EXPECT_EQ(ResourceBinding::ResourceType::kDepthTexture, result[7].resource_type);
+    EXPECT_EQ(3u, result[7].bind_group);
+    EXPECT_EQ(1u, result[7].binding);
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kDepthMultisampledTexture,
-            result[8].resource_type);
-  EXPECT_EQ(3u, result[8].bind_group);
-  EXPECT_EQ(3u, result[8].binding);
+    EXPECT_EQ(ResourceBinding::ResourceType::kDepthMultisampledTexture, result[8].resource_type);
+    EXPECT_EQ(3u, result[8].bind_group);
+    EXPECT_EQ(3u, result[8].binding);
 }
 
 TEST_F(InspectorGetUniformBufferResourceBindingsTest, MissingEntryPoint) {
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetUniformBufferResourceBindings("ep_func");
-  ASSERT_TRUE(inspector.has_error());
-  std::string error = inspector.error();
-  EXPECT_TRUE(error.find("not found") != std::string::npos);
+    auto result = inspector.GetUniformBufferResourceBindings("ep_func");
+    ASSERT_TRUE(inspector.has_error());
+    std::string error = inspector.error();
+    EXPECT_TRUE(error.find("not found") != std::string::npos);
 }
 
 TEST_F(InspectorGetUniformBufferResourceBindingsTest, NonEntryPointFunc) {
-  auto* foo_struct_type = MakeUniformBufferType("foo_type", {ty.i32()});
-  AddUniformBuffer("foo_ub", ty.Of(foo_struct_type), 0, 0);
+    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()}});
+    MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub", {{0, ty.i32()}});
 
-  MakeCallerBodyFunction("ep_func", {"ub_func"},
-                         ast::AttributeList{
-                             Stage(ast::PipelineStage::kFragment),
-                         });
+    MakeCallerBodyFunction("ep_func", {"ub_func"},
+                           ast::AttributeList{
+                               Stage(ast::PipelineStage::kFragment),
+                           });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetUniformBufferResourceBindings("ub_func");
-  std::string error = inspector.error();
-  EXPECT_TRUE(error.find("not an entry point") != std::string::npos);
+    auto result = inspector.GetUniformBufferResourceBindings("ub_func");
+    std::string error = inspector.error();
+    EXPECT_TRUE(error.find("not an entry point") != std::string::npos);
 }
 
 TEST_F(InspectorGetUniformBufferResourceBindingsTest, Simple_NonStruct) {
-  AddUniformBuffer("foo_ub", ty.i32(), 0, 0);
-  MakePlainGlobalReferenceBodyFunction("ub_func", "foo_ub", ty.i32(), {});
+    AddUniformBuffer("foo_ub", ty.i32(), 0, 0);
+    MakePlainGlobalReferenceBodyFunction("ub_func", "foo_ub", ty.i32(), {});
 
-  MakeCallerBodyFunction("ep_func", {"ub_func"},
-                         ast::AttributeList{
-                             Stage(ast::PipelineStage::kFragment),
-                         });
+    MakeCallerBodyFunction("ep_func", {"ub_func"},
+                           ast::AttributeList{
+                               Stage(ast::PipelineStage::kFragment),
+                           });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetUniformBufferResourceBindings("ep_func");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
-  ASSERT_EQ(1u, result.size());
+    auto result = inspector.GetUniformBufferResourceBindings("ep_func");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    ASSERT_EQ(1u, result.size());
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kUniformBuffer,
-            result[0].resource_type);
-  EXPECT_EQ(0u, result[0].bind_group);
-  EXPECT_EQ(0u, result[0].binding);
-  EXPECT_EQ(4u, result[0].size);
-  EXPECT_EQ(4u, result[0].size_no_padding);
+    EXPECT_EQ(ResourceBinding::ResourceType::kUniformBuffer, result[0].resource_type);
+    EXPECT_EQ(0u, result[0].bind_group);
+    EXPECT_EQ(0u, result[0].binding);
+    EXPECT_EQ(4u, result[0].size);
+    EXPECT_EQ(4u, result[0].size_no_padding);
 }
 
 TEST_F(InspectorGetUniformBufferResourceBindingsTest, Simple_Struct) {
-  auto* foo_struct_type = MakeUniformBufferType("foo_type", {ty.i32()});
-  AddUniformBuffer("foo_ub", ty.Of(foo_struct_type), 0, 0);
+    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()}});
+    MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub", {{0, ty.i32()}});
 
-  MakeCallerBodyFunction("ep_func", {"ub_func"},
-                         ast::AttributeList{
-                             Stage(ast::PipelineStage::kFragment),
-                         });
+    MakeCallerBodyFunction("ep_func", {"ub_func"},
+                           ast::AttributeList{
+                               Stage(ast::PipelineStage::kFragment),
+                           });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetUniformBufferResourceBindings("ep_func");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
-  ASSERT_EQ(1u, result.size());
+    auto result = inspector.GetUniformBufferResourceBindings("ep_func");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    ASSERT_EQ(1u, result.size());
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kUniformBuffer,
-            result[0].resource_type);
-  EXPECT_EQ(0u, result[0].bind_group);
-  EXPECT_EQ(0u, result[0].binding);
-  EXPECT_EQ(4u, result[0].size);
-  EXPECT_EQ(4u, result[0].size_no_padding);
+    EXPECT_EQ(ResourceBinding::ResourceType::kUniformBuffer, result[0].resource_type);
+    EXPECT_EQ(0u, result[0].bind_group);
+    EXPECT_EQ(0u, result[0].binding);
+    EXPECT_EQ(4u, result[0].size);
+    EXPECT_EQ(4u, result[0].size_no_padding);
 }
 
 TEST_F(InspectorGetUniformBufferResourceBindingsTest, MultipleMembers) {
-  auto* foo_struct_type =
-      MakeUniformBufferType("foo_type", {ty.i32(), ty.u32(), ty.f32()});
-  AddUniformBuffer("foo_ub", ty.Of(foo_struct_type), 0, 0);
+    auto* foo_struct_type = MakeUniformBufferType("foo_type", {ty.i32(), ty.u32(), ty.f32()});
+    AddUniformBuffer("foo_ub", ty.Of(foo_struct_type), 0, 0);
 
-  MakeStructVariableReferenceBodyFunction(
-      "ub_func", "foo_ub", {{0, ty.i32()}, {1, ty.u32()}, {2, ty.f32()}});
+    MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub",
+                                            {{0, ty.i32()}, {1, ty.u32()}, {2, ty.f32()}});
 
-  MakeCallerBodyFunction("ep_func", {"ub_func"},
-                         ast::AttributeList{
-                             Stage(ast::PipelineStage::kFragment),
-                         });
+    MakeCallerBodyFunction("ep_func", {"ub_func"},
+                           ast::AttributeList{
+                               Stage(ast::PipelineStage::kFragment),
+                           });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetUniformBufferResourceBindings("ep_func");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
-  ASSERT_EQ(1u, result.size());
+    auto result = inspector.GetUniformBufferResourceBindings("ep_func");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    ASSERT_EQ(1u, result.size());
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kUniformBuffer,
-            result[0].resource_type);
-  EXPECT_EQ(0u, result[0].bind_group);
-  EXPECT_EQ(0u, result[0].binding);
-  EXPECT_EQ(12u, result[0].size);
-  EXPECT_EQ(12u, result[0].size_no_padding);
+    EXPECT_EQ(ResourceBinding::ResourceType::kUniformBuffer, result[0].resource_type);
+    EXPECT_EQ(0u, result[0].bind_group);
+    EXPECT_EQ(0u, result[0].binding);
+    EXPECT_EQ(12u, result[0].size);
+    EXPECT_EQ(12u, result[0].size_no_padding);
 }
 
 TEST_F(InspectorGetUniformBufferResourceBindingsTest, ContainingPadding) {
-  auto* foo_struct_type = MakeUniformBufferType("foo_type", {ty.vec3<f32>()});
-  AddUniformBuffer("foo_ub", ty.Of(foo_struct_type), 0, 0);
+    auto* foo_struct_type = MakeUniformBufferType("foo_type", {ty.vec3<f32>()});
+    AddUniformBuffer("foo_ub", ty.Of(foo_struct_type), 0, 0);
 
-  MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub",
-                                          {{0, ty.vec3<f32>()}});
+    MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub", {{0, ty.vec3<f32>()}});
 
-  MakeCallerBodyFunction("ep_func", {"ub_func"},
-                         ast::AttributeList{
-                             Stage(ast::PipelineStage::kFragment),
-                         });
+    MakeCallerBodyFunction("ep_func", {"ub_func"},
+                           ast::AttributeList{
+                               Stage(ast::PipelineStage::kFragment),
+                           });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetUniformBufferResourceBindings("ep_func");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
-  ASSERT_EQ(1u, result.size());
+    auto result = inspector.GetUniformBufferResourceBindings("ep_func");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    ASSERT_EQ(1u, result.size());
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kUniformBuffer,
-            result[0].resource_type);
-  EXPECT_EQ(0u, result[0].bind_group);
-  EXPECT_EQ(0u, result[0].binding);
-  EXPECT_EQ(16u, result[0].size);
-  EXPECT_EQ(12u, result[0].size_no_padding);
+    EXPECT_EQ(ResourceBinding::ResourceType::kUniformBuffer, result[0].resource_type);
+    EXPECT_EQ(0u, result[0].bind_group);
+    EXPECT_EQ(0u, result[0].binding);
+    EXPECT_EQ(16u, result[0].size);
+    EXPECT_EQ(12u, result[0].size_no_padding);
 }
 
 TEST_F(InspectorGetUniformBufferResourceBindingsTest, NonStructVec3) {
-  AddUniformBuffer("foo_ub", ty.vec3<f32>(), 0, 0);
-  MakePlainGlobalReferenceBodyFunction("ub_func", "foo_ub", ty.vec3<f32>(), {});
+    AddUniformBuffer("foo_ub", ty.vec3<f32>(), 0, 0);
+    MakePlainGlobalReferenceBodyFunction("ub_func", "foo_ub", ty.vec3<f32>(), {});
 
-  MakeCallerBodyFunction("ep_func", {"ub_func"},
-                         ast::AttributeList{
-                             Stage(ast::PipelineStage::kFragment),
-                         });
+    MakeCallerBodyFunction("ep_func", {"ub_func"},
+                           ast::AttributeList{
+                               Stage(ast::PipelineStage::kFragment),
+                           });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetUniformBufferResourceBindings("ep_func");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
-  ASSERT_EQ(1u, result.size());
+    auto result = inspector.GetUniformBufferResourceBindings("ep_func");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    ASSERT_EQ(1u, result.size());
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kUniformBuffer,
-            result[0].resource_type);
-  EXPECT_EQ(0u, result[0].bind_group);
-  EXPECT_EQ(0u, result[0].binding);
-  EXPECT_EQ(12u, result[0].size);
-  EXPECT_EQ(12u, result[0].size_no_padding);
+    EXPECT_EQ(ResourceBinding::ResourceType::kUniformBuffer, result[0].resource_type);
+    EXPECT_EQ(0u, result[0].bind_group);
+    EXPECT_EQ(0u, result[0].binding);
+    EXPECT_EQ(12u, result[0].size);
+    EXPECT_EQ(12u, result[0].size_no_padding);
 }
 
 TEST_F(InspectorGetUniformBufferResourceBindingsTest, MultipleUniformBuffers) {
-  auto* ub_struct_type =
-      MakeUniformBufferType("ub_type", {ty.i32(), ty.u32(), ty.f32()});
-  AddUniformBuffer("ub_foo", ty.Of(ub_struct_type), 0, 0);
-  AddUniformBuffer("ub_bar", ty.Of(ub_struct_type), 0, 1);
-  AddUniformBuffer("ub_baz", ty.Of(ub_struct_type), 2, 0);
+    auto* ub_struct_type = MakeUniformBufferType("ub_type", {ty.i32(), ty.u32(), ty.f32()});
+    AddUniformBuffer("ub_foo", ty.Of(ub_struct_type), 0, 0);
+    AddUniformBuffer("ub_bar", ty.Of(ub_struct_type), 0, 1);
+    AddUniformBuffer("ub_baz", ty.Of(ub_struct_type), 2, 0);
 
-  auto AddReferenceFunc = [this](const std::string& func_name,
-                                 const std::string& var_name) {
-    MakeStructVariableReferenceBodyFunction(
-        func_name, var_name, {{0, ty.i32()}, {1, ty.u32()}, {2, ty.f32()}});
-  };
-  AddReferenceFunc("ub_foo_func", "ub_foo");
-  AddReferenceFunc("ub_bar_func", "ub_bar");
-  AddReferenceFunc("ub_baz_func", "ub_baz");
+    auto AddReferenceFunc = [this](const std::string& func_name, const std::string& var_name) {
+        MakeStructVariableReferenceBodyFunction(func_name, var_name,
+                                                {{0, ty.i32()}, {1, ty.u32()}, {2, ty.f32()}});
+    };
+    AddReferenceFunc("ub_foo_func", "ub_foo");
+    AddReferenceFunc("ub_bar_func", "ub_bar");
+    AddReferenceFunc("ub_baz_func", "ub_baz");
 
-  auto FuncCall = [&](const std::string& callee) {
-    return create<ast::CallStatement>(Call(callee));
-  };
+    auto FuncCall = [&](const std::string& callee) {
+        return create<ast::CallStatement>(Call(callee));
+    };
 
-  Func("ep_func", ast::VariableList(), ty.void_(),
-       ast::StatementList{FuncCall("ub_foo_func"), FuncCall("ub_bar_func"),
-                          FuncCall("ub_baz_func"), Return()},
-       ast::AttributeList{
-           Stage(ast::PipelineStage::kFragment),
-       });
+    Func("ep_func", ast::VariableList(), ty.void_(),
+         ast::StatementList{FuncCall("ub_foo_func"), FuncCall("ub_bar_func"),
+                            FuncCall("ub_baz_func"), Return()},
+         ast::AttributeList{
+             Stage(ast::PipelineStage::kFragment),
+         });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetUniformBufferResourceBindings("ep_func");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
-  ASSERT_EQ(3u, result.size());
+    auto result = inspector.GetUniformBufferResourceBindings("ep_func");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    ASSERT_EQ(3u, result.size());
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kUniformBuffer,
-            result[0].resource_type);
-  EXPECT_EQ(0u, result[0].bind_group);
-  EXPECT_EQ(0u, result[0].binding);
-  EXPECT_EQ(12u, result[0].size);
-  EXPECT_EQ(12u, result[0].size_no_padding);
+    EXPECT_EQ(ResourceBinding::ResourceType::kUniformBuffer, result[0].resource_type);
+    EXPECT_EQ(0u, result[0].bind_group);
+    EXPECT_EQ(0u, result[0].binding);
+    EXPECT_EQ(12u, result[0].size);
+    EXPECT_EQ(12u, result[0].size_no_padding);
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kUniformBuffer,
-            result[1].resource_type);
-  EXPECT_EQ(0u, result[1].bind_group);
-  EXPECT_EQ(1u, result[1].binding);
-  EXPECT_EQ(12u, result[1].size);
-  EXPECT_EQ(12u, result[1].size_no_padding);
+    EXPECT_EQ(ResourceBinding::ResourceType::kUniformBuffer, result[1].resource_type);
+    EXPECT_EQ(0u, result[1].bind_group);
+    EXPECT_EQ(1u, result[1].binding);
+    EXPECT_EQ(12u, result[1].size);
+    EXPECT_EQ(12u, result[1].size_no_padding);
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kUniformBuffer,
-            result[2].resource_type);
-  EXPECT_EQ(2u, result[2].bind_group);
-  EXPECT_EQ(0u, result[2].binding);
-  EXPECT_EQ(12u, result[2].size);
-  EXPECT_EQ(12u, result[2].size_no_padding);
+    EXPECT_EQ(ResourceBinding::ResourceType::kUniformBuffer, result[2].resource_type);
+    EXPECT_EQ(2u, result[2].bind_group);
+    EXPECT_EQ(0u, result[2].binding);
+    EXPECT_EQ(12u, result[2].size);
+    EXPECT_EQ(12u, result[2].size_no_padding);
 }
 
 TEST_F(InspectorGetUniformBufferResourceBindingsTest, ContainingArray) {
-  // Manually create uniform buffer to make sure it had a valid layout (array
-  // with elem stride of 16, and that is 16-byte aligned within the struct)
-  auto* foo_struct_type = Structure(
-      "foo_type",
-      {Member("0i32", ty.i32()),
-       Member("b", ty.array(ty.u32(), 4, /*stride*/ 16), {MemberAlign(16)})});
+    // Manually create uniform buffer to make sure it had a valid layout (array
+    // with elem stride of 16, and that is 16-byte aligned within the struct)
+    auto* foo_struct_type = Structure(
+        "foo_type", {Member("0i32", ty.i32()),
+                     Member("b", ty.array(ty.u32(), 4_u, /*stride*/ 16), {MemberAlign(16)})});
 
-  AddUniformBuffer("foo_ub", ty.Of(foo_struct_type), 0, 0);
+    AddUniformBuffer("foo_ub", ty.Of(foo_struct_type), 0, 0);
 
-  MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub", {{0, ty.i32()}});
+    MakeStructVariableReferenceBodyFunction("ub_func", "foo_ub", {{0, ty.i32()}});
 
-  MakeCallerBodyFunction("ep_func", {"ub_func"},
-                         ast::AttributeList{
-                             Stage(ast::PipelineStage::kFragment),
-                         });
+    MakeCallerBodyFunction("ep_func", {"ub_func"},
+                           ast::AttributeList{
+                               Stage(ast::PipelineStage::kFragment),
+                           });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetUniformBufferResourceBindings("ep_func");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
-  ASSERT_EQ(1u, result.size());
+    auto result = inspector.GetUniformBufferResourceBindings("ep_func");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    ASSERT_EQ(1u, result.size());
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kUniformBuffer,
-            result[0].resource_type);
-  EXPECT_EQ(0u, result[0].bind_group);
-  EXPECT_EQ(0u, result[0].binding);
-  EXPECT_EQ(80u, result[0].size);
-  EXPECT_EQ(80u, result[0].size_no_padding);
+    EXPECT_EQ(ResourceBinding::ResourceType::kUniformBuffer, result[0].resource_type);
+    EXPECT_EQ(0u, result[0].bind_group);
+    EXPECT_EQ(0u, result[0].binding);
+    EXPECT_EQ(80u, result[0].size);
+    EXPECT_EQ(80u, result[0].size_no_padding);
 }
 
 TEST_F(InspectorGetStorageBufferResourceBindingsTest, Simple_NonStruct) {
-  AddStorageBuffer("foo_sb", ty.i32(), ast::Access::kReadWrite, 0, 0);
-  MakePlainGlobalReferenceBodyFunction("sb_func", "foo_sb", ty.i32(), {});
+    AddStorageBuffer("foo_sb", ty.i32(), ast::Access::kReadWrite, 0, 0);
+    MakePlainGlobalReferenceBodyFunction("sb_func", "foo_sb", ty.i32(), {});
 
-  MakeCallerBodyFunction("ep_func", {"sb_func"},
-                         ast::AttributeList{
-                             Stage(ast::PipelineStage::kFragment),
-                         });
+    MakeCallerBodyFunction("ep_func", {"sb_func"},
+                           ast::AttributeList{
+                               Stage(ast::PipelineStage::kFragment),
+                           });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetStorageBufferResourceBindings("ep_func");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
-  ASSERT_EQ(1u, result.size());
+    auto result = inspector.GetStorageBufferResourceBindings("ep_func");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    ASSERT_EQ(1u, result.size());
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer,
-            result[0].resource_type);
-  EXPECT_EQ(0u, result[0].bind_group);
-  EXPECT_EQ(0u, result[0].binding);
-  EXPECT_EQ(4u, result[0].size);
-  EXPECT_EQ(4u, result[0].size_no_padding);
+    EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer, result[0].resource_type);
+    EXPECT_EQ(0u, result[0].bind_group);
+    EXPECT_EQ(0u, result[0].binding);
+    EXPECT_EQ(4u, result[0].size);
+    EXPECT_EQ(4u, result[0].size_no_padding);
 }
 
 TEST_F(InspectorGetStorageBufferResourceBindingsTest, Simple_Struct) {
-  auto foo_struct_type = MakeStorageBufferTypes("foo_type", {ty.i32()});
-  AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kReadWrite, 0, 0);
+    auto foo_struct_type = MakeStorageBufferTypes("foo_type", {ty.i32()});
+    AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kReadWrite, 0, 0);
 
-  MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
+    MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
 
-  MakeCallerBodyFunction("ep_func", {"sb_func"},
-                         ast::AttributeList{
-                             Stage(ast::PipelineStage::kFragment),
-                         });
+    MakeCallerBodyFunction("ep_func", {"sb_func"},
+                           ast::AttributeList{
+                               Stage(ast::PipelineStage::kFragment),
+                           });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetStorageBufferResourceBindings("ep_func");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
-  ASSERT_EQ(1u, result.size());
+    auto result = inspector.GetStorageBufferResourceBindings("ep_func");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    ASSERT_EQ(1u, result.size());
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer,
-            result[0].resource_type);
-  EXPECT_EQ(0u, result[0].bind_group);
-  EXPECT_EQ(0u, result[0].binding);
-  EXPECT_EQ(4u, result[0].size);
-  EXPECT_EQ(4u, result[0].size_no_padding);
+    EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer, result[0].resource_type);
+    EXPECT_EQ(0u, result[0].bind_group);
+    EXPECT_EQ(0u, result[0].binding);
+    EXPECT_EQ(4u, result[0].size);
+    EXPECT_EQ(4u, result[0].size_no_padding);
 }
 
 TEST_F(InspectorGetStorageBufferResourceBindingsTest, MultipleMembers) {
-  auto foo_struct_type = MakeStorageBufferTypes("foo_type", {
+    auto foo_struct_type = MakeStorageBufferTypes("foo_type", {
+                                                                  ty.i32(),
+                                                                  ty.u32(),
+                                                                  ty.f32(),
+                                                              });
+    AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kReadWrite, 0, 0);
+
+    MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
+                                            {{0, ty.i32()}, {1, ty.u32()}, {2, ty.f32()}});
+
+    MakeCallerBodyFunction("ep_func", {"sb_func"},
+                           ast::AttributeList{
+                               Stage(ast::PipelineStage::kFragment),
+                           });
+
+    Inspector& inspector = Build();
+
+    auto result = inspector.GetStorageBufferResourceBindings("ep_func");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    ASSERT_EQ(1u, result.size());
+
+    EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer, result[0].resource_type);
+    EXPECT_EQ(0u, result[0].bind_group);
+    EXPECT_EQ(0u, result[0].binding);
+    EXPECT_EQ(12u, result[0].size);
+    EXPECT_EQ(12u, result[0].size_no_padding);
+}
+
+TEST_F(InspectorGetStorageBufferResourceBindingsTest, MultipleStorageBuffers) {
+    auto sb_struct_type = MakeStorageBufferTypes("sb_type", {
                                                                 ty.i32(),
                                                                 ty.u32(),
                                                                 ty.f32(),
                                                             });
-  AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kReadWrite, 0, 0);
+    AddStorageBuffer("sb_foo", sb_struct_type(), ast::Access::kReadWrite, 0, 0);
+    AddStorageBuffer("sb_bar", sb_struct_type(), ast::Access::kReadWrite, 0, 1);
+    AddStorageBuffer("sb_baz", sb_struct_type(), ast::Access::kReadWrite, 2, 0);
 
-  MakeStructVariableReferenceBodyFunction(
-      "sb_func", "foo_sb", {{0, ty.i32()}, {1, ty.u32()}, {2, ty.f32()}});
+    auto AddReferenceFunc = [this](const std::string& func_name, const std::string& var_name) {
+        MakeStructVariableReferenceBodyFunction(func_name, var_name,
+                                                {{0, ty.i32()}, {1, ty.u32()}, {2, ty.f32()}});
+    };
+    AddReferenceFunc("sb_foo_func", "sb_foo");
+    AddReferenceFunc("sb_bar_func", "sb_bar");
+    AddReferenceFunc("sb_baz_func", "sb_baz");
 
-  MakeCallerBodyFunction("ep_func", {"sb_func"},
-                         ast::AttributeList{
-                             Stage(ast::PipelineStage::kFragment),
-                         });
+    auto FuncCall = [&](const std::string& callee) {
+        return create<ast::CallStatement>(Call(callee));
+    };
 
-  Inspector& inspector = Build();
+    Func("ep_func", ast::VariableList(), ty.void_(),
+         ast::StatementList{
+             FuncCall("sb_foo_func"),
+             FuncCall("sb_bar_func"),
+             FuncCall("sb_baz_func"),
+             Return(),
+         },
+         ast::AttributeList{
+             Stage(ast::PipelineStage::kFragment),
+         });
 
-  auto result = inspector.GetStorageBufferResourceBindings("ep_func");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
-  ASSERT_EQ(1u, result.size());
+    Inspector& inspector = Build();
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer,
-            result[0].resource_type);
-  EXPECT_EQ(0u, result[0].bind_group);
-  EXPECT_EQ(0u, result[0].binding);
-  EXPECT_EQ(12u, result[0].size);
-  EXPECT_EQ(12u, result[0].size_no_padding);
-}
+    auto result = inspector.GetStorageBufferResourceBindings("ep_func");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    ASSERT_EQ(3u, result.size());
 
-TEST_F(InspectorGetStorageBufferResourceBindingsTest, MultipleStorageBuffers) {
-  auto sb_struct_type = MakeStorageBufferTypes("sb_type", {
-                                                              ty.i32(),
-                                                              ty.u32(),
-                                                              ty.f32(),
-                                                          });
-  AddStorageBuffer("sb_foo", sb_struct_type(), ast::Access::kReadWrite, 0, 0);
-  AddStorageBuffer("sb_bar", sb_struct_type(), ast::Access::kReadWrite, 0, 1);
-  AddStorageBuffer("sb_baz", sb_struct_type(), ast::Access::kReadWrite, 2, 0);
+    EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer, result[0].resource_type);
+    EXPECT_EQ(0u, result[0].bind_group);
+    EXPECT_EQ(0u, result[0].binding);
+    EXPECT_EQ(12u, result[0].size);
+    EXPECT_EQ(12u, result[0].size_no_padding);
 
-  auto AddReferenceFunc = [this](const std::string& func_name,
-                                 const std::string& var_name) {
-    MakeStructVariableReferenceBodyFunction(
-        func_name, var_name, {{0, ty.i32()}, {1, ty.u32()}, {2, ty.f32()}});
-  };
-  AddReferenceFunc("sb_foo_func", "sb_foo");
-  AddReferenceFunc("sb_bar_func", "sb_bar");
-  AddReferenceFunc("sb_baz_func", "sb_baz");
+    EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer, result[1].resource_type);
+    EXPECT_EQ(0u, result[1].bind_group);
+    EXPECT_EQ(1u, result[1].binding);
+    EXPECT_EQ(12u, result[1].size);
+    EXPECT_EQ(12u, result[1].size_no_padding);
 
-  auto FuncCall = [&](const std::string& callee) {
-    return create<ast::CallStatement>(Call(callee));
-  };
-
-  Func("ep_func", ast::VariableList(), ty.void_(),
-       ast::StatementList{
-           FuncCall("sb_foo_func"),
-           FuncCall("sb_bar_func"),
-           FuncCall("sb_baz_func"),
-           Return(),
-       },
-       ast::AttributeList{
-           Stage(ast::PipelineStage::kFragment),
-       });
-
-  Inspector& inspector = Build();
-
-  auto result = inspector.GetStorageBufferResourceBindings("ep_func");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
-  ASSERT_EQ(3u, result.size());
-
-  EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer,
-            result[0].resource_type);
-  EXPECT_EQ(0u, result[0].bind_group);
-  EXPECT_EQ(0u, result[0].binding);
-  EXPECT_EQ(12u, result[0].size);
-  EXPECT_EQ(12u, result[0].size_no_padding);
-
-  EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer,
-            result[1].resource_type);
-  EXPECT_EQ(0u, result[1].bind_group);
-  EXPECT_EQ(1u, result[1].binding);
-  EXPECT_EQ(12u, result[1].size);
-  EXPECT_EQ(12u, result[1].size_no_padding);
-
-  EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer,
-            result[2].resource_type);
-  EXPECT_EQ(2u, result[2].bind_group);
-  EXPECT_EQ(0u, result[2].binding);
-  EXPECT_EQ(12u, result[2].size);
-  EXPECT_EQ(12u, result[2].size_no_padding);
+    EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer, result[2].resource_type);
+    EXPECT_EQ(2u, result[2].bind_group);
+    EXPECT_EQ(0u, result[2].binding);
+    EXPECT_EQ(12u, result[2].size);
+    EXPECT_EQ(12u, result[2].size_no_padding);
 }
 
 TEST_F(InspectorGetStorageBufferResourceBindingsTest, ContainingArray) {
-  auto foo_struct_type =
-      MakeStorageBufferTypes("foo_type", {ty.i32(), ty.array<u32, 4>()});
-  AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kReadWrite, 0, 0);
+    auto foo_struct_type = MakeStorageBufferTypes("foo_type", {ty.i32(), ty.array<u32, 4>()});
+    AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kReadWrite, 0, 0);
 
-  MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
+    MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
 
-  MakeCallerBodyFunction("ep_func", {"sb_func"},
-                         ast::AttributeList{
-                             Stage(ast::PipelineStage::kFragment),
-                         });
+    MakeCallerBodyFunction("ep_func", {"sb_func"},
+                           ast::AttributeList{
+                               Stage(ast::PipelineStage::kFragment),
+                           });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetStorageBufferResourceBindings("ep_func");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
-  ASSERT_EQ(1u, result.size());
+    auto result = inspector.GetStorageBufferResourceBindings("ep_func");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    ASSERT_EQ(1u, result.size());
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer,
-            result[0].resource_type);
-  EXPECT_EQ(0u, result[0].bind_group);
-  EXPECT_EQ(0u, result[0].binding);
-  EXPECT_EQ(20u, result[0].size);
-  EXPECT_EQ(20u, result[0].size_no_padding);
+    EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer, result[0].resource_type);
+    EXPECT_EQ(0u, result[0].bind_group);
+    EXPECT_EQ(0u, result[0].binding);
+    EXPECT_EQ(20u, result[0].size);
+    EXPECT_EQ(20u, result[0].size_no_padding);
 }
 
 TEST_F(InspectorGetStorageBufferResourceBindingsTest, ContainingRuntimeArray) {
-  auto foo_struct_type = MakeStorageBufferTypes("foo_type", {
-                                                                ty.i32(),
-                                                                ty.array<u32>(),
-                                                            });
-  AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kReadWrite, 0, 0);
+    auto foo_struct_type = MakeStorageBufferTypes("foo_type", {
+                                                                  ty.i32(),
+                                                                  ty.array<u32>(),
+                                                              });
+    AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kReadWrite, 0, 0);
 
-  MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
+    MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
 
-  MakeCallerBodyFunction("ep_func", {"sb_func"},
-                         ast::AttributeList{
-                             Stage(ast::PipelineStage::kFragment),
-                         });
+    MakeCallerBodyFunction("ep_func", {"sb_func"},
+                           ast::AttributeList{
+                               Stage(ast::PipelineStage::kFragment),
+                           });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetStorageBufferResourceBindings("ep_func");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
-  ASSERT_EQ(1u, result.size());
+    auto result = inspector.GetStorageBufferResourceBindings("ep_func");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    ASSERT_EQ(1u, result.size());
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer,
-            result[0].resource_type);
-  EXPECT_EQ(0u, result[0].bind_group);
-  EXPECT_EQ(0u, result[0].binding);
-  EXPECT_EQ(8u, result[0].size);
-  EXPECT_EQ(8u, result[0].size_no_padding);
+    EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer, result[0].resource_type);
+    EXPECT_EQ(0u, result[0].bind_group);
+    EXPECT_EQ(0u, result[0].binding);
+    EXPECT_EQ(8u, result[0].size);
+    EXPECT_EQ(8u, result[0].size_no_padding);
 }
 
 TEST_F(InspectorGetStorageBufferResourceBindingsTest, ContainingPadding) {
-  auto foo_struct_type = MakeStorageBufferTypes("foo_type", {ty.vec3<f32>()});
-  AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kReadWrite, 0, 0);
+    auto foo_struct_type = MakeStorageBufferTypes("foo_type", {ty.vec3<f32>()});
+    AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kReadWrite, 0, 0);
 
-  MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb",
-                                          {{0, ty.vec3<f32>()}});
+    MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.vec3<f32>()}});
 
-  MakeCallerBodyFunction("ep_func", {"sb_func"},
-                         ast::AttributeList{
-                             Stage(ast::PipelineStage::kFragment),
-                         });
+    MakeCallerBodyFunction("ep_func", {"sb_func"},
+                           ast::AttributeList{
+                               Stage(ast::PipelineStage::kFragment),
+                           });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetStorageBufferResourceBindings("ep_func");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
-  ASSERT_EQ(1u, result.size());
+    auto result = inspector.GetStorageBufferResourceBindings("ep_func");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    ASSERT_EQ(1u, result.size());
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer,
-            result[0].resource_type);
-  EXPECT_EQ(0u, result[0].bind_group);
-  EXPECT_EQ(0u, result[0].binding);
-  EXPECT_EQ(16u, result[0].size);
-  EXPECT_EQ(12u, result[0].size_no_padding);
+    EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer, result[0].resource_type);
+    EXPECT_EQ(0u, result[0].bind_group);
+    EXPECT_EQ(0u, result[0].binding);
+    EXPECT_EQ(16u, result[0].size);
+    EXPECT_EQ(12u, result[0].size_no_padding);
 }
 
 TEST_F(InspectorGetStorageBufferResourceBindingsTest, NonStructVec3) {
-  AddStorageBuffer("foo_ub", ty.vec3<f32>(), ast::Access::kReadWrite, 0, 0);
-  MakePlainGlobalReferenceBodyFunction("ub_func", "foo_ub", ty.vec3<f32>(), {});
+    AddStorageBuffer("foo_ub", ty.vec3<f32>(), ast::Access::kReadWrite, 0, 0);
+    MakePlainGlobalReferenceBodyFunction("ub_func", "foo_ub", ty.vec3<f32>(), {});
 
-  MakeCallerBodyFunction("ep_func", {"ub_func"},
-                         ast::AttributeList{
-                             Stage(ast::PipelineStage::kFragment),
-                         });
+    MakeCallerBodyFunction("ep_func", {"ub_func"},
+                           ast::AttributeList{
+                               Stage(ast::PipelineStage::kFragment),
+                           });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetStorageBufferResourceBindings("ep_func");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
-  ASSERT_EQ(1u, result.size());
+    auto result = inspector.GetStorageBufferResourceBindings("ep_func");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    ASSERT_EQ(1u, result.size());
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer,
-            result[0].resource_type);
-  EXPECT_EQ(0u, result[0].bind_group);
-  EXPECT_EQ(0u, result[0].binding);
-  EXPECT_EQ(12u, result[0].size);
-  EXPECT_EQ(12u, result[0].size_no_padding);
+    EXPECT_EQ(ResourceBinding::ResourceType::kStorageBuffer, result[0].resource_type);
+    EXPECT_EQ(0u, result[0].bind_group);
+    EXPECT_EQ(0u, result[0].binding);
+    EXPECT_EQ(12u, result[0].size);
+    EXPECT_EQ(12u, result[0].size_no_padding);
 }
 
 TEST_F(InspectorGetStorageBufferResourceBindingsTest, SkipReadOnly) {
-  auto foo_struct_type = MakeStorageBufferTypes("foo_type", {ty.i32()});
-  AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kRead, 0, 0);
+    auto foo_struct_type = MakeStorageBufferTypes("foo_type", {ty.i32()});
+    AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kRead, 0, 0);
 
-  MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
+    MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
 
-  MakeCallerBodyFunction("ep_func", {"sb_func"},
-                         ast::AttributeList{
-                             Stage(ast::PipelineStage::kFragment),
-                         });
+    MakeCallerBodyFunction("ep_func", {"sb_func"},
+                           ast::AttributeList{
+                               Stage(ast::PipelineStage::kFragment),
+                           });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetStorageBufferResourceBindings("ep_func");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
-  ASSERT_EQ(0u, result.size());
+    auto result = inspector.GetStorageBufferResourceBindings("ep_func");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    ASSERT_EQ(0u, result.size());
 }
 
 TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest, Simple) {
-  auto foo_struct_type = MakeStorageBufferTypes("foo_type", {ty.i32()});
-  AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kRead, 0, 0);
+    auto foo_struct_type = MakeStorageBufferTypes("foo_type", {ty.i32()});
+    AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kRead, 0, 0);
 
-  MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
+    MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
 
-  MakeCallerBodyFunction("ep_func", {"sb_func"},
-                         ast::AttributeList{
-                             Stage(ast::PipelineStage::kFragment),
-                         });
+    MakeCallerBodyFunction("ep_func", {"sb_func"},
+                           ast::AttributeList{
+                               Stage(ast::PipelineStage::kFragment),
+                           });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetReadOnlyStorageBufferResourceBindings("ep_func");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
-  ASSERT_EQ(1u, result.size());
+    auto result = inspector.GetReadOnlyStorageBufferResourceBindings("ep_func");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    ASSERT_EQ(1u, result.size());
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kReadOnlyStorageBuffer,
-            result[0].resource_type);
-  EXPECT_EQ(0u, result[0].bind_group);
-  EXPECT_EQ(0u, result[0].binding);
-  EXPECT_EQ(4u, result[0].size);
-  EXPECT_EQ(4u, result[0].size_no_padding);
+    EXPECT_EQ(ResourceBinding::ResourceType::kReadOnlyStorageBuffer, result[0].resource_type);
+    EXPECT_EQ(0u, result[0].bind_group);
+    EXPECT_EQ(0u, result[0].binding);
+    EXPECT_EQ(4u, result[0].size);
+    EXPECT_EQ(4u, result[0].size_no_padding);
 }
 
-TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest,
-       MultipleStorageBuffers) {
-  auto sb_struct_type = MakeStorageBufferTypes("sb_type", {
-                                                              ty.i32(),
-                                                              ty.u32(),
-                                                              ty.f32(),
-                                                          });
-  AddStorageBuffer("sb_foo", sb_struct_type(), ast::Access::kRead, 0, 0);
-  AddStorageBuffer("sb_bar", sb_struct_type(), ast::Access::kRead, 0, 1);
-  AddStorageBuffer("sb_baz", sb_struct_type(), ast::Access::kRead, 2, 0);
+TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest, MultipleStorageBuffers) {
+    auto sb_struct_type = MakeStorageBufferTypes("sb_type", {
+                                                                ty.i32(),
+                                                                ty.u32(),
+                                                                ty.f32(),
+                                                            });
+    AddStorageBuffer("sb_foo", sb_struct_type(), ast::Access::kRead, 0, 0);
+    AddStorageBuffer("sb_bar", sb_struct_type(), ast::Access::kRead, 0, 1);
+    AddStorageBuffer("sb_baz", sb_struct_type(), ast::Access::kRead, 2, 0);
 
-  auto AddReferenceFunc = [this](const std::string& func_name,
-                                 const std::string& var_name) {
-    MakeStructVariableReferenceBodyFunction(
-        func_name, var_name, {{0, ty.i32()}, {1, ty.u32()}, {2, ty.f32()}});
-  };
-  AddReferenceFunc("sb_foo_func", "sb_foo");
-  AddReferenceFunc("sb_bar_func", "sb_bar");
-  AddReferenceFunc("sb_baz_func", "sb_baz");
+    auto AddReferenceFunc = [this](const std::string& func_name, const std::string& var_name) {
+        MakeStructVariableReferenceBodyFunction(func_name, var_name,
+                                                {{0, ty.i32()}, {1, ty.u32()}, {2, ty.f32()}});
+    };
+    AddReferenceFunc("sb_foo_func", "sb_foo");
+    AddReferenceFunc("sb_bar_func", "sb_bar");
+    AddReferenceFunc("sb_baz_func", "sb_baz");
 
-  auto FuncCall = [&](const std::string& callee) {
-    return create<ast::CallStatement>(Call(callee));
-  };
+    auto FuncCall = [&](const std::string& callee) {
+        return create<ast::CallStatement>(Call(callee));
+    };
 
-  Func("ep_func", ast::VariableList(), ty.void_(),
-       ast::StatementList{
-           FuncCall("sb_foo_func"),
-           FuncCall("sb_bar_func"),
-           FuncCall("sb_baz_func"),
-           Return(),
-       },
-       ast::AttributeList{
-           Stage(ast::PipelineStage::kFragment),
-       });
+    Func("ep_func", ast::VariableList(), ty.void_(),
+         ast::StatementList{
+             FuncCall("sb_foo_func"),
+             FuncCall("sb_bar_func"),
+             FuncCall("sb_baz_func"),
+             Return(),
+         },
+         ast::AttributeList{
+             Stage(ast::PipelineStage::kFragment),
+         });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetReadOnlyStorageBufferResourceBindings("ep_func");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
-  ASSERT_EQ(3u, result.size());
+    auto result = inspector.GetReadOnlyStorageBufferResourceBindings("ep_func");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    ASSERT_EQ(3u, result.size());
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kReadOnlyStorageBuffer,
-            result[0].resource_type);
-  EXPECT_EQ(0u, result[0].bind_group);
-  EXPECT_EQ(0u, result[0].binding);
-  EXPECT_EQ(12u, result[0].size);
-  EXPECT_EQ(12u, result[0].size_no_padding);
+    EXPECT_EQ(ResourceBinding::ResourceType::kReadOnlyStorageBuffer, result[0].resource_type);
+    EXPECT_EQ(0u, result[0].bind_group);
+    EXPECT_EQ(0u, result[0].binding);
+    EXPECT_EQ(12u, result[0].size);
+    EXPECT_EQ(12u, result[0].size_no_padding);
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kReadOnlyStorageBuffer,
-            result[1].resource_type);
-  EXPECT_EQ(0u, result[1].bind_group);
-  EXPECT_EQ(1u, result[1].binding);
-  EXPECT_EQ(12u, result[1].size);
-  EXPECT_EQ(12u, result[1].size_no_padding);
+    EXPECT_EQ(ResourceBinding::ResourceType::kReadOnlyStorageBuffer, result[1].resource_type);
+    EXPECT_EQ(0u, result[1].bind_group);
+    EXPECT_EQ(1u, result[1].binding);
+    EXPECT_EQ(12u, result[1].size);
+    EXPECT_EQ(12u, result[1].size_no_padding);
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kReadOnlyStorageBuffer,
-            result[2].resource_type);
-  EXPECT_EQ(2u, result[2].bind_group);
-  EXPECT_EQ(0u, result[2].binding);
-  EXPECT_EQ(12u, result[2].size);
-  EXPECT_EQ(12u, result[2].size_no_padding);
+    EXPECT_EQ(ResourceBinding::ResourceType::kReadOnlyStorageBuffer, result[2].resource_type);
+    EXPECT_EQ(2u, result[2].bind_group);
+    EXPECT_EQ(0u, result[2].binding);
+    EXPECT_EQ(12u, result[2].size);
+    EXPECT_EQ(12u, result[2].size_no_padding);
 }
 
 TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest, ContainingArray) {
-  auto foo_struct_type =
-      MakeStorageBufferTypes("foo_type", {
-                                             ty.i32(),
-                                             ty.array<u32, 4>(),
-                                         });
-  AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kRead, 0, 0);
+    auto foo_struct_type = MakeStorageBufferTypes("foo_type", {
+                                                                  ty.i32(),
+                                                                  ty.array<u32, 4>(),
+                                                              });
+    AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kRead, 0, 0);
 
-  MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
+    MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
 
-  MakeCallerBodyFunction("ep_func", {"sb_func"},
-                         ast::AttributeList{
-                             Stage(ast::PipelineStage::kFragment),
-                         });
+    MakeCallerBodyFunction("ep_func", {"sb_func"},
+                           ast::AttributeList{
+                               Stage(ast::PipelineStage::kFragment),
+                           });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetReadOnlyStorageBufferResourceBindings("ep_func");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
-  ASSERT_EQ(1u, result.size());
+    auto result = inspector.GetReadOnlyStorageBufferResourceBindings("ep_func");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    ASSERT_EQ(1u, result.size());
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kReadOnlyStorageBuffer,
-            result[0].resource_type);
-  EXPECT_EQ(0u, result[0].bind_group);
-  EXPECT_EQ(0u, result[0].binding);
-  EXPECT_EQ(20u, result[0].size);
-  EXPECT_EQ(20u, result[0].size_no_padding);
+    EXPECT_EQ(ResourceBinding::ResourceType::kReadOnlyStorageBuffer, result[0].resource_type);
+    EXPECT_EQ(0u, result[0].bind_group);
+    EXPECT_EQ(0u, result[0].binding);
+    EXPECT_EQ(20u, result[0].size);
+    EXPECT_EQ(20u, result[0].size_no_padding);
 }
 
-TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest,
-       ContainingRuntimeArray) {
-  auto foo_struct_type = MakeStorageBufferTypes("foo_type", {
-                                                                ty.i32(),
-                                                                ty.array<u32>(),
-                                                            });
-  AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kRead, 0, 0);
+TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest, ContainingRuntimeArray) {
+    auto foo_struct_type = MakeStorageBufferTypes("foo_type", {
+                                                                  ty.i32(),
+                                                                  ty.array<u32>(),
+                                                              });
+    AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kRead, 0, 0);
 
-  MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
+    MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
 
-  MakeCallerBodyFunction("ep_func", {"sb_func"},
-                         ast::AttributeList{
-                             Stage(ast::PipelineStage::kFragment),
-                         });
+    MakeCallerBodyFunction("ep_func", {"sb_func"},
+                           ast::AttributeList{
+                               Stage(ast::PipelineStage::kFragment),
+                           });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetReadOnlyStorageBufferResourceBindings("ep_func");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
-  ASSERT_EQ(1u, result.size());
+    auto result = inspector.GetReadOnlyStorageBufferResourceBindings("ep_func");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    ASSERT_EQ(1u, result.size());
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kReadOnlyStorageBuffer,
-            result[0].resource_type);
-  EXPECT_EQ(0u, result[0].bind_group);
-  EXPECT_EQ(0u, result[0].binding);
-  EXPECT_EQ(8u, result[0].size);
-  EXPECT_EQ(8u, result[0].size_no_padding);
+    EXPECT_EQ(ResourceBinding::ResourceType::kReadOnlyStorageBuffer, result[0].resource_type);
+    EXPECT_EQ(0u, result[0].bind_group);
+    EXPECT_EQ(0u, result[0].binding);
+    EXPECT_EQ(8u, result[0].size);
+    EXPECT_EQ(8u, result[0].size_no_padding);
 }
 
 TEST_F(InspectorGetReadOnlyStorageBufferResourceBindingsTest, SkipNonReadOnly) {
-  auto foo_struct_type = MakeStorageBufferTypes("foo_type", {ty.i32()});
-  AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kReadWrite, 0, 0);
+    auto foo_struct_type = MakeStorageBufferTypes("foo_type", {ty.i32()});
+    AddStorageBuffer("foo_sb", foo_struct_type(), ast::Access::kReadWrite, 0, 0);
 
-  MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
+    MakeStructVariableReferenceBodyFunction("sb_func", "foo_sb", {{0, ty.i32()}});
 
-  MakeCallerBodyFunction("ep_func", {"sb_func"},
-                         ast::AttributeList{
-                             Stage(ast::PipelineStage::kFragment),
-                         });
+    MakeCallerBodyFunction("ep_func", {"sb_func"},
+                           ast::AttributeList{
+                               Stage(ast::PipelineStage::kFragment),
+                           });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetReadOnlyStorageBufferResourceBindings("ep_func");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
-  ASSERT_EQ(0u, result.size());
+    auto result = inspector.GetReadOnlyStorageBufferResourceBindings("ep_func");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    ASSERT_EQ(0u, result.size());
 }
 
 TEST_F(InspectorGetSamplerResourceBindingsTest, Simple) {
-  auto* sampled_texture_type =
-      ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
-  AddResource("foo_texture", sampled_texture_type, 0, 0);
-  AddSampler("foo_sampler", 0, 1);
-  AddGlobalVariable("foo_coords", ty.f32());
+    auto* sampled_texture_type = ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
+    AddResource("foo_texture", sampled_texture_type, 0, 0);
+    AddSampler("foo_sampler", 0, 1);
+    AddGlobalVariable("foo_coords", ty.f32());
 
-  MakeSamplerReferenceBodyFunction("ep", "foo_texture", "foo_sampler",
-                                   "foo_coords", ty.f32(),
-                                   ast::AttributeList{
-                                       Stage(ast::PipelineStage::kFragment),
-                                   });
+    MakeSamplerReferenceBodyFunction("ep", "foo_texture", "foo_sampler", "foo_coords", ty.f32(),
+                                     ast::AttributeList{
+                                         Stage(ast::PipelineStage::kFragment),
+                                     });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetSamplerResourceBindings("ep");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    auto result = inspector.GetSamplerResourceBindings("ep");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kSampler, result[0].resource_type);
-  ASSERT_EQ(1u, result.size());
-  EXPECT_EQ(0u, result[0].bind_group);
-  EXPECT_EQ(1u, result[0].binding);
+    EXPECT_EQ(ResourceBinding::ResourceType::kSampler, result[0].resource_type);
+    ASSERT_EQ(1u, result.size());
+    EXPECT_EQ(0u, result[0].bind_group);
+    EXPECT_EQ(1u, result[0].binding);
 }
 
 TEST_F(InspectorGetSamplerResourceBindingsTest, NoSampler) {
-  MakeEmptyBodyFunction("ep_func", ast::AttributeList{
-                                       Stage(ast::PipelineStage::kFragment),
-                                   });
+    MakeEmptyBodyFunction("ep_func", ast::AttributeList{
+                                         Stage(ast::PipelineStage::kFragment),
+                                     });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetSamplerResourceBindings("ep_func");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    auto result = inspector.GetSamplerResourceBindings("ep_func");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
-  ASSERT_EQ(0u, result.size());
+    ASSERT_EQ(0u, result.size());
 }
 
 TEST_F(InspectorGetSamplerResourceBindingsTest, InFunction) {
-  auto* sampled_texture_type =
-      ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
-  AddResource("foo_texture", sampled_texture_type, 0, 0);
-  AddSampler("foo_sampler", 0, 1);
-  AddGlobalVariable("foo_coords", ty.f32());
+    auto* sampled_texture_type = ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
+    AddResource("foo_texture", sampled_texture_type, 0, 0);
+    AddSampler("foo_sampler", 0, 1);
+    AddGlobalVariable("foo_coords", ty.f32());
 
-  MakeSamplerReferenceBodyFunction("foo_func", "foo_texture", "foo_sampler",
-                                   "foo_coords", ty.f32(), {});
+    MakeSamplerReferenceBodyFunction("foo_func", "foo_texture", "foo_sampler", "foo_coords",
+                                     ty.f32(), {});
 
-  MakeCallerBodyFunction("ep_func", {"foo_func"},
-                         ast::AttributeList{
-                             Stage(ast::PipelineStage::kFragment),
-                         });
+    MakeCallerBodyFunction("ep_func", {"foo_func"},
+                           ast::AttributeList{
+                               Stage(ast::PipelineStage::kFragment),
+                           });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetSamplerResourceBindings("ep_func");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    auto result = inspector.GetSamplerResourceBindings("ep_func");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kSampler, result[0].resource_type);
-  ASSERT_EQ(1u, result.size());
-  EXPECT_EQ(0u, result[0].bind_group);
-  EXPECT_EQ(1u, result[0].binding);
+    EXPECT_EQ(ResourceBinding::ResourceType::kSampler, result[0].resource_type);
+    ASSERT_EQ(1u, result.size());
+    EXPECT_EQ(0u, result[0].bind_group);
+    EXPECT_EQ(1u, result[0].binding);
 }
 
 TEST_F(InspectorGetSamplerResourceBindingsTest, UnknownEntryPoint) {
-  auto* sampled_texture_type =
-      ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
-  AddResource("foo_texture", sampled_texture_type, 0, 0);
-  AddSampler("foo_sampler", 0, 1);
-  AddGlobalVariable("foo_coords", ty.f32());
+    auto* sampled_texture_type = ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
+    AddResource("foo_texture", sampled_texture_type, 0, 0);
+    AddSampler("foo_sampler", 0, 1);
+    AddGlobalVariable("foo_coords", ty.f32());
 
-  MakeSamplerReferenceBodyFunction("ep", "foo_texture", "foo_sampler",
-                                   "foo_coords", ty.f32(),
-                                   ast::AttributeList{
-                                       Stage(ast::PipelineStage::kFragment),
-                                   });
+    MakeSamplerReferenceBodyFunction("ep", "foo_texture", "foo_sampler", "foo_coords", ty.f32(),
+                                     ast::AttributeList{
+                                         Stage(ast::PipelineStage::kFragment),
+                                     });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetSamplerResourceBindings("foo");
-  ASSERT_TRUE(inspector.has_error()) << inspector.error();
+    auto result = inspector.GetSamplerResourceBindings("foo");
+    ASSERT_TRUE(inspector.has_error()) << inspector.error();
 }
 
 TEST_F(InspectorGetSamplerResourceBindingsTest, SkipsComparisonSamplers) {
-  auto* depth_texture_type = ty.depth_texture(ast::TextureDimension::k2d);
-  AddResource("foo_texture", depth_texture_type, 0, 0);
-  AddComparisonSampler("foo_sampler", 0, 1);
-  AddGlobalVariable("foo_coords", ty.vec2<f32>());
-  AddGlobalVariable("foo_depth", ty.f32());
+    auto* depth_texture_type = ty.depth_texture(ast::TextureDimension::k2d);
+    AddResource("foo_texture", depth_texture_type, 0, 0);
+    AddComparisonSampler("foo_sampler", 0, 1);
+    AddGlobalVariable("foo_coords", ty.vec2<f32>());
+    AddGlobalVariable("foo_depth", ty.f32());
 
-  MakeComparisonSamplerReferenceBodyFunction(
-      "ep", "foo_texture", "foo_sampler", "foo_coords", "foo_depth", ty.f32(),
-      ast::AttributeList{
-          Stage(ast::PipelineStage::kFragment),
-      });
+    MakeComparisonSamplerReferenceBodyFunction("ep", "foo_texture", "foo_sampler", "foo_coords",
+                                               "foo_depth", ty.f32(),
+                                               ast::AttributeList{
+                                                   Stage(ast::PipelineStage::kFragment),
+                                               });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetSamplerResourceBindings("ep");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    auto result = inspector.GetSamplerResourceBindings("ep");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
-  ASSERT_EQ(0u, result.size());
+    ASSERT_EQ(0u, result.size());
 }
 
 TEST_F(InspectorGetComparisonSamplerResourceBindingsTest, Simple) {
-  auto* depth_texture_type = ty.depth_texture(ast::TextureDimension::k2d);
-  AddResource("foo_texture", depth_texture_type, 0, 0);
-  AddComparisonSampler("foo_sampler", 0, 1);
-  AddGlobalVariable("foo_coords", ty.vec2<f32>());
-  AddGlobalVariable("foo_depth", ty.f32());
+    auto* depth_texture_type = ty.depth_texture(ast::TextureDimension::k2d);
+    AddResource("foo_texture", depth_texture_type, 0, 0);
+    AddComparisonSampler("foo_sampler", 0, 1);
+    AddGlobalVariable("foo_coords", ty.vec2<f32>());
+    AddGlobalVariable("foo_depth", ty.f32());
 
-  MakeComparisonSamplerReferenceBodyFunction(
-      "ep", "foo_texture", "foo_sampler", "foo_coords", "foo_depth", ty.f32(),
-      ast::AttributeList{
-          Stage(ast::PipelineStage::kFragment),
-      });
+    MakeComparisonSamplerReferenceBodyFunction("ep", "foo_texture", "foo_sampler", "foo_coords",
+                                               "foo_depth", ty.f32(),
+                                               ast::AttributeList{
+                                                   Stage(ast::PipelineStage::kFragment),
+                                               });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetComparisonSamplerResourceBindings("ep");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    auto result = inspector.GetComparisonSamplerResourceBindings("ep");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kComparisonSampler,
-            result[0].resource_type);
-  ASSERT_EQ(1u, result.size());
-  EXPECT_EQ(0u, result[0].bind_group);
-  EXPECT_EQ(1u, result[0].binding);
+    EXPECT_EQ(ResourceBinding::ResourceType::kComparisonSampler, result[0].resource_type);
+    ASSERT_EQ(1u, result.size());
+    EXPECT_EQ(0u, result[0].bind_group);
+    EXPECT_EQ(1u, result[0].binding);
 }
 
 TEST_F(InspectorGetComparisonSamplerResourceBindingsTest, NoSampler) {
-  MakeEmptyBodyFunction("ep_func", ast::AttributeList{
-                                       Stage(ast::PipelineStage::kFragment),
-                                   });
+    MakeEmptyBodyFunction("ep_func", ast::AttributeList{
+                                         Stage(ast::PipelineStage::kFragment),
+                                     });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetComparisonSamplerResourceBindings("ep_func");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    auto result = inspector.GetComparisonSamplerResourceBindings("ep_func");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
-  ASSERT_EQ(0u, result.size());
+    ASSERT_EQ(0u, result.size());
 }
 
 TEST_F(InspectorGetComparisonSamplerResourceBindingsTest, InFunction) {
-  auto* depth_texture_type = ty.depth_texture(ast::TextureDimension::k2d);
-  AddResource("foo_texture", depth_texture_type, 0, 0);
-  AddComparisonSampler("foo_sampler", 0, 1);
-  AddGlobalVariable("foo_coords", ty.vec2<f32>());
-  AddGlobalVariable("foo_depth", ty.f32());
+    auto* depth_texture_type = ty.depth_texture(ast::TextureDimension::k2d);
+    AddResource("foo_texture", depth_texture_type, 0, 0);
+    AddComparisonSampler("foo_sampler", 0, 1);
+    AddGlobalVariable("foo_coords", ty.vec2<f32>());
+    AddGlobalVariable("foo_depth", ty.f32());
 
-  MakeComparisonSamplerReferenceBodyFunction("foo_func", "foo_texture",
-                                             "foo_sampler", "foo_coords",
-                                             "foo_depth", ty.f32(), {});
+    MakeComparisonSamplerReferenceBodyFunction("foo_func", "foo_texture", "foo_sampler",
+                                               "foo_coords", "foo_depth", ty.f32(), {});
 
-  MakeCallerBodyFunction("ep_func", {"foo_func"},
-                         ast::AttributeList{
-                             Stage(ast::PipelineStage::kFragment),
-                         });
+    MakeCallerBodyFunction("ep_func", {"foo_func"},
+                           ast::AttributeList{
+                               Stage(ast::PipelineStage::kFragment),
+                           });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetComparisonSamplerResourceBindings("ep_func");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    auto result = inspector.GetComparisonSamplerResourceBindings("ep_func");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kComparisonSampler,
-            result[0].resource_type);
-  ASSERT_EQ(1u, result.size());
-  EXPECT_EQ(0u, result[0].bind_group);
-  EXPECT_EQ(1u, result[0].binding);
+    EXPECT_EQ(ResourceBinding::ResourceType::kComparisonSampler, result[0].resource_type);
+    ASSERT_EQ(1u, result.size());
+    EXPECT_EQ(0u, result[0].bind_group);
+    EXPECT_EQ(1u, result[0].binding);
 }
 
 TEST_F(InspectorGetComparisonSamplerResourceBindingsTest, UnknownEntryPoint) {
-  auto* depth_texture_type = ty.depth_texture(ast::TextureDimension::k2d);
-  AddResource("foo_texture", depth_texture_type, 0, 0);
-  AddComparisonSampler("foo_sampler", 0, 1);
-  AddGlobalVariable("foo_coords", ty.vec2<f32>());
-  AddGlobalVariable("foo_depth", ty.f32());
+    auto* depth_texture_type = ty.depth_texture(ast::TextureDimension::k2d);
+    AddResource("foo_texture", depth_texture_type, 0, 0);
+    AddComparisonSampler("foo_sampler", 0, 1);
+    AddGlobalVariable("foo_coords", ty.vec2<f32>());
+    AddGlobalVariable("foo_depth", ty.f32());
 
-  MakeComparisonSamplerReferenceBodyFunction(
-      "ep", "foo_texture", "foo_sampler", "foo_coords", "foo_depth", ty.f32(),
-      ast::AttributeList{
-          Stage(ast::PipelineStage::kFragment),
-      });
+    MakeComparisonSamplerReferenceBodyFunction("ep", "foo_texture", "foo_sampler", "foo_coords",
+                                               "foo_depth", ty.f32(),
+                                               ast::AttributeList{
+                                                   Stage(ast::PipelineStage::kFragment),
+                                               });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetSamplerResourceBindings("foo");
-  ASSERT_TRUE(inspector.has_error()) << inspector.error();
+    auto result = inspector.GetSamplerResourceBindings("foo");
+    ASSERT_TRUE(inspector.has_error()) << inspector.error();
 }
 
 TEST_F(InspectorGetComparisonSamplerResourceBindingsTest, SkipsSamplers) {
-  auto* sampled_texture_type =
-      ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
-  AddResource("foo_texture", sampled_texture_type, 0, 0);
-  AddSampler("foo_sampler", 0, 1);
-  AddGlobalVariable("foo_coords", ty.f32());
+    auto* sampled_texture_type = ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
+    AddResource("foo_texture", sampled_texture_type, 0, 0);
+    AddSampler("foo_sampler", 0, 1);
+    AddGlobalVariable("foo_coords", ty.f32());
 
-  MakeSamplerReferenceBodyFunction("ep", "foo_texture", "foo_sampler",
-                                   "foo_coords", ty.f32(),
-                                   ast::AttributeList{
-                                       Stage(ast::PipelineStage::kFragment),
-                                   });
+    MakeSamplerReferenceBodyFunction("ep", "foo_texture", "foo_sampler", "foo_coords", ty.f32(),
+                                     ast::AttributeList{
+                                         Stage(ast::PipelineStage::kFragment),
+                                     });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetComparisonSamplerResourceBindings("ep");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    auto result = inspector.GetComparisonSamplerResourceBindings("ep");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
-  ASSERT_EQ(0u, result.size());
+    ASSERT_EQ(0u, result.size());
 }
 
 TEST_F(InspectorGetSampledTextureResourceBindingsTest, Empty) {
-  MakeEmptyBodyFunction("foo", ast::AttributeList{
-                                   Stage(ast::PipelineStage::kFragment),
-                               });
+    MakeEmptyBodyFunction("foo", ast::AttributeList{
+                                     Stage(ast::PipelineStage::kFragment),
+                                 });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetSampledTextureResourceBindings("foo");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    auto result = inspector.GetSampledTextureResourceBindings("foo");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
-  EXPECT_EQ(0u, result.size());
+    EXPECT_EQ(0u, result.size());
 }
 
 TEST_P(InspectorGetSampledTextureResourceBindingsTestWithParam, textureSample) {
-  auto* sampled_texture_type = ty.sampled_texture(
-      GetParam().type_dim, GetBaseType(GetParam().sampled_kind));
-  AddResource("foo_texture", sampled_texture_type, 0, 0);
-  AddSampler("foo_sampler", 0, 1);
-  auto* coord_type = GetCoordsType(GetParam().type_dim, ty.f32());
-  AddGlobalVariable("foo_coords", coord_type);
+    auto* sampled_texture_type =
+        ty.sampled_texture(GetParam().type_dim, GetBaseType(GetParam().sampled_kind));
+    AddResource("foo_texture", sampled_texture_type, 0, 0);
+    AddSampler("foo_sampler", 0, 1);
+    auto* coord_type = GetCoordsType(GetParam().type_dim, ty.f32());
+    AddGlobalVariable("foo_coords", coord_type);
 
-  MakeSamplerReferenceBodyFunction("ep", "foo_texture", "foo_sampler",
-                                   "foo_coords",
-                                   GetBaseType(GetParam().sampled_kind),
-                                   ast::AttributeList{
-                                       Stage(ast::PipelineStage::kFragment),
-                                   });
+    MakeSamplerReferenceBodyFunction("ep", "foo_texture", "foo_sampler", "foo_coords",
+                                     GetBaseType(GetParam().sampled_kind),
+                                     ast::AttributeList{
+                                         Stage(ast::PipelineStage::kFragment),
+                                     });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetSampledTextureResourceBindings("ep");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    auto result = inspector.GetSampledTextureResourceBindings("ep");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kSampledTexture,
-            result[0].resource_type);
-  ASSERT_EQ(1u, result.size());
-  EXPECT_EQ(0u, result[0].bind_group);
-  EXPECT_EQ(0u, result[0].binding);
-  EXPECT_EQ(GetParam().inspector_dim, result[0].dim);
-  EXPECT_EQ(GetParam().sampled_kind, result[0].sampled_kind);
+    EXPECT_EQ(ResourceBinding::ResourceType::kSampledTexture, result[0].resource_type);
+    ASSERT_EQ(1u, result.size());
+    EXPECT_EQ(0u, result[0].bind_group);
+    EXPECT_EQ(0u, result[0].binding);
+    EXPECT_EQ(GetParam().inspector_dim, result[0].dim);
+    EXPECT_EQ(GetParam().sampled_kind, result[0].sampled_kind);
 
-  // Prove that sampled and multi-sampled bindings are accounted
-  // for separately.
-  auto multisampled_result =
-      inspector.GetMultisampledTextureResourceBindings("ep");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
-  ASSERT_TRUE(multisampled_result.empty());
+    // Prove that sampled and multi-sampled bindings are accounted
+    // for separately.
+    auto multisampled_result = inspector.GetMultisampledTextureResourceBindings("ep");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    ASSERT_TRUE(multisampled_result.empty());
 }
 
 INSTANTIATE_TEST_SUITE_P(
     InspectorGetSampledTextureResourceBindingsTest,
     InspectorGetSampledTextureResourceBindingsTestWithParam,
-    testing::Values(
-        GetSampledTextureTestParams{
-            ast::TextureDimension::k1d,
-            inspector::ResourceBinding::TextureDimension::k1d,
-            inspector::ResourceBinding::SampledKind::kFloat},
-        GetSampledTextureTestParams{
-            ast::TextureDimension::k2d,
-            inspector::ResourceBinding::TextureDimension::k2d,
-            inspector::ResourceBinding::SampledKind::kFloat},
-        GetSampledTextureTestParams{
-            ast::TextureDimension::k3d,
-            inspector::ResourceBinding::TextureDimension::k3d,
-            inspector::ResourceBinding::SampledKind::kFloat},
-        GetSampledTextureTestParams{
-            ast::TextureDimension::kCube,
-            inspector::ResourceBinding::TextureDimension::kCube,
-            inspector::ResourceBinding::SampledKind::kFloat}));
+    testing::Values(GetSampledTextureTestParams{ast::TextureDimension::k1d,
+                                                inspector::ResourceBinding::TextureDimension::k1d,
+                                                inspector::ResourceBinding::SampledKind::kFloat},
+                    GetSampledTextureTestParams{ast::TextureDimension::k2d,
+                                                inspector::ResourceBinding::TextureDimension::k2d,
+                                                inspector::ResourceBinding::SampledKind::kFloat},
+                    GetSampledTextureTestParams{ast::TextureDimension::k3d,
+                                                inspector::ResourceBinding::TextureDimension::k3d,
+                                                inspector::ResourceBinding::SampledKind::kFloat},
+                    GetSampledTextureTestParams{ast::TextureDimension::kCube,
+                                                inspector::ResourceBinding::TextureDimension::kCube,
+                                                inspector::ResourceBinding::SampledKind::kFloat}));
 
-TEST_P(InspectorGetSampledArrayTextureResourceBindingsTestWithParam,
-       textureSample) {
-  auto* sampled_texture_type = ty.sampled_texture(
-      GetParam().type_dim, GetBaseType(GetParam().sampled_kind));
-  AddResource("foo_texture", sampled_texture_type, 0, 0);
-  AddSampler("foo_sampler", 0, 1);
-  auto* coord_type = GetCoordsType(GetParam().type_dim, ty.f32());
-  AddGlobalVariable("foo_coords", coord_type);
-  AddGlobalVariable("foo_array_index", ty.i32());
+TEST_P(InspectorGetSampledArrayTextureResourceBindingsTestWithParam, textureSample) {
+    auto* sampled_texture_type =
+        ty.sampled_texture(GetParam().type_dim, GetBaseType(GetParam().sampled_kind));
+    AddResource("foo_texture", sampled_texture_type, 0, 0);
+    AddSampler("foo_sampler", 0, 1);
+    auto* coord_type = GetCoordsType(GetParam().type_dim, ty.f32());
+    AddGlobalVariable("foo_coords", coord_type);
+    AddGlobalVariable("foo_array_index", ty.i32());
 
-  MakeSamplerReferenceBodyFunction("ep", "foo_texture", "foo_sampler",
-                                   "foo_coords", "foo_array_index",
-                                   GetBaseType(GetParam().sampled_kind),
-                                   ast::AttributeList{
-                                       Stage(ast::PipelineStage::kFragment),
-                                   });
+    MakeSamplerReferenceBodyFunction("ep", "foo_texture", "foo_sampler", "foo_coords",
+                                     "foo_array_index", GetBaseType(GetParam().sampled_kind),
+                                     ast::AttributeList{
+                                         Stage(ast::PipelineStage::kFragment),
+                                     });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetSampledTextureResourceBindings("ep");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
-  ASSERT_EQ(1u, result.size());
+    auto result = inspector.GetSampledTextureResourceBindings("ep");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    ASSERT_EQ(1u, result.size());
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kSampledTexture,
-            result[0].resource_type);
-  EXPECT_EQ(0u, result[0].bind_group);
-  EXPECT_EQ(0u, result[0].binding);
-  EXPECT_EQ(GetParam().inspector_dim, result[0].dim);
-  EXPECT_EQ(GetParam().sampled_kind, result[0].sampled_kind);
+    EXPECT_EQ(ResourceBinding::ResourceType::kSampledTexture, result[0].resource_type);
+    EXPECT_EQ(0u, result[0].bind_group);
+    EXPECT_EQ(0u, result[0].binding);
+    EXPECT_EQ(GetParam().inspector_dim, result[0].dim);
+    EXPECT_EQ(GetParam().sampled_kind, result[0].sampled_kind);
 }
 
 INSTANTIATE_TEST_SUITE_P(
     InspectorGetSampledArrayTextureResourceBindingsTest,
     InspectorGetSampledArrayTextureResourceBindingsTestWithParam,
     testing::Values(
-        GetSampledTextureTestParams{
-            ast::TextureDimension::k2dArray,
-            inspector::ResourceBinding::TextureDimension::k2dArray,
-            inspector::ResourceBinding::SampledKind::kFloat},
-        GetSampledTextureTestParams{
-            ast::TextureDimension::kCubeArray,
-            inspector::ResourceBinding::TextureDimension::kCubeArray,
-            inspector::ResourceBinding::SampledKind::kFloat}));
+        GetSampledTextureTestParams{ast::TextureDimension::k2dArray,
+                                    inspector::ResourceBinding::TextureDimension::k2dArray,
+                                    inspector::ResourceBinding::SampledKind::kFloat},
+        GetSampledTextureTestParams{ast::TextureDimension::kCubeArray,
+                                    inspector::ResourceBinding::TextureDimension::kCubeArray,
+                                    inspector::ResourceBinding::SampledKind::kFloat}));
 
-TEST_P(InspectorGetMultisampledTextureResourceBindingsTestWithParam,
-       textureLoad) {
-  auto* multisampled_texture_type = ty.multisampled_texture(
-      GetParam().type_dim, GetBaseType(GetParam().sampled_kind));
-  AddResource("foo_texture", multisampled_texture_type, 0, 0);
-  auto* coord_type = GetCoordsType(GetParam().type_dim, ty.i32());
-  AddGlobalVariable("foo_coords", coord_type);
-  AddGlobalVariable("foo_sample_index", ty.i32());
+TEST_P(InspectorGetMultisampledTextureResourceBindingsTestWithParam, textureLoad) {
+    auto* multisampled_texture_type =
+        ty.multisampled_texture(GetParam().type_dim, GetBaseType(GetParam().sampled_kind));
+    AddResource("foo_texture", multisampled_texture_type, 0, 0);
+    auto* coord_type = GetCoordsType(GetParam().type_dim, ty.i32());
+    AddGlobalVariable("foo_coords", coord_type);
+    AddGlobalVariable("foo_sample_index", ty.i32());
 
-  Func("ep", ast::VariableList(), ty.void_(),
-       ast::StatementList{
-           CallStmt(Call("textureLoad", "foo_texture", "foo_coords",
-                         "foo_sample_index")),
-       },
-       ast::AttributeList{
-           Stage(ast::PipelineStage::kFragment),
-       });
+    Func("ep", ast::VariableList(), ty.void_(),
+         ast::StatementList{
+             CallStmt(Call("textureLoad", "foo_texture", "foo_coords", "foo_sample_index")),
+         },
+         ast::AttributeList{
+             Stage(ast::PipelineStage::kFragment),
+         });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetMultisampledTextureResourceBindings("ep");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    auto result = inspector.GetMultisampledTextureResourceBindings("ep");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
-  ASSERT_EQ(1u, result.size());
-  EXPECT_EQ(ResourceBinding::ResourceType::kMultisampledTexture,
-            result[0].resource_type);
-  EXPECT_EQ(0u, result[0].bind_group);
-  EXPECT_EQ(0u, result[0].binding);
-  EXPECT_EQ(GetParam().inspector_dim, result[0].dim);
-  EXPECT_EQ(GetParam().sampled_kind, result[0].sampled_kind);
+    ASSERT_EQ(1u, result.size());
+    EXPECT_EQ(ResourceBinding::ResourceType::kMultisampledTexture, result[0].resource_type);
+    EXPECT_EQ(0u, result[0].bind_group);
+    EXPECT_EQ(0u, result[0].binding);
+    EXPECT_EQ(GetParam().inspector_dim, result[0].dim);
+    EXPECT_EQ(GetParam().sampled_kind, result[0].sampled_kind);
 
-  // Prove that sampled and multi-sampled bindings are accounted
-  // for separately.
-  auto single_sampled_result =
-      inspector.GetSampledTextureResourceBindings("ep");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
-  ASSERT_TRUE(single_sampled_result.empty());
+    // Prove that sampled and multi-sampled bindings are accounted
+    // for separately.
+    auto single_sampled_result = inspector.GetSampledTextureResourceBindings("ep");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    ASSERT_TRUE(single_sampled_result.empty());
 }
 
 INSTANTIATE_TEST_SUITE_P(
     InspectorGetMultisampledTextureResourceBindingsTest,
     InspectorGetMultisampledTextureResourceBindingsTestWithParam,
     testing::Values(
-        GetMultisampledTextureTestParams{
-            ast::TextureDimension::k2d,
-            inspector::ResourceBinding::TextureDimension::k2d,
-            inspector::ResourceBinding::SampledKind::kFloat},
-        GetMultisampledTextureTestParams{
-            ast::TextureDimension::k2d,
-            inspector::ResourceBinding::TextureDimension::k2d,
-            inspector::ResourceBinding::SampledKind::kSInt},
-        GetMultisampledTextureTestParams{
-            ast::TextureDimension::k2d,
-            inspector::ResourceBinding::TextureDimension::k2d,
-            inspector::ResourceBinding::SampledKind::kUInt}));
+        GetMultisampledTextureTestParams{ast::TextureDimension::k2d,
+                                         inspector::ResourceBinding::TextureDimension::k2d,
+                                         inspector::ResourceBinding::SampledKind::kFloat},
+        GetMultisampledTextureTestParams{ast::TextureDimension::k2d,
+                                         inspector::ResourceBinding::TextureDimension::k2d,
+                                         inspector::ResourceBinding::SampledKind::kSInt},
+        GetMultisampledTextureTestParams{ast::TextureDimension::k2d,
+                                         inspector::ResourceBinding::TextureDimension::k2d,
+                                         inspector::ResourceBinding::SampledKind::kUInt}));
 
 TEST_F(InspectorGetMultisampledArrayTextureResourceBindingsTest, Empty) {
-  MakeEmptyBodyFunction("foo", ast::AttributeList{
-                                   Stage(ast::PipelineStage::kFragment),
-                               });
+    MakeEmptyBodyFunction("foo", ast::AttributeList{
+                                     Stage(ast::PipelineStage::kFragment),
+                                 });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetSampledTextureResourceBindings("foo");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    auto result = inspector.GetSampledTextureResourceBindings("foo");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
-  EXPECT_EQ(0u, result.size());
+    EXPECT_EQ(0u, result.size());
 }
 
-TEST_P(InspectorGetMultisampledArrayTextureResourceBindingsTestWithParam,
-       DISABLED_textureSample) {
-  auto* multisampled_texture_type = ty.multisampled_texture(
-      GetParam().type_dim, GetBaseType(GetParam().sampled_kind));
-  AddResource("foo_texture", multisampled_texture_type, 0, 0);
-  AddSampler("foo_sampler", 0, 1);
-  auto* coord_type = GetCoordsType(GetParam().type_dim, ty.f32());
-  AddGlobalVariable("foo_coords", coord_type);
-  AddGlobalVariable("foo_array_index", ty.i32());
+TEST_P(InspectorGetMultisampledArrayTextureResourceBindingsTestWithParam, DISABLED_textureSample) {
+    auto* multisampled_texture_type =
+        ty.multisampled_texture(GetParam().type_dim, GetBaseType(GetParam().sampled_kind));
+    AddResource("foo_texture", multisampled_texture_type, 0, 0);
+    AddSampler("foo_sampler", 0, 1);
+    auto* coord_type = GetCoordsType(GetParam().type_dim, ty.f32());
+    AddGlobalVariable("foo_coords", coord_type);
+    AddGlobalVariable("foo_array_index", ty.i32());
 
-  MakeSamplerReferenceBodyFunction("ep", "foo_texture", "foo_sampler",
-                                   "foo_coords", "foo_array_index",
-                                   GetBaseType(GetParam().sampled_kind),
-                                   ast::AttributeList{
-                                       Stage(ast::PipelineStage::kFragment),
-                                   });
+    MakeSamplerReferenceBodyFunction("ep", "foo_texture", "foo_sampler", "foo_coords",
+                                     "foo_array_index", GetBaseType(GetParam().sampled_kind),
+                                     ast::AttributeList{
+                                         Stage(ast::PipelineStage::kFragment),
+                                     });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetMultisampledTextureResourceBindings("ep");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
-  ASSERT_EQ(1u, result.size());
+    auto result = inspector.GetMultisampledTextureResourceBindings("ep");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    ASSERT_EQ(1u, result.size());
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kMultisampledTexture,
-            result[0].resource_type);
-  EXPECT_EQ(0u, result[0].bind_group);
-  EXPECT_EQ(0u, result[0].binding);
-  EXPECT_EQ(GetParam().inspector_dim, result[0].dim);
-  EXPECT_EQ(GetParam().sampled_kind, result[0].sampled_kind);
+    EXPECT_EQ(ResourceBinding::ResourceType::kMultisampledTexture, result[0].resource_type);
+    EXPECT_EQ(0u, result[0].bind_group);
+    EXPECT_EQ(0u, result[0].binding);
+    EXPECT_EQ(GetParam().inspector_dim, result[0].dim);
+    EXPECT_EQ(GetParam().sampled_kind, result[0].sampled_kind);
 }
 
 INSTANTIATE_TEST_SUITE_P(
     InspectorGetMultisampledArrayTextureResourceBindingsTest,
     InspectorGetMultisampledArrayTextureResourceBindingsTestWithParam,
     testing::Values(
-        GetMultisampledTextureTestParams{
-            ast::TextureDimension::k2dArray,
-            inspector::ResourceBinding::TextureDimension::k2dArray,
-            inspector::ResourceBinding::SampledKind::kFloat},
-        GetMultisampledTextureTestParams{
-            ast::TextureDimension::k2dArray,
-            inspector::ResourceBinding::TextureDimension::k2dArray,
-            inspector::ResourceBinding::SampledKind::kSInt},
-        GetMultisampledTextureTestParams{
-            ast::TextureDimension::k2dArray,
-            inspector::ResourceBinding::TextureDimension::k2dArray,
-            inspector::ResourceBinding::SampledKind::kUInt}));
+        GetMultisampledTextureTestParams{ast::TextureDimension::k2dArray,
+                                         inspector::ResourceBinding::TextureDimension::k2dArray,
+                                         inspector::ResourceBinding::SampledKind::kFloat},
+        GetMultisampledTextureTestParams{ast::TextureDimension::k2dArray,
+                                         inspector::ResourceBinding::TextureDimension::k2dArray,
+                                         inspector::ResourceBinding::SampledKind::kSInt},
+        GetMultisampledTextureTestParams{ast::TextureDimension::k2dArray,
+                                         inspector::ResourceBinding::TextureDimension::k2dArray,
+                                         inspector::ResourceBinding::SampledKind::kUInt}));
 
 TEST_F(InspectorGetStorageTextureResourceBindingsTest, Empty) {
-  MakeEmptyBodyFunction("ep", ast::AttributeList{
-                                  Stage(ast::PipelineStage::kFragment),
-                              });
+    MakeEmptyBodyFunction("ep", ast::AttributeList{
+                                    Stage(ast::PipelineStage::kFragment),
+                                });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetWriteOnlyStorageTextureResourceBindings("ep");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
-  EXPECT_EQ(0u, result.size());
+    auto result = inspector.GetWriteOnlyStorageTextureResourceBindings("ep");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    EXPECT_EQ(0u, result.size());
 }
 
 TEST_P(InspectorGetStorageTextureResourceBindingsTestWithParam, Simple) {
-  DimensionParams dim_params;
-  TexelFormatParams format_params;
-  std::tie(dim_params, format_params) = GetParam();
+    DimensionParams dim_params;
+    TexelFormatParams format_params;
+    std::tie(dim_params, format_params) = GetParam();
 
-  ast::TextureDimension dim;
-  ResourceBinding::TextureDimension expected_dim;
-  std::tie(dim, expected_dim) = dim_params;
+    ast::TextureDimension dim;
+    ResourceBinding::TextureDimension expected_dim;
+    std::tie(dim, expected_dim) = dim_params;
 
-  ast::TexelFormat format;
-  ResourceBinding::TexelFormat expected_format;
-  ResourceBinding::SampledKind expected_kind;
-  std::tie(format, expected_format, expected_kind) = format_params;
+    ast::TexelFormat format;
+    ResourceBinding::TexelFormat expected_format;
+    ResourceBinding::SampledKind expected_kind;
+    std::tie(format, expected_format, expected_kind) = format_params;
 
-  auto* st_type = MakeStorageTextureTypes(dim, format);
-  AddStorageTexture("st_var", st_type, 0, 0);
+    auto* st_type = MakeStorageTextureTypes(dim, format);
+    AddStorageTexture("st_var", st_type, 0, 0);
 
-  const ast::Type* dim_type = nullptr;
-  switch (dim) {
-    case ast::TextureDimension::k1d:
-      dim_type = ty.i32();
-      break;
-    case ast::TextureDimension::k2d:
-    case ast::TextureDimension::k2dArray:
-      dim_type = ty.vec2<i32>();
-      break;
-    case ast::TextureDimension::k3d:
-      dim_type = ty.vec3<i32>();
-      break;
-    default:
-      break;
-  }
+    const ast::Type* dim_type = nullptr;
+    switch (dim) {
+        case ast::TextureDimension::k1d:
+            dim_type = ty.i32();
+            break;
+        case ast::TextureDimension::k2d:
+        case ast::TextureDimension::k2dArray:
+            dim_type = ty.vec2<i32>();
+            break;
+        case ast::TextureDimension::k3d:
+            dim_type = ty.vec3<i32>();
+            break;
+        default:
+            break;
+    }
 
-  ASSERT_FALSE(dim_type == nullptr);
+    ASSERT_FALSE(dim_type == nullptr);
 
-  MakeStorageTextureBodyFunction(
-      "ep", "st_var", dim_type,
-      ast::AttributeList{Stage(ast::PipelineStage::kFragment)});
+    MakeStorageTextureBodyFunction("ep", "st_var", dim_type,
+                                   ast::AttributeList{Stage(ast::PipelineStage::kFragment)});
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetWriteOnlyStorageTextureResourceBindings("ep");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
-  ASSERT_EQ(1u, result.size());
+    auto result = inspector.GetWriteOnlyStorageTextureResourceBindings("ep");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    ASSERT_EQ(1u, result.size());
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kWriteOnlyStorageTexture,
-            result[0].resource_type);
-  EXPECT_EQ(0u, result[0].bind_group);
-  EXPECT_EQ(0u, result[0].binding);
-  EXPECT_EQ(expected_dim, result[0].dim);
-  EXPECT_EQ(expected_format, result[0].image_format);
-  EXPECT_EQ(expected_kind, result[0].sampled_kind);
+    EXPECT_EQ(ResourceBinding::ResourceType::kWriteOnlyStorageTexture, result[0].resource_type);
+    EXPECT_EQ(0u, result[0].bind_group);
+    EXPECT_EQ(0u, result[0].binding);
+    EXPECT_EQ(expected_dim, result[0].dim);
+    EXPECT_EQ(expected_format, result[0].image_format);
+    EXPECT_EQ(expected_kind, result[0].sampled_kind);
 }
 
 INSTANTIATE_TEST_SUITE_P(
     InspectorGetStorageTextureResourceBindingsTest,
     InspectorGetStorageTextureResourceBindingsTestWithParam,
-    testing::Combine(
-        testing::Values(
-            std::make_tuple(ast::TextureDimension::k1d,
-                            ResourceBinding::TextureDimension::k1d),
-            std::make_tuple(ast::TextureDimension::k2d,
-                            ResourceBinding::TextureDimension::k2d),
-            std::make_tuple(ast::TextureDimension::k2dArray,
-                            ResourceBinding::TextureDimension::k2dArray),
-            std::make_tuple(ast::TextureDimension::k3d,
-                            ResourceBinding::TextureDimension::k3d)),
-        testing::Values(
-            std::make_tuple(ast::TexelFormat::kR32Float,
-                            ResourceBinding::TexelFormat::kR32Float,
-                            ResourceBinding::SampledKind::kFloat),
-            std::make_tuple(ast::TexelFormat::kR32Sint,
-                            ResourceBinding::TexelFormat::kR32Sint,
-                            ResourceBinding::SampledKind::kSInt),
-            std::make_tuple(ast::TexelFormat::kR32Uint,
-                            ResourceBinding::TexelFormat::kR32Uint,
-                            ResourceBinding::SampledKind::kUInt),
-            std::make_tuple(ast::TexelFormat::kRg32Float,
-                            ResourceBinding::TexelFormat::kRg32Float,
-                            ResourceBinding::SampledKind::kFloat),
-            std::make_tuple(ast::TexelFormat::kRg32Sint,
-                            ResourceBinding::TexelFormat::kRg32Sint,
-                            ResourceBinding::SampledKind::kSInt),
-            std::make_tuple(ast::TexelFormat::kRg32Uint,
-                            ResourceBinding::TexelFormat::kRg32Uint,
-                            ResourceBinding::SampledKind::kUInt),
-            std::make_tuple(ast::TexelFormat::kRgba16Float,
-                            ResourceBinding::TexelFormat::kRgba16Float,
-                            ResourceBinding::SampledKind::kFloat),
-            std::make_tuple(ast::TexelFormat::kRgba16Sint,
-                            ResourceBinding::TexelFormat::kRgba16Sint,
-                            ResourceBinding::SampledKind::kSInt),
-            std::make_tuple(ast::TexelFormat::kRgba16Uint,
-                            ResourceBinding::TexelFormat::kRgba16Uint,
-                            ResourceBinding::SampledKind::kUInt),
-            std::make_tuple(ast::TexelFormat::kRgba32Float,
-                            ResourceBinding::TexelFormat::kRgba32Float,
-                            ResourceBinding::SampledKind::kFloat),
-            std::make_tuple(ast::TexelFormat::kRgba32Sint,
-                            ResourceBinding::TexelFormat::kRgba32Sint,
-                            ResourceBinding::SampledKind::kSInt),
-            std::make_tuple(ast::TexelFormat::kRgba32Uint,
-                            ResourceBinding::TexelFormat::kRgba32Uint,
-                            ResourceBinding::SampledKind::kUInt),
-            std::make_tuple(ast::TexelFormat::kRgba8Sint,
-                            ResourceBinding::TexelFormat::kRgba8Sint,
-                            ResourceBinding::SampledKind::kSInt),
-            std::make_tuple(ast::TexelFormat::kRgba8Snorm,
-                            ResourceBinding::TexelFormat::kRgba8Snorm,
-                            ResourceBinding::SampledKind::kFloat),
-            std::make_tuple(ast::TexelFormat::kRgba8Uint,
-                            ResourceBinding::TexelFormat::kRgba8Uint,
-                            ResourceBinding::SampledKind::kUInt),
-            std::make_tuple(ast::TexelFormat::kRgba8Unorm,
-                            ResourceBinding::TexelFormat::kRgba8Unorm,
-                            ResourceBinding::SampledKind::kFloat))));
+    testing::Combine(testing::Values(std::make_tuple(ast::TextureDimension::k1d,
+                                                     ResourceBinding::TextureDimension::k1d),
+                                     std::make_tuple(ast::TextureDimension::k2d,
+                                                     ResourceBinding::TextureDimension::k2d),
+                                     std::make_tuple(ast::TextureDimension::k2dArray,
+                                                     ResourceBinding::TextureDimension::k2dArray),
+                                     std::make_tuple(ast::TextureDimension::k3d,
+                                                     ResourceBinding::TextureDimension::k3d)),
+                     testing::Values(std::make_tuple(ast::TexelFormat::kR32Float,
+                                                     ResourceBinding::TexelFormat::kR32Float,
+                                                     ResourceBinding::SampledKind::kFloat),
+                                     std::make_tuple(ast::TexelFormat::kR32Sint,
+                                                     ResourceBinding::TexelFormat::kR32Sint,
+                                                     ResourceBinding::SampledKind::kSInt),
+                                     std::make_tuple(ast::TexelFormat::kR32Uint,
+                                                     ResourceBinding::TexelFormat::kR32Uint,
+                                                     ResourceBinding::SampledKind::kUInt),
+                                     std::make_tuple(ast::TexelFormat::kRg32Float,
+                                                     ResourceBinding::TexelFormat::kRg32Float,
+                                                     ResourceBinding::SampledKind::kFloat),
+                                     std::make_tuple(ast::TexelFormat::kRg32Sint,
+                                                     ResourceBinding::TexelFormat::kRg32Sint,
+                                                     ResourceBinding::SampledKind::kSInt),
+                                     std::make_tuple(ast::TexelFormat::kRg32Uint,
+                                                     ResourceBinding::TexelFormat::kRg32Uint,
+                                                     ResourceBinding::SampledKind::kUInt),
+                                     std::make_tuple(ast::TexelFormat::kRgba16Float,
+                                                     ResourceBinding::TexelFormat::kRgba16Float,
+                                                     ResourceBinding::SampledKind::kFloat),
+                                     std::make_tuple(ast::TexelFormat::kRgba16Sint,
+                                                     ResourceBinding::TexelFormat::kRgba16Sint,
+                                                     ResourceBinding::SampledKind::kSInt),
+                                     std::make_tuple(ast::TexelFormat::kRgba16Uint,
+                                                     ResourceBinding::TexelFormat::kRgba16Uint,
+                                                     ResourceBinding::SampledKind::kUInt),
+                                     std::make_tuple(ast::TexelFormat::kRgba32Float,
+                                                     ResourceBinding::TexelFormat::kRgba32Float,
+                                                     ResourceBinding::SampledKind::kFloat),
+                                     std::make_tuple(ast::TexelFormat::kRgba32Sint,
+                                                     ResourceBinding::TexelFormat::kRgba32Sint,
+                                                     ResourceBinding::SampledKind::kSInt),
+                                     std::make_tuple(ast::TexelFormat::kRgba32Uint,
+                                                     ResourceBinding::TexelFormat::kRgba32Uint,
+                                                     ResourceBinding::SampledKind::kUInt),
+                                     std::make_tuple(ast::TexelFormat::kRgba8Sint,
+                                                     ResourceBinding::TexelFormat::kRgba8Sint,
+                                                     ResourceBinding::SampledKind::kSInt),
+                                     std::make_tuple(ast::TexelFormat::kRgba8Snorm,
+                                                     ResourceBinding::TexelFormat::kRgba8Snorm,
+                                                     ResourceBinding::SampledKind::kFloat),
+                                     std::make_tuple(ast::TexelFormat::kRgba8Uint,
+                                                     ResourceBinding::TexelFormat::kRgba8Uint,
+                                                     ResourceBinding::SampledKind::kUInt),
+                                     std::make_tuple(ast::TexelFormat::kRgba8Unorm,
+                                                     ResourceBinding::TexelFormat::kRgba8Unorm,
+                                                     ResourceBinding::SampledKind::kFloat))));
 
-TEST_P(InspectorGetDepthTextureResourceBindingsTestWithParam,
-       textureDimensions) {
-  auto* depth_texture_type = ty.depth_texture(GetParam().type_dim);
-  AddResource("dt", depth_texture_type, 0, 0);
+TEST_P(InspectorGetDepthTextureResourceBindingsTestWithParam, textureDimensions) {
+    auto* depth_texture_type = ty.depth_texture(GetParam().type_dim);
+    AddResource("dt", depth_texture_type, 0, 0);
 
-  Func("ep", ast::VariableList(), ty.void_(),
-       ast::StatementList{
-           CallStmt(Call("textureDimensions", "dt")),
-       },
-       ast::AttributeList{
-           Stage(ast::PipelineStage::kFragment),
-       });
+    Func("ep", ast::VariableList(), ty.void_(),
+         ast::StatementList{
+             CallStmt(Call("textureDimensions", "dt")),
+         },
+         ast::AttributeList{
+             Stage(ast::PipelineStage::kFragment),
+         });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetDepthTextureResourceBindings("ep");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    auto result = inspector.GetDepthTextureResourceBindings("ep");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kDepthTexture,
-            result[0].resource_type);
-  ASSERT_EQ(1u, result.size());
-  EXPECT_EQ(0u, result[0].bind_group);
-  EXPECT_EQ(0u, result[0].binding);
-  EXPECT_EQ(GetParam().inspector_dim, result[0].dim);
+    EXPECT_EQ(ResourceBinding::ResourceType::kDepthTexture, result[0].resource_type);
+    ASSERT_EQ(1u, result.size());
+    EXPECT_EQ(0u, result[0].bind_group);
+    EXPECT_EQ(0u, result[0].binding);
+    EXPECT_EQ(GetParam().inspector_dim, result[0].dim);
 }
 
 INSTANTIATE_TEST_SUITE_P(
     InspectorGetDepthTextureResourceBindingsTest,
     InspectorGetDepthTextureResourceBindingsTestWithParam,
     testing::Values(
-        GetDepthTextureTestParams{
-            ast::TextureDimension::k2d,
-            inspector::ResourceBinding::TextureDimension::k2d},
-        GetDepthTextureTestParams{
-            ast::TextureDimension::k2dArray,
-            inspector::ResourceBinding::TextureDimension::k2dArray},
-        GetDepthTextureTestParams{
-            ast::TextureDimension::kCube,
-            inspector::ResourceBinding::TextureDimension::kCube},
-        GetDepthTextureTestParams{
-            ast::TextureDimension::kCubeArray,
-            inspector::ResourceBinding::TextureDimension::kCubeArray}));
+        GetDepthTextureTestParams{ast::TextureDimension::k2d,
+                                  inspector::ResourceBinding::TextureDimension::k2d},
+        GetDepthTextureTestParams{ast::TextureDimension::k2dArray,
+                                  inspector::ResourceBinding::TextureDimension::k2dArray},
+        GetDepthTextureTestParams{ast::TextureDimension::kCube,
+                                  inspector::ResourceBinding::TextureDimension::kCube},
+        GetDepthTextureTestParams{ast::TextureDimension::kCubeArray,
+                                  inspector::ResourceBinding::TextureDimension::kCubeArray}));
 
-TEST_F(InspectorGetDepthMultisampledTextureResourceBindingsTest,
-       textureDimensions) {
-  auto* depth_ms_texture_type =
-      ty.depth_multisampled_texture(ast::TextureDimension::k2d);
-  AddResource("tex", depth_ms_texture_type, 0, 0);
+TEST_F(InspectorGetDepthMultisampledTextureResourceBindingsTest, textureDimensions) {
+    auto* depth_ms_texture_type = ty.depth_multisampled_texture(ast::TextureDimension::k2d);
+    AddResource("tex", depth_ms_texture_type, 0, 0);
 
-  Func("ep", ast::VariableList(), ty.void_(),
-       ast::StatementList{
-           CallStmt(Call("textureDimensions", "tex")),
-       },
-       ast::AttributeList{
-           Stage(ast::PipelineStage::kFragment),
-       });
+    Func("ep", ast::VariableList(), ty.void_(),
+         ast::StatementList{
+             CallStmt(Call("textureDimensions", "tex")),
+         },
+         ast::AttributeList{
+             Stage(ast::PipelineStage::kFragment),
+         });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetDepthMultisampledTextureResourceBindings("ep");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    auto result = inspector.GetDepthMultisampledTextureResourceBindings("ep");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
-  EXPECT_EQ(ResourceBinding::ResourceType::kDepthMultisampledTexture,
-            result[0].resource_type);
-  ASSERT_EQ(1u, result.size());
-  EXPECT_EQ(0u, result[0].bind_group);
-  EXPECT_EQ(0u, result[0].binding);
-  EXPECT_EQ(ResourceBinding::TextureDimension::k2d, result[0].dim);
+    EXPECT_EQ(ResourceBinding::ResourceType::kDepthMultisampledTexture, result[0].resource_type);
+    ASSERT_EQ(1u, result.size());
+    EXPECT_EQ(0u, result[0].bind_group);
+    EXPECT_EQ(0u, result[0].binding);
+    EXPECT_EQ(ResourceBinding::TextureDimension::k2d, result[0].dim);
 }
 
 TEST_F(InspectorGetExternalTextureResourceBindingsTest, Simple) {
-  auto* external_texture_type = ty.external_texture();
-  AddResource("et", external_texture_type, 0, 0);
+    auto* external_texture_type = ty.external_texture();
+    AddResource("et", external_texture_type, 0, 0);
 
-  Func("ep", ast::VariableList(), ty.void_(),
-       ast::StatementList{
-           CallStmt(Call("textureDimensions", "et")),
-       },
-       ast::AttributeList{
-           Stage(ast::PipelineStage::kFragment),
-       });
+    Func("ep", ast::VariableList(), ty.void_(),
+         ast::StatementList{
+             CallStmt(Call("textureDimensions", "et")),
+         },
+         ast::AttributeList{
+             Stage(ast::PipelineStage::kFragment),
+         });
 
-  Inspector& inspector = Build();
+    Inspector& inspector = Build();
 
-  auto result = inspector.GetExternalTextureResourceBindings("ep");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
-  EXPECT_EQ(ResourceBinding::ResourceType::kExternalTexture,
-            result[0].resource_type);
+    auto result = inspector.GetExternalTextureResourceBindings("ep");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    EXPECT_EQ(ResourceBinding::ResourceType::kExternalTexture, result[0].resource_type);
 
-  ASSERT_EQ(1u, result.size());
-  EXPECT_EQ(0u, result[0].bind_group);
-  EXPECT_EQ(0u, result[0].binding);
+    ASSERT_EQ(1u, result.size());
+    EXPECT_EQ(0u, result[0].bind_group);
+    EXPECT_EQ(0u, result[0].binding);
 }
 
 TEST_F(InspectorGetSamplerTextureUsesTest, None) {
-  std::string shader = R"(
+    std::string shader = R"(
 @stage(fragment)
 fn main() {
 })";
 
-  Inspector& inspector = Initialize(shader);
-  auto result = inspector.GetSamplerTextureUses("main");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    Inspector& inspector = Initialize(shader);
+    auto result = inspector.GetSamplerTextureUses("main");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
-  ASSERT_EQ(0u, result.size());
+    ASSERT_EQ(0u, result.size());
 }
 
 TEST_F(InspectorGetSamplerTextureUsesTest, Simple) {
-  std::string shader = R"(
+    std::string shader = R"(
 @group(0) @binding(1) var mySampler: sampler;
 @group(0) @binding(2) var myTexture: texture_2d<f32>;
 
@@ -2683,20 +2507,20 @@
   return textureSample(myTexture, mySampler, fragUV) * fragPosition;
 })";
 
-  Inspector& inspector = Initialize(shader);
-  auto result = inspector.GetSamplerTextureUses("main");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    Inspector& inspector = Initialize(shader);
+    auto result = inspector.GetSamplerTextureUses("main");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
-  ASSERT_EQ(1u, result.size());
+    ASSERT_EQ(1u, result.size());
 
-  EXPECT_EQ(0u, result[0].sampler_binding_point.group);
-  EXPECT_EQ(1u, result[0].sampler_binding_point.binding);
-  EXPECT_EQ(0u, result[0].texture_binding_point.group);
-  EXPECT_EQ(2u, result[0].texture_binding_point.binding);
+    EXPECT_EQ(0u, result[0].sampler_binding_point.group);
+    EXPECT_EQ(1u, result[0].sampler_binding_point.binding);
+    EXPECT_EQ(0u, result[0].texture_binding_point.group);
+    EXPECT_EQ(2u, result[0].texture_binding_point.binding);
 }
 
 TEST_F(InspectorGetSamplerTextureUsesTest, UnknownEntryPoint) {
-  std::string shader = R"(
+    std::string shader = R"(
 @group(0) @binding(1) var mySampler: sampler;
 @group(0) @binding(2) var myTexture: texture_2d<f32>;
 
@@ -2706,13 +2530,13 @@
   return textureSample(myTexture, mySampler, fragUV) * fragPosition;
 })";
 
-  Inspector& inspector = Initialize(shader);
-  auto result = inspector.GetSamplerTextureUses("foo");
-  ASSERT_TRUE(inspector.has_error()) << inspector.error();
+    Inspector& inspector = Initialize(shader);
+    auto result = inspector.GetSamplerTextureUses("foo");
+    ASSERT_TRUE(inspector.has_error()) << inspector.error();
 }
 
 TEST_F(InspectorGetSamplerTextureUsesTest, MultipleCalls) {
-  std::string shader = R"(
+    std::string shader = R"(
 @group(0) @binding(1) var mySampler: sampler;
 @group(0) @binding(2) var myTexture: texture_2d<f32>;
 
@@ -2722,18 +2546,18 @@
   return textureSample(myTexture, mySampler, fragUV) * fragPosition;
 })";
 
-  Inspector& inspector = Initialize(shader);
-  auto result_0 = inspector.GetSamplerTextureUses("main");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    Inspector& inspector = Initialize(shader);
+    auto result_0 = inspector.GetSamplerTextureUses("main");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
-  auto result_1 = inspector.GetSamplerTextureUses("main");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    auto result_1 = inspector.GetSamplerTextureUses("main");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
-  EXPECT_EQ(result_0, result_1);
+    EXPECT_EQ(result_0, result_1);
 }
 
 TEST_F(InspectorGetSamplerTextureUsesTest, BothIndirect) {
-  std::string shader = R"(
+    std::string shader = R"(
 @group(0) @binding(1) var mySampler: sampler;
 @group(0) @binding(2) var myTexture: texture_2d<f32>;
 
@@ -2747,20 +2571,20 @@
   return doSample(myTexture, mySampler, fragUV) * fragPosition;
 })";
 
-  Inspector& inspector = Initialize(shader);
-  auto result = inspector.GetSamplerTextureUses("main");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    Inspector& inspector = Initialize(shader);
+    auto result = inspector.GetSamplerTextureUses("main");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
-  ASSERT_EQ(1u, result.size());
+    ASSERT_EQ(1u, result.size());
 
-  EXPECT_EQ(0u, result[0].sampler_binding_point.group);
-  EXPECT_EQ(1u, result[0].sampler_binding_point.binding);
-  EXPECT_EQ(0u, result[0].texture_binding_point.group);
-  EXPECT_EQ(2u, result[0].texture_binding_point.binding);
+    EXPECT_EQ(0u, result[0].sampler_binding_point.group);
+    EXPECT_EQ(1u, result[0].sampler_binding_point.binding);
+    EXPECT_EQ(0u, result[0].texture_binding_point.group);
+    EXPECT_EQ(2u, result[0].texture_binding_point.binding);
 }
 
 TEST_F(InspectorGetSamplerTextureUsesTest, SamplerIndirect) {
-  std::string shader = R"(
+    std::string shader = R"(
 @group(0) @binding(1) var mySampler: sampler;
 @group(0) @binding(2) var myTexture: texture_2d<f32>;
 
@@ -2774,20 +2598,20 @@
   return doSample(mySampler, fragUV) * fragPosition;
 })";
 
-  Inspector& inspector = Initialize(shader);
-  auto result = inspector.GetSamplerTextureUses("main");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    Inspector& inspector = Initialize(shader);
+    auto result = inspector.GetSamplerTextureUses("main");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
-  ASSERT_EQ(1u, result.size());
+    ASSERT_EQ(1u, result.size());
 
-  EXPECT_EQ(0u, result[0].sampler_binding_point.group);
-  EXPECT_EQ(1u, result[0].sampler_binding_point.binding);
-  EXPECT_EQ(0u, result[0].texture_binding_point.group);
-  EXPECT_EQ(2u, result[0].texture_binding_point.binding);
+    EXPECT_EQ(0u, result[0].sampler_binding_point.group);
+    EXPECT_EQ(1u, result[0].sampler_binding_point.binding);
+    EXPECT_EQ(0u, result[0].texture_binding_point.group);
+    EXPECT_EQ(2u, result[0].texture_binding_point.binding);
 }
 
 TEST_F(InspectorGetSamplerTextureUsesTest, TextureIndirect) {
-  std::string shader = R"(
+    std::string shader = R"(
 @group(0) @binding(1) var mySampler: sampler;
 @group(0) @binding(2) var myTexture: texture_2d<f32>;
 
@@ -2801,20 +2625,20 @@
   return doSample(myTexture, fragUV) * fragPosition;
 })";
 
-  Inspector& inspector = Initialize(shader);
-  auto result = inspector.GetSamplerTextureUses("main");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    Inspector& inspector = Initialize(shader);
+    auto result = inspector.GetSamplerTextureUses("main");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
-  ASSERT_EQ(1u, result.size());
+    ASSERT_EQ(1u, result.size());
 
-  EXPECT_EQ(0u, result[0].sampler_binding_point.group);
-  EXPECT_EQ(1u, result[0].sampler_binding_point.binding);
-  EXPECT_EQ(0u, result[0].texture_binding_point.group);
-  EXPECT_EQ(2u, result[0].texture_binding_point.binding);
+    EXPECT_EQ(0u, result[0].sampler_binding_point.group);
+    EXPECT_EQ(1u, result[0].sampler_binding_point.binding);
+    EXPECT_EQ(0u, result[0].texture_binding_point.group);
+    EXPECT_EQ(2u, result[0].texture_binding_point.binding);
 }
 
 TEST_F(InspectorGetSamplerTextureUsesTest, NeitherIndirect) {
-  std::string shader = R"(
+    std::string shader = R"(
 @group(0) @binding(1) var mySampler: sampler;
 @group(0) @binding(2) var myTexture: texture_2d<f32>;
 
@@ -2828,20 +2652,20 @@
   return doSample(fragUV) * fragPosition;
 })";
 
-  Inspector& inspector = Initialize(shader);
-  auto result = inspector.GetSamplerTextureUses("main");
-  ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    Inspector& inspector = Initialize(shader);
+    auto result = inspector.GetSamplerTextureUses("main");
+    ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
-  ASSERT_EQ(1u, result.size());
+    ASSERT_EQ(1u, result.size());
 
-  EXPECT_EQ(0u, result[0].sampler_binding_point.group);
-  EXPECT_EQ(1u, result[0].sampler_binding_point.binding);
-  EXPECT_EQ(0u, result[0].texture_binding_point.group);
-  EXPECT_EQ(2u, result[0].texture_binding_point.binding);
+    EXPECT_EQ(0u, result[0].sampler_binding_point.group);
+    EXPECT_EQ(1u, result[0].sampler_binding_point.binding);
+    EXPECT_EQ(0u, result[0].texture_binding_point.group);
+    EXPECT_EQ(2u, result[0].texture_binding_point.binding);
 }
 
 TEST_F(InspectorGetSamplerTextureUsesTest, Complex) {
-  std::string shader = R"(
+    std::string shader = R"(
 @group(0) @binding(1) var mySampler: sampler;
 @group(0) @binding(2) var myTexture: texture_2d<f32>;
 
@@ -2880,134 +2704,247 @@
   return textureSample(myTexture, mySampler, fragUV) + fragPosition;
 })";
 
-  Inspector& inspector = Initialize(shader);
+    Inspector& inspector = Initialize(shader);
 
-  {
-    auto result = inspector.GetSamplerTextureUses("via_call");
-    ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    {
+        auto result = inspector.GetSamplerTextureUses("via_call");
+        ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
-    ASSERT_EQ(1u, result.size());
+        ASSERT_EQ(1u, result.size());
 
-    EXPECT_EQ(0u, result[0].sampler_binding_point.group);
-    EXPECT_EQ(1u, result[0].sampler_binding_point.binding);
-    EXPECT_EQ(0u, result[0].texture_binding_point.group);
-    EXPECT_EQ(2u, result[0].texture_binding_point.binding);
-  }
+        EXPECT_EQ(0u, result[0].sampler_binding_point.group);
+        EXPECT_EQ(1u, result[0].sampler_binding_point.binding);
+        EXPECT_EQ(0u, result[0].texture_binding_point.group);
+        EXPECT_EQ(2u, result[0].texture_binding_point.binding);
+    }
 
-  {
-    auto result = inspector.GetSamplerTextureUses("via_ptr");
-    ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    {
+        auto result = inspector.GetSamplerTextureUses("via_ptr");
+        ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
-    ASSERT_EQ(1u, result.size());
+        ASSERT_EQ(1u, result.size());
 
-    EXPECT_EQ(0u, result[0].sampler_binding_point.group);
-    EXPECT_EQ(1u, result[0].sampler_binding_point.binding);
-    EXPECT_EQ(0u, result[0].texture_binding_point.group);
-    EXPECT_EQ(2u, result[0].texture_binding_point.binding);
-  }
+        EXPECT_EQ(0u, result[0].sampler_binding_point.group);
+        EXPECT_EQ(1u, result[0].sampler_binding_point.binding);
+        EXPECT_EQ(0u, result[0].texture_binding_point.group);
+        EXPECT_EQ(2u, result[0].texture_binding_point.binding);
+    }
 
-  {
-    auto result = inspector.GetSamplerTextureUses("direct");
-    ASSERT_FALSE(inspector.has_error()) << inspector.error();
+    {
+        auto result = inspector.GetSamplerTextureUses("direct");
+        ASSERT_FALSE(inspector.has_error()) << inspector.error();
 
-    ASSERT_EQ(1u, result.size());
+        ASSERT_EQ(1u, result.size());
 
-    EXPECT_EQ(0u, result[0].sampler_binding_point.group);
-    EXPECT_EQ(1u, result[0].sampler_binding_point.binding);
-    EXPECT_EQ(0u, result[0].texture_binding_point.group);
-    EXPECT_EQ(2u, result[0].texture_binding_point.binding);
-  }
+        EXPECT_EQ(0u, result[0].sampler_binding_point.group);
+        EXPECT_EQ(1u, result[0].sampler_binding_point.binding);
+        EXPECT_EQ(0u, result[0].texture_binding_point.group);
+        EXPECT_EQ(2u, result[0].texture_binding_point.binding);
+    }
 }
 
 TEST_F(InspectorGetWorkgroupStorageSizeTest, Empty) {
-  MakeEmptyBodyFunction("ep_func",
-                        ast::AttributeList{Stage(ast::PipelineStage::kCompute),
-                                           WorkgroupSize(1)});
-  Inspector& inspector = Build();
-  EXPECT_EQ(0u, inspector.GetWorkgroupStorageSize("ep_func"));
+    MakeEmptyBodyFunction(
+        "ep_func", ast::AttributeList{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+    Inspector& inspector = Build();
+    EXPECT_EQ(0u, inspector.GetWorkgroupStorageSize("ep_func"));
 }
 
 TEST_F(InspectorGetWorkgroupStorageSizeTest, Simple) {
-  AddWorkgroupStorage("wg_f32", ty.f32());
-  MakePlainGlobalReferenceBodyFunction("f32_func", "wg_f32", ty.f32(), {});
+    AddWorkgroupStorage("wg_f32", ty.f32());
+    MakePlainGlobalReferenceBodyFunction("f32_func", "wg_f32", ty.f32(), {});
 
-  MakeCallerBodyFunction("ep_func", {"f32_func"},
-                         ast::AttributeList{
-                             Stage(ast::PipelineStage::kCompute),
-                             WorkgroupSize(1),
-                         });
+    MakeCallerBodyFunction("ep_func", {"f32_func"},
+                           ast::AttributeList{
+                               Stage(ast::PipelineStage::kCompute),
+                               WorkgroupSize(1_i),
+                           });
 
-  Inspector& inspector = Build();
-  EXPECT_EQ(4u, inspector.GetWorkgroupStorageSize("ep_func"));
+    Inspector& inspector = Build();
+    EXPECT_EQ(4u, inspector.GetWorkgroupStorageSize("ep_func"));
 }
 
 TEST_F(InspectorGetWorkgroupStorageSizeTest, CompoundTypes) {
-  // This struct should occupy 68 bytes. 4 from the i32 field, and another 64
-  // from the 4-element array with 16-byte stride.
-  auto* wg_struct_type = MakeStructType(
-      "WgStruct", {ty.i32(), ty.array(ty.i32(), 4, /*stride=*/16)});
-  AddWorkgroupStorage("wg_struct_var", ty.Of(wg_struct_type));
-  MakeStructVariableReferenceBodyFunction("wg_struct_func", "wg_struct_var",
-                                          {{0, ty.i32()}});
+    // This struct should occupy 68 bytes. 4 from the i32 field, and another 64
+    // from the 4-element array with 16-byte stride.
+    auto* wg_struct_type =
+        MakeStructType("WgStruct", {ty.i32(), ty.array(ty.i32(), 4_u, /*stride=*/16)});
+    AddWorkgroupStorage("wg_struct_var", ty.Of(wg_struct_type));
+    MakeStructVariableReferenceBodyFunction("wg_struct_func", "wg_struct_var", {{0, ty.i32()}});
 
-  // Plus another 4 bytes from this other workgroup-class f32.
-  AddWorkgroupStorage("wg_f32", ty.f32());
-  MakePlainGlobalReferenceBodyFunction("f32_func", "wg_f32", ty.f32(), {});
+    // Plus another 4 bytes from this other workgroup-class f32.
+    AddWorkgroupStorage("wg_f32", ty.f32());
+    MakePlainGlobalReferenceBodyFunction("f32_func", "wg_f32", ty.f32(), {});
 
-  MakeCallerBodyFunction("ep_func", {"wg_struct_func", "f32_func"},
-                         ast::AttributeList{
-                             Stage(ast::PipelineStage::kCompute),
-                             WorkgroupSize(1),
-                         });
+    MakeCallerBodyFunction("ep_func", {"wg_struct_func", "f32_func"},
+                           ast::AttributeList{
+                               Stage(ast::PipelineStage::kCompute),
+                               WorkgroupSize(1_i),
+                           });
 
-  Inspector& inspector = Build();
-  EXPECT_EQ(72u, inspector.GetWorkgroupStorageSize("ep_func"));
+    Inspector& inspector = Build();
+    EXPECT_EQ(72u, inspector.GetWorkgroupStorageSize("ep_func"));
 }
 
 TEST_F(InspectorGetWorkgroupStorageSizeTest, AlignmentPadding) {
-  // vec3<f32> has an alignment of 16 but a size of 12. We leverage this to test
-  // that our padded size calculation for workgroup storage is accurate.
-  AddWorkgroupStorage("wg_vec3", ty.vec3<f32>());
-  MakePlainGlobalReferenceBodyFunction("wg_func", "wg_vec3", ty.vec3<f32>(),
-                                       {});
+    // vec3<f32> has an alignment of 16 but a size of 12. We leverage this to test
+    // that our padded size calculation for workgroup storage is accurate.
+    AddWorkgroupStorage("wg_vec3", ty.vec3<f32>());
+    MakePlainGlobalReferenceBodyFunction("wg_func", "wg_vec3", ty.vec3<f32>(), {});
 
-  MakeCallerBodyFunction("ep_func", {"wg_func"},
-                         ast::AttributeList{
-                             Stage(ast::PipelineStage::kCompute),
-                             WorkgroupSize(1),
-                         });
+    MakeCallerBodyFunction("ep_func", {"wg_func"},
+                           ast::AttributeList{
+                               Stage(ast::PipelineStage::kCompute),
+                               WorkgroupSize(1_i),
+                           });
 
-  Inspector& inspector = Build();
-  EXPECT_EQ(16u, inspector.GetWorkgroupStorageSize("ep_func"));
+    Inspector& inspector = Build();
+    EXPECT_EQ(16u, inspector.GetWorkgroupStorageSize("ep_func"));
 }
 
 TEST_F(InspectorGetWorkgroupStorageSizeTest, StructAlignment) {
-  // Per WGSL spec, a struct's size is the offset its last member plus the size
-  // of its last member, rounded up to the alignment of its largest member. So
-  // here the struct is expected to occupy 1024 bytes of workgroup storage.
-  const auto* wg_struct_type = MakeStructTypeFromMembers(
-      "WgStruct",
-      {MakeStructMember(0, ty.f32(),
-                        {create<ast::StructMemberAlignAttribute>(1024)})});
+    // Per WGSL spec, a struct's size is the offset its last member plus the size
+    // of its last member, rounded up to the alignment of its largest member. So
+    // here the struct is expected to occupy 1024 bytes of workgroup storage.
+    const auto* wg_struct_type = MakeStructTypeFromMembers(
+        "WgStruct",
+        {MakeStructMember(0, ty.f32(), {create<ast::StructMemberAlignAttribute>(1024)})});
 
-  AddWorkgroupStorage("wg_struct_var", ty.Of(wg_struct_type));
-  MakeStructVariableReferenceBodyFunction("wg_struct_func", "wg_struct_var",
-                                          {{0, ty.f32()}});
+    AddWorkgroupStorage("wg_struct_var", ty.Of(wg_struct_type));
+    MakeStructVariableReferenceBodyFunction("wg_struct_func", "wg_struct_var", {{0, ty.f32()}});
 
-  MakeCallerBodyFunction("ep_func", {"wg_struct_func"},
-                         ast::AttributeList{
-                             Stage(ast::PipelineStage::kCompute),
-                             WorkgroupSize(1),
-                         });
+    MakeCallerBodyFunction("ep_func", {"wg_struct_func"},
+                           ast::AttributeList{
+                               Stage(ast::PipelineStage::kCompute),
+                               WorkgroupSize(1_i),
+                           });
 
-  Inspector& inspector = Build();
-  EXPECT_EQ(1024u, inspector.GetWorkgroupStorageSize("ep_func"));
+    Inspector& inspector = Build();
+    EXPECT_EQ(1024u, inspector.GetWorkgroupStorageSize("ep_func"));
+}
+
+// Test calling GetUsedExtensionNames on a empty shader.
+TEST_F(InspectorGetUsedExtensionNamesTest, Empty) {
+    std::string shader = "";
+
+    Inspector& inspector = Initialize(shader);
+
+    auto result = inspector.GetUsedExtensionNames();
+    EXPECT_EQ(result.size(), 0u);
+}
+
+// Test calling GetUsedExtensionNames on a shader with no extension.
+TEST_F(InspectorGetUsedExtensionNamesTest, None) {
+    std::string shader = R"(
+@stage(fragment)
+fn main() {
+})";
+
+    Inspector& inspector = Initialize(shader);
+
+    auto result = inspector.GetUsedExtensionNames();
+    EXPECT_EQ(result.size(), 0u);
+}
+
+// Test calling GetUsedExtensionNames on a shader with valid extension.
+TEST_F(InspectorGetUsedExtensionNamesTest, Simple) {
+    std::string shader = R"(
+enable InternalExtensionForTesting;
+
+@stage(fragment)
+fn main() {
+})";
+
+    Inspector& inspector = Initialize(shader);
+
+    auto result = inspector.GetUsedExtensionNames();
+    EXPECT_EQ(result.size(), 1u);
+    EXPECT_EQ(result[0], "InternalExtensionForTesting");
+}
+
+// Test calling GetUsedExtensionNames on a shader with a extension enabled for
+// multiple times.
+TEST_F(InspectorGetUsedExtensionNamesTest, Duplicated) {
+    std::string shader = R"(
+enable InternalExtensionForTesting;
+enable InternalExtensionForTesting;
+
+@stage(fragment)
+fn main() {
+})";
+
+    Inspector& inspector = Initialize(shader);
+
+    auto result = inspector.GetUsedExtensionNames();
+    EXPECT_EQ(result.size(), 1u);
+    EXPECT_EQ(result[0], "InternalExtensionForTesting");
+}
+
+// Test calling GetEnableDirectives on a empty shader.
+TEST_F(InspectorGetEnableDirectivesTest, Empty) {
+    std::string shader = "";
+
+    Inspector& inspector = Initialize(shader);
+
+    auto result = inspector.GetEnableDirectives();
+    EXPECT_EQ(result.size(), 0u);
+}
+
+// Test calling GetEnableDirectives on a shader with no extension.
+TEST_F(InspectorGetEnableDirectivesTest, None) {
+    std::string shader = R"(
+@stage(fragment)
+fn main() {
+})";
+
+    Inspector& inspector = Initialize(shader);
+
+    auto result = inspector.GetEnableDirectives();
+    EXPECT_EQ(result.size(), 0u);
+}
+
+// Test calling GetEnableDirectives on a shader with valid extension.
+TEST_F(InspectorGetEnableDirectivesTest, Simple) {
+    std::string shader = R"(
+enable InternalExtensionForTesting;
+
+@stage(fragment)
+fn main() {
+})";
+
+    Inspector& inspector = Initialize(shader);
+
+    auto result = inspector.GetEnableDirectives();
+    EXPECT_EQ(result.size(), 1u);
+    EXPECT_EQ(result[0].first, "InternalExtensionForTesting");
+    EXPECT_EQ(result[0].second.range, (Source::Range{{2, 8}, {2, 35}}));
+}
+
+// Test calling GetEnableDirectives on a shader with a extension enabled for
+// multiple times.
+TEST_F(InspectorGetEnableDirectivesTest, Duplicated) {
+    std::string shader = R"(
+enable InternalExtensionForTesting;
+
+enable InternalExtensionForTesting;
+@stage(fragment)
+fn main() {
+})";
+
+    Inspector& inspector = Initialize(shader);
+
+    auto result = inspector.GetEnableDirectives();
+    EXPECT_EQ(result.size(), 2u);
+    EXPECT_EQ(result[0].first, "InternalExtensionForTesting");
+    EXPECT_EQ(result[0].second.range, (Source::Range{{2, 8}, {2, 35}}));
+    EXPECT_EQ(result[1].first, "InternalExtensionForTesting");
+    EXPECT_EQ(result[1].second.range, (Source::Range{{4, 8}, {4, 35}}));
 }
 
 // Crash was occuring in ::GenerateSamplerTargets, when
 // ::GetSamplerTextureUses was called.
 TEST_F(InspectorRegressionTest, tint967) {
-  std::string shader = R"(
+    std::string shader = R"(
 @group(0) @binding(1) var mySampler: sampler;
 @group(0) @binding(2) var myTexture: texture_2d<f32>;
 
@@ -3021,8 +2958,8 @@
   return doSample(myTexture, mySampler, fragUV) * fragPosition;
 })";
 
-  Inspector& inspector = Initialize(shader);
-  auto result = inspector.GetSamplerTextureUses("main");
+    Inspector& inspector = Initialize(shader);
+    auto result = inspector.GetSamplerTextureUses("main");
 }
 
 }  // namespace
diff --git a/src/tint/inspector/resource_binding.cc b/src/tint/inspector/resource_binding.cc
index 5095e2d..3efb59e 100644
--- a/src/tint/inspector/resource_binding.cc
+++ b/src/tint/inspector/resource_binding.cc
@@ -15,100 +15,99 @@
 #include "src/tint/inspector/resource_binding.h"
 
 #include "src/tint/sem/array.h"
-#include "src/tint/sem/f32_type.h"
-#include "src/tint/sem/i32_type.h"
-#include "src/tint/sem/matrix_type.h"
+#include "src/tint/sem/f32.h"
+#include "src/tint/sem/i32.h"
+#include "src/tint/sem/matrix.h"
 #include "src/tint/sem/type.h"
-#include "src/tint/sem/u32_type.h"
-#include "src/tint/sem/vector_type.h"
+#include "src/tint/sem/u32.h"
+#include "src/tint/sem/vector.h"
 
 namespace tint::inspector {
 
-ResourceBinding::TextureDimension
-TypeTextureDimensionToResourceBindingTextureDimension(
+ResourceBinding::TextureDimension TypeTextureDimensionToResourceBindingTextureDimension(
     const ast::TextureDimension& type_dim) {
-  switch (type_dim) {
-    case ast::TextureDimension::k1d:
-      return ResourceBinding::TextureDimension::k1d;
-    case ast::TextureDimension::k2d:
-      return ResourceBinding::TextureDimension::k2d;
-    case ast::TextureDimension::k2dArray:
-      return ResourceBinding::TextureDimension::k2dArray;
-    case ast::TextureDimension::k3d:
-      return ResourceBinding::TextureDimension::k3d;
-    case ast::TextureDimension::kCube:
-      return ResourceBinding::TextureDimension::kCube;
-    case ast::TextureDimension::kCubeArray:
-      return ResourceBinding::TextureDimension::kCubeArray;
-    case ast::TextureDimension::kNone:
-      return ResourceBinding::TextureDimension::kNone;
-  }
-  return ResourceBinding::TextureDimension::kNone;
+    switch (type_dim) {
+        case ast::TextureDimension::k1d:
+            return ResourceBinding::TextureDimension::k1d;
+        case ast::TextureDimension::k2d:
+            return ResourceBinding::TextureDimension::k2d;
+        case ast::TextureDimension::k2dArray:
+            return ResourceBinding::TextureDimension::k2dArray;
+        case ast::TextureDimension::k3d:
+            return ResourceBinding::TextureDimension::k3d;
+        case ast::TextureDimension::kCube:
+            return ResourceBinding::TextureDimension::kCube;
+        case ast::TextureDimension::kCubeArray:
+            return ResourceBinding::TextureDimension::kCubeArray;
+        case ast::TextureDimension::kNone:
+            return ResourceBinding::TextureDimension::kNone;
+    }
+    return ResourceBinding::TextureDimension::kNone;
 }
 
 ResourceBinding::SampledKind BaseTypeToSampledKind(const sem::Type* base_type) {
-  if (!base_type) {
-    return ResourceBinding::SampledKind::kUnknown;
-  }
+    if (!base_type) {
+        return ResourceBinding::SampledKind::kUnknown;
+    }
 
-  if (auto* at = base_type->As<sem::Array>()) {
-    base_type = at->ElemType();
-  } else if (auto* mt = base_type->As<sem::Matrix>()) {
-    base_type = mt->type();
-  } else if (auto* vt = base_type->As<sem::Vector>()) {
-    base_type = vt->type();
-  }
+    if (auto* at = base_type->As<sem::Array>()) {
+        base_type = at->ElemType();
+    } else if (auto* mt = base_type->As<sem::Matrix>()) {
+        base_type = mt->type();
+    } else if (auto* vt = base_type->As<sem::Vector>()) {
+        base_type = vt->type();
+    }
 
-  if (base_type->Is<sem::F32>()) {
-    return ResourceBinding::SampledKind::kFloat;
-  } else if (base_type->Is<sem::U32>()) {
-    return ResourceBinding::SampledKind::kUInt;
-  } else if (base_type->Is<sem::I32>()) {
-    return ResourceBinding::SampledKind::kSInt;
-  } else {
-    return ResourceBinding::SampledKind::kUnknown;
-  }
+    if (base_type->Is<sem::F32>()) {
+        return ResourceBinding::SampledKind::kFloat;
+    } else if (base_type->Is<sem::U32>()) {
+        return ResourceBinding::SampledKind::kUInt;
+    } else if (base_type->Is<sem::I32>()) {
+        return ResourceBinding::SampledKind::kSInt;
+    } else {
+        return ResourceBinding::SampledKind::kUnknown;
+    }
 }
 
 ResourceBinding::TexelFormat TypeTexelFormatToResourceBindingTexelFormat(
     const ast::TexelFormat& image_format) {
-  switch (image_format) {
-    case ast::TexelFormat::kR32Uint:
-      return ResourceBinding::TexelFormat::kR32Uint;
-    case ast::TexelFormat::kR32Sint:
-      return ResourceBinding::TexelFormat::kR32Sint;
-    case ast::TexelFormat::kR32Float:
-      return ResourceBinding::TexelFormat::kR32Float;
-    case ast::TexelFormat::kRgba8Unorm:
-      return ResourceBinding::TexelFormat::kRgba8Unorm;
-    case ast::TexelFormat::kRgba8Snorm:
-      return ResourceBinding::TexelFormat::kRgba8Snorm;
-    case ast::TexelFormat::kRgba8Uint:
-      return ResourceBinding::TexelFormat::kRgba8Uint;
-    case ast::TexelFormat::kRgba8Sint:
-      return ResourceBinding::TexelFormat::kRgba8Sint;
-    case ast::TexelFormat::kRg32Uint:
-      return ResourceBinding::TexelFormat::kRg32Uint;
-    case ast::TexelFormat::kRg32Sint:
-      return ResourceBinding::TexelFormat::kRg32Sint;
-    case ast::TexelFormat::kRg32Float:
-      return ResourceBinding::TexelFormat::kRg32Float;
-    case ast::TexelFormat::kRgba16Uint:
-      return ResourceBinding::TexelFormat::kRgba16Uint;
-    case ast::TexelFormat::kRgba16Sint:
-      return ResourceBinding::TexelFormat::kRgba16Sint;
-    case ast::TexelFormat::kRgba16Float:
-      return ResourceBinding::TexelFormat::kRgba16Float;
-    case ast::TexelFormat::kRgba32Uint:
-      return ResourceBinding::TexelFormat::kRgba32Uint;
-    case ast::TexelFormat::kRgba32Sint:
-      return ResourceBinding::TexelFormat::kRgba32Sint;
-    case ast::TexelFormat::kRgba32Float:
-      return ResourceBinding::TexelFormat::kRgba32Float;
-    case ast::TexelFormat::kNone:
-      return ResourceBinding::TexelFormat::kNone;
-  }
-  return ResourceBinding::TexelFormat::kNone;
+    switch (image_format) {
+        case ast::TexelFormat::kR32Uint:
+            return ResourceBinding::TexelFormat::kR32Uint;
+        case ast::TexelFormat::kR32Sint:
+            return ResourceBinding::TexelFormat::kR32Sint;
+        case ast::TexelFormat::kR32Float:
+            return ResourceBinding::TexelFormat::kR32Float;
+        case ast::TexelFormat::kRgba8Unorm:
+            return ResourceBinding::TexelFormat::kRgba8Unorm;
+        case ast::TexelFormat::kRgba8Snorm:
+            return ResourceBinding::TexelFormat::kRgba8Snorm;
+        case ast::TexelFormat::kRgba8Uint:
+            return ResourceBinding::TexelFormat::kRgba8Uint;
+        case ast::TexelFormat::kRgba8Sint:
+            return ResourceBinding::TexelFormat::kRgba8Sint;
+        case ast::TexelFormat::kRg32Uint:
+            return ResourceBinding::TexelFormat::kRg32Uint;
+        case ast::TexelFormat::kRg32Sint:
+            return ResourceBinding::TexelFormat::kRg32Sint;
+        case ast::TexelFormat::kRg32Float:
+            return ResourceBinding::TexelFormat::kRg32Float;
+        case ast::TexelFormat::kRgba16Uint:
+            return ResourceBinding::TexelFormat::kRgba16Uint;
+        case ast::TexelFormat::kRgba16Sint:
+            return ResourceBinding::TexelFormat::kRgba16Sint;
+        case ast::TexelFormat::kRgba16Float:
+            return ResourceBinding::TexelFormat::kRgba16Float;
+        case ast::TexelFormat::kRgba32Uint:
+            return ResourceBinding::TexelFormat::kRgba32Uint;
+        case ast::TexelFormat::kRgba32Sint:
+            return ResourceBinding::TexelFormat::kRgba32Sint;
+        case ast::TexelFormat::kRgba32Float:
+            return ResourceBinding::TexelFormat::kRgba32Float;
+        case ast::TexelFormat::kNone:
+            return ResourceBinding::TexelFormat::kNone;
+    }
+    return ResourceBinding::TexelFormat::kNone;
 }
 
 }  // namespace tint::inspector
diff --git a/src/tint/inspector/resource_binding.h b/src/tint/inspector/resource_binding.h
index 1801b85..9a54435 100644
--- a/src/tint/inspector/resource_binding.h
+++ b/src/tint/inspector/resource_binding.h
@@ -24,90 +24,89 @@
 
 /// Container for information about how a resource is bound
 struct ResourceBinding {
-  /// The dimensionality of a texture
-  enum class TextureDimension {
-    /// Invalid texture
-    kNone = -1,
-    /// 1 dimensional texture
-    k1d,
-    /// 2 dimensional texture
-    k2d,
-    /// 2 dimensional array texture
-    k2dArray,
-    /// 3 dimensional texture
-    k3d,
-    /// cube texture
-    kCube,
-    /// cube array texture
-    kCubeArray,
-  };
+    /// The dimensionality of a texture
+    enum class TextureDimension {
+        /// Invalid texture
+        kNone = -1,
+        /// 1 dimensional texture
+        k1d,
+        /// 2 dimensional texture
+        k2d,
+        /// 2 dimensional array texture
+        k2dArray,
+        /// 3 dimensional texture
+        k3d,
+        /// cube texture
+        kCube,
+        /// cube array texture
+        kCubeArray,
+    };
 
-  /// Component type of the texture's data. Same as the Sampled Type parameter
-  /// in SPIR-V OpTypeImage.
-  enum class SampledKind { kUnknown = -1, kFloat, kUInt, kSInt };
+    /// Component type of the texture's data. Same as the Sampled Type parameter
+    /// in SPIR-V OpTypeImage.
+    enum class SampledKind { kUnknown = -1, kFloat, kUInt, kSInt };
 
-  /// Enumerator of texel image formats
-  enum class TexelFormat {
-    kNone = -1,
+    /// Enumerator of texel image formats
+    enum class TexelFormat {
+        kNone = -1,
 
-    kRgba8Unorm,
-    kRgba8Snorm,
-    kRgba8Uint,
-    kRgba8Sint,
-    kRgba16Uint,
-    kRgba16Sint,
-    kRgba16Float,
-    kR32Uint,
-    kR32Sint,
-    kR32Float,
-    kRg32Uint,
-    kRg32Sint,
-    kRg32Float,
-    kRgba32Uint,
-    kRgba32Sint,
-    kRgba32Float,
-  };
+        kRgba8Unorm,
+        kRgba8Snorm,
+        kRgba8Uint,
+        kRgba8Sint,
+        kRgba16Uint,
+        kRgba16Sint,
+        kRgba16Float,
+        kR32Uint,
+        kR32Sint,
+        kR32Float,
+        kRg32Uint,
+        kRg32Sint,
+        kRg32Float,
+        kRgba32Uint,
+        kRgba32Sint,
+        kRgba32Float,
+    };
 
-  /// kXXX maps to entries returned by GetXXXResourceBindings call.
-  enum class ResourceType {
-    kUniformBuffer,
-    kStorageBuffer,
-    kReadOnlyStorageBuffer,
-    kSampler,
-    kComparisonSampler,
-    kSampledTexture,
-    kMultisampledTexture,
-    kWriteOnlyStorageTexture,
-    kDepthTexture,
-    kDepthMultisampledTexture,
-    kExternalTexture
-  };
+    /// kXXX maps to entries returned by GetXXXResourceBindings call.
+    enum class ResourceType {
+        kUniformBuffer,
+        kStorageBuffer,
+        kReadOnlyStorageBuffer,
+        kSampler,
+        kComparisonSampler,
+        kSampledTexture,
+        kMultisampledTexture,
+        kWriteOnlyStorageTexture,
+        kDepthTexture,
+        kDepthMultisampledTexture,
+        kExternalTexture
+    };
 
-  /// Type of resource that is bound.
-  ResourceType resource_type;
-  /// Bind group the binding belongs
-  uint32_t bind_group;
-  /// Identifier to identify this binding within the bind group
-  uint32_t binding;
-  /// Size for this binding, in bytes, if defined.
-  uint64_t size;
-  /// Size for this binding without trailing structure padding, in bytes, if
-  /// defined.
-  uint64_t size_no_padding;
-  /// Dimensionality of this binding, if defined.
-  TextureDimension dim;
-  /// Kind of data being sampled, if defined.
-  SampledKind sampled_kind;
-  /// Format of data, if defined.
-  TexelFormat image_format;
+    /// Type of resource that is bound.
+    ResourceType resource_type;
+    /// Bind group the binding belongs
+    uint32_t bind_group;
+    /// Identifier to identify this binding within the bind group
+    uint32_t binding;
+    /// Size for this binding, in bytes, if defined.
+    uint64_t size;
+    /// Size for this binding without trailing structure padding, in bytes, if
+    /// defined.
+    uint64_t size_no_padding;
+    /// Dimensionality of this binding, if defined.
+    TextureDimension dim;
+    /// Kind of data being sampled, if defined.
+    SampledKind sampled_kind;
+    /// Format of data, if defined.
+    TexelFormat image_format;
 };
 
 /// Convert from internal ast::TextureDimension to public
 /// ResourceBinding::TextureDimension
 /// @param type_dim internal value to convert from
 /// @returns the publicly visible equivalent
-ResourceBinding::TextureDimension
-TypeTextureDimensionToResourceBindingTextureDimension(
+ResourceBinding::TextureDimension TypeTextureDimensionToResourceBindingTextureDimension(
     const ast::TextureDimension& type_dim);
 
 /// Infer ResourceBinding::SampledKind for a given sem::Type
diff --git a/src/tint/inspector/scalar.cc b/src/tint/inspector/scalar.cc
index a08ce76..b0b139f 100644
--- a/src/tint/inspector/scalar.cc
+++ b/src/tint/inspector/scalar.cc
@@ -19,55 +19,55 @@
 Scalar::Scalar() : type_(kNull) {}
 
 Scalar::Scalar(bool val) : type_(kBool) {
-  value_.b = val;
+    value_.b = val;
 }
 
 Scalar::Scalar(uint32_t val) : type_(kU32) {
-  value_.u = val;
+    value_.u = val;
 }
 
 Scalar::Scalar(int32_t val) : type_(kI32) {
-  value_.i = val;
+    value_.i = val;
 }
 
 Scalar::Scalar(float val) : type_(kFloat) {
-  value_.f = val;
+    value_.f = val;
 }
 
 bool Scalar::IsNull() const {
-  return type_ == kNull;
+    return type_ == kNull;
 }
 
 bool Scalar::IsBool() const {
-  return type_ == kBool;
+    return type_ == kBool;
 }
 
 bool Scalar::IsU32() const {
-  return type_ == kU32;
+    return type_ == kU32;
 }
 
 bool Scalar::IsI32() const {
-  return type_ == kI32;
+    return type_ == kI32;
 }
 
 bool Scalar::IsFloat() const {
-  return type_ == kFloat;
+    return type_ == kFloat;
 }
 
 bool Scalar::AsBool() const {
-  return value_.b;
+    return value_.b;
 }
 
 uint32_t Scalar::AsU32() const {
-  return value_.u;
+    return value_.u;
 }
 
 int32_t Scalar::AsI32() const {
-  return value_.i;
+    return value_.i;
 }
 
 float Scalar::AsFloat() const {
-  return value_.f;
+    return value_.f;
 }
 
 }  // namespace tint::inspector
diff --git a/src/tint/inspector/scalar.h b/src/tint/inspector/scalar.h
index 4c328ee..1470b30 100644
--- a/src/tint/inspector/scalar.h
+++ b/src/tint/inspector/scalar.h
@@ -21,56 +21,56 @@
 
 /// Contains a literal scalar value
 class Scalar {
- public:
-  /// Null Constructor
-  Scalar();
-  /// @param val literal scalar value to contain
-  explicit Scalar(bool val);
-  /// @param val literal scalar value to contain
-  explicit Scalar(uint32_t val);
-  /// @param val literal scalar value to contain
-  explicit Scalar(int32_t val);
-  /// @param val literal scalar value to contain
-  explicit Scalar(float val);
+  public:
+    /// Null Constructor
+    Scalar();
+    /// @param val literal scalar value to contain
+    explicit Scalar(bool val);
+    /// @param val literal scalar value to contain
+    explicit Scalar(uint32_t val);
+    /// @param val literal scalar value to contain
+    explicit Scalar(int32_t val);
+    /// @param val literal scalar value to contain
+    explicit Scalar(float val);
 
-  /// @returns true if this is a null
-  bool IsNull() const;
-  /// @returns true if this is a bool
-  bool IsBool() const;
-  /// @returns true if this is a unsigned integer.
-  bool IsU32() const;
-  /// @returns true if this is a signed integer.
-  bool IsI32() const;
-  /// @returns true if this is a float.
-  bool IsFloat() const;
+    /// @returns true if this is a null
+    bool IsNull() const;
+    /// @returns true if this is a bool
+    bool IsBool() const;
+    /// @returns true if this is a unsigned integer.
+    bool IsU32() const;
+    /// @returns true if this is a signed integer.
+    bool IsI32() const;
+    /// @returns true if this is a float.
+    bool IsFloat() const;
 
-  /// @returns scalar value if bool, otherwise undefined behaviour.
-  bool AsBool() const;
-  /// @returns scalar value if unsigned integer, otherwise undefined behaviour.
-  uint32_t AsU32() const;
-  /// @returns scalar value if signed integer, otherwise undefined behaviour.
-  int32_t AsI32() const;
-  /// @returns scalar value if float, otherwise undefined behaviour.
-  float AsFloat() const;
+    /// @returns scalar value if bool, otherwise undefined behaviour.
+    bool AsBool() const;
+    /// @returns scalar value if unsigned integer, otherwise undefined behaviour.
+    uint32_t AsU32() const;
+    /// @returns scalar value if signed integer, otherwise undefined behaviour.
+    int32_t AsI32() const;
+    /// @returns scalar value if float, otherwise undefined behaviour.
+    float AsFloat() const;
 
- private:
-  typedef enum {
-    kNull,
-    kBool,
-    kU32,
-    kI32,
-    kFloat,
-  } Type;
+  private:
+    typedef enum {
+        kNull,
+        kBool,
+        kU32,
+        kI32,
+        kFloat,
+    } Type;
 
-  typedef union {
-    bool b;
-    uint32_t u;
-    int32_t i;
-    float f;
-  } Value;
+    typedef union {
+        bool b;
+        uint32_t u;
+        int32_t i;
+        float f;
+    } Value;
 
-  Type type_;
-  Value value_;
+    Type type_;
+    Value value_;
 };
 
 }  // namespace tint::inspector
diff --git a/src/tint/inspector/test_inspector_builder.cc b/src/tint/inspector/test_inspector_builder.cc
index 978cc8a..074f29c 100644
--- a/src/tint/inspector/test_inspector_builder.cc
+++ b/src/tint/inspector/test_inspector_builder.cc
@@ -27,37 +27,34 @@
 InspectorBuilder::InspectorBuilder() = default;
 InspectorBuilder::~InspectorBuilder() = default;
 
-void InspectorBuilder::MakeEmptyBodyFunction(std::string name,
-                                             ast::AttributeList attributes) {
-  Func(name, ast::VariableList(), ty.void_(), ast::StatementList{Return()},
-       attributes);
+void InspectorBuilder::MakeEmptyBodyFunction(std::string name, ast::AttributeList attributes) {
+    Func(name, ast::VariableList(), ty.void_(), ast::StatementList{Return()}, attributes);
 }
 
 void InspectorBuilder::MakeCallerBodyFunction(std::string caller,
                                               std::vector<std::string> callees,
                                               ast::AttributeList attributes) {
-  ast::StatementList body;
-  body.reserve(callees.size() + 1);
-  for (auto callee : callees) {
-    body.push_back(CallStmt(Call(callee)));
-  }
-  body.push_back(Return());
+    ast::StatementList body;
+    body.reserve(callees.size() + 1);
+    for (auto callee : callees) {
+        body.push_back(CallStmt(Call(callee)));
+    }
+    body.push_back(Return());
 
-  Func(caller, ast::VariableList(), ty.void_(), body, attributes);
+    Func(caller, ast::VariableList(), ty.void_(), body, attributes);
 }
 
 const ast::Struct* InspectorBuilder::MakeInOutStruct(
     std::string name,
     std::vector<std::tuple<std::string, uint32_t>> inout_vars) {
-  ast::StructMemberList members;
-  for (auto var : inout_vars) {
-    std::string member_name;
-    uint32_t location;
-    std::tie(member_name, location) = var;
-    members.push_back(
-        Member(member_name, ty.u32(), {Location(location), Flat()}));
-  }
-  return Structure(name, members);
+    ast::StructMemberList members;
+    for (auto var : inout_vars) {
+        std::string member_name;
+        uint32_t location;
+        std::tie(member_name, location) = var;
+        members.push_back(Member(member_name, ty.u32(), {Location(location), Flat()}));
+    }
+    return Structure(name, members);
 }
 
 const ast::Function* InspectorBuilder::MakePlainGlobalReferenceBodyFunction(
@@ -65,79 +62,74 @@
     std::string var,
     const ast::Type* type,
     ast::AttributeList attributes) {
-  ast::StatementList stmts;
-  stmts.emplace_back(Decl(Var("local_" + var, type)));
-  stmts.emplace_back(Assign("local_" + var, var));
-  stmts.emplace_back(Return());
+    ast::StatementList stmts;
+    stmts.emplace_back(Decl(Var("local_" + var, type)));
+    stmts.emplace_back(Assign("local_" + var, var));
+    stmts.emplace_back(Return());
 
-  return Func(func, ast::VariableList(), ty.void_(), stmts, attributes);
+    return Func(func, ast::VariableList(), ty.void_(), stmts, attributes);
 }
 
 bool InspectorBuilder::ContainsName(const std::vector<StageVariable>& vec,
                                     const std::string& name) {
-  for (auto& s : vec) {
-    if (s.name == name) {
-      return true;
+    for (auto& s : vec) {
+        if (s.name == name) {
+            return true;
+        }
     }
-  }
-  return false;
+    return false;
 }
 
-std::string InspectorBuilder::StructMemberName(size_t idx,
-                                               const ast::Type* type) {
-  return std::to_string(idx) + type->FriendlyName(Symbols());
+std::string InspectorBuilder::StructMemberName(size_t idx, const ast::Type* type) {
+    return std::to_string(idx) + type->FriendlyName(Symbols());
 }
 
-const ast::Struct* InspectorBuilder::MakeStructType(
-    const std::string& name,
-    std::vector<const ast::Type*> member_types) {
-  ast::StructMemberList members;
-  for (auto* type : member_types) {
-    members.push_back(MakeStructMember(members.size(), type, {}));
-  }
-  return MakeStructTypeFromMembers(name, std::move(members));
+const ast::Struct* InspectorBuilder::MakeStructType(const std::string& name,
+                                                    std::vector<const ast::Type*> member_types) {
+    ast::StructMemberList members;
+    for (auto* type : member_types) {
+        members.push_back(MakeStructMember(members.size(), type, {}));
+    }
+    return MakeStructTypeFromMembers(name, std::move(members));
 }
 
-const ast::Struct* InspectorBuilder::MakeStructTypeFromMembers(
-    const std::string& name,
-    ast::StructMemberList members) {
-  return Structure(name, std::move(members));
+const ast::Struct* InspectorBuilder::MakeStructTypeFromMembers(const std::string& name,
+                                                               ast::StructMemberList members) {
+    return Structure(name, std::move(members));
 }
 
-const ast::StructMember* InspectorBuilder::MakeStructMember(
-    size_t index,
-    const ast::Type* type,
-    ast::AttributeList attributes) {
-  return Member(StructMemberName(index, type), type, std::move(attributes));
+const ast::StructMember* InspectorBuilder::MakeStructMember(size_t index,
+                                                            const ast::Type* type,
+                                                            ast::AttributeList attributes) {
+    return Member(StructMemberName(index, type), type, std::move(attributes));
 }
 
 const ast::Struct* InspectorBuilder::MakeUniformBufferType(
     const std::string& name,
     std::vector<const ast::Type*> member_types) {
-  return MakeStructType(name, member_types);
+    return MakeStructType(name, member_types);
 }
 
 std::function<const ast::TypeName*()> InspectorBuilder::MakeStorageBufferTypes(
     const std::string& name,
     std::vector<const ast::Type*> member_types) {
-  MakeStructType(name, member_types);
-  return [this, name] { return ty.type_name(name); };
+    MakeStructType(name, member_types);
+    return [this, name] { return ty.type_name(name); };
 }
 
 void InspectorBuilder::AddUniformBuffer(const std::string& name,
                                         const ast::Type* type,
                                         uint32_t group,
                                         uint32_t binding) {
-  Global(name, type, ast::StorageClass::kUniform,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(binding),
-             create<ast::GroupAttribute>(group),
-         });
+    Global(name, type, ast::StorageClass::kUniform,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(binding),
+               create<ast::GroupAttribute>(group),
+           });
 }
 
-void InspectorBuilder::AddWorkgroupStorage(const std::string& name,
-                                           const ast::Type* type) {
-  Global(name, type, ast::StorageClass::kWorkgroup);
+void InspectorBuilder::AddWorkgroupStorage(const std::string& name, const ast::Type* type) {
+    Global(name, type, ast::StorageClass::kWorkgroup);
 }
 
 void InspectorBuilder::AddStorageBuffer(const std::string& name,
@@ -145,76 +137,72 @@
                                         ast::Access access,
                                         uint32_t group,
                                         uint32_t binding) {
-  Global(name, type, ast::StorageClass::kStorage, access,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(binding),
-             create<ast::GroupAttribute>(group),
-         });
+    Global(name, type, ast::StorageClass::kStorage, access,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(binding),
+               create<ast::GroupAttribute>(group),
+           });
 }
 
 void InspectorBuilder::MakeStructVariableReferenceBodyFunction(
     std::string func_name,
     std::string struct_name,
     std::vector<std::tuple<size_t, const ast::Type*>> members) {
-  ast::StatementList stmts;
-  for (auto member : members) {
-    size_t member_idx;
-    const ast::Type* member_type;
-    std::tie(member_idx, member_type) = member;
-    std::string member_name = StructMemberName(member_idx, member_type);
+    ast::StatementList stmts;
+    for (auto member : members) {
+        size_t member_idx;
+        const ast::Type* member_type;
+        std::tie(member_idx, member_type) = member;
+        std::string member_name = StructMemberName(member_idx, member_type);
 
-    stmts.emplace_back(Decl(Var("local" + member_name, member_type)));
-  }
+        stmts.emplace_back(Decl(Var("local" + member_name, member_type)));
+    }
 
-  for (auto member : members) {
-    size_t member_idx;
-    const ast::Type* member_type;
-    std::tie(member_idx, member_type) = member;
-    std::string member_name = StructMemberName(member_idx, member_type);
+    for (auto member : members) {
+        size_t member_idx;
+        const ast::Type* member_type;
+        std::tie(member_idx, member_type) = member;
+        std::string member_name = StructMemberName(member_idx, member_type);
 
-    stmts.emplace_back(Assign("local" + member_name,
-                              MemberAccessor(struct_name, member_name)));
-  }
+        stmts.emplace_back(Assign("local" + member_name, MemberAccessor(struct_name, member_name)));
+    }
 
-  stmts.emplace_back(Return());
+    stmts.emplace_back(Return());
 
-  Func(func_name, ast::VariableList(), ty.void_(), stmts, ast::AttributeList{});
+    Func(func_name, ast::VariableList(), ty.void_(), stmts, ast::AttributeList{});
 }
 
-void InspectorBuilder::AddSampler(const std::string& name,
-                                  uint32_t group,
-                                  uint32_t binding) {
-  Global(name, sampler_type(),
-         ast::AttributeList{
-             create<ast::BindingAttribute>(binding),
-             create<ast::GroupAttribute>(group),
-         });
+void InspectorBuilder::AddSampler(const std::string& name, uint32_t group, uint32_t binding) {
+    Global(name, sampler_type(),
+           ast::AttributeList{
+               create<ast::BindingAttribute>(binding),
+               create<ast::GroupAttribute>(group),
+           });
 }
 
 void InspectorBuilder::AddComparisonSampler(const std::string& name,
                                             uint32_t group,
                                             uint32_t binding) {
-  Global(name, comparison_sampler_type(),
-         ast::AttributeList{
-             create<ast::BindingAttribute>(binding),
-             create<ast::GroupAttribute>(group),
-         });
+    Global(name, comparison_sampler_type(),
+           ast::AttributeList{
+               create<ast::BindingAttribute>(binding),
+               create<ast::GroupAttribute>(group),
+           });
 }
 
 void InspectorBuilder::AddResource(const std::string& name,
                                    const ast::Type* type,
                                    uint32_t group,
                                    uint32_t binding) {
-  Global(name, type,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(binding),
-             create<ast::GroupAttribute>(group),
-         });
+    Global(name, type,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(binding),
+               create<ast::GroupAttribute>(group),
+           });
 }
 
-void InspectorBuilder::AddGlobalVariable(const std::string& name,
-                                         const ast::Type* type) {
-  Global(name, type, ast::StorageClass::kPrivate);
+void InspectorBuilder::AddGlobalVariable(const std::string& name, const ast::Type* type) {
+    Global(name, type, ast::StorageClass::kPrivate);
 }
 
 const ast::Function* InspectorBuilder::MakeSamplerReferenceBodyFunction(
@@ -224,16 +212,16 @@
     const std::string& coords_name,
     const ast::Type* base_type,
     ast::AttributeList attributes) {
-  std::string result_name = "sampler_result";
+    std::string result_name = "sampler_result";
 
-  ast::StatementList stmts;
-  stmts.emplace_back(Decl(Var(result_name, ty.vec(base_type, 4))));
+    ast::StatementList stmts;
+    stmts.emplace_back(Decl(Var(result_name, ty.vec(base_type, 4))));
 
-  stmts.emplace_back(Assign(result_name, Call("textureSample", texture_name,
-                                              sampler_name, coords_name)));
-  stmts.emplace_back(Return());
+    stmts.emplace_back(
+        Assign(result_name, Call("textureSample", texture_name, sampler_name, coords_name)));
+    stmts.emplace_back(Return());
 
-  return Func(func_name, ast::VariableList(), ty.void_(), stmts, attributes);
+    return Func(func_name, ast::VariableList(), ty.void_(), stmts, attributes);
 }
 
 const ast::Function* InspectorBuilder::MakeSamplerReferenceBodyFunction(
@@ -244,22 +232,20 @@
     const std::string& array_index,
     const ast::Type* base_type,
     ast::AttributeList attributes) {
-  std::string result_name = "sampler_result";
+    std::string result_name = "sampler_result";
 
-  ast::StatementList stmts;
+    ast::StatementList stmts;
 
-  stmts.emplace_back(Decl(Var("sampler_result", ty.vec(base_type, 4))));
+    stmts.emplace_back(Decl(Var("sampler_result", ty.vec(base_type, 4))));
 
-  stmts.emplace_back(
-      Assign("sampler_result", Call("textureSample", texture_name, sampler_name,
-                                    coords_name, array_index)));
-  stmts.emplace_back(Return());
+    stmts.emplace_back(Assign("sampler_result", Call("textureSample", texture_name, sampler_name,
+                                                     coords_name, array_index)));
+    stmts.emplace_back(Return());
 
-  return Func(func_name, ast::VariableList(), ty.void_(), stmts, attributes);
+    return Func(func_name, ast::VariableList(), ty.void_(), stmts, attributes);
 }
 
-const ast::Function*
-InspectorBuilder::MakeComparisonSamplerReferenceBodyFunction(
+const ast::Function* InspectorBuilder::MakeComparisonSamplerReferenceBodyFunction(
     const std::string& func_name,
     const std::string& texture_name,
     const std::string& sampler_name,
@@ -267,66 +253,63 @@
     const std::string& depth_name,
     const ast::Type* base_type,
     ast::AttributeList attributes) {
-  std::string result_name = "sampler_result";
+    std::string result_name = "sampler_result";
 
-  ast::StatementList stmts;
+    ast::StatementList stmts;
 
-  stmts.emplace_back(Decl(Var("sampler_result", base_type)));
-  stmts.emplace_back(
-      Assign("sampler_result", Call("textureSampleCompare", texture_name,
-                                    sampler_name, coords_name, depth_name)));
-  stmts.emplace_back(Return());
+    stmts.emplace_back(Decl(Var("sampler_result", base_type)));
+    stmts.emplace_back(Assign("sampler_result", Call("textureSampleCompare", texture_name,
+                                                     sampler_name, coords_name, depth_name)));
+    stmts.emplace_back(Return());
 
-  return Func(func_name, ast::VariableList(), ty.void_(), stmts, attributes);
+    return Func(func_name, ast::VariableList(), ty.void_(), stmts, attributes);
 }
 
-const ast::Type* InspectorBuilder::GetBaseType(
-    ResourceBinding::SampledKind sampled_kind) {
-  switch (sampled_kind) {
-    case ResourceBinding::SampledKind::kFloat:
-      return ty.f32();
-    case ResourceBinding::SampledKind::kSInt:
-      return ty.i32();
-    case ResourceBinding::SampledKind::kUInt:
-      return ty.u32();
-    default:
-      return nullptr;
-  }
+const ast::Type* InspectorBuilder::GetBaseType(ResourceBinding::SampledKind sampled_kind) {
+    switch (sampled_kind) {
+        case ResourceBinding::SampledKind::kFloat:
+            return ty.f32();
+        case ResourceBinding::SampledKind::kSInt:
+            return ty.i32();
+        case ResourceBinding::SampledKind::kUInt:
+            return ty.u32();
+        default:
+            return nullptr;
+    }
 }
 
 const ast::Type* InspectorBuilder::GetCoordsType(ast::TextureDimension dim,
                                                  const ast::Type* scalar) {
-  switch (dim) {
-    case ast::TextureDimension::k1d:
-      return scalar;
-    case ast::TextureDimension::k2d:
-    case ast::TextureDimension::k2dArray:
-      return create<ast::Vector>(scalar, 2);
-    case ast::TextureDimension::k3d:
-    case ast::TextureDimension::kCube:
-    case ast::TextureDimension::kCubeArray:
-      return create<ast::Vector>(scalar, 3);
-    default:
-      [=]() { FAIL() << "Unsupported texture dimension: " << dim; }();
-  }
-  return nullptr;
+    switch (dim) {
+        case ast::TextureDimension::k1d:
+            return scalar;
+        case ast::TextureDimension::k2d:
+        case ast::TextureDimension::k2dArray:
+            return create<ast::Vector>(scalar, 2);
+        case ast::TextureDimension::k3d:
+        case ast::TextureDimension::kCube:
+        case ast::TextureDimension::kCubeArray:
+            return create<ast::Vector>(scalar, 3);
+        default:
+            [=]() { FAIL() << "Unsupported texture dimension: " << dim; }();
+    }
+    return nullptr;
 }
 
-const ast::Type* InspectorBuilder::MakeStorageTextureTypes(
-    ast::TextureDimension dim,
-    ast::TexelFormat format) {
-  return ty.storage_texture(dim, format, ast::Access::kWrite);
+const ast::Type* InspectorBuilder::MakeStorageTextureTypes(ast::TextureDimension dim,
+                                                           ast::TexelFormat format) {
+    return ty.storage_texture(dim, format, ast::Access::kWrite);
 }
 
 void InspectorBuilder::AddStorageTexture(const std::string& name,
                                          const ast::Type* type,
                                          uint32_t group,
                                          uint32_t binding) {
-  Global(name, type,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(binding),
-             create<ast::GroupAttribute>(group),
-         });
+    Global(name, type,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(binding),
+               create<ast::GroupAttribute>(group),
+           });
 }
 
 const ast::Function* InspectorBuilder::MakeStorageTextureBodyFunction(
@@ -334,64 +317,62 @@
     const std::string& st_name,
     const ast::Type* dim_type,
     ast::AttributeList attributes) {
-  ast::StatementList stmts;
+    ast::StatementList stmts;
 
-  stmts.emplace_back(Decl(Var("dim", dim_type)));
-  stmts.emplace_back(Assign("dim", Call("textureDimensions", st_name)));
-  stmts.emplace_back(Return());
+    stmts.emplace_back(Decl(Var("dim", dim_type)));
+    stmts.emplace_back(Assign("dim", Call("textureDimensions", st_name)));
+    stmts.emplace_back(Return());
 
-  return Func(func_name, ast::VariableList(), ty.void_(), stmts, attributes);
+    return Func(func_name, ast::VariableList(), ty.void_(), stmts, attributes);
 }
 
-std::function<const ast::Type*()> InspectorBuilder::GetTypeFunction(
-    ComponentType component,
-    CompositionType composition) {
-  std::function<const ast::Type*()> func;
-  switch (component) {
-    case ComponentType::kFloat:
-      func = [this]() -> const ast::Type* { return ty.f32(); };
-      break;
-    case ComponentType::kSInt:
-      func = [this]() -> const ast::Type* { return ty.i32(); };
-      break;
-    case ComponentType::kUInt:
-      func = [this]() -> const ast::Type* { return ty.u32(); };
-      break;
-    case ComponentType::kUnknown:
-      return []() -> const ast::Type* { return nullptr; };
-  }
+std::function<const ast::Type*()> InspectorBuilder::GetTypeFunction(ComponentType component,
+                                                                    CompositionType composition) {
+    std::function<const ast::Type*()> func;
+    switch (component) {
+        case ComponentType::kFloat:
+            func = [this]() -> const ast::Type* { return ty.f32(); };
+            break;
+        case ComponentType::kSInt:
+            func = [this]() -> const ast::Type* { return ty.i32(); };
+            break;
+        case ComponentType::kUInt:
+            func = [this]() -> const ast::Type* { return ty.u32(); };
+            break;
+        case ComponentType::kUnknown:
+            return []() -> const ast::Type* { return nullptr; };
+    }
 
-  uint32_t n;
-  switch (composition) {
-    case CompositionType::kScalar:
-      return func;
-    case CompositionType::kVec2:
-      n = 2;
-      break;
-    case CompositionType::kVec3:
-      n = 3;
-      break;
-    case CompositionType::kVec4:
-      n = 4;
-      break;
-    default:
-      return []() -> ast::Type* { return nullptr; };
-  }
+    uint32_t n;
+    switch (composition) {
+        case CompositionType::kScalar:
+            return func;
+        case CompositionType::kVec2:
+            n = 2;
+            break;
+        case CompositionType::kVec3:
+            n = 3;
+            break;
+        case CompositionType::kVec4:
+            n = 4;
+            break;
+        default:
+            return []() -> ast::Type* { return nullptr; };
+    }
 
-  return [this, func, n]() -> const ast::Type* { return ty.vec(func(), n); };
+    return [this, func, n]() -> const ast::Type* { return ty.vec(func(), n); };
 }
 
 Inspector& InspectorBuilder::Build() {
-  if (inspector_) {
+    if (inspector_) {
+        return *inspector_;
+    }
+    program_ = std::make_unique<Program>(std::move(*this));
+    [&]() {
+        ASSERT_TRUE(program_->IsValid()) << diag::Formatter().format(program_->Diagnostics());
+    }();
+    inspector_ = std::make_unique<Inspector>(program_.get());
     return *inspector_;
-  }
-  program_ = std::make_unique<Program>(std::move(*this));
-  [&]() {
-    ASSERT_TRUE(program_->IsValid())
-        << diag::Formatter().format(program_->Diagnostics());
-  }();
-  inspector_ = std::make_unique<Inspector>(program_.get());
-  return *inspector_;
 }
 
 }  // namespace tint::inspector
diff --git a/src/tint/inspector/test_inspector_builder.h b/src/tint/inspector/test_inspector_builder.h
index 97a2ae3..391e1a1 100644
--- a/src/tint/inspector/test_inspector_builder.h
+++ b/src/tint/inspector/test_inspector_builder.h
@@ -26,10 +26,10 @@
 #include "src/tint/ast/stage_attribute.h"
 #include "src/tint/ast/workgroup_attribute.h"
 #include "src/tint/program_builder.h"
-#include "src/tint/sem/depth_texture_type.h"
-#include "src/tint/sem/external_texture_type.h"
-#include "src/tint/sem/multisampled_texture_type.h"
-#include "src/tint/sem/sampled_texture_type.h"
+#include "src/tint/sem/depth_texture.h"
+#include "src/tint/sem/external_texture.h"
+#include "src/tint/sem/multisampled_texture.h"
+#include "src/tint/sem/sampled_texture.h"
 #include "src/tint/sem/variable.h"
 #include "tint/tint.h"
 
@@ -37,346 +37,327 @@
 
 /// Utility class for building programs in inspector tests
 class InspectorBuilder : public ProgramBuilder {
- public:
-  InspectorBuilder();
-  ~InspectorBuilder() override;
+  public:
+    InspectorBuilder();
+    ~InspectorBuilder() override;
 
-  /// Generates an empty function
-  /// @param name name of the function created
-  /// @param attributes the function attributes
-  void MakeEmptyBodyFunction(std::string name, ast::AttributeList attributes);
+    /// Generates an empty function
+    /// @param name name of the function created
+    /// @param attributes the function attributes
+    void MakeEmptyBodyFunction(std::string name, ast::AttributeList attributes);
 
-  /// Generates a function that calls other functions
-  /// @param caller name of the function created
-  /// @param callees names of the functions to be called
-  /// @param attributes the function attributes
-  void MakeCallerBodyFunction(std::string caller,
-                              std::vector<std::string> callees,
-                              ast::AttributeList attributes);
+    /// Generates a function that calls other functions
+    /// @param caller name of the function created
+    /// @param callees names of the functions to be called
+    /// @param attributes the function attributes
+    void MakeCallerBodyFunction(std::string caller,
+                                std::vector<std::string> callees,
+                                ast::AttributeList attributes);
 
-  /// Generates a struct that contains user-defined IO members
-  /// @param name the name of the generated struct
-  /// @param inout_vars tuples of {name, loc} that will be the struct members
-  /// @returns a structure object
-  const ast::Struct* MakeInOutStruct(
-      std::string name,
-      std::vector<std::tuple<std::string, uint32_t>> inout_vars);
+    /// Generates a struct that contains user-defined IO members
+    /// @param name the name of the generated struct
+    /// @param inout_vars tuples of {name, loc} that will be the struct members
+    /// @returns a structure object
+    const ast::Struct* MakeInOutStruct(std::string name,
+                                       std::vector<std::tuple<std::string, uint32_t>> inout_vars);
 
-  // TODO(crbug.com/tint/697): Remove this.
-  /// Add In/Out variables to the global variables
-  /// @param inout_vars tuples of {in, out} that will be added as entries to the
-  ///                   global variables
-  void AddInOutVariables(
-      std::vector<std::tuple<std::string, std::string>> inout_vars);
+    // TODO(crbug.com/tint/697): Remove this.
+    /// Add In/Out variables to the global variables
+    /// @param inout_vars tuples of {in, out} that will be added as entries to the
+    ///                   global variables
+    void AddInOutVariables(std::vector<std::tuple<std::string, std::string>> inout_vars);
 
-  // TODO(crbug.com/tint/697): Remove this.
-  /// Generates a function that references in/out variables
-  /// @param name name of the function created
-  /// @param inout_vars tuples of {in, out} that will be converted into out = in
-  ///                   calls in the function body
-  /// @param attributes the function attributes
-  void MakeInOutVariableBodyFunction(
-      std::string name,
-      std::vector<std::tuple<std::string, std::string>> inout_vars,
-      ast::AttributeList attributes);
+    // TODO(crbug.com/tint/697): Remove this.
+    /// Generates a function that references in/out variables
+    /// @param name name of the function created
+    /// @param inout_vars tuples of {in, out} that will be converted into out = in
+    ///                   calls in the function body
+    /// @param attributes the function attributes
+    void MakeInOutVariableBodyFunction(std::string name,
+                                       std::vector<std::tuple<std::string, std::string>> inout_vars,
+                                       ast::AttributeList attributes);
 
-  // TODO(crbug.com/tint/697): Remove this.
-  /// Generates a function that references in/out variables and calls another
-  /// function.
-  /// @param caller name of the function created
-  /// @param callee name of the function to be called
-  /// @param inout_vars tuples of {in, out} that will be converted into out = in
-  ///                   calls in the function body
-  /// @param attributes the function attributes
-  /// @returns a function object
-  const ast::Function* MakeInOutVariableCallerBodyFunction(
-      std::string caller,
-      std::string callee,
-      std::vector<std::tuple<std::string, std::string>> inout_vars,
-      ast::AttributeList attributes);
+    // TODO(crbug.com/tint/697): Remove this.
+    /// Generates a function that references in/out variables and calls another
+    /// function.
+    /// @param caller name of the function created
+    /// @param callee name of the function to be called
+    /// @param inout_vars tuples of {in, out} that will be converted into out = in
+    ///                   calls in the function body
+    /// @param attributes the function attributes
+    /// @returns a function object
+    const ast::Function* MakeInOutVariableCallerBodyFunction(
+        std::string caller,
+        std::string callee,
+        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, 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);
-  }
+    /// 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.
-  /// @param func name of the function created
-  /// @param var name of the constant to be reference
-  /// @param type type of the const being referenced
-  /// @param attributes the function attributes
-  /// @returns a function object
-  const ast::Function* MakePlainGlobalReferenceBodyFunction(
-      std::string func,
-      std::string var,
-      const ast::Type* type,
-      ast::AttributeList attributes);
+    /// Generates a function that references module-scoped, plain-typed constant
+    /// or variable.
+    /// @param func name of the function created
+    /// @param var name of the constant to be reference
+    /// @param type type of the const being referenced
+    /// @param attributes the function attributes
+    /// @returns a function object
+    const ast::Function* MakePlainGlobalReferenceBodyFunction(std::string func,
+                                                              std::string var,
+                                                              const ast::Type* type,
+                                                              ast::AttributeList attributes);
 
-  /// @param vec Vector of StageVariable to be searched
-  /// @param name Name to be searching for
-  /// @returns true if name is in vec, otherwise false
-  bool ContainsName(const std::vector<StageVariable>& vec,
-                    const std::string& name);
+    /// @param vec Vector of StageVariable to be searched
+    /// @param name Name to be searching for
+    /// @returns true if name is in vec, otherwise false
+    bool ContainsName(const std::vector<StageVariable>& vec, const std::string& name);
 
-  /// Builds a string for accessing a member in a generated struct
-  /// @param idx index of member
-  /// @param type type of member
-  /// @returns a string for the member
-  std::string StructMemberName(size_t idx, const ast::Type* type);
+    /// Builds a string for accessing a member in a generated struct
+    /// @param idx index of member
+    /// @param type type of member
+    /// @returns a string for the member
+    std::string StructMemberName(size_t idx, const ast::Type* type);
 
-  /// Generates a struct type
-  /// @param name name for the type
-  /// @param member_types a vector of member types
-  /// @returns a struct type
-  const ast::Struct* MakeStructType(const std::string& name,
-                                    std::vector<const ast::Type*> member_types);
+    /// Generates a struct type
+    /// @param name name for the type
+    /// @param member_types a vector of member types
+    /// @returns a struct type
+    const ast::Struct* MakeStructType(const std::string& name,
+                                      std::vector<const ast::Type*> member_types);
 
-  /// Generates a struct type from a list of member nodes.
-  /// @param name name for the struct type
-  /// @param members a vector of members
-  /// @returns a struct type
-  const ast::Struct* MakeStructTypeFromMembers(const std::string& name,
-                                               ast::StructMemberList members);
+    /// Generates a struct type from a list of member nodes.
+    /// @param name name for the struct type
+    /// @param members a vector of members
+    /// @returns a struct type
+    const ast::Struct* MakeStructTypeFromMembers(const std::string& name,
+                                                 ast::StructMemberList members);
 
-  /// Generates a struct member with a specified index and type.
-  /// @param index index of the field within the struct
-  /// @param type the type of the member field
-  /// @param attributes a list of attributes to apply to the member field
-  /// @returns a struct member
-  const ast::StructMember* MakeStructMember(size_t index,
-                                            const ast::Type* type,
-                                            ast::AttributeList attributes);
+    /// Generates a struct member with a specified index and type.
+    /// @param index index of the field within the struct
+    /// @param type the type of the member field
+    /// @param attributes a list of attributes to apply to the member field
+    /// @returns a struct member
+    const ast::StructMember* MakeStructMember(size_t index,
+                                              const ast::Type* type,
+                                              ast::AttributeList attributes);
 
-  /// Generates types appropriate for using in an uniform buffer
-  /// @param name name for the type
-  /// @param member_types a vector of member types
-  /// @returns a struct type that has the layout for an uniform buffer.
-  const ast::Struct* MakeUniformBufferType(
-      const std::string& name,
-      std::vector<const ast::Type*> member_types);
+    /// Generates types appropriate for using in an uniform buffer
+    /// @param name name for the type
+    /// @param member_types a vector of member types
+    /// @returns a struct type that has the layout for an uniform buffer.
+    const ast::Struct* MakeUniformBufferType(const std::string& name,
+                                             std::vector<const ast::Type*> member_types);
 
-  /// Generates types appropriate for using in a storage buffer
-  /// @param name name for the type
-  /// @param member_types a vector of member types
-  /// @returns a function that returns the created structure.
-  std::function<const ast::TypeName*()> MakeStorageBufferTypes(
-      const std::string& name,
-      std::vector<const ast::Type*> member_types);
+    /// Generates types appropriate for using in a storage buffer
+    /// @param name name for the type
+    /// @param member_types a vector of member types
+    /// @returns a function that returns the created structure.
+    std::function<const ast::TypeName*()> MakeStorageBufferTypes(
+        const std::string& name,
+        std::vector<const ast::Type*> member_types);
 
-  /// Adds an uniform buffer variable to the program
-  /// @param name the name of the variable
-  /// @param type the type to use
-  /// @param group the binding/group/ to use for the uniform buffer
-  /// @param binding the binding number to use for the uniform buffer
-  void AddUniformBuffer(const std::string& name,
-                        const ast::Type* type,
-                        uint32_t group,
-                        uint32_t binding);
+    /// Adds an uniform buffer variable to the program
+    /// @param name the name of the variable
+    /// @param type the type to use
+    /// @param group the binding/group/ to use for the uniform buffer
+    /// @param binding the binding number to use for the uniform buffer
+    void AddUniformBuffer(const std::string& name,
+                          const ast::Type* type,
+                          uint32_t group,
+                          uint32_t binding);
 
-  /// Adds a workgroup storage variable to the program
-  /// @param name the name of the variable
-  /// @param type the type of the variable
-  void AddWorkgroupStorage(const std::string& name, const ast::Type* type);
+    /// Adds a workgroup storage variable to the program
+    /// @param name the name of the variable
+    /// @param type the type of the variable
+    void AddWorkgroupStorage(const std::string& name, const ast::Type* type);
 
-  /// Adds a storage buffer variable to the program
-  /// @param name the name of the variable
-  /// @param type the type to use
-  /// @param access the storage buffer access control
-  /// @param group the binding/group to use for the storage buffer
-  /// @param binding the binding number to use for the storage buffer
-  void AddStorageBuffer(const std::string& name,
-                        const ast::Type* type,
-                        ast::Access access,
-                        uint32_t group,
-                        uint32_t binding);
+    /// Adds a storage buffer variable to the program
+    /// @param name the name of the variable
+    /// @param type the type to use
+    /// @param access the storage buffer access control
+    /// @param group the binding/group to use for the storage buffer
+    /// @param binding the binding number to use for the storage buffer
+    void AddStorageBuffer(const std::string& name,
+                          const ast::Type* type,
+                          ast::Access access,
+                          uint32_t group,
+                          uint32_t binding);
 
-  /// Generates a function that references a specific struct variable
-  /// @param func_name name of the function created
-  /// @param struct_name name of the struct variabler to be accessed
-  /// @param members list of members to access, by index and type
-  void MakeStructVariableReferenceBodyFunction(
-      std::string func_name,
-      std::string struct_name,
-      std::vector<std::tuple<size_t, const ast::Type*>> members);
+    /// Generates a function that references a specific struct variable
+    /// @param func_name name of the function created
+    /// @param struct_name name of the struct variabler to be accessed
+    /// @param members list of members to access, by index and type
+    void MakeStructVariableReferenceBodyFunction(
+        std::string func_name,
+        std::string struct_name,
+        std::vector<std::tuple<size_t, const ast::Type*>> members);
 
-  /// Adds a regular sampler variable to the program
-  /// @param name the name of the variable
-  /// @param group the binding/group to use for the storage buffer
-  /// @param binding the binding number to use for the storage buffer
-  void AddSampler(const std::string& name, uint32_t group, uint32_t binding);
+    /// Adds a regular sampler variable to the program
+    /// @param name the name of the variable
+    /// @param group the binding/group to use for the storage buffer
+    /// @param binding the binding number to use for the storage buffer
+    void AddSampler(const std::string& name, uint32_t group, uint32_t binding);
 
-  /// Adds a comparison sampler variable to the program
-  /// @param name the name of the variable
-  /// @param group the binding/group to use for the storage buffer
-  /// @param binding the binding number to use for the storage buffer
-  void AddComparisonSampler(const std::string& name,
-                            uint32_t group,
-                            uint32_t binding);
+    /// Adds a comparison sampler variable to the program
+    /// @param name the name of the variable
+    /// @param group the binding/group to use for the storage buffer
+    /// @param binding the binding number to use for the storage buffer
+    void AddComparisonSampler(const std::string& name, uint32_t group, uint32_t binding);
 
-  /// Adds a sampler or texture variable to the program
-  /// @param name the name of the variable
-  /// @param type the type to use
-  /// @param group the binding/group to use for the resource
-  /// @param binding the binding number to use for the resource
-  void AddResource(const std::string& name,
-                   const ast::Type* type,
-                   uint32_t group,
-                   uint32_t binding);
+    /// Adds a sampler or texture variable to the program
+    /// @param name the name of the variable
+    /// @param type the type to use
+    /// @param group the binding/group to use for the resource
+    /// @param binding the binding number to use for the resource
+    void AddResource(const std::string& name,
+                     const ast::Type* type,
+                     uint32_t group,
+                     uint32_t binding);
 
-  /// Add a module scope private variable to the progames
-  /// @param name the name of the variable
-  /// @param type the type to use
-  void AddGlobalVariable(const std::string& name, const ast::Type* type);
+    /// Add a module scope private variable to the progames
+    /// @param name the name of the variable
+    /// @param type the type to use
+    void AddGlobalVariable(const std::string& name, const ast::Type* type);
 
-  /// Generates a function that references a specific sampler variable
-  /// @param func_name name of the function created
-  /// @param texture_name name of the texture to be sampled
-  /// @param sampler_name name of the sampler to use
-  /// @param coords_name name of the coords variable to use
-  /// @param base_type sampler base type
-  /// @param attributes the function attributes
-  /// @returns a function that references all of the values specified
-  const ast::Function* MakeSamplerReferenceBodyFunction(
-      const std::string& func_name,
-      const std::string& texture_name,
-      const std::string& sampler_name,
-      const std::string& coords_name,
-      const ast::Type* base_type,
-      ast::AttributeList attributes);
+    /// Generates a function that references a specific sampler variable
+    /// @param func_name name of the function created
+    /// @param texture_name name of the texture to be sampled
+    /// @param sampler_name name of the sampler to use
+    /// @param coords_name name of the coords variable to use
+    /// @param base_type sampler base type
+    /// @param attributes the function attributes
+    /// @returns a function that references all of the values specified
+    const ast::Function* MakeSamplerReferenceBodyFunction(const std::string& func_name,
+                                                          const std::string& texture_name,
+                                                          const std::string& sampler_name,
+                                                          const std::string& coords_name,
+                                                          const ast::Type* base_type,
+                                                          ast::AttributeList attributes);
 
-  /// Generates a function that references a specific sampler variable
-  /// @param func_name name of the function created
-  /// @param texture_name name of the texture to be sampled
-  /// @param sampler_name name of the sampler to use
-  /// @param coords_name name of the coords variable to use
-  /// @param array_index name of the array index variable to use
-  /// @param base_type sampler base type
-  /// @param attributes the function attributes
-  /// @returns a function that references all of the values specified
-  const ast::Function* MakeSamplerReferenceBodyFunction(
-      const std::string& func_name,
-      const std::string& texture_name,
-      const std::string& sampler_name,
-      const std::string& coords_name,
-      const std::string& array_index,
-      const ast::Type* base_type,
-      ast::AttributeList attributes);
+    /// Generates a function that references a specific sampler variable
+    /// @param func_name name of the function created
+    /// @param texture_name name of the texture to be sampled
+    /// @param sampler_name name of the sampler to use
+    /// @param coords_name name of the coords variable to use
+    /// @param array_index name of the array index variable to use
+    /// @param base_type sampler base type
+    /// @param attributes the function attributes
+    /// @returns a function that references all of the values specified
+    const ast::Function* MakeSamplerReferenceBodyFunction(const std::string& func_name,
+                                                          const std::string& texture_name,
+                                                          const std::string& sampler_name,
+                                                          const std::string& coords_name,
+                                                          const std::string& array_index,
+                                                          const ast::Type* base_type,
+                                                          ast::AttributeList attributes);
 
-  /// Generates a function that references a specific comparison sampler
-  /// variable.
-  /// @param func_name name of the function created
-  /// @param texture_name name of the depth texture to  use
-  /// @param sampler_name name of the sampler to use
-  /// @param coords_name name of the coords variable to use
-  /// @param depth_name name of the depth reference to use
-  /// @param base_type sampler base type
-  /// @param attributes the function attributes
-  /// @returns a function that references all of the values specified
-  const ast::Function* MakeComparisonSamplerReferenceBodyFunction(
-      const std::string& func_name,
-      const std::string& texture_name,
-      const std::string& sampler_name,
-      const std::string& coords_name,
-      const std::string& depth_name,
-      const ast::Type* base_type,
-      ast::AttributeList attributes);
+    /// Generates a function that references a specific comparison sampler
+    /// variable.
+    /// @param func_name name of the function created
+    /// @param texture_name name of the depth texture to  use
+    /// @param sampler_name name of the sampler to use
+    /// @param coords_name name of the coords variable to use
+    /// @param depth_name name of the depth reference to use
+    /// @param base_type sampler base type
+    /// @param attributes the function attributes
+    /// @returns a function that references all of the values specified
+    const ast::Function* MakeComparisonSamplerReferenceBodyFunction(const std::string& func_name,
+                                                                    const std::string& texture_name,
+                                                                    const std::string& sampler_name,
+                                                                    const std::string& coords_name,
+                                                                    const std::string& depth_name,
+                                                                    const ast::Type* base_type,
+                                                                    ast::AttributeList attributes);
 
-  /// Gets an appropriate type for the data in a given texture type.
-  /// @param sampled_kind type of in the texture
-  /// @returns a pointer to a type appropriate for the coord param
-  const ast::Type* GetBaseType(ResourceBinding::SampledKind sampled_kind);
+    /// Gets an appropriate type for the data in a given texture type.
+    /// @param sampled_kind type of in the texture
+    /// @returns a pointer to a type appropriate for the coord param
+    const ast::Type* GetBaseType(ResourceBinding::SampledKind sampled_kind);
 
-  /// Gets an appropriate type for the coords parameter depending the the
-  /// dimensionality of the texture being sampled.
-  /// @param dim dimensionality of the texture being sampled
-  /// @param scalar the scalar type
-  /// @returns a pointer to a type appropriate for the coord param
-  const ast::Type* GetCoordsType(ast::TextureDimension dim,
-                                 const ast::Type* scalar);
+    /// Gets an appropriate type for the coords parameter depending the the
+    /// dimensionality of the texture being sampled.
+    /// @param dim dimensionality of the texture being sampled
+    /// @param scalar the scalar type
+    /// @returns a pointer to a type appropriate for the coord param
+    const ast::Type* GetCoordsType(ast::TextureDimension dim, const ast::Type* scalar);
 
-  /// Generates appropriate types for a Read-Only StorageTexture
-  /// @param dim the texture dimension of the storage texture
-  /// @param format the texel format of the storage texture
-  /// @returns the storage texture type
-  const ast::Type* MakeStorageTextureTypes(ast::TextureDimension dim,
-                                           ast::TexelFormat format);
+    /// Generates appropriate types for a Read-Only StorageTexture
+    /// @param dim the texture dimension of the storage texture
+    /// @param format the texel format of the storage texture
+    /// @returns the storage texture type
+    const ast::Type* MakeStorageTextureTypes(ast::TextureDimension dim, ast::TexelFormat format);
 
-  /// Adds a storage texture variable to the program
-  /// @param name the name of the variable
-  /// @param type the type to use
-  /// @param group the binding/group to use for the sampled texture
-  /// @param binding the binding57 number to use for the sampled texture
-  void AddStorageTexture(const std::string& name,
-                         const ast::Type* type,
-                         uint32_t group,
-                         uint32_t binding);
+    /// Adds a storage texture variable to the program
+    /// @param name the name of the variable
+    /// @param type the type to use
+    /// @param group the binding/group to use for the sampled texture
+    /// @param binding the binding57 number to use for the sampled texture
+    void AddStorageTexture(const std::string& name,
+                           const ast::Type* type,
+                           uint32_t group,
+                           uint32_t binding);
 
-  /// Generates a function that references a storage texture variable.
-  /// @param func_name name of the function created
-  /// @param st_name name of the storage texture to use
-  /// @param dim_type type expected by textureDimensons to return
-  /// @param attributes the function attributes
-  /// @returns a function that references all of the values specified
-  const ast::Function* MakeStorageTextureBodyFunction(
-      const std::string& func_name,
-      const std::string& st_name,
-      const ast::Type* dim_type,
-      ast::AttributeList attributes);
+    /// Generates a function that references a storage texture variable.
+    /// @param func_name name of the function created
+    /// @param st_name name of the storage texture to use
+    /// @param dim_type type expected by textureDimensons to return
+    /// @param attributes the function attributes
+    /// @returns a function that references all of the values specified
+    const ast::Function* MakeStorageTextureBodyFunction(const std::string& func_name,
+                                                        const std::string& st_name,
+                                                        const ast::Type* dim_type,
+                                                        ast::AttributeList attributes);
 
-  /// Get a generator function that returns a type appropriate for a stage
-  /// variable with the given combination of component and composition type.
-  /// @param component component type of the stage variable
-  /// @param composition composition type of the stage variable
-  /// @returns a generator function for the stage variable's type.
-  std::function<const ast::Type*()> GetTypeFunction(
-      ComponentType component,
-      CompositionType composition);
+    /// Get a generator function that returns a type appropriate for a stage
+    /// variable with the given combination of component and composition type.
+    /// @param component component type of the stage variable
+    /// @param composition composition type of the stage variable
+    /// @returns a generator function for the stage variable's type.
+    std::function<const ast::Type*()> GetTypeFunction(ComponentType component,
+                                                      CompositionType composition);
 
-  /// Build the Program given all of the previous methods called and return an
-  /// Inspector for it.
-  /// Should only be called once per test.
-  /// @returns a reference to the Inspector for the built Program.
-  Inspector& Build();
+    /// Build the Program given all of the previous methods called and return an
+    /// Inspector for it.
+    /// Should only be called once per test.
+    /// @returns a reference to the Inspector for the built Program.
+    Inspector& Build();
 
-  /// @returns the type for a SamplerKind::kSampler
-  const ast::Sampler* sampler_type() {
-    return ty.sampler(ast::SamplerKind::kSampler);
-  }
+    /// @returns the type for a SamplerKind::kSampler
+    const ast::Sampler* sampler_type() { return ty.sampler(ast::SamplerKind::kSampler); }
 
-  /// @returns the type for a SamplerKind::kComparison
-  const ast::Sampler* comparison_sampler_type() {
-    return ty.sampler(ast::SamplerKind::kComparisonSampler);
-  }
+    /// @returns the type for a SamplerKind::kComparison
+    const ast::Sampler* comparison_sampler_type() {
+        return ty.sampler(ast::SamplerKind::kComparisonSampler);
+    }
 
- protected:
-  /// Program built by this builder.
-  std::unique_ptr<Program> program_;
-  /// Inspector for |program_|
-  std::unique_ptr<Inspector> inspector_;
+  protected:
+    /// Program built by this builder.
+    std::unique_ptr<Program> program_;
+    /// Inspector for |program_|
+    std::unique_ptr<Inspector> inspector_;
 };
 
 }  // namespace tint::inspector
diff --git a/src/tint/inspector/test_inspector_runner.cc b/src/tint/inspector/test_inspector_runner.cc
index 0bb5858..16e4196 100644
--- a/src/tint/inspector/test_inspector_runner.cc
+++ b/src/tint/inspector/test_inspector_runner.cc
@@ -20,18 +20,17 @@
 InspectorRunner::~InspectorRunner() = default;
 
 Inspector& InspectorRunner::Initialize(std::string shader) {
-  if (inspector_) {
-    return *inspector_;
-  }
+    if (inspector_) {
+        return *inspector_;
+    }
 
-  file_ = std::make_unique<Source::File>("test", shader);
-  program_ = std::make_unique<Program>(reader::wgsl::Parse(file_.get()));
-  [&]() {
-    ASSERT_TRUE(program_->IsValid())
-        << diag::Formatter().format(program_->Diagnostics());
-  }();
-  inspector_ = std::make_unique<Inspector>(program_.get());
-  return *inspector_;
+    file_ = std::make_unique<Source::File>("test", shader);
+    program_ = std::make_unique<Program>(reader::wgsl::Parse(file_.get()));
+    [&]() {
+        ASSERT_TRUE(program_->IsValid()) << diag::Formatter().format(program_->Diagnostics());
+    }();
+    inspector_ = std::make_unique<Inspector>(program_.get());
+    return *inspector_;
 }
 
 }  // namespace tint::inspector
diff --git a/src/tint/inspector/test_inspector_runner.h b/src/tint/inspector/test_inspector_runner.h
index bac3beb..6d46725 100644
--- a/src/tint/inspector/test_inspector_runner.h
+++ b/src/tint/inspector/test_inspector_runner.h
@@ -25,23 +25,23 @@
 
 /// Utility class for running shaders in inspector tests
 class InspectorRunner {
- public:
-  InspectorRunner();
-  virtual ~InspectorRunner();
+  public:
+    InspectorRunner();
+    virtual ~InspectorRunner();
 
-  /// Create a Program with Inspector from the provided WGSL shader.
-  /// Should only be called once per test.
-  /// @param shader a WGSL shader
-  /// @returns a reference to the Inspector for the built Program.
-  Inspector& Initialize(std::string shader);
+    /// Create a Program with Inspector from the provided WGSL shader.
+    /// Should only be called once per test.
+    /// @param shader a WGSL shader
+    /// @returns a reference to the Inspector for the built Program.
+    Inspector& Initialize(std::string shader);
 
- protected:
-  /// File created from input shader and used to create Program.
-  std::unique_ptr<Source::File> file_;
-  /// Program created by this runner.
-  std::unique_ptr<Program> program_;
-  /// Inspector for |program_|
-  std::unique_ptr<Inspector> inspector_;
+  protected:
+    /// File created from input shader and used to create Program.
+    std::unique_ptr<Source::File> file_;
+    /// Program created by this runner.
+    std::unique_ptr<Program> program_;
+    /// Inspector for |program_|
+    std::unique_ptr<Inspector> inspector_;
 };
 
 }  // namespace tint::inspector
diff --git a/src/tint/number.h b/src/tint/number.h
new file mode 100644
index 0000000..165a00a
--- /dev/null
+++ b/src/tint/number.h
@@ -0,0 +1,86 @@
+// Copyright 2021 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_NUMBER_H_
+#define SRC_TINT_NUMBER_H_
+
+#include <stdint.h>
+
+namespace tint {
+
+/// Number wraps a integer or floating point number, enforcing explicit casting.
+template <typename T>
+struct Number {
+    /// Constructor. The value is zero-initialized.
+    Number() = default;
+
+    /// Constructor.
+    /// @param v the value to initialize this Number to
+    explicit Number(T v) : value(v) {}
+
+    /// Conversion operator
+    /// @returns the value as T
+    operator T() const { return value; }
+
+    /// Assignment operator
+    /// @param v the new value
+    /// @returns this Number so calls can be chained
+    Number& operator=(T v) {
+        value = v;
+        return *this;
+    }
+
+    /// The number value
+    T value = {};
+};
+
+template <typename A, typename B>
+bool operator==(Number<A> a, Number<B> b) {
+    return a.value == b.value;
+}
+
+template <typename A, typename B>
+bool operator==(Number<A> a, B b) {
+    return a.value == b;
+}
+
+template <typename A, typename B>
+bool operator==(A a, Number<B> b) {
+    return a == b.value;
+}
+
+/// `i32` is a type alias to `Number<int32_t>`.
+using i32 = Number<int32_t>;
+/// `u32` is a type alias to `Number<uint32_t>`.
+using u32 = Number<uint32_t>;
+/// `f32` is a type alias to `float`
+using f32 = float;
+
+}  // namespace tint
+
+namespace tint::number_suffixes {
+
+/// Literal suffix for i32 literals
+inline i32 operator"" _i(unsigned long long int value) {  // NOLINT
+    return i32(static_cast<int32_t>(value));
+}
+
+/// Literal suffix for u32 literals
+inline u32 operator"" _u(unsigned long long int value) {  // NOLINT
+    return u32(static_cast<uint32_t>(value));
+}
+
+}  // namespace tint::number_suffixes
+
+#endif  // SRC_TINT_NUMBER_H_
diff --git a/src/tint/program.cc b/src/tint/program.cc
index a6a6ab7..6722a09 100644
--- a/src/tint/program.cc
+++ b/src/tint/program.cc
@@ -24,7 +24,7 @@
 namespace {
 
 std::string DefaultPrinter(const Program*) {
-  return "<no program printer assigned>";
+    return "<no program printer assigned>";
 }
 
 }  // namespace
@@ -43,89 +43,89 @@
       symbols_(std::move(program.symbols_)),
       diagnostics_(std::move(program.diagnostics_)),
       is_valid_(program.is_valid_) {
-  program.AssertNotMoved();
-  program.moved_ = true;
+    program.AssertNotMoved();
+    program.moved_ = true;
 }
 
 Program::Program(ProgramBuilder&& builder) {
-  id_ = builder.ID();
+    id_ = builder.ID();
 
-  is_valid_ = builder.IsValid();
-  if (builder.ResolveOnBuild() && builder.IsValid()) {
-    resolver::Resolver resolver(&builder);
-    if (!resolver.Resolve()) {
-      is_valid_ = false;
+    is_valid_ = builder.IsValid();
+    if (builder.ResolveOnBuild() && builder.IsValid()) {
+        resolver::Resolver resolver(&builder);
+        if (!resolver.Resolve()) {
+            is_valid_ = false;
+        }
     }
-  }
 
-  // The above must be called *before* the calls to std::move() below
-  types_ = std::move(builder.Types());
-  ast_nodes_ = std::move(builder.ASTNodes());
-  sem_nodes_ = std::move(builder.SemNodes());
-  ast_ = &builder.AST();  // ast::Module is actually a heap allocation.
-  sem_ = std::move(builder.Sem());
-  symbols_ = std::move(builder.Symbols());
-  diagnostics_.add(std::move(builder.Diagnostics()));
-  builder.MarkAsMoved();
+    // The above must be called *before* the calls to std::move() below
+    types_ = std::move(builder.Types());
+    ast_nodes_ = std::move(builder.ASTNodes());
+    sem_nodes_ = std::move(builder.SemNodes());
+    ast_ = &builder.AST();  // ast::Module is actually a heap allocation.
+    sem_ = std::move(builder.Sem());
+    symbols_ = std::move(builder.Symbols());
+    diagnostics_.add(std::move(builder.Diagnostics()));
+    builder.MarkAsMoved();
 
-  if (!is_valid_ && !diagnostics_.contains_errors()) {
-    // If the builder claims to be invalid, then we really should have an error
-    // message generated. If we find a situation where the program is not valid
-    // and there are no errors reported, add one here.
-    diagnostics_.add_error(diag::System::Program, "invalid program generated");
-  }
+    if (!is_valid_ && !diagnostics_.contains_errors()) {
+        // If the builder claims to be invalid, then we really should have an error
+        // message generated. If we find a situation where the program is not valid
+        // and there are no errors reported, add one here.
+        diagnostics_.add_error(diag::System::Program, "invalid program generated");
+    }
 }
 
 Program::~Program() = default;
 
 Program& Program::operator=(Program&& program) {
-  program.AssertNotMoved();
-  program.moved_ = true;
-  moved_ = false;
-  id_ = std::move(program.id_);
-  types_ = std::move(program.types_);
-  ast_nodes_ = std::move(program.ast_nodes_);
-  sem_nodes_ = std::move(program.sem_nodes_);
-  ast_ = std::move(program.ast_);
-  sem_ = std::move(program.sem_);
-  symbols_ = std::move(program.symbols_);
-  diagnostics_ = std::move(program.diagnostics_);
-  is_valid_ = program.is_valid_;
-  return *this;
+    program.AssertNotMoved();
+    program.moved_ = true;
+    moved_ = false;
+    id_ = std::move(program.id_);
+    types_ = std::move(program.types_);
+    ast_nodes_ = std::move(program.ast_nodes_);
+    sem_nodes_ = std::move(program.sem_nodes_);
+    ast_ = std::move(program.ast_);
+    sem_ = std::move(program.sem_);
+    symbols_ = std::move(program.symbols_);
+    diagnostics_ = std::move(program.diagnostics_);
+    is_valid_ = program.is_valid_;
+    return *this;
 }
 
 Program Program::Clone() const {
-  AssertNotMoved();
-  return Program(CloneAsBuilder());
+    AssertNotMoved();
+    return Program(CloneAsBuilder());
 }
 
 ProgramBuilder Program::CloneAsBuilder() const {
-  AssertNotMoved();
-  ProgramBuilder out;
-  CloneContext(&out, this).Clone();
-  return out;
+    AssertNotMoved();
+    ProgramBuilder out;
+    CloneContext(&out, this).Clone();
+    return out;
 }
 
 bool Program::IsValid() const {
-  AssertNotMoved();
-  return is_valid_;
+    AssertNotMoved();
+    return is_valid_;
 }
 
 const sem::Type* Program::TypeOf(const ast::Expression* expr) const {
-  auto* sem = Sem().Get(expr);
-  return sem ? sem->Type() : nullptr;
+    auto* sem = Sem().Get(expr);
+    return sem ? sem->Type() : nullptr;
 }
 
 const sem::Type* Program::TypeOf(const ast::Type* type) const {
-  return Sem().Get(type);
+    return Sem().Get(type);
 }
 
 const sem::Type* Program::TypeOf(const ast::TypeDecl* type_decl) const {
-  return Sem().Get(type_decl);
+    return Sem().Get(type_decl);
 }
 
 void Program::AssertNotMoved() const {
-  TINT_ASSERT(Program, !moved_);
+    TINT_ASSERT(Program, !moved_);
 }
 
 }  // namespace tint
diff --git a/src/tint/program.h b/src/tint/program.h
index 37b462e..3230e7e 100644
--- a/src/tint/program.h
+++ b/src/tint/program.h
@@ -36,142 +36,142 @@
 
 /// Program holds the AST, Type information and SymbolTable for a tint program.
 class Program {
- public:
-  /// ASTNodeAllocator is an alias to BlockAllocator<ast::Node>
-  using ASTNodeAllocator = utils::BlockAllocator<ast::Node>;
+  public:
+    /// ASTNodeAllocator is an alias to BlockAllocator<ast::Node>
+    using ASTNodeAllocator = utils::BlockAllocator<ast::Node>;
 
-  /// SemNodeAllocator is an alias to BlockAllocator<sem::Node>
-  using SemNodeAllocator = utils::BlockAllocator<sem::Node>;
+    /// SemNodeAllocator is an alias to BlockAllocator<sem::Node>
+    using SemNodeAllocator = utils::BlockAllocator<sem::Node>;
 
-  /// Constructor
-  Program();
+    /// Constructor
+    Program();
 
-  /// Move constructor
-  /// @param rhs the Program to move
-  Program(Program&& rhs);
+    /// Move constructor
+    /// @param rhs the Program to move
+    Program(Program&& rhs);
 
-  /// Move constructor from builder
-  /// @param builder the builder used to construct the program
-  explicit Program(ProgramBuilder&& builder);
+    /// Move constructor from builder
+    /// @param builder the builder used to construct the program
+    explicit Program(ProgramBuilder&& builder);
 
-  /// Destructor
-  ~Program();
+    /// Destructor
+    ~Program();
 
-  /// Move assignment operator
-  /// @param rhs the Program to move
-  /// @return this Program
-  Program& operator=(Program&& rhs);
+    /// Move assignment operator
+    /// @param rhs the Program to move
+    /// @return this Program
+    Program& operator=(Program&& rhs);
 
-  /// @returns the unique identifier for this program
-  ProgramID ID() const { return id_; }
+    /// @returns the unique identifier for this program
+    ProgramID ID() const { return id_; }
 
-  /// @returns a reference to the program's types
-  const sem::Manager& Types() const {
-    AssertNotMoved();
-    return types_;
-  }
+    /// @returns a reference to the program's types
+    const sem::Manager& Types() const {
+        AssertNotMoved();
+        return types_;
+    }
 
-  /// @returns a reference to the program's AST nodes storage
-  const ASTNodeAllocator& ASTNodes() const {
-    AssertNotMoved();
-    return ast_nodes_;
-  }
+    /// @returns a reference to the program's AST nodes storage
+    const ASTNodeAllocator& ASTNodes() const {
+        AssertNotMoved();
+        return ast_nodes_;
+    }
 
-  /// @returns a reference to the program's semantic nodes storage
-  const SemNodeAllocator& SemNodes() const {
-    AssertNotMoved();
-    return sem_nodes_;
-  }
+    /// @returns a reference to the program's semantic nodes storage
+    const SemNodeAllocator& SemNodes() const {
+        AssertNotMoved();
+        return sem_nodes_;
+    }
 
-  /// @returns a reference to the program's AST root Module
-  const ast::Module& AST() const {
-    AssertNotMoved();
-    return *ast_;
-  }
+    /// @returns a reference to the program's AST root Module
+    const ast::Module& AST() const {
+        AssertNotMoved();
+        return *ast_;
+    }
 
-  /// @returns a reference to the program's semantic info
-  const sem::Info& Sem() const {
-    AssertNotMoved();
-    return sem_;
-  }
+    /// @returns a reference to the program's semantic info
+    const sem::Info& Sem() const {
+        AssertNotMoved();
+        return sem_;
+    }
 
-  /// @returns a reference to the program's SymbolTable
-  const SymbolTable& Symbols() const {
-    AssertNotMoved();
-    return symbols_;
-  }
+    /// @returns a reference to the program's SymbolTable
+    const SymbolTable& Symbols() const {
+        AssertNotMoved();
+        return symbols_;
+    }
 
-  /// @returns a reference to the program's diagnostics
-  const diag::List& Diagnostics() const {
-    AssertNotMoved();
-    return diagnostics_;
-  }
+    /// @returns a reference to the program's diagnostics
+    const diag::List& Diagnostics() const {
+        AssertNotMoved();
+        return diagnostics_;
+    }
 
-  /// Performs a deep clone of this program.
-  /// The returned Program will contain no pointers to objects owned by this
-  /// Program, and so after calling, this Program can be safely destructed.
-  /// @return a new Program copied from this Program
-  Program Clone() const;
+    /// Performs a deep clone of this program.
+    /// The returned Program will contain no pointers to objects owned by this
+    /// Program, and so after calling, this Program can be safely destructed.
+    /// @return a new Program copied from this Program
+    Program Clone() const;
 
-  /// Performs a deep clone of this Program's AST nodes, types and symbols into
-  /// a new ProgramBuilder. Semantic nodes are not cloned, as these will be
-  /// rebuilt when the ProgramBuilder builds its Program.
-  /// The returned ProgramBuilder will contain no pointers to objects owned by
-  /// this Program, and so after calling, this Program can be safely destructed.
-  /// @return a new ProgramBuilder copied from this Program
-  ProgramBuilder CloneAsBuilder() const;
+    /// Performs a deep clone of this Program's AST nodes, types and symbols into
+    /// a new ProgramBuilder. Semantic nodes are not cloned, as these will be
+    /// rebuilt when the ProgramBuilder builds its Program.
+    /// The returned ProgramBuilder will contain no pointers to objects owned by
+    /// this Program, and so after calling, this Program can be safely destructed.
+    /// @return a new ProgramBuilder copied from this Program
+    ProgramBuilder CloneAsBuilder() const;
 
-  /// @returns true if the program has no error diagnostics and is not missing
-  /// information
-  bool IsValid() const;
+    /// @returns true if the program has no error diagnostics and is not missing
+    /// information
+    bool IsValid() const;
 
-  /// Helper for returning the resolved semantic type of the expression `expr`.
-  /// @param expr the AST expression
-  /// @return the resolved semantic type for the expression, or nullptr if the
-  /// expression has no resolved type.
-  const sem::Type* TypeOf(const ast::Expression* expr) const;
+    /// Helper for returning the resolved semantic type of the expression `expr`.
+    /// @param expr the AST expression
+    /// @return the resolved semantic type for the expression, or nullptr if the
+    /// expression has no resolved type.
+    const sem::Type* TypeOf(const ast::Expression* expr) const;
 
-  /// Helper for returning the resolved semantic type of the AST type `type`.
-  /// @param type the AST type
-  /// @return the resolved semantic type for the type, or nullptr if the type
-  /// has no resolved type.
-  const sem::Type* TypeOf(const ast::Type* type) const;
+    /// Helper for returning the resolved semantic type of the AST type `type`.
+    /// @param type the AST type
+    /// @return the resolved semantic type for the type, or nullptr if the type
+    /// has no resolved type.
+    const sem::Type* TypeOf(const ast::Type* type) const;
 
-  /// Helper for returning the resolved semantic type of the AST type
-  /// declaration `type_decl`.
-  /// @param type_decl the AST type declaration
-  /// @return the resolved semantic type for the type declaration, or nullptr if
-  /// the type declaration has no resolved type.
-  const sem::Type* TypeOf(const ast::TypeDecl* type_decl) const;
+    /// Helper for returning the resolved semantic type of the AST type
+    /// declaration `type_decl`.
+    /// @param type_decl the AST type declaration
+    /// @return the resolved semantic type for the type declaration, or nullptr if
+    /// the type declaration has no resolved type.
+    const sem::Type* TypeOf(const ast::TypeDecl* type_decl) const;
 
-  /// A function that can be used to print a program
-  using Printer = std::string (*)(const Program*);
+    /// A function that can be used to print a program
+    using Printer = std::string (*)(const Program*);
 
-  /// The Program printer used for testing and debugging.
-  static Printer printer;
+    /// The Program printer used for testing and debugging.
+    static Printer printer;
 
- private:
-  Program(const Program&) = delete;
+  private:
+    Program(const Program&) = delete;
 
-  /// Asserts that the program has not been moved.
-  void AssertNotMoved() const;
+    /// Asserts that the program has not been moved.
+    void AssertNotMoved() const;
 
-  ProgramID id_;
-  sem::Manager types_;
-  ASTNodeAllocator ast_nodes_;
-  SemNodeAllocator sem_nodes_;
-  ast::Module* ast_ = nullptr;
-  sem::Info sem_;
-  SymbolTable symbols_{id_};
-  diag::List diagnostics_;
-  bool is_valid_ = false;  // Not valid until it is built
-  bool moved_ = false;
+    ProgramID id_;
+    sem::Manager types_;
+    ASTNodeAllocator ast_nodes_;
+    SemNodeAllocator sem_nodes_;
+    ast::Module* ast_ = nullptr;
+    sem::Info sem_;
+    SymbolTable symbols_{id_};
+    diag::List diagnostics_;
+    bool is_valid_ = false;  // Not valid until it is built
+    bool moved_ = false;
 };
 
 /// @param program the Program
 /// @returns the ProgramID of the Program
 inline ProgramID ProgramIDOf(const Program* program) {
-  return program->ID();
+    return program->ID();
 }
 
 }  // namespace tint
diff --git a/src/tint/program_builder.cc b/src/tint/program_builder.cc
index c2f58ec..cd05fd4 100644
--- a/src/tint/program_builder.cc
+++ b/src/tint/program_builder.cc
@@ -22,13 +22,14 @@
 #include "src/tint/sem/expression.h"
 #include "src/tint/sem/variable.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint {
 
 ProgramBuilder::VarOptionals::~VarOptionals() = default;
 
 ProgramBuilder::ProgramBuilder()
-    : id_(ProgramID::New()),
-      ast_(ast_nodes_.Create<ast::Module>(id_, Source{})) {}
+    : id_(ProgramID::New()), ast_(ast_nodes_.Create<ast::Module>(id_, Source{})) {}
 
 ProgramBuilder::ProgramBuilder(ProgramBuilder&& rhs)
     : id_(std::move(rhs.id_)),
@@ -39,100 +40,95 @@
       sem_(std::move(rhs.sem_)),
       symbols_(std::move(rhs.symbols_)),
       diagnostics_(std::move(rhs.diagnostics_)) {
-  rhs.MarkAsMoved();
+    rhs.MarkAsMoved();
 }
 
 ProgramBuilder::~ProgramBuilder() = default;
 
 ProgramBuilder& ProgramBuilder::operator=(ProgramBuilder&& rhs) {
-  rhs.MarkAsMoved();
-  AssertNotMoved();
-  id_ = std::move(rhs.id_);
-  types_ = std::move(rhs.types_);
-  ast_nodes_ = std::move(rhs.ast_nodes_);
-  sem_nodes_ = std::move(rhs.sem_nodes_);
-  ast_ = rhs.ast_;
-  sem_ = std::move(rhs.sem_);
-  symbols_ = std::move(rhs.symbols_);
-  diagnostics_ = std::move(rhs.diagnostics_);
+    rhs.MarkAsMoved();
+    AssertNotMoved();
+    id_ = std::move(rhs.id_);
+    types_ = std::move(rhs.types_);
+    ast_nodes_ = std::move(rhs.ast_nodes_);
+    sem_nodes_ = std::move(rhs.sem_nodes_);
+    ast_ = rhs.ast_;
+    sem_ = std::move(rhs.sem_);
+    symbols_ = std::move(rhs.symbols_);
+    diagnostics_ = std::move(rhs.diagnostics_);
 
-  return *this;
+    return *this;
 }
 
 ProgramBuilder ProgramBuilder::Wrap(const Program* program) {
-  ProgramBuilder builder;
-  builder.id_ = program->ID();
-  builder.types_ = sem::Manager::Wrap(program->Types());
-  builder.ast_ = builder.create<ast::Module>(
-      program->AST().source, program->AST().GlobalDeclarations());
-  builder.sem_ = sem::Info::Wrap(program->Sem());
-  builder.symbols_ = program->Symbols();
-  builder.diagnostics_ = program->Diagnostics();
-  return builder;
+    ProgramBuilder builder;
+    builder.id_ = program->ID();
+    builder.types_ = sem::Manager::Wrap(program->Types());
+    builder.ast_ =
+        builder.create<ast::Module>(program->AST().source, program->AST().GlobalDeclarations());
+    builder.sem_ = sem::Info::Wrap(program->Sem());
+    builder.symbols_ = program->Symbols();
+    builder.diagnostics_ = program->Diagnostics();
+    return builder;
 }
 
 bool ProgramBuilder::IsValid() const {
-  return !diagnostics_.contains_errors();
+    return !diagnostics_.contains_errors();
 }
 
 void ProgramBuilder::MarkAsMoved() {
-  AssertNotMoved();
-  moved_ = true;
+    AssertNotMoved();
+    moved_ = true;
 }
 
 void ProgramBuilder::AssertNotMoved() const {
-  if (moved_) {
-    TINT_ICE(ProgramBuilder, const_cast<ProgramBuilder*>(this)->diagnostics_)
-        << "Attempting to use ProgramBuilder after it has been moved";
-  }
+    if (moved_) {
+        TINT_ICE(ProgramBuilder, const_cast<ProgramBuilder*>(this)->diagnostics_)
+            << "Attempting to use ProgramBuilder after it has been moved";
+    }
 }
 
 const sem::Type* ProgramBuilder::TypeOf(const ast::Expression* expr) const {
-  auto* sem = Sem().Get(expr);
-  return sem ? sem->Type() : nullptr;
+    auto* sem = Sem().Get(expr);
+    return sem ? sem->Type() : nullptr;
 }
 
 const sem::Type* ProgramBuilder::TypeOf(const ast::Variable* var) const {
-  auto* sem = Sem().Get(var);
-  return sem ? sem->Type() : nullptr;
+    auto* sem = Sem().Get(var);
+    return sem ? sem->Type() : nullptr;
 }
 
 const sem::Type* ProgramBuilder::TypeOf(const ast::Type* type) const {
-  return Sem().Get(type);
+    return Sem().Get(type);
 }
 
 const sem::Type* ProgramBuilder::TypeOf(const ast::TypeDecl* type_decl) const {
-  return Sem().Get(type_decl);
+    return Sem().Get(type_decl);
 }
 
-const ast::TypeName* ProgramBuilder::TypesBuilder::Of(
-    const ast::TypeDecl* decl) const {
-  return type_name(decl->name);
+const ast::TypeName* ProgramBuilder::TypesBuilder::Of(const ast::TypeDecl* decl) const {
+    return type_name(decl->name);
 }
 
 ProgramBuilder::TypesBuilder::TypesBuilder(ProgramBuilder* pb) : builder(pb) {}
 
-const ast::Statement* ProgramBuilder::WrapInStatement(
-    const ast::Expression* expr) {
-  // Create a temporary variable of inferred type from expr.
-  return Decl(Const(symbols_.New(), nullptr, expr));
+const ast::Statement* ProgramBuilder::WrapInStatement(const ast::Expression* expr) {
+    // Create a temporary variable of inferred type from expr.
+    return Decl(Let(symbols_.New(), nullptr, expr));
 }
 
-const ast::VariableDeclStatement* ProgramBuilder::WrapInStatement(
-    const ast::Variable* v) {
-  return create<ast::VariableDeclStatement>(v);
+const ast::VariableDeclStatement* ProgramBuilder::WrapInStatement(const ast::Variable* v) {
+    return create<ast::VariableDeclStatement>(v);
 }
 
-const ast::Statement* ProgramBuilder::WrapInStatement(
-    const ast::Statement* stmt) {
-  return stmt;
+const ast::Statement* ProgramBuilder::WrapInStatement(const ast::Statement* stmt) {
+    return stmt;
 }
 
-const ast::Function* ProgramBuilder::WrapInFunction(
-    const ast::StatementList stmts) {
-  return Func("test_function", {}, ty.void_(), std::move(stmts),
-              {create<ast::StageAttribute>(ast::PipelineStage::kCompute),
-               WorkgroupSize(1, 1, 1)});
+const ast::Function* ProgramBuilder::WrapInFunction(const ast::StatementList stmts) {
+    return Func(
+        "test_function", {}, ty.void_(), std::move(stmts),
+        {create<ast::StageAttribute>(ast::PipelineStage::kCompute), WorkgroupSize(1_i, 1_i, 1_i)});
 }
 
 }  // namespace tint
diff --git a/src/tint/program_builder.h b/src/tint/program_builder.h
index 2f7449e..088efc9 100644
--- a/src/tint/program_builder.h
+++ b/src/tint/program_builder.h
@@ -38,6 +38,7 @@
 #include "src/tint/ast/depth_texture.h"
 #include "src/tint/ast/disable_validation_attribute.h"
 #include "src/tint/ast/discard_statement.h"
+#include "src/tint/ast/enable.h"
 #include "src/tint/ast/external_texture.h"
 #include "src/tint/ast/f32.h"
 #include "src/tint/ast/fallthrough_statement.h"
@@ -60,7 +61,6 @@
 #include "src/tint/ast/return_statement.h"
 #include "src/tint/ast/sampled_texture.h"
 #include "src/tint/ast/sampler.h"
-#include "src/tint/ast/sint_literal_expression.h"
 #include "src/tint/ast/stage_attribute.h"
 #include "src/tint/ast/storage_texture.h"
 #include "src/tint/ast/stride_attribute.h"
@@ -70,29 +70,29 @@
 #include "src/tint/ast/switch_statement.h"
 #include "src/tint/ast/type_name.h"
 #include "src/tint/ast/u32.h"
-#include "src/tint/ast/uint_literal_expression.h"
 #include "src/tint/ast/unary_op_expression.h"
 #include "src/tint/ast/variable_decl_statement.h"
 #include "src/tint/ast/vector.h"
 #include "src/tint/ast/void.h"
 #include "src/tint/ast/workgroup_attribute.h"
+#include "src/tint/number.h"
 #include "src/tint/program.h"
 #include "src/tint/program_id.h"
 #include "src/tint/sem/array.h"
-#include "src/tint/sem/bool_type.h"
-#include "src/tint/sem/depth_texture_type.h"
-#include "src/tint/sem/external_texture_type.h"
-#include "src/tint/sem/f32_type.h"
-#include "src/tint/sem/i32_type.h"
-#include "src/tint/sem/matrix_type.h"
-#include "src/tint/sem/multisampled_texture_type.h"
-#include "src/tint/sem/pointer_type.h"
-#include "src/tint/sem/sampled_texture_type.h"
-#include "src/tint/sem/storage_texture_type.h"
+#include "src/tint/sem/bool.h"
+#include "src/tint/sem/depth_texture.h"
+#include "src/tint/sem/external_texture.h"
+#include "src/tint/sem/f32.h"
+#include "src/tint/sem/i32.h"
+#include "src/tint/sem/matrix.h"
+#include "src/tint/sem/multisampled_texture.h"
+#include "src/tint/sem/pointer.h"
+#include "src/tint/sem/sampled_texture.h"
+#include "src/tint/sem/storage_texture.h"
 #include "src/tint/sem/struct.h"
-#include "src/tint/sem/u32_type.h"
-#include "src/tint/sem/vector_type.h"
-#include "src/tint/sem/void_type.h"
+#include "src/tint/sem/u32.h"
+#include "src/tint/sem/vector.h"
+#include "src/tint/sem/void.h"
 
 #ifdef INCLUDE_TINT_TINT_H_
 #error "internal tint header being #included from tint.h"
@@ -112,2707 +112,2546 @@
 /// To construct a Program, populate the builder and then `std::move` it to a
 /// Program.
 class ProgramBuilder {
-  /// A helper used to disable overloads if the first type in `TYPES` is a
-  /// Source. Used to avoid ambiguities in overloads that take a Source as the
-  /// first parameter and those that perfectly-forward the first argument.
-  template <typename... TYPES>
-  using DisableIfSource = traits::EnableIfIsNotType<
-      traits::Decay<traits::NthTypeOf<0, TYPES..., void>>,
-      Source>;
+    /// A helper used to disable overloads if the first type in `TYPES` is a
+    /// Source. Used to avoid ambiguities in overloads that take a Source as the
+    /// first parameter and those that perfectly-forward the first argument.
+    template <typename... TYPES>
+    using DisableIfSource =
+        traits::EnableIfIsNotType<traits::Decay<traits::NthTypeOf<0, TYPES..., void>>, Source>;
 
-  /// VarOptionals is a helper for accepting a number of optional, extra
-  /// arguments for Var() and Global().
-  struct VarOptionals {
-    template <typename... ARGS>
-    explicit VarOptionals(ARGS&&... args) {
-      Apply(std::forward<ARGS>(args)...);
-    }
-    ~VarOptionals();
+    /// VarOptionals is a helper for accepting a number of optional, extra
+    /// arguments for Var() and Global().
+    struct VarOptionals {
+        template <typename... ARGS>
+        explicit VarOptionals(ARGS&&... args) {
+            Apply(std::forward<ARGS>(args)...);
+        }
+        ~VarOptionals();
 
-    ast::StorageClass storage = ast::StorageClass::kNone;
-    ast::Access access = ast::Access::kUndefined;
-    const ast::Expression* constructor = nullptr;
-    ast::AttributeList attributes = {};
+        ast::StorageClass storage = ast::StorageClass::kNone;
+        ast::Access access = ast::Access::kUndefined;
+        const ast::Expression* constructor = nullptr;
+        ast::AttributeList attributes = {};
 
-   private:
-    void Set(ast::StorageClass sc) { storage = sc; }
-    void Set(ast::Access ac) { access = ac; }
-    void Set(const ast::Expression* c) { constructor = c; }
-    void Set(const ast::AttributeList& l) { attributes = l; }
+      private:
+        void Set(ast::StorageClass sc) { storage = sc; }
+        void Set(ast::Access ac) { access = ac; }
+        void Set(const ast::Expression* c) { constructor = c; }
+        void Set(const ast::AttributeList& l) { attributes = l; }
 
-    template <typename FIRST, typename... ARGS>
-    void Apply(FIRST&& first, ARGS&&... args) {
-      Set(std::forward<FIRST>(first));
-      Apply(std::forward<ARGS>(args)...);
-    }
-    void Apply() {}
-  };
+        template <typename FIRST, typename... ARGS>
+        void Apply(FIRST&& first, ARGS&&... args) {
+            Set(std::forward<FIRST>(first));
+            Apply(std::forward<ARGS>(args)...);
+        }
+        void Apply() {}
+    };
 
- public:
-  /// ASTNodeAllocator is an alias to BlockAllocator<ast::Node>
-  using ASTNodeAllocator = utils::BlockAllocator<ast::Node>;
+  public:
+    /// ASTNodeAllocator is an alias to BlockAllocator<ast::Node>
+    using ASTNodeAllocator = utils::BlockAllocator<ast::Node>;
 
-  /// SemNodeAllocator is an alias to BlockAllocator<sem::Node>
-  using SemNodeAllocator = utils::BlockAllocator<sem::Node>;
+    /// SemNodeAllocator is an alias to BlockAllocator<sem::Node>
+    using SemNodeAllocator = utils::BlockAllocator<sem::Node>;
 
-  /// `i32` is a type alias to `int`.
-  /// Useful for passing to template methods such as `vec2<i32>()` to imitate
-  /// WGSL syntax.
-  /// Note: this is intentionally not aliased to uint32_t as we want integer
-  /// literals passed to the builder to match WGSL's integer literal types.
-  using i32 = decltype(1);
-  /// `u32` is a type alias to `unsigned int`.
-  /// Useful for passing to template methods such as `vec2<u32>()` to imitate
-  /// WGSL syntax.
-  /// Note: this is intentionally not aliased to uint32_t as we want integer
-  /// literals passed to the builder to match WGSL's integer literal types.
-  using u32 = decltype(1u);
-  /// `f32` is a type alias to `float`
-  /// Useful for passing to template methods such as `vec2<f32>()` to imitate
-  /// WGSL syntax.
-  using f32 = float;
-
-  /// Constructor
-  ProgramBuilder();
-
-  /// Move constructor
-  /// @param rhs the builder to move
-  ProgramBuilder(ProgramBuilder&& rhs);
-
-  /// Destructor
-  virtual ~ProgramBuilder();
-
-  /// Move assignment operator
-  /// @param rhs the builder to move
-  /// @return this builder
-  ProgramBuilder& operator=(ProgramBuilder&& rhs);
-
-  /// Wrap returns a new ProgramBuilder wrapping the Program `program` without
-  /// making a deep clone of the Program contents.
-  /// ProgramBuilder returned by Wrap() is intended to temporarily extend an
-  /// existing immutable program.
-  /// As the returned ProgramBuilder wraps `program`, `program` must not be
-  /// destructed or assigned while using the returned ProgramBuilder.
-  /// TODO(bclayton) - Evaluate whether there are safer alternatives to this
-  /// function. See crbug.com/tint/460.
-  /// @param program the immutable Program to wrap
-  /// @return the ProgramBuilder that wraps `program`
-  static ProgramBuilder Wrap(const Program* program);
-
-  /// @returns the unique identifier for this program
-  ProgramID ID() const { return id_; }
-
-  /// @returns a reference to the program's types
-  sem::Manager& Types() {
-    AssertNotMoved();
-    return types_;
-  }
-
-  /// @returns a reference to the program's types
-  const sem::Manager& Types() const {
-    AssertNotMoved();
-    return types_;
-  }
-
-  /// @returns a reference to the program's AST nodes storage
-  ASTNodeAllocator& ASTNodes() {
-    AssertNotMoved();
-    return ast_nodes_;
-  }
-
-  /// @returns a reference to the program's AST nodes storage
-  const ASTNodeAllocator& ASTNodes() const {
-    AssertNotMoved();
-    return ast_nodes_;
-  }
-
-  /// @returns a reference to the program's semantic nodes storage
-  SemNodeAllocator& SemNodes() {
-    AssertNotMoved();
-    return sem_nodes_;
-  }
-
-  /// @returns a reference to the program's semantic nodes storage
-  const SemNodeAllocator& SemNodes() const {
-    AssertNotMoved();
-    return sem_nodes_;
-  }
-
-  /// @returns a reference to the program's AST root Module
-  ast::Module& AST() {
-    AssertNotMoved();
-    return *ast_;
-  }
-
-  /// @returns a reference to the program's AST root Module
-  const ast::Module& AST() const {
-    AssertNotMoved();
-    return *ast_;
-  }
-
-  /// @returns a reference to the program's semantic info
-  sem::Info& Sem() {
-    AssertNotMoved();
-    return sem_;
-  }
-
-  /// @returns a reference to the program's semantic info
-  const sem::Info& Sem() const {
-    AssertNotMoved();
-    return sem_;
-  }
-
-  /// @returns a reference to the program's SymbolTable
-  SymbolTable& Symbols() {
-    AssertNotMoved();
-    return symbols_;
-  }
-
-  /// @returns a reference to the program's SymbolTable
-  const SymbolTable& Symbols() const {
-    AssertNotMoved();
-    return symbols_;
-  }
-
-  /// @returns a reference to the program's diagnostics
-  diag::List& Diagnostics() {
-    AssertNotMoved();
-    return diagnostics_;
-  }
-
-  /// @returns a reference to the program's diagnostics
-  const diag::List& Diagnostics() const {
-    AssertNotMoved();
-    return diagnostics_;
-  }
-
-  /// Controls whether the Resolver will be run on the program when it is built.
-  /// @param enable the new flag value (defaults to true)
-  void SetResolveOnBuild(bool enable) { resolve_on_build_ = enable; }
-
-  /// @return true if the Resolver will be run on the program when it is
-  /// built.
-  bool ResolveOnBuild() const { return resolve_on_build_; }
-
-  /// @returns true if the program has no error diagnostics and is not missing
-  /// information
-  bool IsValid() const;
-
-  /// Creates a new ast::Node owned by the ProgramBuilder. When the
-  /// ProgramBuilder is destructed, the ast::Node will also be destructed.
-  /// @param source the Source of the node
-  /// @param args the arguments to pass to the type constructor
-  /// @returns the node pointer
-  template <typename T, typename... ARGS>
-  traits::EnableIfIsType<T, ast::Node>* create(const Source& source,
-                                               ARGS&&... args) {
-    AssertNotMoved();
-    return ast_nodes_.Create<T>(id_, source, std::forward<ARGS>(args)...);
-  }
-
-  /// Creates a new ast::Node owned by the ProgramBuilder, injecting the current
-  /// Source as set by the last call to SetSource() as the only argument to the
-  /// constructor.
-  /// When the ProgramBuilder is destructed, the ast::Node will also be
-  /// destructed.
-  /// @returns the node pointer
-  template <typename T>
-  traits::EnableIfIsType<T, ast::Node>* create() {
-    AssertNotMoved();
-    return ast_nodes_.Create<T>(id_, source_);
-  }
-
-  /// Creates a new ast::Node owned by the ProgramBuilder, injecting the current
-  /// Source as set by the last call to SetSource() as the first argument to the
-  /// constructor.
-  /// When the ProgramBuilder is destructed, the ast::Node will also be
-  /// destructed.
-  /// @param arg0 the first arguments to pass to the type constructor
-  /// @param args the remaining arguments to pass to the type constructor
-  /// @returns the node pointer
-  template <typename T, typename ARG0, typename... ARGS>
-  traits::EnableIf</* T is ast::Node and ARG0 is not Source */
-                   traits::IsTypeOrDerived<T, ast::Node> &&
-                       !traits::IsTypeOrDerived<ARG0, Source>,
-                   T>*
-  create(ARG0&& arg0, ARGS&&... args) {
-    AssertNotMoved();
-    return ast_nodes_.Create<T>(id_, source_, std::forward<ARG0>(arg0),
-                                std::forward<ARGS>(args)...);
-  }
-
-  /// Creates a new sem::Node owned by the ProgramBuilder.
-  /// When the ProgramBuilder is destructed, the sem::Node will also be
-  /// destructed.
-  /// @param args the arguments to pass to the type constructor
-  /// @returns the node pointer
-  template <typename T, typename... ARGS>
-  traits::EnableIf<traits::IsTypeOrDerived<T, sem::Node> &&
-                       !traits::IsTypeOrDerived<T, sem::Type>,
-                   T>*
-  create(ARGS&&... args) {
-    AssertNotMoved();
-    return sem_nodes_.Create<T>(std::forward<ARGS>(args)...);
-  }
-
-  /// Creates a new sem::Type owned by the ProgramBuilder.
-  /// When the ProgramBuilder is destructed, owned ProgramBuilder and the
-  /// returned`Type` will also be destructed.
-  /// Types are unique (de-aliased), and so calling create() for the same `T`
-  /// and arguments will return the same pointer.
-  /// @warning Use this method to acquire a type only if all of its type
-  /// information is provided in the constructor arguments `args`.<br>
-  /// If the type requires additional configuration after construction that
-  /// affect its fundamental type, build the type with `std::make_unique`, make
-  /// any necessary alterations and then call unique_type() instead.
-  /// @param args the arguments to pass to the type constructor
-  /// @returns the de-aliased type pointer
-  template <typename T, typename... ARGS>
-  traits::EnableIfIsType<T, sem::Type>* create(ARGS&&... args) {
-    static_assert(std::is_base_of<sem::Type, T>::value,
-                  "T does not derive from sem::Type");
-    AssertNotMoved();
-    return types_.Get<T>(std::forward<ARGS>(args)...);
-  }
-
-  /// Marks this builder as moved, preventing any further use of the builder.
-  void MarkAsMoved();
-
-  //////////////////////////////////////////////////////////////////////////////
-  // TypesBuilder
-  //////////////////////////////////////////////////////////////////////////////
-
-  /// TypesBuilder holds basic `tint` types and methods for constructing
-  /// complex types.
-  class TypesBuilder {
-   public:
     /// Constructor
-    /// @param builder the program builder
-    explicit TypesBuilder(ProgramBuilder* builder);
+    ProgramBuilder();
 
-    /// @return the tint AST type for the C type `T`.
-    template <typename T>
-    const ast::Type* Of() const {
-      return CToAST<T>::get(this);
+    /// Move constructor
+    /// @param rhs the builder to move
+    ProgramBuilder(ProgramBuilder&& rhs);
+
+    /// Destructor
+    virtual ~ProgramBuilder();
+
+    /// Move assignment operator
+    /// @param rhs the builder to move
+    /// @return this builder
+    ProgramBuilder& operator=(ProgramBuilder&& rhs);
+
+    /// Wrap returns a new ProgramBuilder wrapping the Program `program` without
+    /// making a deep clone of the Program contents.
+    /// ProgramBuilder returned by Wrap() is intended to temporarily extend an
+    /// existing immutable program.
+    /// As the returned ProgramBuilder wraps `program`, `program` must not be
+    /// destructed or assigned while using the returned ProgramBuilder.
+    /// TODO(bclayton) - Evaluate whether there are safer alternatives to this
+    /// function. See crbug.com/tint/460.
+    /// @param program the immutable Program to wrap
+    /// @return the ProgramBuilder that wraps `program`
+    static ProgramBuilder Wrap(const Program* program);
+
+    /// @returns the unique identifier for this program
+    ProgramID ID() const { return id_; }
+
+    /// @returns a reference to the program's types
+    sem::Manager& Types() {
+        AssertNotMoved();
+        return types_;
     }
 
-    /// @returns a boolean type
-    const ast::Bool* bool_() const { return builder->create<ast::Bool>(); }
+    /// @returns a reference to the program's types
+    const sem::Manager& Types() const {
+        AssertNotMoved();
+        return types_;
+    }
 
+    /// @returns a reference to the program's AST nodes storage
+    ASTNodeAllocator& ASTNodes() {
+        AssertNotMoved();
+        return ast_nodes_;
+    }
+
+    /// @returns a reference to the program's AST nodes storage
+    const ASTNodeAllocator& ASTNodes() const {
+        AssertNotMoved();
+        return ast_nodes_;
+    }
+
+    /// @returns a reference to the program's semantic nodes storage
+    SemNodeAllocator& SemNodes() {
+        AssertNotMoved();
+        return sem_nodes_;
+    }
+
+    /// @returns a reference to the program's semantic nodes storage
+    const SemNodeAllocator& SemNodes() const {
+        AssertNotMoved();
+        return sem_nodes_;
+    }
+
+    /// @returns a reference to the program's AST root Module
+    ast::Module& AST() {
+        AssertNotMoved();
+        return *ast_;
+    }
+
+    /// @returns a reference to the program's AST root Module
+    const ast::Module& AST() const {
+        AssertNotMoved();
+        return *ast_;
+    }
+
+    /// @returns a reference to the program's semantic info
+    sem::Info& Sem() {
+        AssertNotMoved();
+        return sem_;
+    }
+
+    /// @returns a reference to the program's semantic info
+    const sem::Info& Sem() const {
+        AssertNotMoved();
+        return sem_;
+    }
+
+    /// @returns a reference to the program's SymbolTable
+    SymbolTable& Symbols() {
+        AssertNotMoved();
+        return symbols_;
+    }
+
+    /// @returns a reference to the program's SymbolTable
+    const SymbolTable& Symbols() const {
+        AssertNotMoved();
+        return symbols_;
+    }
+
+    /// @returns a reference to the program's diagnostics
+    diag::List& Diagnostics() {
+        AssertNotMoved();
+        return diagnostics_;
+    }
+
+    /// @returns a reference to the program's diagnostics
+    const diag::List& Diagnostics() const {
+        AssertNotMoved();
+        return diagnostics_;
+    }
+
+    /// Controls whether the Resolver will be run on the program when it is built.
+    /// @param enable the new flag value (defaults to true)
+    void SetResolveOnBuild(bool enable) { resolve_on_build_ = enable; }
+
+    /// @return true if the Resolver will be run on the program when it is
+    /// built.
+    bool ResolveOnBuild() const { return resolve_on_build_; }
+
+    /// @returns true if the program has no error diagnostics and is not missing
+    /// information
+    bool IsValid() const;
+
+    /// Creates a new ast::Node owned by the ProgramBuilder. When the
+    /// ProgramBuilder is destructed, the ast::Node will also be destructed.
     /// @param source the Source of the node
-    /// @returns a boolean type
-    const ast::Bool* bool_(const Source& source) const {
-      return builder->create<ast::Bool>(source);
+    /// @param args the arguments to pass to the type constructor
+    /// @returns the node pointer
+    template <typename T, typename... ARGS>
+    traits::EnableIfIsType<T, ast::Node>* create(const Source& source, ARGS&&... args) {
+        AssertNotMoved();
+        return ast_nodes_.Create<T>(id_, source, std::forward<ARGS>(args)...);
     }
 
-    /// @returns a f32 type
-    const ast::F32* f32() const { return builder->create<ast::F32>(); }
-
-    /// @param source the Source of the node
-    /// @returns a f32 type
-    const ast::F32* f32(const Source& source) const {
-      return builder->create<ast::F32>(source);
-    }
-
-    /// @returns a i32 type
-    const ast::I32* i32() const { return builder->create<ast::I32>(); }
-
-    /// @param source the Source of the node
-    /// @returns a i32 type
-    const ast::I32* i32(const Source& source) const {
-      return builder->create<ast::I32>(source);
-    }
-
-    /// @returns a u32 type
-    const ast::U32* u32() const { return builder->create<ast::U32>(); }
-
-    /// @param source the Source of the node
-    /// @returns a u32 type
-    const ast::U32* u32(const Source& source) const {
-      return builder->create<ast::U32>(source);
-    }
-
-    /// @returns a void type
-    const ast::Void* void_() const { return builder->create<ast::Void>(); }
-
-    /// @param source the Source of the node
-    /// @returns a void type
-    const ast::Void* void_(const Source& source) const {
-      return builder->create<ast::Void>(source);
-    }
-
-    /// @param type vector subtype
-    /// @param n vector width in elements
-    /// @return the tint AST type for a `n`-element vector of `type`.
-    const ast::Vector* vec(const ast::Type* type, uint32_t n) const {
-      return builder->create<ast::Vector>(type, n);
-    }
-
-    /// @param source the Source of the node
-    /// @param type vector subtype
-    /// @param n vector width in elements
-    /// @return the tint AST type for a `n`-element vector of `type`.
-    const ast::Vector* vec(const Source& source,
-                           const ast::Type* type,
-                           uint32_t n) const {
-      return builder->create<ast::Vector>(source, type, n);
-    }
-
-    /// @param type vector subtype
-    /// @return the tint AST type for a 2-element vector of `type`.
-    const ast::Vector* vec2(const ast::Type* type) const {
-      return vec(type, 2u);
-    }
-
-    /// @param type vector subtype
-    /// @return the tint AST type for a 3-element vector of `type`.
-    const ast::Vector* vec3(const ast::Type* type) const {
-      return vec(type, 3u);
-    }
-
-    /// @param type vector subtype
-    /// @return the tint AST type for a 4-element vector of `type`.
-    const ast::Vector* vec4(const ast::Type* type) const {
-      return vec(type, 4u);
-    }
-
-    /// @param n vector width in elements
-    /// @return the tint AST type for a `n`-element vector of `type`.
+    /// Creates a new ast::Node owned by the ProgramBuilder, injecting the current
+    /// Source as set by the last call to SetSource() as the only argument to the
+    /// constructor.
+    /// When the ProgramBuilder is destructed, the ast::Node will also be
+    /// destructed.
+    /// @returns the node pointer
     template <typename T>
-    const ast::Vector* vec(uint32_t n) const {
-      return vec(Of<T>(), n);
+    traits::EnableIfIsType<T, ast::Node>* create() {
+        AssertNotMoved();
+        return ast_nodes_.Create<T>(id_, source_);
     }
 
-    /// @return the tint AST type for a 2-element vector of the C type `T`.
+    /// Creates a new ast::Node owned by the ProgramBuilder, injecting the current
+    /// Source as set by the last call to SetSource() as the first argument to the
+    /// constructor.
+    /// When the ProgramBuilder is destructed, the ast::Node will also be
+    /// destructed.
+    /// @param arg0 the first arguments to pass to the type constructor
+    /// @param args the remaining arguments to pass to the type constructor
+    /// @returns the node pointer
+    template <typename T, typename ARG0, typename... ARGS>
+    traits::EnableIf</* T is ast::Node and ARG0 is not Source */
+                     traits::IsTypeOrDerived<T, ast::Node> &&
+                         !traits::IsTypeOrDerived<ARG0, Source>,
+                     T>*
+    create(ARG0&& arg0, ARGS&&... args) {
+        AssertNotMoved();
+        return ast_nodes_.Create<T>(id_, source_, std::forward<ARG0>(arg0),
+                                    std::forward<ARGS>(args)...);
+    }
+
+    /// Creates a new sem::Node owned by the ProgramBuilder.
+    /// When the ProgramBuilder is destructed, the sem::Node will also be
+    /// destructed.
+    /// @param args the arguments to pass to the type constructor
+    /// @returns the node pointer
+    template <typename T, typename... ARGS>
+    traits::EnableIf<traits::IsTypeOrDerived<T, sem::Node> &&
+                         !traits::IsTypeOrDerived<T, sem::Type>,
+                     T>*
+    create(ARGS&&... args) {
+        AssertNotMoved();
+        return sem_nodes_.Create<T>(std::forward<ARGS>(args)...);
+    }
+
+    /// Creates a new sem::Type owned by the ProgramBuilder.
+    /// When the ProgramBuilder is destructed, owned ProgramBuilder and the
+    /// returned`Type` will also be destructed.
+    /// Types are unique (de-aliased), and so calling create() for the same `T`
+    /// and arguments will return the same pointer.
+    /// @warning Use this method to acquire a type only if all of its type
+    /// information is provided in the constructor arguments `args`.<br>
+    /// If the type requires additional configuration after construction that
+    /// affect its fundamental type, build the type with `std::make_unique`, make
+    /// any necessary alterations and then call unique_type() instead.
+    /// @param args the arguments to pass to the type constructor
+    /// @returns the de-aliased type pointer
+    template <typename T, typename... ARGS>
+    traits::EnableIfIsType<T, sem::Type>* create(ARGS&&... args) {
+        static_assert(std::is_base_of<sem::Type, T>::value, "T does not derive from sem::Type");
+        AssertNotMoved();
+        return types_.Get<T>(std::forward<ARGS>(args)...);
+    }
+
+    /// Marks this builder as moved, preventing any further use of the builder.
+    void MarkAsMoved();
+
+    //////////////////////////////////////////////////////////////////////////////
+    // TypesBuilder
+    //////////////////////////////////////////////////////////////////////////////
+
+    /// TypesBuilder holds basic `tint` types and methods for constructing
+    /// complex types.
+    class TypesBuilder {
+      public:
+        /// Constructor
+        /// @param builder the program builder
+        explicit TypesBuilder(ProgramBuilder* builder);
+
+        /// @return the tint AST type for the C type `T`.
+        template <typename T>
+        const ast::Type* Of() const {
+            return CToAST<T>::get(this);
+        }
+
+        /// @returns a boolean type
+        const ast::Bool* bool_() const { return builder->create<ast::Bool>(); }
+
+        /// @param source the Source of the node
+        /// @returns a boolean type
+        const ast::Bool* bool_(const Source& source) const {
+            return builder->create<ast::Bool>(source);
+        }
+
+        /// @returns a f32 type
+        const ast::F32* f32() const { return builder->create<ast::F32>(); }
+
+        /// @param source the Source of the node
+        /// @returns a f32 type
+        const ast::F32* f32(const Source& source) const {
+            return builder->create<ast::F32>(source);
+        }
+
+        /// @returns a i32 type
+        const ast::I32* i32() const { return builder->create<ast::I32>(); }
+
+        /// @param source the Source of the node
+        /// @returns a i32 type
+        const ast::I32* i32(const Source& source) const {
+            return builder->create<ast::I32>(source);
+        }
+
+        /// @returns a u32 type
+        const ast::U32* u32() const { return builder->create<ast::U32>(); }
+
+        /// @param source the Source of the node
+        /// @returns a u32 type
+        const ast::U32* u32(const Source& source) const {
+            return builder->create<ast::U32>(source);
+        }
+
+        /// @returns a void type
+        const ast::Void* void_() const { return builder->create<ast::Void>(); }
+
+        /// @param source the Source of the node
+        /// @returns a void type
+        const ast::Void* void_(const Source& source) const {
+            return builder->create<ast::Void>(source);
+        }
+
+        /// @param type vector subtype
+        /// @param n vector width in elements
+        /// @return the tint AST type for a `n`-element vector of `type`.
+        const ast::Vector* vec(const ast::Type* type, uint32_t n) const {
+            return builder->create<ast::Vector>(type, n);
+        }
+
+        /// @param source the Source of the node
+        /// @param type vector subtype
+        /// @param n vector width in elements
+        /// @return the tint AST type for a `n`-element vector of `type`.
+        const ast::Vector* vec(const Source& source, const ast::Type* type, uint32_t n) const {
+            return builder->create<ast::Vector>(source, type, n);
+        }
+
+        /// @param type vector subtype
+        /// @return the tint AST type for a 2-element vector of `type`.
+        const ast::Vector* vec2(const ast::Type* type) const { return vec(type, 2u); }
+
+        /// @param type vector subtype
+        /// @return the tint AST type for a 3-element vector of `type`.
+        const ast::Vector* vec3(const ast::Type* type) const { return vec(type, 3u); }
+
+        /// @param type vector subtype
+        /// @return the tint AST type for a 4-element vector of `type`.
+        const ast::Vector* vec4(const ast::Type* type) const { return vec(type, 4u); }
+
+        /// @param n vector width in elements
+        /// @return the tint AST type for a `n`-element vector of `type`.
+        template <typename T>
+        const ast::Vector* vec(uint32_t n) const {
+            return vec(Of<T>(), n);
+        }
+
+        /// @return the tint AST type for a 2-element vector of the C type `T`.
+        template <typename T>
+        const ast::Vector* vec2() const {
+            return vec2(Of<T>());
+        }
+
+        /// @return the tint AST type for a 3-element vector of the C type `T`.
+        template <typename T>
+        const ast::Vector* vec3() const {
+            return vec3(Of<T>());
+        }
+
+        /// @return the tint AST type for a 4-element vector of the C type `T`.
+        template <typename T>
+        const ast::Vector* vec4() const {
+            return vec4(Of<T>());
+        }
+
+        /// @param type matrix subtype
+        /// @param columns number of columns for the matrix
+        /// @param rows number of rows for the matrix
+        /// @return the tint AST type for a matrix of `type`
+        const ast::Matrix* mat(const ast::Type* type, uint32_t columns, uint32_t rows) const {
+            return builder->create<ast::Matrix>(type, rows, columns);
+        }
+
+        /// @param source the Source of the node
+        /// @param type matrix subtype
+        /// @param columns number of columns for the matrix
+        /// @param rows number of rows for the matrix
+        /// @return the tint AST type for a matrix of `type`
+        const ast::Matrix* mat(const Source& source,
+                               const ast::Type* type,
+                               uint32_t columns,
+                               uint32_t rows) const {
+            return builder->create<ast::Matrix>(source, type, rows, columns);
+        }
+
+        /// @param type matrix subtype
+        /// @return the tint AST type for a 2x3 matrix of `type`.
+        const ast::Matrix* mat2x2(const ast::Type* type) const { return mat(type, 2u, 2u); }
+
+        /// @param type matrix subtype
+        /// @return the tint AST type for a 2x3 matrix of `type`.
+        const ast::Matrix* mat2x3(const ast::Type* type) const { return mat(type, 2u, 3u); }
+
+        /// @param type matrix subtype
+        /// @return the tint AST type for a 2x4 matrix of `type`.
+        const ast::Matrix* mat2x4(const ast::Type* type) const { return mat(type, 2u, 4u); }
+
+        /// @param type matrix subtype
+        /// @return the tint AST type for a 3x2 matrix of `type`.
+        const ast::Matrix* mat3x2(const ast::Type* type) const { return mat(type, 3u, 2u); }
+
+        /// @param type matrix subtype
+        /// @return the tint AST type for a 3x3 matrix of `type`.
+        const ast::Matrix* mat3x3(const ast::Type* type) const { return mat(type, 3u, 3u); }
+
+        /// @param type matrix subtype
+        /// @return the tint AST type for a 3x4 matrix of `type`.
+        const ast::Matrix* mat3x4(const ast::Type* type) const { return mat(type, 3u, 4u); }
+
+        /// @param type matrix subtype
+        /// @return the tint AST type for a 4x2 matrix of `type`.
+        const ast::Matrix* mat4x2(const ast::Type* type) const { return mat(type, 4u, 2u); }
+
+        /// @param type matrix subtype
+        /// @return the tint AST type for a 4x3 matrix of `type`.
+        const ast::Matrix* mat4x3(const ast::Type* type) const { return mat(type, 4u, 3u); }
+
+        /// @param type matrix subtype
+        /// @return the tint AST type for a 4x4 matrix of `type`.
+        const ast::Matrix* mat4x4(const ast::Type* type) const { return mat(type, 4u, 4u); }
+
+        /// @param columns number of columns for the matrix
+        /// @param rows number of rows for the matrix
+        /// @return the tint AST type for a matrix of `type`
+        template <typename T>
+        const ast::Matrix* mat(uint32_t columns, uint32_t rows) const {
+            return mat(Of<T>(), columns, rows);
+        }
+
+        /// @return the tint AST type for a 2x3 matrix of the C type `T`.
+        template <typename T>
+        const ast::Matrix* mat2x2() const {
+            return mat2x2(Of<T>());
+        }
+
+        /// @return the tint AST type for a 2x3 matrix of the C type `T`.
+        template <typename T>
+        const ast::Matrix* mat2x3() const {
+            return mat2x3(Of<T>());
+        }
+
+        /// @return the tint AST type for a 2x4 matrix of the C type `T`.
+        template <typename T>
+        const ast::Matrix* mat2x4() const {
+            return mat2x4(Of<T>());
+        }
+
+        /// @return the tint AST type for a 3x2 matrix of the C type `T`.
+        template <typename T>
+        const ast::Matrix* mat3x2() const {
+            return mat3x2(Of<T>());
+        }
+
+        /// @return the tint AST type for a 3x3 matrix of the C type `T`.
+        template <typename T>
+        const ast::Matrix* mat3x3() const {
+            return mat3x3(Of<T>());
+        }
+
+        /// @return the tint AST type for a 3x4 matrix of the C type `T`.
+        template <typename T>
+        const ast::Matrix* mat3x4() const {
+            return mat3x4(Of<T>());
+        }
+
+        /// @return the tint AST type for a 4x2 matrix of the C type `T`.
+        template <typename T>
+        const ast::Matrix* mat4x2() const {
+            return mat4x2(Of<T>());
+        }
+
+        /// @return the tint AST type for a 4x3 matrix of the C type `T`.
+        template <typename T>
+        const ast::Matrix* mat4x3() const {
+            return mat4x3(Of<T>());
+        }
+
+        /// @return the tint AST type for a 4x4 matrix of the C type `T`.
+        template <typename T>
+        const ast::Matrix* mat4x4() const {
+            return mat4x4(Of<T>());
+        }
+
+        /// @param subtype the array element type
+        /// @param n the array size. nullptr represents a runtime-array
+        /// @param attrs the optional attributes for the array
+        /// @return the tint AST type for a array of size `n` of type `T`
+        template <typename EXPR = ast::Expression*>
+        const ast::Array* array(const ast::Type* subtype,
+                                EXPR&& n = nullptr,
+                                ast::AttributeList attrs = {}) const {
+            return builder->create<ast::Array>(subtype, builder->Expr(std::forward<EXPR>(n)),
+                                               attrs);
+        }
+
+        /// @param source the Source of the node
+        /// @param subtype the array element type
+        /// @param n the array size. nullptr represents a runtime-array
+        /// @param attrs the optional attributes for the array
+        /// @return the tint AST type for a array of size `n` of type `T`
+        template <typename EXPR = ast::Expression*>
+        const ast::Array* array(const Source& source,
+                                const ast::Type* subtype,
+                                EXPR&& n = nullptr,
+                                ast::AttributeList attrs = {}) const {
+            return builder->create<ast::Array>(source, subtype,
+                                               builder->Expr(std::forward<EXPR>(n)), attrs);
+        }
+
+        /// @param subtype the array element type
+        /// @param n the array size. nullptr represents a runtime-array
+        /// @param stride the array stride. 0 represents implicit stride
+        /// @return the tint AST type for a array of size `n` of type `T`
+        template <typename EXPR>
+        const ast::Array* array(const ast::Type* subtype, EXPR&& n, uint32_t stride) const {
+            ast::AttributeList attrs;
+            if (stride) {
+                attrs.emplace_back(builder->create<ast::StrideAttribute>(stride));
+            }
+            return array(subtype, std::forward<EXPR>(n), std::move(attrs));
+        }
+
+        /// @param source the Source of the node
+        /// @param subtype the array element type
+        /// @param n the array size. nullptr represents a runtime-array
+        /// @param stride the array stride. 0 represents implicit stride
+        /// @return the tint AST type for a array of size `n` of type `T`
+        template <typename EXPR>
+        const ast::Array* array(const Source& source,
+                                const ast::Type* subtype,
+                                EXPR&& n,
+                                uint32_t stride) const {
+            ast::AttributeList attrs;
+            if (stride) {
+                attrs.emplace_back(builder->create<ast::StrideAttribute>(stride));
+            }
+            return array(source, subtype, std::forward<EXPR>(n), std::move(attrs));
+        }
+
+        /// @return the tint AST type for a runtime-sized array of type `T`
+        template <typename T>
+        const ast::Array* array() const {
+            return array(Of<T>(), nullptr);
+        }
+
+        /// @return the tint AST type for an array of size `N` of type `T`
+        template <typename T, int N>
+        const ast::Array* array() const {
+            return array(Of<T>(), builder->Expr(tint::u32(N)));
+        }
+
+        /// @param stride the array stride
+        /// @return the tint AST type for a runtime-sized array of type `T`
+        template <typename T>
+        const ast::Array* array(uint32_t stride) const {
+            return array(Of<T>(), nullptr, stride);
+        }
+
+        /// @param stride the array stride
+        /// @return the tint AST type for an array of size `N` of type `T`
+        template <typename T, int N>
+        const ast::Array* array(uint32_t stride) const {
+            return array(Of<T>(), builder->Expr(tint::u32(N)), stride);
+        }
+
+        /// Creates a type name
+        /// @param name the name
+        /// @returns the type name
+        template <typename NAME>
+        const ast::TypeName* type_name(NAME&& name) const {
+            return builder->create<ast::TypeName>(builder->Sym(std::forward<NAME>(name)));
+        }
+
+        /// Creates a type name
+        /// @param source the Source of the node
+        /// @param name the name
+        /// @returns the type name
+        template <typename NAME>
+        const ast::TypeName* type_name(const Source& source, NAME&& name) const {
+            return builder->create<ast::TypeName>(source, builder->Sym(std::forward<NAME>(name)));
+        }
+
+        /// Creates an alias type
+        /// @param name the alias name
+        /// @param type the alias type
+        /// @returns the alias pointer
+        template <typename NAME>
+        const ast::Alias* alias(NAME&& name, const ast::Type* type) const {
+            auto sym = builder->Sym(std::forward<NAME>(name));
+            return builder->create<ast::Alias>(sym, type);
+        }
+
+        /// Creates an alias type
+        /// @param source the Source of the node
+        /// @param name the alias name
+        /// @param type the alias type
+        /// @returns the alias pointer
+        template <typename NAME>
+        const ast::Alias* alias(const Source& source, NAME&& name, const ast::Type* type) const {
+            auto sym = builder->Sym(std::forward<NAME>(name));
+            return builder->create<ast::Alias>(source, sym, type);
+        }
+
+        /// @param type the type of the pointer
+        /// @param storage_class the storage class of the pointer
+        /// @param access the optional access control of the pointer
+        /// @return the pointer to `type` with the given ast::StorageClass
+        const ast::Pointer* pointer(const ast::Type* type,
+                                    ast::StorageClass storage_class,
+                                    ast::Access access = ast::Access::kUndefined) const {
+            return builder->create<ast::Pointer>(type, storage_class, access);
+        }
+
+        /// @param source the Source of the node
+        /// @param type the type of the pointer
+        /// @param storage_class the storage class of the pointer
+        /// @param access the optional access control of the pointer
+        /// @return the pointer to `type` with the given ast::StorageClass
+        const ast::Pointer* pointer(const Source& source,
+                                    const ast::Type* type,
+                                    ast::StorageClass storage_class,
+                                    ast::Access access = ast::Access::kUndefined) const {
+            return builder->create<ast::Pointer>(source, type, storage_class, access);
+        }
+
+        /// @param storage_class the storage class of the pointer
+        /// @param access the optional access control of the pointer
+        /// @return the pointer to type `T` with the given ast::StorageClass.
+        template <typename T>
+        const ast::Pointer* pointer(ast::StorageClass storage_class,
+                                    ast::Access access = ast::Access::kUndefined) const {
+            return pointer(Of<T>(), storage_class, access);
+        }
+
+        /// @param source the Source of the node
+        /// @param type the type of the atomic
+        /// @return the atomic to `type`
+        const ast::Atomic* atomic(const Source& source, const ast::Type* type) const {
+            return builder->create<ast::Atomic>(source, type);
+        }
+
+        /// @param type the type of the atomic
+        /// @return the atomic to `type`
+        const ast::Atomic* atomic(const ast::Type* type) const {
+            return builder->create<ast::Atomic>(type);
+        }
+
+        /// @return the atomic to type `T`
+        template <typename T>
+        const ast::Atomic* atomic() const {
+            return atomic(Of<T>());
+        }
+
+        /// @param kind the kind of sampler
+        /// @returns the sampler
+        const ast::Sampler* sampler(ast::SamplerKind kind) const {
+            return builder->create<ast::Sampler>(kind);
+        }
+
+        /// @param source the Source of the node
+        /// @param kind the kind of sampler
+        /// @returns the sampler
+        const ast::Sampler* sampler(const Source& source, ast::SamplerKind kind) const {
+            return builder->create<ast::Sampler>(source, kind);
+        }
+
+        /// @param dims the dimensionality of the texture
+        /// @returns the depth texture
+        const ast::DepthTexture* depth_texture(ast::TextureDimension dims) const {
+            return builder->create<ast::DepthTexture>(dims);
+        }
+
+        /// @param source the Source of the node
+        /// @param dims the dimensionality of the texture
+        /// @returns the depth texture
+        const ast::DepthTexture* depth_texture(const Source& source,
+                                               ast::TextureDimension dims) const {
+            return builder->create<ast::DepthTexture>(source, dims);
+        }
+
+        /// @param dims the dimensionality of the texture
+        /// @returns the multisampled depth texture
+        const ast::DepthMultisampledTexture* depth_multisampled_texture(
+            ast::TextureDimension dims) const {
+            return builder->create<ast::DepthMultisampledTexture>(dims);
+        }
+
+        /// @param source the Source of the node
+        /// @param dims the dimensionality of the texture
+        /// @returns the multisampled depth texture
+        const ast::DepthMultisampledTexture* depth_multisampled_texture(
+            const Source& source,
+            ast::TextureDimension dims) const {
+            return builder->create<ast::DepthMultisampledTexture>(source, dims);
+        }
+
+        /// @param dims the dimensionality of the texture
+        /// @param subtype the texture subtype.
+        /// @returns the sampled texture
+        const ast::SampledTexture* sampled_texture(ast::TextureDimension dims,
+                                                   const ast::Type* subtype) const {
+            return builder->create<ast::SampledTexture>(dims, subtype);
+        }
+
+        /// @param source the Source of the node
+        /// @param dims the dimensionality of the texture
+        /// @param subtype the texture subtype.
+        /// @returns the sampled texture
+        const ast::SampledTexture* sampled_texture(const Source& source,
+                                                   ast::TextureDimension dims,
+                                                   const ast::Type* subtype) const {
+            return builder->create<ast::SampledTexture>(source, dims, subtype);
+        }
+
+        /// @param dims the dimensionality of the texture
+        /// @param subtype the texture subtype.
+        /// @returns the multisampled texture
+        const ast::MultisampledTexture* multisampled_texture(ast::TextureDimension dims,
+                                                             const ast::Type* subtype) const {
+            return builder->create<ast::MultisampledTexture>(dims, subtype);
+        }
+
+        /// @param source the Source of the node
+        /// @param dims the dimensionality of the texture
+        /// @param subtype the texture subtype.
+        /// @returns the multisampled texture
+        const ast::MultisampledTexture* multisampled_texture(const Source& source,
+                                                             ast::TextureDimension dims,
+                                                             const ast::Type* subtype) const {
+            return builder->create<ast::MultisampledTexture>(source, dims, subtype);
+        }
+
+        /// @param dims the dimensionality of the texture
+        /// @param format the texel format of the texture
+        /// @param access the access control of the texture
+        /// @returns the storage texture
+        const ast::StorageTexture* storage_texture(ast::TextureDimension dims,
+                                                   ast::TexelFormat format,
+                                                   ast::Access access) const {
+            auto* subtype = ast::StorageTexture::SubtypeFor(format, *builder);
+            return builder->create<ast::StorageTexture>(dims, format, subtype, access);
+        }
+
+        /// @param source the Source of the node
+        /// @param dims the dimensionality of the texture
+        /// @param format the texel format of the texture
+        /// @param access the access control of the texture
+        /// @returns the storage texture
+        const ast::StorageTexture* storage_texture(const Source& source,
+                                                   ast::TextureDimension dims,
+                                                   ast::TexelFormat format,
+                                                   ast::Access access) const {
+            auto* subtype = ast::StorageTexture::SubtypeFor(format, *builder);
+            return builder->create<ast::StorageTexture>(source, dims, format, subtype, access);
+        }
+
+        /// @returns the external texture
+        const ast::ExternalTexture* external_texture() const {
+            return builder->create<ast::ExternalTexture>();
+        }
+
+        /// @param source the Source of the node
+        /// @returns the external texture
+        const ast::ExternalTexture* external_texture(const Source& source) const {
+            return builder->create<ast::ExternalTexture>(source);
+        }
+
+        /// Constructs a TypeName for the type declaration.
+        /// @param type the type
+        /// @return either type or a pointer to a new ast::TypeName
+        const ast::TypeName* Of(const ast::TypeDecl* type) const;
+
+        /// The ProgramBuilder
+        ProgramBuilder* const builder;
+
+      private:
+        /// CToAST<T> is specialized for various `T` types and each specialization
+        /// contains a single static `get()` method for obtaining the corresponding
+        /// AST type for the C type `T`.
+        /// `get()` has the signature:
+        ///    `static const ast::Type* get(Types* t)`
+        template <typename T>
+        struct CToAST {};
+    };
+
+    //////////////////////////////////////////////////////////////////////////////
+    // AST helper methods
+    //////////////////////////////////////////////////////////////////////////////
+
+    /// @return a new unnamed symbol
+    Symbol Sym() { return Symbols().New(); }
+
+    /// @param name the symbol string
+    /// @return a Symbol with the given name
+    Symbol Sym(const std::string& name) { return Symbols().Register(name); }
+
+    /// @param sym the symbol
+    /// @return `sym`
+    Symbol Sym(Symbol sym) { return sym; }
+
+    /// @param expr the expression
+    /// @return expr
     template <typename T>
-    const ast::Vector* vec2() const {
-      return vec2(Of<T>());
+    traits::EnableIfIsType<T, ast::Expression>* Expr(T* expr) {
+        return expr;
     }
 
-    /// @return the tint AST type for a 3-element vector of the C type `T`.
-    template <typename T>
-    const ast::Vector* vec3() const {
-      return vec3(Of<T>());
+    /// Passthrough for nullptr
+    /// @return nullptr
+    const ast::IdentifierExpression* Expr(std::nullptr_t) { return nullptr; }
+
+    /// @param source the source information
+    /// @param symbol the identifier symbol
+    /// @return an ast::IdentifierExpression with the given symbol
+    const ast::IdentifierExpression* Expr(const Source& source, Symbol symbol) {
+        return create<ast::IdentifierExpression>(source, symbol);
     }
 
-    /// @return the tint AST type for a 4-element vector of the C type `T`.
-    template <typename T>
-    const ast::Vector* vec4() const {
-      return vec4(Of<T>());
+    /// @param symbol the identifier symbol
+    /// @return an ast::IdentifierExpression with the given symbol
+    const ast::IdentifierExpression* Expr(Symbol symbol) {
+        return create<ast::IdentifierExpression>(symbol);
     }
 
-    /// @param type matrix subtype
-    /// @param columns number of columns for the matrix
-    /// @param rows number of rows for the matrix
-    /// @return the tint AST type for a matrix of `type`
-    const ast::Matrix* mat(const ast::Type* type,
-                           uint32_t columns,
-                           uint32_t rows) const {
-      return builder->create<ast::Matrix>(type, rows, columns);
+    /// @param source the source information
+    /// @param variable the AST variable
+    /// @return an ast::IdentifierExpression with the variable's symbol
+    const ast::IdentifierExpression* Expr(const Source& source, const ast::Variable* variable) {
+        return create<ast::IdentifierExpression>(source, variable->symbol);
     }
 
-    /// @param source the Source of the node
-    /// @param type matrix subtype
-    /// @param columns number of columns for the matrix
-    /// @param rows number of rows for the matrix
-    /// @return the tint AST type for a matrix of `type`
-    const ast::Matrix* mat(const Source& source,
-                           const ast::Type* type,
-                           uint32_t columns,
-                           uint32_t rows) const {
-      return builder->create<ast::Matrix>(source, type, rows, columns);
+    /// @param variable the AST variable
+    /// @return an ast::IdentifierExpression with the variable's symbol
+    const ast::IdentifierExpression* Expr(const ast::Variable* variable) {
+        return create<ast::IdentifierExpression>(variable->symbol);
     }
 
-    /// @param type matrix subtype
-    /// @return the tint AST type for a 2x3 matrix of `type`.
-    const ast::Matrix* mat2x2(const ast::Type* type) const {
-      return mat(type, 2u, 2u);
+    /// @param source the source information
+    /// @param name the identifier name
+    /// @return an ast::IdentifierExpression with the given name
+    const ast::IdentifierExpression* Expr(const Source& source, const char* name) {
+        return create<ast::IdentifierExpression>(source, Symbols().Register(name));
     }
 
-    /// @param type matrix subtype
-    /// @return the tint AST type for a 2x3 matrix of `type`.
-    const ast::Matrix* mat2x3(const ast::Type* type) const {
-      return mat(type, 2u, 3u);
+    /// @param name the identifier name
+    /// @return an ast::IdentifierExpression with the given name
+    const ast::IdentifierExpression* Expr(const char* name) {
+        return create<ast::IdentifierExpression>(Symbols().Register(name));
     }
 
-    /// @param type matrix subtype
-    /// @return the tint AST type for a 2x4 matrix of `type`.
-    const ast::Matrix* mat2x4(const ast::Type* type) const {
-      return mat(type, 2u, 4u);
+    /// @param source the source information
+    /// @param name the identifier name
+    /// @return an ast::IdentifierExpression with the given name
+    const ast::IdentifierExpression* Expr(const Source& source, const std::string& name) {
+        return create<ast::IdentifierExpression>(source, Symbols().Register(name));
     }
 
-    /// @param type matrix subtype
-    /// @return the tint AST type for a 3x2 matrix of `type`.
-    const ast::Matrix* mat3x2(const ast::Type* type) const {
-      return mat(type, 3u, 2u);
+    /// @param name the identifier name
+    /// @return an ast::IdentifierExpression with the given name
+    const ast::IdentifierExpression* Expr(const std::string& name) {
+        return create<ast::IdentifierExpression>(Symbols().Register(name));
     }
 
-    /// @param type matrix subtype
-    /// @return the tint AST type for a 3x3 matrix of `type`.
-    const ast::Matrix* mat3x3(const ast::Type* type) const {
-      return mat(type, 3u, 3u);
+    /// @param source the source information
+    /// @param value the boolean value
+    /// @return a Scalar constructor for the given value
+    const ast::BoolLiteralExpression* Expr(const Source& source, bool value) {
+        return create<ast::BoolLiteralExpression>(source, value);
     }
 
-    /// @param type matrix subtype
-    /// @return the tint AST type for a 3x4 matrix of `type`.
-    const ast::Matrix* mat3x4(const ast::Type* type) const {
-      return mat(type, 3u, 4u);
+    /// @param value the boolean value
+    /// @return a Scalar constructor for the given value
+    const ast::BoolLiteralExpression* Expr(bool value) {
+        return create<ast::BoolLiteralExpression>(value);
     }
 
-    /// @param type matrix subtype
-    /// @return the tint AST type for a 4x2 matrix of `type`.
-    const ast::Matrix* mat4x2(const ast::Type* type) const {
-      return mat(type, 4u, 2u);
+    /// @param source the source information
+    /// @param value the float value
+    /// @return a Scalar constructor for the given value
+    const ast::FloatLiteralExpression* Expr(const Source& source, f32 value) {
+        return create<ast::FloatLiteralExpression>(source, value);
     }
 
-    /// @param type matrix subtype
-    /// @return the tint AST type for a 4x3 matrix of `type`.
-    const ast::Matrix* mat4x3(const ast::Type* type) const {
-      return mat(type, 4u, 3u);
+    /// @param value the float value
+    /// @return a Scalar constructor for the given value
+    const ast::FloatLiteralExpression* Expr(f32 value) {
+        return create<ast::FloatLiteralExpression>(value);
     }
 
-    /// @param type matrix subtype
-    /// @return the tint AST type for a 4x4 matrix of `type`.
-    const ast::Matrix* mat4x4(const ast::Type* type) const {
-      return mat(type, 4u, 4u);
+    /// @param source the source information
+    /// @param value the integer value
+    /// @return a 'i'-suffixed IntLiteralExpression for the given value
+    const ast::IntLiteralExpression* Expr(const Source& source, i32 value) {
+        return create<ast::IntLiteralExpression>(source, value,
+                                                 ast::IntLiteralExpression::Suffix::kI);
     }
 
-    /// @param columns number of columns for the matrix
-    /// @param rows number of rows for the matrix
-    /// @return the tint AST type for a matrix of `type`
-    template <typename T>
-    const ast::Matrix* mat(uint32_t columns, uint32_t rows) const {
-      return mat(Of<T>(), columns, rows);
+    /// @param value the integer value
+    /// @return a 'i'-suffixed IntLiteralExpression for the given value
+    const ast::IntLiteralExpression* Expr(i32 value) {
+        return create<ast::IntLiteralExpression>(value, ast::IntLiteralExpression::Suffix::kI);
     }
 
-    /// @return the tint AST type for a 2x3 matrix of the C type `T`.
-    template <typename T>
-    const ast::Matrix* mat2x2() const {
-      return mat2x2(Of<T>());
+    /// @param source the source information
+    /// @param value the unsigned int value
+    /// @return a 'u'-suffixed IntLiteralExpression for the given value
+    const ast::IntLiteralExpression* Expr(const Source& source, u32 value) {
+        return create<ast::IntLiteralExpression>(source, value,
+                                                 ast::IntLiteralExpression::Suffix::kU);
     }
 
-    /// @return the tint AST type for a 2x3 matrix of the C type `T`.
-    template <typename T>
-    const ast::Matrix* mat2x3() const {
-      return mat2x3(Of<T>());
+    /// @param value the unsigned int value
+    /// @return a 'u'-suffixed IntLiteralExpression for the given value
+    const ast::IntLiteralExpression* Expr(u32 value) {
+        return create<ast::IntLiteralExpression>(value, ast::IntLiteralExpression::Suffix::kU);
     }
 
-    /// @return the tint AST type for a 2x4 matrix of the C type `T`.
-    template <typename T>
-    const ast::Matrix* mat2x4() const {
-      return mat2x4(Of<T>());
+    /// Converts `arg` to an `ast::Expression` using `Expr()`, then appends it to
+    /// `list`.
+    /// @param list the list to append too
+    /// @param arg the arg to create
+    template <typename ARG>
+    void Append(ast::ExpressionList& list, ARG&& arg) {
+        list.emplace_back(Expr(std::forward<ARG>(arg)));
     }
 
-    /// @return the tint AST type for a 3x2 matrix of the C type `T`.
-    template <typename T>
-    const ast::Matrix* mat3x2() const {
-      return mat3x2(Of<T>());
+    /// Converts `arg0` and `args` to `ast::Expression`s using `Expr()`,
+    /// then appends them to `list`.
+    /// @param list the list to append too
+    /// @param arg0 the first argument
+    /// @param args the rest of the arguments
+    template <typename ARG0, typename... ARGS>
+    void Append(ast::ExpressionList& list, ARG0&& arg0, ARGS&&... args) {
+        Append(list, std::forward<ARG0>(arg0));
+        Append(list, std::forward<ARGS>(args)...);
     }
 
-    /// @return the tint AST type for a 3x3 matrix of the C type `T`.
-    template <typename T>
-    const ast::Matrix* mat3x3() const {
-      return mat3x3(Of<T>());
+    /// @return an empty list of expressions
+    ast::ExpressionList ExprList() { return {}; }
+
+    /// @param args the list of expressions
+    /// @return the list of expressions converted to `ast::Expression`s using
+    /// `Expr()`,
+    template <typename... ARGS>
+    ast::ExpressionList ExprList(ARGS&&... args) {
+        ast::ExpressionList list;
+        list.reserve(sizeof...(args));
+        Append(list, std::forward<ARGS>(args)...);
+        return list;
     }
 
-    /// @return the tint AST type for a 3x4 matrix of the C type `T`.
-    template <typename T>
-    const ast::Matrix* mat3x4() const {
-      return mat3x4(Of<T>());
+    /// @param list the list of expressions
+    /// @return `list`
+    ast::ExpressionList ExprList(ast::ExpressionList list) { return list; }
+
+    /// @param args the arguments for the type constructor
+    /// @return an `ast::CallExpression` of type `ty`, with the values
+    /// of `args` converted to `ast::Expression`s using `Expr()`
+    template <typename T, typename... ARGS>
+    const ast::CallExpression* Construct(ARGS&&... args) {
+        return Construct(ty.Of<T>(), std::forward<ARGS>(args)...);
     }
 
-    /// @return the tint AST type for a 4x2 matrix of the C type `T`.
-    template <typename T>
-    const ast::Matrix* mat4x2() const {
-      return mat4x2(Of<T>());
+    /// @param type the type to construct
+    /// @param args the arguments for the constructor
+    /// @return an `ast::CallExpression` of `type` constructed with the
+    /// values `args`.
+    template <typename... ARGS>
+    const ast::CallExpression* Construct(const ast::Type* type, ARGS&&... args) {
+        return Construct(source_, type, std::forward<ARGS>(args)...);
     }
 
-    /// @return the tint AST type for a 4x3 matrix of the C type `T`.
-    template <typename T>
-    const ast::Matrix* mat4x3() const {
-      return mat4x3(Of<T>());
+    /// @param source the source information
+    /// @param type the type to construct
+    /// @param args the arguments for the constructor
+    /// @return an `ast::CallExpression` of `type` constructed with the
+    /// values `args`.
+    template <typename... ARGS>
+    const ast::CallExpression* Construct(const Source& source,
+                                         const ast::Type* type,
+                                         ARGS&&... args) {
+        return create<ast::CallExpression>(source, type, ExprList(std::forward<ARGS>(args)...));
     }
 
-    /// @return the tint AST type for a 4x4 matrix of the C type `T`.
-    template <typename T>
-    const ast::Matrix* mat4x4() const {
-      return mat4x4(Of<T>());
+    /// @param expr the expression for the bitcast
+    /// @return an `ast::BitcastExpression` of type `ty`, with the values of
+    /// `expr` converted to `ast::Expression`s using `Expr()`
+    template <typename T, typename EXPR>
+    const ast::BitcastExpression* Bitcast(EXPR&& expr) {
+        return Bitcast(ty.Of<T>(), std::forward<EXPR>(expr));
     }
 
-    /// @param subtype the array element type
-    /// @param n the array size. nullptr represents a runtime-array
-    /// @param attrs the optional attributes for the array
-    /// @return the tint AST type for a array of size `n` of type `T`
-    template <typename EXPR = ast::Expression*>
-    const ast::Array* array(const ast::Type* subtype,
-                            EXPR&& n = nullptr,
-                            ast::AttributeList attrs = {}) const {
-      return builder->create<ast::Array>(
-          subtype, builder->Expr(std::forward<EXPR>(n)), attrs);
-    }
-
-    /// @param source the Source of the node
-    /// @param subtype the array element type
-    /// @param n the array size. nullptr represents a runtime-array
-    /// @param attrs the optional attributes for the array
-    /// @return the tint AST type for a array of size `n` of type `T`
-    template <typename EXPR = ast::Expression*>
-    const ast::Array* array(const Source& source,
-                            const ast::Type* subtype,
-                            EXPR&& n = nullptr,
-                            ast::AttributeList attrs = {}) const {
-      return builder->create<ast::Array>(
-          source, subtype, builder->Expr(std::forward<EXPR>(n)), attrs);
-    }
-
-    /// @param subtype the array element type
-    /// @param n the array size. nullptr represents a runtime-array
-    /// @param stride the array stride. 0 represents implicit stride
-    /// @return the tint AST type for a array of size `n` of type `T`
+    /// @param type the type to cast to
+    /// @param expr the expression for the bitcast
+    /// @return an `ast::BitcastExpression` of `type` constructed with the values
+    /// `expr`.
     template <typename EXPR>
-    const ast::Array* array(const ast::Type* subtype,
-                            EXPR&& n,
-                            uint32_t stride) const {
-      ast::AttributeList attrs;
-      if (stride) {
-        attrs.emplace_back(builder->create<ast::StrideAttribute>(stride));
-      }
-      return array(subtype, std::forward<EXPR>(n), std::move(attrs));
+    const ast::BitcastExpression* Bitcast(const ast::Type* type, EXPR&& expr) {
+        return create<ast::BitcastExpression>(type, Expr(std::forward<EXPR>(expr)));
     }
 
-    /// @param source the Source of the node
-    /// @param subtype the array element type
-    /// @param n the array size. nullptr represents a runtime-array
-    /// @param stride the array stride. 0 represents implicit stride
-    /// @return the tint AST type for a array of size `n` of type `T`
+    /// @param source the source information
+    /// @param type the type to cast to
+    /// @param expr the expression for the bitcast
+    /// @return an `ast::BitcastExpression` of `type` constructed with the values
+    /// `expr`.
     template <typename EXPR>
-    const ast::Array* array(const Source& source,
-                            const ast::Type* subtype,
-                            EXPR&& n,
-                            uint32_t stride) const {
-      ast::AttributeList attrs;
-      if (stride) {
-        attrs.emplace_back(builder->create<ast::StrideAttribute>(stride));
-      }
-      return array(source, subtype, std::forward<EXPR>(n), std::move(attrs));
+    const ast::BitcastExpression* Bitcast(const Source& source,
+                                          const ast::Type* type,
+                                          EXPR&& expr) {
+        return create<ast::BitcastExpression>(source, type, Expr(std::forward<EXPR>(expr)));
     }
 
-    /// @return the tint AST type for a runtime-sized array of type `T`
-    template <typename T>
-    const ast::Array* array() const {
-      return array(Of<T>(), nullptr);
+    /// @param args the arguments for the vector constructor
+    /// @param type the vector type
+    /// @param size the vector size
+    /// @return an `ast::CallExpression` of a `size`-element vector of
+    /// type `type`, constructed with the values `args`.
+    template <typename... ARGS>
+    const ast::CallExpression* vec(const ast::Type* type, uint32_t size, ARGS&&... args) {
+        return Construct(ty.vec(type, size), std::forward<ARGS>(args)...);
     }
 
-    /// @return the tint AST type for an array of size `N` of type `T`
-    template <typename T, int N>
-    const ast::Array* array() const {
-      return array(Of<T>(), builder->Expr(N));
+    /// @param args the arguments for the vector constructor
+    /// @return an `ast::CallExpression` of a 2-element vector of type
+    /// `T`, constructed with the values `args`.
+    template <typename T, typename... ARGS>
+    const ast::CallExpression* vec2(ARGS&&... args) {
+        return Construct(ty.vec2<T>(), std::forward<ARGS>(args)...);
     }
 
-    /// @param stride the array stride
-    /// @return the tint AST type for a runtime-sized array of type `T`
-    template <typename T>
-    const ast::Array* array(uint32_t stride) const {
-      return array(Of<T>(), nullptr, stride);
+    /// @param args the arguments for the vector constructor
+    /// @return an `ast::CallExpression` of a 3-element vector of type
+    /// `T`, constructed with the values `args`.
+    template <typename T, typename... ARGS>
+    const ast::CallExpression* vec3(ARGS&&... args) {
+        return Construct(ty.vec3<T>(), std::forward<ARGS>(args)...);
     }
 
-    /// @param stride the array stride
-    /// @return the tint AST type for an array of size `N` of type `T`
-    template <typename T, int N>
-    const ast::Array* array(uint32_t stride) const {
-      return array(Of<T>(), builder->Expr(N), stride);
+    /// @param args the arguments for the vector constructor
+    /// @return an `ast::CallExpression` of a 4-element vector of type
+    /// `T`, constructed with the values `args`.
+    template <typename T, typename... ARGS>
+    const ast::CallExpression* vec4(ARGS&&... args) {
+        return Construct(ty.vec4<T>(), std::forward<ARGS>(args)...);
     }
 
-    /// Creates a type name
-    /// @param name the name
-    /// @returns the type name
+    /// @param args the arguments for the matrix constructor
+    /// @return an `ast::CallExpression` of a 2x2 matrix of type
+    /// `T`, constructed with the values `args`.
+    template <typename T, typename... ARGS>
+    const ast::CallExpression* mat2x2(ARGS&&... args) {
+        return Construct(ty.mat2x2<T>(), std::forward<ARGS>(args)...);
+    }
+
+    /// @param args the arguments for the matrix constructor
+    /// @return an `ast::CallExpression` of a 2x3 matrix of type
+    /// `T`, constructed with the values `args`.
+    template <typename T, typename... ARGS>
+    const ast::CallExpression* mat2x3(ARGS&&... args) {
+        return Construct(ty.mat2x3<T>(), std::forward<ARGS>(args)...);
+    }
+
+    /// @param args the arguments for the matrix constructor
+    /// @return an `ast::CallExpression` of a 2x4 matrix of type
+    /// `T`, constructed with the values `args`.
+    template <typename T, typename... ARGS>
+    const ast::CallExpression* mat2x4(ARGS&&... args) {
+        return Construct(ty.mat2x4<T>(), std::forward<ARGS>(args)...);
+    }
+
+    /// @param args the arguments for the matrix constructor
+    /// @return an `ast::CallExpression` of a 3x2 matrix of type
+    /// `T`, constructed with the values `args`.
+    template <typename T, typename... ARGS>
+    const ast::CallExpression* mat3x2(ARGS&&... args) {
+        return Construct(ty.mat3x2<T>(), std::forward<ARGS>(args)...);
+    }
+
+    /// @param args the arguments for the matrix constructor
+    /// @return an `ast::CallExpression` of a 3x3 matrix of type
+    /// `T`, constructed with the values `args`.
+    template <typename T, typename... ARGS>
+    const ast::CallExpression* mat3x3(ARGS&&... args) {
+        return Construct(ty.mat3x3<T>(), std::forward<ARGS>(args)...);
+    }
+
+    /// @param args the arguments for the matrix constructor
+    /// @return an `ast::CallExpression` of a 3x4 matrix of type
+    /// `T`, constructed with the values `args`.
+    template <typename T, typename... ARGS>
+    const ast::CallExpression* mat3x4(ARGS&&... args) {
+        return Construct(ty.mat3x4<T>(), std::forward<ARGS>(args)...);
+    }
+
+    /// @param args the arguments for the matrix constructor
+    /// @return an `ast::CallExpression` of a 4x2 matrix of type
+    /// `T`, constructed with the values `args`.
+    template <typename T, typename... ARGS>
+    const ast::CallExpression* mat4x2(ARGS&&... args) {
+        return Construct(ty.mat4x2<T>(), std::forward<ARGS>(args)...);
+    }
+
+    /// @param args the arguments for the matrix constructor
+    /// @return an `ast::CallExpression` of a 4x3 matrix of type
+    /// `T`, constructed with the values `args`.
+    template <typename T, typename... ARGS>
+    const ast::CallExpression* mat4x3(ARGS&&... args) {
+        return Construct(ty.mat4x3<T>(), std::forward<ARGS>(args)...);
+    }
+
+    /// @param args the arguments for the matrix constructor
+    /// @return an `ast::CallExpression` of a 4x4 matrix of type
+    /// `T`, constructed with the values `args`.
+    template <typename T, typename... ARGS>
+    const ast::CallExpression* mat4x4(ARGS&&... args) {
+        return Construct(ty.mat4x4<T>(), std::forward<ARGS>(args)...);
+    }
+
+    /// @param args the arguments for the array constructor
+    /// @return an `ast::CallExpression` of an array with element type
+    /// `T` and size `N`, constructed with the values `args`.
+    template <typename T, int N, typename... ARGS>
+    const ast::CallExpression* array(ARGS&&... args) {
+        return Construct(ty.array<T, N>(), std::forward<ARGS>(args)...);
+    }
+
+    /// @param subtype the array element type
+    /// @param n the array size. nullptr represents a runtime-array.
+    /// @param args the arguments for the array constructor
+    /// @return an `ast::CallExpression` of an array with element type
+    /// `subtype`, constructed with the values `args`.
+    template <typename EXPR, typename... ARGS>
+    const ast::CallExpression* array(const ast::Type* subtype, EXPR&& n, ARGS&&... args) {
+        return Construct(ty.array(subtype, std::forward<EXPR>(n)), std::forward<ARGS>(args)...);
+    }
+
+    /// @param name the variable name
+    /// @param type the variable type
+    /// @param optional the optional variable settings.
+    /// Can be any of the following, in any order:
+    ///   * ast::StorageClass   - specifies the variable storage class
+    ///   * ast::Access         - specifies the variable's access control
+    ///   * ast::Expression*    - specifies the variable's initializer expression
+    ///   * ast::AttributeList - specifies the variable's attributes
+    /// Note that repeated arguments of the same type will use the last argument's
+    /// value.
+    /// @returns a `ast::Variable` with the given name, type and additional
+    /// options
+    template <typename NAME, typename... OPTIONAL>
+    const ast::Variable* Var(NAME&& name, const ast::Type* type, OPTIONAL&&... optional) {
+        VarOptionals opts(std::forward<OPTIONAL>(optional)...);
+        return create<ast::Variable>(Sym(std::forward<NAME>(name)), opts.storage, opts.access, type,
+                                     false /* is_const */, false /* is_overridable */,
+                                     opts.constructor, std::move(opts.attributes));
+    }
+
+    /// @param source the variable source
+    /// @param name the variable name
+    /// @param type the variable type
+    /// @param optional the optional variable settings.
+    /// Can be any of the following, in any order:
+    ///   * ast::StorageClass   - specifies the variable storage class
+    ///   * ast::Access         - specifies the variable's access control
+    ///   * ast::Expression*    - specifies the variable's initializer expression
+    ///   * ast::AttributeList - specifies the variable's attributes
+    /// Note that repeated arguments of the same type will use the last argument's
+    /// value.
+    /// @returns a `ast::Variable` with the given name, storage and type
+    template <typename NAME, typename... OPTIONAL>
+    const ast::Variable* Var(const Source& source,
+                             NAME&& name,
+                             const ast::Type* type,
+                             OPTIONAL&&... optional) {
+        VarOptionals opts(std::forward<OPTIONAL>(optional)...);
+        return create<ast::Variable>(source, Sym(std::forward<NAME>(name)), opts.storage,
+                                     opts.access, type, false /* is_const */,
+                                     false /* is_overridable */, opts.constructor,
+                                     std::move(opts.attributes));
+    }
+
+    /// @param name the variable name
+    /// @param type the variable type
+    /// @param constructor constructor expression
+    /// @param attributes optional variable attributes
+    /// @returns an immutable `ast::Variable` with the given name and type
     template <typename NAME>
-    const ast::TypeName* type_name(NAME&& name) const {
-      return builder->create<ast::TypeName>(
-          builder->Sym(std::forward<NAME>(name)));
-    }
-
-    /// Creates a type name
-    /// @param source the Source of the node
-    /// @param name the name
-    /// @returns the type name
-    template <typename NAME>
-    const ast::TypeName* type_name(const Source& source, NAME&& name) const {
-      return builder->create<ast::TypeName>(
-          source, builder->Sym(std::forward<NAME>(name)));
-    }
-
-    /// Creates an alias type
-    /// @param name the alias name
-    /// @param type the alias type
-    /// @returns the alias pointer
-    template <typename NAME>
-    const ast::Alias* alias(NAME&& name, const ast::Type* type) const {
-      auto sym = builder->Sym(std::forward<NAME>(name));
-      return builder->create<ast::Alias>(sym, type);
-    }
-
-    /// Creates an alias type
-    /// @param source the Source of the node
-    /// @param name the alias name
-    /// @param type the alias type
-    /// @returns the alias pointer
-    template <typename NAME>
-    const ast::Alias* alias(const Source& source,
-                            NAME&& name,
-                            const ast::Type* type) const {
-      auto sym = builder->Sym(std::forward<NAME>(name));
-      return builder->create<ast::Alias>(source, sym, type);
-    }
-
-    /// @param type the type of the pointer
-    /// @param storage_class the storage class of the pointer
-    /// @param access the optional access control of the pointer
-    /// @return the pointer to `type` with the given ast::StorageClass
-    const ast::Pointer* pointer(
-        const ast::Type* type,
-        ast::StorageClass storage_class,
-        ast::Access access = ast::Access::kUndefined) const {
-      return builder->create<ast::Pointer>(type, storage_class, access);
-    }
-
-    /// @param source the Source of the node
-    /// @param type the type of the pointer
-    /// @param storage_class the storage class of the pointer
-    /// @param access the optional access control of the pointer
-    /// @return the pointer to `type` with the given ast::StorageClass
-    const ast::Pointer* pointer(
-        const Source& source,
-        const ast::Type* type,
-        ast::StorageClass storage_class,
-        ast::Access access = ast::Access::kUndefined) const {
-      return builder->create<ast::Pointer>(source, type, storage_class, access);
-    }
-
-    /// @param storage_class the storage class of the pointer
-    /// @param access the optional access control of the pointer
-    /// @return the pointer to type `T` with the given ast::StorageClass.
-    template <typename T>
-    const ast::Pointer* pointer(
-        ast::StorageClass storage_class,
-        ast::Access access = ast::Access::kUndefined) const {
-      return pointer(Of<T>(), storage_class, access);
-    }
-
-    /// @param source the Source of the node
-    /// @param type the type of the atomic
-    /// @return the atomic to `type`
-    const ast::Atomic* atomic(const Source& source,
-                              const ast::Type* type) const {
-      return builder->create<ast::Atomic>(source, type);
-    }
-
-    /// @param type the type of the atomic
-    /// @return the atomic to `type`
-    const ast::Atomic* atomic(const ast::Type* type) const {
-      return builder->create<ast::Atomic>(type);
-    }
-
-    /// @return the atomic to type `T`
-    template <typename T>
-    const ast::Atomic* atomic() const {
-      return atomic(Of<T>());
-    }
-
-    /// @param kind the kind of sampler
-    /// @returns the sampler
-    const ast::Sampler* sampler(ast::SamplerKind kind) const {
-      return builder->create<ast::Sampler>(kind);
-    }
-
-    /// @param source the Source of the node
-    /// @param kind the kind of sampler
-    /// @returns the sampler
-    const ast::Sampler* sampler(const Source& source,
-                                ast::SamplerKind kind) const {
-      return builder->create<ast::Sampler>(source, kind);
-    }
-
-    /// @param dims the dimensionality of the texture
-    /// @returns the depth texture
-    const ast::DepthTexture* depth_texture(ast::TextureDimension dims) const {
-      return builder->create<ast::DepthTexture>(dims);
-    }
-
-    /// @param source the Source of the node
-    /// @param dims the dimensionality of the texture
-    /// @returns the depth texture
-    const ast::DepthTexture* depth_texture(const Source& source,
-                                           ast::TextureDimension dims) const {
-      return builder->create<ast::DepthTexture>(source, dims);
-    }
-
-    /// @param dims the dimensionality of the texture
-    /// @returns the multisampled depth texture
-    const ast::DepthMultisampledTexture* depth_multisampled_texture(
-        ast::TextureDimension dims) const {
-      return builder->create<ast::DepthMultisampledTexture>(dims);
-    }
-
-    /// @param source the Source of the node
-    /// @param dims the dimensionality of the texture
-    /// @returns the multisampled depth texture
-    const ast::DepthMultisampledTexture* depth_multisampled_texture(
-        const Source& source,
-        ast::TextureDimension dims) const {
-      return builder->create<ast::DepthMultisampledTexture>(source, dims);
-    }
-
-    /// @param dims the dimensionality of the texture
-    /// @param subtype the texture subtype.
-    /// @returns the sampled texture
-    const ast::SampledTexture* sampled_texture(ast::TextureDimension dims,
-                                               const ast::Type* subtype) const {
-      return builder->create<ast::SampledTexture>(dims, subtype);
-    }
-
-    /// @param source the Source of the node
-    /// @param dims the dimensionality of the texture
-    /// @param subtype the texture subtype.
-    /// @returns the sampled texture
-    const ast::SampledTexture* sampled_texture(const Source& source,
-                                               ast::TextureDimension dims,
-                                               const ast::Type* subtype) const {
-      return builder->create<ast::SampledTexture>(source, dims, subtype);
-    }
-
-    /// @param dims the dimensionality of the texture
-    /// @param subtype the texture subtype.
-    /// @returns the multisampled texture
-    const ast::MultisampledTexture* multisampled_texture(
-        ast::TextureDimension dims,
-        const ast::Type* subtype) const {
-      return builder->create<ast::MultisampledTexture>(dims, subtype);
-    }
-
-    /// @param source the Source of the node
-    /// @param dims the dimensionality of the texture
-    /// @param subtype the texture subtype.
-    /// @returns the multisampled texture
-    const ast::MultisampledTexture* multisampled_texture(
-        const Source& source,
-        ast::TextureDimension dims,
-        const ast::Type* subtype) const {
-      return builder->create<ast::MultisampledTexture>(source, dims, subtype);
-    }
-
-    /// @param dims the dimensionality of the texture
-    /// @param format the texel format of the texture
-    /// @param access the access control of the texture
-    /// @returns the storage texture
-    const ast::StorageTexture* storage_texture(ast::TextureDimension dims,
-                                               ast::TexelFormat format,
-                                               ast::Access access) const {
-      auto* subtype = ast::StorageTexture::SubtypeFor(format, *builder);
-      return builder->create<ast::StorageTexture>(dims, format, subtype,
-                                                  access);
-    }
-
-    /// @param source the Source of the node
-    /// @param dims the dimensionality of the texture
-    /// @param format the texel format of the texture
-    /// @param access the access control of the texture
-    /// @returns the storage texture
-    const ast::StorageTexture* storage_texture(const Source& source,
-                                               ast::TextureDimension dims,
-                                               ast::TexelFormat format,
-                                               ast::Access access) const {
-      auto* subtype = ast::StorageTexture::SubtypeFor(format, *builder);
-      return builder->create<ast::StorageTexture>(source, dims, format, subtype,
-                                                  access);
-    }
-
-    /// @returns the external texture
-    const ast::ExternalTexture* external_texture() const {
-      return builder->create<ast::ExternalTexture>();
-    }
-
-    /// @param source the Source of the node
-    /// @returns the external texture
-    const ast::ExternalTexture* external_texture(const Source& source) const {
-      return builder->create<ast::ExternalTexture>(source);
-    }
-
-    /// Constructs a TypeName for the type declaration.
-    /// @param type the type
-    /// @return either type or a pointer to a new ast::TypeName
-    const ast::TypeName* Of(const ast::TypeDecl* type) const;
-
-    /// The ProgramBuilder
-    ProgramBuilder* const builder;
-
-   private:
-    /// CToAST<T> is specialized for various `T` types and each specialization
-    /// contains a single static `get()` method for obtaining the corresponding
-    /// AST type for the C type `T`.
-    /// `get()` has the signature:
-    ///    `static const ast::Type* get(Types* t)`
-    template <typename T>
-    struct CToAST {};
-  };
-
-  //////////////////////////////////////////////////////////////////////////////
-  // AST helper methods
-  //////////////////////////////////////////////////////////////////////////////
-
-  /// @return a new unnamed symbol
-  Symbol Sym() { return Symbols().New(); }
-
-  /// @param name the symbol string
-  /// @return a Symbol with the given name
-  Symbol Sym(const std::string& name) { return Symbols().Register(name); }
-
-  /// @param sym the symbol
-  /// @return `sym`
-  Symbol Sym(Symbol sym) { return sym; }
-
-  /// @param expr the expression
-  /// @return expr
-  template <typename T>
-  traits::EnableIfIsType<T, ast::Expression>* Expr(T* expr) {
-    return expr;
-  }
-
-  /// Passthrough for nullptr
-  /// @return nullptr
-  const ast::IdentifierExpression* Expr(std::nullptr_t) { return nullptr; }
-
-  /// @param source the source information
-  /// @param symbol the identifier symbol
-  /// @return an ast::IdentifierExpression with the given symbol
-  const ast::IdentifierExpression* Expr(const Source& source, Symbol symbol) {
-    return create<ast::IdentifierExpression>(source, symbol);
-  }
-
-  /// @param symbol the identifier symbol
-  /// @return an ast::IdentifierExpression with the given symbol
-  const ast::IdentifierExpression* Expr(Symbol symbol) {
-    return create<ast::IdentifierExpression>(symbol);
-  }
-
-  /// @param source the source information
-  /// @param variable the AST variable
-  /// @return an ast::IdentifierExpression with the variable's symbol
-  const ast::IdentifierExpression* Expr(const Source& source,
-                                        const ast::Variable* variable) {
-    return create<ast::IdentifierExpression>(source, variable->symbol);
-  }
-
-  /// @param variable the AST variable
-  /// @return an ast::IdentifierExpression with the variable's symbol
-  const ast::IdentifierExpression* Expr(const ast::Variable* variable) {
-    return create<ast::IdentifierExpression>(variable->symbol);
-  }
-
-  /// @param source the source information
-  /// @param name the identifier name
-  /// @return an ast::IdentifierExpression with the given name
-  const ast::IdentifierExpression* Expr(const Source& source,
-                                        const char* name) {
-    return create<ast::IdentifierExpression>(source, Symbols().Register(name));
-  }
-
-  /// @param name the identifier name
-  /// @return an ast::IdentifierExpression with the given name
-  const ast::IdentifierExpression* Expr(const char* name) {
-    return create<ast::IdentifierExpression>(Symbols().Register(name));
-  }
-
-  /// @param source the source information
-  /// @param name the identifier name
-  /// @return an ast::IdentifierExpression with the given name
-  const ast::IdentifierExpression* Expr(const Source& source,
-                                        const std::string& name) {
-    return create<ast::IdentifierExpression>(source, Symbols().Register(name));
-  }
-
-  /// @param name the identifier name
-  /// @return an ast::IdentifierExpression with the given name
-  const ast::IdentifierExpression* Expr(const std::string& name) {
-    return create<ast::IdentifierExpression>(Symbols().Register(name));
-  }
-
-  /// @param source the source information
-  /// @param value the boolean value
-  /// @return a Scalar constructor for the given value
-  const ast::BoolLiteralExpression* Expr(const Source& source, bool value) {
-    return create<ast::BoolLiteralExpression>(source, value);
-  }
-
-  /// @param value the boolean value
-  /// @return a Scalar constructor for the given value
-  const ast::BoolLiteralExpression* Expr(bool value) {
-    return create<ast::BoolLiteralExpression>(value);
-  }
-
-  /// @param source the source information
-  /// @param value the float value
-  /// @return a Scalar constructor for the given value
-  const ast::FloatLiteralExpression* Expr(const Source& source, f32 value) {
-    return create<ast::FloatLiteralExpression>(source, value);
-  }
-
-  /// @param value the float value
-  /// @return a Scalar constructor for the given value
-  const ast::FloatLiteralExpression* Expr(f32 value) {
-    return create<ast::FloatLiteralExpression>(value);
-  }
-
-  /// @param source the source information
-  /// @param value the integer value
-  /// @return a Scalar constructor for the given value
-  const ast::SintLiteralExpression* Expr(const Source& source, i32 value) {
-    return create<ast::SintLiteralExpression>(source, value);
-  }
-
-  /// @param value the integer value
-  /// @return a Scalar constructor for the given value
-  const ast::SintLiteralExpression* Expr(i32 value) {
-    return create<ast::SintLiteralExpression>(value);
-  }
-
-  /// @param source the source information
-  /// @param value the unsigned int value
-  /// @return a Scalar constructor for the given value
-  const ast::UintLiteralExpression* Expr(const Source& source, u32 value) {
-    return create<ast::UintLiteralExpression>(source, value);
-  }
-
-  /// @param value the unsigned int value
-  /// @return a Scalar constructor for the given value
-  const ast::UintLiteralExpression* Expr(u32 value) {
-    return create<ast::UintLiteralExpression>(value);
-  }
-
-  /// Converts `arg` to an `ast::Expression` using `Expr()`, then appends it to
-  /// `list`.
-  /// @param list the list to append too
-  /// @param arg the arg to create
-  template <typename ARG>
-  void Append(ast::ExpressionList& list, ARG&& arg) {
-    list.emplace_back(Expr(std::forward<ARG>(arg)));
-  }
-
-  /// Converts `arg0` and `args` to `ast::Expression`s using `Expr()`,
-  /// then appends them to `list`.
-  /// @param list the list to append too
-  /// @param arg0 the first argument
-  /// @param args the rest of the arguments
-  template <typename ARG0, typename... ARGS>
-  void Append(ast::ExpressionList& list, ARG0&& arg0, ARGS&&... args) {
-    Append(list, std::forward<ARG0>(arg0));
-    Append(list, std::forward<ARGS>(args)...);
-  }
-
-  /// @return an empty list of expressions
-  ast::ExpressionList ExprList() { return {}; }
-
-  /// @param args the list of expressions
-  /// @return the list of expressions converted to `ast::Expression`s using
-  /// `Expr()`,
-  template <typename... ARGS>
-  ast::ExpressionList ExprList(ARGS&&... args) {
-    ast::ExpressionList list;
-    list.reserve(sizeof...(args));
-    Append(list, std::forward<ARGS>(args)...);
-    return list;
-  }
-
-  /// @param list the list of expressions
-  /// @return `list`
-  ast::ExpressionList ExprList(ast::ExpressionList list) { return list; }
-
-  /// @param args the arguments for the type constructor
-  /// @return an `ast::CallExpression` of type `ty`, with the values
-  /// of `args` converted to `ast::Expression`s using `Expr()`
-  template <typename T, typename... ARGS>
-  const ast::CallExpression* Construct(ARGS&&... args) {
-    return Construct(ty.Of<T>(), std::forward<ARGS>(args)...);
-  }
-
-  /// @param type the type to construct
-  /// @param args the arguments for the constructor
-  /// @return an `ast::CallExpression` of `type` constructed with the
-  /// values `args`.
-  template <typename... ARGS>
-  const ast::CallExpression* Construct(const ast::Type* type, ARGS&&... args) {
-    return Construct(source_, type, std::forward<ARGS>(args)...);
-  }
-
-  /// @param source the source information
-  /// @param type the type to construct
-  /// @param args the arguments for the constructor
-  /// @return an `ast::CallExpression` of `type` constructed with the
-  /// values `args`.
-  template <typename... ARGS>
-  const ast::CallExpression* Construct(const Source& source,
-                                       const ast::Type* type,
-                                       ARGS&&... args) {
-    return create<ast::CallExpression>(source, type,
-                                       ExprList(std::forward<ARGS>(args)...));
-  }
-
-  /// @param expr the expression for the bitcast
-  /// @return an `ast::BitcastExpression` of type `ty`, with the values of
-  /// `expr` converted to `ast::Expression`s using `Expr()`
-  template <typename T, typename EXPR>
-  const ast::BitcastExpression* Bitcast(EXPR&& expr) {
-    return Bitcast(ty.Of<T>(), std::forward<EXPR>(expr));
-  }
-
-  /// @param type the type to cast to
-  /// @param expr the expression for the bitcast
-  /// @return an `ast::BitcastExpression` of `type` constructed with the values
-  /// `expr`.
-  template <typename EXPR>
-  const ast::BitcastExpression* Bitcast(const ast::Type* type, EXPR&& expr) {
-    return create<ast::BitcastExpression>(type, Expr(std::forward<EXPR>(expr)));
-  }
-
-  /// @param source the source information
-  /// @param type the type to cast to
-  /// @param expr the expression for the bitcast
-  /// @return an `ast::BitcastExpression` of `type` constructed with the values
-  /// `expr`.
-  template <typename EXPR>
-  const ast::BitcastExpression* Bitcast(const Source& source,
-                                        const ast::Type* type,
-                                        EXPR&& expr) {
-    return create<ast::BitcastExpression>(source, type,
-                                          Expr(std::forward<EXPR>(expr)));
-  }
-
-  /// @param args the arguments for the vector constructor
-  /// @param type the vector type
-  /// @param size the vector size
-  /// @return an `ast::CallExpression` of a `size`-element vector of
-  /// type `type`, constructed with the values `args`.
-  template <typename... ARGS>
-  const ast::CallExpression* vec(const ast::Type* type,
-                                 uint32_t size,
-                                 ARGS&&... args) {
-    return Construct(ty.vec(type, size), std::forward<ARGS>(args)...);
-  }
-
-  /// @param args the arguments for the vector constructor
-  /// @return an `ast::CallExpression` of a 2-element vector of type
-  /// `T`, constructed with the values `args`.
-  template <typename T, typename... ARGS>
-  const ast::CallExpression* vec2(ARGS&&... args) {
-    return Construct(ty.vec2<T>(), std::forward<ARGS>(args)...);
-  }
-
-  /// @param args the arguments for the vector constructor
-  /// @return an `ast::CallExpression` of a 3-element vector of type
-  /// `T`, constructed with the values `args`.
-  template <typename T, typename... ARGS>
-  const ast::CallExpression* vec3(ARGS&&... args) {
-    return Construct(ty.vec3<T>(), std::forward<ARGS>(args)...);
-  }
-
-  /// @param args the arguments for the vector constructor
-  /// @return an `ast::CallExpression` of a 4-element vector of type
-  /// `T`, constructed with the values `args`.
-  template <typename T, typename... ARGS>
-  const ast::CallExpression* vec4(ARGS&&... args) {
-    return Construct(ty.vec4<T>(), std::forward<ARGS>(args)...);
-  }
-
-  /// @param args the arguments for the matrix constructor
-  /// @return an `ast::CallExpression` of a 2x2 matrix of type
-  /// `T`, constructed with the values `args`.
-  template <typename T, typename... ARGS>
-  const ast::CallExpression* mat2x2(ARGS&&... args) {
-    return Construct(ty.mat2x2<T>(), std::forward<ARGS>(args)...);
-  }
-
-  /// @param args the arguments for the matrix constructor
-  /// @return an `ast::CallExpression` of a 2x3 matrix of type
-  /// `T`, constructed with the values `args`.
-  template <typename T, typename... ARGS>
-  const ast::CallExpression* mat2x3(ARGS&&... args) {
-    return Construct(ty.mat2x3<T>(), std::forward<ARGS>(args)...);
-  }
-
-  /// @param args the arguments for the matrix constructor
-  /// @return an `ast::CallExpression` of a 2x4 matrix of type
-  /// `T`, constructed with the values `args`.
-  template <typename T, typename... ARGS>
-  const ast::CallExpression* mat2x4(ARGS&&... args) {
-    return Construct(ty.mat2x4<T>(), std::forward<ARGS>(args)...);
-  }
-
-  /// @param args the arguments for the matrix constructor
-  /// @return an `ast::CallExpression` of a 3x2 matrix of type
-  /// `T`, constructed with the values `args`.
-  template <typename T, typename... ARGS>
-  const ast::CallExpression* mat3x2(ARGS&&... args) {
-    return Construct(ty.mat3x2<T>(), std::forward<ARGS>(args)...);
-  }
-
-  /// @param args the arguments for the matrix constructor
-  /// @return an `ast::CallExpression` of a 3x3 matrix of type
-  /// `T`, constructed with the values `args`.
-  template <typename T, typename... ARGS>
-  const ast::CallExpression* mat3x3(ARGS&&... args) {
-    return Construct(ty.mat3x3<T>(), std::forward<ARGS>(args)...);
-  }
-
-  /// @param args the arguments for the matrix constructor
-  /// @return an `ast::CallExpression` of a 3x4 matrix of type
-  /// `T`, constructed with the values `args`.
-  template <typename T, typename... ARGS>
-  const ast::CallExpression* mat3x4(ARGS&&... args) {
-    return Construct(ty.mat3x4<T>(), std::forward<ARGS>(args)...);
-  }
-
-  /// @param args the arguments for the matrix constructor
-  /// @return an `ast::CallExpression` of a 4x2 matrix of type
-  /// `T`, constructed with the values `args`.
-  template <typename T, typename... ARGS>
-  const ast::CallExpression* mat4x2(ARGS&&... args) {
-    return Construct(ty.mat4x2<T>(), std::forward<ARGS>(args)...);
-  }
-
-  /// @param args the arguments for the matrix constructor
-  /// @return an `ast::CallExpression` of a 4x3 matrix of type
-  /// `T`, constructed with the values `args`.
-  template <typename T, typename... ARGS>
-  const ast::CallExpression* mat4x3(ARGS&&... args) {
-    return Construct(ty.mat4x3<T>(), std::forward<ARGS>(args)...);
-  }
-
-  /// @param args the arguments for the matrix constructor
-  /// @return an `ast::CallExpression` of a 4x4 matrix of type
-  /// `T`, constructed with the values `args`.
-  template <typename T, typename... ARGS>
-  const ast::CallExpression* mat4x4(ARGS&&... args) {
-    return Construct(ty.mat4x4<T>(), std::forward<ARGS>(args)...);
-  }
-
-  /// @param args the arguments for the array constructor
-  /// @return an `ast::CallExpression` of an array with element type
-  /// `T` and size `N`, constructed with the values `args`.
-  template <typename T, int N, typename... ARGS>
-  const ast::CallExpression* array(ARGS&&... args) {
-    return Construct(ty.array<T, N>(), std::forward<ARGS>(args)...);
-  }
-
-  /// @param subtype the array element type
-  /// @param n the array size. nullptr represents a runtime-array.
-  /// @param args the arguments for the array constructor
-  /// @return an `ast::CallExpression` of an array with element type
-  /// `subtype`, constructed with the values `args`.
-  template <typename EXPR, typename... ARGS>
-  const ast::CallExpression* array(const ast::Type* subtype,
-                                   EXPR&& n,
-                                   ARGS&&... args) {
-    return Construct(ty.array(subtype, std::forward<EXPR>(n)),
-                     std::forward<ARGS>(args)...);
-  }
-
-  /// @param name the variable name
-  /// @param type the variable type
-  /// @param optional the optional variable settings.
-  /// Can be any of the following, in any order:
-  ///   * ast::StorageClass   - specifies the variable storage class
-  ///   * ast::Access         - specifies the variable's access control
-  ///   * ast::Expression*    - specifies the variable's initializer expression
-  ///   * ast::AttributeList - specifies the variable's attributes
-  /// Note that repeated arguments of the same type will use the last argument's
-  /// value.
-  /// @returns a `ast::Variable` with the given name, type and additional
-  /// options
-  template <typename NAME, typename... OPTIONAL>
-  const ast::Variable* Var(NAME&& name,
-                           const ast::Type* type,
-                           OPTIONAL&&... optional) {
-    VarOptionals opts(std::forward<OPTIONAL>(optional)...);
-    return create<ast::Variable>(Sym(std::forward<NAME>(name)), opts.storage,
-                                 opts.access, type, false /* is_const */,
-                                 false /* is_overridable */, opts.constructor,
-                                 std::move(opts.attributes));
-  }
-
-  /// @param source the variable source
-  /// @param name the variable name
-  /// @param type the variable type
-  /// @param optional the optional variable settings.
-  /// Can be any of the following, in any order:
-  ///   * ast::StorageClass   - specifies the variable storage class
-  ///   * ast::Access         - specifies the variable's access control
-  ///   * ast::Expression*    - specifies the variable's initializer expression
-  ///   * ast::AttributeList - specifies the variable's attributes
-  /// Note that repeated arguments of the same type will use the last argument's
-  /// value.
-  /// @returns a `ast::Variable` with the given name, storage and type
-  template <typename NAME, typename... OPTIONAL>
-  const ast::Variable* Var(const Source& source,
-                           NAME&& name,
-                           const ast::Type* type,
-                           OPTIONAL&&... optional) {
-    VarOptionals opts(std::forward<OPTIONAL>(optional)...);
-    return create<ast::Variable>(
-        source, Sym(std::forward<NAME>(name)), opts.storage, opts.access, type,
-        false /* is_const */, false /* is_overridable */, opts.constructor,
-        std::move(opts.attributes));
-  }
-
-  /// @param name the variable name
-  /// @param type the variable type
-  /// @param constructor constructor expression
-  /// @param attributes optional variable attributes
-  /// @returns a constant `ast::Variable` with the given name and type
-  template <typename NAME>
-  const ast::Variable* Const(NAME&& name,
+    const ast::Variable* Let(NAME&& name,
                              const ast::Type* type,
                              const ast::Expression* constructor,
                              ast::AttributeList attributes = {}) {
-    return create<ast::Variable>(
-        Sym(std::forward<NAME>(name)), ast::StorageClass::kNone,
-        ast::Access::kUndefined, type, true /* is_const */,
-        false /* is_overridable */, constructor, attributes);
-  }
+        return create<ast::Variable>(Sym(std::forward<NAME>(name)), ast::StorageClass::kNone,
+                                     ast::Access::kUndefined, type, true /* is_const */,
+                                     false /* is_overridable */, constructor, attributes);
+    }
 
-  /// @param source the variable source
-  /// @param name the variable name
-  /// @param type the variable type
-  /// @param constructor constructor expression
-  /// @param attributes optional variable attributes
-  /// @returns a constant `ast::Variable` with the given name and type
-  template <typename NAME>
-  const ast::Variable* Const(const Source& source,
+    /// @param source the variable source
+    /// @param name the variable name
+    /// @param type the variable type
+    /// @param constructor constructor expression
+    /// @param attributes optional variable attributes
+    /// @returns an immutable `ast::Variable` with the given name and type
+    template <typename NAME>
+    const ast::Variable* Let(const Source& source,
                              NAME&& name,
                              const ast::Type* type,
                              const ast::Expression* constructor,
                              ast::AttributeList attributes = {}) {
-    return create<ast::Variable>(
-        source, Sym(std::forward<NAME>(name)), ast::StorageClass::kNone,
-        ast::Access::kUndefined, type, true /* is_const */,
-        false /* is_overridable */, constructor, attributes);
-  }
+        return create<ast::Variable>(source, Sym(std::forward<NAME>(name)),
+                                     ast::StorageClass::kNone, ast::Access::kUndefined, type,
+                                     true /* is_const */, false /* is_overridable */, constructor,
+                                     attributes);
+    }
 
-  /// @param name the parameter name
-  /// @param type the parameter type
-  /// @param attributes optional parameter attributes
-  /// @returns a constant `ast::Variable` with the given name and type
-  template <typename NAME>
-  const ast::Variable* Param(NAME&& name,
-                             const ast::Type* type,
-                             ast::AttributeList attributes = {}) {
-    return create<ast::Variable>(
-        Sym(std::forward<NAME>(name)), ast::StorageClass::kNone,
-        ast::Access::kUndefined, type, true /* is_const */,
-        false /* is_overridable */, nullptr, attributes);
-  }
+    /// @param name the parameter name
+    /// @param type the parameter type
+    /// @param attributes optional parameter attributes
+    /// @returns an immutable `ast::Variable` with the given name and type
+    template <typename NAME>
+    const ast::Variable* Param(NAME&& name,
+                               const ast::Type* type,
+                               ast::AttributeList attributes = {}) {
+        return create<ast::Variable>(Sym(std::forward<NAME>(name)), ast::StorageClass::kNone,
+                                     ast::Access::kUndefined, type, true /* is_const */,
+                                     false /* is_overridable */, nullptr, attributes);
+    }
 
-  /// @param source the parameter source
-  /// @param name the parameter name
-  /// @param type the parameter type
-  /// @param attributes optional parameter attributes
-  /// @returns a constant `ast::Variable` with the given name and type
-  template <typename NAME>
-  const ast::Variable* Param(const Source& source,
-                             NAME&& name,
-                             const ast::Type* type,
-                             ast::AttributeList attributes = {}) {
-    return create<ast::Variable>(
-        source, Sym(std::forward<NAME>(name)), ast::StorageClass::kNone,
-        ast::Access::kUndefined, type, true /* is_const */,
-        false /* is_overridable */, nullptr, attributes);
-  }
+    /// @param source the parameter source
+    /// @param name the parameter name
+    /// @param type the parameter type
+    /// @param attributes optional parameter attributes
+    /// @returns an immutable `ast::Variable` with the given name and type
+    template <typename NAME>
+    const ast::Variable* Param(const Source& source,
+                               NAME&& name,
+                               const ast::Type* type,
+                               ast::AttributeList attributes = {}) {
+        return create<ast::Variable>(source, Sym(std::forward<NAME>(name)),
+                                     ast::StorageClass::kNone, ast::Access::kUndefined, type,
+                                     true /* is_const */, false /* is_overridable */, nullptr,
+                                     attributes);
+    }
 
-  /// @param name the variable name
-  /// @param type the variable type
-  /// @param optional the optional variable settings.
-  /// Can be any of the following, in any order:
-  ///   * ast::StorageClass   - specifies the variable storage class
-  ///   * ast::Access         - specifies the variable's access control
-  ///   * ast::Expression*    - specifies the variable's initializer expression
-  ///   * ast::AttributeList - specifies the variable's attributes
-  /// Note that repeated arguments of the same type will use the last argument's
-  /// value.
-  /// @returns a new `ast::Variable`, which is automatically registered as a
-  /// global variable with the ast::Module.
-  template <typename NAME,
-            typename... OPTIONAL,
-            typename = DisableIfSource<NAME>>
-  const ast::Variable* Global(NAME&& name,
-                              const ast::Type* type,
-                              OPTIONAL&&... optional) {
-    auto* var = Var(std::forward<NAME>(name), type,
-                    std::forward<OPTIONAL>(optional)...);
-    AST().AddGlobalVariable(var);
-    return var;
-  }
+    /// @param name the variable name
+    /// @param type the variable type
+    /// @param optional the optional variable settings.
+    /// Can be any of the following, in any order:
+    ///   * ast::StorageClass   - specifies the variable storage class
+    ///   * ast::Access         - specifies the variable's access control
+    ///   * ast::Expression*    - specifies the variable's initializer expression
+    ///   * ast::AttributeList - specifies the variable's attributes
+    /// Note that repeated arguments of the same type will use the last argument's
+    /// value.
+    /// @returns a new `ast::Variable`, which is automatically registered as a
+    /// global variable with the ast::Module.
+    template <typename NAME, typename... OPTIONAL, typename = DisableIfSource<NAME>>
+    const ast::Variable* Global(NAME&& name, const ast::Type* type, OPTIONAL&&... optional) {
+        auto* var = Var(std::forward<NAME>(name), type, std::forward<OPTIONAL>(optional)...);
+        AST().AddGlobalVariable(var);
+        return var;
+    }
 
-  /// @param source the variable source
-  /// @param name the variable name
-  /// @param type the variable type
-  /// @param optional the optional variable settings.
-  /// Can be any of the following, in any order:
-  ///   * ast::StorageClass   - specifies the variable storage class
-  ///   * ast::Access         - specifies the variable's access control
-  ///   * ast::Expression*    - specifies the variable's initializer expression
-  ///   * ast::AttributeList - specifies the variable's attributes
-  /// Note that repeated arguments of the same type will use the last argument's
-  /// value.
-  /// @returns a new `ast::Variable`, which is automatically registered as a
-  /// global variable with the ast::Module.
-  template <typename NAME, typename... OPTIONAL>
-  const ast::Variable* Global(const Source& source,
-                              NAME&& name,
-                              const ast::Type* type,
-                              OPTIONAL&&... optional) {
-    auto* var = Var(source, std::forward<NAME>(name), type,
-                    std::forward<OPTIONAL>(optional)...);
-    AST().AddGlobalVariable(var);
-    return var;
-  }
-
-  /// @param name the variable name
-  /// @param type the variable type
-  /// @param constructor constructor expression
-  /// @param attributes optional variable attributes
-  /// @returns a const `ast::Variable` constructed by calling Var() with the
-  /// arguments of `args`, which is automatically registered as a global
-  /// variable with the ast::Module.
-  template <typename NAME>
-  const ast::Variable* GlobalConst(NAME&& name,
-                                   const ast::Type* type,
-                                   const ast::Expression* constructor,
-                                   ast::AttributeList attributes = {}) {
-    auto* var = Const(std::forward<NAME>(name), type, constructor,
-                      std::move(attributes));
-    AST().AddGlobalVariable(var);
-    return var;
-  }
-
-  /// @param source the variable source
-  /// @param name the variable name
-  /// @param type the variable type
-  /// @param constructor constructor expression
-  /// @param attributes optional variable attributes
-  /// @returns a const `ast::Variable` constructed by calling Var() with the
-  /// arguments of `args`, which is automatically registered as a global
-  /// variable with the ast::Module.
-  template <typename NAME>
-  const ast::Variable* GlobalConst(const Source& source,
-                                   NAME&& name,
-                                   const ast::Type* type,
-                                   const ast::Expression* constructor,
-                                   ast::AttributeList attributes = {}) {
-    auto* var = Const(source, std::forward<NAME>(name), type, constructor,
-                      std::move(attributes));
-    AST().AddGlobalVariable(var);
-    return var;
-  }
-
-  /// @param name the variable name
-  /// @param type the variable type
-  /// @param constructor optional constructor expression
-  /// @param attributes optional variable attributes
-  /// @returns an overridable const `ast::Variable` which is automatically
-  /// registered as a global variable with the ast::Module.
-  template <typename NAME>
-  const ast::Variable* Override(NAME&& name,
-                                const ast::Type* type,
-                                const ast::Expression* constructor,
-                                ast::AttributeList attributes = {}) {
-    auto* var = create<ast::Variable>(
-        source_, Sym(std::forward<NAME>(name)), ast::StorageClass::kNone,
-        ast::Access::kUndefined, type, true /* is_const */,
-        true /* is_overridable */, constructor, std::move(attributes));
-    AST().AddGlobalVariable(var);
-    return var;
-  }
-
-  /// @param source the variable source
-  /// @param name the variable name
-  /// @param type the variable type
-  /// @param constructor constructor expression
-  /// @param attributes optional variable attributes
-  /// @returns a const `ast::Variable` constructed by calling Var() with the
-  /// arguments of `args`, which is automatically registered as a global
-  /// variable with the ast::Module.
-  template <typename NAME>
-  const ast::Variable* Override(const Source& source,
+    /// @param source the variable source
+    /// @param name the variable name
+    /// @param type the variable type
+    /// @param optional the optional variable settings.
+    /// Can be any of the following, in any order:
+    ///   * ast::StorageClass   - specifies the variable storage class
+    ///   * ast::Access         - specifies the variable's access control
+    ///   * ast::Expression*    - specifies the variable's initializer expression
+    ///   * ast::AttributeList - specifies the variable's attributes
+    /// Note that repeated arguments of the same type will use the last argument's
+    /// value.
+    /// @returns a new `ast::Variable`, which is automatically registered as a
+    /// global variable with the ast::Module.
+    template <typename NAME, typename... OPTIONAL>
+    const ast::Variable* Global(const Source& source,
                                 NAME&& name,
                                 const ast::Type* type,
-                                const ast::Expression* constructor,
-                                ast::AttributeList attributes = {}) {
-    auto* var = create<ast::Variable>(
-        source, Sym(std::forward<NAME>(name)), ast::StorageClass::kNone,
-        ast::Access::kUndefined, type, true /* is_const */,
-        true /* is_overridable */, constructor, std::move(attributes));
-    AST().AddGlobalVariable(var);
-    return var;
-  }
+                                OPTIONAL&&... optional) {
+        auto* var =
+            Var(source, std::forward<NAME>(name), type, std::forward<OPTIONAL>(optional)...);
+        AST().AddGlobalVariable(var);
+        return var;
+    }
 
-  /// @param source the source information
-  /// @param expr the expression to take the address of
-  /// @return an ast::UnaryOpExpression that takes the address of `expr`
-  template <typename EXPR>
-  const ast::UnaryOpExpression* AddressOf(const Source& source, EXPR&& expr) {
-    return create<ast::UnaryOpExpression>(source, ast::UnaryOp::kAddressOf,
-                                          Expr(std::forward<EXPR>(expr)));
-  }
+    /// @param name the variable name
+    /// @param type the variable type
+    /// @param constructor constructor expression
+    /// @param attributes optional variable attributes
+    /// @returns a const `ast::Variable` constructed by calling Var() with the
+    /// arguments of `args`, which is automatically registered as a global
+    /// variable with the ast::Module.
+    template <typename NAME>
+    const ast::Variable* GlobalConst(NAME&& name,
+                                     const ast::Type* type,
+                                     const ast::Expression* constructor,
+                                     ast::AttributeList attributes = {}) {
+        auto* var = Let(std::forward<NAME>(name), type, constructor, std::move(attributes));
+        AST().AddGlobalVariable(var);
+        return var;
+    }
 
-  /// @param expr the expression to take the address of
-  /// @return an ast::UnaryOpExpression that takes the address of `expr`
-  template <typename EXPR>
-  const ast::UnaryOpExpression* AddressOf(EXPR&& expr) {
-    return create<ast::UnaryOpExpression>(ast::UnaryOp::kAddressOf,
-                                          Expr(std::forward<EXPR>(expr)));
-  }
+    /// @param source the variable source
+    /// @param name the variable name
+    /// @param type the variable type
+    /// @param constructor constructor expression
+    /// @param attributes optional variable attributes
+    /// @returns a const `ast::Variable` constructed by calling Var() with the
+    /// arguments of `args`, which is automatically registered as a global
+    /// variable with the ast::Module.
+    template <typename NAME>
+    const ast::Variable* GlobalConst(const Source& source,
+                                     NAME&& name,
+                                     const ast::Type* type,
+                                     const ast::Expression* constructor,
+                                     ast::AttributeList attributes = {}) {
+        auto* var = Let(source, std::forward<NAME>(name), type, constructor, std::move(attributes));
+        AST().AddGlobalVariable(var);
+        return var;
+    }
 
-  /// @param source the source information
-  /// @param expr the expression to perform an indirection on
-  /// @return an ast::UnaryOpExpression that dereferences the pointer `expr`
-  template <typename EXPR>
-  const ast::UnaryOpExpression* Deref(const Source& source, EXPR&& expr) {
-    return create<ast::UnaryOpExpression>(source, ast::UnaryOp::kIndirection,
-                                          Expr(std::forward<EXPR>(expr)));
-  }
+    /// @param name the variable name
+    /// @param type the variable type
+    /// @param constructor optional constructor expression
+    /// @param attributes optional variable attributes
+    /// @returns an overridable const `ast::Variable` which is automatically
+    /// registered as a global variable with the ast::Module.
+    template <typename NAME>
+    const ast::Variable* Override(NAME&& name,
+                                  const ast::Type* type,
+                                  const ast::Expression* constructor,
+                                  ast::AttributeList attributes = {}) {
+        auto* var =
+            create<ast::Variable>(source_, Sym(std::forward<NAME>(name)), ast::StorageClass::kNone,
+                                  ast::Access::kUndefined, type, true /* is_const */,
+                                  true /* is_overridable */, constructor, std::move(attributes));
+        AST().AddGlobalVariable(var);
+        return var;
+    }
 
-  /// @param expr the expression to perform an indirection on
-  /// @return an ast::UnaryOpExpression that dereferences the pointer `expr`
-  template <typename EXPR>
-  const ast::UnaryOpExpression* Deref(EXPR&& expr) {
-    return create<ast::UnaryOpExpression>(ast::UnaryOp::kIndirection,
-                                          Expr(std::forward<EXPR>(expr)));
-  }
-
-  /// @param expr the expression to perform a unary not on
-  /// @return an ast::UnaryOpExpression that is the unary not of the input
-  /// expression
-  template <typename EXPR>
-  const ast::UnaryOpExpression* Not(EXPR&& expr) {
-    return create<ast::UnaryOpExpression>(ast::UnaryOp::kNot,
-                                          Expr(std::forward<EXPR>(expr)));
-  }
-
-  /// @param expr the expression to perform a unary complement on
-  /// @return an ast::UnaryOpExpression that is the unary complement of the
-  /// input expression
-  template <typename EXPR>
-  const ast::UnaryOpExpression* Complement(EXPR&& expr) {
-    return create<ast::UnaryOpExpression>(ast::UnaryOp::kComplement,
-                                          Expr(std::forward<EXPR>(expr)));
-  }
-
-  /// @param source the source information
-  /// @param func the function name
-  /// @param args the function call arguments
-  /// @returns a `ast::CallExpression` to the function `func`, with the
-  /// arguments of `args` converted to `ast::Expression`s using `Expr()`.
-  template <typename NAME, typename... ARGS>
-  const ast::CallExpression* Call(const Source& source,
-                                  NAME&& func,
-                                  ARGS&&... args) {
-    return create<ast::CallExpression>(source, Expr(func),
-                                       ExprList(std::forward<ARGS>(args)...));
-  }
-
-  /// @param func the function name
-  /// @param args the function call arguments
-  /// @returns a `ast::CallExpression` to the function `func`, with the
-  /// arguments of `args` converted to `ast::Expression`s using `Expr()`.
-  template <typename NAME, typename... ARGS, typename = DisableIfSource<NAME>>
-  const ast::CallExpression* Call(NAME&& func, ARGS&&... args) {
-    return create<ast::CallExpression>(Expr(func),
-                                       ExprList(std::forward<ARGS>(args)...));
-  }
-
-  /// @param source the source information
-  /// @param call the call expression to wrap in a call statement
-  /// @returns a `ast::CallStatement` for the given call expression
-  const ast::CallStatement* CallStmt(const Source& source,
-                                     const ast::CallExpression* call) {
-    return create<ast::CallStatement>(source, call);
-  }
-
-  /// @param call the call expression to wrap in a call statement
-  /// @returns a `ast::CallStatement` for the given call expression
-  const ast::CallStatement* CallStmt(const ast::CallExpression* call) {
-    return create<ast::CallStatement>(call);
-  }
-
-  /// @param source the source information
-  /// @returns a `ast::PhonyExpression`
-  const ast::PhonyExpression* Phony(const Source& source) {
-    return create<ast::PhonyExpression>(source);
-  }
-
-  /// @returns a `ast::PhonyExpression`
-  const ast::PhonyExpression* Phony() { return create<ast::PhonyExpression>(); }
-
-  /// @param expr the expression to ignore
-  /// @returns a `ast::AssignmentStatement` that assigns 'expr' to the phony
-  /// (underscore) variable.
-  template <typename EXPR>
-  const ast::AssignmentStatement* Ignore(EXPR&& expr) {
-    return create<ast::AssignmentStatement>(Phony(), Expr(expr));
-  }
-
-  /// @param lhs the left hand argument to the addition operation
-  /// @param rhs the right hand argument to the addition operation
-  /// @returns a `ast::BinaryExpression` summing the arguments `lhs` and `rhs`
-  template <typename LHS, typename RHS>
-  const ast::BinaryExpression* Add(LHS&& lhs, RHS&& rhs) {
-    return create<ast::BinaryExpression>(ast::BinaryOp::kAdd,
-                                         Expr(std::forward<LHS>(lhs)),
-                                         Expr(std::forward<RHS>(rhs)));
-  }
-
-  /// @param lhs the left hand argument to the and operation
-  /// @param rhs the right hand argument to the and operation
-  /// @returns a `ast::BinaryExpression` bitwise anding `lhs` and `rhs`
-  template <typename LHS, typename RHS>
-  const ast::BinaryExpression* And(LHS&& lhs, RHS&& rhs) {
-    return create<ast::BinaryExpression>(ast::BinaryOp::kAnd,
-                                         Expr(std::forward<LHS>(lhs)),
-                                         Expr(std::forward<RHS>(rhs)));
-  }
-
-  /// @param lhs the left hand argument to the or operation
-  /// @param rhs the right hand argument to the or operation
-  /// @returns a `ast::BinaryExpression` bitwise or-ing `lhs` and `rhs`
-  template <typename LHS, typename RHS>
-  const ast::BinaryExpression* Or(LHS&& lhs, RHS&& rhs) {
-    return create<ast::BinaryExpression>(ast::BinaryOp::kOr,
-                                         Expr(std::forward<LHS>(lhs)),
-                                         Expr(std::forward<RHS>(rhs)));
-  }
-
-  /// @param lhs the left hand argument to the subtraction operation
-  /// @param rhs the right hand argument to the subtraction operation
-  /// @returns a `ast::BinaryExpression` subtracting `rhs` from `lhs`
-  template <typename LHS, typename RHS>
-  const ast::BinaryExpression* Sub(LHS&& lhs, RHS&& rhs) {
-    return create<ast::BinaryExpression>(ast::BinaryOp::kSubtract,
-                                         Expr(std::forward<LHS>(lhs)),
-                                         Expr(std::forward<RHS>(rhs)));
-  }
-
-  /// @param lhs the left hand argument to the multiplication operation
-  /// @param rhs the right hand argument to the multiplication operation
-  /// @returns a `ast::BinaryExpression` multiplying `rhs` from `lhs`
-  template <typename LHS, typename RHS>
-  const ast::BinaryExpression* Mul(LHS&& lhs, RHS&& rhs) {
-    return create<ast::BinaryExpression>(ast::BinaryOp::kMultiply,
-                                         Expr(std::forward<LHS>(lhs)),
-                                         Expr(std::forward<RHS>(rhs)));
-  }
-
-  /// @param source the source information
-  /// @param lhs the left hand argument to the multiplication operation
-  /// @param rhs the right hand argument to the multiplication operation
-  /// @returns a `ast::BinaryExpression` multiplying `rhs` from `lhs`
-  template <typename LHS, typename RHS>
-  const ast::BinaryExpression* Mul(const Source& source, LHS&& lhs, RHS&& rhs) {
-    return create<ast::BinaryExpression>(source, ast::BinaryOp::kMultiply,
-                                         Expr(std::forward<LHS>(lhs)),
-                                         Expr(std::forward<RHS>(rhs)));
-  }
-
-  /// @param lhs the left hand argument to the division operation
-  /// @param rhs the right hand argument to the division operation
-  /// @returns a `ast::BinaryExpression` dividing `lhs` by `rhs`
-  template <typename LHS, typename RHS>
-  const ast::BinaryExpression* Div(LHS&& lhs, RHS&& rhs) {
-    return create<ast::BinaryExpression>(ast::BinaryOp::kDivide,
-                                         Expr(std::forward<LHS>(lhs)),
-                                         Expr(std::forward<RHS>(rhs)));
-  }
-
-  /// @param lhs the left hand argument to the modulo operation
-  /// @param rhs the right hand argument to the modulo operation
-  /// @returns a `ast::BinaryExpression` applying modulo of `lhs` by `rhs`
-  template <typename LHS, typename RHS>
-  const ast::BinaryExpression* Mod(LHS&& lhs, RHS&& rhs) {
-    return create<ast::BinaryExpression>(ast::BinaryOp::kModulo,
-                                         Expr(std::forward<LHS>(lhs)),
-                                         Expr(std::forward<RHS>(rhs)));
-  }
-
-  /// @param lhs the left hand argument to the bit shift right operation
-  /// @param rhs the right hand argument to the bit shift right operation
-  /// @returns a `ast::BinaryExpression` bit shifting right `lhs` by `rhs`
-  template <typename LHS, typename RHS>
-  const ast::BinaryExpression* Shr(LHS&& lhs, RHS&& rhs) {
-    return create<ast::BinaryExpression>(ast::BinaryOp::kShiftRight,
-                                         Expr(std::forward<LHS>(lhs)),
-                                         Expr(std::forward<RHS>(rhs)));
-  }
-
-  /// @param lhs the left hand argument to the bit shift left operation
-  /// @param rhs the right hand argument to the bit shift left operation
-  /// @returns a `ast::BinaryExpression` bit shifting left `lhs` by `rhs`
-  template <typename LHS, typename RHS>
-  const ast::BinaryExpression* Shl(LHS&& lhs, RHS&& rhs) {
-    return create<ast::BinaryExpression>(ast::BinaryOp::kShiftLeft,
-                                         Expr(std::forward<LHS>(lhs)),
-                                         Expr(std::forward<RHS>(rhs)));
-  }
-
-  /// @param lhs the left hand argument to the xor operation
-  /// @param rhs the right hand argument to the xor operation
-  /// @returns a `ast::BinaryExpression` bitwise xor-ing `lhs` and `rhs`
-  template <typename LHS, typename RHS>
-  const ast::BinaryExpression* Xor(LHS&& lhs, RHS&& rhs) {
-    return create<ast::BinaryExpression>(ast::BinaryOp::kXor,
-                                         Expr(std::forward<LHS>(lhs)),
-                                         Expr(std::forward<RHS>(rhs)));
-  }
-
-  /// @param lhs the left hand argument to the logical and operation
-  /// @param rhs the right hand argument to the logical and operation
-  /// @returns a `ast::BinaryExpression` of `lhs` && `rhs`
-  template <typename LHS, typename RHS>
-  const ast::BinaryExpression* LogicalAnd(LHS&& lhs, RHS&& rhs) {
-    return create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd,
-                                         Expr(std::forward<LHS>(lhs)),
-                                         Expr(std::forward<RHS>(rhs)));
-  }
-
-  /// @param lhs the left hand argument to the logical or operation
-  /// @param rhs the right hand argument to the logical or operation
-  /// @returns a `ast::BinaryExpression` of `lhs` || `rhs`
-  template <typename LHS, typename RHS>
-  const ast::BinaryExpression* LogicalOr(LHS&& lhs, RHS&& rhs) {
-    return create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr,
-                                         Expr(std::forward<LHS>(lhs)),
-                                         Expr(std::forward<RHS>(rhs)));
-  }
-
-  /// @param lhs the left hand argument to the greater than operation
-  /// @param rhs the right hand argument to the greater than operation
-  /// @returns a `ast::BinaryExpression` of `lhs` > `rhs`
-  template <typename LHS, typename RHS>
-  const ast::BinaryExpression* GreaterThan(LHS&& lhs, RHS&& rhs) {
-    return create<ast::BinaryExpression>(ast::BinaryOp::kGreaterThan,
-                                         Expr(std::forward<LHS>(lhs)),
-                                         Expr(std::forward<RHS>(rhs)));
-  }
-
-  /// @param lhs the left hand argument to the greater than or equal operation
-  /// @param rhs the right hand argument to the greater than or equal operation
-  /// @returns a `ast::BinaryExpression` of `lhs` >= `rhs`
-  template <typename LHS, typename RHS>
-  const ast::BinaryExpression* GreaterThanEqual(LHS&& lhs, RHS&& rhs) {
-    return create<ast::BinaryExpression>(ast::BinaryOp::kGreaterThanEqual,
-                                         Expr(std::forward<LHS>(lhs)),
-                                         Expr(std::forward<RHS>(rhs)));
-  }
-
-  /// @param lhs the left hand argument to the less than operation
-  /// @param rhs the right hand argument to the less than operation
-  /// @returns a `ast::BinaryExpression` of `lhs` < `rhs`
-  template <typename LHS, typename RHS>
-  const ast::BinaryExpression* LessThan(LHS&& lhs, RHS&& rhs) {
-    return create<ast::BinaryExpression>(ast::BinaryOp::kLessThan,
-                                         Expr(std::forward<LHS>(lhs)),
-                                         Expr(std::forward<RHS>(rhs)));
-  }
-
-  /// @param lhs the left hand argument to the less than or equal operation
-  /// @param rhs the right hand argument to the less than or equal operation
-  /// @returns a `ast::BinaryExpression` of `lhs` <= `rhs`
-  template <typename LHS, typename RHS>
-  const ast::BinaryExpression* LessThanEqual(LHS&& lhs, RHS&& rhs) {
-    return create<ast::BinaryExpression>(ast::BinaryOp::kLessThanEqual,
-                                         Expr(std::forward<LHS>(lhs)),
-                                         Expr(std::forward<RHS>(rhs)));
-  }
-
-  /// @param lhs the left hand argument to the equal expression
-  /// @param rhs the right hand argument to the equal expression
-  /// @returns a `ast::BinaryExpression` comparing `lhs` equal to `rhs`
-  template <typename LHS, typename RHS>
-  const ast::BinaryExpression* Equal(LHS&& lhs, RHS&& rhs) {
-    return create<ast::BinaryExpression>(ast::BinaryOp::kEqual,
-                                         Expr(std::forward<LHS>(lhs)),
-                                         Expr(std::forward<RHS>(rhs)));
-  }
-
-  /// @param lhs the left hand argument to the not-equal expression
-  /// @param rhs the right hand argument to the not-equal expression
-  /// @returns a `ast::BinaryExpression` comparing `lhs` equal to `rhs` for
-  ///          disequality
-  template <typename LHS, typename RHS>
-  const ast::BinaryExpression* NotEqual(LHS&& lhs, RHS&& rhs) {
-    return create<ast::BinaryExpression>(ast::BinaryOp::kNotEqual,
-                                         Expr(std::forward<LHS>(lhs)),
-                                         Expr(std::forward<RHS>(rhs)));
-  }
-
-  /// @param source the source information
-  /// @param obj the object for the index accessor expression
-  /// @param idx the index argument for the index accessor expression
-  /// @returns a `ast::IndexAccessorExpression` that indexes `arr` with `idx`
-  template <typename OBJ, typename IDX>
-  const ast::IndexAccessorExpression* IndexAccessor(const Source& source,
-                                                    OBJ&& obj,
-                                                    IDX&& idx) {
-    return create<ast::IndexAccessorExpression>(
-        source, Expr(std::forward<OBJ>(obj)), Expr(std::forward<IDX>(idx)));
-  }
-
-  /// @param obj the object for the index accessor expression
-  /// @param idx the index argument for the index accessor expression
-  /// @returns a `ast::IndexAccessorExpression` that indexes `arr` with `idx`
-  template <typename OBJ, typename IDX>
-  const ast::IndexAccessorExpression* IndexAccessor(OBJ&& obj, IDX&& idx) {
-    return create<ast::IndexAccessorExpression>(Expr(std::forward<OBJ>(obj)),
-                                                Expr(std::forward<IDX>(idx)));
-  }
-
-  /// @param source the source information
-  /// @param obj the object for the member accessor expression
-  /// @param idx the index argument for the member accessor expression
-  /// @returns a `ast::MemberAccessorExpression` that indexes `obj` with `idx`
-  template <typename OBJ, typename IDX>
-  const ast::MemberAccessorExpression* MemberAccessor(const Source& source,
-                                                      OBJ&& obj,
-                                                      IDX&& idx) {
-    return create<ast::MemberAccessorExpression>(
-        source, Expr(std::forward<OBJ>(obj)), Expr(std::forward<IDX>(idx)));
-  }
-
-  /// @param obj the object for the member accessor expression
-  /// @param idx the index argument for the member accessor expression
-  /// @returns a `ast::MemberAccessorExpression` that indexes `obj` with `idx`
-  template <typename OBJ, typename IDX>
-  const ast::MemberAccessorExpression* MemberAccessor(OBJ&& obj, IDX&& idx) {
-    return create<ast::MemberAccessorExpression>(Expr(std::forward<OBJ>(obj)),
-                                                 Expr(std::forward<IDX>(idx)));
-  }
-
-  /// Creates a ast::StructMemberOffsetAttribute
-  /// @param val the offset value
-  /// @returns the offset attribute pointer
-  const ast::StructMemberOffsetAttribute* MemberOffset(uint32_t val) {
-    return create<ast::StructMemberOffsetAttribute>(source_, val);
-  }
-
-  /// Creates a ast::StructMemberSizeAttribute
-  /// @param source the source information
-  /// @param val the size value
-  /// @returns the size attribute pointer
-  const ast::StructMemberSizeAttribute* MemberSize(const Source& source,
-                                                   uint32_t val) {
-    return create<ast::StructMemberSizeAttribute>(source, val);
-  }
-
-  /// Creates a ast::StructMemberSizeAttribute
-  /// @param val the size value
-  /// @returns the size attribute pointer
-  const ast::StructMemberSizeAttribute* MemberSize(uint32_t val) {
-    return create<ast::StructMemberSizeAttribute>(source_, val);
-  }
-
-  /// Creates a ast::StructMemberAlignAttribute
-  /// @param source the source information
-  /// @param val the align value
-  /// @returns the align attribute pointer
-  const ast::StructMemberAlignAttribute* MemberAlign(const Source& source,
-                                                     uint32_t val) {
-    return create<ast::StructMemberAlignAttribute>(source, val);
-  }
-
-  /// Creates a ast::StructMemberAlignAttribute
-  /// @param val the align value
-  /// @returns the align attribute pointer
-  const ast::StructMemberAlignAttribute* MemberAlign(uint32_t val) {
-    return create<ast::StructMemberAlignAttribute>(source_, val);
-  }
-
-  /// Creates the ast::GroupAttribute
-  /// @param value group attribute index
-  /// @returns the group attribute pointer
-  const ast::GroupAttribute* Group(uint32_t value) {
-    return create<ast::GroupAttribute>(value);
-  }
-
-  /// Creates the ast::BindingAttribute
-  /// @param value the binding index
-  /// @returns the binding deocration pointer
-  const ast::BindingAttribute* Binding(uint32_t value) {
-    return create<ast::BindingAttribute>(value);
-  }
-
-  /// Convenience function to create both a ast::GroupAttribute and
-  /// ast::BindingAttribute
-  /// @param group the group index
-  /// @param binding the binding index
-  /// @returns a attribute list with both the group and binding attributes
-  ast::AttributeList GroupAndBinding(uint32_t group, uint32_t binding) {
-    return {Group(group), Binding(binding)};
-  }
-
-  /// Creates an ast::Function and registers it with the ast::Module.
-  /// @param source the source information
-  /// @param name the function name
-  /// @param params the function parameters
-  /// @param type the function return type
-  /// @param body the function body
-  /// @param attributes the optional function attributes
-  /// @param return_type_attributes the optional function return type
-  /// attributes
-  /// @returns the function pointer
-  template <typename NAME>
-  const ast::Function* Func(const Source& source,
-                            NAME&& name,
-                            ast::VariableList params,
-                            const ast::Type* type,
-                            ast::StatementList body,
-                            ast::AttributeList attributes = {},
-                            ast::AttributeList return_type_attributes = {}) {
-    auto* func = create<ast::Function>(
-        source, Sym(std::forward<NAME>(name)), params, type,
-        create<ast::BlockStatement>(body), attributes, return_type_attributes);
-    AST().AddFunction(func);
-    return func;
-  }
-
-  /// Creates an ast::Function and registers it with the ast::Module.
-  /// @param name the function name
-  /// @param params the function parameters
-  /// @param type the function return type
-  /// @param body the function body
-  /// @param attributes the optional function attributes
-  /// @param return_type_attributes the optional function return type
-  /// attributes
-  /// @returns the function pointer
-  template <typename NAME>
-  const ast::Function* Func(NAME&& name,
-                            ast::VariableList params,
-                            const ast::Type* type,
-                            ast::StatementList body,
-                            ast::AttributeList attributes = {},
-                            ast::AttributeList return_type_attributes = {}) {
-    auto* func = create<ast::Function>(Sym(std::forward<NAME>(name)), params,
-                                       type, create<ast::BlockStatement>(body),
-                                       attributes, return_type_attributes);
-    AST().AddFunction(func);
-    return func;
-  }
-
-  /// Creates an ast::BreakStatement
-  /// @param source the source information
-  /// @returns the break statement pointer
-  const ast::BreakStatement* Break(const Source& source) {
-    return create<ast::BreakStatement>(source);
-  }
-
-  /// Creates an ast::BreakStatement
-  /// @returns the break statement pointer
-  const ast::BreakStatement* Break() { return create<ast::BreakStatement>(); }
-
-  /// Creates an ast::ContinueStatement
-  /// @param source the source information
-  /// @returns the continue statement pointer
-  const ast::ContinueStatement* Continue(const Source& source) {
-    return create<ast::ContinueStatement>(source);
-  }
-
-  /// Creates an ast::ContinueStatement
-  /// @returns the continue statement pointer
-  const ast::ContinueStatement* Continue() {
-    return create<ast::ContinueStatement>();
-  }
-
-  /// Creates an ast::ReturnStatement with no return value
-  /// @param source the source information
-  /// @returns the return statement pointer
-  const ast::ReturnStatement* Return(const Source& source) {
-    return create<ast::ReturnStatement>(source);
-  }
-
-  /// Creates an ast::ReturnStatement with no return value
-  /// @returns the return statement pointer
-  const ast::ReturnStatement* Return() {
-    return create<ast::ReturnStatement>();
-  }
-
-  /// Creates an ast::ReturnStatement with the given return value
-  /// @param source the source information
-  /// @param val the return value
-  /// @returns the return statement pointer
-  template <typename EXPR>
-  const ast::ReturnStatement* Return(const Source& source, EXPR&& val) {
-    return create<ast::ReturnStatement>(source, Expr(std::forward<EXPR>(val)));
-  }
-
-  /// Creates an ast::ReturnStatement with the given return value
-  /// @param val the return value
-  /// @returns the return statement pointer
-  template <typename EXPR, typename = DisableIfSource<EXPR>>
-  const ast::ReturnStatement* Return(EXPR&& val) {
-    return create<ast::ReturnStatement>(Expr(std::forward<EXPR>(val)));
-  }
-
-  /// Creates an ast::DiscardStatement
-  /// @param source the source information
-  /// @returns the discard statement pointer
-  const ast::DiscardStatement* Discard(const Source& source) {
-    return create<ast::DiscardStatement>(source);
-  }
-
-  /// Creates an ast::DiscardStatement
-  /// @returns the discard statement pointer
-  const ast::DiscardStatement* Discard() {
-    return create<ast::DiscardStatement>();
-  }
-
-  /// Creates a ast::Alias registering it with the AST().TypeDecls().
-  /// @param source the source information
-  /// @param name the alias name
-  /// @param type the alias target type
-  /// @returns the alias type
-  template <typename NAME>
-  const ast::Alias* Alias(const Source& source,
-                          NAME&& name,
-                          const ast::Type* type) {
-    auto* out = ty.alias(source, std::forward<NAME>(name), type);
-    AST().AddTypeDecl(out);
-    return out;
-  }
-
-  /// Creates a ast::Alias registering it with the AST().TypeDecls().
-  /// @param name the alias name
-  /// @param type the alias target type
-  /// @returns the alias type
-  template <typename NAME>
-  const ast::Alias* Alias(NAME&& name, const ast::Type* type) {
-    auto* out = ty.alias(std::forward<NAME>(name), type);
-    AST().AddTypeDecl(out);
-    return out;
-  }
-
-  /// Creates a ast::Struct registering it with the AST().TypeDecls().
-  /// @param source the source information
-  /// @param name the struct name
-  /// @param members the struct members
-  /// @returns the struct type
-  template <typename NAME>
-  const ast::Struct* Structure(const Source& source,
-                               NAME&& name,
-                               ast::StructMemberList members) {
-    auto sym = Sym(std::forward<NAME>(name));
-    auto* type = create<ast::Struct>(source, sym, std::move(members),
-                                     ast::AttributeList{});
-    AST().AddTypeDecl(type);
-    return type;
-  }
-
-  /// Creates a ast::Struct registering it with the AST().TypeDecls().
-  /// @param name the struct name
-  /// @param members the struct members
-  /// @returns the struct type
-  template <typename NAME>
-  const ast::Struct* Structure(NAME&& name, ast::StructMemberList members) {
-    auto sym = Sym(std::forward<NAME>(name));
-    auto* type =
-        create<ast::Struct>(sym, std::move(members), ast::AttributeList{});
-    AST().AddTypeDecl(type);
-    return type;
-  }
-
-  /// Creates a ast::StructMember
-  /// @param source the source information
-  /// @param name the struct member name
-  /// @param type the struct member type
-  /// @param attributes the optional struct member attributes
-  /// @returns the struct member pointer
-  template <typename NAME>
-  const ast::StructMember* Member(const Source& source,
+    /// @param source the variable source
+    /// @param name the variable name
+    /// @param type the variable type
+    /// @param constructor constructor expression
+    /// @param attributes optional variable attributes
+    /// @returns a const `ast::Variable` constructed by calling Var() with the
+    /// arguments of `args`, which is automatically registered as a global
+    /// variable with the ast::Module.
+    template <typename NAME>
+    const ast::Variable* Override(const Source& source,
                                   NAME&& name,
                                   const ast::Type* type,
+                                  const ast::Expression* constructor,
                                   ast::AttributeList attributes = {}) {
-    return create<ast::StructMember>(source, Sym(std::forward<NAME>(name)),
-                                     type, std::move(attributes));
-  }
+        auto* var =
+            create<ast::Variable>(source, Sym(std::forward<NAME>(name)), ast::StorageClass::kNone,
+                                  ast::Access::kUndefined, type, true /* is_const */,
+                                  true /* is_overridable */, constructor, std::move(attributes));
+        AST().AddGlobalVariable(var);
+        return var;
+    }
 
-  /// Creates a ast::StructMember
-  /// @param name the struct member name
-  /// @param type the struct member type
-  /// @param attributes the optional struct member attributes
-  /// @returns the struct member pointer
-  template <typename NAME>
-  const ast::StructMember* Member(NAME&& name,
-                                  const ast::Type* type,
-                                  ast::AttributeList attributes = {}) {
-    return create<ast::StructMember>(source_, Sym(std::forward<NAME>(name)),
-                                     type, std::move(attributes));
-  }
+    /// @param source the source information
+    /// @param expr the expression to take the address of
+    /// @return an ast::UnaryOpExpression that takes the address of `expr`
+    template <typename EXPR>
+    const ast::UnaryOpExpression* AddressOf(const Source& source, EXPR&& expr) {
+        return create<ast::UnaryOpExpression>(source, ast::UnaryOp::kAddressOf,
+                                              Expr(std::forward<EXPR>(expr)));
+    }
 
-  /// Creates a ast::StructMember with the given byte offset
-  /// @param offset the offset to use in the StructMemberOffsetattribute
-  /// @param name the struct member name
-  /// @param type the struct member type
-  /// @returns the struct member pointer
-  template <typename NAME>
-  const ast::StructMember* Member(uint32_t offset,
-                                  NAME&& name,
-                                  const ast::Type* type) {
-    return create<ast::StructMember>(
-        source_, Sym(std::forward<NAME>(name)), type,
-        ast::AttributeList{
-            create<ast::StructMemberOffsetAttribute>(offset),
-        });
-  }
+    /// @param expr the expression to take the address of
+    /// @return an ast::UnaryOpExpression that takes the address of `expr`
+    template <typename EXPR>
+    const ast::UnaryOpExpression* AddressOf(EXPR&& expr) {
+        return create<ast::UnaryOpExpression>(ast::UnaryOp::kAddressOf,
+                                              Expr(std::forward<EXPR>(expr)));
+    }
 
-  /// Creates a ast::BlockStatement with input statements
-  /// @param source the source information for the block
-  /// @param statements statements of block
-  /// @returns the block statement pointer
-  template <typename... Statements>
-  const ast::BlockStatement* Block(const Source& source,
-                                   Statements&&... statements) {
-    return create<ast::BlockStatement>(
-        source, ast::StatementList{std::forward<Statements>(statements)...});
-  }
+    /// @param source the source information
+    /// @param expr the expression to perform an indirection on
+    /// @return an ast::UnaryOpExpression that dereferences the pointer `expr`
+    template <typename EXPR>
+    const ast::UnaryOpExpression* Deref(const Source& source, EXPR&& expr) {
+        return create<ast::UnaryOpExpression>(source, ast::UnaryOp::kIndirection,
+                                              Expr(std::forward<EXPR>(expr)));
+    }
 
-  /// Creates a ast::BlockStatement with input statements
-  /// @param statements statements of block
-  /// @returns the block statement pointer
-  template <typename... STATEMENTS, typename = DisableIfSource<STATEMENTS...>>
-  const ast::BlockStatement* Block(STATEMENTS&&... statements) {
-    return create<ast::BlockStatement>(
-        ast::StatementList{std::forward<STATEMENTS>(statements)...});
-  }
+    /// @param expr the expression to perform an indirection on
+    /// @return an ast::UnaryOpExpression that dereferences the pointer `expr`
+    template <typename EXPR>
+    const ast::UnaryOpExpression* Deref(EXPR&& expr) {
+        return create<ast::UnaryOpExpression>(ast::UnaryOp::kIndirection,
+                                              Expr(std::forward<EXPR>(expr)));
+    }
 
-  /// Creates a ast::ElseStatement with input condition and body
-  /// @param condition the else condition expression
-  /// @param body the else body
-  /// @returns the else statement pointer
-  template <typename CONDITION>
-  const ast::ElseStatement* Else(CONDITION&& condition,
-                                 const ast::BlockStatement* body) {
-    return create<ast::ElseStatement>(Expr(std::forward<CONDITION>(condition)),
-                                      body);
-  }
+    /// @param expr the expression to perform a unary not on
+    /// @return an ast::UnaryOpExpression that is the unary not of the input
+    /// expression
+    template <typename EXPR>
+    const ast::UnaryOpExpression* Not(EXPR&& expr) {
+        return create<ast::UnaryOpExpression>(ast::UnaryOp::kNot, Expr(std::forward<EXPR>(expr)));
+    }
 
-  /// Creates a ast::ElseStatement with no condition and body
-  /// @param body the else body
-  /// @returns the else statement pointer
-  const ast::ElseStatement* Else(const ast::BlockStatement* body) {
-    return create<ast::ElseStatement>(nullptr, body);
-  }
+    /// @param expr the expression to perform a unary complement on
+    /// @return an ast::UnaryOpExpression that is the unary complement of the
+    /// input expression
+    template <typename EXPR>
+    const ast::UnaryOpExpression* Complement(EXPR&& expr) {
+        return create<ast::UnaryOpExpression>(ast::UnaryOp::kComplement,
+                                              Expr(std::forward<EXPR>(expr)));
+    }
 
-  /// Creates a ast::IfStatement with input condition, body, and optional
-  /// variadic else statements
-  /// @param source the source information for the if statement
-  /// @param condition the if statement condition expression
-  /// @param body the if statement body
-  /// @param elseStatements optional variadic else statements
-  /// @returns the if statement pointer
-  template <typename CONDITION, typename... ELSE_STATEMENTS>
-  const ast::IfStatement* If(const Source& source,
-                             CONDITION&& condition,
-                             const ast::BlockStatement* body,
-                             ELSE_STATEMENTS&&... elseStatements) {
-    return create<ast::IfStatement>(
-        source, Expr(std::forward<CONDITION>(condition)), body,
-        ast::ElseStatementList{
-            std::forward<ELSE_STATEMENTS>(elseStatements)...});
-  }
+    /// @param expr the expression to perform a unary negation on
+    /// @return an ast::UnaryOpExpression that is the unary negation of the
+    /// input expression
+    template <typename EXPR>
+    const ast::UnaryOpExpression* Negation(EXPR&& expr) {
+        return create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation,
+                                              Expr(std::forward<EXPR>(expr)));
+    }
 
-  /// Creates a ast::IfStatement with input condition, body, and optional
-  /// variadic else statements
-  /// @param condition the if statement condition expression
-  /// @param body the if statement body
-  /// @param elseStatements optional variadic else statements
-  /// @returns the if statement pointer
-  template <typename CONDITION, typename... ELSE_STATEMENTS>
-  const ast::IfStatement* If(CONDITION&& condition,
-                             const ast::BlockStatement* body,
-                             ELSE_STATEMENTS&&... elseStatements) {
-    return create<ast::IfStatement>(
-        Expr(std::forward<CONDITION>(condition)), body,
-        ast::ElseStatementList{
-            std::forward<ELSE_STATEMENTS>(elseStatements)...});
-  }
+    /// @param source the source information
+    /// @param func the function name
+    /// @param args the function call arguments
+    /// @returns a `ast::CallExpression` to the function `func`, with the
+    /// arguments of `args` converted to `ast::Expression`s using `Expr()`.
+    template <typename NAME, typename... ARGS>
+    const ast::CallExpression* Call(const Source& source, NAME&& func, ARGS&&... args) {
+        return create<ast::CallExpression>(source, Expr(func),
+                                           ExprList(std::forward<ARGS>(args)...));
+    }
 
-  /// Creates a ast::AssignmentStatement with input lhs and rhs expressions
-  /// @param source the source information
-  /// @param lhs the left hand side expression initializer
-  /// @param rhs the right hand side expression initializer
-  /// @returns the assignment statement pointer
-  template <typename LhsExpressionInit, typename RhsExpressionInit>
-  const ast::AssignmentStatement* Assign(const Source& source,
-                                         LhsExpressionInit&& lhs,
-                                         RhsExpressionInit&& rhs) {
-    return create<ast::AssignmentStatement>(
-        source, Expr(std::forward<LhsExpressionInit>(lhs)),
-        Expr(std::forward<RhsExpressionInit>(rhs)));
-  }
+    /// @param func the function name
+    /// @param args the function call arguments
+    /// @returns a `ast::CallExpression` to the function `func`, with the
+    /// arguments of `args` converted to `ast::Expression`s using `Expr()`.
+    template <typename NAME, typename... ARGS, typename = DisableIfSource<NAME>>
+    const ast::CallExpression* Call(NAME&& func, ARGS&&... args) {
+        return create<ast::CallExpression>(Expr(func), ExprList(std::forward<ARGS>(args)...));
+    }
 
-  /// Creates a ast::AssignmentStatement with input lhs and rhs expressions
-  /// @param lhs the left hand side expression initializer
-  /// @param rhs the right hand side expression initializer
-  /// @returns the assignment statement pointer
-  template <typename LhsExpressionInit, typename RhsExpressionInit>
-  const ast::AssignmentStatement* Assign(LhsExpressionInit&& lhs,
-                                         RhsExpressionInit&& rhs) {
-    return create<ast::AssignmentStatement>(
-        Expr(std::forward<LhsExpressionInit>(lhs)),
-        Expr(std::forward<RhsExpressionInit>(rhs)));
-  }
+    /// @param source the source information
+    /// @param call the call expression to wrap in a call statement
+    /// @returns a `ast::CallStatement` for the given call expression
+    const ast::CallStatement* CallStmt(const Source& source, const ast::CallExpression* call) {
+        return create<ast::CallStatement>(source, call);
+    }
 
-  /// Creates a ast::CompoundAssignmentStatement with input lhs and rhs
-  /// expressions, and a binary operator.
-  /// @param source the source information
-  /// @param lhs the left hand side expression initializer
-  /// @param rhs the right hand side expression initializer
-  /// @param op the binary operator
-  /// @returns the compound assignment statement pointer
-  template <typename LhsExpressionInit, typename RhsExpressionInit>
-  const ast::CompoundAssignmentStatement* CompoundAssign(
-      const Source& source,
-      LhsExpressionInit&& lhs,
-      RhsExpressionInit&& rhs,
-      ast::BinaryOp op) {
-    return create<ast::CompoundAssignmentStatement>(
-        source, Expr(std::forward<LhsExpressionInit>(lhs)),
-        Expr(std::forward<RhsExpressionInit>(rhs)), op);
-  }
+    /// @param call the call expression to wrap in a call statement
+    /// @returns a `ast::CallStatement` for the given call expression
+    const ast::CallStatement* CallStmt(const ast::CallExpression* call) {
+        return create<ast::CallStatement>(call);
+    }
 
-  /// Creates a ast::CompoundAssignmentStatement with input lhs and rhs
-  /// expressions, and a binary operator.
-  /// @param lhs the left hand side expression initializer
-  /// @param rhs the right hand side expression initializer
-  /// @param op the binary operator
-  /// @returns the compound assignment statement pointer
-  template <typename LhsExpressionInit, typename RhsExpressionInit>
-  const ast::CompoundAssignmentStatement* CompoundAssign(
-      LhsExpressionInit&& lhs,
-      RhsExpressionInit&& rhs,
-      ast::BinaryOp op) {
-    return create<ast::CompoundAssignmentStatement>(
-        Expr(std::forward<LhsExpressionInit>(lhs)),
-        Expr(std::forward<RhsExpressionInit>(rhs)), op);
-  }
+    /// @param source the source information
+    /// @returns a `ast::PhonyExpression`
+    const ast::PhonyExpression* Phony(const Source& source) {
+        return create<ast::PhonyExpression>(source);
+    }
 
-  /// Creates an ast::IncrementDecrementStatement with input lhs.
-  /// @param source the source information
-  /// @param lhs the left hand side expression initializer
-  /// @returns the increment decrement statement pointer
-  template <typename LhsExpressionInit>
-  const ast::IncrementDecrementStatement* Increment(const Source& source,
-                                                    LhsExpressionInit&& lhs) {
-    return create<ast::IncrementDecrementStatement>(
-        source, Expr(std::forward<LhsExpressionInit>(lhs)), true);
-  }
+    /// @returns a `ast::PhonyExpression`
+    const ast::PhonyExpression* Phony() { return create<ast::PhonyExpression>(); }
 
-  /// Creates a ast::IncrementDecrementStatement with input lhs.
-  /// @param lhs the left hand side expression initializer
-  /// @returns the increment decrement statement pointer
-  template <typename LhsExpressionInit>
-  const ast::IncrementDecrementStatement* Increment(LhsExpressionInit&& lhs) {
-    return create<ast::IncrementDecrementStatement>(
-        Expr(std::forward<LhsExpressionInit>(lhs)), true);
-  }
+    /// @param expr the expression to ignore
+    /// @returns a `ast::AssignmentStatement` that assigns 'expr' to the phony
+    /// (underscore) variable.
+    template <typename EXPR>
+    const ast::AssignmentStatement* Ignore(EXPR&& expr) {
+        return create<ast::AssignmentStatement>(Phony(), Expr(expr));
+    }
 
-  /// Creates an ast::IncrementDecrementStatement with input lhs.
-  /// @param source the source information
-  /// @param lhs the left hand side expression initializer
-  /// @returns the increment decrement statement pointer
-  template <typename LhsExpressionInit>
-  const ast::IncrementDecrementStatement* Decrement(const Source& source,
-                                                    LhsExpressionInit&& lhs) {
-    return create<ast::IncrementDecrementStatement>(
-        source, Expr(std::forward<LhsExpressionInit>(lhs)), false);
-  }
+    /// @param lhs the left hand argument to the addition operation
+    /// @param rhs the right hand argument to the addition operation
+    /// @returns a `ast::BinaryExpression` summing the arguments `lhs` and `rhs`
+    template <typename LHS, typename RHS>
+    const ast::BinaryExpression* Add(LHS&& lhs, RHS&& rhs) {
+        return create<ast::BinaryExpression>(ast::BinaryOp::kAdd, Expr(std::forward<LHS>(lhs)),
+                                             Expr(std::forward<RHS>(rhs)));
+    }
 
-  /// Creates a ast::IncrementDecrementStatement with input lhs.
-  /// @param lhs the left hand side expression initializer
-  /// @returns the increment decrement statement pointer
-  template <typename LhsExpressionInit>
-  const ast::IncrementDecrementStatement* Decrement(LhsExpressionInit&& lhs) {
-    return create<ast::IncrementDecrementStatement>(
-        Expr(std::forward<LhsExpressionInit>(lhs)), false);
-  }
+    /// @param lhs the left hand argument to the and operation
+    /// @param rhs the right hand argument to the and operation
+    /// @returns a `ast::BinaryExpression` bitwise anding `lhs` and `rhs`
+    template <typename LHS, typename RHS>
+    const ast::BinaryExpression* And(LHS&& lhs, RHS&& rhs) {
+        return create<ast::BinaryExpression>(ast::BinaryOp::kAnd, Expr(std::forward<LHS>(lhs)),
+                                             Expr(std::forward<RHS>(rhs)));
+    }
 
-  /// Creates a ast::LoopStatement with input body and optional continuing
-  /// @param source the source information
-  /// @param body the loop body
-  /// @param continuing the optional continuing block
-  /// @returns the loop statement pointer
-  const ast::LoopStatement* Loop(
-      const Source& source,
-      const ast::BlockStatement* body,
-      const ast::BlockStatement* continuing = nullptr) {
-    return create<ast::LoopStatement>(source, body, continuing);
-  }
+    /// @param lhs the left hand argument to the or operation
+    /// @param rhs the right hand argument to the or operation
+    /// @returns a `ast::BinaryExpression` bitwise or-ing `lhs` and `rhs`
+    template <typename LHS, typename RHS>
+    const ast::BinaryExpression* Or(LHS&& lhs, RHS&& rhs) {
+        return create<ast::BinaryExpression>(ast::BinaryOp::kOr, Expr(std::forward<LHS>(lhs)),
+                                             Expr(std::forward<RHS>(rhs)));
+    }
 
-  /// Creates a ast::LoopStatement with input body and optional continuing
-  /// @param body the loop body
-  /// @param continuing the optional continuing block
-  /// @returns the loop statement pointer
-  const ast::LoopStatement* Loop(
-      const ast::BlockStatement* body,
-      const ast::BlockStatement* continuing = nullptr) {
-    return create<ast::LoopStatement>(body, continuing);
-  }
+    /// @param lhs the left hand argument to the subtraction operation
+    /// @param rhs the right hand argument to the subtraction operation
+    /// @returns a `ast::BinaryExpression` subtracting `rhs` from `lhs`
+    template <typename LHS, typename RHS>
+    const ast::BinaryExpression* Sub(LHS&& lhs, RHS&& rhs) {
+        return create<ast::BinaryExpression>(ast::BinaryOp::kSubtract, Expr(std::forward<LHS>(lhs)),
+                                             Expr(std::forward<RHS>(rhs)));
+    }
 
-  /// Creates a ast::ForLoopStatement with input body and optional initializer,
-  /// condition and continuing.
-  /// @param source the source information
-  /// @param init the optional loop initializer
-  /// @param cond the optional loop condition
-  /// @param cont the optional loop continuing
-  /// @param body the loop body
-  /// @returns the for loop statement pointer
-  template <typename COND>
-  const ast::ForLoopStatement* For(const Source& source,
-                                   const ast::Statement* init,
-                                   COND&& cond,
-                                   const ast::Statement* cont,
-                                   const ast::BlockStatement* body) {
-    return create<ast::ForLoopStatement>(
-        source, init, Expr(std::forward<COND>(cond)), cont, body);
-  }
+    /// @param lhs the left hand argument to the multiplication operation
+    /// @param rhs the right hand argument to the multiplication operation
+    /// @returns a `ast::BinaryExpression` multiplying `rhs` from `lhs`
+    template <typename LHS, typename RHS>
+    const ast::BinaryExpression* Mul(LHS&& lhs, RHS&& rhs) {
+        return create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, Expr(std::forward<LHS>(lhs)),
+                                             Expr(std::forward<RHS>(rhs)));
+    }
 
-  /// Creates a ast::ForLoopStatement with input body and optional initializer,
-  /// condition and continuing.
-  /// @param init the optional loop initializer
-  /// @param cond the optional loop condition
-  /// @param cont the optional loop continuing
-  /// @param body the loop body
-  /// @returns the for loop statement pointer
-  template <typename COND>
-  const ast::ForLoopStatement* For(const ast::Statement* init,
-                                   COND&& cond,
-                                   const ast::Statement* cont,
-                                   const ast::BlockStatement* body) {
-    return create<ast::ForLoopStatement>(init, Expr(std::forward<COND>(cond)),
-                                         cont, body);
-  }
+    /// @param source the source information
+    /// @param lhs the left hand argument to the multiplication operation
+    /// @param rhs the right hand argument to the multiplication operation
+    /// @returns a `ast::BinaryExpression` multiplying `rhs` from `lhs`
+    template <typename LHS, typename RHS>
+    const ast::BinaryExpression* Mul(const Source& source, LHS&& lhs, RHS&& rhs) {
+        return create<ast::BinaryExpression>(source, ast::BinaryOp::kMultiply,
+                                             Expr(std::forward<LHS>(lhs)),
+                                             Expr(std::forward<RHS>(rhs)));
+    }
 
-  /// Creates a ast::VariableDeclStatement for the input variable
-  /// @param source the source information
-  /// @param var the variable to wrap in a decl statement
-  /// @returns the variable decl statement pointer
-  const ast::VariableDeclStatement* Decl(const Source& source,
-                                         const ast::Variable* var) {
-    return create<ast::VariableDeclStatement>(source, var);
-  }
+    /// @param lhs the left hand argument to the division operation
+    /// @param rhs the right hand argument to the division operation
+    /// @returns a `ast::BinaryExpression` dividing `lhs` by `rhs`
+    template <typename LHS, typename RHS>
+    const ast::BinaryExpression* Div(LHS&& lhs, RHS&& rhs) {
+        return create<ast::BinaryExpression>(ast::BinaryOp::kDivide, Expr(std::forward<LHS>(lhs)),
+                                             Expr(std::forward<RHS>(rhs)));
+    }
 
-  /// Creates a ast::VariableDeclStatement for the input variable
-  /// @param var the variable to wrap in a decl statement
-  /// @returns the variable decl statement pointer
-  const ast::VariableDeclStatement* Decl(const ast::Variable* var) {
-    return create<ast::VariableDeclStatement>(var);
-  }
+    /// @param lhs the left hand argument to the modulo operation
+    /// @param rhs the right hand argument to the modulo operation
+    /// @returns a `ast::BinaryExpression` applying modulo of `lhs` by `rhs`
+    template <typename LHS, typename RHS>
+    const ast::BinaryExpression* Mod(LHS&& lhs, RHS&& rhs) {
+        return create<ast::BinaryExpression>(ast::BinaryOp::kModulo, Expr(std::forward<LHS>(lhs)),
+                                             Expr(std::forward<RHS>(rhs)));
+    }
 
-  /// Creates a ast::SwitchStatement with input expression and cases
-  /// @param source the source information
-  /// @param condition the condition expression initializer
-  /// @param cases case statements
-  /// @returns the switch statement pointer
-  template <typename ExpressionInit, typename... Cases>
-  const ast::SwitchStatement* Switch(const Source& source,
-                                     ExpressionInit&& condition,
-                                     Cases&&... cases) {
-    return create<ast::SwitchStatement>(
-        source, Expr(std::forward<ExpressionInit>(condition)),
-        ast::CaseStatementList{std::forward<Cases>(cases)...});
-  }
+    /// @param lhs the left hand argument to the bit shift right operation
+    /// @param rhs the right hand argument to the bit shift right operation
+    /// @returns a `ast::BinaryExpression` bit shifting right `lhs` by `rhs`
+    template <typename LHS, typename RHS>
+    const ast::BinaryExpression* Shr(LHS&& lhs, RHS&& rhs) {
+        return create<ast::BinaryExpression>(
+            ast::BinaryOp::kShiftRight, Expr(std::forward<LHS>(lhs)), Expr(std::forward<RHS>(rhs)));
+    }
 
-  /// Creates a ast::SwitchStatement with input expression and cases
-  /// @param condition the condition expression initializer
-  /// @param cases case statements
-  /// @returns the switch statement pointer
-  template <typename ExpressionInit,
-            typename... Cases,
-            typename = DisableIfSource<ExpressionInit>>
-  const ast::SwitchStatement* Switch(ExpressionInit&& condition,
-                                     Cases&&... cases) {
-    return create<ast::SwitchStatement>(
-        Expr(std::forward<ExpressionInit>(condition)),
-        ast::CaseStatementList{std::forward<Cases>(cases)...});
-  }
+    /// @param lhs the left hand argument to the bit shift left operation
+    /// @param rhs the right hand argument to the bit shift left operation
+    /// @returns a `ast::BinaryExpression` bit shifting left `lhs` by `rhs`
+    template <typename LHS, typename RHS>
+    const ast::BinaryExpression* Shl(LHS&& lhs, RHS&& rhs) {
+        return create<ast::BinaryExpression>(
+            ast::BinaryOp::kShiftLeft, Expr(std::forward<LHS>(lhs)), Expr(std::forward<RHS>(rhs)));
+    }
 
-  /// Creates a ast::CaseStatement with input list of selectors, and body
-  /// @param source the source information
-  /// @param selectors list of selectors
-  /// @param body the case body
-  /// @returns the case statement pointer
-  const ast::CaseStatement* Case(const Source& source,
-                                 ast::CaseSelectorList selectors,
-                                 const ast::BlockStatement* body = nullptr) {
-    return create<ast::CaseStatement>(source, std::move(selectors),
-                                      body ? body : Block());
-  }
+    /// @param lhs the left hand argument to the xor operation
+    /// @param rhs the right hand argument to the xor operation
+    /// @returns a `ast::BinaryExpression` bitwise xor-ing `lhs` and `rhs`
+    template <typename LHS, typename RHS>
+    const ast::BinaryExpression* Xor(LHS&& lhs, RHS&& rhs) {
+        return create<ast::BinaryExpression>(ast::BinaryOp::kXor, Expr(std::forward<LHS>(lhs)),
+                                             Expr(std::forward<RHS>(rhs)));
+    }
 
-  /// Creates a ast::CaseStatement with input list of selectors, and body
-  /// @param selectors list of selectors
-  /// @param body the case body
-  /// @returns the case statement pointer
-  const ast::CaseStatement* Case(ast::CaseSelectorList selectors,
-                                 const ast::BlockStatement* body = nullptr) {
-    return create<ast::CaseStatement>(std::move(selectors),
-                                      body ? body : Block());
-  }
+    /// @param lhs the left hand argument to the logical and operation
+    /// @param rhs the right hand argument to the logical and operation
+    /// @returns a `ast::BinaryExpression` of `lhs` && `rhs`
+    template <typename LHS, typename RHS>
+    const ast::BinaryExpression* LogicalAnd(LHS&& lhs, RHS&& rhs) {
+        return create<ast::BinaryExpression>(
+            ast::BinaryOp::kLogicalAnd, Expr(std::forward<LHS>(lhs)), Expr(std::forward<RHS>(rhs)));
+    }
 
-  /// Convenient overload that takes a single selector
-  /// @param selector a single case selector
-  /// @param body the case body
-  /// @returns the case statement pointer
-  const ast::CaseStatement* Case(const ast::IntLiteralExpression* selector,
-                                 const ast::BlockStatement* body = nullptr) {
-    return Case(ast::CaseSelectorList{selector}, body);
-  }
+    /// @param lhs the left hand argument to the logical or operation
+    /// @param rhs the right hand argument to the logical or operation
+    /// @returns a `ast::BinaryExpression` of `lhs` || `rhs`
+    template <typename LHS, typename RHS>
+    const ast::BinaryExpression* LogicalOr(LHS&& lhs, RHS&& rhs) {
+        return create<ast::BinaryExpression>(
+            ast::BinaryOp::kLogicalOr, Expr(std::forward<LHS>(lhs)), Expr(std::forward<RHS>(rhs)));
+    }
 
-  /// Convenience function that creates a 'default' ast::CaseStatement
-  /// @param source the source information
-  /// @param body the case body
-  /// @returns the case statement pointer
-  const ast::CaseStatement* DefaultCase(
-      const Source& source,
-      const ast::BlockStatement* body = nullptr) {
-    return Case(source, ast::CaseSelectorList{}, body);
-  }
+    /// @param lhs the left hand argument to the greater than operation
+    /// @param rhs the right hand argument to the greater than operation
+    /// @returns a `ast::BinaryExpression` of `lhs` > `rhs`
+    template <typename LHS, typename RHS>
+    const ast::BinaryExpression* GreaterThan(LHS&& lhs, RHS&& rhs) {
+        return create<ast::BinaryExpression>(ast::BinaryOp::kGreaterThan,
+                                             Expr(std::forward<LHS>(lhs)),
+                                             Expr(std::forward<RHS>(rhs)));
+    }
 
-  /// Convenience function that creates a 'default' ast::CaseStatement
-  /// @param body the case body
-  /// @returns the case statement pointer
-  const ast::CaseStatement* DefaultCase(
-      const ast::BlockStatement* body = nullptr) {
-    return Case(ast::CaseSelectorList{}, body);
-  }
+    /// @param lhs the left hand argument to the greater than or equal operation
+    /// @param rhs the right hand argument to the greater than or equal operation
+    /// @returns a `ast::BinaryExpression` of `lhs` >= `rhs`
+    template <typename LHS, typename RHS>
+    const ast::BinaryExpression* GreaterThanEqual(LHS&& lhs, RHS&& rhs) {
+        return create<ast::BinaryExpression>(ast::BinaryOp::kGreaterThanEqual,
+                                             Expr(std::forward<LHS>(lhs)),
+                                             Expr(std::forward<RHS>(rhs)));
+    }
 
-  /// Creates an ast::FallthroughStatement
-  /// @param source the source information
-  /// @returns the fallthrough statement pointer
-  const ast::FallthroughStatement* Fallthrough(const Source& source) {
-    return create<ast::FallthroughStatement>(source);
-  }
+    /// @param lhs the left hand argument to the less than operation
+    /// @param rhs the right hand argument to the less than operation
+    /// @returns a `ast::BinaryExpression` of `lhs` < `rhs`
+    template <typename LHS, typename RHS>
+    const ast::BinaryExpression* LessThan(LHS&& lhs, RHS&& rhs) {
+        return create<ast::BinaryExpression>(ast::BinaryOp::kLessThan, Expr(std::forward<LHS>(lhs)),
+                                             Expr(std::forward<RHS>(rhs)));
+    }
 
-  /// Creates an ast::FallthroughStatement
-  /// @returns the fallthrough statement pointer
-  const ast::FallthroughStatement* Fallthrough() {
-    return create<ast::FallthroughStatement>();
-  }
+    /// @param lhs the left hand argument to the less than or equal operation
+    /// @param rhs the right hand argument to the less than or equal operation
+    /// @returns a `ast::BinaryExpression` of `lhs` <= `rhs`
+    template <typename LHS, typename RHS>
+    const ast::BinaryExpression* LessThanEqual(LHS&& lhs, RHS&& rhs) {
+        return create<ast::BinaryExpression>(ast::BinaryOp::kLessThanEqual,
+                                             Expr(std::forward<LHS>(lhs)),
+                                             Expr(std::forward<RHS>(rhs)));
+    }
 
-  /// Creates an ast::BuiltinAttribute
-  /// @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) {
-    return create<ast::BuiltinAttribute>(source, builtin);
-  }
+    /// @param lhs the left hand argument to the equal expression
+    /// @param rhs the right hand argument to the equal expression
+    /// @returns a `ast::BinaryExpression` comparing `lhs` equal to `rhs`
+    template <typename LHS, typename RHS>
+    const ast::BinaryExpression* Equal(LHS&& lhs, RHS&& rhs) {
+        return create<ast::BinaryExpression>(ast::BinaryOp::kEqual, Expr(std::forward<LHS>(lhs)),
+                                             Expr(std::forward<RHS>(rhs)));
+    }
 
-  /// Creates an ast::BuiltinAttribute
-  /// @param builtin the builtin value
-  /// @returns the builtin attribute pointer
-  const ast::BuiltinAttribute* Builtin(ast::Builtin builtin) {
-    return create<ast::BuiltinAttribute>(source_, builtin);
-  }
+    /// @param lhs the left hand argument to the not-equal expression
+    /// @param rhs the right hand argument to the not-equal expression
+    /// @returns a `ast::BinaryExpression` comparing `lhs` equal to `rhs` for
+    ///          disequality
+    template <typename LHS, typename RHS>
+    const ast::BinaryExpression* NotEqual(LHS&& lhs, RHS&& rhs) {
+        return create<ast::BinaryExpression>(ast::BinaryOp::kNotEqual, Expr(std::forward<LHS>(lhs)),
+                                             Expr(std::forward<RHS>(rhs)));
+    }
 
-  /// Creates an ast::InterpolateAttribute
-  /// @param source the source information
-  /// @param type the interpolation type
-  /// @param sampling the interpolation sampling
-  /// @returns the interpolate attribute pointer
-  const ast::InterpolateAttribute* Interpolate(
-      const Source& source,
-      ast::InterpolationType type,
-      ast::InterpolationSampling sampling = ast::InterpolationSampling::kNone) {
-    return create<ast::InterpolateAttribute>(source, type, sampling);
-  }
+    /// @param source the source information
+    /// @param obj the object for the index accessor expression
+    /// @param idx the index argument for the index accessor expression
+    /// @returns a `ast::IndexAccessorExpression` that indexes `arr` with `idx`
+    template <typename OBJ, typename IDX>
+    const ast::IndexAccessorExpression* IndexAccessor(const Source& source, OBJ&& obj, IDX&& idx) {
+        return create<ast::IndexAccessorExpression>(source, Expr(std::forward<OBJ>(obj)),
+                                                    Expr(std::forward<IDX>(idx)));
+    }
 
-  /// Creates an ast::InterpolateAttribute
-  /// @param type the interpolation type
-  /// @param sampling the interpolation sampling
-  /// @returns the interpolate attribute pointer
-  const ast::InterpolateAttribute* Interpolate(
-      ast::InterpolationType type,
-      ast::InterpolationSampling sampling = ast::InterpolationSampling::kNone) {
-    return create<ast::InterpolateAttribute>(source_, type, sampling);
-  }
+    /// @param obj the object for the index accessor expression
+    /// @param idx the index argument for the index accessor expression
+    /// @returns a `ast::IndexAccessorExpression` that indexes `arr` with `idx`
+    template <typename OBJ, typename IDX>
+    const ast::IndexAccessorExpression* IndexAccessor(OBJ&& obj, IDX&& idx) {
+        return create<ast::IndexAccessorExpression>(Expr(std::forward<OBJ>(obj)),
+                                                    Expr(std::forward<IDX>(idx)));
+    }
 
-  /// Creates an ast::InterpolateAttribute using flat interpolation
-  /// @param source the source information
-  /// @returns the interpolate attribute pointer
-  const ast::InterpolateAttribute* Flat(const Source& source) {
-    return Interpolate(source, ast::InterpolationType::kFlat);
-  }
+    /// @param source the source information
+    /// @param obj the object for the member accessor expression
+    /// @param idx the index argument for the member accessor expression
+    /// @returns a `ast::MemberAccessorExpression` that indexes `obj` with `idx`
+    template <typename OBJ, typename IDX>
+    const ast::MemberAccessorExpression* MemberAccessor(const Source& source,
+                                                        OBJ&& obj,
+                                                        IDX&& idx) {
+        return create<ast::MemberAccessorExpression>(source, Expr(std::forward<OBJ>(obj)),
+                                                     Expr(std::forward<IDX>(idx)));
+    }
 
-  /// Creates an ast::InterpolateAttribute using flat interpolation
-  /// @returns the interpolate attribute pointer
-  const ast::InterpolateAttribute* Flat() {
-    return Interpolate(ast::InterpolationType::kFlat);
-  }
+    /// @param obj the object for the member accessor expression
+    /// @param idx the index argument for the member accessor expression
+    /// @returns a `ast::MemberAccessorExpression` that indexes `obj` with `idx`
+    template <typename OBJ, typename IDX>
+    const ast::MemberAccessorExpression* MemberAccessor(OBJ&& obj, IDX&& idx) {
+        return create<ast::MemberAccessorExpression>(Expr(std::forward<OBJ>(obj)),
+                                                     Expr(std::forward<IDX>(idx)));
+    }
 
-  /// Creates an ast::InvariantAttribute
-  /// @param source the source information
-  /// @returns the invariant attribute pointer
-  const ast::InvariantAttribute* Invariant(const Source& source) {
-    return create<ast::InvariantAttribute>(source);
-  }
+    /// Creates a ast::StructMemberOffsetAttribute
+    /// @param val the offset value
+    /// @returns the offset attribute pointer
+    const ast::StructMemberOffsetAttribute* MemberOffset(uint32_t val) {
+        return create<ast::StructMemberOffsetAttribute>(source_, val);
+    }
 
-  /// Creates an ast::InvariantAttribute
-  /// @returns the invariant attribute pointer
-  const ast::InvariantAttribute* Invariant() {
-    return create<ast::InvariantAttribute>(source_);
-  }
+    /// Creates a ast::StructMemberSizeAttribute
+    /// @param source the source information
+    /// @param val the size value
+    /// @returns the size attribute pointer
+    const ast::StructMemberSizeAttribute* MemberSize(const Source& source, uint32_t val) {
+        return create<ast::StructMemberSizeAttribute>(source, val);
+    }
 
-  /// Creates an ast::LocationAttribute
-  /// @param source the source information
-  /// @param location the location value
-  /// @returns the location attribute pointer
-  const ast::LocationAttribute* Location(const Source& source,
-                                         uint32_t location) {
-    return create<ast::LocationAttribute>(source, location);
-  }
+    /// Creates a ast::StructMemberSizeAttribute
+    /// @param val the size value
+    /// @returns the size attribute pointer
+    const ast::StructMemberSizeAttribute* MemberSize(uint32_t val) {
+        return create<ast::StructMemberSizeAttribute>(source_, val);
+    }
 
-  /// Creates an ast::LocationAttribute
-  /// @param location the location value
-  /// @returns the location attribute pointer
-  const ast::LocationAttribute* Location(uint32_t location) {
-    return create<ast::LocationAttribute>(source_, location);
-  }
+    /// Creates a ast::StructMemberAlignAttribute
+    /// @param source the source information
+    /// @param val the align value
+    /// @returns the align attribute pointer
+    const ast::StructMemberAlignAttribute* MemberAlign(const Source& source, uint32_t val) {
+        return create<ast::StructMemberAlignAttribute>(source, val);
+    }
 
-  /// 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 a ast::StructMemberAlignAttribute
+    /// @param val the align value
+    /// @returns the align attribute pointer
+    const ast::StructMemberAlignAttribute* MemberAlign(uint32_t val) {
+        return create<ast::StructMemberAlignAttribute>(source_, val);
+    }
 
-  /// Creates an ast::IdAttribute with a constant ID
-  /// @param id the optional id value
-  /// @returns the override attribute pointer
-  const ast::IdAttribute* Id(uint32_t id) { return Id(source_, id); }
+    /// Creates the ast::GroupAttribute
+    /// @param value group attribute index
+    /// @returns the group attribute pointer
+    const ast::GroupAttribute* Group(uint32_t value) { return create<ast::GroupAttribute>(value); }
 
-  /// Creates an ast::StageAttribute
-  /// @param source the source information
-  /// @param stage the pipeline stage
-  /// @returns the stage attribute pointer
-  const ast::StageAttribute* Stage(const Source& source,
-                                   ast::PipelineStage stage) {
-    return create<ast::StageAttribute>(source, stage);
-  }
+    /// Creates the ast::BindingAttribute
+    /// @param value the binding index
+    /// @returns the binding deocration pointer
+    const ast::BindingAttribute* Binding(uint32_t value) {
+        return create<ast::BindingAttribute>(value);
+    }
 
-  /// Creates an ast::StageAttribute
-  /// @param stage the pipeline stage
-  /// @returns the stage attribute pointer
-  const ast::StageAttribute* Stage(ast::PipelineStage stage) {
-    return create<ast::StageAttribute>(source_, stage);
-  }
+    /// Convenience function to create both a ast::GroupAttribute and
+    /// ast::BindingAttribute
+    /// @param group the group index
+    /// @param binding the binding index
+    /// @returns a attribute list with both the group and binding attributes
+    ast::AttributeList GroupAndBinding(uint32_t group, uint32_t binding) {
+        return {Group(group), Binding(binding)};
+    }
 
-  /// Creates an ast::WorkgroupAttribute
-  /// @param x the x dimension expression
-  /// @returns the workgroup attribute pointer
-  template <typename EXPR_X>
-  const ast::WorkgroupAttribute* WorkgroupSize(EXPR_X&& x) {
-    return WorkgroupSize(std::forward<EXPR_X>(x), nullptr, nullptr);
-  }
+    /// Creates an ast::Function and registers it with the ast::Module.
+    /// @param source the source information
+    /// @param name the function name
+    /// @param params the function parameters
+    /// @param type the function return type
+    /// @param body the function body
+    /// @param attributes the optional function attributes
+    /// @param return_type_attributes the optional function return type
+    /// attributes
+    /// @returns the function pointer
+    template <typename NAME>
+    const ast::Function* Func(const Source& source,
+                              NAME&& name,
+                              ast::VariableList params,
+                              const ast::Type* type,
+                              ast::StatementList body,
+                              ast::AttributeList attributes = {},
+                              ast::AttributeList return_type_attributes = {}) {
+        auto* func = create<ast::Function>(source, Sym(std::forward<NAME>(name)), params, type,
+                                           create<ast::BlockStatement>(body), attributes,
+                                           return_type_attributes);
+        AST().AddFunction(func);
+        return func;
+    }
 
-  /// Creates an ast::WorkgroupAttribute
-  /// @param x the x dimension expression
-  /// @param y the y dimension expression
-  /// @returns the workgroup attribute pointer
-  template <typename EXPR_X, typename EXPR_Y>
-  const ast::WorkgroupAttribute* WorkgroupSize(EXPR_X&& x, EXPR_Y&& y) {
-    return WorkgroupSize(std::forward<EXPR_X>(x), std::forward<EXPR_Y>(y),
-                         nullptr);
-  }
+    /// Creates an ast::Function and registers it with the ast::Module.
+    /// @param name the function name
+    /// @param params the function parameters
+    /// @param type the function return type
+    /// @param body the function body
+    /// @param attributes the optional function attributes
+    /// @param return_type_attributes the optional function return type
+    /// attributes
+    /// @returns the function pointer
+    template <typename NAME>
+    const ast::Function* Func(NAME&& name,
+                              ast::VariableList params,
+                              const ast::Type* type,
+                              ast::StatementList body,
+                              ast::AttributeList attributes = {},
+                              ast::AttributeList return_type_attributes = {}) {
+        auto* func = create<ast::Function>(Sym(std::forward<NAME>(name)), params, type,
+                                           create<ast::BlockStatement>(body), attributes,
+                                           return_type_attributes);
+        AST().AddFunction(func);
+        return func;
+    }
 
-  /// Creates an ast::WorkgroupAttribute
-  /// @param source the source information
-  /// @param x the x dimension expression
-  /// @param y the y dimension expression
-  /// @param z the z dimension expression
-  /// @returns the workgroup attribute pointer
-  template <typename EXPR_X, typename EXPR_Y, typename EXPR_Z>
-  const ast::WorkgroupAttribute* WorkgroupSize(const Source& source,
-                                               EXPR_X&& x,
-                                               EXPR_Y&& y,
-                                               EXPR_Z&& z) {
-    return create<ast::WorkgroupAttribute>(
-        source, Expr(std::forward<EXPR_X>(x)), Expr(std::forward<EXPR_Y>(y)),
-        Expr(std::forward<EXPR_Z>(z)));
-  }
+    /// Creates an ast::BreakStatement
+    /// @param source the source information
+    /// @returns the break statement pointer
+    const ast::BreakStatement* Break(const Source& source) {
+        return create<ast::BreakStatement>(source);
+    }
 
-  /// Creates an ast::WorkgroupAttribute
-  /// @param x the x dimension expression
-  /// @param y the y dimension expression
-  /// @param z the z dimension expression
-  /// @returns the workgroup attribute pointer
-  template <typename EXPR_X, typename EXPR_Y, typename EXPR_Z>
-  const ast::WorkgroupAttribute* WorkgroupSize(EXPR_X&& x,
-                                               EXPR_Y&& y,
-                                               EXPR_Z&& z) {
-    return create<ast::WorkgroupAttribute>(
-        source_, Expr(std::forward<EXPR_X>(x)), Expr(std::forward<EXPR_Y>(y)),
-        Expr(std::forward<EXPR_Z>(z)));
-  }
+    /// Creates an ast::BreakStatement
+    /// @returns the break statement pointer
+    const ast::BreakStatement* Break() { return create<ast::BreakStatement>(); }
 
-  /// Creates an ast::DisableValidationAttribute
-  /// @param validation the validation to disable
-  /// @returns the disable validation attribute pointer
-  const ast::DisableValidationAttribute* Disable(
-      ast::DisabledValidation validation) {
-    return ASTNodes().Create<ast::DisableValidationAttribute>(ID(), validation);
-  }
+    /// Creates an ast::ContinueStatement
+    /// @param source the source information
+    /// @returns the continue statement pointer
+    const ast::ContinueStatement* Continue(const Source& source) {
+        return create<ast::ContinueStatement>(source);
+    }
 
-  /// Sets the current builder source to `src`
-  /// @param src the Source used for future create() calls
-  void SetSource(const Source& src) {
-    AssertNotMoved();
-    source_ = src;
-  }
+    /// Creates an ast::ContinueStatement
+    /// @returns the continue statement pointer
+    const ast::ContinueStatement* Continue() { return create<ast::ContinueStatement>(); }
 
-  /// Sets the current builder source to `loc`
-  /// @param loc the Source used for future create() calls
-  void SetSource(const Source::Location& loc) {
-    AssertNotMoved();
-    source_ = Source(loc);
-  }
+    /// Creates an ast::ReturnStatement with no return value
+    /// @param source the source information
+    /// @returns the return statement pointer
+    const ast::ReturnStatement* Return(const Source& source) {
+        return create<ast::ReturnStatement>(source);
+    }
 
-  /// Helper for returning the resolved semantic type of the expression `expr`.
-  /// @note As the Resolver is run when the Program is built, this will only be
-  /// useful for the Resolver itself and tests that use their own Resolver.
-  /// @param expr the AST expression
-  /// @return the resolved semantic type for the expression, or nullptr if the
-  /// expression has no resolved type.
-  const sem::Type* TypeOf(const ast::Expression* expr) const;
+    /// Creates an ast::ReturnStatement with no return value
+    /// @returns the return statement pointer
+    const ast::ReturnStatement* Return() { return create<ast::ReturnStatement>(); }
 
-  /// Helper for returning the resolved semantic type of the variable `var`.
-  /// @note As the Resolver is run when the Program is built, this will only be
-  /// useful for the Resolver itself and tests that use their own Resolver.
-  /// @param var the AST variable
-  /// @return the resolved semantic type for the variable, or nullptr if the
-  /// variable has no resolved type.
-  const sem::Type* TypeOf(const ast::Variable* var) const;
+    /// Creates an ast::ReturnStatement with the given return value
+    /// @param source the source information
+    /// @param val the return value
+    /// @returns the return statement pointer
+    template <typename EXPR>
+    const ast::ReturnStatement* Return(const Source& source, EXPR&& val) {
+        return create<ast::ReturnStatement>(source, Expr(std::forward<EXPR>(val)));
+    }
 
-  /// Helper for returning the resolved semantic type of the AST type `type`.
-  /// @note As the Resolver is run when the Program is built, this will only be
-  /// useful for the Resolver itself and tests that use their own Resolver.
-  /// @param type the AST type
-  /// @return the resolved semantic type for the type, or nullptr if the type
-  /// has no resolved type.
-  const sem::Type* TypeOf(const ast::Type* type) const;
+    /// Creates an ast::ReturnStatement with the given return value
+    /// @param val the return value
+    /// @returns the return statement pointer
+    template <typename EXPR, typename = DisableIfSource<EXPR>>
+    const ast::ReturnStatement* Return(EXPR&& val) {
+        return create<ast::ReturnStatement>(Expr(std::forward<EXPR>(val)));
+    }
 
-  /// Helper for returning the resolved semantic type of the AST type
-  /// declaration `type_decl`.
-  /// @note As the Resolver is run when the Program is built, this will only be
-  /// useful for the Resolver itself and tests that use their own Resolver.
-  /// @param type_decl the AST type declaration
-  /// @return the resolved semantic type for the type declaration, or nullptr if
-  /// the type declaration has no resolved type.
-  const sem::Type* TypeOf(const ast::TypeDecl* type_decl) const;
+    /// Creates an ast::DiscardStatement
+    /// @param source the source information
+    /// @returns the discard statement pointer
+    const ast::DiscardStatement* Discard(const Source& source) {
+        return create<ast::DiscardStatement>(source);
+    }
 
-  /// Wraps the ast::Expression in a statement. This is used by tests that
-  /// construct a partial AST and require the Resolver to reach these
-  /// nodes.
-  /// @param expr the ast::Expression to be wrapped by an ast::Statement
-  /// @return the ast::Statement that wraps the ast::Expression
-  const ast::Statement* WrapInStatement(const ast::Expression* expr);
-  /// Wraps the ast::Variable in a ast::VariableDeclStatement. This is used by
-  /// tests that construct a partial AST and require the Resolver to reach
-  /// these nodes.
-  /// @param v the ast::Variable to be wrapped by an ast::VariableDeclStatement
-  /// @return the ast::VariableDeclStatement that wraps the ast::Variable
-  const ast::VariableDeclStatement* WrapInStatement(const ast::Variable* v);
-  /// Returns the statement argument. Used as a passthrough-overload by
-  /// WrapInFunction().
-  /// @param stmt the ast::Statement
-  /// @return `stmt`
-  const ast::Statement* WrapInStatement(const ast::Statement* stmt);
-  /// Wraps the list of arguments in a simple function so that each is reachable
-  /// by the Resolver.
-  /// @param args a mix of ast::Expression, ast::Statement, ast::Variables.
-  /// @returns the function
-  template <typename... ARGS>
-  const ast::Function* WrapInFunction(ARGS&&... args) {
-    ast::StatementList stmts{WrapInStatement(std::forward<ARGS>(args))...};
-    return WrapInFunction(std::move(stmts));
-  }
-  /// @param stmts a list of ast::Statement that will be wrapped by a function,
-  /// so that each statement is reachable by the Resolver.
-  /// @returns the function
-  const ast::Function* WrapInFunction(ast::StatementList stmts);
+    /// Creates an ast::DiscardStatement
+    /// @returns the discard statement pointer
+    const ast::DiscardStatement* Discard() { return create<ast::DiscardStatement>(); }
 
-  /// The builder types
-  TypesBuilder const ty{this};
+    /// Creates a ast::Alias registering it with the AST().TypeDecls().
+    /// @param source the source information
+    /// @param name the alias name
+    /// @param type the alias target type
+    /// @returns the alias type
+    template <typename NAME>
+    const ast::Alias* Alias(const Source& source, NAME&& name, const ast::Type* type) {
+        auto* out = ty.alias(source, std::forward<NAME>(name), type);
+        AST().AddTypeDecl(out);
+        return out;
+    }
 
- protected:
-  /// Asserts that the builder has not been moved.
-  void AssertNotMoved() const;
+    /// Creates a ast::Alias registering it with the AST().TypeDecls().
+    /// @param name the alias name
+    /// @param type the alias target type
+    /// @returns the alias type
+    template <typename NAME>
+    const ast::Alias* Alias(NAME&& name, const ast::Type* type) {
+        auto* out = ty.alias(std::forward<NAME>(name), type);
+        AST().AddTypeDecl(out);
+        return out;
+    }
 
- private:
-  ProgramID id_;
-  sem::Manager types_;
-  ASTNodeAllocator ast_nodes_;
-  SemNodeAllocator sem_nodes_;
-  ast::Module* ast_;
-  sem::Info sem_;
-  SymbolTable symbols_{id_};
-  diag::List diagnostics_;
+    /// Creates a ast::Struct registering it with the AST().TypeDecls().
+    /// @param source the source information
+    /// @param name the struct name
+    /// @param members the struct members
+    /// @returns the struct type
+    template <typename NAME>
+    const ast::Struct* Structure(const Source& source, NAME&& name, ast::StructMemberList members) {
+        auto sym = Sym(std::forward<NAME>(name));
+        auto* type = create<ast::Struct>(source, sym, std::move(members), ast::AttributeList{});
+        AST().AddTypeDecl(type);
+        return type;
+    }
 
-  /// The source to use when creating AST nodes without providing a Source as
-  /// the first argument.
-  Source source_;
+    /// Creates a ast::Struct registering it with the AST().TypeDecls().
+    /// @param name the struct name
+    /// @param members the struct members
+    /// @returns the struct type
+    template <typename NAME>
+    const ast::Struct* Structure(NAME&& name, ast::StructMemberList members) {
+        auto sym = Sym(std::forward<NAME>(name));
+        auto* type = create<ast::Struct>(sym, std::move(members), ast::AttributeList{});
+        AST().AddTypeDecl(type);
+        return type;
+    }
 
-  /// Set by SetResolveOnBuild(). If set, the Resolver will be run on the
-  /// program when built.
-  bool resolve_on_build_ = true;
+    /// Creates a ast::StructMember
+    /// @param source the source information
+    /// @param name the struct member name
+    /// @param type the struct member type
+    /// @param attributes the optional struct member attributes
+    /// @returns the struct member pointer
+    template <typename NAME>
+    const ast::StructMember* Member(const Source& source,
+                                    NAME&& name,
+                                    const ast::Type* type,
+                                    ast::AttributeList attributes = {}) {
+        return create<ast::StructMember>(source, Sym(std::forward<NAME>(name)), type,
+                                         std::move(attributes));
+    }
 
-  /// Set by MarkAsMoved(). Once set, no methods may be called on this builder.
-  bool moved_ = false;
+    /// Creates a ast::StructMember
+    /// @param name the struct member name
+    /// @param type the struct member type
+    /// @param attributes the optional struct member attributes
+    /// @returns the struct member pointer
+    template <typename NAME>
+    const ast::StructMember* Member(NAME&& name,
+                                    const ast::Type* type,
+                                    ast::AttributeList attributes = {}) {
+        return create<ast::StructMember>(source_, Sym(std::forward<NAME>(name)), type,
+                                         std::move(attributes));
+    }
+
+    /// Creates a ast::StructMember with the given byte offset
+    /// @param offset the offset to use in the StructMemberOffsetattribute
+    /// @param name the struct member name
+    /// @param type the struct member type
+    /// @returns the struct member pointer
+    template <typename NAME>
+    const ast::StructMember* Member(uint32_t offset, NAME&& name, const ast::Type* type) {
+        return create<ast::StructMember>(source_, Sym(std::forward<NAME>(name)), type,
+                                         ast::AttributeList{
+                                             create<ast::StructMemberOffsetAttribute>(offset),
+                                         });
+    }
+
+    /// Creates a ast::BlockStatement with input statements
+    /// @param source the source information for the block
+    /// @param statements statements of block
+    /// @returns the block statement pointer
+    template <typename... Statements>
+    const ast::BlockStatement* Block(const Source& source, Statements&&... statements) {
+        return create<ast::BlockStatement>(
+            source, ast::StatementList{std::forward<Statements>(statements)...});
+    }
+
+    /// Creates a ast::BlockStatement with input statements
+    /// @param statements statements of block
+    /// @returns the block statement pointer
+    template <typename... STATEMENTS, typename = DisableIfSource<STATEMENTS...>>
+    const ast::BlockStatement* Block(STATEMENTS&&... statements) {
+        return create<ast::BlockStatement>(
+            ast::StatementList{std::forward<STATEMENTS>(statements)...});
+    }
+
+    /// A wrapper type for the Else statement used to create If statements.
+    struct ElseStmt {
+        /// Default constructor - no else statement.
+        ElseStmt() : stmt(nullptr) {}
+        /// Constructor
+        /// @param s The else statement
+        explicit ElseStmt(const ast::Statement* s) : stmt(s) {}
+        /// The else statement, or nullptr.
+        const ast::Statement* stmt;
+    };
+
+    /// Creates a ast::IfStatement with input condition, body, and optional
+    /// else statement
+    /// @param source the source information for the if statement
+    /// @param condition the if statement condition expression
+    /// @param body the if statement body
+    /// @param else_stmt optional else statement
+    /// @returns the if statement pointer
+    template <typename CONDITION>
+    const ast::IfStatement* If(const Source& source,
+                               CONDITION&& condition,
+                               const ast::BlockStatement* body,
+                               const ElseStmt else_stmt = ElseStmt()) {
+        return create<ast::IfStatement>(source, Expr(std::forward<CONDITION>(condition)), body,
+                                        else_stmt.stmt);
+    }
+
+    /// Creates a ast::IfStatement with input condition, body, and optional
+    /// else statement
+    /// @param condition the if statement condition expression
+    /// @param body the if statement body
+    /// @param else_stmt optional else statement
+    /// @returns the if statement pointer
+    template <typename CONDITION>
+    const ast::IfStatement* If(CONDITION&& condition,
+                               const ast::BlockStatement* body,
+                               const ElseStmt else_stmt = ElseStmt()) {
+        return create<ast::IfStatement>(Expr(std::forward<CONDITION>(condition)), body,
+                                        else_stmt.stmt);
+    }
+
+    /// Creates an Else object.
+    /// @param stmt else statement
+    /// @returns the Else object
+    ElseStmt Else(const ast::Statement* stmt) { return ElseStmt(stmt); }
+
+    /// Creates a ast::AssignmentStatement with input lhs and rhs expressions
+    /// @param source the source information
+    /// @param lhs the left hand side expression initializer
+    /// @param rhs the right hand side expression initializer
+    /// @returns the assignment statement pointer
+    template <typename LhsExpressionInit, typename RhsExpressionInit>
+    const ast::AssignmentStatement* Assign(const Source& source,
+                                           LhsExpressionInit&& lhs,
+                                           RhsExpressionInit&& rhs) {
+        return create<ast::AssignmentStatement>(source, Expr(std::forward<LhsExpressionInit>(lhs)),
+                                                Expr(std::forward<RhsExpressionInit>(rhs)));
+    }
+
+    /// Creates a ast::AssignmentStatement with input lhs and rhs expressions
+    /// @param lhs the left hand side expression initializer
+    /// @param rhs the right hand side expression initializer
+    /// @returns the assignment statement pointer
+    template <typename LhsExpressionInit, typename RhsExpressionInit>
+    const ast::AssignmentStatement* Assign(LhsExpressionInit&& lhs, RhsExpressionInit&& rhs) {
+        return create<ast::AssignmentStatement>(Expr(std::forward<LhsExpressionInit>(lhs)),
+                                                Expr(std::forward<RhsExpressionInit>(rhs)));
+    }
+
+    /// Creates a ast::CompoundAssignmentStatement with input lhs and rhs
+    /// expressions, and a binary operator.
+    /// @param source the source information
+    /// @param lhs the left hand side expression initializer
+    /// @param rhs the right hand side expression initializer
+    /// @param op the binary operator
+    /// @returns the compound assignment statement pointer
+    template <typename LhsExpressionInit, typename RhsExpressionInit>
+    const ast::CompoundAssignmentStatement* CompoundAssign(const Source& source,
+                                                           LhsExpressionInit&& lhs,
+                                                           RhsExpressionInit&& rhs,
+                                                           ast::BinaryOp op) {
+        return create<ast::CompoundAssignmentStatement>(
+            source, Expr(std::forward<LhsExpressionInit>(lhs)),
+            Expr(std::forward<RhsExpressionInit>(rhs)), op);
+    }
+
+    /// Creates a ast::CompoundAssignmentStatement with input lhs and rhs
+    /// expressions, and a binary operator.
+    /// @param lhs the left hand side expression initializer
+    /// @param rhs the right hand side expression initializer
+    /// @param op the binary operator
+    /// @returns the compound assignment statement pointer
+    template <typename LhsExpressionInit, typename RhsExpressionInit>
+    const ast::CompoundAssignmentStatement* CompoundAssign(LhsExpressionInit&& lhs,
+                                                           RhsExpressionInit&& rhs,
+                                                           ast::BinaryOp op) {
+        return create<ast::CompoundAssignmentStatement>(Expr(std::forward<LhsExpressionInit>(lhs)),
+                                                        Expr(std::forward<RhsExpressionInit>(rhs)),
+                                                        op);
+    }
+
+    /// Creates an ast::IncrementDecrementStatement with input lhs.
+    /// @param source the source information
+    /// @param lhs the left hand side expression initializer
+    /// @returns the increment decrement statement pointer
+    template <typename LhsExpressionInit>
+    const ast::IncrementDecrementStatement* Increment(const Source& source,
+                                                      LhsExpressionInit&& lhs) {
+        return create<ast::IncrementDecrementStatement>(
+            source, Expr(std::forward<LhsExpressionInit>(lhs)), true);
+    }
+
+    /// Creates a ast::IncrementDecrementStatement with input lhs.
+    /// @param lhs the left hand side expression initializer
+    /// @returns the increment decrement statement pointer
+    template <typename LhsExpressionInit>
+    const ast::IncrementDecrementStatement* Increment(LhsExpressionInit&& lhs) {
+        return create<ast::IncrementDecrementStatement>(Expr(std::forward<LhsExpressionInit>(lhs)),
+                                                        true);
+    }
+
+    /// Creates an ast::IncrementDecrementStatement with input lhs.
+    /// @param source the source information
+    /// @param lhs the left hand side expression initializer
+    /// @returns the increment decrement statement pointer
+    template <typename LhsExpressionInit>
+    const ast::IncrementDecrementStatement* Decrement(const Source& source,
+                                                      LhsExpressionInit&& lhs) {
+        return create<ast::IncrementDecrementStatement>(
+            source, Expr(std::forward<LhsExpressionInit>(lhs)), false);
+    }
+
+    /// Creates a ast::IncrementDecrementStatement with input lhs.
+    /// @param lhs the left hand side expression initializer
+    /// @returns the increment decrement statement pointer
+    template <typename LhsExpressionInit>
+    const ast::IncrementDecrementStatement* Decrement(LhsExpressionInit&& lhs) {
+        return create<ast::IncrementDecrementStatement>(Expr(std::forward<LhsExpressionInit>(lhs)),
+                                                        false);
+    }
+
+    /// Creates a ast::LoopStatement with input body and optional continuing
+    /// @param source the source information
+    /// @param body the loop body
+    /// @param continuing the optional continuing block
+    /// @returns the loop statement pointer
+    const ast::LoopStatement* Loop(const Source& source,
+                                   const ast::BlockStatement* body,
+                                   const ast::BlockStatement* continuing = nullptr) {
+        return create<ast::LoopStatement>(source, body, continuing);
+    }
+
+    /// Creates a ast::LoopStatement with input body and optional continuing
+    /// @param body the loop body
+    /// @param continuing the optional continuing block
+    /// @returns the loop statement pointer
+    const ast::LoopStatement* Loop(const ast::BlockStatement* body,
+                                   const ast::BlockStatement* continuing = nullptr) {
+        return create<ast::LoopStatement>(body, continuing);
+    }
+
+    /// Creates a ast::ForLoopStatement with input body and optional initializer,
+    /// condition and continuing.
+    /// @param source the source information
+    /// @param init the optional loop initializer
+    /// @param cond the optional loop condition
+    /// @param cont the optional loop continuing
+    /// @param body the loop body
+    /// @returns the for loop statement pointer
+    template <typename COND>
+    const ast::ForLoopStatement* For(const Source& source,
+                                     const ast::Statement* init,
+                                     COND&& cond,
+                                     const ast::Statement* cont,
+                                     const ast::BlockStatement* body) {
+        return create<ast::ForLoopStatement>(source, init, Expr(std::forward<COND>(cond)), cont,
+                                             body);
+    }
+
+    /// Creates a ast::ForLoopStatement with input body and optional initializer,
+    /// condition and continuing.
+    /// @param init the optional loop initializer
+    /// @param cond the optional loop condition
+    /// @param cont the optional loop continuing
+    /// @param body the loop body
+    /// @returns the for loop statement pointer
+    template <typename COND>
+    const ast::ForLoopStatement* For(const ast::Statement* init,
+                                     COND&& cond,
+                                     const ast::Statement* cont,
+                                     const ast::BlockStatement* body) {
+        return create<ast::ForLoopStatement>(init, Expr(std::forward<COND>(cond)), cont, body);
+    }
+
+    /// Creates a ast::VariableDeclStatement for the input variable
+    /// @param source the source information
+    /// @param var the variable to wrap in a decl statement
+    /// @returns the variable decl statement pointer
+    const ast::VariableDeclStatement* Decl(const Source& source, const ast::Variable* var) {
+        return create<ast::VariableDeclStatement>(source, var);
+    }
+
+    /// Creates a ast::VariableDeclStatement for the input variable
+    /// @param var the variable to wrap in a decl statement
+    /// @returns the variable decl statement pointer
+    const ast::VariableDeclStatement* Decl(const ast::Variable* var) {
+        return create<ast::VariableDeclStatement>(var);
+    }
+
+    /// Creates a ast::SwitchStatement with input expression and cases
+    /// @param source the source information
+    /// @param condition the condition expression initializer
+    /// @param cases case statements
+    /// @returns the switch statement pointer
+    template <typename ExpressionInit, typename... Cases>
+    const ast::SwitchStatement* Switch(const Source& source,
+                                       ExpressionInit&& condition,
+                                       Cases&&... cases) {
+        return create<ast::SwitchStatement>(source, Expr(std::forward<ExpressionInit>(condition)),
+                                            ast::CaseStatementList{std::forward<Cases>(cases)...});
+    }
+
+    /// Creates a ast::SwitchStatement with input expression and cases
+    /// @param condition the condition expression initializer
+    /// @param cases case statements
+    /// @returns the switch statement pointer
+    template <typename ExpressionInit,
+              typename... Cases,
+              typename = DisableIfSource<ExpressionInit>>
+    const ast::SwitchStatement* Switch(ExpressionInit&& condition, Cases&&... cases) {
+        return create<ast::SwitchStatement>(Expr(std::forward<ExpressionInit>(condition)),
+                                            ast::CaseStatementList{std::forward<Cases>(cases)...});
+    }
+
+    /// Creates a ast::CaseStatement with input list of selectors, and body
+    /// @param source the source information
+    /// @param selectors list of selectors
+    /// @param body the case body
+    /// @returns the case statement pointer
+    const ast::CaseStatement* Case(const Source& source,
+                                   ast::CaseSelectorList selectors,
+                                   const ast::BlockStatement* body = nullptr) {
+        return create<ast::CaseStatement>(source, std::move(selectors), body ? body : Block());
+    }
+
+    /// Creates a ast::CaseStatement with input list of selectors, and body
+    /// @param selectors list of selectors
+    /// @param body the case body
+    /// @returns the case statement pointer
+    const ast::CaseStatement* Case(ast::CaseSelectorList selectors,
+                                   const ast::BlockStatement* body = nullptr) {
+        return create<ast::CaseStatement>(std::move(selectors), body ? body : Block());
+    }
+
+    /// Convenient overload that takes a single selector
+    /// @param selector a single case selector
+    /// @param body the case body
+    /// @returns the case statement pointer
+    const ast::CaseStatement* Case(const ast::IntLiteralExpression* selector,
+                                   const ast::BlockStatement* body = nullptr) {
+        return Case(ast::CaseSelectorList{selector}, body);
+    }
+
+    /// Convenience function that creates a 'default' ast::CaseStatement
+    /// @param source the source information
+    /// @param body the case body
+    /// @returns the case statement pointer
+    const ast::CaseStatement* DefaultCase(const Source& source,
+                                          const ast::BlockStatement* body = nullptr) {
+        return Case(source, ast::CaseSelectorList{}, body);
+    }
+
+    /// Convenience function that creates a 'default' ast::CaseStatement
+    /// @param body the case body
+    /// @returns the case statement pointer
+    const ast::CaseStatement* DefaultCase(const ast::BlockStatement* body = nullptr) {
+        return Case(ast::CaseSelectorList{}, body);
+    }
+
+    /// Creates an ast::FallthroughStatement
+    /// @param source the source information
+    /// @returns the fallthrough statement pointer
+    const ast::FallthroughStatement* Fallthrough(const Source& source) {
+        return create<ast::FallthroughStatement>(source);
+    }
+
+    /// Creates an ast::FallthroughStatement
+    /// @returns the fallthrough statement pointer
+    const ast::FallthroughStatement* Fallthrough() { return create<ast::FallthroughStatement>(); }
+
+    /// Creates an ast::BuiltinAttribute
+    /// @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) {
+        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) {
+        return create<ast::BuiltinAttribute>(source_, builtin);
+    }
+
+    /// Creates an ast::InterpolateAttribute
+    /// @param source the source information
+    /// @param type the interpolation type
+    /// @param sampling the interpolation sampling
+    /// @returns the interpolate attribute pointer
+    const ast::InterpolateAttribute* Interpolate(
+        const Source& source,
+        ast::InterpolationType type,
+        ast::InterpolationSampling sampling = ast::InterpolationSampling::kNone) {
+        return create<ast::InterpolateAttribute>(source, type, sampling);
+    }
+
+    /// Creates an ast::InterpolateAttribute
+    /// @param type the interpolation type
+    /// @param sampling the interpolation sampling
+    /// @returns the interpolate attribute pointer
+    const ast::InterpolateAttribute* Interpolate(
+        ast::InterpolationType type,
+        ast::InterpolationSampling sampling = ast::InterpolationSampling::kNone) {
+        return create<ast::InterpolateAttribute>(source_, type, sampling);
+    }
+
+    /// Creates an ast::InterpolateAttribute using flat interpolation
+    /// @param source the source information
+    /// @returns the interpolate attribute pointer
+    const ast::InterpolateAttribute* Flat(const Source& source) {
+        return Interpolate(source, ast::InterpolationType::kFlat);
+    }
+
+    /// Creates an ast::InterpolateAttribute using flat interpolation
+    /// @returns the interpolate attribute pointer
+    const ast::InterpolateAttribute* Flat() { return Interpolate(ast::InterpolationType::kFlat); }
+
+    /// Creates an ast::InvariantAttribute
+    /// @param source the source information
+    /// @returns the invariant attribute pointer
+    const ast::InvariantAttribute* Invariant(const Source& source) {
+        return create<ast::InvariantAttribute>(source);
+    }
+
+    /// Creates an ast::InvariantAttribute
+    /// @returns the invariant attribute pointer
+    const ast::InvariantAttribute* Invariant() { return create<ast::InvariantAttribute>(source_); }
+
+    /// Creates an ast::LocationAttribute
+    /// @param source the source information
+    /// @param location the location value
+    /// @returns the location attribute pointer
+    const ast::LocationAttribute* Location(const Source& source, uint32_t location) {
+        return create<ast::LocationAttribute>(source, location);
+    }
+
+    /// Creates an ast::LocationAttribute
+    /// @param location the location value
+    /// @returns the location attribute pointer
+    const ast::LocationAttribute* Location(uint32_t location) {
+        return create<ast::LocationAttribute>(source_, location);
+    }
+
+    /// 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
+    /// @param id the optional id value
+    /// @returns the override attribute pointer
+    const ast::IdAttribute* Id(uint32_t id) { return Id(source_, id); }
+
+    /// Creates an ast::StageAttribute
+    /// @param source the source information
+    /// @param stage the pipeline stage
+    /// @returns the stage attribute pointer
+    const ast::StageAttribute* Stage(const Source& source, ast::PipelineStage stage) {
+        return create<ast::StageAttribute>(source, stage);
+    }
+
+    /// Creates an ast::StageAttribute
+    /// @param stage the pipeline stage
+    /// @returns the stage attribute pointer
+    const ast::StageAttribute* Stage(ast::PipelineStage stage) {
+        return create<ast::StageAttribute>(source_, stage);
+    }
+
+    /// Creates an ast::WorkgroupAttribute
+    /// @param x the x dimension expression
+    /// @returns the workgroup attribute pointer
+    template <typename EXPR_X>
+    const ast::WorkgroupAttribute* WorkgroupSize(EXPR_X&& x) {
+        return WorkgroupSize(std::forward<EXPR_X>(x), nullptr, nullptr);
+    }
+
+    /// Creates an ast::WorkgroupAttribute
+    /// @param x the x dimension expression
+    /// @param y the y dimension expression
+    /// @returns the workgroup attribute pointer
+    template <typename EXPR_X, typename EXPR_Y>
+    const ast::WorkgroupAttribute* WorkgroupSize(EXPR_X&& x, EXPR_Y&& y) {
+        return WorkgroupSize(std::forward<EXPR_X>(x), std::forward<EXPR_Y>(y), nullptr);
+    }
+
+    /// Creates an ast::WorkgroupAttribute
+    /// @param source the source information
+    /// @param x the x dimension expression
+    /// @param y the y dimension expression
+    /// @param z the z dimension expression
+    /// @returns the workgroup attribute pointer
+    template <typename EXPR_X, typename EXPR_Y, typename EXPR_Z>
+    const ast::WorkgroupAttribute* WorkgroupSize(const Source& source,
+                                                 EXPR_X&& x,
+                                                 EXPR_Y&& y,
+                                                 EXPR_Z&& z) {
+        return create<ast::WorkgroupAttribute>(source, Expr(std::forward<EXPR_X>(x)),
+                                               Expr(std::forward<EXPR_Y>(y)),
+                                               Expr(std::forward<EXPR_Z>(z)));
+    }
+
+    /// Creates an ast::WorkgroupAttribute
+    /// @param x the x dimension expression
+    /// @param y the y dimension expression
+    /// @param z the z dimension expression
+    /// @returns the workgroup attribute pointer
+    template <typename EXPR_X, typename EXPR_Y, typename EXPR_Z>
+    const ast::WorkgroupAttribute* WorkgroupSize(EXPR_X&& x, EXPR_Y&& y, EXPR_Z&& z) {
+        return create<ast::WorkgroupAttribute>(source_, Expr(std::forward<EXPR_X>(x)),
+                                               Expr(std::forward<EXPR_Y>(y)),
+                                               Expr(std::forward<EXPR_Z>(z)));
+    }
+
+    /// Creates an ast::DisableValidationAttribute
+    /// @param validation the validation to disable
+    /// @returns the disable validation attribute pointer
+    const ast::DisableValidationAttribute* Disable(ast::DisabledValidation validation) {
+        return ASTNodes().Create<ast::DisableValidationAttribute>(ID(), validation);
+    }
+
+    /// Sets the current builder source to `src`
+    /// @param src the Source used for future create() calls
+    void SetSource(const Source& src) {
+        AssertNotMoved();
+        source_ = src;
+    }
+
+    /// Sets the current builder source to `loc`
+    /// @param loc the Source used for future create() calls
+    void SetSource(const Source::Location& loc) {
+        AssertNotMoved();
+        source_ = Source(loc);
+    }
+
+    /// Helper for returning the resolved semantic type of the expression `expr`.
+    /// @note As the Resolver is run when the Program is built, this will only be
+    /// useful for the Resolver itself and tests that use their own Resolver.
+    /// @param expr the AST expression
+    /// @return the resolved semantic type for the expression, or nullptr if the
+    /// expression has no resolved type.
+    const sem::Type* TypeOf(const ast::Expression* expr) const;
+
+    /// Helper for returning the resolved semantic type of the variable `var`.
+    /// @note As the Resolver is run when the Program is built, this will only be
+    /// useful for the Resolver itself and tests that use their own Resolver.
+    /// @param var the AST variable
+    /// @return the resolved semantic type for the variable, or nullptr if the
+    /// variable has no resolved type.
+    const sem::Type* TypeOf(const ast::Variable* var) const;
+
+    /// Helper for returning the resolved semantic type of the AST type `type`.
+    /// @note As the Resolver is run when the Program is built, this will only be
+    /// useful for the Resolver itself and tests that use their own Resolver.
+    /// @param type the AST type
+    /// @return the resolved semantic type for the type, or nullptr if the type
+    /// has no resolved type.
+    const sem::Type* TypeOf(const ast::Type* type) const;
+
+    /// Helper for returning the resolved semantic type of the AST type
+    /// declaration `type_decl`.
+    /// @note As the Resolver is run when the Program is built, this will only be
+    /// useful for the Resolver itself and tests that use their own Resolver.
+    /// @param type_decl the AST type declaration
+    /// @return the resolved semantic type for the type declaration, or nullptr if
+    /// the type declaration has no resolved type.
+    const sem::Type* TypeOf(const ast::TypeDecl* type_decl) const;
+
+    /// Wraps the ast::Expression in a statement. This is used by tests that
+    /// construct a partial AST and require the Resolver to reach these
+    /// nodes.
+    /// @param expr the ast::Expression to be wrapped by an ast::Statement
+    /// @return the ast::Statement that wraps the ast::Expression
+    const ast::Statement* WrapInStatement(const ast::Expression* expr);
+    /// Wraps the ast::Variable in a ast::VariableDeclStatement. This is used by
+    /// tests that construct a partial AST and require the Resolver to reach
+    /// these nodes.
+    /// @param v the ast::Variable to be wrapped by an ast::VariableDeclStatement
+    /// @return the ast::VariableDeclStatement that wraps the ast::Variable
+    const ast::VariableDeclStatement* WrapInStatement(const ast::Variable* v);
+    /// Returns the statement argument. Used as a passthrough-overload by
+    /// WrapInFunction().
+    /// @param stmt the ast::Statement
+    /// @return `stmt`
+    const ast::Statement* WrapInStatement(const ast::Statement* stmt);
+    /// Wraps the list of arguments in a simple function so that each is reachable
+    /// by the Resolver.
+    /// @param args a mix of ast::Expression, ast::Statement, ast::Variables.
+    /// @returns the function
+    template <typename... ARGS>
+    const ast::Function* WrapInFunction(ARGS&&... args) {
+        ast::StatementList stmts{WrapInStatement(std::forward<ARGS>(args))...};
+        return WrapInFunction(std::move(stmts));
+    }
+    /// @param stmts a list of ast::Statement that will be wrapped by a function,
+    /// so that each statement is reachable by the Resolver.
+    /// @returns the function
+    const ast::Function* WrapInFunction(ast::StatementList stmts);
+
+    /// The builder types
+    TypesBuilder const ty{this};
+
+  protected:
+    /// Asserts that the builder has not been moved.
+    void AssertNotMoved() const;
+
+  private:
+    ProgramID id_;
+    sem::Manager types_;
+    ASTNodeAllocator ast_nodes_;
+    SemNodeAllocator sem_nodes_;
+    ast::Module* ast_;
+    sem::Info sem_;
+    SymbolTable symbols_{id_};
+    diag::List diagnostics_;
+
+    /// The source to use when creating AST nodes without providing a Source as
+    /// the first argument.
+    Source source_;
+
+    /// Set by SetResolveOnBuild(). If set, the Resolver will be run on the
+    /// program when built.
+    bool resolve_on_build_ = true;
+
+    /// Set by MarkAsMoved(). Once set, no methods may be called on this builder.
+    bool moved_ = false;
 };
 
 //! @cond Doxygen_Suppress
 // Various template specializations for ProgramBuilder::TypesBuilder::CToAST.
 template <>
-struct ProgramBuilder::TypesBuilder::CToAST<ProgramBuilder::i32> {
-  static const ast::Type* get(const ProgramBuilder::TypesBuilder* t) {
-    return t->i32();
-  }
+struct ProgramBuilder::TypesBuilder::CToAST<i32> {
+    static const ast::Type* get(const ProgramBuilder::TypesBuilder* t) { return t->i32(); }
 };
 template <>
-struct ProgramBuilder::TypesBuilder::CToAST<ProgramBuilder::u32> {
-  static const ast::Type* get(const ProgramBuilder::TypesBuilder* t) {
-    return t->u32();
-  }
+struct ProgramBuilder::TypesBuilder::CToAST<u32> {
+    static const ast::Type* get(const ProgramBuilder::TypesBuilder* t) { return t->u32(); }
 };
 template <>
-struct ProgramBuilder::TypesBuilder::CToAST<ProgramBuilder::f32> {
-  static const ast::Type* get(const ProgramBuilder::TypesBuilder* t) {
-    return t->f32();
-  }
+struct ProgramBuilder::TypesBuilder::CToAST<f32> {
+    static const ast::Type* get(const ProgramBuilder::TypesBuilder* t) { return t->f32(); }
 };
 template <>
 struct ProgramBuilder::TypesBuilder::CToAST<bool> {
-  static const ast::Type* get(const ProgramBuilder::TypesBuilder* t) {
-    return t->bool_();
-  }
+    static const ast::Type* get(const ProgramBuilder::TypesBuilder* t) { return t->bool_(); }
 };
 template <>
 struct ProgramBuilder::TypesBuilder::CToAST<void> {
-  static const ast::Type* get(const ProgramBuilder::TypesBuilder* t) {
-    return t->void_();
-  }
+    static const ast::Type* get(const ProgramBuilder::TypesBuilder* t) { return t->void_(); }
 };
 //! @endcond
 
 /// @param builder the ProgramBuilder
 /// @returns the ProgramID of the ProgramBuilder
 inline ProgramID ProgramIDOf(const ProgramBuilder* builder) {
-  return builder->ID();
+    return builder->ID();
 }
 
 }  // namespace tint
diff --git a/src/tint/program_builder_test.cc b/src/tint/program_builder_test.cc
index f18aa10..dd7e7a8 100644
--- a/src/tint/program_builder_test.cc
+++ b/src/tint/program_builder_test.cc
@@ -22,50 +22,50 @@
 using ProgramBuilderTest = testing::Test;
 
 TEST_F(ProgramBuilderTest, IDsAreUnique) {
-  Program program_a(ProgramBuilder{});
-  Program program_b(ProgramBuilder{});
-  Program program_c(ProgramBuilder{});
-  EXPECT_NE(program_a.ID(), program_b.ID());
-  EXPECT_NE(program_b.ID(), program_c.ID());
-  EXPECT_NE(program_c.ID(), program_a.ID());
+    Program program_a(ProgramBuilder{});
+    Program program_b(ProgramBuilder{});
+    Program program_c(ProgramBuilder{});
+    EXPECT_NE(program_a.ID(), program_b.ID());
+    EXPECT_NE(program_b.ID(), program_c.ID());
+    EXPECT_NE(program_c.ID(), program_a.ID());
 }
 
 TEST_F(ProgramBuilderTest, WrapDoesntAffectInner) {
-  Program inner([] {
-    ProgramBuilder builder;
-    auto* ty = builder.ty.f32();
-    builder.Func("a", {}, ty, {}, {});
-    return builder;
-  }());
+    Program inner([] {
+        ProgramBuilder builder;
+        auto* ty = builder.ty.f32();
+        builder.Func("a", {}, ty, {}, {});
+        return builder;
+    }());
 
-  ASSERT_EQ(inner.AST().Functions().size(), 1u);
-  ASSERT_TRUE(inner.Symbols().Get("a").IsValid());
-  ASSERT_FALSE(inner.Symbols().Get("b").IsValid());
+    ASSERT_EQ(inner.AST().Functions().size(), 1u);
+    ASSERT_TRUE(inner.Symbols().Get("a").IsValid());
+    ASSERT_FALSE(inner.Symbols().Get("b").IsValid());
 
-  ProgramBuilder outer = ProgramBuilder::Wrap(&inner);
+    ProgramBuilder outer = ProgramBuilder::Wrap(&inner);
 
-  ASSERT_EQ(inner.AST().Functions().size(), 1u);
-  ASSERT_EQ(outer.AST().Functions().size(), 1u);
-  EXPECT_EQ(inner.AST().Functions()[0], outer.AST().Functions()[0]);
-  EXPECT_TRUE(inner.Symbols().Get("a").IsValid());
-  EXPECT_EQ(inner.Symbols().Get("a"), outer.Symbols().Get("a"));
-  EXPECT_TRUE(inner.Symbols().Get("a").IsValid());
-  EXPECT_TRUE(outer.Symbols().Get("a").IsValid());
-  EXPECT_FALSE(inner.Symbols().Get("b").IsValid());
-  EXPECT_FALSE(outer.Symbols().Get("b").IsValid());
+    ASSERT_EQ(inner.AST().Functions().size(), 1u);
+    ASSERT_EQ(outer.AST().Functions().size(), 1u);
+    EXPECT_EQ(inner.AST().Functions()[0], outer.AST().Functions()[0]);
+    EXPECT_TRUE(inner.Symbols().Get("a").IsValid());
+    EXPECT_EQ(inner.Symbols().Get("a"), outer.Symbols().Get("a"));
+    EXPECT_TRUE(inner.Symbols().Get("a").IsValid());
+    EXPECT_TRUE(outer.Symbols().Get("a").IsValid());
+    EXPECT_FALSE(inner.Symbols().Get("b").IsValid());
+    EXPECT_FALSE(outer.Symbols().Get("b").IsValid());
 
-  auto* ty = outer.ty.f32();
-  outer.Func("b", {}, ty, {}, {});
+    auto* ty = outer.ty.f32();
+    outer.Func("b", {}, ty, {}, {});
 
-  ASSERT_EQ(inner.AST().Functions().size(), 1u);
-  ASSERT_EQ(outer.AST().Functions().size(), 2u);
-  EXPECT_EQ(inner.AST().Functions()[0], outer.AST().Functions()[0]);
-  EXPECT_EQ(outer.AST().Functions()[1]->symbol, outer.Symbols().Get("b"));
-  EXPECT_EQ(inner.Symbols().Get("a"), outer.Symbols().Get("a"));
-  EXPECT_TRUE(inner.Symbols().Get("a").IsValid());
-  EXPECT_TRUE(outer.Symbols().Get("a").IsValid());
-  EXPECT_FALSE(inner.Symbols().Get("b").IsValid());
-  EXPECT_TRUE(outer.Symbols().Get("b").IsValid());
+    ASSERT_EQ(inner.AST().Functions().size(), 1u);
+    ASSERT_EQ(outer.AST().Functions().size(), 2u);
+    EXPECT_EQ(inner.AST().Functions()[0], outer.AST().Functions()[0]);
+    EXPECT_EQ(outer.AST().Functions()[1]->symbol, outer.Symbols().Get("b"));
+    EXPECT_EQ(inner.Symbols().Get("a"), outer.Symbols().Get("a"));
+    EXPECT_TRUE(inner.Symbols().Get("a").IsValid());
+    EXPECT_TRUE(outer.Symbols().Get("a").IsValid());
+    EXPECT_FALSE(inner.Symbols().Get("b").IsValid());
+    EXPECT_TRUE(outer.Symbols().Get("b").IsValid());
 }
 
 }  // namespace
diff --git a/src/tint/program_id.cc b/src/tint/program_id.cc
index 5350de7..7374df3 100644
--- a/src/tint/program_id.cc
+++ b/src/tint/program_id.cc
@@ -29,7 +29,7 @@
 ProgramID::ProgramID(uint32_t id) : val(id) {}
 
 ProgramID ProgramID::New() {
-  return ProgramID(next_program_id++);
+    return ProgramID(next_program_id++);
 }
 
 namespace detail {
@@ -44,14 +44,14 @@
                            const char* msg,
                            const char* file,
                            size_t line) {
-  if (a == b) {
-    return;  // matched
-  }
-  if (if_valid && (!a || !b)) {
-    return;  //  a or b were not valid
-  }
-  diag::List diagnostics;
-  tint::InternalCompilerError(file, line, system, diagnostics) << msg;
+    if (a == b) {
+        return;  // matched
+    }
+    if (if_valid && (!a || !b)) {
+        return;  //  a or b were not valid
+    }
+    diag::List diagnostics;
+    tint::InternalCompilerError(file, line, system, diagnostics) << msg;
 }
 
 }  // namespace detail
diff --git a/src/tint/program_id.h b/src/tint/program_id.h
index 09e232f..c018543 100644
--- a/src/tint/program_id.h
+++ b/src/tint/program_id.h
@@ -34,33 +34,33 @@
 /// owned exclusively by that Program and have accidentally not leaked from
 /// another Program.
 class ProgramID {
- public:
-  /// Constructor
-  ProgramID();
+  public:
+    /// Constructor
+    ProgramID();
 
-  /// @returns a new. globally unique ProgramID
-  static ProgramID New();
+    /// @returns a new. globally unique ProgramID
+    static ProgramID New();
 
-  /// Equality operator
-  /// @param rhs the other ProgramID
-  /// @returns true if the ProgramIDs are equal
-  bool operator==(const ProgramID& rhs) const { return val == rhs.val; }
+    /// Equality operator
+    /// @param rhs the other ProgramID
+    /// @returns true if the ProgramIDs are equal
+    bool operator==(const ProgramID& rhs) const { return val == rhs.val; }
 
-  /// Inequality operator
-  /// @param rhs the other ProgramID
-  /// @returns true if the ProgramIDs are not equal
-  bool operator!=(const ProgramID& rhs) const { return val != rhs.val; }
+    /// Inequality operator
+    /// @param rhs the other ProgramID
+    /// @returns true if the ProgramIDs are not equal
+    bool operator!=(const ProgramID& rhs) const { return val != rhs.val; }
 
-  /// @returns the numerical identifier value
-  uint32_t Value() const { return val; }
+    /// @returns the numerical identifier value
+    uint32_t Value() const { return val; }
 
-  /// @returns true if this ProgramID is valid
-  operator bool() const { return val != 0; }
+    /// @returns true if this ProgramID is valid
+    operator bool() const { return val != 0; }
 
- private:
-  explicit ProgramID(uint32_t);
+  private:
+    explicit ProgramID(uint32_t);
 
-  uint32_t val = 0;
+    uint32_t val = 0;
 };
 
 /// A simple pass-through function for ProgramID. Intended to be overloaded for
@@ -68,7 +68,7 @@
 /// @param id a ProgramID
 /// @returns id. Simple pass-through function
 inline ProgramID ProgramIDOf(ProgramID id) {
-  return id;
+    return id;
 }
 
 /// Writes the ProgramID to the std::ostream.
@@ -76,8 +76,8 @@
 /// @param id the program identifier to write
 /// @returns out so calls can be chained
 inline std::ostream& operator<<(std::ostream& out, ProgramID id) {
-  out << "Program<" << id.Value() << ">";
-  return out;
+    out << "Program<" << id.Value() << ">";
+    return out;
 }
 
 namespace detail {
@@ -102,23 +102,21 @@
 /// that the program identifiers for A and B are equal, if both A and B have
 /// valid program identifiers.
 #if TINT_CHECK_FOR_CROSS_PROGRAM_LEAKS
-#define TINT_ASSERT_PROGRAM_IDS_EQUAL(system, a, b)                          \
-  detail::AssertProgramIDsEqual(                                             \
-      ProgramIDOf(a), ProgramIDOf(b), false, tint::diag::System::system,     \
-      "TINT_ASSERT_PROGRAM_IDS_EQUAL(" #system "," #a ", " #b ")", __FILE__, \
-      __LINE__)
-#define TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(system, a, b)                 \
-  detail::AssertProgramIDsEqual(                                             \
-      ProgramIDOf(a), ProgramIDOf(b), true, tint::diag::System::system,      \
-      "TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(" #system ", " #a ", " #b ")", \
-      __FILE__, __LINE__)
+#define TINT_ASSERT_PROGRAM_IDS_EQUAL(system, a, b)                        \
+    detail::AssertProgramIDsEqual(                                         \
+        ProgramIDOf(a), ProgramIDOf(b), false, tint::diag::System::system, \
+        "TINT_ASSERT_PROGRAM_IDS_EQUAL(" #system "," #a ", " #b ")", __FILE__, __LINE__)
+#define TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(system, a, b)              \
+    detail::AssertProgramIDsEqual(                                        \
+        ProgramIDOf(a), ProgramIDOf(b), true, tint::diag::System::system, \
+        "TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(" #system ", " #a ", " #b ")", __FILE__, __LINE__)
 #else
 #define TINT_ASSERT_PROGRAM_IDS_EQUAL(a, b) \
-  do {                                      \
-  } while (false)
+    do {                                    \
+    } while (false)
 #define TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(a, b) \
-  do {                                               \
-  } while (false)
+    do {                                             \
+    } while (false)
 #endif
 
 }  // namespace tint
diff --git a/src/tint/program_test.cc b/src/tint/program_test.cc
index a161ecb..3bdf11a 100644
--- a/src/tint/program_test.cc
+++ b/src/tint/program_test.cc
@@ -22,88 +22,88 @@
 using ProgramTest = ast::TestHelper;
 
 TEST_F(ProgramTest, Unbuilt) {
-  Program program;
-  EXPECT_FALSE(program.IsValid());
+    Program program;
+    EXPECT_FALSE(program.IsValid());
 }
 
 TEST_F(ProgramTest, Creation) {
-  Program program(std::move(*this));
-  EXPECT_EQ(program.AST().Functions().size(), 0u);
+    Program program(std::move(*this));
+    EXPECT_EQ(program.AST().Functions().size(), 0u);
 }
 
 TEST_F(ProgramTest, EmptyIsValid) {
-  Program program(std::move(*this));
-  EXPECT_TRUE(program.IsValid());
+    Program program(std::move(*this));
+    EXPECT_TRUE(program.IsValid());
 }
 
 TEST_F(ProgramTest, IDsAreUnique) {
-  Program program_a(ProgramBuilder{});
-  Program program_b(ProgramBuilder{});
-  Program program_c(ProgramBuilder{});
-  EXPECT_NE(program_a.ID(), program_b.ID());
-  EXPECT_NE(program_b.ID(), program_c.ID());
-  EXPECT_NE(program_c.ID(), program_a.ID());
+    Program program_a(ProgramBuilder{});
+    Program program_b(ProgramBuilder{});
+    Program program_c(ProgramBuilder{});
+    EXPECT_NE(program_a.ID(), program_b.ID());
+    EXPECT_NE(program_b.ID(), program_c.ID());
+    EXPECT_NE(program_c.ID(), program_a.ID());
 }
 
 TEST_F(ProgramTest, Assert_GlobalVariable) {
-  Global("var", ty.f32(), ast::StorageClass::kPrivate);
+    Global("var", ty.f32(), ast::StorageClass::kPrivate);
 
-  Program program(std::move(*this));
-  EXPECT_TRUE(program.IsValid());
+    Program program(std::move(*this));
+    EXPECT_TRUE(program.IsValid());
 }
 
 TEST_F(ProgramTest, Assert_NullGlobalVariable) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.AST().AddGlobalVariable(nullptr);
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.AST().AddGlobalVariable(nullptr);
+        },
+        "internal compiler error");
 }
 
 TEST_F(ProgramTest, Assert_NullTypeDecl) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.AST().AddTypeDecl(nullptr);
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.AST().AddTypeDecl(nullptr);
+        },
+        "internal compiler error");
 }
 
 TEST_F(ProgramTest, Assert_Null_Function) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.AST().AddFunction(nullptr);
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.AST().AddFunction(nullptr);
+        },
+        "internal compiler error");
 }
 
 TEST_F(ProgramTest, DiagnosticsMove) {
-  Diagnostics().add_error(diag::System::Program, "an error message");
+    Diagnostics().add_error(diag::System::Program, "an error message");
 
-  Program program_a(std::move(*this));
-  EXPECT_FALSE(program_a.IsValid());
-  EXPECT_EQ(program_a.Diagnostics().count(), 1u);
-  EXPECT_EQ(program_a.Diagnostics().error_count(), 1u);
-  EXPECT_EQ(program_a.Diagnostics().begin()->message, "an error message");
+    Program program_a(std::move(*this));
+    EXPECT_FALSE(program_a.IsValid());
+    EXPECT_EQ(program_a.Diagnostics().count(), 1u);
+    EXPECT_EQ(program_a.Diagnostics().error_count(), 1u);
+    EXPECT_EQ(program_a.Diagnostics().begin()->message, "an error message");
 
-  Program program_b(std::move(program_a));
-  EXPECT_FALSE(program_b.IsValid());
-  EXPECT_EQ(program_b.Diagnostics().count(), 1u);
-  EXPECT_EQ(program_b.Diagnostics().error_count(), 1u);
-  EXPECT_EQ(program_b.Diagnostics().begin()->message, "an error message");
+    Program program_b(std::move(program_a));
+    EXPECT_FALSE(program_b.IsValid());
+    EXPECT_EQ(program_b.Diagnostics().count(), 1u);
+    EXPECT_EQ(program_b.Diagnostics().error_count(), 1u);
+    EXPECT_EQ(program_b.Diagnostics().begin()->message, "an error message");
 }
 
 TEST_F(ProgramTest, ReuseMovedFromVariable) {
-  Program a(std::move(*this));
-  EXPECT_TRUE(a.IsValid());
+    Program a(std::move(*this));
+    EXPECT_TRUE(a.IsValid());
 
-  Program b = std::move(a);
-  EXPECT_TRUE(b.IsValid());
+    Program b = std::move(a);
+    EXPECT_TRUE(b.IsValid());
 
-  a = std::move(b);
-  EXPECT_TRUE(a.IsValid());
+    a = std::move(b);
+    EXPECT_TRUE(a.IsValid());
 }
 
 }  // namespace
diff --git a/src/tint/reader/reader.h b/src/tint/reader/reader.h
index 7d97821..8ba0a89 100644
--- a/src/tint/reader/reader.h
+++ b/src/tint/reader/reader.h
@@ -23,39 +23,39 @@
 
 /// Base class for input readers
 class Reader {
- public:
-  virtual ~Reader();
+  public:
+    virtual ~Reader();
 
-  /// Parses the input data
-  /// @returns true if the parse was successful
-  virtual bool Parse() = 0;
+    /// Parses the input data
+    /// @returns true if the parse was successful
+    virtual bool Parse() = 0;
 
-  /// @returns true if an error was encountered.
-  bool has_error() const { return diags_.contains_errors(); }
+    /// @returns true if an error was encountered.
+    bool has_error() const { return diags_.contains_errors(); }
 
-  /// @returns the parser error string
-  std::string error() const {
-    diag::Formatter formatter{{false, false, false, false}};
-    return formatter.format(diags_);
-  }
+    /// @returns the parser error string
+    std::string error() const {
+        diag::Formatter formatter{{false, false, false, false}};
+        return formatter.format(diags_);
+    }
 
-  /// @returns the full list of diagnostic messages.
-  const diag::List& diagnostics() const { return diags_; }
+    /// @returns the full list of diagnostic messages.
+    const diag::List& diagnostics() const { return diags_; }
 
-  /// @returns the program. The program builder in the parser will be reset
-  /// after this.
-  virtual Program program() = 0;
+    /// @returns the program. The program builder in the parser will be reset
+    /// after this.
+    virtual Program program() = 0;
 
- protected:
-  /// Constructor
-  Reader();
+  protected:
+    /// Constructor
+    Reader();
 
-  /// Sets the diagnostic messages
-  /// @param diags the list of diagnostic messages
-  void set_diagnostics(const diag::List& diags) { diags_ = diags; }
+    /// Sets the diagnostic messages
+    /// @param diags the list of diagnostic messages
+    void set_diagnostics(const diag::List& diags) { diags_ = diags; }
 
-  /// All diagnostic messages from the reader.
-  diag::List diags_;
+    /// All diagnostic messages from the reader.
+    diag::List diags_;
 };
 
 }  // namespace tint::reader
diff --git a/src/tint/reader/spirv/construct.cc b/src/tint/reader/spirv/construct.cc
index 2307c24..9f24d23 100644
--- a/src/tint/reader/spirv/construct.cc
+++ b/src/tint/reader/spirv/construct.cc
@@ -32,25 +32,22 @@
           // it's incidental which will appear on the stack first.
           the_kind == kLoop
               ? this
-              : ((parent && parent->depth < the_depth) ? parent->enclosing_loop
-                                                       : nullptr)),
+              : ((parent && parent->depth < the_depth) ? parent->enclosing_loop : nullptr)),
       enclosing_continue(
           // Compute the enclosing continue construct. Doing this in the
           // constructor member list lets us make the member const.
           // Compare parent depth because loop and continue are siblings and
           // it's incidental which will appear on the stack first.
-          the_kind == kContinue ? this
-                                : ((parent && parent->depth < the_depth)
-                                       ? parent->enclosing_continue
-                                       : nullptr)),
+          the_kind == kContinue
+              ? this
+              : ((parent && parent->depth < the_depth) ? parent->enclosing_continue : nullptr)),
       enclosing_loop_or_continue_or_switch(
           // Compute the enclosing loop or continue or switch construct.
           // Doing this in the constructor member list lets us make the
           // member const.
           // Compare parent depth because loop and continue are siblings and
           // it's incidental which will appear on the stack first.
-          (the_kind == kLoop || the_kind == kContinue ||
-           the_kind == kSwitchSelection)
+          (the_kind == kLoop || the_kind == kContinue || the_kind == kSwitchSelection)
               ? this
               : ((parent && parent->depth < the_depth)
                      ? parent->enclosing_loop_or_continue_or_switch
diff --git a/src/tint/reader/spirv/construct.h b/src/tint/reader/spirv/construct.h
index eebb899..de4e477 100644
--- a/src/tint/reader/spirv/construct.h
+++ b/src/tint/reader/spirv/construct.h
@@ -65,88 +65,84 @@
 ///  - switch-selection: where the header block ends in OpSwitch
 ///
 struct Construct {
-  /// Enumeration for the kinds of structured constructs.
-  enum Kind {
-    /// The whole function.
-    kFunction,
-    /// A SPIR-V selection construct, header basic block ending in
-    /// OpBrancConditional.
-    kIfSelection,
-    /// A SPIR-V selection construct, header basic block ending in OpSwitch.
-    kSwitchSelection,
-    /// A SPIR-V loop construct.
-    kLoop,
-    /// A SPIR-V continue construct.
-    kContinue,
-  };
+    /// Enumeration for the kinds of structured constructs.
+    enum Kind {
+        /// The whole function.
+        kFunction,
+        /// A SPIR-V selection construct, header basic block ending in
+        /// OpBrancConditional.
+        kIfSelection,
+        /// A SPIR-V selection construct, header basic block ending in OpSwitch.
+        kSwitchSelection,
+        /// A SPIR-V loop construct.
+        kLoop,
+        /// A SPIR-V continue construct.
+        kContinue,
+    };
 
-  /// Constructor
-  /// @param the_parent parent construct
-  /// @param the_depth construct nesting depth
-  /// @param the_kind construct kind
-  /// @param the_begin_id block id of the first block in the construct
-  /// @param the_end_id block id of the first block after the construct, or 0
-  /// @param the_begin_pos block order position of the_begin_id
-  /// @param the_end_pos block order position of the_end_id or a too-large value
-  /// @param the_scope_end_pos block position of the first block past the end of
-  /// the WGSL scope
-  Construct(const Construct* the_parent,
-            int the_depth,
-            Kind the_kind,
-            uint32_t the_begin_id,
-            uint32_t the_end_id,
-            uint32_t the_begin_pos,
-            uint32_t the_end_pos,
-            uint32_t the_scope_end_pos);
+    /// Constructor
+    /// @param the_parent parent construct
+    /// @param the_depth construct nesting depth
+    /// @param the_kind construct kind
+    /// @param the_begin_id block id of the first block in the construct
+    /// @param the_end_id block id of the first block after the construct, or 0
+    /// @param the_begin_pos block order position of the_begin_id
+    /// @param the_end_pos block order position of the_end_id or a too-large value
+    /// @param the_scope_end_pos block position of the first block past the end of
+    /// the WGSL scope
+    Construct(const Construct* the_parent,
+              int the_depth,
+              Kind the_kind,
+              uint32_t the_begin_id,
+              uint32_t the_end_id,
+              uint32_t the_begin_pos,
+              uint32_t the_end_pos,
+              uint32_t the_scope_end_pos);
 
-  /// @param pos a block position
-  /// @returns true if the given block position is inside this construct.
-  bool ContainsPos(uint32_t pos) const {
-    return begin_pos <= pos && pos < end_pos;
-  }
-  /// Returns true if the given block position is inside the WGSL scope
-  /// corresponding to this construct. A loop construct's WGSL scope encloses
-  /// the associated continue construct. Otherwise the WGSL scope extent is the
-  /// same as the block extent.
-  /// @param pos a block position
-  /// @returns true if the given block position is inside the WGSL scope.
-  bool ScopeContainsPos(uint32_t pos) const {
-    return begin_pos <= pos && pos < scope_end_pos;
-  }
+    /// @param pos a block position
+    /// @returns true if the given block position is inside this construct.
+    bool ContainsPos(uint32_t pos) const { return begin_pos <= pos && pos < end_pos; }
+    /// Returns true if the given block position is inside the WGSL scope
+    /// corresponding to this construct. A loop construct's WGSL scope encloses
+    /// the associated continue construct. Otherwise the WGSL scope extent is the
+    /// same as the block extent.
+    /// @param pos a block position
+    /// @returns true if the given block position is inside the WGSL scope.
+    bool ScopeContainsPos(uint32_t pos) const { return begin_pos <= pos && pos < scope_end_pos; }
 
-  /// The nearest enclosing construct other than itself, or nullptr if
-  /// this construct represents the entire function.
-  const Construct* const parent = nullptr;
-  /// The nearest enclosing loop construct, if one exists.  Points to `this`
-  /// when this is a loop construct.
-  const Construct* const enclosing_loop = nullptr;
-  /// The nearest enclosing continue construct, if one exists.  Points to
-  /// `this` when this is a contnue construct.
-  const Construct* const enclosing_continue = nullptr;
-  /// The nearest enclosing loop construct or continue construct or
-  /// switch-selection construct, if one exists. The signficance is
-  /// that a high level language "break" will branch to the merge block
-  /// of such an enclosing construct. Points to `this` when this is
-  /// a loop construct, a continue construct, or a switch-selection construct.
-  const Construct* const enclosing_loop_or_continue_or_switch = nullptr;
+    /// The nearest enclosing construct other than itself, or nullptr if
+    /// this construct represents the entire function.
+    const Construct* const parent = nullptr;
+    /// The nearest enclosing loop construct, if one exists.  Points to `this`
+    /// when this is a loop construct.
+    const Construct* const enclosing_loop = nullptr;
+    /// The nearest enclosing continue construct, if one exists.  Points to
+    /// `this` when this is a contnue construct.
+    const Construct* const enclosing_continue = nullptr;
+    /// The nearest enclosing loop construct or continue construct or
+    /// switch-selection construct, if one exists. The signficance is
+    /// that a high level language "break" will branch to the merge block
+    /// of such an enclosing construct. Points to `this` when this is
+    /// a loop construct, a continue construct, or a switch-selection construct.
+    const Construct* const enclosing_loop_or_continue_or_switch = nullptr;
 
-  /// Control flow nesting depth. The entry block is at nesting depth 0.
-  const int depth = 0;
-  /// The construct kind
-  const Kind kind = kFunction;
-  /// The id of the first block in this structure.
-  const uint32_t begin_id = 0;
-  /// 0 for kFunction, or the id of the block immediately after this construct
-  /// in the computed block order.
-  const uint32_t end_id = 0;
-  /// The position of block #begin_id in the computed block order.
-  const uint32_t begin_pos = 0;
-  /// The position of block #end_id in the block order, or the number of
-  /// block order elements if #end_id is 0.
-  const uint32_t end_pos = 0;
-  /// The position of the first block after the WGSL scope corresponding to
-  /// this construct.
-  const uint32_t scope_end_pos = 0;
+    /// Control flow nesting depth. The entry block is at nesting depth 0.
+    const int depth = 0;
+    /// The construct kind
+    const Kind kind = kFunction;
+    /// The id of the first block in this structure.
+    const uint32_t begin_id = 0;
+    /// 0 for kFunction, or the id of the block immediately after this construct
+    /// in the computed block order.
+    const uint32_t end_id = 0;
+    /// The position of block #begin_id in the computed block order.
+    const uint32_t begin_pos = 0;
+    /// The position of block #end_id in the block order, or the number of
+    /// block order elements if #end_id is 0.
+    const uint32_t end_pos = 0;
+    /// The position of the first block after the WGSL scope corresponding to
+    /// this construct.
+    const uint32_t scope_end_pos = 0;
 };
 
 /// ConstructList is a list of Construct unique pointers.
@@ -156,31 +152,31 @@
 /// @param kind the construct kind to convert
 /// @returns the string representation
 inline std::string ToString(Construct::Kind kind) {
-  switch (kind) {
-    case Construct::kFunction:
-      return "Function";
-    case Construct::kIfSelection:
-      return "IfSelection";
-    case Construct::kSwitchSelection:
-      return "SwitchSelection";
-    case Construct::kLoop:
-      return "Loop";
-    case Construct::kContinue:
-      return "Continue";
-  }
-  return "NONE";
+    switch (kind) {
+        case Construct::kFunction:
+            return "Function";
+        case Construct::kIfSelection:
+            return "IfSelection";
+        case Construct::kSwitchSelection:
+            return "SwitchSelection";
+        case Construct::kLoop:
+            return "Loop";
+        case Construct::kContinue:
+            return "Continue";
+    }
+    return "NONE";
 }
 
 /// Converts a construct into a short summary string.
 /// @param c the construct, which can be null
 /// @returns a short summary string
 inline std::string ToStringBrief(const Construct* c) {
-  if (c) {
-    std::stringstream ss;
-    ss << ToString(c->kind) << "@" << c->begin_id;
-    return ss.str();
-  }
-  return "null";
+    if (c) {
+        std::stringstream ss;
+        ss << ToString(c->kind) << "@" << c->begin_id;
+        return ss.str();
+    }
+    return "null";
 }
 
 /// Emits a construct to a stream.
@@ -188,64 +184,61 @@
 /// @param c the structured construct
 /// @returns the stream
 inline std::ostream& operator<<(std::ostream& o, const Construct& c) {
-  o << "Construct{ " << ToString(c.kind) << " [" << c.begin_pos << ","
-    << c.end_pos << ")"
-    << " begin_id:" << c.begin_id << " end_id:" << c.end_id
-    << " depth:" << c.depth;
+    o << "Construct{ " << ToString(c.kind) << " [" << c.begin_pos << "," << c.end_pos << ")"
+      << " begin_id:" << c.begin_id << " end_id:" << c.end_id << " depth:" << c.depth;
 
-  o << " parent:" << ToStringBrief(c.parent);
+    o << " parent:" << ToStringBrief(c.parent);
 
-  if (c.scope_end_pos != c.end_pos) {
-    o << " scope:[" << c.begin_pos << "," << c.scope_end_pos << ")";
-  }
+    if (c.scope_end_pos != c.end_pos) {
+        o << " scope:[" << c.begin_pos << "," << c.scope_end_pos << ")";
+    }
 
-  if (c.enclosing_loop) {
-    o << " in-l:" << ToStringBrief(c.enclosing_loop);
-  }
+    if (c.enclosing_loop) {
+        o << " in-l:" << ToStringBrief(c.enclosing_loop);
+    }
 
-  if (c.enclosing_continue) {
-    o << " in-c:" << ToStringBrief(c.enclosing_continue);
-  }
+    if (c.enclosing_continue) {
+        o << " in-c:" << ToStringBrief(c.enclosing_continue);
+    }
 
-  if ((c.enclosing_loop_or_continue_or_switch != c.enclosing_loop) &&
-      (c.enclosing_loop_or_continue_or_switch != c.enclosing_continue)) {
-    o << " in-c-l-s:" << ToStringBrief(c.enclosing_loop_or_continue_or_switch);
-  }
+    if ((c.enclosing_loop_or_continue_or_switch != c.enclosing_loop) &&
+        (c.enclosing_loop_or_continue_or_switch != c.enclosing_continue)) {
+        o << " in-c-l-s:" << ToStringBrief(c.enclosing_loop_or_continue_or_switch);
+    }
 
-  o << " }";
-  return o;
+    o << " }";
+    return o;
 }
 
 /// Emits a construct to a stream.
 /// @param o the stream
 /// @param c the structured construct
 /// @returns the stream
-inline std::ostream& operator<<(std::ostream& o,
-                                const std::unique_ptr<Construct>& c) {
-  return o << *(c.get());
+inline std::ostream& operator<<(std::ostream& o, const std::unique_ptr<Construct>& c) {
+    return o << *(c.get());
 }
 
 /// Converts a construct to a string.
 /// @param c the construct
 /// @returns the string representation
 inline std::string ToString(const Construct& c) {
-  std::stringstream ss;
-  ss << c;
-  return ss.str();
+    std::stringstream ss;
+    ss << c;
+    return ss.str();
 }
 
 /// Converts a construct to a string.
 /// @param c the construct
 /// @returns the string representation
 inline std::string ToString(const Construct* c) {
-  return c ? ToString(*c) : ToStringBrief(c);
+    return c ? ToString(*c) : ToStringBrief(c);
 }
 
 /// Converts a unique pointer to a construct to a string.
 /// @param c the construct
 /// @returns the string representation
 inline std::string ToString(const std::unique_ptr<Construct>& c) {
-  return ToString(*(c.get()));
+    return ToString(*(c.get()));
 }
 
 /// Emits a construct list to a stream.
@@ -253,21 +246,21 @@
 /// @param cl the construct list
 /// @returns the stream
 inline std::ostream& operator<<(std::ostream& o, const ConstructList& cl) {
-  o << "ConstructList{\n";
-  for (const auto& c : cl) {
-    o << "  " << c << "\n";
-  }
-  o << "}";
-  return o;
+    o << "ConstructList{\n";
+    for (const auto& c : cl) {
+        o << "  " << c << "\n";
+    }
+    o << "}";
+    return o;
 }
 
 /// Converts a construct list to a string.
 /// @param cl the construct list
 /// @returns the string representation
 inline std::string ToString(const ConstructList& cl) {
-  std::stringstream ss;
-  ss << cl;
-  return ss.str();
+    std::stringstream ss;
+    ss << cl;
+    return ss.str();
 }
 
 }  // namespace tint::reader::spirv
diff --git a/src/tint/reader/spirv/entry_point_info.h b/src/tint/reader/spirv/entry_point_info.h
index 374bd83..bc13759 100644
--- a/src/tint/reader/spirv/entry_point_info.h
+++ b/src/tint/reader/spirv/entry_point_info.h
@@ -24,66 +24,66 @@
 
 /// The size of an integer-coordinate grid, in the x, y, and z dimensions.
 struct GridSize {
-  /// x value
-  uint32_t x = 0;
-  /// y value
-  uint32_t y = 0;
-  /// z value
-  uint32_t z = 0;
+    /// x value
+    uint32_t x = 0;
+    /// y value
+    uint32_t y = 0;
+    /// z value
+    uint32_t z = 0;
 };
 
 /// Entry point information for a function
 struct EntryPointInfo {
-  /// Constructor.
-  /// @param the_name the name of the entry point
-  /// @param the_stage the pipeline stage
-  /// @param the_owns_inner_implementation if true, this entry point is
-  /// responsible for generating the inner implementation function.
-  /// @param the_inner_name the name of the inner implementation function of the
-  /// entry point
-  /// @param the_inputs list of IDs for Input variables used by the shader
-  /// @param the_outputs list of IDs for Output variables used by the shader
-  /// @param the_wg_size the workgroup_size, for a compute shader
-  EntryPointInfo(std::string the_name,
-                 ast::PipelineStage the_stage,
-                 bool the_owns_inner_implementation,
-                 std::string the_inner_name,
-                 std::vector<uint32_t>&& the_inputs,
-                 std::vector<uint32_t>&& the_outputs,
-                 GridSize the_wg_size);
-  /// Copy constructor
-  /// @param other the other entry point info to be built from
-  EntryPointInfo(const EntryPointInfo& other);
-  /// Destructor
-  ~EntryPointInfo();
+    /// Constructor.
+    /// @param the_name the name of the entry point
+    /// @param the_stage the pipeline stage
+    /// @param the_owns_inner_implementation if true, this entry point is
+    /// responsible for generating the inner implementation function.
+    /// @param the_inner_name the name of the inner implementation function of the
+    /// entry point
+    /// @param the_inputs list of IDs for Input variables used by the shader
+    /// @param the_outputs list of IDs for Output variables used by the shader
+    /// @param the_wg_size the workgroup_size, for a compute shader
+    EntryPointInfo(std::string the_name,
+                   ast::PipelineStage the_stage,
+                   bool the_owns_inner_implementation,
+                   std::string the_inner_name,
+                   std::vector<uint32_t>&& the_inputs,
+                   std::vector<uint32_t>&& the_outputs,
+                   GridSize the_wg_size);
+    /// Copy constructor
+    /// @param other the other entry point info to be built from
+    EntryPointInfo(const EntryPointInfo& other);
+    /// Destructor
+    ~EntryPointInfo();
 
-  /// The entry point name.
-  /// In the WGSL output, this function will have pipeline inputs and outputs
-  /// as parameters. This function will store them into Private variables,
-  /// and then call the "inner" function, named by the next memeber.
-  /// Then outputs are copied from the private variables to the return value.
-  std::string name;
-  /// The entry point stage
-  ast::PipelineStage stage = ast::PipelineStage::kNone;
+    /// The entry point name.
+    /// In the WGSL output, this function will have pipeline inputs and outputs
+    /// as parameters. This function will store them into Private variables,
+    /// and then call the "inner" function, named by the next memeber.
+    /// Then outputs are copied from the private variables to the return value.
+    std::string name;
+    /// The entry point stage
+    ast::PipelineStage stage = ast::PipelineStage::kNone;
 
-  /// True when this entry point is responsible for generating the
-  /// inner implementation function.  False when this is the second entry
-  /// point encountered for the same function in SPIR-V. It's unusual, but
-  /// possible for the same function to be the implementation for multiple
-  /// entry points.
-  bool owns_inner_implementation;
-  /// The name of the inner implementation function of the entry point.
-  std::string inner_name;
-  /// IDs of pipeline input variables, sorted and without duplicates.
-  std::vector<uint32_t> inputs;
-  /// IDs of pipeline output variables, sorted and without duplicates.
-  std::vector<uint32_t> outputs;
+    /// True when this entry point is responsible for generating the
+    /// inner implementation function.  False when this is the second entry
+    /// point encountered for the same function in SPIR-V. It's unusual, but
+    /// possible for the same function to be the implementation for multiple
+    /// entry points.
+    bool owns_inner_implementation;
+    /// The name of the inner implementation function of the entry point.
+    std::string inner_name;
+    /// IDs of pipeline input variables, sorted and without duplicates.
+    std::vector<uint32_t> inputs;
+    /// IDs of pipeline output variables, sorted and without duplicates.
+    std::vector<uint32_t> outputs;
 
-  /// If this is a compute shader, this is the workgroup size in the x, y,
-  /// and z dimensions set via LocalSize, or via the composite value
-  /// decorated as the WorkgroupSize BuiltIn.  The WorkgroupSize builtin
-  /// takes priority.
-  GridSize workgroup_size;
+    /// If this is a compute shader, this is the workgroup size in the x, y,
+    /// and z dimensions set via LocalSize, or via the composite value
+    /// decorated as the WorkgroupSize BuiltIn.  The WorkgroupSize builtin
+    /// takes priority.
+    GridSize workgroup_size;
 };
 
 }  // namespace tint::reader::spirv
diff --git a/src/tint/reader/spirv/enum_converter.cc b/src/tint/reader/spirv/enum_converter.cc
index 2cd1daa..1d58eee 100644
--- a/src/tint/reader/spirv/enum_converter.cc
+++ b/src/tint/reader/spirv/enum_converter.cc
@@ -21,158 +21,158 @@
 EnumConverter::~EnumConverter() = default;
 
 ast::PipelineStage EnumConverter::ToPipelineStage(SpvExecutionModel model) {
-  switch (model) {
-    case SpvExecutionModelVertex:
-      return ast::PipelineStage::kVertex;
-    case SpvExecutionModelFragment:
-      return ast::PipelineStage::kFragment;
-    case SpvExecutionModelGLCompute:
-      return ast::PipelineStage::kCompute;
-    default:
-      break;
-  }
+    switch (model) {
+        case SpvExecutionModelVertex:
+            return ast::PipelineStage::kVertex;
+        case SpvExecutionModelFragment:
+            return ast::PipelineStage::kFragment;
+        case SpvExecutionModelGLCompute:
+            return ast::PipelineStage::kCompute;
+        default:
+            break;
+    }
 
-  Fail() << "unknown SPIR-V execution model: " << uint32_t(model);
-  return ast::PipelineStage::kNone;
+    Fail() << "unknown SPIR-V execution model: " << uint32_t(model);
+    return ast::PipelineStage::kNone;
 }
 
 ast::StorageClass EnumConverter::ToStorageClass(const SpvStorageClass sc) {
-  switch (sc) {
-    case SpvStorageClassInput:
-      return ast::StorageClass::kInput;
-    case SpvStorageClassOutput:
-      return ast::StorageClass::kOutput;
-    case SpvStorageClassUniform:
-      return ast::StorageClass::kUniform;
-    case SpvStorageClassWorkgroup:
-      return ast::StorageClass::kWorkgroup;
-    case SpvStorageClassUniformConstant:
-      return ast::StorageClass::kNone;
-    case SpvStorageClassStorageBuffer:
-      return ast::StorageClass::kStorage;
-    case SpvStorageClassPrivate:
-      return ast::StorageClass::kPrivate;
-    case SpvStorageClassFunction:
-      return ast::StorageClass::kFunction;
-    default:
-      break;
-  }
+    switch (sc) {
+        case SpvStorageClassInput:
+            return ast::StorageClass::kInput;
+        case SpvStorageClassOutput:
+            return ast::StorageClass::kOutput;
+        case SpvStorageClassUniform:
+            return ast::StorageClass::kUniform;
+        case SpvStorageClassWorkgroup:
+            return ast::StorageClass::kWorkgroup;
+        case SpvStorageClassUniformConstant:
+            return ast::StorageClass::kNone;
+        case SpvStorageClassStorageBuffer:
+            return ast::StorageClass::kStorage;
+        case SpvStorageClassPrivate:
+            return ast::StorageClass::kPrivate;
+        case SpvStorageClassFunction:
+            return ast::StorageClass::kFunction;
+        default:
+            break;
+    }
 
-  Fail() << "unknown SPIR-V storage class: " << uint32_t(sc);
-  return ast::StorageClass::kInvalid;
+    Fail() << "unknown SPIR-V storage class: " << uint32_t(sc);
+    return ast::StorageClass::kInvalid;
 }
 
 ast::Builtin EnumConverter::ToBuiltin(SpvBuiltIn b) {
-  switch (b) {
-    case SpvBuiltInPosition:
-      return ast::Builtin::kPosition;
-    case SpvBuiltInVertexIndex:
-      return ast::Builtin::kVertexIndex;
-    case SpvBuiltInInstanceIndex:
-      return ast::Builtin::kInstanceIndex;
-    case SpvBuiltInFrontFacing:
-      return ast::Builtin::kFrontFacing;
-    case SpvBuiltInFragCoord:
-      return ast::Builtin::kPosition;
-    case SpvBuiltInFragDepth:
-      return ast::Builtin::kFragDepth;
-    case SpvBuiltInLocalInvocationId:
-      return ast::Builtin::kLocalInvocationId;
-    case SpvBuiltInLocalInvocationIndex:
-      return ast::Builtin::kLocalInvocationIndex;
-    case SpvBuiltInGlobalInvocationId:
-      return ast::Builtin::kGlobalInvocationId;
-    case SpvBuiltInWorkgroupId:
-      return ast::Builtin::kWorkgroupId;
-    case SpvBuiltInSampleId:
-      return ast::Builtin::kSampleIndex;
-    case SpvBuiltInSampleMask:
-      return ast::Builtin::kSampleMask;
-    default:
-      break;
-  }
+    switch (b) {
+        case SpvBuiltInPosition:
+            return ast::Builtin::kPosition;
+        case SpvBuiltInVertexIndex:
+            return ast::Builtin::kVertexIndex;
+        case SpvBuiltInInstanceIndex:
+            return ast::Builtin::kInstanceIndex;
+        case SpvBuiltInFrontFacing:
+            return ast::Builtin::kFrontFacing;
+        case SpvBuiltInFragCoord:
+            return ast::Builtin::kPosition;
+        case SpvBuiltInFragDepth:
+            return ast::Builtin::kFragDepth;
+        case SpvBuiltInLocalInvocationId:
+            return ast::Builtin::kLocalInvocationId;
+        case SpvBuiltInLocalInvocationIndex:
+            return ast::Builtin::kLocalInvocationIndex;
+        case SpvBuiltInGlobalInvocationId:
+            return ast::Builtin::kGlobalInvocationId;
+        case SpvBuiltInWorkgroupId:
+            return ast::Builtin::kWorkgroupId;
+        case SpvBuiltInSampleId:
+            return ast::Builtin::kSampleIndex;
+        case SpvBuiltInSampleMask:
+            return ast::Builtin::kSampleMask;
+        default:
+            break;
+    }
 
-  Fail() << "unknown SPIR-V builtin: " << uint32_t(b);
-  return ast::Builtin::kNone;
+    Fail() << "unknown SPIR-V builtin: " << uint32_t(b);
+    return ast::Builtin::kNone;
 }
 
 ast::TextureDimension EnumConverter::ToDim(SpvDim dim, bool arrayed) {
-  if (arrayed) {
-    switch (dim) {
-      case SpvDim2D:
-        return ast::TextureDimension::k2dArray;
-      case SpvDimCube:
-        return ast::TextureDimension::kCubeArray;
-      default:
-        break;
+    if (arrayed) {
+        switch (dim) {
+            case SpvDim2D:
+                return ast::TextureDimension::k2dArray;
+            case SpvDimCube:
+                return ast::TextureDimension::kCubeArray;
+            default:
+                break;
+        }
+        Fail() << "arrayed dimension must be 2D or Cube. Got " << int(dim);
+        return ast::TextureDimension::kNone;
     }
-    Fail() << "arrayed dimension must be 2D or Cube. Got " << int(dim);
+    // Assume non-arrayed
+    switch (dim) {
+        case SpvDim1D:
+            return ast::TextureDimension::k1d;
+        case SpvDim2D:
+            return ast::TextureDimension::k2d;
+        case SpvDim3D:
+            return ast::TextureDimension::k3d;
+        case SpvDimCube:
+            return ast::TextureDimension::kCube;
+        default:
+            break;
+    }
+    Fail() << "invalid dimension: " << int(dim);
     return ast::TextureDimension::kNone;
-  }
-  // Assume non-arrayed
-  switch (dim) {
-    case SpvDim1D:
-      return ast::TextureDimension::k1d;
-    case SpvDim2D:
-      return ast::TextureDimension::k2d;
-    case SpvDim3D:
-      return ast::TextureDimension::k3d;
-    case SpvDimCube:
-      return ast::TextureDimension::kCube;
-    default:
-      break;
-  }
-  Fail() << "invalid dimension: " << int(dim);
-  return ast::TextureDimension::kNone;
 }
 
 ast::TexelFormat EnumConverter::ToTexelFormat(SpvImageFormat fmt) {
-  switch (fmt) {
-    case SpvImageFormatUnknown:
-      return ast::TexelFormat::kNone;
+    switch (fmt) {
+        case SpvImageFormatUnknown:
+            return ast::TexelFormat::kNone;
 
-    // 8 bit channels
-    case SpvImageFormatRgba8:
-      return ast::TexelFormat::kRgba8Unorm;
-    case SpvImageFormatRgba8Snorm:
-      return ast::TexelFormat::kRgba8Snorm;
-    case SpvImageFormatRgba8ui:
-      return ast::TexelFormat::kRgba8Uint;
-    case SpvImageFormatRgba8i:
-      return ast::TexelFormat::kRgba8Sint;
+        // 8 bit channels
+        case SpvImageFormatRgba8:
+            return ast::TexelFormat::kRgba8Unorm;
+        case SpvImageFormatRgba8Snorm:
+            return ast::TexelFormat::kRgba8Snorm;
+        case SpvImageFormatRgba8ui:
+            return ast::TexelFormat::kRgba8Uint;
+        case SpvImageFormatRgba8i:
+            return ast::TexelFormat::kRgba8Sint;
 
-    // 16 bit channels
-    case SpvImageFormatRgba16ui:
-      return ast::TexelFormat::kRgba16Uint;
-    case SpvImageFormatRgba16i:
-      return ast::TexelFormat::kRgba16Sint;
-    case SpvImageFormatRgba16f:
-      return ast::TexelFormat::kRgba16Float;
+        // 16 bit channels
+        case SpvImageFormatRgba16ui:
+            return ast::TexelFormat::kRgba16Uint;
+        case SpvImageFormatRgba16i:
+            return ast::TexelFormat::kRgba16Sint;
+        case SpvImageFormatRgba16f:
+            return ast::TexelFormat::kRgba16Float;
 
-    // 32 bit channels
-    case SpvImageFormatR32ui:
-      return ast::TexelFormat::kR32Uint;
-    case SpvImageFormatR32i:
-      return ast::TexelFormat::kR32Sint;
-    case SpvImageFormatR32f:
-      return ast::TexelFormat::kR32Float;
-    case SpvImageFormatRg32ui:
-      return ast::TexelFormat::kRg32Uint;
-    case SpvImageFormatRg32i:
-      return ast::TexelFormat::kRg32Sint;
-    case SpvImageFormatRg32f:
-      return ast::TexelFormat::kRg32Float;
-    case SpvImageFormatRgba32ui:
-      return ast::TexelFormat::kRgba32Uint;
-    case SpvImageFormatRgba32i:
-      return ast::TexelFormat::kRgba32Sint;
-    case SpvImageFormatRgba32f:
-      return ast::TexelFormat::kRgba32Float;
-    default:
-      break;
-  }
-  Fail() << "invalid image format: " << int(fmt);
-  return ast::TexelFormat::kNone;
+        // 32 bit channels
+        case SpvImageFormatR32ui:
+            return ast::TexelFormat::kR32Uint;
+        case SpvImageFormatR32i:
+            return ast::TexelFormat::kR32Sint;
+        case SpvImageFormatR32f:
+            return ast::TexelFormat::kR32Float;
+        case SpvImageFormatRg32ui:
+            return ast::TexelFormat::kRg32Uint;
+        case SpvImageFormatRg32i:
+            return ast::TexelFormat::kRg32Sint;
+        case SpvImageFormatRg32f:
+            return ast::TexelFormat::kRg32Float;
+        case SpvImageFormatRgba32ui:
+            return ast::TexelFormat::kRgba32Uint;
+        case SpvImageFormatRgba32i:
+            return ast::TexelFormat::kRgba32Sint;
+        case SpvImageFormatRgba32f:
+            return ast::TexelFormat::kRgba32Float;
+        default:
+            break;
+    }
+    Fail() << "invalid image format: " << int(fmt);
+    return ast::TexelFormat::kNone;
 }
 
 }  // namespace tint::reader::spirv
diff --git a/src/tint/reader/spirv/enum_converter.h b/src/tint/reader/spirv/enum_converter.h
index 4a31cfe..ac86f71 100644
--- a/src/tint/reader/spirv/enum_converter.h
+++ b/src/tint/reader/spirv/enum_converter.h
@@ -20,56 +20,56 @@
 #include "src/tint/ast/pipeline_stage.h"
 #include "src/tint/ast/storage_class.h"
 #include "src/tint/reader/spirv/fail_stream.h"
-#include "src/tint/sem/storage_texture_type.h"
+#include "src/tint/sem/storage_texture.h"
 
 namespace tint::reader::spirv {
 
 /// A converter from SPIR-V enums to Tint AST enums.
 class EnumConverter {
- public:
-  /// Creates a new enum converter.
-  /// @param fail_stream the error reporting stream.
-  explicit EnumConverter(const FailStream& fail_stream);
-  /// Destructor
-  ~EnumConverter();
+  public:
+    /// Creates a new enum converter.
+    /// @param fail_stream the error reporting stream.
+    explicit EnumConverter(const FailStream& fail_stream);
+    /// Destructor
+    ~EnumConverter();
 
-  /// Converts a SPIR-V execution model to a Tint pipeline stage.
-  /// On failure, logs an error and returns kNone
-  /// @param model the SPIR-V entry point execution model
-  /// @returns a Tint AST pipeline stage
-  ast::PipelineStage ToPipelineStage(SpvExecutionModel model);
+    /// Converts a SPIR-V execution model to a Tint pipeline stage.
+    /// On failure, logs an error and returns kNone
+    /// @param model the SPIR-V entry point execution model
+    /// @returns a Tint AST pipeline stage
+    ast::PipelineStage ToPipelineStage(SpvExecutionModel model);
 
-  /// Converts a SPIR-V storage class to a Tint storage class.
-  /// On failure, logs an error and returns kNone
-  /// @param sc the SPIR-V storage class
-  /// @returns a Tint AST storage class
-  ast::StorageClass ToStorageClass(const SpvStorageClass sc);
+    /// Converts a SPIR-V storage class to a Tint storage class.
+    /// On failure, logs an error and returns kNone
+    /// @param sc the SPIR-V storage class
+    /// @returns a Tint AST storage class
+    ast::StorageClass ToStorageClass(const SpvStorageClass sc);
 
-  /// Converts a SPIR-V Builtin value a Tint Builtin.
-  /// On failure, logs an error and returns kNone
-  /// @param b the SPIR-V builtin
-  /// @returns a Tint AST builtin
-  ast::Builtin ToBuiltin(SpvBuiltIn b);
+    /// Converts a SPIR-V Builtin value a Tint Builtin.
+    /// On failure, logs an error and returns kNone
+    /// @param b the SPIR-V builtin
+    /// @returns a Tint AST builtin
+    ast::Builtin ToBuiltin(SpvBuiltIn b);
 
-  /// Converts a possibly arrayed SPIR-V Dim to a Tint texture dimension.
-  /// On failure, logs an error and returns kNone
-  /// @param dim the SPIR-V Dim value
-  /// @param arrayed true if the texture is arrayed
-  /// @returns a Tint AST texture dimension
-  ast::TextureDimension ToDim(SpvDim dim, bool arrayed);
+    /// Converts a possibly arrayed SPIR-V Dim to a Tint texture dimension.
+    /// On failure, logs an error and returns kNone
+    /// @param dim the SPIR-V Dim value
+    /// @param arrayed true if the texture is arrayed
+    /// @returns a Tint AST texture dimension
+    ast::TextureDimension ToDim(SpvDim dim, bool arrayed);
 
-  /// Converts a SPIR-V Image Format to a TexelFormat
-  /// On failure, logs an error and returns kNone
-  /// @param fmt the SPIR-V format
-  /// @returns a Tint AST format
-  ast::TexelFormat ToTexelFormat(SpvImageFormat fmt);
+    /// Converts a SPIR-V Image Format to a TexelFormat
+    /// On failure, logs an error and returns kNone
+    /// @param fmt the SPIR-V format
+    /// @returns a Tint AST format
+    ast::TexelFormat ToTexelFormat(SpvImageFormat fmt);
 
- private:
-  /// Registers a failure and returns a stream for log diagnostics.
-  /// @returns a failure stream
-  FailStream Fail() { return fail_stream_.Fail(); }
+  private:
+    /// Registers a failure and returns a stream for log diagnostics.
+    /// @returns a failure stream
+    FailStream Fail() { return fail_stream_.Fail(); }
 
-  FailStream fail_stream_;
+    FailStream fail_stream_;
 };
 
 }  // namespace tint::reader::spirv
diff --git a/src/tint/reader/spirv/enum_converter_test.cc b/src/tint/reader/spirv/enum_converter_test.cc
index 6f9e2a1..791d7e3 100644
--- a/src/tint/reader/spirv/enum_converter_test.cc
+++ b/src/tint/reader/spirv/enum_converter_test.cc
@@ -24,179 +24,160 @@
 // Pipeline stage
 
 struct PipelineStageCase {
-  SpvExecutionModel model;
-  bool expect_success;
-  ast::PipelineStage expected;
+    SpvExecutionModel model;
+    bool expect_success;
+    ast::PipelineStage expected;
 };
 inline std::ostream& operator<<(std::ostream& out, PipelineStageCase psc) {
-  out << "PipelineStageCase{ SpvExecutionModel:" << int(psc.model)
-      << " expect_success?:" << int(psc.expect_success)
-      << " expected:" << int(psc.expected) << "}";
-  return out;
+    out << "PipelineStageCase{ SpvExecutionModel:" << int(psc.model)
+        << " expect_success?:" << int(psc.expect_success) << " expected:" << int(psc.expected)
+        << "}";
+    return out;
 }
 
 class SpvPipelineStageTest : public testing::TestWithParam<PipelineStageCase> {
- public:
-  SpvPipelineStageTest()
-      : success_(true),
-        fail_stream_(&success_, &errors_),
-        converter_(fail_stream_) {}
+  public:
+    SpvPipelineStageTest()
+        : success_(true), fail_stream_(&success_, &errors_), converter_(fail_stream_) {}
 
-  std::string error() const { return errors_.str(); }
+    std::string error() const { return errors_.str(); }
 
- protected:
-  bool success_ = true;
-  std::stringstream errors_;
-  FailStream fail_stream_;
-  EnumConverter converter_;
+  protected:
+    bool success_ = true;
+    std::stringstream errors_;
+    FailStream fail_stream_;
+    EnumConverter converter_;
 };
 
 TEST_P(SpvPipelineStageTest, Samples) {
-  const auto params = GetParam();
+    const auto params = GetParam();
 
-  const auto result = converter_.ToPipelineStage(params.model);
-  EXPECT_EQ(success_, params.expect_success);
-  if (params.expect_success) {
-    EXPECT_EQ(result, params.expected);
-    EXPECT_TRUE(error().empty());
-  } else {
-    EXPECT_EQ(result, params.expected);
-    EXPECT_THAT(error(),
-                ::testing::StartsWith("unknown SPIR-V execution model:"));
-  }
+    const auto result = converter_.ToPipelineStage(params.model);
+    EXPECT_EQ(success_, params.expect_success);
+    if (params.expect_success) {
+        EXPECT_EQ(result, params.expected);
+        EXPECT_TRUE(error().empty());
+    } else {
+        EXPECT_EQ(result, params.expected);
+        EXPECT_THAT(error(), ::testing::StartsWith("unknown SPIR-V execution model:"));
+    }
 }
 
-INSTANTIATE_TEST_SUITE_P(
-    EnumConverterGood,
-    SpvPipelineStageTest,
-    testing::Values(PipelineStageCase{SpvExecutionModelVertex, true,
-                                      ast::PipelineStage::kVertex},
-                    PipelineStageCase{SpvExecutionModelFragment, true,
-                                      ast::PipelineStage::kFragment},
-                    PipelineStageCase{SpvExecutionModelGLCompute, true,
-                                      ast::PipelineStage::kCompute}));
+INSTANTIATE_TEST_SUITE_P(EnumConverterGood,
+                         SpvPipelineStageTest,
+                         testing::Values(PipelineStageCase{SpvExecutionModelVertex, true,
+                                                           ast::PipelineStage::kVertex},
+                                         PipelineStageCase{SpvExecutionModelFragment, true,
+                                                           ast::PipelineStage::kFragment},
+                                         PipelineStageCase{SpvExecutionModelGLCompute, true,
+                                                           ast::PipelineStage::kCompute}));
 
-INSTANTIATE_TEST_SUITE_P(
-    EnumConverterBad,
-    SpvPipelineStageTest,
-    testing::Values(PipelineStageCase{static_cast<SpvExecutionModel>(9999),
-                                      false, ast::PipelineStage::kNone},
-                    PipelineStageCase{SpvExecutionModelTessellationControl,
-                                      false, ast::PipelineStage::kNone}));
+INSTANTIATE_TEST_SUITE_P(EnumConverterBad,
+                         SpvPipelineStageTest,
+                         testing::Values(PipelineStageCase{static_cast<SpvExecutionModel>(9999),
+                                                           false, ast::PipelineStage::kNone},
+                                         PipelineStageCase{SpvExecutionModelTessellationControl,
+                                                           false, ast::PipelineStage::kNone}));
 
 // Storage class
 
 struct StorageClassCase {
-  SpvStorageClass sc;
-  bool expect_success;
-  ast::StorageClass expected;
+    SpvStorageClass sc;
+    bool expect_success;
+    ast::StorageClass expected;
 };
 inline std::ostream& operator<<(std::ostream& out, StorageClassCase scc) {
-  out << "StorageClassCase{ SpvStorageClass:" << int(scc.sc)
-      << " expect_success?:" << int(scc.expect_success)
-      << " expected:" << int(scc.expected) << "}";
-  return out;
+    out << "StorageClassCase{ SpvStorageClass:" << int(scc.sc)
+        << " expect_success?:" << int(scc.expect_success) << " expected:" << int(scc.expected)
+        << "}";
+    return out;
 }
 
 class SpvStorageClassTest : public testing::TestWithParam<StorageClassCase> {
- public:
-  SpvStorageClassTest()
-      : success_(true),
-        fail_stream_(&success_, &errors_),
-        converter_(fail_stream_) {}
+  public:
+    SpvStorageClassTest()
+        : success_(true), fail_stream_(&success_, &errors_), converter_(fail_stream_) {}
 
-  std::string error() const { return errors_.str(); }
+    std::string error() const { return errors_.str(); }
 
- protected:
-  bool success_ = true;
-  std::stringstream errors_;
-  FailStream fail_stream_;
-  EnumConverter converter_;
+  protected:
+    bool success_ = true;
+    std::stringstream errors_;
+    FailStream fail_stream_;
+    EnumConverter converter_;
 };
 
 TEST_P(SpvStorageClassTest, Samples) {
-  const auto params = GetParam();
+    const auto params = GetParam();
 
-  const auto result = converter_.ToStorageClass(params.sc);
-  EXPECT_EQ(success_, params.expect_success);
-  if (params.expect_success) {
-    EXPECT_EQ(result, params.expected);
-    EXPECT_TRUE(error().empty());
-  } else {
-    EXPECT_EQ(result, params.expected);
-    EXPECT_THAT(error(),
-                ::testing::StartsWith("unknown SPIR-V storage class: "));
-  }
+    const auto result = converter_.ToStorageClass(params.sc);
+    EXPECT_EQ(success_, params.expect_success);
+    if (params.expect_success) {
+        EXPECT_EQ(result, params.expected);
+        EXPECT_TRUE(error().empty());
+    } else {
+        EXPECT_EQ(result, params.expected);
+        EXPECT_THAT(error(), ::testing::StartsWith("unknown SPIR-V storage class: "));
+    }
 }
 
 INSTANTIATE_TEST_SUITE_P(
     EnumConverterGood,
     SpvStorageClassTest,
-    testing::Values(StorageClassCase{SpvStorageClassInput, true,
-                                     ast::StorageClass::kInput},
-                    StorageClassCase{SpvStorageClassOutput, true,
-                                     ast::StorageClass::kOutput},
-                    StorageClassCase{SpvStorageClassUniform, true,
-                                     ast::StorageClass::kUniform},
-                    StorageClassCase{SpvStorageClassWorkgroup, true,
-                                     ast::StorageClass::kWorkgroup},
-                    StorageClassCase{SpvStorageClassUniformConstant, true,
-                                     ast::StorageClass::kNone},
-                    StorageClassCase{SpvStorageClassStorageBuffer, true,
-                                     ast::StorageClass::kStorage},
-                    StorageClassCase{SpvStorageClassPrivate, true,
-                                     ast::StorageClass::kPrivate},
-                    StorageClassCase{SpvStorageClassFunction, true,
-                                     ast::StorageClass::kFunction}));
+    testing::Values(
+        StorageClassCase{SpvStorageClassInput, true, ast::StorageClass::kInput},
+        StorageClassCase{SpvStorageClassOutput, true, ast::StorageClass::kOutput},
+        StorageClassCase{SpvStorageClassUniform, true, ast::StorageClass::kUniform},
+        StorageClassCase{SpvStorageClassWorkgroup, true, ast::StorageClass::kWorkgroup},
+        StorageClassCase{SpvStorageClassUniformConstant, true, ast::StorageClass::kNone},
+        StorageClassCase{SpvStorageClassStorageBuffer, true, ast::StorageClass::kStorage},
+        StorageClassCase{SpvStorageClassPrivate, true, ast::StorageClass::kPrivate},
+        StorageClassCase{SpvStorageClassFunction, true, ast::StorageClass::kFunction}));
 
 INSTANTIATE_TEST_SUITE_P(EnumConverterBad,
                          SpvStorageClassTest,
-                         testing::Values(StorageClassCase{
-                             static_cast<SpvStorageClass>(9999), false,
-                             ast::StorageClass::kInvalid}));
+                         testing::Values(StorageClassCase{static_cast<SpvStorageClass>(9999), false,
+                                                          ast::StorageClass::kInvalid}));
 
 // Builtin
 
 struct BuiltinCase {
-  SpvBuiltIn builtin;
-  bool expect_success;
-  ast::Builtin expected;
+    SpvBuiltIn builtin;
+    bool expect_success;
+    ast::Builtin expected;
 };
 inline std::ostream& operator<<(std::ostream& out, BuiltinCase bc) {
-  out << "BuiltinCase{ SpvBuiltIn:" << int(bc.builtin)
-      << " expect_success?:" << int(bc.expect_success)
-      << " expected:" << int(bc.expected) << "}";
-  return out;
+    out << "BuiltinCase{ SpvBuiltIn:" << int(bc.builtin)
+        << " expect_success?:" << int(bc.expect_success) << " expected:" << int(bc.expected) << "}";
+    return out;
 }
 
 class SpvBuiltinTest : public testing::TestWithParam<BuiltinCase> {
- public:
-  SpvBuiltinTest()
-      : success_(true),
-        fail_stream_(&success_, &errors_),
-        converter_(fail_stream_) {}
+  public:
+    SpvBuiltinTest()
+        : success_(true), fail_stream_(&success_, &errors_), converter_(fail_stream_) {}
 
-  std::string error() const { return errors_.str(); }
+    std::string error() const { return errors_.str(); }
 
- protected:
-  bool success_ = true;
-  std::stringstream errors_;
-  FailStream fail_stream_;
-  EnumConverter converter_;
+  protected:
+    bool success_ = true;
+    std::stringstream errors_;
+    FailStream fail_stream_;
+    EnumConverter converter_;
 };
 
 TEST_P(SpvBuiltinTest, Samples) {
-  const auto params = GetParam();
+    const auto params = GetParam();
 
-  const auto result = converter_.ToBuiltin(params.builtin);
-  EXPECT_EQ(success_, params.expect_success);
-  if (params.expect_success) {
-    EXPECT_EQ(result, params.expected);
-    EXPECT_TRUE(error().empty());
-  } else {
-    EXPECT_EQ(result, params.expected);
-    EXPECT_THAT(error(), ::testing::StartsWith("unknown SPIR-V builtin: "));
-  }
+    const auto result = converter_.ToBuiltin(params.builtin);
+    EXPECT_EQ(success_, params.expect_success);
+    if (params.expect_success) {
+        EXPECT_EQ(result, params.expected);
+        EXPECT_TRUE(error().empty());
+    } else {
+        EXPECT_EQ(result, params.expected);
+        EXPECT_THAT(error(), ::testing::StartsWith("unknown SPIR-V builtin: "));
+    }
 }
 
 INSTANTIATE_TEST_SUITE_P(
@@ -204,16 +185,12 @@
     SpvBuiltinTest,
     testing::Values(
         BuiltinCase{SpvBuiltInPosition, true, ast::Builtin::kPosition},
-        BuiltinCase{SpvBuiltInInstanceIndex, true,
-                    ast::Builtin::kInstanceIndex},
+        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{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}));
@@ -221,136 +198,127 @@
 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::Builtin::kPosition},
+                    BuiltinCase{SpvBuiltInFragDepth, true, ast::Builtin::kFragDepth},
+                    BuiltinCase{SpvBuiltInSampleMask, true, ast::Builtin::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::Builtin::kNone},
+                    BuiltinCase{static_cast<SpvBuiltIn>(9999), false, ast::Builtin::kNone},
+                    BuiltinCase{SpvBuiltInNumWorkgroups, false, ast::Builtin::kNone}));
 
 // Dim
 
 struct DimCase {
-  SpvDim dim;
-  bool arrayed;
-  bool expect_success;
-  ast::TextureDimension expected;
+    SpvDim dim;
+    bool arrayed;
+    bool expect_success;
+    ast::TextureDimension expected;
 };
 inline std::ostream& operator<<(std::ostream& out, DimCase dc) {
-  out << "DimCase{ SpvDim:" << int(dc.dim) << " arrayed?:" << int(dc.arrayed)
-      << " expect_success?:" << int(dc.expect_success)
-      << " expected:" << int(dc.expected) << "}";
-  return out;
+    out << "DimCase{ SpvDim:" << int(dc.dim) << " arrayed?:" << int(dc.arrayed)
+        << " expect_success?:" << int(dc.expect_success) << " expected:" << int(dc.expected) << "}";
+    return out;
 }
 
 class SpvDimTest : public testing::TestWithParam<DimCase> {
- public:
-  SpvDimTest()
-      : success_(true),
-        fail_stream_(&success_, &errors_),
-        converter_(fail_stream_) {}
+  public:
+    SpvDimTest() : success_(true), fail_stream_(&success_, &errors_), converter_(fail_stream_) {}
 
-  std::string error() const { return errors_.str(); }
+    std::string error() const { return errors_.str(); }
 
- protected:
-  bool success_ = true;
-  std::stringstream errors_;
-  FailStream fail_stream_;
-  EnumConverter converter_;
+  protected:
+    bool success_ = true;
+    std::stringstream errors_;
+    FailStream fail_stream_;
+    EnumConverter converter_;
 };
 
 TEST_P(SpvDimTest, Samples) {
-  const auto params = GetParam();
+    const auto params = GetParam();
 
-  const auto result = converter_.ToDim(params.dim, params.arrayed);
-  EXPECT_EQ(success_, params.expect_success);
-  if (params.expect_success) {
-    EXPECT_EQ(result, params.expected);
-    EXPECT_TRUE(error().empty());
-  } else {
-    EXPECT_EQ(result, params.expected);
-    EXPECT_THAT(error(), ::testing::HasSubstr("dimension"));
-  }
+    const auto result = converter_.ToDim(params.dim, params.arrayed);
+    EXPECT_EQ(success_, params.expect_success);
+    if (params.expect_success) {
+        EXPECT_EQ(result, params.expected);
+        EXPECT_TRUE(error().empty());
+    } else {
+        EXPECT_EQ(result, params.expected);
+        EXPECT_THAT(error(), ::testing::HasSubstr("dimension"));
+    }
 }
 
-INSTANTIATE_TEST_SUITE_P(
-    EnumConverterGood,
-    SpvDimTest,
-    testing::Values(
-        // Non-arrayed
-        DimCase{SpvDim1D, false, true, ast::TextureDimension::k1d},
-        DimCase{SpvDim2D, false, true, ast::TextureDimension::k2d},
-        DimCase{SpvDim3D, false, true, ast::TextureDimension::k3d},
-        DimCase{SpvDimCube, false, true, ast::TextureDimension::kCube},
-        // Arrayed
-        DimCase{SpvDim2D, true, true, ast::TextureDimension::k2dArray},
-        DimCase{SpvDimCube, true, true, ast::TextureDimension::kCubeArray}));
+INSTANTIATE_TEST_SUITE_P(EnumConverterGood,
+                         SpvDimTest,
+                         testing::Values(
+                             // Non-arrayed
+                             DimCase{SpvDim1D, false, true, ast::TextureDimension::k1d},
+                             DimCase{SpvDim2D, false, true, ast::TextureDimension::k2d},
+                             DimCase{SpvDim3D, false, true, ast::TextureDimension::k3d},
+                             DimCase{SpvDimCube, false, true, ast::TextureDimension::kCube},
+                             // Arrayed
+                             DimCase{SpvDim2D, true, true, ast::TextureDimension::k2dArray},
+                             DimCase{SpvDimCube, true, true, ast::TextureDimension::kCubeArray}));
 
-INSTANTIATE_TEST_SUITE_P(
-    EnumConverterBad,
-    SpvDimTest,
-    testing::Values(
-        // Invalid SPIR-V dimensionality.
-        DimCase{SpvDimMax, false, false, ast::TextureDimension::kNone},
-        DimCase{SpvDimMax, true, false, ast::TextureDimension::kNone},
-        // Vulkan non-arrayed dimensionalities not supported by WGSL.
-        DimCase{SpvDimRect, false, false, ast::TextureDimension::kNone},
-        DimCase{SpvDimBuffer, false, false, ast::TextureDimension::kNone},
-        DimCase{SpvDimSubpassData, false, false, ast::TextureDimension::kNone},
-        // Arrayed dimensionalities not supported by WGSL
-        DimCase{SpvDim3D, true, false, ast::TextureDimension::kNone},
-        DimCase{SpvDimRect, true, false, ast::TextureDimension::kNone},
-        DimCase{SpvDimBuffer, true, false, ast::TextureDimension::kNone},
-        DimCase{SpvDimSubpassData, true, false, ast::TextureDimension::kNone}));
+INSTANTIATE_TEST_SUITE_P(EnumConverterBad,
+                         SpvDimTest,
+                         testing::Values(
+                             // Invalid SPIR-V dimensionality.
+                             DimCase{SpvDimMax, false, false, ast::TextureDimension::kNone},
+                             DimCase{SpvDimMax, true, false, ast::TextureDimension::kNone},
+                             // Vulkan non-arrayed dimensionalities not supported by WGSL.
+                             DimCase{SpvDimRect, false, false, ast::TextureDimension::kNone},
+                             DimCase{SpvDimBuffer, false, false, ast::TextureDimension::kNone},
+                             DimCase{SpvDimSubpassData, false, false, ast::TextureDimension::kNone},
+                             // Arrayed dimensionalities not supported by WGSL
+                             DimCase{SpvDim3D, true, false, ast::TextureDimension::kNone},
+                             DimCase{SpvDimRect, true, false, ast::TextureDimension::kNone},
+                             DimCase{SpvDimBuffer, true, false, ast::TextureDimension::kNone},
+                             DimCase{SpvDimSubpassData, true, false,
+                                     ast::TextureDimension::kNone}));
 
 // TexelFormat
 
 struct TexelFormatCase {
-  SpvImageFormat format;
-  bool expect_success;
-  ast::TexelFormat expected;
+    SpvImageFormat format;
+    bool expect_success;
+    ast::TexelFormat expected;
 };
 inline std::ostream& operator<<(std::ostream& out, TexelFormatCase ifc) {
-  out << "TexelFormatCase{ SpvImageFormat:" << int(ifc.format)
-      << " expect_success?:" << int(ifc.expect_success)
-      << " expected:" << int(ifc.expected) << "}";
-  return out;
+    out << "TexelFormatCase{ SpvImageFormat:" << int(ifc.format)
+        << " expect_success?:" << int(ifc.expect_success) << " expected:" << int(ifc.expected)
+        << "}";
+    return out;
 }
 
 class SpvImageFormatTest : public testing::TestWithParam<TexelFormatCase> {
- public:
-  SpvImageFormatTest()
-      : success_(true),
-        fail_stream_(&success_, &errors_),
-        converter_(fail_stream_) {}
+  public:
+    SpvImageFormatTest()
+        : success_(true), fail_stream_(&success_, &errors_), converter_(fail_stream_) {}
 
-  std::string error() const { return errors_.str(); }
+    std::string error() const { return errors_.str(); }
 
- protected:
-  bool success_ = true;
-  std::stringstream errors_;
-  FailStream fail_stream_;
-  EnumConverter converter_;
+  protected:
+    bool success_ = true;
+    std::stringstream errors_;
+    FailStream fail_stream_;
+    EnumConverter converter_;
 };
 
 TEST_P(SpvImageFormatTest, Samples) {
-  const auto params = GetParam();
+    const auto params = GetParam();
 
-  const auto result = converter_.ToTexelFormat(params.format);
-  EXPECT_EQ(success_, params.expect_success) << params;
-  if (params.expect_success) {
-    EXPECT_EQ(result, params.expected);
-    EXPECT_TRUE(error().empty());
-  } else {
-    EXPECT_EQ(result, params.expected);
-    EXPECT_THAT(error(), ::testing::StartsWith("invalid image format: "));
-  }
+    const auto result = converter_.ToTexelFormat(params.format);
+    EXPECT_EQ(success_, params.expect_success) << params;
+    if (params.expect_success) {
+        EXPECT_EQ(result, params.expected);
+        EXPECT_TRUE(error().empty());
+    } else {
+        EXPECT_EQ(result, params.expected);
+        EXPECT_THAT(error(), ::testing::StartsWith("invalid image format: "));
+    }
 }
 
 INSTANTIATE_TEST_SUITE_P(
@@ -360,39 +328,27 @@
         // Unknown.  This is used for sampled images.
         TexelFormatCase{SpvImageFormatUnknown, true, ast::TexelFormat::kNone},
         // 8 bit channels
-        TexelFormatCase{SpvImageFormatRgba8, true,
-                        ast::TexelFormat::kRgba8Unorm},
-        TexelFormatCase{SpvImageFormatRgba8Snorm, true,
-                        ast::TexelFormat::kRgba8Snorm},
-        TexelFormatCase{SpvImageFormatRgba8ui, true,
-                        ast::TexelFormat::kRgba8Uint},
-        TexelFormatCase{SpvImageFormatRgba8i, true,
-                        ast::TexelFormat::kRgba8Sint},
+        TexelFormatCase{SpvImageFormatRgba8, true, ast::TexelFormat::kRgba8Unorm},
+        TexelFormatCase{SpvImageFormatRgba8Snorm, true, ast::TexelFormat::kRgba8Snorm},
+        TexelFormatCase{SpvImageFormatRgba8ui, true, ast::TexelFormat::kRgba8Uint},
+        TexelFormatCase{SpvImageFormatRgba8i, true, ast::TexelFormat::kRgba8Sint},
         // 16 bit channels
-        TexelFormatCase{SpvImageFormatRgba16ui, true,
-                        ast::TexelFormat::kRgba16Uint},
-        TexelFormatCase{SpvImageFormatRgba16i, true,
-                        ast::TexelFormat::kRgba16Sint},
-        TexelFormatCase{SpvImageFormatRgba16f, true,
-                        ast::TexelFormat::kRgba16Float},
+        TexelFormatCase{SpvImageFormatRgba16ui, true, ast::TexelFormat::kRgba16Uint},
+        TexelFormatCase{SpvImageFormatRgba16i, true, ast::TexelFormat::kRgba16Sint},
+        TexelFormatCase{SpvImageFormatRgba16f, true, ast::TexelFormat::kRgba16Float},
         // 32 bit channels
         // ... 1 channel
         TexelFormatCase{SpvImageFormatR32ui, true, ast::TexelFormat::kR32Uint},
         TexelFormatCase{SpvImageFormatR32i, true, ast::TexelFormat::kR32Sint},
         TexelFormatCase{SpvImageFormatR32f, true, ast::TexelFormat::kR32Float},
         // ... 2 channels
-        TexelFormatCase{SpvImageFormatRg32ui, true,
-                        ast::TexelFormat::kRg32Uint},
+        TexelFormatCase{SpvImageFormatRg32ui, true, ast::TexelFormat::kRg32Uint},
         TexelFormatCase{SpvImageFormatRg32i, true, ast::TexelFormat::kRg32Sint},
-        TexelFormatCase{SpvImageFormatRg32f, true,
-                        ast::TexelFormat::kRg32Float},
+        TexelFormatCase{SpvImageFormatRg32f, true, ast::TexelFormat::kRg32Float},
         // ... 4 channels
-        TexelFormatCase{SpvImageFormatRgba32ui, true,
-                        ast::TexelFormat::kRgba32Uint},
-        TexelFormatCase{SpvImageFormatRgba32i, true,
-                        ast::TexelFormat::kRgba32Sint},
-        TexelFormatCase{SpvImageFormatRgba32f, true,
-                        ast::TexelFormat::kRgba32Float}));
+        TexelFormatCase{SpvImageFormatRgba32ui, true, ast::TexelFormat::kRgba32Uint},
+        TexelFormatCase{SpvImageFormatRgba32i, true, ast::TexelFormat::kRgba32Sint},
+        TexelFormatCase{SpvImageFormatRgba32f, true, ast::TexelFormat::kRgba32Float}));
 
 INSTANTIATE_TEST_SUITE_P(
     EnumConverterBad,
@@ -400,24 +356,20 @@
     testing::Values(
         // Scanning in order from the SPIR-V spec.
         TexelFormatCase{SpvImageFormatRg16f, false, ast::TexelFormat::kNone},
-        TexelFormatCase{SpvImageFormatR11fG11fB10f, 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{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{SpvImageFormatRgb10a2ui, false, ast::TexelFormat::kNone},
         TexelFormatCase{SpvImageFormatRg16ui, false, ast::TexelFormat::kNone},
         TexelFormatCase{SpvImageFormatRg8ui, false, ast::TexelFormat::kNone}));
 
diff --git a/src/tint/reader/spirv/fail_stream.h b/src/tint/reader/spirv/fail_stream.h
index 6160de8..382fe5f 100644
--- a/src/tint/reader/spirv/fail_stream.h
+++ b/src/tint/reader/spirv/fail_stream.h
@@ -23,46 +23,45 @@
 /// and can be used to record failure by writing the false value
 /// to given a pointer-to-bool.
 class FailStream {
- public:
-  /// Creates a new fail stream
-  /// @param status_ptr where we will write false to indicate failure. Assumed
-  /// to be a valid pointer to bool.
-  /// @param out output stream where a message should be written to explain
-  /// the failure
-  FailStream(bool* status_ptr, std::ostream* out)
-      : status_ptr_(status_ptr), out_(out) {}
-  /// Copy constructor
-  /// @param other the fail stream to clone
-  FailStream(const FailStream& other) = default;
+  public:
+    /// Creates a new fail stream
+    /// @param status_ptr where we will write false to indicate failure. Assumed
+    /// to be a valid pointer to bool.
+    /// @param out output stream where a message should be written to explain
+    /// the failure
+    FailStream(bool* status_ptr, std::ostream* out) : status_ptr_(status_ptr), out_(out) {}
+    /// Copy constructor
+    /// @param other the fail stream to clone
+    FailStream(const FailStream& other) = default;
 
-  /// Converts to a boolean status. A true result indicates success,
-  /// and a false result indicates failure.
-  /// @returns the status
-  operator bool() const { return *status_ptr_; }
-  /// Returns the current status value.  This can be more readable
-  /// the conversion operator.
-  /// @returns the status
-  bool status() const { return *status_ptr_; }
+    /// Converts to a boolean status. A true result indicates success,
+    /// and a false result indicates failure.
+    /// @returns the status
+    operator bool() const { return *status_ptr_; }
+    /// Returns the current status value.  This can be more readable
+    /// the conversion operator.
+    /// @returns the status
+    bool status() const { return *status_ptr_; }
 
-  /// Records failure.
-  /// @returns a FailStream
-  FailStream& Fail() {
-    *status_ptr_ = false;
-    return *this;
-  }
+    /// Records failure.
+    /// @returns a FailStream
+    FailStream& Fail() {
+        *status_ptr_ = false;
+        return *this;
+    }
 
-  /// Appends the given value to the message output stream.
-  /// @param val the value to write to the output stream.
-  /// @returns this object
-  template <typename T>
-  FailStream& operator<<(const T& val) {
-    *out_ << val;
-    return *this;
-  }
+    /// Appends the given value to the message output stream.
+    /// @param val the value to write to the output stream.
+    /// @returns this object
+    template <typename T>
+    FailStream& operator<<(const T& val) {
+        *out_ << val;
+        return *this;
+    }
 
- private:
-  bool* status_ptr_;
-  std::ostream* out_;
+  private:
+    bool* status_ptr_;
+    std::ostream* out_;
 };
 
 }  // namespace tint::reader::spirv
diff --git a/src/tint/reader/spirv/fail_stream_test.cc b/src/tint/reader/spirv/fail_stream_test.cc
index 13c35e5..5b8701d 100644
--- a/src/tint/reader/spirv/fail_stream_test.cc
+++ b/src/tint/reader/spirv/fail_stream_test.cc
@@ -24,45 +24,45 @@
 using FailStreamTest = ::testing::Test;
 
 TEST_F(FailStreamTest, ConversionToBoolIsSameAsStatusMethod) {
-  bool flag = true;
-  FailStream fs(&flag, nullptr);
+    bool flag = true;
+    FailStream fs(&flag, nullptr);
 
-  EXPECT_TRUE(fs.status());
-  EXPECT_TRUE(bool(fs));  // NOLINT
-  flag = false;
-  EXPECT_FALSE(fs.status());
-  EXPECT_FALSE(bool(fs));  // NOLINT
-  flag = true;
-  EXPECT_TRUE(fs.status());
-  EXPECT_TRUE(bool(fs));  // NOLINT
+    EXPECT_TRUE(fs.status());
+    EXPECT_TRUE(bool(fs));  // NOLINT
+    flag = false;
+    EXPECT_FALSE(fs.status());
+    EXPECT_FALSE(bool(fs));  // NOLINT
+    flag = true;
+    EXPECT_TRUE(fs.status());
+    EXPECT_TRUE(bool(fs));  // NOLINT
 }
 
 TEST_F(FailStreamTest, FailMethodChangesStatusToFalse) {
-  bool flag = true;
-  FailStream fs(&flag, nullptr);
-  EXPECT_TRUE(flag);
-  EXPECT_TRUE(bool(fs));  // NOLINT
-  fs.Fail();
-  EXPECT_FALSE(flag);
-  EXPECT_FALSE(bool(fs));  // NOLINT
+    bool flag = true;
+    FailStream fs(&flag, nullptr);
+    EXPECT_TRUE(flag);
+    EXPECT_TRUE(bool(fs));  // NOLINT
+    fs.Fail();
+    EXPECT_FALSE(flag);
+    EXPECT_FALSE(bool(fs));  // NOLINT
 }
 
 TEST_F(FailStreamTest, FailMethodReturnsSelf) {
-  bool flag = true;
-  FailStream fs(&flag, nullptr);
-  FailStream& result = fs.Fail();
-  EXPECT_THAT(&result, Eq(&fs));
+    bool flag = true;
+    FailStream fs(&flag, nullptr);
+    FailStream& result = fs.Fail();
+    EXPECT_THAT(&result, Eq(&fs));
 }
 
 TEST_F(FailStreamTest, ShiftOperatorAccumulatesValues) {
-  bool flag = true;
-  std::stringstream ss;
-  FailStream fs(&flag, &ss);
+    bool flag = true;
+    std::stringstream ss;
+    FailStream fs(&flag, &ss);
 
-  ss << "prefix ";
-  fs << "cat " << 42;
+    ss << "prefix ";
+    fs << "cat " << 42;
 
-  EXPECT_THAT(ss.str(), Eq("prefix cat 42"));
+    EXPECT_THAT(ss.str(), Eq("prefix cat 42"));
 }
 
 }  // namespace
diff --git a/src/tint/reader/spirv/function.cc b/src/tint/reader/spirv/function.cc
index 43a3140..b416a6a 100644
--- a/src/tint/reader/spirv/function.cc
+++ b/src/tint/reader/spirv/function.cc
@@ -34,8 +34,8 @@
 #include "src/tint/ast/unary_op_expression.h"
 #include "src/tint/ast/variable_decl_statement.h"
 #include "src/tint/sem/builtin_type.h"
-#include "src/tint/sem/depth_texture_type.h"
-#include "src/tint/sem/sampled_texture_type.h"
+#include "src/tint/sem/depth_texture.h"
+#include "src/tint/sem/sampled_texture.h"
 
 // Terms:
 //    CFG: the control flow graph of the function, where basic blocks are the
@@ -148,111 +148,111 @@
 // @param ast_unary_op return parameter
 // @returns true if it was a unary operation
 bool GetUnaryOp(SpvOp opcode, ast::UnaryOp* ast_unary_op) {
-  switch (opcode) {
-    case SpvOpSNegate:
-    case SpvOpFNegate:
-      *ast_unary_op = ast::UnaryOp::kNegation;
-      return true;
-    case SpvOpLogicalNot:
-      *ast_unary_op = ast::UnaryOp::kNot;
-      return true;
-    case SpvOpNot:
-      *ast_unary_op = ast::UnaryOp::kComplement;
-      return true;
-    default:
-      break;
-  }
-  return false;
+    switch (opcode) {
+        case SpvOpSNegate:
+        case SpvOpFNegate:
+            *ast_unary_op = ast::UnaryOp::kNegation;
+            return true;
+        case SpvOpLogicalNot:
+            *ast_unary_op = ast::UnaryOp::kNot;
+            return true;
+        case SpvOpNot:
+            *ast_unary_op = ast::UnaryOp::kComplement;
+            return true;
+        default:
+            break;
+    }
+    return false;
 }
 
 /// Converts a SPIR-V opcode for a WGSL builtin function, if there is a
 /// direct translation. Returns nullptr otherwise.
 /// @returns the WGSL builtin function name for the given opcode, or nullptr.
 const char* GetUnaryBuiltInFunctionName(SpvOp opcode) {
-  switch (opcode) {
-    case SpvOpAny:
-      return "any";
-    case SpvOpAll:
-      return "all";
-    case SpvOpIsNan:
-      return "isNan";
-    case SpvOpIsInf:
-      return "isInf";
-    case SpvOpTranspose:
-      return "transpose";
-    default:
-      break;
-  }
-  return nullptr;
+    switch (opcode) {
+        case SpvOpAny:
+            return "any";
+        case SpvOpAll:
+            return "all";
+        case SpvOpIsNan:
+            return "isNan";
+        case SpvOpIsInf:
+            return "isInf";
+        case SpvOpTranspose:
+            return "transpose";
+        default:
+            break;
+    }
+    return nullptr;
 }
 
 // Converts a SPIR-V opcode to its corresponding AST binary opcode, if any
 // @param opcode SPIR-V opcode
 // @returns the AST binary op for the given opcode, or kNone
 ast::BinaryOp ConvertBinaryOp(SpvOp opcode) {
-  switch (opcode) {
-    case SpvOpIAdd:
-    case SpvOpFAdd:
-      return ast::BinaryOp::kAdd;
-    case SpvOpISub:
-    case SpvOpFSub:
-      return ast::BinaryOp::kSubtract;
-    case SpvOpIMul:
-    case SpvOpFMul:
-    case SpvOpVectorTimesScalar:
-    case SpvOpMatrixTimesScalar:
-    case SpvOpVectorTimesMatrix:
-    case SpvOpMatrixTimesVector:
-    case SpvOpMatrixTimesMatrix:
-      return ast::BinaryOp::kMultiply;
-    case SpvOpUDiv:
-    case SpvOpSDiv:
-    case SpvOpFDiv:
-      return ast::BinaryOp::kDivide;
-    case SpvOpUMod:
-    case SpvOpSMod:
-    case SpvOpFRem:
-      return ast::BinaryOp::kModulo;
-    case SpvOpLogicalEqual:
-    case SpvOpIEqual:
-    case SpvOpFOrdEqual:
-      return ast::BinaryOp::kEqual;
-    case SpvOpLogicalNotEqual:
-    case SpvOpINotEqual:
-    case SpvOpFOrdNotEqual:
-      return ast::BinaryOp::kNotEqual;
-    case SpvOpBitwiseAnd:
-      return ast::BinaryOp::kAnd;
-    case SpvOpBitwiseOr:
-      return ast::BinaryOp::kOr;
-    case SpvOpBitwiseXor:
-      return ast::BinaryOp::kXor;
-    case SpvOpLogicalAnd:
-      return ast::BinaryOp::kAnd;
-    case SpvOpLogicalOr:
-      return ast::BinaryOp::kOr;
-    case SpvOpUGreaterThan:
-    case SpvOpSGreaterThan:
-    case SpvOpFOrdGreaterThan:
-      return ast::BinaryOp::kGreaterThan;
-    case SpvOpUGreaterThanEqual:
-    case SpvOpSGreaterThanEqual:
-    case SpvOpFOrdGreaterThanEqual:
-      return ast::BinaryOp::kGreaterThanEqual;
-    case SpvOpULessThan:
-    case SpvOpSLessThan:
-    case SpvOpFOrdLessThan:
-      return ast::BinaryOp::kLessThan;
-    case SpvOpULessThanEqual:
-    case SpvOpSLessThanEqual:
-    case SpvOpFOrdLessThanEqual:
-      return ast::BinaryOp::kLessThanEqual;
-    default:
-      break;
-  }
-  // It's not clear what OpSMod should map to.
-  // https://bugs.chromium.org/p/tint/issues/detail?id=52
-  return ast::BinaryOp::kNone;
+    switch (opcode) {
+        case SpvOpIAdd:
+        case SpvOpFAdd:
+            return ast::BinaryOp::kAdd;
+        case SpvOpISub:
+        case SpvOpFSub:
+            return ast::BinaryOp::kSubtract;
+        case SpvOpIMul:
+        case SpvOpFMul:
+        case SpvOpVectorTimesScalar:
+        case SpvOpMatrixTimesScalar:
+        case SpvOpVectorTimesMatrix:
+        case SpvOpMatrixTimesVector:
+        case SpvOpMatrixTimesMatrix:
+            return ast::BinaryOp::kMultiply;
+        case SpvOpUDiv:
+        case SpvOpSDiv:
+        case SpvOpFDiv:
+            return ast::BinaryOp::kDivide;
+        case SpvOpUMod:
+        case SpvOpSMod:
+        case SpvOpFRem:
+            return ast::BinaryOp::kModulo;
+        case SpvOpLogicalEqual:
+        case SpvOpIEqual:
+        case SpvOpFOrdEqual:
+            return ast::BinaryOp::kEqual;
+        case SpvOpLogicalNotEqual:
+        case SpvOpINotEqual:
+        case SpvOpFOrdNotEqual:
+            return ast::BinaryOp::kNotEqual;
+        case SpvOpBitwiseAnd:
+            return ast::BinaryOp::kAnd;
+        case SpvOpBitwiseOr:
+            return ast::BinaryOp::kOr;
+        case SpvOpBitwiseXor:
+            return ast::BinaryOp::kXor;
+        case SpvOpLogicalAnd:
+            return ast::BinaryOp::kAnd;
+        case SpvOpLogicalOr:
+            return ast::BinaryOp::kOr;
+        case SpvOpUGreaterThan:
+        case SpvOpSGreaterThan:
+        case SpvOpFOrdGreaterThan:
+            return ast::BinaryOp::kGreaterThan;
+        case SpvOpUGreaterThanEqual:
+        case SpvOpSGreaterThanEqual:
+        case SpvOpFOrdGreaterThanEqual:
+            return ast::BinaryOp::kGreaterThanEqual;
+        case SpvOpULessThan:
+        case SpvOpSLessThan:
+        case SpvOpFOrdLessThan:
+            return ast::BinaryOp::kLessThan;
+        case SpvOpULessThanEqual:
+        case SpvOpSLessThanEqual:
+        case SpvOpFOrdLessThanEqual:
+            return ast::BinaryOp::kLessThanEqual;
+        default:
+            break;
+    }
+    // It's not clear what OpSMod should map to.
+    // https://bugs.chromium.org/p/tint/issues/detail?id=52
+    return ast::BinaryOp::kNone;
 }
 
 // If the given SPIR-V opcode is a floating point unordered comparison,
@@ -261,23 +261,23 @@
 // @param opcode SPIR-V opcode
 // @returns operation corresponding to negated version of the SPIR-V opcode
 ast::BinaryOp NegatedFloatCompare(SpvOp opcode) {
-  switch (opcode) {
-    case SpvOpFUnordEqual:
-      return ast::BinaryOp::kNotEqual;
-    case SpvOpFUnordNotEqual:
-      return ast::BinaryOp::kEqual;
-    case SpvOpFUnordLessThan:
-      return ast::BinaryOp::kGreaterThanEqual;
-    case SpvOpFUnordLessThanEqual:
-      return ast::BinaryOp::kGreaterThan;
-    case SpvOpFUnordGreaterThan:
-      return ast::BinaryOp::kLessThanEqual;
-    case SpvOpFUnordGreaterThanEqual:
-      return ast::BinaryOp::kLessThan;
-    default:
-      break;
-  }
-  return ast::BinaryOp::kNone;
+    switch (opcode) {
+        case SpvOpFUnordEqual:
+            return ast::BinaryOp::kNotEqual;
+        case SpvOpFUnordNotEqual:
+            return ast::BinaryOp::kEqual;
+        case SpvOpFUnordLessThan:
+            return ast::BinaryOp::kGreaterThanEqual;
+        case SpvOpFUnordLessThanEqual:
+            return ast::BinaryOp::kGreaterThan;
+        case SpvOpFUnordGreaterThan:
+            return ast::BinaryOp::kLessThanEqual;
+        case SpvOpFUnordGreaterThanEqual:
+            return ast::BinaryOp::kLessThan;
+        default:
+            break;
+    }
+    return ast::BinaryOp::kNone;
 }
 
 // Returns the WGSL standard library function for the given
@@ -285,286 +285,286 @@
 // and invalid opcodes map to the empty string.
 // @returns the WGSL standard function name, or an empty string.
 std::string GetGlslStd450FuncName(uint32_t ext_opcode) {
-  switch (ext_opcode) {
-    case GLSLstd450FAbs:
-    case GLSLstd450SAbs:
-      return "abs";
-    case GLSLstd450Acos:
-      return "acos";
-    case GLSLstd450Asin:
-      return "asin";
-    case GLSLstd450Atan:
-      return "atan";
-    case GLSLstd450Atan2:
-      return "atan2";
-    case GLSLstd450Ceil:
-      return "ceil";
-    case GLSLstd450UClamp:
-    case GLSLstd450SClamp:
-    case GLSLstd450NClamp:
-    case GLSLstd450FClamp:  // FClamp is less prescriptive about NaN operands
-      return "clamp";
-    case GLSLstd450Cos:
-      return "cos";
-    case GLSLstd450Cosh:
-      return "cosh";
-    case GLSLstd450Cross:
-      return "cross";
-    case GLSLstd450Degrees:
-      return "degrees";
-    case GLSLstd450Distance:
-      return "distance";
-    case GLSLstd450Exp:
-      return "exp";
-    case GLSLstd450Exp2:
-      return "exp2";
-    case GLSLstd450FaceForward:
-      return "faceForward";
-    case GLSLstd450Floor:
-      return "floor";
-    case GLSLstd450Fma:
-      return "fma";
-    case GLSLstd450Fract:
-      return "fract";
-    case GLSLstd450InverseSqrt:
-      return "inverseSqrt";
-    case GLSLstd450Ldexp:
-      return "ldexp";
-    case GLSLstd450Length:
-      return "length";
-    case GLSLstd450Log:
-      return "log";
-    case GLSLstd450Log2:
-      return "log2";
-    case GLSLstd450NMax:
-    case GLSLstd450FMax:  // FMax is less prescriptive about NaN operands
-    case GLSLstd450UMax:
-    case GLSLstd450SMax:
-      return "max";
-    case GLSLstd450NMin:
-    case GLSLstd450FMin:  // FMin is less prescriptive about NaN operands
-    case GLSLstd450UMin:
-    case GLSLstd450SMin:
-      return "min";
-    case GLSLstd450FMix:
-      return "mix";
-    case GLSLstd450Normalize:
-      return "normalize";
-    case GLSLstd450PackSnorm4x8:
-      return "pack4x8snorm";
-    case GLSLstd450PackUnorm4x8:
-      return "pack4x8unorm";
-    case GLSLstd450PackSnorm2x16:
-      return "pack2x16snorm";
-    case GLSLstd450PackUnorm2x16:
-      return "pack2x16unorm";
-    case GLSLstd450PackHalf2x16:
-      return "pack2x16float";
-    case GLSLstd450Pow:
-      return "pow";
-    case GLSLstd450FSign:
-      return "sign";
-    case GLSLstd450Radians:
-      return "radians";
-    case GLSLstd450Reflect:
-      return "reflect";
-    case GLSLstd450Refract:
-      return "refract";
-    case GLSLstd450Round:
-    case GLSLstd450RoundEven:
-      return "round";
-    case GLSLstd450Sin:
-      return "sin";
-    case GLSLstd450Sinh:
-      return "sinh";
-    case GLSLstd450SmoothStep:
-      return "smoothstep";
-    case GLSLstd450Sqrt:
-      return "sqrt";
-    case GLSLstd450Step:
-      return "step";
-    case GLSLstd450Tan:
-      return "tan";
-    case GLSLstd450Tanh:
-      return "tanh";
-    case GLSLstd450Trunc:
-      return "trunc";
-    case GLSLstd450UnpackSnorm4x8:
-      return "unpack4x8snorm";
-    case GLSLstd450UnpackUnorm4x8:
-      return "unpack4x8unorm";
-    case GLSLstd450UnpackSnorm2x16:
-      return "unpack2x16snorm";
-    case GLSLstd450UnpackUnorm2x16:
-      return "unpack2x16unorm";
-    case GLSLstd450UnpackHalf2x16:
-      return "unpack2x16float";
+    switch (ext_opcode) {
+        case GLSLstd450FAbs:
+        case GLSLstd450SAbs:
+            return "abs";
+        case GLSLstd450Acos:
+            return "acos";
+        case GLSLstd450Asin:
+            return "asin";
+        case GLSLstd450Atan:
+            return "atan";
+        case GLSLstd450Atan2:
+            return "atan2";
+        case GLSLstd450Ceil:
+            return "ceil";
+        case GLSLstd450UClamp:
+        case GLSLstd450SClamp:
+        case GLSLstd450NClamp:
+        case GLSLstd450FClamp:  // FClamp is less prescriptive about NaN operands
+            return "clamp";
+        case GLSLstd450Cos:
+            return "cos";
+        case GLSLstd450Cosh:
+            return "cosh";
+        case GLSLstd450Cross:
+            return "cross";
+        case GLSLstd450Degrees:
+            return "degrees";
+        case GLSLstd450Distance:
+            return "distance";
+        case GLSLstd450Exp:
+            return "exp";
+        case GLSLstd450Exp2:
+            return "exp2";
+        case GLSLstd450FaceForward:
+            return "faceForward";
+        case GLSLstd450Floor:
+            return "floor";
+        case GLSLstd450Fma:
+            return "fma";
+        case GLSLstd450Fract:
+            return "fract";
+        case GLSLstd450InverseSqrt:
+            return "inverseSqrt";
+        case GLSLstd450Ldexp:
+            return "ldexp";
+        case GLSLstd450Length:
+            return "length";
+        case GLSLstd450Log:
+            return "log";
+        case GLSLstd450Log2:
+            return "log2";
+        case GLSLstd450NMax:
+        case GLSLstd450FMax:  // FMax is less prescriptive about NaN operands
+        case GLSLstd450UMax:
+        case GLSLstd450SMax:
+            return "max";
+        case GLSLstd450NMin:
+        case GLSLstd450FMin:  // FMin is less prescriptive about NaN operands
+        case GLSLstd450UMin:
+        case GLSLstd450SMin:
+            return "min";
+        case GLSLstd450FMix:
+            return "mix";
+        case GLSLstd450Normalize:
+            return "normalize";
+        case GLSLstd450PackSnorm4x8:
+            return "pack4x8snorm";
+        case GLSLstd450PackUnorm4x8:
+            return "pack4x8unorm";
+        case GLSLstd450PackSnorm2x16:
+            return "pack2x16snorm";
+        case GLSLstd450PackUnorm2x16:
+            return "pack2x16unorm";
+        case GLSLstd450PackHalf2x16:
+            return "pack2x16float";
+        case GLSLstd450Pow:
+            return "pow";
+        case GLSLstd450FSign:
+            return "sign";
+        case GLSLstd450Radians:
+            return "radians";
+        case GLSLstd450Reflect:
+            return "reflect";
+        case GLSLstd450Refract:
+            return "refract";
+        case GLSLstd450Round:
+        case GLSLstd450RoundEven:
+            return "round";
+        case GLSLstd450Sin:
+            return "sin";
+        case GLSLstd450Sinh:
+            return "sinh";
+        case GLSLstd450SmoothStep:
+            return "smoothstep";
+        case GLSLstd450Sqrt:
+            return "sqrt";
+        case GLSLstd450Step:
+            return "step";
+        case GLSLstd450Tan:
+            return "tan";
+        case GLSLstd450Tanh:
+            return "tanh";
+        case GLSLstd450Trunc:
+            return "trunc";
+        case GLSLstd450UnpackSnorm4x8:
+            return "unpack4x8snorm";
+        case GLSLstd450UnpackUnorm4x8:
+            return "unpack4x8unorm";
+        case GLSLstd450UnpackSnorm2x16:
+            return "unpack2x16snorm";
+        case GLSLstd450UnpackUnorm2x16:
+            return "unpack2x16unorm";
+        case GLSLstd450UnpackHalf2x16:
+            return "unpack2x16float";
 
-    default:
-      // TODO(dneto) - The following are not implemented.
-      // They are grouped semantically, as in GLSL.std.450.h.
+        default:
+            // TODO(dneto) - The following are not implemented.
+            // They are grouped semantically, as in GLSL.std.450.h.
 
-    case GLSLstd450SSign:
+        case GLSLstd450SSign:
 
-    case GLSLstd450Asinh:
-    case GLSLstd450Acosh:
-    case GLSLstd450Atanh:
+        case GLSLstd450Asinh:
+        case GLSLstd450Acosh:
+        case GLSLstd450Atanh:
 
-    case GLSLstd450Determinant:
-    case GLSLstd450MatrixInverse:
+        case GLSLstd450Determinant:
+        case GLSLstd450MatrixInverse:
 
-    case GLSLstd450Modf:
-    case GLSLstd450ModfStruct:
-    case GLSLstd450IMix:
+        case GLSLstd450Modf:
+        case GLSLstd450ModfStruct:
+        case GLSLstd450IMix:
 
-    case GLSLstd450Frexp:
-    case GLSLstd450FrexpStruct:
+        case GLSLstd450Frexp:
+        case GLSLstd450FrexpStruct:
 
-    case GLSLstd450PackDouble2x32:
-    case GLSLstd450UnpackDouble2x32:
+        case GLSLstd450PackDouble2x32:
+        case GLSLstd450UnpackDouble2x32:
 
-    case GLSLstd450FindILsb:
-    case GLSLstd450FindSMsb:
-    case GLSLstd450FindUMsb:
+        case GLSLstd450FindILsb:
+        case GLSLstd450FindSMsb:
+        case GLSLstd450FindUMsb:
 
-    case GLSLstd450InterpolateAtCentroid:
-    case GLSLstd450InterpolateAtSample:
-    case GLSLstd450InterpolateAtOffset:
-      break;
-  }
-  return "";
+        case GLSLstd450InterpolateAtCentroid:
+        case GLSLstd450InterpolateAtSample:
+        case GLSLstd450InterpolateAtOffset:
+            break;
+    }
+    return "";
 }
 
 // Returns the WGSL standard library function builtin for the
 // given instruction, or sem::BuiltinType::kNone
 sem::BuiltinType GetBuiltin(SpvOp opcode) {
-  switch (opcode) {
-    case SpvOpBitCount:
-      return sem::BuiltinType::kCountOneBits;
-    case SpvOpBitFieldInsert:
-      return sem::BuiltinType::kInsertBits;
-    case SpvOpBitFieldSExtract:
-    case SpvOpBitFieldUExtract:
-      return sem::BuiltinType::kExtractBits;
-    case SpvOpBitReverse:
-      return sem::BuiltinType::kReverseBits;
-    case SpvOpDot:
-      return sem::BuiltinType::kDot;
-    case SpvOpDPdx:
-      return sem::BuiltinType::kDpdx;
-    case SpvOpDPdy:
-      return sem::BuiltinType::kDpdy;
-    case SpvOpFwidth:
-      return sem::BuiltinType::kFwidth;
-    case SpvOpDPdxFine:
-      return sem::BuiltinType::kDpdxFine;
-    case SpvOpDPdyFine:
-      return sem::BuiltinType::kDpdyFine;
-    case SpvOpFwidthFine:
-      return sem::BuiltinType::kFwidthFine;
-    case SpvOpDPdxCoarse:
-      return sem::BuiltinType::kDpdxCoarse;
-    case SpvOpDPdyCoarse:
-      return sem::BuiltinType::kDpdyCoarse;
-    case SpvOpFwidthCoarse:
-      return sem::BuiltinType::kFwidthCoarse;
-    default:
-      break;
-  }
-  return sem::BuiltinType::kNone;
+    switch (opcode) {
+        case SpvOpBitCount:
+            return sem::BuiltinType::kCountOneBits;
+        case SpvOpBitFieldInsert:
+            return sem::BuiltinType::kInsertBits;
+        case SpvOpBitFieldSExtract:
+        case SpvOpBitFieldUExtract:
+            return sem::BuiltinType::kExtractBits;
+        case SpvOpBitReverse:
+            return sem::BuiltinType::kReverseBits;
+        case SpvOpDot:
+            return sem::BuiltinType::kDot;
+        case SpvOpDPdx:
+            return sem::BuiltinType::kDpdx;
+        case SpvOpDPdy:
+            return sem::BuiltinType::kDpdy;
+        case SpvOpFwidth:
+            return sem::BuiltinType::kFwidth;
+        case SpvOpDPdxFine:
+            return sem::BuiltinType::kDpdxFine;
+        case SpvOpDPdyFine:
+            return sem::BuiltinType::kDpdyFine;
+        case SpvOpFwidthFine:
+            return sem::BuiltinType::kFwidthFine;
+        case SpvOpDPdxCoarse:
+            return sem::BuiltinType::kDpdxCoarse;
+        case SpvOpDPdyCoarse:
+            return sem::BuiltinType::kDpdyCoarse;
+        case SpvOpFwidthCoarse:
+            return sem::BuiltinType::kFwidthCoarse;
+        default:
+            break;
+    }
+    return sem::BuiltinType::kNone;
 }
 
 // @param opcode a SPIR-V opcode
 // @returns true if the given instruction is an image access instruction
 // whose first input operand is an OpSampledImage value.
 bool IsSampledImageAccess(SpvOp opcode) {
-  switch (opcode) {
-    case SpvOpImageSampleImplicitLod:
-    case SpvOpImageSampleExplicitLod:
-    case SpvOpImageSampleDrefImplicitLod:
-    case SpvOpImageSampleDrefExplicitLod:
-    // WGSL doesn't have *Proj* texturing; spirv reader emulates it.
-    case SpvOpImageSampleProjImplicitLod:
-    case SpvOpImageSampleProjExplicitLod:
-    case SpvOpImageSampleProjDrefImplicitLod:
-    case SpvOpImageSampleProjDrefExplicitLod:
-    case SpvOpImageGather:
-    case SpvOpImageDrefGather:
-    case SpvOpImageQueryLod:
-      return true;
-    default:
-      break;
-  }
-  return false;
+    switch (opcode) {
+        case SpvOpImageSampleImplicitLod:
+        case SpvOpImageSampleExplicitLod:
+        case SpvOpImageSampleDrefImplicitLod:
+        case SpvOpImageSampleDrefExplicitLod:
+        // WGSL doesn't have *Proj* texturing; spirv reader emulates it.
+        case SpvOpImageSampleProjImplicitLod:
+        case SpvOpImageSampleProjExplicitLod:
+        case SpvOpImageSampleProjDrefImplicitLod:
+        case SpvOpImageSampleProjDrefExplicitLod:
+        case SpvOpImageGather:
+        case SpvOpImageDrefGather:
+        case SpvOpImageQueryLod:
+            return true;
+        default:
+            break;
+    }
+    return false;
 }
 
 // @param opcode a SPIR-V opcode
 // @returns true if the given instruction is an image sampling, gather,
 // or gather-compare operation.
 bool IsImageSamplingOrGatherOrDrefGather(SpvOp opcode) {
-  switch (opcode) {
-    case SpvOpImageSampleImplicitLod:
-    case SpvOpImageSampleExplicitLod:
-    case SpvOpImageSampleDrefImplicitLod:
-    case SpvOpImageSampleDrefExplicitLod:
-      // WGSL doesn't have *Proj* texturing; spirv reader emulates it.
-    case SpvOpImageSampleProjImplicitLod:
-    case SpvOpImageSampleProjExplicitLod:
-    case SpvOpImageSampleProjDrefImplicitLod:
-    case SpvOpImageSampleProjDrefExplicitLod:
-    case SpvOpImageGather:
-    case SpvOpImageDrefGather:
-      return true;
-    default:
-      break;
-  }
-  return false;
+    switch (opcode) {
+        case SpvOpImageSampleImplicitLod:
+        case SpvOpImageSampleExplicitLod:
+        case SpvOpImageSampleDrefImplicitLod:
+        case SpvOpImageSampleDrefExplicitLod:
+            // WGSL doesn't have *Proj* texturing; spirv reader emulates it.
+        case SpvOpImageSampleProjImplicitLod:
+        case SpvOpImageSampleProjExplicitLod:
+        case SpvOpImageSampleProjDrefImplicitLod:
+        case SpvOpImageSampleProjDrefExplicitLod:
+        case SpvOpImageGather:
+        case SpvOpImageDrefGather:
+            return true;
+        default:
+            break;
+    }
+    return false;
 }
 
 // @param opcode a SPIR-V opcode
 // @returns true if the given instruction is an image access instruction
 // whose first input operand is an OpImage value.
 bool IsRawImageAccess(SpvOp opcode) {
-  switch (opcode) {
-    case SpvOpImageRead:
-    case SpvOpImageWrite:
-    case SpvOpImageFetch:
-      return true;
-    default:
-      break;
-  }
-  return false;
+    switch (opcode) {
+        case SpvOpImageRead:
+        case SpvOpImageWrite:
+        case SpvOpImageFetch:
+            return true;
+        default:
+            break;
+    }
+    return false;
 }
 
 // @param opcode a SPIR-V opcode
 // @returns true if the given instruction is an image query instruction
 bool IsImageQuery(SpvOp opcode) {
-  switch (opcode) {
-    case SpvOpImageQuerySize:
-    case SpvOpImageQuerySizeLod:
-    case SpvOpImageQueryLevels:
-    case SpvOpImageQuerySamples:
-    case SpvOpImageQueryLod:
-      return true;
-    default:
-      break;
-  }
-  return false;
+    switch (opcode) {
+        case SpvOpImageQuerySize:
+        case SpvOpImageQuerySizeLod:
+        case SpvOpImageQueryLevels:
+        case SpvOpImageQuerySamples:
+        case SpvOpImageQueryLod:
+            return true;
+        default:
+            break;
+    }
+    return false;
 }
 
 // @returns the merge block ID for the given basic block, or 0 if there is none.
 uint32_t MergeFor(const spvtools::opt::BasicBlock& bb) {
-  // Get the OpSelectionMerge or OpLoopMerge instruction, if any.
-  auto* inst = bb.GetMergeInst();
-  return inst == nullptr ? 0 : inst->GetSingleWordInOperand(0);
+    // Get the OpSelectionMerge or OpLoopMerge instruction, if any.
+    auto* inst = bb.GetMergeInst();
+    return inst == nullptr ? 0 : inst->GetSingleWordInOperand(0);
 }
 
 // @returns the continue target ID for the given basic block, or 0 if there
 // is none.
 uint32_t ContinueTargetFor(const spvtools::opt::BasicBlock& bb) {
-  // Get the OpLoopMerge instruction, if any.
-  auto* inst = bb.GetLoopMergeInst();
-  return inst == nullptr ? 0 : inst->GetSingleWordInOperand(1);
+    // Get the OpLoopMerge instruction, if any.
+    auto* inst = bb.GetLoopMergeInst();
+    return inst == nullptr ? 0 : inst->GetSingleWordInOperand(1);
 }
 
 // A structured traverser produces the reverse structured post-order of the
@@ -575,157 +575,148 @@
 //  - a block mentioned as a merge block or continue target for a block in the
 //  set
 class StructuredTraverser {
- public:
-  explicit StructuredTraverser(const spvtools::opt::Function& function)
-      : function_(function) {
-    for (auto& block : function_) {
-      id_to_block_[block.id()] = &block;
-    }
-  }
-
-  // Returns the reverse postorder traversal of the CFG, where:
-  //  - a merge block always follows its associated constructs
-  //  - a continue target always follows the associated loop construct, if any
-  // @returns the IDs of blocks in reverse structured post order
-  std::vector<uint32_t> ReverseStructuredPostOrder() {
-    visit_order_.clear();
-    visited_.clear();
-    VisitBackward(function_.entry()->id());
-
-    std::vector<uint32_t> order(visit_order_.rbegin(), visit_order_.rend());
-    return order;
-  }
-
- private:
-  // Executes a depth first search of the CFG, where right after we visit a
-  // header, we will visit its merge block, then its continue target (if any).
-  // Also records the post order ordering.
-  void VisitBackward(uint32_t id) {
-    if (id == 0)
-      return;
-    if (visited_.count(id))
-      return;
-    visited_.insert(id);
-
-    const spvtools::opt::BasicBlock* bb =
-        id_to_block_[id];  // non-null for valid modules
-    VisitBackward(MergeFor(*bb));
-    VisitBackward(ContinueTargetFor(*bb));
-
-    // Visit successors. We will naturally skip the continue target and merge
-    // blocks.
-    auto* terminator = bb->terminator();
-    auto opcode = terminator->opcode();
-    if (opcode == SpvOpBranchConditional) {
-      // Visit the false branch, then the true branch, to make them come
-      // out in the natural order for an "if".
-      VisitBackward(terminator->GetSingleWordInOperand(2));
-      VisitBackward(terminator->GetSingleWordInOperand(1));
-    } else if (opcode == SpvOpBranch) {
-      VisitBackward(terminator->GetSingleWordInOperand(0));
-    } else if (opcode == SpvOpSwitch) {
-      // TODO(dneto): Consider visiting the labels in literal-value order.
-      std::vector<uint32_t> successors;
-      bb->ForEachSuccessorLabel([&successors](const uint32_t succ_id) {
-        successors.push_back(succ_id);
-      });
-      for (auto succ_id : successors) {
-        VisitBackward(succ_id);
-      }
+  public:
+    explicit StructuredTraverser(const spvtools::opt::Function& function) : function_(function) {
+        for (auto& block : function_) {
+            id_to_block_[block.id()] = &block;
+        }
     }
 
-    visit_order_.push_back(id);
-  }
+    // Returns the reverse postorder traversal of the CFG, where:
+    //  - a merge block always follows its associated constructs
+    //  - a continue target always follows the associated loop construct, if any
+    // @returns the IDs of blocks in reverse structured post order
+    std::vector<uint32_t> ReverseStructuredPostOrder() {
+        visit_order_.clear();
+        visited_.clear();
+        VisitBackward(function_.entry()->id());
 
-  const spvtools::opt::Function& function_;
-  std::unordered_map<uint32_t, const spvtools::opt::BasicBlock*> id_to_block_;
-  std::vector<uint32_t> visit_order_;
-  std::unordered_set<uint32_t> visited_;
+        std::vector<uint32_t> order(visit_order_.rbegin(), visit_order_.rend());
+        return order;
+    }
+
+  private:
+    // Executes a depth first search of the CFG, where right after we visit a
+    // header, we will visit its merge block, then its continue target (if any).
+    // Also records the post order ordering.
+    void VisitBackward(uint32_t id) {
+        if (id == 0)
+            return;
+        if (visited_.count(id))
+            return;
+        visited_.insert(id);
+
+        const spvtools::opt::BasicBlock* bb = id_to_block_[id];  // non-null for valid modules
+        VisitBackward(MergeFor(*bb));
+        VisitBackward(ContinueTargetFor(*bb));
+
+        // Visit successors. We will naturally skip the continue target and merge
+        // blocks.
+        auto* terminator = bb->terminator();
+        auto opcode = terminator->opcode();
+        if (opcode == SpvOpBranchConditional) {
+            // Visit the false branch, then the true branch, to make them come
+            // out in the natural order for an "if".
+            VisitBackward(terminator->GetSingleWordInOperand(2));
+            VisitBackward(terminator->GetSingleWordInOperand(1));
+        } else if (opcode == SpvOpBranch) {
+            VisitBackward(terminator->GetSingleWordInOperand(0));
+        } else if (opcode == SpvOpSwitch) {
+            // TODO(dneto): Consider visiting the labels in literal-value order.
+            std::vector<uint32_t> successors;
+            bb->ForEachSuccessorLabel(
+                [&successors](const uint32_t succ_id) { successors.push_back(succ_id); });
+            for (auto succ_id : successors) {
+                VisitBackward(succ_id);
+            }
+        }
+
+        visit_order_.push_back(id);
+    }
+
+    const spvtools::opt::Function& function_;
+    std::unordered_map<uint32_t, const spvtools::opt::BasicBlock*> id_to_block_;
+    std::vector<uint32_t> visit_order_;
+    std::unordered_set<uint32_t> visited_;
 };
 
 /// A StatementBuilder for ast::SwitchStatement
 /// @see StatementBuilder
-struct SwitchStatementBuilder final
-    : public Castable<SwitchStatementBuilder, StatementBuilder> {
-  /// Constructor
-  /// @param cond the switch statement condition
-  explicit SwitchStatementBuilder(const ast::Expression* cond)
-      : condition(cond) {}
+struct SwitchStatementBuilder final : public Castable<SwitchStatementBuilder, StatementBuilder> {
+    /// Constructor
+    /// @param cond the switch statement condition
+    explicit SwitchStatementBuilder(const ast::Expression* cond) : condition(cond) {}
 
-  /// @param builder the program builder
-  /// @returns the built ast::SwitchStatement
-  const ast::SwitchStatement* Build(ProgramBuilder* builder) const override {
-    // We've listed cases in reverse order in the switch statement.
-    // Reorder them to match the presentation order in WGSL.
-    auto reversed_cases = cases;
-    std::reverse(reversed_cases.begin(), reversed_cases.end());
+    /// @param builder the program builder
+    /// @returns the built ast::SwitchStatement
+    const ast::SwitchStatement* Build(ProgramBuilder* builder) const override {
+        // We've listed cases in reverse order in the switch statement.
+        // Reorder them to match the presentation order in WGSL.
+        auto reversed_cases = cases;
+        std::reverse(reversed_cases.begin(), reversed_cases.end());
 
-    return builder->create<ast::SwitchStatement>(Source{}, condition,
-                                                 reversed_cases);
-  }
+        return builder->create<ast::SwitchStatement>(Source{}, condition, reversed_cases);
+    }
 
-  /// Switch statement condition
-  const ast::Expression* const condition;
-  /// Switch statement cases
-  ast::CaseStatementList cases;
+    /// Switch statement condition
+    const ast::Expression* const condition;
+    /// Switch statement cases
+    ast::CaseStatementList cases;
 };
 
 /// A StatementBuilder for ast::IfStatement
 /// @see StatementBuilder
-struct IfStatementBuilder final
-    : public Castable<IfStatementBuilder, StatementBuilder> {
-  /// Constructor
-  /// @param c the if-statement condition
-  explicit IfStatementBuilder(const ast::Expression* c) : cond(c) {}
+struct IfStatementBuilder final : public Castable<IfStatementBuilder, StatementBuilder> {
+    /// Constructor
+    /// @param c the if-statement condition
+    explicit IfStatementBuilder(const ast::Expression* c) : cond(c) {}
 
-  /// @param builder the program builder
-  /// @returns the built ast::IfStatement
-  const ast::IfStatement* Build(ProgramBuilder* builder) const override {
-    return builder->create<ast::IfStatement>(Source{}, cond, body, else_stmts);
-  }
+    /// @param builder the program builder
+    /// @returns the built ast::IfStatement
+    const ast::IfStatement* Build(ProgramBuilder* builder) const override {
+        return builder->create<ast::IfStatement>(Source{}, cond, body, else_stmt);
+    }
 
-  /// If-statement condition
-  const ast::Expression* const cond;
-  /// If-statement block body
-  const ast::BlockStatement* body = nullptr;
-  /// Optional if-statement else statements
-  ast::ElseStatementList else_stmts;
+    /// If-statement condition
+    const ast::Expression* const cond;
+    /// If-statement block body
+    const ast::BlockStatement* body = nullptr;
+    /// Optional if-statement else statement
+    const ast::Statement* else_stmt = nullptr;
 };
 
 /// A StatementBuilder for ast::LoopStatement
 /// @see StatementBuilder
-struct LoopStatementBuilder final
-    : public Castable<LoopStatementBuilder, StatementBuilder> {
-  /// @param builder the program builder
-  /// @returns the built ast::LoopStatement
-  ast::LoopStatement* Build(ProgramBuilder* builder) const override {
-    return builder->create<ast::LoopStatement>(Source{}, body, continuing);
-  }
+struct LoopStatementBuilder final : public Castable<LoopStatementBuilder, StatementBuilder> {
+    /// @param builder the program builder
+    /// @returns the built ast::LoopStatement
+    ast::LoopStatement* Build(ProgramBuilder* builder) const override {
+        return builder->create<ast::LoopStatement>(Source{}, body, continuing);
+    }
 
-  /// Loop-statement block body
-  const ast::BlockStatement* body = nullptr;
-  /// Loop-statement continuing body
-  /// @note the mutable keyword here is required as all non-StatementBuilders
-  /// `ast::Node`s are immutable and are referenced with `const` pointers.
-  /// StatementBuilders however exist to provide mutable state while the
-  /// FunctionEmitter is building the function. All StatementBuilders are
-  /// replaced with immutable AST nodes when Finalize() is called.
-  mutable const ast::BlockStatement* continuing = nullptr;
+    /// Loop-statement block body
+    const ast::BlockStatement* body = nullptr;
+    /// Loop-statement continuing body
+    /// @note the mutable keyword here is required as all non-StatementBuilders
+    /// `ast::Node`s are immutable and are referenced with `const` pointers.
+    /// StatementBuilders however exist to provide mutable state while the
+    /// FunctionEmitter is building the function. All StatementBuilders are
+    /// replaced with immutable AST nodes when Finalize() is called.
+    mutable const ast::BlockStatement* continuing = nullptr;
 };
 
 /// @param decos a list of parsed decorations
 /// @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 false;
+    if (auto* builtin = ast::GetAttribute<ast::BuiltinAttribute>(decos)) {
+        return builtin->builtin == ast::Builtin::kSampleMask;
+    }
+    return false;
 }
 
 }  // namespace
 
-BlockInfo::BlockInfo(const spvtools::opt::BasicBlock& bb)
-    : basic_block(&bb), id(bb.id()) {}
+BlockInfo::BlockInfo(const spvtools::opt::BasicBlock& bb) : basic_block(&bb), id(bb.id()) {}
 
 BlockInfo::~BlockInfo() = default;
 
@@ -737,7 +728,7 @@
 DefInfo::~DefInfo() = default;
 
 ast::Node* StatementBuilder::Clone(CloneContext*) const {
-  return nullptr;
+    return nullptr;
 }
 
 FunctionEmitter::FunctionEmitter(ParserImpl* pi,
@@ -756,11 +747,10 @@
       sample_mask_in_id(0u),
       sample_mask_out_id(0u),
       ep_info_(ep_info) {
-  PushNewStatementBlock(nullptr, 0, nullptr);
+    PushNewStatementBlock(nullptr, 0, nullptr);
 }
 
-FunctionEmitter::FunctionEmitter(ParserImpl* pi,
-                                 const spvtools::opt::Function& function)
+FunctionEmitter::FunctionEmitter(ParserImpl* pi, const spvtools::opt::Function& function)
     : FunctionEmitter(pi, function, nullptr) {}
 
 FunctionEmitter::FunctionEmitter(FunctionEmitter&& other)
@@ -777,181 +767,172 @@
       sample_mask_in_id(other.sample_mask_out_id),
       sample_mask_out_id(other.sample_mask_in_id),
       ep_info_(other.ep_info_) {
-  other.statements_stack_.clear();
-  PushNewStatementBlock(nullptr, 0, nullptr);
+    other.statements_stack_.clear();
+    PushNewStatementBlock(nullptr, 0, nullptr);
 }
 
 FunctionEmitter::~FunctionEmitter() = default;
 
-FunctionEmitter::StatementBlock::StatementBlock(
-    const Construct* construct,
-    uint32_t end_id,
-    FunctionEmitter::CompletionAction completion_action)
-    : construct_(construct),
-      end_id_(end_id),
-      completion_action_(completion_action) {}
+FunctionEmitter::StatementBlock::StatementBlock(const Construct* construct,
+                                                uint32_t end_id,
+                                                FunctionEmitter::CompletionAction completion_action)
+    : construct_(construct), end_id_(end_id), completion_action_(completion_action) {}
 
-FunctionEmitter::StatementBlock::StatementBlock(StatementBlock&& other) =
-    default;
+FunctionEmitter::StatementBlock::StatementBlock(StatementBlock&& other) = default;
 
 FunctionEmitter::StatementBlock::~StatementBlock() = default;
 
 void FunctionEmitter::StatementBlock::Finalize(ProgramBuilder* pb) {
-  TINT_ASSERT(Reader, !finalized_ /* Finalize() must only be called once */);
+    TINT_ASSERT(Reader, !finalized_ /* Finalize() must only be called once */);
 
-  for (size_t i = 0; i < statements_.size(); i++) {
-    if (auto* sb = statements_[i]->As<StatementBuilder>()) {
-      statements_[i] = sb->Build(pb);
+    for (size_t i = 0; i < statements_.size(); i++) {
+        if (auto* sb = statements_[i]->As<StatementBuilder>()) {
+            statements_[i] = sb->Build(pb);
+        }
     }
-  }
 
-  if (completion_action_ != nullptr) {
-    completion_action_(statements_);
-  }
+    if (completion_action_ != nullptr) {
+        completion_action_(statements_);
+    }
 
-  finalized_ = true;
+    finalized_ = true;
 }
 
 void FunctionEmitter::StatementBlock::Add(const ast::Statement* statement) {
-  TINT_ASSERT(Reader,
-              !finalized_ /* Add() must not be called after Finalize() */);
-  statements_.emplace_back(statement);
+    TINT_ASSERT(Reader, !finalized_ /* Add() must not be called after Finalize() */);
+    statements_.emplace_back(statement);
 }
 
 void FunctionEmitter::PushNewStatementBlock(const Construct* construct,
                                             uint32_t end_id,
                                             CompletionAction action) {
-  statements_stack_.emplace_back(StatementBlock{construct, end_id, action});
+    statements_stack_.emplace_back(StatementBlock{construct, end_id, action});
 }
 
-void FunctionEmitter::PushGuard(const std::string& guard_name,
-                                uint32_t end_id) {
-  TINT_ASSERT(Reader, !statements_stack_.empty());
-  TINT_ASSERT(Reader, !guard_name.empty());
-  // Guard control flow by the guard variable.  Introduce a new
-  // if-selection with a then-clause ending at the same block
-  // as the statement block at the top of the stack.
-  const auto& top = statements_stack_.back();
+void FunctionEmitter::PushGuard(const std::string& guard_name, uint32_t end_id) {
+    TINT_ASSERT(Reader, !statements_stack_.empty());
+    TINT_ASSERT(Reader, !guard_name.empty());
+    // Guard control flow by the guard variable.  Introduce a new
+    // if-selection with a then-clause ending at the same block
+    // as the statement block at the top of the stack.
+    const auto& top = statements_stack_.back();
 
-  auto* cond = create<ast::IdentifierExpression>(
-      Source{}, builder_.Symbols().Register(guard_name));
-  auto* builder = AddStatementBuilder<IfStatementBuilder>(cond);
+    auto* cond =
+        create<ast::IdentifierExpression>(Source{}, builder_.Symbols().Register(guard_name));
+    auto* builder = AddStatementBuilder<IfStatementBuilder>(cond);
 
-  PushNewStatementBlock(
-      top.GetConstruct(), end_id, [=](const ast::StatementList& stmts) {
+    PushNewStatementBlock(top.GetConstruct(), end_id, [=](const ast::StatementList& stmts) {
         builder->body = create<ast::BlockStatement>(Source{}, stmts);
-      });
+    });
 }
 
 void FunctionEmitter::PushTrueGuard(uint32_t end_id) {
-  TINT_ASSERT(Reader, !statements_stack_.empty());
-  const auto& top = statements_stack_.back();
+    TINT_ASSERT(Reader, !statements_stack_.empty());
+    const auto& top = statements_stack_.back();
 
-  auto* cond = MakeTrue(Source{});
-  auto* builder = AddStatementBuilder<IfStatementBuilder>(cond);
+    auto* cond = MakeTrue(Source{});
+    auto* builder = AddStatementBuilder<IfStatementBuilder>(cond);
 
-  PushNewStatementBlock(
-      top.GetConstruct(), end_id, [=](const ast::StatementList& stmts) {
+    PushNewStatementBlock(top.GetConstruct(), end_id, [=](const ast::StatementList& stmts) {
         builder->body = create<ast::BlockStatement>(Source{}, stmts);
-      });
+    });
 }
 
 const ast::StatementList FunctionEmitter::ast_body() {
-  TINT_ASSERT(Reader, !statements_stack_.empty());
-  auto& entry = statements_stack_[0];
-  entry.Finalize(&builder_);
-  return entry.GetStatements();
+    TINT_ASSERT(Reader, !statements_stack_.empty());
+    auto& entry = statements_stack_[0];
+    entry.Finalize(&builder_);
+    return entry.GetStatements();
 }
 
-const ast::Statement* FunctionEmitter::AddStatement(
-    const ast::Statement* statement) {
-  TINT_ASSERT(Reader, !statements_stack_.empty());
-  if (statement != nullptr) {
-    statements_stack_.back().Add(statement);
-  }
-  return statement;
+const ast::Statement* FunctionEmitter::AddStatement(const ast::Statement* statement) {
+    TINT_ASSERT(Reader, !statements_stack_.empty());
+    if (statement != nullptr) {
+        statements_stack_.back().Add(statement);
+    }
+    return statement;
 }
 
 const ast::Statement* FunctionEmitter::LastStatement() {
-  TINT_ASSERT(Reader, !statements_stack_.empty());
-  auto& statement_list = statements_stack_.back().GetStatements();
-  TINT_ASSERT(Reader, !statement_list.empty());
-  return statement_list.back();
+    TINT_ASSERT(Reader, !statements_stack_.empty());
+    auto& statement_list = statements_stack_.back().GetStatements();
+    TINT_ASSERT(Reader, !statement_list.empty());
+    return statement_list.back();
 }
 
 bool FunctionEmitter::Emit() {
-  if (failed()) {
-    return false;
-  }
-  // We only care about functions with bodies.
-  if (function_.cbegin() == function_.cend()) {
-    return true;
-  }
-
-  // The function declaration, corresponding to how it's written in SPIR-V,
-  // and without regard to whether it's an entry point.
-  FunctionDeclaration decl;
-  if (!ParseFunctionDeclaration(&decl)) {
-    return false;
-  }
-
-  bool make_body_function = true;
-  if (ep_info_) {
-    TINT_ASSERT(Reader, !ep_info_->inner_name.empty());
-    if (ep_info_->owns_inner_implementation) {
-      // This is an entry point, and we want to emit it as a wrapper around
-      // an implementation function.
-      decl.name = ep_info_->inner_name;
-    } else {
-      // This is a second entry point that shares an inner implementation
-      // function.
-      make_body_function = false;
+    if (failed()) {
+        return false;
     }
-  }
-
-  if (make_body_function) {
-    auto* body = MakeFunctionBody();
-    if (!body) {
-      return false;
+    // We only care about functions with bodies.
+    if (function_.cbegin() == function_.cend()) {
+        return true;
     }
 
-    builder_.AST().AddFunction(create<ast::Function>(
-        decl.source, builder_.Symbols().Register(decl.name),
-        std::move(decl.params), decl.return_type->Build(builder_), body,
-        std::move(decl.attributes), ast::AttributeList{}));
-  }
+    // The function declaration, corresponding to how it's written in SPIR-V,
+    // and without regard to whether it's an entry point.
+    FunctionDeclaration decl;
+    if (!ParseFunctionDeclaration(&decl)) {
+        return false;
+    }
 
-  if (ep_info_ && !ep_info_->inner_name.empty()) {
-    return EmitEntryPointAsWrapper();
-  }
+    bool make_body_function = true;
+    if (ep_info_) {
+        TINT_ASSERT(Reader, !ep_info_->inner_name.empty());
+        if (ep_info_->owns_inner_implementation) {
+            // This is an entry point, and we want to emit it as a wrapper around
+            // an implementation function.
+            decl.name = ep_info_->inner_name;
+        } else {
+            // This is a second entry point that shares an inner implementation
+            // function.
+            make_body_function = false;
+        }
+    }
 
-  return success();
+    if (make_body_function) {
+        auto* body = MakeFunctionBody();
+        if (!body) {
+            return false;
+        }
+
+        builder_.AST().AddFunction(
+            create<ast::Function>(decl.source, builder_.Symbols().Register(decl.name),
+                                  std::move(decl.params), decl.return_type->Build(builder_), body,
+                                  std::move(decl.attributes), ast::AttributeList{}));
+    }
+
+    if (ep_info_ && !ep_info_->inner_name.empty()) {
+        return EmitEntryPointAsWrapper();
+    }
+
+    return success();
 }
 
 const ast::BlockStatement* FunctionEmitter::MakeFunctionBody() {
-  TINT_ASSERT(Reader, statements_stack_.size() == 1);
+    TINT_ASSERT(Reader, statements_stack_.size() == 1);
 
-  if (!EmitBody()) {
-    return nullptr;
-  }
+    if (!EmitBody()) {
+        return nullptr;
+    }
 
-  // Set the body of the AST function node.
-  if (statements_stack_.size() != 1) {
-    Fail() << "internal error: statement-list stack should have 1 "
-              "element but has "
-           << statements_stack_.size();
-    return nullptr;
-  }
+    // Set the body of the AST function node.
+    if (statements_stack_.size() != 1) {
+        Fail() << "internal error: statement-list stack should have 1 "
+                  "element but has "
+               << statements_stack_.size();
+        return nullptr;
+    }
 
-  statements_stack_[0].Finalize(&builder_);
-  auto& statements = statements_stack_[0].GetStatements();
-  auto* body = create<ast::BlockStatement>(Source{}, statements);
+    statements_stack_[0].Finalize(&builder_);
+    auto& statements = statements_stack_[0].GetStatements();
+    auto* body = create<ast::BlockStatement>(Source{}, statements);
 
-  // Maintain the invariant by repopulating the one and only element.
-  statements_stack_.clear();
-  PushNewStatementBlock(constructs_[0].get(), 0, nullptr);
+    // Maintain the invariant by repopulating the one and only element.
+    statements_stack_.clear();
+    PushNewStatementBlock(constructs_[0].get(), 0, nullptr);
 
-  return body;
+    return body;
 }
 
 bool FunctionEmitter::EmitPipelineInput(std::string var_name,
@@ -962,149 +943,139 @@
                                         const Type* forced_param_type,
                                         ast::VariableList* params,
                                         ast::StatementList* statements) {
-  // TODO(dneto): Handle structs where the locations are annotated on members.
-  tip_type = tip_type->UnwrapAlias();
-  if (auto* ref_type = tip_type->As<Reference>()) {
-    tip_type = ref_type->type;
-  }
+    // TODO(dneto): Handle structs where the locations are annotated on members.
+    tip_type = tip_type->UnwrapAlias();
+    if (auto* ref_type = tip_type->As<Reference>()) {
+        tip_type = ref_type->type;
+    }
 
-  // Recursively flatten matrices, arrays, and structures.
-  return Switch(
-      tip_type,
-      [&](const Matrix* matrix_type) -> bool {
-        index_prefix.push_back(0);
-        const auto num_columns = static_cast<int>(matrix_type->columns);
-        const Type* vec_ty = ty_.Vector(matrix_type->type, matrix_type->rows);
-        for (int col = 0; col < num_columns; col++) {
-          index_prefix.back() = col;
-          if (!EmitPipelineInput(var_name, var_type, attrs, index_prefix,
-                                 vec_ty, forced_param_type, params,
-                                 statements)) {
-            return false;
-          }
-        }
-        return success();
-      },
-      [&](const Array* array_type) -> bool {
-        if (array_type->size == 0) {
-          return Fail() << "runtime-size array not allowed on pipeline IO";
-        }
-        index_prefix.push_back(0);
-        const Type* elem_ty = array_type->type;
-        for (int i = 0; i < static_cast<int>(array_type->size); i++) {
-          index_prefix.back() = i;
-          if (!EmitPipelineInput(var_name, var_type, attrs, index_prefix,
-                                 elem_ty, forced_param_type, params,
-                                 statements)) {
-            return false;
-          }
-        }
-        return success();
-      },
-      [&](const Struct* struct_type) -> bool {
-        const auto& members = struct_type->members;
-        index_prefix.push_back(0);
-        for (int i = 0; i < static_cast<int>(members.size()); ++i) {
-          index_prefix.back() = i;
-          ast::AttributeList member_attrs(*attrs);
-          if (!parser_impl_.ConvertPipelineDecorations(
-                  struct_type,
-                  parser_impl_.GetMemberPipelineDecorations(*struct_type, i),
-                  &member_attrs)) {
-            return false;
-          }
-          if (!EmitPipelineInput(var_name, var_type, &member_attrs,
-                                 index_prefix, members[i], forced_param_type,
-                                 params, statements)) {
-            return false;
-          }
-          // Copy the location as updated by nested expansion of the member.
-          parser_impl_.SetLocation(attrs, GetLocation(member_attrs));
-        }
-        return success();
-      },
-      [&](Default) {
-        const bool is_builtin =
-            ast::HasAttribute<ast::BuiltinAttribute>(*attrs);
+    // Recursively flatten matrices, arrays, and structures.
+    return Switch(
+        tip_type,
+        [&](const Matrix* matrix_type) -> bool {
+            index_prefix.push_back(0);
+            const auto num_columns = static_cast<int>(matrix_type->columns);
+            const Type* vec_ty = ty_.Vector(matrix_type->type, matrix_type->rows);
+            for (int col = 0; col < num_columns; col++) {
+                index_prefix.back() = col;
+                if (!EmitPipelineInput(var_name, var_type, attrs, index_prefix, vec_ty,
+                                       forced_param_type, params, statements)) {
+                    return false;
+                }
+            }
+            return success();
+        },
+        [&](const Array* array_type) -> bool {
+            if (array_type->size == 0) {
+                return Fail() << "runtime-size array not allowed on pipeline IO";
+            }
+            index_prefix.push_back(0);
+            const Type* elem_ty = array_type->type;
+            for (int i = 0; i < static_cast<int>(array_type->size); i++) {
+                index_prefix.back() = i;
+                if (!EmitPipelineInput(var_name, var_type, attrs, index_prefix, elem_ty,
+                                       forced_param_type, params, statements)) {
+                    return false;
+                }
+            }
+            return success();
+        },
+        [&](const Struct* struct_type) -> bool {
+            const auto& members = struct_type->members;
+            index_prefix.push_back(0);
+            for (int i = 0; i < static_cast<int>(members.size()); ++i) {
+                index_prefix.back() = i;
+                ast::AttributeList member_attrs(*attrs);
+                if (!parser_impl_.ConvertPipelineDecorations(
+                        struct_type, parser_impl_.GetMemberPipelineDecorations(*struct_type, i),
+                        &member_attrs)) {
+                    return false;
+                }
+                if (!EmitPipelineInput(var_name, var_type, &member_attrs, index_prefix, members[i],
+                                       forced_param_type, params, statements)) {
+                    return false;
+                }
+                // Copy the location as updated by nested expansion of the member.
+                parser_impl_.SetLocation(attrs, GetLocation(member_attrs));
+            }
+            return success();
+        },
+        [&](Default) {
+            const bool is_builtin = ast::HasAttribute<ast::BuiltinAttribute>(*attrs);
 
-        const Type* param_type = is_builtin ? forced_param_type : tip_type;
+            const Type* param_type = is_builtin ? forced_param_type : tip_type;
 
-        const auto param_name = namer_.MakeDerivedName(var_name + "_param");
-        // Create the parameter.
-        // TODO(dneto): Note: If the parameter has non-location decorations,
-        // then those decoration AST nodes will be reused between multiple
-        // elements of a matrix, array, or structure.  Normally that's
-        // disallowed but currently the SPIR-V reader will make duplicates when
-        // the entire AST is cloned at the top level of the SPIR-V reader flow.
-        // Consider rewriting this to avoid this node-sharing.
-        params->push_back(
-            builder_.Param(param_name, param_type->Build(builder_), *attrs));
+            const auto param_name = namer_.MakeDerivedName(var_name + "_param");
+            // Create the parameter.
+            // TODO(dneto): Note: If the parameter has non-location decorations,
+            // then those decoration AST nodes will be reused between multiple
+            // elements of a matrix, array, or structure.  Normally that's
+            // disallowed but currently the SPIR-V reader will make duplicates when
+            // the entire AST is cloned at the top level of the SPIR-V reader flow.
+            // Consider rewriting this to avoid this node-sharing.
+            params->push_back(builder_.Param(param_name, param_type->Build(builder_), *attrs));
 
-        // Add a body statement to copy the parameter to the corresponding
-        // private variable.
-        const ast::Expression* param_value = builder_.Expr(param_name);
-        const ast::Expression* store_dest = builder_.Expr(var_name);
+            // Add a body statement to copy the parameter to the corresponding
+            // private variable.
+            const ast::Expression* param_value = builder_.Expr(param_name);
+            const ast::Expression* store_dest = builder_.Expr(var_name);
 
-        // Index into the LHS as needed.
-        auto* current_type =
-            var_type->UnwrapAlias()->UnwrapRef()->UnwrapAlias();
-        for (auto index : index_prefix) {
-          Switch(
-              current_type,
-              [&](const Matrix* matrix_type) {
-                store_dest =
-                    builder_.IndexAccessor(store_dest, builder_.Expr(index));
-                current_type = ty_.Vector(matrix_type->type, matrix_type->rows);
-              },
-              [&](const Array* array_type) {
-                store_dest =
-                    builder_.IndexAccessor(store_dest, builder_.Expr(index));
-                current_type = array_type->type->UnwrapAlias();
-              },
-              [&](const Struct* struct_type) {
-                store_dest = builder_.MemberAccessor(
-                    store_dest, builder_.Expr(parser_impl_.GetMemberName(
-                                    *struct_type, index)));
-                current_type = struct_type->members[index];
-              });
-        }
+            // Index into the LHS as needed.
+            auto* current_type = var_type->UnwrapAlias()->UnwrapRef()->UnwrapAlias();
+            for (auto index : index_prefix) {
+                Switch(
+                    current_type,
+                    [&](const Matrix* matrix_type) {
+                        store_dest = builder_.IndexAccessor(store_dest, builder_.Expr(i32(index)));
+                        current_type = ty_.Vector(matrix_type->type, matrix_type->rows);
+                    },
+                    [&](const Array* array_type) {
+                        store_dest = builder_.IndexAccessor(store_dest, builder_.Expr(i32(index)));
+                        current_type = array_type->type->UnwrapAlias();
+                    },
+                    [&](const Struct* struct_type) {
+                        store_dest = builder_.MemberAccessor(
+                            store_dest,
+                            builder_.Expr(parser_impl_.GetMemberName(*struct_type, index)));
+                        current_type = struct_type->members[index];
+                    });
+            }
 
-        if (is_builtin && (tip_type != forced_param_type)) {
-          // The parameter will have the WGSL type, but we need bitcast to
-          // the variable store type.
-          param_value = create<ast::BitcastExpression>(
-              tip_type->Build(builder_), param_value);
-        }
+            if (is_builtin && (tip_type != forced_param_type)) {
+                // The parameter will have the WGSL type, but we need bitcast to
+                // the variable store type.
+                param_value =
+                    create<ast::BitcastExpression>(tip_type->Build(builder_), param_value);
+            }
 
-        statements->push_back(builder_.Assign(store_dest, param_value));
+            statements->push_back(builder_.Assign(store_dest, param_value));
 
-        // Increment the location attribute, in case more parameters will
-        // follow.
-        IncrementLocation(attrs);
+            // Increment the location attribute, in case more parameters will
+            // follow.
+            IncrementLocation(attrs);
 
-        return success();
-      });
+            return success();
+        });
 }
 
 void FunctionEmitter::IncrementLocation(ast::AttributeList* attributes) {
-  for (auto*& attr : *attributes) {
-    if (auto* loc_attr = attr->As<ast::LocationAttribute>()) {
-      // Replace this location attribute with a new one with one higher index.
-      // The old one doesn't leak because it's kept in the builder's AST node
-      // list.
-      attr = builder_.Location(loc_attr->source, loc_attr->value + 1);
+    for (auto*& attr : *attributes) {
+        if (auto* loc_attr = attr->As<ast::LocationAttribute>()) {
+            // Replace this location attribute with a new one with one higher index.
+            // The old one doesn't leak because it's kept in the builder's AST node
+            // list.
+            attr = builder_.Location(loc_attr->source, loc_attr->value + 1);
+        }
     }
-  }
 }
 
-const ast::Attribute* FunctionEmitter::GetLocation(
-    const ast::AttributeList& attributes) {
-  for (auto* const& attr : attributes) {
-    if (attr->Is<ast::LocationAttribute>()) {
-      return attr;
+const ast::Attribute* FunctionEmitter::GetLocation(const ast::AttributeList& attributes) {
+    for (auto* const& attr : attributes) {
+        if (attr->Is<ast::LocationAttribute>()) {
+            return attr;
+        }
     }
-  }
-  return nullptr;
+    return nullptr;
 }
 
 bool FunctionEmitter::EmitPipelineOutput(std::string var_name,
@@ -1115,3345 +1086,3199 @@
                                          const Type* forced_member_type,
                                          ast::StructMemberList* return_members,
                                          ast::ExpressionList* return_exprs) {
-  tip_type = tip_type->UnwrapAlias();
-  if (auto* ref_type = tip_type->As<Reference>()) {
-    tip_type = ref_type->type;
-  }
+    tip_type = tip_type->UnwrapAlias();
+    if (auto* ref_type = tip_type->As<Reference>()) {
+        tip_type = ref_type->type;
+    }
 
-  // Recursively flatten matrices, arrays, and structures.
-  return Switch(
-      tip_type,
-      [&](const Matrix* matrix_type) {
-        index_prefix.push_back(0);
-        const auto num_columns = static_cast<int>(matrix_type->columns);
-        const Type* vec_ty = ty_.Vector(matrix_type->type, matrix_type->rows);
-        for (int col = 0; col < num_columns; col++) {
-          index_prefix.back() = col;
-          if (!EmitPipelineOutput(var_name, var_type, decos, index_prefix,
-                                  vec_ty, forced_member_type, return_members,
-                                  return_exprs)) {
-            return false;
-          }
-        }
-        return success();
-      },
-      [&](const Array* array_type) -> bool {
-        if (array_type->size == 0) {
-          return Fail() << "runtime-size array not allowed on pipeline IO";
-        }
-        index_prefix.push_back(0);
-        const Type* elem_ty = array_type->type;
-        for (int i = 0; i < static_cast<int>(array_type->size); i++) {
-          index_prefix.back() = i;
-          if (!EmitPipelineOutput(var_name, var_type, decos, index_prefix,
-                                  elem_ty, forced_member_type, return_members,
-                                  return_exprs)) {
-            return false;
-          }
-        }
-        return success();
-      },
-      [&](const Struct* struct_type) -> bool {
-        const auto& members = struct_type->members;
-        index_prefix.push_back(0);
-        for (int i = 0; i < static_cast<int>(members.size()); ++i) {
-          index_prefix.back() = i;
-          ast::AttributeList member_attrs(*decos);
-          if (!parser_impl_.ConvertPipelineDecorations(
-                  struct_type,
-                  parser_impl_.GetMemberPipelineDecorations(*struct_type, i),
-                  &member_attrs)) {
-            return false;
-          }
-          if (!EmitPipelineOutput(var_name, var_type, &member_attrs,
-                                  index_prefix, members[i], forced_member_type,
-                                  return_members, return_exprs)) {
-            return false;
-          }
-          // Copy the location as updated by nested expansion of the member.
-          parser_impl_.SetLocation(decos, GetLocation(member_attrs));
-        }
-        return success();
-      },
-      [&](Default) {
-        const bool is_builtin =
-            ast::HasAttribute<ast::BuiltinAttribute>(*decos);
+    // Recursively flatten matrices, arrays, and structures.
+    return Switch(
+        tip_type,
+        [&](const Matrix* matrix_type) {
+            index_prefix.push_back(0);
+            const auto num_columns = static_cast<int>(matrix_type->columns);
+            const Type* vec_ty = ty_.Vector(matrix_type->type, matrix_type->rows);
+            for (int col = 0; col < num_columns; col++) {
+                index_prefix.back() = col;
+                if (!EmitPipelineOutput(var_name, var_type, decos, index_prefix, vec_ty,
+                                        forced_member_type, return_members, return_exprs)) {
+                    return false;
+                }
+            }
+            return success();
+        },
+        [&](const Array* array_type) -> bool {
+            if (array_type->size == 0) {
+                return Fail() << "runtime-size array not allowed on pipeline IO";
+            }
+            index_prefix.push_back(0);
+            const Type* elem_ty = array_type->type;
+            for (int i = 0; i < static_cast<int>(array_type->size); i++) {
+                index_prefix.back() = i;
+                if (!EmitPipelineOutput(var_name, var_type, decos, index_prefix, elem_ty,
+                                        forced_member_type, return_members, return_exprs)) {
+                    return false;
+                }
+            }
+            return success();
+        },
+        [&](const Struct* struct_type) -> bool {
+            const auto& members = struct_type->members;
+            index_prefix.push_back(0);
+            for (int i = 0; i < static_cast<int>(members.size()); ++i) {
+                index_prefix.back() = i;
+                ast::AttributeList member_attrs(*decos);
+                if (!parser_impl_.ConvertPipelineDecorations(
+                        struct_type, parser_impl_.GetMemberPipelineDecorations(*struct_type, i),
+                        &member_attrs)) {
+                    return false;
+                }
+                if (!EmitPipelineOutput(var_name, var_type, &member_attrs, index_prefix, members[i],
+                                        forced_member_type, return_members, return_exprs)) {
+                    return false;
+                }
+                // Copy the location as updated by nested expansion of the member.
+                parser_impl_.SetLocation(decos, GetLocation(member_attrs));
+            }
+            return success();
+        },
+        [&](Default) {
+            const bool is_builtin = ast::HasAttribute<ast::BuiltinAttribute>(*decos);
 
-        const Type* member_type = is_builtin ? forced_member_type : tip_type;
-        // Derive the member name directly from the variable name.  They can't
-        // collide.
-        const auto member_name = namer_.MakeDerivedName(var_name);
-        // Create the member.
-        // TODO(dneto): Note: If the parameter has non-location decorations,
-        // then those decoration AST nodes  will be reused between multiple
-        // elements of a matrix, array, or structure.  Normally that's
-        // disallowed but currently the SPIR-V reader will make duplicates when
-        // the entire AST is cloned at the top level of the SPIR-V reader flow.
-        // Consider rewriting this to avoid this node-sharing.
-        return_members->push_back(
-            builder_.Member(member_name, member_type->Build(builder_), *decos));
+            const Type* member_type = is_builtin ? forced_member_type : tip_type;
+            // Derive the member name directly from the variable name.  They can't
+            // collide.
+            const auto member_name = namer_.MakeDerivedName(var_name);
+            // Create the member.
+            // TODO(dneto): Note: If the parameter has non-location decorations,
+            // then those decoration AST nodes  will be reused between multiple
+            // elements of a matrix, array, or structure.  Normally that's
+            // disallowed but currently the SPIR-V reader will make duplicates when
+            // the entire AST is cloned at the top level of the SPIR-V reader flow.
+            // Consider rewriting this to avoid this node-sharing.
+            return_members->push_back(
+                builder_.Member(member_name, member_type->Build(builder_), *decos));
 
-        // Create an expression to evaluate the part of the variable indexed by
-        // the index_prefix.
-        const ast::Expression* load_source = builder_.Expr(var_name);
+            // Create an expression to evaluate the part of the variable indexed by
+            // the index_prefix.
+            const ast::Expression* load_source = builder_.Expr(var_name);
 
-        // Index into the variable as needed to pick out the flattened member.
-        auto* current_type =
-            var_type->UnwrapAlias()->UnwrapRef()->UnwrapAlias();
-        for (auto index : index_prefix) {
-          Switch(
-              current_type,
-              [&](const Matrix* matrix_type) {
-                load_source =
-                    builder_.IndexAccessor(load_source, builder_.Expr(index));
-                current_type = ty_.Vector(matrix_type->type, matrix_type->rows);
-              },
-              [&](const Array* array_type) {
-                load_source =
-                    builder_.IndexAccessor(load_source, builder_.Expr(index));
-                current_type = array_type->type->UnwrapAlias();
-              },
-              [&](const Struct* struct_type) {
-                load_source = builder_.MemberAccessor(
-                    load_source, builder_.Expr(parser_impl_.GetMemberName(
-                                     *struct_type, index)));
-                current_type = struct_type->members[index];
-              });
-        }
+            // Index into the variable as needed to pick out the flattened member.
+            auto* current_type = var_type->UnwrapAlias()->UnwrapRef()->UnwrapAlias();
+            for (auto index : index_prefix) {
+                Switch(
+                    current_type,
+                    [&](const Matrix* matrix_type) {
+                        load_source =
+                            builder_.IndexAccessor(load_source, builder_.Expr(i32(index)));
+                        current_type = ty_.Vector(matrix_type->type, matrix_type->rows);
+                    },
+                    [&](const Array* array_type) {
+                        load_source =
+                            builder_.IndexAccessor(load_source, builder_.Expr(i32(index)));
+                        current_type = array_type->type->UnwrapAlias();
+                    },
+                    [&](const Struct* struct_type) {
+                        load_source = builder_.MemberAccessor(
+                            load_source,
+                            builder_.Expr(parser_impl_.GetMemberName(*struct_type, index)));
+                        current_type = struct_type->members[index];
+                    });
+            }
 
-        if (is_builtin && (tip_type != forced_member_type)) {
-          // The member will have the WGSL type, but we need bitcast to
-          // the variable store type.
-          load_source = create<ast::BitcastExpression>(
-              forced_member_type->Build(builder_), load_source);
-        }
-        return_exprs->push_back(load_source);
+            if (is_builtin && (tip_type != forced_member_type)) {
+                // The member will have the WGSL type, but we need bitcast to
+                // the variable store type.
+                load_source = create<ast::BitcastExpression>(forced_member_type->Build(builder_),
+                                                             load_source);
+            }
+            return_exprs->push_back(load_source);
 
-        // Increment the location attribute, in case more parameters will
-        // follow.
-        IncrementLocation(decos);
+            // Increment the location attribute, in case more parameters will
+            // follow.
+            IncrementLocation(decos);
 
-        return success();
-      });
+            return success();
+        });
 }
 
 bool FunctionEmitter::EmitEntryPointAsWrapper() {
-  Source source;
+    Source source;
 
-  // The statements in the body.
-  ast::StatementList stmts;
+    // The statements in the body.
+    ast::StatementList stmts;
 
-  FunctionDeclaration decl;
-  decl.source = source;
-  decl.name = ep_info_->name;
-  const ast::Type* return_type = nullptr;  // Populated below.
+    FunctionDeclaration decl;
+    decl.source = source;
+    decl.name = ep_info_->name;
+    const ast::Type* return_type = nullptr;  // Populated below.
 
-  // Pipeline inputs become parameters to the wrapper function, and
-  // their values are saved into the corresponding private variables that
-  // have already been created.
-  for (uint32_t var_id : ep_info_->inputs) {
-    const auto* var = def_use_mgr_->GetDef(var_id);
-    TINT_ASSERT(Reader, var != nullptr);
-    TINT_ASSERT(Reader, var->opcode() == SpvOpVariable);
-    auto* store_type = GetVariableStoreType(*var);
-    auto* forced_param_type = store_type;
-    ast::AttributeList param_decos;
-    if (!parser_impl_.ConvertDecorationsForVariable(var_id, &forced_param_type,
-                                                    &param_decos, true)) {
-      // This occurs, and is not an error, for the PointSize builtin.
-      if (!success()) {
-        // But exit early if an error was logged.
-        return false;
-      }
-      continue;
-    }
-
-    // We don't have to handle initializers because in Vulkan SPIR-V, Input
-    // variables must not have them.
-
-    const auto var_name = namer_.GetName(var_id);
-
-    bool ok = true;
-    if (HasBuiltinSampleMask(param_decos)) {
-      // In Vulkan SPIR-V, the sample mask is an array. In WGSL it's a scalar.
-      // Use the first element only.
-      auto* sample_mask_array_type =
-          store_type->UnwrapRef()->UnwrapAlias()->As<Array>();
-      TINT_ASSERT(Reader, sample_mask_array_type);
-      ok = EmitPipelineInput(var_name, store_type, &param_decos, {0},
-                             sample_mask_array_type->type, forced_param_type,
-                             &(decl.params), &stmts);
-    } else {
-      // The normal path.
-      ok = EmitPipelineInput(var_name, store_type, &param_decos, {}, store_type,
-                             forced_param_type, &(decl.params), &stmts);
-    }
-    if (!ok) {
-      return false;
-    }
-  }
-
-  // Call the inner function.  It has no parameters.
-  stmts.push_back(create<ast::CallStatement>(
-      source,
-      create<ast::CallExpression>(
-          source,
-          create<ast::IdentifierExpression>(
-              source, builder_.Symbols().Register(ep_info_->inner_name)),
-          ast::ExpressionList{})));
-
-  // Pipeline outputs are mapped to the return value.
-  if (ep_info_->outputs.empty()) {
-    // There is nothing to return.
-    return_type = ty_.Void()->Build(builder_);
-  } else {
-    // Pipeline outputs are converted to a structure that is written
-    // to just before returning.
-
-    const auto return_struct_name =
-        namer_.MakeDerivedName(ep_info_->name + "_out");
-    const auto return_struct_sym =
-        builder_.Symbols().Register(return_struct_name);
-
-    // Define the structure.
-    std::vector<const ast::StructMember*> return_members;
-    ast::ExpressionList return_exprs;
-
-    const auto& builtin_position_info = parser_impl_.GetBuiltInPositionInfo();
-
-    for (uint32_t var_id : ep_info_->outputs) {
-      if (var_id == builtin_position_info.per_vertex_var_id) {
-        // The SPIR-V gl_PerVertex variable has already been remapped to
-        // a gl_Position variable.  Substitute the type.
-        const Type* param_type = ty_.Vector(ty_.F32(), 4);
-        ast::AttributeList out_decos{
-            create<ast::BuiltinAttribute>(source, ast::Builtin::kPosition)};
-
-        const auto var_name = namer_.GetName(var_id);
-        return_members.push_back(
-            builder_.Member(var_name, param_type->Build(builder_), out_decos));
-        return_exprs.push_back(builder_.Expr(var_name));
-
-      } else {
+    // Pipeline inputs become parameters to the wrapper function, and
+    // their values are saved into the corresponding private variables that
+    // have already been created.
+    for (uint32_t var_id : ep_info_->inputs) {
         const auto* var = def_use_mgr_->GetDef(var_id);
         TINT_ASSERT(Reader, var != nullptr);
         TINT_ASSERT(Reader, var->opcode() == SpvOpVariable);
-        const Type* store_type = GetVariableStoreType(*var);
-        const Type* forced_member_type = store_type;
-        ast::AttributeList out_decos;
-        if (!parser_impl_.ConvertDecorationsForVariable(
-                var_id, &forced_member_type, &out_decos, true)) {
-          // This occurs, and is not an error, for the PointSize builtin.
-          if (!success()) {
-            // But exit early if an error was logged.
-            return false;
-          }
-          continue;
+        auto* store_type = GetVariableStoreType(*var);
+        auto* forced_param_type = store_type;
+        ast::AttributeList param_decos;
+        if (!parser_impl_.ConvertDecorationsForVariable(var_id, &forced_param_type, &param_decos,
+                                                        true)) {
+            // This occurs, and is not an error, for the PointSize builtin.
+            if (!success()) {
+                // But exit early if an error was logged.
+                return false;
+            }
+            continue;
         }
 
+        // We don't have to handle initializers because in Vulkan SPIR-V, Input
+        // variables must not have them.
+
         const auto var_name = namer_.GetName(var_id);
+
         bool ok = true;
-        if (HasBuiltinSampleMask(out_decos)) {
-          // In Vulkan SPIR-V, the sample mask is an array. In WGSL it's a
-          // scalar. Use the first element only.
-          auto* sample_mask_array_type =
-              store_type->UnwrapRef()->UnwrapAlias()->As<Array>();
-          TINT_ASSERT(Reader, sample_mask_array_type);
-          ok = EmitPipelineOutput(var_name, store_type, &out_decos, {0},
-                                  sample_mask_array_type->type,
-                                  forced_member_type, &return_members,
-                                  &return_exprs);
+        if (HasBuiltinSampleMask(param_decos)) {
+            // In Vulkan SPIR-V, the sample mask is an array. In WGSL it's a scalar.
+            // Use the first element only.
+            auto* sample_mask_array_type = store_type->UnwrapRef()->UnwrapAlias()->As<Array>();
+            TINT_ASSERT(Reader, sample_mask_array_type);
+            ok = EmitPipelineInput(var_name, store_type, &param_decos, {0},
+                                   sample_mask_array_type->type, forced_param_type, &(decl.params),
+                                   &stmts);
         } else {
-          // The normal path.
-          ok = EmitPipelineOutput(var_name, store_type, &out_decos, {},
-                                  store_type, forced_member_type,
-                                  &return_members, &return_exprs);
+            // The normal path.
+            ok = EmitPipelineInput(var_name, store_type, &param_decos, {}, store_type,
+                                   forced_param_type, &(decl.params), &stmts);
         }
         if (!ok) {
-          return false;
+            return false;
         }
-      }
     }
 
-    if (return_members.empty()) {
-      // This can occur if only the PointSize member is accessed, because we
-      // never emit it.
-      return_type = ty_.Void()->Build(builder_);
+    // Call the inner function.  It has no parameters.
+    stmts.push_back(create<ast::CallStatement>(
+        source,
+        create<ast::CallExpression>(source,
+                                    create<ast::IdentifierExpression>(
+                                        source, builder_.Symbols().Register(ep_info_->inner_name)),
+                                    ast::ExpressionList{})));
+
+    // Pipeline outputs are mapped to the return value.
+    if (ep_info_->outputs.empty()) {
+        // There is nothing to return.
+        return_type = ty_.Void()->Build(builder_);
     } else {
-      // Create and register the result type.
-      auto* str = create<ast::Struct>(Source{}, return_struct_sym,
-                                      return_members, ast::AttributeList{});
-      parser_impl_.AddTypeDecl(return_struct_sym, str);
-      return_type = builder_.ty.Of(str);
+        // Pipeline outputs are converted to a structure that is written
+        // to just before returning.
 
-      // Add the return-value statement.
-      stmts.push_back(create<ast::ReturnStatement>(
-          source,
-          builder_.Construct(source, return_type, std::move(return_exprs))));
+        const auto return_struct_name = namer_.MakeDerivedName(ep_info_->name + "_out");
+        const auto return_struct_sym = builder_.Symbols().Register(return_struct_name);
+
+        // Define the structure.
+        std::vector<const ast::StructMember*> return_members;
+        ast::ExpressionList return_exprs;
+
+        const auto& builtin_position_info = parser_impl_.GetBuiltInPositionInfo();
+
+        for (uint32_t var_id : ep_info_->outputs) {
+            if (var_id == builtin_position_info.per_vertex_var_id) {
+                // The SPIR-V gl_PerVertex variable has already been remapped to
+                // a gl_Position variable.  Substitute the type.
+                const Type* param_type = ty_.Vector(ty_.F32(), 4);
+                ast::AttributeList out_decos{
+                    create<ast::BuiltinAttribute>(source, ast::Builtin::kPosition)};
+
+                const auto var_name = namer_.GetName(var_id);
+                return_members.push_back(
+                    builder_.Member(var_name, param_type->Build(builder_), out_decos));
+                return_exprs.push_back(builder_.Expr(var_name));
+
+            } else {
+                const auto* var = def_use_mgr_->GetDef(var_id);
+                TINT_ASSERT(Reader, var != nullptr);
+                TINT_ASSERT(Reader, var->opcode() == SpvOpVariable);
+                const Type* store_type = GetVariableStoreType(*var);
+                const Type* forced_member_type = store_type;
+                ast::AttributeList out_decos;
+                if (!parser_impl_.ConvertDecorationsForVariable(var_id, &forced_member_type,
+                                                                &out_decos, true)) {
+                    // This occurs, and is not an error, for the PointSize builtin.
+                    if (!success()) {
+                        // But exit early if an error was logged.
+                        return false;
+                    }
+                    continue;
+                }
+
+                const auto var_name = namer_.GetName(var_id);
+                bool ok = true;
+                if (HasBuiltinSampleMask(out_decos)) {
+                    // In Vulkan SPIR-V, the sample mask is an array. In WGSL it's a
+                    // scalar. Use the first element only.
+                    auto* sample_mask_array_type =
+                        store_type->UnwrapRef()->UnwrapAlias()->As<Array>();
+                    TINT_ASSERT(Reader, sample_mask_array_type);
+                    ok = EmitPipelineOutput(var_name, store_type, &out_decos, {0},
+                                            sample_mask_array_type->type, forced_member_type,
+                                            &return_members, &return_exprs);
+                } else {
+                    // The normal path.
+                    ok = EmitPipelineOutput(var_name, store_type, &out_decos, {}, store_type,
+                                            forced_member_type, &return_members, &return_exprs);
+                }
+                if (!ok) {
+                    return false;
+                }
+            }
+        }
+
+        if (return_members.empty()) {
+            // This can occur if only the PointSize member is accessed, because we
+            // never emit it.
+            return_type = ty_.Void()->Build(builder_);
+        } else {
+            // Create and register the result type.
+            auto* str = create<ast::Struct>(Source{}, return_struct_sym, return_members,
+                                            ast::AttributeList{});
+            parser_impl_.AddTypeDecl(return_struct_sym, str);
+            return_type = builder_.ty.Of(str);
+
+            // Add the return-value statement.
+            stmts.push_back(create<ast::ReturnStatement>(
+                source, builder_.Construct(source, return_type, std::move(return_exprs))));
+        }
     }
-  }
 
-  auto* body = create<ast::BlockStatement>(source, stmts);
-  ast::AttributeList fn_attrs;
-  fn_attrs.emplace_back(create<ast::StageAttribute>(source, ep_info_->stage));
+    auto* body = create<ast::BlockStatement>(source, stmts);
+    ast::AttributeList fn_attrs;
+    fn_attrs.emplace_back(create<ast::StageAttribute>(source, ep_info_->stage));
 
-  if (ep_info_->stage == ast::PipelineStage::kCompute) {
-    auto& size = ep_info_->workgroup_size;
-    if (size.x != 0 && size.y != 0 && size.z != 0) {
-      const ast::Expression* x = builder_.Expr(static_cast<int>(size.x));
-      const ast::Expression* y =
-          size.y ? builder_.Expr(static_cast<int>(size.y)) : nullptr;
-      const ast::Expression* z =
-          size.z ? builder_.Expr(static_cast<int>(size.z)) : nullptr;
-      fn_attrs.emplace_back(create<ast::WorkgroupAttribute>(Source{}, x, y, z));
+    if (ep_info_->stage == ast::PipelineStage::kCompute) {
+        auto& size = ep_info_->workgroup_size;
+        if (size.x != 0 && size.y != 0 && size.z != 0) {
+            const ast::Expression* x = builder_.Expr(i32(size.x));
+            const ast::Expression* y = size.y ? builder_.Expr(i32(size.y)) : nullptr;
+            const ast::Expression* z = size.z ? builder_.Expr(i32(size.z)) : nullptr;
+            fn_attrs.emplace_back(create<ast::WorkgroupAttribute>(Source{}, x, y, z));
+        }
     }
-  }
 
-  builder_.AST().AddFunction(
-      create<ast::Function>(source, builder_.Symbols().Register(ep_info_->name),
-                            std::move(decl.params), return_type, body,
-                            std::move(fn_attrs), ast::AttributeList{}));
+    builder_.AST().AddFunction(create<ast::Function>(
+        source, builder_.Symbols().Register(ep_info_->name), std::move(decl.params), return_type,
+        body, std::move(fn_attrs), ast::AttributeList{}));
 
-  return true;
+    return true;
 }
 
 bool FunctionEmitter::ParseFunctionDeclaration(FunctionDeclaration* decl) {
-  if (failed()) {
-    return false;
-  }
+    if (failed()) {
+        return false;
+    }
 
-  const std::string name = namer_.Name(function_.result_id());
+    const std::string name = namer_.Name(function_.result_id());
 
-  // Surprisingly, the "type id" on an OpFunction is the result type of the
-  // function, not the type of the function.  This is the one exceptional case
-  // in SPIR-V where the type ID is not the type of the result ID.
-  auto* ret_ty = parser_impl_.ConvertType(function_.type_id());
-  if (failed()) {
-    return false;
-  }
-  if (ret_ty == nullptr) {
-    return Fail()
-           << "internal error: unregistered return type for function with ID "
-           << function_.result_id();
-  }
+    // Surprisingly, the "type id" on an OpFunction is the result type of the
+    // function, not the type of the function.  This is the one exceptional case
+    // in SPIR-V where the type ID is not the type of the result ID.
+    auto* ret_ty = parser_impl_.ConvertType(function_.type_id());
+    if (failed()) {
+        return false;
+    }
+    if (ret_ty == nullptr) {
+        return Fail() << "internal error: unregistered return type for function with ID "
+                      << function_.result_id();
+    }
 
-  ast::VariableList ast_params;
-  function_.ForEachParam(
-      [this, &ast_params](const spvtools::opt::Instruction* param) {
+    ast::VariableList ast_params;
+    function_.ForEachParam([this, &ast_params](const spvtools::opt::Instruction* param) {
         auto* type = parser_impl_.ConvertType(param->type_id());
         if (type != nullptr) {
-          auto* ast_param = parser_impl_.MakeVariable(
-              param->result_id(), ast::StorageClass::kNone, type, true, false,
-              nullptr, ast::AttributeList{});
-          // Parameters are treated as const declarations.
-          ast_params.emplace_back(ast_param);
-          // The value is accessible by name.
-          identifier_types_.emplace(param->result_id(), type);
+            auto* ast_param =
+                parser_impl_.MakeVariable(param->result_id(), ast::StorageClass::kNone, type, true,
+                                          false, nullptr, ast::AttributeList{});
+            // Parameters are treated as const declarations.
+            ast_params.emplace_back(ast_param);
+            // The value is accessible by name.
+            identifier_types_.emplace(param->result_id(), type);
         } else {
-          // We've already logged an error and emitted a diagnostic. Do nothing
-          // here.
+            // We've already logged an error and emitted a diagnostic. Do nothing
+            // here.
         }
-      });
-  if (failed()) {
-    return false;
-  }
-  decl->name = name;
-  decl->params = std::move(ast_params);
-  decl->return_type = ret_ty;
-  decl->attributes.clear();
+    });
+    if (failed()) {
+        return false;
+    }
+    decl->name = name;
+    decl->params = std::move(ast_params);
+    decl->return_type = ret_ty;
+    decl->attributes.clear();
 
-  return success();
+    return success();
 }
 
-const Type* FunctionEmitter::GetVariableStoreType(
-    const spvtools::opt::Instruction& var_decl_inst) {
-  const auto type_id = var_decl_inst.type_id();
-  // Normally we use the SPIRV-Tools optimizer to manage types.
-  // But when two struct types have the same member types and decorations,
-  // but differ only in member names, the two struct types will be
-  // represented by a single common internal struct type.
-  // So avoid the optimizer's representation and instead follow the
-  // SPIR-V instructions themselves.
-  const auto* ptr_ty = def_use_mgr_->GetDef(type_id);
-  const auto store_ty_id = ptr_ty->GetSingleWordInOperand(1);
-  const auto* result = parser_impl_.ConvertType(store_ty_id);
-  return result;
+const Type* FunctionEmitter::GetVariableStoreType(const spvtools::opt::Instruction& var_decl_inst) {
+    const auto type_id = var_decl_inst.type_id();
+    // Normally we use the SPIRV-Tools optimizer to manage types.
+    // But when two struct types have the same member types and decorations,
+    // but differ only in member names, the two struct types will be
+    // represented by a single common internal struct type.
+    // So avoid the optimizer's representation and instead follow the
+    // SPIR-V instructions themselves.
+    const auto* ptr_ty = def_use_mgr_->GetDef(type_id);
+    const auto store_ty_id = ptr_ty->GetSingleWordInOperand(1);
+    const auto* result = parser_impl_.ConvertType(store_ty_id);
+    return result;
 }
 
 bool FunctionEmitter::EmitBody() {
-  RegisterBasicBlocks();
+    RegisterBasicBlocks();
 
-  if (!TerminatorsAreValid()) {
-    return false;
-  }
-  if (!RegisterMerges()) {
-    return false;
-  }
+    if (!TerminatorsAreValid()) {
+        return false;
+    }
+    if (!RegisterMerges()) {
+        return false;
+    }
 
-  ComputeBlockOrderAndPositions();
-  if (!VerifyHeaderContinueMergeOrder()) {
-    return false;
-  }
-  if (!LabelControlFlowConstructs()) {
-    return false;
-  }
-  if (!FindSwitchCaseHeaders()) {
-    return false;
-  }
-  if (!ClassifyCFGEdges()) {
-    return false;
-  }
-  if (!FindIfSelectionInternalHeaders()) {
-    return false;
-  }
+    ComputeBlockOrderAndPositions();
+    if (!VerifyHeaderContinueMergeOrder()) {
+        return false;
+    }
+    if (!LabelControlFlowConstructs()) {
+        return false;
+    }
+    if (!FindSwitchCaseHeaders()) {
+        return false;
+    }
+    if (!ClassifyCFGEdges()) {
+        return false;
+    }
+    if (!FindIfSelectionInternalHeaders()) {
+        return false;
+    }
 
-  if (!RegisterSpecialBuiltInVariables()) {
-    return false;
-  }
-  if (!RegisterLocallyDefinedValues()) {
-    return false;
-  }
-  FindValuesNeedingNamedOrHoistedDefinition();
+    if (!RegisterSpecialBuiltInVariables()) {
+        return false;
+    }
+    if (!RegisterLocallyDefinedValues()) {
+        return false;
+    }
+    FindValuesNeedingNamedOrHoistedDefinition();
 
-  if (!EmitFunctionVariables()) {
-    return false;
-  }
-  if (!EmitFunctionBodyStatements()) {
-    return false;
-  }
-  return success();
+    if (!EmitFunctionVariables()) {
+        return false;
+    }
+    if (!EmitFunctionBodyStatements()) {
+        return false;
+    }
+    return success();
 }
 
 void FunctionEmitter::RegisterBasicBlocks() {
-  for (auto& block : function_) {
-    block_info_[block.id()] = std::make_unique<BlockInfo>(block);
-  }
+    for (auto& block : function_) {
+        block_info_[block.id()] = std::make_unique<BlockInfo>(block);
+    }
 }
 
 bool FunctionEmitter::TerminatorsAreValid() {
-  if (failed()) {
-    return false;
-  }
-
-  const auto entry_id = function_.begin()->id();
-  for (const auto& block : function_) {
-    if (!block.terminator()) {
-      return Fail() << "Block " << block.id() << " has no terminator";
+    if (failed()) {
+        return false;
     }
-  }
-  for (const auto& block : function_) {
-    block.WhileEachSuccessorLabel(
-        [this, &block, entry_id](const uint32_t succ_id) -> bool {
-          if (succ_id == entry_id) {
-            return Fail() << "Block " << block.id()
-                          << " branches to function entry block " << entry_id;
-          }
-          if (!GetBlockInfo(succ_id)) {
-            return Fail() << "Block " << block.id() << " in function "
-                          << function_.DefInst().result_id() << " branches to "
-                          << succ_id << " which is not a block in the function";
-          }
-          return true;
+
+    const auto entry_id = function_.begin()->id();
+    for (const auto& block : function_) {
+        if (!block.terminator()) {
+            return Fail() << "Block " << block.id() << " has no terminator";
+        }
+    }
+    for (const auto& block : function_) {
+        block.WhileEachSuccessorLabel([this, &block, entry_id](const uint32_t succ_id) -> bool {
+            if (succ_id == entry_id) {
+                return Fail() << "Block " << block.id() << " branches to function entry block "
+                              << entry_id;
+            }
+            if (!GetBlockInfo(succ_id)) {
+                return Fail() << "Block " << block.id() << " in function "
+                              << function_.DefInst().result_id() << " branches to " << succ_id
+                              << " which is not a block in the function";
+            }
+            return true;
         });
-  }
-  return success();
+    }
+    return success();
 }
 
 bool FunctionEmitter::RegisterMerges() {
-  if (failed()) {
-    return false;
-  }
-
-  const auto entry_id = function_.begin()->id();
-  for (const auto& block : function_) {
-    const auto block_id = block.id();
-    auto* block_info = GetBlockInfo(block_id);
-    if (!block_info) {
-      return Fail() << "internal error: block " << block_id
-                    << " missing; blocks should already "
-                       "have been registered";
+    if (failed()) {
+        return false;
     }
 
-    if (const auto* inst = block.GetMergeInst()) {
-      auto terminator_opcode = block.terminator()->opcode();
-      switch (inst->opcode()) {
-        case SpvOpSelectionMerge:
-          if ((terminator_opcode != SpvOpBranchConditional) &&
-              (terminator_opcode != SpvOpSwitch)) {
-            return Fail() << "Selection header " << block_id
-                          << " does not end in an OpBranchConditional or "
-                             "OpSwitch instruction";
-          }
-          break;
-        case SpvOpLoopMerge:
-          if ((terminator_opcode != SpvOpBranchConditional) &&
-              (terminator_opcode != SpvOpBranch)) {
-            return Fail() << "Loop header " << block_id
-                          << " does not end in an OpBranch or "
-                             "OpBranchConditional instruction";
-          }
-          break;
-        default:
-          break;
-      }
+    const auto entry_id = function_.begin()->id();
+    for (const auto& block : function_) {
+        const auto block_id = block.id();
+        auto* block_info = GetBlockInfo(block_id);
+        if (!block_info) {
+            return Fail() << "internal error: block " << block_id
+                          << " missing; blocks should already "
+                             "have been registered";
+        }
 
-      const uint32_t header = block.id();
-      auto* header_info = block_info;
-      const uint32_t merge = inst->GetSingleWordInOperand(0);
-      auto* merge_info = GetBlockInfo(merge);
-      if (!merge_info) {
-        return Fail() << "Structured header block " << header
-                      << " declares invalid merge block " << merge;
-      }
-      if (merge == header) {
-        return Fail() << "Structured header block " << header
-                      << " cannot be its own merge block";
-      }
-      if (merge_info->header_for_merge) {
-        return Fail() << "Block " << merge
-                      << " declared as merge block for more than one header: "
-                      << merge_info->header_for_merge << ", " << header;
-      }
-      merge_info->header_for_merge = header;
-      header_info->merge_for_header = merge;
+        if (const auto* inst = block.GetMergeInst()) {
+            auto terminator_opcode = block.terminator()->opcode();
+            switch (inst->opcode()) {
+                case SpvOpSelectionMerge:
+                    if ((terminator_opcode != SpvOpBranchConditional) &&
+                        (terminator_opcode != SpvOpSwitch)) {
+                        return Fail() << "Selection header " << block_id
+                                      << " does not end in an OpBranchConditional or "
+                                         "OpSwitch instruction";
+                    }
+                    break;
+                case SpvOpLoopMerge:
+                    if ((terminator_opcode != SpvOpBranchConditional) &&
+                        (terminator_opcode != SpvOpBranch)) {
+                        return Fail() << "Loop header " << block_id
+                                      << " does not end in an OpBranch or "
+                                         "OpBranchConditional instruction";
+                    }
+                    break;
+                default:
+                    break;
+            }
 
-      if (inst->opcode() == SpvOpLoopMerge) {
-        if (header == entry_id) {
-          return Fail() << "Function entry block " << entry_id
-                        << " cannot be a loop header";
+            const uint32_t header = block.id();
+            auto* header_info = block_info;
+            const uint32_t merge = inst->GetSingleWordInOperand(0);
+            auto* merge_info = GetBlockInfo(merge);
+            if (!merge_info) {
+                return Fail() << "Structured header block " << header
+                              << " declares invalid merge block " << merge;
+            }
+            if (merge == header) {
+                return Fail() << "Structured header block " << header
+                              << " cannot be its own merge block";
+            }
+            if (merge_info->header_for_merge) {
+                return Fail() << "Block " << merge
+                              << " declared as merge block for more than one header: "
+                              << merge_info->header_for_merge << ", " << header;
+            }
+            merge_info->header_for_merge = header;
+            header_info->merge_for_header = merge;
+
+            if (inst->opcode() == SpvOpLoopMerge) {
+                if (header == entry_id) {
+                    return Fail() << "Function entry block " << entry_id
+                                  << " cannot be a loop header";
+                }
+                const uint32_t ct = inst->GetSingleWordInOperand(1);
+                auto* ct_info = GetBlockInfo(ct);
+                if (!ct_info) {
+                    return Fail() << "Structured header " << header
+                                  << " declares invalid continue target " << ct;
+                }
+                if (ct == merge) {
+                    return Fail() << "Invalid structured header block " << header
+                                  << ": declares block " << ct
+                                  << " as both its merge block and continue target";
+                }
+                if (ct_info->header_for_continue) {
+                    return Fail() << "Block " << ct
+                                  << " declared as continue target for more than one header: "
+                                  << ct_info->header_for_continue << ", " << header;
+                }
+                ct_info->header_for_continue = header;
+                header_info->continue_for_header = ct;
+            }
         }
-        const uint32_t ct = inst->GetSingleWordInOperand(1);
-        auto* ct_info = GetBlockInfo(ct);
-        if (!ct_info) {
-          return Fail() << "Structured header " << header
-                        << " declares invalid continue target " << ct;
+
+        // Check single-block loop cases.
+        bool is_single_block_loop = false;
+        block_info->basic_block->ForEachSuccessorLabel(
+            [&is_single_block_loop, block_id](const uint32_t succ) {
+                if (block_id == succ)
+                    is_single_block_loop = true;
+            });
+        const auto ct = block_info->continue_for_header;
+        block_info->is_continue_entire_loop = ct == block_id;
+        if (is_single_block_loop && !block_info->is_continue_entire_loop) {
+            return Fail() << "Block " << block_id
+                          << " branches to itself but is not its own continue target";
         }
-        if (ct == merge) {
-          return Fail() << "Invalid structured header block " << header
-                        << ": declares block " << ct
-                        << " as both its merge block and continue target";
-        }
-        if (ct_info->header_for_continue) {
-          return Fail()
-                 << "Block " << ct
-                 << " declared as continue target for more than one header: "
-                 << ct_info->header_for_continue << ", " << header;
-        }
-        ct_info->header_for_continue = header;
-        header_info->continue_for_header = ct;
-      }
+        // It's valid for a the header of a multi-block loop header to declare
+        // itself as its own continue target.
     }
-
-    // Check single-block loop cases.
-    bool is_single_block_loop = false;
-    block_info->basic_block->ForEachSuccessorLabel(
-        [&is_single_block_loop, block_id](const uint32_t succ) {
-          if (block_id == succ)
-            is_single_block_loop = true;
-        });
-    const auto ct = block_info->continue_for_header;
-    block_info->is_continue_entire_loop = ct == block_id;
-    if (is_single_block_loop && !block_info->is_continue_entire_loop) {
-      return Fail() << "Block " << block_id
-                    << " branches to itself but is not its own continue target";
-    }
-    // It's valid for a the header of a multi-block loop header to declare
-    // itself as its own continue target.
-  }
-  return success();
+    return success();
 }
 
 void FunctionEmitter::ComputeBlockOrderAndPositions() {
-  block_order_ = StructuredTraverser(function_).ReverseStructuredPostOrder();
+    block_order_ = StructuredTraverser(function_).ReverseStructuredPostOrder();
 
-  for (uint32_t i = 0; i < block_order_.size(); ++i) {
-    GetBlockInfo(block_order_[i])->pos = i;
-  }
-  // The invalid block position is not the position of any block that is in the
-  // order.
-  assert(block_order_.size() <= kInvalidBlockPos);
+    for (uint32_t i = 0; i < block_order_.size(); ++i) {
+        GetBlockInfo(block_order_[i])->pos = i;
+    }
+    // The invalid block position is not the position of any block that is in the
+    // order.
+    assert(block_order_.size() <= kInvalidBlockPos);
 }
 
 bool FunctionEmitter::VerifyHeaderContinueMergeOrder() {
-  // Verify interval rules for a structured header block:
-  //
-  //    If the CFG satisfies structured control flow rules, then:
-  //    If header H is reachable, then the following "interval rules" hold,
-  //    where M(H) is H's merge block, and CT(H) is H's continue target:
-  //
-  //      Pos(H) < Pos(M(H))
-  //
-  //      If CT(H) exists, then:
-  //         Pos(H) <= Pos(CT(H))
-  //         Pos(CT(H)) < Pos(M)
-  //
-  for (auto block_id : block_order_) {
-    const auto* block_info = GetBlockInfo(block_id);
-    const auto merge = block_info->merge_for_header;
-    if (merge == 0) {
-      continue;
-    }
-    // This is a header.
-    const auto header = block_id;
-    const auto* header_info = block_info;
-    const auto header_pos = header_info->pos;
-    const auto merge_pos = GetBlockInfo(merge)->pos;
+    // Verify interval rules for a structured header block:
+    //
+    //    If the CFG satisfies structured control flow rules, then:
+    //    If header H is reachable, then the following "interval rules" hold,
+    //    where M(H) is H's merge block, and CT(H) is H's continue target:
+    //
+    //      Pos(H) < Pos(M(H))
+    //
+    //      If CT(H) exists, then:
+    //         Pos(H) <= Pos(CT(H))
+    //         Pos(CT(H)) < Pos(M)
+    //
+    for (auto block_id : block_order_) {
+        const auto* block_info = GetBlockInfo(block_id);
+        const auto merge = block_info->merge_for_header;
+        if (merge == 0) {
+            continue;
+        }
+        // This is a header.
+        const auto header = block_id;
+        const auto* header_info = block_info;
+        const auto header_pos = header_info->pos;
+        const auto merge_pos = GetBlockInfo(merge)->pos;
 
-    // Pos(H) < Pos(M(H))
-    // Note: When recording merges we made sure H != M(H)
-    if (merge_pos <= header_pos) {
-      return Fail() << "Header " << header
-                    << " does not strictly dominate its merge block " << merge;
-      // TODO(dneto): Report a path from the entry block to the merge block
-      // without going through the header block.
-    }
+        // Pos(H) < Pos(M(H))
+        // Note: When recording merges we made sure H != M(H)
+        if (merge_pos <= header_pos) {
+            return Fail() << "Header " << header << " does not strictly dominate its merge block "
+                          << merge;
+            // TODO(dneto): Report a path from the entry block to the merge block
+            // without going through the header block.
+        }
 
-    const auto ct = block_info->continue_for_header;
-    if (ct == 0) {
-      continue;
+        const auto ct = block_info->continue_for_header;
+        if (ct == 0) {
+            continue;
+        }
+        // Furthermore, this is a loop header.
+        const auto* ct_info = GetBlockInfo(ct);
+        const auto ct_pos = ct_info->pos;
+        // Pos(H) <= Pos(CT(H))
+        if (ct_pos < header_pos) {
+            Fail() << "Loop header " << header << " does not dominate its continue target " << ct;
+        }
+        // Pos(CT(H)) < Pos(M(H))
+        // Note: When recording merges we made sure CT(H) != M(H)
+        if (merge_pos <= ct_pos) {
+            return Fail() << "Merge block " << merge << " for loop headed at block " << header
+                          << " appears at or before the loop's continue "
+                             "construct headed by "
+                             "block "
+                          << ct;
+        }
     }
-    // Furthermore, this is a loop header.
-    const auto* ct_info = GetBlockInfo(ct);
-    const auto ct_pos = ct_info->pos;
-    // Pos(H) <= Pos(CT(H))
-    if (ct_pos < header_pos) {
-      Fail() << "Loop header " << header
-             << " does not dominate its continue target " << ct;
-    }
-    // Pos(CT(H)) < Pos(M(H))
-    // Note: When recording merges we made sure CT(H) != M(H)
-    if (merge_pos <= ct_pos) {
-      return Fail() << "Merge block " << merge << " for loop headed at block "
-                    << header
-                    << " appears at or before the loop's continue "
-                       "construct headed by "
-                       "block "
-                    << ct;
-    }
-  }
-  return success();
+    return success();
 }
 
 bool FunctionEmitter::LabelControlFlowConstructs() {
-  // Label each block in the block order with its nearest enclosing structured
-  // control flow construct. Populates the |construct| member of BlockInfo.
+    // Label each block in the block order with its nearest enclosing structured
+    // control flow construct. Populates the |construct| member of BlockInfo.
 
-  //  Keep a stack of enclosing structured control flow constructs.  Start
-  //  with the synthetic construct representing the entire function.
-  //
-  //  Scan from left to right in the block order, and check conditions
-  //  on each block in the following order:
-  //
-  //        a. When you reach a merge block, the top of the stack should
-  //           be the associated header. Pop it off.
-  //        b. When you reach a header, push it on the stack.
-  //        c. When you reach a continue target, push it on the stack.
-  //           (A block can be both a header and a continue target.)
-  //        c. When you reach a block with an edge branching backward (in the
-  //           structured order) to block T:
-  //            T should be a loop header, and the top of the stack should be a
-  //            continue target associated with T.
-  //            This is the end of the continue construct. Pop the continue
-  //            target off the stack.
-  //
-  //       Note: A loop header can declare itself as its own continue target.
-  //
-  //       Note: For a single-block loop, that block is a header, its own
-  //       continue target, and its own backedge block.
-  //
-  //       Note: We pop the merge off first because a merge block that marks
-  //       the end of one construct can be a single-block loop.  So that block
-  //       is a merge, a header, a continue target, and a backedge block.
-  //       But we want to finish processing of the merge before dealing with
-  //       the loop.
-  //
-  //      In the same scan, mark each basic block with the nearest enclosing
-  //      header: the most recent header for which we haven't reached its merge
-  //      block. Also mark the the most recent continue target for which we
-  //      haven't reached the backedge block.
+    //  Keep a stack of enclosing structured control flow constructs.  Start
+    //  with the synthetic construct representing the entire function.
+    //
+    //  Scan from left to right in the block order, and check conditions
+    //  on each block in the following order:
+    //
+    //        a. When you reach a merge block, the top of the stack should
+    //           be the associated header. Pop it off.
+    //        b. When you reach a header, push it on the stack.
+    //        c. When you reach a continue target, push it on the stack.
+    //           (A block can be both a header and a continue target.)
+    //        c. When you reach a block with an edge branching backward (in the
+    //           structured order) to block T:
+    //            T should be a loop header, and the top of the stack should be a
+    //            continue target associated with T.
+    //            This is the end of the continue construct. Pop the continue
+    //            target off the stack.
+    //
+    //       Note: A loop header can declare itself as its own continue target.
+    //
+    //       Note: For a single-block loop, that block is a header, its own
+    //       continue target, and its own backedge block.
+    //
+    //       Note: We pop the merge off first because a merge block that marks
+    //       the end of one construct can be a single-block loop.  So that block
+    //       is a merge, a header, a continue target, and a backedge block.
+    //       But we want to finish processing of the merge before dealing with
+    //       the loop.
+    //
+    //      In the same scan, mark each basic block with the nearest enclosing
+    //      header: the most recent header for which we haven't reached its merge
+    //      block. Also mark the the most recent continue target for which we
+    //      haven't reached the backedge block.
 
-  TINT_ASSERT(Reader, block_order_.size() > 0);
-  constructs_.clear();
-  const auto entry_id = block_order_[0];
+    TINT_ASSERT(Reader, block_order_.size() > 0);
+    constructs_.clear();
+    const auto entry_id = block_order_[0];
 
-  // The stack of enclosing constructs.
-  std::vector<Construct*> enclosing;
+    // The stack of enclosing constructs.
+    std::vector<Construct*> enclosing;
 
-  // Creates a control flow construct and pushes it onto the stack.
-  // Its parent is the top of the stack, or nullptr if the stack is empty.
-  // Returns the newly created construct.
-  auto push_construct = [this, &enclosing](size_t depth, Construct::Kind k,
-                                           uint32_t begin_id,
-                                           uint32_t end_id) -> Construct* {
-    const auto begin_pos = GetBlockInfo(begin_id)->pos;
-    const auto end_pos =
-        end_id == 0 ? uint32_t(block_order_.size()) : GetBlockInfo(end_id)->pos;
-    const auto* parent = enclosing.empty() ? nullptr : enclosing.back();
-    auto scope_end_pos = end_pos;
-    // A loop construct is added right after its associated continue construct.
-    // In that case, adjust the parent up.
-    if (k == Construct::kLoop) {
-      TINT_ASSERT(Reader, parent);
-      TINT_ASSERT(Reader, parent->kind == Construct::kContinue);
-      scope_end_pos = parent->end_pos;
-      parent = parent->parent;
-    }
-    constructs_.push_back(std::make_unique<Construct>(
-        parent, static_cast<int>(depth), k, begin_id, end_id, begin_pos,
-        end_pos, scope_end_pos));
-    Construct* result = constructs_.back().get();
-    enclosing.push_back(result);
-    return result;
-  };
-
-  // Make a synthetic kFunction construct to enclose all blocks in the function.
-  push_construct(0, Construct::kFunction, entry_id, 0);
-  // The entry block can be a selection construct, so be sure to process
-  // it anyway.
-
-  for (uint32_t i = 0; i < block_order_.size(); ++i) {
-    const auto block_id = block_order_[i];
-    TINT_ASSERT(Reader, block_id > 0);
-    auto* block_info = GetBlockInfo(block_id);
-    TINT_ASSERT(Reader, block_info);
-
-    if (enclosing.empty()) {
-      return Fail() << "internal error: too many merge blocks before block "
-                    << block_id;
-    }
-    const Construct* top = enclosing.back();
-
-    while (block_id == top->end_id) {
-      // We've reached a predeclared end of the construct.  Pop it off the
-      // stack.
-      enclosing.pop_back();
-      if (enclosing.empty()) {
-        return Fail() << "internal error: too many merge blocks before block "
-                      << block_id;
-      }
-      top = enclosing.back();
-    }
-
-    const auto merge = block_info->merge_for_header;
-    if (merge != 0) {
-      // The current block is a header.
-      const auto header = block_id;
-      const auto* header_info = block_info;
-      const auto depth = 1 + top->depth;
-      const auto ct = header_info->continue_for_header;
-      if (ct != 0) {
-        // The current block is a loop header.
-        // We should see the continue construct after the loop construct, so
-        // push the loop construct last.
-
-        // From the interval rule, the continue construct consists of blocks
-        // in the block order, starting at the continue target, until just
-        // before the merge block.
-        top = push_construct(depth, Construct::kContinue, ct, merge);
-        // A loop header that is its own continue target will have an
-        // empty loop construct. Only create a loop construct when
-        // the continue target is *not* the same as the loop header.
-        if (header != ct) {
-          // From the interval rule, the loop construct consists of blocks
-          // in the block order, starting at the header, until just
-          // before the continue target.
-          top = push_construct(depth, Construct::kLoop, header, ct);
-
-          // If the loop header branches to two different blocks inside the loop
-          // construct, then the loop body should be modeled as an if-selection
-          // construct
-          std::vector<uint32_t> targets;
-          header_info->basic_block->ForEachSuccessorLabel(
-              [&targets](const uint32_t target) { targets.push_back(target); });
-          if ((targets.size() == 2u) && targets[0] != targets[1]) {
-            const auto target0_pos = GetBlockInfo(targets[0])->pos;
-            const auto target1_pos = GetBlockInfo(targets[1])->pos;
-            if (top->ContainsPos(target0_pos) &&
-                top->ContainsPos(target1_pos)) {
-              // Insert a synthetic if-selection
-              top = push_construct(depth + 1, Construct::kIfSelection, header,
-                                   ct);
-            }
-          }
+    // Creates a control flow construct and pushes it onto the stack.
+    // Its parent is the top of the stack, or nullptr if the stack is empty.
+    // Returns the newly created construct.
+    auto push_construct = [this, &enclosing](size_t depth, Construct::Kind k, uint32_t begin_id,
+                                             uint32_t end_id) -> Construct* {
+        const auto begin_pos = GetBlockInfo(begin_id)->pos;
+        const auto end_pos =
+            end_id == 0 ? uint32_t(block_order_.size()) : GetBlockInfo(end_id)->pos;
+        const auto* parent = enclosing.empty() ? nullptr : enclosing.back();
+        auto scope_end_pos = end_pos;
+        // A loop construct is added right after its associated continue construct.
+        // In that case, adjust the parent up.
+        if (k == Construct::kLoop) {
+            TINT_ASSERT(Reader, parent);
+            TINT_ASSERT(Reader, parent->kind == Construct::kContinue);
+            scope_end_pos = parent->end_pos;
+            parent = parent->parent;
         }
-      } else {
-        // From the interval rule, the selection construct consists of blocks
-        // in the block order, starting at the header, until just before the
-        // merge block.
-        const auto branch_opcode =
-            header_info->basic_block->terminator()->opcode();
-        const auto kind = (branch_opcode == SpvOpBranchConditional)
-                              ? Construct::kIfSelection
-                              : Construct::kSwitchSelection;
-        top = push_construct(depth, kind, header, merge);
-      }
+        constructs_.push_back(std::make_unique<Construct>(parent, static_cast<int>(depth), k,
+                                                          begin_id, end_id, begin_pos, end_pos,
+                                                          scope_end_pos));
+        Construct* result = constructs_.back().get();
+        enclosing.push_back(result);
+        return result;
+    };
+
+    // Make a synthetic kFunction construct to enclose all blocks in the function.
+    push_construct(0, Construct::kFunction, entry_id, 0);
+    // The entry block can be a selection construct, so be sure to process
+    // it anyway.
+
+    for (uint32_t i = 0; i < block_order_.size(); ++i) {
+        const auto block_id = block_order_[i];
+        TINT_ASSERT(Reader, block_id > 0);
+        auto* block_info = GetBlockInfo(block_id);
+        TINT_ASSERT(Reader, block_info);
+
+        if (enclosing.empty()) {
+            return Fail() << "internal error: too many merge blocks before block " << block_id;
+        }
+        const Construct* top = enclosing.back();
+
+        while (block_id == top->end_id) {
+            // We've reached a predeclared end of the construct.  Pop it off the
+            // stack.
+            enclosing.pop_back();
+            if (enclosing.empty()) {
+                return Fail() << "internal error: too many merge blocks before block " << block_id;
+            }
+            top = enclosing.back();
+        }
+
+        const auto merge = block_info->merge_for_header;
+        if (merge != 0) {
+            // The current block is a header.
+            const auto header = block_id;
+            const auto* header_info = block_info;
+            const auto depth = 1 + top->depth;
+            const auto ct = header_info->continue_for_header;
+            if (ct != 0) {
+                // The current block is a loop header.
+                // We should see the continue construct after the loop construct, so
+                // push the loop construct last.
+
+                // From the interval rule, the continue construct consists of blocks
+                // in the block order, starting at the continue target, until just
+                // before the merge block.
+                top = push_construct(depth, Construct::kContinue, ct, merge);
+                // A loop header that is its own continue target will have an
+                // empty loop construct. Only create a loop construct when
+                // the continue target is *not* the same as the loop header.
+                if (header != ct) {
+                    // From the interval rule, the loop construct consists of blocks
+                    // in the block order, starting at the header, until just
+                    // before the continue target.
+                    top = push_construct(depth, Construct::kLoop, header, ct);
+
+                    // If the loop header branches to two different blocks inside the loop
+                    // construct, then the loop body should be modeled as an if-selection
+                    // construct
+                    std::vector<uint32_t> targets;
+                    header_info->basic_block->ForEachSuccessorLabel(
+                        [&targets](const uint32_t target) { targets.push_back(target); });
+                    if ((targets.size() == 2u) && targets[0] != targets[1]) {
+                        const auto target0_pos = GetBlockInfo(targets[0])->pos;
+                        const auto target1_pos = GetBlockInfo(targets[1])->pos;
+                        if (top->ContainsPos(target0_pos) && top->ContainsPos(target1_pos)) {
+                            // Insert a synthetic if-selection
+                            top = push_construct(depth + 1, Construct::kIfSelection, header, ct);
+                        }
+                    }
+                }
+            } else {
+                // From the interval rule, the selection construct consists of blocks
+                // in the block order, starting at the header, until just before the
+                // merge block.
+                const auto branch_opcode = header_info->basic_block->terminator()->opcode();
+                const auto kind = (branch_opcode == SpvOpBranchConditional)
+                                      ? Construct::kIfSelection
+                                      : Construct::kSwitchSelection;
+                top = push_construct(depth, kind, header, merge);
+            }
+        }
+
+        TINT_ASSERT(Reader, top);
+        block_info->construct = top;
     }
 
-    TINT_ASSERT(Reader, top);
-    block_info->construct = top;
-  }
+    // At the end of the block list, we should only have the kFunction construct
+    // left.
+    if (enclosing.size() != 1) {
+        return Fail() << "internal error: unbalanced structured constructs when "
+                         "labeling structured constructs: ended with "
+                      << enclosing.size() - 1 << " unterminated constructs";
+    }
+    const auto* top = enclosing[0];
+    if (top->kind != Construct::kFunction || top->depth != 0) {
+        return Fail() << "internal error: outermost construct is not a function?!";
+    }
 
-  // At the end of the block list, we should only have the kFunction construct
-  // left.
-  if (enclosing.size() != 1) {
-    return Fail() << "internal error: unbalanced structured constructs when "
-                     "labeling structured constructs: ended with "
-                  << enclosing.size() - 1 << " unterminated constructs";
-  }
-  const auto* top = enclosing[0];
-  if (top->kind != Construct::kFunction || top->depth != 0) {
-    return Fail() << "internal error: outermost construct is not a function?!";
-  }
-
-  return success();
+    return success();
 }
 
 bool FunctionEmitter::FindSwitchCaseHeaders() {
-  if (failed()) {
-    return false;
-  }
-  for (auto& construct : constructs_) {
-    if (construct->kind != Construct::kSwitchSelection) {
-      continue;
+    if (failed()) {
+        return false;
     }
-    const auto* branch =
-        GetBlockInfo(construct->begin_id)->basic_block->terminator();
+    for (auto& construct : constructs_) {
+        if (construct->kind != Construct::kSwitchSelection) {
+            continue;
+        }
+        const auto* branch = GetBlockInfo(construct->begin_id)->basic_block->terminator();
 
-    // Mark the default block
-    const auto default_id = branch->GetSingleWordInOperand(1);
-    auto* default_block = GetBlockInfo(default_id);
-    // A default target can't be a backedge.
-    if (construct->begin_pos >= default_block->pos) {
-      // An OpSwitch must dominate its cases.  Also, it can't be a self-loop
-      // as that would be a backedge, and backedges can only target a loop,
-      // and loops use an OpLoopMerge instruction, which can't precede an
-      // OpSwitch.
-      return Fail() << "Switch branch from block " << construct->begin_id
-                    << " to default target block " << default_id
-                    << " can't be a back-edge";
+        // Mark the default block
+        const auto default_id = branch->GetSingleWordInOperand(1);
+        auto* default_block = GetBlockInfo(default_id);
+        // A default target can't be a backedge.
+        if (construct->begin_pos >= default_block->pos) {
+            // An OpSwitch must dominate its cases.  Also, it can't be a self-loop
+            // as that would be a backedge, and backedges can only target a loop,
+            // and loops use an OpLoopMerge instruction, which can't precede an
+            // OpSwitch.
+            return Fail() << "Switch branch from block " << construct->begin_id
+                          << " to default target block " << default_id << " can't be a back-edge";
+        }
+        // A default target can be the merge block, but can't go past it.
+        if (construct->end_pos < default_block->pos) {
+            return Fail() << "Switch branch from block " << construct->begin_id
+                          << " to default block " << default_id
+                          << " escapes the selection construct";
+        }
+        if (default_block->default_head_for) {
+            // An OpSwitch must dominate its cases, including the default target.
+            return Fail() << "Block " << default_id
+                          << " is declared as the default target for two OpSwitch "
+                             "instructions, at blocks "
+                          << default_block->default_head_for->begin_id << " and "
+                          << construct->begin_id;
+        }
+        if ((default_block->header_for_merge != 0) &&
+            (default_block->header_for_merge != construct->begin_id)) {
+            // The switch instruction for this default block is an alternate path to
+            // the merge block, and hence the merge block is not dominated by its own
+            // (different) header.
+            return Fail() << "Block " << default_block->id
+                          << " is the default block for switch-selection header "
+                          << construct->begin_id << " and also the merge block for "
+                          << default_block->header_for_merge << " (violates dominance rule)";
+        }
+
+        default_block->default_head_for = construct.get();
+        default_block->default_is_merge = default_block->pos == construct->end_pos;
+
+        // Map a case target to the list of values selecting that case.
+        std::unordered_map<uint32_t, std::vector<uint64_t>> block_to_values;
+        std::vector<uint32_t> case_targets;
+        std::unordered_set<uint64_t> case_values;
+
+        // Process case targets.
+        for (uint32_t iarg = 2; iarg + 1 < branch->NumInOperands(); iarg += 2) {
+            const auto value = branch->GetInOperand(iarg).AsLiteralUint64();
+            const auto case_target_id = branch->GetSingleWordInOperand(iarg + 1);
+
+            if (case_values.count(value)) {
+                return Fail() << "Duplicate case value " << value << " in OpSwitch in block "
+                              << construct->begin_id;
+            }
+            case_values.insert(value);
+            if (block_to_values.count(case_target_id) == 0) {
+                case_targets.push_back(case_target_id);
+            }
+            block_to_values[case_target_id].push_back(value);
+        }
+
+        for (uint32_t case_target_id : case_targets) {
+            auto* case_block = GetBlockInfo(case_target_id);
+
+            case_block->case_values =
+                std::make_unique<std::vector<uint64_t>>(std::move(block_to_values[case_target_id]));
+
+            // A case target can't be a back-edge.
+            if (construct->begin_pos >= case_block->pos) {
+                // An OpSwitch must dominate its cases.  Also, it can't be a self-loop
+                // as that would be a backedge, and backedges can only target a loop,
+                // and loops use an OpLoopMerge instruction, which can't preceded an
+                // OpSwitch.
+                return Fail() << "Switch branch from block " << construct->begin_id
+                              << " to case target block " << case_target_id
+                              << " can't be a back-edge";
+            }
+            // A case target can be the merge block, but can't go past it.
+            if (construct->end_pos < case_block->pos) {
+                return Fail() << "Switch branch from block " << construct->begin_id
+                              << " to case target block " << case_target_id
+                              << " escapes the selection construct";
+            }
+            if (case_block->header_for_merge != 0 &&
+                case_block->header_for_merge != construct->begin_id) {
+                // The switch instruction for this case block is an alternate path to
+                // the merge block, and hence the merge block is not dominated by its
+                // own (different) header.
+                return Fail() << "Block " << case_block->id
+                              << " is a case block for switch-selection header "
+                              << construct->begin_id << " and also the merge block for "
+                              << case_block->header_for_merge << " (violates dominance rule)";
+            }
+
+            // Mark the target as a case target.
+            if (case_block->case_head_for) {
+                // An OpSwitch must dominate its cases.
+                return Fail() << "Block " << case_target_id
+                              << " is declared as the switch case target for two OpSwitch "
+                                 "instructions, at blocks "
+                              << case_block->case_head_for->begin_id << " and "
+                              << construct->begin_id;
+            }
+            case_block->case_head_for = construct.get();
+        }
     }
-    // A default target can be the merge block, but can't go past it.
-    if (construct->end_pos < default_block->pos) {
-      return Fail() << "Switch branch from block " << construct->begin_id
-                    << " to default block " << default_id
-                    << " escapes the selection construct";
-    }
-    if (default_block->default_head_for) {
-      // An OpSwitch must dominate its cases, including the default target.
-      return Fail() << "Block " << default_id
-                    << " is declared as the default target for two OpSwitch "
-                       "instructions, at blocks "
-                    << default_block->default_head_for->begin_id << " and "
-                    << construct->begin_id;
-    }
-    if ((default_block->header_for_merge != 0) &&
-        (default_block->header_for_merge != construct->begin_id)) {
-      // The switch instruction for this default block is an alternate path to
-      // the merge block, and hence the merge block is not dominated by its own
-      // (different) header.
-      return Fail() << "Block " << default_block->id
-                    << " is the default block for switch-selection header "
-                    << construct->begin_id << " and also the merge block for "
-                    << default_block->header_for_merge
-                    << " (violates dominance rule)";
-    }
-
-    default_block->default_head_for = construct.get();
-    default_block->default_is_merge = default_block->pos == construct->end_pos;
-
-    // Map a case target to the list of values selecting that case.
-    std::unordered_map<uint32_t, std::vector<uint64_t>> block_to_values;
-    std::vector<uint32_t> case_targets;
-    std::unordered_set<uint64_t> case_values;
-
-    // Process case targets.
-    for (uint32_t iarg = 2; iarg + 1 < branch->NumInOperands(); iarg += 2) {
-      const auto value = branch->GetInOperand(iarg).AsLiteralUint64();
-      const auto case_target_id = branch->GetSingleWordInOperand(iarg + 1);
-
-      if (case_values.count(value)) {
-        return Fail() << "Duplicate case value " << value
-                      << " in OpSwitch in block " << construct->begin_id;
-      }
-      case_values.insert(value);
-      if (block_to_values.count(case_target_id) == 0) {
-        case_targets.push_back(case_target_id);
-      }
-      block_to_values[case_target_id].push_back(value);
-    }
-
-    for (uint32_t case_target_id : case_targets) {
-      auto* case_block = GetBlockInfo(case_target_id);
-
-      case_block->case_values = std::make_unique<std::vector<uint64_t>>(
-          std::move(block_to_values[case_target_id]));
-
-      // A case target can't be a back-edge.
-      if (construct->begin_pos >= case_block->pos) {
-        // An OpSwitch must dominate its cases.  Also, it can't be a self-loop
-        // as that would be a backedge, and backedges can only target a loop,
-        // and loops use an OpLoopMerge instruction, which can't preceded an
-        // OpSwitch.
-        return Fail() << "Switch branch from block " << construct->begin_id
-                      << " to case target block " << case_target_id
-                      << " can't be a back-edge";
-      }
-      // A case target can be the merge block, but can't go past it.
-      if (construct->end_pos < case_block->pos) {
-        return Fail() << "Switch branch from block " << construct->begin_id
-                      << " to case target block " << case_target_id
-                      << " escapes the selection construct";
-      }
-      if (case_block->header_for_merge != 0 &&
-          case_block->header_for_merge != construct->begin_id) {
-        // The switch instruction for this case block is an alternate path to
-        // the merge block, and hence the merge block is not dominated by its
-        // own (different) header.
-        return Fail() << "Block " << case_block->id
-                      << " is a case block for switch-selection header "
-                      << construct->begin_id << " and also the merge block for "
-                      << case_block->header_for_merge
-                      << " (violates dominance rule)";
-      }
-
-      // Mark the target as a case target.
-      if (case_block->case_head_for) {
-        // An OpSwitch must dominate its cases.
-        return Fail()
-               << "Block " << case_target_id
-               << " is declared as the switch case target for two OpSwitch "
-                  "instructions, at blocks "
-               << case_block->case_head_for->begin_id << " and "
-               << construct->begin_id;
-      }
-      case_block->case_head_for = construct.get();
-    }
-  }
-  return success();
+    return success();
 }
 
 BlockInfo* FunctionEmitter::HeaderIfBreakable(const Construct* c) {
-  if (c == nullptr) {
-    return nullptr;
-  }
-  switch (c->kind) {
-    case Construct::kLoop:
-    case Construct::kSwitchSelection:
-      return GetBlockInfo(c->begin_id);
-    case Construct::kContinue: {
-      const auto* continue_target = GetBlockInfo(c->begin_id);
-      return GetBlockInfo(continue_target->header_for_continue);
+    if (c == nullptr) {
+        return nullptr;
     }
-    default:
-      break;
-  }
-  return nullptr;
+    switch (c->kind) {
+        case Construct::kLoop:
+        case Construct::kSwitchSelection:
+            return GetBlockInfo(c->begin_id);
+        case Construct::kContinue: {
+            const auto* continue_target = GetBlockInfo(c->begin_id);
+            return GetBlockInfo(continue_target->header_for_continue);
+        }
+        default:
+            break;
+    }
+    return nullptr;
 }
 
-const Construct* FunctionEmitter::SiblingLoopConstruct(
-    const Construct* c) const {
-  if (c == nullptr || c->kind != Construct::kContinue) {
-    return nullptr;
-  }
-  const uint32_t continue_target_id = c->begin_id;
-  const auto* continue_target = GetBlockInfo(continue_target_id);
-  const uint32_t header_id = continue_target->header_for_continue;
-  if (continue_target_id == header_id) {
-    // The continue target is the whole loop.
-    return nullptr;
-  }
-  const auto* candidate = GetBlockInfo(header_id)->construct;
-  // Walk up the construct tree until we hit the loop.  In future
-  // we might handle the corner case where the same block is both a
-  // loop header and a selection header. For example, where the
-  // loop header block has a conditional branch going to distinct
-  // targets inside the loop body.
-  while (candidate && candidate->kind != Construct::kLoop) {
-    candidate = candidate->parent;
-  }
-  return candidate;
+const Construct* FunctionEmitter::SiblingLoopConstruct(const Construct* c) const {
+    if (c == nullptr || c->kind != Construct::kContinue) {
+        return nullptr;
+    }
+    const uint32_t continue_target_id = c->begin_id;
+    const auto* continue_target = GetBlockInfo(continue_target_id);
+    const uint32_t header_id = continue_target->header_for_continue;
+    if (continue_target_id == header_id) {
+        // The continue target is the whole loop.
+        return nullptr;
+    }
+    const auto* candidate = GetBlockInfo(header_id)->construct;
+    // Walk up the construct tree until we hit the loop.  In future
+    // we might handle the corner case where the same block is both a
+    // loop header and a selection header. For example, where the
+    // loop header block has a conditional branch going to distinct
+    // targets inside the loop body.
+    while (candidate && candidate->kind != Construct::kLoop) {
+        candidate = candidate->parent;
+    }
+    return candidate;
 }
 
 bool FunctionEmitter::ClassifyCFGEdges() {
-  if (failed()) {
-    return false;
-  }
-
-  // Checks validity of CFG edges leaving each basic block.  This implicitly
-  // checks dominance rules for headers and continue constructs.
-  //
-  // For each branch encountered, classify each edge (S,T) as:
-  //    - a back-edge
-  //    - a structured exit (specific ways of branching to enclosing construct)
-  //    - a normal (forward) edge, either natural control flow or a case
-  //    fallthrough
-  //
-  // If more than one block is targeted by a normal edge, then S must be a
-  // structured header.
-  //
-  // Term: NEC(B) is the nearest enclosing construct for B.
-  //
-  // If edge (S,T) is a normal edge, and NEC(S) != NEC(T), then
-  //    T is the header block of its NEC(T), and
-  //    NEC(S) is the parent of NEC(T).
-
-  for (const auto src : block_order_) {
-    TINT_ASSERT(Reader, src > 0);
-    auto* src_info = GetBlockInfo(src);
-    TINT_ASSERT(Reader, src_info);
-    const auto src_pos = src_info->pos;
-    const auto& src_construct = *(src_info->construct);
-
-    // Compute the ordered list of unique successors.
-    std::vector<uint32_t> successors;
-    {
-      std::unordered_set<uint32_t> visited;
-      src_info->basic_block->ForEachSuccessorLabel(
-          [&successors, &visited](const uint32_t succ) {
-            if (visited.count(succ) == 0) {
-              successors.push_back(succ);
-              visited.insert(succ);
-            }
-          });
+    if (failed()) {
+        return false;
     }
 
-    // There should only be one backedge per backedge block.
-    uint32_t num_backedges = 0;
+    // Checks validity of CFG edges leaving each basic block.  This implicitly
+    // checks dominance rules for headers and continue constructs.
+    //
+    // For each branch encountered, classify each edge (S,T) as:
+    //    - a back-edge
+    //    - a structured exit (specific ways of branching to enclosing construct)
+    //    - a normal (forward) edge, either natural control flow or a case
+    //    fallthrough
+    //
+    // If more than one block is targeted by a normal edge, then S must be a
+    // structured header.
+    //
+    // Term: NEC(B) is the nearest enclosing construct for B.
+    //
+    // If edge (S,T) is a normal edge, and NEC(S) != NEC(T), then
+    //    T is the header block of its NEC(T), and
+    //    NEC(S) is the parent of NEC(T).
 
-    // Track destinations for normal forward edges, either kForward
-    // or kCaseFallThrough. These count toward the need
-    // to have a merge instruction.  We also track kIfBreak edges
-    // because when used with normal forward edges, we'll need
-    // to generate a flow guard variable.
-    std::vector<uint32_t> normal_forward_edges;
-    std::vector<uint32_t> if_break_edges;
+    for (const auto src : block_order_) {
+        TINT_ASSERT(Reader, src > 0);
+        auto* src_info = GetBlockInfo(src);
+        TINT_ASSERT(Reader, src_info);
+        const auto src_pos = src_info->pos;
+        const auto& src_construct = *(src_info->construct);
 
-    if (successors.empty() && src_construct.enclosing_continue) {
-      // Kill and return are not allowed in a continue construct.
-      return Fail() << "Invalid function exit at block " << src
-                    << " from continue construct starting at "
-                    << src_construct.enclosing_continue->begin_id;
+        // Compute the ordered list of unique successors.
+        std::vector<uint32_t> successors;
+        {
+            std::unordered_set<uint32_t> visited;
+            src_info->basic_block->ForEachSuccessorLabel(
+                [&successors, &visited](const uint32_t succ) {
+                    if (visited.count(succ) == 0) {
+                        successors.push_back(succ);
+                        visited.insert(succ);
+                    }
+                });
+        }
+
+        // There should only be one backedge per backedge block.
+        uint32_t num_backedges = 0;
+
+        // Track destinations for normal forward edges, either kForward
+        // or kCaseFallThrough. These count toward the need
+        // to have a merge instruction.  We also track kIfBreak edges
+        // because when used with normal forward edges, we'll need
+        // to generate a flow guard variable.
+        std::vector<uint32_t> normal_forward_edges;
+        std::vector<uint32_t> if_break_edges;
+
+        if (successors.empty() && src_construct.enclosing_continue) {
+            // Kill and return are not allowed in a continue construct.
+            return Fail() << "Invalid function exit at block " << src
+                          << " from continue construct starting at "
+                          << src_construct.enclosing_continue->begin_id;
+        }
+
+        for (const auto dest : successors) {
+            const auto* dest_info = GetBlockInfo(dest);
+            // We've already checked terminators are valid.
+            TINT_ASSERT(Reader, dest_info);
+            const auto dest_pos = dest_info->pos;
+
+            // Insert the edge kind entry and keep a handle to update
+            // its classification.
+            EdgeKind& edge_kind = src_info->succ_edge[dest];
+
+            if (src_pos >= dest_pos) {
+                // This is a backedge.
+                edge_kind = EdgeKind::kBack;
+                num_backedges++;
+                const auto* continue_construct = src_construct.enclosing_continue;
+                if (!continue_construct) {
+                    return Fail() << "Invalid backedge (" << src << "->" << dest << "): " << src
+                                  << " is not in a continue construct";
+                }
+                if (src_pos != continue_construct->end_pos - 1) {
+                    return Fail() << "Invalid exit (" << src << "->" << dest
+                                  << ") from continue construct: " << src
+                                  << " is not the last block in the continue construct "
+                                     "starting at "
+                                  << src_construct.begin_id << " (violates post-dominance rule)";
+                }
+                const auto* ct_info = GetBlockInfo(continue_construct->begin_id);
+                TINT_ASSERT(Reader, ct_info);
+                if (ct_info->header_for_continue != dest) {
+                    return Fail() << "Invalid backedge (" << src << "->" << dest
+                                  << "): does not branch to the corresponding loop header, "
+                                     "expected "
+                                  << ct_info->header_for_continue;
+                }
+            } else {
+                // This is a forward edge.
+                // For now, classify it that way, but we might update it.
+                edge_kind = EdgeKind::kForward;
+
+                // Exit from a continue construct can only be from the last block.
+                const auto* continue_construct = src_construct.enclosing_continue;
+                if (continue_construct != nullptr) {
+                    if (continue_construct->ContainsPos(src_pos) &&
+                        !continue_construct->ContainsPos(dest_pos) &&
+                        (src_pos != continue_construct->end_pos - 1)) {
+                        return Fail()
+                               << "Invalid exit (" << src << "->" << dest
+                               << ") from continue construct: " << src
+                               << " is not the last block in the continue construct "
+                                  "starting at "
+                               << continue_construct->begin_id << " (violates post-dominance rule)";
+                    }
+                }
+
+                // Check valid structured exit cases.
+
+                if (edge_kind == EdgeKind::kForward) {
+                    // Check for a 'break' from a loop or from a switch.
+                    const auto* breakable_header =
+                        HeaderIfBreakable(src_construct.enclosing_loop_or_continue_or_switch);
+                    if (breakable_header != nullptr) {
+                        if (dest == breakable_header->merge_for_header) {
+                            // It's a break.
+                            edge_kind =
+                                (breakable_header->construct->kind == Construct::kSwitchSelection)
+                                    ? EdgeKind::kSwitchBreak
+                                    : EdgeKind::kLoopBreak;
+                        }
+                    }
+                }
+
+                if (edge_kind == EdgeKind::kForward) {
+                    // Check for a 'continue' from within a loop.
+                    const auto* loop_header = HeaderIfBreakable(src_construct.enclosing_loop);
+                    if (loop_header != nullptr) {
+                        if (dest == loop_header->continue_for_header) {
+                            // It's a continue.
+                            edge_kind = EdgeKind::kLoopContinue;
+                        }
+                    }
+                }
+
+                if (edge_kind == EdgeKind::kForward) {
+                    const auto& header_info = *GetBlockInfo(src_construct.begin_id);
+                    if (dest == header_info.merge_for_header) {
+                        // Branch to construct's merge block.  The loop break and
+                        // switch break cases have already been covered.
+                        edge_kind = EdgeKind::kIfBreak;
+                    }
+                }
+
+                // A forward edge into a case construct that comes from something
+                // other than the OpSwitch is actually a fallthrough.
+                if (edge_kind == EdgeKind::kForward) {
+                    const auto* switch_construct =
+                        (dest_info->case_head_for ? dest_info->case_head_for
+                                                  : dest_info->default_head_for);
+                    if (switch_construct != nullptr) {
+                        if (src != switch_construct->begin_id) {
+                            edge_kind = EdgeKind::kCaseFallThrough;
+                        }
+                    }
+                }
+
+                // The edge-kind has been finalized.
+
+                if ((edge_kind == EdgeKind::kForward) ||
+                    (edge_kind == EdgeKind::kCaseFallThrough)) {
+                    normal_forward_edges.push_back(dest);
+                }
+                if (edge_kind == EdgeKind::kIfBreak) {
+                    if_break_edges.push_back(dest);
+                }
+
+                if ((edge_kind == EdgeKind::kForward) ||
+                    (edge_kind == EdgeKind::kCaseFallThrough)) {
+                    // Check for an invalid forward exit out of this construct.
+                    if (dest_info->pos > src_construct.end_pos) {
+                        // In most cases we're bypassing the merge block for the source
+                        // construct.
+                        auto end_block = src_construct.end_id;
+                        const char* end_block_desc = "merge block";
+                        if (src_construct.kind == Construct::kLoop) {
+                            // For a loop construct, we have two valid places to go: the
+                            // continue target or the merge for the loop header, which is
+                            // further down.
+                            const auto loop_merge =
+                                GetBlockInfo(src_construct.begin_id)->merge_for_header;
+                            if (dest_info->pos >= GetBlockInfo(loop_merge)->pos) {
+                                // We're bypassing the loop's merge block.
+                                end_block = loop_merge;
+                            } else {
+                                // We're bypassing the loop's continue target, and going into
+                                // the middle of the continue construct.
+                                end_block_desc = "continue target";
+                            }
+                        }
+                        return Fail() << "Branch from block " << src << " to block " << dest
+                                      << " is an invalid exit from construct starting at block "
+                                      << src_construct.begin_id << "; branch bypasses "
+                                      << end_block_desc << " " << end_block;
+                    }
+
+                    // Check dominance.
+
+                    //      Look for edges that violate the dominance condition: a branch
+                    //      from X to Y where:
+                    //        If Y is in a nearest enclosing continue construct headed by
+                    //        CT:
+                    //          Y is not CT, and
+                    //          In the structured order, X appears before CT order or
+                    //          after CT's backedge block.
+                    //        Otherwise, if Y is in a nearest enclosing construct
+                    //        headed by H:
+                    //          Y is not H, and
+                    //          In the structured order, X appears before H or after H's
+                    //          merge block.
+
+                    const auto& dest_construct = *(dest_info->construct);
+                    if (dest != dest_construct.begin_id && !dest_construct.ContainsPos(src_pos)) {
+                        return Fail()
+                               << "Branch from " << src << " to " << dest << " bypasses "
+                               << (dest_construct.kind == Construct::kContinue ? "continue target "
+                                                                               : "header ")
+                               << dest_construct.begin_id << " (dominance rule violated)";
+                    }
+                }
+            }  // end forward edge
+        }      // end successor
+
+        if (num_backedges > 1) {
+            return Fail() << "Block " << src << " has too many backedges: " << num_backedges;
+        }
+        if ((normal_forward_edges.size() > 1) && (src_info->merge_for_header == 0)) {
+            return Fail() << "Control flow diverges at block " << src << " (to "
+                          << normal_forward_edges[0] << ", " << normal_forward_edges[1]
+                          << ") but it is not a structured header (it has no merge "
+                             "instruction)";
+        }
+        if ((normal_forward_edges.size() + if_break_edges.size() > 1) &&
+            (src_info->merge_for_header == 0)) {
+            // There is a branch to the merge of an if-selection combined
+            // with an other normal forward branch.  Control within the
+            // if-selection needs to be gated by a flow predicate.
+            for (auto if_break_dest : if_break_edges) {
+                auto* head_info = GetBlockInfo(GetBlockInfo(if_break_dest)->header_for_merge);
+                // Generate a guard name, but only once.
+                if (head_info->flow_guard_name.empty()) {
+                    const std::string guard = "guard" + std::to_string(head_info->id);
+                    head_info->flow_guard_name = namer_.MakeDerivedName(guard);
+                }
+            }
+        }
     }
 
-    for (const auto dest : successors) {
-      const auto* dest_info = GetBlockInfo(dest);
-      // We've already checked terminators are valid.
-      TINT_ASSERT(Reader, dest_info);
-      const auto dest_pos = dest_info->pos;
-
-      // Insert the edge kind entry and keep a handle to update
-      // its classification.
-      EdgeKind& edge_kind = src_info->succ_edge[dest];
-
-      if (src_pos >= dest_pos) {
-        // This is a backedge.
-        edge_kind = EdgeKind::kBack;
-        num_backedges++;
-        const auto* continue_construct = src_construct.enclosing_continue;
-        if (!continue_construct) {
-          return Fail() << "Invalid backedge (" << src << "->" << dest
-                        << "): " << src << " is not in a continue construct";
-        }
-        if (src_pos != continue_construct->end_pos - 1) {
-          return Fail() << "Invalid exit (" << src << "->" << dest
-                        << ") from continue construct: " << src
-                        << " is not the last block in the continue construct "
-                           "starting at "
-                        << src_construct.begin_id
-                        << " (violates post-dominance rule)";
-        }
-        const auto* ct_info = GetBlockInfo(continue_construct->begin_id);
-        TINT_ASSERT(Reader, ct_info);
-        if (ct_info->header_for_continue != dest) {
-          return Fail()
-                 << "Invalid backedge (" << src << "->" << dest
-                 << "): does not branch to the corresponding loop header, "
-                    "expected "
-                 << ct_info->header_for_continue;
-        }
-      } else {
-        // This is a forward edge.
-        // For now, classify it that way, but we might update it.
-        edge_kind = EdgeKind::kForward;
-
-        // Exit from a continue construct can only be from the last block.
-        const auto* continue_construct = src_construct.enclosing_continue;
-        if (continue_construct != nullptr) {
-          if (continue_construct->ContainsPos(src_pos) &&
-              !continue_construct->ContainsPos(dest_pos) &&
-              (src_pos != continue_construct->end_pos - 1)) {
-            return Fail() << "Invalid exit (" << src << "->" << dest
-                          << ") from continue construct: " << src
-                          << " is not the last block in the continue construct "
-                             "starting at "
-                          << continue_construct->begin_id
-                          << " (violates post-dominance rule)";
-          }
-        }
-
-        // Check valid structured exit cases.
-
-        if (edge_kind == EdgeKind::kForward) {
-          // Check for a 'break' from a loop or from a switch.
-          const auto* breakable_header = HeaderIfBreakable(
-              src_construct.enclosing_loop_or_continue_or_switch);
-          if (breakable_header != nullptr) {
-            if (dest == breakable_header->merge_for_header) {
-              // It's a break.
-              edge_kind = (breakable_header->construct->kind ==
-                           Construct::kSwitchSelection)
-                              ? EdgeKind::kSwitchBreak
-                              : EdgeKind::kLoopBreak;
-            }
-          }
-        }
-
-        if (edge_kind == EdgeKind::kForward) {
-          // Check for a 'continue' from within a loop.
-          const auto* loop_header =
-              HeaderIfBreakable(src_construct.enclosing_loop);
-          if (loop_header != nullptr) {
-            if (dest == loop_header->continue_for_header) {
-              // It's a continue.
-              edge_kind = EdgeKind::kLoopContinue;
-            }
-          }
-        }
-
-        if (edge_kind == EdgeKind::kForward) {
-          const auto& header_info = *GetBlockInfo(src_construct.begin_id);
-          if (dest == header_info.merge_for_header) {
-            // Branch to construct's merge block.  The loop break and
-            // switch break cases have already been covered.
-            edge_kind = EdgeKind::kIfBreak;
-          }
-        }
-
-        // A forward edge into a case construct that comes from something
-        // other than the OpSwitch is actually a fallthrough.
-        if (edge_kind == EdgeKind::kForward) {
-          const auto* switch_construct =
-              (dest_info->case_head_for ? dest_info->case_head_for
-                                        : dest_info->default_head_for);
-          if (switch_construct != nullptr) {
-            if (src != switch_construct->begin_id) {
-              edge_kind = EdgeKind::kCaseFallThrough;
-            }
-          }
-        }
-
-        // The edge-kind has been finalized.
-
-        if ((edge_kind == EdgeKind::kForward) ||
-            (edge_kind == EdgeKind::kCaseFallThrough)) {
-          normal_forward_edges.push_back(dest);
-        }
-        if (edge_kind == EdgeKind::kIfBreak) {
-          if_break_edges.push_back(dest);
-        }
-
-        if ((edge_kind == EdgeKind::kForward) ||
-            (edge_kind == EdgeKind::kCaseFallThrough)) {
-          // Check for an invalid forward exit out of this construct.
-          if (dest_info->pos > src_construct.end_pos) {
-            // In most cases we're bypassing the merge block for the source
-            // construct.
-            auto end_block = src_construct.end_id;
-            const char* end_block_desc = "merge block";
-            if (src_construct.kind == Construct::kLoop) {
-              // For a loop construct, we have two valid places to go: the
-              // continue target or the merge for the loop header, which is
-              // further down.
-              const auto loop_merge =
-                  GetBlockInfo(src_construct.begin_id)->merge_for_header;
-              if (dest_info->pos >= GetBlockInfo(loop_merge)->pos) {
-                // We're bypassing the loop's merge block.
-                end_block = loop_merge;
-              } else {
-                // We're bypassing the loop's continue target, and going into
-                // the middle of the continue construct.
-                end_block_desc = "continue target";
-              }
-            }
-            return Fail()
-                   << "Branch from block " << src << " to block " << dest
-                   << " is an invalid exit from construct starting at block "
-                   << src_construct.begin_id << "; branch bypasses "
-                   << end_block_desc << " " << end_block;
-          }
-
-          // Check dominance.
-
-          //      Look for edges that violate the dominance condition: a branch
-          //      from X to Y where:
-          //        If Y is in a nearest enclosing continue construct headed by
-          //        CT:
-          //          Y is not CT, and
-          //          In the structured order, X appears before CT order or
-          //          after CT's backedge block.
-          //        Otherwise, if Y is in a nearest enclosing construct
-          //        headed by H:
-          //          Y is not H, and
-          //          In the structured order, X appears before H or after H's
-          //          merge block.
-
-          const auto& dest_construct = *(dest_info->construct);
-          if (dest != dest_construct.begin_id &&
-              !dest_construct.ContainsPos(src_pos)) {
-            return Fail() << "Branch from " << src << " to " << dest
-                          << " bypasses "
-                          << (dest_construct.kind == Construct::kContinue
-                                  ? "continue target "
-                                  : "header ")
-                          << dest_construct.begin_id
-                          << " (dominance rule violated)";
-          }
-        }
-      }  // end forward edge
-    }    // end successor
-
-    if (num_backedges > 1) {
-      return Fail() << "Block " << src
-                    << " has too many backedges: " << num_backedges;
-    }
-    if ((normal_forward_edges.size() > 1) &&
-        (src_info->merge_for_header == 0)) {
-      return Fail() << "Control flow diverges at block " << src << " (to "
-                    << normal_forward_edges[0] << ", "
-                    << normal_forward_edges[1]
-                    << ") but it is not a structured header (it has no merge "
-                       "instruction)";
-    }
-    if ((normal_forward_edges.size() + if_break_edges.size() > 1) &&
-        (src_info->merge_for_header == 0)) {
-      // There is a branch to the merge of an if-selection combined
-      // with an other normal forward branch.  Control within the
-      // if-selection needs to be gated by a flow predicate.
-      for (auto if_break_dest : if_break_edges) {
-        auto* head_info =
-            GetBlockInfo(GetBlockInfo(if_break_dest)->header_for_merge);
-        // Generate a guard name, but only once.
-        if (head_info->flow_guard_name.empty()) {
-          const std::string guard = "guard" + std::to_string(head_info->id);
-          head_info->flow_guard_name = namer_.MakeDerivedName(guard);
-        }
-      }
-    }
-  }
-
-  return success();
+    return success();
 }
 
 bool FunctionEmitter::FindIfSelectionInternalHeaders() {
-  if (failed()) {
-    return false;
-  }
-  for (auto& construct : constructs_) {
-    if (construct->kind != Construct::kIfSelection) {
-      continue;
+    if (failed()) {
+        return false;
     }
-    auto* if_header_info = GetBlockInfo(construct->begin_id);
-    const auto* branch = if_header_info->basic_block->terminator();
-    const auto true_head = branch->GetSingleWordInOperand(1);
-    const auto false_head = branch->GetSingleWordInOperand(2);
-
-    auto* true_head_info = GetBlockInfo(true_head);
-    auto* false_head_info = GetBlockInfo(false_head);
-    const auto true_head_pos = true_head_info->pos;
-    const auto false_head_pos = false_head_info->pos;
-
-    const bool contains_true = construct->ContainsPos(true_head_pos);
-    const bool contains_false = construct->ContainsPos(false_head_pos);
-
-    // The cases for each edge are:
-    //  - kBack: invalid because it's an invalid exit from the selection
-    //  - kSwitchBreak ; record this for later special processing
-    //  - kLoopBreak ; record this for later special processing
-    //  - kLoopContinue ; record this for later special processing
-    //  - kIfBreak; normal case, may require a guard variable.
-    //  - kFallThrough; invalid exit from the selection
-    //  - kForward; normal case
-
-    if_header_info->true_kind = if_header_info->succ_edge[true_head];
-    if_header_info->false_kind = if_header_info->succ_edge[false_head];
-    if (contains_true) {
-      if_header_info->true_head = true_head;
-    }
-    if (contains_false) {
-      if_header_info->false_head = false_head;
-    }
-
-    if (contains_true && (true_head_info->header_for_merge != 0) &&
-        (true_head_info->header_for_merge != construct->begin_id)) {
-      // The OpBranchConditional instruction for the true head block is an
-      // alternate path to the merge block of a construct nested inside the
-      // selection, and hence the merge block is not dominated by its own
-      // (different) header.
-      return Fail() << "Block " << true_head
-                    << " is the true branch for if-selection header "
-                    << construct->begin_id
-                    << " and also the merge block for header block "
-                    << true_head_info->header_for_merge
-                    << " (violates dominance rule)";
-    }
-    if (contains_false && (false_head_info->header_for_merge != 0) &&
-        (false_head_info->header_for_merge != construct->begin_id)) {
-      // The OpBranchConditional instruction for the false head block is an
-      // alternate path to the merge block of a construct nested inside the
-      // selection, and hence the merge block is not dominated by its own
-      // (different) header.
-      return Fail() << "Block " << false_head
-                    << " is the false branch for if-selection header "
-                    << construct->begin_id
-                    << " and also the merge block for header block "
-                    << false_head_info->header_for_merge
-                    << " (violates dominance rule)";
-    }
-
-    if (contains_true && contains_false && (true_head_pos != false_head_pos)) {
-      // This construct has both a "then" clause and an "else" clause.
-      //
-      // We have this structure:
-      //
-      //   Option 1:
-      //
-      //     * condbranch
-      //        * true-head (start of then-clause)
-      //        ...
-      //        * end-then-clause
-      //        * false-head (start of else-clause)
-      //        ...
-      //        * end-false-clause
-      //        * premerge-head
-      //        ...
-      //     * selection merge
-      //
-      //   Option 2:
-      //
-      //     * condbranch
-      //        * true-head (start of then-clause)
-      //        ...
-      //        * end-then-clause
-      //        * false-head (start of else-clause) and also premerge-head
-      //        ...
-      //        * end-false-clause
-      //     * selection merge
-      //
-      //   Option 3:
-      //
-      //     * condbranch
-      //        * false-head (start of else-clause)
-      //        ...
-      //        * end-else-clause
-      //        * true-head (start of then-clause) and also premerge-head
-      //        ...
-      //        * end-then-clause
-      //     * selection merge
-      //
-      // The premerge-head exists if there is a kForward branch from the end
-      // of the first clause to a block within the surrounding selection.
-      // The first clause might be a then-clause or an else-clause.
-      const auto second_head = std::max(true_head_pos, false_head_pos);
-      const auto end_first_clause_pos = second_head - 1;
-      TINT_ASSERT(Reader, end_first_clause_pos < block_order_.size());
-      const auto end_first_clause = block_order_[end_first_clause_pos];
-      uint32_t premerge_id = 0;
-      uint32_t if_break_id = 0;
-      for (auto& then_succ_iter : GetBlockInfo(end_first_clause)->succ_edge) {
-        const uint32_t dest_id = then_succ_iter.first;
-        const auto edge_kind = then_succ_iter.second;
-        switch (edge_kind) {
-          case EdgeKind::kIfBreak:
-            if_break_id = dest_id;
-            break;
-          case EdgeKind::kForward: {
-            if (construct->ContainsPos(GetBlockInfo(dest_id)->pos)) {
-              // It's a premerge.
-              if (premerge_id != 0) {
-                // TODO(dneto): I think this is impossible to trigger at this
-                // point in the flow. It would require a merge instruction to
-                // get past the check of "at-most-one-forward-edge".
-                return Fail()
-                       << "invalid structure: then-clause headed by block "
-                       << true_head << " ending at block " << end_first_clause
-                       << " has two forward edges to within selection"
-                       << " going to " << premerge_id << " and " << dest_id;
-              }
-              premerge_id = dest_id;
-              auto* dest_block_info = GetBlockInfo(dest_id);
-              if_header_info->premerge_head = dest_id;
-              if (dest_block_info->header_for_merge != 0) {
-                // Premerge has two edges coming into it, from the then-clause
-                // and the else-clause. It's also, by construction, not the
-                // merge block of the if-selection.  So it must not be a merge
-                // block itself. The OpBranchConditional instruction for the
-                // false head block is an alternate path to the merge block, and
-                // hence the merge block is not dominated by its own (different)
-                // header.
-                return Fail()
-                       << "Block " << premerge_id << " is the merge block for "
-                       << dest_block_info->header_for_merge
-                       << " but has alternate paths reaching it, starting from"
-                       << " blocks " << true_head << " and " << false_head
-                       << " which are the true and false branches for the"
-                       << " if-selection header block " << construct->begin_id
-                       << " (violates dominance rule)";
-              }
-            }
-            break;
-          }
-          default:
-            break;
+    for (auto& construct : constructs_) {
+        if (construct->kind != Construct::kIfSelection) {
+            continue;
         }
-      }
-      if (if_break_id != 0 && premerge_id != 0) {
-        return Fail() << "Block " << end_first_clause
-                      << " in if-selection headed at block "
-                      << construct->begin_id
-                      << " branches to both the merge block " << if_break_id
-                      << " and also to block " << premerge_id
-                      << " later in the selection";
-      }
+        auto* if_header_info = GetBlockInfo(construct->begin_id);
+        const auto* branch = if_header_info->basic_block->terminator();
+        const auto true_head = branch->GetSingleWordInOperand(1);
+        const auto false_head = branch->GetSingleWordInOperand(2);
+
+        auto* true_head_info = GetBlockInfo(true_head);
+        auto* false_head_info = GetBlockInfo(false_head);
+        const auto true_head_pos = true_head_info->pos;
+        const auto false_head_pos = false_head_info->pos;
+
+        const bool contains_true = construct->ContainsPos(true_head_pos);
+        const bool contains_false = construct->ContainsPos(false_head_pos);
+
+        // The cases for each edge are:
+        //  - kBack: invalid because it's an invalid exit from the selection
+        //  - kSwitchBreak ; record this for later special processing
+        //  - kLoopBreak ; record this for later special processing
+        //  - kLoopContinue ; record this for later special processing
+        //  - kIfBreak; normal case, may require a guard variable.
+        //  - kFallThrough; invalid exit from the selection
+        //  - kForward; normal case
+
+        if_header_info->true_kind = if_header_info->succ_edge[true_head];
+        if_header_info->false_kind = if_header_info->succ_edge[false_head];
+        if (contains_true) {
+            if_header_info->true_head = true_head;
+        }
+        if (contains_false) {
+            if_header_info->false_head = false_head;
+        }
+
+        if (contains_true && (true_head_info->header_for_merge != 0) &&
+            (true_head_info->header_for_merge != construct->begin_id)) {
+            // The OpBranchConditional instruction for the true head block is an
+            // alternate path to the merge block of a construct nested inside the
+            // selection, and hence the merge block is not dominated by its own
+            // (different) header.
+            return Fail() << "Block " << true_head << " is the true branch for if-selection header "
+                          << construct->begin_id << " and also the merge block for header block "
+                          << true_head_info->header_for_merge << " (violates dominance rule)";
+        }
+        if (contains_false && (false_head_info->header_for_merge != 0) &&
+            (false_head_info->header_for_merge != construct->begin_id)) {
+            // The OpBranchConditional instruction for the false head block is an
+            // alternate path to the merge block of a construct nested inside the
+            // selection, and hence the merge block is not dominated by its own
+            // (different) header.
+            return Fail() << "Block " << false_head
+                          << " is the false branch for if-selection header " << construct->begin_id
+                          << " and also the merge block for header block "
+                          << false_head_info->header_for_merge << " (violates dominance rule)";
+        }
+
+        if (contains_true && contains_false && (true_head_pos != false_head_pos)) {
+            // This construct has both a "then" clause and an "else" clause.
+            //
+            // We have this structure:
+            //
+            //   Option 1:
+            //
+            //     * condbranch
+            //        * true-head (start of then-clause)
+            //        ...
+            //        * end-then-clause
+            //        * false-head (start of else-clause)
+            //        ...
+            //        * end-false-clause
+            //        * premerge-head
+            //        ...
+            //     * selection merge
+            //
+            //   Option 2:
+            //
+            //     * condbranch
+            //        * true-head (start of then-clause)
+            //        ...
+            //        * end-then-clause
+            //        * false-head (start of else-clause) and also premerge-head
+            //        ...
+            //        * end-false-clause
+            //     * selection merge
+            //
+            //   Option 3:
+            //
+            //     * condbranch
+            //        * false-head (start of else-clause)
+            //        ...
+            //        * end-else-clause
+            //        * true-head (start of then-clause) and also premerge-head
+            //        ...
+            //        * end-then-clause
+            //     * selection merge
+            //
+            // The premerge-head exists if there is a kForward branch from the end
+            // of the first clause to a block within the surrounding selection.
+            // The first clause might be a then-clause or an else-clause.
+            const auto second_head = std::max(true_head_pos, false_head_pos);
+            const auto end_first_clause_pos = second_head - 1;
+            TINT_ASSERT(Reader, end_first_clause_pos < block_order_.size());
+            const auto end_first_clause = block_order_[end_first_clause_pos];
+            uint32_t premerge_id = 0;
+            uint32_t if_break_id = 0;
+            for (auto& then_succ_iter : GetBlockInfo(end_first_clause)->succ_edge) {
+                const uint32_t dest_id = then_succ_iter.first;
+                const auto edge_kind = then_succ_iter.second;
+                switch (edge_kind) {
+                    case EdgeKind::kIfBreak:
+                        if_break_id = dest_id;
+                        break;
+                    case EdgeKind::kForward: {
+                        if (construct->ContainsPos(GetBlockInfo(dest_id)->pos)) {
+                            // It's a premerge.
+                            if (premerge_id != 0) {
+                                // TODO(dneto): I think this is impossible to trigger at this
+                                // point in the flow. It would require a merge instruction to
+                                // get past the check of "at-most-one-forward-edge".
+                                return Fail()
+                                       << "invalid structure: then-clause headed by block "
+                                       << true_head << " ending at block " << end_first_clause
+                                       << " has two forward edges to within selection"
+                                       << " going to " << premerge_id << " and " << dest_id;
+                            }
+                            premerge_id = dest_id;
+                            auto* dest_block_info = GetBlockInfo(dest_id);
+                            if_header_info->premerge_head = dest_id;
+                            if (dest_block_info->header_for_merge != 0) {
+                                // Premerge has two edges coming into it, from the then-clause
+                                // and the else-clause. It's also, by construction, not the
+                                // merge block of the if-selection.  So it must not be a merge
+                                // block itself. The OpBranchConditional instruction for the
+                                // false head block is an alternate path to the merge block, and
+                                // hence the merge block is not dominated by its own (different)
+                                // header.
+                                return Fail()
+                                       << "Block " << premerge_id << " is the merge block for "
+                                       << dest_block_info->header_for_merge
+                                       << " but has alternate paths reaching it, starting from"
+                                       << " blocks " << true_head << " and " << false_head
+                                       << " which are the true and false branches for the"
+                                       << " if-selection header block " << construct->begin_id
+                                       << " (violates dominance rule)";
+                            }
+                        }
+                        break;
+                    }
+                    default:
+                        break;
+                }
+            }
+            if (if_break_id != 0 && premerge_id != 0) {
+                return Fail() << "Block " << end_first_clause << " in if-selection headed at block "
+                              << construct->begin_id << " branches to both the merge block "
+                              << if_break_id << " and also to block " << premerge_id
+                              << " later in the selection";
+            }
+        }
     }
-  }
-  return success();
+    return success();
 }
 
 bool FunctionEmitter::EmitFunctionVariables() {
-  if (failed()) {
-    return false;
-  }
-  for (auto& inst : *function_.entry()) {
-    if (inst.opcode() != SpvOpVariable) {
-      continue;
-    }
-    auto* var_store_type = GetVariableStoreType(inst);
     if (failed()) {
-      return false;
-    }
-    const ast::Expression* constructor = nullptr;
-    if (inst.NumInOperands() > 1) {
-      // SPIR-V initializers are always constants.
-      // (OpenCL also allows the ID of an OpVariable, but we don't handle that
-      // here.)
-      constructor =
-          parser_impl_.MakeConstantExpression(inst.GetSingleWordInOperand(1))
-              .expr;
-      if (!constructor) {
         return false;
-      }
     }
-    auto* var = parser_impl_.MakeVariable(
-        inst.result_id(), ast::StorageClass::kNone, var_store_type, false,
-        false, constructor, ast::AttributeList{});
-    auto* var_decl_stmt = create<ast::VariableDeclStatement>(Source{}, var);
-    AddStatement(var_decl_stmt);
-    auto* var_type = ty_.Reference(var_store_type, ast::StorageClass::kNone);
-    identifier_types_.emplace(inst.result_id(), var_type);
-  }
-  return success();
+    for (auto& inst : *function_.entry()) {
+        if (inst.opcode() != SpvOpVariable) {
+            continue;
+        }
+        auto* var_store_type = GetVariableStoreType(inst);
+        if (failed()) {
+            return false;
+        }
+        const ast::Expression* constructor = nullptr;
+        if (inst.NumInOperands() > 1) {
+            // SPIR-V initializers are always constants.
+            // (OpenCL also allows the ID of an OpVariable, but we don't handle that
+            // here.)
+            constructor = parser_impl_.MakeConstantExpression(inst.GetSingleWordInOperand(1)).expr;
+            if (!constructor) {
+                return false;
+            }
+        }
+        auto* var =
+            parser_impl_.MakeVariable(inst.result_id(), ast::StorageClass::kNone, var_store_type,
+                                      false, false, constructor, ast::AttributeList{});
+        auto* var_decl_stmt = create<ast::VariableDeclStatement>(Source{}, var);
+        AddStatement(var_decl_stmt);
+        auto* var_type = ty_.Reference(var_store_type, ast::StorageClass::kNone);
+        identifier_types_.emplace(inst.result_id(), var_type);
+    }
+    return success();
 }
 
-TypedExpression FunctionEmitter::AddressOfIfNeeded(
-    TypedExpression expr,
-    const spvtools::opt::Instruction* inst) {
-  if (inst && expr) {
-    if (auto* spirv_type = type_mgr_->GetType(inst->type_id())) {
-      if (expr.type->Is<Reference>() && spirv_type->AsPointer()) {
-        return AddressOf(expr);
-      }
+TypedExpression FunctionEmitter::AddressOfIfNeeded(TypedExpression expr,
+                                                   const spvtools::opt::Instruction* inst) {
+    if (inst && expr) {
+        if (auto* spirv_type = type_mgr_->GetType(inst->type_id())) {
+            if (expr.type->Is<Reference>() && spirv_type->AsPointer()) {
+                return AddressOf(expr);
+            }
+        }
     }
-  }
-  return expr;
+    return expr;
 }
 
 TypedExpression FunctionEmitter::MakeExpression(uint32_t id) {
-  if (failed()) {
-    return {};
-  }
-  switch (GetSkipReason(id)) {
-    case SkipReason::kDontSkip:
-      break;
-    case SkipReason::kOpaqueObject:
-      Fail() << "internal error: unhandled use of opaque object with ID: "
-             << id;
-      return {};
-    case SkipReason::kSinkPointerIntoUse: {
-      // Replace the pointer with its source reference expression.
-      auto source_expr = GetDefInfo(id)->sink_pointer_source_expr;
-      TINT_ASSERT(Reader, source_expr.type->Is<Reference>());
-      return source_expr;
+    if (failed()) {
+        return {};
     }
-    case SkipReason::kPointSizeBuiltinValue: {
-      return {ty_.F32(), create<ast::FloatLiteralExpression>(Source{}, 1.0f)};
+    switch (GetSkipReason(id)) {
+        case SkipReason::kDontSkip:
+            break;
+        case SkipReason::kOpaqueObject:
+            Fail() << "internal error: unhandled use of opaque object with ID: " << id;
+            return {};
+        case SkipReason::kSinkPointerIntoUse: {
+            // Replace the pointer with its source reference expression.
+            auto source_expr = GetDefInfo(id)->sink_pointer_source_expr;
+            TINT_ASSERT(Reader, source_expr.type->Is<Reference>());
+            return source_expr;
+        }
+        case SkipReason::kPointSizeBuiltinValue: {
+            return {ty_.F32(), create<ast::FloatLiteralExpression>(Source{}, 1.0f)};
+        }
+        case SkipReason::kPointSizeBuiltinPointer:
+            Fail() << "unhandled use of a pointer to the PointSize builtin, with ID: " << id;
+            return {};
+        case SkipReason::kSampleMaskInBuiltinPointer:
+            Fail() << "unhandled use of a pointer to the SampleMask builtin, with ID: " << id;
+            return {};
+        case SkipReason::kSampleMaskOutBuiltinPointer: {
+            // The result type is always u32.
+            auto name = namer_.Name(sample_mask_out_id);
+            return TypedExpression{ty_.U32(), create<ast::IdentifierExpression>(
+                                                  Source{}, builder_.Symbols().Register(name))};
+        }
     }
-    case SkipReason::kPointSizeBuiltinPointer:
-      Fail() << "unhandled use of a pointer to the PointSize builtin, with ID: "
-             << id;
-      return {};
-    case SkipReason::kSampleMaskInBuiltinPointer:
-      Fail()
-          << "unhandled use of a pointer to the SampleMask builtin, with ID: "
-          << id;
-      return {};
-    case SkipReason::kSampleMaskOutBuiltinPointer: {
-      // The result type is always u32.
-      auto name = namer_.Name(sample_mask_out_id);
-      return TypedExpression{ty_.U32(),
-                             create<ast::IdentifierExpression>(
-                                 Source{}, builder_.Symbols().Register(name))};
+    auto type_it = identifier_types_.find(id);
+    if (type_it != identifier_types_.end()) {
+        auto name = namer_.Name(id);
+        auto* type = type_it->second;
+        return TypedExpression{
+            type, create<ast::IdentifierExpression>(Source{}, builder_.Symbols().Register(name))};
     }
-  }
-  auto type_it = identifier_types_.find(id);
-  if (type_it != identifier_types_.end()) {
-    auto name = namer_.Name(id);
-    auto* type = type_it->second;
-    return TypedExpression{type,
-                           create<ast::IdentifierExpression>(
-                               Source{}, builder_.Symbols().Register(name))};
-  }
-  if (parser_impl_.IsScalarSpecConstant(id)) {
-    auto name = namer_.Name(id);
-    return TypedExpression{
-        parser_impl_.ConvertType(def_use_mgr_->GetDef(id)->type_id()),
-        create<ast::IdentifierExpression>(Source{},
-                                          builder_.Symbols().Register(name))};
-  }
-  if (singly_used_values_.count(id)) {
-    auto expr = std::move(singly_used_values_[id]);
-    singly_used_values_.erase(id);
-    return expr;
-  }
-  const auto* spirv_constant = constant_mgr_->FindDeclaredConstant(id);
-  if (spirv_constant) {
-    return parser_impl_.MakeConstantExpression(id);
-  }
-  const auto* inst = def_use_mgr_->GetDef(id);
-  if (inst == nullptr) {
-    Fail() << "ID " << id << " does not have a defining SPIR-V instruction";
-    return {};
-  }
-  switch (inst->opcode()) {
-    case SpvOpVariable: {
-      // This occurs for module-scope variables.
-      auto name = namer_.Name(inst->result_id());
-      return TypedExpression{
-          parser_impl_.ConvertType(inst->type_id(), PtrAs::Ref),
-          create<ast::IdentifierExpression>(Source{},
-                                            builder_.Symbols().Register(name))};
+    if (parser_impl_.IsScalarSpecConstant(id)) {
+        auto name = namer_.Name(id);
+        return TypedExpression{
+            parser_impl_.ConvertType(def_use_mgr_->GetDef(id)->type_id()),
+            create<ast::IdentifierExpression>(Source{}, builder_.Symbols().Register(name))};
     }
-    case SpvOpUndef:
-      // Substitute a null value for undef.
-      // This case occurs when OpUndef appears at module scope, as if it were
-      // a constant.
-      return parser_impl_.MakeNullExpression(
-          parser_impl_.ConvertType(inst->type_id()));
+    if (singly_used_values_.count(id)) {
+        auto expr = std::move(singly_used_values_[id]);
+        singly_used_values_.erase(id);
+        return expr;
+    }
+    const auto* spirv_constant = constant_mgr_->FindDeclaredConstant(id);
+    if (spirv_constant) {
+        return parser_impl_.MakeConstantExpression(id);
+    }
+    const auto* inst = def_use_mgr_->GetDef(id);
+    if (inst == nullptr) {
+        Fail() << "ID " << id << " does not have a defining SPIR-V instruction";
+        return {};
+    }
+    switch (inst->opcode()) {
+        case SpvOpVariable: {
+            // This occurs for module-scope variables.
+            auto name = namer_.Name(inst->result_id());
+            return TypedExpression{
+                parser_impl_.ConvertType(inst->type_id(), PtrAs::Ref),
+                create<ast::IdentifierExpression>(Source{}, builder_.Symbols().Register(name))};
+        }
+        case SpvOpUndef:
+            // Substitute a null value for undef.
+            // This case occurs when OpUndef appears at module scope, as if it were
+            // a constant.
+            return parser_impl_.MakeNullExpression(parser_impl_.ConvertType(inst->type_id()));
 
-    default:
-      break;
-  }
-  if (const spvtools::opt::BasicBlock* const bb =
-          ir_context_.get_instr_block(id)) {
-    if (auto* block = GetBlockInfo(bb->id())) {
-      if (block->pos == kInvalidBlockPos) {
-        // The value came from a block not in the block order.
-        // Substitute a null value.
-        return parser_impl_.MakeNullExpression(
-            parser_impl_.ConvertType(inst->type_id()));
-      }
+        default:
+            break;
     }
-  }
-  Fail() << "unhandled expression for ID " << id << "\n" << inst->PrettyPrint();
-  return {};
+    if (const spvtools::opt::BasicBlock* const bb = ir_context_.get_instr_block(id)) {
+        if (auto* block = GetBlockInfo(bb->id())) {
+            if (block->pos == kInvalidBlockPos) {
+                // The value came from a block not in the block order.
+                // Substitute a null value.
+                return parser_impl_.MakeNullExpression(parser_impl_.ConvertType(inst->type_id()));
+            }
+        }
+    }
+    Fail() << "unhandled expression for ID " << id << "\n" << inst->PrettyPrint();
+    return {};
 }
 
 bool FunctionEmitter::EmitFunctionBodyStatements() {
-  // Dump the basic blocks in order, grouped by construct.
+    // Dump the basic blocks in order, grouped by construct.
 
-  // We maintain a stack of StatementBlock objects, where new statements
-  // are always written to the topmost entry of the stack. By this point in
-  // processing, we have already recorded the interesting control flow
-  // boundaries in the BlockInfo and associated Construct objects. As we
-  // enter a new statement grouping, we push onto the stack, and also schedule
-  // the statement block's completion and removal at a future block's ID.
+    // We maintain a stack of StatementBlock objects, where new statements
+    // are always written to the topmost entry of the stack. By this point in
+    // processing, we have already recorded the interesting control flow
+    // boundaries in the BlockInfo and associated Construct objects. As we
+    // enter a new statement grouping, we push onto the stack, and also schedule
+    // the statement block's completion and removal at a future block's ID.
 
-  // Upon entry, the statement stack has one entry representing the whole
-  // function.
-  TINT_ASSERT(Reader, !constructs_.empty());
-  Construct* function_construct = constructs_[0].get();
-  TINT_ASSERT(Reader, function_construct != nullptr);
-  TINT_ASSERT(Reader, function_construct->kind == Construct::kFunction);
-  // Make the first entry valid by filling in the construct field, which
-  // had not been computed at the time the entry was first created.
-  // TODO(dneto): refactor how the first construct is created vs.
-  // this statements stack entry is populated.
-  TINT_ASSERT(Reader, statements_stack_.size() == 1);
-  statements_stack_[0].SetConstruct(function_construct);
+    // Upon entry, the statement stack has one entry representing the whole
+    // function.
+    TINT_ASSERT(Reader, !constructs_.empty());
+    Construct* function_construct = constructs_[0].get();
+    TINT_ASSERT(Reader, function_construct != nullptr);
+    TINT_ASSERT(Reader, function_construct->kind == Construct::kFunction);
+    // Make the first entry valid by filling in the construct field, which
+    // had not been computed at the time the entry was first created.
+    // TODO(dneto): refactor how the first construct is created vs.
+    // this statements stack entry is populated.
+    TINT_ASSERT(Reader, statements_stack_.size() == 1);
+    statements_stack_[0].SetConstruct(function_construct);
 
-  for (auto block_id : block_order()) {
-    if (!EmitBasicBlock(*GetBlockInfo(block_id))) {
-      return false;
+    for (auto block_id : block_order()) {
+        if (!EmitBasicBlock(*GetBlockInfo(block_id))) {
+            return false;
+        }
     }
-  }
-  return success();
+    return success();
 }
 
 bool FunctionEmitter::EmitBasicBlock(const BlockInfo& block_info) {
-  // Close off previous constructs.
-  while (!statements_stack_.empty() &&
-         (statements_stack_.back().GetEndId() == block_info.id)) {
-    statements_stack_.back().Finalize(&builder_);
-    statements_stack_.pop_back();
-  }
-  if (statements_stack_.empty()) {
-    return Fail() << "internal error: statements stack empty at block "
-                  << block_info.id;
-  }
-
-  // Enter new constructs.
-
-  std::vector<const Construct*> entering_constructs;  // inner most comes first
-  {
-    auto* here = block_info.construct;
-    auto* const top_construct = statements_stack_.back().GetConstruct();
-    while (here != top_construct) {
-      // Only enter a construct at its header block.
-      if (here->begin_id == block_info.id) {
-        entering_constructs.push_back(here);
-      }
-      here = here->parent;
+    // Close off previous constructs.
+    while (!statements_stack_.empty() && (statements_stack_.back().GetEndId() == block_info.id)) {
+        statements_stack_.back().Finalize(&builder_);
+        statements_stack_.pop_back();
     }
-  }
-  // What constructs can we have entered?
-  // - It can't be kFunction, because there is only one of those, and it was
-  //   already on the stack at the outermost level.
-  // - We have at most one of kSwitchSelection, or kLoop because each of those
-  //   is headed by a block with a merge instruction (OpLoopMerge for kLoop,
-  //   and OpSelectionMerge for kSwitchSelection).
-  // - When there is a kIfSelection, it can't contain another construct,
-  //   because both would have to have their own distinct merge instructions
-  //   and distinct terminators.
-  // - A kContinue can contain a kContinue
-  //   This is possible in Vulkan SPIR-V, but Tint disallows this by the rule
-  //   that a block can be continue target for at most one header block. See
-  //   test DISABLED_BlockIsContinueForMoreThanOneHeader. If we generalize this,
-  //   then by a dominance argument, the inner loop continue target can only be
-  //   a single-block loop.
-  // TODO(dneto): Handle this case.
-  // - If a kLoop is on the outside, its terminator is either:
-  //   - an OpBranch, in which case there is no other construct.
-  //   - an OpBranchConditional, in which case there is either an kIfSelection
-  //     (when both branch targets are different and are inside the loop),
-  //     or no other construct (because the branch targets are the same,
-  //     or one of them is a break or continue).
-  // - All that's left is a kContinue on the outside, and one of
-  //   kIfSelection, kSwitchSelection, kLoop on the inside.
-  //
-  //   The kContinue can be the parent of the other.  For example, a selection
-  //   starting at the first block of a continue construct.
-  //
-  //   The kContinue can't be the child of the other because either:
-  //     - The other can't be kLoop because:
-  //        - If the kLoop is for a different loop then the kContinue, then
-  //          the kContinue must be its own loop header, and so the same
-  //          block is two different loops. That's a contradiction.
-  //        - If the kLoop is for a the same loop, then this is a contradiction
-  //          because a kContinue and its kLoop have disjoint block sets.
-  //     - The other construct can't be a selection because:
-  //       - The kContinue construct is the entire loop, i.e. the continue
-  //         target is its own loop header block.  But then the continue target
-  //         has an OpLoopMerge instruction, which contradicts this block being
-  //         a selection header.
-  //       - The kContinue is in a multi-block loop that is has a non-empty
-  //         kLoop; and the selection contains the kContinue block but not the
-  //         loop block. That breaks dominance rules. That is, the continue
-  //         target is dominated by that loop header, and so gets found by the
-  //         block traversal on the outside before the selection is found. The
-  //         selection is inside the outer loop.
-  //
-  // So we fall into one of the following cases:
-  //  - We are entering 0 or 1 constructs, or
-  //  - We are entering 2 constructs, with the outer one being a kContinue or
-  //    kLoop, the inner one is not a continue.
-  if (entering_constructs.size() > 2) {
-    return Fail() << "internal error: bad construct nesting found";
-  }
-  if (entering_constructs.size() == 2) {
-    auto inner_kind = entering_constructs[0]->kind;
-    auto outer_kind = entering_constructs[1]->kind;
-    if (outer_kind != Construct::kContinue && outer_kind != Construct::kLoop) {
-      return Fail()
-             << "internal error: bad construct nesting. Only a Continue "
-                "or a Loop construct can be outer construct on same block.  "
-                "Got outer kind "
-             << int(outer_kind) << " inner kind " << int(inner_kind);
+    if (statements_stack_.empty()) {
+        return Fail() << "internal error: statements stack empty at block " << block_info.id;
     }
-    if (inner_kind == Construct::kContinue) {
-      return Fail() << "internal error: unsupported construct nesting: "
-                       "Continue around Continue";
-    }
-    if (inner_kind != Construct::kIfSelection &&
-        inner_kind != Construct::kSwitchSelection &&
-        inner_kind != Construct::kLoop) {
-      return Fail() << "internal error: bad construct nesting. Continue around "
-                       "something other than if, switch, or loop";
-    }
-  }
 
-  // Enter constructs from outermost to innermost.
-  // kLoop and kContinue push a new statement-block onto the stack before
-  // emitting statements in the block.
-  // kIfSelection and kSwitchSelection emit statements in the block and then
-  // emit push a new statement-block. Only emit the statements in the block
-  // once.
+    // Enter new constructs.
 
-  // Have we emitted the statements for this block?
-  bool emitted = false;
-
-  // When entering an if-selection or switch-selection, we will emit the WGSL
-  // construct to cause the divergent branching.  But otherwise, we will
-  // emit a "normal" block terminator, which occurs at the end of this method.
-  bool has_normal_terminator = true;
-
-  for (auto iter = entering_constructs.rbegin();
-       iter != entering_constructs.rend(); ++iter) {
-    const Construct* construct = *iter;
-
-    switch (construct->kind) {
-      case Construct::kFunction:
-        return Fail() << "internal error: nested function construct";
-
-      case Construct::kLoop:
-        if (!EmitLoopStart(construct)) {
-          return false;
+    std::vector<const Construct*> entering_constructs;  // inner most comes first
+    {
+        auto* here = block_info.construct;
+        auto* const top_construct = statements_stack_.back().GetConstruct();
+        while (here != top_construct) {
+            // Only enter a construct at its header block.
+            if (here->begin_id == block_info.id) {
+                entering_constructs.push_back(here);
+            }
+            here = here->parent;
         }
-        if (!EmitStatementsInBasicBlock(block_info, &emitted)) {
-          return false;
+    }
+    // What constructs can we have entered?
+    // - It can't be kFunction, because there is only one of those, and it was
+    //   already on the stack at the outermost level.
+    // - We have at most one of kSwitchSelection, or kLoop because each of those
+    //   is headed by a block with a merge instruction (OpLoopMerge for kLoop,
+    //   and OpSelectionMerge for kSwitchSelection).
+    // - When there is a kIfSelection, it can't contain another construct,
+    //   because both would have to have their own distinct merge instructions
+    //   and distinct terminators.
+    // - A kContinue can contain a kContinue
+    //   This is possible in Vulkan SPIR-V, but Tint disallows this by the rule
+    //   that a block can be continue target for at most one header block. See
+    //   test DISABLED_BlockIsContinueForMoreThanOneHeader. If we generalize this,
+    //   then by a dominance argument, the inner loop continue target can only be
+    //   a single-block loop.
+    // TODO(dneto): Handle this case.
+    // - If a kLoop is on the outside, its terminator is either:
+    //   - an OpBranch, in which case there is no other construct.
+    //   - an OpBranchConditional, in which case there is either an kIfSelection
+    //     (when both branch targets are different and are inside the loop),
+    //     or no other construct (because the branch targets are the same,
+    //     or one of them is a break or continue).
+    // - All that's left is a kContinue on the outside, and one of
+    //   kIfSelection, kSwitchSelection, kLoop on the inside.
+    //
+    //   The kContinue can be the parent of the other.  For example, a selection
+    //   starting at the first block of a continue construct.
+    //
+    //   The kContinue can't be the child of the other because either:
+    //     - The other can't be kLoop because:
+    //        - If the kLoop is for a different loop then the kContinue, then
+    //          the kContinue must be its own loop header, and so the same
+    //          block is two different loops. That's a contradiction.
+    //        - If the kLoop is for a the same loop, then this is a contradiction
+    //          because a kContinue and its kLoop have disjoint block sets.
+    //     - The other construct can't be a selection because:
+    //       - The kContinue construct is the entire loop, i.e. the continue
+    //         target is its own loop header block.  But then the continue target
+    //         has an OpLoopMerge instruction, which contradicts this block being
+    //         a selection header.
+    //       - The kContinue is in a multi-block loop that is has a non-empty
+    //         kLoop; and the selection contains the kContinue block but not the
+    //         loop block. That breaks dominance rules. That is, the continue
+    //         target is dominated by that loop header, and so gets found by the
+    //         block traversal on the outside before the selection is found. The
+    //         selection is inside the outer loop.
+    //
+    // So we fall into one of the following cases:
+    //  - We are entering 0 or 1 constructs, or
+    //  - We are entering 2 constructs, with the outer one being a kContinue or
+    //    kLoop, the inner one is not a continue.
+    if (entering_constructs.size() > 2) {
+        return Fail() << "internal error: bad construct nesting found";
+    }
+    if (entering_constructs.size() == 2) {
+        auto inner_kind = entering_constructs[0]->kind;
+        auto outer_kind = entering_constructs[1]->kind;
+        if (outer_kind != Construct::kContinue && outer_kind != Construct::kLoop) {
+            return Fail() << "internal error: bad construct nesting. Only a Continue "
+                             "or a Loop construct can be outer construct on same block.  "
+                             "Got outer kind "
+                          << int(outer_kind) << " inner kind " << int(inner_kind);
         }
-        break;
+        if (inner_kind == Construct::kContinue) {
+            return Fail() << "internal error: unsupported construct nesting: "
+                             "Continue around Continue";
+        }
+        if (inner_kind != Construct::kIfSelection && inner_kind != Construct::kSwitchSelection &&
+            inner_kind != Construct::kLoop) {
+            return Fail() << "internal error: bad construct nesting. Continue around "
+                             "something other than if, switch, or loop";
+        }
+    }
 
-      case Construct::kContinue:
-        if (block_info.is_continue_entire_loop) {
-          if (!EmitLoopStart(construct)) {
+    // Enter constructs from outermost to innermost.
+    // kLoop and kContinue push a new statement-block onto the stack before
+    // emitting statements in the block.
+    // kIfSelection and kSwitchSelection emit statements in the block and then
+    // emit push a new statement-block. Only emit the statements in the block
+    // once.
+
+    // Have we emitted the statements for this block?
+    bool emitted = false;
+
+    // When entering an if-selection or switch-selection, we will emit the WGSL
+    // construct to cause the divergent branching.  But otherwise, we will
+    // emit a "normal" block terminator, which occurs at the end of this method.
+    bool has_normal_terminator = true;
+
+    for (auto iter = entering_constructs.rbegin(); iter != entering_constructs.rend(); ++iter) {
+        const Construct* construct = *iter;
+
+        switch (construct->kind) {
+            case Construct::kFunction:
+                return Fail() << "internal error: nested function construct";
+
+            case Construct::kLoop:
+                if (!EmitLoopStart(construct)) {
+                    return false;
+                }
+                if (!EmitStatementsInBasicBlock(block_info, &emitted)) {
+                    return false;
+                }
+                break;
+
+            case Construct::kContinue:
+                if (block_info.is_continue_entire_loop) {
+                    if (!EmitLoopStart(construct)) {
+                        return false;
+                    }
+                    if (!EmitStatementsInBasicBlock(block_info, &emitted)) {
+                        return false;
+                    }
+                } else {
+                    if (!EmitContinuingStart(construct)) {
+                        return false;
+                    }
+                }
+                break;
+
+            case Construct::kIfSelection:
+                if (!EmitStatementsInBasicBlock(block_info, &emitted)) {
+                    return false;
+                }
+                if (!EmitIfStart(block_info)) {
+                    return false;
+                }
+                has_normal_terminator = false;
+                break;
+
+            case Construct::kSwitchSelection:
+                if (!EmitStatementsInBasicBlock(block_info, &emitted)) {
+                    return false;
+                }
+                if (!EmitSwitchStart(block_info)) {
+                    return false;
+                }
+                has_normal_terminator = false;
+                break;
+        }
+    }
+
+    // If we aren't starting or transitioning, then emit the normal
+    // statements now.
+    if (!EmitStatementsInBasicBlock(block_info, &emitted)) {
+        return false;
+    }
+
+    if (has_normal_terminator) {
+        if (!EmitNormalTerminator(block_info)) {
             return false;
-          }
-          if (!EmitStatementsInBasicBlock(block_info, &emitted)) {
-            return false;
-          }
-        } else {
-          if (!EmitContinuingStart(construct)) {
-            return false;
-          }
         }
-        break;
-
-      case Construct::kIfSelection:
-        if (!EmitStatementsInBasicBlock(block_info, &emitted)) {
-          return false;
-        }
-        if (!EmitIfStart(block_info)) {
-          return false;
-        }
-        has_normal_terminator = false;
-        break;
-
-      case Construct::kSwitchSelection:
-        if (!EmitStatementsInBasicBlock(block_info, &emitted)) {
-          return false;
-        }
-        if (!EmitSwitchStart(block_info)) {
-          return false;
-        }
-        has_normal_terminator = false;
-        break;
     }
-  }
-
-  // If we aren't starting or transitioning, then emit the normal
-  // statements now.
-  if (!EmitStatementsInBasicBlock(block_info, &emitted)) {
-    return false;
-  }
-
-  if (has_normal_terminator) {
-    if (!EmitNormalTerminator(block_info)) {
-      return false;
-    }
-  }
-  return success();
+    return success();
 }
 
 bool FunctionEmitter::EmitIfStart(const BlockInfo& block_info) {
-  // The block is the if-header block.  So its construct is the if construct.
-  auto* construct = block_info.construct;
-  TINT_ASSERT(Reader, construct->kind == Construct::kIfSelection);
-  TINT_ASSERT(Reader, construct->begin_id == block_info.id);
+    // The block is the if-header block.  So its construct is the if construct.
+    auto* construct = block_info.construct;
+    TINT_ASSERT(Reader, construct->kind == Construct::kIfSelection);
+    TINT_ASSERT(Reader, construct->begin_id == block_info.id);
 
-  const uint32_t true_head = block_info.true_head;
-  const uint32_t false_head = block_info.false_head;
-  const uint32_t premerge_head = block_info.premerge_head;
+    const uint32_t true_head = block_info.true_head;
+    const uint32_t false_head = block_info.false_head;
+    const uint32_t premerge_head = block_info.premerge_head;
 
-  const std::string guard_name = block_info.flow_guard_name;
-  if (!guard_name.empty()) {
-    // Declare the guard variable just before the "if", initialized to true.
-    auto* guard_var =
-        builder_.Var(guard_name, builder_.ty.bool_(), MakeTrue(Source{}));
-    auto* guard_decl = create<ast::VariableDeclStatement>(Source{}, guard_var);
-    AddStatement(guard_decl);
-  }
+    const std::string guard_name = block_info.flow_guard_name;
+    if (!guard_name.empty()) {
+        // Declare the guard variable just before the "if", initialized to true.
+        auto* guard_var = builder_.Var(guard_name, builder_.ty.bool_(), MakeTrue(Source{}));
+        auto* guard_decl = create<ast::VariableDeclStatement>(Source{}, guard_var);
+        AddStatement(guard_decl);
+    }
 
-  const auto condition_id =
-      block_info.basic_block->terminator()->GetSingleWordInOperand(0);
-  auto* cond = MakeExpression(condition_id).expr;
-  if (!cond) {
-    return false;
-  }
-  // Generate the code for the condition.
-  auto* builder = AddStatementBuilder<IfStatementBuilder>(cond);
+    const auto condition_id = block_info.basic_block->terminator()->GetSingleWordInOperand(0);
+    auto* cond = MakeExpression(condition_id).expr;
+    if (!cond) {
+        return false;
+    }
+    // Generate the code for the condition.
+    auto* builder = AddStatementBuilder<IfStatementBuilder>(cond);
 
-  // Compute the block IDs that should end the then-clause and the else-clause.
+    // Compute the block IDs that should end the then-clause and the else-clause.
 
-  // We need to know where the *emitted* selection should end, i.e. the intended
-  // merge block id.  That should be the current premerge block, if it exists,
-  // or otherwise the declared merge block.
-  //
-  // This is another way to think about it:
-  //   If there is a premerge, then there are three cases:
-  //    - premerge_head is different from the true_head and false_head:
-  //      - Premerge comes last. In effect, move the selection merge up
-  //        to where the premerge begins.
-  //    - premerge_head is the same as the false_head
-  //      - This is really an if-then without an else clause.
-  //        Move the merge up to where the premerge is.
-  //    - premerge_head is the same as the true_head
-  //      - This is really an if-else without an then clause.
-  //        Emit it as:   if (cond) {} else {....}
-  //        Move the merge up to where the premerge is.
-  const uint32_t intended_merge =
-      premerge_head ? premerge_head : construct->end_id;
+    // We need to know where the *emitted* selection should end, i.e. the intended
+    // merge block id.  That should be the current premerge block, if it exists,
+    // or otherwise the declared merge block.
+    //
+    // This is another way to think about it:
+    //   If there is a premerge, then there are three cases:
+    //    - premerge_head is different from the true_head and false_head:
+    //      - Premerge comes last. In effect, move the selection merge up
+    //        to where the premerge begins.
+    //    - premerge_head is the same as the false_head
+    //      - This is really an if-then without an else clause.
+    //        Move the merge up to where the premerge is.
+    //    - premerge_head is the same as the true_head
+    //      - This is really an if-else without an then clause.
+    //        Emit it as:   if (cond) {} else {....}
+    //        Move the merge up to where the premerge is.
+    const uint32_t intended_merge = premerge_head ? premerge_head : construct->end_id;
 
-  // then-clause:
-  //   If true_head exists:
-  //     spans from true head to the earlier of the false head (if it exists)
-  //     or the selection merge.
-  //   Otherwise:
-  //     ends at from the false head (if it exists), otherwise the selection
-  //     end.
-  const uint32_t then_end = false_head ? false_head : intended_merge;
+    // then-clause:
+    //   If true_head exists:
+    //     spans from true head to the earlier of the false head (if it exists)
+    //     or the selection merge.
+    //   Otherwise:
+    //     ends at from the false head (if it exists), otherwise the selection
+    //     end.
+    const uint32_t then_end = false_head ? false_head : intended_merge;
 
-  // else-clause:
-  //   ends at the premerge head (if it exists) or at the selection end.
-  const uint32_t else_end = premerge_head ? premerge_head : intended_merge;
+    // else-clause:
+    //   ends at the premerge head (if it exists) or at the selection end.
+    const uint32_t else_end = premerge_head ? premerge_head : intended_merge;
 
-  const bool true_is_break = (block_info.true_kind == EdgeKind::kSwitchBreak) ||
-                             (block_info.true_kind == EdgeKind::kLoopBreak);
-  const bool false_is_break =
-      (block_info.false_kind == EdgeKind::kSwitchBreak) ||
-      (block_info.false_kind == EdgeKind::kLoopBreak);
-  const bool true_is_continue = block_info.true_kind == EdgeKind::kLoopContinue;
-  const bool false_is_continue =
-      block_info.false_kind == EdgeKind::kLoopContinue;
+    const bool true_is_break = (block_info.true_kind == EdgeKind::kSwitchBreak) ||
+                               (block_info.true_kind == EdgeKind::kLoopBreak);
+    const bool false_is_break = (block_info.false_kind == EdgeKind::kSwitchBreak) ||
+                                (block_info.false_kind == EdgeKind::kLoopBreak);
+    const bool true_is_continue = block_info.true_kind == EdgeKind::kLoopContinue;
+    const bool false_is_continue = block_info.false_kind == EdgeKind::kLoopContinue;
 
-  // Push statement blocks for the then-clause and the else-clause.
-  // But make sure we do it in the right order.
-  auto push_else = [this, builder, else_end, construct, false_is_break,
-                    false_is_continue]() {
-    // Push the else clause onto the stack first.
-    PushNewStatementBlock(
-        construct, else_end, [=](const ast::StatementList& stmts) {
-          // Only set the else-clause if there are statements to fill it.
-          if (!stmts.empty()) {
-            // The "else" consists of the statement list from the top of
-            // statements stack, without an elseif condition.
-            auto* else_body = create<ast::BlockStatement>(Source{}, stmts);
-            builder->else_stmts.emplace_back(
-                create<ast::ElseStatement>(Source{}, nullptr, else_body));
-          }
+    // Push statement blocks for the then-clause and the else-clause.
+    // But make sure we do it in the right order.
+    auto push_else = [this, builder, else_end, construct, false_is_break, false_is_continue]() {
+        // Push the else clause onto the stack first.
+        PushNewStatementBlock(construct, else_end, [=](const ast::StatementList& stmts) {
+            // Only set the else-clause if there are statements to fill it.
+            if (!stmts.empty()) {
+                // The "else" consists of the statement list from the top of
+                // statements stack, without an "else if" condition.
+                builder->else_stmt = create<ast::BlockStatement>(Source{}, stmts);
+            }
         });
-    if (false_is_break) {
-      AddStatement(create<ast::BreakStatement>(Source{}));
-    }
-    if (false_is_continue) {
-      AddStatement(create<ast::ContinueStatement>(Source{}));
-    }
-  };
+        if (false_is_break) {
+            AddStatement(create<ast::BreakStatement>(Source{}));
+        }
+        if (false_is_continue) {
+            AddStatement(create<ast::ContinueStatement>(Source{}));
+        }
+    };
 
-  if (!true_is_break && !true_is_continue &&
-      (GetBlockInfo(else_end)->pos < GetBlockInfo(then_end)->pos)) {
-    // Process the else-clause first.  The then-clause will be empty so avoid
-    // pushing onto the stack at all.
-    push_else();
-  } else {
-    // Blocks for the then-clause appear before blocks for the else-clause.
-    // So push the else-clause handling onto the stack first. The else-clause
-    // might be empty, but this works anyway.
+    if (!true_is_break && !true_is_continue &&
+        (GetBlockInfo(else_end)->pos < GetBlockInfo(then_end)->pos)) {
+        // Process the else-clause first.  The then-clause will be empty so avoid
+        // pushing onto the stack at all.
+        push_else();
+    } else {
+        // Blocks for the then-clause appear before blocks for the else-clause.
+        // So push the else-clause handling onto the stack first. The else-clause
+        // might be empty, but this works anyway.
 
-    // Handle the premerge, if it exists.
-    if (premerge_head) {
-      // The top of the stack is the statement block that is the parent of the
-      // if-statement. Adding statements now will place them after that 'if'.
-      if (guard_name.empty()) {
-        // We won't have a flow guard for the premerge.
-        // Insert a trivial if(true) { ... } around the blocks from the
-        // premerge head until the end of the if-selection.  This is needed
-        // to ensure uniform reconvergence occurs at the end of the if-selection
-        // just like in the original SPIR-V.
-        PushTrueGuard(construct->end_id);
-      } else {
-        // Add a flow guard around the blocks in the premerge area.
-        PushGuard(guard_name, construct->end_id);
-      }
-    }
+        // Handle the premerge, if it exists.
+        if (premerge_head) {
+            // The top of the stack is the statement block that is the parent of the
+            // if-statement. Adding statements now will place them after that 'if'.
+            if (guard_name.empty()) {
+                // We won't have a flow guard for the premerge.
+                // Insert a trivial if(true) { ... } around the blocks from the
+                // premerge head until the end of the if-selection.  This is needed
+                // to ensure uniform reconvergence occurs at the end of the if-selection
+                // just like in the original SPIR-V.
+                PushTrueGuard(construct->end_id);
+            } else {
+                // Add a flow guard around the blocks in the premerge area.
+                PushGuard(guard_name, construct->end_id);
+            }
+        }
 
-    push_else();
-    if (true_head && false_head && !guard_name.empty()) {
-      // There are non-trivial then and else clauses.
-      // We have to guard the start of the else.
-      PushGuard(guard_name, else_end);
-    }
+        push_else();
+        if (true_head && false_head && !guard_name.empty()) {
+            // There are non-trivial then and else clauses.
+            // We have to guard the start of the else.
+            PushGuard(guard_name, else_end);
+        }
 
-    // Push the then clause onto the stack.
-    PushNewStatementBlock(
-        construct, then_end, [=](const ast::StatementList& stmts) {
-          builder->body = create<ast::BlockStatement>(Source{}, stmts);
+        // Push the then clause onto the stack.
+        PushNewStatementBlock(construct, then_end, [=](const ast::StatementList& stmts) {
+            builder->body = create<ast::BlockStatement>(Source{}, stmts);
         });
-    if (true_is_break) {
-      AddStatement(create<ast::BreakStatement>(Source{}));
+        if (true_is_break) {
+            AddStatement(create<ast::BreakStatement>(Source{}));
+        }
+        if (true_is_continue) {
+            AddStatement(create<ast::ContinueStatement>(Source{}));
+        }
     }
-    if (true_is_continue) {
-      AddStatement(create<ast::ContinueStatement>(Source{}));
-    }
-  }
 
-  return success();
+    return success();
 }
 
 bool FunctionEmitter::EmitSwitchStart(const BlockInfo& block_info) {
-  // The block is the if-header block.  So its construct is the if construct.
-  auto* construct = block_info.construct;
-  TINT_ASSERT(Reader, construct->kind == Construct::kSwitchSelection);
-  TINT_ASSERT(Reader, construct->begin_id == block_info.id);
-  const auto* branch = block_info.basic_block->terminator();
+    // The block is the if-header block.  So its construct is the if construct.
+    auto* construct = block_info.construct;
+    TINT_ASSERT(Reader, construct->kind == Construct::kSwitchSelection);
+    TINT_ASSERT(Reader, construct->begin_id == block_info.id);
+    const auto* branch = block_info.basic_block->terminator();
 
-  const auto selector_id = branch->GetSingleWordInOperand(0);
-  // Generate the code for the selector.
-  auto selector = MakeExpression(selector_id);
-  if (!selector) {
-    return false;
-  }
-  // First, push the statement block for the entire switch.
-  auto* swch = AddStatementBuilder<SwitchStatementBuilder>(selector.expr);
-
-  // Grab a pointer to the case list.  It will get buried in the statement block
-  // stack.
-  PushNewStatementBlock(construct, construct->end_id, nullptr);
-
-  // We will push statement-blocks onto the stack to gather the statements in
-  // the default clause and cases clauses. Determine the list of blocks
-  // that start each clause.
-  std::vector<const BlockInfo*> clause_heads;
-
-  // Collect the case clauses, even if they are just the merge block.
-  // First the default clause.
-  const auto default_id = branch->GetSingleWordInOperand(1);
-  const auto* default_info = GetBlockInfo(default_id);
-  clause_heads.push_back(default_info);
-  // Now the case clauses.
-  for (uint32_t iarg = 2; iarg + 1 < branch->NumInOperands(); iarg += 2) {
-    const auto case_target_id = branch->GetSingleWordInOperand(iarg + 1);
-    clause_heads.push_back(GetBlockInfo(case_target_id));
-  }
-
-  std::stable_sort(clause_heads.begin(), clause_heads.end(),
-                   [](const BlockInfo* lhs, const BlockInfo* rhs) {
-                     return lhs->pos < rhs->pos;
-                   });
-  // Remove duplicates
-  {
-    // Use read index r, and write index w.
-    // Invariant: w <= r;
-    size_t w = 0;
-    for (size_t r = 0; r < clause_heads.size(); ++r) {
-      if (clause_heads[r] != clause_heads[w]) {
-        ++w;  // Advance the write cursor.
-      }
-      clause_heads[w] = clause_heads[r];
+    const auto selector_id = branch->GetSingleWordInOperand(0);
+    // Generate the code for the selector.
+    auto selector = MakeExpression(selector_id);
+    if (!selector) {
+        return false;
     }
-    // We know it's not empty because it always has at least a default clause.
-    TINT_ASSERT(Reader, !clause_heads.empty());
-    clause_heads.resize(w + 1);
-  }
+    // First, push the statement block for the entire switch.
+    auto* swch = AddStatementBuilder<SwitchStatementBuilder>(selector.expr);
 
-  // Push them on in reverse order.
-  const auto last_clause_index = clause_heads.size() - 1;
-  for (size_t i = last_clause_index;; --i) {
-    // Create a list of integer literals for the selector values leading to
-    // this case clause.
-    ast::CaseSelectorList selectors;
-    const auto* values_ptr = clause_heads[i]->case_values.get();
-    const bool has_selectors = (values_ptr && !values_ptr->empty());
-    if (has_selectors) {
-      std::vector<uint64_t> values(values_ptr->begin(), values_ptr->end());
-      std::stable_sort(values.begin(), values.end());
-      for (auto value : values) {
-        // The rest of this module can handle up to 64 bit switch values.
-        // The Tint AST handles 32-bit values.
-        const uint32_t value32 = uint32_t(value & 0xFFFFFFFF);
-        if (selector.type->IsUnsignedScalarOrVector()) {
-          selectors.emplace_back(
-              create<ast::UintLiteralExpression>(Source{}, value32));
-        } else {
-          selectors.emplace_back(
-              create<ast::SintLiteralExpression>(Source{}, value32));
+    // Grab a pointer to the case list.  It will get buried in the statement block
+    // stack.
+    PushNewStatementBlock(construct, construct->end_id, nullptr);
+
+    // We will push statement-blocks onto the stack to gather the statements in
+    // the default clause and cases clauses. Determine the list of blocks
+    // that start each clause.
+    std::vector<const BlockInfo*> clause_heads;
+
+    // Collect the case clauses, even if they are just the merge block.
+    // First the default clause.
+    const auto default_id = branch->GetSingleWordInOperand(1);
+    const auto* default_info = GetBlockInfo(default_id);
+    clause_heads.push_back(default_info);
+    // Now the case clauses.
+    for (uint32_t iarg = 2; iarg + 1 < branch->NumInOperands(); iarg += 2) {
+        const auto case_target_id = branch->GetSingleWordInOperand(iarg + 1);
+        clause_heads.push_back(GetBlockInfo(case_target_id));
+    }
+
+    std::stable_sort(
+        clause_heads.begin(), clause_heads.end(),
+        [](const BlockInfo* lhs, const BlockInfo* rhs) { return lhs->pos < rhs->pos; });
+    // Remove duplicates
+    {
+        // Use read index r, and write index w.
+        // Invariant: w <= r;
+        size_t w = 0;
+        for (size_t r = 0; r < clause_heads.size(); ++r) {
+            if (clause_heads[r] != clause_heads[w]) {
+                ++w;  // Advance the write cursor.
+            }
+            clause_heads[w] = clause_heads[r];
         }
-      }
+        // We know it's not empty because it always has at least a default clause.
+        TINT_ASSERT(Reader, !clause_heads.empty());
+        clause_heads.resize(w + 1);
     }
 
-    // Where does this clause end?
-    const auto end_id = (i + 1 < clause_heads.size()) ? clause_heads[i + 1]->id
-                                                      : construct->end_id;
+    // Push them on in reverse order.
+    const auto last_clause_index = clause_heads.size() - 1;
+    for (size_t i = last_clause_index;; --i) {
+        // Create a list of integer literals for the selector values leading to
+        // this case clause.
+        ast::CaseSelectorList selectors;
+        const auto* values_ptr = clause_heads[i]->case_values.get();
+        const bool has_selectors = (values_ptr && !values_ptr->empty());
+        if (has_selectors) {
+            std::vector<uint64_t> values(values_ptr->begin(), values_ptr->end());
+            std::stable_sort(values.begin(), values.end());
+            for (auto value : values) {
+                // The rest of this module can handle up to 64 bit switch values.
+                // The Tint AST handles 32-bit values.
+                const uint32_t value32 = uint32_t(value & 0xFFFFFFFF);
+                if (selector.type->IsUnsignedScalarOrVector()) {
+                    selectors.emplace_back(create<ast::IntLiteralExpression>(
+                        Source{}, value32, ast::IntLiteralExpression::Suffix::kU));
+                } else {
+                    selectors.emplace_back(
+                        create<ast::IntLiteralExpression>(Source{}, static_cast<int32_t>(value32),
+                                                          ast::IntLiteralExpression::Suffix::kI));
+                }
+            }
+        }
 
-    // Reserve the case clause slot in swch->cases, push the new statement block
-    // for the case, and fill the case clause once the block is generated.
-    auto case_idx = swch->cases.size();
-    swch->cases.emplace_back(nullptr);
-    PushNewStatementBlock(
-        construct, end_id, [=](const ast::StatementList& stmts) {
-          auto* body = create<ast::BlockStatement>(Source{}, stmts);
-          swch->cases[case_idx] =
-              create<ast::CaseStatement>(Source{}, selectors, body);
+        // Where does this clause end?
+        const auto end_id =
+            (i + 1 < clause_heads.size()) ? clause_heads[i + 1]->id : construct->end_id;
+
+        // Reserve the case clause slot in swch->cases, push the new statement block
+        // for the case, and fill the case clause once the block is generated.
+        auto case_idx = swch->cases.size();
+        swch->cases.emplace_back(nullptr);
+        PushNewStatementBlock(construct, end_id, [=](const ast::StatementList& stmts) {
+            auto* body = create<ast::BlockStatement>(Source{}, stmts);
+            swch->cases[case_idx] = create<ast::CaseStatement>(Source{}, selectors, body);
         });
 
-    if ((default_info == clause_heads[i]) && has_selectors &&
-        construct->ContainsPos(default_info->pos)) {
-      // Generate a default clause with a just fallthrough.
-      auto* stmts = create<ast::BlockStatement>(
-          Source{}, ast::StatementList{
-                        create<ast::FallthroughStatement>(Source{}),
-                    });
-      auto* case_stmt =
-          create<ast::CaseStatement>(Source{}, ast::CaseSelectorList{}, stmts);
-      swch->cases.emplace_back(case_stmt);
+        if ((default_info == clause_heads[i]) && has_selectors &&
+            construct->ContainsPos(default_info->pos)) {
+            // Generate a default clause with a just fallthrough.
+            auto* stmts = create<ast::BlockStatement>(
+                Source{}, ast::StatementList{
+                              create<ast::FallthroughStatement>(Source{}),
+                          });
+            auto* case_stmt = create<ast::CaseStatement>(Source{}, ast::CaseSelectorList{}, stmts);
+            swch->cases.emplace_back(case_stmt);
+        }
+
+        if (i == 0) {
+            break;
+        }
     }
 
-    if (i == 0) {
-      break;
-    }
-  }
-
-  return success();
+    return success();
 }
 
 bool FunctionEmitter::EmitLoopStart(const Construct* construct) {
-  auto* builder = AddStatementBuilder<LoopStatementBuilder>();
-  PushNewStatementBlock(
-      construct, construct->end_id, [=](const ast::StatementList& stmts) {
+    auto* builder = AddStatementBuilder<LoopStatementBuilder>();
+    PushNewStatementBlock(construct, construct->end_id, [=](const ast::StatementList& stmts) {
         builder->body = create<ast::BlockStatement>(Source{}, stmts);
-      });
-  return success();
+    });
+    return success();
 }
 
 bool FunctionEmitter::EmitContinuingStart(const Construct* construct) {
-  // A continue construct has the same depth as its associated loop
-  // construct. Start a continue construct.
-  auto* loop_candidate = LastStatement();
-  auto* loop = loop_candidate->As<LoopStatementBuilder>();
-  if (loop == nullptr) {
-    return Fail() << "internal error: starting continue construct, "
-                     "expected loop on top of stack";
-  }
-  PushNewStatementBlock(
-      construct, construct->end_id, [=](const ast::StatementList& stmts) {
+    // A continue construct has the same depth as its associated loop
+    // construct. Start a continue construct.
+    auto* loop_candidate = LastStatement();
+    auto* loop = loop_candidate->As<LoopStatementBuilder>();
+    if (loop == nullptr) {
+        return Fail() << "internal error: starting continue construct, "
+                         "expected loop on top of stack";
+    }
+    PushNewStatementBlock(construct, construct->end_id, [=](const ast::StatementList& stmts) {
         loop->continuing = create<ast::BlockStatement>(Source{}, stmts);
-      });
+    });
 
-  return success();
+    return success();
 }
 
 bool FunctionEmitter::EmitNormalTerminator(const BlockInfo& block_info) {
-  const auto& terminator = *(block_info.basic_block->terminator());
-  switch (terminator.opcode()) {
-    case SpvOpReturn:
-      AddStatement(create<ast::ReturnStatement>(Source{}));
-      return true;
-    case SpvOpReturnValue: {
-      auto value = MakeExpression(terminator.GetSingleWordInOperand(0));
-      if (!value) {
-        return false;
-      }
-      AddStatement(create<ast::ReturnStatement>(Source{}, value.expr));
-    }
-      return true;
-    case SpvOpKill:
-      // For now, assume SPIR-V OpKill has same semantics as WGSL discard.
-      // TODO(dneto): https://github.com/gpuweb/gpuweb/issues/676
-      AddStatement(create<ast::DiscardStatement>(Source{}));
-      return true;
-    case SpvOpUnreachable:
-      // Translate as if it's a return. This avoids the problem where WGSL
-      // requires a return statement at the end of the function body.
-      {
-        const auto* result_type = type_mgr_->GetType(function_.type_id());
-        if (result_type->AsVoid() != nullptr) {
-          AddStatement(create<ast::ReturnStatement>(Source{}));
-        } else {
-          auto* ast_type = parser_impl_.ConvertType(function_.type_id());
-          AddStatement(create<ast::ReturnStatement>(
-              Source{}, parser_impl_.MakeNullValue(ast_type)));
+    const auto& terminator = *(block_info.basic_block->terminator());
+    switch (terminator.opcode()) {
+        case SpvOpReturn:
+            AddStatement(create<ast::ReturnStatement>(Source{}));
+            return true;
+        case SpvOpReturnValue: {
+            auto value = MakeExpression(terminator.GetSingleWordInOperand(0));
+            if (!value) {
+                return false;
+            }
+            AddStatement(create<ast::ReturnStatement>(Source{}, value.expr));
         }
-      }
-      return true;
-    case SpvOpBranch: {
-      const auto dest_id = terminator.GetSingleWordInOperand(0);
-      AddStatement(MakeBranch(block_info, *GetBlockInfo(dest_id)));
-      return true;
+            return true;
+        case SpvOpKill:
+            // For now, assume SPIR-V OpKill has same semantics as WGSL discard.
+            // TODO(dneto): https://github.com/gpuweb/gpuweb/issues/676
+            AddStatement(create<ast::DiscardStatement>(Source{}));
+            return true;
+        case SpvOpUnreachable:
+            // Translate as if it's a return. This avoids the problem where WGSL
+            // requires a return statement at the end of the function body.
+            {
+                const auto* result_type = type_mgr_->GetType(function_.type_id());
+                if (result_type->AsVoid() != nullptr) {
+                    AddStatement(create<ast::ReturnStatement>(Source{}));
+                } else {
+                    auto* ast_type = parser_impl_.ConvertType(function_.type_id());
+                    AddStatement(create<ast::ReturnStatement>(
+                        Source{}, parser_impl_.MakeNullValue(ast_type)));
+                }
+            }
+            return true;
+        case SpvOpBranch: {
+            const auto dest_id = terminator.GetSingleWordInOperand(0);
+            AddStatement(MakeBranch(block_info, *GetBlockInfo(dest_id)));
+            return true;
+        }
+        case SpvOpBranchConditional: {
+            // If both destinations are the same, then do the same as we would
+            // for an unconditional branch (OpBranch).
+            const auto true_dest = terminator.GetSingleWordInOperand(1);
+            const auto false_dest = terminator.GetSingleWordInOperand(2);
+            if (true_dest == false_dest) {
+                // This is like an unconditional branch.
+                AddStatement(MakeBranch(block_info, *GetBlockInfo(true_dest)));
+                return true;
+            }
+
+            const EdgeKind true_kind = block_info.succ_edge.find(true_dest)->second;
+            const EdgeKind false_kind = block_info.succ_edge.find(false_dest)->second;
+            auto* const true_info = GetBlockInfo(true_dest);
+            auto* const false_info = GetBlockInfo(false_dest);
+            auto* cond = MakeExpression(terminator.GetSingleWordInOperand(0)).expr;
+            if (!cond) {
+                return false;
+            }
+
+            // We have two distinct destinations. But we only get here if this
+            // is a normal terminator; in particular the source block is *not* the
+            // start of an if-selection or a switch-selection.  So at most one branch
+            // is a kForward, kCaseFallThrough, or kIfBreak.
+
+            // The fallthrough case is special because WGSL requires the fallthrough
+            // statement to be last in the case clause.
+            if (true_kind == EdgeKind::kCaseFallThrough) {
+                return EmitConditionalCaseFallThrough(block_info, cond, false_kind, *false_info,
+                                                      true);
+            } else if (false_kind == EdgeKind::kCaseFallThrough) {
+                return EmitConditionalCaseFallThrough(block_info, cond, true_kind, *true_info,
+                                                      false);
+            }
+
+            // At this point, at most one edge is kForward or kIfBreak.
+
+            // Emit an 'if' statement to express the *other* branch as a conditional
+            // break or continue.  Either or both of these could be nullptr.
+            // (A nullptr is generated for kIfBreak, kForward, or kBack.)
+            // Also if one of the branches is an if-break out of an if-selection
+            // requiring a flow guard, then get that flow guard name too.  It will
+            // come from at most one of these two branches.
+            std::string flow_guard;
+            auto* true_branch = MakeBranchDetailed(block_info, *true_info, false, &flow_guard);
+            auto* false_branch = MakeBranchDetailed(block_info, *false_info, false, &flow_guard);
+
+            AddStatement(MakeSimpleIf(cond, true_branch, false_branch));
+            if (!flow_guard.empty()) {
+                PushGuard(flow_guard, statements_stack_.back().GetEndId());
+            }
+            return true;
+        }
+        case SpvOpSwitch:
+            // An OpSelectionMerge must precede an OpSwitch.  That is clarified
+            // in the resolution to Khronos-internal SPIR-V issue 115.
+            // A new enough version of the SPIR-V validator checks this case.
+            // But issue an error in this case, as a defensive measure.
+            return Fail() << "invalid structured control flow: found an OpSwitch "
+                             "that is not preceded by an "
+                             "OpSelectionMerge: "
+                          << terminator.PrettyPrint();
+        default:
+            break;
     }
-    case SpvOpBranchConditional: {
-      // If both destinations are the same, then do the same as we would
-      // for an unconditional branch (OpBranch).
-      const auto true_dest = terminator.GetSingleWordInOperand(1);
-      const auto false_dest = terminator.GetSingleWordInOperand(2);
-      if (true_dest == false_dest) {
-        // This is like an unconditional branch.
-        AddStatement(MakeBranch(block_info, *GetBlockInfo(true_dest)));
-        return true;
-      }
-
-      const EdgeKind true_kind = block_info.succ_edge.find(true_dest)->second;
-      const EdgeKind false_kind = block_info.succ_edge.find(false_dest)->second;
-      auto* const true_info = GetBlockInfo(true_dest);
-      auto* const false_info = GetBlockInfo(false_dest);
-      auto* cond = MakeExpression(terminator.GetSingleWordInOperand(0)).expr;
-      if (!cond) {
-        return false;
-      }
-
-      // We have two distinct destinations. But we only get here if this
-      // is a normal terminator; in particular the source block is *not* the
-      // start of an if-selection or a switch-selection.  So at most one branch
-      // is a kForward, kCaseFallThrough, or kIfBreak.
-
-      // The fallthrough case is special because WGSL requires the fallthrough
-      // statement to be last in the case clause.
-      if (true_kind == EdgeKind::kCaseFallThrough) {
-        return EmitConditionalCaseFallThrough(block_info, cond, false_kind,
-                                              *false_info, true);
-      } else if (false_kind == EdgeKind::kCaseFallThrough) {
-        return EmitConditionalCaseFallThrough(block_info, cond, true_kind,
-                                              *true_info, false);
-      }
-
-      // At this point, at most one edge is kForward or kIfBreak.
-
-      // Emit an 'if' statement to express the *other* branch as a conditional
-      // break or continue.  Either or both of these could be nullptr.
-      // (A nullptr is generated for kIfBreak, kForward, or kBack.)
-      // Also if one of the branches is an if-break out of an if-selection
-      // requiring a flow guard, then get that flow guard name too.  It will
-      // come from at most one of these two branches.
-      std::string flow_guard;
-      auto* true_branch =
-          MakeBranchDetailed(block_info, *true_info, false, &flow_guard);
-      auto* false_branch =
-          MakeBranchDetailed(block_info, *false_info, false, &flow_guard);
-
-      AddStatement(MakeSimpleIf(cond, true_branch, false_branch));
-      if (!flow_guard.empty()) {
-        PushGuard(flow_guard, statements_stack_.back().GetEndId());
-      }
-      return true;
-    }
-    case SpvOpSwitch:
-      // An OpSelectionMerge must precede an OpSwitch.  That is clarified
-      // in the resolution to Khronos-internal SPIR-V issue 115.
-      // A new enough version of the SPIR-V validator checks this case.
-      // But issue an error in this case, as a defensive measure.
-      return Fail() << "invalid structured control flow: found an OpSwitch "
-                       "that is not preceded by an "
-                       "OpSelectionMerge: "
-                    << terminator.PrettyPrint();
-    default:
-      break;
-  }
-  return success();
+    return success();
 }
 
-const ast::Statement* FunctionEmitter::MakeBranchDetailed(
-    const BlockInfo& src_info,
-    const BlockInfo& dest_info,
-    bool forced,
-    std::string* flow_guard_name_ptr) const {
-  auto kind = src_info.succ_edge.find(dest_info.id)->second;
-  switch (kind) {
-    case EdgeKind::kBack:
-      // Nothing to do. The loop backedge is implicit.
-      break;
-    case EdgeKind::kSwitchBreak: {
-      if (forced) {
-        return create<ast::BreakStatement>(Source{});
-      }
-      // Unless forced, don't bother with a break at the end of a case/default
-      // clause.
-      const auto header = dest_info.header_for_merge;
-      TINT_ASSERT(Reader, header != 0);
-      const auto* exiting_construct = GetBlockInfo(header)->construct;
-      TINT_ASSERT(Reader,
-                  exiting_construct->kind == Construct::kSwitchSelection);
-      const auto candidate_next_case_pos = src_info.pos + 1;
-      // Leaving the last block from the last case?
-      if (candidate_next_case_pos == dest_info.pos) {
-        // No break needed.
-        return nullptr;
-      }
-      // Leaving the last block from not-the-last-case?
-      if (exiting_construct->ContainsPos(candidate_next_case_pos)) {
-        const auto* candidate_next_case =
-            GetBlockInfo(block_order_[candidate_next_case_pos]);
-        if (candidate_next_case->case_head_for == exiting_construct ||
-            candidate_next_case->default_head_for == exiting_construct) {
-          // No break needed.
-          return nullptr;
+const ast::Statement* FunctionEmitter::MakeBranchDetailed(const BlockInfo& src_info,
+                                                          const BlockInfo& dest_info,
+                                                          bool forced,
+                                                          std::string* flow_guard_name_ptr) const {
+    auto kind = src_info.succ_edge.find(dest_info.id)->second;
+    switch (kind) {
+        case EdgeKind::kBack:
+            // Nothing to do. The loop backedge is implicit.
+            break;
+        case EdgeKind::kSwitchBreak: {
+            if (forced) {
+                return create<ast::BreakStatement>(Source{});
+            }
+            // Unless forced, don't bother with a break at the end of a case/default
+            // clause.
+            const auto header = dest_info.header_for_merge;
+            TINT_ASSERT(Reader, header != 0);
+            const auto* exiting_construct = GetBlockInfo(header)->construct;
+            TINT_ASSERT(Reader, exiting_construct->kind == Construct::kSwitchSelection);
+            const auto candidate_next_case_pos = src_info.pos + 1;
+            // Leaving the last block from the last case?
+            if (candidate_next_case_pos == dest_info.pos) {
+                // No break needed.
+                return nullptr;
+            }
+            // Leaving the last block from not-the-last-case?
+            if (exiting_construct->ContainsPos(candidate_next_case_pos)) {
+                const auto* candidate_next_case =
+                    GetBlockInfo(block_order_[candidate_next_case_pos]);
+                if (candidate_next_case->case_head_for == exiting_construct ||
+                    candidate_next_case->default_head_for == exiting_construct) {
+                    // No break needed.
+                    return nullptr;
+                }
+            }
+            // We need a break.
+            return create<ast::BreakStatement>(Source{});
         }
-      }
-      // We need a break.
-      return create<ast::BreakStatement>(Source{});
-    }
-    case EdgeKind::kLoopBreak:
-      return create<ast::BreakStatement>(Source{});
-    case EdgeKind::kLoopContinue:
-      // An unconditional continue to the next block is redundant and ugly.
-      // Skip it in that case.
-      if (dest_info.pos == 1 + src_info.pos) {
-        break;
-      }
-      // Otherwise, emit a regular continue statement.
-      return create<ast::ContinueStatement>(Source{});
-    case EdgeKind::kIfBreak: {
-      const auto& flow_guard =
-          GetBlockInfo(dest_info.header_for_merge)->flow_guard_name;
-      if (!flow_guard.empty()) {
-        if (flow_guard_name_ptr != nullptr) {
-          *flow_guard_name_ptr = flow_guard;
+        case EdgeKind::kLoopBreak:
+            return create<ast::BreakStatement>(Source{});
+        case EdgeKind::kLoopContinue:
+            // An unconditional continue to the next block is redundant and ugly.
+            // Skip it in that case.
+            if (dest_info.pos == 1 + src_info.pos) {
+                break;
+            }
+            // Otherwise, emit a regular continue statement.
+            return create<ast::ContinueStatement>(Source{});
+        case EdgeKind::kIfBreak: {
+            const auto& flow_guard = GetBlockInfo(dest_info.header_for_merge)->flow_guard_name;
+            if (!flow_guard.empty()) {
+                if (flow_guard_name_ptr != nullptr) {
+                    *flow_guard_name_ptr = flow_guard;
+                }
+                // Signal an exit from the branch.
+                return create<ast::AssignmentStatement>(
+                    Source{},
+                    create<ast::IdentifierExpression>(Source{},
+                                                      builder_.Symbols().Register(flow_guard)),
+                    MakeFalse(Source{}));
+            }
+
+            // For an unconditional branch, the break out to an if-selection
+            // merge block is implicit.
+            break;
         }
-        // Signal an exit from the branch.
-        return create<ast::AssignmentStatement>(
-            Source{},
-            create<ast::IdentifierExpression>(
-                Source{}, builder_.Symbols().Register(flow_guard)),
-            MakeFalse(Source{}));
-      }
-
-      // For an unconditional branch, the break out to an if-selection
-      // merge block is implicit.
-      break;
+        case EdgeKind::kCaseFallThrough:
+            return create<ast::FallthroughStatement>(Source{});
+        case EdgeKind::kForward:
+            // Unconditional forward branch is implicit.
+            break;
     }
-    case EdgeKind::kCaseFallThrough:
-      return create<ast::FallthroughStatement>(Source{});
-    case EdgeKind::kForward:
-      // Unconditional forward branch is implicit.
-      break;
-  }
-  return nullptr;
-}
-
-const ast::Statement* FunctionEmitter::MakeSimpleIf(
-    const ast::Expression* condition,
-    const ast::Statement* then_stmt,
-    const ast::Statement* else_stmt) const {
-  if ((then_stmt == nullptr) && (else_stmt == nullptr)) {
     return nullptr;
-  }
-  ast::ElseStatementList else_stmts;
-  if (else_stmt != nullptr) {
-    ast::StatementList stmts{else_stmt};
-    else_stmts.emplace_back(create<ast::ElseStatement>(
-        Source{}, nullptr, create<ast::BlockStatement>(Source{}, stmts)));
-  }
-  ast::StatementList if_stmts;
-  if (then_stmt != nullptr) {
-    if_stmts.emplace_back(then_stmt);
-  }
-  auto* if_block = create<ast::BlockStatement>(Source{}, if_stmts);
-  auto* if_stmt =
-      create<ast::IfStatement>(Source{}, condition, if_block, else_stmts);
-
-  return if_stmt;
 }
 
-bool FunctionEmitter::EmitConditionalCaseFallThrough(
-    const BlockInfo& src_info,
-    const ast::Expression* cond,
-    EdgeKind other_edge_kind,
-    const BlockInfo& other_dest,
-    bool fall_through_is_true_branch) {
-  // In WGSL, the fallthrough statement must come last in the case clause.
-  // So we'll emit an if statement for the other branch, and then emit
-  // the fallthrough.
+const ast::Statement* FunctionEmitter::MakeSimpleIf(const ast::Expression* condition,
+                                                    const ast::Statement* then_stmt,
+                                                    const ast::Statement* else_stmt) const {
+    if ((then_stmt == nullptr) && (else_stmt == nullptr)) {
+        return nullptr;
+    }
+    ast::StatementList if_stmts;
+    if (then_stmt != nullptr) {
+        if_stmts.emplace_back(then_stmt);
+    }
+    auto* if_block = create<ast::BlockStatement>(Source{}, if_stmts);
 
-  // We have two distinct destinations. But we only get here if this
-  // is a normal terminator; in particular the source block is *not* the
-  // start of an if-selection.  So at most one branch is a kForward or
-  // kCaseFallThrough.
-  if (other_edge_kind == EdgeKind::kForward) {
-    return Fail()
-           << "internal error: normal terminator OpBranchConditional has "
-              "both forward and fallthrough edges";
-  }
-  if (other_edge_kind == EdgeKind::kIfBreak) {
-    return Fail()
-           << "internal error: normal terminator OpBranchConditional has "
-              "both IfBreak and fallthrough edges.  Violates nesting rule";
-  }
-  if (other_edge_kind == EdgeKind::kBack) {
-    return Fail()
-           << "internal error: normal terminator OpBranchConditional has "
-              "both backedge and fallthrough edges.  Violates nesting rule";
-  }
-  auto* other_branch = MakeForcedBranch(src_info, other_dest);
-  if (other_branch == nullptr) {
-    return Fail() << "internal error: expected a branch for edge-kind "
-                  << int(other_edge_kind);
-  }
-  if (fall_through_is_true_branch) {
-    AddStatement(MakeSimpleIf(cond, nullptr, other_branch));
-  } else {
-    AddStatement(MakeSimpleIf(cond, other_branch, nullptr));
-  }
-  AddStatement(create<ast::FallthroughStatement>(Source{}));
+    const ast::Statement* else_block = nullptr;
+    if (else_stmt) {
+        else_block = create<ast::BlockStatement>(ast::StatementList{else_stmt});
+    }
 
-  return success();
+    auto* if_stmt = create<ast::IfStatement>(Source{}, condition, if_block, else_block);
+
+    return if_stmt;
+}
+
+bool FunctionEmitter::EmitConditionalCaseFallThrough(const BlockInfo& src_info,
+                                                     const ast::Expression* cond,
+                                                     EdgeKind other_edge_kind,
+                                                     const BlockInfo& other_dest,
+                                                     bool fall_through_is_true_branch) {
+    // In WGSL, the fallthrough statement must come last in the case clause.
+    // So we'll emit an if statement for the other branch, and then emit
+    // the fallthrough.
+
+    // We have two distinct destinations. But we only get here if this
+    // is a normal terminator; in particular the source block is *not* the
+    // start of an if-selection.  So at most one branch is a kForward or
+    // kCaseFallThrough.
+    if (other_edge_kind == EdgeKind::kForward) {
+        return Fail() << "internal error: normal terminator OpBranchConditional has "
+                         "both forward and fallthrough edges";
+    }
+    if (other_edge_kind == EdgeKind::kIfBreak) {
+        return Fail() << "internal error: normal terminator OpBranchConditional has "
+                         "both IfBreak and fallthrough edges.  Violates nesting rule";
+    }
+    if (other_edge_kind == EdgeKind::kBack) {
+        return Fail() << "internal error: normal terminator OpBranchConditional has "
+                         "both backedge and fallthrough edges.  Violates nesting rule";
+    }
+    auto* other_branch = MakeForcedBranch(src_info, other_dest);
+    if (other_branch == nullptr) {
+        return Fail() << "internal error: expected a branch for edge-kind " << int(other_edge_kind);
+    }
+    if (fall_through_is_true_branch) {
+        AddStatement(MakeSimpleIf(cond, nullptr, other_branch));
+    } else {
+        AddStatement(MakeSimpleIf(cond, other_branch, nullptr));
+    }
+    AddStatement(create<ast::FallthroughStatement>(Source{}));
+
+    return success();
 }
 
 bool FunctionEmitter::EmitStatementsInBasicBlock(const BlockInfo& block_info,
                                                  bool* already_emitted) {
-  if (*already_emitted) {
-    // Only emit this part of the basic block once.
+    if (*already_emitted) {
+        // Only emit this part of the basic block once.
+        return true;
+    }
+    // Returns the given list of local definition IDs, sorted by their index.
+    auto sorted_by_index = [this](const std::vector<uint32_t>& ids) {
+        auto sorted = ids;
+        std::stable_sort(sorted.begin(), sorted.end(),
+                         [this](const uint32_t lhs, const uint32_t rhs) {
+                             return GetDefInfo(lhs)->index < GetDefInfo(rhs)->index;
+                         });
+        return sorted;
+    };
+
+    // Emit declarations of hoisted variables, in index order.
+    for (auto id : sorted_by_index(block_info.hoisted_ids)) {
+        const auto* def_inst = def_use_mgr_->GetDef(id);
+        TINT_ASSERT(Reader, def_inst);
+        auto* storage_type = RemapStorageClass(parser_impl_.ConvertType(def_inst->type_id()), id);
+        AddStatement(create<ast::VariableDeclStatement>(
+            Source{}, parser_impl_.MakeVariable(id, ast::StorageClass::kNone, storage_type, false,
+                                                false, nullptr, ast::AttributeList{})));
+        auto* type = ty_.Reference(storage_type, ast::StorageClass::kNone);
+        identifier_types_.emplace(id, type);
+    }
+    // Emit declarations of phi state variables, in index order.
+    for (auto id : sorted_by_index(block_info.phis_needing_state_vars)) {
+        const auto* def_inst = def_use_mgr_->GetDef(id);
+        TINT_ASSERT(Reader, def_inst);
+        const auto phi_var_name = GetDefInfo(id)->phi_var;
+        TINT_ASSERT(Reader, !phi_var_name.empty());
+        auto* var = builder_.Var(phi_var_name,
+                                 parser_impl_.ConvertType(def_inst->type_id())->Build(builder_));
+        AddStatement(create<ast::VariableDeclStatement>(Source{}, var));
+    }
+
+    // Emit regular statements.
+    const spvtools::opt::BasicBlock& bb = *(block_info.basic_block);
+    const auto* terminator = bb.terminator();
+    const auto* merge = bb.GetMergeInst();  // Might be nullptr
+    for (auto& inst : bb) {
+        if (&inst == terminator || &inst == merge || inst.opcode() == SpvOpLabel ||
+            inst.opcode() == SpvOpVariable) {
+            continue;
+        }
+        if (!EmitStatement(inst)) {
+            return false;
+        }
+    }
+
+    // Emit assignments to carry values to phi nodes in potential destinations.
+    // Do it in index order.
+    if (!block_info.phi_assignments.empty()) {
+        auto sorted = block_info.phi_assignments;
+        std::stable_sort(
+            sorted.begin(), sorted.end(),
+            [this](const BlockInfo::PhiAssignment& lhs, const BlockInfo::PhiAssignment& rhs) {
+                return GetDefInfo(lhs.phi_id)->index < GetDefInfo(rhs.phi_id)->index;
+            });
+        for (auto assignment : block_info.phi_assignments) {
+            const auto var_name = GetDefInfo(assignment.phi_id)->phi_var;
+            auto expr = MakeExpression(assignment.value);
+            if (!expr) {
+                return false;
+            }
+            AddStatement(create<ast::AssignmentStatement>(
+                Source{},
+                create<ast::IdentifierExpression>(Source{}, builder_.Symbols().Register(var_name)),
+                expr.expr));
+        }
+    }
+
+    *already_emitted = true;
     return true;
-  }
-  // Returns the given list of local definition IDs, sorted by their index.
-  auto sorted_by_index = [this](const std::vector<uint32_t>& ids) {
-    auto sorted = ids;
-    std::stable_sort(sorted.begin(), sorted.end(),
-                     [this](const uint32_t lhs, const uint32_t rhs) {
-                       return GetDefInfo(lhs)->index < GetDefInfo(rhs)->index;
-                     });
-    return sorted;
-  };
+}
 
-  // Emit declarations of hoisted variables, in index order.
-  for (auto id : sorted_by_index(block_info.hoisted_ids)) {
-    const auto* def_inst = def_use_mgr_->GetDef(id);
-    TINT_ASSERT(Reader, def_inst);
-    auto* storage_type =
-        RemapStorageClass(parser_impl_.ConvertType(def_inst->type_id()), id);
-    AddStatement(create<ast::VariableDeclStatement>(
-        Source{}, parser_impl_.MakeVariable(id, ast::StorageClass::kNone,
-                                            storage_type, false, false, nullptr,
-                                            ast::AttributeList{})));
-    auto* type = ty_.Reference(storage_type, ast::StorageClass::kNone);
-    identifier_types_.emplace(id, type);
-  }
-  // Emit declarations of phi state variables, in index order.
-  for (auto id : sorted_by_index(block_info.phis_needing_state_vars)) {
-    const auto* def_inst = def_use_mgr_->GetDef(id);
-    TINT_ASSERT(Reader, def_inst);
-    const auto phi_var_name = GetDefInfo(id)->phi_var;
-    TINT_ASSERT(Reader, !phi_var_name.empty());
-    auto* var = builder_.Var(
-        phi_var_name,
-        parser_impl_.ConvertType(def_inst->type_id())->Build(builder_));
-    AddStatement(create<ast::VariableDeclStatement>(Source{}, var));
-  }
-
-  // Emit regular statements.
-  const spvtools::opt::BasicBlock& bb = *(block_info.basic_block);
-  const auto* terminator = bb.terminator();
-  const auto* merge = bb.GetMergeInst();  // Might be nullptr
-  for (auto& inst : bb) {
-    if (&inst == terminator || &inst == merge || inst.opcode() == SpvOpLabel ||
-        inst.opcode() == SpvOpVariable) {
-      continue;
-    }
-    if (!EmitStatement(inst)) {
-      return false;
-    }
-  }
-
-  // Emit assignments to carry values to phi nodes in potential destinations.
-  // Do it in index order.
-  if (!block_info.phi_assignments.empty()) {
-    auto sorted = block_info.phi_assignments;
-    std::stable_sort(sorted.begin(), sorted.end(),
-                     [this](const BlockInfo::PhiAssignment& lhs,
-                            const BlockInfo::PhiAssignment& rhs) {
-                       return GetDefInfo(lhs.phi_id)->index <
-                              GetDefInfo(rhs.phi_id)->index;
-                     });
-    for (auto assignment : block_info.phi_assignments) {
-      const auto var_name = GetDefInfo(assignment.phi_id)->phi_var;
-      auto expr = MakeExpression(assignment.value);
-      if (!expr) {
+bool FunctionEmitter::EmitConstDefinition(const spvtools::opt::Instruction& inst,
+                                          TypedExpression expr) {
+    if (!expr) {
         return false;
-      }
-      AddStatement(create<ast::AssignmentStatement>(
-          Source{},
-          create<ast::IdentifierExpression>(
-              Source{}, builder_.Symbols().Register(var_name)),
-          expr.expr));
     }
-  }
 
-  *already_emitted = true;
-  return true;
+    // Do not generate pointers that we want to sink.
+    if (GetDefInfo(inst.result_id())->skip == SkipReason::kSinkPointerIntoUse) {
+        return true;
+    }
+
+    expr = AddressOfIfNeeded(expr, &inst);
+    auto* ast_const =
+        parser_impl_.MakeVariable(inst.result_id(), ast::StorageClass::kNone, expr.type, true,
+                                  false, expr.expr, ast::AttributeList{});
+    if (!ast_const) {
+        return false;
+    }
+    AddStatement(create<ast::VariableDeclStatement>(Source{}, ast_const));
+    identifier_types_.emplace(inst.result_id(), expr.type);
+    return success();
 }
 
-bool FunctionEmitter::EmitConstDefinition(
-    const spvtools::opt::Instruction& inst,
-    TypedExpression expr) {
-  if (!expr) {
-    return false;
-  }
-
-  // Do not generate pointers that we want to sink.
-  if (GetDefInfo(inst.result_id())->skip == SkipReason::kSinkPointerIntoUse) {
-    return true;
-  }
-
-  expr = AddressOfIfNeeded(expr, &inst);
-  auto* ast_const = parser_impl_.MakeVariable(
-      inst.result_id(), ast::StorageClass::kNone, expr.type, true, false,
-      expr.expr, ast::AttributeList{});
-  if (!ast_const) {
-    return false;
-  }
-  AddStatement(create<ast::VariableDeclStatement>(Source{}, ast_const));
-  identifier_types_.emplace(inst.result_id(), expr.type);
-  return success();
-}
-
-bool FunctionEmitter::EmitConstDefOrWriteToHoistedVar(
-    const spvtools::opt::Instruction& inst,
-    TypedExpression expr) {
-  return WriteIfHoistedVar(inst, expr) || EmitConstDefinition(inst, expr);
+bool FunctionEmitter::EmitConstDefOrWriteToHoistedVar(const spvtools::opt::Instruction& inst,
+                                                      TypedExpression expr) {
+    return WriteIfHoistedVar(inst, expr) || EmitConstDefinition(inst, expr);
 }
 
 bool FunctionEmitter::WriteIfHoistedVar(const spvtools::opt::Instruction& inst,
                                         TypedExpression expr) {
-  const auto result_id = inst.result_id();
-  const auto* def_info = GetDefInfo(result_id);
-  if (def_info && def_info->requires_hoisted_def) {
-    auto name = namer_.Name(result_id);
-    // Emit an assignment of the expression to the hoisted variable.
-    AddStatement(create<ast::AssignmentStatement>(
-        Source{},
-        create<ast::IdentifierExpression>(Source{},
-                                          builder_.Symbols().Register(name)),
-        expr.expr));
-    return true;
-  }
-  return false;
+    const auto result_id = inst.result_id();
+    const auto* def_info = GetDefInfo(result_id);
+    if (def_info && def_info->requires_hoisted_def) {
+        auto name = namer_.Name(result_id);
+        // Emit an assignment of the expression to the hoisted variable.
+        AddStatement(create<ast::AssignmentStatement>(
+            Source{},
+            create<ast::IdentifierExpression>(Source{}, builder_.Symbols().Register(name)),
+            expr.expr));
+        return true;
+    }
+    return false;
 }
 
 bool FunctionEmitter::EmitStatement(const spvtools::opt::Instruction& inst) {
-  if (failed()) {
-    return false;
-  }
-  const auto result_id = inst.result_id();
-  const auto type_id = inst.type_id();
-
-  if (type_id != 0) {
-    const auto& builtin_position_info = parser_impl_.GetBuiltInPositionInfo();
-    if (type_id == builtin_position_info.struct_type_id) {
-      return Fail() << "operations producing a per-vertex structure are not "
-                       "supported: "
-                    << inst.PrettyPrint();
-    }
-    if (type_id == builtin_position_info.pointer_type_id) {
-      return Fail() << "operations producing a pointer to a per-vertex "
-                       "structure are not "
-                       "supported: "
-                    << inst.PrettyPrint();
-    }
-  }
-
-  // Handle combinatorial instructions.
-  const auto* def_info = GetDefInfo(result_id);
-  if (def_info) {
-    TypedExpression combinatorial_expr;
-    if (def_info->skip == SkipReason::kDontSkip) {
-      combinatorial_expr = MaybeEmitCombinatorialValue(inst);
-      if (!success()) {
+    if (failed()) {
         return false;
-      }
     }
-    // An access chain or OpCopyObject can generate a skip.
-    if (def_info->skip != SkipReason::kDontSkip) {
-      return true;
-    }
+    const auto result_id = inst.result_id();
+    const auto type_id = inst.type_id();
 
-    if (combinatorial_expr.expr != nullptr) {
-      if (def_info->requires_hoisted_def ||
-          def_info->requires_named_const_def || def_info->num_uses != 1) {
-        // Generate a const definition or an assignment to a hoisted definition
-        // now and later use the const or variable name at the uses of this
-        // value.
-        return EmitConstDefOrWriteToHoistedVar(inst, combinatorial_expr);
-      }
-      // It is harmless to defer emitting the expression until it's used.
-      // Any supporting statements have already been emitted.
-      singly_used_values_.insert(std::make_pair(result_id, combinatorial_expr));
-      return success();
-    }
-  }
-  if (failed()) {
-    return false;
-  }
-
-  if (IsImageQuery(inst.opcode())) {
-    return EmitImageQuery(inst);
-  }
-
-  if (IsSampledImageAccess(inst.opcode()) || IsRawImageAccess(inst.opcode())) {
-    return EmitImageAccess(inst);
-  }
-
-  switch (inst.opcode()) {
-    case SpvOpNop:
-      return true;
-
-    case SpvOpStore: {
-      auto ptr_id = inst.GetSingleWordInOperand(0);
-      const auto value_id = inst.GetSingleWordInOperand(1);
-
-      const auto ptr_type_id = def_use_mgr_->GetDef(ptr_id)->type_id();
-      const auto& builtin_position_info = parser_impl_.GetBuiltInPositionInfo();
-      if (ptr_type_id == builtin_position_info.pointer_type_id) {
-        return Fail()
-               << "storing to the whole per-vertex structure is not supported: "
-               << inst.PrettyPrint();
-      }
-
-      TypedExpression rhs = MakeExpression(value_id);
-      if (!rhs) {
-        return false;
-      }
-
-      TypedExpression lhs;
-
-      // Handle exceptional cases
-      switch (GetSkipReason(ptr_id)) {
-        case SkipReason::kPointSizeBuiltinPointer:
-          if (IsFloatOne(value_id)) {
-            // Don't store to PointSize
-            return true;
-          }
-          return Fail() << "cannot store a value other than constant 1.0 to "
-                           "PointSize builtin: "
-                        << inst.PrettyPrint();
-
-        case SkipReason::kSampleMaskOutBuiltinPointer:
-          lhs = MakeExpression(sample_mask_out_id);
-          if (lhs.type->Is<Pointer>()) {
-            // LHS of an assignment must be a reference type.
-            // Convert the LHS to a reference by dereferencing it.
-            lhs = Dereference(lhs);
-          }
-          // The private variable is an array whose element type is already of
-          // the same type as the value being stored into it.  Form the
-          // reference into the first element.
-          lhs.expr = create<ast::IndexAccessorExpression>(
-              Source{}, lhs.expr, parser_impl_.MakeNullValue(ty_.I32()));
-          if (auto* ref = lhs.type->As<Reference>()) {
-            lhs.type = ref->type;
-          }
-          if (auto* arr = lhs.type->As<Array>()) {
-            lhs.type = arr->type;
-          }
-          TINT_ASSERT(Reader, lhs.type);
-          break;
-        default:
-          break;
-      }
-
-      // Handle an ordinary store as an assignment.
-      if (!lhs) {
-        lhs = MakeExpression(ptr_id);
-      }
-      if (!lhs) {
-        return false;
-      }
-
-      if (lhs.type->Is<Pointer>()) {
-        // LHS of an assignment must be a reference type.
-        // Convert the LHS to a reference by dereferencing it.
-        lhs = Dereference(lhs);
-      }
-
-      AddStatement(
-          create<ast::AssignmentStatement>(Source{}, lhs.expr, rhs.expr));
-      return success();
-    }
-
-    case SpvOpLoad: {
-      // Memory accesses must be issued in SPIR-V program order.
-      // So represent a load by a new const definition.
-      const auto ptr_id = inst.GetSingleWordInOperand(0);
-      const auto skip_reason = GetSkipReason(ptr_id);
-
-      switch (skip_reason) {
-        case SkipReason::kPointSizeBuiltinPointer:
-          GetDefInfo(inst.result_id())->skip =
-              SkipReason::kPointSizeBuiltinValue;
-          return true;
-        case SkipReason::kSampleMaskInBuiltinPointer: {
-          auto name = namer_.Name(sample_mask_in_id);
-          const ast::Expression* id_expr = create<ast::IdentifierExpression>(
-              Source{}, builder_.Symbols().Register(name));
-          // SampleMask is an array in Vulkan SPIR-V. Always access the first
-          // element.
-          id_expr = create<ast::IndexAccessorExpression>(
-              Source{}, id_expr, parser_impl_.MakeNullValue(ty_.I32()));
-
-          auto* loaded_type = parser_impl_.ConvertType(inst.type_id());
-
-          if (!loaded_type->IsIntegerScalar()) {
-            return Fail() << "loading the whole SampleMask input array is not "
+    if (type_id != 0) {
+        const auto& builtin_position_info = parser_impl_.GetBuiltInPositionInfo();
+        if (type_id == builtin_position_info.struct_type_id) {
+            return Fail() << "operations producing a per-vertex structure are not "
                              "supported: "
                           << inst.PrettyPrint();
-          }
-
-          auto expr = TypedExpression{loaded_type, id_expr};
-          return EmitConstDefinition(inst, expr);
         }
+        if (type_id == builtin_position_info.pointer_type_id) {
+            return Fail() << "operations producing a pointer to a per-vertex "
+                             "structure are not "
+                             "supported: "
+                          << inst.PrettyPrint();
+        }
+    }
+
+    // Handle combinatorial instructions.
+    const auto* def_info = GetDefInfo(result_id);
+    if (def_info) {
+        TypedExpression combinatorial_expr;
+        if (def_info->skip == SkipReason::kDontSkip) {
+            combinatorial_expr = MaybeEmitCombinatorialValue(inst);
+            if (!success()) {
+                return false;
+            }
+        }
+        // An access chain or OpCopyObject can generate a skip.
+        if (def_info->skip != SkipReason::kDontSkip) {
+            return true;
+        }
+
+        if (combinatorial_expr.expr != nullptr) {
+            if (def_info->requires_hoisted_def || def_info->requires_named_const_def ||
+                def_info->num_uses != 1) {
+                // Generate a const definition or an assignment to a hoisted definition
+                // now and later use the const or variable name at the uses of this
+                // value.
+                return EmitConstDefOrWriteToHoistedVar(inst, combinatorial_expr);
+            }
+            // It is harmless to defer emitting the expression until it's used.
+            // Any supporting statements have already been emitted.
+            singly_used_values_.insert(std::make_pair(result_id, combinatorial_expr));
+            return success();
+        }
+    }
+    if (failed()) {
+        return false;
+    }
+
+    if (IsImageQuery(inst.opcode())) {
+        return EmitImageQuery(inst);
+    }
+
+    if (IsSampledImageAccess(inst.opcode()) || IsRawImageAccess(inst.opcode())) {
+        return EmitImageAccess(inst);
+    }
+
+    switch (inst.opcode()) {
+        case SpvOpNop:
+            return true;
+
+        case SpvOpStore: {
+            auto ptr_id = inst.GetSingleWordInOperand(0);
+            const auto value_id = inst.GetSingleWordInOperand(1);
+
+            const auto ptr_type_id = def_use_mgr_->GetDef(ptr_id)->type_id();
+            const auto& builtin_position_info = parser_impl_.GetBuiltInPositionInfo();
+            if (ptr_type_id == builtin_position_info.pointer_type_id) {
+                return Fail() << "storing to the whole per-vertex structure is not supported: "
+                              << inst.PrettyPrint();
+            }
+
+            TypedExpression rhs = MakeExpression(value_id);
+            if (!rhs) {
+                return false;
+            }
+
+            TypedExpression lhs;
+
+            // Handle exceptional cases
+            switch (GetSkipReason(ptr_id)) {
+                case SkipReason::kPointSizeBuiltinPointer:
+                    if (IsFloatOne(value_id)) {
+                        // Don't store to PointSize
+                        return true;
+                    }
+                    return Fail() << "cannot store a value other than constant 1.0 to "
+                                     "PointSize builtin: "
+                                  << inst.PrettyPrint();
+
+                case SkipReason::kSampleMaskOutBuiltinPointer:
+                    lhs = MakeExpression(sample_mask_out_id);
+                    if (lhs.type->Is<Pointer>()) {
+                        // LHS of an assignment must be a reference type.
+                        // Convert the LHS to a reference by dereferencing it.
+                        lhs = Dereference(lhs);
+                    }
+                    // The private variable is an array whose element type is already of
+                    // the same type as the value being stored into it.  Form the
+                    // reference into the first element.
+                    lhs.expr = create<ast::IndexAccessorExpression>(
+                        Source{}, lhs.expr, parser_impl_.MakeNullValue(ty_.I32()));
+                    if (auto* ref = lhs.type->As<Reference>()) {
+                        lhs.type = ref->type;
+                    }
+                    if (auto* arr = lhs.type->As<Array>()) {
+                        lhs.type = arr->type;
+                    }
+                    TINT_ASSERT(Reader, lhs.type);
+                    break;
+                default:
+                    break;
+            }
+
+            // Handle an ordinary store as an assignment.
+            if (!lhs) {
+                lhs = MakeExpression(ptr_id);
+            }
+            if (!lhs) {
+                return false;
+            }
+
+            if (lhs.type->Is<Pointer>()) {
+                // LHS of an assignment must be a reference type.
+                // Convert the LHS to a reference by dereferencing it.
+                lhs = Dereference(lhs);
+            }
+
+            AddStatement(create<ast::AssignmentStatement>(Source{}, lhs.expr, rhs.expr));
+            return success();
+        }
+
+        case SpvOpLoad: {
+            // Memory accesses must be issued in SPIR-V program order.
+            // So represent a load by a new const definition.
+            const auto ptr_id = inst.GetSingleWordInOperand(0);
+            const auto skip_reason = GetSkipReason(ptr_id);
+
+            switch (skip_reason) {
+                case SkipReason::kPointSizeBuiltinPointer:
+                    GetDefInfo(inst.result_id())->skip = SkipReason::kPointSizeBuiltinValue;
+                    return true;
+                case SkipReason::kSampleMaskInBuiltinPointer: {
+                    auto name = namer_.Name(sample_mask_in_id);
+                    const ast::Expression* id_expr = create<ast::IdentifierExpression>(
+                        Source{}, builder_.Symbols().Register(name));
+                    // SampleMask is an array in Vulkan SPIR-V. Always access the first
+                    // element.
+                    id_expr = create<ast::IndexAccessorExpression>(
+                        Source{}, id_expr, parser_impl_.MakeNullValue(ty_.I32()));
+
+                    auto* loaded_type = parser_impl_.ConvertType(inst.type_id());
+
+                    if (!loaded_type->IsIntegerScalar()) {
+                        return Fail() << "loading the whole SampleMask input array is not "
+                                         "supported: "
+                                      << inst.PrettyPrint();
+                    }
+
+                    auto expr = TypedExpression{loaded_type, id_expr};
+                    return EmitConstDefinition(inst, expr);
+                }
+                default:
+                    break;
+            }
+            auto expr = MakeExpression(ptr_id);
+            if (!expr) {
+                return false;
+            }
+
+            // The load result type is the storage type of its operand.
+            if (expr.type->Is<Pointer>()) {
+                expr = Dereference(expr);
+            } else if (auto* ref = expr.type->As<Reference>()) {
+                expr.type = ref->type;
+            } else {
+                Fail() << "OpLoad expression is not a pointer or reference";
+                return false;
+            }
+
+            return EmitConstDefOrWriteToHoistedVar(inst, expr);
+        }
+
+        case SpvOpCopyMemory: {
+            // Generate an assignment.
+            auto lhs = MakeOperand(inst, 0);
+            auto rhs = MakeOperand(inst, 1);
+            // Ignore any potential memory operands. Currently they are all for
+            // concepts not in WGSL:
+            //   Volatile
+            //   Aligned
+            //   Nontemporal
+            //   MakePointerAvailable ; Vulkan memory model
+            //   MakePointerVisible   ; Vulkan memory model
+            //   NonPrivatePointer    ; Vulkan memory model
+
+            if (!success()) {
+                return false;
+            }
+
+            // LHS and RHS pointers must be reference types in WGSL.
+            if (lhs.type->Is<Pointer>()) {
+                lhs = Dereference(lhs);
+            }
+            if (rhs.type->Is<Pointer>()) {
+                rhs = Dereference(rhs);
+            }
+
+            AddStatement(create<ast::AssignmentStatement>(Source{}, lhs.expr, rhs.expr));
+            return success();
+        }
+
+        case SpvOpCopyObject: {
+            // Arguably, OpCopyObject is purely combinatorial. On the other hand,
+            // it exists to make a new name for something. So we choose to make
+            // a new named constant definition.
+            auto value_id = inst.GetSingleWordInOperand(0);
+            const auto skip = GetSkipReason(value_id);
+            if (skip != SkipReason::kDontSkip) {
+                GetDefInfo(inst.result_id())->skip = skip;
+                GetDefInfo(inst.result_id())->sink_pointer_source_expr =
+                    GetDefInfo(value_id)->sink_pointer_source_expr;
+                return true;
+            }
+            auto expr = AddressOfIfNeeded(MakeExpression(value_id), &inst);
+            if (!expr) {
+                return false;
+            }
+            expr.type = RemapStorageClass(expr.type, result_id);
+            return EmitConstDefOrWriteToHoistedVar(inst, expr);
+        }
+
+        case SpvOpPhi: {
+            // Emit a read from the associated state variable.
+            TypedExpression expr{parser_impl_.ConvertType(inst.type_id()),
+                                 create<ast::IdentifierExpression>(
+                                     Source{}, builder_.Symbols().Register(def_info->phi_var))};
+            return EmitConstDefOrWriteToHoistedVar(inst, expr);
+        }
+
+        case SpvOpOuterProduct:
+            // Synthesize an outer product expression in its own statement.
+            return EmitConstDefOrWriteToHoistedVar(inst, MakeOuterProduct(inst));
+
+        case SpvOpVectorInsertDynamic:
+            // Synthesize a vector insertion in its own statements.
+            return MakeVectorInsertDynamic(inst);
+
+        case SpvOpCompositeInsert:
+            // Synthesize a composite insertion in its own statements.
+            return MakeCompositeInsert(inst);
+
+        case SpvOpFunctionCall:
+            return EmitFunctionCall(inst);
+
+        case SpvOpControlBarrier:
+            return EmitControlBarrier(inst);
+
+        case SpvOpExtInst:
+            if (parser_impl_.IsIgnoredExtendedInstruction(inst)) {
+                return true;
+            }
+            break;
+
+        case SpvOpIAddCarry:
+        case SpvOpISubBorrow:
+        case SpvOpUMulExtended:
+        case SpvOpSMulExtended:
+            return Fail() << "extended arithmetic is not finalized for WGSL: "
+                             "https://github.com/gpuweb/gpuweb/issues/1565: "
+                          << inst.PrettyPrint();
+
         default:
-          break;
-      }
-      auto expr = MakeExpression(ptr_id);
-      if (!expr) {
-        return false;
-      }
-
-      // The load result type is the storage type of its operand.
-      if (expr.type->Is<Pointer>()) {
-        expr = Dereference(expr);
-      } else if (auto* ref = expr.type->As<Reference>()) {
-        expr.type = ref->type;
-      } else {
-        Fail() << "OpLoad expression is not a pointer or reference";
-        return false;
-      }
-
-      return EmitConstDefOrWriteToHoistedVar(inst, expr);
+            break;
     }
-
-    case SpvOpCopyMemory: {
-      // Generate an assignment.
-      auto lhs = MakeOperand(inst, 0);
-      auto rhs = MakeOperand(inst, 1);
-      // Ignore any potential memory operands. Currently they are all for
-      // concepts not in WGSL:
-      //   Volatile
-      //   Aligned
-      //   Nontemporal
-      //   MakePointerAvailable ; Vulkan memory model
-      //   MakePointerVisible   ; Vulkan memory model
-      //   NonPrivatePointer    ; Vulkan memory model
-
-      if (!success()) {
-        return false;
-      }
-
-      // LHS and RHS pointers must be reference types in WGSL.
-      if (lhs.type->Is<Pointer>()) {
-        lhs = Dereference(lhs);
-      }
-      if (rhs.type->Is<Pointer>()) {
-        rhs = Dereference(rhs);
-      }
-
-      AddStatement(
-          create<ast::AssignmentStatement>(Source{}, lhs.expr, rhs.expr));
-      return success();
-    }
-
-    case SpvOpCopyObject: {
-      // Arguably, OpCopyObject is purely combinatorial. On the other hand,
-      // it exists to make a new name for something. So we choose to make
-      // a new named constant definition.
-      auto value_id = inst.GetSingleWordInOperand(0);
-      const auto skip = GetSkipReason(value_id);
-      if (skip != SkipReason::kDontSkip) {
-        GetDefInfo(inst.result_id())->skip = skip;
-        GetDefInfo(inst.result_id())->sink_pointer_source_expr =
-            GetDefInfo(value_id)->sink_pointer_source_expr;
-        return true;
-      }
-      auto expr = AddressOfIfNeeded(MakeExpression(value_id), &inst);
-      if (!expr) {
-        return false;
-      }
-      expr.type = RemapStorageClass(expr.type, result_id);
-      return EmitConstDefOrWriteToHoistedVar(inst, expr);
-    }
-
-    case SpvOpPhi: {
-      // Emit a read from the associated state variable.
-      TypedExpression expr{
-          parser_impl_.ConvertType(inst.type_id()),
-          create<ast::IdentifierExpression>(
-              Source{}, builder_.Symbols().Register(def_info->phi_var))};
-      return EmitConstDefOrWriteToHoistedVar(inst, expr);
-    }
-
-    case SpvOpOuterProduct:
-      // Synthesize an outer product expression in its own statement.
-      return EmitConstDefOrWriteToHoistedVar(inst, MakeOuterProduct(inst));
-
-    case SpvOpVectorInsertDynamic:
-      // Synthesize a vector insertion in its own statements.
-      return MakeVectorInsertDynamic(inst);
-
-    case SpvOpCompositeInsert:
-      // Synthesize a composite insertion in its own statements.
-      return MakeCompositeInsert(inst);
-
-    case SpvOpFunctionCall:
-      return EmitFunctionCall(inst);
-
-    case SpvOpControlBarrier:
-      return EmitControlBarrier(inst);
-
-    case SpvOpExtInst:
-      if (parser_impl_.IsIgnoredExtendedInstruction(inst)) {
-        return true;
-      }
-      break;
-
-    case SpvOpIAddCarry:
-    case SpvOpISubBorrow:
-    case SpvOpUMulExtended:
-    case SpvOpSMulExtended:
-      return Fail() << "extended arithmetic is not finalized for WGSL: "
-                       "https://github.com/gpuweb/gpuweb/issues/1565: "
-                    << inst.PrettyPrint();
-
-    default:
-      break;
-  }
-  return Fail() << "unhandled instruction with opcode " << inst.opcode() << ": "
-                << inst.PrettyPrint();
+    return Fail() << "unhandled instruction with opcode " << inst.opcode() << ": "
+                  << inst.PrettyPrint();
 }
 
-TypedExpression FunctionEmitter::MakeOperand(
-    const spvtools::opt::Instruction& inst,
-    uint32_t operand_index) {
-  auto expr = MakeExpression(inst.GetSingleWordInOperand(operand_index));
-  if (!expr) {
-    return {};
-  }
-  return parser_impl_.RectifyOperandSignedness(inst, std::move(expr));
+TypedExpression FunctionEmitter::MakeOperand(const spvtools::opt::Instruction& inst,
+                                             uint32_t operand_index) {
+    auto expr = MakeExpression(inst.GetSingleWordInOperand(operand_index));
+    if (!expr) {
+        return {};
+    }
+    return parser_impl_.RectifyOperandSignedness(inst, std::move(expr));
 }
 
-TypedExpression FunctionEmitter::InferFunctionStorageClass(
-    TypedExpression expr) {
-  TypedExpression result(expr);
-  if (const auto* ref = expr.type->UnwrapAlias()->As<Reference>()) {
-    if (ref->storage_class == ast::StorageClass::kNone) {
-      expr.type = ty_.Reference(ref->type, ast::StorageClass::kFunction);
+TypedExpression FunctionEmitter::InferFunctionStorageClass(TypedExpression expr) {
+    TypedExpression result(expr);
+    if (const auto* ref = expr.type->UnwrapAlias()->As<Reference>()) {
+        if (ref->storage_class == ast::StorageClass::kNone) {
+            expr.type = ty_.Reference(ref->type, ast::StorageClass::kFunction);
+        }
+    } else if (const auto* ptr = expr.type->UnwrapAlias()->As<Pointer>()) {
+        if (ptr->storage_class == ast::StorageClass::kNone) {
+            expr.type = ty_.Pointer(ptr->type, ast::StorageClass::kFunction);
+        }
     }
-  } else if (const auto* ptr = expr.type->UnwrapAlias()->As<Pointer>()) {
-    if (ptr->storage_class == ast::StorageClass::kNone) {
-      expr.type = ty_.Pointer(ptr->type, ast::StorageClass::kFunction);
-    }
-  }
-  return expr;
+    return expr;
 }
 
 TypedExpression FunctionEmitter::MaybeEmitCombinatorialValue(
     const spvtools::opt::Instruction& inst) {
-  if (inst.result_id() == 0) {
+    if (inst.result_id() == 0) {
+        return {};
+    }
+
+    const auto opcode = inst.opcode();
+
+    const Type* ast_type = nullptr;
+    if (inst.type_id()) {
+        ast_type = parser_impl_.ConvertType(inst.type_id());
+        if (!ast_type) {
+            Fail() << "couldn't convert result type for: " << inst.PrettyPrint();
+            return {};
+        }
+    }
+
+    auto binary_op = ConvertBinaryOp(opcode);
+    if (binary_op != ast::BinaryOp::kNone) {
+        auto arg0 = MakeOperand(inst, 0);
+        auto arg1 =
+            parser_impl_.RectifySecondOperandSignedness(inst, arg0.type, MakeOperand(inst, 1));
+        if (!arg0 || !arg1) {
+            return {};
+        }
+        auto* binary_expr =
+            create<ast::BinaryExpression>(Source{}, binary_op, arg0.expr, arg1.expr);
+        TypedExpression result{ast_type, binary_expr};
+        return parser_impl_.RectifyForcedResultType(result, inst, arg0.type);
+    }
+
+    auto unary_op = ast::UnaryOp::kNegation;
+    if (GetUnaryOp(opcode, &unary_op)) {
+        auto arg0 = MakeOperand(inst, 0);
+        auto* unary_expr = create<ast::UnaryOpExpression>(Source{}, unary_op, arg0.expr);
+        TypedExpression result{ast_type, unary_expr};
+        return parser_impl_.RectifyForcedResultType(result, inst, arg0.type);
+    }
+
+    const char* unary_builtin_name = GetUnaryBuiltInFunctionName(opcode);
+    if (unary_builtin_name != nullptr) {
+        ast::ExpressionList params;
+        params.emplace_back(MakeOperand(inst, 0).expr);
+        return {ast_type, create<ast::CallExpression>(
+                              Source{},
+                              create<ast::IdentifierExpression>(
+                                  Source{}, builder_.Symbols().Register(unary_builtin_name)),
+                              std::move(params))};
+    }
+
+    const auto builtin = GetBuiltin(opcode);
+    if (builtin != sem::BuiltinType::kNone) {
+        return MakeBuiltinCall(inst);
+    }
+
+    if (opcode == SpvOpFMod) {
+        return MakeFMod(inst);
+    }
+
+    if (opcode == SpvOpAccessChain || opcode == SpvOpInBoundsAccessChain) {
+        return MakeAccessChain(inst);
+    }
+
+    if (opcode == SpvOpBitcast) {
+        return {ast_type, create<ast::BitcastExpression>(Source{}, ast_type->Build(builder_),
+                                                         MakeOperand(inst, 0).expr)};
+    }
+
+    if (opcode == SpvOpShiftLeftLogical || opcode == SpvOpShiftRightLogical ||
+        opcode == SpvOpShiftRightArithmetic) {
+        auto arg0 = MakeOperand(inst, 0);
+        // The second operand must be unsigned. It's ok to wrap the shift amount
+        // since the shift is modulo the bit width of the first operand.
+        auto arg1 = parser_impl_.AsUnsigned(MakeOperand(inst, 1));
+
+        switch (opcode) {
+            case SpvOpShiftLeftLogical:
+                binary_op = ast::BinaryOp::kShiftLeft;
+                break;
+            case SpvOpShiftRightLogical:
+                arg0 = parser_impl_.AsUnsigned(arg0);
+                binary_op = ast::BinaryOp::kShiftRight;
+                break;
+            case SpvOpShiftRightArithmetic:
+                arg0 = parser_impl_.AsSigned(arg0);
+                binary_op = ast::BinaryOp::kShiftRight;
+                break;
+            default:
+                break;
+        }
+        TypedExpression result{
+            ast_type, create<ast::BinaryExpression>(Source{}, binary_op, arg0.expr, arg1.expr)};
+        return parser_impl_.RectifyForcedResultType(result, inst, arg0.type);
+    }
+
+    auto negated_op = NegatedFloatCompare(opcode);
+    if (negated_op != ast::BinaryOp::kNone) {
+        auto arg0 = MakeOperand(inst, 0);
+        auto arg1 = MakeOperand(inst, 1);
+        auto* binary_expr =
+            create<ast::BinaryExpression>(Source{}, negated_op, arg0.expr, arg1.expr);
+        auto* negated_expr =
+            create<ast::UnaryOpExpression>(Source{}, ast::UnaryOp::kNot, binary_expr);
+        return {ast_type, negated_expr};
+    }
+
+    if (opcode == SpvOpExtInst) {
+        if (parser_impl_.IsIgnoredExtendedInstruction(inst)) {
+            // Ignore it but don't error out.
+            return {};
+        }
+        if (!parser_impl_.IsGlslExtendedInstruction(inst)) {
+            Fail() << "unhandled extended instruction import with ID "
+                   << inst.GetSingleWordInOperand(0);
+            return {};
+        }
+        return EmitGlslStd450ExtInst(inst);
+    }
+
+    if (opcode == SpvOpCompositeConstruct) {
+        ast::ExpressionList operands;
+        for (uint32_t iarg = 0; iarg < inst.NumInOperands(); ++iarg) {
+            operands.emplace_back(MakeOperand(inst, iarg).expr);
+        }
+        return {ast_type,
+                builder_.Construct(Source{}, ast_type->Build(builder_), std::move(operands))};
+    }
+
+    if (opcode == SpvOpCompositeExtract) {
+        return MakeCompositeExtract(inst);
+    }
+
+    if (opcode == SpvOpVectorShuffle) {
+        return MakeVectorShuffle(inst);
+    }
+
+    if (opcode == SpvOpVectorExtractDynamic) {
+        return {ast_type, create<ast::IndexAccessorExpression>(Source{}, MakeOperand(inst, 0).expr,
+                                                               MakeOperand(inst, 1).expr)};
+    }
+
+    if (opcode == SpvOpConvertSToF || opcode == SpvOpConvertUToF || opcode == SpvOpConvertFToS ||
+        opcode == SpvOpConvertFToU) {
+        return MakeNumericConversion(inst);
+    }
+
+    if (opcode == SpvOpUndef) {
+        // Replace undef with the null value.
+        return parser_impl_.MakeNullExpression(ast_type);
+    }
+
+    if (opcode == SpvOpSelect) {
+        return MakeSimpleSelect(inst);
+    }
+
+    if (opcode == SpvOpArrayLength) {
+        return MakeArrayLength(inst);
+    }
+
+    // builtin readonly function
+    // glsl.std.450 readonly function
+
+    // Instructions:
+    //    OpSatConvertSToU // Only in Kernel (OpenCL), not in WebGPU
+    //    OpSatConvertUToS // Only in Kernel (OpenCL), not in WebGPU
+    //    OpUConvert // Only needed when multiple widths supported
+    //    OpSConvert // Only needed when multiple widths supported
+    //    OpFConvert // Only needed when multiple widths supported
+    //    OpConvertPtrToU // Not in WebGPU
+    //    OpConvertUToPtr // Not in WebGPU
+    //    OpPtrCastToGeneric // Not in Vulkan
+    //    OpGenericCastToPtr // Not in Vulkan
+    //    OpGenericCastToPtrExplicit // Not in Vulkan
+
     return {};
-  }
-
-  const auto opcode = inst.opcode();
-
-  const Type* ast_type = nullptr;
-  if (inst.type_id()) {
-    ast_type = parser_impl_.ConvertType(inst.type_id());
-    if (!ast_type) {
-      Fail() << "couldn't convert result type for: " << inst.PrettyPrint();
-      return {};
-    }
-  }
-
-  auto binary_op = ConvertBinaryOp(opcode);
-  if (binary_op != ast::BinaryOp::kNone) {
-    auto arg0 = MakeOperand(inst, 0);
-    auto arg1 = parser_impl_.RectifySecondOperandSignedness(
-        inst, arg0.type, MakeOperand(inst, 1));
-    if (!arg0 || !arg1) {
-      return {};
-    }
-    auto* binary_expr = create<ast::BinaryExpression>(Source{}, binary_op,
-                                                      arg0.expr, arg1.expr);
-    TypedExpression result{ast_type, binary_expr};
-    return parser_impl_.RectifyForcedResultType(result, inst, arg0.type);
-  }
-
-  auto unary_op = ast::UnaryOp::kNegation;
-  if (GetUnaryOp(opcode, &unary_op)) {
-    auto arg0 = MakeOperand(inst, 0);
-    auto* unary_expr =
-        create<ast::UnaryOpExpression>(Source{}, unary_op, arg0.expr);
-    TypedExpression result{ast_type, unary_expr};
-    return parser_impl_.RectifyForcedResultType(result, inst, arg0.type);
-  }
-
-  const char* unary_builtin_name = GetUnaryBuiltInFunctionName(opcode);
-  if (unary_builtin_name != nullptr) {
-    ast::ExpressionList params;
-    params.emplace_back(MakeOperand(inst, 0).expr);
-    return {ast_type,
-            create<ast::CallExpression>(
-                Source{},
-                create<ast::IdentifierExpression>(
-                    Source{}, builder_.Symbols().Register(unary_builtin_name)),
-                std::move(params))};
-  }
-
-  const auto builtin = GetBuiltin(opcode);
-  if (builtin != sem::BuiltinType::kNone) {
-    return MakeBuiltinCall(inst);
-  }
-
-  if (opcode == SpvOpFMod) {
-    return MakeFMod(inst);
-  }
-
-  if (opcode == SpvOpAccessChain || opcode == SpvOpInBoundsAccessChain) {
-    return MakeAccessChain(inst);
-  }
-
-  if (opcode == SpvOpBitcast) {
-    return {ast_type,
-            create<ast::BitcastExpression>(Source{}, ast_type->Build(builder_),
-                                           MakeOperand(inst, 0).expr)};
-  }
-
-  if (opcode == SpvOpShiftLeftLogical || opcode == SpvOpShiftRightLogical ||
-      opcode == SpvOpShiftRightArithmetic) {
-    auto arg0 = MakeOperand(inst, 0);
-    // The second operand must be unsigned. It's ok to wrap the shift amount
-    // since the shift is modulo the bit width of the first operand.
-    auto arg1 = parser_impl_.AsUnsigned(MakeOperand(inst, 1));
-
-    switch (opcode) {
-      case SpvOpShiftLeftLogical:
-        binary_op = ast::BinaryOp::kShiftLeft;
-        break;
-      case SpvOpShiftRightLogical:
-        arg0 = parser_impl_.AsUnsigned(arg0);
-        binary_op = ast::BinaryOp::kShiftRight;
-        break;
-      case SpvOpShiftRightArithmetic:
-        arg0 = parser_impl_.AsSigned(arg0);
-        binary_op = ast::BinaryOp::kShiftRight;
-        break;
-      default:
-        break;
-    }
-    TypedExpression result{
-        ast_type, create<ast::BinaryExpression>(Source{}, binary_op, arg0.expr,
-                                                arg1.expr)};
-    return parser_impl_.RectifyForcedResultType(result, inst, arg0.type);
-  }
-
-  auto negated_op = NegatedFloatCompare(opcode);
-  if (negated_op != ast::BinaryOp::kNone) {
-    auto arg0 = MakeOperand(inst, 0);
-    auto arg1 = MakeOperand(inst, 1);
-    auto* binary_expr = create<ast::BinaryExpression>(Source{}, negated_op,
-                                                      arg0.expr, arg1.expr);
-    auto* negated_expr = create<ast::UnaryOpExpression>(
-        Source{}, ast::UnaryOp::kNot, binary_expr);
-    return {ast_type, negated_expr};
-  }
-
-  if (opcode == SpvOpExtInst) {
-    if (parser_impl_.IsIgnoredExtendedInstruction(inst)) {
-      // Ignore it but don't error out.
-      return {};
-    }
-    if (!parser_impl_.IsGlslExtendedInstruction(inst)) {
-      Fail() << "unhandled extended instruction import with ID "
-             << inst.GetSingleWordInOperand(0);
-      return {};
-    }
-    return EmitGlslStd450ExtInst(inst);
-  }
-
-  if (opcode == SpvOpCompositeConstruct) {
-    ast::ExpressionList operands;
-    for (uint32_t iarg = 0; iarg < inst.NumInOperands(); ++iarg) {
-      operands.emplace_back(MakeOperand(inst, iarg).expr);
-    }
-    return {ast_type, builder_.Construct(Source{}, ast_type->Build(builder_),
-                                         std::move(operands))};
-  }
-
-  if (opcode == SpvOpCompositeExtract) {
-    return MakeCompositeExtract(inst);
-  }
-
-  if (opcode == SpvOpVectorShuffle) {
-    return MakeVectorShuffle(inst);
-  }
-
-  if (opcode == SpvOpVectorExtractDynamic) {
-    return {ast_type, create<ast::IndexAccessorExpression>(
-                          Source{}, MakeOperand(inst, 0).expr,
-                          MakeOperand(inst, 1).expr)};
-  }
-
-  if (opcode == SpvOpConvertSToF || opcode == SpvOpConvertUToF ||
-      opcode == SpvOpConvertFToS || opcode == SpvOpConvertFToU) {
-    return MakeNumericConversion(inst);
-  }
-
-  if (opcode == SpvOpUndef) {
-    // Replace undef with the null value.
-    return parser_impl_.MakeNullExpression(ast_type);
-  }
-
-  if (opcode == SpvOpSelect) {
-    return MakeSimpleSelect(inst);
-  }
-
-  if (opcode == SpvOpArrayLength) {
-    return MakeArrayLength(inst);
-  }
-
-  // builtin readonly function
-  // glsl.std.450 readonly function
-
-  // Instructions:
-  //    OpSatConvertSToU // Only in Kernel (OpenCL), not in WebGPU
-  //    OpSatConvertUToS // Only in Kernel (OpenCL), not in WebGPU
-  //    OpUConvert // Only needed when multiple widths supported
-  //    OpSConvert // Only needed when multiple widths supported
-  //    OpFConvert // Only needed when multiple widths supported
-  //    OpConvertPtrToU // Not in WebGPU
-  //    OpConvertUToPtr // Not in WebGPU
-  //    OpPtrCastToGeneric // Not in Vulkan
-  //    OpGenericCastToPtr // Not in Vulkan
-  //    OpGenericCastToPtrExplicit // Not in Vulkan
-
-  return {};
 }
 
-TypedExpression FunctionEmitter::EmitGlslStd450ExtInst(
-    const spvtools::opt::Instruction& inst) {
-  const auto ext_opcode = inst.GetSingleWordInOperand(1);
+TypedExpression FunctionEmitter::EmitGlslStd450ExtInst(const spvtools::opt::Instruction& inst) {
+    const auto ext_opcode = inst.GetSingleWordInOperand(1);
 
-  if (ext_opcode == GLSLstd450Ldexp) {
-    // WGSL requires the second argument to be signed.
-    // Use a type constructor to convert it, which is the same as a bitcast.
-    // If the value would go from very large positive to negative, then the
-    // original result would have been infinity.  And since WGSL
-    // implementations may assume that infinities are not present, then we
-    // don't have to worry about that case.
-    auto e1 = MakeOperand(inst, 2);
-    auto e2 = ToSignedIfUnsigned(MakeOperand(inst, 3));
+    if (ext_opcode == GLSLstd450Ldexp) {
+        // WGSL requires the second argument to be signed.
+        // Use a type constructor to convert it, which is the same as a bitcast.
+        // If the value would go from very large positive to negative, then the
+        // original result would have been infinity.  And since WGSL
+        // implementations may assume that infinities are not present, then we
+        // don't have to worry about that case.
+        auto e1 = MakeOperand(inst, 2);
+        auto e2 = ToSignedIfUnsigned(MakeOperand(inst, 3));
 
-    return {e1.type, builder_.Call(Source{}, "ldexp",
-                                   ast::ExpressionList{e1.expr, e2.expr})};
-  }
+        return {e1.type, builder_.Call(Source{}, "ldexp", ast::ExpressionList{e1.expr, e2.expr})};
+    }
 
-  auto* result_type = parser_impl_.ConvertType(inst.type_id());
+    auto* result_type = parser_impl_.ConvertType(inst.type_id());
 
-  if (result_type->IsScalar()) {
-    // Some GLSLstd450 builtins have scalar forms not supported by WGSL.
-    // Emulate them.
-    switch (ext_opcode) {
-      case GLSLstd450Normalize:
-        // WGSL does not have scalar form of the normalize builtin.
-        // The answer would be 1 anyway, so return that directly.
-        return {ty_.F32(), builder_.Expr(1.0f)};
+    if (result_type->IsScalar()) {
+        // Some GLSLstd450 builtins have scalar forms not supported by WGSL.
+        // Emulate them.
+        switch (ext_opcode) {
+            case GLSLstd450Normalize:
+                // WGSL does not have scalar form of the normalize builtin.
+                // The answer would be 1 anyway, so return that directly.
+                return {ty_.F32(), builder_.Expr(1.0f)};
 
-      case GLSLstd450FaceForward: {
-        // If dot(Nref, Incident) < 0, the result is Normal, otherwise -Normal.
-        // Also: select(-normal,normal, Incident*Nref < 0)
-        // (The dot product of scalars is their product.)
-        // Use a multiply instead of comparing floating point signs. It should
-        // be among the fastest operations on a GPU.
-        auto normal = MakeOperand(inst, 2);
-        auto incident = MakeOperand(inst, 3);
-        auto nref = MakeOperand(inst, 4);
-        TINT_ASSERT(Reader, normal.type->Is<F32>());
-        TINT_ASSERT(Reader, incident.type->Is<F32>());
-        TINT_ASSERT(Reader, nref.type->Is<F32>());
-        return {ty_.F32(),
-                builder_.Call(
-                    Source{}, "select",
-                    ast::ExpressionList{
-                        create<ast::UnaryOpExpression>(
-                            Source{}, ast::UnaryOp::kNegation, normal.expr),
-                        normal.expr,
-                        create<ast::BinaryExpression>(
-                            Source{}, ast::BinaryOp::kLessThan,
-                            builder_.Mul({}, incident.expr, nref.expr),
-                            builder_.Expr(0.0f))})};
-      }
+            case GLSLstd450FaceForward: {
+                // If dot(Nref, Incident) < 0, the result is Normal, otherwise -Normal.
+                // Also: select(-normal,normal, Incident*Nref < 0)
+                // (The dot product of scalars is their product.)
+                // Use a multiply instead of comparing floating point signs. It should
+                // be among the fastest operations on a GPU.
+                auto normal = MakeOperand(inst, 2);
+                auto incident = MakeOperand(inst, 3);
+                auto nref = MakeOperand(inst, 4);
+                TINT_ASSERT(Reader, normal.type->Is<F32>());
+                TINT_ASSERT(Reader, incident.type->Is<F32>());
+                TINT_ASSERT(Reader, nref.type->Is<F32>());
+                return {ty_.F32(),
+                        builder_.Call(
+                            Source{}, "select",
+                            ast::ExpressionList{create<ast::UnaryOpExpression>(
+                                                    Source{}, ast::UnaryOp::kNegation, normal.expr),
+                                                normal.expr,
+                                                create<ast::BinaryExpression>(
+                                                    Source{}, ast::BinaryOp::kLessThan,
+                                                    builder_.Mul({}, incident.expr, nref.expr),
+                                                    builder_.Expr(0.0f))})};
+            }
 
-      case GLSLstd450Reflect: {
-        // Compute  Incident - 2 * Normal * Normal * Incident
-        auto incident = MakeOperand(inst, 2);
-        auto normal = MakeOperand(inst, 3);
-        TINT_ASSERT(Reader, incident.type->Is<F32>());
-        TINT_ASSERT(Reader, normal.type->Is<F32>());
-        return {
-            ty_.F32(),
-            builder_.Sub(
-                incident.expr,
-                builder_.Mul(2.0f, builder_.Mul(normal.expr,
-                                                builder_.Mul(normal.expr,
-                                                             incident.expr))))};
-      }
+            case GLSLstd450Reflect: {
+                // Compute  Incident - 2 * Normal * Normal * Incident
+                auto incident = MakeOperand(inst, 2);
+                auto normal = MakeOperand(inst, 3);
+                TINT_ASSERT(Reader, incident.type->Is<F32>());
+                TINT_ASSERT(Reader, normal.type->Is<F32>());
+                return {ty_.F32(),
+                        builder_.Sub(
+                            incident.expr,
+                            builder_.Mul(2.0f,
+                                         builder_.Mul(normal.expr,
+                                                      builder_.Mul(normal.expr, incident.expr))))};
+            }
 
-      case GLSLstd450Refract: {
-        // It's a complicated expression. Compute it in two dimensions, but
-        // with a 0-valued y component in both the incident and normal vectors,
-        // then take the x component of that result.
-        auto incident = MakeOperand(inst, 2);
-        auto normal = MakeOperand(inst, 3);
-        auto eta = MakeOperand(inst, 4);
-        TINT_ASSERT(Reader, incident.type->Is<F32>());
-        TINT_ASSERT(Reader, normal.type->Is<F32>());
-        TINT_ASSERT(Reader, eta.type->Is<F32>());
-        if (!success()) {
-          return {};
+            case GLSLstd450Refract: {
+                // It's a complicated expression. Compute it in two dimensions, but
+                // with a 0-valued y component in both the incident and normal vectors,
+                // then take the x component of that result.
+                auto incident = MakeOperand(inst, 2);
+                auto normal = MakeOperand(inst, 3);
+                auto eta = MakeOperand(inst, 4);
+                TINT_ASSERT(Reader, incident.type->Is<F32>());
+                TINT_ASSERT(Reader, normal.type->Is<F32>());
+                TINT_ASSERT(Reader, eta.type->Is<F32>());
+                if (!success()) {
+                    return {};
+                }
+                const Type* f32 = eta.type;
+                return {f32,
+                        builder_.MemberAccessor(
+                            builder_.Call(Source{}, "refract",
+                                          ast::ExpressionList{
+                                              builder_.vec2<float>(incident.expr, 0.0f),
+                                              builder_.vec2<float>(normal.expr, 0.0f), eta.expr}),
+                            "x")};
+            }
+            default:
+                break;
         }
-        const Type* f32 = eta.type;
-        return {f32,
-                builder_.MemberAccessor(
-                    builder_.Call(
-                        Source{}, "refract",
-                        ast::ExpressionList{
-                            builder_.vec2<float>(incident.expr, 0.0f),
-                            builder_.vec2<float>(normal.expr, 0.0f), eta.expr}),
-                    "x")};
-      }
-      default:
-        break;
     }
-  }
 
-  const auto name = GetGlslStd450FuncName(ext_opcode);
-  if (name.empty()) {
-    Fail() << "unhandled GLSL.std.450 instruction " << ext_opcode;
-    return {};
-  }
-
-  auto* func = create<ast::IdentifierExpression>(
-      Source{}, builder_.Symbols().Register(name));
-  ast::ExpressionList operands;
-  const Type* first_operand_type = nullptr;
-  // All parameters to GLSL.std.450 extended instructions are IDs.
-  for (uint32_t iarg = 2; iarg < inst.NumInOperands(); ++iarg) {
-    TypedExpression operand = MakeOperand(inst, iarg);
-    if (first_operand_type == nullptr) {
-      first_operand_type = operand.type;
+    const auto name = GetGlslStd450FuncName(ext_opcode);
+    if (name.empty()) {
+        Fail() << "unhandled GLSL.std.450 instruction " << ext_opcode;
+        return {};
     }
-    operands.emplace_back(operand.expr);
-  }
-  auto* call = create<ast::CallExpression>(Source{}, func, std::move(operands));
-  TypedExpression call_expr{result_type, call};
-  return parser_impl_.RectifyForcedResultType(call_expr, inst,
-                                              first_operand_type);
+
+    auto* func = create<ast::IdentifierExpression>(Source{}, builder_.Symbols().Register(name));
+    ast::ExpressionList operands;
+    const Type* first_operand_type = nullptr;
+    // All parameters to GLSL.std.450 extended instructions are IDs.
+    for (uint32_t iarg = 2; iarg < inst.NumInOperands(); ++iarg) {
+        TypedExpression operand = MakeOperand(inst, iarg);
+        if (first_operand_type == nullptr) {
+            first_operand_type = operand.type;
+        }
+        operands.emplace_back(operand.expr);
+    }
+    auto* call = create<ast::CallExpression>(Source{}, func, std::move(operands));
+    TypedExpression call_expr{result_type, call};
+    return parser_impl_.RectifyForcedResultType(call_expr, inst, first_operand_type);
 }
 
 ast::IdentifierExpression* FunctionEmitter::Swizzle(uint32_t i) {
-  if (i >= kMaxVectorLen) {
-    Fail() << "vector component index is larger than " << kMaxVectorLen - 1
-           << ": " << i;
-    return nullptr;
-  }
-  const char* names[] = {"x", "y", "z", "w"};
-  return create<ast::IdentifierExpression>(
-      Source{}, builder_.Symbols().Register(names[i & 3]));
+    if (i >= kMaxVectorLen) {
+        Fail() << "vector component index is larger than " << kMaxVectorLen - 1 << ": " << i;
+        return nullptr;
+    }
+    const char* names[] = {"x", "y", "z", "w"};
+    return create<ast::IdentifierExpression>(Source{}, builder_.Symbols().Register(names[i & 3]));
 }
 
 ast::IdentifierExpression* FunctionEmitter::PrefixSwizzle(uint32_t n) {
-  switch (n) {
-    case 1:
-      return create<ast::IdentifierExpression>(
-          Source{}, builder_.Symbols().Register("x"));
-    case 2:
-      return create<ast::IdentifierExpression>(
-          Source{}, builder_.Symbols().Register("xy"));
-    case 3:
-      return create<ast::IdentifierExpression>(
-          Source{}, builder_.Symbols().Register("xyz"));
-    default:
-      break;
-  }
-  Fail() << "invalid swizzle prefix count: " << n;
-  return nullptr;
+    switch (n) {
+        case 1:
+            return create<ast::IdentifierExpression>(Source{}, builder_.Symbols().Register("x"));
+        case 2:
+            return create<ast::IdentifierExpression>(Source{}, builder_.Symbols().Register("xy"));
+        case 3:
+            return create<ast::IdentifierExpression>(Source{}, builder_.Symbols().Register("xyz"));
+        default:
+            break;
+    }
+    Fail() << "invalid swizzle prefix count: " << n;
+    return nullptr;
 }
 
-TypedExpression FunctionEmitter::MakeFMod(
-    const spvtools::opt::Instruction& inst) {
-  auto x = MakeOperand(inst, 0);
-  auto y = MakeOperand(inst, 1);
-  if (!x || !y) {
-    return {};
-  }
-  // Emulated with: x - y * floor(x / y)
-  auto* div = builder_.Div(x.expr, y.expr);
-  auto* floor = builder_.Call("floor", div);
-  auto* y_floor = builder_.Mul(y.expr, floor);
-  auto* res = builder_.Sub(x.expr, y_floor);
-  return {x.type, res};
+TypedExpression FunctionEmitter::MakeFMod(const spvtools::opt::Instruction& inst) {
+    auto x = MakeOperand(inst, 0);
+    auto y = MakeOperand(inst, 1);
+    if (!x || !y) {
+        return {};
+    }
+    // Emulated with: x - y * floor(x / y)
+    auto* div = builder_.Div(x.expr, y.expr);
+    auto* floor = builder_.Call("floor", div);
+    auto* y_floor = builder_.Mul(y.expr, floor);
+    auto* res = builder_.Sub(x.expr, y_floor);
+    return {x.type, res};
 }
 
-TypedExpression FunctionEmitter::MakeAccessChain(
-    const spvtools::opt::Instruction& inst) {
-  if (inst.NumInOperands() < 1) {
-    // Binary parsing will fail on this anyway.
-    Fail() << "invalid access chain: has no input operands";
-    return {};
-  }
-
-  const auto base_id = inst.GetSingleWordInOperand(0);
-  const auto base_skip = GetSkipReason(base_id);
-  if (base_skip != SkipReason::kDontSkip) {
-    // This can occur for AccessChain with no indices.
-    GetDefInfo(inst.result_id())->skip = base_skip;
-    GetDefInfo(inst.result_id())->sink_pointer_source_expr =
-        GetDefInfo(base_id)->sink_pointer_source_expr;
-    return {};
-  }
-
-  auto ptr_ty_id = def_use_mgr_->GetDef(base_id)->type_id();
-  uint32_t first_index = 1;
-  const auto num_in_operands = inst.NumInOperands();
-
-  bool sink_pointer = false;
-  TypedExpression current_expr;
-
-  // If the variable was originally gl_PerVertex, then in the AST we
-  // have instead emitted a gl_Position variable.
-  // If computing the pointer to the Position builtin, then emit the
-  // pointer to the generated gl_Position variable.
-  // If computing the pointer to the PointSize builtin, then mark the
-  // result as skippable due to being the point-size pointer.
-  // If computing the pointer to the ClipDistance or CullDistance builtins,
-  // then error out.
-  {
-    const auto& builtin_position_info = parser_impl_.GetBuiltInPositionInfo();
-    if (base_id == builtin_position_info.per_vertex_var_id) {
-      // We only support the Position member.
-      const auto* member_index_inst =
-          def_use_mgr_->GetDef(inst.GetSingleWordInOperand(first_index));
-      if (member_index_inst == nullptr) {
-        Fail()
-            << "first index of access chain does not reference an instruction: "
-            << inst.PrettyPrint();
+TypedExpression FunctionEmitter::MakeAccessChain(const spvtools::opt::Instruction& inst) {
+    if (inst.NumInOperands() < 1) {
+        // Binary parsing will fail on this anyway.
+        Fail() << "invalid access chain: has no input operands";
         return {};
-      }
-      const auto* member_index_const =
-          constant_mgr_->GetConstantFromInst(member_index_inst);
-      if (member_index_const == nullptr) {
-        Fail() << "first index of access chain into per-vertex structure is "
-                  "not a constant: "
-               << inst.PrettyPrint();
+    }
+
+    const auto base_id = inst.GetSingleWordInOperand(0);
+    const auto base_skip = GetSkipReason(base_id);
+    if (base_skip != SkipReason::kDontSkip) {
+        // This can occur for AccessChain with no indices.
+        GetDefInfo(inst.result_id())->skip = base_skip;
+        GetDefInfo(inst.result_id())->sink_pointer_source_expr =
+            GetDefInfo(base_id)->sink_pointer_source_expr;
         return {};
-      }
-      const auto* member_index_const_int = member_index_const->AsIntConstant();
-      if (member_index_const_int == nullptr) {
-        Fail() << "first index of access chain into per-vertex structure is "
-                  "not a constant integer: "
-               << inst.PrettyPrint();
+    }
+
+    auto ptr_ty_id = def_use_mgr_->GetDef(base_id)->type_id();
+    uint32_t first_index = 1;
+    const auto num_in_operands = inst.NumInOperands();
+
+    bool sink_pointer = false;
+    TypedExpression current_expr;
+
+    // If the variable was originally gl_PerVertex, then in the AST we
+    // have instead emitted a gl_Position variable.
+    // If computing the pointer to the Position builtin, then emit the
+    // pointer to the generated gl_Position variable.
+    // If computing the pointer to the PointSize builtin, then mark the
+    // result as skippable due to being the point-size pointer.
+    // If computing the pointer to the ClipDistance or CullDistance builtins,
+    // then error out.
+    {
+        const auto& builtin_position_info = parser_impl_.GetBuiltInPositionInfo();
+        if (base_id == builtin_position_info.per_vertex_var_id) {
+            // We only support the Position member.
+            const auto* member_index_inst =
+                def_use_mgr_->GetDef(inst.GetSingleWordInOperand(first_index));
+            if (member_index_inst == nullptr) {
+                Fail() << "first index of access chain does not reference an instruction: "
+                       << inst.PrettyPrint();
+                return {};
+            }
+            const auto* member_index_const = constant_mgr_->GetConstantFromInst(member_index_inst);
+            if (member_index_const == nullptr) {
+                Fail() << "first index of access chain into per-vertex structure is "
+                          "not a constant: "
+                       << inst.PrettyPrint();
+                return {};
+            }
+            const auto* member_index_const_int = member_index_const->AsIntConstant();
+            if (member_index_const_int == nullptr) {
+                Fail() << "first index of access chain into per-vertex structure is "
+                          "not a constant integer: "
+                       << inst.PrettyPrint();
+                return {};
+            }
+            const auto member_index_value = member_index_const_int->GetZeroExtendedValue();
+            if (member_index_value != builtin_position_info.position_member_index) {
+                if (member_index_value == builtin_position_info.pointsize_member_index) {
+                    if (auto* def_info = GetDefInfo(inst.result_id())) {
+                        def_info->skip = SkipReason::kPointSizeBuiltinPointer;
+                        return {};
+                    }
+                } else {
+                    // TODO(dneto): Handle ClipDistance and CullDistance
+                    Fail() << "accessing per-vertex member " << member_index_value
+                           << " is not supported. Only Position is supported, and "
+                              "PointSize is ignored";
+                    return {};
+                }
+            }
+
+            // Skip past the member index that gets us to Position.
+            first_index = first_index + 1;
+            // Replace the gl_PerVertex reference with the gl_Position reference
+            ptr_ty_id = builtin_position_info.position_member_pointer_type_id;
+
+            auto name = namer_.Name(base_id);
+            current_expr.expr =
+                create<ast::IdentifierExpression>(Source{}, builder_.Symbols().Register(name));
+            current_expr.type = parser_impl_.ConvertType(ptr_ty_id, PtrAs::Ref);
+        }
+    }
+
+    // A SPIR-V access chain is a single instruction with multiple indices
+    // walking down into composites.  The Tint AST represents this as
+    // ever-deeper nested indexing expressions. Start off with an expression
+    // for the base, and then bury that inside nested indexing expressions.
+    if (!current_expr) {
+        current_expr = InferFunctionStorageClass(MakeOperand(inst, 0));
+        if (current_expr.type->Is<Pointer>()) {
+            current_expr = Dereference(current_expr);
+        }
+    }
+    const auto constants = constant_mgr_->GetOperandConstants(&inst);
+
+    const auto* ptr_type_inst = def_use_mgr_->GetDef(ptr_ty_id);
+    if (!ptr_type_inst || (ptr_type_inst->opcode() != SpvOpTypePointer)) {
+        Fail() << "Access chain %" << inst.result_id() << " base pointer is not of pointer type";
         return {};
-      }
-      const auto member_index_value =
-          member_index_const_int->GetZeroExtendedValue();
-      if (member_index_value != builtin_position_info.position_member_index) {
-        if (member_index_value ==
-            builtin_position_info.pointsize_member_index) {
-          if (auto* def_info = GetDefInfo(inst.result_id())) {
-            def_info->skip = SkipReason::kPointSizeBuiltinPointer;
+    }
+    SpvStorageClass storage_class =
+        static_cast<SpvStorageClass>(ptr_type_inst->GetSingleWordInOperand(0));
+    uint32_t pointee_type_id = ptr_type_inst->GetSingleWordInOperand(1);
+
+    // Build up a nested expression for the access chain by walking down the type
+    // hierarchy, maintaining |pointee_type_id| as the SPIR-V ID of the type of
+    // the object pointed to after processing the previous indices.
+    for (uint32_t index = first_index; index < num_in_operands; ++index) {
+        const auto* index_const = constants[index] ? constants[index]->AsIntConstant() : nullptr;
+        const int64_t index_const_val = index_const ? index_const->GetSignExtendedValue() : 0;
+        const ast::Expression* next_expr = nullptr;
+
+        const auto* pointee_type_inst = def_use_mgr_->GetDef(pointee_type_id);
+        if (!pointee_type_inst) {
+            Fail() << "pointee type %" << pointee_type_id << " is invalid after following "
+                   << (index - first_index) << " indices: " << inst.PrettyPrint();
             return {};
-          }
-        } else {
-          // TODO(dneto): Handle ClipDistance and CullDistance
-          Fail() << "accessing per-vertex member " << member_index_value
-                 << " is not supported. Only Position is supported, and "
-                    "PointSize is ignored";
-          return {};
         }
-      }
+        switch (pointee_type_inst->opcode()) {
+            case SpvOpTypeVector:
+                if (index_const) {
+                    // Try generating a MemberAccessor expression
+                    const auto num_elems = pointee_type_inst->GetSingleWordInOperand(1);
+                    if (index_const_val < 0 || num_elems <= index_const_val) {
+                        Fail() << "Access chain %" << inst.result_id() << " index %"
+                               << inst.GetSingleWordInOperand(index) << " value " << index_const_val
+                               << " is out of bounds for vector of " << num_elems << " elements";
+                        return {};
+                    }
+                    if (uint64_t(index_const_val) >= kMaxVectorLen) {
+                        Fail() << "internal error: swizzle index " << index_const_val
+                               << " is too big. Max handled index is " << kMaxVectorLen - 1;
+                    }
+                    next_expr = create<ast::MemberAccessorExpression>(
+                        Source{}, current_expr.expr, Swizzle(uint32_t(index_const_val)));
+                } else {
+                    // Non-constant index. Use array syntax
+                    next_expr = create<ast::IndexAccessorExpression>(Source{}, current_expr.expr,
+                                                                     MakeOperand(inst, index).expr);
+                }
+                // All vector components are the same type.
+                pointee_type_id = pointee_type_inst->GetSingleWordInOperand(0);
+                // Sink pointers to vector components.
+                sink_pointer = true;
+                break;
+            case SpvOpTypeMatrix:
+                // Use array syntax.
+                next_expr = create<ast::IndexAccessorExpression>(Source{}, current_expr.expr,
+                                                                 MakeOperand(inst, index).expr);
+                // All matrix components are the same type.
+                pointee_type_id = pointee_type_inst->GetSingleWordInOperand(0);
+                break;
+            case SpvOpTypeArray:
+                next_expr = create<ast::IndexAccessorExpression>(Source{}, current_expr.expr,
+                                                                 MakeOperand(inst, index).expr);
+                pointee_type_id = pointee_type_inst->GetSingleWordInOperand(0);
+                break;
+            case SpvOpTypeRuntimeArray:
+                next_expr = create<ast::IndexAccessorExpression>(Source{}, current_expr.expr,
+                                                                 MakeOperand(inst, index).expr);
+                pointee_type_id = pointee_type_inst->GetSingleWordInOperand(0);
+                break;
+            case SpvOpTypeStruct: {
+                if (!index_const) {
+                    Fail() << "Access chain %" << inst.result_id() << " index %"
+                           << inst.GetSingleWordInOperand(index)
+                           << " is a non-constant index into a structure %" << pointee_type_id;
+                    return {};
+                }
+                const auto num_members = pointee_type_inst->NumInOperands();
+                if ((index_const_val < 0) || num_members <= uint64_t(index_const_val)) {
+                    Fail() << "Access chain %" << inst.result_id() << " index value "
+                           << index_const_val << " is out of bounds for structure %"
+                           << pointee_type_id << " having " << num_members << " members";
+                    return {};
+                }
+                auto name = namer_.GetMemberName(pointee_type_id, uint32_t(index_const_val));
+                auto* member_access =
+                    create<ast::IdentifierExpression>(Source{}, builder_.Symbols().Register(name));
 
-      // Skip past the member index that gets us to Position.
-      first_index = first_index + 1;
-      // Replace the gl_PerVertex reference with the gl_Position reference
-      ptr_ty_id = builtin_position_info.position_member_pointer_type_id;
-
-      auto name = namer_.Name(base_id);
-      current_expr.expr = create<ast::IdentifierExpression>(
-          Source{}, builder_.Symbols().Register(name));
-      current_expr.type = parser_impl_.ConvertType(ptr_ty_id, PtrAs::Ref);
-    }
-  }
-
-  // A SPIR-V access chain is a single instruction with multiple indices
-  // walking down into composites.  The Tint AST represents this as
-  // ever-deeper nested indexing expressions. Start off with an expression
-  // for the base, and then bury that inside nested indexing expressions.
-  if (!current_expr) {
-    current_expr = InferFunctionStorageClass(MakeOperand(inst, 0));
-    if (current_expr.type->Is<Pointer>()) {
-      current_expr = Dereference(current_expr);
-    }
-  }
-  const auto constants = constant_mgr_->GetOperandConstants(&inst);
-
-  const auto* ptr_type_inst = def_use_mgr_->GetDef(ptr_ty_id);
-  if (!ptr_type_inst || (ptr_type_inst->opcode() != SpvOpTypePointer)) {
-    Fail() << "Access chain %" << inst.result_id()
-           << " base pointer is not of pointer type";
-    return {};
-  }
-  SpvStorageClass storage_class =
-      static_cast<SpvStorageClass>(ptr_type_inst->GetSingleWordInOperand(0));
-  uint32_t pointee_type_id = ptr_type_inst->GetSingleWordInOperand(1);
-
-  // Build up a nested expression for the access chain by walking down the type
-  // hierarchy, maintaining |pointee_type_id| as the SPIR-V ID of the type of
-  // the object pointed to after processing the previous indices.
-  for (uint32_t index = first_index; index < num_in_operands; ++index) {
-    const auto* index_const =
-        constants[index] ? constants[index]->AsIntConstant() : nullptr;
-    const int64_t index_const_val =
-        index_const ? index_const->GetSignExtendedValue() : 0;
-    const ast::Expression* next_expr = nullptr;
-
-    const auto* pointee_type_inst = def_use_mgr_->GetDef(pointee_type_id);
-    if (!pointee_type_inst) {
-      Fail() << "pointee type %" << pointee_type_id
-             << " is invalid after following " << (index - first_index)
-             << " indices: " << inst.PrettyPrint();
-      return {};
-    }
-    switch (pointee_type_inst->opcode()) {
-      case SpvOpTypeVector:
-        if (index_const) {
-          // Try generating a MemberAccessor expression
-          const auto num_elems = pointee_type_inst->GetSingleWordInOperand(1);
-          if (index_const_val < 0 || num_elems <= index_const_val) {
-            Fail() << "Access chain %" << inst.result_id() << " index %"
-                   << inst.GetSingleWordInOperand(index) << " value "
-                   << index_const_val << " is out of bounds for vector of "
-                   << num_elems << " elements";
-            return {};
-          }
-          if (uint64_t(index_const_val) >= kMaxVectorLen) {
-            Fail() << "internal error: swizzle index " << index_const_val
-                   << " is too big. Max handled index is " << kMaxVectorLen - 1;
-          }
-          next_expr = create<ast::MemberAccessorExpression>(
-              Source{}, current_expr.expr, Swizzle(uint32_t(index_const_val)));
-        } else {
-          // Non-constant index. Use array syntax
-          next_expr = create<ast::IndexAccessorExpression>(
-              Source{}, current_expr.expr, MakeOperand(inst, index).expr);
+                next_expr = create<ast::MemberAccessorExpression>(Source{}, current_expr.expr,
+                                                                  member_access);
+                pointee_type_id = pointee_type_inst->GetSingleWordInOperand(
+                    static_cast<uint32_t>(index_const_val));
+                break;
+            }
+            default:
+                Fail() << "Access chain with unknown or invalid pointee type %" << pointee_type_id
+                       << ": " << pointee_type_inst->PrettyPrint();
+                return {};
         }
-        // All vector components are the same type.
-        pointee_type_id = pointee_type_inst->GetSingleWordInOperand(0);
-        // Sink pointers to vector components.
-        sink_pointer = true;
-        break;
-      case SpvOpTypeMatrix:
-        // Use array syntax.
-        next_expr = create<ast::IndexAccessorExpression>(
-            Source{}, current_expr.expr, MakeOperand(inst, index).expr);
-        // All matrix components are the same type.
-        pointee_type_id = pointee_type_inst->GetSingleWordInOperand(0);
-        break;
-      case SpvOpTypeArray:
-        next_expr = create<ast::IndexAccessorExpression>(
-            Source{}, current_expr.expr, MakeOperand(inst, index).expr);
-        pointee_type_id = pointee_type_inst->GetSingleWordInOperand(0);
-        break;
-      case SpvOpTypeRuntimeArray:
-        next_expr = create<ast::IndexAccessorExpression>(
-            Source{}, current_expr.expr, MakeOperand(inst, index).expr);
-        pointee_type_id = pointee_type_inst->GetSingleWordInOperand(0);
-        break;
-      case SpvOpTypeStruct: {
-        if (!index_const) {
-          Fail() << "Access chain %" << inst.result_id() << " index %"
-                 << inst.GetSingleWordInOperand(index)
-                 << " is a non-constant index into a structure %"
-                 << pointee_type_id;
-          return {};
-        }
-        const auto num_members = pointee_type_inst->NumInOperands();
-        if ((index_const_val < 0) || num_members <= uint64_t(index_const_val)) {
-          Fail() << "Access chain %" << inst.result_id() << " index value "
-                 << index_const_val << " is out of bounds for structure %"
-                 << pointee_type_id << " having " << num_members << " members";
-          return {};
-        }
-        auto name =
-            namer_.GetMemberName(pointee_type_id, uint32_t(index_const_val));
-        auto* member_access = create<ast::IdentifierExpression>(
-            Source{}, builder_.Symbols().Register(name));
-
-        next_expr = create<ast::MemberAccessorExpression>(
-            Source{}, current_expr.expr, member_access);
-        pointee_type_id = pointee_type_inst->GetSingleWordInOperand(
-            static_cast<uint32_t>(index_const_val));
-        break;
-      }
-      default:
-        Fail() << "Access chain with unknown or invalid pointee type %"
-               << pointee_type_id << ": " << pointee_type_inst->PrettyPrint();
-        return {};
+        const auto pointer_type_id = type_mgr_->FindPointerToType(pointee_type_id, storage_class);
+        auto* type = parser_impl_.ConvertType(pointer_type_id, PtrAs::Ref);
+        TINT_ASSERT(Reader, type && type->Is<Reference>());
+        current_expr = TypedExpression{type, next_expr};
     }
-    const auto pointer_type_id =
-        type_mgr_->FindPointerToType(pointee_type_id, storage_class);
-    auto* type = parser_impl_.ConvertType(pointer_type_id, PtrAs::Ref);
-    TINT_ASSERT(Reader, type && type->Is<Reference>());
-    current_expr = TypedExpression{type, next_expr};
-  }
 
-  if (sink_pointer) {
-    // Capture the reference so that we can sink it into the point of use.
-    GetDefInfo(inst.result_id())->skip = SkipReason::kSinkPointerIntoUse;
-    GetDefInfo(inst.result_id())->sink_pointer_source_expr = current_expr;
-  }
+    if (sink_pointer) {
+        // Capture the reference so that we can sink it into the point of use.
+        GetDefInfo(inst.result_id())->skip = SkipReason::kSinkPointerIntoUse;
+        GetDefInfo(inst.result_id())->sink_pointer_source_expr = current_expr;
+    }
 
-  return current_expr;
+    return current_expr;
 }
 
-TypedExpression FunctionEmitter::MakeCompositeExtract(
-    const spvtools::opt::Instruction& inst) {
-  // This is structurally similar to creating an access chain, but
-  // the SPIR-V instruction has literal indices instead of IDs for indices.
+TypedExpression FunctionEmitter::MakeCompositeExtract(const spvtools::opt::Instruction& inst) {
+    // This is structurally similar to creating an access chain, but
+    // the SPIR-V instruction has literal indices instead of IDs for indices.
 
-  auto composite_index = 0;
-  auto first_index_position = 1;
-  TypedExpression current_expr(MakeOperand(inst, composite_index));
-  if (!current_expr) {
-    return {};
-  }
+    auto composite_index = 0;
+    auto first_index_position = 1;
+    TypedExpression current_expr(MakeOperand(inst, composite_index));
+    if (!current_expr) {
+        return {};
+    }
 
-  const auto composite_id = inst.GetSingleWordInOperand(composite_index);
-  auto current_type_id = def_use_mgr_->GetDef(composite_id)->type_id();
+    const auto composite_id = inst.GetSingleWordInOperand(composite_index);
+    auto current_type_id = def_use_mgr_->GetDef(composite_id)->type_id();
 
-  return MakeCompositeValueDecomposition(inst, current_expr, current_type_id,
-                                         first_index_position);
+    return MakeCompositeValueDecomposition(inst, current_expr, current_type_id,
+                                           first_index_position);
 }
 
 TypedExpression FunctionEmitter::MakeCompositeValueDecomposition(
@@ -4461,1681 +4286,1595 @@
     TypedExpression composite,
     uint32_t composite_type_id,
     int index_start) {
-  // This is structurally similar to creating an access chain, but
-  // the SPIR-V instruction has literal indices instead of IDs for indices.
+    // This is structurally similar to creating an access chain, but
+    // the SPIR-V instruction has literal indices instead of IDs for indices.
 
-  // A SPIR-V composite extract is a single instruction with multiple
-  // literal indices walking down into composites.
-  // A SPIR-V composite insert is similar but also tells you what component
-  // to inject. This function is responsible for the the walking-into part
-  // of composite-insert.
-  //
-  // The Tint AST represents this as ever-deeper nested indexing expressions.
-  // Start off with an expression for the composite, and then bury that inside
-  // nested indexing expressions.
+    // A SPIR-V composite extract is a single instruction with multiple
+    // literal indices walking down into composites.
+    // A SPIR-V composite insert is similar but also tells you what component
+    // to inject. This function is responsible for the the walking-into part
+    // of composite-insert.
+    //
+    // The Tint AST represents this as ever-deeper nested indexing expressions.
+    // Start off with an expression for the composite, and then bury that inside
+    // nested indexing expressions.
 
-  auto current_expr = composite;
-  auto current_type_id = composite_type_id;
+    auto current_expr = composite;
+    auto current_type_id = composite_type_id;
 
-  auto make_index = [this](uint32_t literal) {
-    return create<ast::UintLiteralExpression>(Source{}, literal);
-  };
+    auto make_index = [this](uint32_t literal) {
+        return create<ast::IntLiteralExpression>(Source{}, literal,
+                                                 ast::IntLiteralExpression::Suffix::kU);
+    };
 
-  // Build up a nested expression for the decomposition by walking down the type
-  // hierarchy, maintaining |current_type_id| as the SPIR-V ID of the type of
-  // the object pointed to after processing the previous indices.
-  const auto num_in_operands = inst.NumInOperands();
-  for (uint32_t index = index_start; index < num_in_operands; ++index) {
-    const uint32_t index_val = inst.GetSingleWordInOperand(index);
+    // Build up a nested expression for the decomposition by walking down the type
+    // hierarchy, maintaining |current_type_id| as the SPIR-V ID of the type of
+    // the object pointed to after processing the previous indices.
+    const auto num_in_operands = inst.NumInOperands();
+    for (uint32_t index = index_start; index < num_in_operands; ++index) {
+        const uint32_t index_val = inst.GetSingleWordInOperand(index);
 
-    const auto* current_type_inst = def_use_mgr_->GetDef(current_type_id);
-    if (!current_type_inst) {
-      Fail() << "composite type %" << current_type_id
-             << " is invalid after following " << (index - index_start)
-             << " indices: " << inst.PrettyPrint();
-      return {};
+        const auto* current_type_inst = def_use_mgr_->GetDef(current_type_id);
+        if (!current_type_inst) {
+            Fail() << "composite type %" << current_type_id << " is invalid after following "
+                   << (index - index_start) << " indices: " << inst.PrettyPrint();
+            return {};
+        }
+        const char* operation_name = nullptr;
+        switch (inst.opcode()) {
+            case SpvOpCompositeExtract:
+                operation_name = "OpCompositeExtract";
+                break;
+            case SpvOpCompositeInsert:
+                operation_name = "OpCompositeInsert";
+                break;
+            default:
+                Fail() << "internal error: unhandled " << inst.PrettyPrint();
+                return {};
+        }
+        const ast::Expression* next_expr = nullptr;
+        switch (current_type_inst->opcode()) {
+            case SpvOpTypeVector: {
+                // Try generating a MemberAccessor expression. That result in something
+                // like  "foo.z", which is more idiomatic than "foo[2]".
+                const auto num_elems = current_type_inst->GetSingleWordInOperand(1);
+                if (num_elems <= index_val) {
+                    Fail() << operation_name << " %" << inst.result_id() << " index value "
+                           << index_val << " is out of bounds for vector of " << num_elems
+                           << " elements";
+                    return {};
+                }
+                if (index_val >= kMaxVectorLen) {
+                    Fail() << "internal error: swizzle index " << index_val
+                           << " is too big. Max handled index is " << kMaxVectorLen - 1;
+                    return {};
+                }
+                next_expr = create<ast::MemberAccessorExpression>(Source{}, current_expr.expr,
+                                                                  Swizzle(index_val));
+                // All vector components are the same type.
+                current_type_id = current_type_inst->GetSingleWordInOperand(0);
+                break;
+            }
+            case SpvOpTypeMatrix: {
+                // Check bounds
+                const auto num_elems = current_type_inst->GetSingleWordInOperand(1);
+                if (num_elems <= index_val) {
+                    Fail() << operation_name << " %" << inst.result_id() << " index value "
+                           << index_val << " is out of bounds for matrix of " << num_elems
+                           << " elements";
+                    return {};
+                }
+                if (index_val >= kMaxVectorLen) {
+                    Fail() << "internal error: swizzle index " << index_val
+                           << " is too big. Max handled index is " << kMaxVectorLen - 1;
+                }
+                // Use array syntax.
+                next_expr = create<ast::IndexAccessorExpression>(Source{}, current_expr.expr,
+                                                                 make_index(index_val));
+                // All matrix components are the same type.
+                current_type_id = current_type_inst->GetSingleWordInOperand(0);
+                break;
+            }
+            case SpvOpTypeArray:
+                // The array size could be a spec constant, and so it's not always
+                // statically checkable.  Instead, rely on a runtime index clamp
+                // or runtime check to keep this safe.
+                next_expr = create<ast::IndexAccessorExpression>(Source{}, current_expr.expr,
+                                                                 make_index(index_val));
+                current_type_id = current_type_inst->GetSingleWordInOperand(0);
+                break;
+            case SpvOpTypeRuntimeArray:
+                Fail() << "can't do " << operation_name
+                       << " on a runtime array: " << inst.PrettyPrint();
+                return {};
+            case SpvOpTypeStruct: {
+                const auto num_members = current_type_inst->NumInOperands();
+                if (num_members <= index_val) {
+                    Fail() << operation_name << " %" << inst.result_id() << " index value "
+                           << index_val << " is out of bounds for structure %" << current_type_id
+                           << " having " << num_members << " members";
+                    return {};
+                }
+                auto name = namer_.GetMemberName(current_type_id, uint32_t(index_val));
+                auto* member_access =
+                    create<ast::IdentifierExpression>(Source{}, builder_.Symbols().Register(name));
+
+                next_expr = create<ast::MemberAccessorExpression>(Source{}, current_expr.expr,
+                                                                  member_access);
+                current_type_id = current_type_inst->GetSingleWordInOperand(index_val);
+                break;
+            }
+            default:
+                Fail() << operation_name << " with bad type %" << current_type_id << ": "
+                       << current_type_inst->PrettyPrint();
+                return {};
+        }
+        current_expr = TypedExpression{parser_impl_.ConvertType(current_type_id), next_expr};
     }
-    const char* operation_name = nullptr;
-    switch (inst.opcode()) {
-      case SpvOpCompositeExtract:
-        operation_name = "OpCompositeExtract";
-        break;
-      case SpvOpCompositeInsert:
-        operation_name = "OpCompositeInsert";
-        break;
-      default:
-        Fail() << "internal error: unhandled " << inst.PrettyPrint();
-        return {};
-    }
-    const ast::Expression* next_expr = nullptr;
-    switch (current_type_inst->opcode()) {
-      case SpvOpTypeVector: {
-        // Try generating a MemberAccessor expression. That result in something
-        // like  "foo.z", which is more idiomatic than "foo[2]".
-        const auto num_elems = current_type_inst->GetSingleWordInOperand(1);
-        if (num_elems <= index_val) {
-          Fail() << operation_name << " %" << inst.result_id()
-                 << " index value " << index_val
-                 << " is out of bounds for vector of " << num_elems
-                 << " elements";
-          return {};
-        }
-        if (index_val >= kMaxVectorLen) {
-          Fail() << "internal error: swizzle index " << index_val
-                 << " is too big. Max handled index is " << kMaxVectorLen - 1;
-          return {};
-        }
-        next_expr = create<ast::MemberAccessorExpression>(
-            Source{}, current_expr.expr, Swizzle(index_val));
-        // All vector components are the same type.
-        current_type_id = current_type_inst->GetSingleWordInOperand(0);
-        break;
-      }
-      case SpvOpTypeMatrix: {
-        // Check bounds
-        const auto num_elems = current_type_inst->GetSingleWordInOperand(1);
-        if (num_elems <= index_val) {
-          Fail() << operation_name << " %" << inst.result_id()
-                 << " index value " << index_val
-                 << " is out of bounds for matrix of " << num_elems
-                 << " elements";
-          return {};
-        }
-        if (index_val >= kMaxVectorLen) {
-          Fail() << "internal error: swizzle index " << index_val
-                 << " is too big. Max handled index is " << kMaxVectorLen - 1;
-        }
-        // Use array syntax.
-        next_expr = create<ast::IndexAccessorExpression>(
-            Source{}, current_expr.expr, make_index(index_val));
-        // All matrix components are the same type.
-        current_type_id = current_type_inst->GetSingleWordInOperand(0);
-        break;
-      }
-      case SpvOpTypeArray:
-        // The array size could be a spec constant, and so it's not always
-        // statically checkable.  Instead, rely on a runtime index clamp
-        // or runtime check to keep this safe.
-        next_expr = create<ast::IndexAccessorExpression>(
-            Source{}, current_expr.expr, make_index(index_val));
-        current_type_id = current_type_inst->GetSingleWordInOperand(0);
-        break;
-      case SpvOpTypeRuntimeArray:
-        Fail() << "can't do " << operation_name
-               << " on a runtime array: " << inst.PrettyPrint();
-        return {};
-      case SpvOpTypeStruct: {
-        const auto num_members = current_type_inst->NumInOperands();
-        if (num_members <= index_val) {
-          Fail() << operation_name << " %" << inst.result_id()
-                 << " index value " << index_val
-                 << " is out of bounds for structure %" << current_type_id
-                 << " having " << num_members << " members";
-          return {};
-        }
-        auto name = namer_.GetMemberName(current_type_id, uint32_t(index_val));
-        auto* member_access = create<ast::IdentifierExpression>(
-            Source{}, builder_.Symbols().Register(name));
-
-        next_expr = create<ast::MemberAccessorExpression>(
-            Source{}, current_expr.expr, member_access);
-        current_type_id = current_type_inst->GetSingleWordInOperand(index_val);
-        break;
-      }
-      default:
-        Fail() << operation_name << " with bad type %" << current_type_id
-               << ": " << current_type_inst->PrettyPrint();
-        return {};
-    }
-    current_expr =
-        TypedExpression{parser_impl_.ConvertType(current_type_id), next_expr};
-  }
-  return current_expr;
+    return current_expr;
 }
 
 const ast::Expression* FunctionEmitter::MakeTrue(const Source& source) const {
-  return create<ast::BoolLiteralExpression>(source, true);
+    return create<ast::BoolLiteralExpression>(source, true);
 }
 
 const ast::Expression* FunctionEmitter::MakeFalse(const Source& source) const {
-  return create<ast::BoolLiteralExpression>(source, false);
+    return create<ast::BoolLiteralExpression>(source, false);
 }
 
-TypedExpression FunctionEmitter::MakeVectorShuffle(
-    const spvtools::opt::Instruction& inst) {
-  const auto vec0_id = inst.GetSingleWordInOperand(0);
-  const auto vec1_id = inst.GetSingleWordInOperand(1);
-  const spvtools::opt::Instruction& vec0 = *(def_use_mgr_->GetDef(vec0_id));
-  const spvtools::opt::Instruction& vec1 = *(def_use_mgr_->GetDef(vec1_id));
-  const auto vec0_len =
-      type_mgr_->GetType(vec0.type_id())->AsVector()->element_count();
-  const auto vec1_len =
-      type_mgr_->GetType(vec1.type_id())->AsVector()->element_count();
+TypedExpression FunctionEmitter::MakeVectorShuffle(const spvtools::opt::Instruction& inst) {
+    const auto vec0_id = inst.GetSingleWordInOperand(0);
+    const auto vec1_id = inst.GetSingleWordInOperand(1);
+    const spvtools::opt::Instruction& vec0 = *(def_use_mgr_->GetDef(vec0_id));
+    const spvtools::opt::Instruction& vec1 = *(def_use_mgr_->GetDef(vec1_id));
+    const auto vec0_len = type_mgr_->GetType(vec0.type_id())->AsVector()->element_count();
+    const auto vec1_len = type_mgr_->GetType(vec1.type_id())->AsVector()->element_count();
 
-  // Idiomatic vector accessors.
+    // Idiomatic vector accessors.
 
-  // Generate an ast::TypeConstructor expression.
-  // Assume the literal indices are valid, and there is a valid number of them.
-  auto source = GetSourceForInst(inst);
-  const Vector* result_type =
-      As<Vector>(parser_impl_.ConvertType(inst.type_id()));
-  ast::ExpressionList values;
-  for (uint32_t i = 2; i < inst.NumInOperands(); ++i) {
-    const auto index = inst.GetSingleWordInOperand(i);
-    if (index < vec0_len) {
-      auto expr = MakeExpression(vec0_id);
-      if (!expr) {
-        return {};
-      }
-      values.emplace_back(create<ast::MemberAccessorExpression>(
-          source, expr.expr, Swizzle(index)));
-    } else if (index < vec0_len + vec1_len) {
-      const auto sub_index = index - vec0_len;
-      TINT_ASSERT(Reader, sub_index < kMaxVectorLen);
-      auto expr = MakeExpression(vec1_id);
-      if (!expr) {
-        return {};
-      }
-      values.emplace_back(create<ast::MemberAccessorExpression>(
-          source, expr.expr, Swizzle(sub_index)));
-    } else if (index == 0xFFFFFFFF) {
-      // By rule, this maps to OpUndef.  Instead, make it zero.
-      values.emplace_back(parser_impl_.MakeNullValue(result_type->type));
-    } else {
-      Fail() << "invalid vectorshuffle ID %" << inst.result_id()
-             << ": index too large: " << index;
-      return {};
+    // Generate an ast::TypeConstructor expression.
+    // Assume the literal indices are valid, and there is a valid number of them.
+    auto source = GetSourceForInst(inst);
+    const Vector* result_type = As<Vector>(parser_impl_.ConvertType(inst.type_id()));
+    ast::ExpressionList values;
+    for (uint32_t i = 2; i < inst.NumInOperands(); ++i) {
+        const auto index = inst.GetSingleWordInOperand(i);
+        if (index < vec0_len) {
+            auto expr = MakeExpression(vec0_id);
+            if (!expr) {
+                return {};
+            }
+            values.emplace_back(
+                create<ast::MemberAccessorExpression>(source, expr.expr, Swizzle(index)));
+        } else if (index < vec0_len + vec1_len) {
+            const auto sub_index = index - vec0_len;
+            TINT_ASSERT(Reader, sub_index < kMaxVectorLen);
+            auto expr = MakeExpression(vec1_id);
+            if (!expr) {
+                return {};
+            }
+            values.emplace_back(
+                create<ast::MemberAccessorExpression>(source, expr.expr, Swizzle(sub_index)));
+        } else if (index == 0xFFFFFFFF) {
+            // By rule, this maps to OpUndef.  Instead, make it zero.
+            values.emplace_back(parser_impl_.MakeNullValue(result_type->type));
+        } else {
+            Fail() << "invalid vectorshuffle ID %" << inst.result_id()
+                   << ": index too large: " << index;
+            return {};
+        }
     }
-  }
-  return {result_type,
-          builder_.Construct(source, result_type->Build(builder_), values)};
+    return {result_type, builder_.Construct(source, result_type->Build(builder_), values)};
 }
 
 bool FunctionEmitter::RegisterSpecialBuiltInVariables() {
-  size_t index = def_info_.size();
-  for (auto& special_var : parser_impl_.special_builtins()) {
-    const auto id = special_var.first;
-    const auto builtin = special_var.second;
-    const auto* var = def_use_mgr_->GetDef(id);
-    def_info_[id] = std::make_unique<DefInfo>(*var, 0, index);
-    ++index;
-    auto& def = def_info_[id];
-    switch (builtin) {
-      case SpvBuiltInPointSize:
-        def->skip = SkipReason::kPointSizeBuiltinPointer;
-        break;
-      case SpvBuiltInSampleMask: {
-        // Distinguish between input and output variable.
-        const auto storage_class =
-            static_cast<SpvStorageClass>(var->GetSingleWordInOperand(0));
-        if (storage_class == SpvStorageClassInput) {
-          sample_mask_in_id = id;
-          def->skip = SkipReason::kSampleMaskInBuiltinPointer;
-        } else {
-          sample_mask_out_id = id;
-          def->skip = SkipReason::kSampleMaskOutBuiltinPointer;
+    size_t index = def_info_.size();
+    for (auto& special_var : parser_impl_.special_builtins()) {
+        const auto id = special_var.first;
+        const auto builtin = special_var.second;
+        const auto* var = def_use_mgr_->GetDef(id);
+        def_info_[id] = std::make_unique<DefInfo>(*var, 0, index);
+        ++index;
+        auto& def = def_info_[id];
+        switch (builtin) {
+            case SpvBuiltInPointSize:
+                def->skip = SkipReason::kPointSizeBuiltinPointer;
+                break;
+            case SpvBuiltInSampleMask: {
+                // Distinguish between input and output variable.
+                const auto storage_class =
+                    static_cast<SpvStorageClass>(var->GetSingleWordInOperand(0));
+                if (storage_class == SpvStorageClassInput) {
+                    sample_mask_in_id = id;
+                    def->skip = SkipReason::kSampleMaskInBuiltinPointer;
+                } else {
+                    sample_mask_out_id = id;
+                    def->skip = SkipReason::kSampleMaskOutBuiltinPointer;
+                }
+                break;
+            }
+            case SpvBuiltInSampleId:
+            case SpvBuiltInInstanceIndex:
+            case SpvBuiltInVertexIndex:
+            case SpvBuiltInLocalInvocationIndex:
+            case SpvBuiltInLocalInvocationId:
+            case SpvBuiltInGlobalInvocationId:
+            case SpvBuiltInWorkgroupId:
+            case SpvBuiltInNumWorkgroups:
+                break;
+            default:
+                return Fail() << "unrecognized special builtin: " << int(builtin);
         }
-        break;
-      }
-      case SpvBuiltInSampleId:
-      case SpvBuiltInInstanceIndex:
-      case SpvBuiltInVertexIndex:
-      case SpvBuiltInLocalInvocationIndex:
-      case SpvBuiltInLocalInvocationId:
-      case SpvBuiltInGlobalInvocationId:
-      case SpvBuiltInWorkgroupId:
-      case SpvBuiltInNumWorkgroups:
-        break;
-      default:
-        return Fail() << "unrecognized special builtin: " << int(builtin);
     }
-  }
-  return true;
+    return true;
 }
 
 bool FunctionEmitter::RegisterLocallyDefinedValues() {
-  // Create a DefInfo for each value definition in this function.
-  size_t index = def_info_.size();
-  for (auto block_id : block_order_) {
-    const auto* block_info = GetBlockInfo(block_id);
-    const auto block_pos = block_info->pos;
-    for (const auto& inst : *(block_info->basic_block)) {
-      const auto result_id = inst.result_id();
-      if ((result_id == 0) || inst.opcode() == SpvOpLabel) {
-        continue;
-      }
-      def_info_[result_id] = std::make_unique<DefInfo>(inst, block_pos, index);
-      ++index;
-      auto& info = def_info_[result_id];
-
-      // Determine storage class for pointer values. Do this in order because
-      // we might rely on the storage class for a previously-visited definition.
-      // Logical pointers can't be transmitted through OpPhi, so remaining
-      // pointer definitions are SSA values, and their definitions must be
-      // visited before their uses.
-      const auto* type = type_mgr_->GetType(inst.type_id());
-      if (type) {
-        if (type->AsPointer()) {
-          if (auto* ast_type = parser_impl_.ConvertType(inst.type_id())) {
-            if (auto* ptr = ast_type->As<Pointer>()) {
-              info->storage_class = ptr->storage_class;
+    // Create a DefInfo for each value definition in this function.
+    size_t index = def_info_.size();
+    for (auto block_id : block_order_) {
+        const auto* block_info = GetBlockInfo(block_id);
+        const auto block_pos = block_info->pos;
+        for (const auto& inst : *(block_info->basic_block)) {
+            const auto result_id = inst.result_id();
+            if ((result_id == 0) || inst.opcode() == SpvOpLabel) {
+                continue;
             }
-          }
-          switch (inst.opcode()) {
-            case SpvOpUndef:
-              return Fail()
-                     << "undef pointer is not valid: " << inst.PrettyPrint();
-            case SpvOpVariable:
-              // Keep the default decision based on the result type.
-              break;
-            case SpvOpAccessChain:
-            case SpvOpInBoundsAccessChain:
-            case SpvOpCopyObject:
-              // Inherit from the first operand. We need this so we can pick up
-              // a remapped storage buffer.
-              info->storage_class = GetStorageClassForPointerValue(
-                  inst.GetSingleWordInOperand(0));
-              break;
-            default:
-              return Fail()
-                     << "pointer defined in function from unknown opcode: "
-                     << inst.PrettyPrint();
-          }
+            def_info_[result_id] = std::make_unique<DefInfo>(inst, block_pos, index);
+            ++index;
+            auto& info = def_info_[result_id];
+
+            // Determine storage class for pointer values. Do this in order because
+            // we might rely on the storage class for a previously-visited definition.
+            // Logical pointers can't be transmitted through OpPhi, so remaining
+            // pointer definitions are SSA values, and their definitions must be
+            // visited before their uses.
+            const auto* type = type_mgr_->GetType(inst.type_id());
+            if (type) {
+                if (type->AsPointer()) {
+                    if (auto* ast_type = parser_impl_.ConvertType(inst.type_id())) {
+                        if (auto* ptr = ast_type->As<Pointer>()) {
+                            info->storage_class = ptr->storage_class;
+                        }
+                    }
+                    switch (inst.opcode()) {
+                        case SpvOpUndef:
+                            return Fail() << "undef pointer is not valid: " << inst.PrettyPrint();
+                        case SpvOpVariable:
+                            // Keep the default decision based on the result type.
+                            break;
+                        case SpvOpAccessChain:
+                        case SpvOpInBoundsAccessChain:
+                        case SpvOpCopyObject:
+                            // Inherit from the first operand. We need this so we can pick up
+                            // a remapped storage buffer.
+                            info->storage_class =
+                                GetStorageClassForPointerValue(inst.GetSingleWordInOperand(0));
+                            break;
+                        default:
+                            return Fail() << "pointer defined in function from unknown opcode: "
+                                          << inst.PrettyPrint();
+                    }
+                }
+                auto* unwrapped = type;
+                while (auto* ptr = unwrapped->AsPointer()) {
+                    unwrapped = ptr->pointee_type();
+                }
+                if (unwrapped->AsSampler() || unwrapped->AsImage() || unwrapped->AsSampledImage()) {
+                    // Defer code generation until the instruction that actually acts on
+                    // the image.
+                    info->skip = SkipReason::kOpaqueObject;
+                }
+            }
         }
-        auto* unwrapped = type;
-        while (auto* ptr = unwrapped->AsPointer()) {
-          unwrapped = ptr->pointee_type();
-        }
-        if (unwrapped->AsSampler() || unwrapped->AsImage() ||
-            unwrapped->AsSampledImage()) {
-          // Defer code generation until the instruction that actually acts on
-          // the image.
-          info->skip = SkipReason::kOpaqueObject;
-        }
-      }
     }
-  }
-  return true;
+    return true;
 }
 
 ast::StorageClass FunctionEmitter::GetStorageClassForPointerValue(uint32_t id) {
-  auto where = def_info_.find(id);
-  if (where != def_info_.end()) {
-    auto candidate = where->second.get()->storage_class;
-    if (candidate != ast::StorageClass::kInvalid) {
-      return candidate;
+    auto where = def_info_.find(id);
+    if (where != def_info_.end()) {
+        auto candidate = where->second.get()->storage_class;
+        if (candidate != ast::StorageClass::kInvalid) {
+            return candidate;
+        }
     }
-  }
-  const auto type_id = def_use_mgr_->GetDef(id)->type_id();
-  if (type_id) {
-    auto* ast_type = parser_impl_.ConvertType(type_id);
-    if (auto* ptr = As<Pointer>(ast_type)) {
-      return ptr->storage_class;
+    const auto type_id = def_use_mgr_->GetDef(id)->type_id();
+    if (type_id) {
+        auto* ast_type = parser_impl_.ConvertType(type_id);
+        if (auto* ptr = As<Pointer>(ast_type)) {
+            return ptr->storage_class;
+        }
     }
-  }
-  return ast::StorageClass::kInvalid;
+    return ast::StorageClass::kInvalid;
 }
 
-const Type* FunctionEmitter::RemapStorageClass(const Type* type,
-                                               uint32_t result_id) {
-  if (auto* ast_ptr_type = As<Pointer>(type)) {
-    // Remap an old-style storage buffer pointer to a new-style storage
-    // buffer pointer.
-    const auto sc = GetStorageClassForPointerValue(result_id);
-    if (ast_ptr_type->storage_class != sc) {
-      return ty_.Pointer(ast_ptr_type->type, sc);
+const Type* FunctionEmitter::RemapStorageClass(const Type* type, uint32_t result_id) {
+    if (auto* ast_ptr_type = As<Pointer>(type)) {
+        // Remap an old-style storage buffer pointer to a new-style storage
+        // buffer pointer.
+        const auto sc = GetStorageClassForPointerValue(result_id);
+        if (ast_ptr_type->storage_class != sc) {
+            return ty_.Pointer(ast_ptr_type->type, sc);
+        }
     }
-  }
-  return type;
+    return type;
 }
 
 void FunctionEmitter::FindValuesNeedingNamedOrHoistedDefinition() {
-  // Mark vector operands of OpVectorShuffle as needing a named definition,
-  // but only if they are defined in this function as well.
-  auto require_named_const_def = [&](const spvtools::opt::Instruction& inst,
-                                     int in_operand_index) {
-    const auto id = inst.GetSingleWordInOperand(in_operand_index);
-    auto* const operand_def = GetDefInfo(id);
-    if (operand_def) {
-      operand_def->requires_named_const_def = true;
+    // Mark vector operands of OpVectorShuffle as needing a named definition,
+    // but only if they are defined in this function as well.
+    auto require_named_const_def = [&](const spvtools::opt::Instruction& inst,
+                                       int in_operand_index) {
+        const auto id = inst.GetSingleWordInOperand(in_operand_index);
+        auto* const operand_def = GetDefInfo(id);
+        if (operand_def) {
+            operand_def->requires_named_const_def = true;
+        }
+    };
+    for (auto& id_def_info_pair : def_info_) {
+        const auto& inst = id_def_info_pair.second->inst;
+        const auto opcode = inst.opcode();
+        if ((opcode == SpvOpVectorShuffle) || (opcode == SpvOpOuterProduct)) {
+            // We might access the vector operands multiple times. Make sure they
+            // are evaluated only once.
+            require_named_const_def(inst, 0);
+            require_named_const_def(inst, 1);
+        }
+        if (parser_impl_.IsGlslExtendedInstruction(inst)) {
+            // Some emulations of GLSLstd450 instructions evaluate certain operands
+            // multiple times. Ensure their expressions are evaluated only once.
+            switch (inst.GetSingleWordInOperand(1)) {
+                case GLSLstd450FaceForward:
+                    // The "normal" operand expression is used twice in code generation.
+                    require_named_const_def(inst, 2);
+                    break;
+                case GLSLstd450Reflect:
+                    require_named_const_def(inst, 2);  // Incident
+                    require_named_const_def(inst, 3);  // Normal
+                    break;
+                default:
+                    break;
+            }
+        }
     }
-  };
-  for (auto& id_def_info_pair : def_info_) {
-    const auto& inst = id_def_info_pair.second->inst;
+
+    // Scan uses of locally defined IDs, in function block order.
+    for (auto block_id : block_order_) {
+        const auto* block_info = GetBlockInfo(block_id);
+        const auto block_pos = block_info->pos;
+        for (const auto& inst : *(block_info->basic_block)) {
+            // Update bookkeeping for locally-defined IDs used by this instruction.
+            inst.ForEachInId([this, block_pos, block_info](const uint32_t* id_ptr) {
+                auto* def_info = GetDefInfo(*id_ptr);
+                if (def_info) {
+                    // Update usage count.
+                    def_info->num_uses++;
+                    // Update usage span.
+                    def_info->last_use_pos = std::max(def_info->last_use_pos, block_pos);
+
+                    // Determine whether this ID is defined in a different construct
+                    // from this use.
+                    const auto defining_block = block_order_[def_info->block_pos];
+                    const auto* def_in_construct = GetBlockInfo(defining_block)->construct;
+                    if (def_in_construct != block_info->construct) {
+                        def_info->used_in_another_construct = true;
+                    }
+                }
+            });
+
+            if (inst.opcode() == SpvOpPhi) {
+                // Declare a name for the variable used to carry values to a phi.
+                const auto phi_id = inst.result_id();
+                auto* phi_def_info = GetDefInfo(phi_id);
+                phi_def_info->phi_var = namer_.MakeDerivedName(namer_.Name(phi_id) + "_phi");
+                // Track all the places where we need to mention the variable,
+                // so we can place its declaration.  First, record the location of
+                // the read from the variable.
+                uint32_t first_pos = block_pos;
+                uint32_t last_pos = block_pos;
+                // Record the assignments that will propagate values from predecessor
+                // blocks.
+                for (uint32_t i = 0; i + 1 < inst.NumInOperands(); i += 2) {
+                    const uint32_t value_id = inst.GetSingleWordInOperand(i);
+                    const uint32_t pred_block_id = inst.GetSingleWordInOperand(i + 1);
+                    auto* pred_block_info = GetBlockInfo(pred_block_id);
+                    // The predecessor might not be in the block order at all, so we
+                    // need this guard.
+                    if (IsInBlockOrder(pred_block_info)) {
+                        // Record the assignment that needs to occur at the end
+                        // of the predecessor block.
+                        pred_block_info->phi_assignments.push_back({phi_id, value_id});
+                        first_pos = std::min(first_pos, pred_block_info->pos);
+                        last_pos = std::max(last_pos, pred_block_info->pos);
+                    }
+                }
+
+                // Schedule the declaration of the state variable.
+                const auto* enclosing_construct = GetEnclosingScope(first_pos, last_pos);
+                GetBlockInfo(enclosing_construct->begin_id)
+                    ->phis_needing_state_vars.push_back(phi_id);
+            }
+        }
+    }
+
+    // For an ID defined in this function, determine if its evaluation and
+    // potential declaration needs special handling:
+    // - Compensate for the fact that dominance does not map directly to scope.
+    //   A definition could dominate its use, but a named definition in WGSL
+    //   at the location of the definition could go out of scope by the time
+    //   you reach the use.  In that case, we hoist the definition to a basic
+    //   block at the smallest scope enclosing both the definition and all
+    //   its uses.
+    // - If value is used in a different construct than its definition, then it
+    //   needs a named constant definition.  Otherwise we might sink an
+    //   expensive computation into control flow, and hence change performance.
+    for (auto& id_def_info_pair : def_info_) {
+        const auto def_id = id_def_info_pair.first;
+        auto* def_info = id_def_info_pair.second.get();
+        if (def_info->num_uses == 0) {
+            // There is no need to adjust the location of the declaration.
+            continue;
+        }
+        // The first use must be the at the SSA definition, because block order
+        // respects dominance.
+        const auto first_pos = def_info->block_pos;
+        const auto last_use_pos = def_info->last_use_pos;
+
+        const auto* def_in_construct = GetBlockInfo(block_order_[first_pos])->construct;
+        // A definition in the first block of an kIfSelection or kSwitchSelection
+        // occurs before the branch, and so that definition should count as
+        // having been defined at the scope of the parent construct.
+        if (first_pos == def_in_construct->begin_pos) {
+            if ((def_in_construct->kind == Construct::kIfSelection) ||
+                (def_in_construct->kind == Construct::kSwitchSelection)) {
+                def_in_construct = def_in_construct->parent;
+            }
+        }
+
+        bool should_hoist = false;
+        if (!def_in_construct->ContainsPos(last_use_pos)) {
+            // To satisfy scoping, we have to hoist the definition out to an enclosing
+            // construct.
+            should_hoist = true;
+        } else {
+            // Avoid moving combinatorial values across constructs.  This is a
+            // simple heuristic to avoid changing the cost of an operation
+            // by moving it into or out of a loop, for example.
+            if ((def_info->storage_class == ast::StorageClass::kInvalid) &&
+                def_info->used_in_another_construct) {
+                should_hoist = true;
+            }
+        }
+
+        if (should_hoist) {
+            const auto* enclosing_construct = GetEnclosingScope(first_pos, last_use_pos);
+            if (enclosing_construct == def_in_construct) {
+                // We can use a plain 'const' definition.
+                def_info->requires_named_const_def = true;
+            } else {
+                // We need to make a hoisted variable definition.
+                // TODO(dneto): Handle non-storable types, particularly pointers.
+                def_info->requires_hoisted_def = true;
+                auto* hoist_to_block = GetBlockInfo(enclosing_construct->begin_id);
+                hoist_to_block->hoisted_ids.push_back(def_id);
+            }
+        }
+    }
+}
+
+const Construct* FunctionEmitter::GetEnclosingScope(uint32_t first_pos, uint32_t last_pos) const {
+    const auto* enclosing_construct = GetBlockInfo(block_order_[first_pos])->construct;
+    TINT_ASSERT(Reader, enclosing_construct != nullptr);
+    // Constructs are strictly nesting, so follow parent pointers
+    while (enclosing_construct && !enclosing_construct->ScopeContainsPos(last_pos)) {
+        // The scope of a continue construct is enclosed in its associated loop
+        // construct, but they are siblings in our construct tree.
+        const auto* sibling_loop = SiblingLoopConstruct(enclosing_construct);
+        // Go to the sibling loop if it exists, otherwise walk up to the parent.
+        enclosing_construct = sibling_loop ? sibling_loop : enclosing_construct->parent;
+    }
+    // At worst, we go all the way out to the function construct.
+    TINT_ASSERT(Reader, enclosing_construct != nullptr);
+    return enclosing_construct;
+}
+
+TypedExpression FunctionEmitter::MakeNumericConversion(const spvtools::opt::Instruction& inst) {
     const auto opcode = inst.opcode();
-    if ((opcode == SpvOpVectorShuffle) || (opcode == SpvOpOuterProduct)) {
-      // We might access the vector operands multiple times. Make sure they
-      // are evaluated only once.
-      require_named_const_def(inst, 0);
-      require_named_const_def(inst, 1);
+    auto* requested_type = parser_impl_.ConvertType(inst.type_id());
+    auto arg_expr = MakeOperand(inst, 0);
+    if (!arg_expr) {
+        return {};
     }
-    if (parser_impl_.IsGlslExtendedInstruction(inst)) {
-      // Some emulations of GLSLstd450 instructions evaluate certain operands
-      // multiple times. Ensure their expressions are evaluated only once.
-      switch (inst.GetSingleWordInOperand(1)) {
-        case GLSLstd450FaceForward:
-          // The "normal" operand expression is used twice in code generation.
-          require_named_const_def(inst, 2);
-          break;
-        case GLSLstd450Reflect:
-          require_named_const_def(inst, 2);  // Incident
-          require_named_const_def(inst, 3);  // Normal
-          break;
-        default:
-          break;
-      }
-    }
-  }
+    arg_expr.type = arg_expr.type->UnwrapRef();
 
-  // Scan uses of locally defined IDs, in function block order.
-  for (auto block_id : block_order_) {
-    const auto* block_info = GetBlockInfo(block_id);
-    const auto block_pos = block_info->pos;
-    for (const auto& inst : *(block_info->basic_block)) {
-      // Update bookkeeping for locally-defined IDs used by this instruction.
-      inst.ForEachInId([this, block_pos, block_info](const uint32_t* id_ptr) {
-        auto* def_info = GetDefInfo(*id_ptr);
-        if (def_info) {
-          // Update usage count.
-          def_info->num_uses++;
-          // Update usage span.
-          def_info->last_use_pos = std::max(def_info->last_use_pos, block_pos);
-
-          // Determine whether this ID is defined in a different construct
-          // from this use.
-          const auto defining_block = block_order_[def_info->block_pos];
-          const auto* def_in_construct =
-              GetBlockInfo(defining_block)->construct;
-          if (def_in_construct != block_info->construct) {
-            def_info->used_in_another_construct = true;
-          }
+    const Type* expr_type = nullptr;
+    if ((opcode == SpvOpConvertSToF) || (opcode == SpvOpConvertUToF)) {
+        if (arg_expr.type->IsIntegerScalarOrVector()) {
+            expr_type = requested_type;
+        } else {
+            Fail() << "operand for conversion to floating point must be integral "
+                      "scalar or vector: "
+                   << inst.PrettyPrint();
         }
-      });
-
-      if (inst.opcode() == SpvOpPhi) {
-        // Declare a name for the variable used to carry values to a phi.
-        const auto phi_id = inst.result_id();
-        auto* phi_def_info = GetDefInfo(phi_id);
-        phi_def_info->phi_var =
-            namer_.MakeDerivedName(namer_.Name(phi_id) + "_phi");
-        // Track all the places where we need to mention the variable,
-        // so we can place its declaration.  First, record the location of
-        // the read from the variable.
-        uint32_t first_pos = block_pos;
-        uint32_t last_pos = block_pos;
-        // Record the assignments that will propagate values from predecessor
-        // blocks.
-        for (uint32_t i = 0; i + 1 < inst.NumInOperands(); i += 2) {
-          const uint32_t value_id = inst.GetSingleWordInOperand(i);
-          const uint32_t pred_block_id = inst.GetSingleWordInOperand(i + 1);
-          auto* pred_block_info = GetBlockInfo(pred_block_id);
-          // The predecessor might not be in the block order at all, so we
-          // need this guard.
-          if (IsInBlockOrder(pred_block_info)) {
-            // Record the assignment that needs to occur at the end
-            // of the predecessor block.
-            pred_block_info->phi_assignments.push_back({phi_id, value_id});
-            first_pos = std::min(first_pos, pred_block_info->pos);
-            last_pos = std::max(last_pos, pred_block_info->pos);
-          }
+    } else if (inst.opcode() == SpvOpConvertFToU) {
+        if (arg_expr.type->IsFloatScalarOrVector()) {
+            expr_type = parser_impl_.GetUnsignedIntMatchingShape(arg_expr.type);
+        } else {
+            Fail() << "operand for conversion to unsigned integer must be floating "
+                      "point scalar or vector: "
+                   << inst.PrettyPrint();
         }
-
-        // Schedule the declaration of the state variable.
-        const auto* enclosing_construct =
-            GetEnclosingScope(first_pos, last_pos);
-        GetBlockInfo(enclosing_construct->begin_id)
-            ->phis_needing_state_vars.push_back(phi_id);
-      }
+    } else if (inst.opcode() == SpvOpConvertFToS) {
+        if (arg_expr.type->IsFloatScalarOrVector()) {
+            expr_type = parser_impl_.GetSignedIntMatchingShape(arg_expr.type);
+        } else {
+            Fail() << "operand for conversion to signed integer must be floating "
+                      "point scalar or vector: "
+                   << inst.PrettyPrint();
+        }
     }
-  }
-
-  // For an ID defined in this function, determine if its evaluation and
-  // potential declaration needs special handling:
-  // - Compensate for the fact that dominance does not map directly to scope.
-  //   A definition could dominate its use, but a named definition in WGSL
-  //   at the location of the definition could go out of scope by the time
-  //   you reach the use.  In that case, we hoist the definition to a basic
-  //   block at the smallest scope enclosing both the definition and all
-  //   its uses.
-  // - If value is used in a different construct than its definition, then it
-  //   needs a named constant definition.  Otherwise we might sink an
-  //   expensive computation into control flow, and hence change performance.
-  for (auto& id_def_info_pair : def_info_) {
-    const auto def_id = id_def_info_pair.first;
-    auto* def_info = id_def_info_pair.second.get();
-    if (def_info->num_uses == 0) {
-      // There is no need to adjust the location of the declaration.
-      continue;
-    }
-    // The first use must be the at the SSA definition, because block order
-    // respects dominance.
-    const auto first_pos = def_info->block_pos;
-    const auto last_use_pos = def_info->last_use_pos;
-
-    const auto* def_in_construct =
-        GetBlockInfo(block_order_[first_pos])->construct;
-    // A definition in the first block of an kIfSelection or kSwitchSelection
-    // occurs before the branch, and so that definition should count as
-    // having been defined at the scope of the parent construct.
-    if (first_pos == def_in_construct->begin_pos) {
-      if ((def_in_construct->kind == Construct::kIfSelection) ||
-          (def_in_construct->kind == Construct::kSwitchSelection)) {
-        def_in_construct = def_in_construct->parent;
-      }
+    if (expr_type == nullptr) {
+        // The diagnostic has already been emitted.
+        return {};
     }
 
-    bool should_hoist = false;
-    if (!def_in_construct->ContainsPos(last_use_pos)) {
-      // To satisfy scoping, we have to hoist the definition out to an enclosing
-      // construct.
-      should_hoist = true;
-    } else {
-      // Avoid moving combinatorial values across constructs.  This is a
-      // simple heuristic to avoid changing the cost of an operation
-      // by moving it into or out of a loop, for example.
-      if ((def_info->storage_class == ast::StorageClass::kInvalid) &&
-          def_info->used_in_another_construct) {
-        should_hoist = true;
-      }
+    ast::ExpressionList params;
+    params.push_back(arg_expr.expr);
+    TypedExpression result{
+        expr_type,
+        builder_.Construct(GetSourceForInst(inst), expr_type->Build(builder_), std::move(params))};
+
+    if (requested_type == expr_type) {
+        return result;
     }
-
-    if (should_hoist) {
-      const auto* enclosing_construct =
-          GetEnclosingScope(first_pos, last_use_pos);
-      if (enclosing_construct == def_in_construct) {
-        // We can use a plain 'const' definition.
-        def_info->requires_named_const_def = true;
-      } else {
-        // We need to make a hoisted variable definition.
-        // TODO(dneto): Handle non-storable types, particularly pointers.
-        def_info->requires_hoisted_def = true;
-        auto* hoist_to_block = GetBlockInfo(enclosing_construct->begin_id);
-        hoist_to_block->hoisted_ids.push_back(def_id);
-      }
-    }
-  }
-}
-
-const Construct* FunctionEmitter::GetEnclosingScope(uint32_t first_pos,
-                                                    uint32_t last_pos) const {
-  const auto* enclosing_construct =
-      GetBlockInfo(block_order_[first_pos])->construct;
-  TINT_ASSERT(Reader, enclosing_construct != nullptr);
-  // Constructs are strictly nesting, so follow parent pointers
-  while (enclosing_construct &&
-         !enclosing_construct->ScopeContainsPos(last_pos)) {
-    // The scope of a continue construct is enclosed in its associated loop
-    // construct, but they are siblings in our construct tree.
-    const auto* sibling_loop = SiblingLoopConstruct(enclosing_construct);
-    // Go to the sibling loop if it exists, otherwise walk up to the parent.
-    enclosing_construct =
-        sibling_loop ? sibling_loop : enclosing_construct->parent;
-  }
-  // At worst, we go all the way out to the function construct.
-  TINT_ASSERT(Reader, enclosing_construct != nullptr);
-  return enclosing_construct;
-}
-
-TypedExpression FunctionEmitter::MakeNumericConversion(
-    const spvtools::opt::Instruction& inst) {
-  const auto opcode = inst.opcode();
-  auto* requested_type = parser_impl_.ConvertType(inst.type_id());
-  auto arg_expr = MakeOperand(inst, 0);
-  if (!arg_expr) {
-    return {};
-  }
-  arg_expr.type = arg_expr.type->UnwrapRef();
-
-  const Type* expr_type = nullptr;
-  if ((opcode == SpvOpConvertSToF) || (opcode == SpvOpConvertUToF)) {
-    if (arg_expr.type->IsIntegerScalarOrVector()) {
-      expr_type = requested_type;
-    } else {
-      Fail() << "operand for conversion to floating point must be integral "
-                "scalar or vector: "
-             << inst.PrettyPrint();
-    }
-  } else if (inst.opcode() == SpvOpConvertFToU) {
-    if (arg_expr.type->IsFloatScalarOrVector()) {
-      expr_type = parser_impl_.GetUnsignedIntMatchingShape(arg_expr.type);
-    } else {
-      Fail() << "operand for conversion to unsigned integer must be floating "
-                "point scalar or vector: "
-             << inst.PrettyPrint();
-    }
-  } else if (inst.opcode() == SpvOpConvertFToS) {
-    if (arg_expr.type->IsFloatScalarOrVector()) {
-      expr_type = parser_impl_.GetSignedIntMatchingShape(arg_expr.type);
-    } else {
-      Fail() << "operand for conversion to signed integer must be floating "
-                "point scalar or vector: "
-             << inst.PrettyPrint();
-    }
-  }
-  if (expr_type == nullptr) {
-    // The diagnostic has already been emitted.
-    return {};
-  }
-
-  ast::ExpressionList params;
-  params.push_back(arg_expr.expr);
-  TypedExpression result{
-      expr_type,
-      builder_.Construct(GetSourceForInst(inst), expr_type->Build(builder_),
-                         std::move(params))};
-
-  if (requested_type == expr_type) {
-    return result;
-  }
-  return {requested_type, create<ast::BitcastExpression>(
-                              GetSourceForInst(inst),
-                              requested_type->Build(builder_), result.expr)};
+    return {requested_type,
+            create<ast::BitcastExpression>(GetSourceForInst(inst), requested_type->Build(builder_),
+                                           result.expr)};
 }
 
 bool FunctionEmitter::EmitFunctionCall(const spvtools::opt::Instruction& inst) {
-  // We ignore function attributes such as Inline, DontInline, Pure, Const.
-  auto name = namer_.Name(inst.GetSingleWordInOperand(0));
-  auto* function = create<ast::IdentifierExpression>(
-      Source{}, builder_.Symbols().Register(name));
+    // We ignore function attributes such as Inline, DontInline, Pure, Const.
+    auto name = namer_.Name(inst.GetSingleWordInOperand(0));
+    auto* function = create<ast::IdentifierExpression>(Source{}, builder_.Symbols().Register(name));
 
-  ast::ExpressionList args;
-  for (uint32_t iarg = 1; iarg < inst.NumInOperands(); ++iarg) {
-    auto expr = MakeOperand(inst, iarg);
-    if (!expr) {
-      return false;
+    ast::ExpressionList args;
+    for (uint32_t iarg = 1; iarg < inst.NumInOperands(); ++iarg) {
+        auto expr = MakeOperand(inst, iarg);
+        if (!expr) {
+            return false;
+        }
+        // Functions cannot use references as parameters, so we need to pass by
+        // pointer if the operand is of pointer type.
+        expr = AddressOfIfNeeded(expr, def_use_mgr_->GetDef(inst.GetSingleWordInOperand(iarg)));
+        args.emplace_back(expr.expr);
     }
-    // Functions cannot use references as parameters, so we need to pass by
-    // pointer if the operand is of pointer type.
-    expr = AddressOfIfNeeded(
-        expr, def_use_mgr_->GetDef(inst.GetSingleWordInOperand(iarg)));
-    args.emplace_back(expr.expr);
-  }
-  if (failed()) {
-    return false;
-  }
-  auto* call_expr =
-      create<ast::CallExpression>(Source{}, function, std::move(args));
-  auto* result_type = parser_impl_.ConvertType(inst.type_id());
-  if (!result_type) {
-    return Fail() << "internal error: no mapped type result of call: "
-                  << inst.PrettyPrint();
-  }
+    if (failed()) {
+        return false;
+    }
+    auto* call_expr = create<ast::CallExpression>(Source{}, function, std::move(args));
+    auto* result_type = parser_impl_.ConvertType(inst.type_id());
+    if (!result_type) {
+        return Fail() << "internal error: no mapped type result of call: " << inst.PrettyPrint();
+    }
 
-  if (result_type->Is<Void>()) {
-    return nullptr !=
-           AddStatement(create<ast::CallStatement>(Source{}, call_expr));
-  }
+    if (result_type->Is<Void>()) {
+        return nullptr != AddStatement(create<ast::CallStatement>(Source{}, call_expr));
+    }
 
-  return EmitConstDefOrWriteToHoistedVar(inst, {result_type, call_expr});
+    return EmitConstDefOrWriteToHoistedVar(inst, {result_type, call_expr});
 }
 
-bool FunctionEmitter::EmitControlBarrier(
-    const spvtools::opt::Instruction& inst) {
-  uint32_t operands[3];
-  for (int i = 0; i < 3; i++) {
-    auto id = inst.GetSingleWordInOperand(i);
-    if (auto* constant = constant_mgr_->FindDeclaredConstant(id)) {
-      operands[i] = constant->GetU32();
+bool FunctionEmitter::EmitControlBarrier(const spvtools::opt::Instruction& inst) {
+    uint32_t operands[3];
+    for (int i = 0; i < 3; i++) {
+        auto id = inst.GetSingleWordInOperand(i);
+        if (auto* constant = constant_mgr_->FindDeclaredConstant(id)) {
+            operands[i] = constant->GetU32();
+        } else {
+            return Fail() << "invalid or missing operands for control barrier";
+        }
+    }
+
+    uint32_t execution = operands[0];
+    uint32_t memory = operands[1];
+    uint32_t semantics = operands[2];
+
+    if (execution != SpvScopeWorkgroup) {
+        return Fail() << "unsupported control barrier execution scope: "
+                      << "expected Workgroup (2), got: " << execution;
+    }
+    if (semantics & SpvMemorySemanticsAcquireReleaseMask) {
+        semantics &= ~SpvMemorySemanticsAcquireReleaseMask;
     } else {
-      return Fail() << "invalid or missing operands for control barrier";
+        return Fail() << "control barrier semantics requires acquire and release";
     }
-  }
-
-  uint32_t execution = operands[0];
-  uint32_t memory = operands[1];
-  uint32_t semantics = operands[2];
-
-  if (execution != SpvScopeWorkgroup) {
-    return Fail() << "unsupported control barrier execution scope: "
-                  << "expected Workgroup (2), got: " << execution;
-  }
-  if (semantics & SpvMemorySemanticsAcquireReleaseMask) {
-    semantics &= ~SpvMemorySemanticsAcquireReleaseMask;
-  } else {
-    return Fail() << "control barrier semantics requires acquire and release";
-  }
-  if (semantics & SpvMemorySemanticsWorkgroupMemoryMask) {
-    if (memory != SpvScopeWorkgroup) {
-      return Fail() << "workgroupBarrier requires workgroup memory scope";
+    if (semantics & SpvMemorySemanticsWorkgroupMemoryMask) {
+        if (memory != SpvScopeWorkgroup) {
+            return Fail() << "workgroupBarrier requires workgroup memory scope";
+        }
+        AddStatement(create<ast::CallStatement>(builder_.Call("workgroupBarrier")));
+        semantics &= ~SpvMemorySemanticsWorkgroupMemoryMask;
     }
-    AddStatement(create<ast::CallStatement>(builder_.Call("workgroupBarrier")));
-    semantics &= ~SpvMemorySemanticsWorkgroupMemoryMask;
-  }
-  if (semantics & SpvMemorySemanticsUniformMemoryMask) {
-    if (memory != SpvScopeDevice) {
-      return Fail() << "storageBarrier requires device memory scope";
+    if (semantics & SpvMemorySemanticsUniformMemoryMask) {
+        if (memory != SpvScopeDevice) {
+            return Fail() << "storageBarrier requires device memory scope";
+        }
+        AddStatement(create<ast::CallStatement>(builder_.Call("storageBarrier")));
+        semantics &= ~SpvMemorySemanticsUniformMemoryMask;
     }
-    AddStatement(create<ast::CallStatement>(builder_.Call("storageBarrier")));
-    semantics &= ~SpvMemorySemanticsUniformMemoryMask;
-  }
-  if (semantics) {
-    return Fail() << "unsupported control barrier semantics: " << semantics;
-  }
-  return true;
+    if (semantics) {
+        return Fail() << "unsupported control barrier semantics: " << semantics;
+    }
+    return true;
 }
 
-TypedExpression FunctionEmitter::MakeBuiltinCall(
-    const spvtools::opt::Instruction& inst) {
-  const auto builtin = GetBuiltin(inst.opcode());
-  auto* name = sem::str(builtin);
-  auto* ident = create<ast::IdentifierExpression>(
-      Source{}, builder_.Symbols().Register(name));
+TypedExpression FunctionEmitter::MakeBuiltinCall(const spvtools::opt::Instruction& inst) {
+    const auto builtin = GetBuiltin(inst.opcode());
+    auto* name = sem::str(builtin);
+    auto* ident = create<ast::IdentifierExpression>(Source{}, builder_.Symbols().Register(name));
 
-  ast::ExpressionList params;
-  const Type* first_operand_type = nullptr;
-  for (uint32_t iarg = 0; iarg < inst.NumInOperands(); ++iarg) {
-    TypedExpression operand = MakeOperand(inst, iarg);
-    if (first_operand_type == nullptr) {
-      first_operand_type = operand.type;
-    }
-    params.emplace_back(operand.expr);
-  }
-  auto* call_expr =
-      create<ast::CallExpression>(Source{}, ident, std::move(params));
-  auto* result_type = parser_impl_.ConvertType(inst.type_id());
-  if (!result_type) {
-    Fail() << "internal error: no mapped type result of call: "
-           << inst.PrettyPrint();
-    return {};
-  }
-  TypedExpression call{result_type, call_expr};
-  return parser_impl_.RectifyForcedResultType(call, inst, first_operand_type);
-}
-
-TypedExpression FunctionEmitter::MakeSimpleSelect(
-    const spvtools::opt::Instruction& inst) {
-  auto condition = MakeOperand(inst, 0);
-  auto true_value = MakeOperand(inst, 1);
-  auto false_value = MakeOperand(inst, 2);
-
-  // SPIR-V validation requires:
-  // - the condition to be bool or bool vector, so we don't check it here.
-  // - true_value false_value, and result type to match.
-  // - you can't select over pointers or pointer vectors, unless you also have
-  //   a VariablePointers* capability, which is not allowed in by WebGPU.
-  auto* op_ty = true_value.type;
-  if (op_ty->Is<Vector>() || op_ty->IsFloatScalar() ||
-      op_ty->IsIntegerScalar() || op_ty->Is<Bool>()) {
     ast::ExpressionList params;
-    params.push_back(false_value.expr);
-    params.push_back(true_value.expr);
-    // The condition goes last.
-    params.push_back(condition.expr);
-    return {op_ty, create<ast::CallExpression>(
-                       Source{},
-                       create<ast::IdentifierExpression>(
-                           Source{}, builder_.Symbols().Register("select")),
-                       std::move(params))};
-  }
-  return {};
+    const Type* first_operand_type = nullptr;
+    for (uint32_t iarg = 0; iarg < inst.NumInOperands(); ++iarg) {
+        TypedExpression operand = MakeOperand(inst, iarg);
+        if (first_operand_type == nullptr) {
+            first_operand_type = operand.type;
+        }
+        params.emplace_back(operand.expr);
+    }
+    auto* call_expr = create<ast::CallExpression>(Source{}, ident, std::move(params));
+    auto* result_type = parser_impl_.ConvertType(inst.type_id());
+    if (!result_type) {
+        Fail() << "internal error: no mapped type result of call: " << inst.PrettyPrint();
+        return {};
+    }
+    TypedExpression call{result_type, call_expr};
+    return parser_impl_.RectifyForcedResultType(call, inst, first_operand_type);
 }
 
-Source FunctionEmitter::GetSourceForInst(
-    const spvtools::opt::Instruction& inst) const {
-  return parser_impl_.GetSourceForInst(&inst);
+TypedExpression FunctionEmitter::MakeSimpleSelect(const spvtools::opt::Instruction& inst) {
+    auto condition = MakeOperand(inst, 0);
+    auto true_value = MakeOperand(inst, 1);
+    auto false_value = MakeOperand(inst, 2);
+
+    // SPIR-V validation requires:
+    // - the condition to be bool or bool vector, so we don't check it here.
+    // - true_value false_value, and result type to match.
+    // - you can't select over pointers or pointer vectors, unless you also have
+    //   a VariablePointers* capability, which is not allowed in by WebGPU.
+    auto* op_ty = true_value.type;
+    if (op_ty->Is<Vector>() || op_ty->IsFloatScalar() || op_ty->IsIntegerScalar() ||
+        op_ty->Is<Bool>()) {
+        ast::ExpressionList params;
+        params.push_back(false_value.expr);
+        params.push_back(true_value.expr);
+        // The condition goes last.
+        params.push_back(condition.expr);
+        return {op_ty,
+                create<ast::CallExpression>(Source{},
+                                            create<ast::IdentifierExpression>(
+                                                Source{}, builder_.Symbols().Register("select")),
+                                            std::move(params))};
+    }
+    return {};
+}
+
+Source FunctionEmitter::GetSourceForInst(const spvtools::opt::Instruction& inst) const {
+    return parser_impl_.GetSourceForInst(&inst);
 }
 
 const spvtools::opt::Instruction* FunctionEmitter::GetImage(
     const spvtools::opt::Instruction& inst) {
-  if (inst.NumInOperands() == 0) {
-    Fail() << "not an image access instruction: " << inst.PrettyPrint();
-    return nullptr;
-  }
-  // The image or sampled image operand is always the first operand.
-  const auto image_or_sampled_image_operand_id = inst.GetSingleWordInOperand(0);
-  const auto* image = parser_impl_.GetMemoryObjectDeclarationForHandle(
-      image_or_sampled_image_operand_id, true);
-  if (!image) {
-    Fail() << "internal error: couldn't find image for " << inst.PrettyPrint();
-    return nullptr;
-  }
-  return image;
+    if (inst.NumInOperands() == 0) {
+        Fail() << "not an image access instruction: " << inst.PrettyPrint();
+        return nullptr;
+    }
+    // The image or sampled image operand is always the first operand.
+    const auto image_or_sampled_image_operand_id = inst.GetSingleWordInOperand(0);
+    const auto* image =
+        parser_impl_.GetMemoryObjectDeclarationForHandle(image_or_sampled_image_operand_id, true);
+    if (!image) {
+        Fail() << "internal error: couldn't find image for " << inst.PrettyPrint();
+        return nullptr;
+    }
+    return image;
 }
 
-const Texture* FunctionEmitter::GetImageType(
-    const spvtools::opt::Instruction& image) {
-  const Pointer* ptr_type = parser_impl_.GetTypeForHandleVar(image);
-  if (!parser_impl_.success()) {
-    Fail();
-    return {};
-  }
-  if (!ptr_type) {
-    Fail() << "invalid texture type for " << image.PrettyPrint();
-    return {};
-  }
-  auto* result = ptr_type->type->UnwrapAll()->As<Texture>();
-  if (!result) {
-    Fail() << "invalid texture type for " << image.PrettyPrint();
-    return {};
-  }
-  return result;
+const Texture* FunctionEmitter::GetImageType(const spvtools::opt::Instruction& image) {
+    const Pointer* ptr_type = parser_impl_.GetTypeForHandleVar(image);
+    if (!parser_impl_.success()) {
+        Fail();
+        return {};
+    }
+    if (!ptr_type) {
+        Fail() << "invalid texture type for " << image.PrettyPrint();
+        return {};
+    }
+    auto* result = ptr_type->type->UnwrapAll()->As<Texture>();
+    if (!result) {
+        Fail() << "invalid texture type for " << image.PrettyPrint();
+        return {};
+    }
+    return result;
 }
 
-const ast::Expression* FunctionEmitter::GetImageExpression(
-    const spvtools::opt::Instruction& inst) {
-  auto* image = GetImage(inst);
-  if (!image) {
-    return nullptr;
-  }
-  auto name = namer_.Name(image->result_id());
-  return create<ast::IdentifierExpression>(GetSourceForInst(inst),
-                                           builder_.Symbols().Register(name));
+const ast::Expression* FunctionEmitter::GetImageExpression(const spvtools::opt::Instruction& inst) {
+    auto* image = GetImage(inst);
+    if (!image) {
+        return nullptr;
+    }
+    auto name = namer_.Name(image->result_id());
+    return create<ast::IdentifierExpression>(GetSourceForInst(inst),
+                                             builder_.Symbols().Register(name));
 }
 
 const ast::Expression* FunctionEmitter::GetSamplerExpression(
     const spvtools::opt::Instruction& inst) {
-  // The sampled image operand is always the first operand.
-  const auto image_or_sampled_image_operand_id = inst.GetSingleWordInOperand(0);
-  const auto* image = parser_impl_.GetMemoryObjectDeclarationForHandle(
-      image_or_sampled_image_operand_id, false);
-  if (!image) {
-    Fail() << "internal error: couldn't find sampler for "
-           << inst.PrettyPrint();
-    return nullptr;
-  }
-  auto name = namer_.Name(image->result_id());
-  return create<ast::IdentifierExpression>(GetSourceForInst(inst),
-                                           builder_.Symbols().Register(name));
+    // The sampled image operand is always the first operand.
+    const auto image_or_sampled_image_operand_id = inst.GetSingleWordInOperand(0);
+    const auto* image =
+        parser_impl_.GetMemoryObjectDeclarationForHandle(image_or_sampled_image_operand_id, false);
+    if (!image) {
+        Fail() << "internal error: couldn't find sampler for " << inst.PrettyPrint();
+        return nullptr;
+    }
+    auto name = namer_.Name(image->result_id());
+    return create<ast::IdentifierExpression>(GetSourceForInst(inst),
+                                             builder_.Symbols().Register(name));
 }
 
 bool FunctionEmitter::EmitImageAccess(const spvtools::opt::Instruction& inst) {
-  ast::ExpressionList args;
-  const auto opcode = inst.opcode();
+    ast::ExpressionList args;
+    const auto opcode = inst.opcode();
 
-  // Form the texture operand.
-  const spvtools::opt::Instruction* image = GetImage(inst);
-  if (!image) {
-    return false;
-  }
-  args.push_back(GetImageExpression(inst));
-
-  // Form the sampler operand, if needed.
-  if (IsSampledImageAccess(opcode)) {
-    // Form the sampler operand.
-    if (auto* sampler = GetSamplerExpression(inst)) {
-      args.push_back(sampler);
-    } else {
-      return false;
+    // Form the texture operand.
+    const spvtools::opt::Instruction* image = GetImage(inst);
+    if (!image) {
+        return false;
     }
-  }
+    args.push_back(GetImageExpression(inst));
 
-  // Find the texture type.
-  const Pointer* texture_ptr_type = parser_impl_.GetTypeForHandleVar(*image);
-  if (!texture_ptr_type) {
-    return Fail();
-  }
-  const Texture* texture_type =
-      texture_ptr_type->type->UnwrapAll()->As<Texture>();
+    // Form the sampler operand, if needed.
+    if (IsSampledImageAccess(opcode)) {
+        // Form the sampler operand.
+        if (auto* sampler = GetSamplerExpression(inst)) {
+            args.push_back(sampler);
+        } else {
+            return false;
+        }
+    }
 
-  if (!texture_type) {
-    return Fail();
-  }
+    // Find the texture type.
+    const Pointer* texture_ptr_type = parser_impl_.GetTypeForHandleVar(*image);
+    if (!texture_ptr_type) {
+        return Fail();
+    }
+    const Texture* texture_type = texture_ptr_type->type->UnwrapAll()->As<Texture>();
 
-  // This is the SPIR-V operand index.  We're done with the first operand.
-  uint32_t arg_index = 1;
+    if (!texture_type) {
+        return Fail();
+    }
 
-  // Push the coordinates operands.
-  auto coords = MakeCoordinateOperandsForImageAccess(inst);
-  if (coords.empty()) {
-    return false;
-  }
-  args.insert(args.end(), coords.begin(), coords.end());
-  // Skip the coordinates operand.
-  arg_index++;
+    // This is the SPIR-V operand index.  We're done with the first operand.
+    uint32_t arg_index = 1;
 
-  const auto num_args = inst.NumInOperands();
+    // Push the coordinates operands.
+    auto coords = MakeCoordinateOperandsForImageAccess(inst);
+    if (coords.empty()) {
+        return false;
+    }
+    args.insert(args.end(), coords.begin(), coords.end());
+    // Skip the coordinates operand.
+    arg_index++;
 
-  // Consumes the depth-reference argument, pushing it onto the end of
-  // the parameter list. Issues a diagnostic and returns false on error.
-  auto consume_dref = [&]() -> bool {
+    const auto num_args = inst.NumInOperands();
+
+    // Consumes the depth-reference argument, pushing it onto the end of
+    // the parameter list. Issues a diagnostic and returns false on error.
+    auto consume_dref = [&]() -> bool {
+        if (arg_index < num_args) {
+            args.push_back(MakeOperand(inst, arg_index).expr);
+            arg_index++;
+        } else {
+            return Fail() << "image depth-compare instruction is missing a Dref operand: "
+                          << inst.PrettyPrint();
+        }
+        return true;
+    };
+
+    std::string builtin_name;
+    bool use_level_of_detail_suffix = true;
+    bool is_dref_sample = false;
+    bool is_gather_or_dref_gather = false;
+    bool is_non_dref_sample = false;
+    switch (opcode) {
+        case SpvOpImageSampleImplicitLod:
+        case SpvOpImageSampleExplicitLod:
+        case SpvOpImageSampleProjImplicitLod:
+        case SpvOpImageSampleProjExplicitLod:
+            is_non_dref_sample = true;
+            builtin_name = "textureSample";
+            break;
+        case SpvOpImageSampleDrefImplicitLod:
+        case SpvOpImageSampleDrefExplicitLod:
+        case SpvOpImageSampleProjDrefImplicitLod:
+        case SpvOpImageSampleProjDrefExplicitLod:
+            is_dref_sample = true;
+            builtin_name = "textureSampleCompare";
+            if (!consume_dref()) {
+                return false;
+            }
+            break;
+        case SpvOpImageGather:
+            is_gather_or_dref_gather = true;
+            builtin_name = "textureGather";
+            if (!texture_type->Is<DepthTexture>()) {
+                // The explicit component is the *first* argument in WGSL.
+                args.insert(args.begin(), ToI32(MakeOperand(inst, arg_index)).expr);
+            }
+            // Skip over the component operand, even for depth textures.
+            arg_index++;
+            break;
+        case SpvOpImageDrefGather:
+            is_gather_or_dref_gather = true;
+            builtin_name = "textureGatherCompare";
+            if (!consume_dref()) {
+                return false;
+            }
+            break;
+        case SpvOpImageFetch:
+        case SpvOpImageRead:
+            // Read a single texel from a sampled or storage image.
+            builtin_name = "textureLoad";
+            use_level_of_detail_suffix = false;
+            break;
+        case SpvOpImageWrite:
+            builtin_name = "textureStore";
+            use_level_of_detail_suffix = false;
+            if (arg_index < num_args) {
+                auto texel = MakeOperand(inst, arg_index);
+                auto* converted_texel = ConvertTexelForStorage(inst, texel, texture_type);
+                if (!converted_texel) {
+                    return false;
+                }
+
+                args.push_back(converted_texel);
+                arg_index++;
+            } else {
+                return Fail() << "image write is missing a Texel operand: " << inst.PrettyPrint();
+            }
+            break;
+        default:
+            return Fail() << "internal error: unrecognized image access: " << inst.PrettyPrint();
+    }
+
+    // Loop over the image operands, looking for extra operands to the builtin.
+    // Except we uroll the loop.
+    uint32_t image_operands_mask = 0;
     if (arg_index < num_args) {
-      args.push_back(MakeOperand(inst, arg_index).expr);
-      arg_index++;
-    } else {
-      return Fail()
-             << "image depth-compare instruction is missing a Dref operand: "
-             << inst.PrettyPrint();
+        image_operands_mask = inst.GetSingleWordInOperand(arg_index);
+        arg_index++;
     }
-    return true;
-  };
-
-  std::string builtin_name;
-  bool use_level_of_detail_suffix = true;
-  bool is_dref_sample = false;
-  bool is_gather_or_dref_gather = false;
-  bool is_non_dref_sample = false;
-  switch (opcode) {
-    case SpvOpImageSampleImplicitLod:
-    case SpvOpImageSampleExplicitLod:
-    case SpvOpImageSampleProjImplicitLod:
-    case SpvOpImageSampleProjExplicitLod:
-      is_non_dref_sample = true;
-      builtin_name = "textureSample";
-      break;
-    case SpvOpImageSampleDrefImplicitLod:
-    case SpvOpImageSampleDrefExplicitLod:
-    case SpvOpImageSampleProjDrefImplicitLod:
-    case SpvOpImageSampleProjDrefExplicitLod:
-      is_dref_sample = true;
-      builtin_name = "textureSampleCompare";
-      if (!consume_dref()) {
-        return false;
-      }
-      break;
-    case SpvOpImageGather:
-      is_gather_or_dref_gather = true;
-      builtin_name = "textureGather";
-      if (!texture_type->Is<DepthTexture>()) {
-        // The explicit component is the *first* argument in WGSL.
-        args.insert(args.begin(), ToI32(MakeOperand(inst, arg_index)).expr);
-      }
-      // Skip over the component operand, even for depth textures.
-      arg_index++;
-      break;
-    case SpvOpImageDrefGather:
-      is_gather_or_dref_gather = true;
-      builtin_name = "textureGatherCompare";
-      if (!consume_dref()) {
-        return false;
-      }
-      break;
-    case SpvOpImageFetch:
-    case SpvOpImageRead:
-      // Read a single texel from a sampled or storage image.
-      builtin_name = "textureLoad";
-      use_level_of_detail_suffix = false;
-      break;
-    case SpvOpImageWrite:
-      builtin_name = "textureStore";
-      use_level_of_detail_suffix = false;
-      if (arg_index < num_args) {
-        auto texel = MakeOperand(inst, arg_index);
-        auto* converted_texel =
-            ConvertTexelForStorage(inst, texel, texture_type);
-        if (!converted_texel) {
-          return false;
+    if (arg_index < num_args && (image_operands_mask & SpvImageOperandsBiasMask)) {
+        if (is_dref_sample) {
+            return Fail() << "WGSL does not support depth-reference sampling with "
+                             "level-of-detail bias: "
+                          << inst.PrettyPrint();
+        }
+        if (is_gather_or_dref_gather) {
+            return Fail() << "WGSL does not support image gather with "
+                             "level-of-detail bias: "
+                          << inst.PrettyPrint();
+        }
+        builtin_name += "Bias";
+        args.push_back(MakeOperand(inst, arg_index).expr);
+        image_operands_mask ^= SpvImageOperandsBiasMask;
+        arg_index++;
+    }
+    if (arg_index < num_args && (image_operands_mask & SpvImageOperandsLodMask)) {
+        if (use_level_of_detail_suffix) {
+            builtin_name += "Level";
+        }
+        if (is_dref_sample || is_gather_or_dref_gather) {
+            // Metal only supports Lod = 0 for comparison sampling without
+            // derivatives.
+            // Vulkan SPIR-V does not allow Lod with OpImageGather or
+            // OpImageDrefGather.
+            if (!IsFloatZero(inst.GetSingleWordInOperand(arg_index))) {
+                return Fail() << "WGSL comparison sampling without derivatives "
+                                 "requires level-of-detail 0.0"
+                              << inst.PrettyPrint();
+            }
+            // Don't generate the Lod argument.
+        } else {
+            // Generate the Lod argument.
+            TypedExpression lod = MakeOperand(inst, arg_index);
+            // When sampling from a depth texture, the Lod operand must be an I32.
+            if (texture_type->Is<DepthTexture>()) {
+                // Convert it to a signed integer type.
+                lod = ToI32(lod);
+            }
+            args.push_back(lod.expr);
         }
 
-        args.push_back(converted_texel);
+        image_operands_mask ^= SpvImageOperandsLodMask;
         arg_index++;
-      } else {
-        return Fail() << "image write is missing a Texel operand: "
-                      << inst.PrettyPrint();
-      }
-      break;
-    default:
-      return Fail() << "internal error: unrecognized image access: "
-                    << inst.PrettyPrint();
-  }
+    } else if ((opcode == SpvOpImageFetch || opcode == SpvOpImageRead) &&
+               !texture_type->IsAnyOf<DepthMultisampledTexture, MultisampledTexture>()) {
+        // textureLoad requires an explicit level-of-detail parameter for
+        // non-multisampled texture types.
+        args.push_back(parser_impl_.MakeNullValue(ty_.I32()));
+    }
+    if (arg_index + 1 < num_args && (image_operands_mask & SpvImageOperandsGradMask)) {
+        if (is_dref_sample) {
+            return Fail() << "WGSL does not support depth-reference sampling with "
+                             "explicit gradient: "
+                          << inst.PrettyPrint();
+        }
+        if (is_gather_or_dref_gather) {
+            return Fail() << "WGSL does not support image gather with "
+                             "explicit gradient: "
+                          << inst.PrettyPrint();
+        }
+        builtin_name += "Grad";
+        args.push_back(MakeOperand(inst, arg_index).expr);
+        args.push_back(MakeOperand(inst, arg_index + 1).expr);
+        image_operands_mask ^= SpvImageOperandsGradMask;
+        arg_index += 2;
+    }
+    if (arg_index < num_args && (image_operands_mask & SpvImageOperandsConstOffsetMask)) {
+        if (!IsImageSamplingOrGatherOrDrefGather(opcode)) {
+            return Fail() << "ConstOffset is only permitted for sampling, gather, or "
+                             "depth-reference gather operations: "
+                          << inst.PrettyPrint();
+        }
+        switch (texture_type->dims) {
+            case ast::TextureDimension::k2d:
+            case ast::TextureDimension::k2dArray:
+            case ast::TextureDimension::k3d:
+                break;
+            default:
+                return Fail() << "ConstOffset is only permitted for 2D, 2D Arrayed, "
+                                 "and 3D textures: "
+                              << inst.PrettyPrint();
+        }
 
-  // Loop over the image operands, looking for extra operands to the builtin.
-  // Except we uroll the loop.
-  uint32_t image_operands_mask = 0;
-  if (arg_index < num_args) {
-    image_operands_mask = inst.GetSingleWordInOperand(arg_index);
-    arg_index++;
-  }
-  if (arg_index < num_args &&
-      (image_operands_mask & SpvImageOperandsBiasMask)) {
-    if (is_dref_sample) {
-      return Fail() << "WGSL does not support depth-reference sampling with "
-                       "level-of-detail bias: "
-                    << inst.PrettyPrint();
+        args.push_back(ToSignedIfUnsigned(MakeOperand(inst, arg_index)).expr);
+        image_operands_mask ^= SpvImageOperandsConstOffsetMask;
+        arg_index++;
     }
-    if (is_gather_or_dref_gather) {
-      return Fail() << "WGSL does not support image gather with "
-                       "level-of-detail bias: "
-                    << inst.PrettyPrint();
+    if (arg_index < num_args && (image_operands_mask & SpvImageOperandsSampleMask)) {
+        // TODO(dneto): only permitted with ImageFetch
+        args.push_back(ToI32(MakeOperand(inst, arg_index)).expr);
+        image_operands_mask ^= SpvImageOperandsSampleMask;
+        arg_index++;
     }
-    builtin_name += "Bias";
-    args.push_back(MakeOperand(inst, arg_index).expr);
-    image_operands_mask ^= SpvImageOperandsBiasMask;
-    arg_index++;
-  }
-  if (arg_index < num_args && (image_operands_mask & SpvImageOperandsLodMask)) {
-    if (use_level_of_detail_suffix) {
-      builtin_name += "Level";
+    if (image_operands_mask) {
+        return Fail() << "unsupported image operands (" << image_operands_mask
+                      << "): " << inst.PrettyPrint();
     }
-    if (is_dref_sample || is_gather_or_dref_gather) {
-      // Metal only supports Lod = 0 for comparison sampling without
-      // derivatives.
-      // Vulkan SPIR-V does not allow Lod with OpImageGather or
-      // OpImageDrefGather.
-      if (!IsFloatZero(inst.GetSingleWordInOperand(arg_index))) {
-        return Fail() << "WGSL comparison sampling without derivatives "
-                         "requires level-of-detail 0.0"
-                      << inst.PrettyPrint();
-      }
-      // Don't generate the Lod argument.
+
+    // If any of the arguments are nullptr, then we've failed.
+    if (std::any_of(args.begin(), args.end(), [](auto* expr) { return expr == nullptr; })) {
+        return false;
+    }
+
+    auto* ident =
+        create<ast::IdentifierExpression>(Source{}, builder_.Symbols().Register(builtin_name));
+    auto* call_expr = create<ast::CallExpression>(Source{}, ident, std::move(args));
+
+    if (inst.type_id() != 0) {
+        // It returns a value.
+        const ast::Expression* value = call_expr;
+
+        // The result type, derived from the SPIR-V instruction.
+        auto* result_type = parser_impl_.ConvertType(inst.type_id());
+        auto* result_component_type = result_type;
+        if (auto* result_vector_type = As<Vector>(result_type)) {
+            result_component_type = result_vector_type->type;
+        }
+
+        // For depth textures, the arity might mot match WGSL:
+        //  Operation           SPIR-V                     WGSL
+        //   normal sampling     vec4  ImplicitLod          f32
+        //   normal sampling     vec4  ExplicitLod          f32
+        //   compare sample      f32   DrefImplicitLod      f32
+        //   compare sample      f32   DrefExplicitLod      f32
+        //   texel load          vec4  ImageFetch           f32
+        //   normal gather       vec4  ImageGather          vec4
+        //   dref gather         vec4  ImageDrefGather      vec4
+        // Construct a 4-element vector with the result from the builtin in the
+        // first component.
+        if (texture_type->IsAnyOf<DepthTexture, DepthMultisampledTexture>()) {
+            if (is_non_dref_sample || (opcode == SpvOpImageFetch)) {
+                value = builder_.Construct(
+                    Source{},
+                    result_type->Build(builder_),  // a vec4
+                    ast::ExpressionList{value, parser_impl_.MakeNullValue(result_component_type),
+                                        parser_impl_.MakeNullValue(result_component_type),
+                                        parser_impl_.MakeNullValue(result_component_type)});
+            }
+        }
+
+        // If necessary, convert the result to the signedness of the instruction
+        // result type. Compare the SPIR-V image's sampled component type with the
+        // component of the result type of the SPIR-V instruction.
+        auto* spirv_image_type = parser_impl_.GetSpirvTypeForHandleMemoryObjectDeclaration(*image);
+        if (!spirv_image_type || (spirv_image_type->opcode() != SpvOpTypeImage)) {
+            return Fail() << "invalid image type for image memory object declaration "
+                          << image->PrettyPrint();
+        }
+        auto* expected_component_type =
+            parser_impl_.ConvertType(spirv_image_type->GetSingleWordInOperand(0));
+        if (expected_component_type != result_component_type) {
+            // This occurs if one is signed integer and the other is unsigned integer,
+            // or vice versa. Perform a bitcast.
+            value =
+                create<ast::BitcastExpression>(Source{}, result_type->Build(builder_), call_expr);
+        }
+        if (!expected_component_type->Is<F32>() && IsSampledImageAccess(opcode)) {
+            // WGSL permits sampled image access only on float textures.
+            // Reject this case in the SPIR-V reader, at least until SPIR-V validation
+            // catches up with this rule and can reject it earlier in the workflow.
+            return Fail() << "sampled image must have float component type";
+        }
+
+        EmitConstDefOrWriteToHoistedVar(inst, {result_type, value});
     } else {
-      // Generate the Lod argument.
-      TypedExpression lod = MakeOperand(inst, arg_index);
-      // When sampling from a depth texture, the Lod operand must be an I32.
-      if (texture_type->Is<DepthTexture>()) {
-        // Convert it to a signed integer type.
-        lod = ToI32(lod);
-      }
-      args.push_back(lod.expr);
+        // It's an image write. No value is returned, so make a statement out
+        // of the call.
+        AddStatement(create<ast::CallStatement>(Source{}, call_expr));
     }
-
-    image_operands_mask ^= SpvImageOperandsLodMask;
-    arg_index++;
-  } else if ((opcode == SpvOpImageFetch || opcode == SpvOpImageRead) &&
-             !texture_type
-                  ->IsAnyOf<DepthMultisampledTexture, MultisampledTexture>()) {
-    // textureLoad requires an explicit level-of-detail parameter for
-    // non-multisampled texture types.
-    args.push_back(parser_impl_.MakeNullValue(ty_.I32()));
-  }
-  if (arg_index + 1 < num_args &&
-      (image_operands_mask & SpvImageOperandsGradMask)) {
-    if (is_dref_sample) {
-      return Fail() << "WGSL does not support depth-reference sampling with "
-                       "explicit gradient: "
-                    << inst.PrettyPrint();
-    }
-    if (is_gather_or_dref_gather) {
-      return Fail() << "WGSL does not support image gather with "
-                       "explicit gradient: "
-                    << inst.PrettyPrint();
-    }
-    builtin_name += "Grad";
-    args.push_back(MakeOperand(inst, arg_index).expr);
-    args.push_back(MakeOperand(inst, arg_index + 1).expr);
-    image_operands_mask ^= SpvImageOperandsGradMask;
-    arg_index += 2;
-  }
-  if (arg_index < num_args &&
-      (image_operands_mask & SpvImageOperandsConstOffsetMask)) {
-    if (!IsImageSamplingOrGatherOrDrefGather(opcode)) {
-      return Fail() << "ConstOffset is only permitted for sampling, gather, or "
-                       "depth-reference gather operations: "
-                    << inst.PrettyPrint();
-    }
-    switch (texture_type->dims) {
-      case ast::TextureDimension::k2d:
-      case ast::TextureDimension::k2dArray:
-      case ast::TextureDimension::k3d:
-        break;
-      default:
-        return Fail() << "ConstOffset is only permitted for 2D, 2D Arrayed, "
-                         "and 3D textures: "
-                      << inst.PrettyPrint();
-    }
-
-    args.push_back(ToSignedIfUnsigned(MakeOperand(inst, arg_index)).expr);
-    image_operands_mask ^= SpvImageOperandsConstOffsetMask;
-    arg_index++;
-  }
-  if (arg_index < num_args &&
-      (image_operands_mask & SpvImageOperandsSampleMask)) {
-    // TODO(dneto): only permitted with ImageFetch
-    args.push_back(ToI32(MakeOperand(inst, arg_index)).expr);
-    image_operands_mask ^= SpvImageOperandsSampleMask;
-    arg_index++;
-  }
-  if (image_operands_mask) {
-    return Fail() << "unsupported image operands (" << image_operands_mask
-                  << "): " << inst.PrettyPrint();
-  }
-
-  // If any of the arguments are nullptr, then we've failed.
-  if (std::any_of(args.begin(), args.end(),
-                  [](auto* expr) { return expr == nullptr; })) {
-    return false;
-  }
-
-  auto* ident = create<ast::IdentifierExpression>(
-      Source{}, builder_.Symbols().Register(builtin_name));
-  auto* call_expr =
-      create<ast::CallExpression>(Source{}, ident, std::move(args));
-
-  if (inst.type_id() != 0) {
-    // It returns a value.
-    const ast::Expression* value = call_expr;
-
-    // The result type, derived from the SPIR-V instruction.
-    auto* result_type = parser_impl_.ConvertType(inst.type_id());
-    auto* result_component_type = result_type;
-    if (auto* result_vector_type = As<Vector>(result_type)) {
-      result_component_type = result_vector_type->type;
-    }
-
-    // For depth textures, the arity might mot match WGSL:
-    //  Operation           SPIR-V                     WGSL
-    //   normal sampling     vec4  ImplicitLod          f32
-    //   normal sampling     vec4  ExplicitLod          f32
-    //   compare sample      f32   DrefImplicitLod      f32
-    //   compare sample      f32   DrefExplicitLod      f32
-    //   texel load          vec4  ImageFetch           f32
-    //   normal gather       vec4  ImageGather          vec4
-    //   dref gather         vec4  ImageDrefGather      vec4
-    // Construct a 4-element vector with the result from the builtin in the
-    // first component.
-    if (texture_type->IsAnyOf<DepthTexture, DepthMultisampledTexture>()) {
-      if (is_non_dref_sample || (opcode == SpvOpImageFetch)) {
-        value = builder_.Construct(
-            Source{},
-            result_type->Build(builder_),  // a vec4
-            ast::ExpressionList{
-                value, parser_impl_.MakeNullValue(result_component_type),
-                parser_impl_.MakeNullValue(result_component_type),
-                parser_impl_.MakeNullValue(result_component_type)});
-      }
-    }
-
-    // If necessary, convert the result to the signedness of the instruction
-    // result type. Compare the SPIR-V image's sampled component type with the
-    // component of the result type of the SPIR-V instruction.
-    auto* spirv_image_type =
-        parser_impl_.GetSpirvTypeForHandleMemoryObjectDeclaration(*image);
-    if (!spirv_image_type || (spirv_image_type->opcode() != SpvOpTypeImage)) {
-      return Fail() << "invalid image type for image memory object declaration "
-                    << image->PrettyPrint();
-    }
-    auto* expected_component_type =
-        parser_impl_.ConvertType(spirv_image_type->GetSingleWordInOperand(0));
-    if (expected_component_type != result_component_type) {
-      // This occurs if one is signed integer and the other is unsigned integer,
-      // or vice versa. Perform a bitcast.
-      value = create<ast::BitcastExpression>(
-          Source{}, result_type->Build(builder_), call_expr);
-    }
-    if (!expected_component_type->Is<F32>() && IsSampledImageAccess(opcode)) {
-      // WGSL permits sampled image access only on float textures.
-      // Reject this case in the SPIR-V reader, at least until SPIR-V validation
-      // catches up with this rule and can reject it earlier in the workflow.
-      return Fail() << "sampled image must have float component type";
-    }
-
-    EmitConstDefOrWriteToHoistedVar(inst, {result_type, value});
-  } else {
-    // It's an image write. No value is returned, so make a statement out
-    // of the call.
-    AddStatement(create<ast::CallStatement>(Source{}, call_expr));
-  }
-  return success();
+    return success();
 }
 
 bool FunctionEmitter::EmitImageQuery(const spvtools::opt::Instruction& inst) {
-  // TODO(dneto): Reject cases that are valid in Vulkan but invalid in WGSL.
-  const spvtools::opt::Instruction* image = GetImage(inst);
-  if (!image) {
-    return false;
-  }
-  auto* texture_type = GetImageType(*image);
-  if (!texture_type) {
-    return false;
-  }
+    // TODO(dneto): Reject cases that are valid in Vulkan but invalid in WGSL.
+    const spvtools::opt::Instruction* image = GetImage(inst);
+    if (!image) {
+        return false;
+    }
+    auto* texture_type = GetImageType(*image);
+    if (!texture_type) {
+        return false;
+    }
 
-  const auto opcode = inst.opcode();
-  switch (opcode) {
-    case SpvOpImageQuerySize:
-    case SpvOpImageQuerySizeLod: {
-      ast::ExpressionList exprs;
-      // Invoke textureDimensions.
-      // If the texture is arrayed, combine with the result from
-      // textureNumLayers.
-      auto* dims_ident = create<ast::IdentifierExpression>(
-          Source{}, builder_.Symbols().Register("textureDimensions"));
-      ast::ExpressionList dims_args{GetImageExpression(inst)};
-      if (opcode == SpvOpImageQuerySizeLod) {
-        dims_args.push_back(ToI32(MakeOperand(inst, 1)).expr);
-      }
-      const ast::Expression* dims_call =
-          create<ast::CallExpression>(Source{}, dims_ident, dims_args);
-      auto dims = texture_type->dims;
-      if ((dims == ast::TextureDimension::kCube) ||
-          (dims == ast::TextureDimension::kCubeArray)) {
-        // textureDimension returns a 3-element vector but SPIR-V expects 2.
-        dims_call = create<ast::MemberAccessorExpression>(Source{}, dims_call,
-                                                          PrefixSwizzle(2));
-      }
-      exprs.push_back(dims_call);
-      if (ast::IsTextureArray(dims)) {
-        auto* layers_ident = create<ast::IdentifierExpression>(
-            Source{}, builder_.Symbols().Register("textureNumLayers"));
-        exprs.push_back(create<ast::CallExpression>(
-            Source{}, layers_ident,
-            ast::ExpressionList{GetImageExpression(inst)}));
-      }
-      auto* result_type = parser_impl_.ConvertType(inst.type_id());
-      TypedExpression expr = {
-          result_type,
-          builder_.Construct(Source{}, result_type->Build(builder_), exprs)};
-      return EmitConstDefOrWriteToHoistedVar(inst, expr);
+    const auto opcode = inst.opcode();
+    switch (opcode) {
+        case SpvOpImageQuerySize:
+        case SpvOpImageQuerySizeLod: {
+            ast::ExpressionList exprs;
+            // Invoke textureDimensions.
+            // If the texture is arrayed, combine with the result from
+            // textureNumLayers.
+            auto* dims_ident = create<ast::IdentifierExpression>(
+                Source{}, builder_.Symbols().Register("textureDimensions"));
+            ast::ExpressionList dims_args{GetImageExpression(inst)};
+            if (opcode == SpvOpImageQuerySizeLod) {
+                dims_args.push_back(ToI32(MakeOperand(inst, 1)).expr);
+            }
+            const ast::Expression* dims_call =
+                create<ast::CallExpression>(Source{}, dims_ident, dims_args);
+            auto dims = texture_type->dims;
+            if ((dims == ast::TextureDimension::kCube) ||
+                (dims == ast::TextureDimension::kCubeArray)) {
+                // textureDimension returns a 3-element vector but SPIR-V expects 2.
+                dims_call =
+                    create<ast::MemberAccessorExpression>(Source{}, dims_call, PrefixSwizzle(2));
+            }
+            exprs.push_back(dims_call);
+            if (ast::IsTextureArray(dims)) {
+                auto* layers_ident = create<ast::IdentifierExpression>(
+                    Source{}, builder_.Symbols().Register("textureNumLayers"));
+                exprs.push_back(create<ast::CallExpression>(
+                    Source{}, layers_ident, ast::ExpressionList{GetImageExpression(inst)}));
+            }
+            auto* result_type = parser_impl_.ConvertType(inst.type_id());
+            TypedExpression expr = {
+                result_type, builder_.Construct(Source{}, result_type->Build(builder_), exprs)};
+            return EmitConstDefOrWriteToHoistedVar(inst, expr);
+        }
+        case SpvOpImageQueryLod:
+            return Fail() << "WGSL does not support querying the level of detail of "
+                             "an image: "
+                          << inst.PrettyPrint();
+        case SpvOpImageQueryLevels:
+        case SpvOpImageQuerySamples: {
+            const auto* name =
+                (opcode == SpvOpImageQueryLevels) ? "textureNumLevels" : "textureNumSamples";
+            auto* levels_ident =
+                create<ast::IdentifierExpression>(Source{}, builder_.Symbols().Register(name));
+            const ast::Expression* ast_expr = create<ast::CallExpression>(
+                Source{}, levels_ident, ast::ExpressionList{GetImageExpression(inst)});
+            auto* result_type = parser_impl_.ConvertType(inst.type_id());
+            // The SPIR-V result type must be integer scalar. The WGSL bulitin
+            // returns i32. If they aren't the same then convert the result.
+            if (!result_type->Is<I32>()) {
+                ast_expr = builder_.Construct(Source{}, result_type->Build(builder_),
+                                              ast::ExpressionList{ast_expr});
+            }
+            TypedExpression expr{result_type, ast_expr};
+            return EmitConstDefOrWriteToHoistedVar(inst, expr);
+        }
+        default:
+            break;
     }
-    case SpvOpImageQueryLod:
-      return Fail() << "WGSL does not support querying the level of detail of "
-                       "an image: "
-                    << inst.PrettyPrint();
-    case SpvOpImageQueryLevels:
-    case SpvOpImageQuerySamples: {
-      const auto* name = (opcode == SpvOpImageQueryLevels)
-                             ? "textureNumLevels"
-                             : "textureNumSamples";
-      auto* levels_ident = create<ast::IdentifierExpression>(
-          Source{}, builder_.Symbols().Register(name));
-      const ast::Expression* ast_expr = create<ast::CallExpression>(
-          Source{}, levels_ident,
-          ast::ExpressionList{GetImageExpression(inst)});
-      auto* result_type = parser_impl_.ConvertType(inst.type_id());
-      // The SPIR-V result type must be integer scalar. The WGSL bulitin
-      // returns i32. If they aren't the same then convert the result.
-      if (!result_type->Is<I32>()) {
-        ast_expr = builder_.Construct(Source{}, result_type->Build(builder_),
-                                      ast::ExpressionList{ast_expr});
-      }
-      TypedExpression expr{result_type, ast_expr};
-      return EmitConstDefOrWriteToHoistedVar(inst, expr);
-    }
-    default:
-      break;
-  }
-  return Fail() << "unhandled image query: " << inst.PrettyPrint();
+    return Fail() << "unhandled image query: " << inst.PrettyPrint();
 }
 
 ast::ExpressionList FunctionEmitter::MakeCoordinateOperandsForImageAccess(
     const spvtools::opt::Instruction& inst) {
-  if (!parser_impl_.success()) {
-    Fail();
-    return {};
-  }
-  const spvtools::opt::Instruction* image = GetImage(inst);
-  if (!image) {
-    return {};
-  }
-  if (inst.NumInOperands() < 1) {
-    Fail() << "image access is missing a coordinate parameter: "
-           << inst.PrettyPrint();
-    return {};
-  }
+    if (!parser_impl_.success()) {
+        Fail();
+        return {};
+    }
+    const spvtools::opt::Instruction* image = GetImage(inst);
+    if (!image) {
+        return {};
+    }
+    if (inst.NumInOperands() < 1) {
+        Fail() << "image access is missing a coordinate parameter: " << inst.PrettyPrint();
+        return {};
+    }
 
-  // In SPIR-V for Shader, coordinates are:
-  //  - floating point for sampling, dref sampling, gather, dref gather
-  //  - integral for fetch, read, write
-  // In WGSL:
-  //  - floating point for sampling, dref sampling, gather, dref gather
-  //  - signed integral for textureLoad, textureStore
-  //
-  // The only conversions we have to do for WGSL are:
-  //  - When the coordinates are unsigned integral, convert them to signed.
-  //  - Array index is always i32
+    // In SPIR-V for Shader, coordinates are:
+    //  - floating point for sampling, dref sampling, gather, dref gather
+    //  - integral for fetch, read, write
+    // In WGSL:
+    //  - floating point for sampling, dref sampling, gather, dref gather
+    //  - signed integral for textureLoad, textureStore
+    //
+    // The only conversions we have to do for WGSL are:
+    //  - When the coordinates are unsigned integral, convert them to signed.
+    //  - Array index is always i32
 
-  // The coordinates parameter is always in position 1.
-  TypedExpression raw_coords(MakeOperand(inst, 1));
-  if (!raw_coords) {
-    return {};
-  }
-  const Texture* texture_type = GetImageType(*image);
-  if (!texture_type) {
-    return {};
-  }
-  ast::TextureDimension dim = texture_type->dims;
-  // Number of regular coordinates.
-  uint32_t num_axes = ast::NumCoordinateAxes(dim);
-  bool is_arrayed = ast::IsTextureArray(dim);
-  if ((num_axes == 0) || (num_axes > 3)) {
-    Fail() << "unsupported image dimensionality for "
-           << texture_type->TypeInfo().name << " prompted by "
-           << inst.PrettyPrint();
-  }
-  bool is_proj = false;
-  switch (inst.opcode()) {
-    case SpvOpImageSampleProjImplicitLod:
-    case SpvOpImageSampleProjExplicitLod:
-    case SpvOpImageSampleProjDrefImplicitLod:
-    case SpvOpImageSampleProjDrefExplicitLod:
-      is_proj = true;
-      break;
-    default:
-      break;
-  }
+    // The coordinates parameter is always in position 1.
+    TypedExpression raw_coords(MakeOperand(inst, 1));
+    if (!raw_coords) {
+        return {};
+    }
+    const Texture* texture_type = GetImageType(*image);
+    if (!texture_type) {
+        return {};
+    }
+    ast::TextureDimension dim = texture_type->dims;
+    // Number of regular coordinates.
+    uint32_t num_axes = ast::NumCoordinateAxes(dim);
+    bool is_arrayed = ast::IsTextureArray(dim);
+    if ((num_axes == 0) || (num_axes > 3)) {
+        Fail() << "unsupported image dimensionality for " << texture_type->TypeInfo().name
+               << " prompted by " << inst.PrettyPrint();
+    }
+    bool is_proj = false;
+    switch (inst.opcode()) {
+        case SpvOpImageSampleProjImplicitLod:
+        case SpvOpImageSampleProjExplicitLod:
+        case SpvOpImageSampleProjDrefImplicitLod:
+        case SpvOpImageSampleProjDrefExplicitLod:
+            is_proj = true;
+            break;
+        default:
+            break;
+    }
 
-  const auto num_coords_required =
-      num_axes + (is_arrayed ? 1 : 0) + (is_proj ? 1 : 0);
-  uint32_t num_coords_supplied = 0;
-  auto* component_type = raw_coords.type;
-  if (component_type->IsFloatScalar() || component_type->IsIntegerScalar()) {
-    num_coords_supplied = 1;
-  } else if (auto* vec_type = As<Vector>(raw_coords.type)) {
-    component_type = vec_type->type;
-    num_coords_supplied = vec_type->size;
-  }
-  if (num_coords_supplied == 0) {
-    Fail() << "bad or unsupported coordinate type for image access: "
-           << inst.PrettyPrint();
-    return {};
-  }
-  if (num_coords_required > num_coords_supplied) {
-    Fail() << "image access required " << num_coords_required
-           << " coordinate components, but only " << num_coords_supplied
-           << " provided, in: " << inst.PrettyPrint();
-    return {};
-  }
+    const auto num_coords_required = num_axes + (is_arrayed ? 1 : 0) + (is_proj ? 1 : 0);
+    uint32_t num_coords_supplied = 0;
+    auto* component_type = raw_coords.type;
+    if (component_type->IsFloatScalar() || component_type->IsIntegerScalar()) {
+        num_coords_supplied = 1;
+    } else if (auto* vec_type = As<Vector>(raw_coords.type)) {
+        component_type = vec_type->type;
+        num_coords_supplied = vec_type->size;
+    }
+    if (num_coords_supplied == 0) {
+        Fail() << "bad or unsupported coordinate type for image access: " << inst.PrettyPrint();
+        return {};
+    }
+    if (num_coords_required > num_coords_supplied) {
+        Fail() << "image access required " << num_coords_required
+               << " coordinate components, but only " << num_coords_supplied
+               << " provided, in: " << inst.PrettyPrint();
+        return {};
+    }
 
-  ast::ExpressionList result;
+    ast::ExpressionList result;
 
-  // Generates the expression for the WGSL coordinates, when it is a prefix
-  // swizzle with num_axes.  If the result would be unsigned, also converts
-  // it to a signed value of the same shape (scalar or vector).
-  // Use a lambda to make it easy to only generate the expressions when we
-  // will actually use them.
-  auto prefix_swizzle_expr = [this, num_axes, component_type, is_proj,
-                              raw_coords]() -> const ast::Expression* {
-    auto* swizzle_type =
-        (num_axes == 1) ? component_type : ty_.Vector(component_type, num_axes);
-    auto* swizzle = create<ast::MemberAccessorExpression>(
-        Source{}, raw_coords.expr, PrefixSwizzle(num_axes));
-    if (is_proj) {
-      auto* q = create<ast::MemberAccessorExpression>(Source{}, raw_coords.expr,
-                                                      Swizzle(num_axes));
-      auto* proj_div = builder_.Div(swizzle, q);
-      return ToSignedIfUnsigned({swizzle_type, proj_div}).expr;
+    // Generates the expression for the WGSL coordinates, when it is a prefix
+    // swizzle with num_axes.  If the result would be unsigned, also converts
+    // it to a signed value of the same shape (scalar or vector).
+    // Use a lambda to make it easy to only generate the expressions when we
+    // will actually use them.
+    auto prefix_swizzle_expr = [this, num_axes, component_type, is_proj,
+                                raw_coords]() -> const ast::Expression* {
+        auto* swizzle_type =
+            (num_axes == 1) ? component_type : ty_.Vector(component_type, num_axes);
+        auto* swizzle = create<ast::MemberAccessorExpression>(Source{}, raw_coords.expr,
+                                                              PrefixSwizzle(num_axes));
+        if (is_proj) {
+            auto* q =
+                create<ast::MemberAccessorExpression>(Source{}, raw_coords.expr, Swizzle(num_axes));
+            auto* proj_div = builder_.Div(swizzle, q);
+            return ToSignedIfUnsigned({swizzle_type, proj_div}).expr;
+        } else {
+            return ToSignedIfUnsigned({swizzle_type, swizzle}).expr;
+        }
+    };
+
+    if (is_arrayed) {
+        // The source must be a vector. It has at least one coordinate component
+        // and it must have an array component.  Use a vector swizzle to get the
+        // first `num_axes` components.
+        result.push_back(prefix_swizzle_expr());
+
+        // Now get the array index.
+        const ast::Expression* array_index =
+            builder_.MemberAccessor(raw_coords.expr, Swizzle(num_axes));
+        if (component_type->IsFloatScalar()) {
+            // When converting from a float array layer to integer, Vulkan requires
+            // round-to-nearest, with preference for round-to-nearest-even.
+            // But i32(f32) in WGSL has unspecified rounding mode, so we have to
+            // explicitly specify the rounding.
+            array_index = builder_.Call("round", array_index);
+        }
+        // Convert it to a signed integer type, if needed.
+        result.push_back(ToI32({component_type, array_index}).expr);
     } else {
-      return ToSignedIfUnsigned({swizzle_type, swizzle}).expr;
+        if (num_coords_supplied == num_coords_required && !is_proj) {
+            // Pass the value through, with possible unsigned->signed conversion.
+            result.push_back(ToSignedIfUnsigned(raw_coords).expr);
+        } else {
+            // There are more coordinates supplied than needed. So the source type
+            // is a vector. Use a vector swizzle to get the first `num_axes`
+            // components.
+            result.push_back(prefix_swizzle_expr());
+        }
     }
-  };
-
-  if (is_arrayed) {
-    // The source must be a vector. It has at least one coordinate component
-    // and it must have an array component.  Use a vector swizzle to get the
-    // first `num_axes` components.
-    result.push_back(prefix_swizzle_expr());
-
-    // Now get the array index.
-    const ast::Expression* array_index =
-        builder_.MemberAccessor(raw_coords.expr, Swizzle(num_axes));
-    if (component_type->IsFloatScalar()) {
-      // When converting from a float array layer to integer, Vulkan requires
-      // round-to-nearest, with preference for round-to-nearest-even.
-      // But i32(f32) in WGSL has unspecified rounding mode, so we have to
-      // explicitly specify the rounding.
-      array_index = builder_.Call("round", array_index);
-    }
-    // Convert it to a signed integer type, if needed.
-    result.push_back(ToI32({component_type, array_index}).expr);
-  } else {
-    if (num_coords_supplied == num_coords_required && !is_proj) {
-      // Pass the value through, with possible unsigned->signed conversion.
-      result.push_back(ToSignedIfUnsigned(raw_coords).expr);
-    } else {
-      // There are more coordinates supplied than needed. So the source type
-      // is a vector. Use a vector swizzle to get the first `num_axes`
-      // components.
-      result.push_back(prefix_swizzle_expr());
-    }
-  }
-  return result;
+    return result;
 }
 
 const ast::Expression* FunctionEmitter::ConvertTexelForStorage(
     const spvtools::opt::Instruction& inst,
     TypedExpression texel,
     const Texture* texture_type) {
-  auto* storage_texture_type = As<StorageTexture>(texture_type);
-  auto* src_type = texel.type;
-  if (!storage_texture_type) {
-    Fail() << "writing to other than storage texture: " << inst.PrettyPrint();
-    return nullptr;
-  }
-  const auto format = storage_texture_type->format;
-  auto* dest_type = parser_impl_.GetTexelTypeForFormat(format);
-  if (!dest_type) {
-    Fail();
-    return nullptr;
-  }
-
-  // The texel type is always a 4-element vector.
-  const uint32_t dest_count = 4u;
-  TINT_ASSERT(Reader, dest_type->Is<Vector>() &&
-                          dest_type->As<Vector>()->size == dest_count);
-  TINT_ASSERT(Reader, dest_type->IsFloatVector() ||
-                          dest_type->IsUnsignedIntegerVector() ||
-                          dest_type->IsSignedIntegerVector());
-
-  if (src_type == dest_type) {
-    return texel.expr;
-  }
-
-  // Component type must match floatness, or integral signedness.
-  if ((src_type->IsFloatScalarOrVector() != dest_type->IsFloatVector()) ||
-      (src_type->IsUnsignedIntegerVector() !=
-       dest_type->IsUnsignedIntegerVector()) ||
-      (src_type->IsSignedIntegerVector() !=
-       dest_type->IsSignedIntegerVector())) {
-    Fail() << "invalid texel type for storage texture write: component must be "
-              "float, signed integer, or unsigned integer "
-              "to match the texture channel type: "
-           << inst.PrettyPrint();
-    return nullptr;
-  }
-
-  const auto required_count = parser_impl_.GetChannelCountForFormat(format);
-  TINT_ASSERT(Reader, 0 < required_count && required_count <= 4);
-
-  const uint32_t src_count =
-      src_type->IsScalar() ? 1 : src_type->As<Vector>()->size;
-  if (src_count < required_count) {
-    Fail() << "texel has too few components for storage texture: " << src_count
-           << " provided but " << required_count
-           << " required, in: " << inst.PrettyPrint();
-    return nullptr;
-  }
-
-  // It's valid for required_count < src_count. The extra components will
-  // be written out but the textureStore will ignore them.
-
-  if (src_count < dest_count) {
-    // Expand the texel to a 4 element vector.
-    auto* component_type =
-        texel.type->IsScalar() ? texel.type : texel.type->As<Vector>()->type;
-    texel.type = ty_.Vector(component_type, dest_count);
-    ast::ExpressionList exprs;
-    exprs.push_back(texel.expr);
-    for (auto i = src_count; i < dest_count; i++) {
-      exprs.push_back(parser_impl_.MakeNullExpression(component_type).expr);
+    auto* storage_texture_type = As<StorageTexture>(texture_type);
+    auto* src_type = texel.type;
+    if (!storage_texture_type) {
+        Fail() << "writing to other than storage texture: " << inst.PrettyPrint();
+        return nullptr;
     }
-    texel.expr = builder_.Construct(Source{}, texel.type->Build(builder_),
-                                    std::move(exprs));
-  }
+    const auto format = storage_texture_type->format;
+    auto* dest_type = parser_impl_.GetTexelTypeForFormat(format);
+    if (!dest_type) {
+        Fail();
+        return nullptr;
+    }
 
-  return texel.expr;
+    // The texel type is always a 4-element vector.
+    const uint32_t dest_count = 4u;
+    TINT_ASSERT(Reader, dest_type->Is<Vector>() && dest_type->As<Vector>()->size == dest_count);
+    TINT_ASSERT(Reader, dest_type->IsFloatVector() || dest_type->IsUnsignedIntegerVector() ||
+                            dest_type->IsSignedIntegerVector());
+
+    if (src_type == dest_type) {
+        return texel.expr;
+    }
+
+    // Component type must match floatness, or integral signedness.
+    if ((src_type->IsFloatScalarOrVector() != dest_type->IsFloatVector()) ||
+        (src_type->IsUnsignedIntegerVector() != dest_type->IsUnsignedIntegerVector()) ||
+        (src_type->IsSignedIntegerVector() != dest_type->IsSignedIntegerVector())) {
+        Fail() << "invalid texel type for storage texture write: component must be "
+                  "float, signed integer, or unsigned integer "
+                  "to match the texture channel type: "
+               << inst.PrettyPrint();
+        return nullptr;
+    }
+
+    const auto required_count = parser_impl_.GetChannelCountForFormat(format);
+    TINT_ASSERT(Reader, 0 < required_count && required_count <= 4);
+
+    const uint32_t src_count = src_type->IsScalar() ? 1 : src_type->As<Vector>()->size;
+    if (src_count < required_count) {
+        Fail() << "texel has too few components for storage texture: " << src_count
+               << " provided but " << required_count << " required, in: " << inst.PrettyPrint();
+        return nullptr;
+    }
+
+    // It's valid for required_count < src_count. The extra components will
+    // be written out but the textureStore will ignore them.
+
+    if (src_count < dest_count) {
+        // Expand the texel to a 4 element vector.
+        auto* component_type = texel.type->IsScalar() ? texel.type : texel.type->As<Vector>()->type;
+        texel.type = ty_.Vector(component_type, dest_count);
+        ast::ExpressionList exprs;
+        exprs.push_back(texel.expr);
+        for (auto i = src_count; i < dest_count; i++) {
+            exprs.push_back(parser_impl_.MakeNullExpression(component_type).expr);
+        }
+        texel.expr = builder_.Construct(Source{}, texel.type->Build(builder_), std::move(exprs));
+    }
+
+    return texel.expr;
 }
 
 TypedExpression FunctionEmitter::ToI32(TypedExpression value) {
-  if (!value || value.type->Is<I32>()) {
-    return value;
-  }
-  return {ty_.I32(), builder_.Construct(Source{}, builder_.ty.i32(),
-                                        ast::ExpressionList{value.expr})};
+    if (!value || value.type->Is<I32>()) {
+        return value;
+    }
+    return {ty_.I32(),
+            builder_.Construct(Source{}, builder_.ty.i32(), ast::ExpressionList{value.expr})};
 }
 
 TypedExpression FunctionEmitter::ToSignedIfUnsigned(TypedExpression value) {
-  if (!value || !value.type->IsUnsignedScalarOrVector()) {
-    return value;
-  }
-  if (auto* vec_type = value.type->As<Vector>()) {
-    auto* new_type = ty_.Vector(ty_.I32(), vec_type->size);
-    return {new_type, builder_.Construct(new_type->Build(builder_),
-                                         ast::ExpressionList{value.expr})};
-  }
-  return ToI32(value);
-}
-
-TypedExpression FunctionEmitter::MakeArrayLength(
-    const spvtools::opt::Instruction& inst) {
-  if (inst.NumInOperands() != 2) {
-    // Binary parsing will fail on this anyway.
-    Fail() << "invalid array length: requires 2 operands: "
-           << inst.PrettyPrint();
-    return {};
-  }
-  const auto struct_ptr_id = inst.GetSingleWordInOperand(0);
-  const auto field_index = inst.GetSingleWordInOperand(1);
-  const auto struct_ptr_type_id =
-      def_use_mgr_->GetDef(struct_ptr_id)->type_id();
-  // Trace through the pointer type to get to the struct type.
-  const auto struct_type_id =
-      def_use_mgr_->GetDef(struct_ptr_type_id)->GetSingleWordInOperand(1);
-  const auto field_name = namer_.GetMemberName(struct_type_id, field_index);
-  if (field_name.empty()) {
-    Fail() << "struct index out of bounds for array length: "
-           << inst.PrettyPrint();
-    return {};
-  }
-
-  auto member_expr = MakeExpression(struct_ptr_id);
-  if (!member_expr) {
-    return {};
-  }
-  if (member_expr.type->Is<Pointer>()) {
-    member_expr = Dereference(member_expr);
-  }
-  auto* member_ident = create<ast::IdentifierExpression>(
-      Source{}, builder_.Symbols().Register(field_name));
-  auto* member_access = create<ast::MemberAccessorExpression>(
-      Source{}, member_expr.expr, member_ident);
-
-  // Generate the builtin function call.
-  auto* call_expr =
-      builder_.Call(Source{}, "arrayLength", builder_.AddressOf(member_access));
-
-  return {parser_impl_.ConvertType(inst.type_id()), call_expr};
-}
-
-TypedExpression FunctionEmitter::MakeOuterProduct(
-    const spvtools::opt::Instruction& inst) {
-  // Synthesize the result.
-  auto col = MakeOperand(inst, 0);
-  auto row = MakeOperand(inst, 1);
-  auto* col_ty = As<Vector>(col.type);
-  auto* row_ty = As<Vector>(row.type);
-  auto* result_ty = As<Matrix>(parser_impl_.ConvertType(inst.type_id()));
-  if (!col_ty || !col_ty || !result_ty || result_ty->type != col_ty->type ||
-      result_ty->type != row_ty->type || result_ty->columns != row_ty->size ||
-      result_ty->rows != col_ty->size) {
-    Fail() << "invalid outer product instruction: bad types "
-           << inst.PrettyPrint();
-    return {};
-  }
-
-  // Example:
-  //    c : vec3 column vector
-  //    r : vec2 row vector
-  //    OuterProduct c r : mat2x3 (2 columns, 3 rows)
-  //    Result:
-  //      | c.x * r.x   c.x * r.y |
-  //      | c.y * r.x   c.y * r.y |
-  //      | c.z * r.x   c.z * r.y |
-
-  ast::ExpressionList result_columns;
-  for (uint32_t icol = 0; icol < result_ty->columns; icol++) {
-    ast::ExpressionList result_row;
-    auto* row_factor = create<ast::MemberAccessorExpression>(Source{}, row.expr,
-                                                             Swizzle(icol));
-    for (uint32_t irow = 0; irow < result_ty->rows; irow++) {
-      auto* column_factor = create<ast::MemberAccessorExpression>(
-          Source{}, col.expr, Swizzle(irow));
-      auto* elem = create<ast::BinaryExpression>(
-          Source{}, ast::BinaryOp::kMultiply, row_factor, column_factor);
-      result_row.push_back(elem);
+    if (!value || !value.type->IsUnsignedScalarOrVector()) {
+        return value;
     }
-    result_columns.push_back(
-        builder_.Construct(Source{}, col_ty->Build(builder_), result_row));
-  }
-  return {result_ty, builder_.Construct(Source{}, result_ty->Build(builder_),
-                                        result_columns)};
+    if (auto* vec_type = value.type->As<Vector>()) {
+        auto* new_type = ty_.Vector(ty_.I32(), vec_type->size);
+        return {new_type,
+                builder_.Construct(new_type->Build(builder_), ast::ExpressionList{value.expr})};
+    }
+    return ToI32(value);
 }
 
-bool FunctionEmitter::MakeVectorInsertDynamic(
-    const spvtools::opt::Instruction& inst) {
-  // For
-  //    %result = OpVectorInsertDynamic %type %src_vector %component %index
-  // there are two cases.
-  //
-  // Case 1:
-  //   The %src_vector value has already been hoisted into a variable.
-  //   In this case, assign %src_vector to that variable, then write the
-  //   component into the right spot:
-  //
-  //    hoisted = src_vector;
-  //    hoisted[index] = component;
-  //
-  // Case 2:
-  //   The %src_vector value is not hoisted. In this case, make a temporary
-  //   variable with the %src_vector contents, then write the component,
-  //   and then make a let-declaration that reads the value out:
-  //
-  //    var temp : type = src_vector;
-  //    temp[index] = component;
-  //    let result : type = temp;
-  //
-  //   Then use result everywhere the original SPIR-V id is used.  Using a const
-  //   like this avoids constantly reloading the value many times.
+TypedExpression FunctionEmitter::MakeArrayLength(const spvtools::opt::Instruction& inst) {
+    if (inst.NumInOperands() != 2) {
+        // Binary parsing will fail on this anyway.
+        Fail() << "invalid array length: requires 2 operands: " << inst.PrettyPrint();
+        return {};
+    }
+    const auto struct_ptr_id = inst.GetSingleWordInOperand(0);
+    const auto field_index = inst.GetSingleWordInOperand(1);
+    const auto struct_ptr_type_id = def_use_mgr_->GetDef(struct_ptr_id)->type_id();
+    // Trace through the pointer type to get to the struct type.
+    const auto struct_type_id = def_use_mgr_->GetDef(struct_ptr_type_id)->GetSingleWordInOperand(1);
+    const auto field_name = namer_.GetMemberName(struct_type_id, field_index);
+    if (field_name.empty()) {
+        Fail() << "struct index out of bounds for array length: " << inst.PrettyPrint();
+        return {};
+    }
 
-  auto* type = parser_impl_.ConvertType(inst.type_id());
-  auto src_vector = MakeOperand(inst, 0);
-  auto component = MakeOperand(inst, 1);
-  auto index = MakeOperand(inst, 2);
+    auto member_expr = MakeExpression(struct_ptr_id);
+    if (!member_expr) {
+        return {};
+    }
+    if (member_expr.type->Is<Pointer>()) {
+        member_expr = Dereference(member_expr);
+    }
+    auto* member_ident =
+        create<ast::IdentifierExpression>(Source{}, builder_.Symbols().Register(field_name));
+    auto* member_access =
+        create<ast::MemberAccessorExpression>(Source{}, member_expr.expr, member_ident);
 
-  std::string var_name;
-  auto original_value_name = namer_.Name(inst.result_id());
-  const bool hoisted = WriteIfHoistedVar(inst, src_vector);
-  if (hoisted) {
-    // The variable was already declared in an earlier block.
-    var_name = original_value_name;
-    // Assign the source vector value to it.
-    builder_.Assign({}, builder_.Expr(var_name), src_vector.expr);
-  } else {
-    // Synthesize the temporary variable.
-    // It doesn't correspond to a SPIR-V ID, so we don't use the ordinary
-    // API in parser_impl_.
-    var_name = namer_.MakeDerivedName(original_value_name);
+    // Generate the builtin function call.
+    auto* call_expr = builder_.Call(Source{}, "arrayLength", builder_.AddressOf(member_access));
 
-    auto* temp_var = builder_.Var(var_name, type->Build(builder_),
-                                  ast::StorageClass::kNone, src_vector.expr);
-
-    AddStatement(builder_.Decl({}, temp_var));
-  }
-
-  auto* lhs = create<ast::IndexAccessorExpression>(
-      Source{}, builder_.Expr(var_name), index.expr);
-  if (!lhs) {
-    return false;
-  }
-
-  AddStatement(builder_.Assign(lhs, component.expr));
-
-  if (hoisted) {
-    // The hoisted variable itself stands for this result ID.
-    return success();
-  }
-  // Create a new let-declaration that is initialized by the contents
-  // of the temporary variable.
-  return EmitConstDefinition(inst, {type, builder_.Expr(var_name)});
+    return {parser_impl_.ConvertType(inst.type_id()), call_expr};
 }
 
-bool FunctionEmitter::MakeCompositeInsert(
-    const spvtools::opt::Instruction& inst) {
-  // For
-  //    %result = OpCompositeInsert %type %object %composite 1 2 3 ...
-  // there are two cases.
-  //
-  // Case 1:
-  //   The %composite value has already been hoisted into a variable.
-  //   In this case, assign %composite to that variable, then write the
-  //   component into the right spot:
-  //
-  //    hoisted = composite;
-  //    hoisted[index].x = object;
-  //
-  // Case 2:
-  //   The %composite value is not hoisted. In this case, make a temporary
-  //   variable with the %composite contents, then write the component,
-  //   and then make a let-declaration that reads the value out:
-  //
-  //    var temp : type = composite;
-  //    temp[index].x = object;
-  //    let result : type = temp;
-  //
-  //   Then use result everywhere the original SPIR-V id is used.  Using a const
-  //   like this avoids constantly reloading the value many times.
-  //
-  //   This technique is a combination of:
-  //   - making a temporary variable and constant declaration, like what we do
-  //     for VectorInsertDynamic, and
-  //   - building up an access-chain like access like for CompositeExtract, but
-  //     on the left-hand side of the assignment.
+TypedExpression FunctionEmitter::MakeOuterProduct(const spvtools::opt::Instruction& inst) {
+    // Synthesize the result.
+    auto col = MakeOperand(inst, 0);
+    auto row = MakeOperand(inst, 1);
+    auto* col_ty = As<Vector>(col.type);
+    auto* row_ty = As<Vector>(row.type);
+    auto* result_ty = As<Matrix>(parser_impl_.ConvertType(inst.type_id()));
+    if (!col_ty || !col_ty || !result_ty || result_ty->type != col_ty->type ||
+        result_ty->type != row_ty->type || result_ty->columns != row_ty->size ||
+        result_ty->rows != col_ty->size) {
+        Fail() << "invalid outer product instruction: bad types " << inst.PrettyPrint();
+        return {};
+    }
 
-  auto* type = parser_impl_.ConvertType(inst.type_id());
-  auto component = MakeOperand(inst, 0);
-  auto src_composite = MakeOperand(inst, 1);
+    // Example:
+    //    c : vec3 column vector
+    //    r : vec2 row vector
+    //    OuterProduct c r : mat2x3 (2 columns, 3 rows)
+    //    Result:
+    //      | c.x * r.x   c.x * r.y |
+    //      | c.y * r.x   c.y * r.y |
+    //      | c.z * r.x   c.z * r.y |
 
-  std::string var_name;
-  auto original_value_name = namer_.Name(inst.result_id());
-  const bool hoisted = WriteIfHoistedVar(inst, src_composite);
-  if (hoisted) {
-    // The variable was already declared in an earlier block.
-    var_name = original_value_name;
-    // Assign the source composite value to it.
-    builder_.Assign({}, builder_.Expr(var_name), src_composite.expr);
-  } else {
-    // Synthesize a temporary variable.
-    // It doesn't correspond to a SPIR-V ID, so we don't use the ordinary
-    // API in parser_impl_.
-    var_name = namer_.MakeDerivedName(original_value_name);
-    auto* temp_var = builder_.Var(var_name, type->Build(builder_),
-                                  ast::StorageClass::kNone, src_composite.expr);
-    AddStatement(builder_.Decl({}, temp_var));
-  }
+    ast::ExpressionList result_columns;
+    for (uint32_t icol = 0; icol < result_ty->columns; icol++) {
+        ast::ExpressionList result_row;
+        auto* row_factor = create<ast::MemberAccessorExpression>(Source{}, row.expr, Swizzle(icol));
+        for (uint32_t irow = 0; irow < result_ty->rows; irow++) {
+            auto* column_factor =
+                create<ast::MemberAccessorExpression>(Source{}, col.expr, Swizzle(irow));
+            auto* elem = create<ast::BinaryExpression>(Source{}, ast::BinaryOp::kMultiply,
+                                                       row_factor, column_factor);
+            result_row.push_back(elem);
+        }
+        result_columns.push_back(builder_.Construct(Source{}, col_ty->Build(builder_), result_row));
+    }
+    return {result_ty, builder_.Construct(Source{}, result_ty->Build(builder_), result_columns)};
+}
 
-  TypedExpression seed_expr{type, builder_.Expr(var_name)};
+bool FunctionEmitter::MakeVectorInsertDynamic(const spvtools::opt::Instruction& inst) {
+    // For
+    //    %result = OpVectorInsertDynamic %type %src_vector %component %index
+    // there are two cases.
+    //
+    // Case 1:
+    //   The %src_vector value has already been hoisted into a variable.
+    //   In this case, assign %src_vector to that variable, then write the
+    //   component into the right spot:
+    //
+    //    hoisted = src_vector;
+    //    hoisted[index] = component;
+    //
+    // Case 2:
+    //   The %src_vector value is not hoisted. In this case, make a temporary
+    //   variable with the %src_vector contents, then write the component,
+    //   and then make a let-declaration that reads the value out:
+    //
+    //    var temp : type = src_vector;
+    //    temp[index] = component;
+    //    let result : type = temp;
+    //
+    //   Then use result everywhere the original SPIR-V id is used.  Using a const
+    //   like this avoids constantly reloading the value many times.
 
-  // The left-hand side of the assignment *looks* like a decomposition.
-  TypedExpression lhs =
-      MakeCompositeValueDecomposition(inst, seed_expr, inst.type_id(), 2);
-  if (!lhs) {
-    return false;
-  }
+    auto* type = parser_impl_.ConvertType(inst.type_id());
+    auto src_vector = MakeOperand(inst, 0);
+    auto component = MakeOperand(inst, 1);
+    auto index = MakeOperand(inst, 2);
 
-  AddStatement(builder_.Assign(lhs.expr, component.expr));
+    std::string var_name;
+    auto original_value_name = namer_.Name(inst.result_id());
+    const bool hoisted = WriteIfHoistedVar(inst, src_vector);
+    if (hoisted) {
+        // The variable was already declared in an earlier block.
+        var_name = original_value_name;
+        // Assign the source vector value to it.
+        builder_.Assign({}, builder_.Expr(var_name), src_vector.expr);
+    } else {
+        // Synthesize the temporary variable.
+        // It doesn't correspond to a SPIR-V ID, so we don't use the ordinary
+        // API in parser_impl_.
+        var_name = namer_.MakeDerivedName(original_value_name);
 
-  if (hoisted) {
-    // The hoisted variable itself stands for this result ID.
-    return success();
-  }
-  // Create a new let-declaration that is initialized by the contents
-  // of the temporary variable.
-  return EmitConstDefinition(inst, {type, builder_.Expr(var_name)});
+        auto* temp_var = builder_.Var(var_name, type->Build(builder_), ast::StorageClass::kNone,
+                                      src_vector.expr);
+
+        AddStatement(builder_.Decl({}, temp_var));
+    }
+
+    auto* lhs = create<ast::IndexAccessorExpression>(Source{}, builder_.Expr(var_name), index.expr);
+    if (!lhs) {
+        return false;
+    }
+
+    AddStatement(builder_.Assign(lhs, component.expr));
+
+    if (hoisted) {
+        // The hoisted variable itself stands for this result ID.
+        return success();
+    }
+    // Create a new let-declaration that is initialized by the contents
+    // of the temporary variable.
+    return EmitConstDefinition(inst, {type, builder_.Expr(var_name)});
+}
+
+bool FunctionEmitter::MakeCompositeInsert(const spvtools::opt::Instruction& inst) {
+    // For
+    //    %result = OpCompositeInsert %type %object %composite 1 2 3 ...
+    // there are two cases.
+    //
+    // Case 1:
+    //   The %composite value has already been hoisted into a variable.
+    //   In this case, assign %composite to that variable, then write the
+    //   component into the right spot:
+    //
+    //    hoisted = composite;
+    //    hoisted[index].x = object;
+    //
+    // Case 2:
+    //   The %composite value is not hoisted. In this case, make a temporary
+    //   variable with the %composite contents, then write the component,
+    //   and then make a let-declaration that reads the value out:
+    //
+    //    var temp : type = composite;
+    //    temp[index].x = object;
+    //    let result : type = temp;
+    //
+    //   Then use result everywhere the original SPIR-V id is used.  Using a const
+    //   like this avoids constantly reloading the value many times.
+    //
+    //   This technique is a combination of:
+    //   - making a temporary variable and constant declaration, like what we do
+    //     for VectorInsertDynamic, and
+    //   - building up an access-chain like access like for CompositeExtract, but
+    //     on the left-hand side of the assignment.
+
+    auto* type = parser_impl_.ConvertType(inst.type_id());
+    auto component = MakeOperand(inst, 0);
+    auto src_composite = MakeOperand(inst, 1);
+
+    std::string var_name;
+    auto original_value_name = namer_.Name(inst.result_id());
+    const bool hoisted = WriteIfHoistedVar(inst, src_composite);
+    if (hoisted) {
+        // The variable was already declared in an earlier block.
+        var_name = original_value_name;
+        // Assign the source composite value to it.
+        builder_.Assign({}, builder_.Expr(var_name), src_composite.expr);
+    } else {
+        // Synthesize a temporary variable.
+        // It doesn't correspond to a SPIR-V ID, so we don't use the ordinary
+        // API in parser_impl_.
+        var_name = namer_.MakeDerivedName(original_value_name);
+        auto* temp_var = builder_.Var(var_name, type->Build(builder_), ast::StorageClass::kNone,
+                                      src_composite.expr);
+        AddStatement(builder_.Decl({}, temp_var));
+    }
+
+    TypedExpression seed_expr{type, builder_.Expr(var_name)};
+
+    // The left-hand side of the assignment *looks* like a decomposition.
+    TypedExpression lhs = MakeCompositeValueDecomposition(inst, seed_expr, inst.type_id(), 2);
+    if (!lhs) {
+        return false;
+    }
+
+    AddStatement(builder_.Assign(lhs.expr, component.expr));
+
+    if (hoisted) {
+        // The hoisted variable itself stands for this result ID.
+        return success();
+    }
+    // Create a new let-declaration that is initialized by the contents
+    // of the temporary variable.
+    return EmitConstDefinition(inst, {type, builder_.Expr(var_name)});
 }
 
 TypedExpression FunctionEmitter::AddressOf(TypedExpression expr) {
-  auto* ref = expr.type->As<Reference>();
-  if (!ref) {
-    Fail() << "AddressOf() called on non-reference type";
-    return {};
-  }
-  return {
-      ty_.Pointer(ref->type, ref->storage_class),
-      create<ast::UnaryOpExpression>(Source{}, ast::UnaryOp::kAddressOf,
-                                     expr.expr),
-  };
+    auto* ref = expr.type->As<Reference>();
+    if (!ref) {
+        Fail() << "AddressOf() called on non-reference type";
+        return {};
+    }
+    return {
+        ty_.Pointer(ref->type, ref->storage_class),
+        create<ast::UnaryOpExpression>(Source{}, ast::UnaryOp::kAddressOf, expr.expr),
+    };
 }
 
 TypedExpression FunctionEmitter::Dereference(TypedExpression expr) {
-  auto* ptr = expr.type->As<Pointer>();
-  if (!ptr) {
-    Fail() << "Dereference() called on non-pointer type";
-    return {};
-  }
-  return {
-      ptr->type,
-      create<ast::UnaryOpExpression>(Source{}, ast::UnaryOp::kIndirection,
-                                     expr.expr),
-  };
+    auto* ptr = expr.type->As<Pointer>();
+    if (!ptr) {
+        Fail() << "Dereference() called on non-pointer type";
+        return {};
+    }
+    return {
+        ptr->type,
+        create<ast::UnaryOpExpression>(Source{}, ast::UnaryOp::kIndirection, expr.expr),
+    };
 }
 
 bool FunctionEmitter::IsFloatZero(uint32_t value_id) {
-  if (const auto* c = constant_mgr_->FindDeclaredConstant(value_id)) {
-    if (const auto* float_const = c->AsFloatConstant()) {
-      return 0.0f == float_const->GetFloatValue();
+    if (const auto* c = constant_mgr_->FindDeclaredConstant(value_id)) {
+        if (const auto* float_const = c->AsFloatConstant()) {
+            return 0.0f == float_const->GetFloatValue();
+        }
+        if (c->AsNullConstant()) {
+            // Valid SPIR-V requires it to be a float value anyway.
+            return true;
+        }
     }
-    if (c->AsNullConstant()) {
-      // Valid SPIR-V requires it to be a float value anyway.
-      return true;
-    }
-  }
-  return false;
+    return false;
 }
 
 bool FunctionEmitter::IsFloatOne(uint32_t value_id) {
-  if (const auto* c = constant_mgr_->FindDeclaredConstant(value_id)) {
-    if (const auto* float_const = c->AsFloatConstant()) {
-      return 1.0f == float_const->GetFloatValue();
+    if (const auto* c = constant_mgr_->FindDeclaredConstant(value_id)) {
+        if (const auto* float_const = c->AsFloatConstant()) {
+            return 1.0f == float_const->GetFloatValue();
+        }
     }
-  }
-  return false;
+    return false;
 }
 
 FunctionEmitter::FunctionDeclaration::FunctionDeclaration() = default;
diff --git a/src/tint/reader/spirv/function.h b/src/tint/reader/spirv/function.h
index b000370..8eb33ab 100644
--- a/src/tint/reader/spirv/function.h
+++ b/src/tint/reader/spirv/function.h
@@ -43,29 +43,29 @@
 // kLoopBreak, and kLoopContinue directly map to 'break', 'break', and
 // 'continue', respectively.
 enum class EdgeKind {
-  // A back-edge: An edge from a node to one of its ancestors in a depth-first
-  // search from the entry block.
-  kBack,
-  // An edge from a node to the merge block of the nearest enclosing switch,
-  // where there is no intervening loop.
-  kSwitchBreak,
-  // An edge from a node to the merge block of the nearest enclosing loop, where
-  // there is no intervening switch.
-  // The source block is a "break block" as defined by SPIR-V.
-  kLoopBreak,
-  // An edge from a node in a loop body to the associated continue target, where
-  // there are no other intervening loops or switches.
-  // The source block is a "continue block" as defined by SPIR-V.
-  kLoopContinue,
-  // An edge from a node to the merge block of the nearest enclosing structured
-  // construct, but which is neither a kSwitchBreak or a kLoopBreak.
-  // This can only occur for an "if" selection, i.e. where the selection
-  // header ends in OpBranchConditional.
-  kIfBreak,
-  // An edge from one switch case to the next sibling switch case.
-  kCaseFallThrough,
-  // None of the above.
-  kForward
+    // A back-edge: An edge from a node to one of its ancestors in a depth-first
+    // search from the entry block.
+    kBack,
+    // An edge from a node to the merge block of the nearest enclosing switch,
+    // where there is no intervening loop.
+    kSwitchBreak,
+    // An edge from a node to the merge block of the nearest enclosing loop, where
+    // there is no intervening switch.
+    // The source block is a "break block" as defined by SPIR-V.
+    kLoopBreak,
+    // An edge from a node in a loop body to the associated continue target, where
+    // there are no other intervening loops or switches.
+    // The source block is a "continue block" as defined by SPIR-V.
+    kLoopContinue,
+    // An edge from a node to the merge block of the nearest enclosing structured
+    // construct, but which is neither a kSwitchBreak or a kLoopBreak.
+    // This can only occur for an "if" selection, i.e. where the selection
+    // header ends in OpBranchConditional.
+    kIfBreak,
+    // An edge from one switch case to the next sibling switch case.
+    kCaseFallThrough,
+    // None of the above.
+    kForward
 };
 
 /// The number used to represent an invalid block position
@@ -73,107 +73,107 @@
 
 /// Bookkeeping info for a basic block.
 struct BlockInfo {
-  /// Constructor
-  /// @param bb internal representation of the basic block
-  explicit BlockInfo(const spvtools::opt::BasicBlock& bb);
-  ~BlockInfo();
+    /// Constructor
+    /// @param bb internal representation of the basic block
+    explicit BlockInfo(const spvtools::opt::BasicBlock& bb);
+    ~BlockInfo();
 
-  /// The internal representation of the basic block.
-  const spvtools::opt::BasicBlock* basic_block;
+    /// The internal representation of the basic block.
+    const spvtools::opt::BasicBlock* basic_block;
 
-  /// The ID of the OpLabel instruction that starts this block.
-  uint32_t id = 0;
+    /// The ID of the OpLabel instruction that starts this block.
+    uint32_t id = 0;
 
-  /// The position of this block in the reverse structured post-order.
-  /// If the block is not in that order, then this remains the invalid value.
-  uint32_t pos = kInvalidBlockPos;
+    /// The position of this block in the reverse structured post-order.
+    /// If the block is not in that order, then this remains the invalid value.
+    uint32_t pos = kInvalidBlockPos;
 
-  /// If this block is a header, then this is the ID of the merge block.
-  uint32_t merge_for_header = 0;
-  /// If this block is a loop header, then this is the ID of the continue
-  /// target.
-  uint32_t continue_for_header = 0;
-  /// If this block is a merge, then this is the ID of the header.
-  uint32_t header_for_merge = 0;
-  /// If this block is a continue target, then this is the ID of the loop
-  /// header.
-  uint32_t header_for_continue = 0;
-  /// Is this block a continue target which is its own loop header block?
-  /// In this case the continue construct is the entire loop.  The associated
-  /// "loop construct" is empty, and not represented.
-  bool is_continue_entire_loop = false;
+    /// If this block is a header, then this is the ID of the merge block.
+    uint32_t merge_for_header = 0;
+    /// If this block is a loop header, then this is the ID of the continue
+    /// target.
+    uint32_t continue_for_header = 0;
+    /// If this block is a merge, then this is the ID of the header.
+    uint32_t header_for_merge = 0;
+    /// If this block is a continue target, then this is the ID of the loop
+    /// header.
+    uint32_t header_for_continue = 0;
+    /// Is this block a continue target which is its own loop header block?
+    /// In this case the continue construct is the entire loop.  The associated
+    /// "loop construct" is empty, and not represented.
+    bool is_continue_entire_loop = false;
 
-  /// The immediately enclosing structured construct. If this block is not
-  /// in the block order at all, then this is still nullptr.
-  const Construct* construct = nullptr;
+    /// The immediately enclosing structured construct. If this block is not
+    /// in the block order at all, then this is still nullptr.
+    const Construct* construct = nullptr;
 
-  /// Maps the ID of a successor block (in the CFG) to its edge classification.
-  std::unordered_map<uint32_t, EdgeKind> succ_edge;
+    /// Maps the ID of a successor block (in the CFG) to its edge classification.
+    std::unordered_map<uint32_t, EdgeKind> succ_edge;
 
-  /// The following fields record relationships among blocks in a selection
-  /// construct for an OpSwitch instruction.
+    /// The following fields record relationships among blocks in a selection
+    /// construct for an OpSwitch instruction.
 
-  /// If not null, then the pointed-at construct is a selection for an OpSwitch,
-  /// and this block is a case target for it.  We say this block "heads" the
-  /// case construct.
-  const Construct* case_head_for = nullptr;
-  /// If not null, then the pointed-at construct is a selection for an OpSwitch,
-  /// and this block is the default target for it.  We say this block "heads"
-  /// the default case construct.
-  const Construct* default_head_for = nullptr;
-  /// Is this a default target for a switch, and is it also the merge for its
-  /// switch?
-  bool default_is_merge = false;
-  /// The list of switch values that cause a branch to this block.
-  std::unique_ptr<std::vector<uint64_t>> case_values;
+    /// If not null, then the pointed-at construct is a selection for an OpSwitch,
+    /// and this block is a case target for it.  We say this block "heads" the
+    /// case construct.
+    const Construct* case_head_for = nullptr;
+    /// If not null, then the pointed-at construct is a selection for an OpSwitch,
+    /// and this block is the default target for it.  We say this block "heads"
+    /// the default case construct.
+    const Construct* default_head_for = nullptr;
+    /// Is this a default target for a switch, and is it also the merge for its
+    /// switch?
+    bool default_is_merge = false;
+    /// The list of switch values that cause a branch to this block.
+    std::unique_ptr<std::vector<uint64_t>> case_values;
 
-  /// The following fields record relationships among blocks in a selection
-  /// construct for an OpBranchConditional instruction.
+    /// The following fields record relationships among blocks in a selection
+    /// construct for an OpBranchConditional instruction.
 
-  /// When this block is an if-selection header, this is the edge kind
-  /// for the true branch.
-  EdgeKind true_kind = EdgeKind::kForward;
-  /// When this block is an if-selection header, this is the edge kind
-  /// for the false branch.
-  EdgeKind false_kind = EdgeKind::kForward;
-  /// If not 0, then this block is an if-selection header, and `true_head` is
-  /// the target id of the true branch on the OpBranchConditional, and that
-  /// target is inside the if-selection.
-  uint32_t true_head = 0;
-  /// If not 0, then this block is an if-selection header, and `false_head`
-  /// is the target id of the false branch on the OpBranchConditional, and
-  /// that target is inside the if-selection.
-  uint32_t false_head = 0;
-  /// If not 0, then this block is an if-selection header, and when following
-  /// the flow via the true and false branches, control first reconverges at
-  /// the block with ID `premerge_head`, and `premerge_head` is still inside
-  /// the if-selection.
-  uint32_t premerge_head = 0;
-  /// If non-empty, then this block is an if-selection header, and control flow
-  /// in the body must be guarded by a boolean flow variable with this name.
-  /// This occurs when a block in this selection has both an if-break edge, and
-  /// also a different normal forward edge but without a merge instruction.
-  std::string flow_guard_name = "";
+    /// When this block is an if-selection header, this is the edge kind
+    /// for the true branch.
+    EdgeKind true_kind = EdgeKind::kForward;
+    /// When this block is an if-selection header, this is the edge kind
+    /// for the false branch.
+    EdgeKind false_kind = EdgeKind::kForward;
+    /// If not 0, then this block is an if-selection header, and `true_head` is
+    /// the target id of the true branch on the OpBranchConditional, and that
+    /// target is inside the if-selection.
+    uint32_t true_head = 0;
+    /// If not 0, then this block is an if-selection header, and `false_head`
+    /// is the target id of the false branch on the OpBranchConditional, and
+    /// that target is inside the if-selection.
+    uint32_t false_head = 0;
+    /// If not 0, then this block is an if-selection header, and when following
+    /// the flow via the true and false branches, control first reconverges at
+    /// the block with ID `premerge_head`, and `premerge_head` is still inside
+    /// the if-selection.
+    uint32_t premerge_head = 0;
+    /// If non-empty, then this block is an if-selection header, and control flow
+    /// in the body must be guarded by a boolean flow variable with this name.
+    /// This occurs when a block in this selection has both an if-break edge, and
+    /// also a different normal forward edge but without a merge instruction.
+    std::string flow_guard_name = "";
 
-  /// The result IDs that this block is responsible for declaring as a
-  /// hoisted variable.
-  /// @see DefInfo#requires_hoisted_def
-  std::vector<uint32_t> hoisted_ids;
+    /// The result IDs that this block is responsible for declaring as a
+    /// hoisted variable.
+    /// @see DefInfo#requires_hoisted_def
+    std::vector<uint32_t> hoisted_ids;
 
-  /// A PhiAssignment represents the assignment of a value to the state
-  /// variable associated with an OpPhi in a successor block.
-  struct PhiAssignment {
-    /// The ID of an OpPhi receiving a value from this basic block.
-    uint32_t phi_id;
-    /// The the value carried to the given OpPhi.
-    uint32_t value;
-  };
-  /// If this basic block branches to a visited basic block containing phis,
-  /// then this is the list of writes to the variables associated those phis.
-  std::vector<PhiAssignment> phi_assignments;
-  /// The IDs of OpPhi instructions which require their associated state
-  /// variable to be declared in this basic block.
-  std::vector<uint32_t> phis_needing_state_vars;
+    /// A PhiAssignment represents the assignment of a value to the state
+    /// variable associated with an OpPhi in a successor block.
+    struct PhiAssignment {
+        /// The ID of an OpPhi receiving a value from this basic block.
+        uint32_t phi_id;
+        /// The the value carried to the given OpPhi.
+        uint32_t value;
+    };
+    /// If this basic block branches to a visited basic block containing phis,
+    /// then this is the list of writes to the variables associated those phis.
+    std::vector<PhiAssignment> phi_assignments;
+    /// The IDs of OpPhi instructions which require their associated state
+    /// variable to be declared in this basic block.
+    std::vector<uint32_t> phis_needing_state_vars;
 };
 
 /// Writes the BlockInfo to the ostream
@@ -181,55 +181,54 @@
 /// @param bi the BlockInfo
 /// @returns the ostream so calls can be chained
 inline std::ostream& operator<<(std::ostream& o, const BlockInfo& bi) {
-  o << "BlockInfo{"
-    << " id: " << bi.id << " pos: " << bi.pos
-    << " merge_for_header: " << bi.merge_for_header
-    << " continue_for_header: " << bi.continue_for_header
-    << " header_for_merge: " << bi.header_for_merge
-    << " is_continue_entire_loop: " << int(bi.is_continue_entire_loop) << "}";
-  return o;
+    o << "BlockInfo{"
+      << " id: " << bi.id << " pos: " << bi.pos << " merge_for_header: " << bi.merge_for_header
+      << " continue_for_header: " << bi.continue_for_header
+      << " header_for_merge: " << bi.header_for_merge
+      << " is_continue_entire_loop: " << int(bi.is_continue_entire_loop) << "}";
+    return o;
 }
 
 /// Reasons for avoiding generating an intermediate value.
 enum class SkipReason {
-  /// `kDontSkip`: The value should be generated. Used for most values.
-  kDontSkip,
+    /// `kDontSkip`: The value should be generated. Used for most values.
+    kDontSkip,
 
-  /// For remaining cases, the value is not generated.
+    /// For remaining cases, the value is not generated.
 
-  /// `kOpaqueObject`: used for any intermediate value which is an sampler,
-  /// image,
-  /// or sampled image, or any pointer to such object. Code is generated
-  /// for those objects only when emitting the image instructions that access
-  /// the image (read, write, sample, gather, fetch, or query). For example,
-  /// when encountering an OpImageSampleExplicitLod, a call to the
-  /// textureSampleLevel builtin function will be emitted, and the call will
-  /// directly reference the underlying texture and sampler (variable or
-  /// function parameter).
-  kOpaqueObject,
+    /// `kOpaqueObject`: used for any intermediate value which is an sampler,
+    /// image,
+    /// or sampled image, or any pointer to such object. Code is generated
+    /// for those objects only when emitting the image instructions that access
+    /// the image (read, write, sample, gather, fetch, or query). For example,
+    /// when encountering an OpImageSampleExplicitLod, a call to the
+    /// textureSampleLevel builtin function will be emitted, and the call will
+    /// directly reference the underlying texture and sampler (variable or
+    /// function parameter).
+    kOpaqueObject,
 
-  /// `kSinkPointerIntoUse`: used to avoid emitting certain pointer expressions,
-  /// by instead generating their reference expression directly at the point of
-  /// use. For example, we apply this to OpAccessChain when indexing into a
-  /// vector, to avoid generating address-of vector component expressions.
-  kSinkPointerIntoUse,
+    /// `kSinkPointerIntoUse`: used to avoid emitting certain pointer expressions,
+    /// by instead generating their reference expression directly at the point of
+    /// use. For example, we apply this to OpAccessChain when indexing into a
+    /// vector, to avoid generating address-of vector component expressions.
+    kSinkPointerIntoUse,
 
-  /// `kPointSizeBuiltinPointer`: the value is a pointer to the Position builtin
-  /// variable.  Don't generate its address.  Avoid generating stores to this
-  /// pointer.
-  kPointSizeBuiltinPointer,
-  /// `kPointSizeBuiltinValue`: the value is the value loaded from the
-  /// PointSize builtin. Use 1.0f instead, because that's the only value
-  /// supported by WebGPU.
-  kPointSizeBuiltinValue,
+    /// `kPointSizeBuiltinPointer`: the value is a pointer to the Position builtin
+    /// variable.  Don't generate its address.  Avoid generating stores to this
+    /// pointer.
+    kPointSizeBuiltinPointer,
+    /// `kPointSizeBuiltinValue`: the value is the value loaded from the
+    /// PointSize builtin. Use 1.0f instead, because that's the only value
+    /// supported by WebGPU.
+    kPointSizeBuiltinValue,
 
-  /// `kSampleMaskInBuiltinPointer`: the value is a pointer to the SampleMaskIn
-  /// builtin input variable.  Don't generate its address.
-  kSampleMaskInBuiltinPointer,
+    /// `kSampleMaskInBuiltinPointer`: the value is a pointer to the SampleMaskIn
+    /// builtin input variable.  Don't generate its address.
+    kSampleMaskInBuiltinPointer,
 
-  /// `kSampleMaskOutBuiltinPointer`: the value is a pointer to the SampleMask
-  /// builtin output variable.
-  kSampleMaskOutBuiltinPointer,
+    /// `kSampleMaskOutBuiltinPointer`: the value is a pointer to the SampleMask
+    /// builtin output variable.
+    kSampleMaskOutBuiltinPointer,
 };
 
 /// Bookkeeping info for a SPIR-V ID defined in the function, or some
@@ -240,81 +239,79 @@
 ///    function.
 /// - certain module-scope builtin variables.
 struct DefInfo {
-  /// Constructor.
-  /// @param def_inst the SPIR-V instruction defining the ID
-  /// @param block_pos the position of the basic block where the ID is defined.
-  /// @param index an ordering index for this local definition
-  DefInfo(const spvtools::opt::Instruction& def_inst,
-          uint32_t block_pos,
-          size_t index);
-  /// Destructor.
-  ~DefInfo();
+    /// Constructor.
+    /// @param def_inst the SPIR-V instruction defining the ID
+    /// @param block_pos the position of the basic block where the ID is defined.
+    /// @param index an ordering index for this local definition
+    DefInfo(const spvtools::opt::Instruction& def_inst, uint32_t block_pos, size_t index);
+    /// Destructor.
+    ~DefInfo();
 
-  /// The SPIR-V instruction that defines the ID.
-  const spvtools::opt::Instruction& inst;
-  /// The position of the first block in which this ID is visible, in function
-  /// block order.  For IDs defined outside of the function, it is 0.
-  /// For IDs defined in the function, it is the position of the block
-  /// containing the definition of the ID.
-  /// See method `FunctionEmitter::ComputeBlockOrderAndPositions`
-  const uint32_t block_pos = 0;
+    /// The SPIR-V instruction that defines the ID.
+    const spvtools::opt::Instruction& inst;
+    /// The position of the first block in which this ID is visible, in function
+    /// block order.  For IDs defined outside of the function, it is 0.
+    /// For IDs defined in the function, it is the position of the block
+    /// containing the definition of the ID.
+    /// See method `FunctionEmitter::ComputeBlockOrderAndPositions`
+    const uint32_t block_pos = 0;
 
-  /// An index for uniquely and deterministically ordering all DefInfo records
-  /// in a function.
-  const size_t index = 0;
+    /// An index for uniquely and deterministically ordering all DefInfo records
+    /// in a function.
+    const size_t index = 0;
 
-  /// The number of uses of this ID.
-  uint32_t num_uses = 0;
+    /// The number of uses of this ID.
+    uint32_t num_uses = 0;
 
-  /// The block position of the last use of this ID, or 0 if it is not used
-  /// at all.  The "last" ordering is determined by the function block order.
-  uint32_t last_use_pos = 0;
+    /// The block position of the last use of this ID, or 0 if it is not used
+    /// at all.  The "last" ordering is determined by the function block order.
+    uint32_t last_use_pos = 0;
 
-  /// Is this value used in a construct other than the one in which it was
-  /// defined?
-  bool used_in_another_construct = false;
+    /// Is this value used in a construct other than the one in which it was
+    /// defined?
+    bool used_in_another_construct = false;
 
-  /// True if this ID requires a WGSL 'const' definition, due to context. It
-  /// might get one anyway (so this is *not* an if-and-only-if condition).
-  bool requires_named_const_def = false;
+    /// True if this ID requires a WGSL 'const' definition, due to context. It
+    /// might get one anyway (so this is *not* an if-and-only-if condition).
+    bool requires_named_const_def = false;
 
-  /// True if this ID must map to a WGSL variable declaration before the
-  /// corresponding position of the ID definition in SPIR-V.  This compensates
-  /// for the difference between dominance and scoping. An SSA definition can
-  /// dominate all its uses, but the construct where it is defined does not
-  /// enclose all the uses, and so if it were declared as a WGSL constant
-  /// definition at the point of its SPIR-V definition, then the WGSL name
-  /// would go out of scope too early. Fix that by creating a variable at the
-  /// top of the smallest construct that encloses both the definition and all
-  /// its uses. Then the original SPIR-V definition maps to a WGSL assignment
-  /// to that variable, and each SPIR-V use becomes a WGSL read from the
-  /// variable.
-  /// TODO(dneto): This works for constants of storable type, but not, for
-  /// example, pointers. crbug.com/tint/98
-  bool requires_hoisted_def = false;
+    /// True if this ID must map to a WGSL variable declaration before the
+    /// corresponding position of the ID definition in SPIR-V.  This compensates
+    /// for the difference between dominance and scoping. An SSA definition can
+    /// dominate all its uses, but the construct where it is defined does not
+    /// enclose all the uses, and so if it were declared as a WGSL constant
+    /// definition at the point of its SPIR-V definition, then the WGSL name
+    /// would go out of scope too early. Fix that by creating a variable at the
+    /// top of the smallest construct that encloses both the definition and all
+    /// its uses. Then the original SPIR-V definition maps to a WGSL assignment
+    /// to that variable, and each SPIR-V use becomes a WGSL read from the
+    /// variable.
+    /// TODO(dneto): This works for constants of storable type, but not, for
+    /// example, pointers. crbug.com/tint/98
+    bool requires_hoisted_def = false;
 
-  /// If the definition is an OpPhi, then `phi_var` is the name of the
-  /// variable that stores the value carried from parent basic blocks into
-  /// the basic block containing the OpPhi. Otherwise this is the empty string.
-  std::string phi_var;
+    /// If the definition is an OpPhi, then `phi_var` is the name of the
+    /// variable that stores the value carried from parent basic blocks into
+    /// the basic block containing the OpPhi. Otherwise this is the empty string.
+    std::string phi_var;
 
-  /// The storage class to use for this value, if it is of pointer type.
-  /// This is required to carry a storage class override from a storage
-  /// buffer expressed in the old style (with Uniform storage class)
-  /// that needs to be remapped to StorageBuffer storage class.
-  /// This is kInvalid for non-pointers.
-  ast::StorageClass storage_class = ast::StorageClass::kInvalid;
+    /// The storage class to use for this value, if it is of pointer type.
+    /// This is required to carry a storage class override from a storage
+    /// buffer expressed in the old style (with Uniform storage class)
+    /// that needs to be remapped to StorageBuffer storage class.
+    /// This is kInvalid for non-pointers.
+    ast::StorageClass storage_class = ast::StorageClass::kInvalid;
 
-  /// The expression to use when sinking pointers into their use.
-  /// When encountering a use of this instruction, we will emit this expression
-  /// instead.
-  TypedExpression sink_pointer_source_expr = {};
+    /// The expression to use when sinking pointers into their use.
+    /// When encountering a use of this instruction, we will emit this expression
+    /// instead.
+    TypedExpression sink_pointer_source_expr = {};
 
-  /// The reason, if any, that this value should be ignored.
-  /// Normally no values are ignored.  This field can be updated while
-  /// generating code because sometimes we only discover necessary facts
-  /// in the middle of generating code.
-  SkipReason skip = SkipReason::kDontSkip;
+    /// The reason, if any, that this value should be ignored.
+    /// Normally no values are ignored.  This field can be updated while
+    /// generating code because sometimes we only discover necessary facts
+    /// in the middle of generating code.
+    SkipReason skip = SkipReason::kDontSkip;
 };
 
 /// Writes the DefInfo to the ostream
@@ -322,40 +319,39 @@
 /// @param di the DefInfo
 /// @returns the ostream so calls can be chained
 inline std::ostream& operator<<(std::ostream& o, const DefInfo& di) {
-  o << "DefInfo{"
-    << " inst.result_id: " << di.inst.result_id()
-    << " block_pos: " << di.block_pos << " num_uses: " << di.num_uses
-    << " last_use_pos: " << di.last_use_pos << " requires_named_const_def: "
-    << (di.requires_named_const_def ? "true" : "false")
-    << " requires_hoisted_def: " << (di.requires_hoisted_def ? "true" : "false")
-    << " phi_var: '" << di.phi_var << "'";
-  if (di.storage_class != ast::StorageClass::kNone) {
-    o << " sc:" << int(di.storage_class);
-  }
-  switch (di.skip) {
-    case SkipReason::kDontSkip:
-      break;
-    case SkipReason::kOpaqueObject:
-      o << " skip:opaque";
-      break;
-    case SkipReason::kSinkPointerIntoUse:
-      o << " skip:sink_pointer";
-      break;
-    case SkipReason::kPointSizeBuiltinPointer:
-      o << " skip:pointsize_pointer";
-      break;
-    case SkipReason::kPointSizeBuiltinValue:
-      o << " skip:pointsize_value";
-      break;
-    case SkipReason::kSampleMaskInBuiltinPointer:
-      o << " skip:samplemaskin_pointer";
-      break;
-    case SkipReason::kSampleMaskOutBuiltinPointer:
-      o << " skip:samplemaskout_pointer";
-      break;
-  }
-  o << "}";
-  return o;
+    o << "DefInfo{"
+      << " inst.result_id: " << di.inst.result_id() << " block_pos: " << di.block_pos
+      << " num_uses: " << di.num_uses << " last_use_pos: " << di.last_use_pos
+      << " requires_named_const_def: " << (di.requires_named_const_def ? "true" : "false")
+      << " requires_hoisted_def: " << (di.requires_hoisted_def ? "true" : "false") << " phi_var: '"
+      << di.phi_var << "'";
+    if (di.storage_class != ast::StorageClass::kNone) {
+        o << " sc:" << int(di.storage_class);
+    }
+    switch (di.skip) {
+        case SkipReason::kDontSkip:
+            break;
+        case SkipReason::kOpaqueObject:
+            o << " skip:opaque";
+            break;
+        case SkipReason::kSinkPointerIntoUse:
+            o << " skip:sink_pointer";
+            break;
+        case SkipReason::kPointSizeBuiltinPointer:
+            o << " skip:pointsize_pointer";
+            break;
+        case SkipReason::kPointSizeBuiltinValue:
+            o << " skip:pointsize_value";
+            break;
+        case SkipReason::kSampleMaskInBuiltinPointer:
+            o << " skip:samplemaskin_pointer";
+            break;
+        case SkipReason::kSampleMaskOutBuiltinPointer:
+            o << " skip:samplemaskout_pointer";
+            break;
+    }
+    o << "}";
+    return o;
 }
 
 /// A placeholder Statement that exists for the duration of building a
@@ -367,941 +363,925 @@
 /// StatementBlock is being constructed, which becomes an immutable node on
 /// StatementBlock::Finalize().
 class StatementBuilder : public Castable<StatementBuilder, ast::Statement> {
- public:
-  /// Constructor
-  StatementBuilder() : Base(ProgramID(), Source{}) {}
+  public:
+    /// Constructor
+    StatementBuilder() : Base(ProgramID(), Source{}) {}
 
-  /// @param builder the program builder
-  /// @returns the build AST node
-  virtual const ast::Statement* Build(ProgramBuilder* builder) const = 0;
+    /// @param builder the program builder
+    /// @returns the build AST node
+    virtual const ast::Statement* Build(ProgramBuilder* builder) const = 0;
 
- private:
-  Node* Clone(CloneContext*) const override;
+  private:
+    Node* Clone(CloneContext*) const override;
 };
 
 /// A FunctionEmitter emits a SPIR-V function onto a Tint AST module.
 class FunctionEmitter {
- public:
-  /// Creates a FunctionEmitter, and prepares to write to the AST module
-  /// in `pi`
-  /// @param pi a ParserImpl which has already executed BuildInternalModule
-  /// @param function the function to emit
-  FunctionEmitter(ParserImpl* pi, const spvtools::opt::Function& function);
-  /// Creates a FunctionEmitter, and prepares to write to the AST module
-  /// in `pi`
-  /// @param pi a ParserImpl which has already executed BuildInternalModule
-  /// @param function the function to emit
-  /// @param ep_info entry point information for this function, or nullptr
-  FunctionEmitter(ParserImpl* pi,
-                  const spvtools::opt::Function& function,
-                  const EntryPointInfo* ep_info);
-  /// Move constructor. Only valid when the other object was newly created.
-  /// @param other the emitter to clone
-  FunctionEmitter(FunctionEmitter&& other);
-  /// Destructor
-  ~FunctionEmitter();
-
-  /// Emits the function to AST module.
-  /// @return whether emission succeeded
-  bool Emit();
-
-  /// @returns true if emission has not yet failed.
-  bool success() const { return fail_stream_.status(); }
-  /// @returns true if emission has failed.
-  bool failed() const { return !success(); }
-
-  /// Finalizes any StatementBuilders returns the body of the function.
-  /// Must only be called once, and to be used only for testing.
-  /// @returns the body of the function.
-  const ast::StatementList ast_body();
-
-  /// Records failure.
-  /// @returns a FailStream on which to emit diagnostics.
-  FailStream& Fail() { return fail_stream_.Fail(); }
-
-  /// @returns the parser implementation
-  ParserImpl* parser() { return &parser_impl_; }
-
-  /// Emits the entry point as a wrapper around its implementation function.
-  /// Pipeline inputs become formal parameters, and pipeline outputs become
-  /// return values.
-  /// @returns false if emission failed.
-  bool EmitEntryPointAsWrapper();
-
-  /// Creates one or more entry point input parameters corresponding to a
-  /// part of an input variable.  The part of the input variable is specfied
-  /// by the `index_prefix`, which successively indexes into the variable.
-  /// Also generates the assignment statements that copy the input parameter
-  /// to the corresponding part of the variable.  Assumes the variable
-  /// has already been created in the Private storage class.
-  /// @param var_name The name of the variable
-  /// @param var_type The store type of the variable
-  /// @param decos The variable's decorations
-  /// @param index_prefix Indices stepping into the variable, indicating
-  /// what part of the variable to populate.
-  /// @param tip_type The type of the component inside variable, after indexing
-  /// with the indices in `index_prefix`.
-  /// @param forced_param_type The type forced by WGSL, if the variable is a
-  /// builtin, otherwise the same as var_type.
-  /// @param params The parameter list where the new parameter is appended.
-  /// @param statements The statement list where the assignment is appended.
-  /// @returns false if emission failed
-  bool EmitPipelineInput(std::string var_name,
-                         const Type* var_type,
-                         ast::AttributeList* decos,
-                         std::vector<int> index_prefix,
-                         const Type* tip_type,
-                         const Type* forced_param_type,
-                         ast::VariableList* params,
-                         ast::StatementList* statements);
-
-  /// Creates one or more struct members from an output variable, and the
-  /// expressions that compute the value they contribute to the entry point
-  /// return value.  The part of the output variable is specfied
-  /// by the `index_prefix`, which successively indexes into the variable.
-  /// Assumes the variable has already been created in the Private storage
-  /// class.
-  /// @param var_name The name of the variable
-  /// @param var_type The store type of the variable
-  /// @param decos The variable's decorations
-  /// @param index_prefix Indices stepping into the variable, indicating
-  /// what part of the variable to populate.
-  /// @param tip_type The type of the component inside variable, after indexing
-  /// with the indices in `index_prefix`.
-  /// @param forced_member_type The type forced by WGSL, if the variable is a
-  /// builtin, otherwise the same as var_type.
-  /// @param return_members The struct member list where the new member is
-  /// added.
-  /// @param return_exprs The expression list where the return expression is
-  /// added.
-  /// @returns false if emission failed
-  bool EmitPipelineOutput(std::string var_name,
-                          const Type* var_type,
-                          ast::AttributeList* decos,
-                          std::vector<int> index_prefix,
-                          const Type* tip_type,
-                          const Type* forced_member_type,
-                          ast::StructMemberList* return_members,
-                          ast::ExpressionList* return_exprs);
-
-  /// Updates the attribute list, replacing an existing Location attribute
-  /// with another having one higher location value. Does nothing if no
-  /// location attribute exists.
-  /// Assumes the list contains at most one Location attribute.
-  /// @param attributes the attribute list to modify
-  void IncrementLocation(ast::AttributeList* attributes);
-
-  /// Returns the Location attribute, if it exists.
-  /// @param attributes the list of attributes to search
-  /// @returns the Location attribute, or nullptr if it doesn't exist
-  const ast::Attribute* GetLocation(const ast::AttributeList& attributes);
-
-  /// Create an ast::BlockStatement representing the body of the function.
-  /// This creates the statement stack, which is non-empty for the lifetime
-  /// of the function.
-  /// @returns the body of the function, or null on error
-  const ast::BlockStatement* MakeFunctionBody();
-
-  /// Emits the function body, populating the bottom entry of the statements
-  /// stack.
-  /// @returns false if emission failed.
-  bool EmitBody();
-
-  /// Records a mapping from block ID to a BlockInfo struct.
-  /// Populates `block_info_`
-  void RegisterBasicBlocks();
-
-  /// Verifies that terminators only branch to labels in the current function.
-  /// Assumes basic blocks have been registered.
-  /// @returns true if terminators are valid
-  bool TerminatorsAreValid();
-
-  /// Populates merge-header cross-links and BlockInfo#is_continue_entire_loop.
-  /// Also verifies that merge instructions go to blocks in the same function.
-  /// Assumes basic blocks have been registered, and terminators are valid.
-  /// @returns false if registration fails
-  bool RegisterMerges();
-
-  /// Determines the output order for the basic blocks in the function.
-  /// Populates `block_order_` and BlockInfo#pos.
-  /// Assumes basic blocks have been registered.
-  void ComputeBlockOrderAndPositions();
-
-  /// @returns the reverse structured post order of the basic blocks in
-  /// the function.
-  const std::vector<uint32_t>& block_order() const { return block_order_; }
-
-  /// Verifies that the orderings among a structured header, continue target,
-  /// and merge block are valid. Assumes block order has been computed, and
-  /// merges are valid and recorded.
-  /// @returns false if invalid nesting was detected
-  bool VerifyHeaderContinueMergeOrder();
-
-  /// Labels each basic block with its nearest enclosing structured construct.
-  /// Populates BlockInfo#construct and the `constructs_` list.
-  /// Assumes terminators are valid and merges have been registered, block
-  /// order has been computed, and each block is labeled with its position.
-  /// Checks nesting of structured control flow constructs.
-  /// @returns false if bad nesting has been detected
-  bool LabelControlFlowConstructs();
-
-  /// @returns the structured constructs
-  const ConstructList& constructs() const { return constructs_; }
-
-  /// Marks blocks targets of a switch, either as the head of a case or
-  /// as the default target.
-  /// @returns false on failure
-  bool FindSwitchCaseHeaders();
-
-  /// Classifies the successor CFG edges for the ordered basic blocks.
-  /// Also checks validity of each edge (populates BlockInfo#succ_edge).
-  /// Implicitly checks dominance rules for headers and continue constructs.
-  /// Assumes each block has been labeled with its control flow construct.
-  /// @returns false on failure
-  bool ClassifyCFGEdges();
-
-  /// Marks the blocks within a selection construct that are the first blocks
-  /// in the "then" clause, the "else" clause, and the "premerge" clause.
-  /// The head of the premerge clause is the block, if it exists, at which
-  /// control flow reconverges from the "then" and "else" clauses, but before
-  /// before the merge block for that selection.   The existence of a premerge
-  /// should be an exceptional case, but is allowed by the structured control
-  /// flow rules.
-  /// @returns false if bad nesting has been detected.
-  bool FindIfSelectionInternalHeaders();
-
-  /// Creates a DefInfo record for each module-scope builtin variable
-  /// that should be handled specially.  Either it's ignored, or its store
-  /// type is converted on load.
-  /// Populates the `def_info_` mapping for such IDs.
-  /// @returns false on failure
-  bool RegisterSpecialBuiltInVariables();
-
-  /// Creates a DefInfo record for each locally defined SPIR-V ID.
-  /// Populates the `def_info_` mapping with basic results for such IDs.
-  /// @returns false on failure
-  bool RegisterLocallyDefinedValues();
-
-  /// Returns the Tint storage class for the given SPIR-V ID that is a
-  /// pointer value.
-  /// @param id a SPIR-V ID for a pointer value
-  /// @returns the storage class
-  ast::StorageClass GetStorageClassForPointerValue(uint32_t id);
-
-  /// Remaps the storage class for the type of a locally-defined value,
-  /// if necessary. If it's not a pointer type, or if its storage class
-  /// already matches, then the result is a copy of the `type` argument.
-  /// @param type the AST type
-  /// @param result_id the SPIR-V ID for the locally defined value
-  /// @returns an possibly updated type
-  const Type* RemapStorageClass(const Type* type, uint32_t result_id);
-
-  /// Marks locally defined values when they should get a 'const'
-  /// definition in WGSL, or a 'var' definition at an outer scope.
-  /// This occurs in several cases:
-  ///  - When a SPIR-V instruction might use the dynamically computed value
-  ///    only once, but the WGSL code might reference it multiple times.
-  ///    For example, this occurs for the vector operands of OpVectorShuffle.
-  ///    In this case the definition's DefInfo#requires_named_const_def property
-  ///    is set to true.
-  ///  - When a definition and at least one of its uses are not in the
-  ///    same structured construct.
-  ///    In this case the definition's DefInfo#requires_named_const_def property
-  ///    is set to true.
-  ///  - When a definition is in a construct that does not enclose all the
-  ///    uses.  In this case the definition's DefInfo#requires_hoisted_def
-  ///    property is set to true.
-  /// Updates the `def_info_` mapping.
-  void FindValuesNeedingNamedOrHoistedDefinition();
-
-  /// Emits declarations of function variables.
-  /// @returns false if emission failed.
-  bool EmitFunctionVariables();
-
-  /// Emits statements in the body.
-  /// @returns false if emission failed.
-  bool EmitFunctionBodyStatements();
-
-  /// Emits a basic block.
-  /// @param block_info the block to emit
-  /// @returns false if emission failed.
-  bool EmitBasicBlock(const BlockInfo& block_info);
-
-  /// Emits an IfStatement, including its condition expression, and sets
-  /// up the statement stack to accumulate subsequent basic blocks into
-  /// the "then" and "else" clauses.
-  /// @param block_info the if-selection header block
-  /// @returns false if emission failed.
-  bool EmitIfStart(const BlockInfo& block_info);
-
-  /// Emits a SwitchStatement, including its condition expression, and sets
-  /// up the statement stack to accumulate subsequent basic blocks into
-  /// the default clause and case clauses.
-  /// @param block_info the switch-selection header block
-  /// @returns false if emission failed.
-  bool EmitSwitchStart(const BlockInfo& block_info);
-
-  /// Emits a LoopStatement, and pushes a new StatementBlock to accumulate
-  /// the remaining instructions in the current block and subsequent blocks
-  /// in the loop.
-  /// @param construct the loop construct
-  /// @returns false if emission failed.
-  bool EmitLoopStart(const Construct* construct);
-
-  /// Emits a ContinuingStatement, and pushes a new StatementBlock to accumulate
-  /// the remaining instructions in the current block and subsequent blocks
-  /// in the continue construct.
-  /// @param construct the continue construct
-  /// @returns false if emission failed.
-  bool EmitContinuingStart(const Construct* construct);
-
-  /// Emits the non-control-flow parts of a basic block, but only once.
-  /// The `already_emitted` parameter indicates whether the code has already
-  /// been emitted, and is used to signal that this invocation actually emitted
-  /// it.
-  /// @param block_info the block to emit
-  /// @param already_emitted the block to emit
-  /// @returns false if the code had not yet been emitted, but emission failed
-  bool EmitStatementsInBasicBlock(const BlockInfo& block_info,
-                                  bool* already_emitted);
-
-  /// Emits code for terminators, but that aren't part of entering or
-  /// resolving structured control flow. That is, if the basic block
-  /// terminator calls for it, emit the fallthrough, break, continue, return,
-  /// or kill commands.
-  /// @param block_info the block with the terminator to emit (if any)
-  /// @returns false if emission failed
-  bool EmitNormalTerminator(const BlockInfo& block_info);
-
-  /// Returns a new statement to represent the given branch representing a
-  /// "normal" terminator, as in the sense of EmitNormalTerminator.  If no
-  /// WGSL statement is required, the statement will be nullptr. This method
-  /// tries to avoid emitting a 'break' statement when that would be redundant
-  /// in WGSL due to implicit breaking out of a switch.
-  /// @param src_info the source block
-  /// @param dest_info the destination block
-  /// @returns the new statement, or a null statement
-  const ast::Statement* MakeBranch(const BlockInfo& src_info,
-                                   const BlockInfo& dest_info) const {
-    return MakeBranchDetailed(src_info, dest_info, false, nullptr);
-  }
-
-  /// Returns a new statement to represent the given branch representing a
-  /// "normal" terminator, as in the sense of EmitNormalTerminator.  If no
-  /// WGSL statement is required, the statement will be nullptr.
-  /// @param src_info the source block
-  /// @param dest_info the destination block
-  /// @returns the new statement, or a null statement
-  const ast::Statement* MakeForcedBranch(const BlockInfo& src_info,
-                                         const BlockInfo& dest_info) const {
-    return MakeBranchDetailed(src_info, dest_info, true, nullptr);
-  }
-
-  /// Returns a new statement to represent the given branch representing a
-  /// "normal" terminator, as in the sense of EmitNormalTerminator.  If no
-  /// WGSL statement is required, the statement will be nullptr. When `forced`
-  /// is false, this method tries to avoid emitting a 'break' statement when
-  /// that would be redundant in WGSL due to implicit breaking out of a switch.
-  /// When `forced` is true, the method won't try to avoid emitting that break.
-  /// If the control flow edge is an if-break for an if-selection with a
-  /// control flow guard, then return that guard name via `flow_guard_name_ptr`
-  /// when that parameter is not null.
-  /// @param src_info the source block
-  /// @param dest_info the destination block
-  /// @param forced if true, always emit the branch (if it exists in WGSL)
-  /// @param flow_guard_name_ptr return parameter for control flow guard name
-  /// @returns the new statement, or a null statement
-  const ast::Statement* MakeBranchDetailed(
-      const BlockInfo& src_info,
-      const BlockInfo& dest_info,
-      bool forced,
-      std::string* flow_guard_name_ptr) const;
-
-  /// Returns a new if statement with the given statements as the then-clause
-  /// and the else-clause.  Either or both clauses might be nullptr. If both
-  /// are nullptr, then don't make a new statement and instead return nullptr.
-  /// @param condition the branching condition
-  /// @param then_stmt the statement for the then clause of the if, or nullptr
-  /// @param else_stmt the statement for the else clause of the if, or nullptr
-  /// @returns the new statement, or nullptr
-  const ast::Statement* MakeSimpleIf(const ast::Expression* condition,
-                                     const ast::Statement* then_stmt,
-                                     const ast::Statement* else_stmt) const;
-
-  /// Emits the statements for an normal-terminator OpBranchConditional
-  /// where one branch is a case fall through (the true branch if and only
-  /// if `fall_through_is_true_branch` is true), and the other branch is
-  /// goes to a different destination, named by `other_dest`.
-  /// @param src_info the basic block from which we're branching
-  /// @param cond the branching condition
-  /// @param other_edge_kind the edge kind from the source block to the other
-  /// destination
-  /// @param other_dest the other branching destination
-  /// @param fall_through_is_true_branch true when the fall-through is the true
-  /// branch
-  /// @returns the false if emission fails
-  bool EmitConditionalCaseFallThrough(const BlockInfo& src_info,
-                                      const ast::Expression* cond,
-                                      EdgeKind other_edge_kind,
-                                      const BlockInfo& other_dest,
-                                      bool fall_through_is_true_branch);
-
-  /// Emits a normal instruction: not a terminator, label, or variable
-  /// declaration.
-  /// @param inst the instruction
-  /// @returns false if emission failed.
-  bool EmitStatement(const spvtools::opt::Instruction& inst);
-
-  /// Emits a const definition for the typed value in `ast_expr`, and
-  /// records it as the translation for the result ID from `inst`.
-  /// @param inst the SPIR-V instruction defining the value
-  /// @param ast_expr the already-computed AST expression for the value
-  /// @returns false if emission failed.
-  bool EmitConstDefinition(const spvtools::opt::Instruction& inst,
-                           TypedExpression ast_expr);
-
-  /// Emits a write of the typed value in `ast_expr` to a hoisted variable
-  /// for the given SPIR-V ID, if that ID has a hoisted declaration. Otherwise,
-  /// emits a const definition instead.
-  /// @param inst the SPIR-V instruction defining the value
-  /// @param ast_expr the already-computed AST expression for the value
-  /// @returns false if emission failed.
-  bool EmitConstDefOrWriteToHoistedVar(const spvtools::opt::Instruction& inst,
-                                       TypedExpression ast_expr);
-
-  /// If the result ID of the given instruction is hoisted, then emits
-  /// a statement to write the expression to the hoisted variable, and
-  /// returns true.  Otherwise return false.
-  /// @param inst the SPIR-V instruction defining a value.
-  /// @param ast_expr the expression to assign.
-  /// @returns true if the instruction has an associated hoisted variable.
-  bool WriteIfHoistedVar(const spvtools::opt::Instruction& inst,
-                         TypedExpression ast_expr);
-
-  /// Makes an expression from a SPIR-V ID.
-  /// if the SPIR-V result type is a pointer.
-  /// @param id the SPIR-V ID of the value
-  /// @returns an AST expression for the instruction, or an invalid
-  /// TypedExpression on error.
-  TypedExpression MakeExpression(uint32_t id);
-
-  /// Creates an expression and supporting statements for a combinatorial
-  /// instruction, or returns null.  A SPIR-V instruction is combinatorial
-  /// if it has no side effects and its result depends only on its operands,
-  /// and not on accessing external state like memory or the state of other
-  /// invocations.  Statements are only created if required to provide values
-  /// to the expression. Supporting statements are not required to be
-  /// combinatorial.
-  /// @param inst a SPIR-V instruction representing an exrpression
-  /// @returns an AST expression for the instruction, or nullptr.
-  TypedExpression MaybeEmitCombinatorialValue(
-      const spvtools::opt::Instruction& inst);
-
-  /// Creates an expression and supporting statements for the a GLSL.std.450
-  /// extended instruction.
-  /// @param inst a SPIR-V OpExtInst instruction from GLSL.std.450
-  /// @returns an AST expression for the instruction, or nullptr.
-  TypedExpression EmitGlslStd450ExtInst(const spvtools::opt::Instruction& inst);
-
-  /// Creates an expression for OpCompositeExtract
-  /// @param inst an OpCompositeExtract instruction.
-  /// @returns an AST expression for the instruction, or nullptr.
-  TypedExpression MakeCompositeExtract(const spvtools::opt::Instruction& inst);
-
-  /// Creates an expression for indexing into a composite value.  The literal
-  /// indices that step into the value start at instruction input operand
-  /// `start_index` and run to the end of the instruction.
-  /// @param inst the original instruction
-  /// @param composite the typed expression for the composite
-  /// @param composite_type_id the SPIR-V type ID for the composite
-  /// @param index_start the index of the first operand in `inst` that is an
-  /// index into the composite type
-  /// @returns an AST expression for the decomposed composite, or {} on error
-  TypedExpression MakeCompositeValueDecomposition(
-      const spvtools::opt::Instruction& inst,
-      TypedExpression composite,
-      uint32_t composite_type_id,
-      int index_start);
-
-  /// Creates an expression for OpVectorShuffle
-  /// @param inst an OpVectorShuffle instruction.
-  /// @returns an AST expression for the instruction, or nullptr.
-  TypedExpression MakeVectorShuffle(const spvtools::opt::Instruction& inst);
-
-  /// Creates an expression for a numeric conversion.
-  /// @param inst a numeric conversion instruction
-  /// @returns an AST expression for the instruction, or nullptr.
-  TypedExpression MakeNumericConversion(const spvtools::opt::Instruction& inst);
-
-  /// Gets the block info for a block ID, if any exists
-  /// @param id the SPIR-V ID of the OpLabel instruction starting the block
-  /// @returns the block info for the given ID, if it exists, or nullptr
-  BlockInfo* GetBlockInfo(uint32_t id) const {
-    auto where = block_info_.find(id);
-    if (where == block_info_.end()) {
-      return nullptr;
-    }
-    return where->second.get();
-  }
-
-  /// Is the block, represented by info, in the structured block order?
-  /// @param info the block
-  /// @returns true if the block is in the structured block order.
-  bool IsInBlockOrder(const BlockInfo* info) const {
-    return info && info->pos != kInvalidBlockPos;
-  }
-
-  /// Gets the local definition info for a result ID.
-  /// @param id the SPIR-V ID of local definition.
-  /// @returns the definition info for the given ID, if it exists, or nullptr
-  DefInfo* GetDefInfo(uint32_t id) const {
-    auto where = def_info_.find(id);
-    if (where == def_info_.end()) {
-      return nullptr;
-    }
-    return where->second.get();
-  }
-  /// Returns the skip reason for a result ID.
-  /// @param id SPIR-V result ID
-  /// @returns the skip reason for the given ID, or SkipReason::kDontSkip
-  SkipReason GetSkipReason(uint32_t id) const {
-    if (auto* def_info = GetDefInfo(id)) {
-      return def_info->skip;
-    }
-    return SkipReason::kDontSkip;
-  }
-
-  /// Returns the most deeply nested structured construct which encloses the
-  /// WGSL scopes of names declared in both block positions. Each position must
-  /// be a valid index into the function block order array.
-  /// @param first_pos the first block position
-  /// @param last_pos the last block position
-  /// @returns the smallest construct containing both positions
-  const Construct* GetEnclosingScope(uint32_t first_pos,
-                                     uint32_t last_pos) const;
-
-  /// Finds loop construct associated with a continue construct, if it exists.
-  /// Returns nullptr if:
-  ///  - the given construct is not a continue construct
-  ///  - the continue construct does not have an associated loop construct
-  ///    (the continue target is also the loop header block)
-  /// @param c the continue construct
-  /// @returns the associated loop construct, or nullptr
-  const Construct* SiblingLoopConstruct(const Construct* c) const;
-
-  /// Returns an identifier expression for the swizzle name of the given
-  /// index into a vector.  Emits an error and returns nullptr if the
-  /// index is out of range, i.e. 4 or higher.
-  /// @param i index of the subcomponent
-  /// @returns the identifier expression for the `i`'th component
-  ast::IdentifierExpression* Swizzle(uint32_t i);
-
-  /// Returns an identifier expression for the swizzle name of the first
-  /// `n` elements of a vector.  Emits an error and returns nullptr if `n`
-  /// is out of range, i.e. 4 or higher.
-  /// @param n the number of components in the swizzle
-  /// @returns the swizzle identifier for the first n elements of a vector
-  ast::IdentifierExpression* PrefixSwizzle(uint32_t n);
-
-  /// Converts SPIR-V image coordinates from an image access instruction
-  /// (e.g. OpImageSampledImplicitLod) into an expression list consisting of
-  /// the texture coordinates, and an integral array index if the texture is
-  /// arrayed. The texture coordinate is a scalar for 1D textures, a vector of
-  /// 2 elements for a 2D texture, and a vector of 3 elements for a 3D or
-  /// Cube texture. Excess components are ignored, e.g. if the SPIR-V
-  /// coordinate is a 4-element vector but the image is a 2D non-arrayed
-  /// texture then the 3rd and 4th components are ignored.
-  /// On failure, issues an error and returns an empty expression list.
-  /// @param image_access the image access instruction
-  /// @returns an ExpressionList of the coordinate and array index (if any)
-  ast::ExpressionList MakeCoordinateOperandsForImageAccess(
-      const spvtools::opt::Instruction& image_access);
-
-  /// Returns the given value as an I32.  If it's already an I32 then this
-  /// return the given value.  Otherwise, wrap the value in a TypeConstructor
-  /// expression.
-  /// @param value the value to pass through or convert
-  /// @returns the value as an I32 value.
-  TypedExpression ToI32(TypedExpression value);
-
-  /// Returns the given value as a signed integer type of the same shape
-  /// if the value is unsigned scalar or vector, by wrapping the value
-  /// with a TypeConstructor expression.  Returns the value itself if the
-  /// value otherwise.
-  /// @param value the value to pass through or convert
-  /// @returns the value itself, or converted to signed integral
-  TypedExpression ToSignedIfUnsigned(TypedExpression value);
-
-  /// @param value_id the value identifier to check
-  /// @returns true if the given SPIR-V id represents a constant float 0.
-  bool IsFloatZero(uint32_t value_id);
-  /// @param value_id the value identifier to check
-  /// @returns true if the given SPIR-V id represents a constant float 1.
-  bool IsFloatOne(uint32_t value_id);
-
- private:
-  /// FunctionDeclaration contains the parsed information for a function header.
-  struct FunctionDeclaration {
-    /// Constructor
-    FunctionDeclaration();
+  public:
+    /// Creates a FunctionEmitter, and prepares to write to the AST module
+    /// in `pi`
+    /// @param pi a ParserImpl which has already executed BuildInternalModule
+    /// @param function the function to emit
+    FunctionEmitter(ParserImpl* pi, const spvtools::opt::Function& function);
+    /// Creates a FunctionEmitter, and prepares to write to the AST module
+    /// in `pi`
+    /// @param pi a ParserImpl which has already executed BuildInternalModule
+    /// @param function the function to emit
+    /// @param ep_info entry point information for this function, or nullptr
+    FunctionEmitter(ParserImpl* pi,
+                    const spvtools::opt::Function& function,
+                    const EntryPointInfo* ep_info);
+    /// Move constructor. Only valid when the other object was newly created.
+    /// @param other the emitter to clone
+    FunctionEmitter(FunctionEmitter&& other);
     /// Destructor
-    ~FunctionDeclaration();
+    ~FunctionEmitter();
 
-    /// Parsed header source
-    Source source;
-    /// Function name
-    std::string name;
-    /// Function parameters
-    ast::VariableList params;
-    /// Function return type
-    const Type* return_type;
-    /// Function attributes
-    ast::AttributeList attributes;
-  };
+    /// Emits the function to AST module.
+    /// @return whether emission succeeded
+    bool Emit();
 
-  /// Parse the function declaration, which comprises the name, parameters, and
-  /// return type, populating `decl`.
-  /// @param decl the FunctionDeclaration to populate
-  /// @returns true if emission has not yet failed.
-  bool ParseFunctionDeclaration(FunctionDeclaration* decl);
+    /// @returns true if emission has not yet failed.
+    bool success() const { return fail_stream_.status(); }
+    /// @returns true if emission has failed.
+    bool failed() const { return !success(); }
 
-  /// @returns the store type for the OpVariable instruction, or
-  /// null on failure.
-  const Type* GetVariableStoreType(
-      const spvtools::opt::Instruction& var_decl_inst);
+    /// Finalizes any StatementBuilders returns the body of the function.
+    /// Must only be called once, and to be used only for testing.
+    /// @returns the body of the function.
+    const ast::StatementList ast_body();
 
-  /// Returns an expression for an instruction operand. Signedness conversion is
-  /// performed to match the result type of the SPIR-V instruction.
-  /// @param inst the SPIR-V instruction
-  /// @param operand_index the index of the operand, counting 0 as the first
-  /// input operand
-  /// @returns a new expression node
-  TypedExpression MakeOperand(const spvtools::opt::Instruction& inst,
-                              uint32_t operand_index);
+    /// Records failure.
+    /// @returns a FailStream on which to emit diagnostics.
+    FailStream& Fail() { return fail_stream_.Fail(); }
 
-  /// Copies a typed expression to the result, but when the type is a pointer
-  /// or reference type, ensures the storage class is not defaulted.  That is,
-  /// it changes a storage class of "none" to "function".
-  /// @param expr a typed expression
-  /// @results a copy of the expression, with possibly updated type
-  TypedExpression InferFunctionStorageClass(TypedExpression expr);
+    /// @returns the parser implementation
+    ParserImpl* parser() { return &parser_impl_; }
 
-  /// Returns an expression for a SPIR-V OpFMod instruction.
-  /// @param inst the SPIR-V instruction
-  /// @returns an expression
-  TypedExpression MakeFMod(const spvtools::opt::Instruction& inst);
+    /// Emits the entry point as a wrapper around its implementation function.
+    /// Pipeline inputs become formal parameters, and pipeline outputs become
+    /// return values.
+    /// @returns false if emission failed.
+    bool EmitEntryPointAsWrapper();
 
-  /// Returns an expression for a SPIR-V OpAccessChain or OpInBoundsAccessChain
-  /// instruction.
-  /// @param inst the SPIR-V instruction
-  /// @returns an expression
-  TypedExpression MakeAccessChain(const spvtools::opt::Instruction& inst);
+    /// Creates one or more entry point input parameters corresponding to a
+    /// part of an input variable.  The part of the input variable is specfied
+    /// by the `index_prefix`, which successively indexes into the variable.
+    /// Also generates the assignment statements that copy the input parameter
+    /// to the corresponding part of the variable.  Assumes the variable
+    /// has already been created in the Private storage class.
+    /// @param var_name The name of the variable
+    /// @param var_type The store type of the variable
+    /// @param decos The variable's decorations
+    /// @param index_prefix Indices stepping into the variable, indicating
+    /// what part of the variable to populate.
+    /// @param tip_type The type of the component inside variable, after indexing
+    /// with the indices in `index_prefix`.
+    /// @param forced_param_type The type forced by WGSL, if the variable is a
+    /// builtin, otherwise the same as var_type.
+    /// @param params The parameter list where the new parameter is appended.
+    /// @param statements The statement list where the assignment is appended.
+    /// @returns false if emission failed
+    bool EmitPipelineInput(std::string var_name,
+                           const Type* var_type,
+                           ast::AttributeList* decos,
+                           std::vector<int> index_prefix,
+                           const Type* tip_type,
+                           const Type* forced_param_type,
+                           ast::VariableList* params,
+                           ast::StatementList* statements);
 
-  /// Emits a function call.  On failure, emits a diagnostic and returns false.
-  /// @param inst the SPIR-V function call instruction
-  /// @returns false if emission failed
-  bool EmitFunctionCall(const spvtools::opt::Instruction& inst);
+    /// Creates one or more struct members from an output variable, and the
+    /// expressions that compute the value they contribute to the entry point
+    /// return value.  The part of the output variable is specfied
+    /// by the `index_prefix`, which successively indexes into the variable.
+    /// Assumes the variable has already been created in the Private storage
+    /// class.
+    /// @param var_name The name of the variable
+    /// @param var_type The store type of the variable
+    /// @param decos The variable's decorations
+    /// @param index_prefix Indices stepping into the variable, indicating
+    /// what part of the variable to populate.
+    /// @param tip_type The type of the component inside variable, after indexing
+    /// with the indices in `index_prefix`.
+    /// @param forced_member_type The type forced by WGSL, if the variable is a
+    /// builtin, otherwise the same as var_type.
+    /// @param return_members The struct member list where the new member is
+    /// added.
+    /// @param return_exprs The expression list where the return expression is
+    /// added.
+    /// @returns false if emission failed
+    bool EmitPipelineOutput(std::string var_name,
+                            const Type* var_type,
+                            ast::AttributeList* decos,
+                            std::vector<int> index_prefix,
+                            const Type* tip_type,
+                            const Type* forced_member_type,
+                            ast::StructMemberList* return_members,
+                            ast::ExpressionList* return_exprs);
 
-  /// Emits a control barrier builtin.  On failure, emits a diagnostic and
-  /// returns false.
-  /// @param inst the SPIR-V control barrier instruction
-  /// @returns false if emission failed
-  bool EmitControlBarrier(const spvtools::opt::Instruction& inst);
+    /// Updates the attribute list, replacing an existing Location attribute
+    /// with another having one higher location value. Does nothing if no
+    /// location attribute exists.
+    /// Assumes the list contains at most one Location attribute.
+    /// @param attributes the attribute list to modify
+    void IncrementLocation(ast::AttributeList* attributes);
 
-  /// Returns an expression for a SPIR-V instruction that maps to a WGSL
-  /// builtin function call.
-  /// @param inst the SPIR-V instruction
-  /// @returns an expression
-  TypedExpression MakeBuiltinCall(const spvtools::opt::Instruction& inst);
+    /// Returns the Location attribute, if it exists.
+    /// @param attributes the list of attributes to search
+    /// @returns the Location attribute, or nullptr if it doesn't exist
+    const ast::Attribute* GetLocation(const ast::AttributeList& attributes);
 
-  /// Returns an expression for a SPIR-V OpArrayLength instruction.
-  /// @param inst the SPIR-V instruction
-  /// @returns an expression
-  TypedExpression MakeArrayLength(const spvtools::opt::Instruction& inst);
+    /// Create an ast::BlockStatement representing the body of the function.
+    /// This creates the statement stack, which is non-empty for the lifetime
+    /// of the function.
+    /// @returns the body of the function, or null on error
+    const ast::BlockStatement* MakeFunctionBody();
 
-  /// Generates an expression for a SPIR-V OpOuterProduct instruction.
-  /// @param inst the SPIR-V instruction
-  /// @returns an expression
-  TypedExpression MakeOuterProduct(const spvtools::opt::Instruction& inst);
+    /// Emits the function body, populating the bottom entry of the statements
+    /// stack.
+    /// @returns false if emission failed.
+    bool EmitBody();
 
-  /// Generates statements for a SPIR-V OpVectorInsertDynamic instruction.
-  /// Registers a const declaration for the result.
-  /// @param inst the SPIR-V instruction
-  /// @returns an expression
-  bool MakeVectorInsertDynamic(const spvtools::opt::Instruction& inst);
+    /// Records a mapping from block ID to a BlockInfo struct.
+    /// Populates `block_info_`
+    void RegisterBasicBlocks();
 
-  /// Generates statements for a SPIR-V OpComposite instruction.
-  /// Registers a const declaration for the result.
-  /// @param inst the SPIR-V instruction
-  /// @returns an expression
-  bool MakeCompositeInsert(const spvtools::opt::Instruction& inst);
+    /// Verifies that terminators only branch to labels in the current function.
+    /// Assumes basic blocks have been registered.
+    /// @returns true if terminators are valid
+    bool TerminatorsAreValid();
 
-  /// Get the SPIR-V instruction for the image memory object declaration for
-  /// the image operand to the given instruction.
-  /// @param inst the SPIR-V instruction
-  /// @returns a SPIR-V OpVariable or OpFunctionParameter instruction, or null
-  /// on error
-  const spvtools::opt::Instruction* GetImage(
-      const spvtools::opt::Instruction& inst);
+    /// Populates merge-header cross-links and BlockInfo#is_continue_entire_loop.
+    /// Also verifies that merge instructions go to blocks in the same function.
+    /// Assumes basic blocks have been registered, and terminators are valid.
+    /// @returns false if registration fails
+    bool RegisterMerges();
 
-  /// Get the AST texture the SPIR-V image memory object declaration.
-  /// @param inst the SPIR-V memory object declaration for the image.
-  /// @returns a texture type, or null on error
-  const Texture* GetImageType(const spvtools::opt::Instruction& inst);
+    /// Determines the output order for the basic blocks in the function.
+    /// Populates `block_order_` and BlockInfo#pos.
+    /// Assumes basic blocks have been registered.
+    void ComputeBlockOrderAndPositions();
 
-  /// Get the expression for the image operand from the first operand to the
-  /// given instruction.
-  /// @param inst the SPIR-V instruction
-  /// @returns an identifier expression, or null on error
-  const ast::Expression* GetImageExpression(
-      const spvtools::opt::Instruction& inst);
+    /// @returns the reverse structured post order of the basic blocks in
+    /// the function.
+    const std::vector<uint32_t>& block_order() const { return block_order_; }
 
-  /// Get the expression for the sampler operand from the first operand to the
-  /// given instruction.
-  /// @param inst the SPIR-V instruction
-  /// @returns an identifier expression, or null on error
-  const ast::Expression* GetSamplerExpression(
-      const spvtools::opt::Instruction& inst);
+    /// Verifies that the orderings among a structured header, continue target,
+    /// and merge block are valid. Assumes block order has been computed, and
+    /// merges are valid and recorded.
+    /// @returns false if invalid nesting was detected
+    bool VerifyHeaderContinueMergeOrder();
 
-  /// Emits a texture builtin function call for a SPIR-V instruction that
-  /// accesses an image or sampled image.
-  /// @param inst the SPIR-V instruction
-  /// @returns an expression
-  bool EmitImageAccess(const spvtools::opt::Instruction& inst);
+    /// Labels each basic block with its nearest enclosing structured construct.
+    /// Populates BlockInfo#construct and the `constructs_` list.
+    /// Assumes terminators are valid and merges have been registered, block
+    /// order has been computed, and each block is labeled with its position.
+    /// Checks nesting of structured control flow constructs.
+    /// @returns false if bad nesting has been detected
+    bool LabelControlFlowConstructs();
 
-  /// Emits statements to implement a SPIR-V image query.
-  /// @param inst the SPIR-V instruction
-  /// @returns an expression
-  bool EmitImageQuery(const spvtools::opt::Instruction& inst);
+    /// @returns the structured constructs
+    const ConstructList& constructs() const { return constructs_; }
 
-  /// Converts the given texel to match the type required for the storage
-  /// texture with the given type. In WGSL the texel value is always provided
-  /// as a 4-element vector, but the component type is determined by the
-  /// texel channel type. See "Texel Formats for Storage Textures" in the WGSL
-  /// spec. Returns an expression, or emits an error and returns nullptr.
-  /// @param inst the image access instruction (used for diagnostics)
-  /// @param texel the texel
-  /// @param texture_type the type of the storage texture
-  /// @returns the texel, after necessary conversion.
-  const ast::Expression* ConvertTexelForStorage(
-      const spvtools::opt::Instruction& inst,
-      TypedExpression texel,
-      const Texture* texture_type);
+    /// Marks blocks targets of a switch, either as the head of a case or
+    /// as the default target.
+    /// @returns false on failure
+    bool FindSwitchCaseHeaders();
 
-  /// Returns an expression for an OpSelect, if its operands are scalars
-  /// or vectors. These translate directly to WGSL select.  Otherwise, return
-  /// an expression with a null owned expression
-  /// @param inst the SPIR-V OpSelect instruction
-  /// @returns a typed expression, or one with a null owned expression
-  TypedExpression MakeSimpleSelect(const spvtools::opt::Instruction& inst);
+    /// Classifies the successor CFG edges for the ordered basic blocks.
+    /// Also checks validity of each edge (populates BlockInfo#succ_edge).
+    /// Implicitly checks dominance rules for headers and continue constructs.
+    /// Assumes each block has been labeled with its control flow construct.
+    /// @returns false on failure
+    bool ClassifyCFGEdges();
 
-  /// Finds the header block for a structured construct that we can "break"
-  /// out from, from deeply nested control flow, if such a block exists.
-  /// If the construct is:
-  ///  - a switch selection: return the selection header (ending in OpSwitch)
-  ///  - a loop construct: return the loop header block
-  ///  - a continue construct: return the loop header block
-  /// Otherwise, return nullptr.
-  /// @param c a structured construct, or nullptr
-  /// @returns the block info for the structured header we can "break" from,
-  /// or nullptr
-  BlockInfo* HeaderIfBreakable(const Construct* c);
+    /// Marks the blocks within a selection construct that are the first blocks
+    /// in the "then" clause, the "else" clause, and the "premerge" clause.
+    /// The head of the premerge clause is the block, if it exists, at which
+    /// control flow reconverges from the "then" and "else" clauses, but before
+    /// before the merge block for that selection.   The existence of a premerge
+    /// should be an exceptional case, but is allowed by the structured control
+    /// flow rules.
+    /// @returns false if bad nesting has been detected.
+    bool FindIfSelectionInternalHeaders();
 
-  /// Appends a new statement to the top of the statement stack.
-  /// Does nothing if the statement is null.
-  /// @param statement the new statement
-  /// @returns a pointer to the statement.
-  const ast::Statement* AddStatement(const ast::Statement* statement);
+    /// Creates a DefInfo record for each module-scope builtin variable
+    /// that should be handled specially.  Either it's ignored, or its store
+    /// type is converted on load.
+    /// Populates the `def_info_` mapping for such IDs.
+    /// @returns false on failure
+    bool RegisterSpecialBuiltInVariables();
 
-  /// AddStatementBuilder() constructs and adds the StatementBuilder of type
-  /// `T` to the top of the statement stack.
-  /// @param args the arguments forwarded to the T constructor
-  /// @return the built StatementBuilder
-  template <typename T, typename... ARGS>
-  T* AddStatementBuilder(ARGS&&... args) {
-    TINT_ASSERT(Reader, !statements_stack_.empty());
-    return statements_stack_.back().AddStatementBuilder<T>(
-        std::forward<ARGS>(args)...);
-  }
+    /// Creates a DefInfo record for each locally defined SPIR-V ID.
+    /// Populates the `def_info_` mapping with basic results for such IDs.
+    /// @returns false on failure
+    bool RegisterLocallyDefinedValues();
 
-  /// Returns the source record for the given instruction.
-  /// @param inst the SPIR-V instruction
-  /// @return the Source record, or a default one
-  Source GetSourceForInst(const spvtools::opt::Instruction& inst) const;
+    /// Returns the Tint storage class for the given SPIR-V ID that is a
+    /// pointer value.
+    /// @param id a SPIR-V ID for a pointer value
+    /// @returns the storage class
+    ast::StorageClass GetStorageClassForPointerValue(uint32_t id);
 
-  /// @returns the last statetment in the top of the statement stack.
-  const ast::Statement* LastStatement();
+    /// Remaps the storage class for the type of a locally-defined value,
+    /// if necessary. If it's not a pointer type, or if its storage class
+    /// already matches, then the result is a copy of the `type` argument.
+    /// @param type the AST type
+    /// @param result_id the SPIR-V ID for the locally defined value
+    /// @returns an possibly updated type
+    const Type* RemapStorageClass(const Type* type, uint32_t result_id);
 
-  using CompletionAction = std::function<void(const ast::StatementList&)>;
+    /// Marks locally defined values when they should get a 'const'
+    /// definition in WGSL, or a 'var' definition at an outer scope.
+    /// This occurs in several cases:
+    ///  - When a SPIR-V instruction might use the dynamically computed value
+    ///    only once, but the WGSL code might reference it multiple times.
+    ///    For example, this occurs for the vector operands of OpVectorShuffle.
+    ///    In this case the definition's DefInfo#requires_named_const_def property
+    ///    is set to true.
+    ///  - When a definition and at least one of its uses are not in the
+    ///    same structured construct.
+    ///    In this case the definition's DefInfo#requires_named_const_def property
+    ///    is set to true.
+    ///  - When a definition is in a construct that does not enclose all the
+    ///    uses.  In this case the definition's DefInfo#requires_hoisted_def
+    ///    property is set to true.
+    /// Updates the `def_info_` mapping.
+    void FindValuesNeedingNamedOrHoistedDefinition();
 
-  // A StatementBlock represents a braced-list of statements while it is being
-  // constructed.
-  class StatementBlock {
-   public:
-    StatementBlock(const Construct* construct,
-                   uint32_t end_id,
-                   CompletionAction completion_action);
-    StatementBlock(StatementBlock&&);
-    ~StatementBlock();
+    /// Emits declarations of function variables.
+    /// @returns false if emission failed.
+    bool EmitFunctionVariables();
 
-    StatementBlock(const StatementBlock&) = delete;
-    StatementBlock& operator=(const StatementBlock&) = delete;
+    /// Emits statements in the body.
+    /// @returns false if emission failed.
+    bool EmitFunctionBodyStatements();
 
-    /// Replaces any StatementBuilders with the built result, and calls the
-    /// completion callback (if set). Must only be called once, after all
-    /// statements have been added with Add().
-    /// @param builder the program builder
-    void Finalize(ProgramBuilder* builder);
+    /// Emits a basic block.
+    /// @param block_info the block to emit
+    /// @returns false if emission failed.
+    bool EmitBasicBlock(const BlockInfo& block_info);
 
-    /// Add() adds `statement` to the block.
-    /// Add() must not be called after calling Finalize().
-    void Add(const ast::Statement* statement);
+    /// Emits an IfStatement, including its condition expression, and sets
+    /// up the statement stack to accumulate subsequent basic blocks into
+    /// the "then" and "else" clauses.
+    /// @param block_info the if-selection header block
+    /// @returns false if emission failed.
+    bool EmitIfStart(const BlockInfo& block_info);
+
+    /// Emits a SwitchStatement, including its condition expression, and sets
+    /// up the statement stack to accumulate subsequent basic blocks into
+    /// the default clause and case clauses.
+    /// @param block_info the switch-selection header block
+    /// @returns false if emission failed.
+    bool EmitSwitchStart(const BlockInfo& block_info);
+
+    /// Emits a LoopStatement, and pushes a new StatementBlock to accumulate
+    /// the remaining instructions in the current block and subsequent blocks
+    /// in the loop.
+    /// @param construct the loop construct
+    /// @returns false if emission failed.
+    bool EmitLoopStart(const Construct* construct);
+
+    /// Emits a ContinuingStatement, and pushes a new StatementBlock to accumulate
+    /// the remaining instructions in the current block and subsequent blocks
+    /// in the continue construct.
+    /// @param construct the continue construct
+    /// @returns false if emission failed.
+    bool EmitContinuingStart(const Construct* construct);
+
+    /// Emits the non-control-flow parts of a basic block, but only once.
+    /// The `already_emitted` parameter indicates whether the code has already
+    /// been emitted, and is used to signal that this invocation actually emitted
+    /// it.
+    /// @param block_info the block to emit
+    /// @param already_emitted the block to emit
+    /// @returns false if the code had not yet been emitted, but emission failed
+    bool EmitStatementsInBasicBlock(const BlockInfo& block_info, bool* already_emitted);
+
+    /// Emits code for terminators, but that aren't part of entering or
+    /// resolving structured control flow. That is, if the basic block
+    /// terminator calls for it, emit the fallthrough, break, continue, return,
+    /// or kill commands.
+    /// @param block_info the block with the terminator to emit (if any)
+    /// @returns false if emission failed
+    bool EmitNormalTerminator(const BlockInfo& block_info);
+
+    /// Returns a new statement to represent the given branch representing a
+    /// "normal" terminator, as in the sense of EmitNormalTerminator.  If no
+    /// WGSL statement is required, the statement will be nullptr. This method
+    /// tries to avoid emitting a 'break' statement when that would be redundant
+    /// in WGSL due to implicit breaking out of a switch.
+    /// @param src_info the source block
+    /// @param dest_info the destination block
+    /// @returns the new statement, or a null statement
+    const ast::Statement* MakeBranch(const BlockInfo& src_info, const BlockInfo& dest_info) const {
+        return MakeBranchDetailed(src_info, dest_info, false, nullptr);
+    }
+
+    /// Returns a new statement to represent the given branch representing a
+    /// "normal" terminator, as in the sense of EmitNormalTerminator.  If no
+    /// WGSL statement is required, the statement will be nullptr.
+    /// @param src_info the source block
+    /// @param dest_info the destination block
+    /// @returns the new statement, or a null statement
+    const ast::Statement* MakeForcedBranch(const BlockInfo& src_info,
+                                           const BlockInfo& dest_info) const {
+        return MakeBranchDetailed(src_info, dest_info, true, nullptr);
+    }
+
+    /// Returns a new statement to represent the given branch representing a
+    /// "normal" terminator, as in the sense of EmitNormalTerminator.  If no
+    /// WGSL statement is required, the statement will be nullptr. When `forced`
+    /// is false, this method tries to avoid emitting a 'break' statement when
+    /// that would be redundant in WGSL due to implicit breaking out of a switch.
+    /// When `forced` is true, the method won't try to avoid emitting that break.
+    /// If the control flow edge is an if-break for an if-selection with a
+    /// control flow guard, then return that guard name via `flow_guard_name_ptr`
+    /// when that parameter is not null.
+    /// @param src_info the source block
+    /// @param dest_info the destination block
+    /// @param forced if true, always emit the branch (if it exists in WGSL)
+    /// @param flow_guard_name_ptr return parameter for control flow guard name
+    /// @returns the new statement, or a null statement
+    const ast::Statement* MakeBranchDetailed(const BlockInfo& src_info,
+                                             const BlockInfo& dest_info,
+                                             bool forced,
+                                             std::string* flow_guard_name_ptr) const;
+
+    /// Returns a new if statement with the given statements as the then-clause
+    /// and the else-clause.  Either or both clauses might be nullptr. If both
+    /// are nullptr, then don't make a new statement and instead return nullptr.
+    /// @param condition the branching condition
+    /// @param then_stmt the statement for the then clause of the if, or nullptr
+    /// @param else_stmt the statement for the else clause of the if, or nullptr
+    /// @returns the new statement, or nullptr
+    const ast::Statement* MakeSimpleIf(const ast::Expression* condition,
+                                       const ast::Statement* then_stmt,
+                                       const ast::Statement* else_stmt) const;
+
+    /// Emits the statements for an normal-terminator OpBranchConditional
+    /// where one branch is a case fall through (the true branch if and only
+    /// if `fall_through_is_true_branch` is true), and the other branch is
+    /// goes to a different destination, named by `other_dest`.
+    /// @param src_info the basic block from which we're branching
+    /// @param cond the branching condition
+    /// @param other_edge_kind the edge kind from the source block to the other
+    /// destination
+    /// @param other_dest the other branching destination
+    /// @param fall_through_is_true_branch true when the fall-through is the true
+    /// branch
+    /// @returns the false if emission fails
+    bool EmitConditionalCaseFallThrough(const BlockInfo& src_info,
+                                        const ast::Expression* cond,
+                                        EdgeKind other_edge_kind,
+                                        const BlockInfo& other_dest,
+                                        bool fall_through_is_true_branch);
+
+    /// Emits a normal instruction: not a terminator, label, or variable
+    /// declaration.
+    /// @param inst the instruction
+    /// @returns false if emission failed.
+    bool EmitStatement(const spvtools::opt::Instruction& inst);
+
+    /// Emits a const definition for the typed value in `ast_expr`, and
+    /// records it as the translation for the result ID from `inst`.
+    /// @param inst the SPIR-V instruction defining the value
+    /// @param ast_expr the already-computed AST expression for the value
+    /// @returns false if emission failed.
+    bool EmitConstDefinition(const spvtools::opt::Instruction& inst, TypedExpression ast_expr);
+
+    /// Emits a write of the typed value in `ast_expr` to a hoisted variable
+    /// for the given SPIR-V ID, if that ID has a hoisted declaration. Otherwise,
+    /// emits a const definition instead.
+    /// @param inst the SPIR-V instruction defining the value
+    /// @param ast_expr the already-computed AST expression for the value
+    /// @returns false if emission failed.
+    bool EmitConstDefOrWriteToHoistedVar(const spvtools::opt::Instruction& inst,
+                                         TypedExpression ast_expr);
+
+    /// If the result ID of the given instruction is hoisted, then emits
+    /// a statement to write the expression to the hoisted variable, and
+    /// returns true.  Otherwise return false.
+    /// @param inst the SPIR-V instruction defining a value.
+    /// @param ast_expr the expression to assign.
+    /// @returns true if the instruction has an associated hoisted variable.
+    bool WriteIfHoistedVar(const spvtools::opt::Instruction& inst, TypedExpression ast_expr);
+
+    /// Makes an expression from a SPIR-V ID.
+    /// if the SPIR-V result type is a pointer.
+    /// @param id the SPIR-V ID of the value
+    /// @returns an AST expression for the instruction, or an invalid
+    /// TypedExpression on error.
+    TypedExpression MakeExpression(uint32_t id);
+
+    /// Creates an expression and supporting statements for a combinatorial
+    /// instruction, or returns null.  A SPIR-V instruction is combinatorial
+    /// if it has no side effects and its result depends only on its operands,
+    /// and not on accessing external state like memory or the state of other
+    /// invocations.  Statements are only created if required to provide values
+    /// to the expression. Supporting statements are not required to be
+    /// combinatorial.
+    /// @param inst a SPIR-V instruction representing an exrpression
+    /// @returns an AST expression for the instruction, or nullptr.
+    TypedExpression MaybeEmitCombinatorialValue(const spvtools::opt::Instruction& inst);
+
+    /// Creates an expression and supporting statements for the a GLSL.std.450
+    /// extended instruction.
+    /// @param inst a SPIR-V OpExtInst instruction from GLSL.std.450
+    /// @returns an AST expression for the instruction, or nullptr.
+    TypedExpression EmitGlslStd450ExtInst(const spvtools::opt::Instruction& inst);
+
+    /// Creates an expression for OpCompositeExtract
+    /// @param inst an OpCompositeExtract instruction.
+    /// @returns an AST expression for the instruction, or nullptr.
+    TypedExpression MakeCompositeExtract(const spvtools::opt::Instruction& inst);
+
+    /// Creates an expression for indexing into a composite value.  The literal
+    /// indices that step into the value start at instruction input operand
+    /// `start_index` and run to the end of the instruction.
+    /// @param inst the original instruction
+    /// @param composite the typed expression for the composite
+    /// @param composite_type_id the SPIR-V type ID for the composite
+    /// @param index_start the index of the first operand in `inst` that is an
+    /// index into the composite type
+    /// @returns an AST expression for the decomposed composite, or {} on error
+    TypedExpression MakeCompositeValueDecomposition(const spvtools::opt::Instruction& inst,
+                                                    TypedExpression composite,
+                                                    uint32_t composite_type_id,
+                                                    int index_start);
+
+    /// Creates an expression for OpVectorShuffle
+    /// @param inst an OpVectorShuffle instruction.
+    /// @returns an AST expression for the instruction, or nullptr.
+    TypedExpression MakeVectorShuffle(const spvtools::opt::Instruction& inst);
+
+    /// Creates an expression for a numeric conversion.
+    /// @param inst a numeric conversion instruction
+    /// @returns an AST expression for the instruction, or nullptr.
+    TypedExpression MakeNumericConversion(const spvtools::opt::Instruction& inst);
+
+    /// Gets the block info for a block ID, if any exists
+    /// @param id the SPIR-V ID of the OpLabel instruction starting the block
+    /// @returns the block info for the given ID, if it exists, or nullptr
+    BlockInfo* GetBlockInfo(uint32_t id) const {
+        auto where = block_info_.find(id);
+        if (where == block_info_.end()) {
+            return nullptr;
+        }
+        return where->second.get();
+    }
+
+    /// Is the block, represented by info, in the structured block order?
+    /// @param info the block
+    /// @returns true if the block is in the structured block order.
+    bool IsInBlockOrder(const BlockInfo* info) const {
+        return info && info->pos != kInvalidBlockPos;
+    }
+
+    /// Gets the local definition info for a result ID.
+    /// @param id the SPIR-V ID of local definition.
+    /// @returns the definition info for the given ID, if it exists, or nullptr
+    DefInfo* GetDefInfo(uint32_t id) const {
+        auto where = def_info_.find(id);
+        if (where == def_info_.end()) {
+            return nullptr;
+        }
+        return where->second.get();
+    }
+    /// Returns the skip reason for a result ID.
+    /// @param id SPIR-V result ID
+    /// @returns the skip reason for the given ID, or SkipReason::kDontSkip
+    SkipReason GetSkipReason(uint32_t id) const {
+        if (auto* def_info = GetDefInfo(id)) {
+            return def_info->skip;
+        }
+        return SkipReason::kDontSkip;
+    }
+
+    /// Returns the most deeply nested structured construct which encloses the
+    /// WGSL scopes of names declared in both block positions. Each position must
+    /// be a valid index into the function block order array.
+    /// @param first_pos the first block position
+    /// @param last_pos the last block position
+    /// @returns the smallest construct containing both positions
+    const Construct* GetEnclosingScope(uint32_t first_pos, uint32_t last_pos) const;
+
+    /// Finds loop construct associated with a continue construct, if it exists.
+    /// Returns nullptr if:
+    ///  - the given construct is not a continue construct
+    ///  - the continue construct does not have an associated loop construct
+    ///    (the continue target is also the loop header block)
+    /// @param c the continue construct
+    /// @returns the associated loop construct, or nullptr
+    const Construct* SiblingLoopConstruct(const Construct* c) const;
+
+    /// Returns an identifier expression for the swizzle name of the given
+    /// index into a vector.  Emits an error and returns nullptr if the
+    /// index is out of range, i.e. 4 or higher.
+    /// @param i index of the subcomponent
+    /// @returns the identifier expression for the `i`'th component
+    ast::IdentifierExpression* Swizzle(uint32_t i);
+
+    /// Returns an identifier expression for the swizzle name of the first
+    /// `n` elements of a vector.  Emits an error and returns nullptr if `n`
+    /// is out of range, i.e. 4 or higher.
+    /// @param n the number of components in the swizzle
+    /// @returns the swizzle identifier for the first n elements of a vector
+    ast::IdentifierExpression* PrefixSwizzle(uint32_t n);
+
+    /// Converts SPIR-V image coordinates from an image access instruction
+    /// (e.g. OpImageSampledImplicitLod) into an expression list consisting of
+    /// the texture coordinates, and an integral array index if the texture is
+    /// arrayed. The texture coordinate is a scalar for 1D textures, a vector of
+    /// 2 elements for a 2D texture, and a vector of 3 elements for a 3D or
+    /// Cube texture. Excess components are ignored, e.g. if the SPIR-V
+    /// coordinate is a 4-element vector but the image is a 2D non-arrayed
+    /// texture then the 3rd and 4th components are ignored.
+    /// On failure, issues an error and returns an empty expression list.
+    /// @param image_access the image access instruction
+    /// @returns an ExpressionList of the coordinate and array index (if any)
+    ast::ExpressionList MakeCoordinateOperandsForImageAccess(
+        const spvtools::opt::Instruction& image_access);
+
+    /// Returns the given value as an I32.  If it's already an I32 then this
+    /// return the given value.  Otherwise, wrap the value in a TypeConstructor
+    /// expression.
+    /// @param value the value to pass through or convert
+    /// @returns the value as an I32 value.
+    TypedExpression ToI32(TypedExpression value);
+
+    /// Returns the given value as a signed integer type of the same shape
+    /// if the value is unsigned scalar or vector, by wrapping the value
+    /// with a TypeConstructor expression.  Returns the value itself if the
+    /// value otherwise.
+    /// @param value the value to pass through or convert
+    /// @returns the value itself, or converted to signed integral
+    TypedExpression ToSignedIfUnsigned(TypedExpression value);
+
+    /// @param value_id the value identifier to check
+    /// @returns true if the given SPIR-V id represents a constant float 0.
+    bool IsFloatZero(uint32_t value_id);
+    /// @param value_id the value identifier to check
+    /// @returns true if the given SPIR-V id represents a constant float 1.
+    bool IsFloatOne(uint32_t value_id);
+
+  private:
+    /// FunctionDeclaration contains the parsed information for a function header.
+    struct FunctionDeclaration {
+        /// Constructor
+        FunctionDeclaration();
+        /// Destructor
+        ~FunctionDeclaration();
+
+        /// Parsed header source
+        Source source;
+        /// Function name
+        std::string name;
+        /// Function parameters
+        ast::VariableList params;
+        /// Function return type
+        const Type* return_type;
+        /// Function attributes
+        ast::AttributeList attributes;
+    };
+
+    /// Parse the function declaration, which comprises the name, parameters, and
+    /// return type, populating `decl`.
+    /// @param decl the FunctionDeclaration to populate
+    /// @returns true if emission has not yet failed.
+    bool ParseFunctionDeclaration(FunctionDeclaration* decl);
+
+    /// @returns the store type for the OpVariable instruction, or
+    /// null on failure.
+    const Type* GetVariableStoreType(const spvtools::opt::Instruction& var_decl_inst);
+
+    /// Returns an expression for an instruction operand. Signedness conversion is
+    /// performed to match the result type of the SPIR-V instruction.
+    /// @param inst the SPIR-V instruction
+    /// @param operand_index the index of the operand, counting 0 as the first
+    /// input operand
+    /// @returns a new expression node
+    TypedExpression MakeOperand(const spvtools::opt::Instruction& inst, uint32_t operand_index);
+
+    /// Copies a typed expression to the result, but when the type is a pointer
+    /// or reference type, ensures the storage class is not defaulted.  That is,
+    /// it changes a storage class of "none" to "function".
+    /// @param expr a typed expression
+    /// @results a copy of the expression, with possibly updated type
+    TypedExpression InferFunctionStorageClass(TypedExpression expr);
+
+    /// Returns an expression for a SPIR-V OpFMod instruction.
+    /// @param inst the SPIR-V instruction
+    /// @returns an expression
+    TypedExpression MakeFMod(const spvtools::opt::Instruction& inst);
+
+    /// Returns an expression for a SPIR-V OpAccessChain or OpInBoundsAccessChain
+    /// instruction.
+    /// @param inst the SPIR-V instruction
+    /// @returns an expression
+    TypedExpression MakeAccessChain(const spvtools::opt::Instruction& inst);
+
+    /// Emits a function call.  On failure, emits a diagnostic and returns false.
+    /// @param inst the SPIR-V function call instruction
+    /// @returns false if emission failed
+    bool EmitFunctionCall(const spvtools::opt::Instruction& inst);
+
+    /// Emits a control barrier builtin.  On failure, emits a diagnostic and
+    /// returns false.
+    /// @param inst the SPIR-V control barrier instruction
+    /// @returns false if emission failed
+    bool EmitControlBarrier(const spvtools::opt::Instruction& inst);
+
+    /// Returns an expression for a SPIR-V instruction that maps to a WGSL
+    /// builtin function call.
+    /// @param inst the SPIR-V instruction
+    /// @returns an expression
+    TypedExpression MakeBuiltinCall(const spvtools::opt::Instruction& inst);
+
+    /// Returns an expression for a SPIR-V OpArrayLength instruction.
+    /// @param inst the SPIR-V instruction
+    /// @returns an expression
+    TypedExpression MakeArrayLength(const spvtools::opt::Instruction& inst);
+
+    /// Generates an expression for a SPIR-V OpOuterProduct instruction.
+    /// @param inst the SPIR-V instruction
+    /// @returns an expression
+    TypedExpression MakeOuterProduct(const spvtools::opt::Instruction& inst);
+
+    /// Generates statements for a SPIR-V OpVectorInsertDynamic instruction.
+    /// Registers a const declaration for the result.
+    /// @param inst the SPIR-V instruction
+    /// @returns an expression
+    bool MakeVectorInsertDynamic(const spvtools::opt::Instruction& inst);
+
+    /// Generates statements for a SPIR-V OpComposite instruction.
+    /// Registers a const declaration for the result.
+    /// @param inst the SPIR-V instruction
+    /// @returns an expression
+    bool MakeCompositeInsert(const spvtools::opt::Instruction& inst);
+
+    /// Get the SPIR-V instruction for the image memory object declaration for
+    /// the image operand to the given instruction.
+    /// @param inst the SPIR-V instruction
+    /// @returns a SPIR-V OpVariable or OpFunctionParameter instruction, or null
+    /// on error
+    const spvtools::opt::Instruction* GetImage(const spvtools::opt::Instruction& inst);
+
+    /// Get the AST texture the SPIR-V image memory object declaration.
+    /// @param inst the SPIR-V memory object declaration for the image.
+    /// @returns a texture type, or null on error
+    const Texture* GetImageType(const spvtools::opt::Instruction& inst);
+
+    /// Get the expression for the image operand from the first operand to the
+    /// given instruction.
+    /// @param inst the SPIR-V instruction
+    /// @returns an identifier expression, or null on error
+    const ast::Expression* GetImageExpression(const spvtools::opt::Instruction& inst);
+
+    /// Get the expression for the sampler operand from the first operand to the
+    /// given instruction.
+    /// @param inst the SPIR-V instruction
+    /// @returns an identifier expression, or null on error
+    const ast::Expression* GetSamplerExpression(const spvtools::opt::Instruction& inst);
+
+    /// Emits a texture builtin function call for a SPIR-V instruction that
+    /// accesses an image or sampled image.
+    /// @param inst the SPIR-V instruction
+    /// @returns an expression
+    bool EmitImageAccess(const spvtools::opt::Instruction& inst);
+
+    /// Emits statements to implement a SPIR-V image query.
+    /// @param inst the SPIR-V instruction
+    /// @returns an expression
+    bool EmitImageQuery(const spvtools::opt::Instruction& inst);
+
+    /// Converts the given texel to match the type required for the storage
+    /// texture with the given type. In WGSL the texel value is always provided
+    /// as a 4-element vector, but the component type is determined by the
+    /// texel channel type. See "Texel Formats for Storage Textures" in the WGSL
+    /// spec. Returns an expression, or emits an error and returns nullptr.
+    /// @param inst the image access instruction (used for diagnostics)
+    /// @param texel the texel
+    /// @param texture_type the type of the storage texture
+    /// @returns the texel, after necessary conversion.
+    const ast::Expression* ConvertTexelForStorage(const spvtools::opt::Instruction& inst,
+                                                  TypedExpression texel,
+                                                  const Texture* texture_type);
+
+    /// Returns an expression for an OpSelect, if its operands are scalars
+    /// or vectors. These translate directly to WGSL select.  Otherwise, return
+    /// an expression with a null owned expression
+    /// @param inst the SPIR-V OpSelect instruction
+    /// @returns a typed expression, or one with a null owned expression
+    TypedExpression MakeSimpleSelect(const spvtools::opt::Instruction& inst);
+
+    /// Finds the header block for a structured construct that we can "break"
+    /// out from, from deeply nested control flow, if such a block exists.
+    /// If the construct is:
+    ///  - a switch selection: return the selection header (ending in OpSwitch)
+    ///  - a loop construct: return the loop header block
+    ///  - a continue construct: return the loop header block
+    /// Otherwise, return nullptr.
+    /// @param c a structured construct, or nullptr
+    /// @returns the block info for the structured header we can "break" from,
+    /// or nullptr
+    BlockInfo* HeaderIfBreakable(const Construct* c);
+
+    /// Appends a new statement to the top of the statement stack.
+    /// Does nothing if the statement is null.
+    /// @param statement the new statement
+    /// @returns a pointer to the statement.
+    const ast::Statement* AddStatement(const ast::Statement* statement);
 
     /// AddStatementBuilder() constructs and adds the StatementBuilder of type
-    /// `T` to the block.
-    /// Add() must not be called after calling Finalize().
+    /// `T` to the top of the statement stack.
     /// @param args the arguments forwarded to the T constructor
     /// @return the built StatementBuilder
     template <typename T, typename... ARGS>
     T* AddStatementBuilder(ARGS&&... args) {
-      auto builder = std::make_unique<T>(std::forward<ARGS>(args)...);
-      auto* ptr = builder.get();
-      Add(ptr);
-      builders_.emplace_back(std::move(builder));
-      return ptr;
+        TINT_ASSERT(Reader, !statements_stack_.empty());
+        return statements_stack_.back().AddStatementBuilder<T>(std::forward<ARGS>(args)...);
     }
 
-    /// @param construct the construct which this construct constributes to
-    void SetConstruct(const Construct* construct) { construct_ = construct; }
+    /// Returns the source record for the given instruction.
+    /// @param inst the SPIR-V instruction
+    /// @return the Source record, or a default one
+    Source GetSourceForInst(const spvtools::opt::Instruction& inst) const;
 
-    /// @return the construct to which this construct constributes
-    const Construct* GetConstruct() const { return construct_; }
+    /// @returns the last statetment in the top of the statement stack.
+    const ast::Statement* LastStatement();
 
-    /// @return the ID of the block at which the completion action should be
-    /// triggered and this statement block discarded. This is often the `end_id`
-    /// of `construct` itself.
-    uint32_t GetEndId() const { return end_id_; }
+    using CompletionAction = std::function<void(const ast::StatementList&)>;
 
-    /// @return the list of statements being built, if this construct is not a
-    /// switch.
-    const ast::StatementList& GetStatements() const { return statements_; }
+    // A StatementBlock represents a braced-list of statements while it is being
+    // constructed.
+    class StatementBlock {
+      public:
+        StatementBlock(const Construct* construct,
+                       uint32_t end_id,
+                       CompletionAction completion_action);
+        StatementBlock(StatementBlock&&);
+        ~StatementBlock();
 
-   private:
-    /// The construct to which this construct constributes.
-    const Construct* construct_;
-    /// The ID of the block at which the completion action should be triggered
-    /// and this statement block discarded. This is often the `end_id` of
-    /// `construct` itself.
-    const uint32_t end_id_;
-    /// The completion action finishes processing this statement block.
-    FunctionEmitter::CompletionAction const completion_action_;
-    /// The list of statements being built, if this construct is not a switch.
-    ast::StatementList statements_;
+        StatementBlock(const StatementBlock&) = delete;
+        StatementBlock& operator=(const StatementBlock&) = delete;
 
-    /// Owned statement builders
-    std::vector<std::unique_ptr<StatementBuilder>> builders_;
-    /// True if Finalize() has been called.
-    bool finalized_ = false;
-  };
+        /// Replaces any StatementBuilders with the built result, and calls the
+        /// completion callback (if set). Must only be called once, after all
+        /// statements have been added with Add().
+        /// @param builder the program builder
+        void Finalize(ProgramBuilder* builder);
 
-  /// Pushes an empty statement block onto the statements stack.
-  /// @param action the completion action for this block
-  void PushNewStatementBlock(const Construct* construct,
-                             uint32_t end_id,
-                             CompletionAction action);
+        /// Add() adds `statement` to the block.
+        /// Add() must not be called after calling Finalize().
+        void Add(const ast::Statement* statement);
 
-  /// Emits an if-statement whose condition is the given flow guard
-  /// variable, and pushes onto the statement stack the corresponding
-  /// statement block ending (and not including) the given block.
-  /// @param flow_guard name of the flow guard variable
-  /// @param end_id first block after the if construct.
-  void PushGuard(const std::string& flow_guard, uint32_t end_id);
+        /// AddStatementBuilder() constructs and adds the StatementBuilder of type
+        /// `T` to the block.
+        /// Add() must not be called after calling Finalize().
+        /// @param args the arguments forwarded to the T constructor
+        /// @return the built StatementBuilder
+        template <typename T, typename... ARGS>
+        T* AddStatementBuilder(ARGS&&... args) {
+            auto builder = std::make_unique<T>(std::forward<ARGS>(args)...);
+            auto* ptr = builder.get();
+            Add(ptr);
+            builders_.emplace_back(std::move(builder));
+            return ptr;
+        }
 
-  /// Emits an if-statement with 'true' condition, and pushes onto the
-  /// statement stack the corresponding statement block ending (and not
-  /// including) the given block.
-  /// @param end_id first block after the if construct.
-  void PushTrueGuard(uint32_t end_id);
+        /// @param construct the construct which this construct constributes to
+        void SetConstruct(const Construct* construct) { construct_ = construct; }
 
-  /// @returns a boolean true expression.
-  const ast::Expression* MakeTrue(const Source&) const;
+        /// @return the construct to which this construct constributes
+        const Construct* GetConstruct() const { return construct_; }
 
-  /// @returns a boolean false expression.
-  const ast::Expression* MakeFalse(const Source&) const;
+        /// @return the ID of the block at which the completion action should be
+        /// triggered and this statement block discarded. This is often the `end_id`
+        /// of `construct` itself.
+        uint32_t GetEndId() const { return end_id_; }
 
-  /// @param expr the expression to take the address of
-  /// @returns a TypedExpression that is the address-of `expr` (`&expr`)
-  /// @note `expr` must be a reference type
-  TypedExpression AddressOf(TypedExpression expr);
+        /// @return the list of statements being built, if this construct is not a
+        /// switch.
+        const ast::StatementList& GetStatements() const { return statements_; }
 
-  /// Returns AddressOf(expr) if expr is has reference type and
-  /// the instruction has a pointer result type.  Otherwise returns expr.
-  /// @param expr the expression to take the address of
-  /// @returns a TypedExpression that is the address-of `expr` (`&expr`)
-  /// @note `expr` must be a reference type
-  TypedExpression AddressOfIfNeeded(TypedExpression expr,
-                                    const spvtools::opt::Instruction* inst);
+      private:
+        /// The construct to which this construct constributes.
+        const Construct* construct_;
+        /// The ID of the block at which the completion action should be triggered
+        /// and this statement block discarded. This is often the `end_id` of
+        /// `construct` itself.
+        const uint32_t end_id_;
+        /// The completion action finishes processing this statement block.
+        FunctionEmitter::CompletionAction const completion_action_;
+        /// The list of statements being built, if this construct is not a switch.
+        ast::StatementList statements_;
 
-  /// @param expr the expression to dereference
-  /// @returns a TypedExpression that is the dereference-of `expr` (`*expr`)
-  /// @note `expr` must be a pointer type
-  TypedExpression Dereference(TypedExpression expr);
+        /// Owned statement builders
+        std::vector<std::unique_ptr<StatementBuilder>> builders_;
+        /// True if Finalize() has been called.
+        bool finalized_ = false;
+    };
 
-  /// Creates a new `ast::Node` owned by the ProgramBuilder.
-  /// @param args the arguments to pass to the type constructor
-  /// @returns the node pointer
-  template <typename T, typename... ARGS>
-  T* create(ARGS&&... args) const {
-    return builder_.create<T>(std::forward<ARGS>(args)...);
-  }
+    /// Pushes an empty statement block onto the statements stack.
+    /// @param action the completion action for this block
+    void PushNewStatementBlock(const Construct* construct,
+                               uint32_t end_id,
+                               CompletionAction action);
 
-  using StatementsStack = std::vector<StatementBlock>;
-  using PtrAs = ParserImpl::PtrAs;
+    /// Emits an if-statement whose condition is the given flow guard
+    /// variable, and pushes onto the statement stack the corresponding
+    /// statement block ending (and not including) the given block.
+    /// @param flow_guard name of the flow guard variable
+    /// @param end_id first block after the if construct.
+    void PushGuard(const std::string& flow_guard, uint32_t end_id);
 
-  ParserImpl& parser_impl_;
-  TypeManager& ty_;
-  ProgramBuilder& builder_;
-  spvtools::opt::IRContext& ir_context_;
-  spvtools::opt::analysis::DefUseManager* def_use_mgr_;
-  spvtools::opt::analysis::ConstantManager* constant_mgr_;
-  spvtools::opt::analysis::TypeManager* type_mgr_;
-  FailStream& fail_stream_;
-  Namer& namer_;
-  const spvtools::opt::Function& function_;
+    /// Emits an if-statement with 'true' condition, and pushes onto the
+    /// statement stack the corresponding statement block ending (and not
+    /// including) the given block.
+    /// @param end_id first block after the if construct.
+    void PushTrueGuard(uint32_t end_id);
 
-  // The SPIR-V ID for the SampleMask input variable.
-  uint32_t sample_mask_in_id;
-  // The SPIR-V ID for the SampleMask output variable.
-  uint32_t sample_mask_out_id;
+    /// @returns a boolean true expression.
+    const ast::Expression* MakeTrue(const Source&) const;
 
-  // A stack of statement lists. Each list is contained in a construct in
-  // the next deeper element of stack. The 0th entry represents the statements
-  // for the entire function.  This stack is never empty.
-  // The `construct` member for the 0th element is only valid during the
-  // lifetime of the EmitFunctionBodyStatements method.
-  StatementsStack statements_stack_;
+    /// @returns a boolean false expression.
+    const ast::Expression* MakeFalse(const Source&) const;
 
-  // The map of IDs that have already had an identifier name generated for it,
-  // to their Type.
-  std::unordered_map<uint32_t, const Type*> identifier_types_;
-  // Mapping from SPIR-V ID that is used at most once, to its AST expression.
-  std::unordered_map<uint32_t, TypedExpression> singly_used_values_;
+    /// @param expr the expression to take the address of
+    /// @returns a TypedExpression that is the address-of `expr` (`&expr`)
+    /// @note `expr` must be a reference type
+    TypedExpression AddressOf(TypedExpression expr);
 
-  // The IDs of basic blocks, in reverse structured post-order (RSPO).
-  // This is the output order for the basic blocks.
-  std::vector<uint32_t> block_order_;
+    /// Returns AddressOf(expr) if expr is has reference type and
+    /// the instruction has a pointer result type.  Otherwise returns expr.
+    /// @param expr the expression to take the address of
+    /// @returns a TypedExpression that is the address-of `expr` (`&expr`)
+    /// @note `expr` must be a reference type
+    TypedExpression AddressOfIfNeeded(TypedExpression expr, const spvtools::opt::Instruction* inst);
 
-  // Mapping from block ID to its bookkeeping info.
-  std::unordered_map<uint32_t, std::unique_ptr<BlockInfo>> block_info_;
+    /// @param expr the expression to dereference
+    /// @returns a TypedExpression that is the dereference-of `expr` (`*expr`)
+    /// @note `expr` must be a pointer type
+    TypedExpression Dereference(TypedExpression expr);
 
-  // Mapping from a locally-defined result ID to its bookkeeping info.
-  std::unordered_map<uint32_t, std::unique_ptr<DefInfo>> def_info_;
+    /// Creates a new `ast::Node` owned by the ProgramBuilder.
+    /// @param args the arguments to pass to the type constructor
+    /// @returns the node pointer
+    template <typename T, typename... ARGS>
+    T* create(ARGS&&... args) const {
+        return builder_.create<T>(std::forward<ARGS>(args)...);
+    }
 
-  // Structured constructs, where enclosing constructs precede their children.
-  ConstructList constructs_;
+    using StatementsStack = std::vector<StatementBlock>;
+    using PtrAs = ParserImpl::PtrAs;
 
-  // Information about entry point, if this function is referenced by one
-  const EntryPointInfo* ep_info_ = nullptr;
+    ParserImpl& parser_impl_;
+    TypeManager& ty_;
+    ProgramBuilder& builder_;
+    spvtools::opt::IRContext& ir_context_;
+    spvtools::opt::analysis::DefUseManager* def_use_mgr_;
+    spvtools::opt::analysis::ConstantManager* constant_mgr_;
+    spvtools::opt::analysis::TypeManager* type_mgr_;
+    FailStream& fail_stream_;
+    Namer& namer_;
+    const spvtools::opt::Function& function_;
+
+    // The SPIR-V ID for the SampleMask input variable.
+    uint32_t sample_mask_in_id;
+    // The SPIR-V ID for the SampleMask output variable.
+    uint32_t sample_mask_out_id;
+
+    // A stack of statement lists. Each list is contained in a construct in
+    // the next deeper element of stack. The 0th entry represents the statements
+    // for the entire function.  This stack is never empty.
+    // The `construct` member for the 0th element is only valid during the
+    // lifetime of the EmitFunctionBodyStatements method.
+    StatementsStack statements_stack_;
+
+    // The map of IDs that have already had an identifier name generated for it,
+    // to their Type.
+    std::unordered_map<uint32_t, const Type*> identifier_types_;
+    // Mapping from SPIR-V ID that is used at most once, to its AST expression.
+    std::unordered_map<uint32_t, TypedExpression> singly_used_values_;
+
+    // The IDs of basic blocks, in reverse structured post-order (RSPO).
+    // This is the output order for the basic blocks.
+    std::vector<uint32_t> block_order_;
+
+    // Mapping from block ID to its bookkeeping info.
+    std::unordered_map<uint32_t, std::unique_ptr<BlockInfo>> block_info_;
+
+    // Mapping from a locally-defined result ID to its bookkeeping info.
+    std::unordered_map<uint32_t, std::unique_ptr<DefInfo>> def_info_;
+
+    // Structured constructs, where enclosing constructs precede their children.
+    ConstructList constructs_;
+
+    // Information about entry point, if this function is referenced by one
+    const EntryPointInfo* ep_info_ = nullptr;
 };
 
 }  // namespace tint::reader::spirv
diff --git a/src/tint/reader/spirv/function_arithmetic_test.cc b/src/tint/reader/spirv/function_arithmetic_test.cc
index c48f86d..9db49d9 100644
--- a/src/tint/reader/spirv/function_arithmetic_test.cc
+++ b/src/tint/reader/spirv/function_arithmetic_test.cc
@@ -23,7 +23,7 @@
 using ::testing::HasSubstr;
 
 std::string Preamble() {
-  return R"(
+    return R"(
   OpCapability Shader
   OpMemoryModel Logical Simple
   OpEntryPoint Fragment %100 "main"
@@ -74,317 +74,283 @@
 
 // Returns the AST dump for a given SPIR-V assembly constant.
 std::string AstFor(std::string assembly) {
-  if (assembly == "v2uint_10_20") {
-    return "vec2<u32>(10u, 20u)";
-  }
-  if (assembly == "v2uint_20_10") {
-    return "vec2<u32>(20u, 10u)";
-  }
-  if (assembly == "v2int_30_40") {
-    return "vec2<i32>(30, 40)";
-  }
-  if (assembly == "v2int_40_30") {
-    return "vec2<i32>(40, 30)";
-  }
-  if (assembly == "cast_int_v2uint_10_20") {
-    return "bitcast<vec2<i32>>(vec2<u32>(10u, 20u))";
-  }
-  if (assembly == "cast_uint_v2int_40_30") {
-    return "bitcast<vec2<u32>>(vec2<i32>(40, 30))";
-  }
-  if (assembly == "v2float_50_60") {
-    return "vec2<f32>(50.0, 60.0)";
-  }
-  if (assembly == "v2float_60_50") {
-    return "vec2<f32>(60.0, 50.0)";
-  }
-  return "bad case";
+    if (assembly == "v2uint_10_20") {
+        return "vec2<u32>(10u, 20u)";
+    }
+    if (assembly == "v2uint_20_10") {
+        return "vec2<u32>(20u, 10u)";
+    }
+    if (assembly == "v2int_30_40") {
+        return "vec2<i32>(30i, 40i)";
+    }
+    if (assembly == "v2int_40_30") {
+        return "vec2<i32>(40i, 30i)";
+    }
+    if (assembly == "cast_int_v2uint_10_20") {
+        return "bitcast<vec2<i32>>(vec2<u32>(10u, 20u))";
+    }
+    if (assembly == "cast_uint_v2int_40_30") {
+        return "bitcast<vec2<u32>>(vec2<i32>(40i, 30i))";
+    }
+    if (assembly == "v2float_50_60") {
+        return "vec2<f32>(50.0, 60.0)";
+    }
+    if (assembly == "v2float_60_50") {
+        return "vec2<f32>(60.0, 50.0)";
+    }
+    return "bad case";
 }
 
 using SpvUnaryArithTest = SpvParserTestBase<::testing::Test>;
 
 TEST_F(SpvUnaryArithTest, SNegate_Int_Int) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpSNegate %int %int_30
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << p->error() << "\n"
-      << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : i32 = -(30);"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr("let x_1 : i32 = -(30i);"));
 }
 
 TEST_F(SpvUnaryArithTest, SNegate_Int_Uint) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpSNegate %int %uint_10
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << p->error() << "\n"
-      << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : i32 = -(bitcast<i32>(10u));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : i32 = -(bitcast<i32>(10u));"));
 }
 
 TEST_F(SpvUnaryArithTest, SNegate_Uint_Int) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpSNegate %uint %int_30
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << p->error() << "\n"
-      << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : u32 = bitcast<u32>(-(30));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : u32 = bitcast<u32>(-(30i));"));
 }
 
 TEST_F(SpvUnaryArithTest, SNegate_Uint_Uint) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpSNegate %uint %uint_10
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << p->error() << "\n"
-      << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : u32 = bitcast<u32>(-(bitcast<i32>(10u)));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : u32 = bitcast<u32>(-(bitcast<i32>(10u)));"));
 }
 
 TEST_F(SpvUnaryArithTest, SNegate_SignedVec_SignedVec) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpSNegate %v2int %v2int_30_40
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << p->error() << "\n"
-      << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : vec2<i32> = -(vec2<i32>(30, 40));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : vec2<i32> = -(vec2<i32>(30i, 40i));"));
 }
 
 TEST_F(SpvUnaryArithTest, SNegate_SignedVec_UnsignedVec) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpSNegate %v2int %v2uint_10_20
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << p->error() << "\n"
-      << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(
-      test::ToString(p->program(), ast_body),
-      HasSubstr(
-          "let x_1 : vec2<i32> = -(bitcast<vec2<i32>>(vec2<u32>(10u, 20u)));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : vec2<i32> = -(bitcast<vec2<i32>>(vec2<u32>(10u, 20u)));"));
 }
 
 TEST_F(SpvUnaryArithTest, SNegate_UnsignedVec_SignedVec) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpSNegate %v2uint %v2int_30_40
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << p->error() << "\n"
-      << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(
-      test::ToString(p->program(), ast_body),
-      HasSubstr(
-          "let x_1 : vec2<u32> = bitcast<vec2<u32>>(-(vec2<i32>(30, 40)));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : vec2<u32> = bitcast<vec2<u32>>(-(vec2<i32>(30i, 40i)));"));
 }
 
 TEST_F(SpvUnaryArithTest, SNegate_UnsignedVec_UnsignedVec) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpSNegate %v2uint %v2uint_10_20
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << p->error() << "\n"
-      << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(
-      test::ToString(p->program(), ast_body),
-      HasSubstr(
-          R"(let x_1 : vec2<u32> = bitcast<vec2<u32>>(-(bitcast<vec2<i32>>(vec2<u32>(10u, 20u))));)"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(
+        test::ToString(p->program(), ast_body),
+        HasSubstr(
+            R"(let x_1 : vec2<u32> = bitcast<vec2<u32>>(-(bitcast<vec2<i32>>(vec2<u32>(10u, 20u))));)"));
 }
 
 TEST_F(SpvUnaryArithTest, FNegate_Scalar) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpFNegate %float %float_50
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << p->error() << "\n"
-      << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : f32 = -(50.0);"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr("let x_1 : f32 = -(50.0);"));
 }
 
 TEST_F(SpvUnaryArithTest, FNegate_Vector) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpFNegate %v2float %v2float_50_60
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << p->error() << "\n"
-      << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : vec2<f32> = -(vec2<f32>(50.0, 60.0));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : vec2<f32> = -(vec2<f32>(50.0, 60.0));"));
 }
 
 struct BinaryData {
-  const std::string res_type;
-  const std::string lhs;
-  const std::string op;
-  const std::string rhs;
-  const std::string ast_type;
-  const std::string ast_lhs;
-  const std::string ast_op;
-  const std::string ast_rhs;
+    const std::string res_type;
+    const std::string lhs;
+    const std::string op;
+    const std::string rhs;
+    const std::string ast_type;
+    const std::string ast_lhs;
+    const std::string ast_op;
+    const std::string ast_rhs;
 };
 inline std::ostream& operator<<(std::ostream& out, BinaryData data) {
-  out << "BinaryData{" << data.res_type << "," << data.lhs << "," << data.op
-      << "," << data.rhs << "," << data.ast_type << "," << data.ast_lhs << ","
-      << data.ast_op << "," << data.ast_rhs << "}";
-  return out;
+    out << "BinaryData{" << data.res_type << "," << data.lhs << "," << data.op << "," << data.rhs
+        << "," << data.ast_type << "," << data.ast_lhs << "," << data.ast_op << "," << data.ast_rhs
+        << "}";
+    return out;
 }
 
-using SpvBinaryArithTest =
-    SpvParserTestBase<::testing::TestWithParam<BinaryData>>;
+using SpvBinaryArithTest = SpvParserTestBase<::testing::TestWithParam<BinaryData>>;
 using SpvBinaryArithTestBasic = SpvParserTestBase<::testing::Test>;
 
 TEST_P(SpvBinaryArithTest, EmitExpression) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = )" + GetParam().op +
-                        " %" + GetParam().res_type + " %" + GetParam().lhs +
-                        " %" + GetParam().rhs + R"(
+                          " %" + GetParam().res_type + " %" + GetParam().lhs + " %" +
+                          GetParam().rhs + R"(
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << p->error() << "\n"
-      << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  std::ostringstream ss;
-  ss << "let x_1 : " << GetParam().ast_type << " = (" << GetParam().ast_lhs
-     << " " << GetParam().ast_op << " " << GetParam().ast_rhs << ");";
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(got, HasSubstr(ss.str())) << "got:\n" << got << assembly;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    std::ostringstream ss;
+    ss << "let x_1 : " << GetParam().ast_type << " = (" << GetParam().ast_lhs << " "
+       << GetParam().ast_op << " " << GetParam().ast_rhs << ");";
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(got, HasSubstr(ss.str())) << "got:\n" << got << assembly;
 }
 
 // Use this when the result might have extra bitcasts on the outside.
 struct BinaryDataGeneral {
-  const std::string res_type;
-  const std::string lhs;
-  const std::string op;
-  const std::string rhs;
-  const std::string wgsl_type;
-  const std::string expected;
+    const std::string res_type;
+    const std::string lhs;
+    const std::string op;
+    const std::string rhs;
+    const std::string wgsl_type;
+    const std::string expected;
 };
 inline std::ostream& operator<<(std::ostream& out, BinaryDataGeneral data) {
-  out << "BinaryDataGeneral{" << data.res_type << "," << data.lhs << ","
-      << data.op << "," << data.rhs << "," << data.wgsl_type << ","
-      << data.expected << "}";
-  return out;
+    out << "BinaryDataGeneral{" << data.res_type << "," << data.lhs << "," << data.op << ","
+        << data.rhs << "," << data.wgsl_type << "," << data.expected << "}";
+    return out;
 }
 
-using SpvBinaryArithGeneralTest =
-    SpvParserTestBase<::testing::TestWithParam<BinaryDataGeneral>>;
+using SpvBinaryArithGeneralTest = SpvParserTestBase<::testing::TestWithParam<BinaryDataGeneral>>;
 
 TEST_P(SpvBinaryArithGeneralTest, EmitExpression) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = )" + GetParam().op +
-                        " %" + GetParam().res_type + " %" + GetParam().lhs +
-                        " %" + GetParam().rhs + R"(
+                          " %" + GetParam().res_type + " %" + GetParam().lhs + " %" +
+                          GetParam().rhs + R"(
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << p->error() << "\n"
-      << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  std::ostringstream ss;
-  ss << "let x_1 : " << GetParam().wgsl_type << " = " << GetParam().expected
-     << ";";
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(got, HasSubstr(ss.str())) << "got:\n" << got << assembly;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    std::ostringstream ss;
+    ss << "let x_1 : " << GetParam().wgsl_type << " = " << GetParam().expected << ";";
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(got, HasSubstr(ss.str())) << "got:\n" << got << assembly;
 }
 
 INSTANTIATE_TEST_SUITE_P(
@@ -392,13 +358,10 @@
     SpvBinaryArithTest,
     ::testing::Values(
         // Both uint
-        BinaryData{"uint", "uint_10", "OpIAdd", "uint_20", "u32", "10u", "+",
-                   "20u"},  // Both int
-        BinaryData{"int", "int_30", "OpIAdd", "int_40", "i32", "30", "+",
-                   "40"},  // Both v2uint
-        BinaryData{"v2uint", "v2uint_10_20", "OpIAdd", "v2uint_20_10",
-                   "vec2<u32>", AstFor("v2uint_10_20"), "+",
-                   AstFor("v2uint_20_10")},
+        BinaryData{"uint", "uint_10", "OpIAdd", "uint_20", "u32", "10u", "+", "20u"},  // Both int
+        BinaryData{"int", "int_30", "OpIAdd", "int_40", "i32", "30i", "+", "40i"},  // Both v2uint
+        BinaryData{"v2uint", "v2uint_10_20", "OpIAdd", "v2uint_20_10", "vec2<u32>",
+                   AstFor("v2uint_10_20"), "+", AstFor("v2uint_20_10")},
         // Both v2int
         BinaryData{"v2int", "v2int_30_40", "OpIAdd", "v2int_40_30", "vec2<i32>",
                    AstFor("v2int_30_40"), "+", AstFor("v2int_40_30")}));
@@ -409,48 +372,43 @@
     ::testing::Values(
         // Mixed, uint <- int uint
         BinaryDataGeneral{"uint", "int_30", "OpIAdd", "uint_10", "u32",
-                          "bitcast<u32>((30 + bitcast<i32>(10u)))"},
+                          "bitcast<u32>((30i + bitcast<i32>(10u)))"},
         // Mixed, int <- int uint
-        BinaryDataGeneral{"int", "int_30", "OpIAdd", "uint_10", "i32",
-                          "(30 + bitcast<i32>(10u))"},
+        BinaryDataGeneral{"int", "int_30", "OpIAdd", "uint_10", "i32", "(30i + bitcast<i32>(10u))"},
         // Mixed, uint <- uint int
         BinaryDataGeneral{"uint", "uint_10", "OpIAdd", "int_30", "u32",
-                          "(10u + bitcast<u32>(30))"},
+                          "(10u + bitcast<u32>(30i))"},
         // Mixed, int <- uint uint
         BinaryDataGeneral{"int", "uint_20", "OpIAdd", "uint_10", "i32",
                           "bitcast<i32>((20u + 10u))"},
         // Mixed, returning v2uint
         BinaryDataGeneral{
             "v2uint", "v2int_30_40", "OpIAdd", "v2uint_10_20", "vec2<u32>",
-            R"(bitcast<vec2<u32>>((vec2<i32>(30, 40) + bitcast<vec2<i32>>(vec2<u32>(10u, 20u)))))"},
+            R"(bitcast<vec2<u32>>((vec2<i32>(30i, 40i) + bitcast<vec2<i32>>(vec2<u32>(10u, 20u)))))"},
         // Mixed, returning v2int
         BinaryDataGeneral{
             "v2int", "v2uint_10_20", "OpIAdd", "v2int_40_30", "vec2<i32>",
-            R"(bitcast<vec2<i32>>((vec2<u32>(10u, 20u) + bitcast<vec2<u32>>(vec2<i32>(40, 30)))))"}));
+            R"(bitcast<vec2<i32>>((vec2<u32>(10u, 20u) + bitcast<vec2<u32>>(vec2<i32>(40i, 30i)))))"}));
 
-INSTANTIATE_TEST_SUITE_P(
-    SpvParserTest_FAdd,
-    SpvBinaryArithTest,
-    ::testing::Values(
-        // Scalar float
-        BinaryData{"float", "float_50", "OpFAdd", "float_60", "f32", "50.0",
-                   "+", "60.0"},  // Vector float
-        BinaryData{"v2float", "v2float_50_60", "OpFAdd", "v2float_60_50",
-                   "vec2<f32>", AstFor("v2float_50_60"), "+",
-                   AstFor("v2float_60_50")}));
+INSTANTIATE_TEST_SUITE_P(SpvParserTest_FAdd,
+                         SpvBinaryArithTest,
+                         ::testing::Values(
+                             // Scalar float
+                             BinaryData{"float", "float_50", "OpFAdd", "float_60", "f32", "50.0",
+                                        "+", "60.0"},  // Vector float
+                             BinaryData{"v2float", "v2float_50_60", "OpFAdd", "v2float_60_50",
+                                        "vec2<f32>", AstFor("v2float_50_60"), "+",
+                                        AstFor("v2float_60_50")}));
 
 INSTANTIATE_TEST_SUITE_P(
     SpvParserTest_ISub,
     SpvBinaryArithTest,
     ::testing::Values(
         // Both uint
-        BinaryData{"uint", "uint_10", "OpISub", "uint_20", "u32", "10u", "-",
-                   "20u"},  // Both int
-        BinaryData{"int", "int_30", "OpISub", "int_40", "i32", "30", "-",
-                   "40"},  // Both v2uint
-        BinaryData{"v2uint", "v2uint_10_20", "OpISub", "v2uint_20_10",
-                   "vec2<u32>", AstFor("v2uint_10_20"), "-",
-                   AstFor("v2uint_20_10")},
+        BinaryData{"uint", "uint_10", "OpISub", "uint_20", "u32", "10u", "-", "20u"},  // Both int
+        BinaryData{"int", "int_30", "OpISub", "int_40", "i32", "30i", "-", "40i"},  // Both v2uint
+        BinaryData{"v2uint", "v2uint_10_20", "OpISub", "v2uint_20_10", "vec2<u32>",
+                   AstFor("v2uint_10_20"), "-", AstFor("v2uint_20_10")},
         // Both v2int
         BinaryData{"v2int", "v2int_30_40", "OpISub", "v2int_40_30", "vec2<i32>",
                    AstFor("v2int_30_40"), "-", AstFor("v2int_40_30")}));
@@ -461,48 +419,43 @@
     ::testing::Values(
         // Mixed, uint <- int uint
         BinaryDataGeneral{"uint", "int_30", "OpISub", "uint_10", "u32",
-                          R"(bitcast<u32>((30 - bitcast<i32>(10u))))"},
+                          R"(bitcast<u32>((30i - bitcast<i32>(10u))))"},
         // Mixed, int <- int uint
-        BinaryDataGeneral{"int", "int_30", "OpISub", "uint_10", "i32",
-                          "(30 - bitcast<i32>(10u))"},
+        BinaryDataGeneral{"int", "int_30", "OpISub", "uint_10", "i32", "(30i - bitcast<i32>(10u))"},
         // Mixed, uint <- uint int
         BinaryDataGeneral{"uint", "uint_10", "OpISub", "int_30", "u32",
-                          "(10u - bitcast<u32>(30))"},
+                          "(10u - bitcast<u32>(30i))"},
         // Mixed, int <- uint uint
         BinaryDataGeneral{"int", "uint_20", "OpISub", "uint_10", "i32",
                           "bitcast<i32>((20u - 10u))"},
         // Mixed, returning v2uint
         BinaryDataGeneral{
             "v2uint", "v2int_30_40", "OpISub", "v2uint_10_20", "vec2<u32>",
-            R"(bitcast<vec2<u32>>((vec2<i32>(30, 40) - bitcast<vec2<i32>>(vec2<u32>(10u, 20u)))))"},
+            R"(bitcast<vec2<u32>>((vec2<i32>(30i, 40i) - bitcast<vec2<i32>>(vec2<u32>(10u, 20u)))))"},
         // Mixed, returning v2int
         BinaryDataGeneral{
             "v2int", "v2uint_10_20", "OpISub", "v2int_40_30", "vec2<i32>",
-            R"(bitcast<vec2<i32>>((vec2<u32>(10u, 20u) - bitcast<vec2<u32>>(vec2<i32>(40, 30)))))"}));
+            R"(bitcast<vec2<i32>>((vec2<u32>(10u, 20u) - bitcast<vec2<u32>>(vec2<i32>(40i, 30i)))))"}));
 
-INSTANTIATE_TEST_SUITE_P(
-    SpvParserTest_FSub,
-    SpvBinaryArithTest,
-    ::testing::Values(
-        // Scalar float
-        BinaryData{"float", "float_50", "OpFSub", "float_60", "f32", "50.0",
-                   "-", "60.0"},  // Vector float
-        BinaryData{"v2float", "v2float_50_60", "OpFSub", "v2float_60_50",
-                   "vec2<f32>", AstFor("v2float_50_60"), "-",
-                   AstFor("v2float_60_50")}));
+INSTANTIATE_TEST_SUITE_P(SpvParserTest_FSub,
+                         SpvBinaryArithTest,
+                         ::testing::Values(
+                             // Scalar float
+                             BinaryData{"float", "float_50", "OpFSub", "float_60", "f32", "50.0",
+                                        "-", "60.0"},  // Vector float
+                             BinaryData{"v2float", "v2float_50_60", "OpFSub", "v2float_60_50",
+                                        "vec2<f32>", AstFor("v2float_50_60"), "-",
+                                        AstFor("v2float_60_50")}));
 
 INSTANTIATE_TEST_SUITE_P(
     SpvParserTest_IMul,
     SpvBinaryArithTest,
     ::testing::Values(
         // Both uint
-        BinaryData{"uint", "uint_10", "OpIMul", "uint_20", "u32", "10u", "*",
-                   "20u"},  // Both int
-        BinaryData{"int", "int_30", "OpIMul", "int_40", "i32", "30", "*",
-                   "40"},  // Both v2uint
-        BinaryData{"v2uint", "v2uint_10_20", "OpIMul", "v2uint_20_10",
-                   "vec2<u32>", AstFor("v2uint_10_20"), "*",
-                   AstFor("v2uint_20_10")},
+        BinaryData{"uint", "uint_10", "OpIMul", "uint_20", "u32", "10u", "*", "20u"},  // Both int
+        BinaryData{"int", "int_30", "OpIMul", "int_40", "i32", "30i", "*", "40i"},  // Both v2uint
+        BinaryData{"v2uint", "v2uint_10_20", "OpIMul", "v2uint_20_10", "vec2<u32>",
+                   AstFor("v2uint_10_20"), "*", AstFor("v2uint_20_10")},
         // Both v2int
         BinaryData{"v2int", "v2int_30_40", "OpIMul", "v2int_40_30", "vec2<i32>",
                    AstFor("v2int_30_40"), "*", AstFor("v2int_40_30")}));
@@ -513,54 +466,50 @@
     ::testing::Values(
         // Mixed, uint <- int uint
         BinaryDataGeneral{"uint", "int_30", "OpIMul", "uint_10", "u32",
-                          "bitcast<u32>((30 * bitcast<i32>(10u)))"},
+                          "bitcast<u32>((30i * bitcast<i32>(10u)))"},
         // Mixed, int <- int uint
-        BinaryDataGeneral{"int", "int_30", "OpIMul", "uint_10", "i32",
-                          "(30 * bitcast<i32>(10u))"},
+        BinaryDataGeneral{"int", "int_30", "OpIMul", "uint_10", "i32", "(30i * bitcast<i32>(10u))"},
         // Mixed, uint <- uint int
         BinaryDataGeneral{"uint", "uint_10", "OpIMul", "int_30", "u32",
-                          "(10u * bitcast<u32>(30))"},
+                          "(10u * bitcast<u32>(30i))"},
         // Mixed, int <- uint uint
         BinaryDataGeneral{"int", "uint_20", "OpIMul", "uint_10", "i32",
                           "bitcast<i32>((20u * 10u))"},
         // Mixed, returning v2uint
         BinaryDataGeneral{
             "v2uint", "v2int_30_40", "OpIMul", "v2uint_10_20", "vec2<u32>",
-            R"(bitcast<vec2<u32>>((vec2<i32>(30, 40) * bitcast<vec2<i32>>(vec2<u32>(10u, 20u)))))"},
+            R"(bitcast<vec2<u32>>((vec2<i32>(30i, 40i) * bitcast<vec2<i32>>(vec2<u32>(10u, 20u)))))"},
         // Mixed, returning v2int
         BinaryDataGeneral{
             "v2int", "v2uint_10_20", "OpIMul", "v2int_40_30", "vec2<i32>",
-            R"(bitcast<vec2<i32>>((vec2<u32>(10u, 20u) * bitcast<vec2<u32>>(vec2<i32>(40, 30)))))"}));
+            R"(bitcast<vec2<i32>>((vec2<u32>(10u, 20u) * bitcast<vec2<u32>>(vec2<i32>(40i, 30i)))))"}));
 
-INSTANTIATE_TEST_SUITE_P(
-    SpvParserTest_FMul,
-    SpvBinaryArithTest,
-    ::testing::Values(
-        // Scalar float
-        BinaryData{"float", "float_50", "OpFMul", "float_60", "f32", "50.0",
-                   "*", "60.0"},  // Vector float
-        BinaryData{"v2float", "v2float_50_60", "OpFMul", "v2float_60_50",
-                   "vec2<f32>", AstFor("v2float_50_60"), "*",
-                   AstFor("v2float_60_50")}));
+INSTANTIATE_TEST_SUITE_P(SpvParserTest_FMul,
+                         SpvBinaryArithTest,
+                         ::testing::Values(
+                             // Scalar float
+                             BinaryData{"float", "float_50", "OpFMul", "float_60", "f32", "50.0",
+                                        "*", "60.0"},  // Vector float
+                             BinaryData{"v2float", "v2float_50_60", "OpFMul", "v2float_60_50",
+                                        "vec2<f32>", AstFor("v2float_50_60"), "*",
+                                        AstFor("v2float_60_50")}));
 
-INSTANTIATE_TEST_SUITE_P(
-    SpvParserTest_UDiv,
-    SpvBinaryArithTest,
-    ::testing::Values(
-        // Both uint
-        BinaryData{"uint", "uint_10", "OpUDiv", "uint_20", "u32", "10u", "/",
-                   "20u"},  // Both v2uint
-        BinaryData{"v2uint", "v2uint_10_20", "OpUDiv", "v2uint_20_10",
-                   "vec2<u32>", AstFor("v2uint_10_20"), "/",
-                   AstFor("v2uint_20_10")}));
+INSTANTIATE_TEST_SUITE_P(SpvParserTest_UDiv,
+                         SpvBinaryArithTest,
+                         ::testing::Values(
+                             // Both uint
+                             BinaryData{"uint", "uint_10", "OpUDiv", "uint_20", "u32", "10u", "/",
+                                        "20u"},  // Both v2uint
+                             BinaryData{"v2uint", "v2uint_10_20", "OpUDiv", "v2uint_20_10",
+                                        "vec2<u32>", AstFor("v2uint_10_20"), "/",
+                                        AstFor("v2uint_20_10")}));
 
 INSTANTIATE_TEST_SUITE_P(
     SpvParserTest_SDiv,
     SpvBinaryArithTest,
     ::testing::Values(
         // Both int
-        BinaryData{"int", "int_30", "OpSDiv", "int_40", "i32", "30", "/",
-                   "40"},  // Both v2int
+        BinaryData{"int", "int_30", "OpSDiv", "int_40", "i32", "30i", "/", "40i"},  // Both v2int
         BinaryData{"v2int", "v2int_30_40", "OpSDiv", "v2int_40_30", "vec2<i32>",
                    AstFor("v2int_30_40"), "/", AstFor("v2int_40_30")}));
 
@@ -569,89 +518,79 @@
     SpvBinaryArithTest,
     ::testing::Values(
         // Mixed, returning int, second arg uint
-        BinaryData{"int", "int_30", "OpSDiv", "uint_10", "i32", "30", "/",
-                   "bitcast<i32>(10u)"},
+        BinaryData{"int", "int_30", "OpSDiv", "uint_10", "i32", "30i", "/", "bitcast<i32>(10u)"},
         // Mixed, returning int, first arg uint
-        BinaryData{"int", "uint_10", "OpSDiv", "int_30", "i32",
-                   "bitcast<i32>(10u)", "/",
-                   "30"},  // Mixed, returning v2int, first arg v2uint
-        BinaryData{"v2int", "v2uint_10_20", "OpSDiv", "v2int_30_40",
-                   "vec2<i32>", AstFor("cast_int_v2uint_10_20"), "/",
-                   AstFor("v2int_30_40")},
+        BinaryData{"int", "uint_10", "OpSDiv", "int_30", "i32", "bitcast<i32>(10u)", "/",
+                   "30i"},  // Mixed, returning v2int, first arg v2uint
+        BinaryData{"v2int", "v2uint_10_20", "OpSDiv", "v2int_30_40", "vec2<i32>",
+                   AstFor("cast_int_v2uint_10_20"), "/", AstFor("v2int_30_40")},
         // Mixed, returning v2int, second arg v2uint
-        BinaryData{"v2int", "v2int_30_40", "OpSDiv", "v2uint_10_20",
-                   "vec2<i32>", AstFor("v2int_30_40"), "/",
-                   AstFor("cast_int_v2uint_10_20")}));
+        BinaryData{"v2int", "v2int_30_40", "OpSDiv", "v2uint_10_20", "vec2<i32>",
+                   AstFor("v2int_30_40"), "/", AstFor("cast_int_v2uint_10_20")}));
 
 TEST_F(SpvBinaryArithTestBasic, SDiv_Scalar_UnsignedResult) {
-  // The WGSL signed division operator expects both operands to be signed
-  // and the result is signed as well.
-  // In this test SPIR-V demands an unsigned result, so we have to
-  // wrap the result with an as-cast.
-  const auto assembly = Preamble() + R"(
+    // The WGSL signed division operator expects both operands to be signed
+    // and the result is signed as well.
+    // In this test SPIR-V demands an unsigned result, so we have to
+    // wrap the result with an as-cast.
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpSDiv %uint %int_30 %int_40
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << p->error() << "\n"
-      << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : u32 = bitcast<u32>((30 / 40));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : u32 = bitcast<u32>((30i / 40i));"));
 }
 
 TEST_F(SpvBinaryArithTestBasic, SDiv_Vector_UnsignedResult) {
-  // The WGSL signed division operator expects both operands to be signed
-  // and the result is signed as well.
-  // In this test SPIR-V demands an unsigned result, so we have to
-  // wrap the result with an as-cast.
-  const auto assembly = Preamble() + R"(
+    // The WGSL signed division operator expects both operands to be signed
+    // and the result is signed as well.
+    // In this test SPIR-V demands an unsigned result, so we have to
+    // wrap the result with an as-cast.
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpSDiv %v2uint %v2int_30_40 %v2int_40_30
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << p->error() << "\n"
-      << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(
-      test::ToString(p->program(), ast_body),
-      HasSubstr(
-          R"(let x_1 : vec2<u32> = bitcast<vec2<u32>>((vec2<i32>(30, 40) / vec2<i32>(40, 30)));)"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(
+        test::ToString(p->program(), ast_body),
+        HasSubstr(
+            R"(let x_1 : vec2<u32> = bitcast<vec2<u32>>((vec2<i32>(30i, 40i) / vec2<i32>(40i, 30i)));)"));
 }
 
-INSTANTIATE_TEST_SUITE_P(
-    SpvParserTest_FDiv,
-    SpvBinaryArithTest,
-    ::testing::Values(
-        // Scalar float
-        BinaryData{"float", "float_50", "OpFDiv", "float_60", "f32", "50.0",
-                   "/", "60.0"},  // Vector float
-        BinaryData{"v2float", "v2float_50_60", "OpFDiv", "v2float_60_50",
-                   "vec2<f32>", AstFor("v2float_50_60"), "/",
-                   AstFor("v2float_60_50")}));
+INSTANTIATE_TEST_SUITE_P(SpvParserTest_FDiv,
+                         SpvBinaryArithTest,
+                         ::testing::Values(
+                             // Scalar float
+                             BinaryData{"float", "float_50", "OpFDiv", "float_60", "f32", "50.0",
+                                        "/", "60.0"},  // Vector float
+                             BinaryData{"v2float", "v2float_50_60", "OpFDiv", "v2float_60_50",
+                                        "vec2<f32>", AstFor("v2float_50_60"), "/",
+                                        AstFor("v2float_60_50")}));
 
-INSTANTIATE_TEST_SUITE_P(
-    SpvParserTest_UMod,
-    SpvBinaryArithTest,
-    ::testing::Values(
-        // Both uint
-        BinaryData{"uint", "uint_10", "OpUMod", "uint_20", "u32", "10u", "%",
-                   "20u"},  // Both v2uint
-        BinaryData{"v2uint", "v2uint_10_20", "OpUMod", "v2uint_20_10",
-                   "vec2<u32>", AstFor("v2uint_10_20"), "%",
-                   AstFor("v2uint_20_10")}));
+INSTANTIATE_TEST_SUITE_P(SpvParserTest_UMod,
+                         SpvBinaryArithTest,
+                         ::testing::Values(
+                             // Both uint
+                             BinaryData{"uint", "uint_10", "OpUMod", "uint_20", "u32", "10u", "%",
+                                        "20u"},  // Both v2uint
+                             BinaryData{"v2uint", "v2uint_10_20", "OpUMod", "v2uint_20_10",
+                                        "vec2<u32>", AstFor("v2uint_10_20"), "%",
+                                        AstFor("v2uint_20_10")}));
 
 // Currently WGSL is missing a mapping for OpSRem
 // https://github.com/gpuweb/gpuweb/issues/702
@@ -661,8 +600,7 @@
     SpvBinaryArithTest,
     ::testing::Values(
         // Both int
-        BinaryData{"int", "int_30", "OpSMod", "int_40", "i32", "30", "%",
-                   "40"},  // Both v2int
+        BinaryData{"int", "int_30", "OpSMod", "int_40", "i32", "30i", "%", "40i"},  // Both v2int
         BinaryData{"v2int", "v2int_30_40", "OpSMod", "v2int_40_30", "vec2<i32>",
                    AstFor("v2int_30_40"), "%", AstFor("v2int_40_30")}));
 
@@ -671,122 +609,108 @@
     SpvBinaryArithTest,
     ::testing::Values(
         // Mixed, returning int, second arg uint
-        BinaryData{"int", "int_30", "OpSMod", "uint_10", "i32", "30", "%",
-                   "bitcast<i32>(10u)"},
+        BinaryData{"int", "int_30", "OpSMod", "uint_10", "i32", "30i", "%", "bitcast<i32>(10u)"},
         // Mixed, returning int, first arg uint
-        BinaryData{"int", "uint_10", "OpSMod", "int_30", "i32",
-                   "bitcast<i32>(10u)", "%",
-                   "30"},  // Mixed, returning v2int, first arg v2uint
-        BinaryData{"v2int", "v2uint_10_20", "OpSMod", "v2int_30_40",
-                   "vec2<i32>", AstFor("cast_int_v2uint_10_20"), "%",
-                   AstFor("v2int_30_40")},
+        BinaryData{"int", "uint_10", "OpSMod", "int_30", "i32", "bitcast<i32>(10u)", "%",
+                   "30i"},  // Mixed, returning v2int, first arg v2uint
+        BinaryData{"v2int", "v2uint_10_20", "OpSMod", "v2int_30_40", "vec2<i32>",
+                   AstFor("cast_int_v2uint_10_20"), "%", AstFor("v2int_30_40")},
         // Mixed, returning v2int, second arg v2uint
-        BinaryData{"v2int", "v2int_30_40", "OpSMod", "v2uint_10_20",
-                   "vec2<i32>", AstFor("v2int_30_40"), "%",
-                   AstFor("cast_int_v2uint_10_20")}));
+        BinaryData{"v2int", "v2int_30_40", "OpSMod", "v2uint_10_20", "vec2<i32>",
+                   AstFor("v2int_30_40"), "%", AstFor("cast_int_v2uint_10_20")}));
 
 TEST_F(SpvBinaryArithTestBasic, SMod_Scalar_UnsignedResult) {
-  // The WGSL signed modulus operator expects both operands to be signed
-  // and the result is signed as well.
-  // In this test SPIR-V demands an unsigned result, so we have to
-  // wrap the result with an as-cast.
-  const auto assembly = Preamble() + R"(
+    // The WGSL signed modulus operator expects both operands to be signed
+    // and the result is signed as well.
+    // In this test SPIR-V demands an unsigned result, so we have to
+    // wrap the result with an as-cast.
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpSMod %uint %int_30 %int_40
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << p->error() << "\n"
-      << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : u32 = bitcast<u32>((30 % 40));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : u32 = bitcast<u32>((30i % 40i));"));
 }
 
 TEST_F(SpvBinaryArithTestBasic, SMod_Vector_UnsignedResult) {
-  // The WGSL signed modulus operator expects both operands to be signed
-  // and the result is signed as well.
-  // In this test SPIR-V demands an unsigned result, so we have to
-  // wrap the result with an as-cast.
-  const auto assembly = Preamble() + R"(
+    // The WGSL signed modulus operator expects both operands to be signed
+    // and the result is signed as well.
+    // In this test SPIR-V demands an unsigned result, so we have to
+    // wrap the result with an as-cast.
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpSMod %v2uint %v2int_30_40 %v2int_40_30
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << p->error() << "\n"
-      << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(
-      test::ToString(p->program(), ast_body),
-      HasSubstr(
-          R"(let x_1 : vec2<u32> = bitcast<vec2<u32>>((vec2<i32>(30, 40) % vec2<i32>(40, 30)));)"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(
+        test::ToString(p->program(), ast_body),
+        HasSubstr(
+            R"(let x_1 : vec2<u32> = bitcast<vec2<u32>>((vec2<i32>(30i, 40i) % vec2<i32>(40i, 30i)));)"));
 }
 
-INSTANTIATE_TEST_SUITE_P(
-    SpvParserTest_FRem,
-    SpvBinaryArithTest,
-    ::testing::Values(
-        // Scalar float
-        BinaryData{"float", "float_50", "OpFRem", "float_60", "f32", "50.0",
-                   "%", "60.0"},  // Vector float
-        BinaryData{"v2float", "v2float_50_60", "OpFRem", "v2float_60_50",
-                   "vec2<f32>", AstFor("v2float_50_60"), "%",
-                   AstFor("v2float_60_50")}));
+INSTANTIATE_TEST_SUITE_P(SpvParserTest_FRem,
+                         SpvBinaryArithTest,
+                         ::testing::Values(
+                             // Scalar float
+                             BinaryData{"float", "float_50", "OpFRem", "float_60", "f32", "50.0",
+                                        "%", "60.0"},  // Vector float
+                             BinaryData{"v2float", "v2float_50_60", "OpFRem", "v2float_60_50",
+                                        "vec2<f32>", AstFor("v2float_50_60"), "%",
+                                        AstFor("v2float_60_50")}));
 
 TEST_F(SpvBinaryArithTestBasic, FMod_Scalar) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpFMod %float %float_50 %float_60
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << p->error() << "\n"
-      << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(
-      test::ToString(p->program(), ast_body),
-      HasSubstr("let x_1 : f32 = (50.0 - (60.0 * floor((50.0 / 60.0))));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : f32 = (50.0 - (60.0 * floor((50.0 / 60.0))));"));
 }
 
 TEST_F(SpvBinaryArithTestBasic, FMod_Vector) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpFMod %v2float %v2float_50_60 %v2float_60_50
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << p->error() << "\n"
-      << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(
-      test::ToString(p->program(), ast_body),
-      HasSubstr(
-          R"(let x_1 : vec2<f32> = (vec2<f32>(50.0, 60.0) - (vec2<f32>(60.0, 50.0) * floor((vec2<f32>(50.0, 60.0) / vec2<f32>(60.0, 50.0)))));)"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(
+        test::ToString(p->program(), ast_body),
+        HasSubstr(
+            R"(let x_1 : vec2<f32> = (vec2<f32>(50.0, 60.0) - (vec2<f32>(60.0, 50.0) * floor((vec2<f32>(50.0, 60.0) / vec2<f32>(60.0, 50.0)))));)"));
 }
 
 TEST_F(SpvBinaryArithTestBasic, VectorTimesScalar) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpCopyObject %v2float %v2float_50_60
@@ -795,18 +719,17 @@
      OpReturn
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << assembly << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_10 : vec2<f32> = (x_1 * x_2);"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_10 : vec2<f32> = (x_1 * x_2);"));
 }
 
 TEST_F(SpvBinaryArithTestBasic, MatrixTimesScalar) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpCopyObject %m2v2float %m2v2float_a
@@ -815,18 +738,17 @@
      OpReturn
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << assembly << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_10 : mat2x2<f32> = (x_1 * x_2);"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_10 : mat2x2<f32> = (x_1 * x_2);"));
 }
 
 TEST_F(SpvBinaryArithTestBasic, VectorTimesMatrix) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpCopyObject %m2v2float %m2v2float_a
@@ -835,18 +757,17 @@
      OpReturn
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << assembly << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_10 : vec2<f32> = (x_1 * x_2);"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_10 : vec2<f32> = (x_1 * x_2);"));
 }
 
 TEST_F(SpvBinaryArithTestBasic, MatrixTimesVector) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpCopyObject %m2v2float %m2v2float_a
@@ -855,18 +776,17 @@
      OpReturn
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << assembly << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_10 : vec2<f32> = (x_1 * x_2);"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_10 : vec2<f32> = (x_1 * x_2);"));
 }
 
 TEST_F(SpvBinaryArithTestBasic, MatrixTimesMatrix) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpCopyObject %m2v2float %m2v2float_a
@@ -875,18 +795,17 @@
      OpReturn
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << assembly << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_10 : mat2x2<f32> = (x_1 * x_2);"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_10 : mat2x2<f32> = (x_1 * x_2);"));
 }
 
 TEST_F(SpvBinaryArithTestBasic, Dot) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpCopyObject %v2float %v2float_50_60
@@ -895,20 +814,19 @@
      OpReturn
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << assembly << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_3 : f32 = dot(x_1, x_2);"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_3 : f32 = dot(x_1, x_2);"));
 }
 
 TEST_F(SpvBinaryArithTestBasic, OuterProduct) {
-  // OpOuterProduct is expanded to basic operations.
-  // The operands, even if used once, are given their own const definitions.
-  const auto assembly = Preamble() + R"(
+    // OpOuterProduct is expanded to basic operations.
+    // The operands, even if used once, are given their own const definitions.
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpFAdd %v3float %v3float_50_60_70 %v3float_50_60_70 ; column vector
@@ -917,91 +835,84 @@
      OpReturn
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << assembly << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(
-      got,
-      HasSubstr(
-          "let x_3 : mat2x3<f32> = mat2x3<f32>("
-          "vec3<f32>((x_2.x * x_1.x), (x_2.x * x_1.y), (x_2.x * x_1.z)), "
-          "vec3<f32>((x_2.y * x_1.x), (x_2.y * x_1.y), (x_2.y * x_1.z)));"))
-      << got;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(got, HasSubstr("let x_3 : mat2x3<f32> = mat2x3<f32>("
+                               "vec3<f32>((x_2.x * x_1.x), (x_2.x * x_1.y), (x_2.x * x_1.z)), "
+                               "vec3<f32>((x_2.y * x_1.x), (x_2.y * x_1.y), (x_2.y * x_1.z)));"))
+        << got;
 }
 
 struct BuiltinData {
-  const std::string spirv;
-  const std::string wgsl;
+    const std::string spirv;
+    const std::string wgsl;
 };
 inline std::ostream& operator<<(std::ostream& out, BuiltinData data) {
-  out << "OpData{" << data.spirv << "," << data.wgsl << "}";
-  return out;
+    out << "OpData{" << data.spirv << "," << data.wgsl << "}";
+    return out;
 }
 struct ArgAndTypeData {
-  const std::string spirv_type;
-  const std::string spirv_arg;
-  const std::string ast_type;
+    const std::string spirv_type;
+    const std::string spirv_arg;
+    const std::string ast_type;
 };
 inline std::ostream& operator<<(std::ostream& out, ArgAndTypeData data) {
-  out << "ArgAndTypeData{" << data.spirv_type << "," << data.spirv_arg << ","
-      << data.ast_type << "}";
-  return out;
+    out << "ArgAndTypeData{" << data.spirv_type << "," << data.spirv_arg << "," << data.ast_type
+        << "}";
+    return out;
 }
 
-using SpvBinaryDerivativeTest = SpvParserTestBase<
-    ::testing::TestWithParam<std::tuple<BuiltinData, ArgAndTypeData>>>;
+using SpvBinaryDerivativeTest =
+    SpvParserTestBase<::testing::TestWithParam<std::tuple<BuiltinData, ArgAndTypeData>>>;
 
 TEST_P(SpvBinaryDerivativeTest, Derivatives) {
-  auto& builtin = std::get<0>(GetParam());
-  auto& arg = std::get<1>(GetParam());
+    auto& builtin = std::get<0>(GetParam());
+    auto& arg = std::get<1>(GetParam());
 
-  const auto assembly = R"(
+    const auto assembly = R"(
      OpCapability DerivativeControl
 )" + Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpCopyObject %)" +
-                        arg.spirv_type + " %" + arg.spirv_arg + R"(
+                          arg.spirv_type + " %" + arg.spirv_arg + R"(
      %2 = )" + builtin.spirv +
-                        " %" + arg.spirv_type + R"( %1
+                          " %" + arg.spirv_type + R"( %1
      OpReturn
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << assembly << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(
-      test::ToString(p->program(), ast_body),
-      HasSubstr("let x_2 : " + arg.ast_type + " = " + builtin.wgsl + "(x_1);"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_2 : " + arg.ast_type + " = " + builtin.wgsl + "(x_1);"));
 }
 
 INSTANTIATE_TEST_SUITE_P(
     SpvBinaryDerivativeTest,
     SpvBinaryDerivativeTest,
-    testing::Combine(
-        ::testing::Values(BuiltinData{"OpDPdx", "dpdx"},
-                          BuiltinData{"OpDPdy", "dpdy"},
-                          BuiltinData{"OpFwidth", "fwidth"},
-                          BuiltinData{"OpDPdxFine", "dpdxFine"},
-                          BuiltinData{"OpDPdyFine", "dpdyFine"},
-                          BuiltinData{"OpFwidthFine", "fwidthFine"},
-                          BuiltinData{"OpDPdxCoarse", "dpdxCoarse"},
-                          BuiltinData{"OpDPdyCoarse", "dpdyCoarse"},
-                          BuiltinData{"OpFwidthCoarse", "fwidthCoarse"}),
-        ::testing::Values(
-            ArgAndTypeData{"float", "float_50", "f32"},
-            ArgAndTypeData{"v2float", "v2float_50_60", "vec2<f32>"},
-            ArgAndTypeData{"v3float", "v3float_50_60_70", "vec3<f32>"})));
+    testing::Combine(::testing::Values(BuiltinData{"OpDPdx", "dpdx"},
+                                       BuiltinData{"OpDPdy", "dpdy"},
+                                       BuiltinData{"OpFwidth", "fwidth"},
+                                       BuiltinData{"OpDPdxFine", "dpdxFine"},
+                                       BuiltinData{"OpDPdyFine", "dpdyFine"},
+                                       BuiltinData{"OpFwidthFine", "fwidthFine"},
+                                       BuiltinData{"OpDPdxCoarse", "dpdxCoarse"},
+                                       BuiltinData{"OpDPdyCoarse", "dpdyCoarse"},
+                                       BuiltinData{"OpFwidthCoarse", "fwidthCoarse"}),
+                     ::testing::Values(ArgAndTypeData{"float", "float_50", "f32"},
+                                       ArgAndTypeData{"v2float", "v2float_50_60", "vec2<f32>"},
+                                       ArgAndTypeData{"v3float", "v3float_50_60_70",
+                                                      "vec3<f32>"})));
 
 TEST_F(SpvUnaryArithTest, Transpose_2x2) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpCopyObject %m2v2float %m2v2float_a
@@ -1009,20 +920,18 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << p->error() << "\n"
-      << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  const auto* expected = "let x_2 : mat2x2<f32> = transpose(x_1);";
-  auto ast_body = fe.ast_body();
-  const auto got = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(got, HasSubstr(expected)) << got;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    const auto* expected = "let x_2 : mat2x2<f32> = transpose(x_1);";
+    auto ast_body = fe.ast_body();
+    const auto got = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(got, HasSubstr(expected)) << got;
 }
 
 TEST_F(SpvUnaryArithTest, Transpose_2x3) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpCopyObject %m2v3float %m2v3float_a
@@ -1030,23 +939,21 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << p->error() << "\n"
-      << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  // Note, in the AST dump mat_2_3 means 2 rows and 3 columns.
-  // So the column vectors have 2 elements.
-  // That is,   %m3v2float is __mat_2_3f32.
-  const auto* expected = "let x_2 : mat3x2<f32> = transpose(x_1);";
-  auto ast_body = fe.ast_body();
-  const auto got = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(got, HasSubstr(expected)) << got;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    // Note, in the AST dump mat_2_3 means 2 rows and 3 columns.
+    // So the column vectors have 2 elements.
+    // That is,   %m3v2float is __mat_2_3f32.
+    const auto* expected = "let x_2 : mat3x2<f32> = transpose(x_1);";
+    auto ast_body = fe.ast_body();
+    const auto got = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(got, HasSubstr(expected)) << got;
 }
 
 TEST_F(SpvUnaryArithTest, Transpose_3x2) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpCopyObject %m3v2float %m3v2float_a
@@ -1054,16 +961,14 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << p->error() << "\n"
-      << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  const auto* expected = "let x_2 : mat2x3<f32> = transpose(x_1);";
-  auto ast_body = fe.ast_body();
-  const auto got = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(got, HasSubstr(expected)) << got;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    const auto* expected = "let x_2 : mat2x3<f32> = transpose(x_1);";
+    auto ast_body = fe.ast_body();
+    const auto got = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(got, HasSubstr(expected)) << got;
 }
 
 // TODO(dneto): OpSRem. Missing from WGSL
diff --git a/src/tint/reader/spirv/function_bit_test.cc b/src/tint/reader/spirv/function_bit_test.cc
index ba0e67e..a8e97b3 100644
--- a/src/tint/reader/spirv/function_bit_test.cc
+++ b/src/tint/reader/spirv/function_bit_test.cc
@@ -22,7 +22,7 @@
 using ::testing::HasSubstr;
 
 std::string CommonTypes() {
-  return R"(
+    return R"(
   %void = OpTypeVoid
   %voidfn = OpTypeFunction %void
 
@@ -55,7 +55,7 @@
 }
 
 std::string SimplePreamble() {
-  return R"(
+    return R"(
   OpCapability Shader
   OpMemoryModel Logical Simple
   OpEntryPoint Fragment %100 "main"
@@ -65,118 +65,109 @@
 
 // Returns the AST dump for a given SPIR-V assembly constant.
 std::string AstFor(std::string assembly) {
-  if (assembly == "v2uint_10_20") {
-    return "vec2<u32>(10u, 20u)";
-  }
-  if (assembly == "v2uint_20_10") {
-    return "vec2<u32>(20u, 10u)";
-  }
-  if (assembly == "v2int_30_40") {
-    return "vec2<i32>(30, 40)";
-  }
-  if (assembly == "v2int_40_30") {
-    return "vec2<i32>(40, 30)";
-  }
-  if (assembly == "cast_int_v2uint_10_20") {
-    return "bitcast<vec2<i32>(vec2<u32>(10u, 20u))";
-  }
-  if (assembly == "v2float_50_60") {
-    return "vec2<f32>(50.0, 60.0))";
-  }
-  if (assembly == "v2float_60_50") {
-    return "vec2<f32>(60.0, 50.0))";
-  }
-  return "bad case";
+    if (assembly == "v2uint_10_20") {
+        return "vec2<u32>(10u, 20u)";
+    }
+    if (assembly == "v2uint_20_10") {
+        return "vec2<u32>(20u, 10u)";
+    }
+    if (assembly == "v2int_30_40") {
+        return "vec2<i32>(30i, 40i)";
+    }
+    if (assembly == "v2int_40_30") {
+        return "vec2<i32>(40i, 30i)";
+    }
+    if (assembly == "cast_int_v2uint_10_20") {
+        return "bitcast<vec2<i32>(vec2<u32>(10u, 20u))";
+    }
+    if (assembly == "v2float_50_60") {
+        return "vec2<f32>(50.0, 60.0))";
+    }
+    if (assembly == "v2float_60_50") {
+        return "vec2<f32>(60.0, 50.0))";
+    }
+    return "bad case";
 }
 
 using SpvUnaryBitTest = SpvParserTestBase<::testing::Test>;
 
 struct BinaryData {
-  const std::string res_type;
-  const std::string lhs;
-  const std::string op;
-  const std::string rhs;
-  const std::string ast_type;
-  const std::string ast_lhs;
-  const std::string ast_op;
-  const std::string ast_rhs;
+    const std::string res_type;
+    const std::string lhs;
+    const std::string op;
+    const std::string rhs;
+    const std::string ast_type;
+    const std::string ast_lhs;
+    const std::string ast_op;
+    const std::string ast_rhs;
 };
 inline std::ostream& operator<<(std::ostream& out, BinaryData data) {
-  out << "BinaryData{" << data.res_type << "," << data.lhs << "," << data.op
-      << "," << data.rhs << "," << data.ast_type << "," << data.ast_lhs << ","
-      << data.ast_op << "," << data.ast_rhs << "}";
-  return out;
+    out << "BinaryData{" << data.res_type << "," << data.lhs << "," << data.op << "," << data.rhs
+        << "," << data.ast_type << "," << data.ast_lhs << "," << data.ast_op << "," << data.ast_rhs
+        << "}";
+    return out;
 }
 
-using SpvBinaryBitTest =
-    SpvParserTestBase<::testing::TestWithParam<BinaryData>>;
+using SpvBinaryBitTest = SpvParserTestBase<::testing::TestWithParam<BinaryData>>;
 using SpvBinaryBitTestBasic = SpvParserTestBase<::testing::Test>;
 
 TEST_P(SpvBinaryBitTest, EmitExpression) {
-  const auto assembly = SimplePreamble() + R"(
+    const auto assembly = SimplePreamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = )" + GetParam().op +
-                        " %" + GetParam().res_type + " %" + GetParam().lhs +
-                        " %" + GetParam().rhs + R"(
+                          " %" + GetParam().res_type + " %" + GetParam().lhs + " %" +
+                          GetParam().rhs + R"(
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << p->error() << "\n"
-      << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  std::ostringstream ss;
-  ss << "let x_1 : " << GetParam().ast_type << " = (" << GetParam().ast_lhs
-     << " " << GetParam().ast_op << " " << GetParam().ast_rhs << ");";
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr(ss.str()))
-      << assembly;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    std::ostringstream ss;
+    ss << "let x_1 : " << GetParam().ast_type << " = (" << GetParam().ast_lhs << " "
+       << GetParam().ast_op << " " << GetParam().ast_rhs << ");";
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr(ss.str())) << assembly;
 }
 
 // Use this when the result might have extra bitcasts on the outside.
 struct BinaryDataGeneral {
-  const std::string res_type;
-  const std::string lhs;
-  const std::string op;
-  const std::string rhs;
-  const std::string wgsl_type;
-  const std::string expected;
+    const std::string res_type;
+    const std::string lhs;
+    const std::string op;
+    const std::string rhs;
+    const std::string wgsl_type;
+    const std::string expected;
 };
 inline std::ostream& operator<<(std::ostream& out, BinaryDataGeneral data) {
-  out << "BinaryDataGeneral{" << data.res_type << "," << data.lhs << ","
-      << data.op << "," << data.rhs << "," << data.wgsl_type << ","
-      << data.expected << "}";
-  return out;
+    out << "BinaryDataGeneral{" << data.res_type << "," << data.lhs << "," << data.op << ","
+        << data.rhs << "," << data.wgsl_type << "," << data.expected << "}";
+    return out;
 }
 
-using SpvBinaryBitGeneralTest =
-    SpvParserTestBase<::testing::TestWithParam<BinaryDataGeneral>>;
+using SpvBinaryBitGeneralTest = SpvParserTestBase<::testing::TestWithParam<BinaryDataGeneral>>;
 
 TEST_P(SpvBinaryBitGeneralTest, EmitExpression) {
-  const auto assembly = SimplePreamble() + R"(
+    const auto assembly = SimplePreamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = )" + GetParam().op +
-                        " %" + GetParam().res_type + " %" + GetParam().lhs +
-                        " %" + GetParam().rhs + R"(
+                          " %" + GetParam().res_type + " %" + GetParam().lhs + " %" +
+                          GetParam().rhs + R"(
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << p->error() << "\n"
-      << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error() << assembly;
-  std::ostringstream ss;
-  ss << "let x_1 : " << GetParam().wgsl_type << " = " << GetParam().expected
-     << ";\nreturn;\n";
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(got, HasSubstr(ss.str())) << "got:\n" << got << assembly;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error() << assembly;
+    std::ostringstream ss;
+    ss << "let x_1 : " << GetParam().wgsl_type << " = " << GetParam().expected << ";\nreturn;\n";
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(got, HasSubstr(ss.str())) << "got:\n" << got << assembly;
 }
 
 INSTANTIATE_TEST_SUITE_P(
@@ -184,19 +175,15 @@
     SpvBinaryBitTest,
     ::testing::Values(
         // uint uint -> uint
-        BinaryData{"uint", "uint_10", "OpShiftLeftLogical", "uint_20", "u32",
-                   "10u", "<<", "20u"},
+        BinaryData{"uint", "uint_10", "OpShiftLeftLogical", "uint_20", "u32", "10u", "<<", "20u"},
         // int, uint -> int
-        BinaryData{"int", "int_30", "OpShiftLeftLogical", "uint_20", "i32",
-                   "30", "<<", "20u"},
+        BinaryData{"int", "int_30", "OpShiftLeftLogical", "uint_20", "i32", "30i", "<<", "20u"},
         // v2uint v2uint -> v2uint
-        BinaryData{"v2uint", "v2uint_10_20", "OpShiftLeftLogical",
-                   "v2uint_20_10", "vec2<u32>", AstFor("v2uint_10_20"), "<<",
-                   AstFor("v2uint_20_10")},
+        BinaryData{"v2uint", "v2uint_10_20", "OpShiftLeftLogical", "v2uint_20_10", "vec2<u32>",
+                   AstFor("v2uint_10_20"), "<<", AstFor("v2uint_20_10")},
         // v2int, v2uint -> v2int
-        BinaryData{"v2int", "v2int_30_40", "OpShiftLeftLogical", "v2uint_20_10",
-                   "vec2<i32>", AstFor("v2int_30_40"), "<<",
-                   AstFor("v2uint_20_10")}));
+        BinaryData{"v2int", "v2int_30_40", "OpShiftLeftLogical", "v2uint_20_10", "vec2<i32>",
+                   AstFor("v2int_30_40"), "<<", AstFor("v2uint_20_10")}));
 
 INSTANTIATE_TEST_SUITE_P(
     // WGSL requires second operand to be unsigned, so insert bitcasts
@@ -204,164 +191,143 @@
     SpvBinaryBitGeneralTest,
     ::testing::Values(
         // int, int -> int
-        BinaryDataGeneral{"int", "int_30", "OpShiftLeftLogical", "int_40",
-                          "i32", "(30 << bitcast<u32>(40))"},
+        BinaryDataGeneral{"int", "int_30", "OpShiftLeftLogical", "int_40", "i32",
+                          "(30i << bitcast<u32>(40i))"},
         // uint, int -> uint
-        BinaryDataGeneral{"uint", "uint_10", "OpShiftLeftLogical", "int_40",
-                          "u32", "(10u << bitcast<u32>(40))"},
+        BinaryDataGeneral{"uint", "uint_10", "OpShiftLeftLogical", "int_40", "u32",
+                          "(10u << bitcast<u32>(40i))"},
         // v2uint, v2int -> v2uint
-        BinaryDataGeneral{"v2uint", "v2uint_10_20", "OpShiftLeftLogical",
-                          "v2uint_20_10", "vec2<u32>",
-                          "(vec2<u32>(10u, 20u) << vec2<u32>(20u, 10u))"},
+        BinaryDataGeneral{"v2uint", "v2uint_10_20", "OpShiftLeftLogical", "v2uint_20_10",
+                          "vec2<u32>", "(vec2<u32>(10u, 20u) << vec2<u32>(20u, 10u))"},
         // v2int, v2int -> v2int
-        BinaryDataGeneral{
-            "v2int", "v2int_30_40", "OpShiftLeftLogical", "v2int_40_30",
-            "vec2<i32>",
-            "(vec2<i32>(30, 40) << bitcast<vec2<u32>>(vec2<i32>(40, 30)))"}));
+        BinaryDataGeneral{"v2int", "v2int_30_40", "OpShiftLeftLogical", "v2int_40_30", "vec2<i32>",
+                          "(vec2<i32>(30i, 40i) << bitcast<vec2<u32>>(vec2<i32>(40i, 30i)))"}));
 
 INSTANTIATE_TEST_SUITE_P(
     SpvParserTest_ShiftLeftLogical_BitcastResult,
     SpvBinaryBitGeneralTest,
     ::testing::Values(
         // int, int -> uint
-        BinaryDataGeneral{"uint", "int_30", "OpShiftLeftLogical", "uint_10",
-                          "u32", "bitcast<u32>((30 << 10u))"},
+        BinaryDataGeneral{"uint", "int_30", "OpShiftLeftLogical", "uint_10", "u32",
+                          "bitcast<u32>((30i << 10u))"},
         // v2uint, v2int -> v2uint
-        BinaryDataGeneral{
-            "v2uint", "v2int_30_40", "OpShiftLeftLogical", "v2uint_20_10",
-            "vec2<u32>",
-            "bitcast<vec2<u32>>((vec2<i32>(30, 40) << vec2<u32>(20u, 10u)))"}));
+        BinaryDataGeneral{"v2uint", "v2int_30_40", "OpShiftLeftLogical", "v2uint_20_10",
+                          "vec2<u32>",
+                          "bitcast<vec2<u32>>((vec2<i32>(30i, 40i) << vec2<u32>(20u, 10u)))"}));
 
 INSTANTIATE_TEST_SUITE_P(
     SpvParserTest_ShiftRightLogical_Arg2Unsigned,
     SpvBinaryBitGeneralTest,
     ::testing::Values(
         // uint, uint -> uint
-        BinaryDataGeneral{"uint", "uint_10", "OpShiftRightLogical", "uint_20",
-                          "u32", "(10u >> 20u)"},
+        BinaryDataGeneral{"uint", "uint_10", "OpShiftRightLogical", "uint_20", "u32",
+                          "(10u >> 20u)"},
         // int, uint -> int
-        BinaryDataGeneral{"int", "int_30", "OpShiftRightLogical", "uint_20",
-                          "i32", "bitcast<i32>((bitcast<u32>(30) >> 20u))"},
+        BinaryDataGeneral{"int", "int_30", "OpShiftRightLogical", "uint_20", "i32",
+                          "bitcast<i32>((bitcast<u32>(30i) >> 20u))"},
         // v2uint, v2uint -> v2uint
-        BinaryDataGeneral{"v2uint", "v2uint_10_20", "OpShiftRightLogical",
-                          "v2uint_20_10", "vec2<u32>",
-                          "(vec2<u32>(10u, 20u) >> vec2<u32>(20u, 10u))"},
+        BinaryDataGeneral{"v2uint", "v2uint_10_20", "OpShiftRightLogical", "v2uint_20_10",
+                          "vec2<u32>", "(vec2<u32>(10u, 20u) >> vec2<u32>(20u, 10u))"},
         // v2int, v2uint -> v2int
         BinaryDataGeneral{
-            "v2int", "v2int_30_40", "OpShiftRightLogical", "v2uint_10_20",
-            "vec2<i32>",
-            R"(bitcast<vec2<i32>>((bitcast<vec2<u32>>(vec2<i32>(30, 40)) >> vec2<u32>(10u, 20u))))"}));
+            "v2int", "v2int_30_40", "OpShiftRightLogical", "v2uint_10_20", "vec2<i32>",
+            R"(bitcast<vec2<i32>>((bitcast<vec2<u32>>(vec2<i32>(30i, 40i)) >> vec2<u32>(10u, 20u))))"}));
 
 INSTANTIATE_TEST_SUITE_P(
     SpvParserTest_ShiftRightLogical_Arg2Signed,
     SpvBinaryBitGeneralTest,
     ::testing::Values(
         // uint, int -> uint
-        BinaryDataGeneral{"uint", "uint_10", "OpShiftRightLogical", "int_30",
-                          "u32", "(10u >> bitcast<u32>(30))"},
+        BinaryDataGeneral{"uint", "uint_10", "OpShiftRightLogical", "int_30", "u32",
+                          "(10u >> bitcast<u32>(30i))"},
         // int, int -> int
-        BinaryDataGeneral{
-            "int", "int_30", "OpShiftRightLogical", "int_40", "i32",
-            "bitcast<i32>((bitcast<u32>(30) >> bitcast<u32>(40)))"},
+        BinaryDataGeneral{"int", "int_30", "OpShiftRightLogical", "int_40", "i32",
+                          "bitcast<i32>((bitcast<u32>(30i) >> bitcast<u32>(40i)))"},
         // v2uint, v2int -> v2uint
-        BinaryDataGeneral{
-            "v2uint", "v2uint_10_20", "OpShiftRightLogical", "v2int_30_40",
-            "vec2<u32>",
-            "(vec2<u32>(10u, 20u) >> bitcast<vec2<u32>>(vec2<i32>(30, 40)))"},
+        BinaryDataGeneral{"v2uint", "v2uint_10_20", "OpShiftRightLogical", "v2int_30_40",
+                          "vec2<u32>",
+                          "(vec2<u32>(10u, 20u) >> bitcast<vec2<u32>>(vec2<i32>(30i, 40i)))"},
         // v2int, v2int -> v2int
         BinaryDataGeneral{
-            "v2int", "v2int_40_30", "OpShiftRightLogical", "v2int_30_40",
-            "vec2<i32>",
-            R"(bitcast<vec2<i32>>((bitcast<vec2<u32>>(vec2<i32>(40, 30)) >> bitcast<vec2<u32>>(vec2<i32>(30, 40)))))"}));
+            "v2int", "v2int_40_30", "OpShiftRightLogical", "v2int_30_40", "vec2<i32>",
+            R"(bitcast<vec2<i32>>((bitcast<vec2<u32>>(vec2<i32>(40i, 30i)) >> bitcast<vec2<u32>>(vec2<i32>(30i, 40i)))))"}));
 
 INSTANTIATE_TEST_SUITE_P(
     SpvParserTest_ShiftRightLogical_BitcastResult,
     SpvBinaryBitGeneralTest,
     ::testing::Values(
         // uint, uint -> int
-        BinaryDataGeneral{"int", "uint_20", "OpShiftRightLogical", "uint_10",
-                          "i32", "bitcast<i32>((20u >> 10u))"},
+        BinaryDataGeneral{"int", "uint_20", "OpShiftRightLogical", "uint_10", "i32",
+                          "bitcast<i32>((20u >> 10u))"},
         // v2uint, v2uint -> v2int
-        BinaryDataGeneral{
-            "v2int", "v2uint_10_20", "OpShiftRightLogical", "v2uint_20_10",
-            "vec2<i32>",
-            R"(bitcast<vec2<i32>>((vec2<u32>(10u, 20u) >> vec2<u32>(20u, 10u))))"}));
+        BinaryDataGeneral{"v2int", "v2uint_10_20", "OpShiftRightLogical", "v2uint_20_10",
+                          "vec2<i32>",
+                          R"(bitcast<vec2<i32>>((vec2<u32>(10u, 20u) >> vec2<u32>(20u, 10u))))"}));
 
 INSTANTIATE_TEST_SUITE_P(
     SpvParserTest_ShiftRightArithmetic_Arg2Unsigned,
     SpvBinaryBitGeneralTest,
     ::testing::Values(
         // uint, uint -> uint
-        BinaryDataGeneral{"uint", "uint_10", "OpShiftRightArithmetic",
-                          "uint_20", "u32",
+        BinaryDataGeneral{"uint", "uint_10", "OpShiftRightArithmetic", "uint_20", "u32",
                           "bitcast<u32>((bitcast<i32>(10u) >> 20u))"},
         // int, uint -> int
-        BinaryDataGeneral{"int", "int_30", "OpShiftRightArithmetic", "uint_10",
-                          "i32", "(30 >> 10u)"},
+        BinaryDataGeneral{"int", "int_30", "OpShiftRightArithmetic", "uint_10", "i32",
+                          "(30i >> 10u)"},
         // v2uint, v2uint -> v2uint
         BinaryDataGeneral{
-            "v2uint", "v2uint_10_20", "OpShiftRightArithmetic", "v2uint_20_10",
-            "vec2<u32>",
+            "v2uint", "v2uint_10_20", "OpShiftRightArithmetic", "v2uint_20_10", "vec2<u32>",
             R"(bitcast<vec2<u32>>((bitcast<vec2<i32>>(vec2<u32>(10u, 20u)) >> vec2<u32>(20u, 10u))))"},
         // v2int, v2uint -> v2int
-        BinaryDataGeneral{"v2int", "v2int_40_30", "OpShiftRightArithmetic",
-                          "v2uint_20_10", "vec2<i32>",
-                          "(vec2<i32>(40, 30) >> vec2<u32>(20u, 10u))"}));
+        BinaryDataGeneral{"v2int", "v2int_40_30", "OpShiftRightArithmetic", "v2uint_20_10",
+                          "vec2<i32>", "(vec2<i32>(40i, 30i) >> vec2<u32>(20u, 10u))"}));
 
 INSTANTIATE_TEST_SUITE_P(
     SpvParserTest_ShiftRightArithmetic_Arg2Signed,
     SpvBinaryBitGeneralTest,
     ::testing::Values(
         // uint, int -> uint
-        BinaryDataGeneral{
-            "uint", "uint_10", "OpShiftRightArithmetic", "int_30", "u32",
-            "bitcast<u32>((bitcast<i32>(10u) >> bitcast<u32>(30)))"},
+        BinaryDataGeneral{"uint", "uint_10", "OpShiftRightArithmetic", "int_30", "u32",
+                          "bitcast<u32>((bitcast<i32>(10u) >> bitcast<u32>(30i)))"},
         // int, int -> int
-        BinaryDataGeneral{"int", "int_30", "OpShiftRightArithmetic", "int_40",
-                          "i32", "(30 >> bitcast<u32>(40))"},
+        BinaryDataGeneral{"int", "int_30", "OpShiftRightArithmetic", "int_40", "i32",
+                          "(30i >> bitcast<u32>(40i))"},
         // v2uint, v2int -> v2uint
         BinaryDataGeneral{
-            "v2uint", "v2uint_10_20", "OpShiftRightArithmetic", "v2int_30_40",
-            "vec2<u32>",
-            R"(bitcast<vec2<u32>>((bitcast<vec2<i32>>(vec2<u32>(10u, 20u)) >> bitcast<vec2<u32>>(vec2<i32>(30, 40)))))"},
+            "v2uint", "v2uint_10_20", "OpShiftRightArithmetic", "v2int_30_40", "vec2<u32>",
+            R"(bitcast<vec2<u32>>((bitcast<vec2<i32>>(vec2<u32>(10u, 20u)) >> bitcast<vec2<u32>>(vec2<i32>(30i, 40i)))))"},
         // v2int, v2int -> v2int
-        BinaryDataGeneral{
-            "v2int", "v2int_40_30", "OpShiftRightArithmetic", "v2int_30_40",
-            "vec2<i32>",
-            "(vec2<i32>(40, 30) >> bitcast<vec2<u32>>(vec2<i32>(30, 40)))"}));
+        BinaryDataGeneral{"v2int", "v2int_40_30", "OpShiftRightArithmetic", "v2int_30_40",
+                          "vec2<i32>",
+                          "(vec2<i32>(40i, 30i) >> bitcast<vec2<u32>>(vec2<i32>(30i, 40i)))"}));
 
 INSTANTIATE_TEST_SUITE_P(
     SpvParserTest_ShiftRightArithmetic_BitcastResult,
     SpvBinaryBitGeneralTest,
     ::testing::Values(
         // int, uint -> uint
-        BinaryDataGeneral{"uint", "int_30", "OpShiftRightArithmetic", "uint_10",
-                          "u32", "bitcast<u32>((30 >> 10u))"},
+        BinaryDataGeneral{"uint", "int_30", "OpShiftRightArithmetic", "uint_10", "u32",
+                          "bitcast<u32>((30i >> 10u))"},
         // v2int, v2uint -> v2uint
-        BinaryDataGeneral{
-            "v2uint", "v2int_30_40", "OpShiftRightArithmetic", "v2uint_20_10",
-            "vec2<u32>",
-            "bitcast<vec2<u32>>((vec2<i32>(30, 40) >> vec2<u32>(20u, 10u)))"}));
+        BinaryDataGeneral{"v2uint", "v2int_30_40", "OpShiftRightArithmetic", "v2uint_20_10",
+                          "vec2<u32>",
+                          "bitcast<vec2<u32>>((vec2<i32>(30i, 40i) >> vec2<u32>(20u, 10u)))"}));
 
 INSTANTIATE_TEST_SUITE_P(
     SpvParserTest_BitwiseAnd,
     SpvBinaryBitTest,
     ::testing::Values(
         // Both uint
-        BinaryData{"uint", "uint_10", "OpBitwiseAnd", "uint_20", "u32", "10u",
-                   "&", "20u"},
+        BinaryData{"uint", "uint_10", "OpBitwiseAnd", "uint_20", "u32", "10u", "&", "20u"},
         // Both int
-        BinaryData{"int", "int_30", "OpBitwiseAnd", "int_40", "i32", "30", "&",
-                   "40"},
+        BinaryData{"int", "int_30", "OpBitwiseAnd", "int_40", "i32", "30i", "&", "40i"},
         // TODO(crbug.com/tint/678): Resolver fails on vector bitwise operations
         // Both v2uint
-        BinaryData{"v2uint", "v2uint_10_20", "OpBitwiseAnd", "v2uint_20_10",
-                   "vec2<u32>", AstFor("v2uint_10_20"), "&",
-                   AstFor("v2uint_20_10")},
+        BinaryData{"v2uint", "v2uint_10_20", "OpBitwiseAnd", "v2uint_20_10", "vec2<u32>",
+                   AstFor("v2uint_10_20"), "&", AstFor("v2uint_20_10")},
         // Both v2int
-        BinaryData{"v2int", "v2int_30_40", "OpBitwiseAnd", "v2int_40_30",
-                   "vec2<i32>", AstFor("v2int_30_40"), "&",
-                   AstFor("v2int_40_30")}));
+        BinaryData{"v2int", "v2int_30_40", "OpBitwiseAnd", "v2int_40_30", "vec2<i32>",
+                   AstFor("v2int_30_40"), "&", AstFor("v2int_40_30")}));
 
 INSTANTIATE_TEST_SUITE_P(
     SpvParserTest_BitwiseAnd_MixedSignedness,
@@ -369,45 +335,40 @@
     ::testing::Values(
         // Mixed, uint <- int uint
         BinaryDataGeneral{"uint", "int_30", "OpBitwiseAnd", "uint_10", "u32",
-                          "bitcast<u32>((30 & bitcast<i32>(10u)))"},
+                          "bitcast<u32>((30i & bitcast<i32>(10u)))"},
         // Mixed, int <- int uint
         BinaryDataGeneral{"int", "int_30", "OpBitwiseAnd", "uint_10", "i32",
-                          "(30 & bitcast<i32>(10u))"},
+                          "(30i & bitcast<i32>(10u))"},
         // Mixed, uint <- uint int
         BinaryDataGeneral{"uint", "uint_10", "OpBitwiseAnd", "int_30", "u32",
-                          "(10u & bitcast<u32>(30))"},
+                          "(10u & bitcast<u32>(30i))"},
         // Mixed, int <- uint uint
         BinaryDataGeneral{"int", "uint_20", "OpBitwiseAnd", "uint_10", "i32",
                           "bitcast<i32>((20u & 10u))"},
         // Mixed, returning v2uint
         BinaryDataGeneral{
-            "v2uint", "v2int_30_40", "OpBitwiseAnd", "v2uint_10_20",
-            "vec2<u32>",
-            R"(bitcast<vec2<u32>>((vec2<i32>(30, 40) & bitcast<vec2<i32>>(vec2<u32>(10u, 20u)))))"},
+            "v2uint", "v2int_30_40", "OpBitwiseAnd", "v2uint_10_20", "vec2<u32>",
+            R"(bitcast<vec2<u32>>((vec2<i32>(30i, 40i) & bitcast<vec2<i32>>(vec2<u32>(10u, 20u)))))"},
         // Mixed, returning v2int
         BinaryDataGeneral{
             "v2int", "v2uint_10_20", "OpBitwiseAnd", "v2int_40_30", "vec2<i32>",
-            R"(bitcast<vec2<i32>>((vec2<u32>(10u, 20u) & bitcast<vec2<u32>>(vec2<i32>(40, 30)))))"}));
+            R"(bitcast<vec2<i32>>((vec2<u32>(10u, 20u) & bitcast<vec2<u32>>(vec2<i32>(40i, 30i)))))"}));
 
 INSTANTIATE_TEST_SUITE_P(
     SpvParserTest_BitwiseOr,
     SpvBinaryBitTest,
     ::testing::Values(
         // Both uint
-        BinaryData{"uint", "uint_10", "OpBitwiseOr", "uint_20", "u32", "10u",
-                   "|", "20u"},
+        BinaryData{"uint", "uint_10", "OpBitwiseOr", "uint_20", "u32", "10u", "|", "20u"},
         // Both int
-        BinaryData{"int", "int_30", "OpBitwiseOr", "int_40", "i32", "30", "|",
-                   "40"},
+        BinaryData{"int", "int_30", "OpBitwiseOr", "int_40", "i32", "30i", "|", "40i"},
         // TODO(crbug.com/tint/678): Resolver fails on vector bitwise operations
         // Both v2uint
-        BinaryData{"v2uint", "v2uint_10_20", "OpBitwiseOr", "v2uint_20_10",
-                   "vec2<u32>", AstFor("v2uint_10_20"), "|",
-                   AstFor("v2uint_20_10")},
+        BinaryData{"v2uint", "v2uint_10_20", "OpBitwiseOr", "v2uint_20_10", "vec2<u32>",
+                   AstFor("v2uint_10_20"), "|", AstFor("v2uint_20_10")},
         // Both v2int
-        BinaryData{"v2int", "v2int_30_40", "OpBitwiseOr", "v2int_40_30",
-                   "vec2<i32>", AstFor("v2int_30_40"), "|",
-                   AstFor("v2int_40_30")}));
+        BinaryData{"v2int", "v2int_30_40", "OpBitwiseOr", "v2int_40_30", "vec2<i32>",
+                   AstFor("v2int_30_40"), "|", AstFor("v2int_40_30")}));
 
 INSTANTIATE_TEST_SUITE_P(
     SpvParserTest_BitwiseOr_MixedSignedness,
@@ -415,44 +376,40 @@
     ::testing::Values(
         // Mixed, uint <- int uint
         BinaryDataGeneral{"uint", "int_30", "OpBitwiseOr", "uint_10", "u32",
-                          "bitcast<u32>((30 | bitcast<i32>(10u)))"},
+                          "bitcast<u32>((30i | bitcast<i32>(10u)))"},
         // Mixed, int <- int uint
         BinaryDataGeneral{"int", "int_30", "OpBitwiseOr", "uint_10", "i32",
-                          "(30 | bitcast<i32>(10u))"},
+                          "(30i | bitcast<i32>(10u))"},
         // Mixed, uint <- uint int
         BinaryDataGeneral{"uint", "uint_10", "OpBitwiseOr", "int_30", "u32",
-                          "(10u | bitcast<u32>(30))"},
+                          "(10u | bitcast<u32>(30i))"},
         // Mixed, int <- uint uint
         BinaryDataGeneral{"int", "uint_20", "OpBitwiseOr", "uint_10", "i32",
                           "bitcast<i32>((20u | 10u))"},
         // Mixed, returning v2uint
         BinaryDataGeneral{
             "v2uint", "v2int_30_40", "OpBitwiseOr", "v2uint_10_20", "vec2<u32>",
-            R"(bitcast<vec2<u32>>((vec2<i32>(30, 40) | bitcast<vec2<i32>>(vec2<u32>(10u, 20u)))))"},
+            R"(bitcast<vec2<u32>>((vec2<i32>(30i, 40i) | bitcast<vec2<i32>>(vec2<u32>(10u, 20u)))))"},
         // Mixed, returning v2int
         BinaryDataGeneral{
             "v2int", "v2uint_10_20", "OpBitwiseOr", "v2int_40_30", "vec2<i32>",
-            R"(bitcast<vec2<i32>>((vec2<u32>(10u, 20u) | bitcast<vec2<u32>>(vec2<i32>(40, 30)))))"}));
+            R"(bitcast<vec2<i32>>((vec2<u32>(10u, 20u) | bitcast<vec2<u32>>(vec2<i32>(40i, 30i)))))"}));
 
 INSTANTIATE_TEST_SUITE_P(
     SpvParserTest_BitwiseXor,
     SpvBinaryBitTest,
     ::testing::Values(
         // Both uint
-        BinaryData{"uint", "uint_10", "OpBitwiseXor", "uint_20", "u32", "10u",
-                   "^", "20u"},
+        BinaryData{"uint", "uint_10", "OpBitwiseXor", "uint_20", "u32", "10u", "^", "20u"},
         // Both int
-        BinaryData{"int", "int_30", "OpBitwiseXor", "int_40", "i32", "30", "^",
-                   "40"},
+        BinaryData{"int", "int_30", "OpBitwiseXor", "int_40", "i32", "30i", "^", "40i"},
         // TODO(crbug.com/tint/678): Resolver fails on vector bitwise operations
         // Both v2uint
-        BinaryData{"v2uint", "v2uint_10_20", "OpBitwiseXor", "v2uint_20_10",
-                   "vec2<u32>", AstFor("v2uint_10_20"), "^",
-                   AstFor("v2uint_20_10")},
+        BinaryData{"v2uint", "v2uint_10_20", "OpBitwiseXor", "v2uint_20_10", "vec2<u32>",
+                   AstFor("v2uint_10_20"), "^", AstFor("v2uint_20_10")},
         // Both v2int
-        BinaryData{"v2int", "v2int_30_40", "OpBitwiseXor", "v2int_40_30",
-                   "vec2<i32>", AstFor("v2int_30_40"), "^",
-                   AstFor("v2int_40_30")}));
+        BinaryData{"v2int", "v2int_30_40", "OpBitwiseXor", "v2int_40_30", "vec2<i32>",
+                   AstFor("v2int_30_40"), "^", AstFor("v2int_40_30")}));
 
 INSTANTIATE_TEST_SUITE_P(
     SpvParserTest_BitwiseXor_MixedSignedness,
@@ -460,169 +417,164 @@
     ::testing::Values(
         // Mixed, uint <- int uint
         BinaryDataGeneral{"uint", "int_30", "OpBitwiseXor", "uint_10", "u32",
-                          "bitcast<u32>((30 ^ bitcast<i32>(10u)))"},
+                          "bitcast<u32>((30i ^ bitcast<i32>(10u)))"},
         // Mixed, int <- int uint
         BinaryDataGeneral{"int", "int_30", "OpBitwiseXor", "uint_10", "i32",
-                          "(30 ^ bitcast<i32>(10u))"},
+                          "(30i ^ bitcast<i32>(10u))"},
         // Mixed, uint <- uint int
         BinaryDataGeneral{"uint", "uint_10", "OpBitwiseXor", "int_30", "u32",
-                          "(10u ^ bitcast<u32>(30))"},
+                          "(10u ^ bitcast<u32>(30i))"},
         // Mixed, int <- uint uint
         BinaryDataGeneral{"int", "uint_20", "OpBitwiseXor", "uint_10", "i32",
                           "bitcast<i32>((20u ^ 10u))"},
         // Mixed, returning v2uint
         BinaryDataGeneral{
-            "v2uint", "v2int_30_40", "OpBitwiseXor", "v2uint_10_20",
-            "vec2<u32>",
-            R"(bitcast<vec2<u32>>((vec2<i32>(30, 40) ^ bitcast<vec2<i32>>(vec2<u32>(10u, 20u)))))"},
+            "v2uint", "v2int_30_40", "OpBitwiseXor", "v2uint_10_20", "vec2<u32>",
+            R"(bitcast<vec2<u32>>((vec2<i32>(30i, 40i) ^ bitcast<vec2<i32>>(vec2<u32>(10u, 20u)))))"},
         // Mixed, returning v2int
         BinaryDataGeneral{
             "v2int", "v2uint_10_20", "OpBitwiseXor", "v2int_40_30", "vec2<i32>",
-            R"(bitcast<vec2<i32>>((vec2<u32>(10u, 20u) ^ bitcast<vec2<u32>>(vec2<i32>(40, 30)))))"}));
+            R"(bitcast<vec2<i32>>((vec2<u32>(10u, 20u) ^ bitcast<vec2<u32>>(vec2<i32>(40i, 30i)))))"}));
 
 TEST_F(SpvUnaryBitTest, Not_Int_Int) {
-  const auto assembly = SimplePreamble() + R"(
+    const auto assembly = SimplePreamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpNot %int %int_30
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body, HasSubstr("let x_1 : i32 = ~(30);"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : i32 = ~(30i);"));
 }
 
 TEST_F(SpvUnaryBitTest, Not_Int_Uint) {
-  const auto assembly = SimplePreamble() + R"(
+    const auto assembly = SimplePreamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpNot %int %uint_10
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body, HasSubstr("let x_1 : i32 = bitcast<i32>(~(10u));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : i32 = bitcast<i32>(~(10u));"));
 }
 
 TEST_F(SpvUnaryBitTest, Not_Uint_Int) {
-  const auto assembly = SimplePreamble() + R"(
+    const auto assembly = SimplePreamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpNot %uint %int_30
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body, HasSubstr("let x_1 : u32 = bitcast<u32>(~(30));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : u32 = bitcast<u32>(~(30i));"));
 }
 
 TEST_F(SpvUnaryBitTest, Not_Uint_Uint) {
-  const auto assembly = SimplePreamble() + R"(
+    const auto assembly = SimplePreamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpNot %uint %uint_10
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body, HasSubstr("let x_1 : u32 = ~(10u);"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : u32 = ~(10u);"));
 }
 
 TEST_F(SpvUnaryBitTest, Not_SignedVec_SignedVec) {
-  const auto assembly = SimplePreamble() + R"(
+    const auto assembly = SimplePreamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpNot %v2int %v2int_30_40
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body, HasSubstr("let x_1 : vec2<i32> = ~(vec2<i32>(30, 40));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : vec2<i32> = ~(vec2<i32>(30i, 40i));"));
 }
 
 TEST_F(SpvUnaryBitTest, Not_SignedVec_UnsignedVec) {
-  const auto assembly = SimplePreamble() + R"(
+    const auto assembly = SimplePreamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpNot %v2int %v2uint_10_20
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(
-      body,
-      HasSubstr(
-          "let x_1 : vec2<i32> = bitcast<vec2<i32>>(~(vec2<u32>(10u, 20u)));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body,
+                HasSubstr("let x_1 : vec2<i32> = bitcast<vec2<i32>>(~(vec2<u32>(10u, 20u)));"));
 }
 
 TEST_F(SpvUnaryBitTest, Not_UnsignedVec_SignedVec) {
-  const auto assembly = SimplePreamble() + R"(
+    const auto assembly = SimplePreamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpNot %v2uint %v2int_30_40
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(
-      body,
-      HasSubstr(
-          "let x_1 : vec2<u32> = bitcast<vec2<u32>>(~(vec2<i32>(30, 40)));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body,
+                HasSubstr("let x_1 : vec2<u32> = bitcast<vec2<u32>>(~(vec2<i32>(30i, 40i)));"));
 }
 TEST_F(SpvUnaryBitTest, Not_UnsignedVec_UnsignedVec) {
-  const auto assembly = SimplePreamble() + R"(
+    const auto assembly = SimplePreamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpNot %v2uint %v2uint_10_20
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body, HasSubstr("let x_1 : vec2<u32> = ~(vec2<u32>(10u, 20u));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : vec2<u32> = ~(vec2<u32>(10u, 20u));"));
 }
 
 std::string BitTestPreamble() {
-  return R"(
+    return R"(
   OpCapability Shader
   %glsl = OpExtInstImport "GLSL.std.450"
   OpMemoryModel Logical GLSL450
@@ -635,7 +587,7 @@
   OpName %v2i1 "v2i1"
 
 )" + CommonTypes() +
-         R"(
+           R"(
 
   %100 = OpFunction %void None %voidfn
   %entry = OpLabel
@@ -648,399 +600,365 @@
 }
 
 TEST_F(SpvUnaryBitTest, BitCount_Uint_Uint) {
-  const auto assembly = BitTestPreamble() + R"(
+    const auto assembly = BitTestPreamble() + R"(
      %1 = OpBitCount %uint %u1
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body, HasSubstr("let x_1 : u32 = countOneBits(u1);")) << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : u32 = countOneBits(u1);")) << body;
 }
 
 TEST_F(SpvUnaryBitTest, BitCount_Uint_Int) {
-  const auto assembly = BitTestPreamble() + R"(
+    const auto assembly = BitTestPreamble() + R"(
      %1 = OpBitCount %uint %i1
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body,
-              HasSubstr("let x_1 : u32 = bitcast<u32>(countOneBits(i1));"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : u32 = bitcast<u32>(countOneBits(i1));")) << body;
 }
 
 TEST_F(SpvUnaryBitTest, BitCount_Int_Uint) {
-  const auto assembly = BitTestPreamble() + R"(
+    const auto assembly = BitTestPreamble() + R"(
      %1 = OpBitCount %int %u1
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body,
-              HasSubstr("let x_1 : i32 = bitcast<i32>(countOneBits(u1));"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : i32 = bitcast<i32>(countOneBits(u1));")) << body;
 }
 
 TEST_F(SpvUnaryBitTest, BitCount_Int_Int) {
-  const auto assembly = BitTestPreamble() + R"(
+    const auto assembly = BitTestPreamble() + R"(
      %1 = OpBitCount %int %i1
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body, HasSubstr("let x_1 : i32 = countOneBits(i1);")) << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : i32 = countOneBits(i1);")) << body;
 }
 
 TEST_F(SpvUnaryBitTest, BitCount_UintVector_UintVector) {
-  const auto assembly = BitTestPreamble() + R"(
+    const auto assembly = BitTestPreamble() + R"(
      %1 = OpBitCount %v2uint %v2u1
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body, HasSubstr("let x_1 : vec2<u32> = countOneBits(v2u1);"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : vec2<u32> = countOneBits(v2u1);")) << body;
 }
 
 TEST_F(SpvUnaryBitTest, BitCount_UintVector_IntVector) {
-  const auto assembly = BitTestPreamble() + R"(
+    const auto assembly = BitTestPreamble() + R"(
      %1 = OpBitCount %v2uint %v2i1
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(
-      body,
-      HasSubstr(
-          "let x_1 : vec2<u32> = bitcast<vec2<u32>>(countOneBits(v2i1));"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : vec2<u32> = bitcast<vec2<u32>>(countOneBits(v2i1));"))
+        << body;
 }
 
 TEST_F(SpvUnaryBitTest, BitCount_IntVector_UintVector) {
-  const auto assembly = BitTestPreamble() + R"(
+    const auto assembly = BitTestPreamble() + R"(
      %1 = OpBitCount %v2int %v2u1
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(
-      body,
-      HasSubstr(
-          "let x_1 : vec2<i32> = bitcast<vec2<i32>>(countOneBits(v2u1));"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : vec2<i32> = bitcast<vec2<i32>>(countOneBits(v2u1));"))
+        << body;
 }
 
 TEST_F(SpvUnaryBitTest, BitCount_IntVector_IntVector) {
-  const auto assembly = BitTestPreamble() + R"(
+    const auto assembly = BitTestPreamble() + R"(
      %1 = OpBitCount %v2int %v2i1
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body, HasSubstr("let x_1 : vec2<i32> = countOneBits(v2i1);"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : vec2<i32> = countOneBits(v2i1);")) << body;
 }
 
 TEST_F(SpvUnaryBitTest, BitReverse_Uint_Uint) {
-  const auto assembly = BitTestPreamble() + R"(
+    const auto assembly = BitTestPreamble() + R"(
      %1 = OpBitReverse %uint %u1
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body, HasSubstr("let x_1 : u32 = reverseBits(u1);")) << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : u32 = reverseBits(u1);")) << body;
 }
 
 TEST_F(SpvUnaryBitTest, BitReverse_Uint_Int) {
-  const auto assembly = BitTestPreamble() + R"(
+    const auto assembly = BitTestPreamble() + R"(
      %1 = OpBitReverse %uint %i1
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_FALSE(p->Parse());
-  EXPECT_FALSE(p->success());
-  EXPECT_THAT(
-      p->error(),
-      HasSubstr("Expected Base Type to be equal to Result Type: BitReverse"));
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_FALSE(p->Parse());
+    EXPECT_FALSE(p->success());
+    EXPECT_THAT(p->error(), HasSubstr("Expected Base Type to be equal to Result Type: BitReverse"));
 }
 
 TEST_F(SpvUnaryBitTest, BitReverse_Int_Uint) {
-  const auto assembly = BitTestPreamble() + R"(
+    const auto assembly = BitTestPreamble() + R"(
      %1 = OpBitReverse %int %u1
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_FALSE(p->Parse());
-  EXPECT_FALSE(p->success());
-  EXPECT_THAT(
-      p->error(),
-      HasSubstr("Expected Base Type to be equal to Result Type: BitReverse"));
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_FALSE(p->Parse());
+    EXPECT_FALSE(p->success());
+    EXPECT_THAT(p->error(), HasSubstr("Expected Base Type to be equal to Result Type: BitReverse"));
 }
 
 TEST_F(SpvUnaryBitTest, BitReverse_Int_Int) {
-  const auto assembly = BitTestPreamble() + R"(
+    const auto assembly = BitTestPreamble() + R"(
      %1 = OpBitReverse %int %i1
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body, HasSubstr("let x_1 : i32 = reverseBits(i1);")) << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : i32 = reverseBits(i1);")) << body;
 }
 
 TEST_F(SpvUnaryBitTest, BitReverse_UintVector_UintVector) {
-  const auto assembly = BitTestPreamble() + R"(
+    const auto assembly = BitTestPreamble() + R"(
      %1 = OpBitReverse %v2uint %v2u1
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body, HasSubstr("let x_1 : vec2<u32> = reverseBits(v2u1);"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : vec2<u32> = reverseBits(v2u1);")) << body;
 }
 
 TEST_F(SpvUnaryBitTest, BitReverse_UintVector_IntVector) {
-  const auto assembly = BitTestPreamble() + R"(
+    const auto assembly = BitTestPreamble() + R"(
      %1 = OpBitReverse %v2uint %v2i1
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_FALSE(p->Parse());
-  EXPECT_FALSE(p->success());
-  EXPECT_THAT(
-      p->error(),
-      HasSubstr("Expected Base Type to be equal to Result Type: BitReverse"));
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_FALSE(p->Parse());
+    EXPECT_FALSE(p->success());
+    EXPECT_THAT(p->error(), HasSubstr("Expected Base Type to be equal to Result Type: BitReverse"));
 }
 
 TEST_F(SpvUnaryBitTest, BitReverse_IntVector_UintVector) {
-  const auto assembly = BitTestPreamble() + R"(
+    const auto assembly = BitTestPreamble() + R"(
      %1 = OpBitReverse %v2int %v2u1
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_FALSE(p->Parse());
-  EXPECT_FALSE(p->success());
-  EXPECT_THAT(
-      p->error(),
-      HasSubstr("Expected Base Type to be equal to Result Type: BitReverse"));
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_FALSE(p->Parse());
+    EXPECT_FALSE(p->success());
+    EXPECT_THAT(p->error(), HasSubstr("Expected Base Type to be equal to Result Type: BitReverse"));
 }
 
 TEST_F(SpvUnaryBitTest, BitReverse_IntVector_IntVector) {
-  const auto assembly = BitTestPreamble() + R"(
+    const auto assembly = BitTestPreamble() + R"(
      %1 = OpBitReverse %v2int %v2i1
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body, HasSubstr("let x_1 : vec2<i32> = reverseBits(v2i1);"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : vec2<i32> = reverseBits(v2i1);")) << body;
 }
 
 TEST_F(SpvUnaryBitTest, InsertBits_Int) {
-  const auto assembly = BitTestPreamble() + R"(
+    const auto assembly = BitTestPreamble() + R"(
      %1 = OpBitFieldInsert %v2int %int_30 %int_40 %uint_10 %uint_20
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body,
-              HasSubstr("let x_1 : vec2<i32> = insertBits(30, 40, 10u, 20u);"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : vec2<i32> = insertBits(30i, 40i, 10u, 20u);")) << body;
 }
 
 TEST_F(SpvUnaryBitTest, InsertBits_IntVector) {
-  const auto assembly = BitTestPreamble() + R"(
+    const auto assembly = BitTestPreamble() + R"(
      %1 = OpBitFieldInsert %v2int %v2int_30_40 %v2int_40_30 %uint_10 %uint_20
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(
-      body,
-      HasSubstr(
-          R"(let x_1 : vec2<i32> = insertBits(vec2<i32>(30, 40), vec2<i32>(40, 30), 10u, 20u);)"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(
+        body,
+        HasSubstr(
+            R"(let x_1 : vec2<i32> = insertBits(vec2<i32>(30i, 40i), vec2<i32>(40i, 30i), 10u, 20u);)"))
+        << body;
 }
 
 TEST_F(SpvUnaryBitTest, InsertBits_Uint) {
-  const auto assembly = BitTestPreamble() + R"(
+    const auto assembly = BitTestPreamble() + R"(
      %1 = OpBitFieldInsert %v2uint %uint_20 %uint_10 %uint_10 %uint_20
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(
-      body, HasSubstr("let x_1 : vec2<u32> = insertBits(20u, 10u, 10u, 20u);"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : vec2<u32> = insertBits(20u, 10u, 10u, 20u);")) << body;
 }
 
 TEST_F(SpvUnaryBitTest, InsertBits_UintVector) {
-  const auto assembly = BitTestPreamble() + R"(
+    const auto assembly = BitTestPreamble() + R"(
      %1 = OpBitFieldInsert %v2uint %v2uint_10_20 %v2uint_20_10 %uint_10 %uint_20
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(
-      body,
-      HasSubstr(
-          R"(let x_1 : vec2<u32> = insertBits(vec2<u32>(10u, 20u), vec2<u32>(20u, 10u), 10u, 20u);)"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(
+        body,
+        HasSubstr(
+            R"(let x_1 : vec2<u32> = insertBits(vec2<u32>(10u, 20u), vec2<u32>(20u, 10u), 10u, 20u);)"))
+        << body;
 }
 
 TEST_F(SpvUnaryBitTest, ExtractBits_Int) {
-  const auto assembly = BitTestPreamble() + R"(
+    const auto assembly = BitTestPreamble() + R"(
      %1 = OpBitFieldSExtract %v2int %int_30 %uint_10 %uint_20
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body,
-              HasSubstr("let x_1 : vec2<i32> = extractBits(30, 10u, 20u);"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : vec2<i32> = extractBits(30i, 10u, 20u);")) << body;
 }
 
 TEST_F(SpvUnaryBitTest, ExtractBits_IntVector) {
-  const auto assembly = BitTestPreamble() + R"(
+    const auto assembly = BitTestPreamble() + R"(
      %1 = OpBitFieldSExtract %v2int %v2int_30_40 %uint_10 %uint_20
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(
-      body,
-      HasSubstr(
-          "let x_1 : vec2<i32> = extractBits(vec2<i32>(30, 40), 10u, 20u);"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body,
+                HasSubstr("let x_1 : vec2<i32> = extractBits(vec2<i32>(30i, 40i), 10u, 20u);"))
+        << body;
 }
 
 TEST_F(SpvUnaryBitTest, ExtractBits_Uint) {
-  const auto assembly = BitTestPreamble() + R"(
+    const auto assembly = BitTestPreamble() + R"(
      %1 = OpBitFieldUExtract %v2uint %uint_20 %uint_10 %uint_20
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body,
-              HasSubstr("let x_1 : vec2<u32> = extractBits(20u, 10u, 20u);"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : vec2<u32> = extractBits(20u, 10u, 20u);")) << body;
 }
 
 TEST_F(SpvUnaryBitTest, ExtractBits_UintVector) {
-  const auto assembly = BitTestPreamble() + R"(
+    const auto assembly = BitTestPreamble() + R"(
      %1 = OpBitFieldUExtract %v2uint %v2uint_10_20 %uint_10 %uint_20
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(
-      body,
-      HasSubstr(
-          "let x_1 : vec2<u32> = extractBits(vec2<u32>(10u, 20u), 10u, 20u);"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body,
+                HasSubstr("let x_1 : vec2<u32> = extractBits(vec2<u32>(10u, 20u), 10u, 20u);"))
+        << body;
 }
 
 }  // namespace
diff --git a/src/tint/reader/spirv/function_call_test.cc b/src/tint/reader/spirv/function_call_test.cc
index 6aba922..aa1789b 100644
--- a/src/tint/reader/spirv/function_call_test.cc
+++ b/src/tint/reader/spirv/function_call_test.cc
@@ -24,7 +24,7 @@
 using ::testing::HasSubstr;
 
 std::string Preamble() {
-  return R"(
+    return R"(
      OpCapability Shader
      OpMemoryModel Logical Simple
      OpEntryPoint Fragment %100 "x_100"
@@ -33,7 +33,7 @@
 }
 
 TEST_F(SpvParserTest, EmitStatement_VoidCallNoParams) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
      %void = OpTypeVoid
      %voidfn = OpTypeFunction %void
 
@@ -48,9 +48,9 @@
      OpReturn
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error();
-  const auto got = test::ToString(p->program());
-  const char* expect = R"(fn x_50() {
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error();
+    const auto got = test::ToString(p->program());
+    const char* expect = R"(fn x_50() {
   return;
 }
 
@@ -64,11 +64,11 @@
   x_100_1();
 }
 )";
-  EXPECT_EQ(expect, got);
+    EXPECT_EQ(expect, got);
 }
 
 TEST_F(SpvParserTest, EmitStatement_ScalarCallNoParams) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
      %void = OpTypeVoid
      %voidfn = OpTypeFunction %void
      %uint = OpTypeInt 32 0
@@ -86,27 +86,26 @@
      OpReturn
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  ast::StatementList f100;
-  {
-    auto fe = p->function_emitter(100);
-    EXPECT_TRUE(fe.EmitBody()) << p->error();
-    f100 = fe.ast_body();
-  }
-  ast::StatementList f50;
-  {
-    auto fe = p->function_emitter(50);
-    EXPECT_TRUE(fe.EmitBody()) << p->error();
-    f50 = fe.ast_body();
-  }
-  auto program = p->program();
-  EXPECT_THAT(test::ToString(program, f100),
-              HasSubstr("let x_1 : u32 = x_50();\nreturn;"));
-  EXPECT_THAT(test::ToString(program, f50), HasSubstr("return 42u;"));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    ast::StatementList f100;
+    {
+        auto fe = p->function_emitter(100);
+        EXPECT_TRUE(fe.EmitBody()) << p->error();
+        f100 = fe.ast_body();
+    }
+    ast::StatementList f50;
+    {
+        auto fe = p->function_emitter(50);
+        EXPECT_TRUE(fe.EmitBody()) << p->error();
+        f50 = fe.ast_body();
+    }
+    auto program = p->program();
+    EXPECT_THAT(test::ToString(program, f100), HasSubstr("let x_1 : u32 = x_50();\nreturn;"));
+    EXPECT_THAT(test::ToString(program, f50), HasSubstr("return 42u;"));
 }
 
 TEST_F(SpvParserTest, EmitStatement_ScalarCallNoParamsUsedTwice) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
      %void = OpTypeVoid
      %voidfn = OpTypeFunction %void
      %uint = OpTypeInt 32 0
@@ -128,31 +127,31 @@
      OpReturn
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  ast::StatementList f100;
-  {
-    auto fe = p->function_emitter(100);
-    EXPECT_TRUE(fe.EmitBody()) << p->error();
-    f100 = fe.ast_body();
-  }
-  ast::StatementList f50;
-  {
-    auto fe = p->function_emitter(50);
-    EXPECT_TRUE(fe.EmitBody()) << p->error();
-    f50 = fe.ast_body();
-  }
-  auto program = p->program();
-  EXPECT_EQ(test::ToString(program, f100), R"(var x_10 : u32;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    ast::StatementList f100;
+    {
+        auto fe = p->function_emitter(100);
+        EXPECT_TRUE(fe.EmitBody()) << p->error();
+        f100 = fe.ast_body();
+    }
+    ast::StatementList f50;
+    {
+        auto fe = p->function_emitter(50);
+        EXPECT_TRUE(fe.EmitBody()) << p->error();
+        f50 = fe.ast_body();
+    }
+    auto program = p->program();
+    EXPECT_EQ(test::ToString(program, f100), R"(var x_10 : u32;
 let x_1 : u32 = x_50();
 x_10 = x_1;
 x_10 = x_1;
 return;
 )");
-  EXPECT_THAT(test::ToString(program, f50), HasSubstr("return 42u;"));
+    EXPECT_THAT(test::ToString(program, f50), HasSubstr("return 42u;"));
 }
 
 TEST_F(SpvParserTest, EmitStatement_CallWithParams) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
      %void = OpTypeVoid
      %voidfn = OpTypeFunction %void
      %uint = OpTypeInt 32 0
@@ -174,10 +173,10 @@
      OpReturn
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error();
-  EXPECT_TRUE(p->error().empty());
-  const auto program_ast_str = test::ToString(p->program());
-  const std::string expected = R"(fn x_50(x_51 : u32, x_52 : u32) -> u32 {
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error();
+    EXPECT_TRUE(p->error().empty());
+    const auto program_ast_str = test::ToString(p->program());
+    const std::string expected = R"(fn x_50(x_51 : u32, x_52 : u32) -> u32 {
   return (x_51 + x_52);
 }
 
@@ -191,7 +190,7 @@
   x_100_1();
 }
 )";
-  EXPECT_EQ(program_ast_str, expected);
+    EXPECT_EQ(program_ast_str, expected);
 }
 
 }  // namespace
diff --git a/src/tint/reader/spirv/function_cfg_test.cc b/src/tint/reader/spirv/function_cfg_test.cc
index bd3c98c..edeea55 100644
--- a/src/tint/reader/spirv/function_cfg_test.cc
+++ b/src/tint/reader/spirv/function_cfg_test.cc
@@ -27,13 +27,13 @@
 using SpvParserCFGTest = SpvParserTest;
 
 std::string Dump(const std::vector<uint32_t>& v) {
-  std::ostringstream o;
-  o << "{";
-  for (auto a : v) {
-    o << a << " ";
-  }
-  o << "}";
-  return o.str();
+    std::ostringstream o;
+    o << "{";
+    for (auto a : v) {
+        o << a << " ";
+    }
+    o << "}";
+    return o.str();
 }
 
 using ::testing::ElementsAre;
@@ -41,7 +41,7 @@
 using ::testing::UnorderedElementsAre;
 
 std::string CommonTypes() {
-  return R"(
+    return R"(
     OpCapability Shader
     OpMemoryModel Logical Simple
     OpEntryPoint Fragment %100 "main"
@@ -92,38 +92,38 @@
 /// flow constructs.
 /// @returns the result of labeling control flow constructs.
 bool FlowLabelControlFlowConstructs(FunctionEmitter* fe) {
-  fe->RegisterBasicBlocks();
-  EXPECT_TRUE(fe->RegisterMerges()) << fe->parser()->error();
-  fe->ComputeBlockOrderAndPositions();
-  EXPECT_TRUE(fe->VerifyHeaderContinueMergeOrder()) << fe->parser()->error();
-  return fe->LabelControlFlowConstructs();
+    fe->RegisterBasicBlocks();
+    EXPECT_TRUE(fe->RegisterMerges()) << fe->parser()->error();
+    fe->ComputeBlockOrderAndPositions();
+    EXPECT_TRUE(fe->VerifyHeaderContinueMergeOrder()) << fe->parser()->error();
+    return fe->LabelControlFlowConstructs();
 }
 
 /// Runs the necessary flow until and including finding switch case
 /// headers.
 /// @returns the result of finding switch case headers.
 bool FlowFindSwitchCaseHeaders(FunctionEmitter* fe) {
-  EXPECT_TRUE(FlowLabelControlFlowConstructs(fe)) << fe->parser()->error();
-  return fe->FindSwitchCaseHeaders();
+    EXPECT_TRUE(FlowLabelControlFlowConstructs(fe)) << fe->parser()->error();
+    return fe->FindSwitchCaseHeaders();
 }
 
 /// Runs the necessary flow until and including classify CFG edges,
 /// @returns the result of classify CFG edges.
 bool FlowClassifyCFGEdges(FunctionEmitter* fe) {
-  EXPECT_TRUE(FlowFindSwitchCaseHeaders(fe)) << fe->parser()->error();
-  return fe->ClassifyCFGEdges();
+    EXPECT_TRUE(FlowFindSwitchCaseHeaders(fe)) << fe->parser()->error();
+    return fe->ClassifyCFGEdges();
 }
 
 /// Runs the necessary flow until and including finding if-selection
 /// internal headers.
 /// @returns the result of classify CFG edges.
 bool FlowFindIfSelectionInternalHeaders(FunctionEmitter* fe) {
-  EXPECT_TRUE(FlowClassifyCFGEdges(fe)) << fe->parser()->error();
-  return fe->FindIfSelectionInternalHeaders();
+    EXPECT_TRUE(FlowClassifyCFGEdges(fe)) << fe->parser()->error();
+    return fe->FindIfSelectionInternalHeaders();
 }
 
 TEST_F(SpvParserCFGTest, TerminatorsAreValid_SingleBlock) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %42 = OpLabel
@@ -131,14 +131,14 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  EXPECT_TRUE(fe.TerminatorsAreValid());
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    EXPECT_TRUE(fe.TerminatorsAreValid());
 }
 
 TEST_F(SpvParserCFGTest, TerminatorsAreValid_Sequence) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %20 = OpLabel
@@ -149,14 +149,14 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  EXPECT_TRUE(fe.TerminatorsAreValid()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    EXPECT_TRUE(fe.TerminatorsAreValid()) << p->error();
 }
 
 TEST_F(SpvParserCFGTest, TerminatorsAreValid_If) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %20 = OpLabel
@@ -174,14 +174,14 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  EXPECT_TRUE(fe.TerminatorsAreValid()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    EXPECT_TRUE(fe.TerminatorsAreValid()) << p->error();
 }
 
 TEST_F(SpvParserCFGTest, TerminatorsAreValid_Switch) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -202,14 +202,14 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  EXPECT_TRUE(fe.TerminatorsAreValid());
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    EXPECT_TRUE(fe.TerminatorsAreValid());
 }
 
 TEST_F(SpvParserCFGTest, TerminatorsAreValid_Loop_SingleBlock) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -224,14 +224,14 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  EXPECT_TRUE(fe.TerminatorsAreValid());
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    EXPECT_TRUE(fe.TerminatorsAreValid());
 }
 
 TEST_F(SpvParserCFGTest, TerminatorsAreValid_Loop_Simple) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -252,14 +252,14 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  EXPECT_TRUE(fe.TerminatorsAreValid());
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    EXPECT_TRUE(fe.TerminatorsAreValid());
 }
 
 TEST_F(SpvParserCFGTest, TerminatorsAreValid_Kill) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -267,14 +267,14 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  EXPECT_TRUE(fe.TerminatorsAreValid());
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    EXPECT_TRUE(fe.TerminatorsAreValid());
 }
 
 TEST_F(SpvParserCFGTest, TerminatorsAreValid_Unreachable) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -282,26 +282,26 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  EXPECT_TRUE(fe.TerminatorsAreValid());
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    EXPECT_TRUE(fe.TerminatorsAreValid());
 }
 
 TEST_F(SpvParserCFGTest, TerminatorsAreValid_MissingTerminator) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
 
      OpFunctionEnd
   )"));
-  // The SPIRV-Tools internal representation rejects this case earlier.
-  EXPECT_FALSE(p->BuildAndParseInternalModuleExceptFunctions());
+    // The SPIRV-Tools internal representation rejects this case earlier.
+    EXPECT_FALSE(p->BuildAndParseInternalModuleExceptFunctions());
 }
 
 TEST_F(SpvParserCFGTest, TerminatorsAreValid_DisallowLoopToEntryBlock) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -312,15 +312,15 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  EXPECT_FALSE(fe.TerminatorsAreValid());
-  EXPECT_THAT(p->error(), Eq("Block 20 branches to function entry block 10"));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    EXPECT_FALSE(fe.TerminatorsAreValid());
+    EXPECT_THAT(p->error(), Eq("Block 20 branches to function entry block 10"));
 }
 
 TEST_F(SpvParserCFGTest, TerminatorsAreValid_DisallowNonBlock) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -328,17 +328,16 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  EXPECT_FALSE(fe.TerminatorsAreValid());
-  EXPECT_THAT(p->error(),
-              Eq("Block 10 in function 100 branches to 999 which is "
-                 "not a block in the function"));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    EXPECT_FALSE(fe.TerminatorsAreValid());
+    EXPECT_THAT(p->error(), Eq("Block 10 in function 100 branches to 999 which is "
+                               "not a block in the function"));
 }
 
 TEST_F(SpvParserCFGTest, TerminatorsAreValid_DisallowBlockInDifferentFunction) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -354,16 +353,16 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  EXPECT_FALSE(fe.TerminatorsAreValid());
-  EXPECT_THAT(p->error(), Eq("Block 10 in function 100 branches to 210 which "
-                             "is not a block in the function"));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    EXPECT_FALSE(fe.TerminatorsAreValid());
+    EXPECT_THAT(p->error(), Eq("Block 10 in function 100 branches to 210 which "
+                               "is not a block in the function"));
 }
 
 TEST_F(SpvParserCFGTest, RegisterMerges_NoMerges) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -371,22 +370,22 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  EXPECT_TRUE(fe.RegisterMerges());
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    EXPECT_TRUE(fe.RegisterMerges());
 
-  const auto* bi = fe.GetBlockInfo(10);
-  ASSERT_NE(bi, nullptr);
-  EXPECT_EQ(bi->merge_for_header, 0u);
-  EXPECT_EQ(bi->continue_for_header, 0u);
-  EXPECT_EQ(bi->header_for_merge, 0u);
-  EXPECT_EQ(bi->header_for_continue, 0u);
-  EXPECT_FALSE(bi->is_continue_entire_loop);
+    const auto* bi = fe.GetBlockInfo(10);
+    ASSERT_NE(bi, nullptr);
+    EXPECT_EQ(bi->merge_for_header, 0u);
+    EXPECT_EQ(bi->continue_for_header, 0u);
+    EXPECT_EQ(bi->header_for_merge, 0u);
+    EXPECT_EQ(bi->header_for_continue, 0u);
+    EXPECT_FALSE(bi->is_continue_entire_loop);
 }
 
 TEST_F(SpvParserCFGTest, RegisterMerges_GoodSelectionMerge_BranchConditional) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -401,41 +400,41 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  EXPECT_TRUE(fe.RegisterMerges());
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    EXPECT_TRUE(fe.RegisterMerges());
 
-  // Header points to the merge
-  const auto* bi10 = fe.GetBlockInfo(10);
-  ASSERT_NE(bi10, nullptr);
-  EXPECT_EQ(bi10->merge_for_header, 99u);
-  EXPECT_EQ(bi10->continue_for_header, 0u);
-  EXPECT_EQ(bi10->header_for_merge, 0u);
-  EXPECT_EQ(bi10->header_for_continue, 0u);
-  EXPECT_FALSE(bi10->is_continue_entire_loop);
+    // Header points to the merge
+    const auto* bi10 = fe.GetBlockInfo(10);
+    ASSERT_NE(bi10, nullptr);
+    EXPECT_EQ(bi10->merge_for_header, 99u);
+    EXPECT_EQ(bi10->continue_for_header, 0u);
+    EXPECT_EQ(bi10->header_for_merge, 0u);
+    EXPECT_EQ(bi10->header_for_continue, 0u);
+    EXPECT_FALSE(bi10->is_continue_entire_loop);
 
-  // Middle block is neither header nor merge
-  const auto* bi20 = fe.GetBlockInfo(20);
-  ASSERT_NE(bi20, nullptr);
-  EXPECT_EQ(bi20->merge_for_header, 0u);
-  EXPECT_EQ(bi20->continue_for_header, 0u);
-  EXPECT_EQ(bi20->header_for_merge, 0u);
-  EXPECT_EQ(bi20->header_for_continue, 0u);
-  EXPECT_FALSE(bi20->is_continue_entire_loop);
+    // Middle block is neither header nor merge
+    const auto* bi20 = fe.GetBlockInfo(20);
+    ASSERT_NE(bi20, nullptr);
+    EXPECT_EQ(bi20->merge_for_header, 0u);
+    EXPECT_EQ(bi20->continue_for_header, 0u);
+    EXPECT_EQ(bi20->header_for_merge, 0u);
+    EXPECT_EQ(bi20->header_for_continue, 0u);
+    EXPECT_FALSE(bi20->is_continue_entire_loop);
 
-  // Merge block points to the header
-  const auto* bi99 = fe.GetBlockInfo(99);
-  ASSERT_NE(bi99, nullptr);
-  EXPECT_EQ(bi99->merge_for_header, 0u);
-  EXPECT_EQ(bi99->continue_for_header, 0u);
-  EXPECT_EQ(bi99->header_for_merge, 10u);
-  EXPECT_EQ(bi99->header_for_continue, 0u);
-  EXPECT_FALSE(bi99->is_continue_entire_loop);
+    // Merge block points to the header
+    const auto* bi99 = fe.GetBlockInfo(99);
+    ASSERT_NE(bi99, nullptr);
+    EXPECT_EQ(bi99->merge_for_header, 0u);
+    EXPECT_EQ(bi99->continue_for_header, 0u);
+    EXPECT_EQ(bi99->header_for_merge, 10u);
+    EXPECT_EQ(bi99->header_for_continue, 0u);
+    EXPECT_FALSE(bi99->is_continue_entire_loop);
 }
 
 TEST_F(SpvParserCFGTest, RegisterMerges_GoodSelectionMerge_Switch) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -450,41 +449,41 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  EXPECT_TRUE(fe.RegisterMerges());
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    EXPECT_TRUE(fe.RegisterMerges());
 
-  // Header points to the merge
-  const auto* bi10 = fe.GetBlockInfo(10);
-  ASSERT_NE(bi10, nullptr);
-  EXPECT_EQ(bi10->merge_for_header, 99u);
-  EXPECT_EQ(bi10->continue_for_header, 0u);
-  EXPECT_EQ(bi10->header_for_merge, 0u);
-  EXPECT_EQ(bi10->header_for_continue, 0u);
-  EXPECT_FALSE(bi10->is_continue_entire_loop);
+    // Header points to the merge
+    const auto* bi10 = fe.GetBlockInfo(10);
+    ASSERT_NE(bi10, nullptr);
+    EXPECT_EQ(bi10->merge_for_header, 99u);
+    EXPECT_EQ(bi10->continue_for_header, 0u);
+    EXPECT_EQ(bi10->header_for_merge, 0u);
+    EXPECT_EQ(bi10->header_for_continue, 0u);
+    EXPECT_FALSE(bi10->is_continue_entire_loop);
 
-  // Middle block is neither header nor merge
-  const auto* bi20 = fe.GetBlockInfo(20);
-  ASSERT_NE(bi20, nullptr);
-  EXPECT_EQ(bi20->merge_for_header, 0u);
-  EXPECT_EQ(bi20->continue_for_header, 0u);
-  EXPECT_EQ(bi20->header_for_merge, 0u);
-  EXPECT_EQ(bi20->header_for_continue, 0u);
-  EXPECT_FALSE(bi20->is_continue_entire_loop);
+    // Middle block is neither header nor merge
+    const auto* bi20 = fe.GetBlockInfo(20);
+    ASSERT_NE(bi20, nullptr);
+    EXPECT_EQ(bi20->merge_for_header, 0u);
+    EXPECT_EQ(bi20->continue_for_header, 0u);
+    EXPECT_EQ(bi20->header_for_merge, 0u);
+    EXPECT_EQ(bi20->header_for_continue, 0u);
+    EXPECT_FALSE(bi20->is_continue_entire_loop);
 
-  // Merge block points to the header
-  const auto* bi99 = fe.GetBlockInfo(99);
-  ASSERT_NE(bi99, nullptr);
-  EXPECT_EQ(bi99->merge_for_header, 0u);
-  EXPECT_EQ(bi99->continue_for_header, 0u);
-  EXPECT_EQ(bi99->header_for_merge, 10u);
-  EXPECT_EQ(bi99->header_for_continue, 0u);
-  EXPECT_FALSE(bi99->is_continue_entire_loop);
+    // Merge block points to the header
+    const auto* bi99 = fe.GetBlockInfo(99);
+    ASSERT_NE(bi99, nullptr);
+    EXPECT_EQ(bi99->merge_for_header, 0u);
+    EXPECT_EQ(bi99->continue_for_header, 0u);
+    EXPECT_EQ(bi99->header_for_merge, 10u);
+    EXPECT_EQ(bi99->header_for_continue, 0u);
+    EXPECT_FALSE(bi99->is_continue_entire_loop);
 }
 
 TEST_F(SpvParserCFGTest, RegisterMerges_GoodLoopMerge_SingleBlockLoop) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -499,42 +498,41 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  EXPECT_TRUE(fe.RegisterMerges());
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    EXPECT_TRUE(fe.RegisterMerges());
 
-  // Entry block is not special
-  const auto* bi10 = fe.GetBlockInfo(10);
-  ASSERT_NE(bi10, nullptr);
-  EXPECT_EQ(bi10->merge_for_header, 0u);
-  EXPECT_EQ(bi10->continue_for_header, 0u);
-  EXPECT_EQ(bi10->header_for_merge, 0u);
-  EXPECT_EQ(bi10->header_for_continue, 0u);
-  EXPECT_FALSE(bi10->is_continue_entire_loop);
+    // Entry block is not special
+    const auto* bi10 = fe.GetBlockInfo(10);
+    ASSERT_NE(bi10, nullptr);
+    EXPECT_EQ(bi10->merge_for_header, 0u);
+    EXPECT_EQ(bi10->continue_for_header, 0u);
+    EXPECT_EQ(bi10->header_for_merge, 0u);
+    EXPECT_EQ(bi10->header_for_continue, 0u);
+    EXPECT_FALSE(bi10->is_continue_entire_loop);
 
-  // Single block loop is its own continue, and marked as single block loop.
-  const auto* bi20 = fe.GetBlockInfo(20);
-  ASSERT_NE(bi20, nullptr);
-  EXPECT_EQ(bi20->merge_for_header, 99u);
-  EXPECT_EQ(bi20->continue_for_header, 20u);
-  EXPECT_EQ(bi20->header_for_merge, 0u);
-  EXPECT_EQ(bi20->header_for_continue, 20u);
-  EXPECT_TRUE(bi20->is_continue_entire_loop);
+    // Single block loop is its own continue, and marked as single block loop.
+    const auto* bi20 = fe.GetBlockInfo(20);
+    ASSERT_NE(bi20, nullptr);
+    EXPECT_EQ(bi20->merge_for_header, 99u);
+    EXPECT_EQ(bi20->continue_for_header, 20u);
+    EXPECT_EQ(bi20->header_for_merge, 0u);
+    EXPECT_EQ(bi20->header_for_continue, 20u);
+    EXPECT_TRUE(bi20->is_continue_entire_loop);
 
-  // Merge block points to the header
-  const auto* bi99 = fe.GetBlockInfo(99);
-  ASSERT_NE(bi99, nullptr);
-  EXPECT_EQ(bi99->merge_for_header, 0u);
-  EXPECT_EQ(bi99->continue_for_header, 0u);
-  EXPECT_EQ(bi99->header_for_merge, 20u);
-  EXPECT_EQ(bi99->header_for_continue, 0u);
-  EXPECT_FALSE(bi99->is_continue_entire_loop);
+    // Merge block points to the header
+    const auto* bi99 = fe.GetBlockInfo(99);
+    ASSERT_NE(bi99, nullptr);
+    EXPECT_EQ(bi99->merge_for_header, 0u);
+    EXPECT_EQ(bi99->continue_for_header, 0u);
+    EXPECT_EQ(bi99->header_for_merge, 20u);
+    EXPECT_EQ(bi99->header_for_continue, 0u);
+    EXPECT_FALSE(bi99->is_continue_entire_loop);
 }
 
-TEST_F(SpvParserCFGTest,
-       RegisterMerges_GoodLoopMerge_MultiBlockLoop_ContinueIsHeader) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, RegisterMerges_GoodLoopMerge_MultiBlockLoop_ContinueIsHeader) {
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -552,42 +550,41 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  EXPECT_TRUE(fe.RegisterMerges());
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    EXPECT_TRUE(fe.RegisterMerges());
 
-  // Loop header points to continue (itself) and merge
-  const auto* bi20 = fe.GetBlockInfo(20);
-  ASSERT_NE(bi20, nullptr);
-  EXPECT_EQ(bi20->merge_for_header, 99u);
-  EXPECT_EQ(bi20->continue_for_header, 20u);
-  EXPECT_EQ(bi20->header_for_merge, 0u);
-  EXPECT_EQ(bi20->header_for_continue, 20u);
-  EXPECT_TRUE(bi20->is_continue_entire_loop);
+    // Loop header points to continue (itself) and merge
+    const auto* bi20 = fe.GetBlockInfo(20);
+    ASSERT_NE(bi20, nullptr);
+    EXPECT_EQ(bi20->merge_for_header, 99u);
+    EXPECT_EQ(bi20->continue_for_header, 20u);
+    EXPECT_EQ(bi20->header_for_merge, 0u);
+    EXPECT_EQ(bi20->header_for_continue, 20u);
+    EXPECT_TRUE(bi20->is_continue_entire_loop);
 
-  // Backedge block, but is not a declared header, merge, or continue
-  const auto* bi40 = fe.GetBlockInfo(40);
-  ASSERT_NE(bi40, nullptr);
-  EXPECT_EQ(bi40->merge_for_header, 0u);
-  EXPECT_EQ(bi40->continue_for_header, 0u);
-  EXPECT_EQ(bi40->header_for_merge, 0u);
-  EXPECT_EQ(bi40->header_for_continue, 0u);
-  EXPECT_FALSE(bi40->is_continue_entire_loop);
+    // Backedge block, but is not a declared header, merge, or continue
+    const auto* bi40 = fe.GetBlockInfo(40);
+    ASSERT_NE(bi40, nullptr);
+    EXPECT_EQ(bi40->merge_for_header, 0u);
+    EXPECT_EQ(bi40->continue_for_header, 0u);
+    EXPECT_EQ(bi40->header_for_merge, 0u);
+    EXPECT_EQ(bi40->header_for_continue, 0u);
+    EXPECT_FALSE(bi40->is_continue_entire_loop);
 
-  // Merge block points to the header
-  const auto* bi99 = fe.GetBlockInfo(99);
-  ASSERT_NE(bi99, nullptr);
-  EXPECT_EQ(bi99->merge_for_header, 0u);
-  EXPECT_EQ(bi99->continue_for_header, 0u);
-  EXPECT_EQ(bi99->header_for_merge, 20u);
-  EXPECT_EQ(bi99->header_for_continue, 0u);
-  EXPECT_FALSE(bi99->is_continue_entire_loop);
+    // Merge block points to the header
+    const auto* bi99 = fe.GetBlockInfo(99);
+    ASSERT_NE(bi99, nullptr);
+    EXPECT_EQ(bi99->merge_for_header, 0u);
+    EXPECT_EQ(bi99->continue_for_header, 0u);
+    EXPECT_EQ(bi99->header_for_merge, 20u);
+    EXPECT_EQ(bi99->header_for_continue, 0u);
+    EXPECT_FALSE(bi99->is_continue_entire_loop);
 }
 
-TEST_F(SpvParserCFGTest,
-       RegisterMerges_GoodLoopMerge_MultiBlockLoop_ContinueIsNotHeader_Branch) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, RegisterMerges_GoodLoopMerge_MultiBlockLoop_ContinueIsNotHeader_Branch) {
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -608,43 +605,43 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  EXPECT_TRUE(fe.RegisterMerges());
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    EXPECT_TRUE(fe.RegisterMerges());
 
-  // Loop header points to continue and merge
-  const auto* bi20 = fe.GetBlockInfo(20);
-  ASSERT_NE(bi20, nullptr);
-  EXPECT_EQ(bi20->merge_for_header, 99u);
-  EXPECT_EQ(bi20->continue_for_header, 40u);
-  EXPECT_EQ(bi20->header_for_merge, 0u);
-  EXPECT_EQ(bi20->header_for_continue, 0u);
-  EXPECT_FALSE(bi20->is_continue_entire_loop);
+    // Loop header points to continue and merge
+    const auto* bi20 = fe.GetBlockInfo(20);
+    ASSERT_NE(bi20, nullptr);
+    EXPECT_EQ(bi20->merge_for_header, 99u);
+    EXPECT_EQ(bi20->continue_for_header, 40u);
+    EXPECT_EQ(bi20->header_for_merge, 0u);
+    EXPECT_EQ(bi20->header_for_continue, 0u);
+    EXPECT_FALSE(bi20->is_continue_entire_loop);
 
-  // Continue block points to header
-  const auto* bi40 = fe.GetBlockInfo(40);
-  ASSERT_NE(bi40, nullptr);
-  EXPECT_EQ(bi40->merge_for_header, 0u);
-  EXPECT_EQ(bi40->continue_for_header, 0u);
-  EXPECT_EQ(bi40->header_for_merge, 0u);
-  EXPECT_EQ(bi40->header_for_continue, 20u);
-  EXPECT_FALSE(bi40->is_continue_entire_loop);
+    // Continue block points to header
+    const auto* bi40 = fe.GetBlockInfo(40);
+    ASSERT_NE(bi40, nullptr);
+    EXPECT_EQ(bi40->merge_for_header, 0u);
+    EXPECT_EQ(bi40->continue_for_header, 0u);
+    EXPECT_EQ(bi40->header_for_merge, 0u);
+    EXPECT_EQ(bi40->header_for_continue, 20u);
+    EXPECT_FALSE(bi40->is_continue_entire_loop);
 
-  // Merge block points to the header
-  const auto* bi99 = fe.GetBlockInfo(99);
-  ASSERT_NE(bi99, nullptr);
-  EXPECT_EQ(bi99->merge_for_header, 0u);
-  EXPECT_EQ(bi99->continue_for_header, 0u);
-  EXPECT_EQ(bi99->header_for_merge, 20u);
-  EXPECT_EQ(bi99->header_for_continue, 0u);
-  EXPECT_FALSE(bi99->is_continue_entire_loop);
+    // Merge block points to the header
+    const auto* bi99 = fe.GetBlockInfo(99);
+    ASSERT_NE(bi99, nullptr);
+    EXPECT_EQ(bi99->merge_for_header, 0u);
+    EXPECT_EQ(bi99->continue_for_header, 0u);
+    EXPECT_EQ(bi99->header_for_merge, 20u);
+    EXPECT_EQ(bi99->header_for_continue, 0u);
+    EXPECT_FALSE(bi99->is_continue_entire_loop);
 }
 
 TEST_F(
     SpvParserCFGTest,
     RegisterMerges_GoodLoopMerge_MultiBlockLoop_ContinueIsNotHeader_BranchConditional) {  // NOLINT
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -665,41 +662,41 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  EXPECT_TRUE(fe.RegisterMerges());
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    EXPECT_TRUE(fe.RegisterMerges());
 
-  // Loop header points to continue and merge
-  const auto* bi20 = fe.GetBlockInfo(20);
-  ASSERT_NE(bi20, nullptr);
-  EXPECT_EQ(bi20->merge_for_header, 99u);
-  EXPECT_EQ(bi20->continue_for_header, 40u);
-  EXPECT_EQ(bi20->header_for_merge, 0u);
-  EXPECT_EQ(bi20->header_for_continue, 0u);
-  EXPECT_FALSE(bi20->is_continue_entire_loop);
+    // Loop header points to continue and merge
+    const auto* bi20 = fe.GetBlockInfo(20);
+    ASSERT_NE(bi20, nullptr);
+    EXPECT_EQ(bi20->merge_for_header, 99u);
+    EXPECT_EQ(bi20->continue_for_header, 40u);
+    EXPECT_EQ(bi20->header_for_merge, 0u);
+    EXPECT_EQ(bi20->header_for_continue, 0u);
+    EXPECT_FALSE(bi20->is_continue_entire_loop);
 
-  // Continue block points to header
-  const auto* bi40 = fe.GetBlockInfo(40);
-  ASSERT_NE(bi40, nullptr);
-  EXPECT_EQ(bi40->merge_for_header, 0u);
-  EXPECT_EQ(bi40->continue_for_header, 0u);
-  EXPECT_EQ(bi40->header_for_merge, 0u);
-  EXPECT_EQ(bi40->header_for_continue, 20u);
-  EXPECT_FALSE(bi40->is_continue_entire_loop);
+    // Continue block points to header
+    const auto* bi40 = fe.GetBlockInfo(40);
+    ASSERT_NE(bi40, nullptr);
+    EXPECT_EQ(bi40->merge_for_header, 0u);
+    EXPECT_EQ(bi40->continue_for_header, 0u);
+    EXPECT_EQ(bi40->header_for_merge, 0u);
+    EXPECT_EQ(bi40->header_for_continue, 20u);
+    EXPECT_FALSE(bi40->is_continue_entire_loop);
 
-  // Merge block points to the header
-  const auto* bi99 = fe.GetBlockInfo(99);
-  ASSERT_NE(bi99, nullptr);
-  EXPECT_EQ(bi99->merge_for_header, 0u);
-  EXPECT_EQ(bi99->continue_for_header, 0u);
-  EXPECT_EQ(bi99->header_for_merge, 20u);
-  EXPECT_EQ(bi99->header_for_continue, 0u);
-  EXPECT_FALSE(bi99->is_continue_entire_loop);
+    // Merge block points to the header
+    const auto* bi99 = fe.GetBlockInfo(99);
+    ASSERT_NE(bi99, nullptr);
+    EXPECT_EQ(bi99->merge_for_header, 0u);
+    EXPECT_EQ(bi99->continue_for_header, 0u);
+    EXPECT_EQ(bi99->header_for_merge, 20u);
+    EXPECT_EQ(bi99->header_for_continue, 0u);
+    EXPECT_FALSE(bi99->is_continue_entire_loop);
 }
 
 TEST_F(SpvParserCFGTest, RegisterMerges_SelectionMerge_BadTerminator) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -714,16 +711,16 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  EXPECT_FALSE(fe.RegisterMerges());
-  EXPECT_THAT(p->error(), Eq("Selection header 10 does not end in an "
-                             "OpBranchConditional or OpSwitch instruction"));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    EXPECT_FALSE(fe.RegisterMerges());
+    EXPECT_THAT(p->error(), Eq("Selection header 10 does not end in an "
+                               "OpBranchConditional or OpSwitch instruction"));
 }
 
 TEST_F(SpvParserCFGTest, RegisterMerges_LoopMerge_BadTerminator) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -744,16 +741,16 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  EXPECT_FALSE(fe.RegisterMerges());
-  EXPECT_THAT(p->error(), Eq("Loop header 20 does not end in an OpBranch or "
-                             "OpBranchConditional instruction"));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    EXPECT_FALSE(fe.RegisterMerges());
+    EXPECT_THAT(p->error(), Eq("Loop header 20 does not end in an OpBranch or "
+                               "OpBranchConditional instruction"));
 }
 
 TEST_F(SpvParserCFGTest, RegisterMerges_BadMergeBlock) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -768,16 +765,15 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  EXPECT_FALSE(fe.RegisterMerges());
-  EXPECT_THAT(p->error(),
-              Eq("Structured header block 10 declares invalid merge block 2"));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    EXPECT_FALSE(fe.RegisterMerges());
+    EXPECT_THAT(p->error(), Eq("Structured header block 10 declares invalid merge block 2"));
 }
 
 TEST_F(SpvParserCFGTest, RegisterMerges_HeaderIsItsOwnMerge) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -792,16 +788,15 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  EXPECT_FALSE(fe.RegisterMerges());
-  EXPECT_THAT(p->error(),
-              Eq("Structured header block 10 cannot be its own merge block"));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    EXPECT_FALSE(fe.RegisterMerges());
+    EXPECT_THAT(p->error(), Eq("Structured header block 10 cannot be its own merge block"));
 }
 
 TEST_F(SpvParserCFGTest, RegisterMerges_MergeReused) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -826,17 +821,16 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  EXPECT_FALSE(fe.RegisterMerges());
-  EXPECT_THAT(
-      p->error(),
-      Eq("Block 49 declared as merge block for more than one header: 10, 50"));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    EXPECT_FALSE(fe.RegisterMerges());
+    EXPECT_THAT(p->error(),
+                Eq("Block 49 declared as merge block for more than one header: 10, 50"));
 }
 
 TEST_F(SpvParserCFGTest, RegisterMerges_EntryBlockIsLoopHeader) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -851,16 +845,15 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  EXPECT_FALSE(fe.RegisterMerges());
-  EXPECT_THAT(p->error(),
-              Eq("Function entry block 10 cannot be a loop header"));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    EXPECT_FALSE(fe.RegisterMerges());
+    EXPECT_THAT(p->error(), Eq("Function entry block 10 cannot be a loop header"));
 }
 
 TEST_F(SpvParserCFGTest, RegisterMerges_BadContinueTarget) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -875,16 +868,15 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  EXPECT_FALSE(fe.RegisterMerges());
-  EXPECT_THAT(p->error(),
-              Eq("Structured header 20 declares invalid continue target 999"));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    EXPECT_FALSE(fe.RegisterMerges());
+    EXPECT_THAT(p->error(), Eq("Structured header 20 declares invalid continue target 999"));
 }
 
 TEST_F(SpvParserCFGTest, RegisterMerges_MergeSameAsContinue) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -903,17 +895,16 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  EXPECT_FALSE(fe.RegisterMerges());
-  EXPECT_THAT(p->error(),
-              Eq("Invalid structured header block 20: declares block 50 as "
-                 "both its merge block and continue target"));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    EXPECT_FALSE(fe.RegisterMerges());
+    EXPECT_THAT(p->error(), Eq("Invalid structured header block 20: declares block 50 as "
+                               "both its merge block and continue target"));
 }
 
 TEST_F(SpvParserCFGTest, RegisterMerges_ContinueReused) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -947,16 +938,16 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  EXPECT_FALSE(fe.RegisterMerges());
-  EXPECT_THAT(p->error(), Eq("Block 40 declared as continue target for more "
-                             "than one header: 20, 50"));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    EXPECT_FALSE(fe.RegisterMerges());
+    EXPECT_THAT(p->error(), Eq("Block 40 declared as continue target for more "
+                               "than one header: 20, 50"));
 }
 
 TEST_F(SpvParserCFGTest, RegisterMerges_SingleBlockLoop_NotItsOwnContinue) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -974,17 +965,15 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  EXPECT_FALSE(fe.RegisterMerges());
-  EXPECT_THAT(
-      p->error(),
-      Eq("Block 20 branches to itself but is not its own continue target"));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    EXPECT_FALSE(fe.RegisterMerges());
+    EXPECT_THAT(p->error(), Eq("Block 20 branches to itself but is not its own continue target"));
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_OneBlock) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %42 = OpLabel
@@ -992,20 +981,20 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(42));
+    EXPECT_THAT(fe.block_order(), ElementsAre(42));
 
-  const auto* bi = fe.GetBlockInfo(42);
-  ASSERT_NE(bi, nullptr);
-  EXPECT_EQ(bi->pos, 0u);
+    const auto* bi = fe.GetBlockInfo(42);
+    ASSERT_NE(bi, nullptr);
+    EXPECT_EQ(bi->pos, 0u);
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_IgnoreStaticalyUnreachable) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -1019,16 +1008,16 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 20));
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20));
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_KillIsDeadEnd) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -1042,16 +1031,16 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 20));
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20));
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_UnreachableIsDeadEnd) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -1065,16 +1054,16 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 20));
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20));
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_ReorderSequence) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -1092,29 +1081,29 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 99));
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 99));
 
-  const auto* bi10 = fe.GetBlockInfo(10);
-  ASSERT_NE(bi10, nullptr);
-  EXPECT_EQ(bi10->pos, 0u);
-  const auto* bi20 = fe.GetBlockInfo(20);
-  ASSERT_NE(bi20, nullptr);
-  EXPECT_EQ(bi20->pos, 1u);
-  const auto* bi30 = fe.GetBlockInfo(30);
-  ASSERT_NE(bi30, nullptr);
-  EXPECT_EQ(bi30->pos, 2u);
-  const auto* bi99 = fe.GetBlockInfo(99);
-  ASSERT_NE(bi99, nullptr);
-  EXPECT_EQ(bi99->pos, 3u);
+    const auto* bi10 = fe.GetBlockInfo(10);
+    ASSERT_NE(bi10, nullptr);
+    EXPECT_EQ(bi10->pos, 0u);
+    const auto* bi20 = fe.GetBlockInfo(20);
+    ASSERT_NE(bi20, nullptr);
+    EXPECT_EQ(bi20->pos, 1u);
+    const auto* bi30 = fe.GetBlockInfo(30);
+    ASSERT_NE(bi30, nullptr);
+    EXPECT_EQ(bi30->pos, 2u);
+    const auto* bi99 = fe.GetBlockInfo(99);
+    ASSERT_NE(bi99, nullptr);
+    EXPECT_EQ(bi99->pos, 3u);
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_DupConditionalBranch) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -1129,16 +1118,16 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 99));
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 99));
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_RespectConditionalBranchOrder) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -1156,16 +1145,16 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 99));
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 99));
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_TrueOnlyBranch) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -1180,16 +1169,16 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 99));
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 99));
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_FalseOnlyBranch) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -1204,16 +1193,16 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 99));
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 99));
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_SwitchOrderNaturallyReversed) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -1231,17 +1220,16 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 30, 20, 99));
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 30, 20, 99));
 }
 
-TEST_F(SpvParserCFGTest,
-       ComputeBlockOrder_SwitchWithDefaultOrderNaturallyReversed) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, ComputeBlockOrder_SwitchWithDefaultOrderNaturallyReversed) {
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -1262,16 +1250,16 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 30, 20, 80, 99));
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 30, 20, 80, 99));
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Switch_DefaultSameAsACase) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -1292,16 +1280,16 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 40, 20, 30, 99));
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 40, 20, 30, 99));
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_RespectSwitchCaseFallthrough) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -1327,19 +1315,17 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 30, 50, 20, 40, 99))
-      << assembly;
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 30, 50, 20, 40, 99)) << assembly;
 }
 
-TEST_F(SpvParserCFGTest,
-       ComputeBlockOrder_RespectSwitchCaseFallthrough_FromDefault) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, ComputeBlockOrder_RespectSwitchCaseFallthrough_FromDefault) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -1363,19 +1349,17 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 80, 30, 40, 99))
-      << assembly;
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 80, 30, 40, 99)) << assembly;
 }
 
-TEST_F(SpvParserCFGTest,
-       ComputeBlockOrder_RespectSwitchCaseFallthrough_FromCaseToDefaultToCase) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, ComputeBlockOrder_RespectSwitchCaseFallthrough_FromCaseToDefaultToCase) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -1396,18 +1380,17 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 80, 30, 99)) << assembly;
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 80, 30, 99)) << assembly;
 }
 
-TEST_F(SpvParserCFGTest,
-       ComputeBlockOrder_SwitchCasesFallthrough_OppositeDirections) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, ComputeBlockOrder_SwitchCasesFallthrough_OppositeDirections) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -1433,22 +1416,20 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 50, 40, 20, 30, 99))
-      << assembly;
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 50, 40, 20, 30, 99)) << assembly;
 
-  // We're deliberately testing a case that SPIR-V doesn't allow.
-  p->DeliberatelyInvalidSpirv();
+    // We're deliberately testing a case that SPIR-V doesn't allow.
+    p->DeliberatelyInvalidSpirv();
 }
 
-TEST_F(SpvParserCFGTest,
-       ComputeBlockOrder_RespectSwitchCaseFallthrough_Interleaved) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, ComputeBlockOrder_RespectSwitchCaseFallthrough_Interleaved) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -1480,18 +1461,17 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 30, 50, 70, 20, 40, 60, 99))
-      << assembly;
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 30, 50, 70, 20, 40, 60, 99)) << assembly;
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Nest_If_Contains_If) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -1529,19 +1509,17 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(),
-              ElementsAre(10, 20, 30, 40, 49, 50, 60, 70, 79, 99))
-      << assembly;
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 40, 49, 50, 60, 70, 79, 99)) << assembly;
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Nest_If_In_SwitchCase) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -1579,19 +1557,17 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(),
-              ElementsAre(10, 20, 30, 40, 49, 50, 60, 70, 79, 99))
-      << assembly;
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 40, 49, 50, 60, 70, 79, 99)) << assembly;
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Nest_IfFallthrough_In_SwitchCase) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -1629,19 +1605,17 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(),
-              ElementsAre(10, 20, 30, 40, 49, 50, 60, 70, 79, 99))
-      << assembly;
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 40, 49, 50, 60, 70, 79, 99)) << assembly;
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Nest_IfBreak_In_SwitchCase) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -1673,18 +1647,17 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 40, 49, 50, 60, 79, 99))
-      << assembly;
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 40, 49, 50, 60, 79, 99)) << assembly;
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_SingleBlock_Simple) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      ; The entry block can't be the target of a branch
@@ -1700,17 +1673,17 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 99)) << assembly;
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 99)) << assembly;
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_SingleBlock_Infinite) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      ; The entry block can't be the target of a branch
@@ -1726,17 +1699,17 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 99)) << assembly;
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 99)) << assembly;
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_SingleBlock_DupInfinite) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      ; The entry block can't be the target of a branch
@@ -1752,17 +1725,17 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 99)) << assembly;
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 99)) << assembly;
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_HeaderHasBreakIf) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -1783,17 +1756,17 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 50, 99)) << assembly;
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 50, 99)) << assembly;
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_HeaderHasBreakUnless) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -1814,17 +1787,17 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 50, 99)) << assembly;
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 50, 99)) << assembly;
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_BodyHasBreak) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -1845,17 +1818,17 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 50, 99)) << assembly;
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 50, 99)) << assembly;
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_BodyHasBreakIf) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -1879,18 +1852,17 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 40, 50, 99))
-      << assembly;
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 40, 50, 99)) << assembly;
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_BodyHasBreakUnless) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -1914,18 +1886,17 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 40, 50, 99))
-      << assembly;
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 40, 50, 99)) << assembly;
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Body_If) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -1956,18 +1927,17 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 40, 45, 49, 50, 99))
-      << assembly;
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 40, 45, 49, 50, 99)) << assembly;
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Body_If_Break) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -1995,18 +1965,17 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 40, 49, 50, 99))
-      << assembly;
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 40, 49, 50, 99)) << assembly;
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_BodyHasContinueIf) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -2030,18 +1999,17 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 40, 50, 99))
-      << assembly;
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 40, 50, 99)) << assembly;
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_BodyHasContinueUnless) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -2065,18 +2033,17 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 40, 50, 99))
-      << assembly;
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 40, 50, 99)) << assembly;
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Body_If_Continue) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -2104,18 +2071,17 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 40, 49, 50, 99))
-      << assembly;
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 40, 49, 50, 99)) << assembly;
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Body_Switch) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -2146,18 +2112,17 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 45, 40, 49, 50, 99))
-      << assembly;
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 45, 40, 49, 50, 99)) << assembly;
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Body_Switch_CaseBreaks) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -2190,23 +2155,22 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 45, 40, 49, 50, 99))
-      << assembly;
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 45, 40, 49, 50, 99)) << assembly;
 
-  // Fails SPIR-V validation:
-  // Branch from block 40 to block 99 is an invalid exit from construct starting
-  // at block 30; branch bypasses merge block 49
-  p->DeliberatelyInvalidSpirv();
+    // Fails SPIR-V validation:
+    // Branch from block 40 to block 99 is an invalid exit from construct starting
+    // at block 30; branch bypasses merge block 49
+    p->DeliberatelyInvalidSpirv();
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Body_Switch_CaseContinues) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -2237,21 +2201,19 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 45, 40, 49, 50, 99))
-      << assembly;
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 45, 40, 49, 50, 99)) << assembly;
 }
 
 // TODO(crbug.com/tint/1406): Re-enable with the typo fix (preceeded->preceded)
 // once that typo fix is rolled in Tint's SPIRV-Tools.
-TEST_F(SpvParserCFGTest,
-       DISABLED_ComputeBlockOrder_Loop_BodyHasSwitchContinueBreak) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, DISABLED_ComputeBlockOrder_Loop_BodyHasSwitchContinueBreak) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -2276,15 +2238,14 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_FALSE(p->Parse());
-  EXPECT_FALSE(p->success());
-  EXPECT_THAT(p->error(),
-              HasSubstr("OpSwitch must be preceeded by an OpSelectionMerge"));
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_FALSE(p->Parse());
+    EXPECT_FALSE(p->success());
+    EXPECT_THAT(p->error(), HasSubstr("OpSwitch must be preceeded by an OpSelectionMerge"));
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Continue_Sequence) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -2308,17 +2269,17 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 50, 60, 99));
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 50, 60, 99));
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Continue_ContainsIf) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -2349,17 +2310,17 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 50, 60, 70, 89, 99));
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 50, 60, 70, 89, 99));
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Continue_HasBreakIf) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -2380,17 +2341,17 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 50, 99));
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 50, 99));
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Continue_HasBreakUnless) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -2411,19 +2372,19 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 50, 99));
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 50, 99));
 }
 
 // TODO(crbug.com/tint/1406): Re-enable with the typo fix (preceeded->preceded)
 // once that typo fix is rolled in Tint's SPIRV-Tools.
 TEST_F(SpvParserCFGTest, DISABLED_ComputeBlockOrder_Loop_Continue_SwitchBreak) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -2446,15 +2407,14 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_FALSE(p->Parse());
-  EXPECT_FALSE(p->success());
-  EXPECT_THAT(p->error(),
-              HasSubstr("OpSwitch must be preceeded by an OpSelectionMerge"));
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_FALSE(p->Parse());
+    EXPECT_FALSE(p->success());
+    EXPECT_THAT(p->error(), HasSubstr("OpSwitch must be preceeded by an OpSelectionMerge"));
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Loop) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -2488,18 +2448,17 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(),
-              ElementsAre(10, 20, 30, 35, 37, 40, 49, 50, 99));
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 35, 37, 40, 49, 50, 99));
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Loop_InnerBreak) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -2533,18 +2492,17 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(),
-              ElementsAre(10, 20, 30, 35, 37, 40, 49, 50, 99));
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 35, 37, 40, 49, 50, 99));
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Loop_InnerContinue) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -2578,18 +2536,17 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(),
-              ElementsAre(10, 20, 30, 35, 37, 40, 49, 50, 99));
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 35, 37, 40, 49, 50, 99));
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Loop_InnerContinueBreaks) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -2623,18 +2580,17 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(),
-              ElementsAre(10, 20, 30, 35, 37, 40, 49, 50, 99));
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 35, 37, 40, 49, 50, 99));
 }
 
 TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Loop_InnerContinueContinues) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -2668,24 +2624,22 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(),
-              ElementsAre(10, 20, 30, 35, 37, 40, 49, 50, 99));
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 35, 37, 40, 49, 50, 99));
 
-  p->DeliberatelyInvalidSpirv();
-  // SPIR-V validation fails:
-  //    block <ID> 40[%40] exits the continue headed by <ID> 40[%40], but not
-  //    via a structured exit"
+    p->DeliberatelyInvalidSpirv();
+    // SPIR-V validation fails:
+    //    block <ID> 40[%40] exits the continue headed by <ID> 40[%40], but not
+    //    via a structured exit"
 }
 
-TEST_F(SpvParserCFGTest,
-       ComputeBlockOrder_Loop_Loop_SwitchBackedgeBreakContinue) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, ComputeBlockOrder_Loop_Loop_SwitchBackedgeBreakContinue) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -2724,23 +2678,22 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
 
-  EXPECT_THAT(fe.block_order(),
-              ElementsAre(10, 20, 30, 35, 37, 40, 49, 50, 99));
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 35, 37, 40, 49, 50, 99));
 
-  p->DeliberatelyInvalidSpirv();
-  // SPIR-V validation fails:
-  //    block <ID> 40[%40] exits the continue headed by <ID> 40[%40], but not
-  //    via a structured exit"
+    p->DeliberatelyInvalidSpirv();
+    // SPIR-V validation fails:
+    //    block <ID> 40[%40] exits the continue headed by <ID> 40[%40], but not
+    //    via a structured exit"
 }
 
 TEST_F(SpvParserCFGTest, VerifyHeaderContinueMergeOrder_Selection_Good) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -2758,17 +2711,17 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  fe.RegisterMerges();
-  EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    fe.RegisterMerges();
+    EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
 }
 
 TEST_F(SpvParserCFGTest, VerifyHeaderContinueMergeOrder_SingleBlockLoop_Good) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -2783,17 +2736,17 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  fe.RegisterMerges();
-  EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder()) << p->error();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    fe.RegisterMerges();
+    EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder()) << p->error();
 }
 
 TEST_F(SpvParserCFGTest, VerifyHeaderContinueMergeOrder_MultiBlockLoop_Good) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -2811,18 +2764,17 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  fe.RegisterMerges();
-  EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    fe.RegisterMerges();
+    EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
 }
 
-TEST_F(SpvParserCFGTest,
-       VerifyHeaderContinueMergeOrder_HeaderDoesNotStrictlyDominateMerge) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, VerifyHeaderContinueMergeOrder_HeaderDoesNotStrictlyDominateMerge) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -2843,24 +2795,22 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  fe.RegisterMerges();
-  EXPECT_FALSE(fe.VerifyHeaderContinueMergeOrder());
-  EXPECT_THAT(p->error(),
-              Eq("Header 50 does not strictly dominate its merge block 20"))
-      << *fe.GetBlockInfo(50) << std::endl
-      << *fe.GetBlockInfo(20) << std::endl
-      << Dump(fe.block_order());
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    fe.RegisterMerges();
+    EXPECT_FALSE(fe.VerifyHeaderContinueMergeOrder());
+    EXPECT_THAT(p->error(), Eq("Header 50 does not strictly dominate its merge block 20"))
+        << *fe.GetBlockInfo(50) << std::endl
+        << *fe.GetBlockInfo(20) << std::endl
+        << Dump(fe.block_order());
 }
 
-TEST_F(
-    SpvParserCFGTest,
-    VerifyHeaderContinueMergeOrder_HeaderDoesNotStrictlyDominateContinueTarget) {  // NOLINT
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest,
+       VerifyHeaderContinueMergeOrder_HeaderDoesNotStrictlyDominateContinueTarget) {  // NOLINT
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -2881,23 +2831,21 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  fe.RegisterMerges();
-  EXPECT_FALSE(fe.VerifyHeaderContinueMergeOrder());
-  EXPECT_THAT(p->error(),
-              Eq("Loop header 50 does not dominate its continue target 20"))
-      << *fe.GetBlockInfo(50) << std::endl
-      << *fe.GetBlockInfo(20) << std::endl
-      << Dump(fe.block_order());
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    fe.RegisterMerges();
+    EXPECT_FALSE(fe.VerifyHeaderContinueMergeOrder());
+    EXPECT_THAT(p->error(), Eq("Loop header 50 does not dominate its continue target 20"))
+        << *fe.GetBlockInfo(50) << std::endl
+        << *fe.GetBlockInfo(20) << std::endl
+        << Dump(fe.block_order());
 }
 
-TEST_F(SpvParserCFGTest,
-       VerifyHeaderContinueMergeOrder_MergeInsideContinueTarget) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, VerifyHeaderContinueMergeOrder_MergeInsideContinueTarget) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -2918,22 +2866,20 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  fe.RegisterMerges();
-  EXPECT_FALSE(fe.VerifyHeaderContinueMergeOrder());
-  EXPECT_THAT(p->error(),
-              Eq("Merge block 60 for loop headed at block 50 appears at or "
-                 "before the loop's continue construct headed by block 70"))
-      << Dump(fe.block_order());
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    fe.RegisterMerges();
+    EXPECT_FALSE(fe.VerifyHeaderContinueMergeOrder());
+    EXPECT_THAT(p->error(), Eq("Merge block 60 for loop headed at block 50 appears at or "
+                               "before the loop's continue construct headed by block 70"))
+        << Dump(fe.block_order());
 }
 
-TEST_F(SpvParserCFGTest,
-       LabelControlFlowConstructs_OuterConstructIsFunction_SingleBlock) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_OuterConstructIsFunction_SingleBlock) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -2941,23 +2887,22 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  fe.RegisterMerges();
-  EXPECT_TRUE(fe.LabelControlFlowConstructs());
-  EXPECT_EQ(fe.constructs().size(), 1u);
-  auto& c = fe.constructs().front();
-  EXPECT_THAT(ToString(c), Eq("Construct{ Function [0,1) begin_id:10 end_id:0 "
-                              "depth:0 parent:null }"));
-  EXPECT_EQ(fe.GetBlockInfo(10)->construct, c.get());
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    fe.RegisterMerges();
+    EXPECT_TRUE(fe.LabelControlFlowConstructs());
+    EXPECT_EQ(fe.constructs().size(), 1u);
+    auto& c = fe.constructs().front();
+    EXPECT_THAT(ToString(c), Eq("Construct{ Function [0,1) begin_id:10 end_id:0 "
+                                "depth:0 parent:null }"));
+    EXPECT_EQ(fe.GetBlockInfo(10)->construct, c.get());
 }
 
-TEST_F(SpvParserCFGTest,
-       LabelControlFlowConstructs_OuterConstructIsFunction_MultiBlock) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_OuterConstructIsFunction_MultiBlock) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -2968,24 +2913,23 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  fe.RegisterMerges();
-  EXPECT_TRUE(fe.LabelControlFlowConstructs());
-  EXPECT_EQ(fe.constructs().size(), 1u);
-  auto& c = fe.constructs().front();
-  EXPECT_THAT(ToString(c), Eq("Construct{ Function [0,2) begin_id:10 end_id:0 "
-                              "depth:0 parent:null }"));
-  EXPECT_EQ(fe.GetBlockInfo(10)->construct, c.get());
-  EXPECT_EQ(fe.GetBlockInfo(5)->construct, c.get());
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    fe.RegisterMerges();
+    EXPECT_TRUE(fe.LabelControlFlowConstructs());
+    EXPECT_EQ(fe.constructs().size(), 1u);
+    auto& c = fe.constructs().front();
+    EXPECT_THAT(ToString(c), Eq("Construct{ Function [0,2) begin_id:10 end_id:0 "
+                                "depth:0 parent:null }"));
+    EXPECT_EQ(fe.GetBlockInfo(10)->construct, c.get());
+    EXPECT_EQ(fe.GetBlockInfo(5)->construct, c.get());
 }
 
-TEST_F(SpvParserCFGTest,
-       LabelControlFlowConstructs_FunctionIsOnlyIfSelectionAndItsMerge) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_FunctionIsOnlyIfSelectionAndItsMerge) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -3003,30 +2947,29 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  fe.RegisterMerges();
-  EXPECT_TRUE(fe.LabelControlFlowConstructs());
-  const auto& constructs = fe.constructs();
-  EXPECT_EQ(constructs.size(), 2u);
-  EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    fe.RegisterMerges();
+    EXPECT_TRUE(fe.LabelControlFlowConstructs());
+    const auto& constructs = fe.constructs();
+    EXPECT_EQ(constructs.size(), 2u);
+    EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
   Construct{ Function [0,4) begin_id:10 end_id:0 depth:0 parent:null }
   Construct{ IfSelection [0,3) begin_id:10 end_id:99 depth:1 parent:Function@10 }
 })")) << constructs;
-  // The block records the nearest enclosing construct.
-  EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
-  EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[1].get());
-  EXPECT_EQ(fe.GetBlockInfo(30)->construct, constructs[1].get());
-  EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
+    // The block records the nearest enclosing construct.
+    EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
+    EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[1].get());
+    EXPECT_EQ(fe.GetBlockInfo(30)->construct, constructs[1].get());
+    EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
 }
 
-TEST_F(
-    SpvParserCFGTest,
-    LabelControlFlowConstructs_PaddingBlocksBeforeAndAfterStructuredConstruct) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest,
+       LabelControlFlowConstructs_PaddingBlocksBeforeAndAfterStructuredConstruct) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %5 = OpLabel
@@ -3050,30 +2993,30 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  fe.RegisterMerges();
-  EXPECT_TRUE(fe.LabelControlFlowConstructs());
-  const auto& constructs = fe.constructs();
-  EXPECT_EQ(constructs.size(), 2u);
-  EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    fe.RegisterMerges();
+    EXPECT_TRUE(fe.LabelControlFlowConstructs());
+    const auto& constructs = fe.constructs();
+    EXPECT_EQ(constructs.size(), 2u);
+    EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
   Construct{ Function [0,6) begin_id:5 end_id:0 depth:0 parent:null }
   Construct{ IfSelection [1,4) begin_id:10 end_id:99 depth:1 parent:Function@5 }
 })")) << constructs;
-  // The block records the nearest enclosing construct.
-  EXPECT_EQ(fe.GetBlockInfo(5)->construct, constructs[0].get());
-  EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
-  EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[1].get());
-  EXPECT_EQ(fe.GetBlockInfo(30)->construct, constructs[1].get());
-  EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
-  EXPECT_EQ(fe.GetBlockInfo(200)->construct, constructs[0].get());
+    // The block records the nearest enclosing construct.
+    EXPECT_EQ(fe.GetBlockInfo(5)->construct, constructs[0].get());
+    EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
+    EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[1].get());
+    EXPECT_EQ(fe.GetBlockInfo(30)->construct, constructs[1].get());
+    EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
+    EXPECT_EQ(fe.GetBlockInfo(200)->construct, constructs[0].get());
 }
 
 TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_SwitchSelection) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -3094,29 +3037,29 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  fe.RegisterMerges();
-  EXPECT_TRUE(fe.LabelControlFlowConstructs());
-  const auto& constructs = fe.constructs();
-  EXPECT_EQ(constructs.size(), 2u);
-  EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    fe.RegisterMerges();
+    EXPECT_TRUE(fe.LabelControlFlowConstructs());
+    const auto& constructs = fe.constructs();
+    EXPECT_EQ(constructs.size(), 2u);
+    EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
   Construct{ Function [0,5) begin_id:10 end_id:0 depth:0 parent:null }
   Construct{ SwitchSelection [0,4) begin_id:10 end_id:99 depth:1 parent:Function@10 in-c-l-s:SwitchSelection@10 }
 })")) << constructs;
-  // The block records the nearest enclosing construct.
-  EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
-  EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[1].get());
-  EXPECT_EQ(fe.GetBlockInfo(30)->construct, constructs[1].get());
-  EXPECT_EQ(fe.GetBlockInfo(40)->construct, constructs[1].get());
-  EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
+    // The block records the nearest enclosing construct.
+    EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
+    EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[1].get());
+    EXPECT_EQ(fe.GetBlockInfo(30)->construct, constructs[1].get());
+    EXPECT_EQ(fe.GetBlockInfo(40)->construct, constructs[1].get());
+    EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
 }
 
 TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_SingleBlockLoop) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -3131,31 +3074,30 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  fe.RegisterMerges();
-  EXPECT_TRUE(fe.LabelControlFlowConstructs());
-  const auto& constructs = fe.constructs();
-  EXPECT_EQ(constructs.size(), 2u);
-  // A single-block loop consists *only* of a continue target with one block in
-  // it.
-  EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    fe.RegisterMerges();
+    EXPECT_TRUE(fe.LabelControlFlowConstructs());
+    const auto& constructs = fe.constructs();
+    EXPECT_EQ(constructs.size(), 2u);
+    // A single-block loop consists *only* of a continue target with one block in
+    // it.
+    EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
   Construct{ Function [0,3) begin_id:10 end_id:0 depth:0 parent:null }
   Construct{ Continue [1,2) begin_id:20 end_id:99 depth:1 parent:Function@10 in-c:Continue@20 }
 })")) << constructs;
-  // The block records the nearest enclosing construct.
-  EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[0].get());
-  EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[1].get());
-  EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
+    // The block records the nearest enclosing construct.
+    EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[0].get());
+    EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[1].get());
+    EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
 }
 
-TEST_F(SpvParserCFGTest,
-       LabelControlFlowConstructs_MultiBlockLoop_HeaderIsNotContinue) {
-  // In this case, we have a continue construct and a non-empty loop construct.
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_MultiBlockLoop_HeaderIsNotContinue) {
+    // In this case, we have a continue construct and a non-empty loop construct.
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -3179,32 +3121,31 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  fe.RegisterMerges();
-  EXPECT_TRUE(fe.LabelControlFlowConstructs());
-  const auto& constructs = fe.constructs();
-  EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    fe.RegisterMerges();
+    EXPECT_TRUE(fe.LabelControlFlowConstructs());
+    const auto& constructs = fe.constructs();
+    EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
   Construct{ Function [0,6) begin_id:10 end_id:0 depth:0 parent:null }
   Construct{ Continue [3,5) begin_id:40 end_id:99 depth:1 parent:Function@10 in-c:Continue@40 }
   Construct{ Loop [1,3) begin_id:20 end_id:40 depth:1 parent:Function@10 scope:[1,5) in-l:Loop@20 }
 })")) << constructs;
-  // The block records the nearest enclosing construct.
-  EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[0].get());
-  EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[2].get());
-  EXPECT_EQ(fe.GetBlockInfo(30)->construct, constructs[2].get());
-  EXPECT_EQ(fe.GetBlockInfo(40)->construct, constructs[1].get());
-  EXPECT_EQ(fe.GetBlockInfo(50)->construct, constructs[1].get());
-  EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
+    // The block records the nearest enclosing construct.
+    EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[0].get());
+    EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[2].get());
+    EXPECT_EQ(fe.GetBlockInfo(30)->construct, constructs[2].get());
+    EXPECT_EQ(fe.GetBlockInfo(40)->construct, constructs[1].get());
+    EXPECT_EQ(fe.GetBlockInfo(50)->construct, constructs[1].get());
+    EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
 }
 
-TEST_F(SpvParserCFGTest,
-       LabelControlFlowConstructs_MultiBlockLoop_HeaderIsContinue) {
-  // In this case, we have only a continue construct and no loop construct.
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_MultiBlockLoop_HeaderIsContinue) {
+    // In this case, we have only a continue construct and no loop construct.
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -3228,30 +3169,29 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  fe.RegisterMerges();
-  EXPECT_TRUE(fe.LabelControlFlowConstructs());
-  const auto& constructs = fe.constructs();
-  EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    fe.RegisterMerges();
+    EXPECT_TRUE(fe.LabelControlFlowConstructs());
+    const auto& constructs = fe.constructs();
+    EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
   Construct{ Function [0,6) begin_id:10 end_id:0 depth:0 parent:null }
   Construct{ Continue [1,5) begin_id:20 end_id:99 depth:1 parent:Function@10 in-c:Continue@20 }
 })")) << constructs;
-  // The block records the nearest enclosing construct.
-  EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[0].get());
-  EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[1].get());
-  EXPECT_EQ(fe.GetBlockInfo(30)->construct, constructs[1].get());
-  EXPECT_EQ(fe.GetBlockInfo(40)->construct, constructs[1].get());
-  EXPECT_EQ(fe.GetBlockInfo(50)->construct, constructs[1].get());
-  EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
+    // The block records the nearest enclosing construct.
+    EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[0].get());
+    EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[1].get());
+    EXPECT_EQ(fe.GetBlockInfo(30)->construct, constructs[1].get());
+    EXPECT_EQ(fe.GetBlockInfo(40)->construct, constructs[1].get());
+    EXPECT_EQ(fe.GetBlockInfo(50)->construct, constructs[1].get());
+    EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
 }
 
-TEST_F(SpvParserCFGTest,
-       LabelControlFlowConstructs_MergeBlockIsAlsoSingleBlockLoop) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_MergeBlockIsAlsoSingleBlockLoop) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -3272,32 +3212,31 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  fe.RegisterMerges();
-  EXPECT_TRUE(fe.LabelControlFlowConstructs());
-  const auto& constructs = fe.constructs();
-  EXPECT_EQ(constructs.size(), 3u);
-  // A single-block loop consists *only* of a continue target with one block in
-  // it.
-  EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    fe.RegisterMerges();
+    EXPECT_TRUE(fe.LabelControlFlowConstructs());
+    const auto& constructs = fe.constructs();
+    EXPECT_EQ(constructs.size(), 3u);
+    // A single-block loop consists *only* of a continue target with one block in
+    // it.
+    EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
   Construct{ Function [0,4) begin_id:10 end_id:0 depth:0 parent:null }
   Construct{ IfSelection [0,2) begin_id:10 end_id:50 depth:1 parent:Function@10 }
   Construct{ Continue [2,3) begin_id:50 end_id:99 depth:1 parent:Function@10 in-c:Continue@50 }
 })")) << constructs;
-  // The block records the nearest enclosing construct.
-  EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
-  EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[1].get());
-  EXPECT_EQ(fe.GetBlockInfo(50)->construct, constructs[2].get());
-  EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
+    // The block records the nearest enclosing construct.
+    EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
+    EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[1].get());
+    EXPECT_EQ(fe.GetBlockInfo(50)->construct, constructs[2].get());
+    EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
 }
 
-TEST_F(SpvParserCFGTest,
-       LabelControlFlowConstructs_MergeBlockIsAlsoMultiBlockLoopHeader) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_MergeBlockIsAlsoMultiBlockLoopHeader) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -3321,31 +3260,31 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  fe.RegisterMerges();
-  EXPECT_TRUE(fe.LabelControlFlowConstructs());
-  const auto& constructs = fe.constructs();
-  EXPECT_EQ(constructs.size(), 4u);
-  EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    fe.RegisterMerges();
+    EXPECT_TRUE(fe.LabelControlFlowConstructs());
+    const auto& constructs = fe.constructs();
+    EXPECT_EQ(constructs.size(), 4u);
+    EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
   Construct{ Function [0,5) begin_id:10 end_id:0 depth:0 parent:null }
   Construct{ IfSelection [0,2) begin_id:10 end_id:50 depth:1 parent:Function@10 }
   Construct{ Continue [3,4) begin_id:60 end_id:99 depth:1 parent:Function@10 in-c:Continue@60 }
   Construct{ Loop [2,3) begin_id:50 end_id:60 depth:1 parent:Function@10 scope:[2,4) in-l:Loop@50 }
 })")) << constructs;
-  // The block records the nearest enclosing construct.
-  EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
-  EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[1].get());
-  EXPECT_EQ(fe.GetBlockInfo(50)->construct, constructs[3].get());
-  EXPECT_EQ(fe.GetBlockInfo(60)->construct, constructs[2].get());
-  EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
+    // The block records the nearest enclosing construct.
+    EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
+    EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[1].get());
+    EXPECT_EQ(fe.GetBlockInfo(50)->construct, constructs[3].get());
+    EXPECT_EQ(fe.GetBlockInfo(60)->construct, constructs[2].get());
+    EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
 }
 
 TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_Nest_If_If) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -3380,35 +3319,35 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  fe.RegisterMerges();
-  EXPECT_TRUE(fe.LabelControlFlowConstructs());
-  const auto& constructs = fe.constructs();
-  EXPECT_EQ(constructs.size(), 4u);
-  EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    fe.RegisterMerges();
+    EXPECT_TRUE(fe.LabelControlFlowConstructs());
+    const auto& constructs = fe.constructs();
+    EXPECT_EQ(constructs.size(), 4u);
+    EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
   Construct{ Function [0,9) begin_id:10 end_id:0 depth:0 parent:null }
   Construct{ IfSelection [0,8) begin_id:10 end_id:99 depth:1 parent:Function@10 }
   Construct{ IfSelection [1,3) begin_id:20 end_id:40 depth:2 parent:IfSelection@10 }
   Construct{ IfSelection [5,7) begin_id:50 end_id:89 depth:2 parent:IfSelection@10 }
 })")) << constructs;
-  // The block records the nearest enclosing construct.
-  EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
-  EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[2].get());
-  EXPECT_EQ(fe.GetBlockInfo(30)->construct, constructs[2].get());
-  EXPECT_EQ(fe.GetBlockInfo(40)->construct, constructs[1].get());
-  EXPECT_EQ(fe.GetBlockInfo(49)->construct, constructs[1].get());
-  EXPECT_EQ(fe.GetBlockInfo(50)->construct, constructs[3].get());
-  EXPECT_EQ(fe.GetBlockInfo(60)->construct, constructs[3].get());
-  EXPECT_EQ(fe.GetBlockInfo(89)->construct, constructs[1].get());
-  EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
+    // The block records the nearest enclosing construct.
+    EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
+    EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[2].get());
+    EXPECT_EQ(fe.GetBlockInfo(30)->construct, constructs[2].get());
+    EXPECT_EQ(fe.GetBlockInfo(40)->construct, constructs[1].get());
+    EXPECT_EQ(fe.GetBlockInfo(49)->construct, constructs[1].get());
+    EXPECT_EQ(fe.GetBlockInfo(50)->construct, constructs[3].get());
+    EXPECT_EQ(fe.GetBlockInfo(60)->construct, constructs[3].get());
+    EXPECT_EQ(fe.GetBlockInfo(89)->construct, constructs[1].get());
+    EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
 }
 
 TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_Nest_Switch_If) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -3440,35 +3379,35 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  fe.RegisterMerges();
-  EXPECT_TRUE(fe.LabelControlFlowConstructs());
-  const auto& constructs = fe.constructs();
-  EXPECT_EQ(constructs.size(), 4u);
-  // The ordering among siblings depends on the computed block order.
-  EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    fe.RegisterMerges();
+    EXPECT_TRUE(fe.LabelControlFlowConstructs());
+    const auto& constructs = fe.constructs();
+    EXPECT_EQ(constructs.size(), 4u);
+    // The ordering among siblings depends on the computed block order.
+    EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
   Construct{ Function [0,8) begin_id:10 end_id:0 depth:0 parent:null }
   Construct{ SwitchSelection [0,7) begin_id:10 end_id:99 depth:1 parent:Function@10 in-c-l-s:SwitchSelection@10 }
   Construct{ IfSelection [1,3) begin_id:50 end_id:89 depth:2 parent:SwitchSelection@10 in-c-l-s:SwitchSelection@10 }
   Construct{ IfSelection [4,6) begin_id:20 end_id:49 depth:2 parent:SwitchSelection@10 in-c-l-s:SwitchSelection@10 }
 })")) << constructs;
-  // The block records the nearest enclosing construct.
-  EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
-  EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[3].get());
-  EXPECT_EQ(fe.GetBlockInfo(30)->construct, constructs[3].get());
-  EXPECT_EQ(fe.GetBlockInfo(49)->construct, constructs[1].get());
-  EXPECT_EQ(fe.GetBlockInfo(50)->construct, constructs[2].get());
-  EXPECT_EQ(fe.GetBlockInfo(60)->construct, constructs[2].get());
-  EXPECT_EQ(fe.GetBlockInfo(89)->construct, constructs[1].get());
-  EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
+    // The block records the nearest enclosing construct.
+    EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
+    EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[3].get());
+    EXPECT_EQ(fe.GetBlockInfo(30)->construct, constructs[3].get());
+    EXPECT_EQ(fe.GetBlockInfo(49)->construct, constructs[1].get());
+    EXPECT_EQ(fe.GetBlockInfo(50)->construct, constructs[2].get());
+    EXPECT_EQ(fe.GetBlockInfo(60)->construct, constructs[2].get());
+    EXPECT_EQ(fe.GetBlockInfo(89)->construct, constructs[1].get());
+    EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
 }
 
 TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_Nest_If_Switch) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -3490,30 +3429,30 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  fe.RegisterMerges();
-  EXPECT_TRUE(fe.LabelControlFlowConstructs());
-  const auto& constructs = fe.constructs();
-  EXPECT_EQ(constructs.size(), 3u);
-  EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    fe.RegisterMerges();
+    EXPECT_TRUE(fe.LabelControlFlowConstructs());
+    const auto& constructs = fe.constructs();
+    EXPECT_EQ(constructs.size(), 3u);
+    EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
   Construct{ Function [0,5) begin_id:10 end_id:0 depth:0 parent:null }
   Construct{ IfSelection [0,4) begin_id:10 end_id:99 depth:1 parent:Function@10 }
   Construct{ SwitchSelection [1,3) begin_id:20 end_id:89 depth:2 parent:IfSelection@10 in-c-l-s:SwitchSelection@20 }
 })")) << constructs;
-  // The block records the nearest enclosing construct.
-  EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
-  EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[2].get());
-  EXPECT_EQ(fe.GetBlockInfo(30)->construct, constructs[2].get());
-  EXPECT_EQ(fe.GetBlockInfo(89)->construct, constructs[1].get());
-  EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
+    // The block records the nearest enclosing construct.
+    EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
+    EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[2].get());
+    EXPECT_EQ(fe.GetBlockInfo(30)->construct, constructs[2].get());
+    EXPECT_EQ(fe.GetBlockInfo(89)->construct, constructs[1].get());
+    EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
 }
 
 TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_Nest_Loop_Loop) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -3544,34 +3483,34 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  fe.RegisterMerges();
-  EXPECT_TRUE(fe.LabelControlFlowConstructs());
-  const auto& constructs = fe.constructs();
-  EXPECT_EQ(constructs.size(), 4u);
-  EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    fe.RegisterMerges();
+    EXPECT_TRUE(fe.LabelControlFlowConstructs());
+    const auto& constructs = fe.constructs();
+    EXPECT_EQ(constructs.size(), 4u);
+    EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
   Construct{ Function [0,8) begin_id:10 end_id:0 depth:0 parent:null }
   Construct{ Continue [4,6) begin_id:50 end_id:89 depth:1 parent:Function@10 in-c:Continue@50 }
   Construct{ Loop [1,4) begin_id:20 end_id:50 depth:1 parent:Function@10 scope:[1,6) in-l:Loop@20 }
   Construct{ Continue [2,3) begin_id:30 end_id:40 depth:2 parent:Loop@20 in-l:Loop@20 in-c:Continue@30 }
 })")) << constructs;
-  // The block records the nearest enclosing construct.
-  EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[0].get());
-  EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[2].get());
-  EXPECT_EQ(fe.GetBlockInfo(30)->construct, constructs[3].get());
-  EXPECT_EQ(fe.GetBlockInfo(40)->construct, constructs[2].get());
-  EXPECT_EQ(fe.GetBlockInfo(50)->construct, constructs[1].get());
-  EXPECT_EQ(fe.GetBlockInfo(60)->construct, constructs[1].get());
-  EXPECT_EQ(fe.GetBlockInfo(89)->construct, constructs[0].get());
-  EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
+    // The block records the nearest enclosing construct.
+    EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[0].get());
+    EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[2].get());
+    EXPECT_EQ(fe.GetBlockInfo(30)->construct, constructs[3].get());
+    EXPECT_EQ(fe.GetBlockInfo(40)->construct, constructs[2].get());
+    EXPECT_EQ(fe.GetBlockInfo(50)->construct, constructs[1].get());
+    EXPECT_EQ(fe.GetBlockInfo(60)->construct, constructs[1].get());
+    EXPECT_EQ(fe.GetBlockInfo(89)->construct, constructs[0].get());
+    EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
 }
 
 TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_Nest_Loop_If) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -3599,33 +3538,33 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  fe.RegisterMerges();
-  EXPECT_TRUE(fe.LabelControlFlowConstructs());
-  const auto& constructs = fe.constructs();
-  EXPECT_EQ(constructs.size(), 4u);
-  EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    fe.RegisterMerges();
+    EXPECT_TRUE(fe.LabelControlFlowConstructs());
+    const auto& constructs = fe.constructs();
+    EXPECT_EQ(constructs.size(), 4u);
+    EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
   Construct{ Function [0,7) begin_id:10 end_id:0 depth:0 parent:null }
   Construct{ Continue [5,6) begin_id:80 end_id:99 depth:1 parent:Function@10 in-c:Continue@80 }
   Construct{ Loop [1,5) begin_id:20 end_id:80 depth:1 parent:Function@10 scope:[1,6) in-l:Loop@20 }
   Construct{ IfSelection [2,4) begin_id:30 end_id:49 depth:2 parent:Loop@20 in-l:Loop@20 }
 })")) << constructs;
-  // The block records the nearest enclosing construct.
-  EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[0].get());
-  EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[2].get());
-  EXPECT_EQ(fe.GetBlockInfo(30)->construct, constructs[3].get());
-  EXPECT_EQ(fe.GetBlockInfo(40)->construct, constructs[3].get());
-  EXPECT_EQ(fe.GetBlockInfo(49)->construct, constructs[2].get());
-  EXPECT_EQ(fe.GetBlockInfo(80)->construct, constructs[1].get());
-  EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
+    // The block records the nearest enclosing construct.
+    EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[0].get());
+    EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[2].get());
+    EXPECT_EQ(fe.GetBlockInfo(30)->construct, constructs[3].get());
+    EXPECT_EQ(fe.GetBlockInfo(40)->construct, constructs[3].get());
+    EXPECT_EQ(fe.GetBlockInfo(49)->construct, constructs[2].get());
+    EXPECT_EQ(fe.GetBlockInfo(80)->construct, constructs[1].get());
+    EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
 }
 
 TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_Nest_LoopContinue_If) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -3650,32 +3589,32 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  fe.RegisterMerges();
-  EXPECT_TRUE(fe.LabelControlFlowConstructs());
-  const auto& constructs = fe.constructs();
-  EXPECT_EQ(constructs.size(), 4u);
-  EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    fe.RegisterMerges();
+    EXPECT_TRUE(fe.LabelControlFlowConstructs());
+    const auto& constructs = fe.constructs();
+    EXPECT_EQ(constructs.size(), 4u);
+    EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
   Construct{ Function [0,6) begin_id:10 end_id:0 depth:0 parent:null }
   Construct{ Continue [2,5) begin_id:30 end_id:99 depth:1 parent:Function@10 in-c:Continue@30 }
   Construct{ Loop [1,2) begin_id:20 end_id:30 depth:1 parent:Function@10 scope:[1,5) in-l:Loop@20 }
   Construct{ IfSelection [2,4) begin_id:30 end_id:49 depth:2 parent:Continue@30 in-c:Continue@30 }
 })")) << constructs;
-  // The block records the nearest enclosing construct.
-  EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[0].get());
-  EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[2].get());
-  EXPECT_EQ(fe.GetBlockInfo(30)->construct, constructs[3].get());
-  EXPECT_EQ(fe.GetBlockInfo(40)->construct, constructs[3].get());
-  EXPECT_EQ(fe.GetBlockInfo(49)->construct, constructs[1].get());
-  EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
+    // The block records the nearest enclosing construct.
+    EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[0].get());
+    EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[2].get());
+    EXPECT_EQ(fe.GetBlockInfo(30)->construct, constructs[3].get());
+    EXPECT_EQ(fe.GetBlockInfo(40)->construct, constructs[3].get());
+    EXPECT_EQ(fe.GetBlockInfo(49)->construct, constructs[1].get());
+    EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
 }
 
 TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_Nest_If_SingleBlockLoop) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -3694,28 +3633,28 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  fe.RegisterMerges();
-  EXPECT_TRUE(fe.LabelControlFlowConstructs());
-  const auto& constructs = fe.constructs();
-  EXPECT_EQ(constructs.size(), 3u);
-  EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    fe.RegisterMerges();
+    EXPECT_TRUE(fe.LabelControlFlowConstructs());
+    const auto& constructs = fe.constructs();
+    EXPECT_EQ(constructs.size(), 3u);
+    EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
   Construct{ Function [0,4) begin_id:10 end_id:0 depth:0 parent:null }
   Construct{ IfSelection [0,3) begin_id:10 end_id:99 depth:1 parent:Function@10 }
   Construct{ Continue [1,2) begin_id:20 end_id:89 depth:2 parent:IfSelection@10 in-c:Continue@20 }
 })")) << constructs;
-  // The block records the nearest enclosing construct.
-  EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
-  EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[2].get());
-  EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
+    // The block records the nearest enclosing construct.
+    EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
+    EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[2].get());
+    EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
 }
 
 TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_Nest_If_MultiBlockLoop) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -3743,36 +3682,36 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  fe.RegisterMerges();
-  EXPECT_TRUE(fe.LabelControlFlowConstructs());
-  const auto& constructs = fe.constructs();
-  EXPECT_EQ(constructs.size(), 4u);
-  EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    fe.RegisterMerges();
+    EXPECT_TRUE(fe.LabelControlFlowConstructs());
+    const auto& constructs = fe.constructs();
+    EXPECT_EQ(constructs.size(), 4u);
+    EXPECT_THAT(ToString(constructs), Eq(R"(ConstructList{
   Construct{ Function [0,7) begin_id:10 end_id:0 depth:0 parent:null }
   Construct{ IfSelection [0,6) begin_id:10 end_id:99 depth:1 parent:Function@10 }
   Construct{ Continue [3,5) begin_id:40 end_id:89 depth:2 parent:IfSelection@10 in-c:Continue@40 }
   Construct{ Loop [1,3) begin_id:20 end_id:40 depth:2 parent:IfSelection@10 scope:[1,5) in-l:Loop@20 }
 })")) << constructs;
-  // The block records the nearest enclosing construct.
-  EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
-  EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[3].get());
-  EXPECT_EQ(fe.GetBlockInfo(30)->construct, constructs[3].get());
-  EXPECT_EQ(fe.GetBlockInfo(40)->construct, constructs[2].get());
-  EXPECT_EQ(fe.GetBlockInfo(50)->construct, constructs[2].get());
-  EXPECT_EQ(fe.GetBlockInfo(89)->construct, constructs[1].get());
-  EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
+    // The block records the nearest enclosing construct.
+    EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[1].get());
+    EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[3].get());
+    EXPECT_EQ(fe.GetBlockInfo(30)->construct, constructs[3].get());
+    EXPECT_EQ(fe.GetBlockInfo(40)->construct, constructs[2].get());
+    EXPECT_EQ(fe.GetBlockInfo(50)->construct, constructs[2].get());
+    EXPECT_EQ(fe.GetBlockInfo(89)->construct, constructs[1].get());
+    EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
 }
 
 TEST_F(SpvParserCFGTest, LabelControlFlowConstructs_LoopInterallyDiverge) {
-  // In this case, insert a synthetic if-selection with the same blocks
-  // as the loop construct.
-  // crbug.com/tint/524
-  auto assembly = CommonTypes() + R"(
+    // In this case, insert a synthetic if-selection with the same blocks
+    // as the loop construct.
+    // crbug.com/tint/524
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -3796,29 +3735,29 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  ASSERT_TRUE(FlowLabelControlFlowConstructs(&fe)) << p->error();
-  const auto& constructs = fe.constructs();
-  EXPECT_EQ(constructs.size(), 4u);
-  ASSERT_THAT(ToString(constructs), Eq(R"(ConstructList{
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    ASSERT_TRUE(FlowLabelControlFlowConstructs(&fe)) << p->error();
+    const auto& constructs = fe.constructs();
+    EXPECT_EQ(constructs.size(), 4u);
+    ASSERT_THAT(ToString(constructs), Eq(R"(ConstructList{
   Construct{ Function [0,6) begin_id:10 end_id:0 depth:0 parent:null }
   Construct{ Continue [4,5) begin_id:90 end_id:99 depth:1 parent:Function@10 in-c:Continue@90 }
   Construct{ Loop [1,4) begin_id:20 end_id:90 depth:1 parent:Function@10 scope:[1,5) in-l:Loop@20 }
   Construct{ IfSelection [1,4) begin_id:20 end_id:90 depth:2 parent:Loop@20 in-l:Loop@20 }
 })")) << constructs;
-  // The block records the nearest enclosing construct.
-  EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[0].get());
-  EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[3].get());
-  EXPECT_EQ(fe.GetBlockInfo(30)->construct, constructs[3].get());
-  EXPECT_EQ(fe.GetBlockInfo(40)->construct, constructs[3].get());
-  EXPECT_EQ(fe.GetBlockInfo(90)->construct, constructs[1].get());
-  EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
+    // The block records the nearest enclosing construct.
+    EXPECT_EQ(fe.GetBlockInfo(10)->construct, constructs[0].get());
+    EXPECT_EQ(fe.GetBlockInfo(20)->construct, constructs[3].get());
+    EXPECT_EQ(fe.GetBlockInfo(30)->construct, constructs[3].get());
+    EXPECT_EQ(fe.GetBlockInfo(40)->construct, constructs[3].get());
+    EXPECT_EQ(fe.GetBlockInfo(90)->construct, constructs[1].get());
+    EXPECT_EQ(fe.GetBlockInfo(99)->construct, constructs[0].get());
 }
 
 TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_DefaultIsLongRangeBackedge) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -3836,21 +3775,21 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
-  fe.RegisterMerges();
-  fe.LabelControlFlowConstructs();
-  EXPECT_FALSE(fe.FindSwitchCaseHeaders());
-  EXPECT_THAT(p->error(), Eq("Switch branch from block 20 to default target "
-                             "block 10 can't be a back-edge"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
+    fe.RegisterMerges();
+    fe.LabelControlFlowConstructs();
+    EXPECT_FALSE(fe.FindSwitchCaseHeaders());
+    EXPECT_THAT(p->error(), Eq("Switch branch from block 20 to default target "
+                               "block 10 can't be a back-edge"));
 }
 
 TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_DefaultIsSelfLoop) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -3868,24 +3807,22 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
-  fe.RegisterMerges();
-  fe.LabelControlFlowConstructs();
-  EXPECT_FALSE(fe.FindSwitchCaseHeaders());
-  // Self-loop that isn't its own continue target is already rejected with a
-  // different message.
-  EXPECT_THAT(
-      p->error(),
-      Eq("Block 20 branches to itself but is not its own continue target"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
+    fe.RegisterMerges();
+    fe.LabelControlFlowConstructs();
+    EXPECT_FALSE(fe.FindSwitchCaseHeaders());
+    // Self-loop that isn't its own continue target is already rejected with a
+    // different message.
+    EXPECT_THAT(p->error(), Eq("Block 20 branches to itself but is not its own continue target"));
 }
 
 TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_DefaultCantEscapeSwitch) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -3903,21 +3840,21 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
-  fe.RegisterMerges();
-  fe.LabelControlFlowConstructs();
-  EXPECT_FALSE(fe.FindSwitchCaseHeaders());
-  EXPECT_THAT(p->error(), Eq("Switch branch from block 10 to default block 99 "
-                             "escapes the selection construct"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
+    fe.RegisterMerges();
+    fe.LabelControlFlowConstructs();
+    EXPECT_FALSE(fe.FindSwitchCaseHeaders());
+    EXPECT_THAT(p->error(), Eq("Switch branch from block 10 to default block 99 "
+                               "escapes the selection construct"));
 }
 
 TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_DefaultForTwoSwitches_AsMerge) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -3942,23 +3879,21 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
-  fe.RegisterMerges();
-  fe.LabelControlFlowConstructs();
-  EXPECT_FALSE(fe.FindSwitchCaseHeaders());
-  EXPECT_THAT(p->error(),
-              Eq("Block 89 is the default block for switch-selection header 10 "
-                 "and also the merge block for 50 (violates dominance rule)"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
+    fe.RegisterMerges();
+    fe.LabelControlFlowConstructs();
+    EXPECT_FALSE(fe.FindSwitchCaseHeaders());
+    EXPECT_THAT(p->error(), Eq("Block 89 is the default block for switch-selection header 10 "
+                               "and also the merge block for 50 (violates dominance rule)"));
 }
 
-TEST_F(SpvParserCFGTest,
-       FindSwitchCaseHeaders_DefaultForTwoSwitches_AsCaseClause) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_DefaultForTwoSwitches_AsCaseClause) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -3986,21 +3921,21 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
-  fe.RegisterMerges();
-  fe.LabelControlFlowConstructs();
-  EXPECT_FALSE(fe.FindSwitchCaseHeaders());
-  EXPECT_THAT(p->error(), Eq("Block 80 is declared as the default target for "
-                             "two OpSwitch instructions, at blocks 10 and 50"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
+    fe.RegisterMerges();
+    fe.LabelControlFlowConstructs();
+    EXPECT_FALSE(fe.FindSwitchCaseHeaders());
+    EXPECT_THAT(p->error(), Eq("Block 80 is declared as the default target for "
+                               "two OpSwitch instructions, at blocks 10 and 50"));
 }
 
 TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_CaseIsLongRangeBackedge) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -4015,21 +3950,21 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
-  fe.RegisterMerges();
-  fe.LabelControlFlowConstructs();
-  EXPECT_FALSE(fe.FindSwitchCaseHeaders());
-  EXPECT_THAT(p->error(), Eq("Switch branch from block 20 to case target "
-                             "block 10 can't be a back-edge"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
+    fe.RegisterMerges();
+    fe.LabelControlFlowConstructs();
+    EXPECT_FALSE(fe.FindSwitchCaseHeaders());
+    EXPECT_THAT(p->error(), Eq("Switch branch from block 20 to case target "
+                               "block 10 can't be a back-edge"));
 }
 
 TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_CaseIsSelfLoop) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -4044,23 +3979,21 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
-  fe.RegisterMerges();
-  fe.LabelControlFlowConstructs();
-  EXPECT_FALSE(fe.FindSwitchCaseHeaders());
-  // The error is caught earlier
-  EXPECT_THAT(
-      p->error(),
-      Eq("Block 20 branches to itself but is not its own continue target"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
+    fe.RegisterMerges();
+    fe.LabelControlFlowConstructs();
+    EXPECT_FALSE(fe.FindSwitchCaseHeaders());
+    // The error is caught earlier
+    EXPECT_THAT(p->error(), Eq("Block 20 branches to itself but is not its own continue target"));
 }
 
 TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_CaseCanBeSwitchMerge) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -4075,22 +4008,22 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
-  fe.RegisterMerges();
-  fe.LabelControlFlowConstructs();
-  EXPECT_TRUE(fe.FindSwitchCaseHeaders());
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
+    fe.RegisterMerges();
+    fe.LabelControlFlowConstructs();
+    EXPECT_TRUE(fe.FindSwitchCaseHeaders());
 
-  // TODO(crbug.com/tint/774) Re-enable after codegen bug fixed.
-  p->DeliberatelyInvalidSpirv();
+    // TODO(crbug.com/tint/774) Re-enable after codegen bug fixed.
+    p->DeliberatelyInvalidSpirv();
 }
 
 TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_CaseCantEscapeSwitch) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -4109,21 +4042,21 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
-  fe.RegisterMerges();
-  fe.LabelControlFlowConstructs();
-  EXPECT_FALSE(fe.FindSwitchCaseHeaders());
-  EXPECT_THAT(p->error(), Eq("Switch branch from block 20 to case target block "
-                             "99 escapes the selection construct"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
+    fe.RegisterMerges();
+    fe.LabelControlFlowConstructs();
+    EXPECT_FALSE(fe.FindSwitchCaseHeaders());
+    EXPECT_THAT(p->error(), Eq("Switch branch from block 20 to case target block "
+                               "99 escapes the selection construct"));
 }
 
 TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_CaseForMoreThanOneSwitch) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -4145,22 +4078,21 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
-  fe.RegisterMerges();
-  fe.LabelControlFlowConstructs();
-  EXPECT_FALSE(fe.FindSwitchCaseHeaders());
-  EXPECT_THAT(p->error(),
-              Eq("Block 50 is declared as the switch case target for two "
-                 "OpSwitch instructions, at blocks 10 and 20"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
+    fe.RegisterMerges();
+    fe.LabelControlFlowConstructs();
+    EXPECT_FALSE(fe.FindSwitchCaseHeaders());
+    EXPECT_THAT(p->error(), Eq("Block 50 is declared as the switch case target for two "
+                               "OpSwitch instructions, at blocks 10 and 20"));
 }
 
 TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_CaseIsMergeForAnotherConstruct) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -4185,21 +4117,21 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
-  fe.RegisterMerges();
-  fe.LabelControlFlowConstructs();
-  EXPECT_FALSE(fe.FindSwitchCaseHeaders());
-  EXPECT_THAT(p->error(), Eq("Switch branch from block 10 to case target block "
-                             "20 escapes the selection construct"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
+    fe.RegisterMerges();
+    fe.LabelControlFlowConstructs();
+    EXPECT_FALSE(fe.FindSwitchCaseHeaders());
+    EXPECT_THAT(p->error(), Eq("Switch branch from block 10 to case target block "
+                               "20 escapes the selection construct"));
 }
 
 TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_NoSwitch) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -4207,26 +4139,26 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
-  fe.RegisterMerges();
-  fe.LabelControlFlowConstructs();
-  EXPECT_TRUE(fe.FindSwitchCaseHeaders());
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
+    fe.RegisterMerges();
+    fe.LabelControlFlowConstructs();
+    EXPECT_TRUE(fe.FindSwitchCaseHeaders());
 
-  const auto* bi10 = fe.GetBlockInfo(10);
-  ASSERT_NE(bi10, nullptr);
-  EXPECT_EQ(bi10->case_head_for, nullptr);
-  EXPECT_EQ(bi10->default_head_for, nullptr);
-  EXPECT_FALSE(bi10->default_is_merge);
-  EXPECT_EQ(bi10->case_values.get(), nullptr);
+    const auto* bi10 = fe.GetBlockInfo(10);
+    ASSERT_NE(bi10, nullptr);
+    EXPECT_EQ(bi10->case_head_for, nullptr);
+    EXPECT_EQ(bi10->default_head_for, nullptr);
+    EXPECT_FALSE(bi10->default_is_merge);
+    EXPECT_EQ(bi10->case_values.get(), nullptr);
 }
 
 TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_DefaultIsMerge) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -4241,27 +4173,27 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
-  fe.RegisterMerges();
-  fe.LabelControlFlowConstructs();
-  EXPECT_TRUE(fe.FindSwitchCaseHeaders());
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
+    fe.RegisterMerges();
+    fe.LabelControlFlowConstructs();
+    EXPECT_TRUE(fe.FindSwitchCaseHeaders());
 
-  const auto* bi99 = fe.GetBlockInfo(99);
-  ASSERT_NE(bi99, nullptr);
-  EXPECT_EQ(bi99->case_head_for, nullptr);
-  ASSERT_NE(bi99->default_head_for, nullptr);
-  EXPECT_EQ(bi99->default_head_for->begin_id, 10u);
-  EXPECT_TRUE(bi99->default_is_merge);
-  EXPECT_EQ(bi99->case_values.get(), nullptr);
+    const auto* bi99 = fe.GetBlockInfo(99);
+    ASSERT_NE(bi99, nullptr);
+    EXPECT_EQ(bi99->case_head_for, nullptr);
+    ASSERT_NE(bi99->default_head_for, nullptr);
+    EXPECT_EQ(bi99->default_head_for->begin_id, 10u);
+    EXPECT_TRUE(bi99->default_is_merge);
+    EXPECT_EQ(bi99->case_values.get(), nullptr);
 }
 
 TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_DefaultIsNotMerge) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -4279,27 +4211,27 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
-  fe.RegisterMerges();
-  fe.LabelControlFlowConstructs();
-  EXPECT_TRUE(fe.FindSwitchCaseHeaders());
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
+    fe.RegisterMerges();
+    fe.LabelControlFlowConstructs();
+    EXPECT_TRUE(fe.FindSwitchCaseHeaders());
 
-  const auto* bi30 = fe.GetBlockInfo(30);
-  ASSERT_NE(bi30, nullptr);
-  EXPECT_EQ(bi30->case_head_for, nullptr);
-  ASSERT_NE(bi30->default_head_for, nullptr);
-  EXPECT_EQ(bi30->default_head_for->begin_id, 10u);
-  EXPECT_FALSE(bi30->default_is_merge);
-  EXPECT_EQ(bi30->case_values.get(), nullptr);
+    const auto* bi30 = fe.GetBlockInfo(30);
+    ASSERT_NE(bi30, nullptr);
+    EXPECT_EQ(bi30->case_head_for, nullptr);
+    ASSERT_NE(bi30->default_head_for, nullptr);
+    EXPECT_EQ(bi30->default_head_for->begin_id, 10u);
+    EXPECT_FALSE(bi30->default_is_merge);
+    EXPECT_EQ(bi30->case_values.get(), nullptr);
 }
 
 TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_CaseIsNotDefault) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -4317,27 +4249,27 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
-  fe.RegisterMerges();
-  fe.LabelControlFlowConstructs();
-  EXPECT_TRUE(fe.FindSwitchCaseHeaders());
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
+    fe.RegisterMerges();
+    fe.LabelControlFlowConstructs();
+    EXPECT_TRUE(fe.FindSwitchCaseHeaders());
 
-  const auto* bi20 = fe.GetBlockInfo(20);
-  ASSERT_NE(bi20, nullptr);
-  ASSERT_NE(bi20->case_head_for, nullptr);
-  EXPECT_EQ(bi20->case_head_for->begin_id, 10u);
-  EXPECT_EQ(bi20->default_head_for, nullptr);
-  EXPECT_FALSE(bi20->default_is_merge);
-  EXPECT_THAT(*(bi20->case_values.get()), UnorderedElementsAre(200));
+    const auto* bi20 = fe.GetBlockInfo(20);
+    ASSERT_NE(bi20, nullptr);
+    ASSERT_NE(bi20->case_head_for, nullptr);
+    EXPECT_EQ(bi20->case_head_for->begin_id, 10u);
+    EXPECT_EQ(bi20->default_head_for, nullptr);
+    EXPECT_FALSE(bi20->default_is_merge);
+    EXPECT_THAT(*(bi20->case_values.get()), UnorderedElementsAre(200));
 }
 
 TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_CaseIsDefault) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -4352,27 +4284,27 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
-  fe.RegisterMerges();
-  fe.LabelControlFlowConstructs();
-  EXPECT_TRUE(fe.FindSwitchCaseHeaders());
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
+    fe.RegisterMerges();
+    fe.LabelControlFlowConstructs();
+    EXPECT_TRUE(fe.FindSwitchCaseHeaders());
 
-  const auto* bi20 = fe.GetBlockInfo(20);
-  ASSERT_NE(bi20, nullptr);
-  ASSERT_NE(bi20->case_head_for, nullptr);
-  EXPECT_EQ(bi20->case_head_for->begin_id, 10u);
-  EXPECT_EQ(bi20->default_head_for, bi20->case_head_for);
-  EXPECT_FALSE(bi20->default_is_merge);
-  EXPECT_THAT(*(bi20->case_values.get()), UnorderedElementsAre(200));
+    const auto* bi20 = fe.GetBlockInfo(20);
+    ASSERT_NE(bi20, nullptr);
+    ASSERT_NE(bi20->case_head_for, nullptr);
+    EXPECT_EQ(bi20->case_head_for->begin_id, 10u);
+    EXPECT_EQ(bi20->default_head_for, bi20->case_head_for);
+    EXPECT_FALSE(bi20->default_is_merge);
+    EXPECT_THAT(*(bi20->case_values.get()), UnorderedElementsAre(200));
 }
 
 TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_ManyCasesWithSameValue_IsError) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -4390,22 +4322,21 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
-  fe.RegisterMerges();
-  fe.LabelControlFlowConstructs();
-  EXPECT_FALSE(fe.FindSwitchCaseHeaders());
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
+    fe.RegisterMerges();
+    fe.LabelControlFlowConstructs();
+    EXPECT_FALSE(fe.FindSwitchCaseHeaders());
 
-  EXPECT_THAT(p->error(),
-              Eq("Duplicate case value 200 in OpSwitch in block 10"));
+    EXPECT_THAT(p->error(), Eq("Duplicate case value 200 in OpSwitch in block 10"));
 }
 
 TEST_F(SpvParserCFGTest, FindSwitchCaseHeaders_ManyValuesWithSameCase) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -4420,27 +4351,27 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
-  fe.RegisterMerges();
-  fe.LabelControlFlowConstructs();
-  EXPECT_TRUE(fe.FindSwitchCaseHeaders());
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
+    fe.RegisterMerges();
+    fe.LabelControlFlowConstructs();
+    EXPECT_TRUE(fe.FindSwitchCaseHeaders());
 
-  const auto* bi20 = fe.GetBlockInfo(20);
-  ASSERT_NE(bi20, nullptr);
-  ASSERT_NE(bi20->case_head_for, nullptr);
-  EXPECT_EQ(bi20->case_head_for->begin_id, 10u);
-  EXPECT_EQ(bi20->default_head_for, nullptr);
-  EXPECT_FALSE(bi20->default_is_merge);
-  EXPECT_THAT(*(bi20->case_values.get()), UnorderedElementsAre(200, 300));
+    const auto* bi20 = fe.GetBlockInfo(20);
+    ASSERT_NE(bi20, nullptr);
+    ASSERT_NE(bi20->case_head_for, nullptr);
+    EXPECT_EQ(bi20->case_head_for->begin_id, 10u);
+    EXPECT_EQ(bi20->default_head_for, nullptr);
+    EXPECT_FALSE(bi20->default_is_merge);
+    EXPECT_THAT(*(bi20->case_values.get()), UnorderedElementsAre(200, 300));
 }
 
 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_BranchEscapesIfConstruct) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -4465,19 +4396,17 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(FlowClassifyCFGEdges(&fe)) << p->error();
-  // Some further processing
-  EXPECT_THAT(
-      p->error(),
-      Eq("Branch from block 30 to block 80 is an invalid exit from construct "
-         "starting at block 20; branch bypasses merge block 50"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(FlowClassifyCFGEdges(&fe)) << p->error();
+    // Some further processing
+    EXPECT_THAT(p->error(), Eq("Branch from block 30 to block 80 is an invalid exit from construct "
+                               "starting at block 20; branch bypasses merge block 50"));
 }
 
 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_ReturnInContinueConstruct) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -4498,16 +4427,16 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(FlowClassifyCFGEdges(&fe)) << p->error();
-  EXPECT_THAT(p->error(), Eq("Invalid function exit at block 50 from continue "
-                             "construct starting at 50"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(FlowClassifyCFGEdges(&fe)) << p->error();
+    EXPECT_THAT(p->error(), Eq("Invalid function exit at block 50 from continue "
+                               "construct starting at 50"));
 }
 
 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_KillInContinueConstruct) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -4528,16 +4457,16 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
-  EXPECT_THAT(p->error(), Eq("Invalid function exit at block 50 from continue "
-                             "construct starting at 50"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
+    EXPECT_THAT(p->error(), Eq("Invalid function exit at block 50 from continue "
+                               "construct starting at 50"));
 }
 
 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_UnreachableInContinueConstruct) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -4558,16 +4487,16 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
-  EXPECT_THAT(p->error(), Eq("Invalid function exit at block 50 from continue "
-                             "construct starting at 50"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
+    EXPECT_THAT(p->error(), Eq("Invalid function exit at block 50 from continue "
+                               "construct starting at 50"));
 }
 
 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_BackEdge_NotInContinueConstruct) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -4588,18 +4517,15 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
-  EXPECT_THAT(
-      p->error(),
-      Eq("Invalid backedge (30->20): 30 is not in a continue construct"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
+    EXPECT_THAT(p->error(), Eq("Invalid backedge (30->20): 30 is not in a continue construct"));
 }
 
-TEST_F(SpvParserCFGTest,
-       ClassifyCFGEdges_BackEdge_NotInLastBlockOfContinueConstruct) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, ClassifyCFGEdges_BackEdge_NotInLastBlockOfContinueConstruct) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -4623,18 +4549,17 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
-  EXPECT_THAT(p->error(),
-              Eq("Invalid exit (50->20) from continue construct: 50 is not the "
-                 "last block in the continue construct starting at 50 "
-                 "(violates post-dominance rule)"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
+    EXPECT_THAT(p->error(), Eq("Invalid exit (50->20) from continue construct: 50 is not the "
+                               "last block in the continue construct starting at 50 "
+                               "(violates post-dominance rule)"));
 }
 
 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_BackEdge_ToWrongHeader) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -4659,16 +4584,16 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
-  EXPECT_THAT(p->error(), Eq("Invalid backedge (50->10): does not branch to "
-                             "the corresponding loop header, expected 20"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
+    EXPECT_THAT(p->error(), Eq("Invalid backedge (50->10): does not branch to "
+                               "the corresponding loop header, expected 20"));
 }
 
 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_BackEdge_SingleBlockLoop) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -4683,20 +4608,19 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
 
-  auto* bi20 = fe.GetBlockInfo(20);
-  ASSERT_NE(bi20, nullptr);
-  EXPECT_EQ(bi20->succ_edge.count(20), 1u);
-  EXPECT_EQ(bi20->succ_edge[20], EdgeKind::kBack);
+    auto* bi20 = fe.GetBlockInfo(20);
+    ASSERT_NE(bi20, nullptr);
+    EXPECT_EQ(bi20->succ_edge.count(20), 1u);
+    EXPECT_EQ(bi20->succ_edge[20], EdgeKind::kBack);
 }
 
-TEST_F(SpvParserCFGTest,
-       ClassifyCFGEdges_BackEdge_MultiBlockLoop_SingleBlockContinueConstruct) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, ClassifyCFGEdges_BackEdge_MultiBlockLoop_SingleBlockContinueConstruct) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -4717,21 +4641,21 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
 
-  auto* bi40 = fe.GetBlockInfo(40);
-  ASSERT_NE(bi40, nullptr);
-  EXPECT_EQ(bi40->succ_edge.count(20), 1u);
-  EXPECT_EQ(bi40->succ_edge[20], EdgeKind::kBack);
+    auto* bi40 = fe.GetBlockInfo(40);
+    ASSERT_NE(bi40, nullptr);
+    EXPECT_EQ(bi40->succ_edge.count(20), 1u);
+    EXPECT_EQ(bi40->succ_edge[20], EdgeKind::kBack);
 }
 
 TEST_F(
     SpvParserCFGTest,
     ClassifyCFGEdges_BackEdge_MultiBlockLoop_MultiBlockContinueConstruct_ContinueIsNotHeader) {  // NOLINT
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -4755,21 +4679,21 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
 
-  auto* bi50 = fe.GetBlockInfo(50);
-  ASSERT_NE(bi50, nullptr);
-  EXPECT_EQ(bi50->succ_edge.count(20), 1u);
-  EXPECT_EQ(bi50->succ_edge[20], EdgeKind::kBack);
+    auto* bi50 = fe.GetBlockInfo(50);
+    ASSERT_NE(bi50, nullptr);
+    EXPECT_EQ(bi50->succ_edge.count(20), 1u);
+    EXPECT_EQ(bi50->succ_edge[20], EdgeKind::kBack);
 }
 
 TEST_F(
     SpvParserCFGTest,
     ClassifyCFGEdges_BackEdge_MultiBlockLoop_MultiBlockContinueConstruct_ContinueIsHeader) {  // NOLINT
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -4793,19 +4717,19 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe)) << p->error();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe)) << p->error();
 
-  auto* bi50 = fe.GetBlockInfo(50);
-  ASSERT_NE(bi50, nullptr);
-  EXPECT_EQ(bi50->succ_edge.count(20), 1u);
-  EXPECT_EQ(bi50->succ_edge[20], EdgeKind::kBack);
+    auto* bi50 = fe.GetBlockInfo(50);
+    ASSERT_NE(bi50, nullptr);
+    EXPECT_EQ(bi50->succ_edge.count(20), 1u);
+    EXPECT_EQ(bi50->succ_edge[20], EdgeKind::kBack);
 }
 
 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_PrematureExitFromContinueConstruct) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -4829,19 +4753,17 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
-  EXPECT_THAT(p->error(),
-              Eq("Invalid exit (40->99) from continue construct: 40 is not the "
-                 "last block in the continue construct starting at 40 "
-                 "(violates post-dominance rule)"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
+    EXPECT_THAT(p->error(), Eq("Invalid exit (40->99) from continue construct: 40 is not the "
+                               "last block in the continue construct starting at 40 "
+                               "(violates post-dominance rule)"));
 }
 
-TEST_F(SpvParserCFGTest,
-       ClassifyCFGEdges_LoopBreak_FromLoopHeader_SingleBlockLoop_TrueBranch) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, ClassifyCFGEdges_LoopBreak_FromLoopHeader_SingleBlockLoop_TrueBranch) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -4856,22 +4778,21 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
 
-  auto* bi = fe.GetBlockInfo(20);
-  ASSERT_NE(bi, nullptr);
-  EXPECT_EQ(bi->succ_edge.count(99), 1u);
-  EXPECT_EQ(bi->succ_edge[99], EdgeKind::kLoopBreak);
-  EXPECT_EQ(bi->succ_edge.count(20), 1u);
-  EXPECT_EQ(bi->succ_edge[20], EdgeKind::kBack);
+    auto* bi = fe.GetBlockInfo(20);
+    ASSERT_NE(bi, nullptr);
+    EXPECT_EQ(bi->succ_edge.count(99), 1u);
+    EXPECT_EQ(bi->succ_edge[99], EdgeKind::kLoopBreak);
+    EXPECT_EQ(bi->succ_edge.count(20), 1u);
+    EXPECT_EQ(bi->succ_edge[20], EdgeKind::kBack);
 }
 
-TEST_F(SpvParserCFGTest,
-       ClassifyCFGEdges_LoopBreak_FromLoopHeader_SingleBlockLoop_FalseBranch) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, ClassifyCFGEdges_LoopBreak_FromLoopHeader_SingleBlockLoop_FalseBranch) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -4886,22 +4807,21 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
 
-  auto* bi = fe.GetBlockInfo(20);
-  ASSERT_NE(bi, nullptr);
-  EXPECT_EQ(bi->succ_edge.count(99), 1u);
-  EXPECT_EQ(bi->succ_edge[99], EdgeKind::kLoopBreak);
-  EXPECT_EQ(bi->succ_edge.count(20), 1u);
-  EXPECT_EQ(bi->succ_edge[20], EdgeKind::kBack);
+    auto* bi = fe.GetBlockInfo(20);
+    ASSERT_NE(bi, nullptr);
+    EXPECT_EQ(bi->succ_edge.count(99), 1u);
+    EXPECT_EQ(bi->succ_edge[99], EdgeKind::kLoopBreak);
+    EXPECT_EQ(bi->succ_edge.count(20), 1u);
+    EXPECT_EQ(bi->succ_edge[20], EdgeKind::kBack);
 }
 
-TEST_F(SpvParserCFGTest,
-       ClassifyCFGEdges_LoopBreak_FromLoopHeader_MultiBlockLoop) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, ClassifyCFGEdges_LoopBreak_FromLoopHeader_MultiBlockLoop) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -4919,20 +4839,19 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
 
-  auto* bi = fe.GetBlockInfo(20);
-  ASSERT_NE(bi, nullptr);
-  EXPECT_EQ(bi->succ_edge.count(99), 1u);
-  EXPECT_EQ(bi->succ_edge[99], EdgeKind::kLoopBreak);
+    auto* bi = fe.GetBlockInfo(20);
+    ASSERT_NE(bi, nullptr);
+    EXPECT_EQ(bi->succ_edge.count(99), 1u);
+    EXPECT_EQ(bi->succ_edge[99], EdgeKind::kLoopBreak);
 }
 
-TEST_F(SpvParserCFGTest,
-       ClassifyCFGEdges_LoopBreak_FromContinueConstructHeader) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, ClassifyCFGEdges_LoopBreak_FromContinueConstructHeader) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -4950,19 +4869,19 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
 
-  auto* bi = fe.GetBlockInfo(30);
-  ASSERT_NE(bi, nullptr);
-  EXPECT_EQ(bi->succ_edge.count(99), 1u);
-  EXPECT_EQ(bi->succ_edge[99], EdgeKind::kLoopBreak);
+    auto* bi = fe.GetBlockInfo(30);
+    ASSERT_NE(bi, nullptr);
+    EXPECT_EQ(bi->succ_edge.count(99), 1u);
+    EXPECT_EQ(bi->succ_edge[99], EdgeKind::kLoopBreak);
 }
 
 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_IfBreak_FromIfHeader) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -4977,19 +4896,19 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
 
-  auto* bi = fe.GetBlockInfo(20);
-  ASSERT_NE(bi, nullptr);
-  EXPECT_EQ(bi->succ_edge.count(99), 1u);
-  EXPECT_EQ(bi->succ_edge[99], EdgeKind::kIfBreak);
+    auto* bi = fe.GetBlockInfo(20);
+    ASSERT_NE(bi, nullptr);
+    EXPECT_EQ(bi->succ_edge.count(99), 1u);
+    EXPECT_EQ(bi->succ_edge[99], EdgeKind::kIfBreak);
 }
 
 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_IfBreak_FromIfThenElse) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -5007,26 +4926,26 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
 
-  // Then clause
-  auto* bi20 = fe.GetBlockInfo(20);
-  ASSERT_NE(bi20, nullptr);
-  EXPECT_EQ(bi20->succ_edge.count(99), 1u);
-  EXPECT_EQ(bi20->succ_edge[99], EdgeKind::kIfBreak);
+    // Then clause
+    auto* bi20 = fe.GetBlockInfo(20);
+    ASSERT_NE(bi20, nullptr);
+    EXPECT_EQ(bi20->succ_edge.count(99), 1u);
+    EXPECT_EQ(bi20->succ_edge[99], EdgeKind::kIfBreak);
 
-  // Else clause
-  auto* bi50 = fe.GetBlockInfo(50);
-  ASSERT_NE(bi50, nullptr);
-  EXPECT_EQ(bi50->succ_edge.count(99), 1u);
-  EXPECT_EQ(bi50->succ_edge[99], EdgeKind::kIfBreak);
+    // Else clause
+    auto* bi50 = fe.GetBlockInfo(50);
+    ASSERT_NE(bi50, nullptr);
+    EXPECT_EQ(bi50->succ_edge.count(99), 1u);
+    EXPECT_EQ(bi50->succ_edge[99], EdgeKind::kIfBreak);
 }
 
 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_IfBreak_BypassesMerge_IsError) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -5044,22 +4963,20 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
-  EXPECT_THAT(
-      p->error(),
-      Eq("Branch from block 20 to block 99 is an invalid exit from "
-         "construct starting at block 10; branch bypasses merge block 50"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
+    EXPECT_THAT(p->error(), Eq("Branch from block 20 to block 99 is an invalid exit from "
+                               "construct starting at block 10; branch bypasses merge block 50"));
 }
 
 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_IfBreak_EscapeSwitchCase_IsError) {
-  // Code generation assumes that you can't have kCaseFallThrough and kIfBreak
-  // from the same OpBranchConditional.
-  // This checks one direction of that, where the IfBreak is shown it can't
-  // escape a switch case.
-  auto assembly = CommonTypes() + R"(
+    // Code generation assumes that you can't have kCaseFallThrough and kIfBreak
+    // from the same OpBranchConditional.
+    // This checks one direction of that, where the IfBreak is shown it can't
+    // escape a switch case.
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -5086,18 +5003,16 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
-  EXPECT_THAT(
-      p->error(),
-      Eq("Branch from block 30 to block 99 is an invalid exit from "
-         "construct starting at block 20; branch bypasses merge block 80"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
+    EXPECT_THAT(p->error(), Eq("Branch from block 30 to block 99 is an invalid exit from "
+                               "construct starting at block 20; branch bypasses merge block 80"));
 }
 
 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_SwitchBreak_FromSwitchCaseDirect) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -5112,19 +5027,19 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
 
-  auto* bi = fe.GetBlockInfo(10);
-  ASSERT_NE(bi, nullptr);
-  EXPECT_EQ(bi->succ_edge.count(99), 1u);
-  EXPECT_EQ(bi->succ_edge[99], EdgeKind::kSwitchBreak);
+    auto* bi = fe.GetBlockInfo(10);
+    ASSERT_NE(bi, nullptr);
+    EXPECT_EQ(bi->succ_edge.count(99), 1u);
+    EXPECT_EQ(bi->succ_edge[99], EdgeKind::kSwitchBreak);
 }
 
 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_SwitchBreak_FromSwitchCaseBody) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -5139,19 +5054,19 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
 
-  auto* bi = fe.GetBlockInfo(20);
-  ASSERT_NE(bi, nullptr);
-  EXPECT_EQ(bi->succ_edge.count(99), 1u);
-  EXPECT_EQ(bi->succ_edge[99], EdgeKind::kSwitchBreak);
+    auto* bi = fe.GetBlockInfo(20);
+    ASSERT_NE(bi, nullptr);
+    EXPECT_EQ(bi->succ_edge.count(99), 1u);
+    EXPECT_EQ(bi->succ_edge[99], EdgeKind::kSwitchBreak);
 }
 
 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_SwitchBreak_FromSwitchDefaultBody) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -5169,20 +5084,19 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
 
-  auto* bi = fe.GetBlockInfo(30);
-  ASSERT_NE(bi, nullptr);
-  EXPECT_EQ(bi->succ_edge.count(99), 1u);
-  EXPECT_EQ(bi->succ_edge[99], EdgeKind::kSwitchBreak);
+    auto* bi = fe.GetBlockInfo(30);
+    ASSERT_NE(bi, nullptr);
+    EXPECT_EQ(bi->succ_edge.count(99), 1u);
+    EXPECT_EQ(bi->succ_edge[99], EdgeKind::kSwitchBreak);
 }
 
-TEST_F(SpvParserCFGTest,
-       ClassifyCFGEdges_SwitchBreak_FromSwitchDefaultIsMerge) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, ClassifyCFGEdges_SwitchBreak_FromSwitchDefaultIsMerge) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -5197,20 +5111,19 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
 
-  auto* bi = fe.GetBlockInfo(10);
-  ASSERT_NE(bi, nullptr);
-  EXPECT_EQ(bi->succ_edge.count(99), 1u);
-  EXPECT_EQ(bi->succ_edge[99], EdgeKind::kSwitchBreak);
+    auto* bi = fe.GetBlockInfo(10);
+    ASSERT_NE(bi, nullptr);
+    EXPECT_EQ(bi->succ_edge.count(99), 1u);
+    EXPECT_EQ(bi->succ_edge[99], EdgeKind::kSwitchBreak);
 }
 
-TEST_F(SpvParserCFGTest,
-       ClassifyCFGEdges_SwitchBreak_FromNestedIf_Unconditional) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, ClassifyCFGEdges_SwitchBreak_FromNestedIf_Unconditional) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -5232,20 +5145,19 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
 
-  auto* bi = fe.GetBlockInfo(30);
-  ASSERT_NE(bi, nullptr);
-  EXPECT_EQ(bi->succ_edge.count(99), 1u);
-  EXPECT_EQ(bi->succ_edge[99], EdgeKind::kSwitchBreak);
+    auto* bi = fe.GetBlockInfo(30);
+    ASSERT_NE(bi, nullptr);
+    EXPECT_EQ(bi->succ_edge.count(99), 1u);
+    EXPECT_EQ(bi->succ_edge[99], EdgeKind::kSwitchBreak);
 }
 
-TEST_F(SpvParserCFGTest,
-       ClassifyCFGEdges_SwitchBreak_FromNestedIf_Conditional) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, ClassifyCFGEdges_SwitchBreak_FromNestedIf_Conditional) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -5267,19 +5179,19 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
 
-  auto* bi = fe.GetBlockInfo(30);
-  ASSERT_NE(bi, nullptr);
-  EXPECT_EQ(bi->succ_edge.count(99), 1u);
-  EXPECT_EQ(bi->succ_edge[99], EdgeKind::kSwitchBreak);
+    auto* bi = fe.GetBlockInfo(30);
+    ASSERT_NE(bi, nullptr);
+    EXPECT_EQ(bi->succ_edge.count(99), 1u);
+    EXPECT_EQ(bi->succ_edge[99], EdgeKind::kSwitchBreak);
 }
 
 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_SwitchBreak_BypassesMerge_IsError) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -5297,19 +5209,17 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
-  EXPECT_THAT(
-      p->error(),
-      Eq("Branch from block 20 to block 99 is an invalid exit from "
-         "construct starting at block 10; branch bypasses merge block 50"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
+    EXPECT_THAT(p->error(), Eq("Branch from block 20 to block 99 is an invalid exit from "
+                               "construct starting at block 10; branch bypasses merge block 50"));
 }
 
 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_SwitchBreak_FromNestedLoop_IsError) {
-  // It's an error because the break can only go as far as the loop.
-  auto assembly = CommonTypes() + R"(
+    // It's an error because the break can only go as far as the loop.
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -5334,20 +5244,17 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
-  EXPECT_THAT(
-      p->error(),
-      Eq("Branch from block 30 to block 99 is an invalid exit from "
-         "construct starting at block 20; branch bypasses merge block 80"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
+    EXPECT_THAT(p->error(), Eq("Branch from block 30 to block 99 is an invalid exit from "
+                               "construct starting at block 20; branch bypasses merge block 80"));
 }
 
-TEST_F(SpvParserCFGTest,
-       ClassifyCFGEdges_SwitchBreak_FromNestedSwitch_IsError) {
-  // It's an error because the break can only go as far as inner switch
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, ClassifyCFGEdges_SwitchBreak_FromNestedSwitch_IsError) {
+    // It's an error because the break can only go as far as inner switch
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -5369,18 +5276,16 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
-  EXPECT_THAT(
-      p->error(),
-      Eq("Branch from block 30 to block 99 is an invalid exit from "
-         "construct starting at block 20; branch bypasses merge block 80"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
+    EXPECT_THAT(p->error(), Eq("Branch from block 30 to block 99 is an invalid exit from "
+                               "construct starting at block 20; branch bypasses merge block 80"));
 }
 
 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_LoopBreak_FromLoopBody) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -5401,19 +5306,19 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
 
-  auto* bi = fe.GetBlockInfo(30);
-  ASSERT_NE(bi, nullptr);
-  EXPECT_EQ(bi->succ_edge.count(99), 1u);
-  EXPECT_EQ(bi->succ_edge[99], EdgeKind::kLoopBreak);
+    auto* bi = fe.GetBlockInfo(30);
+    ASSERT_NE(bi, nullptr);
+    EXPECT_EQ(bi->succ_edge.count(99), 1u);
+    EXPECT_EQ(bi->succ_edge[99], EdgeKind::kLoopBreak);
 }
 
 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_LoopBreak_FromContinueConstructTail) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -5437,19 +5342,19 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
 
-  auto* bi = fe.GetBlockInfo(60);
-  ASSERT_NE(bi, nullptr);
-  EXPECT_EQ(bi->succ_edge.count(99), 1u);
-  EXPECT_EQ(bi->succ_edge[99], EdgeKind::kLoopBreak);
+    auto* bi = fe.GetBlockInfo(60);
+    ASSERT_NE(bi, nullptr);
+    EXPECT_EQ(bi->succ_edge.count(99), 1u);
+    EXPECT_EQ(bi->succ_edge[99], EdgeKind::kLoopBreak);
 }
 
 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_LoopBreak_FromLoopBodyDirect) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -5470,20 +5375,19 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
 
-  auto* bi = fe.GetBlockInfo(30);
-  ASSERT_NE(bi, nullptr);
-  EXPECT_EQ(bi->succ_edge.count(99), 1u);
-  EXPECT_EQ(bi->succ_edge[99], EdgeKind::kLoopBreak);
+    auto* bi = fe.GetBlockInfo(30);
+    ASSERT_NE(bi, nullptr);
+    EXPECT_EQ(bi->succ_edge.count(99), 1u);
+    EXPECT_EQ(bi->succ_edge[99], EdgeKind::kLoopBreak);
 }
 
-TEST_F(SpvParserCFGTest,
-       ClassifyCFGEdges_LoopBreak_FromLoopBodyNestedSelection_Unconditional) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, ClassifyCFGEdges_LoopBreak_FromLoopBodyNestedSelection_Unconditional) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -5511,20 +5415,19 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
 
-  auto* bi = fe.GetBlockInfo(40);
-  ASSERT_NE(bi, nullptr);
-  EXPECT_EQ(bi->succ_edge.count(99), 1u);
-  EXPECT_EQ(bi->succ_edge[99], EdgeKind::kLoopBreak);
+    auto* bi = fe.GetBlockInfo(40);
+    ASSERT_NE(bi, nullptr);
+    EXPECT_EQ(bi->succ_edge.count(99), 1u);
+    EXPECT_EQ(bi->succ_edge[99], EdgeKind::kLoopBreak);
 }
 
-TEST_F(SpvParserCFGTest,
-       ClassifyCFGEdges_LoopBreak_FromLoopBodyNestedSelection_Conditional) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, ClassifyCFGEdges_LoopBreak_FromLoopBodyNestedSelection_Conditional) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -5552,20 +5455,19 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
 
-  auto* bi = fe.GetBlockInfo(40);
-  ASSERT_NE(bi, nullptr);
-  EXPECT_EQ(bi->succ_edge.count(99), 1u);
-  EXPECT_EQ(bi->succ_edge[99], EdgeKind::kLoopBreak);
+    auto* bi = fe.GetBlockInfo(40);
+    ASSERT_NE(bi, nullptr);
+    EXPECT_EQ(bi->succ_edge.count(99), 1u);
+    EXPECT_EQ(bi->succ_edge[99], EdgeKind::kLoopBreak);
 }
 
-TEST_F(SpvParserCFGTest,
-       ClassifyCFGEdges_LoopBreak_FromContinueConstructNestedFlow_IsError) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, ClassifyCFGEdges_LoopBreak_FromContinueConstructNestedFlow_IsError) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -5596,19 +5498,17 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
-  EXPECT_THAT(p->error(),
-              Eq("Invalid exit (50->99) from continue construct: 50 is not the "
-                 "last block in the continue construct starting at 40 "
-                 "(violates post-dominance rule)"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
+    EXPECT_THAT(p->error(), Eq("Invalid exit (50->99) from continue construct: 50 is not the "
+                               "last block in the continue construct starting at 40 "
+                               "(violates post-dominance rule)"));
 }
 
-TEST_F(SpvParserCFGTest,
-       ClassifyCFGEdges_LoopBreak_FromLoopBypassesMerge_IsError) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, ClassifyCFGEdges_LoopBreak_FromLoopBypassesMerge_IsError) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -5632,19 +5532,16 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
-  EXPECT_THAT(
-      p->error(),
-      Eq("Branch from block 30 to block 99 is an invalid exit from "
-         "construct starting at block 20; branch bypasses merge block 50"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
+    EXPECT_THAT(p->error(), Eq("Branch from block 30 to block 99 is an invalid exit from "
+                               "construct starting at block 20; branch bypasses merge block 50"));
 }
 
-TEST_F(SpvParserCFGTest,
-       ClassifyCFGEdges_LoopBreak_FromContinueBypassesMerge_IsError) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, ClassifyCFGEdges_LoopBreak_FromContinueBypassesMerge_IsError) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -5671,18 +5568,16 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
-  EXPECT_THAT(
-      p->error(),
-      Eq("Branch from block 45 to block 99 is an invalid exit from "
-         "construct starting at block 40; branch bypasses merge block 50"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
+    EXPECT_THAT(p->error(), Eq("Branch from block 45 to block 99 is an invalid exit from "
+                               "construct starting at block 40; branch bypasses merge block 50"));
 }
 
 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_LoopContinue_LoopBodyToContinue) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -5703,19 +5598,19 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
 
-  auto* bi = fe.GetBlockInfo(30);
-  ASSERT_NE(bi, nullptr);
-  EXPECT_EQ(bi->succ_edge.count(80), 1u);
-  EXPECT_EQ(bi->succ_edge[80], EdgeKind::kLoopContinue);
+    auto* bi = fe.GetBlockInfo(30);
+    ASSERT_NE(bi, nullptr);
+    EXPECT_EQ(bi->succ_edge.count(80), 1u);
+    EXPECT_EQ(bi->succ_edge[80], EdgeKind::kLoopContinue);
 }
 
 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_LoopContinue_FromNestedIf) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -5743,20 +5638,19 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
 
-  auto* bi = fe.GetBlockInfo(40);
-  ASSERT_NE(bi, nullptr);
-  EXPECT_EQ(bi->succ_edge.count(80), 1u);
-  EXPECT_EQ(bi->succ_edge[80], EdgeKind::kLoopContinue);
+    auto* bi = fe.GetBlockInfo(40);
+    ASSERT_NE(bi, nullptr);
+    EXPECT_EQ(bi->succ_edge.count(80), 1u);
+    EXPECT_EQ(bi->succ_edge[80], EdgeKind::kLoopContinue);
 }
 
-TEST_F(SpvParserCFGTest,
-       ClassifyCFGEdges_LoopContinue_ConditionalFromNestedIf) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, ClassifyCFGEdges_LoopContinue_ConditionalFromNestedIf) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -5784,20 +5678,19 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
 
-  auto* bi = fe.GetBlockInfo(40);
-  ASSERT_NE(bi, nullptr);
-  EXPECT_EQ(bi->succ_edge.count(80), 1u);
-  EXPECT_EQ(bi->succ_edge[80], EdgeKind::kLoopContinue);
+    auto* bi = fe.GetBlockInfo(40);
+    ASSERT_NE(bi, nullptr);
+    EXPECT_EQ(bi->succ_edge.count(80), 1u);
+    EXPECT_EQ(bi->succ_edge[80], EdgeKind::kLoopContinue);
 }
 
-TEST_F(SpvParserCFGTest,
-       ClassifyCFGEdges_LoopContinue_FromNestedSwitchCaseBody_Unconditional) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, ClassifyCFGEdges_LoopContinue_FromNestedSwitchCaseBody_Unconditional) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -5825,20 +5718,19 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe)) << p->error();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe)) << p->error();
 
-  auto* bi = fe.GetBlockInfo(40);
-  ASSERT_NE(bi, nullptr);
-  EXPECT_EQ(bi->succ_edge.count(80), 1u);
-  EXPECT_EQ(bi->succ_edge[80], EdgeKind::kLoopContinue);
+    auto* bi = fe.GetBlockInfo(40);
+    ASSERT_NE(bi, nullptr);
+    EXPECT_EQ(bi->succ_edge.count(80), 1u);
+    EXPECT_EQ(bi->succ_edge[80], EdgeKind::kLoopContinue);
 }
 
-TEST_F(SpvParserCFGTest,
-       ClassifyCFGEdges_LoopContinue_FromNestedSwitchCaseDirect_IsError) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, ClassifyCFGEdges_LoopContinue_FromNestedSwitchCaseDirect_IsError) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -5863,22 +5755,21 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
-  EXPECT_TRUE(fe.RegisterMerges());
-  EXPECT_TRUE(fe.LabelControlFlowConstructs());
-  EXPECT_FALSE(fe.FindSwitchCaseHeaders());
-  EXPECT_THAT(p->error(), Eq("Switch branch from block 30 to case target block "
-                             "80 escapes the selection construct"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
+    EXPECT_TRUE(fe.RegisterMerges());
+    EXPECT_TRUE(fe.LabelControlFlowConstructs());
+    EXPECT_FALSE(fe.FindSwitchCaseHeaders());
+    EXPECT_THAT(p->error(), Eq("Switch branch from block 30 to case target block "
+                               "80 escapes the selection construct"));
 }
 
-TEST_F(SpvParserCFGTest,
-       ClassifyCFGEdges_LoopContinue_FromNestedSwitchDefaultDirect_IsError) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, ClassifyCFGEdges_LoopContinue_FromNestedSwitchDefaultDirect_IsError) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -5903,22 +5794,21 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
-  EXPECT_TRUE(fe.RegisterMerges());
-  EXPECT_TRUE(fe.LabelControlFlowConstructs());
-  EXPECT_FALSE(fe.FindSwitchCaseHeaders());
-  EXPECT_THAT(p->error(), Eq("Switch branch from block 30 to default block 80 "
-                             "escapes the selection construct"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
+    EXPECT_TRUE(fe.RegisterMerges());
+    EXPECT_TRUE(fe.LabelControlFlowConstructs());
+    EXPECT_FALSE(fe.FindSwitchCaseHeaders());
+    EXPECT_THAT(p->error(), Eq("Switch branch from block 30 to default block 80 "
+                               "escapes the selection construct"));
 }
 
-TEST_F(SpvParserCFGTest,
-       ClassifyCFGEdges_LoopContinue_FromNestedSwitchDefaultBody_Conditional) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, ClassifyCFGEdges_LoopContinue_FromNestedSwitchDefaultBody_Conditional) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -5946,21 +5836,19 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe)) << p->error();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe)) << p->error();
 
-  auto* bi = fe.GetBlockInfo(40);
-  ASSERT_NE(bi, nullptr);
-  EXPECT_EQ(bi->succ_edge.count(80), 1u);
-  EXPECT_EQ(bi->succ_edge[80], EdgeKind::kLoopContinue);
+    auto* bi = fe.GetBlockInfo(40);
+    ASSERT_NE(bi, nullptr);
+    EXPECT_EQ(bi->succ_edge.count(80), 1u);
+    EXPECT_EQ(bi->succ_edge[80], EdgeKind::kLoopContinue);
 }
 
-TEST_F(
-    SpvParserCFGTest,
-    ClassifyCFGEdges_LoopContinue_FromNestedSwitchDefaultBody_Unconditional) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, ClassifyCFGEdges_LoopContinue_FromNestedSwitchDefaultBody_Unconditional) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -5988,24 +5876,23 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
 
-  auto* bi = fe.GetBlockInfo(40);
-  ASSERT_NE(bi, nullptr);
-  EXPECT_EQ(bi->succ_edge.count(80), 1u);
-  EXPECT_EQ(bi->succ_edge[80], EdgeKind::kLoopContinue);
+    auto* bi = fe.GetBlockInfo(40);
+    ASSERT_NE(bi, nullptr);
+    EXPECT_EQ(bi->succ_edge.count(80), 1u);
+    EXPECT_EQ(bi->succ_edge[80], EdgeKind::kLoopContinue);
 }
 
-TEST_F(SpvParserCFGTest,
-       ClassifyCFGEdges_LoopContinue_FromNestedLoopHeader_IsError) {
-  // Inner loop header tries to do continue to outer loop continue target.
-  // This is disallowed by the rule:
-  //    "a continue block is valid only for the innermost loop it is nested
-  //    inside of"
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, ClassifyCFGEdges_LoopContinue_FromNestedLoopHeader_IsError) {
+    // Inner loop header tries to do continue to outer loop continue target.
+    // This is disallowed by the rule:
+    //    "a continue block is valid only for the innermost loop it is nested
+    //    inside of"
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -6039,18 +5926,16 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
-  EXPECT_THAT(
-      p->error(),
-      Eq("Branch from block 30 to block 80 is an invalid exit from construct "
-         "starting at block 30; branch bypasses merge block 59"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
+    EXPECT_THAT(p->error(), Eq("Branch from block 30 to block 80 is an invalid exit from construct "
+                               "starting at block 30; branch bypasses merge block 59"));
 }
 
 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_Fallthrough_CaseTailToCase) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -6071,20 +5956,19 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
 
-  auto* bi = fe.GetBlockInfo(30);
-  ASSERT_NE(bi, nullptr);
-  EXPECT_EQ(bi->succ_edge.count(40), 1u);
-  EXPECT_EQ(bi->succ_edge[40], EdgeKind::kCaseFallThrough);
+    auto* bi = fe.GetBlockInfo(30);
+    ASSERT_NE(bi, nullptr);
+    EXPECT_EQ(bi->succ_edge.count(40), 1u);
+    EXPECT_EQ(bi->succ_edge[40], EdgeKind::kCaseFallThrough);
 }
 
-TEST_F(SpvParserCFGTest,
-       ClassifyCFGEdges_Fallthrough_CaseTailToDefaultNotMerge) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, ClassifyCFGEdges_Fallthrough_CaseTailToDefaultNotMerge) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -6105,19 +5989,19 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
 
-  auto* bi = fe.GetBlockInfo(30);
-  ASSERT_NE(bi, nullptr);
-  EXPECT_EQ(bi->succ_edge.count(40), 1u);
-  EXPECT_EQ(bi->succ_edge[40], EdgeKind::kCaseFallThrough);
+    auto* bi = fe.GetBlockInfo(30);
+    ASSERT_NE(bi, nullptr);
+    EXPECT_EQ(bi->succ_edge.count(40), 1u);
+    EXPECT_EQ(bi->succ_edge[40], EdgeKind::kCaseFallThrough);
 }
 
 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_Fallthrough_DefaultToCase) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -6138,22 +6022,21 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
 
-  auto* bi = fe.GetBlockInfo(30);
-  ASSERT_NE(bi, nullptr);
-  EXPECT_EQ(bi->succ_edge.count(40), 1u);
-  EXPECT_EQ(bi->succ_edge[40], EdgeKind::kCaseFallThrough);
+    auto* bi = fe.GetBlockInfo(30);
+    ASSERT_NE(bi, nullptr);
+    EXPECT_EQ(bi->succ_edge.count(40), 1u);
+    EXPECT_EQ(bi->succ_edge[40], EdgeKind::kCaseFallThrough);
 }
 
-TEST_F(SpvParserCFGTest,
-       ClassifyCFGEdges_Fallthrough_BranchConditionalWith_IfBreak_IsError) {
-  // Code generation assumes OpBranchConditional can't have kCaseFallThrough
-  // with kIfBreak.
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, ClassifyCFGEdges_Fallthrough_BranchConditionalWith_IfBreak_IsError) {
+    // Code generation assumes OpBranchConditional can't have kCaseFallThrough
+    // with kIfBreak.
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -6180,21 +6063,18 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
-  EXPECT_THAT(
-      p->error(),
-      Eq("Branch from block 30 to block 99 is an invalid exit from "
-         "construct starting at block 20; branch bypasses merge block 80"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
+    EXPECT_THAT(p->error(), Eq("Branch from block 30 to block 99 is an invalid exit from "
+                               "construct starting at block 20; branch bypasses merge block 80"));
 }
 
-TEST_F(SpvParserCFGTest,
-       ClassifyCFGEdges_Fallthrough_BranchConditionalWith_Forward_IsError) {
-  // Code generation assumes OpBranchConditional can't have kCaseFallThrough
-  // with kForward.
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, ClassifyCFGEdges_Fallthrough_BranchConditionalWith_Forward_IsError) {
+    // Code generation assumes OpBranchConditional can't have kCaseFallThrough
+    // with kForward.
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -6216,26 +6096,24 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
-  EXPECT_THAT(p->error(),
-              Eq("Control flow diverges at block 20 (to 25, 30) but it is not "
-                 "a structured header (it has no merge instruction)"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
+    EXPECT_THAT(p->error(), Eq("Control flow diverges at block 20 (to 25, 30) but it is not "
+                               "a structured header (it has no merge instruction)"));
 }
 
-TEST_F(
-    SpvParserCFGTest,
-    ClassifyCFGEdges_Fallthrough_BranchConditionalWith_Back_LoopOnOutside_IsError) {  // NOLINT
-  // Code generation assumes OpBranchConditional can't have kCaseFallThrough
-  // with kBack.
-  //
-  // This test has the loop on the outside. The backedge coming from a case
-  // clause means the switch is inside the continue construct, and the nesting
-  // of the switch's merge means the backedge is coming from a block that is not
-  // at the end of the continue construct.
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest,
+       ClassifyCFGEdges_Fallthrough_BranchConditionalWith_Back_LoopOnOutside_IsError) {  // NOLINT
+    // Code generation assumes OpBranchConditional can't have kCaseFallThrough
+    // with kBack.
+    //
+    // This test has the loop on the outside. The backedge coming from a case
+    // clause means the switch is inside the continue construct, and the nesting
+    // of the switch's merge means the backedge is coming from a block that is not
+    // at the end of the continue construct.
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -6264,25 +6142,24 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
-  EXPECT_THAT(p->error(),
-              Eq("Invalid exit (40->20) from continue construct: 40 is not the "
-                 "last block in the continue construct starting at 30 "
-                 "(violates post-dominance rule)"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
+    EXPECT_THAT(p->error(), Eq("Invalid exit (40->20) from continue construct: 40 is not the "
+                               "last block in the continue construct starting at 30 "
+                               "(violates post-dominance rule)"));
 }
 
 TEST_F(
     SpvParserCFGTest,
     FindSwitchCaseSelectionHeaders_Fallthrough_BranchConditionalWith_Back_LoopOnInside_FallthroughIsMerge_IsError) {  // NOLINT
-  // Code generation assumes OpBranchConditional can't have kCaseFallThrough
-  // with kBack.
-  //
-  // This test has the loop on the inside. The merge block is also the
-  // fallthrough target.
-  auto assembly = CommonTypes() + R"(
+    // Code generation assumes OpBranchConditional can't have kCaseFallThrough
+    // with kBack.
+    //
+    // This test has the loop on the inside. The merge block is also the
+    // fallthrough target.
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel  ; continue target and
@@ -6305,26 +6182,25 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(FlowFindSwitchCaseHeaders(&fe));
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 40, 50, 99));
-  EXPECT_THAT(p->error(),
-              Eq("Block 50 is a case block for switch-selection header 10 and "
-                 "also the merge block for 20 (violates dominance rule)"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(FlowFindSwitchCaseHeaders(&fe));
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 40, 50, 99));
+    EXPECT_THAT(p->error(), Eq("Block 50 is a case block for switch-selection header 10 and "
+                               "also the merge block for 20 (violates dominance rule)"));
 }
 
 TEST_F(
     SpvParserCFGTest,
     ClassifyCFGEdges_Fallthrough_BranchConditionalWith_Back_LoopOnInside_FallthroughIsNotMerge_IsError) {  // NOLINT
-  // Code generation assumes OpBranchConditional can't have kCaseFallThrough
-  // with kBack.
-  //
-  // This test has the loop on the inside. The merge block is not the merge
-  // target But the block order gets messed up because of the weird
-  // connectivity.
-  auto assembly = CommonTypes() + R"(
+    // Code generation assumes OpBranchConditional can't have kCaseFallThrough
+    // with kBack.
+    //
+    // This test has the loop on the inside. The merge block is not the merge
+    // target But the block order gets messed up because of the weird
+    // connectivity.
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel  ; continue target and
@@ -6350,24 +6226,24 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
-  EXPECT_THAT(p->error(), Eq("Branch from 10 to 50 bypasses continue target 40 "
-                             "(dominance rule violated)"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
+    EXPECT_THAT(p->error(), Eq("Branch from 10 to 50 bypasses continue target 40 "
+                               "(dominance rule violated)"));
 }
 
 TEST_F(
     SpvParserCFGTest,
     ClassifyCFGEdges_Fallthrough_BranchConditionalWith_Back_LoopOnInside_NestedMerge_IsError) {  // NOLINT
-  // Code generation assumes OpBranchConditional can't have kCaseFallThrough
-  // with kBack.
-  //
-  // This test has the loop on the inside. The fallthrough is an invalid exit
-  // from the loop. However, the block order gets all messed up because going
-  // from 40 to 50 ends up pulling in 99
-  auto assembly = CommonTypes() + R"(
+    // Code generation assumes OpBranchConditional can't have kCaseFallThrough
+    // with kBack.
+    //
+    // This test has the loop on the inside. The fallthrough is an invalid exit
+    // from the loop. However, the block order gets all messed up because going
+    // from 40 to 50 ends up pulling in 99
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel  ; continue target and
@@ -6393,28 +6269,27 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 40, 50, 49, 99));
-  EXPECT_THAT(p->error(), Eq("Branch from 10 to 50 bypasses continue target 40 "
-                             "(dominance rule violated)"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 40, 50, 49, 99));
+    EXPECT_THAT(p->error(), Eq("Branch from 10 to 50 bypasses continue target 40 "
+                               "(dominance rule violated)"));
 }
 
-TEST_F(SpvParserCFGTest,
-       ClassifyCFGEdges_Fallthrough_CaseNonTailToCase_TrueBranch) {
-  // This is an unusual one, and is an error. Structurally it looks like this:
-  //   switch (val) {
-  //   case 0: {
-  //        if (cond) {
-  //          fallthrough;
-  //        }
-  //        something = 1;
-  //      }
-  //   case 1: { }
-  //   }
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, ClassifyCFGEdges_Fallthrough_CaseNonTailToCase_TrueBranch) {
+    // This is an unusual one, and is an error. Structurally it looks like this:
+    //   switch (val) {
+    //   case 0: {
+    //        if (cond) {
+    //          fallthrough;
+    //        }
+    //        something = 1;
+    //      }
+    //   case 1: { }
+    //   }
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -6439,30 +6314,28 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
-  EXPECT_THAT(
-      p->error(),
-      Eq("Branch from 10 to 50 bypasses header 20 (dominance rule violated)"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
+    EXPECT_THAT(p->error(),
+                Eq("Branch from 10 to 50 bypasses header 20 (dominance rule violated)"));
 }
 
-TEST_F(SpvParserCFGTest,
-       ClassifyCFGEdges_Fallthrough_CaseNonTailToCase_FalseBranch) {
-  // Like previous test, but taking the false branch.
+TEST_F(SpvParserCFGTest, ClassifyCFGEdges_Fallthrough_CaseNonTailToCase_FalseBranch) {
+    // Like previous test, but taking the false branch.
 
-  // This is an unusual one, and is an error. Structurally it looks like this:
-  //   switch (val) {
-  //   case 0: {
-  //        if (cond) {
-  //          fallthrough;
-  //        }
-  //        something = 1;
-  //      }
-  //   case 1: { }
-  //   }
-  auto assembly = CommonTypes() + R"(
+    // This is an unusual one, and is an error. Structurally it looks like this:
+    //   switch (val) {
+    //   case 0: {
+    //        if (cond) {
+    //          fallthrough;
+    //        }
+    //        something = 1;
+    //      }
+    //   case 1: { }
+    //   }
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -6487,17 +6360,16 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
-  EXPECT_THAT(
-      p->error(),
-      Eq("Branch from 10 to 50 bypasses header 20 (dominance rule violated)"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
+    EXPECT_THAT(p->error(),
+                Eq("Branch from 10 to 50 bypasses header 20 (dominance rule violated)"));
 }
 
 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_Forward_IfToThen) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -6512,19 +6384,19 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
 
-  auto* bi = fe.GetBlockInfo(10);
-  ASSERT_NE(bi, nullptr);
-  EXPECT_EQ(bi->succ_edge.count(20), 1u);
-  EXPECT_EQ(bi->succ_edge[20], EdgeKind::kForward);
+    auto* bi = fe.GetBlockInfo(10);
+    ASSERT_NE(bi, nullptr);
+    EXPECT_EQ(bi->succ_edge.count(20), 1u);
+    EXPECT_EQ(bi->succ_edge[20], EdgeKind::kForward);
 }
 
 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_Forward_IfToElse) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -6539,19 +6411,19 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
 
-  auto* bi = fe.GetBlockInfo(10);
-  ASSERT_NE(bi, nullptr);
-  EXPECT_EQ(bi->succ_edge.count(30), 1u);
-  EXPECT_EQ(bi->succ_edge[30], EdgeKind::kForward);
+    auto* bi = fe.GetBlockInfo(10);
+    ASSERT_NE(bi, nullptr);
+    EXPECT_EQ(bi->succ_edge.count(30), 1u);
+    EXPECT_EQ(bi->succ_edge[30], EdgeKind::kForward);
 }
 
 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_Forward_SwitchToCase) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -6566,19 +6438,19 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
 
-  auto* bi = fe.GetBlockInfo(10);
-  ASSERT_NE(bi, nullptr);
-  EXPECT_EQ(bi->succ_edge.count(20), 1u);
-  EXPECT_EQ(bi->succ_edge[20], EdgeKind::kForward);
+    auto* bi = fe.GetBlockInfo(10);
+    ASSERT_NE(bi, nullptr);
+    EXPECT_EQ(bi->succ_edge.count(20), 1u);
+    EXPECT_EQ(bi->succ_edge[20], EdgeKind::kForward);
 }
 
 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_Forward_SwitchToDefaultNotMerge) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -6596,19 +6468,19 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
 
-  auto* bi = fe.GetBlockInfo(10);
-  ASSERT_NE(bi, nullptr);
-  EXPECT_EQ(bi->succ_edge.count(30), 1u);
-  EXPECT_EQ(bi->succ_edge[30], EdgeKind::kForward);
+    auto* bi = fe.GetBlockInfo(10);
+    ASSERT_NE(bi, nullptr);
+    EXPECT_EQ(bi->succ_edge.count(30), 1u);
+    EXPECT_EQ(bi->succ_edge[30], EdgeKind::kForward);
 }
 
 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_Forward_LoopHeadToBody) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -6629,20 +6501,19 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
 
-  auto* bi = fe.GetBlockInfo(20);
-  ASSERT_NE(bi, nullptr);
-  EXPECT_EQ(bi->succ_edge.count(30), 1u);
-  EXPECT_EQ(bi->succ_edge[30], EdgeKind::kForward);
+    auto* bi = fe.GetBlockInfo(20);
+    ASSERT_NE(bi, nullptr);
+    EXPECT_EQ(bi->succ_edge.count(30), 1u);
+    EXPECT_EQ(bi->succ_edge[30], EdgeKind::kForward);
 }
 
-TEST_F(SpvParserCFGTest,
-       ClassifyCFGEdges_DomViolation_BeforeIfToSelectionInterior) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, ClassifyCFGEdges_DomViolation_BeforeIfToSelectionInterior) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -6664,18 +6535,16 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
-  EXPECT_THAT(
-      p->error(),
-      Eq("Branch from 10 to 50 bypasses header 20 (dominance rule violated)"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
+    EXPECT_THAT(p->error(),
+                Eq("Branch from 10 to 50 bypasses header 20 (dominance rule violated)"));
 }
 
-TEST_F(SpvParserCFGTest,
-       ClassifyCFGEdges_DomViolation_BeforeSwitchToSelectionInterior) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, ClassifyCFGEdges_DomViolation_BeforeSwitchToSelectionInterior) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -6697,18 +6566,16 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
-  EXPECT_THAT(
-      p->error(),
-      Eq("Branch from 10 to 50 bypasses header 20 (dominance rule violated)"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
+    EXPECT_THAT(p->error(),
+                Eq("Branch from 10 to 50 bypasses header 20 (dominance rule violated)"));
 }
 
-TEST_F(SpvParserCFGTest,
-       ClassifyCFGEdges_DomViolation_BeforeLoopToLoopBodyInterior) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, ClassifyCFGEdges_DomViolation_BeforeLoopToLoopBodyInterior) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -6733,22 +6600,21 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
-  EXPECT_THAT(p->error(),
-              // Weird error, but still we caught it.
-              // Preferred: Eq("Branch from 10 to 50 bypasses header 20
-              // (dominance rule violated)"))
-              Eq("Branch from 10 to 50 bypasses continue target 80 (dominance "
-                 "rule violated)"))
-      << Dump(fe.block_order());
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
+    EXPECT_THAT(p->error(),
+                // Weird error, but still we caught it.
+                // Preferred: Eq("Branch from 10 to 50 bypasses header 20
+                // (dominance rule violated)"))
+                Eq("Branch from 10 to 50 bypasses continue target 80 (dominance "
+                   "rule violated)"))
+        << Dump(fe.block_order());
 }
 
-TEST_F(SpvParserCFGTest,
-       ClassifyCFGEdges_DomViolation_BeforeContinueToContinueInterior) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, ClassifyCFGEdges_DomViolation_BeforeContinueToContinueInterior) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -6775,19 +6641,17 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
-  EXPECT_THAT(
-      p->error(),
-      Eq("Branch from block 30 to block 60 is an invalid exit from "
-         "construct starting at block 20; branch bypasses continue target 50"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
+    EXPECT_THAT(p->error(),
+                Eq("Branch from block 30 to block 60 is an invalid exit from "
+                   "construct starting at block 20; branch bypasses continue target 50"));
 }
 
-TEST_F(SpvParserCFGTest,
-       ClassifyCFGEdges_DomViolation_AfterContinueToContinueInterior) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, ClassifyCFGEdges_DomViolation_AfterContinueToContinueInterior) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -6809,20 +6673,17 @@
      %80 = OpLabel
      OpBranch %60 ; bad branch
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
-  EXPECT_THAT(
-      p->error(),
-      Eq("Branch from block 50 to block 60 is an invalid exit from "
-         "construct starting at block 50; branch bypasses merge block 80"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
+    EXPECT_THAT(p->error(), Eq("Branch from block 50 to block 60 is an invalid exit from "
+                               "construct starting at block 50; branch bypasses merge block 80"));
 }
 
-TEST_F(
-    SpvParserCFGTest,
-    FindSwitchCaseHeaders_DomViolation_SwitchCase_CantBeMergeForOtherConstruct) {  // NOLINT
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest,
+       FindSwitchCaseHeaders_DomViolation_SwitchCase_CantBeMergeForOtherConstruct) {  // NOLINT
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -6844,19 +6705,16 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(FlowFindSwitchCaseHeaders(&fe));
-  EXPECT_THAT(p->error(),
-              Eq("Block 50 is a case block for switch-selection header 10 and "
-                 "also the merge block for 20 (violates dominance rule)"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(FlowFindSwitchCaseHeaders(&fe));
+    EXPECT_THAT(p->error(), Eq("Block 50 is a case block for switch-selection header 10 and "
+                               "also the merge block for 20 (violates dominance rule)"));
 }
 
-TEST_F(
-    SpvParserCFGTest,
-    ClassifyCFGEdges_DomViolation_SwitchDefault_CantBeMergeForOtherConstruct) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, ClassifyCFGEdges_DomViolation_SwitchDefault_CantBeMergeForOtherConstruct) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -6878,17 +6736,16 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(FlowFindSwitchCaseHeaders(&fe));
-  EXPECT_THAT(p->error(),
-              Eq("Block 50 is the default block for switch-selection header 10 "
-                 "and also the merge block for 20 (violates dominance rule)"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(FlowFindSwitchCaseHeaders(&fe));
+    EXPECT_THAT(p->error(), Eq("Block 50 is the default block for switch-selection header 10 "
+                               "and also the merge block for 20 (violates dominance rule)"));
 }
 
 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_TooManyBackedges) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -6909,17 +6766,15 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
-  EXPECT_THAT(
-      p->error(),
-      Eq("Invalid backedge (30->20): 30 is not in a continue construct"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
+    EXPECT_THAT(p->error(), Eq("Invalid backedge (30->20): 30 is not in a continue construct"));
 }
 
 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_NeededMerge_BranchConditional) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %20 = OpLabel
@@ -6936,17 +6791,16 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
-  EXPECT_THAT(p->error(),
-              Eq("Control flow diverges at block 20 (to 30, 40) but it is not "
-                 "a structured header (it has no merge instruction)"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
+    EXPECT_THAT(p->error(), Eq("Control flow diverges at block 20 (to 30, 40) but it is not "
+                               "a structured header (it has no merge instruction)"));
 }
 
 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_NeededMerge_Switch) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -6963,20 +6817,18 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
-  EXPECT_THAT(p->error(),
-              Eq("Control flow diverges at block 10 (to 99, 20) but it is not "
-                 "a structured header (it has no merge instruction)"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
+    EXPECT_THAT(p->error(), Eq("Control flow diverges at block 10 (to 99, 20) but it is not "
+                               "a structured header (it has no merge instruction)"));
 }
 
-TEST_F(SpvParserCFGTest,
-       ClassifyCFGEdges_Pathological_Forward_LoopHeadSplitBody) {
-  // In this case the branch-conditional in the loop header is really also a
-  // selection header.
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, ClassifyCFGEdges_Pathological_Forward_LoopHeadSplitBody) {
+    // In this case the branch-conditional in the loop header is really also a
+    // selection header.
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -7000,22 +6852,22 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
 
-  auto* bi = fe.GetBlockInfo(20);
-  ASSERT_NE(bi, nullptr);
-  EXPECT_EQ(bi->succ_edge.count(30), 1u);
-  EXPECT_EQ(bi->succ_edge[30], EdgeKind::kForward);
-  EXPECT_EQ(bi->succ_edge.count(50), 1u);
-  EXPECT_EQ(bi->succ_edge[50], EdgeKind::kForward);
+    auto* bi = fe.GetBlockInfo(20);
+    ASSERT_NE(bi, nullptr);
+    EXPECT_EQ(bi->succ_edge.count(30), 1u);
+    EXPECT_EQ(bi->succ_edge[30], EdgeKind::kForward);
+    EXPECT_EQ(bi->succ_edge.count(50), 1u);
+    EXPECT_EQ(bi->succ_edge[50], EdgeKind::kForward);
 }
 
 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_Pathological_Forward_Premerge) {
-  // Two arms of an if-selection converge early, before the merge block
-  auto assembly = CommonTypes() + R"(
+    // Two arms of an if-selection converge early, before the merge block
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -7039,35 +6891,35 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
 
-  auto* bi20 = fe.GetBlockInfo(20);
-  ASSERT_NE(bi20, nullptr);
-  EXPECT_EQ(bi20->succ_edge.count(50), 1u);
-  EXPECT_EQ(bi20->succ_edge[50], EdgeKind::kForward);
+    auto* bi20 = fe.GetBlockInfo(20);
+    ASSERT_NE(bi20, nullptr);
+    EXPECT_EQ(bi20->succ_edge.count(50), 1u);
+    EXPECT_EQ(bi20->succ_edge[50], EdgeKind::kForward);
 
-  auto* bi30 = fe.GetBlockInfo(30);
-  ASSERT_NE(bi30, nullptr);
-  EXPECT_EQ(bi30->succ_edge.count(50), 1u);
-  EXPECT_EQ(bi30->succ_edge[50], EdgeKind::kForward);
+    auto* bi30 = fe.GetBlockInfo(30);
+    ASSERT_NE(bi30, nullptr);
+    EXPECT_EQ(bi30->succ_edge.count(50), 1u);
+    EXPECT_EQ(bi30->succ_edge[50], EdgeKind::kForward);
 
-  auto* bi50 = fe.GetBlockInfo(50);
-  ASSERT_NE(bi50, nullptr);
-  EXPECT_EQ(bi50->succ_edge.count(60), 1u);
-  EXPECT_EQ(bi50->succ_edge[60], EdgeKind::kForward);
+    auto* bi50 = fe.GetBlockInfo(50);
+    ASSERT_NE(bi50, nullptr);
+    EXPECT_EQ(bi50->succ_edge.count(60), 1u);
+    EXPECT_EQ(bi50->succ_edge[60], EdgeKind::kForward);
 
-  auto* bi60 = fe.GetBlockInfo(60);
-  ASSERT_NE(bi60, nullptr);
-  EXPECT_EQ(bi60->succ_edge.count(99), 1u);
-  EXPECT_EQ(bi60->succ_edge[99], EdgeKind::kIfBreak);
+    auto* bi60 = fe.GetBlockInfo(60);
+    ASSERT_NE(bi60, nullptr);
+    EXPECT_EQ(bi60->succ_edge.count(99), 1u);
+    EXPECT_EQ(bi60->succ_edge[99], EdgeKind::kIfBreak);
 }
 
 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_Pathological_Forward_Regardless) {
-  // Both arms of an OpBranchConditional go to the same target.
-  auto assembly = CommonTypes() + R"(
+    // Both arms of an OpBranchConditional go to the same target.
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -7082,24 +6934,24 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
 
-  auto* bi10 = fe.GetBlockInfo(10);
-  ASSERT_NE(bi10, nullptr);
-  EXPECT_EQ(bi10->succ_edge.count(20), 1u);
-  EXPECT_EQ(bi10->succ_edge[20], EdgeKind::kForward);
+    auto* bi10 = fe.GetBlockInfo(10);
+    ASSERT_NE(bi10, nullptr);
+    EXPECT_EQ(bi10->succ_edge.count(20), 1u);
+    EXPECT_EQ(bi10->succ_edge[20], EdgeKind::kForward);
 
-  auto* bi20 = fe.GetBlockInfo(20);
-  ASSERT_NE(bi20, nullptr);
-  EXPECT_EQ(bi20->succ_edge.count(99), 1u);
-  EXPECT_EQ(bi20->succ_edge[99], EdgeKind::kIfBreak);
+    auto* bi20 = fe.GetBlockInfo(20);
+    ASSERT_NE(bi20, nullptr);
+    EXPECT_EQ(bi20->succ_edge.count(99), 1u);
+    EXPECT_EQ(bi20->succ_edge[99], EdgeKind::kIfBreak);
 }
 
 TEST_F(SpvParserCFGTest, FindIfSelectionInternalHeaders_NoIf) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -7107,20 +6959,20 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
 
-  auto* bi = fe.GetBlockInfo(10);
-  ASSERT_NE(bi, nullptr);
-  EXPECT_EQ(bi->true_head, 0u);
-  EXPECT_EQ(bi->false_head, 0u);
-  EXPECT_EQ(bi->premerge_head, 0u);
+    auto* bi = fe.GetBlockInfo(10);
+    ASSERT_NE(bi, nullptr);
+    EXPECT_EQ(bi->true_head, 0u);
+    EXPECT_EQ(bi->false_head, 0u);
+    EXPECT_EQ(bi->premerge_head, 0u);
 }
 
 TEST_F(SpvParserCFGTest, FindIfSelectionInternalHeaders_ThenElse) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -7138,38 +6990,38 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowFindIfSelectionInternalHeaders(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowFindIfSelectionInternalHeaders(&fe));
 
-  auto* bi10 = fe.GetBlockInfo(10);
-  ASSERT_NE(bi10, nullptr);
-  EXPECT_EQ(bi10->true_head, 20u);
-  EXPECT_EQ(bi10->false_head, 30u);
-  EXPECT_EQ(bi10->premerge_head, 0u);
+    auto* bi10 = fe.GetBlockInfo(10);
+    ASSERT_NE(bi10, nullptr);
+    EXPECT_EQ(bi10->true_head, 20u);
+    EXPECT_EQ(bi10->false_head, 30u);
+    EXPECT_EQ(bi10->premerge_head, 0u);
 
-  auto* bi20 = fe.GetBlockInfo(20);
-  ASSERT_NE(bi20, nullptr);
-  EXPECT_EQ(bi20->true_head, 0u);
-  EXPECT_EQ(bi20->false_head, 0u);
-  EXPECT_EQ(bi20->premerge_head, 0u);
+    auto* bi20 = fe.GetBlockInfo(20);
+    ASSERT_NE(bi20, nullptr);
+    EXPECT_EQ(bi20->true_head, 0u);
+    EXPECT_EQ(bi20->false_head, 0u);
+    EXPECT_EQ(bi20->premerge_head, 0u);
 
-  auto* bi30 = fe.GetBlockInfo(30);
-  ASSERT_NE(bi30, nullptr);
-  EXPECT_EQ(bi30->true_head, 0u);
-  EXPECT_EQ(bi30->false_head, 0u);
-  EXPECT_EQ(bi30->premerge_head, 0u);
+    auto* bi30 = fe.GetBlockInfo(30);
+    ASSERT_NE(bi30, nullptr);
+    EXPECT_EQ(bi30->true_head, 0u);
+    EXPECT_EQ(bi30->false_head, 0u);
+    EXPECT_EQ(bi30->premerge_head, 0u);
 
-  auto* bi99 = fe.GetBlockInfo(99);
-  ASSERT_NE(bi99, nullptr);
-  EXPECT_EQ(bi99->true_head, 0u);
-  EXPECT_EQ(bi99->false_head, 0u);
-  EXPECT_EQ(bi99->premerge_head, 0u);
+    auto* bi99 = fe.GetBlockInfo(99);
+    ASSERT_NE(bi99, nullptr);
+    EXPECT_EQ(bi99->true_head, 0u);
+    EXPECT_EQ(bi99->false_head, 0u);
+    EXPECT_EQ(bi99->premerge_head, 0u);
 }
 
 TEST_F(SpvParserCFGTest, FindIfSelectionInternalHeaders_IfOnly) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -7184,32 +7036,32 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowFindIfSelectionInternalHeaders(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowFindIfSelectionInternalHeaders(&fe));
 
-  auto* bi10 = fe.GetBlockInfo(10);
-  ASSERT_NE(bi10, nullptr);
-  EXPECT_EQ(bi10->true_head, 30u);
-  EXPECT_EQ(bi10->false_head, 0u);
-  EXPECT_EQ(bi10->premerge_head, 0u);
+    auto* bi10 = fe.GetBlockInfo(10);
+    ASSERT_NE(bi10, nullptr);
+    EXPECT_EQ(bi10->true_head, 30u);
+    EXPECT_EQ(bi10->false_head, 0u);
+    EXPECT_EQ(bi10->premerge_head, 0u);
 
-  auto* bi30 = fe.GetBlockInfo(30);
-  ASSERT_NE(bi30, nullptr);
-  EXPECT_EQ(bi30->true_head, 0u);
-  EXPECT_EQ(bi30->false_head, 0u);
-  EXPECT_EQ(bi30->premerge_head, 0u);
+    auto* bi30 = fe.GetBlockInfo(30);
+    ASSERT_NE(bi30, nullptr);
+    EXPECT_EQ(bi30->true_head, 0u);
+    EXPECT_EQ(bi30->false_head, 0u);
+    EXPECT_EQ(bi30->premerge_head, 0u);
 
-  auto* bi99 = fe.GetBlockInfo(99);
-  ASSERT_NE(bi99, nullptr);
-  EXPECT_EQ(bi99->true_head, 0u);
-  EXPECT_EQ(bi99->false_head, 0u);
-  EXPECT_EQ(bi99->premerge_head, 0u);
+    auto* bi99 = fe.GetBlockInfo(99);
+    ASSERT_NE(bi99, nullptr);
+    EXPECT_EQ(bi99->true_head, 0u);
+    EXPECT_EQ(bi99->false_head, 0u);
+    EXPECT_EQ(bi99->premerge_head, 0u);
 }
 
 TEST_F(SpvParserCFGTest, FindIfSelectionInternalHeaders_ElseOnly) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -7224,32 +7076,32 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowFindIfSelectionInternalHeaders(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowFindIfSelectionInternalHeaders(&fe));
 
-  auto* bi10 = fe.GetBlockInfo(10);
-  ASSERT_NE(bi10, nullptr);
-  EXPECT_EQ(bi10->true_head, 0u);
-  EXPECT_EQ(bi10->false_head, 30u);
-  EXPECT_EQ(bi10->premerge_head, 0u);
+    auto* bi10 = fe.GetBlockInfo(10);
+    ASSERT_NE(bi10, nullptr);
+    EXPECT_EQ(bi10->true_head, 0u);
+    EXPECT_EQ(bi10->false_head, 30u);
+    EXPECT_EQ(bi10->premerge_head, 0u);
 
-  auto* bi30 = fe.GetBlockInfo(30);
-  ASSERT_NE(bi30, nullptr);
-  EXPECT_EQ(bi30->true_head, 0u);
-  EXPECT_EQ(bi30->false_head, 0u);
-  EXPECT_EQ(bi30->premerge_head, 0u);
+    auto* bi30 = fe.GetBlockInfo(30);
+    ASSERT_NE(bi30, nullptr);
+    EXPECT_EQ(bi30->true_head, 0u);
+    EXPECT_EQ(bi30->false_head, 0u);
+    EXPECT_EQ(bi30->premerge_head, 0u);
 
-  auto* bi99 = fe.GetBlockInfo(99);
-  ASSERT_NE(bi99, nullptr);
-  EXPECT_EQ(bi99->true_head, 0u);
-  EXPECT_EQ(bi99->false_head, 0u);
-  EXPECT_EQ(bi99->premerge_head, 0u);
+    auto* bi99 = fe.GetBlockInfo(99);
+    ASSERT_NE(bi99, nullptr);
+    EXPECT_EQ(bi99->true_head, 0u);
+    EXPECT_EQ(bi99->false_head, 0u);
+    EXPECT_EQ(bi99->premerge_head, 0u);
 }
 
 TEST_F(SpvParserCFGTest, FindIfSelectionInternalHeaders_Regardless) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -7267,22 +7119,22 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowFindIfSelectionInternalHeaders(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowFindIfSelectionInternalHeaders(&fe));
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 80, 99));
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 80, 99));
 
-  auto* bi10 = fe.GetBlockInfo(10);
-  ASSERT_NE(bi10, nullptr);
-  EXPECT_EQ(bi10->true_head, 20u);
-  EXPECT_EQ(bi10->false_head, 20u);
-  EXPECT_EQ(bi10->premerge_head, 0u);
+    auto* bi10 = fe.GetBlockInfo(10);
+    ASSERT_NE(bi10, nullptr);
+    EXPECT_EQ(bi10->true_head, 20u);
+    EXPECT_EQ(bi10->false_head, 20u);
+    EXPECT_EQ(bi10->premerge_head, 0u);
 }
 
 TEST_F(SpvParserCFGTest, FindIfSelectionInternalHeaders_Premerge_Simple) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -7303,23 +7155,22 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowFindIfSelectionInternalHeaders(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowFindIfSelectionInternalHeaders(&fe));
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 80, 99));
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 80, 99));
 
-  auto* bi10 = fe.GetBlockInfo(10);
-  ASSERT_NE(bi10, nullptr);
-  EXPECT_EQ(bi10->true_head, 20u);
-  EXPECT_EQ(bi10->false_head, 30u);
-  EXPECT_EQ(bi10->premerge_head, 80u);
+    auto* bi10 = fe.GetBlockInfo(10);
+    ASSERT_NE(bi10, nullptr);
+    EXPECT_EQ(bi10->true_head, 20u);
+    EXPECT_EQ(bi10->false_head, 30u);
+    EXPECT_EQ(bi10->premerge_head, 80u);
 }
 
-TEST_F(SpvParserCFGTest,
-       FindIfSelectionInternalHeaders_Premerge_ThenDirectToElse) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, FindIfSelectionInternalHeaders_Premerge_ThenDirectToElse) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -7340,23 +7191,22 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowFindIfSelectionInternalHeaders(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowFindIfSelectionInternalHeaders(&fe));
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 80, 99));
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 80, 99));
 
-  auto* bi10 = fe.GetBlockInfo(10);
-  ASSERT_NE(bi10, nullptr);
-  EXPECT_EQ(bi10->true_head, 20u);
-  EXPECT_EQ(bi10->false_head, 30u);
-  EXPECT_EQ(bi10->premerge_head, 30u);
+    auto* bi10 = fe.GetBlockInfo(10);
+    ASSERT_NE(bi10, nullptr);
+    EXPECT_EQ(bi10->true_head, 20u);
+    EXPECT_EQ(bi10->false_head, 30u);
+    EXPECT_EQ(bi10->premerge_head, 30u);
 }
 
-TEST_F(SpvParserCFGTest,
-       FindIfSelectionInternalHeaders_Premerge_ElseDirectToThen) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, FindIfSelectionInternalHeaders_Premerge_ElseDirectToThen) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -7377,23 +7227,22 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowFindIfSelectionInternalHeaders(&fe));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowFindIfSelectionInternalHeaders(&fe));
 
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 30, 20, 80, 99));
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 30, 20, 80, 99));
 
-  auto* bi10 = fe.GetBlockInfo(10);
-  ASSERT_NE(bi10, nullptr);
-  EXPECT_EQ(bi10->true_head, 20u);
-  EXPECT_EQ(bi10->false_head, 30u);
-  EXPECT_EQ(bi10->premerge_head, 20u);
+    auto* bi10 = fe.GetBlockInfo(10);
+    ASSERT_NE(bi10, nullptr);
+    EXPECT_EQ(bi10->true_head, 20u);
+    EXPECT_EQ(bi10->false_head, 30u);
+    EXPECT_EQ(bi10->premerge_head, 20u);
 }
 
-TEST_F(SpvParserCFGTest,
-       FindIfSelectionInternalHeaders_Premerge_MultiCandidate_IsError) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, FindIfSelectionInternalHeaders_Premerge_MultiCandidate_IsError) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -7420,19 +7269,18 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  // Error out sooner in the flow
-  EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
-  EXPECT_THAT(p->error(),
-              Eq("Control flow diverges at block 20 (to 70, 80) but it is not "
-                 "a structured header (it has no merge instruction)"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    // Error out sooner in the flow
+    EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
+    EXPECT_THAT(p->error(), Eq("Control flow diverges at block 20 (to 70, 80) but it is not "
+                               "a structured header (it has no merge instruction)"));
 }
 
 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_IfBreak_FromThen_ForwardWithinThen) {
-  // SPIR-V allows this unusual configuration.
-  auto assembly = CommonTypes() + R"(
+    // SPIR-V allows this unusual configuration.
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -7449,25 +7297,25 @@
      OpReturn
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 80, 99));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 80, 99));
 
-  auto* bi20 = fe.GetBlockInfo(20);
-  ASSERT_NE(bi20, nullptr);
-  EXPECT_EQ(bi20->succ_edge.count(80), 1u);
-  EXPECT_EQ(bi20->succ_edge[80], EdgeKind::kForward);
-  EXPECT_EQ(bi20->succ_edge.count(99), 1u);
-  EXPECT_EQ(bi20->succ_edge[99], EdgeKind::kIfBreak);
+    auto* bi20 = fe.GetBlockInfo(20);
+    ASSERT_NE(bi20, nullptr);
+    EXPECT_EQ(bi20->succ_edge.count(80), 1u);
+    EXPECT_EQ(bi20->succ_edge[80], EdgeKind::kForward);
+    EXPECT_EQ(bi20->succ_edge.count(99), 1u);
+    EXPECT_EQ(bi20->succ_edge[99], EdgeKind::kIfBreak);
 
-  EXPECT_THAT(p->error(), Eq(""));
+    EXPECT_THAT(p->error(), Eq(""));
 }
 
 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_IfBreak_FromElse_ForwardWithinElse) {
-  // SPIR-V allows this unusual configuration.
-  auto assembly = CommonTypes() + R"(
+    // SPIR-V allows this unusual configuration.
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -7487,24 +7335,24 @@
      OpReturn
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 80, 99));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 80, 99));
 
-  auto* bi30 = fe.GetBlockInfo(30);
-  ASSERT_NE(bi30, nullptr);
-  EXPECT_EQ(bi30->succ_edge.count(80), 1u);
-  EXPECT_EQ(bi30->succ_edge[80], EdgeKind::kForward);
-  EXPECT_EQ(bi30->succ_edge.count(99), 1u);
-  EXPECT_EQ(bi30->succ_edge[99], EdgeKind::kIfBreak);
+    auto* bi30 = fe.GetBlockInfo(30);
+    ASSERT_NE(bi30, nullptr);
+    EXPECT_EQ(bi30->succ_edge.count(80), 1u);
+    EXPECT_EQ(bi30->succ_edge[80], EdgeKind::kForward);
+    EXPECT_EQ(bi30->succ_edge.count(99), 1u);
+    EXPECT_EQ(bi30->succ_edge[99], EdgeKind::kIfBreak);
 
-  EXPECT_THAT(p->error(), Eq(""));
+    EXPECT_THAT(p->error(), Eq(""));
 }
 
 TEST_F(SpvParserCFGTest, ClassifyCFGEdges_IfBreak_WithForwardToPremerge) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -7524,30 +7372,30 @@
      OpReturn
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 80, 99));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowClassifyCFGEdges(&fe));
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 30, 80, 99));
 
-  auto* bi20 = fe.GetBlockInfo(20);
-  ASSERT_NE(bi20, nullptr);
-  EXPECT_EQ(bi20->succ_edge.count(80), 1u);
-  EXPECT_EQ(bi20->succ_edge[80], EdgeKind::kForward);
-  EXPECT_EQ(bi20->succ_edge.count(99), 1u);
-  EXPECT_EQ(bi20->succ_edge[99], EdgeKind::kIfBreak);
+    auto* bi20 = fe.GetBlockInfo(20);
+    ASSERT_NE(bi20, nullptr);
+    EXPECT_EQ(bi20->succ_edge.count(80), 1u);
+    EXPECT_EQ(bi20->succ_edge[80], EdgeKind::kForward);
+    EXPECT_EQ(bi20->succ_edge.count(99), 1u);
+    EXPECT_EQ(bi20->succ_edge[99], EdgeKind::kIfBreak);
 
-  EXPECT_THAT(p->error(), Eq(""));
+    EXPECT_THAT(p->error(), Eq(""));
 
-  // TODO(crbug.com/tint/775): The SPIR-V reader errors out on this case.
-  // Remove this when it's fixed.
-  p->DeliberatelyInvalidSpirv();
+    // TODO(crbug.com/tint/775): The SPIR-V reader errors out on this case.
+    // Remove this when it's fixed.
+    p->DeliberatelyInvalidSpirv();
 }
 
-TEST_F(
-    SpvParserCFGTest,
-    FindIfSelectionInternalHeaders_DomViolation_InteriorMerge_CantBeTrueHeader) {  // NOLINT - line length
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest,
+       FindIfSelectionInternalHeaders_DomViolation_InteriorMerge_CantBeTrueHeader) {  // NOLINT -
+                                                                                      // line length
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -7569,20 +7417,20 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(FlowFindIfSelectionInternalHeaders(&fe));
-  EXPECT_THAT(
-      p->error(),
-      Eq("Block 40 is the true branch for if-selection header 10 and also the "
-         "merge block for header block 20 (violates dominance rule)"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(FlowFindIfSelectionInternalHeaders(&fe));
+    EXPECT_THAT(p->error(),
+                Eq("Block 40 is the true branch for if-selection header 10 and also the "
+                   "merge block for header block 20 (violates dominance rule)"));
 }
 
 TEST_F(
     SpvParserCFGTest,
-    FindIfSelectionInternalHeaders_DomViolation_InteriorMerge_CantBeFalseHeader) {  // NOLINT - line length
-  auto assembly = CommonTypes() + R"(
+    FindIfSelectionInternalHeaders_DomViolation_InteriorMerge_CantBeFalseHeader) {  // NOLINT - line
+                                                                                    // length
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -7604,20 +7452,17 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(FlowFindIfSelectionInternalHeaders(&fe));
-  EXPECT_THAT(
-      p->error(),
-      Eq("Block 40 is the false branch for if-selection header 10 and also the "
-         "merge block for header block 20 (violates dominance rule)"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(FlowFindIfSelectionInternalHeaders(&fe));
+    EXPECT_THAT(p->error(),
+                Eq("Block 40 is the false branch for if-selection header 10 and also the "
+                   "merge block for header block 20 (violates dominance rule)"));
 }
 
-TEST_F(
-    SpvParserCFGTest,
-    FindIfSelectionInternalHeaders_DomViolation_InteriorMerge_CantBePremerge) {
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, FindIfSelectionInternalHeaders_DomViolation_InteriorMerge_CantBePremerge) {
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel ; outer if-header
@@ -7645,21 +7490,19 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(FlowFindIfSelectionInternalHeaders(&fe));
-  EXPECT_THAT(p->error(),
-              Eq("Block 70 is the merge block for 50 but has alternate paths "
-                 "reaching it, starting from blocks 20 and 50 which are the "
-                 "true and false branches for the if-selection header block 10 "
-                 "(violates dominance rule)"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(FlowFindIfSelectionInternalHeaders(&fe));
+    EXPECT_THAT(p->error(), Eq("Block 70 is the merge block for 50 but has alternate paths "
+                               "reaching it, starting from blocks 20 and 50 which are the "
+                               "true and false branches for the if-selection header block 10 "
+                               "(violates dominance rule)"));
 }
 
-TEST_F(SpvParserCFGTest,
-       FindIfSelectionInternalHeaders_TrueBranch_LoopBreak_Ok) {
-  // crbug.com/tint/243
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, FindIfSelectionInternalHeaders_TrueBranch_LoopBreak_Ok) {
+    // crbug.com/tint/243
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %5 = OpLabel
@@ -7687,17 +7530,16 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowFindIfSelectionInternalHeaders(&fe));
-  EXPECT_THAT(p->error(), Eq(""));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowFindIfSelectionInternalHeaders(&fe));
+    EXPECT_THAT(p->error(), Eq(""));
 }
 
-TEST_F(SpvParserCFGTest,
-       FindIfSelectionInternalHeaders_TrueBranch_LoopContinue_Ok) {
-  // crbug.com/tint/243
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, FindIfSelectionInternalHeaders_TrueBranch_LoopContinue_Ok) {
+    // crbug.com/tint/243
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %5 = OpLabel
@@ -7725,17 +7567,16 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowFindIfSelectionInternalHeaders(&fe));
-  EXPECT_THAT(p->error(), Eq(""));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowFindIfSelectionInternalHeaders(&fe));
+    EXPECT_THAT(p->error(), Eq(""));
 }
 
-TEST_F(SpvParserCFGTest,
-       FindIfSelectionInternalHeaders_TrueBranch_SwitchBreak_Ok) {
-  // crbug.com/tint/243
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, FindIfSelectionInternalHeaders_TrueBranch_SwitchBreak_Ok) {
+    // crbug.com/tint/243
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -7757,17 +7598,16 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowFindIfSelectionInternalHeaders(&fe));
-  EXPECT_THAT(p->error(), Eq(""));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowFindIfSelectionInternalHeaders(&fe));
+    EXPECT_THAT(p->error(), Eq(""));
 }
 
-TEST_F(SpvParserCFGTest,
-       FindIfSelectionInternalHeaders_FalseBranch_LoopBreak_Ok) {
-  // crbug.com/tint/243
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, FindIfSelectionInternalHeaders_FalseBranch_LoopBreak_Ok) {
+    // crbug.com/tint/243
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %5 = OpLabel
@@ -7795,17 +7635,16 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowFindIfSelectionInternalHeaders(&fe));
-  EXPECT_THAT(p->error(), Eq(""));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowFindIfSelectionInternalHeaders(&fe));
+    EXPECT_THAT(p->error(), Eq(""));
 }
 
-TEST_F(SpvParserCFGTest,
-       FindIfSelectionInternalHeaders_FalseBranch_LoopContinue_Ok) {
-  // crbug.com/tint/243
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, FindIfSelectionInternalHeaders_FalseBranch_LoopContinue_Ok) {
+    // crbug.com/tint/243
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %5 = OpLabel
@@ -7833,17 +7672,16 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowFindIfSelectionInternalHeaders(&fe));
-  EXPECT_THAT(p->error(), Eq(""));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowFindIfSelectionInternalHeaders(&fe));
+    EXPECT_THAT(p->error(), Eq(""));
 }
 
-TEST_F(SpvParserCFGTest,
-       FindIfSelectionInternalHeaders_FalseBranch_SwitchBreak_Ok) {
-  // crbug.com/tint/243
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, FindIfSelectionInternalHeaders_FalseBranch_SwitchBreak_Ok) {
+    // crbug.com/tint/243
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -7865,17 +7703,17 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(FlowFindIfSelectionInternalHeaders(&fe));
-  EXPECT_THAT(p->error(), Eq(""));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(FlowFindIfSelectionInternalHeaders(&fe));
+    EXPECT_THAT(p->error(), Eq(""));
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_IfBreak_FromThen_ForwardWithinThen) {
-  // Exercises the hard case where we a single OpBranchConditional has both
-  // IfBreak and Forward edges, within the true-branch clause.
-  auto assembly = CommonTypes() + R"(
+    // Exercises the hard case where we a single OpBranchConditional has both
+    // IfBreak and Forward edges, within the true-branch clause.
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -7900,13 +7738,13 @@
      OpReturn
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 1u;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 1u;
 var guard10 : bool = true;
 if (false) {
   var_1 = 2u;
@@ -7926,13 +7764,13 @@
 var_1 = 5u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_IfBreak_FromElse_ForwardWithinElse) {
-  // Exercises the hard case where we a single OpBranchConditional has both
-  // IfBreak and Forward edges, within the false-branch clause.
-  auto assembly = CommonTypes() + R"(
+    // Exercises the hard case where we a single OpBranchConditional has both
+    // IfBreak and Forward edges, within the false-branch clause.
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -7957,13 +7795,13 @@
      OpReturn
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 1u;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 1u;
 var guard10 : bool = true;
 if (false) {
   var_1 = 2u;
@@ -7983,16 +7821,15 @@
 var_1 = 5u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
-TEST_F(SpvParserCFGTest,
-       EmitBody_IfBreak_FromThenWithForward_FromElseWithForward_AlsoPremerge) {
-  // This is a combination of the previous two, but also adding a premerge.
-  // We have IfBreak and Forward edges from the same OpBranchConditional, and
-  // this occurs in the true-branch clause, the false-branch clause, and within
-  // the premerge clause.  Flow guards have to be sprinkled in lots of places.
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, EmitBody_IfBreak_FromThenWithForward_FromElseWithForward_AlsoPremerge) {
+    // This is a combination of the previous two, but also adding a premerge.
+    // We have IfBreak and Forward edges from the same OpBranchConditional, and
+    // this occurs in the true-branch clause, the false-branch clause, and within
+    // the premerge clause.  Flow guards have to be sprinkled in lots of places.
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -8029,13 +7866,13 @@
      OpReturn
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error() << assembly;
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 1u;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error() << assembly;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 1u;
 var guard10 : bool = true;
 if (false) {
   var_1 = 2u;
@@ -8071,14 +7908,14 @@
 var_1 = 8u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, BlockIsContinueForMoreThanOneHeader) {
-  // This is disallowed by the rule:
-  //    "a continue block is valid only for the innermost loop it is nested
-  //    inside of"
-  auto assembly = CommonTypes() + R"(
+    // This is disallowed by the rule:
+    //    "a continue block is valid only for the innermost loop it is nested
+    //    inside of"
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -8099,19 +7936,19 @@
      OpReturn
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  fe.RegisterBasicBlocks();
-  fe.ComputeBlockOrderAndPositions();
-  EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
-  EXPECT_FALSE(fe.RegisterMerges());
-  EXPECT_THAT(p->error(), Eq("Block 50 declared as continue target for more "
-                             "than one header: 20, 50"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    fe.RegisterBasicBlocks();
+    fe.ComputeBlockOrderAndPositions();
+    EXPECT_TRUE(fe.VerifyHeaderContinueMergeOrder());
+    EXPECT_FALSE(fe.RegisterMerges());
+    EXPECT_THAT(p->error(), Eq("Block 50 declared as continue target for more "
+                               "than one header: 20, 50"));
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_If_Empty) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -8122,21 +7959,21 @@
      OpReturn
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(if (false) {
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(if (false) {
 }
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_If_Then_NoElse) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -8154,24 +7991,24 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 0u;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 0u;
 if (false) {
   var_1 = 1u;
 }
 var_1 = 999u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_If_NoThen_Else) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -8189,13 +8026,13 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 0u;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 0u;
 if (false) {
 } else {
   var_1 = 1u;
@@ -8203,11 +8040,11 @@
 var_1 = 999u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_If_Then_Else) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -8229,13 +8066,13 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 0u;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 0u;
 if (false) {
   var_1 = 1u;
 } else {
@@ -8244,14 +8081,14 @@
 var_1 = 999u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_If_Then_Else_Premerge) {
-  // TODO(dneto): This should get an extra if(true) around
-  // the premerge code.
-  // See https://bugs.chromium.org/p/tint/issues/detail?id=82
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    // TODO(dneto): This should get an extra if(true) around
+    // the premerge code.
+    // See https://bugs.chromium.org/p/tint/issues/detail?id=82
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -8277,13 +8114,13 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 0u;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 0u;
 if (false) {
   var_1 = 1u;
 } else {
@@ -8295,12 +8132,12 @@
 var_1 = 999u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_If_Then_Premerge) {
-  // The premerge *is* the else.
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    // The premerge *is* the else.
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -8322,13 +8159,13 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 0u;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 0u;
 if (false) {
   var_1 = 1u;
 }
@@ -8338,12 +8175,12 @@
 var_1 = 999u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_If_Else_Premerge) {
-  // The premerge *is* the then-clause.
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    // The premerge *is* the then-clause.
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -8365,13 +8202,13 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 0u;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 0u;
 if (false) {
 } else {
   var_1 = 1u;
@@ -8382,11 +8219,11 @@
 var_1 = 999u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_If_Nest_If) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -8426,13 +8263,13 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 0u;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 0u;
 if (false) {
   var_1 = 1u;
   if (true) {
@@ -8450,11 +8287,11 @@
 var_1 = 999u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Loop_SingleBlock_TrueBackedge) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -8472,13 +8309,13 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 0u;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 0u;
 loop {
   var_1 = 1u;
   if (false) {
@@ -8489,11 +8326,11 @@
 var_1 = 999u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Loop_SingleBlock_FalseBackedge) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -8511,13 +8348,13 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 0u;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 0u;
 loop {
   var_1 = 1u;
   if (false) {
@@ -8527,11 +8364,11 @@
 var_1 = 999u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Loop_SingleBlock_BothBackedge) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -8549,24 +8386,24 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 0u;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 0u;
 loop {
   var_1 = 1u;
 }
 var_1 = 999u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Loop_SingleBlock_UnconditionalBackege) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -8584,24 +8421,24 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 0u;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 0u;
 loop {
   var_1 = 1u;
 }
 var_1 = 999u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Loop_Unconditional_Body_SingleBlockContinue) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -8627,13 +8464,13 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 0u;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 0u;
 loop {
   var_1 = 1u;
   var_1 = 2u;
@@ -8645,11 +8482,11 @@
 var_1 = 999u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Loop_Unconditional_Body_MultiBlockContinue) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -8679,13 +8516,13 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 0u;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 0u;
 loop {
   var_1 = 1u;
   var_1 = 2u;
@@ -8698,11 +8535,11 @@
 var_1 = 999u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Loop_Unconditional_Body_ContinueNestIf) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -8737,13 +8574,13 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 0u;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 0u;
 loop {
   var_1 = 1u;
   var_1 = 2u;
@@ -8759,12 +8596,12 @@
 var_1 = 999u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Loop_MultiBlockContinueIsEntireLoop) {
-  // Test case where both branches exit. e.g both go to merge.
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    // Test case where both branches exit. e.g both go to merge.
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -8786,12 +8623,12 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 0u;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 0u;
 loop {
   var_1 = 1u;
   var_1 = 2u;
@@ -8802,12 +8639,12 @@
 var_1 = 3u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Loop_Never) {
-  // Test case where both branches exit. e.g both go to merge.
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    // Test case where both branches exit. e.g both go to merge.
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -8828,12 +8665,12 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(loop {
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(loop {
   var_1 = 1u;
   break;
 
@@ -8844,19 +8681,19 @@
 var_1 = 3u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Loop_HeaderBreakAndContinue) {
-  // Header block branches to merge, and to an outer continue.
-  // This is disallowed by the rule:
-  //    "a continue block is valid only for the innermost loop it is nested
-  //    inside of"
-  // See test ClassifyCFGEdges_LoopContinue_FromNestedLoopHeader_IsError
+    // Header block branches to merge, and to an outer continue.
+    // This is disallowed by the rule:
+    //    "a continue block is valid only for the innermost loop it is nested
+    //    inside of"
+    // See test ClassifyCFGEdges_LoopContinue_FromNestedLoopHeader_IsError
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Loop_TrueToBody_FalseBreaks) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -8881,12 +8718,12 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(loop {
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(loop {
   var_1 = 1u;
   if (false) {
   } else {
@@ -8901,11 +8738,11 @@
 var_1 = 4u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Loop_FalseToBody_TrueBreaks) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -8930,12 +8767,12 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(loop {
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(loop {
   var_1 = 1u;
   if (false) {
   } else {
@@ -8950,12 +8787,12 @@
 var_1 = 4u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Loop_NestedIfContinue) {
-  // By construction, it has to come from nested code.
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    // By construction, it has to come from nested code.
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -8986,12 +8823,12 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(loop {
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(loop {
   if (false) {
     var_1 = 1u;
     continue;
@@ -9004,11 +8841,11 @@
 }
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Loop_BodyAlwaysBreaks) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -9031,13 +8868,13 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(loop {
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(loop {
   var_1 = 1u;
   break;
 
@@ -9047,13 +8884,13 @@
 }
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Loop_BodyConditionallyBreaks_FromTrue) {
-  // The else-branch has a continue but it's skipped because it's from a
-  // block that immediately precedes the continue construct.
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    // The else-branch has a continue but it's skipped because it's from a
+    // block that immediately precedes the continue construct.
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -9076,13 +8913,13 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(loop {
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(loop {
   var_1 = 1u;
   if (false) {
     break;
@@ -9094,13 +8931,13 @@
 }
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Loop_BodyConditionallyBreaks_FromFalse) {
-  // The else-branch has a continue but it's skipped because it's from a
-  // block that immediately precedes the continue construct.
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    // The else-branch has a continue but it's skipped because it's from a
+    // block that immediately precedes the continue construct.
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -9123,13 +8960,13 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(loop {
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(loop {
   var_1 = 1u;
   if (false) {
   } else {
@@ -9142,11 +8979,11 @@
 }
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Loop_BodyConditionallyBreaks_FromTrue_Early) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -9173,13 +9010,13 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(loop {
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(loop {
   var_1 = 1u;
   if (false) {
     break;
@@ -9192,12 +9029,11 @@
 }
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
-TEST_F(SpvParserCFGTest,
-       EmitBody_Loop_BodyConditionallyBreaks_FromFalse_Early) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, EmitBody_Loop_BodyConditionallyBreaks_FromFalse_Early) {
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -9224,13 +9060,13 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(loop {
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(loop {
   var_1 = 1u;
   if (false) {
   } else {
@@ -9244,11 +9080,11 @@
 }
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Switch_DefaultIsMerge_NoCases) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -9262,13 +9098,13 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 1u;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 1u;
 switch(42u) {
   default: {
   }
@@ -9276,12 +9112,12 @@
 var_1 = 7u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 // First do no special control flow: no fallthroughs, breaks, continues.
 TEST_F(SpvParserCFGTest, EmitBody_Switch_DefaultIsMerge_OneCase) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -9299,13 +9135,13 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 1u;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 1u;
 switch(42u) {
   case 20u: {
     var_1 = 20u;
@@ -9316,11 +9152,11 @@
 var_1 = 7u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Switch_DefaultIsMerge_TwoCases) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -9342,13 +9178,13 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 1u;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 1u;
 switch(42u) {
   case 30u: {
     var_1 = 30u;
@@ -9362,11 +9198,11 @@
 var_1 = 7u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Switch_DefaultIsMerge_CasesWithDup) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -9388,13 +9224,13 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 1u;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 1u;
 switch(42u) {
   case 30u: {
     var_1 = 30u;
@@ -9408,13 +9244,13 @@
 var_1 = 7u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Switch_DefaultIsCase_NoDupCases) {
-  // The default block is not the merge block. But not the same as a case
-  // either.
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    // The default block is not the merge block. But not the same as a case
+    // either.
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -9440,13 +9276,13 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 1u;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 1u;
 switch(42u) {
   case 40u: {
     var_1 = 40u;
@@ -9461,14 +9297,14 @@
 var_1 = 7u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Switch_DefaultIsCase_WithDupCase) {
-  // The default block is not the merge block and is the same as a case.
-  // We emit the default case separately, but just before the labeled
-  // case, and with a fallthrough.
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    // The default block is not the merge block and is the same as a case.
+    // We emit the default case separately, but just before the labeled
+    // case, and with a fallthrough.
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -9494,13 +9330,13 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 1u;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 1u;
 switch(42u) {
   case 40u: {
     var_1 = 40u;
@@ -9518,11 +9354,11 @@
 var_1 = 7u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Switch_Case_SintValue) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -9549,21 +9385,21 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 1u;
-switch(42) {
-  case -294967296: {
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 1u;
+switch(42i) {
+  case -294967296i: {
     var_1 = 40u;
   }
-  case 2000000000: {
+  case 2000000000i: {
     var_1 = 30u;
   }
-  case 20: {
+  case 20i: {
     var_1 = 20u;
   }
   default: {
@@ -9572,11 +9408,11 @@
 var_1 = 7u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Switch_Case_UintValue) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -9602,13 +9438,13 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 1u;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 1u;
 switch(42u) {
   case 50u: {
     var_1 = 40u;
@@ -9625,11 +9461,11 @@
 var_1 = 7u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Return_TopLevel) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -9637,19 +9473,19 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(return;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Return_InsideIf) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -9664,22 +9500,22 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(if (false) {
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(if (false) {
   return;
 }
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Return_InsideLoop) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -9700,22 +9536,22 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(loop {
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(loop {
   return;
 }
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_ReturnValue_TopLevel) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %200 = OpFunction %uint None %uintfn
 
      %210 = OpLabel
@@ -9731,19 +9567,19 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(200);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(200);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(return 2u;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(return 2u;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_ReturnValue_InsideIf) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %200 = OpFunction %uint None %uintfn
 
      %210 = OpLabel
@@ -9767,22 +9603,22 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(200);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(200);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(if (false) {
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(if (false) {
   return 2u;
 }
 return 3u;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_ReturnValue_Loop) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %200 = OpFunction %uint None %uintfn
 
      %210 = OpLabel
@@ -9812,22 +9648,22 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(200);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(200);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(loop {
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(loop {
   return 2u;
 }
 return 3u;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Kill_TopLevel) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -9835,19 +9671,19 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(discard;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(discard;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Kill_InsideIf) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -9862,22 +9698,22 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(if (false) {
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(if (false) {
   discard;
 }
 discard;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Kill_InsideLoop) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -9898,22 +9734,22 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(loop {
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(loop {
   discard;
 }
 discard;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Unreachable_TopLevel) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -9921,19 +9757,19 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(return;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Unreachable_InsideIf) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -9948,22 +9784,22 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(if (false) {
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(if (false) {
   return;
 }
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Unreachable_InsideLoop) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -9984,22 +9820,22 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(loop {
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(loop {
   return;
 }
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Unreachable_InNonVoidFunction) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %200 = OpFunction %uint None %uintfn
 
      %210 = OpLabel
@@ -10015,19 +9851,19 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(200);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(200);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(return 0u;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(return 0u;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Branch_BackEdge_MultiBlockLoop) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -10046,13 +9882,13 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(loop {
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(loop {
 
   continuing {
     var_1 = 1u;
@@ -10060,11 +9896,11 @@
 }
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Branch_BackEdge_SingleBlockLoop) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -10080,24 +9916,24 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(loop {
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(loop {
   var_1 = 1u;
 }
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Branch_SwitchBreak_LastInCase) {
-  // When the break is last in its case, we omit it because it's implicit in
-  // WGSL.
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    // When the break is last in its case, we omit it because it's implicit in
+    // WGSL.
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -10115,13 +9951,13 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 1u;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 1u;
 switch(42u) {
   case 20u: {
     var_1 = 20u;
@@ -10132,12 +9968,12 @@
 var_1 = 7u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Branch_SwitchBreak_NotLastInCase) {
-  // When the break is not last in its case, we must emit a 'break'
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    // When the break is not last in its case, we must emit a 'break'
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -10164,13 +10000,13 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 1u;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 1u;
 switch(42u) {
   case 20u: {
     var_1 = 20u;
@@ -10186,11 +10022,11 @@
 var_1 = 7u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Branch_LoopBreak_MultiBlockLoop_FromBody) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -10213,13 +10049,13 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(loop {
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(loop {
   var_1 = 1u;
   break;
 
@@ -10229,15 +10065,14 @@
 }
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
-TEST_F(
-    SpvParserCFGTest,
-    EmitBody_Branch_LoopBreak_MultiBlockLoop_FromContinueConstructConditional) {
-  // This case is invalid because the backedge block doesn't post-dominate the
-  // continue target.
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+TEST_F(SpvParserCFGTest,
+       EmitBody_Branch_LoopBreak_MultiBlockLoop_FromContinueConstructConditional) {
+    // This case is invalid because the backedge block doesn't post-dominate the
+    // continue target.
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -10262,19 +10097,19 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(fe.EmitBody()) << p->error();
-  EXPECT_THAT(p->error(),
-              Eq("Invalid exit (40->99) from continue construct: 40 is not the "
-                 "last block in the continue construct starting at 30 "
-                 "(violates post-dominance rule)"));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(fe.EmitBody()) << p->error();
+    EXPECT_THAT(p->error(), Eq("Invalid exit (40->99) from continue construct: 40 is not the "
+                               "last block in the continue construct starting at 30 "
+                               "(violates post-dominance rule)"));
 }
 
-TEST_F(
-    SpvParserCFGTest,
-    EmitBody_Branch_LoopBreak_MultiBlockLoop_FromContinueConstructEnd_Unconditional) {  // NOLINT - line length
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+TEST_F(SpvParserCFGTest,
+       EmitBody_Branch_LoopBreak_MultiBlockLoop_FromContinueConstructEnd_Unconditional) {  // NOLINT
+                                                                                           // - line
+                                                                                           // length
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -10297,14 +10132,14 @@
      OpFunctionEnd
   )"));
 
-  p->DeliberatelyInvalidSpirv();
+    p->DeliberatelyInvalidSpirv();
 
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(loop {
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(loop {
 
   continuing {
     var_1 = 1u;
@@ -10313,13 +10148,14 @@
 }
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(
     SpvParserCFGTest,
-    EmitBody_Branch_LoopBreak_MultiBlockLoop_FromContinueConstructEnd_Conditional) {  // NOLINT - line length
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    EmitBody_Branch_LoopBreak_MultiBlockLoop_FromContinueConstructEnd_Conditional) {  // NOLINT -
+                                                                                      // line length
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -10338,12 +10174,12 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(loop {
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(loop {
 
   continuing {
     var_1 = 1u;
@@ -10355,11 +10191,11 @@
 }
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Branch_LoopContinue_LastInLoopConstruct) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -10382,12 +10218,12 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(loop {
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(loop {
   var_1 = 1u;
 
   continuing {
@@ -10396,12 +10232,12 @@
 }
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Branch_LoopContinue_BeforeLast) {
-  // By construction, it has to come from nested code.
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    // By construction, it has to come from nested code.
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -10432,12 +10268,12 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(loop {
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(loop {
   if (false) {
     var_1 = 1u;
     continue;
@@ -10450,11 +10286,11 @@
 }
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Branch_LoopContinue_FromSwitch) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -10489,12 +10325,12 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 1u;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 1u;
 loop {
   var_1 = 2u;
   var_1 = 3u;
@@ -10515,12 +10351,12 @@
 var_1 = 7u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Branch_IfBreak_FromThen) {
-  // When unconditional, the if-break must be last in the then clause.
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    // When unconditional, the if-break must be last in the then clause.
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -10537,23 +10373,23 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(if (false) {
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(if (false) {
   var_1 = 1u;
 }
 var_1 = 2u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Branch_IfBreak_FromElse) {
-  // When unconditional, the if-break must be last in the else clause.
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    // When unconditional, the if-break must be last in the else clause.
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -10570,23 +10406,23 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(if (false) {
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(if (false) {
 } else {
   var_1 = 1u;
 }
 var_1 = 2u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Branch_Fallthrough) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -10608,13 +10444,13 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 1u;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 1u;
 switch(42u) {
   case 20u: {
     var_1 = 20u;
@@ -10629,11 +10465,11 @@
 var_1 = 7u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_Branch_Forward) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -10646,16 +10482,16 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 1u;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 1u;
 var_1 = 2u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 // Test matrix for normal OpBranchConditional:
@@ -10727,7 +10563,7 @@
 //      kForward: dup general case
 
 TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_Back_SingleBlock_Back) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -10745,24 +10581,23 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 0u;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 0u;
 loop {
   var_1 = 1u;
 }
 var_1 = 5u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
-TEST_F(SpvParserCFGTest,
-       EmitBody_BranchConditional_Back_SingleBlock_LoopBreak_OnTrue) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_Back_SingleBlock_LoopBreak_OnTrue) {
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -10780,12 +10615,12 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 0u;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 0u;
 loop {
   var_1 = 1u;
   if (false) {
@@ -10795,12 +10630,11 @@
 var_1 = 5u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
-TEST_F(SpvParserCFGTest,
-       EmitBody_BranchConditional_Back_SingleBlock_LoopBreak_OnFalse) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_Back_SingleBlock_LoopBreak_OnFalse) {
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -10818,12 +10652,12 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 0u;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 0u;
 loop {
   var_1 = 1u;
   if (false) {
@@ -10834,12 +10668,11 @@
 var_1 = 5u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
-TEST_F(SpvParserCFGTest,
-       EmitBody_BranchConditional_Back_MultiBlock_LoopBreak_OnTrue) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_Back_MultiBlock_LoopBreak_OnTrue) {
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -10860,12 +10693,12 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 0u;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 0u;
 loop {
   var_1 = 1u;
 
@@ -10878,12 +10711,11 @@
 var_1 = 5u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
-TEST_F(SpvParserCFGTest,
-       EmitBody_BranchConditional_Back_MultiBlock_LoopBreak_OnFalse) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_Back_MultiBlock_LoopBreak_OnFalse) {
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -10904,12 +10736,12 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 0u;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 0u;
 loop {
   var_1 = 1u;
 
@@ -10923,14 +10755,13 @@
 var_1 = 5u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
-TEST_F(SpvParserCFGTest,
-       EmitBody_BranchConditional_SwitchBreak_SwitchBreak_LastInCase) {
-  // When the break is last in its case, we omit it because it's implicit in
-  // WGSL.
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_SwitchBreak_SwitchBreak_LastInCase) {
+    // When the break is last in its case, we omit it because it's implicit in
+    // WGSL.
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -10948,13 +10779,13 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 1u;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 1u;
 switch(42u) {
   case 20u: {
     var_1 = 20u;
@@ -10965,13 +10796,12 @@
 var_1 = 7u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
-TEST_F(SpvParserCFGTest,
-       EmitBody_BranchConditional_SwitchBreak_SwitchBreak_NotLastInCase) {
-  // When the break is not last in its case, we must emit a 'break'
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_SwitchBreak_SwitchBreak_NotLastInCase) {
+    // When the break is not last in its case, we must emit a 'break'
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -10998,13 +10828,13 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 1u;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 1u;
 switch(42u) {
   case 20u: {
     var_1 = 20u;
@@ -11020,12 +10850,11 @@
 var_1 = 7u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
-TEST_F(SpvParserCFGTest,
-       EmitBody_BranchConditional_SwitchBreak_Continue_OnTrue) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_SwitchBreak_Continue_OnTrue) {
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -11060,13 +10889,13 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 1u;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 1u;
 loop {
   var_1 = 2u;
   var_1 = 3u;
@@ -11089,12 +10918,11 @@
 var_1 = 8u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
-TEST_F(SpvParserCFGTest,
-       EmitBody_BranchConditional_SwitchBreak_Continue_OnFalse) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_SwitchBreak_Continue_OnFalse) {
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -11129,13 +10957,13 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 1u;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 1u;
 loop {
   var_1 = 2u;
   var_1 = 3u;
@@ -11159,12 +10987,11 @@
 var_1 = 8u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
-TEST_F(SpvParserCFGTest,
-       EmitBody_BranchConditional_SwitchBreak_Forward_OnTrue) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_SwitchBreak_Forward_OnTrue) {
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -11186,12 +11013,12 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 1u;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 1u;
 switch(42u) {
   case 20u: {
     var_1 = 20u;
@@ -11207,12 +11034,11 @@
 var_1 = 8u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
-TEST_F(SpvParserCFGTest,
-       EmitBody_BranchConditional_SwitchBreak_Forward_OnFalse) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_SwitchBreak_Forward_OnFalse) {
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -11234,12 +11060,12 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 1u;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 1u;
 switch(42u) {
   case 20u: {
     var_1 = 20u;
@@ -11254,12 +11080,11 @@
 var_1 = 8u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
-TEST_F(SpvParserCFGTest,
-       EmitBody_BranchConditional_SwitchBreak_Fallthrough_OnTrue) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_SwitchBreak_Fallthrough_OnTrue) {
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -11281,13 +11106,13 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 1u;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 1u;
 switch(42u) {
   case 20u: {
     var_1 = 20u;
@@ -11306,12 +11131,11 @@
 var_1 = 7u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
-TEST_F(SpvParserCFGTest,
-       EmitBody_BranchConditional_SwitchBreak_Fallthrough_OnFalse) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_SwitchBreak_Fallthrough_OnFalse) {
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -11333,13 +11157,13 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 1u;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 1u;
 switch(42u) {
   case 20u: {
     var_1 = 20u;
@@ -11357,12 +11181,11 @@
 var_1 = 7u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
-TEST_F(SpvParserCFGTest,
-       EmitBody_BranchConditional_LoopBreak_SingleBlock_LoopBreak) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_LoopBreak_SingleBlock_LoopBreak) {
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -11384,12 +11207,12 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 0u;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 0u;
 loop {
   var_1 = 1u;
   break;
@@ -11401,12 +11224,11 @@
 var_1 = 5u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
-TEST_F(SpvParserCFGTest,
-       EmitBody_BranchConditional_LoopBreak_MultiBlock_LoopBreak) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_LoopBreak_MultiBlock_LoopBreak) {
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -11432,12 +11254,12 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 0u;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 0u;
 loop {
   var_1 = 1u;
   var_1 = 2u;
@@ -11450,11 +11272,11 @@
 var_1 = 5u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_LoopBreak_Continue_OnTrue) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -11492,12 +11314,12 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 0u;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 0u;
 loop {
   var_1 = 1u;
   if (true) {
@@ -11517,12 +11339,11 @@
 var_1 = 5u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
-TEST_F(SpvParserCFGTest,
-       EmitBody_BranchConditional_LoopBreak_Continue_OnFalse) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_LoopBreak_Continue_OnFalse) {
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -11560,12 +11381,12 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 0u;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 0u;
 loop {
   var_1 = 1u;
   if (true) {
@@ -11585,13 +11406,12 @@
 var_1 = 5u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
-TEST_F(SpvParserCFGTest,
-       EmitBody_BranchConditional_LoopBreak_Fallthrough_IsError) {
-  // It's an error because switch break conflicts with loop break.
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_LoopBreak_Fallthrough_IsError) {
+    // It's an error because switch break conflicts with loop break.
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -11629,17 +11449,15 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(fe.EmitBody()) << p->error();
-  EXPECT_THAT(
-      p->error(),
-      Eq("Branch from block 40 to block 99 is an invalid exit from construct "
-         "starting at block 30; branch bypasses merge block 79"));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(fe.EmitBody()) << p->error();
+    EXPECT_THAT(p->error(), Eq("Branch from block 40 to block 99 is an invalid exit from construct "
+                               "starting at block 30; branch bypasses merge block 79"));
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_LoopBreak_Forward_OnTrue) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -11670,12 +11488,12 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 0u;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 0u;
 loop {
   var_1 = 1u;
   var_1 = 2u;
@@ -11692,11 +11510,11 @@
 var_1 = 5u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_LoopBreak_Forward_OnFalse) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -11727,12 +11545,12 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 0u;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 0u;
 loop {
   var_1 = 1u;
   var_1 = 2u;
@@ -11748,12 +11566,11 @@
 var_1 = 5u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
-TEST_F(SpvParserCFGTest,
-       EmitBody_BranchConditional_Continue_Continue_FromHeader) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_Continue_Continue_FromHeader) {
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -11775,12 +11592,12 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 0u;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 0u;
 loop {
   var_1 = 1u;
 
@@ -11791,12 +11608,11 @@
 var_1 = 5u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
-TEST_F(SpvParserCFGTest,
-       EmitBody_BranchConditional_Continue_Continue_AfterHeader_Unconditional) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_Continue_Continue_AfterHeader_Unconditional) {
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -11822,12 +11638,12 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 0u;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 0u;
 loop {
   var_1 = 1u;
   var_1 = 2u;
@@ -11839,14 +11655,13 @@
 var_1 = 5u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
-TEST_F(SpvParserCFGTest,
-       EmitBody_BranchConditional_Continue_Continue_AfterHeader_Conditional) {
-  // Create an intervening block so we actually require a "continue" statement
-  // instead of just an adjacent fallthrough to the continue target.
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_Continue_Continue_AfterHeader_Conditional) {
+    // Create an intervening block so we actually require a "continue" statement
+    // instead of just an adjacent fallthrough to the continue target.
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -11881,12 +11696,12 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 0u;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 0u;
 loop {
   var_1 = 1u;
   var_1 = 2u;
@@ -11903,14 +11718,14 @@
 var_1 = 6u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(
     SpvParserCFGTest,
     EmitBody_BranchConditional_Continue_Continue_AfterHeader_Conditional_EmptyContinuing) {  // NOLINT
-  // Like the previous tests, but with an empty continuing clause.
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    // Like the previous tests, but with an empty continuing clause.
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -11945,12 +11760,12 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 0u;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 0u;
 loop {
   var_1 = 1u;
   var_1 = 2u;
@@ -11963,11 +11778,11 @@
 var_1 = 6u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_LoopContinue_FromSwitch) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -12002,12 +11817,12 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 1u;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 1u;
 loop {
   var_1 = 2u;
   var_1 = 3u;
@@ -12028,11 +11843,11 @@
 var_1 = 7u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_Continue_IfBreak_OnTrue) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -12068,12 +11883,12 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 0u;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 0u;
 loop {
   var_1 = 1u;
   var_1 = 2u;
@@ -12093,11 +11908,11 @@
 var_1 = 6u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_Continue_IfBreak_OnFalse) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -12133,12 +11948,12 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 0u;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 0u;
 loop {
   var_1 = 1u;
   var_1 = 2u;
@@ -12157,12 +11972,11 @@
 var_1 = 6u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
-TEST_F(SpvParserCFGTest,
-       EmitBody_BranchConditional_Continue_Fallthrough_OnTrue) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_Continue_Fallthrough_OnTrue) {
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -12201,12 +12015,12 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 0u;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 0u;
 loop {
   var_1 = 1u;
   var_1 = 2u;
@@ -12234,12 +12048,11 @@
 var_1 = 5u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
-TEST_F(SpvParserCFGTest,
-       EmitBody_BranchConditional_Continue_Fallthrough_OnFalse) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_Continue_Fallthrough_OnFalse) {
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -12278,12 +12091,12 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 0u;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 0u;
 loop {
   var_1 = 1u;
   var_1 = 2u;
@@ -12310,11 +12123,11 @@
 var_1 = 5u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_Continue_Forward_OnTrue) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -12345,12 +12158,12 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 0u;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 0u;
 loop {
   var_1 = 1u;
   var_1 = 2u;
@@ -12367,11 +12180,11 @@
 var_1 = 5u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_Continue_Forward_OnFalse) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -12402,12 +12215,12 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 0u;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 0u;
 loop {
   var_1 = 1u;
   var_1 = 2u;
@@ -12423,11 +12236,11 @@
 var_1 = 5u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_IfBreak_IfBreak_Same) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -12445,23 +12258,22 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 0u;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 0u;
 if (false) {
 }
 var_1 = 5u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
-TEST_F(SpvParserCFGTest,
-       EmitBody_BranchConditional_IfBreak_IfBreak_DifferentIsError) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_IfBreak_IfBreak_DifferentIsError) {
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -12487,18 +12299,15 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
-  EXPECT_THAT(
-      p->error(),
-      Eq("Branch from block 30 to block 99 is an invalid exit from construct "
-         "starting at block 20; branch bypasses merge block 89"));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(FlowClassifyCFGEdges(&fe));
+    EXPECT_THAT(p->error(), Eq("Branch from block 30 to block 99 is an invalid exit from construct "
+                               "starting at block 20; branch bypasses merge block 89"));
 }
 
-TEST_F(SpvParserCFGTest,
-       EmitBody_BranchConditional_Fallthrough_Fallthrough_Same) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_Fallthrough_Fallthrough_Same) {
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -12520,13 +12329,13 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 1u;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 1u;
 switch(42u) {
   case 20u: {
     var_1 = 20u;
@@ -12541,14 +12350,13 @@
 var_1 = 7u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
-TEST_F(SpvParserCFGTest,
-       EmitBody_BranchConditional_Fallthrough_NotLastInCase_IsError) {
-  // See also
-  // ClassifyCFGEdges_Fallthrough_BranchConditionalWith_Forward_IsError.
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_Fallthrough_NotLastInCase_IsError) {
+    // See also
+    // ClassifyCFGEdges_Fallthrough_BranchConditionalWith_Forward_IsError.
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -12573,19 +12381,18 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(fe.EmitBody());
-  // The weird forward branch pulls in 40 as part of the selection rather than
-  // as a case.
-  EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 40, 30, 39, 99));
-  EXPECT_THAT(
-      p->error(),
-      Eq("Branch from 10 to 40 bypasses header 20 (dominance rule violated)"));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(fe.EmitBody());
+    // The weird forward branch pulls in 40 as part of the selection rather than
+    // as a case.
+    EXPECT_THAT(fe.block_order(), ElementsAre(10, 20, 40, 30, 39, 99));
+    EXPECT_THAT(p->error(),
+                Eq("Branch from 10 to 40 bypasses header 20 (dominance rule violated)"));
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_Forward_Forward_Same) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -12598,21 +12405,20 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 1u;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 1u;
 var_1 = 2u;
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
-TEST_F(SpvParserCFGTest,
-       EmitBody_BranchConditional_Forward_Forward_Different_IsError) {
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, EmitBody_BranchConditional_Forward_Forward_Different_IsError) {
+    auto p = parser(test::Assemble(CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -12627,16 +12433,15 @@
 
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(fe.EmitBody());
-  EXPECT_THAT(p->error(),
-              Eq("Control flow diverges at block 10 (to 20, 99) but it is not "
-                 "a structured header (it has no merge instruction)"));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(fe.EmitBody());
+    EXPECT_THAT(p->error(), Eq("Control flow diverges at block 10 (to 20, 99) but it is not "
+                               "a structured header (it has no merge instruction)"));
 }
 
 TEST_F(SpvParserCFGTest, Switch_NotAsSelectionHeader_Simple) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -12647,20 +12452,17 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(fe.EmitBody());
-  EXPECT_THAT(
-      p->error(),
-      HasSubstr("invalid structured control flow: found an OpSwitch that "
-                "is not preceded by an OpSelectionMerge:"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(fe.EmitBody());
+    EXPECT_THAT(p->error(), HasSubstr("invalid structured control flow: found an OpSwitch that "
+                                      "is not preceded by an OpSelectionMerge:"));
 }
 
-TEST_F(SpvParserCFGTest,
-       Switch_NotAsSelectionHeader_NonDefaultBranchesAreContinue) {
-  // Adapted from SPIRV-Tools test MissingMergeOneUnseenTargetSwitchBad
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, Switch_NotAsSelectionHeader_NonDefaultBranchesAreContinue) {
+    // Adapted from SPIRV-Tools test MissingMergeOneUnseenTargetSwitchBad
+    auto p = parser(test::Assemble(CommonTypes() + R"(
  %100 = OpFunction %void None %voidfn
  %entry = OpLabel
  OpBranch %loop
@@ -12684,18 +12486,16 @@
  OpReturn
  OpFunctionEnd
    )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(fe.EmitBody());
-  EXPECT_THAT(
-      p->error(),
-      HasSubstr("invalid structured control flow: found an OpSwitch that "
-                "is not preceded by an OpSelectionMerge:"));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(fe.EmitBody());
+    EXPECT_THAT(p->error(), HasSubstr("invalid structured control flow: found an OpSwitch that "
+                                      "is not preceded by an OpSelectionMerge:"));
 }
 
 TEST_F(SpvParserCFGTest, Switch_NotAsSelectionHeader_DefaultBranchIsContinue) {
-  // Adapted from SPIRV-Tools test MissingMergeOneUnseenTargetSwitchBad
-  auto p = parser(test::Assemble(CommonTypes() + R"(
+    // Adapted from SPIRV-Tools test MissingMergeOneUnseenTargetSwitchBad
+    auto p = parser(test::Assemble(CommonTypes() + R"(
  %100 = OpFunction %void None %voidfn
  %entry = OpLabel
  OpBranch %loop
@@ -12719,30 +12519,28 @@
  OpReturn
  OpFunctionEnd
    )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(fe.EmitBody());
-  EXPECT_THAT(
-      p->error(),
-      HasSubstr("invalid structured control flow: found an OpSwitch that "
-                "is not preceded by an OpSelectionMerge:"));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(fe.EmitBody());
+    EXPECT_THAT(p->error(), HasSubstr("invalid structured control flow: found an OpSwitch that "
+                                      "is not preceded by an OpSelectionMerge:"));
 }
 
 TEST_F(SpvParserCFGTest, SiblingLoopConstruct_Null) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
      %10 = OpLabel
      OpReturn
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_EQ(fe.SiblingLoopConstruct(nullptr), nullptr);
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_EQ(fe.SiblingLoopConstruct(nullptr), nullptr);
 }
 
 TEST_F(SpvParserCFGTest, SiblingLoopConstruct_NotAContinue) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -12750,17 +12548,17 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  ASSERT_TRUE(FlowLabelControlFlowConstructs(&fe)) << p->error();
-  const Construct* c = fe.GetBlockInfo(10)->construct;
-  EXPECT_NE(c, nullptr);
-  EXPECT_EQ(fe.SiblingLoopConstruct(c), nullptr);
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    ASSERT_TRUE(FlowLabelControlFlowConstructs(&fe)) << p->error();
+    const Construct* c = fe.GetBlockInfo(10)->construct;
+    EXPECT_NE(c, nullptr);
+    EXPECT_EQ(fe.SiblingLoopConstruct(c), nullptr);
 }
 
 TEST_F(SpvParserCFGTest, SiblingLoopConstruct_SingleBlockLoop) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -12775,17 +12573,17 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  ASSERT_TRUE(FlowLabelControlFlowConstructs(&fe)) << p->error();
-  const Construct* c = fe.GetBlockInfo(20)->construct;
-  EXPECT_EQ(c->kind, Construct::kContinue);
-  EXPECT_EQ(fe.SiblingLoopConstruct(c), nullptr);
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    ASSERT_TRUE(FlowLabelControlFlowConstructs(&fe)) << p->error();
+    const Construct* c = fe.GetBlockInfo(20)->construct;
+    EXPECT_EQ(c->kind, Construct::kContinue);
+    EXPECT_EQ(fe.SiblingLoopConstruct(c), nullptr);
 }
 
 TEST_F(SpvParserCFGTest, SiblingLoopConstruct_ContinueIsWholeMultiBlockLoop) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -12803,18 +12601,17 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << p->error() << assembly;
-  auto fe = p->function_emitter(100);
-  ASSERT_TRUE(FlowLabelControlFlowConstructs(&fe)) << p->error();
-  const Construct* c = fe.GetBlockInfo(20)->construct;
-  EXPECT_EQ(c->kind, Construct::kContinue);
-  EXPECT_EQ(fe.SiblingLoopConstruct(c), nullptr);
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << assembly;
+    auto fe = p->function_emitter(100);
+    ASSERT_TRUE(FlowLabelControlFlowConstructs(&fe)) << p->error();
+    const Construct* c = fe.GetBlockInfo(20)->construct;
+    EXPECT_EQ(c->kind, Construct::kContinue);
+    EXPECT_EQ(fe.SiblingLoopConstruct(c), nullptr);
 }
 
 TEST_F(SpvParserCFGTest, SiblingLoopConstruct_HasSiblingLoop) {
-  auto assembly = CommonTypes() + R"(
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -12832,20 +12629,20 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  ASSERT_TRUE(FlowLabelControlFlowConstructs(&fe)) << p->error();
-  const Construct* c = fe.GetBlockInfo(30)->construct;
-  EXPECT_EQ(c->kind, Construct::kContinue);
-  EXPECT_THAT(ToString(fe.SiblingLoopConstruct(c)),
-              Eq("Construct{ Loop [1,2) begin_id:20 end_id:30 depth:1 "
-                 "parent:Function@10 scope:[1,3) in-l:Loop@20 }"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    ASSERT_TRUE(FlowLabelControlFlowConstructs(&fe)) << p->error();
+    const Construct* c = fe.GetBlockInfo(30)->construct;
+    EXPECT_EQ(c->kind, Construct::kContinue);
+    EXPECT_THAT(ToString(fe.SiblingLoopConstruct(c)),
+                Eq("Construct{ Loop [1,2) begin_id:20 end_id:30 depth:1 "
+                   "parent:Function@10 scope:[1,3) in-l:Loop@20 }"));
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_IfSelection_TrueBranch_LoopBreak) {
-  // crbug.com/tint/243
-  auto assembly = CommonTypes() + R"(
+    // crbug.com/tint/243
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %5 = OpLabel
@@ -12872,26 +12669,26 @@
      OpReturn
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(loop {
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(loop {
   if (false) {
     break;
   }
 }
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_TrueBranch_LoopContinue) {
-  // crbug.com/tint/243
-  auto assembly = CommonTypes() + R"(
+    // crbug.com/tint/243
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %5 = OpLabel
@@ -12919,25 +12716,25 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(loop {
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(loop {
   if (false) {
     continue;
   }
 }
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_TrueBranch_SwitchBreak) {
-  // crbug.com/tint/243
-  auto assembly = CommonTypes() + R"(
+    // crbug.com/tint/243
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -12959,13 +12756,13 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(switch(20u) {
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(switch(20u) {
   case 20u: {
     if (false) {
       break;
@@ -12976,12 +12773,12 @@
 }
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_FalseBranch_LoopBreak) {
-  // crbug.com/tint/243
-  auto assembly = CommonTypes() + R"(
+    // crbug.com/tint/243
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %5 = OpLabel
@@ -13009,13 +12806,13 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(loop {
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(loop {
   if (false) {
   } else {
     break;
@@ -13023,12 +12820,12 @@
 }
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_FalseBranch_LoopContinue) {
-  // crbug.com/tint/243
-  auto assembly = CommonTypes() + R"(
+    // crbug.com/tint/243
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %5 = OpLabel
@@ -13056,13 +12853,13 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(loop {
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(loop {
   if (false) {
   } else {
     continue;
@@ -13070,12 +12867,12 @@
 }
 return;
 )";
-  ASSERT_EQ(expect, got) << p->error();
+    ASSERT_EQ(expect, got) << p->error();
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_FalseBranch_SwitchBreak) {
-  // crbug.com/tint/243
-  auto assembly = CommonTypes() + R"(
+    // crbug.com/tint/243
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -13097,13 +12894,13 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(switch(20u) {
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(switch(20u) {
   case 20u: {
     if (false) {
     } else {
@@ -13115,12 +12912,12 @@
 }
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 TEST_F(SpvParserCFGTest, EmitBody_LoopInternallyDiverge_Simple) {
-  // crbug.com/tint/524
-  auto assembly = CommonTypes() + R"(
+    // crbug.com/tint/524
+    auto assembly = CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
      %10 = OpLabel
      OpStore %var %uint_10
@@ -13149,13 +12946,13 @@
 
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var_1 = 10u;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var_1 = 10u;
 loop {
   var_1 = 20u;
   if (false) {
@@ -13172,15 +12969,14 @@
 var_1 = 99u;
 return;
 )";
-  ASSERT_EQ(expect, got) << got;
+    ASSERT_EQ(expect, got) << got;
 }
 
-TEST_F(SpvParserCFGTest,
-       EmitBody_ContinueFromSingleBlockLoopToOuterLoop_IsError) {
-  // crbug.com/tint/793
-  // This is invalid SPIR-V but the validator was only recently upgraded
-  // to catch it.
-  auto assembly = CommonTypes() + R"(
+TEST_F(SpvParserCFGTest, EmitBody_ContinueFromSingleBlockLoopToOuterLoop_IsError) {
+    // crbug.com/tint/793
+    // This is invalid SPIR-V but the validator was only recently upgraded
+    // to catch it.
+    auto assembly = CommonTypes() + R"(
   %100 = OpFunction %void None %voidfn
   %5 = OpLabel
   OpBranch %10
@@ -13212,13 +13008,12 @@
   OpFunctionEnd
 
 )";
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_FALSE(p->Parse());
-  EXPECT_FALSE(p->success());
-  EXPECT_THAT(p->error(),
-              HasSubstr("block <ID> 20[%20] exits the continue headed by <ID> "
-                        "20[%20], but not via a structured exit"))
-      << p->error();
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_FALSE(p->Parse());
+    EXPECT_FALSE(p->success());
+    EXPECT_THAT(p->error(), HasSubstr("block <ID> 20[%20] exits the continue headed by <ID> "
+                                      "20[%20], but not via a structured exit"))
+        << p->error();
 }
 
 }  // namespace
diff --git a/src/tint/reader/spirv/function_composite_test.cc b/src/tint/reader/spirv/function_composite_test.cc
index 8b29a90..2e15743 100644
--- a/src/tint/reader/spirv/function_composite_test.cc
+++ b/src/tint/reader/spirv/function_composite_test.cc
@@ -24,7 +24,7 @@
 using ::testing::HasSubstr;
 
 std::string Caps() {
-  return R"(
+    return R"(
   OpCapability Shader
   OpMemoryModel Logical Simple
   OpEntryPoint GLCompute %100 "main"
@@ -33,7 +33,7 @@
 }
 
 std::string CommonTypes() {
-  return R"(
+    return R"(
   %void = OpTypeVoid
   %voidfn = OpTypeFunction %void
 
@@ -75,13 +75,13 @@
 }
 
 std::string Preamble() {
-  return Caps() + CommonTypes();
+    return Caps() + CommonTypes();
 }
 
 using SpvParserTest_Composite_Construct = SpvParserTest;
 
 TEST_F(SpvParserTest_Composite_Construct, Vector) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpCompositeConstruct %v2uint %uint_10 %uint_20
@@ -90,77 +90,74 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr(R"(let x_1 : vec2<u32> = vec2<u32>(10u, 20u);
-let x_2 : vec2<i32> = vec2<i32>(30, 40);
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr(R"(let x_1 : vec2<u32> = vec2<u32>(10u, 20u);
+let x_2 : vec2<i32> = vec2<i32>(30i, 40i);
 let x_3 : vec2<f32> = vec2<f32>(50.0, 60.0);
 )"));
 }
 
 TEST_F(SpvParserTest_Composite_Construct, Matrix) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpCompositeConstruct %m3v2float %v2float_50_60 %v2float_60_50 %v2float_70_70
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : mat3x2<f32> = mat3x2<f32>("
-                        "vec2<f32>(50.0, 60.0), "
-                        "vec2<f32>(60.0, 50.0), "
-                        "vec2<f32>(70.0, 70.0));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : mat3x2<f32> = mat3x2<f32>("
+                          "vec2<f32>(50.0, 60.0), "
+                          "vec2<f32>(60.0, 50.0), "
+                          "vec2<f32>(70.0, 70.0));"));
 }
 
 TEST_F(SpvParserTest_Composite_Construct, Array) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpCompositeConstruct %a_u_5 %uint_10 %uint_20 %uint_3 %uint_4 %uint_5
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(
-      test::ToString(p->program(), ast_body),
-      HasSubstr(
-          "let x_1 : array<u32, 5u> = array<u32, 5u>(10u, 20u, 3u, 4u, 5u);"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : array<u32, 5u> = array<u32, 5u>(10u, 20u, 3u, 4u, 5u);"));
 }
 
 TEST_F(SpvParserTest_Composite_Construct, Struct) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpCompositeConstruct %s_v2f_u_i %v2float_50_60 %uint_5 %int_30
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : S = S(vec2<f32>(50.0, 60.0), 5u, 30);"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : S = S(vec2<f32>(50.0, 60.0), 5u, 30i);"));
 }
 
-TEST_F(SpvParserTest_Composite_Construct,
-       ConstantComposite_Struct_NoDeduplication) {
-  const auto assembly = Preamble() + R"(
+TEST_F(SpvParserTest_Composite_Construct, ConstantComposite_Struct_NoDeduplication) {
+    const auto assembly = Preamble() + R"(
      %200 = OpTypeStruct %uint
      %300 = OpTypeStruct %uint ; isomorphic structures
 
@@ -174,58 +171,58 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto got = test::ToString(p->program(), ast_body);
-  const auto expected = std::string(
-      R"(let x_2 : S_1 = S_1(10u);
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto got = test::ToString(p->program(), ast_body);
+    const auto expected = std::string(
+        R"(let x_2 : S_1 = S_1(10u);
 let x_3 : S_2 = S_2(10u);
 return;
 )");
-  EXPECT_EQ(got, expected) << got;
+    EXPECT_EQ(got, expected) << got;
 }
 
 using SpvParserTest_CompositeExtract = SpvParserTest;
 
 TEST_F(SpvParserTest_CompositeExtract, Vector) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpCompositeExtract %float %v2float_50_60 1
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : f32 = vec2<f32>(50.0, 60.0).y;"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : f32 = vec2<f32>(50.0, 60.0).y;"));
 }
 
 TEST_F(SpvParserTest_CompositeExtract, Vector_IndexTooBigError) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpCompositeExtract %float %v2float_50_60 900
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(fe.EmitBody());
-  EXPECT_EQ(p->error(),
-            "OpCompositeExtract %1 index value 900 is out of bounds for vector "
-            "of 2 elements");
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(fe.EmitBody());
+    EXPECT_EQ(p->error(),
+              "OpCompositeExtract %1 index value 900 is out of bounds for vector "
+              "of 2 elements");
 }
 
 TEST_F(SpvParserTest_CompositeExtract, Matrix) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %ptr = OpTypePointer Function %m3v2float
 
      %100 = OpFunction %void None %voidfn
@@ -236,17 +233,17 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_2 : vec2<f32> = x_1[2u];"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_2 : vec2<f32> = x_1[2u];"));
 }
 
 TEST_F(SpvParserTest_CompositeExtract, Matrix_IndexTooBigError) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %ptr = OpTypePointer Function %m3v2float
 
      %100 = OpFunction %void None %voidfn
@@ -257,17 +254,17 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(fe.EmitBody()) << p->error();
-  EXPECT_EQ(p->error(),
-            "OpCompositeExtract %2 index value 3 is out of bounds for matrix "
-            "of 3 elements");
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(fe.EmitBody()) << p->error();
+    EXPECT_EQ(p->error(),
+              "OpCompositeExtract %2 index value 3 is out of bounds for matrix "
+              "of 3 elements");
 }
 
 TEST_F(SpvParserTest_CompositeExtract, Matrix_Vector) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %ptr = OpTypePointer Function %m3v2float
 
      %100 = OpFunction %void None %voidfn
@@ -278,17 +275,16 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_2 : f32 = x_1[2u].y;"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr("let x_2 : f32 = x_1[2u].y;"));
 }
 
 TEST_F(SpvParserTest_CompositeExtract, Array) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %ptr = OpTypePointer Function %a_u_5
 
      %100 = OpFunction %void None %voidfn
@@ -299,17 +295,16 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_2 : u32 = x_1[3u];"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr("let x_2 : u32 = x_1[3u];"));
 }
 
 TEST_F(SpvParserTest_CompositeExtract, RuntimeArray_IsError) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %rtarr = OpTypeRuntimeArray %uint
      %ptr = OpTypePointer Function %rtarr
 
@@ -321,16 +316,15 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(fe.EmitBody()) << p->error();
-  EXPECT_THAT(p->error(),
-              HasSubstr("can't do OpCompositeExtract on a runtime array: "));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(fe.EmitBody()) << p->error();
+    EXPECT_THAT(p->error(), HasSubstr("can't do OpCompositeExtract on a runtime array: "));
 }
 
 TEST_F(SpvParserTest_CompositeExtract, Struct) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %ptr = OpTypePointer Function %s_v2f_u_i
 
      %100 = OpFunction %void None %voidfn
@@ -341,17 +335,16 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_2 : i32 = x_1.field2;"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr("let x_2 : i32 = x_1.field2;"));
 }
 
 TEST_F(SpvParserTest_CompositeExtract, Struct_DifferOnlyInMemberName) {
-  const std::string assembly = R"(
+    const std::string assembly = R"(
      OpCapability Shader
      OpMemoryModel Logical Simple
      OpEntryPoint Fragment %100 "main"
@@ -381,23 +374,21 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto got = fe.ast_body();
-  auto program = p->program();
-  EXPECT_THAT(test::ToString(program, got),
-              HasSubstr("let x_2 : u32 = x_1.algo;"))
-      << test::ToString(program, got);
-  EXPECT_THAT(test::ToString(program, got),
-              HasSubstr("let x_4 : u32 = x_3.rithm;"))
-      << test::ToString(program, got);
-  p->SkipDumpingPending("crbug.com/tint/863");
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto got = fe.ast_body();
+    auto program = p->program();
+    EXPECT_THAT(test::ToString(program, got), HasSubstr("let x_2 : u32 = x_1.algo;"))
+        << test::ToString(program, got);
+    EXPECT_THAT(test::ToString(program, got), HasSubstr("let x_4 : u32 = x_3.rithm;"))
+        << test::ToString(program, got);
+    p->SkipDumpingPending("crbug.com/tint/863");
 }
 
 TEST_F(SpvParserTest_CompositeExtract, Struct_IndexTooBigError) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %ptr = OpTypePointer Function %s_v2f_u_i
 
      %100 = OpFunction %void None %voidfn
@@ -408,17 +399,17 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(fe.EmitBody());
-  EXPECT_EQ(p->error(),
-            "OpCompositeExtract %2 index value 40 is out of bounds for "
-            "structure %27 having 3 members");
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(fe.EmitBody());
+    EXPECT_EQ(p->error(),
+              "OpCompositeExtract %2 index value 40 is out of bounds for "
+              "structure %27 having 3 members");
 }
 
 TEST_F(SpvParserTest_CompositeExtract, Struct_Array_Matrix_Vector) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %a_mat = OpTypeArray %m3v2float %uint_3
      %s = OpTypeStruct %uint %a_mat
      %ptr = OpTypePointer Function %s
@@ -431,59 +422,59 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_2 : f32 = x_1.field1[2u][0u].y;"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_2 : f32 = x_1.field1[2u][0u].y;"));
 }
 
 using SpvParserTest_CompositeInsert = SpvParserTest;
 
 TEST_F(SpvParserTest_CompositeInsert, Vector) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpCompositeInsert %v2float %float_70 %v2float_50_60 1
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  const auto* expected =
-      R"(var x_1_1 : vec2<f32> = vec2<f32>(50.0, 60.0);
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    const auto* expected =
+        R"(var x_1_1 : vec2<f32> = vec2<f32>(50.0, 60.0);
 x_1_1.y = 70.0;
 let x_1 : vec2<f32> = x_1_1;
 return;
 )";
-  EXPECT_EQ(got, expected);
+    EXPECT_EQ(got, expected);
 }
 
 TEST_F(SpvParserTest_CompositeInsert, Vector_IndexTooBigError) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpCompositeInsert %v2float %float_70 %v2float_50_60 900
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(fe.EmitBody());
-  EXPECT_EQ(p->error(),
-            "OpCompositeInsert %1 index value 900 is out of bounds for vector "
-            "of 2 elements");
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(fe.EmitBody());
+    EXPECT_EQ(p->error(),
+              "OpCompositeInsert %1 index value 900 is out of bounds for vector "
+              "of 2 elements");
 }
 
 TEST_F(SpvParserTest_CompositeInsert, Matrix) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %ptr = OpTypePointer Function %m3v2float
 
      %100 = OpFunction %void None %voidfn
@@ -494,20 +485,20 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto body_str = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body_str, HasSubstr(R"(var x_2_1 : mat3x2<f32> = x_1;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto body_str = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body_str, HasSubstr(R"(var x_2_1 : mat3x2<f32> = x_1;
 x_2_1[2u] = vec2<f32>(50.0, 60.0);
 let x_2 : mat3x2<f32> = x_2_1;
 )")) << body_str;
 }
 
 TEST_F(SpvParserTest_CompositeInsert, Matrix_IndexTooBigError) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %ptr = OpTypePointer Function %m3v2float
 
      %100 = OpFunction %void None %voidfn
@@ -518,17 +509,17 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(fe.EmitBody()) << p->error();
-  EXPECT_EQ(p->error(),
-            "OpCompositeInsert %2 index value 3 is out of bounds for matrix of "
-            "3 elements");
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(fe.EmitBody()) << p->error();
+    EXPECT_EQ(p->error(),
+              "OpCompositeInsert %2 index value 3 is out of bounds for matrix of "
+              "3 elements");
 }
 
 TEST_F(SpvParserTest_CompositeInsert, Matrix_Vector) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %ptr = OpTypePointer Function %m3v2float
 
      %100 = OpFunction %void None %voidfn
@@ -539,13 +530,13 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto body_str = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body_str, HasSubstr(R"(var x_2_1 : mat3x2<f32> = x_1;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto body_str = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body_str, HasSubstr(R"(var x_2_1 : mat3x2<f32> = x_1;
 x_2_1[2u] = vec2<f32>(50.0, 60.0);
 let x_2 : mat3x2<f32> = x_2_1;
 return;
@@ -553,7 +544,7 @@
 }
 
 TEST_F(SpvParserTest_CompositeInsert, Array) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %ptr = OpTypePointer Function %a_u_5
 
      %100 = OpFunction %void None %voidfn
@@ -564,20 +555,20 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto body_str = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body_str, HasSubstr(R"(var x_2_1 : array<u32, 5u> = x_1;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto body_str = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body_str, HasSubstr(R"(var x_2_1 : array<u32, 5u> = x_1;
 x_2_1[3u] = 20u;
 let x_2 : array<u32, 5u> = x_2_1;
 )")) << body_str;
 }
 
 TEST_F(SpvParserTest_CompositeInsert, RuntimeArray_IsError) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %rtarr = OpTypeRuntimeArray %uint
      %ptr = OpTypePointer Function %rtarr
 
@@ -589,16 +580,15 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(fe.EmitBody()) << p->error();
-  EXPECT_THAT(p->error(),
-              HasSubstr("can't do OpCompositeInsert on a runtime array: "));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(fe.EmitBody()) << p->error();
+    EXPECT_THAT(p->error(), HasSubstr("can't do OpCompositeInsert on a runtime array: "));
 }
 
 TEST_F(SpvParserTest_CompositeInsert, Struct) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %ptr = OpTypePointer Function %s_v2f_u_i
 
      %100 = OpFunction %void None %voidfn
@@ -609,22 +599,22 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto body_str = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body_str, HasSubstr(R"(var x_36 : S;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto body_str = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body_str, HasSubstr(R"(var x_36 : S;
 let x_1 : S = x_36;
 var x_2_1 : S = x_1;
-x_2_1.field2 = 30;
+x_2_1.field2 = 30i;
 let x_2 : S = x_2_1;
 )")) << body_str;
 }
 
 TEST_F(SpvParserTest_CompositeInsert, Struct_DifferOnlyInMemberName) {
-  const std::string assembly = R"(
+    const std::string assembly = R"(
      OpCapability Shader
      OpMemoryModel Logical Simple
      OpEntryPoint Fragment %100 "main"
@@ -658,13 +648,13 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto got = test::ToString(p->program(), ast_body);
-  const std::string expected = R"(var var0 : S;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto got = test::ToString(p->program(), ast_body);
+    const std::string expected = R"(var var0 : S;
 var var1 : S_1;
 let x_1 : S = var0;
 var x_2_1 : S = x_1;
@@ -676,11 +666,11 @@
 let x_4 : S_1 = x_4_1;
 return;
 )";
-  EXPECT_EQ(got, expected) << got;
+    EXPECT_EQ(got, expected) << got;
 }
 
 TEST_F(SpvParserTest_CompositeInsert, Struct_IndexTooBigError) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %ptr = OpTypePointer Function %s_v2f_u_i
 
      %100 = OpFunction %void None %voidfn
@@ -691,17 +681,17 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(fe.EmitBody());
-  EXPECT_EQ(p->error(),
-            "OpCompositeInsert %2 index value 40 is out of bounds for "
-            "structure %27 having 3 members");
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(fe.EmitBody());
+    EXPECT_EQ(p->error(),
+              "OpCompositeInsert %2 index value 40 is out of bounds for "
+              "structure %27 having 3 members");
 }
 
 TEST_F(SpvParserTest_CompositeInsert, Struct_Array_Matrix_Vector) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %a_mat = OpTypeArray %m3v2float %uint_3
      %s = OpTypeStruct %uint %a_mat
      %ptr = OpTypePointer Function %s
@@ -714,13 +704,13 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto body_str = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body_str, HasSubstr(R"(var x_38 : S_1;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto body_str = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body_str, HasSubstr(R"(var x_38 : S_1;
 let x_1 : S_1 = x_38;
 var x_2_1 : S_1 = x_1;
 x_2_1.field1[2u][0u].y = 70.0;
@@ -731,7 +721,7 @@
 using SpvParserTest_CopyObject = SpvParserTest;
 
 TEST_F(SpvParserTest_CopyObject, Scalar) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpCopyObject %uint %uint_3
@@ -739,19 +729,18 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr(R"(let x_1 : u32 = 3u;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr(R"(let x_1 : u32 = 3u;
 let x_2 : u32 = x_1;
 )"));
 }
 
 TEST_F(SpvParserTest_CopyObject, Pointer) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %ptr = OpTypePointer Function %uint
 
      %100 = OpFunction %void None %voidfn
@@ -762,13 +751,13 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr(R"(let x_1 : ptr<function, u32> = &(x_10);
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr(R"(let x_1 : ptr<function, u32> = &(x_10);
 let x_2 : ptr<function, u32> = x_1;
 )"));
 }
@@ -776,8 +765,8 @@
 using SpvParserTest_VectorShuffle = SpvParserTest;
 
 TEST_F(SpvParserTest_VectorShuffle, FunctionScopeOperands_UseBoth) {
-  // Note that variables are generated for the vector operands.
-  const auto assembly = Preamble() + R"(
+    // Note that variables are generated for the vector operands.
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpCopyObject %v2uint %v2uint_3_4
@@ -787,19 +776,17 @@
      OpFunctionEnd
 )";
 
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(
-      test::ToString(p->program(), ast_body),
-      HasSubstr(
-          "let x_10 : vec4<u32> = vec4<u32>(x_2.y, x_2.x, x_1.y, x_1.x);"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_10 : vec4<u32> = vec4<u32>(x_2.y, x_2.x, x_1.y, x_1.x);"));
 }
 
 TEST_F(SpvParserTest_VectorShuffle, ConstantOperands_UseBoth) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %10 = OpVectorShuffle %v4uint %v2uint_3_4 %v2uint_4_3 3 2 1 0
@@ -807,21 +794,21 @@
      OpFunctionEnd
 )";
 
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_10 : vec4<u32> = vec4<u32>("
-                        "vec2<u32>(4u, 3u).y, "
-                        "vec2<u32>(4u, 3u).x, "
-                        "vec2<u32>(3u, 4u).y, "
-                        "vec2<u32>(3u, 4u).x);"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_10 : vec4<u32> = vec4<u32>("
+                          "vec2<u32>(4u, 3u).y, "
+                          "vec2<u32>(4u, 3u).x, "
+                          "vec2<u32>(3u, 4u).y, "
+                          "vec2<u32>(3u, 4u).x);"));
 }
 
 TEST_F(SpvParserTest_VectorShuffle, ConstantOperands_AllOnesMapToNull) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpCopyObject %v2uint %v2uint_4_3
@@ -830,19 +817,18 @@
      OpFunctionEnd
 )";
 
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_10 : vec2<u32> = vec2<u32>(0u, x_1.y);"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_10 : vec2<u32> = vec2<u32>(0u, x_1.y);"));
 }
 
-TEST_F(SpvParserTest_VectorShuffle,
-       FunctionScopeOperands_MixedInputOperandSizes) {
-  // Note that variables are generated for the vector operands.
-  const auto assembly = Preamble() + R"(
+TEST_F(SpvParserTest_VectorShuffle, FunctionScopeOperands_MixedInputOperandSizes) {
+    // Note that variables are generated for the vector operands.
+    const auto assembly = Preamble() + R"(
      %v3uint_3_4_5 = OpConstantComposite %v3uint %uint_3 %uint_4 %uint_5
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
@@ -853,17 +839,17 @@
      OpFunctionEnd
 )";
 
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_10 : vec2<u32> = vec2<u32>(x_1.y, x_3.z);"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_10 : vec2<u32> = vec2<u32>(x_1.y, x_3.z);"));
 }
 
 TEST_F(SpvParserTest_VectorShuffle, IndexTooBig_IsError) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %10 = OpVectorShuffle %v4uint %v2uint_3_4 %v2uint_4_3 9 2 1 0
@@ -871,18 +857,17 @@
      OpFunctionEnd
 )";
 
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(fe.EmitBody()) << p->error();
-  EXPECT_THAT(p->error(),
-              Eq("invalid vectorshuffle ID %10: index too large: 9"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(fe.EmitBody()) << p->error();
+    EXPECT_THAT(p->error(), Eq("invalid vectorshuffle ID %10: index too large: 9"));
 }
 
 using SpvParserTest_VectorExtractDynamic = SpvParserTest;
 
 TEST_F(SpvParserTest_VectorExtractDynamic, SignedIndex) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpCopyObject %v2uint %v2uint_3_4
@@ -892,17 +877,17 @@
      OpFunctionEnd
 )";
 
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto got = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(got, HasSubstr("let x_10 : u32 = x_1[x_2];")) << got;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto got = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(got, HasSubstr("let x_10 : u32 = x_1[x_2];")) << got;
 }
 
 TEST_F(SpvParserTest_VectorExtractDynamic, UnsignedIndex) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpCopyObject %v2uint %v2uint_3_4
@@ -912,19 +897,19 @@
      OpFunctionEnd
 )";
 
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto got = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(got, HasSubstr("let x_10 : u32 = x_1[x_2];")) << got;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto got = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(got, HasSubstr("let x_10 : u32 = x_1[x_2];")) << got;
 }
 
 using SpvParserTest_VectorInsertDynamic = SpvParserTest;
 
 TEST_F(SpvParserTest_VectorInsertDynamic, Sample) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpCopyObject %v2uint %v2uint_3_4
@@ -935,13 +920,13 @@
      OpFunctionEnd
 )";
 
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto got = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(got, HasSubstr(R"(var x_10_1 : vec2<u32> = x_1;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto got = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(got, HasSubstr(R"(var x_10_1 : vec2<u32> = x_1;
 x_10_1[x_3] = x_2;
 let x_10 : vec2<u32> = x_10_1;
 )")) << got
@@ -949,8 +934,8 @@
 }
 
 TEST_F(SpvParserTest, DISABLED_WorkgroupSize_Overridable) {
-  // TODO(dneto): Support specializable workgroup size. crbug.com/tint/504
-  const auto* assembly = R"(
+    // TODO(dneto): Support specializable workgroup size. crbug.com/tint/504
+    const auto* assembly = R"(
   OpCapability Shader
   OpMemoryModel Logical Simple
   OpEntryPoint GLCompute %100 "main"
@@ -978,12 +963,12 @@
      OpFunctionEnd
 )";
 
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.Emit()) << p->error();
-  const auto got = test::ToString(p->program());
-  EXPECT_THAT(got, HasSubstr(R"(
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.Emit()) << p->error();
+    const auto got = test::ToString(p->program());
+    EXPECT_THAT(got, HasSubstr(R"(
   VariableConst{
     Decorations{
       OverrideDecoration{0}
@@ -1018,7 +1003,7 @@
     }
   }
 )")) << got;
-  EXPECT_THAT(got, HasSubstr(R"(
+    EXPECT_THAT(got, HasSubstr(R"(
     VariableDeclStatement{
       VariableConst{
         x_10
@@ -1064,7 +1049,7 @@
         }
       }
     })"))
-      << got << assembly;
+        << got << assembly;
 }
 
 }  // namespace
diff --git a/src/tint/reader/spirv/function_conversion_test.cc b/src/tint/reader/spirv/function_conversion_test.cc
index 4d77997..e2f10b2 100644
--- a/src/tint/reader/spirv/function_conversion_test.cc
+++ b/src/tint/reader/spirv/function_conversion_test.cc
@@ -24,7 +24,7 @@
 using ::testing::HasSubstr;
 
 std::string Preamble() {
-  return R"(
+    return R"(
   OpCapability Shader
   OpMemoryModel Logical Simple
   OpEntryPoint Fragment %100 "main"
@@ -70,142 +70,133 @@
 using SpvUnaryConversionTest = SpvParserTestBase<::testing::Test>;
 
 TEST_F(SpvUnaryConversionTest, Bitcast_Scalar) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpBitcast %uint %float_50
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : u32 = bitcast<u32>(50.0);"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : u32 = bitcast<u32>(50.0);"));
 }
 
 TEST_F(SpvUnaryConversionTest, Bitcast_Vector) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpBitcast %v2float %v2uint_10_20
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(
-      test::ToString(p->program(), ast_body),
-      HasSubstr(
-          "let x_1 : vec2<f32> = bitcast<vec2<f32>>(vec2<u32>(10u, 20u));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : vec2<f32> = bitcast<vec2<f32>>(vec2<u32>(10u, 20u));"));
 }
 
 TEST_F(SpvUnaryConversionTest, ConvertSToF_BadArg) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpConvertSToF %float %void
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(fe.EmitBody());
-  EXPECT_THAT(p->error(),
-              HasSubstr("unhandled expression for ID 2\n%2 = OpTypeVoid"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(fe.EmitBody());
+    EXPECT_THAT(p->error(), HasSubstr("unhandled expression for ID 2\n%2 = OpTypeVoid"));
 }
 
 TEST_F(SpvUnaryConversionTest, ConvertUToF_BadArg) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpConvertUToF %float %void
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(fe.EmitBody());
-  EXPECT_THAT(p->error(),
-              HasSubstr("unhandled expression for ID 2\n%2 = OpTypeVoid"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(fe.EmitBody());
+    EXPECT_THAT(p->error(), HasSubstr("unhandled expression for ID 2\n%2 = OpTypeVoid"));
 }
 
 TEST_F(SpvUnaryConversionTest, ConvertFToS_BadArg) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpConvertFToS %float %void
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(fe.EmitBody());
-  EXPECT_THAT(p->error(),
-              HasSubstr("unhandled expression for ID 2\n%2 = OpTypeVoid"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(fe.EmitBody());
+    EXPECT_THAT(p->error(), HasSubstr("unhandled expression for ID 2\n%2 = OpTypeVoid"));
 }
 
 TEST_F(SpvUnaryConversionTest, ConvertFToU_BadArg) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpConvertFToU %float %void
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(fe.EmitBody());
-  EXPECT_THAT(p->error(),
-              HasSubstr("unhandled expression for ID 2\n%2 = OpTypeVoid"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(fe.EmitBody());
+    EXPECT_THAT(p->error(), HasSubstr("unhandled expression for ID 2\n%2 = OpTypeVoid"));
 }
 
 TEST_F(SpvUnaryConversionTest, ConvertSToF_Scalar_BadArgType) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpConvertSToF %float %false
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(fe.EmitBody());
-  EXPECT_THAT(p->error(),
-              HasSubstr("operand for conversion to floating point must be "
-                        "integral scalar or vector"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(fe.EmitBody());
+    EXPECT_THAT(p->error(), HasSubstr("operand for conversion to floating point must be "
+                                      "integral scalar or vector"));
 }
 
 TEST_F(SpvUnaryConversionTest, ConvertSToF_Vector_BadArgType) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpConvertSToF %v2float %v2bool_t_f
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(fe.EmitBody());
-  EXPECT_THAT(
-      p->error(),
-      HasSubstr("operand for conversion to floating point must be integral "
-                "scalar or vector"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(fe.EmitBody());
+    EXPECT_THAT(p->error(), HasSubstr("operand for conversion to floating point must be integral "
+                                      "scalar or vector"));
 }
 
 TEST_F(SpvUnaryConversionTest, ConvertSToF_Scalar_FromSigned) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %30 = OpCopyObject %int %int_30
@@ -213,17 +204,16 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : f32 = f32(x_30);"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr("let x_1 : f32 = f32(x_30);"));
 }
 
 TEST_F(SpvUnaryConversionTest, ConvertSToF_Scalar_FromUnsigned) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %30 = OpCopyObject %uint %uint_10
@@ -231,17 +221,17 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : f32 = f32(bitcast<i32>(x_30));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : f32 = f32(bitcast<i32>(x_30));"));
 }
 
 TEST_F(SpvUnaryConversionTest, ConvertSToF_Vector_FromSigned) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %30 = OpCopyObject %v2int %v2int_30_40
@@ -249,17 +239,17 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : vec2<f32> = vec2<f32>(x_30);"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : vec2<f32> = vec2<f32>(x_30);"));
 }
 
 TEST_F(SpvUnaryConversionTest, ConvertSToF_Vector_FromUnsigned) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %30 = OpCopyObject %v2uint %v2uint_10_20
@@ -267,53 +257,49 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(
-      test::ToString(p->program(), ast_body),
-      HasSubstr("let x_1 : vec2<f32> = vec2<f32>(bitcast<vec2<i32>>(x_30));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : vec2<f32> = vec2<f32>(bitcast<vec2<i32>>(x_30));"));
 }
 
 TEST_F(SpvUnaryConversionTest, ConvertUToF_Scalar_BadArgType) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpConvertUToF %float %false
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(fe.EmitBody());
-  EXPECT_THAT(p->error(),
-              HasSubstr("operand for conversion to floating point must be "
-                        "integral scalar or vector"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(fe.EmitBody());
+    EXPECT_THAT(p->error(), HasSubstr("operand for conversion to floating point must be "
+                                      "integral scalar or vector"));
 }
 
 TEST_F(SpvUnaryConversionTest, ConvertUToF_Vector_BadArgType) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpConvertUToF %v2float %v2bool_t_f
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(fe.EmitBody());
-  EXPECT_THAT(
-      p->error(),
-      HasSubstr("operand for conversion to floating point must be integral "
-                "scalar or vector"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(fe.EmitBody());
+    EXPECT_THAT(p->error(), HasSubstr("operand for conversion to floating point must be integral "
+                                      "scalar or vector"));
 }
 
 TEST_F(SpvUnaryConversionTest, ConvertUToF_Scalar_FromSigned) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %30 = OpCopyObject %int %int_30
@@ -321,17 +307,17 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : f32 = f32(bitcast<u32>(x_30));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : f32 = f32(bitcast<u32>(x_30));"));
 }
 
 TEST_F(SpvUnaryConversionTest, ConvertUToF_Scalar_FromUnsigned) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %30 = OpCopyObject %uint %uint_10
@@ -339,17 +325,16 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : f32 = f32(x_30);"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr("let x_1 : f32 = f32(x_30);"));
 }
 
 TEST_F(SpvUnaryConversionTest, ConvertUToF_Vector_FromSigned) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %30 = OpCopyObject %v2int %v2int_30_40
@@ -357,18 +342,17 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(
-      test::ToString(p->program(), ast_body),
-      HasSubstr("let x_1 : vec2<f32> = vec2<f32>(bitcast<vec2<u32>>(x_30));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : vec2<f32> = vec2<f32>(bitcast<vec2<u32>>(x_30));"));
 }
 
 TEST_F(SpvUnaryConversionTest, ConvertUToF_Vector_FromUnsigned) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %30 = OpCopyObject %v2uint %v2uint_10_20
@@ -376,53 +360,49 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : vec2<f32> = vec2<f32>(x_30);"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : vec2<f32> = vec2<f32>(x_30);"));
 }
 
 TEST_F(SpvUnaryConversionTest, ConvertFToS_Scalar_BadArgType) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpConvertFToS %int %uint_10
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(fe.EmitBody());
-  EXPECT_THAT(
-      p->error(),
-      HasSubstr("operand for conversion to signed integer must be floating "
-                "point scalar or vector"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(fe.EmitBody());
+    EXPECT_THAT(p->error(), HasSubstr("operand for conversion to signed integer must be floating "
+                                      "point scalar or vector"));
 }
 
 TEST_F(SpvUnaryConversionTest, ConvertFToS_Vector_BadArgType) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpConvertFToS %v2float %v2bool_t_f
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(fe.EmitBody());
-  EXPECT_THAT(
-      p->error(),
-      HasSubstr("operand for conversion to signed integer must be floating "
-                "point scalar or vector"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(fe.EmitBody());
+    EXPECT_THAT(p->error(), HasSubstr("operand for conversion to signed integer must be floating "
+                                      "point scalar or vector"));
 }
 
 TEST_F(SpvUnaryConversionTest, ConvertFToS_Scalar_ToSigned) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %30 = OpCopyObject %float %float_50
@@ -430,17 +410,16 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : i32 = i32(x_30);"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr("let x_1 : i32 = i32(x_30);"));
 }
 
 TEST_F(SpvUnaryConversionTest, ConvertFToS_Scalar_ToUnsigned) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %30 = OpCopyObject %float %float_50
@@ -448,17 +427,17 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : u32 = bitcast<u32>(i32(x_30));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : u32 = bitcast<u32>(i32(x_30));"));
 }
 
 TEST_F(SpvUnaryConversionTest, ConvertFToS_Vector_ToSigned) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %30 = OpCopyObject %v2float %v2float_50_60
@@ -466,17 +445,17 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : vec2<i32> = vec2<i32>(x_30);"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : vec2<i32> = vec2<i32>(x_30);"));
 }
 
 TEST_F(SpvUnaryConversionTest, ConvertFToS_Vector_ToUnsigned) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %30 = OpCopyObject %v2float %v2float_50_60
@@ -484,54 +463,49 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(
-      test::ToString(p->program(), ast_body),
-      HasSubstr("let x_1 : vec2<u32> = bitcast<vec2<u32>>(vec2<i32>(x_30));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : vec2<u32> = bitcast<vec2<u32>>(vec2<i32>(x_30));"));
 }
 
 TEST_F(SpvUnaryConversionTest, ConvertFToU_Scalar_BadArgType) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpConvertFToU %int %uint_10
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(fe.EmitBody());
-  EXPECT_THAT(
-      p->error(),
-      HasSubstr("operand for conversion to unsigned integer must be floating "
-                "point scalar or vector"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(fe.EmitBody());
+    EXPECT_THAT(p->error(), HasSubstr("operand for conversion to unsigned integer must be floating "
+                                      "point scalar or vector"));
 }
 
 TEST_F(SpvUnaryConversionTest, ConvertFToU_Vector_BadArgType) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpConvertFToU %v2float %v2bool_t_f
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(fe.EmitBody());
-  EXPECT_THAT(
-      p->error(),
-      HasSubstr("operand for conversion to unsigned integer must be floating "
-                "point scalar or vector"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(fe.EmitBody());
+    EXPECT_THAT(p->error(), HasSubstr("operand for conversion to unsigned integer must be floating "
+                                      "point scalar or vector"));
 }
 
 TEST_F(SpvUnaryConversionTest, ConvertFToU_Scalar_ToSigned_IsError) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %30 = OpCopyObject %float %float_50
@@ -539,15 +513,15 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_FALSE(p->Parse());
-  EXPECT_FALSE(p->success());
-  EXPECT_THAT(p->error(), HasSubstr("Expected unsigned int scalar or vector "
-                                    "type as Result Type: ConvertFToU"));
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_FALSE(p->Parse());
+    EXPECT_FALSE(p->success());
+    EXPECT_THAT(p->error(), HasSubstr("Expected unsigned int scalar or vector "
+                                      "type as Result Type: ConvertFToU"));
 }
 
 TEST_F(SpvUnaryConversionTest, ConvertFToU_Scalar_ToUnsigned) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %30 = OpCopyObject %float %float_50
@@ -555,17 +529,16 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : u32 = u32(x_30);"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr("let x_1 : u32 = u32(x_30);"));
 }
 
 TEST_F(SpvUnaryConversionTest, ConvertFToU_Vector_ToSigned_IsError) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %30 = OpCopyObject %v2float %v2float_50_60
@@ -573,15 +546,15 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_FALSE(p->Parse());
-  EXPECT_FALSE(p->success());
-  EXPECT_THAT(p->error(), HasSubstr("Expected unsigned int scalar or vector "
-                                    "type as Result Type: ConvertFToU"));
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_FALSE(p->Parse());
+    EXPECT_FALSE(p->success());
+    EXPECT_THAT(p->error(), HasSubstr("Expected unsigned int scalar or vector "
+                                      "type as Result Type: ConvertFToU"));
 }
 
 TEST_F(SpvUnaryConversionTest, ConvertFToU_Vector_ToUnsigned) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %30 = OpCopyObject %v2float %v2float_50_60
@@ -589,18 +562,18 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : vec2<u32> = vec2<u32>(x_30);"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : vec2<u32> = vec2<u32>(x_30);"));
 }
 
 TEST_F(SpvUnaryConversionTest, ConvertFToU_HoistedValue) {
-  // From crbug.com/tint/804
-  const auto assembly = Preamble() + R"(
+    // From crbug.com/tint/804
+    const auto assembly = Preamble() + R"(
 
 %100 = OpFunction %void None %voidfn
 %10 = OpLabel
@@ -631,13 +604,12 @@
 OpFunctionEnd
 
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_82 : u32 = u32(x_600);"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr("let x_82 : u32 = u32(x_600);"));
 }
 
 // TODO(dneto): OpSConvert // only if multiple widths
diff --git a/src/tint/reader/spirv/function_decl_test.cc b/src/tint/reader/spirv/function_decl_test.cc
index 5fa6330..bced935 100644
--- a/src/tint/reader/spirv/function_decl_test.cc
+++ b/src/tint/reader/spirv/function_decl_test.cc
@@ -23,7 +23,7 @@
 using ::testing::HasSubstr;
 
 std::string Preamble() {
-  return R"(
+    return R"(
     OpCapability Shader
     OpMemoryModel Logical Simple
     OpEntryPoint Fragment %100 "x_100"
@@ -34,15 +34,15 @@
 /// @returns a SPIR-V assembly segment which assigns debug names
 /// to particular IDs.
 std::string Names(std::vector<std::string> ids) {
-  std::ostringstream outs;
-  for (auto& id : ids) {
-    outs << "    OpName %" << id << " \"" << id << "\"\n";
-  }
-  return outs.str();
+    std::ostringstream outs;
+    for (auto& id : ids) {
+        outs << "    OpName %" << id << " \"" << id << "\"\n";
+    }
+    return outs.str();
 }
 
 std::string CommonTypes() {
-  return R"(
+    return R"(
     %void = OpTypeVoid
     %voidfn = OpTypeFunction %void
     %float = OpTypeFloat 32
@@ -53,7 +53,7 @@
 }
 
 std::string MainBody() {
-  return R"(
+    return R"(
     %100 = OpFunction %void None %voidfn
     %entry_100 = OpLabel
     OpReturn
@@ -62,46 +62,45 @@
 }
 
 TEST_F(SpvParserTest, Emit_VoidFunctionWithoutParams) {
-  auto p = parser(test::Assemble(Preamble() + CommonTypes() + R"(
+    auto p = parser(test::Assemble(Preamble() + CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      OpReturn
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.Emit());
-  auto got = test::ToString(p->program());
-  std::string expect = R"(fn x_100() {
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.Emit());
+    auto got = test::ToString(p->program());
+    std::string expect = R"(fn x_100() {
   return;
 }
 )";
-  EXPECT_EQ(got, expect);
+    EXPECT_EQ(got, expect);
 }
 
 TEST_F(SpvParserTest, Emit_NonVoidResultType) {
-  auto p = parser(test::Assemble(Preamble() + CommonTypes() + R"(
+    auto p = parser(test::Assemble(Preamble() + CommonTypes() + R"(
      %fn_ret_float = OpTypeFunction %float
      %200 = OpFunction %float None %fn_ret_float
      %entry = OpLabel
      OpReturnValue %float_0
      OpFunctionEnd
   )" + MainBody()));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(200);
-  EXPECT_TRUE(fe.Emit());
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(200);
+    EXPECT_TRUE(fe.Emit());
 
-  auto got = test::ToString(p->program());
-  std::string expect = R"(fn x_200() -> f32 {
+    auto got = test::ToString(p->program());
+    std::string expect = R"(fn x_200() -> f32 {
   return 0.0;
 }
 )";
-  EXPECT_THAT(got, HasSubstr(expect));
+    EXPECT_THAT(got, HasSubstr(expect));
 }
 
 TEST_F(SpvParserTest, Emit_MixedParamTypes) {
-  auto p = parser(
-      test::Assemble(Preamble() + Names({"a", "b", "c"}) + CommonTypes() + R"(
+    auto p = parser(test::Assemble(Preamble() + Names({"a", "b", "c"}) + CommonTypes() + R"(
      %fn_mixed_params = OpTypeFunction %void %uint %float %int
 
      %200 = OpFunction %void None %fn_mixed_params
@@ -112,20 +111,20 @@
      OpReturn
      OpFunctionEnd
   )" + MainBody()));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(200);
-  EXPECT_TRUE(fe.Emit());
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(200);
+    EXPECT_TRUE(fe.Emit());
 
-  auto got = test::ToString(p->program());
-  std::string expect = R"(fn x_200(a : u32, b : f32, c : i32) {
+    auto got = test::ToString(p->program());
+    std::string expect = R"(fn x_200(a : u32, b : f32, c : i32) {
   return;
 }
 )";
-  EXPECT_THAT(got, HasSubstr(expect));
+    EXPECT_THAT(got, HasSubstr(expect));
 }
 
 TEST_F(SpvParserTest, Emit_GenerateParamNames) {
-  auto p = parser(test::Assemble(Preamble() + CommonTypes() + R"(
+    auto p = parser(test::Assemble(Preamble() + CommonTypes() + R"(
      %fn_mixed_params = OpTypeFunction %void %uint %float %int
 
      %200 = OpFunction %void None %fn_mixed_params
@@ -136,16 +135,16 @@
      OpReturn
      OpFunctionEnd
   )" + MainBody()));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(200);
-  EXPECT_TRUE(fe.Emit());
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(200);
+    EXPECT_TRUE(fe.Emit());
 
-  auto got = test::ToString(p->program());
-  std::string expect = R"(fn x_200(x_14 : u32, x_15 : f32, x_16 : i32) {
+    auto got = test::ToString(p->program());
+    std::string expect = R"(fn x_200(x_14 : u32, x_15 : f32, x_16 : i32) {
   return;
 }
 )";
-  EXPECT_THAT(got, HasSubstr(expect));
+    EXPECT_THAT(got, HasSubstr(expect));
 }
 
 }  // namespace
diff --git a/src/tint/reader/spirv/function_glsl_std_450_test.cc b/src/tint/reader/spirv/function_glsl_std_450_test.cc
index 7451882..319332a 100644
--- a/src/tint/reader/spirv/function_glsl_std_450_test.cc
+++ b/src/tint/reader/spirv/function_glsl_std_450_test.cc
@@ -23,7 +23,7 @@
 using ::testing::HasSubstr;
 
 std::string Preamble() {
-  return R"(
+    return R"(
   OpCapability Shader
   %glsl = OpExtInstImport "GLSL.std.450"
   OpMemoryModel Logical GLSL450
@@ -127,12 +127,12 @@
 }
 
 struct GlslStd450Case {
-  std::string opcode;
-  std::string wgsl_func;
+    std::string opcode;
+    std::string wgsl_func;
 };
 inline std::ostream& operator<<(std::ostream& out, GlslStd450Case c) {
-  out << "GlslStd450Case(" << c.opcode << " " << c.wgsl_func << ")";
-  return out;
+    out << "GlslStd450Case(" << c.opcode << " " << c.wgsl_func << ")";
+    return out;
 }
 
 // Nomenclature:
@@ -171,240 +171,222 @@
     SpvParserTestBase<::testing::TestWithParam<GlslStd450Case>>;
 
 TEST_P(SpvParserTest_GlslStd450_Float_Floating, Scalar) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %1 = OpExtInst %float %glsl )" +
-                        GetParam().opcode + R"( %f1
+                          GetParam().opcode + R"( %f1
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body,
-              HasSubstr("let x_1 : f32 = " + GetParam().wgsl_func + "(f1);"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : f32 = " + GetParam().wgsl_func + "(f1);")) << body;
 }
 
 TEST_P(SpvParserTest_GlslStd450_Float_Floating, Vector) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %1 = OpExtInst %float %glsl )" +
-                        GetParam().opcode + R"( %v2f1
+                          GetParam().opcode + R"( %v2f1
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body,
-              HasSubstr("let x_1 : f32 = " + GetParam().wgsl_func + "(v2f1);"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : f32 = " + GetParam().wgsl_func + "(v2f1);")) << body;
 }
 
 TEST_P(SpvParserTest_GlslStd450_Float_FloatingFloating, Scalar) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %1 = OpExtInst %float %glsl )" +
-                        GetParam().opcode + R"( %f1 %f2
+                          GetParam().opcode + R"( %f1 %f2
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(
-      body, HasSubstr("let x_1 : f32 = " + GetParam().wgsl_func + "(f1, f2);"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : f32 = " + GetParam().wgsl_func + "(f1, f2);")) << body;
 }
 
 TEST_P(SpvParserTest_GlslStd450_Float_FloatingFloating, Vector) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %1 = OpExtInst %float %glsl )" +
-                        GetParam().opcode + R"( %v2f1 %v2f2
+                          GetParam().opcode + R"( %v2f1 %v2f2
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body, HasSubstr("let x_1 : f32 = " + GetParam().wgsl_func +
-                              "(v2f1, v2f2);"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : f32 = " + GetParam().wgsl_func + "(v2f1, v2f2);"))
+        << body;
 }
 
 TEST_P(SpvParserTest_GlslStd450_Floating_Floating, Scalar) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %1 = OpExtInst %float %glsl )" +
-                        GetParam().opcode + R"( %f1
+                          GetParam().opcode + R"( %f1
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body,
-              HasSubstr("let x_1 : f32 = " + GetParam().wgsl_func + "(f1);"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : f32 = " + GetParam().wgsl_func + "(f1);")) << body;
 }
 
 TEST_P(SpvParserTest_GlslStd450_Floating_Floating, Vector) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %1 = OpExtInst %v2float %glsl )" +
-                        GetParam().opcode + R"( %v2f1
+                          GetParam().opcode + R"( %v2f1
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body, HasSubstr("let x_1 : vec2<f32> = " + GetParam().wgsl_func +
-                              "(v2f1);"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : vec2<f32> = " + GetParam().wgsl_func + "(v2f1);"))
+        << body;
 }
 
 TEST_P(SpvParserTest_GlslStd450_Floating_FloatingFloating, Scalar) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %1 = OpExtInst %float %glsl )" +
-                        GetParam().opcode + R"( %f1 %f2
+                          GetParam().opcode + R"( %f1 %f2
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(
-      body, HasSubstr("let x_1 : f32 = " + GetParam().wgsl_func + "(f1, f2);"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : f32 = " + GetParam().wgsl_func + "(f1, f2);")) << body;
 }
 
 TEST_P(SpvParserTest_GlslStd450_Floating_FloatingFloating, Vector) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %1 = OpExtInst %v2float %glsl )" +
-                        GetParam().opcode + R"( %v2f1 %v2f2
+                          GetParam().opcode + R"( %v2f1 %v2f2
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body, HasSubstr("let x_1 : vec2<f32> = " + GetParam().wgsl_func +
-                              "(v2f1, v2f2);"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : vec2<f32> = " + GetParam().wgsl_func + "(v2f1, v2f2);"))
+        << body;
 }
 
 TEST_P(SpvParserTest_GlslStd450_Floating_FloatingFloatingFloating, Scalar) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %1 = OpExtInst %float %glsl )" +
-                        GetParam().opcode + R"( %f1 %f2 %f3
+                          GetParam().opcode + R"( %f1 %f2 %f3
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body, HasSubstr("let x_1 : f32 = " + GetParam().wgsl_func +
-                              "(f1, f2, f3);"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : f32 = " + GetParam().wgsl_func + "(f1, f2, f3);"))
+        << body;
 }
 
 TEST_P(SpvParserTest_GlslStd450_Floating_FloatingFloatingFloating, Vector) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %1 = OpExtInst %v2float %glsl )" +
-                        GetParam().opcode +
-                        R"( %v2f1 %v2f2 %v2f3
+                          GetParam().opcode +
+                          R"( %v2f1 %v2f2 %v2f3
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body, HasSubstr("let x_1 : vec2<f32> = " + GetParam().wgsl_func +
-                              "(v2f1, v2f2, v2f3);"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body,
+                HasSubstr("let x_1 : vec2<f32> = " + GetParam().wgsl_func + "(v2f1, v2f2, v2f3);"))
+        << body;
 }
 
 TEST_P(SpvParserTest_GlslStd450_Floating_FloatingInting, Scalar) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %1 = OpExtInst %float %glsl )" +
-                        GetParam().opcode + R"( %f1 %i1
+                          GetParam().opcode + R"( %f1 %i1
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(
-      body, HasSubstr("let x_1 : f32 = " + GetParam().wgsl_func + "(f1, i1);"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : f32 = " + GetParam().wgsl_func + "(f1, i1);")) << body;
 }
 
 TEST_P(SpvParserTest_GlslStd450_Floating_FloatingInting, Vector) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %1 = OpExtInst %v2float %glsl )" +
-                        GetParam().opcode +
-                        R"( %v2f1 %v2i1
+                          GetParam().opcode +
+                          R"( %v2f1 %v2i1
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body, HasSubstr("let x_1 : vec2<f32> = " + GetParam().wgsl_func +
-                              "(v2f1, v2i1);"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : vec2<f32> = " + GetParam().wgsl_func + "(v2f1, v2i1);"))
+        << body;
 }
 
 TEST_P(SpvParserTest_GlslStd450_Float3_Float3Float3, Samples) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %1 = OpExtInst %v3float %glsl )" +
-                        GetParam().opcode +
-                        R"( %v3f1 %v3f2
+                          GetParam().opcode +
+                          R"( %v3f1 %v3f2
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body, HasSubstr("let x_1 : vec3<f32> = " + GetParam().wgsl_func +
-                              "(v3f1, v3f2);"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : vec3<f32> = " + GetParam().wgsl_func + "(v3f1, v3f2);"))
+        << body;
 }
 
 INSTANTIATE_TEST_SUITE_P(Samples,
@@ -413,8 +395,7 @@
 
 INSTANTIATE_TEST_SUITE_P(Samples,
                          SpvParserTest_GlslStd450_Float_FloatingFloating,
-                         ::testing::Values(GlslStd450Case{"Distance",
-                                                          "distance"}));
+                         ::testing::Values(GlslStd450Case{"Distance", "distance"}));
 
 INSTANTIATE_TEST_SUITE_P(Samples,
                          SpvParserTest_GlslStd450_Floating_Floating,
@@ -467,128 +448,120 @@
                          SpvParserTest_GlslStd450_Float3_Float3Float3,
                          ::testing::Values(GlslStd450Case{"Cross", "cross"}));
 
-INSTANTIATE_TEST_SUITE_P(
-    Samples,
-    SpvParserTest_GlslStd450_Floating_FloatingFloatingFloating,
-    ::testing::ValuesIn(std::vector<GlslStd450Case>{
-        {"NClamp", "clamp"},
-        {"FClamp", "clamp"},  // WGSL FClamp promises more for NaN
-        {"Fma", "fma"},
-        {"FMix", "mix"},
-        {"SmoothStep", "smoothstep"}}));
+INSTANTIATE_TEST_SUITE_P(Samples,
+                         SpvParserTest_GlslStd450_Floating_FloatingFloatingFloating,
+                         ::testing::ValuesIn(std::vector<GlslStd450Case>{
+                             {"NClamp", "clamp"},
+                             {"FClamp", "clamp"},  // WGSL FClamp promises more for NaN
+                             {"Fma", "fma"},
+                             {"FMix", "mix"},
+                             {"SmoothStep", "smoothstep"}}));
 
 TEST_P(SpvParserTest_GlslStd450_Inting_Inting, Scalar) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %1 = OpExtInst %int %glsl )" +
-                        GetParam().opcode +
-                        R"( %i1
+                          GetParam().opcode +
+                          R"( %i1
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body,
-              HasSubstr("let x_1 : i32 = " + GetParam().wgsl_func + "(i1);"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : i32 = " + GetParam().wgsl_func + "(i1);")) << body;
 }
 
 TEST_P(SpvParserTest_GlslStd450_Inting_Inting, Vector) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %1 = OpExtInst %v2int %glsl )" +
-                        GetParam().opcode +
-                        R"( %v2i1
+                          GetParam().opcode +
+                          R"( %v2i1
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body, HasSubstr("let x_1 : vec2<i32> = " + GetParam().wgsl_func +
-                              "(v2i1);"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : vec2<i32> = " + GetParam().wgsl_func + "(v2i1);"))
+        << body;
 }
 
 TEST_P(SpvParserTest_GlslStd450_Inting_IntingInting, Scalar) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %1 = OpExtInst %int %glsl )" +
-                        GetParam().opcode +
-                        R"( %i1 %i2
+                          GetParam().opcode +
+                          R"( %i1 %i2
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(
-      body, HasSubstr("let x_1 : i32 = " + GetParam().wgsl_func + "(i1, i2);"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : i32 = " + GetParam().wgsl_func + "(i1, i2);")) << body;
 }
 
 TEST_P(SpvParserTest_GlslStd450_Inting_IntingInting, Vector) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %1 = OpExtInst %v2int %glsl )" +
-                        GetParam().opcode +
-                        R"( %v2i1 %v2i2
+                          GetParam().opcode +
+                          R"( %v2i1 %v2i2
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body, HasSubstr("let x_1 : vec2<i32> = " + GetParam().wgsl_func +
-                              "(v2i1, v2i2);"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : vec2<i32> = " + GetParam().wgsl_func + "(v2i1, v2i2);"))
+        << body;
 }
 
 TEST_P(SpvParserTest_GlslStd450_Inting_IntingIntingInting, Scalar) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %1 = OpExtInst %int %glsl )" +
-                        GetParam().opcode +
-                        R"( %i1 %i2 %i3
+                          GetParam().opcode +
+                          R"( %i1 %i2 %i3
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body, HasSubstr("let x_1 : i32 = " + GetParam().wgsl_func +
-                              "(i1, i2, i3);"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : i32 = " + GetParam().wgsl_func + "(i1, i2, i3);"))
+        << body;
 }
 
 TEST_P(SpvParserTest_GlslStd450_Inting_IntingIntingInting, Vector) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %1 = OpExtInst %v2int %glsl )" +
-                        GetParam().opcode +
-                        R"( %v2i1 %v2i2 %v2i3
+                          GetParam().opcode +
+                          R"( %v2i1 %v2i2 %v2i3
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body, HasSubstr("let x_1 : vec2<i32> = " + GetParam().wgsl_func +
-                              "(v2i1, v2i2, v2i3);"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body,
+                HasSubstr("let x_1 : vec2<i32> = " + GetParam().wgsl_func + "(v2i1, v2i2, v2i3);"))
+        << body;
 }
 
 INSTANTIATE_TEST_SUITE_P(Samples,
@@ -605,77 +578,73 @@
                          ::testing::Values(GlslStd450Case{"SClamp", "clamp"}));
 
 TEST_P(SpvParserTest_GlslStd450_Uinting_UintingUinting, Scalar) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %1 = OpExtInst %uint %glsl )" +
-                        GetParam().opcode + R"( %u1 %u2
+                          GetParam().opcode + R"( %u1 %u2
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(
-      body, HasSubstr("let x_1 : u32 = " + GetParam().wgsl_func + "(u1, u2);"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : u32 = " + GetParam().wgsl_func + "(u1, u2);")) << body;
 }
 
 TEST_P(SpvParserTest_GlslStd450_Uinting_UintingUinting, Vector) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %1 = OpExtInst %v2uint %glsl )" +
-                        GetParam().opcode +
-                        R"( %v2u1 %v2u2
+                          GetParam().opcode +
+                          R"( %v2u1 %v2u2
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body, HasSubstr("let x_1 : vec2<u32> = " + GetParam().wgsl_func +
-                              "(v2u1, v2u2);"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : vec2<u32> = " + GetParam().wgsl_func + "(v2u1, v2u2);"))
+        << body;
 }
 
 TEST_P(SpvParserTest_GlslStd450_Uinting_UintingUintingUinting, Scalar) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %1 = OpExtInst %uint %glsl )" +
-                        GetParam().opcode + R"( %u1 %u2 %u3
+                          GetParam().opcode + R"( %u1 %u2 %u3
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body, HasSubstr("let x_1 : u32 = " + GetParam().wgsl_func +
-                              "(u1, u2, u3);"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : u32 = " + GetParam().wgsl_func + "(u1, u2, u3);"))
+        << body;
 }
 
 TEST_P(SpvParserTest_GlslStd450_Uinting_UintingUintingUinting, Vector) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %1 = OpExtInst %v2uint %glsl )" +
-                        GetParam().opcode +
-                        R"( %v2u1 %v2u2 %v2u3
+                          GetParam().opcode +
+                          R"( %v2u1 %v2u2 %v2u3
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body, HasSubstr("let x_1 : vec2<u32> = " + GetParam().wgsl_func +
-                              "(v2u1, v2u2, v2u3);"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body,
+                HasSubstr("let x_1 : vec2<u32> = " + GetParam().wgsl_func + "(v2u1, v2u2, v2u3);"))
+        << body;
 }
 
 INSTANTIATE_TEST_SUITE_P(Samples,
@@ -692,281 +661,269 @@
 // above.
 
 TEST_F(SpvParserTest, Normalize_Scalar) {
-  // Scalar normalize always results in 1.0
-  const auto assembly = Preamble() + R"(
+    // Scalar normalize always results in 1.0
+    const auto assembly = Preamble() + R"(
      %1 = OpExtInst %float %glsl Normalize %f1
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body, HasSubstr("let x_1 : f32 = 1.0;")) << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : f32 = 1.0;")) << body;
 }
 
 TEST_F(SpvParserTest, Normalize_Vector2) {
-  // Scalar normalize always results in 1.0
-  const auto assembly = Preamble() + R"(
+    // Scalar normalize always results in 1.0
+    const auto assembly = Preamble() + R"(
      %1 = OpExtInst %v2float %glsl Normalize %v2f1
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body, HasSubstr("let x_1 : vec2<f32> = normalize(v2f1);"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : vec2<f32> = normalize(v2f1);")) << body;
 }
 
 TEST_F(SpvParserTest, Normalize_Vector3) {
-  // Scalar normalize always results in 1.0
-  const auto assembly = Preamble() + R"(
+    // Scalar normalize always results in 1.0
+    const auto assembly = Preamble() + R"(
      %1 = OpExtInst %v3float %glsl Normalize %v3f1
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body, HasSubstr("let x_1 : vec3<f32> = normalize(v3f1);"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : vec3<f32> = normalize(v3f1);")) << body;
 }
 
 TEST_F(SpvParserTest, Normalize_Vector4) {
-  // Scalar normalize always results in 1.0
-  const auto assembly = Preamble() + R"(
+    // Scalar normalize always results in 1.0
+    const auto assembly = Preamble() + R"(
      %1 = OpExtInst %v4float %glsl Normalize %v4f1
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body, HasSubstr("let x_1 : vec4<f32> = normalize(v4f1);"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : vec4<f32> = normalize(v4f1);")) << body;
 }
 
 // Check that we convert signedness of operands and result type.
 // This is needed for each of the integer-based extended instructions.
 
 TEST_F(SpvParserTest, RectifyOperandsAndResult_SAbs) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %1 = OpExtInst %uint %glsl SAbs %u1
      %2 = OpExtInst %v2uint %glsl SAbs %v2u1
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(
-      body,
-      HasSubstr(R"(let x_1 : u32 = bitcast<u32>(abs(bitcast<i32>(u1)));)"))
-      << body;
-  EXPECT_THAT(
-      body,
-      HasSubstr(
-          R"(let x_2 : vec2<u32> = bitcast<vec2<u32>>(abs(bitcast<vec2<i32>>(v2u1)));)"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr(R"(let x_1 : u32 = bitcast<u32>(abs(bitcast<i32>(u1)));)")) << body;
+    EXPECT_THAT(
+        body,
+        HasSubstr(R"(let x_2 : vec2<u32> = bitcast<vec2<u32>>(abs(bitcast<vec2<i32>>(v2u1)));)"))
+        << body;
 }
 
 TEST_F(SpvParserTest, RectifyOperandsAndResult_SMax) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %1 = OpExtInst %uint %glsl SMax %u1 %u2
      %2 = OpExtInst %v2uint %glsl SMax %v2u1 %v2u2
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(
-      body,
-      HasSubstr(
-          R"(let x_1 : u32 = bitcast<u32>(max(bitcast<i32>(u1), bitcast<i32>(u2)));)"))
-      << body;
-  EXPECT_THAT(
-      body,
-      HasSubstr(
-          R"(let x_2 : vec2<u32> = bitcast<vec2<u32>>(max(bitcast<vec2<i32>>(v2u1), bitcast<vec2<i32>>(v2u2)));)"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(
+        body,
+        HasSubstr(R"(let x_1 : u32 = bitcast<u32>(max(bitcast<i32>(u1), bitcast<i32>(u2)));)"))
+        << body;
+    EXPECT_THAT(
+        body,
+        HasSubstr(
+            R"(let x_2 : vec2<u32> = bitcast<vec2<u32>>(max(bitcast<vec2<i32>>(v2u1), bitcast<vec2<i32>>(v2u2)));)"))
+        << body;
 }
 
 TEST_F(SpvParserTest, RectifyOperandsAndResult_SMin) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %1 = OpExtInst %uint %glsl SMin %u1 %u2
      %2 = OpExtInst %v2uint %glsl SMin %v2u1 %v2u2
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(
-      body,
-      HasSubstr(
-          R"(let x_1 : u32 = bitcast<u32>(min(bitcast<i32>(u1), bitcast<i32>(u2)));)"))
-      << body;
-  EXPECT_THAT(
-      body,
-      HasSubstr(
-          R"(let x_2 : vec2<u32> = bitcast<vec2<u32>>(min(bitcast<vec2<i32>>(v2u1), bitcast<vec2<i32>>(v2u2)));)"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(
+        body,
+        HasSubstr(R"(let x_1 : u32 = bitcast<u32>(min(bitcast<i32>(u1), bitcast<i32>(u2)));)"))
+        << body;
+    EXPECT_THAT(
+        body,
+        HasSubstr(
+            R"(let x_2 : vec2<u32> = bitcast<vec2<u32>>(min(bitcast<vec2<i32>>(v2u1), bitcast<vec2<i32>>(v2u2)));)"))
+        << body;
 }
 
 TEST_F(SpvParserTest, RectifyOperandsAndResult_SClamp) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %1 = OpExtInst %uint %glsl SClamp %u1 %i2 %u3
      %2 = OpExtInst %v2uint %glsl SClamp %v2u1 %v2i2 %v2u3
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(
-      body,
-      HasSubstr(
-          R"(let x_1 : u32 = bitcast<u32>(clamp(bitcast<i32>(u1), i2, bitcast<i32>(u3)));)"))
-      << body;
-  EXPECT_THAT(
-      body,
-      HasSubstr(
-          R"(let x_2 : vec2<u32> = bitcast<vec2<u32>>(clamp(bitcast<vec2<i32>>(v2u1), v2i2, bitcast<vec2<i32>>(v2u3)));)"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(
+        body,
+        HasSubstr(
+            R"(let x_1 : u32 = bitcast<u32>(clamp(bitcast<i32>(u1), i2, bitcast<i32>(u3)));)"))
+        << body;
+    EXPECT_THAT(
+        body,
+        HasSubstr(
+            R"(let x_2 : vec2<u32> = bitcast<vec2<u32>>(clamp(bitcast<vec2<i32>>(v2u1), v2i2, bitcast<vec2<i32>>(v2u3)));)"))
+        << body;
 }
 
 TEST_F(SpvParserTest, RectifyOperandsAndResult_UMax) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %1 = OpExtInst %int %glsl UMax %i1 %i2
      %2 = OpExtInst %v2int %glsl UMax %v2i1 %v2i2
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(
-      body,
-      HasSubstr(
-          R"(let x_1 : i32 = bitcast<i32>(max(bitcast<u32>(i1), bitcast<u32>(i2)));)"))
-      << body;
-  EXPECT_THAT(
-      body,
-      HasSubstr(
-          R"(let x_2 : vec2<i32> = bitcast<vec2<i32>>(max(bitcast<vec2<u32>>(v2i1), bitcast<vec2<u32>>(v2i2)));)"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(
+        body,
+        HasSubstr(R"(let x_1 : i32 = bitcast<i32>(max(bitcast<u32>(i1), bitcast<u32>(i2)));)"))
+        << body;
+    EXPECT_THAT(
+        body,
+        HasSubstr(
+            R"(let x_2 : vec2<i32> = bitcast<vec2<i32>>(max(bitcast<vec2<u32>>(v2i1), bitcast<vec2<u32>>(v2i2)));)"))
+        << body;
 }
 
 TEST_F(SpvParserTest, RectifyOperandsAndResult_UMin) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %1 = OpExtInst %int %glsl UMin %i1 %i2
      %2 = OpExtInst %v2int %glsl UMin %v2i1 %v2i2
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(
-      body,
-      HasSubstr(
-          R"(let x_1 : i32 = bitcast<i32>(min(bitcast<u32>(i1), bitcast<u32>(i2)));)"))
-      << body;
-  EXPECT_THAT(
-      body,
-      HasSubstr(
-          R"(let x_2 : vec2<i32> = bitcast<vec2<i32>>(min(bitcast<vec2<u32>>(v2i1), bitcast<vec2<u32>>(v2i2)));)"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(
+        body,
+        HasSubstr(R"(let x_1 : i32 = bitcast<i32>(min(bitcast<u32>(i1), bitcast<u32>(i2)));)"))
+        << body;
+    EXPECT_THAT(
+        body,
+        HasSubstr(
+            R"(let x_2 : vec2<i32> = bitcast<vec2<i32>>(min(bitcast<vec2<u32>>(v2i1), bitcast<vec2<u32>>(v2i2)));)"))
+        << body;
 }
 
 TEST_F(SpvParserTest, RectifyOperandsAndResult_UClamp) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %1 = OpExtInst %int %glsl UClamp %i1 %u2 %i3
      %2 = OpExtInst %v2int %glsl UClamp %v2i1 %v2u2 %v2i3
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(
-      body,
-      HasSubstr(
-          R"(let x_1 : i32 = bitcast<i32>(clamp(bitcast<u32>(i1), u2, bitcast<u32>(i3)));)"))
-      << body;
-  EXPECT_THAT(
-      body,
-      HasSubstr(
-          R"(let x_2 : vec2<i32> = bitcast<vec2<i32>>(clamp(bitcast<vec2<u32>>(v2i1), v2u2, bitcast<vec2<u32>>(v2i3)));)"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(
+        body,
+        HasSubstr(
+            R"(let x_1 : i32 = bitcast<i32>(clamp(bitcast<u32>(i1), u2, bitcast<u32>(i3)));)"))
+        << body;
+    EXPECT_THAT(
+        body,
+        HasSubstr(
+            R"(let x_2 : vec2<i32> = bitcast<vec2<i32>>(clamp(bitcast<vec2<u32>>(v2i1), v2u2, bitcast<vec2<u32>>(v2i3)));)"))
+        << body;
 }
 
 struct DataPackingCase {
-  std::string opcode;
-  std::string wgsl_func;
-  uint32_t vec_size;
+    std::string opcode;
+    std::string wgsl_func;
+    uint32_t vec_size;
 };
 
 inline std::ostream& operator<<(std::ostream& out, DataPackingCase c) {
-  out << "DataPacking(" << c.opcode << ")";
-  return out;
+    out << "DataPacking(" << c.opcode << ")";
+    return out;
 }
 
 using SpvParserTest_GlslStd450_DataPacking =
     SpvParserTestBase<::testing::TestWithParam<DataPackingCase>>;
 
 TEST_P(SpvParserTest_GlslStd450_DataPacking, Valid) {
-  auto param = GetParam();
-  const auto assembly = Preamble() + R"(
+    auto param = GetParam();
+    const auto assembly = Preamble() + R"(
   %1 = OpExtInst %uint %glsl )" +
-                        param.opcode +
-                        (param.vec_size == 2 ? " %v2f1" : " %v4f1") + R"(
+                          param.opcode + (param.vec_size == 2 ? " %v2f1" : " %v4f1") + R"(
   OpReturn
   OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body, HasSubstr("let x_1 : u32 = " + param.wgsl_func + "(v" +
-                              std::to_string(param.vec_size) + "f1);"))
-      << body;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : u32 = " + param.wgsl_func + "(v" +
+                                std::to_string(param.vec_size) + "f1);"))
+        << body;
 }
 
 INSTANTIATE_TEST_SUITE_P(Samples,
@@ -982,25 +939,24 @@
     SpvParserTestBase<::testing::TestWithParam<DataPackingCase>>;
 
 TEST_P(SpvParserTest_GlslStd450_DataUnpacking, Valid) {
-  auto param = GetParam();
-  const auto assembly = Preamble() + R"(
+    auto param = GetParam();
+    const auto assembly = Preamble() + R"(
   %1 = OpExtInst )" + (param.vec_size == 2 ? "%v2float" : "%v4float") +
-                        std::string(" %glsl ") + param.opcode + R"( %u1
+                          std::string(" %glsl ") + param.opcode + R"( %u1
   OpReturn
   OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body, HasSubstr("let x_1 : " +
-                              std::string(param.vec_size == 2 ? "vec2<f32>"
-                                                              : "vec4<f32>") +
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body, HasSubstr("let x_1 : " +
+                                std::string(param.vec_size == 2 ? "vec2<f32>" : "vec4<f32>") +
 
-                              +" = " + param.wgsl_func + "(u1);"))
-      << body;
+                                +" = " + param.wgsl_func + "(u1);"))
+        << body;
 }
 
 INSTANTIATE_TEST_SUITE_P(Samples,
@@ -1013,160 +969,157 @@
                              {"UnpackHalf2x16", "unpack2x16float", 2}}));
 
 TEST_F(SpvParserTest, GlslStd450_Refract_Scalar) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %1 = OpExtInst %float %glsl Refract %f1 %f2 %f3
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body = test::ToString(p->program(), ast_body);
-  const auto* expected =
-      R"(let x_1 : f32 = refract(vec2<f32>(f1, 0.0), vec2<f32>(f2, 0.0), f3).x;)";
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+    const auto* expected =
+        R"(let x_1 : f32 = refract(vec2<f32>(f1, 0.0), vec2<f32>(f2, 0.0), f3).x;)";
 
-  EXPECT_THAT(body, HasSubstr(expected)) << body;
+    EXPECT_THAT(body, HasSubstr(expected)) << body;
 }
 
 TEST_F(SpvParserTest, GlslStd450_Refract_Vector) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %1 = OpExtInst %v2float %glsl Refract %v2f1 %v2f2 %f3
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body = test::ToString(p->program(), ast_body);
-  const auto* expected = R"(let x_1 : vec2<f32> = refract(v2f1, v2f2, f3);)";
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+    const auto* expected = R"(let x_1 : vec2<f32> = refract(v2f1, v2f2, f3);)";
 
-  EXPECT_THAT(body, HasSubstr(expected)) << body;
+    EXPECT_THAT(body, HasSubstr(expected)) << body;
 }
 
 TEST_F(SpvParserTest, GlslStd450_FaceForward_Scalar) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %99 = OpFAdd %float %f1 %f1 ; normal operand has only one use
      %1 = OpExtInst %float %glsl FaceForward %99 %f2 %f3
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body = test::ToString(p->program(), ast_body);
-  // The %99 sum only has one use.  Ensure it is evaluated only once by
-  // making a let-declaration for it, since it is the normal operand to
-  // the builtin function, and code generation uses it twice.
-  const auto* expected =
-      R"(let x_1 : f32 = select(-(x_99), x_99, ((f2 * f3) < 0.0));)";
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+    // The %99 sum only has one use.  Ensure it is evaluated only once by
+    // making a let-declaration for it, since it is the normal operand to
+    // the builtin function, and code generation uses it twice.
+    const auto* expected = R"(let x_1 : f32 = select(-(x_99), x_99, ((f2 * f3) < 0.0));)";
 
-  EXPECT_THAT(body, HasSubstr(expected)) << body;
+    EXPECT_THAT(body, HasSubstr(expected)) << body;
 }
 
 TEST_F(SpvParserTest, GlslStd450_FaceForward_Vector) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %99 = OpFAdd %v2float %v2f1 %v2f1
      %1 = OpExtInst %v2float %glsl FaceForward %v2f1 %v2f2 %v2f3
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body = test::ToString(p->program(), ast_body);
-  const auto* expected =
-      R"(let x_1 : vec2<f32> = faceForward(v2f1, v2f2, v2f3);)";
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+    const auto* expected = R"(let x_1 : vec2<f32> = faceForward(v2f1, v2f2, v2f3);)";
 
-  EXPECT_THAT(body, HasSubstr(expected)) << body;
+    EXPECT_THAT(body, HasSubstr(expected)) << body;
 }
 
 TEST_F(SpvParserTest, GlslStd450_Reflect_Scalar) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %98 = OpFAdd %float %f1 %f1 ; has only one use
      %99 = OpFAdd %float %f2 %f2 ; has only one use
      %1 = OpExtInst %float %glsl Reflect %98 %99
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body = test::ToString(p->program(), ast_body);
-  // The %99 sum only has one use.  Ensure it is evaluated only once by
-  // making a let-declaration for it, since it is the normal operand to
-  // the builtin function, and code generation uses it twice.
-  const auto* expected =
-      R"(let x_1 : f32 = (x_98 - (2.0 * (x_99 * (x_99 * x_98))));)";
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+    // The %99 sum only has one use.  Ensure it is evaluated only once by
+    // making a let-declaration for it, since it is the normal operand to
+    // the builtin function, and code generation uses it twice.
+    const auto* expected = R"(let x_1 : f32 = (x_98 - (2.0 * (x_99 * (x_99 * x_98))));)";
 
-  EXPECT_THAT(body, HasSubstr(expected)) << body;
+    EXPECT_THAT(body, HasSubstr(expected)) << body;
 }
 
 TEST_F(SpvParserTest, GlslStd450_Reflect_Vector) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %98 = OpFAdd %v2float %v2f1 %v2f1
      %99 = OpFAdd %v2float %v2f2 %v2f2
      %1 = OpExtInst %v2float %glsl Reflect %98 %99
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body = test::ToString(p->program(), ast_body);
-  const auto* expected = R"(
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+    const auto* expected = R"(
 let x_98 : vec2<f32> = (v2f1 + v2f1);
 let x_99 : vec2<f32> = (v2f2 + v2f2);
 let x_1 : vec2<f32> = reflect(x_98, x_99);
 )";
 
-  EXPECT_THAT(body, HasSubstr(expected)) << body;
+    EXPECT_THAT(body, HasSubstr(expected)) << body;
 }
 
 // For ldexp with signed second argument, see above.
 TEST_F(SpvParserTest, GlslStd450_Ldexp_Scalar_Float_Uint) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %1 = OpExtInst %float %glsl Ldexp %f1 %u1
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body = test::ToString(p->program(), ast_body);
-  const auto* expected = "let x_1 : f32 = ldexp(f1, i32(u1));";
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+    const auto* expected = "let x_1 : f32 = ldexp(f1, i32(u1));";
 
-  EXPECT_THAT(body, HasSubstr(expected)) << body;
+    EXPECT_THAT(body, HasSubstr(expected)) << body;
 }
 
 TEST_F(SpvParserTest, GlslStd450_Ldexp_Vector_Floatvec_Uintvec) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %1 = OpExtInst %v2float %glsl Ldexp %v2f1 %v2u1
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body = test::ToString(p->program(), ast_body);
-  const auto* expected = "let x_1 : vec2<f32> = ldexp(v2f1, vec2<i32>(v2u1));";
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body = test::ToString(p->program(), ast_body);
+    const auto* expected = "let x_1 : vec2<f32> = ldexp(v2f1, vec2<i32>(v2u1));";
 
-  EXPECT_THAT(body, HasSubstr(expected)) << body;
+    EXPECT_THAT(body, HasSubstr(expected)) << body;
 }
 
 }  // namespace
diff --git a/src/tint/reader/spirv/function_logical_test.cc b/src/tint/reader/spirv/function_logical_test.cc
index 2d2e4e9..ba73d5d 100644
--- a/src/tint/reader/spirv/function_logical_test.cc
+++ b/src/tint/reader/spirv/function_logical_test.cc
@@ -23,7 +23,7 @@
 using ::testing::HasSubstr;
 
 std::string Preamble() {
-  return R"(
+    return R"(
   OpCapability Shader
   OpMemoryModel Logical Simple
   OpEntryPoint Fragment %100 "main"
@@ -69,135 +69,130 @@
 
 // Returns the AST dump for a given SPIR-V assembly constant.
 std::string AstFor(std::string assembly) {
-  if (assembly == "v2bool_t_f") {
-    return "vec2<bool>(true, false)";
-  }
-  if (assembly == "v2bool_f_t") {
-    return "vec2<bool>(false, true)";
-  }
-  if (assembly == "v2uint_10_20") {
-    return "vec2<u32>(10u, 20u)";
-  }
-  if (assembly == "cast_uint_10") {
-    return "bitcast<i32>(10u)";
-  }
-  if (assembly == "cast_uint_20") {
-    return "bitcast<i32>(20u)";
-  }
-  if (assembly == "cast_v2uint_10_20") {
-    return "bitcast<vec2<i32>>(vec2<u32>(10u, 20u))";
-  }
-  if (assembly == "v2uint_20_10") {
-    return "vec2<u32>(20u, 10u)";
-  }
-  if (assembly == "cast_v2uint_20_10") {
-    return "bitcast<vec2<i32>>(vec2<u32>(20u, 10u))";
-  }
-  if (assembly == "cast_int_30") {
-    return "bitcast<u32>(30)";
-  }
-  if (assembly == "cast_int_40") {
-    return "bitcast<u32>(40)";
-  }
-  if (assembly == "v2int_30_40") {
-    return "vec2<i32>(30, 40)";
-  }
-  if (assembly == "cast_v2int_30_40") {
-    return "bitcast<vec2<u32>>(vec2<i32>(30, 40))";
-  }
-  if (assembly == "v2int_40_30") {
-    return "vec2<i32>(40, 30)";
-  }
-  if (assembly == "cast_v2int_40_30") {
-    return "bitcast<vec2<u32>>(vec2<i32>(40, 30))";
-  }
-  if (assembly == "v2float_50_60") {
-    return "vec2<f32>(50.0, 60.0)";
-  }
-  if (assembly == "v2float_60_50") {
-    return "vec2<f32>(60.0, 50.0)";
-  }
-  return "bad case";
+    if (assembly == "v2bool_t_f") {
+        return "vec2<bool>(true, false)";
+    }
+    if (assembly == "v2bool_f_t") {
+        return "vec2<bool>(false, true)";
+    }
+    if (assembly == "v2uint_10_20") {
+        return "vec2<u32>(10u, 20u)";
+    }
+    if (assembly == "cast_uint_10") {
+        return "bitcast<i32>(10u)";
+    }
+    if (assembly == "cast_uint_20") {
+        return "bitcast<i32>(20u)";
+    }
+    if (assembly == "cast_v2uint_10_20") {
+        return "bitcast<vec2<i32>>(vec2<u32>(10u, 20u))";
+    }
+    if (assembly == "v2uint_20_10") {
+        return "vec2<u32>(20u, 10u)";
+    }
+    if (assembly == "cast_v2uint_20_10") {
+        return "bitcast<vec2<i32>>(vec2<u32>(20u, 10u))";
+    }
+    if (assembly == "cast_int_30") {
+        return "bitcast<u32>(30i)";
+    }
+    if (assembly == "cast_int_40") {
+        return "bitcast<u32>(40i)";
+    }
+    if (assembly == "v2int_30_40") {
+        return "vec2<i32>(30i, 40i)";
+    }
+    if (assembly == "cast_v2int_30_40") {
+        return "bitcast<vec2<u32>>(vec2<i32>(30i, 40i))";
+    }
+    if (assembly == "v2int_40_30") {
+        return "vec2<i32>(40i, 30i)";
+    }
+    if (assembly == "cast_v2int_40_30") {
+        return "bitcast<vec2<u32>>(vec2<i32>(40i, 30i))";
+    }
+    if (assembly == "v2float_50_60") {
+        return "vec2<f32>(50.0, 60.0)";
+    }
+    if (assembly == "v2float_60_50") {
+        return "vec2<f32>(60.0, 50.0)";
+    }
+    return "bad case";
 }
 
 using SpvUnaryLogicalTest = SpvParserTestBase<::testing::Test>;
 
 TEST_F(SpvUnaryLogicalTest, LogicalNot_Scalar) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpLogicalNot %bool %true
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : bool = !(true);"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr("let x_1 : bool = !(true);"));
 }
 
 TEST_F(SpvUnaryLogicalTest, LogicalNot_Vector) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpLogicalNot %v2bool %v2bool_t_f
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : vec2<bool> = !(vec2<bool>(true, false));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : vec2<bool> = !(vec2<bool>(true, false));"));
 }
 
 struct BinaryData {
-  const std::string res_type;
-  const std::string lhs;
-  const std::string op;
-  const std::string rhs;
-  const std::string ast_type;
-  const std::string ast_lhs;
-  const std::string ast_op;
-  const std::string ast_rhs;
+    const std::string res_type;
+    const std::string lhs;
+    const std::string op;
+    const std::string rhs;
+    const std::string ast_type;
+    const std::string ast_lhs;
+    const std::string ast_op;
+    const std::string ast_rhs;
 };
 inline std::ostream& operator<<(std::ostream& out, BinaryData data) {
-  out << "BinaryData{" << data.res_type << "," << data.lhs << "," << data.op
-      << "," << data.rhs << "," << data.ast_type << "," << data.ast_lhs << ","
-      << data.ast_op << "," << data.ast_rhs << "}";
-  return out;
+    out << "BinaryData{" << data.res_type << "," << data.lhs << "," << data.op << "," << data.rhs
+        << "," << data.ast_type << "," << data.ast_lhs << "," << data.ast_op << "," << data.ast_rhs
+        << "}";
+    return out;
 }
 
-using SpvBinaryLogicalTest =
-    SpvParserTestBase<::testing::TestWithParam<BinaryData>>;
+using SpvBinaryLogicalTest = SpvParserTestBase<::testing::TestWithParam<BinaryData>>;
 
 TEST_P(SpvBinaryLogicalTest, EmitExpression) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = )" + GetParam().op +
-                        " %" + GetParam().res_type + " %" + GetParam().lhs +
-                        " %" + GetParam().rhs + R"(
+                          " %" + GetParam().res_type + " %" + GetParam().lhs + " %" +
+                          GetParam().rhs + R"(
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << p->error() << "\n"
-      << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  std::ostringstream ss;
-  ss << "let x_1 : " << GetParam().ast_type << " = (" << GetParam().ast_lhs
-     << " " << GetParam().ast_op << " " << GetParam().ast_rhs << ");";
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr(ss.str()))
-      << assembly;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << "\n" << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    std::ostringstream ss;
+    ss << "let x_1 : " << GetParam().ast_type << " = (" << GetParam().ast_lhs << " "
+       << GetParam().ast_op << " " << GetParam().ast_rhs << ");";
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr(ss.str())) << assembly;
 }
 
 INSTANTIATE_TEST_SUITE_P(
@@ -205,780 +200,716 @@
     SpvBinaryLogicalTest,
     ::testing::Values(
         // uint uint
-        BinaryData{"bool", "uint_10", "OpIEqual", "uint_20", "bool", "10u",
-                   "==", "20u"},
+        BinaryData{"bool", "uint_10", "OpIEqual", "uint_20", "bool", "10u", "==", "20u"},
         // int int
-        BinaryData{"bool", "int_30", "OpIEqual", "int_40", "bool", "30",
-                   "==", "40"},
+        BinaryData{"bool", "int_30", "OpIEqual", "int_40", "bool", "30i", "==", "40i"},
         // uint int
         BinaryData{"bool", "uint_10", "OpIEqual", "int_40", "bool", "10u",
-                   "==", "bitcast<u32>(40)"},
+                   "==", "bitcast<u32>(40i)"},
         // int uint
-        BinaryData{"bool", "int_40", "OpIEqual", "uint_10", "bool", "40",
+        BinaryData{"bool", "int_40", "OpIEqual", "uint_10", "bool", "40i",
                    "==", "bitcast<i32>(10u)"},
         // v2uint v2uint
-        BinaryData{"v2bool", "v2uint_10_20", "OpIEqual", "v2uint_20_10",
-                   "vec2<bool>", AstFor("v2uint_10_20"),
-                   "==", AstFor("v2uint_20_10")},
+        BinaryData{"v2bool", "v2uint_10_20", "OpIEqual", "v2uint_20_10", "vec2<bool>",
+                   AstFor("v2uint_10_20"), "==", AstFor("v2uint_20_10")},
         // v2int v2int
-        BinaryData{"v2bool", "v2int_30_40", "OpIEqual", "v2int_40_30",
-                   "vec2<bool>", AstFor("v2int_30_40"),
-                   "==", AstFor("v2int_40_30")}));
+        BinaryData{"v2bool", "v2int_30_40", "OpIEqual", "v2int_40_30", "vec2<bool>",
+                   AstFor("v2int_30_40"), "==", AstFor("v2int_40_30")}));
 
-INSTANTIATE_TEST_SUITE_P(
-    SpvParserTest_FOrdEqual,
-    SpvBinaryLogicalTest,
-    ::testing::Values(BinaryData{"bool", "float_50", "OpFOrdEqual", "float_60",
-                                 "bool", "50.0", "==", "60.0"},
-                      BinaryData{"v2bool", "v2float_50_60", "OpFOrdEqual",
-                                 "v2float_60_50", "vec2<bool>",
-                                 AstFor("v2float_50_60"),
-                                 "==", AstFor("v2float_60_50")}));
+INSTANTIATE_TEST_SUITE_P(SpvParserTest_FOrdEqual,
+                         SpvBinaryLogicalTest,
+                         ::testing::Values(BinaryData{"bool", "float_50", "OpFOrdEqual", "float_60",
+                                                      "bool", "50.0", "==", "60.0"},
+                                           BinaryData{"v2bool", "v2float_50_60", "OpFOrdEqual",
+                                                      "v2float_60_50", "vec2<bool>",
+                                                      AstFor("v2float_50_60"),
+                                                      "==", AstFor("v2float_60_50")}));
 
 INSTANTIATE_TEST_SUITE_P(
     SpvParserTest_INotEqual,
     SpvBinaryLogicalTest,
     ::testing::Values(
         // Both uint
-        BinaryData{"bool", "uint_10", "OpINotEqual", "uint_20", "bool", "10u",
-                   "!=", "20u"},
+        BinaryData{"bool", "uint_10", "OpINotEqual", "uint_20", "bool", "10u", "!=", "20u"},
         // Both int
-        BinaryData{"bool", "int_30", "OpINotEqual", "int_40", "bool", "30",
-                   "!=", "40"},
+        BinaryData{"bool", "int_30", "OpINotEqual", "int_40", "bool", "30i", "!=", "40i"},
         // uint int
         BinaryData{"bool", "uint_10", "OpINotEqual", "int_40", "bool", "10u",
-                   "!=", "bitcast<u32>(40)"},
+                   "!=", "bitcast<u32>(40i)"},
         // int uint
-        BinaryData{"bool", "int_40", "OpINotEqual", "uint_10", "bool", "40",
+        BinaryData{"bool", "int_40", "OpINotEqual", "uint_10", "bool", "40i",
                    "!=", "bitcast<i32>(10u)"},
         // Both v2uint
-        BinaryData{"v2bool", "v2uint_10_20", "OpINotEqual", "v2uint_20_10",
-                   "vec2<bool>", AstFor("v2uint_10_20"),
-                   "!=", AstFor("v2uint_20_10")},
+        BinaryData{"v2bool", "v2uint_10_20", "OpINotEqual", "v2uint_20_10", "vec2<bool>",
+                   AstFor("v2uint_10_20"), "!=", AstFor("v2uint_20_10")},
         // Both v2int
-        BinaryData{"v2bool", "v2int_30_40", "OpINotEqual", "v2int_40_30",
-                   "vec2<bool>", AstFor("v2int_30_40"),
-                   "!=", AstFor("v2int_40_30")}));
+        BinaryData{"v2bool", "v2int_30_40", "OpINotEqual", "v2int_40_30", "vec2<bool>",
+                   AstFor("v2int_30_40"), "!=", AstFor("v2int_40_30")}));
 
-INSTANTIATE_TEST_SUITE_P(
-    SpvParserTest_FOrdNotEqual,
-    SpvBinaryLogicalTest,
-    ::testing::Values(BinaryData{"bool", "float_50", "OpFOrdNotEqual",
-                                 "float_60", "bool", "50.0", "!=", "60.0"},
-                      BinaryData{"v2bool", "v2float_50_60", "OpFOrdNotEqual",
-                                 "v2float_60_50", "vec2<bool>",
-                                 AstFor("v2float_50_60"),
-                                 "!=", AstFor("v2float_60_50")}));
+INSTANTIATE_TEST_SUITE_P(SpvParserTest_FOrdNotEqual,
+                         SpvBinaryLogicalTest,
+                         ::testing::Values(BinaryData{"bool", "float_50", "OpFOrdNotEqual",
+                                                      "float_60", "bool", "50.0", "!=", "60.0"},
+                                           BinaryData{"v2bool", "v2float_50_60", "OpFOrdNotEqual",
+                                                      "v2float_60_50", "vec2<bool>",
+                                                      AstFor("v2float_50_60"),
+                                                      "!=", AstFor("v2float_60_50")}));
 
-INSTANTIATE_TEST_SUITE_P(
-    SpvParserTest_FOrdLessThan,
-    SpvBinaryLogicalTest,
-    ::testing::Values(BinaryData{"bool", "float_50", "OpFOrdLessThan",
-                                 "float_60", "bool", "50.0", "<", "60.0"},
-                      BinaryData{"v2bool", "v2float_50_60", "OpFOrdLessThan",
-                                 "v2float_60_50", "vec2<bool>",
-                                 AstFor("v2float_50_60"), "<",
-                                 AstFor("v2float_60_50")}));
+INSTANTIATE_TEST_SUITE_P(SpvParserTest_FOrdLessThan,
+                         SpvBinaryLogicalTest,
+                         ::testing::Values(BinaryData{"bool", "float_50", "OpFOrdLessThan",
+                                                      "float_60", "bool", "50.0", "<", "60.0"},
+                                           BinaryData{"v2bool", "v2float_50_60", "OpFOrdLessThan",
+                                                      "v2float_60_50", "vec2<bool>",
+                                                      AstFor("v2float_50_60"), "<",
+                                                      AstFor("v2float_60_50")}));
 
-INSTANTIATE_TEST_SUITE_P(
-    SpvParserTest_FOrdLessThanEqual,
-    SpvBinaryLogicalTest,
-    ::testing::Values(BinaryData{"bool", "float_50", "OpFOrdLessThanEqual",
-                                 "float_60", "bool", "50.0", "<=", "60.0"},
-                      BinaryData{"v2bool", "v2float_50_60",
-                                 "OpFOrdLessThanEqual", "v2float_60_50",
-                                 "vec2<bool>", AstFor("v2float_50_60"),
-                                 "<=", AstFor("v2float_60_50")}));
+INSTANTIATE_TEST_SUITE_P(SpvParserTest_FOrdLessThanEqual,
+                         SpvBinaryLogicalTest,
+                         ::testing::Values(BinaryData{"bool", "float_50", "OpFOrdLessThanEqual",
+                                                      "float_60", "bool", "50.0", "<=", "60.0"},
+                                           BinaryData{"v2bool", "v2float_50_60",
+                                                      "OpFOrdLessThanEqual", "v2float_60_50",
+                                                      "vec2<bool>", AstFor("v2float_50_60"),
+                                                      "<=", AstFor("v2float_60_50")}));
 
-INSTANTIATE_TEST_SUITE_P(
-    SpvParserTest_FOrdGreaterThan,
-    SpvBinaryLogicalTest,
-    ::testing::Values(BinaryData{"bool", "float_50", "OpFOrdGreaterThan",
-                                 "float_60", "bool", "50.0", ">", "60.0"},
-                      BinaryData{"v2bool", "v2float_50_60", "OpFOrdGreaterThan",
-                                 "v2float_60_50", "vec2<bool>",
-                                 AstFor("v2float_50_60"), ">",
-                                 AstFor("v2float_60_50")}));
+INSTANTIATE_TEST_SUITE_P(SpvParserTest_FOrdGreaterThan,
+                         SpvBinaryLogicalTest,
+                         ::testing::Values(BinaryData{"bool", "float_50", "OpFOrdGreaterThan",
+                                                      "float_60", "bool", "50.0", ">", "60.0"},
+                                           BinaryData{"v2bool", "v2float_50_60",
+                                                      "OpFOrdGreaterThan", "v2float_60_50",
+                                                      "vec2<bool>", AstFor("v2float_50_60"), ">",
+                                                      AstFor("v2float_60_50")}));
 
-INSTANTIATE_TEST_SUITE_P(
-    SpvParserTest_FOrdGreaterThanEqual,
-    SpvBinaryLogicalTest,
-    ::testing::Values(BinaryData{"bool", "float_50", "OpFOrdGreaterThanEqual",
-                                 "float_60", "bool", "50.0", ">=", "60.0"},
-                      BinaryData{"v2bool", "v2float_50_60",
-                                 "OpFOrdGreaterThanEqual", "v2float_60_50",
-                                 "vec2<bool>", AstFor("v2float_50_60"),
-                                 ">=", AstFor("v2float_60_50")}));
+INSTANTIATE_TEST_SUITE_P(SpvParserTest_FOrdGreaterThanEqual,
+                         SpvBinaryLogicalTest,
+                         ::testing::Values(BinaryData{"bool", "float_50", "OpFOrdGreaterThanEqual",
+                                                      "float_60", "bool", "50.0", ">=", "60.0"},
+                                           BinaryData{"v2bool", "v2float_50_60",
+                                                      "OpFOrdGreaterThanEqual", "v2float_60_50",
+                                                      "vec2<bool>", AstFor("v2float_50_60"),
+                                                      ">=", AstFor("v2float_60_50")}));
 
 INSTANTIATE_TEST_SUITE_P(
     SpvParserTest_LogicalAnd,
     SpvBinaryLogicalTest,
-    ::testing::Values(BinaryData{"bool", "true", "OpLogicalAnd", "false",
-                                 "bool", "true", "&", "false"},
-                      BinaryData{"v2bool", "v2bool_t_f", "OpLogicalAnd",
-                                 "v2bool_f_t", "vec2<bool>",
-                                 AstFor("v2bool_t_f"), "&",
-                                 AstFor("v2bool_f_t")}));
+    ::testing::Values(BinaryData{"bool", "true", "OpLogicalAnd", "false", "bool", "true", "&",
+                                 "false"},
+                      BinaryData{"v2bool", "v2bool_t_f", "OpLogicalAnd", "v2bool_f_t", "vec2<bool>",
+                                 AstFor("v2bool_t_f"), "&", AstFor("v2bool_f_t")}));
 
 INSTANTIATE_TEST_SUITE_P(
     SpvParserTest_LogicalOr,
     SpvBinaryLogicalTest,
-    ::testing::Values(BinaryData{"bool", "true", "OpLogicalOr", "false", "bool",
-                                 "true", "|", "false"},
-                      BinaryData{"v2bool", "v2bool_t_f", "OpLogicalOr",
-                                 "v2bool_f_t", "vec2<bool>",
-                                 AstFor("v2bool_t_f"), "|",
-                                 AstFor("v2bool_f_t")}));
+    ::testing::Values(BinaryData{"bool", "true", "OpLogicalOr", "false", "bool", "true", "|",
+                                 "false"},
+                      BinaryData{"v2bool", "v2bool_t_f", "OpLogicalOr", "v2bool_f_t", "vec2<bool>",
+                                 AstFor("v2bool_t_f"), "|", AstFor("v2bool_f_t")}));
 
 INSTANTIATE_TEST_SUITE_P(
     SpvParserTest_LogicalEqual,
     SpvBinaryLogicalTest,
-    ::testing::Values(BinaryData{"bool", "true", "OpLogicalEqual", "false",
-                                 "bool", "true", "==", "false"},
-                      BinaryData{"v2bool", "v2bool_t_f", "OpLogicalEqual",
-                                 "v2bool_f_t", "vec2<bool>",
-                                 AstFor("v2bool_t_f"),
-                                 "==", AstFor("v2bool_f_t")}));
+    ::testing::Values(BinaryData{"bool", "true", "OpLogicalEqual", "false", "bool", "true",
+                                 "==", "false"},
+                      BinaryData{"v2bool", "v2bool_t_f", "OpLogicalEqual", "v2bool_f_t",
+                                 "vec2<bool>", AstFor("v2bool_t_f"), "==", AstFor("v2bool_f_t")}));
 
 INSTANTIATE_TEST_SUITE_P(
     SpvParserTest_LogicalNotEqual,
     SpvBinaryLogicalTest,
-    ::testing::Values(BinaryData{"bool", "true", "OpLogicalNotEqual", "false",
-                                 "bool", "true", "!=", "false"},
-                      BinaryData{"v2bool", "v2bool_t_f", "OpLogicalNotEqual",
-                                 "v2bool_f_t", "vec2<bool>",
-                                 AstFor("v2bool_t_f"),
-                                 "!=", AstFor("v2bool_f_t")}));
+    ::testing::Values(BinaryData{"bool", "true", "OpLogicalNotEqual", "false", "bool", "true",
+                                 "!=", "false"},
+                      BinaryData{"v2bool", "v2bool_t_f", "OpLogicalNotEqual", "v2bool_f_t",
+                                 "vec2<bool>", AstFor("v2bool_t_f"), "!=", AstFor("v2bool_f_t")}));
 
 INSTANTIATE_TEST_SUITE_P(
     SpvParserTest_UGreaterThan,
     SpvBinaryLogicalTest,
     ::testing::Values(
         // Both unsigned
-        BinaryData{"bool", "uint_10", "OpUGreaterThan", "uint_20", "bool",
-                   "10u", ">", "20u"},
+        BinaryData{"bool", "uint_10", "OpUGreaterThan", "uint_20", "bool", "10u", ">", "20u"},
         // First arg signed
-        BinaryData{"bool", "int_30", "OpUGreaterThan", "uint_20", "bool",
-                   AstFor("cast_int_30"), ">", "20u"},
+        BinaryData{"bool", "int_30", "OpUGreaterThan", "uint_20", "bool", AstFor("cast_int_30"),
+                   ">", "20u"},
         // Second arg signed
-        BinaryData{"bool", "uint_10", "OpUGreaterThan", "int_40", "bool", "10u",
-                   ">", AstFor("cast_int_40")},
+        BinaryData{"bool", "uint_10", "OpUGreaterThan", "int_40", "bool", "10u", ">",
+                   AstFor("cast_int_40")},
         // Vector, both unsigned
-        BinaryData{"v2bool", "v2uint_10_20", "OpUGreaterThan", "v2uint_20_10",
-                   "vec2<bool>", AstFor("v2uint_10_20"), ">",
-                   AstFor("v2uint_20_10")},
+        BinaryData{"v2bool", "v2uint_10_20", "OpUGreaterThan", "v2uint_20_10", "vec2<bool>",
+                   AstFor("v2uint_10_20"), ">", AstFor("v2uint_20_10")},
         // First arg signed
-        BinaryData{"v2bool", "v2int_30_40", "OpUGreaterThan", "v2uint_20_10",
-                   "vec2<bool>", AstFor("cast_v2int_30_40"), ">",
-                   AstFor("v2uint_20_10")},
+        BinaryData{"v2bool", "v2int_30_40", "OpUGreaterThan", "v2uint_20_10", "vec2<bool>",
+                   AstFor("cast_v2int_30_40"), ">", AstFor("v2uint_20_10")},
         // Second arg signed
-        BinaryData{"v2bool", "v2uint_10_20", "OpUGreaterThan", "v2int_40_30",
-                   "vec2<bool>", AstFor("v2uint_10_20"), ">",
-                   AstFor("cast_v2int_40_30")}));
+        BinaryData{"v2bool", "v2uint_10_20", "OpUGreaterThan", "v2int_40_30", "vec2<bool>",
+                   AstFor("v2uint_10_20"), ">", AstFor("cast_v2int_40_30")}));
 
 INSTANTIATE_TEST_SUITE_P(
     SpvParserTest_UGreaterThanEqual,
     SpvBinaryLogicalTest,
     ::testing::Values(
         // Both unsigned
-        BinaryData{"bool", "uint_10", "OpUGreaterThanEqual", "uint_20", "bool",
-                   "10u", ">=", "20u"},
+        BinaryData{"bool", "uint_10", "OpUGreaterThanEqual", "uint_20", "bool", "10u", ">=", "20u"},
         // First arg signed
         BinaryData{"bool", "int_30", "OpUGreaterThanEqual", "uint_20", "bool",
                    AstFor("cast_int_30"), ">=", "20u"},
         // Second arg signed
-        BinaryData{"bool", "uint_10", "OpUGreaterThanEqual", "int_40", "bool",
-                   "10u", ">=", AstFor("cast_int_40")},
+        BinaryData{"bool", "uint_10", "OpUGreaterThanEqual", "int_40", "bool", "10u",
+                   ">=", AstFor("cast_int_40")},
         // Vector, both unsigned
-        BinaryData{"v2bool", "v2uint_10_20", "OpUGreaterThanEqual",
-                   "v2uint_20_10", "vec2<bool>", AstFor("v2uint_10_20"),
-                   ">=", AstFor("v2uint_20_10")},
+        BinaryData{"v2bool", "v2uint_10_20", "OpUGreaterThanEqual", "v2uint_20_10", "vec2<bool>",
+                   AstFor("v2uint_10_20"), ">=", AstFor("v2uint_20_10")},
         // First arg signed
-        BinaryData{"v2bool", "v2int_30_40", "OpUGreaterThanEqual",
-                   "v2uint_20_10", "vec2<bool>", AstFor("cast_v2int_30_40"),
-                   ">=", AstFor("v2uint_20_10")},
+        BinaryData{"v2bool", "v2int_30_40", "OpUGreaterThanEqual", "v2uint_20_10", "vec2<bool>",
+                   AstFor("cast_v2int_30_40"), ">=", AstFor("v2uint_20_10")},
         // Second arg signed
-        BinaryData{"v2bool", "v2uint_10_20", "OpUGreaterThanEqual",
-                   "v2int_40_30", "vec2<bool>", AstFor("v2uint_10_20"),
-                   ">=", AstFor("cast_v2int_40_30")}));
+        BinaryData{"v2bool", "v2uint_10_20", "OpUGreaterThanEqual", "v2int_40_30", "vec2<bool>",
+                   AstFor("v2uint_10_20"), ">=", AstFor("cast_v2int_40_30")}));
 
 INSTANTIATE_TEST_SUITE_P(
     SpvParserTest_ULessThan,
     SpvBinaryLogicalTest,
     ::testing::Values(
         // Both unsigned
-        BinaryData{"bool", "uint_10", "OpULessThan", "uint_20", "bool", "10u",
-                   "<", "20u"},
+        BinaryData{"bool", "uint_10", "OpULessThan", "uint_20", "bool", "10u", "<", "20u"},
         // First arg signed
-        BinaryData{"bool", "int_30", "OpULessThan", "uint_20", "bool",
-                   AstFor("cast_int_30"), "<", "20u"},
+        BinaryData{"bool", "int_30", "OpULessThan", "uint_20", "bool", AstFor("cast_int_30"), "<",
+                   "20u"},
         // Second arg signed
-        BinaryData{"bool", "uint_10", "OpULessThan", "int_40", "bool", "10u",
-                   "<", AstFor("cast_int_40")},
+        BinaryData{"bool", "uint_10", "OpULessThan", "int_40", "bool", "10u", "<",
+                   AstFor("cast_int_40")},
         // Vector, both unsigned
-        BinaryData{"v2bool", "v2uint_10_20", "OpULessThan", "v2uint_20_10",
-                   "vec2<bool>", AstFor("v2uint_10_20"), "<",
-                   AstFor("v2uint_20_10")},
+        BinaryData{"v2bool", "v2uint_10_20", "OpULessThan", "v2uint_20_10", "vec2<bool>",
+                   AstFor("v2uint_10_20"), "<", AstFor("v2uint_20_10")},
         // First arg signed
-        BinaryData{"v2bool", "v2int_30_40", "OpULessThan", "v2uint_20_10",
-                   "vec2<bool>", AstFor("cast_v2int_30_40"), "<",
-                   AstFor("v2uint_20_10")},
+        BinaryData{"v2bool", "v2int_30_40", "OpULessThan", "v2uint_20_10", "vec2<bool>",
+                   AstFor("cast_v2int_30_40"), "<", AstFor("v2uint_20_10")},
         // Second arg signed
-        BinaryData{"v2bool", "v2uint_10_20", "OpULessThan", "v2int_40_30",
-                   "vec2<bool>", AstFor("v2uint_10_20"), "<",
-                   AstFor("cast_v2int_40_30")}));
+        BinaryData{"v2bool", "v2uint_10_20", "OpULessThan", "v2int_40_30", "vec2<bool>",
+                   AstFor("v2uint_10_20"), "<", AstFor("cast_v2int_40_30")}));
 
 INSTANTIATE_TEST_SUITE_P(
     SpvParserTest_ULessThanEqual,
     SpvBinaryLogicalTest,
     ::testing::Values(
         // Both unsigned
-        BinaryData{"bool", "uint_10", "OpULessThanEqual", "uint_20", "bool",
-                   "10u", "<=", "20u"},
+        BinaryData{"bool", "uint_10", "OpULessThanEqual", "uint_20", "bool", "10u", "<=", "20u"},
         // First arg signed
-        BinaryData{"bool", "int_30", "OpULessThanEqual", "uint_20", "bool",
-                   AstFor("cast_int_30"), "<=", "20u"},
+        BinaryData{"bool", "int_30", "OpULessThanEqual", "uint_20", "bool", AstFor("cast_int_30"),
+                   "<=", "20u"},
         // Second arg signed
-        BinaryData{"bool", "uint_10", "OpULessThanEqual", "int_40", "bool",
-                   "10u", "<=", AstFor("cast_int_40")},
+        BinaryData{"bool", "uint_10", "OpULessThanEqual", "int_40", "bool", "10u",
+                   "<=", AstFor("cast_int_40")},
         // Vector, both unsigned
-        BinaryData{"v2bool", "v2uint_10_20", "OpULessThanEqual", "v2uint_20_10",
-                   "vec2<bool>", AstFor("v2uint_10_20"),
-                   "<=", AstFor("v2uint_20_10")},
+        BinaryData{"v2bool", "v2uint_10_20", "OpULessThanEqual", "v2uint_20_10", "vec2<bool>",
+                   AstFor("v2uint_10_20"), "<=", AstFor("v2uint_20_10")},
         // First arg signed
-        BinaryData{"v2bool", "v2int_30_40", "OpULessThanEqual", "v2uint_20_10",
-                   "vec2<bool>", AstFor("cast_v2int_30_40"),
-                   "<=", AstFor("v2uint_20_10")},
+        BinaryData{"v2bool", "v2int_30_40", "OpULessThanEqual", "v2uint_20_10", "vec2<bool>",
+                   AstFor("cast_v2int_30_40"), "<=", AstFor("v2uint_20_10")},
         // Second arg signed
-        BinaryData{"v2bool", "v2uint_10_20", "OpULessThanEqual", "v2int_40_30",
-                   "vec2<bool>", AstFor("v2uint_10_20"),
-                   "<=", AstFor("cast_v2int_40_30")}));
+        BinaryData{"v2bool", "v2uint_10_20", "OpULessThanEqual", "v2int_40_30", "vec2<bool>",
+                   AstFor("v2uint_10_20"), "<=", AstFor("cast_v2int_40_30")}));
 
 INSTANTIATE_TEST_SUITE_P(
     SpvParserTest_SGreaterThan,
     SpvBinaryLogicalTest,
     ::testing::Values(
         // Both signed
-        BinaryData{"bool", "int_30", "OpSGreaterThan", "int_40", "bool", "30",
-                   ">", "40"},
+        BinaryData{"bool", "int_30", "OpSGreaterThan", "int_40", "bool", "30i", ">", "40i"},
         // First arg unsigned
-        BinaryData{"bool", "uint_10", "OpSGreaterThan", "int_40", "bool",
-                   AstFor("cast_uint_10"), ">", "40"},
+        BinaryData{"bool", "uint_10", "OpSGreaterThan", "int_40", "bool", AstFor("cast_uint_10"),
+                   ">", "40i"},
         // Second arg unsigned
-        BinaryData{"bool", "int_30", "OpSGreaterThan", "uint_20", "bool", "30",
-                   ">", AstFor("cast_uint_20")},
+        BinaryData{"bool", "int_30", "OpSGreaterThan", "uint_20", "bool", "30i", ">",
+                   AstFor("cast_uint_20")},
         // Vector, both signed
-        BinaryData{"v2bool", "v2int_30_40", "OpSGreaterThan", "v2int_40_30",
-                   "vec2<bool>", AstFor("v2int_30_40"), ">",
-                   AstFor("v2int_40_30")},
+        BinaryData{"v2bool", "v2int_30_40", "OpSGreaterThan", "v2int_40_30", "vec2<bool>",
+                   AstFor("v2int_30_40"), ">", AstFor("v2int_40_30")},
         // First arg unsigned
-        BinaryData{"v2bool", "v2uint_10_20", "OpSGreaterThan", "v2int_40_30",
-                   "vec2<bool>", AstFor("cast_v2uint_10_20"), ">",
-                   AstFor("v2int_40_30")},
+        BinaryData{"v2bool", "v2uint_10_20", "OpSGreaterThan", "v2int_40_30", "vec2<bool>",
+                   AstFor("cast_v2uint_10_20"), ">", AstFor("v2int_40_30")},
         // Second arg unsigned
-        BinaryData{"v2bool", "v2int_30_40", "OpSGreaterThan", "v2uint_20_10",
-                   "vec2<bool>", AstFor("v2int_30_40"), ">",
-                   AstFor("cast_v2uint_20_10")}));
+        BinaryData{"v2bool", "v2int_30_40", "OpSGreaterThan", "v2uint_20_10", "vec2<bool>",
+                   AstFor("v2int_30_40"), ">", AstFor("cast_v2uint_20_10")}));
 
 INSTANTIATE_TEST_SUITE_P(
     SpvParserTest_SGreaterThanEqual,
     SpvBinaryLogicalTest,
     ::testing::Values(
         // Both signed
-        BinaryData{"bool", "int_30", "OpSGreaterThanEqual", "int_40", "bool",
-                   "30", ">=", "40"},
+        BinaryData{"bool", "int_30", "OpSGreaterThanEqual", "int_40", "bool", "30i", ">=", "40i"},
         // First arg unsigned
         BinaryData{"bool", "uint_10", "OpSGreaterThanEqual", "int_40", "bool",
-                   AstFor("cast_uint_10"), ">=", "40"},
+                   AstFor("cast_uint_10"), ">=", "40i"},
         // Second arg unsigned
-        BinaryData{"bool", "int_30", "OpSGreaterThanEqual", "uint_20", "bool",
-                   "30", ">=", AstFor("cast_uint_20")},
+        BinaryData{"bool", "int_30", "OpSGreaterThanEqual", "uint_20", "bool", "30i",
+                   ">=", AstFor("cast_uint_20")},
         // Vector, both signed
-        BinaryData{"v2bool", "v2int_30_40", "OpSGreaterThanEqual",
-                   "v2int_40_30", "vec2<bool>", AstFor("v2int_30_40"),
-                   ">=", AstFor("v2int_40_30")},
+        BinaryData{"v2bool", "v2int_30_40", "OpSGreaterThanEqual", "v2int_40_30", "vec2<bool>",
+                   AstFor("v2int_30_40"), ">=", AstFor("v2int_40_30")},
         // First arg unsigned
-        BinaryData{"v2bool", "v2uint_10_20", "OpSGreaterThanEqual",
-                   "v2int_40_30", "vec2<bool>", AstFor("cast_v2uint_10_20"),
-                   ">=", AstFor("v2int_40_30")},
+        BinaryData{"v2bool", "v2uint_10_20", "OpSGreaterThanEqual", "v2int_40_30", "vec2<bool>",
+                   AstFor("cast_v2uint_10_20"), ">=", AstFor("v2int_40_30")},
         // Second arg unsigned
-        BinaryData{"v2bool", "v2int_30_40", "OpSGreaterThanEqual",
-                   "v2uint_20_10", "vec2<bool>", AstFor("v2int_30_40"),
-                   ">=", AstFor("cast_v2uint_20_10")}));
+        BinaryData{"v2bool", "v2int_30_40", "OpSGreaterThanEqual", "v2uint_20_10", "vec2<bool>",
+                   AstFor("v2int_30_40"), ">=", AstFor("cast_v2uint_20_10")}));
 
 INSTANTIATE_TEST_SUITE_P(
     SpvParserTest_SLessThan,
     SpvBinaryLogicalTest,
     ::testing::Values(
         // Both signed
-        BinaryData{"bool", "int_30", "OpSLessThan", "int_40", "bool", "30", "<",
-                   "40"},
+        BinaryData{"bool", "int_30", "OpSLessThan", "int_40", "bool", "30i", "<", "40i"},
         // First arg unsigned
-        BinaryData{"bool", "uint_10", "OpSLessThan", "int_40", "bool",
-                   AstFor("cast_uint_10"), "<", "40"},
+        BinaryData{"bool", "uint_10", "OpSLessThan", "int_40", "bool", AstFor("cast_uint_10"), "<",
+                   "40i"},
         // Second arg unsigned
-        BinaryData{"bool", "int_30", "OpSLessThan", "uint_20", "bool", "30",
-                   "<", AstFor("cast_uint_20")},
+        BinaryData{"bool", "int_30", "OpSLessThan", "uint_20", "bool", "30i", "<",
+                   AstFor("cast_uint_20")},
         // Vector, both signed
-        BinaryData{"v2bool", "v2int_30_40", "OpSLessThan", "v2int_40_30",
-                   "vec2<bool>", AstFor("v2int_30_40"), "<",
-                   AstFor("v2int_40_30")},
+        BinaryData{"v2bool", "v2int_30_40", "OpSLessThan", "v2int_40_30", "vec2<bool>",
+                   AstFor("v2int_30_40"), "<", AstFor("v2int_40_30")},
         // First arg unsigned
-        BinaryData{"v2bool", "v2uint_10_20", "OpSLessThan", "v2int_40_30",
-                   "vec2<bool>", AstFor("cast_v2uint_10_20"), "<",
-                   AstFor("v2int_40_30")},
+        BinaryData{"v2bool", "v2uint_10_20", "OpSLessThan", "v2int_40_30", "vec2<bool>",
+                   AstFor("cast_v2uint_10_20"), "<", AstFor("v2int_40_30")},
         // Second arg unsigned
-        BinaryData{"v2bool", "v2int_30_40", "OpSLessThan", "v2uint_20_10",
-                   "vec2<bool>", AstFor("v2int_30_40"), "<",
-                   AstFor("cast_v2uint_20_10")}));
+        BinaryData{"v2bool", "v2int_30_40", "OpSLessThan", "v2uint_20_10", "vec2<bool>",
+                   AstFor("v2int_30_40"), "<", AstFor("cast_v2uint_20_10")}));
 
 INSTANTIATE_TEST_SUITE_P(
     SpvParserTest_SLessThanEqual,
     SpvBinaryLogicalTest,
     ::testing::Values(
         // Both signed
-        BinaryData{"bool", "int_30", "OpSLessThanEqual", "int_40", "bool", "30",
-                   "<=", "40"},
+        BinaryData{"bool", "int_30", "OpSLessThanEqual", "int_40", "bool", "30i", "<=", "40i"},
         // First arg unsigned
-        BinaryData{"bool", "uint_10", "OpSLessThanEqual", "int_40", "bool",
-                   AstFor("cast_uint_10"), "<=", "40"},
+        BinaryData{"bool", "uint_10", "OpSLessThanEqual", "int_40", "bool", AstFor("cast_uint_10"),
+                   "<=", "40i"},
         // Second arg unsigned
-        BinaryData{"bool", "int_30", "OpSLessThanEqual", "uint_20", "bool",
-                   "30", "<=", AstFor("cast_uint_20")},
+        BinaryData{"bool", "int_30", "OpSLessThanEqual", "uint_20", "bool", "30i",
+                   "<=", AstFor("cast_uint_20")},
         // Vector, both signed
-        BinaryData{"v2bool", "v2int_30_40", "OpSLessThanEqual", "v2int_40_30",
-                   "vec2<bool>", AstFor("v2int_30_40"),
-                   "<=", AstFor("v2int_40_30")},
+        BinaryData{"v2bool", "v2int_30_40", "OpSLessThanEqual", "v2int_40_30", "vec2<bool>",
+                   AstFor("v2int_30_40"), "<=", AstFor("v2int_40_30")},
         // First arg unsigned
-        BinaryData{"v2bool", "v2uint_10_20", "OpSLessThanEqual", "v2int_40_30",
-                   "vec2<bool>", AstFor("cast_v2uint_10_20"),
-                   "<=", AstFor("v2int_40_30")},
+        BinaryData{"v2bool", "v2uint_10_20", "OpSLessThanEqual", "v2int_40_30", "vec2<bool>",
+                   AstFor("cast_v2uint_10_20"), "<=", AstFor("v2int_40_30")},
         // Second arg unsigned
-        BinaryData{"v2bool", "v2int_30_40", "OpSLessThanEqual", "v2uint_20_10",
-                   "vec2<bool>", AstFor("v2int_30_40"),
-                   "<=", AstFor("cast_v2uint_20_10")}));
+        BinaryData{"v2bool", "v2int_30_40", "OpSLessThanEqual", "v2uint_20_10", "vec2<bool>",
+                   AstFor("v2int_30_40"), "<=", AstFor("cast_v2uint_20_10")}));
 
 using SpvFUnordTest = SpvParserTestBase<::testing::Test>;
 
 TEST_F(SpvFUnordTest, FUnordEqual_Scalar) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpFUnordEqual %bool %float_50 %float_60
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : bool = !((50.0 != 60.0));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : bool = !((50.0 != 60.0));"));
 }
 
 TEST_F(SpvFUnordTest, FUnordEqual_Vector) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpFUnordEqual %v2bool %v2float_50_60 %v2float_60_50
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(
-      test::ToString(p->program(), ast_body),
-      HasSubstr("let x_1 : vec2<bool> = "
-                "!((vec2<f32>(50.0, 60.0) != vec2<f32>(60.0, 50.0)));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : vec2<bool> = "
+                          "!((vec2<f32>(50.0, 60.0) != vec2<f32>(60.0, 50.0)));"));
 }
 
 TEST_F(SpvFUnordTest, FUnordNotEqual_Scalar) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpFUnordNotEqual %bool %float_50 %float_60
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : bool = !((50.0 == 60.0));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : bool = !((50.0 == 60.0));"));
 }
 
 TEST_F(SpvFUnordTest, FUnordNotEqual_Vector) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpFUnordNotEqual %v2bool %v2float_50_60 %v2float_60_50
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(
-      test::ToString(p->program(), ast_body),
-      HasSubstr("let x_1 : vec2<bool> = "
-                "!((vec2<f32>(50.0, 60.0) == vec2<f32>(60.0, 50.0)));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : vec2<bool> = "
+                          "!((vec2<f32>(50.0, 60.0) == vec2<f32>(60.0, 50.0)));"));
 }
 
 TEST_F(SpvFUnordTest, FUnordLessThan_Scalar) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpFUnordLessThan %bool %float_50 %float_60
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : bool = !((50.0 >= 60.0));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : bool = !((50.0 >= 60.0));"));
 }
 
 TEST_F(SpvFUnordTest, FUnordLessThan_Vector) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpFUnordLessThan %v2bool %v2float_50_60 %v2float_60_50
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(
-      test::ToString(p->program(), ast_body),
-      HasSubstr("let x_1 : vec2<bool> = "
-                "!((vec2<f32>(50.0, 60.0) >= vec2<f32>(60.0, 50.0)));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : vec2<bool> = "
+                          "!((vec2<f32>(50.0, 60.0) >= vec2<f32>(60.0, 50.0)));"));
 }
 
 TEST_F(SpvFUnordTest, FUnordLessThanEqual_Scalar) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpFUnordLessThanEqual %bool %float_50 %float_60
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : bool = !((50.0 > 60.0));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : bool = !((50.0 > 60.0));"));
 }
 
 TEST_F(SpvFUnordTest, FUnordLessThanEqual_Vector) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpFUnordLessThanEqual %v2bool %v2float_50_60 %v2float_60_50
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : vec2<bool> = "
-                        "!((vec2<f32>(50.0, 60.0) > vec2<f32>(60.0, 50.0)));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : vec2<bool> = "
+                          "!((vec2<f32>(50.0, 60.0) > vec2<f32>(60.0, 50.0)));"));
 }
 
 TEST_F(SpvFUnordTest, FUnordGreaterThan_Scalar) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpFUnordGreaterThan %bool %float_50 %float_60
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : bool = !((50.0 <= 60.0));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : bool = !((50.0 <= 60.0));"));
 }
 
 TEST_F(SpvFUnordTest, FUnordGreaterThan_Vector) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpFUnordGreaterThan %v2bool %v2float_50_60 %v2float_60_50
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(
-      test::ToString(p->program(), ast_body),
-      HasSubstr("let x_1 : vec2<bool> = "
-                "!((vec2<f32>(50.0, 60.0) <= vec2<f32>(60.0, 50.0)));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : vec2<bool> = "
+                          "!((vec2<f32>(50.0, 60.0) <= vec2<f32>(60.0, 50.0)));"));
 }
 
 TEST_F(SpvFUnordTest, FUnordGreaterThanEqual_Scalar) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpFUnordGreaterThanEqual %bool %float_50 %float_60
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : bool = !((50.0 < 60.0));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : bool = !((50.0 < 60.0));"));
 }
 
 TEST_F(SpvFUnordTest, FUnordGreaterThanEqual_Vector) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpFUnordGreaterThanEqual %v2bool %v2float_50_60 %v2float_60_50
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : vec2<bool> = !(("
-                        "vec2<f32>(50.0, 60.0) < vec2<f32>(60.0, 50.0)"
-                        "));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : vec2<bool> = !(("
+                          "vec2<f32>(50.0, 60.0) < vec2<f32>(60.0, 50.0)"
+                          "));"));
 }
 
 using SpvLogicalTest = SpvParserTestBase<::testing::Test>;
 
 TEST_F(SpvLogicalTest, Select_BoolCond_BoolParams) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpSelect %bool %true %true %false
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : bool = select(false, true, true);"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : bool = select(false, true, true);"));
 }
 
 TEST_F(SpvLogicalTest, Select_BoolCond_IntScalarParams) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpSelect %uint %true %uint_10 %uint_20
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : u32 = select(20u, 10u, true);"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : u32 = select(20u, 10u, true);"));
 }
 
 TEST_F(SpvLogicalTest, Select_BoolCond_FloatScalarParams) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpSelect %float %true %float_50 %float_60
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : f32 = select(60.0, 50.0, true);"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : f32 = select(60.0, 50.0, true);"));
 }
 
 TEST_F(SpvLogicalTest, Select_BoolCond_VectorParams) {
-  // Prior to SPIR-V 1.4, the condition must be a vector of bools
-  // when the value operands are vectors.
-  // "Before version 1.4, results are only computed per component."
-  const auto assembly = Preamble() + R"(
+    // Prior to SPIR-V 1.4, the condition must be a vector of bools
+    // when the value operands are vectors.
+    // "Before version 1.4, results are only computed per component."
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpSelect %v2uint %true %v2uint_10_20 %v2uint_20_10
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : vec2<u32> = select("
-                        "vec2<u32>(20u, 10u), "
-                        "vec2<u32>(10u, 20u), "
-                        "true);"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr("let x_1 : vec2<u32> = select("
+                                                                  "vec2<u32>(20u, 10u), "
+                                                                  "vec2<u32>(10u, 20u), "
+                                                                  "true);"));
 
-  // Fails validation prior to SPIR-V 1.4: If the value operands are vectors,
-  // then the condition must be a vector.
-  // "Expected vector sizes of Result Type and the condition to be equal:
-  // Select"
-  p->DeliberatelyInvalidSpirv();
+    // Fails validation prior to SPIR-V 1.4: If the value operands are vectors,
+    // then the condition must be a vector.
+    // "Expected vector sizes of Result Type and the condition to be equal:
+    // Select"
+    p->DeliberatelyInvalidSpirv();
 }
 
 TEST_F(SpvLogicalTest, Select_VecBoolCond_VectorParams) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpSelect %v2uint %v2bool_t_f %v2uint_10_20 %v2uint_20_10
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : vec2<u32> = select("
-                        "vec2<u32>(20u, 10u), "
-                        "vec2<u32>(10u, 20u), "
-                        "vec2<bool>(true, false));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr("let x_1 : vec2<u32> = select("
+                                                                  "vec2<u32>(20u, 10u), "
+                                                                  "vec2<u32>(10u, 20u), "
+                                                                  "vec2<bool>(true, false));"));
 }
 
 TEST_F(SpvLogicalTest, Any) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpAny %bool %v2bool_t_f
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : bool = any(vec2<bool>(true, false));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : bool = any(vec2<bool>(true, false));"));
 }
 
 TEST_F(SpvLogicalTest, All) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpAll %bool %v2bool_t_f
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : bool = all(vec2<bool>(true, false));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : bool = all(vec2<bool>(true, false));"));
 }
 
 TEST_F(SpvLogicalTest, IsNan_Scalar) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpIsNan %bool %float_50
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : bool = isNan(50.0);"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr("let x_1 : bool = isNan(50.0);"));
 }
 
 TEST_F(SpvLogicalTest, IsNan_Vector) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpIsNan %v2bool %v2float_50_60
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(
-      test::ToString(p->program(), ast_body),
-      HasSubstr("let x_1 : vec2<bool> = isNan(vec2<f32>(50.0, 60.0));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : vec2<bool> = isNan(vec2<f32>(50.0, 60.0));"));
 }
 
 TEST_F(SpvLogicalTest, IsInf_Scalar) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpIsInf %bool %float_50
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_1 : bool = isInf(50.0);"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr("let x_1 : bool = isInf(50.0);"));
 }
 
 TEST_F(SpvLogicalTest, IsInf_Vector) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpIsInf %v2bool %v2float_50_60
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(
-      test::ToString(p->program(), ast_body),
-      HasSubstr("let x_1 : vec2<bool> = isInf(vec2<f32>(50.0, 60.0));"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_1 : vec2<bool> = isInf(vec2<f32>(50.0, 60.0));"));
 }
 
 // TODO(dneto): Kernel-guarded instructions.
diff --git a/src/tint/reader/spirv/function_memory_test.cc b/src/tint/reader/spirv/function_memory_test.cc
index 33fa2f5..58cceda 100644
--- a/src/tint/reader/spirv/function_memory_test.cc
+++ b/src/tint/reader/spirv/function_memory_test.cc
@@ -26,7 +26,7 @@
 using SpvParserMemoryTest = SpvParserTest;
 
 std::string Preamble() {
-  return R"(
+    return R"(
     OpCapability Shader
     OpMemoryModel Logical Simple
     OpEntryPoint Fragment %100 "main"
@@ -35,7 +35,7 @@
 }
 
 TEST_F(SpvParserMemoryTest, EmitStatement_StoreBoolConst) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
      %void = OpTypeVoid
      %voidfn = OpTypeFunction %void
      %ty = OpTypeBool
@@ -52,18 +52,18 @@
      OpReturn
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr(R"(x_1 = true;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr(R"(x_1 = true;
 x_1 = false;
 x_1 = false;
 )"));
 }
 
 TEST_F(SpvParserMemoryTest, EmitStatement_StoreUintConst) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
      %void = OpTypeVoid
      %voidfn = OpTypeFunction %void
      %ty = OpTypeInt 32 0
@@ -78,17 +78,17 @@
      OpReturn
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody());
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr(R"(x_1 = 42u;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody());
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr(R"(x_1 = 42u;
 x_1 = 0u;
 )"));
 }
 
 TEST_F(SpvParserMemoryTest, EmitStatement_StoreIntConst) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
      %void = OpTypeVoid
      %voidfn = OpTypeFunction %void
      %ty = OpTypeInt 32 1
@@ -103,17 +103,18 @@
      OpReturn
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody());
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr(R"(x_1 = 42;
-x_1 = 0;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody());
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr(R"(x_1 = 42i;
+x_1 = 0i;
+return;
 )"));
 }
 
 TEST_F(SpvParserMemoryTest, EmitStatement_StoreFloatConst) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
      %void = OpTypeVoid
      %voidfn = OpTypeFunction %void
      %ty = OpTypeFloat 32
@@ -128,17 +129,17 @@
      OpReturn
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody());
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr(R"(x_1 = 42.0;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody());
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr(R"(x_1 = 42.0;
 x_1 = 0.0;
 )"));
 }
 
 TEST_F(SpvParserMemoryTest, EmitStatement_LoadBool) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
      %void = OpTypeVoid
      %voidfn = OpTypeFunction %void
      %ty = OpTypeBool
@@ -153,16 +154,15 @@
      OpReturn
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_2 : bool = x_1;"));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr("let x_2 : bool = x_1;"));
 }
 
 TEST_F(SpvParserMemoryTest, EmitStatement_LoadScalar) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
      %void = OpTypeVoid
      %voidfn = OpTypeFunction %void
      %ty = OpTypeInt 32 0
@@ -176,18 +176,17 @@
      OpReturn
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr(R"(let x_2 : u32 = x_1;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr(R"(let x_2 : u32 = x_1;
 let x_3 : u32 = x_1;
 )"));
 }
 
 TEST_F(SpvParserMemoryTest, EmitStatement_UseLoadedScalarTwice) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
      %void = OpTypeVoid
      %voidfn = OpTypeFunction %void
      %ty = OpTypeInt 32 0
@@ -202,19 +201,18 @@
      OpReturn
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr(R"(let x_2 : u32 = x_1;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr(R"(let x_2 : u32 = x_1;
 x_1 = x_2;
 x_1 = x_2;
 )"));
 }
 
 TEST_F(SpvParserMemoryTest, EmitStatement_StoreToModuleScopeVar) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
      %void = OpTypeVoid
      %voidfn = OpTypeFunction %void
      %ty = OpTypeInt 32 0
@@ -227,16 +225,15 @@
      OpReturn
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody());
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr("x_1 = 42u;"));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody());
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr("x_1 = 42u;"));
 }
 
-TEST_F(SpvParserMemoryTest,
-       EmitStatement_CopyMemory_Scalar_Function_To_Private) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+TEST_F(SpvParserMemoryTest, EmitStatement_CopyMemory_Scalar_Function_To_Private) {
+    auto p = parser(test::Assemble(Preamble() + R"(
      %void = OpTypeVoid
      %voidfn = OpTypeFunction %void
      %ty = OpTypeInt 32 0
@@ -251,17 +248,17 @@
      OpReturn
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody());
-  auto ast_body = fe.ast_body();
-  const auto got = test::ToString(p->program(), ast_body);
-  const auto* expected = "x_2 = x_1;";
-  EXPECT_THAT(got, HasSubstr(expected));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody());
+    auto ast_body = fe.ast_body();
+    const auto got = test::ToString(p->program(), ast_body);
+    const auto* expected = "x_2 = x_1;";
+    EXPECT_THAT(got, HasSubstr(expected));
 }
 
 TEST_F(SpvParserMemoryTest, EmitStatement_AccessChain_BaseIsNotPointer) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
      %void = OpTypeVoid
      %voidfn = OpTypeFunction %void
      %10 = OpTypeInt 32 0
@@ -274,12 +271,12 @@
      OpStore %1 %val
      OpReturn
   )"));
-  EXPECT_FALSE(p->BuildAndParseInternalModuleExceptFunctions());
-  EXPECT_THAT(p->error(), Eq("variable with ID 20 has non-pointer type 10"));
+    EXPECT_FALSE(p->BuildAndParseInternalModuleExceptFunctions());
+    EXPECT_THAT(p->error(), Eq("variable with ID 20 has non-pointer type 10"));
 }
 
 TEST_F(SpvParserMemoryTest, EmitStatement_AccessChain_VectorSwizzle) {
-  const std::string assembly = Preamble() + R"(
+    const std::string assembly = Preamble() + R"(
      OpName %1 "myvar"
      %void = OpTypeVoid
      %voidfn = OpTypeFunction %void
@@ -297,18 +294,16 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << assembly << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody());
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("myvar.z = 42u;"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody());
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr("myvar.z = 42u;"));
 }
 
 TEST_F(SpvParserMemoryTest, EmitStatement_AccessChain_VectorConstOutOfBounds) {
-  const std::string assembly = Preamble() + R"(
+    const std::string assembly = Preamble() + R"(
      OpName %1 "myvar"
      %void = OpTypeVoid
      %voidfn = OpTypeFunction %void
@@ -326,17 +321,16 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << assembly << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(fe.EmitBody());
-  EXPECT_THAT(p->error(), Eq("Access chain %2 index %42 value 42 is out of "
-                             "bounds for vector of 4 elements"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(fe.EmitBody());
+    EXPECT_THAT(p->error(), Eq("Access chain %2 index %42 value 42 is out of "
+                               "bounds for vector of 4 elements"));
 }
 
 TEST_F(SpvParserMemoryTest, EmitStatement_AccessChain_VectorNonConstIndex) {
-  const std::string assembly = Preamble() + R"(
+    const std::string assembly = Preamble() + R"(
      OpName %1 "myvar"
      OpName %13 "a_dynamic_index"
      %void = OpTypeVoid
@@ -359,21 +353,18 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << assembly << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody());
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("myvar[a_dynamic_index] = 42u;"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody());
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr("myvar[a_dynamic_index] = 42u;"));
 }
 
-TEST_F(SpvParserMemoryTest,
-       EmitStatement_AccessChain_VectorComponent_MultiUse) {
-  // WGSL does not support pointer-to-vector-component, so test that we sink
-  // these pointers into the point of use.
-  const std::string assembly = Preamble() + R"(
+TEST_F(SpvParserMemoryTest, EmitStatement_AccessChain_VectorComponent_MultiUse) {
+    // WGSL does not support pointer-to-vector-component, so test that we sink
+    // these pointers into the point of use.
+    const std::string assembly = Preamble() + R"(
      OpName %1 "myvar"
      %void = OpTypeVoid
      %voidfn = OpTypeFunction %void
@@ -393,23 +384,21 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << assembly << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto wgsl = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(wgsl, Not(HasSubstr("&")));
-  EXPECT_THAT(wgsl, HasSubstr(" = myvar.z;"));
-  EXPECT_THAT(wgsl, HasSubstr("myvar.z = "));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto wgsl = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(wgsl, Not(HasSubstr("&")));
+    EXPECT_THAT(wgsl, HasSubstr(" = myvar.z;"));
+    EXPECT_THAT(wgsl, HasSubstr("myvar.z = "));
 }
 
-TEST_F(SpvParserMemoryTest,
-       EmitStatement_AccessChain_VectorComponent_MultiUse_NonConstIndex) {
-  // WGSL does not support pointer-to-vector-component, so test that we sink
-  // these pointers into the point of use.
-  const std::string assembly = Preamble() + R"(
+TEST_F(SpvParserMemoryTest, EmitStatement_AccessChain_VectorComponent_MultiUse_NonConstIndex) {
+    // WGSL does not support pointer-to-vector-component, so test that we sink
+    // these pointers into the point of use.
+    const std::string assembly = Preamble() + R"(
      OpName %1 "myvar"
      %void = OpTypeVoid
      %voidfn = OpTypeFunction %void
@@ -431,23 +420,21 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << assembly << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto wgsl = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(wgsl, Not(HasSubstr("&")));
-  EXPECT_THAT(wgsl, HasSubstr(" = myvar[x_12];"));
-  EXPECT_THAT(wgsl, HasSubstr("myvar[x_12] = "));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto wgsl = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(wgsl, Not(HasSubstr("&")));
+    EXPECT_THAT(wgsl, HasSubstr(" = myvar[x_12];"));
+    EXPECT_THAT(wgsl, HasSubstr("myvar[x_12] = "));
 }
 
-TEST_F(SpvParserMemoryTest,
-       EmitStatement_AccessChain_VectorComponent_SinkThroughChain) {
-  // Test that we can sink a pointer-to-vector-component through a chain of
-  // instructions that propagate it.
-  const std::string assembly = Preamble() + R"(
+TEST_F(SpvParserMemoryTest, EmitStatement_AccessChain_VectorComponent_SinkThroughChain) {
+    // Test that we can sink a pointer-to-vector-component through a chain of
+    // instructions that propagate it.
+    const std::string assembly = Preamble() + R"(
      OpName %1 "myvar"
      %void = OpTypeVoid
      %voidfn = OpTypeFunction %void
@@ -470,20 +457,19 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << assembly << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  auto wgsl = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(wgsl, Not(HasSubstr("&")));
-  EXPECT_THAT(wgsl, HasSubstr(" = myvar.z;"));
-  EXPECT_THAT(wgsl, HasSubstr("myvar.z = "));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    auto wgsl = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(wgsl, Not(HasSubstr("&")));
+    EXPECT_THAT(wgsl, HasSubstr(" = myvar.z;"));
+    EXPECT_THAT(wgsl, HasSubstr("myvar.z = "));
 }
 
 TEST_F(SpvParserMemoryTest, EmitStatement_AccessChain_Matrix) {
-  const std::string assembly = Preamble() + R"(
+    const std::string assembly = Preamble() + R"(
      OpName %1 "myvar"
      %void = OpTypeVoid
      %voidfn = OpTypeFunction %void
@@ -505,18 +491,17 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << assembly << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody());
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("myvar[2u] = vec4<f32>(42.0, 42.0, 42.0, 42.0);"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody());
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("myvar[2u] = vec4<f32>(42.0, 42.0, 42.0, 42.0);"));
 }
 
 TEST_F(SpvParserMemoryTest, EmitStatement_AccessChain_Array) {
-  const std::string assembly = Preamble() + R"(
+    const std::string assembly = Preamble() + R"(
      OpName %1 "myvar"
      %void = OpTypeVoid
      %voidfn = OpTypeFunction %void
@@ -538,18 +523,17 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << assembly << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody());
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("myvar[2u] = vec4<f32>(42.0, 42.0, 42.0, 42.0);"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody());
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("myvar[2u] = vec4<f32>(42.0, 42.0, 42.0, 42.0);"));
 }
 
 TEST_F(SpvParserMemoryTest, EmitStatement_AccessChain_Struct) {
-  const std::string assembly = Preamble() + R"(
+    const std::string assembly = Preamble() + R"(
      OpName %1 "myvar"
      OpMemberName %strct 1 "age"
      %void = OpTypeVoid
@@ -570,23 +554,20 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << assembly << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody());
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("myvar.age = 42.0;"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody());
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr("myvar.age = 42.0;"));
 }
 
-TEST_F(SpvParserMemoryTest,
-       EmitStatement_AccessChain_Struct_DifferOnlyMemberName) {
-  // The spirv-opt internal representation will map both structs to the
-  // same canonicalized type, because it doesn't care about member names.
-  // But we care about member names when producing a member-access expression.
-  // crbug.com/tint/213
-  const std::string assembly = Preamble() + R"(
+TEST_F(SpvParserMemoryTest, EmitStatement_AccessChain_Struct_DifferOnlyMemberName) {
+    // The spirv-opt internal representation will map both structs to the
+    // same canonicalized type, because it doesn't care about member names.
+    // But we care about member names when producing a member-access expression.
+    // crbug.com/tint/213
+    const std::string assembly = Preamble() + R"(
      OpName %1 "myvar"
      OpName %10 "myvar2"
      OpMemberName %strct 1 "age"
@@ -615,20 +596,18 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << assembly << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody());
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr(R"(myvar.age = 42.0;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody());
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr(R"(myvar.age = 42.0;
 myvar2.ancientness = 420.0;
 )"));
 }
 
 TEST_F(SpvParserMemoryTest, EmitStatement_AccessChain_StructNonConstIndex) {
-  const std::string assembly = Preamble() + R"(
+    const std::string assembly = Preamble() + R"(
      OpName %1 "myvar"
      OpMemberName %55 1 "age"
      %void = OpTypeVoid
@@ -652,17 +631,16 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << assembly << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(fe.EmitBody());
-  EXPECT_THAT(p->error(), Eq("Access chain %2 index %10 is a non-constant "
-                             "index into a structure %55"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(fe.EmitBody());
+    EXPECT_THAT(p->error(), Eq("Access chain %2 index %10 is a non-constant "
+                               "index into a structure %55"));
 }
 
 TEST_F(SpvParserMemoryTest, EmitStatement_AccessChain_StructConstOutOfBounds) {
-  const std::string assembly = Preamble() + R"(
+    const std::string assembly = Preamble() + R"(
      OpName %1 "myvar"
      OpMemberName %55 1 "age"
      %void = OpTypeVoid
@@ -683,17 +661,16 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << assembly << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(fe.EmitBody());
-  EXPECT_THAT(p->error(), Eq("Access chain %2 index value 99 is out of bounds "
-                             "for structure %55 having 2 members"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(fe.EmitBody());
+    EXPECT_THAT(p->error(), Eq("Access chain %2 index value 99 is out of bounds "
+                               "for structure %55 having 2 members"));
 }
 
 TEST_F(SpvParserMemoryTest, EmitStatement_AccessChain_Struct_RuntimeArray) {
-  const std::string assembly = Preamble() + R"(
+    const std::string assembly = Preamble() + R"(
      OpName %1 "myvar"
      OpMemberName %strct 1 "age"
 
@@ -724,18 +701,16 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << assembly << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody());
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("myvar.age[2u] = 42.0;"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody());
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr("myvar.age[2u] = 42.0;"));
 }
 
 TEST_F(SpvParserMemoryTest, EmitStatement_AccessChain_Compound_Matrix_Vector) {
-  const std::string assembly = Preamble() + R"(
+    const std::string assembly = Preamble() + R"(
      OpName %1 "myvar"
      %void = OpTypeVoid
      %voidfn = OpTypeFunction %void
@@ -757,18 +732,16 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << assembly << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody());
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("myvar[2u].w = 42.0;"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody());
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr("myvar[2u].w = 42.0;"));
 }
 
 TEST_F(SpvParserMemoryTest, EmitStatement_AccessChain_InvalidPointeeType) {
-  const std::string assembly = Preamble() + R"(
+    const std::string assembly = Preamble() + R"(
      OpName %1 "myvar"
      %55 = OpTypeVoid
      %voidfn = OpTypeFunction %55
@@ -785,20 +758,18 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << assembly << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_FALSE(fe.EmitBody());
-  EXPECT_THAT(p->error(),
-              HasSubstr("Access chain with unknown or invalid pointee type "
-                        "%60: %60 = OpTypePointer Private %55"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_FALSE(fe.EmitBody());
+    EXPECT_THAT(p->error(), HasSubstr("Access chain with unknown or invalid pointee type "
+                                      "%60: %60 = OpTypePointer Private %55"));
 }
 
 TEST_F(SpvParserMemoryTest, EmitStatement_AccessChain_DereferenceBase) {
-  // The base operand to OpAccessChain may have to be dereferenced first.
-  // crbug.com/tint/737
-  const std::string assembly = Preamble() + R"(
+    // The base operand to OpAccessChain may have to be dereferenced first.
+    // crbug.com/tint/737
+    const std::string assembly = Preamble() + R"(
      %void = OpTypeVoid
      %voidfn = OpTypeFunction %void
 
@@ -825,10 +796,10 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule());
-  const auto got = test::ToString(p->program());
-  const std::string expected = R"(fn x_200(x_1 : ptr<private, vec2<u32>>) {
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule());
+    const auto got = test::ToString(p->program());
+    const std::string expected = R"(fn x_200(x_1 : ptr<private, vec2<u32>>) {
   let x_3 : u32 = (*(x_1)).x;
   return;
 }
@@ -842,16 +813,15 @@
   main_1();
 }
 )";
-  EXPECT_EQ(got, expected) << got;
+    EXPECT_EQ(got, expected) << got;
 }
 
-TEST_F(SpvParserMemoryTest,
-       EmitStatement_AccessChain_InferFunctionStorageClass) {
-  // An access chain can have no indices. When the base is a Function variable,
-  // the reference type has no explicit storage class in the AST representation.
-  // But the pointer type for the let declaration must have an explicit
-  // 'function' storage class. From crbug.com/tint/807
-  const std::string assembly = R"(
+TEST_F(SpvParserMemoryTest, EmitStatement_AccessChain_InferFunctionStorageClass) {
+    // An access chain can have no indices. When the base is a Function variable,
+    // the reference type has no explicit storage class in the AST representation.
+    // But the pointer type for the let declaration must have an explicit
+    // 'function' storage class. From crbug.com/tint/807
+    const std::string assembly = R"(
 OpCapability Shader
 OpMemoryModel Logical Simple
 OpEntryPoint Fragment %main "main"
@@ -869,10 +839,10 @@
           OpReturn
           OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << assembly;
-  const auto got = test::ToString(p->program());
-  const std::string expected = R"(fn main_1() {
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << assembly;
+    const auto got = test::ToString(p->program());
+    const std::string expected = R"(fn main_1() {
   var x_1 : u32;
   let x_2 : ptr<function, u32> = &(x_1);
   return;
@@ -883,11 +853,11 @@
   main_1();
 }
 )";
-  EXPECT_EQ(got, expected) << got;
+    EXPECT_EQ(got, expected) << got;
 }
 
 std::string OldStorageBufferPreamble() {
-  return Preamble() + R"(
+    return Preamble() + R"(
      OpName %myvar "myvar"
 
      OpDecorate %myvar DescriptorSet 0
@@ -915,21 +885,20 @@
 }
 
 TEST_F(SpvParserMemoryTest, RemapStorageBuffer_TypesAndVarDeclarations) {
-  // Enusure we get the right module-scope declaration.  This tests translation
-  // of the structure type, arrays of the structure, pointers to them, and
-  // OpVariable of these.
-  const auto assembly = OldStorageBufferPreamble() + R"(
+    // Enusure we get the right module-scope declaration.  This tests translation
+    // of the structure type, arrays of the structure, pointers to them, and
+    // OpVariable of these.
+    const auto assembly = OldStorageBufferPreamble() + R"(
   ; The preamble declared %100 to be an entry point, so supply it.
   %100 = OpFunction %void None %voidfn
   %entry = OpLabel
   OpReturn
   OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << assembly << p->error();
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(module_str, HasSubstr(R"(type RTArr = @stride(4) array<u32>;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly << p->error();
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr(R"(type RTArr = @stride(4) array<u32>;
 
 struct S {
   field0 : u32,
@@ -941,7 +910,7 @@
 }
 
 TEST_F(SpvParserMemoryTest, RemapStorageBuffer_ThroughAccessChain_NonCascaded) {
-  const auto assembly = OldStorageBufferPreamble() + R"(
+    const auto assembly = OldStorageBufferPreamble() + R"(
   %100 = OpFunction %void None %voidfn
   %entry = OpLabel
 
@@ -956,21 +925,20 @@
   OpReturn
   OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << assembly << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto got = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(got, HasSubstr(R"(myvar.field0 = 0u;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << assembly << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto got = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(got, HasSubstr(R"(myvar.field0 = 0u;
 myvar.field1[1u] = 0u;
 )"));
 }
 
-TEST_F(SpvParserMemoryTest,
-       RemapStorageBuffer_ThroughAccessChain_NonCascaded_InBoundsAccessChain) {
-  // Like the previous test, but using OpInBoundsAccessChain.
-  const auto assembly = OldStorageBufferPreamble() + R"(
+TEST_F(SpvParserMemoryTest, RemapStorageBuffer_ThroughAccessChain_NonCascaded_InBoundsAccessChain) {
+    // Like the previous test, but using OpInBoundsAccessChain.
+    const auto assembly = OldStorageBufferPreamble() + R"(
   %100 = OpFunction %void None %voidfn
   %entry = OpLabel
 
@@ -985,20 +953,20 @@
   OpReturn
   OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << assembly << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto got = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(got, HasSubstr(R"(myvar.field0 = 0u;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << assembly << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto got = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(got, HasSubstr(R"(myvar.field0 = 0u;
 myvar.field1[1u] = 0u;
 )")) << got
      << p->error();
 }
 
 TEST_F(SpvParserMemoryTest, RemapStorageBuffer_ThroughAccessChain_Cascaded) {
-  const auto assembly = OldStorageBufferPreamble() + R"(
+    const auto assembly = OldStorageBufferPreamble() + R"(
   %ptr_rtarr = OpTypePointer Uniform %arr
   %100 = OpFunction %void None %voidfn
   %entry = OpLabel
@@ -1012,23 +980,21 @@
   OpReturn
   OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << assembly << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("myvar.field1[1u] = 0u;"))
-      << p->error();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << assembly << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr("myvar.field1[1u] = 0u;"))
+        << p->error();
 }
 
-TEST_F(SpvParserMemoryTest,
-       RemapStorageBuffer_ThroughCopyObject_WithoutHoisting) {
-  // Generates a const declaration directly.
-  // We have to do a bunch of storage class tracking for locally
-  // defined values in order to get the right pointer-to-storage-buffer
-  // value type for the const declration.
-  const auto assembly = OldStorageBufferPreamble() + R"(
+TEST_F(SpvParserMemoryTest, RemapStorageBuffer_ThroughCopyObject_WithoutHoisting) {
+    // Generates a const declaration directly.
+    // We have to do a bunch of storage class tracking for locally
+    // defined values in order to get the right pointer-to-storage-buffer
+    // value type for the const declration.
+    const auto assembly = OldStorageBufferPreamble() + R"(
   %100 = OpFunction %void None %voidfn
   %entry = OpLabel
 
@@ -1039,28 +1005,27 @@
   OpReturn
   OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << assembly << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr(R"(let x_2 : ptr<storage, u32> = &(myvar.field1[1u]);
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << assembly << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr(R"(let x_2 : ptr<storage, u32> = &(myvar.field1[1u]);
 *(x_2) = 0u;
 )")) << p->error();
 
-  p->SkipDumpingPending(
-      "crbug.com/tint/1041 track access mode in spirv-reader parser type");
+    p->SkipDumpingPending("crbug.com/tint/1041 track access mode in spirv-reader parser type");
 }
 
 TEST_F(SpvParserMemoryTest, RemapStorageBuffer_ThroughCopyObject_WithHoisting) {
-  // TODO(dneto): Hoisting non-storable values (pointers) is not yet supported.
-  // It's debatable whether this test should run at all.
-  // crbug.com/tint/98
+    // TODO(dneto): Hoisting non-storable values (pointers) is not yet supported.
+    // It's debatable whether this test should run at all.
+    // crbug.com/tint/98
 
-  // Like the previous test, but the declaration for the copy-object
-  // has its declaration hoisted.
-  const auto assembly = OldStorageBufferPreamble() + R"(
+    // Like the previous test, but the declaration for the copy-object
+    // has its declaration hoisted.
+    const auto assembly = OldStorageBufferPreamble() + R"(
   %bool = OpTypeBool
   %cond = OpConstantTrue %bool
 
@@ -1085,13 +1050,13 @@
 
   OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << assembly << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_EQ(test::ToString(p->program(), ast_body),
-            R"(var x_2 : ptr<storage, u32>;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << assembly << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_EQ(test::ToString(p->program(), ast_body),
+              R"(var x_2 : ptr<storage, u32>;
 if (true) {
   x_2 = &(myvar.field1[1u]);
 } else {
@@ -1100,19 +1065,18 @@
 x_2 = 0u;
 return;
 )") << p->error();
-  p->SkipDumpingPending("crbug.com/tint/98");
+    p->SkipDumpingPending("crbug.com/tint/98");
 }
 
 TEST_F(SpvParserMemoryTest, DISABLED_RemapStorageBuffer_ThroughFunctionCall) {
-  // WGSL does not support pointer-to-storage-buffer as function parameter
+    // WGSL does not support pointer-to-storage-buffer as function parameter
 }
-TEST_F(SpvParserMemoryTest,
-       DISABLED_RemapStorageBuffer_ThroughFunctionParameter) {
-  // WGSL does not support pointer-to-storage-buffer as function parameter
+TEST_F(SpvParserMemoryTest, DISABLED_RemapStorageBuffer_ThroughFunctionParameter) {
+    // WGSL does not support pointer-to-storage-buffer as function parameter
 }
 
 std::string RuntimeArrayPreamble() {
-  return R"(
+    return R"(
      OpCapability Shader
      OpMemoryModel Logical Simple
      OpEntryPoint Fragment %100 "main"
@@ -1147,7 +1111,7 @@
 }
 
 TEST_F(SpvParserMemoryTest, ArrayLength_FromVar) {
-  const auto assembly = RuntimeArrayPreamble() + R"(
+    const auto assembly = RuntimeArrayPreamble() + R"(
 
   %100 = OpFunction %void None %voidfn
 
@@ -1156,19 +1120,17 @@
   OpReturn
   OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << assembly << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body_str = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body_str,
-              HasSubstr("let x_1 : u32 = arrayLength(&(myvar.rtarr));"))
-      << body_str;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << assembly << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body_str = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body_str, HasSubstr("let x_1 : u32 = arrayLength(&(myvar.rtarr));")) << body_str;
 }
 
 TEST_F(SpvParserMemoryTest, ArrayLength_FromCopyObject) {
-  const auto assembly = RuntimeArrayPreamble() + R"(
+    const auto assembly = RuntimeArrayPreamble() + R"(
 
   %100 = OpFunction %void None %voidfn
 
@@ -1178,22 +1140,21 @@
   OpReturn
   OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << assembly << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body_str = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body_str, HasSubstr(R"(let x_2 : ptr<storage, S> = &(myvar);
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << assembly << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body_str = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body_str, HasSubstr(R"(let x_2 : ptr<storage, S> = &(myvar);
 let x_1 : u32 = arrayLength(&((*(x_2)).rtarr));
 )")) << body_str;
 
-  p->SkipDumpingPending(
-      "crbug.com/tint/1041 track access mode in spirv-reader parser type");
+    p->SkipDumpingPending("crbug.com/tint/1041 track access mode in spirv-reader parser type");
 }
 
 TEST_F(SpvParserMemoryTest, ArrayLength_FromAccessChain) {
-  const auto assembly = RuntimeArrayPreamble() + R"(
+    const auto assembly = RuntimeArrayPreamble() + R"(
 
   %100 = OpFunction %void None %voidfn
 
@@ -1203,19 +1164,17 @@
   OpReturn
   OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << assembly << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto body_str = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(body_str,
-              HasSubstr("let x_1 : u32 = arrayLength(&(myvar.rtarr));"))
-      << body_str;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << assembly << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto body_str = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(body_str, HasSubstr("let x_1 : u32 = arrayLength(&(myvar.rtarr));")) << body_str;
 }
 
 std::string InvalidPointerPreamble() {
-  return R"(
+    return R"(
 OpCapability Shader
 OpMemoryModel Logical Simple
 OpEntryPoint Fragment %main "main"
@@ -1230,7 +1189,7 @@
 }
 
 TEST_F(SpvParserMemoryTest, InvalidPointer_Undef_ModuleScope_IsError) {
-  const std::string assembly = InvalidPointerPreamble() + R"(
+    const std::string assembly = InvalidPointerPreamble() + R"(
  %ptr = OpUndef %ptr_ty
 
   %main = OpFunction %void None %voidfn
@@ -1245,13 +1204,13 @@
           OpReturn
           OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_FALSE(p->BuildAndParseInternalModule()) << assembly;
-  EXPECT_EQ(p->error(), "undef pointer is not valid: %9 = OpUndef %6");
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_FALSE(p->BuildAndParseInternalModule()) << assembly;
+    EXPECT_EQ(p->error(), "undef pointer is not valid: %9 = OpUndef %6");
 }
 
 TEST_F(SpvParserMemoryTest, InvalidPointer_Undef_FunctionScope_IsError) {
-  const std::string assembly = InvalidPointerPreamble() + R"(
+    const std::string assembly = InvalidPointerPreamble() + R"(
 
   %main = OpFunction %void None %voidfn
  %entry = OpLabel
@@ -1259,15 +1218,15 @@
           OpReturn
           OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_FALSE(p->BuildAndParseInternalModule()) << assembly;
-  EXPECT_EQ(p->error(), "undef pointer is not valid: %7 = OpUndef %3");
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_FALSE(p->BuildAndParseInternalModule()) << assembly;
+    EXPECT_EQ(p->error(), "undef pointer is not valid: %7 = OpUndef %3");
 }
 
 TEST_F(SpvParserMemoryTest, InvalidPointer_ConstantNull_IsError) {
-  // OpConstantNull on logical pointer requires variable-pointers, which
-  // is not (yet) supported by WGSL features.
-  const std::string assembly = InvalidPointerPreamble() + R"(
+    // OpConstantNull on logical pointer requires variable-pointers, which
+    // is not (yet) supported by WGSL features.
+    const std::string assembly = InvalidPointerPreamble() + R"(
  %ptr = OpConstantNull %ptr_ty
 
   %main = OpFunction %void None %voidfn
@@ -1282,9 +1241,9 @@
           OpReturn
           OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_FALSE(p->BuildAndParseInternalModule());
-  EXPECT_EQ(p->error(), "null pointer is not valid: %9 = OpConstantNull %6");
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_FALSE(p->BuildAndParseInternalModule());
+    EXPECT_EQ(p->error(), "null pointer is not valid: %9 = OpConstantNull %6");
 }
 
 }  // namespace
diff --git a/src/tint/reader/spirv/function_misc_test.cc b/src/tint/reader/spirv/function_misc_test.cc
index e64eb2e..9d40ffc 100644
--- a/src/tint/reader/spirv/function_misc_test.cc
+++ b/src/tint/reader/spirv/function_misc_test.cc
@@ -24,7 +24,7 @@
 using ::testing::HasSubstr;
 
 std::string Preamble() {
-  return R"(
+    return R"(
    OpCapability Shader
    OpMemoryModel Logical Simple
    OpEntryPoint Fragment %100 "main"
@@ -33,7 +33,7 @@
 }
 
 std::string CommonTypes() {
-  return R"(
+    return R"(
   %void = OpTypeVoid
   %voidfn = OpTypeFunction %void
 
@@ -52,7 +52,7 @@
 using SpvParserTestMiscInstruction = SpvParserTest;
 
 TEST_F(SpvParserTestMiscInstruction, OpUndef_BeforeFunction_Scalar) {
-  const auto assembly = Preamble() + CommonTypes() + R"(
+    const auto assembly = Preamble() + CommonTypes() + R"(
      %1 = OpUndef %bool
      %2 = OpUndef %uint
      %3 = OpUndef %int
@@ -67,21 +67,20 @@
      OpReturn
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr(R"(let x_11 : bool = false;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr(R"(let x_11 : bool = false;
 let x_12 : u32 = 0u;
-let x_13 : i32 = 0;
+let x_13 : i32 = 0i;
 let x_14 : f32 = 0.0;
 )"));
 }
 
 TEST_F(SpvParserTestMiscInstruction, OpUndef_BeforeFunction_Vector) {
-  const auto assembly = Preamble() + CommonTypes() + R"(
+    const auto assembly = Preamble() + CommonTypes() + R"(
      %4 = OpUndef %v2bool
      %1 = OpUndef %v2uint
      %2 = OpUndef %v2int
@@ -97,13 +96,13 @@
      OpReturn
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr(R"(let x_14 : vec2<bool> = vec2<bool>();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr(R"(let x_14 : vec2<bool> = vec2<bool>();
 let x_11 : vec2<u32> = vec2<u32>();
 let x_12 : vec2<i32> = vec2<i32>();
 let x_13 : vec2<f32> = vec2<f32>();
@@ -111,7 +110,7 @@
 }
 
 TEST_F(SpvParserTestMiscInstruction, OpUndef_InFunction_Scalar) {
-  const auto assembly = Preamble() + CommonTypes() + R"(
+    const auto assembly = Preamble() + CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpUndef %bool
@@ -126,21 +125,20 @@
      OpReturn
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr(R"(let x_11 : bool = false;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr(R"(let x_11 : bool = false;
 let x_12 : u32 = 0u;
-let x_13 : i32 = 0;
+let x_13 : i32 = 0i;
 let x_14 : f32 = 0.0;
 )"));
 }
 
 TEST_F(SpvParserTestMiscInstruction, OpUndef_InFunction_Vector) {
-  const auto assembly = Preamble() + CommonTypes() + R"(
+    const auto assembly = Preamble() + CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpUndef %v2uint
@@ -153,20 +151,20 @@
      OpReturn
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr(R"(let x_11 : vec2<u32> = vec2<u32>();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr(R"(let x_11 : vec2<u32> = vec2<u32>();
 let x_12 : vec2<i32> = vec2<i32>();
 let x_13 : vec2<f32> = vec2<f32>();
 )"));
 }
 
 TEST_F(SpvParserTestMiscInstruction, OpUndef_InFunction_Matrix) {
-  const auto assembly = Preamble() + CommonTypes() + R"(
+    const auto assembly = Preamble() + CommonTypes() + R"(
      %mat = OpTypeMatrix %v2float 2
 
      %100 = OpFunction %void None %voidfn
@@ -177,17 +175,17 @@
      OpReturn
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_11 : mat2x2<f32> = mat2x2<f32>();"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_11 : mat2x2<f32> = mat2x2<f32>();"));
 }
 
 TEST_F(SpvParserTestMiscInstruction, OpUndef_InFunction_Array) {
-  const auto assembly = Preamble() + CommonTypes() + R"(
+    const auto assembly = Preamble() + CommonTypes() + R"(
      %uint_2 = OpConstant %uint 2
      %arr = OpTypeArray %uint %uint_2
 
@@ -199,17 +197,17 @@
      OpReturn
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_11 : array<u32, 2u> = array<u32, 2u>();"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_11 : array<u32, 2u> = array<u32, 2u>();"));
 }
 
 TEST_F(SpvParserTestMiscInstruction, OpUndef_InFunction_Struct) {
-  const auto assembly = Preamble() + CommonTypes() + R"(
+    const auto assembly = Preamble() + CommonTypes() + R"(
      %strct = OpTypeStruct %bool %uint %int %float
 
      %100 = OpFunction %void None %voidfn
@@ -220,82 +218,79 @@
      OpReturn
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("let x_11 : S = S(false, 0u, 0, 0.0);"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("let x_11 : S = S(false, 0u, 0i, 0.0);"));
 }
 
 TEST_F(SpvParserTestMiscInstruction, OpNop) {
-  const auto assembly = Preamble() + CommonTypes() + R"(
+    const auto assembly = Preamble() + CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      OpNop
      OpReturn
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << p->error() << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  EXPECT_EQ(test::ToString(p->program(), ast_body), "return;\n");
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error() << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    EXPECT_EQ(test::ToString(p->program(), ast_body), "return;\n");
 }
 
 // Test swizzle generation.
 
 struct SwizzleCase {
-  uint32_t index;
-  std::string expected_expr;
-  std::string expected_error;
+    uint32_t index;
+    std::string expected_expr;
+    std::string expected_error;
 };
-using SpvParserSwizzleTest =
-    SpvParserTestBase<::testing::TestWithParam<SwizzleCase>>;
+using SpvParserSwizzleTest = SpvParserTestBase<::testing::TestWithParam<SwizzleCase>>;
 
 TEST_P(SpvParserSwizzleTest, Sample) {
-  // We need a function so we can get a FunctionEmitter.
-  const auto assembly = Preamble() + CommonTypes() + R"(
+    // We need a function so we can get a FunctionEmitter.
+    const auto assembly = Preamble() + CommonTypes() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      OpReturn
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
 
-  auto* result = fe.Swizzle(GetParam().index);
-  if (GetParam().expected_error.empty()) {
-    Program program(p->program());
-    EXPECT_TRUE(fe.success());
-    ASSERT_NE(result, nullptr);
-    auto got = test::ToString(program, result);
-    EXPECT_EQ(got, GetParam().expected_expr);
-  } else {
-    EXPECT_EQ(result, nullptr);
-    EXPECT_FALSE(fe.success());
-    EXPECT_EQ(p->error(), GetParam().expected_error);
-  }
+    auto* result = fe.Swizzle(GetParam().index);
+    if (GetParam().expected_error.empty()) {
+        Program program(p->program());
+        EXPECT_TRUE(fe.success());
+        ASSERT_NE(result, nullptr);
+        auto got = test::ToString(program, result);
+        EXPECT_EQ(got, GetParam().expected_expr);
+    } else {
+        EXPECT_EQ(result, nullptr);
+        EXPECT_FALSE(fe.success());
+        EXPECT_EQ(p->error(), GetParam().expected_error);
+    }
 }
 
-INSTANTIATE_TEST_SUITE_P(
-    ValidIndex,
-    SpvParserSwizzleTest,
-    ::testing::ValuesIn(std::vector<SwizzleCase>{
-        {0, "x", ""},
-        {1, "y", ""},
-        {2, "z", ""},
-        {3, "w", ""},
-        {4, "", "vector component index is larger than 3: 4"},
-        {99999, "", "vector component index is larger than 3: 99999"}}));
+INSTANTIATE_TEST_SUITE_P(ValidIndex,
+                         SpvParserSwizzleTest,
+                         ::testing::ValuesIn(std::vector<SwizzleCase>{
+                             {0, "x", ""},
+                             {1, "y", ""},
+                             {2, "z", ""},
+                             {3, "w", ""},
+                             {4, "", "vector component index is larger than 3: 4"},
+                             {99999, "", "vector component index is larger than 3: 99999"}}));
 
 TEST_F(SpvParserTest, ValueFromBlockNotInBlockOrder) {
-  // crbug.com/tint/804
-  const auto assembly = Preamble() + CommonTypes() + R"(
+    // crbug.com/tint/804
+    const auto assembly = Preamble() + CommonTypes() + R"(
      %float_42 = OpConstant %float 42.0
      %cond = OpUndef %bool
 
@@ -329,13 +324,13 @@
      OpReturn
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto got = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(got, HasSubstr("let x_81 : f32 = (0.0 * 42.0);"));
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto got = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(got, HasSubstr("let x_81 : f32 = (0.0 * 42.0);"));
 }
 
 // TODO(dneto): OpSizeof : requires Kernel (OpenCL)
diff --git a/src/tint/reader/spirv/function_var_test.cc b/src/tint/reader/spirv/function_var_test.cc
index c6c1aa5..c986af8 100644
--- a/src/tint/reader/spirv/function_var_test.cc
+++ b/src/tint/reader/spirv/function_var_test.cc
@@ -26,16 +26,16 @@
 /// @returns a SPIR-V assembly segment which assigns debug names
 /// to particular IDs.
 std::string Names(std::vector<std::string> ids) {
-  std::ostringstream outs;
-  for (auto& id : ids) {
-    outs << "    OpName %" << id << " \"" << id << "\"\n";
-  }
-  return outs.str();
+    std::ostringstream outs;
+    for (auto& id : ids) {
+        outs << "    OpName %" << id << " \"" << id << "\"\n";
+    }
+    return outs.str();
 }
 
 std::string CommonTypes() {
-  return
-      R"(
+    return
+        R"(
 
     %void = OpTypeVoid
     %voidfn = OpTypeFunction %void
@@ -80,7 +80,7 @@
 // a vertex shader entry point declaration, and name declarations
 // for specified IDs.
 std::string Caps(std::vector<std::string> ids = {}) {
-  return R"(
+    return R"(
     OpCapability Shader
     OpMemoryModel Logical Simple
     OpEntryPoint Fragment %100 "main"
@@ -91,17 +91,17 @@
 // Returns the SPIR-V assembly for a vertex shader, optionally
 // with OpName decorations for certain SPIR-V IDs
 std::string PreambleNames(std::vector<std::string> ids) {
-  return Caps(ids) + CommonTypes();
+    return Caps(ids) + CommonTypes();
 }
 
 std::string Preamble() {
-  return PreambleNames({});
+    return PreambleNames({});
 }
 
 using SpvParserFunctionVarTest = SpvParserTest;
 
 TEST_F(SpvParserFunctionVarTest, EmitFunctionVariables_AnonymousVars) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %1 = OpVariable %ptr_uint Function
@@ -110,20 +110,19 @@
      OpReturn
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitFunctionVariables());
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitFunctionVariables());
 
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr(R"(var x_1 : u32;
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr(R"(var x_1 : u32;
 var x_2 : u32;
 var x_3 : u32;
 )"));
 }
 
 TEST_F(SpvParserFunctionVarTest, EmitFunctionVariables_NamedVars) {
-  auto p = parser(test::Assemble(PreambleNames({"a", "b", "c"}) + R"(
+    auto p = parser(test::Assemble(PreambleNames({"a", "b", "c"}) + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %a = OpVariable %ptr_uint Function
@@ -132,19 +131,19 @@
      OpReturn
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitFunctionVariables());
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitFunctionVariables());
 
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr(R"(var a : u32;
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr(R"(var a : u32;
 var b : u32;
 var c : u32;
 )"));
 }
 
 TEST_F(SpvParserFunctionVarTest, EmitFunctionVariables_MixedTypes) {
-  auto p = parser(test::Assemble(PreambleNames({"a", "b", "c"}) + R"(
+    auto p = parser(test::Assemble(PreambleNames({"a", "b", "c"}) + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %a = OpVariable %ptr_uint Function
@@ -153,19 +152,19 @@
      OpReturn
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitFunctionVariables());
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitFunctionVariables());
 
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr(R"(var a : u32;
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr(R"(var a : u32;
 var b : i32;
 var c : f32;
 )"));
 }
 
 TEST_F(SpvParserFunctionVarTest, EmitFunctionVariables_ScalarInitializers) {
-  auto p = parser(test::Assemble(PreambleNames({"a", "b", "c", "d", "e"}) + R"(
+    auto p = parser(test::Assemble(PreambleNames({"a", "b", "c", "d", "e"}) + R"(
      %100 = OpFunction %void None %voidfn
      %entry = OpLabel
      %a = OpVariable %ptr_bool Function %true
@@ -176,22 +175,21 @@
      OpReturn
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitFunctionVariables());
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitFunctionVariables());
 
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr(R"(var a : bool = true;
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr(R"(var a : bool = true;
 var b : bool = false;
-var c : i32 = -1;
+var c : i32 = -1i;
 var d : u32 = 1u;
 var e : f32 = 1.5;
 )"));
 }
 
 TEST_F(SpvParserFunctionVarTest, EmitFunctionVariables_ScalarNullInitializers) {
-  auto p = parser(test::Assemble(PreambleNames({"a", "b", "c", "d"}) + R"(
+    auto p = parser(test::Assemble(PreambleNames({"a", "b", "c", "d"}) + R"(
      %null_bool = OpConstantNull %bool
      %null_int = OpConstantNull %int
      %null_uint = OpConstantNull %uint
@@ -206,21 +204,20 @@
      OpReturn
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitFunctionVariables());
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitFunctionVariables());
 
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr(R"(var a : bool = false;
-var b : i32 = 0;
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body), HasSubstr(R"(var a : bool = false;
+var b : i32 = 0i;
 var c : u32 = 0u;
 var d : f32 = 0.0;
 )"));
 }
 
 TEST_F(SpvParserFunctionVarTest, EmitFunctionVariables_VectorInitializer) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
      %ptr = OpTypePointer Function %v2float
      %two = OpConstant %float 2.0
      %const = OpConstantComposite %v2float %float_1p5 %two
@@ -231,17 +228,17 @@
      OpReturn
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitFunctionVariables());
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitFunctionVariables());
 
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("var x_200 : vec2<f32> = vec2<f32>(1.5, 2.0);"));
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("var x_200 : vec2<f32> = vec2<f32>(1.5, 2.0);"));
 }
 
 TEST_F(SpvParserFunctionVarTest, EmitFunctionVariables_MatrixInitializer) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
      %ptr = OpTypePointer Function %m3v2float
      %two = OpConstant %float 2.0
      %three = OpConstant %float 3.0
@@ -257,20 +254,20 @@
      OpReturn
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitFunctionVariables());
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitFunctionVariables());
 
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("var x_200 : mat3x2<f32> = mat3x2<f32>("
-                        "vec2<f32>(1.5, 2.0), "
-                        "vec2<f32>(2.0, 3.0), "
-                        "vec2<f32>(3.0, 4.0));"));
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("var x_200 : mat3x2<f32> = mat3x2<f32>("
+                          "vec2<f32>(1.5, 2.0), "
+                          "vec2<f32>(2.0, 3.0), "
+                          "vec2<f32>(3.0, 4.0));"));
 }
 
 TEST_F(SpvParserFunctionVarTest, EmitFunctionVariables_ArrayInitializer) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
      %ptr = OpTypePointer Function %arr2uint
      %two = OpConstant %uint 2
      %const = OpConstantComposite %arr2uint %uint_1 %two
@@ -281,18 +278,17 @@
      OpReturn
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitFunctionVariables());
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitFunctionVariables());
 
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(
-      test::ToString(p->program(), ast_body),
-      HasSubstr("var x_200 : array<u32, 2u> = array<u32, 2u>(1u, 2u);"));
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("var x_200 : array<u32, 2u> = array<u32, 2u>(1u, 2u);"));
 }
 
 TEST_F(SpvParserFunctionVarTest, EmitFunctionVariables_ArrayInitializer_Alias) {
-  auto p = parser(test::Assemble(R"(
+    auto p = parser(test::Assemble(R"(
      OpCapability Shader
      OpMemoryModel Logical Simple
      OpEntryPoint Fragment %100 "main"
@@ -309,18 +305,18 @@
      OpReturn
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitFunctionVariables());
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitFunctionVariables());
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  const char* expect = "var x_200 : Arr = Arr(1u, 2u);\n";
-  EXPECT_EQ(expect, got);
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    const char* expect = "var x_200 : Arr = Arr(1u, 2u);\n";
+    EXPECT_EQ(expect, got);
 }
 
 TEST_F(SpvParserFunctionVarTest, EmitFunctionVariables_ArrayInitializer_Null) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
      %ptr = OpTypePointer Function %arr2uint
      %two = OpConstant %uint 2
      %const = OpConstantNull %arr2uint
@@ -331,18 +327,17 @@
      OpReturn
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitFunctionVariables());
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitFunctionVariables());
 
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("var x_200 : array<u32, 2u> = array<u32, 2u>();"));
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("var x_200 : array<u32, 2u> = array<u32, 2u>();"));
 }
 
-TEST_F(SpvParserFunctionVarTest,
-       EmitFunctionVariables_ArrayInitializer_Alias_Null) {
-  auto p = parser(test::Assemble(R"(
+TEST_F(SpvParserFunctionVarTest, EmitFunctionVariables_ArrayInitializer_Alias_Null) {
+    auto p = parser(test::Assemble(R"(
      OpCapability Shader
      OpMemoryModel Logical Simple
      OpEntryPoint Fragment %100 "main"
@@ -359,17 +354,17 @@
      OpReturn
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitFunctionVariables());
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitFunctionVariables());
 
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("var x_200 : Arr = @stride(16) array<u32, 2u>();"));
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("var x_200 : Arr = @stride(16) array<u32, 2u>();"));
 }
 
 TEST_F(SpvParserFunctionVarTest, EmitFunctionVariables_StructInitializer) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
      %ptr = OpTypePointer Function %strct
      %two = OpConstant %uint 2
      %arrconst = OpConstantComposite %arr2uint %uint_1 %two
@@ -381,17 +376,17 @@
      OpReturn
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitFunctionVariables());
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitFunctionVariables());
 
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("var x_200 : S = S(1u, 1.5, array<u32, 2u>(1u, 2u));"));
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("var x_200 : S = S(1u, 1.5, array<u32, 2u>(1u, 2u));"));
 }
 
 TEST_F(SpvParserFunctionVarTest, EmitFunctionVariables_StructInitializer_Null) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
      %ptr = OpTypePointer Function %strct
      %two = OpConstant %uint 2
      %arrconst = OpConstantComposite %arr2uint %uint_1 %two
@@ -403,19 +398,18 @@
      OpReturn
      OpFunctionEnd
   )"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitFunctionVariables());
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitFunctionVariables());
 
-  auto ast_body = fe.ast_body();
-  EXPECT_THAT(test::ToString(p->program(), ast_body),
-              HasSubstr("var x_200 : S = S(0u, 0.0, array<u32, 2u>());"));
+    auto ast_body = fe.ast_body();
+    EXPECT_THAT(test::ToString(p->program(), ast_body),
+                HasSubstr("var x_200 : S = S(0u, 0.0, array<u32, 2u>());"));
 }
 
-TEST_F(SpvParserFunctionVarTest,
-       EmitFunctionVariables_Decorate_RelaxedPrecision) {
-  // RelaxedPrecisionis dropped
-  const auto assembly = Caps({"myvar"}) + R"(
+TEST_F(SpvParserFunctionVarTest, EmitFunctionVariables_Decorate_RelaxedPrecision) {
+    // RelaxedPrecisionis dropped
+    const auto assembly = Caps({"myvar"}) + R"(
      OpDecorate %myvar RelaxedPrecision
 
      %float = OpTypeFloat 32
@@ -430,20 +424,19 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitFunctionVariables());
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitFunctionVariables());
 
-  auto ast_body = fe.ast_body();
-  const auto got = test::ToString(p->program(), ast_body);
-  EXPECT_EQ(got, "var myvar : f32;\n") << got;
+    auto ast_body = fe.ast_body();
+    const auto got = test::ToString(p->program(), ast_body);
+    EXPECT_EQ(got, "var myvar : f32;\n") << got;
 }
 
-TEST_F(SpvParserFunctionVarTest,
-       EmitFunctionVariables_MemberDecorate_RelaxedPrecision) {
-  // RelaxedPrecisionis dropped
-  const auto assembly = Caps({"myvar", "strct"}) + R"(
+TEST_F(SpvParserFunctionVarTest, EmitFunctionVariables_MemberDecorate_RelaxedPrecision) {
+    // RelaxedPrecisionis dropped
+    const auto assembly = Caps({"myvar", "strct"}) + R"(
      OpMemberDecorate %strct 0 RelaxedPrecision
 
      %float = OpTypeFloat 32
@@ -459,20 +452,19 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << assembly << p->error() << std::endl;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitFunctionVariables());
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
+        << assembly << p->error() << std::endl;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitFunctionVariables());
 
-  auto ast_body = fe.ast_body();
-  const auto got = test::ToString(p->program(), ast_body);
-  EXPECT_EQ(got, "var myvar : strct;\n") << got;
+    auto ast_body = fe.ast_body();
+    const auto got = test::ToString(p->program(), ast_body);
+    EXPECT_EQ(got, "var myvar : strct;\n") << got;
 }
 
-TEST_F(SpvParserFunctionVarTest,
-       EmitFunctionVariables_StructDifferOnlyInMemberName) {
-  auto p = parser(test::Assemble(R"(
+TEST_F(SpvParserFunctionVarTest, EmitFunctionVariables_StructDifferOnlyInMemberName) {
+    auto p = parser(test::Assemble(R"(
       OpCapability Shader
       OpMemoryModel Logical Simple
       OpEntryPoint Fragment %100 "main"
@@ -496,20 +488,19 @@
       %41 = OpVariable %_ptr_Function__struct_6 Function
       OpReturn
       OpFunctionEnd)"));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitFunctionVariables());
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitFunctionVariables());
 
-  auto ast_body = fe.ast_body();
-  const auto got = test::ToString(p->program(), ast_body);
-  EXPECT_THAT(got, HasSubstr(R"(var x_40 : S;
+    auto ast_body = fe.ast_body();
+    const auto got = test::ToString(p->program(), ast_body);
+    EXPECT_THAT(got, HasSubstr(R"(var x_40 : S;
 var x_41 : S_1;
 )"));
 }
 
-TEST_F(SpvParserFunctionVarTest,
-       EmitStatement_CombinatorialValue_Defer_UsedOnceSameConstruct) {
-  auto assembly = Preamble() + R"(
+TEST_F(SpvParserFunctionVarTest, EmitStatement_CombinatorialValue_Defer_UsedOnceSameConstruct) {
+    auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -524,25 +515,24 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect =
-      R"(var x_25 : u32;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect =
+        R"(var x_25 : u32;
 x_25 = 1u;
 x_25 = (1u + 1u);
 return;
 )";
-  EXPECT_EQ(expect, got);
+    EXPECT_EQ(expect, got);
 }
 
-TEST_F(SpvParserFunctionVarTest,
-       EmitStatement_CombinatorialValue_Immediate_UsedTwice) {
-  auto assembly = Preamble() + R"(
+TEST_F(SpvParserFunctionVarTest, EmitStatement_CombinatorialValue_Immediate_UsedTwice) {
+    auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -558,29 +548,29 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var x_25 : u32;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var x_25 : u32;
 let x_2 : u32 = (1u + 1u);
 x_25 = 1u;
 x_25 = x_2;
 x_25 = x_2;
 return;
 )";
-  EXPECT_EQ(expect, got);
+    EXPECT_EQ(expect, got);
 }
 
 TEST_F(SpvParserFunctionVarTest,
        EmitStatement_CombinatorialValue_Immediate_UsedOnceDifferentConstruct) {
-  // Translation should not sink expensive operations into or out of control
-  // flow. As a simple heuristic, don't move *any* combinatorial operation
-  // across any control flow.
-  auto assembly = Preamble() + R"(
+    // Translation should not sink expensive operations into or out of control
+    // flow. As a simple heuristic, don't move *any* combinatorial operation
+    // across any control flow.
+    auto assembly = Preamble() + R"(
      %100 = OpFunction %void None %voidfn
 
      %10 = OpLabel
@@ -603,14 +593,14 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var x_25 : u32;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var x_25 : u32;
 let x_2 : u32 = (1u + 1u);
 x_25 = 1u;
 loop {
@@ -622,18 +612,17 @@
 x_25 = 2u;
 return;
 )";
-  EXPECT_EQ(expect, got);
+    EXPECT_EQ(expect, got);
 }
 
-TEST_F(
-    SpvParserFunctionVarTest,
-    EmitStatement_CombinatorialNonPointer_DefConstruct_DoesNotEncloseAllUses) {
-  // Compensate for the difference between dominance and scoping.
-  // Exercise hoisting of the constant definition to before its natural
-  // location.
-  //
-  // The definition of %2 should be hoisted
-  auto assembly = Preamble() + R"(
+TEST_F(SpvParserFunctionVarTest,
+       EmitStatement_CombinatorialNonPointer_DefConstruct_DoesNotEncloseAllUses) {
+    // Compensate for the difference between dominance and scoping.
+    // Exercise hoisting of the constant definition to before its natural
+    // location.
+    //
+    // The definition of %2 should be hoisted
+    auto assembly = Preamble() + R"(
      %pty = OpTypePointer Private %uint
      %1 = OpVariable %pty Private
 
@@ -676,14 +665,14 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(x_1 = 0u;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(x_1 = 0u;
 loop {
   var x_2 : u32;
   x_1 = 1u;
@@ -708,21 +697,20 @@
 x_1 = 5u;
 return;
 )";
-  EXPECT_EQ(expect, got);
+    EXPECT_EQ(expect, got);
 }
 
-TEST_F(
-    SpvParserFunctionVarTest,
-    EmitStatement_CombinatorialNonPointer_Hoisting_DefFirstBlockIf_InFunction) {
-  // This is a hoisting case, where the definition is in the first block
-  // of an if selection construct. In this case the definition should count
-  // as being in the parent (enclosing) construct.
-  //
-  // The definition of %1 is in an IfSelection construct and also the enclosing
-  // Function construct, both of which start at block %10. For the purpose of
-  // determining the construct containing %10, go to the parent construct of
-  // the IfSelection.
-  auto assembly = Preamble() + R"(
+TEST_F(SpvParserFunctionVarTest,
+       EmitStatement_CombinatorialNonPointer_Hoisting_DefFirstBlockIf_InFunction) {
+    // This is a hoisting case, where the definition is in the first block
+    // of an if selection construct. In this case the definition should count
+    // as being in the parent (enclosing) construct.
+    //
+    // The definition of %1 is in an IfSelection construct and also the enclosing
+    // Function construct, both of which start at block %10. For the purpose of
+    // determining the construct containing %10, go to the parent construct of
+    // the IfSelection.
+    auto assembly = Preamble() + R"(
      %pty = OpTypePointer Private %uint
      %200 = OpVariable %pty Private
      %cond = OpConstantTrue %bool
@@ -745,36 +733,36 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  // We don't hoist x_1 into its own mutable variable. It is emitted as
-  // a const definition.
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(let x_1 : u32 = 1u;
+    // We don't hoist x_1 into its own mutable variable. It is emitted as
+    // a const definition.
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(let x_1 : u32 = 1u;
 if (true) {
 }
 let x_3 : u32 = x_1;
 x_200 = x_3;
 return;
 )";
-  EXPECT_EQ(expect, got);
+    EXPECT_EQ(expect, got);
 }
 
 TEST_F(SpvParserFunctionVarTest,
        EmitStatement_CombinatorialNonPointer_Hoisting_DefFirstBlockIf_InIf) {
-  // This is like the previous case, but the IfSelection is nested inside
-  // another IfSelection.
-  // This tests that the hoisting algorithm goes to only one parent of
-  // the definining if-selection block, and doesn't jump all the way out
-  // to the Function construct that encloses everything.
-  //
-  // We should not hoist %1 because its definition should count as being
-  // in the outer IfSelection, not the inner IfSelection.
-  auto assembly = Preamble() + R"(
+    // This is like the previous case, but the IfSelection is nested inside
+    // another IfSelection.
+    // This tests that the hoisting algorithm goes to only one parent of
+    // the definining if-selection block, and doesn't jump all the way out
+    // to the Function construct that encloses everything.
+    //
+    // We should not hoist %1 because its definition should count as being
+    // in the outer IfSelection, not the inner IfSelection.
+    auto assembly = Preamble() + R"(
 
      %pty = OpTypePointer Private %uint
      %200 = OpVariable %pty Private
@@ -807,14 +795,14 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(if (true) {
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(if (true) {
   let x_1 : u32 = 1u;
   if (true) {
   }
@@ -823,17 +811,16 @@
 }
 return;
 )";
-  EXPECT_EQ(expect, got);
+    EXPECT_EQ(expect, got);
 }
 
-TEST_F(
-    SpvParserFunctionVarTest,
-    EmitStatement_CombinatorialNonPointer_Hoisting_DefFirstBlockSwitch_InIf) {
-  // This is like the previous case, but the definition is in a SwitchSelection
-  // inside another IfSelection.
-  // Tests that definitions in the first block of a switch count as being
-  // in the parent of the switch construct.
-  auto assembly = Preamble() + R"(
+TEST_F(SpvParserFunctionVarTest,
+       EmitStatement_CombinatorialNonPointer_Hoisting_DefFirstBlockSwitch_InIf) {
+    // This is like the previous case, but the definition is in a SwitchSelection
+    // inside another IfSelection.
+    // Tests that definitions in the first block of a switch count as being
+    // in the parent of the switch construct.
+    auto assembly = Preamble() + R"(
      %pty = OpTypePointer Private %uint
      %200 = OpVariable %pty Private
      %cond = OpConstantTrue %bool
@@ -864,14 +851,14 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(if (true) {
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(if (true) {
   let x_1 : u32 = 1u;
   switch(1u) {
     case 0u: {
@@ -884,20 +871,20 @@
 }
 return;
 )";
-  EXPECT_EQ(expect, got);
+    EXPECT_EQ(expect, got);
 }
 
 TEST_F(SpvParserFunctionVarTest,
        EmitStatement_CombinatorialNonPointer_Hoisting_DefAndUseFirstBlockIf) {
-  // In this test, both the defintion and the use are in the first block
-  // of an IfSelection.  No hoisting occurs because hoisting is triggered
-  // on whether the defining construct contains the last use, rather than
-  // whether the two constructs are the same.
-  //
-  // This example has two SSA IDs which are tempting to hoist but should not:
-  //   %1 is defined and used in the first block of an IfSelection.
-  //       Do not hoist it.
-  auto assembly = Preamble() + R"(
+    // In this test, both the defintion and the use are in the first block
+    // of an IfSelection.  No hoisting occurs because hoisting is triggered
+    // on whether the defining construct contains the last use, rather than
+    // whether the two constructs are the same.
+    //
+    // This example has two SSA IDs which are tempting to hoist but should not:
+    //   %1 is defined and used in the first block of an IfSelection.
+    //       Do not hoist it.
+    auto assembly = Preamble() + R"(
      %cond = OpConstantTrue %bool
 
      %100 = OpFunction %void None %voidfn
@@ -917,26 +904,26 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  // We don't hoist x_1 into its own mutable variable. It is emitted as
-  // a const definition.
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(let x_1 : u32 = 1u;
+    // We don't hoist x_1 into its own mutable variable. It is emitted as
+    // a const definition.
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(let x_1 : u32 = 1u;
 let x_2 : u32 = x_1;
 if (true) {
 }
 return;
 )";
-  EXPECT_EQ(expect, got);
+    EXPECT_EQ(expect, got);
 }
 
 TEST_F(SpvParserFunctionVarTest, EmitStatement_Phi_SingleBlockLoopIndex) {
-  auto assembly = Preamble() + R"(
+    auto assembly = Preamble() + R"(
      %pty = OpTypePointer Private %uint
      %1 = OpVariable %pty Private
      %boolpty = OpTypePointer Private %bool
@@ -974,14 +961,14 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(loop {
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(loop {
   var x_2_phi : u32;
   var x_3_phi : u32;
   let x_101 : bool = x_7;
@@ -1003,11 +990,11 @@
 }
 return;
 )";
-  EXPECT_EQ(expect, got);
+    EXPECT_EQ(expect, got);
 }
 
 TEST_F(SpvParserFunctionVarTest, EmitStatement_Phi_MultiBlockLoopIndex) {
-  auto assembly = Preamble() + R"(
+    auto assembly = Preamble() + R"(
      %pty = OpTypePointer Private %uint
      %1 = OpVariable %pty Private
      %boolpty = OpTypePointer Private %bool
@@ -1048,14 +1035,14 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(loop {
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(loop {
   var x_2_phi : u32;
   var x_3_phi : u32;
   let x_101 : bool = x_7;
@@ -1082,12 +1069,11 @@
 }
 return;
 )";
-  EXPECT_EQ(expect, got);
+    EXPECT_EQ(expect, got);
 }
 
-TEST_F(SpvParserFunctionVarTest,
-       EmitStatement_Phi_ValueFromLoopBodyAndContinuing) {
-  auto assembly = Preamble() + R"(
+TEST_F(SpvParserFunctionVarTest, EmitStatement_Phi_ValueFromLoopBodyAndContinuing) {
+    auto assembly = Preamble() + R"(
      %pty = OpTypePointer Private %uint
      %1 = OpVariable %pty Private
      %boolpty = OpTypePointer Private %bool
@@ -1128,15 +1114,14 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions())
-      << assembly << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(let x_101 : bool = x_17;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(let x_101 : bool = x_17;
 loop {
   var x_2_phi : u32;
   var x_5_phi : u32;
@@ -1161,11 +1146,11 @@
 }
 return;
 )";
-  EXPECT_EQ(expect, got);
+    EXPECT_EQ(expect, got);
 }
 
 TEST_F(SpvParserFunctionVarTest, EmitStatement_Phi_FromElseAndThen) {
-  auto assembly = Preamble() + R"(
+    auto assembly = Preamble() + R"(
      %pty = OpTypePointer Private %uint
      %1 = OpVariable %pty Private
      %boolpty = OpTypePointer Private %bool
@@ -1208,14 +1193,14 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(let x_101 : bool = x_7;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(let x_101 : bool = x_7;
 let x_102 : bool = x_8;
 loop {
   var x_2_phi : u32;
@@ -1238,11 +1223,11 @@
 }
 return;
 )";
-  EXPECT_EQ(expect, got) << got;
+    EXPECT_EQ(expect, got) << got;
 }
 
 TEST_F(SpvParserFunctionVarTest, EmitStatement_Phi_FromHeaderAndThen) {
-  auto assembly = Preamble() + R"(
+    auto assembly = Preamble() + R"(
      %pty = OpTypePointer Private %uint
      %1 = OpVariable %pty Private
      %boolpty = OpTypePointer Private %bool
@@ -1282,14 +1267,14 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(let x_101 : bool = x_7;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(let x_101 : bool = x_7;
 let x_102 : bool = x_8;
 loop {
   var x_2_phi : u32;
@@ -1312,13 +1297,12 @@
 }
 return;
 )";
-  EXPECT_EQ(expect, got) << got;
+    EXPECT_EQ(expect, got) << got;
 }
 
-TEST_F(SpvParserFunctionVarTest,
-       EmitStatement_Phi_InMerge_PredecessorsDominatdByNestedSwitchCase) {
-  // This is the essence of the bug report from crbug.com/tint/495
-  auto assembly = Preamble() + R"(
+TEST_F(SpvParserFunctionVarTest, EmitStatement_Phi_InMerge_PredecessorsDominatdByNestedSwitchCase) {
+    // This is the essence of the bug report from crbug.com/tint/495
+    auto assembly = Preamble() + R"(
      %cond = OpConstantTrue %bool
      %pty = OpTypePointer Private %uint
      %1 = OpVariable %pty Private
@@ -1355,14 +1339,14 @@
 
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var x_41_phi : u32;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var x_41_phi : u32;
 switch(1u) {
   default: {
     fallthrough;
@@ -1382,20 +1366,20 @@
 let x_41 : u32 = x_41_phi;
 return;
 )";
-  EXPECT_EQ(expect, got) << got << assembly;
+    EXPECT_EQ(expect, got) << got << assembly;
 }
 
 TEST_F(SpvParserFunctionVarTest, EmitStatement_UseInPhiCountsAsUse) {
-  // From crbug.com/215
-  // If the only use of a combinatorially computed ID is as the value
-  // in an OpPhi, then we still have to emit it.  The algorithm fix
-  // is to always count uses in Phis.
-  // This is the reduced case from the bug report.
-  //
-  // The only use of %12 is in the phi.
-  // The only use of %11 is in %12.
-  // Both definintions need to be emitted to the output.
-  auto assembly = Preamble() + R"(
+    // From crbug.com/215
+    // If the only use of a combinatorially computed ID is as the value
+    // in an OpPhi, then we still have to emit it.  The algorithm fix
+    // is to always count uses in Phis.
+    // This is the reduced case from the bug report.
+    //
+    // The only use of %12 is in the phi.
+    // The only use of %11 is in %12.
+    // Both definintions need to be emitted to the output.
+    auto assembly = Preamble() + R"(
         %100 = OpFunction %void None %voidfn
 
          %10 = OpLabel
@@ -1414,14 +1398,14 @@
                OpFunctionEnd
 
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var x_101_phi : bool;
+    auto ast_body = fe.ast_body();
+    auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var x_101_phi : bool;
 let x_11 : bool = (true & true);
 let x_12 : bool = !(x_11);
 x_101_phi = x_11;
@@ -1431,13 +1415,12 @@
 let x_101 : bool = x_101_phi;
 return;
 )";
-  EXPECT_EQ(expect, got);
+    EXPECT_EQ(expect, got);
 }
 
-TEST_F(SpvParserFunctionVarTest,
-       EmitStatement_Phi_ValueFromBlockNotInBlockOrderIgnored) {
-  // From crbug.com/tint/804
-  const auto assembly = Preamble() + R"(
+TEST_F(SpvParserFunctionVarTest, EmitStatement_Phi_ValueFromBlockNotInBlockOrderIgnored) {
+    // From crbug.com/tint/804
+    const auto assembly = Preamble() + R"(
      %float_42 = OpConstant %float 42.0
      %cond = OpUndef %bool
 
@@ -1471,12 +1454,12 @@
      OpReturn
      OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  const auto* expected = R"(loop {
+    const auto* expected = R"(loop {
   if (false) {
     break;
   }
@@ -1489,14 +1472,14 @@
 }
 return;
 )";
-  auto ast_body = fe.ast_body();
-  const auto got = test::ToString(p->program(), ast_body);
-  EXPECT_EQ(got, expected);
+    auto ast_body = fe.ast_body();
+    const auto got = test::ToString(p->program(), ast_body);
+    EXPECT_EQ(got, expected);
 }
 
 TEST_F(SpvParserFunctionVarTest, EmitStatement_Hoist_CompositeInsert) {
-  // From crbug.com/tint/804
-  const auto assembly = Preamble() + R"(
+    // From crbug.com/tint/804
+    const auto assembly = Preamble() + R"(
     %100 = OpFunction %void None %voidfn
 
     %10 = OpLabel
@@ -1515,29 +1498,29 @@
     OpReturn
     OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  const auto* expected = R"(var x_200 : vec2<i32>;
+    const auto* expected = R"(var x_200 : vec2<i32>;
 if (true) {
   x_200 = vec2<i32>();
-  x_200.x = 0;
+  x_200.x = 0i;
 } else {
   return;
 }
 let x_201 : vec2<i32> = x_200;
 return;
 )";
-  auto ast_body = fe.ast_body();
-  const auto got = test::ToString(p->program(), ast_body);
-  EXPECT_EQ(got, expected);
+    auto ast_body = fe.ast_body();
+    const auto got = test::ToString(p->program(), ast_body);
+    EXPECT_EQ(got, expected);
 }
 
 TEST_F(SpvParserFunctionVarTest, EmitStatement_Hoist_VectorInsertDynamic) {
-  // Spawned from crbug.com/tint/804
-  const auto assembly = Preamble() + R"(
+    // Spawned from crbug.com/tint/804
+    const auto assembly = Preamble() + R"(
     %100 = OpFunction %void None %voidfn
 
     %10 = OpLabel
@@ -1556,29 +1539,29 @@
     OpReturn
     OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  const auto got = test::ToString(p->program(), ast_body);
-  const auto* expected = R"(var x_200 : vec2<i32>;
+    auto ast_body = fe.ast_body();
+    const auto got = test::ToString(p->program(), ast_body);
+    const auto* expected = R"(var x_200 : vec2<i32>;
 if (true) {
   x_200 = vec2<i32>();
-  x_200[1] = 3;
+  x_200[1i] = 3i;
 } else {
   return;
 }
 let x_201 : vec2<i32> = x_200;
 return;
 )";
-  EXPECT_EQ(got, expected) << got;
+    EXPECT_EQ(got, expected) << got;
 }
 
 TEST_F(SpvParserFunctionVarTest, EmitStatement_Hoist_UsedAsNonPtrArg) {
-  // Spawned from crbug.com/tint/804
-  const auto assembly = Preamble() + R"(
+    // Spawned from crbug.com/tint/804
+    const auto assembly = Preamble() + R"(
     %fn_int = OpTypeFunction %void %int
 
     %500 = OpFunction %void None %fn_int
@@ -1605,29 +1588,29 @@
     OpReturn
     OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  const auto got = test::ToString(p->program(), ast_body);
-  const auto* expected = R"(var x_200 : i32;
+    auto ast_body = fe.ast_body();
+    const auto got = test::ToString(p->program(), ast_body);
+    const auto* expected = R"(var x_200 : i32;
 if (true) {
-  x_200 = 1;
+  x_200 = 1i;
 } else {
   return;
 }
 x_500(x_200);
 return;
 )";
-  EXPECT_EQ(got, expected) << got;
+    EXPECT_EQ(got, expected) << got;
 }
 
 TEST_F(SpvParserFunctionVarTest, DISABLED_EmitStatement_Hoist_UsedAsPtrArg) {
-  // Spawned from crbug.com/tint/804
-  // Blocked by crbug.com/tint/98: hoisting pointer types
-  const auto assembly = Preamble() + R"(
+    // Spawned from crbug.com/tint/804
+    // Blocked by crbug.com/tint/98: hoisting pointer types
+    const auto assembly = Preamble() + R"(
 
     %fn_int = OpTypeFunction %void %ptr_int
 
@@ -1656,15 +1639,15 @@
     OpReturn
     OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
 
-  auto ast_body = fe.ast_body();
-  const auto got = test::ToString(p->program(), ast_body);
-  const auto* expected = R"(xxxxxxxxxxxxxxxxxxxxx)";
-  EXPECT_EQ(got, expected) << got;
+    auto ast_body = fe.ast_body();
+    const auto got = test::ToString(p->program(), ast_body);
+    const auto* expected = R"(xxxxxxxxxxxxxxxxxxxxx)";
+    EXPECT_EQ(got, expected) << got;
 }
 
 }  // namespace
diff --git a/src/tint/reader/spirv/namer.cc b/src/tint/reader/spirv/namer.cc
index 6e7044f..1233157 100644
--- a/src/tint/reader/spirv/namer.cc
+++ b/src/tint/reader/spirv/namer.cc
@@ -58,178 +58,173 @@
 }  // namespace
 
 Namer::Namer(const FailStream& fail_stream) : fail_stream_(fail_stream) {
-  for (const auto* reserved : kWGSLReservedWords) {
-    name_to_id_[std::string(reserved)] = 0;
-  }
+    for (const auto* reserved : kWGSLReservedWords) {
+        name_to_id_[std::string(reserved)] = 0;
+    }
 }
 
 Namer::~Namer() = default;
 
 std::string Namer::Sanitize(const std::string& suggested_name) {
-  if (suggested_name.empty()) {
-    return "empty";
-  }
-  // Otherwise, replace invalid characters by '_'.
-  std::string result;
-  std::string invalid_as_first_char = "_0123456789";
-  std::string valid =
-      "abcdefghijklmnopqrstuvwxyz"
-      "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-      "_0123456789";
-  // If the first character is invalid for starting a WGSL identifier, then
-  // prefix the result with "x".
-  if ((std::string::npos != invalid_as_first_char.find(suggested_name[0])) ||
-      (std::string::npos == valid.find(suggested_name[0]))) {
-    result = "x";
-  }
-  std::transform(suggested_name.begin(), suggested_name.end(),
-                 std::back_inserter(result), [&valid](const char c) {
-                   return (std::string::npos == valid.find(c)) ? '_' : c;
-                 });
-  return result;
+    if (suggested_name.empty()) {
+        return "empty";
+    }
+    // Otherwise, replace invalid characters by '_'.
+    std::string result;
+    std::string invalid_as_first_char = "_0123456789";
+    std::string valid =
+        "abcdefghijklmnopqrstuvwxyz"
+        "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+        "_0123456789";
+    // If the first character is invalid for starting a WGSL identifier, then
+    // prefix the result with "x".
+    if ((std::string::npos != invalid_as_first_char.find(suggested_name[0])) ||
+        (std::string::npos == valid.find(suggested_name[0]))) {
+        result = "x";
+    }
+    std::transform(
+        suggested_name.begin(), suggested_name.end(), std::back_inserter(result),
+        [&valid](const char c) { return (std::string::npos == valid.find(c)) ? '_' : c; });
+    return result;
 }
 
-std::string Namer::GetMemberName(uint32_t struct_id,
-                                 uint32_t member_index) const {
-  std::string result;
-  auto where = struct_member_names_.find(struct_id);
-  if (where != struct_member_names_.end()) {
-    auto& member_names = where->second;
-    if (member_index < member_names.size()) {
-      result = member_names[member_index];
+std::string Namer::GetMemberName(uint32_t struct_id, uint32_t member_index) const {
+    std::string result;
+    auto where = struct_member_names_.find(struct_id);
+    if (where != struct_member_names_.end()) {
+        auto& member_names = where->second;
+        if (member_index < member_names.size()) {
+            result = member_names[member_index];
+        }
     }
-  }
-  return result;
+    return result;
 }
 
 std::string Namer::FindUnusedDerivedName(const std::string& base_name) {
-  // Ensure uniqueness among names.
-  std::string derived_name;
-  uint32_t& i = next_unusued_derived_name_id_[base_name];
-  while (i != 0xffffffff) {
-    std::stringstream new_name_stream;
-    new_name_stream << base_name;
-    if (i > 0) {
-      new_name_stream << "_" << i;
+    // Ensure uniqueness among names.
+    std::string derived_name;
+    uint32_t& i = next_unusued_derived_name_id_[base_name];
+    while (i != 0xffffffff) {
+        std::stringstream new_name_stream;
+        new_name_stream << base_name;
+        if (i > 0) {
+            new_name_stream << "_" << i;
+        }
+        derived_name = new_name_stream.str();
+        if (!IsRegistered(derived_name)) {
+            return derived_name;
+        }
+        i++;
     }
-    derived_name = new_name_stream.str();
-    if (!IsRegistered(derived_name)) {
-      return derived_name;
-    }
-    i++;
-  }
-  TINT_ASSERT(Reader, false /* FindUnusedDerivedName() overflowed u32 */);
-  return "<u32 overflow>";
+    TINT_ASSERT(Reader, false /* FindUnusedDerivedName() overflowed u32 */);
+    return "<u32 overflow>";
 }
 
 std::string Namer::MakeDerivedName(const std::string& base_name) {
-  auto result = FindUnusedDerivedName(base_name);
-  const bool registered = RegisterWithoutId(result);
-  TINT_ASSERT(Reader, registered);
-  return result;
+    auto result = FindUnusedDerivedName(base_name);
+    const bool registered = RegisterWithoutId(result);
+    TINT_ASSERT(Reader, registered);
+    return result;
 }
 
 bool Namer::Register(uint32_t id, const std::string& name) {
-  if (HasName(id)) {
-    return Fail() << "internal error: ID " << id
-                  << " already has registered name: " << id_to_name_[id];
-  }
-  if (!RegisterWithoutId(name)) {
-    return false;
-  }
-  id_to_name_[id] = name;
-  name_to_id_[name] = id;
-  return true;
+    if (HasName(id)) {
+        return Fail() << "internal error: ID " << id
+                      << " already has registered name: " << id_to_name_[id];
+    }
+    if (!RegisterWithoutId(name)) {
+        return false;
+    }
+    id_to_name_[id] = name;
+    name_to_id_[name] = id;
+    return true;
 }
 
 bool Namer::RegisterWithoutId(const std::string& name) {
-  if (IsRegistered(name)) {
-    return Fail() << "internal error: name already registered: " << name;
-  }
-  name_to_id_[name] = 0;
-  return true;
+    if (IsRegistered(name)) {
+        return Fail() << "internal error: name already registered: " << name;
+    }
+    name_to_id_[name] = 0;
+    return true;
 }
 
-bool Namer::SuggestSanitizedName(uint32_t id,
-                                 const std::string& suggested_name) {
-  if (HasName(id)) {
-    return false;
-  }
+bool Namer::SuggestSanitizedName(uint32_t id, const std::string& suggested_name) {
+    if (HasName(id)) {
+        return false;
+    }
 
-  return Register(id, FindUnusedDerivedName(Sanitize(suggested_name)));
+    return Register(id, FindUnusedDerivedName(Sanitize(suggested_name)));
 }
 
 bool Namer::SuggestSanitizedMemberName(uint32_t struct_id,
                                        uint32_t member_index,
                                        const std::string& suggested_name) {
-  // Creates an empty vector the first time we visit this struct.
-  auto& name_vector = struct_member_names_[struct_id];
-  // Resizing will set new entries to the empty string.
-  name_vector.resize(std::max(name_vector.size(), size_t(member_index + 1)));
-  auto& entry = name_vector[member_index];
-  if (entry.empty()) {
-    entry = Sanitize(suggested_name);
-    return true;
-  }
-  return false;
+    // Creates an empty vector the first time we visit this struct.
+    auto& name_vector = struct_member_names_[struct_id];
+    // Resizing will set new entries to the empty string.
+    name_vector.resize(std::max(name_vector.size(), size_t(member_index + 1)));
+    auto& entry = name_vector[member_index];
+    if (entry.empty()) {
+        entry = Sanitize(suggested_name);
+        return true;
+    }
+    return false;
 }
 
-void Namer::ResolveMemberNamesForStruct(uint32_t struct_id,
-                                        uint32_t num_members) {
-  auto& name_vector = struct_member_names_[struct_id];
-  // Resizing will set new entries to the empty string.
-  // It would have been an error if the client had registered a name for
-  // an out-of-bounds member index, so toss those away.
-  name_vector.resize(num_members);
+void Namer::ResolveMemberNamesForStruct(uint32_t struct_id, uint32_t num_members) {
+    auto& name_vector = struct_member_names_[struct_id];
+    // Resizing will set new entries to the empty string.
+    // It would have been an error if the client had registered a name for
+    // an out-of-bounds member index, so toss those away.
+    name_vector.resize(num_members);
 
-  std::unordered_set<std::string> used_names;
+    std::unordered_set<std::string> used_names;
 
-  // Returns a name, based on the suggestion, which does not equal
-  // any name in the used_names set.
-  auto disambiguate_name =
-      [&used_names](const std::string& suggestion) -> std::string {
-    if (used_names.find(suggestion) == used_names.end()) {
-      // There is no collision.
-      return suggestion;
+    // Returns a name, based on the suggestion, which does not equal
+    // any name in the used_names set.
+    auto disambiguate_name = [&used_names](const std::string& suggestion) -> std::string {
+        if (used_names.find(suggestion) == used_names.end()) {
+            // There is no collision.
+            return suggestion;
+        }
+
+        uint32_t i = 1;
+        std::string new_name;
+        do {
+            std::stringstream new_name_stream;
+            new_name_stream << suggestion << "_" << i;
+            new_name = new_name_stream.str();
+            ++i;
+        } while (used_names.find(new_name) != used_names.end());
+        return new_name;
+    };
+
+    // First ensure uniqueness among names for which we have already taken
+    // suggestions.
+    for (auto& name : name_vector) {
+        if (!name.empty()) {
+            // This modifies the names in-place, i.e. update the name_vector
+            // entries.
+            name = disambiguate_name(name);
+            used_names.insert(name);
+        }
     }
 
-    uint32_t i = 1;
-    std::string new_name;
-    do {
-      std::stringstream new_name_stream;
-      new_name_stream << suggestion << "_" << i;
-      new_name = new_name_stream.str();
-      ++i;
-    } while (used_names.find(new_name) != used_names.end());
-    return new_name;
-  };
-
-  // First ensure uniqueness among names for which we have already taken
-  // suggestions.
-  for (auto& name : name_vector) {
-    if (!name.empty()) {
-      // This modifies the names in-place, i.e. update the name_vector
-      // entries.
-      name = disambiguate_name(name);
-      used_names.insert(name);
+    // Now ensure uniqueness among the rest.  Doing this in a second pass
+    // allows us to preserve suggestions as much as possible.  Otherwise
+    // a generated name such as 'field1' might collide with a user-suggested
+    // name of 'field1' attached to a later member.
+    uint32_t index = 0;
+    for (auto& name : name_vector) {
+        if (name.empty()) {
+            std::stringstream suggestion;
+            suggestion << "field" << index;
+            // Again, modify the name-vector in-place.
+            name = disambiguate_name(suggestion.str());
+            used_names.insert(name);
+        }
+        index++;
     }
-  }
-
-  // Now ensure uniqueness among the rest.  Doing this in a second pass
-  // allows us to preserve suggestions as much as possible.  Otherwise
-  // a generated name such as 'field1' might collide with a user-suggested
-  // name of 'field1' attached to a later member.
-  uint32_t index = 0;
-  for (auto& name : name_vector) {
-    if (name.empty()) {
-      std::stringstream suggestion;
-      suggestion << "field" << index;
-      // Again, modify the name-vector in-place.
-      name = disambiguate_name(suggestion.str());
-      used_names.insert(name);
-    }
-    index++;
-  }
 }
 
 }  // namespace tint::reader::spirv
diff --git a/src/tint/reader/spirv/namer.h b/src/tint/reader/spirv/namer.h
index fa5fc3a..7a20e87 100644
--- a/src/tint/reader/spirv/namer.h
+++ b/src/tint/reader/spirv/namer.h
@@ -31,129 +31,125 @@
 /// to a safer character such as an underscore.  Also, sanitized names
 /// never start with an underscore.
 class Namer {
- public:
-  /// Creates a new namer
-  /// @param fail_stream the error reporting stream
-  explicit Namer(const FailStream& fail_stream);
-  /// Destructor
-  ~Namer();
+  public:
+    /// Creates a new namer
+    /// @param fail_stream the error reporting stream
+    explicit Namer(const FailStream& fail_stream);
+    /// Destructor
+    ~Namer();
 
-  /// Sanitizes the given string, to replace unusual characters with
-  /// obviously-valid idenfier characters. An empy string yields "empty".
-  /// A sanitized name never starts with an underscore.
-  /// @param suggested_name input string
-  /// @returns sanitized name, suitable for use as an identifier
-  static std::string Sanitize(const std::string& suggested_name);
+    /// Sanitizes the given string, to replace unusual characters with
+    /// obviously-valid idenfier characters. An empy string yields "empty".
+    /// A sanitized name never starts with an underscore.
+    /// @param suggested_name input string
+    /// @returns sanitized name, suitable for use as an identifier
+    static std::string Sanitize(const std::string& suggested_name);
 
-  /// Registers a failure.
-  /// @returns a fail stream to accumulate diagnostics.
-  FailStream& Fail() { return fail_stream_.Fail(); }
+    /// Registers a failure.
+    /// @returns a fail stream to accumulate diagnostics.
+    FailStream& Fail() { return fail_stream_.Fail(); }
 
-  /// @param id the SPIR-V ID
-  /// @returns true if we the given ID already has a registered name.
-  bool HasName(uint32_t id) {
-    return id_to_name_.find(id) != id_to_name_.end();
-  }
+    /// @param id the SPIR-V ID
+    /// @returns true if we the given ID already has a registered name.
+    bool HasName(uint32_t id) { return id_to_name_.find(id) != id_to_name_.end(); }
 
-  /// @param name a string
-  /// @returns true if the string has been registered as a name.
-  bool IsRegistered(const std::string& name) const {
-    return name_to_id_.find(name) != name_to_id_.end();
-  }
-
-  /// @param id the SPIR-V ID
-  /// @returns the name for the ID. It must have been registered.
-  const std::string& GetName(uint32_t id) const {
-    return id_to_name_.find(id)->second;
-  }
-
-  /// Gets a unique name for the ID. If one already exists, then return
-  /// that, otherwise synthesize a name and remember it for later.
-  /// @param id the SPIR-V ID
-  /// @returns a name for the given ID. Generates a name if non exists.
-  const std::string& Name(uint32_t id) {
-    if (!HasName(id)) {
-      SuggestSanitizedName(id, "x_" + std::to_string(id));
+    /// @param name a string
+    /// @returns true if the string has been registered as a name.
+    bool IsRegistered(const std::string& name) const {
+        return name_to_id_.find(name) != name_to_id_.end();
     }
-    return GetName(id);
-  }
 
-  /// Gets the registered name for a struct member. If no name has
-  /// been registered for this member, then returns the empty string.
-  /// member index is in bounds.
-  /// @param id the SPIR-V ID of the struct type
-  /// @param member_index the index of the member, counting from 0
-  /// @returns the registered name for the ID, or an empty string if
-  /// nothing has been registered.
-  std::string GetMemberName(uint32_t id, uint32_t member_index) const;
+    /// @param id the SPIR-V ID
+    /// @returns the name for the ID. It must have been registered.
+    const std::string& GetName(uint32_t id) const { return id_to_name_.find(id)->second; }
 
-  /// Returns an unregistered name based on a given base name.
-  /// @param base_name the base name
-  /// @returns a new name
-  std::string FindUnusedDerivedName(const std::string& base_name);
+    /// Gets a unique name for the ID. If one already exists, then return
+    /// that, otherwise synthesize a name and remember it for later.
+    /// @param id the SPIR-V ID
+    /// @returns a name for the given ID. Generates a name if non exists.
+    const std::string& Name(uint32_t id) {
+        if (!HasName(id)) {
+            SuggestSanitizedName(id, "x_" + std::to_string(id));
+        }
+        return GetName(id);
+    }
 
-  /// Returns a newly registered name based on a given base name.
-  /// In the internal table `name_to_id_`, it is mapped to the invalid
-  /// SPIR-V ID 0.  It does not have an entry in `id_to_name_`.
-  /// @param base_name the base name
-  /// @returns a new name
-  std::string MakeDerivedName(const std::string& base_name);
+    /// Gets the registered name for a struct member. If no name has
+    /// been registered for this member, then returns the empty string.
+    /// member index is in bounds.
+    /// @param id the SPIR-V ID of the struct type
+    /// @param member_index the index of the member, counting from 0
+    /// @returns the registered name for the ID, or an empty string if
+    /// nothing has been registered.
+    std::string GetMemberName(uint32_t id, uint32_t member_index) const;
 
-  /// Records a mapping from the given ID to a name. Emits a failure
-  /// if the ID already has a registered name.
-  /// @param id the SPIR-V ID
-  /// @param name the name to map to the ID
-  /// @returns true if the ID did not have a previously registered name.
-  bool Register(uint32_t id, const std::string& name);
+    /// Returns an unregistered name based on a given base name.
+    /// @param base_name the base name
+    /// @returns a new name
+    std::string FindUnusedDerivedName(const std::string& base_name);
 
-  /// Registers a name, but not associated to any ID. Fails and emits
-  /// a diagnostic if the name was already registered.
-  /// @param name the name to register
-  /// @returns true if the name was not already reegistered.
-  bool RegisterWithoutId(const std::string& name);
+    /// Returns a newly registered name based on a given base name.
+    /// In the internal table `name_to_id_`, it is mapped to the invalid
+    /// SPIR-V ID 0.  It does not have an entry in `id_to_name_`.
+    /// @param base_name the base name
+    /// @returns a new name
+    std::string MakeDerivedName(const std::string& base_name);
 
-  /// Saves a sanitized name for the given ID, if that ID does not yet
-  /// have a registered name, and if the sanitized name has not already
-  /// been registered to a different ID.
-  /// @param id the SPIR-V ID
-  /// @param suggested_name the suggested name
-  /// @returns true if a name was newly registered for the ID
-  bool SuggestSanitizedName(uint32_t id, const std::string& suggested_name);
+    /// Records a mapping from the given ID to a name. Emits a failure
+    /// if the ID already has a registered name.
+    /// @param id the SPIR-V ID
+    /// @param name the name to map to the ID
+    /// @returns true if the ID did not have a previously registered name.
+    bool Register(uint32_t id, const std::string& name);
 
-  /// Saves a sanitized name for a member of a struct, if that member
-  /// does not yet have a registered name.
-  /// @param struct_id the SPIR-V ID for the struct
-  /// @param member_index the index of the member inside the struct
-  /// @param suggested_name the suggested name
-  /// @returns true if a name was newly registered
-  bool SuggestSanitizedMemberName(uint32_t struct_id,
-                                  uint32_t member_index,
-                                  const std::string& suggested_name);
+    /// Registers a name, but not associated to any ID. Fails and emits
+    /// a diagnostic if the name was already registered.
+    /// @param name the name to register
+    /// @returns true if the name was not already reegistered.
+    bool RegisterWithoutId(const std::string& name);
 
-  /// Ensure there are member names registered for members of the given struct
-  /// such that:
-  /// - Each member has a non-empty sanitized name.
-  /// - No two members in the struct have the same name.
-  /// @param struct_id the SPIR-V ID for the struct
-  /// @param num_members the number of members in the struct
-  void ResolveMemberNamesForStruct(uint32_t struct_id, uint32_t num_members);
+    /// Saves a sanitized name for the given ID, if that ID does not yet
+    /// have a registered name, and if the sanitized name has not already
+    /// been registered to a different ID.
+    /// @param id the SPIR-V ID
+    /// @param suggested_name the suggested name
+    /// @returns true if a name was newly registered for the ID
+    bool SuggestSanitizedName(uint32_t id, const std::string& suggested_name);
 
- private:
-  FailStream fail_stream_;
+    /// Saves a sanitized name for a member of a struct, if that member
+    /// does not yet have a registered name.
+    /// @param struct_id the SPIR-V ID for the struct
+    /// @param member_index the index of the member inside the struct
+    /// @param suggested_name the suggested name
+    /// @returns true if a name was newly registered
+    bool SuggestSanitizedMemberName(uint32_t struct_id,
+                                    uint32_t member_index,
+                                    const std::string& suggested_name);
 
-  // Maps an ID to its registered name.
-  std::unordered_map<uint32_t, std::string> id_to_name_;
-  // Maps a name to a SPIR-V ID, or 0 (the case for derived names).
-  std::unordered_map<std::string, uint32_t> name_to_id_;
+    /// Ensure there are member names registered for members of the given struct
+    /// such that:
+    /// - Each member has a non-empty sanitized name.
+    /// - No two members in the struct have the same name.
+    /// @param struct_id the SPIR-V ID for the struct
+    /// @param num_members the number of members in the struct
+    void ResolveMemberNamesForStruct(uint32_t struct_id, uint32_t num_members);
 
-  // Maps a struct id and member index to a suggested sanitized name.
-  // If entry k in the vector is an empty string, then a suggestion
-  // was recorded for a higher-numbered index, but not for index k.
-  std::unordered_map<uint32_t, std::vector<std::string>> struct_member_names_;
+  private:
+    FailStream fail_stream_;
 
-  // Saved search id suffix for a given base name. Used by
-  // FindUnusedDerivedName().
-  std::unordered_map<std::string, uint32_t> next_unusued_derived_name_id_;
+    // Maps an ID to its registered name.
+    std::unordered_map<uint32_t, std::string> id_to_name_;
+    // Maps a name to a SPIR-V ID, or 0 (the case for derived names).
+    std::unordered_map<std::string, uint32_t> name_to_id_;
+
+    // Maps a struct id and member index to a suggested sanitized name.
+    // If entry k in the vector is an empty string, then a suggestion
+    // was recorded for a higher-numbered index, but not for index k.
+    std::unordered_map<uint32_t, std::vector<std::string>> struct_member_names_;
+
+    // Saved search id suffix for a given base name. Used by
+    // FindUnusedDerivedName().
+    std::unordered_map<std::string, uint32_t> next_unusued_derived_name_id_;
 };
 
 }  // namespace tint::reader::spirv
diff --git a/src/tint/reader/spirv/namer_test.cc b/src/tint/reader/spirv/namer_test.cc
index 62cf56d..a24e03c 100644
--- a/src/tint/reader/spirv/namer_test.cc
+++ b/src/tint/reader/spirv/namer_test.cc
@@ -22,348 +22,341 @@
 using ::testing::Eq;
 
 class SpvNamerTest : public testing::Test {
- public:
-  SpvNamerTest() : fail_stream_(&success_, &errors_) {}
+  public:
+    SpvNamerTest() : fail_stream_(&success_, &errors_) {}
 
-  /// @returns the accumulated diagnostic strings
-  std::string error() { return errors_.str(); }
+    /// @returns the accumulated diagnostic strings
+    std::string error() { return errors_.str(); }
 
- protected:
-  std::stringstream errors_;
-  bool success_ = true;
-  FailStream fail_stream_;
+  protected:
+    std::stringstream errors_;
+    bool success_ = true;
+    FailStream fail_stream_;
 };
 
 TEST_F(SpvNamerTest, SanitizeEmpty) {
-  EXPECT_THAT(Namer::Sanitize(""), Eq("empty"));
+    EXPECT_THAT(Namer::Sanitize(""), Eq("empty"));
 }
 
 TEST_F(SpvNamerTest, SanitizeLeadingUnderscore) {
-  EXPECT_THAT(Namer::Sanitize("_"), Eq("x_"));
+    EXPECT_THAT(Namer::Sanitize("_"), Eq("x_"));
 }
 
 TEST_F(SpvNamerTest, SanitizeLeadingDigit) {
-  EXPECT_THAT(Namer::Sanitize("7zip"), Eq("x7zip"));
+    EXPECT_THAT(Namer::Sanitize("7zip"), Eq("x7zip"));
 }
 
 TEST_F(SpvNamerTest, SanitizeOkChars) {
-  EXPECT_THAT(Namer::Sanitize("_abcdef12345"), Eq("x_abcdef12345"));
+    EXPECT_THAT(Namer::Sanitize("_abcdef12345"), Eq("x_abcdef12345"));
 }
 
 TEST_F(SpvNamerTest, SanitizeNonIdentifierChars) {
-  EXPECT_THAT(Namer::Sanitize("a:1.2'f\n"), "a_1_2_f_");
+    EXPECT_THAT(Namer::Sanitize("a:1.2'f\n"), "a_1_2_f_");
 }
 
 TEST_F(SpvNamerTest, NoFailureToStart) {
-  Namer namer(fail_stream_);
-  EXPECT_TRUE(success_);
-  EXPECT_TRUE(error().empty());
+    Namer namer(fail_stream_);
+    EXPECT_TRUE(success_);
+    EXPECT_TRUE(error().empty());
 }
 
 TEST_F(SpvNamerTest, FailLogsError) {
-  Namer namer(fail_stream_);
-  const bool converted_result = namer.Fail() << "st. johns wood";
-  EXPECT_FALSE(converted_result);
-  EXPECT_EQ(error(), "st. johns wood");
-  EXPECT_FALSE(success_);
+    Namer namer(fail_stream_);
+    const bool converted_result = namer.Fail() << "st. johns wood";
+    EXPECT_FALSE(converted_result);
+    EXPECT_EQ(error(), "st. johns wood");
+    EXPECT_FALSE(success_);
 }
 
 TEST_F(SpvNamerTest, NoNameRecorded) {
-  Namer namer(fail_stream_);
+    Namer namer(fail_stream_);
 
-  EXPECT_FALSE(namer.HasName(12));
-  EXPECT_TRUE(success_);
-  EXPECT_TRUE(error().empty());
+    EXPECT_FALSE(namer.HasName(12));
+    EXPECT_TRUE(success_);
+    EXPECT_TRUE(error().empty());
 }
 
 TEST_F(SpvNamerTest, FindUnusedDerivedName_NoRecordedName) {
-  Namer namer(fail_stream_);
-  EXPECT_THAT(namer.FindUnusedDerivedName("eleanor"), Eq("eleanor"));
-  // Prove that it wasn't registered when first found.
-  EXPECT_THAT(namer.FindUnusedDerivedName("eleanor"), Eq("eleanor"));
+    Namer namer(fail_stream_);
+    EXPECT_THAT(namer.FindUnusedDerivedName("eleanor"), Eq("eleanor"));
+    // Prove that it wasn't registered when first found.
+    EXPECT_THAT(namer.FindUnusedDerivedName("eleanor"), Eq("eleanor"));
 }
 
 TEST_F(SpvNamerTest, FindUnusedDerivedName_HasRecordedName) {
-  Namer namer(fail_stream_);
-  namer.Register(12, "rigby");
-  EXPECT_THAT(namer.FindUnusedDerivedName("rigby"), Eq("rigby_1"));
+    Namer namer(fail_stream_);
+    namer.Register(12, "rigby");
+    EXPECT_THAT(namer.FindUnusedDerivedName("rigby"), Eq("rigby_1"));
 }
 
 TEST_F(SpvNamerTest, FindUnusedDerivedName_HasMultipleConflicts) {
-  Namer namer(fail_stream_);
-  namer.Register(12, "rigby");
-  namer.Register(13, "rigby_1");
-  namer.Register(14, "rigby_3");
-  // It picks the first non-conflicting suffix.
-  EXPECT_THAT(namer.FindUnusedDerivedName("rigby"), Eq("rigby_2"));
+    Namer namer(fail_stream_);
+    namer.Register(12, "rigby");
+    namer.Register(13, "rigby_1");
+    namer.Register(14, "rigby_3");
+    // It picks the first non-conflicting suffix.
+    EXPECT_THAT(namer.FindUnusedDerivedName("rigby"), Eq("rigby_2"));
 }
 
 TEST_F(SpvNamerTest, IsRegistered_NoRecordedName) {
-  Namer namer(fail_stream_);
-  EXPECT_FALSE(namer.IsRegistered("abbey"));
+    Namer namer(fail_stream_);
+    EXPECT_FALSE(namer.IsRegistered("abbey"));
 }
 
 TEST_F(SpvNamerTest, IsRegistered_RegisteredById) {
-  Namer namer(fail_stream_);
-  namer.Register(1, "abbey");
-  EXPECT_TRUE(namer.IsRegistered("abbey"));
+    Namer namer(fail_stream_);
+    namer.Register(1, "abbey");
+    EXPECT_TRUE(namer.IsRegistered("abbey"));
 }
 
 TEST_F(SpvNamerTest, IsRegistered_RegisteredByDerivation) {
-  Namer namer(fail_stream_);
-  const auto got = namer.MakeDerivedName("abbey");
-  EXPECT_TRUE(namer.IsRegistered("abbey"));
-  EXPECT_EQ(got, "abbey");
+    Namer namer(fail_stream_);
+    const auto got = namer.MakeDerivedName("abbey");
+    EXPECT_TRUE(namer.IsRegistered("abbey"));
+    EXPECT_EQ(got, "abbey");
 }
 
 TEST_F(SpvNamerTest, MakeDerivedName_NoRecordedName) {
-  Namer namer(fail_stream_);
-  EXPECT_THAT(namer.MakeDerivedName("eleanor"), Eq("eleanor"));
-  // Prove that it was registered when first found.
-  EXPECT_THAT(namer.MakeDerivedName("eleanor"), Eq("eleanor_1"));
+    Namer namer(fail_stream_);
+    EXPECT_THAT(namer.MakeDerivedName("eleanor"), Eq("eleanor"));
+    // Prove that it was registered when first found.
+    EXPECT_THAT(namer.MakeDerivedName("eleanor"), Eq("eleanor_1"));
 }
 
 TEST_F(SpvNamerTest, MakeDerivedName_HasRecordedName) {
-  Namer namer(fail_stream_);
-  namer.Register(12, "rigby");
-  EXPECT_THAT(namer.MakeDerivedName("rigby"), Eq("rigby_1"));
+    Namer namer(fail_stream_);
+    namer.Register(12, "rigby");
+    EXPECT_THAT(namer.MakeDerivedName("rigby"), Eq("rigby_1"));
 }
 
 TEST_F(SpvNamerTest, MakeDerivedName_HasMultipleConflicts) {
-  Namer namer(fail_stream_);
-  namer.Register(12, "rigby");
-  namer.Register(13, "rigby_1");
-  namer.Register(14, "rigby_3");
-  // It picks the first non-conflicting suffix.
-  EXPECT_THAT(namer.MakeDerivedName("rigby"), Eq("rigby_2"));
+    Namer namer(fail_stream_);
+    namer.Register(12, "rigby");
+    namer.Register(13, "rigby_1");
+    namer.Register(14, "rigby_3");
+    // It picks the first non-conflicting suffix.
+    EXPECT_THAT(namer.MakeDerivedName("rigby"), Eq("rigby_2"));
 }
 
 TEST_F(SpvNamerTest, RegisterWithoutId_Once) {
-  Namer namer(fail_stream_);
+    Namer namer(fail_stream_);
 
-  const std::string n("abbey");
-  EXPECT_FALSE(namer.IsRegistered(n));
-  EXPECT_TRUE(namer.RegisterWithoutId(n));
-  EXPECT_TRUE(namer.IsRegistered(n));
-  EXPECT_TRUE(success_);
-  EXPECT_TRUE(error().empty());
+    const std::string n("abbey");
+    EXPECT_FALSE(namer.IsRegistered(n));
+    EXPECT_TRUE(namer.RegisterWithoutId(n));
+    EXPECT_TRUE(namer.IsRegistered(n));
+    EXPECT_TRUE(success_);
+    EXPECT_TRUE(error().empty());
 }
 
 TEST_F(SpvNamerTest, RegisterWithoutId_Twice) {
-  Namer namer(fail_stream_);
+    Namer namer(fail_stream_);
 
-  const std::string n("abbey");
-  EXPECT_FALSE(namer.IsRegistered(n));
-  EXPECT_TRUE(namer.RegisterWithoutId(n));
-  // Fails on second attempt.
-  EXPECT_FALSE(namer.RegisterWithoutId(n));
-  EXPECT_FALSE(success_);
-  EXPECT_EQ(error(), "internal error: name already registered: abbey");
+    const std::string n("abbey");
+    EXPECT_FALSE(namer.IsRegistered(n));
+    EXPECT_TRUE(namer.RegisterWithoutId(n));
+    // Fails on second attempt.
+    EXPECT_FALSE(namer.RegisterWithoutId(n));
+    EXPECT_FALSE(success_);
+    EXPECT_EQ(error(), "internal error: name already registered: abbey");
 }
 
 TEST_F(SpvNamerTest, RegisterWithoutId_ConflictsWithIdRegisteredName) {
-  Namer namer(fail_stream_);
+    Namer namer(fail_stream_);
 
-  const std::string n("abbey");
-  EXPECT_TRUE(namer.Register(1, n));
-  EXPECT_TRUE(namer.IsRegistered(n));
-  // Fails on attempt to register without ID.
-  EXPECT_FALSE(namer.RegisterWithoutId(n));
-  EXPECT_FALSE(success_);
-  EXPECT_EQ(error(), "internal error: name already registered: abbey");
+    const std::string n("abbey");
+    EXPECT_TRUE(namer.Register(1, n));
+    EXPECT_TRUE(namer.IsRegistered(n));
+    // Fails on attempt to register without ID.
+    EXPECT_FALSE(namer.RegisterWithoutId(n));
+    EXPECT_FALSE(success_);
+    EXPECT_EQ(error(), "internal error: name already registered: abbey");
 }
 
 TEST_F(SpvNamerTest, Register_Once) {
-  Namer namer(fail_stream_);
+    Namer namer(fail_stream_);
 
-  const uint32_t id = 9;
-  EXPECT_FALSE(namer.HasName(id));
-  const bool save_result = namer.Register(id, "abbey road");
-  EXPECT_TRUE(save_result);
-  EXPECT_TRUE(namer.HasName(id));
-  EXPECT_EQ(namer.GetName(id), "abbey road");
-  EXPECT_TRUE(success_);
-  EXPECT_TRUE(error().empty());
+    const uint32_t id = 9;
+    EXPECT_FALSE(namer.HasName(id));
+    const bool save_result = namer.Register(id, "abbey road");
+    EXPECT_TRUE(save_result);
+    EXPECT_TRUE(namer.HasName(id));
+    EXPECT_EQ(namer.GetName(id), "abbey road");
+    EXPECT_TRUE(success_);
+    EXPECT_TRUE(error().empty());
 }
 
 TEST_F(SpvNamerTest, Register_TwoIds) {
-  Namer namer(fail_stream_);
+    Namer namer(fail_stream_);
 
-  EXPECT_FALSE(namer.HasName(8));
-  EXPECT_FALSE(namer.HasName(9));
-  EXPECT_TRUE(namer.Register(8, "abbey road"));
-  EXPECT_TRUE(namer.Register(9, "rubber soul"));
-  EXPECT_TRUE(namer.HasName(8));
-  EXPECT_TRUE(namer.HasName(9));
-  EXPECT_EQ(namer.GetName(9), "rubber soul");
-  EXPECT_EQ(namer.GetName(8), "abbey road");
-  EXPECT_TRUE(success_);
-  EXPECT_TRUE(error().empty());
+    EXPECT_FALSE(namer.HasName(8));
+    EXPECT_FALSE(namer.HasName(9));
+    EXPECT_TRUE(namer.Register(8, "abbey road"));
+    EXPECT_TRUE(namer.Register(9, "rubber soul"));
+    EXPECT_TRUE(namer.HasName(8));
+    EXPECT_TRUE(namer.HasName(9));
+    EXPECT_EQ(namer.GetName(9), "rubber soul");
+    EXPECT_EQ(namer.GetName(8), "abbey road");
+    EXPECT_TRUE(success_);
+    EXPECT_TRUE(error().empty());
 }
 
 TEST_F(SpvNamerTest, Register_FailsDueToIdReuse) {
-  Namer namer(fail_stream_);
+    Namer namer(fail_stream_);
 
-  const uint32_t id = 9;
-  EXPECT_TRUE(namer.Register(id, "abbey road"));
-  EXPECT_FALSE(namer.Register(id, "rubber soul"));
-  EXPECT_TRUE(namer.HasName(id));
-  EXPECT_EQ(namer.GetName(id), "abbey road");
-  EXPECT_FALSE(success_);
-  EXPECT_FALSE(error().empty());
+    const uint32_t id = 9;
+    EXPECT_TRUE(namer.Register(id, "abbey road"));
+    EXPECT_FALSE(namer.Register(id, "rubber soul"));
+    EXPECT_TRUE(namer.HasName(id));
+    EXPECT_EQ(namer.GetName(id), "abbey road");
+    EXPECT_FALSE(success_);
+    EXPECT_FALSE(error().empty());
 }
 
 TEST_F(SpvNamerTest, SuggestSanitizedName_TakeSuggestionWhenNoConflict) {
-  Namer namer(fail_stream_);
+    Namer namer(fail_stream_);
 
-  EXPECT_TRUE(namer.SuggestSanitizedName(1, "father"));
-  EXPECT_THAT(namer.GetName(1), Eq("father"));
+    EXPECT_TRUE(namer.SuggestSanitizedName(1, "father"));
+    EXPECT_THAT(namer.GetName(1), Eq("father"));
 }
 
-TEST_F(SpvNamerTest,
-       SuggestSanitizedName_RejectSuggestionWhenConflictOnSameId) {
-  Namer namer(fail_stream_);
+TEST_F(SpvNamerTest, SuggestSanitizedName_RejectSuggestionWhenConflictOnSameId) {
+    Namer namer(fail_stream_);
 
-  namer.Register(1, "lennon");
-  EXPECT_FALSE(namer.SuggestSanitizedName(1, "mccartney"));
-  EXPECT_THAT(namer.GetName(1), Eq("lennon"));
+    namer.Register(1, "lennon");
+    EXPECT_FALSE(namer.SuggestSanitizedName(1, "mccartney"));
+    EXPECT_THAT(namer.GetName(1), Eq("lennon"));
 }
 
 TEST_F(SpvNamerTest, SuggestSanitizedName_SanitizeSuggestion) {
-  Namer namer(fail_stream_);
+    Namer namer(fail_stream_);
 
-  EXPECT_TRUE(namer.SuggestSanitizedName(9, "m:kenzie"));
-  EXPECT_THAT(namer.GetName(9), Eq("m_kenzie"));
+    EXPECT_TRUE(namer.SuggestSanitizedName(9, "m:kenzie"));
+    EXPECT_THAT(namer.GetName(9), Eq("m_kenzie"));
 }
 
-TEST_F(SpvNamerTest,
-       SuggestSanitizedName_GenerateNewNameWhenConflictOnDifferentId) {
-  Namer namer(fail_stream_);
+TEST_F(SpvNamerTest, SuggestSanitizedName_GenerateNewNameWhenConflictOnDifferentId) {
+    Namer namer(fail_stream_);
 
-  namer.Register(7, "rice");
-  EXPECT_TRUE(namer.SuggestSanitizedName(9, "rice"));
-  EXPECT_THAT(namer.GetName(9), Eq("rice_1"));
+    namer.Register(7, "rice");
+    EXPECT_TRUE(namer.SuggestSanitizedName(9, "rice"));
+    EXPECT_THAT(namer.GetName(9), Eq("rice_1"));
 }
 
 TEST_F(SpvNamerTest, GetMemberName_EmptyStringForUnvisitedStruct) {
-  Namer namer(fail_stream_);
-  EXPECT_THAT(namer.GetMemberName(1, 2), Eq(""));
+    Namer namer(fail_stream_);
+    EXPECT_THAT(namer.GetMemberName(1, 2), Eq(""));
 }
 
 TEST_F(SpvNamerTest, GetMemberName_EmptyStringForUnvisitedMember) {
-  Namer namer(fail_stream_);
-  namer.SuggestSanitizedMemberName(1, 2, "mother");
-  EXPECT_THAT(namer.GetMemberName(1, 0), Eq(""));
+    Namer namer(fail_stream_);
+    namer.SuggestSanitizedMemberName(1, 2, "mother");
+    EXPECT_THAT(namer.GetMemberName(1, 0), Eq(""));
 }
 
 TEST_F(SpvNamerTest, SuggestSanitizedMemberName_TakeSuggestionWhenNoConflict) {
-  Namer namer(fail_stream_);
-  EXPECT_TRUE(namer.SuggestSanitizedMemberName(1, 2, "mother"));
-  EXPECT_THAT(namer.GetMemberName(1, 2), Eq("mother"));
+    Namer namer(fail_stream_);
+    EXPECT_TRUE(namer.SuggestSanitizedMemberName(1, 2, "mother"));
+    EXPECT_THAT(namer.GetMemberName(1, 2), Eq("mother"));
 }
 
 TEST_F(SpvNamerTest, SuggestSanitizedMemberName_TakeSanitizedSuggestion) {
-  Namer namer(fail_stream_);
-  EXPECT_TRUE(namer.SuggestSanitizedMemberName(1, 2, "m:t%er"));
-  EXPECT_THAT(namer.GetMemberName(1, 2), Eq("m_t_er"));
+    Namer namer(fail_stream_);
+    EXPECT_TRUE(namer.SuggestSanitizedMemberName(1, 2, "m:t%er"));
+    EXPECT_THAT(namer.GetMemberName(1, 2), Eq("m_t_er"));
 }
 
 TEST_F(
     SpvNamerTest,
     SuggestSanitizedMemberName_TakeSuggestionWhenNoConflictAfterSuggestionForLowerMember) {  // NOLINT
-  Namer namer(fail_stream_);
-  EXPECT_TRUE(namer.SuggestSanitizedMemberName(1, 7, "mother"));
-  EXPECT_THAT(namer.GetMemberName(1, 2), Eq(""));
-  EXPECT_TRUE(namer.SuggestSanitizedMemberName(1, 2, "mary"));
-  EXPECT_THAT(namer.GetMemberName(1, 2), Eq("mary"));
+    Namer namer(fail_stream_);
+    EXPECT_TRUE(namer.SuggestSanitizedMemberName(1, 7, "mother"));
+    EXPECT_THAT(namer.GetMemberName(1, 2), Eq(""));
+    EXPECT_TRUE(namer.SuggestSanitizedMemberName(1, 2, "mary"));
+    EXPECT_THAT(namer.GetMemberName(1, 2), Eq("mary"));
 }
 
-TEST_F(SpvNamerTest,
-       SuggestSanitizedMemberName_RejectSuggestionIfConflictOnMember) {
-  Namer namer(fail_stream_);
-  EXPECT_TRUE(namer.SuggestSanitizedMemberName(1, 2, "mother"));
-  EXPECT_FALSE(namer.SuggestSanitizedMemberName(1, 2, "mary"));
-  EXPECT_THAT(namer.GetMemberName(1, 2), Eq("mother"));
+TEST_F(SpvNamerTest, SuggestSanitizedMemberName_RejectSuggestionIfConflictOnMember) {
+    Namer namer(fail_stream_);
+    EXPECT_TRUE(namer.SuggestSanitizedMemberName(1, 2, "mother"));
+    EXPECT_FALSE(namer.SuggestSanitizedMemberName(1, 2, "mary"));
+    EXPECT_THAT(namer.GetMemberName(1, 2), Eq("mother"));
 }
 
 TEST_F(SpvNamerTest, Name_GeneratesNameIfNoneRegistered) {
-  Namer namer(fail_stream_);
-  EXPECT_THAT(namer.Name(14), Eq("x_14"));
+    Namer namer(fail_stream_);
+    EXPECT_THAT(namer.Name(14), Eq("x_14"));
 }
 
 TEST_F(SpvNamerTest, Name_GeneratesNameWithoutConflict) {
-  Namer namer(fail_stream_);
-  namer.Register(42, "x_14");
-  EXPECT_THAT(namer.Name(14), Eq("x_14_1"));
+    Namer namer(fail_stream_);
+    namer.Register(42, "x_14");
+    EXPECT_THAT(namer.Name(14), Eq("x_14_1"));
 }
 
 TEST_F(SpvNamerTest, Name_ReturnsRegisteredName) {
-  Namer namer(fail_stream_);
-  namer.Register(14, "hello");
-  EXPECT_THAT(namer.Name(14), Eq("hello"));
+    Namer namer(fail_stream_);
+    namer.Register(14, "hello");
+    EXPECT_THAT(namer.Name(14), Eq("hello"));
 }
 
-TEST_F(SpvNamerTest,
-       ResolveMemberNamesForStruct_GeneratesRegularNamesOnItsOwn) {
-  Namer namer(fail_stream_);
-  namer.ResolveMemberNamesForStruct(2, 4);
-  EXPECT_THAT(namer.GetMemberName(2, 0), Eq("field0"));
-  EXPECT_THAT(namer.GetMemberName(2, 1), Eq("field1"));
-  EXPECT_THAT(namer.GetMemberName(2, 2), Eq("field2"));
-  EXPECT_THAT(namer.GetMemberName(2, 3), Eq("field3"));
+TEST_F(SpvNamerTest, ResolveMemberNamesForStruct_GeneratesRegularNamesOnItsOwn) {
+    Namer namer(fail_stream_);
+    namer.ResolveMemberNamesForStruct(2, 4);
+    EXPECT_THAT(namer.GetMemberName(2, 0), Eq("field0"));
+    EXPECT_THAT(namer.GetMemberName(2, 1), Eq("field1"));
+    EXPECT_THAT(namer.GetMemberName(2, 2), Eq("field2"));
+    EXPECT_THAT(namer.GetMemberName(2, 3), Eq("field3"));
 }
 
-TEST_F(SpvNamerTest,
-       ResolveMemberNamesForStruct_ResolvesConflictBetweenSuggestedNames) {
-  Namer namer(fail_stream_);
-  namer.SuggestSanitizedMemberName(2, 0, "apple");
-  namer.SuggestSanitizedMemberName(2, 1, "apple");
-  namer.ResolveMemberNamesForStruct(2, 2);
-  EXPECT_THAT(namer.GetMemberName(2, 0), Eq("apple"));
-  EXPECT_THAT(namer.GetMemberName(2, 1), Eq("apple_1"));
+TEST_F(SpvNamerTest, ResolveMemberNamesForStruct_ResolvesConflictBetweenSuggestedNames) {
+    Namer namer(fail_stream_);
+    namer.SuggestSanitizedMemberName(2, 0, "apple");
+    namer.SuggestSanitizedMemberName(2, 1, "apple");
+    namer.ResolveMemberNamesForStruct(2, 2);
+    EXPECT_THAT(namer.GetMemberName(2, 0), Eq("apple"));
+    EXPECT_THAT(namer.GetMemberName(2, 1), Eq("apple_1"));
 }
 
 TEST_F(SpvNamerTest, ResolveMemberNamesForStruct_FillsUnsuggestedGaps) {
-  Namer namer(fail_stream_);
-  namer.SuggestSanitizedMemberName(2, 1, "apple");
-  namer.SuggestSanitizedMemberName(2, 2, "core");
-  namer.ResolveMemberNamesForStruct(2, 4);
-  EXPECT_THAT(namer.GetMemberName(2, 0), Eq("field0"));
-  EXPECT_THAT(namer.GetMemberName(2, 1), Eq("apple"));
-  EXPECT_THAT(namer.GetMemberName(2, 2), Eq("core"));
-  EXPECT_THAT(namer.GetMemberName(2, 3), Eq("field3"));
+    Namer namer(fail_stream_);
+    namer.SuggestSanitizedMemberName(2, 1, "apple");
+    namer.SuggestSanitizedMemberName(2, 2, "core");
+    namer.ResolveMemberNamesForStruct(2, 4);
+    EXPECT_THAT(namer.GetMemberName(2, 0), Eq("field0"));
+    EXPECT_THAT(namer.GetMemberName(2, 1), Eq("apple"));
+    EXPECT_THAT(namer.GetMemberName(2, 2), Eq("core"));
+    EXPECT_THAT(namer.GetMemberName(2, 3), Eq("field3"));
 }
 
-TEST_F(SpvNamerTest,
-       ResolveMemberNamesForStruct_GeneratedNameAvoidsConflictWithSuggestion) {
-  Namer namer(fail_stream_);
-  namer.SuggestSanitizedMemberName(2, 0, "field1");
-  namer.ResolveMemberNamesForStruct(2, 2);
-  EXPECT_THAT(namer.GetMemberName(2, 0), Eq("field1"));
-  EXPECT_THAT(namer.GetMemberName(2, 1), Eq("field1_1"));
+TEST_F(SpvNamerTest, ResolveMemberNamesForStruct_GeneratedNameAvoidsConflictWithSuggestion) {
+    Namer namer(fail_stream_);
+    namer.SuggestSanitizedMemberName(2, 0, "field1");
+    namer.ResolveMemberNamesForStruct(2, 2);
+    EXPECT_THAT(namer.GetMemberName(2, 0), Eq("field1"));
+    EXPECT_THAT(namer.GetMemberName(2, 1), Eq("field1_1"));
 }
 
-TEST_F(SpvNamerTest,
-       ResolveMemberNamesForStruct_TruncatesOutOfBoundsSuggestion) {
-  Namer namer(fail_stream_);
-  namer.SuggestSanitizedMemberName(2, 3, "sitar");
-  EXPECT_THAT(namer.GetMemberName(2, 3), Eq("sitar"));
-  namer.ResolveMemberNamesForStruct(2, 2);
-  EXPECT_THAT(namer.GetMemberName(2, 0), Eq("field0"));
-  EXPECT_THAT(namer.GetMemberName(2, 1), Eq("field1"));
-  EXPECT_THAT(namer.GetMemberName(2, 3), Eq(""));
+TEST_F(SpvNamerTest, ResolveMemberNamesForStruct_TruncatesOutOfBoundsSuggestion) {
+    Namer namer(fail_stream_);
+    namer.SuggestSanitizedMemberName(2, 3, "sitar");
+    EXPECT_THAT(namer.GetMemberName(2, 3), Eq("sitar"));
+    namer.ResolveMemberNamesForStruct(2, 2);
+    EXPECT_THAT(namer.GetMemberName(2, 0), Eq("field0"));
+    EXPECT_THAT(namer.GetMemberName(2, 1), Eq("field1"));
+    EXPECT_THAT(namer.GetMemberName(2, 3), Eq(""));
 }
 
 using SpvNamerReservedWordTest = ::testing::TestWithParam<std::string>;
 
 TEST_P(SpvNamerReservedWordTest, ReservedWordsAreUsed) {
-  bool success;
-  std::stringstream errors;
-  FailStream fail_stream(&success, &errors);
-  Namer namer(fail_stream);
-  const std::string reserved = GetParam();
-  // Since it's reserved, it's marked as used, and we can't register an ID
-  EXPECT_THAT(namer.FindUnusedDerivedName(reserved), Eq(reserved + "_1"));
+    bool success;
+    std::stringstream errors;
+    FailStream fail_stream(&success, &errors);
+    Namer namer(fail_stream);
+    const std::string reserved = GetParam();
+    // Since it's reserved, it's marked as used, and we can't register an ID
+    EXPECT_THAT(namer.FindUnusedDerivedName(reserved), Eq(reserved + "_1"));
 }
 
 INSTANTIATE_TEST_SUITE_P(SpvParserTest_ReservedWords,
diff --git a/src/tint/reader/spirv/parser.cc b/src/tint/reader/spirv/parser.cc
index ebb5bc4..f430d94 100644
--- a/src/tint/reader/spirv/parser.cc
+++ b/src/tint/reader/spirv/parser.cc
@@ -27,35 +27,35 @@
 namespace tint::reader::spirv {
 
 Program Parse(const std::vector<uint32_t>& input) {
-  ParserImpl parser(input);
-  bool parsed = parser.Parse();
+    ParserImpl parser(input);
+    bool parsed = parser.Parse();
 
-  ProgramBuilder& builder = parser.builder();
-  if (!parsed) {
-    // TODO(bclayton): Migrate spirv::ParserImpl to using diagnostics.
-    builder.Diagnostics().add_error(diag::System::Reader, parser.error());
-    return Program(std::move(builder));
-  }
+    ProgramBuilder& builder = parser.builder();
+    if (!parsed) {
+        // TODO(bclayton): Migrate spirv::ParserImpl to using diagnostics.
+        builder.Diagnostics().add_error(diag::System::Reader, parser.error());
+        return Program(std::move(builder));
+    }
 
-  // The SPIR-V parser can construct disjoint AST nodes, which is invalid for
-  // the Resolver. Clone the Program to clean these up.
-  builder.SetResolveOnBuild(false);
-  Program program_with_disjoint_ast(std::move(builder));
+    // The SPIR-V parser can construct disjoint AST nodes, which is invalid for
+    // the Resolver. Clone the Program to clean these up.
+    builder.SetResolveOnBuild(false);
+    Program program_with_disjoint_ast(std::move(builder));
 
-  ProgramBuilder output;
-  CloneContext(&output, &program_with_disjoint_ast, false).Clone();
-  auto program = Program(std::move(output));
-  if (!program.IsValid()) {
-    return program;
-  }
+    ProgramBuilder output;
+    CloneContext(&output, &program_with_disjoint_ast, false).Clone();
+    auto program = Program(std::move(output));
+    if (!program.IsValid()) {
+        return program;
+    }
 
-  transform::Manager manager;
-  manager.Add<transform::Unshadow>();
-  manager.Add<transform::SimplifyPointers>();
-  manager.Add<transform::DecomposeStridedMatrix>();
-  manager.Add<transform::DecomposeStridedArray>();
-  manager.Add<transform::RemoveUnreachableStatements>();
-  return manager.Run(&program).program;
+    transform::Manager manager;
+    manager.Add<transform::Unshadow>();
+    manager.Add<transform::SimplifyPointers>();
+    manager.Add<transform::DecomposeStridedMatrix>();
+    manager.Add<transform::DecomposeStridedArray>();
+    manager.Add<transform::RemoveUnreachableStatements>();
+    return manager.Run(&program).program;
 }
 
 }  // namespace tint::reader::spirv
diff --git a/src/tint/reader/spirv/parser_impl.cc b/src/tint/reader/spirv/parser_impl.cc
index 6cf8e7a..28dc856 100644
--- a/src/tint/reader/spirv/parser_impl.cc
+++ b/src/tint/reader/spirv/parser_impl.cc
@@ -27,9 +27,9 @@
 #include "src/tint/ast/type_name.h"
 #include "src/tint/ast/unary_op_expression.h"
 #include "src/tint/reader/spirv/function.h"
-#include "src/tint/sem/depth_texture_type.h"
-#include "src/tint/sem/multisampled_texture_type.h"
-#include "src/tint/sem/sampled_texture_type.h"
+#include "src/tint/sem/depth_texture.h"
+#include "src/tint/sem/multisampled_texture.h"
+#include "src/tint/sem/sampled_texture.h"
 #include "src/tint/utils/unique_vector.h"
 
 namespace tint::reader::spirv {
@@ -45,101 +45,100 @@
 // A FunctionTraverser is used to compute an ordering of functions in the
 // module such that callees precede callers.
 class FunctionTraverser {
- public:
-  explicit FunctionTraverser(const spvtools::opt::Module& module)
-      : module_(module) {}
+  public:
+    explicit FunctionTraverser(const spvtools::opt::Module& module) : module_(module) {}
 
-  // @returns the functions in the modules such that callees precede callers.
-  std::vector<const spvtools::opt::Function*> TopologicallyOrderedFunctions() {
-    visited_.clear();
-    ordered_.clear();
-    id_to_func_.clear();
-    for (const auto& f : module_) {
-      id_to_func_[f.result_id()] = &f;
-    }
-    for (const auto& f : module_) {
-      Visit(f);
-    }
-    return ordered_;
-  }
-
- private:
-  void Visit(const spvtools::opt::Function& f) {
-    if (visited_.count(&f)) {
-      return;
-    }
-    visited_.insert(&f);
-    for (const auto& bb : f) {
-      for (const auto& inst : bb) {
-        if (inst.opcode() != SpvOpFunctionCall) {
-          continue;
+    // @returns the functions in the modules such that callees precede callers.
+    std::vector<const spvtools::opt::Function*> TopologicallyOrderedFunctions() {
+        visited_.clear();
+        ordered_.clear();
+        id_to_func_.clear();
+        for (const auto& f : module_) {
+            id_to_func_[f.result_id()] = &f;
         }
-        const auto* callee = id_to_func_[inst.GetSingleWordInOperand(0)];
-        if (callee) {
-          Visit(*callee);
+        for (const auto& f : module_) {
+            Visit(f);
         }
-      }
+        return ordered_;
     }
-    ordered_.push_back(&f);
-  }
 
-  const spvtools::opt::Module& module_;
-  std::unordered_set<const spvtools::opt::Function*> visited_;
-  std::unordered_map<uint32_t, const spvtools::opt::Function*> id_to_func_;
-  std::vector<const spvtools::opt::Function*> ordered_;
+  private:
+    void Visit(const spvtools::opt::Function& f) {
+        if (visited_.count(&f)) {
+            return;
+        }
+        visited_.insert(&f);
+        for (const auto& bb : f) {
+            for (const auto& inst : bb) {
+                if (inst.opcode() != SpvOpFunctionCall) {
+                    continue;
+                }
+                const auto* callee = id_to_func_[inst.GetSingleWordInOperand(0)];
+                if (callee) {
+                    Visit(*callee);
+                }
+            }
+        }
+        ordered_.push_back(&f);
+    }
+
+    const spvtools::opt::Module& module_;
+    std::unordered_set<const spvtools::opt::Function*> visited_;
+    std::unordered_map<uint32_t, const spvtools::opt::Function*> id_to_func_;
+    std::vector<const spvtools::opt::Function*> ordered_;
 };
 
 // Returns true if the opcode operates as if its operands are signed integral.
 bool AssumesSignedOperands(SpvOp opcode) {
-  switch (opcode) {
-    case SpvOpSNegate:
-    case SpvOpSDiv:
-    case SpvOpSRem:
-    case SpvOpSMod:
-    case SpvOpSLessThan:
-    case SpvOpSLessThanEqual:
-    case SpvOpSGreaterThan:
-    case SpvOpSGreaterThanEqual:
-    case SpvOpConvertSToF:
-      return true;
-    default:
-      break;
-  }
-  return false;
+    switch (opcode) {
+        case SpvOpSNegate:
+        case SpvOpSDiv:
+        case SpvOpSRem:
+        case SpvOpSMod:
+        case SpvOpSLessThan:
+        case SpvOpSLessThanEqual:
+        case SpvOpSGreaterThan:
+        case SpvOpSGreaterThanEqual:
+        case SpvOpConvertSToF:
+            return true;
+        default:
+            break;
+    }
+    return false;
 }
 
 // Returns true if the GLSL extended instruction expects operands to be signed.
 // @param extended_opcode GLSL.std.450 opcode
 // @returns true if all operands must be signed integral type
 bool AssumesSignedOperands(GLSLstd450 extended_opcode) {
-  switch (extended_opcode) {
-    case GLSLstd450SAbs:
-    case GLSLstd450SSign:
-    case GLSLstd450SMin:
-    case GLSLstd450SMax:
-    case GLSLstd450SClamp:
-      return true;
-    default:
-      break;
-  }
-  return false;
+    switch (extended_opcode) {
+        case GLSLstd450SAbs:
+        case GLSLstd450SSign:
+        case GLSLstd450SMin:
+        case GLSLstd450SMax:
+        case GLSLstd450SClamp:
+            return true;
+        default:
+            break;
+    }
+    return false;
 }
 
 // Returns true if the opcode operates as if its operands are unsigned integral.
 bool AssumesUnsignedOperands(SpvOp opcode) {
-  switch (opcode) {
-    case SpvOpUDiv:
-    case SpvOpUMod:
-    case SpvOpULessThan:
-    case SpvOpULessThanEqual:
-    case SpvOpUGreaterThan:
-    case SpvOpUGreaterThanEqual:
-    case SpvOpConvertUToF:
-      return true;
-    default:
-      break;
-  }
-  return false;
+    switch (opcode) {
+        case SpvOpUDiv:
+        case SpvOpUMod:
+        case SpvOpULessThan:
+        case SpvOpULessThanEqual:
+        case SpvOpUGreaterThan:
+        case SpvOpUGreaterThanEqual:
+        case SpvOpConvertUToF:
+            return true;
+        default:
+            break;
+    }
+    return false;
 }
 
 // Returns true if the GLSL extended instruction expects operands to be
@@ -147,15 +146,15 @@
 // @param extended_opcode GLSL.std.450 opcode
 // @returns true if all operands must be unsigned integral type
 bool AssumesUnsignedOperands(GLSLstd450 extended_opcode) {
-  switch (extended_opcode) {
-    case GLSLstd450UMin:
-    case GLSLstd450UMax:
-    case GLSLstd450UClamp:
-      return true;
-    default:
-      break;
-  }
-  return false;
+    switch (extended_opcode) {
+        case GLSLstd450UMin:
+        case GLSLstd450UMax:
+        case GLSLstd450UClamp:
+            return true;
+        default:
+            break;
+    }
+    return false;
 }
 
 // Returns true if the corresponding WGSL operation requires
@@ -163,49 +162,49 @@
 // first operand, and it's not one of the OpU* or OpS* instructions.
 // (Those are handled via MakeOperand.)
 bool AssumesSecondOperandSignednessMatchesFirstOperand(SpvOp opcode) {
-  switch (opcode) {
-    // All the OpI* integer binary operations.
-    case SpvOpIAdd:
-    case SpvOpISub:
-    case SpvOpIMul:
-    case SpvOpIEqual:
-    case SpvOpINotEqual:
-    // All the bitwise integer binary operations.
-    case SpvOpBitwiseAnd:
-    case SpvOpBitwiseOr:
-    case SpvOpBitwiseXor:
-      return true;
-    default:
-      break;
-  }
-  return false;
+    switch (opcode) {
+        // All the OpI* integer binary operations.
+        case SpvOpIAdd:
+        case SpvOpISub:
+        case SpvOpIMul:
+        case SpvOpIEqual:
+        case SpvOpINotEqual:
+        // All the bitwise integer binary operations.
+        case SpvOpBitwiseAnd:
+        case SpvOpBitwiseOr:
+        case SpvOpBitwiseXor:
+            return true;
+        default:
+            break;
+    }
+    return false;
 }
 
 // Returns true if the corresponding WGSL operation requires
 // the signedness of the result to match the signedness of the first operand.
 bool AssumesResultSignednessMatchesFirstOperand(SpvOp opcode) {
-  switch (opcode) {
-    case SpvOpNot:
-    case SpvOpSNegate:
-    case SpvOpBitCount:
-    case SpvOpBitReverse:
-    case SpvOpSDiv:
-    case SpvOpSMod:
-    case SpvOpSRem:
-    case SpvOpIAdd:
-    case SpvOpISub:
-    case SpvOpIMul:
-    case SpvOpBitwiseAnd:
-    case SpvOpBitwiseOr:
-    case SpvOpBitwiseXor:
-    case SpvOpShiftLeftLogical:
-    case SpvOpShiftRightLogical:
-    case SpvOpShiftRightArithmetic:
-      return true;
-    default:
-      break;
-  }
-  return false;
+    switch (opcode) {
+        case SpvOpNot:
+        case SpvOpSNegate:
+        case SpvOpBitCount:
+        case SpvOpBitReverse:
+        case SpvOpSDiv:
+        case SpvOpSMod:
+        case SpvOpSRem:
+        case SpvOpIAdd:
+        case SpvOpISub:
+        case SpvOpIMul:
+        case SpvOpBitwiseAnd:
+        case SpvOpBitwiseOr:
+        case SpvOpBitwiseXor:
+        case SpvOpShiftLeftLogical:
+        case SpvOpShiftRightLogical:
+        case SpvOpShiftRightArithmetic:
+            return true;
+        default:
+            break;
+    }
+    return false;
 }
 
 // Returns true if the extended instruction requires the signedness of the
@@ -213,42 +212,42 @@
 // @param extended_opcode GLSL.std.450 opcode
 // @returns true if the result type must match the first operand type.
 bool AssumesResultSignednessMatchesFirstOperand(GLSLstd450 extended_opcode) {
-  switch (extended_opcode) {
-    case GLSLstd450SAbs:
-    case GLSLstd450SSign:
-    case GLSLstd450SMin:
-    case GLSLstd450SMax:
-    case GLSLstd450SClamp:
-    case GLSLstd450UMin:
-    case GLSLstd450UMax:
-    case GLSLstd450UClamp:
-      // TODO(dneto): FindSMsb?
-      // TODO(dneto): FindUMsb?
-      return true;
-    default:
-      break;
-  }
-  return false;
+    switch (extended_opcode) {
+        case GLSLstd450SAbs:
+        case GLSLstd450SSign:
+        case GLSLstd450SMin:
+        case GLSLstd450SMax:
+        case GLSLstd450SClamp:
+        case GLSLstd450UMin:
+        case GLSLstd450UMax:
+        case GLSLstd450UClamp:
+            // TODO(dneto): FindSMsb?
+            // TODO(dneto): FindUMsb?
+            return true;
+        default:
+            break;
+    }
+    return false;
 }
 
 // @param a SPIR-V decoration
 // @return true when the given decoration is a pipeline decoration other than a
 // bulitin variable.
 bool IsPipelineDecoration(const Decoration& deco) {
-  if (deco.size() < 1) {
+    if (deco.size() < 1) {
+        return false;
+    }
+    switch (deco[0]) {
+        case SpvDecorationLocation:
+        case SpvDecorationFlat:
+        case SpvDecorationNoPerspective:
+        case SpvDecorationCentroid:
+        case SpvDecorationSample:
+            return true;
+        default:
+            break;
+    }
     return false;
-  }
-  switch (deco[0]) {
-    case SpvDecorationLocation:
-    case SpvDecorationFlat:
-    case SpvDecorationNoPerspective:
-    case SpvDecorationCentroid:
-    case SpvDecorationSample:
-      return true;
-    default:
-      break;
-  }
-  return false;
 }
 
 }  // namespace
@@ -259,8 +258,7 @@
 
 TypedExpression& TypedExpression::operator=(const TypedExpression&) = default;
 
-TypedExpression::TypedExpression(const Type* type_in,
-                                 const ast::Expression* expr_in)
+TypedExpression::TypedExpression(const Type* type_in, const ast::Expression* expr_in)
     : type(type_in), expr(expr_in) {}
 
 ParserImpl::ParserImpl(const std::vector<uint32_t>& spv_binary)
@@ -270,1341 +268,1288 @@
       namer_(fail_stream_),
       enum_converter_(fail_stream_),
       tools_context_(kInputEnv) {
-  // Create a message consumer to propagate error messages from SPIRV-Tools
-  // out as our own failures.
-  message_consumer_ = [this](spv_message_level_t level, const char* /*source*/,
-                             const spv_position_t& position,
-                             const char* message) {
-    switch (level) {
-      // Ignore info and warning message.
-      case SPV_MSG_WARNING:
-      case SPV_MSG_INFO:
-        break;
-      // Otherwise, propagate the error.
-      default:
-        // For binary validation errors, we only have the instruction
-        // number.  It's not text, so there is no column number.
-        this->Fail() << "line:" << position.index << ": " << message;
-    }
-  };
+    // Create a message consumer to propagate error messages from SPIRV-Tools
+    // out as our own failures.
+    message_consumer_ = [this](spv_message_level_t level, const char* /*source*/,
+                               const spv_position_t& position, const char* message) {
+        switch (level) {
+            // Ignore info and warning message.
+            case SPV_MSG_WARNING:
+            case SPV_MSG_INFO:
+                break;
+            // Otherwise, propagate the error.
+            default:
+                // For binary validation errors, we only have the instruction
+                // number.  It's not text, so there is no column number.
+                this->Fail() << "line:" << position.index << ": " << message;
+        }
+    };
 }
 
 ParserImpl::~ParserImpl() = default;
 
 bool ParserImpl::Parse() {
-  // Set up use of SPIRV-Tools utilities.
-  spvtools::SpirvTools spv_tools(kInputEnv);
+    // Set up use of SPIRV-Tools utilities.
+    spvtools::SpirvTools spv_tools(kInputEnv);
 
-  // Error messages from SPIRV-Tools are forwarded as failures, including
-  // setting |success_| to false.
-  spv_tools.SetMessageConsumer(message_consumer_);
+    // Error messages from SPIRV-Tools are forwarded as failures, including
+    // setting |success_| to false.
+    spv_tools.SetMessageConsumer(message_consumer_);
 
-  if (!success_) {
-    return false;
-  }
+    if (!success_) {
+        return false;
+    }
 
-  // Only consider modules valid for Vulkan 1.0.  On failure, the message
-  // consumer will set the error status.
-  if (!spv_tools.Validate(spv_binary_)) {
-    success_ = false;
-    return false;
-  }
-  if (!BuildInternalModule()) {
-    return false;
-  }
-  if (!ParseInternalModule()) {
-    return false;
-  }
+    // Only consider modules valid for Vulkan 1.0.  On failure, the message
+    // consumer will set the error status.
+    if (!spv_tools.Validate(spv_binary_)) {
+        success_ = false;
+        return false;
+    }
+    if (!BuildInternalModule()) {
+        return false;
+    }
+    if (!ParseInternalModule()) {
+        return false;
+    }
 
-  return success_;
+    return success_;
 }
 
 Program ParserImpl::program() {
-  // TODO(dneto): Should we clear out spv_binary_ here, to reduce
-  // memory usage?
-  return tint::Program(std::move(builder_));
+    // TODO(dneto): Should we clear out spv_binary_ here, to reduce
+    // memory usage?
+    return tint::Program(std::move(builder_));
 }
 
 const Type* ParserImpl::ConvertType(uint32_t type_id, PtrAs ptr_as) {
-  if (!success_) {
+    if (!success_) {
+        return nullptr;
+    }
+
+    if (type_mgr_ == nullptr) {
+        Fail() << "ConvertType called when the internal module has not been built";
+        return nullptr;
+    }
+
+    auto* spirv_type = type_mgr_->GetType(type_id);
+    if (spirv_type == nullptr) {
+        Fail() << "ID is not a SPIR-V type: " << type_id;
+        return nullptr;
+    }
+
+    switch (spirv_type->kind()) {
+        case spvtools::opt::analysis::Type::kVoid:
+            return ty_.Void();
+        case spvtools::opt::analysis::Type::kBool:
+            return ty_.Bool();
+        case spvtools::opt::analysis::Type::kInteger:
+            return ConvertType(spirv_type->AsInteger());
+        case spvtools::opt::analysis::Type::kFloat:
+            return ConvertType(spirv_type->AsFloat());
+        case spvtools::opt::analysis::Type::kVector:
+            return ConvertType(spirv_type->AsVector());
+        case spvtools::opt::analysis::Type::kMatrix:
+            return ConvertType(spirv_type->AsMatrix());
+        case spvtools::opt::analysis::Type::kRuntimeArray:
+            return ConvertType(type_id, spirv_type->AsRuntimeArray());
+        case spvtools::opt::analysis::Type::kArray:
+            return ConvertType(type_id, spirv_type->AsArray());
+        case spvtools::opt::analysis::Type::kStruct:
+            return ConvertType(type_id, spirv_type->AsStruct());
+        case spvtools::opt::analysis::Type::kPointer:
+            return ConvertType(type_id, ptr_as, spirv_type->AsPointer());
+        case spvtools::opt::analysis::Type::kFunction:
+            // Tint doesn't have a Function type.
+            // We need to convert the result type and parameter types.
+            // But the SPIR-V defines those before defining the function
+            // type.  No further work is required here.
+            return nullptr;
+        case spvtools::opt::analysis::Type::kSampler:
+        case spvtools::opt::analysis::Type::kSampledImage:
+        case spvtools::opt::analysis::Type::kImage:
+            // Fake it for sampler and texture types.  These are handled in an
+            // entirely different way.
+            return ty_.Void();
+        default:
+            break;
+    }
+
+    Fail() << "unknown SPIR-V type with ID " << type_id << ": "
+           << def_use_mgr_->GetDef(type_id)->PrettyPrint();
     return nullptr;
-  }
-
-  if (type_mgr_ == nullptr) {
-    Fail() << "ConvertType called when the internal module has not been built";
-    return nullptr;
-  }
-
-  auto* spirv_type = type_mgr_->GetType(type_id);
-  if (spirv_type == nullptr) {
-    Fail() << "ID is not a SPIR-V type: " << type_id;
-    return nullptr;
-  }
-
-  switch (spirv_type->kind()) {
-    case spvtools::opt::analysis::Type::kVoid:
-      return ty_.Void();
-    case spvtools::opt::analysis::Type::kBool:
-      return ty_.Bool();
-    case spvtools::opt::analysis::Type::kInteger:
-      return ConvertType(spirv_type->AsInteger());
-    case spvtools::opt::analysis::Type::kFloat:
-      return ConvertType(spirv_type->AsFloat());
-    case spvtools::opt::analysis::Type::kVector:
-      return ConvertType(spirv_type->AsVector());
-    case spvtools::opt::analysis::Type::kMatrix:
-      return ConvertType(spirv_type->AsMatrix());
-    case spvtools::opt::analysis::Type::kRuntimeArray:
-      return ConvertType(type_id, spirv_type->AsRuntimeArray());
-    case spvtools::opt::analysis::Type::kArray:
-      return ConvertType(type_id, spirv_type->AsArray());
-    case spvtools::opt::analysis::Type::kStruct:
-      return ConvertType(type_id, spirv_type->AsStruct());
-    case spvtools::opt::analysis::Type::kPointer:
-      return ConvertType(type_id, ptr_as, spirv_type->AsPointer());
-    case spvtools::opt::analysis::Type::kFunction:
-      // Tint doesn't have a Function type.
-      // We need to convert the result type and parameter types.
-      // But the SPIR-V defines those before defining the function
-      // type.  No further work is required here.
-      return nullptr;
-    case spvtools::opt::analysis::Type::kSampler:
-    case spvtools::opt::analysis::Type::kSampledImage:
-    case spvtools::opt::analysis::Type::kImage:
-      // Fake it for sampler and texture types.  These are handled in an
-      // entirely different way.
-      return ty_.Void();
-    default:
-      break;
-  }
-
-  Fail() << "unknown SPIR-V type with ID " << type_id << ": "
-         << def_use_mgr_->GetDef(type_id)->PrettyPrint();
-  return nullptr;
 }
 
 DecorationList ParserImpl::GetDecorationsFor(uint32_t id) const {
-  DecorationList result;
-  const auto& decorations = deco_mgr_->GetDecorationsFor(id, true);
-  std::unordered_set<uint32_t> visited;
-  for (const auto* inst : decorations) {
-    if (inst->opcode() != SpvOpDecorate) {
-      continue;
-    }
-    // Example: OpDecorate %struct_id Block
-    // Example: OpDecorate %array_ty ArrayStride 16
-    auto decoration_kind = inst->GetSingleWordInOperand(1);
-    switch (decoration_kind) {
-      // Restrict and RestrictPointer have no effect in graphics APIs.
-      case SpvDecorationRestrict:
-      case SpvDecorationRestrictPointer:
-        break;
-      default:
-        if (visited.emplace(decoration_kind).second) {
-          std::vector<uint32_t> inst_as_words;
-          inst->ToBinaryWithoutAttachedDebugInsts(&inst_as_words);
-          Decoration d(inst_as_words.begin() + 2, inst_as_words.end());
-          result.push_back(d);
+    DecorationList result;
+    const auto& decorations = deco_mgr_->GetDecorationsFor(id, true);
+    std::unordered_set<uint32_t> visited;
+    for (const auto* inst : decorations) {
+        if (inst->opcode() != SpvOpDecorate) {
+            continue;
         }
-        break;
+        // Example: OpDecorate %struct_id Block
+        // Example: OpDecorate %array_ty ArrayStride 16
+        auto decoration_kind = inst->GetSingleWordInOperand(1);
+        switch (decoration_kind) {
+            // Restrict and RestrictPointer have no effect in graphics APIs.
+            case SpvDecorationRestrict:
+            case SpvDecorationRestrictPointer:
+                break;
+            default:
+                if (visited.emplace(decoration_kind).second) {
+                    std::vector<uint32_t> inst_as_words;
+                    inst->ToBinaryWithoutAttachedDebugInsts(&inst_as_words);
+                    Decoration d(inst_as_words.begin() + 2, inst_as_words.end());
+                    result.push_back(d);
+                }
+                break;
+        }
     }
-  }
-  return result;
+    return result;
 }
 
-DecorationList ParserImpl::GetDecorationsForMember(
-    uint32_t id,
-    uint32_t member_index) const {
-  DecorationList result;
-  const auto& decorations = deco_mgr_->GetDecorationsFor(id, true);
-  std::unordered_set<uint32_t> visited;
-  for (const auto* inst : decorations) {
-    // Example: OpMemberDecorate %struct_id 1 Offset 16
-    if ((inst->opcode() != SpvOpMemberDecorate) ||
-        (inst->GetSingleWordInOperand(1) != member_index)) {
-      continue;
-    }
-    auto decoration_kind = inst->GetSingleWordInOperand(2);
-    switch (decoration_kind) {
-      // Restrict and RestrictPointer have no effect in graphics APIs.
-      case SpvDecorationRestrict:
-      case SpvDecorationRestrictPointer:
-        break;
-      default:
-        if (visited.emplace(decoration_kind).second) {
-          std::vector<uint32_t> inst_as_words;
-          inst->ToBinaryWithoutAttachedDebugInsts(&inst_as_words);
-          Decoration d(inst_as_words.begin() + 3, inst_as_words.end());
-          result.push_back(d);
+DecorationList ParserImpl::GetDecorationsForMember(uint32_t id, uint32_t member_index) const {
+    DecorationList result;
+    const auto& decorations = deco_mgr_->GetDecorationsFor(id, true);
+    std::unordered_set<uint32_t> visited;
+    for (const auto* inst : decorations) {
+        // Example: OpMemberDecorate %struct_id 1 Offset 16
+        if ((inst->opcode() != SpvOpMemberDecorate) ||
+            (inst->GetSingleWordInOperand(1) != member_index)) {
+            continue;
+        }
+        auto decoration_kind = inst->GetSingleWordInOperand(2);
+        switch (decoration_kind) {
+            // Restrict and RestrictPointer have no effect in graphics APIs.
+            case SpvDecorationRestrict:
+            case SpvDecorationRestrictPointer:
+                break;
+            default:
+                if (visited.emplace(decoration_kind).second) {
+                    std::vector<uint32_t> inst_as_words;
+                    inst->ToBinaryWithoutAttachedDebugInsts(&inst_as_words);
+                    Decoration d(inst_as_words.begin() + 3, inst_as_words.end());
+                    result.push_back(d);
+                }
         }
     }
-  }
-  return result;
+    return result;
 }
 
 std::string ParserImpl::ShowType(uint32_t type_id) {
-  if (def_use_mgr_) {
-    const auto* type_inst = def_use_mgr_->GetDef(type_id);
-    if (type_inst) {
-      return type_inst->PrettyPrint();
+    if (def_use_mgr_) {
+        const auto* type_inst = def_use_mgr_->GetDef(type_id);
+        if (type_inst) {
+            return type_inst->PrettyPrint();
+        }
     }
-  }
-  return "SPIR-V type " + std::to_string(type_id);
+    return "SPIR-V type " + std::to_string(type_id);
 }
 
-ast::AttributeList ParserImpl::ConvertMemberDecoration(
-    uint32_t struct_type_id,
-    uint32_t member_index,
-    const Type* member_ty,
-    const Decoration& decoration) {
-  if (decoration.empty()) {
-    Fail() << "malformed SPIR-V decoration: it's empty";
-    return {};
-  }
-  switch (decoration[0]) {
-    case SpvDecorationOffset:
-      if (decoration.size() != 2) {
-        Fail()
-            << "malformed Offset decoration: expected 1 literal operand, has "
-            << decoration.size() - 1 << ": member " << member_index << " of "
-            << ShowType(struct_type_id);
+ast::AttributeList ParserImpl::ConvertMemberDecoration(uint32_t struct_type_id,
+                                                       uint32_t member_index,
+                                                       const Type* member_ty,
+                                                       const Decoration& decoration) {
+    if (decoration.empty()) {
+        Fail() << "malformed SPIR-V decoration: it's empty";
         return {};
-      }
-      return {
-          create<ast::StructMemberOffsetAttribute>(Source{}, decoration[1]),
-      };
-    case SpvDecorationNonReadable:
-      // WGSL doesn't have a member decoration for this.  Silently drop it.
-      return {};
-    case SpvDecorationNonWritable:
-      // WGSL doesn't have a member decoration for this.
-      return {};
-    case SpvDecorationColMajor:
-      // WGSL only supports column major matrices.
-      return {};
-    case SpvDecorationRelaxedPrecision:
-      // WGSL doesn't support relaxed precision.
-      return {};
-    case SpvDecorationRowMajor:
-      Fail() << "WGSL does not support row-major matrices: can't "
-                "translate member "
-             << member_index << " of " << ShowType(struct_type_id);
-      return {};
-    case SpvDecorationMatrixStride: {
-      if (decoration.size() != 2) {
-        Fail() << "malformed MatrixStride decoration: expected 1 literal "
-                  "operand, has "
-               << decoration.size() - 1 << ": member " << member_index << " of "
-               << ShowType(struct_type_id);
-        return {};
-      }
-      uint32_t stride = decoration[1];
-      auto* ty = member_ty->UnwrapAlias();
-      while (auto* arr = ty->As<Array>()) {
-        ty = arr->type->UnwrapAlias();
-      }
-      auto* mat = ty->As<Matrix>();
-      if (!mat) {
-        Fail() << "MatrixStride cannot be applied to type " << ty->String();
-        return {};
-      }
-      uint32_t natural_stride = (mat->rows == 2) ? 8 : 16;
-      if (stride == natural_stride) {
-        return {};  // Decoration matches the natural stride for the matrix
-      }
-      if (!member_ty->Is<Matrix>()) {
-        Fail() << "custom matrix strides not currently supported on array of "
-                  "matrices";
-        return {};
-      }
-      return {
-          create<ast::StrideAttribute>(Source{}, decoration[1]),
-          builder_.ASTNodes().Create<ast::DisableValidationAttribute>(
-              builder_.ID(), ast::DisabledValidation::kIgnoreStrideAttribute),
-      };
     }
-    default:
-      // TODO(dneto): Support the remaining member decorations.
-      break;
-  }
-  Fail() << "unhandled member decoration: " << decoration[0] << " on member "
-         << member_index << " of " << ShowType(struct_type_id);
-  return {};
+    switch (decoration[0]) {
+        case SpvDecorationOffset:
+            if (decoration.size() != 2) {
+                Fail() << "malformed Offset decoration: expected 1 literal operand, has "
+                       << decoration.size() - 1 << ": member " << member_index << " of "
+                       << ShowType(struct_type_id);
+                return {};
+            }
+            return {
+                create<ast::StructMemberOffsetAttribute>(Source{}, decoration[1]),
+            };
+        case SpvDecorationNonReadable:
+            // WGSL doesn't have a member decoration for this.  Silently drop it.
+            return {};
+        case SpvDecorationNonWritable:
+            // WGSL doesn't have a member decoration for this.
+            return {};
+        case SpvDecorationColMajor:
+            // WGSL only supports column major matrices.
+            return {};
+        case SpvDecorationRelaxedPrecision:
+            // WGSL doesn't support relaxed precision.
+            return {};
+        case SpvDecorationRowMajor:
+            Fail() << "WGSL does not support row-major matrices: can't "
+                      "translate member "
+                   << member_index << " of " << ShowType(struct_type_id);
+            return {};
+        case SpvDecorationMatrixStride: {
+            if (decoration.size() != 2) {
+                Fail() << "malformed MatrixStride decoration: expected 1 literal "
+                          "operand, has "
+                       << decoration.size() - 1 << ": member " << member_index << " of "
+                       << ShowType(struct_type_id);
+                return {};
+            }
+            uint32_t stride = decoration[1];
+            auto* ty = member_ty->UnwrapAlias();
+            while (auto* arr = ty->As<Array>()) {
+                ty = arr->type->UnwrapAlias();
+            }
+            auto* mat = ty->As<Matrix>();
+            if (!mat) {
+                Fail() << "MatrixStride cannot be applied to type " << ty->String();
+                return {};
+            }
+            uint32_t natural_stride = (mat->rows == 2) ? 8 : 16;
+            if (stride == natural_stride) {
+                return {};  // Decoration matches the natural stride for the matrix
+            }
+            if (!member_ty->Is<Matrix>()) {
+                Fail() << "custom matrix strides not currently supported on array of "
+                          "matrices";
+                return {};
+            }
+            return {
+                create<ast::StrideAttribute>(Source{}, decoration[1]),
+                builder_.ASTNodes().Create<ast::DisableValidationAttribute>(
+                    builder_.ID(), ast::DisabledValidation::kIgnoreStrideAttribute),
+            };
+        }
+        default:
+            // TODO(dneto): Support the remaining member decorations.
+            break;
+    }
+    Fail() << "unhandled member decoration: " << decoration[0] << " on member " << member_index
+           << " of " << ShowType(struct_type_id);
+    return {};
 }
 
 bool ParserImpl::BuildInternalModule() {
-  if (!success_) {
-    return false;
-  }
+    if (!success_) {
+        return false;
+    }
 
-  const spv_context& context = tools_context_.CContext();
-  ir_context_ = spvtools::BuildModule(context->target_env, context->consumer,
-                                      spv_binary_.data(), spv_binary_.size());
-  if (!ir_context_) {
-    return Fail() << "internal error: couldn't build the internal "
-                     "representation of the module";
-  }
-  module_ = ir_context_->module();
-  def_use_mgr_ = ir_context_->get_def_use_mgr();
-  constant_mgr_ = ir_context_->get_constant_mgr();
-  type_mgr_ = ir_context_->get_type_mgr();
-  deco_mgr_ = ir_context_->get_decoration_mgr();
+    const spv_context& context = tools_context_.CContext();
+    ir_context_ = spvtools::BuildModule(context->target_env, context->consumer, spv_binary_.data(),
+                                        spv_binary_.size());
+    if (!ir_context_) {
+        return Fail() << "internal error: couldn't build the internal "
+                         "representation of the module";
+    }
+    module_ = ir_context_->module();
+    def_use_mgr_ = ir_context_->get_def_use_mgr();
+    constant_mgr_ = ir_context_->get_constant_mgr();
+    type_mgr_ = ir_context_->get_type_mgr();
+    deco_mgr_ = ir_context_->get_decoration_mgr();
 
-  topologically_ordered_functions_ =
-      FunctionTraverser(*module_).TopologicallyOrderedFunctions();
+    topologically_ordered_functions_ = FunctionTraverser(*module_).TopologicallyOrderedFunctions();
 
-  return success_;
+    return success_;
 }
 
 void ParserImpl::ResetInternalModule() {
-  ir_context_.reset(nullptr);
-  module_ = nullptr;
-  def_use_mgr_ = nullptr;
-  constant_mgr_ = nullptr;
-  type_mgr_ = nullptr;
-  deco_mgr_ = nullptr;
+    ir_context_.reset(nullptr);
+    module_ = nullptr;
+    def_use_mgr_ = nullptr;
+    constant_mgr_ = nullptr;
+    type_mgr_ = nullptr;
+    deco_mgr_ = nullptr;
 
-  glsl_std_450_imports_.clear();
+    glsl_std_450_imports_.clear();
 }
 
 bool ParserImpl::ParseInternalModule() {
-  if (!success_) {
-    return false;
-  }
-  RegisterLineNumbers();
-  if (!ParseInternalModuleExceptFunctions()) {
-    return false;
-  }
-  if (!EmitFunctions()) {
-    return false;
-  }
-  return success_;
+    if (!success_) {
+        return false;
+    }
+    RegisterLineNumbers();
+    if (!ParseInternalModuleExceptFunctions()) {
+        return false;
+    }
+    if (!EmitFunctions()) {
+        return false;
+    }
+    return success_;
 }
 
 void ParserImpl::RegisterLineNumbers() {
-  Source::Location instruction_number{};
+    Source::Location instruction_number{};
 
-  // Has there been an OpLine since the last OpNoLine or start of the module?
-  bool in_op_line_scope = false;
-  // The source location provided by the most recent OpLine instruction.
-  Source::Location op_line_source{};
-  const bool run_on_debug_insts = true;
-  module_->ForEachInst(
-      [this, &in_op_line_scope, &op_line_source,
-       &instruction_number](const spvtools::opt::Instruction* inst) {
-        ++instruction_number.line;
-        switch (inst->opcode()) {
-          case SpvOpLine:
-            in_op_line_scope = true;
-            // TODO(dneto): This ignores the File ID (operand 0), since the Tint
-            // Source concept doesn't represent that.
-            op_line_source.line = inst->GetSingleWordInOperand(1);
-            op_line_source.column = inst->GetSingleWordInOperand(2);
-            break;
-          case SpvOpNoLine:
-            in_op_line_scope = false;
-            break;
-          default:
-            break;
-        }
-        this->inst_source_[inst] =
-            in_op_line_scope ? op_line_source : instruction_number;
-      },
-      run_on_debug_insts);
+    // Has there been an OpLine since the last OpNoLine or start of the module?
+    bool in_op_line_scope = false;
+    // The source location provided by the most recent OpLine instruction.
+    Source::Location op_line_source{};
+    const bool run_on_debug_insts = true;
+    module_->ForEachInst(
+        [this, &in_op_line_scope, &op_line_source,
+         &instruction_number](const spvtools::opt::Instruction* inst) {
+            ++instruction_number.line;
+            switch (inst->opcode()) {
+                case SpvOpLine:
+                    in_op_line_scope = true;
+                    // TODO(dneto): This ignores the File ID (operand 0), since the Tint
+                    // Source concept doesn't represent that.
+                    op_line_source.line = inst->GetSingleWordInOperand(1);
+                    op_line_source.column = inst->GetSingleWordInOperand(2);
+                    break;
+                case SpvOpNoLine:
+                    in_op_line_scope = false;
+                    break;
+                default:
+                    break;
+            }
+            this->inst_source_[inst] = in_op_line_scope ? op_line_source : instruction_number;
+        },
+        run_on_debug_insts);
 }
 
 Source ParserImpl::GetSourceForResultIdForTest(uint32_t id) const {
-  return GetSourceForInst(def_use_mgr_->GetDef(id));
+    return GetSourceForInst(def_use_mgr_->GetDef(id));
 }
 
-Source ParserImpl::GetSourceForInst(
-    const spvtools::opt::Instruction* inst) const {
-  auto where = inst_source_.find(inst);
-  if (where == inst_source_.end()) {
-    return {};
-  }
-  return Source{where->second };
+Source ParserImpl::GetSourceForInst(const spvtools::opt::Instruction* inst) const {
+    auto where = inst_source_.find(inst);
+    if (where == inst_source_.end()) {
+        return {};
+    }
+    return Source{where->second};
 }
 
 bool ParserImpl::ParseInternalModuleExceptFunctions() {
-  if (!success_) {
-    return false;
-  }
-  if (!RegisterExtendedInstructionImports()) {
-    return false;
-  }
-  if (!RegisterUserAndStructMemberNames()) {
-    return false;
-  }
-  if (!RegisterWorkgroupSizeBuiltin()) {
-    return false;
-  }
-  if (!RegisterEntryPoints()) {
-    return false;
-  }
-  if (!RegisterHandleUsage()) {
-    return false;
-  }
-  if (!RegisterTypes()) {
-    return false;
-  }
-  if (!RejectInvalidPointerRoots()) {
-    return false;
-  }
-  if (!EmitScalarSpecConstants()) {
-    return false;
-  }
-  if (!EmitModuleScopeVariables()) {
-    return false;
-  }
-  return success_;
+    if (!success_) {
+        return false;
+    }
+    if (!RegisterExtendedInstructionImports()) {
+        return false;
+    }
+    if (!RegisterUserAndStructMemberNames()) {
+        return false;
+    }
+    if (!RegisterWorkgroupSizeBuiltin()) {
+        return false;
+    }
+    if (!RegisterEntryPoints()) {
+        return false;
+    }
+    if (!RegisterHandleUsage()) {
+        return false;
+    }
+    if (!RegisterTypes()) {
+        return false;
+    }
+    if (!RejectInvalidPointerRoots()) {
+        return false;
+    }
+    if (!EmitScalarSpecConstants()) {
+        return false;
+    }
+    if (!EmitModuleScopeVariables()) {
+        return false;
+    }
+    return success_;
 }
 
 bool ParserImpl::RegisterExtendedInstructionImports() {
-  for (const spvtools::opt::Instruction& import : module_->ext_inst_imports()) {
-    std::string name(
-        reinterpret_cast<const char*>(import.GetInOperand(0).words.data()));
-    // TODO(dneto): Handle other extended instruction sets when needed.
-    if (name == "GLSL.std.450") {
-      glsl_std_450_imports_.insert(import.result_id());
-    } else if (name.find("NonSemantic.") == 0) {
-      ignored_imports_.insert(import.result_id());
-    } else {
-      return Fail() << "Unrecognized extended instruction set: " << name;
+    for (const spvtools::opt::Instruction& import : module_->ext_inst_imports()) {
+        std::string name(reinterpret_cast<const char*>(import.GetInOperand(0).words.data()));
+        // TODO(dneto): Handle other extended instruction sets when needed.
+        if (name == "GLSL.std.450") {
+            glsl_std_450_imports_.insert(import.result_id());
+        } else if (name.find("NonSemantic.") == 0) {
+            ignored_imports_.insert(import.result_id());
+        } else {
+            return Fail() << "Unrecognized extended instruction set: " << name;
+        }
     }
-  }
-  return true;
+    return true;
 }
 
-bool ParserImpl::IsGlslExtendedInstruction(
-    const spvtools::opt::Instruction& inst) const {
-  return (inst.opcode() == SpvOpExtInst) &&
-         (glsl_std_450_imports_.count(inst.GetSingleWordInOperand(0)) > 0);
+bool ParserImpl::IsGlslExtendedInstruction(const spvtools::opt::Instruction& inst) const {
+    return (inst.opcode() == SpvOpExtInst) &&
+           (glsl_std_450_imports_.count(inst.GetSingleWordInOperand(0)) > 0);
 }
 
-bool ParserImpl::IsIgnoredExtendedInstruction(
-    const spvtools::opt::Instruction& inst) const {
-  return (inst.opcode() == SpvOpExtInst) &&
-         (ignored_imports_.count(inst.GetSingleWordInOperand(0)) > 0);
+bool ParserImpl::IsIgnoredExtendedInstruction(const spvtools::opt::Instruction& inst) const {
+    return (inst.opcode() == SpvOpExtInst) &&
+           (ignored_imports_.count(inst.GetSingleWordInOperand(0)) > 0);
 }
 
 bool ParserImpl::RegisterUserAndStructMemberNames() {
-  if (!success_) {
-    return false;
-  }
-  // Register entry point names. An entry point name is the point of contact
-  // between the API and the shader. It has the highest priority for
-  // preservation, so register it first.
-  for (const spvtools::opt::Instruction& entry_point :
-       module_->entry_points()) {
-    const uint32_t function_id = entry_point.GetSingleWordInOperand(1);
-    const std::string name = entry_point.GetInOperand(2).AsString();
-
-    // This translator requires the entry point to be a valid WGSL identifier.
-    // Allowing otherwise leads to difficulties in that the programmer needs
-    // to get a mapping from their original entry point name to the WGSL name,
-    // and we don't have a good mechanism for that.
-    if (!IsValidIdentifier(name)) {
-      return Fail() << "entry point name is not a valid WGSL identifier: "
-                    << name;
-    }
-
-    // SPIR-V allows a single function to be the implementation for more
-    // than one entry point.  In the common case, it's one-to-one, and we should
-    // try to name the function after the entry point.  Otherwise, give the
-    // function a name automatically derived from the entry point name.
-    namer_.SuggestSanitizedName(function_id, name);
-
-    // There is another many-to-one relationship to take care of:  In SPIR-V
-    // the same name can be used for multiple entry points, provided they are
-    // for different shader stages. Take action now to ensure we can use the
-    // entry point name later on, and not have it taken for another identifier
-    // by an accidental collision with a derived name made for a different ID.
-    if (!namer_.IsRegistered(name)) {
-      // The entry point name is "unoccupied" becase an earlier entry point
-      // grabbed the slot for the function that implements both entry points.
-      // Register this new entry point's name, to avoid accidental collisions
-      // with a future generated ID.
-      if (!namer_.RegisterWithoutId(name)) {
+    if (!success_) {
         return false;
-      }
     }
-  }
+    // Register entry point names. An entry point name is the point of contact
+    // between the API and the shader. It has the highest priority for
+    // preservation, so register it first.
+    for (const spvtools::opt::Instruction& entry_point : module_->entry_points()) {
+        const uint32_t function_id = entry_point.GetSingleWordInOperand(1);
+        const std::string name = entry_point.GetInOperand(2).AsString();
 
-  // Register names from OpName and OpMemberName
-  for (const auto& inst : module_->debugs2()) {
-    switch (inst.opcode()) {
-      case SpvOpName: {
-        const auto name = inst.GetInOperand(1).AsString();
-        if (!name.empty()) {
-          namer_.SuggestSanitizedName(inst.GetSingleWordInOperand(0), name);
+        // This translator requires the entry point to be a valid WGSL identifier.
+        // Allowing otherwise leads to difficulties in that the programmer needs
+        // to get a mapping from their original entry point name to the WGSL name,
+        // and we don't have a good mechanism for that.
+        if (!IsValidIdentifier(name)) {
+            return Fail() << "entry point name is not a valid WGSL identifier: " << name;
         }
-        break;
-      }
-      case SpvOpMemberName: {
-        const auto name = inst.GetInOperand(2).AsString();
-        if (!name.empty()) {
-          namer_.SuggestSanitizedMemberName(inst.GetSingleWordInOperand(0),
-                                            inst.GetSingleWordInOperand(1),
-                                            name);
+
+        // SPIR-V allows a single function to be the implementation for more
+        // than one entry point.  In the common case, it's one-to-one, and we should
+        // try to name the function after the entry point.  Otherwise, give the
+        // function a name automatically derived from the entry point name.
+        namer_.SuggestSanitizedName(function_id, name);
+
+        // There is another many-to-one relationship to take care of:  In SPIR-V
+        // the same name can be used for multiple entry points, provided they are
+        // for different shader stages. Take action now to ensure we can use the
+        // entry point name later on, and not have it taken for another identifier
+        // by an accidental collision with a derived name made for a different ID.
+        if (!namer_.IsRegistered(name)) {
+            // The entry point name is "unoccupied" becase an earlier entry point
+            // grabbed the slot for the function that implements both entry points.
+            // Register this new entry point's name, to avoid accidental collisions
+            // with a future generated ID.
+            if (!namer_.RegisterWithoutId(name)) {
+                return false;
+            }
         }
-        break;
-      }
-      default:
-        break;
     }
-  }
 
-  // Fill in struct member names, and disambiguate them.
-  for (const auto* type_inst : module_->GetTypes()) {
-    if (type_inst->opcode() == SpvOpTypeStruct) {
-      namer_.ResolveMemberNamesForStruct(type_inst->result_id(),
-                                         type_inst->NumInOperands());
+    // Register names from OpName and OpMemberName
+    for (const auto& inst : module_->debugs2()) {
+        switch (inst.opcode()) {
+            case SpvOpName: {
+                const auto name = inst.GetInOperand(1).AsString();
+                if (!name.empty()) {
+                    namer_.SuggestSanitizedName(inst.GetSingleWordInOperand(0), name);
+                }
+                break;
+            }
+            case SpvOpMemberName: {
+                const auto name = inst.GetInOperand(2).AsString();
+                if (!name.empty()) {
+                    namer_.SuggestSanitizedMemberName(inst.GetSingleWordInOperand(0),
+                                                      inst.GetSingleWordInOperand(1), name);
+                }
+                break;
+            }
+            default:
+                break;
+        }
     }
-  }
 
-  return true;
+    // Fill in struct member names, and disambiguate them.
+    for (const auto* type_inst : module_->GetTypes()) {
+        if (type_inst->opcode() == SpvOpTypeStruct) {
+            namer_.ResolveMemberNamesForStruct(type_inst->result_id(), type_inst->NumInOperands());
+        }
+    }
+
+    return true;
 }
 
 bool ParserImpl::IsValidIdentifier(const std::string& str) {
-  if (str.empty()) {
-    return false;
-  }
-  std::locale c_locale("C");
-  if (str[0] == '_') {
-    if (str.length() == 1u || str[1] == '_') {
-      // https://www.w3.org/TR/WGSL/#identifiers
-      // must not be '_' (a single underscore)
-      // must not start with two underscores
-      return false;
+    if (str.empty()) {
+        return false;
     }
-  } else if (!std::isalpha(str[0], c_locale)) {
-    return false;
-  }
-  for (const char& ch : str) {
-    if ((ch != '_') && !std::isalnum(ch, c_locale)) {
-      return false;
+    std::locale c_locale("C");
+    if (str[0] == '_') {
+        if (str.length() == 1u || str[1] == '_') {
+            // https://www.w3.org/TR/WGSL/#identifiers
+            // must not be '_' (a single underscore)
+            // must not start with two underscores
+            return false;
+        }
+    } else if (!std::isalpha(str[0], c_locale)) {
+        return false;
     }
-  }
-  return true;
+    for (const char& ch : str) {
+        if ((ch != '_') && !std::isalnum(ch, c_locale)) {
+            return false;
+        }
+    }
+    return true;
 }
 
 bool ParserImpl::RegisterWorkgroupSizeBuiltin() {
-  WorkgroupSizeInfo& info = workgroup_size_builtin_;
-  for (const spvtools::opt::Instruction& inst : module_->annotations()) {
-    if (inst.opcode() != SpvOpDecorate) {
-      continue;
+    WorkgroupSizeInfo& info = workgroup_size_builtin_;
+    for (const spvtools::opt::Instruction& inst : module_->annotations()) {
+        if (inst.opcode() != SpvOpDecorate) {
+            continue;
+        }
+        if (inst.GetSingleWordInOperand(1) != SpvDecorationBuiltIn) {
+            continue;
+        }
+        if (inst.GetSingleWordInOperand(2) != SpvBuiltInWorkgroupSize) {
+            continue;
+        }
+        info.id = inst.GetSingleWordInOperand(0);
     }
-    if (inst.GetSingleWordInOperand(1) != SpvDecorationBuiltIn) {
-      continue;
+    if (info.id == 0) {
+        return true;
     }
-    if (inst.GetSingleWordInOperand(2) != SpvBuiltInWorkgroupSize) {
-      continue;
+    // Gather the values.
+    const spvtools::opt::Instruction* composite_def = def_use_mgr_->GetDef(info.id);
+    if (!composite_def) {
+        return Fail() << "Invalid WorkgroupSize builtin value";
     }
-    info.id = inst.GetSingleWordInOperand(0);
-  }
-  if (info.id == 0) {
-    return true;
-  }
-  // Gather the values.
-  const spvtools::opt::Instruction* composite_def =
-      def_use_mgr_->GetDef(info.id);
-  if (!composite_def) {
-    return Fail() << "Invalid WorkgroupSize builtin value";
-  }
-  // SPIR-V validation checks that the result is a 3-element vector of 32-bit
-  // integer scalars (signed or unsigned).  Rely on validation to check the
-  // type.  In theory the instruction could be OpConstantNull and still
-  // pass validation, but that would be non-sensical.  Be a little more
-  // stringent here and check for specific opcodes.  WGSL does not support
-  // const-expr yet, so avoid supporting OpSpecConstantOp here.
-  // TODO(dneto): See https://github.com/gpuweb/gpuweb/issues/1272 for WGSL
-  // const_expr proposals.
-  if ((composite_def->opcode() != SpvOpSpecConstantComposite &&
-       composite_def->opcode() != SpvOpConstantComposite)) {
-    return Fail() << "Invalid WorkgroupSize builtin.  Expected 3-element "
-                     "OpSpecConstantComposite or OpConstantComposite:  "
-                  << composite_def->PrettyPrint();
-  }
-  info.type_id = composite_def->type_id();
-  // Extract the component type from the vector type.
-  info.component_type_id =
-      def_use_mgr_->GetDef(info.type_id)->GetSingleWordInOperand(0);
+    // SPIR-V validation checks that the result is a 3-element vector of 32-bit
+    // integer scalars (signed or unsigned).  Rely on validation to check the
+    // type.  In theory the instruction could be OpConstantNull and still
+    // pass validation, but that would be non-sensical.  Be a little more
+    // stringent here and check for specific opcodes.  WGSL does not support
+    // const-expr yet, so avoid supporting OpSpecConstantOp here.
+    // TODO(dneto): See https://github.com/gpuweb/gpuweb/issues/1272 for WGSL
+    // const_expr proposals.
+    if ((composite_def->opcode() != SpvOpSpecConstantComposite &&
+         composite_def->opcode() != SpvOpConstantComposite)) {
+        return Fail() << "Invalid WorkgroupSize builtin.  Expected 3-element "
+                         "OpSpecConstantComposite or OpConstantComposite:  "
+                      << composite_def->PrettyPrint();
+    }
+    info.type_id = composite_def->type_id();
+    // Extract the component type from the vector type.
+    info.component_type_id = def_use_mgr_->GetDef(info.type_id)->GetSingleWordInOperand(0);
 
-  /// Sets the ID and value of the index'th member of the composite constant.
-  /// Returns false and emits a diagnostic on error.
-  auto set_param = [this, composite_def](uint32_t* id_ptr, uint32_t* value_ptr,
-                                         int index) -> bool {
-    const auto id = composite_def->GetSingleWordInOperand(index);
-    const auto* def = def_use_mgr_->GetDef(id);
-    if (!def ||
-        (def->opcode() != SpvOpSpecConstant &&
-         def->opcode() != SpvOpConstant) ||
-        (def->NumInOperands() != 1)) {
-      return Fail() << "invalid component " << index << " of workgroupsize "
-                    << (def ? def->PrettyPrint()
-                            : std::string("no definition"));
-    }
-    *id_ptr = id;
-    // Use the default value of a spec constant.
-    *value_ptr = def->GetSingleWordInOperand(0);
-    return true;
-  };
+    /// Sets the ID and value of the index'th member of the composite constant.
+    /// Returns false and emits a diagnostic on error.
+    auto set_param = [this, composite_def](uint32_t* id_ptr, uint32_t* value_ptr,
+                                           int index) -> bool {
+        const auto id = composite_def->GetSingleWordInOperand(index);
+        const auto* def = def_use_mgr_->GetDef(id);
+        if (!def || (def->opcode() != SpvOpSpecConstant && def->opcode() != SpvOpConstant) ||
+            (def->NumInOperands() != 1)) {
+            return Fail() << "invalid component " << index << " of workgroupsize "
+                          << (def ? def->PrettyPrint() : std::string("no definition"));
+        }
+        *id_ptr = id;
+        // Use the default value of a spec constant.
+        *value_ptr = def->GetSingleWordInOperand(0);
+        return true;
+    };
 
-  return set_param(&info.x_id, &info.x_value, 0) &&
-         set_param(&info.y_id, &info.y_value, 1) &&
-         set_param(&info.z_id, &info.z_value, 2);
+    return set_param(&info.x_id, &info.x_value, 0) && set_param(&info.y_id, &info.y_value, 1) &&
+           set_param(&info.z_id, &info.z_value, 2);
 }
 
 bool ParserImpl::RegisterEntryPoints() {
-  // Mapping from entry point ID to GridSize computed from LocalSize
-  // decorations.
-  std::unordered_map<uint32_t, GridSize> local_size;
-  for (const spvtools::opt::Instruction& inst : module_->execution_modes()) {
-    auto mode = static_cast<SpvExecutionMode>(inst.GetSingleWordInOperand(1));
-    if (mode == SpvExecutionModeLocalSize) {
-      if (inst.NumInOperands() != 5) {
-        // This won't even get past SPIR-V binary parsing.
-        return Fail() << "invalid LocalSize execution mode: "
-                      << inst.PrettyPrint();
-      }
-      uint32_t function_id = inst.GetSingleWordInOperand(0);
-      local_size[function_id] = GridSize{inst.GetSingleWordInOperand(2),
-                                         inst.GetSingleWordInOperand(3),
-                                         inst.GetSingleWordInOperand(4)};
-    }
-  }
-
-  for (const spvtools::opt::Instruction& entry_point :
-       module_->entry_points()) {
-    const auto stage = SpvExecutionModel(entry_point.GetSingleWordInOperand(0));
-    const uint32_t function_id = entry_point.GetSingleWordInOperand(1);
-
-    const std::string ep_name = entry_point.GetOperand(2).AsString();
-    if (!IsValidIdentifier(ep_name)) {
-      return Fail() << "entry point name is not a valid WGSL identifier: "
-                    << ep_name;
-    }
-
-    bool owns_inner_implementation = false;
-    std::string inner_implementation_name;
-
-    auto where = function_to_ep_info_.find(function_id);
-    if (where == function_to_ep_info_.end()) {
-      // If this is the first entry point to have function_id as its
-      // implementation, then this entry point is responsible for generating
-      // the inner implementation.
-      owns_inner_implementation = true;
-      inner_implementation_name = namer_.MakeDerivedName(ep_name);
-    } else {
-      // Reuse the inner implementation owned by the first entry point.
-      inner_implementation_name = where->second[0].inner_name;
-    }
-    TINT_ASSERT(Reader, !inner_implementation_name.empty());
-    TINT_ASSERT(Reader, ep_name != inner_implementation_name);
-
-    utils::UniqueVector<uint32_t> inputs;
-    utils::UniqueVector<uint32_t> outputs;
-    for (unsigned iarg = 3; iarg < entry_point.NumInOperands(); iarg++) {
-      const uint32_t var_id = entry_point.GetSingleWordInOperand(iarg);
-      if (const auto* var_inst = def_use_mgr_->GetDef(var_id)) {
-        switch (SpvStorageClass(var_inst->GetSingleWordInOperand(0))) {
-          case SpvStorageClassInput:
-            inputs.add(var_id);
-            break;
-          case SpvStorageClassOutput:
-            outputs.add(var_id);
-            break;
-          default:
-            break;
+    // Mapping from entry point ID to GridSize computed from LocalSize
+    // decorations.
+    std::unordered_map<uint32_t, GridSize> local_size;
+    for (const spvtools::opt::Instruction& inst : module_->execution_modes()) {
+        auto mode = static_cast<SpvExecutionMode>(inst.GetSingleWordInOperand(1));
+        if (mode == SpvExecutionModeLocalSize) {
+            if (inst.NumInOperands() != 5) {
+                // This won't even get past SPIR-V binary parsing.
+                return Fail() << "invalid LocalSize execution mode: " << inst.PrettyPrint();
+            }
+            uint32_t function_id = inst.GetSingleWordInOperand(0);
+            local_size[function_id] =
+                GridSize{inst.GetSingleWordInOperand(2), inst.GetSingleWordInOperand(3),
+                         inst.GetSingleWordInOperand(4)};
         }
-      }
     }
-    // Save the lists, in ID-sorted order.
-    std::vector<uint32_t> sorted_inputs(inputs);
-    std::sort(sorted_inputs.begin(), sorted_inputs.end());
-    std::vector<uint32_t> sorted_outputs(outputs);
-    std::sort(sorted_outputs.begin(), sorted_outputs.end());
 
-    const auto ast_stage = enum_converter_.ToPipelineStage(stage);
-    GridSize wgsize;
-    if (ast_stage == ast::PipelineStage::kCompute) {
-      if (workgroup_size_builtin_.id) {
-        // Store the default values.
-        // WGSL allows specializing these, but this code doesn't support that
-        // yet. https://github.com/gpuweb/gpuweb/issues/1442
-        wgsize = GridSize{workgroup_size_builtin_.x_value,
-                          workgroup_size_builtin_.y_value,
-                          workgroup_size_builtin_.z_value};
-      } else {
-        // Use the LocalSize execution mode.  This is the second choice.
-        auto where_local_size = local_size.find(function_id);
-        if (where_local_size != local_size.end()) {
-          wgsize = where_local_size->second;
+    for (const spvtools::opt::Instruction& entry_point : module_->entry_points()) {
+        const auto stage = SpvExecutionModel(entry_point.GetSingleWordInOperand(0));
+        const uint32_t function_id = entry_point.GetSingleWordInOperand(1);
+
+        const std::string ep_name = entry_point.GetOperand(2).AsString();
+        if (!IsValidIdentifier(ep_name)) {
+            return Fail() << "entry point name is not a valid WGSL identifier: " << ep_name;
         }
-      }
-    }
-    function_to_ep_info_[function_id].emplace_back(
-        ep_name, ast_stage, owns_inner_implementation,
-        inner_implementation_name, std::move(sorted_inputs),
-        std::move(sorted_outputs), wgsize);
-  }
 
-  // The enum conversion could have failed, so return the existing status value.
-  return success_;
-}
+        bool owns_inner_implementation = false;
+        std::string inner_implementation_name;
 
-const Type* ParserImpl::ConvertType(
-    const spvtools::opt::analysis::Integer* int_ty) {
-  if (int_ty->width() == 32) {
-    return int_ty->IsSigned() ? static_cast<const Type*>(ty_.I32())
-                              : static_cast<const Type*>(ty_.U32());
-  }
-  Fail() << "unhandled integer width: " << int_ty->width();
-  return nullptr;
-}
+        auto where = function_to_ep_info_.find(function_id);
+        if (where == function_to_ep_info_.end()) {
+            // If this is the first entry point to have function_id as its
+            // implementation, then this entry point is responsible for generating
+            // the inner implementation.
+            owns_inner_implementation = true;
+            inner_implementation_name = namer_.MakeDerivedName(ep_name);
+        } else {
+            // Reuse the inner implementation owned by the first entry point.
+            inner_implementation_name = where->second[0].inner_name;
+        }
+        TINT_ASSERT(Reader, !inner_implementation_name.empty());
+        TINT_ASSERT(Reader, ep_name != inner_implementation_name);
 
-const Type* ParserImpl::ConvertType(
-    const spvtools::opt::analysis::Float* float_ty) {
-  if (float_ty->width() == 32) {
-    return ty_.F32();
-  }
-  Fail() << "unhandled float width: " << float_ty->width();
-  return nullptr;
-}
+        utils::UniqueVector<uint32_t> inputs;
+        utils::UniqueVector<uint32_t> outputs;
+        for (unsigned iarg = 3; iarg < entry_point.NumInOperands(); iarg++) {
+            const uint32_t var_id = entry_point.GetSingleWordInOperand(iarg);
+            if (const auto* var_inst = def_use_mgr_->GetDef(var_id)) {
+                switch (SpvStorageClass(var_inst->GetSingleWordInOperand(0))) {
+                    case SpvStorageClassInput:
+                        inputs.add(var_id);
+                        break;
+                    case SpvStorageClassOutput:
+                        outputs.add(var_id);
+                        break;
+                    default:
+                        break;
+                }
+            }
+        }
+        // Save the lists, in ID-sorted order.
+        std::vector<uint32_t> sorted_inputs(inputs);
+        std::sort(sorted_inputs.begin(), sorted_inputs.end());
+        std::vector<uint32_t> sorted_outputs(outputs);
+        std::sort(sorted_outputs.begin(), sorted_outputs.end());
 
-const Type* ParserImpl::ConvertType(
-    const spvtools::opt::analysis::Vector* vec_ty) {
-  const auto num_elem = vec_ty->element_count();
-  auto* ast_elem_ty = ConvertType(type_mgr_->GetId(vec_ty->element_type()));
-  if (ast_elem_ty == nullptr) {
-    return ast_elem_ty;
-  }
-  return ty_.Vector(ast_elem_ty, num_elem);
-}
-
-const Type* ParserImpl::ConvertType(
-    const spvtools::opt::analysis::Matrix* mat_ty) {
-  const auto* vec_ty = mat_ty->element_type()->AsVector();
-  const auto* scalar_ty = vec_ty->element_type();
-  const auto num_rows = vec_ty->element_count();
-  const auto num_columns = mat_ty->element_count();
-  auto* ast_scalar_ty = ConvertType(type_mgr_->GetId(scalar_ty));
-  if (ast_scalar_ty == nullptr) {
-    return nullptr;
-  }
-  return ty_.Matrix(ast_scalar_ty, num_columns, num_rows);
-}
-
-const Type* ParserImpl::ConvertType(
-    uint32_t type_id,
-    const spvtools::opt::analysis::RuntimeArray* rtarr_ty) {
-  auto* ast_elem_ty = ConvertType(type_mgr_->GetId(rtarr_ty->element_type()));
-  if (ast_elem_ty == nullptr) {
-    return nullptr;
-  }
-  uint32_t array_stride = 0;
-  if (!ParseArrayDecorations(rtarr_ty, &array_stride)) {
-    return nullptr;
-  }
-  const Type* result = ty_.Array(ast_elem_ty, 0, array_stride);
-  return MaybeGenerateAlias(type_id, rtarr_ty, result);
-}
-
-const Type* ParserImpl::ConvertType(
-    uint32_t type_id,
-    const spvtools::opt::analysis::Array* arr_ty) {
-  // Get the element type. The SPIR-V optimizer's types representation
-  // deduplicates array types that have the same parameterization.
-  // We don't want that deduplication, so get the element type from
-  // the SPIR-V type directly.
-  const auto* inst = def_use_mgr_->GetDef(type_id);
-  const auto elem_type_id = inst->GetSingleWordInOperand(0);
-  auto* ast_elem_ty = ConvertType(elem_type_id);
-  if (ast_elem_ty == nullptr) {
-    return nullptr;
-  }
-  // Get the length.
-  const auto& length_info = arr_ty->length_info();
-  if (length_info.words.empty()) {
-    // The internal representation is invalid. The discriminant vector
-    // is mal-formed.
-    Fail() << "internal error: Array length info is invalid";
-    return nullptr;
-  }
-  if (length_info.words[0] !=
-      spvtools::opt::analysis::Array::LengthInfo::kConstant) {
-    Fail() << "Array type " << type_mgr_->GetId(arr_ty)
-           << " length is a specialization constant";
-    return nullptr;
-  }
-  const auto* constant = constant_mgr_->FindDeclaredConstant(length_info.id);
-  if (constant == nullptr) {
-    Fail() << "Array type " << type_mgr_->GetId(arr_ty) << " length ID "
-           << length_info.id << " does not name an OpConstant";
-    return nullptr;
-  }
-  const uint64_t num_elem = constant->GetZeroExtendedValue();
-  // For now, limit to only 32bits.
-  if (num_elem > std::numeric_limits<uint32_t>::max()) {
-    Fail() << "Array type " << type_mgr_->GetId(arr_ty)
-           << " has too many elements (more than can fit in 32 bits): "
-           << num_elem;
-    return nullptr;
-  }
-  uint32_t array_stride = 0;
-  if (!ParseArrayDecorations(arr_ty, &array_stride)) {
-    return nullptr;
-  }
-  if (remap_buffer_block_type_.count(elem_type_id)) {
-    remap_buffer_block_type_.insert(type_mgr_->GetId(arr_ty));
-  }
-  const Type* result =
-      ty_.Array(ast_elem_ty, static_cast<uint32_t>(num_elem), array_stride);
-  return MaybeGenerateAlias(type_id, arr_ty, result);
-}
-
-bool ParserImpl::ParseArrayDecorations(
-    const spvtools::opt::analysis::Type* spv_type,
-    uint32_t* array_stride) {
-  *array_stride = 0;  // Implicit stride case.
-  const auto type_id = type_mgr_->GetId(spv_type);
-  for (auto& decoration : this->GetDecorationsFor(type_id)) {
-    if (decoration.size() == 2 && decoration[0] == SpvDecorationArrayStride) {
-      const auto stride = decoration[1];
-      if (stride == 0) {
-        return Fail() << "invalid array type ID " << type_id
-                      << ": ArrayStride can't be 0";
-      }
-      *array_stride = stride;
-    } else {
-      return Fail() << "invalid array type ID " << type_id
-                    << ": unknown decoration "
-                    << (decoration.empty() ? "(empty)"
-                                           : std::to_string(decoration[0]))
-                    << " with " << decoration.size() << " total words";
-    }
-  }
-  return true;
-}
-
-const Type* ParserImpl::ConvertType(
-    uint32_t type_id,
-    const spvtools::opt::analysis::Struct* struct_ty) {
-  // Compute the struct decoration.
-  auto struct_decorations = this->GetDecorationsFor(type_id);
-  if (struct_decorations.size() == 1) {
-    const auto decoration = struct_decorations[0][0];
-    if (decoration == SpvDecorationBufferBlock) {
-      remap_buffer_block_type_.insert(type_id);
-    } else if (decoration != SpvDecorationBlock) {
-      Fail() << "struct with ID " << type_id
-             << " has unrecognized decoration: " << int(decoration);
-    }
-  } else if (struct_decorations.size() > 1) {
-    Fail() << "can't handle a struct with more than one decoration: struct "
-           << type_id << " has " << struct_decorations.size();
-    return nullptr;
-  }
-
-  // Compute members
-  ast::StructMemberList ast_members;
-  const auto members = struct_ty->element_types();
-  if (members.empty()) {
-    Fail() << "WGSL does not support empty structures. can't convert type: "
-           << def_use_mgr_->GetDef(type_id)->PrettyPrint();
-    return nullptr;
-  }
-  TypeList ast_member_types;
-  unsigned num_non_writable_members = 0;
-  for (uint32_t member_index = 0; member_index < members.size();
-       ++member_index) {
-    const auto member_type_id = type_mgr_->GetId(members[member_index]);
-    auto* ast_member_ty = ConvertType(member_type_id);
-    if (ast_member_ty == nullptr) {
-      // Already emitted diagnostics.
-      return nullptr;
+        const auto ast_stage = enum_converter_.ToPipelineStage(stage);
+        GridSize wgsize;
+        if (ast_stage == ast::PipelineStage::kCompute) {
+            if (workgroup_size_builtin_.id) {
+                // Store the default values.
+                // WGSL allows specializing these, but this code doesn't support that
+                // yet. https://github.com/gpuweb/gpuweb/issues/1442
+                wgsize = GridSize{workgroup_size_builtin_.x_value, workgroup_size_builtin_.y_value,
+                                  workgroup_size_builtin_.z_value};
+            } else {
+                // Use the LocalSize execution mode.  This is the second choice.
+                auto where_local_size = local_size.find(function_id);
+                if (where_local_size != local_size.end()) {
+                    wgsize = where_local_size->second;
+                }
+            }
+        }
+        function_to_ep_info_[function_id].emplace_back(
+            ep_name, ast_stage, owns_inner_implementation, inner_implementation_name,
+            std::move(sorted_inputs), std::move(sorted_outputs), wgsize);
     }
 
-    ast_member_types.emplace_back(ast_member_ty);
+    // The enum conversion could have failed, so return the existing status value.
+    return success_;
+}
 
-    // Scan member for built-in decorations. Some vertex built-ins are handled
-    // specially, and should not generate a structure member.
-    bool create_ast_member = true;
-    for (auto& decoration : GetDecorationsForMember(type_id, member_index)) {
-      if (decoration.empty()) {
-        Fail() << "malformed SPIR-V decoration: it's empty";
+const Type* ParserImpl::ConvertType(const spvtools::opt::analysis::Integer* int_ty) {
+    if (int_ty->width() == 32) {
+        return int_ty->IsSigned() ? static_cast<const Type*>(ty_.I32())
+                                  : static_cast<const Type*>(ty_.U32());
+    }
+    Fail() << "unhandled integer width: " << int_ty->width();
+    return nullptr;
+}
+
+const Type* ParserImpl::ConvertType(const spvtools::opt::analysis::Float* float_ty) {
+    if (float_ty->width() == 32) {
+        return ty_.F32();
+    }
+    Fail() << "unhandled float width: " << float_ty->width();
+    return nullptr;
+}
+
+const Type* ParserImpl::ConvertType(const spvtools::opt::analysis::Vector* vec_ty) {
+    const auto num_elem = vec_ty->element_count();
+    auto* ast_elem_ty = ConvertType(type_mgr_->GetId(vec_ty->element_type()));
+    if (ast_elem_ty == nullptr) {
+        return ast_elem_ty;
+    }
+    return ty_.Vector(ast_elem_ty, num_elem);
+}
+
+const Type* ParserImpl::ConvertType(const spvtools::opt::analysis::Matrix* mat_ty) {
+    const auto* vec_ty = mat_ty->element_type()->AsVector();
+    const auto* scalar_ty = vec_ty->element_type();
+    const auto num_rows = vec_ty->element_count();
+    const auto num_columns = mat_ty->element_count();
+    auto* ast_scalar_ty = ConvertType(type_mgr_->GetId(scalar_ty));
+    if (ast_scalar_ty == nullptr) {
         return nullptr;
-      }
-      if ((decoration[0] == SpvDecorationBuiltIn) && (decoration.size() > 1)) {
-        switch (decoration[1]) {
-          case SpvBuiltInPosition:
-            // Record this built-in variable specially.
-            builtin_position_.struct_type_id = type_id;
-            builtin_position_.position_member_index = member_index;
-            builtin_position_.position_member_type_id = member_type_id;
-            create_ast_member = false;  // Not part of the WGSL structure.
-            break;
-          case SpvBuiltInPointSize:  // not supported in WGSL, but ignore
-            builtin_position_.pointsize_member_index = member_index;
-            create_ast_member = false;  // Not part of the WGSL structure.
-            break;
-          case SpvBuiltInClipDistance:  // not supported in WGSL
-          case SpvBuiltInCullDistance:  // not supported in WGSL
-            create_ast_member = false;  // Not part of the WGSL structure.
-            break;
-          default:
-            Fail() << "unrecognized builtin " << decoration[1];
+    }
+    return ty_.Matrix(ast_scalar_ty, num_columns, num_rows);
+}
+
+const Type* ParserImpl::ConvertType(uint32_t type_id,
+                                    const spvtools::opt::analysis::RuntimeArray* rtarr_ty) {
+    auto* ast_elem_ty = ConvertType(type_mgr_->GetId(rtarr_ty->element_type()));
+    if (ast_elem_ty == nullptr) {
+        return nullptr;
+    }
+    uint32_t array_stride = 0;
+    if (!ParseArrayDecorations(rtarr_ty, &array_stride)) {
+        return nullptr;
+    }
+    const Type* result = ty_.Array(ast_elem_ty, 0, array_stride);
+    return MaybeGenerateAlias(type_id, rtarr_ty, result);
+}
+
+const Type* ParserImpl::ConvertType(uint32_t type_id,
+                                    const spvtools::opt::analysis::Array* arr_ty) {
+    // Get the element type. The SPIR-V optimizer's types representation
+    // deduplicates array types that have the same parameterization.
+    // We don't want that deduplication, so get the element type from
+    // the SPIR-V type directly.
+    const auto* inst = def_use_mgr_->GetDef(type_id);
+    const auto elem_type_id = inst->GetSingleWordInOperand(0);
+    auto* ast_elem_ty = ConvertType(elem_type_id);
+    if (ast_elem_ty == nullptr) {
+        return nullptr;
+    }
+    // Get the length.
+    const auto& length_info = arr_ty->length_info();
+    if (length_info.words.empty()) {
+        // The internal representation is invalid. The discriminant vector
+        // is mal-formed.
+        Fail() << "internal error: Array length info is invalid";
+        return nullptr;
+    }
+    if (length_info.words[0] != spvtools::opt::analysis::Array::LengthInfo::kConstant) {
+        Fail() << "Array type " << type_mgr_->GetId(arr_ty)
+               << " length is a specialization constant";
+        return nullptr;
+    }
+    const auto* constant = constant_mgr_->FindDeclaredConstant(length_info.id);
+    if (constant == nullptr) {
+        Fail() << "Array type " << type_mgr_->GetId(arr_ty) << " length ID " << length_info.id
+               << " does not name an OpConstant";
+        return nullptr;
+    }
+    const uint64_t num_elem = constant->GetZeroExtendedValue();
+    // For now, limit to only 32bits.
+    if (num_elem > std::numeric_limits<uint32_t>::max()) {
+        Fail() << "Array type " << type_mgr_->GetId(arr_ty)
+               << " has too many elements (more than can fit in 32 bits): " << num_elem;
+        return nullptr;
+    }
+    uint32_t array_stride = 0;
+    if (!ParseArrayDecorations(arr_ty, &array_stride)) {
+        return nullptr;
+    }
+    if (remap_buffer_block_type_.count(elem_type_id)) {
+        remap_buffer_block_type_.insert(type_mgr_->GetId(arr_ty));
+    }
+    const Type* result = ty_.Array(ast_elem_ty, static_cast<uint32_t>(num_elem), array_stride);
+    return MaybeGenerateAlias(type_id, arr_ty, result);
+}
+
+bool ParserImpl::ParseArrayDecorations(const spvtools::opt::analysis::Type* spv_type,
+                                       uint32_t* array_stride) {
+    *array_stride = 0;  // Implicit stride case.
+    const auto type_id = type_mgr_->GetId(spv_type);
+    for (auto& decoration : this->GetDecorationsFor(type_id)) {
+        if (decoration.size() == 2 && decoration[0] == SpvDecorationArrayStride) {
+            const auto stride = decoration[1];
+            if (stride == 0) {
+                return Fail() << "invalid array type ID " << type_id << ": ArrayStride can't be 0";
+            }
+            *array_stride = stride;
+        } else {
+            return Fail() << "invalid array type ID " << type_id << ": unknown decoration "
+                          << (decoration.empty() ? "(empty)" : std::to_string(decoration[0]))
+                          << " with " << decoration.size() << " total words";
+        }
+    }
+    return true;
+}
+
+const Type* ParserImpl::ConvertType(uint32_t type_id,
+                                    const spvtools::opt::analysis::Struct* struct_ty) {
+    // Compute the struct decoration.
+    auto struct_decorations = this->GetDecorationsFor(type_id);
+    if (struct_decorations.size() == 1) {
+        const auto decoration = struct_decorations[0][0];
+        if (decoration == SpvDecorationBufferBlock) {
+            remap_buffer_block_type_.insert(type_id);
+        } else if (decoration != SpvDecorationBlock) {
+            Fail() << "struct with ID " << type_id
+                   << " has unrecognized decoration: " << int(decoration);
+        }
+    } else if (struct_decorations.size() > 1) {
+        Fail() << "can't handle a struct with more than one decoration: struct " << type_id
+               << " has " << struct_decorations.size();
+        return nullptr;
+    }
+
+    // Compute members
+    ast::StructMemberList ast_members;
+    const auto members = struct_ty->element_types();
+    if (members.empty()) {
+        Fail() << "WGSL does not support empty structures. can't convert type: "
+               << def_use_mgr_->GetDef(type_id)->PrettyPrint();
+        return nullptr;
+    }
+    TypeList ast_member_types;
+    unsigned num_non_writable_members = 0;
+    for (uint32_t member_index = 0; member_index < members.size(); ++member_index) {
+        const auto member_type_id = type_mgr_->GetId(members[member_index]);
+        auto* ast_member_ty = ConvertType(member_type_id);
+        if (ast_member_ty == nullptr) {
+            // Already emitted diagnostics.
             return nullptr;
         }
-      }
-    }
-    if (!create_ast_member) {
-      // This member is decorated as a built-in, and is handled specially.
-      continue;
-    }
 
-    bool is_non_writable = false;
-    ast::AttributeList ast_member_decorations;
-    for (auto& decoration : GetDecorationsForMember(type_id, member_index)) {
-      if (IsPipelineDecoration(decoration)) {
-        // IO decorations are handled when emitting the entry point.
-        continue;
-      } else if (decoration[0] == SpvDecorationNonWritable) {
-        // WGSL doesn't represent individual members as non-writable. Instead,
-        // apply the ReadOnly access control to the containing struct if all
-        // the members are non-writable.
-        is_non_writable = true;
-      } else {
-        auto decos = ConvertMemberDecoration(type_id, member_index,
-                                             ast_member_ty, decoration);
-        for (auto* deco : decos) {
-          ast_member_decorations.emplace_back(deco);
+        ast_member_types.emplace_back(ast_member_ty);
+
+        // Scan member for built-in decorations. Some vertex built-ins are handled
+        // specially, and should not generate a structure member.
+        bool create_ast_member = true;
+        for (auto& decoration : GetDecorationsForMember(type_id, member_index)) {
+            if (decoration.empty()) {
+                Fail() << "malformed SPIR-V decoration: it's empty";
+                return nullptr;
+            }
+            if ((decoration[0] == SpvDecorationBuiltIn) && (decoration.size() > 1)) {
+                switch (decoration[1]) {
+                    case SpvBuiltInPosition:
+                        // Record this built-in variable specially.
+                        builtin_position_.struct_type_id = type_id;
+                        builtin_position_.position_member_index = member_index;
+                        builtin_position_.position_member_type_id = member_type_id;
+                        create_ast_member = false;  // Not part of the WGSL structure.
+                        break;
+                    case SpvBuiltInPointSize:  // not supported in WGSL, but ignore
+                        builtin_position_.pointsize_member_index = member_index;
+                        create_ast_member = false;  // Not part of the WGSL structure.
+                        break;
+                    case SpvBuiltInClipDistance:    // not supported in WGSL
+                    case SpvBuiltInCullDistance:    // not supported in WGSL
+                        create_ast_member = false;  // Not part of the WGSL structure.
+                        break;
+                    default:
+                        Fail() << "unrecognized builtin " << decoration[1];
+                        return nullptr;
+                }
+            }
         }
-        if (!success_) {
-          return nullptr;
+        if (!create_ast_member) {
+            // This member is decorated as a built-in, and is handled specially.
+            continue;
         }
-      }
+
+        bool is_non_writable = false;
+        ast::AttributeList ast_member_decorations;
+        for (auto& decoration : GetDecorationsForMember(type_id, member_index)) {
+            if (IsPipelineDecoration(decoration)) {
+                // IO decorations are handled when emitting the entry point.
+                continue;
+            } else if (decoration[0] == SpvDecorationNonWritable) {
+                // WGSL doesn't represent individual members as non-writable. Instead,
+                // apply the ReadOnly access control to the containing struct if all
+                // the members are non-writable.
+                is_non_writable = true;
+            } else {
+                auto decos =
+                    ConvertMemberDecoration(type_id, member_index, ast_member_ty, decoration);
+                for (auto* deco : decos) {
+                    ast_member_decorations.emplace_back(deco);
+                }
+                if (!success_) {
+                    return nullptr;
+                }
+            }
+        }
+
+        if (is_non_writable) {
+            // Count a member as non-writable only once, no matter how many
+            // NonWritable decorations are applied to it.
+            ++num_non_writable_members;
+        }
+        const auto member_name = namer_.GetMemberName(type_id, member_index);
+        auto* ast_struct_member = create<ast::StructMember>(
+            Source{}, builder_.Symbols().Register(member_name), ast_member_ty->Build(builder_),
+            std::move(ast_member_decorations));
+        ast_members.push_back(ast_struct_member);
     }
 
-    if (is_non_writable) {
-      // Count a member as non-writable only once, no matter how many
-      // NonWritable decorations are applied to it.
-      ++num_non_writable_members;
+    if (ast_members.empty()) {
+        // All members were likely built-ins. Don't generate an empty AST structure.
+        return nullptr;
     }
-    const auto member_name = namer_.GetMemberName(type_id, member_index);
-    auto* ast_struct_member = create<ast::StructMember>(
-        Source{}, builder_.Symbols().Register(member_name),
-        ast_member_ty->Build(builder_), std::move(ast_member_decorations));
-    ast_members.push_back(ast_struct_member);
-  }
 
-  if (ast_members.empty()) {
-    // All members were likely built-ins. Don't generate an empty AST structure.
-    return nullptr;
-  }
+    namer_.SuggestSanitizedName(type_id, "S");
 
-  namer_.SuggestSanitizedName(type_id, "S");
+    auto name = namer_.GetName(type_id);
 
-  auto name = namer_.GetName(type_id);
-
-  // Now make the struct.
-  auto sym = builder_.Symbols().Register(name);
-  auto* ast_struct = create<ast::Struct>(Source{}, sym, std::move(ast_members),
-                                         ast::AttributeList());
-  if (num_non_writable_members == members.size()) {
-    read_only_struct_types_.insert(ast_struct->name);
-  }
-  AddTypeDecl(sym, ast_struct);
-  const auto* result = ty_.Struct(sym, std::move(ast_member_types));
-  struct_id_for_symbol_[sym] = type_id;
-  return result;
+    // Now make the struct.
+    auto sym = builder_.Symbols().Register(name);
+    auto* ast_struct =
+        create<ast::Struct>(Source{}, sym, std::move(ast_members), ast::AttributeList());
+    if (num_non_writable_members == members.size()) {
+        read_only_struct_types_.insert(ast_struct->name);
+    }
+    AddTypeDecl(sym, ast_struct);
+    const auto* result = ty_.Struct(sym, std::move(ast_member_types));
+    struct_id_for_symbol_[sym] = type_id;
+    return result;
 }
 
 void ParserImpl::AddTypeDecl(Symbol name, const ast::TypeDecl* decl) {
-  auto iter = declared_types_.insert(name);
-  if (iter.second) {
-    builder_.AST().AddTypeDecl(decl);
-  }
+    auto iter = declared_types_.insert(name);
+    if (iter.second) {
+        builder_.AST().AddTypeDecl(decl);
+    }
 }
 
 const Type* ParserImpl::ConvertType(uint32_t type_id,
                                     PtrAs ptr_as,
                                     const spvtools::opt::analysis::Pointer*) {
-  const auto* inst = def_use_mgr_->GetDef(type_id);
-  const auto pointee_type_id = inst->GetSingleWordInOperand(1);
-  const auto storage_class = SpvStorageClass(inst->GetSingleWordInOperand(0));
+    const auto* inst = def_use_mgr_->GetDef(type_id);
+    const auto pointee_type_id = inst->GetSingleWordInOperand(1);
+    const auto storage_class = SpvStorageClass(inst->GetSingleWordInOperand(0));
 
-  if (pointee_type_id == builtin_position_.struct_type_id) {
-    builtin_position_.pointer_type_id = type_id;
-    // Pipeline IO builtins map to private variables.
-    builtin_position_.storage_class = SpvStorageClassPrivate;
-    return nullptr;
-  }
-  auto* ast_elem_ty = ConvertType(pointee_type_id, PtrAs::Ptr);
-  if (ast_elem_ty == nullptr) {
-    Fail() << "SPIR-V pointer type with ID " << type_id
-           << " has invalid pointee type " << pointee_type_id;
-    return nullptr;
-  }
+    if (pointee_type_id == builtin_position_.struct_type_id) {
+        builtin_position_.pointer_type_id = type_id;
+        // Pipeline IO builtins map to private variables.
+        builtin_position_.storage_class = SpvStorageClassPrivate;
+        return nullptr;
+    }
+    auto* ast_elem_ty = ConvertType(pointee_type_id, PtrAs::Ptr);
+    if (ast_elem_ty == nullptr) {
+        Fail() << "SPIR-V pointer type with ID " << type_id << " has invalid pointee type "
+               << pointee_type_id;
+        return nullptr;
+    }
 
-  auto ast_storage_class = enum_converter_.ToStorageClass(storage_class);
-  if (ast_storage_class == ast::StorageClass::kInvalid) {
-    Fail() << "SPIR-V pointer type with ID " << type_id
-           << " has invalid storage class "
-           << static_cast<uint32_t>(storage_class);
-    return nullptr;
-  }
-  if (ast_storage_class == ast::StorageClass::kUniform &&
-      remap_buffer_block_type_.count(pointee_type_id)) {
-    ast_storage_class = ast::StorageClass::kStorage;
-    remap_buffer_block_type_.insert(type_id);
-  }
+    auto ast_storage_class = enum_converter_.ToStorageClass(storage_class);
+    if (ast_storage_class == ast::StorageClass::kInvalid) {
+        Fail() << "SPIR-V pointer type with ID " << type_id << " has invalid storage class "
+               << static_cast<uint32_t>(storage_class);
+        return nullptr;
+    }
+    if (ast_storage_class == ast::StorageClass::kUniform &&
+        remap_buffer_block_type_.count(pointee_type_id)) {
+        ast_storage_class = ast::StorageClass::kStorage;
+        remap_buffer_block_type_.insert(type_id);
+    }
 
-  // Pipeline input and output variables map to private variables.
-  if (ast_storage_class == ast::StorageClass::kInput ||
-      ast_storage_class == ast::StorageClass::kOutput) {
-    ast_storage_class = ast::StorageClass::kPrivate;
-  }
-  switch (ptr_as) {
-    case PtrAs::Ref:
-      return ty_.Reference(ast_elem_ty, ast_storage_class);
-    case PtrAs::Ptr:
-      return ty_.Pointer(ast_elem_ty, ast_storage_class);
-  }
-  Fail() << "invalid value for ptr_as: " << static_cast<int>(ptr_as);
-  return nullptr;
+    // Pipeline input and output variables map to private variables.
+    if (ast_storage_class == ast::StorageClass::kInput ||
+        ast_storage_class == ast::StorageClass::kOutput) {
+        ast_storage_class = ast::StorageClass::kPrivate;
+    }
+    switch (ptr_as) {
+        case PtrAs::Ref:
+            return ty_.Reference(ast_elem_ty, ast_storage_class);
+        case PtrAs::Ptr:
+            return ty_.Pointer(ast_elem_ty, ast_storage_class);
+    }
+    Fail() << "invalid value for ptr_as: " << static_cast<int>(ptr_as);
+    return nullptr;
 }
 
 bool ParserImpl::RegisterTypes() {
-  if (!success_) {
-    return false;
-  }
+    if (!success_) {
+        return false;
+    }
 
-  // First record the structure types that should have a `block` decoration
-  // in WGSL. In particular, exclude user-defined pipeline IO in a
-  // block-decorated struct.
-  for (const auto& type_or_value : module_->types_values()) {
-    if (type_or_value.opcode() != SpvOpVariable) {
-      continue;
+    // First record the structure types that should have a `block` decoration
+    // in WGSL. In particular, exclude user-defined pipeline IO in a
+    // block-decorated struct.
+    for (const auto& type_or_value : module_->types_values()) {
+        if (type_or_value.opcode() != SpvOpVariable) {
+            continue;
+        }
+        const auto& var = type_or_value;
+        const auto spirv_storage_class = SpvStorageClass(var.GetSingleWordInOperand(0));
+        if ((spirv_storage_class != SpvStorageClassStorageBuffer) &&
+            (spirv_storage_class != SpvStorageClassUniform)) {
+            continue;
+        }
+        const auto* ptr_type = def_use_mgr_->GetDef(var.type_id());
+        if (ptr_type->opcode() != SpvOpTypePointer) {
+            return Fail() << "OpVariable type expected to be a pointer: " << var.PrettyPrint();
+        }
+        const auto* store_type = def_use_mgr_->GetDef(ptr_type->GetSingleWordInOperand(1));
+        if (store_type->opcode() == SpvOpTypeStruct) {
+            struct_types_for_buffers_.insert(store_type->result_id());
+        } else {
+            Fail() << "WGSL does not support arrays of buffers: " << var.PrettyPrint();
+        }
     }
-    const auto& var = type_or_value;
-    const auto spirv_storage_class =
-        SpvStorageClass(var.GetSingleWordInOperand(0));
-    if ((spirv_storage_class != SpvStorageClassStorageBuffer) &&
-        (spirv_storage_class != SpvStorageClassUniform)) {
-      continue;
-    }
-    const auto* ptr_type = def_use_mgr_->GetDef(var.type_id());
-    if (ptr_type->opcode() != SpvOpTypePointer) {
-      return Fail() << "OpVariable type expected to be a pointer: "
-                    << var.PrettyPrint();
-    }
-    const auto* store_type =
-        def_use_mgr_->GetDef(ptr_type->GetSingleWordInOperand(1));
-    if (store_type->opcode() == SpvOpTypeStruct) {
-      struct_types_for_buffers_.insert(store_type->result_id());
-    } else {
-      Fail() << "WGSL does not support arrays of buffers: "
-             << var.PrettyPrint();
-    }
-  }
 
-  // Now convert each type.
-  for (auto& type_or_const : module_->types_values()) {
-    const auto* type = type_mgr_->GetType(type_or_const.result_id());
-    if (type == nullptr) {
-      continue;
+    // Now convert each type.
+    for (auto& type_or_const : module_->types_values()) {
+        const auto* type = type_mgr_->GetType(type_or_const.result_id());
+        if (type == nullptr) {
+            continue;
+        }
+        ConvertType(type_or_const.result_id());
     }
-    ConvertType(type_or_const.result_id());
-  }
-  // Manufacture a type for the gl_Position variable if we have to.
-  if ((builtin_position_.struct_type_id != 0) &&
-      (builtin_position_.position_member_pointer_type_id == 0)) {
-    builtin_position_.position_member_pointer_type_id =
-        type_mgr_->FindPointerToType(builtin_position_.position_member_type_id,
-                                     builtin_position_.storage_class);
-    ConvertType(builtin_position_.position_member_pointer_type_id);
-  }
-  return success_;
+    // Manufacture a type for the gl_Position variable if we have to.
+    if ((builtin_position_.struct_type_id != 0) &&
+        (builtin_position_.position_member_pointer_type_id == 0)) {
+        builtin_position_.position_member_pointer_type_id = type_mgr_->FindPointerToType(
+            builtin_position_.position_member_type_id, builtin_position_.storage_class);
+        ConvertType(builtin_position_.position_member_pointer_type_id);
+    }
+    return success_;
 }
 
 bool ParserImpl::RejectInvalidPointerRoots() {
-  if (!success_) {
-    return false;
-  }
-  for (auto& inst : module_->types_values()) {
-    if (const auto* result_type = type_mgr_->GetType(inst.type_id())) {
-      if (result_type->AsPointer()) {
-        switch (inst.opcode()) {
-          case SpvOpVariable:
-            // This is the only valid case.
-            break;
-          case SpvOpUndef:
-            return Fail() << "undef pointer is not valid: "
-                          << inst.PrettyPrint();
-          case SpvOpConstantNull:
-            return Fail() << "null pointer is not valid: "
-                          << inst.PrettyPrint();
-          default:
-            return Fail() << "module-scope pointer is not valid: "
-                          << inst.PrettyPrint();
-        }
-      }
+    if (!success_) {
+        return false;
     }
-  }
-  return success();
+    for (auto& inst : module_->types_values()) {
+        if (const auto* result_type = type_mgr_->GetType(inst.type_id())) {
+            if (result_type->AsPointer()) {
+                switch (inst.opcode()) {
+                    case SpvOpVariable:
+                        // This is the only valid case.
+                        break;
+                    case SpvOpUndef:
+                        return Fail() << "undef pointer is not valid: " << inst.PrettyPrint();
+                    case SpvOpConstantNull:
+                        return Fail() << "null pointer is not valid: " << inst.PrettyPrint();
+                    default:
+                        return Fail()
+                               << "module-scope pointer is not valid: " << inst.PrettyPrint();
+                }
+            }
+        }
+    }
+    return success();
 }
 
 bool ParserImpl::EmitScalarSpecConstants() {
-  if (!success_) {
-    return false;
-  }
-  // Generate a module-scope const declaration for each instruction
-  // that is OpSpecConstantTrue, OpSpecConstantFalse, or OpSpecConstant.
-  for (auto& inst : module_->types_values()) {
-    // These will be populated for a valid scalar spec constant.
-    const Type* ast_type = nullptr;
-    ast::LiteralExpression* ast_expr = nullptr;
+    if (!success_) {
+        return false;
+    }
+    // Generate a module-scope const declaration for each instruction
+    // that is OpSpecConstantTrue, OpSpecConstantFalse, or OpSpecConstant.
+    for (auto& inst : module_->types_values()) {
+        // These will be populated for a valid scalar spec constant.
+        const Type* ast_type = nullptr;
+        ast::LiteralExpression* ast_expr = nullptr;
 
-    switch (inst.opcode()) {
-      case SpvOpSpecConstantTrue:
-      case SpvOpSpecConstantFalse: {
-        ast_type = ConvertType(inst.type_id());
-        ast_expr = create<ast::BoolLiteralExpression>(
-            Source{}, inst.opcode() == SpvOpSpecConstantTrue);
-        break;
-      }
-      case SpvOpSpecConstant: {
-        ast_type = ConvertType(inst.type_id());
-        const uint32_t literal_value = inst.GetSingleWordInOperand(0);
-        if (ast_type->Is<I32>()) {
-          ast_expr = create<ast::SintLiteralExpression>(
-              Source{}, static_cast<int32_t>(literal_value));
-        } else if (ast_type->Is<U32>()) {
-          ast_expr = create<ast::UintLiteralExpression>(
-              Source{}, static_cast<uint32_t>(literal_value));
-        } else if (ast_type->Is<F32>()) {
-          float float_value;
-          // Copy the bits so we can read them as a float.
-          std::memcpy(&float_value, &literal_value, sizeof(float_value));
-          ast_expr = create<ast::FloatLiteralExpression>(Source{}, float_value);
-        } else {
-          return Fail() << " invalid result type for OpSpecConstant "
-                        << inst.PrettyPrint();
+        switch (inst.opcode()) {
+            case SpvOpSpecConstantTrue:
+            case SpvOpSpecConstantFalse: {
+                ast_type = ConvertType(inst.type_id());
+                ast_expr = create<ast::BoolLiteralExpression>(
+                    Source{}, inst.opcode() == SpvOpSpecConstantTrue);
+                break;
+            }
+            case SpvOpSpecConstant: {
+                ast_type = ConvertType(inst.type_id());
+                const uint32_t literal_value = inst.GetSingleWordInOperand(0);
+                ast_expr = Switch(
+                    ast_type,  //
+                    [&](const I32*) {
+                        return create<ast::IntLiteralExpression>(
+                            Source{}, static_cast<int64_t>(literal_value),
+                            ast::IntLiteralExpression::Suffix::kI);
+                    },
+                    [&](const U32*) {
+                        return create<ast::IntLiteralExpression>(
+                            Source{}, static_cast<uint64_t>(literal_value),
+                            ast::IntLiteralExpression::Suffix::kU);
+                    },
+                    [&](const F32*) {
+                        float float_value;
+                        // Copy the bits so we can read them as a float.
+                        std::memcpy(&float_value, &literal_value, sizeof(float_value));
+                        return create<ast::FloatLiteralExpression>(Source{}, float_value);
+                    });
+                if (ast_expr == nullptr) {
+                    return Fail() << " invalid result type for OpSpecConstant "
+                                  << inst.PrettyPrint();
+                }
+                break;
+            }
+            default:
+                break;
         }
-        break;
-      }
-      default:
-        break;
-    }
-    if (ast_type && ast_expr) {
-      ast::AttributeList spec_id_decos;
-      for (const auto& deco : GetDecorationsFor(inst.result_id())) {
-        if ((deco.size() == 2) && (deco[0] == SpvDecorationSpecId)) {
-          const uint32_t id = deco[1];
-          if (id > 65535) {
-            return Fail() << "SpecId too large. WGSL override IDs must be "
-                             "between 0 and 65535: ID %"
-                          << inst.result_id() << " has SpecId " << id;
-          }
-          auto* cid = create<ast::IdAttribute>(Source{}, id);
-          spec_id_decos.push_back(cid);
-          break;
+        if (ast_type && ast_expr) {
+            ast::AttributeList spec_id_decos;
+            for (const auto& deco : GetDecorationsFor(inst.result_id())) {
+                if ((deco.size() == 2) && (deco[0] == SpvDecorationSpecId)) {
+                    const uint32_t id = deco[1];
+                    if (id > 65535) {
+                        return Fail() << "SpecId too large. WGSL override IDs must be "
+                                         "between 0 and 65535: ID %"
+                                      << inst.result_id() << " has SpecId " << id;
+                    }
+                    auto* cid = create<ast::IdAttribute>(Source{}, id);
+                    spec_id_decos.push_back(cid);
+                    break;
+                }
+            }
+            auto* ast_var = MakeVariable(inst.result_id(), ast::StorageClass::kNone, ast_type, true,
+                                         true, ast_expr, std::move(spec_id_decos));
+            if (ast_var) {
+                builder_.AST().AddGlobalVariable(ast_var);
+                scalar_spec_constants_.insert(inst.result_id());
+            }
         }
-      }
-      auto* ast_var =
-          MakeVariable(inst.result_id(), ast::StorageClass::kNone, ast_type,
-                       true, true, ast_expr, std::move(spec_id_decos));
-      if (ast_var) {
-        builder_.AST().AddGlobalVariable(ast_var);
-        scalar_spec_constants_.insert(inst.result_id());
-      }
     }
-  }
-  return success_;
+    return success_;
 }
 
-const Type* ParserImpl::MaybeGenerateAlias(
-    uint32_t type_id,
-    const spvtools::opt::analysis::Type* type,
-    const Type* ast_type) {
-  if (!success_) {
-    return nullptr;
-  }
+const Type* ParserImpl::MaybeGenerateAlias(uint32_t type_id,
+                                           const spvtools::opt::analysis::Type* type,
+                                           const Type* ast_type) {
+    if (!success_) {
+        return nullptr;
+    }
 
-  // We only care about arrays, and runtime arrays.
-  switch (type->kind()) {
-    case spvtools::opt::analysis::Type::kRuntimeArray:
-      // Runtime arrays are always decorated with ArrayStride so always get a
-      // type alias.
-      namer_.SuggestSanitizedName(type_id, "RTArr");
-      break;
-    case spvtools::opt::analysis::Type::kArray:
-      // Only make a type aliase for arrays with decorations.
-      if (GetDecorationsFor(type_id).empty()) {
-        return ast_type;
-      }
-      namer_.SuggestSanitizedName(type_id, "Arr");
-      break;
-    default:
-      // Ignore constants, and any other types.
-      return ast_type;
-  }
-  auto* ast_underlying_type = ast_type;
-  if (ast_underlying_type == nullptr) {
-    Fail() << "internal error: no type registered for SPIR-V ID: " << type_id;
-    return nullptr;
-  }
-  const auto name = namer_.GetName(type_id);
-  const auto sym = builder_.Symbols().Register(name);
-  auto* ast_alias_type =
-      builder_.ty.alias(sym, ast_underlying_type->Build(builder_));
+    // We only care about arrays, and runtime arrays.
+    switch (type->kind()) {
+        case spvtools::opt::analysis::Type::kRuntimeArray:
+            // Runtime arrays are always decorated with ArrayStride so always get a
+            // type alias.
+            namer_.SuggestSanitizedName(type_id, "RTArr");
+            break;
+        case spvtools::opt::analysis::Type::kArray:
+            // Only make a type aliase for arrays with decorations.
+            if (GetDecorationsFor(type_id).empty()) {
+                return ast_type;
+            }
+            namer_.SuggestSanitizedName(type_id, "Arr");
+            break;
+        default:
+            // Ignore constants, and any other types.
+            return ast_type;
+    }
+    auto* ast_underlying_type = ast_type;
+    if (ast_underlying_type == nullptr) {
+        Fail() << "internal error: no type registered for SPIR-V ID: " << type_id;
+        return nullptr;
+    }
+    const auto name = namer_.GetName(type_id);
+    const auto sym = builder_.Symbols().Register(name);
+    auto* ast_alias_type = builder_.ty.alias(sym, ast_underlying_type->Build(builder_));
 
-  // Record this new alias as the AST type for this SPIR-V ID.
-  AddTypeDecl(sym, ast_alias_type);
+    // Record this new alias as the AST type for this SPIR-V ID.
+    AddTypeDecl(sym, ast_alias_type);
 
-  return ty_.Alias(sym, ast_underlying_type);
+    return ty_.Alias(sym, ast_underlying_type);
 }
 
 bool ParserImpl::EmitModuleScopeVariables() {
-  if (!success_) {
-    return false;
-  }
-  for (const auto& type_or_value : module_->types_values()) {
-    if (type_or_value.opcode() != SpvOpVariable) {
-      continue;
-    }
-    const auto& var = type_or_value;
-    const auto spirv_storage_class =
-        SpvStorageClass(var.GetSingleWordInOperand(0));
-
-    uint32_t type_id = var.type_id();
-    if ((type_id == builtin_position_.pointer_type_id) &&
-        ((spirv_storage_class == SpvStorageClassInput) ||
-         (spirv_storage_class == SpvStorageClassOutput))) {
-      // Skip emitting gl_PerVertex.
-      builtin_position_.per_vertex_var_id = var.result_id();
-      builtin_position_.per_vertex_var_init_id =
-          var.NumInOperands() > 1 ? var.GetSingleWordInOperand(1) : 0u;
-      continue;
-    }
-    switch (enum_converter_.ToStorageClass(spirv_storage_class)) {
-      case ast::StorageClass::kNone:
-      case ast::StorageClass::kInput:
-      case ast::StorageClass::kOutput:
-      case ast::StorageClass::kUniform:
-      case ast::StorageClass::kUniformConstant:
-      case ast::StorageClass::kStorage:
-      case ast::StorageClass::kWorkgroup:
-      case ast::StorageClass::kPrivate:
-        break;
-      default:
-        return Fail() << "invalid SPIR-V storage class "
-                      << int(spirv_storage_class)
-                      << " for module scope variable: " << var.PrettyPrint();
-    }
     if (!success_) {
-      return false;
-    }
-    const Type* ast_type = nullptr;
-    if (spirv_storage_class == SpvStorageClassUniformConstant) {
-      // These are opaque handles: samplers or textures
-      ast_type = GetTypeForHandleVar(var);
-      if (!ast_type) {
         return false;
-      }
-    } else {
-      ast_type = ConvertType(type_id);
-      if (ast_type == nullptr) {
-        return Fail() << "internal error: failed to register Tint AST type for "
-                         "SPIR-V type with ID: "
-                      << var.type_id();
-      }
-      if (!ast_type->Is<Pointer>()) {
-        return Fail() << "variable with ID " << var.result_id()
-                      << " has non-pointer type " << var.type_id();
-      }
+    }
+    for (const auto& type_or_value : module_->types_values()) {
+        if (type_or_value.opcode() != SpvOpVariable) {
+            continue;
+        }
+        const auto& var = type_or_value;
+        const auto spirv_storage_class = SpvStorageClass(var.GetSingleWordInOperand(0));
+
+        uint32_t type_id = var.type_id();
+        if ((type_id == builtin_position_.pointer_type_id) &&
+            ((spirv_storage_class == SpvStorageClassInput) ||
+             (spirv_storage_class == SpvStorageClassOutput))) {
+            // Skip emitting gl_PerVertex.
+            builtin_position_.per_vertex_var_id = var.result_id();
+            builtin_position_.per_vertex_var_init_id =
+                var.NumInOperands() > 1 ? var.GetSingleWordInOperand(1) : 0u;
+            continue;
+        }
+        switch (enum_converter_.ToStorageClass(spirv_storage_class)) {
+            case ast::StorageClass::kNone:
+            case ast::StorageClass::kInput:
+            case ast::StorageClass::kOutput:
+            case ast::StorageClass::kUniform:
+            case ast::StorageClass::kHandle:
+            case ast::StorageClass::kStorage:
+            case ast::StorageClass::kWorkgroup:
+            case ast::StorageClass::kPrivate:
+                break;
+            default:
+                return Fail() << "invalid SPIR-V storage class " << int(spirv_storage_class)
+                              << " for module scope variable: " << var.PrettyPrint();
+        }
+        if (!success_) {
+            return false;
+        }
+        const Type* ast_type = nullptr;
+        if (spirv_storage_class == SpvStorageClassUniformConstant) {
+            // These are opaque handles: samplers or textures
+            ast_type = GetTypeForHandleVar(var);
+            if (!ast_type) {
+                return false;
+            }
+        } else {
+            ast_type = ConvertType(type_id);
+            if (ast_type == nullptr) {
+                return Fail() << "internal error: failed to register Tint AST type for "
+                                 "SPIR-V type with ID: "
+                              << var.type_id();
+            }
+            if (!ast_type->Is<Pointer>()) {
+                return Fail() << "variable with ID " << var.result_id() << " has non-pointer type "
+                              << var.type_id();
+            }
+        }
+
+        auto* ast_store_type = ast_type->As<Pointer>()->type;
+        auto ast_storage_class = ast_type->As<Pointer>()->storage_class;
+        const ast::Expression* ast_constructor = nullptr;
+        if (var.NumInOperands() > 1) {
+            // SPIR-V initializers are always constants.
+            // (OpenCL also allows the ID of an OpVariable, but we don't handle that
+            // here.)
+            ast_constructor = MakeConstantExpression(var.GetSingleWordInOperand(1)).expr;
+        }
+        auto* ast_var = MakeVariable(var.result_id(), ast_storage_class, ast_store_type, false,
+                                     false, ast_constructor, ast::AttributeList{});
+        // TODO(dneto): initializers (a.k.a. constructor expression)
+        if (ast_var) {
+            builder_.AST().AddGlobalVariable(ast_var);
+        }
     }
 
-    auto* ast_store_type = ast_type->As<Pointer>()->type;
-    auto ast_storage_class = ast_type->As<Pointer>()->storage_class;
-    const ast::Expression* ast_constructor = nullptr;
-    if (var.NumInOperands() > 1) {
-      // SPIR-V initializers are always constants.
-      // (OpenCL also allows the ID of an OpVariable, but we don't handle that
-      // here.)
-      ast_constructor =
-          MakeConstantExpression(var.GetSingleWordInOperand(1)).expr;
-    }
-    auto* ast_var =
-        MakeVariable(var.result_id(), ast_storage_class, ast_store_type, false,
-                     false, ast_constructor, ast::AttributeList{});
-    // TODO(dneto): initializers (a.k.a. constructor expression)
-    if (ast_var) {
-      builder_.AST().AddGlobalVariable(ast_var);
-    }
-  }
+    // Emit gl_Position instead of gl_PerVertex
+    if (builtin_position_.per_vertex_var_id) {
+        // Make sure the variable has a name.
+        namer_.SuggestSanitizedName(builtin_position_.per_vertex_var_id, "gl_Position");
+        const ast::Expression* ast_constructor = nullptr;
+        if (builtin_position_.per_vertex_var_init_id) {
+            // The initializer is complex.
+            const auto* init = def_use_mgr_->GetDef(builtin_position_.per_vertex_var_init_id);
+            switch (init->opcode()) {
+                case SpvOpConstantComposite:
+                case SpvOpSpecConstantComposite:
+                    ast_constructor =
+                        MakeConstantExpression(
+                            init->GetSingleWordInOperand(builtin_position_.position_member_index))
+                            .expr;
+                    break;
+                default:
+                    return Fail() << "gl_PerVertex initializer too complex. only "
+                                     "OpCompositeConstruct and OpSpecConstantComposite "
+                                     "are supported: "
+                                  << init->PrettyPrint();
+            }
+        }
+        auto* ast_var =
+            MakeVariable(builtin_position_.per_vertex_var_id,
+                         enum_converter_.ToStorageClass(builtin_position_.storage_class),
+                         ConvertType(builtin_position_.position_member_type_id), false, false,
+                         ast_constructor, {});
 
-  // Emit gl_Position instead of gl_PerVertex
-  if (builtin_position_.per_vertex_var_id) {
-    // Make sure the variable has a name.
-    namer_.SuggestSanitizedName(builtin_position_.per_vertex_var_id,
-                                "gl_Position");
-    const ast::Expression* ast_constructor = nullptr;
-    if (builtin_position_.per_vertex_var_init_id) {
-      // The initializer is complex.
-      const auto* init =
-          def_use_mgr_->GetDef(builtin_position_.per_vertex_var_init_id);
-      switch (init->opcode()) {
-        case SpvOpConstantComposite:
-        case SpvOpSpecConstantComposite:
-          ast_constructor = MakeConstantExpression(
-                                init->GetSingleWordInOperand(
-                                    builtin_position_.position_member_index))
-                                .expr;
-          break;
-        default:
-          return Fail() << "gl_PerVertex initializer too complex. only "
-                           "OpCompositeConstruct and OpSpecConstantComposite "
-                           "are supported: "
-                        << init->PrettyPrint();
-      }
+        builder_.AST().AddGlobalVariable(ast_var);
     }
-    auto* ast_var = MakeVariable(
-        builtin_position_.per_vertex_var_id,
-        enum_converter_.ToStorageClass(builtin_position_.storage_class),
-        ConvertType(builtin_position_.position_member_type_id), false, false,
-        ast_constructor, {});
-
-    builder_.AST().AddGlobalVariable(ast_var);
-  }
-  return success_;
+    return success_;
 }
 
 // @param var_id SPIR-V id of an OpVariable, assumed to be pointer
 // to an array
 // @returns the IntConstant for the size of the array, or nullptr
-const spvtools::opt::analysis::IntConstant* ParserImpl::GetArraySize(
-    uint32_t var_id) {
-  auto* var = def_use_mgr_->GetDef(var_id);
-  if (!var || var->opcode() != SpvOpVariable) {
-    return nullptr;
-  }
-  auto* ptr_type = def_use_mgr_->GetDef(var->type_id());
-  if (!ptr_type || ptr_type->opcode() != SpvOpTypePointer) {
-    return nullptr;
-  }
-  auto* array_type = def_use_mgr_->GetDef(ptr_type->GetSingleWordInOperand(1));
-  if (!array_type || array_type->opcode() != SpvOpTypeArray) {
-    return nullptr;
-  }
-  auto* size = constant_mgr_->FindDeclaredConstant(
-      array_type->GetSingleWordInOperand(1));
-  if (!size) {
-    return nullptr;
-  }
-  return size->AsIntConstant();
+const spvtools::opt::analysis::IntConstant* ParserImpl::GetArraySize(uint32_t var_id) {
+    auto* var = def_use_mgr_->GetDef(var_id);
+    if (!var || var->opcode() != SpvOpVariable) {
+        return nullptr;
+    }
+    auto* ptr_type = def_use_mgr_->GetDef(var->type_id());
+    if (!ptr_type || ptr_type->opcode() != SpvOpTypePointer) {
+        return nullptr;
+    }
+    auto* array_type = def_use_mgr_->GetDef(ptr_type->GetSingleWordInOperand(1));
+    if (!array_type || array_type->opcode() != SpvOpTypeArray) {
+        return nullptr;
+    }
+    auto* size = constant_mgr_->FindDeclaredConstant(array_type->GetSingleWordInOperand(1));
+    if (!size) {
+        return nullptr;
+    }
+    return size->AsIntConstant();
 }
 
 ast::Variable* ParserImpl::MakeVariable(uint32_t id,
@@ -1614,1175 +1559,1141 @@
                                         bool is_overridable,
                                         const ast::Expression* constructor,
                                         ast::AttributeList decorations) {
-  if (storage_type == nullptr) {
-    Fail() << "internal error: can't make ast::Variable for null type";
-    return nullptr;
-  }
-
-  ast::Access access = ast::Access::kUndefined;
-  if (sc == ast::StorageClass::kStorage) {
-    bool read_only = false;
-    if (auto* tn = storage_type->As<Named>()) {
-      read_only = read_only_struct_types_.count(tn->name) > 0;
+    if (storage_type == nullptr) {
+        Fail() << "internal error: can't make ast::Variable for null type";
+        return nullptr;
     }
 
-    // Apply the access(read) or access(read_write) modifier.
-    access = read_only ? ast::Access::kRead : ast::Access::kReadWrite;
-  }
+    ast::Access access = ast::Access::kUndefined;
+    if (sc == ast::StorageClass::kStorage) {
+        bool read_only = false;
+        if (auto* tn = storage_type->As<Named>()) {
+            read_only = read_only_struct_types_.count(tn->name) > 0;
+        }
 
-  // Handle variables (textures and samplers) are always in the handle
-  // storage class, so we don't mention the storage class.
-  if (sc == ast::StorageClass::kUniformConstant) {
-    sc = ast::StorageClass::kNone;
-  }
+        // Apply the access(read) or access(read_write) modifier.
+        access = read_only ? ast::Access::kRead : ast::Access::kReadWrite;
+    }
 
-  if (!ConvertDecorationsForVariable(id, &storage_type, &decorations,
-                                     sc != ast::StorageClass::kPrivate)) {
-    return nullptr;
-  }
+    // Handle variables (textures and samplers) are always in the handle
+    // storage class, so we don't mention the storage class.
+    if (sc == ast::StorageClass::kHandle) {
+        sc = ast::StorageClass::kNone;
+    }
 
-  std::string name = namer_.Name(id);
+    if (!ConvertDecorationsForVariable(id, &storage_type, &decorations,
+                                       sc != ast::StorageClass::kPrivate)) {
+        return nullptr;
+    }
 
-  // Note: we're constructing the variable here with the *storage* type,
-  // regardless of whether this is a `let`, `override`, or `var` declaration.
-  // `var` declarations will have a resolved type of ref<storage>, but at the
-  // AST level all three are declared with the same type.
-  return create<ast::Variable>(Source{}, builder_.Symbols().Register(name), sc,
-                               access, storage_type->Build(builder_), is_const,
-                               is_overridable, constructor, decorations);
+    std::string name = namer_.Name(id);
+
+    // Note: we're constructing the variable here with the *storage* type,
+    // regardless of whether this is a `let`, `override`, or `var` declaration.
+    // `var` declarations will have a resolved type of ref<storage>, but at the
+    // AST level all three are declared with the same type.
+    return create<ast::Variable>(Source{}, builder_.Symbols().Register(name), sc, access,
+                                 storage_type->Build(builder_), is_const, is_overridable,
+                                 constructor, decorations);
 }
 
 bool ParserImpl::ConvertDecorationsForVariable(uint32_t id,
                                                const Type** store_type,
                                                ast::AttributeList* decorations,
                                                bool transfer_pipeline_io) {
-  DecorationList non_builtin_pipeline_decorations;
-  for (auto& deco : GetDecorationsFor(id)) {
-    if (deco.empty()) {
-      return Fail() << "malformed decoration on ID " << id << ": it is empty";
-    }
-    if (deco[0] == SpvDecorationBuiltIn) {
-      if (deco.size() == 1) {
-        return Fail() << "malformed BuiltIn decoration on ID " << id
-                      << ": has no operand";
-      }
-      const auto spv_builtin = static_cast<SpvBuiltIn>(deco[1]);
-      switch (spv_builtin) {
-        case SpvBuiltInPointSize:
-          special_builtins_[id] = spv_builtin;
-          return false;  // This is not an error
-        case SpvBuiltInSampleId:
-        case SpvBuiltInVertexIndex:
-        case SpvBuiltInInstanceIndex:
-        case SpvBuiltInLocalInvocationId:
-        case SpvBuiltInLocalInvocationIndex:
-        case SpvBuiltInGlobalInvocationId:
-        case SpvBuiltInWorkgroupId:
-        case SpvBuiltInNumWorkgroups:
-          // The SPIR-V variable may signed (because GLSL requires signed for
-          // some of these), but WGSL requires unsigned.  Handle specially
-          // so we always perform the conversion at load and store.
-          special_builtins_[id] = spv_builtin;
-          if (auto* forced_type = UnsignedTypeFor(*store_type)) {
-            // Requires conversion and special handling in code generation.
-            if (transfer_pipeline_io) {
-              *store_type = forced_type;
-            }
-          }
-          break;
-        case SpvBuiltInSampleMask: {
-          // In SPIR-V this is used for both input and output variable.
-          // The SPIR-V variable has store type of array of integer scalar,
-          // either signed or unsigned.
-          // WGSL requires the store type to be u32.
-          auto* size = GetArraySize(id);
-          if (!size || size->GetZeroExtendedValue() != 1) {
-            Fail() << "WGSL supports a sample mask of at most 32 bits. "
-                      "SampleMask must be an array of 1 element.";
-          }
-          special_builtins_[id] = spv_builtin;
-          if (transfer_pipeline_io) {
-            *store_type = ty_.U32();
-          }
-          break;
+    DecorationList non_builtin_pipeline_decorations;
+    for (auto& deco : GetDecorationsFor(id)) {
+        if (deco.empty()) {
+            return Fail() << "malformed decoration on ID " << id << ": it is empty";
         }
-        default:
-          break;
-      }
-      auto ast_builtin = enum_converter_.ToBuiltin(spv_builtin);
-      if (ast_builtin == ast::Builtin::kNone) {
-        // A diagnostic has already been emitted.
-        return false;
-      }
-      if (transfer_pipeline_io) {
-        decorations->emplace_back(
-            create<ast::BuiltinAttribute>(Source{}, ast_builtin));
-      }
+        if (deco[0] == SpvDecorationBuiltIn) {
+            if (deco.size() == 1) {
+                return Fail() << "malformed BuiltIn decoration on ID " << id << ": has no operand";
+            }
+            const auto spv_builtin = static_cast<SpvBuiltIn>(deco[1]);
+            switch (spv_builtin) {
+                case SpvBuiltInPointSize:
+                    special_builtins_[id] = spv_builtin;
+                    return false;  // This is not an error
+                case SpvBuiltInSampleId:
+                case SpvBuiltInVertexIndex:
+                case SpvBuiltInInstanceIndex:
+                case SpvBuiltInLocalInvocationId:
+                case SpvBuiltInLocalInvocationIndex:
+                case SpvBuiltInGlobalInvocationId:
+                case SpvBuiltInWorkgroupId:
+                case SpvBuiltInNumWorkgroups:
+                    // The SPIR-V variable may signed (because GLSL requires signed for
+                    // some of these), but WGSL requires unsigned.  Handle specially
+                    // so we always perform the conversion at load and store.
+                    special_builtins_[id] = spv_builtin;
+                    if (auto* forced_type = UnsignedTypeFor(*store_type)) {
+                        // Requires conversion and special handling in code generation.
+                        if (transfer_pipeline_io) {
+                            *store_type = forced_type;
+                        }
+                    }
+                    break;
+                case SpvBuiltInSampleMask: {
+                    // In SPIR-V this is used for both input and output variable.
+                    // The SPIR-V variable has store type of array of integer scalar,
+                    // either signed or unsigned.
+                    // WGSL requires the store type to be u32.
+                    auto* size = GetArraySize(id);
+                    if (!size || size->GetZeroExtendedValue() != 1) {
+                        Fail() << "WGSL supports a sample mask of at most 32 bits. "
+                                  "SampleMask must be an array of 1 element.";
+                    }
+                    special_builtins_[id] = spv_builtin;
+                    if (transfer_pipeline_io) {
+                        *store_type = ty_.U32();
+                    }
+                    break;
+                }
+                default:
+                    break;
+            }
+            auto ast_builtin = enum_converter_.ToBuiltin(spv_builtin);
+            if (ast_builtin == ast::Builtin::kNone) {
+                // A diagnostic has already been emitted.
+                return false;
+            }
+            if (transfer_pipeline_io) {
+                decorations->emplace_back(create<ast::BuiltinAttribute>(Source{}, ast_builtin));
+            }
+        }
+        if (transfer_pipeline_io && IsPipelineDecoration(deco)) {
+            non_builtin_pipeline_decorations.push_back(deco);
+        }
+        if (deco[0] == SpvDecorationDescriptorSet) {
+            if (deco.size() == 1) {
+                return Fail() << "malformed DescriptorSet decoration on ID " << id
+                              << ": has no operand";
+            }
+            decorations->emplace_back(create<ast::GroupAttribute>(Source{}, deco[1]));
+        }
+        if (deco[0] == SpvDecorationBinding) {
+            if (deco.size() == 1) {
+                return Fail() << "malformed Binding decoration on ID " << id << ": has no operand";
+            }
+            decorations->emplace_back(create<ast::BindingAttribute>(Source{}, deco[1]));
+        }
     }
-    if (transfer_pipeline_io && IsPipelineDecoration(deco)) {
-      non_builtin_pipeline_decorations.push_back(deco);
-    }
-    if (deco[0] == SpvDecorationDescriptorSet) {
-      if (deco.size() == 1) {
-        return Fail() << "malformed DescriptorSet decoration on ID " << id
-                      << ": has no operand";
-      }
-      decorations->emplace_back(create<ast::GroupAttribute>(Source{}, deco[1]));
-    }
-    if (deco[0] == SpvDecorationBinding) {
-      if (deco.size() == 1) {
-        return Fail() << "malformed Binding decoration on ID " << id
-                      << ": has no operand";
-      }
-      decorations->emplace_back(
-          create<ast::BindingAttribute>(Source{}, deco[1]));
-    }
-  }
 
-  if (transfer_pipeline_io) {
-    if (!ConvertPipelineDecorations(
-            *store_type, non_builtin_pipeline_decorations, decorations)) {
-      return false;
+    if (transfer_pipeline_io) {
+        if (!ConvertPipelineDecorations(*store_type, non_builtin_pipeline_decorations,
+                                        decorations)) {
+            return false;
+        }
     }
-  }
 
-  return success();
+    return success();
 }
 
-DecorationList ParserImpl::GetMemberPipelineDecorations(
-    const Struct& struct_type,
-    int member_index) {
-  // Yes, I could have used std::copy_if or std::copy_if.
-  DecorationList result;
-  for (const auto& deco : GetDecorationsForMember(
-           struct_id_for_symbol_[struct_type.name], member_index)) {
-    if (IsPipelineDecoration(deco)) {
-      result.emplace_back(deco);
+DecorationList ParserImpl::GetMemberPipelineDecorations(const Struct& struct_type,
+                                                        int member_index) {
+    // Yes, I could have used std::copy_if or std::copy_if.
+    DecorationList result;
+    for (const auto& deco :
+         GetDecorationsForMember(struct_id_for_symbol_[struct_type.name], member_index)) {
+        if (IsPipelineDecoration(deco)) {
+            result.emplace_back(deco);
+        }
     }
-  }
-  return result;
+    return result;
 }
 
-const ast::Attribute* ParserImpl::SetLocation(
-    ast::AttributeList* attributes,
-    const ast::Attribute* replacement) {
-  if (!replacement) {
+const ast::Attribute* ParserImpl::SetLocation(ast::AttributeList* attributes,
+                                              const ast::Attribute* replacement) {
+    if (!replacement) {
+        return nullptr;
+    }
+    for (auto*& attribute : *attributes) {
+        if (attribute->Is<ast::LocationAttribute>()) {
+            // Replace this location attribute with the replacement.
+            // The old one doesn't leak because it's kept in the builder's AST node
+            // list.
+            const ast::Attribute* result = nullptr;
+            result = attribute;
+            attribute = replacement;
+            return result;  // Assume there is only one such decoration.
+        }
+    }
+    // The list didn't have a location. Add it.
+    attributes->push_back(replacement);
     return nullptr;
-  }
-  for (auto*& attribute : *attributes) {
-    if (attribute->Is<ast::LocationAttribute>()) {
-      // Replace this location attribute with the replacement.
-      // The old one doesn't leak because it's kept in the builder's AST node
-      // list.
-      const ast::Attribute* result = nullptr;
-      result = attribute;
-      attribute = replacement;
-      return result;  // Assume there is only one such decoration.
-    }
-  }
-  // The list didn't have a location. Add it.
-  attributes->push_back(replacement);
-  return nullptr;
 }
 
 bool ParserImpl::ConvertPipelineDecorations(const Type* store_type,
                                             const DecorationList& decorations,
                                             ast::AttributeList* attributes) {
-  // Vulkan defaults to perspective-correct interpolation.
-  ast::InterpolationType type = ast::InterpolationType::kPerspective;
-  ast::InterpolationSampling sampling = ast::InterpolationSampling::kNone;
+    // Vulkan defaults to perspective-correct interpolation.
+    ast::InterpolationType type = ast::InterpolationType::kPerspective;
+    ast::InterpolationSampling sampling = ast::InterpolationSampling::kNone;
 
-  for (const auto& deco : decorations) {
-    TINT_ASSERT(Reader, deco.size() > 0);
-    switch (deco[0]) {
-      case SpvDecorationLocation:
-        if (deco.size() != 2) {
-          return Fail() << "malformed Location decoration on ID requires one "
-                           "literal operand";
+    for (const auto& deco : decorations) {
+        TINT_ASSERT(Reader, deco.size() > 0);
+        switch (deco[0]) {
+            case SpvDecorationLocation:
+                if (deco.size() != 2) {
+                    return Fail() << "malformed Location decoration on ID requires one "
+                                     "literal operand";
+                }
+                SetLocation(attributes, create<ast::LocationAttribute>(Source{}, deco[1]));
+                if (store_type->IsIntegerScalarOrVector()) {
+                    // Default to flat interpolation for integral user-defined IO types.
+                    type = ast::InterpolationType::kFlat;
+                }
+                break;
+            case SpvDecorationFlat:
+                type = ast::InterpolationType::kFlat;
+                break;
+            case SpvDecorationNoPerspective:
+                if (store_type->IsIntegerScalarOrVector()) {
+                    // This doesn't capture the array or struct case.
+                    return Fail() << "NoPerspective is invalid on integral IO";
+                }
+                type = ast::InterpolationType::kLinear;
+                break;
+            case SpvDecorationCentroid:
+                if (store_type->IsIntegerScalarOrVector()) {
+                    // This doesn't capture the array or struct case.
+                    return Fail() << "Centroid interpolation sampling is invalid on integral IO";
+                }
+                sampling = ast::InterpolationSampling::kCentroid;
+                break;
+            case SpvDecorationSample:
+                if (store_type->IsIntegerScalarOrVector()) {
+                    // This doesn't capture the array or struct case.
+                    return Fail() << "Sample interpolation sampling is invalid on integral IO";
+                }
+                sampling = ast::InterpolationSampling::kSample;
+                break;
+            default:
+                break;
         }
-        SetLocation(attributes,
-                    create<ast::LocationAttribute>(Source{}, deco[1]));
-        if (store_type->IsIntegerScalarOrVector()) {
-          // Default to flat interpolation for integral user-defined IO types.
-          type = ast::InterpolationType::kFlat;
-        }
-        break;
-      case SpvDecorationFlat:
-        type = ast::InterpolationType::kFlat;
-        break;
-      case SpvDecorationNoPerspective:
-        if (store_type->IsIntegerScalarOrVector()) {
-          // This doesn't capture the array or struct case.
-          return Fail() << "NoPerspective is invalid on integral IO";
-        }
-        type = ast::InterpolationType::kLinear;
-        break;
-      case SpvDecorationCentroid:
-        if (store_type->IsIntegerScalarOrVector()) {
-          // This doesn't capture the array or struct case.
-          return Fail()
-                 << "Centroid interpolation sampling is invalid on integral IO";
-        }
-        sampling = ast::InterpolationSampling::kCentroid;
-        break;
-      case SpvDecorationSample:
-        if (store_type->IsIntegerScalarOrVector()) {
-          // This doesn't capture the array or struct case.
-          return Fail()
-                 << "Sample interpolation sampling is invalid on integral IO";
-        }
-        sampling = ast::InterpolationSampling::kSample;
-        break;
-      default:
-        break;
     }
-  }
 
-  // Apply interpolation.
-  if (type == ast::InterpolationType::kPerspective &&
-      sampling == ast::InterpolationSampling::kNone) {
-    // This is the default. Don't add a decoration.
-  } else {
-    attributes->emplace_back(create<ast::InterpolateAttribute>(type, sampling));
-  }
+    // Apply interpolation.
+    if (type == ast::InterpolationType::kPerspective &&
+        sampling == ast::InterpolationSampling::kNone) {
+        // This is the default. Don't add a decoration.
+    } else {
+        attributes->emplace_back(create<ast::InterpolateAttribute>(type, sampling));
+    }
 
-  return success();
+    return success();
 }
 
 bool ParserImpl::CanMakeConstantExpression(uint32_t id) {
-  if ((id == workgroup_size_builtin_.id) ||
-      (id == workgroup_size_builtin_.x_id) ||
-      (id == workgroup_size_builtin_.y_id) ||
-      (id == workgroup_size_builtin_.z_id)) {
-    return true;
-  }
-  const auto* inst = def_use_mgr_->GetDef(id);
-  if (!inst) {
-    return false;
-  }
-  if (inst->opcode() == SpvOpUndef) {
-    return true;
-  }
-  return nullptr != constant_mgr_->FindDeclaredConstant(id);
+    if ((id == workgroup_size_builtin_.id) || (id == workgroup_size_builtin_.x_id) ||
+        (id == workgroup_size_builtin_.y_id) || (id == workgroup_size_builtin_.z_id)) {
+        return true;
+    }
+    const auto* inst = def_use_mgr_->GetDef(id);
+    if (!inst) {
+        return false;
+    }
+    if (inst->opcode() == SpvOpUndef) {
+        return true;
+    }
+    return nullptr != constant_mgr_->FindDeclaredConstant(id);
 }
 
 TypedExpression ParserImpl::MakeConstantExpression(uint32_t id) {
-  if (!success_) {
-    return {};
-  }
-
-  // Handle the special cases for workgroup sizing.
-  if (id == workgroup_size_builtin_.id) {
-    auto x = MakeConstantExpression(workgroup_size_builtin_.x_id);
-    auto y = MakeConstantExpression(workgroup_size_builtin_.y_id);
-    auto z = MakeConstantExpression(workgroup_size_builtin_.z_id);
-    auto* ast_type = ty_.Vector(x.type, 3);
-    return {ast_type,
-            builder_.Construct(Source{}, ast_type->Build(builder_),
-                               ast::ExpressionList{x.expr, y.expr, z.expr})};
-  } else if (id == workgroup_size_builtin_.x_id) {
-    return MakeConstantExpressionForScalarSpirvConstant(
-        Source{}, ConvertType(workgroup_size_builtin_.component_type_id),
-        constant_mgr_->GetConstant(
-            type_mgr_->GetType(workgroup_size_builtin_.component_type_id),
-            {workgroup_size_builtin_.x_value}));
-  } else if (id == workgroup_size_builtin_.y_id) {
-    return MakeConstantExpressionForScalarSpirvConstant(
-        Source{}, ConvertType(workgroup_size_builtin_.component_type_id),
-        constant_mgr_->GetConstant(
-            type_mgr_->GetType(workgroup_size_builtin_.component_type_id),
-            {workgroup_size_builtin_.y_value}));
-  } else if (id == workgroup_size_builtin_.z_id) {
-    return MakeConstantExpressionForScalarSpirvConstant(
-        Source{}, ConvertType(workgroup_size_builtin_.component_type_id),
-        constant_mgr_->GetConstant(
-            type_mgr_->GetType(workgroup_size_builtin_.component_type_id),
-            {workgroup_size_builtin_.z_value}));
-  }
-
-  // Handle the general case where a constant is already registered
-  // with the SPIR-V optimizer's analysis framework.
-  const auto* inst = def_use_mgr_->GetDef(id);
-  if (inst == nullptr) {
-    Fail() << "ID " << id << " is not a registered instruction";
-    return {};
-  }
-  auto source = GetSourceForInst(inst);
-
-  // TODO(dneto): Handle spec constants too?
-
-  auto* original_ast_type = ConvertType(inst->type_id());
-  if (original_ast_type == nullptr) {
-    return {};
-  }
-
-  switch (inst->opcode()) {
-    case SpvOpUndef:  // Remap undef to null.
-    case SpvOpConstantNull:
-      return {original_ast_type, MakeNullValue(original_ast_type)};
-    case SpvOpConstantTrue:
-    case SpvOpConstantFalse:
-    case SpvOpConstant: {
-      const auto* spirv_const = constant_mgr_->FindDeclaredConstant(id);
-      if (spirv_const == nullptr) {
-        Fail() << "ID " << id << " is not a constant";
+    if (!success_) {
         return {};
-      }
-      return MakeConstantExpressionForScalarSpirvConstant(
-          source, original_ast_type, spirv_const);
     }
-    case SpvOpConstantComposite: {
-      // Handle vector, matrix, array, and struct
 
-      // Generate a composite from explicit components.
-      ast::ExpressionList ast_components;
-      if (!inst->WhileEachInId([&](const uint32_t* id_ref) -> bool {
-            auto component = MakeConstantExpression(*id_ref);
-            if (!component) {
-              this->Fail() << "invalid constant with ID " << *id_ref;
-              return false;
+    // Handle the special cases for workgroup sizing.
+    if (id == workgroup_size_builtin_.id) {
+        auto x = MakeConstantExpression(workgroup_size_builtin_.x_id);
+        auto y = MakeConstantExpression(workgroup_size_builtin_.y_id);
+        auto z = MakeConstantExpression(workgroup_size_builtin_.z_id);
+        auto* ast_type = ty_.Vector(x.type, 3);
+        return {ast_type, builder_.Construct(Source{}, ast_type->Build(builder_),
+                                             ast::ExpressionList{x.expr, y.expr, z.expr})};
+    } else if (id == workgroup_size_builtin_.x_id) {
+        return MakeConstantExpressionForScalarSpirvConstant(
+            Source{}, ConvertType(workgroup_size_builtin_.component_type_id),
+            constant_mgr_->GetConstant(
+                type_mgr_->GetType(workgroup_size_builtin_.component_type_id),
+                {workgroup_size_builtin_.x_value}));
+    } else if (id == workgroup_size_builtin_.y_id) {
+        return MakeConstantExpressionForScalarSpirvConstant(
+            Source{}, ConvertType(workgroup_size_builtin_.component_type_id),
+            constant_mgr_->GetConstant(
+                type_mgr_->GetType(workgroup_size_builtin_.component_type_id),
+                {workgroup_size_builtin_.y_value}));
+    } else if (id == workgroup_size_builtin_.z_id) {
+        return MakeConstantExpressionForScalarSpirvConstant(
+            Source{}, ConvertType(workgroup_size_builtin_.component_type_id),
+            constant_mgr_->GetConstant(
+                type_mgr_->GetType(workgroup_size_builtin_.component_type_id),
+                {workgroup_size_builtin_.z_value}));
+    }
+
+    // Handle the general case where a constant is already registered
+    // with the SPIR-V optimizer's analysis framework.
+    const auto* inst = def_use_mgr_->GetDef(id);
+    if (inst == nullptr) {
+        Fail() << "ID " << id << " is not a registered instruction";
+        return {};
+    }
+    auto source = GetSourceForInst(inst);
+
+    // TODO(dneto): Handle spec constants too?
+
+    auto* original_ast_type = ConvertType(inst->type_id());
+    if (original_ast_type == nullptr) {
+        return {};
+    }
+
+    switch (inst->opcode()) {
+        case SpvOpUndef:  // Remap undef to null.
+        case SpvOpConstantNull:
+            return {original_ast_type, MakeNullValue(original_ast_type)};
+        case SpvOpConstantTrue:
+        case SpvOpConstantFalse:
+        case SpvOpConstant: {
+            const auto* spirv_const = constant_mgr_->FindDeclaredConstant(id);
+            if (spirv_const == nullptr) {
+                Fail() << "ID " << id << " is not a constant";
+                return {};
             }
-            ast_components.emplace_back(component.expr);
-            return true;
-          })) {
-        // We've already emitted a diagnostic.
-        return {};
-      }
-      return {original_ast_type,
-              builder_.Construct(source, original_ast_type->Build(builder_),
-                                 std::move(ast_components))};
+            return MakeConstantExpressionForScalarSpirvConstant(source, original_ast_type,
+                                                                spirv_const);
+        }
+        case SpvOpConstantComposite: {
+            // Handle vector, matrix, array, and struct
+
+            // Generate a composite from explicit components.
+            ast::ExpressionList ast_components;
+            if (!inst->WhileEachInId([&](const uint32_t* id_ref) -> bool {
+                    auto component = MakeConstantExpression(*id_ref);
+                    if (!component) {
+                        this->Fail() << "invalid constant with ID " << *id_ref;
+                        return false;
+                    }
+                    ast_components.emplace_back(component.expr);
+                    return true;
+                })) {
+                // We've already emitted a diagnostic.
+                return {};
+            }
+            return {original_ast_type,
+                    builder_.Construct(source, original_ast_type->Build(builder_),
+                                       std::move(ast_components))};
+        }
+        default:
+            break;
     }
-    default:
-      break;
-  }
-  Fail() << "unhandled constant instruction " << inst->PrettyPrint();
-  return {};
+    Fail() << "unhandled constant instruction " << inst->PrettyPrint();
+    return {};
 }
 
 TypedExpression ParserImpl::MakeConstantExpressionForScalarSpirvConstant(
     Source source,
     const Type* original_ast_type,
     const spvtools::opt::analysis::Constant* spirv_const) {
-  auto* ast_type = original_ast_type->UnwrapAlias();
+    auto* ast_type = original_ast_type->UnwrapAlias();
 
-  // TODO(dneto): Note: NullConstant for int, uint, float map to a regular 0.
-  // So canonicalization should map that way too.
-  // Currently "null<type>" is missing from the WGSL parser.
-  // See https://bugs.chromium.org/p/tint/issues/detail?id=34
-  if (ast_type->Is<U32>()) {
-    return {ty_.U32(),
-            create<ast::UintLiteralExpression>(source, spirv_const->GetU32())};
-  }
-  if (ast_type->Is<I32>()) {
-    return {ty_.I32(),
-            create<ast::SintLiteralExpression>(source, spirv_const->GetS32())};
-  }
-  if (ast_type->Is<F32>()) {
-    return {ty_.F32(), create<ast::FloatLiteralExpression>(
-                           source, spirv_const->GetFloat())};
-  }
-  if (ast_type->Is<Bool>()) {
-    const bool value = spirv_const->AsNullConstant()
-                           ? false
-                           : spirv_const->AsBoolConstant()->value();
-    return {ty_.Bool(), create<ast::BoolLiteralExpression>(source, value)};
-  }
-  Fail() << "expected scalar constant";
-  return {};
+    // TODO(dneto): Note: NullConstant for int, uint, float map to a regular 0.
+    // So canonicalization should map that way too.
+    // Currently "null<type>" is missing from the WGSL parser.
+    // See https://bugs.chromium.org/p/tint/issues/detail?id=34
+    return Switch(
+        ast_type,
+        [&](const I32*) {
+            return TypedExpression{ty_.I32(), create<ast::IntLiteralExpression>(
+                                                  source, spirv_const->GetS32(),
+                                                  ast::IntLiteralExpression::Suffix::kI)};
+        },
+        [&](const U32*) {
+            return TypedExpression{ty_.U32(), create<ast::IntLiteralExpression>(
+                                                  source, spirv_const->GetU32(),
+                                                  ast::IntLiteralExpression::Suffix::kU)};
+        },
+        [&](const F32*) {
+            return TypedExpression{
+                ty_.F32(), create<ast::FloatLiteralExpression>(source, spirv_const->GetFloat())};
+        },
+        [&](const Bool*) {
+            const bool value =
+                spirv_const->AsNullConstant() ? false : spirv_const->AsBoolConstant()->value();
+            return TypedExpression{ty_.Bool(), create<ast::BoolLiteralExpression>(source, value)};
+        },
+        [&](Default) {
+            Fail() << "expected scalar constant";
+            return TypedExpression{};
+        });
 }
 
 const ast::Expression* ParserImpl::MakeNullValue(const Type* type) {
-  // TODO(dneto): Use the no-operands constructor syntax when it becomes
-  // available in Tint.
-  // https://github.com/gpuweb/gpuweb/issues/685
-  // https://bugs.chromium.org/p/tint/issues/detail?id=34
+    // TODO(dneto): Use the no-operands constructor syntax when it becomes
+    // available in Tint.
+    // https://github.com/gpuweb/gpuweb/issues/685
+    // https://bugs.chromium.org/p/tint/issues/detail?id=34
 
-  if (!type) {
-    Fail() << "trying to create null value for a null type";
-    return nullptr;
-  }
-
-  auto* original_type = type;
-  type = type->UnwrapAlias();
-
-  if (type->Is<Bool>()) {
-    return create<ast::BoolLiteralExpression>(Source{}, false);
-  }
-  if (type->Is<U32>()) {
-    return create<ast::UintLiteralExpression>(Source{}, 0u);
-  }
-  if (type->Is<I32>()) {
-    return create<ast::SintLiteralExpression>(Source{}, 0);
-  }
-  if (type->Is<F32>()) {
-    return create<ast::FloatLiteralExpression>(Source{}, 0.0f);
-  }
-  if (type->IsAnyOf<Vector, Matrix, Array>()) {
-    return builder_.Construct(Source{}, type->Build(builder_));
-  }
-  if (auto* struct_ty = type->As<Struct>()) {
-    ast::ExpressionList ast_components;
-    for (auto* member : struct_ty->members) {
-      ast_components.emplace_back(MakeNullValue(member));
+    if (!type) {
+        Fail() << "trying to create null value for a null type";
+        return nullptr;
     }
-    return builder_.Construct(Source{}, original_type->Build(builder_),
-                              std::move(ast_components));
-  }
-  Fail() << "can't make null value for type: " << type->TypeInfo().name;
-  return nullptr;
+
+    auto* original_type = type;
+    type = type->UnwrapAlias();
+
+    return Switch(
+        type,  //
+        [&](const I32*) {
+            return create<ast::IntLiteralExpression>(Source{}, 0,
+                                                     ast::IntLiteralExpression::Suffix::kI);
+        },
+        [&](const U32*) {
+            return create<ast::IntLiteralExpression>(Source{}, 0,
+                                                     ast::IntLiteralExpression::Suffix::kU);
+        },
+        [&](const F32*) { return create<ast::FloatLiteralExpression>(Source{}, 0.0f); },
+        [&](const Vector*) { return builder_.Construct(Source{}, type->Build(builder_)); },
+        [&](const Matrix*) { return builder_.Construct(Source{}, type->Build(builder_)); },
+        [&](const Array*) { return builder_.Construct(Source{}, type->Build(builder_)); },
+        [&](const Bool*) { return create<ast::BoolLiteralExpression>(Source{}, false); },
+        [&](const Struct* struct_ty) {
+            ast::ExpressionList ast_components;
+            for (auto* member : struct_ty->members) {
+                ast_components.emplace_back(MakeNullValue(member));
+            }
+            return builder_.Construct(Source{}, original_type->Build(builder_),
+                                      std::move(ast_components));
+        },
+        [&](Default) {
+            Fail() << "can't make null value for type: " << type->TypeInfo().name;
+            return nullptr;
+        });
 }
 
 TypedExpression ParserImpl::MakeNullExpression(const Type* type) {
-  return {type, MakeNullValue(type)};
+    return {type, MakeNullValue(type)};
 }
 
 const Type* ParserImpl::UnsignedTypeFor(const Type* type) {
-  if (type->Is<I32>()) {
-    return ty_.U32();
-  }
-  if (auto* v = type->As<Vector>()) {
-    if (v->type->Is<I32>()) {
-      return ty_.Vector(ty_.U32(), v->size);
+    if (type->Is<I32>()) {
+        return ty_.U32();
     }
-  }
-  return {};
+    if (auto* v = type->As<Vector>()) {
+        if (v->type->Is<I32>()) {
+            return ty_.Vector(ty_.U32(), v->size);
+        }
+    }
+    return {};
 }
 
 const Type* ParserImpl::SignedTypeFor(const Type* type) {
-  if (type->Is<U32>()) {
-    return ty_.I32();
-  }
-  if (auto* v = type->As<Vector>()) {
-    if (v->type->Is<U32>()) {
-      return ty_.Vector(ty_.I32(), v->size);
+    if (type->Is<U32>()) {
+        return ty_.I32();
     }
-  }
-  return {};
+    if (auto* v = type->As<Vector>()) {
+        if (v->type->Is<U32>()) {
+            return ty_.Vector(ty_.I32(), v->size);
+        }
+    }
+    return {};
 }
 
-TypedExpression ParserImpl::RectifyOperandSignedness(
-    const spvtools::opt::Instruction& inst,
-    TypedExpression&& expr) {
-  bool requires_signed = false;
-  bool requires_unsigned = false;
-  if (IsGlslExtendedInstruction(inst)) {
-    const auto extended_opcode =
-        static_cast<GLSLstd450>(inst.GetSingleWordInOperand(1));
-    requires_signed = AssumesSignedOperands(extended_opcode);
-    requires_unsigned = AssumesUnsignedOperands(extended_opcode);
-  } else {
-    const auto opcode = inst.opcode();
-    requires_signed = AssumesSignedOperands(opcode);
-    requires_unsigned = AssumesUnsignedOperands(opcode);
-  }
-  if (!requires_signed && !requires_unsigned) {
-    // No conversion is required, assuming our tables are complete.
+TypedExpression ParserImpl::RectifyOperandSignedness(const spvtools::opt::Instruction& inst,
+                                                     TypedExpression&& expr) {
+    bool requires_signed = false;
+    bool requires_unsigned = false;
+    if (IsGlslExtendedInstruction(inst)) {
+        const auto extended_opcode = static_cast<GLSLstd450>(inst.GetSingleWordInOperand(1));
+        requires_signed = AssumesSignedOperands(extended_opcode);
+        requires_unsigned = AssumesUnsignedOperands(extended_opcode);
+    } else {
+        const auto opcode = inst.opcode();
+        requires_signed = AssumesSignedOperands(opcode);
+        requires_unsigned = AssumesUnsignedOperands(opcode);
+    }
+    if (!requires_signed && !requires_unsigned) {
+        // No conversion is required, assuming our tables are complete.
+        return std::move(expr);
+    }
+    if (!expr) {
+        Fail() << "internal error: RectifyOperandSignedness given a null expr\n";
+        return {};
+    }
+    auto* type = expr.type;
+    if (!type) {
+        Fail() << "internal error: unmapped type for: " << expr.expr->TypeInfo().name << "\n";
+        return {};
+    }
+    if (requires_unsigned) {
+        if (auto* unsigned_ty = UnsignedTypeFor(type)) {
+            // Conversion is required.
+            return {unsigned_ty, create<ast::BitcastExpression>(
+                                     Source{}, unsigned_ty->Build(builder_), expr.expr)};
+        }
+    } else if (requires_signed) {
+        if (auto* signed_ty = SignedTypeFor(type)) {
+            // Conversion is required.
+            return {signed_ty, create<ast::BitcastExpression>(Source{}, signed_ty->Build(builder_),
+                                                              expr.expr)};
+        }
+    }
+    // We should not reach here.
     return std::move(expr);
-  }
-  if (!expr) {
-    Fail() << "internal error: RectifyOperandSignedness given a null expr\n";
-    return {};
-  }
-  auto* type = expr.type;
-  if (!type) {
-    Fail() << "internal error: unmapped type for: "
-           << expr.expr->TypeInfo().name << "\n";
-    return {};
-  }
-  if (requires_unsigned) {
-    if (auto* unsigned_ty = UnsignedTypeFor(type)) {
-      // Conversion is required.
-      return {unsigned_ty,
-              create<ast::BitcastExpression>(
-                  Source{}, unsigned_ty->Build(builder_), expr.expr)};
-    }
-  } else if (requires_signed) {
-    if (auto* signed_ty = SignedTypeFor(type)) {
-      // Conversion is required.
-      return {signed_ty, create<ast::BitcastExpression>(
-                             Source{}, signed_ty->Build(builder_), expr.expr)};
-    }
-  }
-  // We should not reach here.
-  return std::move(expr);
 }
 
-TypedExpression ParserImpl::RectifySecondOperandSignedness(
-    const spvtools::opt::Instruction& inst,
-    const Type* first_operand_type,
-    TypedExpression&& second_operand_expr) {
-  if ((first_operand_type != second_operand_expr.type) &&
-      AssumesSecondOperandSignednessMatchesFirstOperand(inst.opcode())) {
-    // Conversion is required.
-    return {first_operand_type,
-            create<ast::BitcastExpression>(Source{},
-                                           first_operand_type->Build(builder_),
-                                           second_operand_expr.expr)};
-  }
-  // No conversion necessary.
-  return std::move(second_operand_expr);
+TypedExpression ParserImpl::RectifySecondOperandSignedness(const spvtools::opt::Instruction& inst,
+                                                           const Type* first_operand_type,
+                                                           TypedExpression&& second_operand_expr) {
+    if ((first_operand_type != second_operand_expr.type) &&
+        AssumesSecondOperandSignednessMatchesFirstOperand(inst.opcode())) {
+        // Conversion is required.
+        return {first_operand_type,
+                create<ast::BitcastExpression>(Source{}, first_operand_type->Build(builder_),
+                                               second_operand_expr.expr)};
+    }
+    // No conversion necessary.
+    return std::move(second_operand_expr);
 }
 
 const Type* ParserImpl::ForcedResultType(const spvtools::opt::Instruction& inst,
                                          const Type* first_operand_type) {
-  const auto opcode = inst.opcode();
-  if (AssumesResultSignednessMatchesFirstOperand(opcode)) {
-    return first_operand_type;
-  }
-  if (IsGlslExtendedInstruction(inst)) {
-    const auto extended_opcode =
-        static_cast<GLSLstd450>(inst.GetSingleWordInOperand(1));
-    if (AssumesResultSignednessMatchesFirstOperand(extended_opcode)) {
-      return first_operand_type;
+    const auto opcode = inst.opcode();
+    if (AssumesResultSignednessMatchesFirstOperand(opcode)) {
+        return first_operand_type;
     }
-  }
-  return nullptr;
+    if (IsGlslExtendedInstruction(inst)) {
+        const auto extended_opcode = static_cast<GLSLstd450>(inst.GetSingleWordInOperand(1));
+        if (AssumesResultSignednessMatchesFirstOperand(extended_opcode)) {
+            return first_operand_type;
+        }
+    }
+    return nullptr;
 }
 
 const Type* ParserImpl::GetSignedIntMatchingShape(const Type* other) {
-  if (other == nullptr) {
-    Fail() << "no type provided";
-  }
-  if (other->Is<F32>() || other->Is<U32>() || other->Is<I32>()) {
-    return ty_.I32();
-  }
-  if (auto* vec_ty = other->As<Vector>()) {
-    return ty_.Vector(ty_.I32(), vec_ty->size);
-  }
-  Fail() << "required numeric scalar or vector, but got "
-         << other->TypeInfo().name;
-  return nullptr;
+    if (other == nullptr) {
+        Fail() << "no type provided";
+    }
+    if (other->Is<F32>() || other->Is<U32>() || other->Is<I32>()) {
+        return ty_.I32();
+    }
+    if (auto* vec_ty = other->As<Vector>()) {
+        return ty_.Vector(ty_.I32(), vec_ty->size);
+    }
+    Fail() << "required numeric scalar or vector, but got " << other->TypeInfo().name;
+    return nullptr;
 }
 
 const Type* ParserImpl::GetUnsignedIntMatchingShape(const Type* other) {
-  if (other == nullptr) {
-    Fail() << "no type provided";
+    if (other == nullptr) {
+        Fail() << "no type provided";
+        return nullptr;
+    }
+    if (other->Is<F32>() || other->Is<U32>() || other->Is<I32>()) {
+        return ty_.U32();
+    }
+    if (auto* vec_ty = other->As<Vector>()) {
+        return ty_.Vector(ty_.U32(), vec_ty->size);
+    }
+    Fail() << "required numeric scalar or vector, but got " << other->TypeInfo().name;
     return nullptr;
-  }
-  if (other->Is<F32>() || other->Is<U32>() || other->Is<I32>()) {
-    return ty_.U32();
-  }
-  if (auto* vec_ty = other->As<Vector>()) {
-    return ty_.Vector(ty_.U32(), vec_ty->size);
-  }
-  Fail() << "required numeric scalar or vector, but got "
-         << other->TypeInfo().name;
-  return nullptr;
 }
 
-TypedExpression ParserImpl::RectifyForcedResultType(
-    TypedExpression expr,
-    const spvtools::opt::Instruction& inst,
-    const Type* first_operand_type) {
-  auto* forced_result_ty = ForcedResultType(inst, first_operand_type);
-  if ((!forced_result_ty) || (forced_result_ty == expr.type)) {
-    return expr;
-  }
-  return {expr.type, create<ast::BitcastExpression>(
-                         Source{}, expr.type->Build(builder_), expr.expr)};
+TypedExpression ParserImpl::RectifyForcedResultType(TypedExpression expr,
+                                                    const spvtools::opt::Instruction& inst,
+                                                    const Type* first_operand_type) {
+    auto* forced_result_ty = ForcedResultType(inst, first_operand_type);
+    if ((!forced_result_ty) || (forced_result_ty == expr.type)) {
+        return expr;
+    }
+    return {expr.type,
+            create<ast::BitcastExpression>(Source{}, expr.type->Build(builder_), expr.expr)};
 }
 
 TypedExpression ParserImpl::AsUnsigned(TypedExpression expr) {
-  if (expr.type && expr.type->IsSignedScalarOrVector()) {
-    auto* new_type = GetUnsignedIntMatchingShape(expr.type);
-    return {new_type, create<ast::BitcastExpression>(
-                          Source{}, new_type->Build(builder_), expr.expr)};
-  }
-  return expr;
+    if (expr.type && expr.type->IsSignedScalarOrVector()) {
+        auto* new_type = GetUnsignedIntMatchingShape(expr.type);
+        return {new_type,
+                create<ast::BitcastExpression>(Source{}, new_type->Build(builder_), expr.expr)};
+    }
+    return expr;
 }
 
 TypedExpression ParserImpl::AsSigned(TypedExpression expr) {
-  if (expr.type && expr.type->IsUnsignedScalarOrVector()) {
-    auto* new_type = GetSignedIntMatchingShape(expr.type);
-    return {new_type, create<ast::BitcastExpression>(
-                          Source{}, new_type->Build(builder_), expr.expr)};
-  }
-  return expr;
+    if (expr.type && expr.type->IsUnsignedScalarOrVector()) {
+        auto* new_type = GetSignedIntMatchingShape(expr.type);
+        return {new_type,
+                create<ast::BitcastExpression>(Source{}, new_type->Build(builder_), expr.expr)};
+    }
+    return expr;
 }
 
 bool ParserImpl::EmitFunctions() {
-  if (!success_) {
-    return false;
-  }
-  for (const auto* f : topologically_ordered_functions_) {
     if (!success_) {
-      return false;
+        return false;
     }
-
-    auto id = f->result_id();
-    auto it = function_to_ep_info_.find(id);
-    if (it == function_to_ep_info_.end()) {
-      FunctionEmitter emitter(this, *f, nullptr);
-      success_ = emitter.Emit();
-    } else {
-      for (const auto& ep : it->second) {
-        FunctionEmitter emitter(this, *f, &ep);
-        success_ = emitter.Emit();
+    for (const auto* f : topologically_ordered_functions_) {
         if (!success_) {
-          return false;
+            return false;
         }
-      }
-    }
-  }
-  return success_;
-}
 
-const spvtools::opt::Instruction*
-ParserImpl::GetMemoryObjectDeclarationForHandle(uint32_t id,
-                                                bool follow_image) {
-  auto saved_id = id;
-  auto local_fail = [this, saved_id, id,
-                     follow_image]() -> const spvtools::opt::Instruction* {
-    const auto* inst = def_use_mgr_->GetDef(id);
-    Fail() << "Could not find memory object declaration for the "
-           << (follow_image ? "image" : "sampler") << " underlying id " << id
-           << " (from original id " << saved_id << ") "
-           << (inst ? inst->PrettyPrint() : std::string());
-    return nullptr;
-  };
-
-  auto& memo_table =
-      (follow_image ? mem_obj_decl_image_ : mem_obj_decl_sampler_);
-
-  // Use a visited set to defend against bad input which might have long
-  // chains or even loops.
-  std::unordered_set<uint32_t> visited;
-
-  // Trace backward in the SSA data flow until we hit a memory object
-  // declaration.
-  while (true) {
-    auto where = memo_table.find(id);
-    if (where != memo_table.end()) {
-      return where->second;
-    }
-    // Protect against loops.
-    auto visited_iter = visited.find(id);
-    if (visited_iter != visited.end()) {
-      // We've hit a loop. Mark all the visited nodes
-      // as dead ends.
-      for (auto iter : visited) {
-        memo_table[iter] = nullptr;
-      }
-      return nullptr;
-    }
-    visited.insert(id);
-
-    const auto* inst = def_use_mgr_->GetDef(id);
-    if (inst == nullptr) {
-      return local_fail();
-    }
-    switch (inst->opcode()) {
-      case SpvOpFunctionParameter:
-      case SpvOpVariable:
-        // We found the memory object declaration.
-        // Remember it as the answer for the whole path.
-        for (auto iter : visited) {
-          memo_table[iter] = inst;
-        }
-        return inst;
-      case SpvOpLoad:
-        // Follow the pointer being loaded
-        id = inst->GetSingleWordInOperand(0);
-        break;
-      case SpvOpCopyObject:
-        // Follow the object being copied.
-        id = inst->GetSingleWordInOperand(0);
-        break;
-      case SpvOpAccessChain:
-      case SpvOpInBoundsAccessChain:
-      case SpvOpPtrAccessChain:
-      case SpvOpInBoundsPtrAccessChain:
-        // Follow the base pointer.
-        id = inst->GetSingleWordInOperand(0);
-        break;
-      case SpvOpSampledImage:
-        // Follow the image or the sampler, depending on the follow_image
-        // parameter.
-        id = inst->GetSingleWordInOperand(follow_image ? 0 : 1);
-        break;
-      case SpvOpImage:
-        // Follow the sampled image
-        id = inst->GetSingleWordInOperand(0);
-        break;
-      default:
-        // Can't trace further.
-        // Remember it as the answer for the whole path.
-        for (auto iter : visited) {
-          memo_table[iter] = nullptr;
-        }
-        return nullptr;
-    }
-  }
-}
-
-const spvtools::opt::Instruction*
-ParserImpl::GetSpirvTypeForHandleMemoryObjectDeclaration(
-    const spvtools::opt::Instruction& var) {
-  if (!success()) {
-    return nullptr;
-  }
-  // The WGSL handle type is determined by looking at information from
-  // several sources:
-  //    - the usage of the handle by image access instructions
-  //    - the SPIR-V type declaration
-  // Each source does not have enough information to completely determine
-  // the result.
-
-  // Messages are phrased in terms of images and samplers because those
-  // are the only SPIR-V handles supported by WGSL.
-
-  // Get the SPIR-V handle type.
-  const auto* ptr_type = def_use_mgr_->GetDef(var.type_id());
-  if (!ptr_type || (ptr_type->opcode() != SpvOpTypePointer)) {
-    Fail() << "Invalid type for variable or function parameter "
-           << var.PrettyPrint();
-    return nullptr;
-  }
-  const auto* raw_handle_type =
-      def_use_mgr_->GetDef(ptr_type->GetSingleWordInOperand(1));
-  if (!raw_handle_type) {
-    Fail() << "Invalid pointer type for variable or function parameter "
-           << var.PrettyPrint();
-    return nullptr;
-  }
-  switch (raw_handle_type->opcode()) {
-    case SpvOpTypeSampler:
-    case SpvOpTypeImage:
-      // The expected cases.
-      break;
-    case SpvOpTypeArray:
-    case SpvOpTypeRuntimeArray:
-      Fail()
-          << "arrays of textures or samplers are not supported in WGSL; can't "
-             "translate variable or function parameter: "
-          << var.PrettyPrint();
-      return nullptr;
-    case SpvOpTypeSampledImage:
-      Fail() << "WGSL does not support combined image-samplers: "
-             << var.PrettyPrint();
-      return nullptr;
-    default:
-      Fail() << "invalid type for image or sampler variable or function "
-                "parameter: "
-             << var.PrettyPrint();
-      return nullptr;
-  }
-  return raw_handle_type;
-}
-
-const Pointer* ParserImpl::GetTypeForHandleVar(
-    const spvtools::opt::Instruction& var) {
-  auto where = handle_type_.find(&var);
-  if (where != handle_type_.end()) {
-    return where->second;
-  }
-
-  const spvtools::opt::Instruction* raw_handle_type =
-      GetSpirvTypeForHandleMemoryObjectDeclaration(var);
-  if (!raw_handle_type) {
-    return nullptr;
-  }
-
-  // The variable could be a sampler or image.
-  // Where possible, determine which one it is from the usage inferred
-  // for the variable.
-  Usage usage = handle_usage_[&var];
-  if (!usage.IsValid()) {
-    Fail() << "Invalid sampler or texture usage for variable "
-           << var.PrettyPrint() << "\n"
-           << usage;
-    return nullptr;
-  }
-  // Infer a handle type, if usage didn't already tell us.
-  if (!usage.IsComplete()) {
-    // In SPIR-V you could statically reference a texture or sampler without
-    // using it in a way that gives us a clue on how to declare it.  Look inside
-    // the store type to infer a usage.
-    if (raw_handle_type->opcode() == SpvOpTypeSampler) {
-      usage.AddSampler();
-    } else {
-      // It's a texture.
-      if (raw_handle_type->NumInOperands() != 7) {
-        Fail() << "invalid SPIR-V image type: expected 7 operands: "
-               << raw_handle_type->PrettyPrint();
-        return nullptr;
-      }
-      const auto sampled_param = raw_handle_type->GetSingleWordInOperand(5);
-      const auto format_param = raw_handle_type->GetSingleWordInOperand(6);
-      // Only storage images have a format.
-      if ((format_param != SpvImageFormatUnknown) ||
-          sampled_param == 2 /* without sampler */) {
-        // Get NonWritable and NonReadable attributes of the variable.
-        bool is_nonwritable = false;
-        bool is_nonreadable = false;
-        for (const auto& deco : GetDecorationsFor(var.result_id())) {
-          if (deco.size() != 1) {
-            continue;
-          }
-          if (deco[0] == SpvDecorationNonWritable) {
-            is_nonwritable = true;
-          }
-          if (deco[0] == SpvDecorationNonReadable) {
-            is_nonreadable = true;
-          }
-        }
-        if (is_nonwritable && is_nonreadable) {
-          Fail() << "storage image variable is both NonWritable and NonReadable"
-                 << var.PrettyPrint();
-        }
-        if (!is_nonwritable && !is_nonreadable) {
-          Fail()
-              << "storage image variable is neither NonWritable nor NonReadable"
-              << var.PrettyPrint();
-        }
-        // Let's make it one of the storage textures.
-        if (is_nonwritable) {
-          usage.AddStorageReadTexture();
+        auto id = f->result_id();
+        auto it = function_to_ep_info_.find(id);
+        if (it == function_to_ep_info_.end()) {
+            FunctionEmitter emitter(this, *f, nullptr);
+            success_ = emitter.Emit();
         } else {
-          usage.AddStorageWriteTexture();
+            for (const auto& ep : it->second) {
+                FunctionEmitter emitter(this, *f, &ep);
+                success_ = emitter.Emit();
+                if (!success_) {
+                    return false;
+                }
+            }
         }
-      } else {
-        usage.AddSampledTexture();
-      }
     }
-    if (!usage.IsComplete()) {
-      Fail()
-          << "internal error: should have inferred a complete handle type. got "
-          << usage.to_str();
-      return nullptr;
-    }
-  }
+    return success_;
+}
 
-  // Construct the Tint handle type.
-  const Type* ast_store_type = nullptr;
-  if (usage.IsSampler()) {
-    ast_store_type = ty_.Sampler(usage.IsComparisonSampler()
-                                     ? ast::SamplerKind::kComparisonSampler
-                                     : ast::SamplerKind::kSampler);
-  } else if (usage.IsTexture()) {
-    const spvtools::opt::analysis::Image* image_type =
-        type_mgr_->GetType(raw_handle_type->result_id())->AsImage();
-    if (!image_type) {
-      Fail() << "internal error: Couldn't look up image type"
-             << raw_handle_type->PrettyPrint();
-      return nullptr;
-    }
+const spvtools::opt::Instruction* ParserImpl::GetMemoryObjectDeclarationForHandle(
+    uint32_t id,
+    bool follow_image) {
+    auto saved_id = id;
+    auto local_fail = [this, saved_id, id, follow_image]() -> const spvtools::opt::Instruction* {
+        const auto* inst = def_use_mgr_->GetDef(id);
+        Fail() << "Could not find memory object declaration for the "
+               << (follow_image ? "image" : "sampler") << " underlying id " << id
+               << " (from original id " << saved_id << ") "
+               << (inst ? inst->PrettyPrint() : std::string());
+        return nullptr;
+    };
 
-    if (image_type->is_arrayed()) {
-      // Give a nicer error message here, where we have the offending variable
-      // in hand, rather than inside the enum converter.
-      switch (image_type->dim()) {
-        case SpvDim2D:
-        case SpvDimCube:
-          break;
+    auto& memo_table = (follow_image ? mem_obj_decl_image_ : mem_obj_decl_sampler_);
+
+    // Use a visited set to defend against bad input which might have long
+    // chains or even loops.
+    std::unordered_set<uint32_t> visited;
+
+    // Trace backward in the SSA data flow until we hit a memory object
+    // declaration.
+    while (true) {
+        auto where = memo_table.find(id);
+        if (where != memo_table.end()) {
+            return where->second;
+        }
+        // Protect against loops.
+        auto visited_iter = visited.find(id);
+        if (visited_iter != visited.end()) {
+            // We've hit a loop. Mark all the visited nodes
+            // as dead ends.
+            for (auto iter : visited) {
+                memo_table[iter] = nullptr;
+            }
+            return nullptr;
+        }
+        visited.insert(id);
+
+        const auto* inst = def_use_mgr_->GetDef(id);
+        if (inst == nullptr) {
+            return local_fail();
+        }
+        switch (inst->opcode()) {
+            case SpvOpFunctionParameter:
+            case SpvOpVariable:
+                // We found the memory object declaration.
+                // Remember it as the answer for the whole path.
+                for (auto iter : visited) {
+                    memo_table[iter] = inst;
+                }
+                return inst;
+            case SpvOpLoad:
+                // Follow the pointer being loaded
+                id = inst->GetSingleWordInOperand(0);
+                break;
+            case SpvOpCopyObject:
+                // Follow the object being copied.
+                id = inst->GetSingleWordInOperand(0);
+                break;
+            case SpvOpAccessChain:
+            case SpvOpInBoundsAccessChain:
+            case SpvOpPtrAccessChain:
+            case SpvOpInBoundsPtrAccessChain:
+                // Follow the base pointer.
+                id = inst->GetSingleWordInOperand(0);
+                break;
+            case SpvOpSampledImage:
+                // Follow the image or the sampler, depending on the follow_image
+                // parameter.
+                id = inst->GetSingleWordInOperand(follow_image ? 0 : 1);
+                break;
+            case SpvOpImage:
+                // Follow the sampled image
+                id = inst->GetSingleWordInOperand(0);
+                break;
+            default:
+                // Can't trace further.
+                // Remember it as the answer for the whole path.
+                for (auto iter : visited) {
+                    memo_table[iter] = nullptr;
+                }
+                return nullptr;
+        }
+    }
+}
+
+const spvtools::opt::Instruction* ParserImpl::GetSpirvTypeForHandleMemoryObjectDeclaration(
+    const spvtools::opt::Instruction& var) {
+    if (!success()) {
+        return nullptr;
+    }
+    // The WGSL handle type is determined by looking at information from
+    // several sources:
+    //    - the usage of the handle by image access instructions
+    //    - the SPIR-V type declaration
+    // Each source does not have enough information to completely determine
+    // the result.
+
+    // Messages are phrased in terms of images and samplers because those
+    // are the only SPIR-V handles supported by WGSL.
+
+    // Get the SPIR-V handle type.
+    const auto* ptr_type = def_use_mgr_->GetDef(var.type_id());
+    if (!ptr_type || (ptr_type->opcode() != SpvOpTypePointer)) {
+        Fail() << "Invalid type for variable or function parameter " << var.PrettyPrint();
+        return nullptr;
+    }
+    const auto* raw_handle_type = def_use_mgr_->GetDef(ptr_type->GetSingleWordInOperand(1));
+    if (!raw_handle_type) {
+        Fail() << "Invalid pointer type for variable or function parameter " << var.PrettyPrint();
+        return nullptr;
+    }
+    switch (raw_handle_type->opcode()) {
+        case SpvOpTypeSampler:
+        case SpvOpTypeImage:
+            // The expected cases.
+            break;
+        case SpvOpTypeArray:
+        case SpvOpTypeRuntimeArray:
+            Fail() << "arrays of textures or samplers are not supported in WGSL; can't "
+                      "translate variable or function parameter: "
+                   << var.PrettyPrint();
+            return nullptr;
+        case SpvOpTypeSampledImage:
+            Fail() << "WGSL does not support combined image-samplers: " << var.PrettyPrint();
+            return nullptr;
         default:
-          Fail() << "WGSL arrayed textures must be 2d_array or cube_array: "
-                    "invalid multisampled texture variable "
-                 << namer_.Name(var.result_id()) << ": " << var.PrettyPrint();
-          return nullptr;
-      }
+            Fail() << "invalid type for image or sampler variable or function "
+                      "parameter: "
+                   << var.PrettyPrint();
+            return nullptr;
+    }
+    return raw_handle_type;
+}
+
+const Pointer* ParserImpl::GetTypeForHandleVar(const spvtools::opt::Instruction& var) {
+    auto where = handle_type_.find(&var);
+    if (where != handle_type_.end()) {
+        return where->second;
     }
 
-    const ast::TextureDimension dim =
-        enum_converter_.ToDim(image_type->dim(), image_type->is_arrayed());
-    if (dim == ast::TextureDimension::kNone) {
-      return nullptr;
-    }
-
-    // WGSL textures are always formatted.  Unformatted textures are always
-    // sampled.
-    if (usage.IsSampledTexture() || usage.IsStorageReadTexture() ||
-        (image_type->format() == SpvImageFormatUnknown)) {
-      // Make a sampled texture type.
-      auto* ast_sampled_component_type =
-          ConvertType(raw_handle_type->GetSingleWordInOperand(0));
-
-      // Vulkan ignores the depth parameter on OpImage, so pay attention to the
-      // usage as well.  That is, it's valid for a Vulkan shader to use an
-      // OpImage variable with an OpImage*Dref* instruction.  In WGSL we must
-      // treat that as a depth texture.
-      if (image_type->depth() || usage.IsDepthTexture()) {
-        if (image_type->is_multisampled()) {
-          ast_store_type = ty_.DepthMultisampledTexture(dim);
-        } else {
-          ast_store_type = ty_.DepthTexture(dim);
-        }
-      } else if (image_type->is_multisampled()) {
-        if (dim != ast::TextureDimension::k2d) {
-          Fail() << "WGSL multisampled textures must be 2d and non-arrayed: "
-                    "invalid multisampled texture variable "
-                 << namer_.Name(var.result_id()) << ": " << var.PrettyPrint();
-        }
-        // Multisampled textures are never depth textures.
-        ast_store_type =
-            ty_.MultisampledTexture(dim, ast_sampled_component_type);
-      } else {
-        ast_store_type = ty_.SampledTexture(dim, ast_sampled_component_type);
-      }
-    } else {
-      const auto access = ast::Access::kWrite;
-      const auto format = enum_converter_.ToTexelFormat(image_type->format());
-      if (format == ast::TexelFormat::kNone) {
+    const spvtools::opt::Instruction* raw_handle_type =
+        GetSpirvTypeForHandleMemoryObjectDeclaration(var);
+    if (!raw_handle_type) {
         return nullptr;
-      }
-      ast_store_type = ty_.StorageTexture(dim, format, access);
     }
-  } else {
-    Fail() << "unsupported: UniformConstant variable is not a recognized "
-              "sampler or texture"
-           << var.PrettyPrint();
-    return nullptr;
-  }
 
-  // Form the pointer type.
-  auto* result =
-      ty_.Pointer(ast_store_type, ast::StorageClass::kUniformConstant);
-  // Remember it for later.
-  handle_type_[&var] = result;
-  return result;
+    // The variable could be a sampler or image.
+    // Where possible, determine which one it is from the usage inferred
+    // for the variable.
+    Usage usage = handle_usage_[&var];
+    if (!usage.IsValid()) {
+        Fail() << "Invalid sampler or texture usage for variable " << var.PrettyPrint() << "\n"
+               << usage;
+        return nullptr;
+    }
+    // Infer a handle type, if usage didn't already tell us.
+    if (!usage.IsComplete()) {
+        // In SPIR-V you could statically reference a texture or sampler without
+        // using it in a way that gives us a clue on how to declare it.  Look inside
+        // the store type to infer a usage.
+        if (raw_handle_type->opcode() == SpvOpTypeSampler) {
+            usage.AddSampler();
+        } else {
+            // It's a texture.
+            if (raw_handle_type->NumInOperands() != 7) {
+                Fail() << "invalid SPIR-V image type: expected 7 operands: "
+                       << raw_handle_type->PrettyPrint();
+                return nullptr;
+            }
+            const auto sampled_param = raw_handle_type->GetSingleWordInOperand(5);
+            const auto format_param = raw_handle_type->GetSingleWordInOperand(6);
+            // Only storage images have a format.
+            if ((format_param != SpvImageFormatUnknown) ||
+                sampled_param == 2 /* without sampler */) {
+                // Get NonWritable and NonReadable attributes of the variable.
+                bool is_nonwritable = false;
+                bool is_nonreadable = false;
+                for (const auto& deco : GetDecorationsFor(var.result_id())) {
+                    if (deco.size() != 1) {
+                        continue;
+                    }
+                    if (deco[0] == SpvDecorationNonWritable) {
+                        is_nonwritable = true;
+                    }
+                    if (deco[0] == SpvDecorationNonReadable) {
+                        is_nonreadable = true;
+                    }
+                }
+                if (is_nonwritable && is_nonreadable) {
+                    Fail() << "storage image variable is both NonWritable and NonReadable"
+                           << var.PrettyPrint();
+                }
+                if (!is_nonwritable && !is_nonreadable) {
+                    Fail() << "storage image variable is neither NonWritable nor NonReadable"
+                           << var.PrettyPrint();
+                }
+                // Let's make it one of the storage textures.
+                if (is_nonwritable) {
+                    usage.AddStorageReadTexture();
+                } else {
+                    usage.AddStorageWriteTexture();
+                }
+            } else {
+                usage.AddSampledTexture();
+            }
+        }
+        if (!usage.IsComplete()) {
+            Fail() << "internal error: should have inferred a complete handle type. got "
+                   << usage.to_str();
+            return nullptr;
+        }
+    }
+
+    // Construct the Tint handle type.
+    const Type* ast_store_type = nullptr;
+    if (usage.IsSampler()) {
+        ast_store_type =
+            ty_.Sampler(usage.IsComparisonSampler() ? ast::SamplerKind::kComparisonSampler
+                                                    : ast::SamplerKind::kSampler);
+    } else if (usage.IsTexture()) {
+        const spvtools::opt::analysis::Image* image_type =
+            type_mgr_->GetType(raw_handle_type->result_id())->AsImage();
+        if (!image_type) {
+            Fail() << "internal error: Couldn't look up image type"
+                   << raw_handle_type->PrettyPrint();
+            return nullptr;
+        }
+
+        if (image_type->is_arrayed()) {
+            // Give a nicer error message here, where we have the offending variable
+            // in hand, rather than inside the enum converter.
+            switch (image_type->dim()) {
+                case SpvDim2D:
+                case SpvDimCube:
+                    break;
+                default:
+                    Fail() << "WGSL arrayed textures must be 2d_array or cube_array: "
+                              "invalid multisampled texture variable "
+                           << namer_.Name(var.result_id()) << ": " << var.PrettyPrint();
+                    return nullptr;
+            }
+        }
+
+        const ast::TextureDimension dim =
+            enum_converter_.ToDim(image_type->dim(), image_type->is_arrayed());
+        if (dim == ast::TextureDimension::kNone) {
+            return nullptr;
+        }
+
+        // WGSL textures are always formatted.  Unformatted textures are always
+        // sampled.
+        if (usage.IsSampledTexture() || usage.IsStorageReadTexture() ||
+            (image_type->format() == SpvImageFormatUnknown)) {
+            // Make a sampled texture type.
+            auto* ast_sampled_component_type =
+                ConvertType(raw_handle_type->GetSingleWordInOperand(0));
+
+            // Vulkan ignores the depth parameter on OpImage, so pay attention to the
+            // usage as well.  That is, it's valid for a Vulkan shader to use an
+            // OpImage variable with an OpImage*Dref* instruction.  In WGSL we must
+            // treat that as a depth texture.
+            if (image_type->depth() || usage.IsDepthTexture()) {
+                if (image_type->is_multisampled()) {
+                    ast_store_type = ty_.DepthMultisampledTexture(dim);
+                } else {
+                    ast_store_type = ty_.DepthTexture(dim);
+                }
+            } else if (image_type->is_multisampled()) {
+                if (dim != ast::TextureDimension::k2d) {
+                    Fail() << "WGSL multisampled textures must be 2d and non-arrayed: "
+                              "invalid multisampled texture variable "
+                           << namer_.Name(var.result_id()) << ": " << var.PrettyPrint();
+                }
+                // Multisampled textures are never depth textures.
+                ast_store_type = ty_.MultisampledTexture(dim, ast_sampled_component_type);
+            } else {
+                ast_store_type = ty_.SampledTexture(dim, ast_sampled_component_type);
+            }
+        } else {
+            const auto access = ast::Access::kWrite;
+            const auto format = enum_converter_.ToTexelFormat(image_type->format());
+            if (format == ast::TexelFormat::kNone) {
+                return nullptr;
+            }
+            ast_store_type = ty_.StorageTexture(dim, format, access);
+        }
+    } else {
+        Fail() << "unsupported: UniformConstant variable is not a recognized "
+                  "sampler or texture"
+               << var.PrettyPrint();
+        return nullptr;
+    }
+
+    // Form the pointer type.
+    auto* result = ty_.Pointer(ast_store_type, ast::StorageClass::kHandle);
+    // Remember it for later.
+    handle_type_[&var] = result;
+    return result;
 }
 
 const Type* ParserImpl::GetComponentTypeForFormat(ast::TexelFormat format) {
-  switch (format) {
-    case ast::TexelFormat::kR32Uint:
-    case ast::TexelFormat::kRgba8Uint:
-    case ast::TexelFormat::kRg32Uint:
-    case ast::TexelFormat::kRgba16Uint:
-    case ast::TexelFormat::kRgba32Uint:
-      return ty_.U32();
+    switch (format) {
+        case ast::TexelFormat::kR32Uint:
+        case ast::TexelFormat::kRgba8Uint:
+        case ast::TexelFormat::kRg32Uint:
+        case ast::TexelFormat::kRgba16Uint:
+        case ast::TexelFormat::kRgba32Uint:
+            return ty_.U32();
 
-    case ast::TexelFormat::kR32Sint:
-    case ast::TexelFormat::kRgba8Sint:
-    case ast::TexelFormat::kRg32Sint:
-    case ast::TexelFormat::kRgba16Sint:
-    case ast::TexelFormat::kRgba32Sint:
-      return ty_.I32();
+        case ast::TexelFormat::kR32Sint:
+        case ast::TexelFormat::kRgba8Sint:
+        case ast::TexelFormat::kRg32Sint:
+        case ast::TexelFormat::kRgba16Sint:
+        case ast::TexelFormat::kRgba32Sint:
+            return ty_.I32();
 
-    case ast::TexelFormat::kRgba8Unorm:
-    case ast::TexelFormat::kRgba8Snorm:
-    case ast::TexelFormat::kR32Float:
-    case ast::TexelFormat::kRg32Float:
-    case ast::TexelFormat::kRgba16Float:
-    case ast::TexelFormat::kRgba32Float:
-      return ty_.F32();
-    default:
-      break;
-  }
-  Fail() << "unknown format " << int(format);
-  return nullptr;
+        case ast::TexelFormat::kRgba8Unorm:
+        case ast::TexelFormat::kRgba8Snorm:
+        case ast::TexelFormat::kR32Float:
+        case ast::TexelFormat::kRg32Float:
+        case ast::TexelFormat::kRgba16Float:
+        case ast::TexelFormat::kRgba32Float:
+            return ty_.F32();
+        default:
+            break;
+    }
+    Fail() << "unknown format " << int(format);
+    return nullptr;
 }
 
 unsigned ParserImpl::GetChannelCountForFormat(ast::TexelFormat format) {
-  switch (format) {
-    case ast::TexelFormat::kR32Float:
-    case ast::TexelFormat::kR32Sint:
-    case ast::TexelFormat::kR32Uint:
-      // One channel
-      return 1;
+    switch (format) {
+        case ast::TexelFormat::kR32Float:
+        case ast::TexelFormat::kR32Sint:
+        case ast::TexelFormat::kR32Uint:
+            // One channel
+            return 1;
 
-    case ast::TexelFormat::kRg32Float:
-    case ast::TexelFormat::kRg32Sint:
-    case ast::TexelFormat::kRg32Uint:
-      // Two channels
-      return 2;
+        case ast::TexelFormat::kRg32Float:
+        case ast::TexelFormat::kRg32Sint:
+        case ast::TexelFormat::kRg32Uint:
+            // Two channels
+            return 2;
 
-    case ast::TexelFormat::kRgba16Float:
-    case ast::TexelFormat::kRgba16Sint:
-    case ast::TexelFormat::kRgba16Uint:
-    case ast::TexelFormat::kRgba32Float:
-    case ast::TexelFormat::kRgba32Sint:
-    case ast::TexelFormat::kRgba32Uint:
-    case ast::TexelFormat::kRgba8Sint:
-    case ast::TexelFormat::kRgba8Snorm:
-    case ast::TexelFormat::kRgba8Uint:
-    case ast::TexelFormat::kRgba8Unorm:
-      // Four channels
-      return 4;
+        case ast::TexelFormat::kRgba16Float:
+        case ast::TexelFormat::kRgba16Sint:
+        case ast::TexelFormat::kRgba16Uint:
+        case ast::TexelFormat::kRgba32Float:
+        case ast::TexelFormat::kRgba32Sint:
+        case ast::TexelFormat::kRgba32Uint:
+        case ast::TexelFormat::kRgba8Sint:
+        case ast::TexelFormat::kRgba8Snorm:
+        case ast::TexelFormat::kRgba8Uint:
+        case ast::TexelFormat::kRgba8Unorm:
+            // Four channels
+            return 4;
 
-    default:
-      break;
-  }
-  Fail() << "unknown format " << int(format);
-  return 0;
+        default:
+            break;
+    }
+    Fail() << "unknown format " << int(format);
+    return 0;
 }
 
 const Type* ParserImpl::GetTexelTypeForFormat(ast::TexelFormat format) {
-  const auto* component_type = GetComponentTypeForFormat(format);
-  if (!component_type) {
-    return nullptr;
-  }
-  return ty_.Vector(component_type, 4);
+    const auto* component_type = GetComponentTypeForFormat(format);
+    if (!component_type) {
+        return nullptr;
+    }
+    return ty_.Vector(component_type, 4);
 }
 
 bool ParserImpl::RegisterHandleUsage() {
-  if (!success_) {
-    return false;
-  }
-
-  // Map a function ID to the list of its function parameter instructions, in
-  // order.
-  std::unordered_map<uint32_t, std::vector<const spvtools::opt::Instruction*>>
-      function_params;
-  for (const auto* f : topologically_ordered_functions_) {
-    // Record the instructions defining this function's parameters.
-    auto& params = function_params[f->result_id()];
-    f->ForEachParam([&params](const spvtools::opt::Instruction* param) {
-      params.push_back(param);
-    });
-  }
-
-  // Returns the memory object declaration for an image underlying the first
-  // operand of the given image instruction.
-  auto get_image = [this](const spvtools::opt::Instruction& image_inst) {
-    return this->GetMemoryObjectDeclarationForHandle(
-        image_inst.GetSingleWordInOperand(0), true);
-  };
-  // Returns the memory object declaration for a sampler underlying the first
-  // operand of the given image instruction.
-  auto get_sampler = [this](const spvtools::opt::Instruction& image_inst) {
-    return this->GetMemoryObjectDeclarationForHandle(
-        image_inst.GetSingleWordInOperand(0), false);
-  };
-
-  // Scan the bodies of functions for image operations, recording their implied
-  // usage properties on the memory object declarations (i.e. variables or
-  // function parameters).  We scan the functions in an order so that callees
-  // precede callers. That way the usage on a function parameter is already
-  // computed before we see the call to that function.  So when we reach
-  // a function call, we can add the usage from the callee formal parameters.
-  for (const auto* f : topologically_ordered_functions_) {
-    for (const auto& bb : *f) {
-      for (const auto& inst : bb) {
-        switch (inst.opcode()) {
-            // Single texel reads and writes
-
-          case SpvOpImageRead:
-            handle_usage_[get_image(inst)].AddStorageReadTexture();
-            break;
-          case SpvOpImageWrite:
-            handle_usage_[get_image(inst)].AddStorageWriteTexture();
-            break;
-          case SpvOpImageFetch:
-            handle_usage_[get_image(inst)].AddSampledTexture();
-            break;
-
-            // Sampling and gathering from a sampled image.
-
-          case SpvOpImageSampleImplicitLod:
-          case SpvOpImageSampleExplicitLod:
-          case SpvOpImageSampleProjImplicitLod:
-          case SpvOpImageSampleProjExplicitLod:
-          case SpvOpImageGather:
-            handle_usage_[get_image(inst)].AddSampledTexture();
-            handle_usage_[get_sampler(inst)].AddSampler();
-            break;
-          case SpvOpImageSampleDrefImplicitLod:
-          case SpvOpImageSampleDrefExplicitLod:
-          case SpvOpImageSampleProjDrefImplicitLod:
-          case SpvOpImageSampleProjDrefExplicitLod:
-          case SpvOpImageDrefGather:
-            // Depth reference access implies usage as a depth texture, which
-            // in turn is a sampled texture.
-            handle_usage_[get_image(inst)].AddDepthTexture();
-            handle_usage_[get_sampler(inst)].AddComparisonSampler();
-            break;
-
-            // Image queries
-
-          case SpvOpImageQuerySizeLod:
-            // Vulkan requires Sampled=1 for this. SPIR-V already requires MS=0.
-            handle_usage_[get_image(inst)].AddSampledTexture();
-            break;
-          case SpvOpImageQuerySize:
-            // Applies to either MS=1 or Sampled=0 or 2.
-            // So we can't force it to be multisampled, or storage image.
-            break;
-          case SpvOpImageQueryLod:
-            handle_usage_[get_image(inst)].AddSampledTexture();
-            handle_usage_[get_sampler(inst)].AddSampler();
-            break;
-          case SpvOpImageQueryLevels:
-            // We can't tell anything more than that it's an image.
-            handle_usage_[get_image(inst)].AddTexture();
-            break;
-          case SpvOpImageQuerySamples:
-            handle_usage_[get_image(inst)].AddMultisampledTexture();
-            break;
-
-            // Function calls
-
-          case SpvOpFunctionCall: {
-            // Propagate handle usages from callee function formal parameters to
-            // the matching caller parameters.  This is where we rely on the
-            // fact that callees have been processed earlier in the flow.
-            const auto num_in_operands = inst.NumInOperands();
-            // The first operand of the call is the function ID.
-            // The remaining operands are the operands to the function.
-            if (num_in_operands < 1) {
-              return Fail() << "Call instruction must have at least one operand"
-                            << inst.PrettyPrint();
-            }
-            const auto function_id = inst.GetSingleWordInOperand(0);
-            const auto& formal_params = function_params[function_id];
-            if (formal_params.size() != (num_in_operands - 1)) {
-              return Fail() << "Called function has " << formal_params.size()
-                            << " parameters, but function call has "
-                            << (num_in_operands - 1) << " parameters"
-                            << inst.PrettyPrint();
-            }
-            for (uint32_t i = 1; i < num_in_operands; ++i) {
-              auto where = handle_usage_.find(formal_params[i - 1]);
-              if (where == handle_usage_.end()) {
-                // We haven't recorded any handle usage on the formal parameter.
-                continue;
-              }
-              const Usage& formal_param_usage = where->second;
-              const auto operand_id = inst.GetSingleWordInOperand(i);
-              const auto* operand_as_sampler =
-                  GetMemoryObjectDeclarationForHandle(operand_id, false);
-              const auto* operand_as_image =
-                  GetMemoryObjectDeclarationForHandle(operand_id, true);
-              if (operand_as_sampler) {
-                handle_usage_[operand_as_sampler].Add(formal_param_usage);
-              }
-              if (operand_as_image &&
-                  (operand_as_image != operand_as_sampler)) {
-                handle_usage_[operand_as_image].Add(formal_param_usage);
-              }
-            }
-            break;
-          }
-
-          default:
-            break;
-        }
-      }
+    if (!success_) {
+        return false;
     }
-  }
-  return success_;
+
+    // Map a function ID to the list of its function parameter instructions, in
+    // order.
+    std::unordered_map<uint32_t, std::vector<const spvtools::opt::Instruction*>> function_params;
+    for (const auto* f : topologically_ordered_functions_) {
+        // Record the instructions defining this function's parameters.
+        auto& params = function_params[f->result_id()];
+        f->ForEachParam(
+            [&params](const spvtools::opt::Instruction* param) { params.push_back(param); });
+    }
+
+    // Returns the memory object declaration for an image underlying the first
+    // operand of the given image instruction.
+    auto get_image = [this](const spvtools::opt::Instruction& image_inst) {
+        return this->GetMemoryObjectDeclarationForHandle(image_inst.GetSingleWordInOperand(0),
+                                                         true);
+    };
+    // Returns the memory object declaration for a sampler underlying the first
+    // operand of the given image instruction.
+    auto get_sampler = [this](const spvtools::opt::Instruction& image_inst) {
+        return this->GetMemoryObjectDeclarationForHandle(image_inst.GetSingleWordInOperand(0),
+                                                         false);
+    };
+
+    // Scan the bodies of functions for image operations, recording their implied
+    // usage properties on the memory object declarations (i.e. variables or
+    // function parameters).  We scan the functions in an order so that callees
+    // precede callers. That way the usage on a function parameter is already
+    // computed before we see the call to that function.  So when we reach
+    // a function call, we can add the usage from the callee formal parameters.
+    for (const auto* f : topologically_ordered_functions_) {
+        for (const auto& bb : *f) {
+            for (const auto& inst : bb) {
+                switch (inst.opcode()) {
+                        // Single texel reads and writes
+
+                    case SpvOpImageRead:
+                        handle_usage_[get_image(inst)].AddStorageReadTexture();
+                        break;
+                    case SpvOpImageWrite:
+                        handle_usage_[get_image(inst)].AddStorageWriteTexture();
+                        break;
+                    case SpvOpImageFetch:
+                        handle_usage_[get_image(inst)].AddSampledTexture();
+                        break;
+
+                        // Sampling and gathering from a sampled image.
+
+                    case SpvOpImageSampleImplicitLod:
+                    case SpvOpImageSampleExplicitLod:
+                    case SpvOpImageSampleProjImplicitLod:
+                    case SpvOpImageSampleProjExplicitLod:
+                    case SpvOpImageGather:
+                        handle_usage_[get_image(inst)].AddSampledTexture();
+                        handle_usage_[get_sampler(inst)].AddSampler();
+                        break;
+                    case SpvOpImageSampleDrefImplicitLod:
+                    case SpvOpImageSampleDrefExplicitLod:
+                    case SpvOpImageSampleProjDrefImplicitLod:
+                    case SpvOpImageSampleProjDrefExplicitLod:
+                    case SpvOpImageDrefGather:
+                        // Depth reference access implies usage as a depth texture, which
+                        // in turn is a sampled texture.
+                        handle_usage_[get_image(inst)].AddDepthTexture();
+                        handle_usage_[get_sampler(inst)].AddComparisonSampler();
+                        break;
+
+                        // Image queries
+
+                    case SpvOpImageQuerySizeLod:
+                        // Vulkan requires Sampled=1 for this. SPIR-V already requires MS=0.
+                        handle_usage_[get_image(inst)].AddSampledTexture();
+                        break;
+                    case SpvOpImageQuerySize:
+                        // Applies to either MS=1 or Sampled=0 or 2.
+                        // So we can't force it to be multisampled, or storage image.
+                        break;
+                    case SpvOpImageQueryLod:
+                        handle_usage_[get_image(inst)].AddSampledTexture();
+                        handle_usage_[get_sampler(inst)].AddSampler();
+                        break;
+                    case SpvOpImageQueryLevels:
+                        // We can't tell anything more than that it's an image.
+                        handle_usage_[get_image(inst)].AddTexture();
+                        break;
+                    case SpvOpImageQuerySamples:
+                        handle_usage_[get_image(inst)].AddMultisampledTexture();
+                        break;
+
+                        // Function calls
+
+                    case SpvOpFunctionCall: {
+                        // Propagate handle usages from callee function formal parameters to
+                        // the matching caller parameters.  This is where we rely on the
+                        // fact that callees have been processed earlier in the flow.
+                        const auto num_in_operands = inst.NumInOperands();
+                        // The first operand of the call is the function ID.
+                        // The remaining operands are the operands to the function.
+                        if (num_in_operands < 1) {
+                            return Fail() << "Call instruction must have at least one operand"
+                                          << inst.PrettyPrint();
+                        }
+                        const auto function_id = inst.GetSingleWordInOperand(0);
+                        const auto& formal_params = function_params[function_id];
+                        if (formal_params.size() != (num_in_operands - 1)) {
+                            return Fail()
+                                   << "Called function has " << formal_params.size()
+                                   << " parameters, but function call has " << (num_in_operands - 1)
+                                   << " parameters" << inst.PrettyPrint();
+                        }
+                        for (uint32_t i = 1; i < num_in_operands; ++i) {
+                            auto where = handle_usage_.find(formal_params[i - 1]);
+                            if (where == handle_usage_.end()) {
+                                // We haven't recorded any handle usage on the formal parameter.
+                                continue;
+                            }
+                            const Usage& formal_param_usage = where->second;
+                            const auto operand_id = inst.GetSingleWordInOperand(i);
+                            const auto* operand_as_sampler =
+                                GetMemoryObjectDeclarationForHandle(operand_id, false);
+                            const auto* operand_as_image =
+                                GetMemoryObjectDeclarationForHandle(operand_id, true);
+                            if (operand_as_sampler) {
+                                handle_usage_[operand_as_sampler].Add(formal_param_usage);
+                            }
+                            if (operand_as_image && (operand_as_image != operand_as_sampler)) {
+                                handle_usage_[operand_as_image].Add(formal_param_usage);
+                            }
+                        }
+                        break;
+                    }
+
+                    default:
+                        break;
+                }
+            }
+        }
+    }
+    return success_;
 }
 
 Usage ParserImpl::GetHandleUsage(uint32_t id) const {
-  const auto where = handle_usage_.find(def_use_mgr_->GetDef(id));
-  if (where != handle_usage_.end()) {
-    return where->second;
-  }
-  return Usage();
+    const auto where = handle_usage_.find(def_use_mgr_->GetDef(id));
+    if (where != handle_usage_.end()) {
+        return where->second;
+    }
+    return Usage();
 }
 
-const spvtools::opt::Instruction* ParserImpl::GetInstructionForTest(
-    uint32_t id) const {
-  return def_use_mgr_ ? def_use_mgr_->GetDef(id) : nullptr;
+const spvtools::opt::Instruction* ParserImpl::GetInstructionForTest(uint32_t id) const {
+    return def_use_mgr_ ? def_use_mgr_->GetDef(id) : nullptr;
 }
 
-std::string ParserImpl::GetMemberName(const Struct& struct_type,
-                                      int member_index) {
-  auto where = struct_id_for_symbol_.find(struct_type.name);
-  if (where == struct_id_for_symbol_.end()) {
-    Fail() << "no structure type registered for symbol";
-    return "";
-  }
-  return namer_.GetMemberName(where->second, member_index);
+std::string ParserImpl::GetMemberName(const Struct& struct_type, int member_index) {
+    auto where = struct_id_for_symbol_.find(struct_type.name);
+    if (where == struct_id_for_symbol_.end()) {
+        Fail() << "no structure type registered for symbol";
+        return "";
+    }
+    return namer_.GetMemberName(where->second, member_index);
 }
 
 WorkgroupSizeInfo::WorkgroupSizeInfo() = default;
diff --git a/src/tint/reader/spirv/parser_impl.h b/src/tint/reader/spirv/parser_impl.h
index 96fe99c..b91f192 100644
--- a/src/tint/reader/spirv/parser_impl.h
+++ b/src/tint/reader/spirv/parser_impl.h
@@ -64,821 +64,798 @@
 
 /// An AST expression with its type.
 struct TypedExpression {
-  /// Constructor
-  TypedExpression();
+    /// Constructor
+    TypedExpression();
 
-  /// Copy constructor
-  TypedExpression(const TypedExpression&);
+    /// Copy constructor
+    TypedExpression(const TypedExpression&);
 
-  /// Constructor
-  /// @param type_in the type of the expression
-  /// @param expr_in the expression
-  TypedExpression(const Type* type_in, const ast::Expression* expr_in);
+    /// Constructor
+    /// @param type_in the type of the expression
+    /// @param expr_in the expression
+    TypedExpression(const Type* type_in, const ast::Expression* expr_in);
 
-  /// Assignment operator
-  /// @returns this TypedExpression
-  TypedExpression& operator=(const TypedExpression&);
+    /// Assignment operator
+    /// @returns this TypedExpression
+    TypedExpression& operator=(const TypedExpression&);
 
-  /// @returns true if both type and expr are not nullptr
-  operator bool() const { return type && expr; }
+    /// @returns true if both type and expr are not nullptr
+    operator bool() const { return type && expr; }
 
-  /// The type
-  const Type* type = nullptr;
-  /// The expression
-  const ast::Expression* expr = nullptr;
+    /// The type
+    const Type* type = nullptr;
+    /// The expression
+    const ast::Expression* expr = nullptr;
 };
 
 /// Info about the WorkgroupSize builtin.
 struct WorkgroupSizeInfo {
-  /// Constructor
-  WorkgroupSizeInfo();
-  /// Destructor
-  ~WorkgroupSizeInfo();
-  /// The SPIR-V ID of the WorkgroupSize builtin, if any.
-  uint32_t id = 0u;
-  /// The SPIR-V type ID of the WorkgroupSize builtin, if any.
-  uint32_t type_id = 0u;
-  /// The SPIR-V type IDs of the x, y, and z components.
-  uint32_t component_type_id = 0u;
-  /// The SPIR-V IDs of the X, Y, and Z components of the workgroup size
-  /// builtin.
-  uint32_t x_id = 0u;  /// X component ID
-  uint32_t y_id = 0u;  /// Y component ID
-  uint32_t z_id = 0u;  /// Z component ID
-  /// The effective workgroup size, if this is a compute shader.
-  uint32_t x_value = 0u;  /// X workgroup size
-  uint32_t y_value = 0u;  /// Y workgroup size
-  uint32_t z_value = 0u;  /// Z workgroup size
+    /// Constructor
+    WorkgroupSizeInfo();
+    /// Destructor
+    ~WorkgroupSizeInfo();
+    /// The SPIR-V ID of the WorkgroupSize builtin, if any.
+    uint32_t id = 0u;
+    /// The SPIR-V type ID of the WorkgroupSize builtin, if any.
+    uint32_t type_id = 0u;
+    /// The SPIR-V type IDs of the x, y, and z components.
+    uint32_t component_type_id = 0u;
+    /// The SPIR-V IDs of the X, Y, and Z components of the workgroup size
+    /// builtin.
+    uint32_t x_id = 0u;  /// X component ID
+    uint32_t y_id = 0u;  /// Y component ID
+    uint32_t z_id = 0u;  /// Z component ID
+    /// The effective workgroup size, if this is a compute shader.
+    uint32_t x_value = 0u;  /// X workgroup size
+    uint32_t y_value = 0u;  /// Y workgroup size
+    uint32_t z_value = 0u;  /// Z workgroup size
 };
 
 /// Parser implementation for SPIR-V.
 class ParserImpl : Reader {
- public:
-  /// Creates a new parser
-  /// @param input the input data to parse
-  explicit ParserImpl(const std::vector<uint32_t>& input);
-  /// Destructor
-  ~ParserImpl() override;
+  public:
+    /// Creates a new parser
+    /// @param input the input data to parse
+    explicit ParserImpl(const std::vector<uint32_t>& input);
+    /// Destructor
+    ~ParserImpl() override;
 
-  /// Run the parser
-  /// @returns true if the parse was successful, false otherwise.
-  bool Parse() override;
+    /// Run the parser
+    /// @returns true if the parse was successful, false otherwise.
+    bool Parse() override;
 
-  /// @returns the program. The program builder in the parser will be reset
-  /// after this.
-  Program program() override;
+    /// @returns the program. The program builder in the parser will be reset
+    /// after this.
+    Program program() override;
 
-  /// @returns a reference to the internal builder, without building the
-  /// program. To be used only for testing.
-  ProgramBuilder& builder() { return builder_; }
+    /// @returns a reference to the internal builder, without building the
+    /// program. To be used only for testing.
+    ProgramBuilder& builder() { return builder_; }
 
-  /// @returns the type manager
-  TypeManager& type_manager() { return ty_; }
+    /// @returns the type manager
+    TypeManager& type_manager() { return ty_; }
 
-  /// Logs failure, ands return a failure stream to accumulate diagnostic
-  /// messages. By convention, a failure should only be logged along with
-  /// a non-empty string diagnostic.
-  /// @returns the failure stream
-  FailStream& Fail() {
-    success_ = false;
-    return fail_stream_;
-  }
-
-  /// @return true if failure has not yet occurred
-  bool success() const { return success_; }
-
-  /// @returns the accumulated error string
-  const std::string error() { return errors_.str(); }
-
-  /// Builds an internal representation of the SPIR-V binary,
-  /// and parses it into a Tint AST module.  Diagnostics are emitted
-  /// to the error stream.
-  /// @returns true if it was successful.
-  bool BuildAndParseInternalModule() {
-    return BuildInternalModule() && ParseInternalModule();
-  }
-  /// Builds an internal representation of the SPIR-V binary,
-  /// and parses the module, except functions, into a Tint AST module.
-  /// Diagnostics are emitted to the error stream.
-  /// @returns true if it was successful.
-  bool BuildAndParseInternalModuleExceptFunctions() {
-    return BuildInternalModule() && ParseInternalModuleExceptFunctions();
-  }
-
-  /// @returns the set of SPIR-V IDs for imports of the "GLSL.std.450"
-  /// extended instruction set.
-  const std::unordered_set<uint32_t>& glsl_std_450_imports() const {
-    return glsl_std_450_imports_;
-  }
-
-  /// Desired handling of SPIR-V pointers by ConvertType()
-  enum class PtrAs {
-    // SPIR-V pointer is converted to a spirv::Pointer
-    Ptr,
-    // SPIR-V pointer is converted to a spirv::Reference
-    Ref
-  };
-
-  /// Converts a SPIR-V type to a Tint type, and saves it for fast lookup.
-  /// If the type is only used for builtins, then register that specially,
-  /// and return null.  If the type is a sampler, image, or sampled image, then
-  /// return the Void type, because those opaque types are handled in a
-  /// different way.
-  /// On failure, logs an error and returns null.  This should only be called
-  /// after the internal representation of the module has been built.
-  /// @param type_id the SPIR-V ID of a type.
-  /// @param ptr_as if the SPIR-V type is a pointer and ptr_as is equal to
-  /// PtrAs::Ref then a Reference will be returned, otherwise a Pointer will be
-  /// returned for a SPIR-V pointer
-  /// @returns a Tint type, or nullptr
-  const Type* ConvertType(uint32_t type_id, PtrAs ptr_as = PtrAs::Ptr);
-
-  /// Emits an alias type declaration for array or runtime-sized array type,
-  /// when needed to distinguish between differently-decorated underlying types.
-  /// Updates the mapping of the SPIR-V type ID to the alias type.
-  /// This is a no-op if the parser has already failed.
-  /// @param type_id the SPIR-V ID for the type
-  /// @param type the type that might get an alias
-  /// @param ast_type the ast type that might get an alias
-  /// @returns an alias type or `ast_type` if no alias was created
-  const Type* MaybeGenerateAlias(uint32_t type_id,
-                                 const spvtools::opt::analysis::Type* type,
-                                 const Type* ast_type);
-
-  /// Adds `decl` as a declared type if it hasn't been added yet.
-  /// @param name the type's unique name
-  /// @param decl the type declaration to add
-  void AddTypeDecl(Symbol name, const ast::TypeDecl* decl);
-
-  /// @returns the fail stream object
-  FailStream& fail_stream() { return fail_stream_; }
-  /// @returns the namer object
-  Namer& namer() { return namer_; }
-  /// @returns a borrowed pointer to the internal representation of the module.
-  /// This is null until BuildInternalModule has been called.
-  spvtools::opt::IRContext* ir_context() { return ir_context_.get(); }
-
-  /// Gets the list of unique decorations for a SPIR-V result ID.  Returns an
-  /// empty vector if the ID is not a result ID, or if no decorations target
-  /// that ID. The internal representation must have already been built.
-  /// Ignores decorations that have no effect in graphics APIs, e.g. Restrict
-  /// and RestrictPointer.
-  /// @param id SPIR-V ID
-  /// @returns the list of decorations on the given ID
-  DecorationList GetDecorationsFor(uint32_t id) const;
-  /// Gets the list of unique decorations for the member of a struct.  Returns
-  /// an empty list if the `id` is not the ID of a struct, or if the member
-  /// index is out of range, or if the target member has no decorations. The
-  /// internal representation must have already been built.
-  /// Ignores decorations that have no effect in graphics APIs, e.g. Restrict
-  /// and RestrictPointer.
-  /// @param id SPIR-V ID of a struct
-  /// @param member_index the member within the struct
-  /// @returns the list of decorations on the member
-  DecorationList GetDecorationsForMember(uint32_t id,
-                                         uint32_t member_index) const;
-
-  /// Converts SPIR-V decorations for the variable with the given ID.
-  /// Registers the IDs of variables that require special handling by code
-  /// generation.  If the WGSL type differs from the store type for SPIR-V,
-  /// then the `type` parameter is updated.  Returns false on failure (with
-  /// a diagnostic), or when the variable should not be emitted, e.g. for a
-  /// PointSize builtin.
-  /// @param id the ID of the SPIR-V variable
-  /// @param store_type the WGSL store type for the variable, which should be
-  /// prepopulatd
-  /// @param attributes the attribute list to populate
-  /// @param transfer_pipeline_io true if pipeline IO decorations (builtins,
-  /// or locations) will update the store type and the decorations list
-  /// @returns false when the variable should not be emitted as a variable
-  bool ConvertDecorationsForVariable(uint32_t id,
-                                     const Type** store_type,
-                                     ast::AttributeList* attributes,
-                                     bool transfer_pipeline_io);
-
-  /// Converts SPIR-V decorations for pipeline IO into AST decorations.
-  /// @param store_type the store type for the variable or member
-  /// @param decorations the SPIR-V interpolation decorations
-  /// @param attributes the attribute list to populate.
-  /// @returns false if conversion fails
-  bool ConvertPipelineDecorations(const Type* store_type,
-                                  const DecorationList& decorations,
-                                  ast::AttributeList* attributes);
-
-  /// Updates the attribute list, placing a non-null location decoration into
-  /// the list, replacing an existing one if it exists. Does nothing if the
-  /// replacement is nullptr.
-  /// Assumes the list contains at most one Location decoration.
-  /// @param decos the attribute list to modify
-  /// @param replacement the location decoration to place into the list
-  /// @returns the location decoration that was replaced, if one was replaced,
-  /// or null otherwise.
-  const ast::Attribute* SetLocation(ast::AttributeList* decos,
-                                    const ast::Attribute* replacement);
-
-  /// Converts a SPIR-V struct member decoration into a number of AST
-  /// decorations. If the decoration is recognized but deliberately dropped,
-  /// then returns an empty list without a diagnostic. On failure, emits a
-  /// diagnostic and returns an empty list.
-  /// @param struct_type_id the ID of the struct type
-  /// @param member_index the index of the member
-  /// @param member_ty the type of the member
-  /// @param decoration an encoded SPIR-V Decoration
-  /// @returns the AST decorations
-  ast::AttributeList ConvertMemberDecoration(uint32_t struct_type_id,
-                                             uint32_t member_index,
-                                             const Type* member_ty,
-                                             const Decoration& decoration);
-
-  /// Returns a string for the given type.  If the type ID is invalid,
-  /// then the resulting string only names the type ID.
-  /// @param type_id the SPIR-V ID for the type
-  /// @returns a string description of the type.
-  std::string ShowType(uint32_t type_id);
-
-  /// Builds the internal representation of the SPIR-V module.
-  /// Assumes the module is somewhat well-formed.  Normally you
-  /// would want to validate the SPIR-V module before attempting
-  /// to build this internal representation. Also computes a topological
-  /// ordering of the functions.
-  /// This is a no-op if the parser has already failed.
-  /// @returns true if the parser is still successful.
-  bool BuildInternalModule();
-
-  /// Walks the internal representation of the module to populate
-  /// the AST form of the module.
-  /// This is a no-op if the parser has already failed.
-  /// @returns true if the parser is still successful.
-  bool ParseInternalModule();
-
-  /// Records line numbers for each instruction.
-  void RegisterLineNumbers();
-
-  /// Walks the internal representation of the module, except for function
-  /// definitions, to populate the AST form of the module.
-  /// This is a no-op if the parser has already failed.
-  /// @returns true if the parser is still successful.
-  bool ParseInternalModuleExceptFunctions();
-
-  /// Destroys the internal representation of the SPIR-V module.
-  void ResetInternalModule();
-
-  /// Registers extended instruction imports.  Only "GLSL.std.450" is supported.
-  /// This is a no-op if the parser has already failed.
-  /// @returns true if parser is still successful.
-  bool RegisterExtendedInstructionImports();
-
-  /// Returns true when the given instruction is an extended instruction
-  /// for GLSL.std.450.
-  /// @param inst a SPIR-V instruction
-  /// @returns true if its an SpvOpExtInst for GLSL.std.450
-  bool IsGlslExtendedInstruction(const spvtools::opt::Instruction& inst) const;
-
-  /// Returns true when the given instruction is an extended instruction
-  /// from an ignored extended instruction set.
-  /// @param inst a SPIR-V instruction
-  /// @returns true if its an SpvOpExtInst for an ignored extended instruction
-  bool IsIgnoredExtendedInstruction(
-      const spvtools::opt::Instruction& inst) const;
-
-  /// Registers user names for SPIR-V objects, from OpName, and OpMemberName.
-  /// Also synthesizes struct field names.  Ensures uniqueness for names for
-  /// SPIR-V IDs, and uniqueness of names of fields within any single struct.
-  /// This is a no-op if the parser has already failed.
-  /// @returns true if parser is still successful.
-  bool RegisterUserAndStructMemberNames();
-
-  /// Register the WorkgroupSize builtin and its associated constant value.
-  /// @returns true if parser is still successful.
-  bool RegisterWorkgroupSizeBuiltin();
-
-  /// @returns the workgroup size builtin
-  const WorkgroupSizeInfo& workgroup_size_builtin() {
-    return workgroup_size_builtin_;
-  }
-
-  /// Register entry point information.
-  /// This is a no-op if the parser has already failed.
-  /// @returns true if parser is still successful.
-  bool RegisterEntryPoints();
-
-  /// Register Tint AST types for SPIR-V types, including type aliases as
-  /// needed.  This is a no-op if the parser has already failed.
-  /// @returns true if parser is still successful.
-  bool RegisterTypes();
-
-  /// Fail if there are any module-scope pointer values other than those
-  /// declared by OpVariable.
-  /// @returns true if parser is still successful.
-  bool RejectInvalidPointerRoots();
-
-  /// Register sampler and texture usage for memory object declarations.
-  /// This must be called after we've registered line numbers for all
-  /// instructions. This is a no-op if the parser has already failed.
-  /// @returns true if parser is still successful.
-  bool RegisterHandleUsage();
-
-  /// Emit const definitions for scalar specialization constants generated
-  /// by one of OpConstantTrue, OpConstantFalse, or OpSpecConstant.
-  /// This is a no-op if the parser has already failed.
-  /// @returns true if parser is still successful.
-  bool EmitScalarSpecConstants();
-
-  /// Emits module-scope variables.
-  /// This is a no-op if the parser has already failed.
-  /// @returns true if parser is still successful.
-  bool EmitModuleScopeVariables();
-
-  /// Emits functions, with callees preceding their callers.
-  /// This is a no-op if the parser has already failed.
-  /// @returns true if parser is still successful.
-  bool EmitFunctions();
-
-  /// Emits a single function, if it has a body.
-  /// This is a no-op if the parser has already failed.
-  /// @param f the function to emit
-  /// @returns true if parser is still successful.
-  bool EmitFunction(const spvtools::opt::Function& f);
-
-  /// Returns the integer constant for the array size of the given variable.
-  /// @param var_id SPIR-V ID for an array variable
-  /// @returns the integer constant for its array size, or nullptr.
-  const spvtools::opt::analysis::IntConstant* GetArraySize(uint32_t var_id);
-
-  /// Returns the member name for the struct member.
-  /// @param struct_type the parser's structure type.
-  /// @param member_index the member index
-  /// @returns the field name
-  std::string GetMemberName(const Struct& struct_type, int member_index);
-
-  /// Returns the SPIR-V decorations for pipeline IO, if any, on a struct
-  /// member.
-  /// @param struct_type the parser's structure type.
-  /// @param member_index the member index
-  /// @returns a list of SPIR-V decorations.
-  DecorationList GetMemberPipelineDecorations(const Struct& struct_type,
-                                              int member_index);
-
-  /// Creates an AST Variable node for a SPIR-V ID, including any attached
-  /// decorations, unless it's an ignorable builtin variable.
-  /// @param id the SPIR-V result ID
-  /// @param sc the storage class, which cannot be ast::StorageClass::kNone
-  /// @param storage_type the storage type of the variable
-  /// @param is_const if true, the variable is const
-  /// @param is_overridable if true, the variable is pipeline-overridable
-  /// @param constructor the variable constructor
-  /// @param decorations the variable decorations
-  /// @returns a new Variable node, or null in the ignorable variable case and
-  /// in the error case
-  ast::Variable* MakeVariable(uint32_t id,
-                              ast::StorageClass sc,
-                              const Type* storage_type,
-                              bool is_const,
-                              bool is_overridable,
-                              const ast::Expression* constructor,
-                              ast::AttributeList decorations);
-
-  /// Returns true if a constant expression can be generated.
-  /// @param id the SPIR-V ID of the value
-  /// @returns true if a constant expression can be generated
-  bool CanMakeConstantExpression(uint32_t id);
-
-  /// Creates an AST expression node for a SPIR-V ID.  This is valid to call
-  /// when `CanMakeConstantExpression` returns true.
-  /// @param id the SPIR-V ID of the constant
-  /// @returns a new expression
-  TypedExpression MakeConstantExpression(uint32_t id);
-
-  /// Creates an AST expression node for a scalar SPIR-V constant.
-  /// @param source the source location
-  /// @param ast_type the AST type for the value
-  /// @param spirv_const the internal representation of the SPIR-V constant.
-  /// @returns a new expression
-  TypedExpression MakeConstantExpressionForScalarSpirvConstant(
-      Source source,
-      const Type* ast_type,
-      const spvtools::opt::analysis::Constant* spirv_const);
-
-  /// Creates an AST expression node for the null value for the given type.
-  /// @param type the AST type
-  /// @returns a new expression
-  const ast::Expression* MakeNullValue(const Type* type);
-
-  /// Make a typed expression for the null value for the given type.
-  /// @param type the AST type
-  /// @returns a new typed expression
-  TypedExpression MakeNullExpression(const Type* type);
-
-  /// Converts a given expression to the signedness demanded for an operand
-  /// of the given SPIR-V instruction, if required.  If the instruction assumes
-  /// signed integer operands, and `expr` is unsigned, then return an
-  /// as-cast expression converting it to signed. Otherwise, return
-  /// `expr` itself.  Similarly, convert as required from unsigned
-  /// to signed. Assumes all SPIR-V types have been mapped to AST types.
-  /// @param inst the SPIR-V instruction
-  /// @param expr an expression
-  /// @returns expr, or a cast of expr
-  TypedExpression RectifyOperandSignedness(
-      const spvtools::opt::Instruction& inst,
-      TypedExpression&& expr);
-
-  /// Converts a second operand to the signedness of the first operand
-  /// of a binary operator, if the WGSL operator requires they be the same.
-  /// Returns the converted expression, or the original expression if the
-  /// conversion is not needed.
-  /// @param inst the SPIR-V instruction
-  /// @param first_operand_type the type of the first operand to the instruction
-  /// @param second_operand_expr the second operand of the instruction
-  /// @returns second_operand_expr, or a cast of it
-  TypedExpression RectifySecondOperandSignedness(
-      const spvtools::opt::Instruction& inst,
-      const Type* first_operand_type,
-      TypedExpression&& second_operand_expr);
-
-  /// Returns the "forced" result type for the given SPIR-V instruction.
-  /// If the WGSL result type for an operation has a more strict rule than
-  /// requried by SPIR-V, then we say the result type is "forced".  This occurs
-  /// for signed integer division (OpSDiv), for example, where the result type
-  /// in WGSL must match the operand types.
-  /// @param inst the SPIR-V instruction
-  /// @param first_operand_type the AST type for the first operand.
-  /// @returns the forced AST result type, or nullptr if no forcing is required.
-  const Type* ForcedResultType(const spvtools::opt::Instruction& inst,
-                               const Type* first_operand_type);
-
-  /// Returns a signed integer scalar or vector type matching the shape (scalar,
-  /// vector, and component bit width) of another type, which itself is a
-  /// numeric scalar or vector. Returns null if the other type does not meet the
-  /// requirement.
-  /// @param other the type whose shape must be matched
-  /// @returns the signed scalar or vector type
-  const Type* GetSignedIntMatchingShape(const Type* other);
-
-  /// Returns a signed integer scalar or vector type matching the shape (scalar,
-  /// vector, and component bit width) of another type, which itself is a
-  /// numeric scalar or vector. Returns null if the other type does not meet the
-  /// requirement.
-  /// @param other the type whose shape must be matched
-  /// @returns the unsigned scalar or vector type
-  const Type* GetUnsignedIntMatchingShape(const Type* other);
-
-  /// Wraps the given expression in an as-cast to the given expression's type,
-  /// when the underlying operation produces a forced result type different
-  /// from the expression's result type. Otherwise, returns the given expression
-  /// unchanged.
-  /// @param expr the expression to pass through or to wrap
-  /// @param inst the SPIR-V instruction
-  /// @param first_operand_type the AST type for the first operand.
-  /// @returns the forced AST result type, or nullptr if no forcing is required.
-  TypedExpression RectifyForcedResultType(
-      TypedExpression expr,
-      const spvtools::opt::Instruction& inst,
-      const Type* first_operand_type);
-
-  /// Returns the given expression, but ensuring it's an unsigned type of the
-  /// same shape as the operand. Wraps the expression with a bitcast if needed.
-  /// Assumes the given expresion is a integer scalar or vector.
-  /// @param expr an integer scalar or integer vector expression.
-  /// @return the potentially cast TypedExpression
-  TypedExpression AsUnsigned(TypedExpression expr);
-
-  /// Returns the given expression, but ensuring it's a signed type of the
-  /// same shape as the operand. Wraps the expression with a bitcast if needed.
-  /// Assumes the given expresion is a integer scalar or vector.
-  /// @param expr an integer scalar or integer vector expression.
-  /// @return the potentially cast TypedExpression
-  TypedExpression AsSigned(TypedExpression expr);
-
-  /// Bookkeeping used for tracking the "position" builtin variable.
-  struct BuiltInPositionInfo {
-    /// The ID for the gl_PerVertex struct containing the Position builtin.
-    uint32_t struct_type_id = 0;
-    /// The member index for the Position builtin within the struct.
-    uint32_t position_member_index = 0;
-    /// The member index for the PointSize builtin within the struct.
-    uint32_t pointsize_member_index = 0;
-    /// The ID for the member type, which should map to vec4<f32>.
-    uint32_t position_member_type_id = 0;
-    /// The ID of the type of a pointer to the struct in the Output storage
-    /// class class.
-    uint32_t pointer_type_id = 0;
-    /// The SPIR-V storage class.
-    SpvStorageClass storage_class = SpvStorageClassOutput;
-    /// The ID of the type of a pointer to the Position member.
-    uint32_t position_member_pointer_type_id = 0;
-    /// The ID of the gl_PerVertex variable, if it was declared.
-    /// We'll use this for the gl_Position variable instead.
-    uint32_t per_vertex_var_id = 0;
-    /// The ID of the initializer to gl_PerVertex, if any.
-    uint32_t per_vertex_var_init_id = 0;
-  };
-  /// @returns info about the gl_Position builtin variable.
-  const BuiltInPositionInfo& GetBuiltInPositionInfo() {
-    return builtin_position_;
-  }
-
-  /// Returns the source record for the SPIR-V instruction with the given
-  /// result ID.
-  /// @param id the SPIR-V result id.
-  /// @return the Source record, or a default one
-  Source GetSourceForResultIdForTest(uint32_t id) const;
-  /// Returns the source record for the given instruction.
-  /// @param inst the SPIR-V instruction
-  /// @return the Source record, or a default one
-  Source GetSourceForInst(const spvtools::opt::Instruction* inst) const;
-
-  /// @param str a candidate identifier
-  /// @returns true if the given string is a valid WGSL identifier.
-  static bool IsValidIdentifier(const std::string& str);
-
-  /// Returns true if the given SPIR-V ID is a declared specialization constant,
-  /// generated by one of OpConstantTrue, OpConstantFalse, or OpSpecConstant
-  /// @param id a SPIR-V result ID
-  /// @returns true if the ID is a scalar spec constant.
-  bool IsScalarSpecConstant(uint32_t id) {
-    return scalar_spec_constants_.find(id) != scalar_spec_constants_.end();
-  }
-
-  /// For a SPIR-V ID that might define a sampler, image, or sampled image
-  /// value, return the SPIR-V instruction that represents the memory object
-  /// declaration for the object.  If we encounter an OpSampledImage along the
-  /// way, follow the image operand when follow_image is true; otherwise follow
-  /// the sampler operand. Returns nullptr if we can't trace back to a memory
-  /// object declaration.  Emits an error and returns nullptr when the scan
-  /// fails due to a malformed module. This method can be used any time after
-  /// BuildInternalModule has been invoked.
-  /// @param id the SPIR-V ID of the sampler, image, or sampled image
-  /// @param follow_image indicates whether to follow the image operand of
-  /// OpSampledImage
-  /// @returns the memory object declaration for the handle, or nullptr
-  const spvtools::opt::Instruction* GetMemoryObjectDeclarationForHandle(
-      uint32_t id,
-      bool follow_image);
-
-  /// Returns the handle usage for a memory object declaration.
-  /// @param id SPIR-V ID of a sampler or image OpVariable or
-  /// OpFunctionParameter
-  /// @returns the handle usage, or an empty usage object.
-  Usage GetHandleUsage(uint32_t id) const;
-
-  /// Returns the SPIR-V type for the sampler or image type for the given
-  /// variable in UniformConstant storage class, or function parameter pointing
-  /// into the UniformConstant storage class .  Returns null and emits an
-  /// error on failure.
-  /// @param var the OpVariable instruction or OpFunctionParameter
-  /// @returns the Tint AST type for the sampler or texture, or null on error
-  const spvtools::opt::Instruction*
-  GetSpirvTypeForHandleMemoryObjectDeclaration(
-      const spvtools::opt::Instruction& var);
-
-  /// Returns the AST type for the pointer-to-sampler or pointer-to-texture type
-  /// for the given variable in UniformConstant storage class.  Returns null and
-  /// emits an error on failure.
-  /// @param var the OpVariable instruction
-  /// @returns the Tint AST type for the poiner-to-{sampler|texture} or null on
-  /// error
-  const Pointer* GetTypeForHandleVar(const spvtools::opt::Instruction& var);
-
-  /// Returns the channel component type corresponding to the given image
-  /// format.
-  /// @param format image texel format
-  /// @returns the component type, one of f32, i32, u32
-  const Type* GetComponentTypeForFormat(ast::TexelFormat format);
-
-  /// Returns the number of channels in the given image format.
-  /// @param format image texel format
-  /// @returns the number of channels in the format
-  unsigned GetChannelCountForFormat(ast::TexelFormat format);
-
-  /// Returns the texel type corresponding to the given image format.
-  /// This the WGSL type used for the texel parameter to textureStore.
-  /// It's always a 4-element vector.
-  /// @param format image texel format
-  /// @returns the texel format
-  const Type* GetTexelTypeForFormat(ast::TexelFormat format);
-
-  /// Returns the SPIR-V instruction with the given ID, or nullptr.
-  /// @param id the SPIR-V result ID
-  /// @returns the instruction, or nullptr on error
-  const spvtools::opt::Instruction* GetInstructionForTest(uint32_t id) const;
-
-  /// A map of SPIR-V identifiers to builtins
-  using BuiltInsMap = std::unordered_map<uint32_t, SpvBuiltIn>;
-
-  /// @returns a map of builtins that should be handled specially by code
-  /// generation. Either the builtin does not exist in WGSL, or a type
-  /// conversion must be implemented on load and store.
-  const BuiltInsMap& special_builtins() const { return special_builtins_; }
-
-  /// @param builtin the SPIR-V builtin variable kind
-  /// @returns the SPIR-V ID for the variable defining the given builtin, or 0
-  uint32_t IdForSpecialBuiltIn(SpvBuiltIn builtin) const {
-    // Do a linear search.
-    for (const auto& entry : special_builtins_) {
-      if (entry.second == builtin) {
-        return entry.first;
-      }
+    /// Logs failure, ands return a failure stream to accumulate diagnostic
+    /// messages. By convention, a failure should only be logged along with
+    /// a non-empty string diagnostic.
+    /// @returns the failure stream
+    FailStream& Fail() {
+        success_ = false;
+        return fail_stream_;
     }
-    return 0;
-  }
 
-  /// @param entry_point the SPIR-V ID of an entry point.
-  /// @returns the entry point info for the given ID
-  const std::vector<EntryPointInfo>& GetEntryPointInfo(uint32_t entry_point) {
-    return function_to_ep_info_[entry_point];
-  }
+    /// @return true if failure has not yet occurred
+    bool success() const { return success_; }
 
-  /// @returns the SPIR-V binary.
-  const std::vector<uint32_t>& spv_binary() { return spv_binary_; }
+    /// @returns the accumulated error string
+    const std::string error() { return errors_.str(); }
 
- private:
-  /// Converts a specific SPIR-V type to a Tint type. Integer case
-  const Type* ConvertType(const spvtools::opt::analysis::Integer* int_ty);
-  /// Converts a specific SPIR-V type to a Tint type. Float case
-  const Type* ConvertType(const spvtools::opt::analysis::Float* float_ty);
-  /// Converts a specific SPIR-V type to a Tint type. Vector case
-  const Type* ConvertType(const spvtools::opt::analysis::Vector* vec_ty);
-  /// Converts a specific SPIR-V type to a Tint type. Matrix case
-  const Type* ConvertType(const spvtools::opt::analysis::Matrix* mat_ty);
-  /// Converts a specific SPIR-V type to a Tint type. RuntimeArray case
-  /// Distinct SPIR-V array types map to distinct Tint array types.
-  /// @param rtarr_ty the Tint type
-  const Type* ConvertType(
-      uint32_t type_id,
-      const spvtools::opt::analysis::RuntimeArray* rtarr_ty);
-  /// Converts a specific SPIR-V type to a Tint type. Array case
-  /// Distinct SPIR-V array types map to distinct Tint array types.
-  /// @param arr_ty the Tint type
-  const Type* ConvertType(uint32_t type_id,
-                          const spvtools::opt::analysis::Array* arr_ty);
-  /// Converts a specific SPIR-V type to a Tint type. Struct case.
-  /// SPIR-V allows distinct struct type definitions for two OpTypeStruct
-  /// that otherwise have the same set of members (and struct and member
-  /// decorations).  However, the SPIRV-Tools always produces a unique
-  /// `spvtools::opt::analysis::Struct` object in these cases. For this type
-  /// conversion, we need to have the original SPIR-V ID because we can't always
-  /// recover it from the optimizer's struct type object. This also lets us
-  /// preserve member names, which are given by OpMemberName which is normally
-  /// not significant to the optimizer's module representation.
-  /// @param type_id the SPIR-V ID for the type.
-  /// @param struct_ty the Tint type
-  const Type* ConvertType(uint32_t type_id,
-                          const spvtools::opt::analysis::Struct* struct_ty);
-  /// Converts a specific SPIR-V type to a Tint type. Pointer / Reference case
-  /// The pointer to gl_PerVertex maps to nullptr, and instead is recorded
-  /// in member #builtin_position_.
-  /// @param type_id the SPIR-V ID for the type.
-  /// @param ptr_as if PtrAs::Ref then a Reference will be returned, otherwise
-  /// Pointer
-  /// @param ptr_ty the Tint type
-  const Type* ConvertType(uint32_t type_id,
-                          PtrAs ptr_as,
-                          const spvtools::opt::analysis::Pointer* ptr_ty);
+    /// Builds an internal representation of the SPIR-V binary,
+    /// and parses it into a Tint AST module.  Diagnostics are emitted
+    /// to the error stream.
+    /// @returns true if it was successful.
+    bool BuildAndParseInternalModule() { return BuildInternalModule() && ParseInternalModule(); }
+    /// Builds an internal representation of the SPIR-V binary,
+    /// and parses the module, except functions, into a Tint AST module.
+    /// Diagnostics are emitted to the error stream.
+    /// @returns true if it was successful.
+    bool BuildAndParseInternalModuleExceptFunctions() {
+        return BuildInternalModule() && ParseInternalModuleExceptFunctions();
+    }
 
-  /// If `type` is a signed integral, or vector of signed integral,
-  /// returns the unsigned type, otherwise returns `type`.
-  /// @param type the possibly signed type
-  /// @returns the unsigned type
-  const Type* UnsignedTypeFor(const Type* type);
+    /// @returns the set of SPIR-V IDs for imports of the "GLSL.std.450"
+    /// extended instruction set.
+    const std::unordered_set<uint32_t>& glsl_std_450_imports() const {
+        return glsl_std_450_imports_;
+    }
 
-  /// If `type` is a unsigned integral, or vector of unsigned integral,
-  /// returns the signed type, otherwise returns `type`.
-  /// @param type the possibly unsigned type
-  /// @returns the signed type
-  const Type* SignedTypeFor(const Type* type);
+    /// Desired handling of SPIR-V pointers by ConvertType()
+    enum class PtrAs {
+        // SPIR-V pointer is converted to a spirv::Pointer
+        Ptr,
+        // SPIR-V pointer is converted to a spirv::Reference
+        Ref
+    };
 
-  /// Parses the array or runtime-array decorations. Sets 0 if no explicit
-  /// stride was found, and therefore the implicit stride should be used.
-  /// @param spv_type the SPIR-V array or runtime-array type.
-  /// @param array_stride pointer to the array stride
-  /// @returns true on success.
-  bool ParseArrayDecorations(const spvtools::opt::analysis::Type* spv_type,
-                             uint32_t* array_stride);
+    /// Converts a SPIR-V type to a Tint type, and saves it for fast lookup.
+    /// If the type is only used for builtins, then register that specially,
+    /// and return null.  If the type is a sampler, image, or sampled image, then
+    /// return the Void type, because those opaque types are handled in a
+    /// different way.
+    /// On failure, logs an error and returns null.  This should only be called
+    /// after the internal representation of the module has been built.
+    /// @param type_id the SPIR-V ID of a type.
+    /// @param ptr_as if the SPIR-V type is a pointer and ptr_as is equal to
+    /// PtrAs::Ref then a Reference will be returned, otherwise a Pointer will be
+    /// returned for a SPIR-V pointer
+    /// @returns a Tint type, or nullptr
+    const Type* ConvertType(uint32_t type_id, PtrAs ptr_as = PtrAs::Ptr);
 
-  /// Creates a new `ast::Node` owned by the ProgramBuilder.
-  /// @param args the arguments to pass to the type constructor
-  /// @returns the node pointer
-  template <typename T, typename... ARGS>
-  T* create(ARGS&&... args) {
-    return builder_.create<T>(std::forward<ARGS>(args)...);
-  }
+    /// Emits an alias type declaration for array or runtime-sized array type,
+    /// when needed to distinguish between differently-decorated underlying types.
+    /// Updates the mapping of the SPIR-V type ID to the alias type.
+    /// This is a no-op if the parser has already failed.
+    /// @param type_id the SPIR-V ID for the type
+    /// @param type the type that might get an alias
+    /// @param ast_type the ast type that might get an alias
+    /// @returns an alias type or `ast_type` if no alias was created
+    const Type* MaybeGenerateAlias(uint32_t type_id,
+                                   const spvtools::opt::analysis::Type* type,
+                                   const Type* ast_type);
 
-  // The SPIR-V binary we're parsing
-  std::vector<uint32_t> spv_binary_;
+    /// Adds `decl` as a declared type if it hasn't been added yet.
+    /// @param name the type's unique name
+    /// @param decl the type declaration to add
+    void AddTypeDecl(Symbol name, const ast::TypeDecl* decl);
 
-  // The program builder.
-  ProgramBuilder builder_;
+    /// @returns the fail stream object
+    FailStream& fail_stream() { return fail_stream_; }
+    /// @returns the namer object
+    Namer& namer() { return namer_; }
+    /// @returns a borrowed pointer to the internal representation of the module.
+    /// This is null until BuildInternalModule has been called.
+    spvtools::opt::IRContext* ir_context() { return ir_context_.get(); }
 
-  // The type manager.
-  TypeManager ty_;
+    /// Gets the list of unique decorations for a SPIR-V result ID.  Returns an
+    /// empty vector if the ID is not a result ID, or if no decorations target
+    /// that ID. The internal representation must have already been built.
+    /// Ignores decorations that have no effect in graphics APIs, e.g. Restrict
+    /// and RestrictPointer.
+    /// @param id SPIR-V ID
+    /// @returns the list of decorations on the given ID
+    DecorationList GetDecorationsFor(uint32_t id) const;
+    /// Gets the list of unique decorations for the member of a struct.  Returns
+    /// an empty list if the `id` is not the ID of a struct, or if the member
+    /// index is out of range, or if the target member has no decorations. The
+    /// internal representation must have already been built.
+    /// Ignores decorations that have no effect in graphics APIs, e.g. Restrict
+    /// and RestrictPointer.
+    /// @param id SPIR-V ID of a struct
+    /// @param member_index the member within the struct
+    /// @returns the list of decorations on the member
+    DecorationList GetDecorationsForMember(uint32_t id, uint32_t member_index) const;
 
-  // Is the parse successful?
-  bool success_ = true;
-  // Collector for diagnostic messages.
-  std::stringstream errors_;
-  FailStream fail_stream_;
-  spvtools::MessageConsumer message_consumer_;
+    /// Converts SPIR-V decorations for the variable with the given ID.
+    /// Registers the IDs of variables that require special handling by code
+    /// generation.  If the WGSL type differs from the store type for SPIR-V,
+    /// then the `type` parameter is updated.  Returns false on failure (with
+    /// a diagnostic), or when the variable should not be emitted, e.g. for a
+    /// PointSize builtin.
+    /// @param id the ID of the SPIR-V variable
+    /// @param store_type the WGSL store type for the variable, which should be
+    /// prepopulatd
+    /// @param attributes the attribute list to populate
+    /// @param transfer_pipeline_io true if pipeline IO decorations (builtins,
+    /// or locations) will update the store type and the decorations list
+    /// @returns false when the variable should not be emitted as a variable
+    bool ConvertDecorationsForVariable(uint32_t id,
+                                       const Type** store_type,
+                                       ast::AttributeList* attributes,
+                                       bool transfer_pipeline_io);
 
-  // An object used to store and generate names for SPIR-V objects.
-  Namer namer_;
-  // An object used to convert SPIR-V enums to Tint enums
-  EnumConverter enum_converter_;
+    /// Converts SPIR-V decorations for pipeline IO into AST decorations.
+    /// @param store_type the store type for the variable or member
+    /// @param decorations the SPIR-V interpolation decorations
+    /// @param attributes the attribute list to populate.
+    /// @returns false if conversion fails
+    bool ConvertPipelineDecorations(const Type* store_type,
+                                    const DecorationList& decorations,
+                                    ast::AttributeList* attributes);
 
-  // The internal representation of the SPIR-V module and its context.
-  spvtools::Context tools_context_;
-  // All the state is owned by ir_context_.
-  std::unique_ptr<spvtools::opt::IRContext> ir_context_;
-  // The following are borrowed pointers to the internal state of ir_context_.
-  spvtools::opt::Module* module_ = nullptr;
-  spvtools::opt::analysis::DefUseManager* def_use_mgr_ = nullptr;
-  spvtools::opt::analysis::ConstantManager* constant_mgr_ = nullptr;
-  spvtools::opt::analysis::TypeManager* type_mgr_ = nullptr;
-  spvtools::opt::analysis::DecorationManager* deco_mgr_ = nullptr;
+    /// Updates the attribute list, placing a non-null location decoration into
+    /// the list, replacing an existing one if it exists. Does nothing if the
+    /// replacement is nullptr.
+    /// Assumes the list contains at most one Location decoration.
+    /// @param decos the attribute list to modify
+    /// @param replacement the location decoration to place into the list
+    /// @returns the location decoration that was replaced, if one was replaced,
+    /// or null otherwise.
+    const ast::Attribute* SetLocation(ast::AttributeList* decos, const ast::Attribute* replacement);
 
-  // The functions ordered so that callees precede their callers.
-  std::vector<const spvtools::opt::Function*> topologically_ordered_functions_;
+    /// Converts a SPIR-V struct member decoration into a number of AST
+    /// decorations. If the decoration is recognized but deliberately dropped,
+    /// then returns an empty list without a diagnostic. On failure, emits a
+    /// diagnostic and returns an empty list.
+    /// @param struct_type_id the ID of the struct type
+    /// @param member_index the index of the member
+    /// @param member_ty the type of the member
+    /// @param decoration an encoded SPIR-V Decoration
+    /// @returns the AST decorations
+    ast::AttributeList ConvertMemberDecoration(uint32_t struct_type_id,
+                                               uint32_t member_index,
+                                               const Type* member_ty,
+                                               const Decoration& decoration);
 
-  // Maps an instruction to its source location. If no OpLine information
-  // is in effect for the instruction, map the instruction to its position
-  // in the SPIR-V module, counting by instructions, where the first
-  // instruction is line 1.
-  std::unordered_map<const spvtools::opt::Instruction*, Source::Location>
-      inst_source_;
+    /// Returns a string for the given type.  If the type ID is invalid,
+    /// then the resulting string only names the type ID.
+    /// @param type_id the SPIR-V ID for the type
+    /// @returns a string description of the type.
+    std::string ShowType(uint32_t type_id);
 
-  // The set of IDs that are imports of the GLSL.std.450 extended instruction
-  // sets.
-  std::unordered_set<uint32_t> glsl_std_450_imports_;
-  // The set of IDs of imports that are ignored. For example, any
-  // "NonSemanticInfo." import is ignored.
-  std::unordered_set<uint32_t> ignored_imports_;
+    /// Builds the internal representation of the SPIR-V module.
+    /// Assumes the module is somewhat well-formed.  Normally you
+    /// would want to validate the SPIR-V module before attempting
+    /// to build this internal representation. Also computes a topological
+    /// ordering of the functions.
+    /// This is a no-op if the parser has already failed.
+    /// @returns true if the parser is still successful.
+    bool BuildInternalModule();
 
-  // The SPIR-V IDs of structure types that are the store type for buffer
-  // variables, either UBO or SSBO.
-  std::unordered_set<uint32_t> struct_types_for_buffers_;
+    /// Walks the internal representation of the module to populate
+    /// the AST form of the module.
+    /// This is a no-op if the parser has already failed.
+    /// @returns true if the parser is still successful.
+    bool ParseInternalModule();
 
-  // Bookkeeping for the gl_Position builtin.
-  // In Vulkan SPIR-V, it's the 0 member of the gl_PerVertex structure.
-  // But in WGSL we make a module-scope variable:
-  //    [[position]] var<in> gl_Position : vec4<f32>;
-  // The builtin variable was detected if and only if the struct_id is non-zero.
-  BuiltInPositionInfo builtin_position_;
+    /// Records line numbers for each instruction.
+    void RegisterLineNumbers();
 
-  // SPIR-V type IDs that are either:
-  // - a struct type decorated by BufferBlock
-  // - an array, runtime array containing one of these
-  // - a pointer type to one of these
-  // These are the types "enclosing" a buffer block with the old style
-  // representation: using Uniform storage class and BufferBlock decoration
-  // on the struct.  The new style is to use the StorageBuffer storage class
-  // and Block decoration.
-  std::unordered_set<uint32_t> remap_buffer_block_type_;
+    /// Walks the internal representation of the module, except for function
+    /// definitions, to populate the AST form of the module.
+    /// This is a no-op if the parser has already failed.
+    /// @returns true if the parser is still successful.
+    bool ParseInternalModuleExceptFunctions();
 
-  // The ast::Struct type names with only read-only members.
-  std::unordered_set<Symbol> read_only_struct_types_;
+    /// Destroys the internal representation of the SPIR-V module.
+    void ResetInternalModule();
 
-  // The IDs of scalar spec constants
-  std::unordered_set<uint32_t> scalar_spec_constants_;
+    /// Registers extended instruction imports.  Only "GLSL.std.450" is supported.
+    /// This is a no-op if the parser has already failed.
+    /// @returns true if parser is still successful.
+    bool RegisterExtendedInstructionImports();
 
-  // Maps function_id to a list of entrypoint information
-  std::unordered_map<uint32_t, std::vector<EntryPointInfo>>
-      function_to_ep_info_;
+    /// Returns true when the given instruction is an extended instruction
+    /// for GLSL.std.450.
+    /// @param inst a SPIR-V instruction
+    /// @returns true if its an SpvOpExtInst for GLSL.std.450
+    bool IsGlslExtendedInstruction(const spvtools::opt::Instruction& inst) const;
 
-  // Maps from a SPIR-V ID to its underlying memory object declaration,
-  // following image paths. This a memoization table for
-  // GetMemoryObjectDeclarationForHandle. (A SPIR-V memory object declaration is
-  // an OpVariable or an OpFunctinParameter with pointer type).
-  std::unordered_map<uint32_t, const spvtools::opt::Instruction*>
-      mem_obj_decl_image_;
-  // Maps from a SPIR-V ID to its underlying memory object declaration,
-  // following sampler paths. This a memoization table for
-  // GetMemoryObjectDeclarationForHandle.
-  std::unordered_map<uint32_t, const spvtools::opt::Instruction*>
-      mem_obj_decl_sampler_;
+    /// Returns true when the given instruction is an extended instruction
+    /// from an ignored extended instruction set.
+    /// @param inst a SPIR-V instruction
+    /// @returns true if its an SpvOpExtInst for an ignored extended instruction
+    bool IsIgnoredExtendedInstruction(const spvtools::opt::Instruction& inst) const;
 
-  // Maps a memory-object-declaration instruction to any sampler or texture
-  // usages implied by usages of the memory-object-declaration.
-  std::unordered_map<const spvtools::opt::Instruction*, Usage> handle_usage_;
-  // The inferred pointer type for the given handle variable.
-  std::unordered_map<const spvtools::opt::Instruction*, const Pointer*>
-      handle_type_;
+    /// Registers user names for SPIR-V objects, from OpName, and OpMemberName.
+    /// Also synthesizes struct field names.  Ensures uniqueness for names for
+    /// SPIR-V IDs, and uniqueness of names of fields within any single struct.
+    /// This is a no-op if the parser has already failed.
+    /// @returns true if parser is still successful.
+    bool RegisterUserAndStructMemberNames();
 
-  // Set of symbols of declared type that have been added, used to avoid
-  // adding duplicates.
-  std::unordered_set<Symbol> declared_types_;
+    /// Register the WorkgroupSize builtin and its associated constant value.
+    /// @returns true if parser is still successful.
+    bool RegisterWorkgroupSizeBuiltin();
 
-  // Maps a struct type name to the SPIR-V ID for the structure type.
-  std::unordered_map<Symbol, uint32_t> struct_id_for_symbol_;
+    /// @returns the workgroup size builtin
+    const WorkgroupSizeInfo& workgroup_size_builtin() { return workgroup_size_builtin_; }
 
-  /// Maps the SPIR-V ID of a module-scope builtin variable that should be
-  /// ignored or type-converted, to its builtin kind.
-  /// See also BuiltInPositionInfo which is a separate mechanism for a more
-  /// complex case of replacing an entire structure.
-  BuiltInsMap special_builtins_;
+    /// Register entry point information.
+    /// This is a no-op if the parser has already failed.
+    /// @returns true if parser is still successful.
+    bool RegisterEntryPoints();
 
-  /// Info about the WorkgroupSize builtin. If it's not present, then the 'id'
-  /// field will be 0. Sadly, in SPIR-V right now, there's only one workgroup
-  /// size object in the module.
-  WorkgroupSizeInfo workgroup_size_builtin_;
+    /// Register Tint AST types for SPIR-V types, including type aliases as
+    /// needed.  This is a no-op if the parser has already failed.
+    /// @returns true if parser is still successful.
+    bool RegisterTypes();
+
+    /// Fail if there are any module-scope pointer values other than those
+    /// declared by OpVariable.
+    /// @returns true if parser is still successful.
+    bool RejectInvalidPointerRoots();
+
+    /// Register sampler and texture usage for memory object declarations.
+    /// This must be called after we've registered line numbers for all
+    /// instructions. This is a no-op if the parser has already failed.
+    /// @returns true if parser is still successful.
+    bool RegisterHandleUsage();
+
+    /// Emit const definitions for scalar specialization constants generated
+    /// by one of OpConstantTrue, OpConstantFalse, or OpSpecConstant.
+    /// This is a no-op if the parser has already failed.
+    /// @returns true if parser is still successful.
+    bool EmitScalarSpecConstants();
+
+    /// Emits module-scope variables.
+    /// This is a no-op if the parser has already failed.
+    /// @returns true if parser is still successful.
+    bool EmitModuleScopeVariables();
+
+    /// Emits functions, with callees preceding their callers.
+    /// This is a no-op if the parser has already failed.
+    /// @returns true if parser is still successful.
+    bool EmitFunctions();
+
+    /// Emits a single function, if it has a body.
+    /// This is a no-op if the parser has already failed.
+    /// @param f the function to emit
+    /// @returns true if parser is still successful.
+    bool EmitFunction(const spvtools::opt::Function& f);
+
+    /// Returns the integer constant for the array size of the given variable.
+    /// @param var_id SPIR-V ID for an array variable
+    /// @returns the integer constant for its array size, or nullptr.
+    const spvtools::opt::analysis::IntConstant* GetArraySize(uint32_t var_id);
+
+    /// Returns the member name for the struct member.
+    /// @param struct_type the parser's structure type.
+    /// @param member_index the member index
+    /// @returns the field name
+    std::string GetMemberName(const Struct& struct_type, int member_index);
+
+    /// Returns the SPIR-V decorations for pipeline IO, if any, on a struct
+    /// member.
+    /// @param struct_type the parser's structure type.
+    /// @param member_index the member index
+    /// @returns a list of SPIR-V decorations.
+    DecorationList GetMemberPipelineDecorations(const Struct& struct_type, int member_index);
+
+    /// Creates an AST Variable node for a SPIR-V ID, including any attached
+    /// decorations, unless it's an ignorable builtin variable.
+    /// @param id the SPIR-V result ID
+    /// @param sc the storage class, which cannot be ast::StorageClass::kNone
+    /// @param storage_type the storage type of the variable
+    /// @param is_const if true, the variable is const
+    /// @param is_overridable if true, the variable is pipeline-overridable
+    /// @param constructor the variable constructor
+    /// @param decorations the variable decorations
+    /// @returns a new Variable node, or null in the ignorable variable case and
+    /// in the error case
+    ast::Variable* MakeVariable(uint32_t id,
+                                ast::StorageClass sc,
+                                const Type* storage_type,
+                                bool is_const,
+                                bool is_overridable,
+                                const ast::Expression* constructor,
+                                ast::AttributeList decorations);
+
+    /// Returns true if a constant expression can be generated.
+    /// @param id the SPIR-V ID of the value
+    /// @returns true if a constant expression can be generated
+    bool CanMakeConstantExpression(uint32_t id);
+
+    /// Creates an AST expression node for a SPIR-V ID.  This is valid to call
+    /// when `CanMakeConstantExpression` returns true.
+    /// @param id the SPIR-V ID of the constant
+    /// @returns a new expression
+    TypedExpression MakeConstantExpression(uint32_t id);
+
+    /// Creates an AST expression node for a scalar SPIR-V constant.
+    /// @param source the source location
+    /// @param ast_type the AST type for the value
+    /// @param spirv_const the internal representation of the SPIR-V constant.
+    /// @returns a new expression
+    TypedExpression MakeConstantExpressionForScalarSpirvConstant(
+        Source source,
+        const Type* ast_type,
+        const spvtools::opt::analysis::Constant* spirv_const);
+
+    /// Creates an AST expression node for the null value for the given type.
+    /// @param type the AST type
+    /// @returns a new expression
+    const ast::Expression* MakeNullValue(const Type* type);
+
+    /// Make a typed expression for the null value for the given type.
+    /// @param type the AST type
+    /// @returns a new typed expression
+    TypedExpression MakeNullExpression(const Type* type);
+
+    /// Converts a given expression to the signedness demanded for an operand
+    /// of the given SPIR-V instruction, if required.  If the instruction assumes
+    /// signed integer operands, and `expr` is unsigned, then return an
+    /// as-cast expression converting it to signed. Otherwise, return
+    /// `expr` itself.  Similarly, convert as required from unsigned
+    /// to signed. Assumes all SPIR-V types have been mapped to AST types.
+    /// @param inst the SPIR-V instruction
+    /// @param expr an expression
+    /// @returns expr, or a cast of expr
+    TypedExpression RectifyOperandSignedness(const spvtools::opt::Instruction& inst,
+                                             TypedExpression&& expr);
+
+    /// Converts a second operand to the signedness of the first operand
+    /// of a binary operator, if the WGSL operator requires they be the same.
+    /// Returns the converted expression, or the original expression if the
+    /// conversion is not needed.
+    /// @param inst the SPIR-V instruction
+    /// @param first_operand_type the type of the first operand to the instruction
+    /// @param second_operand_expr the second operand of the instruction
+    /// @returns second_operand_expr, or a cast of it
+    TypedExpression RectifySecondOperandSignedness(const spvtools::opt::Instruction& inst,
+                                                   const Type* first_operand_type,
+                                                   TypedExpression&& second_operand_expr);
+
+    /// Returns the "forced" result type for the given SPIR-V instruction.
+    /// If the WGSL result type for an operation has a more strict rule than
+    /// requried by SPIR-V, then we say the result type is "forced".  This occurs
+    /// for signed integer division (OpSDiv), for example, where the result type
+    /// in WGSL must match the operand types.
+    /// @param inst the SPIR-V instruction
+    /// @param first_operand_type the AST type for the first operand.
+    /// @returns the forced AST result type, or nullptr if no forcing is required.
+    const Type* ForcedResultType(const spvtools::opt::Instruction& inst,
+                                 const Type* first_operand_type);
+
+    /// Returns a signed integer scalar or vector type matching the shape (scalar,
+    /// vector, and component bit width) of another type, which itself is a
+    /// numeric scalar or vector. Returns null if the other type does not meet the
+    /// requirement.
+    /// @param other the type whose shape must be matched
+    /// @returns the signed scalar or vector type
+    const Type* GetSignedIntMatchingShape(const Type* other);
+
+    /// Returns a signed integer scalar or vector type matching the shape (scalar,
+    /// vector, and component bit width) of another type, which itself is a
+    /// numeric scalar or vector. Returns null if the other type does not meet the
+    /// requirement.
+    /// @param other the type whose shape must be matched
+    /// @returns the unsigned scalar or vector type
+    const Type* GetUnsignedIntMatchingShape(const Type* other);
+
+    /// Wraps the given expression in an as-cast to the given expression's type,
+    /// when the underlying operation produces a forced result type different
+    /// from the expression's result type. Otherwise, returns the given expression
+    /// unchanged.
+    /// @param expr the expression to pass through or to wrap
+    /// @param inst the SPIR-V instruction
+    /// @param first_operand_type the AST type for the first operand.
+    /// @returns the forced AST result type, or nullptr if no forcing is required.
+    TypedExpression RectifyForcedResultType(TypedExpression expr,
+                                            const spvtools::opt::Instruction& inst,
+                                            const Type* first_operand_type);
+
+    /// Returns the given expression, but ensuring it's an unsigned type of the
+    /// same shape as the operand. Wraps the expression with a bitcast if needed.
+    /// Assumes the given expresion is a integer scalar or vector.
+    /// @param expr an integer scalar or integer vector expression.
+    /// @return the potentially cast TypedExpression
+    TypedExpression AsUnsigned(TypedExpression expr);
+
+    /// Returns the given expression, but ensuring it's a signed type of the
+    /// same shape as the operand. Wraps the expression with a bitcast if needed.
+    /// Assumes the given expresion is a integer scalar or vector.
+    /// @param expr an integer scalar or integer vector expression.
+    /// @return the potentially cast TypedExpression
+    TypedExpression AsSigned(TypedExpression expr);
+
+    /// Bookkeeping used for tracking the "position" builtin variable.
+    struct BuiltInPositionInfo {
+        /// The ID for the gl_PerVertex struct containing the Position builtin.
+        uint32_t struct_type_id = 0;
+        /// The member index for the Position builtin within the struct.
+        uint32_t position_member_index = 0;
+        /// The member index for the PointSize builtin within the struct.
+        uint32_t pointsize_member_index = 0;
+        /// The ID for the member type, which should map to vec4<f32>.
+        uint32_t position_member_type_id = 0;
+        /// The ID of the type of a pointer to the struct in the Output storage
+        /// class class.
+        uint32_t pointer_type_id = 0;
+        /// The SPIR-V storage class.
+        SpvStorageClass storage_class = SpvStorageClassOutput;
+        /// The ID of the type of a pointer to the Position member.
+        uint32_t position_member_pointer_type_id = 0;
+        /// The ID of the gl_PerVertex variable, if it was declared.
+        /// We'll use this for the gl_Position variable instead.
+        uint32_t per_vertex_var_id = 0;
+        /// The ID of the initializer to gl_PerVertex, if any.
+        uint32_t per_vertex_var_init_id = 0;
+    };
+    /// @returns info about the gl_Position builtin variable.
+    const BuiltInPositionInfo& GetBuiltInPositionInfo() { return builtin_position_; }
+
+    /// Returns the source record for the SPIR-V instruction with the given
+    /// result ID.
+    /// @param id the SPIR-V result id.
+    /// @return the Source record, or a default one
+    Source GetSourceForResultIdForTest(uint32_t id) const;
+    /// Returns the source record for the given instruction.
+    /// @param inst the SPIR-V instruction
+    /// @return the Source record, or a default one
+    Source GetSourceForInst(const spvtools::opt::Instruction* inst) const;
+
+    /// @param str a candidate identifier
+    /// @returns true if the given string is a valid WGSL identifier.
+    static bool IsValidIdentifier(const std::string& str);
+
+    /// Returns true if the given SPIR-V ID is a declared specialization constant,
+    /// generated by one of OpConstantTrue, OpConstantFalse, or OpSpecConstant
+    /// @param id a SPIR-V result ID
+    /// @returns true if the ID is a scalar spec constant.
+    bool IsScalarSpecConstant(uint32_t id) {
+        return scalar_spec_constants_.find(id) != scalar_spec_constants_.end();
+    }
+
+    /// For a SPIR-V ID that might define a sampler, image, or sampled image
+    /// value, return the SPIR-V instruction that represents the memory object
+    /// declaration for the object.  If we encounter an OpSampledImage along the
+    /// way, follow the image operand when follow_image is true; otherwise follow
+    /// the sampler operand. Returns nullptr if we can't trace back to a memory
+    /// object declaration.  Emits an error and returns nullptr when the scan
+    /// fails due to a malformed module. This method can be used any time after
+    /// BuildInternalModule has been invoked.
+    /// @param id the SPIR-V ID of the sampler, image, or sampled image
+    /// @param follow_image indicates whether to follow the image operand of
+    /// OpSampledImage
+    /// @returns the memory object declaration for the handle, or nullptr
+    const spvtools::opt::Instruction* GetMemoryObjectDeclarationForHandle(uint32_t id,
+                                                                          bool follow_image);
+
+    /// Returns the handle usage for a memory object declaration.
+    /// @param id SPIR-V ID of a sampler or image OpVariable or
+    /// OpFunctionParameter
+    /// @returns the handle usage, or an empty usage object.
+    Usage GetHandleUsage(uint32_t id) const;
+
+    /// Returns the SPIR-V type for the sampler or image type for the given
+    /// variable in UniformConstant storage class, or function parameter pointing
+    /// into the UniformConstant storage class .  Returns null and emits an
+    /// error on failure.
+    /// @param var the OpVariable instruction or OpFunctionParameter
+    /// @returns the Tint AST type for the sampler or texture, or null on error
+    const spvtools::opt::Instruction* GetSpirvTypeForHandleMemoryObjectDeclaration(
+        const spvtools::opt::Instruction& var);
+
+    /// Returns the AST type for the pointer-to-sampler or pointer-to-texture type
+    /// for the given variable in UniformConstant storage class.  Returns null and
+    /// emits an error on failure.
+    /// @param var the OpVariable instruction
+    /// @returns the Tint AST type for the poiner-to-{sampler|texture} or null on
+    /// error
+    const Pointer* GetTypeForHandleVar(const spvtools::opt::Instruction& var);
+
+    /// Returns the channel component type corresponding to the given image
+    /// format.
+    /// @param format image texel format
+    /// @returns the component type, one of f32, i32, u32
+    const Type* GetComponentTypeForFormat(ast::TexelFormat format);
+
+    /// Returns the number of channels in the given image format.
+    /// @param format image texel format
+    /// @returns the number of channels in the format
+    unsigned GetChannelCountForFormat(ast::TexelFormat format);
+
+    /// Returns the texel type corresponding to the given image format.
+    /// This the WGSL type used for the texel parameter to textureStore.
+    /// It's always a 4-element vector.
+    /// @param format image texel format
+    /// @returns the texel format
+    const Type* GetTexelTypeForFormat(ast::TexelFormat format);
+
+    /// Returns the SPIR-V instruction with the given ID, or nullptr.
+    /// @param id the SPIR-V result ID
+    /// @returns the instruction, or nullptr on error
+    const spvtools::opt::Instruction* GetInstructionForTest(uint32_t id) const;
+
+    /// A map of SPIR-V identifiers to builtins
+    using BuiltInsMap = std::unordered_map<uint32_t, SpvBuiltIn>;
+
+    /// @returns a map of builtins that should be handled specially by code
+    /// generation. Either the builtin does not exist in WGSL, or a type
+    /// conversion must be implemented on load and store.
+    const BuiltInsMap& special_builtins() const { return special_builtins_; }
+
+    /// @param builtin the SPIR-V builtin variable kind
+    /// @returns the SPIR-V ID for the variable defining the given builtin, or 0
+    uint32_t IdForSpecialBuiltIn(SpvBuiltIn builtin) const {
+        // Do a linear search.
+        for (const auto& entry : special_builtins_) {
+            if (entry.second == builtin) {
+                return entry.first;
+            }
+        }
+        return 0;
+    }
+
+    /// @param entry_point the SPIR-V ID of an entry point.
+    /// @returns the entry point info for the given ID
+    const std::vector<EntryPointInfo>& GetEntryPointInfo(uint32_t entry_point) {
+        return function_to_ep_info_[entry_point];
+    }
+
+    /// @returns the SPIR-V binary.
+    const std::vector<uint32_t>& spv_binary() { return spv_binary_; }
+
+  private:
+    /// Converts a specific SPIR-V type to a Tint type. Integer case
+    const Type* ConvertType(const spvtools::opt::analysis::Integer* int_ty);
+    /// Converts a specific SPIR-V type to a Tint type. Float case
+    const Type* ConvertType(const spvtools::opt::analysis::Float* float_ty);
+    /// Converts a specific SPIR-V type to a Tint type. Vector case
+    const Type* ConvertType(const spvtools::opt::analysis::Vector* vec_ty);
+    /// Converts a specific SPIR-V type to a Tint type. Matrix case
+    const Type* ConvertType(const spvtools::opt::analysis::Matrix* mat_ty);
+    /// Converts a specific SPIR-V type to a Tint type. RuntimeArray case
+    /// Distinct SPIR-V array types map to distinct Tint array types.
+    /// @param rtarr_ty the Tint type
+    const Type* ConvertType(uint32_t type_id,
+                            const spvtools::opt::analysis::RuntimeArray* rtarr_ty);
+    /// Converts a specific SPIR-V type to a Tint type. Array case
+    /// Distinct SPIR-V array types map to distinct Tint array types.
+    /// @param arr_ty the Tint type
+    const Type* ConvertType(uint32_t type_id, const spvtools::opt::analysis::Array* arr_ty);
+    /// Converts a specific SPIR-V type to a Tint type. Struct case.
+    /// SPIR-V allows distinct struct type definitions for two OpTypeStruct
+    /// that otherwise have the same set of members (and struct and member
+    /// decorations).  However, the SPIRV-Tools always produces a unique
+    /// `spvtools::opt::analysis::Struct` object in these cases. For this type
+    /// conversion, we need to have the original SPIR-V ID because we can't always
+    /// recover it from the optimizer's struct type object. This also lets us
+    /// preserve member names, which are given by OpMemberName which is normally
+    /// not significant to the optimizer's module representation.
+    /// @param type_id the SPIR-V ID for the type.
+    /// @param struct_ty the Tint type
+    const Type* ConvertType(uint32_t type_id, const spvtools::opt::analysis::Struct* struct_ty);
+    /// Converts a specific SPIR-V type to a Tint type. Pointer / Reference case
+    /// The pointer to gl_PerVertex maps to nullptr, and instead is recorded
+    /// in member #builtin_position_.
+    /// @param type_id the SPIR-V ID for the type.
+    /// @param ptr_as if PtrAs::Ref then a Reference will be returned, otherwise
+    /// Pointer
+    /// @param ptr_ty the Tint type
+    const Type* ConvertType(uint32_t type_id,
+                            PtrAs ptr_as,
+                            const spvtools::opt::analysis::Pointer* ptr_ty);
+
+    /// If `type` is a signed integral, or vector of signed integral,
+    /// returns the unsigned type, otherwise returns `type`.
+    /// @param type the possibly signed type
+    /// @returns the unsigned type
+    const Type* UnsignedTypeFor(const Type* type);
+
+    /// If `type` is a unsigned integral, or vector of unsigned integral,
+    /// returns the signed type, otherwise returns `type`.
+    /// @param type the possibly unsigned type
+    /// @returns the signed type
+    const Type* SignedTypeFor(const Type* type);
+
+    /// Parses the array or runtime-array decorations. Sets 0 if no explicit
+    /// stride was found, and therefore the implicit stride should be used.
+    /// @param spv_type the SPIR-V array or runtime-array type.
+    /// @param array_stride pointer to the array stride
+    /// @returns true on success.
+    bool ParseArrayDecorations(const spvtools::opt::analysis::Type* spv_type,
+                               uint32_t* array_stride);
+
+    /// Creates a new `ast::Node` owned by the ProgramBuilder.
+    /// @param args the arguments to pass to the type constructor
+    /// @returns the node pointer
+    template <typename T, typename... ARGS>
+    T* create(ARGS&&... args) {
+        return builder_.create<T>(std::forward<ARGS>(args)...);
+    }
+
+    // The SPIR-V binary we're parsing
+    std::vector<uint32_t> spv_binary_;
+
+    // The program builder.
+    ProgramBuilder builder_;
+
+    // The type manager.
+    TypeManager ty_;
+
+    // Is the parse successful?
+    bool success_ = true;
+    // Collector for diagnostic messages.
+    std::stringstream errors_;
+    FailStream fail_stream_;
+    spvtools::MessageConsumer message_consumer_;
+
+    // An object used to store and generate names for SPIR-V objects.
+    Namer namer_;
+    // An object used to convert SPIR-V enums to Tint enums
+    EnumConverter enum_converter_;
+
+    // The internal representation of the SPIR-V module and its context.
+    spvtools::Context tools_context_;
+    // All the state is owned by ir_context_.
+    std::unique_ptr<spvtools::opt::IRContext> ir_context_;
+    // The following are borrowed pointers to the internal state of ir_context_.
+    spvtools::opt::Module* module_ = nullptr;
+    spvtools::opt::analysis::DefUseManager* def_use_mgr_ = nullptr;
+    spvtools::opt::analysis::ConstantManager* constant_mgr_ = nullptr;
+    spvtools::opt::analysis::TypeManager* type_mgr_ = nullptr;
+    spvtools::opt::analysis::DecorationManager* deco_mgr_ = nullptr;
+
+    // The functions ordered so that callees precede their callers.
+    std::vector<const spvtools::opt::Function*> topologically_ordered_functions_;
+
+    // Maps an instruction to its source location. If no OpLine information
+    // is in effect for the instruction, map the instruction to its position
+    // in the SPIR-V module, counting by instructions, where the first
+    // instruction is line 1.
+    std::unordered_map<const spvtools::opt::Instruction*, Source::Location> inst_source_;
+
+    // The set of IDs that are imports of the GLSL.std.450 extended instruction
+    // sets.
+    std::unordered_set<uint32_t> glsl_std_450_imports_;
+    // The set of IDs of imports that are ignored. For example, any
+    // "NonSemanticInfo." import is ignored.
+    std::unordered_set<uint32_t> ignored_imports_;
+
+    // The SPIR-V IDs of structure types that are the store type for buffer
+    // variables, either UBO or SSBO.
+    std::unordered_set<uint32_t> struct_types_for_buffers_;
+
+    // Bookkeeping for the gl_Position builtin.
+    // In Vulkan SPIR-V, it's the 0 member of the gl_PerVertex structure.
+    // But in WGSL we make a module-scope variable:
+    //    [[position]] var<in> gl_Position : vec4<f32>;
+    // The builtin variable was detected if and only if the struct_id is non-zero.
+    BuiltInPositionInfo builtin_position_;
+
+    // SPIR-V type IDs that are either:
+    // - a struct type decorated by BufferBlock
+    // - an array, runtime array containing one of these
+    // - a pointer type to one of these
+    // These are the types "enclosing" a buffer block with the old style
+    // representation: using Uniform storage class and BufferBlock decoration
+    // on the struct.  The new style is to use the StorageBuffer storage class
+    // and Block decoration.
+    std::unordered_set<uint32_t> remap_buffer_block_type_;
+
+    // The ast::Struct type names with only read-only members.
+    std::unordered_set<Symbol> read_only_struct_types_;
+
+    // The IDs of scalar spec constants
+    std::unordered_set<uint32_t> scalar_spec_constants_;
+
+    // Maps function_id to a list of entrypoint information
+    std::unordered_map<uint32_t, std::vector<EntryPointInfo>> function_to_ep_info_;
+
+    // Maps from a SPIR-V ID to its underlying memory object declaration,
+    // following image paths. This a memoization table for
+    // GetMemoryObjectDeclarationForHandle. (A SPIR-V memory object declaration is
+    // an OpVariable or an OpFunctinParameter with pointer type).
+    std::unordered_map<uint32_t, const spvtools::opt::Instruction*> mem_obj_decl_image_;
+    // Maps from a SPIR-V ID to its underlying memory object declaration,
+    // following sampler paths. This a memoization table for
+    // GetMemoryObjectDeclarationForHandle.
+    std::unordered_map<uint32_t, const spvtools::opt::Instruction*> mem_obj_decl_sampler_;
+
+    // Maps a memory-object-declaration instruction to any sampler or texture
+    // usages implied by usages of the memory-object-declaration.
+    std::unordered_map<const spvtools::opt::Instruction*, Usage> handle_usage_;
+    // The inferred pointer type for the given handle variable.
+    std::unordered_map<const spvtools::opt::Instruction*, const Pointer*> handle_type_;
+
+    // Set of symbols of declared type that have been added, used to avoid
+    // adding duplicates.
+    std::unordered_set<Symbol> declared_types_;
+
+    // Maps a struct type name to the SPIR-V ID for the structure type.
+    std::unordered_map<Symbol, uint32_t> struct_id_for_symbol_;
+
+    /// Maps the SPIR-V ID of a module-scope builtin variable that should be
+    /// ignored or type-converted, to its builtin kind.
+    /// See also BuiltInPositionInfo which is a separate mechanism for a more
+    /// complex case of replacing an entire structure.
+    BuiltInsMap special_builtins_;
+
+    /// Info about the WorkgroupSize builtin. If it's not present, then the 'id'
+    /// field will be 0. Sadly, in SPIR-V right now, there's only one workgroup
+    /// size object in the module.
+    WorkgroupSizeInfo workgroup_size_builtin_;
 };
 
 }  // namespace tint::reader::spirv
diff --git a/src/tint/reader/spirv/parser_impl_barrier_test.cc b/src/tint/reader/spirv/parser_impl_barrier_test.cc
index 39f267f..0549bd1 100644
--- a/src/tint/reader/spirv/parser_impl_barrier_test.cc
+++ b/src/tint/reader/spirv/parser_impl_barrier_test.cc
@@ -28,24 +28,24 @@
 using ::testing::StartsWith;
 
 Program ParseAndBuild(std::string spirv) {
-  const char* preamble = R"(OpCapability Shader
+    const char* preamble = R"(OpCapability Shader
             OpMemoryModel Logical GLSL450
             OpEntryPoint GLCompute %main "main"
             OpExecutionMode %main LocalSize 1 1 1
             OpName %main "main"
 )";
 
-  auto p = std::make_unique<ParserImpl>(test::Assemble(preamble + spirv));
-  if (!p->BuildAndParseInternalModule()) {
-    ProgramBuilder builder;
-    builder.Diagnostics().add_error(diag::System::Reader, p->error());
-    return Program(std::move(builder));
-  }
-  return p->program();
+    auto p = std::make_unique<ParserImpl>(test::Assemble(preamble + spirv));
+    if (!p->BuildAndParseInternalModule()) {
+        ProgramBuilder builder;
+        builder.Diagnostics().add_error(diag::System::Reader, p->error());
+        return Program(std::move(builder));
+    }
+    return p->program();
 }
 
 TEST_F(SpvParserTest, WorkgroupBarrier) {
-  auto program = ParseAndBuild(R"(
+    auto program = ParseAndBuild(R"(
                OpName %helper "helper"
        %void = OpTypeVoid
           %1 = OpTypeFunction %void
@@ -62,23 +62,22 @@
                OpReturn
                OpFunctionEnd
   )");
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
-  auto* helper =
-      program.AST().Functions().Find(program.Symbols().Get("helper"));
-  ASSERT_NE(helper, nullptr);
-  ASSERT_GT(helper->body->statements.size(), 0u);
-  auto* call = helper->body->statements[0]->As<ast::CallStatement>();
-  ASSERT_NE(call, nullptr);
-  EXPECT_EQ(call->expr->args.size(), 0u);
-  auto* sem_call = program.Sem().Get(call->expr);
-  ASSERT_NE(sem_call, nullptr);
-  auto* builtin = sem_call->Target()->As<sem::Builtin>();
-  ASSERT_NE(builtin, nullptr);
-  EXPECT_EQ(builtin->Type(), sem::BuiltinType::kWorkgroupBarrier);
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    auto* helper = program.AST().Functions().Find(program.Symbols().Get("helper"));
+    ASSERT_NE(helper, nullptr);
+    ASSERT_GT(helper->body->statements.size(), 0u);
+    auto* call = helper->body->statements[0]->As<ast::CallStatement>();
+    ASSERT_NE(call, nullptr);
+    EXPECT_EQ(call->expr->args.size(), 0u);
+    auto* sem_call = program.Sem().Get(call->expr);
+    ASSERT_NE(sem_call, nullptr);
+    auto* builtin = sem_call->Target()->As<sem::Builtin>();
+    ASSERT_NE(builtin, nullptr);
+    EXPECT_EQ(builtin->Type(), sem::BuiltinType::kWorkgroupBarrier);
 }
 
 TEST_F(SpvParserTest, StorageBarrier) {
-  auto program = ParseAndBuild(R"(
+    auto program = ParseAndBuild(R"(
                OpName %helper "helper"
        %void = OpTypeVoid
           %1 = OpTypeFunction %void
@@ -96,23 +95,22 @@
                OpReturn
                OpFunctionEnd
   )");
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
-  auto* helper =
-      program.AST().Functions().Find(program.Symbols().Get("helper"));
-  ASSERT_NE(helper, nullptr);
-  ASSERT_GT(helper->body->statements.size(), 0u);
-  auto* call = helper->body->statements[0]->As<ast::CallStatement>();
-  ASSERT_NE(call, nullptr);
-  EXPECT_EQ(call->expr->args.size(), 0u);
-  auto* sem_call = program.Sem().Get(call->expr);
-  ASSERT_NE(sem_call, nullptr);
-  auto* builtin = sem_call->Target()->As<sem::Builtin>();
-  ASSERT_NE(builtin, nullptr);
-  EXPECT_EQ(builtin->Type(), sem::BuiltinType::kStorageBarrier);
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    auto* helper = program.AST().Functions().Find(program.Symbols().Get("helper"));
+    ASSERT_NE(helper, nullptr);
+    ASSERT_GT(helper->body->statements.size(), 0u);
+    auto* call = helper->body->statements[0]->As<ast::CallStatement>();
+    ASSERT_NE(call, nullptr);
+    EXPECT_EQ(call->expr->args.size(), 0u);
+    auto* sem_call = program.Sem().Get(call->expr);
+    ASSERT_NE(sem_call, nullptr);
+    auto* builtin = sem_call->Target()->As<sem::Builtin>();
+    ASSERT_NE(builtin, nullptr);
+    EXPECT_EQ(builtin->Type(), sem::BuiltinType::kStorageBarrier);
 }
 
 TEST_F(SpvParserTest, ErrBarrierInvalidExecution) {
-  auto program = ParseAndBuild(R"(
+    auto program = ParseAndBuild(R"(
        %void = OpTypeVoid
           %1 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
@@ -125,13 +123,13 @@
                OpReturn
                OpFunctionEnd
   )");
-  EXPECT_FALSE(program.IsValid());
-  EXPECT_THAT(program.Diagnostics().str(),
-              HasSubstr("unsupported control barrier execution scope"));
+    EXPECT_FALSE(program.IsValid());
+    EXPECT_THAT(program.Diagnostics().str(),
+                HasSubstr("unsupported control barrier execution scope"));
 }
 
 TEST_F(SpvParserTest, ErrBarrierSemanticsMissingAcquireRelease) {
-  auto program = ParseAndBuild(R"(
+    auto program = ParseAndBuild(R"(
        %void = OpTypeVoid
           %1 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
@@ -143,14 +141,13 @@
                OpReturn
                OpFunctionEnd
   )");
-  EXPECT_FALSE(program.IsValid());
-  EXPECT_THAT(
-      program.Diagnostics().str(),
-      HasSubstr("control barrier semantics requires acquire and release"));
+    EXPECT_FALSE(program.IsValid());
+    EXPECT_THAT(program.Diagnostics().str(),
+                HasSubstr("control barrier semantics requires acquire and release"));
 }
 
 TEST_F(SpvParserTest, ErrBarrierInvalidSemantics) {
-  auto program = ParseAndBuild(R"(
+    auto program = ParseAndBuild(R"(
        %void = OpTypeVoid
           %1 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
@@ -162,13 +159,12 @@
                OpReturn
                OpFunctionEnd
   )");
-  EXPECT_FALSE(program.IsValid());
-  EXPECT_THAT(program.Diagnostics().str(),
-              HasSubstr("unsupported control barrier semantics"));
+    EXPECT_FALSE(program.IsValid());
+    EXPECT_THAT(program.Diagnostics().str(), HasSubstr("unsupported control barrier semantics"));
 }
 
 TEST_F(SpvParserTest, ErrWorkgroupBarrierInvalidMemory) {
-  auto program = ParseAndBuild(R"(
+    auto program = ParseAndBuild(R"(
        %void = OpTypeVoid
           %1 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
@@ -181,13 +177,13 @@
                OpReturn
                OpFunctionEnd
   )");
-  EXPECT_FALSE(program.IsValid());
-  EXPECT_THAT(program.Diagnostics().str(),
-              HasSubstr("workgroupBarrier requires workgroup memory scope"));
+    EXPECT_FALSE(program.IsValid());
+    EXPECT_THAT(program.Diagnostics().str(),
+                HasSubstr("workgroupBarrier requires workgroup memory scope"));
 }
 
 TEST_F(SpvParserTest, ErrStorageBarrierInvalidMemory) {
-  auto program = ParseAndBuild(R"(
+    auto program = ParseAndBuild(R"(
        %void = OpTypeVoid
           %1 = OpTypeFunction %void
        %uint = OpTypeInt 32 0
@@ -200,9 +196,9 @@
                OpReturn
                OpFunctionEnd
   )");
-  EXPECT_FALSE(program.IsValid());
-  EXPECT_THAT(program.Diagnostics().str(),
-              HasSubstr("storageBarrier requires device memory scope"));
+    EXPECT_FALSE(program.IsValid());
+    EXPECT_THAT(program.Diagnostics().str(),
+                HasSubstr("storageBarrier requires device memory scope"));
 }
 
 }  // namespace
diff --git a/src/tint/reader/spirv/parser_impl_convert_member_decoration_test.cc b/src/tint/reader/spirv/parser_impl_convert_member_decoration_test.cc
index adc3397..3147ac1 100644
--- a/src/tint/reader/spirv/parser_impl_convert_member_decoration_test.cc
+++ b/src/tint/reader/spirv/parser_impl_convert_member_decoration_test.cc
@@ -21,132 +21,123 @@
 using ::testing::Eq;
 
 TEST_F(SpvParserTest, ConvertMemberDecoration_Empty) {
-  auto p = parser(std::vector<uint32_t>{});
+    auto p = parser(std::vector<uint32_t>{});
 
-  auto result = p->ConvertMemberDecoration(1, 1, nullptr, {});
-  EXPECT_TRUE(result.empty());
-  EXPECT_THAT(p->error(), Eq("malformed SPIR-V decoration: it's empty"));
+    auto result = p->ConvertMemberDecoration(1, 1, nullptr, {});
+    EXPECT_TRUE(result.empty());
+    EXPECT_THAT(p->error(), Eq("malformed SPIR-V decoration: it's empty"));
 }
 
 TEST_F(SpvParserTest, ConvertMemberDecoration_OffsetWithoutOperand) {
-  auto p = parser(std::vector<uint32_t>{});
+    auto p = parser(std::vector<uint32_t>{});
 
-  auto result =
-      p->ConvertMemberDecoration(12, 13, nullptr, {SpvDecorationOffset});
-  EXPECT_TRUE(result.empty());
-  EXPECT_THAT(p->error(), Eq("malformed Offset decoration: expected 1 literal "
-                             "operand, has 0: member 13 of SPIR-V type 12"));
+    auto result = p->ConvertMemberDecoration(12, 13, nullptr, {SpvDecorationOffset});
+    EXPECT_TRUE(result.empty());
+    EXPECT_THAT(p->error(), Eq("malformed Offset decoration: expected 1 literal "
+                               "operand, has 0: member 13 of SPIR-V type 12"));
 }
 
 TEST_F(SpvParserTest, ConvertMemberDecoration_OffsetWithTooManyOperands) {
-  auto p = parser(std::vector<uint32_t>{});
+    auto p = parser(std::vector<uint32_t>{});
 
-  auto result =
-      p->ConvertMemberDecoration(12, 13, nullptr, {SpvDecorationOffset, 3, 4});
-  EXPECT_TRUE(result.empty());
-  EXPECT_THAT(p->error(), Eq("malformed Offset decoration: expected 1 literal "
-                             "operand, has 2: member 13 of SPIR-V type 12"));
+    auto result = p->ConvertMemberDecoration(12, 13, nullptr, {SpvDecorationOffset, 3, 4});
+    EXPECT_TRUE(result.empty());
+    EXPECT_THAT(p->error(), Eq("malformed Offset decoration: expected 1 literal "
+                               "operand, has 2: member 13 of SPIR-V type 12"));
 }
 
 TEST_F(SpvParserTest, ConvertMemberDecoration_Offset) {
-  auto p = parser(std::vector<uint32_t>{});
+    auto p = parser(std::vector<uint32_t>{});
 
-  auto result =
-      p->ConvertMemberDecoration(1, 1, nullptr, {SpvDecorationOffset, 8});
-  ASSERT_FALSE(result.empty());
-  EXPECT_TRUE(result[0]->Is<ast::StructMemberOffsetAttribute>());
-  auto* offset_deco = result[0]->As<ast::StructMemberOffsetAttribute>();
-  ASSERT_NE(offset_deco, nullptr);
-  EXPECT_EQ(offset_deco->offset, 8u);
-  EXPECT_TRUE(p->error().empty());
+    auto result = p->ConvertMemberDecoration(1, 1, nullptr, {SpvDecorationOffset, 8});
+    ASSERT_FALSE(result.empty());
+    EXPECT_TRUE(result[0]->Is<ast::StructMemberOffsetAttribute>());
+    auto* offset_deco = result[0]->As<ast::StructMemberOffsetAttribute>();
+    ASSERT_NE(offset_deco, nullptr);
+    EXPECT_EQ(offset_deco->offset, 8u);
+    EXPECT_TRUE(p->error().empty());
 }
 
 TEST_F(SpvParserTest, ConvertMemberDecoration_Matrix2x2_Stride_Natural) {
-  auto p = parser(std::vector<uint32_t>{});
+    auto p = parser(std::vector<uint32_t>{});
 
-  spirv::F32 f32;
-  spirv::Matrix matrix(&f32, 2, 2);
-  auto result =
-      p->ConvertMemberDecoration(1, 1, &matrix, {SpvDecorationMatrixStride, 8});
-  EXPECT_TRUE(result.empty());
-  EXPECT_TRUE(p->error().empty());
+    spirv::F32 f32;
+    spirv::Matrix matrix(&f32, 2, 2);
+    auto result = p->ConvertMemberDecoration(1, 1, &matrix, {SpvDecorationMatrixStride, 8});
+    EXPECT_TRUE(result.empty());
+    EXPECT_TRUE(p->error().empty());
 }
 
 TEST_F(SpvParserTest, ConvertMemberDecoration_Matrix2x2_Stride_Custom) {
-  auto p = parser(std::vector<uint32_t>{});
+    auto p = parser(std::vector<uint32_t>{});
 
-  spirv::F32 f32;
-  spirv::Matrix matrix(&f32, 2, 2);
-  auto result = p->ConvertMemberDecoration(1, 1, &matrix,
-                                           {SpvDecorationMatrixStride, 16});
-  ASSERT_FALSE(result.empty());
-  EXPECT_TRUE(result[0]->Is<ast::StrideAttribute>());
-  auto* stride_deco = result[0]->As<ast::StrideAttribute>();
-  ASSERT_NE(stride_deco, nullptr);
-  EXPECT_EQ(stride_deco->stride, 16u);
-  EXPECT_TRUE(p->error().empty());
+    spirv::F32 f32;
+    spirv::Matrix matrix(&f32, 2, 2);
+    auto result = p->ConvertMemberDecoration(1, 1, &matrix, {SpvDecorationMatrixStride, 16});
+    ASSERT_FALSE(result.empty());
+    EXPECT_TRUE(result[0]->Is<ast::StrideAttribute>());
+    auto* stride_deco = result[0]->As<ast::StrideAttribute>();
+    ASSERT_NE(stride_deco, nullptr);
+    EXPECT_EQ(stride_deco->stride, 16u);
+    EXPECT_TRUE(p->error().empty());
 }
 
 TEST_F(SpvParserTest, ConvertMemberDecoration_Matrix2x4_Stride_Natural) {
-  auto p = parser(std::vector<uint32_t>{});
+    auto p = parser(std::vector<uint32_t>{});
 
-  spirv::F32 f32;
-  spirv::Matrix matrix(&f32, 2, 4);
-  auto result = p->ConvertMemberDecoration(1, 1, &matrix,
-                                           {SpvDecorationMatrixStride, 16});
-  EXPECT_TRUE(result.empty());
-  EXPECT_TRUE(p->error().empty());
+    spirv::F32 f32;
+    spirv::Matrix matrix(&f32, 2, 4);
+    auto result = p->ConvertMemberDecoration(1, 1, &matrix, {SpvDecorationMatrixStride, 16});
+    EXPECT_TRUE(result.empty());
+    EXPECT_TRUE(p->error().empty());
 }
 
 TEST_F(SpvParserTest, ConvertMemberDecoration_Matrix2x4_Stride_Custom) {
-  auto p = parser(std::vector<uint32_t>{});
+    auto p = parser(std::vector<uint32_t>{});
 
-  spirv::F32 f32;
-  spirv::Matrix matrix(&f32, 2, 4);
-  auto result = p->ConvertMemberDecoration(1, 1, &matrix,
-                                           {SpvDecorationMatrixStride, 64});
-  ASSERT_FALSE(result.empty());
-  EXPECT_TRUE(result[0]->Is<ast::StrideAttribute>());
-  auto* stride_deco = result[0]->As<ast::StrideAttribute>();
-  ASSERT_NE(stride_deco, nullptr);
-  EXPECT_EQ(stride_deco->stride, 64u);
-  EXPECT_TRUE(p->error().empty());
+    spirv::F32 f32;
+    spirv::Matrix matrix(&f32, 2, 4);
+    auto result = p->ConvertMemberDecoration(1, 1, &matrix, {SpvDecorationMatrixStride, 64});
+    ASSERT_FALSE(result.empty());
+    EXPECT_TRUE(result[0]->Is<ast::StrideAttribute>());
+    auto* stride_deco = result[0]->As<ast::StrideAttribute>();
+    ASSERT_NE(stride_deco, nullptr);
+    EXPECT_EQ(stride_deco->stride, 64u);
+    EXPECT_TRUE(p->error().empty());
 }
 
 TEST_F(SpvParserTest, ConvertMemberDecoration_Matrix2x3_Stride_Custom) {
-  auto p = parser(std::vector<uint32_t>{});
+    auto p = parser(std::vector<uint32_t>{});
 
-  spirv::F32 f32;
-  spirv::Matrix matrix(&f32, 2, 3);
-  auto result = p->ConvertMemberDecoration(1, 1, &matrix,
-                                           {SpvDecorationMatrixStride, 32});
-  ASSERT_FALSE(result.empty());
-  EXPECT_TRUE(result[0]->Is<ast::StrideAttribute>());
-  auto* stride_deco = result[0]->As<ast::StrideAttribute>();
-  ASSERT_NE(stride_deco, nullptr);
-  EXPECT_EQ(stride_deco->stride, 32u);
-  EXPECT_TRUE(p->error().empty());
+    spirv::F32 f32;
+    spirv::Matrix matrix(&f32, 2, 3);
+    auto result = p->ConvertMemberDecoration(1, 1, &matrix, {SpvDecorationMatrixStride, 32});
+    ASSERT_FALSE(result.empty());
+    EXPECT_TRUE(result[0]->Is<ast::StrideAttribute>());
+    auto* stride_deco = result[0]->As<ast::StrideAttribute>();
+    ASSERT_NE(stride_deco, nullptr);
+    EXPECT_EQ(stride_deco->stride, 32u);
+    EXPECT_TRUE(p->error().empty());
 }
 
 TEST_F(SpvParserTest, ConvertMemberDecoration_RelaxedPrecision) {
-  // WGSL does not support relaxed precision. Drop it.
-  // It's functionally correct to use full precision f32 instead of
-  // relaxed precision f32.
-  auto p = parser(std::vector<uint32_t>{});
+    // WGSL does not support relaxed precision. Drop it.
+    // It's functionally correct to use full precision f32 instead of
+    // relaxed precision f32.
+    auto p = parser(std::vector<uint32_t>{});
 
-  auto result = p->ConvertMemberDecoration(1, 1, nullptr,
-                                           {SpvDecorationRelaxedPrecision});
-  EXPECT_TRUE(result.empty());
-  EXPECT_TRUE(p->error().empty());
+    auto result = p->ConvertMemberDecoration(1, 1, nullptr, {SpvDecorationRelaxedPrecision});
+    EXPECT_TRUE(result.empty());
+    EXPECT_TRUE(p->error().empty());
 }
 
 TEST_F(SpvParserTest, ConvertMemberDecoration_UnhandledDecoration) {
-  auto p = parser(std::vector<uint32_t>{});
+    auto p = parser(std::vector<uint32_t>{});
 
-  auto result = p->ConvertMemberDecoration(12, 13, nullptr, {12345678});
-  EXPECT_TRUE(result.empty());
-  EXPECT_THAT(p->error(), Eq("unhandled member decoration: 12345678 on member "
-                             "13 of SPIR-V type 12"));
+    auto result = p->ConvertMemberDecoration(12, 13, nullptr, {12345678});
+    EXPECT_TRUE(result.empty());
+    EXPECT_THAT(p->error(), Eq("unhandled member decoration: 12345678 on member "
+                               "13 of SPIR-V type 12"));
 }
 
 }  // namespace
diff --git a/src/tint/reader/spirv/parser_impl_convert_type_test.cc b/src/tint/reader/spirv/parser_impl_convert_type_test.cc
index bbda414..6cedddb 100644
--- a/src/tint/reader/spirv/parser_impl_convert_type_test.cc
+++ b/src/tint/reader/spirv/parser_impl_convert_type_test.cc
@@ -22,7 +22,7 @@
 using ::testing::Eq;
 
 std::string Preamble() {
-  return R"(
+    return R"(
     OpCapability Shader
     OpMemoryModel Logical Simple
     OpEntryPoint Fragment %main "x_100"
@@ -31,7 +31,7 @@
 }
 
 std::string MainBody() {
-  return R"(
+    return R"(
     %void = OpTypeVoid
     %voidfn = OpTypeFunction %void
     %main = OpFunction %void None %voidfn
@@ -42,244 +42,235 @@
 }
 
 TEST_F(SpvParserTest, ConvertType_PreservesExistingFailure) {
-  auto p = parser(std::vector<uint32_t>{});
-  p->Fail() << "boing";
-  auto* type = p->ConvertType(10);
-  EXPECT_EQ(type, nullptr);
-  EXPECT_THAT(p->error(), Eq("boing"));
+    auto p = parser(std::vector<uint32_t>{});
+    p->Fail() << "boing";
+    auto* type = p->ConvertType(10);
+    EXPECT_EQ(type, nullptr);
+    EXPECT_THAT(p->error(), Eq("boing"));
 }
 
 TEST_F(SpvParserTest, ConvertType_RequiresInternalRepresntation) {
-  auto p = parser(std::vector<uint32_t>{});
-  auto* type = p->ConvertType(10);
-  EXPECT_EQ(type, nullptr);
-  EXPECT_THAT(
-      p->error(),
-      Eq("ConvertType called when the internal module has not been built"));
+    auto p = parser(std::vector<uint32_t>{});
+    auto* type = p->ConvertType(10);
+    EXPECT_EQ(type, nullptr);
+    EXPECT_THAT(p->error(), Eq("ConvertType called when the internal module has not been built"));
 }
 
 TEST_F(SpvParserTest, ConvertType_NotAnId) {
-  auto assembly = Preamble() + MainBody();
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_TRUE(p->BuildInternalModule());
+    auto assembly = Preamble() + MainBody();
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_TRUE(p->BuildInternalModule());
 
-  auto* type = p->ConvertType(900);
-  EXPECT_EQ(type, nullptr);
-  EXPECT_EQ(nullptr, type);
-  EXPECT_THAT(p->error(), Eq("ID is not a SPIR-V type: 900"));
+    auto* type = p->ConvertType(900);
+    EXPECT_EQ(type, nullptr);
+    EXPECT_EQ(nullptr, type);
+    EXPECT_THAT(p->error(), Eq("ID is not a SPIR-V type: 900"));
 }
 
 TEST_F(SpvParserTest, ConvertType_IdExistsButIsNotAType) {
-  auto assembly = R"(
+    auto assembly = R"(
      OpCapability Shader
      %1 = OpExtInstImport "GLSL.std.450"
      OpMemoryModel Logical Simple
      OpEntryPoint Fragment %main "x_100"
      OpExecutionMode %main OriginUpperLeft
 )" + MainBody();
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_TRUE(p->BuildInternalModule());
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_TRUE(p->BuildInternalModule());
 
-  auto* type = p->ConvertType(1);
-  EXPECT_EQ(nullptr, type);
-  EXPECT_THAT(p->error(), Eq("ID is not a SPIR-V type: 1"));
+    auto* type = p->ConvertType(1);
+    EXPECT_EQ(nullptr, type);
+    EXPECT_THAT(p->error(), Eq("ID is not a SPIR-V type: 1"));
 }
 
 TEST_F(SpvParserTest, ConvertType_UnhandledType) {
-  // Pipes are an OpenCL type. Tint doesn't support them.
-  auto p = parser(test::Assemble("%70 = OpTypePipe WriteOnly"));
-  EXPECT_TRUE(p->BuildInternalModule());
+    // Pipes are an OpenCL type. Tint doesn't support them.
+    auto p = parser(test::Assemble("%70 = OpTypePipe WriteOnly"));
+    EXPECT_TRUE(p->BuildInternalModule());
 
-  auto* type = p->ConvertType(70);
-  EXPECT_EQ(nullptr, type);
-  EXPECT_THAT(p->error(),
-              Eq("unknown SPIR-V type with ID 70: %70 = OpTypePipe WriteOnly"));
+    auto* type = p->ConvertType(70);
+    EXPECT_EQ(nullptr, type);
+    EXPECT_THAT(p->error(), Eq("unknown SPIR-V type with ID 70: %70 = OpTypePipe WriteOnly"));
 }
 
 TEST_F(SpvParserTest, ConvertType_Void) {
-  auto p = parser(test::Assemble(Preamble() + "%1 = OpTypeVoid" + R"(
+    auto p = parser(test::Assemble(Preamble() + "%1 = OpTypeVoid" + R"(
    %voidfn = OpTypeFunction %1
    %main = OpFunction %1 None %voidfn
    %entry = OpLabel
    OpReturn
    OpFunctionEnd
   )"));
-  EXPECT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->BuildInternalModule());
 
-  auto* type = p->ConvertType(1);
-  EXPECT_TRUE(type->Is<Void>());
-  EXPECT_TRUE(p->error().empty());
+    auto* type = p->ConvertType(1);
+    EXPECT_TRUE(type->Is<Void>());
+    EXPECT_TRUE(p->error().empty());
 }
 
 TEST_F(SpvParserTest, ConvertType_Bool) {
-  auto p =
-      parser(test::Assemble(Preamble() + "%100 = OpTypeBool" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
+    auto p = parser(test::Assemble(Preamble() + "%100 = OpTypeBool" + MainBody()));
+    EXPECT_TRUE(p->BuildInternalModule());
 
-  auto* type = p->ConvertType(100);
-  EXPECT_TRUE(type->Is<Bool>());
-  EXPECT_TRUE(p->error().empty());
+    auto* type = p->ConvertType(100);
+    EXPECT_TRUE(type->Is<Bool>());
+    EXPECT_TRUE(p->error().empty());
 }
 
 TEST_F(SpvParserTest, ConvertType_I32) {
-  auto p =
-      parser(test::Assemble(Preamble() + "%2 = OpTypeInt 32 1" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
+    auto p = parser(test::Assemble(Preamble() + "%2 = OpTypeInt 32 1" + MainBody()));
+    EXPECT_TRUE(p->BuildInternalModule());
 
-  auto* type = p->ConvertType(2);
-  EXPECT_TRUE(type->Is<I32>());
-  EXPECT_TRUE(p->error().empty());
+    auto* type = p->ConvertType(2);
+    EXPECT_TRUE(type->Is<I32>());
+    EXPECT_TRUE(p->error().empty());
 }
 
 TEST_F(SpvParserTest, ConvertType_U32) {
-  auto p =
-      parser(test::Assemble(Preamble() + "%3 = OpTypeInt 32 0" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
+    auto p = parser(test::Assemble(Preamble() + "%3 = OpTypeInt 32 0" + MainBody()));
+    EXPECT_TRUE(p->BuildInternalModule());
 
-  auto* type = p->ConvertType(3);
-  EXPECT_TRUE(type->Is<U32>());
-  EXPECT_TRUE(p->error().empty());
+    auto* type = p->ConvertType(3);
+    EXPECT_TRUE(type->Is<U32>());
+    EXPECT_TRUE(p->error().empty());
 }
 
 TEST_F(SpvParserTest, ConvertType_F32) {
-  auto p =
-      parser(test::Assemble(Preamble() + "%4 = OpTypeFloat 32" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
+    auto p = parser(test::Assemble(Preamble() + "%4 = OpTypeFloat 32" + MainBody()));
+    EXPECT_TRUE(p->BuildInternalModule());
 
-  auto* type = p->ConvertType(4);
-  EXPECT_TRUE(type->Is<F32>());
-  EXPECT_TRUE(p->error().empty());
+    auto* type = p->ConvertType(4);
+    EXPECT_TRUE(type->Is<F32>());
+    EXPECT_TRUE(p->error().empty());
 }
 
 TEST_F(SpvParserTest, ConvertType_BadIntWidth) {
-  auto p =
-      parser(test::Assemble(Preamble() + "%5 = OpTypeInt 17 1" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
+    auto p = parser(test::Assemble(Preamble() + "%5 = OpTypeInt 17 1" + MainBody()));
+    EXPECT_TRUE(p->BuildInternalModule());
 
-  auto* type = p->ConvertType(5);
-  EXPECT_EQ(type, nullptr);
-  EXPECT_THAT(p->error(), Eq("unhandled integer width: 17"));
+    auto* type = p->ConvertType(5);
+    EXPECT_EQ(type, nullptr);
+    EXPECT_THAT(p->error(), Eq("unhandled integer width: 17"));
 }
 
 TEST_F(SpvParserTest, ConvertType_BadFloatWidth) {
-  auto p =
-      parser(test::Assemble(Preamble() + "%6 = OpTypeFloat 19" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
+    auto p = parser(test::Assemble(Preamble() + "%6 = OpTypeFloat 19" + MainBody()));
+    EXPECT_TRUE(p->BuildInternalModule());
 
-  auto* type = p->ConvertType(6);
-  EXPECT_EQ(type, nullptr);
-  EXPECT_THAT(p->error(), Eq("unhandled float width: 19"));
+    auto* type = p->ConvertType(6);
+    EXPECT_EQ(type, nullptr);
+    EXPECT_THAT(p->error(), Eq("unhandled float width: 19"));
 }
 
 TEST_F(SpvParserTest, DISABLED_ConvertType_InvalidVectorElement) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
     %5 = OpTypePipe ReadOnly
     %20 = OpTypeVector %5 2
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->BuildInternalModule());
 
-  auto* type = p->ConvertType(20);
-  EXPECT_EQ(type, nullptr);
-  EXPECT_THAT(p->error(), Eq("unknown SPIR-V type: 5"));
+    auto* type = p->ConvertType(20);
+    EXPECT_EQ(type, nullptr);
+    EXPECT_THAT(p->error(), Eq("unknown SPIR-V type: 5"));
 }
 
 TEST_F(SpvParserTest, ConvertType_VecOverF32) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
     %float = OpTypeFloat 32
     %20 = OpTypeVector %float 2
     %30 = OpTypeVector %float 3
     %40 = OpTypeVector %float 4
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->BuildInternalModule());
 
-  auto* v2xf32 = p->ConvertType(20);
-  EXPECT_TRUE(v2xf32->Is<Vector>());
-  EXPECT_TRUE(v2xf32->As<Vector>()->type->Is<F32>());
-  EXPECT_EQ(v2xf32->As<Vector>()->size, 2u);
+    auto* v2xf32 = p->ConvertType(20);
+    EXPECT_TRUE(v2xf32->Is<Vector>());
+    EXPECT_TRUE(v2xf32->As<Vector>()->type->Is<F32>());
+    EXPECT_EQ(v2xf32->As<Vector>()->size, 2u);
 
-  auto* v3xf32 = p->ConvertType(30);
-  EXPECT_TRUE(v3xf32->Is<Vector>());
-  EXPECT_TRUE(v3xf32->As<Vector>()->type->Is<F32>());
-  EXPECT_EQ(v3xf32->As<Vector>()->size, 3u);
+    auto* v3xf32 = p->ConvertType(30);
+    EXPECT_TRUE(v3xf32->Is<Vector>());
+    EXPECT_TRUE(v3xf32->As<Vector>()->type->Is<F32>());
+    EXPECT_EQ(v3xf32->As<Vector>()->size, 3u);
 
-  auto* v4xf32 = p->ConvertType(40);
-  EXPECT_TRUE(v4xf32->Is<Vector>());
-  EXPECT_TRUE(v4xf32->As<Vector>()->type->Is<F32>());
-  EXPECT_EQ(v4xf32->As<Vector>()->size, 4u);
+    auto* v4xf32 = p->ConvertType(40);
+    EXPECT_TRUE(v4xf32->Is<Vector>());
+    EXPECT_TRUE(v4xf32->As<Vector>()->type->Is<F32>());
+    EXPECT_EQ(v4xf32->As<Vector>()->size, 4u);
 
-  EXPECT_TRUE(p->error().empty());
+    EXPECT_TRUE(p->error().empty());
 }
 
 TEST_F(SpvParserTest, ConvertType_VecOverI32) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
     %int = OpTypeInt 32 1
     %20 = OpTypeVector %int 2
     %30 = OpTypeVector %int 3
     %40 = OpTypeVector %int 4
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->BuildInternalModule());
 
-  auto* v2xi32 = p->ConvertType(20);
-  EXPECT_TRUE(v2xi32->Is<Vector>());
-  EXPECT_TRUE(v2xi32->As<Vector>()->type->Is<I32>());
-  EXPECT_EQ(v2xi32->As<Vector>()->size, 2u);
+    auto* v2xi32 = p->ConvertType(20);
+    EXPECT_TRUE(v2xi32->Is<Vector>());
+    EXPECT_TRUE(v2xi32->As<Vector>()->type->Is<I32>());
+    EXPECT_EQ(v2xi32->As<Vector>()->size, 2u);
 
-  auto* v3xi32 = p->ConvertType(30);
-  EXPECT_TRUE(v3xi32->Is<Vector>());
-  EXPECT_TRUE(v3xi32->As<Vector>()->type->Is<I32>());
-  EXPECT_EQ(v3xi32->As<Vector>()->size, 3u);
+    auto* v3xi32 = p->ConvertType(30);
+    EXPECT_TRUE(v3xi32->Is<Vector>());
+    EXPECT_TRUE(v3xi32->As<Vector>()->type->Is<I32>());
+    EXPECT_EQ(v3xi32->As<Vector>()->size, 3u);
 
-  auto* v4xi32 = p->ConvertType(40);
-  EXPECT_TRUE(v4xi32->Is<Vector>());
-  EXPECT_TRUE(v4xi32->As<Vector>()->type->Is<I32>());
-  EXPECT_EQ(v4xi32->As<Vector>()->size, 4u);
+    auto* v4xi32 = p->ConvertType(40);
+    EXPECT_TRUE(v4xi32->Is<Vector>());
+    EXPECT_TRUE(v4xi32->As<Vector>()->type->Is<I32>());
+    EXPECT_EQ(v4xi32->As<Vector>()->size, 4u);
 
-  EXPECT_TRUE(p->error().empty());
+    EXPECT_TRUE(p->error().empty());
 }
 
 TEST_F(SpvParserTest, ConvertType_VecOverU32) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
     %uint = OpTypeInt 32 0
     %20 = OpTypeVector %uint 2
     %30 = OpTypeVector %uint 3
     %40 = OpTypeVector %uint 4
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->BuildInternalModule());
 
-  auto* v2xu32 = p->ConvertType(20);
-  EXPECT_TRUE(v2xu32->Is<Vector>());
-  EXPECT_TRUE(v2xu32->As<Vector>()->type->Is<U32>());
-  EXPECT_EQ(v2xu32->As<Vector>()->size, 2u);
+    auto* v2xu32 = p->ConvertType(20);
+    EXPECT_TRUE(v2xu32->Is<Vector>());
+    EXPECT_TRUE(v2xu32->As<Vector>()->type->Is<U32>());
+    EXPECT_EQ(v2xu32->As<Vector>()->size, 2u);
 
-  auto* v3xu32 = p->ConvertType(30);
-  EXPECT_TRUE(v3xu32->Is<Vector>());
-  EXPECT_TRUE(v3xu32->As<Vector>()->type->Is<U32>());
-  EXPECT_EQ(v3xu32->As<Vector>()->size, 3u);
+    auto* v3xu32 = p->ConvertType(30);
+    EXPECT_TRUE(v3xu32->Is<Vector>());
+    EXPECT_TRUE(v3xu32->As<Vector>()->type->Is<U32>());
+    EXPECT_EQ(v3xu32->As<Vector>()->size, 3u);
 
-  auto* v4xu32 = p->ConvertType(40);
-  EXPECT_TRUE(v4xu32->Is<Vector>());
-  EXPECT_TRUE(v4xu32->As<Vector>()->type->Is<U32>());
-  EXPECT_EQ(v4xu32->As<Vector>()->size, 4u);
+    auto* v4xu32 = p->ConvertType(40);
+    EXPECT_TRUE(v4xu32->Is<Vector>());
+    EXPECT_TRUE(v4xu32->As<Vector>()->type->Is<U32>());
+    EXPECT_EQ(v4xu32->As<Vector>()->size, 4u);
 
-  EXPECT_TRUE(p->error().empty());
+    EXPECT_TRUE(p->error().empty());
 }
 
 TEST_F(SpvParserTest, DISABLED_ConvertType_InvalidMatrixElement) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
     %5 = OpTypePipe ReadOnly
     %10 = OpTypeVector %5 2
     %20 = OpTypeMatrix %10 2
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->BuildInternalModule());
 
-  auto* type = p->ConvertType(20);
-  EXPECT_EQ(type, nullptr);
-  EXPECT_THAT(p->error(), Eq("unknown SPIR-V type: 5"));
+    auto* type = p->ConvertType(20);
+    EXPECT_EQ(type, nullptr);
+    EXPECT_THAT(p->error(), Eq("unknown SPIR-V type: 5"));
 }
 
 TEST_F(SpvParserTest, ConvertType_MatrixOverF32) {
-  // Matrices are only defined over floats.
-  auto p = parser(test::Assemble(Preamble() + R"(
+    // Matrices are only defined over floats.
+    auto p = parser(test::Assemble(Preamble() + R"(
     %float = OpTypeFloat 32
     %v2 = OpTypeVector %float 2
     %v3 = OpTypeVector %float 3
@@ -296,176 +287,172 @@
     %43 = OpTypeMatrix %v4 3
     %44 = OpTypeMatrix %v4 4
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->BuildInternalModule());
 
-  auto* m22 = p->ConvertType(22);
-  EXPECT_TRUE(m22->Is<Matrix>());
-  EXPECT_TRUE(m22->As<Matrix>()->type->Is<F32>());
-  EXPECT_EQ(m22->As<Matrix>()->rows, 2u);
-  EXPECT_EQ(m22->As<Matrix>()->columns, 2u);
+    auto* m22 = p->ConvertType(22);
+    EXPECT_TRUE(m22->Is<Matrix>());
+    EXPECT_TRUE(m22->As<Matrix>()->type->Is<F32>());
+    EXPECT_EQ(m22->As<Matrix>()->rows, 2u);
+    EXPECT_EQ(m22->As<Matrix>()->columns, 2u);
 
-  auto* m23 = p->ConvertType(23);
-  EXPECT_TRUE(m23->Is<Matrix>());
-  EXPECT_TRUE(m23->As<Matrix>()->type->Is<F32>());
-  EXPECT_EQ(m23->As<Matrix>()->rows, 2u);
-  EXPECT_EQ(m23->As<Matrix>()->columns, 3u);
+    auto* m23 = p->ConvertType(23);
+    EXPECT_TRUE(m23->Is<Matrix>());
+    EXPECT_TRUE(m23->As<Matrix>()->type->Is<F32>());
+    EXPECT_EQ(m23->As<Matrix>()->rows, 2u);
+    EXPECT_EQ(m23->As<Matrix>()->columns, 3u);
 
-  auto* m24 = p->ConvertType(24);
-  EXPECT_TRUE(m24->Is<Matrix>());
-  EXPECT_TRUE(m24->As<Matrix>()->type->Is<F32>());
-  EXPECT_EQ(m24->As<Matrix>()->rows, 2u);
-  EXPECT_EQ(m24->As<Matrix>()->columns, 4u);
+    auto* m24 = p->ConvertType(24);
+    EXPECT_TRUE(m24->Is<Matrix>());
+    EXPECT_TRUE(m24->As<Matrix>()->type->Is<F32>());
+    EXPECT_EQ(m24->As<Matrix>()->rows, 2u);
+    EXPECT_EQ(m24->As<Matrix>()->columns, 4u);
 
-  auto* m32 = p->ConvertType(32);
-  EXPECT_TRUE(m32->Is<Matrix>());
-  EXPECT_TRUE(m32->As<Matrix>()->type->Is<F32>());
-  EXPECT_EQ(m32->As<Matrix>()->rows, 3u);
-  EXPECT_EQ(m32->As<Matrix>()->columns, 2u);
+    auto* m32 = p->ConvertType(32);
+    EXPECT_TRUE(m32->Is<Matrix>());
+    EXPECT_TRUE(m32->As<Matrix>()->type->Is<F32>());
+    EXPECT_EQ(m32->As<Matrix>()->rows, 3u);
+    EXPECT_EQ(m32->As<Matrix>()->columns, 2u);
 
-  auto* m33 = p->ConvertType(33);
-  EXPECT_TRUE(m33->Is<Matrix>());
-  EXPECT_TRUE(m33->As<Matrix>()->type->Is<F32>());
-  EXPECT_EQ(m33->As<Matrix>()->rows, 3u);
-  EXPECT_EQ(m33->As<Matrix>()->columns, 3u);
+    auto* m33 = p->ConvertType(33);
+    EXPECT_TRUE(m33->Is<Matrix>());
+    EXPECT_TRUE(m33->As<Matrix>()->type->Is<F32>());
+    EXPECT_EQ(m33->As<Matrix>()->rows, 3u);
+    EXPECT_EQ(m33->As<Matrix>()->columns, 3u);
 
-  auto* m34 = p->ConvertType(34);
-  EXPECT_TRUE(m34->Is<Matrix>());
-  EXPECT_TRUE(m34->As<Matrix>()->type->Is<F32>());
-  EXPECT_EQ(m34->As<Matrix>()->rows, 3u);
-  EXPECT_EQ(m34->As<Matrix>()->columns, 4u);
+    auto* m34 = p->ConvertType(34);
+    EXPECT_TRUE(m34->Is<Matrix>());
+    EXPECT_TRUE(m34->As<Matrix>()->type->Is<F32>());
+    EXPECT_EQ(m34->As<Matrix>()->rows, 3u);
+    EXPECT_EQ(m34->As<Matrix>()->columns, 4u);
 
-  auto* m42 = p->ConvertType(42);
-  EXPECT_TRUE(m42->Is<Matrix>());
-  EXPECT_TRUE(m42->As<Matrix>()->type->Is<F32>());
-  EXPECT_EQ(m42->As<Matrix>()->rows, 4u);
-  EXPECT_EQ(m42->As<Matrix>()->columns, 2u);
+    auto* m42 = p->ConvertType(42);
+    EXPECT_TRUE(m42->Is<Matrix>());
+    EXPECT_TRUE(m42->As<Matrix>()->type->Is<F32>());
+    EXPECT_EQ(m42->As<Matrix>()->rows, 4u);
+    EXPECT_EQ(m42->As<Matrix>()->columns, 2u);
 
-  auto* m43 = p->ConvertType(43);
-  EXPECT_TRUE(m43->Is<Matrix>());
-  EXPECT_TRUE(m43->As<Matrix>()->type->Is<F32>());
-  EXPECT_EQ(m43->As<Matrix>()->rows, 4u);
-  EXPECT_EQ(m43->As<Matrix>()->columns, 3u);
+    auto* m43 = p->ConvertType(43);
+    EXPECT_TRUE(m43->Is<Matrix>());
+    EXPECT_TRUE(m43->As<Matrix>()->type->Is<F32>());
+    EXPECT_EQ(m43->As<Matrix>()->rows, 4u);
+    EXPECT_EQ(m43->As<Matrix>()->columns, 3u);
 
-  auto* m44 = p->ConvertType(44);
-  EXPECT_TRUE(m44->Is<Matrix>());
-  EXPECT_TRUE(m44->As<Matrix>()->type->Is<F32>());
-  EXPECT_EQ(m44->As<Matrix>()->rows, 4u);
-  EXPECT_EQ(m44->As<Matrix>()->columns, 4u);
+    auto* m44 = p->ConvertType(44);
+    EXPECT_TRUE(m44->Is<Matrix>());
+    EXPECT_TRUE(m44->As<Matrix>()->type->Is<F32>());
+    EXPECT_EQ(m44->As<Matrix>()->rows, 4u);
+    EXPECT_EQ(m44->As<Matrix>()->columns, 4u);
 
-  EXPECT_TRUE(p->error().empty());
+    EXPECT_TRUE(p->error().empty());
 }
 
 TEST_F(SpvParserTest, ConvertType_RuntimeArray) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
     %uint = OpTypeInt 32 0
     %10 = OpTypeRuntimeArray %uint
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->BuildInternalModule());
 
-  auto* type = p->ConvertType(10);
-  ASSERT_NE(type, nullptr);
-  EXPECT_TRUE(type->UnwrapAll()->Is<Array>());
-  auto* arr_type = type->UnwrapAll()->As<Array>();
-  ASSERT_NE(arr_type, nullptr);
-  EXPECT_EQ(arr_type->size, 0u);
-  EXPECT_EQ(arr_type->stride, 0u);
-  auto* elem_type = arr_type->type;
-  ASSERT_NE(elem_type, nullptr);
-  EXPECT_TRUE(elem_type->Is<U32>());
-  EXPECT_TRUE(p->error().empty());
+    auto* type = p->ConvertType(10);
+    ASSERT_NE(type, nullptr);
+    EXPECT_TRUE(type->UnwrapAll()->Is<Array>());
+    auto* arr_type = type->UnwrapAll()->As<Array>();
+    ASSERT_NE(arr_type, nullptr);
+    EXPECT_EQ(arr_type->size, 0u);
+    EXPECT_EQ(arr_type->stride, 0u);
+    auto* elem_type = arr_type->type;
+    ASSERT_NE(elem_type, nullptr);
+    EXPECT_TRUE(elem_type->Is<U32>());
+    EXPECT_TRUE(p->error().empty());
 }
 
 TEST_F(SpvParserTest, ConvertType_RuntimeArray_InvalidDecoration) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
     OpDecorate %10 Block
     %uint = OpTypeInt 32 0
     %10 = OpTypeRuntimeArray %uint
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
-  auto* type = p->ConvertType(10);
-  EXPECT_EQ(type, nullptr);
-  EXPECT_THAT(
-      p->error(),
-      Eq("invalid array type ID 10: unknown decoration 2 with 1 total words"));
+    EXPECT_TRUE(p->BuildInternalModule());
+    auto* type = p->ConvertType(10);
+    EXPECT_EQ(type, nullptr);
+    EXPECT_THAT(p->error(),
+                Eq("invalid array type ID 10: unknown decoration 2 with 1 total words"));
 }
 
 TEST_F(SpvParserTest, ConvertType_RuntimeArray_ArrayStride_Valid) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
     OpDecorate %10 ArrayStride 64
     %uint = OpTypeInt 32 0
     %10 = OpTypeRuntimeArray %uint
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
-  auto* type = p->ConvertType(10);
-  ASSERT_NE(type, nullptr);
-  auto* arr_type = type->UnwrapAll()->As<Array>();
-  ASSERT_NE(arr_type, nullptr);
-  EXPECT_EQ(arr_type->size, 0u);
-  EXPECT_EQ(arr_type->stride, 64u);
+    EXPECT_TRUE(p->BuildInternalModule());
+    auto* type = p->ConvertType(10);
+    ASSERT_NE(type, nullptr);
+    auto* arr_type = type->UnwrapAll()->As<Array>();
+    ASSERT_NE(arr_type, nullptr);
+    EXPECT_EQ(arr_type->size, 0u);
+    EXPECT_EQ(arr_type->stride, 64u);
 }
 
 TEST_F(SpvParserTest, ConvertType_RuntimeArray_ArrayStride_ZeroIsError) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
     OpDecorate %10 ArrayStride 0
     %uint = OpTypeInt 32 0
     %10 = OpTypeRuntimeArray %uint
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
-  auto* type = p->ConvertType(10);
-  EXPECT_EQ(type, nullptr);
-  EXPECT_THAT(p->error(),
-              Eq("invalid array type ID 10: ArrayStride can't be 0"));
+    EXPECT_TRUE(p->BuildInternalModule());
+    auto* type = p->ConvertType(10);
+    EXPECT_EQ(type, nullptr);
+    EXPECT_THAT(p->error(), Eq("invalid array type ID 10: ArrayStride can't be 0"));
 }
 
 TEST_F(SpvParserTest, ConvertType_Array) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
     %uint = OpTypeInt 32 0
     %uint_42 = OpConstant %uint 42
     %10 = OpTypeArray %uint %uint_42
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->BuildInternalModule());
 
-  auto* type = p->ConvertType(10);
-  ASSERT_NE(type, nullptr);
-  EXPECT_TRUE(type->Is<Array>());
-  auto* arr_type = type->As<Array>();
-  ASSERT_NE(arr_type, nullptr);
-  EXPECT_EQ(arr_type->size, 42u);
-  EXPECT_EQ(arr_type->stride, 0u);
-  auto* elem_type = arr_type->type;
-  ASSERT_NE(elem_type, nullptr);
-  EXPECT_TRUE(elem_type->Is<U32>());
-  EXPECT_TRUE(p->error().empty());
+    auto* type = p->ConvertType(10);
+    ASSERT_NE(type, nullptr);
+    EXPECT_TRUE(type->Is<Array>());
+    auto* arr_type = type->As<Array>();
+    ASSERT_NE(arr_type, nullptr);
+    EXPECT_EQ(arr_type->size, 42u);
+    EXPECT_EQ(arr_type->stride, 0u);
+    auto* elem_type = arr_type->type;
+    ASSERT_NE(elem_type, nullptr);
+    EXPECT_TRUE(elem_type->Is<U32>());
+    EXPECT_TRUE(p->error().empty());
 }
 
 TEST_F(SpvParserTest, ConvertType_ArrayBadLengthIsSpecConstantValue) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
     OpDecorate %uint_42 SpecId 12
     %uint = OpTypeInt 32 0
     %uint_42 = OpSpecConstant %uint 42
     %10 = OpTypeArray %uint %uint_42
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->BuildInternalModule());
 
-  auto* type = p->ConvertType(10);
-  ASSERT_EQ(type, nullptr);
-  EXPECT_THAT(p->error(),
-              Eq("Array type 10 length is a specialization constant"));
+    auto* type = p->ConvertType(10);
+    ASSERT_EQ(type, nullptr);
+    EXPECT_THAT(p->error(), Eq("Array type 10 length is a specialization constant"));
 }
 
 TEST_F(SpvParserTest, ConvertType_ArrayBadLengthIsSpecConstantExpr) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
     %uint = OpTypeInt 32 0
     %uint_42 = OpConstant %uint 42
     %sum = OpSpecConstantOp %uint IAdd %uint_42 %uint_42
     %10 = OpTypeArray %uint %sum
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->BuildInternalModule());
 
-  auto* type = p->ConvertType(10);
-  ASSERT_EQ(type, nullptr);
-  EXPECT_THAT(p->error(),
-              Eq("Array type 10 length is a specialization constant"));
+    auto* type = p->ConvertType(10);
+    ASSERT_EQ(type, nullptr);
+    EXPECT_THAT(p->error(), Eq("Array type 10 length is a specialization constant"));
 }
 
 // TODO(dneto): Maybe add a test where the length operand is not a constant.
@@ -473,119 +460,117 @@
 // optimizer representation doesn't handle it and asserts out instead.
 
 TEST_F(SpvParserTest, ConvertType_ArrayBadTooBig) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
     %uint64 = OpTypeInt 64 0
     %uint64_big = OpConstant %uint64 5000000000
     %10 = OpTypeArray %uint64 %uint64_big
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->BuildInternalModule());
 
-  auto* type = p->ConvertType(10);
-  ASSERT_EQ(type, nullptr);
-  // TODO(dneto): Right now it's rejected earlier in the flow because
-  // we can't even utter the uint64 type.
-  EXPECT_THAT(p->error(), Eq("unhandled integer width: 64"));
+    auto* type = p->ConvertType(10);
+    ASSERT_EQ(type, nullptr);
+    // TODO(dneto): Right now it's rejected earlier in the flow because
+    // we can't even utter the uint64 type.
+    EXPECT_THAT(p->error(), Eq("unhandled integer width: 64"));
 }
 
 TEST_F(SpvParserTest, ConvertType_Array_InvalidDecoration) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
     OpDecorate %10 Block
     %uint = OpTypeInt 32 0
     %uint_5 = OpConstant %uint 5
     %10 = OpTypeArray %uint %uint_5
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
-  auto* type = p->ConvertType(10);
-  EXPECT_EQ(type, nullptr);
-  EXPECT_THAT(
-      p->error(),
-      Eq("invalid array type ID 10: unknown decoration 2 with 1 total words"));
+    EXPECT_TRUE(p->BuildInternalModule());
+    auto* type = p->ConvertType(10);
+    EXPECT_EQ(type, nullptr);
+    EXPECT_THAT(p->error(),
+                Eq("invalid array type ID 10: unknown decoration 2 with 1 total words"));
 }
 
 TEST_F(SpvParserTest, ConvertType_ArrayStride_Valid) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
     OpDecorate %10 ArrayStride 8
     %uint = OpTypeInt 32 0
     %uint_5 = OpConstant %uint 5
     %10 = OpTypeArray %uint %uint_5
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->BuildInternalModule());
 
-  auto* type = p->ConvertType(10);
-  ASSERT_NE(type, nullptr);
-  EXPECT_TRUE(type->UnwrapAll()->Is<Array>());
-  auto* arr_type = type->UnwrapAll()->As<Array>();
-  ASSERT_NE(arr_type, nullptr);
-  EXPECT_EQ(arr_type->stride, 8u);
-  EXPECT_TRUE(p->error().empty());
+    auto* type = p->ConvertType(10);
+    ASSERT_NE(type, nullptr);
+    EXPECT_TRUE(type->UnwrapAll()->Is<Array>());
+    auto* arr_type = type->UnwrapAll()->As<Array>();
+    ASSERT_NE(arr_type, nullptr);
+    EXPECT_EQ(arr_type->stride, 8u);
+    EXPECT_TRUE(p->error().empty());
 }
 
 TEST_F(SpvParserTest, ConvertType_ArrayStride_ZeroIsError) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
     OpDecorate %10 ArrayStride 0
     %uint = OpTypeInt 32 0
     %uint_5 = OpConstant %uint 5
     %10 = OpTypeArray %uint %uint_5
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->BuildInternalModule());
 
-  auto* type = p->ConvertType(10);
-  ASSERT_EQ(type, nullptr);
-  EXPECT_THAT(p->error(),
-              Eq("invalid array type ID 10: ArrayStride can't be 0"));
+    auto* type = p->ConvertType(10);
+    ASSERT_EQ(type, nullptr);
+    EXPECT_THAT(p->error(), Eq("invalid array type ID 10: ArrayStride can't be 0"));
 }
 
 TEST_F(SpvParserTest, ConvertType_StructEmpty) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
     %10 = OpTypeStruct
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->BuildInternalModule());
 
-  auto* type = p->ConvertType(10);
-  EXPECT_EQ(type, nullptr);
-  EXPECT_EQ(p->error(),
-            "WGSL does not support empty structures. can't convert type: %10 = "
-            "OpTypeStruct");
+    auto* type = p->ConvertType(10);
+    EXPECT_EQ(type, nullptr);
+    EXPECT_EQ(p->error(),
+              "WGSL does not support empty structures. can't convert type: %10 = "
+              "OpTypeStruct");
 }
 
 TEST_F(SpvParserTest, ConvertType_StructTwoMembers) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
     %uint = OpTypeInt 32 0
     %float = OpTypeFloat 32
     %10 = OpTypeStruct %uint %float
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
-  EXPECT_TRUE(p->RegisterUserAndStructMemberNames());
+    EXPECT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->RegisterUserAndStructMemberNames());
 
-  auto* type = p->ConvertType(10);
-  ASSERT_NE(type, nullptr);
-  EXPECT_TRUE(type->Is<Struct>());
+    auto* type = p->ConvertType(10);
+    ASSERT_NE(type, nullptr);
+    EXPECT_TRUE(type->Is<Struct>());
 
-  auto* str = type->Build(p->builder());
-  Program program = p->program();
-  EXPECT_EQ(test::ToString(program, str), "S");
+    auto* str = type->Build(p->builder());
+    Program program = p->program();
+    EXPECT_EQ(test::ToString(program, str), "S");
 }
 
 TEST_F(SpvParserTest, ConvertType_StructWithBlockDecoration) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
     OpDecorate %10 Block
     %uint = OpTypeInt 32 0
     %10 = OpTypeStruct %uint
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
-  EXPECT_TRUE(p->RegisterUserAndStructMemberNames());
+    EXPECT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->RegisterUserAndStructMemberNames());
 
-  auto* type = p->ConvertType(10);
-  ASSERT_NE(type, nullptr);
-  EXPECT_TRUE(type->Is<Struct>());
+    auto* type = p->ConvertType(10);
+    ASSERT_NE(type, nullptr);
+    EXPECT_TRUE(type->Is<Struct>());
 
-  auto* str = type->Build(p->builder());
-  Program program = p->program();
-  EXPECT_EQ(test::ToString(program, str), "S");
+    auto* str = type->Build(p->builder());
+    Program program = p->program();
+    EXPECT_EQ(test::ToString(program, str), "S");
 }
 
 TEST_F(SpvParserTest, ConvertType_StructWithMemberDecorations) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
     OpMemberDecorate %10 0 Offset 0
     OpMemberDecorate %10 1 Offset 8
     OpMemberDecorate %10 2 Offset 16
@@ -594,50 +579,50 @@
     %mat = OpTypeMatrix %vec 2
     %10 = OpTypeStruct %float %vec %mat
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
-  EXPECT_TRUE(p->RegisterUserAndStructMemberNames());
+    EXPECT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->RegisterUserAndStructMemberNames());
 
-  auto* type = p->ConvertType(10);
-  ASSERT_NE(type, nullptr);
-  EXPECT_TRUE(type->Is<Struct>());
+    auto* type = p->ConvertType(10);
+    ASSERT_NE(type, nullptr);
+    EXPECT_TRUE(type->Is<Struct>());
 
-  auto* str = type->Build(p->builder());
-  Program program = p->program();
-  EXPECT_EQ(test::ToString(program, str), "S");
+    auto* str = type->Build(p->builder());
+    Program program = p->program();
+    EXPECT_EQ(test::ToString(program, str), "S");
 }
 
 TEST_F(SpvParserTest, ConvertType_Struct_NoDeduplication) {
-  // Prove that distinct SPIR-V structs map to distinct WGSL types.
-  auto p = parser(test::Assemble(Preamble() + R"(
+    // Prove that distinct SPIR-V structs map to distinct WGSL types.
+    auto p = parser(test::Assemble(Preamble() + R"(
     %uint = OpTypeInt 32 0
     %10 = OpTypeStruct %uint
     %11 = OpTypeStruct %uint
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
 
-  auto* type10 = p->ConvertType(10);
-  ASSERT_NE(type10, nullptr);
-  EXPECT_TRUE(type10->Is<Struct>());
-  auto* struct_type10 = type10->As<Struct>();
-  ASSERT_NE(struct_type10, nullptr);
-  EXPECT_EQ(struct_type10->members.size(), 1u);
-  EXPECT_TRUE(struct_type10->members[0]->Is<U32>());
+    auto* type10 = p->ConvertType(10);
+    ASSERT_NE(type10, nullptr);
+    EXPECT_TRUE(type10->Is<Struct>());
+    auto* struct_type10 = type10->As<Struct>();
+    ASSERT_NE(struct_type10, nullptr);
+    EXPECT_EQ(struct_type10->members.size(), 1u);
+    EXPECT_TRUE(struct_type10->members[0]->Is<U32>());
 
-  auto* type11 = p->ConvertType(11);
-  ASSERT_NE(type11, nullptr);
-  EXPECT_TRUE(type11->Is<Struct>());
-  auto* struct_type11 = type11->As<Struct>();
-  ASSERT_NE(struct_type11, nullptr);
-  EXPECT_EQ(struct_type11->members.size(), 1u);
-  EXPECT_TRUE(struct_type11->members[0]->Is<U32>());
+    auto* type11 = p->ConvertType(11);
+    ASSERT_NE(type11, nullptr);
+    EXPECT_TRUE(type11->Is<Struct>());
+    auto* struct_type11 = type11->As<Struct>();
+    ASSERT_NE(struct_type11, nullptr);
+    EXPECT_EQ(struct_type11->members.size(), 1u);
+    EXPECT_TRUE(struct_type11->members[0]->Is<U32>());
 
-  // They map to distinct types in WGSL
-  EXPECT_NE(type11, type10);
+    // They map to distinct types in WGSL
+    EXPECT_NE(type11, type10);
 }
 
 TEST_F(SpvParserTest, ConvertType_Array_NoDeduplication) {
-  // Prove that distinct SPIR-V arrays map to distinct WGSL types.
-  auto assembly = Preamble() + R"(
+    // Prove that distinct SPIR-V arrays map to distinct WGSL types.
+    auto assembly = Preamble() + R"(
     %uint = OpTypeInt 32 0
     %10 = OpTypeStruct %uint
     %11 = OpTypeStruct %uint
@@ -645,26 +630,26 @@
     %20 = OpTypeArray %10 %uint_1
     %21 = OpTypeArray %11 %uint_1
   )" + MainBody();
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
 
-  auto* type20 = p->ConvertType(20);
-  ASSERT_NE(type20, nullptr);
-  EXPECT_TRUE(type20->Is<Array>());
+    auto* type20 = p->ConvertType(20);
+    ASSERT_NE(type20, nullptr);
+    EXPECT_TRUE(type20->Is<Array>());
 
-  auto* type21 = p->ConvertType(21);
-  ASSERT_NE(type21, nullptr);
-  EXPECT_TRUE(type21->Is<Array>());
+    auto* type21 = p->ConvertType(21);
+    ASSERT_NE(type21, nullptr);
+    EXPECT_TRUE(type21->Is<Array>());
 
-  // They map to distinct types in WGSL
-  EXPECT_NE(type21, type20);
+    // They map to distinct types in WGSL
+    EXPECT_NE(type21, type20);
 }
 
 TEST_F(SpvParserTest, ConvertType_RuntimeArray_NoDeduplication) {
-  // Prove that distinct SPIR-V runtime arrays map to distinct WGSL types.
-  // The implementation already de-duplicates them because it knows
-  // runtime-arrays normally have stride decorations.
-  auto assembly = Preamble() + R"(
+    // Prove that distinct SPIR-V runtime arrays map to distinct WGSL types.
+    // The implementation already de-duplicates them because it knows
+    // runtime-arrays normally have stride decorations.
+    auto assembly = Preamble() + R"(
     %uint = OpTypeInt 32 0
     %10 = OpTypeStruct %uint
     %11 = OpTypeStruct %uint
@@ -672,31 +657,31 @@
     %21 = OpTypeRuntimeArray %11
     %22 = OpTypeRuntimeArray %10
   )" + MainBody();
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
 
-  auto* type20 = p->ConvertType(20);
-  ASSERT_NE(type20, nullptr);
-  EXPECT_TRUE(type20->Is<Alias>());
-  EXPECT_TRUE(type20->UnwrapAll()->Is<Array>());
-  EXPECT_EQ(type20->UnwrapAll()->As<Array>()->size, 0u);
+    auto* type20 = p->ConvertType(20);
+    ASSERT_NE(type20, nullptr);
+    EXPECT_TRUE(type20->Is<Alias>());
+    EXPECT_TRUE(type20->UnwrapAll()->Is<Array>());
+    EXPECT_EQ(type20->UnwrapAll()->As<Array>()->size, 0u);
 
-  auto* type21 = p->ConvertType(21);
-  ASSERT_NE(type21, nullptr);
-  EXPECT_TRUE(type21->Is<Alias>());
-  EXPECT_TRUE(type21->UnwrapAll()->Is<Array>());
-  EXPECT_EQ(type21->UnwrapAll()->As<Array>()->size, 0u);
+    auto* type21 = p->ConvertType(21);
+    ASSERT_NE(type21, nullptr);
+    EXPECT_TRUE(type21->Is<Alias>());
+    EXPECT_TRUE(type21->UnwrapAll()->Is<Array>());
+    EXPECT_EQ(type21->UnwrapAll()->As<Array>()->size, 0u);
 
-  auto* type22 = p->ConvertType(22);
-  ASSERT_NE(type22, nullptr);
-  EXPECT_TRUE(type22->Is<Alias>());
-  EXPECT_TRUE(type22->UnwrapAll()->Is<Array>());
-  EXPECT_EQ(type22->UnwrapAll()->As<Array>()->size, 0u);
+    auto* type22 = p->ConvertType(22);
+    ASSERT_NE(type22, nullptr);
+    EXPECT_TRUE(type22->Is<Alias>());
+    EXPECT_TRUE(type22->UnwrapAll()->Is<Array>());
+    EXPECT_EQ(type22->UnwrapAll()->As<Array>()->size, 0u);
 
-  // They map to distinct types in WGSL
-  EXPECT_NE(type21, type20);
-  EXPECT_NE(type22, type21);
-  EXPECT_NE(type22, type20);
+    // They map to distinct types in WGSL
+    EXPECT_NE(type21, type20);
+    EXPECT_NE(type22, type21);
+    EXPECT_NE(type22, type20);
 }
 
 // TODO(dneto): Demonstrate other member decorations. Blocked on
@@ -705,8 +690,8 @@
 // crbug.com/tint/30
 
 TEST_F(SpvParserTest, ConvertType_InvalidPointeetype) {
-  // Disallow pointer-to-function
-  auto p = parser(test::Assemble(Preamble() + R"(
+    // Disallow pointer-to-function
+    auto p = parser(test::Assemble(Preamble() + R"(
   %void = OpTypeVoid
   %42 = OpTypeFunction %void
   %3 = OpTypePointer Input %42
@@ -717,214 +702,213 @@
 OpReturn
 OpFunctionEnd
   )"));
-  EXPECT_TRUE(p->BuildInternalModule()) << p->error();
+    EXPECT_TRUE(p->BuildInternalModule()) << p->error();
 
-  auto* type = p->ConvertType(3);
-  EXPECT_EQ(type, nullptr);
-  EXPECT_THAT(p->error(),
-              Eq("SPIR-V pointer type with ID 3 has invalid pointee type 42"));
+    auto* type = p->ConvertType(3);
+    EXPECT_EQ(type, nullptr);
+    EXPECT_THAT(p->error(), Eq("SPIR-V pointer type with ID 3 has invalid pointee type 42"));
 }
 
 TEST_F(SpvParserTest, DISABLED_ConvertType_InvalidStorageClass) {
-  // Disallow invalid storage class
-  auto p = parser(test::Assemble(Preamble() + R"(
+    // Disallow invalid storage class
+    auto p = parser(test::Assemble(Preamble() + R"(
   %1 = OpTypeFloat 32
   %3 = OpTypePointer !999 %1   ; Special syntax to inject 999 as the storage class
   )" + MainBody()));
-  // TODO(dneto): I can't get it past module building.
-  EXPECT_FALSE(p->BuildInternalModule()) << p->error();
+    // TODO(dneto): I can't get it past module building.
+    EXPECT_FALSE(p->BuildInternalModule()) << p->error();
 }
 
 TEST_F(SpvParserTest, ConvertType_PointerInput) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
   %float = OpTypeFloat 32
   %3 = OpTypePointer Input %float
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->BuildInternalModule());
 
-  auto* type = p->ConvertType(3);
-  EXPECT_TRUE(type->Is<Pointer>());
-  auto* ptr_ty = type->As<Pointer>();
-  EXPECT_NE(ptr_ty, nullptr);
-  EXPECT_TRUE(ptr_ty->type->Is<F32>());
-  EXPECT_EQ(ptr_ty->storage_class, ast::StorageClass::kPrivate);
-  EXPECT_TRUE(p->error().empty());
+    auto* type = p->ConvertType(3);
+    EXPECT_TRUE(type->Is<Pointer>());
+    auto* ptr_ty = type->As<Pointer>();
+    EXPECT_NE(ptr_ty, nullptr);
+    EXPECT_TRUE(ptr_ty->type->Is<F32>());
+    EXPECT_EQ(ptr_ty->storage_class, ast::StorageClass::kPrivate);
+    EXPECT_TRUE(p->error().empty());
 }
 
 TEST_F(SpvParserTest, ConvertType_PointerOutput) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
   %float = OpTypeFloat 32
   %3 = OpTypePointer Output %float
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->BuildInternalModule());
 
-  auto* type = p->ConvertType(3);
-  EXPECT_TRUE(type->Is<Pointer>());
-  auto* ptr_ty = type->As<Pointer>();
-  EXPECT_NE(ptr_ty, nullptr);
-  EXPECT_TRUE(ptr_ty->type->Is<F32>());
-  EXPECT_EQ(ptr_ty->storage_class, ast::StorageClass::kPrivate);
-  EXPECT_TRUE(p->error().empty());
+    auto* type = p->ConvertType(3);
+    EXPECT_TRUE(type->Is<Pointer>());
+    auto* ptr_ty = type->As<Pointer>();
+    EXPECT_NE(ptr_ty, nullptr);
+    EXPECT_TRUE(ptr_ty->type->Is<F32>());
+    EXPECT_EQ(ptr_ty->storage_class, ast::StorageClass::kPrivate);
+    EXPECT_TRUE(p->error().empty());
 }
 
 TEST_F(SpvParserTest, ConvertType_PointerUniform) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
   %float = OpTypeFloat 32
   %3 = OpTypePointer Uniform %float
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->BuildInternalModule());
 
-  auto* type = p->ConvertType(3);
-  EXPECT_TRUE(type->Is<Pointer>());
-  auto* ptr_ty = type->As<Pointer>();
-  EXPECT_NE(ptr_ty, nullptr);
-  EXPECT_TRUE(ptr_ty->type->Is<F32>());
-  EXPECT_EQ(ptr_ty->storage_class, ast::StorageClass::kUniform);
-  EXPECT_TRUE(p->error().empty());
+    auto* type = p->ConvertType(3);
+    EXPECT_TRUE(type->Is<Pointer>());
+    auto* ptr_ty = type->As<Pointer>();
+    EXPECT_NE(ptr_ty, nullptr);
+    EXPECT_TRUE(ptr_ty->type->Is<F32>());
+    EXPECT_EQ(ptr_ty->storage_class, ast::StorageClass::kUniform);
+    EXPECT_TRUE(p->error().empty());
 }
 
 TEST_F(SpvParserTest, ConvertType_PointerWorkgroup) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
   %float = OpTypeFloat 32
   %3 = OpTypePointer Workgroup %float
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->BuildInternalModule());
 
-  auto* type = p->ConvertType(3);
-  EXPECT_TRUE(type->Is<Pointer>());
-  auto* ptr_ty = type->As<Pointer>();
-  EXPECT_NE(ptr_ty, nullptr);
-  EXPECT_TRUE(ptr_ty->type->Is<F32>());
-  EXPECT_EQ(ptr_ty->storage_class, ast::StorageClass::kWorkgroup);
-  EXPECT_TRUE(p->error().empty());
+    auto* type = p->ConvertType(3);
+    EXPECT_TRUE(type->Is<Pointer>());
+    auto* ptr_ty = type->As<Pointer>();
+    EXPECT_NE(ptr_ty, nullptr);
+    EXPECT_TRUE(ptr_ty->type->Is<F32>());
+    EXPECT_EQ(ptr_ty->storage_class, ast::StorageClass::kWorkgroup);
+    EXPECT_TRUE(p->error().empty());
 }
 
 TEST_F(SpvParserTest, ConvertType_PointerUniformConstant) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
   %float = OpTypeFloat 32
   %3 = OpTypePointer UniformConstant %float
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->BuildInternalModule());
 
-  auto* type = p->ConvertType(3);
-  EXPECT_TRUE(type->Is<Pointer>());
-  auto* ptr_ty = type->As<Pointer>();
-  EXPECT_NE(ptr_ty, nullptr);
-  EXPECT_TRUE(ptr_ty->type->Is<F32>());
-  EXPECT_EQ(ptr_ty->storage_class, ast::StorageClass::kNone);
-  EXPECT_TRUE(p->error().empty());
+    auto* type = p->ConvertType(3);
+    EXPECT_TRUE(type->Is<Pointer>());
+    auto* ptr_ty = type->As<Pointer>();
+    EXPECT_NE(ptr_ty, nullptr);
+    EXPECT_TRUE(ptr_ty->type->Is<F32>());
+    EXPECT_EQ(ptr_ty->storage_class, ast::StorageClass::kNone);
+    EXPECT_TRUE(p->error().empty());
 }
 
 TEST_F(SpvParserTest, ConvertType_PointerStorageBuffer) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
   %float = OpTypeFloat 32
   %3 = OpTypePointer StorageBuffer %float
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->BuildInternalModule());
 
-  auto* type = p->ConvertType(3);
-  EXPECT_TRUE(type->Is<Pointer>());
-  auto* ptr_ty = type->As<Pointer>();
-  EXPECT_NE(ptr_ty, nullptr);
-  EXPECT_TRUE(ptr_ty->type->Is<F32>());
-  EXPECT_EQ(ptr_ty->storage_class, ast::StorageClass::kStorage);
-  EXPECT_TRUE(p->error().empty());
+    auto* type = p->ConvertType(3);
+    EXPECT_TRUE(type->Is<Pointer>());
+    auto* ptr_ty = type->As<Pointer>();
+    EXPECT_NE(ptr_ty, nullptr);
+    EXPECT_TRUE(ptr_ty->type->Is<F32>());
+    EXPECT_EQ(ptr_ty->storage_class, ast::StorageClass::kStorage);
+    EXPECT_TRUE(p->error().empty());
 }
 
 TEST_F(SpvParserTest, ConvertType_PointerPrivate) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
   %float = OpTypeFloat 32
   %3 = OpTypePointer Private %float
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->BuildInternalModule());
 
-  auto* type = p->ConvertType(3);
-  EXPECT_TRUE(type->Is<Pointer>());
-  auto* ptr_ty = type->As<Pointer>();
-  EXPECT_NE(ptr_ty, nullptr);
-  EXPECT_TRUE(ptr_ty->type->Is<F32>());
-  EXPECT_EQ(ptr_ty->storage_class, ast::StorageClass::kPrivate);
-  EXPECT_TRUE(p->error().empty());
+    auto* type = p->ConvertType(3);
+    EXPECT_TRUE(type->Is<Pointer>());
+    auto* ptr_ty = type->As<Pointer>();
+    EXPECT_NE(ptr_ty, nullptr);
+    EXPECT_TRUE(ptr_ty->type->Is<F32>());
+    EXPECT_EQ(ptr_ty->storage_class, ast::StorageClass::kPrivate);
+    EXPECT_TRUE(p->error().empty());
 }
 
 TEST_F(SpvParserTest, ConvertType_PointerFunction) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
   %float = OpTypeFloat 32
   %3 = OpTypePointer Function %float
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->BuildInternalModule());
 
-  auto* type = p->ConvertType(3);
-  EXPECT_TRUE(type->Is<Pointer>());
-  auto* ptr_ty = type->As<Pointer>();
-  EXPECT_NE(ptr_ty, nullptr);
-  EXPECT_TRUE(ptr_ty->type->Is<F32>());
-  EXPECT_EQ(ptr_ty->storage_class, ast::StorageClass::kFunction);
-  EXPECT_TRUE(p->error().empty());
+    auto* type = p->ConvertType(3);
+    EXPECT_TRUE(type->Is<Pointer>());
+    auto* ptr_ty = type->As<Pointer>();
+    EXPECT_NE(ptr_ty, nullptr);
+    EXPECT_TRUE(ptr_ty->type->Is<F32>());
+    EXPECT_EQ(ptr_ty->storage_class, ast::StorageClass::kFunction);
+    EXPECT_TRUE(p->error().empty());
 }
 
 TEST_F(SpvParserTest, ConvertType_PointerToPointer) {
-  // FYI:  The reader suports pointer-to-pointer even while WebGPU does not.
-  auto p = parser(test::Assemble(Preamble() + R"(
+    // FYI:  The reader suports pointer-to-pointer even while WebGPU does not.
+    auto p = parser(test::Assemble(Preamble() + R"(
   %float = OpTypeFloat 32
   %42 = OpTypePointer Output %float
   %3 = OpTypePointer Input %42
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->BuildInternalModule());
 
-  auto* type = p->ConvertType(3);
-  EXPECT_NE(type, nullptr);
-  EXPECT_TRUE(type->Is<Pointer>());
+    auto* type = p->ConvertType(3);
+    EXPECT_NE(type, nullptr);
+    EXPECT_TRUE(type->Is<Pointer>());
 
-  auto* ptr_ty = type->As<Pointer>();
-  EXPECT_NE(ptr_ty, nullptr);
-  EXPECT_EQ(ptr_ty->storage_class, ast::StorageClass::kPrivate);
-  EXPECT_TRUE(ptr_ty->type->Is<Pointer>());
+    auto* ptr_ty = type->As<Pointer>();
+    EXPECT_NE(ptr_ty, nullptr);
+    EXPECT_EQ(ptr_ty->storage_class, ast::StorageClass::kPrivate);
+    EXPECT_TRUE(ptr_ty->type->Is<Pointer>());
 
-  auto* ptr_ptr_ty = ptr_ty->type->As<Pointer>();
-  EXPECT_NE(ptr_ptr_ty, nullptr);
-  EXPECT_EQ(ptr_ptr_ty->storage_class, ast::StorageClass::kPrivate);
-  EXPECT_TRUE(ptr_ptr_ty->type->Is<F32>());
+    auto* ptr_ptr_ty = ptr_ty->type->As<Pointer>();
+    EXPECT_NE(ptr_ptr_ty, nullptr);
+    EXPECT_EQ(ptr_ptr_ty->storage_class, ast::StorageClass::kPrivate);
+    EXPECT_TRUE(ptr_ptr_ty->type->Is<F32>());
 
-  EXPECT_TRUE(p->error().empty());
+    EXPECT_TRUE(p->error().empty());
 }
 
 TEST_F(SpvParserTest, ConvertType_Sampler_PretendVoid) {
-  // We fake the type suport for samplers, images, and sampled images.
-  auto p = parser(test::Assemble(Preamble() + R"(
+    // We fake the type suport for samplers, images, and sampled images.
+    auto p = parser(test::Assemble(Preamble() + R"(
   %1 = OpTypeSampler
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->BuildInternalModule());
 
-  auto* type = p->ConvertType(1);
-  EXPECT_TRUE(type->Is<Void>());
-  EXPECT_TRUE(p->error().empty());
+    auto* type = p->ConvertType(1);
+    EXPECT_TRUE(type->Is<Void>());
+    EXPECT_TRUE(p->error().empty());
 }
 
 TEST_F(SpvParserTest, ConvertType_Image_PretendVoid) {
-  // We fake the type suport for samplers, images, and sampled images.
-  auto p = parser(test::Assemble(Preamble() + R"(
+    // We fake the type suport for samplers, images, and sampled images.
+    auto p = parser(test::Assemble(Preamble() + R"(
   %float = OpTypeFloat 32
   %1 = OpTypeImage %float 2D 0 0 0 1 Unknown
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->BuildInternalModule());
 
-  auto* type = p->ConvertType(1);
-  EXPECT_TRUE(type->Is<Void>());
-  EXPECT_TRUE(p->error().empty());
+    auto* type = p->ConvertType(1);
+    EXPECT_TRUE(type->Is<Void>());
+    EXPECT_TRUE(p->error().empty());
 }
 
 TEST_F(SpvParserTest, ConvertType_SampledImage_PretendVoid) {
-  auto p = parser(test::Assemble(Preamble() + R"(
+    auto p = parser(test::Assemble(Preamble() + R"(
   %float = OpTypeFloat 32
   %im = OpTypeImage %float 2D 0 0 0 1 Unknown
   %1 = OpTypeSampledImage %im
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->BuildInternalModule());
 
-  auto* type = p->ConvertType(1);
-  EXPECT_TRUE(type->Is<Void>());
-  EXPECT_TRUE(p->error().empty());
+    auto* type = p->ConvertType(1);
+    EXPECT_TRUE(type->Is<Void>());
+    EXPECT_TRUE(p->error().empty());
 }
 
 }  // namespace
diff --git a/src/tint/reader/spirv/parser_impl_function_decl_test.cc b/src/tint/reader/spirv/parser_impl_function_decl_test.cc
index 4e10725..c821c85 100644
--- a/src/tint/reader/spirv/parser_impl_function_decl_test.cc
+++ b/src/tint/reader/spirv/parser_impl_function_decl_test.cc
@@ -22,21 +22,21 @@
 using ::testing::HasSubstr;
 
 std::string Caps() {
-  return R"(
+    return R"(
     OpCapability Shader
     OpMemoryModel Logical Simple
   )";
 }
 
 std::string Preamble() {
-  return Caps() + R"(
+    return Caps() + R"(
     OpEntryPoint Fragment %main "x_100"
     OpExecutionMode %main OriginUpperLeft
   )";
 }
 
 std::string MainBody() {
-  return R"(
+    return R"(
     %main = OpFunction %void None %voidfn
     %main_entry = OpLabel
     OpReturn
@@ -47,15 +47,15 @@
 /// @returns a SPIR-V assembly segment which assigns debug names
 /// to particular IDs.
 std::string Names(std::vector<std::string> ids) {
-  std::ostringstream outs;
-  for (auto& id : ids) {
-    outs << "    OpName %" << id << " \"" << id << "\"\n";
-  }
-  return outs.str();
+    std::ostringstream outs;
+    for (auto& id : ids) {
+        outs << "    OpName %" << id << " \"" << id << "\"\n";
+    }
+    return outs.str();
 }
 
 std::string CommonTypes() {
-  return R"(
+    return R"(
     %void = OpTypeVoid
     %voidfn = OpTypeFunction %void
     %float = OpTypeFloat 32
@@ -65,7 +65,7 @@
 }
 
 std::string BuiltinPosition() {
-  return R"(OpDecorate %position BuiltIn Position
+    return R"(OpDecorate %position BuiltIn Position
     %float = OpTypeFloat 32
     %v4float = OpTypeVector %float 4
     %ptr = OpTypePointer Output %v4float
@@ -78,147 +78,143 @@
 }
 
 TEST_F(SpvParserTest, EmitFunctions_NoFunctions) {
-  auto p = parser(test::Assemble(
-      R"(
+    auto p = parser(test::Assemble(
+        R"(
      OpCapability Shader
      OpMemoryModel Logical Simple
 )" + CommonTypes()));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  Program program = p->program();
-  const auto program_ast = test::ToString(program);
-  EXPECT_THAT(program_ast, Not(HasSubstr("Function{")));
-  p->SkipDumpingPending("Not valid for Vulkan: needs an entry point");
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    Program program = p->program();
+    const auto program_ast = test::ToString(program);
+    EXPECT_THAT(program_ast, Not(HasSubstr("Function{")));
+    p->SkipDumpingPending("Not valid for Vulkan: needs an entry point");
 }
 
 TEST_F(SpvParserTest, EmitFunctions_FunctionWithoutBody) {
-  auto p =
-      parser(test::Assemble(Preamble() + Names({"main"}) + CommonTypes() + R"(
+    auto p = parser(test::Assemble(Preamble() + Names({"main"}) + CommonTypes() + R"(
      %main = OpFunction %void None %voidfn
      OpFunctionEnd
   )"));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  Program program = p->program();
-  const auto program_ast = test::ToString(program);
-  EXPECT_THAT(program_ast, Not(HasSubstr("Function{")));
-  p->SkipDumpingPending("Missing an entry point body requires Linkage");
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    Program program = p->program();
+    const auto program_ast = test::ToString(program);
+    EXPECT_THAT(program_ast, Not(HasSubstr("Function{")));
+    p->SkipDumpingPending("Missing an entry point body requires Linkage");
 }
 
 TEST_F(SpvParserTest, EmitFunctions_Function_EntryPoint_Vertex) {
-  std::string input = Caps() +
-                      R"(OpEntryPoint Vertex %main "main" %position )" +
-                      Names({"main"}) + BuiltinPosition() + R"(
+    std::string input = Caps() + R"(OpEntryPoint Vertex %main "main" %position )" +
+                        Names({"main"}) + BuiltinPosition() + R"(
 
 %main = OpFunction %void None %voidfn
 %entry = OpLabel
 OpReturn
 OpFunctionEnd)";
 
-  auto p = parser(test::Assemble(input));
-  ASSERT_TRUE(p->BuildAndParseInternalModule());
-  ASSERT_TRUE(p->error().empty()) << p->error();
-  Program program = p->program();
-  const auto program_ast = test::ToString(program);
-  EXPECT_THAT(program_ast, HasSubstr(R"(
+    auto p = parser(test::Assemble(input));
+    ASSERT_TRUE(p->BuildAndParseInternalModule());
+    ASSERT_TRUE(p->error().empty()) << p->error();
+    Program program = p->program();
+    const auto program_ast = test::ToString(program);
+    EXPECT_THAT(program_ast, HasSubstr(R"(
 struct main_out {
   @builtin(position)
   x_2_1 : vec4<f32>,
 }
 )")) << program_ast;
 
-  EXPECT_THAT(program_ast, HasSubstr(R"(
+    EXPECT_THAT(program_ast, HasSubstr(R"(
 @stage(vertex)
 fn main() -> main_out {
 )"));
 }
 
 TEST_F(SpvParserTest, EmitFunctions_Function_EntryPoint_Fragment) {
-  std::string input = Caps() + R"(
+    std::string input = Caps() + R"(
      OpEntryPoint Fragment %main "main"
      OpExecutionMode %main OriginUpperLeft
 )" + Names({"main"}) + CommonTypes() +
-                      MainBody();
+                        MainBody();
 
-  auto p = parser(test::Assemble(input));
-  ASSERT_TRUE(p->BuildAndParseInternalModule());
-  ASSERT_TRUE(p->error().empty()) << p->error();
-  Program program = p->program();
-  const auto program_ast = test::ToString(program);
-  EXPECT_THAT(program_ast, HasSubstr(R"(
+    auto p = parser(test::Assemble(input));
+    ASSERT_TRUE(p->BuildAndParseInternalModule());
+    ASSERT_TRUE(p->error().empty()) << p->error();
+    Program program = p->program();
+    const auto program_ast = test::ToString(program);
+    EXPECT_THAT(program_ast, HasSubstr(R"(
 @stage(fragment)
 fn main() {
 )"));
 }
 
 TEST_F(SpvParserTest, EmitFunctions_Function_EntryPoint_GLCompute) {
-  std::string input = Caps() + R"(
+    std::string input = Caps() + R"(
       OpEntryPoint GLCompute %main "main"
       OpExecutionMode %main LocalSize 1 1 1
 )" + Names({"main"}) + CommonTypes() +
-                      MainBody();
+                        MainBody();
 
-  auto p = parser(test::Assemble(input));
-  ASSERT_TRUE(p->BuildAndParseInternalModule());
-  ASSERT_TRUE(p->error().empty()) << p->error();
-  Program program = p->program();
-  const auto program_ast = test::ToString(program);
-  EXPECT_THAT(program_ast, HasSubstr(R"(
-@stage(compute) @workgroup_size(1, 1, 1)
+    auto p = parser(test::Assemble(input));
+    ASSERT_TRUE(p->BuildAndParseInternalModule());
+    ASSERT_TRUE(p->error().empty()) << p->error();
+    Program program = p->program();
+    const auto program_ast = test::ToString(program);
+    EXPECT_THAT(program_ast, HasSubstr(R"(
+@stage(compute) @workgroup_size(1i, 1i, 1i)
 fn main() {
 )"));
 }
 
 TEST_F(SpvParserTest, EmitFunctions_Function_EntryPoint_MultipleEntryPoints) {
-  std::string input = Caps() +
-                      R"(
+    std::string input = Caps() +
+                        R"(
 OpEntryPoint Fragment %main "first_shader"
 OpEntryPoint Fragment %main "second_shader"
 OpExecutionMode %main OriginUpperLeft
 )" + Names({"main"}) + CommonTypes() +
-                      MainBody();
+                        MainBody();
 
-  auto p = parser(test::Assemble(input));
-  ASSERT_TRUE(p->BuildAndParseInternalModule());
-  ASSERT_TRUE(p->error().empty()) << p->error();
-  Program program = p->program();
-  const auto program_ast = test::ToString(program);
-  EXPECT_THAT(program_ast, HasSubstr(R"(
+    auto p = parser(test::Assemble(input));
+    ASSERT_TRUE(p->BuildAndParseInternalModule());
+    ASSERT_TRUE(p->error().empty()) << p->error();
+    Program program = p->program();
+    const auto program_ast = test::ToString(program);
+    EXPECT_THAT(program_ast, HasSubstr(R"(
 @stage(fragment)
 fn first_shader() {
 )"));
-  EXPECT_THAT(program_ast, HasSubstr(R"(
+    EXPECT_THAT(program_ast, HasSubstr(R"(
 @stage(fragment)
 fn second_shader() {
 )"));
 }
 
-TEST_F(SpvParserTest,
-       EmitFunctions_Function_EntryPoint_GLCompute_LocalSize_Only) {
-  std::string input = Caps() + R"(
+TEST_F(SpvParserTest, EmitFunctions_Function_EntryPoint_GLCompute_LocalSize_Only) {
+    std::string input = Caps() + R"(
 OpEntryPoint GLCompute %main "comp_main"
 OpExecutionMode %main LocalSize 2 4 8
 )" + Names({"main"}) + CommonTypes() +
-                      R"(
+                        R"(
 %main = OpFunction %void None %voidfn
 %entry = OpLabel
 OpReturn
 OpFunctionEnd)";
 
-  auto p = parser(test::Assemble(input));
-  ASSERT_TRUE(p->BuildAndParseInternalModule());
-  ASSERT_TRUE(p->error().empty()) << p->error();
-  Program program = p->program();
-  const auto program_ast = test::ToString(program);
-  EXPECT_THAT(program_ast, HasSubstr(R"(
-@stage(compute) @workgroup_size(2, 4, 8)
+    auto p = parser(test::Assemble(input));
+    ASSERT_TRUE(p->BuildAndParseInternalModule());
+    ASSERT_TRUE(p->error().empty()) << p->error();
+    Program program = p->program();
+    const auto program_ast = test::ToString(program);
+    EXPECT_THAT(program_ast, HasSubstr(R"(
+@stage(compute) @workgroup_size(2i, 4i, 8i)
 fn comp_main() {
 )")) << program_ast;
 }
 
-TEST_F(SpvParserTest,
-       EmitFunctions_Function_EntryPoint_WorkgroupSizeBuiltin_Constant_Only) {
-  std::string input = Caps() + R"(OpEntryPoint GLCompute %main "comp_main"
+TEST_F(SpvParserTest, EmitFunctions_Function_EntryPoint_WorkgroupSizeBuiltin_Constant_Only) {
+    std::string input = Caps() + R"(OpEntryPoint GLCompute %main "comp_main"
 OpDecorate %wgsize BuiltIn WorkgroupSize
 )" + CommonTypes() + R"(
 %uvec3 = OpTypeVector %uint 3
@@ -231,22 +227,20 @@
 OpReturn
 OpFunctionEnd)";
 
-  auto p = parser(test::Assemble(input));
-  ASSERT_TRUE(p->BuildAndParseInternalModule());
-  ASSERT_TRUE(p->error().empty()) << p->error();
-  Program program = p->program();
-  const auto program_ast = test::ToString(program);
-  EXPECT_THAT(program_ast, HasSubstr(R"(
-@stage(compute) @workgroup_size(3, 5, 7)
+    auto p = parser(test::Assemble(input));
+    ASSERT_TRUE(p->BuildAndParseInternalModule());
+    ASSERT_TRUE(p->error().empty()) << p->error();
+    Program program = p->program();
+    const auto program_ast = test::ToString(program);
+    EXPECT_THAT(program_ast, HasSubstr(R"(
+@stage(compute) @workgroup_size(3i, 5i, 7i)
 fn comp_main() {
 )")) << program_ast;
 }
 
-TEST_F(
-    SpvParserTest,
-    EmitFunctions_Function_EntryPoint_WorkgroupSizeBuiltin_SpecConstant_Only) {
-  std::string input = Caps() +
-                      R"(OpEntryPoint GLCompute %main "comp_main"
+TEST_F(SpvParserTest, EmitFunctions_Function_EntryPoint_WorkgroupSizeBuiltin_SpecConstant_Only) {
+    std::string input = Caps() +
+                        R"(OpEntryPoint GLCompute %main "comp_main"
 OpDecorate %wgsize BuiltIn WorkgroupSize
 OpDecorate %uint_3 SpecId 0
 OpDecorate %uint_5 SpecId 1
@@ -262,22 +256,20 @@
 OpReturn
 OpFunctionEnd)";
 
-  auto p = parser(test::Assemble(input));
-  ASSERT_TRUE(p->BuildAndParseInternalModule());
-  ASSERT_TRUE(p->error().empty()) << p->error();
-  Program program = p->program();
-  const auto program_ast = test::ToString(program);
-  EXPECT_THAT(program_ast, HasSubstr(R"(
-@stage(compute) @workgroup_size(3, 5, 7)
+    auto p = parser(test::Assemble(input));
+    ASSERT_TRUE(p->BuildAndParseInternalModule());
+    ASSERT_TRUE(p->error().empty()) << p->error();
+    Program program = p->program();
+    const auto program_ast = test::ToString(program);
+    EXPECT_THAT(program_ast, HasSubstr(R"(
+@stage(compute) @workgroup_size(3i, 5i, 7i)
 fn comp_main() {
 )")) << program_ast;
 }
 
-TEST_F(
-    SpvParserTest,
-    EmitFunctions_Function_EntryPoint_WorkgroupSize_MixedConstantSpecConstant) {
-  std::string input = Caps() +
-                      R"(OpEntryPoint GLCompute %main "comp_main"
+TEST_F(SpvParserTest, EmitFunctions_Function_EntryPoint_WorkgroupSize_MixedConstantSpecConstant) {
+    std::string input = Caps() +
+                        R"(OpEntryPoint GLCompute %main "comp_main"
 OpDecorate %wgsize BuiltIn WorkgroupSize
 OpDecorate %uint_3 SpecId 0
 OpDecorate %uint_7 SpecId 2
@@ -292,24 +284,23 @@
 OpReturn
 OpFunctionEnd)";
 
-  auto p = parser(test::Assemble(input));
-  ASSERT_TRUE(p->BuildAndParseInternalModule());
-  ASSERT_TRUE(p->error().empty()) << p->error();
-  Program program = p->program();
-  const auto program_ast = test::ToString(program);
-  EXPECT_THAT(program_ast, HasSubstr(R"(
-@stage(compute) @workgroup_size(3, 5, 7)
+    auto p = parser(test::Assemble(input));
+    ASSERT_TRUE(p->BuildAndParseInternalModule());
+    ASSERT_TRUE(p->error().empty()) << p->error();
+    Program program = p->program();
+    const auto program_ast = test::ToString(program);
+    EXPECT_THAT(program_ast, HasSubstr(R"(
+@stage(compute) @workgroup_size(3i, 5i, 7i)
 fn comp_main() {
 )")) << program_ast;
 }
 
-TEST_F(
-    SpvParserTest,
-    // I had to shorten the name to pass the linter.
-    EmitFunctions_Function_EntryPoint_LocalSize_And_WGSBuiltin_SpecConstant) {
-  // WorkgroupSize builtin wins.
-  std::string input = Caps() +
-                      R"(OpEntryPoint GLCompute %main "comp_main"
+TEST_F(SpvParserTest,
+       // I had to shorten the name to pass the linter.
+       EmitFunctions_Function_EntryPoint_LocalSize_And_WGSBuiltin_SpecConstant) {
+    // WorkgroupSize builtin wins.
+    std::string input = Caps() +
+                        R"(OpEntryPoint GLCompute %main "comp_main"
 OpExecutionMode %main LocalSize 2 4 8
 OpDecorate %wgsize BuiltIn WorkgroupSize
 OpDecorate %uint_3 SpecId 0
@@ -326,38 +317,36 @@
 OpReturn
 OpFunctionEnd)";
 
-  auto p = parser(test::Assemble(input));
-  ASSERT_TRUE(p->BuildAndParseInternalModule());
-  ASSERT_TRUE(p->error().empty()) << p->error();
-  Program program = p->program();
-  const auto program_ast = test::ToString(program);
-  EXPECT_THAT(program_ast, HasSubstr(R"(
-@stage(compute) @workgroup_size(3, 5, 7)
+    auto p = parser(test::Assemble(input));
+    ASSERT_TRUE(p->BuildAndParseInternalModule());
+    ASSERT_TRUE(p->error().empty()) << p->error();
+    Program program = p->program();
+    const auto program_ast = test::ToString(program);
+    EXPECT_THAT(program_ast, HasSubstr(R"(
+@stage(compute) @workgroup_size(3i, 5i, 7i)
 fn comp_main() {
 )")) << program_ast;
 }
 
 TEST_F(SpvParserTest, EmitFunctions_VoidFunctionWithoutParams) {
-  auto p = parser(test::Assemble(Preamble() + Names({"another_function"}) +
-                                 CommonTypes() + R"(
+    auto p = parser(test::Assemble(Preamble() + Names({"another_function"}) + CommonTypes() + R"(
     %another_function = OpFunction %void None %voidfn
     %entry = OpLabel
     OpReturn
     OpFunctionEnd
 )" + MainBody()));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  Program program = p->program();
-  const auto program_ast = test::ToString(program);
-  EXPECT_THAT(program_ast, HasSubstr(R"(fn another_function() {
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    Program program = p->program();
+    const auto program_ast = test::ToString(program);
+    EXPECT_THAT(program_ast, HasSubstr(R"(fn another_function() {
 )"));
 }
 
 TEST_F(SpvParserTest, EmitFunctions_CalleePrecedesCaller) {
-  auto p = parser(test::Assemble(
-      Preamble() +
-      Names({"root", "branch", "leaf", "leaf_result", "branch_result"}) +
-      CommonTypes() + R"(
+    auto p = parser(test::Assemble(
+        Preamble() + Names({"root", "branch", "leaf", "leaf_result", "branch_result"}) +
+        CommonTypes() + R"(
      %uintfn = OpTypeFunction %uint
      %uint_0 = OpConstant %uint 0
 
@@ -378,11 +367,11 @@
      OpReturnValue %uint_0
      OpFunctionEnd
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  Program program = p->program();
-  const auto program_ast = test::ToString(program);
-  EXPECT_THAT(program_ast, HasSubstr(R"(fn leaf() -> u32 {
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    Program program = p->program();
+    const auto program_ast = test::ToString(program);
+    EXPECT_THAT(program_ast, HasSubstr(R"(fn leaf() -> u32 {
   return 0u;
 }
 
@@ -399,8 +388,7 @@
 }
 
 TEST_F(SpvParserTest, EmitFunctions_NonVoidResultType) {
-  auto p = parser(
-      test::Assemble(Preamble() + Names({"ret_float"}) + CommonTypes() + R"(
+    auto p = parser(test::Assemble(Preamble() + Names({"ret_float"}) + CommonTypes() + R"(
      %float_0 = OpConstant %float 0.0
      %fn_ret_float = OpTypeFunction %float
 
@@ -409,19 +397,19 @@
      OpReturnValue %float_0
      OpFunctionEnd
 )" + MainBody()));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  Program program = p->program();
-  const auto program_ast = test::ToString(program);
-  EXPECT_THAT(program_ast, HasSubstr(R"(fn ret_float() -> f32 {
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    Program program = p->program();
+    const auto program_ast = test::ToString(program);
+    EXPECT_THAT(program_ast, HasSubstr(R"(fn ret_float() -> f32 {
   return 0.0;
 }
 )")) << program_ast;
 }
 
 TEST_F(SpvParserTest, EmitFunctions_MixedParamTypes) {
-  auto p = parser(test::Assemble(
-      Preamble() + Names({"mixed_params", "a", "b", "c"}) + CommonTypes() + R"(
+    auto p = parser(
+        test::Assemble(Preamble() + Names({"mixed_params", "a", "b", "c"}) + CommonTypes() + R"(
      %fn_mixed_params = OpTypeFunction %void %uint %float %int
 
      %mixed_params = OpFunction %void None %fn_mixed_params
@@ -432,20 +420,18 @@
      OpReturn
      OpFunctionEnd
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  Program program = p->program();
-  const auto program_ast = test::ToString(program);
-  EXPECT_THAT(program_ast,
-              HasSubstr(R"(fn mixed_params(a : u32, b : f32, c : i32) {
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    Program program = p->program();
+    const auto program_ast = test::ToString(program);
+    EXPECT_THAT(program_ast, HasSubstr(R"(fn mixed_params(a : u32, b : f32, c : i32) {
   return;
 }
 )"));
 }
 
 TEST_F(SpvParserTest, EmitFunctions_GenerateParamNames) {
-  auto p = parser(
-      test::Assemble(Preamble() + Names({"mixed_params"}) + CommonTypes() + R"(
+    auto p = parser(test::Assemble(Preamble() + Names({"mixed_params"}) + CommonTypes() + R"(
      %fn_mixed_params = OpTypeFunction %void %uint %float %int
 
      %mixed_params = OpFunction %void None %fn_mixed_params
@@ -456,12 +442,11 @@
      OpReturn
      OpFunctionEnd
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  Program program = p->program();
-  const auto program_ast = test::ToString(program);
-  EXPECT_THAT(program_ast,
-              HasSubstr(R"(fn mixed_params(x_14 : u32, x_15 : f32, x_16 : i32) {
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    Program program = p->program();
+    const auto program_ast = test::ToString(program);
+    EXPECT_THAT(program_ast, HasSubstr(R"(fn mixed_params(x_14 : u32, x_15 : f32, x_16 : i32) {
   return;
 }
 )")) << program_ast;
diff --git a/src/tint/reader/spirv/parser_impl_get_decorations_test.cc b/src/tint/reader/spirv/parser_impl_get_decorations_test.cc
index 5f4f971..929ab1f 100644
--- a/src/tint/reader/spirv/parser_impl_get_decorations_test.cc
+++ b/src/tint/reader/spirv/parser_impl_get_decorations_test.cc
@@ -27,151 +27,142 @@
 const char* kSkipReason = "This example is deliberately a SPIR-V fragment";
 
 TEST_F(SpvParserGetDecorationsTest, GetDecorationsFor_NotAnId) {
-  auto p = parser(test::Assemble(""));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  auto decorations = p->GetDecorationsFor(42);
-  EXPECT_TRUE(decorations.empty());
-  EXPECT_TRUE(p->error().empty());
-  p->SkipDumpingPending(kSkipReason);
+    auto p = parser(test::Assemble(""));
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    auto decorations = p->GetDecorationsFor(42);
+    EXPECT_TRUE(decorations.empty());
+    EXPECT_TRUE(p->error().empty());
+    p->SkipDumpingPending(kSkipReason);
 }
 
 TEST_F(SpvParserGetDecorationsTest, GetDecorationsFor_NoDecorations) {
-  auto p = parser(test::Assemble("%1 = OpTypeVoid"));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  auto decorations = p->GetDecorationsFor(1);
-  EXPECT_TRUE(decorations.empty());
-  EXPECT_TRUE(p->error().empty());
-  p->SkipDumpingPending(kSkipReason);
+    auto p = parser(test::Assemble("%1 = OpTypeVoid"));
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    auto decorations = p->GetDecorationsFor(1);
+    EXPECT_TRUE(decorations.empty());
+    EXPECT_TRUE(p->error().empty());
+    p->SkipDumpingPending(kSkipReason);
 }
 
 TEST_F(SpvParserGetDecorationsTest, GetDecorationsFor_OneDecoration) {
-  auto p = parser(test::Assemble(R"(
+    auto p = parser(test::Assemble(R"(
     OpDecorate %10 Block
     %float = OpTypeFloat 32
     %10 = OpTypeStruct %float
   )"));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  auto decorations = p->GetDecorationsFor(10);
-  EXPECT_THAT(decorations,
-              UnorderedElementsAre(Decoration{SpvDecorationBlock}));
-  EXPECT_TRUE(p->error().empty());
-  p->SkipDumpingPending(kSkipReason);
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    auto decorations = p->GetDecorationsFor(10);
+    EXPECT_THAT(decorations, UnorderedElementsAre(Decoration{SpvDecorationBlock}));
+    EXPECT_TRUE(p->error().empty());
+    p->SkipDumpingPending(kSkipReason);
 }
 
 TEST_F(SpvParserGetDecorationsTest, GetDecorationsFor_Duplicate) {
-  auto p = parser(test::Assemble(R"(
+    auto p = parser(test::Assemble(R"(
     OpDecorate %10 Block
     OpDecorate %10 Block
     %float = OpTypeFloat 32
     %10 = OpTypeStruct %float
   )"));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  auto decorations = p->GetDecorationsFor(10);
-  EXPECT_THAT(decorations,
-              UnorderedElementsAre(Decoration{SpvDecorationBlock}));
-  EXPECT_TRUE(p->error().empty());
-  p->SkipDumpingPending(kSkipReason);
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    auto decorations = p->GetDecorationsFor(10);
+    EXPECT_THAT(decorations, UnorderedElementsAre(Decoration{SpvDecorationBlock}));
+    EXPECT_TRUE(p->error().empty());
+    p->SkipDumpingPending(kSkipReason);
 }
 
 TEST_F(SpvParserGetDecorationsTest, GetDecorationsFor_MultiDecoration) {
-  auto p = parser(test::Assemble(R"(
+    auto p = parser(test::Assemble(R"(
     OpDecorate %5 RelaxedPrecision
     OpDecorate %5 Location 7      ; Invalid case made up for test
     %float = OpTypeFloat 32
     %5 = OpConstant %float 3.14
   )"));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  auto decorations = p->GetDecorationsFor(5);
-  EXPECT_THAT(decorations,
-              UnorderedElementsAre(Decoration{SpvDecorationRelaxedPrecision},
-                                   Decoration{SpvDecorationLocation, 7}));
-  EXPECT_TRUE(p->error().empty());
-  p->SkipDumpingPending(kSkipReason);
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    auto decorations = p->GetDecorationsFor(5);
+    EXPECT_THAT(decorations, UnorderedElementsAre(Decoration{SpvDecorationRelaxedPrecision},
+                                                  Decoration{SpvDecorationLocation, 7}));
+    EXPECT_TRUE(p->error().empty());
+    p->SkipDumpingPending(kSkipReason);
 }
 
 TEST_F(SpvParserGetDecorationsTest, GetDecorationsForMember_NotAnId) {
-  auto p = parser(test::Assemble(""));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  auto decorations = p->GetDecorationsForMember(42, 9);
-  EXPECT_TRUE(decorations.empty());
-  EXPECT_TRUE(p->error().empty());
-  p->SkipDumpingPending(kSkipReason);
+    auto p = parser(test::Assemble(""));
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    auto decorations = p->GetDecorationsForMember(42, 9);
+    EXPECT_TRUE(decorations.empty());
+    EXPECT_TRUE(p->error().empty());
+    p->SkipDumpingPending(kSkipReason);
 }
 
 TEST_F(SpvParserGetDecorationsTest, GetDecorationsForMember_NotAStruct) {
-  auto p = parser(test::Assemble("%1 = OpTypeVoid"));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  auto decorations = p->GetDecorationsFor(1);
-  EXPECT_TRUE(decorations.empty());
-  EXPECT_TRUE(p->error().empty());
-  p->SkipDumpingPending(kSkipReason);
+    auto p = parser(test::Assemble("%1 = OpTypeVoid"));
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    auto decorations = p->GetDecorationsFor(1);
+    EXPECT_TRUE(decorations.empty());
+    EXPECT_TRUE(p->error().empty());
+    p->SkipDumpingPending(kSkipReason);
 }
 
-TEST_F(SpvParserGetDecorationsTest,
-       GetDecorationsForMember_MemberWithoutDecoration) {
-  auto p = parser(test::Assemble(R"(
+TEST_F(SpvParserGetDecorationsTest, GetDecorationsForMember_MemberWithoutDecoration) {
+    auto p = parser(test::Assemble(R"(
     %uint = OpTypeInt 32 0
     %10 = OpTypeStruct %uint
   )"));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  auto decorations = p->GetDecorationsForMember(10, 0);
-  EXPECT_TRUE(decorations.empty());
-  EXPECT_TRUE(p->error().empty());
-  p->SkipDumpingPending(kSkipReason);
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    auto decorations = p->GetDecorationsForMember(10, 0);
+    EXPECT_TRUE(decorations.empty());
+    EXPECT_TRUE(p->error().empty());
+    p->SkipDumpingPending(kSkipReason);
 }
 
 TEST_F(SpvParserGetDecorationsTest, GetDecorationsForMember_RelaxedPrecision) {
-  auto p = parser(test::Assemble(R"(
+    auto p = parser(test::Assemble(R"(
     OpMemberDecorate %10 0 RelaxedPrecision
     %float = OpTypeFloat 32
     %10 = OpTypeStruct %float
   )"));
-  EXPECT_TRUE(p->BuildAndParseInternalModule()) << p->error();
-  auto decorations = p->GetDecorationsForMember(10, 0);
-  EXPECT_THAT(decorations,
-              UnorderedElementsAre(Decoration{SpvDecorationRelaxedPrecision}));
-  EXPECT_TRUE(p->error().empty());
-  p->SkipDumpingPending(kSkipReason);
+    EXPECT_TRUE(p->BuildAndParseInternalModule()) << p->error();
+    auto decorations = p->GetDecorationsForMember(10, 0);
+    EXPECT_THAT(decorations, UnorderedElementsAre(Decoration{SpvDecorationRelaxedPrecision}));
+    EXPECT_TRUE(p->error().empty());
+    p->SkipDumpingPending(kSkipReason);
 }
 
 TEST_F(SpvParserGetDecorationsTest, GetDecorationsForMember_Duplicate) {
-  auto p = parser(test::Assemble(R"(
+    auto p = parser(test::Assemble(R"(
     OpMemberDecorate %10 0 RelaxedPrecision
     OpMemberDecorate %10 0 RelaxedPrecision
     %float = OpTypeFloat 32
     %10 = OpTypeStruct %float
   )"));
-  EXPECT_TRUE(p->BuildAndParseInternalModule()) << p->error();
-  auto decorations = p->GetDecorationsForMember(10, 0);
-  EXPECT_THAT(decorations,
-              UnorderedElementsAre(Decoration{SpvDecorationRelaxedPrecision}));
-  EXPECT_TRUE(p->error().empty());
-  p->SkipDumpingPending(kSkipReason);
+    EXPECT_TRUE(p->BuildAndParseInternalModule()) << p->error();
+    auto decorations = p->GetDecorationsForMember(10, 0);
+    EXPECT_THAT(decorations, UnorderedElementsAre(Decoration{SpvDecorationRelaxedPrecision}));
+    EXPECT_TRUE(p->error().empty());
+    p->SkipDumpingPending(kSkipReason);
 }
 
 // TODO(dneto): Enable when ArrayStride is handled
-TEST_F(SpvParserGetDecorationsTest,
-       DISABLED_GetDecorationsForMember_OneDecoration) {
-  auto p = parser(test::Assemble(R"(
+TEST_F(SpvParserGetDecorationsTest, DISABLED_GetDecorationsForMember_OneDecoration) {
+    auto p = parser(test::Assemble(R"(
     OpMemberDecorate %10 1 ArrayStride 12
     %uint = OpTypeInt 32 0
     %uint_2 = OpConstant %uint 2
     %arr = OpTypeArray %uint %uint_2
     %10 = OpTypeStruct %uint %arr
   )"));
-  EXPECT_TRUE(p->BuildAndParseInternalModule()) << p->error();
-  auto decorations = p->GetDecorationsForMember(10, 1);
-  EXPECT_THAT(decorations,
-              UnorderedElementsAre(Decoration{SpvDecorationArrayStride, 12}));
-  EXPECT_TRUE(p->error().empty());
+    EXPECT_TRUE(p->BuildAndParseInternalModule()) << p->error();
+    auto decorations = p->GetDecorationsForMember(10, 1);
+    EXPECT_THAT(decorations, UnorderedElementsAre(Decoration{SpvDecorationArrayStride, 12}));
+    EXPECT_TRUE(p->error().empty());
 }
 
 // TODO(dneto): Enable when ArrayStride, MatrixStride, ColMajor are handled
 // crbug.com/tint/30 for ArrayStride
 // crbug.com/tint/31 for matrix layout
-TEST_F(SpvParserGetDecorationsTest,
-       DISABLED_GetDecorationsForMember_MultiDecoration) {
-  auto p = parser(test::Assemble(R"(
+TEST_F(SpvParserGetDecorationsTest, DISABLED_GetDecorationsForMember_MultiDecoration) {
+    auto p = parser(test::Assemble(R"(
     OpMemberDecorate %50 1 RelaxedPrecision
     OpMemberDecorate %50 2 ArrayStride 16
     OpMemberDecorate %50 2 MatrixStride 8
@@ -184,78 +175,78 @@
     %arr = OpTypeArray %mat %uint_2
     %50 = OpTypeStruct %uint %float %arr
   )"));
-  EXPECT_TRUE(p->BuildAndParseInternalModule()) << p->error();
+    EXPECT_TRUE(p->BuildAndParseInternalModule()) << p->error();
 
-  EXPECT_TRUE(p->GetDecorationsForMember(50, 0).empty());
-  EXPECT_THAT(p->GetDecorationsForMember(50, 1),
-              UnorderedElementsAre(Decoration{SpvDecorationRelaxedPrecision}));
-  EXPECT_THAT(p->GetDecorationsForMember(50, 2),
-              UnorderedElementsAre(Decoration{SpvDecorationColMajor},
-                                   Decoration{SpvDecorationMatrixStride, 8},
-                                   Decoration{SpvDecorationArrayStride, 16}));
-  EXPECT_TRUE(p->error().empty());
+    EXPECT_TRUE(p->GetDecorationsForMember(50, 0).empty());
+    EXPECT_THAT(p->GetDecorationsForMember(50, 1),
+                UnorderedElementsAre(Decoration{SpvDecorationRelaxedPrecision}));
+    EXPECT_THAT(p->GetDecorationsForMember(50, 2),
+                UnorderedElementsAre(Decoration{SpvDecorationColMajor},
+                                     Decoration{SpvDecorationMatrixStride, 8},
+                                     Decoration{SpvDecorationArrayStride, 16}));
+    EXPECT_TRUE(p->error().empty());
 }
 
 TEST_F(SpvParserGetDecorationsTest, GetDecorationsFor_Restrict) {
-  // RestrictPointer applies to a memory object declaration. Use a variable.
-  auto p = parser(test::Assemble(R"(
+    // RestrictPointer applies to a memory object declaration. Use a variable.
+    auto p = parser(test::Assemble(R"(
     OpDecorate %10 Restrict
     %float = OpTypeFloat 32
     %ptr = OpTypePointer Workgroup %float
     %10 = OpVariable %ptr Workgroup
   )"));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  auto decorations = p->GetDecorationsFor(10);
-  EXPECT_TRUE(decorations.empty());
-  EXPECT_TRUE(p->error().empty());
-  p->SkipDumpingPending(kSkipReason);
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    auto decorations = p->GetDecorationsFor(10);
+    EXPECT_TRUE(decorations.empty());
+    EXPECT_TRUE(p->error().empty());
+    p->SkipDumpingPending(kSkipReason);
 }
 
 TEST_F(SpvParserGetDecorationsTest, GetDecorationsForMember_Restrict) {
-  // Restrict applies to a memory object declaration.
-  // But OpMemberDecorate can only be applied to a structure type.
-  // Test the reader's ability to be resilient to more than what SPIR-V allows.
-  auto p = parser(test::Assemble(R"(
+    // Restrict applies to a memory object declaration.
+    // But OpMemberDecorate can only be applied to a structure type.
+    // Test the reader's ability to be resilient to more than what SPIR-V allows.
+    auto p = parser(test::Assemble(R"(
     OpMemberDecorate %10 0 Restrict
     %float = OpTypeFloat 32
     %10 = OpTypeStruct %float
   )"));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  auto decorations = p->GetDecorationsForMember(10, 0);
-  EXPECT_TRUE(decorations.empty());
-  EXPECT_TRUE(p->error().empty());
-  p->SkipDumpingPending(kSkipReason);
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    auto decorations = p->GetDecorationsForMember(10, 0);
+    EXPECT_TRUE(decorations.empty());
+    EXPECT_TRUE(p->error().empty());
+    p->SkipDumpingPending(kSkipReason);
 }
 
 TEST_F(SpvParserGetDecorationsTest, GetDecorationsFor_RestrictPointer) {
-  // RestrictPointer applies to a memory object declaration. Use a variable.
-  auto p = parser(test::Assemble(R"(
+    // RestrictPointer applies to a memory object declaration. Use a variable.
+    auto p = parser(test::Assemble(R"(
     OpDecorate %10 RestrictPointer
     %float = OpTypeFloat 32
     %ptr = OpTypePointer Workgroup %float
     %10 = OpVariable %ptr Workgroup
   )"));
-  EXPECT_TRUE(p->BuildAndParseInternalModule()) << p->error();
-  auto decorations = p->GetDecorationsFor(10);
-  EXPECT_TRUE(decorations.empty());
-  EXPECT_TRUE(p->error().empty());
-  p->SkipDumpingPending(kSkipReason);
+    EXPECT_TRUE(p->BuildAndParseInternalModule()) << p->error();
+    auto decorations = p->GetDecorationsFor(10);
+    EXPECT_TRUE(decorations.empty());
+    EXPECT_TRUE(p->error().empty());
+    p->SkipDumpingPending(kSkipReason);
 }
 
 TEST_F(SpvParserGetDecorationsTest, GetDecorationsForMember_RestrictPointer) {
-  // RestrictPointer applies to a memory object declaration.
-  // But OpMemberDecorate can only be applied to a structure type.
-  // Test the reader's ability to be resilient to more than what SPIR-V allows.
-  auto p = parser(test::Assemble(R"(
+    // RestrictPointer applies to a memory object declaration.
+    // But OpMemberDecorate can only be applied to a structure type.
+    // Test the reader's ability to be resilient to more than what SPIR-V allows.
+    auto p = parser(test::Assemble(R"(
     OpMemberDecorate %10 0 RestrictPointer
     %float = OpTypeFloat 32
     %10 = OpTypeStruct %float
   )"));
-  EXPECT_TRUE(p->BuildAndParseInternalModule()) << p->error();
-  auto decorations = p->GetDecorationsFor(10);
-  EXPECT_TRUE(decorations.empty());
-  EXPECT_TRUE(p->error().empty());
-  p->SkipDumpingPending(kSkipReason);
+    EXPECT_TRUE(p->BuildAndParseInternalModule()) << p->error();
+    auto decorations = p->GetDecorationsFor(10);
+    EXPECT_TRUE(decorations.empty());
+    EXPECT_TRUE(p->error().empty());
+    p->SkipDumpingPending(kSkipReason);
 }
 
 }  // namespace
diff --git a/src/tint/reader/spirv/parser_impl_handle_test.cc b/src/tint/reader/spirv/parser_impl_handle_test.cc
index d1938aa..0af3cc5 100644
--- a/src/tint/reader/spirv/parser_impl_handle_test.cc
+++ b/src/tint/reader/spirv/parser_impl_handle_test.cc
@@ -30,7 +30,7 @@
 using SpvParserHandleTest = SpvParserTest;
 
 std::string Preamble() {
-  return R"(
+    return R"(
     OpCapability Shader
     OpCapability Sampled1D
     OpCapability Image1D
@@ -41,14 +41,14 @@
 }
 
 std::string FragMain() {
-  return R"(
+    return R"(
     OpEntryPoint Fragment %main "main" ; assume no IO
     OpExecutionMode %main OriginUpperLeft
   )";
 }
 
 std::string MainBody() {
-  return R"(
+    return R"(
     %main = OpFunction %void None %voidfn
     %main_entry = OpLabel
     OpReturn
@@ -57,7 +57,7 @@
 }
 
 std::string CommonBasicTypes() {
-  return R"(
+    return R"(
     %void = OpTypeVoid
     %voidfn = OpTypeFunction %void
 
@@ -117,7 +117,7 @@
 }
 
 std::string CommonImageTypes() {
-  return R"(
+    return R"(
 
 ; Define types for all sampler and texture types that can map to WGSL,
 ; modulo texel formats for storage textures. For now, we limit
@@ -231,63 +231,58 @@
 }
 
 std::string CommonTypes() {
-  return CommonBasicTypes() + CommonImageTypes();
+    return CommonBasicTypes() + CommonImageTypes();
 }
 
 std::string Bindings(std::vector<uint32_t> ids) {
-  std::ostringstream os;
-  int binding = 0;
-  for (auto id : ids) {
-    os << "  OpDecorate %" << id << " DescriptorSet 0\n"
-       << "  OpDecorate %" << id << " Binding " << binding++ << "\n";
-  }
-  return os.str();
+    std::ostringstream os;
+    int binding = 0;
+    for (auto id : ids) {
+        os << "  OpDecorate %" << id << " DescriptorSet 0\n"
+           << "  OpDecorate %" << id << " Binding " << binding++ << "\n";
+    }
+    return os.str();
 }
 
-TEST_F(SpvParserHandleTest,
-       GetMemoryObjectDeclarationForHandle_WellFormedButNotAHandle) {
-  const auto assembly = Preamble() + FragMain() + CommonTypes() + R"(
+TEST_F(SpvParserHandleTest, GetMemoryObjectDeclarationForHandle_WellFormedButNotAHandle) {
+    const auto assembly = Preamble() + FragMain() + CommonTypes() + R"(
      %10 = OpConstantNull %ptr_sampler
      %20 = OpConstantNull %ptr_f_texture_1d
   )" + MainBody();
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildInternalModule()) << assembly;
-  const auto* sampler = p->GetMemoryObjectDeclarationForHandle(10, false);
-  const auto* image = p->GetMemoryObjectDeclarationForHandle(20, true);
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildInternalModule()) << assembly;
+    const auto* sampler = p->GetMemoryObjectDeclarationForHandle(10, false);
+    const auto* image = p->GetMemoryObjectDeclarationForHandle(20, true);
 
-  EXPECT_EQ(sampler, nullptr);
-  EXPECT_EQ(image, nullptr);
-  EXPECT_TRUE(p->error().empty());
+    EXPECT_EQ(sampler, nullptr);
+    EXPECT_EQ(image, nullptr);
+    EXPECT_TRUE(p->error().empty());
 
-  p->DeliberatelyInvalidSpirv();  // WGSL does not have null pointers.
+    p->DeliberatelyInvalidSpirv();  // WGSL does not have null pointers.
 }
 
-TEST_F(SpvParserHandleTest,
-       GetMemoryObjectDeclarationForHandle_Variable_Direct) {
-  const auto assembly =
-      Preamble() + FragMain() + Bindings({10, 20}) + CommonTypes() + R"(
+TEST_F(SpvParserHandleTest, GetMemoryObjectDeclarationForHandle_Variable_Direct) {
+    const auto assembly = Preamble() + FragMain() + Bindings({10, 20}) + CommonTypes() + R"(
      %10 = OpVariable %ptr_sampler UniformConstant
      %20 = OpVariable %ptr_f_texture_1d UniformConstant
   )" + MainBody();
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  const auto* sampler = p->GetMemoryObjectDeclarationForHandle(10, false);
-  const auto* image = p->GetMemoryObjectDeclarationForHandle(20, true);
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    const auto* sampler = p->GetMemoryObjectDeclarationForHandle(10, false);
+    const auto* image = p->GetMemoryObjectDeclarationForHandle(20, true);
 
-  ASSERT_TRUE(sampler != nullptr);
-  EXPECT_EQ(sampler->result_id(), 10u);
+    ASSERT_TRUE(sampler != nullptr);
+    EXPECT_EQ(sampler->result_id(), 10u);
 
-  ASSERT_TRUE(image != nullptr);
-  EXPECT_EQ(image->result_id(), 20u);
+    ASSERT_TRUE(image != nullptr);
+    EXPECT_EQ(image->result_id(), 20u);
 }
 
-TEST_F(SpvParserHandleTest,
-       GetMemoryObjectDeclarationForHandle_Variable_AccessChain) {
-  // Show that we would generalize to arrays of handles, even though that
-  // is not supported in WGSL MVP.
-  const auto assembly =
-      Preamble() + FragMain() + Bindings({10, 20}) + CommonTypes() + R"(
+TEST_F(SpvParserHandleTest, GetMemoryObjectDeclarationForHandle_Variable_AccessChain) {
+    // Show that we would generalize to arrays of handles, even though that
+    // is not supported in WGSL MVP.
+    const auto assembly = Preamble() + FragMain() + Bindings({10, 20}) + CommonTypes() + R"(
 
      %sampler_array = OpTypeArray %sampler %uint_100
      %image_array = OpTypeArray %f_texture_1d %uint_100
@@ -307,26 +302,24 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  const auto* sampler = p->GetMemoryObjectDeclarationForHandle(110, false);
-  const auto* image = p->GetMemoryObjectDeclarationForHandle(120, true);
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    const auto* sampler = p->GetMemoryObjectDeclarationForHandle(110, false);
+    const auto* image = p->GetMemoryObjectDeclarationForHandle(120, true);
 
-  ASSERT_TRUE(sampler != nullptr);
-  EXPECT_EQ(sampler->result_id(), 10u);
+    ASSERT_TRUE(sampler != nullptr);
+    EXPECT_EQ(sampler->result_id(), 10u);
 
-  ASSERT_TRUE(image != nullptr);
-  EXPECT_EQ(image->result_id(), 20u);
+    ASSERT_TRUE(image != nullptr);
+    EXPECT_EQ(image->result_id(), 20u);
 
-  // WGSL does not support arrays of textures and samplers.
-  p->DeliberatelyInvalidSpirv();
+    // WGSL does not support arrays of textures and samplers.
+    p->DeliberatelyInvalidSpirv();
 }
 
-TEST_F(SpvParserHandleTest,
-       GetMemoryObjectDeclarationForHandle_Variable_InBoundsAccessChain) {
-  const auto assembly =
-      Preamble() + FragMain() + Bindings({10, 20}) + CommonTypes() + R"(
+TEST_F(SpvParserHandleTest, GetMemoryObjectDeclarationForHandle_Variable_InBoundsAccessChain) {
+    const auto assembly = Preamble() + FragMain() + Bindings({10, 20}) + CommonTypes() + R"(
 
      %sampler_array = OpTypeArray %sampler %uint_100
      %image_array = OpTypeArray %f_texture_1d %uint_100
@@ -346,29 +339,28 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  const auto* sampler = p->GetMemoryObjectDeclarationForHandle(110, false);
-  const auto* image = p->GetMemoryObjectDeclarationForHandle(120, true);
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    const auto* sampler = p->GetMemoryObjectDeclarationForHandle(110, false);
+    const auto* image = p->GetMemoryObjectDeclarationForHandle(120, true);
 
-  ASSERT_TRUE(sampler != nullptr);
-  EXPECT_EQ(sampler->result_id(), 10u);
+    ASSERT_TRUE(sampler != nullptr);
+    EXPECT_EQ(sampler->result_id(), 10u);
 
-  ASSERT_TRUE(image != nullptr);
-  EXPECT_EQ(image->result_id(), 20u);
+    ASSERT_TRUE(image != nullptr);
+    EXPECT_EQ(image->result_id(), 20u);
 
-  // WGSL does not support arrays of textures and samplers.
-  p->DeliberatelyInvalidSpirv();
+    // WGSL does not support arrays of textures and samplers.
+    p->DeliberatelyInvalidSpirv();
 }
 
-TEST_F(SpvParserHandleTest,
-       GetMemoryObjectDeclarationForHandle_Variable_PtrAccessChain) {
-  // Show that we would generalize to arrays of handles, even though that
-  // is not supported in WGSL MVP.
-  // Use VariablePointers for the OpInBoundsPtrAccessChain.
-  const auto assembly = "OpCapability VariablePointers " + Preamble() +
-                        FragMain() + Bindings({10, 20}) + CommonTypes() + R"(
+TEST_F(SpvParserHandleTest, GetMemoryObjectDeclarationForHandle_Variable_PtrAccessChain) {
+    // Show that we would generalize to arrays of handles, even though that
+    // is not supported in WGSL MVP.
+    // Use VariablePointers for the OpInBoundsPtrAccessChain.
+    const auto assembly = "OpCapability VariablePointers " + Preamble() + FragMain() +
+                          Bindings({10, 20}) + CommonTypes() + R"(
 
      %sampler_array = OpTypeArray %sampler %uint_100
      %image_array = OpTypeArray %f_texture_1d %uint_100
@@ -388,27 +380,26 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  const auto* sampler = p->GetMemoryObjectDeclarationForHandle(110, false);
-  const auto* image = p->GetMemoryObjectDeclarationForHandle(120, true);
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    const auto* sampler = p->GetMemoryObjectDeclarationForHandle(110, false);
+    const auto* image = p->GetMemoryObjectDeclarationForHandle(120, true);
 
-  ASSERT_TRUE(sampler != nullptr);
-  EXPECT_EQ(sampler->result_id(), 10u);
+    ASSERT_TRUE(sampler != nullptr);
+    EXPECT_EQ(sampler->result_id(), 10u);
 
-  ASSERT_TRUE(image != nullptr);
-  EXPECT_EQ(image->result_id(), 20u);
+    ASSERT_TRUE(image != nullptr);
+    EXPECT_EQ(image->result_id(), 20u);
 
-  // Variable pointers is not allowed for WGSL. So don't dump it.
-  p->DeliberatelyInvalidSpirv();
+    // Variable pointers is not allowed for WGSL. So don't dump it.
+    p->DeliberatelyInvalidSpirv();
 }
 
-TEST_F(SpvParserHandleTest,
-       GetMemoryObjectDeclarationForHandle_Variable_InBoundsPtrAccessChain) {
-  // Use VariablePointers for the OpInBoundsPtrAccessChain.
-  const auto assembly = "OpCapability VariablePointers " + Preamble() +
-                        FragMain() + Bindings({10, 20}) + CommonTypes() + R"(
+TEST_F(SpvParserHandleTest, GetMemoryObjectDeclarationForHandle_Variable_InBoundsPtrAccessChain) {
+    // Use VariablePointers for the OpInBoundsPtrAccessChain.
+    const auto assembly = "OpCapability VariablePointers " + Preamble() + FragMain() +
+                          Bindings({10, 20}) + CommonTypes() + R"(
 
      %sampler_array = OpTypeArray %sampler %uint_100
      %image_array = OpTypeArray %f_texture_1d %uint_100
@@ -428,26 +419,24 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  const auto* sampler = p->GetMemoryObjectDeclarationForHandle(110, false);
-  const auto* image = p->GetMemoryObjectDeclarationForHandle(120, true);
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    const auto* sampler = p->GetMemoryObjectDeclarationForHandle(110, false);
+    const auto* image = p->GetMemoryObjectDeclarationForHandle(120, true);
 
-  ASSERT_TRUE(sampler != nullptr);
-  EXPECT_EQ(sampler->result_id(), 10u);
+    ASSERT_TRUE(sampler != nullptr);
+    EXPECT_EQ(sampler->result_id(), 10u);
 
-  ASSERT_TRUE(image != nullptr);
-  EXPECT_EQ(image->result_id(), 20u);
+    ASSERT_TRUE(image != nullptr);
+    EXPECT_EQ(image->result_id(), 20u);
 
-  // Variable pointers is not allowed for WGSL. So don't dump it.
-  p->DeliberatelyInvalidSpirv();
+    // Variable pointers is not allowed for WGSL. So don't dump it.
+    p->DeliberatelyInvalidSpirv();
 }
 
-TEST_F(SpvParserHandleTest,
-       GetMemoryObjectDeclarationForHandle_Variable_CopyObject) {
-  const auto assembly =
-      Preamble() + FragMain() + Bindings({10, 20}) + CommonTypes() + R"(
+TEST_F(SpvParserHandleTest, GetMemoryObjectDeclarationForHandle_Variable_CopyObject) {
+    const auto assembly = Preamble() + FragMain() + Bindings({10, 20}) + CommonTypes() + R"(
 
      %10 = OpVariable %ptr_sampler UniformConstant
      %20 = OpVariable %ptr_f_texture_1d UniformConstant
@@ -461,22 +450,21 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  const auto* sampler = p->GetMemoryObjectDeclarationForHandle(110, false);
-  const auto* image = p->GetMemoryObjectDeclarationForHandle(120, true);
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    const auto* sampler = p->GetMemoryObjectDeclarationForHandle(110, false);
+    const auto* image = p->GetMemoryObjectDeclarationForHandle(120, true);
 
-  ASSERT_TRUE(sampler != nullptr);
-  EXPECT_EQ(sampler->result_id(), 10u);
+    ASSERT_TRUE(sampler != nullptr);
+    EXPECT_EQ(sampler->result_id(), 10u);
 
-  ASSERT_TRUE(image != nullptr);
-  EXPECT_EQ(image->result_id(), 20u);
+    ASSERT_TRUE(image != nullptr);
+    EXPECT_EQ(image->result_id(), 20u);
 }
 
 TEST_F(SpvParserHandleTest, GetMemoryObjectDeclarationForHandle_Variable_Load) {
-  const auto assembly =
-      Preamble() + FragMain() + Bindings({10, 20}) + CommonTypes() + R"(
+    const auto assembly = Preamble() + FragMain() + Bindings({10, 20}) + CommonTypes() + R"(
 
      %10 = OpVariable %ptr_sampler UniformConstant
      %20 = OpVariable %ptr_f_texture_1d UniformConstant
@@ -490,25 +478,23 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  const auto* sampler = p->GetMemoryObjectDeclarationForHandle(110, false);
-  const auto* image = p->GetMemoryObjectDeclarationForHandle(120, true);
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    const auto* sampler = p->GetMemoryObjectDeclarationForHandle(110, false);
+    const auto* image = p->GetMemoryObjectDeclarationForHandle(120, true);
 
-  ASSERT_TRUE(sampler != nullptr);
-  EXPECT_EQ(sampler->result_id(), 10u);
+    ASSERT_TRUE(sampler != nullptr);
+    EXPECT_EQ(sampler->result_id(), 10u);
 
-  ASSERT_TRUE(image != nullptr);
-  EXPECT_EQ(image->result_id(), 20u);
+    ASSERT_TRUE(image != nullptr);
+    EXPECT_EQ(image->result_id(), 20u);
 }
 
-TEST_F(SpvParserHandleTest,
-       GetMemoryObjectDeclarationForHandle_Variable_SampledImage) {
-  // Trace through the sampled image instruction, but in two different
-  // directions.
-  const auto assembly =
-      Preamble() + FragMain() + Bindings({10, 20}) + CommonTypes() + R"(
+TEST_F(SpvParserHandleTest, GetMemoryObjectDeclarationForHandle_Variable_SampledImage) {
+    // Trace through the sampled image instruction, but in two different
+    // directions.
+    const auto assembly = Preamble() + FragMain() + Bindings({10, 20}) + CommonTypes() + R"(
      %sampled_image_type = OpTypeSampledImage %f_texture_1d
 
      %10 = OpVariable %ptr_sampler UniformConstant
@@ -524,23 +510,21 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  const auto* sampler = p->GetMemoryObjectDeclarationForHandle(100, false);
-  const auto* image = p->GetMemoryObjectDeclarationForHandle(100, true);
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    const auto* sampler = p->GetMemoryObjectDeclarationForHandle(100, false);
+    const auto* image = p->GetMemoryObjectDeclarationForHandle(100, true);
 
-  ASSERT_TRUE(sampler != nullptr);
-  EXPECT_EQ(sampler->result_id(), 10u);
+    ASSERT_TRUE(sampler != nullptr);
+    EXPECT_EQ(sampler->result_id(), 10u);
 
-  ASSERT_TRUE(image != nullptr);
-  EXPECT_EQ(image->result_id(), 20u);
+    ASSERT_TRUE(image != nullptr);
+    EXPECT_EQ(image->result_id(), 20u);
 }
 
-TEST_F(SpvParserHandleTest,
-       GetMemoryObjectDeclarationForHandle_Variable_Image) {
-  const auto assembly =
-      Preamble() + FragMain() + Bindings({10, 20}) + CommonTypes() + R"(
+TEST_F(SpvParserHandleTest, GetMemoryObjectDeclarationForHandle_Variable_Image) {
+    const auto assembly = Preamble() + FragMain() + Bindings({10, 20}) + CommonTypes() + R"(
      %sampled_image_type = OpTypeSampledImage %f_texture_1d
 
      %10 = OpVariable %ptr_sampler UniformConstant
@@ -557,18 +541,17 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildInternalModule());
-  EXPECT_TRUE(p->error().empty());
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->error().empty());
 
-  const auto* image = p->GetMemoryObjectDeclarationForHandle(200, true);
-  ASSERT_TRUE(image != nullptr);
-  EXPECT_EQ(image->result_id(), 20u);
+    const auto* image = p->GetMemoryObjectDeclarationForHandle(200, true);
+    ASSERT_TRUE(image != nullptr);
+    EXPECT_EQ(image->result_id(), 20u);
 }
 
-TEST_F(SpvParserHandleTest,
-       GetMemoryObjectDeclarationForHandle_FuncParam_Direct) {
-  const auto assembly = Preamble() + FragMain() + CommonTypes() + R"(
+TEST_F(SpvParserHandleTest, GetMemoryObjectDeclarationForHandle_FuncParam_Direct) {
+    const auto assembly = Preamble() + FragMain() + CommonTypes() + R"(
      %fty = OpTypeFunction %void %ptr_sampler %ptr_f_texture_1d
 
      %func = OpFunction %void None %fty
@@ -578,26 +561,25 @@
      OpReturn
      OpFunctionEnd
   )" + MainBody();
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  const auto* sampler = p->GetMemoryObjectDeclarationForHandle(10, false);
-  const auto* image = p->GetMemoryObjectDeclarationForHandle(20, true);
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    const auto* sampler = p->GetMemoryObjectDeclarationForHandle(10, false);
+    const auto* image = p->GetMemoryObjectDeclarationForHandle(20, true);
 
-  ASSERT_TRUE(sampler != nullptr);
-  EXPECT_EQ(sampler->result_id(), 10u);
+    ASSERT_TRUE(sampler != nullptr);
+    EXPECT_EQ(sampler->result_id(), 10u);
 
-  ASSERT_TRUE(image != nullptr);
-  EXPECT_EQ(image->result_id(), 20u);
+    ASSERT_TRUE(image != nullptr);
+    EXPECT_EQ(image->result_id(), 20u);
 
-  p->SkipDumpingPending("crbug.com/tint/1039");
+    p->SkipDumpingPending("crbug.com/tint/1039");
 }
 
-TEST_F(SpvParserHandleTest,
-       GetMemoryObjectDeclarationForHandle_FuncParam_AccessChain) {
-  // Show that we would generalize to arrays of handles, even though that
-  // is not supported in WGSL MVP.
-  const auto assembly = Preamble() + FragMain() + CommonTypes() + R"(
+TEST_F(SpvParserHandleTest, GetMemoryObjectDeclarationForHandle_FuncParam_AccessChain) {
+    // Show that we would generalize to arrays of handles, even though that
+    // is not supported in WGSL MVP.
+    const auto assembly = Preamble() + FragMain() + CommonTypes() + R"(
      %sampler_array = OpTypeArray %sampler %uint_100
      %image_array = OpTypeArray %f_texture_1d %uint_100
 
@@ -617,25 +599,24 @@
      OpReturn
      OpFunctionEnd
   )" + MainBody();
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  const auto* sampler = p->GetMemoryObjectDeclarationForHandle(110, false);
-  const auto* image = p->GetMemoryObjectDeclarationForHandle(120, true);
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    const auto* sampler = p->GetMemoryObjectDeclarationForHandle(110, false);
+    const auto* image = p->GetMemoryObjectDeclarationForHandle(120, true);
 
-  ASSERT_TRUE(sampler != nullptr);
-  EXPECT_EQ(sampler->result_id(), 10u);
+    ASSERT_TRUE(sampler != nullptr);
+    EXPECT_EQ(sampler->result_id(), 10u);
 
-  ASSERT_TRUE(image != nullptr);
-  EXPECT_EQ(image->result_id(), 20u);
+    ASSERT_TRUE(image != nullptr);
+    EXPECT_EQ(image->result_id(), 20u);
 
-  // WGSL does not support arrays of textures or samplers
-  p->DeliberatelyInvalidSpirv();
+    // WGSL does not support arrays of textures or samplers
+    p->DeliberatelyInvalidSpirv();
 }
 
-TEST_F(SpvParserHandleTest,
-       GetMemoryObjectDeclarationForHandle_FuncParam_InBoundsAccessChain) {
-  const auto assembly = Preamble() + FragMain() + CommonTypes() + R"(
+TEST_F(SpvParserHandleTest, GetMemoryObjectDeclarationForHandle_FuncParam_InBoundsAccessChain) {
+    const auto assembly = Preamble() + FragMain() + CommonTypes() + R"(
      %sampler_array = OpTypeArray %sampler %uint_100
      %image_array = OpTypeArray %f_texture_1d %uint_100
 
@@ -655,27 +636,26 @@
      OpReturn
      OpFunctionEnd
   )" + MainBody();
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  const auto* sampler = p->GetMemoryObjectDeclarationForHandle(110, false);
-  const auto* image = p->GetMemoryObjectDeclarationForHandle(120, true);
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    const auto* sampler = p->GetMemoryObjectDeclarationForHandle(110, false);
+    const auto* image = p->GetMemoryObjectDeclarationForHandle(120, true);
 
-  ASSERT_TRUE(sampler != nullptr);
-  EXPECT_EQ(sampler->result_id(), 10u);
+    ASSERT_TRUE(sampler != nullptr);
+    EXPECT_EQ(sampler->result_id(), 10u);
 
-  ASSERT_TRUE(image != nullptr);
-  EXPECT_EQ(image->result_id(), 20u);
+    ASSERT_TRUE(image != nullptr);
+    EXPECT_EQ(image->result_id(), 20u);
 
-  // WGSL does not support arrays of textures or samplers
-  p->DeliberatelyInvalidSpirv();
+    // WGSL does not support arrays of textures or samplers
+    p->DeliberatelyInvalidSpirv();
 }
 
-TEST_F(SpvParserHandleTest,
-       GetMemoryObjectDeclarationForHandle_FuncParam_PtrAccessChain) {
-  // Show that we would generalize to arrays of handles, even though that
-  // is not supported in WGSL MVP.
-  const auto assembly = Preamble() + FragMain() + CommonTypes() + R"(
+TEST_F(SpvParserHandleTest, GetMemoryObjectDeclarationForHandle_FuncParam_PtrAccessChain) {
+    // Show that we would generalize to arrays of handles, even though that
+    // is not supported in WGSL MVP.
+    const auto assembly = Preamble() + FragMain() + CommonTypes() + R"(
      %sampler_array = OpTypeArray %sampler %uint_100
      %image_array = OpTypeArray %f_texture_1d %uint_100
 
@@ -695,25 +675,24 @@
      OpReturn
      OpFunctionEnd
   )" + MainBody();
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  const auto* sampler = p->GetMemoryObjectDeclarationForHandle(110, false);
-  const auto* image = p->GetMemoryObjectDeclarationForHandle(120, true);
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    const auto* sampler = p->GetMemoryObjectDeclarationForHandle(110, false);
+    const auto* image = p->GetMemoryObjectDeclarationForHandle(120, true);
 
-  ASSERT_TRUE(sampler != nullptr);
-  EXPECT_EQ(sampler->result_id(), 10u);
+    ASSERT_TRUE(sampler != nullptr);
+    EXPECT_EQ(sampler->result_id(), 10u);
 
-  ASSERT_TRUE(image != nullptr);
-  EXPECT_EQ(image->result_id(), 20u);
+    ASSERT_TRUE(image != nullptr);
+    EXPECT_EQ(image->result_id(), 20u);
 
-  // Variable pointers is not allowed for WGSL. So don't dump it.
-  p->DeliberatelyInvalidSpirv();
+    // Variable pointers is not allowed for WGSL. So don't dump it.
+    p->DeliberatelyInvalidSpirv();
 }
 
-TEST_F(SpvParserHandleTest,
-       GetMemoryObjectDeclarationForHandle_FuncParam_InBoundsPtrAccessChain) {
-  const auto assembly = Preamble() + FragMain() + CommonTypes() + R"(
+TEST_F(SpvParserHandleTest, GetMemoryObjectDeclarationForHandle_FuncParam_InBoundsPtrAccessChain) {
+    const auto assembly = Preamble() + FragMain() + CommonTypes() + R"(
      %sampler_array = OpTypeArray %sampler %uint_100
      %image_array = OpTypeArray %f_texture_1d %uint_100
 
@@ -733,25 +712,24 @@
      OpReturn
      OpFunctionEnd
   )" + MainBody();
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  const auto* sampler = p->GetMemoryObjectDeclarationForHandle(110, false);
-  const auto* image = p->GetMemoryObjectDeclarationForHandle(120, true);
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    const auto* sampler = p->GetMemoryObjectDeclarationForHandle(110, false);
+    const auto* image = p->GetMemoryObjectDeclarationForHandle(120, true);
 
-  ASSERT_TRUE(sampler != nullptr);
-  EXPECT_EQ(sampler->result_id(), 10u);
+    ASSERT_TRUE(sampler != nullptr);
+    EXPECT_EQ(sampler->result_id(), 10u);
 
-  ASSERT_TRUE(image != nullptr);
-  EXPECT_EQ(image->result_id(), 20u);
+    ASSERT_TRUE(image != nullptr);
+    EXPECT_EQ(image->result_id(), 20u);
 
-  // Variable pointers is not allowed for WGSL. So don't dump it.
-  p->DeliberatelyInvalidSpirv();
+    // Variable pointers is not allowed for WGSL. So don't dump it.
+    p->DeliberatelyInvalidSpirv();
 }
 
-TEST_F(SpvParserHandleTest,
-       GetMemoryObjectDeclarationForHandle_FuncParam_CopyObject) {
-  const auto assembly = Preamble() + FragMain() + CommonTypes() + R"(
+TEST_F(SpvParserHandleTest, GetMemoryObjectDeclarationForHandle_FuncParam_CopyObject) {
+    const auto assembly = Preamble() + FragMain() + CommonTypes() + R"(
      %fty = OpTypeFunction %void %ptr_sampler %ptr_f_texture_1d
 
      %func = OpFunction %void None %fty
@@ -765,24 +743,23 @@
      OpReturn
      OpFunctionEnd
   )" + MainBody();
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  const auto* sampler = p->GetMemoryObjectDeclarationForHandle(110, false);
-  const auto* image = p->GetMemoryObjectDeclarationForHandle(120, true);
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    const auto* sampler = p->GetMemoryObjectDeclarationForHandle(110, false);
+    const auto* image = p->GetMemoryObjectDeclarationForHandle(120, true);
 
-  ASSERT_TRUE(sampler != nullptr);
-  EXPECT_EQ(sampler->result_id(), 10u);
+    ASSERT_TRUE(sampler != nullptr);
+    EXPECT_EQ(sampler->result_id(), 10u);
 
-  ASSERT_TRUE(image != nullptr);
-  EXPECT_EQ(image->result_id(), 20u);
+    ASSERT_TRUE(image != nullptr);
+    EXPECT_EQ(image->result_id(), 20u);
 
-  p->SkipDumpingPending("crbug.com/tint/1039");
+    p->SkipDumpingPending("crbug.com/tint/1039");
 }
 
-TEST_F(SpvParserHandleTest,
-       GetMemoryObjectDeclarationForHandle_FuncParam_Load) {
-  const auto assembly = Preamble() + FragMain() + CommonTypes() + R"(
+TEST_F(SpvParserHandleTest, GetMemoryObjectDeclarationForHandle_FuncParam_Load) {
+    const auto assembly = Preamble() + FragMain() + CommonTypes() + R"(
      %fty = OpTypeFunction %void %ptr_sampler %ptr_f_texture_1d
 
      %func = OpFunction %void None %fty
@@ -796,26 +773,25 @@
      OpReturn
      OpFunctionEnd
   )" + MainBody();
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  const auto* sampler = p->GetMemoryObjectDeclarationForHandle(110, false);
-  const auto* image = p->GetMemoryObjectDeclarationForHandle(120, true);
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    const auto* sampler = p->GetMemoryObjectDeclarationForHandle(110, false);
+    const auto* image = p->GetMemoryObjectDeclarationForHandle(120, true);
 
-  ASSERT_TRUE(sampler != nullptr);
-  EXPECT_EQ(sampler->result_id(), 10u);
+    ASSERT_TRUE(sampler != nullptr);
+    EXPECT_EQ(sampler->result_id(), 10u);
 
-  ASSERT_TRUE(image != nullptr);
-  EXPECT_EQ(image->result_id(), 20u);
+    ASSERT_TRUE(image != nullptr);
+    EXPECT_EQ(image->result_id(), 20u);
 
-  p->SkipDumpingPending("crbug.com/tint/1039");
+    p->SkipDumpingPending("crbug.com/tint/1039");
 }
 
-TEST_F(SpvParserHandleTest,
-       GetMemoryObjectDeclarationForHandle_FuncParam_SampledImage) {
-  // Trace through the sampled image instruction, but in two different
-  // directions.
-  const auto assembly = Preamble() + FragMain() + CommonTypes() + R"(
+TEST_F(SpvParserHandleTest, GetMemoryObjectDeclarationForHandle_FuncParam_SampledImage) {
+    // Trace through the sampled image instruction, but in two different
+    // directions.
+    const auto assembly = Preamble() + FragMain() + CommonTypes() + R"(
      %sampled_image_type = OpTypeSampledImage %f_texture_1d
 
      %fty = OpTypeFunction %void %ptr_sampler %ptr_f_texture_1d
@@ -832,24 +808,23 @@
      OpReturn
      OpFunctionEnd
   )" + MainBody();
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  const auto* sampler = p->GetMemoryObjectDeclarationForHandle(100, false);
-  const auto* image = p->GetMemoryObjectDeclarationForHandle(100, true);
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    const auto* sampler = p->GetMemoryObjectDeclarationForHandle(100, false);
+    const auto* image = p->GetMemoryObjectDeclarationForHandle(100, true);
 
-  ASSERT_TRUE(sampler != nullptr);
-  EXPECT_EQ(sampler->result_id(), 10u);
+    ASSERT_TRUE(sampler != nullptr);
+    EXPECT_EQ(sampler->result_id(), 10u);
 
-  ASSERT_TRUE(image != nullptr);
-  EXPECT_EQ(image->result_id(), 20u);
+    ASSERT_TRUE(image != nullptr);
+    EXPECT_EQ(image->result_id(), 20u);
 
-  p->SkipDumpingPending("crbug.com/tint/1039");
+    p->SkipDumpingPending("crbug.com/tint/1039");
 }
 
-TEST_F(SpvParserHandleTest,
-       GetMemoryObjectDeclarationForHandle_FuncParam_Image) {
-  const auto assembly = Preamble() + FragMain() + CommonTypes() + R"(
+TEST_F(SpvParserHandleTest, GetMemoryObjectDeclarationForHandle_FuncParam_Image) {
+    const auto assembly = Preamble() + FragMain() + CommonTypes() + R"(
      %sampled_image_type = OpTypeSampledImage %f_texture_1d
 
      %fty = OpTypeFunction %void %ptr_sampler %ptr_f_texture_1d
@@ -867,38 +842,36 @@
      OpReturn
      OpFunctionEnd
   )" + MainBody();
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildInternalModule());
-  EXPECT_TRUE(p->error().empty());
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->error().empty());
 
-  const auto* image = p->GetMemoryObjectDeclarationForHandle(200, true);
-  ASSERT_TRUE(image != nullptr);
-  EXPECT_EQ(image->result_id(), 20u);
+    const auto* image = p->GetMemoryObjectDeclarationForHandle(200, true);
+    ASSERT_TRUE(image != nullptr);
+    EXPECT_EQ(image->result_id(), 20u);
 
-  p->SkipDumpingPending("crbug.com/tint/1039");
+    p->SkipDumpingPending("crbug.com/tint/1039");
 }
 
 // Test RegisterHandleUsage, sampled image cases
 
 struct UsageImageAccessCase {
-  std::string inst;
-  std::string expected_sampler_usage;
-  std::string expected_image_usage;
+    std::string inst;
+    std::string expected_sampler_usage;
+    std::string expected_image_usage;
 };
-inline std::ostream& operator<<(std::ostream& out,
-                                const UsageImageAccessCase& c) {
-  out << "UsageImageAccessCase(" << c.inst << ", " << c.expected_sampler_usage
-      << ", " << c.expected_image_usage << ")";
-  return out;
+inline std::ostream& operator<<(std::ostream& out, const UsageImageAccessCase& c) {
+    out << "UsageImageAccessCase(" << c.inst << ", " << c.expected_sampler_usage << ", "
+        << c.expected_image_usage << ")";
+    return out;
 }
 
 using SpvParserHandleTest_RegisterHandleUsage_SampledImage =
     SpvParserTestBase<::testing::TestWithParam<UsageImageAccessCase>>;
 
 TEST_P(SpvParserHandleTest_RegisterHandleUsage_SampledImage, Variable) {
-  const std::string inst = GetParam().inst;
-  const auto assembly = Preamble() + FragMain() + Bindings({10, 20}) +
-                        CommonTypes() + R"(
+    const std::string inst = GetParam().inst;
+    const auto assembly = Preamble() + FragMain() + Bindings({10, 20}) + CommonTypes() + R"(
      %si_ty = OpTypeSampledImage %f_texture_2d
      %coords = OpConstantNull %v2float
      %coords3d = OpConstantNull %v3float ; needed for Proj variants
@@ -917,30 +890,29 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildInternalModule());
-  EXPECT_TRUE(p->RegisterHandleUsage());
-  EXPECT_TRUE(p->error().empty());
-  Usage su = p->GetHandleUsage(10);
-  Usage iu = p->GetHandleUsage(20);
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->RegisterHandleUsage());
+    EXPECT_TRUE(p->error().empty());
+    Usage su = p->GetHandleUsage(10);
+    Usage iu = p->GetHandleUsage(20);
 
-  EXPECT_THAT(su.to_str(), Eq(GetParam().expected_sampler_usage));
-  EXPECT_THAT(iu.to_str(), Eq(GetParam().expected_image_usage));
+    EXPECT_THAT(su.to_str(), Eq(GetParam().expected_sampler_usage));
+    EXPECT_THAT(iu.to_str(), Eq(GetParam().expected_image_usage));
 
-  if (inst.find("ImageQueryLod") != std::string::npos) {
-    // WGSL does not support querying image level of detail.
-    // So don't emit them as part of a "passing" corpus.
-    p->DeliberatelyInvalidSpirv();
-  }
-  if (inst.find("ImageSampleDrefExplicitLod") != std::string::npos) {
-    p->SkipDumpingPending("crbug.com/tint/425");  // gpuweb issue #1319
-  }
+    if (inst.find("ImageQueryLod") != std::string::npos) {
+        // WGSL does not support querying image level of detail.
+        // So don't emit them as part of a "passing" corpus.
+        p->DeliberatelyInvalidSpirv();
+    }
+    if (inst.find("ImageSampleDrefExplicitLod") != std::string::npos) {
+        p->SkipDumpingPending("crbug.com/tint/425");  // gpuweb issue #1319
+    }
 }
 
 TEST_P(SpvParserHandleTest_RegisterHandleUsage_SampledImage, FunctionParam) {
-  const std::string inst = GetParam().inst;
-  const auto assembly = Preamble() + FragMain() + Bindings({10, 20}) +
-                        CommonTypes() + R"(
+    const std::string inst = GetParam().inst;
+    const auto assembly = Preamble() + FragMain() + Bindings({10, 20}) + CommonTypes() + R"(
      %f_ty = OpTypeFunction %void %ptr_sampler %ptr_f_texture_2d
      %si_ty = OpTypeSampledImage %f_texture_2d
      %coords = OpConstantNull %v2float
@@ -969,22 +941,22 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildInternalModule()) << p->error() << assembly << std::endl;
-  EXPECT_TRUE(p->RegisterHandleUsage()) << p->error() << assembly << std::endl;
-  EXPECT_TRUE(p->error().empty()) << p->error() << assembly << std::endl;
-  Usage su = p->GetHandleUsage(10);
-  Usage iu = p->GetHandleUsage(20);
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildInternalModule()) << p->error() << assembly << std::endl;
+    EXPECT_TRUE(p->RegisterHandleUsage()) << p->error() << assembly << std::endl;
+    EXPECT_TRUE(p->error().empty()) << p->error() << assembly << std::endl;
+    Usage su = p->GetHandleUsage(10);
+    Usage iu = p->GetHandleUsage(20);
 
-  EXPECT_THAT(su.to_str(), Eq(GetParam().expected_sampler_usage));
-  EXPECT_THAT(iu.to_str(), Eq(GetParam().expected_image_usage));
+    EXPECT_THAT(su.to_str(), Eq(GetParam().expected_sampler_usage));
+    EXPECT_THAT(iu.to_str(), Eq(GetParam().expected_image_usage));
 
-  if (inst.find("ImageQueryLod") != std::string::npos) {
-    // WGSL does not support querying image level of detail.
-    // So don't emit them as part of a "passing" corpus.
-    p->DeliberatelyInvalidSpirv();
-  }
-  p->SkipDumpingPending("crbug.com/tint/785");
+    if (inst.find("ImageQueryLod") != std::string::npos) {
+        // WGSL does not support querying image level of detail.
+        // So don't emit them as part of a "passing" corpus.
+        p->DeliberatelyInvalidSpirv();
+    }
+    p->SkipDumpingPending("crbug.com/tint/785");
 }
 
 INSTANTIATE_TEST_SUITE_P(
@@ -995,37 +967,30 @@
         // OpImageGather
         UsageImageAccessCase{"%result = OpImageGather "
                              "%v4float %sampled_image %coords %uint_1",
-                             "Usage(Sampler( ))",
-                             "Usage(Texture( is_sampled ))"},
+                             "Usage(Sampler( ))", "Usage(Texture( is_sampled ))"},
         // OpImageDrefGather
         UsageImageAccessCase{"%result = OpImageDrefGather "
                              "%v4float %sampled_image %coords %depth",
-                             "Usage(Sampler( comparison ))",
-                             "Usage(Texture( is_sampled depth ))"},
+                             "Usage(Sampler( comparison ))", "Usage(Texture( is_sampled depth ))"},
 
         // Sample the texture.
 
         // OpImageSampleImplicitLod
         UsageImageAccessCase{"%result = OpImageSampleImplicitLod "
                              "%v4float %sampled_image %coords",
-                             "Usage(Sampler( ))",
-                             "Usage(Texture( is_sampled ))"},
+                             "Usage(Sampler( ))", "Usage(Texture( is_sampled ))"},
         // OpImageSampleExplicitLod
         UsageImageAccessCase{"%result = OpImageSampleExplicitLod "
                              "%v4float %sampled_image %coords Lod %float_null",
-                             "Usage(Sampler( ))",
-                             "Usage(Texture( is_sampled ))"},
+                             "Usage(Sampler( ))", "Usage(Texture( is_sampled ))"},
         // OpImageSampleDrefImplicitLod
         UsageImageAccessCase{"%result = OpImageSampleDrefImplicitLod "
                              "%float %sampled_image %coords %depth",
-                             "Usage(Sampler( comparison ))",
-                             "Usage(Texture( is_sampled depth ))"},
+                             "Usage(Sampler( comparison ))", "Usage(Texture( is_sampled depth ))"},
         // OpImageSampleDrefExplicitLod
-        UsageImageAccessCase{
-            "%result = OpImageSampleDrefExplicitLod "
-            "%float %sampled_image %coords %depth Lod %float_null",
-            "Usage(Sampler( comparison ))",
-            "Usage(Texture( is_sampled depth ))"},
+        UsageImageAccessCase{"%result = OpImageSampleDrefExplicitLod "
+                             "%float %sampled_image %coords %depth Lod %float_null",
+                             "Usage(Sampler( comparison ))", "Usage(Texture( is_sampled depth ))"},
 
         // Sample the texture, with *Proj* variants, even though WGSL doesn't
         // support them.
@@ -1033,102 +998,94 @@
         // OpImageSampleProjImplicitLod
         UsageImageAccessCase{"%result = OpImageSampleProjImplicitLod "
                              "%v4float %sampled_image %coords3d",
-                             "Usage(Sampler( ))",
-                             "Usage(Texture( is_sampled ))"},
+                             "Usage(Sampler( ))", "Usage(Texture( is_sampled ))"},
         // OpImageSampleProjExplicitLod
-        UsageImageAccessCase{
-            "%result = OpImageSampleProjExplicitLod "
-            "%v4float %sampled_image %coords3d Lod %float_null",
-            "Usage(Sampler( ))", "Usage(Texture( is_sampled ))"},
+        UsageImageAccessCase{"%result = OpImageSampleProjExplicitLod "
+                             "%v4float %sampled_image %coords3d Lod %float_null",
+                             "Usage(Sampler( ))", "Usage(Texture( is_sampled ))"},
         // OpImageSampleProjDrefImplicitLod
         UsageImageAccessCase{"%result = OpImageSampleProjDrefImplicitLod "
                              "%float %sampled_image %coords3d %depth",
-                             "Usage(Sampler( comparison ))",
-                             "Usage(Texture( is_sampled depth ))"},
+                             "Usage(Sampler( comparison ))", "Usage(Texture( is_sampled depth ))"},
         // OpImageSampleProjDrefExplicitLod
-        UsageImageAccessCase{
-            "%result = OpImageSampleProjDrefExplicitLod "
-            "%float %sampled_image %coords3d %depth Lod %float_null",
-            "Usage(Sampler( comparison ))",
-            "Usage(Texture( is_sampled depth ))"},
+        UsageImageAccessCase{"%result = OpImageSampleProjDrefExplicitLod "
+                             "%float %sampled_image %coords3d %depth Lod %float_null",
+                             "Usage(Sampler( comparison ))", "Usage(Texture( is_sampled depth ))"},
 
         // OpImageQueryLod
-        UsageImageAccessCase{
-            "%result = OpImageQueryLod %v2float %sampled_image %coords",
-            "Usage(Sampler( ))", "Usage(Texture( is_sampled ))"}));
+        UsageImageAccessCase{"%result = OpImageQueryLod %v2float %sampled_image %coords",
+                             "Usage(Sampler( ))", "Usage(Texture( is_sampled ))"}));
 
 // Test RegisterHandleUsage, raw image cases.
 // For these we test the use of an image value directly, and not combined
 // with the sampler. The image still could be of sampled image type.
 
 struct UsageRawImageCase {
-  std::string type;  // Example: f_storage_1d or f_texture_1d
-  std::string inst;
-  std::string expected_image_usage;
+    std::string type;  // Example: f_storage_1d or f_texture_1d
+    std::string inst;
+    std::string expected_image_usage;
 };
 inline std::ostream& operator<<(std::ostream& out, const UsageRawImageCase& c) {
-  out << "UsageRawImageCase(" << c.type << ", " << c.inst << ", "
-      << c.expected_image_usage << ")";
-  return out;
+    out << "UsageRawImageCase(" << c.type << ", " << c.inst << ", " << c.expected_image_usage
+        << ")";
+    return out;
 }
 
 using SpvParserHandleTest_RegisterHandleUsage_RawImage =
     SpvParserTestBase<::testing::TestWithParam<UsageRawImageCase>>;
 
 TEST_P(SpvParserHandleTest_RegisterHandleUsage_RawImage, Variable) {
-  const bool is_storage = GetParam().type.find("storage") != std::string::npos;
-  const bool is_write = GetParam().inst.find("ImageWrite") != std::string::npos;
-  const auto assembly = Preamble() + FragMain() + Bindings({20}) +
-                        (is_storage ? std::string("OpDecorate %20 ") +
-                                          std::string(is_write ? "NonReadable"
-                                                               : "NonWritable")
-                                    : std::string("")) +
-                        " " + CommonTypes() + R"(
+    const bool is_storage = GetParam().type.find("storage") != std::string::npos;
+    const bool is_write = GetParam().inst.find("ImageWrite") != std::string::npos;
+    const auto assembly = Preamble() + FragMain() + Bindings({20}) +
+                          (is_storage ? std::string("OpDecorate %20 ") +
+                                            std::string(is_write ? "NonReadable" : "NonWritable")
+                                      : std::string("")) +
+                          " " + CommonTypes() + R"(
      %20 = OpVariable %ptr_)" +
-                        GetParam().type + R"( UniformConstant
+                          GetParam().type + R"( UniformConstant
 
      %main = OpFunction %void None %voidfn
      %entry = OpLabel
 
      %im = OpLoad %)" + GetParam().type +
-                        R"( %20
+                          R"( %20
 )" + GetParam().inst + R"(
 
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildInternalModule());
-  EXPECT_TRUE(p->RegisterHandleUsage());
-  EXPECT_TRUE(p->error().empty());
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->RegisterHandleUsage());
+    EXPECT_TRUE(p->error().empty());
 
-  Usage iu = p->GetHandleUsage(20);
-  EXPECT_THAT(iu.to_str(), Eq(GetParam().expected_image_usage));
+    Usage iu = p->GetHandleUsage(20);
+    EXPECT_THAT(iu.to_str(), Eq(GetParam().expected_image_usage));
 
-  Usage su = p->GetHandleUsage(20);
+    Usage su = p->GetHandleUsage(20);
 }
 
 TEST_P(SpvParserHandleTest_RegisterHandleUsage_RawImage, FunctionParam) {
-  const bool is_storage = GetParam().type.find("storage") != std::string::npos;
-  const bool is_write = GetParam().inst.find("ImageWrite") != std::string::npos;
-  const auto assembly = Preamble() + FragMain() + Bindings({20}) +
-                        (is_storage ? std::string("OpDecorate %20 ") +
-                                          std::string(is_write ? "NonReadable"
-                                                               : "NonWritable")
-                                    : std::string("")) +
-                        " " + CommonTypes() + R"(
+    const bool is_storage = GetParam().type.find("storage") != std::string::npos;
+    const bool is_write = GetParam().inst.find("ImageWrite") != std::string::npos;
+    const auto assembly = Preamble() + FragMain() + Bindings({20}) +
+                          (is_storage ? std::string("OpDecorate %20 ") +
+                                            std::string(is_write ? "NonReadable" : "NonWritable")
+                                      : std::string("")) +
+                          " " + CommonTypes() + R"(
      %f_ty = OpTypeFunction %void %ptr_)" +
-                        GetParam().type + R"(
+                          GetParam().type + R"(
 
      %20 = OpVariable %ptr_)" +
-                        GetParam().type + R"( UniformConstant
+                          GetParam().type + R"( UniformConstant
 
      %func = OpFunction %void None %f_ty
      %i_param = OpFunctionParameter %ptr_)" +
-                        GetParam().type + R"(
+                          GetParam().type + R"(
      %func_entry = OpLabel
      %im = OpLoad %)" + GetParam().type +
-                        R"( %i_param
+                          R"( %i_param
 
 )" + GetParam().inst + R"(
 
@@ -1141,16 +1098,16 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildInternalModule());
-  EXPECT_TRUE(p->RegisterHandleUsage());
-  EXPECT_TRUE(p->error().empty());
-  Usage iu = p->GetHandleUsage(20);
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildInternalModule());
+    EXPECT_TRUE(p->RegisterHandleUsage());
+    EXPECT_TRUE(p->error().empty());
+    Usage iu = p->GetHandleUsage(20);
 
-  EXPECT_THAT(iu.to_str(), Eq(GetParam().expected_image_usage));
+    EXPECT_THAT(iu.to_str(), Eq(GetParam().expected_image_usage));
 
-  // Textures and samplers not yet supported as function parameters.
-  p->SkipDumpingPending("crbug.com/tint/785");
+    // Textures and samplers not yet supported as function parameters.
+    p->SkipDumpingPending("crbug.com/tint/785");
 }
 
 INSTANTIATE_TEST_SUITE_P(
@@ -1159,13 +1116,11 @@
     ::testing::Values(
 
         // OpImageRead
-        UsageRawImageCase{"f_storage_1d",
-                          "%result = OpImageRead %v4float %im %uint_1",
+        UsageRawImageCase{"f_storage_1d", "%result = OpImageRead %v4float %im %uint_1",
                           "Usage(Texture( read ))"},
 
         // OpImageWrite
-        UsageRawImageCase{"f_storage_1d",
-                          "OpImageWrite %im %uint_1 %v4float_null",
+        UsageRawImageCase{"f_storage_1d", "OpImageWrite %im %uint_1 %v4float_null",
                           "Usage(Texture( write ))"},
 
         // OpImageFetch
@@ -1207,63 +1162,60 @@
 // use in image access instructions in executable code.  For these we have
 // to infer usage from the SPIR-V sampler or image type.
 struct DeclUnderspecifiedHandleCase {
-  std::string decorations;  // SPIR-V decorations
-  std::string inst;         // SPIR-V variable declarations
-  std::string var_decl;     // WGSL variable declaration
+    std::string decorations;  // SPIR-V decorations
+    std::string inst;         // SPIR-V variable declarations
+    std::string var_decl;     // WGSL variable declaration
 };
-inline std::ostream& operator<<(std::ostream& out,
-                                const DeclUnderspecifiedHandleCase& c) {
-  out << "DeclUnderspecifiedHandleCase(" << c.inst << "\n" << c.var_decl << ")";
-  return out;
+inline std::ostream& operator<<(std::ostream& out, const DeclUnderspecifiedHandleCase& c) {
+    out << "DeclUnderspecifiedHandleCase(" << c.inst << "\n" << c.var_decl << ")";
+    return out;
 }
 
 using SpvParserHandleTest_DeclUnderspecifiedHandle =
     SpvParserTestBase<::testing::TestWithParam<DeclUnderspecifiedHandleCase>>;
 
 TEST_P(SpvParserHandleTest_DeclUnderspecifiedHandle, Variable) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      OpEntryPoint Fragment %main "main"
      OpExecutionMode %main OriginUpperLeft
      OpDecorate %10 DescriptorSet 0
      OpDecorate %10 Binding 0
 )" + GetParam().decorations +
-                        CommonTypes() + GetParam().inst +
-                        R"(
+                          CommonTypes() + GetParam().inst +
+                          R"(
 
      %main = OpFunction %void None %voidfn
      %entry = OpLabel
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty()) << p->error();
-  const auto program = test::ToString(p->program());
-  EXPECT_THAT(program, HasSubstr(GetParam().var_decl)) << program;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty()) << p->error();
+    const auto program = test::ToString(p->program());
+    EXPECT_THAT(program, HasSubstr(GetParam().var_decl)) << program;
 }
 
-INSTANTIATE_TEST_SUITE_P(
-    Samplers,
-    SpvParserHandleTest_DeclUnderspecifiedHandle,
-    ::testing::Values(
+INSTANTIATE_TEST_SUITE_P(Samplers,
+                         SpvParserHandleTest_DeclUnderspecifiedHandle,
+                         ::testing::Values(
 
-        DeclUnderspecifiedHandleCase{
-            "", R"(
+                             DeclUnderspecifiedHandleCase{
+                                 "", R"(
          %ptr = OpTypePointer UniformConstant %sampler
          %10 = OpVariable %ptr UniformConstant
 )",
-            R"(@group(0) @binding(0) var x_10 : sampler;)"}));
+                                 R"(@group(0) @binding(0) var x_10 : sampler;)"}));
 
 INSTANTIATE_TEST_SUITE_P(
     Images,
     SpvParserHandleTest_DeclUnderspecifiedHandle,
     ::testing::Values(
 
-        DeclUnderspecifiedHandleCase{
-            "", R"(
+        DeclUnderspecifiedHandleCase{"", R"(
          %10 = OpVariable %ptr_f_texture_1d UniformConstant
 )",
-            R"(@group(0) @binding(0) var x_10 : texture_1d<f32>;)"},
+                                     R"(@group(0) @binding(0) var x_10 : texture_1d<f32>;)"},
         DeclUnderspecifiedHandleCase{
             R"(
          OpDecorate %10 NonWritable
@@ -1284,31 +1236,30 @@
 // Test handle declaration or error, when there is an image access.
 
 struct ImageDeclCase {
-  // SPIR-V image type, excluding result ID and opcode
-  std::string spirv_image_type_details;
-  std::string spirv_image_access;  // Optional instruction to provoke use
-  std::string expected_error;
-  std::string expected_decl;
+    // SPIR-V image type, excluding result ID and opcode
+    std::string spirv_image_type_details;
+    std::string spirv_image_access;  // Optional instruction to provoke use
+    std::string expected_error;
+    std::string expected_decl;
 };
 
 inline std::ostream& operator<<(std::ostream& out, const ImageDeclCase& c) {
-  out << "ImageDeclCase(" << c.spirv_image_type_details << "\n"
-      << "access: " << c.spirv_image_access << "\n"
-      << "error: " << c.expected_error << "\n"
-      << "decl:" << c.expected_decl << "\n)";
-  return out;
+    out << "ImageDeclCase(" << c.spirv_image_type_details << "\n"
+        << "access: " << c.spirv_image_access << "\n"
+        << "error: " << c.expected_error << "\n"
+        << "decl:" << c.expected_decl << "\n)";
+    return out;
 }
 
 using SpvParserHandleTest_ImageDeclTest =
     SpvParserTestBase<::testing::TestWithParam<ImageDeclCase>>;
 
 TEST_P(SpvParserHandleTest_ImageDeclTest, DeclareAndUseHandle) {
-  // Only declare the sampled image type, and the associated variable
-  // if the requested image type is a sampled image type and not multisampled.
-  const bool is_sampled_image_type = GetParam().spirv_image_type_details.find(
-                                         "0 1 Unknown") != std::string::npos;
-  const auto assembly =
-      Preamble() + R"(
+    // Only declare the sampled image type, and the associated variable
+    // if the requested image type is a sampled image type and not multisampled.
+    const bool is_sampled_image_type =
+        GetParam().spirv_image_type_details.find("0 1 Unknown") != std::string::npos;
+    const auto assembly = Preamble() + R"(
      OpEntryPoint Fragment %100 "main"
      OpExecutionMode %100 OriginUpperLeft
      OpName %float_var "float_var"
@@ -1332,14 +1283,14 @@
      OpDecorate %30 DescriptorSet 0
      OpDecorate %30 Binding 1
 )" + CommonBasicTypes() +
-      R"(
+                          R"(
      %sampler = OpTypeSampler
      %ptr_sampler = OpTypePointer UniformConstant %sampler
      %im_ty = OpTypeImage )" +
-      GetParam().spirv_image_type_details + R"(
+                          GetParam().spirv_image_type_details + R"(
      %ptr_im_ty = OpTypePointer UniformConstant %im_ty
 )" + (is_sampled_image_type ? " %si_ty = OpTypeSampledImage %im_ty " : "") +
-      R"(
+                          R"(
 
      %ptr_float = OpTypePointer Function %float
 
@@ -1370,28 +1321,25 @@
      %sam = OpLoad %sampler %10
      %im = OpLoad %im_ty %20
 
-)" +
-      (is_sampled_image_type
-           ? " %sampled_image = OpSampledImage %si_ty %im %sam "
-           : "") +
-      GetParam().spirv_image_access +
-      R"(
+)" + (is_sampled_image_type ? " %sampled_image = OpSampledImage %si_ty %im %sam " : "") +
+                          GetParam().spirv_image_access +
+                          R"(
      ; Use an anchor for the cases when the image access doesn't have a result ID.
      %1000 = OpCopyObject %uint %uint_0
 
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  const bool succeeded = p->BuildAndParseInternalModule();
-  if (succeeded) {
-    EXPECT_TRUE(GetParam().expected_error.empty());
-    const auto got = test::ToString(p->program());
-    EXPECT_THAT(got, HasSubstr(GetParam().expected_decl));
-  } else {
-    EXPECT_FALSE(GetParam().expected_error.empty());
-    EXPECT_THAT(p->error(), HasSubstr(GetParam().expected_error));
-  }
+    auto p = parser(test::Assemble(assembly));
+    const bool succeeded = p->BuildAndParseInternalModule();
+    if (succeeded) {
+        EXPECT_TRUE(GetParam().expected_error.empty());
+        const auto got = test::ToString(p->program());
+        EXPECT_THAT(got, HasSubstr(GetParam().expected_decl));
+    } else {
+        EXPECT_FALSE(GetParam().expected_error.empty());
+        EXPECT_THAT(p->error(), HasSubstr(GetParam().expected_error));
+    }
 }
 
 INSTANTIATE_TEST_SUITE_P(
@@ -1402,49 +1350,46 @@
          "WGSL multisampled textures must be 2d and non-arrayed: ", ""},
         {"%float 1D 0 1 1 1 Unknown", "%result = OpImageQuerySamples %uint %im",
          "WGSL arrayed textures must be 2d_array or cube_array: ", ""},
-        {"%float 2D 0 0 1 1 Unknown", "%result = OpImageQuerySamples %uint %im",
-         "", "@group(2) @binding(1) var x_20 : texture_multisampled_2d<f32>;"},
+        {"%float 2D 0 0 1 1 Unknown", "%result = OpImageQuerySamples %uint %im", "",
+         "@group(2) @binding(1) var x_20 : texture_multisampled_2d<f32>;"},
         {"%float 2D 0 1 1 1 Unknown", "%result = OpImageQuerySamples %uint %im",
          "WGSL multisampled textures must be 2d and non-arrayed: ", ""},
         {"%float 3D 0 0 1 1 Unknown", "%result = OpImageQuerySamples %uint %im",
          "WGSL multisampled textures must be 2d and non-arrayed: ", ""},
         {"%float 3D 0 1 1 1 Unknown", "%result = OpImageQuerySamples %uint %im",
          "WGSL arrayed textures must be 2d_array or cube_array: ", ""},
-        {"%float Cube 0 0 1 1 Unknown",
-         "%result = OpImageQuerySamples %uint %im",
+        {"%float Cube 0 0 1 1 Unknown", "%result = OpImageQuerySamples %uint %im",
          "WGSL multisampled textures must be 2d and non-arrayed: ", ""},
-        {"%float Cube 0 1 1 1 Unknown",
-         "%result = OpImageQuerySamples %uint %im",
+        {"%float Cube 0 1 1 1 Unknown", "%result = OpImageQuerySamples %uint %im",
          "WGSL multisampled textures must be 2d and non-arrayed: ", ""}}));
 
 // Test emission of variables when we have image accesses in executable code.
 
 struct ImageAccessCase {
-  // SPIR-V image type, excluding result ID and opcode
-  std::string spirv_image_type_details;
-  std::string spirv_image_access;  // The provoking image access instruction.
-  std::string var_decl;            // WGSL variable declaration
-  std::string texture_builtin;     // WGSL texture usage.
+    // SPIR-V image type, excluding result ID and opcode
+    std::string spirv_image_type_details;
+    std::string spirv_image_access;  // The provoking image access instruction.
+    std::string var_decl;            // WGSL variable declaration
+    std::string texture_builtin;     // WGSL texture usage.
 };
 inline std::ostream& operator<<(std::ostream& out, const ImageAccessCase& c) {
-  out << "ImageCase(" << c.spirv_image_type_details << "\n"
-      << c.spirv_image_access << "\n"
-      << c.var_decl << "\n"
-      << c.texture_builtin << ")";
-  return out;
+    out << "ImageCase(" << c.spirv_image_type_details << "\n"
+        << c.spirv_image_access << "\n"
+        << c.var_decl << "\n"
+        << c.texture_builtin << ")";
+    return out;
 }
 
 using SpvParserHandleTest_SampledImageAccessTest =
     SpvParserTestBase<::testing::TestWithParam<ImageAccessCase>>;
 
 TEST_P(SpvParserHandleTest_SampledImageAccessTest, Variable) {
-  // Only declare the sampled image type, and the associated variable
-  // if the requested image type is a sampled image type, and not a
-  // multisampled texture
-  const bool is_sampled_image_type = GetParam().spirv_image_type_details.find(
-                                         "0 1 Unknown") != std::string::npos;
-  const auto assembly =
-      Preamble() + R"(
+    // Only declare the sampled image type, and the associated variable
+    // if the requested image type is a sampled image type, and not a
+    // multisampled texture
+    const bool is_sampled_image_type =
+        GetParam().spirv_image_type_details.find("0 1 Unknown") != std::string::npos;
+    const auto assembly = Preamble() + R"(
      OpEntryPoint Fragment %main "main"
      OpExecutionMode %main OriginUpperLeft
      OpName %f1 "f1"
@@ -1473,14 +1418,14 @@
      OpDecorate %30 DescriptorSet 0
      OpDecorate %30 Binding 1
 )" + CommonBasicTypes() +
-      R"(
+                          R"(
      %sampler = OpTypeSampler
      %ptr_sampler = OpTypePointer UniformConstant %sampler
      %im_ty = OpTypeImage )" +
-      GetParam().spirv_image_type_details + R"(
+                          GetParam().spirv_image_type_details + R"(
      %ptr_im_ty = OpTypePointer UniformConstant %im_ty
 )" + (is_sampled_image_type ? " %si_ty = OpTypeSampledImage %im_ty " : "") +
-      R"(
+                          R"(
 
      %10 = OpVariable %ptr_sampler UniformConstant
      %20 = OpVariable %ptr_im_ty UniformConstant
@@ -1516,38 +1461,32 @@
 
      %sam = OpLoad %sampler %10
      %im = OpLoad %im_ty %20
-)" +
-      (is_sampled_image_type
-           ? " %sampled_image = OpSampledImage %si_ty %im %sam\n"
-           : "") +
-      GetParam().spirv_image_access +
-      R"(
+)" + (is_sampled_image_type ? " %sampled_image = OpSampledImage %si_ty %im %sam\n" : "") +
+                          GetParam().spirv_image_access +
+                          R"(
 
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty()) << p->error();
-  const auto program = test::ToString(p->program());
-  EXPECT_THAT(program, HasSubstr(GetParam().var_decl))
-      << "DECLARATIONS ARE BAD " << program;
-  EXPECT_THAT(program, HasSubstr(GetParam().texture_builtin))
-      << "TEXTURE BUILTIN IS BAD " << program << assembly;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty()) << p->error();
+    const auto program = test::ToString(p->program());
+    EXPECT_THAT(program, HasSubstr(GetParam().var_decl)) << "DECLARATIONS ARE BAD " << program;
+    EXPECT_THAT(program, HasSubstr(GetParam().texture_builtin))
+        << "TEXTURE BUILTIN IS BAD " << program << assembly;
 
-  const bool is_query_size =
-      GetParam().spirv_image_access.find("ImageQuerySize") != std::string::npos;
-  const bool is_1d =
-      GetParam().spirv_image_type_details.find("1D") != std::string::npos;
-  if (is_query_size && is_1d) {
-    p->SkipDumpingPending("crbug.com/tint/788");
-  }
+    const bool is_query_size =
+        GetParam().spirv_image_access.find("ImageQuerySize") != std::string::npos;
+    const bool is_1d = GetParam().spirv_image_type_details.find("1D") != std::string::npos;
+    if (is_query_size && is_1d) {
+        p->SkipDumpingPending("crbug.com/tint/788");
+    }
 }
 
 // TODO(dneto): Test variable declaration and texture builtins provoked by
 // use of an image access instruction inside helper function.
-TEST_P(SpvParserHandleTest_RegisterHandleUsage_SampledImage,
-       DISABLED_FunctionParam) {}
+TEST_P(SpvParserHandleTest_RegisterHandleUsage_SampledImage, DISABLED_FunctionParam) {}
 
 INSTANTIATE_TEST_SUITE_P(
     ImageGather,
@@ -1560,16 +1499,15 @@
                         R"(@group(0) @binding(0) var x_10 : sampler;
 
 @group(2) @binding(1) var x_20 : texture_2d<f32>;)",
-                        "textureGather(1, x_20, x_10, coords12)"},
+                        "textureGather(1i, x_20, x_10, coords12)"},
         // OpImageGather 2D ConstOffset signed
-        ImageAccessCase{
-            "%float 2D 0 0 0 1 Unknown",
-            "%result = OpImageGather "
-            "%v4float %sampled_image %coords12 %int_1 ConstOffset %offsets2d",
-            R"(@group(0) @binding(0) var x_10 : sampler;
+        ImageAccessCase{"%float 2D 0 0 0 1 Unknown",
+                        "%result = OpImageGather "
+                        "%v4float %sampled_image %coords12 %int_1 ConstOffset %offsets2d",
+                        R"(@group(0) @binding(0) var x_10 : sampler;
 
 @group(2) @binding(1) var x_20 : texture_2d<f32>;)",
-            "textureGather(1, x_20, x_10, coords12, vec2<i32>(3, 4))"},
+                        "textureGather(1i, x_20, x_10, coords12, vec2<i32>(3i, 4i))"},
         // OpImageGather 2D ConstOffset unsigned
         ImageAccessCase{"%float 2D 0 0 0 1 Unknown",
                         "%result = OpImageGather "
@@ -1578,7 +1516,7 @@
                         R"(@group(0) @binding(0) var x_10 : sampler;
 
 @group(2) @binding(1) var x_20 : texture_2d<f32>;)",
-                        "textureGather(1, x_20, x_10, coords12, "
+                        "textureGather(1i, x_20, x_10, coords12, "
                         "vec2<i32>(vec2<u32>(3u, 4u)))"},
         // OpImageGather 2D Array
         ImageAccessCase{"%float 2D 0 1 0 1 Unknown",
@@ -1587,18 +1525,17 @@
                         R"(@group(0) @binding(0) var x_10 : sampler;
 
 @group(2) @binding(1) var x_20 : texture_2d_array<f32>;)",
-                        "textureGather(1, x_20, x_10, coords123.xy, "
+                        "textureGather(1i, x_20, x_10, coords123.xy, "
                         "i32(round(coords123.z)))"},
         // OpImageGather 2D Array ConstOffset signed
-        ImageAccessCase{
-            "%float 2D 0 1 0 1 Unknown",
-            "%result = OpImageGather "
-            "%v4float %sampled_image %coords123 %int_1 ConstOffset %offsets2d",
-            R"(@group(0) @binding(0) var x_10 : sampler;
+        ImageAccessCase{"%float 2D 0 1 0 1 Unknown",
+                        "%result = OpImageGather "
+                        "%v4float %sampled_image %coords123 %int_1 ConstOffset %offsets2d",
+                        R"(@group(0) @binding(0) var x_10 : sampler;
 
 @group(2) @binding(1) var x_20 : texture_2d_array<f32>;)",
-            "textureGather(1, x_20, x_10, coords123.xy, "
-            "i32(round(coords123.z)), vec2<i32>(3, 4))"},
+                        "textureGather(1i, x_20, x_10, coords123.xy, "
+                        "i32(round(coords123.z)), vec2<i32>(3i, 4i))"},
         // OpImageGather 2D Array ConstOffset unsigned
         ImageAccessCase{"%float 2D 0 1 0 1 Unknown",
                         "%result = OpImageGather "
@@ -1607,7 +1544,7 @@
                         R"(@group(0) @binding(0) var x_10 : sampler;
 
 @group(2) @binding(1) var x_20 : texture_2d_array<f32>;)",
-                        "textureGather(1, x_20, x_10, coords123.xy, "
+                        "textureGather(1i, x_20, x_10, coords123.xy, "
                         "i32(round(coords123.z)), "
                         "vec2<i32>(vec2<u32>(3u, 4u)))"},
         // OpImageGather Cube
@@ -1617,7 +1554,7 @@
                         R"(@group(0) @binding(0) var x_10 : sampler;
 
 @group(2) @binding(1) var x_20 : texture_cube<f32>;)",
-                        "textureGather(1, x_20, x_10, coords123)"},
+                        "textureGather(1i, x_20, x_10, coords123)"},
         // OpImageGather Cube Array
         ImageAccessCase{"%float Cube 0 1 0 1 Unknown",
                         "%result = OpImageGather "
@@ -1625,7 +1562,7 @@
                         R"(@group(0) @binding(0) var x_10 : sampler;
 
 @group(2) @binding(1) var x_20 : texture_cube_array<f32>;)",
-                        "textureGather(1, x_20, x_10, coords1234.xyz, "
+                        "textureGather(1i, x_20, x_10, coords1234.xyz, "
                         "i32(round(coords1234.w)))"},
         // OpImageGather 2DDepth
         ImageAccessCase{"%float 2D 1 0 0 1 Unknown",
@@ -1636,14 +1573,13 @@
 @group(2) @binding(1) var x_20 : texture_depth_2d;)",
                         "textureGather(x_20, x_10, coords12)"},
         // OpImageGather 2DDepth ConstOffset signed
-        ImageAccessCase{
-            "%float 2D 1 0 0 1 Unknown",
-            "%result = OpImageGather "
-            "%v4float %sampled_image %coords12 %int_1 ConstOffset %offsets2d",
-            R"(@group(0) @binding(0) var x_10 : sampler;
+        ImageAccessCase{"%float 2D 1 0 0 1 Unknown",
+                        "%result = OpImageGather "
+                        "%v4float %sampled_image %coords12 %int_1 ConstOffset %offsets2d",
+                        R"(@group(0) @binding(0) var x_10 : sampler;
 
 @group(2) @binding(1) var x_20 : texture_depth_2d;)",
-            "textureGather(x_20, x_10, coords12, vec2<i32>(3, 4))"},
+                        "textureGather(x_20, x_10, coords12, vec2<i32>(3i, 4i))"},
         // OpImageGather 2DDepth ConstOffset unsigned
         ImageAccessCase{"%float 2D 1 0 0 1 Unknown",
                         "%result = OpImageGather "
@@ -1664,15 +1600,14 @@
                         "textureGather(x_20, x_10, coords123.xy, "
                         "i32(round(coords123.z)))"},
         // OpImageGather 2DDepth Array ConstOffset signed
-        ImageAccessCase{
-            "%float 2D 1 1 0 1 Unknown",
-            "%result = OpImageGather "
-            "%v4float %sampled_image %coords123 %int_1 ConstOffset %offsets2d",
-            R"(@group(0) @binding(0) var x_10 : sampler;
+        ImageAccessCase{"%float 2D 1 1 0 1 Unknown",
+                        "%result = OpImageGather "
+                        "%v4float %sampled_image %coords123 %int_1 ConstOffset %offsets2d",
+                        R"(@group(0) @binding(0) var x_10 : sampler;
 
 @group(2) @binding(1) var x_20 : texture_depth_2d_array;)",
-            "textureGather(x_20, x_10, coords123.xy, "
-            "i32(round(coords123.z)), vec2<i32>(3, 4))"},
+                        "textureGather(x_20, x_10, coords123.xy, "
+                        "i32(round(coords123.z)), vec2<i32>(3i, 4i))"},
         // OpImageGather 2DDepth Array ConstOffset unsigned
         ImageAccessCase{"%float 2D 1 1 0 1 Unknown",
                         "%result = OpImageGather "
@@ -1707,35 +1642,32 @@
     SpvParserHandleTest_SampledImageAccessTest,
     ::testing::ValuesIn(std::vector<ImageAccessCase>{
         // OpImageDrefGather 2DDepth
-        ImageAccessCase{
-            "%float 2D 1 0 0 1 Unknown",
-            "%result = OpImageDrefGather "
-            "%v4float %sampled_image %coords12 %depth",
-            R"(@group(0) @binding(0) var x_10 : sampler_comparison;
+        ImageAccessCase{"%float 2D 1 0 0 1 Unknown",
+                        "%result = OpImageDrefGather "
+                        "%v4float %sampled_image %coords12 %depth",
+                        R"(@group(0) @binding(0) var x_10 : sampler_comparison;
 
 @group(2) @binding(1) var x_20 : texture_depth_2d;)",
-            "textureGatherCompare(x_20, x_10, coords12, 0.200000003)"},
+                        "textureGatherCompare(x_20, x_10, coords12, 0.200000003)"},
         // OpImageDrefGather 2DDepth ConstOffset signed
-        ImageAccessCase{
-            "%float 2D 1 0 0 1 Unknown",
-            "%result = OpImageDrefGather "
-            "%v4float %sampled_image %coords12 %depth ConstOffset %offsets2d",
-            R"(@group(0) @binding(0) var x_10 : sampler_comparison;
+        ImageAccessCase{"%float 2D 1 0 0 1 Unknown",
+                        "%result = OpImageDrefGather "
+                        "%v4float %sampled_image %coords12 %depth ConstOffset %offsets2d",
+                        R"(@group(0) @binding(0) var x_10 : sampler_comparison;
 
 @group(2) @binding(1) var x_20 : texture_depth_2d;)",
-            "textureGatherCompare(x_20, x_10, coords12, 0.200000003, "
-            "vec2<i32>(3, 4))"},
+                        "textureGatherCompare(x_20, x_10, coords12, 0.200000003, "
+                        "vec2<i32>(3i, 4i))"},
         // OpImageDrefGather 2DDepth ConstOffset unsigned
-        ImageAccessCase{
-            "%float 2D 1 0 0 1 Unknown",
-            "%result = OpImageDrefGather "
-            "%v4float %sampled_image %coords12 %depth ConstOffset "
-            "%u_offsets2d",
-            R"(@group(0) @binding(0) var x_10 : sampler_comparison;
+        ImageAccessCase{"%float 2D 1 0 0 1 Unknown",
+                        "%result = OpImageDrefGather "
+                        "%v4float %sampled_image %coords12 %depth ConstOffset "
+                        "%u_offsets2d",
+                        R"(@group(0) @binding(0) var x_10 : sampler_comparison;
 
 @group(2) @binding(1) var x_20 : texture_depth_2d;)",
-            "textureGatherCompare(x_20, x_10, coords12, 0.200000003, "
-            "vec2<i32>(vec2<u32>(3u, 4u)))"},
+                        "textureGatherCompare(x_20, x_10, coords12, 0.200000003, "
+                        "vec2<i32>(vec2<u32>(3u, 4u)))"},
         // OpImageDrefGather 2DDepth Array
         ImageAccessCase{"%float 2D 1 1 0 1 Unknown",
                         "%result = OpImageDrefGather "
@@ -1746,15 +1678,14 @@
                         "textureGatherCompare(x_20, x_10, coords123.xy, "
                         "i32(round(coords123.z)), 0.200000003)"},
         // OpImageDrefGather 2DDepth Array ConstOffset signed
-        ImageAccessCase{
-            "%float 2D 1 1 0 1 Unknown",
-            "%result = OpImageDrefGather "
-            "%v4float %sampled_image %coords123 %depth ConstOffset %offsets2d",
-            R"(@group(0) @binding(0) var x_10 : sampler_comparison;
+        ImageAccessCase{"%float 2D 1 1 0 1 Unknown",
+                        "%result = OpImageDrefGather "
+                        "%v4float %sampled_image %coords123 %depth ConstOffset %offsets2d",
+                        R"(@group(0) @binding(0) var x_10 : sampler_comparison;
 
 @group(2) @binding(1) var x_20 : texture_depth_2d_array;)",
-            "textureGatherCompare(x_20, x_10, coords123.xy, "
-            "i32(round(coords123.z)), 0.200000003, vec2<i32>(3, 4))"},
+                        "textureGatherCompare(x_20, x_10, coords123.xy, "
+                        "i32(round(coords123.z)), 0.200000003, vec2<i32>(3i, 4i))"},
         // OpImageDrefGather 2DDepth Array ConstOffset unsigned
         ImageAccessCase{"%float 2D 1 1 0 1 Unknown",
                         "%result = OpImageDrefGather "
@@ -1767,14 +1698,13 @@
                         "i32(round(coords123.z)), 0.200000003, "
                         "vec2<i32>(vec2<u32>(3u, 4u)))"},
         // OpImageDrefGather DepthCube
-        ImageAccessCase{
-            "%float Cube 1 0 0 1 Unknown",
-            "%result = OpImageDrefGather "
-            "%v4float %sampled_image %coords123 %depth",
-            R"(@group(0) @binding(0) var x_10 : sampler_comparison;
+        ImageAccessCase{"%float Cube 1 0 0 1 Unknown",
+                        "%result = OpImageDrefGather "
+                        "%v4float %sampled_image %coords123 %depth",
+                        R"(@group(0) @binding(0) var x_10 : sampler_comparison;
 
 @group(2) @binding(1) var x_20 : texture_depth_cube;)",
-            "textureGatherCompare(x_20, x_10, coords123, 0.200000003)"},
+                        "textureGatherCompare(x_20, x_10, coords123, 0.200000003)"},
         // OpImageDrefGather DepthCube Array
         ImageAccessCase{"%float Cube 1 1 0 1 Unknown",
                         "%result = OpImageDrefGather "
@@ -1800,24 +1730,22 @@
                         "textureSample(x_20, x_10, coords12)"},
 
         // OpImageSampleImplicitLod arrayed
-        ImageAccessCase{
-            "%float 2D 0 1 0 1 Unknown",
-            "%result = OpImageSampleImplicitLod "
-            "%v4float %sampled_image %coords123",
-            R"(@group(0) @binding(0) var x_10 : sampler;
+        ImageAccessCase{"%float 2D 0 1 0 1 Unknown",
+                        "%result = OpImageSampleImplicitLod "
+                        "%v4float %sampled_image %coords123",
+                        R"(@group(0) @binding(0) var x_10 : sampler;
 
 @group(2) @binding(1) var x_20 : texture_2d_array<f32>;)",
-            "textureSample(x_20, x_10, coords123.xy, i32(round(coords123.z)))"},
+                        "textureSample(x_20, x_10, coords123.xy, i32(round(coords123.z)))"},
 
         // OpImageSampleImplicitLod with ConstOffset
-        ImageAccessCase{
-            "%float 2D 0 0 0 1 Unknown",
-            "%result = OpImageSampleImplicitLod "
-            "%v4float %sampled_image %coords12 ConstOffset %offsets2d",
-            R"(@group(0) @binding(0) var x_10 : sampler;
+        ImageAccessCase{"%float 2D 0 0 0 1 Unknown",
+                        "%result = OpImageSampleImplicitLod "
+                        "%v4float %sampled_image %coords12 ConstOffset %offsets2d",
+                        R"(@group(0) @binding(0) var x_10 : sampler;
 
 @group(2) @binding(1) var x_20 : texture_2d<f32>;)",
-            "textureSample(x_20, x_10, coords12, vec2<i32>(3, 4))"},
+                        "textureSample(x_20, x_10, coords12, vec2<i32>(3i, 4i))"},
 
         // OpImageSampleImplicitLod arrayed with ConstOffset
         ImageAccessCase{
@@ -1827,7 +1755,7 @@
             R"(@group(0) @binding(0) var x_10 : sampler;
 
 @group(2) @binding(1) var x_20 : texture_2d_array<f32>;)",
-            R"(textureSample(x_20, x_10, coords123.xy, i32(round(coords123.z)), vec2<i32>(3, 4)))"},
+            R"(textureSample(x_20, x_10, coords123.xy, i32(round(coords123.z)), vec2<i32>(3i, 4i)))"},
 
         // OpImageSampleImplicitLod with Bias
         ImageAccessCase{"%float 2D 0 0 0 1 Unknown",
@@ -1849,15 +1777,14 @@
             R"(textureSampleBias(x_20, x_10, coords123.xy, i32(round(coords123.z)), 7.0))"},
 
         // OpImageSampleImplicitLod with Bias and signed ConstOffset
-        ImageAccessCase{
-            "%float 2D 0 0 0 1 Unknown",
-            "%result = OpImageSampleImplicitLod "
-            "%v4float %sampled_image %coords12 Bias|ConstOffset "
-            "%float_7 %offsets2d",
-            R"(@group(0) @binding(0) var x_10 : sampler;
+        ImageAccessCase{"%float 2D 0 0 0 1 Unknown",
+                        "%result = OpImageSampleImplicitLod "
+                        "%v4float %sampled_image %coords12 Bias|ConstOffset "
+                        "%float_7 %offsets2d",
+                        R"(@group(0) @binding(0) var x_10 : sampler;
 
 @group(2) @binding(1) var x_20 : texture_2d<f32>;)",
-            R"(textureSampleBias(x_20, x_10, coords12, 7.0, vec2<i32>(3, 4))"},
+                        R"(textureSampleBias(x_20, x_10, coords12, 7.0, vec2<i32>(3i, 4i))"},
 
         // OpImageSampleImplicitLod with Bias and unsigned ConstOffset
         // Convert ConstOffset to signed
@@ -1879,7 +1806,7 @@
             R"(@group(0) @binding(0) var x_10 : sampler;
 
 @group(2) @binding(1) var x_20 : texture_2d_array<f32>;)",
-            R"(textureSampleBias(x_20, x_10, coords123.xy, i32(round(coords123.z)), 7.0, vec2<i32>(3, 4))"}));
+            R"(textureSampleBias(x_20, x_10, coords123.xy, i32(round(coords123.z)), 7.0, vec2<i32>(3i, 4i))"}));
 
 INSTANTIATE_TEST_SUITE_P(
     // This test shows the use of a sampled image used with both regular
@@ -1913,15 +1840,14 @@
     SpvParserHandleTest_SampledImageAccessTest,
     ::testing::Values(
         // ImageSampleDrefImplicitLod
-        ImageAccessCase{
-            "%float 2D 0 0 0 1 Unknown",
-            "%result = OpImageSampleDrefImplicitLod "
-            "%float %sampled_image %coords12 %depth",
-            R"(@group(0) @binding(0) var x_10 : sampler_comparison;
+        ImageAccessCase{"%float 2D 0 0 0 1 Unknown",
+                        "%result = OpImageSampleDrefImplicitLod "
+                        "%float %sampled_image %coords12 %depth",
+                        R"(@group(0) @binding(0) var x_10 : sampler_comparison;
 
 @group(2) @binding(1) var x_20 : texture_depth_2d;
 )",
-            R"(textureSampleCompare(x_20, x_10, coords12, 0.200000003))"},
+                        R"(textureSampleCompare(x_20, x_10, coords12, 0.200000003))"},
         // ImageSampleDrefImplicitLod - arrayed
         ImageAccessCase{
             "%float 2D 0 1 0 1 Unknown",
@@ -1940,7 +1866,7 @@
 
 @group(2) @binding(1) var x_20 : texture_depth_2d;
 )",
-            R"(textureSampleCompare(x_20, x_10, coords12, 0.200000003, vec2<i32>(3, 4)))"},
+            R"(textureSampleCompare(x_20, x_10, coords12, 0.200000003, vec2<i32>(3i, 4i)))"},
         // ImageSampleDrefImplicitLod arrayed with ConstOffset
         ImageAccessCase{
             "%float 2D 0 1 0 1 Unknown",
@@ -1949,7 +1875,7 @@
             R"(@group(0) @binding(0) var x_10 : sampler_comparison;
 
 @group(2) @binding(1) var x_20 : texture_depth_2d_array;)",
-            R"(textureSampleCompare(x_20, x_10, coords123.xy, i32(round(coords123.z)), 0.200000003, vec2<i32>(3, 4)))"}));
+            R"(textureSampleCompare(x_20, x_10, coords123.xy, i32(round(coords123.z)), 0.200000003, vec2<i32>(3i, 4i)))"}));
 
 INSTANTIATE_TEST_SUITE_P(
     ImageSampleDrefExplicitLod,
@@ -1958,15 +1884,14 @@
     // Another test checks cases where the Lod is not float constant 0.
     ::testing::Values(
         // 2D
-        ImageAccessCase{
-            "%float 2D 1 0 0 1 Unknown",
-            "%result = OpImageSampleDrefExplicitLod "
-            "%float %sampled_image %coords12 %depth Lod %float_0",
-            R"(@group(0) @binding(0) var x_10 : sampler_comparison;
+        ImageAccessCase{"%float 2D 1 0 0 1 Unknown",
+                        "%result = OpImageSampleDrefExplicitLod "
+                        "%float %sampled_image %coords12 %depth Lod %float_0",
+                        R"(@group(0) @binding(0) var x_10 : sampler_comparison;
 
 @group(2) @binding(1) var x_20 : texture_depth_2d;
 )",
-            R"(textureSampleCompareLevel(x_20, x_10, coords12, 0.200000003))"},
+                        R"(textureSampleCompareLevel(x_20, x_10, coords12, 0.200000003))"},
         // 2D array
         ImageAccessCase{
             "%float 2D 1 1 0 1 Unknown",
@@ -1986,7 +1911,7 @@
 
 @group(2) @binding(1) var x_20 : texture_depth_2d;
 )",
-            R"(textureSampleCompareLevel(x_20, x_10, coords12, 0.200000003, vec2<i32>(3, 4)))"},
+            R"(textureSampleCompareLevel(x_20, x_10, coords12, 0.200000003, vec2<i32>(3i, 4i)))"},
         // 2D array, ConstOffset
         ImageAccessCase{
             "%float 2D 1 1 0 1 Unknown",
@@ -1996,16 +1921,15 @@
             R"(@group(0) @binding(0) var x_10 : sampler_comparison;
 
 @group(2) @binding(1) var x_20 : texture_depth_2d_array;)",
-            R"(textureSampleCompareLevel(x_20, x_10, coords123.xy, i32(round(coords123.z)), 0.200000003, vec2<i32>(3, 4)))"},
+            R"(textureSampleCompareLevel(x_20, x_10, coords123.xy, i32(round(coords123.z)), 0.200000003, vec2<i32>(3i, 4i)))"},
         // Cube
-        ImageAccessCase{
-            "%float Cube 1 0 0 1 Unknown",
-            "%result = OpImageSampleDrefExplicitLod "
-            "%float %sampled_image %coords123 %depth Lod %float_0",
-            R"(@group(0) @binding(0) var x_10 : sampler_comparison;
+        ImageAccessCase{"%float Cube 1 0 0 1 Unknown",
+                        "%result = OpImageSampleDrefExplicitLod "
+                        "%float %sampled_image %coords123 %depth Lod %float_0",
+                        R"(@group(0) @binding(0) var x_10 : sampler_comparison;
 
 @group(2) @binding(1) var x_20 : texture_depth_cube;)",
-            R"(textureSampleCompareLevel(x_20, x_10, coords123, 0.200000003))"},
+                        R"(textureSampleCompareLevel(x_20, x_10, coords123, 0.200000003))"},
         // Cube array
         ImageAccessCase{
             "%float Cube 1 1 0 1 Unknown",
@@ -2041,15 +1965,14 @@
             R"(textureSampleLevel(x_20, x_10, coords123.xy, i32(round(coords123.z)), 0.0))"},
 
         // OpImageSampleExplicitLod - using Lod and ConstOffset
-        ImageAccessCase{
-            "%float 2D 0 0 0 1 Unknown",
-            "%result = OpImageSampleExplicitLod "
-            "%v4float %sampled_image %coords12 Lod|ConstOffset "
-            "%float_null %offsets2d",
-            R"(@group(0) @binding(0) var x_10 : sampler;
+        ImageAccessCase{"%float 2D 0 0 0 1 Unknown",
+                        "%result = OpImageSampleExplicitLod "
+                        "%v4float %sampled_image %coords12 Lod|ConstOffset "
+                        "%float_null %offsets2d",
+                        R"(@group(0) @binding(0) var x_10 : sampler;
 
 @group(2) @binding(1) var x_20 : texture_2d<f32>;)",
-            R"(textureSampleLevel(x_20, x_10, coords12, 0.0, vec2<i32>(3, 4)))"},
+                        R"(textureSampleLevel(x_20, x_10, coords12, 0.0, vec2<i32>(3i, 4i)))"},
 
         // OpImageSampleExplicitLod - using Lod and unsigned ConstOffset
         // Convert the ConstOffset operand to signed
@@ -2072,7 +1995,7 @@
             R"(@group(0) @binding(0) var x_10 : sampler;
 
 @group(2) @binding(1) var x_20 : texture_2d_array<f32>;)",
-            R"(textureSampleLevel(x_20, x_10, coords123.xy, i32(round(coords123.z)), 0.0, vec2<i32>(3, 4)))"}));
+            R"(textureSampleLevel(x_20, x_10, coords123.xy, i32(round(coords123.z)), 0.0, vec2<i32>(3i, 4i)))"}));
 
 INSTANTIATE_TEST_SUITE_P(
     ImageSampleExplicitLod_UsingGrad,
@@ -2080,14 +2003,13 @@
     ::testing::Values(
 
         // OpImageSampleExplicitLod - using Grad
-        ImageAccessCase{
-            "%float 2D 0 0 0 1 Unknown",
-            "%result = OpImageSampleExplicitLod "
-            "%v4float %sampled_image %coords12 Grad %vf12 %vf21",
-            R"(@group(0) @binding(0) var x_10 : sampler;
+        ImageAccessCase{"%float 2D 0 0 0 1 Unknown",
+                        "%result = OpImageSampleExplicitLod "
+                        "%v4float %sampled_image %coords12 Grad %vf12 %vf21",
+                        R"(@group(0) @binding(0) var x_10 : sampler;
 
 @group(2) @binding(1) var x_20 : texture_2d<f32>;)",
-            R"(textureSampleGrad(x_20, x_10, coords12, vf12, vf21))"},
+                        R"(textureSampleGrad(x_20, x_10, coords12, vf12, vf21))"},
 
         // OpImageSampleExplicitLod arrayed - using Grad
         ImageAccessCase{
@@ -2108,7 +2030,7 @@
             R"(@group(0) @binding(0) var x_10 : sampler;
 
 @group(2) @binding(1) var x_20 : texture_2d<f32>;)",
-            R"(textureSampleGrad(x_20, x_10, coords12, vf12, vf21, vec2<i32>(3, 4)))"},
+            R"(textureSampleGrad(x_20, x_10, coords12, vf12, vf21, vec2<i32>(3i, 4i)))"},
 
         // OpImageSampleExplicitLod - using Grad and unsigned ConstOffset
         ImageAccessCase{
@@ -2130,7 +2052,7 @@
             R"(@group(0) @binding(0) var x_10 : sampler;
 
 @group(2) @binding(1) var x_20 : texture_2d_array<f32>;)",
-            R"(textureSampleGrad(x_20, x_10, coords123.xy, i32(round(coords123.z)), vf12, vf21, vec2<i32>(3, 4)))"},
+            R"(textureSampleGrad(x_20, x_10, coords123.xy, i32(round(coords123.z)), vf12, vf21, vec2<i32>(3i, 4i)))"},
 
         // OpImageSampleExplicitLod arrayed - using Grad and unsigned
         // ConstOffset
@@ -2203,34 +2125,31 @@
     ::testing::Values(
 
         // OpImageSampleProjImplicitLod 1D
-        ImageAccessCase{
-            "%float 1D 0 0 0 1 Unknown",
-            "%result = OpImageSampleProjImplicitLod "
-            "%v4float %sampled_image %coords12",
-            R"(@group(0) @binding(0) var x_10 : sampler;
+        ImageAccessCase{"%float 1D 0 0 0 1 Unknown",
+                        "%result = OpImageSampleProjImplicitLod "
+                        "%v4float %sampled_image %coords12",
+                        R"(@group(0) @binding(0) var x_10 : sampler;
 
 @group(2) @binding(1) var x_20 : texture_1d<f32>;)",
-            R"(textureSample(x_20, x_10, (coords12.x / coords12.y)))"},
+                        R"(textureSample(x_20, x_10, (coords12.x / coords12.y)))"},
 
         // OpImageSampleProjImplicitLod 2D
-        ImageAccessCase{
-            "%float 2D 0 0 0 1 Unknown",
-            "%result = OpImageSampleProjImplicitLod "
-            "%v4float %sampled_image %coords123",
-            R"(@group(0) @binding(0) var x_10 : sampler;
+        ImageAccessCase{"%float 2D 0 0 0 1 Unknown",
+                        "%result = OpImageSampleProjImplicitLod "
+                        "%v4float %sampled_image %coords123",
+                        R"(@group(0) @binding(0) var x_10 : sampler;
 
 @group(2) @binding(1) var x_20 : texture_2d<f32>;)",
-            R"(textureSample(x_20, x_10, (coords123.xy / coords123.z)))"},
+                        R"(textureSample(x_20, x_10, (coords123.xy / coords123.z)))"},
 
         // OpImageSampleProjImplicitLod 3D
-        ImageAccessCase{
-            "%float 3D 0 0 0 1 Unknown",
-            "%result = OpImageSampleProjImplicitLod "
-            "%v4float %sampled_image %coords1234",
-            R"(@group(0) @binding(0) var x_10 : sampler;
+        ImageAccessCase{"%float 3D 0 0 0 1 Unknown",
+                        "%result = OpImageSampleProjImplicitLod "
+                        "%v4float %sampled_image %coords1234",
+                        R"(@group(0) @binding(0) var x_10 : sampler;
 
 @group(2) @binding(1) var x_20 : texture_3d<f32>;)",
-            R"(textureSample(x_20, x_10, (coords1234.xyz / coords1234.w)))"},
+                        R"(textureSample(x_20, x_10, (coords1234.xyz / coords1234.w)))"},
 
         // OpImageSampleProjImplicitLod 2D with ConstOffset
         // (Don't need to test with 1D or 3D, as the hard part was the splatted
@@ -2242,7 +2161,7 @@
             R"(@group(0) @binding(0) var x_10 : sampler;
 
 @group(2) @binding(1) var x_20 : texture_2d<f32>;)",
-            R"(textureSample(x_20, x_10, (coords123.xy / coords123.z), vec2<i32>(3, 4)))"}));
+            R"(textureSample(x_20, x_10, (coords123.xy / coords123.z), vec2<i32>(3i, 4i)))"}));
 
 INSTANTIATE_TEST_SUITE_P(
     ImageSampleProjImplicitLod_Bias,
@@ -2251,14 +2170,13 @@
 
         // OpImageSampleProjImplicitLod with Bias
         // Only testing 2D
-        ImageAccessCase{
-            "%float 2D 0 0 0 1 Unknown",
-            "%result = OpImageSampleProjImplicitLod "
-            "%v4float %sampled_image %coords123 Bias %float_7",
-            R"(@group(0) @binding(0) var x_10 : sampler;
+        ImageAccessCase{"%float 2D 0 0 0 1 Unknown",
+                        "%result = OpImageSampleProjImplicitLod "
+                        "%v4float %sampled_image %coords123 Bias %float_7",
+                        R"(@group(0) @binding(0) var x_10 : sampler;
 
 @group(2) @binding(1) var x_20 : texture_2d<f32>;)",
-            R"(textureSampleBias(x_20, x_10, (coords123.xy / coords123.z), 7.0))"},
+                        R"(textureSampleBias(x_20, x_10, (coords123.xy / coords123.z), 7.0))"},
 
         // OpImageSampleProjImplicitLod with Bias and signed ConstOffset
         ImageAccessCase{
@@ -2269,7 +2187,7 @@
             R"(@group(0) @binding(0) var x_10 : sampler;
 
 @group(2) @binding(1) var x_20 : texture_2d<f32>;)",
-            R"(textureSampleBias(x_20, x_10, (coords123.xy / coords123.z), 7.0, vec2<i32>(3, 4)))"},
+            R"(textureSampleBias(x_20, x_10, (coords123.xy / coords123.z), 7.0, vec2<i32>(3i, 4i)))"},
 
         // OpImageSampleProjImplicitLod with Bias and unsigned ConstOffset
         // Convert ConstOffset to signed
@@ -2288,14 +2206,13 @@
     SpvParserHandleTest_SampledImageAccessTest,
     ::testing::Values(
         // OpImageSampleProjExplicitLod 2D
-        ImageAccessCase{
-            "%float 2D 0 0 0 1 Unknown",
-            "%result = OpImageSampleProjExplicitLod "
-            "%v4float %sampled_image %coords123 Lod %f1",
-            R"(@group(0) @binding(0) var x_10 : sampler;
+        ImageAccessCase{"%float 2D 0 0 0 1 Unknown",
+                        "%result = OpImageSampleProjExplicitLod "
+                        "%v4float %sampled_image %coords123 Lod %f1",
+                        R"(@group(0) @binding(0) var x_10 : sampler;
 
 @group(2) @binding(1) var x_20 : texture_2d<f32>;)",
-            R"(textureSampleLevel(x_20, x_10, (coords123.xy / coords123.z), f1))"},
+                        R"(textureSampleLevel(x_20, x_10, (coords123.xy / coords123.z), f1))"},
 
         // OpImageSampleProjExplicitLod 2D Lod with ConstOffset
         ImageAccessCase{
@@ -2305,7 +2222,7 @@
             R"(@group(0) @binding(0) var x_10 : sampler;
 
 @group(2) @binding(1) var x_20 : texture_2d<f32>;)",
-            R"(textureSampleLevel(x_20, x_10, (coords123.xy / coords123.z), f1, vec2<i32>(3, 4)))"}));
+            R"(textureSampleLevel(x_20, x_10, (coords123.xy / coords123.z), f1, vec2<i32>(3i, 4i)))"}));
 
 INSTANTIATE_TEST_SUITE_P(
     ImageSampleProjExplicitLod_Grad,
@@ -2330,7 +2247,7 @@
             R"(@group(0) @binding(0) var x_10 : sampler;
 
 @group(2) @binding(1) var x_20 : texture_2d<f32>;)",
-            R"(textureSampleGrad(x_20, x_10, (coords123.xy / coords123.z), vf12, vf21, vec2<i32>(3, 4)))"}));
+            R"(textureSampleGrad(x_20, x_10, (coords123.xy / coords123.z), vf12, vf21, vec2<i32>(3i, 4i)))"}));
 
 INSTANTIATE_TEST_SUITE_P(
     // Ordinary (non-comparison) sampling on a depth texture.
@@ -2357,15 +2274,14 @@
     ::testing::Values(
 
         // OpImageSampleProjDrefImplicitLod 2D depth-texture
-        ImageAccessCase{
-            "%float 2D 1 0 0 1 Unknown",
-            "%result = OpImageSampleProjDrefImplicitLod "
-            "%float %sampled_image %coords123 %f1",
-            R"(@group(0) @binding(0) var x_10 : sampler_comparison;
+        ImageAccessCase{"%float 2D 1 0 0 1 Unknown",
+                        "%result = OpImageSampleProjDrefImplicitLod "
+                        "%float %sampled_image %coords123 %f1",
+                        R"(@group(0) @binding(0) var x_10 : sampler_comparison;
 
 @group(2) @binding(1) var x_20 : texture_depth_2d;
 )",
-            R"(textureSampleCompare(x_20, x_10, (coords123.xy / coords123.z), f1))"},
+                        R"(textureSampleCompare(x_20, x_10, (coords123.xy / coords123.z), f1))"},
 
         // OpImageSampleProjDrefImplicitLod 2D depth-texture, ConstOffset
         ImageAccessCase{
@@ -2376,7 +2292,7 @@
 
 @group(2) @binding(1) var x_20 : texture_depth_2d;
 )",
-            R"(textureSampleCompare(x_20, x_10, (coords123.xy / coords123.z), f1, vec2<i32>(3, 4)))"}));
+            R"(textureSampleCompare(x_20, x_10, (coords123.xy / coords123.z), f1, vec2<i32>(3i, 4i)))"}));
 
 INSTANTIATE_TEST_SUITE_P(
     DISABLED_ImageSampleProjDrefExplicitLod_Lod,
@@ -2407,7 +2323,7 @@
 
 @group(2) @binding(1) var x_20 : texture_depth_2d;
 )",
-            R"(textureSampleCompareLevel(x_20, x_10, (coords123.xy / coords123.z), 0.200000003, 0.0, vec2<i32>(3, 4)))"}));
+            R"(textureSampleCompareLevel(x_20, x_10, (coords123.xy / coords123.z), 0.200000003, 0.0, vec2<i32>(3i, 4i)))"}));
 
 /////
 // End projection sampling
@@ -2417,8 +2333,8 @@
     SpvParserTestBase<::testing::TestWithParam<ImageAccessCase>>;
 
 TEST_P(SpvParserHandleTest_ImageAccessTest, Variable) {
-  // In this test harness, we only create an image.
-  const auto assembly = Preamble() + R"(
+    // In this test harness, we only create an image.
+    const auto assembly = Preamble() + R"(
      OpEntryPoint Fragment %main "main"
      OpExecutionMode %main OriginUpperLeft
      OpName %f1 "f1"
@@ -2437,9 +2353,9 @@
      OpDecorate %20 DescriptorSet 2
      OpDecorate %20 Binding 1
 )" + CommonBasicTypes() +
-                        R"(
+                          R"(
      %im_ty = OpTypeImage )" +
-                        GetParam().spirv_image_type_details + R"(
+                          GetParam().spirv_image_type_details + R"(
      %ptr_im_ty = OpTypePointer UniformConstant %im_ty
      %20 = OpVariable %ptr_im_ty UniformConstant
 
@@ -2466,26 +2382,24 @@
      %im = OpLoad %im_ty %20
 
 )" + GetParam().spirv_image_access +
-                        R"(
+                          R"(
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty()) << p->error();
-  const auto program = test::ToString(p->program());
-  EXPECT_THAT(program, HasSubstr(GetParam().var_decl))
-      << "DECLARATIONS ARE BAD " << program;
-  EXPECT_THAT(program, HasSubstr(GetParam().texture_builtin))
-      << "TEXTURE BUILTIN IS BAD " << program << assembly;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty()) << p->error();
+    const auto program = test::ToString(p->program());
+    EXPECT_THAT(program, HasSubstr(GetParam().var_decl)) << "DECLARATIONS ARE BAD " << program;
+    EXPECT_THAT(program, HasSubstr(GetParam().texture_builtin))
+        << "TEXTURE BUILTIN IS BAD " << program << assembly;
 }
 
 INSTANTIATE_TEST_SUITE_P(ImageWrite_OptionalParams,
                          SpvParserHandleTest_ImageAccessTest,
                          ::testing::ValuesIn(std::vector<ImageAccessCase>{
                              // OpImageWrite with no extra params
-                             {"%float 2D 0 0 0 2 Rgba32f",
-                              "OpImageWrite %im %vi12 %vf1234",
+                             {"%float 2D 0 0 0 2 Rgba32f", "OpImageWrite %im %vi12 %vf1234",
                               "@group(2) @binding(1) var x_20 : "
                               "texture_storage_2d<rgba32float, write>;",
                               "textureStore(x_20, vi12, vf1234);"}}));
@@ -2535,7 +2449,7 @@
          "textureStore(x_20, vi12, vf1234);"}}));
 
 TEST_F(SpvParserHandleTest, ImageWrite_TooFewSrcTexelComponents_1_vs_4) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      OpEntryPoint Fragment %main "main"
      OpExecutionMode %main OriginUpperLeft
      OpName %f1 "f1"
@@ -2543,7 +2457,7 @@
      OpDecorate %20 DescriptorSet 2
      OpDecorate %20 Binding 1
 )" + CommonBasicTypes() +
-                        R"(
+                          R"(
      %im_ty = OpTypeImage %void 2D 0 0 0 2 Rgba32f
      %ptr_im_ty = OpTypePointer UniformConstant %im_ty
 
@@ -2561,12 +2475,11 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_FALSE(p->BuildAndParseInternalModule());
-  EXPECT_THAT(p->error(),
-              Eq("texel has too few components for storage texture: 1 provided "
-                 "but 4 required, in: OpImageWrite %54 %3 %2"))
-      << p->error();
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_FALSE(p->BuildAndParseInternalModule());
+    EXPECT_THAT(p->error(), Eq("texel has too few components for storage texture: 1 provided "
+                               "but 4 required, in: OpImageWrite %54 %3 %2"))
+        << p->error();
 }
 
 INSTANTIATE_TEST_SUITE_P(
@@ -2651,7 +2564,7 @@
         // Source signed, dest signed
         {"%int 2D 0 0 0 2 R32i", "OpImageWrite %im %vi12 %vi12",
          R"(@group(2) @binding(1) var x_20 : texture_storage_2d<r32sint, write>;)",
-         R"(textureStore(x_20, vi12, vec4<i32>(vi12, 0, 0)))"}}));
+         R"(textureStore(x_20, vi12, vec4<i32>(vi12, 0i, 0i)))"}}));
 
 INSTANTIATE_TEST_SUITE_P(
     ImageFetch_OptionalParams,
@@ -2661,22 +2574,20 @@
         // Level of detail is injected for sampled texture
         {"%float 2D 0 0 0 1 Unknown", "%99 = OpImageFetch %v4float %im %vi12",
          R"(@group(2) @binding(1) var x_20 : texture_2d<f32>;)",
-         R"(let x_99 : vec4<f32> = textureLoad(x_20, vi12, 0);)"},
+         R"(let x_99 : vec4<f32> = textureLoad(x_20, vi12, 0i);)"},
         // OpImageFetch with explicit level, on sampled texture
-        {"%float 2D 0 0 0 1 Unknown",
-         "%99 = OpImageFetch %v4float %im %vi12 Lod %int_3",
+        {"%float 2D 0 0 0 1 Unknown", "%99 = OpImageFetch %v4float %im %vi12 Lod %int_3",
          R"(@group(2) @binding(1) var x_20 : texture_2d<f32>;)",
-         R"(let x_99 : vec4<f32> = textureLoad(x_20, vi12, 3);)"},
+         R"(let x_99 : vec4<f32> = textureLoad(x_20, vi12, 3i);)"},
         // OpImageFetch with no extra params, on depth texture
         // Level of detail is injected for depth texture
         {"%float 2D 1 0 0 1 Unknown", "%99 = OpImageFetch %v4float %im %vi12",
          R"(@group(2) @binding(1) var x_20 : texture_depth_2d;)",
-         R"(let x_99 : vec4<f32> = vec4<f32>(textureLoad(x_20, vi12, 0), 0.0, 0.0, 0.0);)"},
+         R"(let x_99 : vec4<f32> = vec4<f32>(textureLoad(x_20, vi12, 0i), 0.0, 0.0, 0.0);)"},
         // OpImageFetch with extra params, on depth texture
-        {"%float 2D 1 0 0 1 Unknown",
-         "%99 = OpImageFetch %v4float %im %vi12 Lod %int_3",
+        {"%float 2D 1 0 0 1 Unknown", "%99 = OpImageFetch %v4float %im %vi12 Lod %int_3",
          R"(@group(2) @binding(1) var x_20 : texture_depth_2d;)",
-         R"(let x_99 : vec4<f32> = vec4<f32>(textureLoad(x_20, vi12, 3), 0.0, 0.0, 0.0);)"}}));
+         R"(let x_99 : vec4<f32> = vec4<f32>(textureLoad(x_20, vi12, 3i), 0.0, 0.0, 0.0);)"}}));
 
 INSTANTIATE_TEST_SUITE_P(
     ImageFetch_Depth,
@@ -2689,7 +2600,7 @@
         // ImageFetch on depth image.
         {"%float 2D 1 0 0 1 Unknown", "%99 = OpImageFetch %v4float %im %vi12 ",
          R"(@group(2) @binding(1) var x_20 : texture_depth_2d;)",
-         R"(let x_99 : vec4<f32> = vec4<f32>(textureLoad(x_20, vi12, 0), 0.0, 0.0, 0.0);)"}}));
+         R"(let x_99 : vec4<f32> = vec4<f32>(textureLoad(x_20, vi12, 0i), 0.0, 0.0, 0.0);)"}}));
 
 INSTANTIATE_TEST_SUITE_P(
     ImageFetch_DepthMultisampled,
@@ -2700,151 +2611,146 @@
     SpvParserHandleTest_ImageAccessTest,
     ::testing::ValuesIn(std::vector<ImageAccessCase>{
         // ImageFetch on multisampled depth image.
-        {"%float 2D 1 0 1 1 Unknown",
-         "%99 = OpImageFetch %v4float %im %vi12 Sample %i1",
+        {"%float 2D 1 0 1 1 Unknown", "%99 = OpImageFetch %v4float %im %vi12 Sample %i1",
          R"(@group(2) @binding(1) var x_20 : texture_depth_multisampled_2d;)",
          R"(let x_99 : vec4<f32> = vec4<f32>(textureLoad(x_20, vi12, i1), 0.0, 0.0, 0.0);)"}}));
 
-INSTANTIATE_TEST_SUITE_P(
-    ImageFetch_Multisampled,
-    SpvParserHandleTest_ImageAccessTest,
-    ::testing::ValuesIn(std::vector<ImageAccessCase>{
-        // SPIR-V requires a Sample image operand when operating on a
-        // multisampled image.
+INSTANTIATE_TEST_SUITE_P(ImageFetch_Multisampled,
+                         SpvParserHandleTest_ImageAccessTest,
+                         ::testing::ValuesIn(std::vector<ImageAccessCase>{
+                             // SPIR-V requires a Sample image operand when operating on a
+                             // multisampled image.
 
-        // ImageFetch arrayed
-        // Not in WebGPU
+                             // ImageFetch arrayed
+                             // Not in WebGPU
 
-        // ImageFetch non-arrayed
-        {"%float 2D 0 0 1 1 Unknown",
-         "%99 = OpImageFetch %v4float %im %vi12 Sample %i1",
-         R"(@group(2) @binding(1) var x_20 : texture_multisampled_2d<f32>;)",
-         R"(let x_99 : vec4<f32> = textureLoad(x_20, vi12, i1);)"}}));
+                             // ImageFetch non-arrayed
+                             {"%float 2D 0 0 1 1 Unknown",
+                              "%99 = OpImageFetch %v4float %im %vi12 Sample %i1",
+                              R"(@group(2) @binding(1) var x_20 : texture_multisampled_2d<f32>;)",
+                              R"(let x_99 : vec4<f32> = textureLoad(x_20, vi12, i1);)"}}));
 
-INSTANTIATE_TEST_SUITE_P(
-    ImageFetch_Multisampled_ConvertSampleOperand,
-    SpvParserHandleTest_ImageAccessTest,
-    ::testing::ValuesIn(std::vector<ImageAccessCase>{
-        {"%float 2D 0 0 1 1 Unknown",
-         "%99 = OpImageFetch %v4float %im %vi12 Sample %u1",
-         R"(@group(2) @binding(1) var x_20 : texture_multisampled_2d<f32>;)",
-         R"(let x_99 : vec4<f32> = textureLoad(x_20, vi12, i32(u1));)"}}));
+INSTANTIATE_TEST_SUITE_P(ImageFetch_Multisampled_ConvertSampleOperand,
+                         SpvParserHandleTest_ImageAccessTest,
+                         ::testing::ValuesIn(std::vector<ImageAccessCase>{
+                             {"%float 2D 0 0 1 1 Unknown",
+                              "%99 = OpImageFetch %v4float %im %vi12 Sample %u1",
+                              R"(@group(2) @binding(1) var x_20 : texture_multisampled_2d<f32>;)",
+                              R"(let x_99 : vec4<f32> = textureLoad(x_20, vi12, i32(u1));)"}}));
 
-INSTANTIATE_TEST_SUITE_P(
-    ConvertResultSignedness,
-    SpvParserHandleTest_SampledImageAccessTest,
-    ::testing::ValuesIn(std::vector<ImageAccessCase>{
-        // Valid SPIR-V only has:
-        //      float scalar sampled type vs. floating result
-        //      integral scalar sampled type vs. integral result
-        // Any of the sampling, reading, or fetching use the same codepath.
+INSTANTIATE_TEST_SUITE_P(ConvertResultSignedness,
+                         SpvParserHandleTest_SampledImageAccessTest,
+                         ::testing::ValuesIn(std::vector<ImageAccessCase>{
+                             // Valid SPIR-V only has:
+                             //      float scalar sampled type vs. floating result
+                             //      integral scalar sampled type vs. integral result
+                             // Any of the sampling, reading, or fetching use the same codepath.
 
-        // We'll test with:
-        //     OpImageFetch
-        //     OpImageRead
-        //     OpImageSampleImplicitLod - representative of sampling
+                             // We'll test with:
+                             //     OpImageFetch
+                             //     OpImageRead
+                             //     OpImageSampleImplicitLod - representative of sampling
 
-        //
-        // OpImageRead
-        //
+                             //
+                             // OpImageRead
+                             //
 
-        // OpImageFetch requires no conversion, float -> v4float
-        {"%float 2D 0 0 0 1 Unknown", "%99 = OpImageFetch %v4float %im %vi12",
-         R"(@group(2) @binding(1) var x_20 : texture_2d<f32>;)",
-         R"(let x_99 : vec4<f32> = textureLoad(x_20, vi12, 0);)"},
-        // OpImageFetch requires no conversion, uint -> v4uint
-        {"%uint 2D 0 0 0 1 Unknown", "%99 = OpImageFetch %v4uint %im %vi12",
-         R"(@group(2) @binding(1) var x_20 : texture_2d<u32>;)",
-         R"(let x_99 : vec4<u32> = textureLoad(x_20, vi12, 0);)"},
-        // OpImageFetch requires conversion, uint -> v4int
-        // is invalid SPIR-V:
-        // "Expected Image 'Sampled Type' to be the same as Result Type
-        // components"
+                             // OpImageFetch requires no conversion, float -> v4float
+                             {"%float 2D 0 0 0 1 Unknown", "%99 = OpImageFetch %v4float %im %vi12",
+                              R"(@group(2) @binding(1) var x_20 : texture_2d<f32>;)",
+                              R"(let x_99 : vec4<f32> = textureLoad(x_20, vi12, 0i);)"},
+                             // OpImageFetch requires no conversion, uint -> v4uint
+                             {"%uint 2D 0 0 0 1 Unknown", "%99 = OpImageFetch %v4uint %im %vi12",
+                              R"(@group(2) @binding(1) var x_20 : texture_2d<u32>;)",
+                              R"(let x_99 : vec4<u32> = textureLoad(x_20, vi12, 0i);)"},
+                             // OpImageFetch requires conversion, uint -> v4int
+                             // is invalid SPIR-V:
+                             // "Expected Image 'Sampled Type' to be the same as Result Type
+                             // components"
 
-        // OpImageFetch requires no conversion, int -> v4int
-        {"%int 2D 0 0 0 1 Unknown", "%99 = OpImageFetch %v4int %im %vi12",
-         R"(@group(2) @binding(1) var x_20 : texture_2d<i32>;)",
-         R"(let x_99 : vec4<i32> = textureLoad(x_20, vi12, 0);)"},
-        // OpImageFetch requires conversion, int -> v4uint
-        // is invalid SPIR-V:
-        // "Expected Image 'Sampled Type' to be the same as Result Type
-        // components"
+                             // OpImageFetch requires no conversion, int -> v4int
+                             {"%int 2D 0 0 0 1 Unknown", "%99 = OpImageFetch %v4int %im %vi12",
+                              R"(@group(2) @binding(1) var x_20 : texture_2d<i32>;)",
+                              R"(let x_99 : vec4<i32> = textureLoad(x_20, vi12, 0i);)"},
+                             // OpImageFetch requires conversion, int -> v4uint
+                             // is invalid SPIR-V:
+                             // "Expected Image 'Sampled Type' to be the same as Result Type
+                             // components"
 
-        //
-        // OpImageRead
-        //
+                             //
+                             // OpImageRead
+                             //
 
-        // OpImageRead requires no conversion, float -> v4float
-        {"%float 2D 0 0 0 2 Rgba32f", "%99 = OpImageRead %v4float %im %vi12",
-         R"(@group(2) @binding(1) var x_20 : texture_2d<f32>;)",
-         R"(let x_99 : vec4<f32> = textureLoad(x_20, vi12, 0);)"},
-        // OpImageRead requires no conversion, uint -> v4uint
-        {"%uint 2D 0 0 0 2 Rgba32ui", "%99 = OpImageRead %v4uint %im %vi12",
-         R"(@group(2) @binding(1) var x_20 : texture_2d<u32>;)",
-         R"(let x_99 : vec4<u32> = textureLoad(x_20, vi12, 0);)"},
+                             // OpImageRead requires no conversion, float -> v4float
+                             {"%float 2D 0 0 0 2 Rgba32f", "%99 = OpImageRead %v4float %im %vi12",
+                              R"(@group(2) @binding(1) var x_20 : texture_2d<f32>;)",
+                              R"(let x_99 : vec4<f32> = textureLoad(x_20, vi12, 0i);)"},
+                             // OpImageRead requires no conversion, uint -> v4uint
+                             {"%uint 2D 0 0 0 2 Rgba32ui", "%99 = OpImageRead %v4uint %im %vi12",
+                              R"(@group(2) @binding(1) var x_20 : texture_2d<u32>;)",
+                              R"(let x_99 : vec4<u32> = textureLoad(x_20, vi12, 0i);)"},
 
-        // OpImageRead requires conversion, uint -> v4int
-        // is invalid SPIR-V:
-        // "Expected Image 'Sampled Type' to be the same as Result Type
-        // components"
+                             // OpImageRead requires conversion, uint -> v4int
+                             // is invalid SPIR-V:
+                             // "Expected Image 'Sampled Type' to be the same as Result Type
+                             // components"
 
-        // OpImageRead requires no conversion, int -> v4int
-        {"%int 2D 0 0 0 2 Rgba32i", "%99 = OpImageRead %v4int %im %vi12",
-         R"(@group(2) @binding(1) var x_20 : texture_2d<i32>;)",
-         R"(let x_99 : vec4<i32> = textureLoad(x_20, vi12, 0);)"},
+                             // OpImageRead requires no conversion, int -> v4int
+                             {"%int 2D 0 0 0 2 Rgba32i", "%99 = OpImageRead %v4int %im %vi12",
+                              R"(@group(2) @binding(1) var x_20 : texture_2d<i32>;)",
+                              R"(let x_99 : vec4<i32> = textureLoad(x_20, vi12, 0i);)"},
 
-        // OpImageRead requires conversion, int -> v4uint
-        // is invalid SPIR-V:
-        // "Expected Image 'Sampled Type' to be the same as Result Type
-        // components"
+                             // OpImageRead requires conversion, int -> v4uint
+                             // is invalid SPIR-V:
+                             // "Expected Image 'Sampled Type' to be the same as Result Type
+                             // components"
 
-        //
-        // Sampling operations, using OpImageSampleImplicitLod as an example.
-        // WGSL sampling operations only work on textures with a float sampled
-        // component.  So we can only test the float -> float (non-conversion)
-        // case.
+                             //
+                             // Sampling operations, using OpImageSampleImplicitLod as an example.
+                             // WGSL sampling operations only work on textures with a float sampled
+                             // component.  So we can only test the float -> float (non-conversion)
+                             // case.
 
-        // OpImageSampleImplicitLod requires no conversion, float -> v4float
-        {"%float 2D 0 0 0 1 Unknown",
-         "%99 = OpImageSampleImplicitLod %v4float %sampled_image %vf12",
-         R"(@group(0) @binding(0) var x_10 : sampler;
+                             // OpImageSampleImplicitLod requires no conversion, float -> v4float
+                             {"%float 2D 0 0 0 1 Unknown",
+                              "%99 = OpImageSampleImplicitLod %v4float %sampled_image %vf12",
+                              R"(@group(0) @binding(0) var x_10 : sampler;
 
 @group(2) @binding(1) var x_20 : texture_2d<f32>;)",
-         R"(let x_99 : vec4<f32> = textureSample(x_20, x_10, vf12);)"}}));
+                              R"(let x_99 : vec4<f32> = textureSample(x_20, x_10, vf12);)"}}));
 
-INSTANTIATE_TEST_SUITE_P(
-    ImageQuerySize_NonArrayed_SignedResult,
-    // ImageQuerySize requires storage image or multisampled
-    // For storage image, use another instruction to indicate whether it
-    // is readonly or writeonly.
-    SpvParserHandleTest_SampledImageAccessTest,
-    ::testing::ValuesIn(std::vector<ImageAccessCase>{
-        // 1D storage image
-        {"%float 1D 0 0 0 2 Rgba32f",
-         "%99 = OpImageQuerySize %int %im \n"
-         "%98 = OpImageRead %v4float %im %i1\n",  // Implicitly mark as
-                                                  // NonWritable
-         R"(@group(2) @binding(1) var x_20 : texture_1d<f32>;)",
-         R"(let x_99 : i32 = i32(textureDimensions(x_20));)"},
-        // 2D storage image
-        {"%float 2D 0 0 0 2 Rgba32f",
-         "%99 = OpImageQuerySize %v2int %im \n"
-         "%98 = OpImageRead %v4float %im %vi12\n",  // Implicitly mark as
-                                                    // NonWritable
-         R"(@group(2) @binding(1) var x_20 : texture_2d<f32>;)",
-         R"(let x_99 : vec2<i32> = vec2<i32>(textureDimensions(x_20))"},
-        // 3D storage image
-        {"%float 3D 0 0 0 2 Rgba32f",
-         "%99 = OpImageQuerySize %v3int %im \n"
-         "%98 = OpImageRead %v4float %im %vi123\n",  // Implicitly mark as
-                                                     // NonWritable
-         R"(@group(2) @binding(1) var x_20 : texture_3d<f32>;)",
-         R"(let x_99 : vec3<i32> = vec3<i32>(textureDimensions(x_20));)"},
+INSTANTIATE_TEST_SUITE_P(ImageQuerySize_NonArrayed_SignedResult,
+                         // ImageQuerySize requires storage image or multisampled
+                         // For storage image, use another instruction to indicate whether it
+                         // is readonly or writeonly.
+                         SpvParserHandleTest_SampledImageAccessTest,
+                         ::testing::ValuesIn(std::vector<ImageAccessCase>{
+                             // 1D storage image
+                             {"%float 1D 0 0 0 2 Rgba32f",
+                              "%99 = OpImageQuerySize %int %im \n"
+                              "%98 = OpImageRead %v4float %im %i1\n",  // Implicitly mark as
+                                                                       // NonWritable
+                              R"(@group(2) @binding(1) var x_20 : texture_1d<f32>;)",
+                              R"(let x_99 : i32 = i32(textureDimensions(x_20));)"},
+                             // 2D storage image
+                             {"%float 2D 0 0 0 2 Rgba32f",
+                              "%99 = OpImageQuerySize %v2int %im \n"
+                              "%98 = OpImageRead %v4float %im %vi12\n",  // Implicitly mark as
+                                                                         // NonWritable
+                              R"(@group(2) @binding(1) var x_20 : texture_2d<f32>;)",
+                              R"(let x_99 : vec2<i32> = vec2<i32>(textureDimensions(x_20))"},
+                             // 3D storage image
+                             {"%float 3D 0 0 0 2 Rgba32f",
+                              "%99 = OpImageQuerySize %v3int %im \n"
+                              "%98 = OpImageRead %v4float %im %vi123\n",  // Implicitly mark as
+                                                                          // NonWritable
+                              R"(@group(2) @binding(1) var x_20 : texture_3d<f32>;)",
+                              R"(let x_99 : vec3<i32> = vec3<i32>(textureDimensions(x_20));)"},
 
-        // Multisampled
-        {"%float 2D 0 0 1 1 Unknown", "%99 = OpImageQuerySize %v2int %im \n",
-         R"(@group(2) @binding(1) var x_20 : texture_multisampled_2d<f32>;)",
-         R"(let x_99 : vec2<i32> = vec2<i32>(textureDimensions(x_20));)"}}));
+                             // Multisampled
+                             {"%float 2D 0 0 1 1 Unknown", "%99 = OpImageQuerySize %v2int %im \n",
+                              R"(@group(2) @binding(1) var x_20 : texture_multisampled_2d<f32>;)",
+                              R"(let x_99 : vec2<i32> = vec2<i32>(textureDimensions(x_20));)"}}));
 
 INSTANTIATE_TEST_SUITE_P(
     ImageQuerySize_Arrayed_SignedResult,
@@ -2874,38 +2780,32 @@
     SpvParserHandleTest_SampledImageAccessTest,
     ::testing::ValuesIn(std::vector<ImageAccessCase>{
         // 1D
-        {"%float 1D 0 0 0 1 Unknown",
-         "%99 = OpImageQuerySizeLod %int %im %i1\n",
+        {"%float 1D 0 0 0 1 Unknown", "%99 = OpImageQuerySizeLod %int %im %i1\n",
          R"(@group(2) @binding(1) var x_20 : texture_1d<f32>;)",
          R"(let x_99 : i32 = i32(textureDimensions(x_20, i1)))"},
 
         // 2D
-        {"%float 2D 0 0 0 1 Unknown",
-         "%99 = OpImageQuerySizeLod %v2int %im %i1\n",
+        {"%float 2D 0 0 0 1 Unknown", "%99 = OpImageQuerySizeLod %v2int %im %i1\n",
          R"(@group(2) @binding(1) var x_20 : texture_2d<f32>;)",
          R"(let x_99 : vec2<i32> = vec2<i32>(textureDimensions(x_20, i1));)"},
 
         // 3D
-        {"%float 3D 0 0 0 1 Unknown",
-         "%99 = OpImageQuerySizeLod %v3int %im %i1\n",
+        {"%float 3D 0 0 0 1 Unknown", "%99 = OpImageQuerySizeLod %v3int %im %i1\n",
          R"(@group(2) @binding(1) var x_20 : texture_3d<f32>;)",
          R"(let x_99 : vec3<i32> = vec3<i32>(textureDimensions(x_20, i1));)"},
 
         // Cube
-        {"%float Cube 0 0 0 1 Unknown",
-         "%99 = OpImageQuerySizeLod %v2int %im %i1\n",
+        {"%float Cube 0 0 0 1 Unknown", "%99 = OpImageQuerySizeLod %v2int %im %i1\n",
          R"(@group(2) @binding(1) var x_20 : texture_cube<f32>;)",
          R"(let x_99 : vec2<i32> = vec2<i32>(textureDimensions(x_20, i1).xy);)"},
 
         // Depth 2D
-        {"%float 2D 1 0 0 1 Unknown",
-         "%99 = OpImageQuerySizeLod %v2int %im %i1\n",
+        {"%float 2D 1 0 0 1 Unknown", "%99 = OpImageQuerySizeLod %v2int %im %i1\n",
          R"(@group(2) @binding(1) var x_20 : texture_depth_2d;)",
          R"(let x_99 : vec2<i32> = vec2<i32>(textureDimensions(x_20, i1));)"},
 
         // Depth Cube
-        {"%float Cube 1 0 0 1 Unknown",
-         "%99 = OpImageQuerySizeLod %v2int %im %i1\n",
+        {"%float Cube 1 0 0 1 Unknown", "%99 = OpImageQuerySizeLod %v2int %im %i1\n",
          R"(@group(2) @binding(1) var x_20 : texture_depth_cube;)",
          R"(let x_99 : vec2<i32> = vec2<i32>(textureDimensions(x_20, i1).xy);)"}}));
 
@@ -2920,8 +2820,7 @@
         // There is no 1D array
 
         // 2D array
-        {"%float 2D 0 1 0 1 Unknown",
-         "%99 = OpImageQuerySizeLod %v3int %im %i1\n",
+        {"%float 2D 0 1 0 1 Unknown", "%99 = OpImageQuerySizeLod %v3int %im %i1\n",
          R"(@group(2) @binding(1) var x_20 : texture_2d_array<f32>;)",
          R"(let x_99 : vec3<i32> = vec3<i32>(textureDimensions(x_20, i1), textureNumLayers(x_20));)"},
 
@@ -2932,14 +2831,12 @@
         // Currently textureDimension on cube returns vec3 but maybe should
         // return vec2
         // https://github.com/gpuweb/gpuweb/issues/1345
-        {"%float Cube 0 1 0 1 Unknown",
-         "%99 = OpImageQuerySizeLod %v3int %im %i1\n",
+        {"%float Cube 0 1 0 1 Unknown", "%99 = OpImageQuerySizeLod %v3int %im %i1\n",
          R"(@group(2) @binding(1) var x_20 : texture_cube_array<f32>;)",
          R"(let x_99 : vec3<i32> = vec3<i32>(textureDimensions(x_20, i1).xy, textureNumLayers(x_20));)"},
 
         // Depth 2D array
-        {"%float 2D 1 1 0 1 Unknown",
-         "%99 = OpImageQuerySizeLod %v3int %im %i1\n",
+        {"%float 2D 1 1 0 1 Unknown", "%99 = OpImageQuerySizeLod %v3int %im %i1\n",
          R"(@group(2) @binding(1) var x_20 : texture_depth_2d_array;)",
          R"(let x_99 : vec3<i32> = vec3<i32>(textureDimensions(x_20, i1), textureNumLayers(x_20));)"},
 
@@ -2948,8 +2845,7 @@
         // Currently textureDimension on cube returns vec3 but maybe should
         // return vec2
         // https://github.com/gpuweb/gpuweb/issues/1345
-        {"%float Cube 1 1 0 1 Unknown",
-         "%99 = OpImageQuerySizeLod %v3int %im %i1\n",
+        {"%float Cube 1 1 0 1 Unknown", "%99 = OpImageQuerySizeLod %v3int %im %i1\n",
          R"(@group(2) @binding(1) var x_20 : texture_depth_cube_array;)",
          R"(let x_99 : vec3<i32> = vec3<i32>(textureDimensions(x_20, i1).xy, textureNumLayers(x_20));)"}}));
 
@@ -2961,8 +2857,7 @@
     SpvParserHandleTest_SampledImageAccessTest,
     ::testing::ValuesIn(std::vector<ImageAccessCase>{
 
-        {"%float 1D 0 0 0 1 Unknown",
-         "%99 = OpImageQuerySizeLod %int %im %u1\n",
+        {"%float 1D 0 0 0 1 Unknown", "%99 = OpImageQuerySizeLod %int %im %u1\n",
          R"(@group(2) @binding(1) var x_20 : texture_1d<f32>;)",
          R"(let x_99 : i32 = i32(textureDimensions(x_20, i32(u1)));)"}}));
 
@@ -2975,64 +2870,62 @@
     SpvParserHandleTest_SampledImageAccessTest,
     ::testing::ValuesIn(std::vector<ImageAccessCase>{
 
-        {"%float 1D 0 0 0 1 Unknown",
-         "%99 = OpImageQuerySizeLod %uint %im %i1\n",
+        {"%float 1D 0 0 0 1 Unknown", "%99 = OpImageQuerySizeLod %uint %im %i1\n",
          R"(@group(2) @binding(1) var x_20 : texture_1d<f32>;)",
          R"(let x_99 : u32 = u32(textureDimensions(x_20, i1));)"}}));
 
-INSTANTIATE_TEST_SUITE_P(
-    ImageQueryLevels_SignedResult,
-    SpvParserHandleTest_SampledImageAccessTest,
-    ::testing::ValuesIn(std::vector<ImageAccessCase>{
-        // In Vulkan:
-        //      Dim must be 1D, 2D, 3D, Cube
-        // WGSL allows 2d, 2d_array, 3d, cube, cube_array
-        // depth_2d, depth_2d_array, depth_cube, depth_cube_array
+INSTANTIATE_TEST_SUITE_P(ImageQueryLevels_SignedResult,
+                         SpvParserHandleTest_SampledImageAccessTest,
+                         ::testing::ValuesIn(std::vector<ImageAccessCase>{
+                             // In Vulkan:
+                             //      Dim must be 1D, 2D, 3D, Cube
+                             // WGSL allows 2d, 2d_array, 3d, cube, cube_array
+                             // depth_2d, depth_2d_array, depth_cube, depth_cube_array
 
-        // 2D
-        {"%float 2D 0 0 0 1 Unknown", "%99 = OpImageQueryLevels %int %im\n",
-         R"(@group(2) @binding(1) var x_20 : texture_2d<f32>;)",
-         R"(let x_99 : i32 = textureNumLevels(x_20);)"},
+                             // 2D
+                             {"%float 2D 0 0 0 1 Unknown", "%99 = OpImageQueryLevels %int %im\n",
+                              R"(@group(2) @binding(1) var x_20 : texture_2d<f32>;)",
+                              R"(let x_99 : i32 = textureNumLevels(x_20);)"},
 
-        // 2D array
-        {"%float 2D 0 1 0 1 Unknown", "%99 = OpImageQueryLevels %int %im\n",
-         R"(@group(2) @binding(1) var x_20 : texture_2d_array<f32>;)",
-         R"(let x_99 : i32 = textureNumLevels(x_20);)"},
+                             // 2D array
+                             {"%float 2D 0 1 0 1 Unknown", "%99 = OpImageQueryLevels %int %im\n",
+                              R"(@group(2) @binding(1) var x_20 : texture_2d_array<f32>;)",
+                              R"(let x_99 : i32 = textureNumLevels(x_20);)"},
 
-        // 3D
-        {"%float 3D 0 0 0 1 Unknown", "%99 = OpImageQueryLevels %int %im\n",
-         R"(@group(2) @binding(1) var x_20 : texture_3d<f32>;)",
-         R"(let x_99 : i32 = textureNumLevels(x_20);)"},
+                             // 3D
+                             {"%float 3D 0 0 0 1 Unknown", "%99 = OpImageQueryLevels %int %im\n",
+                              R"(@group(2) @binding(1) var x_20 : texture_3d<f32>;)",
+                              R"(let x_99 : i32 = textureNumLevels(x_20);)"},
 
-        // Cube
-        {"%float Cube 0 0 0 1 Unknown", "%99 = OpImageQueryLevels %int %im\n",
-         R"(@group(2) @binding(1) var x_20 : texture_cube<f32>;)",
-         R"(let x_99 : i32 = textureNumLevels(x_20);)"},
+                             // Cube
+                             {"%float Cube 0 0 0 1 Unknown", "%99 = OpImageQueryLevels %int %im\n",
+                              R"(@group(2) @binding(1) var x_20 : texture_cube<f32>;)",
+                              R"(let x_99 : i32 = textureNumLevels(x_20);)"},
 
-        // Cube array
-        {"%float Cube 0 1 0 1 Unknown", "%99 = OpImageQueryLevels %int %im\n",
-         R"(@group(2) @binding(1) var x_20 : texture_cube_array<f32>;)",
-         R"(let x_99 : i32 = textureNumLevels(x_20);)"},
+                             // Cube array
+                             {"%float Cube 0 1 0 1 Unknown", "%99 = OpImageQueryLevels %int %im\n",
+                              R"(@group(2) @binding(1) var x_20 : texture_cube_array<f32>;)",
+                              R"(let x_99 : i32 = textureNumLevels(x_20);)"},
 
-        // depth 2d
-        {"%float 2D 1 0 0 1 Unknown", "%99 = OpImageQueryLevels %int %im\n",
-         R"(@group(2) @binding(1) var x_20 : texture_depth_2d;)",
-         R"(let x_99 : i32 = textureNumLevels(x_20);)"},
+                             // depth 2d
+                             {"%float 2D 1 0 0 1 Unknown", "%99 = OpImageQueryLevels %int %im\n",
+                              R"(@group(2) @binding(1) var x_20 : texture_depth_2d;)",
+                              R"(let x_99 : i32 = textureNumLevels(x_20);)"},
 
-        // depth 2d array
-        {"%float 2D 1 1 0 1 Unknown", "%99 = OpImageQueryLevels %int %im\n",
-         R"(@group(2) @binding(1) var x_20 : texture_depth_2d_array;)",
-         R"(let x_99 : i32 = textureNumLevels(x_20);)"},
+                             // depth 2d array
+                             {"%float 2D 1 1 0 1 Unknown", "%99 = OpImageQueryLevels %int %im\n",
+                              R"(@group(2) @binding(1) var x_20 : texture_depth_2d_array;)",
+                              R"(let x_99 : i32 = textureNumLevels(x_20);)"},
 
-        // depth cube
-        {"%float Cube 1 0 0 1 Unknown", "%99 = OpImageQueryLevels %int %im\n",
-         R"(@group(2) @binding(1) var x_20 : texture_depth_cube;)",
-         R"(let x_99 : i32 = textureNumLevels(x_20);)"},
+                             // depth cube
+                             {"%float Cube 1 0 0 1 Unknown", "%99 = OpImageQueryLevels %int %im\n",
+                              R"(@group(2) @binding(1) var x_20 : texture_depth_cube;)",
+                              R"(let x_99 : i32 = textureNumLevels(x_20);)"},
 
-        // depth cube array
-        {"%float Cube 1 1 0 1 Unknown", "%99 = OpImageQueryLevels %int %im\n",
-         R"(@group(2) @binding(1) var x_20 : texture_depth_cube_array;)",
-         R"(let x_99 : i32 = textureNumLevels(x_20);)"}}));
+                             // depth cube array
+                             {"%float Cube 1 1 0 1 Unknown", "%99 = OpImageQueryLevels %int %im\n",
+                              R"(@group(2) @binding(1) var x_20 : texture_depth_cube_array;)",
+                              R"(let x_99 : i32 = textureNumLevels(x_20);)"}}));
 
 INSTANTIATE_TEST_SUITE_P(
     // Spot check that a type conversion is inserted when SPIR-V asks for
@@ -3044,18 +2937,17 @@
          R"(@group(2) @binding(1) var x_20 : texture_2d<f32>;)",
          R"(let x_99 : u32 = u32(textureNumLevels(x_20));)"}}));
 
-INSTANTIATE_TEST_SUITE_P(
-    ImageQuerySamples_SignedResult,
-    SpvParserHandleTest_SampledImageAccessTest,
-    ::testing::ValuesIn(std::vector<ImageAccessCase>{
-        // Multsample 2D
-        {"%float 2D 0 0 1 1 Unknown", "%99 = OpImageQuerySamples %int %im\n",
-         R"(@group(2) @binding(1) var x_20 : texture_multisampled_2d<f32>;)",
-         R"(let x_99 : i32 = textureNumSamples(x_20);)"}  // namespace
+INSTANTIATE_TEST_SUITE_P(ImageQuerySamples_SignedResult,
+                         SpvParserHandleTest_SampledImageAccessTest,
+                         ::testing::ValuesIn(std::vector<ImageAccessCase>{
+                             // Multsample 2D
+                             {"%float 2D 0 0 1 1 Unknown", "%99 = OpImageQuerySamples %int %im\n",
+                              R"(@group(2) @binding(1) var x_20 : texture_multisampled_2d<f32>;)",
+                              R"(let x_99 : i32 = textureNumSamples(x_20);)"}  // namespace
 
-        // Multisample 2D array
-        // Not in WebGPU
-    }));
+                             // Multisample 2D array
+                             // Not in WebGPU
+                         }));
 
 INSTANTIATE_TEST_SUITE_P(
     // Translation must inject a type coersion from signed to unsigned.
@@ -3072,36 +2964,34 @@
     }));
 
 struct ImageCoordsCase {
-  // SPIR-V image type, excluding result ID and opcode
-  std::string spirv_image_type_details;
-  std::string spirv_image_access;
-  std::string expected_error;
-  std::vector<std::string> expected_expressions;
+    // SPIR-V image type, excluding result ID and opcode
+    std::string spirv_image_type_details;
+    std::string spirv_image_access;
+    std::string expected_error;
+    std::vector<std::string> expected_expressions;
 };
 
 inline std::ostream& operator<<(std::ostream& out, const ImageCoordsCase& c) {
-  out << "ImageCoordsCase(" << c.spirv_image_type_details << "\n"
-      << c.spirv_image_access << "\n"
-      << "expected_error(" << c.expected_error << ")\n";
+    out << "ImageCoordsCase(" << c.spirv_image_type_details << "\n"
+        << c.spirv_image_access << "\n"
+        << "expected_error(" << c.expected_error << ")\n";
 
-  for (auto e : c.expected_expressions) {
-    out << e << ",";
-  }
-  out << ")" << std::endl;
-  return out;
+    for (auto e : c.expected_expressions) {
+        out << e << ",";
+    }
+    out << ")" << std::endl;
+    return out;
 }
 
 using SpvParserHandleTest_ImageCoordsTest =
     SpvParserTestBase<::testing::TestWithParam<ImageCoordsCase>>;
 
-TEST_P(SpvParserHandleTest_ImageCoordsTest,
-       MakeCoordinateOperandsForImageAccess) {
-  // Only declare the sampled image type, and the associated variable
-  // if the requested image type is a sampled image type and not multisampled.
-  const bool is_sampled_image_type = GetParam().spirv_image_type_details.find(
-                                         "0 1 Unknown") != std::string::npos;
-  const auto assembly =
-      Preamble() + R"(
+TEST_P(SpvParserHandleTest_ImageCoordsTest, MakeCoordinateOperandsForImageAccess) {
+    // Only declare the sampled image type, and the associated variable
+    // if the requested image type is a sampled image type and not multisampled.
+    const bool is_sampled_image_type =
+        GetParam().spirv_image_type_details.find("0 1 Unknown") != std::string::npos;
+    const auto assembly = Preamble() + R"(
      OpEntryPoint Fragment %100 "main"
      OpExecutionMode %100 OriginUpperLeft
      OpName %float_var "float_var"
@@ -3125,14 +3015,14 @@
      OpDecorate %30 DescriptorSet 0
      OpDecorate %30 Binding 1
 )" + CommonBasicTypes() +
-      R"(
+                          R"(
      %sampler = OpTypeSampler
      %ptr_sampler = OpTypePointer UniformConstant %sampler
      %im_ty = OpTypeImage )" +
-      GetParam().spirv_image_type_details + R"(
+                          GetParam().spirv_image_type_details + R"(
      %ptr_im_ty = OpTypePointer UniformConstant %im_ty
 )" + (is_sampled_image_type ? " %si_ty = OpTypeSampledImage %im_ty " : "") +
-      R"(
+                          R"(
 
      %ptr_float = OpTypePointer Function %float
 
@@ -3163,66 +3053,58 @@
      %sam = OpLoad %sampler %10
      %im = OpLoad %im_ty %20
 
-)" +
-      (is_sampled_image_type
-           ? " %sampled_image = OpSampledImage %si_ty %im %sam "
-           : "") +
-      GetParam().spirv_image_access +
-      R"(
+)" + (is_sampled_image_type ? " %sampled_image = OpSampledImage %si_ty %im %sam " : "") +
+                          GetParam().spirv_image_access +
+                          R"(
      ; Use an anchor for the cases when the image access doesn't have a result ID.
      %1000 = OpCopyObject %uint %uint_0
 
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  if (!p->BuildAndParseInternalModule()) {
-    EXPECT_THAT(p->error(), StartsWith(GetParam().expected_error)) << assembly;
-  } else {
-    EXPECT_TRUE(p->error().empty()) << p->error();
-    auto fe = p->function_emitter(100);
-    // We actually have to generate the module to cache expressions for the
-    // result IDs, particularly the OpCopyObject
-    fe.Emit();
-
-    const spvtools::opt::Instruction* anchor = p->GetInstructionForTest(1000);
-    ASSERT_NE(anchor, nullptr);
-    const spvtools::opt::Instruction& image_access = *(anchor->PreviousNode());
-
-    ast::ExpressionList result =
-        fe.MakeCoordinateOperandsForImageAccess(image_access);
-    if (GetParam().expected_error.empty()) {
-      EXPECT_TRUE(fe.success()) << p->error();
-      EXPECT_TRUE(p->error().empty());
-      std::vector<std::string> result_strings;
-      Program program = p->program();
-      for (auto* expr : result) {
-        ASSERT_NE(expr, nullptr);
-        result_strings.push_back(test::ToString(program, expr));
-      }
-      EXPECT_THAT(result_strings,
-                  ::testing::ContainerEq(GetParam().expected_expressions));
+    auto p = parser(test::Assemble(assembly));
+    if (!p->BuildAndParseInternalModule()) {
+        EXPECT_THAT(p->error(), StartsWith(GetParam().expected_error)) << assembly;
     } else {
-      EXPECT_FALSE(fe.success());
-      EXPECT_THAT(p->error(), Eq(GetParam().expected_error)) << assembly;
-      EXPECT_TRUE(result.empty());
-    }
-  }
+        EXPECT_TRUE(p->error().empty()) << p->error();
+        auto fe = p->function_emitter(100);
+        // We actually have to generate the module to cache expressions for the
+        // result IDs, particularly the OpCopyObject
+        fe.Emit();
 
-  const bool is_sample_level =
-      GetParam().spirv_image_access.find("ImageSampleExplicitLod") !=
-      std::string::npos;
-  const bool is_comparison_sample_level =
-      GetParam().spirv_image_access.find("ImageSampleDrefExplicitLod") !=
-      std::string::npos;
-  const bool is_1d =
-      GetParam().spirv_image_type_details.find("1D") != std::string::npos;
-  if (is_sample_level && is_1d) {
-    p->SkipDumpingPending("crbug.com/tint/789");
-  }
-  if (is_comparison_sample_level) {
-    p->SkipDumpingPending("crbug.com/tint/425");
-  }
+        const spvtools::opt::Instruction* anchor = p->GetInstructionForTest(1000);
+        ASSERT_NE(anchor, nullptr);
+        const spvtools::opt::Instruction& image_access = *(anchor->PreviousNode());
+
+        ast::ExpressionList result = fe.MakeCoordinateOperandsForImageAccess(image_access);
+        if (GetParam().expected_error.empty()) {
+            EXPECT_TRUE(fe.success()) << p->error();
+            EXPECT_TRUE(p->error().empty());
+            std::vector<std::string> result_strings;
+            Program program = p->program();
+            for (auto* expr : result) {
+                ASSERT_NE(expr, nullptr);
+                result_strings.push_back(test::ToString(program, expr));
+            }
+            EXPECT_THAT(result_strings, ::testing::ContainerEq(GetParam().expected_expressions));
+        } else {
+            EXPECT_FALSE(fe.success());
+            EXPECT_THAT(p->error(), Eq(GetParam().expected_error)) << assembly;
+            EXPECT_TRUE(result.empty());
+        }
+    }
+
+    const bool is_sample_level =
+        GetParam().spirv_image_access.find("ImageSampleExplicitLod") != std::string::npos;
+    const bool is_comparison_sample_level =
+        GetParam().spirv_image_access.find("ImageSampleDrefExplicitLod") != std::string::npos;
+    const bool is_1d = GetParam().spirv_image_type_details.find("1D") != std::string::npos;
+    if (is_sample_level && is_1d) {
+        p->SkipDumpingPending("crbug.com/tint/789");
+    }
+    if (is_comparison_sample_level) {
+        p->SkipDumpingPending("crbug.com/tint/425");
+    }
 }
 
 INSTANTIATE_TEST_SUITE_P(Good_1D,
@@ -3385,34 +3267,33 @@
          {"vf12"}},
     }));
 
-INSTANTIATE_TEST_SUITE_P(
-    PreserveFloatCoords_Arrayed,
-    // In SPIR-V, sampling and dref sampling operations use floating point
-    // coordinates.  Prove that we preserve floating point-ness of the
-    // coordinate part, but convert the array index to signed integer. Test
-    // across all such instructions.
-    SpvParserHandleTest_ImageCoordsTest,
-    ::testing::ValuesIn(std::vector<ImageCoordsCase>{
-        {"%float 2D 0 1 0 1 Unknown",
-         "%result = OpImageSampleImplicitLod %v4float %sampled_image %vf123",
-         "",
-         {"vf123.xy", "i32(round(vf123.z))"}},
+INSTANTIATE_TEST_SUITE_P(PreserveFloatCoords_Arrayed,
+                         // In SPIR-V, sampling and dref sampling operations use floating point
+                         // coordinates.  Prove that we preserve floating point-ness of the
+                         // coordinate part, but convert the array index to signed integer. Test
+                         // across all such instructions.
+                         SpvParserHandleTest_ImageCoordsTest,
+                         ::testing::ValuesIn(std::vector<ImageCoordsCase>{
+                             {"%float 2D 0 1 0 1 Unknown",
+                              "%result = OpImageSampleImplicitLod %v4float %sampled_image %vf123",
+                              "",
+                              {"vf123.xy", "i32(round(vf123.z))"}},
 
-        {"%float 2D 0 1 0 1 Unknown",
-         "%result = OpImageSampleExplicitLod %v4float %sampled_image %vf123 "
-         "Lod %f1",
-         "",
-         {"vf123.xy", "i32(round(vf123.z))"}},
-        {"%float 2D 1 1 0 1 Unknown",
-         "%result = OpImageSampleDrefImplicitLod %float %sampled_image "
-         "%vf123 %depth",
-         "",
-         {"vf123.xy", "i32(round(vf123.z))"}},
-        {"%float 2D 1 1 0 1 Unknown",
-         "%result = OpImageSampleDrefExplicitLod %float %sampled_image "
-         "%vf123 %depth Lod %float_0",
-         "",
-         {"vf123.xy", "i32(round(vf123.z))"}}}));
+                             {"%float 2D 0 1 0 1 Unknown",
+                              "%result = OpImageSampleExplicitLod %v4float %sampled_image %vf123 "
+                              "Lod %f1",
+                              "",
+                              {"vf123.xy", "i32(round(vf123.z))"}},
+                             {"%float 2D 1 1 0 1 Unknown",
+                              "%result = OpImageSampleDrefImplicitLod %float %sampled_image "
+                              "%vf123 %depth",
+                              "",
+                              {"vf123.xy", "i32(round(vf123.z))"}},
+                             {"%float 2D 1 1 0 1 Unknown",
+                              "%result = OpImageSampleDrefExplicitLod %float %sampled_image "
+                              "%vf123 %depth Lod %float_0",
+                              "",
+                              {"vf123.xy", "i32(round(vf123.z))"}}}));
 
 INSTANTIATE_TEST_SUITE_P(
     PreserveIntCoords_NonArrayed,
@@ -3421,47 +3302,31 @@
     SpvParserHandleTest_ImageCoordsTest,
     ::testing::ValuesIn(std::vector<ImageCoordsCase>{
         // Scalar cases
-        {"%float 1D 0 0 0 1 Unknown",
-         "%result = OpImageFetch %v4float %im %i1",
-         "",
-         {"i1"}},
-        {"%float 1D 0 0 0 2 R32f",
-         "%result = OpImageRead %v4float %im %i1",
-         "",
-         {"i1"}},
+        {"%float 1D 0 0 0 1 Unknown", "%result = OpImageFetch %v4float %im %i1", "", {"i1"}},
+        {"%float 1D 0 0 0 2 R32f", "%result = OpImageRead %v4float %im %i1", "", {"i1"}},
         {"%float 1D 0 0 0 2 R32f", "OpImageWrite %im %i1 %vf1234", "", {"i1"}},
         // Vector cases
-        {"%float 2D 0 0 0 1 Unknown",
-         "%result = OpImageFetch %v4float %im %vi12",
-         "",
-         {"vi12"}},
-        {"%float 2D 0 0 0 2 R32f",
-         "%result = OpImageRead %v4float %im %vi12",
-         "",
-         {"vi12"}},
-        {"%float 2D 0 0 0 2 R32f",
-         "OpImageWrite %im %vi12 %vf1234",
-         "",
-         {"vi12"}}}));
+        {"%float 2D 0 0 0 1 Unknown", "%result = OpImageFetch %v4float %im %vi12", "", {"vi12"}},
+        {"%float 2D 0 0 0 2 R32f", "%result = OpImageRead %v4float %im %vi12", "", {"vi12"}},
+        {"%float 2D 0 0 0 2 R32f", "OpImageWrite %im %vi12 %vf1234", "", {"vi12"}}}));
 
-INSTANTIATE_TEST_SUITE_P(
-    PreserveIntCoords_Arrayed,
-    // In SPIR-V, image read, fetch, and write use integer coordinates.
-    // Prove that we preserve signed integer coordinates.
-    SpvParserHandleTest_ImageCoordsTest,
-    ::testing::ValuesIn(std::vector<ImageCoordsCase>{
-        {"%float 2D 0 1 0 1 Unknown",
-         "%result = OpImageFetch %v4float %im %vi123",
-         "",
-         {"vi123.xy", "vi123.z"}},
-        {"%float 2D 0 1 0 2 R32f",
-         "%result = OpImageRead %v4float %im %vi123",
-         "",
-         {"vi123.xy", "vi123.z"}},
-        {"%float 2D 0 1 0 2 R32f",
-         "OpImageWrite %im %vi123 %vf1234",
-         "",
-         {"vi123.xy", "vi123.z"}}}));
+INSTANTIATE_TEST_SUITE_P(PreserveIntCoords_Arrayed,
+                         // In SPIR-V, image read, fetch, and write use integer coordinates.
+                         // Prove that we preserve signed integer coordinates.
+                         SpvParserHandleTest_ImageCoordsTest,
+                         ::testing::ValuesIn(std::vector<ImageCoordsCase>{
+                             {"%float 2D 0 1 0 1 Unknown",
+                              "%result = OpImageFetch %v4float %im %vi123",
+                              "",
+                              {"vi123.xy", "vi123.z"}},
+                             {"%float 2D 0 1 0 2 R32f",
+                              "%result = OpImageRead %v4float %im %vi123",
+                              "",
+                              {"vi123.xy", "vi123.z"}},
+                             {"%float 2D 0 1 0 2 R32f",
+                              "OpImageWrite %im %vi123 %vf1234",
+                              "",
+                              {"vi123.xy", "vi123.z"}}}));
 
 INSTANTIATE_TEST_SUITE_P(
     ConvertUintCoords_NonArrayed,
@@ -3470,18 +3335,9 @@
     SpvParserHandleTest_ImageCoordsTest,
     ::testing::ValuesIn(std::vector<ImageCoordsCase>{
         // Scalar cases
-        {"%float 1D 0 0 0 1 Unknown",
-         "%result = OpImageFetch %v4float %im %u1",
-         "",
-         {"i32(u1)"}},
-        {"%float 1D 0 0 0 2 R32f",
-         "%result = OpImageRead %v4float %im %u1",
-         "",
-         {"i32(u1)"}},
-        {"%float 1D 0 0 0 2 R32f",
-         "OpImageWrite %im %u1 %vf1234",
-         "",
-         {"i32(u1)"}},
+        {"%float 1D 0 0 0 1 Unknown", "%result = OpImageFetch %v4float %im %u1", "", {"i32(u1)"}},
+        {"%float 1D 0 0 0 2 R32f", "%result = OpImageRead %v4float %im %u1", "", {"i32(u1)"}},
+        {"%float 1D 0 0 0 2 R32f", "OpImageWrite %im %u1 %vf1234", "", {"i32(u1)"}},
         // Vector cases
         {"%float 2D 0 0 0 1 Unknown",
          "%result = OpImageFetch %v4float %im %vu12",
@@ -3491,38 +3347,31 @@
          "%result = OpImageRead %v4float %im %vu12",
          "",
          {"vec2<i32>(vu12)"}},
-        {"%float 2D 0 0 0 2 R32f",
-         "OpImageWrite %im %vu12 %vf1234",
-         "",
-         {"vec2<i32>(vu12)"}}}));
+        {"%float 2D 0 0 0 2 R32f", "OpImageWrite %im %vu12 %vf1234", "", {"vec2<i32>(vu12)"}}}));
 
-INSTANTIATE_TEST_SUITE_P(
-    ConvertUintCoords_Arrayed,
-    // In SPIR-V, image read, fetch, and write use integer coordinates.
-    // Prove that we convert unsigned integer coordinates to signed.
-    SpvParserHandleTest_ImageCoordsTest,
-    ::testing::ValuesIn(std::vector<ImageCoordsCase>{
-        {"%float 2D 0 1 0 1 Unknown",
-         "%result = OpImageFetch %v4float %im %vu123",
-         "",
-         {"vec2<i32>(vu123.xy)", "i32(vu123.z)"}},
-        {"%float 2D 0 1 0 2 R32f",
-         "%result = OpImageRead %v4float %im %vu123",
-         "",
-         {"vec2<i32>(vu123.xy)", "i32(vu123.z)"}},
-        {"%float 2D 0 1 0 2 R32f",
-         "OpImageWrite %im %vu123 %vf1234",
-         "",
-         {"vec2<i32>(vu123.xy)", "i32(vu123.z)"}}}));
+INSTANTIATE_TEST_SUITE_P(ConvertUintCoords_Arrayed,
+                         // In SPIR-V, image read, fetch, and write use integer coordinates.
+                         // Prove that we convert unsigned integer coordinates to signed.
+                         SpvParserHandleTest_ImageCoordsTest,
+                         ::testing::ValuesIn(std::vector<ImageCoordsCase>{
+                             {"%float 2D 0 1 0 1 Unknown",
+                              "%result = OpImageFetch %v4float %im %vu123",
+                              "",
+                              {"vec2<i32>(vu123.xy)", "i32(vu123.z)"}},
+                             {"%float 2D 0 1 0 2 R32f",
+                              "%result = OpImageRead %v4float %im %vu123",
+                              "",
+                              {"vec2<i32>(vu123.xy)", "i32(vu123.z)"}},
+                             {"%float 2D 0 1 0 2 R32f",
+                              "OpImageWrite %im %vu123 %vf1234",
+                              "",
+                              {"vec2<i32>(vu123.xy)", "i32(vu123.z)"}}}));
 
 INSTANTIATE_TEST_SUITE_P(
     BadInstructions,
     SpvParserHandleTest_ImageCoordsTest,
     ::testing::ValuesIn(std::vector<ImageCoordsCase>{
-        {"%float 1D 0 0 0 1 Unknown",
-         "OpNop",
-         "not an image access instruction: OpNop",
-         {}},
+        {"%float 1D 0 0 0 1 Unknown", "OpNop", "not an image access instruction: OpNop", {}},
         {"%float 1D 0 0 0 1 Unknown",
          "%50 = OpCopyObject %float %float_1",
          "internal error: couldn't find image for "
@@ -3537,133 +3386,129 @@
         // won't assemble, so we skip it.
     }));
 
-INSTANTIATE_TEST_SUITE_P(
-    Bad_Coordinate,
-    SpvParserHandleTest_ImageCoordsTest,
-    ::testing::ValuesIn(std::vector<ImageCoordsCase>{
-        {"%float 1D 0 0 0 1 Unknown",
-         "%result = OpImageSampleImplicitLod "
-         // bad type for coordinate: not a number
-         "%v4float %sampled_image %float_var",
-         "bad or unsupported coordinate type for image access: %73 = "
-         "OpImageSampleImplicitLod %42 %72 %1",
-         {}},
-        {"%float 2D 0 0 0 1 Unknown",  // 2D
-         "%result = OpImageSampleImplicitLod "
-         // 1 component, but need 2
-         "%v4float %sampled_image %f1",
-         "image access required 2 coordinate components, but only 1 provided, "
-         "in: %73 = OpImageSampleImplicitLod %42 %72 %12",
-         {}},
-        {"%float 2D 0 1 0 1 Unknown",  // 2DArray
-         "%result = OpImageSampleImplicitLod "
-         // 2 component, but need 3
-         "%v4float %sampled_image %vf12",
-         "image access required 3 coordinate components, but only 2 provided, "
-         "in: %73 = OpImageSampleImplicitLod %42 %72 %13",
-         {}},
-        {"%float 3D 0 0 0 1 Unknown",  // 3D
-         "%result = OpImageSampleImplicitLod "
-         // 2 components, but need 3
-         "%v4float %sampled_image %vf12",
-         "image access required 3 coordinate components, but only 2 provided, "
-         "in: %73 = OpImageSampleImplicitLod %42 %72 %13",
-         {}},
-    }));
+INSTANTIATE_TEST_SUITE_P(Bad_Coordinate,
+                         SpvParserHandleTest_ImageCoordsTest,
+                         ::testing::ValuesIn(std::vector<ImageCoordsCase>{
+                             {"%float 1D 0 0 0 1 Unknown",
+                              "%result = OpImageSampleImplicitLod "
+                              // bad type for coordinate: not a number
+                              "%v4float %sampled_image %float_var",
+                              "bad or unsupported coordinate type for image access: %73 = "
+                              "OpImageSampleImplicitLod %42 %72 %1",
+                              {}},
+                             {"%float 2D 0 0 0 1 Unknown",  // 2D
+                              "%result = OpImageSampleImplicitLod "
+                              // 1 component, but need 2
+                              "%v4float %sampled_image %f1",
+                              "image access required 2 coordinate components, but only 1 provided, "
+                              "in: %73 = OpImageSampleImplicitLod %42 %72 %12",
+                              {}},
+                             {"%float 2D 0 1 0 1 Unknown",  // 2DArray
+                              "%result = OpImageSampleImplicitLod "
+                              // 2 component, but need 3
+                              "%v4float %sampled_image %vf12",
+                              "image access required 3 coordinate components, but only 2 provided, "
+                              "in: %73 = OpImageSampleImplicitLod %42 %72 %13",
+                              {}},
+                             {"%float 3D 0 0 0 1 Unknown",  // 3D
+                              "%result = OpImageSampleImplicitLod "
+                              // 2 components, but need 3
+                              "%v4float %sampled_image %vf12",
+                              "image access required 3 coordinate components, but only 2 provided, "
+                              "in: %73 = OpImageSampleImplicitLod %42 %72 %13",
+                              {}},
+                         }));
 
-INSTANTIATE_TEST_SUITE_P(
-    SampleNonFloatTexture_IsError,
-    SpvParserHandleTest_ImageCoordsTest,
-    ::testing::ValuesIn(std::vector<ImageCoordsCase>{
-        // ImageSampleImplicitLod
-        {"%uint 2D 0 0 0 1 Unknown",
-         "%result = OpImageSampleImplicitLod %v4uint %sampled_image %vf12",
-         "sampled image must have float component type",
-         {}},
-        {"%int 2D 0 0 0 1 Unknown",
-         "%result = OpImageSampleImplicitLod %v4int %sampled_image %vf12",
-         "sampled image must have float component type",
-         {}},
-        // ImageSampleExplicitLod
-        {"%uint 2D 0 0 0 1 Unknown",
-         "%result = OpImageSampleExplicitLod %v4uint %sampled_image %vf12 "
-         "Lod %f1",
-         "sampled image must have float component type",
-         {}},
-        {"%int 2D 0 0 0 1 Unknown",
-         "%result = OpImageSampleExplicitLod %v4int %sampled_image %vf12 "
-         "Lod %f1",
-         "sampled image must have float component type",
-         {}},
-        // ImageSampleDrefImplicitLod
-        {"%uint 2D 0 0 0 1 Unknown",
-         "%result = OpImageSampleDrefImplicitLod %uint %sampled_image %vf12 "
-         "%f1",
-         "sampled image must have float component type",
-         {}},
-        {"%int 2D 0 0 0 1 Unknown",
-         "%result = OpImageSampleDrefImplicitLod %int %sampled_image %vf12 "
-         "%f1",
-         "sampled image must have float component type",
-         {}},
-        // ImageSampleDrefExplicitLod
-        {"%uint 2D 0 0 0 1 Unknown",
-         "%result = OpImageSampleDrefExplicitLod %uint %sampled_image %vf12 "
-         "%f1 Lod %float_0",
-         "sampled image must have float component type",
-         {}},
-        {"%int 2D 0 0 0 1 Unknown",
-         "%result = OpImageSampleDrefExplicitLod %int %sampled_image %vf12 "
-         "%f1 Lod %float_0",
-         "sampled image must have float component type",
-         {}}}));
+INSTANTIATE_TEST_SUITE_P(SampleNonFloatTexture_IsError,
+                         SpvParserHandleTest_ImageCoordsTest,
+                         ::testing::ValuesIn(std::vector<ImageCoordsCase>{
+                             // ImageSampleImplicitLod
+                             {"%uint 2D 0 0 0 1 Unknown",
+                              "%result = OpImageSampleImplicitLod %v4uint %sampled_image %vf12",
+                              "sampled image must have float component type",
+                              {}},
+                             {"%int 2D 0 0 0 1 Unknown",
+                              "%result = OpImageSampleImplicitLod %v4int %sampled_image %vf12",
+                              "sampled image must have float component type",
+                              {}},
+                             // ImageSampleExplicitLod
+                             {"%uint 2D 0 0 0 1 Unknown",
+                              "%result = OpImageSampleExplicitLod %v4uint %sampled_image %vf12 "
+                              "Lod %f1",
+                              "sampled image must have float component type",
+                              {}},
+                             {"%int 2D 0 0 0 1 Unknown",
+                              "%result = OpImageSampleExplicitLod %v4int %sampled_image %vf12 "
+                              "Lod %f1",
+                              "sampled image must have float component type",
+                              {}},
+                             // ImageSampleDrefImplicitLod
+                             {"%uint 2D 0 0 0 1 Unknown",
+                              "%result = OpImageSampleDrefImplicitLod %uint %sampled_image %vf12 "
+                              "%f1",
+                              "sampled image must have float component type",
+                              {}},
+                             {"%int 2D 0 0 0 1 Unknown",
+                              "%result = OpImageSampleDrefImplicitLod %int %sampled_image %vf12 "
+                              "%f1",
+                              "sampled image must have float component type",
+                              {}},
+                             // ImageSampleDrefExplicitLod
+                             {"%uint 2D 0 0 0 1 Unknown",
+                              "%result = OpImageSampleDrefExplicitLod %uint %sampled_image %vf12 "
+                              "%f1 Lod %float_0",
+                              "sampled image must have float component type",
+                              {}},
+                             {"%int 2D 0 0 0 1 Unknown",
+                              "%result = OpImageSampleDrefExplicitLod %int %sampled_image %vf12 "
+                              "%f1 Lod %float_0",
+                              "sampled image must have float component type",
+                              {}}}));
 
-INSTANTIATE_TEST_SUITE_P(
-    ConstOffset_BadInstruction_Errors,
-    SpvParserHandleTest_ImageCoordsTest,
-    ::testing::ValuesIn(std::vector<ImageCoordsCase>{
-        // ImageFetch
-        {"%uint 2D 0 0 0 1 Unknown",
-         "%result = OpImageFetch %v4uint %sampled_image %vf12 ConstOffset "
-         "%the_vu12",
-         "ConstOffset is only permitted for sampling, gather, or "
-         "depth-reference gather operations: ",
-         {}},
-        // ImageRead
-        {"%uint 2D 0 0 0 2 Rgba32ui",
-         "%result = OpImageRead %v4uint %im %vu12 ConstOffset %the_vu12",
-         "ConstOffset is only permitted for sampling, gather, or "
-         "depth-reference gather operations: ",
-         {}},
-        // ImageWrite
-        {"%uint 2D 0 0 0 2 Rgba32ui",
-         "OpImageWrite %im %vu12 %vu1234 ConstOffset %the_vu12",
-         "ConstOffset is only permitted for sampling, gather, or "
-         "depth-reference gather operations: ",
-         {}}}));
+INSTANTIATE_TEST_SUITE_P(ConstOffset_BadInstruction_Errors,
+                         SpvParserHandleTest_ImageCoordsTest,
+                         ::testing::ValuesIn(std::vector<ImageCoordsCase>{
+                             // ImageFetch
+                             {"%uint 2D 0 0 0 1 Unknown",
+                              "%result = OpImageFetch %v4uint %sampled_image %vf12 ConstOffset "
+                              "%the_vu12",
+                              "ConstOffset is only permitted for sampling, gather, or "
+                              "depth-reference gather operations: ",
+                              {}},
+                             // ImageRead
+                             {"%uint 2D 0 0 0 2 Rgba32ui",
+                              "%result = OpImageRead %v4uint %im %vu12 ConstOffset %the_vu12",
+                              "ConstOffset is only permitted for sampling, gather, or "
+                              "depth-reference gather operations: ",
+                              {}},
+                             // ImageWrite
+                             {"%uint 2D 0 0 0 2 Rgba32ui",
+                              "OpImageWrite %im %vu12 %vu1234 ConstOffset %the_vu12",
+                              "ConstOffset is only permitted for sampling, gather, or "
+                              "depth-reference gather operations: ",
+                              {}}}));
 
-INSTANTIATE_TEST_SUITE_P(
-    ConstOffset_BadDim_Errors,
-    SpvParserHandleTest_ImageCoordsTest,
-    ::testing::ValuesIn(std::vector<ImageCoordsCase>{
-        // 1D
-        {"%uint 1D 0 0 0 1 Unknown",
-         "%result = OpImageSampleImplicitLod %v4float %sampled_image %vf1234 "
-         "ConstOffset %the_vu12",
-         "ConstOffset is only permitted for 2D, 2D Arrayed, and 3D textures: ",
-         {}},
-        // Cube
-        {"%uint Cube 0 0 0 1 Unknown",
-         "%result = OpImageSampleImplicitLod %v4float %sampled_image %vf1234 "
-         "ConstOffset %the_vu12",
-         "ConstOffset is only permitted for 2D, 2D Arrayed, and 3D textures: ",
-         {}},
-        // Cube Array
-        {"%uint Cube 0 1 0 1 Unknown",
-         "%result = OpImageSampleImplicitLod %v4float %sampled_image %vf1234 "
-         "ConstOffset %the_vu12",
-         "ConstOffset is only permitted for 2D, 2D Arrayed, and 3D textures: ",
-         {}}}));
+INSTANTIATE_TEST_SUITE_P(ConstOffset_BadDim_Errors,
+                         SpvParserHandleTest_ImageCoordsTest,
+                         ::testing::ValuesIn(std::vector<ImageCoordsCase>{
+                             // 1D
+                             {"%uint 1D 0 0 0 1 Unknown",
+                              "%result = OpImageSampleImplicitLod %v4float %sampled_image %vf1234 "
+                              "ConstOffset %the_vu12",
+                              "ConstOffset is only permitted for 2D, 2D Arrayed, and 3D textures: ",
+                              {}},
+                             // Cube
+                             {"%uint Cube 0 0 0 1 Unknown",
+                              "%result = OpImageSampleImplicitLod %v4float %sampled_image %vf1234 "
+                              "ConstOffset %the_vu12",
+                              "ConstOffset is only permitted for 2D, 2D Arrayed, and 3D textures: ",
+                              {}},
+                             // Cube Array
+                             {"%uint Cube 0 1 0 1 Unknown",
+                              "%result = OpImageSampleImplicitLod %v4float %sampled_image %vf1234 "
+                              "ConstOffset %the_vu12",
+                              "ConstOffset is only permitted for 2D, 2D Arrayed, and 3D textures: ",
+                              {}}}));
 
 INSTANTIATE_TEST_SUITE_P(
     ImageSampleDref_Bias_IsError,
@@ -3764,7 +3609,7 @@
          {}}}));
 
 TEST_F(SpvParserHandleTest, CombinedImageSampler_IsError) {
-  const auto assembly = Preamble() + R"(
+    const auto assembly = Preamble() + R"(
      OpEntryPoint Fragment %100 "main"
      OpExecutionMode %100 OriginUpperLeft
 
@@ -3783,72 +3628,65 @@
            OpReturn
            OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_FALSE(p->BuildAndParseInternalModule()) << assembly;
-  EXPECT_THAT(p->error(),
-              HasSubstr("WGSL does not support combined image-samplers: "));
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_FALSE(p->BuildAndParseInternalModule()) << assembly;
+    EXPECT_THAT(p->error(), HasSubstr("WGSL does not support combined image-samplers: "));
 }
 
-INSTANTIATE_TEST_SUITE_P(
-    ImageQueryLod_IsError,
-    SpvParserHandleTest_ImageCoordsTest,
-    ::testing::ValuesIn(std::vector<ImageCoordsCase>{
-        {"%float 2D 0 0 0 1 Unknown",
-         "%result = OpImageQueryLod %v2int %sampled_image %vf12",
-         "WGSL does not support querying the level of detail of an image: ",
-         {}}}));
+INSTANTIATE_TEST_SUITE_P(ImageQueryLod_IsError,
+                         SpvParserHandleTest_ImageCoordsTest,
+                         ::testing::ValuesIn(std::vector<ImageCoordsCase>{
+                             {"%float 2D 0 0 0 1 Unknown",
+                              "%result = OpImageQueryLod %v2int %sampled_image %vf12",
+                              "WGSL does not support querying the level of detail of an image: ",
+                              {}}}));
 
-INSTANTIATE_TEST_SUITE_P(
-    ImageGather_Bias_IsError,
-    SpvParserHandleTest_ImageCoordsTest,
-    ::testing::ValuesIn(std::vector<ImageCoordsCase>{
-        {"%float 2D 0 0 0 1 Unknown",
-         "%result = OpImageGather %v4float %sampled_image %vf12 %int_1 "
-         "Bias %float_null",
-         "WGSL does not support image gather with level-of-detail bias: ",
-         {}}}));
+INSTANTIATE_TEST_SUITE_P(ImageGather_Bias_IsError,
+                         SpvParserHandleTest_ImageCoordsTest,
+                         ::testing::ValuesIn(std::vector<ImageCoordsCase>{
+                             {"%float 2D 0 0 0 1 Unknown",
+                              "%result = OpImageGather %v4float %sampled_image %vf12 %int_1 "
+                              "Bias %float_null",
+                              "WGSL does not support image gather with level-of-detail bias: ",
+                              {}}}));
 
-INSTANTIATE_TEST_SUITE_P(
-    ImageDrefGather_Bias_IsError,
-    SpvParserHandleTest_ImageCoordsTest,
-    ::testing::ValuesIn(std::vector<ImageCoordsCase>{
-        {"%float 2D 1 0 0 1 Unknown",
-         "%result = OpImageDrefGather %v4float %sampled_image %vf12 %depth "
-         "Bias %float_null",
-         "WGSL does not support image gather with level-of-detail bias: ",
-         {}}}));
+INSTANTIATE_TEST_SUITE_P(ImageDrefGather_Bias_IsError,
+                         SpvParserHandleTest_ImageCoordsTest,
+                         ::testing::ValuesIn(std::vector<ImageCoordsCase>{
+                             {"%float 2D 1 0 0 1 Unknown",
+                              "%result = OpImageDrefGather %v4float %sampled_image %vf12 %depth "
+                              "Bias %float_null",
+                              "WGSL does not support image gather with level-of-detail bias: ",
+                              {}}}));
 
 // Note: Vulkan SPIR-V ImageGather and ImageDrefGather do not allow explicit
 // Lod. The SPIR-V validator should reject those cases already.
 
-INSTANTIATE_TEST_SUITE_P(
-    ImageGather_Grad_IsError,
-    SpvParserHandleTest_ImageCoordsTest,
-    ::testing::ValuesIn(std::vector<ImageCoordsCase>{
-        {"%float 2D 0 0 0 1 Unknown",
-         "%result = OpImageGather %v4float %sampled_image %vf12 %int_1 "
-         "Grad %vf12 %vf12",
-         "WGSL does not support image gather with explicit gradient: ",
-         {}}}));
+INSTANTIATE_TEST_SUITE_P(ImageGather_Grad_IsError,
+                         SpvParserHandleTest_ImageCoordsTest,
+                         ::testing::ValuesIn(std::vector<ImageCoordsCase>{
+                             {"%float 2D 0 0 0 1 Unknown",
+                              "%result = OpImageGather %v4float %sampled_image %vf12 %int_1 "
+                              "Grad %vf12 %vf12",
+                              "WGSL does not support image gather with explicit gradient: ",
+                              {}}}));
 
-INSTANTIATE_TEST_SUITE_P(
-    ImageDrefGather_Grad_IsError,
-    SpvParserHandleTest_ImageCoordsTest,
-    ::testing::ValuesIn(std::vector<ImageCoordsCase>{
-        {"%float 2D 1 0 0 1 Unknown",
-         "%result = OpImageDrefGather %v4float %sampled_image %vf12 %depth "
-         "Grad %vf12 %vf12",
-         "WGSL does not support image gather with explicit gradient: ",
-         {}}}));
+INSTANTIATE_TEST_SUITE_P(ImageDrefGather_Grad_IsError,
+                         SpvParserHandleTest_ImageCoordsTest,
+                         ::testing::ValuesIn(std::vector<ImageCoordsCase>{
+                             {"%float 2D 1 0 0 1 Unknown",
+                              "%result = OpImageDrefGather %v4float %sampled_image %vf12 %depth "
+                              "Grad %vf12 %vf12",
+                              "WGSL does not support image gather with explicit gradient: ",
+                              {}}}));
 
-TEST_F(SpvParserHandleTest,
-       NeverGenerateConstDeclForHandle_UseVariableDirectly) {
-  // An ad-hoc test to prove we never had the issue
-  // feared in crbug.com/tint/265.
-  // Never create a const-declaration for a pointer to
-  // a texture or sampler. Code generation always
-  // traces back to the memory object declaration.
-  const auto assembly = Preamble() + R"(
+TEST_F(SpvParserHandleTest, NeverGenerateConstDeclForHandle_UseVariableDirectly) {
+    // An ad-hoc test to prove we never had the issue
+    // feared in crbug.com/tint/265.
+    // Never create a const-declaration for a pointer to
+    // a texture or sampler. Code generation always
+    // traces back to the memory object declaration.
+    const auto assembly = Preamble() + R"(
      OpEntryPoint Fragment %100 "main"
      OpExecutionMode %100 OriginUpperLeft
 
@@ -3899,20 +3737,20 @@
            OpReturn
            OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_TRUE(p->BuildAndParseInternalModule()) << assembly;
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  EXPECT_TRUE(p->error().empty()) << p->error();
-  auto ast_body = fe.ast_body();
-  const auto got = test::ToString(p->program(), ast_body);
-  auto* expect = R"(var var_1 : vec4<f32>;
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_TRUE(p->BuildAndParseInternalModule()) << assembly;
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    EXPECT_TRUE(p->error().empty()) << p->error();
+    auto ast_body = fe.ast_body();
+    const auto got = test::ToString(p->program(), ast_body);
+    auto* expect = R"(var var_1 : vec4<f32>;
 let x_22 : vec4<f32> = textureSample(x_2, x_3, vec2<f32>());
 let x_26 : vec4<f32> = textureSample(x_2, x_3, vec2<f32>());
 var_1 = (x_22 + x_26);
 return;
 )";
-  ASSERT_EQ(expect, got);
+    ASSERT_EQ(expect, got);
 }
 
 }  // namespace
diff --git a/src/tint/reader/spirv/parser_impl_import_test.cc b/src/tint/reader/spirv/parser_impl_import_test.cc
index 852c08a..b25db07 100644
--- a/src/tint/reader/spirv/parser_impl_import_test.cc
+++ b/src/tint/reader/spirv/parser_impl_import_test.cc
@@ -28,44 +28,43 @@
 using SpvParserImportTest = SpvParserTest;
 
 TEST_F(SpvParserImportTest, Import_NoImport) {
-  auto p = parser(test::Assemble("%1 = OpTypeVoid"));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  const auto program_ast = test::ToString(p->program());
-  EXPECT_THAT(program_ast, Not(HasSubstr("Import")));
+    auto p = parser(test::Assemble("%1 = OpTypeVoid"));
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    const auto program_ast = test::ToString(p->program());
+    EXPECT_THAT(program_ast, Not(HasSubstr("Import")));
 
-  p->DeliberatelyInvalidSpirv();
+    p->DeliberatelyInvalidSpirv();
 }
 
 TEST_F(SpvParserImportTest, Import_ImportGlslStd450) {
-  auto p = parser(test::Assemble(R"(%1 = OpExtInstImport "GLSL.std.450")"));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  EXPECT_THAT(p->glsl_std_450_imports(), ElementsAre(1));
+    auto p = parser(test::Assemble(R"(%1 = OpExtInstImport "GLSL.std.450")"));
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    EXPECT_THAT(p->glsl_std_450_imports(), ElementsAre(1));
 
-  p->DeliberatelyInvalidSpirv();
+    p->DeliberatelyInvalidSpirv();
 }
 
 TEST_F(SpvParserImportTest, Import_NonSemantic_IgnoredImport) {
-  auto p = parser(test::Assemble(
-      R"(%40 = OpExtInstImport "NonSemantic.ClspvReflection.1")"));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_TRUE(p->error().empty());
+    auto p = parser(test::Assemble(R"(%40 = OpExtInstImport "NonSemantic.ClspvReflection.1")"));
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_TRUE(p->error().empty());
 
-  p->DeliberatelyInvalidSpirv();
+    p->DeliberatelyInvalidSpirv();
 }
 
 TEST_F(SpvParserImportTest, Import_NonSemantic_IgnoredExtInsts) {
-  // This is the clspv-compiled output of this OpenCL C:
-  //    kernel void foo(global int*A) { A=A; }
-  // It emits NonSemantic.ClspvReflection.1 extended instructions.
-  // But *tweaked*:
-  //    - to remove gl_WorkgroupSize
-  //    - to add LocalSize execution mode
-  //    - to move one of the ExtInsts into the globals-and-constants
-  //      section
-  //    - to move one of the ExtInsts into the function body.
-  auto p = parser(test::Assemble(R"(
+    // This is the clspv-compiled output of this OpenCL C:
+    //    kernel void foo(global int*A) { A=A; }
+    // It emits NonSemantic.ClspvReflection.1 extended instructions.
+    // But *tweaked*:
+    //    - to remove gl_WorkgroupSize
+    //    - to add LocalSize execution mode
+    //    - to move one of the ExtInsts into the globals-and-constants
+    //      section
+    //    - to move one of the ExtInsts into the function body.
+    auto p = parser(test::Assemble(R"(
                OpCapability Shader
                OpExtension "SPV_KHR_storage_buffer_storage_class"
                OpExtension "SPV_KHR_non_semantic_info"
@@ -110,11 +109,10 @@
          %25 = OpExtInst %void %20 ArgumentStorageBuffer %22 %uint_0 %uint_0 %uint_0 %24
          %28 = OpExtInst %void %20 SpecConstantWorkgroupSize %uint_0 %uint_1 %uint_2
 )"));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_TRUE(p->error().empty());
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_TRUE(p->error().empty());
 
-  p->SkipDumpingPending(
-      "crbug.com/tint/1041 track access mode in spirv-reader parser type");
+    p->SkipDumpingPending("crbug.com/tint/1041 track access mode in spirv-reader parser type");
 }
 
 // TODO(dneto): We don't currently support other kinds of extended instruction
diff --git a/src/tint/reader/spirv/parser_impl_module_var_test.cc b/src/tint/reader/spirv/parser_impl_module_var_test.cc
index 443e836..8ef704e 100644
--- a/src/tint/reader/spirv/parser_impl_module_var_test.cc
+++ b/src/tint/reader/spirv/parser_impl_module_var_test.cc
@@ -29,21 +29,21 @@
 using ::testing::Not;
 
 std::string Preamble() {
-  return R"(
+    return R"(
    OpCapability Shader
    OpMemoryModel Logical Simple
 )";
 }
 
 std::string FragMain() {
-  return R"(
+    return R"(
    OpEntryPoint Fragment %main "main"
    OpExecutionMode %main OriginUpperLeft
 )";
 }
 
 std::string MainBody() {
-  return R"(
+    return R"(
    %main = OpFunction %void None %voidfn
    %main_entry = OpLabel
    OpReturn
@@ -52,7 +52,7 @@
 }
 
 std::string CommonCapabilities() {
-  return R"(
+    return R"(
     OpCapability Shader
     OpCapability SampleRateShading
     OpMemoryModel Logical Simple
@@ -60,7 +60,7 @@
 }
 
 std::string CommonTypes() {
-  return R"(
+    return R"(
     %void = OpTypeVoid
     %voidfn = OpTypeFunction %void
 
@@ -95,14 +95,14 @@
 }
 
 std::string StructTypes() {
-  return R"(
+    return R"(
     %strct = OpTypeStruct %uint %float %arr2uint
 )";
 }
 
 // Returns layout annotations for types in StructTypes()
 std::string CommonLayout() {
-  return R"(
+    return R"(
     OpMemberDecorate %strct 0 Offset 0
     OpMemberDecorate %strct 1 Offset 4
     OpMemberDecorate %strct 2 Offset 8
@@ -111,50 +111,49 @@
 }
 
 TEST_F(SpvModuleScopeVarParserTest, NoVar) {
-  auto assembly = Preamble() + FragMain() + CommonTypes() + MainBody();
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_TRUE(p->BuildAndParseInternalModule()) << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto module_ast = test::ToString(p->program());
-  EXPECT_THAT(module_ast, Not(HasSubstr("Variable"))) << module_ast;
+    auto assembly = Preamble() + FragMain() + CommonTypes() + MainBody();
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_TRUE(p->BuildAndParseInternalModule()) << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto module_ast = test::ToString(p->program());
+    EXPECT_THAT(module_ast, Not(HasSubstr("Variable"))) << module_ast;
 }
 
 TEST_F(SpvModuleScopeVarParserTest, BadStorageClass_NotAWebGPUStorageClass) {
-  auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
+    auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
     %float = OpTypeFloat 32
     %ptr = OpTypePointer CrossWorkgroup %float
     %52 = OpVariable %ptr CrossWorkgroup
     %void = OpTypeVoid
     %voidfn = OpTypeFunction %void
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
-  // Normally we should run ParserImpl::RegisterTypes before emitting
-  // variables. But defensive coding in EmitModuleScopeVariables lets
-  // us catch this error.
-  EXPECT_FALSE(p->EmitModuleScopeVariables()) << p->error();
-  EXPECT_THAT(p->error(), HasSubstr("unknown SPIR-V storage class: 5"));
+    EXPECT_TRUE(p->BuildInternalModule());
+    // Normally we should run ParserImpl::RegisterTypes before emitting
+    // variables. But defensive coding in EmitModuleScopeVariables lets
+    // us catch this error.
+    EXPECT_FALSE(p->EmitModuleScopeVariables()) << p->error();
+    EXPECT_THAT(p->error(), HasSubstr("unknown SPIR-V storage class: 5"));
 }
 
 TEST_F(SpvModuleScopeVarParserTest, BadStorageClass_Function) {
-  auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
+    auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
     %float = OpTypeFloat 32
     %ptr = OpTypePointer Function %float
     %52 = OpVariable %ptr Function
     %void = OpTypeVoid
     %voidfn = OpTypeFunction %void
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
-  // Normally we should run ParserImpl::RegisterTypes before emitting
-  // variables. But defensive coding in EmitModuleScopeVariables lets
-  // us catch this error.
-  EXPECT_FALSE(p->EmitModuleScopeVariables()) << p->error();
-  EXPECT_THAT(p->error(),
-              HasSubstr("invalid SPIR-V storage class 7 for module scope "
-                        "variable: %52 = OpVariable %3 Function"));
+    EXPECT_TRUE(p->BuildInternalModule());
+    // Normally we should run ParserImpl::RegisterTypes before emitting
+    // variables. But defensive coding in EmitModuleScopeVariables lets
+    // us catch this error.
+    EXPECT_FALSE(p->EmitModuleScopeVariables()) << p->error();
+    EXPECT_THAT(p->error(), HasSubstr("invalid SPIR-V storage class 7 for module scope "
+                                      "variable: %52 = OpVariable %3 Function"));
 }
 
 TEST_F(SpvModuleScopeVarParserTest, BadPointerType) {
-  auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
+    auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
     %float = OpTypeFloat 32
     %fn_ty = OpTypeFunction %float
     %3 = OpTypePointer Private %fn_ty
@@ -162,17 +161,17 @@
     %void = OpTypeVoid
     %voidfn = OpTypeFunction %void
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
-  // Normally we should run ParserImpl::RegisterTypes before emitting
-  // variables. But defensive coding in EmitModuleScopeVariables lets
-  // us catch this error.
-  EXPECT_FALSE(p->EmitModuleScopeVariables());
-  EXPECT_THAT(p->error(), HasSubstr("internal error: failed to register Tint "
-                                    "AST type for SPIR-V type with ID: 3"));
+    EXPECT_TRUE(p->BuildInternalModule());
+    // Normally we should run ParserImpl::RegisterTypes before emitting
+    // variables. But defensive coding in EmitModuleScopeVariables lets
+    // us catch this error.
+    EXPECT_FALSE(p->EmitModuleScopeVariables());
+    EXPECT_THAT(p->error(), HasSubstr("internal error: failed to register Tint "
+                                      "AST type for SPIR-V type with ID: 3"));
 }
 
 TEST_F(SpvModuleScopeVarParserTest, NonPointerType) {
-  auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
+    auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
     %float = OpTypeFloat 32
     %5 = OpTypeFunction %float
     %3 = OpTypePointer Private %5
@@ -180,15 +179,13 @@
     %void = OpTypeVoid
     %voidfn = OpTypeFunction %void
   )" + MainBody()));
-  EXPECT_TRUE(p->BuildInternalModule());
-  EXPECT_FALSE(p->RegisterTypes());
-  EXPECT_THAT(
-      p->error(),
-      HasSubstr("SPIR-V pointer type with ID 3 has invalid pointee type 5"));
+    EXPECT_TRUE(p->BuildInternalModule());
+    EXPECT_FALSE(p->RegisterTypes());
+    EXPECT_THAT(p->error(), HasSubstr("SPIR-V pointer type with ID 3 has invalid pointee type 5"));
 }
 
 TEST_F(SpvModuleScopeVarParserTest, AnonWorkgroupVar) {
-  auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
+    auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
     %float = OpTypeFloat 32
     %ptr = OpTypePointer Workgroup %float
     %52 = OpVariable %ptr Workgroup
@@ -196,14 +193,14 @@
     %voidfn = OpTypeFunction %void
   )" + MainBody()));
 
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(module_str, HasSubstr("var<workgroup> x_52 : f32;"));
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr("var<workgroup> x_52 : f32;"));
 }
 
 TEST_F(SpvModuleScopeVarParserTest, NamedWorkgroupVar) {
-  auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
+    auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
     OpName %52 "the_counter"
     %float = OpTypeFloat 32
     %ptr = OpTypePointer Workgroup %float
@@ -212,14 +209,14 @@
     %voidfn = OpTypeFunction %void
   )" + MainBody()));
 
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(module_str, HasSubstr("var<workgroup> the_counter : f32;"));
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr("var<workgroup> the_counter : f32;"));
 }
 
 TEST_F(SpvModuleScopeVarParserTest, PrivateVar) {
-  auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
+    auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
     OpName %52 "my_own_private_idaho"
     %float = OpTypeFloat 32
     %ptr = OpTypePointer Private %float
@@ -228,19 +225,18 @@
     %voidfn = OpTypeFunction %void
   )" + MainBody()));
 
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(module_str,
-              HasSubstr("var<private> my_own_private_idaho : f32;"));
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr("var<private> my_own_private_idaho : f32;"));
 }
 
 TEST_F(SpvModuleScopeVarParserTest, BuiltinVertexIndex) {
-  // This is the simple case for the vertex_index builtin,
-  // where the SPIR-V uses the same store type as in WGSL.
-  // See later for tests where the SPIR-V store type is signed
-  // integer, as in GLSL.
-  auto p = parser(test::Assemble(Preamble() + R"(
+    // This is the simple case for the vertex_index builtin,
+    // where the SPIR-V uses the same store type as in WGSL.
+    // See later for tests where the SPIR-V store type is signed
+    // integer, as in GLSL.
+    auto p = parser(test::Assemble(Preamble() + R"(
     OpEntryPoint Vertex %main "main" %52 %position
     OpName %position "position"
     OpDecorate %position BuiltIn Position
@@ -256,14 +252,14 @@
     %position = OpVariable %posty Output
   )" + MainBody()));
 
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(module_str, HasSubstr("var<private> x_52 : u32;"));
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr("var<private> x_52 : u32;"));
 }
 
 std::string PerVertexPreamble() {
-  return R"(
+    return R"(
     OpCapability Shader
     OpMemoryModel Logical Simple
     OpEntryPoint Vertex %main "main" %1
@@ -287,10 +283,9 @@
 )";
 }
 
-TEST_F(SpvModuleScopeVarParserTest,
-       BuiltinPosition_StoreWholeStruct_NotSupported) {
-  // Glslang does not generate this code pattern.
-  const std::string assembly = PerVertexPreamble() + R"(
+TEST_F(SpvModuleScopeVarParserTest, BuiltinPosition_StoreWholeStruct_NotSupported) {
+    // Glslang does not generate this code pattern.
+    const std::string assembly = PerVertexPreamble() + R"(
   %nil = OpConstantNull %10 ; the whole struct
 
   %main = OpFunction %void None %voidfn
@@ -299,48 +294,45 @@
   OpReturn
   OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_FALSE(p->BuildAndParseInternalModule()) << assembly;
-  EXPECT_THAT(p->error(), Eq("storing to the whole per-vertex structure is not "
-                             "supported: OpStore %1 %13"))
-      << p->error();
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_FALSE(p->BuildAndParseInternalModule()) << assembly;
+    EXPECT_THAT(p->error(), Eq("storing to the whole per-vertex structure is not "
+                               "supported: OpStore %1 %13"))
+        << p->error();
 }
 
-TEST_F(SpvModuleScopeVarParserTest,
-       BuiltinPosition_IntermediateWholeStruct_NotSupported) {
-  const std::string assembly = PerVertexPreamble() + R"(
+TEST_F(SpvModuleScopeVarParserTest, BuiltinPosition_IntermediateWholeStruct_NotSupported) {
+    const std::string assembly = PerVertexPreamble() + R"(
   %main = OpFunction %void None %voidfn
   %entry = OpLabel
   %1000 = OpUndef %10
   OpReturn
   OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_FALSE(p->BuildAndParseInternalModule()) << assembly;
-  EXPECT_THAT(p->error(), Eq("operations producing a per-vertex structure are "
-                             "not supported: %1000 = OpUndef %10"))
-      << p->error();
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_FALSE(p->BuildAndParseInternalModule()) << assembly;
+    EXPECT_THAT(p->error(), Eq("operations producing a per-vertex structure are "
+                               "not supported: %1000 = OpUndef %10"))
+        << p->error();
 }
 
-TEST_F(SpvModuleScopeVarParserTest,
-       BuiltinPosition_IntermediatePtrWholeStruct_NotSupported) {
-  const std::string assembly = PerVertexPreamble() + R"(
+TEST_F(SpvModuleScopeVarParserTest, BuiltinPosition_IntermediatePtrWholeStruct_NotSupported) {
+    const std::string assembly = PerVertexPreamble() + R"(
   %main = OpFunction %void None %voidfn
   %entry = OpLabel
   %1000 = OpCopyObject %11 %1
   OpReturn
   OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_FALSE(p->BuildAndParseInternalModule());
-  EXPECT_THAT(p->error(),
-              Eq("operations producing a pointer to a per-vertex structure are "
-                 "not supported: %1000 = OpCopyObject %11 %1"))
-      << p->error();
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_FALSE(p->BuildAndParseInternalModule());
+    EXPECT_THAT(p->error(), Eq("operations producing a pointer to a per-vertex structure are "
+                               "not supported: %1000 = OpCopyObject %11 %1"))
+        << p->error();
 }
 
 TEST_F(SpvModuleScopeVarParserTest, BuiltinPosition_StorePosition) {
-  const std::string assembly = PerVertexPreamble() + R"(
+    const std::string assembly = PerVertexPreamble() + R"(
   %ptr_v4float = OpTypePointer Output %12
   %nil = OpConstantNull %12
 
@@ -351,17 +343,15 @@
   OpReturn
   OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(module_str, HasSubstr("gl_Position = vec4<f32>();"))
-      << module_str;
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr("gl_Position = vec4<f32>();")) << module_str;
 }
 
-TEST_F(SpvModuleScopeVarParserTest,
-       BuiltinPosition_StorePosition_PerVertexStructOutOfOrderDecl) {
-  const std::string assembly = R"(
+TEST_F(SpvModuleScopeVarParserTest, BuiltinPosition_StorePosition_PerVertexStructOutOfOrderDecl) {
+    const std::string assembly = R"(
   OpCapability Shader
   OpMemoryModel Logical Simple
   OpEntryPoint Vertex %main "main" %1
@@ -395,17 +385,15 @@
   OpReturn
   OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(module_str, HasSubstr("gl_Position = vec4<f32>();"))
-      << module_str;
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr("gl_Position = vec4<f32>();")) << module_str;
 }
 
-TEST_F(SpvModuleScopeVarParserTest,
-       BuiltinPosition_StorePositionMember_OneAccessChain) {
-  const std::string assembly = PerVertexPreamble() + R"(
+TEST_F(SpvModuleScopeVarParserTest, BuiltinPosition_StorePositionMember_OneAccessChain) {
+    const std::string assembly = PerVertexPreamble() + R"(
   %ptr_float = OpTypePointer Output %float
   %nil = OpConstantNull %float
 
@@ -416,17 +404,16 @@
   OpReturn
   OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(module_str, HasSubstr("gl_Position.y = 0.0;")) << module_str;
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr("gl_Position.y = 0.0;")) << module_str;
 }
 
-TEST_F(SpvModuleScopeVarParserTest,
-       BuiltinPosition_StorePositionMember_TwoAccessChain) {
-  // The algorithm is smart enough to collapse it down.
-  const std::string assembly = PerVertexPreamble() + R"(
+TEST_F(SpvModuleScopeVarParserTest, BuiltinPosition_StorePositionMember_TwoAccessChain) {
+    // The algorithm is smart enough to collapse it down.
+    const std::string assembly = PerVertexPreamble() + R"(
   %ptr = OpTypePointer Output %12
   %ptr_float = OpTypePointer Output %float
   %nil = OpConstantNull %float
@@ -439,15 +426,15 @@
   OpReturn
   OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(module_str, HasSubstr("gl_Position.y = 0.0;")) << module_str;
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr("gl_Position.y = 0.0;")) << module_str;
 }
 
 TEST_F(SpvModuleScopeVarParserTest, BuiltinPointSize_Write1_IsErased) {
-  const std::string assembly = PerVertexPreamble() + R"(
+    const std::string assembly = PerVertexPreamble() + R"(
   %ptr = OpTypePointer Output %float
   %one = OpConstant %float 1.0
 
@@ -458,11 +445,11 @@
   OpReturn
   OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_EQ(module_str, R"(var<private> gl_Position : vec4<f32>;
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_EQ(module_str, R"(var<private> gl_Position : vec4<f32>;
 
 fn main_1() {
   return;
@@ -482,7 +469,7 @@
 }
 
 TEST_F(SpvModuleScopeVarParserTest, BuiltinPointSize_WriteNon1_IsError) {
-  const std::string assembly = PerVertexPreamble() + R"(
+    const std::string assembly = PerVertexPreamble() + R"(
   %ptr = OpTypePointer Output %float
   %999 = OpConstant %float 2.0
 
@@ -493,15 +480,14 @@
   OpReturn
   OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_FALSE(p->BuildAndParseInternalModule());
-  EXPECT_THAT(p->error(),
-              HasSubstr("cannot store a value other than constant 1.0 to "
-                        "PointSize builtin: OpStore %100 %999"));
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_FALSE(p->BuildAndParseInternalModule());
+    EXPECT_THAT(p->error(), HasSubstr("cannot store a value other than constant 1.0 to "
+                                      "PointSize builtin: OpStore %100 %999"));
 }
 
 TEST_F(SpvModuleScopeVarParserTest, BuiltinPointSize_ReadReplaced) {
-  const std::string assembly = PerVertexPreamble() + R"(
+    const std::string assembly = PerVertexPreamble() + R"(
   %ptr = OpTypePointer Output %float
   %nil = OpConstantNull %12
   %private_ptr = OpTypePointer Private %float
@@ -515,11 +501,11 @@
   OpReturn
   OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_EQ(module_str, R"(var<private> x_900 : f32;
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_EQ(module_str, R"(var<private> x_900 : f32;
 
 var<private> gl_Position : vec4<f32>;
 
@@ -541,9 +527,8 @@
 )") << module_str;
 }
 
-TEST_F(SpvModuleScopeVarParserTest,
-       BuiltinPointSize_WriteViaCopyObjectPriorAccess_Unsupported) {
-  const std::string assembly = PerVertexPreamble() + R"(
+TEST_F(SpvModuleScopeVarParserTest, BuiltinPointSize_WriteViaCopyObjectPriorAccess_Unsupported) {
+    const std::string assembly = PerVertexPreamble() + R"(
   %ptr = OpTypePointer Output %float
   %nil = OpConstantNull %12
 
@@ -555,17 +540,15 @@
   OpReturn
   OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_FALSE(p->BuildAndParseInternalModule()) << p->error();
-  EXPECT_THAT(
-      p->error(),
-      HasSubstr("operations producing a pointer to a per-vertex structure are "
-                "not supported: %20 = OpCopyObject %11 %1"));
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_FALSE(p->BuildAndParseInternalModule()) << p->error();
+    EXPECT_THAT(p->error(),
+                HasSubstr("operations producing a pointer to a per-vertex structure are "
+                          "not supported: %20 = OpCopyObject %11 %1"));
 }
 
-TEST_F(SpvModuleScopeVarParserTest,
-       BuiltinPointSize_WriteViaCopyObjectPostAccessChainErased) {
-  const std::string assembly = PerVertexPreamble() + R"(
+TEST_F(SpvModuleScopeVarParserTest, BuiltinPointSize_WriteViaCopyObjectPostAccessChainErased) {
+    const std::string assembly = PerVertexPreamble() + R"(
   %ptr = OpTypePointer Output %float
   %one = OpConstant %float 1.0
 
@@ -577,11 +560,11 @@
   OpReturn
   OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_TRUE(p->BuildAndParseInternalModule()) << p->error();
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_EQ(module_str, R"(var<private> gl_Position : vec4<f32>;
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_TRUE(p->BuildAndParseInternalModule()) << p->error();
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_EQ(module_str, R"(var<private> gl_Position : vec4<f32>;
 
 fn main_1() {
   return;
@@ -601,15 +584,15 @@
 }
 
 std::string LoosePointSizePreamble(std::string stage = "Vertex") {
-  return R"(
+    return R"(
     OpCapability Shader
     OpMemoryModel Logical Simple
     OpEntryPoint )" +
-         stage + R"( %500 "main" %1
+           stage + R"( %500 "main" %1
 )" + (stage == "Vertex" ? " %2 " : "") +
-         +(stage == "Fragment" ? "OpExecutionMode %500 OriginUpperLeft" : "") +
-         +(stage == "Vertex" ? " OpDecorate %2 BuiltIn Position " : "") +
-         R"(
+           +(stage == "Fragment" ? "OpExecutionMode %500 OriginUpperLeft" : "") +
+           +(stage == "Vertex" ? " OpDecorate %2 BuiltIn Position " : "") +
+           R"(
     OpDecorate %1 BuiltIn PointSize
     %void = OpTypeVoid
     %voidfn = OpTypeFunction %void
@@ -626,7 +609,7 @@
 }
 
 TEST_F(SpvModuleScopeVarParserTest, BuiltinPointSize_Loose_Write1_IsErased) {
-  const std::string assembly = LoosePointSizePreamble() + R"(
+    const std::string assembly = LoosePointSizePreamble() + R"(
   %ptr = OpTypePointer Output %float
   %one = OpConstant %float 1.0
 
@@ -636,11 +619,11 @@
   OpReturn
   OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_EQ(module_str, R"(var<private> x_2 : vec4<f32>;
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_EQ(module_str, R"(var<private> x_2 : vec4<f32>;
 
 fn main_1() {
   return;
@@ -660,7 +643,7 @@
 }
 
 TEST_F(SpvModuleScopeVarParserTest, BuiltinPointSize_Loose_WriteNon1_IsError) {
-  const std::string assembly = LoosePointSizePreamble() + R"(
+    const std::string assembly = LoosePointSizePreamble() + R"(
   %ptr = OpTypePointer Output %float
   %999 = OpConstant %float 2.0
 
@@ -670,16 +653,14 @@
   OpReturn
   OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_FALSE(p->BuildAndParseInternalModule());
-  EXPECT_THAT(p->error(),
-              HasSubstr("cannot store a value other than constant 1.0 to "
-                        "PointSize builtin: OpStore %1 %999"));
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_FALSE(p->BuildAndParseInternalModule());
+    EXPECT_THAT(p->error(), HasSubstr("cannot store a value other than constant 1.0 to "
+                                      "PointSize builtin: OpStore %1 %999"));
 }
 
-TEST_F(SpvModuleScopeVarParserTest,
-       BuiltinPointSize_Loose_ReadReplaced_Vertex) {
-  const std::string assembly = LoosePointSizePreamble() + R"(
+TEST_F(SpvModuleScopeVarParserTest, BuiltinPointSize_Loose_ReadReplaced_Vertex) {
+    const std::string assembly = LoosePointSizePreamble() + R"(
   %ptr = OpTypePointer Private %float
   %900 = OpVariable %ptr Private
 
@@ -690,12 +671,12 @@
   OpReturn
   OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
+    auto p = parser(test::Assemble(assembly));
 
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_EQ(module_str, R"(var<private> x_2 : vec4<f32>;
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_EQ(module_str, R"(var<private> x_2 : vec4<f32>;
 
 var<private> x_900 : f32;
 
@@ -717,9 +698,8 @@
 )") << module_str;
 }
 
-TEST_F(SpvModuleScopeVarParserTest,
-       BuiltinPointSize_Loose_ReadReplaced_Fragment) {
-  const std::string assembly = LoosePointSizePreamble("Fragment") + R"(
+TEST_F(SpvModuleScopeVarParserTest, BuiltinPointSize_Loose_ReadReplaced_Fragment) {
+    const std::string assembly = LoosePointSizePreamble("Fragment") + R"(
   %ptr = OpTypePointer Private %float
   %900 = OpVariable %ptr Private
 
@@ -730,18 +710,17 @@
   OpReturn
   OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
+    auto p = parser(test::Assemble(assembly));
 
-  // This example is invalid because you PointSize is not valid in Vulkan
-  // Fragment shaders.
-  EXPECT_FALSE(p->Parse());
-  EXPECT_FALSE(p->success());
-  EXPECT_THAT(p->error(), HasSubstr("VUID-PointSize-PointSize-04314"));
+    // This example is invalid because you PointSize is not valid in Vulkan
+    // Fragment shaders.
+    EXPECT_FALSE(p->Parse());
+    EXPECT_FALSE(p->success());
+    EXPECT_THAT(p->error(), HasSubstr("VUID-PointSize-PointSize-04314"));
 }
 
-TEST_F(SpvModuleScopeVarParserTest,
-       BuiltinPointSize_Loose_WriteViaCopyObjectPriorAccess_Erased) {
-  const std::string assembly = LoosePointSizePreamble() + R"(
+TEST_F(SpvModuleScopeVarParserTest, BuiltinPointSize_Loose_WriteViaCopyObjectPriorAccess_Erased) {
+    const std::string assembly = LoosePointSizePreamble() + R"(
   %one = OpConstant %float 1.0
 
   %500 = OpFunction %void None %voidfn
@@ -752,11 +731,11 @@
   OpReturn
   OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_TRUE(p->BuildAndParseInternalModule()) << p->error();
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_EQ(module_str, R"(var<private> x_2 : vec4<f32>;
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_TRUE(p->BuildAndParseInternalModule()) << p->error();
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_EQ(module_str, R"(var<private> x_2 : vec4<f32>;
 
 fn main_1() {
   return;
@@ -777,7 +756,7 @@
 
 TEST_F(SpvModuleScopeVarParserTest,
        BuiltinPointSize_Loose_WriteViaCopyObjectPostAccessChainErased) {
-  const std::string assembly = LoosePointSizePreamble() + R"(
+    const std::string assembly = LoosePointSizePreamble() + R"(
   %one = OpConstant %float 1.0
 
   %500 = OpFunction %void None %voidfn
@@ -788,11 +767,11 @@
   OpReturn
   OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_TRUE(p->BuildAndParseInternalModule()) << p->error();
-  EXPECT_TRUE(p->error().empty()) << p->error();
-  const auto module_str = test::ToString(p->program());
-  EXPECT_EQ(module_str, R"(var<private> x_2 : vec4<f32>;
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_TRUE(p->BuildAndParseInternalModule()) << p->error();
+    EXPECT_TRUE(p->error().empty()) << p->error();
+    const auto module_str = test::ToString(p->program());
+    EXPECT_EQ(module_str, R"(var<private> x_2 : vec4<f32>;
 
 fn main_1() {
   return;
@@ -812,7 +791,7 @@
 }
 
 TEST_F(SpvModuleScopeVarParserTest, BuiltinClipDistance_NotSupported) {
-  const std::string assembly = PerVertexPreamble() + R"(
+    const std::string assembly = PerVertexPreamble() + R"(
   %ptr_float = OpTypePointer Output %float
   %nil = OpConstantNull %float
   %uint_2 = OpConstant %uint 2
@@ -825,15 +804,15 @@
   OpReturn
   OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_FALSE(p->BuildAndParseInternalModule());
-  EXPECT_EQ(p->error(),
-            "accessing per-vertex member 2 is not supported. Only Position is "
-            "supported, and PointSize is ignored");
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_FALSE(p->BuildAndParseInternalModule());
+    EXPECT_EQ(p->error(),
+              "accessing per-vertex member 2 is not supported. Only Position is "
+              "supported, and PointSize is ignored");
 }
 
 TEST_F(SpvModuleScopeVarParserTest, BuiltinCullDistance_NotSupported) {
-  const std::string assembly = PerVertexPreamble() + R"(
+    const std::string assembly = PerVertexPreamble() + R"(
   %ptr_float = OpTypePointer Output %float
   %nil = OpConstantNull %float
   %uint_3 = OpConstant %uint 3
@@ -846,15 +825,15 @@
   OpReturn
   OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_FALSE(p->BuildAndParseInternalModule());
-  EXPECT_EQ(p->error(),
-            "accessing per-vertex member 3 is not supported. Only Position is "
-            "supported, and PointSize is ignored");
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_FALSE(p->BuildAndParseInternalModule());
+    EXPECT_EQ(p->error(),
+              "accessing per-vertex member 3 is not supported. Only Position is "
+              "supported, and PointSize is ignored");
 }
 
 TEST_F(SpvModuleScopeVarParserTest, BuiltinPerVertex_MemberIndex_NotConstant) {
-  const std::string assembly = PerVertexPreamble() + R"(
+    const std::string assembly = PerVertexPreamble() + R"(
   %ptr_float = OpTypePointer Output %float
   %nil = OpConstantNull %float
 
@@ -866,16 +845,14 @@
   OpReturn
   OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_FALSE(p->BuildAndParseInternalModule());
-  EXPECT_THAT(p->error(),
-              Eq("first index of access chain into per-vertex structure is not "
-                 "a constant: %100 = OpAccessChain %13 %1 %16"));
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_FALSE(p->BuildAndParseInternalModule());
+    EXPECT_THAT(p->error(), Eq("first index of access chain into per-vertex structure is not "
+                               "a constant: %100 = OpAccessChain %13 %1 %16"));
 }
 
-TEST_F(SpvModuleScopeVarParserTest,
-       BuiltinPerVertex_MemberIndex_NotConstantInteger) {
-  const std::string assembly = PerVertexPreamble() + R"(
+TEST_F(SpvModuleScopeVarParserTest, BuiltinPerVertex_MemberIndex_NotConstantInteger) {
+    const std::string assembly = PerVertexPreamble() + R"(
   %ptr_float = OpTypePointer Output %float
   %nil = OpConstantNull %float
 
@@ -887,29 +864,28 @@
   OpReturn
   OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_FALSE(p->BuildAndParseInternalModule());
-  EXPECT_THAT(p->error(),
-              Eq("first index of access chain into per-vertex structure is not "
-                 "a constant integer: %100 = OpAccessChain %13 %1 %14"));
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_FALSE(p->BuildAndParseInternalModule());
+    EXPECT_THAT(p->error(), Eq("first index of access chain into per-vertex structure is not "
+                               "a constant integer: %100 = OpAccessChain %13 %1 %14"));
 }
 
 TEST_F(SpvModuleScopeVarParserTest, ScalarInitializers) {
-  auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() + R"(
+    auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() + R"(
      %1 = OpVariable %ptr_bool Private %true
      %2 = OpVariable %ptr_bool Private %false
      %3 = OpVariable %ptr_int Private %int_m1
      %4 = OpVariable %ptr_uint Private %uint_1
      %5 = OpVariable %ptr_float Private %float_1p5
   )" + MainBody()));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(module_str, HasSubstr(R"(var<private> x_1 : bool = true;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr(R"(var<private> x_1 : bool = true;
 
 var<private> x_2 : bool = false;
 
-var<private> x_3 : i32 = -1;
+var<private> x_3 : i32 = -1i;
 
 var<private> x_4 : u32 = 1u;
 
@@ -918,7 +894,7 @@
 }
 
 TEST_F(SpvModuleScopeVarParserTest, ScalarNullInitializers) {
-  auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() + R"(
+    auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() + R"(
      %null_bool = OpConstantNull %bool
      %null_int = OpConstantNull %int
      %null_uint = OpConstantNull %uint
@@ -929,12 +905,12 @@
      %3 = OpVariable %ptr_uint Private %null_uint
      %4 = OpVariable %ptr_float Private %null_float
   )" + MainBody()));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(module_str, HasSubstr(R"(var<private> x_1 : bool = false;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr(R"(var<private> x_1 : bool = false;
 
-var<private> x_2 : i32 = 0;
+var<private> x_2 : i32 = 0i;
 
 var<private> x_3 : u32 = 0u;
 
@@ -943,7 +919,7 @@
 }
 
 TEST_F(SpvModuleScopeVarParserTest, ScalarUndefInitializers) {
-  auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() + R"(
+    auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() + R"(
      %undef_bool = OpUndef %bool
      %undef_int = OpUndef %int
      %undef_uint = OpUndef %uint
@@ -954,155 +930,145 @@
      %3 = OpVariable %ptr_uint Private %undef_uint
      %4 = OpVariable %ptr_float Private %undef_float
   )" + MainBody()));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(module_str, HasSubstr(R"(var<private> x_1 : bool = false;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr(R"(var<private> x_1 : bool = false;
 
-var<private> x_2 : i32 = 0;
+var<private> x_2 : i32 = 0i;
 
 var<private> x_3 : u32 = 0u;
 
 var<private> x_4 : f32 = 0.0;
 )"));
 
-  // This example module emits ok, but is not valid SPIR-V in the first place.
-  p->DeliberatelyInvalidSpirv();
+    // This example module emits ok, but is not valid SPIR-V in the first place.
+    p->DeliberatelyInvalidSpirv();
 }
 
 TEST_F(SpvModuleScopeVarParserTest, VectorInitializer) {
-  auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() + R"(
+    auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() + R"(
      %ptr = OpTypePointer Private %v2float
      %two = OpConstant %float 2.0
      %const = OpConstantComposite %v2float %float_1p5 %two
      %200 = OpVariable %ptr Private %const
   )" + MainBody()));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(
-      module_str,
-      HasSubstr("var<private> x_200 : vec2<f32> = vec2<f32>(1.5, 2.0);"));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr("var<private> x_200 : vec2<f32> = vec2<f32>(1.5, 2.0);"));
 }
 
 TEST_F(SpvModuleScopeVarParserTest, VectorBoolNullInitializer) {
-  auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() + R"(
+    auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() + R"(
      %ptr = OpTypePointer Private %v2bool
      %const = OpConstantNull %v2bool
      %200 = OpVariable %ptr Private %const
   )" + MainBody()));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(module_str,
-              HasSubstr("var<private> x_200 : vec2<bool> = vec2<bool>();"));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr("var<private> x_200 : vec2<bool> = vec2<bool>();"));
 }
 
 TEST_F(SpvModuleScopeVarParserTest, VectorBoolUndefInitializer) {
-  auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() + R"(
+    auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() + R"(
      %ptr = OpTypePointer Private %v2bool
      %const = OpUndef %v2bool
      %200 = OpVariable %ptr Private %const
   )" + MainBody()));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(module_str,
-              HasSubstr("var<private> x_200 : vec2<bool> = vec2<bool>();"));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr("var<private> x_200 : vec2<bool> = vec2<bool>();"));
 
-  // This example module emits ok, but is not valid SPIR-V in the first place.
-  p->DeliberatelyInvalidSpirv();
+    // This example module emits ok, but is not valid SPIR-V in the first place.
+    p->DeliberatelyInvalidSpirv();
 }
 
 TEST_F(SpvModuleScopeVarParserTest, VectorUintNullInitializer) {
-  auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() + R"(
+    auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() + R"(
      %ptr = OpTypePointer Private %v2uint
      %const = OpConstantNull %v2uint
      %200 = OpVariable %ptr Private %const
   )" + MainBody()));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(module_str,
-              HasSubstr("var<private> x_200 : vec2<u32> = vec2<u32>();"));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr("var<private> x_200 : vec2<u32> = vec2<u32>();"));
 }
 
 TEST_F(SpvModuleScopeVarParserTest, VectorUintUndefInitializer) {
-  auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() + R"(
+    auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() + R"(
      %ptr = OpTypePointer Private %v2uint
      %const = OpUndef %v2uint
      %200 = OpVariable %ptr Private %const
   )" + MainBody()));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(module_str,
-              HasSubstr("var<private> x_200 : vec2<u32> = vec2<u32>();"));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr("var<private> x_200 : vec2<u32> = vec2<u32>();"));
 
-  // This example module emits ok, but is not valid SPIR-V in the first place.
-  p->DeliberatelyInvalidSpirv();
+    // This example module emits ok, but is not valid SPIR-V in the first place.
+    p->DeliberatelyInvalidSpirv();
 }
 
 TEST_F(SpvModuleScopeVarParserTest, VectorIntNullInitializer) {
-  auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() + R"(
+    auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() + R"(
      %ptr = OpTypePointer Private %v2int
      %const = OpConstantNull %v2int
      %200 = OpVariable %ptr Private %const
   )" + MainBody()));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(module_str,
-              HasSubstr("var<private> x_200 : vec2<i32> = vec2<i32>();"));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr("var<private> x_200 : vec2<i32> = vec2<i32>();"));
 }
 
 TEST_F(SpvModuleScopeVarParserTest, VectorIntUndefInitializer) {
-  auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() + R"(
+    auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() + R"(
      %ptr = OpTypePointer Private %v2int
      %const = OpUndef %v2int
      %200 = OpVariable %ptr Private %const
   )" + MainBody()));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(module_str,
-              HasSubstr("var<private> x_200 : vec2<i32> = vec2<i32>();"));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr("var<private> x_200 : vec2<i32> = vec2<i32>();"));
 
-  // This example module emits ok, but is not valid SPIR-V in the first place.
-  p->DeliberatelyInvalidSpirv();
+    // This example module emits ok, but is not valid SPIR-V in the first place.
+    p->DeliberatelyInvalidSpirv();
 }
 
 TEST_F(SpvModuleScopeVarParserTest, VectorFloatNullInitializer) {
-  auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() + R"(
+    auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() + R"(
      %ptr = OpTypePointer Private %v2float
      %const = OpConstantNull %v2float
      %200 = OpVariable %ptr Private %const
   )" + MainBody()));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(module_str,
-              HasSubstr("var<private> x_200 : vec2<f32> = vec2<f32>();"));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr("var<private> x_200 : vec2<f32> = vec2<f32>();"));
 }
 
 TEST_F(SpvModuleScopeVarParserTest, VectorFloatUndefInitializer) {
-  auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() + R"(
+    auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() + R"(
      %ptr = OpTypePointer Private %v2float
      %const = OpUndef %v2float
      %200 = OpVariable %ptr Private %const
   )" + MainBody()));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(module_str,
-              HasSubstr("var<private> x_200 : vec2<f32> = vec2<f32>();"));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr("var<private> x_200 : vec2<f32> = vec2<f32>();"));
 
-  // This example module emits ok, but is not valid SPIR-V in the first place.
-  p->DeliberatelyInvalidSpirv();
+    // This example module emits ok, but is not valid SPIR-V in the first place.
+    p->DeliberatelyInvalidSpirv();
 }
 
 TEST_F(SpvModuleScopeVarParserTest, MatrixInitializer) {
-  auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() + R"(
+    auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() + R"(
      %ptr = OpTypePointer Private %m3v2float
      %two = OpConstant %float 2.0
      %three = OpConstant %float 3.0
@@ -1113,201 +1079,179 @@
      %const = OpConstantComposite %m3v2float %v0 %v1 %v2
      %200 = OpVariable %ptr Private %const
   )" + MainBody()));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(module_str,
-              HasSubstr("var<private> x_200 : mat3x2<f32> = mat3x2<f32>("
-                        "vec2<f32>(1.5, 2.0), "
-                        "vec2<f32>(2.0, 3.0), "
-                        "vec2<f32>(3.0, 4.0));"));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr("var<private> x_200 : mat3x2<f32> = mat3x2<f32>("
+                                      "vec2<f32>(1.5, 2.0), "
+                                      "vec2<f32>(2.0, 3.0), "
+                                      "vec2<f32>(3.0, 4.0));"));
 }
 
 TEST_F(SpvModuleScopeVarParserTest, MatrixNullInitializer) {
-  auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() + R"(
+    auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() + R"(
      %ptr = OpTypePointer Private %m3v2float
      %const = OpConstantNull %m3v2float
      %200 = OpVariable %ptr Private %const
   )" + MainBody()));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(module_str,
-              HasSubstr("var<private> x_200 : mat3x2<f32> = mat3x2<f32>();"));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr("var<private> x_200 : mat3x2<f32> = mat3x2<f32>();"));
 }
 
 TEST_F(SpvModuleScopeVarParserTest, MatrixUndefInitializer) {
-  auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() + R"(
+    auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() + R"(
      %ptr = OpTypePointer Private %m3v2float
      %const = OpUndef %m3v2float
      %200 = OpVariable %ptr Private %const
   )" + MainBody()));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(module_str,
-              HasSubstr("var<private> x_200 : mat3x2<f32> = mat3x2<f32>();"));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr("var<private> x_200 : mat3x2<f32> = mat3x2<f32>();"));
 
-  // This example module emits ok, but is not valid SPIR-V in the first place.
-  p->DeliberatelyInvalidSpirv();
+    // This example module emits ok, but is not valid SPIR-V in the first place.
+    p->DeliberatelyInvalidSpirv();
 }
 
 TEST_F(SpvModuleScopeVarParserTest, ArrayInitializer) {
-  auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() + R"(
+    auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() + R"(
      %ptr = OpTypePointer Private %arr2uint
      %two = OpConstant %uint 2
      %const = OpConstantComposite %arr2uint %uint_1 %two
      %200 = OpVariable %ptr Private %const
   )" + MainBody()));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(
-      module_str,
-      HasSubstr(
-          "var<private> x_200 : array<u32, 2u> = array<u32, 2u>(1u, 2u);"));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str,
+                HasSubstr("var<private> x_200 : array<u32, 2u> = array<u32, 2u>(1u, 2u);"));
 }
 
 TEST_F(SpvModuleScopeVarParserTest, ArrayNullInitializer) {
-  auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() + R"(
+    auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() + R"(
      %ptr = OpTypePointer Private %arr2uint
      %const = OpConstantNull %arr2uint
      %200 = OpVariable %ptr Private %const
   )" + MainBody()));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(
-      module_str,
-      HasSubstr("var<private> x_200 : array<u32, 2u> = array<u32, 2u>();"));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr("var<private> x_200 : array<u32, 2u> = array<u32, 2u>();"));
 }
 
 TEST_F(SpvModuleScopeVarParserTest, ArrayUndefInitializer) {
-  auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() + R"(
+    auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() + R"(
      %ptr = OpTypePointer Private %arr2uint
      %const = OpUndef %arr2uint
      %200 = OpVariable %ptr Private %const
   )" + MainBody()));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(
-      module_str,
-      HasSubstr("var<private> x_200 : array<u32, 2u> = array<u32, 2u>();"));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr("var<private> x_200 : array<u32, 2u> = array<u32, 2u>();"));
 
-  // This example module emits ok, but is not valid SPIR-V in the first place.
-  p->DeliberatelyInvalidSpirv();
+    // This example module emits ok, but is not valid SPIR-V in the first place.
+    p->DeliberatelyInvalidSpirv();
 }
 
 TEST_F(SpvModuleScopeVarParserTest, StructInitializer) {
-  auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() +
-                                 StructTypes() + R"(
+    auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() + StructTypes() + R"(
      %ptr = OpTypePointer Private %strct
      %two = OpConstant %uint 2
      %arrconst = OpConstantComposite %arr2uint %uint_1 %two
      %const = OpConstantComposite %strct %uint_1 %float_1p5 %arrconst
      %200 = OpVariable %ptr Private %const
   )" + MainBody()));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(
-      module_str,
-      HasSubstr("var<private> x_200 : S = S(1u, 1.5, array<u32, 2u>(1u, 2u));"))
-      << module_str;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str,
+                HasSubstr("var<private> x_200 : S = S(1u, 1.5, array<u32, 2u>(1u, 2u));"))
+        << module_str;
 }
 
 TEST_F(SpvModuleScopeVarParserTest, StructNullInitializer) {
-  auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() +
-                                 StructTypes() + R"(
+    auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() + StructTypes() + R"(
      %ptr = OpTypePointer Private %strct
      %const = OpConstantNull %strct
      %200 = OpVariable %ptr Private %const
   )" + MainBody()));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(
-      module_str,
-      HasSubstr("var<private> x_200 : S = S(0u, 0.0, array<u32, 2u>());"))
-      << module_str;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr("var<private> x_200 : S = S(0u, 0.0, array<u32, 2u>());"))
+        << module_str;
 }
 
 TEST_F(SpvModuleScopeVarParserTest, StructUndefInitializer) {
-  auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() +
-                                 StructTypes() + R"(
+    auto p = parser(test::Assemble(Preamble() + FragMain() + CommonTypes() + StructTypes() + R"(
      %ptr = OpTypePointer Private %strct
      %const = OpUndef %strct
      %200 = OpVariable %ptr Private %const
   )" + MainBody()));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  EXPECT_TRUE(p->error().empty());
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    EXPECT_TRUE(p->error().empty());
 
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(
-      module_str,
-      HasSubstr("var<private> x_200 : S = S(0u, 0.0, array<u32, 2u>());"))
-      << module_str;
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr("var<private> x_200 : S = S(0u, 0.0, array<u32, 2u>());"))
+        << module_str;
 
-  // This example module emits ok, but is not valid SPIR-V in the first place.
-  p->DeliberatelyInvalidSpirv();
+    // This example module emits ok, but is not valid SPIR-V in the first place.
+    p->DeliberatelyInvalidSpirv();
 }
 
 TEST_F(SpvModuleScopeVarParserTest, DescriptorGroupDecoration_Valid) {
-  auto p = parser(test::Assemble(Preamble() + FragMain() + CommonLayout() + R"(
+    auto p = parser(test::Assemble(Preamble() + FragMain() + CommonLayout() + R"(
      OpDecorate %1 DescriptorSet 3
      OpDecorate %1 Binding 9 ; Required to pass WGSL validation
      OpDecorate %strct Block
 )" + CommonTypes() + StructTypes() +
-                                 R"(
+                                   R"(
      %ptr_sb_strct = OpTypePointer StorageBuffer %strct
      %1 = OpVariable %ptr_sb_strct StorageBuffer
   )" + MainBody()));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(
-      module_str,
-      HasSubstr("@group(3) @binding(9) var<storage, read_write> x_1 : S;"))
-      << module_str;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr("@group(3) @binding(9) var<storage, read_write> x_1 : S;"))
+        << module_str;
 }
 
 TEST_F(SpvModuleScopeVarParserTest, BindingDecoration_Valid) {
-  auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
+    auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
      OpDecorate %1 DescriptorSet 0 ; WGSL validation requires this already
      OpDecorate %1 Binding 3
      OpDecorate %strct Block
 )" + CommonLayout() + CommonTypes() +
-                                 StructTypes() +
-                                 R"(
+                                   StructTypes() +
+                                   R"(
      %ptr_sb_strct = OpTypePointer StorageBuffer %strct
      %1 = OpVariable %ptr_sb_strct StorageBuffer
   )" + MainBody()));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(
-      module_str,
-      HasSubstr("@group(0) @binding(3) var<storage, read_write> x_1 : S;"))
-      << module_str;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr("@group(0) @binding(3) var<storage, read_write> x_1 : S;"))
+        << module_str;
 }
 
-TEST_F(SpvModuleScopeVarParserTest,
-       StructMember_NonReadableDecoration_Dropped) {
-  auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
+TEST_F(SpvModuleScopeVarParserTest, StructMember_NonReadableDecoration_Dropped) {
+    auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
      OpDecorate %1 DescriptorSet 0
      OpDecorate %1 Binding 0
      OpDecorate %strct Block
      OpMemberDecorate %strct 0 NonReadable
 )" + CommonLayout() + CommonTypes() +
-                                 StructTypes() + R"(
+                                   StructTypes() + R"(
      %ptr_sb_strct = OpTypePointer StorageBuffer %strct
      %1 = OpVariable %ptr_sb_strct StorageBuffer
   )" + MainBody()));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(module_str, HasSubstr(R"(type Arr = @stride(4) array<u32, 2u>;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr(R"(type Arr = @stride(4) array<u32, 2u>;
 
 struct S {
   field0 : u32,
@@ -1320,7 +1264,7 @@
 }
 
 TEST_F(SpvModuleScopeVarParserTest, ColMajorDecoration_Dropped) {
-  auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
+    auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
      OpName %myvar "myvar"
      OpDecorate %myvar DescriptorSet 0
      OpDecorate %myvar Binding 0
@@ -1338,10 +1282,10 @@
      %void = OpTypeVoid
      %voidfn = OpTypeFunction %void
   )" + MainBody()));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(module_str, HasSubstr(R"(struct S {
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr(R"(struct S {
   field0 : mat3x2<f32>,
 }
 
@@ -1350,7 +1294,7 @@
 }
 
 TEST_F(SpvModuleScopeVarParserTest, MatrixStrideDecoration_Natural_Dropped) {
-  auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
+    auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
      OpName %myvar "myvar"
      OpDecorate %myvar DescriptorSet 0
      OpDecorate %myvar Binding 0
@@ -1367,10 +1311,10 @@
      %ptr_sb_s = OpTypePointer StorageBuffer %s
      %myvar = OpVariable %ptr_sb_s StorageBuffer
   )" + MainBody()));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(module_str, HasSubstr(R"(struct S {
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr(R"(struct S {
   field0 : mat3x2<f32>,
 }
 
@@ -1379,7 +1323,7 @@
 }
 
 TEST_F(SpvModuleScopeVarParserTest, MatrixStrideDecoration) {
-  auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
+    auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
      OpName %myvar "myvar"
      OpDecorate %myvar DescriptorSet 0
      OpDecorate %myvar Binding 0
@@ -1396,10 +1340,10 @@
      %ptr_sb_s = OpTypePointer StorageBuffer %s
      %myvar = OpVariable %ptr_sb_s StorageBuffer
   )" + MainBody()));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(module_str, HasSubstr(R"(struct S {
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr(R"(struct S {
   @stride(64) @internal(disable_validation__ignore_stride)
   field0 : mat3x2<f32>,
 }
@@ -1409,7 +1353,7 @@
 }
 
 TEST_F(SpvModuleScopeVarParserTest, RowMajorDecoration_IsError) {
-  auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
+    auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
      OpName %myvar "myvar"
      OpDecorate %s Block
      OpMemberDecorate %s 0 RowMajor
@@ -1424,16 +1368,16 @@
      %ptr_sb_s = OpTypePointer StorageBuffer %s
      %myvar = OpVariable %ptr_sb_s StorageBuffer
   )" + MainBody()));
-  EXPECT_FALSE(p->BuildAndParseInternalModuleExceptFunctions());
-  EXPECT_THAT(
-      p->error(),
-      Eq(R"(WGSL does not support row-major matrices: can't translate member 0 of %3 = OpTypeStruct %8)"))
-      << p->error();
+    EXPECT_FALSE(p->BuildAndParseInternalModuleExceptFunctions());
+    EXPECT_THAT(
+        p->error(),
+        Eq(R"(WGSL does not support row-major matrices: can't translate member 0 of %3 = OpTypeStruct %8)"))
+        << p->error();
 }
 
 TEST_F(SpvModuleScopeVarParserTest, StorageBuffer_NonWritable_AllMembers) {
-  // Variable should have access(read)
-  auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
+    // Variable should have access(read)
+    auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
      OpDecorate %s Block
      OpDecorate %1 DescriptorSet 0
      OpDecorate %1 Binding 0
@@ -1449,10 +1393,10 @@
      %ptr_sb_s = OpTypePointer StorageBuffer %s
      %1 = OpVariable %ptr_sb_s StorageBuffer
   )" + MainBody()));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(module_str, HasSubstr(R"(struct S {
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr(R"(struct S {
   field0 : f32,
   field1 : f32,
 }
@@ -1462,8 +1406,8 @@
 }
 
 TEST_F(SpvModuleScopeVarParserTest, StorageBuffer_NonWritable_NotAllMembers) {
-  // Variable should have access(read_write)
-  auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
+    // Variable should have access(read_write)
+    auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
      OpDecorate %1 DescriptorSet 0
      OpDecorate %1 Binding 0
      OpDecorate %s Block
@@ -1478,10 +1422,10 @@
      %ptr_sb_s = OpTypePointer StorageBuffer %s
      %1 = OpVariable %ptr_sb_s StorageBuffer
   )" + MainBody()));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(module_str, HasSubstr(R"(struct S {
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr(R"(struct S {
   field0 : f32,
   field1 : f32,
 }
@@ -1490,11 +1434,10 @@
 )")) << module_str;
 }
 
-TEST_F(
-    SpvModuleScopeVarParserTest,
-    StorageBuffer_NonWritable_NotAllMembers_DuplicatedOnSameMember) {  // NOLINT
-  // Variable should have access(read_write)
-  auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
+TEST_F(SpvModuleScopeVarParserTest,
+       StorageBuffer_NonWritable_NotAllMembers_DuplicatedOnSameMember) {  // NOLINT
+    // Variable should have access(read_write)
+    auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
      OpDecorate %s Block
      OpDecorate %1 DescriptorSet 0
      OpDecorate %1 Binding 0
@@ -1510,10 +1453,10 @@
      %ptr_sb_s = OpTypePointer StorageBuffer %s
      %1 = OpVariable %ptr_sb_s StorageBuffer
   )" + MainBody()));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(module_str, HasSubstr(R"(struct S {
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr(R"(struct S {
   field0 : f32,
   field1 : f32,
 }
@@ -1523,36 +1466,35 @@
 }
 
 TEST_F(SpvModuleScopeVarParserTest, ScalarSpecConstant_DeclareConst_Id_TooBig) {
-  // Override IDs must be between 0 and 65535
-  auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
+    // Override IDs must be between 0 and 65535
+    auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
      OpDecorate %1 SpecId 65536
      %bool = OpTypeBool
      %1 = OpSpecConstantTrue %bool
      %void = OpTypeVoid
      %voidfn = OpTypeFunction %void
   )" + MainBody()));
-  EXPECT_FALSE(p->Parse());
-  EXPECT_EQ(p->error(),
-            "SpecId too large. WGSL override IDs must be between 0 and 65535: "
-            "ID %1 has SpecId 65536");
+    EXPECT_FALSE(p->Parse());
+    EXPECT_EQ(p->error(),
+              "SpecId too large. WGSL override IDs must be between 0 and 65535: "
+              "ID %1 has SpecId 65536");
 }
 
-TEST_F(SpvModuleScopeVarParserTest,
-       ScalarSpecConstant_DeclareConst_Id_MaxValid) {
-  // Override IDs must be between 0 and 65535
-  auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
+TEST_F(SpvModuleScopeVarParserTest, ScalarSpecConstant_DeclareConst_Id_MaxValid) {
+    // Override IDs must be between 0 and 65535
+    auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
      OpDecorate %1 SpecId 65535
      %bool = OpTypeBool
      %1 = OpSpecConstantTrue %bool
      %void = OpTypeVoid
      %voidfn = OpTypeFunction %void
   )" + MainBody()));
-  EXPECT_TRUE(p->Parse());
-  EXPECT_EQ(p->error(), "");
+    EXPECT_TRUE(p->Parse());
+    EXPECT_EQ(p->error(), "");
 }
 
 TEST_F(SpvModuleScopeVarParserTest, ScalarSpecConstant_DeclareConst_True) {
-  auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
+    auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
      OpName %c "myconst"
      OpDecorate %c SpecId 12
      %bool = OpTypeBool
@@ -1560,15 +1502,14 @@
      %void = OpTypeVoid
      %voidfn = OpTypeFunction %void
   )" + MainBody()));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(module_str, HasSubstr("@id(12) override myconst : bool = true;"))
-      << module_str;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr("@id(12) override myconst : bool = true;")) << module_str;
 }
 
 TEST_F(SpvModuleScopeVarParserTest, ScalarSpecConstant_DeclareConst_False) {
-  auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
+    auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
      OpName %c "myconst"
      OpDecorate %c SpecId 12
      %bool = OpTypeBool
@@ -1576,15 +1517,14 @@
      %void = OpTypeVoid
      %voidfn = OpTypeFunction %void
   )" + MainBody()));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(module_str, HasSubstr("@id(12) override myconst : bool = false;"))
-      << module_str;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr("@id(12) override myconst : bool = false;")) << module_str;
 }
 
 TEST_F(SpvModuleScopeVarParserTest, ScalarSpecConstant_DeclareConst_U32) {
-  auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
+    auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
      OpName %c "myconst"
      OpDecorate %c SpecId 12
      %uint = OpTypeInt 32 0
@@ -1592,15 +1532,14 @@
      %void = OpTypeVoid
      %voidfn = OpTypeFunction %void
   )" + MainBody()));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(module_str, HasSubstr("@id(12) override myconst : u32 = 42u;"))
-      << module_str;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr("@id(12) override myconst : u32 = 42u;")) << module_str;
 }
 
 TEST_F(SpvModuleScopeVarParserTest, ScalarSpecConstant_DeclareConst_I32) {
-  auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
+    auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
      OpName %c "myconst"
      OpDecorate %c SpecId 12
      %int = OpTypeInt 32 1
@@ -1608,15 +1547,14 @@
      %void = OpTypeVoid
      %voidfn = OpTypeFunction %void
   )" + MainBody()));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(module_str, HasSubstr("@id(12) override myconst : i32 = 42;"))
-      << module_str;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr("@id(12) override myconst : i32 = 42i;")) << module_str;
 }
 
 TEST_F(SpvModuleScopeVarParserTest, ScalarSpecConstant_DeclareConst_F32) {
-  auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
+    auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
      OpName %c "myconst"
      OpDecorate %c SpecId 12
      %float = OpTypeFloat 32
@@ -1624,32 +1562,29 @@
      %void = OpTypeVoid
      %voidfn = OpTypeFunction %void
   )" + MainBody()));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(module_str, HasSubstr("@id(12) override myconst : f32 = 2.5;"))
-      << module_str;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr("@id(12) override myconst : f32 = 2.5;")) << module_str;
 }
 
-TEST_F(SpvModuleScopeVarParserTest,
-       ScalarSpecConstant_DeclareConst_F32_WithoutSpecId) {
-  // When we don't have a spec ID, declare an undecorated module-scope constant.
-  auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
+TEST_F(SpvModuleScopeVarParserTest, ScalarSpecConstant_DeclareConst_F32_WithoutSpecId) {
+    // When we don't have a spec ID, declare an undecorated module-scope constant.
+    auto p = parser(test::Assemble(Preamble() + FragMain() + R"(
      OpName %c "myconst"
      %float = OpTypeFloat 32
      %c = OpSpecConstant %float 2.5
      %void = OpTypeVoid
      %voidfn = OpTypeFunction %void
   )" + MainBody()));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  EXPECT_THAT(module_str, HasSubstr("override myconst : f32 = 2.5;"))
-      << module_str;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    EXPECT_THAT(module_str, HasSubstr("override myconst : f32 = 2.5;")) << module_str;
 }
 
 TEST_F(SpvModuleScopeVarParserTest, ScalarSpecConstant_UsedInFunction) {
-  const auto assembly = Preamble() + FragMain() + R"(
+    const auto assembly = Preamble() + FragMain() + R"(
      OpName %c "myconst"
      %void = OpTypeVoid
      %voidfn = OpTypeFunction %void
@@ -1662,22 +1597,22 @@
      OpReturnValue %1
      OpFunctionEnd
   )" + MainBody();
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
-  auto fe = p->function_emitter(100);
-  EXPECT_TRUE(fe.EmitBody()) << p->error();
-  EXPECT_TRUE(p->error().empty());
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions()) << p->error();
+    auto fe = p->function_emitter(100);
+    EXPECT_TRUE(fe.EmitBody()) << p->error();
+    EXPECT_TRUE(p->error().empty());
 
-  Program program = p->program();
-  const auto got = test::ToString(program, fe.ast_body());
+    Program program = p->program();
+    const auto got = test::ToString(program, fe.ast_body());
 
-  EXPECT_THAT(got, HasSubstr("return (myconst + myconst);")) << got;
+    EXPECT_THAT(got, HasSubstr("return (myconst + myconst);")) << got;
 }
 
 // Returns the start of a shader for testing SampleId,
 // parameterized by store type of %int or %uint
 std::string SampleIdPreamble(std::string store_type) {
-  return R"(
+    return R"(
     OpCapability Shader
     OpCapability SampleRateShading
     OpMemoryModel Logical Simple
@@ -1690,25 +1625,25 @@
     %uint = OpTypeInt 32 0
     %int = OpTypeInt 32 1
     %ptr_ty = OpTypePointer Input )" +
-         store_type + R"(
+           store_type + R"(
     %1 = OpVariable %ptr_ty Input
 )";
 }
 
 TEST_F(SpvModuleScopeVarParserTest, SampleId_I32_Load_Direct) {
-  const std::string assembly = SampleIdPreamble("%int") + R"(
+    const std::string assembly = SampleIdPreamble("%int") + R"(
     %main = OpFunction %void None %voidfn
     %entry = OpLabel
     %2 = OpLoad %int %1
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  const std::string expected =
-      R"(var<private> x_1 : i32;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    const std::string expected =
+        R"(var<private> x_1 : i32;
 
 fn main_1() {
   let x_2 : i32 = x_1;
@@ -1721,11 +1656,11 @@
   main_1();
 }
 )";
-  EXPECT_EQ(module_str, expected) << module_str;
+    EXPECT_EQ(module_str, expected) << module_str;
 }
 
 TEST_F(SpvModuleScopeVarParserTest, SampleId_I32_Load_CopyObject) {
-  const std::string assembly = SampleIdPreamble("%int") + R"(
+    const std::string assembly = SampleIdPreamble("%int") + R"(
     %main = OpFunction %void None %voidfn
     %entry = OpLabel
     %copy_ptr = OpCopyObject %ptr_ty %1
@@ -1733,12 +1668,12 @@
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  const std::string expected =
-      R"(Module{
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    const std::string expected =
+        R"(Module{
   Variable{
     x_1
     private
@@ -1809,7 +1744,7 @@
 }
 
 TEST_F(SpvModuleScopeVarParserTest, SampleId_I32_Load_AccessChain) {
-  const std::string assembly = SampleIdPreamble("%int") + R"(
+    const std::string assembly = SampleIdPreamble("%int") + R"(
     %main = OpFunction %void None %voidfn
     %entry = OpLabel
     %copy_ptr = OpAccessChain %ptr_ty %1
@@ -1817,11 +1752,11 @@
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  const std::string expected = R"(var<private> x_1 : i32;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    const std::string expected = R"(var<private> x_1 : i32;
 
 fn main_1() {
   let x_2 : i32 = x_1;
@@ -1834,11 +1769,11 @@
   main_1();
 }
 )";
-  EXPECT_EQ(module_str, expected);
+    EXPECT_EQ(module_str, expected);
 }
 
 TEST_F(SpvModuleScopeVarParserTest, SampleId_I32_FunctParam) {
-  const std::string assembly = SampleIdPreamble("%int") + R"(
+    const std::string assembly = SampleIdPreamble("%int") + R"(
     %helper_ty = OpTypeFunction %int %ptr_ty
     %helper = OpFunction %int None %helper_ty
     %param = OpFunctionParameter %ptr_ty
@@ -1853,29 +1788,28 @@
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
+    auto p = parser(test::Assemble(assembly));
 
-  // This example is invalid because you can't pass pointer-to-Input
-  // as a function parameter.
-  EXPECT_FALSE(p->Parse());
-  EXPECT_FALSE(p->success());
-  EXPECT_THAT(p->error(),
-              HasSubstr("Invalid storage class for pointer operand 1"));
+    // This example is invalid because you can't pass pointer-to-Input
+    // as a function parameter.
+    EXPECT_FALSE(p->Parse());
+    EXPECT_FALSE(p->success());
+    EXPECT_THAT(p->error(), HasSubstr("Invalid storage class for pointer operand 1"));
 }
 
 TEST_F(SpvModuleScopeVarParserTest, SampleId_U32_Load_Direct) {
-  const std::string assembly = SampleIdPreamble("%uint") + R"(
+    const std::string assembly = SampleIdPreamble("%uint") + R"(
     %main = OpFunction %void None %voidfn
     %entry = OpLabel
     %2 = OpLoad %uint %1
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  const std::string expected = R"(var<private> x_1 : u32;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    const std::string expected = R"(var<private> x_1 : u32;
 
 fn main_1() {
   let x_2 : u32 = x_1;
@@ -1888,11 +1822,11 @@
   main_1();
 }
 )";
-  EXPECT_EQ(module_str, expected) << module_str;
+    EXPECT_EQ(module_str, expected) << module_str;
 }
 
 TEST_F(SpvModuleScopeVarParserTest, SampleId_U32_Load_CopyObject) {
-  const std::string assembly = SampleIdPreamble("%uint") + R"(
+    const std::string assembly = SampleIdPreamble("%uint") + R"(
     %main = OpFunction %void None %voidfn
     %entry = OpLabel
     %copy_ptr = OpCopyObject %ptr_ty %1
@@ -1900,11 +1834,11 @@
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  const std::string expected = R"(var<private> x_1 : u32;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    const std::string expected = R"(var<private> x_1 : u32;
 
 fn main_1() {
   let x_11 : ptr<private, u32> = &(x_1);
@@ -1918,11 +1852,11 @@
   main_1();
 }
 )";
-  EXPECT_EQ(module_str, expected) << module_str;
+    EXPECT_EQ(module_str, expected) << module_str;
 }
 
 TEST_F(SpvModuleScopeVarParserTest, SampleId_U32_Load_AccessChain) {
-  const std::string assembly = SampleIdPreamble("%uint") + R"(
+    const std::string assembly = SampleIdPreamble("%uint") + R"(
     %main = OpFunction %void None %voidfn
     %entry = OpLabel
     %copy_ptr = OpAccessChain %ptr_ty %1
@@ -1930,11 +1864,11 @@
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  const std::string expected = R"(var<private> x_1 : u32;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    const std::string expected = R"(var<private> x_1 : u32;
 
 fn main_1() {
   let x_2 : u32 = x_1;
@@ -1947,11 +1881,11 @@
   main_1();
 }
 )";
-  EXPECT_EQ(module_str, expected) << module_str;
+    EXPECT_EQ(module_str, expected) << module_str;
 }
 
 TEST_F(SpvModuleScopeVarParserTest, SampleId_U32_FunctParam) {
-  const std::string assembly = SampleIdPreamble("%uint") + R"(
+    const std::string assembly = SampleIdPreamble("%uint") + R"(
     %helper_ty = OpTypeFunction %uint %ptr_ty
     %helper = OpFunction %uint None %helper_ty
     %param = OpFunctionParameter %ptr_ty
@@ -1966,32 +1900,31 @@
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
-  // This example is invalid because you can't pass pointer-to-Input
-  // as a function parameter.
-  EXPECT_FALSE(p->Parse());
-  EXPECT_THAT(p->error(),
-              HasSubstr("Invalid storage class for pointer operand 1"));
+    auto p = parser(test::Assemble(assembly));
+    // This example is invalid because you can't pass pointer-to-Input
+    // as a function parameter.
+    EXPECT_FALSE(p->Parse());
+    EXPECT_THAT(p->error(), HasSubstr("Invalid storage class for pointer operand 1"));
 }
 
 // Returns the start of a shader for testing SampleMask
 // parameterized by store type.
 std::string SampleMaskPreamble(std::string store_type, uint32_t stride = 0u) {
-  return std::string(R"(
+    return std::string(R"(
     OpCapability Shader
     OpMemoryModel Logical Simple
     OpEntryPoint Fragment %main "main" %1
     OpExecutionMode %main OriginUpperLeft
     OpDecorate %1 BuiltIn SampleMask
 )") +
-         (stride > 0u ? R"(
+           (stride > 0u ? R"(
     OpDecorate %uarr1 ArrayStride 4
     OpDecorate %uarr2 ArrayStride 4
     OpDecorate %iarr1 ArrayStride 4
     OpDecorate %iarr2 ArrayStride 4
 )"
-                      : "") +
-         R"(
+                        : "") +
+           R"(
     %void = OpTypeVoid
     %voidfn = OpTypeFunction %void
     %float = OpTypeFloat 32
@@ -2010,14 +1943,14 @@
     %iptr_out_ty = OpTypePointer Output %int
     %uptr_out_ty = OpTypePointer Output %uint
     %in_ty = OpTypePointer Input )" +
-         store_type + R"(
+           store_type + R"(
     %out_ty = OpTypePointer Output )" +
-         store_type + R"(
+           store_type + R"(
 )";
 }
 
 TEST_F(SpvModuleScopeVarParserTest, SampleMask_In_ArraySize2_Error) {
-  const std::string assembly = SampleMaskPreamble("%uarr2") + R"(
+    const std::string assembly = SampleMaskPreamble("%uarr2") + R"(
     %1 = OpVariable %in_ty Input
 
     %main = OpFunction %void None %voidfn
@@ -2027,16 +1960,15 @@
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_FALSE(p->BuildAndParseInternalModule());
-  EXPECT_THAT(p->error(),
-              HasSubstr("WGSL supports a sample mask of at most 32 bits. "
-                        "SampleMask must be an array of 1 element"))
-      << p->error() << assembly;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_FALSE(p->BuildAndParseInternalModule());
+    EXPECT_THAT(p->error(), HasSubstr("WGSL supports a sample mask of at most 32 bits. "
+                                      "SampleMask must be an array of 1 element"))
+        << p->error() << assembly;
 }
 
 TEST_F(SpvModuleScopeVarParserTest, SampleMask_In_U32_Direct) {
-  const std::string assembly = SampleMaskPreamble("%uarr1") + R"(
+    const std::string assembly = SampleMaskPreamble("%uarr1") + R"(
     %1 = OpVariable %in_ty Input
 
     %main = OpFunction %void None %voidfn
@@ -2046,28 +1978,28 @@
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  const std::string expected = R"(var<private> x_1 : array<u32, 1u>;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    const std::string expected = R"(var<private> x_1 : array<u32, 1u>;
 
 fn main_1() {
-  let x_3 : u32 = x_1[0];
+  let x_3 : u32 = x_1[0i];
   return;
 }
 
 @stage(fragment)
 fn main(@builtin(sample_mask) x_1_param : u32) {
-  x_1[0] = x_1_param;
+  x_1[0i] = x_1_param;
   main_1();
 }
 )";
-  EXPECT_EQ(module_str, expected);
+    EXPECT_EQ(module_str, expected);
 }
 
 TEST_F(SpvModuleScopeVarParserTest, SampleMask_In_U32_CopyObject) {
-  const std::string assembly = SampleMaskPreamble("%uarr1") + R"(
+    const std::string assembly = SampleMaskPreamble("%uarr1") + R"(
     %1 = OpVariable %in_ty Input
 
     %main = OpFunction %void None %voidfn
@@ -2078,28 +2010,28 @@
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  const std::string expected = R"(var<private> x_1 : array<u32, 1u>;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    const std::string expected = R"(var<private> x_1 : array<u32, 1u>;
 
 fn main_1() {
-  let x_4 : u32 = x_1[0];
+  let x_4 : u32 = x_1[0i];
   return;
 }
 
 @stage(fragment)
 fn main(@builtin(sample_mask) x_1_param : u32) {
-  x_1[0] = x_1_param;
+  x_1[0i] = x_1_param;
   main_1();
 }
 )";
-  EXPECT_EQ(module_str, expected) << module_str;
+    EXPECT_EQ(module_str, expected) << module_str;
 }
 
 TEST_F(SpvModuleScopeVarParserTest, SampleMask_In_U32_AccessChain) {
-  const std::string assembly = SampleMaskPreamble("%uarr1") + R"(
+    const std::string assembly = SampleMaskPreamble("%uarr1") + R"(
     %1 = OpVariable %in_ty Input
 
     %main = OpFunction %void None %voidfn
@@ -2110,28 +2042,28 @@
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  const std::string expected = R"(var<private> x_1 : array<u32, 1u>;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    const std::string expected = R"(var<private> x_1 : array<u32, 1u>;
 
 fn main_1() {
-  let x_4 : u32 = x_1[0];
+  let x_4 : u32 = x_1[0i];
   return;
 }
 
 @stage(fragment)
 fn main(@builtin(sample_mask) x_1_param : u32) {
-  x_1[0] = x_1_param;
+  x_1[0i] = x_1_param;
   main_1();
 }
 )";
-  EXPECT_EQ(module_str, expected);
+    EXPECT_EQ(module_str, expected);
 }
 
 TEST_F(SpvModuleScopeVarParserTest, SampleMask_In_I32_Direct) {
-  const std::string assembly = SampleMaskPreamble("%iarr1") + R"(
+    const std::string assembly = SampleMaskPreamble("%iarr1") + R"(
     %1 = OpVariable %in_ty Input
 
     %main = OpFunction %void None %voidfn
@@ -2141,28 +2073,28 @@
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  const std::string expected = R"(var<private> x_1 : array<i32, 1u>;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    const std::string expected = R"(var<private> x_1 : array<i32, 1u>;
 
 fn main_1() {
-  let x_3 : i32 = x_1[0];
+  let x_3 : i32 = x_1[0i];
   return;
 }
 
 @stage(fragment)
 fn main(@builtin(sample_mask) x_1_param : u32) {
-  x_1[0] = bitcast<i32>(x_1_param);
+  x_1[0i] = bitcast<i32>(x_1_param);
   main_1();
 }
 )";
-  EXPECT_EQ(module_str, expected) << module_str;
+    EXPECT_EQ(module_str, expected) << module_str;
 }
 
 TEST_F(SpvModuleScopeVarParserTest, SampleMask_In_I32_CopyObject) {
-  const std::string assembly = SampleMaskPreamble("%iarr1") + R"(
+    const std::string assembly = SampleMaskPreamble("%iarr1") + R"(
     %1 = OpVariable %in_ty Input
 
     %main = OpFunction %void None %voidfn
@@ -2173,28 +2105,28 @@
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  const std::string expected = R"(var<private> x_1 : array<i32, 1u>;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    const std::string expected = R"(var<private> x_1 : array<i32, 1u>;
 
 fn main_1() {
-  let x_4 : i32 = x_1[0];
+  let x_4 : i32 = x_1[0i];
   return;
 }
 
 @stage(fragment)
 fn main(@builtin(sample_mask) x_1_param : u32) {
-  x_1[0] = bitcast<i32>(x_1_param);
+  x_1[0i] = bitcast<i32>(x_1_param);
   main_1();
 }
 )";
-  EXPECT_EQ(module_str, expected) << module_str;
+    EXPECT_EQ(module_str, expected) << module_str;
 }
 
 TEST_F(SpvModuleScopeVarParserTest, SampleMask_In_I32_AccessChain) {
-  const std::string assembly = SampleMaskPreamble("%iarr1") + R"(
+    const std::string assembly = SampleMaskPreamble("%iarr1") + R"(
     %1 = OpVariable %in_ty Input
 
     %main = OpFunction %void None %voidfn
@@ -2205,28 +2137,28 @@
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  const std::string expected = R"(var<private> x_1 : array<i32, 1u>;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    const std::string expected = R"(var<private> x_1 : array<i32, 1u>;
 
 fn main_1() {
-  let x_4 : i32 = x_1[0];
+  let x_4 : i32 = x_1[0i];
   return;
 }
 
 @stage(fragment)
 fn main(@builtin(sample_mask) x_1_param : u32) {
-  x_1[0] = bitcast<i32>(x_1_param);
+  x_1[0i] = bitcast<i32>(x_1_param);
   main_1();
 }
 )";
-  EXPECT_EQ(module_str, expected) << module_str;
+    EXPECT_EQ(module_str, expected) << module_str;
 }
 
 TEST_F(SpvModuleScopeVarParserTest, SampleMask_Out_ArraySize2_Error) {
-  const std::string assembly = SampleMaskPreamble("%uarr2") + R"(
+    const std::string assembly = SampleMaskPreamble("%uarr2") + R"(
     %1 = OpVariable %out_ty Output
 
     %main = OpFunction %void None %voidfn
@@ -2236,16 +2168,15 @@
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_FALSE(p->BuildAndParseInternalModule());
-  EXPECT_THAT(p->error(),
-              HasSubstr("WGSL supports a sample mask of at most 32 bits. "
-                        "SampleMask must be an array of 1 element"))
-      << p->error() << assembly;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_FALSE(p->BuildAndParseInternalModule());
+    EXPECT_THAT(p->error(), HasSubstr("WGSL supports a sample mask of at most 32 bits. "
+                                      "SampleMask must be an array of 1 element"))
+        << p->error() << assembly;
 }
 
 TEST_F(SpvModuleScopeVarParserTest, SampleMask_Out_U32_Direct) {
-  const std::string assembly = SampleMaskPreamble("%uarr1") + R"(
+    const std::string assembly = SampleMaskPreamble("%uarr1") + R"(
     %1 = OpVariable %out_ty Output
 
     %main = OpFunction %void None %voidfn
@@ -2255,14 +2186,14 @@
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  const std::string expected = R"(var<private> x_1 : array<u32, 1u>;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    const std::string expected = R"(var<private> x_1 : array<u32, 1u>;
 
 fn main_1() {
-  x_1[0] = 0u;
+  x_1[0i] = 0u;
   return;
 }
 
@@ -2274,14 +2205,14 @@
 @stage(fragment)
 fn main() -> main_out {
   main_1();
-  return main_out(x_1[0]);
+  return main_out(x_1[0i]);
 }
 )";
-  EXPECT_EQ(module_str, expected);
+    EXPECT_EQ(module_str, expected);
 }
 
 TEST_F(SpvModuleScopeVarParserTest, SampleMask_Out_U32_CopyObject) {
-  const std::string assembly = SampleMaskPreamble("%uarr1") + R"(
+    const std::string assembly = SampleMaskPreamble("%uarr1") + R"(
     %1 = OpVariable %out_ty Output
 
     %main = OpFunction %void None %voidfn
@@ -2292,14 +2223,14 @@
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  const std::string expected = R"(var<private> x_1 : array<u32, 1u>;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    const std::string expected = R"(var<private> x_1 : array<u32, 1u>;
 
 fn main_1() {
-  x_1[0] = 0u;
+  x_1[0i] = 0u;
   return;
 }
 
@@ -2311,14 +2242,14 @@
 @stage(fragment)
 fn main() -> main_out {
   main_1();
-  return main_out(x_1[0]);
+  return main_out(x_1[0i]);
 }
 )";
-  EXPECT_EQ(module_str, expected);
+    EXPECT_EQ(module_str, expected);
 }
 
 TEST_F(SpvModuleScopeVarParserTest, SampleMask_Out_U32_AccessChain) {
-  const std::string assembly = SampleMaskPreamble("%uarr1") + R"(
+    const std::string assembly = SampleMaskPreamble("%uarr1") + R"(
     %1 = OpVariable %out_ty Output
 
     %main = OpFunction %void None %voidfn
@@ -2329,14 +2260,14 @@
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  const std::string expected = R"(var<private> x_1 : array<u32, 1u>;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    const std::string expected = R"(var<private> x_1 : array<u32, 1u>;
 
 fn main_1() {
-  x_1[0] = 0u;
+  x_1[0i] = 0u;
   return;
 }
 
@@ -2348,14 +2279,14 @@
 @stage(fragment)
 fn main() -> main_out {
   main_1();
-  return main_out(x_1[0]);
+  return main_out(x_1[0i]);
 }
 )";
-  EXPECT_EQ(module_str, expected);
+    EXPECT_EQ(module_str, expected);
 }
 
 TEST_F(SpvModuleScopeVarParserTest, SampleMask_Out_I32_Direct) {
-  const std::string assembly = SampleMaskPreamble("%iarr1") + R"(
+    const std::string assembly = SampleMaskPreamble("%iarr1") + R"(
     %1 = OpVariable %out_ty Output
 
     %main = OpFunction %void None %voidfn
@@ -2365,14 +2296,14 @@
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  const std::string expected = R"(var<private> x_1 : array<i32, 1u>;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    const std::string expected = R"(var<private> x_1 : array<i32, 1u>;
 
 fn main_1() {
-  x_1[0] = 12;
+  x_1[0i] = 12i;
   return;
 }
 
@@ -2384,14 +2315,14 @@
 @stage(fragment)
 fn main() -> main_out {
   main_1();
-  return main_out(bitcast<u32>(x_1[0]));
+  return main_out(bitcast<u32>(x_1[0i]));
 }
 )";
-  EXPECT_EQ(module_str, expected);
+    EXPECT_EQ(module_str, expected);
 }
 
 TEST_F(SpvModuleScopeVarParserTest, SampleMask_Out_I32_CopyObject) {
-  const std::string assembly = SampleMaskPreamble("%iarr1") + R"(
+    const std::string assembly = SampleMaskPreamble("%iarr1") + R"(
     %1 = OpVariable %out_ty Output
 
     %main = OpFunction %void None %voidfn
@@ -2402,14 +2333,14 @@
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  const std::string expected = R"(var<private> x_1 : array<i32, 1u>;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    const std::string expected = R"(var<private> x_1 : array<i32, 1u>;
 
 fn main_1() {
-  x_1[0] = 12;
+  x_1[0i] = 12i;
   return;
 }
 
@@ -2421,14 +2352,14 @@
 @stage(fragment)
 fn main() -> main_out {
   main_1();
-  return main_out(bitcast<u32>(x_1[0]));
+  return main_out(bitcast<u32>(x_1[0i]));
 }
 )";
-  EXPECT_EQ(module_str, expected);
+    EXPECT_EQ(module_str, expected);
 }
 
 TEST_F(SpvModuleScopeVarParserTest, SampleMask_Out_I32_AccessChain) {
-  const std::string assembly = SampleMaskPreamble("%iarr1") + R"(
+    const std::string assembly = SampleMaskPreamble("%iarr1") + R"(
     %1 = OpVariable %out_ty Output
 
     %main = OpFunction %void None %voidfn
@@ -2439,14 +2370,14 @@
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  const std::string expected = R"(var<private> x_1 : array<i32, 1u>;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    const std::string expected = R"(var<private> x_1 : array<i32, 1u>;
 
 fn main_1() {
-  x_1[0] = 12;
+  x_1[0i] = 12i;
   return;
 }
 
@@ -2458,14 +2389,14 @@
 @stage(fragment)
 fn main() -> main_out {
   main_1();
-  return main_out(bitcast<u32>(x_1[0]));
+  return main_out(bitcast<u32>(x_1[0i]));
 }
 )";
-  EXPECT_EQ(module_str, expected);
+    EXPECT_EQ(module_str, expected);
 }
 
 TEST_F(SpvModuleScopeVarParserTest, SampleMask_In_WithStride) {
-  const std::string assembly = SampleMaskPreamble("%uarr1", 4u) + R"(
+    const std::string assembly = SampleMaskPreamble("%uarr1", 4u) + R"(
     %1 = OpVariable %in_ty Input
 
     %main = OpFunction %void None %voidfn
@@ -2475,11 +2406,11 @@
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  const std::string expected = R"(type Arr = @stride(4) array<u32, 1u>;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    const std::string expected = R"(type Arr = @stride(4) array<u32, 1u>;
 
 type Arr_1 = @stride(4) array<u32, 2u>;
 
@@ -2490,21 +2421,21 @@
 var<private> x_1 : Arr;
 
 fn main_1() {
-  let x_3 : u32 = x_1[0];
+  let x_3 : u32 = x_1[0i];
   return;
 }
 
 @stage(fragment)
 fn main(@builtin(sample_mask) x_1_param : u32) {
-  x_1[0] = x_1_param;
+  x_1[0i] = x_1_param;
   main_1();
 }
 )";
-  EXPECT_EQ(module_str, expected);
+    EXPECT_EQ(module_str, expected);
 }
 
 TEST_F(SpvModuleScopeVarParserTest, SampleMask_Out_WithStride) {
-  const std::string assembly = SampleMaskPreamble("%uarr1", 4u) + R"(
+    const std::string assembly = SampleMaskPreamble("%uarr1", 4u) + R"(
     %1 = OpVariable %out_ty Output
 
     %main = OpFunction %void None %voidfn
@@ -2514,11 +2445,11 @@
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  const std::string expected = R"(type Arr = @stride(4) array<u32, 1u>;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    const std::string expected = R"(type Arr = @stride(4) array<u32, 1u>;
 
 type Arr_1 = @stride(4) array<u32, 2u>;
 
@@ -2529,7 +2460,7 @@
 var<private> x_1 : Arr;
 
 fn main_1() {
-  x_1[0] = 0u;
+  x_1[0i] = 0u;
   return;
 }
 
@@ -2541,16 +2472,16 @@
 @stage(fragment)
 fn main() -> main_out {
   main_1();
-  return main_out(x_1[0]);
+  return main_out(x_1[0i]);
 }
 )";
-  EXPECT_EQ(module_str, expected);
+    EXPECT_EQ(module_str, expected);
 }
 
 // Returns the start of a shader for testing VertexIndex,
 // parameterized by store type of %int or %uint
 std::string VertexIndexPreamble(std::string store_type) {
-  return R"(
+    return R"(
     OpCapability Shader
     OpMemoryModel Logical Simple
     OpEntryPoint Vertex %main "main" %position %1
@@ -2562,7 +2493,7 @@
     %uint = OpTypeInt 32 0
     %int = OpTypeInt 32 1
     %ptr_ty = OpTypePointer Input )" +
-         store_type + R"(
+           store_type + R"(
     %1 = OpVariable %ptr_ty Input
     %v4float = OpTypeVector %float 4
     %posty = OpTypePointer Output %v4float
@@ -2571,18 +2502,18 @@
 }
 
 TEST_F(SpvModuleScopeVarParserTest, VertexIndex_I32_Load_Direct) {
-  const std::string assembly = VertexIndexPreamble("%int") + R"(
+    const std::string assembly = VertexIndexPreamble("%int") + R"(
     %main = OpFunction %void None %voidfn
     %entry = OpLabel
     %2 = OpLoad %int %1
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  const std::string expected = R"(var<private> x_1 : i32;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    const std::string expected = R"(var<private> x_1 : i32;
 
 var<private> x_4 : vec4<f32>;
 
@@ -2603,11 +2534,11 @@
   return main_out(x_4);
 }
 )";
-  EXPECT_EQ(module_str, expected) << module_str;
+    EXPECT_EQ(module_str, expected) << module_str;
 }
 
 TEST_F(SpvModuleScopeVarParserTest, VertexIndex_I32_Load_CopyObject) {
-  const std::string assembly = VertexIndexPreamble("%int") + R"(
+    const std::string assembly = VertexIndexPreamble("%int") + R"(
     %main = OpFunction %void None %voidfn
     %entry = OpLabel
     %copy_ptr = OpCopyObject %ptr_ty %1
@@ -2615,11 +2546,11 @@
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  const std::string expected = R"(var<private> x_1 : i32;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    const std::string expected = R"(var<private> x_1 : i32;
 
 var<private> x_4 : vec4<f32>;
 
@@ -2641,11 +2572,11 @@
   return main_out(x_4);
 }
 )";
-  EXPECT_EQ(module_str, expected);
+    EXPECT_EQ(module_str, expected);
 }
 
 TEST_F(SpvModuleScopeVarParserTest, VertexIndex_I32_Load_AccessChain) {
-  const std::string assembly = VertexIndexPreamble("%int") + R"(
+    const std::string assembly = VertexIndexPreamble("%int") + R"(
     %main = OpFunction %void None %voidfn
     %entry = OpLabel
     %copy_ptr = OpAccessChain %ptr_ty %1
@@ -2653,11 +2584,11 @@
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  const std::string expected = R"(var<private> x_1 : i32;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    const std::string expected = R"(var<private> x_1 : i32;
 
 var<private> x_4 : vec4<f32>;
 
@@ -2678,22 +2609,22 @@
   return main_out(x_4);
 }
 )";
-  EXPECT_EQ(module_str, expected);
+    EXPECT_EQ(module_str, expected);
 }
 
 TEST_F(SpvModuleScopeVarParserTest, VertexIndex_U32_Load_Direct) {
-  const std::string assembly = VertexIndexPreamble("%uint") + R"(
+    const std::string assembly = VertexIndexPreamble("%uint") + R"(
     %main = OpFunction %void None %voidfn
     %entry = OpLabel
     %2 = OpLoad %uint %1
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  const std::string expected = R"(var<private> x_1 : u32;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    const std::string expected = R"(var<private> x_1 : u32;
 
 var<private> x_4 : vec4<f32>;
 
@@ -2714,11 +2645,11 @@
   return main_out(x_4);
 }
 )";
-  EXPECT_EQ(module_str, expected);
+    EXPECT_EQ(module_str, expected);
 }
 
 TEST_F(SpvModuleScopeVarParserTest, VertexIndex_U32_Load_CopyObject) {
-  const std::string assembly = VertexIndexPreamble("%uint") + R"(
+    const std::string assembly = VertexIndexPreamble("%uint") + R"(
     %main = OpFunction %void None %voidfn
     %entry = OpLabel
     %copy_ptr = OpCopyObject %ptr_ty %1
@@ -2726,11 +2657,11 @@
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  const std::string expected = R"(var<private> x_1 : u32;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    const std::string expected = R"(var<private> x_1 : u32;
 
 var<private> x_4 : vec4<f32>;
 
@@ -2752,11 +2683,11 @@
   return main_out(x_4);
 }
 )";
-  EXPECT_EQ(module_str, expected);
+    EXPECT_EQ(module_str, expected);
 }
 
 TEST_F(SpvModuleScopeVarParserTest, VertexIndex_U32_Load_AccessChain) {
-  const std::string assembly = VertexIndexPreamble("%uint") + R"(
+    const std::string assembly = VertexIndexPreamble("%uint") + R"(
     %main = OpFunction %void None %voidfn
     %entry = OpLabel
     %copy_ptr = OpAccessChain %ptr_ty %1
@@ -2764,11 +2695,11 @@
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  const std::string expected = R"(var<private> x_1 : u32;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    const std::string expected = R"(var<private> x_1 : u32;
 
 var<private> x_4 : vec4<f32>;
 
@@ -2789,11 +2720,11 @@
   return main_out(x_4);
 }
 )";
-  EXPECT_EQ(module_str, expected);
+    EXPECT_EQ(module_str, expected);
 }
 
 TEST_F(SpvModuleScopeVarParserTest, VertexIndex_U32_FunctParam) {
-  const std::string assembly = VertexIndexPreamble("%uint") + R"(
+    const std::string assembly = VertexIndexPreamble("%uint") + R"(
     %helper_ty = OpTypeFunction %uint %ptr_ty
     %helper = OpFunction %uint None %helper_ty
     %param = OpFunctionParameter %ptr_ty
@@ -2808,19 +2739,18 @@
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
+    auto p = parser(test::Assemble(assembly));
 
-  // This example is invalid because you can't pass pointer-to-Input
-  // as a function parameter.
-  EXPECT_FALSE(p->Parse());
-  EXPECT_THAT(p->error(),
-              HasSubstr("Invalid storage class for pointer operand 1"));
+    // This example is invalid because you can't pass pointer-to-Input
+    // as a function parameter.
+    EXPECT_FALSE(p->Parse());
+    EXPECT_THAT(p->error(), HasSubstr("Invalid storage class for pointer operand 1"));
 }
 
 // Returns the start of a shader for testing InstanceIndex,
 // parameterized by store type of %int or %uint
 std::string InstanceIndexPreamble(std::string store_type) {
-  return R"(
+    return R"(
     OpCapability Shader
     OpMemoryModel Logical Simple
     OpEntryPoint Vertex %main "main" %position %1
@@ -2833,7 +2763,7 @@
     %uint = OpTypeInt 32 0
     %int = OpTypeInt 32 1
     %ptr_ty = OpTypePointer Input )" +
-         store_type + R"(
+           store_type + R"(
     %1 = OpVariable %ptr_ty Input
     %v4float = OpTypeVector %float 4
     %posty = OpTypePointer Output %v4float
@@ -2842,18 +2772,18 @@
 }
 
 TEST_F(SpvModuleScopeVarParserTest, InstanceIndex_I32_Load_Direct) {
-  const std::string assembly = InstanceIndexPreamble("%int") + R"(
+    const std::string assembly = InstanceIndexPreamble("%int") + R"(
     %main = OpFunction %void None %voidfn
     %entry = OpLabel
     %2 = OpLoad %int %1
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  const std::string expected = R"(var<private> x_1 : i32;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    const std::string expected = R"(var<private> x_1 : i32;
 
 var<private> position : vec4<f32>;
 
@@ -2874,11 +2804,11 @@
   return main_out(position);
 }
 )";
-  EXPECT_EQ(module_str, expected) << module_str;
+    EXPECT_EQ(module_str, expected) << module_str;
 }
 
 TEST_F(SpvModuleScopeVarParserTest, InstanceIndex_I32_Load_CopyObject) {
-  const std::string assembly = InstanceIndexPreamble("%int") + R"(
+    const std::string assembly = InstanceIndexPreamble("%int") + R"(
     %main = OpFunction %void None %voidfn
     %entry = OpLabel
     %copy_ptr = OpCopyObject %ptr_ty %1
@@ -2886,11 +2816,11 @@
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  const std::string expected = R"(var<private> x_1 : i32;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    const std::string expected = R"(var<private> x_1 : i32;
 
 var<private> position : vec4<f32>;
 
@@ -2912,11 +2842,11 @@
   return main_out(position);
 }
 )";
-  EXPECT_EQ(module_str, expected) << module_str;
+    EXPECT_EQ(module_str, expected) << module_str;
 }
 
 TEST_F(SpvModuleScopeVarParserTest, InstanceIndex_I32_Load_AccessChain) {
-  const std::string assembly = InstanceIndexPreamble("%int") + R"(
+    const std::string assembly = InstanceIndexPreamble("%int") + R"(
     %main = OpFunction %void None %voidfn
     %entry = OpLabel
     %copy_ptr = OpAccessChain %ptr_ty %1
@@ -2924,11 +2854,11 @@
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  const std::string expected = R"(var<private> x_1 : i32;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    const std::string expected = R"(var<private> x_1 : i32;
 
 var<private> position : vec4<f32>;
 
@@ -2949,11 +2879,11 @@
   return main_out(position);
 }
 )";
-  EXPECT_EQ(module_str, expected) << module_str;
+    EXPECT_EQ(module_str, expected) << module_str;
 }
 
 TEST_F(SpvModuleScopeVarParserTest, InstanceIndex_I32_FunctParam) {
-  const std::string assembly = InstanceIndexPreamble("%int") + R"(
+    const std::string assembly = InstanceIndexPreamble("%int") + R"(
     %helper_ty = OpTypeFunction %int %ptr_ty
     %helper = OpFunction %int None %helper_ty
     %param = OpFunctionParameter %ptr_ty
@@ -2968,27 +2898,26 @@
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
-  // This example is invalid because you can't pass pointer-to-Input
-  // as a function parameter.
-  EXPECT_FALSE(p->Parse());
-  EXPECT_THAT(p->error(),
-              HasSubstr("Invalid storage class for pointer operand 1"));
+    auto p = parser(test::Assemble(assembly));
+    // This example is invalid because you can't pass pointer-to-Input
+    // as a function parameter.
+    EXPECT_FALSE(p->Parse());
+    EXPECT_THAT(p->error(), HasSubstr("Invalid storage class for pointer operand 1"));
 }
 
 TEST_F(SpvModuleScopeVarParserTest, InstanceIndex_U32_Load_Direct) {
-  const std::string assembly = InstanceIndexPreamble("%uint") + R"(
+    const std::string assembly = InstanceIndexPreamble("%uint") + R"(
     %main = OpFunction %void None %voidfn
     %entry = OpLabel
     %2 = OpLoad %uint %1
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  const std::string expected = R"(var<private> x_1 : u32;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    const std::string expected = R"(var<private> x_1 : u32;
 
 var<private> position : vec4<f32>;
 
@@ -3009,11 +2938,11 @@
   return main_out(position);
 }
 )";
-  EXPECT_EQ(module_str, expected);
+    EXPECT_EQ(module_str, expected);
 }
 
 TEST_F(SpvModuleScopeVarParserTest, InstanceIndex_U32_Load_CopyObject) {
-  const std::string assembly = InstanceIndexPreamble("%uint") + R"(
+    const std::string assembly = InstanceIndexPreamble("%uint") + R"(
     %main = OpFunction %void None %voidfn
     %entry = OpLabel
     %copy_ptr = OpCopyObject %ptr_ty %1
@@ -3021,11 +2950,11 @@
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  const std::string expected = R"(var<private> x_1 : u32;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    const std::string expected = R"(var<private> x_1 : u32;
 
 var<private> position : vec4<f32>;
 
@@ -3047,11 +2976,11 @@
   return main_out(position);
 }
 )";
-  EXPECT_EQ(module_str, expected);
+    EXPECT_EQ(module_str, expected);
 }
 
 TEST_F(SpvModuleScopeVarParserTest, InstanceIndex_U32_Load_AccessChain) {
-  const std::string assembly = InstanceIndexPreamble("%uint") + R"(
+    const std::string assembly = InstanceIndexPreamble("%uint") + R"(
     %main = OpFunction %void None %voidfn
     %entry = OpLabel
     %copy_ptr = OpAccessChain %ptr_ty %1
@@ -3059,11 +2988,11 @@
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  const std::string expected = R"(var<private> x_1 : u32;
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    const std::string expected = R"(var<private> x_1 : u32;
 
 var<private> position : vec4<f32>;
 
@@ -3084,11 +3013,11 @@
   return main_out(position);
 }
 )";
-  EXPECT_EQ(module_str, expected);
+    EXPECT_EQ(module_str, expected);
 }
 
 TEST_F(SpvModuleScopeVarParserTest, InstanceIndex_U32_FunctParam) {
-  const std::string assembly = InstanceIndexPreamble("%uint") + R"(
+    const std::string assembly = InstanceIndexPreamble("%uint") + R"(
     %helper_ty = OpTypeFunction %uint %ptr_ty
     %helper = OpFunction %uint None %helper_ty
     %param = OpFunctionParameter %ptr_ty
@@ -3103,25 +3032,23 @@
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
-  // This example is invalid because you can't pass pointer-to-Input
-  // as a function parameter.
-  EXPECT_FALSE(p->Parse());
-  EXPECT_THAT(p->error(),
-              HasSubstr("Invalid storage class for pointer operand 1"));
+    auto p = parser(test::Assemble(assembly));
+    // This example is invalid because you can't pass pointer-to-Input
+    // as a function parameter.
+    EXPECT_FALSE(p->Parse());
+    EXPECT_THAT(p->error(), HasSubstr("Invalid storage class for pointer operand 1"));
 }
 
 // Returns the start of a shader for testing LocalInvocationIndex,
 // parameterized by store type of %int or %uint
-std::string ComputeBuiltinInputPreamble(std::string builtin,
-                                        std::string store_type) {
-  return R"(
+std::string ComputeBuiltinInputPreamble(std::string builtin, std::string store_type) {
+    return R"(
     OpCapability Shader
     OpMemoryModel Logical Simple
     OpEntryPoint GLCompute %main "main" %1
     OpExecutionMode %main LocalSize 1 1 1
     OpDecorate %1 BuiltIn )" +
-         builtin + R"(
+           builtin + R"(
     %void = OpTypeVoid
     %voidfn = OpTypeFunction %void
     %float = OpTypeFloat 32
@@ -3130,141 +3057,137 @@
     %v3uint = OpTypeVector %uint 3
     %v3int = OpTypeVector %int 3
     %ptr_ty = OpTypePointer Input )" +
-         store_type + R"(
+           store_type + R"(
     %1 = OpVariable %ptr_ty Input
 )";
 }
 
 struct ComputeBuiltinInputCase {
-  std::string spirv_builtin;
-  std::string spirv_store_type;
-  std::string wgsl_builtin;
+    std::string spirv_builtin;
+    std::string spirv_store_type;
+    std::string wgsl_builtin;
 };
 inline std::ostream& operator<<(std::ostream& o, ComputeBuiltinInputCase c) {
-  return o << "ComputeBuiltinInputCase(" << c.spirv_builtin << " "
-           << c.spirv_store_type << " " << c.wgsl_builtin << ")";
+    return o << "ComputeBuiltinInputCase(" << c.spirv_builtin << " " << c.spirv_store_type << " "
+             << c.wgsl_builtin << ")";
 }
 
 std::string WgslType(std::string spirv_type) {
-  if (spirv_type == "%uint") {
-    return "u32";
-  }
-  if (spirv_type == "%int") {
-    return "i32";
-  }
-  if (spirv_type == "%v3uint") {
-    return "vec3<u32>";
-  }
-  if (spirv_type == "%v3int") {
-    return "vec3<i32>";
-  }
-  return "error";
+    if (spirv_type == "%uint") {
+        return "u32";
+    }
+    if (spirv_type == "%int") {
+        return "i32";
+    }
+    if (spirv_type == "%v3uint") {
+        return "vec3<u32>";
+    }
+    if (spirv_type == "%v3int") {
+        return "vec3<i32>";
+    }
+    return "error";
 }
 
 std::string UnsignedWgslType(std::string wgsl_type) {
-  if (wgsl_type == "u32") {
-    return "u32";
-  }
-  if (wgsl_type == "i32") {
-    return "u32";
-  }
-  if (wgsl_type == "vec3<u32>") {
-    return "vec3<u32>";
-  }
-  if (wgsl_type == "vec3<i32>") {
-    return "vec3<u32>";
-  }
-  return "error";
+    if (wgsl_type == "u32") {
+        return "u32";
+    }
+    if (wgsl_type == "i32") {
+        return "u32";
+    }
+    if (wgsl_type == "vec3<u32>") {
+        return "vec3<u32>";
+    }
+    if (wgsl_type == "vec3<i32>") {
+        return "vec3<u32>";
+    }
+    return "error";
 }
 
 std::string SignedWgslType(std::string wgsl_type) {
-  if (wgsl_type == "u32") {
-    return "i32";
-  }
-  if (wgsl_type == "i32") {
-    return "i32";
-  }
-  if (wgsl_type == "vec3<u32>") {
-    return "vec3<i32>";
-  }
-  if (wgsl_type == "vec3<i32>") {
-    return "vec3<i32>";
-  }
-  return "error";
+    if (wgsl_type == "u32") {
+        return "i32";
+    }
+    if (wgsl_type == "i32") {
+        return "i32";
+    }
+    if (wgsl_type == "vec3<u32>") {
+        return "vec3<i32>";
+    }
+    if (wgsl_type == "vec3<i32>") {
+        return "vec3<i32>";
+    }
+    return "error";
 }
 
 using SpvModuleScopeVarParserTest_ComputeBuiltin =
     SpvParserTestBase<::testing::TestWithParam<ComputeBuiltinInputCase>>;
 
 TEST_P(SpvModuleScopeVarParserTest_ComputeBuiltin, Load_Direct) {
-  const auto wgsl_type = WgslType(GetParam().spirv_store_type);
-  const auto wgsl_builtin = GetParam().wgsl_builtin;
-  const auto unsigned_wgsl_type = UnsignedWgslType(wgsl_type);
-  const auto signed_wgsl_type = SignedWgslType(wgsl_type);
-  const std::string assembly =
-      ComputeBuiltinInputPreamble(GetParam().spirv_builtin,
-                                  GetParam().spirv_store_type) +
-      R"(
+    const auto wgsl_type = WgslType(GetParam().spirv_store_type);
+    const auto wgsl_builtin = GetParam().wgsl_builtin;
+    const auto unsigned_wgsl_type = UnsignedWgslType(wgsl_type);
+    const auto signed_wgsl_type = SignedWgslType(wgsl_type);
+    const std::string assembly =
+        ComputeBuiltinInputPreamble(GetParam().spirv_builtin, GetParam().spirv_store_type) +
+        R"(
     %main = OpFunction %void None %voidfn
     %entry = OpLabel
     %2 = OpLoad )" +
-      GetParam().spirv_store_type + R"( %1
+        GetParam().spirv_store_type + R"( %1
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  std::string expected = R"(var<private> x_1 : ${wgsl_type};
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    std::string expected = R"(var<private> x_1 : ${wgsl_type};
 
 fn main_1() {
   let x_2 : ${wgsl_type} = x_1;
   return;
 }
 
-@stage(compute) @workgroup_size(1, 1, 1)
+@stage(compute) @workgroup_size(1i, 1i, 1i)
 fn main(@builtin(${wgsl_builtin}) x_1_param : ${unsigned_wgsl_type}) {
   x_1 = ${assignment_value};
   main_1();
 }
 )";
 
-  expected = utils::ReplaceAll(expected, "${wgsl_type}", wgsl_type);
-  expected =
-      utils::ReplaceAll(expected, "${unsigned_wgsl_type}", unsigned_wgsl_type);
-  expected = utils::ReplaceAll(expected, "${wgsl_builtin}", wgsl_builtin);
-  expected =
-      utils::ReplaceAll(expected, "${assignment_value}",
-                        (wgsl_type == unsigned_wgsl_type)
-                            ? "x_1_param"
-                            : "bitcast<" + signed_wgsl_type + ">(x_1_param)");
+    expected = utils::ReplaceAll(expected, "${wgsl_type}", wgsl_type);
+    expected = utils::ReplaceAll(expected, "${unsigned_wgsl_type}", unsigned_wgsl_type);
+    expected = utils::ReplaceAll(expected, "${wgsl_builtin}", wgsl_builtin);
+    expected = utils::ReplaceAll(expected, "${assignment_value}",
+                                 (wgsl_type == unsigned_wgsl_type)
+                                     ? "x_1_param"
+                                     : "bitcast<" + signed_wgsl_type + ">(x_1_param)");
 
-  EXPECT_EQ(module_str, expected) << module_str;
+    EXPECT_EQ(module_str, expected) << module_str;
 }
 
 TEST_P(SpvModuleScopeVarParserTest_ComputeBuiltin, Load_CopyObject) {
-  const auto wgsl_type = WgslType(GetParam().spirv_store_type);
-  const auto wgsl_builtin = GetParam().wgsl_builtin;
-  const auto unsigned_wgsl_type = UnsignedWgslType(wgsl_type);
-  const auto signed_wgsl_type = SignedWgslType(wgsl_type);
-  const std::string assembly =
-      ComputeBuiltinInputPreamble(GetParam().spirv_builtin,
-                                  GetParam().spirv_store_type) +
-      R"(
+    const auto wgsl_type = WgslType(GetParam().spirv_store_type);
+    const auto wgsl_builtin = GetParam().wgsl_builtin;
+    const auto unsigned_wgsl_type = UnsignedWgslType(wgsl_type);
+    const auto signed_wgsl_type = SignedWgslType(wgsl_type);
+    const std::string assembly =
+        ComputeBuiltinInputPreamble(GetParam().spirv_builtin, GetParam().spirv_store_type) +
+        R"(
     %main = OpFunction %void None %voidfn
     %entry = OpLabel
     %13 = OpCopyObject %ptr_ty %1
     %2 = OpLoad )" +
-      GetParam().spirv_store_type + R"( %13
+        GetParam().spirv_store_type + R"( %13
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  std::string expected = R"(var<private> x_1 : ${wgsl_type};
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    std::string expected = R"(var<private> x_1 : ${wgsl_type};
 
 fn main_1() {
   let x_13 : ptr<private, ${wgsl_type}> = &(x_1);
@@ -3272,86 +3195,80 @@
   return;
 }
 
-@stage(compute) @workgroup_size(1, 1, 1)
+@stage(compute) @workgroup_size(1i, 1i, 1i)
 fn main(@builtin(${wgsl_builtin}) x_1_param : ${unsigned_wgsl_type}) {
   x_1 = ${assignment_value};
   main_1();
 }
 )";
 
-  expected = utils::ReplaceAll(expected, "${wgsl_type}", wgsl_type);
-  expected =
-      utils::ReplaceAll(expected, "${unsigned_wgsl_type}", unsigned_wgsl_type);
-  expected = utils::ReplaceAll(expected, "${wgsl_builtin}", wgsl_builtin);
-  expected =
-      utils::ReplaceAll(expected, "${assignment_value}",
-                        (wgsl_type == unsigned_wgsl_type)
-                            ? "x_1_param"
-                            : "bitcast<" + signed_wgsl_type + ">(x_1_param)");
+    expected = utils::ReplaceAll(expected, "${wgsl_type}", wgsl_type);
+    expected = utils::ReplaceAll(expected, "${unsigned_wgsl_type}", unsigned_wgsl_type);
+    expected = utils::ReplaceAll(expected, "${wgsl_builtin}", wgsl_builtin);
+    expected = utils::ReplaceAll(expected, "${assignment_value}",
+                                 (wgsl_type == unsigned_wgsl_type)
+                                     ? "x_1_param"
+                                     : "bitcast<" + signed_wgsl_type + ">(x_1_param)");
 
-  EXPECT_EQ(module_str, expected) << module_str;
+    EXPECT_EQ(module_str, expected) << module_str;
 }
 
 TEST_P(SpvModuleScopeVarParserTest_ComputeBuiltin, Load_AccessChain) {
-  const auto wgsl_type = WgslType(GetParam().spirv_store_type);
-  const auto wgsl_builtin = GetParam().wgsl_builtin;
-  const auto unsigned_wgsl_type = UnsignedWgslType(wgsl_type);
-  const auto signed_wgsl_type = SignedWgslType(wgsl_type);
-  const std::string assembly =
-      ComputeBuiltinInputPreamble(GetParam().spirv_builtin,
-                                  GetParam().spirv_store_type) +
-      R"(
+    const auto wgsl_type = WgslType(GetParam().spirv_store_type);
+    const auto wgsl_builtin = GetParam().wgsl_builtin;
+    const auto unsigned_wgsl_type = UnsignedWgslType(wgsl_type);
+    const auto signed_wgsl_type = SignedWgslType(wgsl_type);
+    const std::string assembly =
+        ComputeBuiltinInputPreamble(GetParam().spirv_builtin, GetParam().spirv_store_type) +
+        R"(
     %main = OpFunction %void None %voidfn
     %entry = OpLabel
     %13 = OpAccessChain %ptr_ty %1
     %2 = OpLoad )" +
-      GetParam().spirv_store_type + R"( %13
+        GetParam().spirv_store_type + R"( %13
     OpReturn
     OpFunctionEnd
  )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto module_str = test::ToString(p->program());
-  std::string expected = R"(var<private> x_1 : ${wgsl_type};
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto module_str = test::ToString(p->program());
+    std::string expected = R"(var<private> x_1 : ${wgsl_type};
 
 fn main_1() {
   let x_2 : ${wgsl_type} = x_1;
   return;
 }
 
-@stage(compute) @workgroup_size(1, 1, 1)
+@stage(compute) @workgroup_size(1i, 1i, 1i)
 fn main(@builtin(${wgsl_builtin}) x_1_param : ${unsigned_wgsl_type}) {
   x_1 = ${assignment_value};
   main_1();
 }
 )";
 
-  expected = utils::ReplaceAll(expected, "${wgsl_type}", wgsl_type);
-  expected =
-      utils::ReplaceAll(expected, "${unsigned_wgsl_type}", unsigned_wgsl_type);
-  expected = utils::ReplaceAll(expected, "${wgsl_builtin}", wgsl_builtin);
-  expected =
-      utils::ReplaceAll(expected, "${assignment_value}",
-                        (wgsl_type == unsigned_wgsl_type)
-                            ? "x_1_param"
-                            : "bitcast<" + signed_wgsl_type + ">(x_1_param)");
+    expected = utils::ReplaceAll(expected, "${wgsl_type}", wgsl_type);
+    expected = utils::ReplaceAll(expected, "${unsigned_wgsl_type}", unsigned_wgsl_type);
+    expected = utils::ReplaceAll(expected, "${wgsl_builtin}", wgsl_builtin);
+    expected = utils::ReplaceAll(expected, "${assignment_value}",
+                                 (wgsl_type == unsigned_wgsl_type)
+                                     ? "x_1_param"
+                                     : "bitcast<" + signed_wgsl_type + ">(x_1_param)");
 
-  EXPECT_EQ(module_str, expected) << module_str;
+    EXPECT_EQ(module_str, expected) << module_str;
 }
 
-INSTANTIATE_TEST_SUITE_P(
-    Samples,
-    SpvModuleScopeVarParserTest_ComputeBuiltin,
-    ::testing::ValuesIn(std::vector<ComputeBuiltinInputCase>{
-        {"LocalInvocationIndex", "%uint", "local_invocation_index"},
-        {"LocalInvocationIndex", "%int", "local_invocation_index"},
-        {"LocalInvocationId", "%v3uint", "local_invocation_id"},
-        {"LocalInvocationId", "%v3int", "local_invocation_id"},
-        {"GlobalInvocationId", "%v3uint", "global_invocation_id"},
-        {"GlobalInvocationId", "%v3int", "global_invocation_id"},
-        {"WorkgroupId", "%v3uint", "workgroup_id"},
-        {"WorkgroupId", "%v3int", "workgroup_id"}}));
+INSTANTIATE_TEST_SUITE_P(Samples,
+                         SpvModuleScopeVarParserTest_ComputeBuiltin,
+                         ::testing::ValuesIn(std::vector<ComputeBuiltinInputCase>{
+                             {"LocalInvocationIndex", "%uint", "local_invocation_index"},
+                             {"LocalInvocationIndex", "%int", "local_invocation_index"},
+                             {"LocalInvocationId", "%v3uint", "local_invocation_id"},
+                             {"LocalInvocationId", "%v3int", "local_invocation_id"},
+                             {"GlobalInvocationId", "%v3uint", "global_invocation_id"},
+                             {"GlobalInvocationId", "%v3int", "global_invocation_id"},
+                             {"WorkgroupId", "%v3uint", "workgroup_id"},
+                             {"WorkgroupId", "%v3int", "workgroup_id"}}));
 
 // TODO(dneto): crbug.com/tint/752
 // NumWorkgroups support is blocked by crbug.com/tint/752
@@ -3360,8 +3277,8 @@
 //        {"NumWorkgroups", "%int", "num_workgroups"}
 
 TEST_F(SpvModuleScopeVarParserTest, RegisterInputOutputVars) {
-  const std::string assembly =
-      R"(
+    const std::string assembly =
+        R"(
     OpCapability Shader
     OpMemoryModel Logical Simple
     OpEntryPoint Fragment %1000 "w1000"
@@ -3382,7 +3299,7 @@
     OpDecorate %15 Location 5
 
 )" + CommonTypes() +
-      R"(
+        R"(
 
     %ptr_in_uint = OpTypePointer Input %uint
     %ptr_out_uint = OpTypePointer Output %uint
@@ -3443,84 +3360,81 @@
     OpFunctionEnd
 
  )";
-  auto p = parser(test::Assemble(assembly));
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
+    auto p = parser(test::Assemble(assembly));
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
 
-  const auto& info_1000 = p->GetEntryPointInfo(1000);
-  EXPECT_EQ(1u, info_1000.size());
-  EXPECT_TRUE(info_1000[0].inputs.empty());
-  EXPECT_TRUE(info_1000[0].outputs.empty());
+    const auto& info_1000 = p->GetEntryPointInfo(1000);
+    EXPECT_EQ(1u, info_1000.size());
+    EXPECT_TRUE(info_1000[0].inputs.empty());
+    EXPECT_TRUE(info_1000[0].outputs.empty());
 
-  const auto& info_1100 = p->GetEntryPointInfo(1100);
-  EXPECT_EQ(1u, info_1100.size());
-  EXPECT_THAT(info_1100[0].inputs, ElementsAre(1));
-  EXPECT_TRUE(info_1100[0].outputs.empty());
+    const auto& info_1100 = p->GetEntryPointInfo(1100);
+    EXPECT_EQ(1u, info_1100.size());
+    EXPECT_THAT(info_1100[0].inputs, ElementsAre(1));
+    EXPECT_TRUE(info_1100[0].outputs.empty());
 
-  const auto& info_1200 = p->GetEntryPointInfo(1200);
-  EXPECT_EQ(1u, info_1200.size());
-  EXPECT_THAT(info_1200[0].inputs, ElementsAre(2));
-  EXPECT_THAT(info_1200[0].outputs, ElementsAre(15));
+    const auto& info_1200 = p->GetEntryPointInfo(1200);
+    EXPECT_EQ(1u, info_1200.size());
+    EXPECT_THAT(info_1200[0].inputs, ElementsAre(2));
+    EXPECT_THAT(info_1200[0].outputs, ElementsAre(15));
 
-  const auto& info_1300 = p->GetEntryPointInfo(1300);
-  EXPECT_EQ(1u, info_1300.size());
-  EXPECT_THAT(info_1300[0].inputs, ElementsAre(1, 2));
-  EXPECT_THAT(info_1300[0].outputs, ElementsAre(15));
+    const auto& info_1300 = p->GetEntryPointInfo(1300);
+    EXPECT_EQ(1u, info_1300.size());
+    EXPECT_THAT(info_1300[0].inputs, ElementsAre(1, 2));
+    EXPECT_THAT(info_1300[0].outputs, ElementsAre(15));
 
-  // Validation incorrectly reports an overlap for the duplicated variable %1 on
-  // shader %1300
-  p->SkipDumpingPending(
-      "https://github.com/KhronosGroup/SPIRV-Tools/issues/4403");
+    // Validation incorrectly reports an overlap for the duplicated variable %1 on
+    // shader %1300
+    p->SkipDumpingPending("https://github.com/KhronosGroup/SPIRV-Tools/issues/4403");
 }
 
 TEST_F(SpvModuleScopeVarParserTest, InputVarsConvertedToPrivate) {
-  const auto assembly = Preamble() + FragMain() + CommonTypes() + R"(
+    const auto assembly = Preamble() + FragMain() + CommonTypes() + R"(
      %ptr_in_uint = OpTypePointer Input %uint
      %1 = OpVariable %ptr_in_uint Input
   )" + MainBody();
-  auto p = parser(test::Assemble(assembly));
+    auto p = parser(test::Assemble(assembly));
 
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  EXPECT_TRUE(p->error().empty());
-  const auto got = test::ToString(p->program());
-  const std::string expected = "var<private> x_1 : u32;";
-  EXPECT_THAT(got, HasSubstr(expected)) << got;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    EXPECT_TRUE(p->error().empty());
+    const auto got = test::ToString(p->program());
+    const std::string expected = "var<private> x_1 : u32;";
+    EXPECT_THAT(got, HasSubstr(expected)) << got;
 }
 
 TEST_F(SpvModuleScopeVarParserTest, OutputVarsConvertedToPrivate) {
-  const auto assembly = Preamble() + FragMain() + CommonTypes() + R"(
+    const auto assembly = Preamble() + FragMain() + CommonTypes() + R"(
      %ptr_out_uint = OpTypePointer Output %uint
      %1 = OpVariable %ptr_out_uint Output
   )" + MainBody();
-  auto p = parser(test::Assemble(assembly));
+    auto p = parser(test::Assemble(assembly));
 
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  EXPECT_TRUE(p->error().empty());
-  const auto got = test::ToString(p->program());
-  const std::string expected = "var<private> x_1 : u32;";
-  EXPECT_THAT(got, HasSubstr(expected)) << got;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    EXPECT_TRUE(p->error().empty());
+    const auto got = test::ToString(p->program());
+    const std::string expected = "var<private> x_1 : u32;";
+    EXPECT_THAT(got, HasSubstr(expected)) << got;
 }
 
-TEST_F(SpvModuleScopeVarParserTest,
-       OutputVarsConvertedToPrivate_WithInitializer) {
-  const auto assembly = Preamble() + FragMain() + CommonTypes() + R"(
+TEST_F(SpvModuleScopeVarParserTest, OutputVarsConvertedToPrivate_WithInitializer) {
+    const auto assembly = Preamble() + FragMain() + CommonTypes() + R"(
      %ptr_out_uint = OpTypePointer Output %uint
      %1 = OpVariable %ptr_out_uint Output %uint_1
   )" + MainBody();
-  auto p = parser(test::Assemble(assembly));
+    auto p = parser(test::Assemble(assembly));
 
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  EXPECT_TRUE(p->error().empty());
-  const auto got = test::ToString(p->program());
-  const std::string expected = "var<private> x_1 : u32 = 1u;";
-  EXPECT_THAT(got, HasSubstr(expected)) << got;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    EXPECT_TRUE(p->error().empty());
+    const auto got = test::ToString(p->program());
+    const std::string expected = "var<private> x_1 : u32 = 1u;";
+    EXPECT_THAT(got, HasSubstr(expected)) << got;
 }
 
-TEST_F(SpvModuleScopeVarParserTest,
-       Builtin_Output_Initializer_SameSignednessAsWGSL) {
-  // Only outputs can have initializers.
-  // WGSL sample_mask store type is u32.
-  const auto assembly = Preamble() + FragMain() + R"(
+TEST_F(SpvModuleScopeVarParserTest, Builtin_Output_Initializer_SameSignednessAsWGSL) {
+    // Only outputs can have initializers.
+    // WGSL sample_mask store type is u32.
+    const auto assembly = Preamble() + FragMain() + R"(
      OpDecorate %1 BuiltIn SampleMask
 )" + CommonTypes() + R"(
      %arr_ty = OpTypeArray %uint %uint_1
@@ -3528,21 +3442,19 @@
      %arr_init = OpConstantComposite %arr_ty %uint_2
      %1 = OpVariable %ptr_ty Output %arr_init
   )" + MainBody();
-  auto p = parser(test::Assemble(assembly));
+    auto p = parser(test::Assemble(assembly));
 
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  EXPECT_TRUE(p->error().empty());
-  const auto got = test::ToString(p->program());
-  const std::string expected =
-      "var<private> x_1 : array<u32, 1u> = array<u32, 1u>(2u);";
-  EXPECT_THAT(got, HasSubstr(expected)) << got;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    EXPECT_TRUE(p->error().empty());
+    const auto got = test::ToString(p->program());
+    const std::string expected = "var<private> x_1 : array<u32, 1u> = array<u32, 1u>(2u);";
+    EXPECT_THAT(got, HasSubstr(expected)) << got;
 }
 
-TEST_F(SpvModuleScopeVarParserTest,
-       Builtin_Output_Initializer_OppositeSignednessAsWGSL) {
-  // Only outputs can have initializers.
-  // WGSL sample_mask store type is u32.  Use i32 in SPIR-V
-  const auto assembly = Preamble() + FragMain() + R"(
+TEST_F(SpvModuleScopeVarParserTest, Builtin_Output_Initializer_OppositeSignednessAsWGSL) {
+    // Only outputs can have initializers.
+    // WGSL sample_mask store type is u32.  Use i32 in SPIR-V
+    const auto assembly = Preamble() + FragMain() + R"(
      OpDecorate %1 BuiltIn SampleMask
 )" + CommonTypes() + R"(
      %arr_ty = OpTypeArray %int %uint_1
@@ -3550,52 +3462,51 @@
      %arr_init = OpConstantComposite %arr_ty %int_14
      %1 = OpVariable %ptr_ty Output %arr_init
   )" + MainBody();
-  auto p = parser(test::Assemble(assembly));
+    auto p = parser(test::Assemble(assembly));
 
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  EXPECT_TRUE(p->error().empty());
-  const auto got = test::ToString(p->program());
-  const std::string expected =
-      "var<private> x_1 : array<i32, 1u> = array<i32, 1u>(14);";
-  EXPECT_THAT(got, HasSubstr(expected)) << got;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    EXPECT_TRUE(p->error().empty());
+    const auto got = test::ToString(p->program());
+    const std::string expected = "var<private> x_1 : array<i32, 1u> = array<i32, 1u>(14i);";
+    EXPECT_THAT(got, HasSubstr(expected)) << got;
 }
 
 TEST_F(SpvModuleScopeVarParserTest, Builtin_Input_SameSignednessAsWGSL) {
-  // WGSL vertex_index store type is u32.
-  const auto assembly = Preamble() + FragMain() + R"(
+    // WGSL vertex_index store type is u32.
+    const auto assembly = Preamble() + FragMain() + R"(
      OpDecorate %1 BuiltIn VertexIndex
 )" + CommonTypes() + R"(
      %ptr_ty = OpTypePointer Input %uint
      %1 = OpVariable %ptr_ty Input
   )" + MainBody();
-  auto p = parser(test::Assemble(assembly));
+    auto p = parser(test::Assemble(assembly));
 
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  EXPECT_TRUE(p->error().empty());
-  const auto got = test::ToString(p->program());
-  const std::string expected = "var<private> x_1 : u32;";
-  EXPECT_THAT(got, HasSubstr(expected)) << got;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    EXPECT_TRUE(p->error().empty());
+    const auto got = test::ToString(p->program());
+    const std::string expected = "var<private> x_1 : u32;";
+    EXPECT_THAT(got, HasSubstr(expected)) << got;
 }
 
 TEST_F(SpvModuleScopeVarParserTest, Builtin_Input_OppositeSignednessAsWGSL) {
-  // WGSL vertex_index store type is u32.  Use i32 in SPIR-V.
-  const auto assembly = Preamble() + FragMain() + R"(
+    // WGSL vertex_index store type is u32.  Use i32 in SPIR-V.
+    const auto assembly = Preamble() + FragMain() + R"(
      OpDecorate %1 BuiltIn VertexIndex
 )" + CommonTypes() + R"(
      %ptr_ty = OpTypePointer Input %int
      %1 = OpVariable %ptr_ty Input
   )" + MainBody();
-  auto p = parser(test::Assemble(assembly));
+    auto p = parser(test::Assemble(assembly));
 
-  ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
-  EXPECT_TRUE(p->error().empty());
-  const auto got = test::ToString(p->program());
-  const std::string expected = "var<private> x_1 : i32;";
-  EXPECT_THAT(got, HasSubstr(expected)) << got;
+    ASSERT_TRUE(p->BuildAndParseInternalModuleExceptFunctions());
+    EXPECT_TRUE(p->error().empty());
+    const auto got = test::ToString(p->program());
+    const std::string expected = "var<private> x_1 : i32;";
+    EXPECT_THAT(got, HasSubstr(expected)) << got;
 }
 
 TEST_F(SpvModuleScopeVarParserTest, EntryPointWrapping_IOLocations) {
-  const auto assembly = CommonCapabilities() + R"(
+    const auto assembly = CommonCapabilities() + R"(
      OpEntryPoint Fragment %main "main" %1 %2 %3 %4
      OpExecutionMode %main OriginUpperLeft
      OpDecorate %1 Location 0
@@ -3603,7 +3514,7 @@
      OpDecorate %3 Location 30
      OpDecorate %4 Location 6
 )" + CommonTypes() +
-                        R"(
+                          R"(
      %ptr_in_uint = OpTypePointer Input %uint
      %ptr_out_uint = OpTypePointer Output %uint
      %1 = OpVariable %ptr_in_uint Input
@@ -3616,13 +3527,13 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
+    auto p = parser(test::Assemble(assembly));
 
-  ASSERT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  const auto got = test::ToString(p->program());
-  const std::string expected =
-      R"(var<private> x_1 : u32;
+    ASSERT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    const auto got = test::ToString(p->program());
+    const std::string expected =
+        R"(var<private> x_1 : u32;
 
 var<private> x_2 : u32;
 
@@ -3649,19 +3560,18 @@
   return main_out(x_2, x_4);
 }
 )";
-  EXPECT_THAT(got, HasSubstr(expected)) << got;
+    EXPECT_THAT(got, HasSubstr(expected)) << got;
 }
 
-TEST_F(SpvModuleScopeVarParserTest,
-       EntryPointWrapping_BuiltinVar_Input_SameSignedness) {
-  // instance_index is u32 in WGSL. Use uint in SPIR-V.
-  // No bitcasts are used for parameter formation or return value.
-  const auto assembly = CommonCapabilities() + R"(
+TEST_F(SpvModuleScopeVarParserTest, EntryPointWrapping_BuiltinVar_Input_SameSignedness) {
+    // instance_index is u32 in WGSL. Use uint in SPIR-V.
+    // No bitcasts are used for parameter formation or return value.
+    const auto assembly = CommonCapabilities() + R"(
      OpEntryPoint Vertex %main "main" %1 %position
      OpDecorate %position BuiltIn Position
      OpDecorate %1 BuiltIn InstanceIndex
 )" + CommonTypes() +
-                        R"(
+                          R"(
      %ptr_in_uint = OpTypePointer Input %uint
      %1 = OpVariable %ptr_in_uint Input
      %posty = OpTypePointer Output %v4float
@@ -3674,12 +3584,12 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
+    auto p = parser(test::Assemble(assembly));
 
-  ASSERT_TRUE(p->Parse()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto got = test::ToString(p->program());
-  const std::string expected = R"(var<private> x_1 : u32;
+    ASSERT_TRUE(p->Parse()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto got = test::ToString(p->program());
+    const std::string expected = R"(var<private> x_1 : u32;
 
 var<private> x_4 : vec4<f32>;
 
@@ -3700,18 +3610,17 @@
   return main_out(x_4);
 }
 )";
-  EXPECT_EQ(got, expected) << got;
+    EXPECT_EQ(got, expected) << got;
 }
 
-TEST_F(SpvModuleScopeVarParserTest,
-       EntryPointWrapping_BuiltinVar_Input_OppositeSignedness) {
-  // instance_index is u32 in WGSL. Use int in SPIR-V.
-  const auto assembly = CommonCapabilities() + R"(
+TEST_F(SpvModuleScopeVarParserTest, EntryPointWrapping_BuiltinVar_Input_OppositeSignedness) {
+    // instance_index is u32 in WGSL. Use int in SPIR-V.
+    const auto assembly = CommonCapabilities() + R"(
      OpEntryPoint Vertex %main "main" %position %1
      OpDecorate %position BuiltIn Position
      OpDecorate %1 BuiltIn InstanceIndex
 )" + CommonTypes() +
-                        R"(
+                          R"(
      %ptr_in_int = OpTypePointer Input %int
      %1 = OpVariable %ptr_in_int Input
      %posty = OpTypePointer Output %v4float
@@ -3724,12 +3633,12 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
+    auto p = parser(test::Assemble(assembly));
 
-  ASSERT_TRUE(p->Parse()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto got = test::ToString(p->program());
-  const std::string expected = R"(var<private> x_1 : i32;
+    ASSERT_TRUE(p->Parse()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto got = test::ToString(p->program());
+    const std::string expected = R"(var<private> x_1 : i32;
 
 var<private> x_4 : vec4<f32>;
 
@@ -3750,20 +3659,19 @@
   return main_out(x_4);
 }
 )";
-  EXPECT_EQ(got, expected) << got;
+    EXPECT_EQ(got, expected) << got;
 }
 
 // SampleMask is an array in Vulkan SPIR-V, but a scalar in WGSL.
-TEST_F(SpvModuleScopeVarParserTest,
-       EntryPointWrapping_BuiltinVar_SampleMask_In_Unsigned) {
-  // SampleMask is u32 in WGSL.
-  // Use unsigned array element in Vulkan.
-  const auto assembly = CommonCapabilities() + R"(
+TEST_F(SpvModuleScopeVarParserTest, EntryPointWrapping_BuiltinVar_SampleMask_In_Unsigned) {
+    // SampleMask is u32 in WGSL.
+    // Use unsigned array element in Vulkan.
+    const auto assembly = CommonCapabilities() + R"(
      OpEntryPoint Fragment %main "main" %1
      OpExecutionMode %main OriginUpperLeft
      OpDecorate %1 BuiltIn SampleMask
 )" + CommonTypes() +
-                        R"(
+                          R"(
      %arr = OpTypeArray %uint %uint_1
      %ptr_ty = OpTypePointer Input %arr
      %1 = OpVariable %ptr_ty Input
@@ -3773,12 +3681,12 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
+    auto p = parser(test::Assemble(assembly));
 
-  ASSERT_TRUE(p->Parse()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto got = test::ToString(p->program());
-  const std::string expected = R"(var<private> x_1 : array<u32, 1u>;
+    ASSERT_TRUE(p->Parse()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto got = test::ToString(p->program());
+    const std::string expected = R"(var<private> x_1 : array<u32, 1u>;
 
 fn main_1() {
   return;
@@ -3786,23 +3694,22 @@
 
 @stage(fragment)
 fn main(@builtin(sample_mask) x_1_param : u32) {
-  x_1[0] = x_1_param;
+  x_1[0i] = x_1_param;
   main_1();
 }
 )";
-  EXPECT_EQ(got, expected) << got;
+    EXPECT_EQ(got, expected) << got;
 }
 
-TEST_F(SpvModuleScopeVarParserTest,
-       EntryPointWrapping_BuiltinVar_SampleMask_In_Signed) {
-  // SampleMask is u32 in WGSL.
-  // Use signed array element in Vulkan.
-  const auto assembly = CommonCapabilities() + R"(
+TEST_F(SpvModuleScopeVarParserTest, EntryPointWrapping_BuiltinVar_SampleMask_In_Signed) {
+    // SampleMask is u32 in WGSL.
+    // Use signed array element in Vulkan.
+    const auto assembly = CommonCapabilities() + R"(
      OpEntryPoint Fragment %main "main" %1
      OpExecutionMode %main OriginUpperLeft
      OpDecorate %1 BuiltIn SampleMask
 )" + CommonTypes() +
-                        R"(
+                          R"(
      %arr = OpTypeArray %int %uint_1
      %ptr_ty = OpTypePointer Input %arr
      %1 = OpVariable %ptr_ty Input
@@ -3812,12 +3719,12 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
+    auto p = parser(test::Assemble(assembly));
 
-  ASSERT_TRUE(p->Parse()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto got = test::ToString(p->program());
-  const std::string expected = R"(var<private> x_1 : array<i32, 1u>;
+    ASSERT_TRUE(p->Parse()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto got = test::ToString(p->program());
+    const std::string expected = R"(var<private> x_1 : array<i32, 1u>;
 
 fn main_1() {
   return;
@@ -3825,23 +3732,23 @@
 
 @stage(fragment)
 fn main(@builtin(sample_mask) x_1_param : u32) {
-  x_1[0] = bitcast<i32>(x_1_param);
+  x_1[0i] = bitcast<i32>(x_1_param);
   main_1();
 }
 )";
-  EXPECT_EQ(got, expected) << got;
+    EXPECT_EQ(got, expected) << got;
 }
 
 TEST_F(SpvModuleScopeVarParserTest,
        EntryPointWrapping_BuiltinVar_SampleMask_Out_Unsigned_Initializer) {
-  // SampleMask is u32 in WGSL.
-  // Use unsigned array element in Vulkan.
-  const auto assembly = CommonCapabilities() + R"(
+    // SampleMask is u32 in WGSL.
+    // Use unsigned array element in Vulkan.
+    const auto assembly = CommonCapabilities() + R"(
      OpEntryPoint Fragment %main "main" %1
      OpExecutionMode %main OriginUpperLeft
      OpDecorate %1 BuiltIn SampleMask
 )" + CommonTypes() +
-                        R"(
+                          R"(
      %arr = OpTypeArray %uint %uint_1
      %ptr_ty = OpTypePointer Output %arr
      %zero = OpConstantNull %arr
@@ -3852,13 +3759,13 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
+    auto p = parser(test::Assemble(assembly));
 
-  ASSERT_TRUE(p->Parse()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto got = test::ToString(p->program());
-  const std::string expected =
-      R"(var<private> x_1 : array<u32, 1u> = array<u32, 1u>();
+    ASSERT_TRUE(p->Parse()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto got = test::ToString(p->program());
+    const std::string expected =
+        R"(var<private> x_1 : array<u32, 1u> = array<u32, 1u>();
 
 fn main_1() {
   return;
@@ -3872,22 +3779,22 @@
 @stage(fragment)
 fn main() -> main_out {
   main_1();
-  return main_out(x_1[0]);
+  return main_out(x_1[0i]);
 }
 )";
-  EXPECT_EQ(got, expected) << got;
+    EXPECT_EQ(got, expected) << got;
 }
 
 TEST_F(SpvModuleScopeVarParserTest,
        EntryPointWrapping_BuiltinVar_SampleMask_Out_Signed_Initializer) {
-  // SampleMask is u32 in WGSL.
-  // Use signed array element in Vulkan.
-  const auto assembly = CommonCapabilities() + R"(
+    // SampleMask is u32 in WGSL.
+    // Use signed array element in Vulkan.
+    const auto assembly = CommonCapabilities() + R"(
      OpEntryPoint Fragment %main "main" %1
      OpExecutionMode %main OriginUpperLeft
      OpDecorate %1 BuiltIn SampleMask
 )" + CommonTypes() +
-                        R"(
+                          R"(
      %arr = OpTypeArray %int %uint_1
      %ptr_ty = OpTypePointer Output %arr
      %zero = OpConstantNull %arr
@@ -3898,13 +3805,13 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
+    auto p = parser(test::Assemble(assembly));
 
-  ASSERT_TRUE(p->Parse()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto got = test::ToString(p->program());
-  const std::string expected =
-      R"(var<private> x_1 : array<i32, 1u> = array<i32, 1u>();
+    ASSERT_TRUE(p->Parse()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto got = test::ToString(p->program());
+    const std::string expected =
+        R"(var<private> x_1 : array<i32, 1u> = array<i32, 1u>();
 
 fn main_1() {
   return;
@@ -3918,23 +3825,22 @@
 @stage(fragment)
 fn main() -> main_out {
   main_1();
-  return main_out(bitcast<u32>(x_1[0]));
+  return main_out(bitcast<u32>(x_1[0i]));
 }
 )";
-  EXPECT_EQ(got, expected) << got;
+    EXPECT_EQ(got, expected) << got;
 }
 
-TEST_F(SpvModuleScopeVarParserTest,
-       EntryPointWrapping_BuiltinVar_FragDepth_Out_Initializer) {
-  // FragDepth does not require conversion, because it's f32.
-  // The member of the return type is just the identifier corresponding
-  // to the module-scope private variable.
-  const auto assembly = CommonCapabilities() + R"(
+TEST_F(SpvModuleScopeVarParserTest, EntryPointWrapping_BuiltinVar_FragDepth_Out_Initializer) {
+    // FragDepth does not require conversion, because it's f32.
+    // The member of the return type is just the identifier corresponding
+    // to the module-scope private variable.
+    const auto assembly = CommonCapabilities() + R"(
      OpEntryPoint Fragment %main "main" %1
      OpExecutionMode %main OriginUpperLeft
      OpDecorate %1 BuiltIn FragDepth
 )" + CommonTypes() +
-                        R"(
+                          R"(
      %ptr_ty = OpTypePointer Output %float
      %1 = OpVariable %ptr_ty Output %float_0
 
@@ -3943,12 +3849,12 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
+    auto p = parser(test::Assemble(assembly));
 
-  ASSERT_TRUE(p->Parse()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
-  const auto got = test::ToString(p->program());
-  const std::string expected = R"(var<private> x_1 : f32 = 0.0;
+    ASSERT_TRUE(p->Parse()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
+    const auto got = test::ToString(p->program());
+    const std::string expected = R"(var<private> x_1 : f32 = 0.0;
 
 fn main_1() {
   return;
@@ -3965,24 +3871,24 @@
   return main_out(x_1);
 }
 )";
-  EXPECT_EQ(got, expected) << got;
+    EXPECT_EQ(got, expected) << got;
 }
 
 TEST_F(SpvModuleScopeVarParserTest, BuiltinPosition_BuiltIn_Position) {
-  // In Vulkan SPIR-V, Position is the first member of gl_PerVertex
-  const std::string assembly = PerVertexPreamble() + R"(
+    // In Vulkan SPIR-V, Position is the first member of gl_PerVertex
+    const std::string assembly = PerVertexPreamble() + R"(
   %main = OpFunction %void None %voidfn
   %entry = OpLabel
   OpReturn
   OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
+    auto p = parser(test::Assemble(assembly));
 
-  ASSERT_TRUE(p->Parse()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
+    ASSERT_TRUE(p->Parse()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
 
-  const auto got = test::ToString(p->program());
-  const std::string expected = R"(var<private> gl_Position : vec4<f32>;
+    const auto got = test::ToString(p->program());
+    const std::string expected = R"(var<private> gl_Position : vec4<f32>;
 
 fn main_1() {
   return;
@@ -3999,12 +3905,11 @@
   return main_out(gl_Position);
 }
 )";
-  EXPECT_EQ(got, expected) << got;
+    EXPECT_EQ(got, expected) << got;
 }
 
-TEST_F(SpvModuleScopeVarParserTest,
-       BuiltinPosition_BuiltIn_Position_Initializer) {
-  const std::string assembly = R"(
+TEST_F(SpvModuleScopeVarParserTest, BuiltinPosition_BuiltIn_Position_Initializer) {
+    const std::string assembly = R"(
     OpCapability Shader
     OpMemoryModel Logical Simple
     OpEntryPoint Vertex %main "main" %1
@@ -4045,14 +3950,14 @@
     OpReturn
     OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
+    auto p = parser(test::Assemble(assembly));
 
-  ASSERT_TRUE(p->Parse()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
+    ASSERT_TRUE(p->Parse()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
 
-  const auto got = test::ToString(p->program());
-  const std::string expected =
-      R"(var<private> gl_Position : vec4<f32> = vec4<f32>(1.0, 2.0, 3.0, 4.0);
+    const auto got = test::ToString(p->program());
+    const std::string expected =
+        R"(var<private> gl_Position : vec4<f32> = vec4<f32>(1.0, 2.0, 3.0, 4.0);
 
 fn main_1() {
   return;
@@ -4069,11 +3974,11 @@
   return main_out(gl_Position);
 }
 )";
-  EXPECT_EQ(got, expected) << got;
+    EXPECT_EQ(got, expected) << got;
 }
 
 TEST_F(SpvModuleScopeVarParserTest, Input_FlattenArray_OneLevel) {
-  const std::string assembly = R"(
+    const std::string assembly = R"(
     OpCapability Shader
     OpMemoryModel Logical Simple
     OpEntryPoint Vertex %main "main" %1 %2
@@ -4101,13 +4006,13 @@
     OpReturn
     OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
+    auto p = parser(test::Assemble(assembly));
 
-  ASSERT_TRUE(p->Parse()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
+    ASSERT_TRUE(p->Parse()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
 
-  const auto got = test::ToString(p->program());
-  const std::string expected = R"(var<private> x_1 : array<f32, 3u>;
+    const auto got = test::ToString(p->program());
+    const std::string expected = R"(var<private> x_1 : array<f32, 3u>;
 
 var<private> x_2 : vec4<f32>;
 
@@ -4122,18 +4027,18 @@
 
 @stage(vertex)
 fn main(@location(4) x_1_param : f32, @location(5) x_1_param_1 : f32, @location(6) x_1_param_2 : f32) -> main_out {
-  x_1[0] = x_1_param;
-  x_1[1] = x_1_param_1;
-  x_1[2] = x_1_param_2;
+  x_1[0i] = x_1_param;
+  x_1[1i] = x_1_param_1;
+  x_1[2i] = x_1_param_2;
   main_1();
   return main_out(x_2);
 }
 )";
-  EXPECT_EQ(got, expected) << got;
+    EXPECT_EQ(got, expected) << got;
 }
 
 TEST_F(SpvModuleScopeVarParserTest, Input_FlattenMatrix) {
-  const std::string assembly = R"(
+    const std::string assembly = R"(
     OpCapability Shader
     OpMemoryModel Logical Simple
     OpEntryPoint Vertex %main "main" %1 %2
@@ -4159,13 +4064,13 @@
     OpReturn
     OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
+    auto p = parser(test::Assemble(assembly));
 
-  ASSERT_TRUE(p->Parse()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
+    ASSERT_TRUE(p->Parse()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
 
-  const auto got = test::ToString(p->program());
-  const std::string expected = R"(var<private> x_1 : mat2x4<f32>;
+    const auto got = test::ToString(p->program());
+    const std::string expected = R"(var<private> x_1 : mat2x4<f32>;
 
 var<private> x_2 : vec4<f32>;
 
@@ -4180,17 +4085,17 @@
 
 @stage(vertex)
 fn main(@location(9) x_1_param : vec4<f32>, @location(10) x_1_param_1 : vec4<f32>) -> main_out {
-  x_1[0] = x_1_param;
-  x_1[1] = x_1_param_1;
+  x_1[0i] = x_1_param;
+  x_1[1i] = x_1_param_1;
   main_1();
   return main_out(x_2);
 }
 )";
-  EXPECT_EQ(got, expected) << got;
+    EXPECT_EQ(got, expected) << got;
 }
 
 TEST_F(SpvModuleScopeVarParserTest, Input_FlattenStruct_LocOnVariable) {
-  const std::string assembly = R"(
+    const std::string assembly = R"(
     OpCapability Shader
     OpMemoryModel Logical Simple
     OpEntryPoint Vertex %main "main" %1 %2
@@ -4221,13 +4126,13 @@
     OpReturn
     OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
+    auto p = parser(test::Assemble(assembly));
 
-  ASSERT_TRUE(p->Parse()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
+    ASSERT_TRUE(p->Parse()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
 
-  const auto got = test::ToString(p->program());
-  const std::string expected = R"(struct Communicators {
+    const auto got = test::ToString(p->program());
+    const std::string expected = R"(struct Communicators {
   alice : f32,
   bob : vec4<f32>,
 }
@@ -4253,11 +4158,11 @@
   return main_out(x_2);
 }
 )";
-  EXPECT_EQ(got, expected) << got;
+    EXPECT_EQ(got, expected) << got;
 }
 
 TEST_F(SpvModuleScopeVarParserTest, Input_FlattenNested) {
-  const std::string assembly = R"(
+    const std::string assembly = R"(
     OpCapability Shader
     OpMemoryModel Logical Simple
     OpEntryPoint Vertex %main "main" %1 %2
@@ -4285,13 +4190,13 @@
     OpReturn
     OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
+    auto p = parser(test::Assemble(assembly));
 
-  ASSERT_TRUE(p->Parse()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
+    ASSERT_TRUE(p->Parse()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
 
-  const auto got = test::ToString(p->program());
-  const std::string expected = R"(var<private> x_1 : array<mat2x4<f32>, 2u>;
+    const auto got = test::ToString(p->program());
+    const std::string expected = R"(var<private> x_1 : array<mat2x4<f32>, 2u>;
 
 var<private> x_2 : vec4<f32>;
 
@@ -4306,19 +4211,19 @@
 
 @stage(vertex)
 fn main(@location(7) x_1_param : vec4<f32>, @location(8) x_1_param_1 : vec4<f32>, @location(9) x_1_param_2 : vec4<f32>, @location(10) x_1_param_3 : vec4<f32>) -> main_out {
-  x_1[0][0] = x_1_param;
-  x_1[0][1] = x_1_param_1;
-  x_1[1][0] = x_1_param_2;
-  x_1[1][1] = x_1_param_3;
+  x_1[0i][0i] = x_1_param;
+  x_1[0i][1i] = x_1_param_1;
+  x_1[1i][0i] = x_1_param_2;
+  x_1[1i][1i] = x_1_param_3;
   main_1();
   return main_out(x_2);
 }
 )";
-  EXPECT_EQ(got, expected) << got;
+    EXPECT_EQ(got, expected) << got;
 }
 
 TEST_F(SpvModuleScopeVarParserTest, Output_FlattenArray_OneLevel) {
-  const std::string assembly = R"(
+    const std::string assembly = R"(
     OpCapability Shader
     OpMemoryModel Logical Simple
     OpEntryPoint Vertex %main "main" %1 %2
@@ -4346,13 +4251,13 @@
     OpReturn
     OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
+    auto p = parser(test::Assemble(assembly));
 
-  ASSERT_TRUE(p->Parse()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
+    ASSERT_TRUE(p->Parse()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
 
-  const auto got = test::ToString(p->program());
-  const std::string expected = R"(var<private> x_1 : array<f32, 3u>;
+    const auto got = test::ToString(p->program());
+    const std::string expected = R"(var<private> x_1 : array<f32, 3u>;
 
 var<private> x_2 : vec4<f32>;
 
@@ -4374,14 +4279,14 @@
 @stage(vertex)
 fn main() -> main_out {
   main_1();
-  return main_out(x_1[0], x_1[1], x_1[2], x_2);
+  return main_out(x_1[0i], x_1[1i], x_1[2i], x_2);
 }
 )";
-  EXPECT_EQ(got, expected) << got;
+    EXPECT_EQ(got, expected) << got;
 }
 
 TEST_F(SpvModuleScopeVarParserTest, Output_FlattenMatrix) {
-  const std::string assembly = R"(
+    const std::string assembly = R"(
     OpCapability Shader
     OpMemoryModel Logical Simple
     OpEntryPoint Vertex %main "main" %1 %2
@@ -4407,13 +4312,13 @@
     OpReturn
     OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
+    auto p = parser(test::Assemble(assembly));
 
-  ASSERT_TRUE(p->Parse()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
+    ASSERT_TRUE(p->Parse()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
 
-  const auto got = test::ToString(p->program());
-  const std::string expected = R"(var<private> x_1 : mat2x4<f32>;
+    const auto got = test::ToString(p->program());
+    const std::string expected = R"(var<private> x_1 : mat2x4<f32>;
 
 var<private> x_2 : vec4<f32>;
 
@@ -4433,14 +4338,14 @@
 @stage(vertex)
 fn main() -> main_out {
   main_1();
-  return main_out(x_1[0], x_1[1], x_2);
+  return main_out(x_1[0i], x_1[1i], x_2);
 }
 )";
-  EXPECT_EQ(got, expected) << got;
+    EXPECT_EQ(got, expected) << got;
 }
 
 TEST_F(SpvModuleScopeVarParserTest, Output_FlattenStruct_LocOnVariable) {
-  const std::string assembly = R"(
+    const std::string assembly = R"(
     OpCapability Shader
     OpMemoryModel Logical Simple
     OpEntryPoint Vertex %main "main" %1 %2
@@ -4471,13 +4376,13 @@
     OpReturn
     OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
+    auto p = parser(test::Assemble(assembly));
 
-  ASSERT_TRUE(p->Parse()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
+    ASSERT_TRUE(p->Parse()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
 
-  const auto got = test::ToString(p->program());
-  const std::string expected = R"(struct Communicators {
+    const auto got = test::ToString(p->program());
+    const std::string expected = R"(struct Communicators {
   alice : f32,
   bob : vec4<f32>,
 }
@@ -4505,12 +4410,12 @@
   return main_out(x_1.alice, x_1.bob, x_2);
 }
 )";
-  EXPECT_EQ(got, expected) << got;
+    EXPECT_EQ(got, expected) << got;
 }
 
 TEST_F(SpvModuleScopeVarParserTest, FlattenStruct_LocOnMembers) {
-  // Block-decorated struct may have its members decorated with Location.
-  const std::string assembly = R"(
+    // Block-decorated struct may have its members decorated with Location.
+    const std::string assembly = R"(
     OpCapability Shader
     OpMemoryModel Logical Simple
     OpEntryPoint Vertex %main "main" %1 %2 %3
@@ -4544,13 +4449,13 @@
     OpReturn
     OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
+    auto p = parser(test::Assemble(assembly));
 
-  ASSERT_TRUE(p->Parse()) << p->error() << assembly;
-  EXPECT_TRUE(p->error().empty());
+    ASSERT_TRUE(p->Parse()) << p->error() << assembly;
+    EXPECT_TRUE(p->error().empty());
 
-  const auto got = test::ToString(p->program());
-  const std::string expected = R"(struct Communicators {
+    const auto got = test::ToString(p->program());
+    const std::string expected = R"(struct Communicators {
   alice : f32,
   bob : vec4<f32>,
 }
@@ -4582,12 +4487,11 @@
   return main_out(x_2, x_3.alice, x_3.bob);
 }
 )";
-  EXPECT_EQ(got, expected) << got;
+    EXPECT_EQ(got, expected) << got;
 }
 
-TEST_F(SpvModuleScopeVarParserTest,
-       EntryPointWrapping_Interpolation_Flat_Vertex_In) {
-  const auto assembly = CommonCapabilities() + R"(
+TEST_F(SpvModuleScopeVarParserTest, EntryPointWrapping_Interpolation_Flat_Vertex_In) {
+    const auto assembly = CommonCapabilities() + R"(
      OpEntryPoint Vertex %main "main" %1 %2 %3 %4 %5 %6 %10
      OpDecorate %1 Location 1
      OpDecorate %2 Location 2
@@ -4603,7 +4507,7 @@
      OpDecorate %6 Flat
      OpDecorate %10 BuiltIn Position
 )" + CommonTypes() +
-                        R"(
+                          R"(
      %ptr_in_uint = OpTypePointer Input %uint
      %ptr_in_v2uint = OpTypePointer Input %v2uint
      %ptr_in_int = OpTypePointer Input %int
@@ -4625,13 +4529,13 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
+    auto p = parser(test::Assemble(assembly));
 
-  ASSERT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  const auto got = test::ToString(p->program());
-  const std::string expected =
-      R"(var<private> x_1 : u32;
+    ASSERT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    const auto got = test::ToString(p->program());
+    const std::string expected =
+        R"(var<private> x_1 : u32;
 
 var<private> x_2 : vec2<u32>;
 
@@ -4666,12 +4570,11 @@
   return main_out(x_10);
 }
 )";
-  EXPECT_EQ(got, expected) << got;
+    EXPECT_EQ(got, expected) << got;
 }
 
-TEST_F(SpvModuleScopeVarParserTest,
-       EntryPointWrapping_Interpolation_Flat_Vertex_Output) {
-  const auto assembly = CommonCapabilities() + R"(
+TEST_F(SpvModuleScopeVarParserTest, EntryPointWrapping_Interpolation_Flat_Vertex_Output) {
+    const auto assembly = CommonCapabilities() + R"(
      OpEntryPoint Vertex %main "main" %1 %2 %3 %4 %5 %6 %10
      OpDecorate %1 Location 1
      OpDecorate %2 Location 2
@@ -4687,7 +4590,7 @@
      OpDecorate %6 Flat
      OpDecorate %10 BuiltIn Position
 )" + CommonTypes() +
-                        R"(
+                          R"(
      %ptr_out_uint = OpTypePointer Output %uint
      %ptr_out_v2uint = OpTypePointer Output %v2uint
      %ptr_out_int = OpTypePointer Output %int
@@ -4709,13 +4612,13 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
+    auto p = parser(test::Assemble(assembly));
 
-  ASSERT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  const auto got = test::ToString(p->program());
-  const std::string expected =
-      R"(var<private> x_1 : u32;
+    ASSERT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    const auto got = test::ToString(p->program());
+    const std::string expected =
+        R"(var<private> x_1 : u32;
 
 var<private> x_2 : vec2<u32>;
 
@@ -4756,12 +4659,11 @@
   return main_out(x_1, x_2, x_3, x_4, x_5, x_6, x_10);
 }
 )";
-  EXPECT_EQ(got, expected) << got;
+    EXPECT_EQ(got, expected) << got;
 }
 
-TEST_F(SpvModuleScopeVarParserTest,
-       EntryPointWrapping_Flatten_Interpolation_Flat_Fragment_In) {
-  const auto assembly = CommonCapabilities() + R"(
+TEST_F(SpvModuleScopeVarParserTest, EntryPointWrapping_Flatten_Interpolation_Flat_Fragment_In) {
+    const auto assembly = CommonCapabilities() + R"(
      OpEntryPoint Fragment %main "main" %1 %2
      OpExecutionMode %main OriginUpperLeft
      OpDecorate %1 Location 1
@@ -4769,7 +4671,7 @@
      OpDecorate %1 Flat
      OpDecorate %2 Flat
 )" + CommonTypes() +
-                        R"(
+                          R"(
      %arr = OpTypeArray %float %uint_2
      %strct = OpTypeStruct %float %float
      %ptr_in_arr = OpTypePointer Input %arr
@@ -4782,13 +4684,13 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
+    auto p = parser(test::Assemble(assembly));
 
-  ASSERT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  const auto got = test::ToString(p->program());
-  const std::string expected =
-      R"(struct S {
+    ASSERT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    const auto got = test::ToString(p->program());
+    const std::string expected =
+        R"(struct S {
   field0 : f32,
   field1 : f32,
 }
@@ -4803,19 +4705,18 @@
 
 @stage(fragment)
 fn main(@location(1) @interpolate(flat) x_1_param : f32, @location(2) @interpolate(flat) x_1_param_1 : f32, @location(5) @interpolate(flat) x_2_param : f32, @location(6) @interpolate(flat) x_2_param_1 : f32) {
-  x_1[0] = x_1_param;
-  x_1[1] = x_1_param_1;
+  x_1[0i] = x_1_param;
+  x_1[1i] = x_1_param_1;
   x_2.field0 = x_2_param;
   x_2.field1 = x_2_param_1;
   main_1();
 }
 )";
-  EXPECT_EQ(got, expected) << got;
+    EXPECT_EQ(got, expected) << got;
 }
 
-TEST_F(SpvModuleScopeVarParserTest,
-       EntryPointWrapping_Interpolation_Floating_Fragment_In) {
-  const auto assembly = CommonCapabilities() + R"(
+TEST_F(SpvModuleScopeVarParserTest, EntryPointWrapping_Interpolation_Floating_Fragment_In) {
+    const auto assembly = CommonCapabilities() + R"(
      OpEntryPoint Fragment %main "main" %1 %2 %3 %4 %5 %6
      OpExecutionMode %main OriginUpperLeft
      OpDecorate %1 Location 1
@@ -4840,7 +4741,7 @@
      OpDecorate %6 Sample
 
 )" + CommonTypes() +
-                        R"(
+                          R"(
      %ptr_in_float = OpTypePointer Input %float
      %1 = OpVariable %ptr_in_float Input
      %2 = OpVariable %ptr_in_float Input
@@ -4854,13 +4755,13 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
+    auto p = parser(test::Assemble(assembly));
 
-  ASSERT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  const auto got = test::ToString(p->program());
-  const std::string expected =
-      R"(var<private> x_1 : f32;
+    ASSERT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    const auto got = test::ToString(p->program());
+    const std::string expected =
+        R"(var<private> x_1 : f32;
 
 var<private> x_2 : f32;
 
@@ -4887,12 +4788,11 @@
   main_1();
 }
 )";
-  EXPECT_EQ(got, expected) << got;
+    EXPECT_EQ(got, expected) << got;
 }
 
-TEST_F(SpvModuleScopeVarParserTest,
-       EntryPointWrapping_Flatten_Interpolation_Floating_Fragment_In) {
-  const auto assembly = CommonCapabilities() + R"(
+TEST_F(SpvModuleScopeVarParserTest, EntryPointWrapping_Flatten_Interpolation_Floating_Fragment_In) {
+    const auto assembly = CommonCapabilities() + R"(
      OpEntryPoint Fragment %main "main" %1
      OpExecutionMode %main OriginUpperLeft
      OpDecorate %1 Location 1
@@ -4912,7 +4812,7 @@
      OpMemberDecorate %10 5 Sample
 
 )" + CommonTypes() +
-                        R"(
+                          R"(
 
      %10 = OpTypeStruct %float %float %float %float %float %float
      %ptr_in_strct = OpTypePointer Input %10
@@ -4923,13 +4823,13 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
+    auto p = parser(test::Assemble(assembly));
 
-  ASSERT_TRUE(p->BuildAndParseInternalModule()) << assembly << p->error();
-  EXPECT_TRUE(p->error().empty());
-  const auto got = test::ToString(p->program());
-  const std::string expected =
-      R"(struct S {
+    ASSERT_TRUE(p->BuildAndParseInternalModule()) << assembly << p->error();
+    EXPECT_TRUE(p->error().empty());
+    const auto got = test::ToString(p->program());
+    const std::string expected =
+        R"(struct S {
   field0 : f32,
   field1 : f32,
   field2 : f32,
@@ -4955,12 +4855,11 @@
   main_1();
 }
 )";
-  EXPECT_EQ(got, expected) << got;
+    EXPECT_EQ(got, expected) << got;
 }
 
-TEST_F(SpvModuleScopeVarParserTest,
-       EntryPointWrapping_Interpolation_Floating_Fragment_Out) {
-  const auto assembly = CommonCapabilities() + R"(
+TEST_F(SpvModuleScopeVarParserTest, EntryPointWrapping_Interpolation_Floating_Fragment_Out) {
+    const auto assembly = CommonCapabilities() + R"(
      OpEntryPoint Fragment %main "main" %1 %2 %3 %4 %5 %6
      OpExecutionMode %main OriginUpperLeft
      OpDecorate %1 Location 1
@@ -4985,7 +4884,7 @@
      OpDecorate %6 Sample
 
 )" + CommonTypes() +
-                        R"(
+                          R"(
      %ptr_out_float = OpTypePointer Output %float
      %1 = OpVariable %ptr_out_float Output
      %2 = OpVariable %ptr_out_float Output
@@ -4999,13 +4898,13 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
+    auto p = parser(test::Assemble(assembly));
 
-  ASSERT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  const auto got = test::ToString(p->program());
-  const std::string expected =
-      R"(var<private> x_1 : f32;
+    ASSERT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    const auto got = test::ToString(p->program());
+    const std::string expected =
+        R"(var<private> x_1 : f32;
 
 var<private> x_2 : f32;
 
@@ -5042,12 +4941,12 @@
   return main_out(x_1, x_2, x_3, x_4, x_5, x_6);
 }
 )";
-  EXPECT_EQ(got, expected) << got;
+    EXPECT_EQ(got, expected) << got;
 }
 
 TEST_F(SpvModuleScopeVarParserTest,
        EntryPointWrapping_Flatten_Interpolation_Floating_Fragment_Out) {
-  const auto assembly = CommonCapabilities() + R"(
+    const auto assembly = CommonCapabilities() + R"(
      OpEntryPoint Fragment %main "main" %1
      OpExecutionMode %main OriginUpperLeft
 
@@ -5068,7 +4967,7 @@
      OpMemberDecorate %10 5 Sample
 
 )" + CommonTypes() +
-                        R"(
+                          R"(
 
      %10 = OpTypeStruct %float %float %float %float %float %float
      %ptr_in_strct = OpTypePointer Output %10
@@ -5079,13 +4978,13 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
+    auto p = parser(test::Assemble(assembly));
 
-  ASSERT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  const auto got = test::ToString(p->program());
-  const std::string expected =
-      R"(struct S {
+    ASSERT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    const auto got = test::ToString(p->program());
+    const std::string expected =
+        R"(struct S {
   field0 : f32,
   field1 : f32,
   field2 : f32,
@@ -5121,15 +5020,14 @@
   return main_out(x_1.field0, x_1.field1, x_1.field2, x_1.field3, x_1.field4, x_1.field5);
 }
 )";
-  EXPECT_EQ(got, expected) << got;
+    EXPECT_EQ(got, expected) << got;
 }
 
-TEST_F(SpvModuleScopeVarParserTest,
-       EntryPointWrapping_Interpolation_Default_Vertex_Output) {
-  // Integral types default to @interpolate(flat).
-  // Floating types default to @interpolate(perspective, center), which is the
-  // same as WGSL and therefore dropped.
-  const auto assembly = CommonCapabilities() + R"(
+TEST_F(SpvModuleScopeVarParserTest, EntryPointWrapping_Interpolation_Default_Vertex_Output) {
+    // Integral types default to @interpolate(flat).
+    // Floating types default to @interpolate(perspective, center), which is the
+    // same as WGSL and therefore dropped.
+    const auto assembly = CommonCapabilities() + R"(
      OpEntryPoint Vertex %main "main" %1 %2 %3 %4 %5 %6 %10
      OpDecorate %1 Location 1
      OpDecorate %2 Location 2
@@ -5139,7 +5037,7 @@
      OpDecorate %6 Location 6
      OpDecorate %10 BuiltIn Position
 )" + CommonTypes() +
-                        R"(
+                          R"(
      %ptr_out_uint = OpTypePointer Output %uint
      %ptr_out_v2uint = OpTypePointer Output %v2uint
      %ptr_out_int = OpTypePointer Output %int
@@ -5161,13 +5059,13 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
+    auto p = parser(test::Assemble(assembly));
 
-  ASSERT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  const auto got = test::ToString(p->program());
-  const std::string expected =
-      R"(var<private> x_1 : u32;
+    ASSERT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    const auto got = test::ToString(p->program());
+    const std::string expected =
+        R"(var<private> x_1 : u32;
 
 var<private> x_2 : vec2<u32>;
 
@@ -5208,15 +5106,14 @@
   return main_out(x_1, x_2, x_3, x_4, x_5, x_6, x_10);
 }
 )";
-  EXPECT_EQ(got, expected) << got;
+    EXPECT_EQ(got, expected) << got;
 }
 
-TEST_F(SpvModuleScopeVarParserTest,
-       EntryPointWrapping_Interpolation_Default_Fragment_In) {
-  // Integral types default to @interpolate(flat).
-  // Floating types default to @interpolate(perspective, center), which is the
-  // same as WGSL and therefore dropped.
-  const auto assembly = CommonCapabilities() + R"(
+TEST_F(SpvModuleScopeVarParserTest, EntryPointWrapping_Interpolation_Default_Fragment_In) {
+    // Integral types default to @interpolate(flat).
+    // Floating types default to @interpolate(perspective, center), which is the
+    // same as WGSL and therefore dropped.
+    const auto assembly = CommonCapabilities() + R"(
      OpEntryPoint Fragment %main "main" %1 %2 %3 %4 %5 %6
      OpDecorate %1 Location 1
      OpDecorate %2 Location 2
@@ -5225,7 +5122,7 @@
      OpDecorate %5 Location 5
      OpDecorate %6 Location 6
 )" + CommonTypes() +
-                        R"(
+                          R"(
      %ptr_in_uint = OpTypePointer Input %uint
      %ptr_in_v2uint = OpTypePointer Input %v2uint
      %ptr_in_int = OpTypePointer Input %int
@@ -5244,13 +5141,13 @@
      OpReturn
      OpFunctionEnd
   )";
-  auto p = parser(test::Assemble(assembly));
+    auto p = parser(test::Assemble(assembly));
 
-  ASSERT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_TRUE(p->error().empty());
-  const auto got = test::ToString(p->program());
-  const std::string expected =
-      R"(var<private> x_1 : u32;
+    ASSERT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_TRUE(p->error().empty());
+    const auto got = test::ToString(p->program());
+    const std::string expected =
+        R"(var<private> x_1 : u32;
 
 var<private> x_2 : vec2<u32>;
 
@@ -5277,7 +5174,7 @@
   main_1();
 }
 )";
-  EXPECT_EQ(got, expected) << got;
+    EXPECT_EQ(got, expected) << got;
 }
 
 }  // namespace
diff --git a/src/tint/reader/spirv/parser_impl_named_types_test.cc b/src/tint/reader/spirv/parser_impl_named_types_test.cc
index 53366e6..3fb07a4 100644
--- a/src/tint/reader/spirv/parser_impl_named_types_test.cc
+++ b/src/tint/reader/spirv/parser_impl_named_types_test.cc
@@ -22,36 +22,36 @@
 using ::testing::HasSubstr;
 
 TEST_F(SpvParserTest, NamedTypes_AnonStruct) {
-  auto p = parser(test::Assemble(R"(
+    auto p = parser(test::Assemble(R"(
     %uint = OpTypeInt 32 0
     %s = OpTypeStruct %uint %uint
   )"));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_THAT(test::ToString(p->program()), HasSubstr("struct S"));
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_THAT(test::ToString(p->program()), HasSubstr("struct S"));
 
-  p->DeliberatelyInvalidSpirv();
+    p->DeliberatelyInvalidSpirv();
 }
 
 TEST_F(SpvParserTest, NamedTypes_NamedStruct) {
-  auto p = parser(test::Assemble(R"(
+    auto p = parser(test::Assemble(R"(
     OpName %s "mystruct"
     %uint = OpTypeInt 32 0
     %s = OpTypeStruct %uint %uint
   )"));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_THAT(test::ToString(p->program()), HasSubstr("struct mystruct"));
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_THAT(test::ToString(p->program()), HasSubstr("struct mystruct"));
 
-  p->DeliberatelyInvalidSpirv();
+    p->DeliberatelyInvalidSpirv();
 }
 
 TEST_F(SpvParserTest, NamedTypes_Dup_EmitBoth) {
-  auto p = parser(test::Assemble(R"(
+    auto p = parser(test::Assemble(R"(
     %uint = OpTypeInt 32 0
     %s = OpTypeStruct %uint %uint
     %s2 = OpTypeStruct %uint %uint
   )"));
-  EXPECT_TRUE(p->BuildAndParseInternalModule()) << p->error();
-  EXPECT_THAT(test::ToString(p->program()), HasSubstr(R"(struct S {
+    EXPECT_TRUE(p->BuildAndParseInternalModule()) << p->error();
+    EXPECT_THAT(test::ToString(p->program()), HasSubstr(R"(struct S {
   field0 : u32,
   field1 : u32,
 }
@@ -61,60 +61,57 @@
   field1 : u32,
 })"));
 
-  p->DeliberatelyInvalidSpirv();
+    p->DeliberatelyInvalidSpirv();
 }
 
 // TODO(dneto): Should we make an alias for an un-decoratrd array with
 // an OpName?
 
 TEST_F(SpvParserTest, NamedTypes_AnonRTArrayWithDecoration) {
-  // Runtime arrays are always in SSBO, and those are always laid out.
-  auto p = parser(test::Assemble(R"(
+    // Runtime arrays are always in SSBO, and those are always laid out.
+    auto p = parser(test::Assemble(R"(
     OpDecorate %arr ArrayStride 8
     %uint = OpTypeInt 32 0
     %arr = OpTypeRuntimeArray %uint
   )"));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_THAT(test::ToString(p->program()),
-              HasSubstr("RTArr = @stride(8) array<u32>;\n"));
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_THAT(test::ToString(p->program()), HasSubstr("RTArr = @stride(8) array<u32>;\n"));
 
-  p->DeliberatelyInvalidSpirv();
+    p->DeliberatelyInvalidSpirv();
 }
 
 TEST_F(SpvParserTest, NamedTypes_AnonRTArray_Dup_EmitBoth) {
-  auto p = parser(test::Assemble(R"(
+    auto p = parser(test::Assemble(R"(
     OpDecorate %arr ArrayStride 8
     OpDecorate %arr2 ArrayStride 8
     %uint = OpTypeInt 32 0
     %arr = OpTypeRuntimeArray %uint
     %arr2 = OpTypeRuntimeArray %uint
   )"));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_THAT(test::ToString(p->program()),
-              HasSubstr(R"(type RTArr = @stride(8) array<u32>;
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_THAT(test::ToString(p->program()), HasSubstr(R"(type RTArr = @stride(8) array<u32>;
 
 type RTArr_1 = @stride(8) array<u32>;
 )"));
 
-  p->DeliberatelyInvalidSpirv();
+    p->DeliberatelyInvalidSpirv();
 }
 
 TEST_F(SpvParserTest, NamedTypes_NamedRTArray) {
-  auto p = parser(test::Assemble(R"(
+    auto p = parser(test::Assemble(R"(
     OpName %arr "myrtarr"
     OpDecorate %arr ArrayStride 8
     %uint = OpTypeInt 32 0
     %arr = OpTypeRuntimeArray %uint
   )"));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_THAT(test::ToString(p->program()),
-              HasSubstr("myrtarr = @stride(8) array<u32>;\n"));
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_THAT(test::ToString(p->program()), HasSubstr("myrtarr = @stride(8) array<u32>;\n"));
 
-  p->DeliberatelyInvalidSpirv();
+    p->DeliberatelyInvalidSpirv();
 }
 
 TEST_F(SpvParserTest, NamedTypes_NamedArray) {
-  auto p = parser(test::Assemble(R"(
+    auto p = parser(test::Assemble(R"(
     OpName %arr "myarr"
     OpDecorate %arr ArrayStride 8
     %uint = OpTypeInt 32 0
@@ -122,15 +119,14 @@
     %arr = OpTypeArray %uint %uint_5
     %arr2 = OpTypeArray %uint %uint_5
   )"));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_THAT(test::ToString(p->program()),
-              HasSubstr("myarr = @stride(8) array<u32, 5u>;"));
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_THAT(test::ToString(p->program()), HasSubstr("myarr = @stride(8) array<u32, 5u>;"));
 
-  p->DeliberatelyInvalidSpirv();
+    p->DeliberatelyInvalidSpirv();
 }
 
 TEST_F(SpvParserTest, NamedTypes_AnonArray_Dup_EmitBoth) {
-  auto p = parser(test::Assemble(R"(
+    auto p = parser(test::Assemble(R"(
     OpDecorate %arr ArrayStride 8
     OpDecorate %arr2 ArrayStride 8
     %uint = OpTypeInt 32 0
@@ -138,14 +134,13 @@
     %arr = OpTypeArray %uint %uint_5
     %arr2 = OpTypeArray %uint %uint_5
   )"));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_THAT(test::ToString(p->program()),
-              HasSubstr(R"(type Arr = @stride(8) array<u32, 5u>;
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_THAT(test::ToString(p->program()), HasSubstr(R"(type Arr = @stride(8) array<u32, 5u>;
 
 type Arr_1 = @stride(8) array<u32, 5u>;
 )"));
 
-  p->DeliberatelyInvalidSpirv();
+    p->DeliberatelyInvalidSpirv();
 }
 
 // TODO(dneto): Handle arrays sized by a spec constant.
diff --git a/src/tint/reader/spirv/parser_impl_test.cc b/src/tint/reader/spirv/parser_impl_test.cc
index 237bb67..42c0098 100644
--- a/src/tint/reader/spirv/parser_impl_test.cc
+++ b/src/tint/reader/spirv/parser_impl_test.cc
@@ -22,24 +22,22 @@
 using ::testing::HasSubstr;
 
 TEST_F(SpvParserTest, Impl_Uint32VecEmpty) {
-  std::vector<uint32_t> data;
-  auto p = parser(data);
-  EXPECT_FALSE(p->Parse());
-  // TODO(dneto): What message?
+    std::vector<uint32_t> data;
+    auto p = parser(data);
+    EXPECT_FALSE(p->Parse());
+    // TODO(dneto): What message?
 }
 
 TEST_F(SpvParserTest, Impl_InvalidModuleFails) {
-  auto invalid_spv = test::Assemble("%ty = OpTypeInt 3 0");
-  auto p = parser(invalid_spv);
-  EXPECT_FALSE(p->Parse());
-  EXPECT_THAT(
-      p->error(),
-      HasSubstr("TypeInt cannot appear before the memory model instruction"));
-  EXPECT_THAT(p->error(), HasSubstr("OpTypeInt 3 0"));
+    auto invalid_spv = test::Assemble("%ty = OpTypeInt 3 0");
+    auto p = parser(invalid_spv);
+    EXPECT_FALSE(p->Parse());
+    EXPECT_THAT(p->error(), HasSubstr("TypeInt cannot appear before the memory model instruction"));
+    EXPECT_THAT(p->error(), HasSubstr("OpTypeInt 3 0"));
 }
 
 TEST_F(SpvParserTest, Impl_GenericVulkanShader_SimpleMemoryModel) {
-  auto spv = test::Assemble(R"(
+    auto spv = test::Assemble(R"(
   OpCapability Shader
   OpMemoryModel Logical Simple
   OpEntryPoint GLCompute %main "main"
@@ -51,13 +49,13 @@
   OpReturn
   OpFunctionEnd
 )");
-  auto p = parser(spv);
-  EXPECT_TRUE(p->Parse());
-  EXPECT_TRUE(p->error().empty());
+    auto p = parser(spv);
+    EXPECT_TRUE(p->Parse());
+    EXPECT_TRUE(p->error().empty());
 }
 
 TEST_F(SpvParserTest, Impl_GenericVulkanShader_GLSL450MemoryModel) {
-  auto spv = test::Assemble(R"(
+    auto spv = test::Assemble(R"(
   OpCapability Shader
   OpMemoryModel Logical GLSL450
   OpEntryPoint GLCompute %main "main"
@@ -69,13 +67,13 @@
   OpReturn
   OpFunctionEnd
 )");
-  auto p = parser(spv);
-  EXPECT_TRUE(p->Parse());
-  EXPECT_TRUE(p->error().empty());
+    auto p = parser(spv);
+    EXPECT_TRUE(p->Parse());
+    EXPECT_TRUE(p->error().empty());
 }
 
 TEST_F(SpvParserTest, Impl_GenericVulkanShader_VulkanMemoryModel) {
-  auto spv = test::Assemble(R"(
+    auto spv = test::Assemble(R"(
   OpCapability Shader
   OpCapability VulkanMemoryModelKHR
   OpExtension "SPV_KHR_vulkan_memory_model"
@@ -89,13 +87,13 @@
   OpReturn
   OpFunctionEnd
 )");
-  auto p = parser(spv);
-  EXPECT_TRUE(p->Parse());
-  EXPECT_TRUE(p->error().empty());
+    auto p = parser(spv);
+    EXPECT_TRUE(p->Parse());
+    EXPECT_TRUE(p->error().empty());
 }
 
 TEST_F(SpvParserTest, Impl_OpenCLKernel_Fails) {
-  auto spv = test::Assemble(R"(
+    auto spv = test::Assemble(R"(
   OpCapability Kernel
   OpCapability Addresses
   OpMemoryModel Physical32 OpenCL
@@ -107,13 +105,13 @@
   OpReturn
   OpFunctionEnd
 )");
-  auto p = parser(spv);
-  EXPECT_FALSE(p->Parse());
-  EXPECT_THAT(p->error(), HasSubstr("Capability Kernel is not allowed"));
+    auto p = parser(spv);
+    EXPECT_FALSE(p->Parse());
+    EXPECT_THAT(p->error(), HasSubstr("Capability Kernel is not allowed"));
 }
 
 TEST_F(SpvParserTest, Impl_Source_NoOpLine) {
-  auto spv = test::Assemble(R"(
+    auto spv = test::Assemble(R"(
   OpCapability Shader
   OpMemoryModel Logical Simple
   OpEntryPoint GLCompute %main "main"
@@ -127,23 +125,23 @@
   OpReturn
   OpFunctionEnd
 )");
-  auto p = parser(spv);
-  EXPECT_TRUE(p->Parse());
-  EXPECT_TRUE(p->error().empty());
-  // Use instruction counting.
-  auto s5 = p->GetSourceForResultIdForTest(5);
-  EXPECT_EQ(7u, s5.range.begin.line);
-  EXPECT_EQ(0u, s5.range.begin.column);
-  auto s60 = p->GetSourceForResultIdForTest(60);
-  EXPECT_EQ(8u, s60.range.begin.line);
-  EXPECT_EQ(0u, s60.range.begin.column);
-  auto s1 = p->GetSourceForResultIdForTest(1);
-  EXPECT_EQ(10u, s1.range.begin.line);
-  EXPECT_EQ(0u, s1.range.begin.column);
+    auto p = parser(spv);
+    EXPECT_TRUE(p->Parse());
+    EXPECT_TRUE(p->error().empty());
+    // Use instruction counting.
+    auto s5 = p->GetSourceForResultIdForTest(5);
+    EXPECT_EQ(7u, s5.range.begin.line);
+    EXPECT_EQ(0u, s5.range.begin.column);
+    auto s60 = p->GetSourceForResultIdForTest(60);
+    EXPECT_EQ(8u, s60.range.begin.line);
+    EXPECT_EQ(0u, s60.range.begin.column);
+    auto s1 = p->GetSourceForResultIdForTest(1);
+    EXPECT_EQ(10u, s1.range.begin.line);
+    EXPECT_EQ(0u, s1.range.begin.column);
 }
 
 TEST_F(SpvParserTest, Impl_Source_WithOpLine_WithOpNoLine) {
-  auto spv = test::Assemble(R"(
+    auto spv = test::Assemble(R"(
   OpCapability Shader
   OpMemoryModel Logical Simple
   OpEntryPoint GLCompute %main "main"
@@ -160,24 +158,24 @@
   OpReturn
   OpFunctionEnd
 )");
-  auto p = parser(spv);
-  EXPECT_TRUE(p->Parse());
-  EXPECT_TRUE(p->error().empty());
-  // Use the information from the OpLine that is still in scope.
-  auto s5 = p->GetSourceForResultIdForTest(5);
-  EXPECT_EQ(42u, s5.range.begin.line);
-  EXPECT_EQ(53u, s5.range.begin.column);
-  auto s60 = p->GetSourceForResultIdForTest(60);
-  EXPECT_EQ(42u, s60.range.begin.line);
-  EXPECT_EQ(53u, s60.range.begin.column);
-  // After OpNoLine, revert back to instruction counting.
-  auto s1 = p->GetSourceForResultIdForTest(1);
-  EXPECT_EQ(14u, s1.range.begin.line);
-  EXPECT_EQ(0u, s1.range.begin.column);
+    auto p = parser(spv);
+    EXPECT_TRUE(p->Parse());
+    EXPECT_TRUE(p->error().empty());
+    // Use the information from the OpLine that is still in scope.
+    auto s5 = p->GetSourceForResultIdForTest(5);
+    EXPECT_EQ(42u, s5.range.begin.line);
+    EXPECT_EQ(53u, s5.range.begin.column);
+    auto s60 = p->GetSourceForResultIdForTest(60);
+    EXPECT_EQ(42u, s60.range.begin.line);
+    EXPECT_EQ(53u, s60.range.begin.column);
+    // After OpNoLine, revert back to instruction counting.
+    auto s1 = p->GetSourceForResultIdForTest(1);
+    EXPECT_EQ(14u, s1.range.begin.line);
+    EXPECT_EQ(0u, s1.range.begin.column);
 }
 
 TEST_F(SpvParserTest, Impl_Source_InvalidId) {
-  auto spv = test::Assemble(R"(
+    auto spv = test::Assemble(R"(
   OpCapability Shader
   OpMemoryModel Logical Simple
   OpEntryPoint GLCompute %main "main"
@@ -190,34 +188,33 @@
   OpReturn
   OpFunctionEnd
 )");
-  auto p = parser(spv);
-  EXPECT_TRUE(p->Parse());
-  EXPECT_TRUE(p->error().empty());
-  auto s99 = p->GetSourceForResultIdForTest(99);
-  EXPECT_EQ(0u, s99.range.begin.line);
-  EXPECT_EQ(0u, s99.range.begin.column);
+    auto p = parser(spv);
+    EXPECT_TRUE(p->Parse());
+    EXPECT_TRUE(p->error().empty());
+    auto s99 = p->GetSourceForResultIdForTest(99);
+    EXPECT_EQ(0u, s99.range.begin.line);
+    EXPECT_EQ(0u, s99.range.begin.column);
 }
 
 TEST_F(SpvParserTest, Impl_IsValidIdentifier) {
-  EXPECT_FALSE(ParserImpl::IsValidIdentifier(""));  // empty
-  EXPECT_FALSE(ParserImpl::IsValidIdentifier("_"));
-  EXPECT_FALSE(ParserImpl::IsValidIdentifier("__"));
-  EXPECT_TRUE(ParserImpl::IsValidIdentifier("_x"));
-  EXPECT_FALSE(
-      ParserImpl::IsValidIdentifier("9"));  // leading digit, but ok later
-  EXPECT_FALSE(ParserImpl::IsValidIdentifier(" "));    // leading space
-  EXPECT_FALSE(ParserImpl::IsValidIdentifier("a "));   // trailing space
-  EXPECT_FALSE(ParserImpl::IsValidIdentifier("a 1"));  // space in the middle
-  EXPECT_FALSE(ParserImpl::IsValidIdentifier("."));    // weird character
+    EXPECT_FALSE(ParserImpl::IsValidIdentifier(""));  // empty
+    EXPECT_FALSE(ParserImpl::IsValidIdentifier("_"));
+    EXPECT_FALSE(ParserImpl::IsValidIdentifier("__"));
+    EXPECT_TRUE(ParserImpl::IsValidIdentifier("_x"));
+    EXPECT_FALSE(ParserImpl::IsValidIdentifier("9"));    // leading digit, but ok later
+    EXPECT_FALSE(ParserImpl::IsValidIdentifier(" "));    // leading space
+    EXPECT_FALSE(ParserImpl::IsValidIdentifier("a "));   // trailing space
+    EXPECT_FALSE(ParserImpl::IsValidIdentifier("a 1"));  // space in the middle
+    EXPECT_FALSE(ParserImpl::IsValidIdentifier("."));    // weird character
 
-  // a simple identifier
-  EXPECT_TRUE(ParserImpl::IsValidIdentifier("A"));
-  // each upper case letter
-  EXPECT_TRUE(ParserImpl::IsValidIdentifier("ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
-  // each lower case letter
-  EXPECT_TRUE(ParserImpl::IsValidIdentifier("abcdefghijklmnopqrstuvwxyz"));
-  EXPECT_TRUE(ParserImpl::IsValidIdentifier("a0123456789"));  // each digit
-  EXPECT_TRUE(ParserImpl::IsValidIdentifier("x_"));           // has underscore
+    // a simple identifier
+    EXPECT_TRUE(ParserImpl::IsValidIdentifier("A"));
+    // each upper case letter
+    EXPECT_TRUE(ParserImpl::IsValidIdentifier("ABCDEFGHIJKLMNOPQRSTUVWXYZ"));
+    // each lower case letter
+    EXPECT_TRUE(ParserImpl::IsValidIdentifier("abcdefghijklmnopqrstuvwxyz"));
+    EXPECT_TRUE(ParserImpl::IsValidIdentifier("a0123456789"));  // each digit
+    EXPECT_TRUE(ParserImpl::IsValidIdentifier("x_"));           // has underscore
 }
 
 }  // namespace
diff --git a/src/tint/reader/spirv/parser_impl_test_helper.cc b/src/tint/reader/spirv/parser_impl_test_helper.cc
index bc62973..1e52d81 100644
--- a/src/tint/reader/spirv/parser_impl_test_helper.cc
+++ b/src/tint/reader/spirv/parser_impl_test_helper.cc
@@ -20,60 +20,57 @@
 // Default to not dumping the SPIR-V assembly.
 bool ParserImplWrapperForTest::dump_successfully_converted_spirv_ = false;
 
-ParserImplWrapperForTest::ParserImplWrapperForTest(
-    const std::vector<uint32_t>& input)
+ParserImplWrapperForTest::ParserImplWrapperForTest(const std::vector<uint32_t>& input)
     : impl_(input) {}
 
 ParserImplWrapperForTest::~ParserImplWrapperForTest() {
-  if (dump_successfully_converted_spirv_ && !skip_dumping_spirv_ &&
-      !impl_.spv_binary().empty() && impl_.success()) {
-    std::string disassembly = Disassemble(impl_.spv_binary());
-    std::cout << "BEGIN ConvertedOk:\n"
-              << disassembly << "\nEND ConvertedOk" << std::endl;
-  }
+    if (dump_successfully_converted_spirv_ && !skip_dumping_spirv_ && !impl_.spv_binary().empty() &&
+        impl_.success()) {
+        std::string disassembly = Disassemble(impl_.spv_binary());
+        std::cout << "BEGIN ConvertedOk:\n" << disassembly << "\nEND ConvertedOk" << std::endl;
+    }
 }
 
 std::string ToString(const Program& program) {
-  writer::wgsl::GeneratorImpl writer(&program);
-  if (!writer.Generate()) {
-    return "WGSL writer error: " + writer.error();
-  }
-  return writer.result();
+    writer::wgsl::GeneratorImpl writer(&program);
+    if (!writer.Generate()) {
+        return "WGSL writer error: " + writer.error();
+    }
+    return writer.result();
 }
 
 std::string ToString(const Program& program, const ast::StatementList& stmts) {
-  writer::wgsl::GeneratorImpl writer(&program);
-  for (const auto* stmt : stmts) {
-    if (!writer.EmitStatement(stmt)) {
-      return "WGSL writer error: " + writer.error();
+    writer::wgsl::GeneratorImpl writer(&program);
+    for (const auto* stmt : stmts) {
+        if (!writer.EmitStatement(stmt)) {
+            return "WGSL writer error: " + writer.error();
+        }
     }
-  }
-  return writer.result();
+    return writer.result();
 }
 
 std::string ToString(const Program& program, const ast::Node* node) {
-  writer::wgsl::GeneratorImpl writer(&program);
-  if (auto* expr = node->As<ast::Expression>()) {
-    std::stringstream out;
-    if (!writer.EmitExpression(out, expr)) {
-      return "WGSL writer error: " + writer.error();
+    writer::wgsl::GeneratorImpl writer(&program);
+    if (auto* expr = node->As<ast::Expression>()) {
+        std::stringstream out;
+        if (!writer.EmitExpression(out, expr)) {
+            return "WGSL writer error: " + writer.error();
+        }
+        return out.str();
+    } else if (auto* stmt = node->As<ast::Statement>()) {
+        if (!writer.EmitStatement(stmt)) {
+            return "WGSL writer error: " + writer.error();
+        }
+    } else if (auto* ty = node->As<ast::Type>()) {
+        std::stringstream out;
+        if (!writer.EmitType(out, ty)) {
+            return "WGSL writer error: " + writer.error();
+        }
+        return out.str();
+    } else {
+        return "<unhandled AST node type " + std::string(node->TypeInfo().name) + ">";
     }
-    return out.str();
-  } else if (auto* stmt = node->As<ast::Statement>()) {
-    if (!writer.EmitStatement(stmt)) {
-      return "WGSL writer error: " + writer.error();
-    }
-  } else if (auto* ty = node->As<ast::Type>()) {
-    std::stringstream out;
-    if (!writer.EmitType(out, ty)) {
-      return "WGSL writer error: " + writer.error();
-    }
-    return out.str();
-  } else {
-    return "<unhandled AST node type " + std::string(node->TypeInfo().name) +
-           ">";
-  }
-  return writer.result();
+    return writer.result();
 }
 
 }  // namespace tint::reader::spirv::test
diff --git a/src/tint/reader/spirv/parser_impl_test_helper.h b/src/tint/reader/spirv/parser_impl_test_helper.h
index 31640a5..7362a2d 100644
--- a/src/tint/reader/spirv/parser_impl_test_helper.h
+++ b/src/tint/reader/spirv/parser_impl_test_helper.h
@@ -39,232 +39,221 @@
 
 /// A test class that wraps ParseImpl
 class ParserImplWrapperForTest {
- public:
-  /// Constructor
-  /// @param input the input data to parse
-  explicit ParserImplWrapperForTest(const std::vector<uint32_t>& input);
-  /// Dumps SPIR-V if the conversion succeeded, then destroys the wrapper.
-  ~ParserImplWrapperForTest();
+  public:
+    /// Constructor
+    /// @param input the input data to parse
+    explicit ParserImplWrapperForTest(const std::vector<uint32_t>& input);
+    /// Dumps SPIR-V if the conversion succeeded, then destroys the wrapper.
+    ~ParserImplWrapperForTest();
 
-  /// Sets global state to force dumping of the assembly text of succesfully
-  /// SPIR-V.
-  static void DumpSuccessfullyConvertedSpirv() {
-    dump_successfully_converted_spirv_ = true;
-  }
-  /// Marks the test has having deliberately invalid SPIR-V
-  void DeliberatelyInvalidSpirv() { skip_dumping_spirv_ = true; }
-  /// Marks the test's SPIR-V as not being suitable for dumping, for a stated
-  /// reason.
-  void SkipDumpingPending(std::string) { skip_dumping_spirv_ = true; }
+    /// Sets global state to force dumping of the assembly text of succesfully
+    /// SPIR-V.
+    static void DumpSuccessfullyConvertedSpirv() { dump_successfully_converted_spirv_ = true; }
+    /// Marks the test has having deliberately invalid SPIR-V
+    void DeliberatelyInvalidSpirv() { skip_dumping_spirv_ = true; }
+    /// Marks the test's SPIR-V as not being suitable for dumping, for a stated
+    /// reason.
+    void SkipDumpingPending(std::string) { skip_dumping_spirv_ = true; }
 
-  /// @returns a new function emitter for the given function ID.
-  /// Assumes ParserImpl::BuildInternalRepresentation has been run and
-  /// succeeded.
-  /// @param function_id the SPIR-V identifier of the function
-  FunctionEmitter function_emitter(uint32_t function_id) {
-    auto* spirv_function = impl_.ir_context()->GetFunction(function_id);
-    return FunctionEmitter(&impl_, *spirv_function);
-  }
+    /// @returns a new function emitter for the given function ID.
+    /// Assumes ParserImpl::BuildInternalRepresentation has been run and
+    /// succeeded.
+    /// @param function_id the SPIR-V identifier of the function
+    FunctionEmitter function_emitter(uint32_t function_id) {
+        auto* spirv_function = impl_.ir_context()->GetFunction(function_id);
+        return FunctionEmitter(&impl_, *spirv_function);
+    }
 
-  /// Run the parser
-  /// @returns true if the parse was successful, false otherwise.
-  bool Parse() { return impl_.Parse(); }
+    /// Run the parser
+    /// @returns true if the parse was successful, false otherwise.
+    bool Parse() { return impl_.Parse(); }
 
-  /// @returns the program. The program builder in the parser will be reset
-  /// after this.
-  Program program() { return impl_.program(); }
+    /// @returns the program. The program builder in the parser will be reset
+    /// after this.
+    Program program() { return impl_.program(); }
 
-  /// @returns the namer object
-  Namer& namer() { return impl_.namer(); }
+    /// @returns the namer object
+    Namer& namer() { return impl_.namer(); }
 
-  /// @returns a reference to the internal builder, without building the
-  /// program. To be used only for testing.
-  ProgramBuilder& builder() { return impl_.builder(); }
+    /// @returns a reference to the internal builder, without building the
+    /// program. To be used only for testing.
+    ProgramBuilder& builder() { return impl_.builder(); }
 
-  /// @returns the accumulated error string
-  const std::string error() { return impl_.error(); }
+    /// @returns the accumulated error string
+    const std::string error() { return impl_.error(); }
 
-  /// @return true if failure has not yet occurred
-  bool success() { return impl_.success(); }
+    /// @return true if failure has not yet occurred
+    bool success() { return impl_.success(); }
 
-  /// Logs failure, ands return a failure stream to accumulate diagnostic
-  /// messages. By convention, a failure should only be logged along with
-  /// a non-empty string diagnostic.
-  /// @returns the failure stream
-  FailStream& Fail() { return impl_.Fail(); }
+    /// Logs failure, ands return a failure stream to accumulate diagnostic
+    /// messages. By convention, a failure should only be logged along with
+    /// a non-empty string diagnostic.
+    /// @returns the failure stream
+    FailStream& Fail() { return impl_.Fail(); }
 
-  /// @returns a borrowed pointer to the internal representation of the module.
-  /// This is null until BuildInternalModule has been called.
-  spvtools::opt::IRContext* ir_context() { return impl_.ir_context(); }
+    /// @returns a borrowed pointer to the internal representation of the module.
+    /// This is null until BuildInternalModule has been called.
+    spvtools::opt::IRContext* ir_context() { return impl_.ir_context(); }
 
-  /// Builds the internal representation of the SPIR-V module.
-  /// Assumes the module is somewhat well-formed.  Normally you
-  /// would want to validate the SPIR-V module before attempting
-  /// to build this internal representation. Also computes a topological
-  /// ordering of the functions.
-  /// This is a no-op if the parser has already failed.
-  /// @returns true if the parser is still successful.
-  bool BuildInternalModule() { return impl_.BuildInternalModule(); }
+    /// Builds the internal representation of the SPIR-V module.
+    /// Assumes the module is somewhat well-formed.  Normally you
+    /// would want to validate the SPIR-V module before attempting
+    /// to build this internal representation. Also computes a topological
+    /// ordering of the functions.
+    /// This is a no-op if the parser has already failed.
+    /// @returns true if the parser is still successful.
+    bool BuildInternalModule() { return impl_.BuildInternalModule(); }
 
-  /// Builds an internal representation of the SPIR-V binary,
-  /// and parses the module, except functions, into a Tint AST module.
-  /// Diagnostics are emitted to the error stream.
-  /// @returns true if it was successful.
-  bool BuildAndParseInternalModuleExceptFunctions() {
-    return impl_.BuildAndParseInternalModuleExceptFunctions();
-  }
+    /// Builds an internal representation of the SPIR-V binary,
+    /// and parses the module, except functions, into a Tint AST module.
+    /// Diagnostics are emitted to the error stream.
+    /// @returns true if it was successful.
+    bool BuildAndParseInternalModuleExceptFunctions() {
+        return impl_.BuildAndParseInternalModuleExceptFunctions();
+    }
 
-  /// Builds an internal representation of the SPIR-V binary,
-  /// and parses it into a Tint AST module.  Diagnostics are emitted
-  /// to the error stream.
-  /// @returns true if it was successful.
-  bool BuildAndParseInternalModule() {
-    return impl_.BuildAndParseInternalModule();
-  }
+    /// Builds an internal representation of the SPIR-V binary,
+    /// and parses it into a Tint AST module.  Diagnostics are emitted
+    /// to the error stream.
+    /// @returns true if it was successful.
+    bool BuildAndParseInternalModule() { return impl_.BuildAndParseInternalModule(); }
 
-  /// Registers user names for SPIR-V objects, from OpName, and OpMemberName.
-  /// Also synthesizes struct field names.  Ensures uniqueness for names for
-  /// SPIR-V IDs, and uniqueness of names of fields within any single struct.
-  /// This is a no-op if the parser has already failed.
-  /// @returns true if parser is still successful.
-  bool RegisterUserAndStructMemberNames() {
-    return impl_.RegisterUserAndStructMemberNames();
-  }
+    /// Registers user names for SPIR-V objects, from OpName, and OpMemberName.
+    /// Also synthesizes struct field names.  Ensures uniqueness for names for
+    /// SPIR-V IDs, and uniqueness of names of fields within any single struct.
+    /// This is a no-op if the parser has already failed.
+    /// @returns true if parser is still successful.
+    bool RegisterUserAndStructMemberNames() { return impl_.RegisterUserAndStructMemberNames(); }
 
-  /// Register Tint AST types for SPIR-V types, including type aliases as
-  /// needed.  This is a no-op if the parser has already failed.
-  /// @returns true if parser is still successful.
-  bool RegisterTypes() { return impl_.RegisterTypes(); }
+    /// Register Tint AST types for SPIR-V types, including type aliases as
+    /// needed.  This is a no-op if the parser has already failed.
+    /// @returns true if parser is still successful.
+    bool RegisterTypes() { return impl_.RegisterTypes(); }
 
-  /// Register sampler and texture usage for memory object declarations.
-  /// This must be called after we've registered line numbers for all
-  /// instructions. This is a no-op if the parser has already failed.
-  /// @returns true if parser is still successful.
-  bool RegisterHandleUsage() { return impl_.RegisterHandleUsage(); }
+    /// Register sampler and texture usage for memory object declarations.
+    /// This must be called after we've registered line numbers for all
+    /// instructions. This is a no-op if the parser has already failed.
+    /// @returns true if parser is still successful.
+    bool RegisterHandleUsage() { return impl_.RegisterHandleUsage(); }
 
-  /// Emits module-scope variables.
-  /// This is a no-op if the parser has already failed.
-  /// @returns true if parser is still successful.
-  bool EmitModuleScopeVariables() { return impl_.EmitModuleScopeVariables(); }
+    /// Emits module-scope variables.
+    /// This is a no-op if the parser has already failed.
+    /// @returns true if parser is still successful.
+    bool EmitModuleScopeVariables() { return impl_.EmitModuleScopeVariables(); }
 
-  /// @returns the set of SPIR-V IDs for imports of the "GLSL.std.450"
-  /// extended instruction set.
-  const std::unordered_set<uint32_t>& glsl_std_450_imports() const {
-    return impl_.glsl_std_450_imports();
-  }
+    /// @returns the set of SPIR-V IDs for imports of the "GLSL.std.450"
+    /// extended instruction set.
+    const std::unordered_set<uint32_t>& glsl_std_450_imports() const {
+        return impl_.glsl_std_450_imports();
+    }
 
-  /// Converts a SPIR-V type to a Tint type, and saves it for fast lookup.
-  /// If the type is only used for builtins, then register that specially,
-  /// and return null.  If the type is a sampler, image, or sampled image, then
-  /// return the Void type, because those opaque types are handled in a
-  /// different way.
-  /// On failure, logs an error and returns null.  This should only be called
-  /// after the internal representation of the module has been built.
-  /// @param id the SPIR-V ID of a type.
-  /// @returns a Tint type, or nullptr
-  const Type* ConvertType(uint32_t id) { return impl_.ConvertType(id); }
+    /// Converts a SPIR-V type to a Tint type, and saves it for fast lookup.
+    /// If the type is only used for builtins, then register that specially,
+    /// and return null.  If the type is a sampler, image, or sampled image, then
+    /// return the Void type, because those opaque types are handled in a
+    /// different way.
+    /// On failure, logs an error and returns null.  This should only be called
+    /// after the internal representation of the module has been built.
+    /// @param id the SPIR-V ID of a type.
+    /// @returns a Tint type, or nullptr
+    const Type* ConvertType(uint32_t id) { return impl_.ConvertType(id); }
 
-  /// Gets the list of decorations for a SPIR-V result ID.  Returns an empty
-  /// vector if the ID is not a result ID, or if no decorations target that ID.
-  /// The internal representation must have already been built.
-  /// @param id SPIR-V ID
-  /// @returns the list of decorations on the given ID
-  DecorationList GetDecorationsFor(uint32_t id) const {
-    return impl_.GetDecorationsFor(id);
-  }
+    /// Gets the list of decorations for a SPIR-V result ID.  Returns an empty
+    /// vector if the ID is not a result ID, or if no decorations target that ID.
+    /// The internal representation must have already been built.
+    /// @param id SPIR-V ID
+    /// @returns the list of decorations on the given ID
+    DecorationList GetDecorationsFor(uint32_t id) const { return impl_.GetDecorationsFor(id); }
 
-  /// Gets the list of decorations for the member of a struct.  Returns an empty
-  /// list if the `id` is not the ID of a struct, or if the member index is out
-  /// of range, or if the target member has no decorations.
-  /// The internal representation must have already been built.
-  /// @param id SPIR-V ID of a struct
-  /// @param member_index the member within the struct
-  /// @returns the list of decorations on the member
-  DecorationList GetDecorationsForMember(uint32_t id,
-                                         uint32_t member_index) const {
-    return impl_.GetDecorationsForMember(id, member_index);
-  }
+    /// Gets the list of decorations for the member of a struct.  Returns an empty
+    /// list if the `id` is not the ID of a struct, or if the member index is out
+    /// of range, or if the target member has no decorations.
+    /// The internal representation must have already been built.
+    /// @param id SPIR-V ID of a struct
+    /// @param member_index the member within the struct
+    /// @returns the list of decorations on the member
+    DecorationList GetDecorationsForMember(uint32_t id, uint32_t member_index) const {
+        return impl_.GetDecorationsForMember(id, member_index);
+    }
 
-  /// Converts a SPIR-V struct member decoration into a number of AST
-  /// decorations. If the decoration is recognized but deliberately dropped,
-  /// then returns an empty list without a diagnostic. On failure, emits a
-  /// diagnostic and returns an empty list.
-  /// @param struct_type_id the ID of the struct type
-  /// @param member_index the index of the member
-  /// @param member_ty the type of the member
-  /// @param decoration an encoded SPIR-V Decoration
-  /// @returns the AST decorations
-  ast::AttributeList ConvertMemberDecoration(uint32_t struct_type_id,
-                                             uint32_t member_index,
-                                             const Type* member_ty,
-                                             const Decoration& decoration) {
-    return impl_.ConvertMemberDecoration(struct_type_id, member_index,
-                                         member_ty, decoration);
-  }
+    /// Converts a SPIR-V struct member decoration into a number of AST
+    /// decorations. If the decoration is recognized but deliberately dropped,
+    /// then returns an empty list without a diagnostic. On failure, emits a
+    /// diagnostic and returns an empty list.
+    /// @param struct_type_id the ID of the struct type
+    /// @param member_index the index of the member
+    /// @param member_ty the type of the member
+    /// @param decoration an encoded SPIR-V Decoration
+    /// @returns the AST decorations
+    ast::AttributeList ConvertMemberDecoration(uint32_t struct_type_id,
+                                               uint32_t member_index,
+                                               const Type* member_ty,
+                                               const Decoration& decoration) {
+        return impl_.ConvertMemberDecoration(struct_type_id, member_index, member_ty, decoration);
+    }
 
-  /// For a SPIR-V ID that might define a sampler, image, or sampled image
-  /// value, return the SPIR-V instruction that represents the memory object
-  /// declaration for the object.  If we encounter an OpSampledImage along the
-  /// way, follow the image operand when follow_image is true; otherwise follow
-  /// the sampler operand. Returns nullptr if we can't trace back to a memory
-  /// object declaration.  Emits an error and returns nullptr when the scan
-  /// fails due to a malformed module. This method can be used any time after
-  /// BuildInternalModule has been invoked.
-  /// @param id the SPIR-V ID of the sampler, image, or sampled image
-  /// @param follow_image indicates whether to follow the image operand of
-  /// OpSampledImage
-  /// @returns the memory object declaration for the handle, or nullptr
-  const spvtools::opt::Instruction* GetMemoryObjectDeclarationForHandle(
-      uint32_t id,
-      bool follow_image) {
-    return impl_.GetMemoryObjectDeclarationForHandle(id, follow_image);
-  }
+    /// For a SPIR-V ID that might define a sampler, image, or sampled image
+    /// value, return the SPIR-V instruction that represents the memory object
+    /// declaration for the object.  If we encounter an OpSampledImage along the
+    /// way, follow the image operand when follow_image is true; otherwise follow
+    /// the sampler operand. Returns nullptr if we can't trace back to a memory
+    /// object declaration.  Emits an error and returns nullptr when the scan
+    /// fails due to a malformed module. This method can be used any time after
+    /// BuildInternalModule has been invoked.
+    /// @param id the SPIR-V ID of the sampler, image, or sampled image
+    /// @param follow_image indicates whether to follow the image operand of
+    /// OpSampledImage
+    /// @returns the memory object declaration for the handle, or nullptr
+    const spvtools::opt::Instruction* GetMemoryObjectDeclarationForHandle(uint32_t id,
+                                                                          bool follow_image) {
+        return impl_.GetMemoryObjectDeclarationForHandle(id, follow_image);
+    }
 
-  /// @param entry_point the SPIR-V ID of an entry point.
-  /// @returns the entry point info for the given ID
-  const std::vector<EntryPointInfo>& GetEntryPointInfo(uint32_t entry_point) {
-    return impl_.GetEntryPointInfo(entry_point);
-  }
+    /// @param entry_point the SPIR-V ID of an entry point.
+    /// @returns the entry point info for the given ID
+    const std::vector<EntryPointInfo>& GetEntryPointInfo(uint32_t entry_point) {
+        return impl_.GetEntryPointInfo(entry_point);
+    }
 
-  /// Returns the handle usage for a memory object declaration.
-  /// @param id SPIR-V ID of a sampler or image OpVariable or
-  /// OpFunctionParameter
-  /// @returns the handle usage, or an empty usage object.
-  Usage GetHandleUsage(uint32_t id) const { return impl_.GetHandleUsage(id); }
+    /// Returns the handle usage for a memory object declaration.
+    /// @param id SPIR-V ID of a sampler or image OpVariable or
+    /// OpFunctionParameter
+    /// @returns the handle usage, or an empty usage object.
+    Usage GetHandleUsage(uint32_t id) const { return impl_.GetHandleUsage(id); }
 
-  /// Returns the SPIR-V instruction with the given ID, or nullptr.
-  /// @param id the SPIR-V result ID
-  /// @returns the instruction, or nullptr on error
-  const spvtools::opt::Instruction* GetInstructionForTest(uint32_t id) const {
-    return impl_.GetInstructionForTest(id);
-  }
+    /// Returns the SPIR-V instruction with the given ID, or nullptr.
+    /// @param id the SPIR-V result ID
+    /// @returns the instruction, or nullptr on error
+    const spvtools::opt::Instruction* GetInstructionForTest(uint32_t id) const {
+        return impl_.GetInstructionForTest(id);
+    }
 
-  /// @returns info about the gl_Position builtin variable.
-  const ParserImpl::BuiltInPositionInfo& GetBuiltInPositionInfo() {
-    return impl_.GetBuiltInPositionInfo();
-  }
+    /// @returns info about the gl_Position builtin variable.
+    const ParserImpl::BuiltInPositionInfo& GetBuiltInPositionInfo() {
+        return impl_.GetBuiltInPositionInfo();
+    }
 
-  /// Returns the source record for the SPIR-V instruction with the given
-  /// result ID.
-  /// @param id the SPIR-V result id.
-  /// @return the Source record, or a default one
-  Source GetSourceForResultIdForTest(uint32_t id) const {
-    return impl_.GetSourceForResultIdForTest(id);
-  }
+    /// Returns the source record for the SPIR-V instruction with the given
+    /// result ID.
+    /// @param id the SPIR-V result id.
+    /// @return the Source record, or a default one
+    Source GetSourceForResultIdForTest(uint32_t id) const {
+        return impl_.GetSourceForResultIdForTest(id);
+    }
 
- private:
-  ParserImpl impl_;
-  /// When true, indicates the input SPIR-V module should not be emitted.
-  /// It's either deliberately invalid, or not supported for some pending
-  /// reason.
-  bool skip_dumping_spirv_ = false;
-  static bool dump_successfully_converted_spirv_;
+  private:
+    ParserImpl impl_;
+    /// When true, indicates the input SPIR-V module should not be emitted.
+    /// It's either deliberately invalid, or not supported for some pending
+    /// reason.
+    bool skip_dumping_spirv_ = false;
+    static bool dump_successfully_converted_spirv_;
 };
 
 // Sets global state to force dumping of the assembly text of succesfully
 // SPIR-V.
 inline void DumpSuccessfullyConvertedSpirv() {
-  ParserImplWrapperForTest::DumpSuccessfullyConvertedSpirv();
+    ParserImplWrapperForTest::DumpSuccessfullyConvertedSpirv();
 }
 
 /// Returns the WGSL printed string of a program.
@@ -289,22 +278,21 @@
 /// SPIR-V Parser test class
 template <typename T>
 class SpvParserTestBase : public T {
- public:
-  SpvParserTestBase() = default;
-  ~SpvParserTestBase() override = default;
+  public:
+    SpvParserTestBase() = default;
+    ~SpvParserTestBase() override = default;
 
-  /// Retrieves the parser from the helper
-  /// @param input the SPIR-V binary to parse
-  /// @returns a parser for the given binary
-  std::unique_ptr<test::ParserImplWrapperForTest> parser(
-      const std::vector<uint32_t>& input) {
-    auto parser = std::make_unique<test::ParserImplWrapperForTest>(input);
+    /// Retrieves the parser from the helper
+    /// @param input the SPIR-V binary to parse
+    /// @returns a parser for the given binary
+    std::unique_ptr<test::ParserImplWrapperForTest> parser(const std::vector<uint32_t>& input) {
+        auto parser = std::make_unique<test::ParserImplWrapperForTest>(input);
 
-    // Don't run the Resolver when building the program.
-    // We're not interested in type information with these tests.
-    parser->builder().SetResolveOnBuild(false);
-    return parser;
-  }
+        // Don't run the Resolver when building the program.
+        // We're not interested in type information with these tests.
+        parser->builder().SetResolveOnBuild(false);
+        return parser;
+    }
 };
 
 /// SpvParserTest the the base class for SPIR-V reader unit tests.
diff --git a/src/tint/reader/spirv/parser_impl_user_name_test.cc b/src/tint/reader/spirv/parser_impl_user_name_test.cc
index 6540512..3af1a58 100644
--- a/src/tint/reader/spirv/parser_impl_user_name_test.cc
+++ b/src/tint/reader/spirv/parser_impl_user_name_test.cc
@@ -24,98 +24,98 @@
 using SpvParserUserNameTest = SpvParserTest;
 
 TEST_F(SpvParserUserNameTest, UserName_RespectOpName) {
-  auto p = parser(test::Assemble(R"(
+    auto p = parser(test::Assemble(R"(
      OpName %1 "the_void_type"
      %1 = OpTypeVoid
   )"));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_THAT(p->namer().GetName(1), Eq("the_void_type"));
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_THAT(p->namer().GetName(1), Eq("the_void_type"));
 
-  p->DeliberatelyInvalidSpirv();
+    p->DeliberatelyInvalidSpirv();
 }
 
 TEST_F(SpvParserUserNameTest, UserName_IgnoreEmptyName) {
-  auto p = parser(test::Assemble(R"(
+    auto p = parser(test::Assemble(R"(
      OpName %1 ""
      %1 = OpTypeVoid
   )"));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_FALSE(p->namer().HasName(1));
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_FALSE(p->namer().HasName(1));
 
-  p->DeliberatelyInvalidSpirv();
+    p->DeliberatelyInvalidSpirv();
 }
 
 TEST_F(SpvParserUserNameTest, UserName_DistinguishDuplicateSuggestion) {
-  auto p = parser(test::Assemble(R"(
+    auto p = parser(test::Assemble(R"(
      OpName %1 "vanilla"
      OpName %2 "vanilla"
      %1 = OpTypeVoid
      %2 = OpTypeInt 32 0
   )"));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_THAT(p->namer().GetName(1), Eq("vanilla"));
-  EXPECT_THAT(p->namer().GetName(2), Eq("vanilla_1"));
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_THAT(p->namer().GetName(1), Eq("vanilla"));
+    EXPECT_THAT(p->namer().GetName(2), Eq("vanilla_1"));
 
-  p->DeliberatelyInvalidSpirv();
+    p->DeliberatelyInvalidSpirv();
 }
 
 TEST_F(SpvParserUserNameTest, UserName_RespectOpMemberName) {
-  auto p = parser(test::Assemble(R"(
+    auto p = parser(test::Assemble(R"(
      OpMemberName %3 0 "strawberry"
      OpMemberName %3 1 "vanilla"
      OpMemberName %3 2 "chocolate"
      %2 = OpTypeInt 32 0
      %3 = OpTypeStruct %2 %2 %2
   )"));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_THAT(p->namer().GetMemberName(3, 0), Eq("strawberry"));
-  EXPECT_THAT(p->namer().GetMemberName(3, 1), Eq("vanilla"));
-  EXPECT_THAT(p->namer().GetMemberName(3, 2), Eq("chocolate"));
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_THAT(p->namer().GetMemberName(3, 0), Eq("strawberry"));
+    EXPECT_THAT(p->namer().GetMemberName(3, 1), Eq("vanilla"));
+    EXPECT_THAT(p->namer().GetMemberName(3, 2), Eq("chocolate"));
 
-  p->DeliberatelyInvalidSpirv();
+    p->DeliberatelyInvalidSpirv();
 }
 
 TEST_F(SpvParserUserNameTest, UserName_IgnoreEmptyMemberName) {
-  auto p = parser(test::Assemble(R"(
+    auto p = parser(test::Assemble(R"(
      OpMemberName %3 0 ""
      %2 = OpTypeInt 32 0
      %3 = OpTypeStruct %2
   )"));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_THAT(p->namer().GetMemberName(3, 0), Eq("field0"));
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_THAT(p->namer().GetMemberName(3, 0), Eq("field0"));
 
-  p->DeliberatelyInvalidSpirv();
+    p->DeliberatelyInvalidSpirv();
 }
 
 TEST_F(SpvParserUserNameTest, UserName_SynthesizeMemberNames) {
-  auto p = parser(test::Assemble(R"(
+    auto p = parser(test::Assemble(R"(
      %2 = OpTypeInt 32 0
      %3 = OpTypeStruct %2 %2 %2
   )"));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_THAT(p->namer().GetMemberName(3, 0), Eq("field0"));
-  EXPECT_THAT(p->namer().GetMemberName(3, 1), Eq("field1"));
-  EXPECT_THAT(p->namer().GetMemberName(3, 2), Eq("field2"));
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_THAT(p->namer().GetMemberName(3, 0), Eq("field0"));
+    EXPECT_THAT(p->namer().GetMemberName(3, 1), Eq("field1"));
+    EXPECT_THAT(p->namer().GetMemberName(3, 2), Eq("field2"));
 
-  p->DeliberatelyInvalidSpirv();
+    p->DeliberatelyInvalidSpirv();
 }
 
 TEST_F(SpvParserUserNameTest, UserName_MemberNamesMixUserAndSynthesized) {
-  auto p = parser(test::Assemble(R"(
+    auto p = parser(test::Assemble(R"(
      OpMemberName %3 1 "vanilla"
      %2 = OpTypeInt 32 0
      %3 = OpTypeStruct %2 %2 %2
   )"));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  EXPECT_THAT(p->namer().GetMemberName(3, 0), Eq("field0"));
-  EXPECT_THAT(p->namer().GetMemberName(3, 1), Eq("vanilla"));
-  EXPECT_THAT(p->namer().GetMemberName(3, 2), Eq("field2"));
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    EXPECT_THAT(p->namer().GetMemberName(3, 0), Eq("field0"));
+    EXPECT_THAT(p->namer().GetMemberName(3, 1), Eq("vanilla"));
+    EXPECT_THAT(p->namer().GetMemberName(3, 2), Eq("field2"));
 
-  p->DeliberatelyInvalidSpirv();
+    p->DeliberatelyInvalidSpirv();
 }
 
 TEST_F(SpvParserUserNameTest, EntryPointNames_AlwaysTakePrecedence) {
-  const std::string assembly = R"(
+    const std::string assembly = R"(
    OpCapability Shader
    OpMemoryModel Logical Simple
    OpEntryPoint Vertex %100 "main"
@@ -137,30 +137,30 @@
    OpReturn
    OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  // The first entry point grabs the best name, "main"
-  EXPECT_THAT(p->namer().Name(100), Eq("main"));
-  // The OpName on %1 is overriden because the second entry point
-  // has grabbed "main_1" first.
-  EXPECT_THAT(p->namer().Name(1), Eq("main_1_1"));
+    auto p = parser(test::Assemble(assembly));
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    // The first entry point grabs the best name, "main"
+    EXPECT_THAT(p->namer().Name(100), Eq("main"));
+    // The OpName on %1 is overriden because the second entry point
+    // has grabbed "main_1" first.
+    EXPECT_THAT(p->namer().Name(1), Eq("main_1_1"));
 
-  const auto& ep_info = p->GetEntryPointInfo(100);
-  ASSERT_EQ(2u, ep_info.size());
-  EXPECT_EQ(ep_info[0].name, "main");
-  EXPECT_EQ(ep_info[1].name, "main_1");
+    const auto& ep_info = p->GetEntryPointInfo(100);
+    ASSERT_EQ(2u, ep_info.size());
+    EXPECT_EQ(ep_info[0].name, "main");
+    EXPECT_EQ(ep_info[1].name, "main_1");
 
-  // This test checks two entry point with the same implementation function.
-  // But for the shader stages supported by WGSL, the SPIR-V rules require
-  // conflicting execution modes be applied to them.
-  // I still want to test the name disambiguation behaviour, but the cases
-  // are rejected by SPIR-V validation. This is true at least for the current
-  // WGSL feature set.
-  p->DeliberatelyInvalidSpirv();
+    // This test checks two entry point with the same implementation function.
+    // But for the shader stages supported by WGSL, the SPIR-V rules require
+    // conflicting execution modes be applied to them.
+    // I still want to test the name disambiguation behaviour, but the cases
+    // are rejected by SPIR-V validation. This is true at least for the current
+    // WGSL feature set.
+    p->DeliberatelyInvalidSpirv();
 }
 
 TEST_F(SpvParserUserNameTest, EntryPointNames_DistinctFromInnerNames) {
-  const std::string assembly = R"(
+    const std::string assembly = R"(
    OpCapability Shader
    OpMemoryModel Logical Simple
    OpEntryPoint Vertex %100 "main"
@@ -182,29 +182,29 @@
    OpReturn
    OpFunctionEnd
 )";
-  auto p = parser(test::Assemble(assembly));
+    auto p = parser(test::Assemble(assembly));
 
-  EXPECT_TRUE(p->BuildAndParseInternalModule());
-  // The first entry point grabs the best name, "main"
-  EXPECT_THAT(p->namer().Name(100), Eq("main"));
-  EXPECT_THAT(p->namer().Name(1), Eq("main_1_1"));
+    EXPECT_TRUE(p->BuildAndParseInternalModule());
+    // The first entry point grabs the best name, "main"
+    EXPECT_THAT(p->namer().Name(100), Eq("main"));
+    EXPECT_THAT(p->namer().Name(1), Eq("main_1_1"));
 
-  const auto ep_info = p->GetEntryPointInfo(100);
-  ASSERT_EQ(2u, ep_info.size());
-  EXPECT_EQ(ep_info[0].name, "main");
-  EXPECT_EQ(ep_info[0].inner_name, "main_2");
-  // The second entry point retains its name...
-  EXPECT_EQ(ep_info[1].name, "main_1");
-  // ...but will use the same implementation function.
-  EXPECT_EQ(ep_info[1].inner_name, "main_2");
+    const auto ep_info = p->GetEntryPointInfo(100);
+    ASSERT_EQ(2u, ep_info.size());
+    EXPECT_EQ(ep_info[0].name, "main");
+    EXPECT_EQ(ep_info[0].inner_name, "main_2");
+    // The second entry point retains its name...
+    EXPECT_EQ(ep_info[1].name, "main_1");
+    // ...but will use the same implementation function.
+    EXPECT_EQ(ep_info[1].inner_name, "main_2");
 
-  // This test checks two entry point with the same implementation function.
-  // But for the shader stages supported by WGSL, the SPIR-V rules require
-  // conflicting execution modes be applied to them.
-  // I still want to test the name disambiguation behaviour, but the cases
-  // are rejected by SPIR-V validation. This is true at least for the current
-  // WGSL feature set.
-  p->DeliberatelyInvalidSpirv();
+    // This test checks two entry point with the same implementation function.
+    // But for the shader stages supported by WGSL, the SPIR-V rules require
+    // conflicting execution modes be applied to them.
+    // I still want to test the name disambiguation behaviour, but the cases
+    // are rejected by SPIR-V validation. This is true at least for the current
+    // WGSL feature set.
+    p->DeliberatelyInvalidSpirv();
 }
 
 }  // namespace
diff --git a/src/tint/reader/spirv/parser_test.cc b/src/tint/reader/spirv/parser_test.cc
index 304eb3e..35cb5da 100644
--- a/src/tint/reader/spirv/parser_test.cc
+++ b/src/tint/reader/spirv/parser_test.cc
@@ -22,11 +22,11 @@
 using ParserTest = testing::Test;
 
 TEST_F(ParserTest, DataEmpty) {
-  std::vector<uint32_t> data;
-  auto program = Parse(data);
-  auto errs = diag::Formatter().format(program.Diagnostics());
-  ASSERT_FALSE(program.IsValid()) << errs;
-  EXPECT_EQ(errs, "error: line:0: Invalid SPIR-V magic number.\n");
+    std::vector<uint32_t> data;
+    auto program = Parse(data);
+    auto errs = diag::Formatter().format(program.Diagnostics());
+    ASSERT_FALSE(program.IsValid()) << errs;
+    EXPECT_EQ(errs, "error: line:0: Invalid SPIR-V magic number.\n");
 }
 
 // TODO(dneto): uint32 vec, valid SPIR-V
diff --git a/src/tint/reader/spirv/parser_type.cc b/src/tint/reader/spirv/parser_type.cc
index dbe4e14..3332cd4 100644
--- a/src/tint/reader/spirv/parser_type.cc
+++ b/src/tint/reader/spirv/parser_type.cc
@@ -49,186 +49,164 @@
 
 namespace {
 struct PointerHasher {
-  size_t operator()(const Pointer& t) const {
-    return utils::Hash(t.type, t.storage_class);
-  }
+    size_t operator()(const Pointer& t) const { return utils::Hash(t.type, t.storage_class); }
 };
 
 struct ReferenceHasher {
-  size_t operator()(const Reference& t) const {
-    return utils::Hash(t.type, t.storage_class);
-  }
+    size_t operator()(const Reference& t) const { return utils::Hash(t.type, t.storage_class); }
 };
 
 struct VectorHasher {
-  size_t operator()(const Vector& t) const {
-    return utils::Hash(t.type, t.size);
-  }
+    size_t operator()(const Vector& t) const { return utils::Hash(t.type, t.size); }
 };
 
 struct MatrixHasher {
-  size_t operator()(const Matrix& t) const {
-    return utils::Hash(t.type, t.columns, t.rows);
-  }
+    size_t operator()(const Matrix& t) const { return utils::Hash(t.type, t.columns, t.rows); }
 };
 
 struct ArrayHasher {
-  size_t operator()(const Array& t) const {
-    return utils::Hash(t.type, t.size, t.stride);
-  }
+    size_t operator()(const Array& t) const { return utils::Hash(t.type, t.size, t.stride); }
 };
 
 struct AliasHasher {
-  size_t operator()(const Alias& t) const { return utils::Hash(t.name); }
+    size_t operator()(const Alias& t) const { return utils::Hash(t.name); }
 };
 
 struct StructHasher {
-  size_t operator()(const Struct& t) const { return utils::Hash(t.name); }
+    size_t operator()(const Struct& t) const { return utils::Hash(t.name); }
 };
 
 struct SamplerHasher {
-  size_t operator()(const Sampler& s) const { return utils::Hash(s.kind); }
+    size_t operator()(const Sampler& s) const { return utils::Hash(s.kind); }
 };
 
 struct DepthTextureHasher {
-  size_t operator()(const DepthTexture& t) const { return utils::Hash(t.dims); }
+    size_t operator()(const DepthTexture& t) const { return utils::Hash(t.dims); }
 };
 
 struct DepthMultisampledTextureHasher {
-  size_t operator()(const DepthMultisampledTexture& t) const {
-    return utils::Hash(t.dims);
-  }
+    size_t operator()(const DepthMultisampledTexture& t) const { return utils::Hash(t.dims); }
 };
 
 struct MultisampledTextureHasher {
-  size_t operator()(const MultisampledTexture& t) const {
-    return utils::Hash(t.dims, t.type);
-  }
+    size_t operator()(const MultisampledTexture& t) const { return utils::Hash(t.dims, t.type); }
 };
 
 struct SampledTextureHasher {
-  size_t operator()(const SampledTexture& t) const {
-    return utils::Hash(t.dims, t.type);
-  }
+    size_t operator()(const SampledTexture& t) const { return utils::Hash(t.dims, t.type); }
 };
 
 struct StorageTextureHasher {
-  size_t operator()(const StorageTexture& t) const {
-    return utils::Hash(t.dims, t.format, t.access);
-  }
+    size_t operator()(const StorageTexture& t) const {
+        return utils::Hash(t.dims, t.format, t.access);
+    }
 };
 }  // namespace
 
 // Equality operators
 //! @cond Doxygen_Suppress
 static bool operator==(const Pointer& a, const Pointer& b) {
-  return a.type == b.type && a.storage_class == b.storage_class;
+    return a.type == b.type && a.storage_class == b.storage_class;
 }
 static bool operator==(const Reference& a, const Reference& b) {
-  return a.type == b.type && a.storage_class == b.storage_class;
+    return a.type == b.type && a.storage_class == b.storage_class;
 }
 static bool operator==(const Vector& a, const Vector& b) {
-  return a.type == b.type && a.size == b.size;
+    return a.type == b.type && a.size == b.size;
 }
 static bool operator==(const Matrix& a, const Matrix& b) {
-  return a.type == b.type && a.columns == b.columns && a.rows == b.rows;
+    return a.type == b.type && a.columns == b.columns && a.rows == b.rows;
 }
 static bool operator==(const Array& a, const Array& b) {
-  return a.type == b.type && a.size == b.size && a.stride == b.stride;
+    return a.type == b.type && a.size == b.size && a.stride == b.stride;
 }
 static bool operator==(const Named& a, const Named& b) {
-  return a.name == b.name;
+    return a.name == b.name;
 }
 static bool operator==(const Sampler& a, const Sampler& b) {
-  return a.kind == b.kind;
+    return a.kind == b.kind;
 }
 static bool operator==(const DepthTexture& a, const DepthTexture& b) {
-  return a.dims == b.dims;
+    return a.dims == b.dims;
 }
-static bool operator==(const DepthMultisampledTexture& a,
-                       const DepthMultisampledTexture& b) {
-  return a.dims == b.dims;
+static bool operator==(const DepthMultisampledTexture& a, const DepthMultisampledTexture& b) {
+    return a.dims == b.dims;
 }
-static bool operator==(const MultisampledTexture& a,
-                       const MultisampledTexture& b) {
-  return a.dims == b.dims && a.type == b.type;
+static bool operator==(const MultisampledTexture& a, const MultisampledTexture& b) {
+    return a.dims == b.dims && a.type == b.type;
 }
 static bool operator==(const SampledTexture& a, const SampledTexture& b) {
-  return a.dims == b.dims && a.type == b.type;
+    return a.dims == b.dims && a.type == b.type;
 }
 static bool operator==(const StorageTexture& a, const StorageTexture& b) {
-  return a.dims == b.dims && a.format == b.format;
+    return a.dims == b.dims && a.format == b.format;
 }
 //! @endcond
 
 const ast::Type* Void::Build(ProgramBuilder& b) const {
-  return b.ty.void_();
+    return b.ty.void_();
 }
 
 const ast::Type* Bool::Build(ProgramBuilder& b) const {
-  return b.ty.bool_();
+    return b.ty.bool_();
 }
 
 const ast::Type* U32::Build(ProgramBuilder& b) const {
-  return b.ty.u32();
+    return b.ty.u32();
 }
 
 const ast::Type* F32::Build(ProgramBuilder& b) const {
-  return b.ty.f32();
+    return b.ty.f32();
 }
 
 const ast::Type* I32::Build(ProgramBuilder& b) const {
-  return b.ty.i32();
+    return b.ty.i32();
 }
 
-Pointer::Pointer(const Type* t, ast::StorageClass s)
-    : type(t), storage_class(s) {}
+Pointer::Pointer(const Type* t, ast::StorageClass s) : type(t), storage_class(s) {}
 Pointer::Pointer(const Pointer&) = default;
 
 const ast::Type* Pointer::Build(ProgramBuilder& b) const {
-  return b.ty.pointer(type->Build(b), storage_class);
+    return b.ty.pointer(type->Build(b), storage_class);
 }
 
-Reference::Reference(const Type* t, ast::StorageClass s)
-    : type(t), storage_class(s) {}
+Reference::Reference(const Type* t, ast::StorageClass s) : type(t), storage_class(s) {}
 Reference::Reference(const Reference&) = default;
 
 const ast::Type* Reference::Build(ProgramBuilder& b) const {
-  return type->Build(b);
+    return type->Build(b);
 }
 
 Vector::Vector(const Type* t, uint32_t s) : type(t), size(s) {}
 Vector::Vector(const Vector&) = default;
 
 const ast::Type* Vector::Build(ProgramBuilder& b) const {
-  return b.ty.vec(type->Build(b), size);
+    return b.ty.vec(type->Build(b), size);
 }
 
-Matrix::Matrix(const Type* t, uint32_t c, uint32_t r)
-    : type(t), columns(c), rows(r) {}
+Matrix::Matrix(const Type* t, uint32_t c, uint32_t r) : type(t), columns(c), rows(r) {}
 Matrix::Matrix(const Matrix&) = default;
 
 const ast::Type* Matrix::Build(ProgramBuilder& b) const {
-  return b.ty.mat(type->Build(b), columns, rows);
+    return b.ty.mat(type->Build(b), columns, rows);
 }
 
-Array::Array(const Type* t, uint32_t sz, uint32_t st)
-    : type(t), size(sz), stride(st) {}
+Array::Array(const Type* t, uint32_t sz, uint32_t st) : type(t), size(sz), stride(st) {}
 Array::Array(const Array&) = default;
 
 const ast::Type* Array::Build(ProgramBuilder& b) const {
-  if (size > 0) {
-    return b.ty.array(type->Build(b), size, stride);
-  } else {
-    return b.ty.array(type->Build(b), nullptr, stride);
-  }
+    if (size > 0) {
+        return b.ty.array(type->Build(b), u32(size), stride);
+    } else {
+        return b.ty.array(type->Build(b), nullptr, stride);
+    }
 }
 
 Sampler::Sampler(ast::SamplerKind k) : kind(k) {}
 Sampler::Sampler(const Sampler&) = default;
 
 const ast::Type* Sampler::Build(ProgramBuilder& b) const {
-  return b.ty.sampler(kind);
+    return b.ty.sampler(kind);
 }
 
 Texture::Texture(ast::TextureDimension d) : dims(d) {}
@@ -238,16 +216,14 @@
 DepthTexture::DepthTexture(const DepthTexture&) = default;
 
 const ast::Type* DepthTexture::Build(ProgramBuilder& b) const {
-  return b.ty.depth_texture(dims);
+    return b.ty.depth_texture(dims);
 }
 
-DepthMultisampledTexture::DepthMultisampledTexture(ast::TextureDimension d)
-    : Base(d) {}
-DepthMultisampledTexture::DepthMultisampledTexture(
-    const DepthMultisampledTexture&) = default;
+DepthMultisampledTexture::DepthMultisampledTexture(ast::TextureDimension d) : Base(d) {}
+DepthMultisampledTexture::DepthMultisampledTexture(const DepthMultisampledTexture&) = default;
 
 const ast::Type* DepthMultisampledTexture::Build(ProgramBuilder& b) const {
-  return b.ty.depth_multisampled_texture(dims);
+    return b.ty.depth_multisampled_texture(dims);
 }
 
 MultisampledTexture::MultisampledTexture(ast::TextureDimension d, const Type* t)
@@ -255,25 +231,22 @@
 MultisampledTexture::MultisampledTexture(const MultisampledTexture&) = default;
 
 const ast::Type* MultisampledTexture::Build(ProgramBuilder& b) const {
-  return b.ty.multisampled_texture(dims, type->Build(b));
+    return b.ty.multisampled_texture(dims, type->Build(b));
 }
 
-SampledTexture::SampledTexture(ast::TextureDimension d, const Type* t)
-    : Base(d), type(t) {}
+SampledTexture::SampledTexture(ast::TextureDimension d, const Type* t) : Base(d), type(t) {}
 SampledTexture::SampledTexture(const SampledTexture&) = default;
 
 const ast::Type* SampledTexture::Build(ProgramBuilder& b) const {
-  return b.ty.sampled_texture(dims, type->Build(b));
+    return b.ty.sampled_texture(dims, type->Build(b));
 }
 
-StorageTexture::StorageTexture(ast::TextureDimension d,
-                               ast::TexelFormat f,
-                               ast::Access a)
+StorageTexture::StorageTexture(ast::TextureDimension d, ast::TexelFormat f, ast::Access a)
     : Base(d), format(f), access(a) {}
 StorageTexture::StorageTexture(const StorageTexture&) = default;
 
 const ast::Type* StorageTexture::Build(ProgramBuilder& b) const {
-  return b.ty.storage_texture(dims, format, access);
+    return b.ty.storage_texture(dims, format, access);
 }
 
 Named::Named(Symbol n) : name(n) {}
@@ -284,7 +257,7 @@
 Alias::Alias(const Alias&) = default;
 
 const ast::Type* Alias::Build(ProgramBuilder& b) const {
-  return b.ty.type_name(name);
+    return b.ty.type_name(name);
 }
 
 Struct::Struct(Symbol n, TypeList m) : Base(n), members(std::move(m)) {}
@@ -292,339 +265,323 @@
 Struct::~Struct() = default;
 
 const ast::Type* Struct::Build(ProgramBuilder& b) const {
-  return b.ty.type_name(name);
+    return b.ty.type_name(name);
 }
 
 /// The PIMPL state of the Types object.
 struct TypeManager::State {
-  /// The allocator of primitive types
-  utils::BlockAllocator<Type> allocator_;
-  /// The lazily-created Void type
-  spirv::Void const* void_ = nullptr;
-  /// The lazily-created Bool type
-  spirv::Bool const* bool_ = nullptr;
-  /// The lazily-created U32 type
-  spirv::U32 const* u32_ = nullptr;
-  /// The lazily-created F32 type
-  spirv::F32 const* f32_ = nullptr;
-  /// The lazily-created I32 type
-  spirv::I32 const* i32_ = nullptr;
-  /// Unique Pointer instances
-  utils::UniqueAllocator<spirv::Pointer, PointerHasher> pointers_;
-  /// Unique Reference instances
-  utils::UniqueAllocator<spirv::Reference, ReferenceHasher> references_;
-  /// Unique Vector instances
-  utils::UniqueAllocator<spirv::Vector, VectorHasher> vectors_;
-  /// Unique Matrix instances
-  utils::UniqueAllocator<spirv::Matrix, MatrixHasher> matrices_;
-  /// Unique Array instances
-  utils::UniqueAllocator<spirv::Array, ArrayHasher> arrays_;
-  /// Unique Alias instances
-  utils::UniqueAllocator<spirv::Alias, AliasHasher> aliases_;
-  /// Unique Struct instances
-  utils::UniqueAllocator<spirv::Struct, StructHasher> structs_;
-  /// Unique Sampler instances
-  utils::UniqueAllocator<spirv::Sampler, SamplerHasher> samplers_;
-  /// Unique DepthTexture instances
-  utils::UniqueAllocator<spirv::DepthTexture, DepthTextureHasher>
-      depth_textures_;
-  /// Unique DepthMultisampledTexture instances
-  utils::UniqueAllocator<spirv::DepthMultisampledTexture,
-                         DepthMultisampledTextureHasher>
-      depth_multisampled_textures_;
-  /// Unique MultisampledTexture instances
-  utils::UniqueAllocator<spirv::MultisampledTexture, MultisampledTextureHasher>
-      multisampled_textures_;
-  /// Unique SampledTexture instances
-  utils::UniqueAllocator<spirv::SampledTexture, SampledTextureHasher>
-      sampled_textures_;
-  /// Unique StorageTexture instances
-  utils::UniqueAllocator<spirv::StorageTexture, StorageTextureHasher>
-      storage_textures_;
+    /// The allocator of primitive types
+    utils::BlockAllocator<Type> allocator_;
+    /// The lazily-created Void type
+    spirv::Void const* void_ = nullptr;
+    /// The lazily-created Bool type
+    spirv::Bool const* bool_ = nullptr;
+    /// The lazily-created U32 type
+    spirv::U32 const* u32_ = nullptr;
+    /// The lazily-created F32 type
+    spirv::F32 const* f32_ = nullptr;
+    /// The lazily-created I32 type
+    spirv::I32 const* i32_ = nullptr;
+    /// Unique Pointer instances
+    utils::UniqueAllocator<spirv::Pointer, PointerHasher> pointers_;
+    /// Unique Reference instances
+    utils::UniqueAllocator<spirv::Reference, ReferenceHasher> references_;
+    /// Unique Vector instances
+    utils::UniqueAllocator<spirv::Vector, VectorHasher> vectors_;
+    /// Unique Matrix instances
+    utils::UniqueAllocator<spirv::Matrix, MatrixHasher> matrices_;
+    /// Unique Array instances
+    utils::UniqueAllocator<spirv::Array, ArrayHasher> arrays_;
+    /// Unique Alias instances
+    utils::UniqueAllocator<spirv::Alias, AliasHasher> aliases_;
+    /// Unique Struct instances
+    utils::UniqueAllocator<spirv::Struct, StructHasher> structs_;
+    /// Unique Sampler instances
+    utils::UniqueAllocator<spirv::Sampler, SamplerHasher> samplers_;
+    /// Unique DepthTexture instances
+    utils::UniqueAllocator<spirv::DepthTexture, DepthTextureHasher> depth_textures_;
+    /// Unique DepthMultisampledTexture instances
+    utils::UniqueAllocator<spirv::DepthMultisampledTexture, DepthMultisampledTextureHasher>
+        depth_multisampled_textures_;
+    /// Unique MultisampledTexture instances
+    utils::UniqueAllocator<spirv::MultisampledTexture, MultisampledTextureHasher>
+        multisampled_textures_;
+    /// Unique SampledTexture instances
+    utils::UniqueAllocator<spirv::SampledTexture, SampledTextureHasher> sampled_textures_;
+    /// Unique StorageTexture instances
+    utils::UniqueAllocator<spirv::StorageTexture, StorageTextureHasher> storage_textures_;
 };
 
 const Type* Type::UnwrapPtr() const {
-  const Type* type = this;
-  while (auto* ptr = type->As<Pointer>()) {
-    type = ptr->type;
-  }
-  return type;
+    const Type* type = this;
+    while (auto* ptr = type->As<Pointer>()) {
+        type = ptr->type;
+    }
+    return type;
 }
 
 const Type* Type::UnwrapRef() const {
-  const Type* type = this;
-  while (auto* ptr = type->As<Reference>()) {
-    type = ptr->type;
-  }
-  return type;
+    const Type* type = this;
+    while (auto* ptr = type->As<Reference>()) {
+        type = ptr->type;
+    }
+    return type;
 }
 
 const Type* Type::UnwrapAlias() const {
-  const Type* type = this;
-  while (auto* alias = type->As<Alias>()) {
-    type = alias->type;
-  }
-  return type;
+    const Type* type = this;
+    while (auto* alias = type->As<Alias>()) {
+        type = alias->type;
+    }
+    return type;
 }
 
 const Type* Type::UnwrapAll() const {
-  auto* type = this;
-  while (true) {
-    if (auto* alias = type->As<Alias>()) {
-      type = alias->type;
-    } else if (auto* ptr = type->As<Pointer>()) {
-      type = ptr->type;
-    } else {
-      break;
+    auto* type = this;
+    while (true) {
+        if (auto* alias = type->As<Alias>()) {
+            type = alias->type;
+        } else if (auto* ptr = type->As<Pointer>()) {
+            type = ptr->type;
+        } else {
+            break;
+        }
     }
-  }
-  return type;
+    return type;
 }
 
 bool Type::IsFloatScalar() const {
-  return Is<F32>();
+    return Is<F32>();
 }
 
 bool Type::IsFloatScalarOrVector() const {
-  return IsFloatScalar() || IsFloatVector();
+    return IsFloatScalar() || IsFloatVector();
 }
 
 bool Type::IsFloatVector() const {
-  return Is([](const Vector* v) { return v->type->IsFloatScalar(); });
+    return Is([](const Vector* v) { return v->type->IsFloatScalar(); });
 }
 
 bool Type::IsIntegerScalar() const {
-  return IsAnyOf<U32, I32>();
+    return IsAnyOf<U32, I32>();
 }
 
 bool Type::IsIntegerScalarOrVector() const {
-  return IsUnsignedScalarOrVector() || IsSignedScalarOrVector();
+    return IsUnsignedScalarOrVector() || IsSignedScalarOrVector();
 }
 
 bool Type::IsScalar() const {
-  return IsAnyOf<F32, U32, I32, Bool>();
+    return IsAnyOf<F32, U32, I32, Bool>();
 }
 
 bool Type::IsSignedIntegerVector() const {
-  return Is([](const Vector* v) { return v->type->Is<I32>(); });
+    return Is([](const Vector* v) { return v->type->Is<I32>(); });
 }
 
 bool Type::IsSignedScalarOrVector() const {
-  return Is<I32>() || IsSignedIntegerVector();
+    return Is<I32>() || IsSignedIntegerVector();
 }
 
 bool Type::IsUnsignedIntegerVector() const {
-  return Is([](const Vector* v) { return v->type->Is<U32>(); });
+    return Is([](const Vector* v) { return v->type->Is<U32>(); });
 }
 
 bool Type::IsUnsignedScalarOrVector() const {
-  return Is<U32>() || IsUnsignedIntegerVector();
+    return Is<U32>() || IsUnsignedIntegerVector();
 }
 
 TypeManager::TypeManager() {
-  state = std::make_unique<State>();
+    state = std::make_unique<State>();
 }
 
 TypeManager::~TypeManager() = default;
 
 const spirv::Void* TypeManager::Void() {
-  if (!state->void_) {
-    state->void_ = state->allocator_.Create<spirv::Void>();
-  }
-  return state->void_;
+    if (!state->void_) {
+        state->void_ = state->allocator_.Create<spirv::Void>();
+    }
+    return state->void_;
 }
 
 const spirv::Bool* TypeManager::Bool() {
-  if (!state->bool_) {
-    state->bool_ = state->allocator_.Create<spirv::Bool>();
-  }
-  return state->bool_;
+    if (!state->bool_) {
+        state->bool_ = state->allocator_.Create<spirv::Bool>();
+    }
+    return state->bool_;
 }
 
 const spirv::U32* TypeManager::U32() {
-  if (!state->u32_) {
-    state->u32_ = state->allocator_.Create<spirv::U32>();
-  }
-  return state->u32_;
+    if (!state->u32_) {
+        state->u32_ = state->allocator_.Create<spirv::U32>();
+    }
+    return state->u32_;
 }
 
 const spirv::F32* TypeManager::F32() {
-  if (!state->f32_) {
-    state->f32_ = state->allocator_.Create<spirv::F32>();
-  }
-  return state->f32_;
+    if (!state->f32_) {
+        state->f32_ = state->allocator_.Create<spirv::F32>();
+    }
+    return state->f32_;
 }
 
 const spirv::I32* TypeManager::I32() {
-  if (!state->i32_) {
-    state->i32_ = state->allocator_.Create<spirv::I32>();
-  }
-  return state->i32_;
+    if (!state->i32_) {
+        state->i32_ = state->allocator_.Create<spirv::I32>();
+    }
+    return state->i32_;
 }
 
-const spirv::Pointer* TypeManager::Pointer(const Type* el,
-                                           ast::StorageClass sc) {
-  return state->pointers_.Get(el, sc);
+const spirv::Pointer* TypeManager::Pointer(const Type* el, ast::StorageClass sc) {
+    return state->pointers_.Get(el, sc);
 }
 
-const spirv::Reference* TypeManager::Reference(const Type* el,
-                                               ast::StorageClass sc) {
-  return state->references_.Get(el, sc);
+const spirv::Reference* TypeManager::Reference(const Type* el, ast::StorageClass sc) {
+    return state->references_.Get(el, sc);
 }
 
 const spirv::Vector* TypeManager::Vector(const Type* el, uint32_t size) {
-  return state->vectors_.Get(el, size);
+    return state->vectors_.Get(el, size);
 }
 
-const spirv::Matrix* TypeManager::Matrix(const Type* el,
-                                         uint32_t columns,
-                                         uint32_t rows) {
-  return state->matrices_.Get(el, columns, rows);
+const spirv::Matrix* TypeManager::Matrix(const Type* el, uint32_t columns, uint32_t rows) {
+    return state->matrices_.Get(el, columns, rows);
 }
 
-const spirv::Array* TypeManager::Array(const Type* el,
-                                       uint32_t size,
-                                       uint32_t stride) {
-  return state->arrays_.Get(el, size, stride);
+const spirv::Array* TypeManager::Array(const Type* el, uint32_t size, uint32_t stride) {
+    return state->arrays_.Get(el, size, stride);
 }
 
 const spirv::Alias* TypeManager::Alias(Symbol name, const Type* ty) {
-  return state->aliases_.Get(name, ty);
+    return state->aliases_.Get(name, ty);
 }
 
 const spirv::Struct* TypeManager::Struct(Symbol name, TypeList members) {
-  return state->structs_.Get(name, std::move(members));
+    return state->structs_.Get(name, std::move(members));
 }
 
 const spirv::Sampler* TypeManager::Sampler(ast::SamplerKind kind) {
-  return state->samplers_.Get(kind);
+    return state->samplers_.Get(kind);
 }
 
-const spirv::DepthTexture* TypeManager::DepthTexture(
-    ast::TextureDimension dims) {
-  return state->depth_textures_.Get(dims);
+const spirv::DepthTexture* TypeManager::DepthTexture(ast::TextureDimension dims) {
+    return state->depth_textures_.Get(dims);
 }
 
 const spirv::DepthMultisampledTexture* TypeManager::DepthMultisampledTexture(
     ast::TextureDimension dims) {
-  return state->depth_multisampled_textures_.Get(dims);
+    return state->depth_multisampled_textures_.Get(dims);
 }
 
-const spirv::MultisampledTexture* TypeManager::MultisampledTexture(
-    ast::TextureDimension dims,
-    const Type* ty) {
-  return state->multisampled_textures_.Get(dims, ty);
+const spirv::MultisampledTexture* TypeManager::MultisampledTexture(ast::TextureDimension dims,
+                                                                   const Type* ty) {
+    return state->multisampled_textures_.Get(dims, ty);
 }
 
-const spirv::SampledTexture* TypeManager::SampledTexture(
-    ast::TextureDimension dims,
-    const Type* ty) {
-  return state->sampled_textures_.Get(dims, ty);
+const spirv::SampledTexture* TypeManager::SampledTexture(ast::TextureDimension dims,
+                                                         const Type* ty) {
+    return state->sampled_textures_.Get(dims, ty);
 }
 
-const spirv::StorageTexture* TypeManager::StorageTexture(
-    ast::TextureDimension dims,
-    ast::TexelFormat fmt,
-    ast::Access access) {
-  return state->storage_textures_.Get(dims, fmt, access);
+const spirv::StorageTexture* TypeManager::StorageTexture(ast::TextureDimension dims,
+                                                         ast::TexelFormat fmt,
+                                                         ast::Access access) {
+    return state->storage_textures_.Get(dims, fmt, access);
 }
 
 // Debug String() methods for Type classes. Only enabled in debug builds.
 #ifndef NDEBUG
 std::string Void::String() const {
-  return "void";
+    return "void";
 }
 
 std::string Bool::String() const {
-  return "bool";
+    return "bool";
 }
 
 std::string U32::String() const {
-  return "u32";
+    return "u32";
 }
 
 std::string F32::String() const {
-  return "f32";
+    return "f32";
 }
 
 std::string I32::String() const {
-  return "i32";
+    return "i32";
 }
 
 std::string Pointer::String() const {
-  std::stringstream ss;
-  ss << "ptr<" << std::string(ast::ToString(storage_class)) << ", "
-     << type->String() + ">";
-  return ss.str();
+    std::stringstream ss;
+    ss << "ptr<" << std::string(ast::ToString(storage_class)) << ", " << type->String() + ">";
+    return ss.str();
 }
 
 std::string Reference::String() const {
-  std::stringstream ss;
-  ss << "ref<" + std::string(ast::ToString(storage_class)) << ", "
-     << type->String() << ">";
-  return ss.str();
+    std::stringstream ss;
+    ss << "ref<" + std::string(ast::ToString(storage_class)) << ", " << type->String() << ">";
+    return ss.str();
 }
 
 std::string Vector::String() const {
-  std::stringstream ss;
-  ss << "vec" << size << "<" << type->String() << ">";
-  return ss.str();
+    std::stringstream ss;
+    ss << "vec" << size << "<" << type->String() << ">";
+    return ss.str();
 }
 
 std::string Matrix::String() const {
-  std::stringstream ss;
-  ss << "mat" << columns << "x" << rows << "<" << type->String() << ">";
-  return ss.str();
+    std::stringstream ss;
+    ss << "mat" << columns << "x" << rows << "<" << type->String() << ">";
+    return ss.str();
 }
 
 std::string Array::String() const {
-  std::stringstream ss;
-  ss << "array<" << type->String() << ", " << size << ", " << stride << ">";
-  return ss.str();
+    std::stringstream ss;
+    ss << "array<" << type->String() << ", " << size << ", " << stride << ">";
+    return ss.str();
 }
 
 std::string Sampler::String() const {
-  switch (kind) {
-    case ast::SamplerKind::kSampler:
-      return "sampler";
-    case ast::SamplerKind::kComparisonSampler:
-      return "sampler_comparison";
-  }
-  return "<unknown sampler>";
+    switch (kind) {
+        case ast::SamplerKind::kSampler:
+            return "sampler";
+        case ast::SamplerKind::kComparisonSampler:
+            return "sampler_comparison";
+    }
+    return "<unknown sampler>";
 }
 
 std::string DepthTexture::String() const {
-  std::stringstream ss;
-  ss << "depth_" << dims;
-  return ss.str();
+    std::stringstream ss;
+    ss << "depth_" << dims;
+    return ss.str();
 }
 
 std::string DepthMultisampledTexture::String() const {
-  std::stringstream ss;
-  ss << "depth_multisampled_" << dims;
-  return ss.str();
+    std::stringstream ss;
+    ss << "depth_multisampled_" << dims;
+    return ss.str();
 }
 
 std::string MultisampledTexture::String() const {
-  std::stringstream ss;
-  ss << "texture_multisampled_" << dims << "<" << type << ">";
-  return ss.str();
+    std::stringstream ss;
+    ss << "texture_multisampled_" << dims << "<" << type << ">";
+    return ss.str();
 }
 
 std::string SampledTexture::String() const {
-  std::stringstream ss;
-  ss << "texture_" << dims << "<" << type << ">";
-  return ss.str();
+    std::stringstream ss;
+    ss << "texture_" << dims << "<" << type << ">";
+    return ss.str();
 }
 
 std::string StorageTexture::String() const {
-  std::stringstream ss;
-  ss << "texture_storage_" << dims << "<" << format << ", " << access << ">";
-  return ss.str();
+    std::stringstream ss;
+    ss << "texture_storage_" << dims << "<" << format << ", " << access << ">";
+    return ss.str();
 }
 
 std::string Named::String() const {
-  return name.to_str();
+    return name.to_str();
 }
 #endif  // NDEBUG
 
diff --git a/src/tint/reader/spirv/parser_type.h b/src/tint/reader/spirv/parser_type.h
index 6225a85..605ac9b 100644
--- a/src/tint/reader/spirv/parser_type.h
+++ b/src/tint/reader/spirv/parser_type.h
@@ -39,51 +39,51 @@
 
 /// Type is the base class for all types
 class Type : public Castable<Type> {
- public:
-  /// @param b the ProgramBuilder used to construct the AST types
-  /// @returns the constructed ast::Type node for the given type
-  virtual const ast::Type* Build(ProgramBuilder& b) const = 0;
+  public:
+    /// @param b the ProgramBuilder used to construct the AST types
+    /// @returns the constructed ast::Type node for the given type
+    virtual const ast::Type* Build(ProgramBuilder& b) const = 0;
 
-  /// @returns the inner most store type if this is a pointer, `this` otherwise
-  const Type* UnwrapPtr() const;
+    /// @returns the inner most store type if this is a pointer, `this` otherwise
+    const Type* UnwrapPtr() const;
 
-  /// @returns the inner most store type if this is a reference, `this`
-  /// otherwise
-  const Type* UnwrapRef() const;
+    /// @returns the inner most store type if this is a reference, `this`
+    /// otherwise
+    const Type* UnwrapRef() const;
 
-  /// @returns the inner most aliased type if this is an alias, `this` otherwise
-  const Type* UnwrapAlias() const;
+    /// @returns the inner most aliased type if this is an alias, `this` otherwise
+    const Type* UnwrapAlias() const;
 
-  /// @returns the type with all aliasing, access control and pointers removed
-  const Type* UnwrapAll() const;
+    /// @returns the type with all aliasing, access control and pointers removed
+    const Type* UnwrapAll() const;
 
-  /// @returns true if this type is a float scalar
-  bool IsFloatScalar() const;
-  /// @returns true if this type is a float scalar or vector
-  bool IsFloatScalarOrVector() const;
-  /// @returns true if this type is a float vector
-  bool IsFloatVector() const;
-  /// @returns true if this type is an integer scalar
-  bool IsIntegerScalar() const;
-  /// @returns true if this type is an integer scalar or vector
-  bool IsIntegerScalarOrVector() const;
-  /// @returns true if this type is a scalar
-  bool IsScalar() const;
-  /// @returns true if this type is a signed integer vector
-  bool IsSignedIntegerVector() const;
-  /// @returns true if this type is a signed scalar or vector
-  bool IsSignedScalarOrVector() const;
-  /// @returns true if this type is an unsigned integer vector
-  bool IsUnsignedIntegerVector() const;
-  /// @returns true if this type is an unsigned scalar or vector
-  bool IsUnsignedScalarOrVector() const;
+    /// @returns true if this type is a float scalar
+    bool IsFloatScalar() const;
+    /// @returns true if this type is a float scalar or vector
+    bool IsFloatScalarOrVector() const;
+    /// @returns true if this type is a float vector
+    bool IsFloatVector() const;
+    /// @returns true if this type is an integer scalar
+    bool IsIntegerScalar() const;
+    /// @returns true if this type is an integer scalar or vector
+    bool IsIntegerScalarOrVector() const;
+    /// @returns true if this type is a scalar
+    bool IsScalar() const;
+    /// @returns true if this type is a signed integer vector
+    bool IsSignedIntegerVector() const;
+    /// @returns true if this type is a signed scalar or vector
+    bool IsSignedScalarOrVector() const;
+    /// @returns true if this type is an unsigned integer vector
+    bool IsUnsignedIntegerVector() const;
+    /// @returns true if this type is an unsigned scalar or vector
+    bool IsUnsignedScalarOrVector() const;
 
 #ifdef NDEBUG
-  /// @returns "<no-type-info>", for debug purposes only
-  std::string String() const { return "<no-type-info>"; }
+    /// @returns "<no-type-info>", for debug purposes only
+    std::string String() const { return "<no-type-info>"; }
 #else
-  /// @returns a string representation of the type, for debug purposes only
-  virtual std::string String() const = 0;
+    /// @returns a string representation of the type, for debug purposes only
+    virtual std::string String() const = 0;
 #endif  // NDEBUG
 };
 
@@ -92,515 +92,510 @@
 
 /// `void` type
 struct Void final : public Castable<Void, Type> {
-  /// @param b the ProgramBuilder used to construct the AST types
-  /// @returns the constructed ast::Type node for the given type
-  const ast::Type* Build(ProgramBuilder& b) const override;
+    /// @param b the ProgramBuilder used to construct the AST types
+    /// @returns the constructed ast::Type node for the given type
+    const ast::Type* Build(ProgramBuilder& b) const override;
 
 #ifndef NDEBUG
-  /// @returns a string representation of the type, for debug purposes only
-  std::string String() const override;
+    /// @returns a string representation of the type, for debug purposes only
+    std::string String() const override;
 #endif  // NDEBUG
 };
 
 /// `bool` type
 struct Bool final : public Castable<Bool, Type> {
-  /// @param b the ProgramBuilder used to construct the AST types
-  /// @returns the constructed ast::Type node for the given type
-  const ast::Type* Build(ProgramBuilder& b) const override;
+    /// @param b the ProgramBuilder used to construct the AST types
+    /// @returns the constructed ast::Type node for the given type
+    const ast::Type* Build(ProgramBuilder& b) const override;
 
 #ifndef NDEBUG
-  /// @returns a string representation of the type, for debug purposes only
-  std::string String() const override;
+    /// @returns a string representation of the type, for debug purposes only
+    std::string String() const override;
 #endif  // NDEBUG
 };
 
 /// `u32` type
 struct U32 final : public Castable<U32, Type> {
-  /// @param b the ProgramBuilder used to construct the AST types
-  /// @returns the constructed ast::Type node for the given type
-  const ast::Type* Build(ProgramBuilder& b) const override;
+    /// @param b the ProgramBuilder used to construct the AST types
+    /// @returns the constructed ast::Type node for the given type
+    const ast::Type* Build(ProgramBuilder& b) const override;
 
 #ifndef NDEBUG
-  /// @returns a string representation of the type, for debug purposes only
-  std::string String() const override;
+    /// @returns a string representation of the type, for debug purposes only
+    std::string String() const override;
 #endif  // NDEBUG
 };
 
 /// `f32` type
 struct F32 final : public Castable<F32, Type> {
-  /// @param b the ProgramBuilder used to construct the AST types
-  /// @returns the constructed ast::Type node for the given type
-  const ast::Type* Build(ProgramBuilder& b) const override;
+    /// @param b the ProgramBuilder used to construct the AST types
+    /// @returns the constructed ast::Type node for the given type
+    const ast::Type* Build(ProgramBuilder& b) const override;
 
 #ifndef NDEBUG
-  /// @returns a string representation of the type, for debug purposes only
-  std::string String() const override;
+    /// @returns a string representation of the type, for debug purposes only
+    std::string String() const override;
 #endif  // NDEBUG
 };
 
 /// `i32` type
 struct I32 final : public Castable<I32, Type> {
-  /// @param b the ProgramBuilder used to construct the AST types
-  /// @returns the constructed ast::Type node for the given type
-  const ast::Type* Build(ProgramBuilder& b) const override;
+    /// @param b the ProgramBuilder used to construct the AST types
+    /// @returns the constructed ast::Type node for the given type
+    const ast::Type* Build(ProgramBuilder& b) const override;
 
 #ifndef NDEBUG
-  /// @returns a string representation of the type, for debug purposes only
-  std::string String() const override;
+    /// @returns a string representation of the type, for debug purposes only
+    std::string String() const override;
 #endif  // NDEBUG
 };
 
 /// `ptr<SC, T>` type
 struct Pointer final : public Castable<Pointer, Type> {
-  /// Constructor
-  /// @param ty the store type
-  /// @param sc the pointer storage class
-  Pointer(const Type* ty, ast::StorageClass sc);
+    /// Constructor
+    /// @param ty the store type
+    /// @param sc the pointer storage class
+    Pointer(const Type* ty, ast::StorageClass sc);
 
-  /// Copy constructor
-  /// @param other the other type to copy
-  Pointer(const Pointer& other);
+    /// Copy constructor
+    /// @param other the other type to copy
+    Pointer(const Pointer& other);
 
-  /// @param b the ProgramBuilder used to construct the AST types
-  /// @returns the constructed ast::Type node for the given type
-  const ast::Type* Build(ProgramBuilder& b) const override;
+    /// @param b the ProgramBuilder used to construct the AST types
+    /// @returns the constructed ast::Type node for the given type
+    const ast::Type* Build(ProgramBuilder& b) const override;
 
 #ifndef NDEBUG
-  /// @returns a string representation of the type, for debug purposes only
-  std::string String() const override;
+    /// @returns a string representation of the type, for debug purposes only
+    std::string String() const override;
 #endif  // NDEBUG
 
-  /// the store type
-  Type const* const type;
-  /// the pointer storage class
-  ast::StorageClass const storage_class;
+    /// the store type
+    Type const* const type;
+    /// the pointer storage class
+    ast::StorageClass const storage_class;
 };
 
 /// `ref<SC, T>` type
 /// Note this has no AST representation, but is used for type tracking in the
 /// reader.
 struct Reference final : public Castable<Reference, Type> {
-  /// Constructor
-  /// @param ty the referenced type
-  /// @param sc the reference storage class
-  Reference(const Type* ty, ast::StorageClass sc);
+    /// Constructor
+    /// @param ty the referenced type
+    /// @param sc the reference storage class
+    Reference(const Type* ty, ast::StorageClass sc);
 
-  /// Copy constructor
-  /// @param other the other type to copy
-  Reference(const Reference& other);
+    /// Copy constructor
+    /// @param other the other type to copy
+    Reference(const Reference& other);
 
-  /// @param b the ProgramBuilder used to construct the AST types
-  /// @returns the constructed ast::Type node for the given type
-  const ast::Type* Build(ProgramBuilder& b) const override;
+    /// @param b the ProgramBuilder used to construct the AST types
+    /// @returns the constructed ast::Type node for the given type
+    const ast::Type* Build(ProgramBuilder& b) const override;
 
 #ifndef NDEBUG
-  /// @returns a string representation of the type, for debug purposes only
-  std::string String() const override;
+    /// @returns a string representation of the type, for debug purposes only
+    std::string String() const override;
 #endif  // NDEBUG
 
-  /// the store type
-  Type const* const type;
-  /// the pointer storage class
-  ast::StorageClass const storage_class;
+    /// the store type
+    Type const* const type;
+    /// the pointer storage class
+    ast::StorageClass const storage_class;
 };
 
 /// `vecN<T>` type
 struct Vector final : public Castable<Vector, Type> {
-  /// Constructor
-  /// @param ty the element type
-  /// @param sz the number of elements in the vector
-  Vector(const Type* ty, uint32_t sz);
+    /// Constructor
+    /// @param ty the element type
+    /// @param sz the number of elements in the vector
+    Vector(const Type* ty, uint32_t sz);
 
-  /// Copy constructor
-  /// @param other the other type to copy
-  Vector(const Vector& other);
+    /// Copy constructor
+    /// @param other the other type to copy
+    Vector(const Vector& other);
 
-  /// @param b the ProgramBuilder used to construct the AST types
-  /// @returns the constructed ast::Type node for the given type
-  const ast::Type* Build(ProgramBuilder& b) const override;
+    /// @param b the ProgramBuilder used to construct the AST types
+    /// @returns the constructed ast::Type node for the given type
+    const ast::Type* Build(ProgramBuilder& b) const override;
 
 #ifndef NDEBUG
-  /// @returns a string representation of the type, for debug purposes only
-  std::string String() const override;
+    /// @returns a string representation of the type, for debug purposes only
+    std::string String() const override;
 #endif  // NDEBUG
 
-  /// the element type
-  Type const* const type;
-  /// the number of elements in the vector
-  const uint32_t size;
+    /// the element type
+    Type const* const type;
+    /// the number of elements in the vector
+    const uint32_t size;
 };
 
 /// `matNxM<T>` type
 struct Matrix final : public Castable<Matrix, Type> {
-  /// Constructor
-  /// @param ty the matrix element type
-  /// @param c the number of columns in the matrix
-  /// @param r the number of rows in the matrix
-  Matrix(const Type* ty, uint32_t c, uint32_t r);
+    /// Constructor
+    /// @param ty the matrix element type
+    /// @param c the number of columns in the matrix
+    /// @param r the number of rows in the matrix
+    Matrix(const Type* ty, uint32_t c, uint32_t r);
 
-  /// Copy constructor
-  /// @param other the other type to copy
-  Matrix(const Matrix& other);
+    /// Copy constructor
+    /// @param other the other type to copy
+    Matrix(const Matrix& other);
 
-  /// @param b the ProgramBuilder used to construct the AST types
-  /// @returns the constructed ast::Type node for the given type
-  const ast::Type* Build(ProgramBuilder& b) const override;
+    /// @param b the ProgramBuilder used to construct the AST types
+    /// @returns the constructed ast::Type node for the given type
+    const ast::Type* Build(ProgramBuilder& b) const override;
 
 #ifndef NDEBUG
-  /// @returns a string representation of the type, for debug purposes only
-  std::string String() const override;
+    /// @returns a string representation of the type, for debug purposes only
+    std::string String() const override;
 #endif  // NDEBUG
 
-  /// the matrix element type
-  Type const* const type;
-  /// the number of columns in the matrix
-  const uint32_t columns;
-  /// the number of rows in the matrix
-  const uint32_t rows;
+    /// the matrix element type
+    Type const* const type;
+    /// the number of columns in the matrix
+    const uint32_t columns;
+    /// the number of rows in the matrix
+    const uint32_t rows;
 };
 
 /// `array<T, N>` type
 struct Array final : public Castable<Array, Type> {
-  /// Constructor
-  /// @param el the element type
-  /// @param sz the number of elements in the array. 0 represents runtime-sized
-  /// array.
-  /// @param st the byte stride of the array. 0 means use implicit stride.
-  Array(const Type* el, uint32_t sz, uint32_t st);
+    /// Constructor
+    /// @param el the element type
+    /// @param sz the number of elements in the array. 0 represents runtime-sized
+    /// array.
+    /// @param st the byte stride of the array. 0 means use implicit stride.
+    Array(const Type* el, uint32_t sz, uint32_t st);
 
-  /// Copy constructor
-  /// @param other the other type to copy
-  Array(const Array& other);
+    /// Copy constructor
+    /// @param other the other type to copy
+    Array(const Array& other);
 
-  /// @param b the ProgramBuilder used to construct the AST types
-  /// @returns the constructed ast::Type node for the given type
-  const ast::Type* Build(ProgramBuilder& b) const override;
+    /// @param b the ProgramBuilder used to construct the AST types
+    /// @returns the constructed ast::Type node for the given type
+    const ast::Type* Build(ProgramBuilder& b) const override;
 
 #ifndef NDEBUG
-  /// @returns a string representation of the type, for debug purposes only
-  std::string String() const override;
+    /// @returns a string representation of the type, for debug purposes only
+    std::string String() const override;
 #endif  // NDEBUG
 
-  /// the element type
-  Type const* const type;
-  /// the number of elements in the array. 0 represents runtime-sized array.
-  const uint32_t size;
-  /// the byte stride of the array
-  const uint32_t stride;
+    /// the element type
+    Type const* const type;
+    /// the number of elements in the array. 0 represents runtime-sized array.
+    const uint32_t size;
+    /// the byte stride of the array
+    const uint32_t stride;
 };
 
 /// `sampler` type
 struct Sampler final : public Castable<Sampler, Type> {
-  /// Constructor
-  /// @param k the sampler kind
-  explicit Sampler(ast::SamplerKind k);
+    /// Constructor
+    /// @param k the sampler kind
+    explicit Sampler(ast::SamplerKind k);
 
-  /// Copy constructor
-  /// @param other the other type to copy
-  Sampler(const Sampler& other);
+    /// Copy constructor
+    /// @param other the other type to copy
+    Sampler(const Sampler& other);
 
-  /// @param b the ProgramBuilder used to construct the AST types
-  /// @returns the constructed ast::Type node for the given type
-  const ast::Type* Build(ProgramBuilder& b) const override;
+    /// @param b the ProgramBuilder used to construct the AST types
+    /// @returns the constructed ast::Type node for the given type
+    const ast::Type* Build(ProgramBuilder& b) const override;
 
 #ifndef NDEBUG
-  /// @returns a string representation of the type, for debug purposes only
-  std::string String() const override;
+    /// @returns a string representation of the type, for debug purposes only
+    std::string String() const override;
 #endif  // NDEBUG
 
-  /// the sampler kind
-  ast::SamplerKind const kind;
+    /// the sampler kind
+    ast::SamplerKind const kind;
 };
 
 /// Base class for texture types
 struct Texture : public Castable<Texture, Type> {
-  /// Constructor
-  /// @param d the texture dimensions
-  explicit Texture(ast::TextureDimension d);
+    /// Constructor
+    /// @param d the texture dimensions
+    explicit Texture(ast::TextureDimension d);
 
-  /// Copy constructor
-  /// @param other the other type to copy
-  Texture(const Texture& other);
+    /// Copy constructor
+    /// @param other the other type to copy
+    Texture(const Texture& other);
 
-  /// the texture dimensions
-  ast::TextureDimension const dims;
+    /// the texture dimensions
+    ast::TextureDimension const dims;
 };
 
 /// `texture_depth_D` type
 struct DepthTexture final : public Castable<DepthTexture, Texture> {
-  /// Constructor
-  /// @param d the texture dimensions
-  explicit DepthTexture(ast::TextureDimension d);
+    /// Constructor
+    /// @param d the texture dimensions
+    explicit DepthTexture(ast::TextureDimension d);
 
-  /// Copy constructor
-  /// @param other the other type to copy
-  DepthTexture(const DepthTexture& other);
+    /// Copy constructor
+    /// @param other the other type to copy
+    DepthTexture(const DepthTexture& other);
 
-  /// @param b the ProgramBuilder used to construct the AST types
-  /// @returns the constructed ast::Type node for the given type
-  const ast::Type* Build(ProgramBuilder& b) const override;
+    /// @param b the ProgramBuilder used to construct the AST types
+    /// @returns the constructed ast::Type node for the given type
+    const ast::Type* Build(ProgramBuilder& b) const override;
 
 #ifndef NDEBUG
-  /// @returns a string representation of the type, for debug purposes only
-  std::string String() const override;
+    /// @returns a string representation of the type, for debug purposes only
+    std::string String() const override;
 #endif  // NDEBUG
 };
 
 /// `texture_depth_multisampled_D` type
-struct DepthMultisampledTexture final
-    : public Castable<DepthMultisampledTexture, Texture> {
-  /// Constructor
-  /// @param d the texture dimensions
-  explicit DepthMultisampledTexture(ast::TextureDimension d);
+struct DepthMultisampledTexture final : public Castable<DepthMultisampledTexture, Texture> {
+    /// Constructor
+    /// @param d the texture dimensions
+    explicit DepthMultisampledTexture(ast::TextureDimension d);
 
-  /// Copy constructor
-  /// @param other the other type to copy
-  DepthMultisampledTexture(const DepthMultisampledTexture& other);
+    /// Copy constructor
+    /// @param other the other type to copy
+    DepthMultisampledTexture(const DepthMultisampledTexture& other);
 
-  /// @param b the ProgramBuilder used to construct the AST types
-  /// @returns the constructed ast::Type node for the given type
-  const ast::Type* Build(ProgramBuilder& b) const override;
+    /// @param b the ProgramBuilder used to construct the AST types
+    /// @returns the constructed ast::Type node for the given type
+    const ast::Type* Build(ProgramBuilder& b) const override;
 
 #ifndef NDEBUG
-  /// @returns a string representation of the type, for debug purposes only
-  std::string String() const override;
+    /// @returns a string representation of the type, for debug purposes only
+    std::string String() const override;
 #endif  // NDEBUG
 };
 
 /// `texture_multisampled_D<T>` type
-struct MultisampledTexture final
-    : public Castable<MultisampledTexture, Texture> {
-  /// Constructor
-  /// @param d the texture dimensions
-  /// @param t the multisampled texture type
-  MultisampledTexture(ast::TextureDimension d, const Type* t);
+struct MultisampledTexture final : public Castable<MultisampledTexture, Texture> {
+    /// Constructor
+    /// @param d the texture dimensions
+    /// @param t the multisampled texture type
+    MultisampledTexture(ast::TextureDimension d, const Type* t);
 
-  /// Copy constructor
-  /// @param other the other type to copy
-  MultisampledTexture(const MultisampledTexture& other);
+    /// Copy constructor
+    /// @param other the other type to copy
+    MultisampledTexture(const MultisampledTexture& other);
 
-  /// @param b the ProgramBuilder used to construct the AST types
-  /// @returns the constructed ast::Type node for the given type
-  const ast::Type* Build(ProgramBuilder& b) const override;
+    /// @param b the ProgramBuilder used to construct the AST types
+    /// @returns the constructed ast::Type node for the given type
+    const ast::Type* Build(ProgramBuilder& b) const override;
 
 #ifndef NDEBUG
-  /// @returns a string representation of the type, for debug purposes only
-  std::string String() const override;
+    /// @returns a string representation of the type, for debug purposes only
+    std::string String() const override;
 #endif  // NDEBUG
 
-  /// the multisampled texture type
-  Type const* const type;
+    /// the multisampled texture type
+    Type const* const type;
 };
 
 /// `texture_D<T>` type
 struct SampledTexture final : public Castable<SampledTexture, Texture> {
-  /// Constructor
-  /// @param d the texture dimensions
-  /// @param t the sampled texture type
-  SampledTexture(ast::TextureDimension d, const Type* t);
+    /// Constructor
+    /// @param d the texture dimensions
+    /// @param t the sampled texture type
+    SampledTexture(ast::TextureDimension d, const Type* t);
 
-  /// Copy constructor
-  /// @param other the other type to copy
-  SampledTexture(const SampledTexture& other);
+    /// Copy constructor
+    /// @param other the other type to copy
+    SampledTexture(const SampledTexture& other);
 
-  /// @param b the ProgramBuilder used to construct the AST types
-  /// @returns the constructed ast::Type node for the given type
-  const ast::Type* Build(ProgramBuilder& b) const override;
+    /// @param b the ProgramBuilder used to construct the AST types
+    /// @returns the constructed ast::Type node for the given type
+    const ast::Type* Build(ProgramBuilder& b) const override;
 
 #ifndef NDEBUG
-  /// @returns a string representation of the type, for debug purposes only
-  std::string String() const override;
+    /// @returns a string representation of the type, for debug purposes only
+    std::string String() const override;
 #endif  // NDEBUG
 
-  /// the sampled texture type
-  Type const* const type;
+    /// the sampled texture type
+    Type const* const type;
 };
 
 /// `texture_storage_D<F>` type
 struct StorageTexture final : public Castable<StorageTexture, Texture> {
-  /// Constructor
-  /// @param d the texture dimensions
-  /// @param f the storage image format
-  /// @param a the access control
-  StorageTexture(ast::TextureDimension d, ast::TexelFormat f, ast::Access a);
+    /// Constructor
+    /// @param d the texture dimensions
+    /// @param f the storage image format
+    /// @param a the access control
+    StorageTexture(ast::TextureDimension d, ast::TexelFormat f, ast::Access a);
 
-  /// Copy constructor
-  /// @param other the other type to copy
-  StorageTexture(const StorageTexture& other);
+    /// Copy constructor
+    /// @param other the other type to copy
+    StorageTexture(const StorageTexture& other);
 
-  /// @param b the ProgramBuilder used to construct the AST types
-  /// @returns the constructed ast::Type node for the given type
-  const ast::Type* Build(ProgramBuilder& b) const override;
+    /// @param b the ProgramBuilder used to construct the AST types
+    /// @returns the constructed ast::Type node for the given type
+    const ast::Type* Build(ProgramBuilder& b) const override;
 
 #ifndef NDEBUG
-  /// @returns a string representation of the type, for debug purposes only
-  std::string String() const override;
+    /// @returns a string representation of the type, for debug purposes only
+    std::string String() const override;
 #endif  // NDEBUG
 
-  /// the storage image format
-  ast::TexelFormat const format;
+    /// the storage image format
+    ast::TexelFormat const format;
 
-  /// the access control
-  ast::Access const access;
+    /// the access control
+    ast::Access const access;
 };
 
 /// Base class for named types
 struct Named : public Castable<Named, Type> {
-  /// Constructor
-  /// @param n the type name
-  explicit Named(Symbol n);
+    /// Constructor
+    /// @param n the type name
+    explicit Named(Symbol n);
 
-  /// Copy constructor
-  /// @param other the other type to copy
-  Named(const Named& other);
+    /// Copy constructor
+    /// @param other the other type to copy
+    Named(const Named& other);
 
-  /// Destructor
-  ~Named() override;
+    /// Destructor
+    ~Named() override;
 
 #ifndef NDEBUG
-  /// @returns a string representation of the type, for debug purposes only
-  std::string String() const override;
+    /// @returns a string representation of the type, for debug purposes only
+    std::string String() const override;
 #endif  // NDEBUG
 
-  /// the type name
-  const Symbol name;
+    /// the type name
+    const Symbol name;
 };
 
 /// `type T = N` type
 struct Alias final : public Castable<Alias, Named> {
-  /// Constructor
-  /// @param n the alias name
-  /// @param t the aliased type
-  Alias(Symbol n, const Type* t);
+    /// Constructor
+    /// @param n the alias name
+    /// @param t the aliased type
+    Alias(Symbol n, const Type* t);
 
-  /// Copy constructor
-  /// @param other the other type to copy
-  Alias(const Alias& other);
+    /// Copy constructor
+    /// @param other the other type to copy
+    Alias(const Alias& other);
 
-  /// @param b the ProgramBuilder used to construct the AST types
-  /// @returns the constructed ast::Type node for the given type
-  const ast::Type* Build(ProgramBuilder& b) const override;
+    /// @param b the ProgramBuilder used to construct the AST types
+    /// @returns the constructed ast::Type node for the given type
+    const ast::Type* Build(ProgramBuilder& b) const override;
 
-  /// the aliased type
-  Type const* const type;
+    /// the aliased type
+    Type const* const type;
 };
 
 /// `struct N { ... };` type
 struct Struct final : public Castable<Struct, Named> {
-  /// Constructor
-  /// @param n the struct name
-  /// @param m the member types
-  Struct(Symbol n, TypeList m);
+    /// Constructor
+    /// @param n the struct name
+    /// @param m the member types
+    Struct(Symbol n, TypeList m);
 
-  /// Copy constructor
-  /// @param other the other type to copy
-  Struct(const Struct& other);
+    /// Copy constructor
+    /// @param other the other type to copy
+    Struct(const Struct& other);
 
-  /// Destructor
-  ~Struct() override;
+    /// Destructor
+    ~Struct() override;
 
-  /// @param b the ProgramBuilder used to construct the AST types
-  /// @returns the constructed ast::Type node for the given type
-  const ast::Type* Build(ProgramBuilder& b) const override;
+    /// @param b the ProgramBuilder used to construct the AST types
+    /// @returns the constructed ast::Type node for the given type
+    const ast::Type* Build(ProgramBuilder& b) const override;
 
-  /// the member types
-  const TypeList members;
+    /// the member types
+    const TypeList members;
 };
 
 /// A manager of types
 class TypeManager {
- public:
-  /// Constructor
-  TypeManager();
+  public:
+    /// Constructor
+    TypeManager();
 
-  /// Destructor
-  ~TypeManager();
+    /// Destructor
+    ~TypeManager();
 
-  /// @return a Void type. Repeated calls will return the same pointer.
-  const spirv::Void* Void();
-  /// @return a Bool type. Repeated calls will return the same pointer.
-  const spirv::Bool* Bool();
-  /// @return a U32 type. Repeated calls will return the same pointer.
-  const spirv::U32* U32();
-  /// @return a F32 type. Repeated calls will return the same pointer.
-  const spirv::F32* F32();
-  /// @return a I32 type. Repeated calls will return the same pointer.
-  const spirv::I32* I32();
-  /// @param ty the store type
-  /// @param sc the pointer storage class
-  /// @return a Pointer type. Repeated calls with the same arguments will return
-  /// the same pointer.
-  const spirv::Pointer* Pointer(const Type* ty, ast::StorageClass sc);
-  /// @param ty the referenced type
-  /// @param sc the reference storage class
-  /// @return a Reference type. Repeated calls with the same arguments will
-  /// return the same pointer.
-  const spirv::Reference* Reference(const Type* ty, ast::StorageClass sc);
-  /// @param ty the element type
-  /// @param sz the number of elements in the vector
-  /// @return a Vector type. Repeated calls with the same arguments will return
-  /// the same pointer.
-  const spirv::Vector* Vector(const Type* ty, uint32_t sz);
-  /// @param ty the matrix element type
-  /// @param c the number of columns in the matrix
-  /// @param r the number of rows in the matrix
-  /// @return a Matrix type. Repeated calls with the same arguments will return
-  /// the same pointer.
-  const spirv::Matrix* Matrix(const Type* ty, uint32_t c, uint32_t r);
-  /// @param el the element type
-  /// @param sz the number of elements in the array. 0 represents runtime-sized
-  /// array.
-  /// @param st the byte stride of the array
-  /// @return a Array type. Repeated calls with the same arguments will return
-  /// the same pointer.
-  const spirv::Array* Array(const Type* el, uint32_t sz, uint32_t st);
-  /// @param n the alias name
-  /// @param t the aliased type
-  /// @return a Alias type. Repeated calls with the same arguments will return
-  /// the same pointer.
-  const spirv::Alias* Alias(Symbol n, const Type* t);
-  /// @param n the struct name
-  /// @param m the member types
-  /// @return a Struct type. Repeated calls with the same arguments will return
-  /// the same pointer.
-  const spirv::Struct* Struct(Symbol n, TypeList m);
-  /// @param k the sampler kind
-  /// @return a Sampler type. Repeated calls with the same arguments will return
-  /// the same pointer.
-  const spirv::Sampler* Sampler(ast::SamplerKind k);
-  /// @param d the texture dimensions
-  /// @return a DepthTexture type. Repeated calls with the same arguments will
-  /// return the same pointer.
-  const spirv::DepthTexture* DepthTexture(ast::TextureDimension d);
-  /// @param d the texture dimensions
-  /// @return a DepthMultisampledTexture type. Repeated calls with the same
-  /// arguments will return the same pointer.
-  const spirv::DepthMultisampledTexture* DepthMultisampledTexture(
-      ast::TextureDimension d);
-  /// @param d the texture dimensions
-  /// @param t the multisampled texture type
-  /// @return a MultisampledTexture type. Repeated calls with the same arguments
-  /// will return the same pointer.
-  const spirv::MultisampledTexture* MultisampledTexture(ast::TextureDimension d,
-                                                        const Type* t);
-  /// @param d the texture dimensions
-  /// @param t the sampled texture type
-  /// @return a SampledTexture type. Repeated calls with the same arguments will
-  /// return the same pointer.
-  const spirv::SampledTexture* SampledTexture(ast::TextureDimension d,
-                                              const Type* t);
-  /// @param d the texture dimensions
-  /// @param f the storage image format
-  /// @param a the access control
-  /// @return a StorageTexture type. Repeated calls with the same arguments will
-  /// return the same pointer.
-  const spirv::StorageTexture* StorageTexture(ast::TextureDimension d,
-                                              ast::TexelFormat f,
-                                              ast::Access a);
+    /// @return a Void type. Repeated calls will return the same pointer.
+    const spirv::Void* Void();
+    /// @return a Bool type. Repeated calls will return the same pointer.
+    const spirv::Bool* Bool();
+    /// @return a U32 type. Repeated calls will return the same pointer.
+    const spirv::U32* U32();
+    /// @return a F32 type. Repeated calls will return the same pointer.
+    const spirv::F32* F32();
+    /// @return a I32 type. Repeated calls will return the same pointer.
+    const spirv::I32* I32();
+    /// @param ty the store type
+    /// @param sc the pointer storage class
+    /// @return a Pointer type. Repeated calls with the same arguments will return
+    /// the same pointer.
+    const spirv::Pointer* Pointer(const Type* ty, ast::StorageClass sc);
+    /// @param ty the referenced type
+    /// @param sc the reference storage class
+    /// @return a Reference type. Repeated calls with the same arguments will
+    /// return the same pointer.
+    const spirv::Reference* Reference(const Type* ty, ast::StorageClass sc);
+    /// @param ty the element type
+    /// @param sz the number of elements in the vector
+    /// @return a Vector type. Repeated calls with the same arguments will return
+    /// the same pointer.
+    const spirv::Vector* Vector(const Type* ty, uint32_t sz);
+    /// @param ty the matrix element type
+    /// @param c the number of columns in the matrix
+    /// @param r the number of rows in the matrix
+    /// @return a Matrix type. Repeated calls with the same arguments will return
+    /// the same pointer.
+    const spirv::Matrix* Matrix(const Type* ty, uint32_t c, uint32_t r);
+    /// @param el the element type
+    /// @param sz the number of elements in the array. 0 represents runtime-sized
+    /// array.
+    /// @param st the byte stride of the array
+    /// @return a Array type. Repeated calls with the same arguments will return
+    /// the same pointer.
+    const spirv::Array* Array(const Type* el, uint32_t sz, uint32_t st);
+    /// @param n the alias name
+    /// @param t the aliased type
+    /// @return a Alias type. Repeated calls with the same arguments will return
+    /// the same pointer.
+    const spirv::Alias* Alias(Symbol n, const Type* t);
+    /// @param n the struct name
+    /// @param m the member types
+    /// @return a Struct type. Repeated calls with the same arguments will return
+    /// the same pointer.
+    const spirv::Struct* Struct(Symbol n, TypeList m);
+    /// @param k the sampler kind
+    /// @return a Sampler type. Repeated calls with the same arguments will return
+    /// the same pointer.
+    const spirv::Sampler* Sampler(ast::SamplerKind k);
+    /// @param d the texture dimensions
+    /// @return a DepthTexture type. Repeated calls with the same arguments will
+    /// return the same pointer.
+    const spirv::DepthTexture* DepthTexture(ast::TextureDimension d);
+    /// @param d the texture dimensions
+    /// @return a DepthMultisampledTexture type. Repeated calls with the same
+    /// arguments will return the same pointer.
+    const spirv::DepthMultisampledTexture* DepthMultisampledTexture(ast::TextureDimension d);
+    /// @param d the texture dimensions
+    /// @param t the multisampled texture type
+    /// @return a MultisampledTexture type. Repeated calls with the same arguments
+    /// will return the same pointer.
+    const spirv::MultisampledTexture* MultisampledTexture(ast::TextureDimension d, const Type* t);
+    /// @param d the texture dimensions
+    /// @param t the sampled texture type
+    /// @return a SampledTexture type. Repeated calls with the same arguments will
+    /// return the same pointer.
+    const spirv::SampledTexture* SampledTexture(ast::TextureDimension d, const Type* t);
+    /// @param d the texture dimensions
+    /// @param f the storage image format
+    /// @param a the access control
+    /// @return a StorageTexture type. Repeated calls with the same arguments will
+    /// return the same pointer.
+    const spirv::StorageTexture* StorageTexture(ast::TextureDimension d,
+                                                ast::TexelFormat f,
+                                                ast::Access a);
 
- private:
-  struct State;
-  std::unique_ptr<State> state;
+  private:
+    struct State;
+    std::unique_ptr<State> state;
 };
 
 }  // namespace tint::reader::spirv
diff --git a/src/tint/reader/spirv/parser_type_test.cc b/src/tint/reader/spirv/parser_type_test.cc
index bddfdc5..c031cd7 100644
--- a/src/tint/reader/spirv/parser_type_test.cc
+++ b/src/tint/reader/spirv/parser_type_test.cc
@@ -20,78 +20,77 @@
 namespace {
 
 TEST(SpvParserTypeTest, SameArgumentsGivesSamePointer) {
-  Symbol sym(Symbol(1, {}));
+    Symbol sym(Symbol(1, {}));
 
-  TypeManager ty;
-  EXPECT_EQ(ty.Void(), ty.Void());
-  EXPECT_EQ(ty.Bool(), ty.Bool());
-  EXPECT_EQ(ty.U32(), ty.U32());
-  EXPECT_EQ(ty.F32(), ty.F32());
-  EXPECT_EQ(ty.I32(), ty.I32());
-  EXPECT_EQ(ty.Pointer(ty.I32(), ast::StorageClass::kNone),
-            ty.Pointer(ty.I32(), ast::StorageClass::kNone));
-  EXPECT_EQ(ty.Vector(ty.I32(), 3), ty.Vector(ty.I32(), 3));
-  EXPECT_EQ(ty.Matrix(ty.I32(), 3, 2), ty.Matrix(ty.I32(), 3, 2));
-  EXPECT_EQ(ty.Array(ty.I32(), 3, 2), ty.Array(ty.I32(), 3, 2));
-  EXPECT_EQ(ty.Alias(sym, ty.I32()), ty.Alias(sym, ty.I32()));
-  EXPECT_EQ(ty.Struct(sym, {ty.I32()}), ty.Struct(sym, {ty.I32()}));
-  EXPECT_EQ(ty.Sampler(ast::SamplerKind::kSampler),
-            ty.Sampler(ast::SamplerKind::kSampler));
-  EXPECT_EQ(ty.DepthTexture(ast::TextureDimension::k2d),
-            ty.DepthTexture(ast::TextureDimension::k2d));
-  EXPECT_EQ(ty.MultisampledTexture(ast::TextureDimension::k2d, ty.I32()),
-            ty.MultisampledTexture(ast::TextureDimension::k2d, ty.I32()));
-  EXPECT_EQ(ty.SampledTexture(ast::TextureDimension::k2d, ty.I32()),
-            ty.SampledTexture(ast::TextureDimension::k2d, ty.I32()));
-  EXPECT_EQ(ty.StorageTexture(ast::TextureDimension::k2d,
-                              ast::TexelFormat::kR32Uint, ast::Access::kRead),
-            ty.StorageTexture(ast::TextureDimension::k2d,
-                              ast::TexelFormat::kR32Uint, ast::Access::kRead));
+    TypeManager ty;
+    EXPECT_EQ(ty.Void(), ty.Void());
+    EXPECT_EQ(ty.Bool(), ty.Bool());
+    EXPECT_EQ(ty.U32(), ty.U32());
+    EXPECT_EQ(ty.F32(), ty.F32());
+    EXPECT_EQ(ty.I32(), ty.I32());
+    EXPECT_EQ(ty.Pointer(ty.I32(), ast::StorageClass::kNone),
+              ty.Pointer(ty.I32(), ast::StorageClass::kNone));
+    EXPECT_EQ(ty.Vector(ty.I32(), 3), ty.Vector(ty.I32(), 3));
+    EXPECT_EQ(ty.Matrix(ty.I32(), 3, 2), ty.Matrix(ty.I32(), 3, 2));
+    EXPECT_EQ(ty.Array(ty.I32(), 3, 2), ty.Array(ty.I32(), 3, 2));
+    EXPECT_EQ(ty.Alias(sym, ty.I32()), ty.Alias(sym, ty.I32()));
+    EXPECT_EQ(ty.Struct(sym, {ty.I32()}), ty.Struct(sym, {ty.I32()}));
+    EXPECT_EQ(ty.Sampler(ast::SamplerKind::kSampler), ty.Sampler(ast::SamplerKind::kSampler));
+    EXPECT_EQ(ty.DepthTexture(ast::TextureDimension::k2d),
+              ty.DepthTexture(ast::TextureDimension::k2d));
+    EXPECT_EQ(ty.MultisampledTexture(ast::TextureDimension::k2d, ty.I32()),
+              ty.MultisampledTexture(ast::TextureDimension::k2d, ty.I32()));
+    EXPECT_EQ(ty.SampledTexture(ast::TextureDimension::k2d, ty.I32()),
+              ty.SampledTexture(ast::TextureDimension::k2d, ty.I32()));
+    EXPECT_EQ(ty.StorageTexture(ast::TextureDimension::k2d, ast::TexelFormat::kR32Uint,
+                                ast::Access::kRead),
+              ty.StorageTexture(ast::TextureDimension::k2d, ast::TexelFormat::kR32Uint,
+                                ast::Access::kRead));
 }
 
 TEST(SpvParserTypeTest, DifferentArgumentsGivesDifferentPointer) {
-  Symbol sym_a(Symbol(1, {}));
-  Symbol sym_b(Symbol(2, {}));
+    Symbol sym_a(Symbol(1, {}));
+    Symbol sym_b(Symbol(2, {}));
 
-  TypeManager ty;
-  EXPECT_NE(ty.Pointer(ty.I32(), ast::StorageClass::kNone),
-            ty.Pointer(ty.U32(), ast::StorageClass::kNone));
-  EXPECT_NE(ty.Pointer(ty.I32(), ast::StorageClass::kNone),
-            ty.Pointer(ty.I32(), ast::StorageClass::kInput));
-  EXPECT_NE(ty.Vector(ty.I32(), 3), ty.Vector(ty.U32(), 3));
-  EXPECT_NE(ty.Vector(ty.I32(), 3), ty.Vector(ty.I32(), 2));
-  EXPECT_NE(ty.Matrix(ty.I32(), 3, 2), ty.Matrix(ty.U32(), 3, 2));
-  EXPECT_NE(ty.Matrix(ty.I32(), 3, 2), ty.Matrix(ty.I32(), 2, 2));
-  EXPECT_NE(ty.Matrix(ty.I32(), 3, 2), ty.Matrix(ty.I32(), 3, 3));
-  EXPECT_NE(ty.Array(ty.I32(), 3, 2), ty.Array(ty.U32(), 3, 2));
-  EXPECT_NE(ty.Array(ty.I32(), 3, 2), ty.Array(ty.I32(), 2, 2));
-  EXPECT_NE(ty.Array(ty.I32(), 3, 2), ty.Array(ty.I32(), 3, 3));
-  EXPECT_NE(ty.Alias(sym_a, ty.I32()), ty.Alias(sym_b, ty.I32()));
-  EXPECT_NE(ty.Struct(sym_a, {ty.I32()}), ty.Struct(sym_b, {ty.I32()}));
-  EXPECT_NE(ty.Sampler(ast::SamplerKind::kSampler),
-            ty.Sampler(ast::SamplerKind::kComparisonSampler));
-  EXPECT_NE(ty.DepthTexture(ast::TextureDimension::k2d),
-            ty.DepthTexture(ast::TextureDimension::k1d));
-  EXPECT_NE(ty.MultisampledTexture(ast::TextureDimension::k2d, ty.I32()),
-            ty.MultisampledTexture(ast::TextureDimension::k3d, ty.I32()));
-  EXPECT_NE(ty.MultisampledTexture(ast::TextureDimension::k2d, ty.I32()),
-            ty.MultisampledTexture(ast::TextureDimension::k2d, ty.U32()));
-  EXPECT_NE(ty.SampledTexture(ast::TextureDimension::k2d, ty.I32()),
-            ty.SampledTexture(ast::TextureDimension::k3d, ty.I32()));
-  EXPECT_NE(ty.SampledTexture(ast::TextureDimension::k2d, ty.I32()),
-            ty.SampledTexture(ast::TextureDimension::k2d, ty.U32()));
-  EXPECT_NE(ty.StorageTexture(ast::TextureDimension::k2d,
-                              ast::TexelFormat::kR32Uint, ast::Access::kRead),
-            ty.StorageTexture(ast::TextureDimension::k3d,
-                              ast::TexelFormat::kR32Uint, ast::Access::kRead));
-  EXPECT_NE(ty.StorageTexture(ast::TextureDimension::k2d,
-                              ast::TexelFormat::kR32Uint, ast::Access::kRead),
-            ty.StorageTexture(ast::TextureDimension::k2d,
-                              ast::TexelFormat::kR32Sint, ast::Access::kRead));
-  EXPECT_NE(ty.StorageTexture(ast::TextureDimension::k2d,
-                              ast::TexelFormat::kR32Uint, ast::Access::kRead),
-            ty.StorageTexture(ast::TextureDimension::k2d,
-                              ast::TexelFormat::kR32Uint, ast::Access::kWrite));
+    TypeManager ty;
+    EXPECT_NE(ty.Pointer(ty.I32(), ast::StorageClass::kNone),
+              ty.Pointer(ty.U32(), ast::StorageClass::kNone));
+    EXPECT_NE(ty.Pointer(ty.I32(), ast::StorageClass::kNone),
+              ty.Pointer(ty.I32(), ast::StorageClass::kInput));
+    EXPECT_NE(ty.Vector(ty.I32(), 3), ty.Vector(ty.U32(), 3));
+    EXPECT_NE(ty.Vector(ty.I32(), 3), ty.Vector(ty.I32(), 2));
+    EXPECT_NE(ty.Matrix(ty.I32(), 3, 2), ty.Matrix(ty.U32(), 3, 2));
+    EXPECT_NE(ty.Matrix(ty.I32(), 3, 2), ty.Matrix(ty.I32(), 2, 2));
+    EXPECT_NE(ty.Matrix(ty.I32(), 3, 2), ty.Matrix(ty.I32(), 3, 3));
+    EXPECT_NE(ty.Array(ty.I32(), 3, 2), ty.Array(ty.U32(), 3, 2));
+    EXPECT_NE(ty.Array(ty.I32(), 3, 2), ty.Array(ty.I32(), 2, 2));
+    EXPECT_NE(ty.Array(ty.I32(), 3, 2), ty.Array(ty.I32(), 3, 3));
+    EXPECT_NE(ty.Alias(sym_a, ty.I32()), ty.Alias(sym_b, ty.I32()));
+    EXPECT_NE(ty.Struct(sym_a, {ty.I32()}), ty.Struct(sym_b, {ty.I32()}));
+    EXPECT_NE(ty.Sampler(ast::SamplerKind::kSampler),
+              ty.Sampler(ast::SamplerKind::kComparisonSampler));
+    EXPECT_NE(ty.DepthTexture(ast::TextureDimension::k2d),
+              ty.DepthTexture(ast::TextureDimension::k1d));
+    EXPECT_NE(ty.MultisampledTexture(ast::TextureDimension::k2d, ty.I32()),
+              ty.MultisampledTexture(ast::TextureDimension::k3d, ty.I32()));
+    EXPECT_NE(ty.MultisampledTexture(ast::TextureDimension::k2d, ty.I32()),
+              ty.MultisampledTexture(ast::TextureDimension::k2d, ty.U32()));
+    EXPECT_NE(ty.SampledTexture(ast::TextureDimension::k2d, ty.I32()),
+              ty.SampledTexture(ast::TextureDimension::k3d, ty.I32()));
+    EXPECT_NE(ty.SampledTexture(ast::TextureDimension::k2d, ty.I32()),
+              ty.SampledTexture(ast::TextureDimension::k2d, ty.U32()));
+    EXPECT_NE(ty.StorageTexture(ast::TextureDimension::k2d, ast::TexelFormat::kR32Uint,
+                                ast::Access::kRead),
+              ty.StorageTexture(ast::TextureDimension::k3d, ast::TexelFormat::kR32Uint,
+                                ast::Access::kRead));
+    EXPECT_NE(ty.StorageTexture(ast::TextureDimension::k2d, ast::TexelFormat::kR32Uint,
+                                ast::Access::kRead),
+              ty.StorageTexture(ast::TextureDimension::k2d, ast::TexelFormat::kR32Sint,
+                                ast::Access::kRead));
+    EXPECT_NE(ty.StorageTexture(ast::TextureDimension::k2d, ast::TexelFormat::kR32Uint,
+                                ast::Access::kRead),
+              ty.StorageTexture(ast::TextureDimension::k2d, ast::TexelFormat::kR32Uint,
+                                ast::Access::kWrite));
 }
 
 }  // namespace
diff --git a/src/tint/reader/spirv/spirv_tools_helpers_test.cc b/src/tint/reader/spirv/spirv_tools_helpers_test.cc
index 057dffd..21a5be2 100644
--- a/src/tint/reader/spirv/spirv_tools_helpers_test.cc
+++ b/src/tint/reader/spirv/spirv_tools_helpers_test.cc
@@ -20,42 +20,38 @@
 namespace tint::reader::spirv::test {
 
 std::vector<uint32_t> Assemble(const std::string& spirv_assembly) {
-  // TODO(dneto): Use ScopedTrace?
+    // TODO(dneto): Use ScopedTrace?
 
-  // (The target environment doesn't affect assembly.
-  spvtools::SpirvTools tools(SPV_ENV_UNIVERSAL_1_0);
-  std::stringstream errors;
-  std::vector<uint32_t> result;
-  tools.SetMessageConsumer([&errors](spv_message_level_t, const char*,
-                                     const spv_position_t& position,
-                                     const char* message) {
-    errors << "assembly error:" << position.line << ":" << position.column
-           << ": " << message;
-  });
+    // (The target environment doesn't affect assembly.
+    spvtools::SpirvTools tools(SPV_ENV_UNIVERSAL_1_0);
+    std::stringstream errors;
+    std::vector<uint32_t> result;
+    tools.SetMessageConsumer([&errors](spv_message_level_t, const char*,
+                                       const spv_position_t& position, const char* message) {
+        errors << "assembly error:" << position.line << ":" << position.column << ": " << message;
+    });
 
-  const auto success = tools.Assemble(
-      spirv_assembly, &result, SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
-  EXPECT_TRUE(success) << errors.str();
+    const auto success =
+        tools.Assemble(spirv_assembly, &result, SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
+    EXPECT_TRUE(success) << errors.str();
 
-  return result;
+    return result;
 }
 
 std::string Disassemble(const std::vector<uint32_t>& spirv_module) {
-  spvtools::SpirvTools tools(SPV_ENV_UNIVERSAL_1_0);
-  std::stringstream errors;
-  tools.SetMessageConsumer([&errors](spv_message_level_t, const char*,
-                                     const spv_position_t& position,
-                                     const char* message) {
-    errors << "disassmbly error:" << position.line << ":" << position.column
-           << ": " << message;
-  });
+    spvtools::SpirvTools tools(SPV_ENV_UNIVERSAL_1_0);
+    std::stringstream errors;
+    tools.SetMessageConsumer([&errors](spv_message_level_t, const char*,
+                                       const spv_position_t& position, const char* message) {
+        errors << "disassmbly error:" << position.line << ":" << position.column << ": " << message;
+    });
 
-  std::string result;
-  const auto success = tools.Disassemble(
-      spirv_module, &result, SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
-  EXPECT_TRUE(success) << errors.str();
+    std::string result;
+    const auto success =
+        tools.Disassemble(spirv_module, &result, SPV_BINARY_TO_TEXT_OPTION_FRIENDLY_NAMES);
+    EXPECT_TRUE(success) << errors.str();
 
-  return result;
+    return result;
 }
 
 }  // namespace tint::reader::spirv::test
diff --git a/src/tint/reader/spirv/usage.cc b/src/tint/reader/spirv/usage.cc
index 2ddb696..c120b2c 100644
--- a/src/tint/reader/spirv/usage.cc
+++ b/src/tint/reader/spirv/usage.cc
@@ -23,168 +23,165 @@
 Usage::~Usage() = default;
 
 std::ostream& Usage::operator<<(std::ostream& out) const {
-  out << "Usage(";
-  if (IsSampler()) {
-    out << "Sampler(";
-    if (is_comparison_sampler_) {
-      out << " comparison";
+    out << "Usage(";
+    if (IsSampler()) {
+        out << "Sampler(";
+        if (is_comparison_sampler_) {
+            out << " comparison";
+        }
+        out << " )";
     }
-    out << " )";
-  }
-  if (IsTexture()) {
-    out << "Texture(";
-    if (is_sampled_) {
-      out << " is_sampled";
+    if (IsTexture()) {
+        out << "Texture(";
+        if (is_sampled_) {
+            out << " is_sampled";
+        }
+        if (is_multisampled_) {
+            out << " ms";
+        }
+        if (is_depth_) {
+            out << " depth";
+        }
+        if (is_storage_read_) {
+            out << " read";
+        }
+        if (is_storage_write_) {
+            out << " write";
+        }
+        out << " )";
     }
-    if (is_multisampled_) {
-      out << " ms";
-    }
-    if (is_depth_) {
-      out << " depth";
-    }
-    if (is_storage_read_) {
-      out << " read";
-    }
-    if (is_storage_write_) {
-      out << " write";
-    }
-    out << " )";
-  }
-  out << ")";
-  return out;
+    out << ")";
+    return out;
 }
 
 bool Usage::IsValid() const {
-  // Check sampler state internal consistency.
-  if (is_comparison_sampler_ && !is_sampler_) {
-    return false;
-  }
-
-  // Check texture state.
-  // |is_texture_| is implied by any of the later texture-based properties.
-  if ((IsStorageTexture() || is_sampled_ || is_multisampled_ || is_depth_) &&
-      !is_texture_) {
-    return false;
-  }
-  if (is_texture_) {
-    // Multisampled implies sampled.
-    if (is_multisampled_) {
-      if (!is_sampled_) {
+    // Check sampler state internal consistency.
+    if (is_comparison_sampler_ && !is_sampler_) {
         return false;
-      }
-    }
-    // Depth implies sampled.
-    if (is_depth_) {
-      if (!is_sampled_) {
-        return false;
-      }
     }
 
-    // Sampled can't be storage.
-    if (is_sampled_) {
-      if (IsStorageTexture()) {
+    // Check texture state.
+    // |is_texture_| is implied by any of the later texture-based properties.
+    if ((IsStorageTexture() || is_sampled_ || is_multisampled_ || is_depth_) && !is_texture_) {
         return false;
-      }
     }
+    if (is_texture_) {
+        // Multisampled implies sampled.
+        if (is_multisampled_) {
+            if (!is_sampled_) {
+                return false;
+            }
+        }
+        // Depth implies sampled.
+        if (is_depth_) {
+            if (!is_sampled_) {
+                return false;
+            }
+        }
 
-    // Storage can't be sampled.
-    if (IsStorageTexture()) {
-      if (is_sampled_) {
-        return false;
-      }
-    }
-    // Storage texture can't also be a sampler.
-    if (IsStorageTexture()) {
-      if (is_sampler_) {
-        return false;
-      }
-    }
+        // Sampled can't be storage.
+        if (is_sampled_) {
+            if (IsStorageTexture()) {
+                return false;
+            }
+        }
 
-    // Can't be both read and write.  This is a restriction in WebGPU.
-    if (is_storage_read_ && is_storage_write_) {
-      return false;
+        // Storage can't be sampled.
+        if (IsStorageTexture()) {
+            if (is_sampled_) {
+                return false;
+            }
+        }
+        // Storage texture can't also be a sampler.
+        if (IsStorageTexture()) {
+            if (is_sampler_) {
+                return false;
+            }
+        }
+
+        // Can't be both read and write.  This is a restriction in WebGPU.
+        if (is_storage_read_ && is_storage_write_) {
+            return false;
+        }
     }
-  }
-  return true;
+    return true;
 }
 
 bool Usage::IsComplete() const {
-  if (!IsValid()) {
+    if (!IsValid()) {
+        return false;
+    }
+    if (IsSampler()) {
+        return true;
+    }
+    if (IsTexture()) {
+        return is_sampled_ || IsStorageTexture();
+    }
     return false;
-  }
-  if (IsSampler()) {
-    return true;
-  }
-  if (IsTexture()) {
-    return is_sampled_ || IsStorageTexture();
-  }
-  return false;
 }
 
 bool Usage::operator==(const Usage& other) const {
-  return is_sampler_ == other.is_sampler_ &&
-         is_comparison_sampler_ == other.is_comparison_sampler_ &&
-         is_texture_ == other.is_texture_ && is_sampled_ == other.is_sampled_ &&
-         is_multisampled_ == other.is_multisampled_ &&
-         is_depth_ == other.is_depth_ &&
-         is_storage_read_ == other.is_storage_read_ &&
-         is_storage_write_ == other.is_storage_write_;
+    return is_sampler_ == other.is_sampler_ &&
+           is_comparison_sampler_ == other.is_comparison_sampler_ &&
+           is_texture_ == other.is_texture_ && is_sampled_ == other.is_sampled_ &&
+           is_multisampled_ == other.is_multisampled_ && is_depth_ == other.is_depth_ &&
+           is_storage_read_ == other.is_storage_read_ &&
+           is_storage_write_ == other.is_storage_write_;
 }
 
 void Usage::Add(const Usage& other) {
-  is_sampler_ = is_sampler_ || other.is_sampler_;
-  is_comparison_sampler_ =
-      is_comparison_sampler_ || other.is_comparison_sampler_;
-  is_texture_ = is_texture_ || other.is_texture_;
-  is_sampled_ = is_sampled_ || other.is_sampled_;
-  is_multisampled_ = is_multisampled_ || other.is_multisampled_;
-  is_depth_ = is_depth_ || other.is_depth_;
-  is_storage_read_ = is_storage_read_ || other.is_storage_read_;
-  is_storage_write_ = is_storage_write_ || other.is_storage_write_;
+    is_sampler_ = is_sampler_ || other.is_sampler_;
+    is_comparison_sampler_ = is_comparison_sampler_ || other.is_comparison_sampler_;
+    is_texture_ = is_texture_ || other.is_texture_;
+    is_sampled_ = is_sampled_ || other.is_sampled_;
+    is_multisampled_ = is_multisampled_ || other.is_multisampled_;
+    is_depth_ = is_depth_ || other.is_depth_;
+    is_storage_read_ = is_storage_read_ || other.is_storage_read_;
+    is_storage_write_ = is_storage_write_ || other.is_storage_write_;
 }
 
 void Usage::AddSampler() {
-  is_sampler_ = true;
+    is_sampler_ = true;
 }
 
 void Usage::AddComparisonSampler() {
-  AddSampler();
-  is_comparison_sampler_ = true;
+    AddSampler();
+    is_comparison_sampler_ = true;
 }
 
 void Usage::AddTexture() {
-  is_texture_ = true;
+    is_texture_ = true;
 }
 
 void Usage::AddStorageReadTexture() {
-  AddTexture();
-  is_storage_read_ = true;
+    AddTexture();
+    is_storage_read_ = true;
 }
 
 void Usage::AddStorageWriteTexture() {
-  AddTexture();
-  is_storage_write_ = true;
+    AddTexture();
+    is_storage_write_ = true;
 }
 
 void Usage::AddSampledTexture() {
-  AddTexture();
-  is_sampled_ = true;
+    AddTexture();
+    is_sampled_ = true;
 }
 
 void Usage::AddMultisampledTexture() {
-  AddSampledTexture();
-  is_multisampled_ = true;
+    AddSampledTexture();
+    is_multisampled_ = true;
 }
 
 void Usage::AddDepthTexture() {
-  AddSampledTexture();
-  is_depth_ = true;
+    AddSampledTexture();
+    is_depth_ = true;
 }
 
 std::string Usage::to_str() const {
-  std::ostringstream ss;
-  ss << *this;
-  return ss.str();
+    std::ostringstream ss;
+    ss << *this;
+    return ss.str();
 }
 
 }  // namespace tint::reader::spirv
diff --git a/src/tint/reader/spirv/usage.h b/src/tint/reader/spirv/usage.h
index 140a4ba..4c2ccbb 100644
--- a/src/tint/reader/spirv/usage.h
+++ b/src/tint/reader/spirv/usage.h
@@ -35,93 +35,91 @@
 ///    - The memory object declaration unederlying %YIm will gain
 ///      AddSampledTexture and AddDepthTexture usages
 class Usage {
- public:
-  /// Constructor
-  Usage();
-  /// Copy constructor
-  /// @param other the Usage to clone
-  Usage(const Usage& other);
-  /// Destructor
-  ~Usage();
+  public:
+    /// Constructor
+    Usage();
+    /// Copy constructor
+    /// @param other the Usage to clone
+    Usage(const Usage& other);
+    /// Destructor
+    ~Usage();
 
-  /// @returns true if this usage is internally consistent
-  bool IsValid() const;
-  /// @returns true if the usage fully determines a WebGPU binding type.
-  bool IsComplete() const;
+    /// @returns true if this usage is internally consistent
+    bool IsValid() const;
+    /// @returns true if the usage fully determines a WebGPU binding type.
+    bool IsComplete() const;
 
-  /// @returns true if this usage is a sampler usage.
-  bool IsSampler() const { return is_sampler_; }
-  /// @returns true if this usage is a comparison sampler usage.
-  bool IsComparisonSampler() const { return is_comparison_sampler_; }
+    /// @returns true if this usage is a sampler usage.
+    bool IsSampler() const { return is_sampler_; }
+    /// @returns true if this usage is a comparison sampler usage.
+    bool IsComparisonSampler() const { return is_comparison_sampler_; }
 
-  /// @returns true if this usage is a texture usage.
-  bool IsTexture() const { return is_texture_; }
-  /// @returns true if this usage is a sampled texture usage.
-  bool IsSampledTexture() const { return is_sampled_; }
-  /// @returns true if this usage is a multisampled texture usage.
-  bool IsMultisampledTexture() const { return is_multisampled_; }
-  /// @returns true if this usage is a dpeth texture usage.
-  bool IsDepthTexture() const { return is_depth_; }
-  /// @returns true if this usage is a read-only storage texture
-  bool IsStorageReadTexture() const { return is_storage_read_; }
-  /// @returns true if this usage is a write-only storage texture
-  bool IsStorageWriteTexture() const { return is_storage_write_; }
+    /// @returns true if this usage is a texture usage.
+    bool IsTexture() const { return is_texture_; }
+    /// @returns true if this usage is a sampled texture usage.
+    bool IsSampledTexture() const { return is_sampled_; }
+    /// @returns true if this usage is a multisampled texture usage.
+    bool IsMultisampledTexture() const { return is_multisampled_; }
+    /// @returns true if this usage is a dpeth texture usage.
+    bool IsDepthTexture() const { return is_depth_; }
+    /// @returns true if this usage is a read-only storage texture
+    bool IsStorageReadTexture() const { return is_storage_read_; }
+    /// @returns true if this usage is a write-only storage texture
+    bool IsStorageWriteTexture() const { return is_storage_write_; }
 
-  /// @returns true if this is a storage texture.
-  bool IsStorageTexture() const {
-    return is_storage_read_ || is_storage_write_;
-  }
+    /// @returns true if this is a storage texture.
+    bool IsStorageTexture() const { return is_storage_read_ || is_storage_write_; }
 
-  /// Emits this usage to the given stream
-  /// @param out the output stream.
-  /// @returns the modified stream.
-  std::ostream& operator<<(std::ostream& out) const;
+    /// Emits this usage to the given stream
+    /// @param out the output stream.
+    /// @returns the modified stream.
+    std::ostream& operator<<(std::ostream& out) const;
 
-  /// Equality operator
-  /// @param other the RHS of the equality test.
-  /// @returns true if `other` is identical to `*this`
-  bool operator==(const Usage& other) const;
+    /// Equality operator
+    /// @param other the RHS of the equality test.
+    /// @returns true if `other` is identical to `*this`
+    bool operator==(const Usage& other) const;
 
-  /// Adds the usages from another usage object.
-  /// @param other the other usage
-  void Add(const Usage& other);
+    /// Adds the usages from another usage object.
+    /// @param other the other usage
+    void Add(const Usage& other);
 
-  /// Records usage as a sampler.
-  void AddSampler();
-  /// Records usage as a comparison sampler.
-  void AddComparisonSampler();
+    /// Records usage as a sampler.
+    void AddSampler();
+    /// Records usage as a comparison sampler.
+    void AddComparisonSampler();
 
-  /// Records usage as a texture of some kind.
-  void AddTexture();
-  /// Records usage as a read-only storage texture.
-  void AddStorageReadTexture();
-  /// Records usage as a write-only storage texture.
-  void AddStorageWriteTexture();
-  /// Records usage as a sampled texture.
-  void AddSampledTexture();
-  /// Records usage as a multisampled texture.
-  void AddMultisampledTexture();
-  /// Records usage as a depth texture.
-  void AddDepthTexture();
+    /// Records usage as a texture of some kind.
+    void AddTexture();
+    /// Records usage as a read-only storage texture.
+    void AddStorageReadTexture();
+    /// Records usage as a write-only storage texture.
+    void AddStorageWriteTexture();
+    /// Records usage as a sampled texture.
+    void AddSampledTexture();
+    /// Records usage as a multisampled texture.
+    void AddMultisampledTexture();
+    /// Records usage as a depth texture.
+    void AddDepthTexture();
 
-  /// @returns this usage object as a string.
-  std::string to_str() const;
+    /// @returns this usage object as a string.
+    std::string to_str() const;
 
- private:
-  // Sampler properties.
-  bool is_sampler_ = false;
-  // A comparison sampler is always a sampler:
-  //    |is_comparison_sampler_| implies |is_sampler_|
-  bool is_comparison_sampler_ = false;
+  private:
+    // Sampler properties.
+    bool is_sampler_ = false;
+    // A comparison sampler is always a sampler:
+    //    |is_comparison_sampler_| implies |is_sampler_|
+    bool is_comparison_sampler_ = false;
 
-  // Texture properties.
-  // |is_texture_| is always implied by any of the others below.
-  bool is_texture_ = false;
-  bool is_sampled_ = false;
-  bool is_multisampled_ = false;  // This implies it's sampled as well.
-  bool is_depth_ = false;
-  bool is_storage_read_ = false;
-  bool is_storage_write_ = false;
+    // Texture properties.
+    // |is_texture_| is always implied by any of the others below.
+    bool is_texture_ = false;
+    bool is_sampled_ = false;
+    bool is_multisampled_ = false;  // This implies it's sampled as well.
+    bool is_depth_ = false;
+    bool is_storage_read_ = false;
+    bool is_storage_write_ = false;
 };
 
 /// Writes the Usage to the ostream
@@ -129,7 +127,7 @@
 /// @param u the Usage
 /// @returns the ostream so calls can be chained
 inline std::ostream& operator<<(std::ostream& out, const Usage& u) {
-  return u.operator<<(out);
+    return u.operator<<(out);
 }
 
 }  // namespace tint::reader::spirv
diff --git a/src/tint/reader/spirv/usage_test.cc b/src/tint/reader/spirv/usage_test.cc
index 0ee7f15..d01d1a2 100644
--- a/src/tint/reader/spirv/usage_test.cc
+++ b/src/tint/reader/spirv/usage_test.cc
@@ -24,267 +24,267 @@
 using ::testing::Eq;
 
 TEST_F(SpvParserTest, Usage_Trivial_Properties) {
-  Usage u;
-  EXPECT_TRUE(u.IsValid());
-  EXPECT_FALSE(u.IsComplete());
-  EXPECT_FALSE(u.IsSampler());
-  EXPECT_FALSE(u.IsComparisonSampler());
-  EXPECT_FALSE(u.IsTexture());
-  EXPECT_FALSE(u.IsSampledTexture());
-  EXPECT_FALSE(u.IsMultisampledTexture());
-  EXPECT_FALSE(u.IsDepthTexture());
-  EXPECT_FALSE(u.IsStorageReadTexture());
-  EXPECT_FALSE(u.IsStorageWriteTexture());
+    Usage u;
+    EXPECT_TRUE(u.IsValid());
+    EXPECT_FALSE(u.IsComplete());
+    EXPECT_FALSE(u.IsSampler());
+    EXPECT_FALSE(u.IsComparisonSampler());
+    EXPECT_FALSE(u.IsTexture());
+    EXPECT_FALSE(u.IsSampledTexture());
+    EXPECT_FALSE(u.IsMultisampledTexture());
+    EXPECT_FALSE(u.IsDepthTexture());
+    EXPECT_FALSE(u.IsStorageReadTexture());
+    EXPECT_FALSE(u.IsStorageWriteTexture());
 }
 
 TEST_F(SpvParserTest, Usage_Trivial_Output) {
-  std::ostringstream ss;
-  Usage u;
-  ss << u;
-  EXPECT_THAT(ss.str(), Eq("Usage()"));
+    std::ostringstream ss;
+    Usage u;
+    ss << u;
+    EXPECT_THAT(ss.str(), Eq("Usage()"));
 }
 
 TEST_F(SpvParserTest, Usage_Equality_OneDifference) {
-  const int num_usages = 9;
-  std::vector<Usage> usages(num_usages);
-  usages[1].AddSampler();
-  usages[2].AddComparisonSampler();
-  usages[3].AddTexture();
-  usages[4].AddSampledTexture();
-  usages[5].AddMultisampledTexture();
-  usages[6].AddDepthTexture();
-  usages[7].AddStorageReadTexture();
-  usages[8].AddStorageWriteTexture();
-  for (int i = 0; i < num_usages; ++i) {
-    for (int j = 0; j < num_usages; ++j) {
-      const auto& lhs = usages[i];
-      const auto& rhs = usages[j];
-      if (i == j) {
-        EXPECT_TRUE(lhs == rhs);
-      } else {
-        EXPECT_FALSE(lhs == rhs);
-      }
+    const int num_usages = 9;
+    std::vector<Usage> usages(num_usages);
+    usages[1].AddSampler();
+    usages[2].AddComparisonSampler();
+    usages[3].AddTexture();
+    usages[4].AddSampledTexture();
+    usages[5].AddMultisampledTexture();
+    usages[6].AddDepthTexture();
+    usages[7].AddStorageReadTexture();
+    usages[8].AddStorageWriteTexture();
+    for (int i = 0; i < num_usages; ++i) {
+        for (int j = 0; j < num_usages; ++j) {
+            const auto& lhs = usages[i];
+            const auto& rhs = usages[j];
+            if (i == j) {
+                EXPECT_TRUE(lhs == rhs);
+            } else {
+                EXPECT_FALSE(lhs == rhs);
+            }
+        }
     }
-  }
 }
 
 TEST_F(SpvParserTest, Usage_Add) {
-  // Mix two nontrivial usages.
-  Usage a;
-  a.AddStorageReadTexture();
+    // Mix two nontrivial usages.
+    Usage a;
+    a.AddStorageReadTexture();
 
-  Usage b;
-  b.AddComparisonSampler();
+    Usage b;
+    b.AddComparisonSampler();
 
-  a.Add(b);
+    a.Add(b);
 
-  EXPECT_FALSE(a.IsValid());
-  EXPECT_FALSE(a.IsComplete());
-  EXPECT_TRUE(a.IsSampler());
-  EXPECT_TRUE(a.IsComparisonSampler());
-  EXPECT_TRUE(a.IsTexture());
-  EXPECT_FALSE(a.IsSampledTexture());
-  EXPECT_FALSE(a.IsMultisampledTexture());
-  EXPECT_FALSE(a.IsDepthTexture());
-  EXPECT_TRUE(a.IsStorageReadTexture());
-  EXPECT_FALSE(a.IsStorageWriteTexture());
+    EXPECT_FALSE(a.IsValid());
+    EXPECT_FALSE(a.IsComplete());
+    EXPECT_TRUE(a.IsSampler());
+    EXPECT_TRUE(a.IsComparisonSampler());
+    EXPECT_TRUE(a.IsTexture());
+    EXPECT_FALSE(a.IsSampledTexture());
+    EXPECT_FALSE(a.IsMultisampledTexture());
+    EXPECT_FALSE(a.IsDepthTexture());
+    EXPECT_TRUE(a.IsStorageReadTexture());
+    EXPECT_FALSE(a.IsStorageWriteTexture());
 
-  std::ostringstream ss;
-  ss << a;
-  EXPECT_THAT(ss.str(), Eq("Usage(Sampler( comparison )Texture( read ))"));
+    std::ostringstream ss;
+    ss << a;
+    EXPECT_THAT(ss.str(), Eq("Usage(Sampler( comparison )Texture( read ))"));
 }
 
 TEST_F(SpvParserTest, Usage_AddSampler) {
-  std::ostringstream ss;
-  Usage u;
-  u.AddSampler();
+    std::ostringstream ss;
+    Usage u;
+    u.AddSampler();
 
-  EXPECT_TRUE(u.IsValid());
-  EXPECT_TRUE(u.IsComplete());
-  EXPECT_TRUE(u.IsSampler());
-  EXPECT_FALSE(u.IsComparisonSampler());
-  EXPECT_FALSE(u.IsTexture());
-  EXPECT_FALSE(u.IsSampledTexture());
-  EXPECT_FALSE(u.IsMultisampledTexture());
-  EXPECT_FALSE(u.IsDepthTexture());
-  EXPECT_FALSE(u.IsStorageReadTexture());
-  EXPECT_FALSE(u.IsStorageWriteTexture());
+    EXPECT_TRUE(u.IsValid());
+    EXPECT_TRUE(u.IsComplete());
+    EXPECT_TRUE(u.IsSampler());
+    EXPECT_FALSE(u.IsComparisonSampler());
+    EXPECT_FALSE(u.IsTexture());
+    EXPECT_FALSE(u.IsSampledTexture());
+    EXPECT_FALSE(u.IsMultisampledTexture());
+    EXPECT_FALSE(u.IsDepthTexture());
+    EXPECT_FALSE(u.IsStorageReadTexture());
+    EXPECT_FALSE(u.IsStorageWriteTexture());
 
-  ss << u;
-  EXPECT_THAT(ss.str(), Eq("Usage(Sampler( ))"));
+    ss << u;
+    EXPECT_THAT(ss.str(), Eq("Usage(Sampler( ))"));
 
-  // Check idempotency
-  auto copy(u);
-  u.AddSampler();
-  EXPECT_TRUE(u == copy);
+    // Check idempotency
+    auto copy(u);
+    u.AddSampler();
+    EXPECT_TRUE(u == copy);
 }
 
 TEST_F(SpvParserTest, Usage_AddComparisonSampler) {
-  std::ostringstream ss;
-  Usage u;
-  u.AddComparisonSampler();
+    std::ostringstream ss;
+    Usage u;
+    u.AddComparisonSampler();
 
-  EXPECT_TRUE(u.IsValid());
-  EXPECT_TRUE(u.IsComplete());
-  EXPECT_TRUE(u.IsSampler());
-  EXPECT_TRUE(u.IsComparisonSampler());
-  EXPECT_FALSE(u.IsTexture());
-  EXPECT_FALSE(u.IsSampledTexture());
-  EXPECT_FALSE(u.IsMultisampledTexture());
-  EXPECT_FALSE(u.IsDepthTexture());
-  EXPECT_FALSE(u.IsStorageReadTexture());
-  EXPECT_FALSE(u.IsStorageWriteTexture());
+    EXPECT_TRUE(u.IsValid());
+    EXPECT_TRUE(u.IsComplete());
+    EXPECT_TRUE(u.IsSampler());
+    EXPECT_TRUE(u.IsComparisonSampler());
+    EXPECT_FALSE(u.IsTexture());
+    EXPECT_FALSE(u.IsSampledTexture());
+    EXPECT_FALSE(u.IsMultisampledTexture());
+    EXPECT_FALSE(u.IsDepthTexture());
+    EXPECT_FALSE(u.IsStorageReadTexture());
+    EXPECT_FALSE(u.IsStorageWriteTexture());
 
-  ss << u;
-  EXPECT_THAT(ss.str(), Eq("Usage(Sampler( comparison ))"));
+    ss << u;
+    EXPECT_THAT(ss.str(), Eq("Usage(Sampler( comparison ))"));
 
-  auto copy(u);
-  u.AddComparisonSampler();
-  EXPECT_TRUE(u == copy);
+    auto copy(u);
+    u.AddComparisonSampler();
+    EXPECT_TRUE(u == copy);
 }
 
 TEST_F(SpvParserTest, Usage_AddTexture) {
-  std::ostringstream ss;
-  Usage u;
-  u.AddTexture();
+    std::ostringstream ss;
+    Usage u;
+    u.AddTexture();
 
-  EXPECT_TRUE(u.IsValid());
-  EXPECT_FALSE(u.IsComplete());  // Don't know if it's sampled or storage
-  EXPECT_FALSE(u.IsSampler());
-  EXPECT_FALSE(u.IsComparisonSampler());
-  EXPECT_TRUE(u.IsTexture());
-  EXPECT_FALSE(u.IsSampledTexture());
-  EXPECT_FALSE(u.IsMultisampledTexture());
-  EXPECT_FALSE(u.IsDepthTexture());
-  EXPECT_FALSE(u.IsStorageReadTexture());
-  EXPECT_FALSE(u.IsStorageWriteTexture());
+    EXPECT_TRUE(u.IsValid());
+    EXPECT_FALSE(u.IsComplete());  // Don't know if it's sampled or storage
+    EXPECT_FALSE(u.IsSampler());
+    EXPECT_FALSE(u.IsComparisonSampler());
+    EXPECT_TRUE(u.IsTexture());
+    EXPECT_FALSE(u.IsSampledTexture());
+    EXPECT_FALSE(u.IsMultisampledTexture());
+    EXPECT_FALSE(u.IsDepthTexture());
+    EXPECT_FALSE(u.IsStorageReadTexture());
+    EXPECT_FALSE(u.IsStorageWriteTexture());
 
-  ss << u;
-  EXPECT_THAT(ss.str(), Eq("Usage(Texture( ))"));
+    ss << u;
+    EXPECT_THAT(ss.str(), Eq("Usage(Texture( ))"));
 
-  auto copy(u);
-  u.AddTexture();
-  EXPECT_TRUE(u == copy);
+    auto copy(u);
+    u.AddTexture();
+    EXPECT_TRUE(u == copy);
 }
 
 TEST_F(SpvParserTest, Usage_AddSampledTexture) {
-  std::ostringstream ss;
-  Usage u;
-  u.AddSampledTexture();
+    std::ostringstream ss;
+    Usage u;
+    u.AddSampledTexture();
 
-  EXPECT_TRUE(u.IsValid());
-  EXPECT_TRUE(u.IsComplete());
-  EXPECT_FALSE(u.IsSampler());
-  EXPECT_FALSE(u.IsComparisonSampler());
-  EXPECT_TRUE(u.IsTexture());
-  EXPECT_TRUE(u.IsSampledTexture());
-  EXPECT_FALSE(u.IsMultisampledTexture());
-  EXPECT_FALSE(u.IsDepthTexture());
-  EXPECT_FALSE(u.IsStorageReadTexture());
-  EXPECT_FALSE(u.IsStorageWriteTexture());
+    EXPECT_TRUE(u.IsValid());
+    EXPECT_TRUE(u.IsComplete());
+    EXPECT_FALSE(u.IsSampler());
+    EXPECT_FALSE(u.IsComparisonSampler());
+    EXPECT_TRUE(u.IsTexture());
+    EXPECT_TRUE(u.IsSampledTexture());
+    EXPECT_FALSE(u.IsMultisampledTexture());
+    EXPECT_FALSE(u.IsDepthTexture());
+    EXPECT_FALSE(u.IsStorageReadTexture());
+    EXPECT_FALSE(u.IsStorageWriteTexture());
 
-  ss << u;
-  EXPECT_THAT(ss.str(), Eq("Usage(Texture( is_sampled ))"));
+    ss << u;
+    EXPECT_THAT(ss.str(), Eq("Usage(Texture( is_sampled ))"));
 
-  auto copy(u);
-  u.AddSampledTexture();
-  EXPECT_TRUE(u == copy);
+    auto copy(u);
+    u.AddSampledTexture();
+    EXPECT_TRUE(u == copy);
 }
 
 TEST_F(SpvParserTest, Usage_AddMultisampledTexture) {
-  std::ostringstream ss;
-  Usage u;
-  u.AddMultisampledTexture();
+    std::ostringstream ss;
+    Usage u;
+    u.AddMultisampledTexture();
 
-  EXPECT_TRUE(u.IsValid());
-  EXPECT_TRUE(u.IsComplete());
-  EXPECT_FALSE(u.IsSampler());
-  EXPECT_FALSE(u.IsComparisonSampler());
-  EXPECT_TRUE(u.IsTexture());
-  EXPECT_TRUE(u.IsSampledTexture());
-  EXPECT_TRUE(u.IsMultisampledTexture());
-  EXPECT_FALSE(u.IsDepthTexture());
-  EXPECT_FALSE(u.IsStorageReadTexture());
-  EXPECT_FALSE(u.IsStorageWriteTexture());
+    EXPECT_TRUE(u.IsValid());
+    EXPECT_TRUE(u.IsComplete());
+    EXPECT_FALSE(u.IsSampler());
+    EXPECT_FALSE(u.IsComparisonSampler());
+    EXPECT_TRUE(u.IsTexture());
+    EXPECT_TRUE(u.IsSampledTexture());
+    EXPECT_TRUE(u.IsMultisampledTexture());
+    EXPECT_FALSE(u.IsDepthTexture());
+    EXPECT_FALSE(u.IsStorageReadTexture());
+    EXPECT_FALSE(u.IsStorageWriteTexture());
 
-  ss << u;
-  EXPECT_THAT(ss.str(), Eq("Usage(Texture( is_sampled ms ))"));
+    ss << u;
+    EXPECT_THAT(ss.str(), Eq("Usage(Texture( is_sampled ms ))"));
 
-  auto copy(u);
-  u.AddMultisampledTexture();
-  EXPECT_TRUE(u == copy);
+    auto copy(u);
+    u.AddMultisampledTexture();
+    EXPECT_TRUE(u == copy);
 }
 
 TEST_F(SpvParserTest, Usage_AddDepthTexture) {
-  std::ostringstream ss;
-  Usage u;
-  u.AddDepthTexture();
+    std::ostringstream ss;
+    Usage u;
+    u.AddDepthTexture();
 
-  EXPECT_TRUE(u.IsValid());
-  EXPECT_TRUE(u.IsComplete());
-  EXPECT_FALSE(u.IsSampler());
-  EXPECT_FALSE(u.IsComparisonSampler());
-  EXPECT_TRUE(u.IsTexture());
-  EXPECT_TRUE(u.IsSampledTexture());
-  EXPECT_FALSE(u.IsMultisampledTexture());
-  EXPECT_TRUE(u.IsDepthTexture());
-  EXPECT_FALSE(u.IsStorageReadTexture());
-  EXPECT_FALSE(u.IsStorageWriteTexture());
+    EXPECT_TRUE(u.IsValid());
+    EXPECT_TRUE(u.IsComplete());
+    EXPECT_FALSE(u.IsSampler());
+    EXPECT_FALSE(u.IsComparisonSampler());
+    EXPECT_TRUE(u.IsTexture());
+    EXPECT_TRUE(u.IsSampledTexture());
+    EXPECT_FALSE(u.IsMultisampledTexture());
+    EXPECT_TRUE(u.IsDepthTexture());
+    EXPECT_FALSE(u.IsStorageReadTexture());
+    EXPECT_FALSE(u.IsStorageWriteTexture());
 
-  ss << u;
-  EXPECT_THAT(ss.str(), Eq("Usage(Texture( is_sampled depth ))"));
+    ss << u;
+    EXPECT_THAT(ss.str(), Eq("Usage(Texture( is_sampled depth ))"));
 
-  auto copy(u);
-  u.AddDepthTexture();
-  EXPECT_TRUE(u == copy);
+    auto copy(u);
+    u.AddDepthTexture();
+    EXPECT_TRUE(u == copy);
 }
 
 TEST_F(SpvParserTest, Usage_AddStorageReadTexture) {
-  std::ostringstream ss;
-  Usage u;
-  u.AddStorageReadTexture();
+    std::ostringstream ss;
+    Usage u;
+    u.AddStorageReadTexture();
 
-  EXPECT_TRUE(u.IsValid());
-  EXPECT_TRUE(u.IsComplete());
-  EXPECT_FALSE(u.IsSampler());
-  EXPECT_FALSE(u.IsComparisonSampler());
-  EXPECT_TRUE(u.IsTexture());
-  EXPECT_FALSE(u.IsSampledTexture());
-  EXPECT_FALSE(u.IsMultisampledTexture());
-  EXPECT_FALSE(u.IsDepthTexture());
-  EXPECT_TRUE(u.IsStorageReadTexture());
-  EXPECT_FALSE(u.IsStorageWriteTexture());
+    EXPECT_TRUE(u.IsValid());
+    EXPECT_TRUE(u.IsComplete());
+    EXPECT_FALSE(u.IsSampler());
+    EXPECT_FALSE(u.IsComparisonSampler());
+    EXPECT_TRUE(u.IsTexture());
+    EXPECT_FALSE(u.IsSampledTexture());
+    EXPECT_FALSE(u.IsMultisampledTexture());
+    EXPECT_FALSE(u.IsDepthTexture());
+    EXPECT_TRUE(u.IsStorageReadTexture());
+    EXPECT_FALSE(u.IsStorageWriteTexture());
 
-  ss << u;
-  EXPECT_THAT(ss.str(), Eq("Usage(Texture( read ))"));
+    ss << u;
+    EXPECT_THAT(ss.str(), Eq("Usage(Texture( read ))"));
 
-  auto copy(u);
-  u.AddStorageReadTexture();
-  EXPECT_TRUE(u == copy);
+    auto copy(u);
+    u.AddStorageReadTexture();
+    EXPECT_TRUE(u == copy);
 }
 
 TEST_F(SpvParserTest, Usage_AddStorageWriteTexture) {
-  std::ostringstream ss;
-  Usage u;
-  u.AddStorageWriteTexture();
+    std::ostringstream ss;
+    Usage u;
+    u.AddStorageWriteTexture();
 
-  EXPECT_TRUE(u.IsValid());
-  EXPECT_TRUE(u.IsComplete());
-  EXPECT_FALSE(u.IsSampler());
-  EXPECT_FALSE(u.IsComparisonSampler());
-  EXPECT_TRUE(u.IsTexture());
-  EXPECT_FALSE(u.IsSampledTexture());
-  EXPECT_FALSE(u.IsMultisampledTexture());
-  EXPECT_FALSE(u.IsDepthTexture());
-  EXPECT_FALSE(u.IsStorageReadTexture());
-  EXPECT_TRUE(u.IsStorageWriteTexture());
+    EXPECT_TRUE(u.IsValid());
+    EXPECT_TRUE(u.IsComplete());
+    EXPECT_FALSE(u.IsSampler());
+    EXPECT_FALSE(u.IsComparisonSampler());
+    EXPECT_TRUE(u.IsTexture());
+    EXPECT_FALSE(u.IsSampledTexture());
+    EXPECT_FALSE(u.IsMultisampledTexture());
+    EXPECT_FALSE(u.IsDepthTexture());
+    EXPECT_FALSE(u.IsStorageReadTexture());
+    EXPECT_TRUE(u.IsStorageWriteTexture());
 
-  ss << u;
-  EXPECT_THAT(ss.str(), Eq("Usage(Texture( write ))"));
+    ss << u;
+    EXPECT_THAT(ss.str(), Eq("Usage(Texture( write ))"));
 
-  auto copy(u);
-  u.AddStorageWriteTexture();
-  EXPECT_TRUE(u == copy);
+    auto copy(u);
+    u.AddStorageWriteTexture();
+    EXPECT_TRUE(u == copy);
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/lexer.cc b/src/tint/reader/wgsl/lexer.cc
index 7d86690..d9a9f34 100644
--- a/src/tint/reader/wgsl/lexer.cc
+++ b/src/tint/reader/wgsl/lexer.cc
@@ -18,6 +18,9 @@
 #include <cmath>
 #include <cstring>
 #include <limits>
+#include <optional>  // NOLINT(build/include_order)
+#include <tuple>
+#include <type_traits>
 #include <utility>
 
 #include "src/tint/debug.h"
@@ -26,1108 +29,1136 @@
 namespace tint::reader::wgsl {
 namespace {
 
-bool is_blankspace(char c) {
-  // See https://www.w3.org/TR/WGSL/#blankspace.
-  return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' ||
-         c == '\r';
+// Unicode parsing code assumes that the size of a single std::string element is
+// 1 byte.
+static_assert(sizeof(decltype(tint::Source::FileContent::data[0])) == sizeof(uint8_t),
+              "tint::reader::wgsl requires the size of a std::string element "
+              "to be a single byte");
+
+bool read_blankspace(std::string_view str, size_t i, bool* is_blankspace, size_t* blankspace_size) {
+    // See https://www.w3.org/TR/WGSL/#blankspace
+
+    auto* utf8 = reinterpret_cast<const uint8_t*>(&str[i]);
+    auto [cp, n] = text::utf8::Decode(utf8, str.size() - i);
+
+    if (n == 0) {
+        return false;
+    }
+
+    static const auto kSpace = text::CodePoint(0x0020);  // space
+    static const auto kHTab = text::CodePoint(0x0009);   // horizontal tab
+    static const auto kL2R = text::CodePoint(0x200E);    // left-to-right mark
+    static const auto kR2L = text::CodePoint(0x200F);    // right-to-left mark
+
+    if (cp == kSpace || cp == kHTab || cp == kL2R || cp == kR2L) {
+        *is_blankspace = true;
+        *blankspace_size = n;
+        return true;
+    }
+
+    *is_blankspace = false;
+    return true;
 }
 
 uint32_t dec_value(char c) {
-  if (c >= '0' && c <= '9') {
-    return static_cast<uint32_t>(c - '0');
-  }
-  return 0;
+    if (c >= '0' && c <= '9') {
+        return static_cast<uint32_t>(c - '0');
+    }
+    return 0;
 }
 
 uint32_t hex_value(char c) {
-  if (c >= '0' && c <= '9') {
-    return static_cast<uint32_t>(c - '0');
-  }
-  if (c >= 'a' && c <= 'f') {
-    return 0xA + static_cast<uint32_t>(c - 'a');
-  }
-  if (c >= 'A' && c <= 'F') {
-    return 0xA + static_cast<uint32_t>(c - 'A');
-  }
-  return 0;
+    if (c >= '0' && c <= '9') {
+        return static_cast<uint32_t>(c - '0');
+    }
+    if (c >= 'a' && c <= 'f') {
+        return 0xA + static_cast<uint32_t>(c - 'a');
+    }
+    if (c >= 'A' && c <= 'F') {
+        return 0xA + static_cast<uint32_t>(c - 'A');
+    }
+    return 0;
+}
+
+/// LimitCheck is the enumerator result of check_limits().
+enum class LimitCheck {
+    /// The value was within the limits of the data type.
+    kWithinLimits,
+    /// The value was too small to fit within the data type.
+    kTooSmall,
+    /// The value was too large to fit within the data type.
+    kTooLarge,
+};
+
+/// Checks whether the value fits within the integer type `T`
+template <typename T>
+LimitCheck check_limits(int64_t value) {
+    static_assert(std::is_integral_v<T>, "T must be an integer");
+    if (value < static_cast<int64_t>(std::numeric_limits<T>::min())) {
+        return LimitCheck::kTooSmall;
+    }
+    if (value > static_cast<int64_t>(std::numeric_limits<T>::max())) {
+        return LimitCheck::kTooLarge;
+    }
+    return LimitCheck::kWithinLimits;
 }
 
 }  // namespace
 
-Lexer::Lexer(const Source::File* file)
-    : file_(file),
-      len_(static_cast<uint32_t>(file->content.data.size())),
-      location_{1, 1} {}
+Lexer::Lexer(const Source::File* file) : file_(file), location_{1, 1} {}
 
 Lexer::~Lexer() = default;
 
-Token Lexer::next() {
-  if (auto t = skip_blankspace_and_comments(); !t.IsUninitialized()) {
-    return t;
-  }
-
-  if (auto t = try_hex_float(); !t.IsUninitialized()) {
-    return t;
-  }
-
-  if (auto t = try_hex_integer(); !t.IsUninitialized()) {
-    return t;
-  }
-
-  if (auto t = try_float(); !t.IsUninitialized()) {
-    return t;
-  }
-
-  if (auto t = try_integer(); !t.IsUninitialized()) {
-    return t;
-  }
-
-  if (auto t = try_ident(); !t.IsUninitialized()) {
-    return t;
-  }
-
-  if (auto t = try_punctuation(); !t.IsUninitialized()) {
-    return t;
-  }
-
-  return {Token::Type::kError, begin_source(),
-          (is_null() ? "null character found" : "invalid character found")};
+const std::string_view Lexer::line() const {
+    if (file_->content.lines.size() == 0) {
+        static const char* empty_string = "";
+        return empty_string;
+    }
+    return file_->content.lines[location_.line - 1];
 }
 
-Source Lexer::begin_source() const {
-  Source src{};
-  src.file = file_;
-  src.range.begin = location_;
-  src.range.end = location_;
-  return src;
+size_t Lexer::pos() const {
+    return location_.column - 1;
 }
 
-void Lexer::end_source(Source& src) const {
-  src.range.end = location_;
+size_t Lexer::length() const {
+    return line().size();
+}
+
+const char& Lexer::at(size_t pos) const {
+    auto l = line();
+    // Unlike for std::string, if pos == l.size(), indexing `l[pos]` is UB for
+    // std::string_view.
+    if (pos >= l.size()) {
+        static const char zero = 0;
+        return zero;
+    }
+    return l[pos];
+}
+
+std::string_view Lexer::substr(size_t offset, size_t count) {
+    return line().substr(offset, count);
+}
+
+void Lexer::advance(size_t offset) {
+    location_.column += offset;
+}
+
+void Lexer::set_pos(size_t pos) {
+    location_.column = pos + 1;
+}
+
+void Lexer::advance_line() {
+    location_.line++;
+    location_.column = 1;
 }
 
 bool Lexer::is_eof() const {
-  return pos_ >= len_;
+    return location_.line >= file_->content.lines.size() && pos() >= length();
+}
+
+bool Lexer::is_eol() const {
+    return pos() >= length();
+}
+
+Token Lexer::next() {
+    if (auto t = skip_blankspace_and_comments(); !t.IsUninitialized()) {
+        return t;
+    }
+
+    if (auto t = try_hex_float(); !t.IsUninitialized()) {
+        return t;
+    }
+
+    if (auto t = try_hex_integer(); !t.IsUninitialized()) {
+        return t;
+    }
+
+    if (auto t = try_float(); !t.IsUninitialized()) {
+        return t;
+    }
+
+    if (auto t = try_integer(); !t.IsUninitialized()) {
+        return t;
+    }
+
+    if (auto t = try_ident(); !t.IsUninitialized()) {
+        return t;
+    }
+
+    if (auto t = try_punctuation(); !t.IsUninitialized()) {
+        return t;
+    }
+
+    return {Token::Type::kError, begin_source(),
+            (is_null() ? "null character found" : "invalid character found")};
+}
+
+Source Lexer::begin_source() const {
+    Source src{};
+    src.file = file_;
+    src.range.begin = location_;
+    src.range.end = location_;
+    return src;
+}
+
+void Lexer::end_source(Source& src) const {
+    src.range.end = location_;
 }
 
 bool Lexer::is_null() const {
-  return (pos_ < len_) && (file_->content.data[pos_] == 0);
+    return (pos() < length()) && (at(pos()) == 0);
 }
 
 bool Lexer::is_digit(char ch) const {
-  return std::isdigit(static_cast<unsigned char>(ch));
+    return std::isdigit(static_cast<unsigned char>(ch));
 }
 
 bool Lexer::is_hex(char ch) const {
-  return std::isxdigit(static_cast<unsigned char>(ch));
+    return std::isxdigit(static_cast<unsigned char>(ch));
 }
 
-bool Lexer::matches(size_t pos, std::string_view substr) {
-  if (pos >= len_)
-    return false;
-  return file_->content.data_view.substr(pos, substr.size()) == substr;
+bool Lexer::matches(size_t pos, std::string_view sub_string) {
+    if (pos >= length())
+        return false;
+    return substr(pos, sub_string.size()) == sub_string;
 }
 
 Token Lexer::skip_blankspace_and_comments() {
-  for (;;) {
-    auto pos = pos_;
-    while (!is_eof() && is_blankspace(file_->content.data[pos_])) {
-      if (matches(pos_, "\n")) {
-        pos_++;
-        location_.line++;
-        location_.column = 1;
-        continue;
-      }
+    for (;;) {
+        auto loc = location_;
+        while (!is_eof()) {
+            if (is_eol()) {
+                advance_line();
+                continue;
+            }
 
-      pos_++;
-      location_.column++;
+            bool is_blankspace;
+            size_t blankspace_size;
+            if (!read_blankspace(line(), pos(), &is_blankspace, &blankspace_size)) {
+                return {Token::Type::kError, begin_source(), "invalid UTF-8"};
+            }
+            if (!is_blankspace) {
+                break;
+            }
+
+            advance(blankspace_size);
+        }
+
+        auto t = skip_comment();
+        if (!t.IsUninitialized()) {
+            return t;
+        }
+
+        // If the cursor didn't advance we didn't remove any blankspace
+        // so we're done.
+        if (loc == location_)
+            break;
+    }
+    if (is_eof()) {
+        return {Token::Type::kEOF, begin_source()};
     }
 
-    auto t = skip_comment();
-    if (!t.IsUninitialized()) {
-      return t;
-    }
-
-    // If the cursor didn't advance we didn't remove any blankspace
-    // so we're done.
-    if (pos == pos_)
-      break;
-  }
-  if (is_eof()) {
-    return {Token::Type::kEOF, begin_source()};
-  }
-
-  return {};
+    return {};
 }
 
 Token Lexer::skip_comment() {
-  if (matches(pos_, "//")) {
-    // Line comment: ignore everything until the end of input or a blankspace
-    // character other than space or horizontal tab.
-    while (!is_eof() && !(is_blankspace(file_->content.data[pos_]) &&
-                          !matches(pos_, " ") && !matches(pos_, "\t"))) {
-      if (is_null()) {
-        return {Token::Type::kError, begin_source(), "null character found"};
-      }
-      pos_++;
-      location_.column++;
+    if (matches(pos(), "//")) {
+        // Line comment: ignore everything until the end of line.
+        while (!is_eol()) {
+            if (is_null()) {
+                return {Token::Type::kError, begin_source(), "null character found"};
+            }
+            advance();
+        }
+        return {};
+    }
+
+    if (matches(pos(), "/*")) {
+        // Block comment: ignore everything until the closing '*/' token.
+
+        // Record source location of the initial '/*'
+        auto source = begin_source();
+        source.range.end.column += 1;
+
+        advance(2);
+
+        int depth = 1;
+        while (!is_eof() && depth > 0) {
+            if (matches(pos(), "/*")) {
+                // Start of block comment: increase nesting depth.
+                advance(2);
+                depth++;
+            } else if (matches(pos(), "*/")) {
+                // End of block comment: decrease nesting depth.
+                advance(2);
+                depth--;
+            } else if (is_eol()) {
+                // Newline: skip and update source location.
+                advance_line();
+            } else if (is_null()) {
+                return {Token::Type::kError, begin_source(), "null character found"};
+            } else {
+                // Anything else: skip and update source location.
+                advance();
+            }
+        }
+        if (depth > 0) {
+            return {Token::Type::kError, source, "unterminated block comment"};
+        }
     }
     return {};
-  }
-
-  if (matches(pos_, "/*")) {
-    // Block comment: ignore everything until the closing '*/' token.
-
-    // Record source location of the initial '/*'
-    auto source = begin_source();
-    source.range.end.column += 1;
-
-    pos_ += 2;
-    location_.column += 2;
-
-    int depth = 1;
-    while (!is_eof() && depth > 0) {
-      if (matches(pos_, "/*")) {
-        // Start of block comment: increase nesting depth.
-        pos_ += 2;
-        location_.column += 2;
-        depth++;
-      } else if (matches(pos_, "*/")) {
-        // End of block comment: decrease nesting depth.
-        pos_ += 2;
-        location_.column += 2;
-        depth--;
-      } else if (matches(pos_, "\n")) {
-        // Newline: skip and update source location.
-        pos_++;
-        location_.line++;
-        location_.column = 1;
-      } else if (is_null()) {
-        return {Token::Type::kError, begin_source(), "null character found"};
-      } else {
-        // Anything else: skip and update source location.
-        pos_++;
-        location_.column++;
-      }
-    }
-    if (depth > 0) {
-      return {Token::Type::kError, source, "unterminated block comment"};
-    }
-  }
-  return {};
 }
 
 Token Lexer::try_float() {
-  auto start = pos_;
-  auto end = pos_;
+    auto start = pos();
+    auto end = pos();
 
-  auto source = begin_source();
-  bool has_mantissa_digits = false;
+    auto source = begin_source();
+    bool has_mantissa_digits = false;
 
-  if (matches(end, "-")) {
-    end++;
-  }
-  while (end < len_ && is_digit(file_->content.data[end])) {
-    has_mantissa_digits = true;
-    end++;
-  }
-
-  bool has_point = false;
-  if (end < len_ && matches(end, ".")) {
-    has_point = true;
-    end++;
-  }
-
-  while (end < len_ && is_digit(file_->content.data[end])) {
-    has_mantissa_digits = true;
-    end++;
-  }
-
-  if (!has_mantissa_digits) {
-    return {};
-  }
-
-  // Parse the exponent if one exists
-  bool has_exponent = false;
-  if (end < len_ && (matches(end, "e") || matches(end, "E"))) {
-    end++;
-    if (end < len_ && (matches(end, "+") || matches(end, "-"))) {
-      end++;
+    if (matches(end, "-")) {
+        end++;
+    }
+    while (end < length() && is_digit(at(end))) {
+        has_mantissa_digits = true;
+        end++;
     }
 
-    while (end < len_ && isdigit(file_->content.data[end])) {
-      has_exponent = true;
-      end++;
+    bool has_point = false;
+    if (end < length() && matches(end, ".")) {
+        has_point = true;
+        end++;
     }
 
-    // If an 'e' or 'E' was present, then the number part must also be present.
-    if (!has_exponent) {
-      const auto str = file_->content.data.substr(start, end - start);
-      return {Token::Type::kError, source,
-              "incomplete exponent for floating point literal: " + str};
+    while (end < length() && is_digit(at(end))) {
+        has_mantissa_digits = true;
+        end++;
     }
-  }
 
-  bool has_f_suffix = false;
-  if (end < len_ && matches(end, "f")) {
-    end++;
-    has_f_suffix = true;
-  }
+    if (!has_mantissa_digits) {
+        return {};
+    }
 
-  if (!has_point && !has_exponent && !has_f_suffix) {
-    // If it only has digits then it's an integer.
-    return {};
-  }
+    // Parse the exponent if one exists
+    bool has_exponent = false;
+    if (end < length() && (matches(end, "e") || matches(end, "E"))) {
+        end++;
+        if (end < length() && (matches(end, "+") || matches(end, "-"))) {
+            end++;
+        }
 
-  // Save the error string, for use by diagnostics.
-  const auto str = file_->content.data.substr(start, end - start);
+        while (end < length() && isdigit(at(end))) {
+            has_exponent = true;
+            end++;
+        }
 
-  pos_ = end;
-  location_.column += (end - start);
+        // If an 'e' or 'E' was present, then the number part must also be present.
+        if (!has_exponent) {
+            const auto str = std::string{substr(start, end - start)};
+            return {Token::Type::kError, source,
+                    "incomplete exponent for floating point literal: " + str};
+        }
+    }
 
-  end_source(source);
+    bool has_f_suffix = false;
+    if (end < length() && matches(end, "f")) {
+        end++;
+        has_f_suffix = true;
+    }
 
-  auto res = strtod(file_->content.data.c_str() + start, nullptr);
-  // This errors out if a non-zero magnitude is too small to represent in a
-  // float. It can't be represented faithfully in an f32.
-  const auto magnitude = std::fabs(res);
-  if (0.0 < magnitude &&
-      magnitude < static_cast<double>(std::numeric_limits<float>::min())) {
-    return {Token::Type::kError, source,
-            "f32 (" + str + ") magnitude too small, not representable"};
-  }
-  // This handles if the number is really large negative number
-  if (res < static_cast<double>(std::numeric_limits<float>::lowest())) {
-    return {Token::Type::kError, source,
-            "f32 (" + str + ") too large (negative)"};
-  }
-  if (res > static_cast<double>(std::numeric_limits<float>::max())) {
-    return {Token::Type::kError, source,
-            "f32 (" + str + ") too large (positive)"};
-  }
+    if (!has_point && !has_exponent && !has_f_suffix) {
+        // If it only has digits then it's an integer.
+        return {};
+    }
 
-  return {source, static_cast<float>(res)};
+    // Save the error string, for use by diagnostics.
+    const auto str = std::string{substr(start, end - start)};
+
+    advance(end - start);
+    end_source(source);
+
+    auto res = strtod(&at(start), nullptr);
+    // This errors out if a non-zero magnitude is too small to represent in a
+    // float. It can't be represented faithfully in an f32.
+    const auto magnitude = std::fabs(res);
+    if (0.0 < magnitude && magnitude < static_cast<double>(std::numeric_limits<float>::min())) {
+        return {Token::Type::kError, source,
+                "f32 (" + str + ") magnitude too small, not representable"};
+    }
+    // This handles if the number is really large negative number
+    if (res < static_cast<double>(std::numeric_limits<float>::lowest())) {
+        return {Token::Type::kError, source, "f32 (" + str + ") too large (negative)"};
+    }
+    if (res > static_cast<double>(std::numeric_limits<float>::max())) {
+        return {Token::Type::kError, source, "f32 (" + str + ") too large (positive)"};
+    }
+
+    return {source, static_cast<float>(res)};
 }
 
 Token Lexer::try_hex_float() {
-  constexpr uint32_t kTotalBits = 32;
-  constexpr uint32_t kTotalMsb = kTotalBits - 1;
-  constexpr uint32_t kMantissaBits = 23;
-  constexpr uint32_t kMantissaMsb = kMantissaBits - 1;
-  constexpr uint32_t kMantissaShiftRight = kTotalBits - kMantissaBits;
-  constexpr int32_t kExponentBias = 127;
-  constexpr int32_t kExponentMax = 255;
-  constexpr uint32_t kExponentBits = 8;
-  constexpr uint32_t kExponentMask = (1 << kExponentBits) - 1;
-  constexpr uint32_t kExponentLeftShift = kMantissaBits;
-  constexpr uint32_t kSignBit = 31;
+    constexpr uint32_t kTotalBits = 32;
+    constexpr uint32_t kTotalMsb = kTotalBits - 1;
+    constexpr uint32_t kMantissaBits = 23;
+    constexpr uint32_t kMantissaMsb = kMantissaBits - 1;
+    constexpr uint32_t kMantissaShiftRight = kTotalBits - kMantissaBits;
+    constexpr int32_t kExponentBias = 127;
+    constexpr int32_t kExponentMax = 255;
+    constexpr uint32_t kExponentBits = 8;
+    constexpr uint32_t kExponentMask = (1 << kExponentBits) - 1;
+    constexpr uint32_t kExponentLeftShift = kMantissaBits;
+    constexpr uint32_t kSignBit = 31;
 
-  auto start = pos_;
-  auto end = pos_;
+    auto start = pos();
+    auto end = pos();
 
-  auto source = begin_source();
+    auto source = begin_source();
 
-  // clang-format off
+    // clang-format off
   // -?0[xX]([0-9a-fA-F]*.?[0-9a-fA-F]+ | [0-9a-fA-F]+.[0-9a-fA-F]*)(p|P)(+|-)?[0-9]+  // NOLINT
-  // clang-format on
+    // clang-format on
 
-  // -?
-  int32_t sign_bit = 0;
-  if (matches(end, "-")) {
-    sign_bit = 1;
-    end++;
-  }
-  // 0[xX]
-  if (matches(end, "0x") || matches(end, "0X")) {
-    end += 2;
-  } else {
-    return {};
-  }
-
-  uint32_t mantissa = 0;
-  uint32_t exponent = 0;
-
-  // TODO(dneto): Values in the normal range for the format do not explicitly
-  // store the most significant bit.  The algorithm here works hard to eliminate
-  // that bit in the representation during parsing, and then it backtracks
-  // when it sees it may have to explicitly represent it, and backtracks again
-  // when it sees the number is sub-normal (i.e. the exponent underflows).
-  // I suspect the logic can be clarified by storing it during parsing, and
-  // then removing it later only when needed.
-
-  // `set_next_mantissa_bit_to` sets next `mantissa` bit starting from msb to
-  // lsb to value 1 if `set` is true, 0 otherwise. Returns true on success, i.e.
-  // when the bit can be accommodated in the available space.
-  uint32_t mantissa_next_bit = kTotalMsb;
-  auto set_next_mantissa_bit_to = [&](bool set, bool integer_part) -> bool {
-    // If adding bits for the integer part, we can overflow whether we set the
-    // bit or not. For the fractional part, we can only overflow when setting
-    // the bit.
-    const bool check_overflow = integer_part || set;
-    // Note: mantissa_next_bit actually decrements, so comparing it as
-    // larger than a positive number relies on wraparound.
-    if (check_overflow && (mantissa_next_bit > kTotalMsb)) {
-      return false;  // Overflowed mantissa
+    // -?
+    int32_t sign_bit = 0;
+    if (matches(end, "-")) {
+        sign_bit = 1;
+        end++;
     }
-    if (set) {
-      mantissa |= (1 << mantissa_next_bit);
-    }
-    --mantissa_next_bit;
-    return true;
-  };
-
-  // Collect integer range (if any)
-  auto integer_range = std::make_pair(end, end);
-  while (end < len_ && is_hex(file_->content.data[end])) {
-    integer_range.second = ++end;
-  }
-
-  // .?
-  bool hex_point = false;
-  if (matches(end, ".")) {
-    hex_point = true;
-    end++;
-  }
-
-  // Collect fractional range (if any)
-  auto fractional_range = std::make_pair(end, end);
-  while (end < len_ && is_hex(file_->content.data[end])) {
-    fractional_range.second = ++end;
-  }
-
-  // Must have at least an integer or fractional part
-  if ((integer_range.first == integer_range.second) &&
-      (fractional_range.first == fractional_range.second)) {
-    return {};
-  }
-
-  // Is the binary exponent present?  It's optional.
-  const bool has_exponent = (matches(end, "p") || matches(end, "P"));
-  if (has_exponent) {
-    end++;
-  }
-  if (!has_exponent && !hex_point) {
-    // It's not a hex float. At best it's a hex integer.
-    return {};
-  }
-
-  // At this point, we know for sure our token is a hex float value,
-  // or an invalid token.
-
-  // Parse integer part
-  // [0-9a-fA-F]*
-
-  bool has_zero_integer = true;
-  // The magnitude is zero if and only if seen_prior_one_bits is false.
-  bool seen_prior_one_bits = false;
-  for (auto i = integer_range.first; i < integer_range.second; ++i) {
-    const auto nibble = hex_value(file_->content.data[i]);
-    if (nibble != 0) {
-      has_zero_integer = false;
+    // 0[xX]
+    if (matches(end, "0x") || matches(end, "0X")) {
+        end += 2;
+    } else {
+        return {};
     }
 
-    for (int32_t bit = 3; bit >= 0; --bit) {
-      auto v = 1 & (nibble >> bit);
+    uint32_t mantissa = 0;
+    uint32_t exponent = 0;
 
-      // Skip leading 0s and the first 1
-      if (seen_prior_one_bits) {
-        if (!set_next_mantissa_bit_to(v != 0, true)) {
-          return {Token::Type::kError, source,
-                  "mantissa is too large for hex float"};
+    // TODO(dneto): Values in the normal range for the format do not explicitly
+    // store the most significant bit.  The algorithm here works hard to eliminate
+    // that bit in the representation during parsing, and then it backtracks
+    // when it sees it may have to explicitly represent it, and backtracks again
+    // when it sees the number is sub-normal (i.e. the exponent underflows).
+    // I suspect the logic can be clarified by storing it during parsing, and
+    // then removing it later only when needed.
+
+    // `set_next_mantissa_bit_to` sets next `mantissa` bit starting from msb to
+    // lsb to value 1 if `set` is true, 0 otherwise. Returns true on success, i.e.
+    // when the bit can be accommodated in the available space.
+    uint32_t mantissa_next_bit = kTotalMsb;
+    auto set_next_mantissa_bit_to = [&](bool set, bool integer_part) -> bool {
+        // If adding bits for the integer part, we can overflow whether we set the
+        // bit or not. For the fractional part, we can only overflow when setting
+        // the bit.
+        const bool check_overflow = integer_part || set;
+        // Note: mantissa_next_bit actually decrements, so comparing it as
+        // larger than a positive number relies on wraparound.
+        if (check_overflow && (mantissa_next_bit > kTotalMsb)) {
+            return false;  // Overflowed mantissa
         }
-        ++exponent;
-      } else {
-        if (v == 1) {
-          seen_prior_one_bits = true;
+        if (set) {
+            mantissa |= (1 << mantissa_next_bit);
         }
-      }
+        --mantissa_next_bit;
+        return true;
+    };
+
+    // Collect integer range (if any)
+    auto integer_range = std::make_pair(end, end);
+    while (end < length() && is_hex(at(end))) {
+        integer_range.second = ++end;
     }
-  }
 
-  // Parse fractional part
-  // [0-9a-fA-F]*
-  for (auto i = fractional_range.first; i < fractional_range.second; ++i) {
-    auto nibble = hex_value(file_->content.data[i]);
-    for (int32_t bit = 3; bit >= 0; --bit) {
-      auto v = 1 & (nibble >> bit);
+    // .?
+    bool hex_point = false;
+    if (matches(end, ".")) {
+        hex_point = true;
+        end++;
+    }
 
-      if (v == 1) {
-        seen_prior_one_bits = true;
-      }
+    // Collect fractional range (if any)
+    auto fractional_range = std::make_pair(end, end);
+    while (end < length() && is_hex(at(end))) {
+        fractional_range.second = ++end;
+    }
 
-      // If integer part is 0, we only start writing bits to the
-      // mantissa once we have a non-zero fractional bit. While the fractional
-      // values are 0, we adjust the exponent to avoid overflowing `mantissa`.
-      if (!seen_prior_one_bits) {
-        --exponent;
-      } else {
-        if (!set_next_mantissa_bit_to(v != 0, false)) {
-          return {Token::Type::kError, source,
-                  "mantissa is too large for hex float"};
+    // Must have at least an integer or fractional part
+    if ((integer_range.first == integer_range.second) &&
+        (fractional_range.first == fractional_range.second)) {
+        return {};
+    }
+
+    // Is the binary exponent present?  It's optional.
+    const bool has_exponent = (matches(end, "p") || matches(end, "P"));
+    if (has_exponent) {
+        end++;
+    }
+    if (!has_exponent && !hex_point) {
+        // It's not a hex float. At best it's a hex integer.
+        return {};
+    }
+
+    // At this point, we know for sure our token is a hex float value,
+    // or an invalid token.
+
+    // Parse integer part
+    // [0-9a-fA-F]*
+
+    bool has_zero_integer = true;
+    // The magnitude is zero if and only if seen_prior_one_bits is false.
+    bool seen_prior_one_bits = false;
+    for (auto i = integer_range.first; i < integer_range.second; ++i) {
+        const auto nibble = hex_value(at(i));
+        if (nibble != 0) {
+            has_zero_integer = false;
         }
-      }
-    }
-  }
 
-  // Determine if the value of the mantissa is zero.
-  // Note: it's not enough to check mantissa == 0 as we drop the initial bit,
-  // whether it's in the integer part or the fractional part.
-  const bool is_zero = !seen_prior_one_bits;
-  TINT_ASSERT(Reader, !is_zero || mantissa == 0);
+        for (int32_t bit = 3; bit >= 0; --bit) {
+            auto v = 1 & (nibble >> bit);
 
-  // Parse the optional exponent.
-  // ((p|P)(\+|-)?[0-9]+)?
-  uint32_t input_exponent = 0;  // Defaults to 0 if not present
-  int32_t exponent_sign = 1;
-  // If the 'p' part is present, the rest of the exponent must exist.
-  if (has_exponent) {
-    // Parse the rest of the exponent.
-    // (+|-)?
-    if (matches(end, "+")) {
-      end++;
-    } else if (matches(end, "-")) {
-      exponent_sign = -1;
-      end++;
+            // Skip leading 0s and the first 1
+            if (seen_prior_one_bits) {
+                if (!set_next_mantissa_bit_to(v != 0, true)) {
+                    return {Token::Type::kError, source, "mantissa is too large for hex float"};
+                }
+                ++exponent;
+            } else {
+                if (v == 1) {
+                    seen_prior_one_bits = true;
+                }
+            }
+        }
     }
 
-    // Parse exponent from input
-    // [0-9]+
-    // Allow overflow (in uint32_t) when the floating point value magnitude is
-    // zero.
-    bool has_exponent_digits = false;
-    while (end < len_ && isdigit(file_->content.data[end])) {
-      has_exponent_digits = true;
-      auto prev_exponent = input_exponent;
-      input_exponent =
-          (input_exponent * 10) + dec_value(file_->content.data[end]);
-      // Check if we've overflowed input_exponent. This only matters when
-      // the mantissa is non-zero.
-      if (!is_zero && (prev_exponent > input_exponent)) {
-        return {Token::Type::kError, source,
-                "exponent is too large for hex float"};
-      }
-      end++;
+    // Parse fractional part
+    // [0-9a-fA-F]*
+    for (auto i = fractional_range.first; i < fractional_range.second; ++i) {
+        auto nibble = hex_value(at(i));
+        for (int32_t bit = 3; bit >= 0; --bit) {
+            auto v = 1 & (nibble >> bit);
+
+            if (v == 1) {
+                seen_prior_one_bits = true;
+            }
+
+            // If integer part is 0, we only start writing bits to the
+            // mantissa once we have a non-zero fractional bit. While the fractional
+            // values are 0, we adjust the exponent to avoid overflowing `mantissa`.
+            if (!seen_prior_one_bits) {
+                --exponent;
+            } else {
+                if (!set_next_mantissa_bit_to(v != 0, false)) {
+                    return {Token::Type::kError, source, "mantissa is too large for hex float"};
+                }
+            }
+        }
     }
 
-    // Parse optional 'f' suffix.  For a hex float, it can only exist
-    // when the exponent is present. Otherwise it will look like
-    // one of the mantissa digits.
-    if (end < len_ && matches(end, "f")) {
-      end++;
+    // Determine if the value of the mantissa is zero.
+    // Note: it's not enough to check mantissa == 0 as we drop the initial bit,
+    // whether it's in the integer part or the fractional part.
+    const bool is_zero = !seen_prior_one_bits;
+    TINT_ASSERT(Reader, !is_zero || mantissa == 0);
+
+    // Parse the optional exponent.
+    // ((p|P)(\+|-)?[0-9]+)?
+    uint32_t input_exponent = 0;  // Defaults to 0 if not present
+    int32_t exponent_sign = 1;
+    // If the 'p' part is present, the rest of the exponent must exist.
+    if (has_exponent) {
+        // Parse the rest of the exponent.
+        // (+|-)?
+        if (matches(end, "+")) {
+            end++;
+        } else if (matches(end, "-")) {
+            exponent_sign = -1;
+            end++;
+        }
+
+        // Parse exponent from input
+        // [0-9]+
+        // Allow overflow (in uint32_t) when the floating point value magnitude is
+        // zero.
+        bool has_exponent_digits = false;
+        while (end < length() && isdigit(at(end))) {
+            has_exponent_digits = true;
+            auto prev_exponent = input_exponent;
+            input_exponent = (input_exponent * 10) + dec_value(at(end));
+            // Check if we've overflowed input_exponent. This only matters when
+            // the mantissa is non-zero.
+            if (!is_zero && (prev_exponent > input_exponent)) {
+                return {Token::Type::kError, source, "exponent is too large for hex float"};
+            }
+            end++;
+        }
+
+        // Parse optional 'f' suffix.  For a hex float, it can only exist
+        // when the exponent is present. Otherwise it will look like
+        // one of the mantissa digits.
+        if (end < length() && matches(end, "f")) {
+            end++;
+        }
+
+        if (!has_exponent_digits) {
+            return {Token::Type::kError, source, "expected an exponent value for hex float"};
+        }
     }
 
-    if (!has_exponent_digits) {
-      return {Token::Type::kError, source,
-              "expected an exponent value for hex float"};
-    }
-  }
+    advance(end - start);
+    end_source(source);
 
-  pos_ = end;
-  location_.column += (end - start);
-  end_source(source);
+    if (is_zero) {
+        // If value is zero, then ignore the exponent and produce a zero
+        exponent = 0;
+    } else {
+        // Ensure input exponent is not too large; i.e. that it won't overflow when
+        // adding the exponent bias.
+        const uint32_t kIntMax = static_cast<uint32_t>(std::numeric_limits<int32_t>::max());
+        const uint32_t kMaxInputExponent = kIntMax - kExponentBias;
+        if (input_exponent > kMaxInputExponent) {
+            return {Token::Type::kError, source, "exponent is too large for hex float"};
+        }
 
-  if (is_zero) {
-    // If value is zero, then ignore the exponent and produce a zero
-    exponent = 0;
-  } else {
-    // Ensure input exponent is not too large; i.e. that it won't overflow when
-    // adding the exponent bias.
-    const uint32_t kIntMax =
-        static_cast<uint32_t>(std::numeric_limits<int32_t>::max());
-    const uint32_t kMaxInputExponent = kIntMax - kExponentBias;
-    if (input_exponent > kMaxInputExponent) {
-      return {Token::Type::kError, source,
-              "exponent is too large for hex float"};
+        // Compute exponent so far
+        exponent += static_cast<uint32_t>(static_cast<int32_t>(input_exponent) * exponent_sign);
+
+        // Bias exponent if non-zero
+        // After this, if exponent is <= 0, our value is a denormal
+        exponent += kExponentBias;
+
+        // We know the number is not zero.  The MSB is 1 (by construction), and
+        // should be eliminated because it becomes the implicit 1 that isn't
+        // explicitly represented in the binary32 format.  We'll bring it back
+        // later if we find the exponent actually underflowed, i.e. the number
+        // is sub-normal.
+        if (has_zero_integer) {
+            mantissa <<= 1;
+            --exponent;
+        }
     }
 
-    // Compute exponent so far
-    exponent += static_cast<uint32_t>(static_cast<int32_t>(input_exponent) *
-                                      exponent_sign);
+    // We can now safely work with exponent as a signed quantity, as there's no
+    // chance to overflow
+    int32_t signed_exponent = static_cast<int32_t>(exponent);
 
-    // Bias exponent if non-zero
-    // After this, if exponent is <= 0, our value is a denormal
-    exponent += kExponentBias;
+    // Shift mantissa to occupy the low 23 bits
+    mantissa >>= kMantissaShiftRight;
 
-    // We know the number is not zero.  The MSB is 1 (by construction), and
-    // should be eliminated because it becomes the implicit 1 that isn't
-    // explicitly represented in the binary32 format.  We'll bring it back
-    // later if we find the exponent actually underflowed, i.e. the number
-    // is sub-normal.
-    if (has_zero_integer) {
-      mantissa <<= 1;
-      --exponent;
-    }
-  }
+    // If denormal, shift mantissa until our exponent is zero
+    if (!is_zero) {
+        // Denorm has exponent 0 and non-zero mantissa. We set the top bit here,
+        // then shift the mantissa to make exponent zero.
+        if (signed_exponent <= 0) {
+            mantissa >>= 1;
+            mantissa |= (1 << kMantissaMsb);
+        }
 
-  // We can now safely work with exponent as a signed quantity, as there's no
-  // chance to overflow
-  int32_t signed_exponent = static_cast<int32_t>(exponent);
+        while (signed_exponent < 0) {
+            mantissa >>= 1;
+            ++signed_exponent;
 
-  // Shift mantissa to occupy the low 23 bits
-  mantissa >>= kMantissaShiftRight;
-
-  // If denormal, shift mantissa until our exponent is zero
-  if (!is_zero) {
-    // Denorm has exponent 0 and non-zero mantissa. We set the top bit here,
-    // then shift the mantissa to make exponent zero.
-    if (signed_exponent <= 0) {
-      mantissa >>= 1;
-      mantissa |= (1 << kMantissaMsb);
+            // If underflow, clamp to zero
+            if (mantissa == 0) {
+                signed_exponent = 0;
+            }
+        }
     }
 
-    while (signed_exponent < 0) {
-      mantissa >>= 1;
-      ++signed_exponent;
-
-      // If underflow, clamp to zero
-      if (mantissa == 0) {
-        signed_exponent = 0;
-      }
+    if (signed_exponent > kExponentMax) {
+        // Overflow: set to infinity
+        signed_exponent = kExponentMax;
+        mantissa = 0;
+    } else if (signed_exponent == kExponentMax && mantissa != 0) {
+        // NaN: set to infinity
+        mantissa = 0;
     }
-  }
 
-  if (signed_exponent > kExponentMax) {
-    // Overflow: set to infinity
-    signed_exponent = kExponentMax;
-    mantissa = 0;
-  } else if (signed_exponent == kExponentMax && mantissa != 0) {
-    // NaN: set to infinity
-    mantissa = 0;
-  }
+    // Combine sign, mantissa, and exponent
+    uint32_t result_u32 = sign_bit << kSignBit;
+    result_u32 |= mantissa;
+    result_u32 |= (static_cast<uint32_t>(signed_exponent) & kExponentMask) << kExponentLeftShift;
 
-  // Combine sign, mantissa, and exponent
-  uint32_t result_u32 = sign_bit << kSignBit;
-  result_u32 |= mantissa;
-  result_u32 |= (static_cast<uint32_t>(signed_exponent) & kExponentMask)
-                << kExponentLeftShift;
-
-  // Reinterpret as float and return
-  float result;
-  std::memcpy(&result, &result_u32, sizeof(result));
-  return {source, static_cast<float>(result)};
+    // Reinterpret as float and return
+    float result;
+    std::memcpy(&result, &result_u32, sizeof(result));
+    return {source, static_cast<float>(result)};
 }
 
 Token Lexer::build_token_from_int_if_possible(Source source,
                                               size_t start,
                                               size_t end,
                                               int32_t base) {
-  auto res = strtoll(file_->content.data.c_str() + start, nullptr, base);
-  if (matches(pos_, "u")) {
-    if (static_cast<uint64_t>(res) >
-        static_cast<uint64_t>(std::numeric_limits<uint32_t>::max())) {
-      return {Token::Type::kError, source,
-              "u32 (" + file_->content.data.substr(start, end - start) +
-                  ") too large"};
-    }
-    pos_ += 1;
-    location_.column += 1;
-    end_source(source);
-    return {source, static_cast<uint32_t>(res)};
-  }
+    int64_t res = strtoll(&at(start), nullptr, base);
 
-  if (res < static_cast<int64_t>(std::numeric_limits<int32_t>::min())) {
-    return {Token::Type::kError, source,
-            "i32 (" + file_->content.data.substr(start, end - start) +
-                ") too small"};
-  }
-  if (res > static_cast<int64_t>(std::numeric_limits<int32_t>::max())) {
-    return {Token::Type::kError, source,
-            "i32 (" + file_->content.data.substr(start, end - start) +
-                ") too large"};
-  }
-  end_source(source);
-  return {source, static_cast<int32_t>(res)};
+    auto str = [&] { return std::string{substr(start, end - start)}; };
+
+    if (matches(pos(), "u")) {
+        switch (check_limits<uint32_t>(res)) {
+            case LimitCheck::kTooSmall:
+                return {Token::Type::kError, source, "unsigned literal cannot be negative"};
+            case LimitCheck::kTooLarge:
+                return {Token::Type::kError, source, str() + " too large for u32"};
+            default:
+                advance(1);
+                end_source(source);
+                return {Token::Type::kIntULiteral, source, res};
+        }
+    }
+
+    if (matches(pos(), "i")) {
+        switch (check_limits<int32_t>(res)) {
+            case LimitCheck::kTooSmall:
+                return {Token::Type::kError, source, str() + " too small for i32"};
+            case LimitCheck::kTooLarge:
+                return {Token::Type::kError, source, str() + " too large for i32"};
+            default:
+                break;
+        }
+        advance(1);
+        end_source(source);
+        return {Token::Type::kIntILiteral, source, res};
+    }
+
+    // TODO(crbug.com/tint/1504): Properly support abstract int:
+    // Change `AbstractIntType` to `int64_t`, update errors to say 'abstract int'.
+    using AbstractIntType = int32_t;
+    switch (check_limits<AbstractIntType>(res)) {
+        case LimitCheck::kTooSmall:
+            return {Token::Type::kError, source, str() + " too small for i32"};
+        case LimitCheck::kTooLarge:
+            return {Token::Type::kError, source, str() + " too large for i32"};
+        default:
+            end_source(source);
+            return {Token::Type::kIntLiteral, source, res};
+    }
 }
 
 Token Lexer::try_hex_integer() {
-  constexpr size_t kMaxDigits = 8;  // Valid for both 32-bit integer types
-  auto start = pos_;
-  auto end = pos_;
+    constexpr size_t kMaxDigits = 8;  // Valid for both 32-bit integer types
+    auto start = pos();
+    auto end = pos();
 
-  auto source = begin_source();
+    auto source = begin_source();
 
-  if (matches(end, "-")) {
-    end++;
-  }
-
-  if (matches(end, "0x") || matches(end, "0X")) {
-    end += 2;
-  } else {
-    return {};
-  }
-
-  auto first = end;
-  while (!is_eof() && is_hex(file_->content.data[end])) {
-    end++;
-
-    auto digits = end - first;
-    if (digits > kMaxDigits) {
-      return {Token::Type::kError, source,
-              "integer literal (" +
-                  file_->content.data.substr(start, end - 1 - start) +
-                  "...) has too many digits"};
+    if (matches(end, "-")) {
+        end++;
     }
-  }
-  if (first == end) {
-    return {Token::Type::kError, source,
-            "integer or float hex literal has no significant digits"};
-  }
 
-  pos_ = end;
-  location_.column += (end - start);
+    if (matches(end, "0x") || matches(end, "0X")) {
+        end += 2;
+    } else {
+        return {};
+    }
 
-  return build_token_from_int_if_possible(source, start, end, 16);
+    auto first = end;
+    while (!is_eol() && is_hex(at(end))) {
+        end++;
+
+        auto digits = end - first;
+        if (digits > kMaxDigits) {
+            return {Token::Type::kError, source,
+                    "integer literal (" + std::string{substr(start, end - 1 - start)} +
+                        "...) has too many digits"};
+        }
+    }
+    if (first == end) {
+        return {Token::Type::kError, source,
+                "integer or float hex literal has no significant digits"};
+    }
+
+    advance(end - start);
+
+    return build_token_from_int_if_possible(source, start, end, 16);
 }
 
 Token Lexer::try_integer() {
-  constexpr size_t kMaxDigits = 10;  // Valid for both 32-bit integer types
-  auto start = pos_;
-  auto end = start;
+    constexpr size_t kMaxDigits = 10;  // Valid for both 32-bit integer types
+    auto start = pos();
+    auto end = start;
 
-  auto source = begin_source();
+    auto source = begin_source();
 
-  if (matches(end, "-")) {
-    end++;
-  }
-
-  if (end >= len_ || !is_digit(file_->content.data[end])) {
-    return {};
-  }
-
-  auto first = end;
-  // If the first digit is a zero this must only be zero as leading zeros
-  // are not allowed.
-  auto next = first + 1;
-  if (next < len_) {
-    if (file_->content.data[first] == '0' &&
-        is_digit(file_->content.data[next])) {
-      return {Token::Type::kError, source,
-              "integer literal (" +
-                  file_->content.data.substr(start, end - 1 - start) +
-                  "...) has leading 0s"};
-    }
-  }
-
-  while (end < len_ && is_digit(file_->content.data[end])) {
-    auto digits = end - first;
-    if (digits > kMaxDigits) {
-      return {Token::Type::kError, source,
-              "integer literal (" +
-                  file_->content.data.substr(start, end - 1 - start) +
-                  "...) has too many digits"};
+    if (matches(end, "-")) {
+        end++;
     }
 
-    end++;
-  }
+    if (end >= length() || !is_digit(at(end))) {
+        return {};
+    }
 
-  pos_ = end;
-  location_.column += (end - start);
+    auto first = end;
+    // If the first digit is a zero this must only be zero as leading zeros
+    // are not allowed.
+    auto next = first + 1;
+    if (next < length()) {
+        if (at(first) == '0' && is_digit(at(next))) {
+            return {Token::Type::kError, source,
+                    "integer literal (" + std::string{substr(start, end - 1 - start)} +
+                        "...) has leading 0s"};
+        }
+    }
 
-  return build_token_from_int_if_possible(source, start, end, 10);
+    while (end < length() && is_digit(at(end))) {
+        auto digits = end - first;
+        if (digits > kMaxDigits) {
+            return {Token::Type::kError, source,
+                    "integer literal (" + std::string{substr(start, end - 1 - start)} +
+                        "...) has too many digits"};
+        }
+
+        end++;
+    }
+
+    advance(end - start);
+
+    return build_token_from_int_if_possible(source, start, end, 10);
 }
 
 Token Lexer::try_ident() {
-  auto source = begin_source();
-  auto start = pos_;
+    auto source = begin_source();
+    auto start = pos();
 
-  // This below assumes that the size of a single std::string element is 1 byte.
-  static_assert(sizeof(file_->content.data[0]) == sizeof(uint8_t),
-                "tint::reader::wgsl requires the size of a std::string element "
-                "to be a single byte");
-
-  // Must begin with an XID_Source unicode character, or underscore
-  {
-    auto* utf8 = reinterpret_cast<const uint8_t*>(&file_->content.data[pos_]);
-    auto [code_point, n] =
-        text::utf8::Decode(utf8, file_->content.data.size() - pos_);
-    if (n == 0) {
-      pos_++;  // Skip the bad byte.
-      return {Token::Type::kError, source, "invalid UTF-8"};
-    }
-    if (code_point != text::CodePoint('_') && !code_point.IsXIDStart()) {
-      return {};
-    }
-    // Consume start codepoint
-    pos_ += n;
-    location_.column += n;
-  }
-
-  while (!is_eof()) {
-    // Must continue with an XID_Continue unicode character
-    auto* utf8 = reinterpret_cast<const uint8_t*>(&file_->content.data[pos_]);
-    auto [code_point, n] =
-        text::utf8::Decode(utf8, file_->content.data.size() - pos_);
-    if (n == 0) {
-      pos_++;  // Skip the bad byte.
-      return {Token::Type::kError, source, "invalid UTF-8"};
-    }
-    if (!code_point.IsXIDContinue()) {
-      break;
+    // Must begin with an XID_Source unicode character, or underscore
+    {
+        auto* utf8 = reinterpret_cast<const uint8_t*>(&at(pos()));
+        auto [code_point, n] = text::utf8::Decode(utf8, length() - pos());
+        if (n == 0) {
+            advance();  // Skip the bad byte.
+            return {Token::Type::kError, source, "invalid UTF-8"};
+        }
+        if (code_point != text::CodePoint('_') && !code_point.IsXIDStart()) {
+            return {};
+        }
+        // Consume start codepoint
+        advance(n);
     }
 
-    // Consume continuing codepoint
-    pos_ += n;
-    location_.column += n;
-  }
+    while (!is_eol()) {
+        // Must continue with an XID_Continue unicode character
+        auto* utf8 = reinterpret_cast<const uint8_t*>(&at(pos()));
+        auto [code_point, n] = text::utf8::Decode(utf8, line().size() - pos());
+        if (n == 0) {
+            advance();  // Skip the bad byte.
+            return {Token::Type::kError, source, "invalid UTF-8"};
+        }
+        if (!code_point.IsXIDContinue()) {
+            break;
+        }
 
-  if (file_->content.data[start] == '_') {
-    // Check for an underscore on its own (special token), or a
-    // double-underscore (not allowed).
-    if ((pos_ == start + 1) || (file_->content.data[start + 1] == '_')) {
-      location_.column -= (pos_ - start);
-      pos_ = start;
-      return {};
+        // Consume continuing codepoint
+        advance(n);
     }
-  }
 
-  auto str = file_->content.data_view.substr(start, pos_ - start);
-  end_source(source);
+    if (at(start) == '_') {
+        // Check for an underscore on its own (special token), or a
+        // double-underscore (not allowed).
+        if ((pos() == start + 1) || (at(start + 1) == '_')) {
+            set_pos(start);
+            return {};
+        }
+    }
 
-  auto t = check_keyword(source, str);
-  if (!t.IsUninitialized()) {
-    return t;
-  }
+    auto str = substr(start, pos() - start);
+    end_source(source);
 
-  return {Token::Type::kIdentifier, source, str};
+    auto t = check_keyword(source, str);
+    if (!t.IsUninitialized()) {
+        return t;
+    }
+
+    return {Token::Type::kIdentifier, source, str};
 }
 
 Token Lexer::try_punctuation() {
-  auto source = begin_source();
-  auto type = Token::Type::kUninitialized;
+    auto source = begin_source();
+    auto type = Token::Type::kUninitialized;
 
-  if (matches(pos_, "@")) {
-    type = Token::Type::kAttr;
-    pos_ += 1;
-    location_.column += 1;
-  } else if (matches(pos_, "(")) {
-    type = Token::Type::kParenLeft;
-    pos_ += 1;
-    location_.column += 1;
-  } else if (matches(pos_, ")")) {
-    type = Token::Type::kParenRight;
-    pos_ += 1;
-    location_.column += 1;
-  } else if (matches(pos_, "[")) {
-    type = Token::Type::kBracketLeft;
-    pos_ += 1;
-    location_.column += 1;
-  } else if (matches(pos_, "]")) {
-    type = Token::Type::kBracketRight;
-    pos_ += 1;
-    location_.column += 1;
-  } else if (matches(pos_, "{")) {
-    type = Token::Type::kBraceLeft;
-    pos_ += 1;
-    location_.column += 1;
-  } else if (matches(pos_, "}")) {
-    type = Token::Type::kBraceRight;
-    pos_ += 1;
-    location_.column += 1;
-  } else if (matches(pos_, "&&")) {
-    type = Token::Type::kAndAnd;
-    pos_ += 2;
-    location_.column += 2;
-  } else if (matches(pos_, "&=")) {
-    type = Token::Type::kAndEqual;
-    pos_ += 2;
-    location_.column += 2;
-  } else if (matches(pos_, "&")) {
-    type = Token::Type::kAnd;
-    pos_ += 1;
-    location_.column += 1;
-  } else if (matches(pos_, "/=")) {
-    type = Token::Type::kDivisionEqual;
-    pos_ += 2;
-    location_.column += 2;
-  } else if (matches(pos_, "/")) {
-    type = Token::Type::kForwardSlash;
-    pos_ += 1;
-    location_.column += 1;
-  } else if (matches(pos_, "!=")) {
-    type = Token::Type::kNotEqual;
-    pos_ += 2;
-    location_.column += 2;
-  } else if (matches(pos_, "!")) {
-    type = Token::Type::kBang;
-    pos_ += 1;
-    location_.column += 1;
-  } else if (matches(pos_, ":")) {
-    type = Token::Type::kColon;
-    pos_ += 1;
-    location_.column += 1;
-  } else if (matches(pos_, ",")) {
-    type = Token::Type::kComma;
-    pos_ += 1;
-    location_.column += 1;
-  } else if (matches(pos_, "==")) {
-    type = Token::Type::kEqualEqual;
-    pos_ += 2;
-    location_.column += 2;
-  } else if (matches(pos_, "=")) {
-    type = Token::Type::kEqual;
-    pos_ += 1;
-    location_.column += 1;
-  } else if (matches(pos_, ">=")) {
-    type = Token::Type::kGreaterThanEqual;
-    pos_ += 2;
-    location_.column += 2;
-  } else if (matches(pos_, ">>")) {
-    type = Token::Type::kShiftRight;
-    pos_ += 2;
-    location_.column += 2;
-  } else if (matches(pos_, ">")) {
-    type = Token::Type::kGreaterThan;
-    pos_ += 1;
-    location_.column += 1;
-  } else if (matches(pos_, "<=")) {
-    type = Token::Type::kLessThanEqual;
-    pos_ += 2;
-    location_.column += 2;
-  } else if (matches(pos_, "<<")) {
-    type = Token::Type::kShiftLeft;
-    pos_ += 2;
-    location_.column += 2;
-  } else if (matches(pos_, "<")) {
-    type = Token::Type::kLessThan;
-    pos_ += 1;
-    location_.column += 1;
-  } else if (matches(pos_, "%=")) {
-    type = Token::Type::kModuloEqual;
-    pos_ += 2;
-    location_.column += 2;
-  } else if (matches(pos_, "%")) {
-    type = Token::Type::kMod;
-    pos_ += 1;
-    location_.column += 1;
-  } else if (matches(pos_, "->")) {
-    type = Token::Type::kArrow;
-    pos_ += 2;
-    location_.column += 2;
-  } else if (matches(pos_, "--")) {
-    type = Token::Type::kMinusMinus;
-    pos_ += 2;
-    location_.column += 2;
-  } else if (matches(pos_, "-=")) {
-    type = Token::Type::kMinusEqual;
-    pos_ += 2;
-    location_.column += 2;
-  } else if (matches(pos_, "-")) {
-    type = Token::Type::kMinus;
-    pos_ += 1;
-    location_.column += 1;
-  } else if (matches(pos_, ".")) {
-    type = Token::Type::kPeriod;
-    pos_ += 1;
-    location_.column += 1;
-  } else if (matches(pos_, "++")) {
-    type = Token::Type::kPlusPlus;
-    pos_ += 2;
-    location_.column += 2;
-  } else if (matches(pos_, "+=")) {
-    type = Token::Type::kPlusEqual;
-    pos_ += 2;
-    location_.column += 2;
-  } else if (matches(pos_, "+")) {
-    type = Token::Type::kPlus;
-    pos_ += 1;
-    location_.column += 1;
-  } else if (matches(pos_, "||")) {
-    type = Token::Type::kOrOr;
-    pos_ += 2;
-    location_.column += 2;
-  } else if (matches(pos_, "|=")) {
-    type = Token::Type::kOrEqual;
-    pos_ += 2;
-    location_.column += 2;
-  } else if (matches(pos_, "|")) {
-    type = Token::Type::kOr;
-    pos_ += 1;
-    location_.column += 1;
-  } else if (matches(pos_, ";")) {
-    type = Token::Type::kSemicolon;
-    pos_ += 1;
-    location_.column += 1;
-  } else if (matches(pos_, "*=")) {
-    type = Token::Type::kTimesEqual;
-    pos_ += 2;
-    location_.column += 2;
-  } else if (matches(pos_, "*")) {
-    type = Token::Type::kStar;
-    pos_ += 1;
-    location_.column += 1;
-  } else if (matches(pos_, "~")) {
-    type = Token::Type::kTilde;
-    pos_ += 1;
-    location_.column += 1;
-  } else if (matches(pos_, "_")) {
-    type = Token::Type::kUnderscore;
-    pos_ += 1;
-    location_.column += 1;
-  } else if (matches(pos_, "^=")) {
-    type = Token::Type::kXorEqual;
-    pos_ += 2;
-    location_.column += 2;
-  } else if (matches(pos_, "^")) {
-    type = Token::Type::kXor;
-    pos_ += 1;
-    location_.column += 1;
-  }
+    if (matches(pos(), "@")) {
+        type = Token::Type::kAttr;
+        advance(1);
+    } else if (matches(pos(), "(")) {
+        type = Token::Type::kParenLeft;
+        advance(1);
+    } else if (matches(pos(), ")")) {
+        type = Token::Type::kParenRight;
+        advance(1);
+    } else if (matches(pos(), "[")) {
+        type = Token::Type::kBracketLeft;
+        advance(1);
+    } else if (matches(pos(), "]")) {
+        type = Token::Type::kBracketRight;
+        advance(1);
+    } else if (matches(pos(), "{")) {
+        type = Token::Type::kBraceLeft;
+        advance(1);
+    } else if (matches(pos(), "}")) {
+        type = Token::Type::kBraceRight;
+        advance(1);
+    } else if (matches(pos(), "&&")) {
+        type = Token::Type::kAndAnd;
+        advance(2);
+    } else if (matches(pos(), "&=")) {
+        type = Token::Type::kAndEqual;
+        advance(2);
+    } else if (matches(pos(), "&")) {
+        type = Token::Type::kAnd;
+        advance(1);
+    } else if (matches(pos(), "/=")) {
+        type = Token::Type::kDivisionEqual;
+        advance(2);
+    } else if (matches(pos(), "/")) {
+        type = Token::Type::kForwardSlash;
+        advance(1);
+    } else if (matches(pos(), "!=")) {
+        type = Token::Type::kNotEqual;
+        advance(2);
+    } else if (matches(pos(), "!")) {
+        type = Token::Type::kBang;
+        advance(1);
+    } else if (matches(pos(), ":")) {
+        type = Token::Type::kColon;
+        advance(1);
+    } else if (matches(pos(), ",")) {
+        type = Token::Type::kComma;
+        advance(1);
+    } else if (matches(pos(), "==")) {
+        type = Token::Type::kEqualEqual;
+        advance(2);
+    } else if (matches(pos(), "=")) {
+        type = Token::Type::kEqual;
+        advance(1);
+    } else if (matches(pos(), ">=")) {
+        type = Token::Type::kGreaterThanEqual;
+        advance(2);
+    } else if (matches(pos(), ">>")) {
+        type = Token::Type::kShiftRight;
+        advance(2);
+    } else if (matches(pos(), ">")) {
+        type = Token::Type::kGreaterThan;
+        advance(1);
+    } else if (matches(pos(), "<=")) {
+        type = Token::Type::kLessThanEqual;
+        advance(2);
+    } else if (matches(pos(), "<<")) {
+        type = Token::Type::kShiftLeft;
+        advance(2);
+    } else if (matches(pos(), "<")) {
+        type = Token::Type::kLessThan;
+        advance(1);
+    } else if (matches(pos(), "%=")) {
+        type = Token::Type::kModuloEqual;
+        advance(2);
+    } else if (matches(pos(), "%")) {
+        type = Token::Type::kMod;
+        advance(1);
+    } else if (matches(pos(), "->")) {
+        type = Token::Type::kArrow;
+        advance(2);
+    } else if (matches(pos(), "--")) {
+        type = Token::Type::kMinusMinus;
+        advance(2);
+    } else if (matches(pos(), "-=")) {
+        type = Token::Type::kMinusEqual;
+        advance(2);
+    } else if (matches(pos(), "-")) {
+        type = Token::Type::kMinus;
+        advance(1);
+    } else if (matches(pos(), ".")) {
+        type = Token::Type::kPeriod;
+        advance(1);
+    } else if (matches(pos(), "++")) {
+        type = Token::Type::kPlusPlus;
+        advance(2);
+    } else if (matches(pos(), "+=")) {
+        type = Token::Type::kPlusEqual;
+        advance(2);
+    } else if (matches(pos(), "+")) {
+        type = Token::Type::kPlus;
+        advance(1);
+    } else if (matches(pos(), "||")) {
+        type = Token::Type::kOrOr;
+        advance(2);
+    } else if (matches(pos(), "|=")) {
+        type = Token::Type::kOrEqual;
+        advance(2);
+    } else if (matches(pos(), "|")) {
+        type = Token::Type::kOr;
+        advance(1);
+    } else if (matches(pos(), ";")) {
+        type = Token::Type::kSemicolon;
+        advance(1);
+    } else if (matches(pos(), "*=")) {
+        type = Token::Type::kTimesEqual;
+        advance(2);
+    } else if (matches(pos(), "*")) {
+        type = Token::Type::kStar;
+        advance(1);
+    } else if (matches(pos(), "~")) {
+        type = Token::Type::kTilde;
+        advance(1);
+    } else if (matches(pos(), "_")) {
+        type = Token::Type::kUnderscore;
+        advance(1);
+    } else if (matches(pos(), "^=")) {
+        type = Token::Type::kXorEqual;
+        advance(2);
+    } else if (matches(pos(), "^")) {
+        type = Token::Type::kXor;
+        advance(1);
+    }
 
-  end_source(source);
+    end_source(source);
 
-  return {type, source};
+    return {type, source};
 }
 
 Token Lexer::check_keyword(const Source& source, std::string_view str) {
-  if (str == "array")
-    return {Token::Type::kArray, source, "array"};
-  if (str == "atomic")
-    return {Token::Type::kAtomic, source, "atomic"};
-  if (str == "bitcast")
-    return {Token::Type::kBitcast, source, "bitcast"};
-  if (str == "bool")
-    return {Token::Type::kBool, source, "bool"};
-  if (str == "break")
-    return {Token::Type::kBreak, source, "break"};
-  if (str == "case")
-    return {Token::Type::kCase, source, "case"};
-  if (str == "continue")
-    return {Token::Type::kContinue, source, "continue"};
-  if (str == "continuing")
-    return {Token::Type::kContinuing, source, "continuing"};
-  if (str == "discard")
-    return {Token::Type::kDiscard, source, "discard"};
-  if (str == "default")
-    return {Token::Type::kDefault, source, "default"};
-  if (str == "else")
-    return {Token::Type::kElse, source, "else"};
-  if (str == "f32")
-    return {Token::Type::kF32, source, "f32"};
-  if (str == "fallthrough")
-    return {Token::Type::kFallthrough, source, "fallthrough"};
-  if (str == "false")
-    return {Token::Type::kFalse, source, "false"};
-  if (str == "fn")
-    return {Token::Type::kFn, source, "fn"};
-  if (str == "for")
-    return {Token::Type::kFor, source, "for"};
-  if (str == "function")
-    return {Token::Type::kFunction, source, "function"};
-  if (str == "i32")
-    return {Token::Type::kI32, source, "i32"};
-  if (str == "if")
-    return {Token::Type::kIf, source, "if"};
-  if (str == "import")
-    return {Token::Type::kImport, source, "import"};
-  if (str == "let")
-    return {Token::Type::kLet, source, "let"};
-  if (str == "loop")
-    return {Token::Type::kLoop, source, "loop"};
-  if (str == "mat2x2")
-    return {Token::Type::kMat2x2, source, "mat2x2"};
-  if (str == "mat2x3")
-    return {Token::Type::kMat2x3, source, "mat2x3"};
-  if (str == "mat2x4")
-    return {Token::Type::kMat2x4, source, "mat2x4"};
-  if (str == "mat3x2")
-    return {Token::Type::kMat3x2, source, "mat3x2"};
-  if (str == "mat3x3")
-    return {Token::Type::kMat3x3, source, "mat3x3"};
-  if (str == "mat3x4")
-    return {Token::Type::kMat3x4, source, "mat3x4"};
-  if (str == "mat4x2")
-    return {Token::Type::kMat4x2, source, "mat4x2"};
-  if (str == "mat4x3")
-    return {Token::Type::kMat4x3, source, "mat4x3"};
-  if (str == "mat4x4")
-    return {Token::Type::kMat4x4, source, "mat4x4"};
-  if (str == "override")
-    return {Token::Type::kOverride, source, "override"};
-  if (str == "private")
-    return {Token::Type::kPrivate, source, "private"};
-  if (str == "ptr")
-    return {Token::Type::kPtr, source, "ptr"};
-  if (str == "return")
-    return {Token::Type::kReturn, source, "return"};
-  if (str == "sampler")
-    return {Token::Type::kSampler, source, "sampler"};
-  if (str == "sampler_comparison")
-    return {Token::Type::kComparisonSampler, source, "sampler_comparison"};
-  if (str == "storage_buffer" || str == "storage")
-    return {Token::Type::kStorage, source, "storage"};
-  if (str == "struct")
-    return {Token::Type::kStruct, source, "struct"};
-  if (str == "switch")
-    return {Token::Type::kSwitch, source, "switch"};
-  if (str == "texture_1d")
-    return {Token::Type::kTextureSampled1d, source, "texture_1d"};
-  if (str == "texture_2d")
-    return {Token::Type::kTextureSampled2d, source, "texture_2d"};
-  if (str == "texture_2d_array")
-    return {Token::Type::kTextureSampled2dArray, source, "texture_2d_array"};
-  if (str == "texture_3d")
-    return {Token::Type::kTextureSampled3d, source, "texture_3d"};
-  if (str == "texture_cube")
-    return {Token::Type::kTextureSampledCube, source, "texture_cube"};
-  if (str == "texture_cube_array") {
-    return {Token::Type::kTextureSampledCubeArray, source,
-            "texture_cube_array"};
-  }
-  if (str == "texture_depth_2d")
-    return {Token::Type::kTextureDepth2d, source, "texture_depth_2d"};
-  if (str == "texture_depth_2d_array") {
-    return {Token::Type::kTextureDepth2dArray, source,
-            "texture_depth_2d_array"};
-  }
-  if (str == "texture_depth_cube")
-    return {Token::Type::kTextureDepthCube, source, "texture_depth_cube"};
-  if (str == "texture_depth_cube_array") {
-    return {Token::Type::kTextureDepthCubeArray, source,
-            "texture_depth_cube_array"};
-  }
-  if (str == "texture_depth_multisampled_2d") {
-    return {Token::Type::kTextureDepthMultisampled2d, source,
-            "texture_depth_multisampled_2d"};
-  }
-  if (str == "texture_external") {
-    return {Token::Type::kTextureExternal, source, "texture_external"};
-  }
-  if (str == "texture_multisampled_2d") {
-    return {Token::Type::kTextureMultisampled2d, source,
-            "texture_multisampled_2d"};
-  }
-  if (str == "texture_storage_1d") {
-    return {Token::Type::kTextureStorage1d, source, "texture_storage_1d"};
-  }
-  if (str == "texture_storage_2d") {
-    return {Token::Type::kTextureStorage2d, source, "texture_storage_2d"};
-  }
-  if (str == "texture_storage_2d_array") {
-    return {Token::Type::kTextureStorage2dArray, source,
-            "texture_storage_2d_array"};
-  }
-  if (str == "texture_storage_3d") {
-    return {Token::Type::kTextureStorage3d, source, "texture_storage_3d"};
-  }
-  if (str == "true")
-    return {Token::Type::kTrue, source, "true"};
-  if (str == "type")
-    return {Token::Type::kType, source, "type"};
-  if (str == "u32")
-    return {Token::Type::kU32, source, "u32"};
-  if (str == "uniform")
-    return {Token::Type::kUniform, source, "uniform"};
-  if (str == "var")
-    return {Token::Type::kVar, source, "var"};
-  if (str == "vec2")
-    return {Token::Type::kVec2, source, "vec2"};
-  if (str == "vec3")
-    return {Token::Type::kVec3, source, "vec3"};
-  if (str == "vec4")
-    return {Token::Type::kVec4, source, "vec4"};
-  if (str == "workgroup")
-    return {Token::Type::kWorkgroup, source, "workgroup"};
-  return {};
+    if (str == "array")
+        return {Token::Type::kArray, source, "array"};
+    if (str == "atomic")
+        return {Token::Type::kAtomic, source, "atomic"};
+    if (str == "bitcast")
+        return {Token::Type::kBitcast, source, "bitcast"};
+    if (str == "bool")
+        return {Token::Type::kBool, source, "bool"};
+    if (str == "break")
+        return {Token::Type::kBreak, source, "break"};
+    if (str == "case")
+        return {Token::Type::kCase, source, "case"};
+    if (str == "continue")
+        return {Token::Type::kContinue, source, "continue"};
+    if (str == "continuing")
+        return {Token::Type::kContinuing, source, "continuing"};
+    if (str == "discard")
+        return {Token::Type::kDiscard, source, "discard"};
+    if (str == "default")
+        return {Token::Type::kDefault, source, "default"};
+    if (str == "else")
+        return {Token::Type::kElse, source, "else"};
+    if (str == "enable")
+        return {Token::Type::kEnable, source, "enable"};
+    if (str == "f32")
+        return {Token::Type::kF32, source, "f32"};
+    if (str == "fallthrough")
+        return {Token::Type::kFallthrough, source, "fallthrough"};
+    if (str == "false")
+        return {Token::Type::kFalse, source, "false"};
+    if (str == "fn")
+        return {Token::Type::kFn, source, "fn"};
+    if (str == "for")
+        return {Token::Type::kFor, source, "for"};
+    if (str == "function")
+        return {Token::Type::kFunction, source, "function"};
+    if (str == "i32")
+        return {Token::Type::kI32, source, "i32"};
+    if (str == "if")
+        return {Token::Type::kIf, source, "if"};
+    if (str == "import")
+        return {Token::Type::kImport, source, "import"};
+    if (str == "let")
+        return {Token::Type::kLet, source, "let"};
+    if (str == "loop")
+        return {Token::Type::kLoop, source, "loop"};
+    if (str == "mat2x2")
+        return {Token::Type::kMat2x2, source, "mat2x2"};
+    if (str == "mat2x3")
+        return {Token::Type::kMat2x3, source, "mat2x3"};
+    if (str == "mat2x4")
+        return {Token::Type::kMat2x4, source, "mat2x4"};
+    if (str == "mat3x2")
+        return {Token::Type::kMat3x2, source, "mat3x2"};
+    if (str == "mat3x3")
+        return {Token::Type::kMat3x3, source, "mat3x3"};
+    if (str == "mat3x4")
+        return {Token::Type::kMat3x4, source, "mat3x4"};
+    if (str == "mat4x2")
+        return {Token::Type::kMat4x2, source, "mat4x2"};
+    if (str == "mat4x3")
+        return {Token::Type::kMat4x3, source, "mat4x3"};
+    if (str == "mat4x4")
+        return {Token::Type::kMat4x4, source, "mat4x4"};
+    if (str == "override")
+        return {Token::Type::kOverride, source, "override"};
+    if (str == "private")
+        return {Token::Type::kPrivate, source, "private"};
+    if (str == "ptr")
+        return {Token::Type::kPtr, source, "ptr"};
+    if (str == "return")
+        return {Token::Type::kReturn, source, "return"};
+    if (str == "sampler")
+        return {Token::Type::kSampler, source, "sampler"};
+    if (str == "sampler_comparison")
+        return {Token::Type::kComparisonSampler, source, "sampler_comparison"};
+    if (str == "storage_buffer" || str == "storage")
+        return {Token::Type::kStorage, source, "storage"};
+    if (str == "struct")
+        return {Token::Type::kStruct, source, "struct"};
+    if (str == "switch")
+        return {Token::Type::kSwitch, source, "switch"};
+    if (str == "texture_1d")
+        return {Token::Type::kTextureSampled1d, source, "texture_1d"};
+    if (str == "texture_2d")
+        return {Token::Type::kTextureSampled2d, source, "texture_2d"};
+    if (str == "texture_2d_array")
+        return {Token::Type::kTextureSampled2dArray, source, "texture_2d_array"};
+    if (str == "texture_3d")
+        return {Token::Type::kTextureSampled3d, source, "texture_3d"};
+    if (str == "texture_cube")
+        return {Token::Type::kTextureSampledCube, source, "texture_cube"};
+    if (str == "texture_cube_array") {
+        return {Token::Type::kTextureSampledCubeArray, source, "texture_cube_array"};
+    }
+    if (str == "texture_depth_2d")
+        return {Token::Type::kTextureDepth2d, source, "texture_depth_2d"};
+    if (str == "texture_depth_2d_array") {
+        return {Token::Type::kTextureDepth2dArray, source, "texture_depth_2d_array"};
+    }
+    if (str == "texture_depth_cube")
+        return {Token::Type::kTextureDepthCube, source, "texture_depth_cube"};
+    if (str == "texture_depth_cube_array") {
+        return {Token::Type::kTextureDepthCubeArray, source, "texture_depth_cube_array"};
+    }
+    if (str == "texture_depth_multisampled_2d") {
+        return {Token::Type::kTextureDepthMultisampled2d, source, "texture_depth_multisampled_2d"};
+    }
+    if (str == "texture_external") {
+        return {Token::Type::kTextureExternal, source, "texture_external"};
+    }
+    if (str == "texture_multisampled_2d") {
+        return {Token::Type::kTextureMultisampled2d, source, "texture_multisampled_2d"};
+    }
+    if (str == "texture_storage_1d") {
+        return {Token::Type::kTextureStorage1d, source, "texture_storage_1d"};
+    }
+    if (str == "texture_storage_2d") {
+        return {Token::Type::kTextureStorage2d, source, "texture_storage_2d"};
+    }
+    if (str == "texture_storage_2d_array") {
+        return {Token::Type::kTextureStorage2dArray, source, "texture_storage_2d_array"};
+    }
+    if (str == "texture_storage_3d") {
+        return {Token::Type::kTextureStorage3d, source, "texture_storage_3d"};
+    }
+    if (str == "true")
+        return {Token::Type::kTrue, source, "true"};
+    if (str == "type")
+        return {Token::Type::kType, source, "type"};
+    if (str == "u32")
+        return {Token::Type::kU32, source, "u32"};
+    if (str == "uniform")
+        return {Token::Type::kUniform, source, "uniform"};
+    if (str == "var")
+        return {Token::Type::kVar, source, "var"};
+    if (str == "vec2")
+        return {Token::Type::kVec2, source, "vec2"};
+    if (str == "vec3")
+        return {Token::Type::kVec3, source, "vec3"};
+    if (str == "vec4")
+        return {Token::Type::kVec4, source, "vec4"};
+    if (str == "workgroup")
+        return {Token::Type::kWorkgroup, source, "workgroup"};
+    return {};
 }
 
 }  // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/lexer.h b/src/tint/reader/wgsl/lexer.h
index f378d57..11ac9cf 100644
--- a/src/tint/reader/wgsl/lexer.h
+++ b/src/tint/reader/wgsl/lexer.h
@@ -23,71 +23,83 @@
 
 /// Converts the input stream into a series of Tokens
 class Lexer {
- public:
-  /// Creates a new Lexer
-  /// @param file the source file
-  explicit Lexer(const Source::File* file);
-  ~Lexer();
+  public:
+    /// Creates a new Lexer
+    /// @param file the source file
+    explicit Lexer(const Source::File* file);
+    ~Lexer();
 
-  /// Returns the next token in the input stream.
-  /// @return Token
-  Token next();
+    /// Returns the next token in the input stream.
+    /// @return Token
+    Token next();
 
- private:
-  /// Advances past blankspace and comments, if present at the current position.
-  /// @returns error token, EOF, or uninitialized
-  Token skip_blankspace_and_comments();
-  /// Advances past a comment at the current position, if one exists.
-  /// Returns an error if there was an unterminated block comment,
-  /// or a null character was present.
-  /// @returns uninitialized token on success, or error
-  Token skip_comment();
+  private:
+    /// Advances past blankspace and comments, if present at the current position.
+    /// @returns error token, EOF, or uninitialized
+    Token skip_blankspace_and_comments();
+    /// Advances past a comment at the current position, if one exists.
+    /// Returns an error if there was an unterminated block comment,
+    /// or a null character was present.
+    /// @returns uninitialized token on success, or error
+    Token skip_comment();
 
-  Token build_token_from_int_if_possible(Source source,
-                                         size_t start,
-                                         size_t end,
-                                         int32_t base);
-  Token check_keyword(const Source&, std::string_view);
+    Token build_token_from_int_if_possible(Source source, size_t start, size_t end, int32_t base);
+    Token check_keyword(const Source&, std::string_view);
 
-  /// The try_* methods have the following in common:
-  /// - They assume there is at least one character to be consumed,
-  ///   i.e. the input has not yet reached end of file.
-  /// - They return an initialized token when they match and consume
-  ///   a token of the specified kind.
-  /// - Some can return an error token.
-  /// - Otherwise they return an uninitialized token when they did not
-  ///   match a token of the specfied kind.
-  Token try_float();
-  Token try_hex_float();
-  Token try_hex_integer();
-  Token try_ident();
-  Token try_integer();
-  Token try_punctuation();
+    /// The try_* methods have the following in common:
+    /// - They assume there is at least one character to be consumed,
+    ///   i.e. the input has not yet reached end of file.
+    /// - They return an initialized token when they match and consume
+    ///   a token of the specified kind.
+    /// - Some can return an error token.
+    /// - Otherwise they return an uninitialized token when they did not
+    ///   match a token of the specfied kind.
+    Token try_float();
+    Token try_hex_float();
+    Token try_hex_integer();
+    Token try_ident();
+    Token try_integer();
+    Token try_punctuation();
 
-  Source begin_source() const;
-  void end_source(Source&) const;
+    Source begin_source() const;
+    void end_source(Source&) const;
 
-  /// @returns true if the end of the input has been reached.
-  bool is_eof() const;
-  /// @returns true if there is another character on the input and
-  /// it is not null.
-  bool is_null() const;
-  /// @param ch a character
-  /// @returns true if 'ch' is a decimal digit
-  bool is_digit(char ch) const;
-  /// @param ch a character
-  /// @returns true if 'ch' is a hexadecimal digit
-  bool is_hex(char ch) const;
-  bool matches(size_t pos, std::string_view substr);
+    /// @returns view of current line
+    const std::string_view line() const;
+    /// @returns position in current line
+    size_t pos() const;
+    /// @returns length of current line
+    size_t length() const;
+    /// @returns reference to character at `pos` within current line
+    const char& at(size_t pos) const;
+    /// @returns substring view at `offset` within current line of length `count`
+    std::string_view substr(size_t offset, size_t count);
+    /// advances current position by `offset` within current line
+    void advance(size_t offset = 1);
+    /// sets current position to `pos` within current line
+    void set_pos(size_t pos);
+    /// advances current position to next line
+    void advance_line();
+    /// @returns true if the end of the input has been reached.
+    bool is_eof() const;
+    /// @returns true if the end of the current line has been reached.
+    bool is_eol() const;
+    /// @returns true if there is another character on the input and
+    /// it is not null.
+    bool is_null() const;
+    /// @param ch a character
+    /// @returns true if 'ch' is a decimal digit
+    bool is_digit(char ch) const;
+    /// @param ch a character
+    /// @returns true if 'ch' is a hexadecimal digit
+    bool is_hex(char ch) const;
+    /// @returns true if string at `pos` matches `substr`
+    bool matches(size_t pos, std::string_view substr);
 
-  /// The source file content
-  Source::File const* const file_;
-  /// The length of the input
-  uint32_t len_ = 0;
-  /// The current position in utf-8 code units (bytes) within the input
-  uint32_t pos_ = 0;
-  /// The current location within the input
-  Source::Location location_;
+    /// The source file content
+    Source::File const* const file_;
+    /// The current location within the input
+    Source::Location location_;
 };
 
 }  // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/lexer_test.cc b/src/tint/reader/wgsl/lexer_test.cc
index 6ea313e..6bcea15 100644
--- a/src/tint/reader/wgsl/lexer_test.cc
+++ b/src/tint/reader/wgsl/lexer_test.cc
@@ -23,228 +23,308 @@
 
 using LexerTest = testing::Test;
 
+// Blankspace constants. These are macros on purpose to be able to easily build
+// up string literals with them.
+//
+// Same line code points
+#define kSpace " "
+#define kHTab "\t"
+#define kL2R "\xE2\x80\x8E"
+#define kR2L "\xE2\x80\x8F"
+// Line break code points
+#define kCR "\r"
+#define kLF "\n"
+#define kVTab "\x0B"
+#define kFF "\x0C"
+#define kNL "\xC2\x85"
+#define kLS "\xE2\x80\xA8"
+#define kPS "\xE2\x80\xA9"
+
 TEST_F(LexerTest, Empty) {
-  Source::File file("", "");
-  Lexer l(&file);
-  auto t = l.next();
-  EXPECT_TRUE(t.IsEof());
+    Source::File file("", "");
+    Lexer l(&file);
+    auto t = l.next();
+    EXPECT_TRUE(t.IsEof());
 }
 
-TEST_F(LexerTest, Skips_Blankspace) {
-  Source::File file("", "\t\r\n\t    ident\t\n\t  \r ");
-  Lexer l(&file);
+TEST_F(LexerTest, Skips_Blankspace_Basic) {
+    Source::File file("", "\t\r\n\t    ident\t\n\t  \r ");
+    Lexer l(&file);
 
-  auto t = l.next();
-  EXPECT_TRUE(t.IsIdentifier());
-  EXPECT_EQ(t.source().range.begin.line, 2u);
-  EXPECT_EQ(t.source().range.begin.column, 6u);
-  EXPECT_EQ(t.source().range.end.line, 2u);
-  EXPECT_EQ(t.source().range.end.column, 11u);
-  EXPECT_EQ(t.to_str(), "ident");
+    auto t = l.next();
+    EXPECT_TRUE(t.IsIdentifier());
+    EXPECT_EQ(t.source().range.begin.line, 2u);
+    EXPECT_EQ(t.source().range.begin.column, 6u);
+    EXPECT_EQ(t.source().range.end.line, 2u);
+    EXPECT_EQ(t.source().range.end.column, 11u);
+    EXPECT_EQ(t.to_str(), "ident");
 
-  t = l.next();
-  EXPECT_TRUE(t.IsEof());
+    t = l.next();
+    EXPECT_TRUE(t.IsEof());
+}
+
+TEST_F(LexerTest, Skips_Blankspace_Exotic) {
+    Source::File file("",                              //
+                      kVTab kFF kNL kLS kPS kL2R kR2L  //
+                      "ident"                          //
+                      kVTab kFF kNL kLS kPS kL2R kR2L);
+    Lexer l(&file);
+
+    auto t = l.next();
+    EXPECT_TRUE(t.IsIdentifier());
+    EXPECT_EQ(t.source().range.begin.line, 6u);
+    EXPECT_EQ(t.source().range.begin.column, 7u);
+    EXPECT_EQ(t.source().range.end.line, 6u);
+    EXPECT_EQ(t.source().range.end.column, 12u);
+    EXPECT_EQ(t.to_str(), "ident");
+
+    t = l.next();
+    EXPECT_TRUE(t.IsEof());
 }
 
 TEST_F(LexerTest, Skips_Comments_Line) {
-  Source::File file("", R"(//starts with comment
+    Source::File file("", R"(//starts with comment
 ident1 //ends with comment
 // blank line
  ident2)");
-  Lexer l(&file);
+    Lexer l(&file);
 
-  auto t = l.next();
-  EXPECT_TRUE(t.IsIdentifier());
-  EXPECT_EQ(t.source().range.begin.line, 2u);
-  EXPECT_EQ(t.source().range.begin.column, 1u);
-  EXPECT_EQ(t.source().range.end.line, 2u);
-  EXPECT_EQ(t.source().range.end.column, 7u);
-  EXPECT_EQ(t.to_str(), "ident1");
+    auto t = l.next();
+    EXPECT_TRUE(t.IsIdentifier());
+    EXPECT_EQ(t.source().range.begin.line, 2u);
+    EXPECT_EQ(t.source().range.begin.column, 1u);
+    EXPECT_EQ(t.source().range.end.line, 2u);
+    EXPECT_EQ(t.source().range.end.column, 7u);
+    EXPECT_EQ(t.to_str(), "ident1");
 
-  t = l.next();
-  EXPECT_TRUE(t.IsIdentifier());
-  EXPECT_EQ(t.source().range.begin.line, 4u);
-  EXPECT_EQ(t.source().range.begin.column, 2u);
-  EXPECT_EQ(t.source().range.end.line, 4u);
-  EXPECT_EQ(t.source().range.end.column, 8u);
-  EXPECT_EQ(t.to_str(), "ident2");
-
-  t = l.next();
-  EXPECT_TRUE(t.IsEof());
-}
-
-using LineCommentTerminatorTest = testing::TestWithParam<char>;
-TEST_P(LineCommentTerminatorTest, Terminators) {
-  // Test that line comments are ended by blankspace characters other than space
-  // and horizontal tab.
-  char c = GetParam();
-  std::string src = "let// This is a comment";
-  src += c;
-  src += "ident";
-  Source::File file("", src);
-  Lexer l(&file);
-
-  auto t = l.next();
-  EXPECT_TRUE(t.Is(Token::Type::kLet));
-  EXPECT_EQ(t.source().range.begin.line, 1u);
-  EXPECT_EQ(t.source().range.begin.column, 1u);
-  EXPECT_EQ(t.source().range.end.line, 1u);
-  EXPECT_EQ(t.source().range.end.column, 4u);
-
-  if (c != ' ' && c != '\t') {
-    size_t line = c == '\n' ? 2u : 1u;
-    size_t col = c == '\n' ? 1u : 25u;
     t = l.next();
     EXPECT_TRUE(t.IsIdentifier());
-    EXPECT_EQ(t.source().range.begin.line, line);
-    EXPECT_EQ(t.source().range.begin.column, col);
-    EXPECT_EQ(t.source().range.end.line, line);
-    EXPECT_EQ(t.source().range.end.column, col + 5);
-    EXPECT_EQ(t.to_str(), "ident");
-  }
+    EXPECT_EQ(t.source().range.begin.line, 4u);
+    EXPECT_EQ(t.source().range.begin.column, 2u);
+    EXPECT_EQ(t.source().range.end.line, 4u);
+    EXPECT_EQ(t.source().range.end.column, 8u);
+    EXPECT_EQ(t.to_str(), "ident2");
 
-  t = l.next();
-  EXPECT_TRUE(t.IsEof());
+    t = l.next();
+    EXPECT_TRUE(t.IsEof());
+}
+
+TEST_F(LexerTest, Skips_Comments_Unicode) {
+    Source::File file("", R"(// starts with 🙂🙂🙂
+ident1 //ends with 🙂🙂🙂
+// blank line
+ ident2)");
+    Lexer l(&file);
+
+    auto t = l.next();
+    EXPECT_TRUE(t.IsIdentifier());
+    EXPECT_EQ(t.source().range.begin.line, 2u);
+    EXPECT_EQ(t.source().range.begin.column, 1u);
+    EXPECT_EQ(t.source().range.end.line, 2u);
+    EXPECT_EQ(t.source().range.end.column, 7u);
+    EXPECT_EQ(t.to_str(), "ident1");
+
+    t = l.next();
+    EXPECT_TRUE(t.IsIdentifier());
+    EXPECT_EQ(t.source().range.begin.line, 4u);
+    EXPECT_EQ(t.source().range.begin.column, 2u);
+    EXPECT_EQ(t.source().range.end.line, 4u);
+    EXPECT_EQ(t.source().range.end.column, 8u);
+    EXPECT_EQ(t.to_str(), "ident2");
+
+    t = l.next();
+    EXPECT_TRUE(t.IsEof());
+}
+
+using LineCommentTerminatorTest = testing::TestWithParam<const char*>;
+TEST_P(LineCommentTerminatorTest, Terminators) {
+    // Test that line comments are ended by blankspace characters other than
+    // space, horizontal tab, left-to-right mark, and right-to-left mark.
+    auto* c = GetParam();
+    std::string src = "let// This is a comment";
+    src += c;
+    src += "ident";
+    Source::File file("", src);
+    Lexer l(&file);
+
+    auto t = l.next();
+    EXPECT_TRUE(t.Is(Token::Type::kLet));
+    EXPECT_EQ(t.source().range.begin.line, 1u);
+    EXPECT_EQ(t.source().range.begin.column, 1u);
+    EXPECT_EQ(t.source().range.end.line, 1u);
+    EXPECT_EQ(t.source().range.end.column, 4u);
+
+    auto is_same_line = [](std::string_view v) {
+        return v == kSpace || v == kHTab || v == kL2R || v == kR2L;
+    };
+
+    if (!is_same_line(c)) {
+        size_t line = is_same_line(c) ? 1u : 2u;
+        size_t col = is_same_line(c) ? 25u : 1u;
+        t = l.next();
+        EXPECT_TRUE(t.IsIdentifier());
+        EXPECT_EQ(t.source().range.begin.line, line);
+        EXPECT_EQ(t.source().range.begin.column, col);
+        EXPECT_EQ(t.source().range.end.line, line);
+        EXPECT_EQ(t.source().range.end.column, col + 5);
+        EXPECT_EQ(t.to_str(), "ident");
+    }
+
+    t = l.next();
+    EXPECT_TRUE(t.IsEof());
 }
 INSTANTIATE_TEST_SUITE_P(LexerTest,
                          LineCommentTerminatorTest,
-                         testing::Values(' ', '\t', '\n', '\v', '\f', '\r'));
+                         testing::Values(
+                             // same line
+                             kSpace,
+                             kHTab,
+                             kCR,
+                             kL2R,
+                             kR2L,
+                             // line break
+                             kLF,
+                             kVTab,
+                             kFF,
+                             kNL,
+                             kLS,
+                             kPS));
 
 TEST_F(LexerTest, Skips_Comments_Block) {
-  Source::File file("", R"(/* comment
+    Source::File file("", R"(/* comment
 text */ident)");
-  Lexer l(&file);
+    Lexer l(&file);
 
-  auto t = l.next();
-  EXPECT_TRUE(t.IsIdentifier());
-  EXPECT_EQ(t.source().range.begin.line, 2u);
-  EXPECT_EQ(t.source().range.begin.column, 8u);
-  EXPECT_EQ(t.source().range.end.line, 2u);
-  EXPECT_EQ(t.source().range.end.column, 13u);
-  EXPECT_EQ(t.to_str(), "ident");
+    auto t = l.next();
+    EXPECT_TRUE(t.IsIdentifier());
+    EXPECT_EQ(t.source().range.begin.line, 2u);
+    EXPECT_EQ(t.source().range.begin.column, 8u);
+    EXPECT_EQ(t.source().range.end.line, 2u);
+    EXPECT_EQ(t.source().range.end.column, 13u);
+    EXPECT_EQ(t.to_str(), "ident");
 
-  t = l.next();
-  EXPECT_TRUE(t.IsEof());
+    t = l.next();
+    EXPECT_TRUE(t.IsEof());
 }
 
 TEST_F(LexerTest, Skips_Comments_Block_Nested) {
-  Source::File file("", R"(/* comment
+    Source::File file("", R"(/* comment
 text // nested line comments are ignored /* more text
 /////**/ */*/ident)");
-  Lexer l(&file);
+    Lexer l(&file);
 
-  auto t = l.next();
-  EXPECT_TRUE(t.IsIdentifier());
-  EXPECT_EQ(t.source().range.begin.line, 3u);
-  EXPECT_EQ(t.source().range.begin.column, 14u);
-  EXPECT_EQ(t.source().range.end.line, 3u);
-  EXPECT_EQ(t.source().range.end.column, 19u);
-  EXPECT_EQ(t.to_str(), "ident");
+    auto t = l.next();
+    EXPECT_TRUE(t.IsIdentifier());
+    EXPECT_EQ(t.source().range.begin.line, 3u);
+    EXPECT_EQ(t.source().range.begin.column, 14u);
+    EXPECT_EQ(t.source().range.end.line, 3u);
+    EXPECT_EQ(t.source().range.end.column, 19u);
+    EXPECT_EQ(t.to_str(), "ident");
 
-  t = l.next();
-  EXPECT_TRUE(t.IsEof());
+    t = l.next();
+    EXPECT_TRUE(t.IsEof());
 }
 
 TEST_F(LexerTest, Skips_Comments_Block_Unterminated) {
-  // I had to break up the /* because otherwise the clang readability check
-  // errored out saying it could not find the end of a multi-line comment.
-  Source::File file("", R"(
+    // I had to break up the /* because otherwise the clang readability check
+    // errored out saying it could not find the end of a multi-line comment.
+    Source::File file("", R"(
   /)"
-                        R"(*
+                          R"(*
 abcd)");
-  Lexer l(&file);
+    Lexer l(&file);
 
-  auto t = l.next();
-  ASSERT_TRUE(t.Is(Token::Type::kError));
-  EXPECT_EQ(t.to_str(), "unterminated block comment");
-  EXPECT_EQ(t.source().range.begin.line, 2u);
-  EXPECT_EQ(t.source().range.begin.column, 3u);
-  EXPECT_EQ(t.source().range.end.line, 2u);
-  EXPECT_EQ(t.source().range.end.column, 4u);
+    auto t = l.next();
+    ASSERT_TRUE(t.Is(Token::Type::kError));
+    EXPECT_EQ(t.to_str(), "unterminated block comment");
+    EXPECT_EQ(t.source().range.begin.line, 2u);
+    EXPECT_EQ(t.source().range.begin.column, 3u);
+    EXPECT_EQ(t.source().range.end.line, 2u);
+    EXPECT_EQ(t.source().range.end.column, 4u);
 }
 
 TEST_F(LexerTest, Null_InBlankspace_IsError) {
-  Source::File file("", std::string{' ', 0, ' '});
-  Lexer l(&file);
+    Source::File file("", std::string{' ', 0, ' '});
+    Lexer l(&file);
 
-  auto t = l.next();
-  EXPECT_TRUE(t.IsError());
-  EXPECT_EQ(t.source().range.begin.line, 1u);
-  EXPECT_EQ(t.source().range.begin.column, 2u);
-  EXPECT_EQ(t.source().range.end.line, 1u);
-  EXPECT_EQ(t.source().range.end.column, 2u);
-  EXPECT_EQ(t.to_str(), "null character found");
+    auto t = l.next();
+    EXPECT_TRUE(t.IsError());
+    EXPECT_EQ(t.source().range.begin.line, 1u);
+    EXPECT_EQ(t.source().range.begin.column, 2u);
+    EXPECT_EQ(t.source().range.end.line, 1u);
+    EXPECT_EQ(t.source().range.end.column, 2u);
+    EXPECT_EQ(t.to_str(), "null character found");
 }
 
 TEST_F(LexerTest, Null_InLineComment_IsError) {
-  Source::File file("", std::string{'/', '/', ' ', 0, ' '});
-  Lexer l(&file);
+    Source::File file("", std::string{'/', '/', ' ', 0, ' '});
+    Lexer l(&file);
 
-  auto t = l.next();
-  EXPECT_TRUE(t.IsError());
-  EXPECT_EQ(t.source().range.begin.line, 1u);
-  EXPECT_EQ(t.source().range.begin.column, 4u);
-  EXPECT_EQ(t.source().range.end.line, 1u);
-  EXPECT_EQ(t.source().range.end.column, 4u);
-  EXPECT_EQ(t.to_str(), "null character found");
+    auto t = l.next();
+    EXPECT_TRUE(t.IsError());
+    EXPECT_EQ(t.source().range.begin.line, 1u);
+    EXPECT_EQ(t.source().range.begin.column, 4u);
+    EXPECT_EQ(t.source().range.end.line, 1u);
+    EXPECT_EQ(t.source().range.end.column, 4u);
+    EXPECT_EQ(t.to_str(), "null character found");
 }
 
 TEST_F(LexerTest, Null_InBlockComment_IsError) {
-  Source::File file("", std::string{'/', '*', ' ', 0, '*', '/'});
-  Lexer l(&file);
+    Source::File file("", std::string{'/', '*', ' ', 0, '*', '/'});
+    Lexer l(&file);
 
-  auto t = l.next();
-  EXPECT_TRUE(t.IsError());
-  EXPECT_EQ(t.source().range.begin.line, 1u);
-  EXPECT_EQ(t.source().range.begin.column, 4u);
-  EXPECT_EQ(t.source().range.end.line, 1u);
-  EXPECT_EQ(t.source().range.end.column, 4u);
-  EXPECT_EQ(t.to_str(), "null character found");
+    auto t = l.next();
+    EXPECT_TRUE(t.IsError());
+    EXPECT_EQ(t.source().range.begin.line, 1u);
+    EXPECT_EQ(t.source().range.begin.column, 4u);
+    EXPECT_EQ(t.source().range.end.line, 1u);
+    EXPECT_EQ(t.source().range.end.column, 4u);
+    EXPECT_EQ(t.to_str(), "null character found");
 }
 
 TEST_F(LexerTest, Null_InIdentifier_IsError) {
-  // Try inserting a null in an identifier. Other valid token
-  // kinds will behave similarly, so use the identifier case
-  // as a representative.
-  Source::File file("", std::string{'a', 0, 'c'});
-  Lexer l(&file);
+    // Try inserting a null in an identifier. Other valid token
+    // kinds will behave similarly, so use the identifier case
+    // as a representative.
+    Source::File file("", std::string{'a', 0, 'c'});
+    Lexer l(&file);
 
-  auto t = l.next();
-  EXPECT_TRUE(t.IsIdentifier());
-  EXPECT_EQ(t.to_str(), "a");
-  t = l.next();
-  EXPECT_TRUE(t.IsError());
-  EXPECT_EQ(t.source().range.begin.line, 1u);
-  EXPECT_EQ(t.source().range.begin.column, 2u);
-  EXPECT_EQ(t.source().range.end.line, 1u);
-  EXPECT_EQ(t.source().range.end.column, 2u);
-  EXPECT_EQ(t.to_str(), "null character found");
+    auto t = l.next();
+    EXPECT_TRUE(t.IsIdentifier());
+    EXPECT_EQ(t.to_str(), "a");
+    t = l.next();
+    EXPECT_TRUE(t.IsError());
+    EXPECT_EQ(t.source().range.begin.line, 1u);
+    EXPECT_EQ(t.source().range.begin.column, 2u);
+    EXPECT_EQ(t.source().range.end.line, 1u);
+    EXPECT_EQ(t.source().range.end.column, 2u);
+    EXPECT_EQ(t.to_str(), "null character found");
 }
 
 struct FloatData {
-  const char* input;
-  float result;
+    const char* input;
+    float result;
 };
 inline std::ostream& operator<<(std::ostream& out, FloatData data) {
-  out << std::string(data.input);
-  return out;
+    out << std::string(data.input);
+    return out;
 }
 using FloatTest = testing::TestWithParam<FloatData>;
 TEST_P(FloatTest, Parse) {
-  auto params = GetParam();
-  Source::File file("", params.input);
-  Lexer l(&file);
+    auto params = GetParam();
+    Source::File file("", params.input);
+    Lexer l(&file);
 
-  auto t = l.next();
-  EXPECT_TRUE(t.Is(Token::Type::kFloatLiteral));
-  EXPECT_EQ(t.to_f32(), params.result);
-  EXPECT_EQ(t.source().range.begin.line, 1u);
-  EXPECT_EQ(t.source().range.begin.column, 1u);
-  EXPECT_EQ(t.source().range.end.line, 1u);
-  EXPECT_EQ(t.source().range.end.column, 1u + strlen(params.input));
+    auto t = l.next();
+    EXPECT_TRUE(t.Is(Token::Type::kFloatLiteral));
+    EXPECT_EQ(t.to_f32(), params.result);
+    EXPECT_EQ(t.source().range.begin.line, 1u);
+    EXPECT_EQ(t.source().range.begin.column, 1u);
+    EXPECT_EQ(t.source().range.end.line, 1u);
+    EXPECT_EQ(t.source().range.end.column, 1u + strlen(params.input));
 
-  t = l.next();
-  EXPECT_TRUE(t.IsEof());
+    t = l.next();
+    EXPECT_TRUE(t.IsEof());
 }
 INSTANTIATE_TEST_SUITE_P(LexerTest,
                          FloatTest,
@@ -310,58 +390,57 @@
 
 using FloatTest_Invalid = testing::TestWithParam<const char*>;
 TEST_P(FloatTest_Invalid, Handles) {
-  Source::File file("", GetParam());
-  Lexer l(&file);
+    Source::File file("", GetParam());
+    Lexer l(&file);
 
-  auto t = l.next();
-  EXPECT_FALSE(t.Is(Token::Type::kFloatLiteral));
+    auto t = l.next();
+    EXPECT_FALSE(t.Is(Token::Type::kFloatLiteral));
 }
-INSTANTIATE_TEST_SUITE_P(
-    LexerTest,
-    FloatTest_Invalid,
-    testing::Values(".",
-                    "-.",
-                    // Need a mantissa digit
-                    ".e5",
-                    ".E5",
-                    // Need exponent digits
-                    ".e",
-                    ".e+",
-                    ".e-",
-                    ".E",
-                    ".e+",
-                    ".e-",
-                    // Overflow
-                    "2.5e+256",
-                    "-2.5e+127",
-                    // Magnitude smaller than smallest positive f32.
-                    "2.5e-300",
-                    "-2.5e-300",
-                    // Decimal exponent must immediately
-                    // follow the 'e'.
-                    "2.5e 12",
-                    "2.5e +12",
-                    "2.5e -12",
-                    "2.5e+ 123",
-                    "2.5e- 123",
-                    "2.5E 12",
-                    "2.5E +12",
-                    "2.5E -12",
-                    "2.5E+ 123",
-                    "2.5E- 123"));
+INSTANTIATE_TEST_SUITE_P(LexerTest,
+                         FloatTest_Invalid,
+                         testing::Values(".",
+                                         "-.",
+                                         // Need a mantissa digit
+                                         ".e5",
+                                         ".E5",
+                                         // Need exponent digits
+                                         ".e",
+                                         ".e+",
+                                         ".e-",
+                                         ".E",
+                                         ".e+",
+                                         ".e-",
+                                         // Overflow
+                                         "2.5e+256",
+                                         "-2.5e+127",
+                                         // Magnitude smaller than smallest positive f32.
+                                         "2.5e-300",
+                                         "-2.5e-300",
+                                         // Decimal exponent must immediately
+                                         // follow the 'e'.
+                                         "2.5e 12",
+                                         "2.5e +12",
+                                         "2.5e -12",
+                                         "2.5e+ 123",
+                                         "2.5e- 123",
+                                         "2.5E 12",
+                                         "2.5E +12",
+                                         "2.5E -12",
+                                         "2.5E+ 123",
+                                         "2.5E- 123"));
 
 using AsciiIdentifierTest = testing::TestWithParam<const char*>;
 TEST_P(AsciiIdentifierTest, Parse) {
-  Source::File file("", GetParam());
-  Lexer l(&file);
+    Source::File file("", GetParam());
+    Lexer l(&file);
 
-  auto t = l.next();
-  EXPECT_TRUE(t.IsIdentifier());
-  EXPECT_EQ(t.source().range.begin.line, 1u);
-  EXPECT_EQ(t.source().range.begin.column, 1u);
-  EXPECT_EQ(t.source().range.end.line, 1u);
-  EXPECT_EQ(t.source().range.end.column, 1u + strlen(GetParam()));
-  EXPECT_EQ(t.to_str(), GetParam());
+    auto t = l.next();
+    EXPECT_TRUE(t.IsIdentifier());
+    EXPECT_EQ(t.source().range.begin.line, 1u);
+    EXPECT_EQ(t.source().range.begin.column, 1u);
+    EXPECT_EQ(t.source().range.end.line, 1u);
+    EXPECT_EQ(t.source().range.end.column, 1u + strlen(GetParam()));
+    EXPECT_EQ(t.to_str(), GetParam());
 }
 INSTANTIATE_TEST_SUITE_P(LexerTest,
                          AsciiIdentifierTest,
@@ -378,22 +457,22 @@
                                          "alldigits_0123456789"));
 
 struct UnicodeCase {
-  const char* utf8;
-  size_t count;
+    const char* utf8;
+    size_t count;
 };
 
 using ValidUnicodeIdentifierTest = testing::TestWithParam<UnicodeCase>;
 TEST_P(ValidUnicodeIdentifierTest, Parse) {
-  Source::File file("", GetParam().utf8);
-  Lexer l(&file);
+    Source::File file("", GetParam().utf8);
+    Lexer l(&file);
 
-  auto t = l.next();
-  EXPECT_TRUE(t.IsIdentifier());
-  EXPECT_EQ(t.source().range.begin.line, 1u);
-  EXPECT_EQ(t.source().range.begin.column, 1u);
-  EXPECT_EQ(t.source().range.end.line, 1u);
-  EXPECT_EQ(t.source().range.end.column, 1u + GetParam().count);
-  EXPECT_EQ(t.to_str(), GetParam().utf8);
+    auto t = l.next();
+    EXPECT_TRUE(t.IsIdentifier());
+    EXPECT_EQ(t.source().range.begin.line, 1u);
+    EXPECT_EQ(t.source().range.begin.column, 1u);
+    EXPECT_EQ(t.source().range.end.line, 1u);
+    EXPECT_EQ(t.source().range.end.column, 1u + GetParam().count);
+    EXPECT_EQ(t.to_str(), GetParam().utf8);
 }
 INSTANTIATE_TEST_SUITE_P(
     LexerTest,
@@ -409,246 +488,250 @@
                     "\x91\x9b\xf0\x9d\x91\xa1\xf0\x9d\x91\x96\xf0\x9d\x91\x93"
                     "\xf0\x9d\x91\x96\xf0\x9d\x91\x92\xf0\x9d\x91\x9f",
                     40},
-        UnicodeCase{
-            // "identifier"
-            "\xef\xbd\x89\xef\xbd\x84\xef\xbd\x85\xef\xbd\x8e\xef\xbd\x94\xef"
-            "\xbd\x89\xef\xbd\x86\xef\xbd\x89\xef\xbd\x85\xef\xbd\x92",
-            30},
+        UnicodeCase{// "identifier"
+                    "\xef\xbd\x89\xef\xbd\x84\xef\xbd\x85\xef\xbd\x8e\xef\xbd\x94\xef"
+                    "\xbd\x89\xef\xbd\x86\xef\xbd\x89\xef\xbd\x85\xef\xbd\x92",
+                    30},
         UnicodeCase{// "𝕚𝕕𝕖𝕟𝕥𝕚𝕗𝕚𝕖𝕣𝟙𝟚𝟛"
                     "\xf0\x9d\x95\x9a\xf0\x9d\x95\x95\xf0\x9d\x95\x96\xf0\x9d"
                     "\x95\x9f\xf0\x9d\x95\xa5\xf0\x9d\x95\x9a\xf0\x9d\x95\x97"
                     "\xf0\x9d\x95\x9a\xf0\x9d\x95\x96\xf0\x9d\x95\xa3\xf0\x9d"
                     "\x9f\x99\xf0\x9d\x9f\x9a\xf0\x9d\x9f\x9b",
                     52},
-        UnicodeCase{
-            // "𝖎𝖉𝖊𝖓𝖙𝖎𝖋𝖎𝖊𝖗123"
-            "\xf0\x9d\x96\x8e\xf0\x9d\x96\x89\xf0\x9d\x96\x8a\xf0\x9d\x96\x93"
-            "\xf0\x9d\x96\x99\xf0\x9d\x96\x8e\xf0\x9d\x96\x8b\xf0\x9d\x96\x8e"
-            "\xf0\x9d\x96\x8a\xf0\x9d\x96\x97\x31\x32\x33",
-            43},
+        UnicodeCase{// "𝖎𝖉𝖊𝖓𝖙𝖎𝖋𝖎𝖊𝖗123"
+                    "\xf0\x9d\x96\x8e\xf0\x9d\x96\x89\xf0\x9d\x96\x8a\xf0\x9d\x96\x93"
+                    "\xf0\x9d\x96\x99\xf0\x9d\x96\x8e\xf0\x9d\x96\x8b\xf0\x9d\x96\x8e"
+                    "\xf0\x9d\x96\x8a\xf0\x9d\x96\x97\x31\x32\x33",
+                    43},
     }));
 
 using InvalidUnicodeIdentifierTest = testing::TestWithParam<const char*>;
 TEST_P(InvalidUnicodeIdentifierTest, Parse) {
-  Source::File file("", GetParam());
-  Lexer l(&file);
+    Source::File file("", GetParam());
+    Lexer l(&file);
 
-  auto t = l.next();
-  EXPECT_TRUE(t.IsError());
-  EXPECT_EQ(t.source().range.begin.line, 1u);
-  EXPECT_EQ(t.source().range.begin.column, 1u);
-  EXPECT_EQ(t.source().range.end.line, 1u);
-  EXPECT_EQ(t.source().range.end.column, 1u);
-  EXPECT_EQ(t.to_str(), "invalid UTF-8");
+    auto t = l.next();
+    EXPECT_TRUE(t.IsError());
+    EXPECT_EQ(t.source().range.begin.line, 1u);
+    EXPECT_EQ(t.source().range.begin.column, 1u);
+    EXPECT_EQ(t.source().range.end.line, 1u);
+    EXPECT_EQ(t.source().range.end.column, 1u);
+    EXPECT_EQ(t.to_str(), "invalid UTF-8");
 }
-INSTANTIATE_TEST_SUITE_P(
-    LexerTest,
-    InvalidUnicodeIdentifierTest,
-    testing::ValuesIn({
-        "\x80\x80\x80\x80",  // 10000000
-        "\x81\x80\x80\x80",  // 10000001
-        "\x8f\x80\x80\x80",  // 10001111
-        "\x90\x80\x80\x80",  // 10010000
-        "\x91\x80\x80\x80",  // 10010001
-        "\x9f\x80\x80\x80",  // 10011111
-        "\xa0\x80\x80\x80",  // 10100000
-        "\xa1\x80\x80\x80",  // 10100001
-        "\xaf\x80\x80\x80",  // 10101111
-        "\xb0\x80\x80\x80",  // 10110000
-        "\xb1\x80\x80\x80",  // 10110001
-        "\xbf\x80\x80\x80",  // 10111111
-        "\xc0\x80\x80\x80",  // 11000000
-        "\xc1\x80\x80\x80",  // 11000001
-        "\xf5\x80\x80\x80",  // 11110101
-        "\xf6\x80\x80\x80",  // 11110110
-        "\xf7\x80\x80\x80",  // 11110111
-        "\xf8\x80\x80\x80",  // 11111000
-        "\xfe\x80\x80\x80",  // 11111110
-        "\xff\x80\x80\x80",  // 11111111
+INSTANTIATE_TEST_SUITE_P(LexerTest,
+                         InvalidUnicodeIdentifierTest,
+                         testing::ValuesIn({
+                             "\x80\x80\x80\x80",  // 10000000
+                             "\x81\x80\x80\x80",  // 10000001
+                             "\x8f\x80\x80\x80",  // 10001111
+                             "\x90\x80\x80\x80",  // 10010000
+                             "\x91\x80\x80\x80",  // 10010001
+                             "\x9f\x80\x80\x80",  // 10011111
+                             "\xa0\x80\x80\x80",  // 10100000
+                             "\xa1\x80\x80\x80",  // 10100001
+                             "\xaf\x80\x80\x80",  // 10101111
+                             "\xb0\x80\x80\x80",  // 10110000
+                             "\xb1\x80\x80\x80",  // 10110001
+                             "\xbf\x80\x80\x80",  // 10111111
+                             "\xc0\x80\x80\x80",  // 11000000
+                             "\xc1\x80\x80\x80",  // 11000001
+                             "\xf5\x80\x80\x80",  // 11110101
+                             "\xf6\x80\x80\x80",  // 11110110
+                             "\xf7\x80\x80\x80",  // 11110111
+                             "\xf8\x80\x80\x80",  // 11111000
+                             "\xfe\x80\x80\x80",  // 11111110
+                             "\xff\x80\x80\x80",  // 11111111
 
-        "\xd0",          // 2-bytes, missing second byte
-        "\xe8\x8f",      // 3-bytes, missing third byte
-        "\xf4\x8f\x8f",  // 4-bytes, missing fourth byte
+                             "\xd0",          // 2-bytes, missing second byte
+                             "\xe8\x8f",      // 3-bytes, missing third byte
+                             "\xf4\x8f\x8f",  // 4-bytes, missing fourth byte
 
-        "\xd0\x7f",          // 2-bytes, second byte MSB unset
-        "\xe8\x7f\x8f",      // 3-bytes, second byte MSB unset
-        "\xe8\x8f\x7f",      // 3-bytes, third byte MSB unset
-        "\xf4\x7f\x8f\x8f",  // 4-bytes, second byte MSB unset
-        "\xf4\x8f\x7f\x8f",  // 4-bytes, third byte MSB unset
-        "\xf4\x8f\x8f\x7f",  // 4-bytes, fourth byte MSB unset
-    }));
+                             "\xd0\x7f",          // 2-bytes, second byte MSB unset
+                             "\xe8\x7f\x8f",      // 3-bytes, second byte MSB unset
+                             "\xe8\x8f\x7f",      // 3-bytes, third byte MSB unset
+                             "\xf4\x7f\x8f\x8f",  // 4-bytes, second byte MSB unset
+                             "\xf4\x8f\x7f\x8f",  // 4-bytes, third byte MSB unset
+                             "\xf4\x8f\x8f\x7f",  // 4-bytes, fourth byte MSB unset
+                         }));
 
 TEST_F(LexerTest, IdentifierTest_SingleUnderscoreDoesNotMatch) {
-  Source::File file("", "_");
-  Lexer l(&file);
+    Source::File file("", "_");
+    Lexer l(&file);
 
-  auto t = l.next();
-  EXPECT_FALSE(t.IsIdentifier());
+    auto t = l.next();
+    EXPECT_FALSE(t.IsIdentifier());
 }
 
 TEST_F(LexerTest, IdentifierTest_DoesNotStartWithDoubleUnderscore) {
-  Source::File file("", "__test");
-  Lexer l(&file);
+    Source::File file("", "__test");
+    Lexer l(&file);
 
-  auto t = l.next();
-  EXPECT_FALSE(t.IsIdentifier());
+    auto t = l.next();
+    EXPECT_FALSE(t.IsIdentifier());
 }
 
 TEST_F(LexerTest, IdentifierTest_DoesNotStartWithNumber) {
-  Source::File file("", "01test");
-  Lexer l(&file);
+    Source::File file("", "01test");
+    Lexer l(&file);
 
-  auto t = l.next();
-  EXPECT_FALSE(t.IsIdentifier());
+    auto t = l.next();
+    EXPECT_FALSE(t.IsIdentifier());
 }
 
 struct HexSignedIntData {
-  const char* input;
-  int32_t result;
+    const char* input;
+    int32_t result;
 };
 inline std::ostream& operator<<(std::ostream& out, HexSignedIntData data) {
-  out << std::string(data.input);
-  return out;
+    out << std::string(data.input);
+    return out;
 }
 
 using IntegerTest_HexSigned = testing::TestWithParam<HexSignedIntData>;
-TEST_P(IntegerTest_HexSigned, Matches) {
-  auto params = GetParam();
-  Source::File file("", params.input);
-  Lexer l(&file);
+TEST_P(IntegerTest_HexSigned, NoSuffix) {
+    auto params = GetParam();
+    Source::File file("", params.input);
+    Lexer l(&file);
 
-  auto t = l.next();
-  EXPECT_TRUE(t.Is(Token::Type::kSintLiteral));
-  EXPECT_EQ(t.source().range.begin.line, 1u);
-  EXPECT_EQ(t.source().range.begin.column, 1u);
-  EXPECT_EQ(t.source().range.end.line, 1u);
-  EXPECT_EQ(t.source().range.end.column, 1u + strlen(params.input));
-  EXPECT_EQ(t.to_i32(), params.result);
+    auto t = l.next();
+    EXPECT_TRUE(t.Is(Token::Type::kIntLiteral));
+    EXPECT_EQ(t.source().range.begin.line, 1u);
+    EXPECT_EQ(t.source().range.begin.column, 1u);
+    EXPECT_EQ(t.source().range.end.line, 1u);
+    EXPECT_EQ(t.source().range.end.column, 1u + strlen(params.input));
+    EXPECT_EQ(t.to_i64(), params.result);
+}
+TEST_P(IntegerTest_HexSigned, ISuffix) {
+    auto params = GetParam();
+    Source::File file("", std::string(params.input) + "i");
+    Lexer l(&file);
+
+    auto t = l.next();
+    EXPECT_TRUE(t.Is(Token::Type::kIntILiteral));
+    EXPECT_EQ(t.source().range.begin.line, 1u);
+    EXPECT_EQ(t.source().range.begin.column, 1u);
+    EXPECT_EQ(t.source().range.end.line, 1u);
+    EXPECT_EQ(t.source().range.end.column, 2u + strlen(params.input));
+    EXPECT_EQ(t.to_i64(), params.result);
 }
 INSTANTIATE_TEST_SUITE_P(
     LexerTest,
     IntegerTest_HexSigned,
-    testing::Values(
-        HexSignedIntData{"0x0", 0},
-        HexSignedIntData{"0X0", 0},
-        HexSignedIntData{"0x42", 66},
-        HexSignedIntData{"0X42", 66},
-        HexSignedIntData{"-0x42", -66},
-        HexSignedIntData{"-0X42", -66},
-        HexSignedIntData{"0xeF1Abc9", 250719177},
-        HexSignedIntData{"0XeF1Abc9", 250719177},
-        HexSignedIntData{"-0x80000000", std::numeric_limits<int32_t>::min()},
-        HexSignedIntData{"-0X80000000", std::numeric_limits<int32_t>::min()},
-        HexSignedIntData{"0x7FFFFFFF", std::numeric_limits<int32_t>::max()},
-        HexSignedIntData{"0X7FFFFFFF", std::numeric_limits<int32_t>::max()}));
+    testing::Values(HexSignedIntData{"0x0", 0},
+                    HexSignedIntData{"0X0", 0},
+                    HexSignedIntData{"0x42", 66},
+                    HexSignedIntData{"0X42", 66},
+                    HexSignedIntData{"-0x42", -66},
+                    HexSignedIntData{"-0X42", -66},
+                    HexSignedIntData{"0xeF1Abc9", 250719177},
+                    HexSignedIntData{"0XeF1Abc9", 250719177},
+                    HexSignedIntData{"-0x80000000", std::numeric_limits<int32_t>::min()},
+                    HexSignedIntData{"-0X80000000", std::numeric_limits<int32_t>::min()},
+                    HexSignedIntData{"0x7FFFFFFF", std::numeric_limits<int32_t>::max()},
+                    HexSignedIntData{"0X7FFFFFFF", std::numeric_limits<int32_t>::max()}));
 
 TEST_F(LexerTest, HexPrefixOnly_IsError) {
-  // Could be the start of a hex integer or hex float, but is neither.
-  Source::File file("", "0x");
-  Lexer l(&file);
+    // Could be the start of a hex integer or hex float, but is neither.
+    Source::File file("", "0x");
+    Lexer l(&file);
 
-  auto t = l.next();
-  ASSERT_TRUE(t.Is(Token::Type::kError));
-  EXPECT_EQ(t.to_str(),
-            "integer or float hex literal has no significant digits");
+    auto t = l.next();
+    ASSERT_TRUE(t.Is(Token::Type::kError));
+    EXPECT_EQ(t.to_str(), "integer or float hex literal has no significant digits");
 }
 
 TEST_F(LexerTest, HexPrefixUpperCaseOnly_IsError) {
-  // Could be the start of a hex integer or hex float, but is neither.
-  Source::File file("", "0X");
-  Lexer l(&file);
+    // Could be the start of a hex integer or hex float, but is neither.
+    Source::File file("", "0X");
+    Lexer l(&file);
 
-  auto t = l.next();
-  ASSERT_TRUE(t.Is(Token::Type::kError));
-  EXPECT_EQ(t.to_str(),
-            "integer or float hex literal has no significant digits");
+    auto t = l.next();
+    ASSERT_TRUE(t.Is(Token::Type::kError));
+    EXPECT_EQ(t.to_str(), "integer or float hex literal has no significant digits");
 }
 
 TEST_F(LexerTest, NegativeHexPrefixOnly_IsError) {
-  // Could be the start of a hex integer or hex float, but is neither.
-  Source::File file("", "-0x");
-  Lexer l(&file);
+    // Could be the start of a hex integer or hex float, but is neither.
+    Source::File file("", "-0x");
+    Lexer l(&file);
 
-  auto t = l.next();
-  ASSERT_TRUE(t.Is(Token::Type::kError));
-  EXPECT_EQ(t.to_str(),
-            "integer or float hex literal has no significant digits");
+    auto t = l.next();
+    ASSERT_TRUE(t.Is(Token::Type::kError));
+    EXPECT_EQ(t.to_str(), "integer or float hex literal has no significant digits");
 }
 
 TEST_F(LexerTest, NegativeHexPrefixUpperCaseOnly_IsError) {
-  // Could be the start of a hex integer or hex float, but is neither.
-  Source::File file("", "-0X");
-  Lexer l(&file);
+    // Could be the start of a hex integer or hex float, but is neither.
+    Source::File file("", "-0X");
+    Lexer l(&file);
 
-  auto t = l.next();
-  ASSERT_TRUE(t.Is(Token::Type::kError));
-  EXPECT_EQ(t.to_str(),
-            "integer or float hex literal has no significant digits");
+    auto t = l.next();
+    ASSERT_TRUE(t.Is(Token::Type::kError));
+    EXPECT_EQ(t.to_str(), "integer or float hex literal has no significant digits");
 }
 
 TEST_F(LexerTest, IntegerTest_HexSignedTooLarge) {
-  Source::File file("", "0x80000000");
-  Lexer l(&file);
+    Source::File file("", "0x80000000");
+    Lexer l(&file);
 
-  auto t = l.next();
-  ASSERT_TRUE(t.Is(Token::Type::kError));
-  EXPECT_EQ(t.to_str(), "i32 (0x80000000) too large");
+    auto t = l.next();
+    ASSERT_TRUE(t.Is(Token::Type::kError));
+    EXPECT_EQ(t.to_str(), "0x80000000 too large for i32");
 }
 
 TEST_F(LexerTest, IntegerTest_HexSignedTooSmall) {
-  Source::File file("", "-0x8000000F");
-  Lexer l(&file);
+    Source::File file("", "-0x8000000F");
+    Lexer l(&file);
 
-  auto t = l.next();
-  ASSERT_TRUE(t.Is(Token::Type::kError));
-  EXPECT_EQ(t.to_str(), "i32 (-0x8000000F) too small");
+    auto t = l.next();
+    ASSERT_TRUE(t.Is(Token::Type::kError));
+    EXPECT_EQ(t.to_str(), "-0x8000000F too small for i32");
 }
 
 TEST_F(LexerTest, IntegerTest_HexSignedTooManyDigits) {
-  {
-    Source::File file("", "-0x100000000000000000000000");
-    Lexer l(&file);
+    {
+        Source::File file("", "-0x100000000000000000000000");
+        Lexer l(&file);
 
-    auto t = l.next();
-    ASSERT_TRUE(t.Is(Token::Type::kError));
-    EXPECT_EQ(t.to_str(),
-              "integer literal (-0x10000000...) has too many digits");
-  }
-  {
-    Source::File file("", "0x100000000000000");
-    Lexer l(&file);
+        auto t = l.next();
+        ASSERT_TRUE(t.Is(Token::Type::kError));
+        EXPECT_EQ(t.to_str(), "integer literal (-0x10000000...) has too many digits");
+    }
+    {
+        Source::File file("", "0x100000000000000");
+        Lexer l(&file);
 
-    auto t = l.next();
-    ASSERT_TRUE(t.Is(Token::Type::kError));
-    EXPECT_EQ(t.to_str(),
-              "integer literal (0x10000000...) has too many digits");
-  }
+        auto t = l.next();
+        ASSERT_TRUE(t.Is(Token::Type::kError));
+        EXPECT_EQ(t.to_str(), "integer literal (0x10000000...) has too many digits");
+    }
 }
 
 struct HexUnsignedIntData {
-  const char* input;
-  uint32_t result;
+    const char* input;
+    uint32_t result;
 };
 inline std::ostream& operator<<(std::ostream& out, HexUnsignedIntData data) {
-  out << std::string(data.input);
-  return out;
+    out << std::string(data.input);
+    return out;
 }
 using IntegerTest_HexUnsigned = testing::TestWithParam<HexUnsignedIntData>;
+// TODO(crbug.com/tint/1504): Split into NoSuffix and USuffix
 TEST_P(IntegerTest_HexUnsigned, Matches) {
-  auto params = GetParam();
-  Source::File file("", params.input);
-  Lexer l(&file);
+    auto params = GetParam();
+    Source::File file("", params.input);
+    Lexer l(&file);
 
-  auto t = l.next();
-  EXPECT_TRUE(t.Is(Token::Type::kUintLiteral));
-  EXPECT_EQ(t.source().range.begin.line, 1u);
-  EXPECT_EQ(t.source().range.begin.column, 1u);
-  EXPECT_EQ(t.source().range.end.line, 1u);
-  EXPECT_EQ(t.source().range.end.column, 1u + strlen(params.input));
-  EXPECT_EQ(t.to_u32(), params.result);
+    auto t = l.next();
+    EXPECT_TRUE(t.Is(Token::Type::kIntULiteral));
+    EXPECT_EQ(t.source().range.begin.line, 1u);
+    EXPECT_EQ(t.source().range.begin.column, 1u);
+    EXPECT_EQ(t.source().range.end.line, 1u);
+    EXPECT_EQ(t.source().range.end.column, 1u + strlen(params.input));
+    EXPECT_EQ(t.to_i64(), params.result);
 
-  t = l.next();
-  EXPECT_TRUE(t.IsEof());
+    t = l.next();
+    EXPECT_TRUE(t.IsEof());
 }
 INSTANTIATE_TEST_SUITE_P(
     LexerTest,
@@ -656,280 +739,266 @@
     testing::Values(HexUnsignedIntData{"0x0u", 0},
                     HexUnsignedIntData{"0x42u", 66},
                     HexUnsignedIntData{"0xeF1Abc9u", 250719177},
-                    HexUnsignedIntData{"0x0u",
-                                       std::numeric_limits<uint32_t>::min()},
-                    HexUnsignedIntData{"0xFFFFFFFFu",
-                                       std::numeric_limits<uint32_t>::max()}));
+                    HexUnsignedIntData{"0x0u", std::numeric_limits<uint32_t>::min()},
+                    HexUnsignedIntData{"0xFFFFFFFFu", std::numeric_limits<uint32_t>::max()}));
 
 TEST_F(LexerTest, IntegerTest_HexUnsignedTooManyDigits) {
-  Source::File file("", "0x1000000000000000000000u");
-  Lexer l(&file);
+    Source::File file("", "0x1000000000000000000000u");
+    Lexer l(&file);
 
-  auto t = l.next();
-  ASSERT_TRUE(t.Is(Token::Type::kError));
-  EXPECT_EQ(t.to_str(), "integer literal (0x10000000...) has too many digits");
+    auto t = l.next();
+    ASSERT_TRUE(t.Is(Token::Type::kError));
+    EXPECT_EQ(t.to_str(), "integer literal (0x10000000...) has too many digits");
 }
 
 struct UnsignedIntData {
-  const char* input;
-  uint32_t result;
+    const char* input;
+    uint32_t result;
 };
 inline std::ostream& operator<<(std::ostream& out, UnsignedIntData data) {
-  out << std::string(data.input);
-  return out;
+    out << std::string(data.input);
+    return out;
 }
 using IntegerTest_Unsigned = testing::TestWithParam<UnsignedIntData>;
 TEST_P(IntegerTest_Unsigned, Matches) {
-  auto params = GetParam();
-  Source::File file("", params.input);
-  Lexer l(&file);
+    auto params = GetParam();
+    Source::File file("", params.input);
+    Lexer l(&file);
 
-  auto t = l.next();
-  EXPECT_TRUE(t.Is(Token::Type::kUintLiteral));
-  EXPECT_EQ(t.to_u32(), params.result);
-  EXPECT_EQ(t.source().range.begin.line, 1u);
-  EXPECT_EQ(t.source().range.begin.column, 1u);
-  EXPECT_EQ(t.source().range.end.line, 1u);
-  EXPECT_EQ(t.source().range.end.column, 1u + strlen(params.input));
+    auto t = l.next();
+    EXPECT_TRUE(t.Is(Token::Type::kIntULiteral));
+    EXPECT_EQ(t.to_i64(), params.result);
+    EXPECT_EQ(t.source().range.begin.line, 1u);
+    EXPECT_EQ(t.source().range.begin.column, 1u);
+    EXPECT_EQ(t.source().range.end.line, 1u);
+    EXPECT_EQ(t.source().range.end.column, 1u + strlen(params.input));
 }
 INSTANTIATE_TEST_SUITE_P(LexerTest,
                          IntegerTest_Unsigned,
                          testing::Values(UnsignedIntData{"0u", 0u},
                                          UnsignedIntData{"123u", 123u},
-                                         UnsignedIntData{"4294967295u",
-                                                         4294967295u}));
+                                         UnsignedIntData{"4294967295u", 4294967295u}));
 
 TEST_F(LexerTest, IntegerTest_UnsignedTooManyDigits) {
-  Source::File file("", "10000000000000000000000u");
-  Lexer l(&file);
+    Source::File file("", "10000000000000000000000u");
+    Lexer l(&file);
 
-  auto t = l.next();
-  ASSERT_TRUE(t.Is(Token::Type::kError));
-  EXPECT_EQ(t.to_str(), "integer literal (1000000000...) has too many digits");
+    auto t = l.next();
+    ASSERT_TRUE(t.Is(Token::Type::kError));
+    EXPECT_EQ(t.to_str(), "integer literal (1000000000...) has too many digits");
 }
 
 struct SignedIntData {
-  const char* input;
-  int32_t result;
+    const char* input;
+    int32_t result;
 };
 inline std::ostream& operator<<(std::ostream& out, SignedIntData data) {
-  out << std::string(data.input);
-  return out;
+    out << std::string(data.input);
+    return out;
 }
 using IntegerTest_Signed = testing::TestWithParam<SignedIntData>;
 TEST_P(IntegerTest_Signed, Matches) {
-  auto params = GetParam();
-  Source::File file("", params.input);
-  Lexer l(&file);
+    auto params = GetParam();
+    Source::File file("", params.input);
+    Lexer l(&file);
 
-  auto t = l.next();
-  EXPECT_TRUE(t.Is(Token::Type::kSintLiteral));
-  EXPECT_EQ(t.to_i32(), params.result);
-  EXPECT_EQ(t.source().range.begin.line, 1u);
-  EXPECT_EQ(t.source().range.begin.column, 1u);
-  EXPECT_EQ(t.source().range.end.line, 1u);
-  EXPECT_EQ(t.source().range.end.column, 1u + strlen(params.input));
+    auto t = l.next();
+    EXPECT_TRUE(t.Is(Token::Type::kIntLiteral));
+    EXPECT_EQ(t.to_i64(), params.result);
+    EXPECT_EQ(t.source().range.begin.line, 1u);
+    EXPECT_EQ(t.source().range.begin.column, 1u);
+    EXPECT_EQ(t.source().range.end.line, 1u);
+    EXPECT_EQ(t.source().range.end.column, 1u + strlen(params.input));
 }
-INSTANTIATE_TEST_SUITE_P(
-    LexerTest,
-    IntegerTest_Signed,
-    testing::Values(SignedIntData{"0", 0},
-                    SignedIntData{"-2", -2},
-                    SignedIntData{"2", 2},
-                    SignedIntData{"123", 123},
-                    SignedIntData{"2147483647", 2147483647},
-                    SignedIntData{"-2147483648", -2147483648LL}));
+INSTANTIATE_TEST_SUITE_P(LexerTest,
+                         IntegerTest_Signed,
+                         testing::Values(SignedIntData{"0", 0},
+                                         SignedIntData{"-2", -2},
+                                         SignedIntData{"2", 2},
+                                         SignedIntData{"123", 123},
+                                         SignedIntData{"2147483647", 2147483647},
+                                         SignedIntData{"-2147483648", -2147483648LL}));
 
 TEST_F(LexerTest, IntegerTest_SignedTooManyDigits) {
-  Source::File file("", "-10000000000000000");
-  Lexer l(&file);
+    Source::File file("", "-10000000000000000");
+    Lexer l(&file);
 
-  auto t = l.next();
-  ASSERT_TRUE(t.Is(Token::Type::kError));
-  EXPECT_EQ(t.to_str(), "integer literal (-1000000000...) has too many digits");
+    auto t = l.next();
+    ASSERT_TRUE(t.Is(Token::Type::kError));
+    EXPECT_EQ(t.to_str(), "integer literal (-1000000000...) has too many digits");
 }
 
 using IntegerTest_Invalid = testing::TestWithParam<const char*>;
 TEST_P(IntegerTest_Invalid, Parses) {
-  Source::File file("", GetParam());
-  Lexer l(&file);
+    Source::File file("", GetParam());
+    Lexer l(&file);
 
-  auto t = l.next();
-  EXPECT_FALSE(t.Is(Token::Type::kSintLiteral));
-  EXPECT_FALSE(t.Is(Token::Type::kUintLiteral));
-}
-INSTANTIATE_TEST_SUITE_P(LexerTest,
-                         IntegerTest_Invalid,
-                         testing::Values("2147483648",
-                                         "4294967296u",
-                                         "01234",
-                                         "0000",
-                                         "-00",
-                                         "00u"));
-
-struct TokenData {
-  const char* input;
-  Token::Type type;
-};
-inline std::ostream& operator<<(std::ostream& out, TokenData data) {
-  out << std::string(data.input);
-  return out;
-}
-using PunctuationTest = testing::TestWithParam<TokenData>;
-TEST_P(PunctuationTest, Parses) {
-  auto params = GetParam();
-  Source::File file("", params.input);
-  Lexer l(&file);
-
-  auto t = l.next();
-  EXPECT_TRUE(t.Is(params.type));
-  EXPECT_EQ(t.source().range.begin.line, 1u);
-  EXPECT_EQ(t.source().range.begin.column, 1u);
-  EXPECT_EQ(t.source().range.end.line, 1u);
-  EXPECT_EQ(t.source().range.end.column, 1u + strlen(params.input));
-
-  t = l.next();
-  EXPECT_EQ(t.source().range.begin.column,
-            1 + std::string(params.input).size());
+    auto t = l.next();
+    EXPECT_FALSE(t.Is(Token::Type::kIntLiteral));
+    EXPECT_FALSE(t.Is(Token::Type::kIntULiteral));
+    EXPECT_FALSE(t.Is(Token::Type::kIntILiteral));
 }
 INSTANTIATE_TEST_SUITE_P(
     LexerTest,
-    PunctuationTest,
-    testing::Values(TokenData{"&", Token::Type::kAnd},
-                    TokenData{"&&", Token::Type::kAndAnd},
-                    TokenData{"->", Token::Type::kArrow},
-                    TokenData{"@", Token::Type::kAttr},
-                    TokenData{"/", Token::Type::kForwardSlash},
-                    TokenData{"!", Token::Type::kBang},
-                    TokenData{"[", Token::Type::kBracketLeft},
-                    TokenData{"]", Token::Type::kBracketRight},
-                    TokenData{"{", Token::Type::kBraceLeft},
-                    TokenData{"}", Token::Type::kBraceRight},
-                    TokenData{":", Token::Type::kColon},
-                    TokenData{",", Token::Type::kComma},
-                    TokenData{"=", Token::Type::kEqual},
-                    TokenData{"==", Token::Type::kEqualEqual},
-                    TokenData{">", Token::Type::kGreaterThan},
-                    TokenData{">=", Token::Type::kGreaterThanEqual},
-                    TokenData{">>", Token::Type::kShiftRight},
-                    TokenData{"<", Token::Type::kLessThan},
-                    TokenData{"<=", Token::Type::kLessThanEqual},
-                    TokenData{"<<", Token::Type::kShiftLeft},
-                    TokenData{"%", Token::Type::kMod},
-                    TokenData{"!=", Token::Type::kNotEqual},
-                    TokenData{"-", Token::Type::kMinus},
-                    TokenData{"--", Token::Type::kMinusMinus},
-                    TokenData{".", Token::Type::kPeriod},
-                    TokenData{"+", Token::Type::kPlus},
-                    TokenData{"++", Token::Type::kPlusPlus},
-                    TokenData{"|", Token::Type::kOr},
-                    TokenData{"||", Token::Type::kOrOr},
-                    TokenData{"(", Token::Type::kParenLeft},
-                    TokenData{")", Token::Type::kParenRight},
-                    TokenData{";", Token::Type::kSemicolon},
-                    TokenData{"*", Token::Type::kStar},
-                    TokenData{"~", Token::Type::kTilde},
-                    TokenData{"_", Token::Type::kUnderscore},
-                    TokenData{"^", Token::Type::kXor},
-                    TokenData{"+=", Token::Type::kPlusEqual},
-                    TokenData{"-=", Token::Type::kMinusEqual},
-                    TokenData{"*=", Token::Type::kTimesEqual},
-                    TokenData{"/=", Token::Type::kDivisionEqual},
-                    TokenData{"%=", Token::Type::kModuloEqual},
-                    TokenData{"&=", Token::Type::kAndEqual},
-                    TokenData{"|=", Token::Type::kOrEqual},
-                    TokenData{"^=", Token::Type::kXorEqual}));
+    IntegerTest_Invalid,
+    testing::Values("2147483648", "4294967296u", "01234", "0000", "-00", "00u"));
+
+struct TokenData {
+    const char* input;
+    Token::Type type;
+};
+inline std::ostream& operator<<(std::ostream& out, TokenData data) {
+    out << std::string(data.input);
+    return out;
+}
+using PunctuationTest = testing::TestWithParam<TokenData>;
+TEST_P(PunctuationTest, Parses) {
+    auto params = GetParam();
+    Source::File file("", params.input);
+    Lexer l(&file);
+
+    auto t = l.next();
+    EXPECT_TRUE(t.Is(params.type));
+    EXPECT_EQ(t.source().range.begin.line, 1u);
+    EXPECT_EQ(t.source().range.begin.column, 1u);
+    EXPECT_EQ(t.source().range.end.line, 1u);
+    EXPECT_EQ(t.source().range.end.column, 1u + strlen(params.input));
+
+    t = l.next();
+    EXPECT_EQ(t.source().range.begin.column, 1 + std::string(params.input).size());
+}
+INSTANTIATE_TEST_SUITE_P(LexerTest,
+                         PunctuationTest,
+                         testing::Values(TokenData{"&", Token::Type::kAnd},
+                                         TokenData{"&&", Token::Type::kAndAnd},
+                                         TokenData{"->", Token::Type::kArrow},
+                                         TokenData{"@", Token::Type::kAttr},
+                                         TokenData{"/", Token::Type::kForwardSlash},
+                                         TokenData{"!", Token::Type::kBang},
+                                         TokenData{"[", Token::Type::kBracketLeft},
+                                         TokenData{"]", Token::Type::kBracketRight},
+                                         TokenData{"{", Token::Type::kBraceLeft},
+                                         TokenData{"}", Token::Type::kBraceRight},
+                                         TokenData{":", Token::Type::kColon},
+                                         TokenData{",", Token::Type::kComma},
+                                         TokenData{"=", Token::Type::kEqual},
+                                         TokenData{"==", Token::Type::kEqualEqual},
+                                         TokenData{">", Token::Type::kGreaterThan},
+                                         TokenData{">=", Token::Type::kGreaterThanEqual},
+                                         TokenData{">>", Token::Type::kShiftRight},
+                                         TokenData{"<", Token::Type::kLessThan},
+                                         TokenData{"<=", Token::Type::kLessThanEqual},
+                                         TokenData{"<<", Token::Type::kShiftLeft},
+                                         TokenData{"%", Token::Type::kMod},
+                                         TokenData{"!=", Token::Type::kNotEqual},
+                                         TokenData{"-", Token::Type::kMinus},
+                                         TokenData{"--", Token::Type::kMinusMinus},
+                                         TokenData{".", Token::Type::kPeriod},
+                                         TokenData{"+", Token::Type::kPlus},
+                                         TokenData{"++", Token::Type::kPlusPlus},
+                                         TokenData{"|", Token::Type::kOr},
+                                         TokenData{"||", Token::Type::kOrOr},
+                                         TokenData{"(", Token::Type::kParenLeft},
+                                         TokenData{")", Token::Type::kParenRight},
+                                         TokenData{";", Token::Type::kSemicolon},
+                                         TokenData{"*", Token::Type::kStar},
+                                         TokenData{"~", Token::Type::kTilde},
+                                         TokenData{"_", Token::Type::kUnderscore},
+                                         TokenData{"^", Token::Type::kXor},
+                                         TokenData{"+=", Token::Type::kPlusEqual},
+                                         TokenData{"-=", Token::Type::kMinusEqual},
+                                         TokenData{"*=", Token::Type::kTimesEqual},
+                                         TokenData{"/=", Token::Type::kDivisionEqual},
+                                         TokenData{"%=", Token::Type::kModuloEqual},
+                                         TokenData{"&=", Token::Type::kAndEqual},
+                                         TokenData{"|=", Token::Type::kOrEqual},
+                                         TokenData{"^=", Token::Type::kXorEqual}));
 
 using KeywordTest = testing::TestWithParam<TokenData>;
 TEST_P(KeywordTest, Parses) {
-  auto params = GetParam();
-  Source::File file("", params.input);
-  Lexer l(&file);
+    auto params = GetParam();
+    Source::File file("", params.input);
+    Lexer l(&file);
 
-  auto t = l.next();
-  EXPECT_TRUE(t.Is(params.type)) << params.input;
-  EXPECT_EQ(t.source().range.begin.line, 1u);
-  EXPECT_EQ(t.source().range.begin.column, 1u);
-  EXPECT_EQ(t.source().range.end.line, 1u);
-  EXPECT_EQ(t.source().range.end.column, 1u + strlen(params.input));
+    auto t = l.next();
+    EXPECT_TRUE(t.Is(params.type)) << params.input;
+    EXPECT_EQ(t.source().range.begin.line, 1u);
+    EXPECT_EQ(t.source().range.begin.column, 1u);
+    EXPECT_EQ(t.source().range.end.line, 1u);
+    EXPECT_EQ(t.source().range.end.column, 1u + strlen(params.input));
 
-  t = l.next();
-  EXPECT_EQ(t.source().range.begin.column,
-            1 + std::string(params.input).size());
+    t = l.next();
+    EXPECT_EQ(t.source().range.begin.column, 1 + std::string(params.input).size());
 }
 INSTANTIATE_TEST_SUITE_P(
     LexerTest,
     KeywordTest,
-    testing::Values(
-        TokenData{"array", Token::Type::kArray},
-        TokenData{"bitcast", Token::Type::kBitcast},
-        TokenData{"bool", Token::Type::kBool},
-        TokenData{"break", Token::Type::kBreak},
-        TokenData{"case", Token::Type::kCase},
-        TokenData{"continue", Token::Type::kContinue},
-        TokenData{"continuing", Token::Type::kContinuing},
-        TokenData{"default", Token::Type::kDefault},
-        TokenData{"discard", Token::Type::kDiscard},
-        TokenData{"else", Token::Type::kElse},
-        TokenData{"f32", Token::Type::kF32},
-        TokenData{"fallthrough", Token::Type::kFallthrough},
-        TokenData{"false", Token::Type::kFalse},
-        TokenData{"fn", Token::Type::kFn},
-        TokenData{"for", Token::Type::kFor},
-        TokenData{"function", Token::Type::kFunction},
-        TokenData{"i32", Token::Type::kI32},
-        TokenData{"if", Token::Type::kIf},
-        TokenData{"import", Token::Type::kImport},
-        TokenData{"let", Token::Type::kLet},
-        TokenData{"loop", Token::Type::kLoop},
-        TokenData{"mat2x2", Token::Type::kMat2x2},
-        TokenData{"mat2x3", Token::Type::kMat2x3},
-        TokenData{"mat2x4", Token::Type::kMat2x4},
-        TokenData{"mat3x2", Token::Type::kMat3x2},
-        TokenData{"mat3x3", Token::Type::kMat3x3},
-        TokenData{"mat3x4", Token::Type::kMat3x4},
-        TokenData{"mat4x2", Token::Type::kMat4x2},
-        TokenData{"mat4x3", Token::Type::kMat4x3},
-        TokenData{"mat4x4", Token::Type::kMat4x4},
-        TokenData{"override", Token::Type::kOverride},
-        TokenData{"private", Token::Type::kPrivate},
-        TokenData{"ptr", Token::Type::kPtr},
-        TokenData{"return", Token::Type::kReturn},
-        TokenData{"sampler", Token::Type::kSampler},
-        TokenData{"sampler_comparison", Token::Type::kComparisonSampler},
-        TokenData{"storage", Token::Type::kStorage},
-        TokenData{"storage_buffer", Token::Type::kStorage},
-        TokenData{"struct", Token::Type::kStruct},
-        TokenData{"switch", Token::Type::kSwitch},
-        TokenData{"texture_1d", Token::Type::kTextureSampled1d},
-        TokenData{"texture_2d", Token::Type::kTextureSampled2d},
-        TokenData{"texture_2d_array", Token::Type::kTextureSampled2dArray},
-        TokenData{"texture_3d", Token::Type::kTextureSampled3d},
-        TokenData{"texture_cube", Token::Type::kTextureSampledCube},
-        TokenData{"texture_cube_array", Token::Type::kTextureSampledCubeArray},
-        TokenData{"texture_depth_2d", Token::Type::kTextureDepth2d},
-        TokenData{"texture_depth_2d_array", Token::Type::kTextureDepth2dArray},
-        TokenData{"texture_depth_cube", Token::Type::kTextureDepthCube},
-        TokenData{"texture_depth_cube_array",
-                  Token::Type::kTextureDepthCubeArray},
-        TokenData{"texture_depth_multisampled_2d",
-                  Token::Type::kTextureDepthMultisampled2d},
-        TokenData{"texture_multisampled_2d",
-                  Token::Type::kTextureMultisampled2d},
-        TokenData{"texture_storage_1d", Token::Type::kTextureStorage1d},
-        TokenData{"texture_storage_2d", Token::Type::kTextureStorage2d},
-        TokenData{"texture_storage_2d_array",
-                  Token::Type::kTextureStorage2dArray},
-        TokenData{"texture_storage_3d", Token::Type::kTextureStorage3d},
-        TokenData{"true", Token::Type::kTrue},
-        TokenData{"type", Token::Type::kType},
-        TokenData{"u32", Token::Type::kU32},
-        TokenData{"uniform", Token::Type::kUniform},
-        TokenData{"var", Token::Type::kVar},
-        TokenData{"vec2", Token::Type::kVec2},
-        TokenData{"vec3", Token::Type::kVec3},
-        TokenData{"vec4", Token::Type::kVec4},
-        TokenData{"workgroup", Token::Type::kWorkgroup}));
+    testing::Values(TokenData{"array", Token::Type::kArray},
+                    TokenData{"bitcast", Token::Type::kBitcast},
+                    TokenData{"bool", Token::Type::kBool},
+                    TokenData{"break", Token::Type::kBreak},
+                    TokenData{"case", Token::Type::kCase},
+                    TokenData{"continue", Token::Type::kContinue},
+                    TokenData{"continuing", Token::Type::kContinuing},
+                    TokenData{"default", Token::Type::kDefault},
+                    TokenData{"discard", Token::Type::kDiscard},
+                    TokenData{"else", Token::Type::kElse},
+                    TokenData{"f32", Token::Type::kF32},
+                    TokenData{"fallthrough", Token::Type::kFallthrough},
+                    TokenData{"false", Token::Type::kFalse},
+                    TokenData{"fn", Token::Type::kFn},
+                    TokenData{"for", Token::Type::kFor},
+                    TokenData{"function", Token::Type::kFunction},
+                    TokenData{"i32", Token::Type::kI32},
+                    TokenData{"if", Token::Type::kIf},
+                    TokenData{"import", Token::Type::kImport},
+                    TokenData{"let", Token::Type::kLet},
+                    TokenData{"loop", Token::Type::kLoop},
+                    TokenData{"mat2x2", Token::Type::kMat2x2},
+                    TokenData{"mat2x3", Token::Type::kMat2x3},
+                    TokenData{"mat2x4", Token::Type::kMat2x4},
+                    TokenData{"mat3x2", Token::Type::kMat3x2},
+                    TokenData{"mat3x3", Token::Type::kMat3x3},
+                    TokenData{"mat3x4", Token::Type::kMat3x4},
+                    TokenData{"mat4x2", Token::Type::kMat4x2},
+                    TokenData{"mat4x3", Token::Type::kMat4x3},
+                    TokenData{"mat4x4", Token::Type::kMat4x4},
+                    TokenData{"override", Token::Type::kOverride},
+                    TokenData{"private", Token::Type::kPrivate},
+                    TokenData{"ptr", Token::Type::kPtr},
+                    TokenData{"return", Token::Type::kReturn},
+                    TokenData{"sampler", Token::Type::kSampler},
+                    TokenData{"sampler_comparison", Token::Type::kComparisonSampler},
+                    TokenData{"storage", Token::Type::kStorage},
+                    TokenData{"storage_buffer", Token::Type::kStorage},
+                    TokenData{"struct", Token::Type::kStruct},
+                    TokenData{"switch", Token::Type::kSwitch},
+                    TokenData{"texture_1d", Token::Type::kTextureSampled1d},
+                    TokenData{"texture_2d", Token::Type::kTextureSampled2d},
+                    TokenData{"texture_2d_array", Token::Type::kTextureSampled2dArray},
+                    TokenData{"texture_3d", Token::Type::kTextureSampled3d},
+                    TokenData{"texture_cube", Token::Type::kTextureSampledCube},
+                    TokenData{"texture_cube_array", Token::Type::kTextureSampledCubeArray},
+                    TokenData{"texture_depth_2d", Token::Type::kTextureDepth2d},
+                    TokenData{"texture_depth_2d_array", Token::Type::kTextureDepth2dArray},
+                    TokenData{"texture_depth_cube", Token::Type::kTextureDepthCube},
+                    TokenData{"texture_depth_cube_array", Token::Type::kTextureDepthCubeArray},
+                    TokenData{"texture_depth_multisampled_2d",
+                              Token::Type::kTextureDepthMultisampled2d},
+                    TokenData{"texture_multisampled_2d", Token::Type::kTextureMultisampled2d},
+                    TokenData{"texture_storage_1d", Token::Type::kTextureStorage1d},
+                    TokenData{"texture_storage_2d", Token::Type::kTextureStorage2d},
+                    TokenData{"texture_storage_2d_array", Token::Type::kTextureStorage2dArray},
+                    TokenData{"texture_storage_3d", Token::Type::kTextureStorage3d},
+                    TokenData{"true", Token::Type::kTrue},
+                    TokenData{"type", Token::Type::kType},
+                    TokenData{"u32", Token::Type::kU32},
+                    TokenData{"uniform", Token::Type::kUniform},
+                    TokenData{"var", Token::Type::kVar},
+                    TokenData{"vec2", Token::Type::kVec2},
+                    TokenData{"vec3", Token::Type::kVec3},
+                    TokenData{"vec4", Token::Type::kVec4},
+                    TokenData{"workgroup", Token::Type::kWorkgroup}));
 
 }  // namespace
 }  // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/parser.cc b/src/tint/reader/wgsl/parser.cc
index 70e8c09..c1ad4a3 100644
--- a/src/tint/reader/wgsl/parser.cc
+++ b/src/tint/reader/wgsl/parser.cc
@@ -21,9 +21,9 @@
 namespace tint::reader::wgsl {
 
 Program Parse(Source::File const* file) {
-  ParserImpl parser(file);
-  parser.Parse();
-  return Program(std::move(parser.builder()));
+    ParserImpl parser(file);
+    parser.Parse();
+    return Program(std::move(parser.builder()));
 }
 
 }  // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/parser_bench.cc b/src/tint/reader/wgsl/parser_bench.cc
index 471bba0..097accf 100644
--- a/src/tint/reader/wgsl/parser_bench.cc
+++ b/src/tint/reader/wgsl/parser_bench.cc
@@ -20,18 +20,18 @@
 namespace {
 
 void ParseWGSL(benchmark::State& state, std::string input_name) {
-  auto res = bench::LoadInputFile(input_name);
-  if (auto err = std::get_if<bench::Error>(&res)) {
-    state.SkipWithError(err->msg.c_str());
-    return;
-  }
-  auto& file = std::get<Source::File>(res);
-  for (auto _ : state) {
-    auto res = Parse(&file);
-    if (res.Diagnostics().contains_errors()) {
-      state.SkipWithError(res.Diagnostics().str().c_str());
+    auto res = bench::LoadInputFile(input_name);
+    if (auto err = std::get_if<bench::Error>(&res)) {
+        state.SkipWithError(err->msg.c_str());
+        return;
     }
-  }
+    auto& file = std::get<Source::File>(res);
+    for (auto _ : state) {
+        auto res = Parse(&file);
+        if (res.Diagnostics().contains_errors()) {
+            state.SkipWithError(res.Diagnostics().str().c_str());
+        }
+    }
 }
 
 TINT_BENCHMARK_WGSL_PROGRAMS(ParseWGSL);
diff --git a/src/tint/reader/wgsl/parser_impl.cc b/src/tint/reader/wgsl/parser_impl.cc
index b5890db..8661a00 100644
--- a/src/tint/reader/wgsl/parser_impl.cc
+++ b/src/tint/reader/wgsl/parser_impl.cc
@@ -14,6 +14,8 @@
 
 #include "src/tint/reader/wgsl/parser_impl.h"
 
+#include <limits>
+
 #include "src/tint/ast/array.h"
 #include "src/tint/ast/assignment_statement.h"
 #include "src/tint/ast/bitcast_expression.h"
@@ -37,10 +39,10 @@
 #include "src/tint/ast/vector.h"
 #include "src/tint/ast/workgroup_attribute.h"
 #include "src/tint/reader/wgsl/lexer.h"
-#include "src/tint/sem/depth_texture_type.h"
-#include "src/tint/sem/external_texture_type.h"
-#include "src/tint/sem/multisampled_texture_type.h"
-#include "src/tint/sem/sampled_texture_type.h"
+#include "src/tint/sem/depth_texture.h"
+#include "src/tint/sem/external_texture.h"
+#include "src/tint/sem/multisampled_texture.h"
+#include "src/tint/sem/sampled_texture.h"
 
 namespace tint::reader::wgsl {
 namespace {
@@ -69,43 +71,43 @@
 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;
+    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";
@@ -122,70 +124,67 @@
 
 // https://gpuweb.github.io/gpuweb/wgsl.html#reserved-keywords
 bool is_reserved(Token t) {
-  return t == "asm" || t == "bf16" || t == "const" || t == "do" ||
-         t == "enum" || t == "f16" || t == "f64" || t == "handle" ||
-         t == "i8" || t == "i16" || t == "i64" || t == "mat" ||
-         t == "premerge" || t == "regardless" || t == "typedef" || t == "u8" ||
-         t == "u16" || t == "u64" || t == "unless" || t == "using" ||
-         t == "vec" || t == "void" || t == "while";
+    return t == "asm" || t == "bf16" || t == "const" || t == "do" || t == "enum" || t == "f16" ||
+           t == "f64" || t == "handle" || t == "i8" || t == "i16" || t == "i64" || t == "mat" ||
+           t == "premerge" || t == "regardless" || t == "typedef" || t == "u8" || t == "u16" ||
+           t == "u64" || t == "unless" || t == "using" || t == "vec" || t == "void" || t == "while";
 }
 
 /// Enter-exit counters for block token types.
 /// Used by sync_to() to skip over closing block tokens that were opened during
 /// the forward scan.
 struct BlockCounters {
-  int brace = 0;    // {   }
-  int bracket = 0;  // [   ]
-  int paren = 0;    // (   )
+    int brace = 0;    // {   }
+    int bracket = 0;  // [   ]
+    int paren = 0;    // (   )
 
-  /// @return the current enter-exit depth for the given block token type. If
-  /// `t` is not a block token type, then 0 is always returned.
-  int consume(const Token& t) {
-    if (t.Is(Token::Type::kBraceLeft))
-      return brace++;
-    if (t.Is(Token::Type::kBraceRight))
-      return brace--;
-    if (t.Is(Token::Type::kBracketLeft))
-      return bracket++;
-    if (t.Is(Token::Type::kBracketRight))
-      return bracket--;
-    if (t.Is(Token::Type::kParenLeft))
-      return paren++;
-    if (t.Is(Token::Type::kParenRight))
-      return paren--;
-    return 0;
-  }
+    /// @return the current enter-exit depth for the given block token type. If
+    /// `t` is not a block token type, then 0 is always returned.
+    int consume(const Token& t) {
+        if (t.Is(Token::Type::kBraceLeft))
+            return brace++;
+        if (t.Is(Token::Type::kBraceRight))
+            return brace--;
+        if (t.Is(Token::Type::kBracketLeft))
+            return bracket++;
+        if (t.Is(Token::Type::kBracketRight))
+            return bracket--;
+        if (t.Is(Token::Type::kParenLeft))
+            return paren++;
+        if (t.Is(Token::Type::kParenRight))
+            return paren--;
+        return 0;
+    }
 };
 }  // namespace
 
 /// RAII helper that combines a Source on construction with the last token's
 /// source when implicitly converted to `Source`.
 class ParserImpl::MultiTokenSource {
- public:
-  /// Constructor that starts with Source at the current peek position
-  /// @param parser the parser
-  explicit MultiTokenSource(ParserImpl* parser)
-      : MultiTokenSource(parser, parser->peek().source().Begin()) {}
+  public:
+    /// Constructor that starts with Source at the current peek position
+    /// @param parser the parser
+    explicit MultiTokenSource(ParserImpl* parser)
+        : MultiTokenSource(parser, parser->peek().source().Begin()) {}
 
-  /// Constructor that starts with the input `start` Source
-  /// @param parser the parser
-  /// @param start the start source of the range
-  MultiTokenSource(ParserImpl* parser, const Source& start)
-      : parser_(parser), start_(start) {}
+    /// Constructor that starts with the input `start` Source
+    /// @param parser the parser
+    /// @param start the start source of the range
+    MultiTokenSource(ParserImpl* parser, const Source& start) : parser_(parser), start_(start) {}
 
-  /// Implicit conversion to Source that returns the combined source from start
-  /// to the current last token's source.
-  operator Source() const {
-    Source end = parser_->last_token().source().End();
-    if (end < start_) {
-      end = start_;
+    /// Implicit conversion to Source that returns the combined source from start
+    /// to the current last token's source.
+    operator Source() const {
+        Source end = parser_->last_token().source().End();
+        if (end < start_) {
+            end = start_;
+        }
+        return Source::Combine(start_, end);
     }
-    return Source::Combine(start_, end);
-  }
 
- private:
-  ParserImpl* parser_;
-  Source start_;
+  private:
+    ParserImpl* parser_;
+    Source start_;
 };
 
 ParserImpl::TypedIdentifier::TypedIdentifier() = default;
@@ -208,16 +207,12 @@
                                            ast::VariableList p,
                                            const ast::Type* ret_ty,
                                            ast::AttributeList ret_attrs)
-    : source(src),
-      name(n),
-      params(p),
-      return_type(ret_ty),
-      return_type_attributes(ret_attrs) {}
+    : source(src), name(n), params(p), return_type(ret_ty), return_type_attributes(ret_attrs) {}
 
 ParserImpl::FunctionHeader::~FunctionHeader() = default;
 
-ParserImpl::FunctionHeader& ParserImpl::FunctionHeader::operator=(
-    const FunctionHeader& rhs) = default;
+ParserImpl::FunctionHeader& ParserImpl::FunctionHeader::operator=(const FunctionHeader& rhs) =
+    default;
 
 ParserImpl::VarDeclInfo::VarDeclInfo() = default;
 
@@ -236,89 +231,152 @@
 
 ParserImpl::VarDeclInfo::~VarDeclInfo() = default;
 
-ParserImpl::ParserImpl(Source::File const* file)
-    : lexer_(std::make_unique<Lexer>(file)) {}
+ParserImpl::ParserImpl(Source::File const* file) : lexer_(std::make_unique<Lexer>(file)) {}
 
 ParserImpl::~ParserImpl() = default;
 
 ParserImpl::Failure::Errored ParserImpl::add_error(const Source& source,
                                                    std::string_view err,
                                                    std::string_view use) {
-  std::stringstream msg;
-  msg << err;
-  if (!use.empty()) {
-    msg << " for " << use;
-  }
-  add_error(source, msg.str());
-  return Failure::kErrored;
+    std::stringstream msg;
+    msg << err;
+    if (!use.empty()) {
+        msg << " for " << use;
+    }
+    add_error(source, msg.str());
+    return Failure::kErrored;
 }
 
-ParserImpl::Failure::Errored ParserImpl::add_error(const Token& t,
-                                                   const std::string& err) {
-  add_error(t.source(), err);
-  return Failure::kErrored;
+ParserImpl::Failure::Errored ParserImpl::add_error(const Token& t, const std::string& err) {
+    add_error(t.source(), err);
+    return Failure::kErrored;
 }
 
-ParserImpl::Failure::Errored ParserImpl::add_error(const Source& source,
-                                                   const std::string& err) {
-  if (silence_errors_ == 0) {
-    builder_.Diagnostics().add_error(diag::System::Reader, err, source);
-  }
-  return Failure::kErrored;
+ParserImpl::Failure::Errored ParserImpl::add_error(const Source& source, const std::string& err) {
+    if (silence_errors_ == 0) {
+        builder_.Diagnostics().add_error(diag::System::Reader, err, source);
+    }
+    return Failure::kErrored;
 }
 
 void ParserImpl::deprecated(const Source& source, const std::string& msg) {
-  builder_.Diagnostics().add_warning(
-      diag::System::Reader, "use of deprecated language feature: " + msg,
-      source);
+    builder_.Diagnostics().add_warning(diag::System::Reader,
+                                       "use of deprecated language feature: " + msg, source);
 }
 
 Token ParserImpl::next() {
-  if (!token_queue_.empty()) {
-    auto t = token_queue_.front();
-    token_queue_.pop_front();
-    last_token_ = t;
+    if (!token_queue_.empty()) {
+        auto t = token_queue_.front();
+        token_queue_.pop_front();
+        last_token_ = t;
+        return last_token_;
+    }
+    last_token_ = lexer_->next();
     return last_token_;
-  }
-  last_token_ = lexer_->next();
-  return last_token_;
 }
 
 Token ParserImpl::peek(size_t idx) {
-  while (token_queue_.size() < (idx + 1)) {
-    token_queue_.push_back(lexer_->next());
-  }
-  return token_queue_[idx];
+    while (token_queue_.size() < (idx + 1)) {
+        token_queue_.push_back(lexer_->next());
+    }
+    return token_queue_[idx];
 }
 
 bool ParserImpl::peek_is(Token::Type tok, size_t idx) {
-  return peek(idx).Is(tok);
+    return peek(idx).Is(tok);
 }
 
 Token ParserImpl::last_token() const {
-  return last_token_;
+    return last_token_;
 }
 
 bool ParserImpl::Parse() {
-  translation_unit();
-  return !has_error();
+    translation_unit();
+    return !has_error();
 }
 
 // translation_unit
-//  : global_decl* EOF
+//  : enable_directive* global_decl* EOF
 void ParserImpl::translation_unit() {
-  while (continue_parsing()) {
-    auto p = peek();
-    if (p.IsEof()) {
-      break;
+    bool after_global_decl = false;
+    while (continue_parsing()) {
+        auto p = peek();
+        if (p.IsEof()) {
+            break;
+        }
+
+        auto ed = enable_directive();
+        if (ed.matched) {
+            if (after_global_decl) {
+                add_error(p, "enable directives must come before all global declarations");
+            }
+        } else {
+            auto gd = global_decl();
+
+            if (gd.matched) {
+                after_global_decl = true;
+            }
+
+            if (!gd.matched && !gd.errored) {
+                add_error(p, "unexpected token");
+            }
+        }
+
+        if (builder_.Diagnostics().error_count() >= max_errors_) {
+            add_error(Source{{}, p.source().file},
+                      "stopping after " + std::to_string(max_errors_) + " errors");
+            break;
+        }
     }
-    expect_global_decl();
-    if (builder_.Diagnostics().error_count() >= max_errors_) {
-      add_error(Source{{}, p.source().file},
-                "stopping after " + std::to_string(max_errors_) + " errors");
-      break;
+}
+
+// enable_directive
+//  : enable name SEMICLON
+Maybe<bool> ParserImpl::enable_directive() {
+    auto decl = sync(Token::Type::kSemicolon, [&]() -> Maybe<bool> {
+        if (!match(Token::Type::kEnable)) {
+            return Failure::kNoMatch;
+        }
+
+        // Match the extension name.
+        Expect<std::string> name = {""};
+        auto t = peek();
+        if (t.IsIdentifier()) {
+            synchronized_ = true;
+            next();
+            name = {t.to_str(), t.source()};
+        } else if (handle_error(t)) {
+            // The token might itself be an error.
+            return Failure::kErrored;
+        } else {
+            // Failed to match an extension name.
+            synchronized_ = false;
+            return add_error(t.source(), "invalid extension name");
+        }
+
+        if (!expect("enable directive", Token::Type::kSemicolon)) {
+            return Failure::kErrored;
+        }
+
+        if (ast::Enable::NameToKind(name.value) != ast::Enable::ExtensionKind::kNotAnExtension) {
+            const ast::Enable* extension = create<ast::Enable>(name.source, name.value);
+            builder_.AST().AddEnable(extension);
+        } else {
+            // Error if an unknown extension is used
+            return add_error(name.source, "unsupported extension: '" + name.value + "'");
+        }
+
+        return true;
+    });
+
+    if (decl.errored) {
+        return Failure::kErrored;
     }
-  }
+    if (decl.matched) {
+        return true;
+    }
+
+    return Failure::kNoMatch;
 }
 
 // global_decl
@@ -328,148 +386,146 @@
 //  | type_alias SEMICOLON
 //  | struct_decl
 //  | function_decl
-Expect<bool> ParserImpl::expect_global_decl() {
-  if (match(Token::Type::kSemicolon) || match(Token::Type::kEOF))
-    return true;
+Maybe<bool> ParserImpl::global_decl() {
+    if (match(Token::Type::kSemicolon) || match(Token::Type::kEOF))
+        return true;
 
-  bool errored = false;
+    bool errored = false;
 
-  auto attrs = attribute_list();
-  if (attrs.errored)
-    errored = true;
-  if (!continue_parsing())
-    return Failure::kErrored;
-
-  auto decl = sync(Token::Type::kSemicolon, [&]() -> Maybe<bool> {
-    auto gv = global_variable_decl(attrs.value);
-    if (gv.errored)
-      return Failure::kErrored;
-    if (gv.matched) {
-      if (!expect("variable declaration", Token::Type::kSemicolon))
+    auto attrs = attribute_list();
+    if (attrs.errored)
+        errored = true;
+    if (!continue_parsing())
         return Failure::kErrored;
 
-      builder_.AST().AddGlobalVariable(gv.value);
-      return true;
+    auto decl = sync(Token::Type::kSemicolon, [&]() -> Maybe<bool> {
+        auto gv = global_variable_decl(attrs.value);
+        if (gv.errored)
+            return Failure::kErrored;
+        if (gv.matched) {
+            if (!expect("variable declaration", Token::Type::kSemicolon))
+                return Failure::kErrored;
+
+            builder_.AST().AddGlobalVariable(gv.value);
+            return true;
+        }
+
+        auto gc = global_constant_decl(attrs.value);
+        if (gc.errored)
+            return Failure::kErrored;
+
+        if (gc.matched) {
+            if (!expect("let declaration", Token::Type::kSemicolon))
+                return Failure::kErrored;
+
+            builder_.AST().AddGlobalVariable(gc.value);
+            return true;
+        }
+
+        auto ta = type_alias();
+        if (ta.errored)
+            return Failure::kErrored;
+
+        if (ta.matched) {
+            if (!expect("type alias", Token::Type::kSemicolon))
+                return Failure::kErrored;
+
+            builder_.AST().AddTypeDecl(ta.value);
+            return true;
+        }
+
+        auto str = struct_decl();
+        if (str.errored)
+            return Failure::kErrored;
+
+        if (str.matched) {
+            builder_.AST().AddTypeDecl(str.value);
+            return true;
+        }
+
+        return Failure::kNoMatch;
+    });
+
+    if (decl.errored) {
+        errored = true;
+    }
+    if (decl.matched) {
+        return expect_attributes_consumed(attrs.value);
     }
 
-    auto gc = global_constant_decl(attrs.value);
-    if (gc.errored)
-      return Failure::kErrored;
+    auto func = function_decl(attrs.value);
+    if (func.errored) {
+        errored = true;
+    }
+    if (func.matched) {
+        builder_.AST().AddFunction(func.value);
+        return true;
+    }
 
-    if (gc.matched) {
-      if (!expect("let declaration", Token::Type::kSemicolon))
+    if (errored) {
         return Failure::kErrored;
-
-      builder_.AST().AddGlobalVariable(gc.value);
-      return true;
     }
 
-    auto ta = type_alias();
-    if (ta.errored)
-      return Failure::kErrored;
+    // Invalid syntax found - try and determine the best error message
 
-    if (ta.matched) {
-      if (!expect("type alias", Token::Type::kSemicolon))
+    // We have attributes parsed, but nothing to consume them?
+    if (attrs.value.size() > 0) {
+        return add_error(next(), "expected declaration after attributes");
+    }
+
+    // We have a statement outside of a function?
+    auto t = peek();
+    auto stat = without_error([&] { return statement(); });
+    if (stat.matched) {
+        // Attempt to jump to the next '}' - the function might have just been
+        // missing an opening line.
+        sync_to(Token::Type::kBraceRight, true);
+        return add_error(t, "statement found outside of function body");
+    }
+    if (!stat.errored) {
+        // No match, no error - the parser might not have progressed.
+        // Ensure we always make _some_ forward progress.
+        next();
+    }
+
+    // The token might itself be an error.
+    if (handle_error(t)) {
         return Failure::kErrored;
-
-      builder_.AST().AddTypeDecl(ta.value);
-      return true;
     }
 
-    auto str = struct_decl();
-    if (str.errored)
-      return Failure::kErrored;
-
-    if (str.matched) {
-      builder_.AST().AddTypeDecl(str.value);
-      return true;
-    }
+    // Exhausted all attempts to make sense of where we're at.
+    // Return a no-match
 
     return Failure::kNoMatch;
-  });
-
-  if (decl.errored) {
-    errored = true;
-  }
-  if (decl.matched) {
-    return expect_attributes_consumed(attrs.value);
-  }
-
-  auto func = function_decl(attrs.value);
-  if (func.errored) {
-    errored = true;
-  }
-  if (func.matched) {
-    builder_.AST().AddFunction(func.value);
-    return true;
-  }
-
-  if (errored) {
-    return Failure::kErrored;
-  }
-
-  // Invalid syntax found - try and determine the best error message
-
-  // We have attributes parsed, but nothing to consume them?
-  if (attrs.value.size() > 0) {
-    return add_error(next(), "expected declaration after attributes");
-  }
-
-  // We have a statement outside of a function?
-  auto t = peek();
-  auto stat = without_error([&] { return statement(); });
-  if (stat.matched) {
-    // Attempt to jump to the next '}' - the function might have just been
-    // missing an opening line.
-    sync_to(Token::Type::kBraceRight, true);
-    return add_error(t, "statement found outside of function body");
-  }
-  if (!stat.errored) {
-    // No match, no error - the parser might not have progressed.
-    // Ensure we always make _some_ forward progress.
-    next();
-  }
-
-  // The token might itself be an error.
-  if (handle_error(t)) {
-    return Failure::kErrored;
-  }
-
-  // Exhausted all attempts to make sense of where we're at.
-  // Spew a generic error.
-
-  return add_error(t, "unexpected token");
 }
 
 // global_variable_decl
 //  : variable_attribute_list* variable_decl
 //  | variable_attribute_list* variable_decl EQUAL const_expr
-Maybe<const ast::Variable*> ParserImpl::global_variable_decl(
-    ast::AttributeList& attrs) {
-  auto decl = variable_decl();
-  if (decl.errored)
-    return Failure::kErrored;
-  if (!decl.matched)
-    return Failure::kNoMatch;
+Maybe<const ast::Variable*> ParserImpl::global_variable_decl(ast::AttributeList& attrs) {
+    auto decl = variable_decl();
+    if (decl.errored)
+        return Failure::kErrored;
+    if (!decl.matched)
+        return Failure::kNoMatch;
 
-  const ast::Expression* constructor = nullptr;
-  if (match(Token::Type::kEqual)) {
-    auto expr = expect_const_expr();
-    if (expr.errored)
-      return Failure::kErrored;
-    constructor = expr.value;
-  }
+    const ast::Expression* constructor = nullptr;
+    if (match(Token::Type::kEqual)) {
+        auto expr = expect_const_expr();
+        if (expr.errored)
+            return Failure::kErrored;
+        constructor = expr.value;
+    }
 
-  return create<ast::Variable>(
-      decl->source,                             // source
-      builder_.Symbols().Register(decl->name),  // symbol
-      decl->storage_class,                      // storage class
-      decl->access,                             // access control
-      decl->type,                               // type
-      false,                                    // is_const
-      false,                                    // is_overridable
-      constructor,                              // constructor
-      std::move(attrs));                        // attributes
+    return create<ast::Variable>(decl->source,                             // source
+                                 builder_.Symbols().Register(decl->name),  // symbol
+                                 decl->storage_class,                      // storage class
+                                 decl->access,                             // access control
+                                 decl->type,                               // type
+                                 false,                                    // is_const
+                                 false,                                    // is_overridable
+                                 constructor,                              // constructor
+                                 std::move(attrs));                        // attributes
 }
 
 // global_constant_decl :
@@ -477,253 +533,246 @@
 //  | attribute* override (ident | variable_ident_decl) (equal expression)?
 // global_const_initializer
 //  : EQUAL const_expr
-Maybe<const ast::Variable*> ParserImpl::global_constant_decl(
-    ast::AttributeList& attrs) {
-  bool is_overridable = false;
-  const char* use = nullptr;
-  if (match(Token::Type::kLet)) {
-    use = "let declaration";
-  } else if (match(Token::Type::kOverride)) {
-    use = "override declaration";
-    is_overridable = true;
-  } else {
-    return Failure::kNoMatch;
-  }
-
-  auto decl = expect_variable_ident_decl(use, /* allow_inferred = */ true);
-  if (decl.errored)
-    return Failure::kErrored;
-
-  const ast::Expression* initializer = nullptr;
-  if (match(Token::Type::kEqual)) {
-    auto init = expect_const_expr();
-    if (init.errored) {
-      return Failure::kErrored;
+Maybe<const ast::Variable*> ParserImpl::global_constant_decl(ast::AttributeList& attrs) {
+    bool is_overridable = false;
+    const char* use = nullptr;
+    if (match(Token::Type::kLet)) {
+        use = "let declaration";
+    } else if (match(Token::Type::kOverride)) {
+        use = "override declaration";
+        is_overridable = true;
+    } else {
+        return Failure::kNoMatch;
     }
-    initializer = std::move(init.value);
-  }
 
-  return create<ast::Variable>(
-      decl->source,                             // source
-      builder_.Symbols().Register(decl->name),  // symbol
-      ast::StorageClass::kNone,                 // storage class
-      ast::Access::kUndefined,                  // access control
-      decl->type,                               // type
-      true,                                     // is_const
-      is_overridable,                           // is_overridable
-      initializer,                              // constructor
-      std::move(attrs));                        // attributes
+    auto decl = expect_variable_ident_decl(use, /* allow_inferred = */ true);
+    if (decl.errored)
+        return Failure::kErrored;
+
+    const ast::Expression* initializer = nullptr;
+    if (match(Token::Type::kEqual)) {
+        auto init = expect_const_expr();
+        if (init.errored) {
+            return Failure::kErrored;
+        }
+        initializer = std::move(init.value);
+    }
+
+    return create<ast::Variable>(decl->source,                             // source
+                                 builder_.Symbols().Register(decl->name),  // symbol
+                                 ast::StorageClass::kNone,                 // storage class
+                                 ast::Access::kUndefined,                  // access control
+                                 decl->type,                               // type
+                                 true,                                     // is_const
+                                 is_overridable,                           // is_overridable
+                                 initializer,                              // constructor
+                                 std::move(attrs));                        // attributes
 }
 
 // variable_decl
 //   : VAR variable_qualifier? variable_ident_decl
 Maybe<ParserImpl::VarDeclInfo> ParserImpl::variable_decl(bool allow_inferred) {
-  Source source;
-  if (!match(Token::Type::kVar, &source))
-    return Failure::kNoMatch;
+    Source source;
+    if (!match(Token::Type::kVar, &source))
+        return Failure::kNoMatch;
 
-  VariableQualifier vq;
-  auto explicit_vq = variable_qualifier();
-  if (explicit_vq.errored)
-    return Failure::kErrored;
-  if (explicit_vq.matched) {
-    vq = explicit_vq.value;
-  }
-
-  auto decl =
-      expect_variable_ident_decl("variable declaration", allow_inferred);
-  if (decl.errored)
-    return Failure::kErrored;
-
-  return VarDeclInfo{decl->source, decl->name, vq.storage_class, vq.access,
-                     decl->type};
-}
-
-// texture_sampler_types
-//  : sampler_type
-//  | depth_texture_type
-//  | sampled_texture_type LESS_THAN type_decl GREATER_THAN
-//  | multisampled_texture_type LESS_THAN type_decl GREATER_THAN
-//  | storage_texture_type LESS_THAN texel_format
-//                         COMMA access GREATER_THAN
-Maybe<const ast::Type*> ParserImpl::texture_sampler_types() {
-  auto type = sampler_type();
-  if (type.matched)
-    return type;
-
-  type = depth_texture_type();
-  if (type.matched)
-    return type;
-
-  type = external_texture_type();
-  if (type.matched)
-    return type.value;
-
-  auto source_range = make_source_range();
-
-  auto dim = sampled_texture_type();
-  if (dim.matched) {
-    const char* use = "sampled texture type";
-
-    auto subtype = expect_lt_gt_block(use, [&] { return expect_type(use); });
-    if (subtype.errored)
-      return Failure::kErrored;
-
-    return builder_.ty.sampled_texture(source_range, dim.value, subtype.value);
-  }
-
-  auto ms_dim = multisampled_texture_type();
-  if (ms_dim.matched) {
-    const char* use = "multisampled texture type";
-
-    auto subtype = expect_lt_gt_block(use, [&] { return expect_type(use); });
-    if (subtype.errored)
-      return Failure::kErrored;
-
-    return builder_.ty.multisampled_texture(source_range, ms_dim.value,
-                                            subtype.value);
-  }
-
-  auto storage = storage_texture_type();
-  if (storage.matched) {
-    const char* use = "storage texture type";
-    using StorageTextureInfo =
-        std::pair<tint::ast::TexelFormat, tint::ast::Access>;
-    auto params = expect_lt_gt_block(use, [&]() -> Expect<StorageTextureInfo> {
-      auto format = expect_texel_format(use);
-      if (format.errored) {
+    VariableQualifier vq;
+    auto explicit_vq = variable_qualifier();
+    if (explicit_vq.errored)
         return Failure::kErrored;
-      }
-
-      if (!expect("access control", Token::Type::kComma)) {
-        return Failure::kErrored;
-      }
-
-      auto access = expect_access("access control");
-      if (access.errored) {
-        return Failure::kErrored;
-      }
-
-      return std::make_pair(format.value, access.value);
-    });
-
-    if (params.errored) {
-      return Failure::kErrored;
+    if (explicit_vq.matched) {
+        vq = explicit_vq.value;
     }
 
-    return builder_.ty.storage_texture(source_range, storage.value,
-                                       params->first, params->second);
-  }
+    auto decl = expect_variable_ident_decl("variable declaration", allow_inferred);
+    if (decl.errored)
+        return Failure::kErrored;
 
-  return Failure::kNoMatch;
+    return VarDeclInfo{decl->source, decl->name, vq.storage_class, vq.access, decl->type};
 }
 
-// sampler_type
+// texture_samplers
+//  : sampler
+//  | depth_texture
+//  | sampled_texture LESS_THAN type_decl GREATER_THAN
+//  | multisampled_texture LESS_THAN type_decl GREATER_THAN
+//  | storage_texture LESS_THAN texel_format
+//                         COMMA access GREATER_THAN
+Maybe<const ast::Type*> ParserImpl::texture_samplers() {
+    auto type = sampler();
+    if (type.matched)
+        return type;
+
+    type = depth_texture();
+    if (type.matched)
+        return type;
+
+    type = external_texture();
+    if (type.matched)
+        return type.value;
+
+    auto source_range = make_source_range();
+
+    auto dim = sampled_texture();
+    if (dim.matched) {
+        const char* use = "sampled texture type";
+
+        auto subtype = expect_lt_gt_block(use, [&] { return expect_type(use); });
+        if (subtype.errored)
+            return Failure::kErrored;
+
+        return builder_.ty.sampled_texture(source_range, dim.value, subtype.value);
+    }
+
+    auto ms_dim = multisampled_texture();
+    if (ms_dim.matched) {
+        const char* use = "multisampled texture type";
+
+        auto subtype = expect_lt_gt_block(use, [&] { return expect_type(use); });
+        if (subtype.errored)
+            return Failure::kErrored;
+
+        return builder_.ty.multisampled_texture(source_range, ms_dim.value, subtype.value);
+    }
+
+    auto storage = storage_texture();
+    if (storage.matched) {
+        const char* use = "storage texture type";
+        using StorageTextureInfo = std::pair<tint::ast::TexelFormat, tint::ast::Access>;
+        auto params = expect_lt_gt_block(use, [&]() -> Expect<StorageTextureInfo> {
+            auto format = expect_texel_format(use);
+            if (format.errored) {
+                return Failure::kErrored;
+            }
+
+            if (!expect("access control", Token::Type::kComma)) {
+                return Failure::kErrored;
+            }
+
+            auto access = expect_access("access control");
+            if (access.errored) {
+                return Failure::kErrored;
+            }
+
+            return std::make_pair(format.value, access.value);
+        });
+
+        if (params.errored) {
+            return Failure::kErrored;
+        }
+
+        return builder_.ty.storage_texture(source_range, storage.value, params->first,
+                                           params->second);
+    }
+
+    return Failure::kNoMatch;
+}
+
+// sampler
 //  : SAMPLER
 //  | SAMPLER_COMPARISON
-Maybe<const ast::Type*> ParserImpl::sampler_type() {
-  Source source;
-  if (match(Token::Type::kSampler, &source))
-    return builder_.ty.sampler(source, ast::SamplerKind::kSampler);
+Maybe<const ast::Type*> ParserImpl::sampler() {
+    Source source;
+    if (match(Token::Type::kSampler, &source))
+        return builder_.ty.sampler(source, ast::SamplerKind::kSampler);
 
-  if (match(Token::Type::kComparisonSampler, &source))
-    return builder_.ty.sampler(source, ast::SamplerKind::kComparisonSampler);
+    if (match(Token::Type::kComparisonSampler, &source))
+        return builder_.ty.sampler(source, ast::SamplerKind::kComparisonSampler);
 
-  return Failure::kNoMatch;
+    return Failure::kNoMatch;
 }
 
-// sampled_texture_type
+// sampled_texture
 //  : TEXTURE_SAMPLED_1D
 //  | TEXTURE_SAMPLED_2D
 //  | TEXTURE_SAMPLED_2D_ARRAY
 //  | TEXTURE_SAMPLED_3D
 //  | TEXTURE_SAMPLED_CUBE
 //  | TEXTURE_SAMPLED_CUBE_ARRAY
-Maybe<const ast::TextureDimension> ParserImpl::sampled_texture_type() {
-  if (match(Token::Type::kTextureSampled1d))
-    return ast::TextureDimension::k1d;
+Maybe<const ast::TextureDimension> ParserImpl::sampled_texture() {
+    if (match(Token::Type::kTextureSampled1d))
+        return ast::TextureDimension::k1d;
 
-  if (match(Token::Type::kTextureSampled2d))
-    return ast::TextureDimension::k2d;
+    if (match(Token::Type::kTextureSampled2d))
+        return ast::TextureDimension::k2d;
 
-  if (match(Token::Type::kTextureSampled2dArray))
-    return ast::TextureDimension::k2dArray;
+    if (match(Token::Type::kTextureSampled2dArray))
+        return ast::TextureDimension::k2dArray;
 
-  if (match(Token::Type::kTextureSampled3d))
-    return ast::TextureDimension::k3d;
+    if (match(Token::Type::kTextureSampled3d))
+        return ast::TextureDimension::k3d;
 
-  if (match(Token::Type::kTextureSampledCube))
-    return ast::TextureDimension::kCube;
+    if (match(Token::Type::kTextureSampledCube))
+        return ast::TextureDimension::kCube;
 
-  if (match(Token::Type::kTextureSampledCubeArray))
-    return ast::TextureDimension::kCubeArray;
+    if (match(Token::Type::kTextureSampledCubeArray))
+        return ast::TextureDimension::kCubeArray;
 
-  return Failure::kNoMatch;
+    return Failure::kNoMatch;
 }
 
-// external_texture_type
+// external_texture
 //  : TEXTURE_EXTERNAL
-Maybe<const ast::Type*> ParserImpl::external_texture_type() {
-  Source source;
-  if (match(Token::Type::kTextureExternal, &source)) {
-    return builder_.ty.external_texture(source);
-  }
+Maybe<const ast::Type*> ParserImpl::external_texture() {
+    Source source;
+    if (match(Token::Type::kTextureExternal, &source)) {
+        return builder_.ty.external_texture(source);
+    }
 
-  return Failure::kNoMatch;
+    return Failure::kNoMatch;
 }
 
-// multisampled_texture_type
+// multisampled_texture
 //  : TEXTURE_MULTISAMPLED_2D
-Maybe<const ast::TextureDimension> ParserImpl::multisampled_texture_type() {
-  if (match(Token::Type::kTextureMultisampled2d))
-    return ast::TextureDimension::k2d;
+Maybe<const ast::TextureDimension> ParserImpl::multisampled_texture() {
+    if (match(Token::Type::kTextureMultisampled2d))
+        return ast::TextureDimension::k2d;
 
-  return Failure::kNoMatch;
+    return Failure::kNoMatch;
 }
 
-// storage_texture_type
+// storage_texture
 //  : TEXTURE_STORAGE_1D
 //  | TEXTURE_STORAGE_2D
 //  | TEXTURE_STORAGE_2D_ARRAY
 //  | TEXTURE_STORAGE_3D
-Maybe<const ast::TextureDimension> ParserImpl::storage_texture_type() {
-  if (match(Token::Type::kTextureStorage1d))
-    return ast::TextureDimension::k1d;
-  if (match(Token::Type::kTextureStorage2d))
-    return ast::TextureDimension::k2d;
-  if (match(Token::Type::kTextureStorage2dArray))
-    return ast::TextureDimension::k2dArray;
-  if (match(Token::Type::kTextureStorage3d))
-    return ast::TextureDimension::k3d;
+Maybe<const ast::TextureDimension> ParserImpl::storage_texture() {
+    if (match(Token::Type::kTextureStorage1d))
+        return ast::TextureDimension::k1d;
+    if (match(Token::Type::kTextureStorage2d))
+        return ast::TextureDimension::k2d;
+    if (match(Token::Type::kTextureStorage2dArray))
+        return ast::TextureDimension::k2dArray;
+    if (match(Token::Type::kTextureStorage3d))
+        return ast::TextureDimension::k3d;
 
-  return Failure::kNoMatch;
+    return Failure::kNoMatch;
 }
 
-// depth_texture_type
+// depth_texture
 //  : TEXTURE_DEPTH_2D
 //  | TEXTURE_DEPTH_2D_ARRAY
 //  | TEXTURE_DEPTH_CUBE
 //  | TEXTURE_DEPTH_CUBE_ARRAY
 //  | TEXTURE_DEPTH_MULTISAMPLED_2D
-Maybe<const ast::Type*> ParserImpl::depth_texture_type() {
-  Source source;
-  if (match(Token::Type::kTextureDepth2d, &source)) {
-    return builder_.ty.depth_texture(source, ast::TextureDimension::k2d);
-  }
-  if (match(Token::Type::kTextureDepth2dArray, &source)) {
-    return builder_.ty.depth_texture(source, ast::TextureDimension::k2dArray);
-  }
-  if (match(Token::Type::kTextureDepthCube, &source)) {
-    return builder_.ty.depth_texture(source, ast::TextureDimension::kCube);
-  }
-  if (match(Token::Type::kTextureDepthCubeArray, &source)) {
-    return builder_.ty.depth_texture(source, ast::TextureDimension::kCubeArray);
-  }
-  if (match(Token::Type::kTextureDepthMultisampled2d, &source)) {
-    return builder_.ty.depth_multisampled_texture(source,
-                                                  ast::TextureDimension::k2d);
-  }
-  return Failure::kNoMatch;
+Maybe<const ast::Type*> ParserImpl::depth_texture() {
+    Source source;
+    if (match(Token::Type::kTextureDepth2d, &source)) {
+        return builder_.ty.depth_texture(source, ast::TextureDimension::k2d);
+    }
+    if (match(Token::Type::kTextureDepth2dArray, &source)) {
+        return builder_.ty.depth_texture(source, ast::TextureDimension::k2dArray);
+    }
+    if (match(Token::Type::kTextureDepthCube, &source)) {
+        return builder_.ty.depth_texture(source, ast::TextureDimension::kCube);
+    }
+    if (match(Token::Type::kTextureDepthCubeArray, &source)) {
+        return builder_.ty.depth_texture(source, ast::TextureDimension::kCubeArray);
+    }
+    if (match(Token::Type::kTextureDepthMultisampled2d, &source)) {
+        return builder_.ty.depth_multisampled_texture(source, ast::TextureDimension::k2d);
+    }
+    return Failure::kNoMatch;
 }
 
 // texel_format
@@ -744,155 +793,153 @@
 //  | 'rgba32sint'
 //  | 'rgba32float'
 Expect<ast::TexelFormat> ParserImpl::expect_texel_format(std::string_view use) {
-  auto t = next();
-  if (t == "rgba8unorm") {
-    return ast::TexelFormat::kRgba8Unorm;
-  }
-  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);
+    auto t = next();
+    if (t == "rgba8unorm") {
+        return ast::TexelFormat::kRgba8Unorm;
+    }
+    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);
 }
 
 // variable_ident_decl
 //   : IDENT COLON type_decl
-Expect<ParserImpl::TypedIdentifier> ParserImpl::expect_variable_ident_decl(
-    std::string_view use,
-    bool allow_inferred) {
-  auto ident = expect_ident(use);
-  if (ident.errored)
-    return Failure::kErrored;
+Expect<ParserImpl::TypedIdentifier> ParserImpl::expect_variable_ident_decl(std::string_view use,
+                                                                           bool allow_inferred) {
+    auto ident = expect_ident(use);
+    if (ident.errored)
+        return Failure::kErrored;
 
-  if (allow_inferred && !peek_is(Token::Type::kColon)) {
-    return TypedIdentifier{nullptr, ident.value, ident.source};
-  }
+    if (allow_inferred && !peek_is(Token::Type::kColon)) {
+        return TypedIdentifier{nullptr, ident.value, ident.source};
+    }
 
-  if (!expect(use, Token::Type::kColon))
-    return Failure::kErrored;
+    if (!expect(use, Token::Type::kColon))
+        return Failure::kErrored;
 
-  auto t = peek();
-  auto type = type_decl();
-  if (type.errored)
-    return Failure::kErrored;
-  if (!type.matched)
-    return add_error(t.source(), "invalid type", use);
+    auto t = peek();
+    auto type = type_decl();
+    if (type.errored)
+        return Failure::kErrored;
+    if (!type.matched)
+        return add_error(t.source(), "invalid type", use);
 
-  return TypedIdentifier{type.value, ident.value, ident.source};
+    return TypedIdentifier{type.value, ident.value, ident.source};
 }
 
 Expect<ast::Access> ParserImpl::expect_access(std::string_view use) {
-  auto ident = expect_ident(use);
-  if (ident.errored)
-    return Failure::kErrored;
+    auto ident = expect_ident(use);
+    if (ident.errored)
+        return Failure::kErrored;
 
-  if (ident.value == kReadAccess)
-    return {ast::Access::kRead, ident.source};
-  if (ident.value == kWriteAccess)
-    return {ast::Access::kWrite, ident.source};
-  if (ident.value == kReadWriteAccess)
-    return {ast::Access::kReadWrite, ident.source};
+    if (ident.value == kReadAccess)
+        return {ast::Access::kRead, ident.source};
+    if (ident.value == kWriteAccess)
+        return {ast::Access::kWrite, ident.source};
+    if (ident.value == kReadWriteAccess)
+        return {ast::Access::kReadWrite, ident.source};
 
-  return add_error(ident.source, "invalid value for access control");
+    return add_error(ident.source, "invalid value for access control");
 }
 
 // variable_qualifier
 //   : LESS_THAN storage_class (COMMA access_mode)? GREATER_THAN
 Maybe<ParserImpl::VariableQualifier> ParserImpl::variable_qualifier() {
-  if (!peek_is(Token::Type::kLessThan)) {
-    return Failure::kNoMatch;
-  }
-
-  auto* use = "variable declaration";
-  auto vq = expect_lt_gt_block(use, [&]() -> Expect<VariableQualifier> {
-    auto source = make_source_range();
-    auto sc = expect_storage_class(use);
-    if (sc.errored) {
-      return Failure::kErrored;
+    if (!peek_is(Token::Type::kLessThan)) {
+        return Failure::kNoMatch;
     }
-    if (match(Token::Type::kComma)) {
-      auto ac = expect_access(use);
-      if (ac.errored) {
+
+    auto* use = "variable declaration";
+    auto vq = expect_lt_gt_block(use, [&]() -> Expect<VariableQualifier> {
+        auto source = make_source_range();
+        auto sc = expect_storage_class(use);
+        if (sc.errored) {
+            return Failure::kErrored;
+        }
+        if (match(Token::Type::kComma)) {
+            auto ac = expect_access(use);
+            if (ac.errored) {
+                return Failure::kErrored;
+            }
+            return VariableQualifier{sc.value, ac.value};
+        }
+        return Expect<VariableQualifier>{VariableQualifier{sc.value, ast::Access::kUndefined},
+                                         source};
+    });
+
+    if (vq.errored) {
         return Failure::kErrored;
-      }
-      return VariableQualifier{sc.value, ac.value};
     }
-    return Expect<VariableQualifier>{
-        VariableQualifier{sc.value, ast::Access::kUndefined}, source};
-  });
 
-  if (vq.errored) {
-    return Failure::kErrored;
-  }
-
-  return vq;
+    return vq;
 }
 
 // type_alias
 //   : TYPE IDENT EQUAL type_decl
 Maybe<const ast::Alias*> ParserImpl::type_alias() {
-  if (!peek_is(Token::Type::kType))
-    return Failure::kNoMatch;
+    if (!peek_is(Token::Type::kType))
+        return Failure::kNoMatch;
 
-  auto t = next();
-  const char* use = "type alias";
+    auto t = next();
+    const char* use = "type alias";
 
-  auto name = expect_ident(use);
-  if (name.errored)
-    return Failure::kErrored;
+    auto name = expect_ident(use);
+    if (name.errored)
+        return Failure::kErrored;
 
-  if (!expect(use, Token::Type::kEqual))
-    return Failure::kErrored;
+    if (!expect(use, Token::Type::kEqual))
+        return Failure::kErrored;
 
-  auto type = type_decl();
-  if (type.errored)
-    return Failure::kErrored;
-  if (!type.matched)
-    return add_error(peek(), "invalid type alias");
+    auto type = type_decl();
+    if (type.errored)
+        return Failure::kErrored;
+    if (!type.matched)
+        return add_error(peek(), "invalid type alias");
 
-  return builder_.ty.alias(make_source_range_from(t.source()), name.value,
-                           type.value);
+    return builder_.ty.alias(make_source_range_from(t.source()), name.value, type.value);
 }
 
 // type_decl
@@ -918,198 +965,195 @@
 //   | MAT4x2 LESS_THAN type_decl GREATER_THAN
 //   | MAT4x3 LESS_THAN type_decl GREATER_THAN
 //   | MAT4x4 LESS_THAN type_decl GREATER_THAN
-//   | texture_sampler_types
+//   | texture_samplers
 Maybe<const ast::Type*> ParserImpl::type_decl() {
-  auto t = peek();
-  Source source;
-  if (match(Token::Type::kIdentifier, &source)) {
-    return builder_.create<ast::TypeName>(
-        source, builder_.Symbols().Register(t.to_str()));
-  }
+    auto t = peek();
+    Source source;
+    if (match(Token::Type::kIdentifier, &source)) {
+        return builder_.create<ast::TypeName>(source, builder_.Symbols().Register(t.to_str()));
+    }
 
-  if (match(Token::Type::kBool, &source))
-    return builder_.ty.bool_(source);
+    if (match(Token::Type::kBool, &source))
+        return builder_.ty.bool_(source);
 
-  if (match(Token::Type::kF32, &source))
-    return builder_.ty.f32(source);
+    if (match(Token::Type::kF32, &source))
+        return builder_.ty.f32(source);
 
-  if (match(Token::Type::kI32, &source))
-    return builder_.ty.i32(source);
+    if (match(Token::Type::kI32, &source))
+        return builder_.ty.i32(source);
 
-  if (match(Token::Type::kU32, &source))
-    return builder_.ty.u32(source);
+    if (match(Token::Type::kU32, &source))
+        return builder_.ty.u32(source);
 
-  if (t.IsVector()) {
-    next();  // Consume the peek
-    return expect_type_decl_vector(t);
-  }
+    if (t.IsVector()) {
+        next();  // Consume the peek
+        return expect_type_decl_vector(t);
+    }
 
-  if (match(Token::Type::kPtr)) {
-    return expect_type_decl_pointer(t);
-  }
+    if (match(Token::Type::kPtr)) {
+        return expect_type_decl_pointer(t);
+    }
 
-  if (match(Token::Type::kAtomic)) {
-    return expect_type_decl_atomic(t);
-  }
+    if (match(Token::Type::kAtomic)) {
+        return expect_type_decl_atomic(t);
+    }
 
-  if (match(Token::Type::kArray, &source)) {
-    return expect_type_decl_array(t);
-  }
+    if (match(Token::Type::kArray, &source)) {
+        return expect_type_decl_array(t);
+    }
 
-  if (t.IsMatrix()) {
-    next();  // Consume the peek
-    return expect_type_decl_matrix(t);
-  }
+    if (t.IsMatrix()) {
+        next();  // Consume the peek
+        return expect_type_decl_matrix(t);
+    }
 
-  auto texture_or_sampler = texture_sampler_types();
-  if (texture_or_sampler.errored)
-    return Failure::kErrored;
-  if (texture_or_sampler.matched)
-    return texture_or_sampler;
+    auto texture_or_sampler = texture_samplers();
+    if (texture_or_sampler.errored)
+        return Failure::kErrored;
+    if (texture_or_sampler.matched)
+        return texture_or_sampler;
 
-  return Failure::kNoMatch;
+    return Failure::kNoMatch;
 }
 
 Expect<const ast::Type*> ParserImpl::expect_type(std::string_view use) {
-  auto type = type_decl();
-  if (type.errored)
-    return Failure::kErrored;
-  if (!type.matched)
-    return add_error(peek().source(), "invalid type", use);
-  return type.value;
+    auto type = type_decl();
+    if (type.errored)
+        return Failure::kErrored;
+    if (!type.matched)
+        return add_error(peek().source(), "invalid type", use);
+    return type.value;
 }
 
 Expect<const ast::Type*> ParserImpl::expect_type_decl_pointer(Token t) {
-  const char* use = "ptr declaration";
+    const char* use = "ptr declaration";
 
-  auto storage_class = ast::StorageClass::kNone;
-  auto access = ast::Access::kUndefined;
+    auto storage_class = ast::StorageClass::kNone;
+    auto access = ast::Access::kUndefined;
 
-  auto subtype = expect_lt_gt_block(use, [&]() -> Expect<const ast::Type*> {
-    auto sc = expect_storage_class(use);
-    if (sc.errored) {
-      return Failure::kErrored;
-    }
-    storage_class = sc.value;
+    auto subtype = expect_lt_gt_block(use, [&]() -> Expect<const ast::Type*> {
+        auto sc = expect_storage_class(use);
+        if (sc.errored) {
+            return Failure::kErrored;
+        }
+        storage_class = sc.value;
 
-    if (!expect(use, Token::Type::kComma)) {
-      return Failure::kErrored;
-    }
+        if (!expect(use, Token::Type::kComma)) {
+            return Failure::kErrored;
+        }
 
-    auto type = expect_type(use);
-    if (type.errored) {
-      return Failure::kErrored;
-    }
+        auto type = expect_type(use);
+        if (type.errored) {
+            return Failure::kErrored;
+        }
 
-    if (match(Token::Type::kComma)) {
-      auto ac = expect_access("access control");
-      if (ac.errored) {
+        if (match(Token::Type::kComma)) {
+            auto ac = expect_access("access control");
+            if (ac.errored) {
+                return Failure::kErrored;
+            }
+            access = ac.value;
+        }
+
+        return type.value;
+    });
+
+    if (subtype.errored) {
         return Failure::kErrored;
-      }
-      access = ac.value;
     }
 
-    return type.value;
-  });
-
-  if (subtype.errored) {
-    return Failure::kErrored;
-  }
-
-  return builder_.ty.pointer(make_source_range_from(t.source()), subtype.value,
-                             storage_class, access);
+    return builder_.ty.pointer(make_source_range_from(t.source()), subtype.value, storage_class,
+                               access);
 }
 
 Expect<const ast::Type*> ParserImpl::expect_type_decl_atomic(Token t) {
-  const char* use = "atomic declaration";
+    const char* use = "atomic declaration";
 
-  auto subtype = expect_lt_gt_block(use, [&] { return expect_type(use); });
-  if (subtype.errored) {
-    return Failure::kErrored;
-  }
+    auto subtype = expect_lt_gt_block(use, [&] { return expect_type(use); });
+    if (subtype.errored) {
+        return Failure::kErrored;
+    }
 
-  return builder_.ty.atomic(make_source_range_from(t.source()), subtype.value);
+    return builder_.ty.atomic(make_source_range_from(t.source()), subtype.value);
 }
 
 Expect<const ast::Type*> ParserImpl::expect_type_decl_vector(Token t) {
-  uint32_t count = 2;
-  if (t.Is(Token::Type::kVec3)) {
-    count = 3;
-  } else if (t.Is(Token::Type::kVec4)) {
-    count = 4;
-  }
-
-  const ast::Type* subtype = nullptr;
-  if (peek_is(Token::Type::kLessThan)) {
-    const char* use = "vector";
-    auto ty = expect_lt_gt_block(use, [&] { return expect_type(use); });
-    if (ty.errored) {
-      return Failure::kErrored;
+    uint32_t count = 2;
+    if (t.Is(Token::Type::kVec3)) {
+        count = 3;
+    } else if (t.Is(Token::Type::kVec4)) {
+        count = 4;
     }
-    subtype = ty.value;
-  }
 
-  return builder_.ty.vec(make_source_range_from(t.source()), subtype, count);
+    const ast::Type* subtype = nullptr;
+    if (peek_is(Token::Type::kLessThan)) {
+        const char* use = "vector";
+        auto ty = expect_lt_gt_block(use, [&] { return expect_type(use); });
+        if (ty.errored) {
+            return Failure::kErrored;
+        }
+        subtype = ty.value;
+    }
+
+    return builder_.ty.vec(make_source_range_from(t.source()), subtype, count);
 }
 
 Expect<const ast::Type*> ParserImpl::expect_type_decl_array(Token t) {
-  const char* use = "array declaration";
+    const char* use = "array declaration";
 
-  const ast::Expression* size = nullptr;
+    const ast::Expression* size = nullptr;
 
-  auto subtype = expect_lt_gt_block(use, [&]() -> Expect<const ast::Type*> {
-    auto type = expect_type(use);
-    if (type.errored)
-      return Failure::kErrored;
+    auto subtype = expect_lt_gt_block(use, [&]() -> Expect<const ast::Type*> {
+        auto type = expect_type(use);
+        if (type.errored)
+            return Failure::kErrored;
 
-    if (match(Token::Type::kComma)) {
-      auto expr = primary_expression();
-      if (expr.errored) {
+        if (match(Token::Type::kComma)) {
+            auto expr = primary_expression();
+            if (expr.errored) {
+                return Failure::kErrored;
+            } else if (!expr.matched) {
+                return add_error(peek(), "expected array size expression");
+            }
+
+            size = std::move(expr.value);
+        }
+
+        return type.value;
+    });
+
+    if (subtype.errored) {
         return Failure::kErrored;
-      } else if (!expr.matched) {
-        return add_error(peek(), "expected array size expression");
-      }
-
-      size = std::move(expr.value);
     }
 
-    return type.value;
-  });
-
-  if (subtype.errored) {
-    return Failure::kErrored;
-  }
-
-  return builder_.ty.array(make_source_range_from(t.source()), subtype.value,
-                           size);
+    return builder_.ty.array(make_source_range_from(t.source()), subtype.value, size);
 }
 
 Expect<const ast::Type*> ParserImpl::expect_type_decl_matrix(Token t) {
-  uint32_t rows = 2;
-  uint32_t columns = 2;
-  if (t.IsMat3xN()) {
-    columns = 3;
-  } else if (t.IsMat4xN()) {
-    columns = 4;
-  }
-  if (t.IsMatNx3()) {
-    rows = 3;
-  } else if (t.IsMatNx4()) {
-    rows = 4;
-  }
-
-  const ast::Type* subtype = nullptr;
-  if (peek_is(Token::Type::kLessThan)) {
-    const char* use = "matrix";
-    auto ty = expect_lt_gt_block(use, [&] { return expect_type(use); });
-    if (ty.errored) {
-      return Failure::kErrored;
+    uint32_t rows = 2;
+    uint32_t columns = 2;
+    if (t.IsMat3xN()) {
+        columns = 3;
+    } else if (t.IsMat4xN()) {
+        columns = 4;
     }
-    subtype = ty.value;
-  }
+    if (t.IsMatNx3()) {
+        rows = 3;
+    } else if (t.IsMatNx4()) {
+        rows = 4;
+    }
 
-  return builder_.ty.mat(make_source_range_from(t.source()), subtype, columns,
-                         rows);
+    const ast::Type* subtype = nullptr;
+    if (peek_is(Token::Type::kLessThan)) {
+        const char* use = "matrix";
+        auto ty = expect_lt_gt_block(use, [&] { return expect_type(use); });
+        if (ty.errored) {
+            return Failure::kErrored;
+        }
+        subtype = ty.value;
+    }
+
+    return builder_.ty.mat(make_source_range_from(t.source()), subtype, columns, rows);
 }
 
 // storage_class
@@ -1120,140 +1164,134 @@
 //  | STORAGE
 //  | PRIVATE
 //  | FUNCTION
-Expect<ast::StorageClass> ParserImpl::expect_storage_class(
-    std::string_view use) {
-  auto source = peek().source();
+Expect<ast::StorageClass> ParserImpl::expect_storage_class(std::string_view use) {
+    auto source = peek().source();
 
-  if (match(Token::Type::kUniform))
-    return {ast::StorageClass::kUniform, source};
+    if (match(Token::Type::kUniform))
+        return {ast::StorageClass::kUniform, source};
 
-  if (match(Token::Type::kWorkgroup))
-    return {ast::StorageClass::kWorkgroup, source};
+    if (match(Token::Type::kWorkgroup))
+        return {ast::StorageClass::kWorkgroup, source};
 
-  if (match(Token::Type::kStorage))
-    return {ast::StorageClass::kStorage, source};
+    if (match(Token::Type::kStorage))
+        return {ast::StorageClass::kStorage, source};
 
-  if (match(Token::Type::kPrivate))
-    return {ast::StorageClass::kPrivate, source};
+    if (match(Token::Type::kPrivate))
+        return {ast::StorageClass::kPrivate, source};
 
-  if (match(Token::Type::kFunction))
-    return {ast::StorageClass::kFunction, source};
+    if (match(Token::Type::kFunction))
+        return {ast::StorageClass::kFunction, source};
 
-  return add_error(source, "invalid storage class", use);
+    return add_error(source, "invalid storage class", use);
 }
 
 // struct_decl
 //   : STRUCT IDENT struct_body_decl
 Maybe<const ast::Struct*> ParserImpl::struct_decl() {
-  auto t = peek();
-  auto source = t.source();
+    auto t = peek();
+    auto source = t.source();
 
-  if (!match(Token::Type::kStruct))
-    return Failure::kNoMatch;
+    if (!match(Token::Type::kStruct))
+        return Failure::kNoMatch;
 
-  auto name = expect_ident("struct declaration");
-  if (name.errored)
-    return Failure::kErrored;
+    auto name = expect_ident("struct declaration");
+    if (name.errored)
+        return Failure::kErrored;
 
-  auto body = expect_struct_body_decl();
-  if (body.errored)
-    return Failure::kErrored;
+    auto body = expect_struct_body_decl();
+    if (body.errored)
+        return Failure::kErrored;
 
-  auto sym = builder_.Symbols().Register(name.value);
-  return create<ast::Struct>(source, sym, std::move(body.value),
-                             ast::AttributeList{});
+    auto sym = builder_.Symbols().Register(name.value);
+    return create<ast::Struct>(source, sym, std::move(body.value), ast::AttributeList{});
 }
 
 // struct_body_decl
 //   : BRACE_LEFT (struct_member COMMA)* struct_member COMMA? BRACE_RIGHT
 Expect<ast::StructMemberList> ParserImpl::expect_struct_body_decl() {
-  return expect_brace_block(
-      "struct declaration", [&]() -> Expect<ast::StructMemberList> {
+    return expect_brace_block("struct declaration", [&]() -> Expect<ast::StructMemberList> {
         ast::StructMemberList members;
         bool errored = false;
         while (continue_parsing()) {
-          // Check for the end of the list.
-          auto t = peek();
-          if (!t.IsIdentifier() && !t.Is(Token::Type::kAttr)) {
-            break;
-          }
-
-          auto member = expect_struct_member();
-          if (member.errored) {
-            errored = true;
-            if (!sync_to(Token::Type::kComma, /* consume: */ false)) {
-              return Failure::kErrored;
+            // Check for the end of the list.
+            auto t = peek();
+            if (!t.IsIdentifier() && !t.Is(Token::Type::kAttr)) {
+                break;
             }
-          } else {
-            members.push_back(member.value);
-          }
 
-          // TODO(crbug.com/tint/1475): Remove support for semicolons.
-          if (auto sc = peek(); sc.Is(Token::Type::kSemicolon)) {
-            deprecated(sc.source(),
-                       "struct members should be separated with commas");
-            next();
-            continue;
-          }
-          if (!match(Token::Type::kComma))
-            break;
+            auto member = expect_struct_member();
+            if (member.errored) {
+                errored = true;
+                if (!sync_to(Token::Type::kComma, /* consume: */ false)) {
+                    return Failure::kErrored;
+                }
+            } else {
+                members.push_back(member.value);
+            }
+
+            // TODO(crbug.com/tint/1475): Remove support for semicolons.
+            if (auto sc = peek(); sc.Is(Token::Type::kSemicolon)) {
+                deprecated(sc.source(), "struct members should be separated with commas");
+                next();
+                continue;
+            }
+            if (!match(Token::Type::kComma))
+                break;
         }
         if (errored) {
-          return Failure::kErrored;
+            return Failure::kErrored;
         }
         return members;
-      });
+    });
 }
 
 // struct_member
 //   : attribute* variable_ident_decl
 Expect<ast::StructMember*> ParserImpl::expect_struct_member() {
-  auto attrs = attribute_list();
-  if (attrs.errored) {
-    return Failure::kErrored;
-  }
+    auto attrs = attribute_list();
+    if (attrs.errored) {
+        return Failure::kErrored;
+    }
 
-  auto decl = expect_variable_ident_decl("struct member");
-  if (decl.errored)
-    return Failure::kErrored;
+    auto decl = expect_variable_ident_decl("struct member");
+    if (decl.errored)
+        return Failure::kErrored;
 
-  return create<ast::StructMember>(decl->source,
-                                   builder_.Symbols().Register(decl->name),
-                                   decl->type, std::move(attrs.value));
+    return create<ast::StructMember>(decl->source, builder_.Symbols().Register(decl->name),
+                                     decl->type, std::move(attrs.value));
 }
 
 // function_decl
 //   : function_header body_stmt
-Maybe<const ast::Function*> ParserImpl::function_decl(
-    ast::AttributeList& attrs) {
-  auto header = function_header();
-  if (header.errored) {
-    if (sync_to(Token::Type::kBraceLeft, /* consume: */ false)) {
-      // There were errors in the function header, but the parser has managed to
-      // resynchronize with the opening brace. As there's no outer
-      // synchronization token for function declarations, attempt to parse the
-      // function body. The AST isn't used as we've already errored, but this
-      // catches any errors inside the body, and can help keep the parser in
-      // sync.
-      expect_body_stmt();
+Maybe<const ast::Function*> ParserImpl::function_decl(ast::AttributeList& attrs) {
+    auto header = function_header();
+    if (header.errored) {
+        if (sync_to(Token::Type::kBraceLeft, /* consume: */ false)) {
+            // There were errors in the function header, but the parser has managed to
+            // resynchronize with the opening brace. As there's no outer
+            // synchronization token for function declarations, attempt to parse the
+            // function body. The AST isn't used as we've already errored, but this
+            // catches any errors inside the body, and can help keep the parser in
+            // sync.
+            expect_body_stmt();
+        }
+        return Failure::kErrored;
     }
-    return Failure::kErrored;
-  }
-  if (!header.matched)
-    return Failure::kNoMatch;
+    if (!header.matched)
+        return Failure::kNoMatch;
 
-  bool errored = false;
+    bool errored = false;
 
-  auto body = expect_body_stmt();
-  if (body.errored)
-    errored = true;
+    auto body = expect_body_stmt();
+    if (body.errored)
+        errored = true;
 
-  if (errored)
-    return Failure::kErrored;
+    if (errored)
+        return Failure::kErrored;
 
-  return create<ast::Function>(
-      header->source, builder_.Symbols().Register(header->name), header->params,
-      header->return_type, body.value, attrs, header->return_type_attributes);
+    return create<ast::Function>(header->source, builder_.Symbols().Register(header->name),
+                                 header->params, header->return_type, body.value, attrs,
+                                 header->return_type_attributes);
 }
 
 // function_header
@@ -1262,109 +1300,108 @@
 //   :
 //   | ARROW attribute_list* type_decl
 Maybe<ParserImpl::FunctionHeader> ParserImpl::function_header() {
-  Source source;
-  if (!match(Token::Type::kFn, &source)) {
-    return Failure::kNoMatch;
-  }
-
-  const char* use = "function declaration";
-  bool errored = false;
-
-  auto name = expect_ident(use);
-  if (name.errored) {
-    errored = true;
-    if (!sync_to(Token::Type::kParenLeft, /* consume: */ false)) {
-      return Failure::kErrored;
+    Source source;
+    if (!match(Token::Type::kFn, &source)) {
+        return Failure::kNoMatch;
     }
-  }
 
-  auto params = expect_paren_block(use, [&] { return expect_param_list(); });
-  if (params.errored) {
-    errored = true;
-    if (!synchronized_) {
-      return Failure::kErrored;
+    const char* use = "function declaration";
+    bool errored = false;
+
+    auto name = expect_ident(use);
+    if (name.errored) {
+        errored = true;
+        if (!sync_to(Token::Type::kParenLeft, /* consume: */ false)) {
+            return Failure::kErrored;
+        }
     }
-  }
 
-  const ast::Type* return_type = nullptr;
-  ast::AttributeList return_attributes;
-
-  if (match(Token::Type::kArrow)) {
-    auto attrs = attribute_list();
-    if (attrs.errored) {
-      return Failure::kErrored;
+    auto params = expect_paren_block(use, [&] { return expect_param_list(); });
+    if (params.errored) {
+        errored = true;
+        if (!synchronized_) {
+            return Failure::kErrored;
+        }
     }
-    return_attributes = attrs.value;
 
-    auto type = type_decl();
-    if (type.errored) {
-      errored = true;
-    } else if (!type.matched) {
-      return add_error(peek(), "unable to determine function return type");
+    const ast::Type* return_type = nullptr;
+    ast::AttributeList return_attributes;
+
+    if (match(Token::Type::kArrow)) {
+        auto attrs = attribute_list();
+        if (attrs.errored) {
+            return Failure::kErrored;
+        }
+        return_attributes = attrs.value;
+
+        auto type = type_decl();
+        if (type.errored) {
+            errored = true;
+        } else if (!type.matched) {
+            return add_error(peek(), "unable to determine function return type");
+        } else {
+            return_type = type.value;
+        }
     } else {
-      return_type = type.value;
+        return_type = builder_.ty.void_();
     }
-  } else {
-    return_type = builder_.ty.void_();
-  }
 
-  if (errored) {
-    return Failure::kErrored;
-  }
+    if (errored) {
+        return Failure::kErrored;
+    }
 
-  return FunctionHeader{source, name.value, std::move(params.value),
-                        return_type, std::move(return_attributes)};
+    return FunctionHeader{source, name.value, std::move(params.value), return_type,
+                          std::move(return_attributes)};
 }
 
 // param_list
 //   :
 //   | (param COMMA)* param COMMA?
 Expect<ast::VariableList> ParserImpl::expect_param_list() {
-  ast::VariableList ret;
-  while (continue_parsing()) {
-    // Check for the end of the list.
-    auto t = peek();
-    if (!t.IsIdentifier() && !t.Is(Token::Type::kAttr)) {
-      break;
+    ast::VariableList ret;
+    while (continue_parsing()) {
+        // Check for the end of the list.
+        auto t = peek();
+        if (!t.IsIdentifier() && !t.Is(Token::Type::kAttr)) {
+            break;
+        }
+
+        auto param = expect_param();
+        if (param.errored)
+            return Failure::kErrored;
+        ret.push_back(param.value);
+
+        if (!match(Token::Type::kComma))
+            break;
     }
 
-    auto param = expect_param();
-    if (param.errored)
-      return Failure::kErrored;
-    ret.push_back(param.value);
-
-    if (!match(Token::Type::kComma))
-      break;
-  }
-
-  return ret;
+    return ret;
 }
 
 // param
 //   : attribute_list* variable_ident_decl
 Expect<ast::Variable*> ParserImpl::expect_param() {
-  auto attrs = attribute_list();
+    auto attrs = attribute_list();
 
-  auto decl = expect_variable_ident_decl("parameter");
-  if (decl.errored)
-    return Failure::kErrored;
+    auto decl = expect_variable_ident_decl("parameter");
+    if (decl.errored)
+        return Failure::kErrored;
 
-  auto* var =
-      create<ast::Variable>(decl->source,                             // source
-                            builder_.Symbols().Register(decl->name),  // symbol
-                            ast::StorageClass::kNone,  // storage class
-                            ast::Access::kUndefined,   // access control
-                            decl->type,                // type
-                            true,                      // is_const
-                            false,                     // is_overridable
-                            nullptr,                   // constructor
-                            std::move(attrs.value));   // attributes
-  // Formal parameters are treated like a const declaration where the
-  // initializer value is provided by the call's argument.  The key point is
-  // that it's not updatable after initially set.  This is unlike C or GLSL
-  // which treat formal parameters like local variables that can be updated.
+    auto* var = create<ast::Variable>(decl->source,                             // source
+                                      builder_.Symbols().Register(decl->name),  // symbol
+                                      ast::StorageClass::kNone,                 // storage class
+                                      ast::Access::kUndefined,                  // access control
+                                      decl->type,                               // type
+                                      true,                                     // is_const
+                                      false,                                    // is_overridable
+                                      nullptr,                                  // constructor
+                                      std::move(attrs.value));                  // attributes
+    // Formal parameters are treated like a const declaration where the
+    // initializer value is provided by the call's argument.  The key point is
+    // that it's not updatable after initially set.  This is unlike C or GLSL
+    // which treat formal parameters like local variables that can be updated.
 
-  return var;
+    return var;
 }
 
 // pipeline_stage
@@ -1372,80 +1409,80 @@
 //   | FRAGMENT
 //   | COMPUTE
 Expect<ast::PipelineStage> ParserImpl::expect_pipeline_stage() {
-  auto t = peek();
-  if (t == kVertexStage) {
-    next();  // Consume the peek
-    return {ast::PipelineStage::kVertex, t.source()};
-  }
-  if (t == kFragmentStage) {
-    next();  // Consume the peek
-    return {ast::PipelineStage::kFragment, t.source()};
-  }
-  if (t == kComputeStage) {
-    next();  // Consume the peek
-    return {ast::PipelineStage::kCompute, t.source()};
-  }
-  return add_error(peek(), "invalid value for stage attribute");
+    auto t = peek();
+    if (t == kVertexStage) {
+        next();  // Consume the peek
+        return {ast::PipelineStage::kVertex, t.source()};
+    }
+    if (t == kFragmentStage) {
+        next();  // Consume the peek
+        return {ast::PipelineStage::kFragment, t.source()};
+    }
+    if (t == kComputeStage) {
+        next();  // Consume the peek
+        return {ast::PipelineStage::kCompute, t.source()};
+    }
+    return add_error(peek(), "invalid value for stage attribute");
 }
 
 Expect<ast::Builtin> ParserImpl::expect_builtin() {
-  auto ident = expect_ident("builtin");
-  if (ident.errored)
-    return Failure::kErrored;
+    auto ident = expect_ident("builtin");
+    if (ident.errored)
+        return Failure::kErrored;
 
-  ast::Builtin builtin = ident_to_builtin(ident.value);
-  if (builtin == ast::Builtin::kNone)
-    return add_error(ident.source, "invalid value for builtin attribute");
+    ast::Builtin builtin = ident_to_builtin(ident.value);
+    if (builtin == ast::Builtin::kNone)
+        return add_error(ident.source, "invalid value for builtin attribute");
 
-  return {builtin, ident.source};
+    return {builtin, ident.source};
 }
 
 // body_stmt
 //   : BRACE_LEFT statements BRACE_RIGHT
 Expect<ast::BlockStatement*> ParserImpl::expect_body_stmt() {
-  return expect_brace_block("", [&]() -> Expect<ast::BlockStatement*> {
-    auto stmts = expect_statements();
-    if (stmts.errored)
-      return Failure::kErrored;
-    return create<ast::BlockStatement>(Source{}, stmts.value);
-  });
+    return expect_brace_block("", [&]() -> Expect<ast::BlockStatement*> {
+        auto stmts = expect_statements();
+        if (stmts.errored)
+            return Failure::kErrored;
+        return create<ast::BlockStatement>(Source{}, stmts.value);
+    });
 }
 
 // paren_rhs_stmt
 //   : PAREN_LEFT logical_or_expression PAREN_RIGHT
 Expect<const ast::Expression*> ParserImpl::expect_paren_rhs_stmt() {
-  return expect_paren_block("", [&]() -> Expect<const ast::Expression*> {
-    auto expr = logical_or_expression();
-    if (expr.errored)
-      return Failure::kErrored;
-    if (!expr.matched)
-      return add_error(peek(), "unable to parse expression");
+    return expect_paren_block("", [&]() -> Expect<const ast::Expression*> {
+        auto expr = logical_or_expression();
+        if (expr.errored)
+            return Failure::kErrored;
+        if (!expr.matched)
+            return add_error(peek(), "unable to parse expression");
 
-    return expr.value;
-  });
+        return expr.value;
+    });
 }
 
 // statements
 //   : statement*
 Expect<ast::StatementList> ParserImpl::expect_statements() {
-  bool errored = false;
-  ast::StatementList stmts;
+    bool errored = false;
+    ast::StatementList stmts;
 
-  while (continue_parsing()) {
-    auto stmt = statement();
-    if (stmt.errored) {
-      errored = true;
-    } else if (stmt.matched) {
-      stmts.emplace_back(stmt.value);
-    } else {
-      break;
+    while (continue_parsing()) {
+        auto stmt = statement();
+        if (stmt.errored) {
+            errored = true;
+        } else if (stmt.matched) {
+            stmts.emplace_back(stmt.value);
+        } else {
+            break;
+        }
     }
-  }
 
-  if (errored)
-    return Failure::kErrored;
+    if (errored)
+        return Failure::kErrored;
 
-  return stmts;
+    return stmts;
 }
 
 // statement
@@ -1466,51 +1503,50 @@
 //      | increment_stmt SEMICOLON
 //      | decrement_stmt SEMICOLON
 Maybe<const ast::Statement*> ParserImpl::statement() {
-  while (match(Token::Type::kSemicolon)) {
-    // Skip empty statements
-  }
+    while (match(Token::Type::kSemicolon)) {
+        // Skip empty statements
+    }
 
-  // Non-block statments that error can resynchronize on semicolon.
-  auto stmt =
-      sync(Token::Type::kSemicolon, [&] { return non_block_statement(); });
+    // Non-block statments that error can resynchronize on semicolon.
+    auto stmt = sync(Token::Type::kSemicolon, [&] { return non_block_statement(); });
 
-  if (stmt.errored)
-    return Failure::kErrored;
-  if (stmt.matched)
-    return stmt;
+    if (stmt.errored)
+        return Failure::kErrored;
+    if (stmt.matched)
+        return stmt;
 
-  auto stmt_if = if_stmt();
-  if (stmt_if.errored)
-    return Failure::kErrored;
-  if (stmt_if.matched)
-    return stmt_if.value;
+    auto stmt_if = if_stmt();
+    if (stmt_if.errored)
+        return Failure::kErrored;
+    if (stmt_if.matched)
+        return stmt_if.value;
 
-  auto sw = switch_stmt();
-  if (sw.errored)
-    return Failure::kErrored;
-  if (sw.matched)
-    return sw.value;
+    auto sw = switch_stmt();
+    if (sw.errored)
+        return Failure::kErrored;
+    if (sw.matched)
+        return sw.value;
 
-  auto loop = loop_stmt();
-  if (loop.errored)
-    return Failure::kErrored;
-  if (loop.matched)
-    return loop.value;
+    auto loop = loop_stmt();
+    if (loop.errored)
+        return Failure::kErrored;
+    if (loop.matched)
+        return loop.value;
 
-  auto stmt_for = for_stmt();
-  if (stmt_for.errored)
-    return Failure::kErrored;
-  if (stmt_for.matched)
-    return stmt_for.value;
+    auto stmt_for = for_stmt();
+    if (stmt_for.errored)
+        return Failure::kErrored;
+    if (stmt_for.matched)
+        return stmt_for.value;
 
-  if (peek_is(Token::Type::kBraceLeft)) {
-    auto body = expect_body_stmt();
-    if (body.errored)
-      return Failure::kErrored;
-    return body.value;
-  }
+    if (peek_is(Token::Type::kBraceLeft)) {
+        auto body = expect_body_stmt();
+        if (body.errored)
+            return Failure::kErrored;
+        return body.value;
+    }
 
-  return Failure::kNoMatch;
+    return Failure::kNoMatch;
 }
 
 // statement (continued)
@@ -1524,72 +1560,72 @@
 //   | increment_stmt SEMICOLON
 //   | decrement_stmt SEMICOLON
 Maybe<const ast::Statement*> ParserImpl::non_block_statement() {
-  auto stmt = [&]() -> Maybe<const ast::Statement*> {
-    auto ret_stmt = return_stmt();
-    if (ret_stmt.errored)
-      return Failure::kErrored;
-    if (ret_stmt.matched)
-      return ret_stmt.value;
+    auto stmt = [&]() -> Maybe<const ast::Statement*> {
+        auto ret_stmt = return_stmt();
+        if (ret_stmt.errored)
+            return Failure::kErrored;
+        if (ret_stmt.matched)
+            return ret_stmt.value;
 
-    auto func = func_call_stmt();
-    if (func.errored)
-      return Failure::kErrored;
-    if (func.matched)
-      return func.value;
+        auto func = func_call_stmt();
+        if (func.errored)
+            return Failure::kErrored;
+        if (func.matched)
+            return func.value;
 
-    auto var = variable_stmt();
-    if (var.errored)
-      return Failure::kErrored;
-    if (var.matched)
-      return var.value;
+        auto var = variable_stmt();
+        if (var.errored)
+            return Failure::kErrored;
+        if (var.matched)
+            return var.value;
 
-    auto b = break_stmt();
-    if (b.errored)
-      return Failure::kErrored;
-    if (b.matched)
-      return b.value;
+        auto b = break_stmt();
+        if (b.errored)
+            return Failure::kErrored;
+        if (b.matched)
+            return b.value;
 
-    auto cont = continue_stmt();
-    if (cont.errored)
-      return Failure::kErrored;
-    if (cont.matched)
-      return cont.value;
+        auto cont = continue_stmt();
+        if (cont.errored)
+            return Failure::kErrored;
+        if (cont.matched)
+            return cont.value;
 
-    auto assign = assignment_stmt();
-    if (assign.errored)
-      return Failure::kErrored;
-    if (assign.matched)
-      return assign.value;
+        auto assign = assignment_stmt();
+        if (assign.errored)
+            return Failure::kErrored;
+        if (assign.matched)
+            return assign.value;
 
-    Source source;
-    if (match(Token::Type::kDiscard, &source))
-      return create<ast::DiscardStatement>(source);
+        Source source;
+        if (match(Token::Type::kDiscard, &source))
+            return create<ast::DiscardStatement>(source);
 
-    return Failure::kNoMatch;
-  }();
+        return Failure::kNoMatch;
+    }();
 
-  if (stmt.matched && !expect(stmt->Name(), Token::Type::kSemicolon))
-    return Failure::kErrored;
+    if (stmt.matched && !expect(stmt->Name(), Token::Type::kSemicolon))
+        return Failure::kErrored;
 
-  return stmt;
+    return stmt;
 }
 
 // return_stmt
 //   : RETURN logical_or_expression?
 Maybe<const ast::ReturnStatement*> ParserImpl::return_stmt() {
-  Source source;
-  if (!match(Token::Type::kReturn, &source))
-    return Failure::kNoMatch;
+    Source source;
+    if (!match(Token::Type::kReturn, &source))
+        return Failure::kNoMatch;
 
-  if (peek_is(Token::Type::kSemicolon))
-    return create<ast::ReturnStatement>(source, nullptr);
+    if (peek_is(Token::Type::kSemicolon))
+        return create<ast::ReturnStatement>(source, nullptr);
 
-  auto expr = logical_or_expression();
-  if (expr.errored)
-    return Failure::kErrored;
+    auto expr = logical_or_expression();
+    if (expr.errored)
+        return Failure::kErrored;
 
-  // TODO(bclayton): Check matched?
-  return create<ast::ReturnStatement>(source, expr.value);
+    // TODO(bclayton): Check matched?
+    return create<ast::ReturnStatement>(source, expr.value);
 }
 
 // variable_stmt
@@ -1597,232 +1633,243 @@
 //   | variable_decl EQUAL logical_or_expression
 //   | CONST variable_ident_decl EQUAL logical_or_expression
 Maybe<const ast::VariableDeclStatement*> ParserImpl::variable_stmt() {
-  if (match(Token::Type::kLet)) {
-    auto decl = expect_variable_ident_decl("let declaration",
-                                           /*allow_inferred = */ true);
+    if (match(Token::Type::kLet)) {
+        auto decl = expect_variable_ident_decl("let declaration",
+                                               /*allow_inferred = */ true);
+        if (decl.errored)
+            return Failure::kErrored;
+
+        if (!expect("let declaration", Token::Type::kEqual))
+            return Failure::kErrored;
+
+        auto constructor = logical_or_expression();
+        if (constructor.errored)
+            return Failure::kErrored;
+        if (!constructor.matched)
+            return add_error(peek(), "missing constructor for let declaration");
+
+        auto* var = create<ast::Variable>(decl->source,                             // source
+                                          builder_.Symbols().Register(decl->name),  // symbol
+                                          ast::StorageClass::kNone,                 // storage class
+                                          ast::Access::kUndefined,  // access control
+                                          decl->type,               // type
+                                          true,                     // is_const
+                                          false,                    // is_overridable
+                                          constructor.value,        // constructor
+                                          ast::AttributeList{});    // attributes
+
+        return create<ast::VariableDeclStatement>(decl->source, var);
+    }
+
+    auto decl = variable_decl(/*allow_inferred = */ true);
     if (decl.errored)
-      return Failure::kErrored;
+        return Failure::kErrored;
+    if (!decl.matched)
+        return Failure::kNoMatch;
 
-    if (!expect("let declaration", Token::Type::kEqual))
-      return Failure::kErrored;
+    const ast::Expression* constructor = nullptr;
+    if (match(Token::Type::kEqual)) {
+        auto constructor_expr = logical_or_expression();
+        if (constructor_expr.errored)
+            return Failure::kErrored;
+        if (!constructor_expr.matched)
+            return add_error(peek(), "missing constructor for variable declaration");
 
-    auto constructor = logical_or_expression();
-    if (constructor.errored)
-      return Failure::kErrored;
-    if (!constructor.matched)
-      return add_error(peek(), "missing constructor for let declaration");
+        constructor = constructor_expr.value;
+    }
 
-    auto* var = create<ast::Variable>(
-        decl->source,                             // source
-        builder_.Symbols().Register(decl->name),  // symbol
-        ast::StorageClass::kNone,                 // storage class
-        ast::Access::kUndefined,                  // access control
-        decl->type,                               // type
-        true,                                     // is_const
-        false,                                    // is_overridable
-        constructor.value,                        // constructor
-        ast::AttributeList{});                    // attributes
+    auto* var = create<ast::Variable>(decl->source,                             // source
+                                      builder_.Symbols().Register(decl->name),  // symbol
+                                      decl->storage_class,                      // storage class
+                                      decl->access,                             // access control
+                                      decl->type,                               // type
+                                      false,                                    // is_const
+                                      false,                                    // is_overridable
+                                      constructor,                              // constructor
+                                      ast::AttributeList{});                    // attributes
 
-    return create<ast::VariableDeclStatement>(decl->source, var);
-  }
-
-  auto decl = variable_decl(/*allow_inferred = */ true);
-  if (decl.errored)
-    return Failure::kErrored;
-  if (!decl.matched)
-    return Failure::kNoMatch;
-
-  const ast::Expression* constructor = nullptr;
-  if (match(Token::Type::kEqual)) {
-    auto constructor_expr = logical_or_expression();
-    if (constructor_expr.errored)
-      return Failure::kErrored;
-    if (!constructor_expr.matched)
-      return add_error(peek(), "missing constructor for variable declaration");
-
-    constructor = constructor_expr.value;
-  }
-
-  auto* var =
-      create<ast::Variable>(decl->source,                             // source
-                            builder_.Symbols().Register(decl->name),  // symbol
-                            decl->storage_class,    // storage class
-                            decl->access,           // access control
-                            decl->type,             // type
-                            false,                  // is_const
-                            false,                  // is_overridable
-                            constructor,            // constructor
-                            ast::AttributeList{});  // attributes
-
-  return create<ast::VariableDeclStatement>(var->source, var);
+    return create<ast::VariableDeclStatement>(var->source, var);
 }
 
 // if_stmt
-//   : IF expression compound_stmt ( ELSE else_stmts ) ?
-Maybe<const ast::IfStatement*> ParserImpl::if_stmt() {
-  Source source;
-  if (!match(Token::Type::kIf, &source))
-    return Failure::kNoMatch;
-
-  auto condition = logical_or_expression();
-  if (condition.errored)
-    return Failure::kErrored;
-  if (!condition.matched) {
-    return add_error(peek(), "unable to parse condition expression");
-  }
-
-  auto body = expect_body_stmt();
-  if (body.errored)
-    return Failure::kErrored;
-
-  auto el = else_stmts();
-  if (el.errored) {
-    return Failure::kErrored;
-  }
-
-  return create<ast::IfStatement>(source, condition.value, body.value,
-                                  std::move(el.value));
-}
-
-// else_stmts
+//   : IF expression compound_stmt ( ELSE else_stmt ) ?
+// else_stmt
 //  : body_stmt
 //  | if_stmt
-Expect<ast::ElseStatementList> ParserImpl::else_stmts() {
-  ast::ElseStatementList stmts;
-  while (continue_parsing()) {
-    Source start;
+Maybe<const ast::IfStatement*> ParserImpl::if_stmt() {
+    // Parse if-else chains iteratively instead of recursively, to avoid
+    // stack-overflow for long chains of if-else statements.
 
-    bool else_if = false;
-    if (match(Token::Type::kElse, &start)) {
-      else_if = match(Token::Type::kIf);
-    } else {
-      break;
-    }
+    struct IfInfo {
+        Source source;
+        const ast::Expression* condition;
+        const ast::BlockStatement* body;
+    };
 
-    const ast::Expression* cond = nullptr;
-    if (else_if) {
-      auto condition = logical_or_expression();
-      if (condition.errored) {
+    // Parse an if statement, capturing the source, condition, and body statement.
+    auto parse_if = [&]() -> Maybe<IfInfo> {
+        Source source;
+        if (!match(Token::Type::kIf, &source)) {
+            return Failure::kNoMatch;
+        }
+
+        auto condition = logical_or_expression();
+        if (condition.errored) {
+            return Failure::kErrored;
+        }
+        if (!condition.matched) {
+            return add_error(peek(), "unable to parse condition expression");
+        }
+
+        auto body = expect_body_stmt();
+        if (body.errored) {
+            return Failure::kErrored;
+        }
+
+        return IfInfo{source, condition.value, body.value};
+    };
+
+    std::vector<IfInfo> statements;
+
+    // Parse the first if statement.
+    auto first_if = parse_if();
+    if (first_if.errored) {
         return Failure::kErrored;
-      }
-      if (!condition.matched) {
-        return add_error(peek(), "unable to parse condition expression");
-      }
+    } else if (!first_if.matched) {
+        return Failure::kNoMatch;
+    }
+    statements.push_back(first_if.value);
 
-      cond = condition.value;
+    // Parse the components of every "else {if}" in the chain.
+    const ast::Statement* last_stmt = nullptr;
+    while (continue_parsing()) {
+        if (!match(Token::Type::kElse)) {
+            break;
+        }
+
+        // Try to parse an "else if".
+        auto else_if = parse_if();
+        if (else_if.errored) {
+            return Failure::kErrored;
+        } else if (else_if.matched) {
+            statements.push_back(else_if.value);
+            continue;
+        }
+
+        // If it wasn't an "else if", it must just be an "else".
+        auto else_body = expect_body_stmt();
+        if (else_body.errored) {
+            return Failure::kErrored;
+        }
+        last_stmt = else_body.value;
+        break;
     }
 
-    auto body = expect_body_stmt();
-    if (body.errored) {
-      return Failure::kErrored;
+    // Now walk back through the statements to create their AST nodes.
+    for (auto itr = statements.rbegin(); itr != statements.rend(); itr++) {
+        last_stmt = create<ast::IfStatement>(itr->source, itr->condition, itr->body, last_stmt);
     }
 
-    Source source = make_source_range_from(start);
-    stmts.emplace_back(create<ast::ElseStatement>(source, cond, body.value));
-  }
-
-  return stmts;
+    return last_stmt->As<ast::IfStatement>();
 }
 
 // switch_stmt
 //   : SWITCH paren_rhs_stmt BRACKET_LEFT switch_body+ BRACKET_RIGHT
 Maybe<const ast::SwitchStatement*> ParserImpl::switch_stmt() {
-  Source source;
-  if (!match(Token::Type::kSwitch, &source))
-    return Failure::kNoMatch;
+    Source source;
+    if (!match(Token::Type::kSwitch, &source))
+        return Failure::kNoMatch;
 
-  auto condition = logical_or_expression();
-  if (condition.errored)
-    return Failure::kErrored;
-  if (!condition.matched) {
-    return add_error(peek(), "unable to parse selector expression");
-  }
+    auto condition = logical_or_expression();
+    if (condition.errored)
+        return Failure::kErrored;
+    if (!condition.matched) {
+        return add_error(peek(), "unable to parse selector expression");
+    }
 
-  auto body = expect_brace_block("switch statement",
-                                 [&]() -> Expect<ast::CaseStatementList> {
-                                   bool errored = false;
-                                   ast::CaseStatementList list;
-                                   while (continue_parsing()) {
-                                     auto stmt = switch_body();
-                                     if (stmt.errored) {
-                                       errored = true;
-                                       continue;
-                                     }
-                                     if (!stmt.matched)
-                                       break;
-                                     list.push_back(stmt.value);
-                                   }
-                                   if (errored)
-                                     return Failure::kErrored;
-                                   return list;
-                                 });
+    auto body = expect_brace_block("switch statement", [&]() -> Expect<ast::CaseStatementList> {
+        bool errored = false;
+        ast::CaseStatementList list;
+        while (continue_parsing()) {
+            auto stmt = switch_body();
+            if (stmt.errored) {
+                errored = true;
+                continue;
+            }
+            if (!stmt.matched)
+                break;
+            list.push_back(stmt.value);
+        }
+        if (errored)
+            return Failure::kErrored;
+        return list;
+    });
 
-  if (body.errored)
-    return Failure::kErrored;
+    if (body.errored)
+        return Failure::kErrored;
 
-  return create<ast::SwitchStatement>(source, condition.value, body.value);
+    return create<ast::SwitchStatement>(source, condition.value, body.value);
 }
 
 // switch_body
 //   : CASE case_selectors COLON? BRACKET_LEFT case_body BRACKET_RIGHT
 //   | DEFAULT COLON? BRACKET_LEFT case_body BRACKET_RIGHT
 Maybe<const ast::CaseStatement*> ParserImpl::switch_body() {
-  if (!peek_is(Token::Type::kCase) && !peek_is(Token::Type::kDefault))
-    return Failure::kNoMatch;
+    if (!peek_is(Token::Type::kCase) && !peek_is(Token::Type::kDefault))
+        return Failure::kNoMatch;
 
-  auto t = next();
-  auto source = t.source();
+    auto t = next();
+    auto source = t.source();
 
-  ast::CaseSelectorList selector_list;
-  if (t.Is(Token::Type::kCase)) {
-    auto selectors = expect_case_selectors();
-    if (selectors.errored)
-      return Failure::kErrored;
+    ast::CaseSelectorList selector_list;
+    if (t.Is(Token::Type::kCase)) {
+        auto selectors = expect_case_selectors();
+        if (selectors.errored)
+            return Failure::kErrored;
 
-    selector_list = std::move(selectors.value);
-  }
+        selector_list = std::move(selectors.value);
+    }
 
-  // Consume the optional colon if present.
-  match(Token::Type::kColon);
+    // Consume the optional colon if present.
+    match(Token::Type::kColon);
 
-  const char* use = "case statement";
-  auto body = expect_brace_block(use, [&] { return case_body(); });
+    const char* use = "case statement";
+    auto body = expect_brace_block(use, [&] { return case_body(); });
 
-  if (body.errored)
-    return Failure::kErrored;
-  if (!body.matched)
-    return add_error(body.source, "expected case body");
+    if (body.errored)
+        return Failure::kErrored;
+    if (!body.matched)
+        return add_error(body.source, "expected case body");
 
-  return create<ast::CaseStatement>(source, selector_list, body.value);
+    return create<ast::CaseStatement>(source, selector_list, body.value);
 }
 
 // case_selectors
 //   : const_literal (COMMA const_literal)* COMMA?
 Expect<ast::CaseSelectorList> ParserImpl::expect_case_selectors() {
-  ast::CaseSelectorList selectors;
+    ast::CaseSelectorList selectors;
 
-  while (continue_parsing()) {
-    auto cond = const_literal();
-    if (cond.errored) {
-      return Failure::kErrored;
-    } else if (!cond.matched) {
-      break;
-    } else if (!cond->Is<ast::IntLiteralExpression>()) {
-      return add_error(cond.value->source,
-                       "invalid case selector must be an integer value");
+    while (continue_parsing()) {
+        auto cond = const_literal();
+        if (cond.errored) {
+            return Failure::kErrored;
+        } else if (!cond.matched) {
+            break;
+        } else if (!cond->Is<ast::IntLiteralExpression>()) {
+            return add_error(cond.value->source, "invalid case selector must be an integer value");
+        }
+
+        selectors.push_back(cond.value->As<ast::IntLiteralExpression>());
+
+        if (!match(Token::Type::kComma)) {
+            break;
+        }
     }
 
-    selectors.push_back(cond.value->As<ast::IntLiteralExpression>());
+    if (selectors.empty())
+        return add_error(peek(), "unable to parse case selectors");
 
-    if (!match(Token::Type::kComma)) {
-      break;
-    }
-  }
-
-  if (selectors.empty())
-    return add_error(peek(), "unable to parse case selectors");
-
-  return selectors;
+    return selectors;
 }
 
 // case_body
@@ -1830,48 +1877,48 @@
 //   | statement case_body
 //   | FALLTHROUGH SEMICOLON
 Maybe<const ast::BlockStatement*> ParserImpl::case_body() {
-  ast::StatementList stmts;
-  while (continue_parsing()) {
-    Source source;
-    if (match(Token::Type::kFallthrough, &source)) {
-      if (!expect("fallthrough statement", Token::Type::kSemicolon))
-        return Failure::kErrored;
+    ast::StatementList stmts;
+    while (continue_parsing()) {
+        Source source;
+        if (match(Token::Type::kFallthrough, &source)) {
+            if (!expect("fallthrough statement", Token::Type::kSemicolon))
+                return Failure::kErrored;
 
-      stmts.emplace_back(create<ast::FallthroughStatement>(source));
-      break;
+            stmts.emplace_back(create<ast::FallthroughStatement>(source));
+            break;
+        }
+
+        auto stmt = statement();
+        if (stmt.errored)
+            return Failure::kErrored;
+        if (!stmt.matched)
+            break;
+
+        stmts.emplace_back(stmt.value);
     }
 
-    auto stmt = statement();
-    if (stmt.errored)
-      return Failure::kErrored;
-    if (!stmt.matched)
-      break;
-
-    stmts.emplace_back(stmt.value);
-  }
-
-  return create<ast::BlockStatement>(Source{}, stmts);
+    return create<ast::BlockStatement>(Source{}, stmts);
 }
 
 // loop_stmt
 //   : LOOP BRACKET_LEFT statements continuing_stmt? BRACKET_RIGHT
 Maybe<const ast::LoopStatement*> ParserImpl::loop_stmt() {
-  Source source;
-  if (!match(Token::Type::kLoop, &source))
-    return Failure::kNoMatch;
+    Source source;
+    if (!match(Token::Type::kLoop, &source))
+        return Failure::kNoMatch;
 
-  return expect_brace_block("loop", [&]() -> Maybe<const ast::LoopStatement*> {
-    auto stmts = expect_statements();
-    if (stmts.errored)
-      return Failure::kErrored;
+    return expect_brace_block("loop", [&]() -> Maybe<const ast::LoopStatement*> {
+        auto stmts = expect_statements();
+        if (stmts.errored)
+            return Failure::kErrored;
 
-    auto continuing = continuing_stmt();
-    if (continuing.errored)
-      return Failure::kErrored;
+        auto continuing = continuing_stmt();
+        if (continuing.errored)
+            return Failure::kErrored;
 
-    auto* body = create<ast::BlockStatement>(source, stmts.value);
-    return create<ast::LoopStatement>(source, body, continuing.value);
-  });
+        auto* body = create<ast::BlockStatement>(source, stmts.value);
+        return create<ast::LoopStatement>(source, body, continuing.value);
+    });
 }
 
 ForHeader::ForHeader(const ast::Statement* init,
@@ -1884,42 +1931,42 @@
 // (variable_stmt | increment_stmt | decrement_stmt | assignment_stmt |
 // func_call_stmt)?
 Maybe<const ast::Statement*> ParserImpl::for_header_initializer() {
-  auto call = func_call_stmt();
-  if (call.errored)
-    return Failure::kErrored;
-  if (call.matched)
-    return call.value;
+    auto call = func_call_stmt();
+    if (call.errored)
+        return Failure::kErrored;
+    if (call.matched)
+        return call.value;
 
-  auto var = variable_stmt();
-  if (var.errored)
-    return Failure::kErrored;
-  if (var.matched)
-    return var.value;
+    auto var = variable_stmt();
+    if (var.errored)
+        return Failure::kErrored;
+    if (var.matched)
+        return var.value;
 
-  auto assign = assignment_stmt();
-  if (assign.errored)
-    return Failure::kErrored;
-  if (assign.matched)
-    return assign.value;
+    auto assign = assignment_stmt();
+    if (assign.errored)
+        return Failure::kErrored;
+    if (assign.matched)
+        return assign.value;
 
-  return Failure::kNoMatch;
+    return Failure::kNoMatch;
 }
 
 // (increment_stmt | decrement_stmt | assignment_stmt | func_call_stmt)?
 Maybe<const ast::Statement*> ParserImpl::for_header_continuing() {
-  auto call_stmt = func_call_stmt();
-  if (call_stmt.errored)
-    return Failure::kErrored;
-  if (call_stmt.matched)
-    return call_stmt.value;
+    auto call_stmt = func_call_stmt();
+    if (call_stmt.errored)
+        return Failure::kErrored;
+    if (call_stmt.matched)
+        return call_stmt.value;
 
-  auto assign = assignment_stmt();
-  if (assign.errored)
-    return Failure::kErrored;
-  if (assign.matched)
-    return assign.value;
+    auto assign = assignment_stmt();
+    if (assign.errored)
+        return Failure::kErrored;
+    if (assign.matched)
+        return assign.value;
 
-  return Failure::kNoMatch;
+    return Failure::kNoMatch;
 }
 
 // for_header
@@ -1928,102 +1975,98 @@
 //      logical_or_expression? SEMICOLON
 //      (assignment_stmt | func_call_stmt)?
 Expect<std::unique_ptr<ForHeader>> ParserImpl::expect_for_header() {
-  auto initializer = for_header_initializer();
-  if (initializer.errored)
-    return Failure::kErrored;
+    auto initializer = for_header_initializer();
+    if (initializer.errored)
+        return Failure::kErrored;
 
-  if (!expect("initializer in for loop", Token::Type::kSemicolon))
-    return Failure::kErrored;
+    if (!expect("initializer in for loop", Token::Type::kSemicolon))
+        return Failure::kErrored;
 
-  auto condition = logical_or_expression();
-  if (condition.errored)
-    return Failure::kErrored;
+    auto condition = logical_or_expression();
+    if (condition.errored)
+        return Failure::kErrored;
 
-  if (!expect("condition in for loop", Token::Type::kSemicolon))
-    return Failure::kErrored;
+    if (!expect("condition in for loop", Token::Type::kSemicolon))
+        return Failure::kErrored;
 
-  auto continuing = for_header_continuing();
-  if (continuing.errored)
-    return Failure::kErrored;
+    auto continuing = for_header_continuing();
+    if (continuing.errored)
+        return Failure::kErrored;
 
-  return std::make_unique<ForHeader>(initializer.value, condition.value,
-                                     continuing.value);
+    return std::make_unique<ForHeader>(initializer.value, condition.value, continuing.value);
 }
 
 // for_statement
 //   : FOR PAREN_LEFT for_header PAREN_RIGHT BRACE_LEFT statements BRACE_RIGHT
 Maybe<const ast::ForLoopStatement*> ParserImpl::for_stmt() {
-  Source source;
-  if (!match(Token::Type::kFor, &source))
-    return Failure::kNoMatch;
+    Source source;
+    if (!match(Token::Type::kFor, &source))
+        return Failure::kNoMatch;
 
-  auto header =
-      expect_paren_block("for loop", [&] { return expect_for_header(); });
-  if (header.errored)
-    return Failure::kErrored;
+    auto header = expect_paren_block("for loop", [&] { return expect_for_header(); });
+    if (header.errored)
+        return Failure::kErrored;
 
-  auto stmts =
-      expect_brace_block("for loop", [&] { return expect_statements(); });
-  if (stmts.errored)
-    return Failure::kErrored;
+    auto stmts = expect_brace_block("for loop", [&] { return expect_statements(); });
+    if (stmts.errored)
+        return Failure::kErrored;
 
-  return create<ast::ForLoopStatement>(
-      source, header->initializer, header->condition, header->continuing,
-      create<ast::BlockStatement>(stmts.value));
+    return create<ast::ForLoopStatement>(source, header->initializer, header->condition,
+                                         header->continuing,
+                                         create<ast::BlockStatement>(stmts.value));
 }
 
 // func_call_stmt
 //    : IDENT argument_expression_list
 Maybe<const ast::CallStatement*> ParserImpl::func_call_stmt() {
-  auto t = peek();
-  auto t2 = peek(1);
-  if (!t.IsIdentifier() || !t2.Is(Token::Type::kParenLeft))
-    return Failure::kNoMatch;
+    auto t = peek();
+    auto t2 = peek(1);
+    if (!t.IsIdentifier() || !t2.Is(Token::Type::kParenLeft))
+        return Failure::kNoMatch;
 
-  next();  // Consume the first peek
+    next();  // Consume the first peek
 
-  auto source = t.source();
-  auto name = t.to_str();
+    auto source = t.source();
+    auto name = t.to_str();
 
-  auto params = expect_argument_expression_list("function call");
-  if (params.errored)
-    return Failure::kErrored;
+    auto params = expect_argument_expression_list("function call");
+    if (params.errored)
+        return Failure::kErrored;
 
-  return create<ast::CallStatement>(
-      source, create<ast::CallExpression>(
-                  source,
-                  create<ast::IdentifierExpression>(
-                      source, builder_.Symbols().Register(name)),
-                  std::move(params.value)));
+    return create<ast::CallStatement>(
+        source,
+        create<ast::CallExpression>(
+            source, create<ast::IdentifierExpression>(source, builder_.Symbols().Register(name)),
+            std::move(params.value)));
 }
 
 // break_stmt
 //   : BREAK
 Maybe<const ast::BreakStatement*> ParserImpl::break_stmt() {
-  Source source;
-  if (!match(Token::Type::kBreak, &source))
-    return Failure::kNoMatch;
+    Source source;
+    if (!match(Token::Type::kBreak, &source))
+        return Failure::kNoMatch;
 
-  return create<ast::BreakStatement>(source);
+    return create<ast::BreakStatement>(source);
 }
 
 // continue_stmt
 //   : CONTINUE
 Maybe<const ast::ContinueStatement*> ParserImpl::continue_stmt() {
-  Source source;
-  if (!match(Token::Type::kContinue, &source))
-    return Failure::kNoMatch;
+    Source source;
+    if (!match(Token::Type::kContinue, &source))
+        return Failure::kNoMatch;
 
-  return create<ast::ContinueStatement>(source);
+    return create<ast::ContinueStatement>(source);
 }
 
 // continuing_stmt
 //   : CONTINUING body_stmt
 Maybe<const ast::BlockStatement*> ParserImpl::continuing_stmt() {
-  if (!match(Token::Type::kContinuing))
-    return create<ast::BlockStatement>(Source{}, ast::StatementList{});
+    if (!match(Token::Type::kContinuing))
+        return create<ast::BlockStatement>(Source{}, ast::StatementList{});
 
-  return expect_body_stmt();
+    return expect_body_stmt();
 }
 
 // primary_expression
@@ -2033,159 +2076,154 @@
 //   | paren_rhs_stmt
 //   | BITCAST LESS_THAN type_decl GREATER_THAN paren_rhs_stmt
 Maybe<const ast::Expression*> ParserImpl::primary_expression() {
-  auto t = peek();
-  auto source = t.source();
+    auto t = peek();
+    auto source = t.source();
 
-  auto lit = const_literal();
-  if (lit.errored) {
-    return Failure::kErrored;
-  }
-  if (lit.matched) {
-    return lit.value;
-  }
-
-  if (t.Is(Token::Type::kParenLeft)) {
-    auto paren = expect_paren_rhs_stmt();
-    if (paren.errored) {
-      return Failure::kErrored;
-    }
-
-    return paren.value;
-  }
-
-  if (match(Token::Type::kBitcast)) {
-    const char* use = "bitcast expression";
-
-    auto type = expect_lt_gt_block(use, [&] { return expect_type(use); });
-    if (type.errored)
-      return Failure::kErrored;
-
-    auto params = expect_paren_rhs_stmt();
-    if (params.errored)
-      return Failure::kErrored;
-
-    return create<ast::BitcastExpression>(source, type.value, params.value);
-  }
-
-  if (t.IsIdentifier()) {
-    next();
-
-    auto* ident = create<ast::IdentifierExpression>(
-        t.source(), builder_.Symbols().Register(t.to_str()));
-
-    if (peek_is(Token::Type::kParenLeft)) {
-      auto params = expect_argument_expression_list("function call");
-      if (params.errored)
+    auto lit = const_literal();
+    if (lit.errored) {
         return Failure::kErrored;
-
-      return create<ast::CallExpression>(source, ident,
-                                         std::move(params.value));
+    }
+    if (lit.matched) {
+        return lit.value;
     }
 
-    return ident;
-  }
+    if (t.Is(Token::Type::kParenLeft)) {
+        auto paren = expect_paren_rhs_stmt();
+        if (paren.errored) {
+            return Failure::kErrored;
+        }
 
-  auto type = type_decl();
-  if (type.errored)
-    return Failure::kErrored;
-  if (type.matched) {
-    auto params = expect_argument_expression_list("type constructor");
-    if (params.errored)
-      return Failure::kErrored;
+        return paren.value;
+    }
 
-    return builder_.Construct(source, type.value, std::move(params.value));
-  }
+    if (match(Token::Type::kBitcast)) {
+        const char* use = "bitcast expression";
 
-  return Failure::kNoMatch;
+        auto type = expect_lt_gt_block(use, [&] { return expect_type(use); });
+        if (type.errored)
+            return Failure::kErrored;
+
+        auto params = expect_paren_rhs_stmt();
+        if (params.errored)
+            return Failure::kErrored;
+
+        return create<ast::BitcastExpression>(source, type.value, params.value);
+    }
+
+    if (t.IsIdentifier()) {
+        next();
+
+        auto* ident =
+            create<ast::IdentifierExpression>(t.source(), builder_.Symbols().Register(t.to_str()));
+
+        if (peek_is(Token::Type::kParenLeft)) {
+            auto params = expect_argument_expression_list("function call");
+            if (params.errored)
+                return Failure::kErrored;
+
+            return create<ast::CallExpression>(source, ident, std::move(params.value));
+        }
+
+        return ident;
+    }
+
+    auto type = type_decl();
+    if (type.errored)
+        return Failure::kErrored;
+    if (type.matched) {
+        auto params = expect_argument_expression_list("type constructor");
+        if (params.errored)
+            return Failure::kErrored;
+
+        return builder_.Construct(source, type.value, std::move(params.value));
+    }
+
+    return Failure::kNoMatch;
 }
 
 // postfix_expression
 //   :
 //   | BRACE_LEFT logical_or_expression BRACE_RIGHT postfix_expr
 //   | PERIOD IDENTIFIER postfix_expr
-Maybe<const ast::Expression*> ParserImpl::postfix_expression(
-    const ast::Expression* prefix) {
-  Source source;
+Maybe<const ast::Expression*> ParserImpl::postfix_expression(const ast::Expression* prefix) {
+    Source source;
 
-  while (continue_parsing()) {
-    if (match(Token::Type::kBracketLeft, &source)) {
-      auto res = sync(
-          Token::Type::kBracketRight, [&]() -> Maybe<const ast::Expression*> {
-            auto param = logical_or_expression();
-            if (param.errored)
-              return Failure::kErrored;
-            if (!param.matched) {
-              return add_error(peek(), "unable to parse expression inside []");
+    while (continue_parsing()) {
+        if (match(Token::Type::kBracketLeft, &source)) {
+            auto res = sync(Token::Type::kBracketRight, [&]() -> Maybe<const ast::Expression*> {
+                auto param = logical_or_expression();
+                if (param.errored)
+                    return Failure::kErrored;
+                if (!param.matched) {
+                    return add_error(peek(), "unable to parse expression inside []");
+                }
+
+                if (!expect("index accessor", Token::Type::kBracketRight)) {
+                    return Failure::kErrored;
+                }
+
+                return create<ast::IndexAccessorExpression>(source, prefix, param.value);
+            });
+
+            if (res.errored) {
+                return res;
+            }
+            prefix = res.value;
+            continue;
+        }
+
+        if (match(Token::Type::kPeriod)) {
+            auto ident = expect_ident("member accessor");
+            if (ident.errored) {
+                return Failure::kErrored;
             }
 
-            if (!expect("index accessor", Token::Type::kBracketRight)) {
-              return Failure::kErrored;
-            }
+            prefix = create<ast::MemberAccessorExpression>(
+                ident.source, prefix,
+                create<ast::IdentifierExpression>(ident.source,
+                                                  builder_.Symbols().Register(ident.value)));
+            continue;
+        }
 
-            return create<ast::IndexAccessorExpression>(source, prefix,
-                                                        param.value);
-          });
-
-      if (res.errored) {
-        return res;
-      }
-      prefix = res.value;
-      continue;
+        return prefix;
     }
 
-    if (match(Token::Type::kPeriod)) {
-      auto ident = expect_ident("member accessor");
-      if (ident.errored) {
-        return Failure::kErrored;
-      }
-
-      prefix = create<ast::MemberAccessorExpression>(
-          ident.source, prefix,
-          create<ast::IdentifierExpression>(
-              ident.source, builder_.Symbols().Register(ident.value)));
-      continue;
-    }
-
-    return prefix;
-  }
-
-  return Failure::kErrored;
+    return Failure::kErrored;
 }
 
 // singular_expression
 //   : primary_expression postfix_expr
 Maybe<const ast::Expression*> ParserImpl::singular_expression() {
-  auto prefix = primary_expression();
-  if (prefix.errored)
-    return Failure::kErrored;
-  if (!prefix.matched)
-    return Failure::kNoMatch;
+    auto prefix = primary_expression();
+    if (prefix.errored)
+        return Failure::kErrored;
+    if (!prefix.matched)
+        return Failure::kNoMatch;
 
-  return postfix_expression(prefix.value);
+    return postfix_expression(prefix.value);
 }
 
 // argument_expression_list
 //   : PAREN_LEFT ((logical_or_expression COMMA)* logical_or_expression COMMA?)?
 //   PAREN_RIGHT
-Expect<ast::ExpressionList> ParserImpl::expect_argument_expression_list(
-    std::string_view use) {
-  return expect_paren_block(use, [&]() -> Expect<ast::ExpressionList> {
-    ast::ExpressionList ret;
-    while (continue_parsing()) {
-      auto arg = logical_or_expression();
-      if (arg.errored) {
-        return Failure::kErrored;
-      } else if (!arg.matched) {
-        break;
-      }
-      ret.push_back(arg.value);
+Expect<ast::ExpressionList> ParserImpl::expect_argument_expression_list(std::string_view use) {
+    return expect_paren_block(use, [&]() -> Expect<ast::ExpressionList> {
+        ast::ExpressionList ret;
+        while (continue_parsing()) {
+            auto arg = logical_or_expression();
+            if (arg.errored) {
+                return Failure::kErrored;
+            } else if (!arg.matched) {
+                break;
+            }
+            ret.push_back(arg.value);
 
-      if (!match(Token::Type::kComma)) {
-        break;
-      }
-    }
-    return ret;
-  });
+            if (!match(Token::Type::kComma)) {
+                break;
+            }
+        }
+        return ret;
+    });
 }
 
 // unary_expression
@@ -2196,51 +2234,51 @@
 //   | STAR unary_expression
 //   | AND unary_expression
 Maybe<const ast::Expression*> ParserImpl::unary_expression() {
-  auto t = peek();
+    auto t = peek();
 
-  if (match(Token::Type::kPlusPlus) || match(Token::Type::kMinusMinus)) {
-    add_error(t.source(),
-              "prefix increment and decrement operators are reserved for a "
-              "future WGSL version");
-    return Failure::kErrored;
-  }
+    if (match(Token::Type::kPlusPlus) || match(Token::Type::kMinusMinus)) {
+        add_error(t.source(),
+                  "prefix increment and decrement operators are reserved for a "
+                  "future WGSL version");
+        return Failure::kErrored;
+    }
 
-  ast::UnaryOp op;
-  if (match(Token::Type::kMinus)) {
-    op = ast::UnaryOp::kNegation;
-  } else if (match(Token::Type::kBang)) {
-    op = ast::UnaryOp::kNot;
-  } else if (match(Token::Type::kTilde)) {
-    op = ast::UnaryOp::kComplement;
-  } else if (match(Token::Type::kStar)) {
-    op = ast::UnaryOp::kIndirection;
-  } else if (match(Token::Type::kAnd)) {
-    op = ast::UnaryOp::kAddressOf;
-  } else {
-    return singular_expression();
-  }
+    ast::UnaryOp op;
+    if (match(Token::Type::kMinus)) {
+        op = ast::UnaryOp::kNegation;
+    } else if (match(Token::Type::kBang)) {
+        op = ast::UnaryOp::kNot;
+    } else if (match(Token::Type::kTilde)) {
+        op = ast::UnaryOp::kComplement;
+    } else if (match(Token::Type::kStar)) {
+        op = ast::UnaryOp::kIndirection;
+    } else if (match(Token::Type::kAnd)) {
+        op = ast::UnaryOp::kAddressOf;
+    } else {
+        return singular_expression();
+    }
 
-  if (parse_depth_ >= kMaxParseDepth) {
-    // We've hit a maximum parser recursive depth.
-    // We can't call into unary_expression() as we might stack overflow.
-    // Instead, report an error
-    add_error(peek(), "maximum parser recursive depth reached");
-    return Failure::kErrored;
-  }
+    if (parse_depth_ >= kMaxParseDepth) {
+        // We've hit a maximum parser recursive depth.
+        // We can't call into unary_expression() as we might stack overflow.
+        // Instead, report an error
+        add_error(peek(), "maximum parser recursive depth reached");
+        return Failure::kErrored;
+    }
 
-  ++parse_depth_;
-  auto expr = unary_expression();
-  --parse_depth_;
+    ++parse_depth_;
+    auto expr = unary_expression();
+    --parse_depth_;
 
-  if (expr.errored) {
-    return Failure::kErrored;
-  }
-  if (!expr.matched) {
-    return add_error(peek(), "unable to parse right side of " +
-                                 std::string(t.to_name()) + " expression");
-  }
+    if (expr.errored) {
+        return Failure::kErrored;
+    }
+    if (!expr.matched) {
+        return add_error(
+            peek(), "unable to parse right side of " + std::string(t.to_name()) + " expression");
+    }
 
-  return create<ast::UnaryOpExpression>(t.source(), op, expr.value);
+    return create<ast::UnaryOpExpression>(t.source(), op, expr.value);
 }
 
 // multiplicative_expr
@@ -2248,133 +2286,130 @@
 //   | STAR unary_expression multiplicative_expr
 //   | FORWARD_SLASH unary_expression multiplicative_expr
 //   | MODULO unary_expression multiplicative_expr
-Expect<const ast::Expression*> ParserImpl::expect_multiplicative_expr(
-    const ast::Expression* lhs) {
-  while (continue_parsing()) {
-    ast::BinaryOp op = ast::BinaryOp::kNone;
-    if (peek_is(Token::Type::kStar))
-      op = ast::BinaryOp::kMultiply;
-    else if (peek_is(Token::Type::kForwardSlash))
-      op = ast::BinaryOp::kDivide;
-    else if (peek_is(Token::Type::kMod))
-      op = ast::BinaryOp::kModulo;
-    else
-      return lhs;
+Expect<const ast::Expression*> ParserImpl::expect_multiplicative_expr(const ast::Expression* lhs) {
+    while (continue_parsing()) {
+        ast::BinaryOp op = ast::BinaryOp::kNone;
+        if (peek_is(Token::Type::kStar))
+            op = ast::BinaryOp::kMultiply;
+        else if (peek_is(Token::Type::kForwardSlash))
+            op = ast::BinaryOp::kDivide;
+        else if (peek_is(Token::Type::kMod))
+            op = ast::BinaryOp::kModulo;
+        else
+            return lhs;
 
-    auto t = next();
-    auto source = t.source();
-    auto name = t.to_name();
+        auto t = next();
+        auto source = t.source();
+        auto name = t.to_name();
 
-    auto rhs = unary_expression();
-    if (rhs.errored)
-      return Failure::kErrored;
-    if (!rhs.matched) {
-      return add_error(peek(), "unable to parse right side of " +
-                                   std::string(name) + " expression");
+        auto rhs = unary_expression();
+        if (rhs.errored)
+            return Failure::kErrored;
+        if (!rhs.matched) {
+            return add_error(peek(),
+                             "unable to parse right side of " + std::string(name) + " expression");
+        }
+
+        lhs = create<ast::BinaryExpression>(source, op, lhs, rhs.value);
     }
-
-    lhs = create<ast::BinaryExpression>(source, op, lhs, rhs.value);
-  }
-  return Failure::kErrored;
+    return Failure::kErrored;
 }
 
 // multiplicative_expression
 //   : unary_expression multiplicative_expr
 Maybe<const ast::Expression*> ParserImpl::multiplicative_expression() {
-  auto lhs = unary_expression();
-  if (lhs.errored)
-    return Failure::kErrored;
-  if (!lhs.matched)
-    return Failure::kNoMatch;
+    auto lhs = unary_expression();
+    if (lhs.errored)
+        return Failure::kErrored;
+    if (!lhs.matched)
+        return Failure::kNoMatch;
 
-  return expect_multiplicative_expr(lhs.value);
+    return expect_multiplicative_expr(lhs.value);
 }
 
 // additive_expr
 //   :
 //   | PLUS multiplicative_expression additive_expr
 //   | MINUS multiplicative_expression additive_expr
-Expect<const ast::Expression*> ParserImpl::expect_additive_expr(
-    const ast::Expression* lhs) {
-  while (continue_parsing()) {
-    ast::BinaryOp op = ast::BinaryOp::kNone;
-    if (peek_is(Token::Type::kPlus))
-      op = ast::BinaryOp::kAdd;
-    else if (peek_is(Token::Type::kMinus))
-      op = ast::BinaryOp::kSubtract;
-    else
-      return lhs;
+Expect<const ast::Expression*> ParserImpl::expect_additive_expr(const ast::Expression* lhs) {
+    while (continue_parsing()) {
+        ast::BinaryOp op = ast::BinaryOp::kNone;
+        if (peek_is(Token::Type::kPlus))
+            op = ast::BinaryOp::kAdd;
+        else if (peek_is(Token::Type::kMinus))
+            op = ast::BinaryOp::kSubtract;
+        else
+            return lhs;
 
-    auto t = next();
-    auto source = t.source();
+        auto t = next();
+        auto source = t.source();
 
-    auto rhs = multiplicative_expression();
-    if (rhs.errored)
-      return Failure::kErrored;
-    if (!rhs.matched)
-      return add_error(peek(), "unable to parse right side of + expression");
+        auto rhs = multiplicative_expression();
+        if (rhs.errored)
+            return Failure::kErrored;
+        if (!rhs.matched)
+            return add_error(peek(), "unable to parse right side of + expression");
 
-    lhs = create<ast::BinaryExpression>(source, op, lhs, rhs.value);
-  }
-  return Failure::kErrored;
+        lhs = create<ast::BinaryExpression>(source, op, lhs, rhs.value);
+    }
+    return Failure::kErrored;
 }
 
 // additive_expression
 //   : multiplicative_expression additive_expr
 Maybe<const ast::Expression*> ParserImpl::additive_expression() {
-  auto lhs = multiplicative_expression();
-  if (lhs.errored)
-    return Failure::kErrored;
-  if (!lhs.matched)
-    return Failure::kNoMatch;
+    auto lhs = multiplicative_expression();
+    if (lhs.errored)
+        return Failure::kErrored;
+    if (!lhs.matched)
+        return Failure::kNoMatch;
 
-  return expect_additive_expr(lhs.value);
+    return expect_additive_expr(lhs.value);
 }
 
 // shift_expr
 //   :
 //   | SHIFT_LEFT additive_expression shift_expr
 //   | SHIFT_RIGHT additive_expression shift_expr
-Expect<const ast::Expression*> ParserImpl::expect_shift_expr(
-    const ast::Expression* lhs) {
-  while (continue_parsing()) {
-    auto* name = "";
-    ast::BinaryOp op = ast::BinaryOp::kNone;
-    if (peek_is(Token::Type::kShiftLeft)) {
-      op = ast::BinaryOp::kShiftLeft;
-      name = "<<";
-    } else if (peek_is(Token::Type::kShiftRight)) {
-      op = ast::BinaryOp::kShiftRight;
-      name = ">>";
-    } else {
-      return lhs;
-    }
+Expect<const ast::Expression*> ParserImpl::expect_shift_expr(const ast::Expression* lhs) {
+    while (continue_parsing()) {
+        auto* name = "";
+        ast::BinaryOp op = ast::BinaryOp::kNone;
+        if (peek_is(Token::Type::kShiftLeft)) {
+            op = ast::BinaryOp::kShiftLeft;
+            name = "<<";
+        } else if (peek_is(Token::Type::kShiftRight)) {
+            op = ast::BinaryOp::kShiftRight;
+            name = ">>";
+        } else {
+            return lhs;
+        }
 
-    auto t = next();
-    auto source = t.source();
-    auto rhs = additive_expression();
-    if (rhs.errored)
-      return Failure::kErrored;
-    if (!rhs.matched) {
-      return add_error(peek(), std::string("unable to parse right side of ") +
-                                   name + " expression");
-    }
+        auto t = next();
+        auto source = t.source();
+        auto rhs = additive_expression();
+        if (rhs.errored)
+            return Failure::kErrored;
+        if (!rhs.matched) {
+            return add_error(peek(),
+                             std::string("unable to parse right side of ") + name + " expression");
+        }
 
-    return lhs = create<ast::BinaryExpression>(source, op, lhs, rhs.value);
-  }
-  return Failure::kErrored;
+        return lhs = create<ast::BinaryExpression>(source, op, lhs, rhs.value);
+    }
+    return Failure::kErrored;
 }
 
 // shift_expression
 //   : additive_expression shift_expr
 Maybe<const ast::Expression*> ParserImpl::shift_expression() {
-  auto lhs = additive_expression();
-  if (lhs.errored)
-    return Failure::kErrored;
-  if (!lhs.matched)
-    return Failure::kNoMatch;
+    auto lhs = additive_expression();
+    if (lhs.errored)
+        return Failure::kErrored;
+    if (!lhs.matched)
+        return Failure::kNoMatch;
 
-  return expect_shift_expr(lhs.value);
+    return expect_shift_expr(lhs.value);
 }
 
 // relational_expr
@@ -2383,268 +2418,256 @@
 //   | GREATER_THAN shift_expression relational_expr
 //   | LESS_THAN_EQUAL shift_expression relational_expr
 //   | GREATER_THAN_EQUAL shift_expression relational_expr
-Expect<const ast::Expression*> ParserImpl::expect_relational_expr(
-    const ast::Expression* lhs) {
-  while (continue_parsing()) {
-    ast::BinaryOp op = ast::BinaryOp::kNone;
-    if (peek_is(Token::Type::kLessThan))
-      op = ast::BinaryOp::kLessThan;
-    else if (peek_is(Token::Type::kGreaterThan))
-      op = ast::BinaryOp::kGreaterThan;
-    else if (peek_is(Token::Type::kLessThanEqual))
-      op = ast::BinaryOp::kLessThanEqual;
-    else if (peek_is(Token::Type::kGreaterThanEqual))
-      op = ast::BinaryOp::kGreaterThanEqual;
-    else
-      return lhs;
+Expect<const ast::Expression*> ParserImpl::expect_relational_expr(const ast::Expression* lhs) {
+    while (continue_parsing()) {
+        ast::BinaryOp op = ast::BinaryOp::kNone;
+        if (peek_is(Token::Type::kLessThan))
+            op = ast::BinaryOp::kLessThan;
+        else if (peek_is(Token::Type::kGreaterThan))
+            op = ast::BinaryOp::kGreaterThan;
+        else if (peek_is(Token::Type::kLessThanEqual))
+            op = ast::BinaryOp::kLessThanEqual;
+        else if (peek_is(Token::Type::kGreaterThanEqual))
+            op = ast::BinaryOp::kGreaterThanEqual;
+        else
+            return lhs;
 
-    auto t = next();
-    auto source = t.source();
-    auto name = t.to_name();
+        auto t = next();
+        auto source = t.source();
+        auto name = t.to_name();
 
-    auto rhs = shift_expression();
-    if (rhs.errored)
-      return Failure::kErrored;
-    if (!rhs.matched) {
-      return add_error(peek(), "unable to parse right side of " +
-                                   std::string(name) + " expression");
+        auto rhs = shift_expression();
+        if (rhs.errored)
+            return Failure::kErrored;
+        if (!rhs.matched) {
+            return add_error(peek(),
+                             "unable to parse right side of " + std::string(name) + " expression");
+        }
+
+        lhs = create<ast::BinaryExpression>(source, op, lhs, rhs.value);
     }
-
-    lhs = create<ast::BinaryExpression>(source, op, lhs, rhs.value);
-  }
-  return Failure::kErrored;
+    return Failure::kErrored;
 }
 
 // relational_expression
 //   : shift_expression relational_expr
 Maybe<const ast::Expression*> ParserImpl::relational_expression() {
-  auto lhs = shift_expression();
-  if (lhs.errored)
-    return Failure::kErrored;
-  if (!lhs.matched)
-    return Failure::kNoMatch;
+    auto lhs = shift_expression();
+    if (lhs.errored)
+        return Failure::kErrored;
+    if (!lhs.matched)
+        return Failure::kNoMatch;
 
-  return expect_relational_expr(lhs.value);
+    return expect_relational_expr(lhs.value);
 }
 
 // equality_expr
 //   :
 //   | EQUAL_EQUAL relational_expression equality_expr
 //   | NOT_EQUAL relational_expression equality_expr
-Expect<const ast::Expression*> ParserImpl::expect_equality_expr(
-    const ast::Expression* lhs) {
-  while (continue_parsing()) {
-    ast::BinaryOp op = ast::BinaryOp::kNone;
-    if (peek_is(Token::Type::kEqualEqual))
-      op = ast::BinaryOp::kEqual;
-    else if (peek_is(Token::Type::kNotEqual))
-      op = ast::BinaryOp::kNotEqual;
-    else
-      return lhs;
+Expect<const ast::Expression*> ParserImpl::expect_equality_expr(const ast::Expression* lhs) {
+    while (continue_parsing()) {
+        ast::BinaryOp op = ast::BinaryOp::kNone;
+        if (peek_is(Token::Type::kEqualEqual))
+            op = ast::BinaryOp::kEqual;
+        else if (peek_is(Token::Type::kNotEqual))
+            op = ast::BinaryOp::kNotEqual;
+        else
+            return lhs;
 
-    auto t = next();
-    auto source = t.source();
-    auto name = t.to_name();
+        auto t = next();
+        auto source = t.source();
+        auto name = t.to_name();
 
-    auto rhs = relational_expression();
-    if (rhs.errored)
-      return Failure::kErrored;
-    if (!rhs.matched) {
-      return add_error(peek(), "unable to parse right side of " +
-                                   std::string(name) + " expression");
+        auto rhs = relational_expression();
+        if (rhs.errored)
+            return Failure::kErrored;
+        if (!rhs.matched) {
+            return add_error(peek(),
+                             "unable to parse right side of " + std::string(name) + " expression");
+        }
+
+        lhs = create<ast::BinaryExpression>(source, op, lhs, rhs.value);
     }
-
-    lhs = create<ast::BinaryExpression>(source, op, lhs, rhs.value);
-  }
-  return Failure::kErrored;
+    return Failure::kErrored;
 }
 
 // equality_expression
 //   : relational_expression equality_expr
 Maybe<const ast::Expression*> ParserImpl::equality_expression() {
-  auto lhs = relational_expression();
-  if (lhs.errored)
-    return Failure::kErrored;
-  if (!lhs.matched)
-    return Failure::kNoMatch;
+    auto lhs = relational_expression();
+    if (lhs.errored)
+        return Failure::kErrored;
+    if (!lhs.matched)
+        return Failure::kNoMatch;
 
-  return expect_equality_expr(lhs.value);
+    return expect_equality_expr(lhs.value);
 }
 
 // and_expr
 //   :
 //   | AND equality_expression and_expr
-Expect<const ast::Expression*> ParserImpl::expect_and_expr(
-    const ast::Expression* lhs) {
-  while (continue_parsing()) {
-    if (!peek_is(Token::Type::kAnd)) {
-      return lhs;
+Expect<const ast::Expression*> ParserImpl::expect_and_expr(const ast::Expression* lhs) {
+    while (continue_parsing()) {
+        if (!peek_is(Token::Type::kAnd)) {
+            return lhs;
+        }
+
+        auto t = next();
+        auto source = t.source();
+
+        auto rhs = equality_expression();
+        if (rhs.errored)
+            return Failure::kErrored;
+        if (!rhs.matched)
+            return add_error(peek(), "unable to parse right side of & expression");
+
+        lhs = create<ast::BinaryExpression>(source, ast::BinaryOp::kAnd, lhs, rhs.value);
     }
-
-    auto t = next();
-    auto source = t.source();
-
-    auto rhs = equality_expression();
-    if (rhs.errored)
-      return Failure::kErrored;
-    if (!rhs.matched)
-      return add_error(peek(), "unable to parse right side of & expression");
-
-    lhs = create<ast::BinaryExpression>(source, ast::BinaryOp::kAnd, lhs,
-                                        rhs.value);
-  }
-  return Failure::kErrored;
+    return Failure::kErrored;
 }
 
 // and_expression
 //   : equality_expression and_expr
 Maybe<const ast::Expression*> ParserImpl::and_expression() {
-  auto lhs = equality_expression();
-  if (lhs.errored)
-    return Failure::kErrored;
-  if (!lhs.matched)
-    return Failure::kNoMatch;
+    auto lhs = equality_expression();
+    if (lhs.errored)
+        return Failure::kErrored;
+    if (!lhs.matched)
+        return Failure::kNoMatch;
 
-  return expect_and_expr(lhs.value);
+    return expect_and_expr(lhs.value);
 }
 
 // exclusive_or_expr
 //   :
 //   | XOR and_expression exclusive_or_expr
-Expect<const ast::Expression*> ParserImpl::expect_exclusive_or_expr(
-    const ast::Expression* lhs) {
-  while (continue_parsing()) {
-    Source source;
-    if (!match(Token::Type::kXor, &source))
-      return lhs;
+Expect<const ast::Expression*> ParserImpl::expect_exclusive_or_expr(const ast::Expression* lhs) {
+    while (continue_parsing()) {
+        Source source;
+        if (!match(Token::Type::kXor, &source))
+            return lhs;
 
-    auto rhs = and_expression();
-    if (rhs.errored)
-      return Failure::kErrored;
-    if (!rhs.matched)
-      return add_error(peek(), "unable to parse right side of ^ expression");
+        auto rhs = and_expression();
+        if (rhs.errored)
+            return Failure::kErrored;
+        if (!rhs.matched)
+            return add_error(peek(), "unable to parse right side of ^ expression");
 
-    lhs = create<ast::BinaryExpression>(source, ast::BinaryOp::kXor, lhs,
-                                        rhs.value);
-  }
-  return Failure::kErrored;
+        lhs = create<ast::BinaryExpression>(source, ast::BinaryOp::kXor, lhs, rhs.value);
+    }
+    return Failure::kErrored;
 }
 
 // exclusive_or_expression
 //   : and_expression exclusive_or_expr
 Maybe<const ast::Expression*> ParserImpl::exclusive_or_expression() {
-  auto lhs = and_expression();
-  if (lhs.errored)
-    return Failure::kErrored;
-  if (!lhs.matched)
-    return Failure::kNoMatch;
+    auto lhs = and_expression();
+    if (lhs.errored)
+        return Failure::kErrored;
+    if (!lhs.matched)
+        return Failure::kNoMatch;
 
-  return expect_exclusive_or_expr(lhs.value);
+    return expect_exclusive_or_expr(lhs.value);
 }
 
 // inclusive_or_expr
 //   :
 //   | OR exclusive_or_expression inclusive_or_expr
-Expect<const ast::Expression*> ParserImpl::expect_inclusive_or_expr(
-    const ast::Expression* lhs) {
-  while (continue_parsing()) {
-    Source source;
-    if (!match(Token::Type::kOr))
-      return lhs;
+Expect<const ast::Expression*> ParserImpl::expect_inclusive_or_expr(const ast::Expression* lhs) {
+    while (continue_parsing()) {
+        Source source;
+        if (!match(Token::Type::kOr))
+            return lhs;
 
-    auto rhs = exclusive_or_expression();
-    if (rhs.errored)
-      return Failure::kErrored;
-    if (!rhs.matched)
-      return add_error(peek(), "unable to parse right side of | expression");
+        auto rhs = exclusive_or_expression();
+        if (rhs.errored)
+            return Failure::kErrored;
+        if (!rhs.matched)
+            return add_error(peek(), "unable to parse right side of | expression");
 
-    lhs = create<ast::BinaryExpression>(source, ast::BinaryOp::kOr, lhs,
-                                        rhs.value);
-  }
-  return Failure::kErrored;
+        lhs = create<ast::BinaryExpression>(source, ast::BinaryOp::kOr, lhs, rhs.value);
+    }
+    return Failure::kErrored;
 }
 
 // inclusive_or_expression
 //   : exclusive_or_expression inclusive_or_expr
 Maybe<const ast::Expression*> ParserImpl::inclusive_or_expression() {
-  auto lhs = exclusive_or_expression();
-  if (lhs.errored)
-    return Failure::kErrored;
-  if (!lhs.matched)
-    return Failure::kNoMatch;
+    auto lhs = exclusive_or_expression();
+    if (lhs.errored)
+        return Failure::kErrored;
+    if (!lhs.matched)
+        return Failure::kNoMatch;
 
-  return expect_inclusive_or_expr(lhs.value);
+    return expect_inclusive_or_expr(lhs.value);
 }
 
 // logical_and_expr
 //   :
 //   | AND_AND inclusive_or_expression logical_and_expr
-Expect<const ast::Expression*> ParserImpl::expect_logical_and_expr(
-    const ast::Expression* lhs) {
-  while (continue_parsing()) {
-    if (!peek_is(Token::Type::kAndAnd)) {
-      return lhs;
+Expect<const ast::Expression*> ParserImpl::expect_logical_and_expr(const ast::Expression* lhs) {
+    while (continue_parsing()) {
+        if (!peek_is(Token::Type::kAndAnd)) {
+            return lhs;
+        }
+
+        auto t = next();
+        auto source = t.source();
+
+        auto rhs = inclusive_or_expression();
+        if (rhs.errored)
+            return Failure::kErrored;
+        if (!rhs.matched)
+            return add_error(peek(), "unable to parse right side of && expression");
+
+        lhs = create<ast::BinaryExpression>(source, ast::BinaryOp::kLogicalAnd, lhs, rhs.value);
     }
-
-    auto t = next();
-    auto source = t.source();
-
-    auto rhs = inclusive_or_expression();
-    if (rhs.errored)
-      return Failure::kErrored;
-    if (!rhs.matched)
-      return add_error(peek(), "unable to parse right side of && expression");
-
-    lhs = create<ast::BinaryExpression>(source, ast::BinaryOp::kLogicalAnd, lhs,
-                                        rhs.value);
-  }
-  return Failure::kErrored;
+    return Failure::kErrored;
 }
 
 // logical_and_expression
 //   : inclusive_or_expression logical_and_expr
 Maybe<const ast::Expression*> ParserImpl::logical_and_expression() {
-  auto lhs = inclusive_or_expression();
-  if (lhs.errored)
-    return Failure::kErrored;
-  if (!lhs.matched)
-    return Failure::kNoMatch;
+    auto lhs = inclusive_or_expression();
+    if (lhs.errored)
+        return Failure::kErrored;
+    if (!lhs.matched)
+        return Failure::kNoMatch;
 
-  return expect_logical_and_expr(lhs.value);
+    return expect_logical_and_expr(lhs.value);
 }
 
 // logical_or_expr
 //   :
 //   | OR_OR logical_and_expression logical_or_expr
-Expect<const ast::Expression*> ParserImpl::expect_logical_or_expr(
-    const ast::Expression* lhs) {
-  while (continue_parsing()) {
-    Source source;
-    if (!match(Token::Type::kOrOr))
-      return lhs;
+Expect<const ast::Expression*> ParserImpl::expect_logical_or_expr(const ast::Expression* lhs) {
+    while (continue_parsing()) {
+        Source source;
+        if (!match(Token::Type::kOrOr))
+            return lhs;
 
-    auto rhs = logical_and_expression();
-    if (rhs.errored)
-      return Failure::kErrored;
-    if (!rhs.matched)
-      return add_error(peek(), "unable to parse right side of || expression");
+        auto rhs = logical_and_expression();
+        if (rhs.errored)
+            return Failure::kErrored;
+        if (!rhs.matched)
+            return add_error(peek(), "unable to parse right side of || expression");
 
-    lhs = create<ast::BinaryExpression>(source, ast::BinaryOp::kLogicalOr, lhs,
-                                        rhs.value);
-  }
-  return Failure::kErrored;
+        lhs = create<ast::BinaryExpression>(source, ast::BinaryOp::kLogicalOr, lhs, rhs.value);
+    }
+    return Failure::kErrored;
 }
 
 // logical_or_expression
 //   : logical_and_expression logical_or_expr
 Maybe<const ast::Expression*> ParserImpl::logical_or_expression() {
-  auto lhs = logical_and_expression();
-  if (lhs.errored)
-    return Failure::kErrored;
-  if (!lhs.matched)
-    return Failure::kNoMatch;
+    auto lhs = logical_and_expression();
+    if (lhs.errored)
+        return Failure::kErrored;
+    if (!lhs.matched)
+        return Failure::kNoMatch;
 
-  return expect_logical_or_expr(lhs.value);
+    return expect_logical_or_expr(lhs.value);
 }
 
 // compound_assignment_operator:
@@ -2657,29 +2680,29 @@
 // | or_equal
 // | xor_equal
 Maybe<ast::BinaryOp> ParserImpl::compound_assignment_operator() {
-  ast::BinaryOp compound_op = ast::BinaryOp::kNone;
-  if (peek_is(Token::Type::kPlusEqual)) {
-    compound_op = ast::BinaryOp::kAdd;
-  } else if (peek_is(Token::Type::kMinusEqual)) {
-    compound_op = ast::BinaryOp::kSubtract;
-  } else if (peek_is(Token::Type::kTimesEqual)) {
-    compound_op = ast::BinaryOp::kMultiply;
-  } else if (peek_is(Token::Type::kDivisionEqual)) {
-    compound_op = ast::BinaryOp::kDivide;
-  } else if (peek_is(Token::Type::kModuloEqual)) {
-    compound_op = ast::BinaryOp::kModulo;
-  } else if (peek_is(Token::Type::kAndEqual)) {
-    compound_op = ast::BinaryOp::kAnd;
-  } else if (peek_is(Token::Type::kOrEqual)) {
-    compound_op = ast::BinaryOp::kOr;
-  } else if (peek_is(Token::Type::kXorEqual)) {
-    compound_op = ast::BinaryOp::kXor;
-  }
-  if (compound_op != ast::BinaryOp::kNone) {
-    next();
-    return compound_op;
-  }
-  return Failure::kNoMatch;
+    ast::BinaryOp compound_op = ast::BinaryOp::kNone;
+    if (peek_is(Token::Type::kPlusEqual)) {
+        compound_op = ast::BinaryOp::kAdd;
+    } else if (peek_is(Token::Type::kMinusEqual)) {
+        compound_op = ast::BinaryOp::kSubtract;
+    } else if (peek_is(Token::Type::kTimesEqual)) {
+        compound_op = ast::BinaryOp::kMultiply;
+    } else if (peek_is(Token::Type::kDivisionEqual)) {
+        compound_op = ast::BinaryOp::kDivide;
+    } else if (peek_is(Token::Type::kModuloEqual)) {
+        compound_op = ast::BinaryOp::kModulo;
+    } else if (peek_is(Token::Type::kAndEqual)) {
+        compound_op = ast::BinaryOp::kAnd;
+    } else if (peek_is(Token::Type::kOrEqual)) {
+        compound_op = ast::BinaryOp::kOr;
+    } else if (peek_is(Token::Type::kXorEqual)) {
+        compound_op = ast::BinaryOp::kXor;
+    }
+    if (compound_op != ast::BinaryOp::kNone) {
+        next();
+        return compound_op;
+    }
+    return Failure::kNoMatch;
 }
 
 // assignment_stmt
@@ -2690,611 +2713,614 @@
 // decrement_stmt
 // | lhs_expression MINUS_MINUS
 Maybe<const ast::Statement*> ParserImpl::assignment_stmt() {
-  auto t = peek();
-  auto source = t.source();
+    auto t = peek();
+    auto source = t.source();
 
-  // tint:295 - Test for `ident COLON` - this is invalid grammar, and without
-  // special casing will error as "missing = for assignment", which is less
-  // helpful than this error message:
-  if (peek_is(Token::Type::kIdentifier) && peek_is(Token::Type::kColon, 1)) {
-    return add_error(peek(0).source(),
-                     "expected 'var' for variable declaration");
-  }
-
-  auto lhs = unary_expression();
-  if (lhs.errored) {
-    return Failure::kErrored;
-  }
-  if (!lhs.matched) {
-    if (!match(Token::Type::kUnderscore, &source)) {
-      return Failure::kNoMatch;
+    // tint:295 - Test for `ident COLON` - this is invalid grammar, and without
+    // special casing will error as "missing = for assignment", which is less
+    // helpful than this error message:
+    if (peek_is(Token::Type::kIdentifier) && peek_is(Token::Type::kColon, 1)) {
+        return add_error(peek(0).source(), "expected 'var' for variable declaration");
     }
-    lhs = create<ast::PhonyExpression>(source);
-  }
 
-  // Handle increment and decrement statements.
-  // We do this here because the parsing of the LHS expression overlaps with
-  // the assignment statement, and we cannot tell which we are parsing until we
-  // hit the ++/--/= token.
-  if (match(Token::Type::kPlusPlus)) {
-    return create<ast::IncrementDecrementStatement>(source, lhs.value, true);
-  } else if (match(Token::Type::kMinusMinus)) {
-    return create<ast::IncrementDecrementStatement>(source, lhs.value, false);
-  }
-
-  auto compound_op = compound_assignment_operator();
-  if (compound_op.errored) {
-    return Failure::kErrored;
-  }
-  if (!compound_op.matched) {
-    if (!expect("assignment", Token::Type::kEqual)) {
-      return Failure::kErrored;
+    auto lhs = unary_expression();
+    if (lhs.errored) {
+        return Failure::kErrored;
     }
-  }
+    if (!lhs.matched) {
+        if (!match(Token::Type::kUnderscore, &source)) {
+            return Failure::kNoMatch;
+        }
+        lhs = create<ast::PhonyExpression>(source);
+    }
 
-  auto rhs = logical_or_expression();
-  if (rhs.errored) {
-    return Failure::kErrored;
-  }
-  if (!rhs.matched) {
-    return add_error(peek(), "unable to parse right side of assignment");
-  }
+    // Handle increment and decrement statements.
+    // We do this here because the parsing of the LHS expression overlaps with
+    // the assignment statement, and we cannot tell which we are parsing until we
+    // hit the ++/--/= token.
+    if (match(Token::Type::kPlusPlus)) {
+        return create<ast::IncrementDecrementStatement>(source, lhs.value, true);
+    } else if (match(Token::Type::kMinusMinus)) {
+        return create<ast::IncrementDecrementStatement>(source, lhs.value, false);
+    }
 
-  if (compound_op.value != ast::BinaryOp::kNone) {
-    return create<ast::CompoundAssignmentStatement>(
-        source, lhs.value, rhs.value, compound_op.value);
-  } else {
-    return create<ast::AssignmentStatement>(source, lhs.value, rhs.value);
-  }
+    auto compound_op = compound_assignment_operator();
+    if (compound_op.errored) {
+        return Failure::kErrored;
+    }
+    if (!compound_op.matched) {
+        if (!expect("assignment", Token::Type::kEqual)) {
+            return Failure::kErrored;
+        }
+    }
+
+    auto rhs = logical_or_expression();
+    if (rhs.errored) {
+        return Failure::kErrored;
+    }
+    if (!rhs.matched) {
+        return add_error(peek(), "unable to parse right side of assignment");
+    }
+
+    if (compound_op.value != ast::BinaryOp::kNone) {
+        return create<ast::CompoundAssignmentStatement>(source, lhs.value, rhs.value,
+                                                        compound_op.value);
+    } else {
+        return create<ast::AssignmentStatement>(source, lhs.value, rhs.value);
+    }
 }
 
 // const_literal
 //   : INT_LITERAL
-//   | UINT_LITERAL
 //   | FLOAT_LITERAL
 //   | TRUE
 //   | FALSE
 Maybe<const ast::LiteralExpression*> ParserImpl::const_literal() {
-  auto t = peek();
-  if (match(Token::Type::kTrue)) {
-    return create<ast::BoolLiteralExpression>(t.source(), true);
-  }
-  if (match(Token::Type::kFalse)) {
-    return create<ast::BoolLiteralExpression>(t.source(), false);
-  }
-  if (match(Token::Type::kSintLiteral)) {
-    return create<ast::SintLiteralExpression>(t.source(), t.to_i32());
-  }
-  if (match(Token::Type::kUintLiteral)) {
-    return create<ast::UintLiteralExpression>(t.source(), t.to_u32());
-  }
-  if (match(Token::Type::kFloatLiteral)) {
-    return create<ast::FloatLiteralExpression>(t.source(), t.to_f32());
-  }
-  if (handle_error(t)) {
-    return Failure::kErrored;
-  }
-  return Failure::kNoMatch;
+    auto t = peek();
+    if (match(Token::Type::kIntLiteral)) {
+        return create<ast::IntLiteralExpression>(t.source(), t.to_i64(),
+                                                 ast::IntLiteralExpression::Suffix::kNone);
+    }
+    if (match(Token::Type::kIntILiteral)) {
+        return create<ast::IntLiteralExpression>(t.source(), t.to_i64(),
+                                                 ast::IntLiteralExpression::Suffix::kI);
+    }
+    if (match(Token::Type::kIntULiteral)) {
+        return create<ast::IntLiteralExpression>(t.source(), t.to_i64(),
+                                                 ast::IntLiteralExpression::Suffix::kU);
+    }
+    if (match(Token::Type::kFloatLiteral)) {
+        return create<ast::FloatLiteralExpression>(t.source(), t.to_f32());
+    }
+    if (match(Token::Type::kTrue)) {
+        return create<ast::BoolLiteralExpression>(t.source(), true);
+    }
+    if (match(Token::Type::kFalse)) {
+        return create<ast::BoolLiteralExpression>(t.source(), false);
+    }
+    if (handle_error(t)) {
+        return Failure::kErrored;
+    }
+    return Failure::kNoMatch;
 }
 
 // const_expr
 //   : type_decl PAREN_LEFT ((const_expr COMMA)? const_expr COMMA?)? PAREN_RIGHT
 //   | const_literal
 Expect<const ast::Expression*> ParserImpl::expect_const_expr() {
-  auto t = peek();
-  auto source = t.source();
-  if (t.IsLiteral()) {
-    auto lit = const_literal();
-    if (lit.errored) {
-      return Failure::kErrored;
-    }
-    if (!lit.matched) {
-      return add_error(peek(), "unable to parse constant literal");
-    }
-    return lit.value;
-  }
-
-  if (peek_is(Token::Type::kParenLeft, 1) ||
-      peek_is(Token::Type::kLessThan, 1)) {
-    auto type = expect_type("const_expr");
-    if (type.errored) {
-      return Failure::kErrored;
+    auto t = peek();
+    auto source = t.source();
+    if (t.IsLiteral()) {
+        auto lit = const_literal();
+        if (lit.errored) {
+            return Failure::kErrored;
+        }
+        if (!lit.matched) {
+            return add_error(peek(), "unable to parse constant literal");
+        }
+        return lit.value;
     }
 
-    auto params = expect_paren_block(
-        "type constructor", [&]() -> Expect<ast::ExpressionList> {
-          ast::ExpressionList list;
-          while (continue_parsing()) {
-            if (peek_is(Token::Type::kParenRight)) {
-              break;
-            }
+    if (peek_is(Token::Type::kParenLeft, 1) || peek_is(Token::Type::kLessThan, 1)) {
+        auto type = expect_type("const_expr");
+        if (type.errored) {
+            return Failure::kErrored;
+        }
 
-            auto arg = expect_const_expr();
-            if (arg.errored) {
-              return Failure::kErrored;
-            }
-            list.emplace_back(arg.value);
+        auto params = expect_paren_block("type constructor", [&]() -> Expect<ast::ExpressionList> {
+            ast::ExpressionList list;
+            while (continue_parsing()) {
+                if (peek_is(Token::Type::kParenRight)) {
+                    break;
+                }
 
-            if (!match(Token::Type::kComma)) {
-              break;
+                auto arg = expect_const_expr();
+                if (arg.errored) {
+                    return Failure::kErrored;
+                }
+                list.emplace_back(arg.value);
+
+                if (!match(Token::Type::kComma)) {
+                    break;
+                }
             }
-          }
-          return list;
+            return list;
         });
 
-    if (params.errored)
-      return Failure::kErrored;
+        if (params.errored)
+            return Failure::kErrored;
 
-    return builder_.Construct(source, type.value, params.value);
-  }
-  return add_error(peek(), "unable to parse const_expr");
+        return builder_.Construct(source, type.value, params.value);
+    }
+    return add_error(peek(), "unable to parse const_expr");
 }
 
 Maybe<ast::AttributeList> ParserImpl::attribute_list() {
-  bool errored = false;
-  ast::AttributeList attrs;
+    bool errored = false;
+    ast::AttributeList attrs;
 
-  while (continue_parsing()) {
-    if (match(Token::Type::kAttr)) {
-      if (auto attr = expect_attribute(); attr.errored) {
-        errored = true;
-      } else {
-        attrs.emplace_back(attr.value);
-      }
-    } else {
-      break;
+    while (continue_parsing()) {
+        if (match(Token::Type::kAttr)) {
+            if (auto attr = expect_attribute(); attr.errored) {
+                errored = true;
+            } else {
+                attrs.emplace_back(attr.value);
+            }
+        } else {
+            break;
+        }
     }
-  }
 
-  if (errored)
-    return Failure::kErrored;
+    if (errored)
+        return Failure::kErrored;
 
-  if (attrs.empty())
-    return Failure::kNoMatch;
+    if (attrs.empty())
+        return Failure::kNoMatch;
 
-  return attrs;
+    return attrs;
 }
 
 Expect<const ast::Attribute*> ParserImpl::expect_attribute() {
-  auto t = peek();
-  auto attr = attribute();
-  if (attr.errored)
-    return Failure::kErrored;
-  if (attr.matched)
-    return attr.value;
-  return add_error(t, "expected attribute");
+    auto t = peek();
+    auto attr = attribute();
+    if (attr.errored)
+        return Failure::kErrored;
+    if (attr.matched)
+        return attr.value;
+    return add_error(t, "expected attribute");
 }
 
 Maybe<const ast::Attribute*> ParserImpl::attribute() {
-  using Result = Maybe<const ast::Attribute*>;
-  auto t = next();
+    using Result = Maybe<const ast::Attribute*>;
+    auto t = next();
 
-  if (!t.IsIdentifier()) {
+    if (!t.IsIdentifier()) {
+        return Failure::kNoMatch;
+    }
+
+    if (t == kLocationAttribute) {
+        const char* use = "location attribute";
+        return expect_paren_block(use, [&]() -> Result {
+            auto val = expect_positive_sint(use);
+            if (val.errored)
+                return Failure::kErrored;
+
+            return create<ast::LocationAttribute>(t.source(), val.value);
+        });
+    }
+
+    if (t == kBindingAttribute) {
+        const char* use = "binding attribute";
+        return expect_paren_block(use, [&]() -> Result {
+            auto val = expect_positive_sint(use);
+            if (val.errored)
+                return Failure::kErrored;
+
+            return create<ast::BindingAttribute>(t.source(), val.value);
+        });
+    }
+
+    if (t == kGroupAttribute) {
+        const char* use = "group attribute";
+        return expect_paren_block(use, [&]() -> Result {
+            auto val = expect_positive_sint(use);
+            if (val.errored)
+                return Failure::kErrored;
+
+            return create<ast::GroupAttribute>(t.source(), val.value);
+        });
+    }
+
+    if (t == kInterpolateAttribute) {
+        return expect_paren_block("interpolate attribute", [&]() -> Result {
+            ast::InterpolationType type;
+            ast::InterpolationSampling sampling = ast::InterpolationSampling::kNone;
+
+            auto type_tok = next();
+            if (type_tok == "perspective") {
+                type = ast::InterpolationType::kPerspective;
+            } else if (type_tok == "linear") {
+                type = ast::InterpolationType::kLinear;
+            } else if (type_tok == "flat") {
+                type = ast::InterpolationType::kFlat;
+            } else {
+                return add_error(type_tok, "invalid interpolation type");
+            }
+
+            if (match(Token::Type::kComma)) {
+                auto sampling_tok = next();
+                if (sampling_tok == "center") {
+                    sampling = ast::InterpolationSampling::kCenter;
+                } else if (sampling_tok == "centroid") {
+                    sampling = ast::InterpolationSampling::kCentroid;
+                } else if (sampling_tok == "sample") {
+                    sampling = ast::InterpolationSampling::kSample;
+                } else {
+                    return add_error(sampling_tok, "invalid interpolation sampling");
+                }
+            }
+
+            return create<ast::InterpolateAttribute>(t.source(), type, sampling);
+        });
+    }
+
+    if (t == kInvariantAttribute) {
+        return create<ast::InvariantAttribute>(t.source());
+    }
+
+    if (t == kBuiltinAttribute) {
+        return expect_paren_block("builtin attribute", [&]() -> Result {
+            auto builtin = expect_builtin();
+            if (builtin.errored)
+                return Failure::kErrored;
+
+            return create<ast::BuiltinAttribute>(t.source(), builtin.value);
+        });
+    }
+
+    if (t == kWorkgroupSizeAttribute) {
+        return expect_paren_block("workgroup_size attribute", [&]() -> Result {
+            const ast::Expression* x = nullptr;
+            const ast::Expression* y = nullptr;
+            const ast::Expression* z = nullptr;
+
+            auto expr = primary_expression();
+            if (expr.errored) {
+                return Failure::kErrored;
+            } else if (!expr.matched) {
+                return add_error(peek(), "expected workgroup_size x parameter");
+            }
+            x = std::move(expr.value);
+
+            if (match(Token::Type::kComma)) {
+                expr = primary_expression();
+                if (expr.errored) {
+                    return Failure::kErrored;
+                } else if (!expr.matched) {
+                    return add_error(peek(), "expected workgroup_size y parameter");
+                }
+                y = std::move(expr.value);
+
+                if (match(Token::Type::kComma)) {
+                    expr = primary_expression();
+                    if (expr.errored) {
+                        return Failure::kErrored;
+                    } else if (!expr.matched) {
+                        return add_error(peek(), "expected workgroup_size z parameter");
+                    }
+                    z = std::move(expr.value);
+                }
+            }
+
+            return create<ast::WorkgroupAttribute>(t.source(), x, y, z);
+        });
+    }
+
+    if (t == kStageAttribute) {
+        return expect_paren_block("stage attribute", [&]() -> Result {
+            auto stage = expect_pipeline_stage();
+            if (stage.errored)
+                return Failure::kErrored;
+
+            return create<ast::StageAttribute>(t.source(), stage.value);
+        });
+    }
+
+    if (t == kSizeAttribute) {
+        const char* use = "size attribute";
+        return expect_paren_block(use, [&]() -> Result {
+            auto val = expect_positive_sint(use);
+            if (val.errored)
+                return Failure::kErrored;
+
+            return create<ast::StructMemberSizeAttribute>(t.source(), val.value);
+        });
+    }
+
+    if (t == kAlignAttribute) {
+        const char* use = "align attribute";
+        return expect_paren_block(use, [&]() -> Result {
+            auto val = expect_positive_sint(use);
+            if (val.errored)
+                return Failure::kErrored;
+
+            return create<ast::StructMemberAlignAttribute>(t.source(), val.value);
+        });
+    }
+
+    if (t == kIdAttribute) {
+        const char* use = "id attribute";
+        return expect_paren_block(use, [&]() -> Result {
+            auto val = expect_positive_sint(use);
+            if (val.errored)
+                return Failure::kErrored;
+
+            return create<ast::IdAttribute>(t.source(), val.value);
+        });
+    }
+
     return Failure::kNoMatch;
-  }
-
-  if (t == kLocationAttribute) {
-    const char* use = "location attribute";
-    return expect_paren_block(use, [&]() -> Result {
-      auto val = expect_positive_sint(use);
-      if (val.errored)
-        return Failure::kErrored;
-
-      return create<ast::LocationAttribute>(t.source(), val.value);
-    });
-  }
-
-  if (t == kBindingAttribute) {
-    const char* use = "binding attribute";
-    return expect_paren_block(use, [&]() -> Result {
-      auto val = expect_positive_sint(use);
-      if (val.errored)
-        return Failure::kErrored;
-
-      return create<ast::BindingAttribute>(t.source(), val.value);
-    });
-  }
-
-  if (t == kGroupAttribute) {
-    const char* use = "group attribute";
-    return expect_paren_block(use, [&]() -> Result {
-      auto val = expect_positive_sint(use);
-      if (val.errored)
-        return Failure::kErrored;
-
-      return create<ast::GroupAttribute>(t.source(), val.value);
-    });
-  }
-
-  if (t == kInterpolateAttribute) {
-    return expect_paren_block("interpolate attribute", [&]() -> Result {
-      ast::InterpolationType type;
-      ast::InterpolationSampling sampling = ast::InterpolationSampling::kNone;
-
-      auto type_tok = next();
-      if (type_tok == "perspective") {
-        type = ast::InterpolationType::kPerspective;
-      } else if (type_tok == "linear") {
-        type = ast::InterpolationType::kLinear;
-      } else if (type_tok == "flat") {
-        type = ast::InterpolationType::kFlat;
-      } else {
-        return add_error(type_tok, "invalid interpolation type");
-      }
-
-      if (match(Token::Type::kComma)) {
-        auto sampling_tok = next();
-        if (sampling_tok == "center") {
-          sampling = ast::InterpolationSampling::kCenter;
-        } else if (sampling_tok == "centroid") {
-          sampling = ast::InterpolationSampling::kCentroid;
-        } else if (sampling_tok == "sample") {
-          sampling = ast::InterpolationSampling::kSample;
-        } else {
-          return add_error(sampling_tok, "invalid interpolation sampling");
-        }
-      }
-
-      return create<ast::InterpolateAttribute>(t.source(), type, sampling);
-    });
-  }
-
-  if (t == kInvariantAttribute) {
-    return create<ast::InvariantAttribute>(t.source());
-  }
-
-  if (t == kBuiltinAttribute) {
-    return expect_paren_block("builtin attribute", [&]() -> Result {
-      auto builtin = expect_builtin();
-      if (builtin.errored)
-        return Failure::kErrored;
-
-      return create<ast::BuiltinAttribute>(t.source(), builtin.value);
-    });
-  }
-
-  if (t == kWorkgroupSizeAttribute) {
-    return expect_paren_block("workgroup_size attribute", [&]() -> Result {
-      const ast::Expression* x = nullptr;
-      const ast::Expression* y = nullptr;
-      const ast::Expression* z = nullptr;
-
-      auto expr = primary_expression();
-      if (expr.errored) {
-        return Failure::kErrored;
-      } else if (!expr.matched) {
-        return add_error(peek(), "expected workgroup_size x parameter");
-      }
-      x = std::move(expr.value);
-
-      if (match(Token::Type::kComma)) {
-        expr = primary_expression();
-        if (expr.errored) {
-          return Failure::kErrored;
-        } else if (!expr.matched) {
-          return add_error(peek(), "expected workgroup_size y parameter");
-        }
-        y = std::move(expr.value);
-
-        if (match(Token::Type::kComma)) {
-          expr = primary_expression();
-          if (expr.errored) {
-            return Failure::kErrored;
-          } else if (!expr.matched) {
-            return add_error(peek(), "expected workgroup_size z parameter");
-          }
-          z = std::move(expr.value);
-        }
-      }
-
-      return create<ast::WorkgroupAttribute>(t.source(), x, y, z);
-    });
-  }
-
-  if (t == kStageAttribute) {
-    return expect_paren_block("stage attribute", [&]() -> Result {
-      auto stage = expect_pipeline_stage();
-      if (stage.errored)
-        return Failure::kErrored;
-
-      return create<ast::StageAttribute>(t.source(), stage.value);
-    });
-  }
-
-  if (t == kSizeAttribute) {
-    const char* use = "size attribute";
-    return expect_paren_block(use, [&]() -> Result {
-      auto val = expect_positive_sint(use);
-      if (val.errored)
-        return Failure::kErrored;
-
-      return create<ast::StructMemberSizeAttribute>(t.source(), val.value);
-    });
-  }
-
-  if (t == kAlignAttribute) {
-    const char* use = "align attribute";
-    return expect_paren_block(use, [&]() -> Result {
-      auto val = expect_positive_sint(use);
-      if (val.errored)
-        return Failure::kErrored;
-
-      return create<ast::StructMemberAlignAttribute>(t.source(), val.value);
-    });
-  }
-
-  if (t == kIdAttribute) {
-    const char* use = "id attribute";
-    return expect_paren_block(use, [&]() -> Result {
-      auto val = expect_positive_sint(use);
-      if (val.errored)
-        return Failure::kErrored;
-
-      return create<ast::IdAttribute>(t.source(), val.value);
-    });
-  }
-
-  return Failure::kNoMatch;
 }
 
 bool ParserImpl::expect_attributes_consumed(ast::AttributeList& in) {
-  if (in.empty()) {
-    return true;
-  }
-  add_error(in[0]->source, "unexpected attributes");
-  return false;
+    if (in.empty()) {
+        return true;
+    }
+    add_error(in[0]->source, "unexpected attributes");
+    return false;
 }
 
 bool ParserImpl::match(Token::Type tok, Source* source /*= nullptr*/) {
-  auto t = peek();
+    auto t = peek();
 
-  if (source != nullptr)
-    *source = t.source();
+    if (source != nullptr)
+        *source = t.source();
 
-  if (t.Is(tok)) {
-    next();
-    return true;
-  }
-  return false;
+    if (t.Is(tok)) {
+        next();
+        return true;
+    }
+    return false;
 }
 
 bool ParserImpl::expect(std::string_view use, Token::Type tok) {
-  auto t = peek();
-  if (t.Is(tok)) {
-    next();
-    synchronized_ = true;
-    return true;
-  }
-
-  // Special case to split `>>` and `>=` tokens if we are looking for a `>`.
-  if (tok == Token::Type::kGreaterThan &&
-      (t.Is(Token::Type::kShiftRight) ||
-       t.Is(Token::Type::kGreaterThanEqual))) {
-    next();
-
-    // Push the second character to the token queue.
-    auto source = t.source();
-    source.range.begin.column++;
-    if (t.Is(Token::Type::kShiftRight)) {
-      token_queue_.push_front(Token(Token::Type::kGreaterThan, source));
-    } else if (t.Is(Token::Type::kGreaterThanEqual)) {
-      token_queue_.push_front(Token(Token::Type::kEqual, source));
+    auto t = peek();
+    if (t.Is(tok)) {
+        next();
+        synchronized_ = true;
+        return true;
     }
 
-    synchronized_ = true;
-    return true;
-  }
+    // Special case to split `>>` and `>=` tokens if we are looking for a `>`.
+    if (tok == Token::Type::kGreaterThan &&
+        (t.Is(Token::Type::kShiftRight) || t.Is(Token::Type::kGreaterThanEqual))) {
+        next();
 
-  // Error cases
-  synchronized_ = false;
-  if (handle_error(t)) {
+        // Push the second character to the token queue.
+        auto source = t.source();
+        source.range.begin.column++;
+        if (t.Is(Token::Type::kShiftRight)) {
+            token_queue_.push_front(Token(Token::Type::kGreaterThan, source));
+        } else if (t.Is(Token::Type::kGreaterThanEqual)) {
+            token_queue_.push_front(Token(Token::Type::kEqual, source));
+        }
+
+        synchronized_ = true;
+        return true;
+    }
+
+    // Error cases
+    synchronized_ = false;
+    if (handle_error(t)) {
+        return false;
+    }
+
+    std::stringstream err;
+    err << "expected '" << Token::TypeToName(tok) << "'";
+    if (!use.empty()) {
+        err << " for " << use;
+    }
+    add_error(t, err.str());
     return false;
-  }
-
-  std::stringstream err;
-  err << "expected '" << Token::TypeToName(tok) << "'";
-  if (!use.empty()) {
-    err << " for " << use;
-  }
-  add_error(t, err.str());
-  return false;
 }
 
 Expect<int32_t> ParserImpl::expect_sint(std::string_view use) {
-  auto t = peek();
-  if (!t.Is(Token::Type::kSintLiteral))
-    return add_error(t.source(), "expected signed integer literal", use);
+    auto t = peek();
+    if (!t.Is(Token::Type::kIntLiteral) && !t.Is(Token::Type::kIntILiteral)) {
+        return add_error(t.source(), "expected signed integer literal", use);
+    }
 
-  next();
-  return {t.to_i32(), t.source()};
+    int64_t val = t.to_i64();
+    if ((val > std::numeric_limits<int32_t>::max()) ||
+        (val < std::numeric_limits<int32_t>::min())) {
+        // TODO(crbug.com/tint/1504): Test this when abstract int is implemented
+        return add_error(t.source(), "value overflows i32", use);
+    }
+
+    next();
+    return {static_cast<int32_t>(t.to_i64()), t.source()};
 }
 
 Expect<uint32_t> ParserImpl::expect_positive_sint(std::string_view use) {
-  auto sint = expect_sint(use);
-  if (sint.errored)
-    return Failure::kErrored;
+    auto sint = expect_sint(use);
+    if (sint.errored)
+        return Failure::kErrored;
 
-  if (sint.value < 0)
-    return add_error(sint.source, std::string(use) + " must be positive");
+    if (sint.value < 0)
+        return add_error(sint.source, std::string(use) + " must be positive");
 
-  return {static_cast<uint32_t>(sint.value), sint.source};
+    return {static_cast<uint32_t>(sint.value), sint.source};
 }
 
-Expect<uint32_t> ParserImpl::expect_nonzero_positive_sint(
-    std::string_view use) {
-  auto sint = expect_sint(use);
-  if (sint.errored)
-    return Failure::kErrored;
+Expect<uint32_t> ParserImpl::expect_nonzero_positive_sint(std::string_view use) {
+    auto sint = expect_sint(use);
+    if (sint.errored)
+        return Failure::kErrored;
 
-  if (sint.value <= 0)
-    return add_error(sint.source, std::string(use) + " must be greater than 0");
+    if (sint.value <= 0)
+        return add_error(sint.source, std::string(use) + " must be greater than 0");
 
-  return {static_cast<uint32_t>(sint.value), sint.source};
+    return {static_cast<uint32_t>(sint.value), sint.source};
 }
 
 Expect<std::string> ParserImpl::expect_ident(std::string_view use) {
-  auto t = peek();
-  if (t.IsIdentifier()) {
-    synchronized_ = true;
-    next();
+    auto t = peek();
+    if (t.IsIdentifier()) {
+        synchronized_ = true;
+        next();
 
-    if (is_reserved(t)) {
-      return add_error(t.source(),
-                       "'" + t.to_str() + "' is a reserved keyword");
+        if (is_reserved(t)) {
+            return add_error(t.source(), "'" + t.to_str() + "' is a reserved keyword");
+        }
+
+        return {t.to_str(), t.source()};
     }
-
-    return {t.to_str(), t.source()};
-  }
-  if (handle_error(t)) {
-    return Failure::kErrored;
-  }
-  synchronized_ = false;
-  return add_error(t.source(), "expected identifier", use);
+    if (handle_error(t)) {
+        return Failure::kErrored;
+    }
+    synchronized_ = false;
+    return add_error(t.source(), "expected identifier", use);
 }
 
 template <typename F, typename T>
-T ParserImpl::expect_block(Token::Type start,
-                           Token::Type end,
-                           std::string_view use,
-                           F&& body) {
-  if (!expect(use, start)) {
-    return Failure::kErrored;
-  }
+T ParserImpl::expect_block(Token::Type start, Token::Type end, std::string_view use, F&& body) {
+    if (!expect(use, start)) {
+        return Failure::kErrored;
+    }
 
-  return sync(end, [&]() -> T {
-    auto res = body();
+    return sync(end, [&]() -> T {
+        auto res = body();
 
-    if (res.errored)
-      return Failure::kErrored;
+        if (res.errored)
+            return Failure::kErrored;
 
-    if (!expect(use, end))
-      return Failure::kErrored;
+        if (!expect(use, end))
+            return Failure::kErrored;
 
-    return res;
-  });
+        return res;
+    });
 }
 
 template <typename F, typename T>
 T ParserImpl::expect_paren_block(std::string_view use, F&& body) {
-  return expect_block(Token::Type::kParenLeft, Token::Type::kParenRight, use,
-                      std::forward<F>(body));
+    return expect_block(Token::Type::kParenLeft, Token::Type::kParenRight, use,
+                        std::forward<F>(body));
 }
 
 template <typename F, typename T>
 T ParserImpl::expect_brace_block(std::string_view use, F&& body) {
-  return expect_block(Token::Type::kBraceLeft, Token::Type::kBraceRight, use,
-                      std::forward<F>(body));
+    return expect_block(Token::Type::kBraceLeft, Token::Type::kBraceRight, use,
+                        std::forward<F>(body));
 }
 
 template <typename F, typename T>
 T ParserImpl::expect_lt_gt_block(std::string_view use, F&& body) {
-  return expect_block(Token::Type::kLessThan, Token::Type::kGreaterThan, use,
-                      std::forward<F>(body));
+    return expect_block(Token::Type::kLessThan, Token::Type::kGreaterThan, use,
+                        std::forward<F>(body));
 }
 
 template <typename F, typename T>
 T ParserImpl::sync(Token::Type tok, F&& body) {
-  if (parse_depth_ >= kMaxParseDepth) {
-    // We've hit a maximum parser recursive depth.
-    // We can't call into body() as we might stack overflow.
-    // Instead, report an error...
-    add_error(peek(), "maximum parser recursive depth reached");
-    // ...and try to resynchronize. If we cannot resynchronize to `tok` then
-    // synchronized_ is set to false, and the parser knows that forward progress
-    // is not being made.
-    sync_to(tok, /* consume: */ true);
-    return Failure::kErrored;
-  }
+    if (parse_depth_ >= kMaxParseDepth) {
+        // We've hit a maximum parser recursive depth.
+        // We can't call into body() as we might stack overflow.
+        // Instead, report an error...
+        add_error(peek(), "maximum parser recursive depth reached");
+        // ...and try to resynchronize. If we cannot resynchronize to `tok` then
+        // synchronized_ is set to false, and the parser knows that forward progress
+        // is not being made.
+        sync_to(tok, /* consume: */ true);
+        return Failure::kErrored;
+    }
 
-  sync_tokens_.push_back(tok);
+    sync_tokens_.push_back(tok);
 
-  ++parse_depth_;
-  auto result = body();
-  --parse_depth_;
+    ++parse_depth_;
+    auto result = body();
+    --parse_depth_;
 
-  if (sync_tokens_.back() != tok) {
-    TINT_ICE(Reader, builder_.Diagnostics()) << "sync_tokens is out of sync";
-  }
-  sync_tokens_.pop_back();
+    if (sync_tokens_.back() != tok) {
+        TINT_ICE(Reader, builder_.Diagnostics()) << "sync_tokens is out of sync";
+    }
+    sync_tokens_.pop_back();
 
-  if (result.errored) {
-    sync_to(tok, /* consume: */ true);
-  }
+    if (result.errored) {
+        sync_to(tok, /* consume: */ true);
+    }
 
-  return result;
+    return result;
 }
 
 bool ParserImpl::sync_to(Token::Type tok, bool consume) {
-  // Clear the synchronized state - gets set to true again on success.
-  synchronized_ = false;
+    // Clear the synchronized state - gets set to true again on success.
+    synchronized_ = false;
 
-  BlockCounters counters;
+    BlockCounters counters;
 
-  for (size_t i = 0; i < kMaxResynchronizeLookahead; i++) {
-    auto t = peek(i);
-    if (counters.consume(t) > 0) {
-      continue;  // Nested block
-    }
-    if (!t.Is(tok) && !is_sync_token(t)) {
-      continue;  // Not a synchronization point
+    for (size_t i = 0; i < kMaxResynchronizeLookahead; i++) {
+        auto t = peek(i);
+        if (counters.consume(t) > 0) {
+            continue;  // Nested block
+        }
+        if (!t.Is(tok) && !is_sync_token(t)) {
+            continue;  // Not a synchronization point
+        }
+
+        // Synchronization point found.
+
+        // Skip any tokens we don't understand, bringing us to just before the
+        // resync point.
+        while (i-- > 0) {
+            next();
+        }
+
+        // Is this synchronization token |tok|?
+        if (t.Is(tok)) {
+            if (consume) {
+                next();
+            }
+            synchronized_ = true;
+            return true;
+        }
+        break;
     }
 
-    // Synchronization point found.
-
-    // Skip any tokens we don't understand, bringing us to just before the
-    // resync point.
-    while (i-- > 0) {
-      next();
-    }
-
-    // Is this synchronization token |tok|?
-    if (t.Is(tok)) {
-      if (consume) {
-        next();
-      }
-      synchronized_ = true;
-      return true;
-    }
-    break;
-  }
-
-  return false;
+    return false;
 }
 
 bool ParserImpl::is_sync_token(const Token& t) const {
-  for (auto r : sync_tokens_) {
-    if (t.Is(r)) {
-      return true;
+    for (auto r : sync_tokens_) {
+        if (t.Is(r)) {
+            return true;
+        }
     }
-  }
-  return false;
+    return false;
 }
 
 bool ParserImpl::handle_error(const Token& t) {
-  // The token might itself be an error.
-  if (t.IsError()) {
-    synchronized_ = false;
-    add_error(t.source(), t.to_str());
-    return true;
-  }
-  return false;
+    // The token might itself be an error.
+    if (t.IsError()) {
+        synchronized_ = false;
+        add_error(t.source(), t.to_str());
+        return true;
+    }
+    return false;
 }
 
 template <typename F, typename T>
 T ParserImpl::without_error(F&& body) {
-  silence_errors_++;
-  auto result = body();
-  silence_errors_--;
-  return result;
+    silence_errors_++;
+    auto result = body();
+    silence_errors_--;
+    return result;
 }
 
 ParserImpl::MultiTokenSource ParserImpl::make_source_range() {
-  return MultiTokenSource(this);
+    return MultiTokenSource(this);
 }
 
-ParserImpl::MultiTokenSource ParserImpl::make_source_range_from(
-    const Source& start) {
-  return MultiTokenSource(this, start);
+ParserImpl::MultiTokenSource ParserImpl::make_source_range_from(const Source& start) {
+    return MultiTokenSource(this, start);
 }
 
 }  // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/parser_impl.h b/src/tint/reader/wgsl/parser_impl.h
index 9c65c97..67d0004 100644
--- a/src/tint/reader/wgsl/parser_impl.h
+++ b/src/tint/reader/wgsl/parser_impl.h
@@ -27,7 +27,7 @@
 #include "src/tint/program_builder.h"
 #include "src/tint/reader/wgsl/parser_impl_detail.h"
 #include "src/tint/reader/wgsl/token.h"
-#include "src/tint/sem/storage_texture_type.h"
+#include "src/tint/sem/storage_texture.h"
 
 namespace tint::ast {
 class BreakStatement;
@@ -46,832 +46,809 @@
 
 /// Struct holding information for a for loop
 struct ForHeader {
-  /// Constructor
-  /// @param init the initializer statement
-  /// @param cond the condition statement
-  /// @param cont the continuing statement
-  ForHeader(const ast::Statement* init,
-            const ast::Expression* cond,
-            const ast::Statement* cont);
+    /// Constructor
+    /// @param init the initializer statement
+    /// @param cond the condition statement
+    /// @param cont the continuing statement
+    ForHeader(const ast::Statement* init, const ast::Expression* cond, const ast::Statement* cont);
 
-  ~ForHeader();
+    ~ForHeader();
 
-  /// The for loop initializer
-  const ast::Statement* initializer = nullptr;
-  /// The for loop condition
-  const ast::Expression* condition = nullptr;
-  /// The for loop continuing statement
-  const ast::Statement* continuing = nullptr;
+    /// The for loop initializer
+    const ast::Statement* initializer = nullptr;
+    /// The for loop condition
+    const ast::Expression* condition = nullptr;
+    /// The for loop continuing statement
+    const ast::Statement* continuing = nullptr;
 };
 
 /// ParserImpl for WGSL source data
 class ParserImpl {
-  /// Failure holds enumerator values used for the constructing an Expect and
-  /// Match in an errored state.
-  struct Failure {
-    enum Errored { kErrored };
-    enum NoMatch { kNoMatch };
-  };
+    /// Failure holds enumerator values used for the constructing an Expect and
+    /// Match in an errored state.
+    struct Failure {
+        enum Errored { kErrored };
+        enum NoMatch { kNoMatch };
+    };
 
- public:
-  /// Expect is the return type of the parser methods that are expected to
-  /// return a parsed value of type T, unless there was an parse error.
-  /// In the case of a parse error the called method will have called
-  /// add_error() and #errored will be set to true.
-  template <typename T>
-  struct Expect {
-    /// An alias to the templated type T.
-    using type = T;
+  public:
+    /// Expect is the return type of the parser methods that are expected to
+    /// return a parsed value of type T, unless there was an parse error.
+    /// In the case of a parse error the called method will have called
+    /// add_error() and #errored will be set to true.
+    template <typename T>
+    struct Expect {
+        /// An alias to the templated type T.
+        using type = T;
 
-    /// Don't allow an Expect to take a nullptr.
-    inline Expect(std::nullptr_t) = delete;  // NOLINT
+        /// Don't allow an Expect to take a nullptr.
+        inline Expect(std::nullptr_t) = delete;  // NOLINT
 
-    /// Constructor for a successful parse.
-    /// @param val the result value of the parse
-    /// @param s the optional source of the value
-    template <typename U>
-    inline Expect(U&& val, const Source& s = {})  // NOLINT
-        : value(std::forward<U>(val)), source(s) {}
+        /// Constructor for a successful parse.
+        /// @param val the result value of the parse
+        /// @param s the optional source of the value
+        template <typename U>
+        inline Expect(U&& val, const Source& s = {})  // NOLINT
+            : value(std::forward<U>(val)), source(s) {}
 
-    /// Constructor for parse error.
-    inline Expect(Failure::Errored) : errored(true) {}  // NOLINT
+        /// Constructor for parse error.
+        inline Expect(Failure::Errored) : errored(true) {}  // NOLINT
 
-    /// Copy constructor
-    inline Expect(const Expect&) = default;
-    /// Move constructor
-    inline Expect(Expect&&) = default;
-    /// Assignment operator
-    /// @return this Expect
-    inline Expect& operator=(const Expect&) = default;
-    /// Assignment move operator
-    /// @return this Expect
-    inline Expect& operator=(Expect&&) = default;
+        /// Copy constructor
+        inline Expect(const Expect&) = default;
+        /// Move constructor
+        inline Expect(Expect&&) = default;
+        /// Assignment operator
+        /// @return this Expect
+        inline Expect& operator=(const Expect&) = default;
+        /// Assignment move operator
+        /// @return this Expect
+        inline Expect& operator=(Expect&&) = default;
 
-    /// @return a pointer to the returned value. If T is a pointer or
-    /// std::unique_ptr, operator->() automatically dereferences so that the
-    /// return type will always be a pointer to a non-pointer type. #errored
-    /// must be false to call.
-    inline typename detail::OperatorArrow<T>::type operator->() {
-      TINT_ASSERT(Reader, !errored);
-      return detail::OperatorArrow<T>::ptr(value);
-    }
+        /// @return a pointer to the returned value. If T is a pointer or
+        /// std::unique_ptr, operator->() automatically dereferences so that the
+        /// return type will always be a pointer to a non-pointer type. #errored
+        /// must be false to call.
+        inline typename detail::OperatorArrow<T>::type operator->() {
+            TINT_ASSERT(Reader, !errored);
+            return detail::OperatorArrow<T>::ptr(value);
+        }
 
-    /// The expected value of a successful parse.
-    /// Zero-initialized when there was a parse error.
-    T value{};
-    /// Optional source of the value.
-    Source source;
-    /// True if there was a error parsing.
-    bool errored = false;
-  };
+        /// The expected value of a successful parse.
+        /// Zero-initialized when there was a parse error.
+        T value{};
+        /// Optional source of the value.
+        Source source;
+        /// True if there was a error parsing.
+        bool errored = false;
+    };
 
-  /// Maybe is the return type of the parser methods that attempts to match a
-  /// grammar and return a parsed value of type T, or may parse part of the
-  /// grammar and then hit a parse error.
-  /// In the case of a successful grammar match, the Maybe will have #matched
-  /// set to true.
-  /// In the case of a parse error the called method will have called
-  /// add_error() and the Maybe will have #errored set to true.
-  template <typename T>
-  struct Maybe {
-    inline Maybe(std::nullptr_t) = delete;  // NOLINT
+    /// Maybe is the return type of the parser methods that attempts to match a
+    /// grammar and return a parsed value of type T, or may parse part of the
+    /// grammar and then hit a parse error.
+    /// In the case of a successful grammar match, the Maybe will have #matched
+    /// set to true.
+    /// In the case of a parse error the called method will have called
+    /// add_error() and the Maybe will have #errored set to true.
+    template <typename T>
+    struct Maybe {
+        inline Maybe(std::nullptr_t) = delete;  // NOLINT
 
-    /// Constructor for a successful parse.
-    /// @param val the result value of the parse
-    /// @param s the optional source of the value
-    template <typename U>
-    inline Maybe(U&& val, const Source& s = {})  // NOLINT
-        : value(std::forward<U>(val)), source(s), matched(true) {}
+        /// Constructor for a successful parse.
+        /// @param val the result value of the parse
+        /// @param s the optional source of the value
+        template <typename U>
+        inline Maybe(U&& val, const Source& s = {})  // NOLINT
+            : value(std::forward<U>(val)), source(s), matched(true) {}
 
-    /// Constructor for parse error state.
-    inline Maybe(Failure::Errored) : errored(true) {}  // NOLINT
+        /// Constructor for parse error state.
+        inline Maybe(Failure::Errored) : errored(true) {}  // NOLINT
 
-    /// Constructor for the no-match state.
-    inline Maybe(Failure::NoMatch) {}  // NOLINT
+        /// Constructor for the no-match state.
+        inline Maybe(Failure::NoMatch) {}  // NOLINT
 
-    /// Constructor from an Expect.
-    /// @param e the Expect to copy this Maybe from
-    template <typename U>
-    inline Maybe(const Expect<U>& e)  // NOLINT
-        : value(e.value),
-          source(e.value),
-          errored(e.errored),
-          matched(!e.errored) {}
+        /// Constructor from an Expect.
+        /// @param e the Expect to copy this Maybe from
+        template <typename U>
+        inline Maybe(const Expect<U>& e)  // NOLINT
+            : value(e.value), source(e.value), errored(e.errored), matched(!e.errored) {}
 
-    /// Move from an Expect.
-    /// @param e the Expect to move this Maybe from
-    template <typename U>
-    inline Maybe(Expect<U>&& e)  // NOLINT
-        : value(std::move(e.value)),
-          source(std::move(e.source)),
-          errored(e.errored),
-          matched(!e.errored) {}
+        /// Move from an Expect.
+        /// @param e the Expect to move this Maybe from
+        template <typename U>
+        inline Maybe(Expect<U>&& e)  // NOLINT
+            : value(std::move(e.value)),
+              source(std::move(e.source)),
+              errored(e.errored),
+              matched(!e.errored) {}
 
-    /// Copy constructor
-    inline Maybe(const Maybe&) = default;
-    /// Move constructor
-    inline Maybe(Maybe&&) = default;
-    /// Assignment operator
-    /// @return this Maybe
-    inline Maybe& operator=(const Maybe&) = default;
-    /// Assignment move operator
-    /// @return this Maybe
-    inline Maybe& operator=(Maybe&&) = default;
+        /// Copy constructor
+        inline Maybe(const Maybe&) = default;
+        /// Move constructor
+        inline Maybe(Maybe&&) = default;
+        /// Assignment operator
+        /// @return this Maybe
+        inline Maybe& operator=(const Maybe&) = default;
+        /// Assignment move operator
+        /// @return this Maybe
+        inline Maybe& operator=(Maybe&&) = default;
 
-    /// @return a pointer to the returned value. If T is a pointer or
-    /// std::unique_ptr, operator->() automatically dereferences so that the
-    /// return type will always be a pointer to a non-pointer type. #errored
-    /// must be false to call.
-    inline typename detail::OperatorArrow<T>::type operator->() {
-      TINT_ASSERT(Reader, !errored);
-      return detail::OperatorArrow<T>::ptr(value);
-    }
+        /// @return a pointer to the returned value. If T is a pointer or
+        /// std::unique_ptr, operator->() automatically dereferences so that the
+        /// return type will always be a pointer to a non-pointer type. #errored
+        /// must be false to call.
+        inline typename detail::OperatorArrow<T>::type operator->() {
+            TINT_ASSERT(Reader, !errored);
+            return detail::OperatorArrow<T>::ptr(value);
+        }
 
-    /// The value of a successful parse.
-    /// Zero-initialized when there was a parse error.
-    T value{};
-    /// Optional source of the value.
-    Source source;
-    /// True if there was a error parsing.
-    bool errored = false;
-    /// True if there was a error parsing.
-    bool matched = false;
-  };
+        /// The value of a successful parse.
+        /// Zero-initialized when there was a parse error.
+        T value{};
+        /// Optional source of the value.
+        Source source;
+        /// True if there was a error parsing.
+        bool errored = false;
+        /// True if there was a error parsing.
+        bool matched = false;
+    };
 
-  /// TypedIdentifier holds a parsed identifier and type. Returned by
-  /// variable_ident_decl().
-  struct TypedIdentifier {
-    /// Constructor
-    TypedIdentifier();
-    /// Copy constructor
-    /// @param other the FunctionHeader to copy
-    TypedIdentifier(const TypedIdentifier& other);
-    /// Constructor
-    /// @param type_in parsed type
-    /// @param name_in parsed identifier
-    /// @param source_in source to the identifier
-    TypedIdentifier(const ast::Type* type_in,
+    /// TypedIdentifier holds a parsed identifier and type. Returned by
+    /// variable_ident_decl().
+    struct TypedIdentifier {
+        /// Constructor
+        TypedIdentifier();
+        /// Copy constructor
+        /// @param other the FunctionHeader to copy
+        TypedIdentifier(const TypedIdentifier& other);
+        /// Constructor
+        /// @param type_in parsed type
+        /// @param name_in parsed identifier
+        /// @param source_in source to the identifier
+        TypedIdentifier(const ast::Type* type_in, std::string name_in, Source source_in);
+        /// Destructor
+        ~TypedIdentifier();
+
+        /// Parsed type. May be nullptr for inferred types.
+        const ast::Type* type = nullptr;
+        /// Parsed identifier.
+        std::string name;
+        /// Source to the identifier.
+        Source source;
+    };
+
+    /// FunctionHeader contains the parsed information for a function header.
+    struct FunctionHeader {
+        /// Constructor
+        FunctionHeader();
+        /// Copy constructor
+        /// @param other the FunctionHeader to copy
+        FunctionHeader(const FunctionHeader& other);
+        /// Constructor
+        /// @param src parsed header source
+        /// @param n function name
+        /// @param p function parameters
+        /// @param ret_ty function return type
+        /// @param ret_attrs return type attributes
+        FunctionHeader(Source src,
+                       std::string n,
+                       ast::VariableList p,
+                       const ast::Type* ret_ty,
+                       ast::AttributeList ret_attrs);
+        /// Destructor
+        ~FunctionHeader();
+        /// Assignment operator
+        /// @param other the FunctionHeader to copy
+        /// @returns this FunctionHeader
+        FunctionHeader& operator=(const FunctionHeader& other);
+
+        /// Parsed header source
+        Source source;
+        /// Function name
+        std::string name;
+        /// Function parameters
+        ast::VariableList params;
+        /// Function return type
+        const ast::Type* return_type = nullptr;
+        /// Function return type attributes
+        ast::AttributeList return_type_attributes;
+    };
+
+    /// VarDeclInfo contains the parsed information for variable declaration.
+    struct VarDeclInfo {
+        /// Constructor
+        VarDeclInfo();
+        /// Copy constructor
+        /// @param other the VarDeclInfo to copy
+        VarDeclInfo(const VarDeclInfo& other);
+        /// Constructor
+        /// @param source_in variable declaration source
+        /// @param name_in variable name
+        /// @param storage_class_in variable storage class
+        /// @param access_in variable access control
+        /// @param type_in variable type
+        VarDeclInfo(Source source_in,
                     std::string name_in,
-                    Source source_in);
-    /// Destructor
-    ~TypedIdentifier();
+                    ast::StorageClass storage_class_in,
+                    ast::Access access_in,
+                    const ast::Type* type_in);
+        /// Destructor
+        ~VarDeclInfo();
 
-    /// Parsed type. May be nullptr for inferred types.
-    const ast::Type* type = nullptr;
-    /// Parsed identifier.
-    std::string name;
-    /// Source to the identifier.
-    Source source;
-  };
+        /// Variable declaration source
+        Source source;
+        /// Variable name
+        std::string name;
+        /// Variable storage class
+        ast::StorageClass storage_class = ast::StorageClass::kNone;
+        /// Variable access control
+        ast::Access access = ast::Access::kUndefined;
+        /// Variable type
+        const ast::Type* type = nullptr;
+    };
 
-  /// FunctionHeader contains the parsed information for a function header.
-  struct FunctionHeader {
-    /// Constructor
-    FunctionHeader();
-    /// Copy constructor
-    /// @param other the FunctionHeader to copy
-    FunctionHeader(const FunctionHeader& other);
-    /// Constructor
-    /// @param src parsed header source
-    /// @param n function name
-    /// @param p function parameters
-    /// @param ret_ty function return type
-    /// @param ret_attrs return type attributes
-    FunctionHeader(Source src,
-                   std::string n,
-                   ast::VariableList p,
-                   const ast::Type* ret_ty,
-                   ast::AttributeList ret_attrs);
-    /// Destructor
-    ~FunctionHeader();
-    /// Assignment operator
-    /// @param other the FunctionHeader to copy
-    /// @returns this FunctionHeader
-    FunctionHeader& operator=(const FunctionHeader& other);
+    /// VariableQualifier contains the parsed information for a variable qualifier
+    struct VariableQualifier {
+        /// The variable's storage class
+        ast::StorageClass storage_class = ast::StorageClass::kNone;
+        /// The variable's access control
+        ast::Access access = ast::Access::kUndefined;
+    };
 
-    /// Parsed header source
-    Source source;
-    /// Function name
-    std::string name;
-    /// Function parameters
-    ast::VariableList params;
-    /// Function return type
-    const ast::Type* return_type = nullptr;
-    /// Function return type attributes
-    ast::AttributeList return_type_attributes;
-  };
+    /// Creates a new parser using the given file
+    /// @param file the input source file to parse
+    explicit ParserImpl(Source::File const* file);
+    ~ParserImpl();
 
-  /// VarDeclInfo contains the parsed information for variable declaration.
-  struct VarDeclInfo {
-    /// Constructor
-    VarDeclInfo();
-    /// Copy constructor
-    /// @param other the VarDeclInfo to copy
-    VarDeclInfo(const VarDeclInfo& other);
-    /// Constructor
-    /// @param source_in variable declaration source
-    /// @param name_in variable name
-    /// @param storage_class_in variable storage class
-    /// @param access_in variable access control
-    /// @param type_in variable type
-    VarDeclInfo(Source source_in,
-                std::string name_in,
-                ast::StorageClass storage_class_in,
-                ast::Access access_in,
-                const ast::Type* type_in);
-    /// Destructor
-    ~VarDeclInfo();
+    /// Run the parser
+    /// @returns true if the parse was successful, false otherwise.
+    bool Parse();
 
-    /// Variable declaration source
-    Source source;
-    /// Variable name
-    std::string name;
-    /// Variable storage class
-    ast::StorageClass storage_class = ast::StorageClass::kNone;
-    /// Variable access control
-    ast::Access access = ast::Access::kUndefined;
-    /// Variable type
-    const ast::Type* type = nullptr;
-  };
+    /// set_max_diagnostics sets the maximum number of reported errors before
+    /// aborting parsing.
+    /// @param limit the new maximum number of errors
+    void set_max_errors(size_t limit) { max_errors_ = limit; }
 
-  /// VariableQualifier contains the parsed information for a variable qualifier
-  struct VariableQualifier {
-    /// The variable's storage class
-    ast::StorageClass storage_class = ast::StorageClass::kNone;
-    /// The variable's access control
-    ast::Access access = ast::Access::kUndefined;
-  };
+    /// @return the number of maximum number of reported errors before aborting
+    /// parsing.
+    size_t get_max_errors() const { return max_errors_; }
 
-  /// Creates a new parser using the given file
-  /// @param file the input source file to parse
-  explicit ParserImpl(Source::File const* file);
-  ~ParserImpl();
+    /// @returns true if an error was encountered.
+    bool has_error() const { return builder_.Diagnostics().contains_errors(); }
 
-  /// Run the parser
-  /// @returns true if the parse was successful, false otherwise.
-  bool Parse();
+    /// @returns the parser error string
+    std::string error() const {
+        diag::Formatter formatter{{false, false, false, false}};
+        return formatter.format(builder_.Diagnostics());
+    }
 
-  /// set_max_diagnostics sets the maximum number of reported errors before
-  /// aborting parsing.
-  /// @param limit the new maximum number of errors
-  void set_max_errors(size_t limit) { max_errors_ = limit; }
+    /// @returns the Program. The program builder in the parser will be reset
+    /// after this.
+    Program program() { return Program(std::move(builder_)); }
 
-  /// @return the number of maximum number of reported errors before aborting
-  /// parsing.
-  size_t get_max_errors() const { return max_errors_; }
+    /// @returns the program builder.
+    ProgramBuilder& builder() { return builder_; }
 
-  /// @returns true if an error was encountered.
-  bool has_error() const { return builder_.Diagnostics().contains_errors(); }
+    /// @returns the next token
+    Token next();
+    /// Peeks ahead and returns the token at `idx` ahead of the current position
+    /// @param idx the index of the token to return
+    /// @returns the token `idx` positions ahead without advancing
+    Token peek(size_t idx = 0);
+    /// Peeks ahead and returns true if the token at `idx` ahead of the current
+    /// position is |tok|
+    /// @param idx the index of the token to return
+    /// @param tok the token to look for
+    /// @returns true if the token `idx` positions ahead is |tok|
+    bool peek_is(Token::Type tok, size_t idx = 0);
+    /// @returns the last token that was returned by `next()`
+    Token last_token() const;
+    /// Appends an error at `t` with the message `msg`
+    /// @param t the token to associate the error with
+    /// @param msg the error message
+    /// @return `Failure::Errored::kError` so that you can combine an add_error()
+    /// call and return on the same line.
+    Failure::Errored add_error(const Token& t, const std::string& msg);
+    /// Appends an error raised when parsing `use` at `t` with the message
+    /// `msg`
+    /// @param source the source to associate the error with
+    /// @param msg the error message
+    /// @param use a description of what was being parsed when the error was
+    /// raised.
+    /// @return `Failure::Errored::kError` so that you can combine an add_error()
+    /// call and return on the same line.
+    Failure::Errored add_error(const Source& source, std::string_view msg, std::string_view use);
+    /// Appends an error at `source` with the message `msg`
+    /// @param source the source to associate the error with
+    /// @param msg the error message
+    /// @return `Failure::Errored::kError` so that you can combine an add_error()
+    /// call and return on the same line.
+    Failure::Errored add_error(const Source& source, const std::string& msg);
+    /// Appends a deprecated-language-feature warning at `source` with the message
+    /// `msg`
+    /// @param source the source to associate the error with
+    /// @param msg the warning message
+    void deprecated(const Source& source, const std::string& msg);
+    /// Parses the `translation_unit` grammar element
+    void translation_unit();
+    /// Parses the `enable_directive` grammar element, erroring on parse failure.
+    /// @return true on parse success, otherwise an error or no-match.
+    Maybe<bool> enable_directive();
+    /// Parses the `global_decl` grammar element, erroring on parse failure.
+    /// @return true on parse success, otherwise an error or no-match.
+    Maybe<bool> global_decl();
+    /// Parses a `global_variable_decl` grammar element with the initial
+    /// `variable_attribute_list*` provided as `attrs`
+    /// @returns the variable parsed or nullptr
+    /// @param attrs the list of attributes for the variable declaration.
+    Maybe<const ast::Variable*> global_variable_decl(ast::AttributeList& attrs);
+    /// Parses a `global_constant_decl` grammar element with the initial
+    /// `variable_attribute_list*` provided as `attrs`
+    /// @returns the const object or nullptr
+    /// @param attrs the list of attributes for the constant declaration.
+    Maybe<const ast::Variable*> global_constant_decl(ast::AttributeList& attrs);
+    /// Parses a `variable_decl` grammar element
+    /// @param allow_inferred if true, do not fail if variable decl does not
+    /// specify type
+    /// @returns the parsed variable declaration info
+    Maybe<VarDeclInfo> variable_decl(bool allow_inferred = false);
+    /// Parses a `variable_ident_decl` grammar element, erroring on parse
+    /// failure.
+    /// @param use a description of what was being parsed if an error was raised.
+    /// @param allow_inferred if true, do not fail if variable decl does not
+    /// specify type
+    /// @returns the identifier and type parsed or empty otherwise
+    Expect<TypedIdentifier> expect_variable_ident_decl(std::string_view use,
+                                                       bool allow_inferred = false);
+    /// Parses a `variable_qualifier` grammar element
+    /// @returns the variable qualifier information
+    Maybe<VariableQualifier> variable_qualifier();
+    /// Parses a `type_alias` grammar element
+    /// @returns the type alias or nullptr on error
+    Maybe<const ast::Alias*> type_alias();
+    /// Parses a `type_decl` grammar element
+    /// @returns the parsed Type or nullptr if none matched.
+    Maybe<const ast::Type*> type_decl();
+    /// Parses a `storage_class` grammar element, erroring on parse failure.
+    /// @param use a description of what was being parsed if an error was raised.
+    /// @returns the storage class or StorageClass::kNone if none matched
+    Expect<ast::StorageClass> expect_storage_class(std::string_view use);
+    /// Parses a `struct_decl` grammar element.
+    /// @returns the struct type or nullptr on error
+    Maybe<const ast::Struct*> struct_decl();
+    /// Parses a `struct_body_decl` grammar element, erroring on parse failure.
+    /// @returns the struct members
+    Expect<ast::StructMemberList> expect_struct_body_decl();
+    /// Parses a `struct_member` grammar element, erroring on parse failure.
+    /// @returns the struct member or nullptr
+    Expect<ast::StructMember*> expect_struct_member();
+    /// Parses a `function_decl` grammar element with the initial
+    /// `function_attribute_decl*` provided as `attrs`.
+    /// @param attrs the list of attributes for the function declaration.
+    /// @returns the parsed function, nullptr otherwise
+    Maybe<const ast::Function*> function_decl(ast::AttributeList& attrs);
+    /// Parses a `texture_samplers` grammar element
+    /// @returns the parsed Type or nullptr if none matched.
+    Maybe<const ast::Type*> texture_samplers();
+    /// Parses a `sampler` grammar element
+    /// @returns the parsed Type or nullptr if none matched.
+    Maybe<const ast::Type*> sampler();
+    /// Parses a `multisampled_texture` grammar element
+    /// @returns returns the multisample texture dimension or kNone if none
+    /// matched.
+    Maybe<const ast::TextureDimension> multisampled_texture();
+    /// Parses a `sampled_texture` grammar element
+    /// @returns returns the sample texture dimension or kNone if none matched.
+    Maybe<const ast::TextureDimension> sampled_texture();
+    /// Parses a `storage_texture` grammar element
+    /// @returns returns the storage texture dimension.
+    /// Returns kNone if none matched.
+    Maybe<const ast::TextureDimension> storage_texture();
+    /// Parses a `depth_texture` grammar element
+    /// @returns the parsed Type or nullptr if none matched.
+    Maybe<const ast::Type*> depth_texture();
+    /// Parses a 'texture_external_type' grammar element
+    /// @returns the parsed Type or nullptr if none matched
+    Maybe<const ast::Type*> external_texture();
+    /// Parses a `texel_format` grammar element
+    /// @param use a description of what was being parsed if an error was raised
+    /// @returns returns the texel format or kNone if none matched.
+    Expect<ast::TexelFormat> expect_texel_format(std::string_view use);
+    /// Parses a `function_header` grammar element
+    /// @returns the parsed function header
+    Maybe<FunctionHeader> function_header();
+    /// Parses a `param_list` grammar element, erroring on parse failure.
+    /// @returns the parsed variables
+    Expect<ast::VariableList> expect_param_list();
+    /// Parses a `param` grammar element, erroring on parse failure.
+    /// @returns the parsed variable
+    Expect<ast::Variable*> expect_param();
+    /// Parses a `pipeline_stage` grammar element, erroring if the next token does
+    /// not match a stage name.
+    /// @returns the pipeline stage.
+    Expect<ast::PipelineStage> expect_pipeline_stage();
+    /// Parses an access control identifier, erroring if the next token does not
+    /// match a valid access control.
+    /// @param use a description of what was being parsed if an error was raised
+    /// @returns the parsed access control.
+    Expect<ast::Access> expect_access(std::string_view use);
+    /// 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();
+    /// Parses a `body_stmt` grammar element, erroring on parse failure.
+    /// @returns the parsed statements
+    Expect<ast::BlockStatement*> expect_body_stmt();
+    /// Parses a `paren_rhs_stmt` grammar element, erroring on parse failure.
+    /// @returns the parsed element or nullptr
+    Expect<const ast::Expression*> expect_paren_rhs_stmt();
+    /// Parses a `statements` grammar element
+    /// @returns the statements parsed
+    Expect<ast::StatementList> expect_statements();
+    /// Parses a `statement` grammar element
+    /// @returns the parsed statement or nullptr
+    Maybe<const ast::Statement*> statement();
+    /// Parses a `break_stmt` grammar element
+    /// @returns the parsed statement or nullptr
+    Maybe<const ast::BreakStatement*> break_stmt();
+    /// Parses a `return_stmt` grammar element
+    /// @returns the parsed statement or nullptr
+    Maybe<const ast::ReturnStatement*> return_stmt();
+    /// Parses a `continue_stmt` grammar element
+    /// @returns the parsed statement or nullptr
+    Maybe<const ast::ContinueStatement*> continue_stmt();
+    /// Parses a `variable_stmt` grammar element
+    /// @returns the parsed variable or nullptr
+    Maybe<const ast::VariableDeclStatement*> variable_stmt();
+    /// Parses a `if_stmt` grammar element
+    /// @returns the parsed statement or nullptr
+    Maybe<const ast::IfStatement*> if_stmt();
+    /// Parses a `switch_stmt` grammar element
+    /// @returns the parsed statement or nullptr
+    Maybe<const ast::SwitchStatement*> switch_stmt();
+    /// Parses a `switch_body` grammar element
+    /// @returns the parsed statement or nullptr
+    Maybe<const ast::CaseStatement*> switch_body();
+    /// Parses a `case_selectors` grammar element
+    /// @returns the list of literals
+    Expect<ast::CaseSelectorList> expect_case_selectors();
+    /// Parses a `case_body` grammar element
+    /// @returns the parsed statements
+    Maybe<const ast::BlockStatement*> case_body();
+    /// Parses a `func_call_stmt` grammar element
+    /// @returns the parsed function call or nullptr
+    Maybe<const ast::CallStatement*> func_call_stmt();
+    /// Parses a `loop_stmt` grammar element
+    /// @returns the parsed loop or nullptr
+    Maybe<const ast::LoopStatement*> loop_stmt();
+    /// Parses a `for_header` grammar element, erroring on parse failure.
+    /// @returns the parsed for header or nullptr
+    Expect<std::unique_ptr<ForHeader>> expect_for_header();
+    /// Parses a `for_stmt` grammar element
+    /// @returns the parsed for loop or nullptr
+    Maybe<const ast::ForLoopStatement*> for_stmt();
+    /// Parses a `continuing_stmt` grammar element
+    /// @returns the parsed statements
+    Maybe<const ast::BlockStatement*> continuing_stmt();
+    /// Parses a `const_literal` grammar element
+    /// @returns the const literal parsed or nullptr if none found
+    Maybe<const ast::LiteralExpression*> const_literal();
+    /// Parses a `const_expr` grammar element, erroring on parse failure.
+    /// @returns the parsed constructor expression or nullptr on error
+    Expect<const ast::Expression*> expect_const_expr();
+    /// Parses a `primary_expression` grammar element
+    /// @returns the parsed expression or nullptr
+    Maybe<const ast::Expression*> primary_expression();
+    /// Parses a `argument_expression_list` grammar element, erroring on parse
+    /// failure.
+    /// @param use a description of what was being parsed if an error was raised
+    /// @returns the list of arguments
+    Expect<ast::ExpressionList> expect_argument_expression_list(std::string_view use);
+    /// Parses the recursive portion of the postfix_expression
+    /// @param prefix the left side of the expression
+    /// @returns the parsed expression or nullptr
+    Maybe<const ast::Expression*> postfix_expression(const ast::Expression* prefix);
+    /// Parses a `singular_expression` grammar elment
+    /// @returns the parsed expression or nullptr
+    Maybe<const ast::Expression*> singular_expression();
+    /// Parses a `unary_expression` grammar element
+    /// @returns the parsed expression or nullptr
+    Maybe<const ast::Expression*> unary_expression();
+    /// Parses the recursive part of the `multiplicative_expression`, erroring on
+    /// parse failure.
+    /// @param lhs the left side of the expression
+    /// @returns the parsed expression or nullptr
+    Expect<const ast::Expression*> expect_multiplicative_expr(const ast::Expression* lhs);
+    /// Parses the `multiplicative_expression` grammar element
+    /// @returns the parsed expression or nullptr
+    Maybe<const ast::Expression*> multiplicative_expression();
+    /// Parses the recursive part of the `additive_expression`, erroring on parse
+    /// failure.
+    /// @param lhs the left side of the expression
+    /// @returns the parsed expression or nullptr
+    Expect<const ast::Expression*> expect_additive_expr(const ast::Expression* lhs);
+    /// Parses the `additive_expression` grammar element
+    /// @returns the parsed expression or nullptr
+    Maybe<const ast::Expression*> additive_expression();
+    /// Parses the recursive part of the `shift_expression`, erroring on parse
+    /// failure.
+    /// @param lhs the left side of the expression
+    /// @returns the parsed expression or nullptr
+    Expect<const ast::Expression*> expect_shift_expr(const ast::Expression* lhs);
+    /// Parses the `shift_expression` grammar element
+    /// @returns the parsed expression or nullptr
+    Maybe<const ast::Expression*> shift_expression();
+    /// Parses the recursive part of the `relational_expression`, erroring on
+    /// parse failure.
+    /// @param lhs the left side of the expression
+    /// @returns the parsed expression or nullptr
+    Expect<const ast::Expression*> expect_relational_expr(const ast::Expression* lhs);
+    /// Parses the `relational_expression` grammar element
+    /// @returns the parsed expression or nullptr
+    Maybe<const ast::Expression*> relational_expression();
+    /// Parses the recursive part of the `equality_expression`, erroring on parse
+    /// failure.
+    /// @param lhs the left side of the expression
+    /// @returns the parsed expression or nullptr
+    Expect<const ast::Expression*> expect_equality_expr(const ast::Expression* lhs);
+    /// Parses the `equality_expression` grammar element
+    /// @returns the parsed expression or nullptr
+    Maybe<const ast::Expression*> equality_expression();
+    /// Parses the recursive part of the `and_expression`, erroring on parse
+    /// failure.
+    /// @param lhs the left side of the expression
+    /// @returns the parsed expression or nullptr
+    Expect<const ast::Expression*> expect_and_expr(const ast::Expression* lhs);
+    /// Parses the `and_expression` grammar element
+    /// @returns the parsed expression or nullptr
+    Maybe<const ast::Expression*> and_expression();
+    /// Parses the recursive part of the `exclusive_or_expression`, erroring on
+    /// parse failure.
+    /// @param lhs the left side of the expression
+    /// @returns the parsed expression or nullptr
+    Expect<const ast::Expression*> expect_exclusive_or_expr(const ast::Expression* lhs);
+    /// Parses the `exclusive_or_expression` grammar elememnt
+    /// @returns the parsed expression or nullptr
+    Maybe<const ast::Expression*> exclusive_or_expression();
+    /// Parses the recursive part of the `inclusive_or_expression`, erroring on
+    /// parse failure.
+    /// @param lhs the left side of the expression
+    /// @returns the parsed expression or nullptr
+    Expect<const ast::Expression*> expect_inclusive_or_expr(const ast::Expression* lhs);
+    /// Parses the `inclusive_or_expression` grammar element
+    /// @returns the parsed expression or nullptr
+    Maybe<const ast::Expression*> inclusive_or_expression();
+    /// Parses the recursive part of the `logical_and_expression`, erroring on
+    /// parse failure.
+    /// @param lhs the left side of the expression
+    /// @returns the parsed expression or nullptr
+    Expect<const ast::Expression*> expect_logical_and_expr(const ast::Expression* lhs);
+    /// Parses a `logical_and_expression` grammar element
+    /// @returns the parsed expression or nullptr
+    Maybe<const ast::Expression*> logical_and_expression();
+    /// Parses the recursive part of the `logical_or_expression`, erroring on
+    /// parse failure.
+    /// @param lhs the left side of the expression
+    /// @returns the parsed expression or nullptr
+    Expect<const ast::Expression*> expect_logical_or_expr(const ast::Expression* lhs);
+    /// Parses a `logical_or_expression` grammar element
+    /// @returns the parsed expression or nullptr
+    Maybe<const ast::Expression*> logical_or_expression();
+    /// Parses a `compound_assignment_operator` grammar element
+    /// @returns the parsed compound assignment operator
+    Maybe<ast::BinaryOp> compound_assignment_operator();
+    /// Parses a `assignment_stmt` grammar element
+    /// @returns the parsed assignment or nullptr
+    Maybe<const ast::Statement*> assignment_stmt();
+    /// Parses one or more attribute lists.
+    /// @return the parsed attribute list, or an empty list on error.
+    Maybe<ast::AttributeList> attribute_list();
+    /// Parses a single attribute of the following types:
+    /// * `struct_attribute`
+    /// * `struct_member_attribute`
+    /// * `array_attribute`
+    /// * `variable_attribute`
+    /// * `global_const_attribute`
+    /// * `function_attribute`
+    /// @return the parsed attribute, or nullptr.
+    Maybe<const ast::Attribute*> attribute();
+    /// Parses a single attribute, reporting an error if the next token does not
+    /// represent a attribute.
+    /// @see #attribute for the full list of attributes this method parses.
+    /// @return the parsed attribute, or nullptr on error.
+    Expect<const ast::Attribute*> expect_attribute();
 
-  /// @returns the parser error string
-  std::string error() const {
-    diag::Formatter formatter{{false, false, false, false}};
-    return formatter.format(builder_.Diagnostics());
-  }
+  private:
+    /// ReturnType resolves to the return type for the function or lambda F.
+    template <typename F>
+    using ReturnType = typename std::invoke_result<F>::type;
 
-  /// @returns the Program. The program builder in the parser will be reset
-  /// after this.
-  Program program() { return Program(std::move(builder_)); }
+    /// ResultType resolves to `T` for a `RESULT` of type Expect<T>.
+    template <typename RESULT>
+    using ResultType = typename RESULT::type;
 
-  /// @returns the program builder.
-  ProgramBuilder& builder() { return builder_; }
+    /// @returns true and consumes the next token if it equals `tok`
+    /// @param source if not nullptr, the next token's source is written to this
+    /// pointer, regardless of success or error
+    bool match(Token::Type tok, Source* source = nullptr);
+    /// Errors if the next token is not equal to `tok`
+    /// Consumes the next token on match.
+    /// expect() also updates #synchronized_, setting it to `true` if the next
+    /// token is equal to `tok`, otherwise `false`.
+    /// @param use a description of what was being parsed if an error was raised.
+    /// @param tok the token to test against
+    /// @returns true if the next token equals `tok`
+    bool expect(std::string_view use, Token::Type tok);
+    /// Parses a signed integer from the next token in the stream, erroring if the
+    /// next token is not a signed integer.
+    /// Consumes the next token on match.
+    /// @param use a description of what was being parsed if an error was raised
+    /// @returns the parsed integer.
+    Expect<int32_t> expect_sint(std::string_view use);
+    /// Parses a signed integer from the next token in the stream, erroring if
+    /// the next token is not a signed integer or is negative.
+    /// Consumes the next token if it is a signed integer (not necessarily
+    /// negative).
+    /// @param use a description of what was being parsed if an error was raised
+    /// @returns the parsed integer.
+    Expect<uint32_t> expect_positive_sint(std::string_view use);
+    /// Parses a non-zero signed integer from the next token in the stream,
+    /// erroring if the next token is not a signed integer or is less than 1.
+    /// Consumes the next token if it is a signed integer (not necessarily
+    /// >= 1).
+    /// @param use a description of what was being parsed if an error was raised
+    /// @returns the parsed integer.
+    Expect<uint32_t> expect_nonzero_positive_sint(std::string_view use);
+    /// Errors if the next token is not an identifier.
+    /// Consumes the next token on match.
+    /// @param use a description of what was being parsed if an error was raised
+    /// @returns the parsed identifier.
+    Expect<std::string> expect_ident(std::string_view use);
+    /// Parses a lexical block starting with the token `start` and ending with
+    /// the token `end`. `body` is called to parse the lexical block body
+    /// between the `start` and `end` tokens. If the `start` or `end` tokens
+    /// are not matched then an error is generated and a zero-initialized `T` is
+    /// returned. If `body` raises an error while parsing then a zero-initialized
+    /// `T` is returned.
+    /// @param start the token that begins the lexical block
+    /// @param end the token that ends the lexical block
+    /// @param use a description of what was being parsed if an error was raised
+    /// @param body a function or lambda that is called to parse the lexical block
+    /// body, with the signature: `Expect<Result>()` or `Maybe<Result>()`.
+    /// @return the value returned by `body` if no errors are raised, otherwise
+    /// an Expect with error state.
+    template <typename F, typename T = ReturnType<F>>
+    T expect_block(Token::Type start, Token::Type end, std::string_view use, F&& body);
+    /// A convenience function that calls expect_block() passing
+    /// `Token::Type::kParenLeft` and `Token::Type::kParenRight` for the `start`
+    /// and `end` arguments, respectively.
+    /// @param use a description of what was being parsed if an error was raised
+    /// @param body a function or lambda that is called to parse the lexical block
+    /// body, with the signature: `Expect<Result>()` or `Maybe<Result>()`.
+    /// @return the value returned by `body` if no errors are raised, otherwise
+    /// an Expect with error state.
+    template <typename F, typename T = ReturnType<F>>
+    T expect_paren_block(std::string_view use, F&& body);
+    /// A convenience function that calls `expect_block` passing
+    /// `Token::Type::kBraceLeft` and `Token::Type::kBraceRight` for the `start`
+    /// and `end` arguments, respectively.
+    /// @param use a description of what was being parsed if an error was raised
+    /// @param body a function or lambda that is called to parse the lexical block
+    /// body, with the signature: `Expect<Result>()` or `Maybe<Result>()`.
+    /// @return the value returned by `body` if no errors are raised, otherwise
+    /// an Expect with error state.
+    template <typename F, typename T = ReturnType<F>>
+    T expect_brace_block(std::string_view use, F&& body);
+    /// A convenience function that calls `expect_block` passing
+    /// `Token::Type::kLessThan` and `Token::Type::kGreaterThan` for the `start`
+    /// and `end` arguments, respectively.
+    /// @param use a description of what was being parsed if an error was raised
+    /// @param body a function or lambda that is called to parse the lexical block
+    /// body, with the signature: `Expect<Result>()` or `Maybe<Result>()`.
+    /// @return the value returned by `body` if no errors are raised, otherwise
+    /// an Expect with error state.
+    template <typename F, typename T = ReturnType<F>>
+    T expect_lt_gt_block(std::string_view use, F&& body);
 
-  /// @returns the next token
-  Token next();
-  /// Peeks ahead and returns the token at `idx` ahead of the current position
-  /// @param idx the index of the token to return
-  /// @returns the token `idx` positions ahead without advancing
-  Token peek(size_t idx = 0);
-  /// Peeks ahead and returns true if the token at `idx` ahead of the current
-  /// position is |tok|
-  /// @param idx the index of the token to return
-  /// @param tok the token to look for
-  /// @returns true if the token `idx` positions ahead is |tok|
-  bool peek_is(Token::Type tok, size_t idx = 0);
-  /// @returns the last token that was returned by `next()`
-  Token last_token() const;
-  /// Appends an error at `t` with the message `msg`
-  /// @param t the token to associate the error with
-  /// @param msg the error message
-  /// @return `Failure::Errored::kError` so that you can combine an add_error()
-  /// call and return on the same line.
-  Failure::Errored add_error(const Token& t, const std::string& msg);
-  /// Appends an error raised when parsing `use` at `t` with the message
-  /// `msg`
-  /// @param source the source to associate the error with
-  /// @param msg the error message
-  /// @param use a description of what was being parsed when the error was
-  /// raised.
-  /// @return `Failure::Errored::kError` so that you can combine an add_error()
-  /// call and return on the same line.
-  Failure::Errored add_error(const Source& source,
-                             std::string_view msg,
-                             std::string_view use);
-  /// Appends an error at `source` with the message `msg`
-  /// @param source the source to associate the error with
-  /// @param msg the error message
-  /// @return `Failure::Errored::kError` so that you can combine an add_error()
-  /// call and return on the same line.
-  Failure::Errored add_error(const Source& source, const std::string& msg);
-  /// Appends a deprecated-language-feature warning at `source` with the message
-  /// `msg`
-  /// @param source the source to associate the error with
-  /// @param msg the warning message
-  void deprecated(const Source& source, const std::string& msg);
-  /// Parses the `translation_unit` grammar element
-  void translation_unit();
-  /// Parses the `global_decl` grammar element, erroring on parse failure.
-  /// @return true on parse success, otherwise an error.
-  Expect<bool> expect_global_decl();
-  /// Parses a `global_variable_decl` grammar element with the initial
-  /// `variable_attribute_list*` provided as `attrs`
-  /// @returns the variable parsed or nullptr
-  /// @param attrs the list of attributes for the variable declaration.
-  Maybe<const ast::Variable*> global_variable_decl(ast::AttributeList& attrs);
-  /// Parses a `global_constant_decl` grammar element with the initial
-  /// `variable_attribute_list*` provided as `attrs`
-  /// @returns the const object or nullptr
-  /// @param attrs the list of attributes for the constant declaration.
-  Maybe<const ast::Variable*> global_constant_decl(ast::AttributeList& attrs);
-  /// Parses a `variable_decl` grammar element
-  /// @param allow_inferred if true, do not fail if variable decl does not
-  /// specify type
-  /// @returns the parsed variable declaration info
-  Maybe<VarDeclInfo> variable_decl(bool allow_inferred = false);
-  /// Parses a `variable_ident_decl` grammar element, erroring on parse
-  /// failure.
-  /// @param use a description of what was being parsed if an error was raised.
-  /// @param allow_inferred if true, do not fail if variable decl does not
-  /// specify type
-  /// @returns the identifier and type parsed or empty otherwise
-  Expect<TypedIdentifier> expect_variable_ident_decl(
-      std::string_view use,
-      bool allow_inferred = false);
-  /// Parses a `variable_qualifier` grammar element
-  /// @returns the variable qualifier information
-  Maybe<VariableQualifier> variable_qualifier();
-  /// Parses a `type_alias` grammar element
-  /// @returns the type alias or nullptr on error
-  Maybe<const ast::Alias*> type_alias();
-  /// Parses a `type_decl` grammar element
-  /// @returns the parsed Type or nullptr if none matched.
-  Maybe<const ast::Type*> type_decl();
-  /// Parses a `storage_class` grammar element, erroring on parse failure.
-  /// @param use a description of what was being parsed if an error was raised.
-  /// @returns the storage class or StorageClass::kNone if none matched
-  Expect<ast::StorageClass> expect_storage_class(std::string_view use);
-  /// Parses a `struct_decl` grammar element.
-  /// @returns the struct type or nullptr on error
-  Maybe<const ast::Struct*> struct_decl();
-  /// Parses a `struct_body_decl` grammar element, erroring on parse failure.
-  /// @returns the struct members
-  Expect<ast::StructMemberList> expect_struct_body_decl();
-  /// Parses a `struct_member` grammar element, erroring on parse failure.
-  /// @returns the struct member or nullptr
-  Expect<ast::StructMember*> expect_struct_member();
-  /// Parses a `function_decl` grammar element with the initial
-  /// `function_attribute_decl*` provided as `attrs`.
-  /// @param attrs the list of attributes for the function declaration.
-  /// @returns the parsed function, nullptr otherwise
-  Maybe<const ast::Function*> function_decl(ast::AttributeList& attrs);
-  /// Parses a `texture_sampler_types` grammar element
-  /// @returns the parsed Type or nullptr if none matched.
-  Maybe<const ast::Type*> texture_sampler_types();
-  /// Parses a `sampler_type` grammar element
-  /// @returns the parsed Type or nullptr if none matched.
-  Maybe<const ast::Type*> sampler_type();
-  /// Parses a `multisampled_texture_type` grammar element
-  /// @returns returns the multisample texture dimension or kNone if none
-  /// matched.
-  Maybe<const ast::TextureDimension> multisampled_texture_type();
-  /// Parses a `sampled_texture_type` grammar element
-  /// @returns returns the sample texture dimension or kNone if none matched.
-  Maybe<const ast::TextureDimension> sampled_texture_type();
-  /// Parses a `storage_texture_type` grammar element
-  /// @returns returns the storage texture dimension.
-  /// Returns kNone if none matched.
-  Maybe<const ast::TextureDimension> storage_texture_type();
-  /// Parses a `depth_texture_type` grammar element
-  /// @returns the parsed Type or nullptr if none matched.
-  Maybe<const ast::Type*> depth_texture_type();
-  /// Parses a 'texture_external_type' grammar element
-  /// @returns the parsed Type or nullptr if none matched
-  Maybe<const ast::Type*> external_texture_type();
-  /// Parses a `texel_format` grammar element
-  /// @param use a description of what was being parsed if an error was raised
-  /// @returns returns the texel format or kNone if none matched.
-  Expect<ast::TexelFormat> expect_texel_format(std::string_view use);
-  /// Parses a `function_header` grammar element
-  /// @returns the parsed function header
-  Maybe<FunctionHeader> function_header();
-  /// Parses a `param_list` grammar element, erroring on parse failure.
-  /// @returns the parsed variables
-  Expect<ast::VariableList> expect_param_list();
-  /// Parses a `param` grammar element, erroring on parse failure.
-  /// @returns the parsed variable
-  Expect<ast::Variable*> expect_param();
-  /// Parses a `pipeline_stage` grammar element, erroring if the next token does
-  /// not match a stage name.
-  /// @returns the pipeline stage.
-  Expect<ast::PipelineStage> expect_pipeline_stage();
-  /// Parses an access control identifier, erroring if the next token does not
-  /// match a valid access control.
-  /// @param use a description of what was being parsed if an error was raised
-  /// @returns the parsed access control.
-  Expect<ast::Access> expect_access(std::string_view use);
-  /// 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();
-  /// Parses a `body_stmt` grammar element, erroring on parse failure.
-  /// @returns the parsed statements
-  Expect<ast::BlockStatement*> expect_body_stmt();
-  /// Parses a `paren_rhs_stmt` grammar element, erroring on parse failure.
-  /// @returns the parsed element or nullptr
-  Expect<const ast::Expression*> expect_paren_rhs_stmt();
-  /// Parses a `statements` grammar element
-  /// @returns the statements parsed
-  Expect<ast::StatementList> expect_statements();
-  /// Parses a `statement` grammar element
-  /// @returns the parsed statement or nullptr
-  Maybe<const ast::Statement*> statement();
-  /// Parses a `break_stmt` grammar element
-  /// @returns the parsed statement or nullptr
-  Maybe<const ast::BreakStatement*> break_stmt();
-  /// Parses a `return_stmt` grammar element
-  /// @returns the parsed statement or nullptr
-  Maybe<const ast::ReturnStatement*> return_stmt();
-  /// Parses a `continue_stmt` grammar element
-  /// @returns the parsed statement or nullptr
-  Maybe<const ast::ContinueStatement*> continue_stmt();
-  /// Parses a `variable_stmt` grammar element
-  /// @returns the parsed variable or nullptr
-  Maybe<const ast::VariableDeclStatement*> variable_stmt();
-  /// Parses a `if_stmt` grammar element
-  /// @returns the parsed statement or nullptr
-  Maybe<const ast::IfStatement*> if_stmt();
-  /// Parses a list of `else_stmt` grammar elements
-  /// @returns the parsed statement or nullptr
-  Expect<ast::ElseStatementList> else_stmts();
-  /// Parses a `switch_stmt` grammar element
-  /// @returns the parsed statement or nullptr
-  Maybe<const ast::SwitchStatement*> switch_stmt();
-  /// Parses a `switch_body` grammar element
-  /// @returns the parsed statement or nullptr
-  Maybe<const ast::CaseStatement*> switch_body();
-  /// Parses a `case_selectors` grammar element
-  /// @returns the list of literals
-  Expect<ast::CaseSelectorList> expect_case_selectors();
-  /// Parses a `case_body` grammar element
-  /// @returns the parsed statements
-  Maybe<const ast::BlockStatement*> case_body();
-  /// Parses a `func_call_stmt` grammar element
-  /// @returns the parsed function call or nullptr
-  Maybe<const ast::CallStatement*> func_call_stmt();
-  /// Parses a `loop_stmt` grammar element
-  /// @returns the parsed loop or nullptr
-  Maybe<const ast::LoopStatement*> loop_stmt();
-  /// Parses a `for_header` grammar element, erroring on parse failure.
-  /// @returns the parsed for header or nullptr
-  Expect<std::unique_ptr<ForHeader>> expect_for_header();
-  /// Parses a `for_stmt` grammar element
-  /// @returns the parsed for loop or nullptr
-  Maybe<const ast::ForLoopStatement*> for_stmt();
-  /// Parses a `continuing_stmt` grammar element
-  /// @returns the parsed statements
-  Maybe<const ast::BlockStatement*> continuing_stmt();
-  /// Parses a `const_literal` grammar element
-  /// @returns the const literal parsed or nullptr if none found
-  Maybe<const ast::LiteralExpression*> const_literal();
-  /// Parses a `const_expr` grammar element, erroring on parse failure.
-  /// @returns the parsed constructor expression or nullptr on error
-  Expect<const ast::Expression*> expect_const_expr();
-  /// Parses a `primary_expression` grammar element
-  /// @returns the parsed expression or nullptr
-  Maybe<const ast::Expression*> primary_expression();
-  /// Parses a `argument_expression_list` grammar element, erroring on parse
-  /// failure.
-  /// @param use a description of what was being parsed if an error was raised
-  /// @returns the list of arguments
-  Expect<ast::ExpressionList> expect_argument_expression_list(
-      std::string_view use);
-  /// Parses the recursive portion of the postfix_expression
-  /// @param prefix the left side of the expression
-  /// @returns the parsed expression or nullptr
-  Maybe<const ast::Expression*> postfix_expression(
-      const ast::Expression* prefix);
-  /// Parses a `singular_expression` grammar elment
-  /// @returns the parsed expression or nullptr
-  Maybe<const ast::Expression*> singular_expression();
-  /// Parses a `unary_expression` grammar element
-  /// @returns the parsed expression or nullptr
-  Maybe<const ast::Expression*> unary_expression();
-  /// Parses the recursive part of the `multiplicative_expression`, erroring on
-  /// parse failure.
-  /// @param lhs the left side of the expression
-  /// @returns the parsed expression or nullptr
-  Expect<const ast::Expression*> expect_multiplicative_expr(
-      const ast::Expression* lhs);
-  /// Parses the `multiplicative_expression` grammar element
-  /// @returns the parsed expression or nullptr
-  Maybe<const ast::Expression*> multiplicative_expression();
-  /// Parses the recursive part of the `additive_expression`, erroring on parse
-  /// failure.
-  /// @param lhs the left side of the expression
-  /// @returns the parsed expression or nullptr
-  Expect<const ast::Expression*> expect_additive_expr(
-      const ast::Expression* lhs);
-  /// Parses the `additive_expression` grammar element
-  /// @returns the parsed expression or nullptr
-  Maybe<const ast::Expression*> additive_expression();
-  /// Parses the recursive part of the `shift_expression`, erroring on parse
-  /// failure.
-  /// @param lhs the left side of the expression
-  /// @returns the parsed expression or nullptr
-  Expect<const ast::Expression*> expect_shift_expr(const ast::Expression* lhs);
-  /// Parses the `shift_expression` grammar element
-  /// @returns the parsed expression or nullptr
-  Maybe<const ast::Expression*> shift_expression();
-  /// Parses the recursive part of the `relational_expression`, erroring on
-  /// parse failure.
-  /// @param lhs the left side of the expression
-  /// @returns the parsed expression or nullptr
-  Expect<const ast::Expression*> expect_relational_expr(
-      const ast::Expression* lhs);
-  /// Parses the `relational_expression` grammar element
-  /// @returns the parsed expression or nullptr
-  Maybe<const ast::Expression*> relational_expression();
-  /// Parses the recursive part of the `equality_expression`, erroring on parse
-  /// failure.
-  /// @param lhs the left side of the expression
-  /// @returns the parsed expression or nullptr
-  Expect<const ast::Expression*> expect_equality_expr(
-      const ast::Expression* lhs);
-  /// Parses the `equality_expression` grammar element
-  /// @returns the parsed expression or nullptr
-  Maybe<const ast::Expression*> equality_expression();
-  /// Parses the recursive part of the `and_expression`, erroring on parse
-  /// failure.
-  /// @param lhs the left side of the expression
-  /// @returns the parsed expression or nullptr
-  Expect<const ast::Expression*> expect_and_expr(const ast::Expression* lhs);
-  /// Parses the `and_expression` grammar element
-  /// @returns the parsed expression or nullptr
-  Maybe<const ast::Expression*> and_expression();
-  /// Parses the recursive part of the `exclusive_or_expression`, erroring on
-  /// parse failure.
-  /// @param lhs the left side of the expression
-  /// @returns the parsed expression or nullptr
-  Expect<const ast::Expression*> expect_exclusive_or_expr(
-      const ast::Expression* lhs);
-  /// Parses the `exclusive_or_expression` grammar elememnt
-  /// @returns the parsed expression or nullptr
-  Maybe<const ast::Expression*> exclusive_or_expression();
-  /// Parses the recursive part of the `inclusive_or_expression`, erroring on
-  /// parse failure.
-  /// @param lhs the left side of the expression
-  /// @returns the parsed expression or nullptr
-  Expect<const ast::Expression*> expect_inclusive_or_expr(
-      const ast::Expression* lhs);
-  /// Parses the `inclusive_or_expression` grammar element
-  /// @returns the parsed expression or nullptr
-  Maybe<const ast::Expression*> inclusive_or_expression();
-  /// Parses the recursive part of the `logical_and_expression`, erroring on
-  /// parse failure.
-  /// @param lhs the left side of the expression
-  /// @returns the parsed expression or nullptr
-  Expect<const ast::Expression*> expect_logical_and_expr(
-      const ast::Expression* lhs);
-  /// Parses a `logical_and_expression` grammar element
-  /// @returns the parsed expression or nullptr
-  Maybe<const ast::Expression*> logical_and_expression();
-  /// Parses the recursive part of the `logical_or_expression`, erroring on
-  /// parse failure.
-  /// @param lhs the left side of the expression
-  /// @returns the parsed expression or nullptr
-  Expect<const ast::Expression*> expect_logical_or_expr(
-      const ast::Expression* lhs);
-  /// Parses a `logical_or_expression` grammar element
-  /// @returns the parsed expression or nullptr
-  Maybe<const ast::Expression*> logical_or_expression();
-  /// Parses a `compound_assignment_operator` grammar element
-  /// @returns the parsed compound assignment operator
-  Maybe<ast::BinaryOp> compound_assignment_operator();
-  /// Parses a `assignment_stmt` grammar element
-  /// @returns the parsed assignment or nullptr
-  Maybe<const ast::Statement*> assignment_stmt();
-  /// Parses one or more attribute lists.
-  /// @return the parsed attribute list, or an empty list on error.
-  Maybe<ast::AttributeList> attribute_list();
-  /// Parses a single attribute of the following types:
-  /// * `struct_attribute`
-  /// * `struct_member_attribute`
-  /// * `array_attribute`
-  /// * `variable_attribute`
-  /// * `global_const_attribute`
-  /// * `function_attribute`
-  /// @return the parsed attribute, or nullptr.
-  Maybe<const ast::Attribute*> attribute();
-  /// Parses a single attribute, reporting an error if the next token does not
-  /// represent a attribute.
-  /// @see #attribute for the full list of attributes this method parses.
-  /// @return the parsed attribute, or nullptr on error.
-  Expect<const ast::Attribute*> expect_attribute();
+    /// sync() calls the function `func`, and attempts to resynchronize the
+    /// parser to the next found resynchronization token if `func` fails. If the
+    /// next found resynchronization token is `tok`, then sync will also consume
+    /// `tok`.
+    ///
+    /// sync() will transiently add `tok` to the parser's stack of
+    /// synchronization tokens for the duration of the call to `func`. Once @p
+    /// func returns,
+    /// `tok` is removed from the stack of resynchronization tokens. sync calls
+    /// may be nested, and so the number of resynchronization tokens is equal to
+    /// the number of sync() calls in the current stack frame.
+    ///
+    /// sync() updates #synchronized_, setting it to `true` if the next
+    /// resynchronization token found was `tok`, otherwise `false`.
+    ///
+    /// @param tok the token to attempt to synchronize the parser to if `func`
+    /// fails.
+    /// @param func a function or lambda with the signature: `Expect<Result>()` or
+    /// `Maybe<Result>()`.
+    /// @return the value returned by `func`
+    template <typename F, typename T = ReturnType<F>>
+    T sync(Token::Type tok, F&& func);
+    /// sync_to() attempts to resynchronize the parser to the next found
+    /// resynchronization token or `tok` (whichever comes first).
+    ///
+    /// Synchronization tokens are transiently defined by calls to sync().
+    ///
+    /// sync_to() updates #synchronized_, setting it to `true` if a
+    /// resynchronization token was found and it was `tok`, otherwise `false`.
+    ///
+    /// @param tok the token to attempt to synchronize the parser to.
+    /// @param consume if true and the next found resynchronization token is
+    /// `tok` then sync_to() will also consume `tok`.
+    /// @return the state of #synchronized_.
+    /// @see sync().
+    bool sync_to(Token::Type tok, bool consume);
+    /// @return true if `t` is in the stack of resynchronization tokens.
+    /// @see sync().
+    bool is_sync_token(const Token& t) const;
 
- private:
-  /// ReturnType resolves to the return type for the function or lambda F.
-  template <typename F>
-  using ReturnType = typename std::invoke_result<F>::type;
+    /// If `t` is an error token, then `synchronized_` is set to false and the
+    /// token's error is appended to the builder's diagnostics. If `t` is not an
+    /// error token, then this function does nothing and false is returned.
+    /// @returns true if `t` is an error, otherwise false.
+    bool handle_error(const Token& t);
 
-  /// ResultType resolves to `T` for a `RESULT` of type Expect<T>.
-  template <typename RESULT>
-  using ResultType = typename RESULT::type;
+    /// @returns true if #synchronized_ is true and the number of reported errors
+    /// is less than #max_errors_.
+    bool continue_parsing() {
+        return synchronized_ && builder_.Diagnostics().error_count() < max_errors_;
+    }
 
-  /// @returns true and consumes the next token if it equals `tok`
-  /// @param source if not nullptr, the next token's source is written to this
-  /// pointer, regardless of success or error
-  bool match(Token::Type tok, Source* source = nullptr);
-  /// Errors if the next token is not equal to `tok`
-  /// Consumes the next token on match.
-  /// expect() also updates #synchronized_, setting it to `true` if the next
-  /// token is equal to `tok`, otherwise `false`.
-  /// @param use a description of what was being parsed if an error was raised.
-  /// @param tok the token to test against
-  /// @returns true if the next token equals `tok`
-  bool expect(std::string_view use, Token::Type tok);
-  /// Parses a signed integer from the next token in the stream, erroring if the
-  /// next token is not a signed integer.
-  /// Consumes the next token on match.
-  /// @param use a description of what was being parsed if an error was raised
-  /// @returns the parsed integer.
-  Expect<int32_t> expect_sint(std::string_view use);
-  /// Parses a signed integer from the next token in the stream, erroring if
-  /// the next token is not a signed integer or is negative.
-  /// Consumes the next token if it is a signed integer (not necessarily
-  /// negative).
-  /// @param use a description of what was being parsed if an error was raised
-  /// @returns the parsed integer.
-  Expect<uint32_t> expect_positive_sint(std::string_view use);
-  /// Parses a non-zero signed integer from the next token in the stream,
-  /// erroring if the next token is not a signed integer or is less than 1.
-  /// Consumes the next token if it is a signed integer (not necessarily
-  /// >= 1).
-  /// @param use a description of what was being parsed if an error was raised
-  /// @returns the parsed integer.
-  Expect<uint32_t> expect_nonzero_positive_sint(std::string_view use);
-  /// Errors if the next token is not an identifier.
-  /// Consumes the next token on match.
-  /// @param use a description of what was being parsed if an error was raised
-  /// @returns the parsed identifier.
-  Expect<std::string> expect_ident(std::string_view use);
-  /// Parses a lexical block starting with the token `start` and ending with
-  /// the token `end`. `body` is called to parse the lexical block body
-  /// between the `start` and `end` tokens. If the `start` or `end` tokens
-  /// are not matched then an error is generated and a zero-initialized `T` is
-  /// returned. If `body` raises an error while parsing then a zero-initialized
-  /// `T` is returned.
-  /// @param start the token that begins the lexical block
-  /// @param end the token that ends the lexical block
-  /// @param use a description of what was being parsed if an error was raised
-  /// @param body a function or lambda that is called to parse the lexical block
-  /// body, with the signature: `Expect<Result>()` or `Maybe<Result>()`.
-  /// @return the value returned by `body` if no errors are raised, otherwise
-  /// an Expect with error state.
-  template <typename F, typename T = ReturnType<F>>
-  T expect_block(Token::Type start,
-                 Token::Type end,
-                 std::string_view use,
-                 F&& body);
-  /// A convenience function that calls expect_block() passing
-  /// `Token::Type::kParenLeft` and `Token::Type::kParenRight` for the `start`
-  /// and `end` arguments, respectively.
-  /// @param use a description of what was being parsed if an error was raised
-  /// @param body a function or lambda that is called to parse the lexical block
-  /// body, with the signature: `Expect<Result>()` or `Maybe<Result>()`.
-  /// @return the value returned by `body` if no errors are raised, otherwise
-  /// an Expect with error state.
-  template <typename F, typename T = ReturnType<F>>
-  T expect_paren_block(std::string_view use, F&& body);
-  /// A convenience function that calls `expect_block` passing
-  /// `Token::Type::kBraceLeft` and `Token::Type::kBraceRight` for the `start`
-  /// and `end` arguments, respectively.
-  /// @param use a description of what was being parsed if an error was raised
-  /// @param body a function or lambda that is called to parse the lexical block
-  /// body, with the signature: `Expect<Result>()` or `Maybe<Result>()`.
-  /// @return the value returned by `body` if no errors are raised, otherwise
-  /// an Expect with error state.
-  template <typename F, typename T = ReturnType<F>>
-  T expect_brace_block(std::string_view use, F&& body);
-  /// A convenience function that calls `expect_block` passing
-  /// `Token::Type::kLessThan` and `Token::Type::kGreaterThan` for the `start`
-  /// and `end` arguments, respectively.
-  /// @param use a description of what was being parsed if an error was raised
-  /// @param body a function or lambda that is called to parse the lexical block
-  /// body, with the signature: `Expect<Result>()` or `Maybe<Result>()`.
-  /// @return the value returned by `body` if no errors are raised, otherwise
-  /// an Expect with error state.
-  template <typename F, typename T = ReturnType<F>>
-  T expect_lt_gt_block(std::string_view use, F&& body);
+    /// without_error() calls the function `func` muting any grammatical errors
+    /// found while executing the function. This can be used as a best-effort to
+    /// produce a meaningful error message when the parser is out of sync.
+    /// @param func a function or lambda with the signature: `Expect<Result>()` or
+    /// `Maybe<Result>()`.
+    /// @return the value returned by `func`
+    template <typename F, typename T = ReturnType<F>>
+    T without_error(F&& func);
 
-  /// sync() calls the function `func`, and attempts to resynchronize the
-  /// parser to the next found resynchronization token if `func` fails. If the
-  /// next found resynchronization token is `tok`, then sync will also consume
-  /// `tok`.
-  ///
-  /// sync() will transiently add `tok` to the parser's stack of
-  /// synchronization tokens for the duration of the call to `func`. Once @p
-  /// func returns,
-  /// `tok` is removed from the stack of resynchronization tokens. sync calls
-  /// may be nested, and so the number of resynchronization tokens is equal to
-  /// the number of sync() calls in the current stack frame.
-  ///
-  /// sync() updates #synchronized_, setting it to `true` if the next
-  /// resynchronization token found was `tok`, otherwise `false`.
-  ///
-  /// @param tok the token to attempt to synchronize the parser to if `func`
-  /// fails.
-  /// @param func a function or lambda with the signature: `Expect<Result>()` or
-  /// `Maybe<Result>()`.
-  /// @return the value returned by `func`
-  template <typename F, typename T = ReturnType<F>>
-  T sync(Token::Type tok, F&& func);
-  /// sync_to() attempts to resynchronize the parser to the next found
-  /// resynchronization token or `tok` (whichever comes first).
-  ///
-  /// Synchronization tokens are transiently defined by calls to sync().
-  ///
-  /// sync_to() updates #synchronized_, setting it to `true` if a
-  /// resynchronization token was found and it was `tok`, otherwise `false`.
-  ///
-  /// @param tok the token to attempt to synchronize the parser to.
-  /// @param consume if true and the next found resynchronization token is
-  /// `tok` then sync_to() will also consume `tok`.
-  /// @return the state of #synchronized_.
-  /// @see sync().
-  bool sync_to(Token::Type tok, bool consume);
-  /// @return true if `t` is in the stack of resynchronization tokens.
-  /// @see sync().
-  bool is_sync_token(const Token& t) const;
+    /// Reports an error if the attribute list `list` is not empty.
+    /// Used to ensure that all attributes are consumed.
+    bool expect_attributes_consumed(ast::AttributeList& list);
 
-  /// If `t` is an error token, then `synchronized_` is set to false and the
-  /// token's error is appended to the builder's diagnostics. If `t` is not an
-  /// error token, then this function does nothing and false is returned.
-  /// @returns true if `t` is an error, otherwise false.
-  bool handle_error(const Token& t);
+    Expect<const ast::Type*> expect_type_decl_pointer(Token t);
+    Expect<const ast::Type*> expect_type_decl_atomic(Token t);
+    Expect<const ast::Type*> expect_type_decl_vector(Token t);
+    Expect<const ast::Type*> expect_type_decl_array(Token t);
+    Expect<const ast::Type*> expect_type_decl_matrix(Token t);
 
-  /// @returns true if #synchronized_ is true and the number of reported errors
-  /// is less than #max_errors_.
-  bool continue_parsing() {
-    return synchronized_ && builder_.Diagnostics().error_count() < max_errors_;
-  }
+    Expect<const ast::Type*> expect_type(std::string_view use);
 
-  /// without_error() calls the function `func` muting any grammatical errors
-  /// found while executing the function. This can be used as a best-effort to
-  /// produce a meaningful error message when the parser is out of sync.
-  /// @param func a function or lambda with the signature: `Expect<Result>()` or
-  /// `Maybe<Result>()`.
-  /// @return the value returned by `func`
-  template <typename F, typename T = ReturnType<F>>
-  T without_error(F&& func);
+    Maybe<const ast::Statement*> non_block_statement();
+    Maybe<const ast::Statement*> for_header_initializer();
+    Maybe<const ast::Statement*> for_header_continuing();
 
-  /// Reports an error if the attribute list `list` is not empty.
-  /// Used to ensure that all attributes are consumed.
-  bool expect_attributes_consumed(ast::AttributeList& list);
+    class MultiTokenSource;
+    MultiTokenSource make_source_range();
+    MultiTokenSource make_source_range_from(const Source& start);
 
-  Expect<const ast::Type*> expect_type_decl_pointer(Token t);
-  Expect<const ast::Type*> expect_type_decl_atomic(Token t);
-  Expect<const ast::Type*> expect_type_decl_vector(Token t);
-  Expect<const ast::Type*> expect_type_decl_array(Token t);
-  Expect<const ast::Type*> expect_type_decl_matrix(Token t);
+    /// Creates a new `ast::Node` owned by the Module. When the Module is
+    /// destructed, the `ast::Node` will also be destructed.
+    /// @param args the arguments to pass to the type constructor
+    /// @returns the node pointer
+    template <typename T, typename... ARGS>
+    T* create(ARGS&&... args) {
+        return builder_.create<T>(std::forward<ARGS>(args)...);
+    }
 
-  Expect<const ast::Type*> expect_type(std::string_view use);
-
-  Maybe<const ast::Statement*> non_block_statement();
-  Maybe<const ast::Statement*> for_header_initializer();
-  Maybe<const ast::Statement*> for_header_continuing();
-
-  class MultiTokenSource;
-  MultiTokenSource make_source_range();
-  MultiTokenSource make_source_range_from(const Source& start);
-
-  /// Creates a new `ast::Node` owned by the Module. When the Module is
-  /// destructed, the `ast::Node` will also be destructed.
-  /// @param args the arguments to pass to the type constructor
-  /// @returns the node pointer
-  template <typename T, typename... ARGS>
-  T* create(ARGS&&... args) {
-    return builder_.create<T>(std::forward<ARGS>(args)...);
-  }
-
-  std::unique_ptr<Lexer> lexer_;
-  std::deque<Token> token_queue_;
-  Token last_token_;
-  bool synchronized_ = true;
-  uint32_t parse_depth_ = 0;
-  std::vector<Token::Type> sync_tokens_;
-  int silence_errors_ = 0;
-  ProgramBuilder builder_;
-  size_t max_errors_ = 25;
+    std::unique_ptr<Lexer> lexer_;
+    std::deque<Token> token_queue_;
+    Token last_token_;
+    bool synchronized_ = true;
+    uint32_t parse_depth_ = 0;
+    std::vector<Token::Type> sync_tokens_;
+    int silence_errors_ = 0;
+    ProgramBuilder builder_;
+    size_t max_errors_ = 25;
 };
 
 }  // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/parser_impl_additive_expression_test.cc b/src/tint/reader/wgsl/parser_impl_additive_expression_test.cc
index b189a52..51cf90e 100644
--- a/src/tint/reader/wgsl/parser_impl_additive_expression_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_additive_expression_test.cc
@@ -18,72 +18,72 @@
 namespace {
 
 TEST_F(ParserImplTest, AdditiveExpression_Parses_Plus) {
-  auto p = parser("a + true");
-  auto e = p->additive_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("a + true");
+    auto e = p->additive_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e->Is<ast::BinaryExpression>());
-  auto* rel = e->As<ast::BinaryExpression>();
-  EXPECT_EQ(ast::BinaryOp::kAdd, rel->op);
+    ASSERT_TRUE(e->Is<ast::BinaryExpression>());
+    auto* rel = e->As<ast::BinaryExpression>();
+    EXPECT_EQ(ast::BinaryOp::kAdd, rel->op);
 
-  ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
-  auto* ident = rel->lhs->As<ast::IdentifierExpression>();
-  EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
+    ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
+    auto* ident = rel->lhs->As<ast::IdentifierExpression>();
+    EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
-  ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
+    ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
+    ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
 }
 
 TEST_F(ParserImplTest, AdditiveExpression_Parses_Minus) {
-  auto p = parser("a - true");
-  auto e = p->additive_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("a - true");
+    auto e = p->additive_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e->Is<ast::BinaryExpression>());
-  auto* rel = e->As<ast::BinaryExpression>();
-  EXPECT_EQ(ast::BinaryOp::kSubtract, rel->op);
+    ASSERT_TRUE(e->Is<ast::BinaryExpression>());
+    auto* rel = e->As<ast::BinaryExpression>();
+    EXPECT_EQ(ast::BinaryOp::kSubtract, rel->op);
 
-  ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
-  auto* ident = rel->lhs->As<ast::IdentifierExpression>();
-  EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
+    ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
+    auto* ident = rel->lhs->As<ast::IdentifierExpression>();
+    EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
-  ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
+    ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
+    ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
 }
 
 TEST_F(ParserImplTest, AdditiveExpression_InvalidLHS) {
-  auto p = parser("if (a) {} + true");
-  auto e = p->additive_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_EQ(e.value, nullptr);
+    auto p = parser("if (a) {} + true");
+    auto e = p->additive_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_EQ(e.value, nullptr);
 }
 
 TEST_F(ParserImplTest, AdditiveExpression_InvalidRHS) {
-  auto p = parser("true + if (a) {}");
-  auto e = p->additive_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:8: unable to parse right side of + expression");
+    auto p = parser("true + if (a) {}");
+    auto e = p->additive_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:8: unable to parse right side of + expression");
 }
 
 TEST_F(ParserImplTest, AdditiveExpression_NoOr_ReturnsLHS) {
-  auto p = parser("a true");
-  auto e = p->additive_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::IdentifierExpression>());
+    auto p = parser("a true");
+    auto e = p->additive_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::IdentifierExpression>());
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_and_expression_test.cc b/src/tint/reader/wgsl/parser_impl_and_expression_test.cc
index 6283cd4..1ed8a9c 100644
--- a/src/tint/reader/wgsl/parser_impl_and_expression_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_and_expression_test.cc
@@ -18,52 +18,52 @@
 namespace {
 
 TEST_F(ParserImplTest, AndExpression_Parses) {
-  auto p = parser("a & true");
-  auto e = p->and_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("a & true");
+    auto e = p->and_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e->Is<ast::BinaryExpression>());
-  auto* rel = e->As<ast::BinaryExpression>();
-  EXPECT_EQ(ast::BinaryOp::kAnd, rel->op);
+    ASSERT_TRUE(e->Is<ast::BinaryExpression>());
+    auto* rel = e->As<ast::BinaryExpression>();
+    EXPECT_EQ(ast::BinaryOp::kAnd, rel->op);
 
-  ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
-  auto* ident = rel->lhs->As<ast::IdentifierExpression>();
-  EXPECT_EQ(ident->symbol, p->builder().Symbols().Register("a"));
+    ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
+    auto* ident = rel->lhs->As<ast::IdentifierExpression>();
+    EXPECT_EQ(ident->symbol, p->builder().Symbols().Register("a"));
 
-  ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
-  ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
+    ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
+    ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
 }
 
 TEST_F(ParserImplTest, AndExpression_InvalidLHS) {
-  auto p = parser("if (a) {} & true");
-  auto e = p->and_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_EQ(e.value, nullptr);
+    auto p = parser("if (a) {} & true");
+    auto e = p->and_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_EQ(e.value, nullptr);
 }
 
 TEST_F(ParserImplTest, AndExpression_InvalidRHS) {
-  auto p = parser("true & if (a) {}");
-  auto e = p->and_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:8: unable to parse right side of & expression");
+    auto p = parser("true & if (a) {}");
+    auto e = p->and_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:8: unable to parse right side of & expression");
 }
 
 TEST_F(ParserImplTest, AndExpression_NoOr_ReturnsLHS) {
-  auto p = parser("a true");
-  auto e = p->and_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::IdentifierExpression>());
+    auto p = parser("a true");
+    auto e = p->and_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::IdentifierExpression>());
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_argument_expression_list_test.cc b/src/tint/reader/wgsl/parser_impl_argument_expression_list_test.cc
index 6d29897..3042c20 100644
--- a/src/tint/reader/wgsl/parser_impl_argument_expression_list_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_argument_expression_list_test.cc
@@ -18,85 +18,85 @@
 namespace {
 
 TEST_F(ParserImplTest, ArgumentExpressionList_Parses) {
-  auto p = parser("(a)");
-  auto e = p->expect_argument_expression_list("argument list");
-  ASSERT_FALSE(p->has_error()) << p->error();
-  ASSERT_FALSE(e.errored);
+    auto p = parser("(a)");
+    auto e = p->expect_argument_expression_list("argument list");
+    ASSERT_FALSE(p->has_error()) << p->error();
+    ASSERT_FALSE(e.errored);
 
-  ASSERT_EQ(e.value.size(), 1u);
-  ASSERT_TRUE(e.value[0]->Is<ast::IdentifierExpression>());
+    ASSERT_EQ(e.value.size(), 1u);
+    ASSERT_TRUE(e.value[0]->Is<ast::IdentifierExpression>());
 }
 
 TEST_F(ParserImplTest, ArgumentExpressionList_ParsesEmptyList) {
-  auto p = parser("()");
-  auto e = p->expect_argument_expression_list("argument list");
-  ASSERT_FALSE(p->has_error()) << p->error();
-  ASSERT_FALSE(e.errored);
+    auto p = parser("()");
+    auto e = p->expect_argument_expression_list("argument list");
+    ASSERT_FALSE(p->has_error()) << p->error();
+    ASSERT_FALSE(e.errored);
 
-  ASSERT_EQ(e.value.size(), 0u);
+    ASSERT_EQ(e.value.size(), 0u);
 }
 
 TEST_F(ParserImplTest, ArgumentExpressionList_ParsesMultiple) {
-  auto p = parser("(a, -33, 1+2)");
-  auto e = p->expect_argument_expression_list("argument list");
-  ASSERT_FALSE(p->has_error()) << p->error();
-  ASSERT_FALSE(e.errored);
+    auto p = parser("(a, -33, 1+2)");
+    auto e = p->expect_argument_expression_list("argument list");
+    ASSERT_FALSE(p->has_error()) << p->error();
+    ASSERT_FALSE(e.errored);
 
-  ASSERT_EQ(e.value.size(), 3u);
-  ASSERT_TRUE(e.value[0]->Is<ast::IdentifierExpression>());
-  ASSERT_TRUE(e.value[1]->Is<ast::LiteralExpression>());
-  ASSERT_TRUE(e.value[2]->Is<ast::BinaryExpression>());
+    ASSERT_EQ(e.value.size(), 3u);
+    ASSERT_TRUE(e.value[0]->Is<ast::IdentifierExpression>());
+    ASSERT_TRUE(e.value[1]->Is<ast::LiteralExpression>());
+    ASSERT_TRUE(e.value[2]->Is<ast::BinaryExpression>());
 }
 
 TEST_F(ParserImplTest, ArgumentExpressionList_TrailingComma) {
-  auto p = parser("(a, 42,)");
-  auto e = p->expect_argument_expression_list("argument list");
-  ASSERT_FALSE(p->has_error()) << p->error();
-  ASSERT_FALSE(e.errored);
+    auto p = parser("(a, 42,)");
+    auto e = p->expect_argument_expression_list("argument list");
+    ASSERT_FALSE(p->has_error()) << p->error();
+    ASSERT_FALSE(e.errored);
 
-  ASSERT_EQ(e.value.size(), 2u);
-  ASSERT_TRUE(e.value[0]->Is<ast::IdentifierExpression>());
-  ASSERT_TRUE(e.value[1]->Is<ast::LiteralExpression>());
+    ASSERT_EQ(e.value.size(), 2u);
+    ASSERT_TRUE(e.value[0]->Is<ast::IdentifierExpression>());
+    ASSERT_TRUE(e.value[1]->Is<ast::LiteralExpression>());
 }
 
 TEST_F(ParserImplTest, ArgumentExpressionList_HandlesMissingLeftParen) {
-  auto p = parser("a)");
-  auto e = p->expect_argument_expression_list("argument list");
-  ASSERT_TRUE(p->has_error());
-  ASSERT_TRUE(e.errored);
-  EXPECT_EQ(p->error(), "1:1: expected '(' for argument list");
+    auto p = parser("a)");
+    auto e = p->expect_argument_expression_list("argument list");
+    ASSERT_TRUE(p->has_error());
+    ASSERT_TRUE(e.errored);
+    EXPECT_EQ(p->error(), "1:1: expected '(' for argument list");
 }
 
 TEST_F(ParserImplTest, ArgumentExpressionList_HandlesMissingRightParen) {
-  auto p = parser("(a");
-  auto e = p->expect_argument_expression_list("argument list");
-  ASSERT_TRUE(p->has_error());
-  ASSERT_TRUE(e.errored);
-  EXPECT_EQ(p->error(), "1:3: expected ')' for argument list");
+    auto p = parser("(a");
+    auto e = p->expect_argument_expression_list("argument list");
+    ASSERT_TRUE(p->has_error());
+    ASSERT_TRUE(e.errored);
+    EXPECT_EQ(p->error(), "1:3: expected ')' for argument list");
 }
 
 TEST_F(ParserImplTest, ArgumentExpressionList_HandlesMissingExpression_0) {
-  auto p = parser("(,)");
-  auto e = p->expect_argument_expression_list("argument list");
-  ASSERT_TRUE(p->has_error());
-  ASSERT_TRUE(e.errored);
-  EXPECT_EQ(p->error(), "1:2: expected ')' for argument list");
+    auto p = parser("(,)");
+    auto e = p->expect_argument_expression_list("argument list");
+    ASSERT_TRUE(p->has_error());
+    ASSERT_TRUE(e.errored);
+    EXPECT_EQ(p->error(), "1:2: expected ')' for argument list");
 }
 
 TEST_F(ParserImplTest, ArgumentExpressionList_HandlesMissingExpression_1) {
-  auto p = parser("(a, ,)");
-  auto e = p->expect_argument_expression_list("argument list");
-  ASSERT_TRUE(p->has_error());
-  ASSERT_TRUE(e.errored);
-  EXPECT_EQ(p->error(), "1:5: expected ')' for argument list");
+    auto p = parser("(a, ,)");
+    auto e = p->expect_argument_expression_list("argument list");
+    ASSERT_TRUE(p->has_error());
+    ASSERT_TRUE(e.errored);
+    EXPECT_EQ(p->error(), "1:5: expected ')' for argument list");
 }
 
 TEST_F(ParserImplTest, ArgumentExpressionList_HandlesInvalidExpression) {
-  auto p = parser("(if(a) {})");
-  auto e = p->expect_argument_expression_list("argument list");
-  ASSERT_TRUE(p->has_error());
-  ASSERT_TRUE(e.errored);
-  EXPECT_EQ(p->error(), "1:2: expected ')' for argument list");
+    auto p = parser("(if(a) {})");
+    auto e = p->expect_argument_expression_list("argument list");
+    ASSERT_TRUE(p->has_error());
+    ASSERT_TRUE(e.errored);
+    EXPECT_EQ(p->error(), "1:2: expected ')' for argument list");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_assignment_stmt_test.cc b/src/tint/reader/wgsl/parser_impl_assignment_stmt_test.cc
index 2f1d405..4fd23ce 100644
--- a/src/tint/reader/wgsl/parser_impl_assignment_stmt_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_assignment_stmt_test.cc
@@ -18,162 +18,170 @@
 namespace {
 
 TEST_F(ParserImplTest, AssignmentStmt_Parses_ToVariable) {
-  auto p = parser("a = 123");
-  auto e = p->assignment_stmt();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("a = 123");
+    auto e = p->assignment_stmt();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  auto* a = e->As<ast::AssignmentStatement>();
-  ASSERT_NE(a, nullptr);
-  ASSERT_NE(a->lhs, nullptr);
-  ASSERT_NE(a->rhs, nullptr);
+    auto* a = e->As<ast::AssignmentStatement>();
+    ASSERT_NE(a, nullptr);
+    ASSERT_NE(a->lhs, nullptr);
+    ASSERT_NE(a->rhs, nullptr);
 
-  ASSERT_TRUE(a->lhs->Is<ast::IdentifierExpression>());
-  auto* ident = a->lhs->As<ast::IdentifierExpression>();
-  EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
+    ASSERT_TRUE(a->lhs->Is<ast::IdentifierExpression>());
+    auto* ident = a->lhs->As<ast::IdentifierExpression>();
+    EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_TRUE(a->rhs->Is<ast::SintLiteralExpression>());
-  EXPECT_EQ(a->rhs->As<ast::SintLiteralExpression>()->value, 123);
+    ASSERT_TRUE(a->rhs->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(a->rhs->As<ast::IntLiteralExpression>()->value, 123);
+    EXPECT_EQ(a->rhs->As<ast::IntLiteralExpression>()->suffix,
+              ast::IntLiteralExpression::Suffix::kNone);
 }
 
 TEST_F(ParserImplTest, AssignmentStmt_Parses_ToMember) {
-  auto p = parser("a.b.c[2].d = 123");
-  auto e = p->assignment_stmt();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("a.b.c[2].d = 123");
+    auto e = p->assignment_stmt();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  auto* a = e->As<ast::AssignmentStatement>();
-  ASSERT_NE(a, nullptr);
-  ASSERT_NE(a->lhs, nullptr);
-  ASSERT_NE(a->rhs, nullptr);
+    auto* a = e->As<ast::AssignmentStatement>();
+    ASSERT_NE(a, nullptr);
+    ASSERT_NE(a->lhs, nullptr);
+    ASSERT_NE(a->rhs, nullptr);
 
-  ASSERT_TRUE(a->rhs->Is<ast::SintLiteralExpression>());
-  EXPECT_EQ(a->rhs->As<ast::SintLiteralExpression>()->value, 123);
+    ASSERT_TRUE(a->rhs->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(a->rhs->As<ast::IntLiteralExpression>()->value, 123);
+    EXPECT_EQ(a->rhs->As<ast::IntLiteralExpression>()->suffix,
+              ast::IntLiteralExpression::Suffix::kNone);
 
-  ASSERT_TRUE(a->lhs->Is<ast::MemberAccessorExpression>());
-  auto* mem = a->lhs->As<ast::MemberAccessorExpression>();
+    ASSERT_TRUE(a->lhs->Is<ast::MemberAccessorExpression>());
+    auto* mem = a->lhs->As<ast::MemberAccessorExpression>();
 
-  ASSERT_TRUE(mem->member->Is<ast::IdentifierExpression>());
-  auto* ident = mem->member->As<ast::IdentifierExpression>();
-  EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("d"));
+    ASSERT_TRUE(mem->member->Is<ast::IdentifierExpression>());
+    auto* ident = mem->member->As<ast::IdentifierExpression>();
+    EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("d"));
 
-  ASSERT_TRUE(mem->structure->Is<ast::IndexAccessorExpression>());
-  auto* idx = mem->structure->As<ast::IndexAccessorExpression>();
+    ASSERT_TRUE(mem->structure->Is<ast::IndexAccessorExpression>());
+    auto* idx = mem->structure->As<ast::IndexAccessorExpression>();
 
-  ASSERT_NE(idx->index, nullptr);
-  ASSERT_TRUE(idx->index->Is<ast::SintLiteralExpression>());
-  EXPECT_EQ(idx->index->As<ast::SintLiteralExpression>()->value, 2);
+    ASSERT_NE(idx->index, nullptr);
+    ASSERT_TRUE(idx->index->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(idx->index->As<ast::IntLiteralExpression>()->value, 2);
 
-  ASSERT_TRUE(idx->object->Is<ast::MemberAccessorExpression>());
-  mem = idx->object->As<ast::MemberAccessorExpression>();
-  ASSERT_TRUE(mem->member->Is<ast::IdentifierExpression>());
-  ident = mem->member->As<ast::IdentifierExpression>();
-  EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("c"));
+    ASSERT_TRUE(idx->object->Is<ast::MemberAccessorExpression>());
+    mem = idx->object->As<ast::MemberAccessorExpression>();
+    ASSERT_TRUE(mem->member->Is<ast::IdentifierExpression>());
+    ident = mem->member->As<ast::IdentifierExpression>();
+    EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("c"));
 
-  ASSERT_TRUE(mem->structure->Is<ast::MemberAccessorExpression>());
-  mem = mem->structure->As<ast::MemberAccessorExpression>();
+    ASSERT_TRUE(mem->structure->Is<ast::MemberAccessorExpression>());
+    mem = mem->structure->As<ast::MemberAccessorExpression>();
 
-  ASSERT_TRUE(mem->structure->Is<ast::IdentifierExpression>());
-  ident = mem->structure->As<ast::IdentifierExpression>();
-  EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
+    ASSERT_TRUE(mem->structure->Is<ast::IdentifierExpression>());
+    ident = mem->structure->As<ast::IdentifierExpression>();
+    EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_TRUE(mem->member->Is<ast::IdentifierExpression>());
-  ident = mem->member->As<ast::IdentifierExpression>();
-  EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("b"));
+    ASSERT_TRUE(mem->member->Is<ast::IdentifierExpression>());
+    ident = mem->member->As<ast::IdentifierExpression>();
+    EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("b"));
 }
 
 TEST_F(ParserImplTest, AssignmentStmt_Parses_ToPhony) {
-  auto p = parser("_ = 123");
-  auto e = p->assignment_stmt();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("_ = 123i");
+    auto e = p->assignment_stmt();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  auto* a = e->As<ast::AssignmentStatement>();
-  ASSERT_NE(a, nullptr);
-  ASSERT_NE(a->lhs, nullptr);
-  ASSERT_NE(a->rhs, nullptr);
+    auto* a = e->As<ast::AssignmentStatement>();
+    ASSERT_NE(a, nullptr);
+    ASSERT_NE(a->lhs, nullptr);
+    ASSERT_NE(a->rhs, nullptr);
 
-  ASSERT_TRUE(a->rhs->Is<ast::SintLiteralExpression>());
-  EXPECT_EQ(a->rhs->As<ast::SintLiteralExpression>()->value, 123);
+    ASSERT_TRUE(a->rhs->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(a->rhs->As<ast::IntLiteralExpression>()->value, 123);
+    EXPECT_EQ(a->rhs->As<ast::IntLiteralExpression>()->suffix,
+              ast::IntLiteralExpression::Suffix::kI);
 
-  ASSERT_TRUE(a->lhs->Is<ast::PhonyExpression>());
+    ASSERT_TRUE(a->lhs->Is<ast::PhonyExpression>());
 }
 
 TEST_F(ParserImplTest, AssignmentStmt_Parses_CompoundOp) {
-  auto p = parser("a += 123");
-  auto e = p->assignment_stmt();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("a += 123u");
+    auto e = p->assignment_stmt();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  auto* a = e->As<ast::CompoundAssignmentStatement>();
-  ASSERT_NE(a, nullptr);
-  ASSERT_NE(a->lhs, nullptr);
-  ASSERT_NE(a->rhs, nullptr);
-  EXPECT_EQ(a->op, ast::BinaryOp::kAdd);
+    auto* a = e->As<ast::CompoundAssignmentStatement>();
+    ASSERT_NE(a, nullptr);
+    ASSERT_NE(a->lhs, nullptr);
+    ASSERT_NE(a->rhs, nullptr);
+    EXPECT_EQ(a->op, ast::BinaryOp::kAdd);
 
-  ASSERT_TRUE(a->lhs->Is<ast::IdentifierExpression>());
-  auto* ident = a->lhs->As<ast::IdentifierExpression>();
-  EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
+    ASSERT_TRUE(a->lhs->Is<ast::IdentifierExpression>());
+    auto* ident = a->lhs->As<ast::IdentifierExpression>();
+    EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_TRUE(a->rhs->Is<ast::SintLiteralExpression>());
-  EXPECT_EQ(a->rhs->As<ast::SintLiteralExpression>()->value, 123);
+    ASSERT_TRUE(a->rhs->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(a->rhs->As<ast::IntLiteralExpression>()->value, 123);
+    EXPECT_EQ(a->rhs->As<ast::IntLiteralExpression>()->suffix,
+              ast::IntLiteralExpression::Suffix::kU);
 }
 
 TEST_F(ParserImplTest, AssignmentStmt_MissingEqual) {
-  auto p = parser("a.b.c[2].d 123");
-  auto e = p->assignment_stmt();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:12: expected '=' for assignment");
+    auto p = parser("a.b.c[2].d 123");
+    auto e = p->assignment_stmt();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:12: expected '=' for assignment");
 }
 
 TEST_F(ParserImplTest, AssignmentStmt_Compound_MissingEqual) {
-  auto p = parser("a + 123");
-  auto e = p->assignment_stmt();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:3: expected '=' for assignment");
+    auto p = parser("a + 123");
+    auto e = p->assignment_stmt();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:3: expected '=' for assignment");
 }
 
 TEST_F(ParserImplTest, AssignmentStmt_InvalidLHS) {
-  auto p = parser("if (true) {} = 123");
-  auto e = p->assignment_stmt();
-  EXPECT_FALSE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_EQ(e.value, nullptr);
+    auto p = parser("if (true) {} = 123");
+    auto e = p->assignment_stmt();
+    EXPECT_FALSE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_EQ(e.value, nullptr);
 }
 
 TEST_F(ParserImplTest, AssignmentStmt_InvalidRHS) {
-  auto p = parser("a.b.c[2].d = if (true) {}");
-  auto e = p->assignment_stmt();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:14: unable to parse right side of assignment");
+    auto p = parser("a.b.c[2].d = if (true) {}");
+    auto e = p->assignment_stmt();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:14: unable to parse right side of assignment");
 }
 
 TEST_F(ParserImplTest, AssignmentStmt_InvalidCompoundOp) {
-  auto p = parser("a &&= true");
-  auto e = p->assignment_stmt();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:3: expected '=' for assignment");
+    auto p = parser("a &&= true");
+    auto e = p->assignment_stmt();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:3: expected '=' for assignment");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_body_stmt_test.cc b/src/tint/reader/wgsl/parser_impl_body_stmt_test.cc
index 56efb9b..f84a5ba 100644
--- a/src/tint/reader/wgsl/parser_impl_body_stmt_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_body_stmt_test.cc
@@ -19,40 +19,40 @@
 namespace {
 
 TEST_F(ParserImplTest, BodyStmt) {
-  auto p = parser(R"({
+    auto p = parser(R"({
   discard;
   return 1 + b / 2;
 })");
-  auto e = p->expect_body_stmt();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  ASSERT_FALSE(e.errored);
-  ASSERT_EQ(e->statements.size(), 2u);
-  EXPECT_TRUE(e->statements[0]->Is<ast::DiscardStatement>());
-  EXPECT_TRUE(e->statements[1]->Is<ast::ReturnStatement>());
+    auto e = p->expect_body_stmt();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    ASSERT_FALSE(e.errored);
+    ASSERT_EQ(e->statements.size(), 2u);
+    EXPECT_TRUE(e->statements[0]->Is<ast::DiscardStatement>());
+    EXPECT_TRUE(e->statements[1]->Is<ast::ReturnStatement>());
 }
 
 TEST_F(ParserImplTest, BodyStmt_Empty) {
-  auto p = parser("{}");
-  auto e = p->expect_body_stmt();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  ASSERT_FALSE(e.errored);
-  EXPECT_EQ(e->statements.size(), 0u);
+    auto p = parser("{}");
+    auto e = p->expect_body_stmt();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    ASSERT_FALSE(e.errored);
+    EXPECT_EQ(e->statements.size(), 0u);
 }
 
 TEST_F(ParserImplTest, BodyStmt_InvalidStmt) {
-  auto p = parser("{fn main() {}}");
-  auto e = p->expect_body_stmt();
-  ASSERT_TRUE(p->has_error());
-  ASSERT_TRUE(e.errored);
-  EXPECT_EQ(p->error(), "1:2: expected '}'");
+    auto p = parser("{fn main() {}}");
+    auto e = p->expect_body_stmt();
+    ASSERT_TRUE(p->has_error());
+    ASSERT_TRUE(e.errored);
+    EXPECT_EQ(p->error(), "1:2: expected '}'");
 }
 
 TEST_F(ParserImplTest, BodyStmt_MissingRightParen) {
-  auto p = parser("{return;");
-  auto e = p->expect_body_stmt();
-  ASSERT_TRUE(p->has_error());
-  ASSERT_TRUE(e.errored);
-  EXPECT_EQ(p->error(), "1:9: expected '}'");
+    auto p = parser("{return;");
+    auto e = p->expect_body_stmt();
+    ASSERT_TRUE(p->has_error());
+    ASSERT_TRUE(e.errored);
+    EXPECT_EQ(p->error(), "1:9: expected '}'");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_break_stmt_test.cc b/src/tint/reader/wgsl/parser_impl_break_stmt_test.cc
index d889b55..ca8802a 100644
--- a/src/tint/reader/wgsl/parser_impl_break_stmt_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_break_stmt_test.cc
@@ -19,12 +19,12 @@
 namespace {
 
 TEST_F(ParserImplTest, BreakStmt) {
-  auto p = parser("break");
-  auto e = p->break_stmt();
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::BreakStatement>());
+    auto p = parser("break");
+    auto e = p->break_stmt();
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::BreakStatement>());
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_bug_cases_test.cc b/src/tint/reader/wgsl/parser_impl_bug_cases_test.cc
index 7119ba2..48afd3d 100644
--- a/src/tint/reader/wgsl/parser_impl_bug_cases_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_bug_cases_test.cc
@@ -18,10 +18,10 @@
 namespace {
 
 TEST_F(ParserImplTest, Bug_chromium_1180130) {
-  auto p = parser(
-      R"(a;{}}a;}};{{{;{}};{};{}}a;{}};{{{}};{{{;{}};{};{}}a;{}};{{{}}{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}}{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}}{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{{{;u[([[,a;{}}a;{}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{z{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}}{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}}{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}}{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}}{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}}{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}}{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}}i;{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};}a;{}};{{{}};{{;u[[a,([}};{{{;{}})");
-  EXPECT_FALSE(p->Parse());
-  EXPECT_TRUE(p->has_error());
+    auto p = parser(
+        R"(a;{}}a;}};{{{;{}};{};{}}a;{}};{{{}};{{{;{}};{};{}}a;{}};{{{}}{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}}{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}}{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{{{;u[([[,a;{}}a;{}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{z{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}}{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}}{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}}{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}}{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}}{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}}{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}}i;{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};{}{}};{{{}};{{{;{}};{};}a;{}};{{{}};{{{;u[({}};{{{}};{{}a;{}};{{{}};{{{;{}};{};}a;{}};{{{}};{{;u[[a,([}};{{{;{}})");
+    EXPECT_FALSE(p->Parse());
+    EXPECT_TRUE(p->has_error());
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_call_stmt_test.cc b/src/tint/reader/wgsl/parser_impl_call_stmt_test.cc
index 8d3ec0f..d044f8d 100644
--- a/src/tint/reader/wgsl/parser_impl_call_stmt_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_call_stmt_test.cc
@@ -19,88 +19,88 @@
 namespace {
 
 TEST_F(ParserImplTest, Statement_Call) {
-  auto p = parser("a();");
-  auto e = p->statement();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
+    auto p = parser("a();");
+    auto e = p->statement();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
 
-  EXPECT_EQ(e->source.range.begin.line, 1u);
-  EXPECT_EQ(e->source.range.begin.column, 1u);
-  EXPECT_EQ(e->source.range.end.line, 1u);
-  EXPECT_EQ(e->source.range.end.column, 2u);
+    EXPECT_EQ(e->source.range.begin.line, 1u);
+    EXPECT_EQ(e->source.range.begin.column, 1u);
+    EXPECT_EQ(e->source.range.end.line, 1u);
+    EXPECT_EQ(e->source.range.end.column, 2u);
 
-  ASSERT_TRUE(e->Is<ast::CallStatement>());
-  auto* c = e->As<ast::CallStatement>()->expr;
+    ASSERT_TRUE(e->Is<ast::CallStatement>());
+    auto* c = e->As<ast::CallStatement>()->expr;
 
-  EXPECT_EQ(c->target.name->symbol, p->builder().Symbols().Get("a"));
+    EXPECT_EQ(c->target.name->symbol, p->builder().Symbols().Get("a"));
 
-  EXPECT_EQ(c->args.size(), 0u);
+    EXPECT_EQ(c->args.size(), 0u);
 }
 
 TEST_F(ParserImplTest, Statement_Call_WithParams) {
-  auto p = parser("a(1, b, 2 + 3 / b);");
-  auto e = p->statement();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
+    auto p = parser("a(1, b, 2 + 3 / b);");
+    auto e = p->statement();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
 
-  ASSERT_TRUE(e->Is<ast::CallStatement>());
-  auto* c = e->As<ast::CallStatement>()->expr;
+    ASSERT_TRUE(e->Is<ast::CallStatement>());
+    auto* c = e->As<ast::CallStatement>()->expr;
 
-  EXPECT_EQ(c->target.name->symbol, p->builder().Symbols().Get("a"));
+    EXPECT_EQ(c->target.name->symbol, p->builder().Symbols().Get("a"));
 
-  EXPECT_EQ(c->args.size(), 3u);
-  EXPECT_TRUE(c->args[0]->Is<ast::IntLiteralExpression>());
-  EXPECT_TRUE(c->args[1]->Is<ast::IdentifierExpression>());
-  EXPECT_TRUE(c->args[2]->Is<ast::BinaryExpression>());
+    EXPECT_EQ(c->args.size(), 3u);
+    EXPECT_TRUE(c->args[0]->Is<ast::IntLiteralExpression>());
+    EXPECT_TRUE(c->args[1]->Is<ast::IdentifierExpression>());
+    EXPECT_TRUE(c->args[2]->Is<ast::BinaryExpression>());
 }
 
 TEST_F(ParserImplTest, Statement_Call_WithParams_TrailingComma) {
-  auto p = parser("a(1, b,);");
-  auto e = p->statement();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
+    auto p = parser("a(1, b,);");
+    auto e = p->statement();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
 
-  ASSERT_TRUE(e->Is<ast::CallStatement>());
-  auto* c = e->As<ast::CallStatement>()->expr;
+    ASSERT_TRUE(e->Is<ast::CallStatement>());
+    auto* c = e->As<ast::CallStatement>()->expr;
 
-  EXPECT_EQ(c->target.name->symbol, p->builder().Symbols().Get("a"));
+    EXPECT_EQ(c->target.name->symbol, p->builder().Symbols().Get("a"));
 
-  EXPECT_EQ(c->args.size(), 2u);
-  EXPECT_TRUE(c->args[0]->Is<ast::IntLiteralExpression>());
-  EXPECT_TRUE(c->args[1]->Is<ast::IdentifierExpression>());
+    EXPECT_EQ(c->args.size(), 2u);
+    EXPECT_TRUE(c->args[0]->Is<ast::IntLiteralExpression>());
+    EXPECT_TRUE(c->args[1]->Is<ast::IdentifierExpression>());
 }
 
 TEST_F(ParserImplTest, Statement_Call_Missing_RightParen) {
-  auto p = parser("a(");
-  auto e = p->statement();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(e.errored);
-  EXPECT_FALSE(e.matched);
-  EXPECT_EQ(p->error(), "1:3: expected ')' for function call");
+    auto p = parser("a(");
+    auto e = p->statement();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(e.errored);
+    EXPECT_FALSE(e.matched);
+    EXPECT_EQ(p->error(), "1:3: expected ')' for function call");
 }
 
 TEST_F(ParserImplTest, Statement_Call_Missing_Semi) {
-  auto p = parser("a()");
-  auto e = p->statement();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(e.errored);
-  EXPECT_FALSE(e.matched);
-  EXPECT_EQ(p->error(), "1:4: expected ';' for function call");
+    auto p = parser("a()");
+    auto e = p->statement();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(e.errored);
+    EXPECT_FALSE(e.matched);
+    EXPECT_EQ(p->error(), "1:4: expected ';' for function call");
 }
 
 TEST_F(ParserImplTest, Statement_Call_Bad_ArgList) {
-  auto p = parser("a(b c);");
-  auto e = p->statement();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(e.errored);
-  EXPECT_FALSE(e.matched);
-  EXPECT_EQ(p->error(), "1:5: expected ')' for function call");
+    auto p = parser("a(b c);");
+    auto e = p->statement();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(e.errored);
+    EXPECT_FALSE(e.matched);
+    EXPECT_EQ(p->error(), "1:5: expected ')' for function call");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_case_body_test.cc b/src/tint/reader/wgsl/parser_impl_case_body_test.cc
index 1c4bb93..f8c07a3 100644
--- a/src/tint/reader/wgsl/parser_impl_case_body_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_case_body_test.cc
@@ -19,55 +19,55 @@
 namespace {
 
 TEST_F(ParserImplTest, CaseBody_Empty) {
-  auto p = parser("");
-  auto e = p->case_body();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  EXPECT_FALSE(e.errored);
-  EXPECT_TRUE(e.matched);
-  EXPECT_EQ(e->statements.size(), 0u);
+    auto p = parser("");
+    auto e = p->case_body();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    EXPECT_FALSE(e.errored);
+    EXPECT_TRUE(e.matched);
+    EXPECT_EQ(e->statements.size(), 0u);
 }
 
 TEST_F(ParserImplTest, CaseBody_Statements) {
-  auto p = parser(R"(
+    auto p = parser(R"(
   var a: i32;
   a = 2;)");
 
-  auto e = p->case_body();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  EXPECT_FALSE(e.errored);
-  EXPECT_TRUE(e.matched);
-  ASSERT_EQ(e->statements.size(), 2u);
-  EXPECT_TRUE(e->statements[0]->Is<ast::VariableDeclStatement>());
-  EXPECT_TRUE(e->statements[1]->Is<ast::AssignmentStatement>());
+    auto e = p->case_body();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    EXPECT_FALSE(e.errored);
+    EXPECT_TRUE(e.matched);
+    ASSERT_EQ(e->statements.size(), 2u);
+    EXPECT_TRUE(e->statements[0]->Is<ast::VariableDeclStatement>());
+    EXPECT_TRUE(e->statements[1]->Is<ast::AssignmentStatement>());
 }
 
 TEST_F(ParserImplTest, CaseBody_InvalidStatement) {
-  auto p = parser("a =");
-  auto e = p->case_body();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(e.errored);
-  EXPECT_FALSE(e.matched);
-  EXPECT_EQ(e.value, nullptr);
+    auto p = parser("a =");
+    auto e = p->case_body();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(e.errored);
+    EXPECT_FALSE(e.matched);
+    EXPECT_EQ(e.value, nullptr);
 }
 
 TEST_F(ParserImplTest, CaseBody_Fallthrough) {
-  auto p = parser("fallthrough;");
-  auto e = p->case_body();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  EXPECT_FALSE(e.errored);
-  EXPECT_TRUE(e.matched);
-  ASSERT_EQ(e->statements.size(), 1u);
-  EXPECT_TRUE(e->statements[0]->Is<ast::FallthroughStatement>());
+    auto p = parser("fallthrough;");
+    auto e = p->case_body();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    EXPECT_FALSE(e.errored);
+    EXPECT_TRUE(e.matched);
+    ASSERT_EQ(e->statements.size(), 1u);
+    EXPECT_TRUE(e->statements[0]->Is<ast::FallthroughStatement>());
 }
 
 TEST_F(ParserImplTest, CaseBody_Fallthrough_MissingSemicolon) {
-  auto p = parser("fallthrough");
-  auto e = p->case_body();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(e.errored);
-  EXPECT_FALSE(e.matched);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:12: expected ';' for fallthrough statement");
+    auto p = parser("fallthrough");
+    auto e = p->case_body();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(e.errored);
+    EXPECT_FALSE(e.matched);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:12: expected ';' for fallthrough statement");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_const_expr_test.cc b/src/tint/reader/wgsl/parser_impl_const_expr_test.cc
index bb612d1..9d58058 100644
--- a/src/tint/reader/wgsl/parser_impl_const_expr_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_const_expr_test.cc
@@ -18,152 +18,151 @@
 namespace {
 
 TEST_F(ParserImplTest, ConstExpr_TypeDecl) {
-  auto p = parser("vec2<f32>(1., 2.)");
-  auto e = p->expect_const_expr();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  ASSERT_FALSE(e.errored);
-  ASSERT_TRUE(e->Is<ast::CallExpression>());
+    auto p = parser("vec2<f32>(1., 2.)");
+    auto e = p->expect_const_expr();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    ASSERT_FALSE(e.errored);
+    ASSERT_TRUE(e->Is<ast::CallExpression>());
 
-  auto* t = e->As<ast::CallExpression>();
-  ASSERT_TRUE(t->target.type->Is<ast::Vector>());
-  EXPECT_EQ(t->target.type->As<ast::Vector>()->width, 2u);
+    auto* t = e->As<ast::CallExpression>();
+    ASSERT_TRUE(t->target.type->Is<ast::Vector>());
+    EXPECT_EQ(t->target.type->As<ast::Vector>()->width, 2u);
 
-  ASSERT_EQ(t->args.size(), 2u);
+    ASSERT_EQ(t->args.size(), 2u);
 
-  ASSERT_TRUE(t->args[0]->Is<ast::FloatLiteralExpression>());
-  EXPECT_FLOAT_EQ(t->args[0]->As<ast::FloatLiteralExpression>()->value, 1.);
+    ASSERT_TRUE(t->args[0]->Is<ast::FloatLiteralExpression>());
+    EXPECT_FLOAT_EQ(t->args[0]->As<ast::FloatLiteralExpression>()->value, 1.);
 
-  ASSERT_TRUE(t->args[1]->Is<ast::FloatLiteralExpression>());
-  EXPECT_FLOAT_EQ(t->args[1]->As<ast::FloatLiteralExpression>()->value, 2.);
+    ASSERT_TRUE(t->args[1]->Is<ast::FloatLiteralExpression>());
+    EXPECT_FLOAT_EQ(t->args[1]->As<ast::FloatLiteralExpression>()->value, 2.);
 }
 
 TEST_F(ParserImplTest, ConstExpr_TypeDecl_Empty) {
-  auto p = parser("vec2<f32>()");
-  auto e = p->expect_const_expr();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  ASSERT_FALSE(e.errored);
-  ASSERT_TRUE(e->Is<ast::CallExpression>());
+    auto p = parser("vec2<f32>()");
+    auto e = p->expect_const_expr();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    ASSERT_FALSE(e.errored);
+    ASSERT_TRUE(e->Is<ast::CallExpression>());
 
-  auto* t = e->As<ast::CallExpression>();
-  ASSERT_TRUE(t->target.type->Is<ast::Vector>());
-  EXPECT_EQ(t->target.type->As<ast::Vector>()->width, 2u);
+    auto* t = e->As<ast::CallExpression>();
+    ASSERT_TRUE(t->target.type->Is<ast::Vector>());
+    EXPECT_EQ(t->target.type->As<ast::Vector>()->width, 2u);
 
-  ASSERT_EQ(t->args.size(), 0u);
+    ASSERT_EQ(t->args.size(), 0u);
 }
 
 TEST_F(ParserImplTest, ConstExpr_TypeDecl_TrailingComma) {
-  auto p = parser("vec2<f32>(1., 2.,)");
-  auto e = p->expect_const_expr();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  ASSERT_FALSE(e.errored);
-  ASSERT_TRUE(e->Is<ast::CallExpression>());
+    auto p = parser("vec2<f32>(1., 2.,)");
+    auto e = p->expect_const_expr();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    ASSERT_FALSE(e.errored);
+    ASSERT_TRUE(e->Is<ast::CallExpression>());
 
-  auto* t = e->As<ast::CallExpression>();
-  ASSERT_TRUE(t->target.type->Is<ast::Vector>());
-  EXPECT_EQ(t->target.type->As<ast::Vector>()->width, 2u);
+    auto* t = e->As<ast::CallExpression>();
+    ASSERT_TRUE(t->target.type->Is<ast::Vector>());
+    EXPECT_EQ(t->target.type->As<ast::Vector>()->width, 2u);
 
-  ASSERT_EQ(t->args.size(), 2u);
-  ASSERT_TRUE(t->args[0]->Is<ast::LiteralExpression>());
-  ASSERT_TRUE(t->args[1]->Is<ast::LiteralExpression>());
+    ASSERT_EQ(t->args.size(), 2u);
+    ASSERT_TRUE(t->args[0]->Is<ast::LiteralExpression>());
+    ASSERT_TRUE(t->args[1]->Is<ast::LiteralExpression>());
 }
 
 TEST_F(ParserImplTest, ConstExpr_TypeDecl_MissingRightParen) {
-  auto p = parser("vec2<f32>(1., 2.");
-  auto e = p->expect_const_expr();
-  ASSERT_TRUE(p->has_error());
-  ASSERT_TRUE(e.errored);
-  ASSERT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:17: expected ')' for type constructor");
+    auto p = parser("vec2<f32>(1., 2.");
+    auto e = p->expect_const_expr();
+    ASSERT_TRUE(p->has_error());
+    ASSERT_TRUE(e.errored);
+    ASSERT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:17: expected ')' for type constructor");
 }
 
 TEST_F(ParserImplTest, ConstExpr_TypeDecl_MissingLeftParen) {
-  auto p = parser("vec2<f32> 1., 2.)");
-  auto e = p->expect_const_expr();
-  ASSERT_TRUE(p->has_error());
-  ASSERT_TRUE(e.errored);
-  ASSERT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:11: expected '(' for type constructor");
+    auto p = parser("vec2<f32> 1., 2.)");
+    auto e = p->expect_const_expr();
+    ASSERT_TRUE(p->has_error());
+    ASSERT_TRUE(e.errored);
+    ASSERT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:11: expected '(' for type constructor");
 }
 
 TEST_F(ParserImplTest, ConstExpr_TypeDecl_MissingComma) {
-  auto p = parser("vec2<f32>(1. 2.");
-  auto e = p->expect_const_expr();
-  ASSERT_TRUE(p->has_error());
-  ASSERT_TRUE(e.errored);
-  ASSERT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:14: expected ')' for type constructor");
+    auto p = parser("vec2<f32>(1. 2.");
+    auto e = p->expect_const_expr();
+    ASSERT_TRUE(p->has_error());
+    ASSERT_TRUE(e.errored);
+    ASSERT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:14: expected ')' for type constructor");
 }
 
 TEST_F(ParserImplTest, ConstExpr_InvalidExpr) {
-  auto p = parser("vec2<f32>(1., if(a) {})");
-  auto e = p->expect_const_expr();
-  ASSERT_TRUE(p->has_error());
-  ASSERT_TRUE(e.errored);
-  ASSERT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:15: invalid type for const_expr");
+    auto p = parser("vec2<f32>(1., if(a) {})");
+    auto e = p->expect_const_expr();
+    ASSERT_TRUE(p->has_error());
+    ASSERT_TRUE(e.errored);
+    ASSERT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:15: invalid type for const_expr");
 }
 
 TEST_F(ParserImplTest, ConstExpr_ConstLiteral) {
-  auto p = parser("true");
-  auto e = p->expect_const_expr();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  ASSERT_FALSE(e.errored);
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e.value->Is<ast::BoolLiteralExpression>());
-  EXPECT_TRUE(e.value->As<ast::BoolLiteralExpression>()->value);
+    auto p = parser("true");
+    auto e = p->expect_const_expr();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    ASSERT_FALSE(e.errored);
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e.value->Is<ast::BoolLiteralExpression>());
+    EXPECT_TRUE(e.value->As<ast::BoolLiteralExpression>()->value);
 }
 
 TEST_F(ParserImplTest, ConstExpr_ConstLiteral_Invalid) {
-  auto p = parser("invalid");
-  auto e = p->expect_const_expr();
-  ASSERT_TRUE(p->has_error());
-  ASSERT_TRUE(e.errored);
-  ASSERT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:1: unable to parse const_expr");
+    auto p = parser("invalid");
+    auto e = p->expect_const_expr();
+    ASSERT_TRUE(p->has_error());
+    ASSERT_TRUE(e.errored);
+    ASSERT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:1: unable to parse const_expr");
 }
 
 TEST_F(ParserImplTest, ConstExpr_TypeConstructor) {
-  auto p = parser("S(0)");
+    auto p = parser("S(0)");
 
-  auto e = p->expect_const_expr();
-  ASSERT_FALSE(e.errored);
-  ASSERT_TRUE(e->Is<ast::CallExpression>());
-  ASSERT_NE(e->As<ast::CallExpression>()->target.type, nullptr);
-  ASSERT_TRUE(e->As<ast::CallExpression>()->target.type->Is<ast::TypeName>());
-  EXPECT_EQ(
-      e->As<ast::CallExpression>()->target.type->As<ast::TypeName>()->name,
-      p->builder().Symbols().Get("S"));
+    auto e = p->expect_const_expr();
+    ASSERT_FALSE(e.errored);
+    ASSERT_TRUE(e->Is<ast::CallExpression>());
+    ASSERT_NE(e->As<ast::CallExpression>()->target.type, nullptr);
+    ASSERT_TRUE(e->As<ast::CallExpression>()->target.type->Is<ast::TypeName>());
+    EXPECT_EQ(e->As<ast::CallExpression>()->target.type->As<ast::TypeName>()->name,
+              p->builder().Symbols().Get("S"));
 }
 
 TEST_F(ParserImplTest, ConstExpr_Recursion) {
-  std::stringstream out;
-  for (size_t i = 0; i < 200; i++) {
-    out << "f32(";
-  }
-  out << "1.0";
-  for (size_t i = 0; i < 200; i++) {
-    out << ")";
-  }
-  auto p = parser(out.str());
-  auto e = p->expect_const_expr();
-  ASSERT_TRUE(p->has_error());
-  ASSERT_TRUE(e.errored);
-  ASSERT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:517: maximum parser recursive depth reached");
+    std::stringstream out;
+    for (size_t i = 0; i < 200; i++) {
+        out << "f32(";
+    }
+    out << "1.0";
+    for (size_t i = 0; i < 200; i++) {
+        out << ")";
+    }
+    auto p = parser(out.str());
+    auto e = p->expect_const_expr();
+    ASSERT_TRUE(p->has_error());
+    ASSERT_TRUE(e.errored);
+    ASSERT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:517: maximum parser recursive depth reached");
 }
 
 TEST_F(ParserImplTest, UnaryOp_Recursion) {
-  std::stringstream out;
-  for (size_t i = 0; i < 200; i++) {
-    out << "!";
-  }
-  out << "1.0";
-  auto p = parser(out.str());
-  auto e = p->unary_expression();
-  ASSERT_TRUE(p->has_error());
-  ASSERT_TRUE(e.errored);
-  ASSERT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:130: maximum parser recursive depth reached");
+    std::stringstream out;
+    for (size_t i = 0; i < 200; i++) {
+        out << "!";
+    }
+    out << "1.0";
+    auto p = parser(out.str());
+    auto e = p->unary_expression();
+    ASSERT_TRUE(p->has_error());
+    ASSERT_TRUE(e.errored);
+    ASSERT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:130: maximum parser recursive depth reached");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_const_literal_test.cc b/src/tint/reader/wgsl/parser_impl_const_literal_test.cc
index 44c7083..3e37092 100644
--- a/src/tint/reader/wgsl/parser_impl_const_literal_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_const_literal_test.cc
@@ -27,143 +27,193 @@
 // - 'exponent_bits' is placed in the exponent space.
 //   So, the exponent bias must already be included.
 float MakeFloat(int sign, int biased_exponent, int mantissa) {
-  const uint32_t sign_bit = sign ? 0x80000000u : 0u;
-  // The binary32 exponent is 8 bits, just below the sign.
-  const uint32_t exponent_bits = (biased_exponent & 0xffu) << 23;
-  // The mantissa is the bottom 23 bits.
-  const uint32_t mantissa_bits = (mantissa & 0x7fffffu);
+    const uint32_t sign_bit = sign ? 0x80000000u : 0u;
+    // The binary32 exponent is 8 bits, just below the sign.
+    const uint32_t exponent_bits = (biased_exponent & 0xffu) << 23;
+    // The mantissa is the bottom 23 bits.
+    const uint32_t mantissa_bits = (mantissa & 0x7fffffu);
 
-  uint32_t bits = sign_bit | exponent_bits | mantissa_bits;
-  float result = 0.0f;
-  static_assert(sizeof(result) == sizeof(bits),
-                "expected float and uint32_t to be the same size");
-  std::memcpy(&result, &bits, sizeof(bits));
-  return result;
+    uint32_t bits = sign_bit | exponent_bits | mantissa_bits;
+    float result = 0.0f;
+    static_assert(sizeof(result) == sizeof(bits),
+                  "expected float and uint32_t to be the same size");
+    std::memcpy(&result, &bits, sizeof(bits));
+    return result;
 }
 
 TEST_F(ParserImplTest, ConstLiteral_Int) {
-  auto p = parser("-234");
-  auto c = p->const_literal();
-  EXPECT_TRUE(c.matched);
-  EXPECT_FALSE(c.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(c.value, nullptr);
-  ASSERT_TRUE(c->Is<ast::SintLiteralExpression>());
-  EXPECT_EQ(c->As<ast::SintLiteralExpression>()->value, -234);
-  EXPECT_EQ(c->source.range, (Source::Range{{1u, 1u}, {1u, 5u}}));
+    {
+        auto p = parser("234");
+        auto c = p->const_literal();
+        EXPECT_TRUE(c.matched);
+        EXPECT_FALSE(c.errored);
+        EXPECT_FALSE(p->has_error()) << p->error();
+        ASSERT_NE(c.value, nullptr);
+        ASSERT_TRUE(c->Is<ast::IntLiteralExpression>());
+        EXPECT_EQ(c->As<ast::IntLiteralExpression>()->value, 234);
+        EXPECT_EQ(c->As<ast::IntLiteralExpression>()->suffix,
+                  ast::IntLiteralExpression::Suffix::kNone);
+        EXPECT_EQ(c->source.range, (Source::Range{{1u, 1u}, {1u, 4u}}));
+    }
+    {
+        auto p = parser("234i");
+        auto c = p->const_literal();
+        EXPECT_TRUE(c.matched);
+        EXPECT_FALSE(c.errored);
+        EXPECT_FALSE(p->has_error()) << p->error();
+        ASSERT_NE(c.value, nullptr);
+        ASSERT_TRUE(c->Is<ast::IntLiteralExpression>());
+        EXPECT_EQ(c->As<ast::IntLiteralExpression>()->value, 234);
+        EXPECT_EQ(c->As<ast::IntLiteralExpression>()->suffix,
+                  ast::IntLiteralExpression::Suffix::kI);
+        EXPECT_EQ(c->source.range, (Source::Range{{1u, 1u}, {1u, 5u}}));
+    }
+    {
+        auto p = parser("-234");
+        auto c = p->const_literal();
+        EXPECT_TRUE(c.matched);
+        EXPECT_FALSE(c.errored);
+        EXPECT_FALSE(p->has_error()) << p->error();
+        ASSERT_NE(c.value, nullptr);
+        ASSERT_TRUE(c->Is<ast::IntLiteralExpression>());
+        EXPECT_EQ(c->As<ast::IntLiteralExpression>()->value, -234);
+        EXPECT_EQ(c->As<ast::IntLiteralExpression>()->suffix,
+                  ast::IntLiteralExpression::Suffix::kNone);
+        EXPECT_EQ(c->source.range, (Source::Range{{1u, 1u}, {1u, 5u}}));
+    }
+    {
+        auto p = parser("-234i");
+        auto c = p->const_literal();
+        EXPECT_TRUE(c.matched);
+        EXPECT_FALSE(c.errored);
+        EXPECT_FALSE(p->has_error()) << p->error();
+        ASSERT_NE(c.value, nullptr);
+        ASSERT_TRUE(c->Is<ast::IntLiteralExpression>());
+        EXPECT_EQ(c->As<ast::IntLiteralExpression>()->value, -234);
+        EXPECT_EQ(c->As<ast::IntLiteralExpression>()->suffix,
+                  ast::IntLiteralExpression::Suffix::kI);
+        EXPECT_EQ(c->source.range, (Source::Range{{1u, 1u}, {1u, 6u}}));
+    }
 }
 
 TEST_F(ParserImplTest, ConstLiteral_Uint) {
-  auto p = parser("234u");
-  auto c = p->const_literal();
-  EXPECT_TRUE(c.matched);
-  EXPECT_FALSE(c.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(c.value, nullptr);
-  ASSERT_TRUE(c->Is<ast::UintLiteralExpression>());
-  EXPECT_EQ(c->As<ast::UintLiteralExpression>()->value, 234u);
-  EXPECT_EQ(c->source.range, (Source::Range{{1u, 1u}, {1u, 5u}}));
+    auto p = parser("234u");
+    auto c = p->const_literal();
+    EXPECT_TRUE(c.matched);
+    EXPECT_FALSE(c.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(c.value, nullptr);
+    ASSERT_TRUE(c->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(c->As<ast::IntLiteralExpression>()->value, 234);
+    EXPECT_EQ(c->As<ast::IntLiteralExpression>()->suffix, ast::IntLiteralExpression::Suffix::kU);
+    EXPECT_EQ(c->source.range, (Source::Range{{1u, 1u}, {1u, 5u}}));
+}
+
+TEST_F(ParserImplTest, ConstLiteral_Uint_Negative) {
+    auto p = parser("-234u");
+    auto c = p->const_literal();
+    EXPECT_FALSE(c.matched);
+    EXPECT_TRUE(c.errored);
+    EXPECT_EQ(p->error(), "1:1: unsigned literal cannot be negative");
+    ASSERT_EQ(c.value, nullptr);
 }
 
 TEST_F(ParserImplTest, ConstLiteral_Float) {
-  auto p = parser("234.e12");
-  auto c = p->const_literal();
-  EXPECT_TRUE(c.matched);
-  EXPECT_FALSE(c.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(c.value, nullptr);
-  ASSERT_TRUE(c->Is<ast::FloatLiteralExpression>());
-  EXPECT_FLOAT_EQ(c->As<ast::FloatLiteralExpression>()->value, 234e12f);
-  EXPECT_EQ(c->source.range, (Source::Range{{1u, 1u}, {1u, 8u}}));
+    auto p = parser("234.e12");
+    auto c = p->const_literal();
+    EXPECT_TRUE(c.matched);
+    EXPECT_FALSE(c.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(c.value, nullptr);
+    ASSERT_TRUE(c->Is<ast::FloatLiteralExpression>());
+    EXPECT_FLOAT_EQ(c->As<ast::FloatLiteralExpression>()->value, 234e12f);
+    EXPECT_EQ(c->source.range, (Source::Range{{1u, 1u}, {1u, 8u}}));
 }
 
 TEST_F(ParserImplTest, ConstLiteral_InvalidFloat_IncompleteExponent) {
-  auto p = parser("1.0e+");
-  auto c = p->const_literal();
-  EXPECT_FALSE(c.matched);
-  EXPECT_TRUE(c.errored);
-  EXPECT_EQ(p->error(),
-            "1:1: incomplete exponent for floating point literal: 1.0e+");
-  ASSERT_EQ(c.value, nullptr);
+    auto p = parser("1.0e+");
+    auto c = p->const_literal();
+    EXPECT_FALSE(c.matched);
+    EXPECT_TRUE(c.errored);
+    EXPECT_EQ(p->error(), "1:1: incomplete exponent for floating point literal: 1.0e+");
+    ASSERT_EQ(c.value, nullptr);
 }
 
 TEST_F(ParserImplTest, ConstLiteral_InvalidFloat_TooSmallMagnitude) {
-  auto p = parser("1e-256");
-  auto c = p->const_literal();
-  EXPECT_FALSE(c.matched);
-  EXPECT_TRUE(c.errored);
-  EXPECT_EQ(p->error(),
-            "1:1: f32 (1e-256) magnitude too small, not representable");
-  ASSERT_EQ(c.value, nullptr);
+    auto p = parser("1e-256");
+    auto c = p->const_literal();
+    EXPECT_FALSE(c.matched);
+    EXPECT_TRUE(c.errored);
+    EXPECT_EQ(p->error(), "1:1: f32 (1e-256) magnitude too small, not representable");
+    ASSERT_EQ(c.value, nullptr);
 }
 
 TEST_F(ParserImplTest, ConstLiteral_InvalidFloat_TooLargeNegative) {
-  auto p = parser("-1.2e+256");
-  auto c = p->const_literal();
-  EXPECT_FALSE(c.matched);
-  EXPECT_TRUE(c.errored);
-  EXPECT_EQ(p->error(), "1:1: f32 (-1.2e+256) too large (negative)");
-  ASSERT_EQ(c.value, nullptr);
+    auto p = parser("-1.2e+256");
+    auto c = p->const_literal();
+    EXPECT_FALSE(c.matched);
+    EXPECT_TRUE(c.errored);
+    EXPECT_EQ(p->error(), "1:1: f32 (-1.2e+256) too large (negative)");
+    ASSERT_EQ(c.value, nullptr);
 }
 
 TEST_F(ParserImplTest, ConstLiteral_InvalidFloat_TooLargePositive) {
-  auto p = parser("1.2e+256");
-  auto c = p->const_literal();
-  EXPECT_FALSE(c.matched);
-  EXPECT_TRUE(c.errored);
-  EXPECT_EQ(p->error(), "1:1: f32 (1.2e+256) too large (positive)");
-  ASSERT_EQ(c.value, nullptr);
+    auto p = parser("1.2e+256");
+    auto c = p->const_literal();
+    EXPECT_FALSE(c.matched);
+    EXPECT_TRUE(c.errored);
+    EXPECT_EQ(p->error(), "1:1: f32 (1.2e+256) too large (positive)");
+    ASSERT_EQ(c.value, nullptr);
 }
 
 // Returns true if the given non-Nan float numbers are equal.
 bool FloatEqual(float a, float b) {
-  // Avoid Clang complaining about equality test on float.
-  // -Wfloat-equal.
-  return (a <= b) && (a >= b);
+    // Avoid Clang complaining about equality test on float.
+    // -Wfloat-equal.
+    return (a <= b) && (a >= b);
 }
 
 struct FloatLiteralTestCase {
-  std::string input;
-  float expected;
-  bool operator==(const FloatLiteralTestCase& other) const {
-    return (input == other.input) && FloatEqual(expected, other.expected);
-  }
+    std::string input;
+    float expected;
+    bool operator==(const FloatLiteralTestCase& other) const {
+        return (input == other.input) && FloatEqual(expected, other.expected);
+    }
 };
 
 inline std::ostream& operator<<(std::ostream& out, FloatLiteralTestCase data) {
-  out << data.input;
-  return out;
+    out << data.input;
+    return out;
 }
 
-class ParserImplFloatLiteralTest
-    : public ParserImplTestWithParam<FloatLiteralTestCase> {};
+class ParserImplFloatLiteralTest : public ParserImplTestWithParam<FloatLiteralTestCase> {};
 TEST_P(ParserImplFloatLiteralTest, Parse) {
-  auto params = GetParam();
-  SCOPED_TRACE(params.input);
-  auto p = parser(params.input);
-  auto c = p->const_literal();
-  EXPECT_TRUE(c.matched);
-  EXPECT_FALSE(c.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(c.value, nullptr);
-  ASSERT_TRUE(c->Is<ast::FloatLiteralExpression>());
-  EXPECT_FLOAT_EQ(c->As<ast::FloatLiteralExpression>()->value, params.expected);
+    auto params = GetParam();
+    SCOPED_TRACE(params.input);
+    auto p = parser(params.input);
+    auto c = p->const_literal();
+    EXPECT_TRUE(c.matched);
+    EXPECT_FALSE(c.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(c.value, nullptr);
+    ASSERT_TRUE(c->Is<ast::FloatLiteralExpression>());
+    EXPECT_FLOAT_EQ(c->As<ast::FloatLiteralExpression>()->value, params.expected);
 }
 
 using FloatLiteralTestCaseList = std::vector<FloatLiteralTestCase>;
 
 FloatLiteralTestCaseList DecimalFloatCases() {
-  return FloatLiteralTestCaseList{
-      {"0.0", 0.0f},                         // Zero
-      {"1.0", 1.0f},                         // One
-      {"-1.0", -1.0f},                       // MinusOne
-      {"1000000000.0", 1e9f},                // Billion
-      {"-0.0", std::copysign(0.0f, -5.0f)},  // NegativeZero
-      {"0.0", MakeFloat(0, 0, 0)},           // Zero
-      {"-0.0", MakeFloat(1, 0, 0)},          // NegativeZero
-      {"1.0", MakeFloat(0, 127, 0)},         // One
-      {"-1.0", MakeFloat(1, 127, 0)},        // NegativeOne
-  };
+    return FloatLiteralTestCaseList{
+        {"0.0", 0.0f},                         // Zero
+        {"1.0", 1.0f},                         // One
+        {"-1.0", -1.0f},                       // MinusOne
+        {"1000000000.0", 1e9f},                // Billion
+        {"-0.0", std::copysign(0.0f, -5.0f)},  // NegativeZero
+        {"0.0", MakeFloat(0, 0, 0)},           // Zero
+        {"-0.0", MakeFloat(1, 0, 0)},          // NegativeZero
+        {"1.0", MakeFloat(0, 127, 0)},         // One
+        {"-1.0", MakeFloat(1, 127, 0)},        // NegativeOne
+    };
 }
 
 INSTANTIATE_TEST_SUITE_P(ParserImplFloatLiteralTest_Float,
@@ -173,173 +223,172 @@
 const float NegInf = MakeFloat(1, 255, 0);
 const float PosInf = MakeFloat(0, 255, 0);
 FloatLiteralTestCaseList HexFloatCases() {
-  return FloatLiteralTestCaseList{
-      // Regular numbers
-      {"0x0p+0", 0.f},
-      {"0x1p+0", 1.f},
-      {"0x1p+1", 2.f},
-      {"0x1.8p+1", 3.f},
-      {"0x1.99999ap-4", 0.1f},
-      {"0x1p-1", 0.5f},
-      {"0x1p-2", 0.25f},
-      {"0x1.8p-1", 0.75f},
-      {"-0x0p+0", -0.f},
-      {"-0x1p+0", -1.f},
-      {"-0x1p-1", -0.5f},
-      {"-0x1p-2", -0.25f},
-      {"-0x1.8p-1", -0.75f},
+    return FloatLiteralTestCaseList{
+        // Regular numbers
+        {"0x0p+0", 0.f},
+        {"0x1p+0", 1.f},
+        {"0x1p+1", 2.f},
+        {"0x1.8p+1", 3.f},
+        {"0x1.99999ap-4", 0.1f},
+        {"0x1p-1", 0.5f},
+        {"0x1p-2", 0.25f},
+        {"0x1.8p-1", 0.75f},
+        {"-0x0p+0", -0.f},
+        {"-0x1p+0", -1.f},
+        {"-0x1p-1", -0.5f},
+        {"-0x1p-2", -0.25f},
+        {"-0x1.8p-1", -0.75f},
 
-      // Large numbers
-      {"0x1p+9", 512.f},
-      {"0x1p+10", 1024.f},
-      {"0x1.02p+10", 1024.f + 8.f},
-      {"-0x1p+9", -512.f},
-      {"-0x1p+10", -1024.f},
-      {"-0x1.02p+10", -1024.f - 8.f},
+        // Large numbers
+        {"0x1p+9", 512.f},
+        {"0x1p+10", 1024.f},
+        {"0x1.02p+10", 1024.f + 8.f},
+        {"-0x1p+9", -512.f},
+        {"-0x1p+10", -1024.f},
+        {"-0x1.02p+10", -1024.f - 8.f},
 
-      // Small numbers
-      {"0x1p-9", 1.0f / 512.f},
-      {"0x1p-10", 1.0f / 1024.f},
-      {"0x1.02p-3", 1.0f / 1024.f + 1.0f / 8.f},
-      {"-0x1p-9", 1.0f / -512.f},
-      {"-0x1p-10", 1.0f / -1024.f},
-      {"-0x1.02p-3", 1.0f / -1024.f - 1.0f / 8.f},
+        // Small numbers
+        {"0x1p-9", 1.0f / 512.f},
+        {"0x1p-10", 1.0f / 1024.f},
+        {"0x1.02p-3", 1.0f / 1024.f + 1.0f / 8.f},
+        {"-0x1p-9", 1.0f / -512.f},
+        {"-0x1p-10", 1.0f / -1024.f},
+        {"-0x1.02p-3", 1.0f / -1024.f - 1.0f / 8.f},
 
-      // Near lowest non-denorm
-      {"0x1p-124", std::ldexp(1.f * 8.f, -127)},
-      {"0x1p-125", std::ldexp(1.f * 4.f, -127)},
-      {"-0x1p-124", -std::ldexp(1.f * 8.f, -127)},
-      {"-0x1p-125", -std::ldexp(1.f * 4.f, -127)},
+        // Near lowest non-denorm
+        {"0x1p-124", std::ldexp(1.f * 8.f, -127)},
+        {"0x1p-125", std::ldexp(1.f * 4.f, -127)},
+        {"-0x1p-124", -std::ldexp(1.f * 8.f, -127)},
+        {"-0x1p-125", -std::ldexp(1.f * 4.f, -127)},
 
-      // Lowest non-denorm
-      {"0x1p-126", std::ldexp(1.f * 2.f, -127)},
-      {"-0x1p-126", -std::ldexp(1.f * 2.f, -127)},
+        // Lowest non-denorm
+        {"0x1p-126", std::ldexp(1.f * 2.f, -127)},
+        {"-0x1p-126", -std::ldexp(1.f * 2.f, -127)},
 
-      // Denormalized values
-      {"0x1p-127", std::ldexp(1.f, -127)},
-      {"0x1p-128", std::ldexp(1.f / 2.f, -127)},
-      {"0x1p-129", std::ldexp(1.f / 4.f, -127)},
-      {"0x1p-130", std::ldexp(1.f / 8.f, -127)},
-      {"-0x1p-127", -std::ldexp(1.f, -127)},
-      {"-0x1p-128", -std::ldexp(1.f / 2.f, -127)},
-      {"-0x1p-129", -std::ldexp(1.f / 4.f, -127)},
-      {"-0x1p-130", -std::ldexp(1.f / 8.f, -127)},
+        // Denormalized values
+        {"0x1p-127", std::ldexp(1.f, -127)},
+        {"0x1p-128", std::ldexp(1.f / 2.f, -127)},
+        {"0x1p-129", std::ldexp(1.f / 4.f, -127)},
+        {"0x1p-130", std::ldexp(1.f / 8.f, -127)},
+        {"-0x1p-127", -std::ldexp(1.f, -127)},
+        {"-0x1p-128", -std::ldexp(1.f / 2.f, -127)},
+        {"-0x1p-129", -std::ldexp(1.f / 4.f, -127)},
+        {"-0x1p-130", -std::ldexp(1.f / 8.f, -127)},
 
-      {"0x1.8p-127", std::ldexp(1.f, -127) + (std::ldexp(1.f, -127) / 2.f)},
-      {"0x1.8p-128",
-       std::ldexp(1.f, -127) / 2.f + (std::ldexp(1.f, -127) / 4.f)},
+        {"0x1.8p-127", std::ldexp(1.f, -127) + (std::ldexp(1.f, -127) / 2.f)},
+        {"0x1.8p-128", std::ldexp(1.f, -127) / 2.f + (std::ldexp(1.f, -127) / 4.f)},
 
-      {"0x1p-149", MakeFloat(0, 0, 1)},                 // +SmallestDenormal
-      {"0x1p-148", MakeFloat(0, 0, 2)},                 // +BiggerDenormal
-      {"0x1.fffffcp-127", MakeFloat(0, 0, 0x7fffff)},   // +LargestDenormal
-      {"-0x1p-149", MakeFloat(1, 0, 1)},                // -SmallestDenormal
-      {"-0x1p-148", MakeFloat(1, 0, 2)},                // -BiggerDenormal
-      {"-0x1.fffffcp-127", MakeFloat(1, 0, 0x7fffff)},  // -LargestDenormal
+        {"0x1p-149", MakeFloat(0, 0, 1)},                 // +SmallestDenormal
+        {"0x1p-148", MakeFloat(0, 0, 2)},                 // +BiggerDenormal
+        {"0x1.fffffcp-127", MakeFloat(0, 0, 0x7fffff)},   // +LargestDenormal
+        {"-0x1p-149", MakeFloat(1, 0, 1)},                // -SmallestDenormal
+        {"-0x1p-148", MakeFloat(1, 0, 2)},                // -BiggerDenormal
+        {"-0x1.fffffcp-127", MakeFloat(1, 0, 0x7fffff)},  // -LargestDenormal
 
-      {"0x1.2bfaf8p-127", MakeFloat(0, 0, 0xcafebe)},   // +Subnormal
-      {"-0x1.2bfaf8p-127", MakeFloat(1, 0, 0xcafebe)},  // -Subnormal
-      {"0x1.55554p-130", MakeFloat(0, 0, 0xaaaaa)},     // +Subnormal
-      {"-0x1.55554p-130", MakeFloat(1, 0, 0xaaaaa)},    // -Subnormal
+        {"0x1.2bfaf8p-127", MakeFloat(0, 0, 0xcafebe)},   // +Subnormal
+        {"-0x1.2bfaf8p-127", MakeFloat(1, 0, 0xcafebe)},  // -Subnormal
+        {"0x1.55554p-130", MakeFloat(0, 0, 0xaaaaa)},     // +Subnormal
+        {"-0x1.55554p-130", MakeFloat(1, 0, 0xaaaaa)},    // -Subnormal
 
-      // Nan -> Infinity
-      {"0x1.8p+128", PosInf},
-      {"0x1.0002p+128", PosInf},
-      {"0x1.0018p+128", PosInf},
-      {"0x1.01ep+128", PosInf},
-      {"0x1.fffffep+128", PosInf},
-      {"-0x1.8p+128", NegInf},
-      {"-0x1.0002p+128", NegInf},
-      {"-0x1.0018p+128", NegInf},
-      {"-0x1.01ep+128", NegInf},
-      {"-0x1.fffffep+128", NegInf},
+        // Nan -> Infinity
+        {"0x1.8p+128", PosInf},
+        {"0x1.0002p+128", PosInf},
+        {"0x1.0018p+128", PosInf},
+        {"0x1.01ep+128", PosInf},
+        {"0x1.fffffep+128", PosInf},
+        {"-0x1.8p+128", NegInf},
+        {"-0x1.0002p+128", NegInf},
+        {"-0x1.0018p+128", NegInf},
+        {"-0x1.01ep+128", NegInf},
+        {"-0x1.fffffep+128", NegInf},
 
-      // Infinity
-      {"0x1p+128", PosInf},
-      {"-0x1p+128", NegInf},
-      {"0x32p+127", PosInf},
-      {"0x32p+500", PosInf},
-      {"-0x32p+127", NegInf},
-      {"-0x32p+500", NegInf},
+        // Infinity
+        {"0x1p+128", PosInf},
+        {"-0x1p+128", NegInf},
+        {"0x32p+127", PosInf},
+        {"0x32p+500", PosInf},
+        {"-0x32p+127", NegInf},
+        {"-0x32p+500", NegInf},
 
-      // Overflow -> Infinity
-      {"0x1p+129", PosInf},
-      {"0x1.1p+128", PosInf},
-      {"-0x1p+129", NegInf},
-      {"-0x1.1p+128", NegInf},
-      {"0x1.0p2147483520", PosInf},  // INT_MAX - 127 (largest valid exponent)
+        // Overflow -> Infinity
+        {"0x1p+129", PosInf},
+        {"0x1.1p+128", PosInf},
+        {"-0x1p+129", NegInf},
+        {"-0x1.1p+128", NegInf},
+        {"0x1.0p2147483520", PosInf},  // INT_MAX - 127 (largest valid exponent)
 
-      // Underflow -> Zero
-      {"0x1p-500", 0.f},  // Exponent underflows
-      {"-0x1p-500", -0.f},
-      {"0x0.00000000001p-126", 0.f},  // Fraction causes underflow
-      {"-0x0.0000000001p-127", -0.f},
-      {"0x0.01p-142", 0.f},
-      {"-0x0.01p-142", -0.f},    // Fraction causes additional underflow
-      {"0x1.0p-2147483520", 0},  // -(INT_MAX - 127) (smallest valid exponent)
+        // Underflow -> Zero
+        {"0x1p-500", 0.f},  // Exponent underflows
+        {"-0x1p-500", -0.f},
+        {"0x0.00000000001p-126", 0.f},  // Fraction causes underflow
+        {"-0x0.0000000001p-127", -0.f},
+        {"0x0.01p-142", 0.f},
+        {"-0x0.01p-142", -0.f},    // Fraction causes additional underflow
+        {"0x1.0p-2147483520", 0},  // -(INT_MAX - 127) (smallest valid exponent)
 
-      // Zero with non-zero exponent -> Zero
-      {"0x0p+0", 0.f},
-      {"0x0p+1", 0.f},
-      {"0x0p-1", 0.f},
-      {"0x0p+9999999999", 0.f},
-      {"0x0p-9999999999", 0.f},
-      // Same, but with very large positive exponents that would cause overflow
-      // if the mantissa were non-zero.
-      {"0x0p+4000000000", 0.f},    // 4 billion:
-      {"0x0p+40000000000", 0.f},   // 40 billion
-      {"-0x0p+40000000000", 0.f},  // As above 2, but negative mantissa
-      {"-0x0p+400000000000", 0.f},
-      {"0x0.00p+4000000000", 0.f},  // As above 4, but with fractional part
-      {"0x0.00p+40000000000", 0.f},
-      {"-0x0.00p+40000000000", 0.f},
-      {"-0x0.00p+400000000000", 0.f},
-      {"0x0p-4000000000", 0.f},  // As above 8, but with negative exponents
-      {"0x0p-40000000000", 0.f},
-      {"-0x0p-40000000000", 0.f},
-      {"-0x0p-400000000000", 0.f},
-      {"0x0.00p-4000000000", 0.f},
-      {"0x0.00p-40000000000", 0.f},
-      {"-0x0.00p-40000000000", 0.f},
-      {"-0x0.00p-400000000000", 0.f},
+        // Zero with non-zero exponent -> Zero
+        {"0x0p+0", 0.f},
+        {"0x0p+1", 0.f},
+        {"0x0p-1", 0.f},
+        {"0x0p+9999999999", 0.f},
+        {"0x0p-9999999999", 0.f},
+        // Same, but with very large positive exponents that would cause overflow
+        // if the mantissa were non-zero.
+        {"0x0p+4000000000", 0.f},    // 4 billion:
+        {"0x0p+40000000000", 0.f},   // 40 billion
+        {"-0x0p+40000000000", 0.f},  // As above 2, but negative mantissa
+        {"-0x0p+400000000000", 0.f},
+        {"0x0.00p+4000000000", 0.f},  // As above 4, but with fractional part
+        {"0x0.00p+40000000000", 0.f},
+        {"-0x0.00p+40000000000", 0.f},
+        {"-0x0.00p+400000000000", 0.f},
+        {"0x0p-4000000000", 0.f},  // As above 8, but with negative exponents
+        {"0x0p-40000000000", 0.f},
+        {"-0x0p-40000000000", 0.f},
+        {"-0x0p-400000000000", 0.f},
+        {"0x0.00p-4000000000", 0.f},
+        {"0x0.00p-40000000000", 0.f},
+        {"-0x0.00p-40000000000", 0.f},
+        {"-0x0.00p-400000000000", 0.f},
 
-      // Test parsing
-      {"0x0p0", 0.f},
-      {"0x0p-0", 0.f},
-      {"0x0p+000", 0.f},
-      {"0x00000000000000p+000000000000000", 0.f},
-      {"0x00000000000000p-000000000000000", 0.f},
-      {"0x00000000000001p+000000000000000", 1.f},
-      {"0x00000000000001p-000000000000000", 1.f},
-      {"0x0000000000000000000001.99999ap-000000000000000004", 0.1f},
-      {"0x2p+0", 2.f},
-      {"0xFFp+0", 255.f},
-      {"0x0.8p+0", 0.5f},
-      {"0x0.4p+0", 0.25f},
-      {"0x0.4p+1", 2 * 0.25f},
-      {"0x0.4p+2", 4 * 0.25f},
-      {"0x123Ep+1", 9340.f},
-      {"-0x123Ep+1", -9340.f},
-      {"0x1a2b3cP12", 7.024656e+09f},
-      {"-0x1a2b3cP12", -7.024656e+09f},
+        // Test parsing
+        {"0x0p0", 0.f},
+        {"0x0p-0", 0.f},
+        {"0x0p+000", 0.f},
+        {"0x00000000000000p+000000000000000", 0.f},
+        {"0x00000000000000p-000000000000000", 0.f},
+        {"0x00000000000001p+000000000000000", 1.f},
+        {"0x00000000000001p-000000000000000", 1.f},
+        {"0x0000000000000000000001.99999ap-000000000000000004", 0.1f},
+        {"0x2p+0", 2.f},
+        {"0xFFp+0", 255.f},
+        {"0x0.8p+0", 0.5f},
+        {"0x0.4p+0", 0.25f},
+        {"0x0.4p+1", 2 * 0.25f},
+        {"0x0.4p+2", 4 * 0.25f},
+        {"0x123Ep+1", 9340.f},
+        {"-0x123Ep+1", -9340.f},
+        {"0x1a2b3cP12", 7.024656e+09f},
+        {"-0x1a2b3cP12", -7.024656e+09f},
 
-      // Examples without a binary exponent part.
-      {"0x1.", 1.0f},
-      {"0x.8", 0.5f},
-      {"0x1.8", 1.5f},
-      {"-0x1.", -1.0f},
-      {"-0x.8", -0.5f},
-      {"-0x1.8", -1.5f},
+        // Examples without a binary exponent part.
+        {"0x1.", 1.0f},
+        {"0x.8", 0.5f},
+        {"0x1.8", 1.5f},
+        {"-0x1.", -1.0f},
+        {"-0x.8", -0.5f},
+        {"-0x1.8", -1.5f},
 
-      // Examples with a binary exponent and a 'f' suffix.
-      {"0x1.p0f", 1.0f},
-      {"0x.8p2f", 2.0f},
-      {"0x1.8p-1f", 0.75f},
-      {"0x2p-2f", 0.5f},  // No binary point
-      {"-0x1.p0f", -1.0f},
-      {"-0x.8p2f", -2.0f},
-      {"-0x1.8p-1f", -0.75f},
-      {"-0x2p-2f", -0.5f},  // No binary point
-  };
+        // Examples with a binary exponent and a 'f' suffix.
+        {"0x1.p0f", 1.0f},
+        {"0x.8p2f", 2.0f},
+        {"0x1.8p-1f", 0.75f},
+        {"0x2p-2f", 0.5f},  // No binary point
+        {"-0x1.p0f", -1.0f},
+        {"-0x.8p2f", -2.0f},
+        {"-0x1.8p-1f", -0.75f},
+        {"-0x2p-2f", -0.5f},  // No binary point
+    };
 }
 INSTANTIATE_TEST_SUITE_P(ParserImplFloatLiteralTest_HexFloat,
                          ParserImplFloatLiteralTest,
@@ -348,30 +397,30 @@
 // Now test all the same hex float cases, but with 0X instead of 0x
 template <typename ARR>
 std::vector<FloatLiteralTestCase> UpperCase0X(const ARR& cases) {
-  std::vector<FloatLiteralTestCase> result;
-  result.reserve(cases.size());
-  for (const auto& c : cases) {
-    result.emplace_back(c);
-    auto& input = result.back().input;
-    const auto where = input.find("0x");
-    if (where != std::string::npos) {
-      input[where+1] = 'X';
+    std::vector<FloatLiteralTestCase> result;
+    result.reserve(cases.size());
+    for (const auto& c : cases) {
+        result.emplace_back(c);
+        auto& input = result.back().input;
+        const auto where = input.find("0x");
+        if (where != std::string::npos) {
+            input[where + 1] = 'X';
+        }
     }
-  }
-  return result;
+    return result;
 }
 
 using UpperCase0XTest = ::testing::Test;
 TEST_F(UpperCase0XTest, Samples) {
-  const auto cases = FloatLiteralTestCaseList{
-      {"absent", 0.0}, {"0x", 1.0},      {"0X", 2.0},      {"-0x", 3.0},
-      {"-0X", 4.0},    {"  0x1p1", 5.0}, {"  -0x1p", 6.0}, {" examine ", 7.0}};
-  const auto expected = FloatLiteralTestCaseList{
-      {"absent", 0.0}, {"0X", 1.0},      {"0X", 2.0},      {"-0X", 3.0},
-      {"-0X", 4.0},    {"  0X1p1", 5.0}, {"  -0X1p", 6.0}, {" examine ", 7.0}};
+    const auto cases = FloatLiteralTestCaseList{
+        {"absent", 0.0}, {"0x", 1.0},      {"0X", 2.0},      {"-0x", 3.0},
+        {"-0X", 4.0},    {"  0x1p1", 5.0}, {"  -0x1p", 6.0}, {" examine ", 7.0}};
+    const auto expected = FloatLiteralTestCaseList{
+        {"absent", 0.0}, {"0X", 1.0},      {"0X", 2.0},      {"-0X", 3.0},
+        {"-0X", 4.0},    {"  0X1p1", 5.0}, {"  -0X1p", 6.0}, {" examine ", 7.0}};
 
-  auto result = UpperCase0X(cases);
-  EXPECT_THAT(result, ::testing::ElementsAreArray(expected));
+    auto result = UpperCase0X(cases);
+    EXPECT_THAT(result, ::testing::ElementsAreArray(expected));
 }
 
 INSTANTIATE_TEST_SUITE_P(ParserImplFloatLiteralTest_HexFloat_UpperCase0X,
@@ -379,20 +428,19 @@
                          testing::ValuesIn(UpperCase0X(HexFloatCases())));
 
 struct InvalidLiteralTestCase {
-  const char* input;
-  const char* error_msg;
+    const char* input;
+    const char* error_msg;
 };
-class ParserImplInvalidLiteralTest
-    : public ParserImplTestWithParam<InvalidLiteralTestCase> {};
+class ParserImplInvalidLiteralTest : public ParserImplTestWithParam<InvalidLiteralTestCase> {};
 TEST_P(ParserImplInvalidLiteralTest, Parse) {
-  auto params = GetParam();
-  SCOPED_TRACE(params.input);
-  auto p = parser(params.input);
-  auto c = p->const_literal();
-  EXPECT_FALSE(c.matched);
-  EXPECT_TRUE(c.errored);
-  EXPECT_EQ(p->error(), params.error_msg);
-  ASSERT_EQ(c.value, nullptr);
+    auto params = GetParam();
+    SCOPED_TRACE(params.input);
+    auto p = parser(params.input);
+    auto c = p->const_literal();
+    EXPECT_FALSE(c.matched);
+    EXPECT_TRUE(c.errored);
+    EXPECT_EQ(p->error(), params.error_msg);
+    ASSERT_EQ(c.value, nullptr);
 }
 
 InvalidLiteralTestCase invalid_hexfloat_mantissa_too_large_cases[] = {
@@ -407,10 +455,9 @@
     {"0x1ffffffff.8p0", "1:1: mantissa is too large for hex float"},
     {"0x1ffffffff8.p0", "1:1: mantissa is too large for hex float"},
 };
-INSTANTIATE_TEST_SUITE_P(
-    ParserImplInvalidLiteralTest_HexFloatMantissaTooLarge,
-    ParserImplInvalidLiteralTest,
-    testing::ValuesIn(invalid_hexfloat_mantissa_too_large_cases));
+INSTANTIATE_TEST_SUITE_P(ParserImplInvalidLiteralTest_HexFloatMantissaTooLarge,
+                         ParserImplInvalidLiteralTest,
+                         testing::ValuesIn(invalid_hexfloat_mantissa_too_large_cases));
 
 InvalidLiteralTestCase invalid_hexfloat_exponent_too_large_cases[] = {
     {"0x1p+2147483521", "1:1: exponent is too large for hex float"},
@@ -418,10 +465,9 @@
     {"0x1p+4294967296", "1:1: exponent is too large for hex float"},
     {"0x1p-4294967296", "1:1: exponent is too large for hex float"},
 };
-INSTANTIATE_TEST_SUITE_P(
-    ParserImplInvalidLiteralTest_HexFloatExponentTooLarge,
-    ParserImplInvalidLiteralTest,
-    testing::ValuesIn(invalid_hexfloat_exponent_too_large_cases));
+INSTANTIATE_TEST_SUITE_P(ParserImplInvalidLiteralTest_HexFloatExponentTooLarge,
+                         ParserImplInvalidLiteralTest,
+                         testing::ValuesIn(invalid_hexfloat_exponent_too_large_cases));
 
 InvalidLiteralTestCase invalid_hexfloat_exponent_missing_cases[] = {
     // Lower case p
@@ -437,84 +483,81 @@
     {"0x1.0P", "1:1: expected an exponent value for hex float"},
     {"0x0.1P", "1:1: expected an exponent value for hex float"},
 };
-INSTANTIATE_TEST_SUITE_P(
-    ParserImplInvalidLiteralTest_HexFloatExponentMissing,
-    ParserImplInvalidLiteralTest,
-    testing::ValuesIn(invalid_hexfloat_exponent_missing_cases));
+INSTANTIATE_TEST_SUITE_P(ParserImplInvalidLiteralTest_HexFloatExponentMissing,
+                         ParserImplInvalidLiteralTest,
+                         testing::ValuesIn(invalid_hexfloat_exponent_missing_cases));
 
 TEST_F(ParserImplTest, ConstLiteral_FloatHighest) {
-  const auto highest = std::numeric_limits<float>::max();
-  const auto expected_highest = 340282346638528859811704183484516925440.0f;
-  if (highest < expected_highest || highest > expected_highest) {
-    GTEST_SKIP() << "std::numeric_limits<float>::max() is not as expected for "
-                    "this target";
-  }
-  auto p = parser("340282346638528859811704183484516925440.0");
-  auto c = p->const_literal();
-  EXPECT_TRUE(c.matched);
-  EXPECT_FALSE(c.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(c.value, nullptr);
-  ASSERT_TRUE(c->Is<ast::FloatLiteralExpression>());
-  EXPECT_FLOAT_EQ(c->As<ast::FloatLiteralExpression>()->value,
-                  std::numeric_limits<float>::max());
-  EXPECT_EQ(c->source.range, (Source::Range{{1u, 1u}, {1u, 42u}}));
+    const auto highest = std::numeric_limits<float>::max();
+    const auto expected_highest = 340282346638528859811704183484516925440.0f;
+    if (highest < expected_highest || highest > expected_highest) {
+        GTEST_SKIP() << "std::numeric_limits<float>::max() is not as expected for "
+                        "this target";
+    }
+    auto p = parser("340282346638528859811704183484516925440.0");
+    auto c = p->const_literal();
+    EXPECT_TRUE(c.matched);
+    EXPECT_FALSE(c.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(c.value, nullptr);
+    ASSERT_TRUE(c->Is<ast::FloatLiteralExpression>());
+    EXPECT_FLOAT_EQ(c->As<ast::FloatLiteralExpression>()->value, std::numeric_limits<float>::max());
+    EXPECT_EQ(c->source.range, (Source::Range{{1u, 1u}, {1u, 42u}}));
 }
 
 TEST_F(ParserImplTest, ConstLiteral_FloatLowest) {
-  // Some compilers complain if you test floating point numbers for equality.
-  // So say it via two inequalities.
-  const auto lowest = std::numeric_limits<float>::lowest();
-  const auto expected_lowest = -340282346638528859811704183484516925440.0f;
-  if (lowest < expected_lowest || lowest > expected_lowest) {
-    GTEST_SKIP()
-        << "std::numeric_limits<float>::lowest() is not as expected for "
-           "this target";
-  }
+    // Some compilers complain if you test floating point numbers for equality.
+    // So say it via two inequalities.
+    const auto lowest = std::numeric_limits<float>::lowest();
+    const auto expected_lowest = -340282346638528859811704183484516925440.0f;
+    if (lowest < expected_lowest || lowest > expected_lowest) {
+        GTEST_SKIP() << "std::numeric_limits<float>::lowest() is not as expected for "
+                        "this target";
+    }
 
-  auto p = parser("-340282346638528859811704183484516925440.0");
-  auto c = p->const_literal();
-  EXPECT_TRUE(c.matched);
-  EXPECT_FALSE(c.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(c.value, nullptr);
-  ASSERT_TRUE(c->Is<ast::FloatLiteralExpression>());
-  EXPECT_FLOAT_EQ(c->As<ast::FloatLiteralExpression>()->value,
-                  std::numeric_limits<float>::lowest());
-  EXPECT_EQ(c->source.range, (Source::Range{{1u, 1u}, {1u, 43u}}));
+    auto p = parser("-340282346638528859811704183484516925440.0");
+    auto c = p->const_literal();
+    EXPECT_TRUE(c.matched);
+    EXPECT_FALSE(c.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(c.value, nullptr);
+    ASSERT_TRUE(c->Is<ast::FloatLiteralExpression>());
+    EXPECT_FLOAT_EQ(c->As<ast::FloatLiteralExpression>()->value,
+                    std::numeric_limits<float>::lowest());
+    EXPECT_EQ(c->source.range, (Source::Range{{1u, 1u}, {1u, 43u}}));
 }
 
 TEST_F(ParserImplTest, ConstLiteral_True) {
-  auto p = parser("true");
-  auto c = p->const_literal();
-  EXPECT_TRUE(c.matched);
-  EXPECT_FALSE(c.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(c.value, nullptr);
-  ASSERT_TRUE(c->Is<ast::BoolLiteralExpression>());
-  EXPECT_TRUE(c->As<ast::BoolLiteralExpression>()->value);
-  EXPECT_EQ(c->source.range, (Source::Range{{1u, 1u}, {1u, 5u}}));
+    auto p = parser("true");
+    auto c = p->const_literal();
+    EXPECT_TRUE(c.matched);
+    EXPECT_FALSE(c.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(c.value, nullptr);
+    ASSERT_TRUE(c->Is<ast::BoolLiteralExpression>());
+    EXPECT_TRUE(c->As<ast::BoolLiteralExpression>()->value);
+    EXPECT_EQ(c->source.range, (Source::Range{{1u, 1u}, {1u, 5u}}));
 }
 
 TEST_F(ParserImplTest, ConstLiteral_False) {
-  auto p = parser("false");
-  auto c = p->const_literal();
-  EXPECT_TRUE(c.matched);
-  EXPECT_FALSE(c.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(c.value, nullptr);
-  ASSERT_TRUE(c->Is<ast::BoolLiteralExpression>());
-  EXPECT_FALSE(c->As<ast::BoolLiteralExpression>()->value);
-  EXPECT_EQ(c->source.range, (Source::Range{{1u, 1u}, {1u, 6u}}));
+    auto p = parser("false");
+    auto c = p->const_literal();
+    EXPECT_TRUE(c.matched);
+    EXPECT_FALSE(c.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(c.value, nullptr);
+    ASSERT_TRUE(c->Is<ast::BoolLiteralExpression>());
+    EXPECT_FALSE(c->As<ast::BoolLiteralExpression>()->value);
+    EXPECT_EQ(c->source.range, (Source::Range{{1u, 1u}, {1u, 6u}}));
 }
 
 TEST_F(ParserImplTest, ConstLiteral_NoMatch) {
-  auto p = parser("another-token");
-  auto c = p->const_literal();
-  EXPECT_FALSE(c.matched);
-  EXPECT_FALSE(c.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_EQ(c.value, nullptr);
+    auto p = parser("another-token");
+    auto c = p->const_literal();
+    EXPECT_FALSE(c.matched);
+    EXPECT_FALSE(c.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_EQ(c.value, nullptr);
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_continue_stmt_test.cc b/src/tint/reader/wgsl/parser_impl_continue_stmt_test.cc
index 34a9d51..002f638 100644
--- a/src/tint/reader/wgsl/parser_impl_continue_stmt_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_continue_stmt_test.cc
@@ -19,12 +19,12 @@
 namespace {
 
 TEST_F(ParserImplTest, ContinueStmt) {
-  auto p = parser("continue");
-  auto e = p->continue_stmt();
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::ContinueStatement>());
+    auto p = parser("continue");
+    auto e = p->continue_stmt();
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::ContinueStatement>());
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_continuing_stmt_test.cc b/src/tint/reader/wgsl/parser_impl_continuing_stmt_test.cc
index 80f2e0e..d7a5779 100644
--- a/src/tint/reader/wgsl/parser_impl_continuing_stmt_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_continuing_stmt_test.cc
@@ -19,23 +19,23 @@
 namespace {
 
 TEST_F(ParserImplTest, ContinuingStmt) {
-  auto p = parser("continuing { discard; }");
-  auto e = p->continuing_stmt();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_EQ(e->statements.size(), 1u);
-  ASSERT_TRUE(e->statements[0]->Is<ast::DiscardStatement>());
+    auto p = parser("continuing { discard; }");
+    auto e = p->continuing_stmt();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_EQ(e->statements.size(), 1u);
+    ASSERT_TRUE(e->statements[0]->Is<ast::DiscardStatement>());
 }
 
 TEST_F(ParserImplTest, ContinuingStmt_InvalidBody) {
-  auto p = parser("continuing { discard }");
-  auto e = p->continuing_stmt();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:22: expected ';' for discard statement");
+    auto p = parser("continuing { discard }");
+    auto e = p->continuing_stmt();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:22: expected ';' for discard statement");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_depth_texture_test.cc b/src/tint/reader/wgsl/parser_impl_depth_texture_test.cc
new file mode 100644
index 0000000..6c70bd3
--- /dev/null
+++ b/src/tint/reader/wgsl/parser_impl_depth_texture_test.cc
@@ -0,0 +1,95 @@
+// Copyright 2020 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/reader/wgsl/parser_impl_test_helper.h"
+#include "src/tint/sem/depth_texture.h"
+
+namespace tint::reader::wgsl {
+namespace {
+
+TEST_F(ParserImplTest, DepthTextureType_Invalid) {
+    auto p = parser("1234");
+    auto t = p->depth_texture();
+    EXPECT_FALSE(t.matched);
+    EXPECT_FALSE(t.errored);
+    EXPECT_FALSE(p->has_error());
+}
+
+TEST_F(ParserImplTest, DepthTextureType_2d) {
+    auto p = parser("texture_depth_2d");
+    auto t = p->depth_texture();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    ASSERT_NE(t.value, nullptr);
+    ASSERT_TRUE(t->Is<ast::Texture>());
+    ASSERT_TRUE(t->Is<ast::DepthTexture>());
+    EXPECT_EQ(t->As<ast::Texture>()->dim, ast::TextureDimension::k2d);
+    EXPECT_FALSE(p->has_error());
+    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 17u}}));
+}
+
+TEST_F(ParserImplTest, DepthTextureType_2dArray) {
+    auto p = parser("texture_depth_2d_array");
+    auto t = p->depth_texture();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    ASSERT_NE(t.value, nullptr);
+    ASSERT_TRUE(t->Is<ast::Texture>());
+    ASSERT_TRUE(t->Is<ast::DepthTexture>());
+    EXPECT_EQ(t->As<ast::Texture>()->dim, ast::TextureDimension::k2dArray);
+    EXPECT_FALSE(p->has_error());
+    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 23u}}));
+}
+
+TEST_F(ParserImplTest, DepthTextureType_Cube) {
+    auto p = parser("texture_depth_cube");
+    auto t = p->depth_texture();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    ASSERT_NE(t.value, nullptr);
+    ASSERT_TRUE(t->Is<ast::Texture>());
+    ASSERT_TRUE(t->Is<ast::DepthTexture>());
+    EXPECT_EQ(t->As<ast::Texture>()->dim, ast::TextureDimension::kCube);
+    EXPECT_FALSE(p->has_error());
+    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 19u}}));
+}
+
+TEST_F(ParserImplTest, DepthTextureType_CubeArray) {
+    auto p = parser("texture_depth_cube_array");
+    auto t = p->depth_texture();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    ASSERT_NE(t.value, nullptr);
+    ASSERT_TRUE(t->Is<ast::Texture>());
+    ASSERT_TRUE(t->Is<ast::DepthTexture>());
+    EXPECT_EQ(t->As<ast::Texture>()->dim, ast::TextureDimension::kCubeArray);
+    EXPECT_FALSE(p->has_error());
+    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 25u}}));
+}
+
+TEST_F(ParserImplTest, DepthTextureType_Multisampled2d) {
+    auto p = parser("texture_depth_multisampled_2d");
+    auto t = p->depth_texture();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    ASSERT_NE(t.value, nullptr);
+    ASSERT_TRUE(t->Is<ast::Texture>());
+    ASSERT_TRUE(t->Is<ast::DepthMultisampledTexture>());
+    EXPECT_EQ(t->As<ast::Texture>()->dim, ast::TextureDimension::k2d);
+    EXPECT_FALSE(p->has_error());
+    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 30u}}));
+}
+
+}  // namespace
+}  // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/parser_impl_depth_texture_type_test.cc b/src/tint/reader/wgsl/parser_impl_depth_texture_type_test.cc
deleted file mode 100644
index 6a9c528..0000000
--- a/src/tint/reader/wgsl/parser_impl_depth_texture_type_test.cc
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright 2020 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/tint/reader/wgsl/parser_impl_test_helper.h"
-#include "src/tint/sem/depth_texture_type.h"
-
-namespace tint::reader::wgsl {
-namespace {
-
-TEST_F(ParserImplTest, DepthTextureType_Invalid) {
-  auto p = parser("1234");
-  auto t = p->depth_texture_type();
-  EXPECT_FALSE(t.matched);
-  EXPECT_FALSE(t.errored);
-  EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, DepthTextureType_2d) {
-  auto p = parser("texture_depth_2d");
-  auto t = p->depth_texture_type();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  ASSERT_NE(t.value, nullptr);
-  ASSERT_TRUE(t->Is<ast::Texture>());
-  ASSERT_TRUE(t->Is<ast::DepthTexture>());
-  EXPECT_EQ(t->As<ast::Texture>()->dim, ast::TextureDimension::k2d);
-  EXPECT_FALSE(p->has_error());
-  EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 17u}}));
-}
-
-TEST_F(ParserImplTest, DepthTextureType_2dArray) {
-  auto p = parser("texture_depth_2d_array");
-  auto t = p->depth_texture_type();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  ASSERT_NE(t.value, nullptr);
-  ASSERT_TRUE(t->Is<ast::Texture>());
-  ASSERT_TRUE(t->Is<ast::DepthTexture>());
-  EXPECT_EQ(t->As<ast::Texture>()->dim, ast::TextureDimension::k2dArray);
-  EXPECT_FALSE(p->has_error());
-  EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 23u}}));
-}
-
-TEST_F(ParserImplTest, DepthTextureType_Cube) {
-  auto p = parser("texture_depth_cube");
-  auto t = p->depth_texture_type();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  ASSERT_NE(t.value, nullptr);
-  ASSERT_TRUE(t->Is<ast::Texture>());
-  ASSERT_TRUE(t->Is<ast::DepthTexture>());
-  EXPECT_EQ(t->As<ast::Texture>()->dim, ast::TextureDimension::kCube);
-  EXPECT_FALSE(p->has_error());
-  EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 19u}}));
-}
-
-TEST_F(ParserImplTest, DepthTextureType_CubeArray) {
-  auto p = parser("texture_depth_cube_array");
-  auto t = p->depth_texture_type();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  ASSERT_NE(t.value, nullptr);
-  ASSERT_TRUE(t->Is<ast::Texture>());
-  ASSERT_TRUE(t->Is<ast::DepthTexture>());
-  EXPECT_EQ(t->As<ast::Texture>()->dim, ast::TextureDimension::kCubeArray);
-  EXPECT_FALSE(p->has_error());
-  EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 25u}}));
-}
-
-TEST_F(ParserImplTest, DepthTextureType_Multisampled2d) {
-  auto p = parser("texture_depth_multisampled_2d");
-  auto t = p->depth_texture_type();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  ASSERT_NE(t.value, nullptr);
-  ASSERT_TRUE(t->Is<ast::Texture>());
-  ASSERT_TRUE(t->Is<ast::DepthMultisampledTexture>());
-  EXPECT_EQ(t->As<ast::Texture>()->dim, ast::TextureDimension::k2d);
-  EXPECT_FALSE(p->has_error());
-  EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 30u}}));
-}
-
-}  // namespace
-}  // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/parser_impl_detail.h b/src/tint/reader/wgsl/parser_impl_detail.h
index 02d63df..d25edff 100644
--- a/src/tint/reader/wgsl/parser_impl_detail.h
+++ b/src/tint/reader/wgsl/parser_impl_detail.h
@@ -29,34 +29,34 @@
 /// the Expect<T> or Maybe<T> is not in an error state before dereferencing.
 template <typename T>
 struct OperatorArrow {
-  /// type resolves to the return type for the operator->()
-  using type = T*;
-  /// @param val the value held by `ParserImpl::Expect<T>` or
-  /// `ParserImpl::Maybe<T>`.
-  /// @return a pointer to `val`
-  static inline T* ptr(T& val) { return &val; }
+    /// type resolves to the return type for the operator->()
+    using type = T*;
+    /// @param val the value held by `ParserImpl::Expect<T>` or
+    /// `ParserImpl::Maybe<T>`.
+    /// @return a pointer to `val`
+    static inline T* ptr(T& val) { return &val; }
 };
 
 /// OperatorArrow template specialization for std::unique_ptr<>.
 template <typename T>
 struct OperatorArrow<std::unique_ptr<T>> {
-  /// type resolves to the return type for the operator->()
-  using type = T*;
-  /// @param val the value held by `ParserImpl::Expect<T>` or
-  /// `ParserImpl::Maybe<T>`.
-  /// @return the raw pointer held by `val`.
-  static inline T* ptr(std::unique_ptr<T>& val) { return val.get(); }
+    /// type resolves to the return type for the operator->()
+    using type = T*;
+    /// @param val the value held by `ParserImpl::Expect<T>` or
+    /// `ParserImpl::Maybe<T>`.
+    /// @return the raw pointer held by `val`.
+    static inline T* ptr(std::unique_ptr<T>& val) { return val.get(); }
 };
 
 /// OperatorArrow template specialization for T*.
 template <typename T>
 struct OperatorArrow<T*> {
-  /// type resolves to the return type for the operator->()
-  using type = T*;
-  /// @param val the value held by `ParserImpl::Expect<T>` or
-  /// `ParserImpl::Maybe<T>`.
-  /// @return `val`.
-  static inline T* ptr(T* val) { return val; }
+    /// type resolves to the return type for the operator->()
+    using type = T*;
+    /// @param val the value held by `ParserImpl::Expect<T>` or
+    /// `ParserImpl::Maybe<T>`.
+    /// @return `val`.
+    static inline T* ptr(T* val) { return val; }
 };
 
 }  // namespace tint::reader::wgsl::detail
diff --git a/src/tint/reader/wgsl/parser_impl_elseif_stmt_test.cc b/src/tint/reader/wgsl/parser_impl_elseif_stmt_test.cc
deleted file mode 100644
index f0fb963..0000000
--- a/src/tint/reader/wgsl/parser_impl_elseif_stmt_test.cc
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2020 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/tint/reader/wgsl/parser_impl_test_helper.h"
-
-namespace tint::reader::wgsl {
-namespace {
-
-TEST_F(ParserImplTest, ElseStmts) {
-  auto p = parser("else if (a == 4) { a = b; c = d; }");
-  auto e = p->else_stmts();
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_EQ(e.value.size(), 1u);
-
-  ASSERT_TRUE(e.value[0]->Is<ast::ElseStatement>());
-  ASSERT_NE(e.value[0]->condition, nullptr);
-  ASSERT_TRUE(e.value[0]->condition->Is<ast::BinaryExpression>());
-  EXPECT_EQ(e.value[0]->body->statements.size(), 2u);
-}
-
-TEST_F(ParserImplTest, ElseStmts_Multiple) {
-  auto p = parser("else if (a == 4) { a = b; c = d; } else if(c) { d = 2; }");
-  auto e = p->else_stmts();
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_EQ(e.value.size(), 2u);
-
-  ASSERT_TRUE(e.value[0]->Is<ast::ElseStatement>());
-  ASSERT_NE(e.value[0]->condition, nullptr);
-  ASSERT_TRUE(e.value[0]->condition->Is<ast::BinaryExpression>());
-  EXPECT_EQ(e.value[0]->body->statements.size(), 2u);
-
-  ASSERT_TRUE(e.value[1]->Is<ast::ElseStatement>());
-  ASSERT_NE(e.value[1]->condition, nullptr);
-  ASSERT_TRUE(e.value[1]->condition->Is<ast::IdentifierExpression>());
-  EXPECT_EQ(e.value[1]->body->statements.size(), 1u);
-}
-
-TEST_F(ParserImplTest, ElseStmts_InvalidBody) {
-  auto p = parser("else if (true) { fn main() {}}");
-  auto e = p->else_stmts();
-  EXPECT_TRUE(e.errored);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:18: expected '}'");
-}
-
-TEST_F(ParserImplTest, ElseStmts_MissingBody) {
-  auto p = parser("else if (true)");
-  auto e = p->else_stmts();
-  EXPECT_TRUE(e.errored);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:15: expected '{'");
-}
-
-}  // namespace
-}  // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/parser_impl_enable_directive_test.cc b/src/tint/reader/wgsl/parser_impl_enable_directive_test.cc
new file mode 100644
index 0000000..0fd6b80
--- /dev/null
+++ b/src/tint/reader/wgsl/parser_impl_enable_directive_test.cc
@@ -0,0 +1,168 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/reader/wgsl/parser_impl_test_helper.h"
+
+#include "src/tint/ast/enable.h"
+
+namespace tint::reader::wgsl {
+namespace {
+
+using EnableDirectiveTest = ParserImplTest;
+
+// Test a valid enable directive.
+TEST_F(EnableDirectiveTest, Valid) {
+    auto p = parser("enable InternalExtensionForTesting;");
+    p->enable_directive();
+    EXPECT_FALSE(p->has_error()) << p->error();
+    auto program = p->program();
+    auto& ast = program.AST();
+    EXPECT_EQ(ast.Extensions(),
+              ast::ExtensionSet{ast::Enable::ExtensionKind::kInternalExtensionForTesting});
+    EXPECT_EQ(ast.GlobalDeclarations().size(), 1u);
+    auto* node = ast.GlobalDeclarations()[0]->As<ast::Enable>();
+    EXPECT_TRUE(node != nullptr);
+    EXPECT_EQ(node->name, "InternalExtensionForTesting");
+    EXPECT_EQ(node->kind, ast::Enable::ExtensionKind::kInternalExtensionForTesting);
+}
+
+// Test multiple enable directives for a same extension.
+TEST_F(EnableDirectiveTest, EnableMultipleTime) {
+    auto p = parser(R"(
+enable InternalExtensionForTesting;
+enable InternalExtensionForTesting;
+)");
+    p->translation_unit();
+    EXPECT_FALSE(p->has_error()) << p->error();
+    auto program = p->program();
+    auto& ast = program.AST();
+    EXPECT_EQ(ast.Extensions(),
+              ast::ExtensionSet{ast::Enable::ExtensionKind::kInternalExtensionForTesting});
+    EXPECT_EQ(ast.GlobalDeclarations().size(), 2u);
+    auto* node1 = ast.GlobalDeclarations()[0]->As<ast::Enable>();
+    EXPECT_TRUE(node1 != nullptr);
+    EXPECT_EQ(node1->name, "InternalExtensionForTesting");
+    EXPECT_EQ(node1->kind, ast::Enable::ExtensionKind::kInternalExtensionForTesting);
+    auto* node2 = ast.GlobalDeclarations()[1]->As<ast::Enable>();
+    EXPECT_TRUE(node2 != nullptr);
+    EXPECT_EQ(node2->name, "InternalExtensionForTesting");
+    EXPECT_EQ(node2->kind, ast::Enable::ExtensionKind::kInternalExtensionForTesting);
+}
+
+// Test an unknown extension identifier.
+TEST_F(EnableDirectiveTest, InvalidIdentifier) {
+    auto p = parser("enable NotAValidExtensionName;");
+    p->enable_directive();
+    // Error when unknown extension found
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:8: unsupported extension: 'NotAValidExtensionName'");
+    auto program = p->program();
+    auto& ast = program.AST();
+    EXPECT_EQ(ast.Extensions().size(), 0u);
+    EXPECT_EQ(ast.GlobalDeclarations().size(), 0u);
+}
+
+// Test an enable directive missing ending semiclon.
+TEST_F(EnableDirectiveTest, MissingEndingSemiclon) {
+    auto p = parser("enable InternalExtensionForTesting");
+    p->translation_unit();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:35: expected ';' for enable directive");
+    auto program = p->program();
+    auto& ast = program.AST();
+    EXPECT_EQ(ast.Extensions().size(), 0u);
+    EXPECT_EQ(ast.GlobalDeclarations().size(), 0u);
+}
+
+// Test using invalid tokens in an enable directive.
+TEST_F(EnableDirectiveTest, InvalidTokens) {
+    {
+        auto p = parser("enable InternalExtensionForTesting<;");
+        p->translation_unit();
+        EXPECT_TRUE(p->has_error());
+        EXPECT_EQ(p->error(), "1:35: expected ';' for enable directive");
+        auto program = p->program();
+        auto& ast = program.AST();
+        EXPECT_EQ(ast.Extensions().size(), 0u);
+        EXPECT_EQ(ast.GlobalDeclarations().size(), 0u);
+    }
+    {
+        auto p = parser("enable <InternalExtensionForTesting;");
+        p->translation_unit();
+        EXPECT_TRUE(p->has_error());
+        EXPECT_EQ(p->error(), "1:8: invalid extension name");
+        auto program = p->program();
+        auto& ast = program.AST();
+        EXPECT_EQ(ast.Extensions().size(), 0u);
+        EXPECT_EQ(ast.GlobalDeclarations().size(), 0u);
+    }
+    {
+        auto p = parser("enable =;");
+        p->translation_unit();
+        EXPECT_TRUE(p->has_error());
+        EXPECT_EQ(p->error(), "1:8: invalid extension name");
+        auto program = p->program();
+        auto& ast = program.AST();
+        EXPECT_EQ(ast.Extensions().size(), 0u);
+        EXPECT_EQ(ast.GlobalDeclarations().size(), 0u);
+    }
+    {
+        auto p = parser("enable vec4;");
+        p->translation_unit();
+        EXPECT_TRUE(p->has_error());
+        EXPECT_EQ(p->error(), "1:8: invalid extension name");
+        auto program = p->program();
+        auto& ast = program.AST();
+        EXPECT_EQ(ast.Extensions().size(), 0u);
+        EXPECT_EQ(ast.GlobalDeclarations().size(), 0u);
+    }
+}
+
+// Test an enable directive go after other global declarations.
+TEST_F(EnableDirectiveTest, FollowingOtherGlobalDecl) {
+    auto p = parser(R"(
+var<private> t: f32 = 0f;
+enable InternalExtensionForTesting;
+)");
+    p->translation_unit();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "3:1: enable directives must come before all global declarations");
+    auto program = p->program();
+    auto& ast = program.AST();
+    // Accept the enable directive although it cause an error
+    EXPECT_EQ(ast.Extensions(),
+              ast::ExtensionSet{ast::Enable::ExtensionKind::kInternalExtensionForTesting});
+    EXPECT_EQ(ast.GlobalDeclarations().size(), 2u);
+}
+
+// Test an enable directive go after an empty semiclon.
+TEST_F(EnableDirectiveTest, FollowingEmptySemiclon) {
+    auto p = parser(R"(
+;
+enable InternalExtensionForTesting;
+)");
+    p->translation_unit();
+    // An empty semiclon is treated as a global declaration
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "3:1: enable directives must come before all global declarations");
+    auto program = p->program();
+    auto& ast = program.AST();
+    // Accept the enable directive although it cause an error
+    EXPECT_EQ(ast.Extensions(),
+              ast::ExtensionSet{ast::Enable::ExtensionKind::kInternalExtensionForTesting});
+    EXPECT_EQ(ast.GlobalDeclarations().size(), 1u);
+}
+
+}  // namespace
+}  // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/parser_impl_equality_expression_test.cc b/src/tint/reader/wgsl/parser_impl_equality_expression_test.cc
index 64cf213..4e1f5a3 100644
--- a/src/tint/reader/wgsl/parser_impl_equality_expression_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_equality_expression_test.cc
@@ -18,72 +18,72 @@
 namespace {
 
 TEST_F(ParserImplTest, EqualityExpression_Parses_Equal) {
-  auto p = parser("a == true");
-  auto e = p->equality_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("a == true");
+    auto e = p->equality_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e->Is<ast::BinaryExpression>());
-  auto* rel = e->As<ast::BinaryExpression>();
-  EXPECT_EQ(ast::BinaryOp::kEqual, rel->op);
+    ASSERT_TRUE(e->Is<ast::BinaryExpression>());
+    auto* rel = e->As<ast::BinaryExpression>();
+    EXPECT_EQ(ast::BinaryOp::kEqual, rel->op);
 
-  ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
-  auto* ident = rel->lhs->As<ast::IdentifierExpression>();
-  EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
+    ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
+    auto* ident = rel->lhs->As<ast::IdentifierExpression>();
+    EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
-  ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
+    ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
+    ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
 }
 
 TEST_F(ParserImplTest, EqualityExpression_Parses_NotEqual) {
-  auto p = parser("a != true");
-  auto e = p->equality_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("a != true");
+    auto e = p->equality_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e->Is<ast::BinaryExpression>());
-  auto* rel = e->As<ast::BinaryExpression>();
-  EXPECT_EQ(ast::BinaryOp::kNotEqual, rel->op);
+    ASSERT_TRUE(e->Is<ast::BinaryExpression>());
+    auto* rel = e->As<ast::BinaryExpression>();
+    EXPECT_EQ(ast::BinaryOp::kNotEqual, rel->op);
 
-  ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
-  auto* ident = rel->lhs->As<ast::IdentifierExpression>();
-  EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
+    ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
+    auto* ident = rel->lhs->As<ast::IdentifierExpression>();
+    EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
-  ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
+    ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
+    ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
 }
 
 TEST_F(ParserImplTest, EqualityExpression_InvalidLHS) {
-  auto p = parser("if (a) {} == true");
-  auto e = p->equality_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_EQ(e.value, nullptr);
+    auto p = parser("if (a) {} == true");
+    auto e = p->equality_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_EQ(e.value, nullptr);
 }
 
 TEST_F(ParserImplTest, EqualityExpression_InvalidRHS) {
-  auto p = parser("true == if (a) {}");
-  auto e = p->equality_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:9: unable to parse right side of == expression");
+    auto p = parser("true == if (a) {}");
+    auto e = p->equality_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:9: unable to parse right side of == expression");
 }
 
 TEST_F(ParserImplTest, EqualityExpression_NoOr_ReturnsLHS) {
-  auto p = parser("a true");
-  auto e = p->equality_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::IdentifierExpression>());
+    auto p = parser("a true");
+    auto e = p->equality_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::IdentifierExpression>());
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_error_msg_test.cc b/src/tint/reader/wgsl/parser_impl_error_msg_test.cc
index bbbb511..1234ae4 100644
--- a/src/tint/reader/wgsl/parser_impl_error_msg_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_error_msg_test.cc
@@ -17,322 +17,322 @@
 namespace tint::reader::wgsl {
 namespace {
 
-const diag::Formatter::Style formatter_style{
-    /* print_file: */ true, /* print_severity: */ true,
-    /* print_line: */ true, /* print_newline_at_end: */ false};
+const diag::Formatter::Style formatter_style{/* print_file: */ true, /* print_severity: */ true,
+                                             /* print_line: */ true,
+                                             /* print_newline_at_end: */ false};
 
 class ParserImplErrorTest : public ParserImplTest {};
 
-#define EXPECT(SOURCE, EXPECTED)                                               \
-  do {                                                                         \
-    std::string source = SOURCE;                                               \
-    std::string expected = EXPECTED;                                           \
-    auto p = parser(source);                                                   \
-    p->set_max_errors(5);                                                      \
-    EXPECT_EQ(false, p->Parse());                                              \
-    auto diagnostics = p->builder().Diagnostics();                             \
-    EXPECT_EQ(true, diagnostics.contains_errors());                            \
-    EXPECT_EQ(expected, diag::Formatter(formatter_style).format(diagnostics)); \
-  } while (false)
+#define EXPECT(SOURCE, EXPECTED)                                                   \
+    do {                                                                           \
+        std::string source = SOURCE;                                               \
+        std::string expected = EXPECTED;                                           \
+        auto p = parser(source);                                                   \
+        p->set_max_errors(5);                                                      \
+        EXPECT_EQ(false, p->Parse());                                              \
+        auto diagnostics = p->builder().Diagnostics();                             \
+        EXPECT_EQ(true, diagnostics.contains_errors());                            \
+        EXPECT_EQ(expected, diag::Formatter(formatter_style).format(diagnostics)); \
+    } while (false)
 
 TEST_F(ParserImplErrorTest, AdditiveInvalidExpr) {
-  EXPECT("fn f() { return 1.0 + <; }",
-         R"(test.wgsl:1:23 error: unable to parse right side of + expression
+    EXPECT("fn f() { return 1.0 + <; }",
+           R"(test.wgsl:1:23 error: unable to parse right side of + expression
 fn f() { return 1.0 + <; }
                       ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, AndInvalidExpr) {
-  EXPECT("fn f() { return 1 & >; }",
-         R"(test.wgsl:1:21 error: unable to parse right side of & expression
+    EXPECT("fn f() { return 1 & >; }",
+           R"(test.wgsl:1:21 error: unable to parse right side of & expression
 fn f() { return 1 & >; }
                     ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, AliasDeclInvalidAttribute) {
-  EXPECT("@invariant type e=u32;",
-         R"(test.wgsl:1:2 error: unexpected attributes
+    EXPECT("@invariant type e=u32;",
+           R"(test.wgsl:1:2 error: unexpected attributes
 @invariant type e=u32;
  ^^^^^^^^^
 )");
 }
 
 TEST_F(ParserImplErrorTest, IndexExprInvalidExpr) {
-  EXPECT("fn f() { x = y[^]; }",
-         R"(test.wgsl:1:16 error: unable to parse expression inside []
+    EXPECT("fn f() { x = y[^]; }",
+           R"(test.wgsl:1:16 error: unable to parse expression inside []
 fn f() { x = y[^]; }
                ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, IndexExprMissingRBracket) {
-  EXPECT("fn f() { x = y[1; }",
-         R"(test.wgsl:1:17 error: expected ']' for index accessor
+    EXPECT("fn f() { x = y[1; }",
+           R"(test.wgsl:1:17 error: expected ']' for index accessor
 fn f() { x = y[1; }
                 ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, AssignmentStmtMissingAssignment) {
-  EXPECT("fn f() { a; }", R"(test.wgsl:1:11 error: expected '=' for assignment
+    EXPECT("fn f() { a; }", R"(test.wgsl:1:11 error: expected '=' for assignment
 fn f() { a; }
           ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, AssignmentStmtMissingAssignment2) {
-  EXPECT("fn f() { a : i32; }",
-         R"(test.wgsl:1:10 error: expected 'var' for variable declaration
+    EXPECT("fn f() { a : i32; }",
+           R"(test.wgsl:1:10 error: expected 'var' for variable declaration
 fn f() { a : i32; }
          ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, AssignmentStmtMissingSemicolon) {
-  EXPECT("fn f() { a = 1 }",
-         R"(test.wgsl:1:16 error: expected ';' for assignment statement
+    EXPECT("fn f() { a = 1 }",
+           R"(test.wgsl:1:16 error: expected ';' for assignment statement
 fn f() { a = 1 }
                ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, AssignmentStmtInvalidLHS_BuiltinFunctionName) {
-  EXPECT("normalize = 5;",
-         R"(test.wgsl:1:1 error: statement found outside of function body
+    EXPECT("normalize = 5;",
+           R"(test.wgsl:1:1 error: statement found outside of function body
 normalize = 5;
 ^^^^^^^^^
 )");
 }
 
 TEST_F(ParserImplErrorTest, AssignmentStmtInvalidRHS) {
-  EXPECT("fn f() { a = >; }",
-         R"(test.wgsl:1:14 error: unable to parse right side of assignment
+    EXPECT("fn f() { a = >; }",
+           R"(test.wgsl:1:14 error: unable to parse right side of assignment
 fn f() { a = >; }
              ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, BitcastExprMissingLessThan) {
-  EXPECT("fn f() { x = bitcast(y); }",
-         R"(test.wgsl:1:21 error: expected '<' for bitcast expression
+    EXPECT("fn f() { x = bitcast(y); }",
+           R"(test.wgsl:1:21 error: expected '<' for bitcast expression
 fn f() { x = bitcast(y); }
                     ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, BitcastExprMissingGreaterThan) {
-  EXPECT("fn f() { x = bitcast<u32(y); }",
-         R"(test.wgsl:1:25 error: expected '>' for bitcast expression
+    EXPECT("fn f() { x = bitcast<u32(y); }",
+           R"(test.wgsl:1:25 error: expected '>' for bitcast expression
 fn f() { x = bitcast<u32(y); }
                         ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, BitcastExprMissingType) {
-  EXPECT("fn f() { x = bitcast<>(y); }",
-         R"(test.wgsl:1:22 error: invalid type for bitcast expression
+    EXPECT("fn f() { x = bitcast<>(y); }",
+           R"(test.wgsl:1:22 error: invalid type for bitcast expression
 fn f() { x = bitcast<>(y); }
                      ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, BreakStmtMissingSemicolon) {
-  EXPECT("fn f() { loop { break } }",
-         R"(test.wgsl:1:23 error: expected ';' for break statement
+    EXPECT("fn f() { loop { break } }",
+           R"(test.wgsl:1:23 error: expected ';' for break statement
 fn f() { loop { break } }
                       ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, CallExprMissingRParen) {
-  EXPECT("fn f() { x = f(1.; }",
-         R"(test.wgsl:1:18 error: expected ')' for function call
+    EXPECT("fn f() { x = f(1.; }",
+           R"(test.wgsl:1:18 error: expected ')' for function call
 fn f() { x = f(1.; }
                  ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, CallStmtMissingRParen) {
-  EXPECT("fn f() { f(1.; }",
-         R"(test.wgsl:1:14 error: expected ')' for function call
+    EXPECT("fn f() { f(1.; }",
+           R"(test.wgsl:1:14 error: expected ')' for function call
 fn f() { f(1.; }
              ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, CallStmtInvalidArgument0) {
-  EXPECT("fn f() { f(<); }",
-         R"(test.wgsl:1:12 error: expected ')' for function call
+    EXPECT("fn f() { f(<); }",
+           R"(test.wgsl:1:12 error: expected ')' for function call
 fn f() { f(<); }
            ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, CallStmtInvalidArgument1) {
-  EXPECT("fn f() { f(1.0, <); }",
-         R"(test.wgsl:1:17 error: expected ')' for function call
+    EXPECT("fn f() { f(1.0, <); }",
+           R"(test.wgsl:1:17 error: expected ')' for function call
 fn f() { f(1.0, <); }
                 ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, CallStmtMissingSemicolon) {
-  EXPECT("fn f() { f() }",
-         R"(test.wgsl:1:14 error: expected ';' for function call
+    EXPECT("fn f() { f() }",
+           R"(test.wgsl:1:14 error: expected ';' for function call
 fn f() { f() }
              ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, ConstructorExprMissingLParen) {
-  EXPECT("fn f() { x = vec2<u32>1,2); }",
-         R"(test.wgsl:1:23 error: expected '(' for type constructor
+    EXPECT("fn f() { x = vec2<u32>1,2); }",
+           R"(test.wgsl:1:23 error: expected '(' for type constructor
 fn f() { x = vec2<u32>1,2); }
                       ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, ConstructorExprMissingRParen) {
-  EXPECT("fn f() { x = vec2<u32>(1,2; }",
-         R"(test.wgsl:1:27 error: expected ')' for type constructor
+    EXPECT("fn f() { x = vec2<u32>(1,2; }",
+           R"(test.wgsl:1:27 error: expected ')' for type constructor
 fn f() { x = vec2<u32>(1,2; }
                           ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, ConstVarStmtInvalid) {
-  EXPECT("fn f() { let >; }",
-         R"(test.wgsl:1:14 error: expected identifier for let declaration
+    EXPECT("fn f() { let >; }",
+           R"(test.wgsl:1:14 error: expected identifier for let declaration
 fn f() { let >; }
              ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, ConstVarStmtMissingAssignment) {
-  EXPECT("fn f() { let a : i32; }",
-         R"(test.wgsl:1:21 error: expected '=' for let declaration
+    EXPECT("fn f() { let a : i32; }",
+           R"(test.wgsl:1:21 error: expected '=' for let declaration
 fn f() { let a : i32; }
                     ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, ConstVarStmtMissingConstructor) {
-  EXPECT("fn f() { let a : i32 = >; }",
-         R"(test.wgsl:1:24 error: missing constructor for let declaration
+    EXPECT("fn f() { let a : i32 = >; }",
+           R"(test.wgsl:1:24 error: missing constructor for let declaration
 fn f() { let a : i32 = >; }
                        ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, ContinueStmtMissingSemicolon) {
-  EXPECT("fn f() { loop { continue } }",
-         R"(test.wgsl:1:26 error: expected ';' for continue statement
+    EXPECT("fn f() { loop { continue } }",
+           R"(test.wgsl:1:26 error: expected ';' for continue statement
 fn f() { loop { continue } }
                          ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, DiscardStmtMissingSemicolon) {
-  EXPECT("fn f() { discard }",
-         R"(test.wgsl:1:18 error: expected ';' for discard statement
+    EXPECT("fn f() { discard }",
+           R"(test.wgsl:1:18 error: expected ';' for discard statement
 fn f() { discard }
                  ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, EqualityInvalidExpr) {
-  EXPECT("fn f() { return 1 == >; }",
-         R"(test.wgsl:1:22 error: unable to parse right side of == expression
+    EXPECT("fn f() { return 1 == >; }",
+           R"(test.wgsl:1:22 error: unable to parse right side of == expression
 fn f() { return 1 == >; }
                      ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, ForLoopInitializerMissingSemicolon) {
-  EXPECT("fn f() { for (var i : i32 = 0 i < 8; i=i+1) {} }",
-         R"(test.wgsl:1:31 error: expected ';' for initializer in for loop
+    EXPECT("fn f() { for (var i : i32 = 0 i < 8; i=i+1) {} }",
+           R"(test.wgsl:1:31 error: expected ';' for initializer in for loop
 fn f() { for (var i : i32 = 0 i < 8; i=i+1) {} }
                               ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, ForLoopInitializerMissingVar) {
-  EXPECT("fn f() { for (i : i32 = 0; i < 8; i=i+1) {} }",
-         R"(test.wgsl:1:15 error: expected 'var' for variable declaration
+    EXPECT("fn f() { for (i : i32 = 0; i < 8; i=i+1) {} }",
+           R"(test.wgsl:1:15 error: expected 'var' for variable declaration
 fn f() { for (i : i32 = 0; i < 8; i=i+1) {} }
               ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, ForLoopConditionMissingSemicolon) {
-  EXPECT("fn f() { for (var i : i32 = 0; i < 8 i=i+1) {} }",
-         R"(test.wgsl:1:38 error: expected ';' for condition in for loop
+    EXPECT("fn f() { for (var i : i32 = 0; i < 8 i=i+1) {} }",
+           R"(test.wgsl:1:38 error: expected ';' for condition in for loop
 fn f() { for (var i : i32 = 0; i < 8 i=i+1) {} }
                                      ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, ForLoopMissingLParen) {
-  EXPECT("fn f() { for var i : i32 = 0; i < 8; i=i+1) {} }",
-         R"(test.wgsl:1:14 error: expected '(' for for loop
+    EXPECT("fn f() { for var i : i32 = 0; i < 8; i=i+1) {} }",
+           R"(test.wgsl:1:14 error: expected '(' for for loop
 fn f() { for var i : i32 = 0; i < 8; i=i+1) {} }
              ^^^
 )");
 }
 
 TEST_F(ParserImplErrorTest, ForLoopMissingRParen) {
-  EXPECT("fn f() { for (var i : i32 = 0; i < 8; i=i+1 {} }",
-         R"(test.wgsl:1:45 error: expected ')' for for loop
+    EXPECT("fn f() { for (var i : i32 = 0; i < 8; i=i+1 {} }",
+           R"(test.wgsl:1:45 error: expected ')' for for loop
 fn f() { for (var i : i32 = 0; i < 8; i=i+1 {} }
                                             ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, ForLoopMissingLBrace) {
-  EXPECT("fn f() { for (var i : i32 = 0; i < 8; i=i+1) }",
-         R"(test.wgsl:1:46 error: expected '{' for for loop
+    EXPECT("fn f() { for (var i : i32 = 0; i < 8; i=i+1) }",
+           R"(test.wgsl:1:46 error: expected '{' for for loop
 fn f() { for (var i : i32 = 0; i < 8; i=i+1) }
                                              ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, ForLoopMissingRBrace) {
-  EXPECT("fn f() { for (var i : i32 = 0; i < 8; i=i+1) {",
-         R"(test.wgsl:1:47 error: expected '}' for for loop
+    EXPECT("fn f() { for (var i : i32 = 0; i < 8; i=i+1) {",
+           R"(test.wgsl:1:47 error: expected '}' for for loop
 fn f() { for (var i : i32 = 0; i < 8; i=i+1) {
                                               ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclStageMissingLParen) {
-  EXPECT("@stage vertex) fn f() {}",
-         R"(test.wgsl:1:8 error: expected '(' for stage attribute
+    EXPECT("@stage vertex) fn f() {}",
+           R"(test.wgsl:1:8 error: expected '(' for stage attribute
 @stage vertex) fn f() {}
        ^^^^^^
 )");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclStageMissingRParen) {
-  EXPECT("@stage(vertex fn f() {}",
-         R"(test.wgsl:1:15 error: expected ')' for stage attribute
+    EXPECT("@stage(vertex fn f() {}",
+           R"(test.wgsl:1:15 error: expected ')' for stage attribute
 @stage(vertex fn f() {}
               ^^
 )");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclStageInvalid) {
-  EXPECT("@stage(x) fn f() {}",
-         R"(test.wgsl:1:8 error: invalid value for stage attribute
+    EXPECT("@stage(x) fn f() {}",
+           R"(test.wgsl:1:8 error: invalid value for stage attribute
 @stage(x) fn f() {}
        ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclStageTypeInvalid) {
-  EXPECT("@shader(vertex) fn main() {}",
-         R"(test.wgsl:1:2 error: expected attribute
+    EXPECT("@shader(vertex) fn main() {}",
+           R"(test.wgsl:1:2 error: expected attribute
 @shader(vertex) fn main() {}
  ^^^^^^
 
@@ -343,118 +343,118 @@
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclWorkgroupSizeXInvalid) {
-  EXPECT("@workgroup_size() fn f() {}",
-         R"(test.wgsl:1:17 error: expected workgroup_size x parameter
+    EXPECT("@workgroup_size() fn f() {}",
+           R"(test.wgsl:1:17 error: expected workgroup_size x parameter
 @workgroup_size() fn f() {}
                 ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclWorkgroupSizeYInvalid) {
-  EXPECT("@workgroup_size(1, ) fn f() {}",
-         R"(test.wgsl:1:20 error: expected workgroup_size y parameter
+    EXPECT("@workgroup_size(1, ) fn f() {}",
+           R"(test.wgsl:1:20 error: expected workgroup_size y parameter
 @workgroup_size(1, ) fn f() {}
                    ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclWorkgroupSizeZInvalid) {
-  EXPECT("@workgroup_size(1, 2, ) fn f() {}",
-         R"(test.wgsl:1:23 error: expected workgroup_size z parameter
+    EXPECT("@workgroup_size(1, 2, ) fn f() {}",
+           R"(test.wgsl:1:23 error: expected workgroup_size z parameter
 @workgroup_size(1, 2, ) fn f() {}
                       ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclMissingIdentifier) {
-  EXPECT("fn () {}",
-         R"(test.wgsl:1:4 error: expected identifier for function declaration
+    EXPECT("fn () {}",
+           R"(test.wgsl:1:4 error: expected identifier for function declaration
 fn () {}
    ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclMissingLParen) {
-  EXPECT("fn f) {}",
-         R"(test.wgsl:1:5 error: expected '(' for function declaration
+    EXPECT("fn f) {}",
+           R"(test.wgsl:1:5 error: expected '(' for function declaration
 fn f) {}
     ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclMissingRParen) {
-  EXPECT("fn f( {}",
-         R"(test.wgsl:1:7 error: expected ')' for function declaration
+    EXPECT("fn f( {}",
+           R"(test.wgsl:1:7 error: expected ')' for function declaration
 fn f( {}
       ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclMissingArrow) {
-  EXPECT("fn f() f32 {}", R"(test.wgsl:1:8 error: expected '{'
+    EXPECT("fn f() f32 {}", R"(test.wgsl:1:8 error: expected '{'
 fn f() f32 {}
        ^^^
 )");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclInvalidReturnType) {
-  EXPECT("fn f() -> 1 {}",
-         R"(test.wgsl:1:11 error: unable to determine function return type
+    EXPECT("fn f() -> 1 {}",
+           R"(test.wgsl:1:11 error: unable to determine function return type
 fn f() -> 1 {}
           ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclParamMissingColon) {
-  EXPECT("fn f(x) {}", R"(test.wgsl:1:7 error: expected ':' for parameter
+    EXPECT("fn f(x) {}", R"(test.wgsl:1:7 error: expected ':' for parameter
 fn f(x) {}
       ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclParamInvalidType) {
-  EXPECT("fn f(x : 1) {}", R"(test.wgsl:1:10 error: invalid type for parameter
+    EXPECT("fn f(x : 1) {}", R"(test.wgsl:1:10 error: invalid type for parameter
 fn f(x : 1) {}
          ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclParamMissing) {
-  EXPECT("fn f(x : i32, ,) {}",
-         R"(test.wgsl:1:15 error: expected ')' for function declaration
+    EXPECT("fn f(x : i32, ,) {}",
+           R"(test.wgsl:1:15 error: expected ')' for function declaration
 fn f(x : i32, ,) {}
               ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclMissingLBrace) {
-  EXPECT("fn f() }", R"(test.wgsl:1:8 error: expected '{'
+    EXPECT("fn f() }", R"(test.wgsl:1:8 error: expected '{'
 fn f() }
        ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, FunctionDeclMissingRBrace) {
-  EXPECT("fn f() {", R"(test.wgsl:1:9 error: expected '}'
+    EXPECT("fn f() {", R"(test.wgsl:1:9 error: expected '}'
 fn f() {
         ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, FunctionScopeUnusedDecl) {
-  EXPECT("fn f(a:i32)->i32{return a;@size(1)}",
-         R"(test.wgsl:1:27 error: expected '}'
+    EXPECT("fn f(a:i32)->i32{return a;@size(1)}",
+           R"(test.wgsl:1:27 error: expected '}'
 fn f(a:i32)->i32{return a;@size(1)}
                           ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, FunctionMissingOpenLine) {
-  EXPECT(R"(let bar : vec2<f32> = vec2<f32>(1., 2.);
+    EXPECT(R"(let bar : vec2<f32> = vec2<f32>(1., 2.);
   var a : f32 = bar[0];
   return;
 })",
-         R"(test.wgsl:2:17 error: unable to parse const_expr
+           R"(test.wgsl:2:17 error: unable to parse const_expr
   var a : f32 = bar[0];
                 ^^^
 
@@ -465,332 +465,330 @@
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclConstInvalidIdentifier) {
-  EXPECT("let ^ : i32 = 1;",
-         R"(test.wgsl:1:5 error: expected identifier for let declaration
+    EXPECT("let ^ : i32 = 1;",
+           R"(test.wgsl:1:5 error: expected identifier for let declaration
 let ^ : i32 = 1;
     ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclConstMissingSemicolon) {
-  EXPECT("let i : i32 = 1",
-         R"(test.wgsl:1:16 error: expected ';' for let declaration
+    EXPECT("let i : i32 = 1",
+           R"(test.wgsl:1:16 error: expected ';' for let declaration
 let i : i32 = 1
                ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclConstMissingLParen) {
-  EXPECT("let i : vec2<i32> = vec2<i32>;",
-         R"(test.wgsl:1:30 error: expected '(' for type constructor
+    EXPECT("let i : vec2<i32> = vec2<i32>;",
+           R"(test.wgsl:1:30 error: expected '(' for type constructor
 let i : vec2<i32> = vec2<i32>;
                              ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclConstMissingRParen) {
-  EXPECT("let i : vec2<i32> = vec2<i32>(1., 2.;",
-         R"(test.wgsl:1:37 error: expected ')' for type constructor
+    EXPECT("let i : vec2<i32> = vec2<i32>(1., 2.;",
+           R"(test.wgsl:1:37 error: expected ')' for type constructor
 let i : vec2<i32> = vec2<i32>(1., 2.;
                                     ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclConstBadConstLiteral) {
-  EXPECT("let i : vec2<i32> = vec2<i32>(!);",
-         R"(test.wgsl:1:31 error: unable to parse const_expr
+    EXPECT("let i : vec2<i32> = vec2<i32>(!);",
+           R"(test.wgsl:1:31 error: unable to parse const_expr
 let i : vec2<i32> = vec2<i32>(!);
                               ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclConstBadConstLiteralSpaceLessThan) {
-  EXPECT("let i = 1 < 2;",
-         R"(test.wgsl:1:11 error: expected ';' for let declaration
+    EXPECT("let i = 1 < 2;",
+           R"(test.wgsl:1:11 error: expected ';' for let declaration
 let i = 1 < 2;
           ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclConstNotConstExpr) {
-  EXPECT(
-      "let a = 1;\n"
-      "let b = a;",
-      R"(test.wgsl:2:9 error: unable to parse const_expr
+    EXPECT(
+        "let a = 1;\n"
+        "let b = a;",
+        R"(test.wgsl:2:9 error: unable to parse const_expr
 let b = a;
         ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclConstExprMaxDepth) {
-  uint32_t kMaxDepth = 128;
+    uint32_t kMaxDepth = 128;
 
-  std::stringstream src;
-  std::stringstream mkr;
-  src << "let i : i32 = ";
-  mkr << "              ";
-  for (size_t i = 0; i < kMaxDepth + 8; i++) {
-    src << "f32(";
-    if (i < kMaxDepth) {
-      mkr << "    ";
-    } else if (i == kMaxDepth) {
-      mkr << "^^^";
+    std::stringstream src;
+    std::stringstream mkr;
+    src << "let i : i32 = ";
+    mkr << "              ";
+    for (size_t i = 0; i < kMaxDepth + 8; i++) {
+        src << "f32(";
+        if (i < kMaxDepth) {
+            mkr << "    ";
+        } else if (i == kMaxDepth) {
+            mkr << "^^^";
+        }
     }
-  }
-  src << "1.0";
-  for (size_t i = 0; i < 200; i++) {
-    src << ")";
-  }
-  src << ";";
-  std::stringstream err;
-  err << "test.wgsl:1:527 error: maximum parser recursive depth reached\n"
-      << src.str() << "\n"
-      << mkr.str() << "\n";
-  EXPECT(src.str().c_str(), err.str().c_str());
+    src << "1.0";
+    for (size_t i = 0; i < 200; i++) {
+        src << ")";
+    }
+    src << ";";
+    std::stringstream err;
+    err << "test.wgsl:1:527 error: maximum parser recursive depth reached\n"
+        << src.str() << "\n"
+        << mkr.str() << "\n";
+    EXPECT(src.str().c_str(), err.str().c_str());
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclConstExprMissingLParen) {
-  EXPECT("let i : vec2<i32> = vec2<i32> 1, 2);",
-         R"(test.wgsl:1:31 error: expected '(' for type constructor
+    EXPECT("let i : vec2<i32> = vec2<i32> 1, 2);",
+           R"(test.wgsl:1:31 error: expected '(' for type constructor
 let i : vec2<i32> = vec2<i32> 1, 2);
                               ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclConstExprMissingRParen) {
-  EXPECT("let i : vec2<i32> = vec2<i32>(1, 2;",
-         R"(test.wgsl:1:35 error: expected ')' for type constructor
+    EXPECT("let i : vec2<i32> = vec2<i32>(1, 2;",
+           R"(test.wgsl:1:35 error: expected ')' for type constructor
 let i : vec2<i32> = vec2<i32>(1, 2;
                                   ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclInvalidAttribute) {
-  EXPECT("@stage(vertex) x;",
-         R"(test.wgsl:1:16 error: expected declaration after attributes
+    EXPECT("@stage(vertex) x;",
+           R"(test.wgsl:1:16 error: expected declaration after attributes
 @stage(vertex) x;
                ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclSampledTextureMissingLessThan) {
-  EXPECT("var x : texture_1d;",
-         R"(test.wgsl:1:19 error: expected '<' for sampled texture type
+    EXPECT("var x : texture_1d;",
+           R"(test.wgsl:1:19 error: expected '<' for sampled texture type
 var x : texture_1d;
                   ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclSampledTextureMissingGreaterThan) {
-  EXPECT("var x : texture_1d<f32;",
-         R"(test.wgsl:1:23 error: expected '>' for sampled texture type
+    EXPECT("var x : texture_1d<f32;",
+           R"(test.wgsl:1:23 error: expected '>' for sampled texture type
 var x : texture_1d<f32;
                       ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclSampledTextureInvalidSubtype) {
-  EXPECT("var x : texture_1d<1>;",
-         R"(test.wgsl:1:20 error: invalid type for sampled texture type
+    EXPECT("var x : texture_1d<1>;",
+           R"(test.wgsl:1:20 error: invalid type for sampled texture type
 var x : texture_1d<1>;
                    ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclMultisampledTextureMissingLessThan) {
-  EXPECT("var x : texture_multisampled_2d;",
-         R"(test.wgsl:1:32 error: expected '<' for multisampled texture type
+    EXPECT("var x : texture_multisampled_2d;",
+           R"(test.wgsl:1:32 error: expected '<' for multisampled texture type
 var x : texture_multisampled_2d;
                                ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclMultisampledTextureMissingGreaterThan) {
-  EXPECT("var x : texture_multisampled_2d<f32;",
-         R"(test.wgsl:1:36 error: expected '>' for multisampled texture type
+    EXPECT("var x : texture_multisampled_2d<f32;",
+           R"(test.wgsl:1:36 error: expected '>' for multisampled texture type
 var x : texture_multisampled_2d<f32;
                                    ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclMultisampledTextureInvalidSubtype) {
-  EXPECT("var x : texture_multisampled_2d<1>;",
-         R"(test.wgsl:1:33 error: invalid type for multisampled texture type
+    EXPECT("var x : texture_multisampled_2d<1>;",
+           R"(test.wgsl:1:33 error: invalid type for multisampled texture type
 var x : texture_multisampled_2d<1>;
                                 ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclStorageTextureMissingLessThan) {
-  EXPECT("var x : texture_storage_2d;",
-         R"(test.wgsl:1:27 error: expected '<' for storage texture type
+    EXPECT("var x : texture_storage_2d;",
+           R"(test.wgsl:1:27 error: expected '<' for storage texture type
 var x : texture_storage_2d;
                           ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclStorageTextureMissingGreaterThan) {
-  EXPECT("var x : texture_storage_2d<r32uint, read;",
-         R"(test.wgsl:1:41 error: expected '>' for storage texture type
+    EXPECT("var x : texture_storage_2d<r32uint, read;",
+           R"(test.wgsl:1:41 error: expected '>' for storage texture type
 var x : texture_storage_2d<r32uint, read;
                                         ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclStorageTextureMissingSubtype) {
-  EXPECT("var x : texture_storage_2d<>;",
-         R"(test.wgsl:1:28 error: invalid format for storage texture type
+    EXPECT("var x : texture_storage_2d<>;",
+           R"(test.wgsl:1:28 error: invalid format for storage texture type
 var x : texture_storage_2d<>;
                            ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclStorageTextureMissingInvalidSubtype) {
-  EXPECT("var x : texture_storage_2d<1>;",
-         R"(test.wgsl:1:28 error: invalid format for storage texture type
+    EXPECT("var x : texture_storage_2d<1>;",
+           R"(test.wgsl:1:28 error: invalid format for storage texture type
 var x : texture_storage_2d<1>;
                            ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclStructDeclMissingIdentifier) {
-  EXPECT("struct {};",
-         R"(test.wgsl:1:8 error: expected identifier for struct declaration
+    EXPECT("struct {};",
+           R"(test.wgsl:1:8 error: expected identifier for struct declaration
 struct {};
        ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclStructDeclMissingLBrace) {
-  EXPECT("struct S };",
-         R"(test.wgsl:1:10 error: expected '{' for struct declaration
+    EXPECT("struct S };",
+           R"(test.wgsl:1:10 error: expected '{' for struct declaration
 struct S };
          ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclStructDeclMissingRBrace) {
-  EXPECT("struct S { i : i32,",
-         R"(test.wgsl:1:20 error: expected '}' for struct declaration
+    EXPECT("struct S { i : i32,",
+           R"(test.wgsl:1:20 error: expected '}' for struct declaration
 struct S { i : i32,
                    ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclStructMemberInvalidIdentifier) {
-  EXPECT("struct S { 1 : i32, };",
-         R"(test.wgsl:1:12 error: expected '}' for struct declaration
+    EXPECT("struct S { 1 : i32, };",
+           R"(test.wgsl:1:12 error: expected '}' for struct declaration
 struct S { 1 : i32, };
            ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclStructMemberAlignInvaldValue) {
-  EXPECT(
-      "struct S { @align(x) i : i32, };",
-      R"(test.wgsl:1:19 error: expected signed integer literal for align attribute
+    EXPECT("struct S { @align(x) i : i32, };",
+           R"(test.wgsl:1:19 error: expected signed integer literal for align attribute
 struct S { @align(x) i : i32, };
                   ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclStructMemberAlignNegativeValue) {
-  EXPECT("struct S { @align(-2) i : i32, };",
-         R"(test.wgsl:1:19 error: align attribute must be positive
+    EXPECT("struct S { @align(-2) i : i32, };",
+           R"(test.wgsl:1:19 error: align attribute must be positive
 struct S { @align(-2) i : i32, };
                   ^^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclStructMemberSizeInvaldValue) {
-  EXPECT(
-      "struct S { @size(x) i : i32, };",
-      R"(test.wgsl:1:18 error: expected signed integer literal for size attribute
+    EXPECT("struct S { @size(x) i : i32, };",
+           R"(test.wgsl:1:18 error: expected signed integer literal for size attribute
 struct S { @size(x) i : i32, };
                  ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclStructMemberSizeNegativeValue) {
-  EXPECT("struct S { @size(-2) i : i32, };",
-         R"(test.wgsl:1:18 error: size attribute must be positive
+    EXPECT("struct S { @size(-2) i : i32, };",
+           R"(test.wgsl:1:18 error: size attribute must be positive
 struct S { @size(-2) i : i32, };
                  ^^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclTypeAliasMissingIdentifier) {
-  EXPECT("type 1 = f32;",
-         R"(test.wgsl:1:6 error: expected identifier for type alias
+    EXPECT("type 1 = f32;",
+           R"(test.wgsl:1:6 error: expected identifier for type alias
 type 1 = f32;
      ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclTypeAliasInvalidType) {
-  EXPECT("type meow = 1;", R"(test.wgsl:1:13 error: invalid type alias
+    EXPECT("type meow = 1;", R"(test.wgsl:1:13 error: invalid type alias
 type meow = 1;
             ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclTypeAliasMissingAssignment) {
-  EXPECT("type meow f32", R"(test.wgsl:1:11 error: expected '=' for type alias
+    EXPECT("type meow f32", R"(test.wgsl:1:11 error: expected '=' for type alias
 type meow f32
           ^^^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclTypeAliasMissingSemicolon) {
-  EXPECT("type meow = f32", R"(test.wgsl:1:16 error: expected ';' for type alias
+    EXPECT("type meow = f32", R"(test.wgsl:1:16 error: expected ';' for type alias
 type meow = f32
                ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarArrayMissingLessThan) {
-  EXPECT("var i : array;",
-         R"(test.wgsl:1:14 error: expected '<' for array declaration
+    EXPECT("var i : array;",
+           R"(test.wgsl:1:14 error: expected '<' for array declaration
 var i : array;
              ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarArrayMissingGreaterThan) {
-  EXPECT("var i : array<u32, 3;",
-         R"(test.wgsl:1:21 error: expected '>' for array declaration
+    EXPECT("var i : array<u32, 3;",
+           R"(test.wgsl:1:21 error: expected '>' for array declaration
 var i : array<u32, 3;
                     ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarArrayMissingType) {
-  EXPECT("var i : array<1, 3>;",
-         R"(test.wgsl:1:15 error: invalid type for array declaration
+    EXPECT("var i : array<1, 3>;",
+           R"(test.wgsl:1:15 error: invalid type for array declaration
 var i : array<1, 3>;
               ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarArrayMissingSize) {
-  EXPECT("var i : array<u32, >;",
-         R"(test.wgsl:1:20 error: expected array size expression
+    EXPECT("var i : array<u32, >;",
+           R"(test.wgsl:1:20 error: expected array size expression
 var i : array<u32, >;
                    ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarArrayInvalidSize) {
-  EXPECT("var i : array<u32, !>;",
-         R"(test.wgsl:1:20 error: expected array size expression
+    EXPECT("var i : array<u32, !>;",
+           R"(test.wgsl:1:20 error: expected array size expression
 var i : array<u32, !>;
                    ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarAttrListMissingComma) {
-  EXPECT("@location(1) group(2) var i : i32;",
-         R"(test.wgsl:1:14 error: expected declaration after attributes
+    EXPECT("@location(1) group(2) var i : i32;",
+           R"(test.wgsl:1:14 error: expected declaration after attributes
 @location(1) group(2) var i : i32;
              ^^^^^
 
@@ -801,275 +799,272 @@
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarAttrLocationMissingLParen) {
-  EXPECT("@location 1) var i : i32;",
-         R"(test.wgsl:1:11 error: expected '(' for location attribute
+    EXPECT("@location 1) var i : i32;",
+           R"(test.wgsl:1:11 error: expected '(' for location attribute
 @location 1) var i : i32;
           ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarAttrLocationMissingRParen) {
-  EXPECT("@location (1 var i : i32;",
-         R"(test.wgsl:1:14 error: expected ')' for location attribute
+    EXPECT("@location (1 var i : i32;",
+           R"(test.wgsl:1:14 error: expected ')' for location attribute
 @location (1 var i : i32;
              ^^^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarAttrLocationInvalidValue) {
-  EXPECT(
-      "@location(x) var i : i32;",
-      R"(test.wgsl:1:11 error: expected signed integer literal for location attribute
+    EXPECT("@location(x) var i : i32;",
+           R"(test.wgsl:1:11 error: expected signed integer literal for location attribute
 @location(x) var i : i32;
           ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarAttrBuiltinMissingLParen) {
-  EXPECT("@builtin position) var i : i32;",
-         R"(test.wgsl:1:10 error: expected '(' for builtin attribute
+    EXPECT("@builtin position) var i : i32;",
+           R"(test.wgsl:1:10 error: expected '(' for builtin attribute
 @builtin position) var i : i32;
          ^^^^^^^^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarAttrBuiltinMissingRParen) {
-  EXPECT("@builtin(position var i : i32;",
-         R"(test.wgsl:1:19 error: expected ')' for builtin attribute
+    EXPECT("@builtin(position var i : i32;",
+           R"(test.wgsl:1:19 error: expected ')' for builtin attribute
 @builtin(position var i : i32;
                   ^^^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarAttrBuiltinInvalidIdentifer) {
-  EXPECT("@builtin(1) var i : i32;",
-         R"(test.wgsl:1:10 error: expected identifier for builtin
+    EXPECT("@builtin(1) var i : i32;",
+           R"(test.wgsl:1:10 error: expected identifier for builtin
 @builtin(1) var i : i32;
          ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarAttrBuiltinInvalidValue) {
-  EXPECT("@builtin(x) var i : i32;",
-         R"(test.wgsl:1:10 error: invalid value for builtin attribute
+    EXPECT("@builtin(x) var i : i32;",
+           R"(test.wgsl:1:10 error: invalid value for builtin attribute
 @builtin(x) var i : i32;
          ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarAttrBindingMissingLParen) {
-  EXPECT("@binding 1) var i : i32;",
-         R"(test.wgsl:1:10 error: expected '(' for binding attribute
+    EXPECT("@binding 1) var i : i32;",
+           R"(test.wgsl:1:10 error: expected '(' for binding attribute
 @binding 1) var i : i32;
          ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarAttrBindingMissingRParen) {
-  EXPECT("@binding(1 var i : i32;",
-         R"(test.wgsl:1:12 error: expected ')' for binding attribute
+    EXPECT("@binding(1 var i : i32;",
+           R"(test.wgsl:1:12 error: expected ')' for binding attribute
 @binding(1 var i : i32;
            ^^^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarAttrBindingInvalidValue) {
-  EXPECT(
-      "@binding(x) var i : i32;",
-      R"(test.wgsl:1:10 error: expected signed integer literal for binding attribute
+    EXPECT("@binding(x) var i : i32;",
+           R"(test.wgsl:1:10 error: expected signed integer literal for binding attribute
 @binding(x) var i : i32;
          ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarAttrGroupMissingLParen) {
-  EXPECT("@group 1) var i : i32;",
-         R"(test.wgsl:1:8 error: expected '(' for group attribute
+    EXPECT("@group 1) var i : i32;",
+           R"(test.wgsl:1:8 error: expected '(' for group attribute
 @group 1) var i : i32;
        ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarAttrGroupMissingRParen) {
-  EXPECT("@group(1 var i : i32;",
-         R"(test.wgsl:1:10 error: expected ')' for group attribute
+    EXPECT("@group(1 var i : i32;",
+           R"(test.wgsl:1:10 error: expected ')' for group attribute
 @group(1 var i : i32;
          ^^^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarAttrBindingGroupValue) {
-  EXPECT(
-      "@group(x) var i : i32;",
-      R"(test.wgsl:1:8 error: expected signed integer literal for group attribute
+    EXPECT("@group(x) var i : i32;",
+           R"(test.wgsl:1:8 error: expected signed integer literal for group attribute
 @group(x) var i : i32;
        ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarInvalidIdentifier) {
-  EXPECT("var ^ : mat4x4;",
-         R"(test.wgsl:1:5 error: expected identifier for variable declaration
+    EXPECT("var ^ : mat4x4;",
+           R"(test.wgsl:1:5 error: expected identifier for variable declaration
 var ^ : mat4x4;
     ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarMatrixMissingGreaterThan) {
-  EXPECT("var i : mat4x4<u32;", R"(test.wgsl:1:19 error: expected '>' for matrix
+    EXPECT("var i : mat4x4<u32;", R"(test.wgsl:1:19 error: expected '>' for matrix
 var i : mat4x4<u32;
                   ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarMatrixMissingType) {
-  EXPECT("var i : mat4x4<1>;", R"(test.wgsl:1:16 error: invalid type for matrix
+    EXPECT("var i : mat4x4<1>;", R"(test.wgsl:1:16 error: invalid type for matrix
 var i : mat4x4<1>;
                ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarMissingSemicolon) {
-  EXPECT("var i : i32",
-         R"(test.wgsl:1:12 error: expected ';' for variable declaration
+    EXPECT("var i : i32",
+           R"(test.wgsl:1:12 error: expected ';' for variable declaration
 var i : i32
            ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarPtrMissingLessThan) {
-  EXPECT("var i : ptr;",
-         R"(test.wgsl:1:12 error: expected '<' for ptr declaration
+    EXPECT("var i : ptr;",
+           R"(test.wgsl:1:12 error: expected '<' for ptr declaration
 var i : ptr;
            ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarPtrMissingGreaterThan) {
-  EXPECT("var i : ptr<private, u32;",
-         R"(test.wgsl:1:25 error: expected '>' for ptr declaration
+    EXPECT("var i : ptr<private, u32;",
+           R"(test.wgsl:1:25 error: expected '>' for ptr declaration
 var i : ptr<private, u32;
                         ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarPtrMissingComma) {
-  EXPECT("var i : ptr<private u32>;",
-         R"(test.wgsl:1:21 error: expected ',' for ptr declaration
+    EXPECT("var i : ptr<private u32>;",
+           R"(test.wgsl:1:21 error: expected ',' for ptr declaration
 var i : ptr<private u32>;
                     ^^^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarPtrMissingStorageClass) {
-  EXPECT("var i : ptr<meow, u32>;",
-         R"(test.wgsl:1:13 error: invalid storage class for ptr declaration
+    EXPECT("var i : ptr<meow, u32>;",
+           R"(test.wgsl:1:13 error: invalid storage class for ptr declaration
 var i : ptr<meow, u32>;
             ^^^^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarPtrMissingType) {
-  EXPECT("var i : ptr<private, 1>;",
-         R"(test.wgsl:1:22 error: invalid type for ptr declaration
+    EXPECT("var i : ptr<private, 1>;",
+           R"(test.wgsl:1:22 error: invalid type for ptr declaration
 var i : ptr<private, 1>;
                      ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarAtomicMissingLessThan) {
-  EXPECT("var i : atomic;",
-         R"(test.wgsl:1:15 error: expected '<' for atomic declaration
+    EXPECT("var i : atomic;",
+           R"(test.wgsl:1:15 error: expected '<' for atomic declaration
 var i : atomic;
               ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarAtomicMissingGreaterThan) {
-  EXPECT("var i : atomic<u32 x;",
-         R"(test.wgsl:1:20 error: expected '>' for atomic declaration
+    EXPECT("var i : atomic<u32 x;",
+           R"(test.wgsl:1:20 error: expected '>' for atomic declaration
 var i : atomic<u32 x;
                    ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarStorageDeclInvalidClass) {
-  EXPECT("var<fish> i : i32",
-         R"(test.wgsl:1:5 error: invalid storage class for variable declaration
+    EXPECT("var<fish> i : i32",
+           R"(test.wgsl:1:5 error: invalid storage class for variable declaration
 var<fish> i : i32
     ^^^^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarStorageDeclMissingGThan) {
-  EXPECT("var<private i : i32",
-         R"(test.wgsl:1:13 error: expected '>' for variable declaration
+    EXPECT("var<private i : i32",
+           R"(test.wgsl:1:13 error: expected '>' for variable declaration
 var<private i : i32
             ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarVectorMissingGreaterThan) {
-  EXPECT("var i : vec3<u32;", R"(test.wgsl:1:17 error: expected '>' for vector
+    EXPECT("var i : vec3<u32;", R"(test.wgsl:1:17 error: expected '>' for vector
 var i : vec3<u32;
                 ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, GlobalDeclVarVectorMissingType) {
-  EXPECT("var i : vec3<1>;", R"(test.wgsl:1:14 error: invalid type for vector
+    EXPECT("var i : vec3<1>;", R"(test.wgsl:1:14 error: invalid type for vector
 var i : vec3<1>;
              ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, IfStmtMissingRParen) {
-  EXPECT("fn f() { if (true {} }", R"(test.wgsl:1:19 error: expected ')'
+    EXPECT("fn f() { if (true {} }", R"(test.wgsl:1:19 error: expected ')'
 fn f() { if (true {} }
                   ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, IfStmtInvalidCond) {
-  EXPECT("fn f() { if (>) {} }",
-         R"(test.wgsl:1:14 error: unable to parse expression
+    EXPECT("fn f() { if (>) {} }",
+           R"(test.wgsl:1:14 error: unable to parse expression
 fn f() { if (>) {} }
              ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, LogicalAndInvalidExpr) {
-  EXPECT("fn f() { return 1 && >; }",
-         R"(test.wgsl:1:22 error: unable to parse right side of && expression
+    EXPECT("fn f() { return 1 && >; }",
+           R"(test.wgsl:1:22 error: unable to parse right side of && expression
 fn f() { return 1 && >; }
                      ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, LogicalOrInvalidExpr) {
-  EXPECT("fn f() { return 1 || >; }",
-         R"(test.wgsl:1:22 error: unable to parse right side of || expression
+    EXPECT("fn f() { return 1 || >; }",
+           R"(test.wgsl:1:22 error: unable to parse right side of || expression
 fn f() { return 1 || >; }
                      ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, LoopMissingLBrace) {
-  EXPECT("fn f() { loop }", R"(test.wgsl:1:15 error: expected '{' for loop
+    EXPECT("fn f() { loop }", R"(test.wgsl:1:15 error: expected '{' for loop
 fn f() { loop }
               ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, LoopMissingRBrace) {
-  EXPECT("fn f() { loop {", R"(test.wgsl:1:16 error: expected '}' for loop
+    EXPECT("fn f() { loop {", R"(test.wgsl:1:16 error: expected '}' for loop
 fn f() { loop {
                ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, MaxErrorsReached) {
-  EXPECT("x; x; x; x; x; x; x; x;", R"(test.wgsl:1:1 error: unexpected token
+    EXPECT("x; x; x; x; x; x; x; x;", R"(test.wgsl:1:1 error: unexpected token
 x; x; x; x; x; x; x; x;
 ^
 
@@ -1093,160 +1088,160 @@
 }
 
 TEST_F(ParserImplErrorTest, MemberExprMissingIdentifier) {
-  EXPECT("fn f() { x = a.; }",
-         R"(test.wgsl:1:16 error: expected identifier for member accessor
+    EXPECT("fn f() { x = a.; }",
+           R"(test.wgsl:1:16 error: expected identifier for member accessor
 fn f() { x = a.; }
                ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, MultiplicativeInvalidExpr) {
-  EXPECT("fn f() { return 1.0 * <; }",
-         R"(test.wgsl:1:23 error: unable to parse right side of * expression
+    EXPECT("fn f() { return 1.0 * <; }",
+           R"(test.wgsl:1:23 error: unable to parse right side of * expression
 fn f() { return 1.0 * <; }
                       ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, OrInvalidExpr) {
-  EXPECT("fn f() { return 1 | >; }",
-         R"(test.wgsl:1:21 error: unable to parse right side of | expression
+    EXPECT("fn f() { return 1 | >; }",
+           R"(test.wgsl:1:21 error: unable to parse right side of | expression
 fn f() { return 1 | >; }
                     ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, PostfixIncrementAsExpr) {
-  EXPECT("fn f() { var x : i32; let y = x++; }",
-         R"(test.wgsl:1:32 error: expected ';' for variable declaration
+    EXPECT("fn f() { var x : i32; let y = x++; }",
+           R"(test.wgsl:1:32 error: expected ';' for variable declaration
 fn f() { var x : i32; let y = x++; }
                                ^^
 )");
 }
 
 TEST_F(ParserImplErrorTest, RelationalInvalidExpr) {
-  EXPECT("fn f() { return 1 < >; }",
-         R"(test.wgsl:1:21 error: unable to parse right side of < expression
+    EXPECT("fn f() { return 1 < >; }",
+           R"(test.wgsl:1:21 error: unable to parse right side of < expression
 fn f() { return 1 < >; }
                     ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, ReturnStmtMissingSemicolon) {
-  EXPECT("fn f() { return }",
-         R"(test.wgsl:1:17 error: expected ';' for return statement
+    EXPECT("fn f() { return }",
+           R"(test.wgsl:1:17 error: expected ';' for return statement
 fn f() { return }
                 ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, ShiftInvalidExpr) {
-  EXPECT("fn f() { return 1 << >; }",
-         R"(test.wgsl:1:22 error: unable to parse right side of << expression
+    EXPECT("fn f() { return 1 << >; }",
+           R"(test.wgsl:1:22 error: unable to parse right side of << expression
 fn f() { return 1 << >; }
                      ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, SwitchStmtMissingLBrace) {
-  EXPECT("fn f() { switch(1) }",
-         R"(test.wgsl:1:20 error: expected '{' for switch statement
+    EXPECT("fn f() { switch(1) }",
+           R"(test.wgsl:1:20 error: expected '{' for switch statement
 fn f() { switch(1) }
                    ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, SwitchStmtMissingRBrace) {
-  EXPECT("fn f() { switch(1) {",
-         R"(test.wgsl:1:21 error: expected '}' for switch statement
+    EXPECT("fn f() { switch(1) {",
+           R"(test.wgsl:1:21 error: expected '}' for switch statement
 fn f() { switch(1) {
                     ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, SwitchStmtInvalidCase) {
-  EXPECT("fn f() { switch(1) { case ^: } }",
-         R"(test.wgsl:1:27 error: unable to parse case selectors
+    EXPECT("fn f() { switch(1) { case ^: } }",
+           R"(test.wgsl:1:27 error: unable to parse case selectors
 fn f() { switch(1) { case ^: } }
                           ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, SwitchStmtInvalidCase2) {
-  EXPECT("fn f() { switch(1) { case false: } }",
-         R"(test.wgsl:1:27 error: invalid case selector must be an integer value
+    EXPECT("fn f() { switch(1) { case false: } }",
+           R"(test.wgsl:1:27 error: invalid case selector must be an integer value
 fn f() { switch(1) { case false: } }
                           ^^^^^
 )");
 }
 
 TEST_F(ParserImplErrorTest, SwitchStmtCaseMissingLBrace) {
-  EXPECT("fn f() { switch(1) { case 1: } }",
-         R"(test.wgsl:1:30 error: expected '{' for case statement
+    EXPECT("fn f() { switch(1) { case 1: } }",
+           R"(test.wgsl:1:30 error: expected '{' for case statement
 fn f() { switch(1) { case 1: } }
                              ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, SwitchStmtCaseMissingRBrace) {
-  EXPECT("fn f() { switch(1) { case 1: {",
-         R"(test.wgsl:1:31 error: expected '}' for case statement
+    EXPECT("fn f() { switch(1) { case 1: {",
+           R"(test.wgsl:1:31 error: expected '}' for case statement
 fn f() { switch(1) { case 1: {
                               ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, SwitchStmtCaseFallthroughMissingSemicolon) {
-  EXPECT("fn f() { switch(1) { case 1: { fallthrough } case 2: {} } }",
-         R"(test.wgsl:1:44 error: expected ';' for fallthrough statement
+    EXPECT("fn f() { switch(1) { case 1: { fallthrough } case 2: {} } }",
+           R"(test.wgsl:1:44 error: expected ';' for fallthrough statement
 fn f() { switch(1) { case 1: { fallthrough } case 2: {} } }
                                            ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, VarStmtMissingSemicolon) {
-  EXPECT("fn f() { var a : u32 }",
-         R"(test.wgsl:1:22 error: expected ';' for variable declaration
+    EXPECT("fn f() { var a : u32 }",
+           R"(test.wgsl:1:22 error: expected ';' for variable declaration
 fn f() { var a : u32 }
                      ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, VarStmtInvalidAssignment) {
-  EXPECT("fn f() { var a : u32 = >; }",
-         R"(test.wgsl:1:24 error: missing constructor for variable declaration
+    EXPECT("fn f() { var a : u32 = >; }",
+           R"(test.wgsl:1:24 error: missing constructor for variable declaration
 fn f() { var a : u32 = >; }
                        ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, UnaryInvalidExpr) {
-  EXPECT("fn f() { return !<; }",
-         R"(test.wgsl:1:18 error: unable to parse right side of ! expression
+    EXPECT("fn f() { return !<; }",
+           R"(test.wgsl:1:18 error: unable to parse right side of ! expression
 fn f() { return !<; }
                  ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, UnexpectedToken) {
-  EXPECT("unexpected", R"(test.wgsl:1:1 error: unexpected token
+    EXPECT("unexpected", R"(test.wgsl:1:1 error: unexpected token
 unexpected
 ^^^^^^^^^^
 )");
 }
 
 TEST_F(ParserImplErrorTest, XorInvalidExpr) {
-  EXPECT("fn f() { return 1 ^ >; }",
-         R"(test.wgsl:1:21 error: unable to parse right side of ^ expression
+    EXPECT("fn f() { return 1 ^ >; }",
+           R"(test.wgsl:1:21 error: unable to parse right side of ^ expression
 fn f() { return 1 ^ >; }
                     ^
 )");
 }
 
 TEST_F(ParserImplErrorTest, InvalidUTF8) {
-  EXPECT("fn fu\xd0nc() {}",
-         "test.wgsl:1:4 error: invalid UTF-8\n"
-         "fn fu\xD0nc() {}\n");
+    EXPECT("fn fu\xd0nc() {}",
+           "test.wgsl:1:4 error: invalid UTF-8\n"
+           "fn fu\xD0nc() {}\n");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_error_resync_test.cc b/src/tint/reader/wgsl/parser_impl_error_resync_test.cc
index 69646a4..9e37b51 100644
--- a/src/tint/reader/wgsl/parser_impl_error_resync_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_error_resync_test.cc
@@ -17,31 +17,31 @@
 namespace tint::reader::wgsl {
 namespace {
 
-const diag::Formatter::Style formatter_style{
-    /* print_file: */ true, /* print_severity: */ true,
-    /* print_line: */ true, /* print_newline_at_end: */ false};
+const diag::Formatter::Style formatter_style{/* print_file: */ true, /* print_severity: */ true,
+                                             /* print_line: */ true,
+                                             /* print_newline_at_end: */ false};
 
 class ParserImplErrorResyncTest : public ParserImplTest {};
 
-#define EXPECT(SOURCE, EXPECTED)                                               \
-  do {                                                                         \
-    std::string source = SOURCE;                                               \
-    std::string expected = EXPECTED;                                           \
-    auto p = parser(source);                                                   \
-    EXPECT_EQ(false, p->Parse());                                              \
-    auto diagnostics = p->builder().Diagnostics();                             \
-    EXPECT_EQ(true, diagnostics.contains_errors());                            \
-    EXPECT_EQ(expected, diag::Formatter(formatter_style).format(diagnostics)); \
-  } while (false)
+#define EXPECT(SOURCE, EXPECTED)                                                   \
+    do {                                                                           \
+        std::string source = SOURCE;                                               \
+        std::string expected = EXPECTED;                                           \
+        auto p = parser(source);                                                   \
+        EXPECT_EQ(false, p->Parse());                                              \
+        auto diagnostics = p->builder().Diagnostics();                             \
+        EXPECT_EQ(true, diagnostics.contains_errors());                            \
+        EXPECT_EQ(expected, diag::Formatter(formatter_style).format(diagnostics)); \
+    } while (false)
 
 TEST_F(ParserImplErrorResyncTest, BadFunctionDecls) {
-  EXPECT(R"(
+    EXPECT(R"(
 fn .() -> . {}
 fn x(.) {}
 @_ fn -> {}
 fn good() {}
 )",
-         R"(test.wgsl:2:4 error: expected identifier for function declaration
+           R"(test.wgsl:2:4 error: expected identifier for function declaration
 fn .() -> . {}
    ^
 
@@ -64,7 +64,7 @@
 }
 
 TEST_F(ParserImplErrorResyncTest, AssignmentStatement) {
-  EXPECT(R"(
+    EXPECT(R"(
 fn f() {
   blah blah blah blah;
   good = 1;
@@ -73,7 +73,7 @@
   good = 1;
 }
 )",
-         R"(test.wgsl:3:8 error: expected '=' for assignment
+           R"(test.wgsl:3:8 error: expected '=' for assignment
   blah blah blah blah;
        ^^^^
 
@@ -88,14 +88,14 @@
 }
 
 TEST_F(ParserImplErrorResyncTest, DiscardStatement) {
-  EXPECT(R"(
+    EXPECT(R"(
 fn f() {
   discard blah blah blah;
   a = 1;
   discard blah blah blah;
 }
 )",
-         R"(test.wgsl:3:11 error: expected ';' for discard statement
+           R"(test.wgsl:3:11 error: expected ';' for discard statement
   discard blah blah blah;
           ^^^^
 
@@ -106,7 +106,7 @@
 }
 
 TEST_F(ParserImplErrorResyncTest, StructMembers) {
-  EXPECT(R"(
+    EXPECT(R"(
 struct S {
     blah blah blah,
     a : i32,
@@ -116,7 +116,7 @@
     c : i32,
 }
 )",
-         R"(test.wgsl:3:10 error: expected ':' for struct member
+           R"(test.wgsl:3:10 error: expected ':' for struct member
     blah blah blah,
          ^^^^
 
@@ -135,14 +135,14 @@
 // the outer resynchronize() is looking for a terminating '}' for the function
 // scope.
 TEST_F(ParserImplErrorResyncTest, NestedSyncPoints) {
-  EXPECT(R"(
+    EXPECT(R"(
 fn f() {
   x = 1;
   discard
 }
 struct S { blah };
 )",
-         R"(test.wgsl:5:1 error: expected ';' for discard statement
+           R"(test.wgsl:5:1 error: expected ';' for discard statement
 }
 ^
 
@@ -153,14 +153,14 @@
 }
 
 TEST_F(ParserImplErrorResyncTest, BracketCounting) {
-  EXPECT(
-      R"(
+    EXPECT(
+        R"(
 fn f(x(((())))) {
   meow = {{{}}}
 }
 struct S { blah };
 )",
-      R"(test.wgsl:2:7 error: expected ':' for parameter
+        R"(test.wgsl:2:7 error: expected ':' for parameter
 fn f(x(((())))) {
       ^
 
diff --git a/src/tint/reader/wgsl/parser_impl_exclusive_or_expression_test.cc b/src/tint/reader/wgsl/parser_impl_exclusive_or_expression_test.cc
index f9fb52a..c6f8ad4 100644
--- a/src/tint/reader/wgsl/parser_impl_exclusive_or_expression_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_exclusive_or_expression_test.cc
@@ -18,52 +18,52 @@
 namespace {
 
 TEST_F(ParserImplTest, ExclusiveOrExpression_Parses) {
-  auto p = parser("a ^ true");
-  auto e = p->exclusive_or_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("a ^ true");
+    auto e = p->exclusive_or_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e->Is<ast::BinaryExpression>());
-  auto* rel = e->As<ast::BinaryExpression>();
-  EXPECT_EQ(ast::BinaryOp::kXor, rel->op);
+    ASSERT_TRUE(e->Is<ast::BinaryExpression>());
+    auto* rel = e->As<ast::BinaryExpression>();
+    EXPECT_EQ(ast::BinaryOp::kXor, rel->op);
 
-  ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
-  auto* ident = rel->lhs->As<ast::IdentifierExpression>();
-  EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
+    ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
+    auto* ident = rel->lhs->As<ast::IdentifierExpression>();
+    EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
-  ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
+    ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
+    ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
 }
 
 TEST_F(ParserImplTest, ExclusiveOrExpression_InvalidLHS) {
-  auto p = parser("if (a) {} ^ true");
-  auto e = p->exclusive_or_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_EQ(e.value, nullptr);
+    auto p = parser("if (a) {} ^ true");
+    auto e = p->exclusive_or_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_EQ(e.value, nullptr);
 }
 
 TEST_F(ParserImplTest, ExclusiveOrExpression_InvalidRHS) {
-  auto p = parser("true ^ if (a) {}");
-  auto e = p->exclusive_or_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:8: unable to parse right side of ^ expression");
+    auto p = parser("true ^ if (a) {}");
+    auto e = p->exclusive_or_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    ASSERT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:8: unable to parse right side of ^ expression");
 }
 
 TEST_F(ParserImplTest, ExclusiveOrExpression_NoOr_ReturnsLHS) {
-  auto p = parser("a true");
-  auto e = p->exclusive_or_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::IdentifierExpression>());
+    auto p = parser("a true");
+    auto e = p->exclusive_or_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::IdentifierExpression>());
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_external_texture_type_test.cc b/src/tint/reader/wgsl/parser_impl_external_texture_test.cc
similarity index 69%
rename from src/tint/reader/wgsl/parser_impl_external_texture_type_test.cc
rename to src/tint/reader/wgsl/parser_impl_external_texture_test.cc
index b567634..4bd5cb1 100644
--- a/src/tint/reader/wgsl/parser_impl_external_texture_type_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_external_texture_test.cc
@@ -18,19 +18,19 @@
 namespace {
 
 TEST_F(ParserImplTest, ExternalTextureType_Invalid) {
-  auto p = parser("1234");
-  auto t = p->external_texture_type();
-  EXPECT_FALSE(t.matched);
-  EXPECT_FALSE(t.errored);
-  EXPECT_FALSE(p->has_error());
+    auto p = parser("1234");
+    auto t = p->external_texture();
+    EXPECT_FALSE(t.matched);
+    EXPECT_FALSE(t.errored);
+    EXPECT_FALSE(p->has_error());
 }
 
 TEST_F(ParserImplTest, ExternalTextureType) {
-  auto p = parser("texture_external");
-  auto t = p->external_texture_type();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 17u}}));
+    auto p = parser("texture_external");
+    auto t = p->external_texture();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 17u}}));
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_for_stmt_test.cc b/src/tint/reader/wgsl/parser_impl_for_stmt_test.cc
index b62ad71..26f3298 100644
--- a/src/tint/reader/wgsl/parser_impl_for_stmt_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_for_stmt_test.cc
@@ -23,298 +23,298 @@
 
 // Test an empty for loop.
 TEST_F(ForStmtTest, Empty) {
-  auto p = parser("for (;;) { }");
-  auto fl = p->for_stmt();
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_FALSE(fl.errored);
-  ASSERT_TRUE(fl.matched);
-  EXPECT_EQ(fl->initializer, nullptr);
-  EXPECT_EQ(fl->condition, nullptr);
-  EXPECT_EQ(fl->continuing, nullptr);
-  EXPECT_TRUE(fl->body->Empty());
+    auto p = parser("for (;;) { }");
+    auto fl = p->for_stmt();
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_FALSE(fl.errored);
+    ASSERT_TRUE(fl.matched);
+    EXPECT_EQ(fl->initializer, nullptr);
+    EXPECT_EQ(fl->condition, nullptr);
+    EXPECT_EQ(fl->continuing, nullptr);
+    EXPECT_TRUE(fl->body->Empty());
 }
 
 // Test a for loop with non-empty body.
 TEST_F(ForStmtTest, Body) {
-  auto p = parser("for (;;) { discard; }");
-  auto fl = p->for_stmt();
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_FALSE(fl.errored);
-  ASSERT_TRUE(fl.matched);
-  EXPECT_EQ(fl->initializer, nullptr);
-  EXPECT_EQ(fl->condition, nullptr);
-  EXPECT_EQ(fl->continuing, nullptr);
-  ASSERT_EQ(fl->body->statements.size(), 1u);
-  EXPECT_TRUE(fl->body->statements[0]->Is<ast::DiscardStatement>());
+    auto p = parser("for (;;) { discard; }");
+    auto fl = p->for_stmt();
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_FALSE(fl.errored);
+    ASSERT_TRUE(fl.matched);
+    EXPECT_EQ(fl->initializer, nullptr);
+    EXPECT_EQ(fl->condition, nullptr);
+    EXPECT_EQ(fl->continuing, nullptr);
+    ASSERT_EQ(fl->body->statements.size(), 1u);
+    EXPECT_TRUE(fl->body->statements[0]->Is<ast::DiscardStatement>());
 }
 
 // Test a for loop declaring a variable in the initializer statement.
 TEST_F(ForStmtTest, InitializerStatementDecl) {
-  auto p = parser("for (var i: i32 ;;) { }");
-  auto fl = p->for_stmt();
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_FALSE(fl.errored);
-  ASSERT_TRUE(fl.matched);
-  ASSERT_TRUE(Is<ast::VariableDeclStatement>(fl->initializer));
-  auto* var = fl->initializer->As<ast::VariableDeclStatement>()->variable;
-  EXPECT_FALSE(var->is_const);
-  EXPECT_EQ(var->constructor, nullptr);
-  EXPECT_EQ(fl->condition, nullptr);
-  EXPECT_EQ(fl->continuing, nullptr);
-  EXPECT_TRUE(fl->body->Empty());
+    auto p = parser("for (var i: i32 ;;) { }");
+    auto fl = p->for_stmt();
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_FALSE(fl.errored);
+    ASSERT_TRUE(fl.matched);
+    ASSERT_TRUE(Is<ast::VariableDeclStatement>(fl->initializer));
+    auto* var = fl->initializer->As<ast::VariableDeclStatement>()->variable;
+    EXPECT_FALSE(var->is_const);
+    EXPECT_EQ(var->constructor, nullptr);
+    EXPECT_EQ(fl->condition, nullptr);
+    EXPECT_EQ(fl->continuing, nullptr);
+    EXPECT_TRUE(fl->body->Empty());
 }
 
 // Test a for loop declaring and initializing a variable in the initializer
 // statement.
 TEST_F(ForStmtTest, InitializerStatementDeclEqual) {
-  auto p = parser("for (var i: i32 = 0 ;;) { }");
-  auto fl = p->for_stmt();
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_FALSE(fl.errored);
-  ASSERT_TRUE(fl.matched);
-  ASSERT_TRUE(Is<ast::VariableDeclStatement>(fl->initializer));
-  auto* var = fl->initializer->As<ast::VariableDeclStatement>()->variable;
-  EXPECT_FALSE(var->is_const);
-  EXPECT_NE(var->constructor, nullptr);
-  EXPECT_EQ(fl->condition, nullptr);
-  EXPECT_EQ(fl->continuing, nullptr);
-  EXPECT_TRUE(fl->body->Empty());
+    auto p = parser("for (var i: i32 = 0 ;;) { }");
+    auto fl = p->for_stmt();
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_FALSE(fl.errored);
+    ASSERT_TRUE(fl.matched);
+    ASSERT_TRUE(Is<ast::VariableDeclStatement>(fl->initializer));
+    auto* var = fl->initializer->As<ast::VariableDeclStatement>()->variable;
+    EXPECT_FALSE(var->is_const);
+    EXPECT_NE(var->constructor, nullptr);
+    EXPECT_EQ(fl->condition, nullptr);
+    EXPECT_EQ(fl->continuing, nullptr);
+    EXPECT_TRUE(fl->body->Empty());
 }
 
 // Test a for loop declaring a const variable in the initializer statement.
 TEST_F(ForStmtTest, InitializerStatementConstDecl) {
-  auto p = parser("for (let i: i32 = 0 ;;) { }");
-  auto fl = p->for_stmt();
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_FALSE(fl.errored);
-  ASSERT_TRUE(fl.matched);
-  ASSERT_TRUE(Is<ast::VariableDeclStatement>(fl->initializer));
-  auto* var = fl->initializer->As<ast::VariableDeclStatement>()->variable;
-  EXPECT_TRUE(var->is_const);
-  EXPECT_NE(var->constructor, nullptr);
-  EXPECT_EQ(fl->condition, nullptr);
-  EXPECT_EQ(fl->continuing, nullptr);
-  EXPECT_TRUE(fl->body->Empty());
+    auto p = parser("for (let i: i32 = 0 ;;) { }");
+    auto fl = p->for_stmt();
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_FALSE(fl.errored);
+    ASSERT_TRUE(fl.matched);
+    ASSERT_TRUE(Is<ast::VariableDeclStatement>(fl->initializer));
+    auto* var = fl->initializer->As<ast::VariableDeclStatement>()->variable;
+    EXPECT_TRUE(var->is_const);
+    EXPECT_NE(var->constructor, nullptr);
+    EXPECT_EQ(fl->condition, nullptr);
+    EXPECT_EQ(fl->continuing, nullptr);
+    EXPECT_TRUE(fl->body->Empty());
 }
 
 // Test a for loop assigning a variable in the initializer statement.
 TEST_F(ForStmtTest, InitializerStatementAssignment) {
-  auto p = parser("for (i = 0 ;;) { }");
-  auto fl = p->for_stmt();
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_FALSE(fl.errored);
-  ASSERT_TRUE(fl.matched);
-  EXPECT_TRUE(Is<ast::AssignmentStatement>(fl->initializer));
-  EXPECT_EQ(fl->condition, nullptr);
-  EXPECT_EQ(fl->continuing, nullptr);
-  EXPECT_TRUE(fl->body->Empty());
+    auto p = parser("for (i = 0 ;;) { }");
+    auto fl = p->for_stmt();
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_FALSE(fl.errored);
+    ASSERT_TRUE(fl.matched);
+    EXPECT_TRUE(Is<ast::AssignmentStatement>(fl->initializer));
+    EXPECT_EQ(fl->condition, nullptr);
+    EXPECT_EQ(fl->continuing, nullptr);
+    EXPECT_TRUE(fl->body->Empty());
 }
 
 // Test a for loop incrementing a variable in the initializer statement.
 TEST_F(ForStmtTest, InitializerStatementIncrement) {
-  auto p = parser("for (i++;;) { }");
-  auto fl = p->for_stmt();
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_FALSE(fl.errored);
-  ASSERT_TRUE(fl.matched);
-  EXPECT_TRUE(Is<ast::IncrementDecrementStatement>(fl->initializer));
-  EXPECT_EQ(fl->condition, nullptr);
-  EXPECT_EQ(fl->continuing, nullptr);
-  EXPECT_TRUE(fl->body->Empty());
+    auto p = parser("for (i++;;) { }");
+    auto fl = p->for_stmt();
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_FALSE(fl.errored);
+    ASSERT_TRUE(fl.matched);
+    EXPECT_TRUE(Is<ast::IncrementDecrementStatement>(fl->initializer));
+    EXPECT_EQ(fl->condition, nullptr);
+    EXPECT_EQ(fl->continuing, nullptr);
+    EXPECT_TRUE(fl->body->Empty());
 }
 
 // Test a for loop calling a function in the initializer statement.
 TEST_F(ForStmtTest, InitializerStatementFuncCall) {
-  auto p = parser("for (a(b,c) ;;) { }");
-  auto fl = p->for_stmt();
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_FALSE(fl.errored);
-  ASSERT_TRUE(fl.matched);
-  EXPECT_TRUE(Is<ast::CallStatement>(fl->initializer));
-  EXPECT_EQ(fl->condition, nullptr);
-  EXPECT_EQ(fl->continuing, nullptr);
-  EXPECT_TRUE(fl->body->Empty());
+    auto p = parser("for (a(b,c) ;;) { }");
+    auto fl = p->for_stmt();
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_FALSE(fl.errored);
+    ASSERT_TRUE(fl.matched);
+    EXPECT_TRUE(Is<ast::CallStatement>(fl->initializer));
+    EXPECT_EQ(fl->condition, nullptr);
+    EXPECT_EQ(fl->continuing, nullptr);
+    EXPECT_TRUE(fl->body->Empty());
 }
 
 // Test a for loop with a break condition
 TEST_F(ForStmtTest, BreakCondition) {
-  auto p = parser("for (; 0 == 1;) { }");
-  auto fl = p->for_stmt();
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_FALSE(fl.errored);
-  ASSERT_TRUE(fl.matched);
-  EXPECT_EQ(fl->initializer, nullptr);
-  EXPECT_TRUE(Is<ast::BinaryExpression>(fl->condition));
-  EXPECT_EQ(fl->continuing, nullptr);
-  EXPECT_TRUE(fl->body->Empty());
+    auto p = parser("for (; 0 == 1;) { }");
+    auto fl = p->for_stmt();
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_FALSE(fl.errored);
+    ASSERT_TRUE(fl.matched);
+    EXPECT_EQ(fl->initializer, nullptr);
+    EXPECT_TRUE(Is<ast::BinaryExpression>(fl->condition));
+    EXPECT_EQ(fl->continuing, nullptr);
+    EXPECT_TRUE(fl->body->Empty());
 }
 
 // Test a for loop assigning a variable in the continuing statement.
 TEST_F(ForStmtTest, ContinuingAssignment) {
-  auto p = parser("for (;; x = 2) { }");
-  auto fl = p->for_stmt();
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_FALSE(fl.errored);
-  ASSERT_TRUE(fl.matched);
-  EXPECT_EQ(fl->initializer, nullptr);
-  EXPECT_EQ(fl->condition, nullptr);
-  EXPECT_TRUE(Is<ast::AssignmentStatement>(fl->continuing));
-  EXPECT_TRUE(fl->body->Empty());
+    auto p = parser("for (;; x = 2) { }");
+    auto fl = p->for_stmt();
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_FALSE(fl.errored);
+    ASSERT_TRUE(fl.matched);
+    EXPECT_EQ(fl->initializer, nullptr);
+    EXPECT_EQ(fl->condition, nullptr);
+    EXPECT_TRUE(Is<ast::AssignmentStatement>(fl->continuing));
+    EXPECT_TRUE(fl->body->Empty());
 }
 
 // Test a for loop with an increment statement as the continuing statement.
 TEST_F(ForStmtTest, ContinuingIncrement) {
-  auto p = parser("for (;; x++) { }");
-  auto fl = p->for_stmt();
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_FALSE(fl.errored);
-  ASSERT_TRUE(fl.matched);
-  EXPECT_EQ(fl->initializer, nullptr);
-  EXPECT_EQ(fl->condition, nullptr);
-  EXPECT_TRUE(Is<ast::IncrementDecrementStatement>(fl->continuing));
-  EXPECT_TRUE(fl->body->Empty());
+    auto p = parser("for (;; x++) { }");
+    auto fl = p->for_stmt();
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_FALSE(fl.errored);
+    ASSERT_TRUE(fl.matched);
+    EXPECT_EQ(fl->initializer, nullptr);
+    EXPECT_EQ(fl->condition, nullptr);
+    EXPECT_TRUE(Is<ast::IncrementDecrementStatement>(fl->continuing));
+    EXPECT_TRUE(fl->body->Empty());
 }
 
 // Test a for loop calling a function in the continuing statement.
 TEST_F(ForStmtTest, ContinuingFuncCall) {
-  auto p = parser("for (;; a(b,c)) { }");
-  auto fl = p->for_stmt();
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_FALSE(fl.errored);
-  ASSERT_TRUE(fl.matched);
-  EXPECT_EQ(fl->initializer, nullptr);
-  EXPECT_EQ(fl->condition, nullptr);
-  EXPECT_TRUE(Is<ast::CallStatement>(fl->continuing));
-  EXPECT_TRUE(fl->body->Empty());
+    auto p = parser("for (;; a(b,c)) { }");
+    auto fl = p->for_stmt();
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_FALSE(fl.errored);
+    ASSERT_TRUE(fl.matched);
+    EXPECT_EQ(fl->initializer, nullptr);
+    EXPECT_EQ(fl->condition, nullptr);
+    EXPECT_TRUE(Is<ast::CallStatement>(fl->continuing));
+    EXPECT_TRUE(fl->body->Empty());
 }
 
 class ForStmtErrorTest : public ParserImplTest {
- public:
-  void TestForWithError(std::string for_str, std::string error_str) {
-    auto p_for = parser(for_str);
-    auto e_for = p_for->for_stmt();
+  public:
+    void TestForWithError(std::string for_str, std::string error_str) {
+        auto p_for = parser(for_str);
+        auto e_for = p_for->for_stmt();
 
-    EXPECT_FALSE(e_for.matched);
-    EXPECT_TRUE(e_for.errored);
-    EXPECT_TRUE(p_for->has_error());
-    ASSERT_EQ(e_for.value, nullptr);
-    EXPECT_EQ(p_for->error(), error_str);
-  }
+        EXPECT_FALSE(e_for.matched);
+        EXPECT_TRUE(e_for.errored);
+        EXPECT_TRUE(p_for->has_error());
+        ASSERT_EQ(e_for.value, nullptr);
+        EXPECT_EQ(p_for->error(), error_str);
+    }
 };
 
 // Test a for loop with missing left parenthesis is invalid.
 TEST_F(ForStmtErrorTest, MissingLeftParen) {
-  std::string for_str = "for { }";
-  std::string error_str = "1:5: expected '(' for for loop";
+    std::string for_str = "for { }";
+    std::string error_str = "1:5: expected '(' for for loop";
 
-  TestForWithError(for_str, error_str);
+    TestForWithError(for_str, error_str);
 }
 
 // Test a for loop with missing first semicolon is invalid.
 TEST_F(ForStmtErrorTest, MissingFirstSemicolon) {
-  std::string for_str = "for () {}";
-  std::string error_str = "1:6: expected ';' for initializer in for loop";
+    std::string for_str = "for () {}";
+    std::string error_str = "1:6: expected ';' for initializer in for loop";
 
-  TestForWithError(for_str, error_str);
+    TestForWithError(for_str, error_str);
 }
 
 // Test a for loop with missing second semicolon is invalid.
 TEST_F(ForStmtErrorTest, MissingSecondSemicolon) {
-  std::string for_str = "for (;) {}";
-  std::string error_str = "1:7: expected ';' for condition in for loop";
+    std::string for_str = "for (;) {}";
+    std::string error_str = "1:7: expected ';' for condition in for loop";
 
-  TestForWithError(for_str, error_str);
+    TestForWithError(for_str, error_str);
 }
 
 // Test a for loop with missing right parenthesis is invalid.
 TEST_F(ForStmtErrorTest, MissingRightParen) {
-  std::string for_str = "for (;; {}";
-  std::string error_str = "1:9: expected ')' for for loop";
+    std::string for_str = "for (;; {}";
+    std::string error_str = "1:9: expected ')' for for loop";
 
-  TestForWithError(for_str, error_str);
+    TestForWithError(for_str, error_str);
 }
 
 // Test a for loop with missing left brace is invalid.
 TEST_F(ForStmtErrorTest, MissingLeftBrace) {
-  std::string for_str = "for (;;)";
-  std::string error_str = "1:9: expected '{' for for loop";
+    std::string for_str = "for (;;)";
+    std::string error_str = "1:9: expected '{' for for loop";
 
-  TestForWithError(for_str, error_str);
+    TestForWithError(for_str, error_str);
 }
 
 // Test a for loop with missing right brace is invalid.
 TEST_F(ForStmtErrorTest, MissingRightBrace) {
-  std::string for_str = "for (;;) {";
-  std::string error_str = "1:11: expected '}' for for loop";
+    std::string for_str = "for (;;) {";
+    std::string error_str = "1:11: expected '}' for for loop";
 
-  TestForWithError(for_str, error_str);
+    TestForWithError(for_str, error_str);
 }
 
 // Test a for loop with an invalid initializer statement.
 TEST_F(ForStmtErrorTest, InvalidInitializerAsConstDecl) {
-  std::string for_str = "for (let x: i32;;) { }";
-  std::string error_str = "1:16: expected '=' for let declaration";
+    std::string for_str = "for (let x: i32;;) { }";
+    std::string error_str = "1:16: expected '=' for let declaration";
 
-  TestForWithError(for_str, error_str);
+    TestForWithError(for_str, error_str);
 }
 
 // Test a for loop with a initializer statement not matching
 // variable_stmt | assignment_stmt | func_call_stmt.
 TEST_F(ForStmtErrorTest, InvalidInitializerMatch) {
-  std::string for_str = "for (if (true) {} ;;) { }";
-  std::string error_str = "1:6: expected ';' for initializer in for loop";
+    std::string for_str = "for (if (true) {} ;;) { }";
+    std::string error_str = "1:6: expected ';' for initializer in for loop";
 
-  TestForWithError(for_str, error_str);
+    TestForWithError(for_str, error_str);
 }
 
 // Test a for loop with an invalid break condition.
 TEST_F(ForStmtErrorTest, InvalidBreakConditionAsExpression) {
-  std::string for_str = "for (; (0 == 1; ) { }";
-  std::string error_str = "1:15: expected ')'";
+    std::string for_str = "for (; (0 == 1; ) { }";
+    std::string error_str = "1:15: expected ')'";
 
-  TestForWithError(for_str, error_str);
+    TestForWithError(for_str, error_str);
 }
 
 // Test a for loop with a break condition not matching
 // logical_or_expression.
 TEST_F(ForStmtErrorTest, InvalidBreakConditionMatch) {
-  std::string for_str = "for (; var i: i32 = 0;) { }";
-  std::string error_str = "1:8: expected ';' for condition in for loop";
+    std::string for_str = "for (; var i: i32 = 0;) { }";
+    std::string error_str = "1:8: expected ';' for condition in for loop";
 
-  TestForWithError(for_str, error_str);
+    TestForWithError(for_str, error_str);
 }
 
 // Test a for loop with an invalid continuing statement.
 TEST_F(ForStmtErrorTest, InvalidContinuingAsFuncCall) {
-  std::string for_str = "for (;; a(,) ) { }";
-  std::string error_str = "1:11: expected ')' for function call";
+    std::string for_str = "for (;; a(,) ) { }";
+    std::string error_str = "1:11: expected ')' for function call";
 
-  TestForWithError(for_str, error_str);
+    TestForWithError(for_str, error_str);
 }
 
 // Test a for loop with a continuing statement not matching
 // assignment_stmt | func_call_stmt.
 TEST_F(ForStmtErrorTest, InvalidContinuingMatch) {
-  std::string for_str = "for (;; var i: i32 = 0) { }";
-  std::string error_str = "1:9: expected ')' for for loop";
+    std::string for_str = "for (;; var i: i32 = 0) { }";
+    std::string error_str = "1:9: expected ')' for for loop";
 
-  TestForWithError(for_str, error_str);
+    TestForWithError(for_str, error_str);
 }
 
 // Test a for loop with an invalid body.
 TEST_F(ForStmtErrorTest, InvalidBody) {
-  std::string for_str = "for (;;) { let x: i32; }";
-  std::string error_str = "1:22: expected '=' for let declaration";
+    std::string for_str = "for (;;) { let x: i32; }";
+    std::string error_str = "1:22: expected '=' for let declaration";
 
-  TestForWithError(for_str, error_str);
+    TestForWithError(for_str, error_str);
 }
 
 // Test a for loop with a body not matching statements
 TEST_F(ForStmtErrorTest, InvalidBodyMatch) {
-  std::string for_str = "for (;;) { fn main() {} }";
-  std::string error_str = "1:12: expected '}' for for loop";
+    std::string for_str = "for (;;) { fn main() {} }";
+    std::string error_str = "1:12: expected '}' for for loop";
 
-  TestForWithError(for_str, error_str);
+    TestForWithError(for_str, error_str);
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_function_attribute_list_test.cc b/src/tint/reader/wgsl/parser_impl_function_attribute_list_test.cc
index 00d3c88..356241b 100644
--- a/src/tint/reader/wgsl/parser_impl_function_attribute_list_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_function_attribute_list_test.cc
@@ -19,48 +19,48 @@
 namespace {
 
 TEST_F(ParserImplTest, AttributeList_Parses) {
-  auto p = parser("@workgroup_size(2) @stage(compute)");
-  auto attrs = p->attribute_list();
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_FALSE(attrs.errored);
-  EXPECT_TRUE(attrs.matched);
-  ASSERT_EQ(attrs.value.size(), 2u);
+    auto p = parser("@workgroup_size(2) @stage(compute)");
+    auto attrs = p->attribute_list();
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_FALSE(attrs.errored);
+    EXPECT_TRUE(attrs.matched);
+    ASSERT_EQ(attrs.value.size(), 2u);
 
-  auto* attr_0 = attrs.value[0]->As<ast::Attribute>();
-  auto* attr_1 = attrs.value[1]->As<ast::Attribute>();
-  ASSERT_NE(attr_0, nullptr);
-  ASSERT_NE(attr_1, nullptr);
+    auto* attr_0 = attrs.value[0]->As<ast::Attribute>();
+    auto* attr_1 = attrs.value[1]->As<ast::Attribute>();
+    ASSERT_NE(attr_0, nullptr);
+    ASSERT_NE(attr_1, nullptr);
 
-  ASSERT_TRUE(attr_0->Is<ast::WorkgroupAttribute>());
-  const ast::Expression* x = attr_0->As<ast::WorkgroupAttribute>()->x;
-  ASSERT_NE(x, nullptr);
-  auto* x_literal = x->As<ast::LiteralExpression>();
-  ASSERT_NE(x_literal, nullptr);
-  ASSERT_TRUE(x_literal->Is<ast::IntLiteralExpression>());
-  EXPECT_EQ(x_literal->As<ast::IntLiteralExpression>()->ValueAsU32(), 2u);
-
-  ASSERT_TRUE(attr_1->Is<ast::StageAttribute>());
-  EXPECT_EQ(attr_1->As<ast::StageAttribute>()->stage,
-            ast::PipelineStage::kCompute);
+    ASSERT_TRUE(attr_0->Is<ast::WorkgroupAttribute>());
+    const ast::Expression* x = attr_0->As<ast::WorkgroupAttribute>()->x;
+    ASSERT_NE(x, nullptr);
+    auto* x_literal = x->As<ast::LiteralExpression>();
+    ASSERT_NE(x_literal, nullptr);
+    ASSERT_TRUE(x_literal->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(x_literal->As<ast::IntLiteralExpression>()->value, 2);
+    EXPECT_EQ(x_literal->As<ast::IntLiteralExpression>()->suffix,
+              ast::IntLiteralExpression::Suffix::kNone);
+    ASSERT_TRUE(attr_1->Is<ast::StageAttribute>());
+    EXPECT_EQ(attr_1->As<ast::StageAttribute>()->stage, ast::PipelineStage::kCompute);
 }
 
 TEST_F(ParserImplTest, AttributeList_Invalid) {
-  auto p = parser("@invalid");
-  auto attrs = p->attribute_list();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(attrs.errored);
-  EXPECT_FALSE(attrs.matched);
-  EXPECT_TRUE(attrs.value.empty());
-  EXPECT_EQ(p->error(), "1:2: expected attribute");
+    auto p = parser("@invalid");
+    auto attrs = p->attribute_list();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(attrs.errored);
+    EXPECT_FALSE(attrs.matched);
+    EXPECT_TRUE(attrs.value.empty());
+    EXPECT_EQ(p->error(), "1:2: expected attribute");
 }
 
 TEST_F(ParserImplTest, AttributeList_BadAttribute) {
-  auto p = parser("@stage()");
-  auto attrs = p->attribute_list();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(attrs.errored);
-  EXPECT_FALSE(attrs.matched);
-  EXPECT_EQ(p->error(), "1:8: invalid value for stage attribute");
+    auto p = parser("@stage()");
+    auto attrs = p->attribute_list();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(attrs.errored);
+    EXPECT_FALSE(attrs.matched);
+    EXPECT_EQ(p->error(), "1:8: invalid value for stage attribute");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_function_attribute_test.cc b/src/tint/reader/wgsl/parser_impl_function_attribute_test.cc
index 5d8c462..d2585b3 100644
--- a/src/tint/reader/wgsl/parser_impl_function_attribute_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_function_attribute_test.cc
@@ -20,236 +20,249 @@
 namespace {
 
 TEST_F(ParserImplTest, Attribute_Workgroup) {
-  auto p = parser("workgroup_size(4)");
-  auto attr = p->attribute();
-  EXPECT_TRUE(attr.matched);
-  EXPECT_FALSE(attr.errored);
-  ASSERT_NE(attr.value, nullptr) << p->error();
-  ASSERT_FALSE(p->has_error());
-  auto* func_attr = attr.value->As<ast::Attribute>();
-  ASSERT_NE(func_attr, nullptr);
-  ASSERT_TRUE(func_attr->Is<ast::WorkgroupAttribute>());
+    auto p = parser("workgroup_size(4)");
+    auto attr = p->attribute();
+    EXPECT_TRUE(attr.matched);
+    EXPECT_FALSE(attr.errored);
+    ASSERT_NE(attr.value, nullptr) << p->error();
+    ASSERT_FALSE(p->has_error());
+    auto* func_attr = attr.value->As<ast::Attribute>();
+    ASSERT_NE(func_attr, nullptr);
+    ASSERT_TRUE(func_attr->Is<ast::WorkgroupAttribute>());
 
-  auto values = func_attr->As<ast::WorkgroupAttribute>()->Values();
+    auto values = func_attr->As<ast::WorkgroupAttribute>()->Values();
 
-  ASSERT_TRUE(values[0]->Is<ast::IntLiteralExpression>());
-  EXPECT_EQ(values[0]->As<ast::IntLiteralExpression>()->ValueAsU32(), 4u);
+    ASSERT_TRUE(values[0]->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(values[0]->As<ast::IntLiteralExpression>()->value, 4);
+    EXPECT_EQ(values[0]->As<ast::IntLiteralExpression>()->suffix,
+              ast::IntLiteralExpression::Suffix::kNone);
 
-  EXPECT_EQ(values[1], nullptr);
-  EXPECT_EQ(values[2], nullptr);
+    EXPECT_EQ(values[1], nullptr);
+    EXPECT_EQ(values[2], nullptr);
 }
 
 TEST_F(ParserImplTest, Attribute_Workgroup_2Param) {
-  auto p = parser("workgroup_size(4, 5)");
-  auto attr = p->attribute();
-  EXPECT_TRUE(attr.matched);
-  EXPECT_FALSE(attr.errored);
-  ASSERT_NE(attr.value, nullptr) << p->error();
-  ASSERT_FALSE(p->has_error());
-  auto* func_attr = attr.value->As<ast::Attribute>();
-  ASSERT_NE(func_attr, nullptr) << p->error();
-  ASSERT_TRUE(func_attr->Is<ast::WorkgroupAttribute>());
+    auto p = parser("workgroup_size(4, 5)");
+    auto attr = p->attribute();
+    EXPECT_TRUE(attr.matched);
+    EXPECT_FALSE(attr.errored);
+    ASSERT_NE(attr.value, nullptr) << p->error();
+    ASSERT_FALSE(p->has_error());
+    auto* func_attr = attr.value->As<ast::Attribute>();
+    ASSERT_NE(func_attr, nullptr) << p->error();
+    ASSERT_TRUE(func_attr->Is<ast::WorkgroupAttribute>());
 
-  auto values = func_attr->As<ast::WorkgroupAttribute>()->Values();
+    auto values = func_attr->As<ast::WorkgroupAttribute>()->Values();
 
-  ASSERT_TRUE(values[0]->Is<ast::IntLiteralExpression>());
-  EXPECT_EQ(values[0]->As<ast::IntLiteralExpression>()->ValueAsU32(), 4u);
+    ASSERT_TRUE(values[0]->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(values[0]->As<ast::IntLiteralExpression>()->value, 4);
+    EXPECT_EQ(values[0]->As<ast::IntLiteralExpression>()->suffix,
+              ast::IntLiteralExpression::Suffix::kNone);
 
-  ASSERT_TRUE(values[1]->Is<ast::IntLiteralExpression>());
-  EXPECT_EQ(values[1]->As<ast::IntLiteralExpression>()->ValueAsU32(), 5u);
+    ASSERT_TRUE(values[1]->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(values[1]->As<ast::IntLiteralExpression>()->value, 5);
+    EXPECT_EQ(values[1]->As<ast::IntLiteralExpression>()->suffix,
+              ast::IntLiteralExpression::Suffix::kNone);
 
-  EXPECT_EQ(values[2], nullptr);
+    EXPECT_EQ(values[2], nullptr);
 }
 
 TEST_F(ParserImplTest, Attribute_Workgroup_3Param) {
-  auto p = parser("workgroup_size(4, 5, 6)");
-  auto attr = p->attribute();
-  EXPECT_TRUE(attr.matched);
-  EXPECT_FALSE(attr.errored);
-  ASSERT_NE(attr.value, nullptr) << p->error();
-  ASSERT_FALSE(p->has_error());
-  auto* func_attr = attr.value->As<ast::Attribute>();
-  ASSERT_NE(func_attr, nullptr);
-  ASSERT_TRUE(func_attr->Is<ast::WorkgroupAttribute>());
+    auto p = parser("workgroup_size(4, 5, 6)");
+    auto attr = p->attribute();
+    EXPECT_TRUE(attr.matched);
+    EXPECT_FALSE(attr.errored);
+    ASSERT_NE(attr.value, nullptr) << p->error();
+    ASSERT_FALSE(p->has_error());
+    auto* func_attr = attr.value->As<ast::Attribute>();
+    ASSERT_NE(func_attr, nullptr);
+    ASSERT_TRUE(func_attr->Is<ast::WorkgroupAttribute>());
 
-  auto values = func_attr->As<ast::WorkgroupAttribute>()->Values();
+    auto values = func_attr->As<ast::WorkgroupAttribute>()->Values();
 
-  ASSERT_TRUE(values[0]->Is<ast::IntLiteralExpression>());
-  EXPECT_EQ(values[0]->As<ast::IntLiteralExpression>()->ValueAsU32(), 4u);
+    ASSERT_TRUE(values[0]->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(values[0]->As<ast::IntLiteralExpression>()->value, 4);
+    EXPECT_EQ(values[0]->As<ast::IntLiteralExpression>()->suffix,
+              ast::IntLiteralExpression::Suffix::kNone);
 
-  ASSERT_TRUE(values[1]->Is<ast::IntLiteralExpression>());
-  EXPECT_EQ(values[1]->As<ast::IntLiteralExpression>()->ValueAsU32(), 5u);
+    ASSERT_TRUE(values[1]->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(values[1]->As<ast::IntLiteralExpression>()->value, 5);
+    EXPECT_EQ(values[1]->As<ast::IntLiteralExpression>()->suffix,
+              ast::IntLiteralExpression::Suffix::kNone);
 
-  ASSERT_TRUE(values[2]->Is<ast::IntLiteralExpression>());
-  EXPECT_EQ(values[2]->As<ast::IntLiteralExpression>()->ValueAsU32(), 6u);
+    ASSERT_TRUE(values[2]->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(values[2]->As<ast::IntLiteralExpression>()->value, 6);
+    EXPECT_EQ(values[2]->As<ast::IntLiteralExpression>()->suffix,
+              ast::IntLiteralExpression::Suffix::kNone);
 }
 
 TEST_F(ParserImplTest, Attribute_Workgroup_WithIdent) {
-  auto p = parser("workgroup_size(4, height)");
-  auto attr = p->attribute();
-  EXPECT_TRUE(attr.matched);
-  EXPECT_FALSE(attr.errored);
-  ASSERT_NE(attr.value, nullptr) << p->error();
-  ASSERT_FALSE(p->has_error());
-  auto* func_attr = attr.value->As<ast::Attribute>();
-  ASSERT_NE(func_attr, nullptr);
-  ASSERT_TRUE(func_attr->Is<ast::WorkgroupAttribute>());
+    auto p = parser("workgroup_size(4, height)");
+    auto attr = p->attribute();
+    EXPECT_TRUE(attr.matched);
+    EXPECT_FALSE(attr.errored);
+    ASSERT_NE(attr.value, nullptr) << p->error();
+    ASSERT_FALSE(p->has_error());
+    auto* func_attr = attr.value->As<ast::Attribute>();
+    ASSERT_NE(func_attr, nullptr);
+    ASSERT_TRUE(func_attr->Is<ast::WorkgroupAttribute>());
 
-  auto values = func_attr->As<ast::WorkgroupAttribute>()->Values();
+    auto values = func_attr->As<ast::WorkgroupAttribute>()->Values();
 
-  ASSERT_TRUE(values[0]->Is<ast::IntLiteralExpression>());
-  EXPECT_EQ(values[0]->As<ast::IntLiteralExpression>()->ValueAsU32(), 4u);
+    ASSERT_TRUE(values[0]->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(values[0]->As<ast::IntLiteralExpression>()->value, 4);
+    EXPECT_EQ(values[0]->As<ast::IntLiteralExpression>()->suffix,
+              ast::IntLiteralExpression::Suffix::kNone);
 
-  ASSERT_NE(values[1], nullptr);
-  auto* y_ident = values[1]->As<ast::IdentifierExpression>();
-  ASSERT_NE(y_ident, nullptr);
-  EXPECT_EQ(p->builder().Symbols().NameFor(y_ident->symbol), "height");
+    ASSERT_NE(values[1], nullptr);
+    auto* y_ident = values[1]->As<ast::IdentifierExpression>();
+    ASSERT_NE(y_ident, nullptr);
+    EXPECT_EQ(p->builder().Symbols().NameFor(y_ident->symbol), "height");
 
-  ASSERT_EQ(values[2], nullptr);
+    ASSERT_EQ(values[2], nullptr);
 }
 
 TEST_F(ParserImplTest, Attribute_Workgroup_TooManyValues) {
-  auto p = parser("workgroup_size(1, 2, 3, 4)");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:23: expected ')' for workgroup_size attribute");
+    auto p = parser("workgroup_size(1, 2, 3, 4)");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:23: expected ')' for workgroup_size attribute");
 }
 
 TEST_F(ParserImplTest, Attribute_Workgroup_MissingLeftParam) {
-  auto p = parser("workgroup_size 4, 5, 6)");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:16: expected '(' for workgroup_size attribute");
+    auto p = parser("workgroup_size 4, 5, 6)");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:16: expected '(' for workgroup_size attribute");
 }
 
 TEST_F(ParserImplTest, Attribute_Workgroup_MissingRightParam) {
-  auto p = parser("workgroup_size(4, 5, 6");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:23: expected ')' for workgroup_size attribute");
+    auto p = parser("workgroup_size(4, 5, 6");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:23: expected ')' for workgroup_size attribute");
 }
 
 TEST_F(ParserImplTest, Attribute_Workgroup_MissingValues) {
-  auto p = parser("workgroup_size()");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:16: expected workgroup_size x parameter");
+    auto p = parser("workgroup_size()");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:16: expected workgroup_size x parameter");
 }
 
 TEST_F(ParserImplTest, Attribute_Workgroup_Missing_X_Value) {
-  auto p = parser("workgroup_size(, 2, 3)");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:16: expected workgroup_size x parameter");
+    auto p = parser("workgroup_size(, 2, 3)");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:16: expected workgroup_size x parameter");
 }
 
 TEST_F(ParserImplTest, Attribute_Workgroup_Missing_Y_Comma) {
-  auto p = parser("workgroup_size(1 2, 3)");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:18: expected ')' for workgroup_size attribute");
+    auto p = parser("workgroup_size(1 2, 3)");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:18: expected ')' for workgroup_size attribute");
 }
 
 TEST_F(ParserImplTest, Attribute_Workgroup_Missing_Y_Value) {
-  auto p = parser("workgroup_size(1, , 3)");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:19: expected workgroup_size y parameter");
+    auto p = parser("workgroup_size(1, , 3)");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:19: expected workgroup_size y parameter");
 }
 
 TEST_F(ParserImplTest, Attribute_Workgroup_Missing_Z_Comma) {
-  auto p = parser("workgroup_size(1, 2 3)");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:21: expected ')' for workgroup_size attribute");
+    auto p = parser("workgroup_size(1, 2 3)");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:21: expected ')' for workgroup_size attribute");
 }
 
 TEST_F(ParserImplTest, Attribute_Workgroup_Missing_Z_Value) {
-  auto p = parser("workgroup_size(1, 2, )");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:22: expected workgroup_size z parameter");
+    auto p = parser("workgroup_size(1, 2, )");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:22: expected workgroup_size z parameter");
 }
 
 TEST_F(ParserImplTest, Attribute_Stage) {
-  auto p = parser("stage(compute)");
-  auto attr = p->attribute();
-  EXPECT_TRUE(attr.matched);
-  EXPECT_FALSE(attr.errored);
-  ASSERT_NE(attr.value, nullptr) << p->error();
-  ASSERT_FALSE(p->has_error());
-  auto* func_attr = attr.value->As<ast::Attribute>();
-  ASSERT_NE(func_attr, nullptr);
-  ASSERT_TRUE(func_attr->Is<ast::StageAttribute>());
-  EXPECT_EQ(func_attr->As<ast::StageAttribute>()->stage,
-            ast::PipelineStage::kCompute);
+    auto p = parser("stage(compute)");
+    auto attr = p->attribute();
+    EXPECT_TRUE(attr.matched);
+    EXPECT_FALSE(attr.errored);
+    ASSERT_NE(attr.value, nullptr) << p->error();
+    ASSERT_FALSE(p->has_error());
+    auto* func_attr = attr.value->As<ast::Attribute>();
+    ASSERT_NE(func_attr, nullptr);
+    ASSERT_TRUE(func_attr->Is<ast::StageAttribute>());
+    EXPECT_EQ(func_attr->As<ast::StageAttribute>()->stage, ast::PipelineStage::kCompute);
 }
 
 TEST_F(ParserImplTest, Attribute_Stage_MissingValue) {
-  auto p = parser("stage()");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:7: invalid value for stage attribute");
+    auto p = parser("stage()");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:7: invalid value for stage attribute");
 }
 
 TEST_F(ParserImplTest, Attribute_Stage_MissingInvalid) {
-  auto p = parser("stage(nan)");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:7: invalid value for stage attribute");
+    auto p = parser("stage(nan)");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:7: invalid value for stage attribute");
 }
 
 TEST_F(ParserImplTest, Attribute_Stage_MissingLeftParen) {
-  auto p = parser("stage compute)");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:7: expected '(' for stage attribute");
+    auto p = parser("stage compute)");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:7: expected '(' for stage attribute");
 }
 
 TEST_F(ParserImplTest, Attribute_Stage_MissingRightParen) {
-  auto p = parser("stage(compute");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:14: expected ')' for stage attribute");
+    auto p = parser("stage(compute");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:14: expected ')' for stage attribute");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_function_decl_test.cc b/src/tint/reader/wgsl/parser_impl_function_decl_test.cc
index d94e525..181501a 100644
--- a/src/tint/reader/wgsl/parser_impl_function_decl_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_function_decl_test.cc
@@ -20,273 +20,289 @@
 namespace {
 
 TEST_F(ParserImplTest, FunctionDecl) {
-  auto p = parser("fn main(a : i32, b : f32) { return; }");
-  auto attrs = p->attribute_list();
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_FALSE(attrs.errored);
-  EXPECT_FALSE(attrs.matched);
-  auto f = p->function_decl(attrs.value);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_FALSE(f.errored);
-  EXPECT_TRUE(f.matched);
-  ASSERT_NE(f.value, nullptr);
+    auto p = parser("fn main(a : i32, b : f32) { return; }");
+    auto attrs = p->attribute_list();
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_FALSE(attrs.errored);
+    EXPECT_FALSE(attrs.matched);
+    auto f = p->function_decl(attrs.value);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_FALSE(f.errored);
+    EXPECT_TRUE(f.matched);
+    ASSERT_NE(f.value, nullptr);
 
-  EXPECT_EQ(f->symbol, p->builder().Symbols().Get("main"));
-  ASSERT_NE(f->return_type, nullptr);
-  EXPECT_TRUE(f->return_type->Is<ast::Void>());
+    EXPECT_EQ(f->symbol, p->builder().Symbols().Get("main"));
+    ASSERT_NE(f->return_type, nullptr);
+    EXPECT_TRUE(f->return_type->Is<ast::Void>());
 
-  ASSERT_EQ(f->params.size(), 2u);
-  EXPECT_EQ(f->params[0]->symbol, p->builder().Symbols().Get("a"));
-  EXPECT_EQ(f->params[1]->symbol, p->builder().Symbols().Get("b"));
+    ASSERT_EQ(f->params.size(), 2u);
+    EXPECT_EQ(f->params[0]->symbol, p->builder().Symbols().Get("a"));
+    EXPECT_EQ(f->params[1]->symbol, p->builder().Symbols().Get("b"));
 
-  ASSERT_NE(f->return_type, nullptr);
-  EXPECT_TRUE(f->return_type->Is<ast::Void>());
+    ASSERT_NE(f->return_type, nullptr);
+    EXPECT_TRUE(f->return_type->Is<ast::Void>());
 
-  auto* body = f->body;
-  ASSERT_EQ(body->statements.size(), 1u);
-  EXPECT_TRUE(body->statements[0]->Is<ast::ReturnStatement>());
+    auto* body = f->body;
+    ASSERT_EQ(body->statements.size(), 1u);
+    EXPECT_TRUE(body->statements[0]->Is<ast::ReturnStatement>());
 }
 
 TEST_F(ParserImplTest, FunctionDecl_Unicode) {
-  const std::string function_ident =  // "𝗳𝘂𝗻𝗰𝘁𝗶𝗼𝗻"
-      "\xf0\x9d\x97\xb3\xf0\x9d\x98\x82\xf0\x9d\x97\xbb\xf0\x9d\x97\xb0\xf0\x9d"
-      "\x98\x81\xf0\x9d\x97\xb6\xf0\x9d\x97\xbc\xf0\x9d\x97\xbb";
+    const std::string function_ident =  // "𝗳𝘂𝗻𝗰𝘁𝗶𝗼𝗻"
+        "\xf0\x9d\x97\xb3\xf0\x9d\x98\x82\xf0\x9d\x97\xbb\xf0\x9d\x97\xb0\xf0\x9d"
+        "\x98\x81\xf0\x9d\x97\xb6\xf0\x9d\x97\xbc\xf0\x9d\x97\xbb";
 
-  const std::string param_a_ident =  // "𝓹𝓪𝓻𝓪𝓶_𝓪"
-      "\xf0\x9d\x93\xb9\xf0\x9d\x93\xaa\xf0\x9d\x93\xbb\xf0\x9d\x93\xaa\xf0\x9d"
-      "\x93\xb6\x5f\xf0\x9d\x93\xaa";
+    const std::string param_a_ident =  // "𝓹𝓪𝓻𝓪𝓶_𝓪"
+        "\xf0\x9d\x93\xb9\xf0\x9d\x93\xaa\xf0\x9d\x93\xbb\xf0\x9d\x93\xaa\xf0\x9d"
+        "\x93\xb6\x5f\xf0\x9d\x93\xaa";
 
-  const std::string param_b_ident =  // "𝕡𝕒𝕣𝕒𝕞_𝕓"
-      "\xf0\x9d\x95\xa1\xf0\x9d\x95\x92\xf0\x9d\x95\xa3\xf0\x9d\x95\x92\xf0\x9d"
-      "\x95\x9e\x5f\xf0\x9d\x95\x93";
+    const std::string param_b_ident =  // "𝕡𝕒𝕣𝕒𝕞_𝕓"
+        "\xf0\x9d\x95\xa1\xf0\x9d\x95\x92\xf0\x9d\x95\xa3\xf0\x9d\x95\x92\xf0\x9d"
+        "\x95\x9e\x5f\xf0\x9d\x95\x93";
 
-  std::string src = "fn $function($param_a : i32, $param_b : f32) { return; }";
-  src = utils::ReplaceAll(src, "$function", function_ident);
-  src = utils::ReplaceAll(src, "$param_a", param_a_ident);
-  src = utils::ReplaceAll(src, "$param_b", param_b_ident);
+    std::string src = "fn $function($param_a : i32, $param_b : f32) { return; }";
+    src = utils::ReplaceAll(src, "$function", function_ident);
+    src = utils::ReplaceAll(src, "$param_a", param_a_ident);
+    src = utils::ReplaceAll(src, "$param_b", param_b_ident);
 
-  auto p = parser(src);
-  auto attrs = p->attribute_list();
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_FALSE(attrs.errored);
-  EXPECT_FALSE(attrs.matched);
-  auto f = p->function_decl(attrs.value);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_FALSE(f.errored);
-  EXPECT_TRUE(f.matched);
-  ASSERT_NE(f.value, nullptr);
+    auto p = parser(src);
+    auto attrs = p->attribute_list();
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_FALSE(attrs.errored);
+    EXPECT_FALSE(attrs.matched);
+    auto f = p->function_decl(attrs.value);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_FALSE(f.errored);
+    EXPECT_TRUE(f.matched);
+    ASSERT_NE(f.value, nullptr);
 
-  EXPECT_EQ(f->symbol, p->builder().Symbols().Get(function_ident));
-  ASSERT_NE(f->return_type, nullptr);
-  EXPECT_TRUE(f->return_type->Is<ast::Void>());
+    EXPECT_EQ(f->symbol, p->builder().Symbols().Get(function_ident));
+    ASSERT_NE(f->return_type, nullptr);
+    EXPECT_TRUE(f->return_type->Is<ast::Void>());
 
-  ASSERT_EQ(f->params.size(), 2u);
-  EXPECT_EQ(f->params[0]->symbol, p->builder().Symbols().Get(param_a_ident));
-  EXPECT_EQ(f->params[1]->symbol, p->builder().Symbols().Get(param_b_ident));
+    ASSERT_EQ(f->params.size(), 2u);
+    EXPECT_EQ(f->params[0]->symbol, p->builder().Symbols().Get(param_a_ident));
+    EXPECT_EQ(f->params[1]->symbol, p->builder().Symbols().Get(param_b_ident));
 
-  ASSERT_NE(f->return_type, nullptr);
-  EXPECT_TRUE(f->return_type->Is<ast::Void>());
+    ASSERT_NE(f->return_type, nullptr);
+    EXPECT_TRUE(f->return_type->Is<ast::Void>());
 
-  auto* body = f->body;
-  ASSERT_EQ(body->statements.size(), 1u);
-  EXPECT_TRUE(body->statements[0]->Is<ast::ReturnStatement>());
+    auto* body = f->body;
+    ASSERT_EQ(body->statements.size(), 1u);
+    EXPECT_TRUE(body->statements[0]->Is<ast::ReturnStatement>());
 }
 
 TEST_F(ParserImplTest, FunctionDecl_AttributeList) {
-  auto p = parser("@workgroup_size(2, 3, 4) fn main() { return; }");
-  auto attrs = p->attribute_list();
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_FALSE(attrs.errored);
-  ASSERT_TRUE(attrs.matched);
-  auto f = p->function_decl(attrs.value);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_FALSE(f.errored);
-  EXPECT_TRUE(f.matched);
-  ASSERT_NE(f.value, nullptr);
+    auto p = parser("@workgroup_size(2, 3, 4) fn main() { return; }");
+    auto attrs = p->attribute_list();
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_FALSE(attrs.errored);
+    ASSERT_TRUE(attrs.matched);
+    auto f = p->function_decl(attrs.value);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_FALSE(f.errored);
+    EXPECT_TRUE(f.matched);
+    ASSERT_NE(f.value, nullptr);
 
-  EXPECT_EQ(f->symbol, p->builder().Symbols().Get("main"));
-  ASSERT_NE(f->return_type, nullptr);
-  EXPECT_TRUE(f->return_type->Is<ast::Void>());
-  ASSERT_EQ(f->params.size(), 0u);
+    EXPECT_EQ(f->symbol, p->builder().Symbols().Get("main"));
+    ASSERT_NE(f->return_type, nullptr);
+    EXPECT_TRUE(f->return_type->Is<ast::Void>());
+    ASSERT_EQ(f->params.size(), 0u);
 
-  auto& attributes = f->attributes;
-  ASSERT_EQ(attributes.size(), 1u);
-  ASSERT_TRUE(attributes[0]->Is<ast::WorkgroupAttribute>());
+    auto& attributes = f->attributes;
+    ASSERT_EQ(attributes.size(), 1u);
+    ASSERT_TRUE(attributes[0]->Is<ast::WorkgroupAttribute>());
 
-  auto values = attributes[0]->As<ast::WorkgroupAttribute>()->Values();
+    auto values = attributes[0]->As<ast::WorkgroupAttribute>()->Values();
 
-  ASSERT_TRUE(values[0]->Is<ast::IntLiteralExpression>());
-  EXPECT_EQ(values[0]->As<ast::IntLiteralExpression>()->ValueAsU32(), 2u);
+    ASSERT_TRUE(values[0]->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(values[0]->As<ast::IntLiteralExpression>()->value, 2);
+    EXPECT_EQ(values[0]->As<ast::IntLiteralExpression>()->suffix,
+              ast::IntLiteralExpression::Suffix::kNone);
 
-  ASSERT_TRUE(values[1]->Is<ast::IntLiteralExpression>());
-  EXPECT_EQ(values[1]->As<ast::IntLiteralExpression>()->ValueAsU32(), 3u);
+    ASSERT_TRUE(values[1]->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(values[1]->As<ast::IntLiteralExpression>()->value, 3);
+    EXPECT_EQ(values[1]->As<ast::IntLiteralExpression>()->suffix,
+              ast::IntLiteralExpression::Suffix::kNone);
 
-  ASSERT_TRUE(values[2]->Is<ast::IntLiteralExpression>());
-  EXPECT_EQ(values[2]->As<ast::IntLiteralExpression>()->ValueAsU32(), 4u);
+    ASSERT_TRUE(values[2]->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(values[2]->As<ast::IntLiteralExpression>()->value, 4);
+    EXPECT_EQ(values[2]->As<ast::IntLiteralExpression>()->suffix,
+              ast::IntLiteralExpression::Suffix::kNone);
 
-  auto* body = f->body;
-  ASSERT_EQ(body->statements.size(), 1u);
-  EXPECT_TRUE(body->statements[0]->Is<ast::ReturnStatement>());
+    auto* body = f->body;
+    ASSERT_EQ(body->statements.size(), 1u);
+    EXPECT_TRUE(body->statements[0]->Is<ast::ReturnStatement>());
 }
 
 TEST_F(ParserImplTest, FunctionDecl_AttributeList_MultipleEntries) {
-  auto p = parser(R"(
+    auto p = parser(R"(
 @workgroup_size(2, 3, 4) @stage(compute)
 fn main() { return; })");
-  auto attrs = p->attribute_list();
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_FALSE(attrs.errored);
-  ASSERT_TRUE(attrs.matched);
-  auto f = p->function_decl(attrs.value);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_FALSE(f.errored);
-  EXPECT_TRUE(f.matched);
-  ASSERT_NE(f.value, nullptr);
+    auto attrs = p->attribute_list();
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_FALSE(attrs.errored);
+    ASSERT_TRUE(attrs.matched);
+    auto f = p->function_decl(attrs.value);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_FALSE(f.errored);
+    EXPECT_TRUE(f.matched);
+    ASSERT_NE(f.value, nullptr);
 
-  EXPECT_EQ(f->symbol, p->builder().Symbols().Get("main"));
-  ASSERT_NE(f->return_type, nullptr);
-  EXPECT_TRUE(f->return_type->Is<ast::Void>());
-  ASSERT_EQ(f->params.size(), 0u);
+    EXPECT_EQ(f->symbol, p->builder().Symbols().Get("main"));
+    ASSERT_NE(f->return_type, nullptr);
+    EXPECT_TRUE(f->return_type->Is<ast::Void>());
+    ASSERT_EQ(f->params.size(), 0u);
 
-  auto& attributes = f->attributes;
-  ASSERT_EQ(attributes.size(), 2u);
+    auto& attributes = f->attributes;
+    ASSERT_EQ(attributes.size(), 2u);
 
-  ASSERT_TRUE(attributes[0]->Is<ast::WorkgroupAttribute>());
-  auto values = attributes[0]->As<ast::WorkgroupAttribute>()->Values();
+    ASSERT_TRUE(attributes[0]->Is<ast::WorkgroupAttribute>());
+    auto values = attributes[0]->As<ast::WorkgroupAttribute>()->Values();
 
-  ASSERT_TRUE(values[0]->Is<ast::IntLiteralExpression>());
-  EXPECT_EQ(values[0]->As<ast::IntLiteralExpression>()->ValueAsU32(), 2u);
+    ASSERT_TRUE(values[0]->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(values[0]->As<ast::IntLiteralExpression>()->value, 2);
+    EXPECT_EQ(values[0]->As<ast::IntLiteralExpression>()->suffix,
+              ast::IntLiteralExpression::Suffix::kNone);
 
-  ASSERT_TRUE(values[1]->Is<ast::IntLiteralExpression>());
-  EXPECT_EQ(values[1]->As<ast::IntLiteralExpression>()->ValueAsU32(), 3u);
+    ASSERT_TRUE(values[1]->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(values[1]->As<ast::IntLiteralExpression>()->value, 3);
+    EXPECT_EQ(values[1]->As<ast::IntLiteralExpression>()->suffix,
+              ast::IntLiteralExpression::Suffix::kNone);
 
-  ASSERT_TRUE(values[2]->Is<ast::IntLiteralExpression>());
-  EXPECT_EQ(values[2]->As<ast::IntLiteralExpression>()->ValueAsU32(), 4u);
+    ASSERT_TRUE(values[2]->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(values[2]->As<ast::IntLiteralExpression>()->value, 4);
+    EXPECT_EQ(values[2]->As<ast::IntLiteralExpression>()->suffix,
+              ast::IntLiteralExpression::Suffix::kNone);
 
-  ASSERT_TRUE(attributes[1]->Is<ast::StageAttribute>());
-  EXPECT_EQ(attributes[1]->As<ast::StageAttribute>()->stage,
-            ast::PipelineStage::kCompute);
+    ASSERT_TRUE(attributes[1]->Is<ast::StageAttribute>());
+    EXPECT_EQ(attributes[1]->As<ast::StageAttribute>()->stage, ast::PipelineStage::kCompute);
 
-  auto* body = f->body;
-  ASSERT_EQ(body->statements.size(), 1u);
-  EXPECT_TRUE(body->statements[0]->Is<ast::ReturnStatement>());
+    auto* body = f->body;
+    ASSERT_EQ(body->statements.size(), 1u);
+    EXPECT_TRUE(body->statements[0]->Is<ast::ReturnStatement>());
 }
 
 TEST_F(ParserImplTest, FunctionDecl_AttributeList_MultipleLists) {
-  auto p = parser(R"(
+    auto p = parser(R"(
 @workgroup_size(2, 3, 4)
 @stage(compute)
 fn main() { return; })");
-  auto attributes = p->attribute_list();
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_FALSE(attributes.errored);
-  ASSERT_TRUE(attributes.matched);
-  auto f = p->function_decl(attributes.value);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_FALSE(f.errored);
-  EXPECT_TRUE(f.matched);
-  ASSERT_NE(f.value, nullptr);
+    auto attributes = p->attribute_list();
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_FALSE(attributes.errored);
+    ASSERT_TRUE(attributes.matched);
+    auto f = p->function_decl(attributes.value);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_FALSE(f.errored);
+    EXPECT_TRUE(f.matched);
+    ASSERT_NE(f.value, nullptr);
 
-  EXPECT_EQ(f->symbol, p->builder().Symbols().Get("main"));
-  ASSERT_NE(f->return_type, nullptr);
-  EXPECT_TRUE(f->return_type->Is<ast::Void>());
-  ASSERT_EQ(f->params.size(), 0u);
+    EXPECT_EQ(f->symbol, p->builder().Symbols().Get("main"));
+    ASSERT_NE(f->return_type, nullptr);
+    EXPECT_TRUE(f->return_type->Is<ast::Void>());
+    ASSERT_EQ(f->params.size(), 0u);
 
-  auto& attrs = f->attributes;
-  ASSERT_EQ(attrs.size(), 2u);
+    auto& attrs = f->attributes;
+    ASSERT_EQ(attrs.size(), 2u);
 
-  ASSERT_TRUE(attrs[0]->Is<ast::WorkgroupAttribute>());
-  auto values = attrs[0]->As<ast::WorkgroupAttribute>()->Values();
+    ASSERT_TRUE(attrs[0]->Is<ast::WorkgroupAttribute>());
+    auto values = attrs[0]->As<ast::WorkgroupAttribute>()->Values();
 
-  ASSERT_TRUE(values[0]->Is<ast::IntLiteralExpression>());
-  EXPECT_EQ(values[0]->As<ast::IntLiteralExpression>()->ValueAsU32(), 2u);
+    ASSERT_TRUE(values[0]->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(values[0]->As<ast::IntLiteralExpression>()->value, 2);
+    EXPECT_EQ(values[0]->As<ast::IntLiteralExpression>()->suffix,
+              ast::IntLiteralExpression::Suffix::kNone);
 
-  ASSERT_TRUE(values[1]->Is<ast::IntLiteralExpression>());
-  EXPECT_EQ(values[1]->As<ast::IntLiteralExpression>()->ValueAsU32(), 3u);
+    ASSERT_TRUE(values[1]->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(values[1]->As<ast::IntLiteralExpression>()->value, 3);
+    EXPECT_EQ(values[1]->As<ast::IntLiteralExpression>()->suffix,
+              ast::IntLiteralExpression::Suffix::kNone);
 
-  ASSERT_TRUE(values[2]->Is<ast::IntLiteralExpression>());
-  EXPECT_EQ(values[2]->As<ast::IntLiteralExpression>()->ValueAsU32(), 4u);
+    ASSERT_TRUE(values[2]->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(values[2]->As<ast::IntLiteralExpression>()->value, 4);
+    EXPECT_EQ(values[2]->As<ast::IntLiteralExpression>()->suffix,
+              ast::IntLiteralExpression::Suffix::kNone);
 
-  ASSERT_TRUE(attrs[1]->Is<ast::StageAttribute>());
-  EXPECT_EQ(attrs[1]->As<ast::StageAttribute>()->stage,
-            ast::PipelineStage::kCompute);
+    ASSERT_TRUE(attrs[1]->Is<ast::StageAttribute>());
+    EXPECT_EQ(attrs[1]->As<ast::StageAttribute>()->stage, ast::PipelineStage::kCompute);
 
-  auto* body = f->body;
-  ASSERT_EQ(body->statements.size(), 1u);
-  EXPECT_TRUE(body->statements[0]->Is<ast::ReturnStatement>());
+    auto* body = f->body;
+    ASSERT_EQ(body->statements.size(), 1u);
+    EXPECT_TRUE(body->statements[0]->Is<ast::ReturnStatement>());
 }
 
 TEST_F(ParserImplTest, FunctionDecl_ReturnTypeAttributeList) {
-  auto p = parser("fn main() -> @location(1) f32 { return 1.0; }");
-  auto attrs = p->attribute_list();
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_FALSE(attrs.errored);
-  EXPECT_FALSE(attrs.matched);
-  auto f = p->function_decl(attrs.value);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_FALSE(f.errored);
-  EXPECT_TRUE(f.matched);
-  ASSERT_NE(f.value, nullptr);
+    auto p = parser("fn main() -> @location(1) f32 { return 1.0; }");
+    auto attrs = p->attribute_list();
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_FALSE(attrs.errored);
+    EXPECT_FALSE(attrs.matched);
+    auto f = p->function_decl(attrs.value);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_FALSE(f.errored);
+    EXPECT_TRUE(f.matched);
+    ASSERT_NE(f.value, nullptr);
 
-  EXPECT_EQ(f->symbol, p->builder().Symbols().Get("main"));
-  ASSERT_NE(f->return_type, nullptr);
-  EXPECT_TRUE(f->return_type->Is<ast::F32>());
-  ASSERT_EQ(f->params.size(), 0u);
+    EXPECT_EQ(f->symbol, p->builder().Symbols().Get("main"));
+    ASSERT_NE(f->return_type, nullptr);
+    EXPECT_TRUE(f->return_type->Is<ast::F32>());
+    ASSERT_EQ(f->params.size(), 0u);
 
-  auto& attributes = f->attributes;
-  EXPECT_EQ(attributes.size(), 0u);
+    auto& attributes = f->attributes;
+    EXPECT_EQ(attributes.size(), 0u);
 
-  auto& ret_type_attributes = f->return_type_attributes;
-  ASSERT_EQ(ret_type_attributes.size(), 1u);
-  auto* loc = ret_type_attributes[0]->As<ast::LocationAttribute>();
-  ASSERT_TRUE(loc != nullptr);
-  EXPECT_EQ(loc->value, 1u);
+    auto& ret_type_attributes = f->return_type_attributes;
+    ASSERT_EQ(ret_type_attributes.size(), 1u);
+    auto* loc = ret_type_attributes[0]->As<ast::LocationAttribute>();
+    ASSERT_TRUE(loc != nullptr);
+    EXPECT_EQ(loc->value, 1u);
 
-  auto* body = f->body;
-  ASSERT_EQ(body->statements.size(), 1u);
-  EXPECT_TRUE(body->statements[0]->Is<ast::ReturnStatement>());
+    auto* body = f->body;
+    ASSERT_EQ(body->statements.size(), 1u);
+    EXPECT_TRUE(body->statements[0]->Is<ast::ReturnStatement>());
 }
 
 TEST_F(ParserImplTest, FunctionDecl_InvalidHeader) {
-  auto p = parser("fn main() -> { }");
-  auto attrs = p->attribute_list();
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_FALSE(attrs.errored);
-  EXPECT_FALSE(attrs.matched);
-  auto f = p->function_decl(attrs.value);
-  EXPECT_TRUE(f.errored);
-  EXPECT_FALSE(f.matched);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(f.value, nullptr);
-  EXPECT_EQ(p->error(), "1:14: unable to determine function return type");
+    auto p = parser("fn main() -> { }");
+    auto attrs = p->attribute_list();
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_FALSE(attrs.errored);
+    EXPECT_FALSE(attrs.matched);
+    auto f = p->function_decl(attrs.value);
+    EXPECT_TRUE(f.errored);
+    EXPECT_FALSE(f.matched);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(f.value, nullptr);
+    EXPECT_EQ(p->error(), "1:14: unable to determine function return type");
 }
 
 TEST_F(ParserImplTest, FunctionDecl_InvalidBody) {
-  auto p = parser("fn main() { return }");
-  auto attrs = p->attribute_list();
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_FALSE(attrs.errored);
-  EXPECT_FALSE(attrs.matched);
-  auto f = p->function_decl(attrs.value);
-  EXPECT_TRUE(f.errored);
-  EXPECT_FALSE(f.matched);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(f.value, nullptr);
-  EXPECT_EQ(p->error(), "1:20: expected ';' for return statement");
+    auto p = parser("fn main() { return }");
+    auto attrs = p->attribute_list();
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_FALSE(attrs.errored);
+    EXPECT_FALSE(attrs.matched);
+    auto f = p->function_decl(attrs.value);
+    EXPECT_TRUE(f.errored);
+    EXPECT_FALSE(f.matched);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(f.value, nullptr);
+    EXPECT_EQ(p->error(), "1:20: expected ';' for return statement");
 }
 
 TEST_F(ParserImplTest, FunctionDecl_MissingLeftBrace) {
-  auto p = parser("fn main() return; }");
-  auto attrs = p->attribute_list();
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_FALSE(attrs.errored);
-  EXPECT_FALSE(attrs.matched);
-  auto f = p->function_decl(attrs.value);
-  EXPECT_TRUE(f.errored);
-  EXPECT_FALSE(f.matched);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(f.value, nullptr);
-  EXPECT_EQ(p->error(), "1:11: expected '{'");
+    auto p = parser("fn main() return; }");
+    auto attrs = p->attribute_list();
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_FALSE(attrs.errored);
+    EXPECT_FALSE(attrs.matched);
+    auto f = p->function_decl(attrs.value);
+    EXPECT_TRUE(f.errored);
+    EXPECT_FALSE(f.matched);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(f.value, nullptr);
+    EXPECT_EQ(p->error(), "1:11: expected '{'");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_function_header_test.cc b/src/tint/reader/wgsl/parser_impl_function_header_test.cc
index c59a7e9..6f2e6cb 100644
--- a/src/tint/reader/wgsl/parser_impl_function_header_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_function_header_test.cc
@@ -18,113 +18,113 @@
 namespace {
 
 TEST_F(ParserImplTest, FunctionHeader) {
-  auto p = parser("fn main(a : i32, b: f32)");
-  auto f = p->function_header();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  EXPECT_TRUE(f.matched);
-  EXPECT_FALSE(f.errored);
+    auto p = parser("fn main(a : i32, b: f32)");
+    auto f = p->function_header();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    EXPECT_TRUE(f.matched);
+    EXPECT_FALSE(f.errored);
 
-  EXPECT_EQ(f->name, "main");
-  ASSERT_EQ(f->params.size(), 2u);
-  EXPECT_EQ(f->params[0]->symbol, p->builder().Symbols().Get("a"));
-  EXPECT_EQ(f->params[1]->symbol, p->builder().Symbols().Get("b"));
-  EXPECT_TRUE(f->return_type->Is<ast::Void>());
+    EXPECT_EQ(f->name, "main");
+    ASSERT_EQ(f->params.size(), 2u);
+    EXPECT_EQ(f->params[0]->symbol, p->builder().Symbols().Get("a"));
+    EXPECT_EQ(f->params[1]->symbol, p->builder().Symbols().Get("b"));
+    EXPECT_TRUE(f->return_type->Is<ast::Void>());
 }
 
 TEST_F(ParserImplTest, FunctionHeader_TrailingComma) {
-  auto p = parser("fn main(a :i32,)");
-  auto f = p->function_header();
-  EXPECT_TRUE(f.matched);
-  EXPECT_FALSE(f.errored);
+    auto p = parser("fn main(a :i32,)");
+    auto f = p->function_header();
+    EXPECT_TRUE(f.matched);
+    EXPECT_FALSE(f.errored);
 
-  EXPECT_EQ(f->name, "main");
-  ASSERT_EQ(f->params.size(), 1u);
-  EXPECT_EQ(f->params[0]->symbol, p->builder().Symbols().Get("a"));
-  EXPECT_TRUE(f->return_type->Is<ast::Void>());
+    EXPECT_EQ(f->name, "main");
+    ASSERT_EQ(f->params.size(), 1u);
+    EXPECT_EQ(f->params[0]->symbol, p->builder().Symbols().Get("a"));
+    EXPECT_TRUE(f->return_type->Is<ast::Void>());
 }
 
 TEST_F(ParserImplTest, FunctionHeader_AttributeReturnType) {
-  auto p = parser("fn main() -> @location(1) f32");
-  auto f = p->function_header();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  EXPECT_TRUE(f.matched);
-  EXPECT_FALSE(f.errored);
+    auto p = parser("fn main() -> @location(1) f32");
+    auto f = p->function_header();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    EXPECT_TRUE(f.matched);
+    EXPECT_FALSE(f.errored);
 
-  EXPECT_EQ(f->name, "main");
-  EXPECT_EQ(f->params.size(), 0u);
-  EXPECT_TRUE(f->return_type->Is<ast::F32>());
-  ASSERT_EQ(f->return_type_attributes.size(), 1u);
-  auto* loc = f->return_type_attributes[0]->As<ast::LocationAttribute>();
-  ASSERT_TRUE(loc != nullptr);
-  EXPECT_EQ(loc->value, 1u);
+    EXPECT_EQ(f->name, "main");
+    EXPECT_EQ(f->params.size(), 0u);
+    EXPECT_TRUE(f->return_type->Is<ast::F32>());
+    ASSERT_EQ(f->return_type_attributes.size(), 1u);
+    auto* loc = f->return_type_attributes[0]->As<ast::LocationAttribute>();
+    ASSERT_TRUE(loc != nullptr);
+    EXPECT_EQ(loc->value, 1u);
 }
 
 TEST_F(ParserImplTest, FunctionHeader_InvariantReturnType) {
-  auto p = parser("fn main() -> @invariant f32");
-  auto f = p->function_header();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  EXPECT_TRUE(f.matched);
-  EXPECT_FALSE(f.errored);
+    auto p = parser("fn main() -> @invariant f32");
+    auto f = p->function_header();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    EXPECT_TRUE(f.matched);
+    EXPECT_FALSE(f.errored);
 
-  EXPECT_EQ(f->name, "main");
-  EXPECT_EQ(f->params.size(), 0u);
-  EXPECT_TRUE(f->return_type->Is<ast::F32>());
-  ASSERT_EQ(f->return_type_attributes.size(), 1u);
-  EXPECT_TRUE(f->return_type_attributes[0]->Is<ast::InvariantAttribute>());
+    EXPECT_EQ(f->name, "main");
+    EXPECT_EQ(f->params.size(), 0u);
+    EXPECT_TRUE(f->return_type->Is<ast::F32>());
+    ASSERT_EQ(f->return_type_attributes.size(), 1u);
+    EXPECT_TRUE(f->return_type_attributes[0]->Is<ast::InvariantAttribute>());
 }
 
 TEST_F(ParserImplTest, FunctionHeader_MissingIdent) {
-  auto p = parser("fn ()");
-  auto f = p->function_header();
-  EXPECT_FALSE(f.matched);
-  EXPECT_TRUE(f.errored);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:4: expected identifier for function declaration");
+    auto p = parser("fn ()");
+    auto f = p->function_header();
+    EXPECT_FALSE(f.matched);
+    EXPECT_TRUE(f.errored);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:4: expected identifier for function declaration");
 }
 
 TEST_F(ParserImplTest, FunctionHeader_InvalidIdent) {
-  auto p = parser("fn 133main() -> i32");
-  auto f = p->function_header();
-  EXPECT_FALSE(f.matched);
-  EXPECT_TRUE(f.errored);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:4: expected identifier for function declaration");
+    auto p = parser("fn 133main() -> i32");
+    auto f = p->function_header();
+    EXPECT_FALSE(f.matched);
+    EXPECT_TRUE(f.errored);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:4: expected identifier for function declaration");
 }
 
 TEST_F(ParserImplTest, FunctionHeader_MissingParenLeft) {
-  auto p = parser("fn main) -> i32");
-  auto f = p->function_header();
-  EXPECT_FALSE(f.matched);
-  EXPECT_TRUE(f.errored);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:8: expected '(' for function declaration");
+    auto p = parser("fn main) -> i32");
+    auto f = p->function_header();
+    EXPECT_FALSE(f.matched);
+    EXPECT_TRUE(f.errored);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:8: expected '(' for function declaration");
 }
 
 TEST_F(ParserImplTest, FunctionHeader_InvalidParamList) {
-  auto p = parser("fn main(a :i32, ,) -> i32");
-  auto f = p->function_header();
-  EXPECT_FALSE(f.matched);
-  EXPECT_TRUE(f.errored);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:17: expected ')' for function declaration");
+    auto p = parser("fn main(a :i32, ,) -> i32");
+    auto f = p->function_header();
+    EXPECT_FALSE(f.matched);
+    EXPECT_TRUE(f.errored);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:17: expected ')' for function declaration");
 }
 
 TEST_F(ParserImplTest, FunctionHeader_MissingParenRight) {
-  auto p = parser("fn main( -> i32");
-  auto f = p->function_header();
-  EXPECT_FALSE(f.matched);
-  EXPECT_TRUE(f.errored);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:10: expected ')' for function declaration");
+    auto p = parser("fn main( -> i32");
+    auto f = p->function_header();
+    EXPECT_FALSE(f.matched);
+    EXPECT_TRUE(f.errored);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:10: expected ')' for function declaration");
 }
 
 TEST_F(ParserImplTest, FunctionHeader_MissingReturnType) {
-  auto p = parser("fn main() ->");
-  auto f = p->function_header();
-  EXPECT_FALSE(f.matched);
-  EXPECT_TRUE(f.errored);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:13: unable to determine function return type");
+    auto p = parser("fn main() ->");
+    auto f = p->function_header();
+    EXPECT_FALSE(f.matched);
+    EXPECT_TRUE(f.errored);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:13: unable to determine function return type");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_global_constant_decl_test.cc b/src/tint/reader/wgsl/parser_impl_global_constant_decl_test.cc
index bbf5323..7a5bb45 100644
--- a/src/tint/reader/wgsl/parser_impl_global_constant_decl_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_global_constant_decl_test.cc
@@ -19,173 +19,171 @@
 namespace {
 
 TEST_F(ParserImplTest, GlobalConstantDecl) {
-  auto p = parser("let a : f32 = 1.");
-  auto attrs = p->attribute_list();
-  EXPECT_FALSE(attrs.errored);
-  EXPECT_FALSE(attrs.matched);
-  auto e = p->global_constant_decl(attrs.value);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("let a : f32 = 1.");
+    auto attrs = p->attribute_list();
+    EXPECT_FALSE(attrs.errored);
+    EXPECT_FALSE(attrs.matched);
+    auto e = p->global_constant_decl(attrs.value);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    ASSERT_NE(e.value, nullptr);
 
-  EXPECT_TRUE(e->is_const);
-  EXPECT_FALSE(e->is_overridable);
-  EXPECT_EQ(e->symbol, p->builder().Symbols().Get("a"));
-  ASSERT_NE(e->type, nullptr);
-  EXPECT_TRUE(e->type->Is<ast::F32>());
+    EXPECT_TRUE(e->is_const);
+    EXPECT_FALSE(e->is_overridable);
+    EXPECT_EQ(e->symbol, p->builder().Symbols().Get("a"));
+    ASSERT_NE(e->type, nullptr);
+    EXPECT_TRUE(e->type->Is<ast::F32>());
 
-  EXPECT_EQ(e->source.range.begin.line, 1u);
-  EXPECT_EQ(e->source.range.begin.column, 5u);
-  EXPECT_EQ(e->source.range.end.line, 1u);
-  EXPECT_EQ(e->source.range.end.column, 6u);
+    EXPECT_EQ(e->source.range.begin.line, 1u);
+    EXPECT_EQ(e->source.range.begin.column, 5u);
+    EXPECT_EQ(e->source.range.end.line, 1u);
+    EXPECT_EQ(e->source.range.end.column, 6u);
 
-  ASSERT_NE(e->constructor, nullptr);
-  EXPECT_TRUE(e->constructor->Is<ast::LiteralExpression>());
+    ASSERT_NE(e->constructor, nullptr);
+    EXPECT_TRUE(e->constructor->Is<ast::LiteralExpression>());
 }
 
 TEST_F(ParserImplTest, GlobalConstantDecl_Inferred) {
-  auto p = parser("let a = 1.");
-  auto attrs = p->attribute_list();
-  EXPECT_FALSE(attrs.errored);
-  EXPECT_FALSE(attrs.matched);
-  auto e = p->global_constant_decl(attrs.value);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("let a = 1.");
+    auto attrs = p->attribute_list();
+    EXPECT_FALSE(attrs.errored);
+    EXPECT_FALSE(attrs.matched);
+    auto e = p->global_constant_decl(attrs.value);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    ASSERT_NE(e.value, nullptr);
 
-  EXPECT_TRUE(e->is_const);
-  EXPECT_FALSE(e->is_overridable);
-  EXPECT_EQ(e->symbol, p->builder().Symbols().Get("a"));
-  EXPECT_EQ(e->type, nullptr);
+    EXPECT_TRUE(e->is_const);
+    EXPECT_FALSE(e->is_overridable);
+    EXPECT_EQ(e->symbol, p->builder().Symbols().Get("a"));
+    EXPECT_EQ(e->type, nullptr);
 
-  EXPECT_EQ(e->source.range.begin.line, 1u);
-  EXPECT_EQ(e->source.range.begin.column, 5u);
-  EXPECT_EQ(e->source.range.end.line, 1u);
-  EXPECT_EQ(e->source.range.end.column, 6u);
+    EXPECT_EQ(e->source.range.begin.line, 1u);
+    EXPECT_EQ(e->source.range.begin.column, 5u);
+    EXPECT_EQ(e->source.range.end.line, 1u);
+    EXPECT_EQ(e->source.range.end.column, 6u);
 
-  ASSERT_NE(e->constructor, nullptr);
-  EXPECT_TRUE(e->constructor->Is<ast::LiteralExpression>());
+    ASSERT_NE(e->constructor, nullptr);
+    EXPECT_TRUE(e->constructor->Is<ast::LiteralExpression>());
 }
 
 TEST_F(ParserImplTest, GlobalConstantDecl_InvalidExpression) {
-  auto p = parser("let a : f32 = if (a) {}");
-  auto attrs = p->attribute_list();
-  EXPECT_FALSE(attrs.errored);
-  EXPECT_FALSE(attrs.matched);
-  auto e = p->global_constant_decl(attrs.value);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(e.errored);
-  EXPECT_FALSE(e.matched);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:15: invalid type for const_expr");
+    auto p = parser("let a : f32 = if (a) {}");
+    auto attrs = p->attribute_list();
+    EXPECT_FALSE(attrs.errored);
+    EXPECT_FALSE(attrs.matched);
+    auto e = p->global_constant_decl(attrs.value);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(e.errored);
+    EXPECT_FALSE(e.matched);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:15: invalid type for const_expr");
 }
 
 TEST_F(ParserImplTest, GlobalConstantDecl_MissingExpression) {
-  auto p = parser("let a : f32 =");
-  auto attrs = p->attribute_list();
-  EXPECT_FALSE(attrs.errored);
-  EXPECT_FALSE(attrs.matched);
-  auto e = p->global_constant_decl(attrs.value);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(e.errored);
-  EXPECT_FALSE(e.matched);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:14: unable to parse const_expr");
+    auto p = parser("let a : f32 =");
+    auto attrs = p->attribute_list();
+    EXPECT_FALSE(attrs.errored);
+    EXPECT_FALSE(attrs.matched);
+    auto e = p->global_constant_decl(attrs.value);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(e.errored);
+    EXPECT_FALSE(e.matched);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:14: unable to parse const_expr");
 }
 
 TEST_F(ParserImplTest, GlobalConstantDec_Override_WithId) {
-  auto p = parser("@id(7) override a : f32 = 1.");
-  auto attrs = p->attribute_list();
-  EXPECT_FALSE(attrs.errored);
-  EXPECT_TRUE(attrs.matched);
+    auto p = parser("@id(7) override a : f32 = 1.");
+    auto attrs = p->attribute_list();
+    EXPECT_FALSE(attrs.errored);
+    EXPECT_TRUE(attrs.matched);
 
-  auto e = p->global_constant_decl(attrs.value);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  ASSERT_NE(e.value, nullptr);
+    auto e = p->global_constant_decl(attrs.value);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    ASSERT_NE(e.value, nullptr);
 
-  EXPECT_TRUE(e->is_const);
-  EXPECT_TRUE(e->is_overridable);
-  EXPECT_EQ(e->symbol, p->builder().Symbols().Get("a"));
-  ASSERT_NE(e->type, nullptr);
-  EXPECT_TRUE(e->type->Is<ast::F32>());
+    EXPECT_TRUE(e->is_const);
+    EXPECT_TRUE(e->is_overridable);
+    EXPECT_EQ(e->symbol, p->builder().Symbols().Get("a"));
+    ASSERT_NE(e->type, nullptr);
+    EXPECT_TRUE(e->type->Is<ast::F32>());
 
-  EXPECT_EQ(e->source.range.begin.line, 1u);
-  EXPECT_EQ(e->source.range.begin.column, 17u);
-  EXPECT_EQ(e->source.range.end.line, 1u);
-  EXPECT_EQ(e->source.range.end.column, 18u);
+    EXPECT_EQ(e->source.range.begin.line, 1u);
+    EXPECT_EQ(e->source.range.begin.column, 17u);
+    EXPECT_EQ(e->source.range.end.line, 1u);
+    EXPECT_EQ(e->source.range.end.column, 18u);
 
-  ASSERT_NE(e->constructor, nullptr);
-  EXPECT_TRUE(e->constructor->Is<ast::LiteralExpression>());
+    ASSERT_NE(e->constructor, nullptr);
+    EXPECT_TRUE(e->constructor->Is<ast::LiteralExpression>());
 
-  auto* override_attr =
-      ast::GetAttribute<ast::IdAttribute>(e.value->attributes);
-  ASSERT_NE(override_attr, nullptr);
-  EXPECT_EQ(override_attr->value, 7u);
+    auto* override_attr = ast::GetAttribute<ast::IdAttribute>(e.value->attributes);
+    ASSERT_NE(override_attr, nullptr);
+    EXPECT_EQ(override_attr->value, 7u);
 }
 
 TEST_F(ParserImplTest, GlobalConstantDec_Override_WithoutId) {
-  auto p = parser("override a : f32 = 1.");
-  auto attrs = p->attribute_list();
-  EXPECT_FALSE(attrs.errored);
-  EXPECT_FALSE(attrs.matched);
+    auto p = parser("override a : f32 = 1.");
+    auto attrs = p->attribute_list();
+    EXPECT_FALSE(attrs.errored);
+    EXPECT_FALSE(attrs.matched);
 
-  auto e = p->global_constant_decl(attrs.value);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  ASSERT_NE(e.value, nullptr);
+    auto e = p->global_constant_decl(attrs.value);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    ASSERT_NE(e.value, nullptr);
 
-  EXPECT_TRUE(e->is_const);
-  EXPECT_TRUE(e->is_overridable);
-  EXPECT_EQ(e->symbol, p->builder().Symbols().Get("a"));
-  ASSERT_NE(e->type, nullptr);
-  EXPECT_TRUE(e->type->Is<ast::F32>());
+    EXPECT_TRUE(e->is_const);
+    EXPECT_TRUE(e->is_overridable);
+    EXPECT_EQ(e->symbol, p->builder().Symbols().Get("a"));
+    ASSERT_NE(e->type, nullptr);
+    EXPECT_TRUE(e->type->Is<ast::F32>());
 
-  EXPECT_EQ(e->source.range.begin.line, 1u);
-  EXPECT_EQ(e->source.range.begin.column, 10u);
-  EXPECT_EQ(e->source.range.end.line, 1u);
-  EXPECT_EQ(e->source.range.end.column, 11u);
+    EXPECT_EQ(e->source.range.begin.line, 1u);
+    EXPECT_EQ(e->source.range.begin.column, 10u);
+    EXPECT_EQ(e->source.range.end.line, 1u);
+    EXPECT_EQ(e->source.range.end.column, 11u);
 
-  ASSERT_NE(e->constructor, nullptr);
-  EXPECT_TRUE(e->constructor->Is<ast::LiteralExpression>());
+    ASSERT_NE(e->constructor, nullptr);
+    EXPECT_TRUE(e->constructor->Is<ast::LiteralExpression>());
 
-  auto* id_attr = ast::GetAttribute<ast::IdAttribute>(e.value->attributes);
-  ASSERT_EQ(id_attr, nullptr);
+    auto* id_attr = ast::GetAttribute<ast::IdAttribute>(e.value->attributes);
+    ASSERT_EQ(id_attr, nullptr);
 }
 
 TEST_F(ParserImplTest, GlobalConstantDec_Override_MissingId) {
-  auto p = parser("@id() override a : f32 = 1.");
-  auto attrs = p->attribute_list();
-  EXPECT_TRUE(attrs.errored);
-  EXPECT_FALSE(attrs.matched);
+    auto p = parser("@id() override a : f32 = 1.");
+    auto attrs = p->attribute_list();
+    EXPECT_TRUE(attrs.errored);
+    EXPECT_FALSE(attrs.matched);
 
-  auto e = p->global_constant_decl(attrs.value);
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  ASSERT_NE(e.value, nullptr);
+    auto e = p->global_constant_decl(attrs.value);
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    ASSERT_NE(e.value, nullptr);
 
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(),
-            "1:5: expected signed integer literal for id attribute");
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:5: expected signed integer literal for id attribute");
 }
 
 TEST_F(ParserImplTest, GlobalConstantDec_Override_InvalidId) {
-  auto p = parser("@id(-7) override a : f32 = 1.");
-  auto attrs = p->attribute_list();
-  EXPECT_TRUE(attrs.errored);
-  EXPECT_FALSE(attrs.matched);
+    auto p = parser("@id(-7) override a : f32 = 1.");
+    auto attrs = p->attribute_list();
+    EXPECT_TRUE(attrs.errored);
+    EXPECT_FALSE(attrs.matched);
 
-  auto e = p->global_constant_decl(attrs.value);
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  ASSERT_NE(e.value, nullptr);
+    auto e = p->global_constant_decl(attrs.value);
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    ASSERT_NE(e.value, nullptr);
 
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:5: id attribute must be positive");
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:5: id attribute must be positive");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_global_decl_test.cc b/src/tint/reader/wgsl/parser_impl_global_decl_test.cc
index 562a2de..e2c7d7a 100644
--- a/src/tint/reader/wgsl/parser_impl_global_decl_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_global_decl_test.cc
@@ -18,157 +18,163 @@
 namespace {
 
 TEST_F(ParserImplTest, GlobalDecl_Semicolon) {
-  auto p = parser(";");
-  p->expect_global_decl();
-  ASSERT_FALSE(p->has_error()) << p->error();
+    auto p = parser(";");
+    p->global_decl();
+    ASSERT_FALSE(p->has_error()) << p->error();
 }
 
 TEST_F(ParserImplTest, GlobalDecl_GlobalVariable) {
-  auto p = parser("var<private> a : vec2<i32> = vec2<i32>(1, 2);");
-  p->expect_global_decl();
-  ASSERT_FALSE(p->has_error()) << p->error();
+    auto p = parser("var<private> a : vec2<i32> = vec2<i32>(1, 2);");
+    p->global_decl();
+    ASSERT_FALSE(p->has_error()) << p->error();
 
-  auto program = p->program();
-  ASSERT_EQ(program.AST().GlobalVariables().size(), 1u);
+    auto program = p->program();
+    ASSERT_EQ(program.AST().GlobalVariables().size(), 1u);
 
-  auto* v = program.AST().GlobalVariables()[0];
-  EXPECT_EQ(v->symbol, program.Symbols().Get("a"));
+    auto* v = program.AST().GlobalVariables()[0];
+    EXPECT_EQ(v->symbol, program.Symbols().Get("a"));
 }
 
 TEST_F(ParserImplTest, GlobalDecl_GlobalVariable_Inferred_Invalid) {
-  auto p = parser("var<private> a = vec2<i32>(1, 2);");
-  p->expect_global_decl();
-  ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:16: expected ':' for variable declaration");
+    auto p = parser("var<private> a = vec2<i32>(1, 2);");
+    p->global_decl();
+    ASSERT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:16: expected ':' for variable declaration");
 }
 
 TEST_F(ParserImplTest, GlobalDecl_GlobalVariable_MissingSemicolon) {
-  auto p = parser("var<private> a : vec2<i32>");
-  p->expect_global_decl();
-  ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:27: expected ';' for variable declaration");
+    auto p = parser("var<private> a : vec2<i32>");
+    p->global_decl();
+    ASSERT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:27: expected ';' for variable declaration");
 }
 
 TEST_F(ParserImplTest, GlobalDecl_GlobalConstant) {
-  auto p = parser("let a : i32 = 2;");
-  p->expect_global_decl();
-  ASSERT_FALSE(p->has_error()) << p->error();
+    auto p = parser("let a : i32 = 2;");
+    p->global_decl();
+    ASSERT_FALSE(p->has_error()) << p->error();
 
-  auto program = p->program();
-  ASSERT_EQ(program.AST().GlobalVariables().size(), 1u);
+    auto program = p->program();
+    ASSERT_EQ(program.AST().GlobalVariables().size(), 1u);
 
-  auto* v = program.AST().GlobalVariables()[0];
-  EXPECT_EQ(v->symbol, program.Symbols().Get("a"));
+    auto* v = program.AST().GlobalVariables()[0];
+    EXPECT_EQ(v->symbol, program.Symbols().Get("a"));
 }
 
 TEST_F(ParserImplTest, GlobalDecl_GlobalConstant_Invalid) {
-  auto p = parser("let a : vec2<i32> 1.0;");
-  p->expect_global_decl();
-  ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:19: expected ';' for let declaration");
+    auto p = parser("let a : vec2<i32> 1.0;");
+    p->global_decl();
+    ASSERT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:19: expected ';' for let declaration");
 }
 
 TEST_F(ParserImplTest, GlobalDecl_GlobalConstant_MissingSemicolon) {
-  auto p = parser("let a : vec2<i32> = vec2<i32>(1, 2)");
-  p->expect_global_decl();
-  ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:36: expected ';' for let declaration");
+    auto p = parser("let a : vec2<i32> = vec2<i32>(1, 2)");
+    p->global_decl();
+    ASSERT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:36: expected ';' for let declaration");
 }
 
 TEST_F(ParserImplTest, GlobalDecl_TypeAlias) {
-  auto p = parser("type A = i32;");
-  p->expect_global_decl();
-  ASSERT_FALSE(p->has_error()) << p->error();
+    auto p = parser("type A = i32;");
+    p->global_decl();
+    ASSERT_FALSE(p->has_error()) << p->error();
 
-  auto program = p->program();
-  ASSERT_EQ(program.AST().TypeDecls().size(), 1u);
-  ASSERT_TRUE(program.AST().TypeDecls()[0]->Is<ast::Alias>());
-  EXPECT_EQ(program.Symbols().NameFor(
-                program.AST().TypeDecls()[0]->As<ast::Alias>()->name),
-            "A");
+    auto program = p->program();
+    ASSERT_EQ(program.AST().TypeDecls().size(), 1u);
+    ASSERT_TRUE(program.AST().TypeDecls()[0]->Is<ast::Alias>());
+    EXPECT_EQ(program.Symbols().NameFor(program.AST().TypeDecls()[0]->As<ast::Alias>()->name), "A");
 }
 
 TEST_F(ParserImplTest, GlobalDecl_TypeAlias_StructIdent) {
-  auto p = parser(R"(struct A {
+    auto p = parser(R"(struct A {
   a : f32,
 }
 type B = A;)");
-  p->expect_global_decl();
-  p->expect_global_decl();
-  ASSERT_FALSE(p->has_error()) << p->error();
+    p->global_decl();
+    p->global_decl();
+    ASSERT_FALSE(p->has_error()) << p->error();
 
-  auto program = p->program();
-  ASSERT_EQ(program.AST().TypeDecls().size(), 2u);
-  ASSERT_TRUE(program.AST().TypeDecls()[0]->Is<ast::Struct>());
-  auto* str = program.AST().TypeDecls()[0]->As<ast::Struct>();
-  EXPECT_EQ(str->name, program.Symbols().Get("A"));
+    auto program = p->program();
+    ASSERT_EQ(program.AST().TypeDecls().size(), 2u);
+    ASSERT_TRUE(program.AST().TypeDecls()[0]->Is<ast::Struct>());
+    auto* str = program.AST().TypeDecls()[0]->As<ast::Struct>();
+    EXPECT_EQ(str->name, program.Symbols().Get("A"));
 
-  ASSERT_TRUE(program.AST().TypeDecls()[1]->Is<ast::Alias>());
-  auto* alias = program.AST().TypeDecls()[1]->As<ast::Alias>();
-  EXPECT_EQ(alias->name, program.Symbols().Get("B"));
-  auto* tn = alias->type->As<ast::TypeName>();
-  EXPECT_NE(tn, nullptr);
-  EXPECT_EQ(tn->name, str->name);
+    ASSERT_TRUE(program.AST().TypeDecls()[1]->Is<ast::Alias>());
+    auto* alias = program.AST().TypeDecls()[1]->As<ast::Alias>();
+    EXPECT_EQ(alias->name, program.Symbols().Get("B"));
+    auto* tn = alias->type->As<ast::TypeName>();
+    EXPECT_NE(tn, nullptr);
+    EXPECT_EQ(tn->name, str->name);
 }
 
 TEST_F(ParserImplTest, GlobalDecl_TypeAlias_MissingSemicolon) {
-  auto p = parser("type A = i32");
-  p->expect_global_decl();
-  ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:13: expected ';' for type alias");
+    auto p = parser("type A = i32");
+    p->global_decl();
+    ASSERT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:13: expected ';' for type alias");
 }
 
 TEST_F(ParserImplTest, GlobalDecl_Function) {
-  auto p = parser("fn main() { return; }");
-  p->expect_global_decl();
-  ASSERT_FALSE(p->has_error()) << p->error();
+    auto p = parser("fn main() { return; }");
+    p->global_decl();
+    ASSERT_FALSE(p->has_error()) << p->error();
 
-  auto program = p->program();
-  ASSERT_EQ(program.AST().Functions().size(), 1u);
-  EXPECT_EQ(program.Symbols().NameFor(program.AST().Functions()[0]->symbol),
-            "main");
+    auto program = p->program();
+    ASSERT_EQ(program.AST().Functions().size(), 1u);
+    EXPECT_EQ(program.Symbols().NameFor(program.AST().Functions()[0]->symbol), "main");
 }
 
 TEST_F(ParserImplTest, GlobalDecl_Function_WithAttribute) {
-  auto p = parser("@workgroup_size(2) fn main() { return; }");
-  p->expect_global_decl();
-  ASSERT_FALSE(p->has_error()) << p->error();
+    auto p = parser("@workgroup_size(2) fn main() { return; }");
+    p->global_decl();
+    ASSERT_FALSE(p->has_error()) << p->error();
 
-  auto program = p->program();
-  ASSERT_EQ(program.AST().Functions().size(), 1u);
-  EXPECT_EQ(program.Symbols().NameFor(program.AST().Functions()[0]->symbol),
-            "main");
+    auto program = p->program();
+    ASSERT_EQ(program.AST().Functions().size(), 1u);
+    EXPECT_EQ(program.Symbols().NameFor(program.AST().Functions()[0]->symbol), "main");
 }
 
 TEST_F(ParserImplTest, GlobalDecl_Function_Invalid) {
-  auto p = parser("fn main() -> { return; }");
-  p->expect_global_decl();
-  ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:14: unable to determine function return type");
+    auto p = parser("fn main() -> { return; }");
+    p->global_decl();
+    ASSERT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:14: unable to determine function return type");
 }
 
 TEST_F(ParserImplTest, GlobalDecl_ParsesStruct) {
-  auto p = parser("struct A { b: i32, c: f32}");
-  p->expect_global_decl();
-  ASSERT_FALSE(p->has_error()) << p->error();
+    auto p = parser("struct A { b: i32, c: f32}");
+    p->global_decl();
+    ASSERT_FALSE(p->has_error()) << p->error();
 
-  auto program = p->program();
-  ASSERT_EQ(program.AST().TypeDecls().size(), 1u);
+    auto program = p->program();
+    ASSERT_EQ(program.AST().TypeDecls().size(), 1u);
 
-  auto* t = program.AST().TypeDecls()[0];
-  ASSERT_NE(t, nullptr);
-  ASSERT_TRUE(t->Is<ast::Struct>());
+    auto* t = program.AST().TypeDecls()[0];
+    ASSERT_NE(t, nullptr);
+    ASSERT_TRUE(t->Is<ast::Struct>());
 
-  auto* str = t->As<ast::Struct>();
-  EXPECT_EQ(str->name, program.Symbols().Get("A"));
-  EXPECT_EQ(str->members.size(), 2u);
+    auto* str = t->As<ast::Struct>();
+    EXPECT_EQ(str->name, program.Symbols().Get("A"));
+    EXPECT_EQ(str->members.size(), 2u);
 }
 
 TEST_F(ParserImplTest, GlobalDecl_Struct_Invalid) {
-  auto p = parser("A {}");
-  p->expect_global_decl();
-  ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:1: unexpected token");
+    {
+        auto p = parser("A {}");
+        auto decl = p->global_decl();
+        // global_decl will result in a no match.
+        ASSERT_FALSE(p->has_error()) << p->error();
+        ASSERT_TRUE(!decl.matched && !decl.errored);
+    }
+    {
+        auto p = parser("A {}");
+        p->translation_unit();
+        // translation_unit will result in a general error.
+        ASSERT_TRUE(p->has_error());
+        EXPECT_EQ(p->error(), "1:1: unexpected token");
+    }
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_global_variable_decl_test.cc b/src/tint/reader/wgsl/parser_impl_global_variable_decl_test.cc
index 6dd8f74..57f90b9 100644
--- a/src/tint/reader/wgsl/parser_impl_global_variable_decl_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_global_variable_decl_test.cc
@@ -18,151 +18,150 @@
 namespace {
 
 TEST_F(ParserImplTest, GlobalVariableDecl_WithoutConstructor) {
-  auto p = parser("var<private> a : f32");
-  auto attrs = p->attribute_list();
-  EXPECT_FALSE(attrs.errored);
-  EXPECT_FALSE(attrs.matched);
-  auto e = p->global_variable_decl(attrs.value);
-  ASSERT_FALSE(p->has_error()) << p->error();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("var<private> a : f32");
+    auto attrs = p->attribute_list();
+    EXPECT_FALSE(attrs.errored);
+    EXPECT_FALSE(attrs.matched);
+    auto e = p->global_variable_decl(attrs.value);
+    ASSERT_FALSE(p->has_error()) << p->error();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    ASSERT_NE(e.value, nullptr);
 
-  EXPECT_EQ(e->symbol, p->builder().Symbols().Get("a"));
-  EXPECT_TRUE(e->type->Is<ast::F32>());
-  EXPECT_EQ(e->declared_storage_class, ast::StorageClass::kPrivate);
+    EXPECT_EQ(e->symbol, p->builder().Symbols().Get("a"));
+    EXPECT_TRUE(e->type->Is<ast::F32>());
+    EXPECT_EQ(e->declared_storage_class, ast::StorageClass::kPrivate);
 
-  EXPECT_EQ(e->source.range.begin.line, 1u);
-  EXPECT_EQ(e->source.range.begin.column, 14u);
-  EXPECT_EQ(e->source.range.end.line, 1u);
-  EXPECT_EQ(e->source.range.end.column, 15u);
+    EXPECT_EQ(e->source.range.begin.line, 1u);
+    EXPECT_EQ(e->source.range.begin.column, 14u);
+    EXPECT_EQ(e->source.range.end.line, 1u);
+    EXPECT_EQ(e->source.range.end.column, 15u);
 
-  ASSERT_EQ(e->constructor, nullptr);
+    ASSERT_EQ(e->constructor, nullptr);
 }
 
 TEST_F(ParserImplTest, GlobalVariableDecl_WithConstructor) {
-  auto p = parser("var<private> a : f32 = 1.");
-  auto attrs = p->attribute_list();
-  EXPECT_FALSE(attrs.errored);
-  EXPECT_FALSE(attrs.matched);
-  auto e = p->global_variable_decl(attrs.value);
-  ASSERT_FALSE(p->has_error()) << p->error();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("var<private> a : f32 = 1.");
+    auto attrs = p->attribute_list();
+    EXPECT_FALSE(attrs.errored);
+    EXPECT_FALSE(attrs.matched);
+    auto e = p->global_variable_decl(attrs.value);
+    ASSERT_FALSE(p->has_error()) << p->error();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    ASSERT_NE(e.value, nullptr);
 
-  EXPECT_EQ(e->symbol, p->builder().Symbols().Get("a"));
-  EXPECT_TRUE(e->type->Is<ast::F32>());
-  EXPECT_EQ(e->declared_storage_class, ast::StorageClass::kPrivate);
+    EXPECT_EQ(e->symbol, p->builder().Symbols().Get("a"));
+    EXPECT_TRUE(e->type->Is<ast::F32>());
+    EXPECT_EQ(e->declared_storage_class, ast::StorageClass::kPrivate);
 
-  EXPECT_EQ(e->source.range.begin.line, 1u);
-  EXPECT_EQ(e->source.range.begin.column, 14u);
-  EXPECT_EQ(e->source.range.end.line, 1u);
-  EXPECT_EQ(e->source.range.end.column, 15u);
+    EXPECT_EQ(e->source.range.begin.line, 1u);
+    EXPECT_EQ(e->source.range.begin.column, 14u);
+    EXPECT_EQ(e->source.range.end.line, 1u);
+    EXPECT_EQ(e->source.range.end.column, 15u);
 
-  ASSERT_NE(e->constructor, nullptr);
-  ASSERT_TRUE(e->constructor->Is<ast::FloatLiteralExpression>());
+    ASSERT_NE(e->constructor, nullptr);
+    ASSERT_TRUE(e->constructor->Is<ast::FloatLiteralExpression>());
 }
 
 TEST_F(ParserImplTest, GlobalVariableDecl_WithAttribute) {
-  auto p = parser("@binding(2) @group(1) var<uniform> a : f32");
-  auto attrs = p->attribute_list();
-  EXPECT_FALSE(attrs.errored);
-  EXPECT_TRUE(attrs.matched);
-  auto e = p->global_variable_decl(attrs.value);
-  ASSERT_FALSE(p->has_error()) << p->error();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("@binding(2) @group(1) var<uniform> a : f32");
+    auto attrs = p->attribute_list();
+    EXPECT_FALSE(attrs.errored);
+    EXPECT_TRUE(attrs.matched);
+    auto e = p->global_variable_decl(attrs.value);
+    ASSERT_FALSE(p->has_error()) << p->error();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    ASSERT_NE(e.value, nullptr);
 
-  EXPECT_EQ(e->symbol, p->builder().Symbols().Get("a"));
-  ASSERT_NE(e->type, nullptr);
-  EXPECT_TRUE(e->type->Is<ast::F32>());
-  EXPECT_EQ(e->declared_storage_class, ast::StorageClass::kUniform);
+    EXPECT_EQ(e->symbol, p->builder().Symbols().Get("a"));
+    ASSERT_NE(e->type, nullptr);
+    EXPECT_TRUE(e->type->Is<ast::F32>());
+    EXPECT_EQ(e->declared_storage_class, ast::StorageClass::kUniform);
 
-  EXPECT_EQ(e->source.range.begin.line, 1u);
-  EXPECT_EQ(e->source.range.begin.column, 36u);
-  EXPECT_EQ(e->source.range.end.line, 1u);
-  EXPECT_EQ(e->source.range.end.column, 37u);
+    EXPECT_EQ(e->source.range.begin.line, 1u);
+    EXPECT_EQ(e->source.range.begin.column, 36u);
+    EXPECT_EQ(e->source.range.end.line, 1u);
+    EXPECT_EQ(e->source.range.end.column, 37u);
 
-  ASSERT_EQ(e->constructor, nullptr);
+    ASSERT_EQ(e->constructor, nullptr);
 
-  auto& attributes = e->attributes;
-  ASSERT_EQ(attributes.size(), 2u);
-  ASSERT_TRUE(attributes[0]->Is<ast::BindingAttribute>());
-  ASSERT_TRUE(attributes[1]->Is<ast::GroupAttribute>());
+    auto& attributes = e->attributes;
+    ASSERT_EQ(attributes.size(), 2u);
+    ASSERT_TRUE(attributes[0]->Is<ast::BindingAttribute>());
+    ASSERT_TRUE(attributes[1]->Is<ast::GroupAttribute>());
 }
 
 TEST_F(ParserImplTest, GlobalVariableDecl_WithAttribute_MulitpleGroups) {
-  auto p = parser("@binding(2) @group(1) var<uniform> a : f32");
-  auto attrs = p->attribute_list();
-  EXPECT_FALSE(attrs.errored);
-  EXPECT_TRUE(attrs.matched);
+    auto p = parser("@binding(2) @group(1) var<uniform> a : f32");
+    auto attrs = p->attribute_list();
+    EXPECT_FALSE(attrs.errored);
+    EXPECT_TRUE(attrs.matched);
 
-  auto e = p->global_variable_decl(attrs.value);
-  ASSERT_FALSE(p->has_error()) << p->error();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  ASSERT_NE(e.value, nullptr);
+    auto e = p->global_variable_decl(attrs.value);
+    ASSERT_FALSE(p->has_error()) << p->error();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    ASSERT_NE(e.value, nullptr);
 
-  EXPECT_EQ(e->symbol, p->builder().Symbols().Get("a"));
-  ASSERT_NE(e->type, nullptr);
-  EXPECT_TRUE(e->type->Is<ast::F32>());
-  EXPECT_EQ(e->declared_storage_class, ast::StorageClass::kUniform);
+    EXPECT_EQ(e->symbol, p->builder().Symbols().Get("a"));
+    ASSERT_NE(e->type, nullptr);
+    EXPECT_TRUE(e->type->Is<ast::F32>());
+    EXPECT_EQ(e->declared_storage_class, ast::StorageClass::kUniform);
 
-  EXPECT_EQ(e->source.range.begin.line, 1u);
-  EXPECT_EQ(e->source.range.begin.column, 36u);
-  EXPECT_EQ(e->source.range.end.line, 1u);
-  EXPECT_EQ(e->source.range.end.column, 37u);
+    EXPECT_EQ(e->source.range.begin.line, 1u);
+    EXPECT_EQ(e->source.range.begin.column, 36u);
+    EXPECT_EQ(e->source.range.end.line, 1u);
+    EXPECT_EQ(e->source.range.end.column, 37u);
 
-  ASSERT_EQ(e->constructor, nullptr);
+    ASSERT_EQ(e->constructor, nullptr);
 
-  auto& attributes = e->attributes;
-  ASSERT_EQ(attributes.size(), 2u);
-  ASSERT_TRUE(attributes[0]->Is<ast::BindingAttribute>());
-  ASSERT_TRUE(attributes[1]->Is<ast::GroupAttribute>());
+    auto& attributes = e->attributes;
+    ASSERT_EQ(attributes.size(), 2u);
+    ASSERT_TRUE(attributes[0]->Is<ast::BindingAttribute>());
+    ASSERT_TRUE(attributes[1]->Is<ast::GroupAttribute>());
 }
 
 TEST_F(ParserImplTest, GlobalVariableDecl_InvalidAttribute) {
-  auto p = parser("@binding() var<uniform> a : f32");
-  auto attrs = p->attribute_list();
-  EXPECT_TRUE(attrs.errored);
-  EXPECT_FALSE(attrs.matched);
+    auto p = parser("@binding() var<uniform> a : f32");
+    auto attrs = p->attribute_list();
+    EXPECT_TRUE(attrs.errored);
+    EXPECT_FALSE(attrs.matched);
 
-  auto e = p->global_variable_decl(attrs.value);
-  EXPECT_FALSE(e.errored);
-  EXPECT_TRUE(e.matched);
-  EXPECT_NE(e.value, nullptr);
+    auto e = p->global_variable_decl(attrs.value);
+    EXPECT_FALSE(e.errored);
+    EXPECT_TRUE(e.matched);
+    EXPECT_NE(e.value, nullptr);
 
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(),
-            "1:10: expected signed integer literal for binding attribute");
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:10: expected signed integer literal for binding attribute");
 }
 
 TEST_F(ParserImplTest, GlobalVariableDecl_InvalidConstExpr) {
-  auto p = parser("var<private> a : f32 = if (a) {}");
-  auto attrs = p->attribute_list();
-  EXPECT_FALSE(attrs.errored);
-  EXPECT_FALSE(attrs.matched);
-  auto e = p->global_variable_decl(attrs.value);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(e.errored);
-  EXPECT_FALSE(e.matched);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:24: invalid type for const_expr");
+    auto p = parser("var<private> a : f32 = if (a) {}");
+    auto attrs = p->attribute_list();
+    EXPECT_FALSE(attrs.errored);
+    EXPECT_FALSE(attrs.matched);
+    auto e = p->global_variable_decl(attrs.value);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(e.errored);
+    EXPECT_FALSE(e.matched);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:24: invalid type for const_expr");
 }
 
 TEST_F(ParserImplTest, GlobalVariableDecl_InvalidVariableDecl) {
-  auto p = parser("var<invalid> a : f32;");
-  auto attrs = p->attribute_list();
-  EXPECT_FALSE(attrs.errored);
-  EXPECT_FALSE(attrs.matched);
-  auto e = p->global_variable_decl(attrs.value);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(e.errored);
-  EXPECT_FALSE(e.matched);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:5: invalid storage class for variable declaration");
+    auto p = parser("var<invalid> a : f32;");
+    auto attrs = p->attribute_list();
+    EXPECT_FALSE(attrs.errored);
+    EXPECT_FALSE(attrs.matched);
+    auto e = p->global_variable_decl(attrs.value);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(e.errored);
+    EXPECT_FALSE(e.matched);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:5: invalid storage class for variable declaration");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_if_stmt_test.cc b/src/tint/reader/wgsl/parser_impl_if_stmt_test.cc
index 18c30e9..b9e5566 100644
--- a/src/tint/reader/wgsl/parser_impl_if_stmt_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_if_stmt_test.cc
@@ -18,124 +18,124 @@
 namespace {
 
 TEST_F(ParserImplTest, IfStmt) {
-  auto p = parser("if a == 4 { a = b; c = d; }");
-  auto e = p->if_stmt();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("if a == 4 { a = b; c = d; }");
+    auto e = p->if_stmt();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e->Is<ast::IfStatement>());
-  ASSERT_NE(e->condition, nullptr);
-  ASSERT_TRUE(e->condition->Is<ast::BinaryExpression>());
-  EXPECT_EQ(e->body->statements.size(), 2u);
-  EXPECT_EQ(e->else_statements.size(), 0u);
+    ASSERT_TRUE(e->Is<ast::IfStatement>());
+    ASSERT_NE(e->condition, nullptr);
+    ASSERT_TRUE(e->condition->Is<ast::BinaryExpression>());
+    EXPECT_EQ(e->body->statements.size(), 2u);
+    EXPECT_EQ(e->else_statement, nullptr);
 }
 
 TEST_F(ParserImplTest, IfStmt_WithElse) {
-  auto p = parser("if a == 4 { a = b; c = d; } else if(c) { d = 2; } else {}");
-  auto e = p->if_stmt();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("if a == 4 { a = b; c = d; } else if(c) { d = 2; } else {}");
+    auto e = p->if_stmt();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e->Is<ast::IfStatement>());
-  ASSERT_NE(e->condition, nullptr);
-  ASSERT_TRUE(e->condition->Is<ast::BinaryExpression>());
-  EXPECT_EQ(e->body->statements.size(), 2u);
+    ASSERT_TRUE(e->Is<ast::IfStatement>());
+    ASSERT_NE(e->condition, nullptr);
+    ASSERT_TRUE(e->condition->Is<ast::BinaryExpression>());
+    EXPECT_EQ(e->body->statements.size(), 2u);
 
-  ASSERT_EQ(e->else_statements.size(), 2u);
-  ASSERT_NE(e->else_statements[0]->condition, nullptr);
-  ASSERT_TRUE(
-      e->else_statements[0]->condition->Is<ast::IdentifierExpression>());
-  EXPECT_EQ(e->else_statements[0]->body->statements.size(), 1u);
+    auto* elseif = As<ast::IfStatement>(e->else_statement);
+    ASSERT_NE(elseif, nullptr);
+    ASSERT_TRUE(elseif->condition->Is<ast::IdentifierExpression>());
+    EXPECT_EQ(elseif->body->statements.size(), 1u);
 
-  ASSERT_EQ(e->else_statements[1]->condition, nullptr);
-  EXPECT_EQ(e->else_statements[1]->body->statements.size(), 0u);
+    auto* el = As<ast::BlockStatement>(elseif->else_statement);
+    ASSERT_NE(el, nullptr);
+    EXPECT_EQ(el->statements.size(), 0u);
 }
 
 TEST_F(ParserImplTest, IfStmt_WithElse_WithParens) {
-  auto p = parser("if(a==4) { a = b; c = d; } else if(c) { d = 2; } else {}");
-  auto e = p->if_stmt();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("if(a==4) { a = b; c = d; } else if(c) { d = 2; } else {}");
+    auto e = p->if_stmt();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e->Is<ast::IfStatement>());
-  ASSERT_NE(e->condition, nullptr);
-  ASSERT_TRUE(e->condition->Is<ast::BinaryExpression>());
-  EXPECT_EQ(e->body->statements.size(), 2u);
+    ASSERT_TRUE(e->Is<ast::IfStatement>());
+    ASSERT_NE(e->condition, nullptr);
+    ASSERT_TRUE(e->condition->Is<ast::BinaryExpression>());
+    EXPECT_EQ(e->body->statements.size(), 2u);
 
-  ASSERT_EQ(e->else_statements.size(), 2u);
-  ASSERT_NE(e->else_statements[0]->condition, nullptr);
-  ASSERT_TRUE(
-      e->else_statements[0]->condition->Is<ast::IdentifierExpression>());
-  EXPECT_EQ(e->else_statements[0]->body->statements.size(), 1u);
+    auto* elseif = As<ast::IfStatement>(e->else_statement);
+    ASSERT_NE(elseif, nullptr);
+    ASSERT_TRUE(elseif->condition->Is<ast::IdentifierExpression>());
+    EXPECT_EQ(elseif->body->statements.size(), 1u);
 
-  ASSERT_EQ(e->else_statements[1]->condition, nullptr);
-  EXPECT_EQ(e->else_statements[1]->body->statements.size(), 0u);
+    auto* el = As<ast::BlockStatement>(elseif->else_statement);
+    ASSERT_NE(el, nullptr);
+    EXPECT_EQ(el->statements.size(), 0u);
 }
 
 TEST_F(ParserImplTest, IfStmt_InvalidCondition) {
-  auto p = parser("if a = 3 {}");
-  auto e = p->if_stmt();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:6: expected '{'");
+    auto p = parser("if a = 3 {}");
+    auto e = p->if_stmt();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:6: expected '{'");
 }
 
 TEST_F(ParserImplTest, IfStmt_MissingCondition) {
-  auto p = parser("if {}");
-  auto e = p->if_stmt();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:4: unable to parse condition expression");
+    auto p = parser("if {}");
+    auto e = p->if_stmt();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:4: unable to parse condition expression");
 }
 
 TEST_F(ParserImplTest, IfStmt_InvalidBody) {
-  auto p = parser("if a { fn main() {}}");
-  auto e = p->if_stmt();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:8: expected '}'");
+    auto p = parser("if a { fn main() {}}");
+    auto e = p->if_stmt();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:8: expected '}'");
 }
 
 TEST_F(ParserImplTest, IfStmt_MissingBody) {
-  auto p = parser("if a");
-  auto e = p->if_stmt();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:5: expected '{'");
+    auto p = parser("if a");
+    auto e = p->if_stmt();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:5: expected '{'");
 }
 
 TEST_F(ParserImplTest, IfStmt_InvalidElseif) {
-  auto p = parser("if a {} else if a { fn main() -> a{}}");
-  auto e = p->if_stmt();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:21: expected '}'");
+    auto p = parser("if a {} else if a { fn main() -> a{}}");
+    auto e = p->if_stmt();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:21: expected '}'");
 }
 
 TEST_F(ParserImplTest, IfStmt_InvalidElse) {
-  auto p = parser("if a {} else { fn main() -> a{}}");
-  auto e = p->if_stmt();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:16: expected '}'");
+    auto p = parser("if a {} else { fn main() -> a{}}");
+    auto e = p->if_stmt();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:16: expected '}'");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_inclusive_or_expression_test.cc b/src/tint/reader/wgsl/parser_impl_inclusive_or_expression_test.cc
index d8b5209..83b9358 100644
--- a/src/tint/reader/wgsl/parser_impl_inclusive_or_expression_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_inclusive_or_expression_test.cc
@@ -18,52 +18,52 @@
 namespace {
 
 TEST_F(ParserImplTest, InclusiveOrExpression_Parses) {
-  auto p = parser("a | true");
-  auto e = p->inclusive_or_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("a | true");
+    auto e = p->inclusive_or_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e->Is<ast::BinaryExpression>());
-  auto* rel = e->As<ast::BinaryExpression>();
-  EXPECT_EQ(ast::BinaryOp::kOr, rel->op);
+    ASSERT_TRUE(e->Is<ast::BinaryExpression>());
+    auto* rel = e->As<ast::BinaryExpression>();
+    EXPECT_EQ(ast::BinaryOp::kOr, rel->op);
 
-  ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
-  auto* ident = rel->lhs->As<ast::IdentifierExpression>();
-  EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
+    ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
+    auto* ident = rel->lhs->As<ast::IdentifierExpression>();
+    EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
-  ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
+    ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
+    ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
 }
 
 TEST_F(ParserImplTest, InclusiveOrExpression_InvalidLHS) {
-  auto p = parser("if (a) {} | true");
-  auto e = p->inclusive_or_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_EQ(e.value, nullptr);
+    auto p = parser("if (a) {} | true");
+    auto e = p->inclusive_or_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_EQ(e.value, nullptr);
 }
 
 TEST_F(ParserImplTest, InclusiveOrExpression_InvalidRHS) {
-  auto p = parser("true | if (a) {}");
-  auto e = p->inclusive_or_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:8: unable to parse right side of | expression");
+    auto p = parser("true | if (a) {}");
+    auto e = p->inclusive_or_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:8: unable to parse right side of | expression");
 }
 
 TEST_F(ParserImplTest, InclusiveOrExpression_NoOr_ReturnsLHS) {
-  auto p = parser("a true");
-  auto e = p->inclusive_or_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::IdentifierExpression>());
+    auto p = parser("a true");
+    auto e = p->inclusive_or_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::IdentifierExpression>());
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_increment_decrement_stmt_test.cc b/src/tint/reader/wgsl/parser_impl_increment_decrement_stmt_test.cc
index 18f69a1..8041735 100644
--- a/src/tint/reader/wgsl/parser_impl_increment_decrement_stmt_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_increment_decrement_stmt_test.cc
@@ -18,114 +18,114 @@
 namespace {
 
 TEST_F(ParserImplTest, IncrementDecrementStmt_Increment) {
-  auto p = parser("a++");
-  auto e = p->assignment_stmt();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("a++");
+    auto e = p->assignment_stmt();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  auto* i = e->As<ast::IncrementDecrementStatement>();
-  ASSERT_NE(i, nullptr);
-  ASSERT_NE(i->lhs, nullptr);
+    auto* i = e->As<ast::IncrementDecrementStatement>();
+    ASSERT_NE(i, nullptr);
+    ASSERT_NE(i->lhs, nullptr);
 
-  ASSERT_TRUE(i->lhs->Is<ast::IdentifierExpression>());
-  auto* ident = i->lhs->As<ast::IdentifierExpression>();
-  EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
+    ASSERT_TRUE(i->lhs->Is<ast::IdentifierExpression>());
+    auto* ident = i->lhs->As<ast::IdentifierExpression>();
+    EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
 
-  EXPECT_TRUE(i->increment);
+    EXPECT_TRUE(i->increment);
 }
 
 TEST_F(ParserImplTest, IncrementDecrementStmt_Decrement) {
-  auto p = parser("a--");
-  auto e = p->assignment_stmt();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("a--");
+    auto e = p->assignment_stmt();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  auto* i = e->As<ast::IncrementDecrementStatement>();
-  ASSERT_NE(i, nullptr);
-  ASSERT_NE(i->lhs, nullptr);
+    auto* i = e->As<ast::IncrementDecrementStatement>();
+    ASSERT_NE(i, nullptr);
+    ASSERT_NE(i->lhs, nullptr);
 
-  ASSERT_TRUE(i->lhs->Is<ast::IdentifierExpression>());
-  auto* ident = i->lhs->As<ast::IdentifierExpression>();
-  EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
+    ASSERT_TRUE(i->lhs->Is<ast::IdentifierExpression>());
+    auto* ident = i->lhs->As<ast::IdentifierExpression>();
+    EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
 
-  EXPECT_FALSE(i->increment);
+    EXPECT_FALSE(i->increment);
 }
 
 TEST_F(ParserImplTest, IncrementDecrementStmt_Parenthesized) {
-  auto p = parser("(a)++");
-  auto e = p->assignment_stmt();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("(a)++");
+    auto e = p->assignment_stmt();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  auto* i = e->As<ast::IncrementDecrementStatement>();
-  ASSERT_NE(i, nullptr);
-  ASSERT_NE(i->lhs, nullptr);
+    auto* i = e->As<ast::IncrementDecrementStatement>();
+    ASSERT_NE(i, nullptr);
+    ASSERT_NE(i->lhs, nullptr);
 
-  ASSERT_TRUE(i->lhs->Is<ast::IdentifierExpression>());
-  auto* ident = i->lhs->As<ast::IdentifierExpression>();
-  EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
+    ASSERT_TRUE(i->lhs->Is<ast::IdentifierExpression>());
+    auto* ident = i->lhs->As<ast::IdentifierExpression>();
+    EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
 
-  EXPECT_TRUE(i->increment);
+    EXPECT_TRUE(i->increment);
 }
 
 TEST_F(ParserImplTest, IncrementDecrementStmt_ToMember) {
-  auto p = parser("a.b.c[2].d++");
-  auto e = p->assignment_stmt();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("a.b.c[2].d++");
+    auto e = p->assignment_stmt();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  auto* i = e->As<ast::IncrementDecrementStatement>();
-  ASSERT_NE(i, nullptr);
-  ASSERT_NE(i->lhs, nullptr);
-  EXPECT_TRUE(i->increment);
+    auto* i = e->As<ast::IncrementDecrementStatement>();
+    ASSERT_NE(i, nullptr);
+    ASSERT_NE(i->lhs, nullptr);
+    EXPECT_TRUE(i->increment);
 
-  ASSERT_TRUE(i->lhs->Is<ast::MemberAccessorExpression>());
-  auto* mem = i->lhs->As<ast::MemberAccessorExpression>();
+    ASSERT_TRUE(i->lhs->Is<ast::MemberAccessorExpression>());
+    auto* mem = i->lhs->As<ast::MemberAccessorExpression>();
 
-  ASSERT_TRUE(mem->member->Is<ast::IdentifierExpression>());
-  auto* ident = mem->member->As<ast::IdentifierExpression>();
-  EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("d"));
+    ASSERT_TRUE(mem->member->Is<ast::IdentifierExpression>());
+    auto* ident = mem->member->As<ast::IdentifierExpression>();
+    EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("d"));
 
-  ASSERT_TRUE(mem->structure->Is<ast::IndexAccessorExpression>());
-  auto* idx = mem->structure->As<ast::IndexAccessorExpression>();
+    ASSERT_TRUE(mem->structure->Is<ast::IndexAccessorExpression>());
+    auto* idx = mem->structure->As<ast::IndexAccessorExpression>();
 
-  ASSERT_NE(idx->index, nullptr);
-  ASSERT_TRUE(idx->index->Is<ast::SintLiteralExpression>());
-  EXPECT_EQ(idx->index->As<ast::SintLiteralExpression>()->value, 2);
+    ASSERT_NE(idx->index, nullptr);
+    ASSERT_TRUE(idx->index->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(idx->index->As<ast::IntLiteralExpression>()->value, 2);
 
-  ASSERT_TRUE(idx->object->Is<ast::MemberAccessorExpression>());
-  mem = idx->object->As<ast::MemberAccessorExpression>();
-  ASSERT_TRUE(mem->member->Is<ast::IdentifierExpression>());
-  ident = mem->member->As<ast::IdentifierExpression>();
-  EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("c"));
+    ASSERT_TRUE(idx->object->Is<ast::MemberAccessorExpression>());
+    mem = idx->object->As<ast::MemberAccessorExpression>();
+    ASSERT_TRUE(mem->member->Is<ast::IdentifierExpression>());
+    ident = mem->member->As<ast::IdentifierExpression>();
+    EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("c"));
 
-  ASSERT_TRUE(mem->structure->Is<ast::MemberAccessorExpression>());
-  mem = mem->structure->As<ast::MemberAccessorExpression>();
+    ASSERT_TRUE(mem->structure->Is<ast::MemberAccessorExpression>());
+    mem = mem->structure->As<ast::MemberAccessorExpression>();
 
-  ASSERT_TRUE(mem->structure->Is<ast::IdentifierExpression>());
-  ident = mem->structure->As<ast::IdentifierExpression>();
-  EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
+    ASSERT_TRUE(mem->structure->Is<ast::IdentifierExpression>());
+    ident = mem->structure->As<ast::IdentifierExpression>();
+    EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_TRUE(mem->member->Is<ast::IdentifierExpression>());
-  ident = mem->member->As<ast::IdentifierExpression>();
-  EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("b"));
+    ASSERT_TRUE(mem->member->Is<ast::IdentifierExpression>());
+    ident = mem->member->As<ast::IdentifierExpression>();
+    EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("b"));
 }
 
 TEST_F(ParserImplTest, IncrementDecrementStmt_InvalidLHS) {
-  auto p = parser("{}++");
-  auto e = p->assignment_stmt();
-  EXPECT_FALSE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_EQ(e.value, nullptr);
+    auto p = parser("{}++");
+    auto e = p->assignment_stmt();
+    EXPECT_FALSE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_EQ(e.value, nullptr);
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_logical_and_expression_test.cc b/src/tint/reader/wgsl/parser_impl_logical_and_expression_test.cc
index ae4cfe8..57624a5 100644
--- a/src/tint/reader/wgsl/parser_impl_logical_and_expression_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_logical_and_expression_test.cc
@@ -18,52 +18,52 @@
 namespace {
 
 TEST_F(ParserImplTest, LogicalAndExpression_Parses) {
-  auto p = parser("a && true");
-  auto e = p->logical_and_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("a && true");
+    auto e = p->logical_and_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e->Is<ast::BinaryExpression>());
-  auto* rel = e->As<ast::BinaryExpression>();
-  EXPECT_EQ(ast::BinaryOp::kLogicalAnd, rel->op);
+    ASSERT_TRUE(e->Is<ast::BinaryExpression>());
+    auto* rel = e->As<ast::BinaryExpression>();
+    EXPECT_EQ(ast::BinaryOp::kLogicalAnd, rel->op);
 
-  ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
-  auto* ident = rel->lhs->As<ast::IdentifierExpression>();
-  EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
+    ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
+    auto* ident = rel->lhs->As<ast::IdentifierExpression>();
+    EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
-  ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
+    ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
+    ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
 }
 
 TEST_F(ParserImplTest, LogicalAndExpression_InvalidLHS) {
-  auto p = parser("if (a) {} && true");
-  auto e = p->logical_and_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_EQ(e.value, nullptr);
+    auto p = parser("if (a) {} && true");
+    auto e = p->logical_and_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_EQ(e.value, nullptr);
 }
 
 TEST_F(ParserImplTest, LogicalAndExpression_InvalidRHS) {
-  auto p = parser("true && if (a) {}");
-  auto e = p->logical_and_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:9: unable to parse right side of && expression");
+    auto p = parser("true && if (a) {}");
+    auto e = p->logical_and_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:9: unable to parse right side of && expression");
 }
 
 TEST_F(ParserImplTest, LogicalAndExpression_NoOr_ReturnsLHS) {
-  auto p = parser("a true");
-  auto e = p->logical_and_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::IdentifierExpression>());
+    auto p = parser("a true");
+    auto e = p->logical_and_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::IdentifierExpression>());
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_logical_or_expression_test.cc b/src/tint/reader/wgsl/parser_impl_logical_or_expression_test.cc
index 6af8355..6bde6bd 100644
--- a/src/tint/reader/wgsl/parser_impl_logical_or_expression_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_logical_or_expression_test.cc
@@ -18,52 +18,52 @@
 namespace {
 
 TEST_F(ParserImplTest, LogicalOrExpression_Parses) {
-  auto p = parser("a || true");
-  auto e = p->logical_or_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("a || true");
+    auto e = p->logical_or_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e->Is<ast::BinaryExpression>());
-  auto* rel = e->As<ast::BinaryExpression>();
-  EXPECT_EQ(ast::BinaryOp::kLogicalOr, rel->op);
+    ASSERT_TRUE(e->Is<ast::BinaryExpression>());
+    auto* rel = e->As<ast::BinaryExpression>();
+    EXPECT_EQ(ast::BinaryOp::kLogicalOr, rel->op);
 
-  ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
-  auto* ident = rel->lhs->As<ast::IdentifierExpression>();
-  EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
+    ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
+    auto* ident = rel->lhs->As<ast::IdentifierExpression>();
+    EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
-  ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
+    ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
+    ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
 }
 
 TEST_F(ParserImplTest, LogicalOrExpression_InvalidLHS) {
-  auto p = parser("if (a) {} || true");
-  auto e = p->logical_or_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_EQ(e.value, nullptr);
+    auto p = parser("if (a) {} || true");
+    auto e = p->logical_or_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_EQ(e.value, nullptr);
 }
 
 TEST_F(ParserImplTest, LogicalOrExpression_InvalidRHS) {
-  auto p = parser("true || if (a) {}");
-  auto e = p->logical_or_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:9: unable to parse right side of || expression");
+    auto p = parser("true || if (a) {}");
+    auto e = p->logical_or_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:9: unable to parse right side of || expression");
 }
 
 TEST_F(ParserImplTest, LogicalOrExpression_NoOr_ReturnsLHS) {
-  auto p = parser("a true");
-  auto e = p->logical_or_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::IdentifierExpression>());
+    auto p = parser("a true");
+    auto e = p->logical_or_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::IdentifierExpression>());
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_loop_stmt_test.cc b/src/tint/reader/wgsl/parser_impl_loop_stmt_test.cc
index 6070cca..20cd4f6 100644
--- a/src/tint/reader/wgsl/parser_impl_loop_stmt_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_loop_stmt_test.cc
@@ -19,95 +19,95 @@
 namespace {
 
 TEST_F(ParserImplTest, LoopStmt_BodyNoContinuing) {
-  auto p = parser("loop { discard; }");
-  auto e = p->loop_stmt();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("loop { discard; }");
+    auto e = p->loop_stmt();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  ASSERT_EQ(e->body->statements.size(), 1u);
-  EXPECT_TRUE(e->body->statements[0]->Is<ast::DiscardStatement>());
+    ASSERT_EQ(e->body->statements.size(), 1u);
+    EXPECT_TRUE(e->body->statements[0]->Is<ast::DiscardStatement>());
 
-  EXPECT_EQ(e->continuing->statements.size(), 0u);
+    EXPECT_EQ(e->continuing->statements.size(), 0u);
 }
 
 TEST_F(ParserImplTest, LoopStmt_BodyWithContinuing) {
-  auto p = parser("loop { discard; continuing { discard; }}");
-  auto e = p->loop_stmt();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("loop { discard; continuing { discard; }}");
+    auto e = p->loop_stmt();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  ASSERT_EQ(e->body->statements.size(), 1u);
-  EXPECT_TRUE(e->body->statements[0]->Is<ast::DiscardStatement>());
+    ASSERT_EQ(e->body->statements.size(), 1u);
+    EXPECT_TRUE(e->body->statements[0]->Is<ast::DiscardStatement>());
 
-  EXPECT_EQ(e->continuing->statements.size(), 1u);
-  EXPECT_TRUE(e->continuing->statements[0]->Is<ast::DiscardStatement>());
+    EXPECT_EQ(e->continuing->statements.size(), 1u);
+    EXPECT_TRUE(e->continuing->statements[0]->Is<ast::DiscardStatement>());
 }
 
 TEST_F(ParserImplTest, LoopStmt_NoBodyNoContinuing) {
-  auto p = parser("loop { }");
-  auto e = p->loop_stmt();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_EQ(e->body->statements.size(), 0u);
-  ASSERT_EQ(e->continuing->statements.size(), 0u);
+    auto p = parser("loop { }");
+    auto e = p->loop_stmt();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_EQ(e->body->statements.size(), 0u);
+    ASSERT_EQ(e->continuing->statements.size(), 0u);
 }
 
 TEST_F(ParserImplTest, LoopStmt_NoBodyWithContinuing) {
-  auto p = parser("loop { continuing { discard; }}");
-  auto e = p->loop_stmt();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_EQ(e->body->statements.size(), 0u);
-  ASSERT_EQ(e->continuing->statements.size(), 1u);
-  EXPECT_TRUE(e->continuing->statements[0]->Is<ast::DiscardStatement>());
+    auto p = parser("loop { continuing { discard; }}");
+    auto e = p->loop_stmt();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_EQ(e->body->statements.size(), 0u);
+    ASSERT_EQ(e->continuing->statements.size(), 1u);
+    EXPECT_TRUE(e->continuing->statements[0]->Is<ast::DiscardStatement>());
 }
 
 TEST_F(ParserImplTest, LoopStmt_MissingBracketLeft) {
-  auto p = parser("loop discard; }");
-  auto e = p->loop_stmt();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:6: expected '{' for loop");
+    auto p = parser("loop discard; }");
+    auto e = p->loop_stmt();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:6: expected '{' for loop");
 }
 
 TEST_F(ParserImplTest, LoopStmt_MissingBracketRight) {
-  auto p = parser("loop { discard; ");
-  auto e = p->loop_stmt();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:17: expected '}' for loop");
+    auto p = parser("loop { discard; ");
+    auto e = p->loop_stmt();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:17: expected '}' for loop");
 }
 
 TEST_F(ParserImplTest, LoopStmt_InvalidStatements) {
-  auto p = parser("loop { discard }");
-  auto e = p->loop_stmt();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:16: expected ';' for discard statement");
+    auto p = parser("loop { discard }");
+    auto e = p->loop_stmt();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:16: expected ';' for discard statement");
 }
 
 TEST_F(ParserImplTest, LoopStmt_InvalidContinuing) {
-  auto p = parser("loop { continuing { discard }}");
-  auto e = p->loop_stmt();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:29: expected ';' for discard statement");
+    auto p = parser("loop { continuing { discard }}");
+    auto e = p->loop_stmt();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:29: expected ';' for discard statement");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_multiplicative_expression_test.cc b/src/tint/reader/wgsl/parser_impl_multiplicative_expression_test.cc
index 56273c9..6d77fd5 100644
--- a/src/tint/reader/wgsl/parser_impl_multiplicative_expression_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_multiplicative_expression_test.cc
@@ -18,92 +18,92 @@
 namespace {
 
 TEST_F(ParserImplTest, MultiplicativeExpression_Parses_Multiply) {
-  auto p = parser("a * true");
-  auto e = p->multiplicative_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("a * true");
+    auto e = p->multiplicative_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e->Is<ast::BinaryExpression>());
-  auto* rel = e->As<ast::BinaryExpression>();
-  EXPECT_EQ(ast::BinaryOp::kMultiply, rel->op);
+    ASSERT_TRUE(e->Is<ast::BinaryExpression>());
+    auto* rel = e->As<ast::BinaryExpression>();
+    EXPECT_EQ(ast::BinaryOp::kMultiply, rel->op);
 
-  ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
-  auto* ident = rel->lhs->As<ast::IdentifierExpression>();
-  EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
+    ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
+    auto* ident = rel->lhs->As<ast::IdentifierExpression>();
+    EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
-  ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
+    ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
+    ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
 }
 
 TEST_F(ParserImplTest, MultiplicativeExpression_Parses_Divide) {
-  auto p = parser("a / true");
-  auto e = p->multiplicative_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("a / true");
+    auto e = p->multiplicative_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e->Is<ast::BinaryExpression>());
-  auto* rel = e->As<ast::BinaryExpression>();
-  EXPECT_EQ(ast::BinaryOp::kDivide, rel->op);
+    ASSERT_TRUE(e->Is<ast::BinaryExpression>());
+    auto* rel = e->As<ast::BinaryExpression>();
+    EXPECT_EQ(ast::BinaryOp::kDivide, rel->op);
 
-  ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
-  auto* ident = rel->lhs->As<ast::IdentifierExpression>();
-  EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
+    ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
+    auto* ident = rel->lhs->As<ast::IdentifierExpression>();
+    EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
-  ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
+    ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
+    ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
 }
 
 TEST_F(ParserImplTest, MultiplicativeExpression_Parses_Modulo) {
-  auto p = parser("a % true");
-  auto e = p->multiplicative_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("a % true");
+    auto e = p->multiplicative_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e->Is<ast::BinaryExpression>());
-  auto* rel = e->As<ast::BinaryExpression>();
-  EXPECT_EQ(ast::BinaryOp::kModulo, rel->op);
+    ASSERT_TRUE(e->Is<ast::BinaryExpression>());
+    auto* rel = e->As<ast::BinaryExpression>();
+    EXPECT_EQ(ast::BinaryOp::kModulo, rel->op);
 
-  ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
-  auto* ident = rel->lhs->As<ast::IdentifierExpression>();
-  EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
+    ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
+    auto* ident = rel->lhs->As<ast::IdentifierExpression>();
+    EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
-  ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
+    ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
+    ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
 }
 
 TEST_F(ParserImplTest, MultiplicativeExpression_InvalidLHS) {
-  auto p = parser("if (a) {} * true");
-  auto e = p->multiplicative_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_EQ(e.value, nullptr);
+    auto p = parser("if (a) {} * true");
+    auto e = p->multiplicative_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_EQ(e.value, nullptr);
 }
 
 TEST_F(ParserImplTest, MultiplicativeExpression_InvalidRHS) {
-  auto p = parser("true * if (a) {}");
-  auto e = p->multiplicative_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:8: unable to parse right side of * expression");
+    auto p = parser("true * if (a) {}");
+    auto e = p->multiplicative_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    ASSERT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:8: unable to parse right side of * expression");
 }
 
 TEST_F(ParserImplTest, MultiplicativeExpression_NoOr_ReturnsLHS) {
-  auto p = parser("a true");
-  auto e = p->multiplicative_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::IdentifierExpression>());
+    auto p = parser("a true");
+    auto e = p->multiplicative_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::IdentifierExpression>());
 }
 
 }  // namespace
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 d4d7b9c..2d79a99 100644
--- a/src/tint/reader/wgsl/parser_impl_param_list_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_param_list_test.cc
@@ -18,114 +18,112 @@
 namespace {
 
 TEST_F(ParserImplTest, ParamList_Single) {
-  auto p = parser("a : i32");
+    auto p = parser("a : i32");
 
-  auto e = p->expect_param_list();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  ASSERT_FALSE(e.errored);
-  EXPECT_EQ(e.value.size(), 1u);
+    auto e = p->expect_param_list();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    ASSERT_FALSE(e.errored);
+    EXPECT_EQ(e.value.size(), 1u);
 
-  EXPECT_EQ(e.value[0]->symbol, p->builder().Symbols().Get("a"));
-  EXPECT_TRUE(e.value[0]->type->Is<ast::I32>());
-  EXPECT_TRUE(e.value[0]->is_const);
+    EXPECT_EQ(e.value[0]->symbol, p->builder().Symbols().Get("a"));
+    EXPECT_TRUE(e.value[0]->type->Is<ast::I32>());
+    EXPECT_TRUE(e.value[0]->is_const);
 
-  ASSERT_EQ(e.value[0]->source.range.begin.line, 1u);
-  ASSERT_EQ(e.value[0]->source.range.begin.column, 1u);
-  ASSERT_EQ(e.value[0]->source.range.end.line, 1u);
-  ASSERT_EQ(e.value[0]->source.range.end.column, 2u);
+    ASSERT_EQ(e.value[0]->source.range.begin.line, 1u);
+    ASSERT_EQ(e.value[0]->source.range.begin.column, 1u);
+    ASSERT_EQ(e.value[0]->source.range.end.line, 1u);
+    ASSERT_EQ(e.value[0]->source.range.end.column, 2u);
 }
 
 TEST_F(ParserImplTest, ParamList_Multiple) {
-  auto p = parser("a : i32, b: f32, c: vec2<f32>");
+    auto p = parser("a : i32, b: f32, c: vec2<f32>");
 
-  auto e = p->expect_param_list();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  ASSERT_FALSE(e.errored);
-  EXPECT_EQ(e.value.size(), 3u);
+    auto e = p->expect_param_list();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    ASSERT_FALSE(e.errored);
+    EXPECT_EQ(e.value.size(), 3u);
 
-  EXPECT_EQ(e.value[0]->symbol, p->builder().Symbols().Get("a"));
-  EXPECT_TRUE(e.value[0]->type->Is<ast::I32>());
-  EXPECT_TRUE(e.value[0]->is_const);
+    EXPECT_EQ(e.value[0]->symbol, p->builder().Symbols().Get("a"));
+    EXPECT_TRUE(e.value[0]->type->Is<ast::I32>());
+    EXPECT_TRUE(e.value[0]->is_const);
 
-  ASSERT_EQ(e.value[0]->source.range.begin.line, 1u);
-  ASSERT_EQ(e.value[0]->source.range.begin.column, 1u);
-  ASSERT_EQ(e.value[0]->source.range.end.line, 1u);
-  ASSERT_EQ(e.value[0]->source.range.end.column, 2u);
+    ASSERT_EQ(e.value[0]->source.range.begin.line, 1u);
+    ASSERT_EQ(e.value[0]->source.range.begin.column, 1u);
+    ASSERT_EQ(e.value[0]->source.range.end.line, 1u);
+    ASSERT_EQ(e.value[0]->source.range.end.column, 2u);
 
-  EXPECT_EQ(e.value[1]->symbol, p->builder().Symbols().Get("b"));
-  EXPECT_TRUE(e.value[1]->type->Is<ast::F32>());
-  EXPECT_TRUE(e.value[1]->is_const);
+    EXPECT_EQ(e.value[1]->symbol, p->builder().Symbols().Get("b"));
+    EXPECT_TRUE(e.value[1]->type->Is<ast::F32>());
+    EXPECT_TRUE(e.value[1]->is_const);
 
-  ASSERT_EQ(e.value[1]->source.range.begin.line, 1u);
-  ASSERT_EQ(e.value[1]->source.range.begin.column, 10u);
-  ASSERT_EQ(e.value[1]->source.range.end.line, 1u);
-  ASSERT_EQ(e.value[1]->source.range.end.column, 11u);
+    ASSERT_EQ(e.value[1]->source.range.begin.line, 1u);
+    ASSERT_EQ(e.value[1]->source.range.begin.column, 10u);
+    ASSERT_EQ(e.value[1]->source.range.end.line, 1u);
+    ASSERT_EQ(e.value[1]->source.range.end.column, 11u);
 
-  EXPECT_EQ(e.value[2]->symbol, p->builder().Symbols().Get("c"));
-  ASSERT_TRUE(e.value[2]->type->Is<ast::Vector>());
-  ASSERT_TRUE(e.value[2]->type->As<ast::Vector>()->type->Is<ast::F32>());
-  EXPECT_EQ(e.value[2]->type->As<ast::Vector>()->width, 2u);
-  EXPECT_TRUE(e.value[2]->is_const);
+    EXPECT_EQ(e.value[2]->symbol, p->builder().Symbols().Get("c"));
+    ASSERT_TRUE(e.value[2]->type->Is<ast::Vector>());
+    ASSERT_TRUE(e.value[2]->type->As<ast::Vector>()->type->Is<ast::F32>());
+    EXPECT_EQ(e.value[2]->type->As<ast::Vector>()->width, 2u);
+    EXPECT_TRUE(e.value[2]->is_const);
 
-  ASSERT_EQ(e.value[2]->source.range.begin.line, 1u);
-  ASSERT_EQ(e.value[2]->source.range.begin.column, 18u);
-  ASSERT_EQ(e.value[2]->source.range.end.line, 1u);
-  ASSERT_EQ(e.value[2]->source.range.end.column, 19u);
+    ASSERT_EQ(e.value[2]->source.range.begin.line, 1u);
+    ASSERT_EQ(e.value[2]->source.range.begin.column, 18u);
+    ASSERT_EQ(e.value[2]->source.range.end.line, 1u);
+    ASSERT_EQ(e.value[2]->source.range.end.column, 19u);
 }
 
 TEST_F(ParserImplTest, ParamList_Empty) {
-  auto p = parser("");
-  auto e = p->expect_param_list();
-  ASSERT_FALSE(p->has_error());
-  ASSERT_FALSE(e.errored);
-  EXPECT_EQ(e.value.size(), 0u);
+    auto p = parser("");
+    auto e = p->expect_param_list();
+    ASSERT_FALSE(p->has_error());
+    ASSERT_FALSE(e.errored);
+    EXPECT_EQ(e.value.size(), 0u);
 }
 
 TEST_F(ParserImplTest, ParamList_TrailingComma) {
-  auto p = parser("a : i32,");
-  auto e = p->expect_param_list();
-  ASSERT_FALSE(p->has_error());
-  ASSERT_FALSE(e.errored);
-  EXPECT_EQ(e.value.size(), 1u);
+    auto p = parser("a : i32,");
+    auto e = p->expect_param_list();
+    ASSERT_FALSE(p->has_error());
+    ASSERT_FALSE(e.errored);
+    EXPECT_EQ(e.value.size(), 1u);
 }
 
 TEST_F(ParserImplTest, ParamList_Attributes) {
-  auto p =
-      parser("@builtin(position) coord : vec4<f32>, @location(1) loc1 : f32");
+    auto p = parser("@builtin(position) coord : vec4<f32>, @location(1) loc1 : f32");
 
-  auto e = p->expect_param_list();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  ASSERT_FALSE(e.errored);
-  ASSERT_EQ(e.value.size(), 2u);
+    auto e = p->expect_param_list();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    ASSERT_FALSE(e.errored);
+    ASSERT_EQ(e.value.size(), 2u);
 
-  EXPECT_EQ(e.value[0]->symbol, p->builder().Symbols().Get("coord"));
-  ASSERT_TRUE(e.value[0]->type->Is<ast::Vector>());
-  EXPECT_TRUE(e.value[0]->type->As<ast::Vector>()->type->Is<ast::F32>());
-  EXPECT_EQ(e.value[0]->type->As<ast::Vector>()->width, 4u);
-  EXPECT_TRUE(e.value[0]->is_const);
-  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(e.value[0]->symbol, p->builder().Symbols().Get("coord"));
+    ASSERT_TRUE(e.value[0]->type->Is<ast::Vector>());
+    EXPECT_TRUE(e.value[0]->type->As<ast::Vector>()->type->Is<ast::F32>());
+    EXPECT_EQ(e.value[0]->type->As<ast::Vector>()->width, 4u);
+    EXPECT_TRUE(e.value[0]->is_const);
+    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);
 
-  ASSERT_EQ(e.value[0]->source.range.begin.line, 1u);
-  ASSERT_EQ(e.value[0]->source.range.begin.column, 20u);
-  ASSERT_EQ(e.value[0]->source.range.end.line, 1u);
-  ASSERT_EQ(e.value[0]->source.range.end.column, 25u);
+    ASSERT_EQ(e.value[0]->source.range.begin.line, 1u);
+    ASSERT_EQ(e.value[0]->source.range.begin.column, 20u);
+    ASSERT_EQ(e.value[0]->source.range.end.line, 1u);
+    ASSERT_EQ(e.value[0]->source.range.end.column, 25u);
 
-  EXPECT_EQ(e.value[1]->symbol, p->builder().Symbols().Get("loc1"));
-  EXPECT_TRUE(e.value[1]->type->Is<ast::F32>());
-  EXPECT_TRUE(e.value[1]->is_const);
-  auto attrs_1 = e.value[1]->attributes;
-  ASSERT_EQ(attrs_1.size(), 1u);
-  EXPECT_TRUE(attrs_1[0]->Is<ast::LocationAttribute>());
-  EXPECT_EQ(attrs_1[0]->As<ast::LocationAttribute>()->value, 1u);
+    EXPECT_EQ(e.value[1]->symbol, p->builder().Symbols().Get("loc1"));
+    EXPECT_TRUE(e.value[1]->type->Is<ast::F32>());
+    EXPECT_TRUE(e.value[1]->is_const);
+    auto attrs_1 = e.value[1]->attributes;
+    ASSERT_EQ(attrs_1.size(), 1u);
+    EXPECT_TRUE(attrs_1[0]->Is<ast::LocationAttribute>());
+    EXPECT_EQ(attrs_1[0]->As<ast::LocationAttribute>()->value, 1u);
 
-  EXPECT_EQ(e.value[1]->source.range.begin.line, 1u);
-  EXPECT_EQ(e.value[1]->source.range.begin.column, 52u);
-  EXPECT_EQ(e.value[1]->source.range.end.line, 1u);
-  EXPECT_EQ(e.value[1]->source.range.end.column, 56u);
+    EXPECT_EQ(e.value[1]->source.range.begin.line, 1u);
+    EXPECT_EQ(e.value[1]->source.range.begin.column, 52u);
+    EXPECT_EQ(e.value[1]->source.range.end.line, 1u);
+    EXPECT_EQ(e.value[1]->source.range.end.column, 56u);
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_paren_rhs_stmt_test.cc b/src/tint/reader/wgsl/parser_impl_paren_rhs_stmt_test.cc
index 214afe7..dd5a978 100644
--- a/src/tint/reader/wgsl/parser_impl_paren_rhs_stmt_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_paren_rhs_stmt_test.cc
@@ -18,48 +18,48 @@
 namespace {
 
 TEST_F(ParserImplTest, ParenRhsStmt) {
-  auto p = parser("(a + b)");
-  auto e = p->expect_paren_rhs_stmt();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  ASSERT_FALSE(e.errored);
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::BinaryExpression>());
+    auto p = parser("(a + b)");
+    auto e = p->expect_paren_rhs_stmt();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    ASSERT_FALSE(e.errored);
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::BinaryExpression>());
 }
 
 TEST_F(ParserImplTest, ParenRhsStmt_MissingLeftParen) {
-  auto p = parser("true)");
-  auto e = p->expect_paren_rhs_stmt();
-  ASSERT_TRUE(p->has_error());
-  ASSERT_TRUE(e.errored);
-  ASSERT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:1: expected '('");
+    auto p = parser("true)");
+    auto e = p->expect_paren_rhs_stmt();
+    ASSERT_TRUE(p->has_error());
+    ASSERT_TRUE(e.errored);
+    ASSERT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:1: expected '('");
 }
 
 TEST_F(ParserImplTest, ParenRhsStmt_MissingRightParen) {
-  auto p = parser("(true");
-  auto e = p->expect_paren_rhs_stmt();
-  ASSERT_TRUE(p->has_error());
-  ASSERT_TRUE(e.errored);
-  ASSERT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:6: expected ')'");
+    auto p = parser("(true");
+    auto e = p->expect_paren_rhs_stmt();
+    ASSERT_TRUE(p->has_error());
+    ASSERT_TRUE(e.errored);
+    ASSERT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:6: expected ')'");
 }
 
 TEST_F(ParserImplTest, ParenRhsStmt_InvalidExpression) {
-  auto p = parser("(if (a() {})");
-  auto e = p->expect_paren_rhs_stmt();
-  ASSERT_TRUE(p->has_error());
-  ASSERT_TRUE(e.errored);
-  ASSERT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:2: unable to parse expression");
+    auto p = parser("(if (a() {})");
+    auto e = p->expect_paren_rhs_stmt();
+    ASSERT_TRUE(p->has_error());
+    ASSERT_TRUE(e.errored);
+    ASSERT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:2: unable to parse expression");
 }
 
 TEST_F(ParserImplTest, ParenRhsStmt_MissingExpression) {
-  auto p = parser("()");
-  auto e = p->expect_paren_rhs_stmt();
-  ASSERT_TRUE(p->has_error());
-  ASSERT_TRUE(e.errored);
-  ASSERT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:2: unable to parse expression");
+    auto p = parser("()");
+    auto e = p->expect_paren_rhs_stmt();
+    ASSERT_TRUE(p->has_error());
+    ASSERT_TRUE(e.errored);
+    ASSERT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:2: unable to parse expression");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_pipeline_stage_test.cc b/src/tint/reader/wgsl/parser_impl_pipeline_stage_test.cc
index c0bce43..75a1ec2 100644
--- a/src/tint/reader/wgsl/parser_impl_pipeline_stage_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_pipeline_stage_test.cc
@@ -18,45 +18,44 @@
 namespace {
 
 struct PipelineStageData {
-  std::string input;
-  ast::PipelineStage result;
+    std::string input;
+    ast::PipelineStage result;
 };
 inline std::ostream& operator<<(std::ostream& out, PipelineStageData data) {
-  return out << data.input;
+    return out << data.input;
 }
 
 class PipelineStageTest : public ParserImplTestWithParam<PipelineStageData> {};
 
 TEST_P(PipelineStageTest, Parses) {
-  auto params = GetParam();
-  auto p = parser(params.input);
+    auto params = GetParam();
+    auto p = parser(params.input);
 
-  auto stage = p->expect_pipeline_stage();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  ASSERT_FALSE(stage.errored);
-  EXPECT_EQ(stage.value, params.result);
-  EXPECT_EQ(stage.source.range.begin.line, 1u);
-  EXPECT_EQ(stage.source.range.begin.column, 1u);
-  EXPECT_EQ(stage.source.range.end.line, 1u);
-  EXPECT_EQ(stage.source.range.end.column, 1u + params.input.size());
+    auto stage = p->expect_pipeline_stage();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    ASSERT_FALSE(stage.errored);
+    EXPECT_EQ(stage.value, params.result);
+    EXPECT_EQ(stage.source.range.begin.line, 1u);
+    EXPECT_EQ(stage.source.range.begin.column, 1u);
+    EXPECT_EQ(stage.source.range.end.line, 1u);
+    EXPECT_EQ(stage.source.range.end.column, 1u + params.input.size());
 
-  auto t = p->next();
-  EXPECT_TRUE(t.IsEof());
+    auto t = p->next();
+    EXPECT_TRUE(t.IsEof());
 }
 INSTANTIATE_TEST_SUITE_P(
     ParserImplTest,
     PipelineStageTest,
-    testing::Values(
-        PipelineStageData{"vertex", ast::PipelineStage::kVertex},
-        PipelineStageData{"fragment", ast::PipelineStage::kFragment},
-        PipelineStageData{"compute", ast::PipelineStage::kCompute}));
+    testing::Values(PipelineStageData{"vertex", ast::PipelineStage::kVertex},
+                    PipelineStageData{"fragment", ast::PipelineStage::kFragment},
+                    PipelineStageData{"compute", ast::PipelineStage::kCompute}));
 
 TEST_F(ParserImplTest, PipelineStage_NoMatch) {
-  auto p = parser("not-a-stage");
-  auto stage = p->expect_pipeline_stage();
-  ASSERT_TRUE(p->has_error());
-  ASSERT_TRUE(stage.errored);
-  ASSERT_EQ(p->error(), "1:1: invalid value for stage attribute");
+    auto p = parser("not-a-stage");
+    auto stage = p->expect_pipeline_stage();
+    ASSERT_TRUE(p->has_error());
+    ASSERT_TRUE(stage.errored);
+    ASSERT_EQ(p->error(), "1:1: invalid value for stage attribute");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_primary_expression_test.cc b/src/tint/reader/wgsl/parser_impl_primary_expression_test.cc
index c81fdd9..493ce87 100644
--- a/src/tint/reader/wgsl/parser_impl_primary_expression_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_primary_expression_test.cc
@@ -19,294 +19,304 @@
 namespace {
 
 TEST_F(ParserImplTest, PrimaryExpression_Ident) {
-  auto p = parser("a");
-  auto e = p->primary_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::IdentifierExpression>());
-  auto* ident = e->As<ast::IdentifierExpression>();
-  EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
+    auto p = parser("a");
+    auto e = p->primary_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::IdentifierExpression>());
+    auto* ident = e->As<ast::IdentifierExpression>();
+    EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
 }
 
 TEST_F(ParserImplTest, PrimaryExpression_TypeDecl) {
-  auto p = parser("vec4<i32>(1, 2, 3, 4))");
-  auto e = p->primary_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::CallExpression>());
-  auto* call = e->As<ast::CallExpression>();
+    auto p = parser("vec4<i32>(1, 2, 3, 4))");
+    auto e = p->primary_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::CallExpression>());
+    auto* call = e->As<ast::CallExpression>();
 
-  EXPECT_NE(call->target.type, nullptr);
+    EXPECT_NE(call->target.type, nullptr);
 
-  ASSERT_EQ(call->args.size(), 4u);
-  const auto& val = call->args;
-  ASSERT_TRUE(val[0]->Is<ast::SintLiteralExpression>());
-  EXPECT_EQ(val[0]->As<ast::SintLiteralExpression>()->value, 1);
+    ASSERT_EQ(call->args.size(), 4u);
+    const auto& val = call->args;
+    ASSERT_TRUE(val[0]->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(val[0]->As<ast::IntLiteralExpression>()->value, 1);
+    EXPECT_EQ(val[0]->As<ast::IntLiteralExpression>()->suffix,
+              ast::IntLiteralExpression::Suffix::kNone);
 
-  ASSERT_TRUE(val[1]->Is<ast::SintLiteralExpression>());
-  EXPECT_EQ(val[1]->As<ast::SintLiteralExpression>()->value, 2);
+    ASSERT_TRUE(val[1]->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(val[1]->As<ast::IntLiteralExpression>()->value, 2);
+    EXPECT_EQ(val[1]->As<ast::IntLiteralExpression>()->suffix,
+              ast::IntLiteralExpression::Suffix::kNone);
 
-  ASSERT_TRUE(val[2]->Is<ast::SintLiteralExpression>());
-  EXPECT_EQ(val[2]->As<ast::SintLiteralExpression>()->value, 3);
+    ASSERT_TRUE(val[2]->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(val[2]->As<ast::IntLiteralExpression>()->value, 3);
+    EXPECT_EQ(val[2]->As<ast::IntLiteralExpression>()->suffix,
+              ast::IntLiteralExpression::Suffix::kNone);
 
-  ASSERT_TRUE(val[3]->Is<ast::SintLiteralExpression>());
-  EXPECT_EQ(val[3]->As<ast::SintLiteralExpression>()->value, 4);
+    ASSERT_TRUE(val[3]->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(val[3]->As<ast::IntLiteralExpression>()->value, 4);
+    EXPECT_EQ(val[3]->As<ast::IntLiteralExpression>()->suffix,
+              ast::IntLiteralExpression::Suffix::kNone);
 }
 
 TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_ZeroConstructor) {
-  auto p = parser("vec4<i32>()");
-  auto e = p->primary_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("vec4<i32>()");
+    auto e = p->primary_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e->Is<ast::CallExpression>());
-  auto* call = e->As<ast::CallExpression>();
+    ASSERT_TRUE(e->Is<ast::CallExpression>());
+    auto* call = e->As<ast::CallExpression>();
 
-  ASSERT_EQ(call->args.size(), 0u);
+    ASSERT_EQ(call->args.size(), 0u);
 }
 
 TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_InvalidTypeDecl) {
-  auto p = parser("vec4<if>(2., 3., 4., 5.)");
-  auto e = p->primary_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:6: invalid type for vector");
+    auto p = parser("vec4<if>(2., 3., 4., 5.)");
+    auto e = p->primary_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    ASSERT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:6: invalid type for vector");
 }
 
 TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_MissingLeftParen) {
-  auto p = parser("vec4<f32> 2., 3., 4., 5.)");
-  auto e = p->primary_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:11: expected '(' for type constructor");
+    auto p = parser("vec4<f32> 2., 3., 4., 5.)");
+    auto e = p->primary_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    ASSERT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:11: expected '(' for type constructor");
 }
 
 TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_MissingRightParen) {
-  auto p = parser("vec4<f32>(2., 3., 4., 5.");
-  auto e = p->primary_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:25: expected ')' for type constructor");
+    auto p = parser("vec4<f32>(2., 3., 4., 5.");
+    auto e = p->primary_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    ASSERT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:25: expected ')' for type constructor");
 }
 
 TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_InvalidValue) {
-  auto p = parser("i32(if(a) {})");
-  auto e = p->primary_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:5: expected ')' for type constructor");
+    auto p = parser("i32(if(a) {})");
+    auto e = p->primary_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    ASSERT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:5: expected ')' for type constructor");
 }
 
 TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_StructConstructor_Empty) {
-  auto p = parser(R"(
+    auto p = parser(R"(
   struct S { a : i32, b : f32, }
   S()
   )");
 
-  p->expect_global_decl();
-  ASSERT_FALSE(p->has_error()) << p->error();
+    p->global_decl();
+    ASSERT_FALSE(p->has_error()) << p->error();
 
-  auto e = p->primary_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto e = p->primary_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e->Is<ast::CallExpression>());
-  auto* call = e->As<ast::CallExpression>();
+    ASSERT_TRUE(e->Is<ast::CallExpression>());
+    auto* call = e->As<ast::CallExpression>();
 
-  ASSERT_NE(call->target.name, nullptr);
-  EXPECT_EQ(call->target.name->symbol, p->builder().Symbols().Get("S"));
+    ASSERT_NE(call->target.name, nullptr);
+    EXPECT_EQ(call->target.name->symbol, p->builder().Symbols().Get("S"));
 
-  ASSERT_EQ(call->args.size(), 0u);
+    ASSERT_EQ(call->args.size(), 0u);
 }
 
 TEST_F(ParserImplTest, PrimaryExpression_TypeDecl_StructConstructor_NotEmpty) {
-  auto p = parser(R"(
+    auto p = parser(R"(
   struct S { a : i32, b : f32, }
   S(1u, 2.0)
   )");
 
-  p->expect_global_decl();
-  ASSERT_FALSE(p->has_error()) << p->error();
+    p->global_decl();
+    ASSERT_FALSE(p->has_error()) << p->error();
 
-  auto e = p->primary_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto e = p->primary_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e->Is<ast::CallExpression>());
-  auto* call = e->As<ast::CallExpression>();
+    ASSERT_TRUE(e->Is<ast::CallExpression>());
+    auto* call = e->As<ast::CallExpression>();
 
-  ASSERT_NE(call->target.name, nullptr);
-  EXPECT_EQ(call->target.name->symbol, p->builder().Symbols().Get("S"));
+    ASSERT_NE(call->target.name, nullptr);
+    EXPECT_EQ(call->target.name->symbol, p->builder().Symbols().Get("S"));
 
-  ASSERT_EQ(call->args.size(), 2u);
+    ASSERT_EQ(call->args.size(), 2u);
 
-  ASSERT_TRUE(call->args[0]->Is<ast::UintLiteralExpression>());
-  EXPECT_EQ(call->args[0]->As<ast::UintLiteralExpression>()->value, 1u);
+    ASSERT_TRUE(call->args[0]->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(call->args[0]->As<ast::IntLiteralExpression>()->value, 1u);
+    EXPECT_EQ(call->args[0]->As<ast::IntLiteralExpression>()->suffix,
+              ast::IntLiteralExpression::Suffix::kU);
 
-  ASSERT_TRUE(call->args[1]->Is<ast::FloatLiteralExpression>());
-  EXPECT_EQ(call->args[1]->As<ast::FloatLiteralExpression>()->value, 2.f);
+    ASSERT_TRUE(call->args[1]->Is<ast::FloatLiteralExpression>());
+    EXPECT_EQ(call->args[1]->As<ast::FloatLiteralExpression>()->value, 2.f);
 }
 
 TEST_F(ParserImplTest, PrimaryExpression_ConstLiteral_True) {
-  auto p = parser("true");
-  auto e = p->primary_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::BoolLiteralExpression>());
-  EXPECT_TRUE(e->As<ast::BoolLiteralExpression>()->value);
+    auto p = parser("true");
+    auto e = p->primary_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::BoolLiteralExpression>());
+    EXPECT_TRUE(e->As<ast::BoolLiteralExpression>()->value);
 }
 
 TEST_F(ParserImplTest, PrimaryExpression_ParenExpr) {
-  auto p = parser("(a == b)");
-  auto e = p->primary_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::BinaryExpression>());
+    auto p = parser("(a == b)");
+    auto e = p->primary_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::BinaryExpression>());
 }
 
 TEST_F(ParserImplTest, PrimaryExpression_ParenExpr_MissingRightParen) {
-  auto p = parser("(a == b");
-  auto e = p->primary_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:8: expected ')'");
+    auto p = parser("(a == b");
+    auto e = p->primary_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    ASSERT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:8: expected ')'");
 }
 
 TEST_F(ParserImplTest, PrimaryExpression_ParenExpr_MissingExpr) {
-  auto p = parser("()");
-  auto e = p->primary_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:2: unable to parse expression");
+    auto p = parser("()");
+    auto e = p->primary_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    ASSERT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:2: unable to parse expression");
 }
 
 TEST_F(ParserImplTest, PrimaryExpression_ParenExpr_InvalidExpr) {
-  auto p = parser("(if (a) {})");
-  auto e = p->primary_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:2: unable to parse expression");
+    auto p = parser("(if (a) {})");
+    auto e = p->primary_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    ASSERT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:2: unable to parse expression");
 }
 
 TEST_F(ParserImplTest, PrimaryExpression_Cast) {
-  auto p = parser("f32(1)");
+    auto p = parser("f32(1)");
 
-  auto e = p->primary_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto e = p->primary_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e->Is<ast::CallExpression>());
-  auto* call = e->As<ast::CallExpression>();
+    ASSERT_TRUE(e->Is<ast::CallExpression>());
+    auto* call = e->As<ast::CallExpression>();
 
-  ASSERT_TRUE(call->target.type->Is<ast::F32>());
-  ASSERT_EQ(call->args.size(), 1u);
+    ASSERT_TRUE(call->target.type->Is<ast::F32>());
+    ASSERT_EQ(call->args.size(), 1u);
 
-  ASSERT_TRUE(call->args[0]->Is<ast::IntLiteralExpression>());
+    ASSERT_TRUE(call->args[0]->Is<ast::IntLiteralExpression>());
 }
 
 TEST_F(ParserImplTest, PrimaryExpression_Bitcast) {
-  auto p = parser("bitcast<f32>(1)");
+    auto p = parser("bitcast<f32>(1)");
 
-  auto e = p->primary_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::BitcastExpression>());
+    auto e = p->primary_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::BitcastExpression>());
 
-  auto* c = e->As<ast::BitcastExpression>();
-  ASSERT_TRUE(c->type->Is<ast::F32>());
-  ASSERT_TRUE(c->expr->Is<ast::IntLiteralExpression>());
+    auto* c = e->As<ast::BitcastExpression>();
+    ASSERT_TRUE(c->type->Is<ast::F32>());
+    ASSERT_TRUE(c->expr->Is<ast::IntLiteralExpression>());
 }
 
 TEST_F(ParserImplTest, PrimaryExpression_Bitcast_MissingGreaterThan) {
-  auto p = parser("bitcast<f32(1)");
-  auto e = p->primary_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:12: expected '>' for bitcast expression");
+    auto p = parser("bitcast<f32(1)");
+    auto e = p->primary_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    ASSERT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:12: expected '>' for bitcast expression");
 }
 
 TEST_F(ParserImplTest, PrimaryExpression_Bitcast_MissingType) {
-  auto p = parser("bitcast<>(1)");
-  auto e = p->primary_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:9: invalid type for bitcast expression");
+    auto p = parser("bitcast<>(1)");
+    auto e = p->primary_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    ASSERT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:9: invalid type for bitcast expression");
 }
 
 TEST_F(ParserImplTest, PrimaryExpression_Bitcast_MissingLeftParen) {
-  auto p = parser("bitcast<f32>1)");
-  auto e = p->primary_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:13: expected '('");
+    auto p = parser("bitcast<f32>1)");
+    auto e = p->primary_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    ASSERT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:13: expected '('");
 }
 
 TEST_F(ParserImplTest, PrimaryExpression_Bitcast_MissingRightParen) {
-  auto p = parser("bitcast<f32>(1");
-  auto e = p->primary_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:15: expected ')'");
+    auto p = parser("bitcast<f32>(1");
+    auto e = p->primary_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    ASSERT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:15: expected ')'");
 }
 
 TEST_F(ParserImplTest, PrimaryExpression_Bitcast_MissingExpression) {
-  auto p = parser("bitcast<f32>()");
-  auto e = p->primary_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:14: unable to parse expression");
+    auto p = parser("bitcast<f32>()");
+    auto e = p->primary_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    ASSERT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:14: unable to parse expression");
 }
 
 TEST_F(ParserImplTest, PrimaryExpression_bitcast_InvalidExpression) {
-  auto p = parser("bitcast<f32>(if (a) {})");
-  auto e = p->primary_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:14: unable to parse expression");
+    auto p = parser("bitcast<f32>(if (a) {})");
+    auto e = p->primary_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    ASSERT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:14: unable to parse expression");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_relational_expression_test.cc b/src/tint/reader/wgsl/parser_impl_relational_expression_test.cc
index f071731..725761b 100644
--- a/src/tint/reader/wgsl/parser_impl_relational_expression_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_relational_expression_test.cc
@@ -18,110 +18,110 @@
 namespace {
 
 TEST_F(ParserImplTest, RelationalExpression_Parses_LessThan) {
-  auto p = parser("a < true");
-  auto e = p->relational_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("a < true");
+    auto e = p->relational_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e->Is<ast::BinaryExpression>());
-  auto* rel = e->As<ast::BinaryExpression>();
-  EXPECT_EQ(ast::BinaryOp::kLessThan, rel->op);
+    ASSERT_TRUE(e->Is<ast::BinaryExpression>());
+    auto* rel = e->As<ast::BinaryExpression>();
+    EXPECT_EQ(ast::BinaryOp::kLessThan, rel->op);
 
-  ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
-  auto* ident = rel->lhs->As<ast::IdentifierExpression>();
-  EXPECT_EQ(ident->symbol, p->builder().Symbols().Register("a"));
+    ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
+    auto* ident = rel->lhs->As<ast::IdentifierExpression>();
+    EXPECT_EQ(ident->symbol, p->builder().Symbols().Register("a"));
 
-  ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
-  ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
+    ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
+    ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
 }
 
 TEST_F(ParserImplTest, RelationalExpression_Parses_GreaterThan) {
-  auto p = parser("a > true");
-  auto e = p->relational_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("a > true");
+    auto e = p->relational_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e->Is<ast::BinaryExpression>());
-  auto* rel = e->As<ast::BinaryExpression>();
-  EXPECT_EQ(ast::BinaryOp::kGreaterThan, rel->op);
+    ASSERT_TRUE(e->Is<ast::BinaryExpression>());
+    auto* rel = e->As<ast::BinaryExpression>();
+    EXPECT_EQ(ast::BinaryOp::kGreaterThan, rel->op);
 
-  ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
-  auto* ident = rel->lhs->As<ast::IdentifierExpression>();
-  EXPECT_EQ(ident->symbol, p->builder().Symbols().Register("a"));
+    ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
+    auto* ident = rel->lhs->As<ast::IdentifierExpression>();
+    EXPECT_EQ(ident->symbol, p->builder().Symbols().Register("a"));
 
-  ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
-  ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
+    ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
+    ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
 }
 
 TEST_F(ParserImplTest, RelationalExpression_Parses_LessThanEqual) {
-  auto p = parser("a <= true");
-  auto e = p->relational_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("a <= true");
+    auto e = p->relational_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e->Is<ast::BinaryExpression>());
-  auto* rel = e->As<ast::BinaryExpression>();
-  EXPECT_EQ(ast::BinaryOp::kLessThanEqual, rel->op);
+    ASSERT_TRUE(e->Is<ast::BinaryExpression>());
+    auto* rel = e->As<ast::BinaryExpression>();
+    EXPECT_EQ(ast::BinaryOp::kLessThanEqual, rel->op);
 
-  ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
-  auto* ident = rel->lhs->As<ast::IdentifierExpression>();
-  EXPECT_EQ(ident->symbol, p->builder().Symbols().Register("a"));
+    ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
+    auto* ident = rel->lhs->As<ast::IdentifierExpression>();
+    EXPECT_EQ(ident->symbol, p->builder().Symbols().Register("a"));
 
-  ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
-  ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
+    ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
+    ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
 }
 
 TEST_F(ParserImplTest, RelationalExpression_Parses_GreaterThanEqual) {
-  auto p = parser("a >= true");
-  auto e = p->relational_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("a >= true");
+    auto e = p->relational_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e->Is<ast::BinaryExpression>());
-  auto* rel = e->As<ast::BinaryExpression>();
-  EXPECT_EQ(ast::BinaryOp::kGreaterThanEqual, rel->op);
+    ASSERT_TRUE(e->Is<ast::BinaryExpression>());
+    auto* rel = e->As<ast::BinaryExpression>();
+    EXPECT_EQ(ast::BinaryOp::kGreaterThanEqual, rel->op);
 
-  ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
-  auto* ident = rel->lhs->As<ast::IdentifierExpression>();
-  EXPECT_EQ(ident->symbol, p->builder().Symbols().Register("a"));
+    ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
+    auto* ident = rel->lhs->As<ast::IdentifierExpression>();
+    EXPECT_EQ(ident->symbol, p->builder().Symbols().Register("a"));
 
-  ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
-  ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
+    ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
+    ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
 }
 
 TEST_F(ParserImplTest, RelationalExpression_InvalidLHS) {
-  auto p = parser("if (a) {} < true");
-  auto e = p->relational_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_EQ(e.value, nullptr);
+    auto p = parser("if (a) {} < true");
+    auto e = p->relational_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_EQ(e.value, nullptr);
 }
 
 TEST_F(ParserImplTest, RelationalExpression_InvalidRHS) {
-  auto p = parser("true < if (a) {}");
-  auto e = p->relational_expression();
-  ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:8: unable to parse right side of < expression");
+    auto p = parser("true < if (a) {}");
+    auto e = p->relational_expression();
+    ASSERT_TRUE(p->has_error());
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:8: unable to parse right side of < expression");
 }
 
 TEST_F(ParserImplTest, RelationalExpression_NoOr_ReturnsLHS) {
-  auto p = parser("a true");
-  auto e = p->relational_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::IdentifierExpression>());
+    auto p = parser("a true");
+    auto e = p->relational_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::IdentifierExpression>());
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_reserved_keyword_test.cc b/src/tint/reader/wgsl/parser_impl_reserved_keyword_test.cc
index 7ce03c2..3226ef5 100644
--- a/src/tint/reader/wgsl/parser_impl_reserved_keyword_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_reserved_keyword_test.cc
@@ -19,67 +19,67 @@
 
 using ParserImplReservedKeywordTest = ParserImplTestWithParam<std::string>;
 TEST_P(ParserImplReservedKeywordTest, Function) {
-  auto name = GetParam();
-  auto p = parser("fn " + name + "() {}");
-  EXPECT_FALSE(p->Parse());
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:4: '" + name + "' is a reserved keyword");
+    auto name = GetParam();
+    auto p = parser("fn " + name + "() {}");
+    EXPECT_FALSE(p->Parse());
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:4: '" + name + "' is a reserved keyword");
 }
 TEST_P(ParserImplReservedKeywordTest, ModuleLet) {
-  auto name = GetParam();
-  auto p = parser("let " + name + " : i32 = 1;");
-  EXPECT_FALSE(p->Parse());
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:5: '" + name + "' is a reserved keyword");
+    auto name = GetParam();
+    auto p = parser("let " + name + " : i32 = 1;");
+    EXPECT_FALSE(p->Parse());
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:5: '" + name + "' is a reserved keyword");
 }
 TEST_P(ParserImplReservedKeywordTest, ModuleVar) {
-  auto name = GetParam();
-  auto p = parser("var " + name + " : i32 = 1;");
-  EXPECT_FALSE(p->Parse());
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:5: '" + name + "' is a reserved keyword");
+    auto name = GetParam();
+    auto p = parser("var " + name + " : i32 = 1;");
+    EXPECT_FALSE(p->Parse());
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:5: '" + name + "' is a reserved keyword");
 }
 TEST_P(ParserImplReservedKeywordTest, FunctionLet) {
-  auto name = GetParam();
-  auto p = parser("fn f() { let " + name + " : i32 = 1; }");
-  EXPECT_FALSE(p->Parse());
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:14: '" + name + "' is a reserved keyword");
+    auto name = GetParam();
+    auto p = parser("fn f() { let " + name + " : i32 = 1; }");
+    EXPECT_FALSE(p->Parse());
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:14: '" + name + "' is a reserved keyword");
 }
 TEST_P(ParserImplReservedKeywordTest, FunctionVar) {
-  auto name = GetParam();
-  auto p = parser("fn f() { var " + name + " : i32 = 1; }");
-  EXPECT_FALSE(p->Parse());
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:14: '" + name + "' is a reserved keyword");
+    auto name = GetParam();
+    auto p = parser("fn f() { var " + name + " : i32 = 1; }");
+    EXPECT_FALSE(p->Parse());
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:14: '" + name + "' is a reserved keyword");
 }
 TEST_P(ParserImplReservedKeywordTest, FunctionParam) {
-  auto name = GetParam();
-  auto p = parser("fn f(" + name + " : i32) {}");
-  EXPECT_FALSE(p->Parse());
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:6: '" + name + "' is a reserved keyword");
+    auto name = GetParam();
+    auto p = parser("fn f(" + name + " : i32) {}");
+    EXPECT_FALSE(p->Parse());
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:6: '" + name + "' is a reserved keyword");
 }
 TEST_P(ParserImplReservedKeywordTest, Struct) {
-  auto name = GetParam();
-  auto p = parser("struct " + name + " {};");
-  EXPECT_FALSE(p->Parse());
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:8: '" + name + "' is a reserved keyword");
+    auto name = GetParam();
+    auto p = parser("struct " + name + " {};");
+    EXPECT_FALSE(p->Parse());
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:8: '" + name + "' is a reserved keyword");
 }
 TEST_P(ParserImplReservedKeywordTest, StructMember) {
-  auto name = GetParam();
-  auto p = parser("struct S { " + name + " : i32, };");
-  EXPECT_FALSE(p->Parse());
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:12: '" + name + "' is a reserved keyword");
+    auto name = GetParam();
+    auto p = parser("struct S { " + name + " : i32, };");
+    EXPECT_FALSE(p->Parse());
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:12: '" + name + "' is a reserved keyword");
 }
 TEST_P(ParserImplReservedKeywordTest, Alias) {
-  auto name = GetParam();
-  auto p = parser("type " + name + " = i32;");
-  EXPECT_FALSE(p->Parse());
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:6: '" + name + "' is a reserved keyword");
+    auto name = GetParam();
+    auto p = parser("type " + name + " = i32;");
+    EXPECT_FALSE(p->Parse());
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:6: '" + name + "' is a reserved keyword");
 }
 INSTANTIATE_TEST_SUITE_P(ParserImplReservedKeywordTest,
                          ParserImplReservedKeywordTest,
diff --git a/src/tint/reader/wgsl/parser_impl_sampled_texture_test.cc b/src/tint/reader/wgsl/parser_impl_sampled_texture_test.cc
new file mode 100644
index 0000000..cf9f089
--- /dev/null
+++ b/src/tint/reader/wgsl/parser_impl_sampled_texture_test.cc
@@ -0,0 +1,83 @@
+// Copyright 2020 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/reader/wgsl/parser_impl_test_helper.h"
+
+namespace tint::reader::wgsl {
+namespace {
+
+TEST_F(ParserImplTest, SampledTextureType_Invalid) {
+    auto p = parser("1234");
+    auto t = p->sampled_texture();
+    EXPECT_FALSE(t.matched);
+    EXPECT_FALSE(t.errored);
+    EXPECT_FALSE(p->has_error());
+}
+
+TEST_F(ParserImplTest, SampledTextureType_1d) {
+    auto p = parser("texture_1d");
+    auto t = p->sampled_texture();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    EXPECT_EQ(t.value, ast::TextureDimension::k1d);
+    EXPECT_FALSE(p->has_error());
+}
+
+TEST_F(ParserImplTest, SampledTextureType_2d) {
+    auto p = parser("texture_2d");
+    auto t = p->sampled_texture();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    EXPECT_EQ(t.value, ast::TextureDimension::k2d);
+    EXPECT_FALSE(p->has_error());
+}
+
+TEST_F(ParserImplTest, SampledTextureType_2dArray) {
+    auto p = parser("texture_2d_array");
+    auto t = p->sampled_texture();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    EXPECT_EQ(t.value, ast::TextureDimension::k2dArray);
+    EXPECT_FALSE(p->has_error());
+}
+
+TEST_F(ParserImplTest, SampledTextureType_3d) {
+    auto p = parser("texture_3d");
+    auto t = p->sampled_texture();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    EXPECT_EQ(t.value, ast::TextureDimension::k3d);
+    EXPECT_FALSE(p->has_error());
+}
+
+TEST_F(ParserImplTest, SampledTextureType_Cube) {
+    auto p = parser("texture_cube");
+    auto t = p->sampled_texture();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    EXPECT_EQ(t.value, ast::TextureDimension::kCube);
+    EXPECT_FALSE(p->has_error());
+}
+
+TEST_F(ParserImplTest, SampledTextureType_kCubeArray) {
+    auto p = parser("texture_cube_array");
+    auto t = p->sampled_texture();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    EXPECT_EQ(t.value, ast::TextureDimension::kCubeArray);
+    EXPECT_FALSE(p->has_error());
+}
+
+}  // namespace
+}  // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/parser_impl_sampled_texture_type_test.cc b/src/tint/reader/wgsl/parser_impl_sampled_texture_type_test.cc
deleted file mode 100644
index a48c32c..0000000
--- a/src/tint/reader/wgsl/parser_impl_sampled_texture_type_test.cc
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright 2020 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/tint/reader/wgsl/parser_impl_test_helper.h"
-
-namespace tint::reader::wgsl {
-namespace {
-
-TEST_F(ParserImplTest, SampledTextureType_Invalid) {
-  auto p = parser("1234");
-  auto t = p->sampled_texture_type();
-  EXPECT_FALSE(t.matched);
-  EXPECT_FALSE(t.errored);
-  EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, SampledTextureType_1d) {
-  auto p = parser("texture_1d");
-  auto t = p->sampled_texture_type();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  EXPECT_EQ(t.value, ast::TextureDimension::k1d);
-  EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, SampledTextureType_2d) {
-  auto p = parser("texture_2d");
-  auto t = p->sampled_texture_type();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  EXPECT_EQ(t.value, ast::TextureDimension::k2d);
-  EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, SampledTextureType_2dArray) {
-  auto p = parser("texture_2d_array");
-  auto t = p->sampled_texture_type();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  EXPECT_EQ(t.value, ast::TextureDimension::k2dArray);
-  EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, SampledTextureType_3d) {
-  auto p = parser("texture_3d");
-  auto t = p->sampled_texture_type();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  EXPECT_EQ(t.value, ast::TextureDimension::k3d);
-  EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, SampledTextureType_Cube) {
-  auto p = parser("texture_cube");
-  auto t = p->sampled_texture_type();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  EXPECT_EQ(t.value, ast::TextureDimension::kCube);
-  EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, SampledTextureType_kCubeArray) {
-  auto p = parser("texture_cube_array");
-  auto t = p->sampled_texture_type();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  EXPECT_EQ(t.value, ast::TextureDimension::kCubeArray);
-  EXPECT_FALSE(p->has_error());
-}
-
-}  // namespace
-}  // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/parser_impl_sampler_test.cc b/src/tint/reader/wgsl/parser_impl_sampler_test.cc
new file mode 100644
index 0000000..7f1e564
--- /dev/null
+++ b/src/tint/reader/wgsl/parser_impl_sampler_test.cc
@@ -0,0 +1,54 @@
+// Copyright 2020 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/reader/wgsl/parser_impl_test_helper.h"
+
+namespace tint::reader::wgsl {
+namespace {
+
+TEST_F(ParserImplTest, SamplerType_Invalid) {
+    auto p = parser("1234");
+    auto t = p->sampler();
+    EXPECT_FALSE(t.matched);
+    EXPECT_FALSE(t.errored);
+    EXPECT_EQ(t.value, nullptr);
+    EXPECT_FALSE(p->has_error());
+}
+
+TEST_F(ParserImplTest, SamplerType_Sampler) {
+    auto p = parser("sampler");
+    auto t = p->sampler();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    ASSERT_NE(t.value, nullptr);
+    ASSERT_TRUE(t->Is<ast::Sampler>());
+    EXPECT_FALSE(t->As<ast::Sampler>()->IsComparison());
+    EXPECT_FALSE(p->has_error());
+    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 8u}}));
+}
+
+TEST_F(ParserImplTest, SamplerType_ComparisonSampler) {
+    auto p = parser("sampler_comparison");
+    auto t = p->sampler();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    ASSERT_NE(t.value, nullptr);
+    ASSERT_TRUE(t->Is<ast::Sampler>());
+    EXPECT_TRUE(t->As<ast::Sampler>()->IsComparison());
+    EXPECT_FALSE(p->has_error());
+    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 19u}}));
+}
+
+}  // namespace
+}  // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/parser_impl_sampler_type_test.cc b/src/tint/reader/wgsl/parser_impl_sampler_type_test.cc
deleted file mode 100644
index 230d58b..0000000
--- a/src/tint/reader/wgsl/parser_impl_sampler_type_test.cc
+++ /dev/null
@@ -1,54 +0,0 @@
-// Copyright 2020 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/tint/reader/wgsl/parser_impl_test_helper.h"
-
-namespace tint::reader::wgsl {
-namespace {
-
-TEST_F(ParserImplTest, SamplerType_Invalid) {
-  auto p = parser("1234");
-  auto t = p->sampler_type();
-  EXPECT_FALSE(t.matched);
-  EXPECT_FALSE(t.errored);
-  EXPECT_EQ(t.value, nullptr);
-  EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, SamplerType_Sampler) {
-  auto p = parser("sampler");
-  auto t = p->sampler_type();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  ASSERT_NE(t.value, nullptr);
-  ASSERT_TRUE(t->Is<ast::Sampler>());
-  EXPECT_FALSE(t->As<ast::Sampler>()->IsComparison());
-  EXPECT_FALSE(p->has_error());
-  EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 8u}}));
-}
-
-TEST_F(ParserImplTest, SamplerType_ComparisonSampler) {
-  auto p = parser("sampler_comparison");
-  auto t = p->sampler_type();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  ASSERT_NE(t.value, nullptr);
-  ASSERT_TRUE(t->Is<ast::Sampler>());
-  EXPECT_TRUE(t->As<ast::Sampler>()->IsComparison());
-  EXPECT_FALSE(p->has_error());
-  EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 19u}}));
-}
-
-}  // namespace
-}  // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/parser_impl_shift_expression_test.cc b/src/tint/reader/wgsl/parser_impl_shift_expression_test.cc
index 62a06ab..fd612b5 100644
--- a/src/tint/reader/wgsl/parser_impl_shift_expression_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_shift_expression_test.cc
@@ -18,90 +18,90 @@
 namespace {
 
 TEST_F(ParserImplTest, ShiftExpression_Parses_ShiftLeft) {
-  auto p = parser("a << true");
-  auto e = p->shift_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("a << true");
+    auto e = p->shift_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e->Is<ast::BinaryExpression>());
-  auto* rel = e->As<ast::BinaryExpression>();
-  EXPECT_EQ(ast::BinaryOp::kShiftLeft, rel->op);
+    ASSERT_TRUE(e->Is<ast::BinaryExpression>());
+    auto* rel = e->As<ast::BinaryExpression>();
+    EXPECT_EQ(ast::BinaryOp::kShiftLeft, rel->op);
 
-  ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
-  auto* ident = rel->lhs->As<ast::IdentifierExpression>();
-  EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
+    ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
+    auto* ident = rel->lhs->As<ast::IdentifierExpression>();
+    EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
-  ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
+    ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
+    ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
 }
 
 TEST_F(ParserImplTest, ShiftExpression_Parses_ShiftRight) {
-  auto p = parser("a >> true");
-  auto e = p->shift_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("a >> true");
+    auto e = p->shift_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e->Is<ast::BinaryExpression>());
-  auto* rel = e->As<ast::BinaryExpression>();
-  EXPECT_EQ(ast::BinaryOp::kShiftRight, rel->op);
+    ASSERT_TRUE(e->Is<ast::BinaryExpression>());
+    auto* rel = e->As<ast::BinaryExpression>();
+    EXPECT_EQ(ast::BinaryOp::kShiftRight, rel->op);
 
-  ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
-  auto* ident = rel->lhs->As<ast::IdentifierExpression>();
-  EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
+    ASSERT_TRUE(rel->lhs->Is<ast::IdentifierExpression>());
+    auto* ident = rel->lhs->As<ast::IdentifierExpression>();
+    EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
-  ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
+    ASSERT_TRUE(rel->rhs->Is<ast::BoolLiteralExpression>());
+    ASSERT_TRUE(rel->rhs->As<ast::BoolLiteralExpression>()->value);
 }
 
 TEST_F(ParserImplTest, ShiftExpression_InvalidSpaceLeft) {
-  auto p = parser("a < < true");
-  auto e = p->shift_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  ASSERT_NE(e.value, nullptr);
-  EXPECT_FALSE(e.value->Is<ast::BinaryExpression>());
+    auto p = parser("a < < true");
+    auto e = p->shift_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    ASSERT_NE(e.value, nullptr);
+    EXPECT_FALSE(e.value->Is<ast::BinaryExpression>());
 }
 
 TEST_F(ParserImplTest, ShiftExpression_InvalidSpaceRight) {
-  auto p = parser("a > > true");
-  auto e = p->shift_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  ASSERT_NE(e.value, nullptr);
-  EXPECT_FALSE(e.value->Is<ast::BinaryExpression>());
+    auto p = parser("a > > true");
+    auto e = p->shift_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    ASSERT_NE(e.value, nullptr);
+    EXPECT_FALSE(e.value->Is<ast::BinaryExpression>());
 }
 
 TEST_F(ParserImplTest, ShiftExpression_InvalidLHS) {
-  auto p = parser("if (a) {} << true");
-  auto e = p->shift_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_EQ(e.value, nullptr);
+    auto p = parser("if (a) {} << true");
+    auto e = p->shift_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_EQ(e.value, nullptr);
 }
 
 TEST_F(ParserImplTest, ShiftExpression_InvalidRHS) {
-  auto p = parser("true << if (a) {}");
-  auto e = p->shift_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:9: unable to parse right side of << expression");
+    auto p = parser("true << if (a) {}");
+    auto e = p->shift_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:9: unable to parse right side of << expression");
 }
 
 TEST_F(ParserImplTest, ShiftExpression_NoOr_ReturnsLHS) {
-  auto p = parser("a true");
-  auto e = p->shift_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::IdentifierExpression>());
+    auto p = parser("a true");
+    auto e = p->shift_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::IdentifierExpression>());
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_singular_expression_test.cc b/src/tint/reader/wgsl/parser_impl_singular_expression_test.cc
index 2d65652..4ab185b 100644
--- a/src/tint/reader/wgsl/parser_impl_singular_expression_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_singular_expression_test.cc
@@ -18,217 +18,214 @@
 namespace {
 
 TEST_F(ParserImplTest, SingularExpression_Array_ConstantIndex) {
-  auto p = parser("a[1]");
-  auto e = p->singular_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("a[1]");
+    auto e = p->singular_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e->Is<ast::IndexAccessorExpression>());
-  auto* idx = e->As<ast::IndexAccessorExpression>();
+    ASSERT_TRUE(e->Is<ast::IndexAccessorExpression>());
+    auto* idx = e->As<ast::IndexAccessorExpression>();
 
-  ASSERT_TRUE(idx->object->Is<ast::IdentifierExpression>());
-  auto* ident = idx->object->As<ast::IdentifierExpression>();
-  EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
+    ASSERT_TRUE(idx->object->Is<ast::IdentifierExpression>());
+    auto* ident = idx->object->As<ast::IdentifierExpression>();
+    EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_TRUE(idx->index->Is<ast::SintLiteralExpression>());
-  EXPECT_EQ(idx->index->As<ast::SintLiteralExpression>()->value, 1);
+    ASSERT_TRUE(idx->index->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(idx->index->As<ast::IntLiteralExpression>()->value, 1);
+    EXPECT_EQ(idx->index->As<ast::IntLiteralExpression>()->suffix,
+              ast::IntLiteralExpression::Suffix::kNone);
 }
 
 TEST_F(ParserImplTest, SingularExpression_Array_ExpressionIndex) {
-  auto p = parser("a[1 + b / 4]");
-  auto e = p->singular_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("a[1 + b / 4]");
+    auto e = p->singular_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e->Is<ast::IndexAccessorExpression>());
-  auto* idx = e->As<ast::IndexAccessorExpression>();
+    ASSERT_TRUE(e->Is<ast::IndexAccessorExpression>());
+    auto* idx = e->As<ast::IndexAccessorExpression>();
 
-  ASSERT_TRUE(idx->object->Is<ast::IdentifierExpression>());
-  auto* ident = idx->object->As<ast::IdentifierExpression>();
-  EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
+    ASSERT_TRUE(idx->object->Is<ast::IdentifierExpression>());
+    auto* ident = idx->object->As<ast::IdentifierExpression>();
+    EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_TRUE(idx->index->Is<ast::BinaryExpression>());
+    ASSERT_TRUE(idx->index->Is<ast::BinaryExpression>());
 }
 
 TEST_F(ParserImplTest, SingularExpression_Array_MissingIndex) {
-  auto p = parser("a[]");
-  auto e = p->singular_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:3: unable to parse expression inside []");
+    auto p = parser("a[]");
+    auto e = p->singular_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:3: unable to parse expression inside []");
 }
 
 TEST_F(ParserImplTest, SingularExpression_Array_MissingRightBrace) {
-  auto p = parser("a[1");
-  auto e = p->singular_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:4: expected ']' for index accessor");
+    auto p = parser("a[1");
+    auto e = p->singular_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:4: expected ']' for index accessor");
 }
 
 TEST_F(ParserImplTest, SingularExpression_Array_InvalidIndex) {
-  auto p = parser("a[if(a() {})]");
-  auto e = p->singular_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:3: unable to parse expression inside []");
+    auto p = parser("a[if(a() {})]");
+    auto e = p->singular_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:3: unable to parse expression inside []");
 }
 
 TEST_F(ParserImplTest, SingularExpression_Call_Empty) {
-  auto p = parser("a()");
-  auto e = p->singular_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("a()");
+    auto e = p->singular_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e->Is<ast::CallExpression>());
-  auto* c = e->As<ast::CallExpression>();
+    ASSERT_TRUE(e->Is<ast::CallExpression>());
+    auto* c = e->As<ast::CallExpression>();
 
-  EXPECT_EQ(c->target.name->symbol, p->builder().Symbols().Get("a"));
+    EXPECT_EQ(c->target.name->symbol, p->builder().Symbols().Get("a"));
 
-  EXPECT_EQ(c->args.size(), 0u);
+    EXPECT_EQ(c->args.size(), 0u);
 }
 
 TEST_F(ParserImplTest, SingularExpression_Call_WithArgs) {
-  auto p = parser("test(1, b, 2 + 3 / b)");
-  auto e = p->singular_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("test(1, b, 2 + 3 / b)");
+    auto e = p->singular_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e->Is<ast::CallExpression>());
-  auto* c = e->As<ast::CallExpression>();
+    ASSERT_TRUE(e->Is<ast::CallExpression>());
+    auto* c = e->As<ast::CallExpression>();
 
-  EXPECT_EQ(c->target.name->symbol, p->builder().Symbols().Get("test"));
+    EXPECT_EQ(c->target.name->symbol, p->builder().Symbols().Get("test"));
 
-  EXPECT_EQ(c->args.size(), 3u);
-  EXPECT_TRUE(c->args[0]->Is<ast::IntLiteralExpression>());
-  EXPECT_TRUE(c->args[1]->Is<ast::IdentifierExpression>());
-  EXPECT_TRUE(c->args[2]->Is<ast::BinaryExpression>());
+    EXPECT_EQ(c->args.size(), 3u);
+    EXPECT_TRUE(c->args[0]->Is<ast::IntLiteralExpression>());
+    EXPECT_TRUE(c->args[1]->Is<ast::IdentifierExpression>());
+    EXPECT_TRUE(c->args[2]->Is<ast::BinaryExpression>());
 }
 
 TEST_F(ParserImplTest, SingularExpression_Call_TrailingComma) {
-  auto p = parser("a(b, )");
-  auto e = p->singular_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("a(b, )");
+    auto e = p->singular_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e->Is<ast::CallExpression>());
-  auto* c = e->As<ast::CallExpression>();
-  EXPECT_EQ(c->args.size(), 1u);
+    ASSERT_TRUE(e->Is<ast::CallExpression>());
+    auto* c = e->As<ast::CallExpression>();
+    EXPECT_EQ(c->args.size(), 1u);
 }
 
 TEST_F(ParserImplTest, SingularExpression_Call_InvalidArg) {
-  auto p = parser("a(if(a) {})");
-  auto e = p->singular_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:3: expected ')' for function call");
+    auto p = parser("a(if(a) {})");
+    auto e = p->singular_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:3: expected ')' for function call");
 }
 
 TEST_F(ParserImplTest, SingularExpression_Call_MissingRightParen) {
-  auto p = parser("a(");
-  auto e = p->singular_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:3: expected ')' for function call");
+    auto p = parser("a(");
+    auto e = p->singular_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:3: expected ')' for function call");
 }
 
 TEST_F(ParserImplTest, SingularExpression_MemberAccessor) {
-  auto p = parser("a.b");
-  auto e = p->singular_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::MemberAccessorExpression>());
+    auto p = parser("a.b");
+    auto e = p->singular_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::MemberAccessorExpression>());
 
-  auto* m = e->As<ast::MemberAccessorExpression>();
-  ASSERT_TRUE(m->structure->Is<ast::IdentifierExpression>());
-  EXPECT_EQ(m->structure->As<ast::IdentifierExpression>()->symbol,
-            p->builder().Symbols().Get("a"));
+    auto* m = e->As<ast::MemberAccessorExpression>();
+    ASSERT_TRUE(m->structure->Is<ast::IdentifierExpression>());
+    EXPECT_EQ(m->structure->As<ast::IdentifierExpression>()->symbol,
+              p->builder().Symbols().Get("a"));
 
-  ASSERT_TRUE(m->member->Is<ast::IdentifierExpression>());
-  EXPECT_EQ(m->member->As<ast::IdentifierExpression>()->symbol,
-            p->builder().Symbols().Get("b"));
+    ASSERT_TRUE(m->member->Is<ast::IdentifierExpression>());
+    EXPECT_EQ(m->member->As<ast::IdentifierExpression>()->symbol, p->builder().Symbols().Get("b"));
 }
 
 TEST_F(ParserImplTest, SingularExpression_MemberAccesssor_InvalidIdent) {
-  auto p = parser("a.if");
-  auto e = p->singular_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:3: expected identifier for member accessor");
+    auto p = parser("a.if");
+    auto e = p->singular_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:3: expected identifier for member accessor");
 }
 
 TEST_F(ParserImplTest, SingularExpression_MemberAccessor_MissingIdent) {
-  auto p = parser("a.");
-  auto e = p->singular_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:3: expected identifier for member accessor");
+    auto p = parser("a.");
+    auto e = p->singular_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:3: expected identifier for member accessor");
 }
 
 TEST_F(ParserImplTest, SingularExpression_NonMatch_returnLHS) {
-  auto p = parser("a b");
-  auto e = p->singular_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::IdentifierExpression>());
+    auto p = parser("a b");
+    auto e = p->singular_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::IdentifierExpression>());
 }
 
 TEST_F(ParserImplTest, SingularExpression_Array_NestedIndexAccessor) {
-  auto p = parser("a[b[c]]");
-  auto e = p->singular_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("a[b[c]]");
+    auto e = p->singular_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  const auto* outer_accessor = e->As<ast::IndexAccessorExpression>();
-  ASSERT_TRUE(outer_accessor);
+    const auto* outer_accessor = e->As<ast::IndexAccessorExpression>();
+    ASSERT_TRUE(outer_accessor);
 
-  const auto* outer_object =
-      outer_accessor->object->As<ast::IdentifierExpression>();
-  ASSERT_TRUE(outer_object);
-  EXPECT_EQ(outer_object->symbol, p->builder().Symbols().Get("a"));
+    const auto* outer_object = outer_accessor->object->As<ast::IdentifierExpression>();
+    ASSERT_TRUE(outer_object);
+    EXPECT_EQ(outer_object->symbol, p->builder().Symbols().Get("a"));
 
-  const auto* inner_accessor =
-      outer_accessor->index->As<ast::IndexAccessorExpression>();
-  ASSERT_TRUE(inner_accessor);
+    const auto* inner_accessor = outer_accessor->index->As<ast::IndexAccessorExpression>();
+    ASSERT_TRUE(inner_accessor);
 
-  const auto* inner_object =
-      inner_accessor->object->As<ast::IdentifierExpression>();
-  ASSERT_TRUE(inner_object);
-  EXPECT_EQ(inner_object->symbol, p->builder().Symbols().Get("b"));
+    const auto* inner_object = inner_accessor->object->As<ast::IdentifierExpression>();
+    ASSERT_TRUE(inner_object);
+    EXPECT_EQ(inner_object->symbol, p->builder().Symbols().Get("b"));
 
-  const auto* index_expr =
-      inner_accessor->index->As<ast::IdentifierExpression>();
-  ASSERT_TRUE(index_expr);
-  EXPECT_EQ(index_expr->symbol, p->builder().Symbols().Get("c"));
+    const auto* index_expr = inner_accessor->index->As<ast::IdentifierExpression>();
+    ASSERT_TRUE(index_expr);
+    EXPECT_EQ(index_expr->symbol, p->builder().Symbols().Get("c"));
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_statement_test.cc b/src/tint/reader/wgsl/parser_impl_statement_test.cc
index d47ca5d..235c748 100644
--- a/src/tint/reader/wgsl/parser_impl_statement_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_statement_test.cc
@@ -21,257 +21,255 @@
 namespace {
 
 TEST_F(ParserImplTest, Statement) {
-  auto p = parser("return;");
-  auto e = p->statement();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  ASSERT_TRUE(e->Is<ast::ReturnStatement>());
+    auto p = parser("return;");
+    auto e = p->statement();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    ASSERT_TRUE(e->Is<ast::ReturnStatement>());
 }
 
 TEST_F(ParserImplTest, Statement_Semicolon) {
-  auto p = parser(";");
-  p->statement();
-  ASSERT_FALSE(p->has_error()) << p->error();
+    auto p = parser(";");
+    p->statement();
+    ASSERT_FALSE(p->has_error()) << p->error();
 }
 
 TEST_F(ParserImplTest, Statement_Return_NoValue) {
-  auto p = parser("return;");
-  auto e = p->statement();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  ASSERT_TRUE(e->Is<ast::ReturnStatement>());
-  auto* ret = e->As<ast::ReturnStatement>();
-  ASSERT_EQ(ret->value, nullptr);
+    auto p = parser("return;");
+    auto e = p->statement();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    ASSERT_TRUE(e->Is<ast::ReturnStatement>());
+    auto* ret = e->As<ast::ReturnStatement>();
+    ASSERT_EQ(ret->value, nullptr);
 }
 
 TEST_F(ParserImplTest, Statement_Return_Value) {
-  auto p = parser("return a + b * (.1 - .2);");
-  auto e = p->statement();
-  ASSERT_FALSE(p->has_error()) << p->error();
+    auto p = parser("return a + b * (.1 - .2);");
+    auto e = p->statement();
+    ASSERT_FALSE(p->has_error()) << p->error();
 
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  ASSERT_TRUE(e->Is<ast::ReturnStatement>());
-  auto* ret = e->As<ast::ReturnStatement>();
-  ASSERT_NE(ret->value, nullptr);
-  EXPECT_TRUE(ret->value->Is<ast::BinaryExpression>());
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    ASSERT_TRUE(e->Is<ast::ReturnStatement>());
+    auto* ret = e->As<ast::ReturnStatement>();
+    ASSERT_NE(ret->value, nullptr);
+    EXPECT_TRUE(ret->value->Is<ast::BinaryExpression>());
 }
 
 TEST_F(ParserImplTest, Statement_Return_MissingSemi) {
-  auto p = parser("return");
-  auto e = p->statement();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(e.errored);
-  EXPECT_FALSE(e.matched);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:7: expected ';' for return statement");
+    auto p = parser("return");
+    auto e = p->statement();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(e.errored);
+    EXPECT_FALSE(e.matched);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:7: expected ';' for return statement");
 }
 
 TEST_F(ParserImplTest, Statement_Return_Invalid) {
-  auto p = parser("return if(a) {};");
-  auto e = p->statement();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(e.errored);
-  EXPECT_FALSE(e.matched);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:8: expected ';' for return statement");
+    auto p = parser("return if(a) {};");
+    auto e = p->statement();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(e.errored);
+    EXPECT_FALSE(e.matched);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:8: expected ';' for return statement");
 }
 
 TEST_F(ParserImplTest, Statement_If) {
-  auto p = parser("if (a) {}");
-  auto e = p->statement();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  ASSERT_TRUE(e->Is<ast::IfStatement>());
+    auto p = parser("if (a) {}");
+    auto e = p->statement();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    ASSERT_TRUE(e->Is<ast::IfStatement>());
 }
 
 TEST_F(ParserImplTest, Statement_If_Invalid) {
-  auto p = parser("if (a) { fn main() -> {}}");
-  auto e = p->statement();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(e.errored);
-  EXPECT_FALSE(e.matched);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:10: expected '}'");
+    auto p = parser("if (a) { fn main() -> {}}");
+    auto e = p->statement();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(e.errored);
+    EXPECT_FALSE(e.matched);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:10: expected '}'");
 }
 
 TEST_F(ParserImplTest, Statement_Variable) {
-  auto p = parser("var a : i32 = 1;");
-  auto e = p->statement();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  ASSERT_TRUE(e->Is<ast::VariableDeclStatement>());
+    auto p = parser("var a : i32 = 1;");
+    auto e = p->statement();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    ASSERT_TRUE(e->Is<ast::VariableDeclStatement>());
 }
 
 TEST_F(ParserImplTest, Statement_Variable_Invalid) {
-  auto p = parser("var a : i32 =;");
-  auto e = p->statement();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(e.errored);
-  EXPECT_FALSE(e.matched);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:14: missing constructor for variable declaration");
+    auto p = parser("var a : i32 =;");
+    auto e = p->statement();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(e.errored);
+    EXPECT_FALSE(e.matched);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:14: missing constructor for variable declaration");
 }
 
 TEST_F(ParserImplTest, Statement_Variable_MissingSemicolon) {
-  auto p = parser("var a : i32");
-  auto e = p->statement();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(e.errored);
-  EXPECT_FALSE(e.matched);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:12: expected ';' for variable declaration");
+    auto p = parser("var a : i32");
+    auto e = p->statement();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(e.errored);
+    EXPECT_FALSE(e.matched);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:12: expected ';' for variable declaration");
 }
 
 TEST_F(ParserImplTest, Statement_Switch) {
-  auto p = parser("switch (a) {}");
-  auto e = p->statement();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  ASSERT_TRUE(e->Is<ast::SwitchStatement>());
+    auto p = parser("switch (a) {}");
+    auto e = p->statement();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    ASSERT_TRUE(e->Is<ast::SwitchStatement>());
 }
 
 TEST_F(ParserImplTest, Statement_Switch_Invalid) {
-  auto p = parser("switch (a) { case: {}}");
-  auto e = p->statement();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(e.errored);
-  EXPECT_FALSE(e.matched);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:18: unable to parse case selectors");
+    auto p = parser("switch (a) { case: {}}");
+    auto e = p->statement();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(e.errored);
+    EXPECT_FALSE(e.matched);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:18: unable to parse case selectors");
 }
 
 TEST_F(ParserImplTest, Statement_Loop) {
-  auto p = parser("loop {}");
-  auto e = p->statement();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  ASSERT_TRUE(e->Is<ast::LoopStatement>());
+    auto p = parser("loop {}");
+    auto e = p->statement();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    ASSERT_TRUE(e->Is<ast::LoopStatement>());
 }
 
 TEST_F(ParserImplTest, Statement_Loop_Invalid) {
-  auto p = parser("loop discard; }");
-  auto e = p->statement();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(e.errored);
-  EXPECT_FALSE(e.matched);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:6: expected '{' for loop");
+    auto p = parser("loop discard; }");
+    auto e = p->statement();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(e.errored);
+    EXPECT_FALSE(e.matched);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:6: expected '{' for loop");
 }
 
 TEST_F(ParserImplTest, Statement_Assignment) {
-  auto p = parser("a = b;");
-  auto e = p->statement();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  ASSERT_TRUE(e->Is<ast::AssignmentStatement>());
+    auto p = parser("a = b;");
+    auto e = p->statement();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    ASSERT_TRUE(e->Is<ast::AssignmentStatement>());
 }
 
 TEST_F(ParserImplTest, Statement_Assignment_Invalid) {
-  auto p = parser("a = if(b) {};");
-  auto e = p->statement();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(e.errored);
-  EXPECT_FALSE(e.matched);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:5: unable to parse right side of assignment");
+    auto p = parser("a = if(b) {};");
+    auto e = p->statement();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(e.errored);
+    EXPECT_FALSE(e.matched);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:5: unable to parse right side of assignment");
 }
 
 TEST_F(ParserImplTest, Statement_Assignment_MissingSemicolon) {
-  auto p = parser("a = b");
-  auto e = p->statement();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(e.errored);
-  EXPECT_FALSE(e.matched);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:6: expected ';' for assignment statement");
+    auto p = parser("a = b");
+    auto e = p->statement();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(e.errored);
+    EXPECT_FALSE(e.matched);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:6: expected ';' for assignment statement");
 }
 
 TEST_F(ParserImplTest, Statement_Break) {
-  auto p = parser("break;");
-  auto e = p->statement();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  ASSERT_TRUE(e->Is<ast::BreakStatement>());
+    auto p = parser("break;");
+    auto e = p->statement();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    ASSERT_TRUE(e->Is<ast::BreakStatement>());
 }
 
 TEST_F(ParserImplTest, Statement_Break_MissingSemicolon) {
-  auto p = parser("break");
-  auto e = p->statement();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(e.errored);
-  EXPECT_FALSE(e.matched);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:6: expected ';' for break statement");
+    auto p = parser("break");
+    auto e = p->statement();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(e.errored);
+    EXPECT_FALSE(e.matched);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:6: expected ';' for break statement");
 }
 
 TEST_F(ParserImplTest, Statement_Continue) {
-  auto p = parser("continue;");
-  auto e = p->statement();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  ASSERT_TRUE(e->Is<ast::ContinueStatement>());
+    auto p = parser("continue;");
+    auto e = p->statement();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    ASSERT_TRUE(e->Is<ast::ContinueStatement>());
 }
 
 TEST_F(ParserImplTest, Statement_Continue_MissingSemicolon) {
-  auto p = parser("continue");
-  auto e = p->statement();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(e.errored);
-  EXPECT_FALSE(e.matched);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:9: expected ';' for continue statement");
+    auto p = parser("continue");
+    auto e = p->statement();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(e.errored);
+    EXPECT_FALSE(e.matched);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:9: expected ';' for continue statement");
 }
 
 TEST_F(ParserImplTest, Statement_Discard) {
-  auto p = parser("discard;");
-  auto e = p->statement();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  ASSERT_TRUE(e->Is<ast::DiscardStatement>());
+    auto p = parser("discard;");
+    auto e = p->statement();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    ASSERT_TRUE(e->Is<ast::DiscardStatement>());
 }
 
 TEST_F(ParserImplTest, Statement_Discard_MissingSemicolon) {
-  auto p = parser("discard");
-  auto e = p->statement();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_TRUE(e.errored);
-  EXPECT_FALSE(e.matched);
-  EXPECT_EQ(p->error(), "1:8: expected ';' for discard statement");
+    auto p = parser("discard");
+    auto e = p->statement();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_TRUE(e.errored);
+    EXPECT_FALSE(e.matched);
+    EXPECT_EQ(p->error(), "1:8: expected ';' for discard statement");
 }
 
 TEST_F(ParserImplTest, Statement_Body) {
-  auto p = parser("{ var i: i32; }");
-  auto e = p->statement();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  ASSERT_TRUE(e->Is<ast::BlockStatement>());
-  EXPECT_TRUE(e->As<ast::BlockStatement>()
-                  ->statements[0]
-                  ->Is<ast::VariableDeclStatement>());
+    auto p = parser("{ var i: i32; }");
+    auto e = p->statement();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    ASSERT_TRUE(e->Is<ast::BlockStatement>());
+    EXPECT_TRUE(e->As<ast::BlockStatement>()->statements[0]->Is<ast::VariableDeclStatement>());
 }
 
 TEST_F(ParserImplTest, Statement_Body_Invalid) {
-  auto p = parser("{ fn main() -> {}}");
-  auto e = p->statement();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(e.errored);
-  EXPECT_FALSE(e.matched);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:3: expected '}'");
+    auto p = parser("{ fn main() -> {}}");
+    auto e = p->statement();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(e.errored);
+    EXPECT_FALSE(e.matched);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:3: expected '}'");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_statements_test.cc b/src/tint/reader/wgsl/parser_impl_statements_test.cc
index 2781974..b96a28a 100644
--- a/src/tint/reader/wgsl/parser_impl_statements_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_statements_test.cc
@@ -19,21 +19,21 @@
 namespace {
 
 TEST_F(ParserImplTest, Statements) {
-  auto p = parser("discard; return;");
-  auto e = p->expect_statements();
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_EQ(e->size(), 2u);
-  EXPECT_TRUE(e.value[0]->Is<ast::DiscardStatement>());
-  EXPECT_TRUE(e.value[1]->Is<ast::ReturnStatement>());
+    auto p = parser("discard; return;");
+    auto e = p->expect_statements();
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_EQ(e->size(), 2u);
+    EXPECT_TRUE(e.value[0]->Is<ast::DiscardStatement>());
+    EXPECT_TRUE(e.value[1]->Is<ast::ReturnStatement>());
 }
 
 TEST_F(ParserImplTest, Statements_Empty) {
-  auto p = parser("");
-  auto e = p->expect_statements();
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_EQ(e->size(), 0u);
+    auto p = parser("");
+    auto e = p->expect_statements();
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_EQ(e->size(), 0u);
 }
 
 }  // namespace
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 4d9110f..4abbe76 100644
--- a/src/tint/reader/wgsl/parser_impl_storage_class_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_storage_class_test.cc
@@ -18,49 +18,48 @@
 namespace {
 
 struct StorageClassData {
-  const char* input;
-  ast::StorageClass result;
+    const char* input;
+    ast::StorageClass result;
 };
 inline std::ostream& operator<<(std::ostream& out, StorageClassData data) {
-  out << std::string(data.input);
-  return out;
+    out << std::string(data.input);
+    return out;
 }
 
 class StorageClassTest : public ParserImplTestWithParam<StorageClassData> {};
 
 TEST_P(StorageClassTest, Parses) {
-  auto params = GetParam();
-  auto p = parser(params.input);
+    auto params = GetParam();
+    auto p = parser(params.input);
 
-  auto sc = p->expect_storage_class("test");
-  EXPECT_FALSE(sc.errored);
-  EXPECT_FALSE(p->has_error());
-  EXPECT_EQ(sc.value, params.result);
+    auto sc = p->expect_storage_class("test");
+    EXPECT_FALSE(sc.errored);
+    EXPECT_FALSE(p->has_error());
+    EXPECT_EQ(sc.value, params.result);
 
-  auto t = p->next();
-  EXPECT_TRUE(t.IsEof());
+    auto t = p->next();
+    EXPECT_TRUE(t.IsEof());
 }
 INSTANTIATE_TEST_SUITE_P(
     ParserImplTest,
     StorageClassTest,
-    testing::Values(
-        StorageClassData{"uniform", ast::StorageClass::kUniform},
-        StorageClassData{"workgroup", ast::StorageClass::kWorkgroup},
-        StorageClassData{"storage", ast::StorageClass::kStorage},
-        StorageClassData{"storage_buffer", ast::StorageClass::kStorage},
-        StorageClassData{"private", ast::StorageClass::kPrivate},
-        StorageClassData{"function", ast::StorageClass::kFunction}));
+    testing::Values(StorageClassData{"uniform", ast::StorageClass::kUniform},
+                    StorageClassData{"workgroup", ast::StorageClass::kWorkgroup},
+                    StorageClassData{"storage", ast::StorageClass::kStorage},
+                    StorageClassData{"storage_buffer", ast::StorageClass::kStorage},
+                    StorageClassData{"private", ast::StorageClass::kPrivate},
+                    StorageClassData{"function", ast::StorageClass::kFunction}));
 
 TEST_F(ParserImplTest, StorageClass_NoMatch) {
-  auto p = parser("not-a-storage-class");
-  auto sc = p->expect_storage_class("test");
-  EXPECT_EQ(sc.errored, true);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:1: invalid storage class for test");
+    auto p = parser("not-a-storage-class");
+    auto sc = p->expect_storage_class("test");
+    EXPECT_EQ(sc.errored, true);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:1: invalid storage class for test");
 
-  auto t = p->next();
-  EXPECT_TRUE(t.IsIdentifier());
-  EXPECT_EQ(t.to_str(), "not");
+    auto t = p->next();
+    EXPECT_TRUE(t.IsIdentifier());
+    EXPECT_EQ(t.to_str(), "not");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_storage_texture_test.cc b/src/tint/reader/wgsl/parser_impl_storage_texture_test.cc
new file mode 100644
index 0000000..6297a1e
--- /dev/null
+++ b/src/tint/reader/wgsl/parser_impl_storage_texture_test.cc
@@ -0,0 +1,65 @@
+// Copyright 2020 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/reader/wgsl/parser_impl_test_helper.h"
+
+namespace tint::reader::wgsl {
+namespace {
+
+TEST_F(ParserImplTest, StorageTextureType_Invalid) {
+    auto p = parser("abc");
+    auto t = p->storage_texture();
+    EXPECT_FALSE(t.matched);
+    EXPECT_FALSE(t.errored);
+    EXPECT_FALSE(p->has_error());
+}
+
+TEST_F(ParserImplTest, StorageTextureType_1d) {
+    auto p = parser("texture_storage_1d");
+    auto t = p->storage_texture();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    EXPECT_EQ(t.value, ast::TextureDimension::k1d);
+    EXPECT_FALSE(p->has_error());
+}
+
+TEST_F(ParserImplTest, StorageTextureType_2d) {
+    auto p = parser("texture_storage_2d");
+    auto t = p->storage_texture();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    EXPECT_EQ(t.value, ast::TextureDimension::k2d);
+    EXPECT_FALSE(p->has_error());
+}
+
+TEST_F(ParserImplTest, StorageTextureType_2dArray) {
+    auto p = parser("texture_storage_2d_array");
+    auto t = p->storage_texture();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    EXPECT_EQ(t.value, ast::TextureDimension::k2dArray);
+    EXPECT_FALSE(p->has_error());
+}
+
+TEST_F(ParserImplTest, StorageTextureType_3d) {
+    auto p = parser("texture_storage_3d");
+    auto t = p->storage_texture();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    EXPECT_EQ(t.value, ast::TextureDimension::k3d);
+    EXPECT_FALSE(p->has_error());
+}
+
+}  // namespace
+}  // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/parser_impl_storage_texture_type_test.cc b/src/tint/reader/wgsl/parser_impl_storage_texture_type_test.cc
deleted file mode 100644
index 8991198..0000000
--- a/src/tint/reader/wgsl/parser_impl_storage_texture_type_test.cc
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright 2020 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/tint/reader/wgsl/parser_impl_test_helper.h"
-
-namespace tint::reader::wgsl {
-namespace {
-
-TEST_F(ParserImplTest, StorageTextureType_Invalid) {
-  auto p = parser("abc");
-  auto t = p->storage_texture_type();
-  EXPECT_FALSE(t.matched);
-  EXPECT_FALSE(t.errored);
-  EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, StorageTextureType_1d) {
-  auto p = parser("texture_storage_1d");
-  auto t = p->storage_texture_type();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  EXPECT_EQ(t.value, ast::TextureDimension::k1d);
-  EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, StorageTextureType_2d) {
-  auto p = parser("texture_storage_2d");
-  auto t = p->storage_texture_type();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  EXPECT_EQ(t.value, ast::TextureDimension::k2d);
-  EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, StorageTextureType_2dArray) {
-  auto p = parser("texture_storage_2d_array");
-  auto t = p->storage_texture_type();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  EXPECT_EQ(t.value, ast::TextureDimension::k2dArray);
-  EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, StorageTextureType_3d) {
-  auto p = parser("texture_storage_3d");
-  auto t = p->storage_texture_type();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  EXPECT_EQ(t.value, ast::TextureDimension::k3d);
-  EXPECT_FALSE(p->has_error());
-}
-
-}  // namespace
-}  // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/parser_impl_struct_attribute_decl_test.cc b/src/tint/reader/wgsl/parser_impl_struct_attribute_decl_test.cc
index aabd841..a22abee 100644
--- a/src/tint/reader/wgsl/parser_impl_struct_attribute_decl_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_struct_attribute_decl_test.cc
@@ -19,54 +19,53 @@
 namespace {
 
 TEST_F(ParserImplTest, AttributeDecl_Parses) {
-  auto p = parser("@invariant");
-  auto attrs = p->attribute_list();
-  EXPECT_FALSE(p->has_error());
-  EXPECT_FALSE(attrs.errored);
-  EXPECT_TRUE(attrs.matched);
-  ASSERT_EQ(attrs.value.size(), 1u);
-  auto* invariant = attrs.value[0]->As<ast::Attribute>();
-  EXPECT_TRUE(invariant->Is<ast::InvariantAttribute>());
+    auto p = parser("@invariant");
+    auto attrs = p->attribute_list();
+    EXPECT_FALSE(p->has_error());
+    EXPECT_FALSE(attrs.errored);
+    EXPECT_TRUE(attrs.matched);
+    ASSERT_EQ(attrs.value.size(), 1u);
+    auto* invariant = attrs.value[0]->As<ast::Attribute>();
+    EXPECT_TRUE(invariant->Is<ast::InvariantAttribute>());
 }
 
 TEST_F(ParserImplTest, AttributeDecl_MissingParenLeft) {
-  auto p = parser("@location 1)");
-  auto attrs = p->attribute_list();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(attrs.errored);
-  EXPECT_FALSE(attrs.matched);
-  EXPECT_TRUE(attrs.value.empty());
-  EXPECT_EQ(p->error(), "1:11: expected '(' for location attribute");
+    auto p = parser("@location 1)");
+    auto attrs = p->attribute_list();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(attrs.errored);
+    EXPECT_FALSE(attrs.matched);
+    EXPECT_TRUE(attrs.value.empty());
+    EXPECT_EQ(p->error(), "1:11: expected '(' for location attribute");
 }
 
 TEST_F(ParserImplTest, AttributeDecl_MissingValue) {
-  auto p = parser("@location()");
-  auto attrs = p->attribute_list();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(attrs.errored);
-  EXPECT_FALSE(attrs.matched);
-  EXPECT_TRUE(attrs.value.empty());
-  EXPECT_EQ(p->error(),
-            "1:11: expected signed integer literal for location attribute");
+    auto p = parser("@location()");
+    auto attrs = p->attribute_list();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(attrs.errored);
+    EXPECT_FALSE(attrs.matched);
+    EXPECT_TRUE(attrs.value.empty());
+    EXPECT_EQ(p->error(), "1:11: expected signed integer literal for location attribute");
 }
 
 TEST_F(ParserImplTest, AttributeDecl_MissingParenRight) {
-  auto p = parser("@location(1");
-  auto attrs = p->attribute_list();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(attrs.errored);
-  EXPECT_FALSE(attrs.matched);
-  EXPECT_TRUE(attrs.value.empty());
-  EXPECT_EQ(p->error(), "1:12: expected ')' for location attribute");
+    auto p = parser("@location(1");
+    auto attrs = p->attribute_list();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(attrs.errored);
+    EXPECT_FALSE(attrs.matched);
+    EXPECT_TRUE(attrs.value.empty());
+    EXPECT_EQ(p->error(), "1:12: expected ')' for location attribute");
 }
 
 TEST_F(ParserImplTest, AttributeDecl_Invalidattribute) {
-  auto p = parser("@invalid");
-  auto attrs = p->attribute_list();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(attrs.errored);
-  EXPECT_FALSE(attrs.matched);
-  EXPECT_TRUE(attrs.value.empty());
+    auto p = parser("@invalid");
+    auto attrs = p->attribute_list();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(attrs.errored);
+    EXPECT_FALSE(attrs.matched);
+    EXPECT_TRUE(attrs.value.empty());
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_struct_body_decl_test.cc b/src/tint/reader/wgsl/parser_impl_struct_body_decl_test.cc
index d17f966..b02fb5a 100644
--- a/src/tint/reader/wgsl/parser_impl_struct_body_decl_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_struct_body_decl_test.cc
@@ -18,87 +18,85 @@
 namespace {
 
 TEST_F(ParserImplTest, StructBodyDecl_Parses) {
-  auto p = parser("{a : i32}");
+    auto p = parser("{a : i32}");
 
-  auto& builder = p->builder();
+    auto& builder = p->builder();
 
-  auto m = p->expect_struct_body_decl();
-  ASSERT_FALSE(p->has_error());
-  ASSERT_FALSE(m.errored);
-  ASSERT_EQ(m.value.size(), 1u);
+    auto m = p->expect_struct_body_decl();
+    ASSERT_FALSE(p->has_error());
+    ASSERT_FALSE(m.errored);
+    ASSERT_EQ(m.value.size(), 1u);
 
-  const auto* mem = m.value[0];
-  EXPECT_EQ(mem->symbol, builder.Symbols().Get("a"));
-  EXPECT_TRUE(mem->type->Is<ast::I32>());
-  EXPECT_EQ(mem->attributes.size(), 0u);
+    const auto* mem = m.value[0];
+    EXPECT_EQ(mem->symbol, builder.Symbols().Get("a"));
+    EXPECT_TRUE(mem->type->Is<ast::I32>());
+    EXPECT_EQ(mem->attributes.size(), 0u);
 }
 
 TEST_F(ParserImplTest, StructBodyDecl_Parses_TrailingComma) {
-  auto p = parser("{a : i32,}");
+    auto p = parser("{a : i32,}");
 
-  auto& builder = p->builder();
+    auto& builder = p->builder();
 
-  auto m = p->expect_struct_body_decl();
-  ASSERT_FALSE(p->has_error());
-  ASSERT_FALSE(m.errored);
-  ASSERT_EQ(m.value.size(), 1u);
+    auto m = p->expect_struct_body_decl();
+    ASSERT_FALSE(p->has_error());
+    ASSERT_FALSE(m.errored);
+    ASSERT_EQ(m.value.size(), 1u);
 
-  const auto* mem = m.value[0];
-  EXPECT_EQ(mem->symbol, builder.Symbols().Get("a"));
-  EXPECT_TRUE(mem->type->Is<ast::I32>());
-  EXPECT_EQ(mem->attributes.size(), 0u);
+    const auto* mem = m.value[0];
+    EXPECT_EQ(mem->symbol, builder.Symbols().Get("a"));
+    EXPECT_TRUE(mem->type->Is<ast::I32>());
+    EXPECT_EQ(mem->attributes.size(), 0u);
 }
 
 TEST_F(ParserImplTest, StructBodyDecl_ParsesEmpty) {
-  auto p = parser("{}");
-  auto m = p->expect_struct_body_decl();
-  ASSERT_FALSE(p->has_error());
-  ASSERT_FALSE(m.errored);
-  ASSERT_EQ(m.value.size(), 0u);
+    auto p = parser("{}");
+    auto m = p->expect_struct_body_decl();
+    ASSERT_FALSE(p->has_error());
+    ASSERT_FALSE(m.errored);
+    ASSERT_EQ(m.value.size(), 0u);
 }
 
 TEST_F(ParserImplTest, StructBodyDecl_InvalidAlign) {
-  auto p = parser(R"(
+    auto p = parser(R"(
 {
   @align(nan) a : i32,
 })");
-  auto m = p->expect_struct_body_decl();
-  ASSERT_TRUE(p->has_error());
-  ASSERT_TRUE(m.errored);
-  EXPECT_EQ(p->error(),
-            "3:10: expected signed integer literal for align attribute");
+    auto m = p->expect_struct_body_decl();
+    ASSERT_TRUE(p->has_error());
+    ASSERT_TRUE(m.errored);
+    EXPECT_EQ(p->error(), "3:10: expected signed integer literal for align attribute");
 }
 
 TEST_F(ParserImplTest, StructBodyDecl_InvalidSize) {
-  auto p = parser(R"(
+    auto p = parser(R"(
 {
   @size(nan) a : i32,
 })");
-  auto m = p->expect_struct_body_decl();
-  ASSERT_TRUE(p->has_error());
-  ASSERT_TRUE(m.errored);
-  EXPECT_EQ(p->error(),
-            "3:9: expected signed integer literal for size attribute");
+    auto m = p->expect_struct_body_decl();
+    ASSERT_TRUE(p->has_error());
+    ASSERT_TRUE(m.errored);
+    EXPECT_EQ(p->error(), "3:9: expected signed integer literal for size attribute");
 }
 
 TEST_F(ParserImplTest, StructBodyDecl_MissingClosingBracket) {
-  auto p = parser("{a : i32,");
-  auto m = p->expect_struct_body_decl();
-  ASSERT_TRUE(p->has_error());
-  ASSERT_TRUE(m.errored);
-  EXPECT_EQ(p->error(), "1:10: expected '}' for struct declaration");
+    auto p = parser("{a : i32,");
+    auto m = p->expect_struct_body_decl();
+    ASSERT_TRUE(p->has_error());
+    ASSERT_TRUE(m.errored);
+    EXPECT_EQ(p->error(), "1:10: expected '}' for struct declaration");
 }
 
 TEST_F(ParserImplTest, StructBodyDecl_InvalidToken) {
-  auto p = parser(R"(
+    auto p = parser(R"(
 {
   a : i32,
   1.23
 } )");
-  auto m = p->expect_struct_body_decl();
-  ASSERT_TRUE(p->has_error());
-  ASSERT_TRUE(m.errored);
-  EXPECT_EQ(p->error(), "4:3: expected '}' for struct declaration");
+    auto m = p->expect_struct_body_decl();
+    ASSERT_TRUE(p->has_error());
+    ASSERT_TRUE(m.errored);
+    EXPECT_EQ(p->error(), "4:3: expected '}' for struct declaration");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_struct_decl_test.cc b/src/tint/reader/wgsl/parser_impl_struct_decl_test.cc
index be0a4ed..106ffd5 100644
--- a/src/tint/reader/wgsl/parser_impl_struct_decl_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_struct_decl_test.cc
@@ -19,109 +19,107 @@
 namespace {
 
 TEST_F(ParserImplTest, StructDecl_Parses) {
-  auto p = parser(R"(
+    auto p = parser(R"(
 struct S {
   a : i32,
   b : f32,
 })");
-  auto s = p->struct_decl();
-  EXPECT_FALSE(p->has_error());
-  EXPECT_FALSE(s.errored);
-  EXPECT_TRUE(s.matched);
-  ASSERT_NE(s.value, nullptr);
-  ASSERT_EQ(s->name, p->builder().Symbols().Register("S"));
-  ASSERT_EQ(s->members.size(), 2u);
-  EXPECT_EQ(s->members[0]->symbol, p->builder().Symbols().Register("a"));
-  EXPECT_EQ(s->members[1]->symbol, p->builder().Symbols().Register("b"));
+    auto s = p->struct_decl();
+    EXPECT_FALSE(p->has_error());
+    EXPECT_FALSE(s.errored);
+    EXPECT_TRUE(s.matched);
+    ASSERT_NE(s.value, nullptr);
+    ASSERT_EQ(s->name, p->builder().Symbols().Register("S"));
+    ASSERT_EQ(s->members.size(), 2u);
+    EXPECT_EQ(s->members[0]->symbol, p->builder().Symbols().Register("a"));
+    EXPECT_EQ(s->members[1]->symbol, p->builder().Symbols().Register("b"));
 }
 
 TEST_F(ParserImplTest, StructDecl_Unicode_Parses) {
-  const std::string struct_ident =  // "𝓼𝓽𝓻𝓾𝓬𝓽𝓾𝓻𝓮"
-      "\xf0\x9d\x93\xbc\xf0\x9d\x93\xbd\xf0\x9d\x93\xbb\xf0\x9d\x93\xbe\xf0\x9d"
-      "\x93\xac\xf0\x9d\x93\xbd\xf0\x9d\x93\xbe\xf0\x9d\x93\xbb\xf0\x9d\x93"
-      "\xae";
-  const std::string member_a_ident =  // "𝕞𝕖𝕞𝕓𝕖𝕣_𝕒"
-      "\xf0\x9d\x95\x9e\xf0\x9d\x95\x96\xf0\x9d\x95\x9e\xf0\x9d\x95\x93\xf0\x9d"
-      "\x95\x96\xf0\x9d\x95\xa3\x5f\xf0\x9d\x95\x92";
-  const std::string member_b_ident =  // "𝔪𝔢𝔪𝔟𝔢𝔯_𝔟"
-      "\xf0\x9d\x94\xaa\xf0\x9d\x94\xa2\xf0\x9d\x94\xaa\xf0\x9d\x94\x9f\xf0\x9d"
-      "\x94\xa2\xf0\x9d\x94\xaf\x5f\xf0\x9d\x94\x9f";
+    const std::string struct_ident =  // "𝓼𝓽𝓻𝓾𝓬𝓽𝓾𝓻𝓮"
+        "\xf0\x9d\x93\xbc\xf0\x9d\x93\xbd\xf0\x9d\x93\xbb\xf0\x9d\x93\xbe\xf0\x9d"
+        "\x93\xac\xf0\x9d\x93\xbd\xf0\x9d\x93\xbe\xf0\x9d\x93\xbb\xf0\x9d\x93"
+        "\xae";
+    const std::string member_a_ident =  // "𝕞𝕖𝕞𝕓𝕖𝕣_𝕒"
+        "\xf0\x9d\x95\x9e\xf0\x9d\x95\x96\xf0\x9d\x95\x9e\xf0\x9d\x95\x93\xf0\x9d"
+        "\x95\x96\xf0\x9d\x95\xa3\x5f\xf0\x9d\x95\x92";
+    const std::string member_b_ident =  // "𝔪𝔢𝔪𝔟𝔢𝔯_𝔟"
+        "\xf0\x9d\x94\xaa\xf0\x9d\x94\xa2\xf0\x9d\x94\xaa\xf0\x9d\x94\x9f\xf0\x9d"
+        "\x94\xa2\xf0\x9d\x94\xaf\x5f\xf0\x9d\x94\x9f";
 
-  std::string src = R"(
+    std::string src = R"(
 struct $struct {
   $member_a : i32,
   $member_b : f32,
 })";
-  src = utils::ReplaceAll(src, "$struct", struct_ident);
-  src = utils::ReplaceAll(src, "$member_a", member_a_ident);
-  src = utils::ReplaceAll(src, "$member_b", member_b_ident);
+    src = utils::ReplaceAll(src, "$struct", struct_ident);
+    src = utils::ReplaceAll(src, "$member_a", member_a_ident);
+    src = utils::ReplaceAll(src, "$member_b", member_b_ident);
 
-  auto p = parser(src);
+    auto p = parser(src);
 
-  auto s = p->struct_decl();
-  EXPECT_FALSE(p->has_error());
-  EXPECT_FALSE(s.errored);
-  EXPECT_TRUE(s.matched);
-  ASSERT_NE(s.value, nullptr);
-  ASSERT_EQ(s->name, p->builder().Symbols().Register(struct_ident));
-  ASSERT_EQ(s->members.size(), 2u);
-  EXPECT_EQ(s->members[0]->symbol,
-            p->builder().Symbols().Register(member_a_ident));
-  EXPECT_EQ(s->members[1]->symbol,
-            p->builder().Symbols().Register(member_b_ident));
+    auto s = p->struct_decl();
+    EXPECT_FALSE(p->has_error());
+    EXPECT_FALSE(s.errored);
+    EXPECT_TRUE(s.matched);
+    ASSERT_NE(s.value, nullptr);
+    ASSERT_EQ(s->name, p->builder().Symbols().Register(struct_ident));
+    ASSERT_EQ(s->members.size(), 2u);
+    EXPECT_EQ(s->members[0]->symbol, p->builder().Symbols().Register(member_a_ident));
+    EXPECT_EQ(s->members[1]->symbol, p->builder().Symbols().Register(member_b_ident));
 }
 
 TEST_F(ParserImplTest, StructDecl_EmptyMembers) {
-  auto p = parser("struct S {}");
+    auto p = parser("struct S {}");
 
-  auto s = p->struct_decl();
-  EXPECT_FALSE(p->has_error());
-  EXPECT_FALSE(s.errored);
-  EXPECT_TRUE(s.matched);
-  ASSERT_NE(s.value, nullptr);
-  ASSERT_EQ(s->members.size(), 0u);
+    auto s = p->struct_decl();
+    EXPECT_FALSE(p->has_error());
+    EXPECT_FALSE(s.errored);
+    EXPECT_TRUE(s.matched);
+    ASSERT_NE(s.value, nullptr);
+    ASSERT_EQ(s->members.size(), 0u);
 }
 
 TEST_F(ParserImplTest, StructDecl_MissingIdent) {
-  auto p = parser("struct {}");
+    auto p = parser("struct {}");
 
-  auto s = p->struct_decl();
-  EXPECT_TRUE(s.errored);
-  EXPECT_FALSE(s.matched);
-  EXPECT_EQ(s.value, nullptr);
+    auto s = p->struct_decl();
+    EXPECT_TRUE(s.errored);
+    EXPECT_FALSE(s.matched);
+    EXPECT_EQ(s.value, nullptr);
 
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:8: expected identifier for struct declaration");
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:8: expected identifier for struct declaration");
 }
 
 TEST_F(ParserImplTest, StructDecl_MissingBracketLeft) {
-  auto p = parser("struct S }");
+    auto p = parser("struct S }");
 
-  auto s = p->struct_decl();
-  EXPECT_TRUE(s.errored);
-  EXPECT_FALSE(s.matched);
-  EXPECT_EQ(s.value, nullptr);
+    auto s = p->struct_decl();
+    EXPECT_TRUE(s.errored);
+    EXPECT_FALSE(s.matched);
+    EXPECT_EQ(s.value, nullptr);
 
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:10: expected '{' for struct declaration");
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:10: expected '{' for struct declaration");
 }
 
 // TODO(crbug.com/tint/1475): Remove this.
 TEST_F(ParserImplTest, DEPRECATED_StructDecl_Parses_WithSemicolons) {
-  auto p = parser(R"(
+    auto p = parser(R"(
 struct S {
   a : i32;
   b : f32;
 })");
-  auto s = p->struct_decl();
-  EXPECT_FALSE(p->has_error());
-  EXPECT_FALSE(s.errored);
-  EXPECT_TRUE(s.matched);
-  ASSERT_NE(s.value, nullptr);
-  ASSERT_EQ(s->name, p->builder().Symbols().Register("S"));
-  ASSERT_EQ(s->members.size(), 2u);
-  EXPECT_EQ(s->members[0]->symbol, p->builder().Symbols().Register("a"));
-  EXPECT_EQ(s->members[1]->symbol, p->builder().Symbols().Register("b"));
+    auto s = p->struct_decl();
+    EXPECT_FALSE(p->has_error());
+    EXPECT_FALSE(s.errored);
+    EXPECT_TRUE(s.matched);
+    ASSERT_NE(s.value, nullptr);
+    ASSERT_EQ(s->name, p->builder().Symbols().Register("S"));
+    ASSERT_EQ(s->members.size(), 2u);
+    EXPECT_EQ(s->members[0]->symbol, p->builder().Symbols().Register("a"));
+    EXPECT_EQ(s->members[1]->symbol, p->builder().Symbols().Register("b"));
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_struct_member_attribute_decl_test.cc b/src/tint/reader/wgsl/parser_impl_struct_member_attribute_decl_test.cc
index b779f58..2695074 100644
--- a/src/tint/reader/wgsl/parser_impl_struct_member_attribute_decl_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_struct_member_attribute_decl_test.cc
@@ -18,34 +18,33 @@
 namespace {
 
 TEST_F(ParserImplTest, AttributeDecl_EmptyStr) {
-  auto p = parser("");
-  auto attrs = p->attribute_list();
-  EXPECT_FALSE(p->has_error());
-  EXPECT_FALSE(attrs.errored);
-  EXPECT_FALSE(attrs.matched);
-  EXPECT_EQ(attrs.value.size(), 0u);
+    auto p = parser("");
+    auto attrs = p->attribute_list();
+    EXPECT_FALSE(p->has_error());
+    EXPECT_FALSE(attrs.errored);
+    EXPECT_FALSE(attrs.matched);
+    EXPECT_EQ(attrs.value.size(), 0u);
 }
 
 TEST_F(ParserImplTest, AttributeDecl_Single) {
-  auto p = parser("@size(4)");
-  auto attrs = p->attribute_list();
-  EXPECT_FALSE(p->has_error());
-  EXPECT_FALSE(attrs.errored);
-  EXPECT_TRUE(attrs.matched);
-  ASSERT_EQ(attrs.value.size(), 1u);
-  auto* attr = attrs.value[0]->As<ast::Attribute>();
-  ASSERT_NE(attr, nullptr);
-  EXPECT_TRUE(attr->Is<ast::StructMemberSizeAttribute>());
+    auto p = parser("@size(4)");
+    auto attrs = p->attribute_list();
+    EXPECT_FALSE(p->has_error());
+    EXPECT_FALSE(attrs.errored);
+    EXPECT_TRUE(attrs.matched);
+    ASSERT_EQ(attrs.value.size(), 1u);
+    auto* attr = attrs.value[0]->As<ast::Attribute>();
+    ASSERT_NE(attr, nullptr);
+    EXPECT_TRUE(attr->Is<ast::StructMemberSizeAttribute>());
 }
 
 TEST_F(ParserImplTest, AttributeDecl_InvalidAttribute) {
-  auto p = parser("@size(nan)");
-  auto attrs = p->attribute_list();
-  EXPECT_TRUE(p->has_error()) << p->error();
-  EXPECT_TRUE(attrs.errored);
-  EXPECT_FALSE(attrs.matched);
-  EXPECT_EQ(p->error(),
-            "1:7: expected signed integer literal for size attribute");
+    auto p = parser("@size(nan)");
+    auto attrs = p->attribute_list();
+    EXPECT_TRUE(p->has_error()) << p->error();
+    EXPECT_TRUE(attrs.errored);
+    EXPECT_FALSE(attrs.matched);
+    EXPECT_EQ(p->error(), "1:7: expected signed integer literal for size attribute");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_struct_member_attribute_test.cc b/src/tint/reader/wgsl/parser_impl_struct_member_attribute_test.cc
index f180da0..d185f37 100644
--- a/src/tint/reader/wgsl/parser_impl_struct_member_attribute_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_struct_member_attribute_test.cc
@@ -18,119 +18,115 @@
 namespace {
 
 TEST_F(ParserImplTest, Attribute_Size) {
-  auto p = parser("size(4)");
-  auto attr = p->attribute();
-  EXPECT_TRUE(attr.matched);
-  EXPECT_FALSE(attr.errored);
-  ASSERT_NE(attr.value, nullptr);
-  ASSERT_FALSE(p->has_error());
+    auto p = parser("size(4)");
+    auto attr = p->attribute();
+    EXPECT_TRUE(attr.matched);
+    EXPECT_FALSE(attr.errored);
+    ASSERT_NE(attr.value, nullptr);
+    ASSERT_FALSE(p->has_error());
 
-  auto* member_attr = attr.value->As<ast::Attribute>();
-  ASSERT_NE(member_attr, nullptr);
-  ASSERT_TRUE(member_attr->Is<ast::StructMemberSizeAttribute>());
+    auto* member_attr = attr.value->As<ast::Attribute>();
+    ASSERT_NE(member_attr, nullptr);
+    ASSERT_TRUE(member_attr->Is<ast::StructMemberSizeAttribute>());
 
-  auto* o = member_attr->As<ast::StructMemberSizeAttribute>();
-  EXPECT_EQ(o->size, 4u);
+    auto* o = member_attr->As<ast::StructMemberSizeAttribute>();
+    EXPECT_EQ(o->size, 4u);
 }
 
 TEST_F(ParserImplTest, Attribute_Size_MissingLeftParen) {
-  auto p = parser("size 4)");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:6: expected '(' for size attribute");
+    auto p = parser("size 4)");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:6: expected '(' for size attribute");
 }
 
 TEST_F(ParserImplTest, Attribute_Size_MissingRightParen) {
-  auto p = parser("size(4");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:7: expected ')' for size attribute");
+    auto p = parser("size(4");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:7: expected ')' for size attribute");
 }
 
 TEST_F(ParserImplTest, Attribute_Size_MissingValue) {
-  auto p = parser("size()");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(),
-            "1:6: expected signed integer literal for size attribute");
+    auto p = parser("size()");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:6: expected signed integer literal for size attribute");
 }
 
 TEST_F(ParserImplTest, Attribute_Size_MissingInvalid) {
-  auto p = parser("size(nan)");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(),
-            "1:6: expected signed integer literal for size attribute");
+    auto p = parser("size(nan)");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:6: expected signed integer literal for size attribute");
 }
 
 TEST_F(ParserImplTest, Attribute_Align) {
-  auto p = parser("align(4)");
-  auto attr = p->attribute();
-  EXPECT_TRUE(attr.matched);
-  EXPECT_FALSE(attr.errored);
-  ASSERT_NE(attr.value, nullptr);
-  ASSERT_FALSE(p->has_error());
+    auto p = parser("align(4)");
+    auto attr = p->attribute();
+    EXPECT_TRUE(attr.matched);
+    EXPECT_FALSE(attr.errored);
+    ASSERT_NE(attr.value, nullptr);
+    ASSERT_FALSE(p->has_error());
 
-  auto* member_attr = attr.value->As<ast::Attribute>();
-  ASSERT_NE(member_attr, nullptr);
-  ASSERT_TRUE(member_attr->Is<ast::StructMemberAlignAttribute>());
+    auto* member_attr = attr.value->As<ast::Attribute>();
+    ASSERT_NE(member_attr, nullptr);
+    ASSERT_TRUE(member_attr->Is<ast::StructMemberAlignAttribute>());
 
-  auto* o = member_attr->As<ast::StructMemberAlignAttribute>();
-  EXPECT_EQ(o->align, 4u);
+    auto* o = member_attr->As<ast::StructMemberAlignAttribute>();
+    EXPECT_EQ(o->align, 4u);
 }
 
 TEST_F(ParserImplTest, Attribute_Align_MissingLeftParen) {
-  auto p = parser("align 4)");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:7: expected '(' for align attribute");
+    auto p = parser("align 4)");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:7: expected '(' for align attribute");
 }
 
 TEST_F(ParserImplTest, Attribute_Align_MissingRightParen) {
-  auto p = parser("align(4");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:8: expected ')' for align attribute");
+    auto p = parser("align(4");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:8: expected ')' for align attribute");
 }
 
 TEST_F(ParserImplTest, Attribute_Align_MissingValue) {
-  auto p = parser("align()");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(),
-            "1:7: expected signed integer literal for align attribute");
+    auto p = parser("align()");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:7: expected signed integer literal for align attribute");
 }
 
 TEST_F(ParserImplTest, Attribute_Align_MissingInvalid) {
-  auto p = parser("align(nan)");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(),
-            "1:7: expected signed integer literal for align attribute");
+    auto p = parser("align(nan)");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:7: expected signed integer literal for align attribute");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_struct_member_test.cc b/src/tint/reader/wgsl/parser_impl_struct_member_test.cc
index 28ec44f..3e8b60e 100644
--- a/src/tint/reader/wgsl/parser_impl_struct_member_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_struct_member_test.cc
@@ -18,96 +18,95 @@
 namespace {
 
 TEST_F(ParserImplTest, StructMember_Parses) {
-  auto p = parser("a : i32,");
+    auto p = parser("a : i32,");
 
-  auto& builder = p->builder();
+    auto& builder = p->builder();
 
-  auto m = p->expect_struct_member();
-  ASSERT_FALSE(p->has_error());
-  ASSERT_FALSE(m.errored);
-  ASSERT_NE(m.value, nullptr);
+    auto m = p->expect_struct_member();
+    ASSERT_FALSE(p->has_error());
+    ASSERT_FALSE(m.errored);
+    ASSERT_NE(m.value, nullptr);
 
-  EXPECT_EQ(m->symbol, builder.Symbols().Get("a"));
-  EXPECT_TRUE(m->type->Is<ast::I32>());
-  EXPECT_EQ(m->attributes.size(), 0u);
+    EXPECT_EQ(m->symbol, builder.Symbols().Get("a"));
+    EXPECT_TRUE(m->type->Is<ast::I32>());
+    EXPECT_EQ(m->attributes.size(), 0u);
 
-  EXPECT_EQ(m->source.range, (Source::Range{{1u, 1u}, {1u, 2u}}));
-  EXPECT_EQ(m->type->source.range, (Source::Range{{1u, 5u}, {1u, 8u}}));
+    EXPECT_EQ(m->source.range, (Source::Range{{1u, 1u}, {1u, 2u}}));
+    EXPECT_EQ(m->type->source.range, (Source::Range{{1u, 5u}, {1u, 8u}}));
 }
 
 TEST_F(ParserImplTest, StructMember_ParsesWithAlignAttribute) {
-  auto p = parser("@align(2) a : i32,");
+    auto p = parser("@align(2) a : i32,");
 
-  auto& builder = p->builder();
+    auto& builder = p->builder();
 
-  auto m = p->expect_struct_member();
-  ASSERT_FALSE(p->has_error());
-  ASSERT_FALSE(m.errored);
-  ASSERT_NE(m.value, nullptr);
+    auto m = p->expect_struct_member();
+    ASSERT_FALSE(p->has_error());
+    ASSERT_FALSE(m.errored);
+    ASSERT_NE(m.value, nullptr);
 
-  EXPECT_EQ(m->symbol, builder.Symbols().Get("a"));
-  EXPECT_TRUE(m->type->Is<ast::I32>());
-  EXPECT_EQ(m->attributes.size(), 1u);
-  EXPECT_TRUE(m->attributes[0]->Is<ast::StructMemberAlignAttribute>());
-  EXPECT_EQ(m->attributes[0]->As<ast::StructMemberAlignAttribute>()->align, 2u);
+    EXPECT_EQ(m->symbol, builder.Symbols().Get("a"));
+    EXPECT_TRUE(m->type->Is<ast::I32>());
+    EXPECT_EQ(m->attributes.size(), 1u);
+    EXPECT_TRUE(m->attributes[0]->Is<ast::StructMemberAlignAttribute>());
+    EXPECT_EQ(m->attributes[0]->As<ast::StructMemberAlignAttribute>()->align, 2u);
 
-  EXPECT_EQ(m->source.range, (Source::Range{{1u, 11u}, {1u, 12u}}));
-  EXPECT_EQ(m->type->source.range, (Source::Range{{1u, 15u}, {1u, 18u}}));
+    EXPECT_EQ(m->source.range, (Source::Range{{1u, 11u}, {1u, 12u}}));
+    EXPECT_EQ(m->type->source.range, (Source::Range{{1u, 15u}, {1u, 18u}}));
 }
 
 TEST_F(ParserImplTest, StructMember_ParsesWithSizeAttribute) {
-  auto p = parser("@size(2) a : i32,");
+    auto p = parser("@size(2) a : i32,");
 
-  auto& builder = p->builder();
+    auto& builder = p->builder();
 
-  auto m = p->expect_struct_member();
-  ASSERT_FALSE(p->has_error());
-  ASSERT_FALSE(m.errored);
-  ASSERT_NE(m.value, nullptr);
+    auto m = p->expect_struct_member();
+    ASSERT_FALSE(p->has_error());
+    ASSERT_FALSE(m.errored);
+    ASSERT_NE(m.value, nullptr);
 
-  EXPECT_EQ(m->symbol, builder.Symbols().Get("a"));
-  EXPECT_TRUE(m->type->Is<ast::I32>());
-  EXPECT_EQ(m->attributes.size(), 1u);
-  EXPECT_TRUE(m->attributes[0]->Is<ast::StructMemberSizeAttribute>());
-  EXPECT_EQ(m->attributes[0]->As<ast::StructMemberSizeAttribute>()->size, 2u);
+    EXPECT_EQ(m->symbol, builder.Symbols().Get("a"));
+    EXPECT_TRUE(m->type->Is<ast::I32>());
+    EXPECT_EQ(m->attributes.size(), 1u);
+    EXPECT_TRUE(m->attributes[0]->Is<ast::StructMemberSizeAttribute>());
+    EXPECT_EQ(m->attributes[0]->As<ast::StructMemberSizeAttribute>()->size, 2u);
 
-  EXPECT_EQ(m->source.range, (Source::Range{{1u, 10u}, {1u, 11u}}));
-  EXPECT_EQ(m->type->source.range, (Source::Range{{1u, 14u}, {1u, 17u}}));
+    EXPECT_EQ(m->source.range, (Source::Range{{1u, 10u}, {1u, 11u}}));
+    EXPECT_EQ(m->type->source.range, (Source::Range{{1u, 14u}, {1u, 17u}}));
 }
 
 TEST_F(ParserImplTest, StructMember_ParsesWithMultipleattributes) {
-  auto p = parser(R"(@size(2)
+    auto p = parser(R"(@size(2)
 @align(4) a : i32,)");
 
-  auto& builder = p->builder();
+    auto& builder = p->builder();
 
-  auto m = p->expect_struct_member();
-  ASSERT_FALSE(p->has_error());
-  ASSERT_FALSE(m.errored);
-  ASSERT_NE(m.value, nullptr);
+    auto m = p->expect_struct_member();
+    ASSERT_FALSE(p->has_error());
+    ASSERT_FALSE(m.errored);
+    ASSERT_NE(m.value, nullptr);
 
-  EXPECT_EQ(m->symbol, builder.Symbols().Get("a"));
-  EXPECT_TRUE(m->type->Is<ast::I32>());
-  EXPECT_EQ(m->attributes.size(), 2u);
-  EXPECT_TRUE(m->attributes[0]->Is<ast::StructMemberSizeAttribute>());
-  EXPECT_EQ(m->attributes[0]->As<ast::StructMemberSizeAttribute>()->size, 2u);
-  EXPECT_TRUE(m->attributes[1]->Is<ast::StructMemberAlignAttribute>());
-  EXPECT_EQ(m->attributes[1]->As<ast::StructMemberAlignAttribute>()->align, 4u);
+    EXPECT_EQ(m->symbol, builder.Symbols().Get("a"));
+    EXPECT_TRUE(m->type->Is<ast::I32>());
+    EXPECT_EQ(m->attributes.size(), 2u);
+    EXPECT_TRUE(m->attributes[0]->Is<ast::StructMemberSizeAttribute>());
+    EXPECT_EQ(m->attributes[0]->As<ast::StructMemberSizeAttribute>()->size, 2u);
+    EXPECT_TRUE(m->attributes[1]->Is<ast::StructMemberAlignAttribute>());
+    EXPECT_EQ(m->attributes[1]->As<ast::StructMemberAlignAttribute>()->align, 4u);
 
-  EXPECT_EQ(m->source.range, (Source::Range{{2u, 11u}, {2u, 12u}}));
-  EXPECT_EQ(m->type->source.range, (Source::Range{{2u, 15u}, {2u, 18u}}));
+    EXPECT_EQ(m->source.range, (Source::Range{{2u, 11u}, {2u, 12u}}));
+    EXPECT_EQ(m->type->source.range, (Source::Range{{2u, 15u}, {2u, 18u}}));
 }
 
 TEST_F(ParserImplTest, StructMember_InvalidAttribute) {
-  auto p = parser("@size(nan) a : i32,");
+    auto p = parser("@size(nan) a : i32,");
 
-  auto m = p->expect_struct_member();
-  ASSERT_TRUE(m.errored);
-  ASSERT_EQ(m.value, nullptr);
+    auto m = p->expect_struct_member();
+    ASSERT_TRUE(m.errored);
+    ASSERT_EQ(m.value, nullptr);
 
-  ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(),
-            "1:7: expected signed integer literal for size attribute");
+    ASSERT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:7: expected signed integer literal for size attribute");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_switch_body_test.cc b/src/tint/reader/wgsl/parser_impl_switch_body_test.cc
index 3efb0c5..0f7384d 100644
--- a/src/tint/reader/wgsl/parser_impl_switch_body_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_switch_body_test.cc
@@ -18,251 +18,259 @@
 namespace {
 
 TEST_F(ParserImplTest, SwitchBody_Case) {
-  auto p = parser("case 1 { a = 4; }");
-  auto e = p->switch_body();
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::CaseStatement>());
-  EXPECT_FALSE(e->IsDefault());
-  auto* stmt = e->As<ast::CaseStatement>();
-  ASSERT_EQ(stmt->selectors.size(), 1u);
-  EXPECT_EQ(stmt->selectors[0]->ValueAsU32(), 1u);
-  ASSERT_EQ(e->body->statements.size(), 1u);
-  EXPECT_TRUE(e->body->statements[0]->Is<ast::AssignmentStatement>());
+    auto p = parser("case 1 { a = 4; }");
+    auto e = p->switch_body();
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::CaseStatement>());
+    EXPECT_FALSE(e->IsDefault());
+    auto* stmt = e->As<ast::CaseStatement>();
+    ASSERT_EQ(stmt->selectors.size(), 1u);
+    EXPECT_EQ(stmt->selectors[0]->value, 1);
+    EXPECT_EQ(stmt->selectors[0]->suffix, ast::IntLiteralExpression::Suffix::kNone);
+    ASSERT_EQ(e->body->statements.size(), 1u);
+    EXPECT_TRUE(e->body->statements[0]->Is<ast::AssignmentStatement>());
 }
 
 TEST_F(ParserImplTest, SwitchBody_Case_WithColon) {
-  auto p = parser("case 1: { a = 4; }");
-  auto e = p->switch_body();
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::CaseStatement>());
-  EXPECT_FALSE(e->IsDefault());
-  auto* stmt = e->As<ast::CaseStatement>();
-  ASSERT_EQ(stmt->selectors.size(), 1u);
-  EXPECT_EQ(stmt->selectors[0]->ValueAsU32(), 1u);
-  ASSERT_EQ(e->body->statements.size(), 1u);
-  EXPECT_TRUE(e->body->statements[0]->Is<ast::AssignmentStatement>());
+    auto p = parser("case 1: { a = 4; }");
+    auto e = p->switch_body();
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::CaseStatement>());
+    EXPECT_FALSE(e->IsDefault());
+    auto* stmt = e->As<ast::CaseStatement>();
+    ASSERT_EQ(stmt->selectors.size(), 1u);
+    EXPECT_EQ(stmt->selectors[0]->value, 1);
+    EXPECT_EQ(stmt->selectors[0]->suffix, ast::IntLiteralExpression::Suffix::kNone);
+    ASSERT_EQ(e->body->statements.size(), 1u);
+    EXPECT_TRUE(e->body->statements[0]->Is<ast::AssignmentStatement>());
 }
 
 TEST_F(ParserImplTest, SwitchBody_Case_TrailingComma) {
-  auto p = parser("case 1, 2, { }");
-  auto e = p->switch_body();
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::CaseStatement>());
-  EXPECT_FALSE(e->IsDefault());
-  auto* stmt = e->As<ast::CaseStatement>();
-  ASSERT_EQ(stmt->selectors.size(), 2u);
-  EXPECT_EQ(stmt->selectors[0]->ValueAsU32(), 1u);
-  EXPECT_EQ(stmt->selectors[1]->ValueAsU32(), 2u);
+    auto p = parser("case 1, 2, { }");
+    auto e = p->switch_body();
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::CaseStatement>());
+    EXPECT_FALSE(e->IsDefault());
+    auto* stmt = e->As<ast::CaseStatement>();
+    ASSERT_EQ(stmt->selectors.size(), 2u);
+    EXPECT_EQ(stmt->selectors[0]->value, 1);
+    EXPECT_EQ(stmt->selectors[0]->suffix, ast::IntLiteralExpression::Suffix::kNone);
+    EXPECT_EQ(stmt->selectors[1]->value, 2);
 }
 
 TEST_F(ParserImplTest, SwitchBody_Case_TrailingComma_WithColon) {
-  auto p = parser("case 1, 2,: { }");
-  auto e = p->switch_body();
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::CaseStatement>());
-  EXPECT_FALSE(e->IsDefault());
-  auto* stmt = e->As<ast::CaseStatement>();
-  ASSERT_EQ(stmt->selectors.size(), 2u);
-  EXPECT_EQ(stmt->selectors[0]->ValueAsU32(), 1u);
-  EXPECT_EQ(stmt->selectors[1]->ValueAsU32(), 2u);
+    auto p = parser("case 1, 2,: { }");
+    auto e = p->switch_body();
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::CaseStatement>());
+    EXPECT_FALSE(e->IsDefault());
+    auto* stmt = e->As<ast::CaseStatement>();
+    ASSERT_EQ(stmt->selectors.size(), 2u);
+    EXPECT_EQ(stmt->selectors[0]->value, 1);
+    EXPECT_EQ(stmt->selectors[0]->suffix, ast::IntLiteralExpression::Suffix::kNone);
+    EXPECT_EQ(stmt->selectors[1]->value, 2);
 }
 
 TEST_F(ParserImplTest, SwitchBody_Case_InvalidConstLiteral) {
-  auto p = parser("case a == 4: { a = 4; }");
-  auto e = p->switch_body();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(e.errored);
-  EXPECT_FALSE(e.matched);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:6: unable to parse case selectors");
+    auto p = parser("case a == 4: { a = 4; }");
+    auto e = p->switch_body();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(e.errored);
+    EXPECT_FALSE(e.matched);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:6: unable to parse case selectors");
 }
 
 TEST_F(ParserImplTest, SwitchBody_Case_InvalidSelector_bool) {
-  auto p = parser("case true: { a = 4; }");
-  auto e = p->switch_body();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(e.errored);
-  EXPECT_FALSE(e.matched);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:6: invalid case selector must be an integer value");
+    auto p = parser("case true: { a = 4; }");
+    auto e = p->switch_body();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(e.errored);
+    EXPECT_FALSE(e.matched);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:6: invalid case selector must be an integer value");
 }
 
 TEST_F(ParserImplTest, SwitchBody_Case_MissingConstLiteral) {
-  auto p = parser("case: { a = 4; }");
-  auto e = p->switch_body();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(e.errored);
-  EXPECT_FALSE(e.matched);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:5: unable to parse case selectors");
+    auto p = parser("case: { a = 4; }");
+    auto e = p->switch_body();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(e.errored);
+    EXPECT_FALSE(e.matched);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:5: unable to parse case selectors");
 }
 
 TEST_F(ParserImplTest, SwitchBody_Case_MissingBracketLeft) {
-  auto p = parser("case 1 a = 4; }");
-  auto e = p->switch_body();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(e.errored);
-  EXPECT_FALSE(e.matched);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:8: expected '{' for case statement");
+    auto p = parser("case 1 a = 4; }");
+    auto e = p->switch_body();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(e.errored);
+    EXPECT_FALSE(e.matched);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:8: expected '{' for case statement");
 }
 
 TEST_F(ParserImplTest, SwitchBody_Case_MissingBracketLeft_WithColon) {
-  auto p = parser("case 1: a = 4; }");
-  auto e = p->switch_body();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(e.errored);
-  EXPECT_FALSE(e.matched);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:9: expected '{' for case statement");
+    auto p = parser("case 1: a = 4; }");
+    auto e = p->switch_body();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(e.errored);
+    EXPECT_FALSE(e.matched);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:9: expected '{' for case statement");
 }
 
 TEST_F(ParserImplTest, SwitchBody_Case_MissingBracketRight) {
-  auto p = parser("case 1: { a = 4; ");
-  auto e = p->switch_body();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(e.errored);
-  EXPECT_FALSE(e.matched);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:18: expected '}' for case statement");
+    auto p = parser("case 1: { a = 4; ");
+    auto e = p->switch_body();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(e.errored);
+    EXPECT_FALSE(e.matched);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:18: expected '}' for case statement");
 }
 
 TEST_F(ParserImplTest, SwitchBody_Case_InvalidCaseBody) {
-  auto p = parser("case 1: { fn main() {} }");
-  auto e = p->switch_body();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(e.errored);
-  EXPECT_FALSE(e.matched);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:11: expected '}' for case statement");
+    auto p = parser("case 1: { fn main() {} }");
+    auto e = p->switch_body();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(e.errored);
+    EXPECT_FALSE(e.matched);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:11: expected '}' for case statement");
 }
 
 TEST_F(ParserImplTest, SwitchBody_Case_MultipleSelectors) {
-  auto p = parser("case 1, 2 { }");
-  auto e = p->switch_body();
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::CaseStatement>());
-  EXPECT_FALSE(e->IsDefault());
-  ASSERT_EQ(e->body->statements.size(), 0u);
-  ASSERT_EQ(e->selectors.size(), 2u);
-  ASSERT_EQ(e->selectors[0]->ValueAsI32(), 1);
-  ASSERT_EQ(e->selectors[1]->ValueAsI32(), 2);
+    auto p = parser("case 1, 2 { }");
+    auto e = p->switch_body();
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::CaseStatement>());
+    EXPECT_FALSE(e->IsDefault());
+    ASSERT_EQ(e->body->statements.size(), 0u);
+    ASSERT_EQ(e->selectors.size(), 2u);
+    ASSERT_EQ(e->selectors[0]->value, 1);
+    EXPECT_EQ(e->selectors[0]->suffix, ast::IntLiteralExpression::Suffix::kNone);
+    ASSERT_EQ(e->selectors[1]->value, 2);
+    EXPECT_EQ(e->selectors[1]->suffix, ast::IntLiteralExpression::Suffix::kNone);
 }
 
 TEST_F(ParserImplTest, SwitchBody_Case_MultipleSelectors_WithColon) {
-  auto p = parser("case 1, 2: { }");
-  auto e = p->switch_body();
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::CaseStatement>());
-  EXPECT_FALSE(e->IsDefault());
-  ASSERT_EQ(e->body->statements.size(), 0u);
-  ASSERT_EQ(e->selectors.size(), 2u);
-  ASSERT_EQ(e->selectors[0]->ValueAsI32(), 1);
-  ASSERT_EQ(e->selectors[1]->ValueAsI32(), 2);
+    auto p = parser("case 1, 2: { }");
+    auto e = p->switch_body();
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::CaseStatement>());
+    EXPECT_FALSE(e->IsDefault());
+    ASSERT_EQ(e->body->statements.size(), 0u);
+    ASSERT_EQ(e->selectors.size(), 2u);
+    ASSERT_EQ(e->selectors[0]->value, 1);
+    EXPECT_EQ(e->selectors[0]->suffix, ast::IntLiteralExpression::Suffix::kNone);
+    ASSERT_EQ(e->selectors[1]->value, 2);
+    EXPECT_EQ(e->selectors[1]->suffix, ast::IntLiteralExpression::Suffix::kNone);
 }
 
 TEST_F(ParserImplTest, SwitchBody_Case_MultipleSelectorsMissingComma) {
-  auto p = parser("case 1 2: { }");
-  auto e = p->switch_body();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(e.errored);
-  EXPECT_FALSE(e.matched);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:8: expected '{' for case statement");
+    auto p = parser("case 1 2: { }");
+    auto e = p->switch_body();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(e.errored);
+    EXPECT_FALSE(e.matched);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:8: expected '{' for case statement");
 }
 
 TEST_F(ParserImplTest, SwitchBody_Case_MultipleSelectorsStartsWithComma) {
-  auto p = parser("case , 1, 2: { }");
-  auto e = p->switch_body();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(e.errored);
-  EXPECT_FALSE(e.matched);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:6: unable to parse case selectors");
+    auto p = parser("case , 1, 2: { }");
+    auto e = p->switch_body();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(e.errored);
+    EXPECT_FALSE(e.matched);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:6: unable to parse case selectors");
 }
 
 TEST_F(ParserImplTest, SwitchBody_Default) {
-  auto p = parser("default { a = 4; }");
-  auto e = p->switch_body();
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::CaseStatement>());
-  EXPECT_TRUE(e->IsDefault());
-  ASSERT_EQ(e->body->statements.size(), 1u);
-  EXPECT_TRUE(e->body->statements[0]->Is<ast::AssignmentStatement>());
+    auto p = parser("default { a = 4; }");
+    auto e = p->switch_body();
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::CaseStatement>());
+    EXPECT_TRUE(e->IsDefault());
+    ASSERT_EQ(e->body->statements.size(), 1u);
+    EXPECT_TRUE(e->body->statements[0]->Is<ast::AssignmentStatement>());
 }
 
 TEST_F(ParserImplTest, SwitchBody_Default_WithColon) {
-  auto p = parser("default: { a = 4; }");
-  auto e = p->switch_body();
-  EXPECT_FALSE(p->has_error()) << p->error();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::CaseStatement>());
-  EXPECT_TRUE(e->IsDefault());
-  ASSERT_EQ(e->body->statements.size(), 1u);
-  EXPECT_TRUE(e->body->statements[0]->Is<ast::AssignmentStatement>());
+    auto p = parser("default: { a = 4; }");
+    auto e = p->switch_body();
+    EXPECT_FALSE(p->has_error()) << p->error();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::CaseStatement>());
+    EXPECT_TRUE(e->IsDefault());
+    ASSERT_EQ(e->body->statements.size(), 1u);
+    EXPECT_TRUE(e->body->statements[0]->Is<ast::AssignmentStatement>());
 }
 
 TEST_F(ParserImplTest, SwitchBody_Default_MissingBracketLeft) {
-  auto p = parser("default a = 4; }");
-  auto e = p->switch_body();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(e.errored);
-  EXPECT_FALSE(e.matched);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:9: expected '{' for case statement");
+    auto p = parser("default a = 4; }");
+    auto e = p->switch_body();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(e.errored);
+    EXPECT_FALSE(e.matched);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:9: expected '{' for case statement");
 }
 
 TEST_F(ParserImplTest, SwitchBody_Default_MissingBracketLeft_WithColon) {
-  auto p = parser("default: a = 4; }");
-  auto e = p->switch_body();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(e.errored);
-  EXPECT_FALSE(e.matched);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:10: expected '{' for case statement");
+    auto p = parser("default: a = 4; }");
+    auto e = p->switch_body();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(e.errored);
+    EXPECT_FALSE(e.matched);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:10: expected '{' for case statement");
 }
 
 TEST_F(ParserImplTest, SwitchBody_Default_MissingBracketRight) {
-  auto p = parser("default: { a = 4; ");
-  auto e = p->switch_body();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(e.errored);
-  EXPECT_FALSE(e.matched);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:19: expected '}' for case statement");
+    auto p = parser("default: { a = 4; ");
+    auto e = p->switch_body();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(e.errored);
+    EXPECT_FALSE(e.matched);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:19: expected '}' for case statement");
 }
 
 TEST_F(ParserImplTest, SwitchBody_Default_InvalidCaseBody) {
-  auto p = parser("default: { fn main() {} }");
-  auto e = p->switch_body();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(e.errored);
-  EXPECT_FALSE(e.matched);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_EQ(p->error(), "1:12: expected '}' for case statement");
+    auto p = parser("default: { fn main() {} }");
+    auto e = p->switch_body();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(e.errored);
+    EXPECT_FALSE(e.matched);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_EQ(p->error(), "1:12: expected '}' for case statement");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_switch_stmt_test.cc b/src/tint/reader/wgsl/parser_impl_switch_stmt_test.cc
index 1237467..c898b12 100644
--- a/src/tint/reader/wgsl/parser_impl_switch_stmt_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_switch_stmt_test.cc
@@ -18,112 +18,112 @@
 namespace {
 
 TEST_F(ParserImplTest, SwitchStmt_WithoutDefault) {
-  auto p = parser(R"(switch a {
+    auto p = parser(R"(switch a {
   case 1: {}
   case 2: {}
 })");
-  auto e = p->switch_stmt();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::SwitchStatement>());
-  ASSERT_EQ(e->body.size(), 2u);
-  EXPECT_FALSE(e->body[0]->IsDefault());
-  EXPECT_FALSE(e->body[1]->IsDefault());
+    auto e = p->switch_stmt();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::SwitchStatement>());
+    ASSERT_EQ(e->body.size(), 2u);
+    EXPECT_FALSE(e->body[0]->IsDefault());
+    EXPECT_FALSE(e->body[1]->IsDefault());
 }
 
 TEST_F(ParserImplTest, SwitchStmt_Empty) {
-  auto p = parser("switch a { }");
-  auto e = p->switch_stmt();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::SwitchStatement>());
-  ASSERT_EQ(e->body.size(), 0u);
+    auto p = parser("switch a { }");
+    auto e = p->switch_stmt();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::SwitchStatement>());
+    ASSERT_EQ(e->body.size(), 0u);
 }
 
 TEST_F(ParserImplTest, SwitchStmt_DefaultInMiddle) {
-  auto p = parser(R"(switch a {
+    auto p = parser(R"(switch a {
   case 1: {}
   default: {}
   case 2: {}
 })");
-  auto e = p->switch_stmt();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::SwitchStatement>());
+    auto e = p->switch_stmt();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::SwitchStatement>());
 
-  ASSERT_EQ(e->body.size(), 3u);
-  ASSERT_FALSE(e->body[0]->IsDefault());
-  ASSERT_TRUE(e->body[1]->IsDefault());
-  ASSERT_FALSE(e->body[2]->IsDefault());
+    ASSERT_EQ(e->body.size(), 3u);
+    ASSERT_FALSE(e->body[0]->IsDefault());
+    ASSERT_TRUE(e->body[1]->IsDefault());
+    ASSERT_FALSE(e->body[2]->IsDefault());
 }
 
 TEST_F(ParserImplTest, SwitchStmt_WithParens) {
-  auto p = parser("switch(a+b) { }");
-  auto e = p->switch_stmt();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::SwitchStatement>());
-  ASSERT_EQ(e->body.size(), 0u);
+    auto p = parser("switch(a+b) { }");
+    auto e = p->switch_stmt();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::SwitchStatement>());
+    ASSERT_EQ(e->body.size(), 0u);
 }
 
 TEST_F(ParserImplTest, SwitchStmt_InvalidExpression) {
-  auto p = parser("switch a=b {}");
-  auto e = p->switch_stmt();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:9: expected '{' for switch statement");
+    auto p = parser("switch a=b {}");
+    auto e = p->switch_stmt();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:9: expected '{' for switch statement");
 }
 
 TEST_F(ParserImplTest, SwitchStmt_MissingExpression) {
-  auto p = parser("switch {}");
-  auto e = p->switch_stmt();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:8: unable to parse selector expression");
+    auto p = parser("switch {}");
+    auto e = p->switch_stmt();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:8: unable to parse selector expression");
 }
 
 TEST_F(ParserImplTest, SwitchStmt_MissingBracketLeft) {
-  auto p = parser("switch a }");
-  auto e = p->switch_stmt();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:10: expected '{' for switch statement");
+    auto p = parser("switch a }");
+    auto e = p->switch_stmt();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:10: expected '{' for switch statement");
 }
 
 TEST_F(ParserImplTest, SwitchStmt_MissingBracketRight) {
-  auto p = parser("switch a {");
-  auto e = p->switch_stmt();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:11: expected '}' for switch statement");
+    auto p = parser("switch a {");
+    auto e = p->switch_stmt();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:11: expected '}' for switch statement");
 }
 
 TEST_F(ParserImplTest, SwitchStmt_InvalidBody) {
-  auto p = parser(R"(switch a {
+    auto p = parser(R"(switch a {
   case: {}
 })");
-  auto e = p->switch_stmt();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "2:7: unable to parse case selectors");
+    auto e = p->switch_stmt();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "2:7: unable to parse case selectors");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_test.cc b/src/tint/reader/wgsl/parser_impl_test.cc
index 5caa96b..33b279c 100644
--- a/src/tint/reader/wgsl/parser_impl_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_test.cc
@@ -18,25 +18,25 @@
 namespace {
 
 TEST_F(ParserImplTest, Empty) {
-  auto p = parser("");
-  ASSERT_TRUE(p->Parse()) << p->error();
+    auto p = parser("");
+    ASSERT_TRUE(p->Parse()) << p->error();
 }
 
 TEST_F(ParserImplTest, Parses) {
-  auto p = parser(R"(
+    auto p = parser(R"(
 @stage(fragment)
 fn main() -> @location(0) vec4<f32> {
   return vec4<f32>(.4, .2, .3, 1);
 }
 )");
-  ASSERT_TRUE(p->Parse()) << p->error();
+    ASSERT_TRUE(p->Parse()) << p->error();
 
-  Program program = p->program();
-  ASSERT_EQ(1u, program.AST().Functions().size());
+    Program program = p->program();
+    ASSERT_EQ(1u, program.AST().Functions().size());
 }
 
 TEST_F(ParserImplTest, Parses_ExtraSemicolons) {
-  auto p = parser(R"(
+    auto p = parser(R"(
 ;
 struct S {
   a : f32,
@@ -49,63 +49,63 @@
 };;
 ;
 )");
-  ASSERT_TRUE(p->Parse()) << p->error();
+    ASSERT_TRUE(p->Parse()) << p->error();
 
-  Program program = p->program();
-  ASSERT_EQ(1u, program.AST().Functions().size());
-  ASSERT_EQ(1u, program.AST().TypeDecls().size());
+    Program program = p->program();
+    ASSERT_EQ(1u, program.AST().Functions().size());
+    ASSERT_EQ(1u, program.AST().TypeDecls().size());
 }
 
 TEST_F(ParserImplTest, HandlesError) {
-  auto p = parser(R"(
+    auto p = parser(R"(
 fn main() ->  {  // missing return type
   return;
 })");
 
-  ASSERT_FALSE(p->Parse());
-  ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "2:15: unable to determine function return type");
+    ASSERT_FALSE(p->Parse());
+    ASSERT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "2:15: unable to determine function return type");
 }
 
 TEST_F(ParserImplTest, HandlesUnexpectedToken) {
-  auto p = parser(R"(
+    auto p = parser(R"(
 fn main() {
 }
 foobar
 )");
 
-  ASSERT_FALSE(p->Parse());
-  ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "4:1: unexpected token");
+    ASSERT_FALSE(p->Parse());
+    ASSERT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "4:1: unexpected token");
 }
 
 TEST_F(ParserImplTest, HandlesBadToken_InMiddle) {
-  auto p = parser(R"(
+    auto p = parser(R"(
 fn main() {
   let f = 0x1p500000000000; // Exponent too big for hex float
   return;
 })");
 
-  ASSERT_FALSE(p->Parse());
-  ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "3:11: exponent is too large for hex float");
+    ASSERT_FALSE(p->Parse());
+    ASSERT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "3:11: exponent is too large for hex float");
 }
 
 TEST_F(ParserImplTest, HandlesBadToken_AtModuleScope) {
-  auto p = parser(R"(
+    auto p = parser(R"(
 fn main() {
   return;
 }
 0x1p5000000000000
 )");
 
-  ASSERT_FALSE(p->Parse());
-  ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "5:1: exponent is too large for hex float");
+    ASSERT_FALSE(p->Parse());
+    ASSERT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "5:1: exponent is too large for hex float");
 }
 
 TEST_F(ParserImplTest, Comments_TerminatedBlockComment) {
-  auto p = parser(R"(
+    auto p = parser(R"(
 /**
  * Here is my shader.
  *
@@ -120,20 +120,20 @@
   return/*block_comments_delimit_tokens*/vec4<f32>(.4, .2, .3, 1);
 }/* block comments are OK at EOF...*/)");
 
-  ASSERT_TRUE(p->Parse()) << p->error();
-  ASSERT_EQ(1u, p->program().AST().Functions().size());
+    ASSERT_TRUE(p->Parse()) << p->error();
+    ASSERT_EQ(1u, p->program().AST().Functions().size());
 }
 
 TEST_F(ParserImplTest, Comments_UnterminatedBlockComment) {
-  auto p = parser(R"(
+    auto p = parser(R"(
 @stage(fragment)
 fn main() -> @location(0) vec4<f32> {
   return vec4<f32>(.4, .2, .3, 1);
 } /* unterminated block comments are invalid ...)");
 
-  ASSERT_FALSE(p->Parse());
-  ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "5:3: unterminated block comment") << p->error();
+    ASSERT_FALSE(p->Parse());
+    ASSERT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "5:3: unterminated block comment") << p->error();
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_test_helper.h b/src/tint/reader/wgsl/parser_impl_test_helper.h
index 8823fe1..f6ee8ea 100644
--- a/src/tint/reader/wgsl/parser_impl_test_helper.h
+++ b/src/tint/reader/wgsl/parser_impl_test_helper.h
@@ -27,46 +27,45 @@
 
 /// WGSL Parser test class
 class ParserImplTest : public testing::Test, public ProgramBuilder {
- public:
-  /// Constructor
-  ParserImplTest();
-  ~ParserImplTest() override;
+  public:
+    /// Constructor
+    ParserImplTest();
+    ~ParserImplTest() override;
 
-  /// Retrieves the parser from the helper
-  /// @param str the string to parse
-  /// @returns the parser implementation
-  std::unique_ptr<ParserImpl> parser(const std::string& str) {
-    auto file = std::make_unique<Source::File>("test.wgsl", str);
-    auto impl = std::make_unique<ParserImpl>(file.get());
-    files_.emplace_back(std::move(file));
-    return impl;
-  }
+    /// Retrieves the parser from the helper
+    /// @param str the string to parse
+    /// @returns the parser implementation
+    std::unique_ptr<ParserImpl> parser(const std::string& str) {
+        auto file = std::make_unique<Source::File>("test.wgsl", str);
+        auto impl = std::make_unique<ParserImpl>(file.get());
+        files_.emplace_back(std::move(file));
+        return impl;
+    }
 
- private:
-  std::vector<std::unique_ptr<Source::File>> files_;
+  private:
+    std::vector<std::unique_ptr<Source::File>> files_;
 };
 
 /// WGSL Parser test class with param
 template <typename T>
-class ParserImplTestWithParam : public testing::TestWithParam<T>,
-                                public ProgramBuilder {
- public:
-  /// Constructor
-  ParserImplTestWithParam() = default;
-  ~ParserImplTestWithParam() override = default;
+class ParserImplTestWithParam : public testing::TestWithParam<T>, public ProgramBuilder {
+  public:
+    /// Constructor
+    ParserImplTestWithParam() = default;
+    ~ParserImplTestWithParam() override = default;
 
-  /// Retrieves the parser from the helper
-  /// @param str the string to parse
-  /// @returns the parser implementation
-  std::unique_ptr<ParserImpl> parser(const std::string& str) {
-    auto file = std::make_unique<Source::File>("test.wgsl", str);
-    auto impl = std::make_unique<ParserImpl>(file.get());
-    files_.emplace_back(std::move(file));
-    return impl;
-  }
+    /// Retrieves the parser from the helper
+    /// @param str the string to parse
+    /// @returns the parser implementation
+    std::unique_ptr<ParserImpl> parser(const std::string& str) {
+        auto file = std::make_unique<Source::File>("test.wgsl", str);
+        auto impl = std::make_unique<ParserImpl>(file.get());
+        files_.emplace_back(std::move(file));
+        return impl;
+    }
 
- private:
-  std::vector<std::unique_ptr<Source::File>> files_;
+  private:
+    std::vector<std::unique_ptr<Source::File>> files_;
 };
 
 }  // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/parser_impl_texel_format_test.cc b/src/tint/reader/wgsl/parser_impl_texel_format_test.cc
index d1c6e7a..e7afb9e 100644
--- a/src/tint/reader/wgsl/parser_impl_texel_format_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_texel_format_test.cc
@@ -18,139 +18,139 @@
 namespace {
 
 TEST_F(ParserImplTest, ImageStorageType_Invalid) {
-  auto p = parser("1234");
-  auto t = p->expect_texel_format("test");
-  EXPECT_TRUE(t.errored);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:1: invalid format for test");
+    auto p = parser("1234");
+    auto t = p->expect_texel_format("test");
+    EXPECT_TRUE(t.errored);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:1: invalid format for test");
 }
 
 TEST_F(ParserImplTest, ImageStorageType_R32Uint) {
-  auto p = parser("r32uint");
-  auto t = p->expect_texel_format("test");
-  EXPECT_FALSE(t.errored);
-  EXPECT_EQ(t.value, ast::TexelFormat::kR32Uint);
-  EXPECT_FALSE(p->has_error());
+    auto p = parser("r32uint");
+    auto t = p->expect_texel_format("test");
+    EXPECT_FALSE(t.errored);
+    EXPECT_EQ(t.value, ast::TexelFormat::kR32Uint);
+    EXPECT_FALSE(p->has_error());
 }
 
 TEST_F(ParserImplTest, ImageStorageType_R32Sint) {
-  auto p = parser("r32sint");
-  auto t = p->expect_texel_format("test");
-  EXPECT_FALSE(t.errored);
-  EXPECT_EQ(t.value, ast::TexelFormat::kR32Sint);
-  EXPECT_FALSE(p->has_error());
+    auto p = parser("r32sint");
+    auto t = p->expect_texel_format("test");
+    EXPECT_FALSE(t.errored);
+    EXPECT_EQ(t.value, ast::TexelFormat::kR32Sint);
+    EXPECT_FALSE(p->has_error());
 }
 
 TEST_F(ParserImplTest, ImageStorageType_R32Float) {
-  auto p = parser("r32float");
-  auto t = p->expect_texel_format("test");
-  EXPECT_FALSE(t.errored);
-  EXPECT_EQ(t.value, ast::TexelFormat::kR32Float);
-  EXPECT_FALSE(p->has_error());
+    auto p = parser("r32float");
+    auto t = p->expect_texel_format("test");
+    EXPECT_FALSE(t.errored);
+    EXPECT_EQ(t.value, ast::TexelFormat::kR32Float);
+    EXPECT_FALSE(p->has_error());
 }
 
 TEST_F(ParserImplTest, ImageStorageType_Rgba8Unorm) {
-  auto p = parser("rgba8unorm");
-  auto t = p->expect_texel_format("test");
-  EXPECT_FALSE(t.errored);
-  EXPECT_EQ(t.value, ast::TexelFormat::kRgba8Unorm);
-  EXPECT_FALSE(p->has_error());
+    auto p = parser("rgba8unorm");
+    auto t = p->expect_texel_format("test");
+    EXPECT_FALSE(t.errored);
+    EXPECT_EQ(t.value, ast::TexelFormat::kRgba8Unorm);
+    EXPECT_FALSE(p->has_error());
 }
 
 TEST_F(ParserImplTest, ImageStorageType_Rgba8Snorm) {
-  auto p = parser("rgba8snorm");
-  auto t = p->expect_texel_format("test");
-  EXPECT_FALSE(t.errored);
-  EXPECT_EQ(t.value, ast::TexelFormat::kRgba8Snorm);
-  EXPECT_FALSE(p->has_error());
+    auto p = parser("rgba8snorm");
+    auto t = p->expect_texel_format("test");
+    EXPECT_FALSE(t.errored);
+    EXPECT_EQ(t.value, ast::TexelFormat::kRgba8Snorm);
+    EXPECT_FALSE(p->has_error());
 }
 
 TEST_F(ParserImplTest, ImageStorageType_Rgba8Uint) {
-  auto p = parser("rgba8uint");
-  auto t = p->expect_texel_format("test");
-  EXPECT_FALSE(t.errored);
-  EXPECT_EQ(t.value, ast::TexelFormat::kRgba8Uint);
-  EXPECT_FALSE(p->has_error());
+    auto p = parser("rgba8uint");
+    auto t = p->expect_texel_format("test");
+    EXPECT_FALSE(t.errored);
+    EXPECT_EQ(t.value, ast::TexelFormat::kRgba8Uint);
+    EXPECT_FALSE(p->has_error());
 }
 
 TEST_F(ParserImplTest, ImageStorageType_Rgba8Sint) {
-  auto p = parser("rgba8sint");
-  auto t = p->expect_texel_format("test");
-  EXPECT_FALSE(t.errored);
-  EXPECT_EQ(t.value, ast::TexelFormat::kRgba8Sint);
-  EXPECT_FALSE(p->has_error());
+    auto p = parser("rgba8sint");
+    auto t = p->expect_texel_format("test");
+    EXPECT_FALSE(t.errored);
+    EXPECT_EQ(t.value, ast::TexelFormat::kRgba8Sint);
+    EXPECT_FALSE(p->has_error());
 }
 
 TEST_F(ParserImplTest, ImageStorageType_Rg32Uint) {
-  auto p = parser("rg32uint");
-  auto t = p->expect_texel_format("test");
-  EXPECT_FALSE(t.errored);
-  EXPECT_EQ(t.value, ast::TexelFormat::kRg32Uint);
-  EXPECT_FALSE(p->has_error());
+    auto p = parser("rg32uint");
+    auto t = p->expect_texel_format("test");
+    EXPECT_FALSE(t.errored);
+    EXPECT_EQ(t.value, ast::TexelFormat::kRg32Uint);
+    EXPECT_FALSE(p->has_error());
 }
 
 TEST_F(ParserImplTest, ImageStorageType_Rg32Sint) {
-  auto p = parser("rg32sint");
-  auto t = p->expect_texel_format("test");
-  EXPECT_FALSE(t.errored);
-  EXPECT_EQ(t.value, ast::TexelFormat::kRg32Sint);
-  EXPECT_FALSE(p->has_error());
+    auto p = parser("rg32sint");
+    auto t = p->expect_texel_format("test");
+    EXPECT_FALSE(t.errored);
+    EXPECT_EQ(t.value, ast::TexelFormat::kRg32Sint);
+    EXPECT_FALSE(p->has_error());
 }
 
 TEST_F(ParserImplTest, ImageStorageType_Rg32Float) {
-  auto p = parser("rg32float");
-  auto t = p->expect_texel_format("test");
-  EXPECT_FALSE(t.errored);
-  EXPECT_EQ(t.value, ast::TexelFormat::kRg32Float);
-  EXPECT_FALSE(p->has_error());
+    auto p = parser("rg32float");
+    auto t = p->expect_texel_format("test");
+    EXPECT_FALSE(t.errored);
+    EXPECT_EQ(t.value, ast::TexelFormat::kRg32Float);
+    EXPECT_FALSE(p->has_error());
 }
 
 TEST_F(ParserImplTest, ImageStorageType_Rgba16Uint) {
-  auto p = parser("rgba16uint");
-  auto t = p->expect_texel_format("test");
-  EXPECT_FALSE(t.errored);
-  EXPECT_EQ(t.value, ast::TexelFormat::kRgba16Uint);
-  EXPECT_FALSE(p->has_error());
+    auto p = parser("rgba16uint");
+    auto t = p->expect_texel_format("test");
+    EXPECT_FALSE(t.errored);
+    EXPECT_EQ(t.value, ast::TexelFormat::kRgba16Uint);
+    EXPECT_FALSE(p->has_error());
 }
 
 TEST_F(ParserImplTest, ImageStorageType_Rgba16Sint) {
-  auto p = parser("rgba16sint");
-  auto t = p->expect_texel_format("test");
-  EXPECT_FALSE(t.errored);
-  EXPECT_EQ(t.value, ast::TexelFormat::kRgba16Sint);
-  EXPECT_FALSE(p->has_error());
+    auto p = parser("rgba16sint");
+    auto t = p->expect_texel_format("test");
+    EXPECT_FALSE(t.errored);
+    EXPECT_EQ(t.value, ast::TexelFormat::kRgba16Sint);
+    EXPECT_FALSE(p->has_error());
 }
 
 TEST_F(ParserImplTest, ImageStorageType_Rgba16Float) {
-  auto p = parser("rgba16float");
-  auto t = p->expect_texel_format("test");
-  EXPECT_FALSE(t.errored);
-  EXPECT_EQ(t.value, ast::TexelFormat::kRgba16Float);
-  EXPECT_FALSE(p->has_error());
+    auto p = parser("rgba16float");
+    auto t = p->expect_texel_format("test");
+    EXPECT_FALSE(t.errored);
+    EXPECT_EQ(t.value, ast::TexelFormat::kRgba16Float);
+    EXPECT_FALSE(p->has_error());
 }
 
 TEST_F(ParserImplTest, ImageStorageType_Rgba32Uint) {
-  auto p = parser("rgba32uint");
-  auto t = p->expect_texel_format("test");
-  EXPECT_FALSE(t.errored);
-  EXPECT_EQ(t.value, ast::TexelFormat::kRgba32Uint);
-  EXPECT_FALSE(p->has_error());
+    auto p = parser("rgba32uint");
+    auto t = p->expect_texel_format("test");
+    EXPECT_FALSE(t.errored);
+    EXPECT_EQ(t.value, ast::TexelFormat::kRgba32Uint);
+    EXPECT_FALSE(p->has_error());
 }
 
 TEST_F(ParserImplTest, ImageStorageType_Rgba32Sint) {
-  auto p = parser("rgba32sint");
-  auto t = p->expect_texel_format("test");
-  EXPECT_FALSE(t.errored);
-  EXPECT_EQ(t.value, ast::TexelFormat::kRgba32Sint);
-  EXPECT_FALSE(p->has_error());
+    auto p = parser("rgba32sint");
+    auto t = p->expect_texel_format("test");
+    EXPECT_FALSE(t.errored);
+    EXPECT_EQ(t.value, ast::TexelFormat::kRgba32Sint);
+    EXPECT_FALSE(p->has_error());
 }
 
 TEST_F(ParserImplTest, ImageStorageType_Rgba32Float) {
-  auto p = parser("rgba32float");
-  auto t = p->expect_texel_format("test");
-  EXPECT_FALSE(t.errored);
-  EXPECT_EQ(t.value, ast::TexelFormat::kRgba32Float);
-  EXPECT_FALSE(p->has_error());
+    auto p = parser("rgba32float");
+    auto t = p->expect_texel_format("test");
+    EXPECT_FALSE(t.errored);
+    EXPECT_EQ(t.value, ast::TexelFormat::kRgba32Float);
+    EXPECT_FALSE(p->has_error());
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_texture_sampler_test.cc b/src/tint/reader/wgsl/parser_impl_texture_sampler_test.cc
new file mode 100644
index 0000000..162b41c
--- /dev/null
+++ b/src/tint/reader/wgsl/parser_impl_texture_sampler_test.cc
@@ -0,0 +1,261 @@
+// Copyright 2020 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/reader/wgsl/parser_impl_test_helper.h"
+#include "src/tint/sem/depth_texture.h"
+#include "src/tint/sem/multisampled_texture.h"
+#include "src/tint/sem/sampled_texture.h"
+
+namespace tint::reader::wgsl {
+namespace {
+
+TEST_F(ParserImplTest, TextureSamplerTypes_Invalid) {
+    auto p = parser("1234");
+    auto t = p->texture_samplers();
+    EXPECT_EQ(t.value, nullptr);
+    EXPECT_FALSE(t.matched);
+    EXPECT_FALSE(t.errored);
+    EXPECT_FALSE(p->has_error());
+}
+
+TEST_F(ParserImplTest, TextureSamplerTypes_Sampler) {
+    auto p = parser("sampler");
+    auto t = p->texture_samplers();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    ASSERT_NE(t.value, nullptr);
+    ASSERT_TRUE(t->Is<ast::Sampler>());
+    ASSERT_FALSE(t->As<ast::Sampler>()->IsComparison());
+    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 8u}}));
+}
+
+TEST_F(ParserImplTest, TextureSamplerTypes_SamplerComparison) {
+    auto p = parser("sampler_comparison");
+    auto t = p->texture_samplers();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    ASSERT_NE(t.value, nullptr);
+    ASSERT_TRUE(t->Is<ast::Sampler>());
+    ASSERT_TRUE(t->As<ast::Sampler>()->IsComparison());
+    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 19u}}));
+}
+
+TEST_F(ParserImplTest, TextureSamplerTypes_DepthTexture) {
+    auto p = parser("texture_depth_2d");
+    auto t = p->texture_samplers();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    ASSERT_NE(t.value, nullptr);
+    ASSERT_TRUE(t->Is<ast::Texture>());
+    ASSERT_TRUE(t->Is<ast::DepthTexture>());
+    EXPECT_EQ(t->As<ast::Texture>()->dim, ast::TextureDimension::k2d);
+    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 17u}}));
+}
+
+TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_F32) {
+    auto p = parser("texture_1d<f32>");
+    auto t = p->texture_samplers();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    ASSERT_NE(t.value, nullptr);
+    ASSERT_TRUE(t->Is<ast::Texture>());
+    ASSERT_TRUE(t->Is<ast::SampledTexture>());
+    ASSERT_TRUE(t->As<ast::SampledTexture>()->type->Is<ast::F32>());
+    EXPECT_EQ(t->As<ast::Texture>()->dim, ast::TextureDimension::k1d);
+    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 16u}}));
+}
+
+TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_I32) {
+    auto p = parser("texture_2d<i32>");
+    auto t = p->texture_samplers();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    ASSERT_NE(t.value, nullptr);
+    ASSERT_TRUE(t->Is<ast::Texture>());
+    ASSERT_TRUE(t->Is<ast::SampledTexture>());
+    ASSERT_TRUE(t->As<ast::SampledTexture>()->type->Is<ast::I32>());
+    EXPECT_EQ(t->As<ast::Texture>()->dim, ast::TextureDimension::k2d);
+    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 16u}}));
+}
+
+TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_U32) {
+    auto p = parser("texture_3d<u32>");
+    auto t = p->texture_samplers();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    ASSERT_NE(t.value, nullptr);
+    ASSERT_TRUE(t->Is<ast::Texture>());
+    ASSERT_TRUE(t->Is<ast::SampledTexture>());
+    ASSERT_TRUE(t->As<ast::SampledTexture>()->type->Is<ast::U32>());
+    EXPECT_EQ(t->As<ast::Texture>()->dim, ast::TextureDimension::k3d);
+    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 16u}}));
+}
+
+TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_MissingType) {
+    auto p = parser("texture_1d<>");
+    auto t = p->texture_samplers();
+    ASSERT_TRUE(p->has_error());
+    EXPECT_EQ(t.value, nullptr);
+    EXPECT_FALSE(t.matched);
+    EXPECT_TRUE(t.errored);
+    EXPECT_EQ(p->error(), "1:12: invalid type for sampled texture type");
+}
+
+TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_MissingLessThan) {
+    auto p = parser("texture_1d");
+    auto t = p->texture_samplers();
+    ASSERT_TRUE(p->has_error());
+    EXPECT_EQ(t.value, nullptr);
+    EXPECT_FALSE(t.matched);
+    EXPECT_TRUE(t.errored);
+    EXPECT_EQ(p->error(), "1:11: expected '<' for sampled texture type");
+}
+
+TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_MissingGreaterThan) {
+    auto p = parser("texture_1d<u32");
+    auto t = p->texture_samplers();
+    ASSERT_TRUE(p->has_error());
+    EXPECT_EQ(t.value, nullptr);
+    EXPECT_FALSE(t.matched);
+    EXPECT_TRUE(t.errored);
+    EXPECT_EQ(p->error(), "1:15: expected '>' for sampled texture type");
+}
+
+TEST_F(ParserImplTest, TextureSamplerTypes_MultisampledTexture_I32) {
+    auto p = parser("texture_multisampled_2d<i32>");
+    auto t = p->texture_samplers();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    ASSERT_NE(t.value, nullptr);
+    ASSERT_TRUE(t->Is<ast::Texture>());
+    ASSERT_TRUE(t->Is<ast::MultisampledTexture>());
+    ASSERT_TRUE(t->As<ast::MultisampledTexture>()->type->Is<ast::I32>());
+    EXPECT_EQ(t->As<ast::Texture>()->dim, ast::TextureDimension::k2d);
+    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 29u}}));
+}
+
+TEST_F(ParserImplTest, TextureSamplerTypes_MultisampledTexture_MissingType) {
+    auto p = parser("texture_multisampled_2d<>");
+    auto t = p->texture_samplers();
+    ASSERT_TRUE(p->has_error());
+    EXPECT_EQ(t.value, nullptr);
+    EXPECT_FALSE(t.matched);
+    EXPECT_TRUE(t.errored);
+    EXPECT_EQ(p->error(), "1:25: invalid type for multisampled texture type");
+}
+
+TEST_F(ParserImplTest, TextureSamplerTypes_MultisampledTexture_MissingLessThan) {
+    auto p = parser("texture_multisampled_2d");
+    auto t = p->texture_samplers();
+    EXPECT_EQ(t.value, nullptr);
+    EXPECT_FALSE(t.matched);
+    EXPECT_TRUE(t.errored);
+    EXPECT_EQ(p->error(), "1:24: expected '<' for multisampled texture type");
+}
+
+TEST_F(ParserImplTest, TextureSamplerTypes_MultisampledTexture_MissingGreaterThan) {
+    auto p = parser("texture_multisampled_2d<u32");
+    auto t = p->texture_samplers();
+    EXPECT_EQ(t.value, nullptr);
+    EXPECT_FALSE(t.matched);
+    EXPECT_TRUE(t.errored);
+    EXPECT_EQ(p->error(), "1:28: expected '>' for multisampled texture type");
+}
+
+TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_Readonly1dRg32Float) {
+    auto p = parser("texture_storage_1d<rg32float, read>");
+    auto t = p->texture_samplers();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    ASSERT_NE(t.value, nullptr);
+
+    ASSERT_TRUE(t->Is<ast::Texture>());
+    ASSERT_TRUE(t->Is<ast::StorageTexture>());
+    EXPECT_EQ(t->As<ast::StorageTexture>()->format, ast::TexelFormat::kRg32Float);
+    EXPECT_EQ(t->As<ast::StorageTexture>()->access, ast::Access::kRead);
+    EXPECT_EQ(t->As<ast::Texture>()->dim, ast::TextureDimension::k1d);
+    EXPECT_EQ(t->source.range, (Source::Range{{1u, 1u}, {1u, 36u}}));
+}
+
+TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_Writeonly2dR32Uint) {
+    auto p = parser("texture_storage_2d<r32uint, write>");
+    auto t = p->texture_samplers();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    ASSERT_NE(t.value, nullptr);
+
+    ASSERT_TRUE(t->Is<ast::Texture>());
+    ASSERT_TRUE(t->Is<ast::StorageTexture>());
+    EXPECT_EQ(t->As<ast::StorageTexture>()->format, ast::TexelFormat::kR32Uint);
+    EXPECT_EQ(t->As<ast::StorageTexture>()->access, ast::Access::kWrite);
+    EXPECT_EQ(t->As<ast::Texture>()->dim, ast::TextureDimension::k2d);
+    EXPECT_EQ(t->source.range, (Source::Range{{1u, 1u}, {1u, 35u}}));
+}
+
+TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_InvalidType) {
+    auto p = parser("texture_storage_1d<abc, read>");
+    auto t = p->texture_samplers();
+    EXPECT_EQ(t.value, nullptr);
+    EXPECT_FALSE(t.matched);
+    EXPECT_TRUE(t.errored);
+    EXPECT_EQ(p->error(), "1:20: invalid format for storage texture type");
+}
+
+TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_InvalidAccess) {
+    auto p = parser("texture_storage_1d<r32float, abc>");
+    auto t = p->texture_samplers();
+    EXPECT_EQ(t.value, nullptr);
+    EXPECT_FALSE(t.matched);
+    EXPECT_TRUE(t.errored);
+    EXPECT_EQ(p->error(), "1:30: invalid value for access control");
+}
+
+TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_MissingType) {
+    auto p = parser("texture_storage_1d<>");
+    auto t = p->texture_samplers();
+    EXPECT_EQ(t.value, nullptr);
+    EXPECT_FALSE(t.matched);
+    EXPECT_TRUE(t.errored);
+    EXPECT_EQ(p->error(), "1:20: invalid format for storage texture type");
+}
+
+TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_MissingLessThan) {
+    auto p = parser("texture_storage_1d");
+    auto t = p->texture_samplers();
+    EXPECT_EQ(t.value, nullptr);
+    EXPECT_FALSE(t.matched);
+    EXPECT_TRUE(t.errored);
+    EXPECT_EQ(p->error(), "1:19: expected '<' for storage texture type");
+}
+
+TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_MissingGreaterThan) {
+    auto p = parser("texture_storage_1d<r32uint, read");
+    auto t = p->texture_samplers();
+    EXPECT_EQ(t.value, nullptr);
+    EXPECT_FALSE(t.matched);
+    EXPECT_TRUE(t.errored);
+    EXPECT_EQ(p->error(), "1:33: expected '>' for storage texture type");
+}
+
+}  // namespace
+}  // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/parser_impl_texture_sampler_types_test.cc b/src/tint/reader/wgsl/parser_impl_texture_sampler_types_test.cc
deleted file mode 100644
index 25a0698..0000000
--- a/src/tint/reader/wgsl/parser_impl_texture_sampler_types_test.cc
+++ /dev/null
@@ -1,263 +0,0 @@
-// Copyright 2020 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/tint/reader/wgsl/parser_impl_test_helper.h"
-#include "src/tint/sem/depth_texture_type.h"
-#include "src/tint/sem/multisampled_texture_type.h"
-#include "src/tint/sem/sampled_texture_type.h"
-
-namespace tint::reader::wgsl {
-namespace {
-
-TEST_F(ParserImplTest, TextureSamplerTypes_Invalid) {
-  auto p = parser("1234");
-  auto t = p->texture_sampler_types();
-  EXPECT_EQ(t.value, nullptr);
-  EXPECT_FALSE(t.matched);
-  EXPECT_FALSE(t.errored);
-  EXPECT_FALSE(p->has_error());
-}
-
-TEST_F(ParserImplTest, TextureSamplerTypes_Sampler) {
-  auto p = parser("sampler");
-  auto t = p->texture_sampler_types();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  ASSERT_NE(t.value, nullptr);
-  ASSERT_TRUE(t->Is<ast::Sampler>());
-  ASSERT_FALSE(t->As<ast::Sampler>()->IsComparison());
-  EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 8u}}));
-}
-
-TEST_F(ParserImplTest, TextureSamplerTypes_SamplerComparison) {
-  auto p = parser("sampler_comparison");
-  auto t = p->texture_sampler_types();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  ASSERT_NE(t.value, nullptr);
-  ASSERT_TRUE(t->Is<ast::Sampler>());
-  ASSERT_TRUE(t->As<ast::Sampler>()->IsComparison());
-  EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 19u}}));
-}
-
-TEST_F(ParserImplTest, TextureSamplerTypes_DepthTexture) {
-  auto p = parser("texture_depth_2d");
-  auto t = p->texture_sampler_types();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  ASSERT_NE(t.value, nullptr);
-  ASSERT_TRUE(t->Is<ast::Texture>());
-  ASSERT_TRUE(t->Is<ast::DepthTexture>());
-  EXPECT_EQ(t->As<ast::Texture>()->dim, ast::TextureDimension::k2d);
-  EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 17u}}));
-}
-
-TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_F32) {
-  auto p = parser("texture_1d<f32>");
-  auto t = p->texture_sampler_types();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  ASSERT_NE(t.value, nullptr);
-  ASSERT_TRUE(t->Is<ast::Texture>());
-  ASSERT_TRUE(t->Is<ast::SampledTexture>());
-  ASSERT_TRUE(t->As<ast::SampledTexture>()->type->Is<ast::F32>());
-  EXPECT_EQ(t->As<ast::Texture>()->dim, ast::TextureDimension::k1d);
-  EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 16u}}));
-}
-
-TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_I32) {
-  auto p = parser("texture_2d<i32>");
-  auto t = p->texture_sampler_types();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  ASSERT_NE(t.value, nullptr);
-  ASSERT_TRUE(t->Is<ast::Texture>());
-  ASSERT_TRUE(t->Is<ast::SampledTexture>());
-  ASSERT_TRUE(t->As<ast::SampledTexture>()->type->Is<ast::I32>());
-  EXPECT_EQ(t->As<ast::Texture>()->dim, ast::TextureDimension::k2d);
-  EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 16u}}));
-}
-
-TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_U32) {
-  auto p = parser("texture_3d<u32>");
-  auto t = p->texture_sampler_types();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  ASSERT_NE(t.value, nullptr);
-  ASSERT_TRUE(t->Is<ast::Texture>());
-  ASSERT_TRUE(t->Is<ast::SampledTexture>());
-  ASSERT_TRUE(t->As<ast::SampledTexture>()->type->Is<ast::U32>());
-  EXPECT_EQ(t->As<ast::Texture>()->dim, ast::TextureDimension::k3d);
-  EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 16u}}));
-}
-
-TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_MissingType) {
-  auto p = parser("texture_1d<>");
-  auto t = p->texture_sampler_types();
-  ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(t.value, nullptr);
-  EXPECT_FALSE(t.matched);
-  EXPECT_TRUE(t.errored);
-  EXPECT_EQ(p->error(), "1:12: invalid type for sampled texture type");
-}
-
-TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_MissingLessThan) {
-  auto p = parser("texture_1d");
-  auto t = p->texture_sampler_types();
-  ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(t.value, nullptr);
-  EXPECT_FALSE(t.matched);
-  EXPECT_TRUE(t.errored);
-  EXPECT_EQ(p->error(), "1:11: expected '<' for sampled texture type");
-}
-
-TEST_F(ParserImplTest, TextureSamplerTypes_SampledTexture_MissingGreaterThan) {
-  auto p = parser("texture_1d<u32");
-  auto t = p->texture_sampler_types();
-  ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(t.value, nullptr);
-  EXPECT_FALSE(t.matched);
-  EXPECT_TRUE(t.errored);
-  EXPECT_EQ(p->error(), "1:15: expected '>' for sampled texture type");
-}
-
-TEST_F(ParserImplTest, TextureSamplerTypes_MultisampledTexture_I32) {
-  auto p = parser("texture_multisampled_2d<i32>");
-  auto t = p->texture_sampler_types();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  ASSERT_NE(t.value, nullptr);
-  ASSERT_TRUE(t->Is<ast::Texture>());
-  ASSERT_TRUE(t->Is<ast::MultisampledTexture>());
-  ASSERT_TRUE(t->As<ast::MultisampledTexture>()->type->Is<ast::I32>());
-  EXPECT_EQ(t->As<ast::Texture>()->dim, ast::TextureDimension::k2d);
-  EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 29u}}));
-}
-
-TEST_F(ParserImplTest, TextureSamplerTypes_MultisampledTexture_MissingType) {
-  auto p = parser("texture_multisampled_2d<>");
-  auto t = p->texture_sampler_types();
-  ASSERT_TRUE(p->has_error());
-  EXPECT_EQ(t.value, nullptr);
-  EXPECT_FALSE(t.matched);
-  EXPECT_TRUE(t.errored);
-  EXPECT_EQ(p->error(), "1:25: invalid type for multisampled texture type");
-}
-
-TEST_F(ParserImplTest,
-       TextureSamplerTypes_MultisampledTexture_MissingLessThan) {
-  auto p = parser("texture_multisampled_2d");
-  auto t = p->texture_sampler_types();
-  EXPECT_EQ(t.value, nullptr);
-  EXPECT_FALSE(t.matched);
-  EXPECT_TRUE(t.errored);
-  EXPECT_EQ(p->error(), "1:24: expected '<' for multisampled texture type");
-}
-
-TEST_F(ParserImplTest,
-       TextureSamplerTypes_MultisampledTexture_MissingGreaterThan) {
-  auto p = parser("texture_multisampled_2d<u32");
-  auto t = p->texture_sampler_types();
-  EXPECT_EQ(t.value, nullptr);
-  EXPECT_FALSE(t.matched);
-  EXPECT_TRUE(t.errored);
-  EXPECT_EQ(p->error(), "1:28: expected '>' for multisampled texture type");
-}
-
-TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_Readonly1dRg32Float) {
-  auto p = parser("texture_storage_1d<rg32float, read>");
-  auto t = p->texture_sampler_types();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  ASSERT_NE(t.value, nullptr);
-
-  ASSERT_TRUE(t->Is<ast::Texture>());
-  ASSERT_TRUE(t->Is<ast::StorageTexture>());
-  EXPECT_EQ(t->As<ast::StorageTexture>()->format, ast::TexelFormat::kRg32Float);
-  EXPECT_EQ(t->As<ast::StorageTexture>()->access, ast::Access::kRead);
-  EXPECT_EQ(t->As<ast::Texture>()->dim, ast::TextureDimension::k1d);
-  EXPECT_EQ(t->source.range, (Source::Range{{1u, 1u}, {1u, 36u}}));
-}
-
-TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_Writeonly2dR32Uint) {
-  auto p = parser("texture_storage_2d<r32uint, write>");
-  auto t = p->texture_sampler_types();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  ASSERT_NE(t.value, nullptr);
-
-  ASSERT_TRUE(t->Is<ast::Texture>());
-  ASSERT_TRUE(t->Is<ast::StorageTexture>());
-  EXPECT_EQ(t->As<ast::StorageTexture>()->format, ast::TexelFormat::kR32Uint);
-  EXPECT_EQ(t->As<ast::StorageTexture>()->access, ast::Access::kWrite);
-  EXPECT_EQ(t->As<ast::Texture>()->dim, ast::TextureDimension::k2d);
-  EXPECT_EQ(t->source.range, (Source::Range{{1u, 1u}, {1u, 35u}}));
-}
-
-TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_InvalidType) {
-  auto p = parser("texture_storage_1d<abc, read>");
-  auto t = p->texture_sampler_types();
-  EXPECT_EQ(t.value, nullptr);
-  EXPECT_FALSE(t.matched);
-  EXPECT_TRUE(t.errored);
-  EXPECT_EQ(p->error(), "1:20: invalid format for storage texture type");
-}
-
-TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_InvalidAccess) {
-  auto p = parser("texture_storage_1d<r32float, abc>");
-  auto t = p->texture_sampler_types();
-  EXPECT_EQ(t.value, nullptr);
-  EXPECT_FALSE(t.matched);
-  EXPECT_TRUE(t.errored);
-  EXPECT_EQ(p->error(), "1:30: invalid value for access control");
-}
-
-TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_MissingType) {
-  auto p = parser("texture_storage_1d<>");
-  auto t = p->texture_sampler_types();
-  EXPECT_EQ(t.value, nullptr);
-  EXPECT_FALSE(t.matched);
-  EXPECT_TRUE(t.errored);
-  EXPECT_EQ(p->error(), "1:20: invalid format for storage texture type");
-}
-
-TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_MissingLessThan) {
-  auto p = parser("texture_storage_1d");
-  auto t = p->texture_sampler_types();
-  EXPECT_EQ(t.value, nullptr);
-  EXPECT_FALSE(t.matched);
-  EXPECT_TRUE(t.errored);
-  EXPECT_EQ(p->error(), "1:19: expected '<' for storage texture type");
-}
-
-TEST_F(ParserImplTest, TextureSamplerTypes_StorageTexture_MissingGreaterThan) {
-  auto p = parser("texture_storage_1d<r32uint, read");
-  auto t = p->texture_sampler_types();
-  EXPECT_EQ(t.value, nullptr);
-  EXPECT_FALSE(t.matched);
-  EXPECT_TRUE(t.errored);
-  EXPECT_EQ(p->error(), "1:33: expected '>' for storage texture type");
-}
-
-}  // namespace
-}  // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/parser_impl_type_alias_test.cc b/src/tint/reader/wgsl/parser_impl_type_alias_test.cc
index e30d228..ea5cbe2 100644
--- a/src/tint/reader/wgsl/parser_impl_type_alias_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_type_alias_test.cc
@@ -18,82 +18,82 @@
 namespace {
 
 TEST_F(ParserImplTest, TypeDecl_ParsesType) {
-  auto p = parser("type a = i32");
+    auto p = parser("type a = i32");
 
-  auto t = p->type_alias();
-  EXPECT_FALSE(p->has_error());
-  EXPECT_FALSE(t.errored);
-  EXPECT_TRUE(t.matched);
-  ASSERT_NE(t.value, nullptr);
-  ASSERT_TRUE(t->Is<ast::Alias>());
-  auto* alias = t->As<ast::Alias>();
-  ASSERT_TRUE(alias->type->Is<ast::I32>());
+    auto t = p->type_alias();
+    EXPECT_FALSE(p->has_error());
+    EXPECT_FALSE(t.errored);
+    EXPECT_TRUE(t.matched);
+    ASSERT_NE(t.value, nullptr);
+    ASSERT_TRUE(t->Is<ast::Alias>());
+    auto* alias = t->As<ast::Alias>();
+    ASSERT_TRUE(alias->type->Is<ast::I32>());
 
-  EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 13u}}));
+    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 13u}}));
 }
 
 TEST_F(ParserImplTest, TypeDecl_Parses_Ident) {
-  auto p = parser("type a = B");
+    auto p = parser("type a = B");
 
-  auto t = p->type_alias();
-  EXPECT_FALSE(p->has_error());
-  EXPECT_FALSE(t.errored);
-  EXPECT_TRUE(t.matched);
-  ASSERT_NE(t.value, nullptr);
-  ASSERT_TRUE(t.value->Is<ast::Alias>());
-  auto* alias = t.value->As<ast::Alias>();
-  EXPECT_EQ(p->builder().Symbols().NameFor(alias->name), "a");
-  EXPECT_TRUE(alias->type->Is<ast::TypeName>());
-  EXPECT_EQ(alias->source.range, (Source::Range{{1u, 1u}, {1u, 11u}}));
+    auto t = p->type_alias();
+    EXPECT_FALSE(p->has_error());
+    EXPECT_FALSE(t.errored);
+    EXPECT_TRUE(t.matched);
+    ASSERT_NE(t.value, nullptr);
+    ASSERT_TRUE(t.value->Is<ast::Alias>());
+    auto* alias = t.value->As<ast::Alias>();
+    EXPECT_EQ(p->builder().Symbols().NameFor(alias->name), "a");
+    EXPECT_TRUE(alias->type->Is<ast::TypeName>());
+    EXPECT_EQ(alias->source.range, (Source::Range{{1u, 1u}, {1u, 11u}}));
 }
 
 TEST_F(ParserImplTest, TypeDecl_Unicode_Parses_Ident) {
-  const std::string ident =  // "𝓶𝔂_𝓽𝔂𝓹𝓮"
-      "\xf0\x9d\x93\xb6\xf0\x9d\x94\x82\x5f\xf0\x9d\x93\xbd\xf0\x9d\x94\x82\xf0"
-      "\x9d\x93\xb9\xf0\x9d\x93\xae";
+    const std::string ident =  // "𝓶𝔂_𝓽𝔂𝓹𝓮"
+        "\xf0\x9d\x93\xb6\xf0\x9d\x94\x82\x5f\xf0\x9d\x93\xbd\xf0\x9d\x94\x82\xf0"
+        "\x9d\x93\xb9\xf0\x9d\x93\xae";
 
-  auto p = parser("type " + ident + " = i32");
+    auto p = parser("type " + ident + " = i32");
 
-  auto t = p->type_alias();
-  EXPECT_FALSE(p->has_error());
-  EXPECT_FALSE(t.errored);
-  EXPECT_TRUE(t.matched);
-  ASSERT_NE(t.value, nullptr);
-  ASSERT_TRUE(t.value->Is<ast::Alias>());
-  auto* alias = t.value->As<ast::Alias>();
-  EXPECT_EQ(p->builder().Symbols().NameFor(alias->name), ident);
-  EXPECT_TRUE(alias->type->Is<ast::I32>());
-  EXPECT_EQ(alias->source.range, (Source::Range{{1u, 1u}, {1u, 37u}}));
+    auto t = p->type_alias();
+    EXPECT_FALSE(p->has_error());
+    EXPECT_FALSE(t.errored);
+    EXPECT_TRUE(t.matched);
+    ASSERT_NE(t.value, nullptr);
+    ASSERT_TRUE(t.value->Is<ast::Alias>());
+    auto* alias = t.value->As<ast::Alias>();
+    EXPECT_EQ(p->builder().Symbols().NameFor(alias->name), ident);
+    EXPECT_TRUE(alias->type->Is<ast::I32>());
+    EXPECT_EQ(alias->source.range, (Source::Range{{1u, 1u}, {1u, 37u}}));
 }
 
 TEST_F(ParserImplTest, TypeDecl_MissingIdent) {
-  auto p = parser("type = i32");
-  auto t = p->type_alias();
-  EXPECT_TRUE(t.errored);
-  EXPECT_FALSE(t.matched);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(t.value, nullptr);
-  EXPECT_EQ(p->error(), "1:6: expected identifier for type alias");
+    auto p = parser("type = i32");
+    auto t = p->type_alias();
+    EXPECT_TRUE(t.errored);
+    EXPECT_FALSE(t.matched);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(t.value, nullptr);
+    EXPECT_EQ(p->error(), "1:6: expected identifier for type alias");
 }
 
 TEST_F(ParserImplTest, TypeDecl_InvalidIdent) {
-  auto p = parser("type 123 = i32");
-  auto t = p->type_alias();
-  EXPECT_TRUE(t.errored);
-  EXPECT_FALSE(t.matched);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(t.value, nullptr);
-  EXPECT_EQ(p->error(), "1:6: expected identifier for type alias");
+    auto p = parser("type 123 = i32");
+    auto t = p->type_alias();
+    EXPECT_TRUE(t.errored);
+    EXPECT_FALSE(t.matched);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(t.value, nullptr);
+    EXPECT_EQ(p->error(), "1:6: expected identifier for type alias");
 }
 
 TEST_F(ParserImplTest, TypeDecl_MissingEqual) {
-  auto p = parser("type a i32");
-  auto t = p->type_alias();
-  EXPECT_TRUE(t.errored);
-  EXPECT_FALSE(t.matched);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(t.value, nullptr);
-  EXPECT_EQ(p->error(), "1:8: expected '=' for type alias");
+    auto p = parser("type a i32");
+    auto t = p->type_alias();
+    EXPECT_TRUE(t.errored);
+    EXPECT_FALSE(t.matched);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(t.value, nullptr);
+    EXPECT_EQ(p->error(), "1:8: expected '=' for type alias");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_type_decl_test.cc b/src/tint/reader/wgsl/parser_impl_type_decl_test.cc
index f649a26..a721d77 100644
--- a/src/tint/reader/wgsl/parser_impl_type_decl_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_type_decl_test.cc
@@ -17,119 +17,118 @@
 #include "src/tint/ast/matrix.h"
 #include "src/tint/ast/sampler.h"
 #include "src/tint/reader/wgsl/parser_impl_test_helper.h"
-#include "src/tint/sem/sampled_texture_type.h"
+#include "src/tint/sem/sampled_texture.h"
 
 namespace tint::reader::wgsl {
 namespace {
 
 TEST_F(ParserImplTest, TypeDecl_Invalid) {
-  auto p = parser("1234");
-  auto t = p->type_decl();
-  EXPECT_EQ(t.errored, false);
-  EXPECT_EQ(t.matched, false);
-  EXPECT_EQ(t.value, nullptr);
-  EXPECT_FALSE(p->has_error());
+    auto p = parser("1234");
+    auto t = p->type_decl();
+    EXPECT_EQ(t.errored, false);
+    EXPECT_EQ(t.matched, false);
+    EXPECT_EQ(t.value, nullptr);
+    EXPECT_FALSE(p->has_error());
 }
 
 TEST_F(ParserImplTest, TypeDecl_Identifier) {
-  auto p = parser("A");
+    auto p = parser("A");
 
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  ASSERT_NE(t.value, nullptr) << p->error();
-  auto* type_name = t.value->As<ast::TypeName>();
-  ASSERT_NE(type_name, nullptr);
-  EXPECT_EQ(p->builder().Symbols().Get("A"), type_name->name);
-  EXPECT_EQ(type_name->source.range, (Source::Range{{1u, 1u}, {1u, 2u}}));
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    ASSERT_NE(t.value, nullptr) << p->error();
+    auto* type_name = t.value->As<ast::TypeName>();
+    ASSERT_NE(type_name, nullptr);
+    EXPECT_EQ(p->builder().Symbols().Get("A"), type_name->name);
+    EXPECT_EQ(type_name->source.range, (Source::Range{{1u, 1u}, {1u, 2u}}));
 }
 
 TEST_F(ParserImplTest, TypeDecl_Bool) {
-  auto p = parser("bool");
+    auto p = parser("bool");
 
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  ASSERT_NE(t.value, nullptr) << p->error();
-  ASSERT_TRUE(t.value->Is<ast::Bool>());
-  EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 5u}}));
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    ASSERT_NE(t.value, nullptr) << p->error();
+    ASSERT_TRUE(t.value->Is<ast::Bool>());
+    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 5u}}));
 }
 
 TEST_F(ParserImplTest, TypeDecl_F32) {
-  auto p = parser("f32");
+    auto p = parser("f32");
 
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  ASSERT_NE(t.value, nullptr) << p->error();
-  ASSERT_TRUE(t.value->Is<ast::F32>());
-  EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 4u}}));
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    ASSERT_NE(t.value, nullptr) << p->error();
+    ASSERT_TRUE(t.value->Is<ast::F32>());
+    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 4u}}));
 }
 
 TEST_F(ParserImplTest, TypeDecl_I32) {
-  auto p = parser("i32");
+    auto p = parser("i32");
 
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  ASSERT_NE(t.value, nullptr) << p->error();
-  ASSERT_TRUE(t.value->Is<ast::I32>());
-  EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 4u}}));
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    ASSERT_NE(t.value, nullptr) << p->error();
+    ASSERT_TRUE(t.value->Is<ast::I32>());
+    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 4u}}));
 }
 
 TEST_F(ParserImplTest, TypeDecl_U32) {
-  auto p = parser("u32");
+    auto p = parser("u32");
 
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  ASSERT_NE(t.value, nullptr) << p->error();
-  ASSERT_TRUE(t.value->Is<ast::U32>());
-  EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 4u}}));
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    ASSERT_NE(t.value, nullptr) << p->error();
+    ASSERT_TRUE(t.value->Is<ast::U32>());
+    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 4u}}));
 }
 
 struct VecData {
-  const char* input;
-  size_t count;
-  Source::Range range;
+    const char* input;
+    size_t count;
+    Source::Range range;
 };
 inline std::ostream& operator<<(std::ostream& out, VecData data) {
-  out << std::string(data.input);
-  return out;
+    out << std::string(data.input);
+    return out;
 }
 
 class VecTest : public ParserImplTestWithParam<VecData> {};
 
 TEST_P(VecTest, Parse) {
-  auto params = GetParam();
-  auto p = parser(params.input);
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  ASSERT_NE(t.value, nullptr) << p->error();
-  ASSERT_FALSE(p->has_error());
-  EXPECT_TRUE(t.value->Is<ast::Vector>());
-  EXPECT_EQ(t.value->As<ast::Vector>()->width, params.count);
-  EXPECT_EQ(t.value->source.range, params.range);
+    auto params = GetParam();
+    auto p = parser(params.input);
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    ASSERT_NE(t.value, nullptr) << p->error();
+    ASSERT_FALSE(p->has_error());
+    EXPECT_TRUE(t.value->Is<ast::Vector>());
+    EXPECT_EQ(t.value->As<ast::Vector>()->width, params.count);
+    EXPECT_EQ(t.value->source.range, params.range);
 }
-INSTANTIATE_TEST_SUITE_P(
-    ParserImplTest,
-    VecTest,
-    testing::Values(VecData{"vec2<f32>", 2, {{1u, 1u}, {1u, 10u}}},
-                    VecData{"vec3<f32>", 3, {{1u, 1u}, {1u, 10u}}},
-                    VecData{"vec4<f32>", 4, {{1u, 1u}, {1u, 10u}}}));
+INSTANTIATE_TEST_SUITE_P(ParserImplTest,
+                         VecTest,
+                         testing::Values(VecData{"vec2<f32>", 2, {{1u, 1u}, {1u, 10u}}},
+                                         VecData{"vec3<f32>", 3, {{1u, 1u}, {1u, 10u}}},
+                                         VecData{"vec4<f32>", 4, {{1u, 1u}, {1u, 10u}}}));
 
 class VecMissingGreaterThanTest : public ParserImplTestWithParam<VecData> {};
 
 TEST_P(VecMissingGreaterThanTest, Handles_Missing_GreaterThan) {
-  auto params = GetParam();
-  auto p = parser(params.input);
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.errored);
-  EXPECT_FALSE(t.matched);
-  ASSERT_EQ(t.value, nullptr);
-  ASSERT_TRUE(p->has_error());
-  ASSERT_EQ(p->error(), "1:9: expected '>' for vector");
+    auto params = GetParam();
+    auto p = parser(params.input);
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.errored);
+    EXPECT_FALSE(t.matched);
+    ASSERT_EQ(t.value, nullptr);
+    ASSERT_TRUE(p->has_error());
+    ASSERT_EQ(p->error(), "1:9: expected '>' for vector");
 }
 INSTANTIATE_TEST_SUITE_P(ParserImplTest,
                          VecMissingGreaterThanTest,
@@ -140,14 +139,14 @@
 class VecMissingType : public ParserImplTestWithParam<VecData> {};
 
 TEST_P(VecMissingType, Handles_Missing_Type) {
-  auto params = GetParam();
-  auto p = parser(params.input);
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.errored);
-  EXPECT_FALSE(t.matched);
-  ASSERT_EQ(t.value, nullptr);
-  ASSERT_TRUE(p->has_error());
-  ASSERT_EQ(p->error(), "1:6: invalid type for vector");
+    auto params = GetParam();
+    auto p = parser(params.input);
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.errored);
+    EXPECT_FALSE(t.matched);
+    ASSERT_EQ(t.value, nullptr);
+    ASSERT_TRUE(p->has_error());
+    ASSERT_EQ(p->error(), "1:6: invalid type for vector");
 }
 INSTANTIATE_TEST_SUITE_P(ParserImplTest,
                          VecMissingType,
@@ -156,421 +155,441 @@
                                          VecData{"vec4<>", 4, {}}));
 
 TEST_F(ParserImplTest, TypeDecl_Ptr) {
-  auto p = parser("ptr<function, f32>");
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  ASSERT_NE(t.value, nullptr) << p->error();
-  ASSERT_FALSE(p->has_error());
-  ASSERT_TRUE(t.value->Is<ast::Pointer>());
+    auto p = parser("ptr<function, f32>");
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    ASSERT_NE(t.value, nullptr) << p->error();
+    ASSERT_FALSE(p->has_error());
+    ASSERT_TRUE(t.value->Is<ast::Pointer>());
 
-  auto* ptr = t.value->As<ast::Pointer>();
-  ASSERT_TRUE(ptr->type->Is<ast::F32>());
-  ASSERT_EQ(ptr->storage_class, ast::StorageClass::kFunction);
-  EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 19u}}));
+    auto* ptr = t.value->As<ast::Pointer>();
+    ASSERT_TRUE(ptr->type->Is<ast::F32>());
+    ASSERT_EQ(ptr->storage_class, ast::StorageClass::kFunction);
+    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 19u}}));
 }
 
 TEST_F(ParserImplTest, TypeDecl_Ptr_WithAccess) {
-  auto p = parser("ptr<function, f32, read>");
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  ASSERT_NE(t.value, nullptr) << p->error();
-  ASSERT_FALSE(p->has_error());
-  ASSERT_TRUE(t.value->Is<ast::Pointer>());
+    auto p = parser("ptr<function, f32, read>");
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    ASSERT_NE(t.value, nullptr) << p->error();
+    ASSERT_FALSE(p->has_error());
+    ASSERT_TRUE(t.value->Is<ast::Pointer>());
 
-  auto* ptr = t.value->As<ast::Pointer>();
-  ASSERT_TRUE(ptr->type->Is<ast::F32>());
-  ASSERT_EQ(ptr->storage_class, ast::StorageClass::kFunction);
-  ASSERT_EQ(ptr->access, ast::Access::kRead);
-  EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 25u}}));
+    auto* ptr = t.value->As<ast::Pointer>();
+    ASSERT_TRUE(ptr->type->Is<ast::F32>());
+    ASSERT_EQ(ptr->storage_class, ast::StorageClass::kFunction);
+    ASSERT_EQ(ptr->access, ast::Access::kRead);
+    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 25u}}));
 }
 
 TEST_F(ParserImplTest, TypeDecl_Ptr_ToVec) {
-  auto p = parser("ptr<function, vec2<f32>>");
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  ASSERT_NE(t.value, nullptr) << p->error();
-  ASSERT_FALSE(p->has_error());
-  ASSERT_TRUE(t.value->Is<ast::Pointer>());
+    auto p = parser("ptr<function, vec2<f32>>");
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    ASSERT_NE(t.value, nullptr) << p->error();
+    ASSERT_FALSE(p->has_error());
+    ASSERT_TRUE(t.value->Is<ast::Pointer>());
 
-  auto* ptr = t.value->As<ast::Pointer>();
-  ASSERT_TRUE(ptr->type->Is<ast::Vector>());
-  ASSERT_EQ(ptr->storage_class, ast::StorageClass::kFunction);
+    auto* ptr = t.value->As<ast::Pointer>();
+    ASSERT_TRUE(ptr->type->Is<ast::Vector>());
+    ASSERT_EQ(ptr->storage_class, ast::StorageClass::kFunction);
 
-  auto* vec = ptr->type->As<ast::Vector>();
-  ASSERT_EQ(vec->width, 2u);
-  ASSERT_TRUE(vec->type->Is<ast::F32>());
-  EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 25}}));
+    auto* vec = ptr->type->As<ast::Vector>();
+    ASSERT_EQ(vec->width, 2u);
+    ASSERT_TRUE(vec->type->Is<ast::F32>());
+    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 25}}));
 }
 
 TEST_F(ParserImplTest, TypeDecl_Ptr_MissingLessThan) {
-  auto p = parser("ptr private, f32>");
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.errored);
-  EXPECT_FALSE(t.matched);
-  ASSERT_EQ(t.value, nullptr);
-  ASSERT_TRUE(p->has_error());
-  ASSERT_EQ(p->error(), "1:5: expected '<' for ptr declaration");
+    auto p = parser("ptr private, f32>");
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.errored);
+    EXPECT_FALSE(t.matched);
+    ASSERT_EQ(t.value, nullptr);
+    ASSERT_TRUE(p->has_error());
+    ASSERT_EQ(p->error(), "1:5: expected '<' for ptr declaration");
 }
 
 TEST_F(ParserImplTest, TypeDecl_Ptr_MissingGreaterThanAfterType) {
-  auto p = parser("ptr<function, f32");
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.errored);
-  EXPECT_FALSE(t.matched);
-  ASSERT_EQ(t.value, nullptr);
-  ASSERT_TRUE(p->has_error());
-  ASSERT_EQ(p->error(), "1:18: expected '>' for ptr declaration");
+    auto p = parser("ptr<function, f32");
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.errored);
+    EXPECT_FALSE(t.matched);
+    ASSERT_EQ(t.value, nullptr);
+    ASSERT_TRUE(p->has_error());
+    ASSERT_EQ(p->error(), "1:18: expected '>' for ptr declaration");
 }
 
 TEST_F(ParserImplTest, TypeDecl_Ptr_MissingGreaterThanAfterAccess) {
-  auto p = parser("ptr<function, f32, read");
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.errored);
-  EXPECT_FALSE(t.matched);
-  ASSERT_EQ(t.value, nullptr);
-  ASSERT_TRUE(p->has_error());
-  ASSERT_EQ(p->error(), "1:24: expected '>' for ptr declaration");
+    auto p = parser("ptr<function, f32, read");
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.errored);
+    EXPECT_FALSE(t.matched);
+    ASSERT_EQ(t.value, nullptr);
+    ASSERT_TRUE(p->has_error());
+    ASSERT_EQ(p->error(), "1:24: expected '>' for ptr declaration");
 }
 
 TEST_F(ParserImplTest, TypeDecl_Ptr_MissingCommaAfterStorageClass) {
-  auto p = parser("ptr<function f32>");
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.errored);
-  EXPECT_FALSE(t.matched);
-  ASSERT_EQ(t.value, nullptr);
-  ASSERT_TRUE(p->has_error());
-  ASSERT_EQ(p->error(), "1:14: expected ',' for ptr declaration");
+    auto p = parser("ptr<function f32>");
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.errored);
+    EXPECT_FALSE(t.matched);
+    ASSERT_EQ(t.value, nullptr);
+    ASSERT_TRUE(p->has_error());
+    ASSERT_EQ(p->error(), "1:14: expected ',' for ptr declaration");
 }
 
 TEST_F(ParserImplTest, TypeDecl_Ptr_MissingCommaAfterAccess) {
-  auto p = parser("ptr<function, f32 read>");
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.errored);
-  EXPECT_FALSE(t.matched);
-  ASSERT_EQ(t.value, nullptr);
-  ASSERT_TRUE(p->has_error());
-  ASSERT_EQ(p->error(), "1:19: expected '>' for ptr declaration");
+    auto p = parser("ptr<function, f32 read>");
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.errored);
+    EXPECT_FALSE(t.matched);
+    ASSERT_EQ(t.value, nullptr);
+    ASSERT_TRUE(p->has_error());
+    ASSERT_EQ(p->error(), "1:19: expected '>' for ptr declaration");
 }
 
 TEST_F(ParserImplTest, TypeDecl_Ptr_MissingStorageClass) {
-  auto p = parser("ptr<, f32>");
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.errored);
-  EXPECT_FALSE(t.matched);
-  ASSERT_EQ(t.value, nullptr);
-  ASSERT_TRUE(p->has_error());
-  ASSERT_EQ(p->error(), "1:5: invalid storage class for ptr declaration");
+    auto p = parser("ptr<, f32>");
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.errored);
+    EXPECT_FALSE(t.matched);
+    ASSERT_EQ(t.value, nullptr);
+    ASSERT_TRUE(p->has_error());
+    ASSERT_EQ(p->error(), "1:5: invalid storage class for ptr declaration");
 }
 
 TEST_F(ParserImplTest, TypeDecl_Ptr_MissingType) {
-  auto p = parser("ptr<function,>");
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.errored);
-  EXPECT_FALSE(t.matched);
-  ASSERT_EQ(t.value, nullptr);
-  ASSERT_TRUE(p->has_error());
-  ASSERT_EQ(p->error(), "1:14: invalid type for ptr declaration");
+    auto p = parser("ptr<function,>");
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.errored);
+    EXPECT_FALSE(t.matched);
+    ASSERT_EQ(t.value, nullptr);
+    ASSERT_TRUE(p->has_error());
+    ASSERT_EQ(p->error(), "1:14: invalid type for ptr declaration");
 }
 
 TEST_F(ParserImplTest, TypeDecl_Ptr_MissingAccess) {
-  auto p = parser("ptr<function, i32, >");
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.errored);
-  EXPECT_FALSE(t.matched);
-  ASSERT_EQ(t.value, nullptr);
-  ASSERT_TRUE(p->has_error());
-  ASSERT_EQ(p->error(), "1:20: expected identifier for access control");
+    auto p = parser("ptr<function, i32, >");
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.errored);
+    EXPECT_FALSE(t.matched);
+    ASSERT_EQ(t.value, nullptr);
+    ASSERT_TRUE(p->has_error());
+    ASSERT_EQ(p->error(), "1:20: expected identifier for access control");
 }
 
 TEST_F(ParserImplTest, TypeDecl_Ptr_MissingParams) {
-  auto p = parser("ptr<>");
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.errored);
-  EXPECT_FALSE(t.matched);
-  ASSERT_EQ(t.value, nullptr);
-  ASSERT_TRUE(p->has_error());
-  ASSERT_EQ(p->error(), "1:5: invalid storage class for ptr declaration");
+    auto p = parser("ptr<>");
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.errored);
+    EXPECT_FALSE(t.matched);
+    ASSERT_EQ(t.value, nullptr);
+    ASSERT_TRUE(p->has_error());
+    ASSERT_EQ(p->error(), "1:5: invalid storage class for ptr declaration");
 }
 
 TEST_F(ParserImplTest, TypeDecl_Ptr_BadStorageClass) {
-  auto p = parser("ptr<unknown, f32>");
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.errored);
-  EXPECT_FALSE(t.matched);
-  ASSERT_EQ(t.value, nullptr);
-  ASSERT_TRUE(p->has_error());
-  ASSERT_EQ(p->error(), "1:5: invalid storage class for ptr declaration");
+    auto p = parser("ptr<unknown, f32>");
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.errored);
+    EXPECT_FALSE(t.matched);
+    ASSERT_EQ(t.value, nullptr);
+    ASSERT_TRUE(p->has_error());
+    ASSERT_EQ(p->error(), "1:5: invalid storage class for ptr declaration");
 }
 
 TEST_F(ParserImplTest, TypeDecl_Ptr_BadAccess) {
-  auto p = parser("ptr<function, i32, unknown>");
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.errored);
-  EXPECT_FALSE(t.matched);
-  ASSERT_EQ(t.value, nullptr);
-  ASSERT_TRUE(p->has_error());
-  ASSERT_EQ(p->error(), "1:20: invalid value for access control");
+    auto p = parser("ptr<function, i32, unknown>");
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.errored);
+    EXPECT_FALSE(t.matched);
+    ASSERT_EQ(t.value, nullptr);
+    ASSERT_TRUE(p->has_error());
+    ASSERT_EQ(p->error(), "1:20: invalid value for access control");
 }
 
 TEST_F(ParserImplTest, TypeDecl_Atomic) {
-  auto p = parser("atomic<f32>");
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  ASSERT_NE(t.value, nullptr) << p->error();
-  ASSERT_FALSE(p->has_error());
-  ASSERT_TRUE(t.value->Is<ast::Atomic>());
+    auto p = parser("atomic<f32>");
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    ASSERT_NE(t.value, nullptr) << p->error();
+    ASSERT_FALSE(p->has_error());
+    ASSERT_TRUE(t.value->Is<ast::Atomic>());
 
-  auto* atomic = t.value->As<ast::Atomic>();
-  ASSERT_TRUE(atomic->type->Is<ast::F32>());
-  EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 12u}}));
+    auto* atomic = t.value->As<ast::Atomic>();
+    ASSERT_TRUE(atomic->type->Is<ast::F32>());
+    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 12u}}));
 }
 
 TEST_F(ParserImplTest, TypeDecl_Atomic_ToVec) {
-  auto p = parser("atomic<vec2<f32>>");
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  ASSERT_NE(t.value, nullptr) << p->error();
-  ASSERT_FALSE(p->has_error());
-  ASSERT_TRUE(t.value->Is<ast::Atomic>());
+    auto p = parser("atomic<vec2<f32>>");
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    ASSERT_NE(t.value, nullptr) << p->error();
+    ASSERT_FALSE(p->has_error());
+    ASSERT_TRUE(t.value->Is<ast::Atomic>());
 
-  auto* atomic = t.value->As<ast::Atomic>();
-  ASSERT_TRUE(atomic->type->Is<ast::Vector>());
+    auto* atomic = t.value->As<ast::Atomic>();
+    ASSERT_TRUE(atomic->type->Is<ast::Vector>());
 
-  auto* vec = atomic->type->As<ast::Vector>();
-  ASSERT_EQ(vec->width, 2u);
-  ASSERT_TRUE(vec->type->Is<ast::F32>());
-  EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 18u}}));
+    auto* vec = atomic->type->As<ast::Vector>();
+    ASSERT_EQ(vec->width, 2u);
+    ASSERT_TRUE(vec->type->Is<ast::F32>());
+    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 18u}}));
 }
 
 TEST_F(ParserImplTest, TypeDecl_Atomic_MissingLessThan) {
-  auto p = parser("atomic f32>");
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.errored);
-  EXPECT_FALSE(t.matched);
-  ASSERT_EQ(t.value, nullptr);
-  ASSERT_TRUE(p->has_error());
-  ASSERT_EQ(p->error(), "1:8: expected '<' for atomic declaration");
+    auto p = parser("atomic f32>");
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.errored);
+    EXPECT_FALSE(t.matched);
+    ASSERT_EQ(t.value, nullptr);
+    ASSERT_TRUE(p->has_error());
+    ASSERT_EQ(p->error(), "1:8: expected '<' for atomic declaration");
 }
 
 TEST_F(ParserImplTest, TypeDecl_Atomic_MissingGreaterThan) {
-  auto p = parser("atomic<f32");
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.errored);
-  EXPECT_FALSE(t.matched);
-  ASSERT_EQ(t.value, nullptr);
-  ASSERT_TRUE(p->has_error());
-  ASSERT_EQ(p->error(), "1:11: expected '>' for atomic declaration");
+    auto p = parser("atomic<f32");
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.errored);
+    EXPECT_FALSE(t.matched);
+    ASSERT_EQ(t.value, nullptr);
+    ASSERT_TRUE(p->has_error());
+    ASSERT_EQ(p->error(), "1:11: expected '>' for atomic declaration");
 }
 
 TEST_F(ParserImplTest, TypeDecl_Atomic_MissingType) {
-  auto p = parser("atomic<>");
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.errored);
-  EXPECT_FALSE(t.matched);
-  ASSERT_EQ(t.value, nullptr);
-  ASSERT_TRUE(p->has_error());
-  ASSERT_EQ(p->error(), "1:8: invalid type for atomic declaration");
+    auto p = parser("atomic<>");
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.errored);
+    EXPECT_FALSE(t.matched);
+    ASSERT_EQ(t.value, nullptr);
+    ASSERT_TRUE(p->has_error());
+    ASSERT_EQ(p->error(), "1:8: invalid type for atomic declaration");
+}
+
+TEST_F(ParserImplTest, TypeDecl_Array_AbstractIntLiteralSize) {
+    auto p = parser("array<f32, 5>");
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    ASSERT_NE(t.value, nullptr) << p->error();
+    ASSERT_FALSE(p->has_error());
+    ASSERT_TRUE(t.value->Is<ast::Array>());
+
+    auto* a = t.value->As<ast::Array>();
+    ASSERT_FALSE(a->IsRuntimeArray());
+    ASSERT_TRUE(a->type->Is<ast::F32>());
+    EXPECT_EQ(a->attributes.size(), 0u);
+    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 14u}}));
+
+    auto* size = a->count->As<ast::IntLiteralExpression>();
+    ASSERT_NE(size, nullptr);
+    EXPECT_EQ(size->value, 5);
+    EXPECT_EQ(size->suffix, ast::IntLiteralExpression::Suffix::kNone);
 }
 
 TEST_F(ParserImplTest, TypeDecl_Array_SintLiteralSize) {
-  auto p = parser("array<f32, 5>");
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  ASSERT_NE(t.value, nullptr) << p->error();
-  ASSERT_FALSE(p->has_error());
-  ASSERT_TRUE(t.value->Is<ast::Array>());
+    auto p = parser("array<f32, 5i>");
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    ASSERT_NE(t.value, nullptr) << p->error();
+    ASSERT_FALSE(p->has_error());
+    ASSERT_TRUE(t.value->Is<ast::Array>());
 
-  auto* a = t.value->As<ast::Array>();
-  ASSERT_FALSE(a->IsRuntimeArray());
-  ASSERT_TRUE(a->type->Is<ast::F32>());
-  EXPECT_EQ(a->attributes.size(), 0u);
-  EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 14u}}));
+    auto* a = t.value->As<ast::Array>();
+    ASSERT_FALSE(a->IsRuntimeArray());
+    ASSERT_TRUE(a->type->Is<ast::F32>());
+    EXPECT_EQ(a->attributes.size(), 0u);
+    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 15u}}));
 
-  auto* size = a->count->As<ast::SintLiteralExpression>();
-  ASSERT_NE(size, nullptr);
-  EXPECT_EQ(size->ValueAsI32(), 5);
+    auto* size = a->count->As<ast::IntLiteralExpression>();
+    ASSERT_NE(size, nullptr);
+    EXPECT_EQ(size->value, 5);
+    EXPECT_EQ(size->suffix, ast::IntLiteralExpression::Suffix::kI);
 }
 
 TEST_F(ParserImplTest, TypeDecl_Array_UintLiteralSize) {
-  auto p = parser("array<f32, 5u>");
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  ASSERT_NE(t.value, nullptr) << p->error();
-  ASSERT_FALSE(p->has_error());
-  ASSERT_TRUE(t.value->Is<ast::Array>());
+    auto p = parser("array<f32, 5u>");
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    ASSERT_NE(t.value, nullptr) << p->error();
+    ASSERT_FALSE(p->has_error());
+    ASSERT_TRUE(t.value->Is<ast::Array>());
 
-  auto* a = t.value->As<ast::Array>();
-  ASSERT_FALSE(a->IsRuntimeArray());
-  ASSERT_TRUE(a->type->Is<ast::F32>());
-  EXPECT_EQ(a->attributes.size(), 0u);
-  EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 15u}}));
+    auto* a = t.value->As<ast::Array>();
+    ASSERT_FALSE(a->IsRuntimeArray());
+    ASSERT_TRUE(a->type->Is<ast::F32>());
+    EXPECT_EQ(a->attributes.size(), 0u);
+    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 15u}}));
 
-  auto* size = a->count->As<ast::UintLiteralExpression>();
-  ASSERT_NE(size, nullptr);
-  EXPECT_EQ(size->ValueAsU32(), 5u);
+    auto* size = a->count->As<ast::IntLiteralExpression>();
+    ASSERT_NE(size, nullptr);
+    EXPECT_EQ(size->suffix, ast::IntLiteralExpression::Suffix::kU);
 }
 
 TEST_F(ParserImplTest, TypeDecl_Array_ConstantSize) {
-  auto p = parser("array<f32, size>");
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  ASSERT_NE(t.value, nullptr) << p->error();
-  ASSERT_FALSE(p->has_error());
-  ASSERT_TRUE(t.value->Is<ast::Array>());
+    auto p = parser("array<f32, size>");
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    ASSERT_NE(t.value, nullptr) << p->error();
+    ASSERT_FALSE(p->has_error());
+    ASSERT_TRUE(t.value->Is<ast::Array>());
 
-  auto* a = t.value->As<ast::Array>();
-  ASSERT_FALSE(a->IsRuntimeArray());
-  ASSERT_TRUE(a->type->Is<ast::F32>());
-  EXPECT_EQ(a->attributes.size(), 0u);
-  EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 17u}}));
+    auto* a = t.value->As<ast::Array>();
+    ASSERT_FALSE(a->IsRuntimeArray());
+    ASSERT_TRUE(a->type->Is<ast::F32>());
+    EXPECT_EQ(a->attributes.size(), 0u);
+    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 17u}}));
 
-  auto* count_expr = a->count->As<ast::IdentifierExpression>();
-  ASSERT_NE(count_expr, nullptr);
-  EXPECT_EQ(p->builder().Symbols().NameFor(count_expr->symbol), "size");
+    auto* count_expr = a->count->As<ast::IdentifierExpression>();
+    ASSERT_NE(count_expr, nullptr);
+    EXPECT_EQ(p->builder().Symbols().NameFor(count_expr->symbol), "size");
 }
 
 TEST_F(ParserImplTest, TypeDecl_Array_Runtime) {
-  auto p = parser("array<u32>");
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  ASSERT_NE(t.value, nullptr) << p->error();
-  ASSERT_FALSE(p->has_error());
-  ASSERT_TRUE(t.value->Is<ast::Array>());
+    auto p = parser("array<u32>");
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    ASSERT_NE(t.value, nullptr) << p->error();
+    ASSERT_FALSE(p->has_error());
+    ASSERT_TRUE(t.value->Is<ast::Array>());
 
-  auto* a = t.value->As<ast::Array>();
-  ASSERT_TRUE(a->IsRuntimeArray());
-  ASSERT_TRUE(a->type->Is<ast::U32>());
-  EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 11u}}));
+    auto* a = t.value->As<ast::Array>();
+    ASSERT_TRUE(a->IsRuntimeArray());
+    ASSERT_TRUE(a->type->Is<ast::U32>());
+    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 11u}}));
 }
 
 TEST_F(ParserImplTest, TypeDecl_Array_Runtime_Vec) {
-  auto p = parser("array<vec4<u32>>");
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  ASSERT_NE(t.value, nullptr) << p->error();
-  ASSERT_FALSE(p->has_error());
-  ASSERT_TRUE(t.value->Is<ast::Array>());
+    auto p = parser("array<vec4<u32>>");
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    ASSERT_NE(t.value, nullptr) << p->error();
+    ASSERT_FALSE(p->has_error());
+    ASSERT_TRUE(t.value->Is<ast::Array>());
 
-  auto* a = t.value->As<ast::Array>();
-  ASSERT_TRUE(a->IsRuntimeArray());
-  ASSERT_TRUE(a->type->Is<ast::Vector>());
-  EXPECT_EQ(a->type->As<ast::Vector>()->width, 4u);
-  EXPECT_TRUE(a->type->As<ast::Vector>()->type->Is<ast::U32>());
-  EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 17u}}));
+    auto* a = t.value->As<ast::Array>();
+    ASSERT_TRUE(a->IsRuntimeArray());
+    ASSERT_TRUE(a->type->Is<ast::Vector>());
+    EXPECT_EQ(a->type->As<ast::Vector>()->width, 4u);
+    EXPECT_TRUE(a->type->As<ast::Vector>()->type->Is<ast::U32>());
+    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 17u}}));
 }
 
 TEST_F(ParserImplTest, TypeDecl_Array_BadSize) {
-  auto p = parser("array<f32, !>");
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.errored);
-  EXPECT_FALSE(t.matched);
-  ASSERT_EQ(t.value, nullptr);
-  ASSERT_TRUE(p->has_error());
-  ASSERT_EQ(p->error(), "1:12: expected array size expression");
+    auto p = parser("array<f32, !>");
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.errored);
+    EXPECT_FALSE(t.matched);
+    ASSERT_EQ(t.value, nullptr);
+    ASSERT_TRUE(p->has_error());
+    ASSERT_EQ(p->error(), "1:12: expected array size expression");
 }
 
 TEST_F(ParserImplTest, TypeDecl_Array_MissingSize) {
-  auto p = parser("array<f32,>");
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.errored);
-  EXPECT_FALSE(t.matched);
-  ASSERT_EQ(t.value, nullptr);
-  ASSERT_TRUE(p->has_error());
-  ASSERT_EQ(p->error(), "1:11: expected array size expression");
+    auto p = parser("array<f32,>");
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.errored);
+    EXPECT_FALSE(t.matched);
+    ASSERT_EQ(t.value, nullptr);
+    ASSERT_TRUE(p->has_error());
+    ASSERT_EQ(p->error(), "1:11: expected array size expression");
 }
 
 TEST_F(ParserImplTest, TypeDecl_Array_MissingLessThan) {
-  auto p = parser("array f32>");
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.errored);
-  EXPECT_FALSE(t.matched);
-  ASSERT_EQ(t.value, nullptr);
-  ASSERT_TRUE(p->has_error());
-  ASSERT_EQ(p->error(), "1:7: expected '<' for array declaration");
+    auto p = parser("array f32>");
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.errored);
+    EXPECT_FALSE(t.matched);
+    ASSERT_EQ(t.value, nullptr);
+    ASSERT_TRUE(p->has_error());
+    ASSERT_EQ(p->error(), "1:7: expected '<' for array declaration");
 }
 
 TEST_F(ParserImplTest, TypeDecl_Array_MissingGreaterThan) {
-  auto p = parser("array<f32");
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.errored);
-  EXPECT_FALSE(t.matched);
-  ASSERT_EQ(t.value, nullptr);
-  ASSERT_TRUE(p->has_error());
-  ASSERT_EQ(p->error(), "1:10: expected '>' for array declaration");
+    auto p = parser("array<f32");
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.errored);
+    EXPECT_FALSE(t.matched);
+    ASSERT_EQ(t.value, nullptr);
+    ASSERT_TRUE(p->has_error());
+    ASSERT_EQ(p->error(), "1:10: expected '>' for array declaration");
 }
 
 TEST_F(ParserImplTest, TypeDecl_Array_MissingComma) {
-  auto p = parser("array<f32 3>");
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.errored);
-  EXPECT_FALSE(t.matched);
-  ASSERT_EQ(t.value, nullptr);
-  ASSERT_TRUE(p->has_error());
-  ASSERT_EQ(p->error(), "1:11: expected '>' for array declaration");
+    auto p = parser("array<f32 3>");
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.errored);
+    EXPECT_FALSE(t.matched);
+    ASSERT_EQ(t.value, nullptr);
+    ASSERT_TRUE(p->has_error());
+    ASSERT_EQ(p->error(), "1:11: expected '>' for array declaration");
 }
 
 struct MatrixData {
-  const char* input;
-  size_t columns;
-  size_t rows;
-  Source::Range range;
+    const char* input;
+    size_t columns;
+    size_t rows;
+    Source::Range range;
 };
 inline std::ostream& operator<<(std::ostream& out, MatrixData data) {
-  out << std::string(data.input);
-  return out;
+    out << std::string(data.input);
+    return out;
 }
 
 class MatrixTest : public ParserImplTestWithParam<MatrixData> {};
 
 TEST_P(MatrixTest, Parse) {
-  auto params = GetParam();
-  auto p = parser(params.input);
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  ASSERT_NE(t.value, nullptr) << p->error();
-  ASSERT_FALSE(p->has_error());
-  EXPECT_TRUE(t.value->Is<ast::Matrix>());
-  auto* mat = t.value->As<ast::Matrix>();
-  EXPECT_EQ(mat->rows, params.rows);
-  EXPECT_EQ(mat->columns, params.columns);
-  EXPECT_EQ(t.value->source.range, params.range);
+    auto params = GetParam();
+    auto p = parser(params.input);
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    ASSERT_NE(t.value, nullptr) << p->error();
+    ASSERT_FALSE(p->has_error());
+    EXPECT_TRUE(t.value->Is<ast::Matrix>());
+    auto* mat = t.value->As<ast::Matrix>();
+    EXPECT_EQ(mat->rows, params.rows);
+    EXPECT_EQ(mat->columns, params.columns);
+    EXPECT_EQ(t.value->source.range, params.range);
 }
-INSTANTIATE_TEST_SUITE_P(
-    ParserImplTest,
-    MatrixTest,
-    testing::Values(MatrixData{"mat2x2<f32>", 2, 2, {{1u, 1u}, {1u, 12u}}},
-                    MatrixData{"mat2x3<f32>", 2, 3, {{1u, 1u}, {1u, 12u}}},
-                    MatrixData{"mat2x4<f32>", 2, 4, {{1u, 1u}, {1u, 12u}}},
-                    MatrixData{"mat3x2<f32>", 3, 2, {{1u, 1u}, {1u, 12u}}},
-                    MatrixData{"mat3x3<f32>", 3, 3, {{1u, 1u}, {1u, 12u}}},
-                    MatrixData{"mat3x4<f32>", 3, 4, {{1u, 1u}, {1u, 12u}}},
-                    MatrixData{"mat4x2<f32>", 4, 2, {{1u, 1u}, {1u, 12u}}},
-                    MatrixData{"mat4x3<f32>", 4, 3, {{1u, 1u}, {1u, 12u}}},
-                    MatrixData{"mat4x4<f32>", 4, 4, {{1u, 1u}, {1u, 12u}}}));
+INSTANTIATE_TEST_SUITE_P(ParserImplTest,
+                         MatrixTest,
+                         testing::Values(MatrixData{"mat2x2<f32>", 2, 2, {{1u, 1u}, {1u, 12u}}},
+                                         MatrixData{"mat2x3<f32>", 2, 3, {{1u, 1u}, {1u, 12u}}},
+                                         MatrixData{"mat2x4<f32>", 2, 4, {{1u, 1u}, {1u, 12u}}},
+                                         MatrixData{"mat3x2<f32>", 3, 2, {{1u, 1u}, {1u, 12u}}},
+                                         MatrixData{"mat3x3<f32>", 3, 3, {{1u, 1u}, {1u, 12u}}},
+                                         MatrixData{"mat3x4<f32>", 3, 4, {{1u, 1u}, {1u, 12u}}},
+                                         MatrixData{"mat4x2<f32>", 4, 2, {{1u, 1u}, {1u, 12u}}},
+                                         MatrixData{"mat4x3<f32>", 4, 3, {{1u, 1u}, {1u, 12u}}},
+                                         MatrixData{"mat4x4<f32>", 4, 4, {{1u, 1u}, {1u, 12u}}}));
 
-class MatrixMissingGreaterThanTest
-    : public ParserImplTestWithParam<MatrixData> {};
+class MatrixMissingGreaterThanTest : public ParserImplTestWithParam<MatrixData> {};
 
 TEST_P(MatrixMissingGreaterThanTest, Handles_Missing_GreaterThan) {
-  auto params = GetParam();
-  auto p = parser(params.input);
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.errored);
-  EXPECT_FALSE(t.matched);
-  ASSERT_EQ(t.value, nullptr);
-  ASSERT_TRUE(p->has_error());
-  ASSERT_EQ(p->error(), "1:11: expected '>' for matrix");
+    auto params = GetParam();
+    auto p = parser(params.input);
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.errored);
+    EXPECT_FALSE(t.matched);
+    ASSERT_EQ(t.value, nullptr);
+    ASSERT_TRUE(p->has_error());
+    ASSERT_EQ(p->error(), "1:11: expected '>' for matrix");
 }
 INSTANTIATE_TEST_SUITE_P(ParserImplTest,
                          MatrixMissingGreaterThanTest,
@@ -587,14 +606,14 @@
 class MatrixMissingType : public ParserImplTestWithParam<MatrixData> {};
 
 TEST_P(MatrixMissingType, Handles_Missing_Type) {
-  auto params = GetParam();
-  auto p = parser(params.input);
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.errored);
-  EXPECT_FALSE(t.matched);
-  ASSERT_EQ(t.value, nullptr);
-  ASSERT_TRUE(p->has_error());
-  ASSERT_EQ(p->error(), "1:8: invalid type for matrix");
+    auto params = GetParam();
+    auto p = parser(params.input);
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.errored);
+    EXPECT_FALSE(t.matched);
+    ASSERT_EQ(t.value, nullptr);
+    ASSERT_TRUE(p->has_error());
+    ASSERT_EQ(p->error(), "1:8: invalid type for matrix");
 }
 INSTANTIATE_TEST_SUITE_P(ParserImplTest,
                          MatrixMissingType,
@@ -609,28 +628,28 @@
                                          MatrixData{"mat4x4<>", 4, 4, {}}));
 
 TEST_F(ParserImplTest, TypeDecl_Sampler) {
-  auto p = parser("sampler");
+    auto p = parser("sampler");
 
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  ASSERT_NE(t.value, nullptr) << p->error();
-  ASSERT_TRUE(t.value->Is<ast::Sampler>());
-  ASSERT_FALSE(t.value->As<ast::Sampler>()->IsComparison());
-  EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 8u}}));
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    ASSERT_NE(t.value, nullptr) << p->error();
+    ASSERT_TRUE(t.value->Is<ast::Sampler>());
+    ASSERT_FALSE(t.value->As<ast::Sampler>()->IsComparison());
+    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 8u}}));
 }
 
 TEST_F(ParserImplTest, TypeDecl_Texture) {
-  auto p = parser("texture_cube<f32>");
+    auto p = parser("texture_cube<f32>");
 
-  auto t = p->type_decl();
-  EXPECT_TRUE(t.matched);
-  EXPECT_FALSE(t.errored);
-  ASSERT_NE(t.value, nullptr);
-  ASSERT_TRUE(t.value->Is<ast::Texture>());
-  ASSERT_TRUE(t.value->Is<ast::SampledTexture>());
-  ASSERT_TRUE(t.value->As<ast::SampledTexture>()->type->Is<ast::F32>());
-  EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 18u}}));
+    auto t = p->type_decl();
+    EXPECT_TRUE(t.matched);
+    EXPECT_FALSE(t.errored);
+    ASSERT_NE(t.value, nullptr);
+    ASSERT_TRUE(t.value->Is<ast::Texture>());
+    ASSERT_TRUE(t.value->Is<ast::SampledTexture>());
+    ASSERT_TRUE(t.value->As<ast::SampledTexture>()->type->Is<ast::F32>());
+    EXPECT_EQ(t.value->source.range, (Source::Range{{1u, 1u}, {1u, 18u}}));
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_unary_expression_test.cc b/src/tint/reader/wgsl/parser_impl_unary_expression_test.cc
index 0ebefa4..184de66 100644
--- a/src/tint/reader/wgsl/parser_impl_unary_expression_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_unary_expression_test.cc
@@ -19,169 +19,177 @@
 namespace {
 
 TEST_F(ParserImplTest, UnaryExpression_Postix) {
-  auto p = parser("a[2]");
-  auto e = p->unary_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
+    auto p = parser("a[2]");
+    auto e = p->unary_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
 
-  ASSERT_TRUE(e->Is<ast::IndexAccessorExpression>());
-  auto* idx = e->As<ast::IndexAccessorExpression>();
-  ASSERT_TRUE(idx->object->Is<ast::IdentifierExpression>());
-  auto* ident = idx->object->As<ast::IdentifierExpression>();
-  EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
+    ASSERT_TRUE(e->Is<ast::IndexAccessorExpression>());
+    auto* idx = e->As<ast::IndexAccessorExpression>();
+    ASSERT_TRUE(idx->object->Is<ast::IdentifierExpression>());
+    auto* ident = idx->object->As<ast::IdentifierExpression>();
+    EXPECT_EQ(ident->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_TRUE(idx->index->Is<ast::SintLiteralExpression>());
-  ASSERT_EQ(idx->index->As<ast::SintLiteralExpression>()->value, 2);
+    ASSERT_TRUE(idx->index->Is<ast::IntLiteralExpression>());
+    ASSERT_EQ(idx->index->As<ast::IntLiteralExpression>()->value, 2);
+    ASSERT_EQ(idx->index->As<ast::IntLiteralExpression>()->suffix,
+              ast::IntLiteralExpression::Suffix::kNone);
 }
 
 TEST_F(ParserImplTest, UnaryExpression_Minus) {
-  auto p = parser("- 1");
-  auto e = p->unary_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::UnaryOpExpression>());
+    auto p = parser("- 1");
+    auto e = p->unary_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::UnaryOpExpression>());
 
-  auto* u = e->As<ast::UnaryOpExpression>();
-  ASSERT_EQ(u->op, ast::UnaryOp::kNegation);
+    auto* u = e->As<ast::UnaryOpExpression>();
+    ASSERT_EQ(u->op, ast::UnaryOp::kNegation);
 
-  ASSERT_TRUE(u->expr->Is<ast::SintLiteralExpression>());
-  EXPECT_EQ(u->expr->As<ast::SintLiteralExpression>()->value, 1);
+    ASSERT_TRUE(u->expr->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(u->expr->As<ast::IntLiteralExpression>()->value, 1);
+    ASSERT_EQ(u->expr->As<ast::IntLiteralExpression>()->suffix,
+              ast::IntLiteralExpression::Suffix::kNone);
 }
 
 TEST_F(ParserImplTest, UnaryExpression_AddressOf) {
-  auto p = parser("&x");
-  auto e = p->unary_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::UnaryOpExpression>());
+    auto p = parser("&x");
+    auto e = p->unary_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::UnaryOpExpression>());
 
-  auto* u = e->As<ast::UnaryOpExpression>();
-  EXPECT_EQ(u->op, ast::UnaryOp::kAddressOf);
-  EXPECT_TRUE(u->expr->Is<ast::IdentifierExpression>());
+    auto* u = e->As<ast::UnaryOpExpression>();
+    EXPECT_EQ(u->op, ast::UnaryOp::kAddressOf);
+    EXPECT_TRUE(u->expr->Is<ast::IdentifierExpression>());
 }
 
 TEST_F(ParserImplTest, UnaryExpression_Dereference) {
-  auto p = parser("*x");
-  auto e = p->unary_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::UnaryOpExpression>());
+    auto p = parser("*x");
+    auto e = p->unary_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::UnaryOpExpression>());
 
-  auto* u = e->As<ast::UnaryOpExpression>();
-  EXPECT_EQ(u->op, ast::UnaryOp::kIndirection);
-  EXPECT_TRUE(u->expr->Is<ast::IdentifierExpression>());
+    auto* u = e->As<ast::UnaryOpExpression>();
+    EXPECT_EQ(u->op, ast::UnaryOp::kIndirection);
+    EXPECT_TRUE(u->expr->Is<ast::IdentifierExpression>());
 }
 
 TEST_F(ParserImplTest, UnaryExpression_AddressOf_Precedence) {
-  auto p = parser("&x.y");
-  auto e = p->logical_or_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::UnaryOpExpression>());
+    auto p = parser("&x.y");
+    auto e = p->logical_or_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::UnaryOpExpression>());
 
-  auto* u = e->As<ast::UnaryOpExpression>();
-  EXPECT_EQ(u->op, ast::UnaryOp::kAddressOf);
-  EXPECT_TRUE(u->expr->Is<ast::MemberAccessorExpression>());
+    auto* u = e->As<ast::UnaryOpExpression>();
+    EXPECT_EQ(u->op, ast::UnaryOp::kAddressOf);
+    EXPECT_TRUE(u->expr->Is<ast::MemberAccessorExpression>());
 }
 
 TEST_F(ParserImplTest, UnaryExpression_Dereference_Precedence) {
-  auto p = parser("*x.y");
-  auto e = p->logical_or_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::UnaryOpExpression>());
+    auto p = parser("*x.y");
+    auto e = p->logical_or_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::UnaryOpExpression>());
 
-  auto* u = e->As<ast::UnaryOpExpression>();
-  EXPECT_EQ(u->op, ast::UnaryOp::kIndirection);
-  EXPECT_TRUE(u->expr->Is<ast::MemberAccessorExpression>());
+    auto* u = e->As<ast::UnaryOpExpression>();
+    EXPECT_EQ(u->op, ast::UnaryOp::kIndirection);
+    EXPECT_TRUE(u->expr->Is<ast::MemberAccessorExpression>());
 }
 
 TEST_F(ParserImplTest, UnaryExpression_Minus_InvalidRHS) {
-  auto p = parser("-if(a) {}");
-  auto e = p->unary_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:2: unable to parse right side of - expression");
+    auto p = parser("-if(a) {}");
+    auto e = p->unary_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:2: unable to parse right side of - expression");
 }
 
 TEST_F(ParserImplTest, UnaryExpression_Bang) {
-  auto p = parser("!1");
-  auto e = p->unary_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::UnaryOpExpression>());
+    auto p = parser("!1");
+    auto e = p->unary_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::UnaryOpExpression>());
 
-  auto* u = e->As<ast::UnaryOpExpression>();
-  ASSERT_EQ(u->op, ast::UnaryOp::kNot);
+    auto* u = e->As<ast::UnaryOpExpression>();
+    ASSERT_EQ(u->op, ast::UnaryOp::kNot);
 
-  ASSERT_TRUE(u->expr->Is<ast::SintLiteralExpression>());
-  EXPECT_EQ(u->expr->As<ast::SintLiteralExpression>()->value, 1);
+    ASSERT_TRUE(u->expr->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(u->expr->As<ast::IntLiteralExpression>()->value, 1);
+    ASSERT_EQ(u->expr->As<ast::IntLiteralExpression>()->suffix,
+              ast::IntLiteralExpression::Suffix::kNone);
 }
 
 TEST_F(ParserImplTest, UnaryExpression_Bang_InvalidRHS) {
-  auto p = parser("!if (a) {}");
-  auto e = p->unary_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:2: unable to parse right side of ! expression");
+    auto p = parser("!if (a) {}");
+    auto e = p->unary_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:2: unable to parse right side of ! expression");
 }
 
 TEST_F(ParserImplTest, UnaryExpression_Tilde) {
-  auto p = parser("~1");
-  auto e = p->unary_expression();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::UnaryOpExpression>());
+    auto p = parser("~1");
+    auto e = p->unary_expression();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::UnaryOpExpression>());
 
-  auto* u = e->As<ast::UnaryOpExpression>();
-  ASSERT_EQ(u->op, ast::UnaryOp::kComplement);
+    auto* u = e->As<ast::UnaryOpExpression>();
+    ASSERT_EQ(u->op, ast::UnaryOp::kComplement);
 
-  ASSERT_TRUE(u->expr->Is<ast::SintLiteralExpression>());
-  EXPECT_EQ(u->expr->As<ast::SintLiteralExpression>()->value, 1);
+    ASSERT_TRUE(u->expr->Is<ast::IntLiteralExpression>());
+    EXPECT_EQ(u->expr->As<ast::IntLiteralExpression>()->value, 1);
+    ASSERT_EQ(u->expr->As<ast::IntLiteralExpression>()->suffix,
+              ast::IntLiteralExpression::Suffix::kNone);
 }
 
 TEST_F(ParserImplTest, UnaryExpression_PrefixPlusPlus) {
-  auto p = parser("++a");
-  auto e = p->unary_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(),
-            "1:1: prefix increment and decrement operators are reserved for a "
-            "future WGSL version");
+    auto p = parser("++a");
+    auto e = p->unary_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(),
+              "1:1: prefix increment and decrement operators are reserved for a "
+              "future WGSL version");
 }
 
 TEST_F(ParserImplTest, UnaryExpression_PrefixMinusMinus) {
-  auto p = parser("--a");
-  auto e = p->unary_expression();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(),
-            "1:1: prefix increment and decrement operators are reserved for a "
-            "future WGSL version");
+    auto p = parser("--a");
+    auto e = p->unary_expression();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(),
+              "1:1: prefix increment and decrement operators are reserved for a "
+              "future WGSL version");
 }
 
 }  // namespace
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 9a02844..133dd36 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
@@ -18,43 +18,42 @@
 namespace {
 
 TEST_F(ParserImplTest, AttributeList_Parses) {
-  auto p = parser(R"(@location(4) @builtin(position))");
-  auto attrs = p->attribute_list();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  ASSERT_FALSE(attrs.errored);
-  ASSERT_TRUE(attrs.matched);
-  ASSERT_EQ(attrs.value.size(), 2u);
+    auto p = parser(R"(@location(4) @builtin(position))");
+    auto attrs = p->attribute_list();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    ASSERT_FALSE(attrs.errored);
+    ASSERT_TRUE(attrs.matched);
+    ASSERT_EQ(attrs.value.size(), 2u);
 
-  auto* attr_0 = attrs.value[0]->As<ast::Attribute>();
-  auto* attr_1 = attrs.value[1]->As<ast::Attribute>();
-  ASSERT_NE(attr_0, nullptr);
-  ASSERT_NE(attr_1, nullptr);
+    auto* attr_0 = attrs.value[0]->As<ast::Attribute>();
+    auto* attr_1 = attrs.value[1]->As<ast::Attribute>();
+    ASSERT_NE(attr_0, nullptr);
+    ASSERT_NE(attr_1, nullptr);
 
-  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);
+    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);
 }
 
 TEST_F(ParserImplTest, AttributeList_Invalid) {
-  auto p = parser(R"(@invalid)");
-  auto attrs = p->attribute_list();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(attrs.errored);
-  EXPECT_FALSE(attrs.matched);
-  EXPECT_TRUE(attrs.value.empty());
-  EXPECT_EQ(p->error(), R"(1:2: expected attribute)");
+    auto p = parser(R"(@invalid)");
+    auto attrs = p->attribute_list();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(attrs.errored);
+    EXPECT_FALSE(attrs.matched);
+    EXPECT_TRUE(attrs.value.empty());
+    EXPECT_EQ(p->error(), R"(1:2: expected attribute)");
 }
 
 TEST_F(ParserImplTest, AttributeList_InvalidValue) {
-  auto p = parser("@builtin(invalid)");
-  auto attrs = p->attribute_list();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(attrs.errored);
-  EXPECT_FALSE(attrs.matched);
-  EXPECT_TRUE(attrs.value.empty());
-  EXPECT_EQ(p->error(), "1:10: invalid value for builtin attribute");
+    auto p = parser("@builtin(invalid)");
+    auto attrs = p->attribute_list();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(attrs.errored);
+    EXPECT_FALSE(attrs.matched);
+    EXPECT_TRUE(attrs.value.empty());
+    EXPECT_EQ(p->error(), "1:10: invalid value for builtin attribute");
 }
 
 }  // namespace
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 435378f..8833273 100644
--- a/src/tint/reader/wgsl/parser_impl_variable_attribute_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_variable_attribute_test.cc
@@ -18,395 +18,386 @@
 namespace {
 
 TEST_F(ParserImplTest, Attribute_Location) {
-  auto p = parser("location(4)");
-  auto attr = p->attribute();
-  EXPECT_TRUE(attr.matched);
-  EXPECT_FALSE(attr.errored);
-  ASSERT_NE(attr.value, nullptr);
-  auto* var_attr = attr.value->As<ast::Attribute>();
-  ASSERT_NE(var_attr, nullptr);
-  ASSERT_FALSE(p->has_error());
-  ASSERT_TRUE(var_attr->Is<ast::LocationAttribute>());
+    auto p = parser("location(4)");
+    auto attr = p->attribute();
+    EXPECT_TRUE(attr.matched);
+    EXPECT_FALSE(attr.errored);
+    ASSERT_NE(attr.value, nullptr);
+    auto* var_attr = attr.value->As<ast::Attribute>();
+    ASSERT_NE(var_attr, nullptr);
+    ASSERT_FALSE(p->has_error());
+    ASSERT_TRUE(var_attr->Is<ast::LocationAttribute>());
 
-  auto* loc = var_attr->As<ast::LocationAttribute>();
-  EXPECT_EQ(loc->value, 4u);
+    auto* loc = var_attr->As<ast::LocationAttribute>();
+    EXPECT_EQ(loc->value, 4u);
 }
 
 TEST_F(ParserImplTest, Attribute_Location_MissingLeftParen) {
-  auto p = parser("location 4)");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:10: expected '(' for location attribute");
+    auto p = parser("location 4)");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:10: expected '(' for location attribute");
 }
 
 TEST_F(ParserImplTest, Attribute_Location_MissingRightParen) {
-  auto p = parser("location(4");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:11: expected ')' for location attribute");
+    auto p = parser("location(4");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:11: expected ')' for location attribute");
 }
 
 TEST_F(ParserImplTest, Attribute_Location_MissingValue) {
-  auto p = parser("location()");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(),
-            "1:10: expected signed integer literal for location attribute");
+    auto p = parser("location()");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:10: expected signed integer literal for location attribute");
 }
 
 TEST_F(ParserImplTest, Attribute_Location_MissingInvalid) {
-  auto p = parser("location(nan)");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(),
-            "1:10: expected signed integer literal for location attribute");
+    auto p = parser("location(nan)");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:10: expected signed integer literal for location attribute");
 }
 
 struct BuiltinData {
-  const char* input;
-  ast::Builtin result;
+    const char* input;
+    ast::Builtin result;
 };
 inline std::ostream& operator<<(std::ostream& out, BuiltinData data) {
-  out << std::string(data.input);
-  return out;
+    out << std::string(data.input);
+    return out;
 }
 
 class BuiltinTest : public ParserImplTestWithParam<BuiltinData> {};
 
 TEST_P(BuiltinTest, Attribute_Builtin) {
-  auto params = GetParam();
-  auto p = parser(std::string("builtin(") + params.input + ")");
+    auto params = GetParam();
+    auto p = parser(std::string("builtin(") + params.input + ")");
 
-  auto attr = p->attribute();
-  EXPECT_TRUE(attr.matched);
-  EXPECT_FALSE(attr.errored);
-  ASSERT_NE(attr.value, nullptr);
-  auto* var_attr = attr.value->As<ast::Attribute>();
-  ASSERT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(var_attr, nullptr);
-  ASSERT_TRUE(var_attr->Is<ast::BuiltinAttribute>());
+    auto attr = p->attribute();
+    EXPECT_TRUE(attr.matched);
+    EXPECT_FALSE(attr.errored);
+    ASSERT_NE(attr.value, nullptr);
+    auto* var_attr = attr.value->As<ast::Attribute>();
+    ASSERT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(var_attr, nullptr);
+    ASSERT_TRUE(var_attr->Is<ast::BuiltinAttribute>());
 
-  auto* builtin = var_attr->As<ast::BuiltinAttribute>();
-  EXPECT_EQ(builtin->builtin, params.result);
+    auto* builtin = var_attr->As<ast::BuiltinAttribute>();
+    EXPECT_EQ(builtin->builtin, params.result);
 }
 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::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}));
 
 TEST_F(ParserImplTest, Attribute_Builtin_MissingLeftParen) {
-  auto p = parser("builtin position)");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:9: expected '(' for builtin attribute");
+    auto p = parser("builtin position)");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:9: expected '(' for builtin attribute");
 }
 
 TEST_F(ParserImplTest, Attribute_Builtin_MissingRightParen) {
-  auto p = parser("builtin(position");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:17: expected ')' for builtin attribute");
+    auto p = parser("builtin(position");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:17: expected ')' for builtin attribute");
 }
 
 TEST_F(ParserImplTest, Attribute_Builtin_MissingValue) {
-  auto p = parser("builtin()");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:9: expected identifier for builtin");
+    auto p = parser("builtin()");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:9: expected identifier for builtin");
 }
 
 TEST_F(ParserImplTest, Attribute_Builtin_InvalidValue) {
-  auto p = parser("builtin(other_thingy)");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:9: invalid value for builtin attribute");
+    auto p = parser("builtin(other_thingy)");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:9: invalid value for builtin attribute");
 }
 
 TEST_F(ParserImplTest, Attribute_Builtin_MissingInvalid) {
-  auto p = parser("builtin(3)");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:9: expected identifier for builtin");
+    auto p = parser("builtin(3)");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:9: expected identifier for builtin");
 }
 
 TEST_F(ParserImplTest, Attribute_Interpolate_Flat) {
-  auto p = parser("interpolate(flat)");
-  auto attr = p->attribute();
-  EXPECT_TRUE(attr.matched);
-  EXPECT_FALSE(attr.errored);
-  ASSERT_NE(attr.value, nullptr);
-  auto* var_attr = attr.value->As<ast::Attribute>();
-  ASSERT_NE(var_attr, nullptr);
-  ASSERT_FALSE(p->has_error());
-  ASSERT_TRUE(var_attr->Is<ast::InterpolateAttribute>());
+    auto p = parser("interpolate(flat)");
+    auto attr = p->attribute();
+    EXPECT_TRUE(attr.matched);
+    EXPECT_FALSE(attr.errored);
+    ASSERT_NE(attr.value, nullptr);
+    auto* var_attr = attr.value->As<ast::Attribute>();
+    ASSERT_NE(var_attr, nullptr);
+    ASSERT_FALSE(p->has_error());
+    ASSERT_TRUE(var_attr->Is<ast::InterpolateAttribute>());
 
-  auto* interp = var_attr->As<ast::InterpolateAttribute>();
-  EXPECT_EQ(interp->type, ast::InterpolationType::kFlat);
-  EXPECT_EQ(interp->sampling, ast::InterpolationSampling::kNone);
+    auto* interp = var_attr->As<ast::InterpolateAttribute>();
+    EXPECT_EQ(interp->type, ast::InterpolationType::kFlat);
+    EXPECT_EQ(interp->sampling, ast::InterpolationSampling::kNone);
 }
 
 TEST_F(ParserImplTest, Attribute_Interpolate_Perspective_Center) {
-  auto p = parser("interpolate(perspective, center)");
-  auto attr = p->attribute();
-  EXPECT_TRUE(attr.matched);
-  EXPECT_FALSE(attr.errored);
-  ASSERT_NE(attr.value, nullptr);
-  auto* var_attr = attr.value->As<ast::Attribute>();
-  ASSERT_NE(var_attr, nullptr);
-  ASSERT_FALSE(p->has_error());
-  ASSERT_TRUE(var_attr->Is<ast::InterpolateAttribute>());
+    auto p = parser("interpolate(perspective, center)");
+    auto attr = p->attribute();
+    EXPECT_TRUE(attr.matched);
+    EXPECT_FALSE(attr.errored);
+    ASSERT_NE(attr.value, nullptr);
+    auto* var_attr = attr.value->As<ast::Attribute>();
+    ASSERT_NE(var_attr, nullptr);
+    ASSERT_FALSE(p->has_error());
+    ASSERT_TRUE(var_attr->Is<ast::InterpolateAttribute>());
 
-  auto* interp = var_attr->As<ast::InterpolateAttribute>();
-  EXPECT_EQ(interp->type, ast::InterpolationType::kPerspective);
-  EXPECT_EQ(interp->sampling, ast::InterpolationSampling::kCenter);
+    auto* interp = var_attr->As<ast::InterpolateAttribute>();
+    EXPECT_EQ(interp->type, ast::InterpolationType::kPerspective);
+    EXPECT_EQ(interp->sampling, ast::InterpolationSampling::kCenter);
 }
 
 TEST_F(ParserImplTest, Attribute_Interpolate_Perspective_Centroid) {
-  auto p = parser("interpolate(perspective, centroid)");
-  auto attr = p->attribute();
-  EXPECT_TRUE(attr.matched);
-  EXPECT_FALSE(attr.errored);
-  ASSERT_NE(attr.value, nullptr);
-  auto* var_attr = attr.value->As<ast::Attribute>();
-  ASSERT_NE(var_attr, nullptr);
-  ASSERT_FALSE(p->has_error());
-  ASSERT_TRUE(var_attr->Is<ast::InterpolateAttribute>());
+    auto p = parser("interpolate(perspective, centroid)");
+    auto attr = p->attribute();
+    EXPECT_TRUE(attr.matched);
+    EXPECT_FALSE(attr.errored);
+    ASSERT_NE(attr.value, nullptr);
+    auto* var_attr = attr.value->As<ast::Attribute>();
+    ASSERT_NE(var_attr, nullptr);
+    ASSERT_FALSE(p->has_error());
+    ASSERT_TRUE(var_attr->Is<ast::InterpolateAttribute>());
 
-  auto* interp = var_attr->As<ast::InterpolateAttribute>();
-  EXPECT_EQ(interp->type, ast::InterpolationType::kPerspective);
-  EXPECT_EQ(interp->sampling, ast::InterpolationSampling::kCentroid);
+    auto* interp = var_attr->As<ast::InterpolateAttribute>();
+    EXPECT_EQ(interp->type, ast::InterpolationType::kPerspective);
+    EXPECT_EQ(interp->sampling, ast::InterpolationSampling::kCentroid);
 }
 
 TEST_F(ParserImplTest, Attribute_Interpolate_Linear_Sample) {
-  auto p = parser("interpolate(linear, sample)");
-  auto attr = p->attribute();
-  EXPECT_TRUE(attr.matched);
-  EXPECT_FALSE(attr.errored);
-  ASSERT_NE(attr.value, nullptr);
-  auto* var_attr = attr.value->As<ast::Attribute>();
-  ASSERT_NE(var_attr, nullptr);
-  ASSERT_FALSE(p->has_error());
-  ASSERT_TRUE(var_attr->Is<ast::InterpolateAttribute>());
+    auto p = parser("interpolate(linear, sample)");
+    auto attr = p->attribute();
+    EXPECT_TRUE(attr.matched);
+    EXPECT_FALSE(attr.errored);
+    ASSERT_NE(attr.value, nullptr);
+    auto* var_attr = attr.value->As<ast::Attribute>();
+    ASSERT_NE(var_attr, nullptr);
+    ASSERT_FALSE(p->has_error());
+    ASSERT_TRUE(var_attr->Is<ast::InterpolateAttribute>());
 
-  auto* interp = var_attr->As<ast::InterpolateAttribute>();
-  EXPECT_EQ(interp->type, ast::InterpolationType::kLinear);
-  EXPECT_EQ(interp->sampling, ast::InterpolationSampling::kSample);
+    auto* interp = var_attr->As<ast::InterpolateAttribute>();
+    EXPECT_EQ(interp->type, ast::InterpolationType::kLinear);
+    EXPECT_EQ(interp->sampling, ast::InterpolationSampling::kSample);
 }
 
 TEST_F(ParserImplTest, Attribute_Interpolate_MissingLeftParen) {
-  auto p = parser("interpolate flat)");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:13: expected '(' for interpolate attribute");
+    auto p = parser("interpolate flat)");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:13: expected '(' for interpolate attribute");
 }
 
 TEST_F(ParserImplTest, Attribute_Interpolate_MissingRightParen) {
-  auto p = parser("interpolate(flat");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:17: expected ')' for interpolate attribute");
+    auto p = parser("interpolate(flat");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:17: expected ')' for interpolate attribute");
 }
 
 TEST_F(ParserImplTest, Attribute_Interpolate_MissingFirstValue) {
-  auto p = parser("interpolate()");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:13: invalid interpolation type");
+    auto p = parser("interpolate()");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:13: invalid interpolation type");
 }
 
 TEST_F(ParserImplTest, Attribute_Interpolate_InvalidFirstValue) {
-  auto p = parser("interpolate(other_thingy)");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:13: invalid interpolation type");
+    auto p = parser("interpolate(other_thingy)");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:13: invalid interpolation type");
 }
 
 TEST_F(ParserImplTest, Attribute_Interpolate_MissingSecondValue) {
-  auto p = parser("interpolate(perspective,)");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:25: invalid interpolation sampling");
+    auto p = parser("interpolate(perspective,)");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:25: invalid interpolation sampling");
 }
 
 TEST_F(ParserImplTest, Attribute_Interpolate_InvalidSecondValue) {
-  auto p = parser("interpolate(perspective, nope)");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:26: invalid interpolation sampling");
+    auto p = parser("interpolate(perspective, nope)");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:26: invalid interpolation sampling");
 }
 
 TEST_F(ParserImplTest, Attribute_Binding) {
-  auto p = parser("binding(4)");
-  auto attr = p->attribute();
-  EXPECT_TRUE(attr.matched);
-  EXPECT_FALSE(attr.errored);
-  ASSERT_NE(attr.value, nullptr);
-  auto* var_attr = attr.value->As<ast::Attribute>();
-  ASSERT_NE(var_attr, nullptr);
-  ASSERT_FALSE(p->has_error());
-  ASSERT_TRUE(var_attr->Is<ast::BindingAttribute>());
+    auto p = parser("binding(4)");
+    auto attr = p->attribute();
+    EXPECT_TRUE(attr.matched);
+    EXPECT_FALSE(attr.errored);
+    ASSERT_NE(attr.value, nullptr);
+    auto* var_attr = attr.value->As<ast::Attribute>();
+    ASSERT_NE(var_attr, nullptr);
+    ASSERT_FALSE(p->has_error());
+    ASSERT_TRUE(var_attr->Is<ast::BindingAttribute>());
 
-  auto* binding = var_attr->As<ast::BindingAttribute>();
-  EXPECT_EQ(binding->value, 4u);
+    auto* binding = var_attr->As<ast::BindingAttribute>();
+    EXPECT_EQ(binding->value, 4u);
 }
 
 TEST_F(ParserImplTest, Attribute_Binding_MissingLeftParen) {
-  auto p = parser("binding 4)");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:9: expected '(' for binding attribute");
+    auto p = parser("binding 4)");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:9: expected '(' for binding attribute");
 }
 
 TEST_F(ParserImplTest, Attribute_Binding_MissingRightParen) {
-  auto p = parser("binding(4");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:10: expected ')' for binding attribute");
+    auto p = parser("binding(4");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:10: expected ')' for binding attribute");
 }
 
 TEST_F(ParserImplTest, Attribute_Binding_MissingValue) {
-  auto p = parser("binding()");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(),
-            "1:9: expected signed integer literal for binding attribute");
+    auto p = parser("binding()");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:9: expected signed integer literal for binding attribute");
 }
 
 TEST_F(ParserImplTest, Attribute_Binding_MissingInvalid) {
-  auto p = parser("binding(nan)");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(),
-            "1:9: expected signed integer literal for binding attribute");
+    auto p = parser("binding(nan)");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:9: expected signed integer literal for binding attribute");
 }
 
 TEST_F(ParserImplTest, Attribute_group) {
-  auto p = parser("group(4)");
-  auto attr = p->attribute();
-  EXPECT_TRUE(attr.matched);
-  EXPECT_FALSE(attr.errored);
-  ASSERT_NE(attr.value, nullptr);
-  auto* var_attr = attr.value->As<ast::Attribute>();
-  ASSERT_FALSE(p->has_error());
-  ASSERT_NE(var_attr, nullptr);
-  ASSERT_TRUE(var_attr->Is<ast::GroupAttribute>());
+    auto p = parser("group(4)");
+    auto attr = p->attribute();
+    EXPECT_TRUE(attr.matched);
+    EXPECT_FALSE(attr.errored);
+    ASSERT_NE(attr.value, nullptr);
+    auto* var_attr = attr.value->As<ast::Attribute>();
+    ASSERT_FALSE(p->has_error());
+    ASSERT_NE(var_attr, nullptr);
+    ASSERT_TRUE(var_attr->Is<ast::GroupAttribute>());
 
-  auto* group = var_attr->As<ast::GroupAttribute>();
-  EXPECT_EQ(group->value, 4u);
+    auto* group = var_attr->As<ast::GroupAttribute>();
+    EXPECT_EQ(group->value, 4u);
 }
 
 TEST_F(ParserImplTest, Attribute_Group_MissingLeftParen) {
-  auto p = parser("group 2)");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:7: expected '(' for group attribute");
+    auto p = parser("group 2)");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:7: expected '(' for group attribute");
 }
 
 TEST_F(ParserImplTest, Attribute_Group_MissingRightParen) {
-  auto p = parser("group(2");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:8: expected ')' for group attribute");
+    auto p = parser("group(2");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:8: expected ')' for group attribute");
 }
 
 TEST_F(ParserImplTest, Attribute_Group_MissingValue) {
-  auto p = parser("group()");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(),
-            "1:7: expected signed integer literal for group attribute");
+    auto p = parser("group()");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:7: expected signed integer literal for group attribute");
 }
 
 TEST_F(ParserImplTest, Attribute_Group_MissingInvalid) {
-  auto p = parser("group(nan)");
-  auto attr = p->attribute();
-  EXPECT_FALSE(attr.matched);
-  EXPECT_TRUE(attr.errored);
-  EXPECT_EQ(attr.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(),
-            "1:7: expected signed integer literal for group attribute");
+    auto p = parser("group(nan)");
+    auto attr = p->attribute();
+    EXPECT_FALSE(attr.matched);
+    EXPECT_TRUE(attr.errored);
+    EXPECT_EQ(attr.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:7: expected signed integer literal for group attribute");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_variable_decl_test.cc b/src/tint/reader/wgsl/parser_impl_variable_decl_test.cc
index 1b1e810..70ec394 100644
--- a/src/tint/reader/wgsl/parser_impl_variable_decl_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_variable_decl_test.cc
@@ -17,93 +17,93 @@
 namespace tint::reader::wgsl {
 namespace {
 TEST_F(ParserImplTest, VariableDecl_Parses) {
-  auto p = parser("var my_var : f32");
-  auto v = p->variable_decl();
-  EXPECT_FALSE(p->has_error());
-  EXPECT_TRUE(v.matched);
-  EXPECT_FALSE(v.errored);
-  EXPECT_EQ(v->name, "my_var");
-  EXPECT_NE(v->type, nullptr);
-  EXPECT_TRUE(v->type->Is<ast::F32>());
+    auto p = parser("var my_var : f32");
+    auto v = p->variable_decl();
+    EXPECT_FALSE(p->has_error());
+    EXPECT_TRUE(v.matched);
+    EXPECT_FALSE(v.errored);
+    EXPECT_EQ(v->name, "my_var");
+    EXPECT_NE(v->type, nullptr);
+    EXPECT_TRUE(v->type->Is<ast::F32>());
 
-  EXPECT_EQ(v->source.range, (Source::Range{{1u, 5u}, {1u, 11u}}));
-  EXPECT_EQ(v->type->source.range, (Source::Range{{1u, 14u}, {1u, 17u}}));
+    EXPECT_EQ(v->source.range, (Source::Range{{1u, 5u}, {1u, 11u}}));
+    EXPECT_EQ(v->type->source.range, (Source::Range{{1u, 14u}, {1u, 17u}}));
 }
 
 TEST_F(ParserImplTest, VariableDecl_Unicode_Parses) {
-  const std::string ident =  // "𝖎𝖉𝖊𝖓𝖙𝖎𝖋𝖎𝖊𝖗123"
-      "\xf0\x9d\x96\x8e\xf0\x9d\x96\x89\xf0\x9d\x96\x8a\xf0\x9d\x96\x93"
-      "\xf0\x9d\x96\x99\xf0\x9d\x96\x8e\xf0\x9d\x96\x8b\xf0\x9d\x96\x8e"
-      "\xf0\x9d\x96\x8a\xf0\x9d\x96\x97\x31\x32\x33";
+    const std::string ident =  // "𝖎𝖉𝖊𝖓𝖙𝖎𝖋𝖎𝖊𝖗123"
+        "\xf0\x9d\x96\x8e\xf0\x9d\x96\x89\xf0\x9d\x96\x8a\xf0\x9d\x96\x93"
+        "\xf0\x9d\x96\x99\xf0\x9d\x96\x8e\xf0\x9d\x96\x8b\xf0\x9d\x96\x8e"
+        "\xf0\x9d\x96\x8a\xf0\x9d\x96\x97\x31\x32\x33";
 
-  auto p = parser("var " + ident + " : f32");
-  auto v = p->variable_decl();
-  EXPECT_FALSE(p->has_error());
-  EXPECT_TRUE(v.matched);
-  EXPECT_FALSE(v.errored);
-  EXPECT_EQ(v->name, ident);
-  EXPECT_NE(v->type, nullptr);
-  EXPECT_TRUE(v->type->Is<ast::F32>());
+    auto p = parser("var " + ident + " : f32");
+    auto v = p->variable_decl();
+    EXPECT_FALSE(p->has_error());
+    EXPECT_TRUE(v.matched);
+    EXPECT_FALSE(v.errored);
+    EXPECT_EQ(v->name, ident);
+    EXPECT_NE(v->type, nullptr);
+    EXPECT_TRUE(v->type->Is<ast::F32>());
 
-  EXPECT_EQ(v->source.range, (Source::Range{{1u, 5u}, {1u, 48u}}));
-  EXPECT_EQ(v->type->source.range, (Source::Range{{1u, 51u}, {1u, 54u}}));
+    EXPECT_EQ(v->source.range, (Source::Range{{1u, 5u}, {1u, 48u}}));
+    EXPECT_EQ(v->type->source.range, (Source::Range{{1u, 51u}, {1u, 54u}}));
 }
 
 TEST_F(ParserImplTest, VariableDecl_Inferred_Parses) {
-  auto p = parser("var my_var = 1.0");
-  auto v = p->variable_decl(/*allow_inferred = */ true);
-  EXPECT_FALSE(p->has_error());
-  EXPECT_TRUE(v.matched);
-  EXPECT_FALSE(v.errored);
-  EXPECT_EQ(v->name, "my_var");
-  EXPECT_EQ(v->type, nullptr);
+    auto p = parser("var my_var = 1.0");
+    auto v = p->variable_decl(/*allow_inferred = */ true);
+    EXPECT_FALSE(p->has_error());
+    EXPECT_TRUE(v.matched);
+    EXPECT_FALSE(v.errored);
+    EXPECT_EQ(v->name, "my_var");
+    EXPECT_EQ(v->type, nullptr);
 
-  EXPECT_EQ(v->source.range, (Source::Range{{1u, 5u}, {1u, 11u}}));
+    EXPECT_EQ(v->source.range, (Source::Range{{1u, 5u}, {1u, 11u}}));
 }
 
 TEST_F(ParserImplTest, VariableDecl_MissingVar) {
-  auto p = parser("my_var : f32");
-  auto v = p->variable_decl();
-  EXPECT_FALSE(v.matched);
-  EXPECT_FALSE(v.errored);
-  EXPECT_FALSE(p->has_error());
+    auto p = parser("my_var : f32");
+    auto v = p->variable_decl();
+    EXPECT_FALSE(v.matched);
+    EXPECT_FALSE(v.errored);
+    EXPECT_FALSE(p->has_error());
 
-  auto t = p->next();
-  ASSERT_TRUE(t.IsIdentifier());
+    auto t = p->next();
+    ASSERT_TRUE(t.IsIdentifier());
 }
 
 TEST_F(ParserImplTest, VariableDecl_InvalidIdentDecl) {
-  auto p = parser("var my_var f32");
-  auto v = p->variable_decl();
-  EXPECT_FALSE(v.matched);
-  EXPECT_TRUE(v.errored);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:12: expected ':' for variable declaration");
+    auto p = parser("var my_var f32");
+    auto v = p->variable_decl();
+    EXPECT_FALSE(v.matched);
+    EXPECT_TRUE(v.errored);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:12: expected ':' for variable declaration");
 }
 
 TEST_F(ParserImplTest, VariableDecl_WithStorageClass) {
-  auto p = parser("var<private> my_var : f32");
-  auto v = p->variable_decl();
-  EXPECT_TRUE(v.matched);
-  EXPECT_FALSE(v.errored);
-  EXPECT_FALSE(p->has_error());
-  EXPECT_EQ(v->name, "my_var");
-  EXPECT_TRUE(v->type->Is<ast::F32>());
-  EXPECT_EQ(v->storage_class, ast::StorageClass::kPrivate);
+    auto p = parser("var<private> my_var : f32");
+    auto v = p->variable_decl();
+    EXPECT_TRUE(v.matched);
+    EXPECT_FALSE(v.errored);
+    EXPECT_FALSE(p->has_error());
+    EXPECT_EQ(v->name, "my_var");
+    EXPECT_TRUE(v->type->Is<ast::F32>());
+    EXPECT_EQ(v->storage_class, ast::StorageClass::kPrivate);
 
-  EXPECT_EQ(v->source.range.begin.line, 1u);
-  EXPECT_EQ(v->source.range.begin.column, 14u);
-  EXPECT_EQ(v->source.range.end.line, 1u);
-  EXPECT_EQ(v->source.range.end.column, 20u);
+    EXPECT_EQ(v->source.range.begin.line, 1u);
+    EXPECT_EQ(v->source.range.begin.column, 14u);
+    EXPECT_EQ(v->source.range.end.line, 1u);
+    EXPECT_EQ(v->source.range.end.column, 20u);
 }
 
 TEST_F(ParserImplTest, VariableDecl_InvalidStorageClass) {
-  auto p = parser("var<unknown> my_var : f32");
-  auto v = p->variable_decl();
-  EXPECT_FALSE(v.matched);
-  EXPECT_TRUE(v.errored);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:5: invalid storage class for variable declaration");
+    auto p = parser("var<unknown> my_var : f32");
+    auto v = p->variable_decl();
+    EXPECT_FALSE(v.matched);
+    EXPECT_TRUE(v.errored);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:5: invalid storage class for variable declaration");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_variable_ident_decl_test.cc b/src/tint/reader/wgsl/parser_impl_variable_ident_decl_test.cc
index dfaa785..3ffb29e 100644
--- a/src/tint/reader/wgsl/parser_impl_variable_ident_decl_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_variable_ident_decl_test.cc
@@ -18,59 +18,59 @@
 namespace {
 
 TEST_F(ParserImplTest, VariableIdentDecl_Parses) {
-  auto p = parser("my_var : f32");
-  auto decl = p->expect_variable_ident_decl("test");
-  ASSERT_FALSE(p->has_error()) << p->error();
-  ASSERT_FALSE(decl.errored);
-  ASSERT_EQ(decl->name, "my_var");
-  ASSERT_NE(decl->type, nullptr);
-  ASSERT_TRUE(decl->type->Is<ast::F32>());
+    auto p = parser("my_var : f32");
+    auto decl = p->expect_variable_ident_decl("test");
+    ASSERT_FALSE(p->has_error()) << p->error();
+    ASSERT_FALSE(decl.errored);
+    ASSERT_EQ(decl->name, "my_var");
+    ASSERT_NE(decl->type, nullptr);
+    ASSERT_TRUE(decl->type->Is<ast::F32>());
 
-  EXPECT_EQ(decl->source.range, (Source::Range{{1u, 1u}, {1u, 7u}}));
-  EXPECT_EQ(decl->type->source.range, (Source::Range{{1u, 10u}, {1u, 13u}}));
+    EXPECT_EQ(decl->source.range, (Source::Range{{1u, 1u}, {1u, 7u}}));
+    EXPECT_EQ(decl->type->source.range, (Source::Range{{1u, 10u}, {1u, 13u}}));
 }
 
 TEST_F(ParserImplTest, VariableIdentDecl_Inferred_Parses) {
-  auto p = parser("my_var = 1.0");
-  auto decl = p->expect_variable_ident_decl("test", /*allow_inferred = */ true);
-  ASSERT_FALSE(p->has_error()) << p->error();
-  ASSERT_FALSE(decl.errored);
-  ASSERT_EQ(decl->name, "my_var");
-  ASSERT_EQ(decl->type, nullptr);
+    auto p = parser("my_var = 1.0");
+    auto decl = p->expect_variable_ident_decl("test", /*allow_inferred = */ true);
+    ASSERT_FALSE(p->has_error()) << p->error();
+    ASSERT_FALSE(decl.errored);
+    ASSERT_EQ(decl->name, "my_var");
+    ASSERT_EQ(decl->type, nullptr);
 
-  EXPECT_EQ(decl->source.range, (Source::Range{{1u, 1u}, {1u, 7u}}));
+    EXPECT_EQ(decl->source.range, (Source::Range{{1u, 1u}, {1u, 7u}}));
 }
 
 TEST_F(ParserImplTest, VariableIdentDecl_MissingIdent) {
-  auto p = parser(": f32");
-  auto decl = p->expect_variable_ident_decl("test");
-  ASSERT_TRUE(p->has_error());
-  ASSERT_TRUE(decl.errored);
-  ASSERT_EQ(p->error(), "1:1: expected identifier for test");
+    auto p = parser(": f32");
+    auto decl = p->expect_variable_ident_decl("test");
+    ASSERT_TRUE(p->has_error());
+    ASSERT_TRUE(decl.errored);
+    ASSERT_EQ(p->error(), "1:1: expected identifier for test");
 }
 
 TEST_F(ParserImplTest, VariableIdentDecl_MissingColon) {
-  auto p = parser("my_var f32");
-  auto decl = p->expect_variable_ident_decl("test");
-  ASSERT_TRUE(p->has_error());
-  ASSERT_TRUE(decl.errored);
-  ASSERT_EQ(p->error(), "1:8: expected ':' for test");
+    auto p = parser("my_var f32");
+    auto decl = p->expect_variable_ident_decl("test");
+    ASSERT_TRUE(p->has_error());
+    ASSERT_TRUE(decl.errored);
+    ASSERT_EQ(p->error(), "1:8: expected ':' for test");
 }
 
 TEST_F(ParserImplTest, VariableIdentDecl_MissingType) {
-  auto p = parser("my_var :");
-  auto decl = p->expect_variable_ident_decl("test");
-  ASSERT_TRUE(p->has_error());
-  ASSERT_TRUE(decl.errored);
-  ASSERT_EQ(p->error(), "1:9: invalid type for test");
+    auto p = parser("my_var :");
+    auto decl = p->expect_variable_ident_decl("test");
+    ASSERT_TRUE(p->has_error());
+    ASSERT_TRUE(decl.errored);
+    ASSERT_EQ(p->error(), "1:9: invalid type for test");
 }
 
 TEST_F(ParserImplTest, VariableIdentDecl_InvalidIdent) {
-  auto p = parser("123 : f32");
-  auto decl = p->expect_variable_ident_decl("test");
-  ASSERT_TRUE(p->has_error());
-  ASSERT_TRUE(decl.errored);
-  ASSERT_EQ(p->error(), "1:1: expected identifier for test");
+    auto p = parser("123 : f32");
+    auto decl = p->expect_variable_ident_decl("test");
+    ASSERT_TRUE(p->has_error());
+    ASSERT_TRUE(decl.errored);
+    ASSERT_EQ(p->error(), "1:1: expected identifier for test");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_variable_qualifier_test.cc b/src/tint/reader/wgsl/parser_impl_variable_qualifier_test.cc
index 6fa909f..de63f92 100644
--- a/src/tint/reader/wgsl/parser_impl_variable_qualifier_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_variable_qualifier_test.cc
@@ -18,102 +18,93 @@
 namespace {
 
 struct VariableStorageData {
-  const char* input;
-  ast::StorageClass storage_class;
-  ast::Access access;
+    const char* input;
+    ast::StorageClass storage_class;
+    ast::Access access;
 };
 inline std::ostream& operator<<(std::ostream& out, VariableStorageData data) {
-  out << std::string(data.input);
-  return out;
+    out << std::string(data.input);
+    return out;
 }
 
-class VariableQualifierTest
-    : public ParserImplTestWithParam<VariableStorageData> {};
+class VariableQualifierTest : public ParserImplTestWithParam<VariableStorageData> {};
 
 TEST_P(VariableQualifierTest, ParsesStorageClass) {
-  auto params = GetParam();
-  auto p = parser(std::string("<") + params.input + ">");
+    auto params = GetParam();
+    auto p = parser(std::string("<") + params.input + ">");
 
-  auto sc = p->variable_qualifier();
-  EXPECT_FALSE(p->has_error());
-  EXPECT_FALSE(sc.errored);
-  EXPECT_TRUE(sc.matched);
-  EXPECT_EQ(sc->storage_class, params.storage_class);
-  EXPECT_EQ(sc->access, params.access);
+    auto sc = p->variable_qualifier();
+    EXPECT_FALSE(p->has_error());
+    EXPECT_FALSE(sc.errored);
+    EXPECT_TRUE(sc.matched);
+    EXPECT_EQ(sc->storage_class, params.storage_class);
+    EXPECT_EQ(sc->access, params.access);
 
-  auto t = p->next();
-  EXPECT_TRUE(t.IsEof());
+    auto t = p->next();
+    EXPECT_TRUE(t.IsEof());
 }
 INSTANTIATE_TEST_SUITE_P(
     ParserImplTest,
     VariableQualifierTest,
     testing::Values(
-        VariableStorageData{"uniform", ast::StorageClass::kUniform,
-                            ast::Access::kUndefined},
-        VariableStorageData{"workgroup", ast::StorageClass::kWorkgroup,
-                            ast::Access::kUndefined},
-        VariableStorageData{"storage", ast::StorageClass::kStorage,
-                            ast::Access::kUndefined},
-        VariableStorageData{"storage_buffer", ast::StorageClass::kStorage,
-                            ast::Access::kUndefined},
-        VariableStorageData{"private", ast::StorageClass::kPrivate,
-                            ast::Access::kUndefined},
-        VariableStorageData{"function", ast::StorageClass::kFunction,
-                            ast::Access::kUndefined},
-        VariableStorageData{"storage, read", ast::StorageClass::kStorage,
-                            ast::Access::kRead},
-        VariableStorageData{"storage, write", ast::StorageClass::kStorage,
-                            ast::Access::kWrite},
+        VariableStorageData{"uniform", ast::StorageClass::kUniform, ast::Access::kUndefined},
+        VariableStorageData{"workgroup", ast::StorageClass::kWorkgroup, ast::Access::kUndefined},
+        VariableStorageData{"storage", ast::StorageClass::kStorage, ast::Access::kUndefined},
+        VariableStorageData{"storage_buffer", ast::StorageClass::kStorage, ast::Access::kUndefined},
+        VariableStorageData{"private", ast::StorageClass::kPrivate, ast::Access::kUndefined},
+        VariableStorageData{"function", ast::StorageClass::kFunction, ast::Access::kUndefined},
+        VariableStorageData{"storage, read", ast::StorageClass::kStorage, ast::Access::kRead},
+        VariableStorageData{"storage, write", ast::StorageClass::kStorage, ast::Access::kWrite},
         VariableStorageData{"storage, read_write", ast::StorageClass::kStorage,
                             ast::Access::kReadWrite}));
 
 TEST_F(ParserImplTest, VariableQualifier_NoMatch) {
-  auto p = parser("<not-a-storage-class>");
-  auto sc = p->variable_qualifier();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(sc.errored);
-  EXPECT_FALSE(sc.matched);
-  EXPECT_EQ(p->error(), "1:2: invalid storage class for variable declaration");
+    auto p = parser("<not-a-storage-class>");
+    auto sc = p->variable_qualifier();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(sc.errored);
+    EXPECT_FALSE(sc.matched);
+    EXPECT_EQ(p->error(), "1:2: invalid storage class for variable declaration");
 }
 
 TEST_F(ParserImplTest, VariableQualifier_Empty) {
-  auto p = parser("<>");
-  auto sc = p->variable_qualifier();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(sc.errored);
-  EXPECT_FALSE(sc.matched);
-  EXPECT_EQ(p->error(), "1:2: invalid storage class for variable declaration");
+    auto p = parser("<>");
+    auto sc = p->variable_qualifier();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(sc.errored);
+    EXPECT_FALSE(sc.matched);
+    EXPECT_EQ(p->error(), "1:2: invalid storage class for variable declaration");
 }
 
 TEST_F(ParserImplTest, VariableQualifier_MissingLessThan) {
-  auto p = parser("private>");
-  auto sc = p->variable_qualifier();
-  EXPECT_FALSE(p->has_error());
-  EXPECT_FALSE(sc.errored);
-  EXPECT_FALSE(sc.matched);
+    auto p = parser("private>");
+    auto sc = p->variable_qualifier();
+    EXPECT_FALSE(p->has_error());
+    EXPECT_FALSE(sc.errored);
+    EXPECT_FALSE(sc.matched);
 
-  auto t = p->next();
-  ASSERT_TRUE(t.Is(Token::Type::kPrivate));
+    auto t = p->next();
+    ASSERT_TRUE(t.Is(Token::Type::kPrivate));
 }
 
 TEST_F(ParserImplTest, VariableQualifier_MissingLessThan_AfterSC) {
-  auto p = parser("private, >");
-  auto sc = p->variable_qualifier();
-  EXPECT_FALSE(p->has_error());
-  EXPECT_FALSE(sc.errored);
-  EXPECT_FALSE(sc.matched);
+    auto p = parser("private, >");
+    auto sc = p->variable_qualifier();
+    EXPECT_FALSE(p->has_error());
+    EXPECT_FALSE(sc.errored);
+    EXPECT_FALSE(sc.matched);
 
-  auto t = p->next();
-  ASSERT_TRUE(t.Is(Token::Type::kPrivate));
+    auto t = p->next();
+    ASSERT_TRUE(t.Is(Token::Type::kPrivate));
 }
 
 TEST_F(ParserImplTest, VariableQualifier_MissingGreaterThan) {
-  auto p = parser("<private");
-  auto sc = p->variable_qualifier();
-  EXPECT_TRUE(p->has_error());
-  EXPECT_TRUE(sc.errored);
-  EXPECT_FALSE(sc.matched);
-  EXPECT_EQ(p->error(), "1:9: expected '>' for variable declaration");
+    auto p = parser("<private");
+    auto sc = p->variable_qualifier();
+    EXPECT_TRUE(p->has_error());
+    EXPECT_TRUE(sc.errored);
+    EXPECT_FALSE(sc.matched);
+    EXPECT_EQ(p->error(), "1:9: expected '>' for variable declaration");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_impl_variable_stmt_test.cc b/src/tint/reader/wgsl/parser_impl_variable_stmt_test.cc
index 8a8d7df..ee89947 100644
--- a/src/tint/reader/wgsl/parser_impl_variable_stmt_test.cc
+++ b/src/tint/reader/wgsl/parser_impl_variable_stmt_test.cc
@@ -18,169 +18,169 @@
 namespace {
 
 TEST_F(ParserImplTest, VariableStmt_VariableDecl) {
-  auto p = parser("var a : i32;");
-  auto e = p->variable_stmt();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::VariableDeclStatement>());
-  ASSERT_NE(e->variable, nullptr);
-  EXPECT_EQ(e->variable->symbol, p->builder().Symbols().Get("a"));
+    auto p = parser("var a : i32;");
+    auto e = p->variable_stmt();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::VariableDeclStatement>());
+    ASSERT_NE(e->variable, nullptr);
+    EXPECT_EQ(e->variable->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_EQ(e->source.range.begin.line, 1u);
-  ASSERT_EQ(e->source.range.begin.column, 5u);
-  ASSERT_EQ(e->source.range.end.line, 1u);
-  ASSERT_EQ(e->source.range.end.column, 6u);
+    ASSERT_EQ(e->source.range.begin.line, 1u);
+    ASSERT_EQ(e->source.range.begin.column, 5u);
+    ASSERT_EQ(e->source.range.end.line, 1u);
+    ASSERT_EQ(e->source.range.end.column, 6u);
 
-  EXPECT_EQ(e->variable->constructor, nullptr);
+    EXPECT_EQ(e->variable->constructor, nullptr);
 }
 
 TEST_F(ParserImplTest, VariableStmt_VariableDecl_WithInit) {
-  auto p = parser("var a : i32 = 1;");
-  auto e = p->variable_stmt();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::VariableDeclStatement>());
-  ASSERT_NE(e->variable, nullptr);
-  EXPECT_EQ(e->variable->symbol, p->builder().Symbols().Get("a"));
+    auto p = parser("var a : i32 = 1;");
+    auto e = p->variable_stmt();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::VariableDeclStatement>());
+    ASSERT_NE(e->variable, nullptr);
+    EXPECT_EQ(e->variable->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_EQ(e->source.range.begin.line, 1u);
-  ASSERT_EQ(e->source.range.begin.column, 5u);
-  ASSERT_EQ(e->source.range.end.line, 1u);
-  ASSERT_EQ(e->source.range.end.column, 6u);
+    ASSERT_EQ(e->source.range.begin.line, 1u);
+    ASSERT_EQ(e->source.range.begin.column, 5u);
+    ASSERT_EQ(e->source.range.end.line, 1u);
+    ASSERT_EQ(e->source.range.end.column, 6u);
 
-  ASSERT_NE(e->variable->constructor, nullptr);
-  EXPECT_TRUE(e->variable->constructor->Is<ast::LiteralExpression>());
+    ASSERT_NE(e->variable->constructor, nullptr);
+    EXPECT_TRUE(e->variable->constructor->Is<ast::LiteralExpression>());
 }
 
 TEST_F(ParserImplTest, VariableStmt_VariableDecl_ConstructorInvalid) {
-  auto p = parser("var a : i32 = if(a) {}");
-  auto e = p->variable_stmt();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:15: missing constructor for variable declaration");
+    auto p = parser("var a : i32 = if(a) {}");
+    auto e = p->variable_stmt();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:15: missing constructor for variable declaration");
 }
 
 TEST_F(ParserImplTest, VariableStmt_VariableDecl_ArrayInit) {
-  auto p = parser("var a : array<i32> = array<i32>();");
-  auto e = p->variable_stmt();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::VariableDeclStatement>());
-  ASSERT_NE(e->variable, nullptr);
-  EXPECT_EQ(e->variable->symbol, p->builder().Symbols().Get("a"));
+    auto p = parser("var a : array<i32> = array<i32>();");
+    auto e = p->variable_stmt();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::VariableDeclStatement>());
+    ASSERT_NE(e->variable, nullptr);
+    EXPECT_EQ(e->variable->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_NE(e->variable->constructor, nullptr);
-  auto* call = e->variable->constructor->As<ast::CallExpression>();
-  ASSERT_NE(call, nullptr);
-  EXPECT_EQ(call->target.name, nullptr);
-  EXPECT_NE(call->target.type, nullptr);
+    ASSERT_NE(e->variable->constructor, nullptr);
+    auto* call = e->variable->constructor->As<ast::CallExpression>();
+    ASSERT_NE(call, nullptr);
+    EXPECT_EQ(call->target.name, nullptr);
+    EXPECT_NE(call->target.type, nullptr);
 }
 
 TEST_F(ParserImplTest, VariableStmt_VariableDecl_ArrayInit_NoSpace) {
-  auto p = parser("var a : array<i32>=array<i32>();");
-  auto e = p->variable_stmt();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::VariableDeclStatement>());
-  ASSERT_NE(e->variable, nullptr);
-  EXPECT_EQ(e->variable->symbol, p->builder().Symbols().Get("a"));
+    auto p = parser("var a : array<i32>=array<i32>();");
+    auto e = p->variable_stmt();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::VariableDeclStatement>());
+    ASSERT_NE(e->variable, nullptr);
+    EXPECT_EQ(e->variable->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_NE(e->variable->constructor, nullptr);
-  auto* call = e->variable->constructor->As<ast::CallExpression>();
-  ASSERT_NE(call, nullptr);
-  EXPECT_EQ(call->target.name, nullptr);
-  EXPECT_NE(call->target.type, nullptr);
+    ASSERT_NE(e->variable->constructor, nullptr);
+    auto* call = e->variable->constructor->As<ast::CallExpression>();
+    ASSERT_NE(call, nullptr);
+    EXPECT_EQ(call->target.name, nullptr);
+    EXPECT_NE(call->target.type, nullptr);
 }
 
 TEST_F(ParserImplTest, VariableStmt_VariableDecl_VecInit) {
-  auto p = parser("var a : vec2<i32> = vec2<i32>();");
-  auto e = p->variable_stmt();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::VariableDeclStatement>());
-  ASSERT_NE(e->variable, nullptr);
-  EXPECT_EQ(e->variable->symbol, p->builder().Symbols().Get("a"));
+    auto p = parser("var a : vec2<i32> = vec2<i32>();");
+    auto e = p->variable_stmt();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::VariableDeclStatement>());
+    ASSERT_NE(e->variable, nullptr);
+    EXPECT_EQ(e->variable->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_NE(e->variable->constructor, nullptr);
-  auto* call = e->variable->constructor->As<ast::CallExpression>();
-  ASSERT_NE(call, nullptr);
-  EXPECT_EQ(call->target.name, nullptr);
-  EXPECT_NE(call->target.type, nullptr);
+    ASSERT_NE(e->variable->constructor, nullptr);
+    auto* call = e->variable->constructor->As<ast::CallExpression>();
+    ASSERT_NE(call, nullptr);
+    EXPECT_EQ(call->target.name, nullptr);
+    EXPECT_NE(call->target.type, nullptr);
 }
 
 TEST_F(ParserImplTest, VariableStmt_VariableDecl_VecInit_NoSpace) {
-  auto p = parser("var a : vec2<i32>=vec2<i32>();");
-  auto e = p->variable_stmt();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::VariableDeclStatement>());
-  ASSERT_NE(e->variable, nullptr);
-  EXPECT_EQ(e->variable->symbol, p->builder().Symbols().Get("a"));
+    auto p = parser("var a : vec2<i32>=vec2<i32>();");
+    auto e = p->variable_stmt();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::VariableDeclStatement>());
+    ASSERT_NE(e->variable, nullptr);
+    EXPECT_EQ(e->variable->symbol, p->builder().Symbols().Get("a"));
 
-  ASSERT_NE(e->variable->constructor, nullptr);
-  auto* call = e->variable->constructor->As<ast::CallExpression>();
-  ASSERT_NE(call, nullptr);
-  EXPECT_EQ(call->target.name, nullptr);
-  EXPECT_NE(call->target.type, nullptr);
+    ASSERT_NE(e->variable->constructor, nullptr);
+    auto* call = e->variable->constructor->As<ast::CallExpression>();
+    ASSERT_NE(call, nullptr);
+    EXPECT_EQ(call->target.name, nullptr);
+    EXPECT_NE(call->target.type, nullptr);
 }
 
 TEST_F(ParserImplTest, VariableStmt_Let) {
-  auto p = parser("let a : i32 = 1");
-  auto e = p->variable_stmt();
-  EXPECT_TRUE(e.matched);
-  EXPECT_FALSE(e.errored);
-  EXPECT_FALSE(p->has_error()) << p->error();
-  ASSERT_NE(e.value, nullptr);
-  ASSERT_TRUE(e->Is<ast::VariableDeclStatement>());
+    auto p = parser("let a : i32 = 1");
+    auto e = p->variable_stmt();
+    EXPECT_TRUE(e.matched);
+    EXPECT_FALSE(e.errored);
+    EXPECT_FALSE(p->has_error()) << p->error();
+    ASSERT_NE(e.value, nullptr);
+    ASSERT_TRUE(e->Is<ast::VariableDeclStatement>());
 
-  ASSERT_EQ(e->source.range.begin.line, 1u);
-  ASSERT_EQ(e->source.range.begin.column, 5u);
-  ASSERT_EQ(e->source.range.end.line, 1u);
-  ASSERT_EQ(e->source.range.end.column, 6u);
+    ASSERT_EQ(e->source.range.begin.line, 1u);
+    ASSERT_EQ(e->source.range.begin.column, 5u);
+    ASSERT_EQ(e->source.range.end.line, 1u);
+    ASSERT_EQ(e->source.range.end.column, 6u);
 }
 
 TEST_F(ParserImplTest, VariableStmt_Let_MissingEqual) {
-  auto p = parser("let a : i32 1");
-  auto e = p->variable_stmt();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:13: expected '=' for let declaration");
+    auto p = parser("let a : i32 1");
+    auto e = p->variable_stmt();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:13: expected '=' for let declaration");
 }
 
 TEST_F(ParserImplTest, VariableStmt_Let_MissingConstructor) {
-  auto p = parser("let a : i32 =");
-  auto e = p->variable_stmt();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:14: missing constructor for let declaration");
+    auto p = parser("let a : i32 =");
+    auto e = p->variable_stmt();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:14: missing constructor for let declaration");
 }
 
 TEST_F(ParserImplTest, VariableStmt_Let_InvalidConstructor) {
-  auto p = parser("let a : i32 = if (a) {}");
-  auto e = p->variable_stmt();
-  EXPECT_FALSE(e.matched);
-  EXPECT_TRUE(e.errored);
-  EXPECT_EQ(e.value, nullptr);
-  EXPECT_TRUE(p->has_error());
-  EXPECT_EQ(p->error(), "1:15: missing constructor for let declaration");
+    auto p = parser("let a : i32 = if (a) {}");
+    auto e = p->variable_stmt();
+    EXPECT_FALSE(e.matched);
+    EXPECT_TRUE(e.errored);
+    EXPECT_EQ(e.value, nullptr);
+    EXPECT_TRUE(p->has_error());
+    EXPECT_EQ(p->error(), "1:15: missing constructor for let declaration");
 }
 
 }  // namespace
diff --git a/src/tint/reader/wgsl/parser_test.cc b/src/tint/reader/wgsl/parser_test.cc
index 55a6287..d343c7c 100644
--- a/src/tint/reader/wgsl/parser_test.cc
+++ b/src/tint/reader/wgsl/parser_test.cc
@@ -24,37 +24,37 @@
 using ParserTest = testing::Test;
 
 TEST_F(ParserTest, Empty) {
-  Source::File file("test.wgsl", "");
-  auto program = Parse(&file);
-  auto errs = diag::Formatter().format(program.Diagnostics());
-  ASSERT_TRUE(program.IsValid()) << errs;
+    Source::File file("test.wgsl", "");
+    auto program = Parse(&file);
+    auto errs = diag::Formatter().format(program.Diagnostics());
+    ASSERT_TRUE(program.IsValid()) << errs;
 }
 
 TEST_F(ParserTest, Parses) {
-  Source::File file("test.wgsl", R"(
+    Source::File file("test.wgsl", R"(
 @stage(fragment)
 fn main() -> @location(0) vec4<f32> {
   return vec4<f32>(.4, .2, .3, 1.);
 }
 )");
-  auto program = Parse(&file);
-  auto errs = diag::Formatter().format(program.Diagnostics());
-  ASSERT_TRUE(program.IsValid()) << errs;
+    auto program = Parse(&file);
+    auto errs = diag::Formatter().format(program.Diagnostics());
+    ASSERT_TRUE(program.IsValid()) << errs;
 
-  ASSERT_EQ(1u, program.AST().Functions().size());
+    ASSERT_EQ(1u, program.AST().Functions().size());
 }
 
 TEST_F(ParserTest, HandlesError) {
-  Source::File file("test.wgsl", R"(
+    Source::File file("test.wgsl", R"(
 fn main() ->  {  // missing return type
   return;
 })");
 
-  auto program = Parse(&file);
-  auto errs = diag::Formatter().format(program.Diagnostics());
-  ASSERT_FALSE(program.IsValid()) << errs;
-  EXPECT_EQ(errs,
-            R"(test.wgsl:2:15 error: unable to determine function return type
+    auto program = Parse(&file);
+    auto errs = diag::Formatter().format(program.Diagnostics());
+    ASSERT_FALSE(program.IsValid()) << errs;
+    EXPECT_EQ(errs,
+              R"(test.wgsl:2:15 error: unable to determine function return type
 fn main() ->  {  // missing return type
               ^
 
diff --git a/src/tint/reader/wgsl/token.cc b/src/tint/reader/wgsl/token.cc
index ef7abc4..2f51a85 100644
--- a/src/tint/reader/wgsl/token.cc
+++ b/src/tint/reader/wgsl/token.cc
@@ -18,246 +18,250 @@
 
 // static
 std::string_view Token::TypeToName(Type type) {
-  switch (type) {
-    case Token::Type::kError:
-      return "kError";
-    case Token::Type::kEOF:
-      return "kEOF";
-    case Token::Type::kIdentifier:
-      return "kIdentifier";
-    case Token::Type::kFloatLiteral:
-      return "kFloatLiteral";
-    case Token::Type::kSintLiteral:
-      return "kSintLiteral";
-    case Token::Type::kUintLiteral:
-      return "kUintLiteral";
-    case Token::Type::kUninitialized:
-      return "kUninitialized";
+    switch (type) {
+        case Token::Type::kError:
+            return "error";
+        case Token::Type::kEOF:
+            return "end of file";
+        case Token::Type::kIdentifier:
+            return "identifier";
+        case Token::Type::kFloatLiteral:
+            return "float literal";
+        case Token::Type::kIntLiteral:
+            return "abstract integer literal";
+        case Token::Type::kIntILiteral:
+            return "'i'-suffixed integer literal";
+        case Token::Type::kIntULiteral:
+            return "'u'-suffixed integer literal";
+        case Token::Type::kUninitialized:
+            return "uninitialized";
 
-    case Token::Type::kAnd:
-      return "&";
-    case Token::Type::kAndAnd:
-      return "&&";
-    case Token::Type::kArrow:
-      return "->";
-    case Token::Type::kAttr:
-      return "@";
-    case Token::Type::kForwardSlash:
-      return "/";
-    case Token::Type::kBang:
-      return "!";
-    case Token::Type::kBracketLeft:
-      return "[";
-    case Token::Type::kBracketRight:
-      return "]";
-    case Token::Type::kBraceLeft:
-      return "{";
-    case Token::Type::kBraceRight:
-      return "}";
-    case Token::Type::kColon:
-      return ":";
-    case Token::Type::kComma:
-      return ",";
-    case Token::Type::kEqual:
-      return "=";
-    case Token::Type::kEqualEqual:
-      return "==";
-    case Token::Type::kGreaterThan:
-      return ">";
-    case Token::Type::kGreaterThanEqual:
-      return ">=";
-    case Token::Type::kShiftRight:
-      return ">>";
-    case Token::Type::kLessThan:
-      return "<";
-    case Token::Type::kLessThanEqual:
-      return "<=";
-    case Token::Type::kShiftLeft:
-      return "<<";
-    case Token::Type::kMod:
-      return "%";
-    case Token::Type::kNotEqual:
-      return "!=";
-    case Token::Type::kMinus:
-      return "-";
-    case Token::Type::kMinusMinus:
-      return "--";
-    case Token::Type::kPeriod:
-      return ".";
-    case Token::Type::kPlus:
-      return "+";
-    case Token::Type::kPlusPlus:
-      return "++";
-    case Token::Type::kOr:
-      return "|";
-    case Token::Type::kOrOr:
-      return "||";
-    case Token::Type::kParenLeft:
-      return "(";
-    case Token::Type::kParenRight:
-      return ")";
-    case Token::Type::kSemicolon:
-      return ";";
-    case Token::Type::kStar:
-      return "*";
-    case Token::Type::kTilde:
-      return "~";
-    case Token::Type::kUnderscore:
-      return "_";
-    case Token::Type::kXor:
-      return "^";
-    case Token::Type::kPlusEqual:
-      return "+=";
-    case Token::Type::kMinusEqual:
-      return "-=";
-    case Token::Type::kTimesEqual:
-      return "*=";
-    case Token::Type::kDivisionEqual:
-      return "/=";
-    case Token::Type::kModuloEqual:
-      return "%=";
-    case Token::Type::kAndEqual:
-      return "&=";
-    case Token::Type::kOrEqual:
-      return "|=";
-    case Token::Type::kXorEqual:
-      return "^=";
+        case Token::Type::kAnd:
+            return "&";
+        case Token::Type::kAndAnd:
+            return "&&";
+        case Token::Type::kArrow:
+            return "->";
+        case Token::Type::kAttr:
+            return "@";
+        case Token::Type::kForwardSlash:
+            return "/";
+        case Token::Type::kBang:
+            return "!";
+        case Token::Type::kBracketLeft:
+            return "[";
+        case Token::Type::kBracketRight:
+            return "]";
+        case Token::Type::kBraceLeft:
+            return "{";
+        case Token::Type::kBraceRight:
+            return "}";
+        case Token::Type::kColon:
+            return ":";
+        case Token::Type::kComma:
+            return ",";
+        case Token::Type::kEqual:
+            return "=";
+        case Token::Type::kEqualEqual:
+            return "==";
+        case Token::Type::kGreaterThan:
+            return ">";
+        case Token::Type::kGreaterThanEqual:
+            return ">=";
+        case Token::Type::kShiftRight:
+            return ">>";
+        case Token::Type::kLessThan:
+            return "<";
+        case Token::Type::kLessThanEqual:
+            return "<=";
+        case Token::Type::kShiftLeft:
+            return "<<";
+        case Token::Type::kMod:
+            return "%";
+        case Token::Type::kNotEqual:
+            return "!=";
+        case Token::Type::kMinus:
+            return "-";
+        case Token::Type::kMinusMinus:
+            return "--";
+        case Token::Type::kPeriod:
+            return ".";
+        case Token::Type::kPlus:
+            return "+";
+        case Token::Type::kPlusPlus:
+            return "++";
+        case Token::Type::kOr:
+            return "|";
+        case Token::Type::kOrOr:
+            return "||";
+        case Token::Type::kParenLeft:
+            return "(";
+        case Token::Type::kParenRight:
+            return ")";
+        case Token::Type::kSemicolon:
+            return ";";
+        case Token::Type::kStar:
+            return "*";
+        case Token::Type::kTilde:
+            return "~";
+        case Token::Type::kUnderscore:
+            return "_";
+        case Token::Type::kXor:
+            return "^";
+        case Token::Type::kPlusEqual:
+            return "+=";
+        case Token::Type::kMinusEqual:
+            return "-=";
+        case Token::Type::kTimesEqual:
+            return "*=";
+        case Token::Type::kDivisionEqual:
+            return "/=";
+        case Token::Type::kModuloEqual:
+            return "%=";
+        case Token::Type::kAndEqual:
+            return "&=";
+        case Token::Type::kOrEqual:
+            return "|=";
+        case Token::Type::kXorEqual:
+            return "^=";
 
-    case Token::Type::kArray:
-      return "array";
-    case Token::Type::kAtomic:
-      return "atomic";
-    case Token::Type::kBitcast:
-      return "bitcast";
-    case Token::Type::kBool:
-      return "bool";
-    case Token::Type::kBreak:
-      return "break";
-    case Token::Type::kCase:
-      return "case";
-    case Token::Type::kContinue:
-      return "continue";
-    case Token::Type::kContinuing:
-      return "continuing";
-    case Token::Type::kDiscard:
-      return "discard";
-    case Token::Type::kDefault:
-      return "default";
-    case Token::Type::kElse:
-      return "else";
-    case Token::Type::kF32:
-      return "f32";
-    case Token::Type::kFallthrough:
-      return "fallthrough";
-    case Token::Type::kFalse:
-      return "false";
-    case Token::Type::kFn:
-      return "fn";
-    case Token::Type::kFor:
-      return "for";
-    case Token::Type::kFunction:
-      return "function";
-    case Token::Type::kI32:
-      return "i32";
-    case Token::Type::kIf:
-      return "if";
-    case Token::Type::kImport:
-      return "import";
-    case Token::Type::kLet:
-      return "let";
-    case Token::Type::kLoop:
-      return "loop";
-    case Token::Type::kMat2x2:
-      return "mat2x2";
-    case Token::Type::kMat2x3:
-      return "mat2x3";
-    case Token::Type::kMat2x4:
-      return "mat2x4";
-    case Token::Type::kMat3x2:
-      return "mat3x2";
-    case Token::Type::kMat3x3:
-      return "mat3x3";
-    case Token::Type::kMat3x4:
-      return "mat3x4";
-    case Token::Type::kMat4x2:
-      return "mat4x2";
-    case Token::Type::kMat4x3:
-      return "mat4x3";
-    case Token::Type::kMat4x4:
-      return "mat4x4";
-    case Token::Type::kOverride:
-      return "override";
-    case Token::Type::kPrivate:
-      return "private";
-    case Token::Type::kPtr:
-      return "ptr";
-    case Token::Type::kReturn:
-      return "return";
-    case Token::Type::kSampler:
-      return "sampler";
-    case Token::Type::kComparisonSampler:
-      return "sampler_comparison";
-    case Token::Type::kStorage:
-      return "storage";
-    case Token::Type::kStruct:
-      return "struct";
-    case Token::Type::kSwitch:
-      return "switch";
-    case Token::Type::kTextureDepth2d:
-      return "texture_depth_2d";
-    case Token::Type::kTextureDepth2dArray:
-      return "texture_depth_2d_array";
-    case Token::Type::kTextureDepthCube:
-      return "texture_depth_cube";
-    case Token::Type::kTextureDepthCubeArray:
-      return "texture_depth_cube_array";
-    case Token::Type::kTextureDepthMultisampled2d:
-      return "texture_depth_multisampled_2d";
-    case Token::Type::kTextureExternal:
-      return "texture_external";
-    case Token::Type::kTextureMultisampled2d:
-      return "texture_multisampled_2d";
-    case Token::Type::kTextureSampled1d:
-      return "texture_1d";
-    case Token::Type::kTextureSampled2d:
-      return "texture_2d";
-    case Token::Type::kTextureSampled2dArray:
-      return "texture_2d_array";
-    case Token::Type::kTextureSampled3d:
-      return "texture_3d";
-    case Token::Type::kTextureSampledCube:
-      return "texture_cube";
-    case Token::Type::kTextureSampledCubeArray:
-      return "texture_cube_array";
-    case Token::Type::kTextureStorage1d:
-      return "texture_storage_1d";
-    case Token::Type::kTextureStorage2d:
-      return "texture_storage_2d";
-    case Token::Type::kTextureStorage2dArray:
-      return "texture_storage_2d_array";
-    case Token::Type::kTextureStorage3d:
-      return "texture_storage_3d";
-    case Token::Type::kTrue:
-      return "true";
-    case Token::Type::kType:
-      return "type";
-    case Token::Type::kU32:
-      return "u32";
-    case Token::Type::kUniform:
-      return "uniform";
-    case Token::Type::kVar:
-      return "var";
-    case Token::Type::kVec2:
-      return "vec2";
-    case Token::Type::kVec3:
-      return "vec3";
-    case Token::Type::kVec4:
-      return "vec4";
-    case Token::Type::kWorkgroup:
-      return "workgroup";
-  }
+        case Token::Type::kArray:
+            return "array";
+        case Token::Type::kAtomic:
+            return "atomic";
+        case Token::Type::kBitcast:
+            return "bitcast";
+        case Token::Type::kBool:
+            return "bool";
+        case Token::Type::kBreak:
+            return "break";
+        case Token::Type::kCase:
+            return "case";
+        case Token::Type::kContinue:
+            return "continue";
+        case Token::Type::kContinuing:
+            return "continuing";
+        case Token::Type::kDiscard:
+            return "discard";
+        case Token::Type::kDefault:
+            return "default";
+        case Token::Type::kElse:
+            return "else";
+        case Token::Type::kEnable:
+            return "enable";
+        case Token::Type::kF32:
+            return "f32";
+        case Token::Type::kFallthrough:
+            return "fallthrough";
+        case Token::Type::kFalse:
+            return "false";
+        case Token::Type::kFn:
+            return "fn";
+        case Token::Type::kFor:
+            return "for";
+        case Token::Type::kFunction:
+            return "function";
+        case Token::Type::kI32:
+            return "i32";
+        case Token::Type::kIf:
+            return "if";
+        case Token::Type::kImport:
+            return "import";
+        case Token::Type::kLet:
+            return "let";
+        case Token::Type::kLoop:
+            return "loop";
+        case Token::Type::kMat2x2:
+            return "mat2x2";
+        case Token::Type::kMat2x3:
+            return "mat2x3";
+        case Token::Type::kMat2x4:
+            return "mat2x4";
+        case Token::Type::kMat3x2:
+            return "mat3x2";
+        case Token::Type::kMat3x3:
+            return "mat3x3";
+        case Token::Type::kMat3x4:
+            return "mat3x4";
+        case Token::Type::kMat4x2:
+            return "mat4x2";
+        case Token::Type::kMat4x3:
+            return "mat4x3";
+        case Token::Type::kMat4x4:
+            return "mat4x4";
+        case Token::Type::kOverride:
+            return "override";
+        case Token::Type::kPrivate:
+            return "private";
+        case Token::Type::kPtr:
+            return "ptr";
+        case Token::Type::kReturn:
+            return "return";
+        case Token::Type::kSampler:
+            return "sampler";
+        case Token::Type::kComparisonSampler:
+            return "sampler_comparison";
+        case Token::Type::kStorage:
+            return "storage";
+        case Token::Type::kStruct:
+            return "struct";
+        case Token::Type::kSwitch:
+            return "switch";
+        case Token::Type::kTextureDepth2d:
+            return "texture_depth_2d";
+        case Token::Type::kTextureDepth2dArray:
+            return "texture_depth_2d_array";
+        case Token::Type::kTextureDepthCube:
+            return "texture_depth_cube";
+        case Token::Type::kTextureDepthCubeArray:
+            return "texture_depth_cube_array";
+        case Token::Type::kTextureDepthMultisampled2d:
+            return "texture_depth_multisampled_2d";
+        case Token::Type::kTextureExternal:
+            return "texture_external";
+        case Token::Type::kTextureMultisampled2d:
+            return "texture_multisampled_2d";
+        case Token::Type::kTextureSampled1d:
+            return "texture_1d";
+        case Token::Type::kTextureSampled2d:
+            return "texture_2d";
+        case Token::Type::kTextureSampled2dArray:
+            return "texture_2d_array";
+        case Token::Type::kTextureSampled3d:
+            return "texture_3d";
+        case Token::Type::kTextureSampledCube:
+            return "texture_cube";
+        case Token::Type::kTextureSampledCubeArray:
+            return "texture_cube_array";
+        case Token::Type::kTextureStorage1d:
+            return "texture_storage_1d";
+        case Token::Type::kTextureStorage2d:
+            return "texture_storage_2d";
+        case Token::Type::kTextureStorage2dArray:
+            return "texture_storage_2d_array";
+        case Token::Type::kTextureStorage3d:
+            return "texture_storage_3d";
+        case Token::Type::kTrue:
+            return "true";
+        case Token::Type::kType:
+            return "type";
+        case Token::Type::kU32:
+            return "u32";
+        case Token::Type::kUniform:
+            return "uniform";
+        case Token::Type::kVar:
+            return "var";
+        case Token::Type::kVec2:
+            return "vec2";
+        case Token::Type::kVec3:
+            return "vec3";
+        case Token::Type::kVec4:
+            return "vec4";
+        case Token::Type::kWorkgroup:
+            return "workgroup";
+    }
 
-  return "<unknown>";
+    return "<unknown>";
 }
 
 Token::Token() : type_(Type::kUninitialized) {}
@@ -271,11 +275,8 @@
 Token::Token(Type type, const Source& source, const char* str)
     : type_(type), source_(source), value_(std::string_view(str)) {}
 
-Token::Token(const Source& source, uint32_t val)
-    : type_(Type::kUintLiteral), source_(source), value_(val) {}
-
-Token::Token(const Source& source, int32_t val)
-    : type_(Type::kSintLiteral), source_(source), value_(val) {}
+Token::Token(Type type, const Source& source, int64_t val)
+    : type_(type), source_(source), value_(val) {}
 
 Token::Token(const Source& source, float val)
     : type_(Type::kFloatLiteral), source_(source), value_(val) {}
@@ -291,44 +292,42 @@
 Token& Token::operator=(const Token& rhs) = default;
 
 bool Token::operator==(std::string_view ident) {
-  if (type_ != Type::kIdentifier) {
-    return false;
-  }
-  if (auto* view = std::get_if<std::string_view>(&value_)) {
-    return *view == ident;
-  }
-  return std::get<std::string>(value_) == ident;
+    if (type_ != Type::kIdentifier) {
+        return false;
+    }
+    if (auto* view = std::get_if<std::string_view>(&value_)) {
+        return *view == ident;
+    }
+    return std::get<std::string>(value_) == ident;
 }
 
 std::string Token::to_str() const {
-  switch (type_) {
-    case Type::kFloatLiteral:
-      return std::to_string(std::get<float>(value_));
-    case Type::kSintLiteral:
-      return std::to_string(std::get<int32_t>(value_));
-    case Type::kUintLiteral:
-      return std::to_string(std::get<uint32_t>(value_));
-    case Type::kIdentifier:
-    case Type::kError:
-      if (auto* view = std::get_if<std::string_view>(&value_)) {
-        return std::string(*view);
-      }
-      return std::get<std::string>(value_);
-    default:
-      return "";
-  }
+    switch (type_) {
+        case Type::kFloatLiteral:
+            return std::to_string(std::get<float>(value_));
+        case Type::kIntLiteral:
+            return std::to_string(std::get<int64_t>(value_));
+        case Type::kIntILiteral:
+            return std::to_string(std::get<int64_t>(value_)) + "i";
+        case Type::kIntULiteral:
+            return std::to_string(std::get<int64_t>(value_)) + "u";
+        case Type::kIdentifier:
+        case Type::kError:
+            if (auto* view = std::get_if<std::string_view>(&value_)) {
+                return std::string(*view);
+            }
+            return std::get<std::string>(value_);
+        default:
+            return "";
+    }
 }
 
 float Token::to_f32() const {
-  return std::get<float>(value_);
+    return std::get<float>(value_);
 }
 
-uint32_t Token::to_u32() const {
-  return std::get<uint32_t>(value_);
-}
-
-int32_t Token::to_i32() const {
-  return std::get<int32_t>(value_);
+int64_t Token::to_i64() const {
+    return std::get<int64_t>(value_);
 }
 
 }  // namespace tint::reader::wgsl
diff --git a/src/tint/reader/wgsl/token.h b/src/tint/reader/wgsl/token.h
index a3715ee..106d1a6 100644
--- a/src/tint/reader/wgsl/token.h
+++ b/src/tint/reader/wgsl/token.h
@@ -26,391 +26,382 @@
 
 /// Stores tokens generated by the Lexer
 class Token {
- public:
-  /// The type of the parsed token
-  enum class Type {
-    /// Error result
-    kError = -2,
-    /// Uninitialized token
-    kUninitialized = 0,
-    /// End of input string reached
-    kEOF,
+  public:
+    /// The type of the parsed token
+    enum class Type {
+        /// Error result
+        kError = -2,
+        /// Uninitialized token
+        kUninitialized = 0,
+        /// End of input string reached
+        kEOF,
 
-    /// An identifier
-    kIdentifier,
-    /// A float value
-    kFloatLiteral,
-    /// An signed int value
-    kSintLiteral,
-    /// A unsigned int value
-    kUintLiteral,
+        /// An identifier
+        kIdentifier,
+        /// A float value
+        kFloatLiteral,
+        /// An integer literal with no suffix
+        kIntLiteral,
+        /// An integer literal with an 'i' suffix
+        kIntILiteral,
+        /// An integer literal with a 'u' suffix
+        kIntULiteral,
 
-    /// A '&'
-    kAnd,
-    /// A '&&'
-    kAndAnd,
-    /// A '->'
-    kArrow,
-    /// A '@'
-    kAttr,
-    /// A '/'
-    kForwardSlash,
-    /// A '!'
-    kBang,
-    /// A '['
-    kBracketLeft,
-    /// A ']'
-    kBracketRight,
-    /// A '{'
-    kBraceLeft,
-    /// A '}'
-    kBraceRight,
-    /// A ':'
-    kColon,
-    /// A ','
-    kComma,
-    /// A '='
-    kEqual,
-    /// A '=='
-    kEqualEqual,
-    /// A '>'
-    kGreaterThan,
-    /// A '>='
-    kGreaterThanEqual,
-    /// A '>>'
-    kShiftRight,
-    /// A '<'
-    kLessThan,
-    /// A '<='
-    kLessThanEqual,
-    /// A '<<'
-    kShiftLeft,
-    /// A '%'
-    kMod,
-    /// A '-'
-    kMinus,
-    /// A '--'
-    kMinusMinus,
-    /// A '!='
-    kNotEqual,
-    /// A '.'
-    kPeriod,
-    /// A '+'
-    kPlus,
-    /// A '++'
-    kPlusPlus,
-    /// A '|'
-    kOr,
-    /// A '||'
-    kOrOr,
-    /// A '('
-    kParenLeft,
-    /// A ')'
-    kParenRight,
-    /// A ';'
-    kSemicolon,
-    /// A '*'
-    kStar,
-    /// A '~'
-    kTilde,
-    /// A '_'
-    kUnderscore,
-    /// A '^'
-    kXor,
-    /// A '+='
-    kPlusEqual,
-    /// A '-='
-    kMinusEqual,
-    /// A '*='
-    kTimesEqual,
-    /// A '/='
-    kDivisionEqual,
-    /// A '%='
-    kModuloEqual,
-    /// A '&='
-    kAndEqual,
-    /// A '|='
-    kOrEqual,
-    /// A '^='
-    kXorEqual,
+        /// A '&'
+        kAnd,
+        /// A '&&'
+        kAndAnd,
+        /// A '->'
+        kArrow,
+        /// A '@'
+        kAttr,
+        /// A '/'
+        kForwardSlash,
+        /// A '!'
+        kBang,
+        /// A '['
+        kBracketLeft,
+        /// A ']'
+        kBracketRight,
+        /// A '{'
+        kBraceLeft,
+        /// A '}'
+        kBraceRight,
+        /// A ':'
+        kColon,
+        /// A ','
+        kComma,
+        /// A '='
+        kEqual,
+        /// A '=='
+        kEqualEqual,
+        /// A '>'
+        kGreaterThan,
+        /// A '>='
+        kGreaterThanEqual,
+        /// A '>>'
+        kShiftRight,
+        /// A '<'
+        kLessThan,
+        /// A '<='
+        kLessThanEqual,
+        /// A '<<'
+        kShiftLeft,
+        /// A '%'
+        kMod,
+        /// A '-'
+        kMinus,
+        /// A '--'
+        kMinusMinus,
+        /// A '!='
+        kNotEqual,
+        /// A '.'
+        kPeriod,
+        /// A '+'
+        kPlus,
+        /// A '++'
+        kPlusPlus,
+        /// A '|'
+        kOr,
+        /// A '||'
+        kOrOr,
+        /// A '('
+        kParenLeft,
+        /// A ')'
+        kParenRight,
+        /// A ';'
+        kSemicolon,
+        /// A '*'
+        kStar,
+        /// A '~'
+        kTilde,
+        /// A '_'
+        kUnderscore,
+        /// A '^'
+        kXor,
+        /// A '+='
+        kPlusEqual,
+        /// A '-='
+        kMinusEqual,
+        /// A '*='
+        kTimesEqual,
+        /// A '/='
+        kDivisionEqual,
+        /// A '%='
+        kModuloEqual,
+        /// A '&='
+        kAndEqual,
+        /// A '|='
+        kOrEqual,
+        /// A '^='
+        kXorEqual,
 
-    /// A 'array'
-    kArray,
-    /// A 'atomic'
-    kAtomic,
-    /// A 'bitcast'
-    kBitcast,
-    /// A 'bool'
-    kBool,
-    /// A 'break'
-    kBreak,
-    /// A 'case'
-    kCase,
-    /// A 'continue'
-    kContinue,
-    /// A 'continuing'
-    kContinuing,
-    /// A 'discard'
-    kDiscard,
-    /// A 'default'
-    kDefault,
-    /// A 'else'
-    kElse,
-    /// A 'f32'
-    kF32,
-    /// A 'fallthrough'
-    kFallthrough,
-    /// A 'false'
-    kFalse,
-    /// A 'fn'
-    kFn,
-    // A 'for'
-    kFor,
-    /// A 'function'
-    kFunction,
-    /// A 'i32'
-    kI32,
-    /// A 'if'
-    kIf,
-    /// A 'import'
-    kImport,
-    /// A 'let'
-    kLet,
-    /// A 'loop'
-    kLoop,
-    /// A 'mat2x2'
-    kMat2x2,
-    /// A 'mat2x3'
-    kMat2x3,
-    /// A 'mat2x4'
-    kMat2x4,
-    /// A 'mat3x2'
-    kMat3x2,
-    /// A 'mat3x3'
-    kMat3x3,
-    /// A 'mat3x4'
-    kMat3x4,
-    /// A 'mat4x2'
-    kMat4x2,
-    /// A 'mat4x3'
-    kMat4x3,
-    /// A 'mat4x4'
-    kMat4x4,
-    /// A 'override'
-    kOverride,
-    /// A 'private'
-    kPrivate,
-    /// A 'ptr'
-    kPtr,
-    /// A 'return'
-    kReturn,
-    /// A 'sampler'
-    kSampler,
-    /// A 'sampler_comparison'
-    kComparisonSampler,
-    /// A 'storage'
-    kStorage,
-    /// A 'struct'
-    kStruct,
-    /// A 'switch'
-    kSwitch,
-    /// A 'texture_depth_2d'
-    kTextureDepth2d,
-    /// A 'texture_depth_2d_array'
-    kTextureDepth2dArray,
-    /// A 'texture_depth_cube'
-    kTextureDepthCube,
-    /// A 'texture_depth_cube_array'
-    kTextureDepthCubeArray,
-    /// A 'texture_depth_multisampled_2d'
-    kTextureDepthMultisampled2d,
-    /// A 'texture_external'
-    kTextureExternal,
-    /// A 'texture_multisampled_2d'
-    kTextureMultisampled2d,
-    /// A 'texture_1d'
-    kTextureSampled1d,
-    /// A 'texture_2d'
-    kTextureSampled2d,
-    /// A 'texture_2d_array'
-    kTextureSampled2dArray,
-    /// A 'texture_3d'
-    kTextureSampled3d,
-    /// A 'texture_cube'
-    kTextureSampledCube,
-    /// A 'texture_cube_array'
-    kTextureSampledCubeArray,
-    /// A 'texture_storage_1d'
-    kTextureStorage1d,
-    /// A 'texture_storage_2d'
-    kTextureStorage2d,
-    /// A 'texture_storage_2d_array'
-    kTextureStorage2dArray,
-    /// A 'texture_storage_3d'
-    kTextureStorage3d,
-    /// A 'true'
-    kTrue,
-    /// A 'type'
-    kType,
-    /// A 'u32'
-    kU32,
-    /// A 'uniform'
-    kUniform,
-    /// A 'var'
-    kVar,
-    /// A 'vec2'
-    kVec2,
-    /// A 'vec3'
-    kVec3,
-    /// A 'vec4'
-    kVec4,
-    /// A 'workgroup'
-    kWorkgroup,
-  };
+        /// A 'array'
+        kArray,
+        /// A 'atomic'
+        kAtomic,
+        /// A 'bitcast'
+        kBitcast,
+        /// A 'bool'
+        kBool,
+        /// A 'break'
+        kBreak,
+        /// A 'case'
+        kCase,
+        /// A 'continue'
+        kContinue,
+        /// A 'continuing'
+        kContinuing,
+        /// A 'discard'
+        kDiscard,
+        /// A 'default'
+        kDefault,
+        /// A 'else'
+        kElse,
+        /// A 'enable'
+        kEnable,
+        /// A 'f32'
+        kF32,
+        /// A 'fallthrough'
+        kFallthrough,
+        /// A 'false'
+        kFalse,
+        /// A 'fn'
+        kFn,
+        // A 'for'
+        kFor,
+        /// A 'function'
+        kFunction,
+        /// A 'i32'
+        kI32,
+        /// A 'if'
+        kIf,
+        /// A 'import'
+        kImport,
+        /// A 'let'
+        kLet,
+        /// A 'loop'
+        kLoop,
+        /// A 'mat2x2'
+        kMat2x2,
+        /// A 'mat2x3'
+        kMat2x3,
+        /// A 'mat2x4'
+        kMat2x4,
+        /// A 'mat3x2'
+        kMat3x2,
+        /// A 'mat3x3'
+        kMat3x3,
+        /// A 'mat3x4'
+        kMat3x4,
+        /// A 'mat4x2'
+        kMat4x2,
+        /// A 'mat4x3'
+        kMat4x3,
+        /// A 'mat4x4'
+        kMat4x4,
+        /// A 'override'
+        kOverride,
+        /// A 'private'
+        kPrivate,
+        /// A 'ptr'
+        kPtr,
+        /// A 'return'
+        kReturn,
+        /// A 'sampler'
+        kSampler,
+        /// A 'sampler_comparison'
+        kComparisonSampler,
+        /// A 'storage'
+        kStorage,
+        /// A 'struct'
+        kStruct,
+        /// A 'switch'
+        kSwitch,
+        /// A 'texture_depth_2d'
+        kTextureDepth2d,
+        /// A 'texture_depth_2d_array'
+        kTextureDepth2dArray,
+        /// A 'texture_depth_cube'
+        kTextureDepthCube,
+        /// A 'texture_depth_cube_array'
+        kTextureDepthCubeArray,
+        /// A 'texture_depth_multisampled_2d'
+        kTextureDepthMultisampled2d,
+        /// A 'texture_external'
+        kTextureExternal,
+        /// A 'texture_multisampled_2d'
+        kTextureMultisampled2d,
+        /// A 'texture_1d'
+        kTextureSampled1d,
+        /// A 'texture_2d'
+        kTextureSampled2d,
+        /// A 'texture_2d_array'
+        kTextureSampled2dArray,
+        /// A 'texture_3d'
+        kTextureSampled3d,
+        /// A 'texture_cube'
+        kTextureSampledCube,
+        /// A 'texture_cube_array'
+        kTextureSampledCubeArray,
+        /// A 'texture_storage_1d'
+        kTextureStorage1d,
+        /// A 'texture_storage_2d'
+        kTextureStorage2d,
+        /// A 'texture_storage_2d_array'
+        kTextureStorage2dArray,
+        /// A 'texture_storage_3d'
+        kTextureStorage3d,
+        /// A 'true'
+        kTrue,
+        /// A 'type'
+        kType,
+        /// A 'u32'
+        kU32,
+        /// A 'uniform'
+        kUniform,
+        /// A 'var'
+        kVar,
+        /// A 'vec2'
+        kVec2,
+        /// A 'vec3'
+        kVec3,
+        /// A 'vec4'
+        kVec4,
+        /// A 'workgroup'
+        kWorkgroup,
+    };
 
-  /// Converts a token type to a name
-  /// @param type the type to convert
-  /// @returns the token type as as string
-  static std::string_view TypeToName(Type type);
+    /// Converts a token type to a name
+    /// @param type the type to convert
+    /// @returns the token type as as string
+    static std::string_view TypeToName(Type type);
 
-  /// Creates an uninitialized token
-  Token();
-  /// Create a Token
-  /// @param type the Token::Type of the token
-  /// @param source the source of the token
-  Token(Type type, const Source& source);
+    /// Creates an uninitialized token
+    Token();
+    /// Create a Token
+    /// @param type the Token::Type of the token
+    /// @param source the source of the token
+    Token(Type type, const Source& source);
 
-  /// Create a string Token
-  /// @param type the Token::Type of the token
-  /// @param source the source of the token
-  /// @param view the source string view for the token
-  Token(Type type, const Source& source, const std::string_view& view);
-  /// Create a string Token
-  /// @param type the Token::Type of the token
-  /// @param source the source of the token
-  /// @param str the source string for the token
-  Token(Type type, const Source& source, const std::string& str);
-  /// Create a string Token
-  /// @param type the Token::Type of the token
-  /// @param source the source of the token
-  /// @param str the source string for the token
-  Token(Type type, const Source& source, const char* str);
-  /// Create a unsigned integer Token
-  /// @param source the source of the token
-  /// @param val the source unsigned for the token
-  Token(const Source& source, uint32_t val);
-  /// Create a signed integer Token
-  /// @param source the source of the token
-  /// @param val the source integer for the token
-  Token(const Source& source, int32_t val);
-  /// Create a float Token
-  /// @param source the source of the token
-  /// @param val the source float for the token
-  Token(const Source& source, float val);
-  /// Move constructor
-  Token(Token&&);
-  /// Copy constructor
-  Token(const Token&);
-  ~Token();
+    /// Create a string Token
+    /// @param type the Token::Type of the token
+    /// @param source the source of the token
+    /// @param view the source string view for the token
+    Token(Type type, const Source& source, const std::string_view& view);
+    /// Create a string Token
+    /// @param type the Token::Type of the token
+    /// @param source the source of the token
+    /// @param str the source string for the token
+    Token(Type type, const Source& source, const std::string& str);
+    /// Create a string Token
+    /// @param type the Token::Type of the token
+    /// @param source the source of the token
+    /// @param str the source string for the token
+    Token(Type type, const Source& source, const char* str);
+    /// Create a integer Token of the given type
+    /// @param type the Token::Type of the token
+    /// @param source the source of the token
+    /// @param val the source unsigned for the token
+    Token(Type type, const Source& source, int64_t val);
+    /// Create a float Token
+    /// @param source the source of the token
+    /// @param val the source float for the token
+    Token(const Source& source, float val);
+    /// Move constructor
+    Token(Token&&);
+    /// Copy constructor
+    Token(const Token&);
+    ~Token();
 
-  /// Assignment operator
-  /// @param b the token to copy
-  /// @return Token
-  Token& operator=(const Token& b);
+    /// Assignment operator
+    /// @param b the token to copy
+    /// @return Token
+    Token& operator=(const Token& b);
 
-  /// Equality operator with an identifier
-  /// @param ident the identifier string
-  /// @return true if this token is an identifier and is equal to ident.
-  bool operator==(std::string_view ident);
+    /// Equality operator with an identifier
+    /// @param ident the identifier string
+    /// @return true if this token is an identifier and is equal to ident.
+    bool operator==(std::string_view ident);
 
-  /// Returns true if the token is of the given type
-  /// @param t the type to check against.
-  /// @returns true if the token is of type `t`
-  bool Is(Type t) const { return type_ == t; }
+    /// Returns true if the token is of the given type
+    /// @param t the type to check against.
+    /// @returns true if the token is of type `t`
+    bool Is(Type t) const { return type_ == t; }
 
-  /// @returns true if the token is uninitialized
-  bool IsUninitialized() const { return type_ == Type::kUninitialized; }
-  /// @returns true if the token is EOF
-  bool IsEof() const { return type_ == Type::kEOF; }
-  /// @returns true if the token is Error
-  bool IsError() const { return type_ == Type::kError; }
-  /// @returns true if the token is an identifier
-  bool IsIdentifier() const { return type_ == Type::kIdentifier; }
-  /// @returns true if the token is a literal
-  bool IsLiteral() const {
-    return type_ == Type::kSintLiteral || type_ == Type::kFalse ||
-           type_ == Type::kUintLiteral || type_ == Type::kTrue ||
-           type_ == Type::kFloatLiteral;
-  }
-  /// @returns true if token is a 'matNxM'
-  bool IsMatrix() const {
-    return type_ == Type::kMat2x2 || type_ == Type::kMat2x3 ||
-           type_ == Type::kMat2x4 || type_ == Type::kMat3x2 ||
-           type_ == Type::kMat3x3 || type_ == Type::kMat3x4 ||
-           type_ == Type::kMat4x2 || type_ == Type::kMat4x3 ||
-           type_ == Type::kMat4x4;
-  }
-  /// @returns true if token is a 'mat3xM'
-  bool IsMat3xN() const {
-    return type_ == Type::kMat3x2 || type_ == Type::kMat3x3 ||
-           type_ == Type::kMat3x4;
-  }
-  /// @returns true if token is a 'mat4xM'
-  bool IsMat4xN() const {
-    return type_ == Type::kMat4x2 || type_ == Type::kMat4x3 ||
-           type_ == Type::kMat4x4;
-  }
-  /// @returns true if token is a 'matNx3'
-  bool IsMatNx3() const {
-    return type_ == Type::kMat2x3 || type_ == Type::kMat3x3 ||
-           type_ == Type::kMat4x3;
-  }
-  /// @returns true if token is a 'matNx4'
-  bool IsMatNx4() const {
-    return type_ == Type::kMat2x4 || type_ == Type::kMat3x4 ||
-           type_ == Type::kMat4x4;
-  }
+    /// @returns true if the token is uninitialized
+    bool IsUninitialized() const { return type_ == Type::kUninitialized; }
+    /// @returns true if the token is EOF
+    bool IsEof() const { return type_ == Type::kEOF; }
+    /// @returns true if the token is Error
+    bool IsError() const { return type_ == Type::kError; }
+    /// @returns true if the token is an identifier
+    bool IsIdentifier() const { return type_ == Type::kIdentifier; }
+    /// @returns true if the token is a literal
+    bool IsLiteral() const {
+        return type_ == Type::kIntLiteral || type_ == Type::kIntILiteral ||
+               type_ == Type::kIntULiteral || type_ == Type::kFalse || type_ == Type::kTrue ||
+               type_ == Type::kFloatLiteral;
+    }
+    /// @returns true if token is a 'matNxM'
+    bool IsMatrix() const {
+        return type_ == Type::kMat2x2 || type_ == Type::kMat2x3 || type_ == Type::kMat2x4 ||
+               type_ == Type::kMat3x2 || type_ == Type::kMat3x3 || type_ == Type::kMat3x4 ||
+               type_ == Type::kMat4x2 || type_ == Type::kMat4x3 || type_ == Type::kMat4x4;
+    }
+    /// @returns true if token is a 'mat3xM'
+    bool IsMat3xN() const {
+        return type_ == Type::kMat3x2 || type_ == Type::kMat3x3 || type_ == Type::kMat3x4;
+    }
+    /// @returns true if token is a 'mat4xM'
+    bool IsMat4xN() const {
+        return type_ == Type::kMat4x2 || type_ == Type::kMat4x3 || type_ == Type::kMat4x4;
+    }
+    /// @returns true if token is a 'matNx3'
+    bool IsMatNx3() const {
+        return type_ == Type::kMat2x3 || type_ == Type::kMat3x3 || type_ == Type::kMat4x3;
+    }
+    /// @returns true if token is a 'matNx4'
+    bool IsMatNx4() const {
+        return type_ == Type::kMat2x4 || type_ == Type::kMat3x4 || type_ == Type::kMat4x4;
+    }
 
-  /// @returns true if token is a 'vecN'
-  bool IsVector() const {
-    return type_ == Type::kVec2 || type_ == Type::kVec3 || type_ == Type::kVec4;
-  }
+    /// @returns true if token is a 'vecN'
+    bool IsVector() const {
+        return type_ == Type::kVec2 || type_ == Type::kVec3 || type_ == Type::kVec4;
+    }
 
-  /// @returns the source information for this token
-  Source source() const { return source_; }
+    /// @returns the source information for this token
+    Source source() const { return source_; }
 
-  /// Returns the string value of the token
-  /// @return std::string
-  std::string to_str() const;
-  /// Returns the float value of the token. 0 is returned if the token does not
-  /// contain a float value.
-  /// @return float
-  float to_f32() const;
-  /// Returns the uint32 value of the token. 0 is returned if the token does not
-  /// contain a unsigned integer value.
-  /// @return uint32_t
-  uint32_t to_u32() const;
-  /// Returns the int32 value of the token. 0 is returned if the token does not
-  /// contain a signed integer value.
-  /// @return int32_t
-  int32_t to_i32() const;
+    /// Returns the string value of the token
+    /// @return std::string
+    std::string to_str() const;
+    /// Returns the float value of the token. 0 is returned if the token does not
+    /// contain a float value.
+    /// @return float
+    float to_f32() const;
+    /// Returns the int64_t value of the token. 0 is returned if the token does
+    /// not contain an integer value.
+    /// @return int64_t
+    int64_t to_i64() const;
 
-  /// @returns the token type as string
-  std::string_view to_name() const { return Token::TypeToName(type_); }
+    /// @returns the token type as string
+    std::string_view to_name() const { return Token::TypeToName(type_); }
 
- private:
-  /// The Token::Type of the token
-  Type type_ = Type::kError;
-  /// The source where the token appeared
-  Source source_;
-  /// The value represented by the token
-  std::variant<int32_t, uint32_t, float, std::string, std::string_view> value_;
+  private:
+    /// The Token::Type of the token
+    Type type_ = Type::kError;
+    /// The source where the token appeared
+    Source source_;
+    /// The value represented by the token
+    std::variant<int64_t, float, std::string, std::string_view> value_;
 };
 
 #ifndef NDEBUG
 inline std::ostream& operator<<(std::ostream& out, Token::Type type) {
-  out << Token::TypeToName(type);
-  return out;
+    out << Token::TypeToName(type);
+    return out;
 }
 #endif  // NDEBUG
 
diff --git a/src/tint/reader/wgsl/token_test.cc b/src/tint/reader/wgsl/token_test.cc
index 6d25cd7..dd46616 100644
--- a/src/tint/reader/wgsl/token_test.cc
+++ b/src/tint/reader/wgsl/token_test.cc
@@ -24,51 +24,51 @@
 using TokenTest = testing::Test;
 
 TEST_F(TokenTest, ReturnsF32) {
-  Token t1(Source{}, -2.345f);
-  EXPECT_EQ(t1.to_f32(), -2.345f);
+    Token t1(Source{}, -2.345f);
+    EXPECT_EQ(t1.to_f32(), -2.345f);
 
-  Token t2(Source{}, 2.345f);
-  EXPECT_EQ(t2.to_f32(), 2.345f);
+    Token t2(Source{}, 2.345f);
+    EXPECT_EQ(t2.to_f32(), 2.345f);
 }
 
 TEST_F(TokenTest, ReturnsI32) {
-  Token t1(Source{}, -2345);
-  EXPECT_EQ(t1.to_i32(), -2345);
+    Token t1(Token::Type::kIntILiteral, Source{}, -2345);
+    EXPECT_EQ(t1.to_i64(), -2345);
 
-  Token t2(Source{}, 2345);
-  EXPECT_EQ(t2.to_i32(), 2345);
+    Token t2(Token::Type::kIntILiteral, Source{}, 2345);
+    EXPECT_EQ(t2.to_i64(), 2345);
 }
 
 TEST_F(TokenTest, HandlesMaxI32) {
-  Token t1(Source{}, std::numeric_limits<int32_t>::max());
-  EXPECT_EQ(t1.to_i32(), std::numeric_limits<int32_t>::max());
+    Token t1(Token::Type::kIntILiteral, Source{}, std::numeric_limits<int32_t>::max());
+    EXPECT_EQ(t1.to_i64(), std::numeric_limits<int32_t>::max());
 }
 
 TEST_F(TokenTest, HandlesMinI32) {
-  Token t1(Source{}, std::numeric_limits<int32_t>::min());
-  EXPECT_EQ(t1.to_i32(), std::numeric_limits<int32_t>::min());
+    Token t1(Token::Type::kIntILiteral, Source{}, std::numeric_limits<int32_t>::min());
+    EXPECT_EQ(t1.to_i64(), std::numeric_limits<int32_t>::min());
 }
 
 TEST_F(TokenTest, ReturnsU32) {
-  Token t2(Source{}, 2345u);
-  EXPECT_EQ(t2.to_u32(), 2345u);
+    Token t2(Token::Type::kIntULiteral, Source{}, 2345u);
+    EXPECT_EQ(t2.to_i64(), 2345u);
 }
 
 TEST_F(TokenTest, ReturnsMaxU32) {
-  Token t1(Source{}, std::numeric_limits<uint32_t>::max());
-  EXPECT_EQ(t1.to_u32(), std::numeric_limits<uint32_t>::max());
+    Token t1(Token::Type::kIntULiteral, Source{}, std::numeric_limits<uint32_t>::max());
+    EXPECT_EQ(t1.to_i64(), std::numeric_limits<uint32_t>::max());
 }
 
 TEST_F(TokenTest, Source) {
-  Source src;
-  src.range.begin = Source::Location{3, 9};
-  src.range.end = Source::Location{4, 3};
+    Source src;
+    src.range.begin = Source::Location{3, 9};
+    src.range.end = Source::Location{4, 3};
 
-  Token t(Token::Type::kUintLiteral, src);
-  EXPECT_EQ(t.source().range.begin.line, 3u);
-  EXPECT_EQ(t.source().range.begin.column, 9u);
-  EXPECT_EQ(t.source().range.end.line, 4u);
-  EXPECT_EQ(t.source().range.end.column, 3u);
+    Token t(Token::Type::kIntLiteral, src);
+    EXPECT_EQ(t.source().range.begin.line, 3u);
+    EXPECT_EQ(t.source().range.begin.column, 9u);
+    EXPECT_EQ(t.source().range.end.line, 4u);
+    EXPECT_EQ(t.source().range.end.column, 3u);
 }
 
 }  // namespace
diff --git a/src/tint/resolver/array_accessor_test.cc b/src/tint/resolver/array_accessor_test.cc
index e506f23..1704699 100644
--- a/src/tint/resolver/array_accessor_test.cc
+++ b/src/tint/resolver/array_accessor_test.cc
@@ -16,7 +16,9 @@
 
 #include "gmock/gmock.h"
 #include "src/tint/resolver/resolver_test_helper.h"
-#include "src/tint/sem/reference_type.h"
+#include "src/tint/sem/reference.h"
+
+using namespace tint::number_suffixes;  // NOLINT
 
 namespace tint::resolver {
 namespace {
@@ -24,286 +26,277 @@
 using ResolverIndexAccessorTest = ResolverTest;
 
 TEST_F(ResolverIndexAccessorTest, Matrix_Dynamic_F32) {
-  Global("my_var", ty.mat2x3<f32>(), ast::StorageClass::kPrivate);
-  auto* acc = IndexAccessor("my_var", Expr(Source{{12, 34}}, 1.0f));
-  WrapInFunction(acc);
+    Global("my_var", ty.mat2x3<f32>(), ast::StorageClass::kPrivate);
+    auto* acc = IndexAccessor("my_var", Expr(Source{{12, 34}}, 1.0f));
+    WrapInFunction(acc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: index must be of type 'i32' or 'u32', found: 'f32'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: index must be of type 'i32' or 'u32', found: 'f32'");
 }
 
 TEST_F(ResolverIndexAccessorTest, Matrix_Dynamic_Ref) {
-  Global("my_var", ty.mat2x3<f32>(), ast::StorageClass::kPrivate);
-  auto* idx = Var("idx", ty.i32(), Construct(ty.i32()));
-  auto* acc = IndexAccessor("my_var", idx);
-  WrapInFunction(Decl(idx), acc);
+    Global("my_var", ty.mat2x3<f32>(), ast::StorageClass::kPrivate);
+    auto* idx = Var("idx", ty.i32(), Construct(ty.i32()));
+    auto* acc = IndexAccessor("my_var", idx);
+    WrapInFunction(Decl(idx), acc);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverIndexAccessorTest, Matrix_BothDimensions_Dynamic_Ref) {
-  Global("my_var", ty.mat4x4<f32>(), ast::StorageClass::kPrivate);
-  auto* idx = Var("idx", ty.u32(), Expr(3u));
-  auto* idy = Var("idy", ty.u32(), Expr(2u));
-  auto* acc = IndexAccessor(IndexAccessor("my_var", idx), idy);
-  WrapInFunction(Decl(idx), Decl(idy), acc);
+    Global("my_var", ty.mat4x4<f32>(), ast::StorageClass::kPrivate);
+    auto* idx = Var("idx", ty.u32(), Expr(3_u));
+    auto* idy = Var("idy", ty.u32(), Expr(2_u));
+    auto* acc = IndexAccessor(IndexAccessor("my_var", idx), idy);
+    WrapInFunction(Decl(idx), Decl(idy), acc);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverIndexAccessorTest, Matrix_Dynamic) {
-  GlobalConst("my_const", ty.mat2x3<f32>(), Construct(ty.mat2x3<f32>()));
-  auto* idx = Var("idx", ty.i32(), Construct(ty.i32()));
-  auto* acc = IndexAccessor("my_const", Expr(Source{{12, 34}}, idx));
-  WrapInFunction(Decl(idx), acc);
+    GlobalConst("my_const", ty.mat2x3<f32>(), Construct(ty.mat2x3<f32>()));
+    auto* idx = Var("idx", ty.i32(), Construct(ty.i32()));
+    auto* acc = IndexAccessor("my_const", Expr(Source{{12, 34}}, idx));
+    WrapInFunction(Decl(idx), acc);
 
-  EXPECT_TRUE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "");
+    EXPECT_TRUE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "");
 }
 
 TEST_F(ResolverIndexAccessorTest, Matrix_XDimension_Dynamic) {
-  GlobalConst("my_var", ty.mat4x4<f32>(), Construct(ty.mat4x4<f32>()));
-  auto* idx = Var("idx", ty.u32(), Expr(3u));
-  auto* acc = IndexAccessor("my_var", Expr(Source{{12, 34}}, idx));
-  WrapInFunction(Decl(idx), acc);
+    GlobalConst("my_var", ty.mat4x4<f32>(), Construct(ty.mat4x4<f32>()));
+    auto* idx = Var("idx", ty.u32(), Expr(3_u));
+    auto* acc = IndexAccessor("my_var", Expr(Source{{12, 34}}, idx));
+    WrapInFunction(Decl(idx), acc);
 
-  EXPECT_TRUE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "");
+    EXPECT_TRUE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "");
 }
 
 TEST_F(ResolverIndexAccessorTest, Matrix_BothDimension_Dynamic) {
-  GlobalConst("my_var", ty.mat4x4<f32>(), Construct(ty.mat4x4<f32>()));
-  auto* idx = Var("idy", ty.u32(), Expr(2u));
-  auto* acc =
-      IndexAccessor(IndexAccessor("my_var", Expr(Source{{12, 34}}, idx)), 1);
-  WrapInFunction(Decl(idx), acc);
+    GlobalConst("my_var", ty.mat4x4<f32>(), Construct(ty.mat4x4<f32>()));
+    auto* idx = Var("idy", ty.u32(), Expr(2_u));
+    auto* acc = IndexAccessor(IndexAccessor("my_var", Expr(Source{{12, 34}}, idx)), 1_i);
+    WrapInFunction(Decl(idx), acc);
 
-  EXPECT_TRUE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "");
+    EXPECT_TRUE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "");
 }
 
 TEST_F(ResolverIndexAccessorTest, Matrix) {
-  Global("my_var", ty.mat2x3<f32>(), ast::StorageClass::kPrivate);
+    Global("my_var", ty.mat2x3<f32>(), ast::StorageClass::kPrivate);
 
-  auto* acc = IndexAccessor("my_var", 2);
-  WrapInFunction(acc);
+    auto* acc = IndexAccessor("my_var", 2_i);
+    WrapInFunction(acc);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(acc), nullptr);
-  ASSERT_TRUE(TypeOf(acc)->Is<sem::Reference>());
+    ASSERT_NE(TypeOf(acc), nullptr);
+    ASSERT_TRUE(TypeOf(acc)->Is<sem::Reference>());
 
-  auto* ref = TypeOf(acc)->As<sem::Reference>();
-  ASSERT_TRUE(ref->StoreType()->Is<sem::Vector>());
-  EXPECT_EQ(ref->StoreType()->As<sem::Vector>()->Width(), 3u);
+    auto* ref = TypeOf(acc)->As<sem::Reference>();
+    ASSERT_TRUE(ref->StoreType()->Is<sem::Vector>());
+    EXPECT_EQ(ref->StoreType()->As<sem::Vector>()->Width(), 3u);
 }
 
 TEST_F(ResolverIndexAccessorTest, Matrix_BothDimensions) {
-  Global("my_var", ty.mat2x3<f32>(), ast::StorageClass::kPrivate);
+    Global("my_var", ty.mat2x3<f32>(), ast::StorageClass::kPrivate);
 
-  auto* acc = IndexAccessor(IndexAccessor("my_var", 2), 1);
-  WrapInFunction(acc);
+    auto* acc = IndexAccessor(IndexAccessor("my_var", 2_i), 1_i);
+    WrapInFunction(acc);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(acc), nullptr);
-  ASSERT_TRUE(TypeOf(acc)->Is<sem::Reference>());
+    ASSERT_NE(TypeOf(acc), nullptr);
+    ASSERT_TRUE(TypeOf(acc)->Is<sem::Reference>());
 
-  auto* ref = TypeOf(acc)->As<sem::Reference>();
-  EXPECT_TRUE(ref->StoreType()->Is<sem::F32>());
+    auto* ref = TypeOf(acc)->As<sem::Reference>();
+    EXPECT_TRUE(ref->StoreType()->Is<sem::F32>());
 }
 
 TEST_F(ResolverIndexAccessorTest, Vector_F32) {
-  Global("my_var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
-  auto* acc = IndexAccessor("my_var", Expr(Source{{12, 34}}, 2.0f));
-  WrapInFunction(acc);
+    Global("my_var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+    auto* acc = IndexAccessor("my_var", Expr(Source{{12, 34}}, 2.0f));
+    WrapInFunction(acc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: index must be of type 'i32' or 'u32', found: 'f32'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: index must be of type 'i32' or 'u32', found: 'f32'");
 }
 
 TEST_F(ResolverIndexAccessorTest, Vector_Dynamic_Ref) {
-  Global("my_var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
-  auto* idx = Var("idx", ty.i32(), Expr(2));
-  auto* acc = IndexAccessor("my_var", idx);
-  WrapInFunction(Decl(idx), acc);
+    Global("my_var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+    auto* idx = Var("idx", ty.i32(), Expr(2_i));
+    auto* acc = IndexAccessor("my_var", idx);
+    WrapInFunction(Decl(idx), acc);
 
-  EXPECT_TRUE(r()->Resolve());
+    EXPECT_TRUE(r()->Resolve());
 }
 
 TEST_F(ResolverIndexAccessorTest, Vector_Dynamic) {
-  GlobalConst("my_var", ty.vec3<f32>(), Construct(ty.vec3<f32>()));
-  auto* idx = Var("idx", ty.i32(), Expr(2));
-  auto* acc = IndexAccessor("my_var", Expr(Source{{12, 34}}, idx));
-  WrapInFunction(Decl(idx), acc);
+    GlobalConst("my_var", ty.vec3<f32>(), Construct(ty.vec3<f32>()));
+    auto* idx = Var("idx", ty.i32(), Expr(2_i));
+    auto* acc = IndexAccessor("my_var", Expr(Source{{12, 34}}, idx));
+    WrapInFunction(Decl(idx), acc);
 
-  EXPECT_TRUE(r()->Resolve());
+    EXPECT_TRUE(r()->Resolve());
 }
 
 TEST_F(ResolverIndexAccessorTest, Vector) {
-  Global("my_var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+    Global("my_var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
 
-  auto* acc = IndexAccessor("my_var", 2);
-  WrapInFunction(acc);
+    auto* acc = IndexAccessor("my_var", 2_i);
+    WrapInFunction(acc);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(acc), nullptr);
-  ASSERT_TRUE(TypeOf(acc)->Is<sem::Reference>());
+    ASSERT_NE(TypeOf(acc), nullptr);
+    ASSERT_TRUE(TypeOf(acc)->Is<sem::Reference>());
 
-  auto* ref = TypeOf(acc)->As<sem::Reference>();
-  EXPECT_TRUE(ref->StoreType()->Is<sem::F32>());
+    auto* ref = TypeOf(acc)->As<sem::Reference>();
+    EXPECT_TRUE(ref->StoreType()->Is<sem::F32>());
 }
 
 TEST_F(ResolverIndexAccessorTest, Array) {
-  auto* idx = Expr(2);
-  Global("my_var", ty.array<f32, 3>(), ast::StorageClass::kPrivate);
+    auto* idx = Expr(2_i);
+    Global("my_var", ty.array<f32, 3>(), ast::StorageClass::kPrivate);
 
-  auto* acc = IndexAccessor("my_var", idx);
-  WrapInFunction(acc);
+    auto* acc = IndexAccessor("my_var", idx);
+    WrapInFunction(acc);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(acc), nullptr);
-  ASSERT_TRUE(TypeOf(acc)->Is<sem::Reference>());
+    ASSERT_NE(TypeOf(acc), nullptr);
+    ASSERT_TRUE(TypeOf(acc)->Is<sem::Reference>());
 
-  auto* ref = TypeOf(acc)->As<sem::Reference>();
-  EXPECT_TRUE(ref->StoreType()->Is<sem::F32>());
+    auto* ref = TypeOf(acc)->As<sem::Reference>();
+    EXPECT_TRUE(ref->StoreType()->Is<sem::F32>());
 }
 
 TEST_F(ResolverIndexAccessorTest, Alias_Array) {
-  auto* aary = Alias("myarrty", ty.array<f32, 3>());
+    auto* aary = Alias("myarrty", ty.array<f32, 3>());
 
-  Global("my_var", ty.Of(aary), ast::StorageClass::kPrivate);
+    Global("my_var", ty.Of(aary), ast::StorageClass::kPrivate);
 
-  auto* acc = IndexAccessor("my_var", 2);
-  WrapInFunction(acc);
+    auto* acc = IndexAccessor("my_var", 2_i);
+    WrapInFunction(acc);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(acc), nullptr);
-  ASSERT_TRUE(TypeOf(acc)->Is<sem::Reference>());
+    ASSERT_NE(TypeOf(acc), nullptr);
+    ASSERT_TRUE(TypeOf(acc)->Is<sem::Reference>());
 
-  auto* ref = TypeOf(acc)->As<sem::Reference>();
-  EXPECT_TRUE(ref->StoreType()->Is<sem::F32>());
+    auto* ref = TypeOf(acc)->As<sem::Reference>();
+    EXPECT_TRUE(ref->StoreType()->Is<sem::F32>());
 }
 
 TEST_F(ResolverIndexAccessorTest, Array_Constant) {
-  GlobalConst("my_var", ty.array<f32, 3>(), array<f32, 3>());
+    GlobalConst("my_var", ty.array<f32, 3>(), array<f32, 3>());
 
-  auto* acc = IndexAccessor("my_var", 2);
-  WrapInFunction(acc);
+    auto* acc = IndexAccessor("my_var", 2_i);
+    WrapInFunction(acc);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(acc), nullptr);
-  EXPECT_TRUE(TypeOf(acc)->Is<sem::F32>());
+    ASSERT_NE(TypeOf(acc), nullptr);
+    EXPECT_TRUE(TypeOf(acc)->Is<sem::F32>());
 }
 
 TEST_F(ResolverIndexAccessorTest, Array_Dynamic_I32) {
-  // let a : array<f32, 3> = 0;
-  // var idx : i32 = 0;
-  // var f : f32 = a[idx];
-  auto* a = Const("a", ty.array<f32, 3>(), array<f32, 3>());
-  auto* idx = Var("idx", ty.i32(), Construct(ty.i32()));
-  auto* f = Var("f", ty.f32(), IndexAccessor("a", Expr(Source{{12, 34}}, idx)));
-  Func("my_func", ast::VariableList{}, ty.void_(),
-       {
-           Decl(a),
-           Decl(idx),
-           Decl(f),
-       },
-       ast::AttributeList{});
+    // let a : array<f32, 3> = 0;
+    // var idx : i32 = 0;
+    // var f : f32 = a[idx];
+    auto* a = Let("a", ty.array<f32, 3>(), array<f32, 3>());
+    auto* idx = Var("idx", ty.i32(), Construct(ty.i32()));
+    auto* f = Var("f", ty.f32(), IndexAccessor("a", Expr(Source{{12, 34}}, idx)));
+    Func("my_func", ast::VariableList{}, ty.void_(),
+         {
+             Decl(a),
+             Decl(idx),
+             Decl(f),
+         },
+         ast::AttributeList{});
 
-  EXPECT_TRUE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "");
+    EXPECT_TRUE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "");
 }
 
 TEST_F(ResolverIndexAccessorTest, Array_Literal_F32) {
-  // let a : array<f32, 3>;
-  // var f : f32 = a[2.0f];
-  auto* a = Const("a", ty.array<f32, 3>(), array<f32, 3>());
-  auto* f =
-      Var("a_2", ty.f32(), IndexAccessor("a", Expr(Source{{12, 34}}, 2.0f)));
-  Func("my_func", ast::VariableList{}, ty.void_(),
-       {
-           Decl(a),
-           Decl(f),
-       },
-       ast::AttributeList{});
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: index must be of type 'i32' or 'u32', found: 'f32'");
+    // let a : array<f32, 3>;
+    // var f : f32 = a[2.0f];
+    auto* a = Let("a", ty.array<f32, 3>(), array<f32, 3>());
+    auto* f = Var("a_2", ty.f32(), IndexAccessor("a", Expr(Source{{12, 34}}, 2.0f)));
+    Func("my_func", ast::VariableList{}, ty.void_(),
+         {
+             Decl(a),
+             Decl(f),
+         },
+         ast::AttributeList{});
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: index must be of type 'i32' or 'u32', found: 'f32'");
 }
 
 TEST_F(ResolverIndexAccessorTest, Array_Literal_I32) {
-  // let a : array<f32, 3>;
-  // var f : f32 = a[2];
-  auto* a = Const("a", ty.array<f32, 3>(), array<f32, 3>());
-  auto* f = Var("a_2", ty.f32(), IndexAccessor("a", 2));
-  Func("my_func", ast::VariableList{}, ty.void_(),
-       {
-           Decl(a),
-           Decl(f),
-       },
-       ast::AttributeList{});
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    // let a : array<f32, 3>;
+    // var f : f32 = a[2i];
+    auto* a = Let("a", ty.array<f32, 3>(), array<f32, 3>());
+    auto* f = Var("a_2", ty.f32(), IndexAccessor("a", 2_i));
+    Func("my_func", ast::VariableList{}, ty.void_(),
+         {
+             Decl(a),
+             Decl(f),
+         },
+         ast::AttributeList{});
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverIndexAccessorTest, EXpr_Deref_FuncGoodParent) {
-  // fn func(p: ptr<function, vec4<f32>>) -> f32 {
-  //     let idx: u32 = u32();
-  //     let x: f32 = (*p)[idx];
-  //     return x;
-  // }
-  auto* p =
-      Param("p", ty.pointer(ty.vec4<f32>(), ast::StorageClass::kFunction));
-  auto* idx = Const("idx", ty.u32(), Construct(ty.u32()));
-  auto* star_p = Deref(p);
-  auto* accessor_expr = IndexAccessor(Source{{12, 34}}, star_p, idx);
-  auto* x = Var("x", ty.f32(), accessor_expr);
-  Func("func", {p}, ty.f32(), {Decl(idx), Decl(x), Return(x)});
+    // fn func(p: ptr<function, vec4<f32>>) -> f32 {
+    //     let idx: u32 = u32();
+    //     let x: f32 = (*p)[idx];
+    //     return x;
+    // }
+    auto* p = Param("p", ty.pointer(ty.vec4<f32>(), ast::StorageClass::kFunction));
+    auto* idx = Let("idx", ty.u32(), Construct(ty.u32()));
+    auto* star_p = Deref(p);
+    auto* accessor_expr = IndexAccessor(Source{{12, 34}}, star_p, idx);
+    auto* x = Var("x", ty.f32(), accessor_expr);
+    Func("func", {p}, ty.f32(), {Decl(idx), Decl(x), Return(x)});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverIndexAccessorTest, EXpr_Deref_FuncBadParent) {
-  // fn func(p: ptr<function, vec4<f32>>) -> f32 {
-  //     let idx: u32 = u32();
-  //     let x: f32 = *p[idx];
-  //     return x;
-  // }
-  auto* p =
-      Param("p", ty.pointer(ty.vec4<f32>(), ast::StorageClass::kFunction));
-  auto* idx = Const("idx", ty.u32(), Construct(ty.u32()));
-  auto* accessor_expr = IndexAccessor(Source{{12, 34}}, p, idx);
-  auto* star_p = Deref(accessor_expr);
-  auto* x = Var("x", ty.f32(), star_p);
-  Func("func", {p}, ty.f32(), {Decl(idx), Decl(x), Return(x)});
+    // fn func(p: ptr<function, vec4<f32>>) -> f32 {
+    //     let idx: u32 = u32();
+    //     let x: f32 = *p[idx];
+    //     return x;
+    // }
+    auto* p = Param("p", ty.pointer(ty.vec4<f32>(), ast::StorageClass::kFunction));
+    auto* idx = Let("idx", ty.u32(), Construct(ty.u32()));
+    auto* accessor_expr = IndexAccessor(Source{{12, 34}}, p, idx);
+    auto* star_p = Deref(accessor_expr);
+    auto* x = Var("x", ty.f32(), star_p);
+    Func("func", {p}, ty.f32(), {Decl(idx), Decl(x), Return(x)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: cannot index type 'ptr<function, vec4<f32>, read_write>'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: cannot index type 'ptr<function, vec4<f32>, read_write>'");
 }
 
 TEST_F(ResolverIndexAccessorTest, Exr_Deref_BadParent) {
-  // var param: vec4<f32>
-  // let x: f32 = *(&param)[0];
-  auto* param = Var("param", ty.vec4<f32>());
-  auto* idx = Var("idx", ty.u32(), Construct(ty.u32()));
-  auto* addressOf_expr = AddressOf(param);
-  auto* accessor_expr = IndexAccessor(Source{{12, 34}}, addressOf_expr, idx);
-  auto* star_p = Deref(accessor_expr);
-  auto* x = Var("x", ty.f32(), star_p);
-  WrapInFunction(param, idx, x);
+    // var param: vec4<f32>
+    // let x: f32 = *(&param)[0];
+    auto* param = Var("param", ty.vec4<f32>());
+    auto* idx = Var("idx", ty.u32(), Construct(ty.u32()));
+    auto* addressOf_expr = AddressOf(param);
+    auto* accessor_expr = IndexAccessor(Source{{12, 34}}, addressOf_expr, idx);
+    auto* star_p = Deref(accessor_expr);
+    auto* x = Var("x", ty.f32(), star_p);
+    WrapInFunction(param, idx, x);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: cannot index type 'ptr<function, vec4<f32>, read_write>'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: cannot index type 'ptr<function, vec4<f32>, read_write>'");
 }
 
 }  // namespace
diff --git a/src/tint/resolver/assignment_validation_test.cc b/src/tint/resolver/assignment_validation_test.cc
index cc2519a..f12f804 100644
--- a/src/tint/resolver/assignment_validation_test.cc
+++ b/src/tint/resolver/assignment_validation_test.cc
@@ -16,7 +16,9 @@
 
 #include "gmock/gmock.h"
 #include "src/tint/resolver/resolver_test_helper.h"
-#include "src/tint/sem/storage_texture_type.h"
+#include "src/tint/sem/storage_texture.h"
+
+using namespace tint::number_suffixes;  // NOLINT
 
 namespace tint::resolver {
 namespace {
@@ -24,367 +26,346 @@
 using ResolverAssignmentValidationTest = ResolverTest;
 
 TEST_F(ResolverAssignmentValidationTest, ReadOnlyBuffer) {
-  // struct S { m : i32 };
-  // @group(0) @binding(0)
-  // var<storage,read> a : S;
-  auto* s = Structure("S", {Member("m", ty.i32())});
-  Global(Source{{12, 34}}, "a", ty.Of(s), ast::StorageClass::kStorage,
-         ast::Access::kRead,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    // struct S { m : i32 };
+    // @group(0) @binding(0)
+    // var<storage,read> a : S;
+    auto* s = Structure("S", {Member("m", ty.i32())});
+    Global(Source{{12, 34}}, "a", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  WrapInFunction(Assign(Source{{56, 78}}, MemberAccessor("a", "m"), 1));
+    WrapInFunction(Assign(Source{{56, 78}}, MemberAccessor("a", "m"), 1_i));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "56:78 error: cannot store into a read-only type 'ref<storage, "
-            "i32, read>'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "56:78 error: cannot store into a read-only type 'ref<storage, "
+              "i32, read>'");
 }
 
 TEST_F(ResolverAssignmentValidationTest, AssignIncompatibleTypes) {
-  // {
-  //  var a : i32 = 2;
-  //  a = 2.3;
-  // }
+    // {
+    //  var a : i32 = 2i;
+    //  a = 2.3;
+    // }
 
-  auto* var = Var("a", ty.i32(), ast::StorageClass::kNone, Expr(2));
+    auto* var = Var("a", ty.i32(), ast::StorageClass::kNone, Expr(2_i));
 
-  auto* assign = Assign(Source{{12, 34}}, "a", 2.3f);
-  WrapInFunction(var, assign);
+    auto* assign = Assign(Source{{12, 34}}, "a", 2.3f);
+    WrapInFunction(var, assign);
 
-  ASSERT_FALSE(r()->Resolve());
+    ASSERT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(r()->error(), "12:34 error: cannot assign 'f32' to 'i32'");
+    EXPECT_EQ(r()->error(), "12:34 error: cannot assign 'f32' to 'i32'");
 }
 
-TEST_F(ResolverAssignmentValidationTest,
-       AssignArraysWithDifferentSizeExpressions_Pass) {
-  // let len = 4u;
-  // {
-  //   var a : array<f32, 4>;
-  //   var b : array<f32, len>;
-  //   a = b;
-  // }
+TEST_F(ResolverAssignmentValidationTest, AssignArraysWithDifferentSizeExpressions_Pass) {
+    // let len = 4u;
+    // {
+    //   var a : array<f32, 4u>;
+    //   var b : array<f32, len>;
+    //   a = b;
+    // }
 
-  GlobalConst("len", nullptr, Expr(4u));
+    GlobalConst("len", nullptr, Expr(4_u));
 
-  auto* a = Var("a", ty.array(ty.f32(), 4));
-  auto* b = Var("b", ty.array(ty.f32(), "len"));
+    auto* a = Var("a", ty.array(ty.f32(), 4_u));
+    auto* b = Var("b", ty.array(ty.f32(), "len"));
 
-  auto* assign = Assign(Source{{12, 34}}, "a", "b");
-  WrapInFunction(a, b, assign);
+    auto* assign = Assign(Source{{12, 34}}, "a", "b");
+    WrapInFunction(a, b, assign);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
-TEST_F(ResolverAssignmentValidationTest,
-       AssignArraysWithDifferentSizeExpressions_Fail) {
-  // let len = 5u;
-  // {
-  //   var a : array<f32, 4>;
-  //   var b : array<f32, len>;
-  //   a = b;
-  // }
+TEST_F(ResolverAssignmentValidationTest, AssignArraysWithDifferentSizeExpressions_Fail) {
+    // let len = 5u;
+    // {
+    //   var a : array<f32, 4u>;
+    //   var b : array<f32, len>;
+    //   a = b;
+    // }
 
-  GlobalConst("len", nullptr, Expr(5u));
+    GlobalConst("len", nullptr, Expr(5_u));
 
-  auto* a = Var("a", ty.array(ty.f32(), 4));
-  auto* b = Var("b", ty.array(ty.f32(), "len"));
+    auto* a = Var("a", ty.array(ty.f32(), 4_u));
+    auto* b = Var("b", ty.array(ty.f32(), "len"));
 
-  auto* assign = Assign(Source{{12, 34}}, "a", "b");
-  WrapInFunction(a, b, assign);
+    auto* assign = Assign(Source{{12, 34}}, "a", "b");
+    WrapInFunction(a, b, assign);
 
-  ASSERT_FALSE(r()->Resolve());
+    ASSERT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(r()->error(),
-            "12:34 error: cannot assign 'array<f32, 5>' to 'array<f32, 4>'");
+    EXPECT_EQ(r()->error(), "12:34 error: cannot assign 'array<f32, 5>' to 'array<f32, 4>'");
 }
 
-TEST_F(ResolverAssignmentValidationTest,
-       AssignCompatibleTypesInBlockStatement_Pass) {
-  // {
-  //  var a : i32 = 2;
-  //  a = 2
-  // }
-  auto* var = Var("a", ty.i32(), ast::StorageClass::kNone, Expr(2));
-  WrapInFunction(var, Assign("a", 2));
+TEST_F(ResolverAssignmentValidationTest, AssignCompatibleTypesInBlockStatement_Pass) {
+    // {
+    //  var a : i32 = 2i;
+    //  a = 2i
+    // }
+    auto* var = Var("a", ty.i32(), ast::StorageClass::kNone, Expr(2_i));
+    WrapInFunction(var, Assign("a", 2_i));
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
-TEST_F(ResolverAssignmentValidationTest,
-       AssignIncompatibleTypesInBlockStatement_Fail) {
-  // {
-  //  var a : i32 = 2;
-  //  a = 2.3;
-  // }
+TEST_F(ResolverAssignmentValidationTest, AssignIncompatibleTypesInBlockStatement_Fail) {
+    // {
+    //  var a : i32 = 2i;
+    //  a = 2.3;
+    // }
 
-  auto* var = Var("a", ty.i32(), ast::StorageClass::kNone, Expr(2));
-  WrapInFunction(var, Assign(Source{{12, 34}}, "a", 2.3f));
+    auto* var = Var("a", ty.i32(), ast::StorageClass::kNone, Expr(2_i));
+    WrapInFunction(var, Assign(Source{{12, 34}}, "a", 2.3f));
 
-  ASSERT_FALSE(r()->Resolve());
+    ASSERT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(r()->error(), "12:34 error: cannot assign 'f32' to 'i32'");
+    EXPECT_EQ(r()->error(), "12:34 error: cannot assign 'f32' to 'i32'");
 }
 
-TEST_F(ResolverAssignmentValidationTest,
-       AssignIncompatibleTypesInNestedBlockStatement_Fail) {
-  // {
-  //  {
-  //   var a : i32 = 2;
-  //   a = 2.3;
-  //  }
-  // }
+TEST_F(ResolverAssignmentValidationTest, AssignIncompatibleTypesInNestedBlockStatement_Fail) {
+    // {
+    //  {
+    //   var a : i32 = 2i;
+    //   a = 2.3;
+    //  }
+    // }
 
-  auto* var = Var("a", ty.i32(), ast::StorageClass::kNone, Expr(2));
-  auto* inner_block = Block(Decl(var), Assign(Source{{12, 34}}, "a", 2.3f));
-  auto* outer_block = Block(inner_block);
-  WrapInFunction(outer_block);
+    auto* var = Var("a", ty.i32(), ast::StorageClass::kNone, Expr(2_i));
+    auto* inner_block = Block(Decl(var), Assign(Source{{12, 34}}, "a", 2.3f));
+    auto* outer_block = Block(inner_block);
+    WrapInFunction(outer_block);
 
-  ASSERT_FALSE(r()->Resolve());
+    ASSERT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(r()->error(), "12:34 error: cannot assign 'f32' to 'i32'");
+    EXPECT_EQ(r()->error(), "12:34 error: cannot assign 'f32' to 'i32'");
 }
 
 TEST_F(ResolverAssignmentValidationTest, AssignToScalar_Fail) {
-  // var my_var : i32 = 2;
-  // 1 = my_var;
+    // var my_var : i32 = 2i;
+    // 1 = my_var;
 
-  auto* var = Var("my_var", ty.i32(), ast::StorageClass::kNone, Expr(2));
-  WrapInFunction(var, Assign(Expr(Source{{12, 34}}, 1), "my_var"));
+    auto* var = Var("my_var", ty.i32(), ast::StorageClass::kNone, Expr(2_i));
+    WrapInFunction(var, Assign(Expr(Source{{12, 34}}, 1_i), "my_var"));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: cannot assign to value of type 'i32'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: cannot assign to value of type 'i32'");
 }
 
 TEST_F(ResolverAssignmentValidationTest, AssignCompatibleTypes_Pass) {
-  // var a : i32 = 2;
-  // a = 2
-  auto* var = Var("a", ty.i32(), ast::StorageClass::kNone, Expr(2));
-  WrapInFunction(var, Assign(Source{{12, 34}}, "a", 2));
+    // var a : i32 = 2i;
+    // a = 2i
+    auto* var = Var("a", ty.i32(), ast::StorageClass::kNone, Expr(2_i));
+    WrapInFunction(var, Assign(Source{{12, 34}}, "a", 2_i));
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
-TEST_F(ResolverAssignmentValidationTest,
-       AssignCompatibleTypesThroughAlias_Pass) {
-  // alias myint = i32;
-  // var a : myint = 2;
-  // a = 2
-  auto* myint = Alias("myint", ty.i32());
-  auto* var = Var("a", ty.Of(myint), ast::StorageClass::kNone, Expr(2));
-  WrapInFunction(var, Assign(Source{{12, 34}}, "a", 2));
+TEST_F(ResolverAssignmentValidationTest, AssignCompatibleTypesThroughAlias_Pass) {
+    // alias myint = i32;
+    // var a : myint = 2i;
+    // a = 2
+    auto* myint = Alias("myint", ty.i32());
+    auto* var = Var("a", ty.Of(myint), ast::StorageClass::kNone, Expr(2_i));
+    WrapInFunction(var, Assign(Source{{12, 34}}, "a", 2_i));
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
-TEST_F(ResolverAssignmentValidationTest,
-       AssignCompatibleTypesInferRHSLoad_Pass) {
-  // var a : i32 = 2;
-  // var b : i32 = 3;
-  // a = b;
-  auto* var_a = Var("a", ty.i32(), ast::StorageClass::kNone, Expr(2));
-  auto* var_b = Var("b", ty.i32(), ast::StorageClass::kNone, Expr(3));
-  WrapInFunction(var_a, var_b, Assign(Source{{12, 34}}, "a", "b"));
+TEST_F(ResolverAssignmentValidationTest, AssignCompatibleTypesInferRHSLoad_Pass) {
+    // var a : i32 = 2i;
+    // var b : i32 = 3i;
+    // a = b;
+    auto* var_a = Var("a", ty.i32(), ast::StorageClass::kNone, Expr(2_i));
+    auto* var_b = Var("b", ty.i32(), ast::StorageClass::kNone, Expr(3_i));
+    WrapInFunction(var_a, var_b, Assign(Source{{12, 34}}, "a", "b"));
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverAssignmentValidationTest, AssignThroughPointer_Pass) {
-  // var a : i32;
-  // let b : ptr<function,i32> = &a;
-  // *b = 2;
-  const auto func = ast::StorageClass::kFunction;
-  auto* var_a = Var("a", ty.i32(), func, Expr(2));
-  auto* var_b = Const("b", ty.pointer<int>(func), AddressOf(Expr("a")));
-  WrapInFunction(var_a, var_b, Assign(Source{{12, 34}}, Deref("b"), 2));
+    // var a : i32;
+    // let b : ptr<function,i32> = &a;
+    // *b = 2i;
+    const auto func = ast::StorageClass::kFunction;
+    auto* var_a = Var("a", ty.i32(), func, Expr(2_i));
+    auto* var_b = Let("b", ty.pointer<i32>(func), AddressOf(Expr("a")));
+    WrapInFunction(var_a, var_b, Assign(Source{{12, 34}}, Deref("b"), 2_i));
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverAssignmentValidationTest, AssignToConstant_Fail) {
-  // {
-  //  let a : i32 = 2;
-  //  a = 2
-  // }
-  auto* var = Const("a", ty.i32(), Expr(2));
-  WrapInFunction(var, Assign(Expr(Source{{12, 34}}, "a"), 2));
+    // {
+    //  let a : i32 = 2i;
+    //  a = 2i
+    // }
+    auto* var = Let("a", ty.i32(), Expr(2_i));
+    WrapInFunction(var, Assign(Expr(Source{{12, 34}}, "a"), 2_i));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: cannot assign to const\nnote: 'a' is declared here:");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: cannot assign to const\nnote: 'a' is declared here:");
 }
 
 TEST_F(ResolverAssignmentValidationTest, AssignNonConstructible_Handle) {
-  // var a : texture_storage_1d<rgba8unorm, write>;
-  // var b : texture_storage_1d<rgba8unorm, write>;
-  // a = b;
+    // var a : texture_storage_1d<rgba8unorm, write>;
+    // var b : texture_storage_1d<rgba8unorm, write>;
+    // a = b;
 
-  auto make_type = [&] {
-    return ty.storage_texture(ast::TextureDimension::k1d,
-                              ast::TexelFormat::kRgba8Unorm,
-                              ast::Access::kWrite);
-  };
+    auto make_type = [&] {
+        return ty.storage_texture(ast::TextureDimension::k1d, ast::TexelFormat::kRgba8Unorm,
+                                  ast::Access::kWrite);
+    };
 
-  Global("a", make_type(), ast::StorageClass::kNone,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
-  Global("b", make_type(), ast::StorageClass::kNone,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(1),
-             create<ast::GroupAttribute>(0),
-         });
+    Global("a", make_type(), ast::StorageClass::kNone,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
+    Global("b", make_type(), ast::StorageClass::kNone,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(1),
+               create<ast::GroupAttribute>(0),
+           });
 
-  WrapInFunction(Assign(Source{{56, 78}}, "a", "b"));
+    WrapInFunction(Assign(Source{{56, 78}}, "a", "b"));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "56:78 error: storage type of assignment must be constructible");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "56:78 error: storage type of assignment must be constructible");
 }
 
 TEST_F(ResolverAssignmentValidationTest, AssignNonConstructible_Atomic) {
-  // struct S { a : atomic<i32>; };
-  // @group(0) @binding(0) var<storage, read_write> v : S;
-  // v.a = v.a;
+    // struct S { a : atomic<i32>; };
+    // @group(0) @binding(0) var<storage, read_write> v : S;
+    // v.a = v.a;
 
-  auto* s = Structure("S", {Member("a", ty.atomic(ty.i32()))});
-  Global(Source{{12, 34}}, "v", ty.Of(s), ast::StorageClass::kStorage,
-         ast::Access::kReadWrite,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    auto* s = Structure("S", {Member("a", ty.atomic(ty.i32()))});
+    Global(Source{{12, 34}}, "v", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  WrapInFunction(Assign(Source{{56, 78}}, MemberAccessor("v", "a"),
-                        MemberAccessor("v", "a")));
+    WrapInFunction(Assign(Source{{56, 78}}, MemberAccessor("v", "a"), MemberAccessor("v", "a")));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "56:78 error: storage type of assignment must be constructible");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "56:78 error: storage type of assignment must be constructible");
 }
 
 TEST_F(ResolverAssignmentValidationTest, AssignNonConstructible_RuntimeArray) {
-  // struct S { a : array<f32>; };
-  // @group(0) @binding(0) var<storage, read_write> v : S;
-  // v.a = v.a;
+    // struct S { a : array<f32>; };
+    // @group(0) @binding(0) var<storage, read_write> v : S;
+    // v.a = v.a;
 
-  auto* s = Structure("S", {Member("a", ty.array(ty.f32()))});
-  Global(Source{{12, 34}}, "v", ty.Of(s), ast::StorageClass::kStorage,
-         ast::Access::kReadWrite,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    auto* s = Structure("S", {Member("a", ty.array(ty.f32()))});
+    Global(Source{{12, 34}}, "v", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  WrapInFunction(Assign(Source{{56, 78}}, MemberAccessor("v", "a"),
-                        MemberAccessor("v", "a")));
+    WrapInFunction(Assign(Source{{56, 78}}, MemberAccessor("v", "a"), MemberAccessor("v", "a")));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "56:78 error: storage type of assignment must be constructible");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "56:78 error: storage type of assignment must be constructible");
 }
 
-TEST_F(ResolverAssignmentValidationTest,
-       AssignToPhony_NonConstructibleStruct_Fail) {
-  // struct S {
-  //   arr: array<i32>;
-  // };
-  // @group(0) @binding(0) var<storage, read_write> s : S;
-  // fn f() {
-  //   _ = s;
-  // }
-  auto* s = Structure("S", {Member("arr", ty.array<i32>())});
-  Global("s", ty.Of(s), ast::StorageClass::kStorage, GroupAndBinding(0, 0));
+TEST_F(ResolverAssignmentValidationTest, AssignToPhony_NonConstructibleStruct_Fail) {
+    // struct S {
+    //   arr: array<i32>;
+    // };
+    // @group(0) @binding(0) var<storage, read_write> s : S;
+    // fn f() {
+    //   _ = s;
+    // }
+    auto* s = Structure("S", {Member("arr", ty.array<i32>())});
+    Global("s", ty.Of(s), ast::StorageClass::kStorage, GroupAndBinding(0, 0));
 
-  WrapInFunction(Assign(Phony(), Expr(Source{{12, 34}}, "s")));
+    WrapInFunction(Assign(Phony(), Expr(Source{{12, 34}}, "s")));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: cannot assign 'S' to '_'. "
-            "'_' can only be assigned a constructible, pointer, texture or "
-            "sampler type");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: cannot assign 'S' to '_'. "
+              "'_' can only be assigned a constructible, pointer, texture or "
+              "sampler type");
 }
 
 TEST_F(ResolverAssignmentValidationTest, AssignToPhony_DynamicArray_Fail) {
-  // struct S {
-  //   arr: array<i32>;
-  // };
-  // @group(0) @binding(0) var<storage, read_write> s : S;
-  // fn f() {
-  //   _ = s.arr;
-  // }
-  auto* s = Structure("S", {Member("arr", ty.array<i32>())});
-  Global("s", ty.Of(s), ast::StorageClass::kStorage, GroupAndBinding(0, 0));
+    // struct S {
+    //   arr: array<i32>;
+    // };
+    // @group(0) @binding(0) var<storage, read_write> s : S;
+    // fn f() {
+    //   _ = s.arr;
+    // }
+    auto* s = Structure("S", {Member("arr", ty.array<i32>())});
+    Global("s", ty.Of(s), ast::StorageClass::kStorage, GroupAndBinding(0, 0));
 
-  WrapInFunction(Assign(Phony(), MemberAccessor(Source{{12, 34}}, "s", "arr")));
+    WrapInFunction(Assign(Phony(), MemberAccessor(Source{{12, 34}}, "s", "arr")));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: cannot assign 'array<i32>' to '_'. "
-      "'_' can only be assigned a constructible, pointer, texture or sampler "
-      "type");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: cannot assign 'array<i32>' to '_'. "
+              "'_' can only be assigned a constructible, pointer, texture or sampler "
+              "type");
 }
 
 TEST_F(ResolverAssignmentValidationTest, AssignToPhony_Pass) {
-  // struct S {
-  //   i:   i32;
-  //   arr: array<i32>;
-  // };
-  // struct U {
-  //   i:   i32;
-  // };
-  // @group(0) @binding(0) var tex texture_2d;
-  // @group(0) @binding(1) var smp sampler;
-  // @group(0) @binding(2) var<uniform> u : U;
-  // @group(0) @binding(3) var<storage, read_write> s : S;
-  // var<workgroup> wg : array<f32, 10>
-  // fn f() {
-  //   _ = 1;
-  //   _ = 2u;
-  //   _ = 3.0;
-  //   _ = vec2<bool>();
-  //   _ = tex;
-  //   _ = smp;
-  //   _ = &s;
-  //   _ = s.i;
-  //   _ = &s.arr;
-  //   _ = u;
-  //   _ = u.i;
-  //   _ = wg;
-  //   _ = wg[3];
-  // }
-  auto* S = Structure("S", {
-                               Member("i", ty.i32()),
-                               Member("arr", ty.array<i32>()),
-                           });
-  auto* U = Structure("U", {Member("i", ty.i32())});
-  Global("tex", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
-         GroupAndBinding(0, 0));
-  Global("smp", ty.sampler(ast::SamplerKind::kSampler), GroupAndBinding(0, 1));
-  Global("u", ty.Of(U), ast::StorageClass::kUniform, GroupAndBinding(0, 2));
-  Global("s", ty.Of(S), ast::StorageClass::kStorage, GroupAndBinding(0, 3));
-  Global("wg", ty.array<f32, 10>(), ast::StorageClass::kWorkgroup);
+    // struct S {
+    //   i:   i32;
+    //   arr: array<i32>;
+    // };
+    // struct U {
+    //   i:   i32;
+    // };
+    // @group(0) @binding(0) var tex texture_2d;
+    // @group(0) @binding(1) var smp sampler;
+    // @group(0) @binding(2) var<uniform> u : U;
+    // @group(0) @binding(3) var<storage, read_write> s : S;
+    // var<workgroup> wg : array<f32, 10>
+    // fn f() {
+    //   _ = 1i;
+    //   _ = 2u;
+    //   _ = 3.0;
+    //   _ = vec2<bool>();
+    //   _ = tex;
+    //   _ = smp;
+    //   _ = &s;
+    //   _ = s.i;
+    //   _ = &s.arr;
+    //   _ = u;
+    //   _ = u.i;
+    //   _ = wg;
+    //   _ = wg[3i];
+    // }
+    auto* S = Structure("S", {
+                                 Member("i", ty.i32()),
+                                 Member("arr", ty.array<i32>()),
+                             });
+    auto* U = Structure("U", {Member("i", ty.i32())});
+    Global("tex", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()), GroupAndBinding(0, 0));
+    Global("smp", ty.sampler(ast::SamplerKind::kSampler), GroupAndBinding(0, 1));
+    Global("u", ty.Of(U), ast::StorageClass::kUniform, GroupAndBinding(0, 2));
+    Global("s", ty.Of(S), ast::StorageClass::kStorage, GroupAndBinding(0, 3));
+    Global("wg", ty.array<f32, 10>(), ast::StorageClass::kWorkgroup);
 
-  WrapInFunction(Assign(Phony(), 1),                                      //
-                 Assign(Phony(), 2),                                      //
-                 Assign(Phony(), 3),                                      //
-                 Assign(Phony(), vec2<bool>()),                           //
-                 Assign(Phony(), "tex"),                                  //
-                 Assign(Phony(), "smp"),                                  //
-                 Assign(Phony(), AddressOf("s")),                         //
-                 Assign(Phony(), MemberAccessor("s", "i")),               //
-                 Assign(Phony(), AddressOf(MemberAccessor("s", "arr"))),  //
-                 Assign(Phony(), "u"),                                    //
-                 Assign(Phony(), MemberAccessor("u", "i")),               //
-                 Assign(Phony(), "wg"),                                   //
-                 Assign(Phony(), IndexAccessor("wg", 3)));
+    WrapInFunction(Assign(Phony(), 1_i),                                    //
+                   Assign(Phony(), 2_u),                                    //
+                   Assign(Phony(), 3.f),                                    //
+                   Assign(Phony(), vec2<bool>()),                           //
+                   Assign(Phony(), "tex"),                                  //
+                   Assign(Phony(), "smp"),                                  //
+                   Assign(Phony(), AddressOf("s")),                         //
+                   Assign(Phony(), MemberAccessor("s", "i")),               //
+                   Assign(Phony(), AddressOf(MemberAccessor("s", "arr"))),  //
+                   Assign(Phony(), "u"),                                    //
+                   Assign(Phony(), MemberAccessor("u", "i")),               //
+                   Assign(Phony(), "wg"),                                   //
+                   Assign(Phony(), IndexAccessor("wg", 3_i)));
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 }  // namespace
diff --git a/src/tint/resolver/atomics_test.cc b/src/tint/resolver/atomics_test.cc
index 02f800d..c0fe5ce 100644
--- a/src/tint/resolver/atomics_test.cc
+++ b/src/tint/resolver/atomics_test.cc
@@ -14,57 +14,52 @@
 
 #include "src/tint/resolver/resolver.h"
 #include "src/tint/resolver/resolver_test_helper.h"
-#include "src/tint/sem/atomic_type.h"
-#include "src/tint/sem/reference_type.h"
+#include "src/tint/sem/atomic.h"
+#include "src/tint/sem/reference.h"
 
 #include "gmock/gmock.h"
 
 namespace tint::resolver {
 namespace {
 
-struct ResolverAtomicTest : public resolver::TestHelper,
-                            public testing::Test {};
+struct ResolverAtomicTest : public resolver::TestHelper, public testing::Test {};
 
 TEST_F(ResolverAtomicTest, GlobalWorkgroupI32) {
-  auto* g = Global("a", ty.atomic(Source{{12, 34}}, ty.i32()),
-                   ast::StorageClass::kWorkgroup);
+    auto* g = Global("a", ty.atomic(Source{{12, 34}}, ty.i32()), ast::StorageClass::kWorkgroup);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  ASSERT_TRUE(TypeOf(g)->Is<sem::Reference>());
-  auto* atomic = TypeOf(g)->UnwrapRef()->As<sem::Atomic>();
-  ASSERT_NE(atomic, nullptr);
-  EXPECT_TRUE(atomic->Type()->Is<sem::I32>());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(TypeOf(g)->Is<sem::Reference>());
+    auto* atomic = TypeOf(g)->UnwrapRef()->As<sem::Atomic>();
+    ASSERT_NE(atomic, nullptr);
+    EXPECT_TRUE(atomic->Type()->Is<sem::I32>());
 }
 
 TEST_F(ResolverAtomicTest, GlobalWorkgroupU32) {
-  auto* g = Global("a", ty.atomic(Source{{12, 34}}, ty.u32()),
-                   ast::StorageClass::kWorkgroup);
+    auto* g = Global("a", ty.atomic(Source{{12, 34}}, ty.u32()), ast::StorageClass::kWorkgroup);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  ASSERT_TRUE(TypeOf(g)->Is<sem::Reference>());
-  auto* atomic = TypeOf(g)->UnwrapRef()->As<sem::Atomic>();
-  ASSERT_NE(atomic, nullptr);
-  EXPECT_TRUE(atomic->Type()->Is<sem::U32>());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(TypeOf(g)->Is<sem::Reference>());
+    auto* atomic = TypeOf(g)->UnwrapRef()->As<sem::Atomic>();
+    ASSERT_NE(atomic, nullptr);
+    EXPECT_TRUE(atomic->Type()->Is<sem::U32>());
 }
 
 TEST_F(ResolverAtomicTest, GlobalStorageStruct) {
-  auto* s =
-      Structure("s", {Member("a", ty.atomic(Source{{12, 34}}, ty.i32()))});
-  auto* g = Global("g", ty.Of(s), ast::StorageClass::kStorage,
-                   ast::Access::kReadWrite,
-                   ast::AttributeList{
-                       create<ast::BindingAttribute>(0),
-                       create<ast::GroupAttribute>(0),
-                   });
+    auto* s = Structure("s", {Member("a", ty.atomic(Source{{12, 34}}, ty.i32()))});
+    auto* g = Global("g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+                     ast::AttributeList{
+                         create<ast::BindingAttribute>(0),
+                         create<ast::GroupAttribute>(0),
+                     });
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  ASSERT_TRUE(TypeOf(g)->Is<sem::Reference>());
-  auto* str = TypeOf(g)->UnwrapRef()->As<sem::Struct>();
-  ASSERT_NE(str, nullptr);
-  ASSERT_EQ(str->Members().size(), 1u);
-  auto* atomic = str->Members()[0]->Type()->As<sem::Atomic>();
-  ASSERT_NE(atomic, nullptr);
-  ASSERT_TRUE(atomic->Type()->Is<sem::I32>());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(TypeOf(g)->Is<sem::Reference>());
+    auto* str = TypeOf(g)->UnwrapRef()->As<sem::Struct>();
+    ASSERT_NE(str, nullptr);
+    ASSERT_EQ(str->Members().size(), 1u);
+    auto* atomic = str->Members()[0]->Type()->As<sem::Atomic>();
+    ASSERT_NE(atomic, nullptr);
+    ASSERT_TRUE(atomic->Type()->Is<sem::I32>());
 }
 
 }  // namespace
diff --git a/src/tint/resolver/atomics_validation_test.cc b/src/tint/resolver/atomics_validation_test.cc
index 5e9668f..78c1fb9 100644
--- a/src/tint/resolver/atomics_validation_test.cc
+++ b/src/tint/resolver/atomics_validation_test.cc
@@ -14,322 +14,302 @@
 
 #include "src/tint/resolver/resolver.h"
 #include "src/tint/resolver/resolver_test_helper.h"
-#include "src/tint/sem/atomic_type.h"
-#include "src/tint/sem/reference_type.h"
+#include "src/tint/sem/atomic.h"
+#include "src/tint/sem/reference.h"
 
 #include "gmock/gmock.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::resolver {
 namespace {
 
-struct ResolverAtomicValidationTest : public resolver::TestHelper,
-                                      public testing::Test {};
+struct ResolverAtomicValidationTest : public resolver::TestHelper, public testing::Test {};
 
 TEST_F(ResolverAtomicValidationTest, StorageClass_WorkGroup) {
-  Global("a", ty.atomic(Source{{12, 34}}, ty.i32()),
-         ast::StorageClass::kWorkgroup);
+    Global("a", ty.atomic(Source{{12, 34}}, ty.i32()), ast::StorageClass::kWorkgroup);
 
-  EXPECT_TRUE(r()->Resolve());
+    EXPECT_TRUE(r()->Resolve());
 }
 
 TEST_F(ResolverAtomicValidationTest, StorageClass_Storage) {
-  Global("g", ty.atomic(Source{{12, 34}}, ty.i32()),
-         ast::StorageClass::kStorage, ast::Access::kReadWrite,
-         GroupAndBinding(0, 0));
+    Global("g", ty.atomic(Source{{12, 34}}, ty.i32()), ast::StorageClass::kStorage,
+           ast::Access::kReadWrite, GroupAndBinding(0, 0));
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverAtomicValidationTest, StorageClass_Storage_Struct) {
-  auto* s =
-      Structure("s", {Member("a", ty.atomic(Source{{12, 34}}, ty.i32()))});
-  Global("g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
-         GroupAndBinding(0, 0));
+    auto* s = Structure("s", {Member("a", ty.atomic(Source{{12, 34}}, ty.i32()))});
+    Global("g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+           GroupAndBinding(0, 0));
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverAtomicValidationTest, InvalidType) {
-  Global("a", ty.atomic(ty.f32(Source{{12, 34}})),
-         ast::StorageClass::kWorkgroup);
+    Global("a", ty.atomic(ty.f32(Source{{12, 34}})), ast::StorageClass::kWorkgroup);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: atomic only supports i32 or u32 types");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: atomic only supports i32 or u32 types");
 }
 
 TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_Simple) {
-  Global("a", ty.atomic(Source{{12, 34}}, ty.i32()),
-         ast::StorageClass::kPrivate);
+    Global("a", ty.atomic(Source{{12, 34}}, ty.i32()), ast::StorageClass::kPrivate);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: atomic variables must have <storage> or <workgroup> "
-            "storage class");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: atomic variables must have <storage> or <workgroup> "
+              "storage class");
 }
 
 TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_Array) {
-  Global("a", ty.atomic(Source{{12, 34}}, ty.i32()),
-         ast::StorageClass::kPrivate);
+    Global("a", ty.atomic(Source{{12, 34}}, ty.i32()), ast::StorageClass::kPrivate);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: atomic variables must have <storage> or <workgroup> "
-            "storage class");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: atomic variables must have <storage> or <workgroup> "
+              "storage class");
 }
 
 TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_Struct) {
-  auto* s =
-      Structure("s", {Member("a", ty.atomic(Source{{12, 34}}, ty.i32()))});
-  Global("g", ty.Of(s), ast::StorageClass::kPrivate);
+    auto* s = Structure("s", {Member("a", ty.atomic(Source{{12, 34}}, ty.i32()))});
+    Global("g", ty.Of(s), ast::StorageClass::kPrivate);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "error: atomic variables must have <storage> or <workgroup> "
-            "storage class\n"
-            "note: atomic sub-type of 's' is declared here");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "error: atomic variables must have <storage> or <workgroup> "
+              "storage class\n"
+              "note: atomic sub-type of 's' is declared here");
 }
 
 TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_StructOfStruct) {
-  // struct Inner { m : atomic<i32>; };
-  // struct Outer { m : array<Inner, 4>; };
-  // var<private> g : Outer;
+    // struct Inner { m : atomic<i32>; };
+    // struct Outer { m : array<Inner, 4>; };
+    // var<private> g : Outer;
 
-  auto* Inner =
-      Structure("Inner", {Member("m", ty.atomic(Source{{12, 34}}, ty.i32()))});
-  auto* Outer = Structure("Outer", {Member("m", ty.Of(Inner))});
-  Global("g", ty.Of(Outer), ast::StorageClass::kPrivate);
+    auto* Inner = Structure("Inner", {Member("m", ty.atomic(Source{{12, 34}}, ty.i32()))});
+    auto* Outer = Structure("Outer", {Member("m", ty.Of(Inner))});
+    Global("g", ty.Of(Outer), ast::StorageClass::kPrivate);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "error: atomic variables must have <storage> or <workgroup> "
-            "storage class\n"
-            "note: atomic sub-type of 'Outer' is declared here");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "error: atomic variables must have <storage> or <workgroup> "
+              "storage class\n"
+              "note: atomic sub-type of 'Outer' is declared here");
 }
 
-TEST_F(ResolverAtomicValidationTest,
-       InvalidStorageClass_StructOfStructOfArray) {
-  // struct Inner { m : array<atomic<i32>, 4>; };
-  // struct Outer { m : array<Inner, 4>; };
-  // var<private> g : Outer;
+TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_StructOfStructOfArray) {
+    // struct Inner { m : array<atomic<i32>, 4>; };
+    // struct Outer { m : array<Inner, 4>; };
+    // var<private> g : Outer;
 
-  auto* Inner =
-      Structure("Inner", {Member(Source{{12, 34}}, "m", ty.atomic(ty.i32()))});
-  auto* Outer = Structure("Outer", {Member("m", ty.Of(Inner))});
-  Global("g", ty.Of(Outer), ast::StorageClass::kPrivate);
+    auto* Inner = Structure("Inner", {Member(Source{{12, 34}}, "m", ty.atomic(ty.i32()))});
+    auto* Outer = Structure("Outer", {Member("m", ty.Of(Inner))});
+    Global("g", ty.Of(Outer), ast::StorageClass::kPrivate);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "error: atomic variables must have <storage> or <workgroup> "
-            "storage class\n"
-            "12:34 note: atomic sub-type of 'Outer' is declared here");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "error: atomic variables must have <storage> or <workgroup> "
+              "storage class\n"
+              "12:34 note: atomic sub-type of 'Outer' is declared here");
 }
 
 TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_ArrayOfArray) {
-  // type AtomicArray = array<atomic<i32>, 5>;
-  // var<private> v: array<s, 5>;
+    // type AtomicArray = array<atomic<i32>, 5>;
+    // var<private> v: array<s, 5>;
 
-  auto* atomic_array = Alias(Source{{12, 34}}, "AtomicArray",
-                             ty.atomic(Source{{12, 34}}, ty.i32()));
-  Global(Source{{56, 78}}, "v", ty.Of(atomic_array),
-         ast::StorageClass::kPrivate);
+    auto* atomic_array =
+        Alias(Source{{12, 34}}, "AtomicArray", ty.atomic(Source{{12, 34}}, ty.i32()));
+    Global(Source{{56, 78}}, "v", ty.Of(atomic_array), ast::StorageClass::kPrivate);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "error: atomic variables must have <storage> or <workgroup> "
-            "storage class");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "error: atomic variables must have <storage> or <workgroup> "
+              "storage class");
 }
 
 TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_ArrayOfStruct) {
-  // struct S{
-  //   m: atomic<u32>;
-  // };
-  // var<private> v: array<S, 5>;
+    // struct S{
+    //   m: atomic<u32>;
+    // };
+    // var<private> v: array<S, 5u>;
 
-  auto* s = Structure("S", {Member("m", ty.atomic<u32>())});
-  Global(Source{{56, 78}}, "v", ty.array(ty.Of(s), 5),
-         ast::StorageClass::kPrivate);
+    auto* s = Structure("S", {Member("m", ty.atomic<u32>())});
+    Global(Source{{56, 78}}, "v", ty.array(ty.Of(s), 5_u), ast::StorageClass::kPrivate);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "error: atomic variables must have <storage> or <workgroup> "
-            "storage class\n"
-            "note: atomic sub-type of 'array<S, 5>' is declared here");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "error: atomic variables must have <storage> or <workgroup> "
+              "storage class\n"
+              "note: atomic sub-type of 'array<S, 5>' is declared here");
 }
 
 TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_ArrayOfStructOfArray) {
-  // type AtomicArray = array<atomic<i32>, 5>;
-  // struct S{
-  //   m: AtomicArray;
-  // };
-  // var<private> v: array<S, 5>;
+    // type AtomicArray = array<atomic<i32>, 5u>;
+    // struct S{
+    //   m: AtomicArray;
+    // };
+    // var<private> v: array<S, 5u>;
 
-  auto* atomic_array = Alias(Source{{12, 34}}, "AtomicArray",
-                             ty.atomic(Source{{12, 34}}, ty.i32()));
-  auto* s = Structure("S", {Member("m", ty.Of(atomic_array))});
-  Global(Source{{56, 78}}, "v", ty.array(ty.Of(s), 5),
-         ast::StorageClass::kPrivate);
+    auto* atomic_array =
+        Alias(Source{{12, 34}}, "AtomicArray", ty.atomic(Source{{12, 34}}, ty.i32()));
+    auto* s = Structure("S", {Member("m", ty.Of(atomic_array))});
+    Global(Source{{56, 78}}, "v", ty.array(ty.Of(s), 5_u), ast::StorageClass::kPrivate);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "error: atomic variables must have <storage> or <workgroup> "
-            "storage class\n"
-            "note: atomic sub-type of 'array<S, 5>' is declared here");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "error: atomic variables must have <storage> or <workgroup> "
+              "storage class\n"
+              "note: atomic sub-type of 'array<S, 5>' is declared here");
 }
 
 TEST_F(ResolverAtomicValidationTest, InvalidStorageClass_Complex) {
-  // type AtomicArray = array<atomic<i32>, 5>;
-  // struct S6 { x: array<i32, 4>; };
-  // struct S5 { x: S6;
-  //             y: AtomicArray;
-  //             z: array<atomic<u32>, 8>; };
-  // struct S4 { x: S6;
-  //             y: S5;
-  //             z: array<atomic<i32>, 4>; };
-  // struct S3 { x: S4; };
-  // struct S2 { x: S3; };
-  // struct S1 { x: S2; };
-  // struct S0 { x: S1; };
-  // var<private> g : S0;
+    // type AtomicArray = array<atomic<i32>, 5u>;
+    // struct S6 { x: array<i32, 4>; };
+    // struct S5 { x: S6;
+    //             y: AtomicArray;
+    //             z: array<atomic<u32>, 8u>; };
+    // struct S4 { x: S6;
+    //             y: S5;
+    //             z: array<atomic<i32>, 4u>; };
+    // struct S3 { x: S4; };
+    // struct S2 { x: S3; };
+    // struct S1 { x: S2; };
+    // struct S0 { x: S1; };
+    // var<private> g : S0;
 
-  auto* atomic_array = Alias(Source{{12, 34}}, "AtomicArray",
-                             ty.atomic(Source{{12, 34}}, ty.i32()));
-  auto* array_i32_4 = ty.array(ty.i32(), 4);
-  auto* array_atomic_u32_8 = ty.array(ty.atomic(ty.u32()), 8);
-  auto* array_atomic_i32_4 = ty.array(ty.atomic(ty.i32()), 4);
+    auto* atomic_array =
+        Alias(Source{{12, 34}}, "AtomicArray", ty.atomic(Source{{12, 34}}, ty.i32()));
+    auto* array_i32_4 = ty.array(ty.i32(), 4_u);
+    auto* array_atomic_u32_8 = ty.array(ty.atomic(ty.u32()), 8_u);
+    auto* array_atomic_i32_4 = ty.array(ty.atomic(ty.i32()), 4_u);
 
-  auto* s6 = Structure("S6", {Member("x", array_i32_4)});
-  auto* s5 = Structure("S5", {Member("x", ty.Of(s6)),             //
-                              Member("y", ty.Of(atomic_array)),   //
-                              Member("z", array_atomic_u32_8)});  //
-  auto* s4 = Structure("S4", {Member("x", ty.Of(s6)),             //
-                              Member("y", ty.Of(s5)),             //
-                              Member("z", array_atomic_i32_4)});  //
-  auto* s3 = Structure("S3", {Member("x", ty.Of(s4))});
-  auto* s2 = Structure("S2", {Member("x", ty.Of(s3))});
-  auto* s1 = Structure("S1", {Member("x", ty.Of(s2))});
-  auto* s0 = Structure("S0", {Member("x", ty.Of(s1))});
-  Global(Source{{56, 78}}, "g", ty.Of(s0), ast::StorageClass::kPrivate);
+    auto* s6 = Structure("S6", {Member("x", array_i32_4)});
+    auto* s5 = Structure("S5", {Member("x", ty.Of(s6)),             //
+                                Member("y", ty.Of(atomic_array)),   //
+                                Member("z", array_atomic_u32_8)});  //
+    auto* s4 = Structure("S4", {Member("x", ty.Of(s6)),             //
+                                Member("y", ty.Of(s5)),             //
+                                Member("z", array_atomic_i32_4)});  //
+    auto* s3 = Structure("S3", {Member("x", ty.Of(s4))});
+    auto* s2 = Structure("S2", {Member("x", ty.Of(s3))});
+    auto* s1 = Structure("S1", {Member("x", ty.Of(s2))});
+    auto* s0 = Structure("S0", {Member("x", ty.Of(s1))});
+    Global(Source{{56, 78}}, "g", ty.Of(s0), ast::StorageClass::kPrivate);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "error: atomic variables must have <storage> or <workgroup> "
-            "storage class\n"
-            "note: atomic sub-type of 'S0' is declared here");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "error: atomic variables must have <storage> or <workgroup> "
+              "storage class\n"
+              "note: atomic sub-type of 'S0' is declared here");
 }
 
 TEST_F(ResolverAtomicValidationTest, Struct_AccessMode_Read) {
-  auto* s =
-      Structure("s", {Member("a", ty.atomic(Source{{12, 34}}, ty.i32()))});
-  Global(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kStorage,
-         ast::Access::kRead, GroupAndBinding(0, 0));
+    auto* s = Structure("s", {Member("a", ty.atomic(Source{{12, 34}}, ty.i32()))});
+    Global(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+           GroupAndBinding(0, 0));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "error: atomic variables in <storage> storage class must have read_write "
-      "access mode\n"
-      "note: atomic sub-type of 's' is declared here");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "error: atomic variables in <storage> storage class must have read_write "
+              "access mode\n"
+              "note: atomic sub-type of 's' is declared here");
 }
 
 TEST_F(ResolverAtomicValidationTest, InvalidAccessMode_Struct) {
-  auto* s =
-      Structure("s", {Member("a", ty.atomic(Source{{12, 34}}, ty.i32()))});
-  Global(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kStorage,
-         ast::Access::kRead, GroupAndBinding(0, 0));
+    auto* s = Structure("s", {Member("a", ty.atomic(Source{{12, 34}}, ty.i32()))});
+    Global(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+           GroupAndBinding(0, 0));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "error: atomic variables in <storage> storage class must have read_write "
-      "access mode\n"
-      "note: atomic sub-type of 's' is declared here");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "error: atomic variables in <storage> storage class must have read_write "
+              "access mode\n"
+              "note: atomic sub-type of 's' is declared here");
 }
 
 TEST_F(ResolverAtomicValidationTest, InvalidAccessMode_StructOfStruct) {
-  // struct Inner { m : atomic<i32>; };
-  // struct Outer { m : array<Inner, 4>; };
-  // var<storage, read> g : Outer;
+    // struct Inner { m : atomic<i32>; };
+    // struct Outer { m : array<Inner, 4>; };
+    // var<storage, read> g : Outer;
 
-  auto* Inner =
-      Structure("Inner", {Member("m", ty.atomic(Source{{12, 34}}, ty.i32()))});
-  auto* Outer = Structure("Outer", {Member("m", ty.Of(Inner))});
-  Global(Source{{56, 78}}, "g", ty.Of(Outer), ast::StorageClass::kStorage,
-         ast::Access::kRead, GroupAndBinding(0, 0));
+    auto* Inner = Structure("Inner", {Member("m", ty.atomic(Source{{12, 34}}, ty.i32()))});
+    auto* Outer = Structure("Outer", {Member("m", ty.Of(Inner))});
+    Global(Source{{56, 78}}, "g", ty.Of(Outer), ast::StorageClass::kStorage, ast::Access::kRead,
+           GroupAndBinding(0, 0));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "error: atomic variables in <storage> storage class must have read_write "
-      "access mode\n"
-      "note: atomic sub-type of 'Outer' is declared here");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "error: atomic variables in <storage> storage class must have read_write "
+              "access mode\n"
+              "note: atomic sub-type of 'Outer' is declared here");
 }
 
 TEST_F(ResolverAtomicValidationTest, InvalidAccessMode_StructOfStructOfArray) {
-  // struct Inner { m : array<atomic<i32>, 4>; };
-  // struct Outer { m : array<Inner, 4>; };
-  // var<storage, read> g : Outer;
+    // struct Inner { m : array<atomic<i32>, 4>; };
+    // struct Outer { m : array<Inner, 4>; };
+    // var<storage, read> g : Outer;
 
-  auto* Inner =
-      Structure("Inner", {Member(Source{{12, 34}}, "m", ty.atomic(ty.i32()))});
-  auto* Outer = Structure("Outer", {Member("m", ty.Of(Inner))});
-  Global(Source{{56, 78}}, "g", ty.Of(Outer), ast::StorageClass::kStorage,
-         ast::Access::kRead, GroupAndBinding(0, 0));
+    auto* Inner = Structure("Inner", {Member(Source{{12, 34}}, "m", ty.atomic(ty.i32()))});
+    auto* Outer = Structure("Outer", {Member("m", ty.Of(Inner))});
+    Global(Source{{56, 78}}, "g", ty.Of(Outer), ast::StorageClass::kStorage, ast::Access::kRead,
+           GroupAndBinding(0, 0));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "error: atomic variables in <storage> storage class must have "
-            "read_write access mode\n"
-            "12:34 note: atomic sub-type of 'Outer' is declared here");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "error: atomic variables in <storage> storage class must have "
+              "read_write access mode\n"
+              "12:34 note: atomic sub-type of 'Outer' is declared here");
 }
 
 TEST_F(ResolverAtomicValidationTest, InvalidAccessMode_Complex) {
-  // type AtomicArray = array<atomic<i32>, 5>;
-  // struct S6 { x: array<i32, 4>; };
-  // struct S5 { x: S6;
-  //             y: AtomicArray;
-  //             z: array<atomic<u32>, 8>; };
-  // struct S4 { x: S6;
-  //             y: S5;
-  //             z: array<atomic<i32>, 4>; };
-  // struct S3 { x: S4; };
-  // struct S2 { x: S3; };
-  // struct S1 { x: S2; };
-  // struct S0 { x: S1; };
-  // var<storage, read> g : S0;
+    // type AtomicArray = array<atomic<i32>, 5>;
+    // struct S6 { x: array<i32, 4u>; };
+    // struct S5 { x: S6;
+    //             y: AtomicArray;
+    //             z: array<atomic<u32>, 8u>; };
+    // struct S4 { x: S6;
+    //             y: S5;
+    //             z: array<atomic<i32>, 4u>; };
+    // struct S3 { x: S4; };
+    // struct S2 { x: S3; };
+    // struct S1 { x: S2; };
+    // struct S0 { x: S1; };
+    // var<storage, read> g : S0;
 
-  auto* atomic_array = Alias(Source{{12, 34}}, "AtomicArray",
-                             ty.atomic(Source{{12, 34}}, ty.i32()));
-  auto* array_i32_4 = ty.array(ty.i32(), 4);
-  auto* array_atomic_u32_8 = ty.array(ty.atomic(ty.u32()), 8);
-  auto* array_atomic_i32_4 = ty.array(ty.atomic(ty.i32()), 4);
+    auto* atomic_array =
+        Alias(Source{{12, 34}}, "AtomicArray", ty.atomic(Source{{12, 34}}, ty.i32()));
+    auto* array_i32_4 = ty.array(ty.i32(), 4_u);
+    auto* array_atomic_u32_8 = ty.array(ty.atomic(ty.u32()), 8_u);
+    auto* array_atomic_i32_4 = ty.array(ty.atomic(ty.i32()), 4_u);
 
-  auto* s6 = Structure("S6", {Member("x", array_i32_4)});
-  auto* s5 = Structure("S5", {Member("x", ty.Of(s6)),             //
-                              Member("y", ty.Of(atomic_array)),   //
-                              Member("z", array_atomic_u32_8)});  //
-  auto* s4 = Structure("S4", {Member("x", ty.Of(s6)),             //
-                              Member("y", ty.Of(s5)),             //
-                              Member("z", array_atomic_i32_4)});  //
-  auto* s3 = Structure("S3", {Member("x", ty.Of(s4))});
-  auto* s2 = Structure("S2", {Member("x", ty.Of(s3))});
-  auto* s1 = Structure("S1", {Member("x", ty.Of(s2))});
-  auto* s0 = Structure("S0", {Member("x", ty.Of(s1))});
-  Global(Source{{56, 78}}, "g", ty.Of(s0), ast::StorageClass::kStorage,
-         ast::Access::kRead, GroupAndBinding(0, 0));
+    auto* s6 = Structure("S6", {Member("x", array_i32_4)});
+    auto* s5 = Structure("S5", {Member("x", ty.Of(s6)),             //
+                                Member("y", ty.Of(atomic_array)),   //
+                                Member("z", array_atomic_u32_8)});  //
+    auto* s4 = Structure("S4", {Member("x", ty.Of(s6)),             //
+                                Member("y", ty.Of(s5)),             //
+                                Member("z", array_atomic_i32_4)});  //
+    auto* s3 = Structure("S3", {Member("x", ty.Of(s4))});
+    auto* s2 = Structure("S2", {Member("x", ty.Of(s3))});
+    auto* s1 = Structure("S1", {Member("x", ty.Of(s2))});
+    auto* s0 = Structure("S0", {Member("x", ty.Of(s1))});
+    Global(Source{{56, 78}}, "g", ty.Of(s0), ast::StorageClass::kStorage, ast::Access::kRead,
+           GroupAndBinding(0, 0));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "error: atomic variables in <storage> storage class must have "
-            "read_write access mode\n"
-            "note: atomic sub-type of 'S0' is declared here");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "error: atomic variables in <storage> storage class must have "
+              "read_write access mode\n"
+              "note: atomic sub-type of 'S0' is declared here");
 }
 
 TEST_F(ResolverAtomicValidationTest, Local) {
-  WrapInFunction(Var("a", ty.atomic(Source{{12, 34}}, ty.i32())));
+    WrapInFunction(Var("a", ty.atomic(Source{{12, 34}}, ty.i32())));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: function variable must have a constructible type");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: function variable must have a constructible type");
 }
 
 }  // namespace
diff --git a/src/tint/resolver/attribute_validation_test.cc b/src/tint/resolver/attribute_validation_test.cc
index 3b8781b..dbefb14 100644
--- a/src/tint/resolver/attribute_validation_test.cc
+++ b/src/tint/resolver/attribute_validation_test.cc
@@ -19,6 +19,8 @@
 
 #include "gmock/gmock.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::resolver {
 
 // Helpers and typedefs
@@ -44,765 +46,721 @@
 using alias2 = builder::alias2<T>;
 template <typename T>
 using alias3 = builder::alias3<T>;
-using f32 = builder::f32;
-using i32 = builder::i32;
-using u32 = builder::u32;
 
 namespace AttributeTests {
 namespace {
 enum class AttributeKind {
-  kAlign,
-  kBinding,
-  kBuiltin,
-  kGroup,
-  kId,
-  kInterpolate,
-  kInvariant,
-  kLocation,
-  kOffset,
-  kSize,
-  kStage,
-  kStride,
-  kWorkgroup,
+    kAlign,
+    kBinding,
+    kBuiltin,
+    kGroup,
+    kId,
+    kInterpolate,
+    kInvariant,
+    kLocation,
+    kOffset,
+    kSize,
+    kStage,
+    kStride,
+    kWorkgroup,
 
-  kBindingAndGroup,
+    kBindingAndGroup,
 };
 
 static bool IsBindingAttribute(AttributeKind kind) {
-  switch (kind) {
-    case AttributeKind::kBinding:
-    case AttributeKind::kGroup:
-    case AttributeKind::kBindingAndGroup:
-      return true;
-    default:
-      return false;
-  }
+    switch (kind) {
+        case AttributeKind::kBinding:
+        case AttributeKind::kGroup:
+        case AttributeKind::kBindingAndGroup:
+            return true;
+        default:
+            return false;
+    }
 }
 
 struct TestParams {
-  AttributeKind kind;
-  bool should_pass;
+    AttributeKind kind;
+    bool should_pass;
 };
 struct TestWithParams : ResolverTestWithParam<TestParams> {};
 
 static ast::AttributeList createAttributes(const Source& source,
                                            ProgramBuilder& builder,
                                            AttributeKind kind) {
-  switch (kind) {
-    case AttributeKind::kAlign:
-      return {builder.create<ast::StructMemberAlignAttribute>(source, 4u)};
-    case AttributeKind::kBinding:
-      return {builder.create<ast::BindingAttribute>(source, 1u)};
-    case AttributeKind::kBuiltin:
-      return {builder.Builtin(source, ast::Builtin::kPosition)};
-    case AttributeKind::kGroup:
-      return {builder.create<ast::GroupAttribute>(source, 1u)};
-    case AttributeKind::kId:
-      return {builder.create<ast::IdAttribute>(source, 0u)};
-    case AttributeKind::kInterpolate:
-      return {builder.Interpolate(source, ast::InterpolationType::kLinear,
-                                  ast::InterpolationSampling::kCenter)};
-    case AttributeKind::kInvariant:
-      return {builder.Invariant(source)};
-    case AttributeKind::kLocation:
-      return {builder.Location(source, 1)};
-    case AttributeKind::kOffset:
-      return {builder.create<ast::StructMemberOffsetAttribute>(source, 4u)};
-    case AttributeKind::kSize:
-      return {builder.create<ast::StructMemberSizeAttribute>(source, 16u)};
-    case AttributeKind::kStage:
-      return {builder.Stage(source, ast::PipelineStage::kCompute)};
-    case AttributeKind::kStride:
-      return {builder.create<ast::StrideAttribute>(source, 4u)};
-    case AttributeKind::kWorkgroup:
-      return {builder.create<ast::WorkgroupAttribute>(source, builder.Expr(1))};
-    case AttributeKind::kBindingAndGroup:
-      return {builder.create<ast::BindingAttribute>(source, 1u),
-              builder.create<ast::GroupAttribute>(source, 1u)};
-  }
-  return {};
+    switch (kind) {
+        case AttributeKind::kAlign:
+            return {builder.create<ast::StructMemberAlignAttribute>(source, 4u)};
+        case AttributeKind::kBinding:
+            return {builder.create<ast::BindingAttribute>(source, 1u)};
+        case AttributeKind::kBuiltin:
+            return {builder.Builtin(source, ast::Builtin::kPosition)};
+        case AttributeKind::kGroup:
+            return {builder.create<ast::GroupAttribute>(source, 1u)};
+        case AttributeKind::kId:
+            return {builder.create<ast::IdAttribute>(source, 0u)};
+        case AttributeKind::kInterpolate:
+            return {builder.Interpolate(source, ast::InterpolationType::kLinear,
+                                        ast::InterpolationSampling::kCenter)};
+        case AttributeKind::kInvariant:
+            return {builder.Invariant(source)};
+        case AttributeKind::kLocation:
+            return {builder.Location(source, 1)};
+        case AttributeKind::kOffset:
+            return {builder.create<ast::StructMemberOffsetAttribute>(source, 4u)};
+        case AttributeKind::kSize:
+            return {builder.create<ast::StructMemberSizeAttribute>(source, 16u)};
+        case AttributeKind::kStage:
+            return {builder.Stage(source, ast::PipelineStage::kCompute)};
+        case AttributeKind::kStride:
+            return {builder.create<ast::StrideAttribute>(source, 4u)};
+        case AttributeKind::kWorkgroup:
+            return {builder.create<ast::WorkgroupAttribute>(source, builder.Expr(1_i))};
+        case AttributeKind::kBindingAndGroup:
+            return {builder.create<ast::BindingAttribute>(source, 1_u),
+                    builder.create<ast::GroupAttribute>(source, 1_u)};
+    }
+    return {};
 }
 
 namespace FunctionInputAndOutputTests {
 using FunctionParameterAttributeTest = TestWithParams;
 TEST_P(FunctionParameterAttributeTest, IsValid) {
-  auto& params = GetParam();
+    auto& params = GetParam();
 
-  Func("main",
-       ast::VariableList{Param("a", ty.vec4<f32>(),
-                               createAttributes({}, *this, params.kind))},
-       ty.void_(), {});
+    Func("main",
+         ast::VariableList{Param("a", ty.vec4<f32>(), createAttributes({}, *this, params.kind))},
+         ty.void_(), {});
 
-  if (params.should_pass) {
-    EXPECT_TRUE(r()->Resolve()) << r()->error();
-  } else {
-    EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              "error: attribute is not valid for non-entry point function "
-              "parameters");
-  }
+    if (params.should_pass) {
+        EXPECT_TRUE(r()->Resolve()) << r()->error();
+    } else {
+        EXPECT_FALSE(r()->Resolve());
+        EXPECT_EQ(r()->error(),
+                  "error: attribute is not valid for non-entry point function "
+                  "parameters");
+    }
 }
-INSTANTIATE_TEST_SUITE_P(
-    ResolverAttributeValidationTest,
-    FunctionParameterAttributeTest,
-    testing::Values(TestParams{AttributeKind::kAlign, false},
-                    TestParams{AttributeKind::kBinding, false},
-                    TestParams{AttributeKind::kBuiltin, false},
-                    TestParams{AttributeKind::kGroup, false},
-                    TestParams{AttributeKind::kId, false},
-                    TestParams{AttributeKind::kInterpolate, false},
-                    TestParams{AttributeKind::kInvariant, false},
-                    TestParams{AttributeKind::kLocation, false},
-                    TestParams{AttributeKind::kOffset, false},
-                    TestParams{AttributeKind::kSize, false},
-                    TestParams{AttributeKind::kStage, false},
-                    TestParams{AttributeKind::kStride, false},
-                    TestParams{AttributeKind::kWorkgroup, false},
-                    TestParams{AttributeKind::kBindingAndGroup, false}));
+INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
+                         FunctionParameterAttributeTest,
+                         testing::Values(TestParams{AttributeKind::kAlign, false},
+                                         TestParams{AttributeKind::kBinding, false},
+                                         TestParams{AttributeKind::kBuiltin, false},
+                                         TestParams{AttributeKind::kGroup, false},
+                                         TestParams{AttributeKind::kId, false},
+                                         TestParams{AttributeKind::kInterpolate, false},
+                                         TestParams{AttributeKind::kInvariant, false},
+                                         TestParams{AttributeKind::kLocation, false},
+                                         TestParams{AttributeKind::kOffset, false},
+                                         TestParams{AttributeKind::kSize, false},
+                                         TestParams{AttributeKind::kStage, false},
+                                         TestParams{AttributeKind::kStride, false},
+                                         TestParams{AttributeKind::kWorkgroup, false},
+                                         TestParams{AttributeKind::kBindingAndGroup, false}));
 
 using FunctionReturnTypeAttributeTest = TestWithParams;
 TEST_P(FunctionReturnTypeAttributeTest, IsValid) {
-  auto& params = GetParam();
+    auto& params = GetParam();
 
-  Func("main", ast::VariableList{}, ty.f32(), ast::StatementList{Return(1.f)},
-       {}, createAttributes({}, *this, params.kind));
+    Func("main", ast::VariableList{}, ty.f32(), ast::StatementList{Return(1.f)}, {},
+         createAttributes({}, *this, params.kind));
 
-  if (params.should_pass) {
-    EXPECT_TRUE(r()->Resolve()) << r()->error();
-  } else {
-    EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              "error: attribute is not valid for non-entry point function "
-              "return types");
-  }
+    if (params.should_pass) {
+        EXPECT_TRUE(r()->Resolve()) << r()->error();
+    } else {
+        EXPECT_FALSE(r()->Resolve());
+        EXPECT_EQ(r()->error(),
+                  "error: attribute is not valid for non-entry point function "
+                  "return types");
+    }
 }
-INSTANTIATE_TEST_SUITE_P(
-    ResolverAttributeValidationTest,
-    FunctionReturnTypeAttributeTest,
-    testing::Values(TestParams{AttributeKind::kAlign, false},
-                    TestParams{AttributeKind::kBinding, false},
-                    TestParams{AttributeKind::kBuiltin, false},
-                    TestParams{AttributeKind::kGroup, false},
-                    TestParams{AttributeKind::kId, false},
-                    TestParams{AttributeKind::kInterpolate, false},
-                    TestParams{AttributeKind::kInvariant, false},
-                    TestParams{AttributeKind::kLocation, false},
-                    TestParams{AttributeKind::kOffset, false},
-                    TestParams{AttributeKind::kSize, false},
-                    TestParams{AttributeKind::kStage, false},
-                    TestParams{AttributeKind::kStride, false},
-                    TestParams{AttributeKind::kWorkgroup, false},
-                    TestParams{AttributeKind::kBindingAndGroup, false}));
+INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
+                         FunctionReturnTypeAttributeTest,
+                         testing::Values(TestParams{AttributeKind::kAlign, false},
+                                         TestParams{AttributeKind::kBinding, false},
+                                         TestParams{AttributeKind::kBuiltin, false},
+                                         TestParams{AttributeKind::kGroup, false},
+                                         TestParams{AttributeKind::kId, false},
+                                         TestParams{AttributeKind::kInterpolate, false},
+                                         TestParams{AttributeKind::kInvariant, false},
+                                         TestParams{AttributeKind::kLocation, false},
+                                         TestParams{AttributeKind::kOffset, false},
+                                         TestParams{AttributeKind::kSize, false},
+                                         TestParams{AttributeKind::kStage, false},
+                                         TestParams{AttributeKind::kStride, false},
+                                         TestParams{AttributeKind::kWorkgroup, false},
+                                         TestParams{AttributeKind::kBindingAndGroup, false}));
 }  // namespace FunctionInputAndOutputTests
 
 namespace EntryPointInputAndOutputTests {
 using ComputeShaderParameterAttributeTest = TestWithParams;
 TEST_P(ComputeShaderParameterAttributeTest, IsValid) {
-  auto& params = GetParam();
-  auto* p = Param("a", ty.vec4<f32>(),
-                  createAttributes(Source{{12, 34}}, *this, params.kind));
-  Func("main", ast::VariableList{p}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
+    auto& params = GetParam();
+    auto* p = Param("a", ty.vec4<f32>(), createAttributes(Source{{12, 34}}, *this, params.kind));
+    Func("main", ast::VariableList{p}, ty.void_(), {},
+         {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
 
-  if (params.should_pass) {
-    EXPECT_TRUE(r()->Resolve()) << r()->error();
-  } else {
-    EXPECT_FALSE(r()->Resolve());
-    if (params.kind == AttributeKind::kBuiltin) {
-      EXPECT_EQ(r()->error(),
-                "12:34 error: builtin(position) cannot be used in input of "
-                "compute pipeline stage");
-    } else if (params.kind == AttributeKind::kInterpolate ||
-               params.kind == AttributeKind::kLocation ||
-               params.kind == AttributeKind::kInvariant) {
-      EXPECT_EQ(
-          r()->error(),
-          "12:34 error: attribute is not valid for compute shader inputs");
+    if (params.should_pass) {
+        EXPECT_TRUE(r()->Resolve()) << r()->error();
     } else {
-      EXPECT_EQ(r()->error(),
-                "12:34 error: attribute is not valid for function parameters");
+        EXPECT_FALSE(r()->Resolve());
+        if (params.kind == AttributeKind::kBuiltin) {
+            EXPECT_EQ(r()->error(),
+                      "12:34 error: builtin(position) cannot be used in input of "
+                      "compute pipeline stage");
+        } else if (params.kind == AttributeKind::kInterpolate ||
+                   params.kind == AttributeKind::kLocation ||
+                   params.kind == AttributeKind::kInvariant) {
+            EXPECT_EQ(r()->error(),
+                      "12:34 error: attribute is not valid for compute shader inputs");
+        } else {
+            EXPECT_EQ(r()->error(), "12:34 error: attribute is not valid for function parameters");
+        }
     }
-  }
 }
-INSTANTIATE_TEST_SUITE_P(
-    ResolverAttributeValidationTest,
-    ComputeShaderParameterAttributeTest,
-    testing::Values(TestParams{AttributeKind::kAlign, false},
-                    TestParams{AttributeKind::kBinding, false},
-                    TestParams{AttributeKind::kBuiltin, false},
-                    TestParams{AttributeKind::kGroup, false},
-                    TestParams{AttributeKind::kId, false},
-                    TestParams{AttributeKind::kInterpolate, false},
-                    TestParams{AttributeKind::kInvariant, false},
-                    TestParams{AttributeKind::kLocation, false},
-                    TestParams{AttributeKind::kOffset, false},
-                    TestParams{AttributeKind::kSize, false},
-                    TestParams{AttributeKind::kStage, false},
-                    TestParams{AttributeKind::kStride, false},
-                    TestParams{AttributeKind::kWorkgroup, false},
-                    TestParams{AttributeKind::kBindingAndGroup, false}));
+INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
+                         ComputeShaderParameterAttributeTest,
+                         testing::Values(TestParams{AttributeKind::kAlign, false},
+                                         TestParams{AttributeKind::kBinding, false},
+                                         TestParams{AttributeKind::kBuiltin, false},
+                                         TestParams{AttributeKind::kGroup, false},
+                                         TestParams{AttributeKind::kId, false},
+                                         TestParams{AttributeKind::kInterpolate, false},
+                                         TestParams{AttributeKind::kInvariant, false},
+                                         TestParams{AttributeKind::kLocation, false},
+                                         TestParams{AttributeKind::kOffset, false},
+                                         TestParams{AttributeKind::kSize, false},
+                                         TestParams{AttributeKind::kStage, false},
+                                         TestParams{AttributeKind::kStride, false},
+                                         TestParams{AttributeKind::kWorkgroup, false},
+                                         TestParams{AttributeKind::kBindingAndGroup, false}));
 
 using FragmentShaderParameterAttributeTest = TestWithParams;
 TEST_P(FragmentShaderParameterAttributeTest, IsValid) {
-  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));
-  }
-  auto* p = Param("a", ty.vec4<f32>(), attrs);
-  Func("frag_main", {p}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kFragment)});
+    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));
+    }
+    auto* p = Param("a", ty.vec4<f32>(), attrs);
+    Func("frag_main", {p}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
 
-  if (params.should_pass) {
-    EXPECT_TRUE(r()->Resolve()) << r()->error();
-  } else {
-    EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              "12:34 error: attribute is not valid for function parameters");
-  }
+    if (params.should_pass) {
+        EXPECT_TRUE(r()->Resolve()) << r()->error();
+    } else {
+        EXPECT_FALSE(r()->Resolve());
+        EXPECT_EQ(r()->error(), "12:34 error: attribute is not valid for function parameters");
+    }
 }
-INSTANTIATE_TEST_SUITE_P(
-    ResolverAttributeValidationTest,
-    FragmentShaderParameterAttributeTest,
-    testing::Values(TestParams{AttributeKind::kAlign, false},
-                    TestParams{AttributeKind::kBinding, false},
-                    TestParams{AttributeKind::kBuiltin, true},
-                    TestParams{AttributeKind::kGroup, false},
-                    TestParams{AttributeKind::kId, false},
-                    // kInterpolate tested separately (requires @location)
-                    TestParams{AttributeKind::kInvariant, true},
-                    TestParams{AttributeKind::kLocation, true},
-                    TestParams{AttributeKind::kOffset, false},
-                    TestParams{AttributeKind::kSize, false},
-                    TestParams{AttributeKind::kStage, false},
-                    TestParams{AttributeKind::kStride, false},
-                    TestParams{AttributeKind::kWorkgroup, false},
-                    TestParams{AttributeKind::kBindingAndGroup, false}));
+INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
+                         FragmentShaderParameterAttributeTest,
+                         testing::Values(TestParams{AttributeKind::kAlign, false},
+                                         TestParams{AttributeKind::kBinding, false},
+                                         TestParams{AttributeKind::kBuiltin, true},
+                                         TestParams{AttributeKind::kGroup, false},
+                                         TestParams{AttributeKind::kId, false},
+                                         // kInterpolate tested separately (requires @location)
+                                         TestParams{AttributeKind::kInvariant, true},
+                                         TestParams{AttributeKind::kLocation, true},
+                                         TestParams{AttributeKind::kOffset, false},
+                                         TestParams{AttributeKind::kSize, false},
+                                         TestParams{AttributeKind::kStage, false},
+                                         TestParams{AttributeKind::kStride, false},
+                                         TestParams{AttributeKind::kWorkgroup, false},
+                                         TestParams{AttributeKind::kBindingAndGroup, false}));
 
 using VertexShaderParameterAttributeTest = TestWithParams;
 TEST_P(VertexShaderParameterAttributeTest, IsValid) {
-  auto& params = GetParam();
-  auto attrs = createAttributes(Source{{12, 34}}, *this, params.kind);
-  if (params.kind != AttributeKind::kLocation) {
-    attrs.push_back(Location(Source{{34, 56}}, 2));
-  }
-  auto* p = Param("a", ty.vec4<f32>(), attrs);
-  Func("vertex_main", ast::VariableList{p}, ty.vec4<f32>(),
-       {Return(Construct(ty.vec4<f32>()))},
-       {Stage(ast::PipelineStage::kVertex)},
-       {Builtin(ast::Builtin::kPosition)});
-
-  if (params.should_pass) {
-    EXPECT_TRUE(r()->Resolve()) << r()->error();
-  } else {
-    EXPECT_FALSE(r()->Resolve());
-    if (params.kind == AttributeKind::kBuiltin) {
-      EXPECT_EQ(r()->error(),
-                "12:34 error: builtin(position) cannot be used in input of "
-                "vertex pipeline stage");
-    } else if (params.kind == AttributeKind::kInvariant) {
-      EXPECT_EQ(r()->error(),
-                "12:34 error: invariant attribute must only be applied to a "
-                "position builtin");
-    } else {
-      EXPECT_EQ(r()->error(),
-                "12:34 error: attribute is not valid for function parameters");
+    auto& params = GetParam();
+    auto attrs = createAttributes(Source{{12, 34}}, *this, params.kind);
+    if (params.kind != AttributeKind::kLocation) {
+        attrs.push_back(Location(Source{{34, 56}}, 2));
     }
-  }
+    auto* p = Param("a", ty.vec4<f32>(), attrs);
+    Func("vertex_main", ast::VariableList{p}, ty.vec4<f32>(), {Return(Construct(ty.vec4<f32>()))},
+         {Stage(ast::PipelineStage::kVertex)}, {Builtin(ast::Builtin::kPosition)});
+
+    if (params.should_pass) {
+        EXPECT_TRUE(r()->Resolve()) << r()->error();
+    } else {
+        EXPECT_FALSE(r()->Resolve());
+        if (params.kind == AttributeKind::kBuiltin) {
+            EXPECT_EQ(r()->error(),
+                      "12:34 error: builtin(position) cannot be used in input of "
+                      "vertex pipeline stage");
+        } else if (params.kind == AttributeKind::kInvariant) {
+            EXPECT_EQ(r()->error(),
+                      "12:34 error: invariant attribute must only be applied to a "
+                      "position builtin");
+        } else {
+            EXPECT_EQ(r()->error(), "12:34 error: attribute is not valid for function parameters");
+        }
+    }
 }
-INSTANTIATE_TEST_SUITE_P(
-    ResolverAttributeValidationTest,
-    VertexShaderParameterAttributeTest,
-    testing::Values(TestParams{AttributeKind::kAlign, false},
-                    TestParams{AttributeKind::kBinding, false},
-                    TestParams{AttributeKind::kBuiltin, false},
-                    TestParams{AttributeKind::kGroup, false},
-                    TestParams{AttributeKind::kId, false},
-                    TestParams{AttributeKind::kInterpolate, true},
-                    TestParams{AttributeKind::kInvariant, false},
-                    TestParams{AttributeKind::kLocation, true},
-                    TestParams{AttributeKind::kOffset, false},
-                    TestParams{AttributeKind::kSize, false},
-                    TestParams{AttributeKind::kStage, false},
-                    TestParams{AttributeKind::kStride, false},
-                    TestParams{AttributeKind::kWorkgroup, false},
-                    TestParams{AttributeKind::kBindingAndGroup, false}));
+INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
+                         VertexShaderParameterAttributeTest,
+                         testing::Values(TestParams{AttributeKind::kAlign, false},
+                                         TestParams{AttributeKind::kBinding, false},
+                                         TestParams{AttributeKind::kBuiltin, false},
+                                         TestParams{AttributeKind::kGroup, false},
+                                         TestParams{AttributeKind::kId, false},
+                                         TestParams{AttributeKind::kInterpolate, true},
+                                         TestParams{AttributeKind::kInvariant, false},
+                                         TestParams{AttributeKind::kLocation, true},
+                                         TestParams{AttributeKind::kOffset, false},
+                                         TestParams{AttributeKind::kSize, false},
+                                         TestParams{AttributeKind::kStage, false},
+                                         TestParams{AttributeKind::kStride, false},
+                                         TestParams{AttributeKind::kWorkgroup, false},
+                                         TestParams{AttributeKind::kBindingAndGroup, false}));
 
 using ComputeShaderReturnTypeAttributeTest = TestWithParams;
 TEST_P(ComputeShaderReturnTypeAttributeTest, IsValid) {
-  auto& params = GetParam();
-  Func("main", ast::VariableList{}, ty.vec4<f32>(),
-       {Return(Construct(ty.vec4<f32>(), 1.f))},
-       {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)},
-       createAttributes(Source{{12, 34}}, *this, params.kind));
+    auto& params = GetParam();
+    Func("main", ast::VariableList{}, ty.vec4<f32>(), {Return(Construct(ty.vec4<f32>(), 1.f))},
+         {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)},
+         createAttributes(Source{{12, 34}}, *this, params.kind));
 
-  if (params.should_pass) {
-    EXPECT_TRUE(r()->Resolve()) << r()->error();
-  } else {
-    EXPECT_FALSE(r()->Resolve());
-    if (params.kind == AttributeKind::kBuiltin) {
-      EXPECT_EQ(r()->error(),
-                "12:34 error: builtin(position) cannot be used in output of "
-                "compute pipeline stage");
-    } else if (params.kind == AttributeKind::kInterpolate ||
-               params.kind == AttributeKind::kLocation ||
-               params.kind == AttributeKind::kInvariant) {
-      EXPECT_EQ(
-          r()->error(),
-          "12:34 error: attribute is not valid for compute shader output");
+    if (params.should_pass) {
+        EXPECT_TRUE(r()->Resolve()) << r()->error();
     } else {
-      EXPECT_EQ(r()->error(),
-                "12:34 error: attribute is not valid for entry point return "
-                "types");
+        EXPECT_FALSE(r()->Resolve());
+        if (params.kind == AttributeKind::kBuiltin) {
+            EXPECT_EQ(r()->error(),
+                      "12:34 error: builtin(position) cannot be used in output of "
+                      "compute pipeline stage");
+        } else if (params.kind == AttributeKind::kInterpolate ||
+                   params.kind == AttributeKind::kLocation ||
+                   params.kind == AttributeKind::kInvariant) {
+            EXPECT_EQ(r()->error(),
+                      "12:34 error: attribute is not valid for compute shader output");
+        } else {
+            EXPECT_EQ(r()->error(),
+                      "12:34 error: attribute is not valid for entry point return "
+                      "types");
+        }
     }
-  }
 }
-INSTANTIATE_TEST_SUITE_P(
-    ResolverAttributeValidationTest,
-    ComputeShaderReturnTypeAttributeTest,
-    testing::Values(TestParams{AttributeKind::kAlign, false},
-                    TestParams{AttributeKind::kBinding, false},
-                    TestParams{AttributeKind::kBuiltin, false},
-                    TestParams{AttributeKind::kGroup, false},
-                    TestParams{AttributeKind::kId, false},
-                    TestParams{AttributeKind::kInterpolate, false},
-                    TestParams{AttributeKind::kInvariant, false},
-                    TestParams{AttributeKind::kLocation, false},
-                    TestParams{AttributeKind::kOffset, false},
-                    TestParams{AttributeKind::kSize, false},
-                    TestParams{AttributeKind::kStage, false},
-                    TestParams{AttributeKind::kStride, false},
-                    TestParams{AttributeKind::kWorkgroup, false},
-                    TestParams{AttributeKind::kBindingAndGroup, false}));
+INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
+                         ComputeShaderReturnTypeAttributeTest,
+                         testing::Values(TestParams{AttributeKind::kAlign, false},
+                                         TestParams{AttributeKind::kBinding, false},
+                                         TestParams{AttributeKind::kBuiltin, false},
+                                         TestParams{AttributeKind::kGroup, false},
+                                         TestParams{AttributeKind::kId, false},
+                                         TestParams{AttributeKind::kInterpolate, false},
+                                         TestParams{AttributeKind::kInvariant, false},
+                                         TestParams{AttributeKind::kLocation, false},
+                                         TestParams{AttributeKind::kOffset, false},
+                                         TestParams{AttributeKind::kSize, false},
+                                         TestParams{AttributeKind::kStage, false},
+                                         TestParams{AttributeKind::kStride, false},
+                                         TestParams{AttributeKind::kWorkgroup, false},
+                                         TestParams{AttributeKind::kBindingAndGroup, false}));
 
 using FragmentShaderReturnTypeAttributeTest = TestWithParams;
 TEST_P(FragmentShaderReturnTypeAttributeTest, IsValid) {
-  auto& params = GetParam();
-  auto attrs = createAttributes(Source{{12, 34}}, *this, params.kind);
-  attrs.push_back(Location(Source{{34, 56}}, 2));
-  Func("frag_main", {}, ty.vec4<f32>(), {Return(Construct(ty.vec4<f32>()))},
-       {Stage(ast::PipelineStage::kFragment)}, attrs);
+    auto& params = GetParam();
+    auto attrs = createAttributes(Source{{12, 34}}, *this, params.kind);
+    attrs.push_back(Location(Source{{34, 56}}, 2));
+    Func("frag_main", {}, ty.vec4<f32>(), {Return(Construct(ty.vec4<f32>()))},
+         {Stage(ast::PipelineStage::kFragment)}, attrs);
 
-  if (params.should_pass) {
-    EXPECT_TRUE(r()->Resolve()) << r()->error();
-  } else {
-    EXPECT_FALSE(r()->Resolve());
-    if (params.kind == AttributeKind::kBuiltin) {
-      EXPECT_EQ(r()->error(),
-                "12:34 error: builtin(position) cannot be used in output of "
-                "fragment pipeline stage");
-    } else if (params.kind == AttributeKind::kInvariant) {
-      EXPECT_EQ(r()->error(),
-                "12:34 error: invariant attribute must only be applied to a "
-                "position builtin");
-    } else if (params.kind == AttributeKind::kLocation) {
-      EXPECT_EQ(r()->error(),
-                "34:56 error: duplicate location attribute\n"
-                "12:34 note: first attribute declared here");
+    if (params.should_pass) {
+        EXPECT_TRUE(r()->Resolve()) << r()->error();
     } else {
-      EXPECT_EQ(r()->error(),
-                "12:34 error: attribute is not valid for entry point return "
-                "types");
+        EXPECT_FALSE(r()->Resolve());
+        if (params.kind == AttributeKind::kBuiltin) {
+            EXPECT_EQ(r()->error(),
+                      "12:34 error: builtin(position) cannot be used in output of "
+                      "fragment pipeline stage");
+        } else if (params.kind == AttributeKind::kInvariant) {
+            EXPECT_EQ(r()->error(),
+                      "12:34 error: invariant attribute must only be applied to a "
+                      "position builtin");
+        } else if (params.kind == AttributeKind::kLocation) {
+            EXPECT_EQ(r()->error(),
+                      "34:56 error: duplicate location attribute\n"
+                      "12:34 note: first attribute declared here");
+        } else {
+            EXPECT_EQ(r()->error(),
+                      "12:34 error: attribute is not valid for entry point return "
+                      "types");
+        }
     }
-  }
 }
-INSTANTIATE_TEST_SUITE_P(
-    ResolverAttributeValidationTest,
-    FragmentShaderReturnTypeAttributeTest,
-    testing::Values(TestParams{AttributeKind::kAlign, false},
-                    TestParams{AttributeKind::kBinding, false},
-                    TestParams{AttributeKind::kBuiltin, false},
-                    TestParams{AttributeKind::kGroup, false},
-                    TestParams{AttributeKind::kId, false},
-                    TestParams{AttributeKind::kInterpolate, true},
-                    TestParams{AttributeKind::kInvariant, false},
-                    TestParams{AttributeKind::kLocation, false},
-                    TestParams{AttributeKind::kOffset, false},
-                    TestParams{AttributeKind::kSize, false},
-                    TestParams{AttributeKind::kStage, false},
-                    TestParams{AttributeKind::kStride, false},
-                    TestParams{AttributeKind::kWorkgroup, false},
-                    TestParams{AttributeKind::kBindingAndGroup, false}));
+INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
+                         FragmentShaderReturnTypeAttributeTest,
+                         testing::Values(TestParams{AttributeKind::kAlign, false},
+                                         TestParams{AttributeKind::kBinding, false},
+                                         TestParams{AttributeKind::kBuiltin, false},
+                                         TestParams{AttributeKind::kGroup, false},
+                                         TestParams{AttributeKind::kId, false},
+                                         TestParams{AttributeKind::kInterpolate, true},
+                                         TestParams{AttributeKind::kInvariant, false},
+                                         TestParams{AttributeKind::kLocation, false},
+                                         TestParams{AttributeKind::kOffset, false},
+                                         TestParams{AttributeKind::kSize, false},
+                                         TestParams{AttributeKind::kStage, false},
+                                         TestParams{AttributeKind::kStride, false},
+                                         TestParams{AttributeKind::kWorkgroup, false},
+                                         TestParams{AttributeKind::kBindingAndGroup, false}));
 
 using VertexShaderReturnTypeAttributeTest = TestWithParams;
 TEST_P(VertexShaderReturnTypeAttributeTest, IsValid) {
-  auto& params = GetParam();
-  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));
-  }
-  Func("vertex_main", ast::VariableList{}, ty.vec4<f32>(),
-       {Return(Construct(ty.vec4<f32>()))},
-       {Stage(ast::PipelineStage::kVertex)}, attrs);
-
-  if (params.should_pass) {
-    EXPECT_TRUE(r()->Resolve()) << r()->error();
-  } else {
-    EXPECT_FALSE(r()->Resolve());
-    if (params.kind == AttributeKind::kLocation) {
-      EXPECT_EQ(r()->error(),
-                "34:56 error: multiple entry point IO attributes\n"
-                "12:34 note: previously consumed location(1)");
-    } else {
-      EXPECT_EQ(r()->error(),
-                "12:34 error: attribute is not valid for entry point return "
-                "types");
+    auto& params = GetParam();
+    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));
     }
-  }
+    Func("vertex_main", ast::VariableList{}, ty.vec4<f32>(), {Return(Construct(ty.vec4<f32>()))},
+         {Stage(ast::PipelineStage::kVertex)}, attrs);
+
+    if (params.should_pass) {
+        EXPECT_TRUE(r()->Resolve()) << r()->error();
+    } else {
+        EXPECT_FALSE(r()->Resolve());
+        if (params.kind == AttributeKind::kLocation) {
+            EXPECT_EQ(r()->error(),
+                      "34:56 error: multiple entry point IO attributes\n"
+                      "12:34 note: previously consumed location(1)");
+        } else {
+            EXPECT_EQ(r()->error(),
+                      "12:34 error: attribute is not valid for entry point return "
+                      "types");
+        }
+    }
 }
-INSTANTIATE_TEST_SUITE_P(
-    ResolverAttributeValidationTest,
-    VertexShaderReturnTypeAttributeTest,
-    testing::Values(TestParams{AttributeKind::kAlign, false},
-                    TestParams{AttributeKind::kBinding, false},
-                    TestParams{AttributeKind::kBuiltin, true},
-                    TestParams{AttributeKind::kGroup, false},
-                    TestParams{AttributeKind::kId, false},
-                    // kInterpolate tested separately (requires @location)
-                    TestParams{AttributeKind::kInvariant, true},
-                    TestParams{AttributeKind::kLocation, false},
-                    TestParams{AttributeKind::kOffset, false},
-                    TestParams{AttributeKind::kSize, false},
-                    TestParams{AttributeKind::kStage, false},
-                    TestParams{AttributeKind::kStride, false},
-                    TestParams{AttributeKind::kWorkgroup, false},
-                    TestParams{AttributeKind::kBindingAndGroup, false}));
+INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
+                         VertexShaderReturnTypeAttributeTest,
+                         testing::Values(TestParams{AttributeKind::kAlign, false},
+                                         TestParams{AttributeKind::kBinding, false},
+                                         TestParams{AttributeKind::kBuiltin, true},
+                                         TestParams{AttributeKind::kGroup, false},
+                                         TestParams{AttributeKind::kId, false},
+                                         // kInterpolate tested separately (requires @location)
+                                         TestParams{AttributeKind::kInvariant, true},
+                                         TestParams{AttributeKind::kLocation, false},
+                                         TestParams{AttributeKind::kOffset, false},
+                                         TestParams{AttributeKind::kSize, false},
+                                         TestParams{AttributeKind::kStage, false},
+                                         TestParams{AttributeKind::kStride, false},
+                                         TestParams{AttributeKind::kWorkgroup, false},
+                                         TestParams{AttributeKind::kBindingAndGroup, false}));
 
 using EntryPointParameterAttributeTest = TestWithParams;
 TEST_F(EntryPointParameterAttributeTest, DuplicateAttribute) {
-  Func("main", ast::VariableList{}, ty.f32(), ast::StatementList{Return(1.f)},
-       {Stage(ast::PipelineStage::kFragment)},
-       {
-           Location(Source{{12, 34}}, 2),
-           Location(Source{{56, 78}}, 3),
-       });
+    Func("main", ast::VariableList{}, ty.f32(), ast::StatementList{Return(1.f)},
+         {Stage(ast::PipelineStage::kFragment)},
+         {
+             Location(Source{{12, 34}}, 2),
+             Location(Source{{56, 78}}, 3),
+         });
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            R"(56:78 error: duplicate location attribute
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(56:78 error: duplicate location attribute
 12:34 note: first attribute declared here)");
 }
 
 TEST_F(EntryPointParameterAttributeTest, DuplicateInternalAttribute) {
-  auto* s = Param("s", ty.sampler(ast::SamplerKind::kSampler),
-                  ast::AttributeList{
-                      create<ast::BindingAttribute>(0),
-                      create<ast::GroupAttribute>(0),
-                      Disable(ast::DisabledValidation::kBindingPointCollision),
-                      Disable(ast::DisabledValidation::kEntryPointParameter),
-                  });
-  Func("f", {s}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
+    auto* s = Param("s", ty.sampler(ast::SamplerKind::kSampler),
+                    ast::AttributeList{
+                        create<ast::BindingAttribute>(0),
+                        create<ast::GroupAttribute>(0),
+                        Disable(ast::DisabledValidation::kBindingPointCollision),
+                        Disable(ast::DisabledValidation::kEntryPointParameter),
+                    });
+    Func("f", {s}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 using EntryPointReturnTypeAttributeTest = ResolverTest;
 TEST_F(EntryPointReturnTypeAttributeTest, DuplicateAttribute) {
-  Func("main", ast::VariableList{}, ty.f32(), ast::StatementList{Return(1.f)},
-       ast::AttributeList{Stage(ast::PipelineStage::kFragment)},
-       ast::AttributeList{
-           Location(Source{{12, 34}}, 2),
-           Location(Source{{56, 78}}, 3),
-       });
+    Func("main", ast::VariableList{}, ty.f32(), ast::StatementList{Return(1.f)},
+         ast::AttributeList{Stage(ast::PipelineStage::kFragment)},
+         ast::AttributeList{
+             Location(Source{{12, 34}}, 2),
+             Location(Source{{56, 78}}, 3),
+         });
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            R"(56:78 error: duplicate location attribute
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(56:78 error: duplicate location attribute
 12:34 note: first attribute declared here)");
 }
 
 TEST_F(EntryPointReturnTypeAttributeTest, DuplicateInternalAttribute) {
-  Func("f", {}, ty.i32(), {Return(1)}, {Stage(ast::PipelineStage::kFragment)},
-       ast::AttributeList{
-           Disable(ast::DisabledValidation::kBindingPointCollision),
-           Disable(ast::DisabledValidation::kEntryPointParameter),
-       });
+    Func("f", {}, ty.i32(), {Return(1_i)}, {Stage(ast::PipelineStage::kFragment)},
+         ast::AttributeList{
+             Disable(ast::DisabledValidation::kBindingPointCollision),
+             Disable(ast::DisabledValidation::kEntryPointParameter),
+         });
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 }  // namespace EntryPointInputAndOutputTests
 
 namespace StructAndStructMemberTests {
 using StructAttributeTest = TestWithParams;
-using SpirvBlockAttribute =
-    transform::AddSpirvBlockAttribute::SpirvBlockAttribute;
+using SpirvBlockAttribute = transform::AddSpirvBlockAttribute::SpirvBlockAttribute;
 TEST_P(StructAttributeTest, IsValid) {
-  auto& params = GetParam();
+    auto& params = GetParam();
 
-  auto* str = create<ast::Struct>(
-      Sym("mystruct"), ast::StructMemberList{Member("a", ty.f32())},
-      createAttributes(Source{{12, 34}}, *this, params.kind));
-  AST().AddGlobalDeclaration(str);
+    auto* str = create<ast::Struct>(Sym("mystruct"), ast::StructMemberList{Member("a", ty.f32())},
+                                    createAttributes(Source{{12, 34}}, *this, params.kind));
+    AST().AddGlobalDeclaration(str);
 
-  if (params.should_pass) {
-    EXPECT_TRUE(r()->Resolve()) << r()->error();
-  } else {
-    EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              "12:34 error: attribute is not valid for struct declarations");
-  }
+    if (params.should_pass) {
+        EXPECT_TRUE(r()->Resolve()) << r()->error();
+    } else {
+        EXPECT_FALSE(r()->Resolve());
+        EXPECT_EQ(r()->error(), "12:34 error: attribute is not valid for struct declarations");
+    }
 }
-INSTANTIATE_TEST_SUITE_P(
-    ResolverAttributeValidationTest,
-    StructAttributeTest,
-    testing::Values(TestParams{AttributeKind::kAlign, false},
-                    TestParams{AttributeKind::kBinding, false},
-                    TestParams{AttributeKind::kBuiltin, false},
-                    TestParams{AttributeKind::kGroup, false},
-                    TestParams{AttributeKind::kId, false},
-                    TestParams{AttributeKind::kInterpolate, false},
-                    TestParams{AttributeKind::kInvariant, false},
-                    TestParams{AttributeKind::kLocation, false},
-                    TestParams{AttributeKind::kOffset, false},
-                    TestParams{AttributeKind::kSize, false},
-                    TestParams{AttributeKind::kStage, false},
-                    TestParams{AttributeKind::kStride, false},
-                    TestParams{AttributeKind::kWorkgroup, false},
-                    TestParams{AttributeKind::kBindingAndGroup, false}));
+INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
+                         StructAttributeTest,
+                         testing::Values(TestParams{AttributeKind::kAlign, false},
+                                         TestParams{AttributeKind::kBinding, false},
+                                         TestParams{AttributeKind::kBuiltin, false},
+                                         TestParams{AttributeKind::kGroup, false},
+                                         TestParams{AttributeKind::kId, false},
+                                         TestParams{AttributeKind::kInterpolate, false},
+                                         TestParams{AttributeKind::kInvariant, false},
+                                         TestParams{AttributeKind::kLocation, false},
+                                         TestParams{AttributeKind::kOffset, false},
+                                         TestParams{AttributeKind::kSize, false},
+                                         TestParams{AttributeKind::kStage, false},
+                                         TestParams{AttributeKind::kStride, false},
+                                         TestParams{AttributeKind::kWorkgroup, false},
+                                         TestParams{AttributeKind::kBindingAndGroup, false}));
 
 using StructMemberAttributeTest = TestWithParams;
 TEST_P(StructMemberAttributeTest, IsValid) {
-  auto& params = GetParam();
-  ast::StructMemberList members;
-  if (params.kind == AttributeKind::kBuiltin) {
-    members.push_back(
-        {Member("a", ty.vec4<f32>(),
-                createAttributes(Source{{12, 34}}, *this, params.kind))});
-  } else {
-    members.push_back(
-        {Member("a", ty.f32(),
-                createAttributes(Source{{12, 34}}, *this, params.kind))});
-  }
-  Structure("mystruct", members);
-  WrapInFunction();
-  if (params.should_pass) {
-    EXPECT_TRUE(r()->Resolve()) << r()->error();
-  } else {
+    auto& params = GetParam();
+    ast::StructMemberList members;
+    if (params.kind == AttributeKind::kBuiltin) {
+        members.push_back(
+            {Member("a", ty.vec4<f32>(), createAttributes(Source{{12, 34}}, *this, params.kind))});
+    } else {
+        members.push_back(
+            {Member("a", ty.f32(), createAttributes(Source{{12, 34}}, *this, params.kind))});
+    }
+    Structure("mystruct", members);
+    WrapInFunction();
+    if (params.should_pass) {
+        EXPECT_TRUE(r()->Resolve()) << r()->error();
+    } else {
+        EXPECT_FALSE(r()->Resolve());
+        EXPECT_EQ(r()->error(), "12:34 error: attribute is not valid for structure members");
+    }
+}
+INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
+                         StructMemberAttributeTest,
+                         testing::Values(TestParams{AttributeKind::kAlign, true},
+                                         TestParams{AttributeKind::kBinding, false},
+                                         TestParams{AttributeKind::kBuiltin, true},
+                                         TestParams{AttributeKind::kGroup, false},
+                                         TestParams{AttributeKind::kId, false},
+                                         // kInterpolate tested separately (requires @location)
+                                         // kInvariant tested separately (requires position builtin)
+                                         TestParams{AttributeKind::kLocation, true},
+                                         TestParams{AttributeKind::kOffset, true},
+                                         TestParams{AttributeKind::kSize, true},
+                                         TestParams{AttributeKind::kStage, false},
+                                         TestParams{AttributeKind::kStride, false},
+                                         TestParams{AttributeKind::kWorkgroup, false},
+                                         TestParams{AttributeKind::kBindingAndGroup, false}));
+TEST_F(StructMemberAttributeTest, DuplicateAttribute) {
+    Structure("mystruct",
+              {
+                  Member("a", ty.i32(),
+                         {
+                             create<ast::StructMemberAlignAttribute>(Source{{12, 34}}, 4u),
+                             create<ast::StructMemberAlignAttribute>(Source{{56, 78}}, 8u),
+                         }),
+              });
+    WrapInFunction();
     EXPECT_FALSE(r()->Resolve());
     EXPECT_EQ(r()->error(),
-              "12:34 error: attribute is not valid for structure members");
-  }
-}
-INSTANTIATE_TEST_SUITE_P(
-    ResolverAttributeValidationTest,
-    StructMemberAttributeTest,
-    testing::Values(TestParams{AttributeKind::kAlign, true},
-                    TestParams{AttributeKind::kBinding, false},
-                    TestParams{AttributeKind::kBuiltin, true},
-                    TestParams{AttributeKind::kGroup, false},
-                    TestParams{AttributeKind::kId, false},
-                    // kInterpolate tested separately (requires @location)
-                    // kInvariant tested separately (requires position builtin)
-                    TestParams{AttributeKind::kLocation, true},
-                    TestParams{AttributeKind::kOffset, true},
-                    TestParams{AttributeKind::kSize, true},
-                    TestParams{AttributeKind::kStage, false},
-                    TestParams{AttributeKind::kStride, false},
-                    TestParams{AttributeKind::kWorkgroup, false},
-                    TestParams{AttributeKind::kBindingAndGroup, false}));
-TEST_F(StructMemberAttributeTest, DuplicateAttribute) {
-  Structure(
-      "mystruct",
-      {
-          Member(
-              "a", ty.i32(),
-              {
-                  create<ast::StructMemberAlignAttribute>(Source{{12, 34}}, 4u),
-                  create<ast::StructMemberAlignAttribute>(Source{{56, 78}}, 8u),
-              }),
-      });
-  WrapInFunction();
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            R"(56:78 error: duplicate align attribute
+              R"(56:78 error: duplicate align attribute
 12:34 note: first attribute declared here)");
 }
 TEST_F(StructMemberAttributeTest, InvariantAttributeWithPosition) {
-  Structure("mystruct", {
-                            Member("a", ty.vec4<f32>(),
-                                   {
-                                       Invariant(),
-                                       Builtin(ast::Builtin::kPosition),
-                                   }),
-                        });
-  WrapInFunction();
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    Structure("mystruct", {
+                              Member("a", ty.vec4<f32>(),
+                                     {
+                                         Invariant(),
+                                         Builtin(ast::Builtin::kPosition),
+                                     }),
+                          });
+    WrapInFunction();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 TEST_F(StructMemberAttributeTest, InvariantAttributeWithoutPosition) {
-  Structure("mystruct", {
-                            Member("a", ty.vec4<f32>(),
-                                   {
-                                       Invariant(Source{{12, 34}}),
-                                   }),
-                        });
-  WrapInFunction();
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: invariant attribute must only be applied to a "
-            "position builtin");
+    Structure("mystruct", {
+                              Member("a", ty.vec4<f32>(),
+                                     {
+                                         Invariant(Source{{12, 34}}),
+                                     }),
+                          });
+    WrapInFunction();
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: invariant attribute must only be applied to a "
+              "position builtin");
 }
 
 }  // namespace StructAndStructMemberTests
 
 using ArrayAttributeTest = TestWithParams;
 TEST_P(ArrayAttributeTest, IsValid) {
-  auto& params = GetParam();
+    auto& params = GetParam();
 
-  auto* arr = ty.array(ty.f32(), nullptr,
-                       createAttributes(Source{{12, 34}}, *this, params.kind));
-  Structure("mystruct", {
-                            Member("a", arr),
-                        });
+    auto* arr = ty.array(ty.f32(), nullptr, createAttributes(Source{{12, 34}}, *this, params.kind));
+    Structure("mystruct", {
+                              Member("a", arr),
+                          });
 
-  WrapInFunction();
+    WrapInFunction();
 
-  if (params.should_pass) {
-    EXPECT_TRUE(r()->Resolve()) << r()->error();
-  } else {
-    EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              "12:34 error: attribute is not valid for array types");
-  }
+    if (params.should_pass) {
+        EXPECT_TRUE(r()->Resolve()) << r()->error();
+    } else {
+        EXPECT_FALSE(r()->Resolve());
+        EXPECT_EQ(r()->error(), "12:34 error: attribute is not valid for array types");
+    }
 }
-INSTANTIATE_TEST_SUITE_P(
-    ResolverAttributeValidationTest,
-    ArrayAttributeTest,
-    testing::Values(TestParams{AttributeKind::kAlign, false},
-                    TestParams{AttributeKind::kBinding, false},
-                    TestParams{AttributeKind::kBuiltin, false},
-                    TestParams{AttributeKind::kGroup, false},
-                    TestParams{AttributeKind::kId, false},
-                    TestParams{AttributeKind::kInterpolate, false},
-                    TestParams{AttributeKind::kInvariant, false},
-                    TestParams{AttributeKind::kLocation, false},
-                    TestParams{AttributeKind::kOffset, false},
-                    TestParams{AttributeKind::kSize, false},
-                    TestParams{AttributeKind::kStage, false},
-                    TestParams{AttributeKind::kStride, true},
-                    TestParams{AttributeKind::kWorkgroup, false},
-                    TestParams{AttributeKind::kBindingAndGroup, false}));
+INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
+                         ArrayAttributeTest,
+                         testing::Values(TestParams{AttributeKind::kAlign, false},
+                                         TestParams{AttributeKind::kBinding, false},
+                                         TestParams{AttributeKind::kBuiltin, false},
+                                         TestParams{AttributeKind::kGroup, false},
+                                         TestParams{AttributeKind::kId, false},
+                                         TestParams{AttributeKind::kInterpolate, false},
+                                         TestParams{AttributeKind::kInvariant, false},
+                                         TestParams{AttributeKind::kLocation, false},
+                                         TestParams{AttributeKind::kOffset, false},
+                                         TestParams{AttributeKind::kSize, false},
+                                         TestParams{AttributeKind::kStage, false},
+                                         TestParams{AttributeKind::kStride, true},
+                                         TestParams{AttributeKind::kWorkgroup, false},
+                                         TestParams{AttributeKind::kBindingAndGroup, false}));
 
 using VariableAttributeTest = TestWithParams;
 TEST_P(VariableAttributeTest, IsValid) {
-  auto& params = GetParam();
+    auto& params = GetParam();
 
-  if (IsBindingAttribute(params.kind)) {
-    Global("a", ty.sampler(ast::SamplerKind::kSampler),
-           ast::StorageClass::kNone, nullptr,
-           createAttributes(Source{{12, 34}}, *this, params.kind));
-  } else {
-    Global("a", ty.f32(), ast::StorageClass::kPrivate, nullptr,
-           createAttributes(Source{{12, 34}}, *this, params.kind));
-  }
-
-  WrapInFunction();
-
-  if (params.should_pass) {
-    EXPECT_TRUE(r()->Resolve()) << r()->error();
-  } else {
-    EXPECT_FALSE(r()->Resolve());
-    if (!IsBindingAttribute(params.kind)) {
-      EXPECT_EQ(r()->error(),
-                "12:34 error: attribute is not valid for variables");
+    if (IsBindingAttribute(params.kind)) {
+        Global("a", ty.sampler(ast::SamplerKind::kSampler), ast::StorageClass::kNone, nullptr,
+               createAttributes(Source{{12, 34}}, *this, params.kind));
+    } else {
+        Global("a", ty.f32(), ast::StorageClass::kPrivate, nullptr,
+               createAttributes(Source{{12, 34}}, *this, params.kind));
     }
-  }
+
+    WrapInFunction();
+
+    if (params.should_pass) {
+        EXPECT_TRUE(r()->Resolve()) << r()->error();
+    } else {
+        EXPECT_FALSE(r()->Resolve());
+        if (!IsBindingAttribute(params.kind)) {
+            EXPECT_EQ(r()->error(), "12:34 error: attribute is not valid for variables");
+        }
+    }
 }
-INSTANTIATE_TEST_SUITE_P(
-    ResolverAttributeValidationTest,
-    VariableAttributeTest,
-    testing::Values(TestParams{AttributeKind::kAlign, false},
-                    TestParams{AttributeKind::kBinding, false},
-                    TestParams{AttributeKind::kBuiltin, false},
-                    TestParams{AttributeKind::kGroup, false},
-                    TestParams{AttributeKind::kId, false},
-                    TestParams{AttributeKind::kInterpolate, false},
-                    TestParams{AttributeKind::kInvariant, false},
-                    TestParams{AttributeKind::kLocation, false},
-                    TestParams{AttributeKind::kOffset, false},
-                    TestParams{AttributeKind::kSize, false},
-                    TestParams{AttributeKind::kStage, false},
-                    TestParams{AttributeKind::kStride, false},
-                    TestParams{AttributeKind::kWorkgroup, false},
-                    TestParams{AttributeKind::kBindingAndGroup, true}));
+INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
+                         VariableAttributeTest,
+                         testing::Values(TestParams{AttributeKind::kAlign, false},
+                                         TestParams{AttributeKind::kBinding, false},
+                                         TestParams{AttributeKind::kBuiltin, false},
+                                         TestParams{AttributeKind::kGroup, false},
+                                         TestParams{AttributeKind::kId, false},
+                                         TestParams{AttributeKind::kInterpolate, false},
+                                         TestParams{AttributeKind::kInvariant, false},
+                                         TestParams{AttributeKind::kLocation, false},
+                                         TestParams{AttributeKind::kOffset, false},
+                                         TestParams{AttributeKind::kSize, false},
+                                         TestParams{AttributeKind::kStage, false},
+                                         TestParams{AttributeKind::kStride, false},
+                                         TestParams{AttributeKind::kWorkgroup, false},
+                                         TestParams{AttributeKind::kBindingAndGroup, true}));
 
 TEST_F(VariableAttributeTest, DuplicateAttribute) {
-  Global("a", ty.sampler(ast::SamplerKind::kSampler),
-         ast::AttributeList{
-             create<ast::BindingAttribute>(Source{{12, 34}}, 2),
-             create<ast::GroupAttribute>(2),
-             create<ast::BindingAttribute>(Source{{56, 78}}, 3),
-         });
+    Global("a", ty.sampler(ast::SamplerKind::kSampler),
+           ast::AttributeList{
+               create<ast::BindingAttribute>(Source{{12, 34}}, 2),
+               create<ast::GroupAttribute>(2),
+               create<ast::BindingAttribute>(Source{{56, 78}}, 3),
+           });
 
-  WrapInFunction();
+    WrapInFunction();
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            R"(56:78 error: duplicate binding attribute
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(56:78 error: duplicate binding attribute
 12:34 note: first attribute declared here)");
 }
 
 TEST_F(VariableAttributeTest, LocalVariable) {
-  auto* v = Var("a", ty.f32(),
-                ast::AttributeList{
-                    create<ast::BindingAttribute>(Source{{12, 34}}, 2),
-                });
+    auto* v = Var("a", ty.f32(),
+                  ast::AttributeList{
+                      create<ast::BindingAttribute>(Source{{12, 34}}, 2),
+                  });
 
-  WrapInFunction(v);
+    WrapInFunction(v);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: attributes are not valid on local variables");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: attributes are not valid on local variables");
 }
 
 using ConstantAttributeTest = TestWithParams;
 TEST_P(ConstantAttributeTest, IsValid) {
-  auto& params = GetParam();
+    auto& params = GetParam();
 
-  GlobalConst("a", ty.f32(), Expr(1.23f),
-              createAttributes(Source{{12, 34}}, *this, params.kind));
+    GlobalConst("a", ty.f32(), Expr(1.23f), createAttributes(Source{{12, 34}}, *this, params.kind));
 
-  WrapInFunction();
+    WrapInFunction();
 
-  if (params.should_pass) {
-    EXPECT_TRUE(r()->Resolve()) << r()->error();
-  } else {
-    EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              "12:34 error: attribute is not valid for constants");
-  }
+    if (params.should_pass) {
+        EXPECT_TRUE(r()->Resolve()) << r()->error();
+    } else {
+        EXPECT_FALSE(r()->Resolve());
+        EXPECT_EQ(r()->error(), "12:34 error: attribute is not valid for constants");
+    }
 }
-INSTANTIATE_TEST_SUITE_P(
-    ResolverAttributeValidationTest,
-    ConstantAttributeTest,
-    testing::Values(TestParams{AttributeKind::kAlign, false},
-                    TestParams{AttributeKind::kBinding, false},
-                    TestParams{AttributeKind::kBuiltin, false},
-                    TestParams{AttributeKind::kGroup, false},
-                    TestParams{AttributeKind::kId, true},
-                    TestParams{AttributeKind::kInterpolate, false},
-                    TestParams{AttributeKind::kInvariant, false},
-                    TestParams{AttributeKind::kLocation, false},
-                    TestParams{AttributeKind::kOffset, false},
-                    TestParams{AttributeKind::kSize, false},
-                    TestParams{AttributeKind::kStage, false},
-                    TestParams{AttributeKind::kStride, false},
-                    TestParams{AttributeKind::kWorkgroup, false},
-                    TestParams{AttributeKind::kBindingAndGroup, false}));
+INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
+                         ConstantAttributeTest,
+                         testing::Values(TestParams{AttributeKind::kAlign, false},
+                                         TestParams{AttributeKind::kBinding, false},
+                                         TestParams{AttributeKind::kBuiltin, false},
+                                         TestParams{AttributeKind::kGroup, false},
+                                         TestParams{AttributeKind::kId, true},
+                                         TestParams{AttributeKind::kInterpolate, false},
+                                         TestParams{AttributeKind::kInvariant, false},
+                                         TestParams{AttributeKind::kLocation, false},
+                                         TestParams{AttributeKind::kOffset, false},
+                                         TestParams{AttributeKind::kSize, false},
+                                         TestParams{AttributeKind::kStage, false},
+                                         TestParams{AttributeKind::kStride, false},
+                                         TestParams{AttributeKind::kWorkgroup, false},
+                                         TestParams{AttributeKind::kBindingAndGroup, false}));
 
 TEST_F(ConstantAttributeTest, DuplicateAttribute) {
-  GlobalConst("a", ty.f32(), Expr(1.23f),
-              ast::AttributeList{
-                  create<ast::IdAttribute>(Source{{12, 34}}, 0),
-                  create<ast::IdAttribute>(Source{{56, 78}}, 1),
-              });
+    GlobalConst("a", ty.f32(), Expr(1.23f),
+                ast::AttributeList{
+                    create<ast::IdAttribute>(Source{{12, 34}}, 0),
+                    create<ast::IdAttribute>(Source{{56, 78}}, 1),
+                });
 
-  WrapInFunction();
+    WrapInFunction();
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            R"(56:78 error: duplicate id attribute
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(56:78 error: duplicate id attribute
 12:34 note: first attribute declared here)");
 }
 
@@ -813,46 +771,46 @@
 namespace {
 
 struct Params {
-  builder::ast_type_func_ptr create_el_type;
-  uint32_t stride;
-  bool should_pass;
+    builder::ast_type_func_ptr create_el_type;
+    uint32_t stride;
+    bool should_pass;
 };
 
 template <typename T>
 constexpr Params ParamsFor(uint32_t stride, bool should_pass) {
-  return Params{DataType<T>::AST, stride, should_pass};
+    return Params{DataType<T>::AST, stride, should_pass};
 }
 
 struct TestWithParams : ResolverTestWithParam<Params> {};
 
 using ArrayStrideTest = TestWithParams;
 TEST_P(ArrayStrideTest, All) {
-  auto& params = GetParam();
-  auto* el_ty = params.create_el_type(*this);
+    auto& params = GetParam();
+    auto* el_ty = params.create_el_type(*this);
 
-  std::stringstream ss;
-  ss << "el_ty: " << FriendlyName(el_ty) << ", stride: " << params.stride
-     << ", should_pass: " << params.should_pass;
-  SCOPED_TRACE(ss.str());
+    std::stringstream ss;
+    ss << "el_ty: " << FriendlyName(el_ty) << ", stride: " << params.stride
+       << ", should_pass: " << params.should_pass;
+    SCOPED_TRACE(ss.str());
 
-  auto* arr = ty.array(Source{{12, 34}}, el_ty, 4, params.stride);
+    auto* arr = ty.array(Source{{12, 34}}, el_ty, 4_u, params.stride);
 
-  Global("myarray", arr, ast::StorageClass::kPrivate);
+    Global("myarray", arr, ast::StorageClass::kPrivate);
 
-  if (params.should_pass) {
-    EXPECT_TRUE(r()->Resolve()) << r()->error();
-  } else {
-    EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              "12:34 error: arrays decorated with the stride attribute must "
-              "have a stride that is at least the size of the element type, "
-              "and be a multiple of the element type's alignment value.");
-  }
+    if (params.should_pass) {
+        EXPECT_TRUE(r()->Resolve()) << r()->error();
+    } else {
+        EXPECT_FALSE(r()->Resolve());
+        EXPECT_EQ(r()->error(),
+                  "12:34 error: arrays decorated with the stride attribute must "
+                  "have a stride that is at least the size of the element type, "
+                  "and be a multiple of the element type's alignment value.");
+    }
 }
 
 struct SizeAndAlignment {
-  uint32_t size;
-  uint32_t align;
+    uint32_t size;
+    uint32_t align;
 };
 constexpr SizeAndAlignment default_u32 = {4, 4};
 constexpr SizeAndAlignment default_i32 = {4, 4};
@@ -864,68 +822,67 @@
 constexpr SizeAndAlignment default_mat3x3 = {48, 16};
 constexpr SizeAndAlignment default_mat4x4 = {64, 16};
 
-INSTANTIATE_TEST_SUITE_P(
-    ResolverAttributeValidationTest,
-    ArrayStrideTest,
-    testing::Values(
-        // Succeed because stride >= element size (while being multiple of
-        // element alignment)
-        ParamsFor<u32>(default_u32.size, true),
-        ParamsFor<i32>(default_i32.size, true),
-        ParamsFor<f32>(default_f32.size, true),
-        ParamsFor<vec2<f32>>(default_vec2.size, true),
-        // vec3's default size is not a multiple of its alignment
-        // ParamsFor<vec3<f32>, default_vec3.size, true},
-        ParamsFor<vec4<f32>>(default_vec4.size, true),
-        ParamsFor<mat2x2<f32>>(default_mat2x2.size, true),
-        ParamsFor<mat3x3<f32>>(default_mat3x3.size, true),
-        ParamsFor<mat4x4<f32>>(default_mat4x4.size, true),
+INSTANTIATE_TEST_SUITE_P(ResolverAttributeValidationTest,
+                         ArrayStrideTest,
+                         testing::Values(
+                             // Succeed because stride >= element size (while being multiple of
+                             // element alignment)
+                             ParamsFor<u32>(default_u32.size, true),
+                             ParamsFor<i32>(default_i32.size, true),
+                             ParamsFor<f32>(default_f32.size, true),
+                             ParamsFor<vec2<f32>>(default_vec2.size, true),
+                             // vec3's default size is not a multiple of its alignment
+                             // ParamsFor<vec3<f32>, default_vec3.size, true},
+                             ParamsFor<vec4<f32>>(default_vec4.size, true),
+                             ParamsFor<mat2x2<f32>>(default_mat2x2.size, true),
+                             ParamsFor<mat3x3<f32>>(default_mat3x3.size, true),
+                             ParamsFor<mat4x4<f32>>(default_mat4x4.size, true),
 
-        // Fail because stride is < element size
-        ParamsFor<u32>(default_u32.size - 1, false),
-        ParamsFor<i32>(default_i32.size - 1, false),
-        ParamsFor<f32>(default_f32.size - 1, false),
-        ParamsFor<vec2<f32>>(default_vec2.size - 1, false),
-        ParamsFor<vec3<f32>>(default_vec3.size - 1, false),
-        ParamsFor<vec4<f32>>(default_vec4.size - 1, false),
-        ParamsFor<mat2x2<f32>>(default_mat2x2.size - 1, false),
-        ParamsFor<mat3x3<f32>>(default_mat3x3.size - 1, false),
-        ParamsFor<mat4x4<f32>>(default_mat4x4.size - 1, false),
+                             // Fail because stride is < element size
+                             ParamsFor<u32>(default_u32.size - 1, false),
+                             ParamsFor<i32>(default_i32.size - 1, false),
+                             ParamsFor<f32>(default_f32.size - 1, false),
+                             ParamsFor<vec2<f32>>(default_vec2.size - 1, false),
+                             ParamsFor<vec3<f32>>(default_vec3.size - 1, false),
+                             ParamsFor<vec4<f32>>(default_vec4.size - 1, false),
+                             ParamsFor<mat2x2<f32>>(default_mat2x2.size - 1, false),
+                             ParamsFor<mat3x3<f32>>(default_mat3x3.size - 1, false),
+                             ParamsFor<mat4x4<f32>>(default_mat4x4.size - 1, false),
 
-        // Succeed because stride equals multiple of element alignment
-        ParamsFor<u32>(default_u32.align * 7, true),
-        ParamsFor<i32>(default_i32.align * 7, true),
-        ParamsFor<f32>(default_f32.align * 7, true),
-        ParamsFor<vec2<f32>>(default_vec2.align * 7, true),
-        ParamsFor<vec3<f32>>(default_vec3.align * 7, true),
-        ParamsFor<vec4<f32>>(default_vec4.align * 7, true),
-        ParamsFor<mat2x2<f32>>(default_mat2x2.align * 7, true),
-        ParamsFor<mat3x3<f32>>(default_mat3x3.align * 7, true),
-        ParamsFor<mat4x4<f32>>(default_mat4x4.align * 7, true),
+                             // Succeed because stride equals multiple of element alignment
+                             ParamsFor<u32>(default_u32.align * 7, true),
+                             ParamsFor<i32>(default_i32.align * 7, true),
+                             ParamsFor<f32>(default_f32.align * 7, true),
+                             ParamsFor<vec2<f32>>(default_vec2.align * 7, true),
+                             ParamsFor<vec3<f32>>(default_vec3.align * 7, true),
+                             ParamsFor<vec4<f32>>(default_vec4.align * 7, true),
+                             ParamsFor<mat2x2<f32>>(default_mat2x2.align * 7, true),
+                             ParamsFor<mat3x3<f32>>(default_mat3x3.align * 7, true),
+                             ParamsFor<mat4x4<f32>>(default_mat4x4.align * 7, true),
 
-        // Fail because stride is not multiple of element alignment
-        ParamsFor<u32>((default_u32.align - 1) * 7, false),
-        ParamsFor<i32>((default_i32.align - 1) * 7, false),
-        ParamsFor<f32>((default_f32.align - 1) * 7, false),
-        ParamsFor<vec2<f32>>((default_vec2.align - 1) * 7, false),
-        ParamsFor<vec3<f32>>((default_vec3.align - 1) * 7, false),
-        ParamsFor<vec4<f32>>((default_vec4.align - 1) * 7, false),
-        ParamsFor<mat2x2<f32>>((default_mat2x2.align - 1) * 7, false),
-        ParamsFor<mat3x3<f32>>((default_mat3x3.align - 1) * 7, false),
-        ParamsFor<mat4x4<f32>>((default_mat4x4.align - 1) * 7, false)));
+                             // Fail because stride is not multiple of element alignment
+                             ParamsFor<u32>((default_u32.align - 1) * 7, false),
+                             ParamsFor<i32>((default_i32.align - 1) * 7, false),
+                             ParamsFor<f32>((default_f32.align - 1) * 7, false),
+                             ParamsFor<vec2<f32>>((default_vec2.align - 1) * 7, false),
+                             ParamsFor<vec3<f32>>((default_vec3.align - 1) * 7, false),
+                             ParamsFor<vec4<f32>>((default_vec4.align - 1) * 7, false),
+                             ParamsFor<mat2x2<f32>>((default_mat2x2.align - 1) * 7, false),
+                             ParamsFor<mat3x3<f32>>((default_mat3x3.align - 1) * 7, false),
+                             ParamsFor<mat4x4<f32>>((default_mat4x4.align - 1) * 7, false)));
 
 TEST_F(ArrayStrideTest, DuplicateAttribute) {
-  auto* arr = ty.array(Source{{12, 34}}, ty.i32(), 4,
-                       {
-                           create<ast::StrideAttribute>(Source{{12, 34}}, 4),
-                           create<ast::StrideAttribute>(Source{{56, 78}}, 4),
-                       });
+    auto* arr = ty.array(Source{{12, 34}}, ty.i32(), 4_u,
+                         {
+                             create<ast::StrideAttribute>(Source{{12, 34}}, 4_i),
+                             create<ast::StrideAttribute>(Source{{56, 78}}, 4_i),
+                         });
 
-  Global("myarray", arr, ast::StorageClass::kPrivate);
+    Global("myarray", arr, ast::StorageClass::kPrivate);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            R"(56:78 error: duplicate stride attribute
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(56:78 error: duplicate stride attribute
 12:34 note: first attribute declared here)");
 }
 
@@ -937,147 +894,132 @@
 
 using ResourceAttributeTest = ResolverTest;
 TEST_F(ResourceAttributeTest, UniformBufferMissingBinding) {
-  auto* s = Structure("S", {Member("x", ty.i32())});
-  Global(Source{{12, 34}}, "G", ty.Of(s), ast::StorageClass::kUniform);
+    auto* s = Structure("S", {Member("x", ty.i32())});
+    Global(Source{{12, 34}}, "G", ty.Of(s), ast::StorageClass::kUniform);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: resource variables require @group and @binding attributes)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: resource variables require @group and @binding attributes)");
 }
 
 TEST_F(ResourceAttributeTest, StorageBufferMissingBinding) {
-  auto* s = Structure("S", {Member("x", ty.i32())});
-  Global(Source{{12, 34}}, "G", ty.Of(s), ast::StorageClass::kStorage,
-         ast::Access::kRead);
+    auto* s = Structure("S", {Member("x", ty.i32())});
+    Global(Source{{12, 34}}, "G", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: resource variables require @group and @binding attributes)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: resource variables require @group and @binding attributes)");
 }
 
 TEST_F(ResourceAttributeTest, TextureMissingBinding) {
-  Global(Source{{12, 34}}, "G", ty.depth_texture(ast::TextureDimension::k2d),
-         ast::StorageClass::kNone);
+    Global(Source{{12, 34}}, "G", ty.depth_texture(ast::TextureDimension::k2d),
+           ast::StorageClass::kNone);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: resource variables require @group and @binding attributes)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: resource variables require @group and @binding attributes)");
 }
 
 TEST_F(ResourceAttributeTest, SamplerMissingBinding) {
-  Global(Source{{12, 34}}, "G", ty.sampler(ast::SamplerKind::kSampler),
-         ast::StorageClass::kNone);
+    Global(Source{{12, 34}}, "G", ty.sampler(ast::SamplerKind::kSampler), ast::StorageClass::kNone);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: resource variables require @group and @binding attributes)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: resource variables require @group and @binding attributes)");
 }
 
 TEST_F(ResourceAttributeTest, BindingPairMissingBinding) {
-  Global(Source{{12, 34}}, "G", ty.sampler(ast::SamplerKind::kSampler),
-         ast::StorageClass::kNone,
-         ast::AttributeList{
-             create<ast::GroupAttribute>(1),
-         });
+    Global(Source{{12, 34}}, "G", ty.sampler(ast::SamplerKind::kSampler), ast::StorageClass::kNone,
+           ast::AttributeList{
+               create<ast::GroupAttribute>(1),
+           });
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: resource variables require @group and @binding attributes)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: resource variables require @group and @binding attributes)");
 }
 
 TEST_F(ResourceAttributeTest, BindingPairMissingGroup) {
-  Global(Source{{12, 34}}, "G", ty.sampler(ast::SamplerKind::kSampler),
-         ast::StorageClass::kNone,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(1),
-         });
+    Global(Source{{12, 34}}, "G", ty.sampler(ast::SamplerKind::kSampler), ast::StorageClass::kNone,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(1),
+           });
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: resource variables require @group and @binding attributes)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: resource variables require @group and @binding attributes)");
 }
 
 TEST_F(ResourceAttributeTest, BindingPointUsedTwiceByEntryPoint) {
-  Global(Source{{12, 34}}, "A",
-         ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
-         ast::StorageClass::kNone,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(1),
-             create<ast::GroupAttribute>(2),
-         });
-  Global(Source{{56, 78}}, "B",
-         ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
-         ast::StorageClass::kNone,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(1),
-             create<ast::GroupAttribute>(2),
-         });
+    Global(Source{{12, 34}}, "A", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
+           ast::StorageClass::kNone,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(1),
+               create<ast::GroupAttribute>(2),
+           });
+    Global(Source{{56, 78}}, "B", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
+           ast::StorageClass::kNone,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(1),
+               create<ast::GroupAttribute>(2),
+           });
 
-  Func("F", {}, ty.void_(),
-       {
-           Decl(Var("a", ty.vec4<f32>(), ast::StorageClass::kNone,
-                    Call("textureLoad", "A", vec2<i32>(1, 2), 0))),
-           Decl(Var("b", ty.vec4<f32>(), ast::StorageClass::kNone,
-                    Call("textureLoad", "B", vec2<i32>(1, 2), 0))),
-       },
-       {Stage(ast::PipelineStage::kFragment)});
+    Func("F", {}, ty.void_(),
+         {
+             Decl(Var("a", ty.vec4<f32>(), ast::StorageClass::kNone,
+                      Call("textureLoad", "A", vec2<i32>(1_i, 2_i), 0_i))),
+             Decl(Var("b", ty.vec4<f32>(), ast::StorageClass::kNone,
+                      Call("textureLoad", "B", vec2<i32>(1_i, 2_i), 0_i))),
+         },
+         {Stage(ast::PipelineStage::kFragment)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(56:78 error: entry point 'F' references multiple variables that use the same resource binding @group(2), @binding(1)
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(
+        r()->error(),
+        R"(56:78 error: entry point 'F' references multiple variables that use the same resource binding @group(2), @binding(1)
 12:34 note: first resource binding usage declared here)");
 }
 
 TEST_F(ResourceAttributeTest, BindingPointUsedTwiceByDifferentEntryPoints) {
-  Global(Source{{12, 34}}, "A",
-         ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
-         ast::StorageClass::kNone,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(1),
-             create<ast::GroupAttribute>(2),
-         });
-  Global(Source{{56, 78}}, "B",
-         ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
-         ast::StorageClass::kNone,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(1),
-             create<ast::GroupAttribute>(2),
-         });
+    Global(Source{{12, 34}}, "A", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
+           ast::StorageClass::kNone,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(1),
+               create<ast::GroupAttribute>(2),
+           });
+    Global(Source{{56, 78}}, "B", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
+           ast::StorageClass::kNone,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(1),
+               create<ast::GroupAttribute>(2),
+           });
 
-  Func("F_A", {}, ty.void_(),
-       {
-           Decl(Var("a", ty.vec4<f32>(), ast::StorageClass::kNone,
-                    Call("textureLoad", "A", vec2<i32>(1, 2), 0))),
-       },
-       {Stage(ast::PipelineStage::kFragment)});
-  Func("F_B", {}, ty.void_(),
-       {
-           Decl(Var("b", ty.vec4<f32>(), ast::StorageClass::kNone,
-                    Call("textureLoad", "B", vec2<i32>(1, 2), 0))),
-       },
-       {Stage(ast::PipelineStage::kFragment)});
+    Func("F_A", {}, ty.void_(),
+         {
+             Decl(Var("a", ty.vec4<f32>(), ast::StorageClass::kNone,
+                      Call("textureLoad", "A", vec2<i32>(1_i, 2_i), 0_i))),
+         },
+         {Stage(ast::PipelineStage::kFragment)});
+    Func("F_B", {}, ty.void_(),
+         {
+             Decl(Var("b", ty.vec4<f32>(), ast::StorageClass::kNone,
+                      Call("textureLoad", "B", vec2<i32>(1_i, 2_i), 0_i))),
+         },
+         {Stage(ast::PipelineStage::kFragment)});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResourceAttributeTest, BindingPointOnNonResource) {
-  Global(Source{{12, 34}}, "G", ty.f32(), ast::StorageClass::kPrivate,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(1),
-             create<ast::GroupAttribute>(2),
-         });
+    Global(Source{{12, 34}}, "G", ty.f32(), ast::StorageClass::kPrivate,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(1),
+               create<ast::GroupAttribute>(2),
+           });
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: non-resource variables must not have @group or @binding attributes)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: non-resource variables must not have @group or @binding attributes)");
 }
 
 }  // namespace
@@ -1087,31 +1029,30 @@
 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)});
-  Func("main", ast::VariableList{param}, ty.vec4<f32>(),
-       ast::StatementList{Return(Construct(ty.vec4<f32>()))},
-       ast::AttributeList{Stage(ast::PipelineStage::kFragment)},
-       ast::AttributeList{
-           Location(0),
-       });
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* param =
+        Param("p", ty.vec4<f32>(),
+              {Invariant(Source{{12, 34}}), Builtin(Source{{56, 78}}, ast::Builtin::kPosition)});
+    Func("main", ast::VariableList{param}, ty.vec4<f32>(),
+         ast::StatementList{Return(Construct(ty.vec4<f32>()))},
+         ast::AttributeList{Stage(ast::PipelineStage::kFragment)},
+         ast::AttributeList{
+             Location(0),
+         });
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(InvariantAttributeTests, InvariantWithoutPosition) {
-  auto* param =
-      Param("p", ty.vec4<f32>(), {Invariant(Source{{12, 34}}), Location(0)});
-  Func("main", ast::VariableList{param}, ty.vec4<f32>(),
-       ast::StatementList{Return(Construct(ty.vec4<f32>()))},
-       ast::AttributeList{Stage(ast::PipelineStage::kFragment)},
-       ast::AttributeList{
-           Location(0),
-       });
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: invariant attribute must only be applied to a "
-            "position builtin");
+    auto* param = Param("p", ty.vec4<f32>(), {Invariant(Source{{12, 34}}), Location(0)});
+    Func("main", ast::VariableList{param}, ty.vec4<f32>(),
+         ast::StatementList{Return(Construct(ty.vec4<f32>()))},
+         ast::AttributeList{Stage(ast::PipelineStage::kFragment)},
+         ast::AttributeList{
+             Location(0),
+         });
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: invariant attribute must only be applied to a "
+              "position builtin");
 }
 }  // namespace
 }  // namespace InvariantAttributeTests
@@ -1121,56 +1062,54 @@
 
 using WorkgroupAttribute = ResolverTest;
 TEST_F(WorkgroupAttribute, ComputeShaderPass) {
-  Func("main", {}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kCompute),
-        create<ast::WorkgroupAttribute>(Source{{12, 34}}, Expr(1))});
+    Func("main", {}, ty.void_(), {},
+         {Stage(ast::PipelineStage::kCompute),
+          create<ast::WorkgroupAttribute>(Source{{12, 34}}, Expr(1_i))});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(WorkgroupAttribute, Missing) {
-  Func(Source{{12, 34}}, "main", {}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kCompute)});
+    Func(Source{{12, 34}}, "main", {}, ty.void_(), {}, {Stage(ast::PipelineStage::kCompute)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: a compute shader must include 'workgroup_size' in its "
-      "attributes");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: a compute shader must include 'workgroup_size' in its "
+              "attributes");
 }
 
 TEST_F(WorkgroupAttribute, NotAnEntryPoint) {
-  Func("main", {}, ty.void_(), {},
-       {create<ast::WorkgroupAttribute>(Source{{12, 34}}, Expr(1))});
+    Func("main", {}, ty.void_(), {},
+         {create<ast::WorkgroupAttribute>(Source{{12, 34}}, Expr(1_i))});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: the workgroup_size attribute is only valid for "
-            "compute stages");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: the workgroup_size attribute is only valid for "
+              "compute stages");
 }
 
 TEST_F(WorkgroupAttribute, NotAComputeShader) {
-  Func("main", {}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kFragment),
-        create<ast::WorkgroupAttribute>(Source{{12, 34}}, Expr(1))});
+    Func("main", {}, ty.void_(), {},
+         {Stage(ast::PipelineStage::kFragment),
+          create<ast::WorkgroupAttribute>(Source{{12, 34}}, Expr(1_i))});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: the workgroup_size attribute is only valid for "
-            "compute stages");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: the workgroup_size attribute is only valid for "
+              "compute stages");
 }
 
 TEST_F(WorkgroupAttribute, DuplicateAttribute) {
-  Func(Source{{12, 34}}, "main", {}, ty.void_(), {},
-       {
-           Stage(ast::PipelineStage::kCompute),
-           WorkgroupSize(Source{{12, 34}}, 1, nullptr, nullptr),
-           WorkgroupSize(Source{{56, 78}}, 2, nullptr, nullptr),
-       });
+    Func(Source{{12, 34}}, "main", {}, ty.void_(), {},
+         {
+             Stage(ast::PipelineStage::kCompute),
+             WorkgroupSize(Source{{12, 34}}, 1_i, nullptr, nullptr),
+             WorkgroupSize(Source{{56, 78}}, 2_i, nullptr, nullptr),
+         });
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            R"(56:78 error: duplicate workgroup_size attribute
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(56:78 error: duplicate workgroup_size attribute
 12:34 note: first attribute declared here)");
 }
 
@@ -1183,184 +1122,157 @@
 using InterpolateTest = ResolverTest;
 
 struct Params {
-  ast::InterpolationType type;
-  ast::InterpolationSampling sampling;
-  bool should_pass;
+    ast::InterpolationType type;
+    ast::InterpolationSampling sampling;
+    bool should_pass;
 };
 
 struct TestWithParams : ResolverTestWithParam<Params> {};
 
 using InterpolateParameterTest = TestWithParams;
 TEST_P(InterpolateParameterTest, All) {
-  auto& params = GetParam();
+    auto& params = GetParam();
 
-  Func("main",
-       ast::VariableList{Param(
-           "a", ty.f32(),
-           {Location(0),
-            Interpolate(Source{{12, 34}}, params.type, params.sampling)})},
-       ty.void_(), {},
-       ast::AttributeList{Stage(ast::PipelineStage::kFragment)});
+    Func("main",
+         ast::VariableList{
+             Param("a", ty.f32(),
+                   {Location(0), Interpolate(Source{{12, 34}}, params.type, params.sampling)})},
+         ty.void_(), {}, ast::AttributeList{Stage(ast::PipelineStage::kFragment)});
 
-  if (params.should_pass) {
-    EXPECT_TRUE(r()->Resolve()) << r()->error();
-  } else {
-    EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              "12:34 error: flat interpolation attribute must not have a "
-              "sampling parameter");
-  }
+    if (params.should_pass) {
+        EXPECT_TRUE(r()->Resolve()) << r()->error();
+    } else {
+        EXPECT_FALSE(r()->Resolve());
+        EXPECT_EQ(r()->error(),
+                  "12:34 error: flat interpolation attribute must not have a "
+                  "sampling parameter");
+    }
 }
 
 TEST_P(InterpolateParameterTest, IntegerScalar) {
-  auto& params = GetParam();
+    auto& params = GetParam();
 
-  Func("main",
-       ast::VariableList{Param(
-           "a", ty.i32(),
-           {Location(0),
-            Interpolate(Source{{12, 34}}, params.type, params.sampling)})},
-       ty.void_(), {},
-       ast::AttributeList{Stage(ast::PipelineStage::kFragment)});
+    Func("main",
+         ast::VariableList{
+             Param("a", ty.i32(),
+                   {Location(0), Interpolate(Source{{12, 34}}, params.type, params.sampling)})},
+         ty.void_(), {}, ast::AttributeList{Stage(ast::PipelineStage::kFragment)});
 
-  if (params.type != ast::InterpolationType::kFlat) {
-    EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              "12:34 error: interpolation type must be 'flat' for integral "
-              "user-defined IO types");
-  } else if (params.should_pass) {
-    EXPECT_TRUE(r()->Resolve()) << r()->error();
-  } else {
-    EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              "12:34 error: flat interpolation attribute must not have a "
-              "sampling parameter");
-  }
+    if (params.type != ast::InterpolationType::kFlat) {
+        EXPECT_FALSE(r()->Resolve());
+        EXPECT_EQ(r()->error(),
+                  "12:34 error: interpolation type must be 'flat' for integral "
+                  "user-defined IO types");
+    } else if (params.should_pass) {
+        EXPECT_TRUE(r()->Resolve()) << r()->error();
+    } else {
+        EXPECT_FALSE(r()->Resolve());
+        EXPECT_EQ(r()->error(),
+                  "12:34 error: flat interpolation attribute must not have a "
+                  "sampling parameter");
+    }
 }
 
 TEST_P(InterpolateParameterTest, IntegerVector) {
-  auto& params = GetParam();
+    auto& params = GetParam();
 
-  Func("main",
-       ast::VariableList{Param(
-           "a", ty.vec4<u32>(),
-           {Location(0),
-            Interpolate(Source{{12, 34}}, params.type, params.sampling)})},
-       ty.void_(), {},
-       ast::AttributeList{Stage(ast::PipelineStage::kFragment)});
+    Func("main",
+         ast::VariableList{
+             Param("a", ty.vec4<u32>(),
+                   {Location(0), Interpolate(Source{{12, 34}}, params.type, params.sampling)})},
+         ty.void_(), {}, ast::AttributeList{Stage(ast::PipelineStage::kFragment)});
 
-  if (params.type != ast::InterpolationType::kFlat) {
-    EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              "12:34 error: interpolation type must be 'flat' for integral "
-              "user-defined IO types");
-  } else if (params.should_pass) {
-    EXPECT_TRUE(r()->Resolve()) << r()->error();
-  } else {
-    EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              "12:34 error: flat interpolation attribute must not have a "
-              "sampling parameter");
-  }
+    if (params.type != ast::InterpolationType::kFlat) {
+        EXPECT_FALSE(r()->Resolve());
+        EXPECT_EQ(r()->error(),
+                  "12:34 error: interpolation type must be 'flat' for integral "
+                  "user-defined IO types");
+    } else if (params.should_pass) {
+        EXPECT_TRUE(r()->Resolve()) << r()->error();
+    } else {
+        EXPECT_FALSE(r()->Resolve());
+        EXPECT_EQ(r()->error(),
+                  "12:34 error: flat interpolation attribute must not have a "
+                  "sampling parameter");
+    }
 }
 
 INSTANTIATE_TEST_SUITE_P(
     ResolverAttributeValidationTest,
     InterpolateParameterTest,
-    testing::Values(Params{ast::InterpolationType::kPerspective,
-                           ast::InterpolationSampling::kNone, true},
-                    Params{ast::InterpolationType::kPerspective,
-                           ast::InterpolationSampling::kCenter, true},
-                    Params{ast::InterpolationType::kPerspective,
-                           ast::InterpolationSampling::kCentroid, true},
-                    Params{ast::InterpolationType::kPerspective,
-                           ast::InterpolationSampling::kSample, true},
-                    Params{ast::InterpolationType::kLinear,
-                           ast::InterpolationSampling::kNone, true},
-                    Params{ast::InterpolationType::kLinear,
-                           ast::InterpolationSampling::kCenter, true},
-                    Params{ast::InterpolationType::kLinear,
-                           ast::InterpolationSampling::kCentroid, true},
-                    Params{ast::InterpolationType::kLinear,
-                           ast::InterpolationSampling::kSample, true},
-                    // flat interpolation must not have a sampling type
-                    Params{ast::InterpolationType::kFlat,
-                           ast::InterpolationSampling::kNone, true},
-                    Params{ast::InterpolationType::kFlat,
-                           ast::InterpolationSampling::kCenter, false},
-                    Params{ast::InterpolationType::kFlat,
-                           ast::InterpolationSampling::kCentroid, false},
-                    Params{ast::InterpolationType::kFlat,
-                           ast::InterpolationSampling::kSample, false}));
+    testing::Values(
+        Params{ast::InterpolationType::kPerspective, ast::InterpolationSampling::kNone, true},
+        Params{ast::InterpolationType::kPerspective, ast::InterpolationSampling::kCenter, true},
+        Params{ast::InterpolationType::kPerspective, ast::InterpolationSampling::kCentroid, true},
+        Params{ast::InterpolationType::kPerspective, ast::InterpolationSampling::kSample, true},
+        Params{ast::InterpolationType::kLinear, ast::InterpolationSampling::kNone, true},
+        Params{ast::InterpolationType::kLinear, ast::InterpolationSampling::kCenter, true},
+        Params{ast::InterpolationType::kLinear, ast::InterpolationSampling::kCentroid, true},
+        Params{ast::InterpolationType::kLinear, ast::InterpolationSampling::kSample, true},
+        // flat interpolation must not have a sampling type
+        Params{ast::InterpolationType::kFlat, ast::InterpolationSampling::kNone, true},
+        Params{ast::InterpolationType::kFlat, ast::InterpolationSampling::kCenter, false},
+        Params{ast::InterpolationType::kFlat, ast::InterpolationSampling::kCentroid, false},
+        Params{ast::InterpolationType::kFlat, ast::InterpolationSampling::kSample, false}));
 
 TEST_F(InterpolateTest, FragmentInput_Integer_MissingFlatInterpolation) {
-  Func("main",
-       ast::VariableList{Param(Source{{12, 34}}, "a", ty.i32(), {Location(0)})},
-       ty.void_(), {},
-       ast::AttributeList{Stage(ast::PipelineStage::kFragment)});
+    Func("main", ast::VariableList{Param(Source{{12, 34}}, "a", ty.i32(), {Location(0)})},
+         ty.void_(), {}, ast::AttributeList{Stage(ast::PipelineStage::kFragment)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: integral user-defined fragment inputs must have a flat interpolation attribute)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(
+        r()->error(),
+        R"(12:34 error: integral user-defined fragment inputs must have a flat interpolation attribute)");
 }
 
 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)}),
-      });
-  Func("main", {}, ty.Of(s), {Return(Construct(ty.Of(s)))},
-       ast::AttributeList{Stage(ast::PipelineStage::kVertex)});
+    auto* s = Structure("S", {
+                                 Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)}),
+                                 Member(Source{{12, 34}}, "u", ty.u32(), {Location(0)}),
+                             });
+    Func("main", {}, ty.Of(s), {Return(Construct(ty.Of(s)))},
+         ast::AttributeList{Stage(ast::PipelineStage::kVertex)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: integral user-defined vertex outputs must have a flat interpolation attribute
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(
+        r()->error(),
+        R"(12:34 error: integral user-defined vertex outputs must have a flat interpolation attribute
 note: while analysing entry point 'main')");
 }
 
 TEST_F(InterpolateTest, MissingLocationAttribute_Parameter) {
-  Func("main",
-       ast::VariableList{
-           Param("a", ty.vec4<f32>(),
-                 {Builtin(ast::Builtin::kPosition),
-                  Interpolate(Source{{12, 34}}, ast::InterpolationType::kFlat,
-                              ast::InterpolationSampling::kNone)})},
-       ty.void_(), {},
-       ast::AttributeList{Stage(ast::PipelineStage::kFragment)});
+    Func("main",
+         ast::VariableList{Param("a", ty.vec4<f32>(),
+                                 {Builtin(ast::Builtin::kPosition),
+                                  Interpolate(Source{{12, 34}}, ast::InterpolationType::kFlat,
+                                              ast::InterpolationSampling::kNone)})},
+         ty.void_(), {}, ast::AttributeList{Stage(ast::PipelineStage::kFragment)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: interpolate attribute must only be used with @location)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: interpolate attribute must only be used with @location)");
 }
 
 TEST_F(InterpolateTest, MissingLocationAttribute_ReturnType) {
-  Func("main", {}, ty.vec4<f32>(), {Return(Construct(ty.vec4<f32>()))},
-       ast::AttributeList{Stage(ast::PipelineStage::kVertex)},
-       {Builtin(ast::Builtin::kPosition),
-        Interpolate(Source{{12, 34}}, ast::InterpolationType::kFlat,
-                    ast::InterpolationSampling::kNone)});
+    Func("main", {}, ty.vec4<f32>(), {Return(Construct(ty.vec4<f32>()))},
+         ast::AttributeList{Stage(ast::PipelineStage::kVertex)},
+         {Builtin(ast::Builtin::kPosition),
+          Interpolate(Source{{12, 34}}, ast::InterpolationType::kFlat,
+                      ast::InterpolationSampling::kNone)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: interpolate attribute must only be used with @location)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: interpolate attribute must only be used with @location)");
 }
 
 TEST_F(InterpolateTest, MissingLocationAttribute_Struct) {
-  Structure(
-      "S", {Member("a", ty.f32(),
-                   {Interpolate(Source{{12, 34}}, ast::InterpolationType::kFlat,
-                                ast::InterpolationSampling::kNone)})});
+    Structure("S", {Member("a", ty.f32(),
+                           {Interpolate(Source{{12, 34}}, ast::InterpolationType::kFlat,
+                                        ast::InterpolationSampling::kNone)})});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: interpolate attribute must only be used with @location)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: interpolate attribute must only be used with @location)");
 }
 
 }  // namespace
diff --git a/src/tint/resolver/bitcast_validation_test.cc b/src/tint/resolver/bitcast_validation_test.cc
index b7b7e9e..78223fc 100644
--- a/src/tint/resolver/bitcast_validation_test.cc
+++ b/src/tint/resolver/bitcast_validation_test.cc
@@ -22,36 +22,36 @@
 namespace {
 
 struct Type {
-  template <typename T>
-  static constexpr Type Create() {
-    return Type{builder::DataType<T>::AST, builder::DataType<T>::Sem,
-                builder::DataType<T>::Expr};
-  }
+    template <typename T>
+    static constexpr Type Create() {
+        return Type{builder::DataType<T>::AST, builder::DataType<T>::Sem,
+                    builder::DataType<T>::Expr};
+    }
 
-  builder::ast_type_func_ptr ast;
-  builder::sem_type_func_ptr sem;
-  builder::ast_expr_func_ptr expr;
+    builder::ast_type_func_ptr ast;
+    builder::sem_type_func_ptr sem;
+    builder::ast_expr_func_ptr expr;
 };
 
 static constexpr Type kNumericScalars[] = {
-    Type::Create<builder::f32>(),
-    Type::Create<builder::i32>(),
-    Type::Create<builder::u32>(),
+    Type::Create<f32>(),
+    Type::Create<i32>(),
+    Type::Create<u32>(),
 };
 static constexpr Type kVec2NumericScalars[] = {
-    Type::Create<builder::vec2<builder::f32>>(),
-    Type::Create<builder::vec2<builder::i32>>(),
-    Type::Create<builder::vec2<builder::u32>>(),
+    Type::Create<builder::vec2<f32>>(),
+    Type::Create<builder::vec2<i32>>(),
+    Type::Create<builder::vec2<u32>>(),
 };
 static constexpr Type kVec3NumericScalars[] = {
-    Type::Create<builder::vec3<builder::f32>>(),
-    Type::Create<builder::vec3<builder::i32>>(),
-    Type::Create<builder::vec3<builder::u32>>(),
+    Type::Create<builder::vec3<f32>>(),
+    Type::Create<builder::vec3<i32>>(),
+    Type::Create<builder::vec3<u32>>(),
 };
 static constexpr Type kVec4NumericScalars[] = {
-    Type::Create<builder::vec4<builder::f32>>(),
-    Type::Create<builder::vec4<builder::i32>>(),
-    Type::Create<builder::vec4<builder::u32>>(),
+    Type::Create<builder::vec4<f32>>(),
+    Type::Create<builder::vec4<i32>>(),
+    Type::Create<builder::vec4<u32>>(),
 };
 static constexpr Type kInvalid[] = {
     // A non-exhaustive selection of uncastable types
@@ -59,168 +59,152 @@
     Type::Create<builder::vec2<bool>>(),
     Type::Create<builder::vec3<bool>>(),
     Type::Create<builder::vec4<bool>>(),
-    Type::Create<builder::array<2, builder::i32>>(),
-    Type::Create<builder::array<3, builder::u32>>(),
-    Type::Create<builder::array<4, builder::f32>>(),
+    Type::Create<builder::array<2, i32>>(),
+    Type::Create<builder::array<3, u32>>(),
+    Type::Create<builder::array<4, f32>>(),
     Type::Create<builder::array<5, bool>>(),
-    Type::Create<builder::mat2x2<builder::f32>>(),
-    Type::Create<builder::mat3x3<builder::f32>>(),
-    Type::Create<builder::mat4x4<builder::f32>>(),
-    Type::Create<builder::ptr<builder::i32>>(),
-    Type::Create<builder::ptr<builder::array<2, builder::i32>>>(),
-    Type::Create<builder::ptr<builder::mat2x2<builder::f32>>>(),
+    Type::Create<builder::mat2x2<f32>>(),
+    Type::Create<builder::mat3x3<f32>>(),
+    Type::Create<builder::mat4x4<f32>>(),
+    Type::Create<builder::ptr<i32>>(),
+    Type::Create<builder::ptr<builder::array<2, i32>>>(),
+    Type::Create<builder::ptr<builder::mat2x2<f32>>>(),
 };
 
-using ResolverBitcastValidationTest =
-    ResolverTestWithParam<std::tuple<Type, Type>>;
+using ResolverBitcastValidationTest = ResolverTestWithParam<std::tuple<Type, Type>>;
 
 ////////////////////////////////////////////////////////////////////////////////
 // Valid bitcasts
 ////////////////////////////////////////////////////////////////////////////////
 using ResolverBitcastValidationTestPass = ResolverBitcastValidationTest;
 TEST_P(ResolverBitcastValidationTestPass, Test) {
-  auto src = std::get<0>(GetParam());
-  auto dst = std::get<1>(GetParam());
+    auto src = std::get<0>(GetParam());
+    auto dst = std::get<1>(GetParam());
 
-  auto* cast = Bitcast(dst.ast(*this), src.expr(*this, 0));
-  WrapInFunction(cast);
+    auto* cast = Bitcast(dst.ast(*this), src.expr(*this, 0));
+    WrapInFunction(cast);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
-  EXPECT_EQ(TypeOf(cast), dst.sem(*this));
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_EQ(TypeOf(cast), dst.sem(*this));
 }
 INSTANTIATE_TEST_SUITE_P(Scalars,
                          ResolverBitcastValidationTestPass,
                          testing::Combine(testing::ValuesIn(kNumericScalars),
                                           testing::ValuesIn(kNumericScalars)));
-INSTANTIATE_TEST_SUITE_P(
-    Vec2,
-    ResolverBitcastValidationTestPass,
-    testing::Combine(testing::ValuesIn(kVec2NumericScalars),
-                     testing::ValuesIn(kVec2NumericScalars)));
-INSTANTIATE_TEST_SUITE_P(
-    Vec3,
-    ResolverBitcastValidationTestPass,
-    testing::Combine(testing::ValuesIn(kVec3NumericScalars),
-                     testing::ValuesIn(kVec3NumericScalars)));
-INSTANTIATE_TEST_SUITE_P(
-    Vec4,
-    ResolverBitcastValidationTestPass,
-    testing::Combine(testing::ValuesIn(kVec4NumericScalars),
-                     testing::ValuesIn(kVec4NumericScalars)));
+INSTANTIATE_TEST_SUITE_P(Vec2,
+                         ResolverBitcastValidationTestPass,
+                         testing::Combine(testing::ValuesIn(kVec2NumericScalars),
+                                          testing::ValuesIn(kVec2NumericScalars)));
+INSTANTIATE_TEST_SUITE_P(Vec3,
+                         ResolverBitcastValidationTestPass,
+                         testing::Combine(testing::ValuesIn(kVec3NumericScalars),
+                                          testing::ValuesIn(kVec3NumericScalars)));
+INSTANTIATE_TEST_SUITE_P(Vec4,
+                         ResolverBitcastValidationTestPass,
+                         testing::Combine(testing::ValuesIn(kVec4NumericScalars),
+                                          testing::ValuesIn(kVec4NumericScalars)));
 
 ////////////////////////////////////////////////////////////////////////////////
 // Invalid source type for bitcasts
 ////////////////////////////////////////////////////////////////////////////////
 using ResolverBitcastValidationTestInvalidSrcTy = ResolverBitcastValidationTest;
 TEST_P(ResolverBitcastValidationTestInvalidSrcTy, Test) {
-  auto src = std::get<0>(GetParam());
-  auto dst = std::get<1>(GetParam());
+    auto src = std::get<0>(GetParam());
+    auto dst = std::get<1>(GetParam());
 
-  auto* cast = Bitcast(dst.ast(*this), Expr(Source{{12, 34}}, "src"));
-  WrapInFunction(Const("src", nullptr, src.expr(*this, 0)), cast);
+    auto* cast = Bitcast(dst.ast(*this), Expr(Source{{12, 34}}, "src"));
+    WrapInFunction(Let("src", nullptr, src.expr(*this, 0)), cast);
 
-  auto expected = "12:34 error: '" + src.sem(*this)->FriendlyName(Symbols()) +
-                  "' cannot be bitcast";
+    auto expected =
+        "12:34 error: '" + src.sem(*this)->FriendlyName(Symbols()) + "' cannot be bitcast";
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), expected);
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), expected);
 }
 INSTANTIATE_TEST_SUITE_P(Scalars,
                          ResolverBitcastValidationTestInvalidSrcTy,
                          testing::Combine(testing::ValuesIn(kInvalid),
                                           testing::ValuesIn(kNumericScalars)));
-INSTANTIATE_TEST_SUITE_P(
-    Vec2,
-    ResolverBitcastValidationTestInvalidSrcTy,
-    testing::Combine(testing::ValuesIn(kInvalid),
-                     testing::ValuesIn(kVec2NumericScalars)));
-INSTANTIATE_TEST_SUITE_P(
-    Vec3,
-    ResolverBitcastValidationTestInvalidSrcTy,
-    testing::Combine(testing::ValuesIn(kInvalid),
-                     testing::ValuesIn(kVec3NumericScalars)));
-INSTANTIATE_TEST_SUITE_P(
-    Vec4,
-    ResolverBitcastValidationTestInvalidSrcTy,
-    testing::Combine(testing::ValuesIn(kInvalid),
-                     testing::ValuesIn(kVec4NumericScalars)));
+INSTANTIATE_TEST_SUITE_P(Vec2,
+                         ResolverBitcastValidationTestInvalidSrcTy,
+                         testing::Combine(testing::ValuesIn(kInvalid),
+                                          testing::ValuesIn(kVec2NumericScalars)));
+INSTANTIATE_TEST_SUITE_P(Vec3,
+                         ResolverBitcastValidationTestInvalidSrcTy,
+                         testing::Combine(testing::ValuesIn(kInvalid),
+                                          testing::ValuesIn(kVec3NumericScalars)));
+INSTANTIATE_TEST_SUITE_P(Vec4,
+                         ResolverBitcastValidationTestInvalidSrcTy,
+                         testing::Combine(testing::ValuesIn(kInvalid),
+                                          testing::ValuesIn(kVec4NumericScalars)));
 
 ////////////////////////////////////////////////////////////////////////////////
 // Invalid target type for bitcasts
 ////////////////////////////////////////////////////////////////////////////////
 using ResolverBitcastValidationTestInvalidDstTy = ResolverBitcastValidationTest;
 TEST_P(ResolverBitcastValidationTestInvalidDstTy, Test) {
-  auto src = std::get<0>(GetParam());
-  auto dst = std::get<1>(GetParam());
+    auto src = std::get<0>(GetParam());
+    auto dst = std::get<1>(GetParam());
 
-  // Use an alias so we can put a Source on the bitcast type
-  Alias("T", dst.ast(*this));
-  WrapInFunction(
-      Bitcast(ty.type_name(Source{{12, 34}}, "T"), src.expr(*this, 0)));
+    // Use an alias so we can put a Source on the bitcast type
+    Alias("T", dst.ast(*this));
+    WrapInFunction(Bitcast(ty.type_name(Source{{12, 34}}, "T"), src.expr(*this, 0)));
 
-  auto expected = "12:34 error: cannot bitcast to '" +
-                  dst.sem(*this)->FriendlyName(Symbols()) + "'";
+    auto expected =
+        "12:34 error: cannot bitcast to '" + dst.sem(*this)->FriendlyName(Symbols()) + "'";
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), expected);
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), expected);
 }
 INSTANTIATE_TEST_SUITE_P(Scalars,
                          ResolverBitcastValidationTestInvalidDstTy,
                          testing::Combine(testing::ValuesIn(kNumericScalars),
                                           testing::ValuesIn(kInvalid)));
-INSTANTIATE_TEST_SUITE_P(
-    Vec2,
-    ResolverBitcastValidationTestInvalidDstTy,
-    testing::Combine(testing::ValuesIn(kVec2NumericScalars),
-                     testing::ValuesIn(kInvalid)));
-INSTANTIATE_TEST_SUITE_P(
-    Vec3,
-    ResolverBitcastValidationTestInvalidDstTy,
-    testing::Combine(testing::ValuesIn(kVec3NumericScalars),
-                     testing::ValuesIn(kInvalid)));
-INSTANTIATE_TEST_SUITE_P(
-    Vec4,
-    ResolverBitcastValidationTestInvalidDstTy,
-    testing::Combine(testing::ValuesIn(kVec4NumericScalars),
-                     testing::ValuesIn(kInvalid)));
+INSTANTIATE_TEST_SUITE_P(Vec2,
+                         ResolverBitcastValidationTestInvalidDstTy,
+                         testing::Combine(testing::ValuesIn(kVec2NumericScalars),
+                                          testing::ValuesIn(kInvalid)));
+INSTANTIATE_TEST_SUITE_P(Vec3,
+                         ResolverBitcastValidationTestInvalidDstTy,
+                         testing::Combine(testing::ValuesIn(kVec3NumericScalars),
+                                          testing::ValuesIn(kInvalid)));
+INSTANTIATE_TEST_SUITE_P(Vec4,
+                         ResolverBitcastValidationTestInvalidDstTy,
+                         testing::Combine(testing::ValuesIn(kVec4NumericScalars),
+                                          testing::ValuesIn(kInvalid)));
 
 ////////////////////////////////////////////////////////////////////////////////
 // Incompatible bitcast, but both src and dst types are valid
 ////////////////////////////////////////////////////////////////////////////////
 using ResolverBitcastValidationTestIncompatible = ResolverBitcastValidationTest;
 TEST_P(ResolverBitcastValidationTestIncompatible, Test) {
-  auto src = std::get<0>(GetParam());
-  auto dst = std::get<1>(GetParam());
+    auto src = std::get<0>(GetParam());
+    auto dst = std::get<1>(GetParam());
 
-  WrapInFunction(Bitcast(Source{{12, 34}}, dst.ast(*this), src.expr(*this, 0)));
+    WrapInFunction(Bitcast(Source{{12, 34}}, dst.ast(*this), src.expr(*this, 0)));
 
-  auto expected = "12:34 error: cannot bitcast from '" +
-                  src.sem(*this)->FriendlyName(Symbols()) + "' to '" +
-                  dst.sem(*this)->FriendlyName(Symbols()) + "'";
+    auto expected = "12:34 error: cannot bitcast from '" + src.sem(*this)->FriendlyName(Symbols()) +
+                    "' to '" + dst.sem(*this)->FriendlyName(Symbols()) + "'";
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), expected);
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), expected);
 }
-INSTANTIATE_TEST_SUITE_P(
-    ScalarToVec2,
-    ResolverBitcastValidationTestIncompatible,
-    testing::Combine(testing::ValuesIn(kNumericScalars),
-                     testing::ValuesIn(kVec2NumericScalars)));
-INSTANTIATE_TEST_SUITE_P(
-    Vec2ToVec3,
-    ResolverBitcastValidationTestIncompatible,
-    testing::Combine(testing::ValuesIn(kVec2NumericScalars),
-                     testing::ValuesIn(kVec3NumericScalars)));
-INSTANTIATE_TEST_SUITE_P(
-    Vec3ToVec4,
-    ResolverBitcastValidationTestIncompatible,
-    testing::Combine(testing::ValuesIn(kVec3NumericScalars),
-                     testing::ValuesIn(kVec4NumericScalars)));
-INSTANTIATE_TEST_SUITE_P(
-    Vec4ToScalar,
-    ResolverBitcastValidationTestIncompatible,
-    testing::Combine(testing::ValuesIn(kVec4NumericScalars),
-                     testing::ValuesIn(kNumericScalars)));
+INSTANTIATE_TEST_SUITE_P(ScalarToVec2,
+                         ResolverBitcastValidationTestIncompatible,
+                         testing::Combine(testing::ValuesIn(kNumericScalars),
+                                          testing::ValuesIn(kVec2NumericScalars)));
+INSTANTIATE_TEST_SUITE_P(Vec2ToVec3,
+                         ResolverBitcastValidationTestIncompatible,
+                         testing::Combine(testing::ValuesIn(kVec2NumericScalars),
+                                          testing::ValuesIn(kVec3NumericScalars)));
+INSTANTIATE_TEST_SUITE_P(Vec3ToVec4,
+                         ResolverBitcastValidationTestIncompatible,
+                         testing::Combine(testing::ValuesIn(kVec3NumericScalars),
+                                          testing::ValuesIn(kVec4NumericScalars)));
+INSTANTIATE_TEST_SUITE_P(Vec4ToScalar,
+                         ResolverBitcastValidationTestIncompatible,
+                         testing::Combine(testing::ValuesIn(kVec4NumericScalars),
+                                          testing::ValuesIn(kNumericScalars)));
 
 }  // namespace
 }  // namespace tint::resolver
diff --git a/src/tint/resolver/builtin_test.cc b/src/tint/resolver/builtin_test.cc
index 732e707..94684ba 100644
--- a/src/tint/resolver/builtin_test.cc
+++ b/src/tint/resolver/builtin_test.cc
@@ -32,13 +32,15 @@
 #include "src/tint/sem/call.h"
 #include "src/tint/sem/function.h"
 #include "src/tint/sem/member_accessor_expression.h"
-#include "src/tint/sem/sampled_texture_type.h"
+#include "src/tint/sem/sampled_texture.h"
 #include "src/tint/sem/statement.h"
 #include "src/tint/sem/variable.h"
 
 using ::testing::ElementsAre;
 using ::testing::HasSubstr;
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::resolver {
 namespace {
 
@@ -48,49 +50,48 @@
 
 using ResolverBuiltinDerivativeTest = ResolverTestWithParam<std::string>;
 TEST_P(ResolverBuiltinDerivativeTest, Scalar) {
-  auto name = GetParam();
+    auto name = GetParam();
 
-  Global("ident", ty.f32(), ast::StorageClass::kPrivate);
+    Global("ident", ty.f32(), ast::StorageClass::kPrivate);
 
-  auto* expr = Call(name, "ident");
-  Func("func", {}, ty.void_(), {Ignore(expr)},
-       {create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
+    auto* expr = Call(name, "ident");
+    Func("func", {}, ty.void_(), {Ignore(expr)},
+         {create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(expr), nullptr);
-  ASSERT_TRUE(TypeOf(expr)->Is<sem::F32>());
+    ASSERT_NE(TypeOf(expr), nullptr);
+    ASSERT_TRUE(TypeOf(expr)->Is<sem::F32>());
 }
 
 TEST_P(ResolverBuiltinDerivativeTest, Vector) {
-  auto name = GetParam();
-  Global("ident", ty.vec4<f32>(), ast::StorageClass::kPrivate);
+    auto name = GetParam();
+    Global("ident", ty.vec4<f32>(), ast::StorageClass::kPrivate);
 
-  auto* expr = Call(name, "ident");
-  Func("func", {}, ty.void_(), {Ignore(expr)},
-       {create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
+    auto* expr = Call(name, "ident");
+    Func("func", {}, ty.void_(), {Ignore(expr)},
+         {create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(expr), nullptr);
-  ASSERT_TRUE(TypeOf(expr)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(expr)->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(TypeOf(expr)->As<sem::Vector>()->Width(), 4u);
+    ASSERT_NE(TypeOf(expr), nullptr);
+    ASSERT_TRUE(TypeOf(expr)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(expr)->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(TypeOf(expr)->As<sem::Vector>()->Width(), 4u);
 }
 
 TEST_P(ResolverBuiltinDerivativeTest, MissingParam) {
-  auto name = GetParam();
+    auto name = GetParam();
 
-  auto* expr = Call(name);
-  WrapInFunction(expr);
+    auto* expr = Call(name);
+    WrapInFunction(expr);
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(r()->error(), "error: no matching call to " + name +
-                              "()\n\n"
-                              "2 candidate functions:\n  " +
-                              name + "(f32) -> f32\n  " + name +
-                              "(vecN<f32>) -> vecN<f32>\n");
+    EXPECT_EQ(r()->error(), "error: no matching call to " + name +
+                                "()\n\n"
+                                "2 candidate functions:\n  " +
+                                name + "(f32) -> f32\n  " + name + "(vecN<f32>) -> vecN<f32>\n");
 }
 
 INSTANTIATE_TEST_SUITE_P(ResolverTest,
@@ -107,30 +108,30 @@
 
 using ResolverBuiltinTest_BoolMethod = ResolverTestWithParam<std::string>;
 TEST_P(ResolverBuiltinTest_BoolMethod, Scalar) {
-  auto name = GetParam();
+    auto name = GetParam();
 
-  Global("my_var", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("my_var", ty.bool_(), ast::StorageClass::kPrivate);
 
-  auto* expr = Call(name, "my_var");
-  WrapInFunction(expr);
+    auto* expr = Call(name, "my_var");
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(expr), nullptr);
-  EXPECT_TRUE(TypeOf(expr)->Is<sem::Bool>());
+    ASSERT_NE(TypeOf(expr), nullptr);
+    EXPECT_TRUE(TypeOf(expr)->Is<sem::Bool>());
 }
 TEST_P(ResolverBuiltinTest_BoolMethod, Vector) {
-  auto name = GetParam();
+    auto name = GetParam();
 
-  Global("my_var", ty.vec3<bool>(), ast::StorageClass::kPrivate);
+    Global("my_var", ty.vec3<bool>(), ast::StorageClass::kPrivate);
 
-  auto* expr = Call(name, "my_var");
-  WrapInFunction(expr);
+    auto* expr = Call(name, "my_var");
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(expr), nullptr);
-  EXPECT_TRUE(TypeOf(expr)->Is<sem::Bool>());
+    ASSERT_NE(TypeOf(expr), nullptr);
+    EXPECT_TRUE(TypeOf(expr)->Is<sem::Bool>());
 }
 INSTANTIATE_TEST_SUITE_P(ResolverTest,
                          ResolverBuiltinTest_BoolMethod,
@@ -138,167 +139,161 @@
 
 enum class Texture { kF32, kI32, kU32 };
 inline std::ostream& operator<<(std::ostream& out, Texture data) {
-  if (data == Texture::kF32) {
-    out << "f32";
-  } else if (data == Texture::kI32) {
-    out << "i32";
-  } else {
-    out << "u32";
-  }
-  return out;
+    if (data == Texture::kF32) {
+        out << "f32";
+    } else if (data == Texture::kI32) {
+        out << "i32";
+    } else {
+        out << "u32";
+    }
+    return out;
 }
 
 struct TextureTestParams {
-  ast::TextureDimension dim;
-  Texture type = Texture::kF32;
-  ast::TexelFormat format = ast::TexelFormat::kR32Float;
+    ast::TextureDimension dim;
+    Texture type = Texture::kF32;
+    ast::TexelFormat format = ast::TexelFormat::kR32Float;
 };
 inline std::ostream& operator<<(std::ostream& out, TextureTestParams data) {
-  out << data.dim << "_" << data.type;
-  return out;
+    out << data.dim << "_" << data.type;
+    return out;
 }
 
-class ResolverBuiltinTest_TextureOperation
-    : public ResolverTestWithParam<TextureTestParams> {
- public:
-  /// Gets an appropriate type for the coords parameter depending the the
-  /// dimensionality of the texture being sampled.
-  /// @param dim dimensionality of the texture being sampled
-  /// @param scalar the scalar type
-  /// @returns a pointer to a type appropriate for the coord param
-  const ast::Type* GetCoordsType(ast::TextureDimension dim,
-                                 const ast::Type* scalar) {
-    switch (dim) {
-      case ast::TextureDimension::k1d:
-        return scalar;
-      case ast::TextureDimension::k2d:
-      case ast::TextureDimension::k2dArray:
-        return ty.vec(scalar, 2);
-      case ast::TextureDimension::k3d:
-      case ast::TextureDimension::kCube:
-      case ast::TextureDimension::kCubeArray:
-        return ty.vec(scalar, 3);
-      default:
-        [=]() { FAIL() << "Unsupported texture dimension: " << dim; }();
-    }
-    return nullptr;
-  }
-
-  void add_call_param(std::string name,
-                      const ast::Type* type,
-                      ast::ExpressionList* call_params) {
-    if (type->IsAnyOf<ast::Texture, ast::Sampler>()) {
-      Global(name, type,
-             ast::AttributeList{
-                 create<ast::BindingAttribute>(0),
-                 create<ast::GroupAttribute>(0),
-             });
-
-    } else {
-      Global(name, type, ast::StorageClass::kPrivate);
+class ResolverBuiltinTest_TextureOperation : public ResolverTestWithParam<TextureTestParams> {
+  public:
+    /// Gets an appropriate type for the coords parameter depending the the
+    /// dimensionality of the texture being sampled.
+    /// @param dim dimensionality of the texture being sampled
+    /// @param scalar the scalar type
+    /// @returns a pointer to a type appropriate for the coord param
+    const ast::Type* GetCoordsType(ast::TextureDimension dim, const ast::Type* scalar) {
+        switch (dim) {
+            case ast::TextureDimension::k1d:
+                return scalar;
+            case ast::TextureDimension::k2d:
+            case ast::TextureDimension::k2dArray:
+                return ty.vec(scalar, 2);
+            case ast::TextureDimension::k3d:
+            case ast::TextureDimension::kCube:
+            case ast::TextureDimension::kCubeArray:
+                return ty.vec(scalar, 3);
+            default:
+                [=]() { FAIL() << "Unsupported texture dimension: " << dim; }();
+        }
+        return nullptr;
     }
 
-    call_params->push_back(Expr(name));
-  }
-  const ast::Type* subtype(Texture type) {
-    if (type == Texture::kF32) {
-      return ty.f32();
+    void add_call_param(std::string name, const ast::Type* type, ast::ExpressionList* call_params) {
+        if (type->IsAnyOf<ast::Texture, ast::Sampler>()) {
+            Global(name, type,
+                   ast::AttributeList{
+                       create<ast::BindingAttribute>(0),
+                       create<ast::GroupAttribute>(0),
+                   });
+
+        } else {
+            Global(name, type, ast::StorageClass::kPrivate);
+        }
+
+        call_params->push_back(Expr(name));
     }
-    if (type == Texture::kI32) {
-      return ty.i32();
+    const ast::Type* subtype(Texture type) {
+        if (type == Texture::kF32) {
+            return ty.f32();
+        }
+        if (type == Texture::kI32) {
+            return ty.i32();
+        }
+        return ty.u32();
     }
-    return ty.u32();
-  }
 };
 
-using ResolverBuiltinTest_SampledTextureOperation =
-    ResolverBuiltinTest_TextureOperation;
+using ResolverBuiltinTest_SampledTextureOperation = ResolverBuiltinTest_TextureOperation;
 TEST_P(ResolverBuiltinTest_SampledTextureOperation, TextureLoadSampled) {
-  auto dim = GetParam().dim;
-  auto type = GetParam().type;
+    auto dim = GetParam().dim;
+    auto type = GetParam().type;
 
-  auto* s = subtype(type);
-  auto* coords_type = GetCoordsType(dim, ty.i32());
-  auto* texture_type = ty.sampled_texture(dim, s);
+    auto* s = subtype(type);
+    auto* coords_type = GetCoordsType(dim, ty.i32());
+    auto* texture_type = ty.sampled_texture(dim, s);
 
-  ast::ExpressionList call_params;
+    ast::ExpressionList call_params;
 
-  add_call_param("texture", texture_type, &call_params);
-  add_call_param("coords", coords_type, &call_params);
-  if (dim == ast::TextureDimension::k2dArray) {
-    add_call_param("array_index", ty.i32(), &call_params);
-  }
-  add_call_param("level", ty.i32(), &call_params);
+    add_call_param("texture", texture_type, &call_params);
+    add_call_param("coords", coords_type, &call_params);
+    if (dim == ast::TextureDimension::k2dArray) {
+        add_call_param("array_index", ty.i32(), &call_params);
+    }
+    add_call_param("level", ty.i32(), &call_params);
 
-  auto* expr = Call("textureLoad", call_params);
-  WrapInFunction(expr);
+    auto* expr = Call("textureLoad", call_params);
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(expr), nullptr);
-  ASSERT_TRUE(TypeOf(expr)->Is<sem::Vector>());
-  if (type == Texture::kF32) {
-    EXPECT_TRUE(TypeOf(expr)->As<sem::Vector>()->type()->Is<sem::F32>());
-  } else if (type == Texture::kI32) {
-    EXPECT_TRUE(TypeOf(expr)->As<sem::Vector>()->type()->Is<sem::I32>());
-  } else {
-    EXPECT_TRUE(TypeOf(expr)->As<sem::Vector>()->type()->Is<sem::U32>());
-  }
-  EXPECT_EQ(TypeOf(expr)->As<sem::Vector>()->Width(), 4u);
+    ASSERT_NE(TypeOf(expr), nullptr);
+    ASSERT_TRUE(TypeOf(expr)->Is<sem::Vector>());
+    if (type == Texture::kF32) {
+        EXPECT_TRUE(TypeOf(expr)->As<sem::Vector>()->type()->Is<sem::F32>());
+    } else if (type == Texture::kI32) {
+        EXPECT_TRUE(TypeOf(expr)->As<sem::Vector>()->type()->Is<sem::I32>());
+    } else {
+        EXPECT_TRUE(TypeOf(expr)->As<sem::Vector>()->type()->Is<sem::U32>());
+    }
+    EXPECT_EQ(TypeOf(expr)->As<sem::Vector>()->Width(), 4u);
 }
 
-INSTANTIATE_TEST_SUITE_P(
-    ResolverTest,
-    ResolverBuiltinTest_SampledTextureOperation,
-    testing::Values(TextureTestParams{ast::TextureDimension::k1d},
-                    TextureTestParams{ast::TextureDimension::k2d},
-                    TextureTestParams{ast::TextureDimension::k2dArray},
-                    TextureTestParams{ast::TextureDimension::k3d}));
+INSTANTIATE_TEST_SUITE_P(ResolverTest,
+                         ResolverBuiltinTest_SampledTextureOperation,
+                         testing::Values(TextureTestParams{ast::TextureDimension::k1d},
+                                         TextureTestParams{ast::TextureDimension::k2d},
+                                         TextureTestParams{ast::TextureDimension::k2dArray},
+                                         TextureTestParams{ast::TextureDimension::k3d}));
 
 TEST_F(ResolverBuiltinTest, Dot_Vec2) {
-  Global("my_var", ty.vec2<f32>(), ast::StorageClass::kPrivate);
+    Global("my_var", ty.vec2<f32>(), ast::StorageClass::kPrivate);
 
-  auto* expr = Call("dot", "my_var", "my_var");
-  WrapInFunction(expr);
+    auto* expr = Call("dot", "my_var", "my_var");
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(expr), nullptr);
-  EXPECT_TRUE(TypeOf(expr)->Is<sem::F32>());
+    ASSERT_NE(TypeOf(expr), nullptr);
+    EXPECT_TRUE(TypeOf(expr)->Is<sem::F32>());
 }
 
 TEST_F(ResolverBuiltinTest, Dot_Vec3) {
-  Global("my_var", ty.vec3<i32>(), ast::StorageClass::kPrivate);
+    Global("my_var", ty.vec3<i32>(), ast::StorageClass::kPrivate);
 
-  auto* expr = Call("dot", "my_var", "my_var");
-  WrapInFunction(expr);
+    auto* expr = Call("dot", "my_var", "my_var");
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(expr), nullptr);
-  EXPECT_TRUE(TypeOf(expr)->Is<sem::I32>());
+    ASSERT_NE(TypeOf(expr), nullptr);
+    EXPECT_TRUE(TypeOf(expr)->Is<sem::I32>());
 }
 
 TEST_F(ResolverBuiltinTest, Dot_Vec4) {
-  Global("my_var", ty.vec4<u32>(), ast::StorageClass::kPrivate);
+    Global("my_var", ty.vec4<u32>(), ast::StorageClass::kPrivate);
 
-  auto* expr = Call("dot", "my_var", "my_var");
-  WrapInFunction(expr);
+    auto* expr = Call("dot", "my_var", "my_var");
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(expr), nullptr);
-  EXPECT_TRUE(TypeOf(expr)->Is<sem::U32>());
+    ASSERT_NE(TypeOf(expr), nullptr);
+    EXPECT_TRUE(TypeOf(expr)->Is<sem::U32>());
 }
 
 TEST_F(ResolverBuiltinTest, Dot_Error_Scalar) {
-  auto* expr = Call("dot", 1.0f, 1.0f);
-  WrapInFunction(expr);
+    auto* expr = Call("dot", 1.0f, 1.0f);
+    WrapInFunction(expr);
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(r()->error(),
-            R"(error: no matching call to dot(f32, f32)
+    EXPECT_EQ(r()->error(),
+              R"(error: no matching call to dot(f32, f32)
 
 1 candidate function:
   dot(vecN<T>, vecN<T>) -> T  where: T is f32, i32 or u32
@@ -306,29 +301,29 @@
 }
 
 TEST_F(ResolverBuiltinTest, Select) {
-  Global("my_var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+    Global("my_var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
 
-  Global("bool_var", ty.vec3<bool>(), ast::StorageClass::kPrivate);
+    Global("bool_var", ty.vec3<bool>(), ast::StorageClass::kPrivate);
 
-  auto* expr = Call("select", "my_var", "my_var", "bool_var");
-  WrapInFunction(expr);
+    auto* expr = Call("select", "my_var", "my_var", "bool_var");
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(expr), nullptr);
-  EXPECT_TRUE(TypeOf(expr)->Is<sem::Vector>());
-  EXPECT_EQ(TypeOf(expr)->As<sem::Vector>()->Width(), 3u);
-  EXPECT_TRUE(TypeOf(expr)->As<sem::Vector>()->type()->Is<sem::F32>());
+    ASSERT_NE(TypeOf(expr), nullptr);
+    EXPECT_TRUE(TypeOf(expr)->Is<sem::Vector>());
+    EXPECT_EQ(TypeOf(expr)->As<sem::Vector>()->Width(), 3u);
+    EXPECT_TRUE(TypeOf(expr)->As<sem::Vector>()->type()->Is<sem::F32>());
 }
 
 TEST_F(ResolverBuiltinTest, Select_Error_NoParams) {
-  auto* expr = Call("select");
-  WrapInFunction(expr);
+    auto* expr = Call("select");
+    WrapInFunction(expr);
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(r()->error(),
-            R"(error: no matching call to select()
+    EXPECT_EQ(r()->error(),
+              R"(error: no matching call to select()
 
 3 candidate functions:
   select(T, T, bool) -> T  where: T is f32, i32, u32 or bool
@@ -338,13 +333,13 @@
 }
 
 TEST_F(ResolverBuiltinTest, Select_Error_SelectorInt) {
-  auto* expr = Call("select", 1, 1, 1);
-  WrapInFunction(expr);
+    auto* expr = Call("select", 1_i, 1_i, 1_i);
+    WrapInFunction(expr);
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(r()->error(),
-            R"(error: no matching call to select(i32, i32, i32)
+    EXPECT_EQ(r()->error(),
+              R"(error: no matching call to select(i32, i32, i32)
 
 3 candidate functions:
   select(T, T, bool) -> T  where: T is f32, i32, u32 or bool
@@ -354,15 +349,14 @@
 }
 
 TEST_F(ResolverBuiltinTest, Select_Error_Matrix) {
-  auto* expr = Call(
-      "select", mat2x2<f32>(vec2<f32>(1.0f, 1.0f), vec2<f32>(1.0f, 1.0f)),
-      mat2x2<f32>(vec2<f32>(1.0f, 1.0f), vec2<f32>(1.0f, 1.0f)), Expr(true));
-  WrapInFunction(expr);
+    auto* expr = Call("select", mat2x2<f32>(vec2<f32>(1.0f, 1.0f), vec2<f32>(1.0f, 1.0f)),
+                      mat2x2<f32>(vec2<f32>(1.0f, 1.0f), vec2<f32>(1.0f, 1.0f)), Expr(true));
+    WrapInFunction(expr);
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(r()->error(),
-            R"(error: no matching call to select(mat2x2<f32>, mat2x2<f32>, bool)
+    EXPECT_EQ(r()->error(),
+              R"(error: no matching call to select(mat2x2<f32>, mat2x2<f32>, bool)
 
 3 candidate functions:
   select(T, T, bool) -> T  where: T is f32, i32, u32 or bool
@@ -372,13 +366,13 @@
 }
 
 TEST_F(ResolverBuiltinTest, Select_Error_MismatchTypes) {
-  auto* expr = Call("select", 1.0f, vec2<f32>(2.0f, 3.0f), Expr(true));
-  WrapInFunction(expr);
+    auto* expr = Call("select", 1.0f, vec2<f32>(2.0f, 3.0f), Expr(true));
+    WrapInFunction(expr);
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(r()->error(),
-            R"(error: no matching call to select(f32, vec2<f32>, bool)
+    EXPECT_EQ(r()->error(),
+              R"(error: no matching call to select(f32, vec2<f32>, bool)
 
 3 candidate functions:
   select(T, T, bool) -> T  where: T is f32, i32, u32 or bool
@@ -388,14 +382,13 @@
 }
 
 TEST_F(ResolverBuiltinTest, Select_Error_MismatchVectorSize) {
-  auto* expr = Call("select", vec2<f32>(1.0f, 2.0f),
-                    vec3<f32>(3.0f, 4.0f, 5.0f), Expr(true));
-  WrapInFunction(expr);
+    auto* expr = Call("select", vec2<f32>(1.0f, 2.0f), vec3<f32>(3.0f, 4.0f, 5.0f), Expr(true));
+    WrapInFunction(expr);
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(r()->error(),
-            R"(error: no matching call to select(vec2<f32>, vec3<f32>, bool)
+    EXPECT_EQ(r()->error(),
+              R"(error: no matching call to select(vec2<f32>, vec3<f32>, bool)
 
 3 candidate functions:
   select(T, T, bool) -> T  where: T is f32, i32, u32 or bool
@@ -405,258 +398,248 @@
 }
 
 struct BuiltinData {
-  const char* name;
-  BuiltinType builtin;
+    const char* name;
+    BuiltinType builtin;
 };
 
 inline std::ostream& operator<<(std::ostream& out, BuiltinData data) {
-  out << data.name;
-  return out;
+    out << data.name;
+    return out;
 }
 
 using ResolverBuiltinTest_Barrier = ResolverTestWithParam<BuiltinData>;
 TEST_P(ResolverBuiltinTest_Barrier, InferType) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* call = Call(param.name);
-  WrapInFunction(CallStmt(call));
+    auto* call = Call(param.name);
+    WrapInFunction(CallStmt(call));
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  ASSERT_NE(TypeOf(call), nullptr);
-  EXPECT_TRUE(TypeOf(call)->Is<sem::Void>());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->Is<sem::Void>());
 }
 
 TEST_P(ResolverBuiltinTest_Barrier, Error_TooManyParams) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* call = Call(param.name, vec4<f32>(1.f, 2.f, 3.f, 4.f), 1.0f);
-  WrapInFunction(CallStmt(call));
+    auto* call = Call(param.name, vec4<f32>(1.f, 2.f, 3.f, 4.f), 1.0f);
+    WrapInFunction(CallStmt(call));
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
-                                      std::string(param.name)));
+    EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " + std::string(param.name)));
 }
 
 INSTANTIATE_TEST_SUITE_P(
     ResolverTest,
     ResolverBuiltinTest_Barrier,
     testing::Values(BuiltinData{"storageBarrier", BuiltinType::kStorageBarrier},
-                    BuiltinData{"workgroupBarrier",
-                                BuiltinType::kWorkgroupBarrier}));
+                    BuiltinData{"workgroupBarrier", BuiltinType::kWorkgroupBarrier}));
 
 using ResolverBuiltinTest_DataPacking = ResolverTestWithParam<BuiltinData>;
 TEST_P(ResolverBuiltinTest_DataPacking, InferType) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  bool pack4 = param.builtin == BuiltinType::kPack4x8snorm ||
-               param.builtin == BuiltinType::kPack4x8unorm;
+    bool pack4 =
+        param.builtin == BuiltinType::kPack4x8snorm || param.builtin == BuiltinType::kPack4x8unorm;
 
-  auto* call = pack4 ? Call(param.name, vec4<f32>(1.f, 2.f, 3.f, 4.f))
-                     : Call(param.name, vec2<f32>(1.f, 2.f));
-  WrapInFunction(call);
+    auto* call = pack4 ? Call(param.name, vec4<f32>(1.f, 2.f, 3.f, 4.f))
+                       : Call(param.name, vec2<f32>(1.f, 2.f));
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  ASSERT_NE(TypeOf(call), nullptr);
-  EXPECT_TRUE(TypeOf(call)->Is<sem::U32>());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->Is<sem::U32>());
 }
 
 TEST_P(ResolverBuiltinTest_DataPacking, Error_IncorrectParamType) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  bool pack4 = param.builtin == BuiltinType::kPack4x8snorm ||
-               param.builtin == BuiltinType::kPack4x8unorm;
+    bool pack4 =
+        param.builtin == BuiltinType::kPack4x8snorm || param.builtin == BuiltinType::kPack4x8unorm;
 
-  auto* call = pack4 ? Call(param.name, vec4<i32>(1, 2, 3, 4))
-                     : Call(param.name, vec2<i32>(1, 2));
-  WrapInFunction(call);
+    auto* call = pack4 ? Call(param.name, vec4<i32>(1_i, 2_i, 3_i, 4_i))
+                       : Call(param.name, vec2<i32>(1_i, 2_i));
+    WrapInFunction(call);
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
-                                      std::string(param.name)));
+    EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " + std::string(param.name)));
 }
 
 TEST_P(ResolverBuiltinTest_DataPacking, Error_NoParams) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* call = Call(param.name);
-  WrapInFunction(call);
+    auto* call = Call(param.name);
+    WrapInFunction(call);
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
-                                      std::string(param.name)));
+    EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " + std::string(param.name)));
 }
 
 TEST_P(ResolverBuiltinTest_DataPacking, Error_TooManyParams) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  bool pack4 = param.builtin == BuiltinType::kPack4x8snorm ||
-               param.builtin == BuiltinType::kPack4x8unorm;
+    bool pack4 =
+        param.builtin == BuiltinType::kPack4x8snorm || param.builtin == BuiltinType::kPack4x8unorm;
 
-  auto* call = pack4 ? Call(param.name, vec4<f32>(1.f, 2.f, 3.f, 4.f), 1.0f)
-                     : Call(param.name, vec2<f32>(1.f, 2.f), 1.0f);
-  WrapInFunction(call);
+    auto* call = pack4 ? Call(param.name, vec4<f32>(1.f, 2.f, 3.f, 4.f), 1.0f)
+                       : Call(param.name, vec2<f32>(1.f, 2.f), 1.0f);
+    WrapInFunction(call);
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
-                                      std::string(param.name)));
+    EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " + std::string(param.name)));
 }
 
-INSTANTIATE_TEST_SUITE_P(
-    ResolverTest,
-    ResolverBuiltinTest_DataPacking,
-    testing::Values(BuiltinData{"pack4x8snorm", BuiltinType::kPack4x8snorm},
-                    BuiltinData{"pack4x8unorm", BuiltinType::kPack4x8unorm},
-                    BuiltinData{"pack2x16snorm", BuiltinType::kPack2x16snorm},
-                    BuiltinData{"pack2x16unorm", BuiltinType::kPack2x16unorm},
-                    BuiltinData{"pack2x16float", BuiltinType::kPack2x16float}));
+INSTANTIATE_TEST_SUITE_P(ResolverTest,
+                         ResolverBuiltinTest_DataPacking,
+                         testing::Values(BuiltinData{"pack4x8snorm", BuiltinType::kPack4x8snorm},
+                                         BuiltinData{"pack4x8unorm", BuiltinType::kPack4x8unorm},
+                                         BuiltinData{"pack2x16snorm", BuiltinType::kPack2x16snorm},
+                                         BuiltinData{"pack2x16unorm", BuiltinType::kPack2x16unorm},
+                                         BuiltinData{"pack2x16float",
+                                                     BuiltinType::kPack2x16float}));
 
 using ResolverBuiltinTest_DataUnpacking = ResolverTestWithParam<BuiltinData>;
 TEST_P(ResolverBuiltinTest_DataUnpacking, InferType) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  bool pack4 = param.builtin == BuiltinType::kUnpack4x8snorm ||
-               param.builtin == BuiltinType::kUnpack4x8unorm;
+    bool pack4 = param.builtin == BuiltinType::kUnpack4x8snorm ||
+                 param.builtin == BuiltinType::kUnpack4x8unorm;
 
-  auto* call = Call(param.name, 1u);
-  WrapInFunction(call);
+    auto* call = Call(param.name, 1_u);
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  ASSERT_NE(TypeOf(call), nullptr);
-  EXPECT_TRUE(TypeOf(call)->is_float_vector());
-  if (pack4) {
-    EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 4u);
-  } else {
-    EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 2u);
-  }
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->is_float_vector());
+    if (pack4) {
+        EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 4u);
+    } else {
+        EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 2u);
+    }
 }
 
 INSTANTIATE_TEST_SUITE_P(
     ResolverTest,
     ResolverBuiltinTest_DataUnpacking,
-    testing::Values(
-        BuiltinData{"unpack4x8snorm", BuiltinType::kUnpack4x8snorm},
-        BuiltinData{"unpack4x8unorm", BuiltinType::kUnpack4x8unorm},
-        BuiltinData{"unpack2x16snorm", BuiltinType::kUnpack2x16snorm},
-        BuiltinData{"unpack2x16unorm", BuiltinType::kUnpack2x16unorm},
-        BuiltinData{"unpack2x16float", BuiltinType::kUnpack2x16float}));
+    testing::Values(BuiltinData{"unpack4x8snorm", BuiltinType::kUnpack4x8snorm},
+                    BuiltinData{"unpack4x8unorm", BuiltinType::kUnpack4x8unorm},
+                    BuiltinData{"unpack2x16snorm", BuiltinType::kUnpack2x16snorm},
+                    BuiltinData{"unpack2x16unorm", BuiltinType::kUnpack2x16unorm},
+                    BuiltinData{"unpack2x16float", BuiltinType::kUnpack2x16float}));
 
 using ResolverBuiltinTest_SingleParam = ResolverTestWithParam<BuiltinData>;
 TEST_P(ResolverBuiltinTest_SingleParam, Scalar) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* call = Call(param.name, 1.f);
-  WrapInFunction(call);
+    auto* call = Call(param.name, 1.f);
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(call), nullptr);
-  EXPECT_TRUE(TypeOf(call)->is_float_scalar());
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->is_float_scalar());
 }
 
 TEST_P(ResolverBuiltinTest_SingleParam, Vector) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* call = Call(param.name, vec3<f32>(1.0f, 1.0f, 3.0f));
-  WrapInFunction(call);
+    auto* call = Call(param.name, vec3<f32>(1.0f, 1.0f, 3.0f));
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    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);
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->is_float_vector());
+    EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
 }
 
 TEST_P(ResolverBuiltinTest_SingleParam, Error_NoParams) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* call = Call(param.name);
-  WrapInFunction(call);
+    auto* call = Call(param.name);
+    WrapInFunction(call);
 
-  EXPECT_FALSE(r()->Resolve());
+    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) + "(f32) -> f32\n  " +
-                std::string(param.name) + "(vecN<f32>) -> vecN<f32>\n");
+    EXPECT_EQ(r()->error(), "error: no matching call to " + std::string(param.name) +
+                                "()\n\n"
+                                "2 candidate functions:\n  " +
+                                std::string(param.name) + "(f32) -> f32\n  " +
+                                std::string(param.name) + "(vecN<f32>) -> vecN<f32>\n");
 }
 
 TEST_P(ResolverBuiltinTest_SingleParam, Error_TooManyParams) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* call = Call(param.name, 1, 2, 3);
-  WrapInFunction(call);
+    auto* call = Call(param.name, 1_i, 2_i, 3_i);
+    WrapInFunction(call);
 
-  EXPECT_FALSE(r()->Resolve());
+    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) + "(f32) -> f32\n  " +
-                std::string(param.name) + "(vecN<f32>) -> vecN<f32>\n");
+    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) + "(f32) -> f32\n  " +
+                                std::string(param.name) + "(vecN<f32>) -> vecN<f32>\n");
 }
 
-INSTANTIATE_TEST_SUITE_P(
-    ResolverTest,
-    ResolverBuiltinTest_SingleParam,
-    testing::Values(BuiltinData{"acos", BuiltinType::kAcos},
-                    BuiltinData{"asin", BuiltinType::kAsin},
-                    BuiltinData{"atan", BuiltinType::kAtan},
-                    BuiltinData{"ceil", BuiltinType::kCeil},
-                    BuiltinData{"cos", BuiltinType::kCos},
-                    BuiltinData{"cosh", BuiltinType::kCosh},
-                    BuiltinData{"exp", BuiltinType::kExp},
-                    BuiltinData{"exp2", BuiltinType::kExp2},
-                    BuiltinData{"floor", BuiltinType::kFloor},
-                    BuiltinData{"fract", BuiltinType::kFract},
-                    BuiltinData{"inverseSqrt", BuiltinType::kInverseSqrt},
-                    BuiltinData{"log", BuiltinType::kLog},
-                    BuiltinData{"log2", BuiltinType::kLog2},
-                    BuiltinData{"round", BuiltinType::kRound},
-                    BuiltinData{"sign", BuiltinType::kSign},
-                    BuiltinData{"sin", BuiltinType::kSin},
-                    BuiltinData{"sinh", BuiltinType::kSinh},
-                    BuiltinData{"sqrt", BuiltinType::kSqrt},
-                    BuiltinData{"tan", BuiltinType::kTan},
-                    BuiltinData{"tanh", BuiltinType::kTanh},
-                    BuiltinData{"trunc", BuiltinType::kTrunc}));
+INSTANTIATE_TEST_SUITE_P(ResolverTest,
+                         ResolverBuiltinTest_SingleParam,
+                         testing::Values(BuiltinData{"acos", BuiltinType::kAcos},
+                                         BuiltinData{"asin", BuiltinType::kAsin},
+                                         BuiltinData{"atan", BuiltinType::kAtan},
+                                         BuiltinData{"ceil", BuiltinType::kCeil},
+                                         BuiltinData{"cos", BuiltinType::kCos},
+                                         BuiltinData{"cosh", BuiltinType::kCosh},
+                                         BuiltinData{"exp", BuiltinType::kExp},
+                                         BuiltinData{"exp2", BuiltinType::kExp2},
+                                         BuiltinData{"floor", BuiltinType::kFloor},
+                                         BuiltinData{"fract", BuiltinType::kFract},
+                                         BuiltinData{"inverseSqrt", BuiltinType::kInverseSqrt},
+                                         BuiltinData{"log", BuiltinType::kLog},
+                                         BuiltinData{"log2", BuiltinType::kLog2},
+                                         BuiltinData{"round", BuiltinType::kRound},
+                                         BuiltinData{"sign", BuiltinType::kSign},
+                                         BuiltinData{"sin", BuiltinType::kSin},
+                                         BuiltinData{"sinh", BuiltinType::kSinh},
+                                         BuiltinData{"sqrt", BuiltinType::kSqrt},
+                                         BuiltinData{"tan", BuiltinType::kTan},
+                                         BuiltinData{"tanh", BuiltinType::kTanh},
+                                         BuiltinData{"trunc", BuiltinType::kTrunc}));
 
 using ResolverBuiltinDataTest = ResolverTest;
 
 TEST_F(ResolverBuiltinDataTest, ArrayLength_Vector) {
-  auto* ary = ty.array<i32>();
-  auto* str = Structure("S", {Member("x", ary)});
-  Global("a", ty.Of(str), ast::StorageClass::kStorage, ast::Access::kRead,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    auto* ary = ty.array<i32>();
+    auto* str = Structure("S", {Member("x", ary)});
+    Global("a", ty.Of(str), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  auto* call = Call("arrayLength", AddressOf(MemberAccessor("a", "x")));
-  WrapInFunction(call);
+    auto* call = Call("arrayLength", AddressOf(MemberAccessor("a", "x")));
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(call), nullptr);
-  EXPECT_TRUE(TypeOf(call)->Is<sem::U32>());
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->Is<sem::U32>());
 }
 
 TEST_F(ResolverBuiltinDataTest, ArrayLength_Error_ArraySized) {
-  Global("arr", ty.array<int, 4>(), ast::StorageClass::kPrivate);
-  auto* call = Call("arrayLength", AddressOf("arr"));
-  WrapInFunction(call);
+    Global("arr", ty.array<i32, 4>(), ast::StorageClass::kPrivate);
+    auto* call = Call("arrayLength", AddressOf("arr"));
+    WrapInFunction(call);
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(
-      r()->error(),
-      R"(error: no matching call to arrayLength(ptr<private, array<i32, 4>, read_write>)
+    EXPECT_EQ(r()->error(),
+              R"(error: no matching call to arrayLength(ptr<private, array<i32, 4>, read_write>)
 
 1 candidate function:
   arrayLength(ptr<storage, array<T>, A>) -> u32
@@ -664,23 +647,23 @@
 }
 
 TEST_F(ResolverBuiltinDataTest, Normalize_Vector) {
-  auto* call = Call("normalize", vec3<f32>(1.0f, 1.0f, 3.0f));
-  WrapInFunction(call);
+    auto* call = Call("normalize", vec3<f32>(1.0f, 1.0f, 3.0f));
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    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);
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->is_float_vector());
+    EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
 }
 
 TEST_F(ResolverBuiltinDataTest, Normalize_Error_NoParams) {
-  auto* call = Call("normalize");
-  WrapInFunction(call);
+    auto* call = Call("normalize");
+    WrapInFunction(call);
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(r()->error(), R"(error: no matching call to normalize()
+    EXPECT_EQ(r()->error(), R"(error: no matching call to normalize()
 
 1 candidate function:
   normalize(vecN<f32>) -> vecN<f32>
@@ -688,77 +671,76 @@
 }
 
 TEST_F(ResolverBuiltinDataTest, FrexpScalar) {
-  auto* call = Call("frexp", 1.0f);
-  WrapInFunction(call);
+    auto* call = Call("frexp", 1.0f);
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(call), nullptr);
-  auto* ty = TypeOf(call)->As<sem::Struct>();
-  ASSERT_NE(ty, nullptr);
-  ASSERT_EQ(ty->Members().size(), 2u);
+    ASSERT_NE(TypeOf(call), nullptr);
+    auto* ty = TypeOf(call)->As<sem::Struct>();
+    ASSERT_NE(ty, nullptr);
+    ASSERT_EQ(ty->Members().size(), 2u);
 
-  auto* sig = ty->Members()[0];
-  EXPECT_TRUE(sig->Type()->Is<sem::F32>());
-  EXPECT_EQ(sig->Offset(), 0u);
-  EXPECT_EQ(sig->Size(), 4u);
-  EXPECT_EQ(sig->Align(), 4u);
-  EXPECT_EQ(sig->Name(), Sym("sig"));
+    auto* sig = ty->Members()[0];
+    EXPECT_TRUE(sig->Type()->Is<sem::F32>());
+    EXPECT_EQ(sig->Offset(), 0u);
+    EXPECT_EQ(sig->Size(), 4u);
+    EXPECT_EQ(sig->Align(), 4u);
+    EXPECT_EQ(sig->Name(), Sym("sig"));
 
-  auto* exp = ty->Members()[1];
-  EXPECT_TRUE(exp->Type()->Is<sem::I32>());
-  EXPECT_EQ(exp->Offset(), 4u);
-  EXPECT_EQ(exp->Size(), 4u);
-  EXPECT_EQ(exp->Align(), 4u);
-  EXPECT_EQ(exp->Name(), Sym("exp"));
+    auto* exp = ty->Members()[1];
+    EXPECT_TRUE(exp->Type()->Is<sem::I32>());
+    EXPECT_EQ(exp->Offset(), 4u);
+    EXPECT_EQ(exp->Size(), 4u);
+    EXPECT_EQ(exp->Align(), 4u);
+    EXPECT_EQ(exp->Name(), Sym("exp"));
 
-  EXPECT_EQ(ty->Size(), 8u);
-  EXPECT_EQ(ty->SizeNoPadding(), 8u);
+    EXPECT_EQ(ty->Size(), 8u);
+    EXPECT_EQ(ty->SizeNoPadding(), 8u);
 }
 
 TEST_F(ResolverBuiltinDataTest, FrexpVector) {
-  auto* call = Call("frexp", vec3<f32>());
-  WrapInFunction(call);
+    auto* call = Call("frexp", vec3<f32>());
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(call), nullptr);
-  auto* ty = TypeOf(call)->As<sem::Struct>();
-  ASSERT_NE(ty, nullptr);
-  ASSERT_EQ(ty->Members().size(), 2u);
+    ASSERT_NE(TypeOf(call), nullptr);
+    auto* ty = TypeOf(call)->As<sem::Struct>();
+    ASSERT_NE(ty, nullptr);
+    ASSERT_EQ(ty->Members().size(), 2u);
 
-  auto* sig = ty->Members()[0];
-  ASSERT_TRUE(sig->Type()->Is<sem::Vector>());
-  EXPECT_EQ(sig->Type()->As<sem::Vector>()->Width(), 3u);
-  EXPECT_TRUE(sig->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(sig->Offset(), 0u);
-  EXPECT_EQ(sig->Size(), 12u);
-  EXPECT_EQ(sig->Align(), 16u);
-  EXPECT_EQ(sig->Name(), Sym("sig"));
+    auto* sig = ty->Members()[0];
+    ASSERT_TRUE(sig->Type()->Is<sem::Vector>());
+    EXPECT_EQ(sig->Type()->As<sem::Vector>()->Width(), 3u);
+    EXPECT_TRUE(sig->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(sig->Offset(), 0u);
+    EXPECT_EQ(sig->Size(), 12u);
+    EXPECT_EQ(sig->Align(), 16u);
+    EXPECT_EQ(sig->Name(), Sym("sig"));
 
-  auto* exp = ty->Members()[1];
-  ASSERT_TRUE(exp->Type()->Is<sem::Vector>());
-  EXPECT_EQ(exp->Type()->As<sem::Vector>()->Width(), 3u);
-  EXPECT_TRUE(exp->Type()->As<sem::Vector>()->type()->Is<sem::I32>());
-  EXPECT_EQ(exp->Offset(), 16u);
-  EXPECT_EQ(exp->Size(), 12u);
-  EXPECT_EQ(exp->Align(), 16u);
-  EXPECT_EQ(exp->Name(), Sym("exp"));
+    auto* exp = ty->Members()[1];
+    ASSERT_TRUE(exp->Type()->Is<sem::Vector>());
+    EXPECT_EQ(exp->Type()->As<sem::Vector>()->Width(), 3u);
+    EXPECT_TRUE(exp->Type()->As<sem::Vector>()->type()->Is<sem::I32>());
+    EXPECT_EQ(exp->Offset(), 16u);
+    EXPECT_EQ(exp->Size(), 12u);
+    EXPECT_EQ(exp->Align(), 16u);
+    EXPECT_EQ(exp->Name(), Sym("exp"));
 
-  EXPECT_EQ(ty->Size(), 32u);
-  EXPECT_EQ(ty->SizeNoPadding(), 28u);
+    EXPECT_EQ(ty->Size(), 32u);
+    EXPECT_EQ(ty->SizeNoPadding(), 28u);
 }
 
 TEST_F(ResolverBuiltinDataTest, Frexp_Error_FirstParamInt) {
-  Global("v", ty.i32(), ast::StorageClass::kWorkgroup);
-  auto* call = Call("frexp", 1, AddressOf("v"));
-  WrapInFunction(call);
+    Global("v", ty.i32(), ast::StorageClass::kWorkgroup);
+    auto* call = Call("frexp", 1_i, AddressOf("v"));
+    WrapInFunction(call);
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(
-      r()->error(),
-      R"(error: no matching call to frexp(i32, ptr<workgroup, i32, read_write>)
+    EXPECT_EQ(r()->error(),
+              R"(error: no matching call to frexp(i32, ptr<workgroup, i32, read_write>)
 
 2 candidate functions:
   frexp(f32) -> __frexp_result
@@ -767,15 +749,14 @@
 }
 
 TEST_F(ResolverBuiltinDataTest, Frexp_Error_SecondParamFloatPtr) {
-  Global("v", ty.f32(), ast::StorageClass::kWorkgroup);
-  auto* call = Call("frexp", 1.0f, AddressOf("v"));
-  WrapInFunction(call);
+    Global("v", ty.f32(), ast::StorageClass::kWorkgroup);
+    auto* call = Call("frexp", 1.0f, AddressOf("v"));
+    WrapInFunction(call);
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(
-      r()->error(),
-      R"(error: no matching call to frexp(f32, ptr<workgroup, f32, read_write>)
+    EXPECT_EQ(r()->error(),
+              R"(error: no matching call to frexp(f32, ptr<workgroup, f32, read_write>)
 
 2 candidate functions:
   frexp(f32) -> __frexp_result
@@ -784,12 +765,12 @@
 }
 
 TEST_F(ResolverBuiltinDataTest, Frexp_Error_SecondParamNotAPointer) {
-  auto* call = Call("frexp", 1.0f, 1);
-  WrapInFunction(call);
+    auto* call = Call("frexp", 1.0f, 1_i);
+    WrapInFunction(call);
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(r()->error(), R"(error: no matching call to frexp(f32, i32)
+    EXPECT_EQ(r()->error(), R"(error: no matching call to frexp(f32, i32)
 
 2 candidate functions:
   frexp(f32) -> __frexp_result
@@ -798,15 +779,14 @@
 }
 
 TEST_F(ResolverBuiltinDataTest, Frexp_Error_VectorSizesDontMatch) {
-  Global("v", ty.vec4<i32>(), ast::StorageClass::kWorkgroup);
-  auto* call = Call("frexp", vec2<f32>(1.0f, 2.0f), AddressOf("v"));
-  WrapInFunction(call);
+    Global("v", ty.vec4<i32>(), ast::StorageClass::kWorkgroup);
+    auto* call = Call("frexp", vec2<f32>(1.0f, 2.0f), AddressOf("v"));
+    WrapInFunction(call);
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(
-      r()->error(),
-      R"(error: no matching call to frexp(vec2<f32>, ptr<workgroup, vec4<i32>, read_write>)
+    EXPECT_EQ(r()->error(),
+              R"(error: no matching call to frexp(vec2<f32>, ptr<workgroup, vec4<i32>, read_write>)
 
 2 candidate functions:
   frexp(vecN<f32>) -> __frexp_result_vecN
@@ -815,77 +795,76 @@
 }
 
 TEST_F(ResolverBuiltinDataTest, ModfScalar) {
-  auto* call = Call("modf", 1.0f);
-  WrapInFunction(call);
+    auto* call = Call("modf", 1.0f);
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(call), nullptr);
-  auto* ty = TypeOf(call)->As<sem::Struct>();
-  ASSERT_NE(ty, nullptr);
-  ASSERT_EQ(ty->Members().size(), 2u);
+    ASSERT_NE(TypeOf(call), nullptr);
+    auto* ty = TypeOf(call)->As<sem::Struct>();
+    ASSERT_NE(ty, nullptr);
+    ASSERT_EQ(ty->Members().size(), 2u);
 
-  auto* fract = ty->Members()[0];
-  EXPECT_TRUE(fract->Type()->Is<sem::F32>());
-  EXPECT_EQ(fract->Offset(), 0u);
-  EXPECT_EQ(fract->Size(), 4u);
-  EXPECT_EQ(fract->Align(), 4u);
-  EXPECT_EQ(fract->Name(), Sym("fract"));
+    auto* fract = ty->Members()[0];
+    EXPECT_TRUE(fract->Type()->Is<sem::F32>());
+    EXPECT_EQ(fract->Offset(), 0u);
+    EXPECT_EQ(fract->Size(), 4u);
+    EXPECT_EQ(fract->Align(), 4u);
+    EXPECT_EQ(fract->Name(), Sym("fract"));
 
-  auto* whole = ty->Members()[1];
-  EXPECT_TRUE(whole->Type()->Is<sem::F32>());
-  EXPECT_EQ(whole->Offset(), 4u);
-  EXPECT_EQ(whole->Size(), 4u);
-  EXPECT_EQ(whole->Align(), 4u);
-  EXPECT_EQ(whole->Name(), Sym("whole"));
+    auto* whole = ty->Members()[1];
+    EXPECT_TRUE(whole->Type()->Is<sem::F32>());
+    EXPECT_EQ(whole->Offset(), 4u);
+    EXPECT_EQ(whole->Size(), 4u);
+    EXPECT_EQ(whole->Align(), 4u);
+    EXPECT_EQ(whole->Name(), Sym("whole"));
 
-  EXPECT_EQ(ty->Size(), 8u);
-  EXPECT_EQ(ty->SizeNoPadding(), 8u);
+    EXPECT_EQ(ty->Size(), 8u);
+    EXPECT_EQ(ty->SizeNoPadding(), 8u);
 }
 
 TEST_F(ResolverBuiltinDataTest, ModfVector) {
-  auto* call = Call("modf", vec3<f32>());
-  WrapInFunction(call);
+    auto* call = Call("modf", vec3<f32>());
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(call), nullptr);
-  auto* ty = TypeOf(call)->As<sem::Struct>();
-  ASSERT_NE(ty, nullptr);
-  ASSERT_EQ(ty->Members().size(), 2u);
+    ASSERT_NE(TypeOf(call), nullptr);
+    auto* ty = TypeOf(call)->As<sem::Struct>();
+    ASSERT_NE(ty, nullptr);
+    ASSERT_EQ(ty->Members().size(), 2u);
 
-  auto* fract = ty->Members()[0];
-  ASSERT_TRUE(fract->Type()->Is<sem::Vector>());
-  EXPECT_EQ(fract->Type()->As<sem::Vector>()->Width(), 3u);
-  EXPECT_TRUE(fract->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(fract->Offset(), 0u);
-  EXPECT_EQ(fract->Size(), 12u);
-  EXPECT_EQ(fract->Align(), 16u);
-  EXPECT_EQ(fract->Name(), Sym("fract"));
+    auto* fract = ty->Members()[0];
+    ASSERT_TRUE(fract->Type()->Is<sem::Vector>());
+    EXPECT_EQ(fract->Type()->As<sem::Vector>()->Width(), 3u);
+    EXPECT_TRUE(fract->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(fract->Offset(), 0u);
+    EXPECT_EQ(fract->Size(), 12u);
+    EXPECT_EQ(fract->Align(), 16u);
+    EXPECT_EQ(fract->Name(), Sym("fract"));
 
-  auto* whole = ty->Members()[1];
-  ASSERT_TRUE(whole->Type()->Is<sem::Vector>());
-  EXPECT_EQ(whole->Type()->As<sem::Vector>()->Width(), 3u);
-  EXPECT_TRUE(whole->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(whole->Offset(), 16u);
-  EXPECT_EQ(whole->Size(), 12u);
-  EXPECT_EQ(whole->Align(), 16u);
-  EXPECT_EQ(whole->Name(), Sym("whole"));
+    auto* whole = ty->Members()[1];
+    ASSERT_TRUE(whole->Type()->Is<sem::Vector>());
+    EXPECT_EQ(whole->Type()->As<sem::Vector>()->Width(), 3u);
+    EXPECT_TRUE(whole->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(whole->Offset(), 16u);
+    EXPECT_EQ(whole->Size(), 12u);
+    EXPECT_EQ(whole->Align(), 16u);
+    EXPECT_EQ(whole->Name(), Sym("whole"));
 
-  EXPECT_EQ(ty->Size(), 32u);
-  EXPECT_EQ(ty->SizeNoPadding(), 28u);
+    EXPECT_EQ(ty->Size(), 32u);
+    EXPECT_EQ(ty->SizeNoPadding(), 28u);
 }
 
 TEST_F(ResolverBuiltinDataTest, Modf_Error_FirstParamInt) {
-  Global("whole", ty.f32(), ast::StorageClass::kWorkgroup);
-  auto* call = Call("modf", 1, AddressOf("whole"));
-  WrapInFunction(call);
+    Global("whole", ty.f32(), ast::StorageClass::kWorkgroup);
+    auto* call = Call("modf", 1_i, AddressOf("whole"));
+    WrapInFunction(call);
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(
-      r()->error(),
-      R"(error: no matching call to modf(i32, ptr<workgroup, f32, read_write>)
+    EXPECT_EQ(r()->error(),
+              R"(error: no matching call to modf(i32, ptr<workgroup, f32, read_write>)
 
 2 candidate functions:
   modf(f32) -> __modf_result
@@ -894,15 +873,14 @@
 }
 
 TEST_F(ResolverBuiltinDataTest, Modf_Error_SecondParamIntPtr) {
-  Global("whole", ty.i32(), ast::StorageClass::kWorkgroup);
-  auto* call = Call("modf", 1.0f, AddressOf("whole"));
-  WrapInFunction(call);
+    Global("whole", ty.i32(), ast::StorageClass::kWorkgroup);
+    auto* call = Call("modf", 1.0f, AddressOf("whole"));
+    WrapInFunction(call);
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(
-      r()->error(),
-      R"(error: no matching call to modf(f32, ptr<workgroup, i32, read_write>)
+    EXPECT_EQ(r()->error(),
+              R"(error: no matching call to modf(f32, ptr<workgroup, i32, read_write>)
 
 2 candidate functions:
   modf(f32) -> __modf_result
@@ -911,12 +889,12 @@
 }
 
 TEST_F(ResolverBuiltinDataTest, Modf_Error_SecondParamNotAPointer) {
-  auto* call = Call("modf", 1.0f, 1.0f);
-  WrapInFunction(call);
+    auto* call = Call("modf", 1.0f, 1.0f);
+    WrapInFunction(call);
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(r()->error(), R"(error: no matching call to modf(f32, f32)
+    EXPECT_EQ(r()->error(), R"(error: no matching call to modf(f32, f32)
 
 2 candidate functions:
   modf(f32) -> __modf_result
@@ -925,15 +903,14 @@
 }
 
 TEST_F(ResolverBuiltinDataTest, Modf_Error_VectorSizesDontMatch) {
-  Global("whole", ty.vec4<f32>(), ast::StorageClass::kWorkgroup);
-  auto* call = Call("modf", vec2<f32>(1.0f, 2.0f), AddressOf("whole"));
-  WrapInFunction(call);
+    Global("whole", ty.vec4<f32>(), ast::StorageClass::kWorkgroup);
+    auto* call = Call("modf", vec2<f32>(1.0f, 2.0f), AddressOf("whole"));
+    WrapInFunction(call);
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(
-      r()->error(),
-      R"(error: no matching call to modf(vec2<f32>, ptr<workgroup, vec4<f32>, read_write>)
+    EXPECT_EQ(r()->error(),
+              R"(error: no matching call to modf(vec2<f32>, ptr<workgroup, vec4<f32>, read_write>)
 
 2 candidate functions:
   modf(vecN<f32>) -> __modf_result_vecN
@@ -941,234 +918,222 @@
 )");
 }
 
-using ResolverBuiltinTest_SingleParam_FloatOrInt =
-    ResolverTestWithParam<BuiltinData>;
+using ResolverBuiltinTest_SingleParam_FloatOrInt = ResolverTestWithParam<BuiltinData>;
 TEST_P(ResolverBuiltinTest_SingleParam_FloatOrInt, Float_Scalar) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* call = Call(param.name, 1.f);
-  WrapInFunction(call);
+    auto* call = Call(param.name, 1.f);
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(call), nullptr);
-  EXPECT_TRUE(TypeOf(call)->is_float_scalar());
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->is_float_scalar());
 }
 
 TEST_P(ResolverBuiltinTest_SingleParam_FloatOrInt, Float_Vector) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* call = Call(param.name, vec3<f32>(1.0f, 1.0f, 3.0f));
-  WrapInFunction(call);
+    auto* call = Call(param.name, vec3<f32>(1.0f, 1.0f, 3.0f));
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    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);
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->is_float_vector());
+    EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
 }
 
 TEST_P(ResolverBuiltinTest_SingleParam_FloatOrInt, Sint_Scalar) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* call = Call(param.name, -1);
-  WrapInFunction(call);
+    auto* call = Call(param.name, i32(-1));
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(call), nullptr);
-  EXPECT_TRUE(TypeOf(call)->Is<sem::I32>());
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->Is<sem::I32>());
 }
 
 TEST_P(ResolverBuiltinTest_SingleParam_FloatOrInt, Sint_Vector) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* call = Call(param.name, vec3<i32>(1, 1, 3));
-  WrapInFunction(call);
+    auto* call = Call(param.name, vec3<i32>(1_i, 1_i, 3_i));
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(call), nullptr);
-  EXPECT_TRUE(TypeOf(call)->is_signed_integer_vector());
-  EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->is_signed_integer_vector());
+    EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
 }
 
 TEST_P(ResolverBuiltinTest_SingleParam_FloatOrInt, Uint_Scalar) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* call = Call(param.name, 1u);
-  WrapInFunction(call);
+    auto* call = Call(param.name, 1_u);
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(call), nullptr);
-  EXPECT_TRUE(TypeOf(call)->Is<sem::U32>());
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->Is<sem::U32>());
 }
 
 TEST_P(ResolverBuiltinTest_SingleParam_FloatOrInt, Uint_Vector) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* call = Call(param.name, vec3<u32>(1u, 1u, 3u));
-  WrapInFunction(call);
+    auto* call = Call(param.name, vec3<u32>(1_u, 1_u, 3_u));
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(call), nullptr);
-  EXPECT_TRUE(TypeOf(call)->is_unsigned_integer_vector());
-  EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->is_unsigned_integer_vector());
+    EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
 }
 
 TEST_P(ResolverBuiltinTest_SingleParam_FloatOrInt, Error_NoParams) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* call = Call(param.name);
-  WrapInFunction(call);
+    auto* call = Call(param.name);
+    WrapInFunction(call);
 
-  EXPECT_FALSE(r()->Resolve());
+    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  where: T is f32, i32 or u32\n  " +
-                std::string(param.name) +
-                "(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  where: T is f32, i32 or u32\n  " +
+                  std::string(param.name) + "(vecN<T>) -> vecN<T>  where: T is f32, i32 or u32\n");
 }
 
 INSTANTIATE_TEST_SUITE_P(ResolverTest,
                          ResolverBuiltinTest_SingleParam_FloatOrInt,
-                         testing::Values(BuiltinData{"abs",
-                                                     BuiltinType::kAbs}));
+                         testing::Values(BuiltinData{"abs", BuiltinType::kAbs}));
 
 TEST_F(ResolverBuiltinTest, Length_Scalar) {
-  auto* call = Call("length", 1.f);
-  WrapInFunction(call);
+    auto* call = Call("length", 1.f);
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(call), nullptr);
-  EXPECT_TRUE(TypeOf(call)->is_float_scalar());
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->is_float_scalar());
 }
 
 TEST_F(ResolverBuiltinTest, Length_FloatVector) {
-  auto* call = Call("length", vec3<f32>(1.0f, 1.0f, 3.0f));
-  WrapInFunction(call);
+    auto* call = Call("length", vec3<f32>(1.0f, 1.0f, 3.0f));
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(call), nullptr);
-  EXPECT_TRUE(TypeOf(call)->is_float_scalar());
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->is_float_scalar());
 }
 
 using ResolverBuiltinTest_TwoParam = ResolverTestWithParam<BuiltinData>;
 TEST_P(ResolverBuiltinTest_TwoParam, Scalar) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* call = Call(param.name, 1.f, 1.f);
-  WrapInFunction(call);
+    auto* call = Call(param.name, 1.f, 1.f);
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(call), nullptr);
-  EXPECT_TRUE(TypeOf(call)->is_float_scalar());
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->is_float_scalar());
 }
 
 TEST_P(ResolverBuiltinTest_TwoParam, Vector) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* call = Call(param.name, vec3<f32>(1.0f, 1.0f, 3.0f),
-                    vec3<f32>(1.0f, 1.0f, 3.0f));
-  WrapInFunction(call);
+    auto* call = Call(param.name, vec3<f32>(1.0f, 1.0f, 3.0f), vec3<f32>(1.0f, 1.0f, 3.0f));
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    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);
+    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, Error_NoTooManyParams) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* call = Call(param.name, 1, 2, 3);
-  WrapInFunction(call);
+    auto* call = Call(param.name, 1_i, 2_i, 3_i);
+    WrapInFunction(call);
 
-  EXPECT_FALSE(r()->Resolve());
+    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) + "(f32, f32) -> f32\n  " +
-                std::string(param.name) +
-                "(vecN<f32>, vecN<f32>) -> vecN<f32>\n");
+    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) + "(f32, f32) -> f32\n  " +
+                                std::string(param.name) + "(vecN<f32>, vecN<f32>) -> vecN<f32>\n");
 }
 
 TEST_P(ResolverBuiltinTest_TwoParam, Error_NoParams) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* call = Call(param.name);
-  WrapInFunction(call);
+    auto* call = Call(param.name);
+    WrapInFunction(call);
 
-  EXPECT_FALSE(r()->Resolve());
+    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) + "(f32, f32) -> f32\n  " +
-                std::string(param.name) +
-                "(vecN<f32>, vecN<f32>) -> vecN<f32>\n");
+    EXPECT_EQ(r()->error(), "error: no matching call to " + std::string(param.name) +
+                                "()\n\n"
+                                "2 candidate functions:\n  " +
+                                std::string(param.name) + "(f32, f32) -> f32\n  " +
+                                std::string(param.name) + "(vecN<f32>, vecN<f32>) -> vecN<f32>\n");
 }
 
-INSTANTIATE_TEST_SUITE_P(
-    ResolverTest,
-    ResolverBuiltinTest_TwoParam,
-    testing::Values(BuiltinData{"atan2", BuiltinType::kAtan2},
-                    BuiltinData{"pow", BuiltinType::kPow},
-                    BuiltinData{"step", BuiltinType::kStep}));
+INSTANTIATE_TEST_SUITE_P(ResolverTest,
+                         ResolverBuiltinTest_TwoParam,
+                         testing::Values(BuiltinData{"atan2", BuiltinType::kAtan2},
+                                         BuiltinData{"pow", BuiltinType::kPow},
+                                         BuiltinData{"step", BuiltinType::kStep}));
 
 TEST_F(ResolverBuiltinTest, Distance_Scalar) {
-  auto* call = Call("distance", 1.f, 1.f);
-  WrapInFunction(call);
+    auto* call = Call("distance", 1.f, 1.f);
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(call), nullptr);
-  EXPECT_TRUE(TypeOf(call)->is_float_scalar());
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->is_float_scalar());
 }
 
 TEST_F(ResolverBuiltinTest, Distance_Vector) {
-  auto* call = Call("distance", vec3<f32>(1.0f, 1.0f, 3.0f),
-                    vec3<f32>(1.0f, 1.0f, 3.0f));
-  WrapInFunction(call);
+    auto* call = Call("distance", vec3<f32>(1.0f, 1.0f, 3.0f), vec3<f32>(1.0f, 1.0f, 3.0f));
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(call), nullptr);
-  EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
 }
 
 TEST_F(ResolverBuiltinTest, Cross) {
-  auto* call =
-      Call("cross", vec3<f32>(1.0f, 2.0f, 3.0f), vec3<f32>(1.0f, 2.0f, 3.0f));
-  WrapInFunction(call);
+    auto* call = Call("cross", vec3<f32>(1.0f, 2.0f, 3.0f), vec3<f32>(1.0f, 2.0f, 3.0f));
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    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);
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->is_float_vector());
+    EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
 }
 
 TEST_F(ResolverBuiltinTest, Cross_Error_NoArgs) {
-  auto* call = Call("cross");
-  WrapInFunction(call);
+    auto* call = Call("cross");
+    WrapInFunction(call);
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(r()->error(), R"(error: no matching call to cross()
+    EXPECT_EQ(r()->error(), R"(error: no matching call to cross()
 
 1 candidate function:
   cross(vec3<f32>, vec3<f32>) -> vec3<f32>
@@ -1176,12 +1141,12 @@
 }
 
 TEST_F(ResolverBuiltinTest, Cross_Error_Scalar) {
-  auto* call = Call("cross", 1.0f, 1.0f);
-  WrapInFunction(call);
+    auto* call = Call("cross", 1.0f, 1.0f);
+    WrapInFunction(call);
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(r()->error(), R"(error: no matching call to cross(f32, f32)
+    EXPECT_EQ(r()->error(), R"(error: no matching call to cross(f32, f32)
 
 1 candidate function:
   cross(vec3<f32>, vec3<f32>) -> vec3<f32>
@@ -1189,13 +1154,13 @@
 }
 
 TEST_F(ResolverBuiltinTest, Cross_Error_Vec3Int) {
-  auto* call = Call("cross", vec3<i32>(1, 2, 3), vec3<i32>(1, 2, 3));
-  WrapInFunction(call);
+    auto* call = Call("cross", vec3<i32>(1_i, 2_i, 3_i), vec3<i32>(1_i, 2_i, 3_i));
+    WrapInFunction(call);
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(r()->error(),
-            R"(error: no matching call to cross(vec3<i32>, vec3<i32>)
+    EXPECT_EQ(r()->error(),
+              R"(error: no matching call to cross(vec3<i32>, vec3<i32>)
 
 1 candidate function:
   cross(vec3<f32>, vec3<f32>) -> vec3<f32>
@@ -1203,15 +1168,15 @@
 }
 
 TEST_F(ResolverBuiltinTest, Cross_Error_Vec4) {
-  auto* call = Call("cross", vec4<f32>(1.0f, 2.0f, 3.0f, 4.0f),
-                    vec4<f32>(1.0f, 2.0f, 3.0f, 4.0f));
+    auto* call =
+        Call("cross", vec4<f32>(1.0f, 2.0f, 3.0f, 4.0f), vec4<f32>(1.0f, 2.0f, 3.0f, 4.0f));
 
-  WrapInFunction(call);
+    WrapInFunction(call);
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(r()->error(),
-            R"(error: no matching call to cross(vec4<f32>, vec4<f32>)
+    EXPECT_EQ(r()->error(),
+              R"(error: no matching call to cross(vec4<f32>, vec4<f32>)
 
 1 candidate function:
   cross(vec3<f32>, vec3<f32>) -> vec3<f32>
@@ -1219,38 +1184,38 @@
 }
 
 TEST_F(ResolverBuiltinTest, Cross_Error_TooManyParams) {
-  auto* call = Call("cross", vec3<f32>(1.0f, 2.0f, 3.0f),
-                    vec3<f32>(1.0f, 2.0f, 3.0f), vec3<f32>(1.0f, 2.0f, 3.0f));
+    auto* call = Call("cross", vec3<f32>(1.0f, 2.0f, 3.0f), vec3<f32>(1.0f, 2.0f, 3.0f),
+                      vec3<f32>(1.0f, 2.0f, 3.0f));
 
-  WrapInFunction(call);
+    WrapInFunction(call);
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(r()->error(),
-            R"(error: no matching call to cross(vec3<f32>, vec3<f32>, vec3<f32>)
+    EXPECT_EQ(r()->error(),
+              R"(error: no matching call to cross(vec3<f32>, vec3<f32>, vec3<f32>)
 
 1 candidate function:
   cross(vec3<f32>, vec3<f32>) -> vec3<f32>
 )");
 }
 TEST_F(ResolverBuiltinTest, Normalize) {
-  auto* call = Call("normalize", vec3<f32>(1.0f, 1.0f, 3.0f));
-  WrapInFunction(call);
+    auto* call = Call("normalize", vec3<f32>(1.0f, 1.0f, 3.0f));
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    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);
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->is_float_vector());
+    EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
 }
 
 TEST_F(ResolverBuiltinTest, Normalize_NoArgs) {
-  auto* call = Call("normalize");
-  WrapInFunction(call);
+    auto* call = Call("normalize");
+    WrapInFunction(call);
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(r()->error(), R"(error: no matching call to normalize()
+    EXPECT_EQ(r()->error(), R"(error: no matching call to normalize()
 
 1 candidate function:
   normalize(vecN<f32>) -> vecN<f32>
@@ -1259,351 +1224,340 @@
 
 using ResolverBuiltinTest_ThreeParam = ResolverTestWithParam<BuiltinData>;
 TEST_P(ResolverBuiltinTest_ThreeParam, Scalar) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* call = Call(param.name, 1.f, 1.f, 1.f);
-  WrapInFunction(call);
+    auto* call = Call(param.name, 1.f, 1.f, 1.f);
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(call), nullptr);
-  EXPECT_TRUE(TypeOf(call)->is_float_scalar());
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->is_float_scalar());
 }
 
 TEST_P(ResolverBuiltinTest_ThreeParam, Vector) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* call = Call(param.name, vec3<f32>(1.0f, 1.0f, 3.0f),
-                    vec3<f32>(1.0f, 1.0f, 3.0f), vec3<f32>(1.0f, 1.0f, 3.0f));
-  WrapInFunction(call);
+    auto* call = Call(param.name, vec3<f32>(1.0f, 1.0f, 3.0f), vec3<f32>(1.0f, 1.0f, 3.0f),
+                      vec3<f32>(1.0f, 1.0f, 3.0f));
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    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);
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->is_float_vector());
+    EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
 }
 TEST_P(ResolverBuiltinTest_ThreeParam, Error_NoParams) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* call = Call(param.name);
-  WrapInFunction(call);
+    auto* call = Call(param.name);
+    WrapInFunction(call);
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_THAT(r()->error(), HasSubstr("error: no matching call to " +
-                                      std::string(param.name) + "()"));
+    EXPECT_THAT(r()->error(),
+                HasSubstr("error: no matching call to " + std::string(param.name) + "()"));
 }
 
-INSTANTIATE_TEST_SUITE_P(
-    ResolverTest,
-    ResolverBuiltinTest_ThreeParam,
-    testing::Values(BuiltinData{"mix", BuiltinType::kMix},
-                    BuiltinData{"smoothstep", BuiltinType::kSmoothstep},
-                    BuiltinData{"smoothStep", BuiltinType::kSmoothStep},
-                    BuiltinData{"fma", BuiltinType::kFma}));
+INSTANTIATE_TEST_SUITE_P(ResolverTest,
+                         ResolverBuiltinTest_ThreeParam,
+                         testing::Values(BuiltinData{"mix", BuiltinType::kMix},
+                                         BuiltinData{"smoothstep", BuiltinType::kSmoothstep},
+                                         BuiltinData{"smoothStep", BuiltinType::kSmoothStep},
+                                         BuiltinData{"fma", BuiltinType::kFma}));
 
-using ResolverBuiltinTest_ThreeParam_FloatOrInt =
-    ResolverTestWithParam<BuiltinData>;
+using ResolverBuiltinTest_ThreeParam_FloatOrInt = ResolverTestWithParam<BuiltinData>;
 TEST_P(ResolverBuiltinTest_ThreeParam_FloatOrInt, Float_Scalar) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* call = Call(param.name, 1.f, 1.f, 1.f);
-  WrapInFunction(call);
+    auto* call = Call(param.name, 1.f, 1.f, 1.f);
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(call), nullptr);
-  EXPECT_TRUE(TypeOf(call)->is_float_scalar());
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->is_float_scalar());
 }
 
 TEST_P(ResolverBuiltinTest_ThreeParam_FloatOrInt, Float_Vector) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* call = Call(param.name, vec3<f32>(1.0f, 1.0f, 3.0f),
-                    vec3<f32>(1.0f, 1.0f, 3.0f), vec3<f32>(1.0f, 1.0f, 3.0f));
-  WrapInFunction(call);
+    auto* call = Call(param.name, vec3<f32>(1.0f, 1.0f, 3.0f), vec3<f32>(1.0f, 1.0f, 3.0f),
+                      vec3<f32>(1.0f, 1.0f, 3.0f));
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    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);
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->is_float_vector());
+    EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
 }
 
 TEST_P(ResolverBuiltinTest_ThreeParam_FloatOrInt, Sint_Scalar) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* call = Call(param.name, 1, 1, 1);
-  WrapInFunction(call);
+    auto* call = Call(param.name, 1_i, 1_i, 1_i);
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(call), nullptr);
-  EXPECT_TRUE(TypeOf(call)->Is<sem::I32>());
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->Is<sem::I32>());
 }
 
 TEST_P(ResolverBuiltinTest_ThreeParam_FloatOrInt, Sint_Vector) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* call = Call(param.name, vec3<i32>(1, 1, 3), vec3<i32>(1, 1, 3),
-                    vec3<i32>(1, 1, 3));
-  WrapInFunction(call);
+    auto* call = Call(param.name, vec3<i32>(1_i, 1_i, 3_i), vec3<i32>(1_i, 1_i, 3_i),
+                      vec3<i32>(1_i, 1_i, 3_i));
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(call), nullptr);
-  EXPECT_TRUE(TypeOf(call)->is_signed_integer_vector());
-  EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->is_signed_integer_vector());
+    EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
 }
 
 TEST_P(ResolverBuiltinTest_ThreeParam_FloatOrInt, Uint_Scalar) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* call = Call(param.name, 1u, 1u, 1u);
-  WrapInFunction(call);
+    auto* call = Call(param.name, 1_u, 1_u, 1_u);
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(call), nullptr);
-  EXPECT_TRUE(TypeOf(call)->Is<sem::U32>());
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->Is<sem::U32>());
 }
 
 TEST_P(ResolverBuiltinTest_ThreeParam_FloatOrInt, Uint_Vector) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* call = Call(param.name, vec3<u32>(1u, 1u, 3u), vec3<u32>(1u, 1u, 3u),
-                    vec3<u32>(1u, 1u, 3u));
-  WrapInFunction(call);
+    auto* call = Call(param.name, vec3<u32>(1_u, 1_u, 3_u), vec3<u32>(1_u, 1_u, 3_u),
+                      vec3<u32>(1_u, 1_u, 3_u));
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(call), nullptr);
-  EXPECT_TRUE(TypeOf(call)->is_unsigned_integer_vector());
-  EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->is_unsigned_integer_vector());
+    EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
 }
 
 TEST_P(ResolverBuiltinTest_ThreeParam_FloatOrInt, Error_NoParams) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* call = Call(param.name);
-  WrapInFunction(call);
+    auto* call = Call(param.name);
+    WrapInFunction(call);
 
-  EXPECT_FALSE(r()->Resolve());
+    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 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");
 }
 
 INSTANTIATE_TEST_SUITE_P(ResolverTest,
                          ResolverBuiltinTest_ThreeParam_FloatOrInt,
-                         testing::Values(BuiltinData{"clamp",
-                                                     BuiltinType::kClamp}));
+                         testing::Values(BuiltinData{"clamp", BuiltinType::kClamp}));
 
 using ResolverBuiltinTest_Int_SingleParam = ResolverTestWithParam<BuiltinData>;
 TEST_P(ResolverBuiltinTest_Int_SingleParam, Scalar) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* call = Call(param.name, 1);
-  WrapInFunction(call);
+    auto* call = Call(param.name, 1_i);
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(call), nullptr);
-  EXPECT_TRUE(TypeOf(call)->is_integer_scalar());
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->is_integer_scalar());
 }
 
 TEST_P(ResolverBuiltinTest_Int_SingleParam, Vector) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* call = Call(param.name, vec3<i32>(1, 1, 3));
-  WrapInFunction(call);
+    auto* call = Call(param.name, vec3<i32>(1_i, 1_i, 3_i));
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(call), nullptr);
-  EXPECT_TRUE(TypeOf(call)->is_signed_integer_vector());
-  EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->is_signed_integer_vector());
+    EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
 }
 
 TEST_P(ResolverBuiltinTest_Int_SingleParam, Error_NoParams) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* call = Call(param.name);
-  WrapInFunction(call);
+    auto* call = Call(param.name);
+    WrapInFunction(call);
 
-  EXPECT_FALSE(r()->Resolve());
+    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  where: T is i32 or u32\n  " +
-                              std::string(param.name) +
-                              "(vecN<T>) -> vecN<T>  where: T is 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  where: T is i32 or u32\n  " +
+                                std::string(param.name) +
+                                "(vecN<T>) -> vecN<T>  where: T is i32 or u32\n");
 }
 
-INSTANTIATE_TEST_SUITE_P(
-    ResolverTest,
-    ResolverBuiltinTest_Int_SingleParam,
-    testing::Values(BuiltinData{"countOneBits", BuiltinType::kCountOneBits},
-                    BuiltinData{"reverseBits", BuiltinType::kReverseBits}));
+INSTANTIATE_TEST_SUITE_P(ResolverTest,
+                         ResolverBuiltinTest_Int_SingleParam,
+                         testing::Values(BuiltinData{"countOneBits", BuiltinType::kCountOneBits},
+                                         BuiltinData{"reverseBits", BuiltinType::kReverseBits}));
 
-using ResolverBuiltinTest_FloatOrInt_TwoParam =
-    ResolverTestWithParam<BuiltinData>;
+using ResolverBuiltinTest_FloatOrInt_TwoParam = ResolverTestWithParam<BuiltinData>;
 TEST_P(ResolverBuiltinTest_FloatOrInt_TwoParam, Scalar_Signed) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* call = Call(param.name, 1, 1);
-  WrapInFunction(call);
+    auto* call = Call(param.name, 1_i, 1_i);
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(call), nullptr);
-  EXPECT_TRUE(TypeOf(call)->Is<sem::I32>());
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->Is<sem::I32>());
 }
 
 TEST_P(ResolverBuiltinTest_FloatOrInt_TwoParam, Scalar_Unsigned) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* call = Call(param.name, 1u, 1u);
-  WrapInFunction(call);
+    auto* call = Call(param.name, 1_u, 1_u);
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(call), nullptr);
-  EXPECT_TRUE(TypeOf(call)->Is<sem::U32>());
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->Is<sem::U32>());
 }
 
 TEST_P(ResolverBuiltinTest_FloatOrInt_TwoParam, Scalar_Float) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* call = Call(param.name, 1.0f, 1.0f);
-  WrapInFunction(call);
+    auto* call = Call(param.name, 1.0f, 1.0f);
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(call), nullptr);
-  EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
 }
 
 TEST_P(ResolverBuiltinTest_FloatOrInt_TwoParam, Vector_Signed) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* call = Call(param.name, vec3<i32>(1, 1, 3), vec3<i32>(1, 1, 3));
-  WrapInFunction(call);
+    auto* call = Call(param.name, vec3<i32>(1_i, 1_i, 3_i), vec3<i32>(1_i, 1_i, 3_i));
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(call), nullptr);
-  EXPECT_TRUE(TypeOf(call)->is_signed_integer_vector());
-  EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->is_signed_integer_vector());
+    EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
 }
 
 TEST_P(ResolverBuiltinTest_FloatOrInt_TwoParam, Vector_Unsigned) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* call = Call(param.name, vec3<u32>(1u, 1u, 3u), vec3<u32>(1u, 1u, 3u));
-  WrapInFunction(call);
+    auto* call = Call(param.name, vec3<u32>(1_u, 1_u, 3_u), vec3<u32>(1_u, 1_u, 3_u));
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(call), nullptr);
-  EXPECT_TRUE(TypeOf(call)->is_unsigned_integer_vector());
-  EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->is_unsigned_integer_vector());
+    EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
 }
 
 TEST_P(ResolverBuiltinTest_FloatOrInt_TwoParam, Vector_Float) {
-  auto param = GetParam();
+    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);
+    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();
+    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);
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->is_float_vector());
+    EXPECT_EQ(TypeOf(call)->As<sem::Vector>()->Width(), 3u);
 }
 
 TEST_P(ResolverBuiltinTest_FloatOrInt_TwoParam, Error_NoParams) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* call = Call(param.name);
-  WrapInFunction(call);
+    auto* call = Call(param.name);
+    WrapInFunction(call);
 
-  EXPECT_FALSE(r()->Resolve());
+    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 f32, i32 or u32\n  " +
-                std::string(param.name) +
-                "(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  where: T is f32, i32 or u32\n  " +
+                                std::string(param.name) +
+                                "(vecN<T>, vecN<T>) -> vecN<T>  where: T is f32, i32 or u32\n");
 }
 
 INSTANTIATE_TEST_SUITE_P(ResolverTest,
                          ResolverBuiltinTest_FloatOrInt_TwoParam,
                          testing::Values(BuiltinData{"min", BuiltinType::kMin},
-                                         BuiltinData{"max",
-                                                     BuiltinType::kMax}));
+                                         BuiltinData{"max", BuiltinType::kMax}));
 
 TEST_F(ResolverBuiltinTest, Determinant_2x2) {
-  Global("var", ty.mat2x2<f32>(), ast::StorageClass::kPrivate);
+    Global("var", ty.mat2x2<f32>(), ast::StorageClass::kPrivate);
 
-  auto* call = Call("determinant", "var");
-  WrapInFunction(call);
+    auto* call = Call("determinant", "var");
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(call), nullptr);
-  EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
 }
 
 TEST_F(ResolverBuiltinTest, Determinant_3x3) {
-  Global("var", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
+    Global("var", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
 
-  auto* call = Call("determinant", "var");
-  WrapInFunction(call);
+    auto* call = Call("determinant", "var");
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(call), nullptr);
-  EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
 }
 
 TEST_F(ResolverBuiltinTest, Determinant_4x4) {
-  Global("var", ty.mat4x4<f32>(), ast::StorageClass::kPrivate);
+    Global("var", ty.mat4x4<f32>(), ast::StorageClass::kPrivate);
 
-  auto* call = Call("determinant", "var");
-  WrapInFunction(call);
+    auto* call = Call("determinant", "var");
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(call), nullptr);
-  EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
 }
 
 TEST_F(ResolverBuiltinTest, Determinant_NotSquare) {
-  Global("var", ty.mat2x3<f32>(), ast::StorageClass::kPrivate);
+    Global("var", ty.mat2x3<f32>(), ast::StorageClass::kPrivate);
 
-  auto* call = Call("determinant", "var");
-  WrapInFunction(call);
+    auto* call = Call("determinant", "var");
+    WrapInFunction(call);
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(r()->error(), R"(error: no matching call to determinant(mat2x3<f32>)
+    EXPECT_EQ(r()->error(), R"(error: no matching call to determinant(mat2x3<f32>)
 
 1 candidate function:
   determinant(matNxN<f32>) -> f32
@@ -1611,378 +1565,374 @@
 }
 
 TEST_F(ResolverBuiltinTest, Determinant_NotMatrix) {
-  Global("var", ty.f32(), ast::StorageClass::kPrivate);
+    Global("var", ty.f32(), ast::StorageClass::kPrivate);
 
-  auto* call = Call("determinant", "var");
-  WrapInFunction(call);
+    auto* call = Call("determinant", "var");
+    WrapInFunction(call);
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(r()->error(), R"(error: no matching call to determinant(f32)
+    EXPECT_EQ(r()->error(), R"(error: no matching call to determinant(f32)
 
 1 candidate function:
   determinant(matNxN<f32>) -> f32
 )");
 }
 
-using ResolverBuiltinTest_Texture =
-    ResolverTestWithParam<ast::builtin::test::TextureOverloadCase>;
+using ResolverBuiltinTest_Texture = ResolverTestWithParam<ast::builtin::test::TextureOverloadCase>;
 
-INSTANTIATE_TEST_SUITE_P(
-    ResolverTest,
-    ResolverBuiltinTest_Texture,
-    testing::ValuesIn(ast::builtin::test::TextureOverloadCase::ValidCases()));
+INSTANTIATE_TEST_SUITE_P(ResolverTest,
+                         ResolverBuiltinTest_Texture,
+                         testing::ValuesIn(ast::builtin::test::TextureOverloadCase::ValidCases()));
 
-std::string to_str(const std::string& function,
-                   const sem::ParameterList& params) {
-  std::stringstream out;
-  out << function << "(";
-  bool first = true;
-  for (auto* param : params) {
-    if (!first) {
-      out << ", ";
+std::string to_str(const std::string& function, const sem::ParameterList& params) {
+    std::stringstream out;
+    out << function << "(";
+    bool first = true;
+    for (auto* param : params) {
+        if (!first) {
+            out << ", ";
+        }
+        out << sem::str(param->Usage());
+        first = false;
     }
-    out << sem::str(param->Usage());
-    first = false;
-  }
-  out << ")";
-  return out.str();
+    out << ")";
+    return out.str();
 }
 
-const char* expected_texture_overload(
-    ast::builtin::test::ValidTextureOverload overload) {
-  using ValidTextureOverload = ast::builtin::test::ValidTextureOverload;
-  switch (overload) {
-    case ValidTextureOverload::kDimensions1d:
-    case ValidTextureOverload::kDimensions2d:
-    case ValidTextureOverload::kDimensions2dArray:
-    case ValidTextureOverload::kDimensions3d:
-    case ValidTextureOverload::kDimensionsCube:
-    case ValidTextureOverload::kDimensionsCubeArray:
-    case ValidTextureOverload::kDimensionsMultisampled2d:
-    case ValidTextureOverload::kDimensionsDepth2d:
-    case ValidTextureOverload::kDimensionsDepth2dArray:
-    case ValidTextureOverload::kDimensionsDepthCube:
-    case ValidTextureOverload::kDimensionsDepthCubeArray:
-    case ValidTextureOverload::kDimensionsDepthMultisampled2d:
-    case ValidTextureOverload::kDimensionsStorageWO1d:
-    case ValidTextureOverload::kDimensionsStorageWO2d:
-    case ValidTextureOverload::kDimensionsStorageWO2dArray:
-    case ValidTextureOverload::kDimensionsStorageWO3d:
-      return R"(textureDimensions(texture))";
-    case ValidTextureOverload::kGather2dF32:
-      return R"(textureGather(component, texture, sampler, coords))";
-    case ValidTextureOverload::kGather2dOffsetF32:
-      return R"(textureGather(component, texture, sampler, coords, offset))";
-    case ValidTextureOverload::kGather2dArrayF32:
-      return R"(textureGather(component, texture, sampler, coords, array_index))";
-    case ValidTextureOverload::kGather2dArrayOffsetF32:
-      return R"(textureGather(component, texture, sampler, coords, array_index, offset))";
-    case ValidTextureOverload::kGatherCubeF32:
-      return R"(textureGather(component, texture, sampler, coords))";
-    case ValidTextureOverload::kGatherCubeArrayF32:
-      return R"(textureGather(component, texture, sampler, coords, array_index))";
-    case ValidTextureOverload::kGatherDepth2dF32:
-      return R"(textureGather(texture, sampler, coords))";
-    case ValidTextureOverload::kGatherDepth2dOffsetF32:
-      return R"(textureGather(texture, sampler, coords, offset))";
-    case ValidTextureOverload::kGatherDepth2dArrayF32:
-      return R"(textureGather(texture, sampler, coords, array_index))";
-    case ValidTextureOverload::kGatherDepth2dArrayOffsetF32:
-      return R"(textureGather(texture, sampler, coords, array_index, offset))";
-    case ValidTextureOverload::kGatherDepthCubeF32:
-      return R"(textureGather(texture, sampler, coords))";
-    case ValidTextureOverload::kGatherDepthCubeArrayF32:
-      return R"(textureGather(texture, sampler, coords, array_index))";
-    case ValidTextureOverload::kGatherCompareDepth2dF32:
-      return R"(textureGatherCompare(texture, sampler, coords, depth_ref))";
-    case ValidTextureOverload::kGatherCompareDepth2dOffsetF32:
-      return R"(textureGatherCompare(texture, sampler, coords, depth_ref, offset))";
-    case ValidTextureOverload::kGatherCompareDepth2dArrayF32:
-      return R"(textureGatherCompare(texture, sampler, coords, array_index, depth_ref))";
-    case ValidTextureOverload::kGatherCompareDepth2dArrayOffsetF32:
-      return R"(textureGatherCompare(texture, sampler, coords, array_index, depth_ref, offset))";
-    case ValidTextureOverload::kGatherCompareDepthCubeF32:
-      return R"(textureGatherCompare(texture, sampler, coords, depth_ref))";
-    case ValidTextureOverload::kGatherCompareDepthCubeArrayF32:
-      return R"(textureGatherCompare(texture, sampler, coords, array_index, depth_ref))";
-    case ValidTextureOverload::kNumLayers2dArray:
-    case ValidTextureOverload::kNumLayersCubeArray:
-    case ValidTextureOverload::kNumLayersDepth2dArray:
-    case ValidTextureOverload::kNumLayersDepthCubeArray:
-    case ValidTextureOverload::kNumLayersStorageWO2dArray:
-      return R"(textureNumLayers(texture))";
-    case ValidTextureOverload::kNumLevels2d:
-    case ValidTextureOverload::kNumLevels2dArray:
-    case ValidTextureOverload::kNumLevels3d:
-    case ValidTextureOverload::kNumLevelsCube:
-    case ValidTextureOverload::kNumLevelsCubeArray:
-    case ValidTextureOverload::kNumLevelsDepth2d:
-    case ValidTextureOverload::kNumLevelsDepth2dArray:
-    case ValidTextureOverload::kNumLevelsDepthCube:
-    case ValidTextureOverload::kNumLevelsDepthCubeArray:
-      return R"(textureNumLevels(texture))";
-    case ValidTextureOverload::kNumSamplesDepthMultisampled2d:
-    case ValidTextureOverload::kNumSamplesMultisampled2d:
-      return R"(textureNumSamples(texture))";
-    case ValidTextureOverload::kDimensions2dLevel:
-    case ValidTextureOverload::kDimensions2dArrayLevel:
-    case ValidTextureOverload::kDimensions3dLevel:
-    case ValidTextureOverload::kDimensionsCubeLevel:
-    case ValidTextureOverload::kDimensionsCubeArrayLevel:
-    case ValidTextureOverload::kDimensionsDepth2dLevel:
-    case ValidTextureOverload::kDimensionsDepth2dArrayLevel:
-    case ValidTextureOverload::kDimensionsDepthCubeLevel:
-    case ValidTextureOverload::kDimensionsDepthCubeArrayLevel:
-      return R"(textureDimensions(texture, level))";
-    case ValidTextureOverload::kSample1dF32:
-      return R"(textureSample(texture, sampler, coords))";
-    case ValidTextureOverload::kSample2dF32:
-      return R"(textureSample(texture, sampler, coords))";
-    case ValidTextureOverload::kSample2dOffsetF32:
-      return R"(textureSample(texture, sampler, coords, offset))";
-    case ValidTextureOverload::kSample2dArrayF32:
-      return R"(textureSample(texture, sampler, coords, array_index))";
-    case ValidTextureOverload::kSample2dArrayOffsetF32:
-      return R"(textureSample(texture, sampler, coords, array_index, offset))";
-    case ValidTextureOverload::kSample3dF32:
-      return R"(textureSample(texture, sampler, coords))";
-    case ValidTextureOverload::kSample3dOffsetF32:
-      return R"(textureSample(texture, sampler, coords, offset))";
-    case ValidTextureOverload::kSampleCubeF32:
-      return R"(textureSample(texture, sampler, coords))";
-    case ValidTextureOverload::kSampleCubeArrayF32:
-      return R"(textureSample(texture, sampler, coords, array_index))";
-    case ValidTextureOverload::kSampleDepth2dF32:
-      return R"(textureSample(texture, sampler, coords))";
-    case ValidTextureOverload::kSampleDepth2dOffsetF32:
-      return R"(textureSample(texture, sampler, coords, offset))";
-    case ValidTextureOverload::kSampleDepth2dArrayF32:
-      return R"(textureSample(texture, sampler, coords, array_index))";
-    case ValidTextureOverload::kSampleDepth2dArrayOffsetF32:
-      return R"(textureSample(texture, sampler, coords, array_index, offset))";
-    case ValidTextureOverload::kSampleDepthCubeF32:
-      return R"(textureSample(texture, sampler, coords))";
-    case ValidTextureOverload::kSampleDepthCubeArrayF32:
-      return R"(textureSample(texture, sampler, coords, array_index))";
-    case ValidTextureOverload::kSampleBias2dF32:
-      return R"(textureSampleBias(texture, sampler, coords, bias))";
-    case ValidTextureOverload::kSampleBias2dOffsetF32:
-      return R"(textureSampleBias(texture, sampler, coords, bias, offset))";
-    case ValidTextureOverload::kSampleBias2dArrayF32:
-      return R"(textureSampleBias(texture, sampler, coords, array_index, bias))";
-    case ValidTextureOverload::kSampleBias2dArrayOffsetF32:
-      return R"(textureSampleBias(texture, sampler, coords, array_index, bias, offset))";
-    case ValidTextureOverload::kSampleBias3dF32:
-      return R"(textureSampleBias(texture, sampler, coords, bias))";
-    case ValidTextureOverload::kSampleBias3dOffsetF32:
-      return R"(textureSampleBias(texture, sampler, coords, bias, offset))";
-    case ValidTextureOverload::kSampleBiasCubeF32:
-      return R"(textureSampleBias(texture, sampler, coords, bias))";
-    case ValidTextureOverload::kSampleBiasCubeArrayF32:
-      return R"(textureSampleBias(texture, sampler, coords, array_index, bias))";
-    case ValidTextureOverload::kSampleLevel2dF32:
-      return R"(textureSampleLevel(texture, sampler, coords, level))";
-    case ValidTextureOverload::kSampleLevel2dOffsetF32:
-      return R"(textureSampleLevel(texture, sampler, coords, level, offset))";
-    case ValidTextureOverload::kSampleLevel2dArrayF32:
-      return R"(textureSampleLevel(texture, sampler, coords, array_index, level))";
-    case ValidTextureOverload::kSampleLevel2dArrayOffsetF32:
-      return R"(textureSampleLevel(texture, sampler, coords, array_index, level, offset))";
-    case ValidTextureOverload::kSampleLevel3dF32:
-      return R"(textureSampleLevel(texture, sampler, coords, level))";
-    case ValidTextureOverload::kSampleLevel3dOffsetF32:
-      return R"(textureSampleLevel(texture, sampler, coords, level, offset))";
-    case ValidTextureOverload::kSampleLevelCubeF32:
-      return R"(textureSampleLevel(texture, sampler, coords, level))";
-    case ValidTextureOverload::kSampleLevelCubeArrayF32:
-      return R"(textureSampleLevel(texture, sampler, coords, array_index, level))";
-    case ValidTextureOverload::kSampleLevelDepth2dF32:
-      return R"(textureSampleLevel(texture, sampler, coords, level))";
-    case ValidTextureOverload::kSampleLevelDepth2dOffsetF32:
-      return R"(textureSampleLevel(texture, sampler, coords, level, offset))";
-    case ValidTextureOverload::kSampleLevelDepth2dArrayF32:
-      return R"(textureSampleLevel(texture, sampler, coords, array_index, level))";
-    case ValidTextureOverload::kSampleLevelDepth2dArrayOffsetF32:
-      return R"(textureSampleLevel(texture, sampler, coords, array_index, level, offset))";
-    case ValidTextureOverload::kSampleLevelDepthCubeF32:
-      return R"(textureSampleLevel(texture, sampler, coords, level))";
-    case ValidTextureOverload::kSampleLevelDepthCubeArrayF32:
-      return R"(textureSampleLevel(texture, sampler, coords, array_index, level))";
-    case ValidTextureOverload::kSampleGrad2dF32:
-      return R"(textureSampleGrad(texture, sampler, coords, ddx, ddy))";
-    case ValidTextureOverload::kSampleGrad2dOffsetF32:
-      return R"(textureSampleGrad(texture, sampler, coords, ddx, ddy, offset))";
-    case ValidTextureOverload::kSampleGrad2dArrayF32:
-      return R"(textureSampleGrad(texture, sampler, coords, array_index, ddx, ddy))";
-    case ValidTextureOverload::kSampleGrad2dArrayOffsetF32:
-      return R"(textureSampleGrad(texture, sampler, coords, array_index, ddx, ddy, offset))";
-    case ValidTextureOverload::kSampleGrad3dF32:
-      return R"(textureSampleGrad(texture, sampler, coords, ddx, ddy))";
-    case ValidTextureOverload::kSampleGrad3dOffsetF32:
-      return R"(textureSampleGrad(texture, sampler, coords, ddx, ddy, offset))";
-    case ValidTextureOverload::kSampleGradCubeF32:
-      return R"(textureSampleGrad(texture, sampler, coords, ddx, ddy))";
-    case ValidTextureOverload::kSampleGradCubeArrayF32:
-      return R"(textureSampleGrad(texture, sampler, coords, array_index, ddx, ddy))";
-    case ValidTextureOverload::kSampleCompareDepth2dF32:
-      return R"(textureSampleCompare(texture, sampler, coords, depth_ref))";
-    case ValidTextureOverload::kSampleCompareDepth2dOffsetF32:
-      return R"(textureSampleCompare(texture, sampler, coords, depth_ref, offset))";
-    case ValidTextureOverload::kSampleCompareDepth2dArrayF32:
-      return R"(textureSampleCompare(texture, sampler, coords, array_index, depth_ref))";
-    case ValidTextureOverload::kSampleCompareDepth2dArrayOffsetF32:
-      return R"(textureSampleCompare(texture, sampler, coords, array_index, depth_ref, offset))";
-    case ValidTextureOverload::kSampleCompareDepthCubeF32:
-      return R"(textureSampleCompare(texture, sampler, coords, depth_ref))";
-    case ValidTextureOverload::kSampleCompareDepthCubeArrayF32:
-      return R"(textureSampleCompare(texture, sampler, coords, array_index, depth_ref))";
-    case ValidTextureOverload::kSampleCompareLevelDepth2dF32:
-      return R"(textureSampleCompare(texture, sampler, coords, depth_ref))";
-    case ValidTextureOverload::kSampleCompareLevelDepth2dOffsetF32:
-      return R"(textureSampleCompare(texture, sampler, coords, depth_ref, offset))";
-    case ValidTextureOverload::kSampleCompareLevelDepth2dArrayF32:
-      return R"(textureSampleCompare(texture, sampler, coords, array_index, depth_ref))";
-    case ValidTextureOverload::kSampleCompareLevelDepth2dArrayOffsetF32:
-      return R"(textureSampleCompare(texture, sampler, coords, array_index, depth_ref, offset))";
-    case ValidTextureOverload::kSampleCompareLevelDepthCubeF32:
-      return R"(textureSampleCompare(texture, sampler, coords, depth_ref))";
-    case ValidTextureOverload::kSampleCompareLevelDepthCubeArrayF32:
-      return R"(textureSampleCompare(texture, sampler, coords, array_index, depth_ref))";
-    case ValidTextureOverload::kLoad1dLevelF32:
-    case ValidTextureOverload::kLoad1dLevelU32:
-    case ValidTextureOverload::kLoad1dLevelI32:
-    case ValidTextureOverload::kLoad2dLevelF32:
-    case ValidTextureOverload::kLoad2dLevelU32:
-    case ValidTextureOverload::kLoad2dLevelI32:
-      return R"(textureLoad(texture, coords, level))";
-    case ValidTextureOverload::kLoad2dArrayLevelF32:
-    case ValidTextureOverload::kLoad2dArrayLevelU32:
-    case ValidTextureOverload::kLoad2dArrayLevelI32:
-      return R"(textureLoad(texture, coords, array_index, level))";
-    case ValidTextureOverload::kLoad3dLevelF32:
-    case ValidTextureOverload::kLoad3dLevelU32:
-    case ValidTextureOverload::kLoad3dLevelI32:
-    case ValidTextureOverload::kLoadDepth2dLevelF32:
-      return R"(textureLoad(texture, coords, level))";
-    case ValidTextureOverload::kLoadDepthMultisampled2dF32:
-    case ValidTextureOverload::kLoadMultisampled2dF32:
-    case ValidTextureOverload::kLoadMultisampled2dU32:
-    case ValidTextureOverload::kLoadMultisampled2dI32:
-      return R"(textureLoad(texture, coords, sample_index))";
-    case ValidTextureOverload::kLoadDepth2dArrayLevelF32:
-      return R"(textureLoad(texture, coords, array_index, level))";
-    case ValidTextureOverload::kStoreWO1dRgba32float:
-    case ValidTextureOverload::kStoreWO2dRgba32float:
-    case ValidTextureOverload::kStoreWO3dRgba32float:
-      return R"(textureStore(texture, coords, value))";
-    case ValidTextureOverload::kStoreWO2dArrayRgba32float:
-      return R"(textureStore(texture, coords, array_index, value))";
-  }
-  return "<unmatched texture overload>";
+const char* expected_texture_overload(ast::builtin::test::ValidTextureOverload overload) {
+    using ValidTextureOverload = ast::builtin::test::ValidTextureOverload;
+    switch (overload) {
+        case ValidTextureOverload::kDimensions1d:
+        case ValidTextureOverload::kDimensions2d:
+        case ValidTextureOverload::kDimensions2dArray:
+        case ValidTextureOverload::kDimensions3d:
+        case ValidTextureOverload::kDimensionsCube:
+        case ValidTextureOverload::kDimensionsCubeArray:
+        case ValidTextureOverload::kDimensionsMultisampled2d:
+        case ValidTextureOverload::kDimensionsDepth2d:
+        case ValidTextureOverload::kDimensionsDepth2dArray:
+        case ValidTextureOverload::kDimensionsDepthCube:
+        case ValidTextureOverload::kDimensionsDepthCubeArray:
+        case ValidTextureOverload::kDimensionsDepthMultisampled2d:
+        case ValidTextureOverload::kDimensionsStorageWO1d:
+        case ValidTextureOverload::kDimensionsStorageWO2d:
+        case ValidTextureOverload::kDimensionsStorageWO2dArray:
+        case ValidTextureOverload::kDimensionsStorageWO3d:
+            return R"(textureDimensions(texture))";
+        case ValidTextureOverload::kGather2dF32:
+            return R"(textureGather(component, texture, sampler, coords))";
+        case ValidTextureOverload::kGather2dOffsetF32:
+            return R"(textureGather(component, texture, sampler, coords, offset))";
+        case ValidTextureOverload::kGather2dArrayF32:
+            return R"(textureGather(component, texture, sampler, coords, array_index))";
+        case ValidTextureOverload::kGather2dArrayOffsetF32:
+            return R"(textureGather(component, texture, sampler, coords, array_index, offset))";
+        case ValidTextureOverload::kGatherCubeF32:
+            return R"(textureGather(component, texture, sampler, coords))";
+        case ValidTextureOverload::kGatherCubeArrayF32:
+            return R"(textureGather(component, texture, sampler, coords, array_index))";
+        case ValidTextureOverload::kGatherDepth2dF32:
+            return R"(textureGather(texture, sampler, coords))";
+        case ValidTextureOverload::kGatherDepth2dOffsetF32:
+            return R"(textureGather(texture, sampler, coords, offset))";
+        case ValidTextureOverload::kGatherDepth2dArrayF32:
+            return R"(textureGather(texture, sampler, coords, array_index))";
+        case ValidTextureOverload::kGatherDepth2dArrayOffsetF32:
+            return R"(textureGather(texture, sampler, coords, array_index, offset))";
+        case ValidTextureOverload::kGatherDepthCubeF32:
+            return R"(textureGather(texture, sampler, coords))";
+        case ValidTextureOverload::kGatherDepthCubeArrayF32:
+            return R"(textureGather(texture, sampler, coords, array_index))";
+        case ValidTextureOverload::kGatherCompareDepth2dF32:
+            return R"(textureGatherCompare(texture, sampler, coords, depth_ref))";
+        case ValidTextureOverload::kGatherCompareDepth2dOffsetF32:
+            return R"(textureGatherCompare(texture, sampler, coords, depth_ref, offset))";
+        case ValidTextureOverload::kGatherCompareDepth2dArrayF32:
+            return R"(textureGatherCompare(texture, sampler, coords, array_index, depth_ref))";
+        case ValidTextureOverload::kGatherCompareDepth2dArrayOffsetF32:
+            return R"(textureGatherCompare(texture, sampler, coords, array_index, depth_ref, offset))";
+        case ValidTextureOverload::kGatherCompareDepthCubeF32:
+            return R"(textureGatherCompare(texture, sampler, coords, depth_ref))";
+        case ValidTextureOverload::kGatherCompareDepthCubeArrayF32:
+            return R"(textureGatherCompare(texture, sampler, coords, array_index, depth_ref))";
+        case ValidTextureOverload::kNumLayers2dArray:
+        case ValidTextureOverload::kNumLayersCubeArray:
+        case ValidTextureOverload::kNumLayersDepth2dArray:
+        case ValidTextureOverload::kNumLayersDepthCubeArray:
+        case ValidTextureOverload::kNumLayersStorageWO2dArray:
+            return R"(textureNumLayers(texture))";
+        case ValidTextureOverload::kNumLevels2d:
+        case ValidTextureOverload::kNumLevels2dArray:
+        case ValidTextureOverload::kNumLevels3d:
+        case ValidTextureOverload::kNumLevelsCube:
+        case ValidTextureOverload::kNumLevelsCubeArray:
+        case ValidTextureOverload::kNumLevelsDepth2d:
+        case ValidTextureOverload::kNumLevelsDepth2dArray:
+        case ValidTextureOverload::kNumLevelsDepthCube:
+        case ValidTextureOverload::kNumLevelsDepthCubeArray:
+            return R"(textureNumLevels(texture))";
+        case ValidTextureOverload::kNumSamplesDepthMultisampled2d:
+        case ValidTextureOverload::kNumSamplesMultisampled2d:
+            return R"(textureNumSamples(texture))";
+        case ValidTextureOverload::kDimensions2dLevel:
+        case ValidTextureOverload::kDimensions2dArrayLevel:
+        case ValidTextureOverload::kDimensions3dLevel:
+        case ValidTextureOverload::kDimensionsCubeLevel:
+        case ValidTextureOverload::kDimensionsCubeArrayLevel:
+        case ValidTextureOverload::kDimensionsDepth2dLevel:
+        case ValidTextureOverload::kDimensionsDepth2dArrayLevel:
+        case ValidTextureOverload::kDimensionsDepthCubeLevel:
+        case ValidTextureOverload::kDimensionsDepthCubeArrayLevel:
+            return R"(textureDimensions(texture, level))";
+        case ValidTextureOverload::kSample1dF32:
+            return R"(textureSample(texture, sampler, coords))";
+        case ValidTextureOverload::kSample2dF32:
+            return R"(textureSample(texture, sampler, coords))";
+        case ValidTextureOverload::kSample2dOffsetF32:
+            return R"(textureSample(texture, sampler, coords, offset))";
+        case ValidTextureOverload::kSample2dArrayF32:
+            return R"(textureSample(texture, sampler, coords, array_index))";
+        case ValidTextureOverload::kSample2dArrayOffsetF32:
+            return R"(textureSample(texture, sampler, coords, array_index, offset))";
+        case ValidTextureOverload::kSample3dF32:
+            return R"(textureSample(texture, sampler, coords))";
+        case ValidTextureOverload::kSample3dOffsetF32:
+            return R"(textureSample(texture, sampler, coords, offset))";
+        case ValidTextureOverload::kSampleCubeF32:
+            return R"(textureSample(texture, sampler, coords))";
+        case ValidTextureOverload::kSampleCubeArrayF32:
+            return R"(textureSample(texture, sampler, coords, array_index))";
+        case ValidTextureOverload::kSampleDepth2dF32:
+            return R"(textureSample(texture, sampler, coords))";
+        case ValidTextureOverload::kSampleDepth2dOffsetF32:
+            return R"(textureSample(texture, sampler, coords, offset))";
+        case ValidTextureOverload::kSampleDepth2dArrayF32:
+            return R"(textureSample(texture, sampler, coords, array_index))";
+        case ValidTextureOverload::kSampleDepth2dArrayOffsetF32:
+            return R"(textureSample(texture, sampler, coords, array_index, offset))";
+        case ValidTextureOverload::kSampleDepthCubeF32:
+            return R"(textureSample(texture, sampler, coords))";
+        case ValidTextureOverload::kSampleDepthCubeArrayF32:
+            return R"(textureSample(texture, sampler, coords, array_index))";
+        case ValidTextureOverload::kSampleBias2dF32:
+            return R"(textureSampleBias(texture, sampler, coords, bias))";
+        case ValidTextureOverload::kSampleBias2dOffsetF32:
+            return R"(textureSampleBias(texture, sampler, coords, bias, offset))";
+        case ValidTextureOverload::kSampleBias2dArrayF32:
+            return R"(textureSampleBias(texture, sampler, coords, array_index, bias))";
+        case ValidTextureOverload::kSampleBias2dArrayOffsetF32:
+            return R"(textureSampleBias(texture, sampler, coords, array_index, bias, offset))";
+        case ValidTextureOverload::kSampleBias3dF32:
+            return R"(textureSampleBias(texture, sampler, coords, bias))";
+        case ValidTextureOverload::kSampleBias3dOffsetF32:
+            return R"(textureSampleBias(texture, sampler, coords, bias, offset))";
+        case ValidTextureOverload::kSampleBiasCubeF32:
+            return R"(textureSampleBias(texture, sampler, coords, bias))";
+        case ValidTextureOverload::kSampleBiasCubeArrayF32:
+            return R"(textureSampleBias(texture, sampler, coords, array_index, bias))";
+        case ValidTextureOverload::kSampleLevel2dF32:
+            return R"(textureSampleLevel(texture, sampler, coords, level))";
+        case ValidTextureOverload::kSampleLevel2dOffsetF32:
+            return R"(textureSampleLevel(texture, sampler, coords, level, offset))";
+        case ValidTextureOverload::kSampleLevel2dArrayF32:
+            return R"(textureSampleLevel(texture, sampler, coords, array_index, level))";
+        case ValidTextureOverload::kSampleLevel2dArrayOffsetF32:
+            return R"(textureSampleLevel(texture, sampler, coords, array_index, level, offset))";
+        case ValidTextureOverload::kSampleLevel3dF32:
+            return R"(textureSampleLevel(texture, sampler, coords, level))";
+        case ValidTextureOverload::kSampleLevel3dOffsetF32:
+            return R"(textureSampleLevel(texture, sampler, coords, level, offset))";
+        case ValidTextureOverload::kSampleLevelCubeF32:
+            return R"(textureSampleLevel(texture, sampler, coords, level))";
+        case ValidTextureOverload::kSampleLevelCubeArrayF32:
+            return R"(textureSampleLevel(texture, sampler, coords, array_index, level))";
+        case ValidTextureOverload::kSampleLevelDepth2dF32:
+            return R"(textureSampleLevel(texture, sampler, coords, level))";
+        case ValidTextureOverload::kSampleLevelDepth2dOffsetF32:
+            return R"(textureSampleLevel(texture, sampler, coords, level, offset))";
+        case ValidTextureOverload::kSampleLevelDepth2dArrayF32:
+            return R"(textureSampleLevel(texture, sampler, coords, array_index, level))";
+        case ValidTextureOverload::kSampleLevelDepth2dArrayOffsetF32:
+            return R"(textureSampleLevel(texture, sampler, coords, array_index, level, offset))";
+        case ValidTextureOverload::kSampleLevelDepthCubeF32:
+            return R"(textureSampleLevel(texture, sampler, coords, level))";
+        case ValidTextureOverload::kSampleLevelDepthCubeArrayF32:
+            return R"(textureSampleLevel(texture, sampler, coords, array_index, level))";
+        case ValidTextureOverload::kSampleGrad2dF32:
+            return R"(textureSampleGrad(texture, sampler, coords, ddx, ddy))";
+        case ValidTextureOverload::kSampleGrad2dOffsetF32:
+            return R"(textureSampleGrad(texture, sampler, coords, ddx, ddy, offset))";
+        case ValidTextureOverload::kSampleGrad2dArrayF32:
+            return R"(textureSampleGrad(texture, sampler, coords, array_index, ddx, ddy))";
+        case ValidTextureOverload::kSampleGrad2dArrayOffsetF32:
+            return R"(textureSampleGrad(texture, sampler, coords, array_index, ddx, ddy, offset))";
+        case ValidTextureOverload::kSampleGrad3dF32:
+            return R"(textureSampleGrad(texture, sampler, coords, ddx, ddy))";
+        case ValidTextureOverload::kSampleGrad3dOffsetF32:
+            return R"(textureSampleGrad(texture, sampler, coords, ddx, ddy, offset))";
+        case ValidTextureOverload::kSampleGradCubeF32:
+            return R"(textureSampleGrad(texture, sampler, coords, ddx, ddy))";
+        case ValidTextureOverload::kSampleGradCubeArrayF32:
+            return R"(textureSampleGrad(texture, sampler, coords, array_index, ddx, ddy))";
+        case ValidTextureOverload::kSampleCompareDepth2dF32:
+            return R"(textureSampleCompare(texture, sampler, coords, depth_ref))";
+        case ValidTextureOverload::kSampleCompareDepth2dOffsetF32:
+            return R"(textureSampleCompare(texture, sampler, coords, depth_ref, offset))";
+        case ValidTextureOverload::kSampleCompareDepth2dArrayF32:
+            return R"(textureSampleCompare(texture, sampler, coords, array_index, depth_ref))";
+        case ValidTextureOverload::kSampleCompareDepth2dArrayOffsetF32:
+            return R"(textureSampleCompare(texture, sampler, coords, array_index, depth_ref, offset))";
+        case ValidTextureOverload::kSampleCompareDepthCubeF32:
+            return R"(textureSampleCompare(texture, sampler, coords, depth_ref))";
+        case ValidTextureOverload::kSampleCompareDepthCubeArrayF32:
+            return R"(textureSampleCompare(texture, sampler, coords, array_index, depth_ref))";
+        case ValidTextureOverload::kSampleCompareLevelDepth2dF32:
+            return R"(textureSampleCompare(texture, sampler, coords, depth_ref))";
+        case ValidTextureOverload::kSampleCompareLevelDepth2dOffsetF32:
+            return R"(textureSampleCompare(texture, sampler, coords, depth_ref, offset))";
+        case ValidTextureOverload::kSampleCompareLevelDepth2dArrayF32:
+            return R"(textureSampleCompare(texture, sampler, coords, array_index, depth_ref))";
+        case ValidTextureOverload::kSampleCompareLevelDepth2dArrayOffsetF32:
+            return R"(textureSampleCompare(texture, sampler, coords, array_index, depth_ref, offset))";
+        case ValidTextureOverload::kSampleCompareLevelDepthCubeF32:
+            return R"(textureSampleCompare(texture, sampler, coords, depth_ref))";
+        case ValidTextureOverload::kSampleCompareLevelDepthCubeArrayF32:
+            return R"(textureSampleCompare(texture, sampler, coords, array_index, depth_ref))";
+        case ValidTextureOverload::kLoad1dLevelF32:
+        case ValidTextureOverload::kLoad1dLevelU32:
+        case ValidTextureOverload::kLoad1dLevelI32:
+        case ValidTextureOverload::kLoad2dLevelF32:
+        case ValidTextureOverload::kLoad2dLevelU32:
+        case ValidTextureOverload::kLoad2dLevelI32:
+            return R"(textureLoad(texture, coords, level))";
+        case ValidTextureOverload::kLoad2dArrayLevelF32:
+        case ValidTextureOverload::kLoad2dArrayLevelU32:
+        case ValidTextureOverload::kLoad2dArrayLevelI32:
+            return R"(textureLoad(texture, coords, array_index, level))";
+        case ValidTextureOverload::kLoad3dLevelF32:
+        case ValidTextureOverload::kLoad3dLevelU32:
+        case ValidTextureOverload::kLoad3dLevelI32:
+        case ValidTextureOverload::kLoadDepth2dLevelF32:
+            return R"(textureLoad(texture, coords, level))";
+        case ValidTextureOverload::kLoadDepthMultisampled2dF32:
+        case ValidTextureOverload::kLoadMultisampled2dF32:
+        case ValidTextureOverload::kLoadMultisampled2dU32:
+        case ValidTextureOverload::kLoadMultisampled2dI32:
+            return R"(textureLoad(texture, coords, sample_index))";
+        case ValidTextureOverload::kLoadDepth2dArrayLevelF32:
+            return R"(textureLoad(texture, coords, array_index, level))";
+        case ValidTextureOverload::kStoreWO1dRgba32float:
+        case ValidTextureOverload::kStoreWO2dRgba32float:
+        case ValidTextureOverload::kStoreWO3dRgba32float:
+            return R"(textureStore(texture, coords, value))";
+        case ValidTextureOverload::kStoreWO2dArrayRgba32float:
+            return R"(textureStore(texture, coords, array_index, value))";
+    }
+    return "<unmatched texture overload>";
 }
 
 TEST_P(ResolverBuiltinTest_Texture, Call) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  param.BuildTextureVariable(this);
-  param.BuildSamplerVariable(this);
+    param.BuildTextureVariable(this);
+    param.BuildSamplerVariable(this);
 
-  auto* call = Call(param.function, param.args(this));
-  auto* stmt = CallStmt(call);
-  Func("func", {}, ty.void_(), {stmt}, {Stage(ast::PipelineStage::kFragment)});
+    auto* call = Call(param.function, param.args(this));
+    auto* stmt = CallStmt(call);
+    Func("func", {}, ty.void_(), {stmt}, {Stage(ast::PipelineStage::kFragment)});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  if (std::string(param.function) == "textureDimensions") {
-    switch (param.texture_dimension) {
-      default:
-        FAIL() << "invalid texture dimensions: " << param.texture_dimension;
-      case ast::TextureDimension::k1d:
-        EXPECT_TRUE(TypeOf(call)->Is<sem::I32>());
-        break;
-      case ast::TextureDimension::k2d:
-      case ast::TextureDimension::k2dArray:
-      case ast::TextureDimension::kCube:
-      case ast::TextureDimension::kCubeArray: {
-        auto* vec = As<sem::Vector>(TypeOf(call));
-        ASSERT_NE(vec, nullptr);
-        EXPECT_EQ(vec->Width(), 2u);
-        EXPECT_TRUE(vec->type()->Is<sem::I32>());
-        break;
-      }
-      case ast::TextureDimension::k3d: {
-        auto* vec = As<sem::Vector>(TypeOf(call));
-        ASSERT_NE(vec, nullptr);
-        EXPECT_EQ(vec->Width(), 3u);
-        EXPECT_TRUE(vec->type()->Is<sem::I32>());
-        break;
-      }
-    }
-  } else if (std::string(param.function) == "textureNumLayers") {
-    EXPECT_TRUE(TypeOf(call)->Is<sem::I32>());
-  } else if (std::string(param.function) == "textureNumLevels") {
-    EXPECT_TRUE(TypeOf(call)->Is<sem::I32>());
-  } else if (std::string(param.function) == "textureNumSamples") {
-    EXPECT_TRUE(TypeOf(call)->Is<sem::I32>());
-  } else if (std::string(param.function) == "textureStore") {
-    EXPECT_TRUE(TypeOf(call)->Is<sem::Void>());
-  } else if (std::string(param.function) == "textureGather") {
-    auto* vec = As<sem::Vector>(TypeOf(call));
-    ASSERT_NE(vec, nullptr);
-    EXPECT_EQ(vec->Width(), 4u);
-    switch (param.texture_data_type) {
-      case ast::builtin::test::TextureDataType::kF32:
-        EXPECT_TRUE(vec->type()->Is<sem::F32>());
-        break;
-      case ast::builtin::test::TextureDataType::kU32:
-        EXPECT_TRUE(vec->type()->Is<sem::U32>());
-        break;
-      case ast::builtin::test::TextureDataType::kI32:
-        EXPECT_TRUE(vec->type()->Is<sem::I32>());
-        break;
-    }
-  } else if (std::string(param.function) == "textureGatherCompare") {
-    auto* vec = As<sem::Vector>(TypeOf(call));
-    ASSERT_NE(vec, nullptr);
-    EXPECT_EQ(vec->Width(), 4u);
-    EXPECT_TRUE(vec->type()->Is<sem::F32>());
-  } else {
-    switch (param.texture_kind) {
-      case ast::builtin::test::TextureKind::kRegular:
-      case ast::builtin::test::TextureKind::kMultisampled:
-      case ast::builtin::test::TextureKind::kStorage: {
-        auto* vec = TypeOf(call)->As<sem::Vector>();
-        ASSERT_NE(vec, nullptr);
-        switch (param.texture_data_type) {
-          case ast::builtin::test::TextureDataType::kF32:
-            EXPECT_TRUE(vec->type()->Is<sem::F32>());
-            break;
-          case ast::builtin::test::TextureDataType::kU32:
-            EXPECT_TRUE(vec->type()->Is<sem::U32>());
-            break;
-          case ast::builtin::test::TextureDataType::kI32:
-            EXPECT_TRUE(vec->type()->Is<sem::I32>());
-            break;
+    if (std::string(param.function) == "textureDimensions") {
+        switch (param.texture_dimension) {
+            default:
+                FAIL() << "invalid texture dimensions: " << param.texture_dimension;
+            case ast::TextureDimension::k1d:
+                EXPECT_TRUE(TypeOf(call)->Is<sem::I32>());
+                break;
+            case ast::TextureDimension::k2d:
+            case ast::TextureDimension::k2dArray:
+            case ast::TextureDimension::kCube:
+            case ast::TextureDimension::kCubeArray: {
+                auto* vec = As<sem::Vector>(TypeOf(call));
+                ASSERT_NE(vec, nullptr);
+                EXPECT_EQ(vec->Width(), 2u);
+                EXPECT_TRUE(vec->type()->Is<sem::I32>());
+                break;
+            }
+            case ast::TextureDimension::k3d: {
+                auto* vec = As<sem::Vector>(TypeOf(call));
+                ASSERT_NE(vec, nullptr);
+                EXPECT_EQ(vec->Width(), 3u);
+                EXPECT_TRUE(vec->type()->Is<sem::I32>());
+                break;
+            }
         }
-        break;
-      }
-      case ast::builtin::test::TextureKind::kDepth:
-      case ast::builtin::test::TextureKind::kDepthMultisampled: {
-        EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
-        break;
-      }
+    } else if (std::string(param.function) == "textureNumLayers") {
+        EXPECT_TRUE(TypeOf(call)->Is<sem::I32>());
+    } else if (std::string(param.function) == "textureNumLevels") {
+        EXPECT_TRUE(TypeOf(call)->Is<sem::I32>());
+    } else if (std::string(param.function) == "textureNumSamples") {
+        EXPECT_TRUE(TypeOf(call)->Is<sem::I32>());
+    } else if (std::string(param.function) == "textureStore") {
+        EXPECT_TRUE(TypeOf(call)->Is<sem::Void>());
+    } else if (std::string(param.function) == "textureGather") {
+        auto* vec = As<sem::Vector>(TypeOf(call));
+        ASSERT_NE(vec, nullptr);
+        EXPECT_EQ(vec->Width(), 4u);
+        switch (param.texture_data_type) {
+            case ast::builtin::test::TextureDataType::kF32:
+                EXPECT_TRUE(vec->type()->Is<sem::F32>());
+                break;
+            case ast::builtin::test::TextureDataType::kU32:
+                EXPECT_TRUE(vec->type()->Is<sem::U32>());
+                break;
+            case ast::builtin::test::TextureDataType::kI32:
+                EXPECT_TRUE(vec->type()->Is<sem::I32>());
+                break;
+        }
+    } else if (std::string(param.function) == "textureGatherCompare") {
+        auto* vec = As<sem::Vector>(TypeOf(call));
+        ASSERT_NE(vec, nullptr);
+        EXPECT_EQ(vec->Width(), 4u);
+        EXPECT_TRUE(vec->type()->Is<sem::F32>());
+    } else {
+        switch (param.texture_kind) {
+            case ast::builtin::test::TextureKind::kRegular:
+            case ast::builtin::test::TextureKind::kMultisampled:
+            case ast::builtin::test::TextureKind::kStorage: {
+                auto* vec = TypeOf(call)->As<sem::Vector>();
+                ASSERT_NE(vec, nullptr);
+                switch (param.texture_data_type) {
+                    case ast::builtin::test::TextureDataType::kF32:
+                        EXPECT_TRUE(vec->type()->Is<sem::F32>());
+                        break;
+                    case ast::builtin::test::TextureDataType::kU32:
+                        EXPECT_TRUE(vec->type()->Is<sem::U32>());
+                        break;
+                    case ast::builtin::test::TextureDataType::kI32:
+                        EXPECT_TRUE(vec->type()->Is<sem::I32>());
+                        break;
+                }
+                break;
+            }
+            case ast::builtin::test::TextureKind::kDepth:
+            case ast::builtin::test::TextureKind::kDepthMultisampled: {
+                EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
+                break;
+            }
+        }
     }
-  }
 
-  auto* call_sem = Sem().Get(call);
-  ASSERT_NE(call_sem, nullptr);
-  auto* target = call_sem->Target();
-  ASSERT_NE(target, nullptr);
+    auto* call_sem = Sem().Get(call);
+    ASSERT_NE(call_sem, nullptr);
+    auto* target = call_sem->Target();
+    ASSERT_NE(target, nullptr);
 
-  auto got = resolver::to_str(param.function, target->Parameters());
-  auto* expected = expected_texture_overload(param.overload);
-  EXPECT_EQ(got, expected);
+    auto got = resolver::to_str(param.function, target->Parameters());
+    auto* expected = expected_texture_overload(param.overload);
+    EXPECT_EQ(got, expected);
 }
 
 }  // namespace
diff --git a/src/tint/resolver/builtin_validation_test.cc b/src/tint/resolver/builtin_validation_test.cc
index df6a0a9..98e29fa 100644
--- a/src/tint/resolver/builtin_validation_test.cc
+++ b/src/tint/resolver/builtin_validation_test.cc
@@ -15,58 +15,56 @@
 #include "src/tint/ast/builtin_texture_helper_test.h"
 #include "src/tint/resolver/resolver_test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::resolver {
 namespace {
 
 using ResolverBuiltinValidationTest = ResolverTest;
 
-TEST_F(ResolverBuiltinValidationTest,
-       FunctionTypeMustMatchReturnStatementType_void_fail) {
-  // fn func { return workgroupBarrier(); }
-  Func("func", {}, ty.void_(),
-       {
-           Return(Call(Source{Source::Location{12, 34}}, "workgroupBarrier")),
-       });
+TEST_F(ResolverBuiltinValidationTest, FunctionTypeMustMatchReturnStatementType_void_fail) {
+    // fn func { return workgroupBarrier(); }
+    Func("func", {}, ty.void_(),
+         {
+             Return(Call(Source{Source::Location{12, 34}}, "workgroupBarrier")),
+         });
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: builtin 'workgroupBarrier' does not return a value");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: builtin 'workgroupBarrier' does not return a value");
 }
 
 TEST_F(ResolverBuiltinValidationTest, InvalidPipelineStageDirect) {
-  // @stage(compute) @workgroup_size(1) fn func { return dpdx(1.0); }
+    // @stage(compute) @workgroup_size(1) fn func { return dpdx(1.0); }
 
-  auto* dpdx = create<ast::CallExpression>(Source{{3, 4}}, Expr("dpdx"),
-                                           ast::ExpressionList{Expr(1.0f)});
-  Func(Source{{1, 2}}, "func", ast::VariableList{}, ty.void_(),
-       {CallStmt(dpdx)},
-       {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
+    auto* dpdx =
+        create<ast::CallExpression>(Source{{3, 4}}, Expr("dpdx"), ast::ExpressionList{Expr(1.0f)});
+    Func(Source{{1, 2}}, "func", ast::VariableList{}, ty.void_(), {CallStmt(dpdx)},
+         {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "3:4 error: built-in cannot be used by compute pipeline stage");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "3:4 error: built-in cannot be used by compute pipeline stage");
 }
 
 TEST_F(ResolverBuiltinValidationTest, InvalidPipelineStageIndirect) {
-  // fn f0 { return dpdx(1.0); }
-  // fn f1 { f0(); }
-  // fn f2 { f1(); }
-  // @stage(compute) @workgroup_size(1) fn main { return f2(); }
+    // fn f0 { return dpdx(1.0); }
+    // fn f1 { f0(); }
+    // fn f2 { f1(); }
+    // @stage(compute) @workgroup_size(1) fn main { return f2(); }
 
-  auto* dpdx = create<ast::CallExpression>(Source{{3, 4}}, Expr("dpdx"),
-                                           ast::ExpressionList{Expr(1.0f)});
-  Func(Source{{1, 2}}, "f0", {}, ty.void_(), {CallStmt(dpdx)});
+    auto* dpdx =
+        create<ast::CallExpression>(Source{{3, 4}}, Expr("dpdx"), ast::ExpressionList{Expr(1.0f)});
+    Func(Source{{1, 2}}, "f0", {}, ty.void_(), {CallStmt(dpdx)});
 
-  Func(Source{{3, 4}}, "f1", {}, ty.void_(), {CallStmt(Call("f0"))});
+    Func(Source{{3, 4}}, "f1", {}, ty.void_(), {CallStmt(Call("f0"))});
 
-  Func(Source{{5, 6}}, "f2", {}, ty.void_(), {CallStmt(Call("f1"))});
+    Func(Source{{5, 6}}, "f2", {}, ty.void_(), {CallStmt(Call("f1"))});
 
-  Func(Source{{7, 8}}, "main", {}, ty.void_(), {CallStmt(Call("f2"))},
-       {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
+    Func(Source{{7, 8}}, "main", {}, ty.void_(), {CallStmt(Call("f2"))},
+         {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            R"(3:4 error: built-in cannot be used by compute pipeline stage
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(3:4 error: built-in cannot be used by compute pipeline stage
 1:2 note: called by function 'f0'
 3:4 note: called by function 'f1'
 5:6 note: called by function 'f2'
@@ -74,49 +72,43 @@
 }
 
 TEST_F(ResolverBuiltinValidationTest, BuiltinRedeclaredAsFunction) {
-  Func(Source{{12, 34}}, "mix", {}, ty.i32(), {});
+    Func(Source{{12, 34}}, "mix", {}, ty.i32(), {});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: 'mix' is a builtin and cannot be redeclared as a function)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: 'mix' is a builtin and cannot be redeclared as a function)");
 }
 
 TEST_F(ResolverBuiltinValidationTest, BuiltinRedeclaredAsGlobalLet) {
-  GlobalConst(Source{{12, 34}}, "mix", ty.i32(), Expr(1));
+    GlobalConst(Source{{12, 34}}, "mix", ty.i32(), Expr(1_i));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: 'mix' is a builtin and cannot be redeclared as a module-scope let)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: 'mix' is a builtin and cannot be redeclared as a module-scope let)");
 }
 
 TEST_F(ResolverBuiltinValidationTest, BuiltinRedeclaredAsGlobalVar) {
-  Global(Source{{12, 34}}, "mix", ty.i32(), Expr(1),
-         ast::StorageClass::kPrivate);
+    Global(Source{{12, 34}}, "mix", ty.i32(), Expr(1_i), ast::StorageClass::kPrivate);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: 'mix' is a builtin and cannot be redeclared as a module-scope var)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: 'mix' is a builtin and cannot be redeclared as a module-scope var)");
 }
 
 TEST_F(ResolverBuiltinValidationTest, BuiltinRedeclaredAsAlias) {
-  Alias(Source{{12, 34}}, "mix", ty.i32());
+    Alias(Source{{12, 34}}, "mix", ty.i32());
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: 'mix' is a builtin and cannot be redeclared as an alias)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: 'mix' is a builtin and cannot be redeclared as an alias)");
 }
 
 TEST_F(ResolverBuiltinValidationTest, BuiltinRedeclaredAsStruct) {
-  Structure(Source{{12, 34}}, "mix", {Member("m", ty.i32())});
+    Structure(Source{{12, 34}}, "mix", {Member("m", ty.i32())});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: 'mix' is a builtin and cannot be redeclared as a struct)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: 'mix' is a builtin and cannot be redeclared as a struct)");
 }
 
 namespace texture_constexpr_args {
@@ -125,274 +117,257 @@
 using ValidTextureOverload = ast::builtin::test::ValidTextureOverload;
 using TextureKind = ast::builtin::test::TextureKind;
 using TextureDataType = ast::builtin::test::TextureDataType;
-using u32 = ProgramBuilder::u32;
-using i32 = ProgramBuilder::i32;
-using f32 = ProgramBuilder::f32;
 
 static std::vector<TextureOverloadCase> TextureCases(
     std::unordered_set<ValidTextureOverload> overloads) {
-  std::vector<TextureOverloadCase> cases;
-  for (auto c : TextureOverloadCase::ValidCases()) {
-    if (overloads.count(c.overload)) {
-      cases.push_back(c);
+    std::vector<TextureOverloadCase> cases;
+    for (auto c : TextureOverloadCase::ValidCases()) {
+        if (overloads.count(c.overload)) {
+            cases.push_back(c);
+        }
     }
-  }
-  return cases;
+    return cases;
 }
 
 enum class Position {
-  kFirst,
-  kLast,
+    kFirst,
+    kLast,
 };
 
 struct Parameter {
-  const char* const name;
-  const Position position;
-  int min;
-  int max;
+    const char* const name;
+    const Position position;
+    int min;
+    int max;
 };
 
 class Constexpr {
- public:
-  enum class Kind {
-    kScalar,
-    kVec2,
-    kVec3,
-    kVec3_Scalar_Vec2,
-    kVec3_Vec2_Scalar,
-    kEmptyVec2,
-    kEmptyVec3,
-  };
+  public:
+    enum class Kind {
+        kScalar,
+        kVec2,
+        kVec3,
+        kVec3_Scalar_Vec2,
+        kVec3_Vec2_Scalar,
+        kEmptyVec2,
+        kEmptyVec3,
+    };
 
-  Constexpr(int32_t invalid_idx,
-            Kind k,
-            int32_t x = 0,
-            int32_t y = 0,
-            int32_t z = 0)
-      : invalid_index(invalid_idx), kind(k), values{x, y, z} {}
+    Constexpr(int32_t invalid_idx, Kind k, int32_t x = 0, int32_t y = 0, int32_t z = 0)
+        : invalid_index(invalid_idx), kind(k), values{x, y, z} {}
 
-  const ast::Expression* operator()(Source src, ProgramBuilder& b) {
-    switch (kind) {
-      case Kind::kScalar:
-        return b.Expr(src, values[0]);
-      case Kind::kVec2:
-        return b.Construct(src, b.ty.vec2<i32>(), values[0], values[1]);
-      case Kind::kVec3:
-        return b.Construct(src, b.ty.vec3<i32>(), values[0], values[1],
-                           values[2]);
-      case Kind::kVec3_Scalar_Vec2:
-        return b.Construct(src, b.ty.vec3<i32>(), values[0],
-                           b.vec2<i32>(values[1], values[2]));
-      case Kind::kVec3_Vec2_Scalar:
-        return b.Construct(src, b.ty.vec3<i32>(),
-                           b.vec2<i32>(values[0], values[1]), values[2]);
-      case Kind::kEmptyVec2:
-        return b.Construct(src, b.ty.vec2<i32>());
-      case Kind::kEmptyVec3:
-        return b.Construct(src, b.ty.vec3<i32>());
+    const ast::Expression* operator()(Source src, ProgramBuilder& b) {
+        switch (kind) {
+            case Kind::kScalar:
+                return b.Expr(src, i32(values[0]));
+            case Kind::kVec2:
+                return b.Construct(src, b.ty.vec2<i32>(), i32(values[0]), i32(values[1]));
+            case Kind::kVec3:
+                return b.Construct(src, b.ty.vec3<i32>(), i32(values[0]), i32(values[1]),
+                                   i32(values[2]));
+            case Kind::kVec3_Scalar_Vec2:
+                return b.Construct(src, b.ty.vec3<i32>(), i32(values[0]),
+                                   b.vec2<i32>(i32(values[1]), i32(values[2])));
+            case Kind::kVec3_Vec2_Scalar:
+                return b.Construct(src, b.ty.vec3<i32>(),
+                                   b.vec2<i32>(i32(values[0]), i32(values[1])), i32(values[2]));
+            case Kind::kEmptyVec2:
+                return b.Construct(src, b.ty.vec2<i32>());
+            case Kind::kEmptyVec3:
+                return b.Construct(src, b.ty.vec3<i32>());
+        }
+        return nullptr;
     }
-    return nullptr;
-  }
 
-  static const constexpr int32_t kValid = -1;
-  const int32_t invalid_index;  // Expected error value, or kValid
-  const Kind kind;
-  const std::array<int32_t, 3> values;
+    static const constexpr int32_t kValid = -1;
+    const int32_t invalid_index;  // Expected error value, or kValid
+    const Kind kind;
+    const std::array<int32_t, 3> values;
 };
 
 static std::ostream& operator<<(std::ostream& out, Parameter param) {
-  return out << param.name;
+    return out << param.name;
 }
 
 static std::ostream& operator<<(std::ostream& out, Constexpr expr) {
-  switch (expr.kind) {
-    case Constexpr::Kind::kScalar:
-      return out << expr.values[0];
-    case Constexpr::Kind::kVec2:
-      return out << "vec2(" << expr.values[0] << ", " << expr.values[1] << ")";
-    case Constexpr::Kind::kVec3:
-      return out << "vec3(" << expr.values[0] << ", " << expr.values[1] << ", "
-                 << expr.values[2] << ")";
-    case Constexpr::Kind::kVec3_Scalar_Vec2:
-      return out << "vec3(" << expr.values[0] << ", vec2(" << expr.values[1]
-                 << ", " << expr.values[2] << "))";
-    case Constexpr::Kind::kVec3_Vec2_Scalar:
-      return out << "vec3(vec2(" << expr.values[0] << ", " << expr.values[1]
-                 << "), " << expr.values[2] << ")";
-    case Constexpr::Kind::kEmptyVec2:
-      return out << "vec2()";
-    case Constexpr::Kind::kEmptyVec3:
-      return out << "vec3()";
-  }
-  return out;
+    switch (expr.kind) {
+        case Constexpr::Kind::kScalar:
+            return out << expr.values[0];
+        case Constexpr::Kind::kVec2:
+            return out << "vec2(" << expr.values[0] << ", " << expr.values[1] << ")";
+        case Constexpr::Kind::kVec3:
+            return out << "vec3(" << expr.values[0] << ", " << expr.values[1] << ", "
+                       << expr.values[2] << ")";
+        case Constexpr::Kind::kVec3_Scalar_Vec2:
+            return out << "vec3(" << expr.values[0] << ", vec2(" << expr.values[1] << ", "
+                       << expr.values[2] << "))";
+        case Constexpr::Kind::kVec3_Vec2_Scalar:
+            return out << "vec3(vec2(" << expr.values[0] << ", " << expr.values[1] << "), "
+                       << expr.values[2] << ")";
+        case Constexpr::Kind::kEmptyVec2:
+            return out << "vec2()";
+        case Constexpr::Kind::kEmptyVec3:
+            return out << "vec3()";
+    }
+    return out;
 }
 
-using BuiltinTextureConstExprArgValidationTest = ResolverTestWithParam<
-    std::tuple<TextureOverloadCase, Parameter, Constexpr>>;
+using BuiltinTextureConstExprArgValidationTest =
+    ResolverTestWithParam<std::tuple<TextureOverloadCase, Parameter, Constexpr>>;
 
 TEST_P(BuiltinTextureConstExprArgValidationTest, Immediate) {
-  auto& p = GetParam();
-  auto overload = std::get<0>(p);
-  auto param = std::get<1>(p);
-  auto expr = std::get<2>(p);
+    auto& p = GetParam();
+    auto overload = std::get<0>(p);
+    auto param = std::get<1>(p);
+    auto expr = std::get<2>(p);
 
-  overload.BuildTextureVariable(this);
-  overload.BuildSamplerVariable(this);
+    overload.BuildTextureVariable(this);
+    overload.BuildSamplerVariable(this);
 
-  auto args = overload.args(this);
-  auto*& arg_to_replace =
-      (param.position == Position::kFirst) ? args.front() : args.back();
+    auto args = overload.args(this);
+    auto*& arg_to_replace = (param.position == Position::kFirst) ? args.front() : args.back();
 
-  // BuildTextureVariable() uses a Literal for scalars, and a CallExpression for
-  // a vector constructor.
-  bool is_vector = arg_to_replace->Is<ast::CallExpression>();
+    // BuildTextureVariable() uses a Literal for scalars, and a CallExpression for
+    // a vector constructor.
+    bool is_vector = arg_to_replace->Is<ast::CallExpression>();
 
-  // Make the expression to be replaced, reachable. This keeps the resolver
-  // happy.
-  WrapInFunction(arg_to_replace);
+    // Make the expression to be replaced, reachable. This keeps the resolver
+    // happy.
+    WrapInFunction(arg_to_replace);
 
-  arg_to_replace = expr(Source{{12, 34}}, *this);
+    arg_to_replace = expr(Source{{12, 34}}, *this);
 
-  // Call the builtin with the constexpr argument replaced
-  Func("func", {}, ty.void_(), {CallStmt(Call(overload.function, args))},
-       {Stage(ast::PipelineStage::kFragment)});
+    // Call the builtin with the constexpr argument replaced
+    Func("func", {}, ty.void_(), {CallStmt(Call(overload.function, args))},
+         {Stage(ast::PipelineStage::kFragment)});
 
-  if (expr.invalid_index == Constexpr::kValid) {
-    EXPECT_TRUE(r()->Resolve()) << r()->error();
-  } else {
-    EXPECT_FALSE(r()->Resolve());
-    std::stringstream err;
-    if (is_vector) {
-      err << "12:34 error: each component of the " << param.name
-          << " argument must be at least " << param.min << " and at most "
-          << param.max << ". " << param.name << " component "
-          << expr.invalid_index << " is "
-          << std::to_string(expr.values[expr.invalid_index]);
+    if (expr.invalid_index == Constexpr::kValid) {
+        EXPECT_TRUE(r()->Resolve()) << r()->error();
     } else {
-      err << "12:34 error: the " << param.name << " argument must be at least "
-          << param.min << " and at most " << param.max << ". " << param.name
-          << " is " << std::to_string(expr.values[expr.invalid_index]);
+        EXPECT_FALSE(r()->Resolve());
+        std::stringstream err;
+        if (is_vector) {
+            err << "12:34 error: each component of the " << param.name
+                << " argument must be at least " << param.min << " and at most " << param.max
+                << ". " << param.name << " component " << expr.invalid_index << " is "
+                << std::to_string(expr.values[expr.invalid_index]);
+        } else {
+            err << "12:34 error: the " << param.name << " argument must be at least " << param.min
+                << " and at most " << param.max << ". " << param.name << " is "
+                << std::to_string(expr.values[expr.invalid_index]);
+        }
+        EXPECT_EQ(r()->error(), err.str());
     }
-    EXPECT_EQ(r()->error(), err.str());
-  }
 }
 
 TEST_P(BuiltinTextureConstExprArgValidationTest, GlobalConst) {
-  auto& p = GetParam();
-  auto overload = std::get<0>(p);
-  auto param = std::get<1>(p);
-  auto expr = std::get<2>(p);
+    auto& p = GetParam();
+    auto overload = std::get<0>(p);
+    auto param = std::get<1>(p);
+    auto expr = std::get<2>(p);
 
-  // Build the global texture and sampler variables
-  overload.BuildTextureVariable(this);
-  overload.BuildSamplerVariable(this);
+    // Build the global texture and sampler variables
+    overload.BuildTextureVariable(this);
+    overload.BuildSamplerVariable(this);
 
-  // Build the module-scope let 'G' with the offset value
-  GlobalConst("G", nullptr, expr({}, *this));
+    // Build the module-scope let 'G' with the offset value
+    GlobalConst("G", nullptr, expr({}, *this));
 
-  auto args = overload.args(this);
-  auto*& arg_to_replace =
-      (param.position == Position::kFirst) ? args.front() : args.back();
+    auto args = overload.args(this);
+    auto*& arg_to_replace = (param.position == Position::kFirst) ? args.front() : args.back();
 
-  // Make the expression to be replaced, reachable. This keeps the resolver
-  // happy.
-  WrapInFunction(arg_to_replace);
+    // Make the expression to be replaced, reachable. This keeps the resolver
+    // happy.
+    WrapInFunction(arg_to_replace);
 
-  arg_to_replace = Expr(Source{{12, 34}}, "G");
+    arg_to_replace = Expr(Source{{12, 34}}, "G");
 
-  // Call the builtin with the constexpr argument replaced
-  Func("func", {}, ty.void_(), {CallStmt(Call(overload.function, args))},
-       {Stage(ast::PipelineStage::kFragment)});
+    // Call the builtin with the constexpr argument replaced
+    Func("func", {}, ty.void_(), {CallStmt(Call(overload.function, args))},
+         {Stage(ast::PipelineStage::kFragment)});
 
-  EXPECT_FALSE(r()->Resolve());
-  std::stringstream err;
-  err << "12:34 error: the " << param.name
-      << " argument must be a const_expression";
-  EXPECT_EQ(r()->error(), err.str());
+    EXPECT_FALSE(r()->Resolve());
+    std::stringstream err;
+    err << "12:34 error: the " << param.name << " argument must be a const_expression";
+    EXPECT_EQ(r()->error(), err.str());
 }
 
 INSTANTIATE_TEST_SUITE_P(
     Offset2D,
     BuiltinTextureConstExprArgValidationTest,
-    testing::Combine(
-        testing::ValuesIn(TextureCases({
-            ValidTextureOverload::kSample2dOffsetF32,
-            ValidTextureOverload::kSample2dArrayOffsetF32,
-            ValidTextureOverload::kSampleDepth2dOffsetF32,
-            ValidTextureOverload::kSampleDepth2dArrayOffsetF32,
-            ValidTextureOverload::kSampleBias2dOffsetF32,
-            ValidTextureOverload::kSampleBias2dArrayOffsetF32,
-            ValidTextureOverload::kSampleLevel2dOffsetF32,
-            ValidTextureOverload::kSampleLevel2dArrayOffsetF32,
-            ValidTextureOverload::kSampleLevelDepth2dOffsetF32,
-            ValidTextureOverload::kSampleLevelDepth2dArrayOffsetF32,
-            ValidTextureOverload::kSampleGrad2dOffsetF32,
-            ValidTextureOverload::kSampleGrad2dArrayOffsetF32,
-            ValidTextureOverload::kSampleCompareDepth2dOffsetF32,
-            ValidTextureOverload::kSampleCompareDepth2dArrayOffsetF32,
-            ValidTextureOverload::kSampleCompareLevelDepth2dOffsetF32,
-            ValidTextureOverload::kSampleCompareLevelDepth2dArrayOffsetF32,
-        })),
-        testing::Values(Parameter{"offset", Position::kLast, -8, 7}),
-        testing::Values(
-            Constexpr{Constexpr::kValid, Constexpr::Kind::kEmptyVec2},
-            Constexpr{Constexpr::kValid, Constexpr::Kind::kVec2, -1, 1},
-            Constexpr{Constexpr::kValid, Constexpr::Kind::kVec2, 7, -8},
-            Constexpr{0, Constexpr::Kind::kVec2, 8, 0},
-            Constexpr{1, Constexpr::Kind::kVec2, 0, 8},
-            Constexpr{0, Constexpr::Kind::kVec2, -9, 0},
-            Constexpr{1, Constexpr::Kind::kVec2, 0, -9},
-            Constexpr{0, Constexpr::Kind::kVec2, 8, 8},
-            Constexpr{0, Constexpr::Kind::kVec2, -9, -9})));
+    testing::Combine(testing::ValuesIn(TextureCases({
+                         ValidTextureOverload::kSample2dOffsetF32,
+                         ValidTextureOverload::kSample2dArrayOffsetF32,
+                         ValidTextureOverload::kSampleDepth2dOffsetF32,
+                         ValidTextureOverload::kSampleDepth2dArrayOffsetF32,
+                         ValidTextureOverload::kSampleBias2dOffsetF32,
+                         ValidTextureOverload::kSampleBias2dArrayOffsetF32,
+                         ValidTextureOverload::kSampleLevel2dOffsetF32,
+                         ValidTextureOverload::kSampleLevel2dArrayOffsetF32,
+                         ValidTextureOverload::kSampleLevelDepth2dOffsetF32,
+                         ValidTextureOverload::kSampleLevelDepth2dArrayOffsetF32,
+                         ValidTextureOverload::kSampleGrad2dOffsetF32,
+                         ValidTextureOverload::kSampleGrad2dArrayOffsetF32,
+                         ValidTextureOverload::kSampleCompareDepth2dOffsetF32,
+                         ValidTextureOverload::kSampleCompareDepth2dArrayOffsetF32,
+                         ValidTextureOverload::kSampleCompareLevelDepth2dOffsetF32,
+                         ValidTextureOverload::kSampleCompareLevelDepth2dArrayOffsetF32,
+                     })),
+                     testing::Values(Parameter{"offset", Position::kLast, -8, 7}),
+                     testing::Values(Constexpr{Constexpr::kValid, Constexpr::Kind::kEmptyVec2},
+                                     Constexpr{Constexpr::kValid, Constexpr::Kind::kVec2, -1, 1},
+                                     Constexpr{Constexpr::kValid, Constexpr::Kind::kVec2, 7, -8},
+                                     Constexpr{0, Constexpr::Kind::kVec2, 8, 0},
+                                     Constexpr{1, Constexpr::Kind::kVec2, 0, 8},
+                                     Constexpr{0, Constexpr::Kind::kVec2, -9, 0},
+                                     Constexpr{1, Constexpr::Kind::kVec2, 0, -9},
+                                     Constexpr{0, Constexpr::Kind::kVec2, 8, 8},
+                                     Constexpr{0, Constexpr::Kind::kVec2, -9, -9})));
 
 INSTANTIATE_TEST_SUITE_P(
     Offset3D,
     BuiltinTextureConstExprArgValidationTest,
-    testing::Combine(
-        testing::ValuesIn(TextureCases({
-            ValidTextureOverload::kSample3dOffsetF32,
-            ValidTextureOverload::kSampleBias3dOffsetF32,
-            ValidTextureOverload::kSampleLevel3dOffsetF32,
-            ValidTextureOverload::kSampleGrad3dOffsetF32,
-        })),
-        testing::Values(Parameter{"offset", Position::kLast, -8, 7}),
-        testing::Values(
-            Constexpr{Constexpr::kValid, Constexpr::Kind::kEmptyVec3},
-            Constexpr{Constexpr::kValid, Constexpr::Kind::kVec3, 0, 0, 0},
-            Constexpr{Constexpr::kValid, Constexpr::Kind::kVec3, 7, -8, 7},
-            Constexpr{0, Constexpr::Kind::kVec3, 10, 0, 0},
-            Constexpr{1, Constexpr::Kind::kVec3, 0, 10, 0},
-            Constexpr{2, Constexpr::Kind::kVec3, 0, 0, 10},
-            Constexpr{0, Constexpr::Kind::kVec3, 10, 11, 12},
-            Constexpr{0, Constexpr::Kind::kVec3_Scalar_Vec2, 10, 0, 0},
-            Constexpr{1, Constexpr::Kind::kVec3_Scalar_Vec2, 0, 10, 0},
-            Constexpr{2, Constexpr::Kind::kVec3_Scalar_Vec2, 0, 0, 10},
-            Constexpr{0, Constexpr::Kind::kVec3_Scalar_Vec2, 10, 11, 12},
-            Constexpr{0, Constexpr::Kind::kVec3_Vec2_Scalar, 10, 0, 0},
-            Constexpr{1, Constexpr::Kind::kVec3_Vec2_Scalar, 0, 10, 0},
-            Constexpr{2, Constexpr::Kind::kVec3_Vec2_Scalar, 0, 0, 10},
-            Constexpr{0, Constexpr::Kind::kVec3_Vec2_Scalar, 10, 11, 12})));
+    testing::Combine(testing::ValuesIn(TextureCases({
+                         ValidTextureOverload::kSample3dOffsetF32,
+                         ValidTextureOverload::kSampleBias3dOffsetF32,
+                         ValidTextureOverload::kSampleLevel3dOffsetF32,
+                         ValidTextureOverload::kSampleGrad3dOffsetF32,
+                     })),
+                     testing::Values(Parameter{"offset", Position::kLast, -8, 7}),
+                     testing::Values(Constexpr{Constexpr::kValid, Constexpr::Kind::kEmptyVec3},
+                                     Constexpr{Constexpr::kValid, Constexpr::Kind::kVec3, 0, 0, 0},
+                                     Constexpr{Constexpr::kValid, Constexpr::Kind::kVec3, 7, -8, 7},
+                                     Constexpr{0, Constexpr::Kind::kVec3, 10, 0, 0},
+                                     Constexpr{1, Constexpr::Kind::kVec3, 0, 10, 0},
+                                     Constexpr{2, Constexpr::Kind::kVec3, 0, 0, 10},
+                                     Constexpr{0, Constexpr::Kind::kVec3, 10, 11, 12},
+                                     Constexpr{0, Constexpr::Kind::kVec3_Scalar_Vec2, 10, 0, 0},
+                                     Constexpr{1, Constexpr::Kind::kVec3_Scalar_Vec2, 0, 10, 0},
+                                     Constexpr{2, Constexpr::Kind::kVec3_Scalar_Vec2, 0, 0, 10},
+                                     Constexpr{0, Constexpr::Kind::kVec3_Scalar_Vec2, 10, 11, 12},
+                                     Constexpr{0, Constexpr::Kind::kVec3_Vec2_Scalar, 10, 0, 0},
+                                     Constexpr{1, Constexpr::Kind::kVec3_Vec2_Scalar, 0, 10, 0},
+                                     Constexpr{2, Constexpr::Kind::kVec3_Vec2_Scalar, 0, 0, 10},
+                                     Constexpr{0, Constexpr::Kind::kVec3_Vec2_Scalar, 10, 11,
+                                               12})));
 
 INSTANTIATE_TEST_SUITE_P(
     Component,
     BuiltinTextureConstExprArgValidationTest,
-    testing::Combine(
-        testing::ValuesIn(
-            TextureCases({ValidTextureOverload::kGather2dF32,
-                          ValidTextureOverload::kGather2dOffsetF32,
-                          ValidTextureOverload::kGather2dArrayF32,
-                          ValidTextureOverload::kGather2dArrayOffsetF32,
-                          ValidTextureOverload::kGatherCubeF32,
-                          ValidTextureOverload::kGatherCubeArrayF32})),
-        testing::Values(Parameter{"component", Position::kFirst, 0, 3}),
-        testing::Values(
-            Constexpr{Constexpr::kValid, Constexpr::Kind::kScalar, 0},
-            Constexpr{Constexpr::kValid, Constexpr::Kind::kScalar, 1},
-            Constexpr{Constexpr::kValid, Constexpr::Kind::kScalar, 2},
-            Constexpr{Constexpr::kValid, Constexpr::Kind::kScalar, 3},
-            Constexpr{0, Constexpr::Kind::kScalar, 4},
-            Constexpr{0, Constexpr::Kind::kScalar, 123},
-            Constexpr{0, Constexpr::Kind::kScalar, -1})));
+    testing::Combine(testing::ValuesIn(TextureCases({ValidTextureOverload::kGather2dF32,
+                                                     ValidTextureOverload::kGather2dOffsetF32,
+                                                     ValidTextureOverload::kGather2dArrayF32,
+                                                     ValidTextureOverload::kGather2dArrayOffsetF32,
+                                                     ValidTextureOverload::kGatherCubeF32,
+                                                     ValidTextureOverload::kGatherCubeArrayF32})),
+                     testing::Values(Parameter{"component", Position::kFirst, 0, 3}),
+                     testing::Values(Constexpr{Constexpr::kValid, Constexpr::Kind::kScalar, 0},
+                                     Constexpr{Constexpr::kValid, Constexpr::Kind::kScalar, 1},
+                                     Constexpr{Constexpr::kValid, Constexpr::Kind::kScalar, 2},
+                                     Constexpr{Constexpr::kValid, Constexpr::Kind::kScalar, 3},
+                                     Constexpr{0, Constexpr::Kind::kScalar, 4},
+                                     Constexpr{0, Constexpr::Kind::kScalar, 123},
+                                     Constexpr{0, Constexpr::Kind::kScalar, -1})));
 
 }  // namespace texture_constexpr_args
 
diff --git a/src/tint/resolver/builtins_validation_test.cc b/src/tint/resolver/builtins_validation_test.cc
index 4bad973..87835d6 100644
--- a/src/tint/resolver/builtins_validation_test.cc
+++ b/src/tint/resolver/builtins_validation_test.cc
@@ -15,6 +15,8 @@
 #include "src/tint/ast/call_statement.h"
 #include "src/tint/resolver/resolver_test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::resolver {
 namespace {
 
@@ -26,1011 +28,874 @@
 using vec3 = builder::vec3<T>;
 template <typename T>
 using vec4 = builder::vec4<T>;
-using f32 = builder::f32;
-using i32 = builder::i32;
-using u32 = builder::u32;
 
-class ResolverBuiltinsValidationTest : public resolver::TestHelper,
-                                       public testing::Test {};
+class ResolverBuiltinsValidationTest : public resolver::TestHelper, public testing::Test {};
 namespace StageTest {
 struct Params {
-  builder::ast_type_func_ptr type;
-  ast::Builtin builtin;
-  ast::PipelineStage stage;
-  bool is_valid;
+    builder::ast_type_func_ptr type;
+    ast::Builtin builtin;
+    ast::PipelineStage stage;
+    bool is_valid;
 };
 
 template <typename T>
-constexpr Params ParamsFor(ast::Builtin builtin,
-                           ast::PipelineStage stage,
-                           bool is_valid) {
-  return Params{DataType<T>::AST, builtin, stage, is_valid};
+constexpr Params ParamsFor(ast::Builtin 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::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<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::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::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::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<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::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<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::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<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::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<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::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::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::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::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::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<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::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::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::Builtin::kSampleMask, ast::PipelineStage::kVertex, false),
+    ParamsFor<u32>(ast::Builtin::kSampleMask, ast::PipelineStage::kFragment, true),
+    ParamsFor<u32>(ast::Builtin::kSampleMask, ast::PipelineStage::kCompute, false),
 };
 
 using ResolverBuiltinsStageTest = ResolverTestWithParam<Params>;
 TEST_P(ResolverBuiltinsStageTest, All_input) {
-  const Params& params = GetParam();
+    const Params& params = GetParam();
 
-  auto* p = Global("p", ty.vec4<f32>(), ast::StorageClass::kPrivate);
-  auto* input =
-      Param("input", params.type(*this),
-            ast::AttributeList{Builtin(Source{{12, 34}}, params.builtin)});
-  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)});
-      break;
-    case ast::PipelineStage::kFragment:
-      Func("main", {input}, ty.void_(), {},
-           {Stage(ast::PipelineStage::kFragment)}, {});
-      break;
-    case ast::PipelineStage::kCompute:
-      Func("main", {input}, ty.void_(), {},
-           ast::AttributeList{Stage(ast::PipelineStage::kCompute),
-                              WorkgroupSize(1)});
-      break;
-    default:
-      break;
-  }
+    auto* p = Global("p", ty.vec4<f32>(), ast::StorageClass::kPrivate);
+    auto* input = Param("input", params.type(*this),
+                        ast::AttributeList{Builtin(Source{{12, 34}}, params.builtin)});
+    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)});
+            break;
+        case ast::PipelineStage::kFragment:
+            Func("main", {input}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)}, {});
+            break;
+        case ast::PipelineStage::kCompute:
+            Func("main", {input}, ty.void_(), {},
+                 ast::AttributeList{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+            break;
+        default:
+            break;
+    }
 
-  if (params.is_valid) {
-    EXPECT_TRUE(r()->Resolve()) << r()->error();
-  } else {
-    std::stringstream err;
-    err << "12:34 error: builtin(" << params.builtin << ")";
-    err << " cannot be used in input of " << params.stage << " pipeline stage";
-    EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(), err.str());
-  }
+    if (params.is_valid) {
+        EXPECT_TRUE(r()->Resolve()) << r()->error();
+    } else {
+        std::stringstream err;
+        err << "12:34 error: builtin(" << params.builtin << ")";
+        err << " cannot be used in input of " << params.stage << " pipeline stage";
+        EXPECT_FALSE(r()->Resolve());
+        EXPECT_EQ(r()->error(), err.str());
+    }
 }
 INSTANTIATE_TEST_SUITE_P(ResolverBuiltinsValidationTest,
                          ResolverBuiltinsStageTest,
                          testing::ValuesIn(cases));
 
 TEST_F(ResolverBuiltinsValidationTest, FragDepthIsInput_Fail) {
-  // @stage(fragment)
-  // fn fs_main(
-  //   @builtin(frag_depth) fd: f32,
-  // ) -> @location(0) f32 { return 1.0; }
-  auto* fd = Param(
-      "fd", ty.f32(),
-      ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kFragDepth)});
-  Func("fs_main", ast::VariableList{fd}, ty.f32(), {Return(1.0f)},
-       ast::AttributeList{Stage(ast::PipelineStage::kFragment)}, {Location(0)});
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: builtin(frag_depth) cannot be used in input of "
-            "fragment pipeline stage");
+    // @stage(fragment)
+    // fn fs_main(
+    //   @builtin(frag_depth) fd: f32,
+    // ) -> @location(0) f32 { return 1.0; }
+    auto* fd = Param("fd", ty.f32(),
+                     ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kFragDepth)});
+    Func("fs_main", ast::VariableList{fd}, ty.f32(), {Return(1.0f)},
+         ast::AttributeList{Stage(ast::PipelineStage::kFragment)}, {Location(0)});
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: builtin(frag_depth) cannot be used in input of "
+              "fragment pipeline stage");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, FragDepthIsInputStruct_Fail) {
-  // struct MyInputs {
-  //   @builtin(frag_depth) ff: f32;
-  // };
-  // @stage(fragment)
-  // fn fragShader(arg: MyInputs) -> @location(0) f32 { return 1.0; }
+    // struct MyInputs {
+    //   @builtin(frag_depth) ff: f32;
+    // };
+    // @stage(fragment)
+    // fn fragShader(arg: MyInputs) -> @location(0) f32 { return 1.0; }
 
-  auto* s = Structure(
-      "MyInputs", {Member("frag_depth", ty.f32(),
-                          ast::AttributeList{Builtin(
-                              Source{{12, 34}}, ast::Builtin::kFragDepth)})});
+    auto* s = Structure(
+        "MyInputs",
+        {Member("frag_depth", ty.f32(),
+                ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kFragDepth)})});
 
-  Func("fragShader", {Param("arg", ty.Of(s))}, ty.f32(), {Return(1.0f)},
-       {Stage(ast::PipelineStage::kFragment)}, {Location(0)});
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: builtin(frag_depth) cannot be used in input of "
-            "fragment pipeline stage\n"
-            "note: while analysing entry point 'fragShader'");
+    Func("fragShader", {Param("arg", ty.Of(s))}, ty.f32(), {Return(1.0f)},
+         {Stage(ast::PipelineStage::kFragment)}, {Location(0)});
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: builtin(frag_depth) cannot be used in input of "
+              "fragment pipeline stage\n"
+              "note: while analysing entry point 'fragShader'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, StructBuiltinInsideEntryPoint_Ignored) {
-  // struct S {
-  //   @builtin(vertex_index) idx: u32;
-  // };
-  // @stage(fragment)
-  // fn fragShader() { var s : S; }
+    // struct S {
+    //   @builtin(vertex_index) idx: u32;
+    // };
+    // @stage(fragment)
+    // fn fragShader() { var s : S; }
 
-  Structure("S",
-            {Member("idx", ty.u32(), {Builtin(ast::Builtin::kVertexIndex)})});
+    Structure("S", {Member("idx", ty.u32(), {Builtin(ast::Builtin::kVertexIndex)})});
 
-  Func("fragShader", {}, ty.void_(), {Decl(Var("s", ty.type_name("S")))},
-       {Stage(ast::PipelineStage::kFragment)});
-  EXPECT_TRUE(r()->Resolve());
+    Func("fragShader", {}, ty.void_(), {Decl(Var("s", ty.type_name("S")))},
+         {Stage(ast::PipelineStage::kFragment)});
+    EXPECT_TRUE(r()->Resolve());
 }
 
 }  // namespace StageTest
 
 TEST_F(ResolverBuiltinsValidationTest, PositionNotF32_Struct_Fail) {
-  // struct MyInputs {
-  //   @builtin(kPosition) p: vec4<u32>;
-  // };
-  // @stage(fragment)
-  // fn fragShader(is_front: MyInputs) -> @location(0) f32 { return 1.0; }
+    // struct MyInputs {
+    //   @builtin(kPosition) p: vec4<u32>;
+    // };
+    // @stage(fragment)
+    // fn fragShader(is_front: MyInputs) -> @location(0) f32 { return 1.0; }
 
-  auto* m = Member(
-      "position", ty.vec4<u32>(),
-      ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kPosition)});
-  auto* s = Structure("MyInputs", {m});
-  Func("fragShader", {Param("arg", ty.Of(s))}, ty.f32(), {Return(1.0f)},
-       {Stage(ast::PipelineStage::kFragment)}, {Location(0)});
+    auto* m = Member("position", ty.vec4<u32>(),
+                     ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kPosition)});
+    auto* s = Structure("MyInputs", {m});
+    Func("fragShader", {Param("arg", ty.Of(s))}, ty.f32(), {Return(1.0f)},
+         {Stage(ast::PipelineStage::kFragment)}, {Location(0)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: store type of builtin(position) must be 'vec4<f32>'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(position) must be 'vec4<f32>'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, PositionNotF32_ReturnType_Fail) {
-  // @stage(vertex)
-  // fn main() -> @builtin(position) f32 { return 1.0; }
-  Func("main", {}, ty.f32(), {Return(1.0f)},
-       {Stage(ast::PipelineStage::kVertex)},
-       {Builtin(Source{{12, 34}}, ast::Builtin::kPosition)});
+    // @stage(vertex)
+    // fn main() -> @builtin(position) f32 { return 1.0; }
+    Func("main", {}, ty.f32(), {Return(1.0f)}, {Stage(ast::PipelineStage::kVertex)},
+         {Builtin(Source{{12, 34}}, ast::Builtin::kPosition)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: store type of builtin(position) must be 'vec4<f32>'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(position) must be 'vec4<f32>'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, FragDepthNotF32_Struct_Fail) {
-  // struct MyInputs {
-  //   @builtin(kFragDepth) p: i32;
-  // };
-  // @stage(fragment)
-  // fn fragShader(is_front: MyInputs) -> @location(0) f32 { return 1.0; }
+    // struct MyInputs {
+    //   @builtin(kFragDepth) p: i32;
+    // };
+    // @stage(fragment)
+    // fn fragShader(is_front: MyInputs) -> @location(0) f32 { return 1.0; }
 
-  auto* m = Member(
-      "frag_depth", ty.i32(),
-      ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kFragDepth)});
-  auto* s = Structure("MyInputs", {m});
-  Func("fragShader", {Param("arg", ty.Of(s))}, ty.f32(), {Return(1.0f)},
-       {Stage(ast::PipelineStage::kFragment)}, {Location(0)});
+    auto* m = Member("frag_depth", ty.i32(),
+                     ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kFragDepth)});
+    auto* s = Structure("MyInputs", {m});
+    Func("fragShader", {Param("arg", ty.Of(s))}, ty.f32(), {Return(1.0f)},
+         {Stage(ast::PipelineStage::kFragment)}, {Location(0)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: store type of builtin(frag_depth) must be 'f32'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(frag_depth) must be 'f32'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, SampleMaskNotU32_Struct_Fail) {
-  // struct MyInputs {
-  //   @builtin(sample_mask) m: f32;
-  // };
-  // @stage(fragment)
-  // fn fragShader(is_front: MyInputs) -> @location(0) f32 { return 1.0; }
+    // struct MyInputs {
+    //   @builtin(sample_mask) m: f32;
+    // };
+    // @stage(fragment)
+    // fn fragShader(is_front: MyInputs) -> @location(0) f32 { return 1.0; }
 
-  auto* s = Structure(
-      "MyInputs", {Member("m", ty.f32(),
-                          ast::AttributeList{Builtin(
-                              Source{{12, 34}}, ast::Builtin::kSampleMask)})});
-  Func("fragShader", {Param("arg", ty.Of(s))}, ty.f32(), {Return(1.0f)},
-       {Stage(ast::PipelineStage::kFragment)}, {Location(0)});
+    auto* s = Structure(
+        "MyInputs",
+        {Member("m", ty.f32(),
+                ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kSampleMask)})});
+    Func("fragShader", {Param("arg", ty.Of(s))}, ty.f32(), {Return(1.0f)},
+         {Stage(ast::PipelineStage::kFragment)}, {Location(0)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: store type of builtin(sample_mask) must be 'u32'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(sample_mask) must be 'u32'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, SampleMaskNotU32_ReturnType_Fail) {
-  // @stage(fragment)
-  // fn main() -> @builtin(sample_mask) i32 { return 1; }
-  Func("main", {}, ty.i32(), {Return(1)},
-       {Stage(ast::PipelineStage::kFragment)},
-       {Builtin(Source{{12, 34}}, ast::Builtin::kSampleMask)});
+    // @stage(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)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: store type of builtin(sample_mask) must be 'u32'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(sample_mask) must be 'u32'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, SampleMaskIsNotU32_Fail) {
-  // @stage(fragment)
-  // fn fs_main(
-  //   @builtin(sample_mask) arg: bool
-  // ) -> @location(0) f32 { return 1.0; }
-  auto* arg = Param(
-      "arg", ty.bool_(),
-      ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kSampleMask)});
-  Func("fs_main", ast::VariableList{arg}, ty.f32(), {Return(1.0f)},
-       ast::AttributeList{Stage(ast::PipelineStage::kFragment)}, {Location(0)});
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: store type of builtin(sample_mask) must be 'u32'");
+    // @stage(fragment)
+    // fn fs_main(
+    //   @builtin(sample_mask) arg: bool
+    // ) -> @location(0) f32 { return 1.0; }
+    auto* arg = Param("arg", ty.bool_(),
+                      ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kSampleMask)});
+    Func("fs_main", ast::VariableList{arg}, ty.f32(), {Return(1.0f)},
+         ast::AttributeList{Stage(ast::PipelineStage::kFragment)}, {Location(0)});
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(sample_mask) must be 'u32'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, SampleIndexIsNotU32_Struct_Fail) {
-  // struct MyInputs {
-  //   @builtin(sample_index) m: f32;
-  // };
-  // @stage(fragment)
-  // fn fragShader(is_front: MyInputs) -> @location(0) f32 { return 1.0; }
+    // struct MyInputs {
+    //   @builtin(sample_index) m: f32;
+    // };
+    // @stage(fragment)
+    // fn fragShader(is_front: MyInputs) -> @location(0) f32 { return 1.0; }
 
-  auto* s = Structure(
-      "MyInputs", {Member("m", ty.f32(),
-                          ast::AttributeList{Builtin(
-                              Source{{12, 34}}, ast::Builtin::kSampleIndex)})});
-  Func("fragShader", {Param("arg", ty.Of(s))}, ty.f32(), {Return(1.0f)},
-       {Stage(ast::PipelineStage::kFragment)}, {Location(0)});
+    auto* s = Structure(
+        "MyInputs",
+        {Member("m", ty.f32(),
+                ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kSampleIndex)})});
+    Func("fragShader", {Param("arg", ty.Of(s))}, ty.f32(), {Return(1.0f)},
+         {Stage(ast::PipelineStage::kFragment)}, {Location(0)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: store type of builtin(sample_index) must be 'u32'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(sample_index) must be 'u32'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, SampleIndexIsNotU32_Fail) {
-  // @stage(fragment)
-  // fn fs_main(
-  //   @builtin(sample_index) arg: bool
-  // ) -> @location(0) f32 { return 1.0; }
-  auto* arg = Param("arg", ty.bool_(),
-                    ast::AttributeList{
-                        Builtin(Source{{12, 34}}, ast::Builtin::kSampleIndex)});
-  Func("fs_main", ast::VariableList{arg}, ty.f32(), {Return(1.0f)},
-       ast::AttributeList{Stage(ast::PipelineStage::kFragment)}, {Location(0)});
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: store type of builtin(sample_index) must be 'u32'");
+    // @stage(fragment)
+    // fn fs_main(
+    //   @builtin(sample_index) arg: bool
+    // ) -> @location(0) f32 { return 1.0; }
+    auto* arg = Param("arg", ty.bool_(),
+                      ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kSampleIndex)});
+    Func("fs_main", ast::VariableList{arg}, ty.f32(), {Return(1.0f)},
+         ast::AttributeList{Stage(ast::PipelineStage::kFragment)}, {Location(0)});
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(sample_index) must be 'u32'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, PositionIsNotF32_Fail) {
-  // @stage(fragment)
-  // fn fs_main(
-  //   @builtin(kPosition) p: vec3<f32>,
-  // ) -> @location(0) f32 { return 1.0; }
-  auto* p = Param(
-      "p", ty.vec3<f32>(),
-      ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kPosition)});
-  Func("fs_main", ast::VariableList{p}, ty.f32(), {Return(1.0f)},
-       ast::AttributeList{Stage(ast::PipelineStage::kFragment)}, {Location(0)});
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: store type of builtin(position) must be 'vec4<f32>'");
+    // @stage(fragment)
+    // fn fs_main(
+    //   @builtin(kPosition) p: vec3<f32>,
+    // ) -> @location(0) f32 { return 1.0; }
+    auto* p = Param("p", ty.vec3<f32>(),
+                    ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kPosition)});
+    Func("fs_main", ast::VariableList{p}, ty.f32(), {Return(1.0f)},
+         ast::AttributeList{Stage(ast::PipelineStage::kFragment)}, {Location(0)});
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(position) must be 'vec4<f32>'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, FragDepthIsNotF32_Fail) {
-  // @stage(fragment)
-  // 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)},
-       ast::AttributeList{Stage(ast::PipelineStage::kFragment)},
-       ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kFragDepth)});
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: store type of builtin(frag_depth) must be 'f32'");
+    // @stage(fragment)
+    // 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)},
+         ast::AttributeList{Stage(ast::PipelineStage::kFragment)},
+         ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kFragDepth)});
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(frag_depth) must be 'f32'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, VertexIndexIsNotU32_Fail) {
-  // @stage(vertex)
-  // fn main(
-  //   @builtin(kVertexIndex) vi : f32,
-  //   @builtin(kPosition) p :vec4<f32>
-  // ) -> @builtin(kPosition) vec4<f32> { return vec4<f32>(); }
-  auto* p = Param("p", ty.vec4<f32>(),
-                  ast::AttributeList{Builtin(ast::Builtin::kPosition)});
-  auto* vi = Param("vi", ty.f32(),
-                   ast::AttributeList{
-                       Builtin(Source{{12, 34}}, ast::Builtin::kVertexIndex)});
-  Func("main", ast::VariableList{vi, p}, ty.vec4<f32>(), {Return(Expr("p"))},
-       ast::AttributeList{Stage(ast::PipelineStage::kVertex)},
-       ast::AttributeList{Builtin(ast::Builtin::kPosition)});
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: store type of builtin(vertex_index) must be 'u32'");
+    // @stage(vertex)
+    // fn main(
+    //   @builtin(kVertexIndex) vi : f32,
+    //   @builtin(kPosition) p :vec4<f32>
+    // ) -> @builtin(kPosition) vec4<f32> { return vec4<f32>(); }
+    auto* p = Param("p", ty.vec4<f32>(), ast::AttributeList{Builtin(ast::Builtin::kPosition)});
+    auto* vi = Param("vi", ty.f32(),
+                     ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kVertexIndex)});
+    Func("main", ast::VariableList{vi, p}, ty.vec4<f32>(), {Return(Expr("p"))},
+         ast::AttributeList{Stage(ast::PipelineStage::kVertex)},
+         ast::AttributeList{Builtin(ast::Builtin::kPosition)});
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(vertex_index) must be 'u32'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, InstanceIndexIsNotU32) {
-  // @stage(vertex)
-  // fn main(
-  //   @builtin(kInstanceIndex) ii : f32,
-  //   @builtin(kPosition) p :vec4<f32>
-  // ) -> @builtin(kPosition) vec4<f32> { return vec4<f32>(); }
-  auto* p = Param("p", ty.vec4<f32>(),
-                  ast::AttributeList{Builtin(ast::Builtin::kPosition)});
-  auto* ii = Param("ii", ty.f32(),
-                   ast::AttributeList{Builtin(Source{{12, 34}},
-                                              ast::Builtin::kInstanceIndex)});
-  Func("main", ast::VariableList{ii, p}, ty.vec4<f32>(), {Return(Expr("p"))},
-       ast::AttributeList{Stage(ast::PipelineStage::kVertex)},
-       ast::AttributeList{Builtin(ast::Builtin::kPosition)});
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: store type of builtin(instance_index) must be 'u32'");
+    // @stage(vertex)
+    // fn main(
+    //   @builtin(kInstanceIndex) ii : f32,
+    //   @builtin(kPosition) p :vec4<f32>
+    // ) -> @builtin(kPosition) vec4<f32> { return vec4<f32>(); }
+    auto* p = Param("p", ty.vec4<f32>(), ast::AttributeList{Builtin(ast::Builtin::kPosition)});
+    auto* ii = Param("ii", ty.f32(),
+                     ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kInstanceIndex)});
+    Func("main", ast::VariableList{ii, p}, ty.vec4<f32>(), {Return(Expr("p"))},
+         ast::AttributeList{Stage(ast::PipelineStage::kVertex)},
+         ast::AttributeList{Builtin(ast::Builtin::kPosition)});
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(instance_index) must be 'u32'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, FragmentBuiltin_Pass) {
-  // @stage(fragment)
-  // fn fs_main(
-  //   @builtin(kPosition) p: vec4<f32>,
-  //   @builtin(front_facing) ff: bool,
-  //   @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>(),
-                  ast::AttributeList{Builtin(ast::Builtin::kPosition)});
-  auto* ff = Param("ff", ty.bool_(),
-                   ast::AttributeList{Builtin(ast::Builtin::kFrontFacing)});
-  auto* si = Param("si", ty.u32(),
-                   ast::AttributeList{Builtin(ast::Builtin::kSampleIndex)});
-  auto* sm = Param("sm", ty.u32(),
-                   ast::AttributeList{Builtin(ast::Builtin::kSampleMask)});
-  auto* var_fd = Var("fd", ty.f32());
-  Func("fs_main", ast::VariableList{p, ff, si, sm}, ty.f32(),
-       {Decl(var_fd), Return(var_fd)},
-       ast::AttributeList{Stage(ast::PipelineStage::kFragment)},
-       ast::AttributeList{Builtin(ast::Builtin::kFragDepth)});
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    // @stage(fragment)
+    // fn fs_main(
+    //   @builtin(kPosition) p: vec4<f32>,
+    //   @builtin(front_facing) ff: bool,
+    //   @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>(), ast::AttributeList{Builtin(ast::Builtin::kPosition)});
+    auto* ff = Param("ff", ty.bool_(), ast::AttributeList{Builtin(ast::Builtin::kFrontFacing)});
+    auto* si = Param("si", ty.u32(), ast::AttributeList{Builtin(ast::Builtin::kSampleIndex)});
+    auto* sm = Param("sm", ty.u32(), ast::AttributeList{Builtin(ast::Builtin::kSampleMask)});
+    auto* var_fd = Var("fd", ty.f32());
+    Func("fs_main", ast::VariableList{p, ff, si, sm}, ty.f32(), {Decl(var_fd), Return(var_fd)},
+         ast::AttributeList{Stage(ast::PipelineStage::kFragment)},
+         ast::AttributeList{Builtin(ast::Builtin::kFragDepth)});
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverBuiltinsValidationTest, VertexBuiltin_Pass) {
-  // @stage(vertex)
-  // fn main(
-  //   @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(),
-                   ast::AttributeList{
-                       Builtin(Source{{12, 34}}, ast::Builtin::kVertexIndex)});
+    // @stage(vertex)
+    // fn main(
+    //   @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(),
+                     ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kVertexIndex)});
 
-  auto* ii = Param("ii", ty.u32(),
-                   ast::AttributeList{Builtin(Source{{12, 34}},
-                                              ast::Builtin::kInstanceIndex)});
-  auto* p = Var("p", ty.vec4<f32>());
-  Func("main", ast::VariableList{vi, ii}, ty.vec4<f32>(),
-       {
-           Decl(p),
-           Return(p),
-       },
-       ast::AttributeList{Stage(ast::PipelineStage::kVertex)},
-       ast::AttributeList{Builtin(ast::Builtin::kPosition)});
+    auto* ii = Param("ii", ty.u32(),
+                     ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kInstanceIndex)});
+    auto* p = Var("p", ty.vec4<f32>());
+    Func("main", ast::VariableList{vi, ii}, ty.vec4<f32>(),
+         {
+             Decl(p),
+             Return(p),
+         },
+         ast::AttributeList{Stage(ast::PipelineStage::kVertex)},
+         ast::AttributeList{Builtin(ast::Builtin::kPosition)});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverBuiltinsValidationTest, ComputeBuiltin_Pass) {
-  // @stage(compute) @workgroup_size(1)
-  // fn main(
-  //   @builtin(local_invocationId) li_id: vec3<u32>,
-  //   @builtin(local_invocationIndex) li_index: u32,
-  //   @builtin(global_invocationId) gi: vec3<u32>,
-  //   @builtin(workgroup_id) wi: vec3<u32>,
-  //   @builtin(num_workgroups) nwgs: vec3<u32>,
-  // ) {}
+    // @stage(compute) @workgroup_size(1)
+    // fn main(
+    //   @builtin(local_invocationId) li_id: vec3<u32>,
+    //   @builtin(local_invocationIndex) li_index: u32,
+    //   @builtin(global_invocationId) gi: vec3<u32>,
+    //   @builtin(workgroup_id) wi: vec3<u32>,
+    //   @builtin(num_workgroups) nwgs: vec3<u32>,
+    // ) {}
 
-  auto* li_id =
-      Param("li_id", ty.vec3<u32>(),
-            ast::AttributeList{Builtin(ast::Builtin::kLocalInvocationId)});
-  auto* li_index =
-      Param("li_index", ty.u32(),
-            ast::AttributeList{Builtin(ast::Builtin::kLocalInvocationIndex)});
-  auto* gi =
-      Param("gi", ty.vec3<u32>(),
-            ast::AttributeList{Builtin(ast::Builtin::kGlobalInvocationId)});
-  auto* wi = Param("wi", ty.vec3<u32>(),
-                   ast::AttributeList{Builtin(ast::Builtin::kWorkgroupId)});
-  auto* nwgs = Param("nwgs", ty.vec3<u32>(),
-                     ast::AttributeList{Builtin(ast::Builtin::kNumWorkgroups)});
+    auto* li_id = Param("li_id", ty.vec3<u32>(),
+                        ast::AttributeList{Builtin(ast::Builtin::kLocalInvocationId)});
+    auto* li_index = Param("li_index", ty.u32(),
+                           ast::AttributeList{Builtin(ast::Builtin::kLocalInvocationIndex)});
+    auto* gi =
+        Param("gi", ty.vec3<u32>(), ast::AttributeList{Builtin(ast::Builtin::kGlobalInvocationId)});
+    auto* wi = Param("wi", ty.vec3<u32>(), ast::AttributeList{Builtin(ast::Builtin::kWorkgroupId)});
+    auto* nwgs =
+        Param("nwgs", ty.vec3<u32>(), ast::AttributeList{Builtin(ast::Builtin::kNumWorkgroups)});
 
-  Func("main", ast::VariableList{li_id, li_index, gi, wi, nwgs}, ty.void_(), {},
-       ast::AttributeList{
-           Stage(ast::PipelineStage::kCompute),
-           WorkgroupSize(Expr(Source{Source::Location{12, 34}}, 2))});
+    Func("main", ast::VariableList{li_id, li_index, gi, wi, nwgs}, ty.void_(), {},
+         ast::AttributeList{Stage(ast::PipelineStage::kCompute),
+                            WorkgroupSize(Expr(Source{Source::Location{12, 34}}, 2_i))});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverBuiltinsValidationTest, ComputeBuiltin_WorkGroupIdNotVec3U32) {
-  auto* wi = Param("wi", ty.f32(),
-                   ast::AttributeList{
-                       Builtin(Source{{12, 34}}, ast::Builtin::kWorkgroupId)});
-  Func("main", ast::VariableList{wi}, ty.void_(), {},
-       ast::AttributeList{
-           Stage(ast::PipelineStage::kCompute),
-           WorkgroupSize(Expr(Source{Source::Location{12, 34}}, 2))});
+    auto* wi = Param("wi", ty.f32(),
+                     ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kWorkgroupId)});
+    Func("main", ast::VariableList{wi}, ty.void_(), {},
+         ast::AttributeList{Stage(ast::PipelineStage::kCompute),
+                            WorkgroupSize(Expr(Source{Source::Location{12, 34}}, 2_i))});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: store type of builtin(workgroup_id) must be "
-            "'vec3<u32>'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: store type of builtin(workgroup_id) must be "
+              "'vec3<u32>'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, ComputeBuiltin_NumWorkgroupsNotVec3U32) {
-  auto* nwgs = Param("nwgs", ty.f32(),
-                     ast::AttributeList{Builtin(Source{{12, 34}},
-                                                ast::Builtin::kNumWorkgroups)});
-  Func("main", ast::VariableList{nwgs}, ty.void_(), {},
-       ast::AttributeList{
-           Stage(ast::PipelineStage::kCompute),
-           WorkgroupSize(Expr(Source{Source::Location{12, 34}}, 2))});
+    auto* nwgs = Param("nwgs", ty.f32(),
+                       ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kNumWorkgroups)});
+    Func("main", ast::VariableList{nwgs}, ty.void_(), {},
+         ast::AttributeList{Stage(ast::PipelineStage::kCompute),
+                            WorkgroupSize(Expr(Source{Source::Location{12, 34}}, 2_i))});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: store type of builtin(num_workgroups) must be "
-            "'vec3<u32>'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: store type of builtin(num_workgroups) must be "
+              "'vec3<u32>'");
 }
 
-TEST_F(ResolverBuiltinsValidationTest,
-       ComputeBuiltin_GlobalInvocationNotVec3U32) {
-  auto* gi = Param("gi", ty.vec3<i32>(),
-                   ast::AttributeList{Builtin(
-                       Source{{12, 34}}, ast::Builtin::kGlobalInvocationId)});
-  Func("main", ast::VariableList{gi}, ty.void_(), {},
-       ast::AttributeList{
-           Stage(ast::PipelineStage::kCompute),
-           WorkgroupSize(Expr(Source{Source::Location{12, 34}}, 2))});
+TEST_F(ResolverBuiltinsValidationTest, ComputeBuiltin_GlobalInvocationNotVec3U32) {
+    auto* gi =
+        Param("gi", ty.vec3<i32>(),
+              ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kGlobalInvocationId)});
+    Func("main", ast::VariableList{gi}, ty.void_(), {},
+         ast::AttributeList{Stage(ast::PipelineStage::kCompute),
+                            WorkgroupSize(Expr(Source{Source::Location{12, 34}}, 2_i))});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: store type of builtin(global_invocation_id) must be "
-            "'vec3<u32>'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: store type of builtin(global_invocation_id) must be "
+              "'vec3<u32>'");
 }
 
-TEST_F(ResolverBuiltinsValidationTest,
-       ComputeBuiltin_LocalInvocationIndexNotU32) {
-  auto* li_index =
-      Param("li_index", ty.vec3<u32>(),
-            ast::AttributeList{Builtin(Source{{12, 34}},
-                                       ast::Builtin::kLocalInvocationIndex)});
-  Func("main", ast::VariableList{li_index}, ty.void_(), {},
-       ast::AttributeList{
-           Stage(ast::PipelineStage::kCompute),
-           WorkgroupSize(Expr(Source{Source::Location{12, 34}}, 2))});
+TEST_F(ResolverBuiltinsValidationTest, ComputeBuiltin_LocalInvocationIndexNotU32) {
+    auto* li_index =
+        Param("li_index", ty.vec3<u32>(),
+              ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kLocalInvocationIndex)});
+    Func("main", ast::VariableList{li_index}, ty.void_(), {},
+         ast::AttributeList{Stage(ast::PipelineStage::kCompute),
+                            WorkgroupSize(Expr(Source{Source::Location{12, 34}}, 2_i))});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: store type of builtin(local_invocation_index) must be "
-      "'u32'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: store type of builtin(local_invocation_index) must be "
+              "'u32'");
 }
 
-TEST_F(ResolverBuiltinsValidationTest,
-       ComputeBuiltin_LocalInvocationNotVec3U32) {
-  auto* li_id = Param("li_id", ty.vec2<u32>(),
-                      ast::AttributeList{Builtin(
-                          Source{{12, 34}}, ast::Builtin::kLocalInvocationId)});
-  Func("main", ast::VariableList{li_id}, ty.void_(), {},
-       ast::AttributeList{
-           Stage(ast::PipelineStage::kCompute),
-           WorkgroupSize(Expr(Source{Source::Location{12, 34}}, 2))});
+TEST_F(ResolverBuiltinsValidationTest, ComputeBuiltin_LocalInvocationNotVec3U32) {
+    auto* li_id =
+        Param("li_id", ty.vec2<u32>(),
+              ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kLocalInvocationId)});
+    Func("main", ast::VariableList{li_id}, ty.void_(), {},
+         ast::AttributeList{Stage(ast::PipelineStage::kCompute),
+                            WorkgroupSize(Expr(Source{Source::Location{12, 34}}, 2_i))});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: store type of builtin(local_invocation_id) must be "
-            "'vec3<u32>'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: store type of builtin(local_invocation_id) must be "
+              "'vec3<u32>'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, FragmentBuiltinStruct_Pass) {
-  // Struct MyInputs {
-  //   @builtin(kPosition) p: vec4<f32>;
-  //   @builtin(frag_depth) fd: f32;
-  //   @builtin(sample_index) si: u32;
-  //   @builtin(sample_mask) sm : u32;;
-  // };
-  // @stage(fragment)
-  // fn fragShader(arg: MyInputs) -> @location(0) f32 { return 1.0; }
+    // Struct MyInputs {
+    //   @builtin(kPosition) p: vec4<f32>;
+    //   @builtin(frag_depth) fd: f32;
+    //   @builtin(sample_index) si: u32;
+    //   @builtin(sample_mask) sm : u32;;
+    // };
+    // @stage(fragment)
+    // fn fragShader(arg: MyInputs) -> @location(0) f32 { return 1.0; }
 
-  auto* s = Structure(
-      "MyInputs",
-      {Member("position", ty.vec4<f32>(),
-              ast::AttributeList{Builtin(ast::Builtin::kPosition)}),
-       Member("front_facing", ty.bool_(),
-              ast::AttributeList{Builtin(ast::Builtin::kFrontFacing)}),
-       Member("sample_index", ty.u32(),
-              ast::AttributeList{Builtin(ast::Builtin::kSampleIndex)}),
-       Member("sample_mask", ty.u32(),
-              ast::AttributeList{Builtin(ast::Builtin::kSampleMask)})});
-  Func("fragShader", {Param("arg", ty.Of(s))}, ty.f32(), {Return(1.0f)},
-       {Stage(ast::PipelineStage::kFragment)}, {Location(0)});
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* s = Structure(
+        "MyInputs",
+        {Member("position", ty.vec4<f32>(), ast::AttributeList{Builtin(ast::Builtin::kPosition)}),
+         Member("front_facing", ty.bool_(),
+                ast::AttributeList{Builtin(ast::Builtin::kFrontFacing)}),
+         Member("sample_index", ty.u32(), ast::AttributeList{Builtin(ast::Builtin::kSampleIndex)}),
+         Member("sample_mask", ty.u32(), ast::AttributeList{Builtin(ast::Builtin::kSampleMask)})});
+    Func("fragShader", {Param("arg", ty.Of(s))}, ty.f32(), {Return(1.0f)},
+         {Stage(ast::PipelineStage::kFragment)}, {Location(0)});
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverBuiltinsValidationTest, FrontFacingParamIsNotBool_Fail) {
-  // @stage(fragment)
-  // fn fs_main(
-  //   @builtin(front_facing) is_front: i32;
-  // ) -> @location(0) f32 { return 1.0; }
+    // @stage(fragment)
+    // fn fs_main(
+    //   @builtin(front_facing) is_front: i32;
+    // ) -> @location(0) f32 { return 1.0; }
 
-  auto* is_front = Param("is_front", ty.i32(),
-                         ast::AttributeList{Builtin(
-                             Source{{12, 34}}, ast::Builtin::kFrontFacing)});
-  Func("fs_main", ast::VariableList{is_front}, ty.f32(), {Return(1.0f)},
-       ast::AttributeList{Stage(ast::PipelineStage::kFragment)}, {Location(0)});
+    auto* is_front =
+        Param("is_front", ty.i32(),
+              ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kFrontFacing)});
+    Func("fs_main", ast::VariableList{is_front}, ty.f32(), {Return(1.0f)},
+         ast::AttributeList{Stage(ast::PipelineStage::kFragment)}, {Location(0)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: store type of builtin(front_facing) must be 'bool'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(front_facing) must be 'bool'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, FrontFacingMemberIsNotBool_Fail) {
-  // struct MyInputs {
-  //   @builtin(front_facing) pos: f32;
-  // };
-  // @stage(fragment)
-  // fn fragShader(is_front: MyInputs) -> @location(0) f32 { return 1.0; }
+    // struct MyInputs {
+    //   @builtin(front_facing) pos: f32;
+    // };
+    // @stage(fragment)
+    // fn fragShader(is_front: MyInputs) -> @location(0) f32 { return 1.0; }
 
-  auto* s = Structure(
-      "MyInputs", {Member("pos", ty.f32(),
-                          ast::AttributeList{Builtin(
-                              Source{{12, 34}}, ast::Builtin::kFrontFacing)})});
-  Func("fragShader", {Param("is_front", ty.Of(s))}, ty.f32(), {Return(1.0f)},
-       {Stage(ast::PipelineStage::kFragment)}, {Location(0)});
+    auto* s = Structure(
+        "MyInputs",
+        {Member("pos", ty.f32(),
+                ast::AttributeList{Builtin(Source{{12, 34}}, ast::Builtin::kFrontFacing)})});
+    Func("fragShader", {Param("is_front", ty.Of(s))}, ty.f32(), {Return(1.0f)},
+         {Stage(ast::PipelineStage::kFragment)}, {Location(0)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: store type of builtin(front_facing) must be 'bool'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: store type of builtin(front_facing) must be 'bool'");
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Length_Float_Scalar) {
-  auto* builtin = Call("length", 1.0f);
-  WrapInFunction(builtin);
+    auto* builtin = Call("length", 1.0f);
+    WrapInFunction(builtin);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Length_Float_Vec2) {
-  auto* builtin = Call("length", vec2<f32>(1.0f, 1.0f));
-  WrapInFunction(builtin);
+    auto* builtin = Call("length", vec2<f32>(1.0f, 1.0f));
+    WrapInFunction(builtin);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Length_Float_Vec3) {
-  auto* builtin = Call("length", vec3<f32>(1.0f, 1.0f, 1.0f));
-  WrapInFunction(builtin);
+    auto* builtin = Call("length", vec3<f32>(1.0f, 1.0f, 1.0f));
+    WrapInFunction(builtin);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Length_Float_Vec4) {
-  auto* builtin = Call("length", vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f));
-  WrapInFunction(builtin);
+    auto* builtin = Call("length", vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f));
+    WrapInFunction(builtin);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Distance_Float_Scalar) {
-  auto* builtin = Call("distance", 1.0f, 1.0f);
-  WrapInFunction(builtin);
+    auto* builtin = Call("distance", 1.0f, 1.0f);
+    WrapInFunction(builtin);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Distance_Float_Vec2) {
-  auto* builtin =
-      Call("distance", vec2<f32>(1.0f, 1.0f), vec2<f32>(1.0f, 1.0f));
-  WrapInFunction(builtin);
+    auto* builtin = Call("distance", vec2<f32>(1.0f, 1.0f), vec2<f32>(1.0f, 1.0f));
+    WrapInFunction(builtin);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Distance_Float_Vec3) {
-  auto* builtin = Call("distance", vec3<f32>(1.0f, 1.0f, 1.0f),
-                       vec3<f32>(1.0f, 1.0f, 1.0f));
-  WrapInFunction(builtin);
+    auto* builtin = Call("distance", vec3<f32>(1.0f, 1.0f, 1.0f), vec3<f32>(1.0f, 1.0f, 1.0f));
+    WrapInFunction(builtin);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Distance_Float_Vec4) {
-  auto* builtin = Call("distance", vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f),
-                       vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f));
-  WrapInFunction(builtin);
+    auto* builtin =
+        Call("distance", vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f), vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f));
+    WrapInFunction(builtin);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Determinant_Mat2x2) {
-  auto* builtin = Call(
-      "determinant", mat2x2<f32>(vec2<f32>(1.0f, 1.0f), vec2<f32>(1.0f, 1.0f)));
-  WrapInFunction(builtin);
+    auto* builtin = Call("determinant", mat2x2<f32>(vec2<f32>(1.0f, 1.0f), vec2<f32>(1.0f, 1.0f)));
+    WrapInFunction(builtin);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Determinant_Mat3x3) {
-  auto* builtin = Call("determinant", mat3x3<f32>(vec3<f32>(1.0f, 1.0f, 1.0f),
-                                                  vec3<f32>(1.0f, 1.0f, 1.0f),
-                                                  vec3<f32>(1.0f, 1.0f, 1.0f)));
-  WrapInFunction(builtin);
+    auto* builtin =
+        Call("determinant", mat3x3<f32>(vec3<f32>(1.0f, 1.0f, 1.0f), vec3<f32>(1.0f, 1.0f, 1.0f),
+                                        vec3<f32>(1.0f, 1.0f, 1.0f)));
+    WrapInFunction(builtin);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Determinant_Mat4x4) {
-  auto* builtin =
-      Call("determinant", mat4x4<f32>(vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f),
-                                      vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f),
-                                      vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f),
-                                      vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f)));
-  WrapInFunction(builtin);
+    auto* builtin =
+        Call("determinant",
+             mat4x4<f32>(vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f), vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f),
+                         vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f), vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f)));
+    WrapInFunction(builtin);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Frexp_Scalar) {
-  auto* builtin = Call("frexp", 1.0f);
-  WrapInFunction(builtin);
+    auto* builtin = Call("frexp", 1.0f);
+    WrapInFunction(builtin);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  auto* res_ty = TypeOf(builtin)->As<sem::Struct>();
-  ASSERT_TRUE(res_ty != nullptr);
-  auto& members = res_ty->Members();
-  ASSERT_EQ(members.size(), 2u);
-  EXPECT_TRUE(members[0]->Type()->Is<sem::F32>());
-  EXPECT_TRUE(members[1]->Type()->Is<sem::I32>());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* res_ty = TypeOf(builtin)->As<sem::Struct>();
+    ASSERT_TRUE(res_ty != nullptr);
+    auto& members = res_ty->Members();
+    ASSERT_EQ(members.size(), 2u);
+    EXPECT_TRUE(members[0]->Type()->Is<sem::F32>());
+    EXPECT_TRUE(members[1]->Type()->Is<sem::I32>());
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Frexp_Vec2) {
-  auto* builtin = Call("frexp", vec2<f32>(1.0f, 1.0f));
-  WrapInFunction(builtin);
+    auto* builtin = Call("frexp", vec2<f32>(1.0f, 1.0f));
+    WrapInFunction(builtin);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  auto* res_ty = TypeOf(builtin)->As<sem::Struct>();
-  ASSERT_TRUE(res_ty != nullptr);
-  auto& members = res_ty->Members();
-  ASSERT_EQ(members.size(), 2u);
-  ASSERT_TRUE(members[0]->Type()->Is<sem::Vector>());
-  ASSERT_TRUE(members[1]->Type()->Is<sem::Vector>());
-  EXPECT_EQ(members[0]->Type()->As<sem::Vector>()->Width(), 2u);
-  EXPECT_TRUE(members[0]->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(members[1]->Type()->As<sem::Vector>()->Width(), 2u);
-  EXPECT_TRUE(members[1]->Type()->As<sem::Vector>()->type()->Is<sem::I32>());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* res_ty = TypeOf(builtin)->As<sem::Struct>();
+    ASSERT_TRUE(res_ty != nullptr);
+    auto& members = res_ty->Members();
+    ASSERT_EQ(members.size(), 2u);
+    ASSERT_TRUE(members[0]->Type()->Is<sem::Vector>());
+    ASSERT_TRUE(members[1]->Type()->Is<sem::Vector>());
+    EXPECT_EQ(members[0]->Type()->As<sem::Vector>()->Width(), 2u);
+    EXPECT_TRUE(members[0]->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(members[1]->Type()->As<sem::Vector>()->Width(), 2u);
+    EXPECT_TRUE(members[1]->Type()->As<sem::Vector>()->type()->Is<sem::I32>());
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Frexp_Vec3) {
-  auto* builtin = Call("frexp", vec3<f32>(1.0f, 1.0f, 1.0f));
-  WrapInFunction(builtin);
+    auto* builtin = Call("frexp", vec3<f32>(1.0f, 1.0f, 1.0f));
+    WrapInFunction(builtin);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  auto* res_ty = TypeOf(builtin)->As<sem::Struct>();
-  ASSERT_TRUE(res_ty != nullptr);
-  auto& members = res_ty->Members();
-  ASSERT_EQ(members.size(), 2u);
-  ASSERT_TRUE(members[0]->Type()->Is<sem::Vector>());
-  ASSERT_TRUE(members[1]->Type()->Is<sem::Vector>());
-  EXPECT_EQ(members[0]->Type()->As<sem::Vector>()->Width(), 3u);
-  EXPECT_TRUE(members[0]->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(members[1]->Type()->As<sem::Vector>()->Width(), 3u);
-  EXPECT_TRUE(members[1]->Type()->As<sem::Vector>()->type()->Is<sem::I32>());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* res_ty = TypeOf(builtin)->As<sem::Struct>();
+    ASSERT_TRUE(res_ty != nullptr);
+    auto& members = res_ty->Members();
+    ASSERT_EQ(members.size(), 2u);
+    ASSERT_TRUE(members[0]->Type()->Is<sem::Vector>());
+    ASSERT_TRUE(members[1]->Type()->Is<sem::Vector>());
+    EXPECT_EQ(members[0]->Type()->As<sem::Vector>()->Width(), 3u);
+    EXPECT_TRUE(members[0]->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(members[1]->Type()->As<sem::Vector>()->Width(), 3u);
+    EXPECT_TRUE(members[1]->Type()->As<sem::Vector>()->type()->Is<sem::I32>());
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Frexp_Vec4) {
-  auto* builtin = Call("frexp", vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f));
-  WrapInFunction(builtin);
+    auto* builtin = Call("frexp", vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f));
+    WrapInFunction(builtin);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  auto* res_ty = TypeOf(builtin)->As<sem::Struct>();
-  ASSERT_TRUE(res_ty != nullptr);
-  auto& members = res_ty->Members();
-  ASSERT_EQ(members.size(), 2u);
-  ASSERT_TRUE(members[0]->Type()->Is<sem::Vector>());
-  ASSERT_TRUE(members[1]->Type()->Is<sem::Vector>());
-  EXPECT_EQ(members[0]->Type()->As<sem::Vector>()->Width(), 4u);
-  EXPECT_TRUE(members[0]->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(members[1]->Type()->As<sem::Vector>()->Width(), 4u);
-  EXPECT_TRUE(members[1]->Type()->As<sem::Vector>()->type()->Is<sem::I32>());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* res_ty = TypeOf(builtin)->As<sem::Struct>();
+    ASSERT_TRUE(res_ty != nullptr);
+    auto& members = res_ty->Members();
+    ASSERT_EQ(members.size(), 2u);
+    ASSERT_TRUE(members[0]->Type()->Is<sem::Vector>());
+    ASSERT_TRUE(members[1]->Type()->Is<sem::Vector>());
+    EXPECT_EQ(members[0]->Type()->As<sem::Vector>()->Width(), 4u);
+    EXPECT_TRUE(members[0]->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(members[1]->Type()->As<sem::Vector>()->Width(), 4u);
+    EXPECT_TRUE(members[1]->Type()->As<sem::Vector>()->type()->Is<sem::I32>());
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Modf_Scalar) {
-  auto* builtin = Call("modf", 1.0f);
-  WrapInFunction(builtin);
+    auto* builtin = Call("modf", 1.0f);
+    WrapInFunction(builtin);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  auto* res_ty = TypeOf(builtin)->As<sem::Struct>();
-  ASSERT_TRUE(res_ty != nullptr);
-  auto& members = res_ty->Members();
-  ASSERT_EQ(members.size(), 2u);
-  EXPECT_TRUE(members[0]->Type()->Is<sem::F32>());
-  EXPECT_TRUE(members[1]->Type()->Is<sem::F32>());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* res_ty = TypeOf(builtin)->As<sem::Struct>();
+    ASSERT_TRUE(res_ty != nullptr);
+    auto& members = res_ty->Members();
+    ASSERT_EQ(members.size(), 2u);
+    EXPECT_TRUE(members[0]->Type()->Is<sem::F32>());
+    EXPECT_TRUE(members[1]->Type()->Is<sem::F32>());
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Modf_Vec2) {
-  auto* builtin = Call("modf", vec2<f32>(1.0f, 1.0f));
-  WrapInFunction(builtin);
+    auto* builtin = Call("modf", vec2<f32>(1.0f, 1.0f));
+    WrapInFunction(builtin);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  auto* res_ty = TypeOf(builtin)->As<sem::Struct>();
-  ASSERT_TRUE(res_ty != nullptr);
-  auto& members = res_ty->Members();
-  ASSERT_EQ(members.size(), 2u);
-  ASSERT_TRUE(members[0]->Type()->Is<sem::Vector>());
-  ASSERT_TRUE(members[1]->Type()->Is<sem::Vector>());
-  EXPECT_EQ(members[0]->Type()->As<sem::Vector>()->Width(), 2u);
-  EXPECT_TRUE(members[0]->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(members[1]->Type()->As<sem::Vector>()->Width(), 2u);
-  EXPECT_TRUE(members[1]->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* res_ty = TypeOf(builtin)->As<sem::Struct>();
+    ASSERT_TRUE(res_ty != nullptr);
+    auto& members = res_ty->Members();
+    ASSERT_EQ(members.size(), 2u);
+    ASSERT_TRUE(members[0]->Type()->Is<sem::Vector>());
+    ASSERT_TRUE(members[1]->Type()->Is<sem::Vector>());
+    EXPECT_EQ(members[0]->Type()->As<sem::Vector>()->Width(), 2u);
+    EXPECT_TRUE(members[0]->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(members[1]->Type()->As<sem::Vector>()->Width(), 2u);
+    EXPECT_TRUE(members[1]->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Modf_Vec3) {
-  auto* builtin = Call("modf", vec3<f32>(1.0f, 1.0f, 1.0f));
-  WrapInFunction(builtin);
+    auto* builtin = Call("modf", vec3<f32>(1.0f, 1.0f, 1.0f));
+    WrapInFunction(builtin);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  auto* res_ty = TypeOf(builtin)->As<sem::Struct>();
-  ASSERT_TRUE(res_ty != nullptr);
-  auto& members = res_ty->Members();
-  ASSERT_EQ(members.size(), 2u);
-  ASSERT_TRUE(members[0]->Type()->Is<sem::Vector>());
-  ASSERT_TRUE(members[1]->Type()->Is<sem::Vector>());
-  EXPECT_EQ(members[0]->Type()->As<sem::Vector>()->Width(), 3u);
-  EXPECT_TRUE(members[0]->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(members[1]->Type()->As<sem::Vector>()->Width(), 3u);
-  EXPECT_TRUE(members[1]->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* res_ty = TypeOf(builtin)->As<sem::Struct>();
+    ASSERT_TRUE(res_ty != nullptr);
+    auto& members = res_ty->Members();
+    ASSERT_EQ(members.size(), 2u);
+    ASSERT_TRUE(members[0]->Type()->Is<sem::Vector>());
+    ASSERT_TRUE(members[1]->Type()->Is<sem::Vector>());
+    EXPECT_EQ(members[0]->Type()->As<sem::Vector>()->Width(), 3u);
+    EXPECT_TRUE(members[0]->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(members[1]->Type()->As<sem::Vector>()->Width(), 3u);
+    EXPECT_TRUE(members[1]->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Modf_Vec4) {
-  auto* builtin = Call("modf", vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f));
-  WrapInFunction(builtin);
+    auto* builtin = Call("modf", vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f));
+    WrapInFunction(builtin);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  auto* res_ty = TypeOf(builtin)->As<sem::Struct>();
-  ASSERT_TRUE(res_ty != nullptr);
-  auto& members = res_ty->Members();
-  ASSERT_EQ(members.size(), 2u);
-  ASSERT_TRUE(members[0]->Type()->Is<sem::Vector>());
-  ASSERT_TRUE(members[1]->Type()->Is<sem::Vector>());
-  EXPECT_EQ(members[0]->Type()->As<sem::Vector>()->Width(), 4u);
-  EXPECT_TRUE(members[0]->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(members[1]->Type()->As<sem::Vector>()->Width(), 4u);
-  EXPECT_TRUE(members[1]->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* res_ty = TypeOf(builtin)->As<sem::Struct>();
+    ASSERT_TRUE(res_ty != nullptr);
+    auto& members = res_ty->Members();
+    ASSERT_EQ(members.size(), 2u);
+    ASSERT_TRUE(members[0]->Type()->Is<sem::Vector>());
+    ASSERT_TRUE(members[1]->Type()->Is<sem::Vector>());
+    EXPECT_EQ(members[0]->Type()->As<sem::Vector>()->Width(), 4u);
+    EXPECT_TRUE(members[0]->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(members[1]->Type()->As<sem::Vector>()->Width(), 4u);
+    EXPECT_TRUE(members[1]->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Cross_Float_Vec3) {
-  auto* builtin =
-      Call("cross", vec3<f32>(1.0f, 1.0f, 1.0f), vec3<f32>(1.0f, 1.0f, 1.0f));
-  WrapInFunction(builtin);
+    auto* builtin = Call("cross", vec3<f32>(1.0f, 1.0f, 1.0f), vec3<f32>(1.0f, 1.0f, 1.0f));
+    WrapInFunction(builtin);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Dot_Float_Vec2) {
-  auto* builtin = Call("dot", vec2<f32>(1.0f, 1.0f), vec2<f32>(1.0f, 1.0f));
-  WrapInFunction(builtin);
+    auto* builtin = Call("dot", vec2<f32>(1.0f, 1.0f), vec2<f32>(1.0f, 1.0f));
+    WrapInFunction(builtin);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Dot_Float_Vec3) {
-  auto* builtin =
-      Call("dot", vec3<f32>(1.0f, 1.0f, 1.0f), vec3<f32>(1.0f, 1.0f, 1.0f));
-  WrapInFunction(builtin);
+    auto* builtin = Call("dot", vec3<f32>(1.0f, 1.0f, 1.0f), vec3<f32>(1.0f, 1.0f, 1.0f));
+    WrapInFunction(builtin);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Dot_Float_Vec4) {
-  auto* builtin = Call("dot", vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f),
-                       vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f));
-  WrapInFunction(builtin);
+    auto* builtin =
+        Call("dot", vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f), vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f));
+    WrapInFunction(builtin);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Select_Float_Scalar) {
-  auto* builtin = Call("select", Expr(1.0f), Expr(1.0f), Expr(true));
-  WrapInFunction(builtin);
+    auto* builtin = Call("select", Expr(1.0f), Expr(1.0f), Expr(true));
+    WrapInFunction(builtin);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Select_Integer_Scalar) {
-  auto* builtin = Call("select", Expr(1), Expr(1), Expr(true));
-  WrapInFunction(builtin);
+    auto* builtin = Call("select", Expr(1_i), Expr(1_i), Expr(true));
+    WrapInFunction(builtin);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Select_Boolean_Scalar) {
-  auto* builtin = Call("select", Expr(true), Expr(true), Expr(true));
-  WrapInFunction(builtin);
+    auto* builtin = Call("select", Expr(true), Expr(true), Expr(true));
+    WrapInFunction(builtin);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Select_Float_Vec2) {
-  auto* builtin = Call("select", vec2<f32>(1.0f, 1.0f), vec2<f32>(1.0f, 1.0f),
-                       vec2<bool>(true, true));
-  WrapInFunction(builtin);
+    auto* builtin =
+        Call("select", vec2<f32>(1.0f, 1.0f), vec2<f32>(1.0f, 1.0f), vec2<bool>(true, true));
+    WrapInFunction(builtin);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Select_Integer_Vec2) {
-  auto* builtin =
-      Call("select", vec2<int>(1, 1), vec2<int>(1, 1), vec2<bool>(true, true));
-  WrapInFunction(builtin);
+    auto* builtin =
+        Call("select", vec2<i32>(1_i, 1_i), vec2<i32>(1_i, 1_i), vec2<bool>(true, true));
+    WrapInFunction(builtin);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverBuiltinsValidationTest, Select_Boolean_Vec2) {
-  auto* builtin = Call("select", vec2<bool>(true, true), vec2<bool>(true, true),
-                       vec2<bool>(true, true));
-  WrapInFunction(builtin);
+    auto* builtin =
+        Call("select", vec2<bool>(true, true), vec2<bool>(true, true), vec2<bool>(true, true));
+    WrapInFunction(builtin);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 template <typename T>
-class ResolverBuiltinsValidationTestWithParams
-    : public resolver::TestHelper,
-      public testing::TestWithParam<T> {};
+class ResolverBuiltinsValidationTestWithParams : public resolver::TestHelper,
+                                                 public testing::TestWithParam<T> {};
 
 using FloatAllMatching =
     ResolverBuiltinsValidationTestWithParams<std::tuple<std::string, uint32_t>>;
 
 TEST_P(FloatAllMatching, Scalar) {
-  std::string name = std::get<0>(GetParam());
-  uint32_t num_params = std::get<1>(GetParam());
+    std::string name = std::get<0>(GetParam());
+    uint32_t num_params = std::get<1>(GetParam());
 
-  ast::ExpressionList params;
-  for (uint32_t i = 0; i < num_params; ++i) {
-    params.push_back(Expr(1.0f));
-  }
-  auto* builtin = Call(name, params);
-  Func("func", {}, ty.void_(), {CallStmt(builtin)},
-       {create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
+    ast::ExpressionList params;
+    for (uint32_t i = 0; i < num_params; ++i) {
+        params.push_back(Expr(1.0f));
+    }
+    auto* builtin = Call(name, params);
+    Func("func", {}, ty.void_(), {CallStmt(builtin)},
+         {create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  EXPECT_TRUE(TypeOf(builtin)->Is<sem::F32>());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(TypeOf(builtin)->Is<sem::F32>());
 }
 
 TEST_P(FloatAllMatching, Vec2) {
-  std::string name = std::get<0>(GetParam());
-  uint32_t num_params = std::get<1>(GetParam());
+    std::string name = std::get<0>(GetParam());
+    uint32_t num_params = std::get<1>(GetParam());
 
-  ast::ExpressionList params;
-  for (uint32_t i = 0; i < num_params; ++i) {
-    params.push_back(vec2<f32>(1.0f, 1.0f));
-  }
-  auto* builtin = Call(name, params);
-  Func("func", {}, ty.void_(), {CallStmt(builtin)},
-       {create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
+    ast::ExpressionList params;
+    for (uint32_t i = 0; i < num_params; ++i) {
+        params.push_back(vec2<f32>(1.0f, 1.0f));
+    }
+    auto* builtin = Call(name, params);
+    Func("func", {}, ty.void_(), {CallStmt(builtin)},
+         {create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  EXPECT_TRUE(TypeOf(builtin)->is_float_vector());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(TypeOf(builtin)->is_float_vector());
 }
 
 TEST_P(FloatAllMatching, Vec3) {
-  std::string name = std::get<0>(GetParam());
-  uint32_t num_params = std::get<1>(GetParam());
+    std::string name = std::get<0>(GetParam());
+    uint32_t num_params = std::get<1>(GetParam());
 
-  ast::ExpressionList params;
-  for (uint32_t i = 0; i < num_params; ++i) {
-    params.push_back(vec3<f32>(1.0f, 1.0f, 1.0f));
-  }
-  auto* builtin = Call(name, params);
-  Func("func", {}, ty.void_(), {CallStmt(builtin)},
-       {create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
+    ast::ExpressionList params;
+    for (uint32_t i = 0; i < num_params; ++i) {
+        params.push_back(vec3<f32>(1.0f, 1.0f, 1.0f));
+    }
+    auto* builtin = Call(name, params);
+    Func("func", {}, ty.void_(), {CallStmt(builtin)},
+         {create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  EXPECT_TRUE(TypeOf(builtin)->is_float_vector());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(TypeOf(builtin)->is_float_vector());
 }
 
 TEST_P(FloatAllMatching, Vec4) {
-  std::string name = std::get<0>(GetParam());
-  uint32_t num_params = std::get<1>(GetParam());
+    std::string name = std::get<0>(GetParam());
+    uint32_t num_params = std::get<1>(GetParam());
 
-  ast::ExpressionList params;
-  for (uint32_t i = 0; i < num_params; ++i) {
-    params.push_back(vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f));
-  }
-  auto* builtin = Call(name, params);
-  Func("func", {}, ty.void_(), {CallStmt(builtin)},
-       {create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
+    ast::ExpressionList params;
+    for (uint32_t i = 0; i < num_params; ++i) {
+        params.push_back(vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f));
+    }
+    auto* builtin = Call(name, params);
+    Func("func", {}, ty.void_(), {CallStmt(builtin)},
+         {create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  EXPECT_TRUE(TypeOf(builtin)->is_float_vector());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(TypeOf(builtin)->is_float_vector());
 }
 
 INSTANTIATE_TEST_SUITE_P(ResolverBuiltinsValidationTest,
@@ -1080,123 +945,123 @@
     ResolverBuiltinsValidationTestWithParams<std::tuple<std::string, uint32_t>>;
 
 TEST_P(IntegerAllMatching, ScalarUnsigned) {
-  std::string name = std::get<0>(GetParam());
-  uint32_t num_params = std::get<1>(GetParam());
+    std::string name = std::get<0>(GetParam());
+    uint32_t num_params = std::get<1>(GetParam());
 
-  ast::ExpressionList params;
-  for (uint32_t i = 0; i < num_params; ++i) {
-    params.push_back(Construct<uint32_t>(1));
-  }
-  auto* builtin = Call(name, params);
-  WrapInFunction(builtin);
+    ast::ExpressionList params;
+    for (uint32_t i = 0; i < num_params; ++i) {
+        params.push_back(Construct<u32>(1_i));
+    }
+    auto* builtin = Call(name, params);
+    WrapInFunction(builtin);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  EXPECT_TRUE(TypeOf(builtin)->Is<sem::U32>());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(TypeOf(builtin)->Is<sem::U32>());
 }
 
 TEST_P(IntegerAllMatching, Vec2Unsigned) {
-  std::string name = std::get<0>(GetParam());
-  uint32_t num_params = std::get<1>(GetParam());
+    std::string name = std::get<0>(GetParam());
+    uint32_t num_params = std::get<1>(GetParam());
 
-  ast::ExpressionList params;
-  for (uint32_t i = 0; i < num_params; ++i) {
-    params.push_back(vec2<uint32_t>(1u, 1u));
-  }
-  auto* builtin = Call(name, params);
-  WrapInFunction(builtin);
+    ast::ExpressionList params;
+    for (uint32_t i = 0; i < num_params; ++i) {
+        params.push_back(vec2<u32>(1_u, 1_u));
+    }
+    auto* builtin = Call(name, params);
+    WrapInFunction(builtin);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  EXPECT_TRUE(TypeOf(builtin)->is_unsigned_integer_vector());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(TypeOf(builtin)->is_unsigned_integer_vector());
 }
 
 TEST_P(IntegerAllMatching, Vec3Unsigned) {
-  std::string name = std::get<0>(GetParam());
-  uint32_t num_params = std::get<1>(GetParam());
+    std::string name = std::get<0>(GetParam());
+    uint32_t num_params = std::get<1>(GetParam());
 
-  ast::ExpressionList params;
-  for (uint32_t i = 0; i < num_params; ++i) {
-    params.push_back(vec3<uint32_t>(1u, 1u, 1u));
-  }
-  auto* builtin = Call(name, params);
-  WrapInFunction(builtin);
+    ast::ExpressionList params;
+    for (uint32_t i = 0; i < num_params; ++i) {
+        params.push_back(vec3<u32>(1_u, 1_u, 1_u));
+    }
+    auto* builtin = Call(name, params);
+    WrapInFunction(builtin);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  EXPECT_TRUE(TypeOf(builtin)->is_unsigned_integer_vector());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(TypeOf(builtin)->is_unsigned_integer_vector());
 }
 
 TEST_P(IntegerAllMatching, Vec4Unsigned) {
-  std::string name = std::get<0>(GetParam());
-  uint32_t num_params = std::get<1>(GetParam());
+    std::string name = std::get<0>(GetParam());
+    uint32_t num_params = std::get<1>(GetParam());
 
-  ast::ExpressionList params;
-  for (uint32_t i = 0; i < num_params; ++i) {
-    params.push_back(vec4<uint32_t>(1u, 1u, 1u, 1u));
-  }
-  auto* builtin = Call(name, params);
-  WrapInFunction(builtin);
+    ast::ExpressionList params;
+    for (uint32_t i = 0; i < num_params; ++i) {
+        params.push_back(vec4<u32>(1_u, 1_u, 1_u, 1_u));
+    }
+    auto* builtin = Call(name, params);
+    WrapInFunction(builtin);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  EXPECT_TRUE(TypeOf(builtin)->is_unsigned_integer_vector());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(TypeOf(builtin)->is_unsigned_integer_vector());
 }
 
 TEST_P(IntegerAllMatching, ScalarSigned) {
-  std::string name = std::get<0>(GetParam());
-  uint32_t num_params = std::get<1>(GetParam());
+    std::string name = std::get<0>(GetParam());
+    uint32_t num_params = std::get<1>(GetParam());
 
-  ast::ExpressionList params;
-  for (uint32_t i = 0; i < num_params; ++i) {
-    params.push_back(Construct<int32_t>(1));
-  }
-  auto* builtin = Call(name, params);
-  WrapInFunction(builtin);
+    ast::ExpressionList params;
+    for (uint32_t i = 0; i < num_params; ++i) {
+        params.push_back(Construct<i32>(1_i));
+    }
+    auto* builtin = Call(name, params);
+    WrapInFunction(builtin);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  EXPECT_TRUE(TypeOf(builtin)->Is<sem::I32>());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(TypeOf(builtin)->Is<sem::I32>());
 }
 
 TEST_P(IntegerAllMatching, Vec2Signed) {
-  std::string name = std::get<0>(GetParam());
-  uint32_t num_params = std::get<1>(GetParam());
+    std::string name = std::get<0>(GetParam());
+    uint32_t num_params = std::get<1>(GetParam());
 
-  ast::ExpressionList params;
-  for (uint32_t i = 0; i < num_params; ++i) {
-    params.push_back(vec2<int32_t>(1, 1));
-  }
-  auto* builtin = Call(name, params);
-  WrapInFunction(builtin);
+    ast::ExpressionList params;
+    for (uint32_t i = 0; i < num_params; ++i) {
+        params.push_back(vec2<i32>(1_i, 1_i));
+    }
+    auto* builtin = Call(name, params);
+    WrapInFunction(builtin);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  EXPECT_TRUE(TypeOf(builtin)->is_signed_integer_vector());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(TypeOf(builtin)->is_signed_integer_vector());
 }
 
 TEST_P(IntegerAllMatching, Vec3Signed) {
-  std::string name = std::get<0>(GetParam());
-  uint32_t num_params = std::get<1>(GetParam());
+    std::string name = std::get<0>(GetParam());
+    uint32_t num_params = std::get<1>(GetParam());
 
-  ast::ExpressionList params;
-  for (uint32_t i = 0; i < num_params; ++i) {
-    params.push_back(vec3<int32_t>(1, 1, 1));
-  }
-  auto* builtin = Call(name, params);
-  WrapInFunction(builtin);
+    ast::ExpressionList params;
+    for (uint32_t i = 0; i < num_params; ++i) {
+        params.push_back(vec3<i32>(1_i, 1_i, 1_i));
+    }
+    auto* builtin = Call(name, params);
+    WrapInFunction(builtin);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  EXPECT_TRUE(TypeOf(builtin)->is_signed_integer_vector());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(TypeOf(builtin)->is_signed_integer_vector());
 }
 
 TEST_P(IntegerAllMatching, Vec4Signed) {
-  std::string name = std::get<0>(GetParam());
-  uint32_t num_params = std::get<1>(GetParam());
+    std::string name = std::get<0>(GetParam());
+    uint32_t num_params = std::get<1>(GetParam());
 
-  ast::ExpressionList params;
-  for (uint32_t i = 0; i < num_params; ++i) {
-    params.push_back(vec4<int32_t>(1, 1, 1, 1));
-  }
-  auto* builtin = Call(name, params);
-  WrapInFunction(builtin);
+    ast::ExpressionList params;
+    for (uint32_t i = 0; i < num_params; ++i) {
+        params.push_back(vec4<i32>(1_i, 1_i, 1_i, 1_i));
+    }
+    auto* builtin = Call(name, params);
+    WrapInFunction(builtin);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  EXPECT_TRUE(TypeOf(builtin)->is_signed_integer_vector());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(TypeOf(builtin)->is_signed_integer_vector());
 }
 
 INSTANTIATE_TEST_SUITE_P(ResolverBuiltinsValidationTest,
@@ -1212,59 +1077,58 @@
     ResolverBuiltinsValidationTestWithParams<std::tuple<std::string, uint32_t>>;
 
 TEST_P(BooleanVectorInput, Vec2) {
-  std::string name = std::get<0>(GetParam());
-  uint32_t num_params = std::get<1>(GetParam());
+    std::string name = std::get<0>(GetParam());
+    uint32_t num_params = std::get<1>(GetParam());
 
-  ast::ExpressionList params;
-  for (uint32_t i = 0; i < num_params; ++i) {
-    params.push_back(vec2<bool>(true, true));
-  }
-  auto* builtin = Call(name, params);
-  WrapInFunction(builtin);
+    ast::ExpressionList params;
+    for (uint32_t i = 0; i < num_params; ++i) {
+        params.push_back(vec2<bool>(true, true));
+    }
+    auto* builtin = Call(name, params);
+    WrapInFunction(builtin);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_P(BooleanVectorInput, Vec3) {
-  std::string name = std::get<0>(GetParam());
-  uint32_t num_params = std::get<1>(GetParam());
+    std::string name = std::get<0>(GetParam());
+    uint32_t num_params = std::get<1>(GetParam());
 
-  ast::ExpressionList params;
-  for (uint32_t i = 0; i < num_params; ++i) {
-    params.push_back(vec3<bool>(true, true, true));
-  }
-  auto* builtin = Call(name, params);
-  WrapInFunction(builtin);
+    ast::ExpressionList params;
+    for (uint32_t i = 0; i < num_params; ++i) {
+        params.push_back(vec3<bool>(true, true, true));
+    }
+    auto* builtin = Call(name, params);
+    WrapInFunction(builtin);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_P(BooleanVectorInput, Vec4) {
-  std::string name = std::get<0>(GetParam());
-  uint32_t num_params = std::get<1>(GetParam());
+    std::string name = std::get<0>(GetParam());
+    uint32_t num_params = std::get<1>(GetParam());
 
-  ast::ExpressionList params;
-  for (uint32_t i = 0; i < num_params; ++i) {
-    params.push_back(vec4<bool>(true, true, true, true));
-  }
-  auto* builtin = Call(name, params);
-  WrapInFunction(builtin);
+    ast::ExpressionList params;
+    for (uint32_t i = 0; i < num_params; ++i) {
+        params.push_back(vec4<bool>(true, true, true, true));
+    }
+    auto* builtin = Call(name, params);
+    WrapInFunction(builtin);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 INSTANTIATE_TEST_SUITE_P(ResolverBuiltinsValidationTest,
                          BooleanVectorInput,
-                         ::testing::Values(std::make_tuple("all", 1),
-                                           std::make_tuple("any", 1)));
+                         ::testing::Values(std::make_tuple("all", 1), std::make_tuple("any", 1)));
 
 using DataPacking4x8 = ResolverBuiltinsValidationTestWithParams<std::string>;
 
 TEST_P(DataPacking4x8, Float_Vec4) {
-  auto name = GetParam();
-  auto* builtin = Call(name, vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f));
-  WrapInFunction(builtin);
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto name = GetParam();
+    auto* builtin = Call(name, vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f));
+    WrapInFunction(builtin);
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 INSTANTIATE_TEST_SUITE_P(ResolverBuiltinsValidationTest,
@@ -1274,17 +1138,15 @@
 using DataPacking2x16 = ResolverBuiltinsValidationTestWithParams<std::string>;
 
 TEST_P(DataPacking2x16, Float_Vec2) {
-  auto name = GetParam();
-  auto* builtin = Call(name, vec2<f32>(1.0f, 1.0f));
-  WrapInFunction(builtin);
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto name = GetParam();
+    auto* builtin = Call(name, vec2<f32>(1.0f, 1.0f));
+    WrapInFunction(builtin);
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 INSTANTIATE_TEST_SUITE_P(ResolverBuiltinsValidationTest,
                          DataPacking2x16,
-                         ::testing::Values("pack2x16snorm",
-                                           "pack2x16unorm",
-                                           "pack2x16float"));
+                         ::testing::Values("pack2x16snorm", "pack2x16unorm", "pack2x16float"));
 
 }  // namespace
 }  // namespace tint::resolver
diff --git a/src/tint/resolver/call_test.cc b/src/tint/resolver/call_test.cc
index 20c80bc..c8b9856 100644
--- a/src/tint/resolver/call_test.cc
+++ b/src/tint/resolver/call_test.cc
@@ -51,20 +51,17 @@
 using alias2 = builder::alias2<T>;
 template <typename T>
 using alias3 = builder::alias3<T>;
-using f32 = builder::f32;
-using i32 = builder::i32;
-using u32 = builder::u32;
 
 using ResolverCallTest = ResolverTest;
 
 struct Params {
-  builder::ast_expr_func_ptr create_value;
-  builder::ast_type_func_ptr create_type;
+    builder::ast_expr_func_ptr create_value;
+    builder::ast_type_func_ptr create_type;
 };
 
 template <typename T>
 constexpr Params ParamsFor() {
-  return Params{DataType<T>::Expr, DataType<T>::AST};
+    return Params{DataType<T>::Expr, DataType<T>::AST};
 }
 
 static constexpr Params all_param_types[] = {
@@ -82,34 +79,34 @@
 };
 
 TEST_F(ResolverCallTest, Valid) {
-  ast::VariableList params;
-  ast::ExpressionList args;
-  for (auto& p : all_param_types) {
-    params.push_back(Param(Sym(), p.create_type(*this)));
-    args.push_back(p.create_value(*this, 0));
-  }
+    ast::VariableList params;
+    ast::ExpressionList args;
+    for (auto& p : all_param_types) {
+        params.push_back(Param(Sym(), p.create_type(*this)));
+        args.push_back(p.create_value(*this, 0));
+    }
 
-  auto* func = Func("foo", std::move(params), ty.f32(), {Return(1.23f)});
-  auto* call_expr = Call("foo", std::move(args));
-  WrapInFunction(call_expr);
+    auto* func = Func("foo", std::move(params), ty.f32(), {Return(1.23f)});
+    auto* call_expr = Call("foo", std::move(args));
+    WrapInFunction(call_expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* call = Sem().Get(call_expr);
-  EXPECT_NE(call, nullptr);
-  EXPECT_EQ(call->Target(), Sem().Get(func));
+    auto* call = Sem().Get(call_expr);
+    EXPECT_NE(call, nullptr);
+    EXPECT_EQ(call->Target(), Sem().Get(func));
 }
 
 TEST_F(ResolverCallTest, OutOfOrder) {
-  auto* call_expr = Call("b");
-  Func("a", {}, ty.void_(), {CallStmt(call_expr)});
-  auto* b = Func("b", {}, ty.void_(), {});
+    auto* call_expr = Call("b");
+    Func("a", {}, ty.void_(), {CallStmt(call_expr)});
+    auto* b = Func("b", {}, ty.void_(), {});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* call = Sem().Get(call_expr);
-  EXPECT_NE(call, nullptr);
-  EXPECT_EQ(call->Target(), Sem().Get(b));
+    auto* call = Sem().Get(call_expr);
+    EXPECT_NE(call, nullptr);
+    EXPECT_EQ(call->Target(), Sem().Get(b));
 }
 
 }  // namespace
diff --git a/src/tint/resolver/call_validation_test.cc b/src/tint/resolver/call_validation_test.cc
index 56cc348..756ba5c 100644
--- a/src/tint/resolver/call_validation_test.cc
+++ b/src/tint/resolver/call_validation_test.cc
@@ -18,267 +18,252 @@
 #include "src/tint/ast/call_statement.h"
 #include "src/tint/resolver/resolver_test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::resolver {
 namespace {
 
 using ResolverCallValidationTest = ResolverTest;
 
 TEST_F(ResolverCallValidationTest, TooFewArgs) {
-  Func("foo", {Param(Sym(), ty.i32()), Param(Sym(), ty.f32())}, ty.void_(),
-       {Return()});
-  auto* call = Call(Source{{12, 34}}, "foo", 1);
-  WrapInFunction(call);
+    Func("foo", {Param(Sym(), ty.i32()), Param(Sym(), ty.f32())}, ty.void_(), {Return()});
+    auto* call = Call(Source{{12, 34}}, "foo", 1_i);
+    WrapInFunction(call);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: too few arguments in call to 'foo', expected 2, got 1");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: too few arguments in call to 'foo', expected 2, got 1");
 }
 
 TEST_F(ResolverCallValidationTest, TooManyArgs) {
-  Func("foo", {Param(Sym(), ty.i32()), Param(Sym(), ty.f32())}, ty.void_(),
-       {Return()});
-  auto* call = Call(Source{{12, 34}}, "foo", 1, 1.0f, 1.0f);
-  WrapInFunction(call);
+    Func("foo", {Param(Sym(), ty.i32()), Param(Sym(), ty.f32())}, ty.void_(), {Return()});
+    auto* call = Call(Source{{12, 34}}, "foo", 1_i, 1.0f, 1.0f);
+    WrapInFunction(call);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: too many arguments in call to 'foo', expected 2, got 3");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: too many arguments in call to 'foo', expected 2, got 3");
 }
 
 TEST_F(ResolverCallValidationTest, MismatchedArgs) {
-  Func("foo", {Param(Sym(), ty.i32()), Param(Sym(), ty.f32())}, ty.void_(),
-       {Return()});
-  auto* call = Call("foo", Expr(Source{{12, 34}}, true), 1.0f);
-  WrapInFunction(call);
+    Func("foo", {Param(Sym(), ty.i32()), Param(Sym(), ty.f32())}, ty.void_(), {Return()});
+    auto* call = Call("foo", Expr(Source{{12, 34}}, true), 1.0f);
+    WrapInFunction(call);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: type mismatch for argument 1 in call to 'foo', "
-            "expected 'i32', got 'bool'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: type mismatch for argument 1 in call to 'foo', "
+              "expected 'i32', got 'bool'");
 }
 
 TEST_F(ResolverCallValidationTest, UnusedRetval) {
-  // fn func() -> f32 { return 1.0; }
-  // fn main() {func(); return; }
+    // fn func() -> f32 { return 1.0; }
+    // fn main() {func(); return; }
 
-  Func("func", {}, ty.f32(), {Return(Expr(1.0f))}, {});
+    Func("func", {}, ty.f32(), {Return(Expr(1.0f))}, {});
 
-  Func("main", {}, ty.void_(),
-       {
-           CallStmt(Source{{12, 34}}, Call("func")),
-           Return(),
-       });
+    Func("main", {}, ty.void_(),
+         {
+             CallStmt(Source{{12, 34}}, Call("func")),
+             Return(),
+         });
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverCallValidationTest, PointerArgument_VariableIdentExpr) {
-  // fn foo(p: ptr<function, i32>) {}
-  // fn main() {
-  //   var z: i32 = 1;
-  //   foo(&z);
-  // }
-  auto* param = Param("p", ty.pointer<i32>(ast::StorageClass::kFunction));
-  Func("foo", {param}, ty.void_(), {});
-  Func("main", {}, ty.void_(),
-       {
-           Decl(Var("z", ty.i32(), Expr(1))),
-           CallStmt(Call("foo", AddressOf(Source{{12, 34}}, Expr("z")))),
-       });
+    // fn foo(p: ptr<function, i32>) {}
+    // fn main() {
+    //   var z: i32 = 1i;
+    //   foo(&z);
+    // }
+    auto* param = Param("p", ty.pointer<i32>(ast::StorageClass::kFunction));
+    Func("foo", {param}, ty.void_(), {});
+    Func("main", {}, ty.void_(),
+         {
+             Decl(Var("z", ty.i32(), Expr(1_i))),
+             CallStmt(Call("foo", AddressOf(Source{{12, 34}}, Expr("z")))),
+         });
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverCallValidationTest, PointerArgument_ConstIdentExpr) {
-  // fn foo(p: ptr<function, i32>) {}
-  // fn main() {
-  //   let z: i32 = 1;
-  //   foo(&z);
-  // }
-  auto* param = Param("p", ty.pointer<i32>(ast::StorageClass::kFunction));
-  Func("foo", {param}, ty.void_(), {});
-  Func("main", {}, ty.void_(),
-       {
-           Decl(Const("z", ty.i32(), Expr(1))),
-           CallStmt(Call("foo", AddressOf(Expr(Source{{12, 34}}, "z")))),
-       });
+    // fn foo(p: ptr<function, i32>) {}
+    // fn main() {
+    //   let z: i32 = 1i;
+    //   foo(&z);
+    // }
+    auto* param = Param("p", ty.pointer<i32>(ast::StorageClass::kFunction));
+    Func("foo", {param}, ty.void_(), {});
+    Func("main", {}, ty.void_(),
+         {
+             Decl(Let("z", ty.i32(), Expr(1_i))),
+             CallStmt(Call("foo", AddressOf(Expr(Source{{12, 34}}, "z")))),
+         });
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: cannot take the address of expression");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: cannot take the address of expression");
 }
 
 TEST_F(ResolverCallValidationTest, PointerArgument_NotIdentExprVar) {
-  // struct S { m: i32; };
-  // fn foo(p: ptr<function, i32>) {}
-  // fn main() {
-  //   var v: S;
-  //   foo(&v.m);
-  // }
-  auto* S = Structure("S", {Member("m", ty.i32())});
-  auto* param = Param("p", ty.pointer<i32>(ast::StorageClass::kFunction));
-  Func("foo", {param}, ty.void_(), {});
-  Func("main", {}, ty.void_(),
-       {
-           Decl(Var("v", ty.Of(S))),
-           CallStmt(Call(
-               "foo", AddressOf(Source{{12, 34}}, MemberAccessor("v", "m")))),
-       });
+    // struct S { m: i32; };
+    // fn foo(p: ptr<function, i32>) {}
+    // fn main() {
+    //   var v: S;
+    //   foo(&v.m);
+    // }
+    auto* S = Structure("S", {Member("m", ty.i32())});
+    auto* param = Param("p", ty.pointer<i32>(ast::StorageClass::kFunction));
+    Func("foo", {param}, ty.void_(), {});
+    Func("main", {}, ty.void_(),
+         {
+             Decl(Var("v", ty.Of(S))),
+             CallStmt(Call("foo", AddressOf(Source{{12, 34}}, MemberAccessor("v", "m")))),
+         });
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: expected an address-of expression of a variable "
-            "identifier expression or a function parameter");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: expected an address-of expression of a variable "
+              "identifier expression or a function parameter");
 }
 
 TEST_F(ResolverCallValidationTest, PointerArgument_AddressOfMemberAccessor) {
-  // struct S { m: i32; };
-  // fn foo(p: ptr<function, i32>) {}
-  // fn main() {
-  //   let v: S = S();
-  //   foo(&v.m);
-  // }
-  auto* S = Structure("S", {Member("m", ty.i32())});
-  auto* param = Param("p", ty.pointer<i32>(ast::StorageClass::kFunction));
-  Func("foo", {param}, ty.void_(), {});
-  Func("main", {}, ty.void_(),
-       {
-           Decl(Const("v", ty.Of(S), Construct(ty.Of(S)))),
-           CallStmt(Call("foo", AddressOf(Expr(Source{{12, 34}},
-                                               MemberAccessor("v", "m"))))),
-       });
+    // struct S { m: i32; };
+    // fn foo(p: ptr<function, i32>) {}
+    // fn main() {
+    //   let v: S = S();
+    //   foo(&v.m);
+    // }
+    auto* S = Structure("S", {Member("m", ty.i32())});
+    auto* param = Param("p", ty.pointer<i32>(ast::StorageClass::kFunction));
+    Func("foo", {param}, ty.void_(), {});
+    Func("main", {}, ty.void_(),
+         {
+             Decl(Let("v", ty.Of(S), Construct(ty.Of(S)))),
+             CallStmt(Call("foo", AddressOf(Expr(Source{{12, 34}}, MemberAccessor("v", "m"))))),
+         });
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: cannot take the address of expression");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: cannot take the address of expression");
 }
 
 TEST_F(ResolverCallValidationTest, PointerArgument_FunctionParam) {
-  // fn foo(p: ptr<function, i32>) {}
-  // fn bar(p: ptr<function, i32>) {
-  // foo(p);
-  // }
-  Func("foo", {Param("p", ty.pointer<i32>(ast::StorageClass::kFunction))},
-       ty.void_(), {});
-  Func("bar", {Param("p", ty.pointer<i32>(ast::StorageClass::kFunction))},
-       ty.void_(), ast::StatementList{CallStmt(Call("foo", Expr("p")))});
+    // fn foo(p: ptr<function, i32>) {}
+    // fn bar(p: ptr<function, i32>) {
+    // foo(p);
+    // }
+    Func("foo", {Param("p", ty.pointer<i32>(ast::StorageClass::kFunction))}, ty.void_(), {});
+    Func("bar", {Param("p", ty.pointer<i32>(ast::StorageClass::kFunction))}, ty.void_(),
+         ast::StatementList{CallStmt(Call("foo", Expr("p")))});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverCallValidationTest, PointerArgument_FunctionParamWithMain) {
-  // fn foo(p: ptr<function, i32>) {}
-  // fn bar(p: ptr<function, i32>) {
-  // foo(p);
-  // }
-  // @stage(fragment)
-  // fn main() {
-  //   var v: i32;
-  //   bar(&v);
-  // }
-  Func("foo", {Param("p", ty.pointer<i32>(ast::StorageClass::kFunction))},
-       ty.void_(), {});
-  Func("bar", {Param("p", ty.pointer<i32>(ast::StorageClass::kFunction))},
-       ty.void_(), ast::StatementList{CallStmt(Call("foo", Expr("p")))});
-  Func("main", ast::VariableList{}, ty.void_(),
-       {
-           Decl(Var("v", ty.i32(), Expr(1))),
-           CallStmt(Call("foo", AddressOf(Expr("v")))),
-       },
-       {
-           Stage(ast::PipelineStage::kFragment),
-       });
+    // fn foo(p: ptr<function, i32>) {}
+    // fn bar(p: ptr<function, i32>) {
+    // foo(p);
+    // }
+    // @stage(fragment)
+    // fn main() {
+    //   var v: i32;
+    //   bar(&v);
+    // }
+    Func("foo", {Param("p", ty.pointer<i32>(ast::StorageClass::kFunction))}, ty.void_(), {});
+    Func("bar", {Param("p", ty.pointer<i32>(ast::StorageClass::kFunction))}, ty.void_(),
+         ast::StatementList{CallStmt(Call("foo", Expr("p")))});
+    Func("main", ast::VariableList{}, ty.void_(),
+         {
+             Decl(Var("v", ty.i32(), Expr(1_i))),
+             CallStmt(Call("foo", AddressOf(Expr("v")))),
+         },
+         {
+             Stage(ast::PipelineStage::kFragment),
+         });
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverCallValidationTest, LetPointer) {
-  // fn x(p : ptr<function, i32>) -> i32 {}
-  // @stage(fragment)
-  // fn main() {
-  //   var v: i32;
-  //   let p: ptr<function, i32> = &v;
-  //   var c: i32 = x(p);
-  // }
-  Func("x", {Param("p", ty.pointer<i32>(ast::StorageClass::kFunction))},
-       ty.void_(), {});
-  auto* v = Var("v", ty.i32());
-  auto* p = Const("p", ty.pointer(ty.i32(), ast::StorageClass::kFunction),
-                  AddressOf(v));
-  auto* c = Var("c", ty.i32(), ast::StorageClass::kNone,
-                Call("x", Expr(Source{{12, 34}}, p)));
-  Func("main", ast::VariableList{}, ty.void_(),
-       {
-           Decl(v),
-           Decl(p),
-           Decl(c),
-       },
-       {
-           Stage(ast::PipelineStage::kFragment),
-       });
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: expected an address-of expression of a variable "
-            "identifier expression or a function parameter");
+    // fn x(p : ptr<function, i32>) -> i32 {}
+    // @stage(fragment)
+    // fn main() {
+    //   var v: i32;
+    //   let p: ptr<function, i32> = &v;
+    //   var c: i32 = x(p);
+    // }
+    Func("x", {Param("p", ty.pointer<i32>(ast::StorageClass::kFunction))}, ty.void_(), {});
+    auto* v = Var("v", ty.i32());
+    auto* p = Let("p", ty.pointer(ty.i32(), ast::StorageClass::kFunction), AddressOf(v));
+    auto* c = Var("c", ty.i32(), ast::StorageClass::kNone, Call("x", Expr(Source{{12, 34}}, p)));
+    Func("main", ast::VariableList{}, ty.void_(),
+         {
+             Decl(v),
+             Decl(p),
+             Decl(c),
+         },
+         {
+             Stage(ast::PipelineStage::kFragment),
+         });
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: expected an address-of expression of a variable "
+              "identifier expression or a function parameter");
 }
 
 TEST_F(ResolverCallValidationTest, LetPointerPrivate) {
-  // let p: ptr<private, i32> = &v;
-  // fn foo(p : ptr<private, i32>) -> i32 {}
-  // var v: i32;
-  // @stage(fragment)
-  // fn main() {
-  //   var c: i32 = foo(p);
-  // }
-  Func("foo", {Param("p", ty.pointer<i32>(ast::StorageClass::kPrivate))},
-       ty.void_(), {});
-  auto* v = Global("v", ty.i32(), ast::StorageClass::kPrivate);
-  auto* p = Const("p", ty.pointer(ty.i32(), ast::StorageClass::kPrivate),
-                  AddressOf(v));
-  auto* c = Var("c", ty.i32(), ast::StorageClass::kNone,
-                Call("foo", Expr(Source{{12, 34}}, p)));
-  Func("main", ast::VariableList{}, ty.void_(),
-       {
-           Decl(p),
-           Decl(c),
-       },
-       {
-           Stage(ast::PipelineStage::kFragment),
-       });
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: expected an address-of expression of a variable "
-            "identifier expression or a function parameter");
+    // let p: ptr<private, i32> = &v;
+    // fn foo(p : ptr<private, i32>) -> i32 {}
+    // var v: i32;
+    // @stage(fragment)
+    // fn main() {
+    //   var c: i32 = foo(p);
+    // }
+    Func("foo", {Param("p", ty.pointer<i32>(ast::StorageClass::kPrivate))}, ty.void_(), {});
+    auto* v = Global("v", ty.i32(), ast::StorageClass::kPrivate);
+    auto* p = Let("p", ty.pointer(ty.i32(), ast::StorageClass::kPrivate), AddressOf(v));
+    auto* c = Var("c", ty.i32(), ast::StorageClass::kNone, Call("foo", Expr(Source{{12, 34}}, p)));
+    Func("main", ast::VariableList{}, ty.void_(),
+         {
+             Decl(p),
+             Decl(c),
+         },
+         {
+             Stage(ast::PipelineStage::kFragment),
+         });
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: expected an address-of expression of a variable "
+              "identifier expression or a function parameter");
 }
 
 TEST_F(ResolverCallValidationTest, CallVariable) {
-  // var v : i32;
-  // fn f() {
-  //   v();
-  // }
-  Global("v", ty.i32(), ast::StorageClass::kPrivate);
-  Func("f", {}, ty.void_(), {CallStmt(Call(Source{{12, 34}}, "v"))});
+    // var v : i32;
+    // fn f() {
+    //   v();
+    // }
+    Global("v", ty.i32(), ast::StorageClass::kPrivate);
+    Func("f", {}, ty.void_(), {CallStmt(Call(Source{{12, 34}}, "v"))});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), R"(error: cannot call variable 'v'
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), R"(error: cannot call variable 'v'
 note: 'v' declared here)");
 }
 
 TEST_F(ResolverCallValidationTest, CallVariableShadowsFunction) {
-  // fn x() {}
-  // fn f() {
-  //   var x : i32;
-  //   x();
-  // }
-  Func("x", {}, ty.void_(), {});
-  Func("f", {}, ty.void_(),
-       {
-           Decl(Var(Source{{56, 78}}, "x", ty.i32())),
-           CallStmt(Call(Source{{12, 34}}, "x")),
-       });
+    // fn x() {}
+    // fn f() {
+    //   var x : i32;
+    //   x();
+    // }
+    Func("x", {}, ty.void_(), {});
+    Func("f", {}, ty.void_(),
+         {
+             Decl(Var(Source{{56, 78}}, "x", ty.i32())),
+             CallStmt(Call(Source{{12, 34}}, "x")),
+         });
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), R"(error: cannot call variable 'x'
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), R"(error: cannot call variable 'x'
 56:78 note: 'x' declared here)");
 }
 
diff --git a/src/tint/resolver/compound_assignment_validation_test.cc b/src/tint/resolver/compound_assignment_validation_test.cc
index 740643c..a3f124d 100644
--- a/src/tint/resolver/compound_assignment_validation_test.cc
+++ b/src/tint/resolver/compound_assignment_validation_test.cc
@@ -16,7 +16,9 @@
 
 #include "gmock/gmock.h"
 #include "src/tint/resolver/resolver_test_helper.h"
-#include "src/tint/sem/storage_texture_type.h"
+#include "src/tint/sem/storage_texture.h"
+
+using namespace tint::number_suffixes;  // NOLINT
 
 namespace tint::resolver {
 namespace {
@@ -24,274 +26,252 @@
 using ResolverCompoundAssignmentValidationTest = ResolverTest;
 
 TEST_F(ResolverCompoundAssignmentValidationTest, CompatibleTypes) {
-  // var a : i32 = 2;
-  // a += 2
-  auto* var = Var("a", ty.i32(), ast::StorageClass::kNone, Expr(2));
-  WrapInFunction(var,
-                 CompoundAssign(Source{{12, 34}}, "a", 2, ast::BinaryOp::kAdd));
+    // var a : i32 = 2;
+    // a += 2
+    auto* var = Var("a", ty.i32(), ast::StorageClass::kNone, Expr(2_i));
+    WrapInFunction(var, CompoundAssign(Source{{12, 34}}, "a", 2_i, ast::BinaryOp::kAdd));
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverCompoundAssignmentValidationTest, CompatibleTypesThroughAlias) {
-  // alias myint = i32;
-  // var a : myint = 2;
-  // a += 2
-  auto* myint = Alias("myint", ty.i32());
-  auto* var = Var("a", ty.Of(myint), ast::StorageClass::kNone, Expr(2));
-  WrapInFunction(var,
-                 CompoundAssign(Source{{12, 34}}, "a", 2, ast::BinaryOp::kAdd));
+    // alias myint = i32;
+    // var a : myint = 2;
+    // a += 2
+    auto* myint = Alias("myint", ty.i32());
+    auto* var = Var("a", ty.Of(myint), ast::StorageClass::kNone, Expr(2_i));
+    WrapInFunction(var, CompoundAssign(Source{{12, 34}}, "a", 2_i, ast::BinaryOp::kAdd));
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
-TEST_F(ResolverCompoundAssignmentValidationTest,
-       CompatibleTypesAssignThroughPointer) {
-  // var a : i32;
-  // let b : ptr<function,i32> = &a;
-  // *b += 2;
-  const auto func = ast::StorageClass::kFunction;
-  auto* var_a = Var("a", ty.i32(), func, Expr(2));
-  auto* var_b = Const("b", ty.pointer<int>(func), AddressOf(Expr("a")));
-  WrapInFunction(
-      var_a, var_b,
-      CompoundAssign(Source{{12, 34}}, Deref("b"), 2, ast::BinaryOp::kAdd));
+TEST_F(ResolverCompoundAssignmentValidationTest, CompatibleTypesAssignThroughPointer) {
+    // var a : i32;
+    // let b : ptr<function,i32> = &a;
+    // *b += 2;
+    const auto func = ast::StorageClass::kFunction;
+    auto* var_a = Var("a", ty.i32(), func, Expr(2_i));
+    auto* var_b = Let("b", ty.pointer<i32>(func), AddressOf(Expr("a")));
+    WrapInFunction(var_a, var_b,
+                   CompoundAssign(Source{{12, 34}}, Deref("b"), 2_i, ast::BinaryOp::kAdd));
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverCompoundAssignmentValidationTest, IncompatibleTypes) {
-  // {
-  //   var a : i32 = 2;
-  //   a += 2.3;
-  // }
+    // {
+    //   var a : i32 = 2;
+    //   a += 2.3;
+    // }
 
-  auto* var = Var("a", ty.i32(), ast::StorageClass::kNone, Expr(2));
+    auto* var = Var("a", ty.i32(), ast::StorageClass::kNone, Expr(2_i));
 
-  auto* assign =
-      CompoundAssign(Source{{12, 34}}, "a", 2.3f, ast::BinaryOp::kAdd);
-  WrapInFunction(var, assign);
+    auto* assign = CompoundAssign(Source{{12, 34}}, "a", 2.3f, ast::BinaryOp::kAdd);
+    WrapInFunction(var, assign);
 
-  ASSERT_FALSE(r()->Resolve());
+    ASSERT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(r()->error(),
-            "12:34 error: compound assignment operand types are invalid: i32 "
-            "add f32");
+    EXPECT_EQ(r()->error(),
+              "12:34 error: compound assignment operand types are invalid: i32 "
+              "add f32");
 }
 
 TEST_F(ResolverCompoundAssignmentValidationTest, IncompatibleOp) {
-  // {
-  //   var a : f32 = 1.0;
-  //   a |= 2.0;
-  // }
+    // {
+    //   var a : f32 = 1.0;
+    //   a |= 2.0;
+    // }
 
-  auto* var = Var("a", ty.f32(), ast::StorageClass::kNone, Expr(1.f));
+    auto* var = Var("a", ty.f32(), ast::StorageClass::kNone, Expr(1.f));
 
-  auto* assign =
-      CompoundAssign(Source{{12, 34}}, "a", 2.0f, ast::BinaryOp::kOr);
-  WrapInFunction(var, assign);
+    auto* assign = CompoundAssign(Source{{12, 34}}, "a", 2.0f, ast::BinaryOp::kOr);
+    WrapInFunction(var, assign);
 
-  ASSERT_FALSE(r()->Resolve());
+    ASSERT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: compound assignment operand types are invalid: f32 or f32");
+    EXPECT_EQ(r()->error(),
+              "12:34 error: compound assignment operand types are invalid: f32 or f32");
 }
 
 TEST_F(ResolverCompoundAssignmentValidationTest, VectorScalar_Pass) {
-  // {
-  //   var a : vec4<f32>;
-  //   a += 1.0;
-  // }
+    // {
+    //   var a : vec4<f32>;
+    //   a += 1.0;
+    // }
 
-  auto* var = Var("a", ty.vec4<f32>(), ast::StorageClass::kNone);
+    auto* var = Var("a", ty.vec4<f32>(), ast::StorageClass::kNone);
 
-  auto* assign =
-      CompoundAssign(Source{{12, 34}}, "a", 1.f, ast::BinaryOp::kAdd);
-  WrapInFunction(var, assign);
+    auto* assign = CompoundAssign(Source{{12, 34}}, "a", 1.f, ast::BinaryOp::kAdd);
+    WrapInFunction(var, assign);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverCompoundAssignmentValidationTest, ScalarVector_Fail) {
-  // {
-  //   var a : f32;
-  //   a += vec4<f32>();
-  // }
+    // {
+    //   var a : f32;
+    //   a += vec4<f32>();
+    // }
 
-  auto* var = Var("a", ty.f32(), ast::StorageClass::kNone);
+    auto* var = Var("a", ty.f32(), ast::StorageClass::kNone);
 
-  auto* assign =
-      CompoundAssign(Source{{12, 34}}, "a", vec4<f32>(), ast::BinaryOp::kAdd);
-  WrapInFunction(var, assign);
+    auto* assign = CompoundAssign(Source{{12, 34}}, "a", vec4<f32>(), ast::BinaryOp::kAdd);
+    WrapInFunction(var, assign);
 
-  ASSERT_FALSE(r()->Resolve());
+    ASSERT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(r()->error(), "12:34 error: cannot assign 'vec4<f32>' to 'f32'");
+    EXPECT_EQ(r()->error(), "12:34 error: cannot assign 'vec4<f32>' to 'f32'");
 }
 
 TEST_F(ResolverCompoundAssignmentValidationTest, MatrixScalar_Pass) {
-  // {
-  //   var a : mat4x4<f32>;
-  //   a *= 2.0;
-  // }
+    // {
+    //   var a : mat4x4<f32>;
+    //   a *= 2.0;
+    // }
 
-  auto* var = Var("a", ty.mat4x4<f32>(), ast::StorageClass::kNone);
+    auto* var = Var("a", ty.mat4x4<f32>(), ast::StorageClass::kNone);
 
-  auto* assign =
-      CompoundAssign(Source{{12, 34}}, "a", 2.f, ast::BinaryOp::kMultiply);
-  WrapInFunction(var, assign);
+    auto* assign = CompoundAssign(Source{{12, 34}}, "a", 2.f, ast::BinaryOp::kMultiply);
+    WrapInFunction(var, assign);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverCompoundAssignmentValidationTest, ScalarMatrix_Fail) {
-  // {
-  //   var a : f32;
-  //   a *= mat4x4();
-  // }
+    // {
+    //   var a : f32;
+    //   a *= mat4x4();
+    // }
 
-  auto* var = Var("a", ty.f32(), ast::StorageClass::kNone);
+    auto* var = Var("a", ty.f32(), ast::StorageClass::kNone);
 
-  auto* assign = CompoundAssign(Source{{12, 34}}, "a", mat4x4<f32>(),
-                                ast::BinaryOp::kMultiply);
-  WrapInFunction(var, assign);
+    auto* assign = CompoundAssign(Source{{12, 34}}, "a", mat4x4<f32>(), ast::BinaryOp::kMultiply);
+    WrapInFunction(var, assign);
 
-  ASSERT_FALSE(r()->Resolve());
+    ASSERT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(r()->error(), "12:34 error: cannot assign 'mat4x4<f32>' to 'f32'");
+    EXPECT_EQ(r()->error(), "12:34 error: cannot assign 'mat4x4<f32>' to 'f32'");
 }
 
 TEST_F(ResolverCompoundAssignmentValidationTest, VectorMatrix_Pass) {
-  // {
-  //   var a : vec4<f32>;
-  //   a *= mat4x4();
-  // }
+    // {
+    //   var a : vec4<f32>;
+    //   a *= mat4x4();
+    // }
 
-  auto* var = Var("a", ty.vec4<f32>(), ast::StorageClass::kNone);
+    auto* var = Var("a", ty.vec4<f32>(), ast::StorageClass::kNone);
 
-  auto* assign = CompoundAssign(Source{{12, 34}}, "a", mat4x4<f32>(),
-                                ast::BinaryOp::kMultiply);
-  WrapInFunction(var, assign);
+    auto* assign = CompoundAssign(Source{{12, 34}}, "a", mat4x4<f32>(), ast::BinaryOp::kMultiply);
+    WrapInFunction(var, assign);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverCompoundAssignmentValidationTest, VectorMatrix_ColumnMismatch) {
-  // {
-  //   var a : vec4<f32>;
-  //   a *= mat4x2();
-  // }
+    // {
+    //   var a : vec4<f32>;
+    //   a *= mat4x2();
+    // }
 
-  auto* var = Var("a", ty.vec4<f32>(), ast::StorageClass::kNone);
+    auto* var = Var("a", ty.vec4<f32>(), ast::StorageClass::kNone);
 
-  auto* assign = CompoundAssign(Source{{12, 34}}, "a", mat4x2<f32>(),
-                                ast::BinaryOp::kMultiply);
-  WrapInFunction(var, assign);
+    auto* assign = CompoundAssign(Source{{12, 34}}, "a", mat4x2<f32>(), ast::BinaryOp::kMultiply);
+    WrapInFunction(var, assign);
 
-  ASSERT_FALSE(r()->Resolve());
+    ASSERT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(r()->error(),
-            "12:34 error: compound assignment operand types are invalid: "
-            "vec4<f32> multiply mat4x2<f32>");
+    EXPECT_EQ(r()->error(),
+              "12:34 error: compound assignment operand types are invalid: "
+              "vec4<f32> multiply mat4x2<f32>");
 }
 
 TEST_F(ResolverCompoundAssignmentValidationTest, VectorMatrix_ResultMismatch) {
-  // {
-  //   var a : vec4<f32>;
-  //   a *= mat2x4();
-  // }
+    // {
+    //   var a : vec4<f32>;
+    //   a *= mat2x4();
+    // }
 
-  auto* var = Var("a", ty.vec4<f32>(), ast::StorageClass::kNone);
+    auto* var = Var("a", ty.vec4<f32>(), ast::StorageClass::kNone);
 
-  auto* assign = CompoundAssign(Source{{12, 34}}, "a", mat2x4<f32>(),
-                                ast::BinaryOp::kMultiply);
-  WrapInFunction(var, assign);
+    auto* assign = CompoundAssign(Source{{12, 34}}, "a", mat2x4<f32>(), ast::BinaryOp::kMultiply);
+    WrapInFunction(var, assign);
 
-  ASSERT_FALSE(r()->Resolve());
+    ASSERT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(r()->error(),
-            "12:34 error: cannot assign 'vec2<f32>' to 'vec4<f32>'");
+    EXPECT_EQ(r()->error(), "12:34 error: cannot assign 'vec2<f32>' to 'vec4<f32>'");
 }
 
 TEST_F(ResolverCompoundAssignmentValidationTest, MatrixVector_Fail) {
-  // {
-  //   var a : mat4x4<f32>;
-  //   a *= vec4();
-  // }
+    // {
+    //   var a : mat4x4<f32>;
+    //   a *= vec4();
+    // }
 
-  auto* var = Var("a", ty.mat4x4<f32>(), ast::StorageClass::kNone);
+    auto* var = Var("a", ty.mat4x4<f32>(), ast::StorageClass::kNone);
 
-  auto* assign = CompoundAssign(Source{{12, 34}}, "a", vec4<f32>(),
-                                ast::BinaryOp::kMultiply);
-  WrapInFunction(var, assign);
+    auto* assign = CompoundAssign(Source{{12, 34}}, "a", vec4<f32>(), ast::BinaryOp::kMultiply);
+    WrapInFunction(var, assign);
 
-  ASSERT_FALSE(r()->Resolve());
+    ASSERT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(r()->error(),
-            "12:34 error: cannot assign 'vec4<f32>' to 'mat4x4<f32>'");
+    EXPECT_EQ(r()->error(), "12:34 error: cannot assign 'vec4<f32>' to 'mat4x4<f32>'");
 }
 
 TEST_F(ResolverCompoundAssignmentValidationTest, Phony) {
-  // {
-  //   _ += 1;
-  // }
-  WrapInFunction(
-      CompoundAssign(Source{{56, 78}}, Phony(), 1, ast::BinaryOp::kAdd));
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "56:78 error: compound assignment operand types are invalid: void "
-            "add i32");
+    // {
+    //   _ += 1i;
+    // }
+    WrapInFunction(CompoundAssign(Source{{56, 78}}, Phony(), 1_i, ast::BinaryOp::kAdd));
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "56:78 error: compound assignment operand types are invalid: void "
+              "add i32");
 }
 
 TEST_F(ResolverCompoundAssignmentValidationTest, ReadOnlyBuffer) {
-  // @group(0) @binding(0) var<storage,read> a : i32;
-  // {
-  //   a += 1;
-  // }
-  Global(Source{{12, 34}}, "a", ty.i32(), ast::StorageClass::kStorage,
-         ast::Access::kRead, GroupAndBinding(0, 0));
-  WrapInFunction(CompoundAssign(Source{{56, 78}}, "a", 1, ast::BinaryOp::kAdd));
+    // @group(0) @binding(0) var<storage,read> a : i32;
+    // {
+    //   a += 1i;
+    // }
+    Global(Source{{12, 34}}, "a", ty.i32(), ast::StorageClass::kStorage, ast::Access::kRead,
+           GroupAndBinding(0, 0));
+    WrapInFunction(CompoundAssign(Source{{56, 78}}, "a", 1_i, ast::BinaryOp::kAdd));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "56:78 error: cannot store into a read-only type 'ref<storage, "
-            "i32, read>'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "56:78 error: cannot store into a read-only type 'ref<storage, "
+              "i32, read>'");
 }
 
 TEST_F(ResolverCompoundAssignmentValidationTest, LhsConstant) {
-  // let a = 1;
-  // a += 1;
-  auto* a = Const(Source{{12, 34}}, "a", nullptr, Expr(1));
-  WrapInFunction(
-      a, CompoundAssign(Expr(Source{{56, 78}}, "a"), 1, ast::BinaryOp::kAdd));
+    // let a = 1i;
+    // a += 1i;
+    auto* a = Let(Source{{12, 34}}, "a", nullptr, Expr(1_i));
+    WrapInFunction(a, CompoundAssign(Expr(Source{{56, 78}}, "a"), 1_i, ast::BinaryOp::kAdd));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), R"(56:78 error: cannot assign to const
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), R"(56:78 error: cannot assign to const
 12:34 note: 'a' is declared here:)");
 }
 
 TEST_F(ResolverCompoundAssignmentValidationTest, LhsLiteral) {
-  // 1 += 1;
-  WrapInFunction(
-      CompoundAssign(Expr(Source{{56, 78}}, 1), 1, ast::BinaryOp::kAdd));
+    // 1i += 1i;
+    WrapInFunction(CompoundAssign(Expr(Source{{56, 78}}, 1_i), 1_i, ast::BinaryOp::kAdd));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "56:78 error: cannot assign to value of type 'i32'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "56:78 error: cannot assign to value of type 'i32'");
 }
 
 TEST_F(ResolverCompoundAssignmentValidationTest, LhsAtomic) {
-  // var<workgroup> a : atomic<i32>;
-  // a += a;
-  Global(Source{{12, 34}}, "a", ty.atomic(ty.i32()),
-         ast::StorageClass::kWorkgroup);
-  WrapInFunction(
-      CompoundAssign(Source{{56, 78}}, "a", "a", ast::BinaryOp::kAdd));
+    // var<workgroup> a : atomic<i32>;
+    // a += a;
+    Global(Source{{12, 34}}, "a", ty.atomic(ty.i32()), ast::StorageClass::kWorkgroup);
+    WrapInFunction(CompoundAssign(Source{{56, 78}}, "a", "a", ast::BinaryOp::kAdd));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "56:78 error: compound assignment operand types are invalid: "
-            "atomic<i32> add atomic<i32>");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "56:78 error: compound assignment operand types are invalid: "
+              "atomic<i32> add atomic<i32>");
 }
 
 }  // namespace
diff --git a/src/tint/resolver/compound_statement_test.cc b/src/tint/resolver/compound_statement_test.cc
index 29c0384..4061a62 100644
--- a/src/tint/resolver/compound_statement_test.cc
+++ b/src/tint/resolver/compound_statement_test.cc
@@ -22,356 +22,347 @@
 #include "src/tint/sem/loop_statement.h"
 #include "src/tint/sem/switch_statement.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::resolver {
 namespace {
 
 using ResolverCompoundStatementTest = ResolverTest;
 
 TEST_F(ResolverCompoundStatementTest, FunctionBlock) {
-  // fn F() {
-  //   var x : 32;
-  // }
-  auto* stmt = Decl(Var("x", ty.i32()));
-  auto* f = Func("F", {}, ty.void_(), {stmt});
+    // fn F() {
+    //   var x : 32;
+    // }
+    auto* stmt = Decl(Var("x", ty.i32()));
+    auto* f = Func("F", {}, ty.void_(), {stmt});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* s = Sem().Get(stmt);
-  ASSERT_NE(s, nullptr);
-  ASSERT_NE(s->Block(), nullptr);
-  ASSERT_TRUE(s->Block()->Is<sem::FunctionBlockStatement>());
-  EXPECT_EQ(s->Block(), s->FindFirstParent<sem::BlockStatement>());
-  EXPECT_EQ(s->Block(), s->FindFirstParent<sem::FunctionBlockStatement>());
-  EXPECT_EQ(s->Function()->Declaration(), f);
-  EXPECT_EQ(s->Block()->Parent(), nullptr);
+    auto* s = Sem().Get(stmt);
+    ASSERT_NE(s, nullptr);
+    ASSERT_NE(s->Block(), nullptr);
+    ASSERT_TRUE(s->Block()->Is<sem::FunctionBlockStatement>());
+    EXPECT_EQ(s->Block(), s->FindFirstParent<sem::BlockStatement>());
+    EXPECT_EQ(s->Block(), s->FindFirstParent<sem::FunctionBlockStatement>());
+    EXPECT_EQ(s->Function()->Declaration(), f);
+    EXPECT_EQ(s->Block()->Parent(), nullptr);
 }
 
 TEST_F(ResolverCompoundStatementTest, Block) {
-  // fn F() {
-  //   {
-  //     var x : 32;
-  //   }
-  // }
-  auto* stmt = Decl(Var("x", ty.i32()));
-  auto* block = Block(stmt);
-  auto* f = Func("F", {}, ty.void_(), {block});
+    // fn F() {
+    //   {
+    //     var x : 32;
+    //   }
+    // }
+    auto* stmt = Decl(Var("x", ty.i32()));
+    auto* block = Block(stmt);
+    auto* f = Func("F", {}, ty.void_(), {block});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  {
-    auto* s = Sem().Get(block);
-    ASSERT_NE(s, nullptr);
-    EXPECT_TRUE(s->Is<sem::BlockStatement>());
-    EXPECT_EQ(s, s->Block());
-    EXPECT_EQ(s->Parent(), s->FindFirstParent<sem::FunctionBlockStatement>());
-  }
-  {
-    auto* s = Sem().Get(stmt);
-    ASSERT_NE(s, nullptr);
-    ASSERT_NE(s->Block(), nullptr);
-    EXPECT_EQ(s->Block(), s->FindFirstParent<sem::BlockStatement>());
-    EXPECT_EQ(s->Block()->Parent(),
-              s->FindFirstParent<sem::FunctionBlockStatement>());
-    ASSERT_TRUE(s->Block()->Parent()->Is<sem::FunctionBlockStatement>());
-    EXPECT_EQ(s->Function()->Declaration(), f);
-    EXPECT_EQ(s->Block()->Parent()->Parent(), nullptr);
-  }
+    {
+        auto* s = Sem().Get(block);
+        ASSERT_NE(s, nullptr);
+        EXPECT_TRUE(s->Is<sem::BlockStatement>());
+        EXPECT_EQ(s, s->Block());
+        EXPECT_EQ(s->Parent(), s->FindFirstParent<sem::FunctionBlockStatement>());
+    }
+    {
+        auto* s = Sem().Get(stmt);
+        ASSERT_NE(s, nullptr);
+        ASSERT_NE(s->Block(), nullptr);
+        EXPECT_EQ(s->Block(), s->FindFirstParent<sem::BlockStatement>());
+        EXPECT_EQ(s->Block()->Parent(), s->FindFirstParent<sem::FunctionBlockStatement>());
+        ASSERT_TRUE(s->Block()->Parent()->Is<sem::FunctionBlockStatement>());
+        EXPECT_EQ(s->Function()->Declaration(), f);
+        EXPECT_EQ(s->Block()->Parent()->Parent(), nullptr);
+    }
 }
 
 TEST_F(ResolverCompoundStatementTest, Loop) {
-  // fn F() {
-  //   loop {
-  //     break;
-  //     continuing {
-  //       stmt;
-  //     }
-  //   }
-  // }
-  auto* brk = Break();
-  auto* stmt = Ignore(1);
-  auto* loop = Loop(Block(brk), Block(stmt));
-  auto* f = Func("F", {}, ty.void_(), {loop});
+    // fn F() {
+    //   loop {
+    //     break;
+    //     continuing {
+    //       stmt;
+    //     }
+    //   }
+    // }
+    auto* brk = Break();
+    auto* stmt = Ignore(1_i);
+    auto* loop = Loop(Block(brk), Block(stmt));
+    auto* f = Func("F", {}, ty.void_(), {loop});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  {
-    auto* s = Sem().Get(loop);
-    ASSERT_NE(s, nullptr);
-    EXPECT_TRUE(s->Is<sem::LoopStatement>());
-    EXPECT_EQ(s->Parent(), s->FindFirstParent<sem::FunctionBlockStatement>());
-    EXPECT_EQ(s->Parent(), s->Block());
-  }
-  {
-    auto* s = Sem().Get(brk);
-    ASSERT_NE(s, nullptr);
-    ASSERT_NE(s->Block(), nullptr);
-    EXPECT_EQ(s->Parent(), s->Block());
-    EXPECT_EQ(s->Parent(), s->FindFirstParent<sem::LoopBlockStatement>());
+    {
+        auto* s = Sem().Get(loop);
+        ASSERT_NE(s, nullptr);
+        EXPECT_TRUE(s->Is<sem::LoopStatement>());
+        EXPECT_EQ(s->Parent(), s->FindFirstParent<sem::FunctionBlockStatement>());
+        EXPECT_EQ(s->Parent(), s->Block());
+    }
+    {
+        auto* s = Sem().Get(brk);
+        ASSERT_NE(s, nullptr);
+        ASSERT_NE(s->Block(), nullptr);
+        EXPECT_EQ(s->Parent(), s->Block());
+        EXPECT_EQ(s->Parent(), s->FindFirstParent<sem::LoopBlockStatement>());
 
-    EXPECT_EQ(s->Parent()->Parent(), s->FindFirstParent<sem::LoopStatement>());
-    EXPECT_TRUE(Is<sem::LoopStatement>(s->Parent()->Parent()));
+        EXPECT_EQ(s->Parent()->Parent(), s->FindFirstParent<sem::LoopStatement>());
+        EXPECT_TRUE(Is<sem::LoopStatement>(s->Parent()->Parent()));
 
-    EXPECT_EQ(s->Parent()->Parent()->Parent(),
-              s->FindFirstParent<sem::FunctionBlockStatement>());
-    EXPECT_TRUE(
-        Is<sem::FunctionBlockStatement>(s->Parent()->Parent()->Parent()));
+        EXPECT_EQ(s->Parent()->Parent()->Parent(),
+                  s->FindFirstParent<sem::FunctionBlockStatement>());
+        EXPECT_TRUE(Is<sem::FunctionBlockStatement>(s->Parent()->Parent()->Parent()));
 
-    EXPECT_EQ(s->Function()->Declaration(), f);
+        EXPECT_EQ(s->Function()->Declaration(), f);
 
-    EXPECT_EQ(s->Parent()->Parent()->Parent()->Parent(), nullptr);
-  }
-  {
-    auto* s = Sem().Get(stmt);
-    ASSERT_NE(s, nullptr);
-    ASSERT_NE(s->Block(), nullptr);
-    EXPECT_EQ(s->Parent(), s->Block());
+        EXPECT_EQ(s->Parent()->Parent()->Parent()->Parent(), nullptr);
+    }
+    {
+        auto* s = Sem().Get(stmt);
+        ASSERT_NE(s, nullptr);
+        ASSERT_NE(s->Block(), nullptr);
+        EXPECT_EQ(s->Parent(), s->Block());
 
-    EXPECT_EQ(s->Parent(),
-              s->FindFirstParent<sem::LoopContinuingBlockStatement>());
-    EXPECT_TRUE(Is<sem::LoopContinuingBlockStatement>(s->Parent()));
+        EXPECT_EQ(s->Parent(), s->FindFirstParent<sem::LoopContinuingBlockStatement>());
+        EXPECT_TRUE(Is<sem::LoopContinuingBlockStatement>(s->Parent()));
 
-    EXPECT_EQ(s->Parent()->Parent(),
-              s->FindFirstParent<sem::LoopBlockStatement>());
-    EXPECT_TRUE(Is<sem::LoopBlockStatement>(s->Parent()->Parent()));
+        EXPECT_EQ(s->Parent()->Parent(), s->FindFirstParent<sem::LoopBlockStatement>());
+        EXPECT_TRUE(Is<sem::LoopBlockStatement>(s->Parent()->Parent()));
 
-    EXPECT_EQ(s->Parent()->Parent()->Parent(),
-              s->FindFirstParent<sem::LoopStatement>());
-    EXPECT_TRUE(Is<sem::LoopStatement>(s->Parent()->Parent()->Parent()));
+        EXPECT_EQ(s->Parent()->Parent()->Parent(), s->FindFirstParent<sem::LoopStatement>());
+        EXPECT_TRUE(Is<sem::LoopStatement>(s->Parent()->Parent()->Parent()));
 
-    EXPECT_EQ(s->Parent()->Parent()->Parent()->Parent(),
-              s->FindFirstParent<sem::FunctionBlockStatement>());
-    EXPECT_TRUE(Is<sem::FunctionBlockStatement>(
-        s->Parent()->Parent()->Parent()->Parent()));
-    EXPECT_EQ(s->Function()->Declaration(), f);
+        EXPECT_EQ(s->Parent()->Parent()->Parent()->Parent(),
+                  s->FindFirstParent<sem::FunctionBlockStatement>());
+        EXPECT_TRUE(Is<sem::FunctionBlockStatement>(s->Parent()->Parent()->Parent()->Parent()));
+        EXPECT_EQ(s->Function()->Declaration(), f);
 
-    EXPECT_EQ(s->Parent()->Parent()->Parent()->Parent()->Parent(), nullptr);
-  }
+        EXPECT_EQ(s->Parent()->Parent()->Parent()->Parent()->Parent(), nullptr);
+    }
 }
 
 TEST_F(ResolverCompoundStatementTest, ForLoop) {
-  // fn F() {
-  //   for (var i : u32; true; i = i + 1u) {
-  //     return;
-  //   }
-  // }
-  auto* init = Decl(Var("i", ty.u32()));
-  auto* cond = Expr(true);
-  auto* cont = Assign("i", Add("i", 1u));
-  auto* stmt = Return();
-  auto* body = Block(stmt);
-  auto* for_ = For(init, cond, cont, body);
-  auto* f = Func("F", {}, ty.void_(), {for_});
+    // fn F() {
+    //   for (var i : u32; true; i = i + 1u) {
+    //     return;
+    //   }
+    // }
+    auto* init = Decl(Var("i", ty.u32()));
+    auto* cond = Expr(true);
+    auto* cont = Assign("i", Add("i", 1_u));
+    auto* stmt = Return();
+    auto* body = Block(stmt);
+    auto* for_ = For(init, cond, cont, body);
+    auto* f = Func("F", {}, ty.void_(), {for_});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  {
-    auto* s = Sem().Get(for_);
-    ASSERT_NE(s, nullptr);
-    EXPECT_TRUE(s->Is<sem::ForLoopStatement>());
-    EXPECT_EQ(s->Parent(), s->FindFirstParent<sem::FunctionBlockStatement>());
-    EXPECT_EQ(s->Parent(), s->Block());
-  }
-  {
-    auto* s = Sem().Get(init);
-    ASSERT_NE(s, nullptr);
-    EXPECT_EQ(s->Parent(), s->FindFirstParent<sem::ForLoopStatement>());
-    EXPECT_TRUE(Is<sem::ForLoopStatement>(s->Parent()));
-    EXPECT_EQ(s->Block(), s->FindFirstParent<sem::FunctionBlockStatement>());
-    EXPECT_TRUE(Is<sem::FunctionBlockStatement>(s->Parent()->Parent()));
-  }
-  {  // Condition expression's statement is the for-loop itself
-    auto* e = Sem().Get(cond);
-    ASSERT_NE(e, nullptr);
-    auto* s = e->Stmt();
-    ASSERT_NE(s, nullptr);
-    ASSERT_TRUE(Is<sem::ForLoopStatement>(s));
-    ASSERT_NE(s->Parent(), nullptr);
-    EXPECT_EQ(s->Parent(), s->Block());
-    EXPECT_EQ(s->Parent(), s->FindFirstParent<sem::FunctionBlockStatement>());
-    EXPECT_TRUE(Is<sem::FunctionBlockStatement>(s->Block()));
-  }
-  {
-    auto* s = Sem().Get(cont);
-    ASSERT_NE(s, nullptr);
-    EXPECT_EQ(s->Parent(), s->FindFirstParent<sem::ForLoopStatement>());
-    EXPECT_TRUE(Is<sem::ForLoopStatement>(s->Parent()));
-    EXPECT_EQ(s->Block(), s->FindFirstParent<sem::FunctionBlockStatement>());
-    EXPECT_TRUE(Is<sem::FunctionBlockStatement>(s->Parent()->Parent()));
-  }
-  {
-    auto* s = Sem().Get(stmt);
-    ASSERT_NE(s, nullptr);
-    ASSERT_NE(s->Block(), nullptr);
-    EXPECT_EQ(s->Parent(), s->Block());
-    EXPECT_EQ(s->Block(), s->FindFirstParent<sem::LoopBlockStatement>());
-    EXPECT_TRUE(Is<sem::ForLoopStatement>(s->Parent()->Parent()));
-    EXPECT_EQ(s->Block()->Parent(),
-              s->FindFirstParent<sem::ForLoopStatement>());
-    ASSERT_TRUE(
-        Is<sem::FunctionBlockStatement>(s->Block()->Parent()->Parent()));
-    EXPECT_EQ(s->Block()->Parent()->Parent(),
-              s->FindFirstParent<sem::FunctionBlockStatement>());
-    EXPECT_EQ(s->Function()->Declaration(), f);
-    EXPECT_EQ(s->Block()->Parent()->Parent()->Parent(), nullptr);
-  }
+    {
+        auto* s = Sem().Get(for_);
+        ASSERT_NE(s, nullptr);
+        EXPECT_TRUE(s->Is<sem::ForLoopStatement>());
+        EXPECT_EQ(s->Parent(), s->FindFirstParent<sem::FunctionBlockStatement>());
+        EXPECT_EQ(s->Parent(), s->Block());
+    }
+    {
+        auto* s = Sem().Get(init);
+        ASSERT_NE(s, nullptr);
+        EXPECT_EQ(s->Parent(), s->FindFirstParent<sem::ForLoopStatement>());
+        EXPECT_TRUE(Is<sem::ForLoopStatement>(s->Parent()));
+        EXPECT_EQ(s->Block(), s->FindFirstParent<sem::FunctionBlockStatement>());
+        EXPECT_TRUE(Is<sem::FunctionBlockStatement>(s->Parent()->Parent()));
+    }
+    {  // Condition expression's statement is the for-loop itself
+        auto* e = Sem().Get(cond);
+        ASSERT_NE(e, nullptr);
+        auto* s = e->Stmt();
+        ASSERT_NE(s, nullptr);
+        ASSERT_TRUE(Is<sem::ForLoopStatement>(s));
+        ASSERT_NE(s->Parent(), nullptr);
+        EXPECT_EQ(s->Parent(), s->Block());
+        EXPECT_EQ(s->Parent(), s->FindFirstParent<sem::FunctionBlockStatement>());
+        EXPECT_TRUE(Is<sem::FunctionBlockStatement>(s->Block()));
+    }
+    {
+        auto* s = Sem().Get(cont);
+        ASSERT_NE(s, nullptr);
+        EXPECT_EQ(s->Parent(), s->FindFirstParent<sem::ForLoopStatement>());
+        EXPECT_TRUE(Is<sem::ForLoopStatement>(s->Parent()));
+        EXPECT_EQ(s->Block(), s->FindFirstParent<sem::FunctionBlockStatement>());
+        EXPECT_TRUE(Is<sem::FunctionBlockStatement>(s->Parent()->Parent()));
+    }
+    {
+        auto* s = Sem().Get(stmt);
+        ASSERT_NE(s, nullptr);
+        ASSERT_NE(s->Block(), nullptr);
+        EXPECT_EQ(s->Parent(), s->Block());
+        EXPECT_EQ(s->Block(), s->FindFirstParent<sem::LoopBlockStatement>());
+        EXPECT_TRUE(Is<sem::ForLoopStatement>(s->Parent()->Parent()));
+        EXPECT_EQ(s->Block()->Parent(), s->FindFirstParent<sem::ForLoopStatement>());
+        ASSERT_TRUE(Is<sem::FunctionBlockStatement>(s->Block()->Parent()->Parent()));
+        EXPECT_EQ(s->Block()->Parent()->Parent(),
+                  s->FindFirstParent<sem::FunctionBlockStatement>());
+        EXPECT_EQ(s->Function()->Declaration(), f);
+        EXPECT_EQ(s->Block()->Parent()->Parent()->Parent(), nullptr);
+    }
 }
 
 TEST_F(ResolverCompoundStatementTest, If) {
-  // fn F() {
-  //   if (cond_a) {
-  //     stat_a;
-  //   } else if (cond_b) {
-  //     stat_b;
-  //   } else {
-  //     stat_c;
-  //   }
-  // }
+    // fn F() {
+    //   if (cond_a) {
+    //     stat_a;
+    //   } else if (cond_b) {
+    //     stat_b;
+    //   } else {
+    //     stat_c;
+    //   }
+    // }
 
-  auto* cond_a = Expr(true);
-  auto* stmt_a = Ignore(1);
-  auto* cond_b = Expr(true);
-  auto* stmt_b = Ignore(1);
-  auto* stmt_c = Ignore(1);
-  auto* if_stmt = If(cond_a, Block(stmt_a), Else(cond_b, Block(stmt_b)),
-                     Else(nullptr, Block(stmt_c)));
-  WrapInFunction(if_stmt);
+    auto* cond_a = Expr(true);
+    auto* stmt_a = Ignore(1_i);
+    auto* cond_b = Expr(true);
+    auto* stmt_b = Ignore(1_i);
+    auto* stmt_c = Ignore(1_i);
+    auto* if_stmt = If(cond_a, Block(stmt_a), Else(If(cond_b, Block(stmt_b), Else(Block(stmt_c)))));
+    WrapInFunction(if_stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  {
-    auto* s = Sem().Get(if_stmt);
-    ASSERT_NE(s, nullptr);
-    EXPECT_TRUE(s->Is<sem::IfStatement>());
-    EXPECT_EQ(s->Parent(), s->FindFirstParent<sem::FunctionBlockStatement>());
-    EXPECT_EQ(s->Parent(), s->Block());
-  }
-  {
-    auto* e = Sem().Get(cond_a);
-    ASSERT_NE(e, nullptr);
-    auto* s = e->Stmt();
-    ASSERT_NE(s, nullptr);
-    EXPECT_TRUE(s->Is<sem::IfStatement>());
-    EXPECT_EQ(s->Parent(), s->FindFirstParent<sem::FunctionBlockStatement>());
-    EXPECT_EQ(s->Parent(), s->Block());
-  }
-  {
-    auto* s = Sem().Get(stmt_a);
-    ASSERT_NE(s, nullptr);
-    EXPECT_EQ(s->Parent(), s->FindFirstParent<sem::BlockStatement>());
-    EXPECT_EQ(s->Parent(), s->Block());
-    EXPECT_EQ(s->Parent()->Parent(), s->FindFirstParent<sem::IfStatement>());
-    EXPECT_EQ(s->Parent()->Parent()->Parent(),
-              s->FindFirstParent<sem::FunctionBlockStatement>());
-  }
-  {
-    auto* e = Sem().Get(cond_b);
-    ASSERT_NE(e, nullptr);
-    auto* s = e->Stmt();
-    ASSERT_NE(s, nullptr);
-    EXPECT_TRUE(s->Is<sem::ElseStatement>());
-    EXPECT_EQ(s->Parent(), s->FindFirstParent<sem::IfStatement>());
-    EXPECT_EQ(s->Parent()->Parent(),
-              s->FindFirstParent<sem::FunctionBlockStatement>());
-    EXPECT_EQ(s->Parent()->Parent(), s->Block());
-  }
-  {
-    auto* s = Sem().Get(stmt_b);
-    ASSERT_NE(s, nullptr);
-    EXPECT_EQ(s->Parent(), s->FindFirstParent<sem::BlockStatement>());
-    EXPECT_EQ(s->Parent(), s->Block());
-    EXPECT_EQ(s->Parent()->Parent(), s->FindFirstParent<sem::ElseStatement>());
-    EXPECT_EQ(s->Parent()->Parent()->Parent(),
-              s->FindFirstParent<sem::IfStatement>());
-    EXPECT_EQ(s->Parent()->Parent()->Parent()->Parent(),
-              s->FindFirstParent<sem::FunctionBlockStatement>());
-  }
-  {
-    auto* s = Sem().Get(stmt_c);
-    ASSERT_NE(s, nullptr);
-    EXPECT_EQ(s->Parent(), s->FindFirstParent<sem::BlockStatement>());
-    EXPECT_EQ(s->Parent(), s->Block());
-    EXPECT_EQ(s->Parent()->Parent(), s->FindFirstParent<sem::ElseStatement>());
-    EXPECT_EQ(s->Parent()->Parent()->Parent(),
-              s->FindFirstParent<sem::IfStatement>());
-    EXPECT_EQ(s->Parent()->Parent()->Parent()->Parent(),
-              s->FindFirstParent<sem::FunctionBlockStatement>());
-  }
+    {
+        auto* s = Sem().Get(if_stmt);
+        ASSERT_NE(s, nullptr);
+        EXPECT_TRUE(s->Is<sem::IfStatement>());
+        EXPECT_EQ(s->Parent(), s->FindFirstParent<sem::FunctionBlockStatement>());
+        EXPECT_EQ(s->Parent(), s->Block());
+    }
+    {
+        auto* e = Sem().Get(cond_a);
+        ASSERT_NE(e, nullptr);
+        auto* s = e->Stmt();
+        ASSERT_NE(s, nullptr);
+        EXPECT_TRUE(s->Is<sem::IfStatement>());
+        EXPECT_EQ(s->Parent(), s->FindFirstParent<sem::FunctionBlockStatement>());
+        EXPECT_EQ(s->Parent(), s->Block());
+    }
+    {
+        auto* s = Sem().Get(stmt_a);
+        ASSERT_NE(s, nullptr);
+        EXPECT_EQ(s->Parent(), s->FindFirstParent<sem::BlockStatement>());
+        EXPECT_EQ(s->Parent(), s->Block());
+        EXPECT_EQ(s->Parent()->Parent(), s->FindFirstParent<sem::IfStatement>());
+        EXPECT_EQ(s->Parent()->Parent()->Parent(),
+                  s->FindFirstParent<sem::FunctionBlockStatement>());
+    }
+    {
+        auto* e = Sem().Get(cond_b);
+        ASSERT_NE(e, nullptr);
+        auto* s = e->Stmt();
+        ASSERT_NE(s, nullptr);
+        EXPECT_TRUE(s->Is<sem::IfStatement>());
+        EXPECT_EQ(s->Parent(), s->Parent()->FindFirstParent<sem::IfStatement>());
+        EXPECT_EQ(s->Parent()->Parent(), s->FindFirstParent<sem::FunctionBlockStatement>());
+        EXPECT_EQ(s->Parent()->Parent(), s->Block());
+    }
+    {
+        auto* s = Sem().Get(stmt_b);
+        ASSERT_NE(s, nullptr);
+        EXPECT_EQ(s->Parent(), s->FindFirstParent<sem::BlockStatement>());
+        EXPECT_EQ(s->Parent(), s->Block());
+        auto* elseif = s->FindFirstParent<sem::IfStatement>();
+        EXPECT_EQ(s->Parent()->Parent(), elseif);
+        EXPECT_EQ(s->Parent()->Parent()->Parent(),
+                  elseif->Parent()->FindFirstParent<sem::IfStatement>());
+        EXPECT_EQ(s->Parent()->Parent()->Parent()->Parent(),
+                  s->FindFirstParent<sem::FunctionBlockStatement>());
+    }
+    {
+        auto* s = Sem().Get(stmt_c);
+        ASSERT_NE(s, nullptr);
+        EXPECT_EQ(s->Parent(), s->FindFirstParent<sem::BlockStatement>());
+        EXPECT_EQ(s->Parent(), s->Block());
+        auto* elseif = s->FindFirstParent<sem::IfStatement>();
+        EXPECT_EQ(s->Parent()->Parent(), elseif);
+        EXPECT_EQ(s->Parent()->Parent()->Parent(),
+                  elseif->Parent()->FindFirstParent<sem::IfStatement>());
+        EXPECT_EQ(s->Parent()->Parent()->Parent()->Parent(),
+                  s->FindFirstParent<sem::FunctionBlockStatement>());
+    }
 }
 
 TEST_F(ResolverCompoundStatementTest, Switch) {
-  // fn F() {
-  //   switch (expr) {
-  //     case 1: {
-  //        stmt_a;
-  //     }
-  //     case 2: {
-  //        stmt_b;
-  //     }
-  //     default: {
-  //        stmt_c;
-  //     }
-  //   }
-  // }
+    // fn F() {
+    //   switch (expr) {
+    //     case 1i: {
+    //        stmt_a;
+    //     }
+    //     case 2i: {
+    //        stmt_b;
+    //     }
+    //     default: {
+    //        stmt_c;
+    //     }
+    //   }
+    // }
 
-  auto* expr = Expr(5);
-  auto* stmt_a = Ignore(1);
-  auto* stmt_b = Ignore(1);
-  auto* stmt_c = Ignore(1);
-  auto* swi = Switch(expr, Case(Expr(1), Block(stmt_a)),
-                     Case(Expr(2), Block(stmt_b)), DefaultCase(Block(stmt_c)));
-  WrapInFunction(swi);
+    auto* expr = Expr(5_i);
+    auto* stmt_a = Ignore(1_i);
+    auto* stmt_b = Ignore(1_i);
+    auto* stmt_c = Ignore(1_i);
+    auto* swi = Switch(expr, Case(Expr(1_i), Block(stmt_a)), Case(Expr(2_i), Block(stmt_b)),
+                       DefaultCase(Block(stmt_c)));
+    WrapInFunction(swi);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  {
-    auto* s = Sem().Get(swi);
-    ASSERT_NE(s, nullptr);
-    EXPECT_TRUE(s->Is<sem::SwitchStatement>());
-    EXPECT_EQ(s->Parent(), s->FindFirstParent<sem::FunctionBlockStatement>());
-    EXPECT_EQ(s->Parent(), s->Block());
-  }
-  {
-    auto* e = Sem().Get(expr);
-    ASSERT_NE(e, nullptr);
-    auto* s = e->Stmt();
-    ASSERT_NE(s, nullptr);
-    EXPECT_TRUE(s->Is<sem::SwitchStatement>());
-    EXPECT_EQ(s->Parent(), s->FindFirstParent<sem::FunctionBlockStatement>());
-    EXPECT_EQ(s->Parent(), s->Block());
-  }
-  {
-    auto* s = Sem().Get(stmt_a);
-    ASSERT_NE(s, nullptr);
-    EXPECT_EQ(s->Parent(), s->FindFirstParent<sem::BlockStatement>());
-    EXPECT_EQ(s->Parent(), s->Block());
-    EXPECT_EQ(s->Parent()->Parent(), s->FindFirstParent<sem::CaseStatement>());
-    EXPECT_EQ(s->Parent()->Parent()->Parent(),
-              s->FindFirstParent<sem::SwitchStatement>());
-    EXPECT_EQ(s->Parent()->Parent()->Parent()->Parent(),
-              s->FindFirstParent<sem::FunctionBlockStatement>());
-  }
-  {
-    auto* s = Sem().Get(stmt_b);
-    ASSERT_NE(s, nullptr);
-    EXPECT_EQ(s->Parent(), s->FindFirstParent<sem::BlockStatement>());
-    EXPECT_EQ(s->Parent(), s->Block());
-    EXPECT_EQ(s->Parent()->Parent(), s->FindFirstParent<sem::CaseStatement>());
-    EXPECT_EQ(s->Parent()->Parent()->Parent(),
-              s->FindFirstParent<sem::SwitchStatement>());
-    EXPECT_EQ(s->Parent()->Parent()->Parent()->Parent(),
-              s->FindFirstParent<sem::FunctionBlockStatement>());
-  }
-  {
-    auto* s = Sem().Get(stmt_c);
-    ASSERT_NE(s, nullptr);
-    EXPECT_EQ(s->Parent(), s->FindFirstParent<sem::BlockStatement>());
-    EXPECT_EQ(s->Parent(), s->Block());
-    EXPECT_EQ(s->Parent()->Parent(), s->FindFirstParent<sem::CaseStatement>());
-    EXPECT_EQ(s->Parent()->Parent()->Parent(),
-              s->FindFirstParent<sem::SwitchStatement>());
-    EXPECT_EQ(s->Parent()->Parent()->Parent()->Parent(),
-              s->FindFirstParent<sem::FunctionBlockStatement>());
-  }
+    {
+        auto* s = Sem().Get(swi);
+        ASSERT_NE(s, nullptr);
+        EXPECT_TRUE(s->Is<sem::SwitchStatement>());
+        EXPECT_EQ(s->Parent(), s->FindFirstParent<sem::FunctionBlockStatement>());
+        EXPECT_EQ(s->Parent(), s->Block());
+    }
+    {
+        auto* e = Sem().Get(expr);
+        ASSERT_NE(e, nullptr);
+        auto* s = e->Stmt();
+        ASSERT_NE(s, nullptr);
+        EXPECT_TRUE(s->Is<sem::SwitchStatement>());
+        EXPECT_EQ(s->Parent(), s->FindFirstParent<sem::FunctionBlockStatement>());
+        EXPECT_EQ(s->Parent(), s->Block());
+    }
+    {
+        auto* s = Sem().Get(stmt_a);
+        ASSERT_NE(s, nullptr);
+        EXPECT_EQ(s->Parent(), s->FindFirstParent<sem::BlockStatement>());
+        EXPECT_EQ(s->Parent(), s->Block());
+        EXPECT_EQ(s->Parent()->Parent(), s->FindFirstParent<sem::CaseStatement>());
+        EXPECT_EQ(s->Parent()->Parent()->Parent(), s->FindFirstParent<sem::SwitchStatement>());
+        EXPECT_EQ(s->Parent()->Parent()->Parent()->Parent(),
+                  s->FindFirstParent<sem::FunctionBlockStatement>());
+    }
+    {
+        auto* s = Sem().Get(stmt_b);
+        ASSERT_NE(s, nullptr);
+        EXPECT_EQ(s->Parent(), s->FindFirstParent<sem::BlockStatement>());
+        EXPECT_EQ(s->Parent(), s->Block());
+        EXPECT_EQ(s->Parent()->Parent(), s->FindFirstParent<sem::CaseStatement>());
+        EXPECT_EQ(s->Parent()->Parent()->Parent(), s->FindFirstParent<sem::SwitchStatement>());
+        EXPECT_EQ(s->Parent()->Parent()->Parent()->Parent(),
+                  s->FindFirstParent<sem::FunctionBlockStatement>());
+    }
+    {
+        auto* s = Sem().Get(stmt_c);
+        ASSERT_NE(s, nullptr);
+        EXPECT_EQ(s->Parent(), s->FindFirstParent<sem::BlockStatement>());
+        EXPECT_EQ(s->Parent(), s->Block());
+        EXPECT_EQ(s->Parent()->Parent(), s->FindFirstParent<sem::CaseStatement>());
+        EXPECT_EQ(s->Parent()->Parent()->Parent(), s->FindFirstParent<sem::SwitchStatement>());
+        EXPECT_EQ(s->Parent()->Parent()->Parent()->Parent(),
+                  s->FindFirstParent<sem::FunctionBlockStatement>());
+    }
 }
 
 }  // namespace
diff --git a/src/tint/resolver/control_block_validation_test.cc b/src/tint/resolver/control_block_validation_test.cc
index fdb2059..b4742c9 100644
--- a/src/tint/resolver/control_block_validation_test.cc
+++ b/src/tint/resolver/control_block_validation_test.cc
@@ -18,346 +18,335 @@
 #include "src/tint/ast/switch_statement.h"
 #include "src/tint/resolver/resolver_test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::resolver {
 namespace {
 
-class ResolverControlBlockValidationTest : public TestHelper,
-                                           public testing::Test {};
+class ResolverControlBlockValidationTest : public TestHelper, public testing::Test {};
 
-TEST_F(ResolverControlBlockValidationTest,
-       SwitchSelectorExpressionNoneIntegerType_Fail) {
-  // var a : f32 = 3.14;
-  // switch (a) {
-  //   default: {}
-  // }
-  auto* var = Var("a", ty.f32(), Expr(3.14f));
+TEST_F(ResolverControlBlockValidationTest, SwitchSelectorExpressionNoneIntegerType_Fail) {
+    // var a : f32 = 3.14;
+    // switch (a) {
+    //   default: {}
+    // }
+    auto* var = Var("a", ty.f32(), Expr(3.14f));
 
-  auto* block = Block(Decl(var), Switch(Expr(Source{{12, 34}}, "a"),  //
-                                        DefaultCase()));
+    auto* block = Block(Decl(var), Switch(Expr(Source{{12, 34}}, "a"),  //
+                                          DefaultCase()));
 
-  WrapInFunction(block);
+    WrapInFunction(block);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: switch statement selector expression must be of a "
-            "scalar integer type");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: switch statement selector expression must be of a "
+              "scalar integer type");
 }
 
 TEST_F(ResolverControlBlockValidationTest, SwitchWithoutDefault_Fail) {
-  // var a : i32 = 2;
-  // switch (a) {
-  //   case 1: {}
-  // }
-  auto* var = Var("a", ty.i32(), Expr(2));
+    // var a : i32 = 2;
+    // switch (a) {
+    //   case 1: {}
+    // }
+    auto* var = Var("a", ty.i32(), Expr(2_i));
 
-  auto* block = Block(Decl(var),                     //
-                      Switch(Source{{12, 34}}, "a",  //
-                             Case(Expr(1))));
+    auto* block = Block(Decl(var),                     //
+                        Switch(Source{{12, 34}}, "a",  //
+                               Case(Expr(1_i))));
 
-  WrapInFunction(block);
+    WrapInFunction(block);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: switch statement must have a default clause");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: switch statement must have a default clause");
 }
 
 TEST_F(ResolverControlBlockValidationTest, SwitchWithTwoDefault_Fail) {
-  // var a : i32 = 2;
-  // switch (a) {
-  //   default: {}
-  //   case 1: {}
-  //   default: {}
-  // }
-  auto* var = Var("a", ty.i32(), Expr(2));
+    // var a : i32 = 2;
+    // switch (a) {
+    //   default: {}
+    //   case 1: {}
+    //   default: {}
+    // }
+    auto* var = Var("a", ty.i32(), Expr(2_i));
 
-  auto* block = Block(Decl(var),             //
-                      Switch("a",            //
-                             DefaultCase(),  //
-                             Case(Expr(1)),  //
-                             DefaultCase(Source{{12, 34}})));
+    auto* block = Block(Decl(var),               //
+                        Switch("a",              //
+                               DefaultCase(),    //
+                               Case(Expr(1_i)),  //
+                               DefaultCase(Source{{12, 34}})));
 
-  WrapInFunction(block);
+    WrapInFunction(block);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: switch statement must have exactly one default clause");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: switch statement must have exactly one default clause");
 }
 
 TEST_F(ResolverControlBlockValidationTest, UnreachableCode_Loop_continue) {
-  // loop {
-  //   if (false) { break; }
-  //   var z: i32;
-  //   continue;
-  //   z = 1;
-  // }
-  auto* decl_z = Decl(Var("z", ty.i32()));
-  auto* cont = Continue();
-  auto* assign_z = Assign(Source{{12, 34}}, "z", 1);
-  WrapInFunction(
-      Loop(Block(If(false, Block(Break())), decl_z, cont, assign_z)));
+    // loop {
+    //   if (false) { break; }
+    //   var z: i32;
+    //   continue;
+    //   z = 1;
+    // }
+    auto* decl_z = Decl(Var("z", ty.i32()));
+    auto* cont = Continue();
+    auto* assign_z = Assign(Source{{12, 34}}, "z", 1_i);
+    WrapInFunction(Loop(Block(If(false, Block(Break())), decl_z, cont, assign_z)));
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
-  EXPECT_EQ(r()->error(), "12:34 warning: code is unreachable");
-  EXPECT_TRUE(Sem().Get(decl_z)->IsReachable());
-  EXPECT_TRUE(Sem().Get(cont)->IsReachable());
-  EXPECT_FALSE(Sem().Get(assign_z)->IsReachable());
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_EQ(r()->error(), "12:34 warning: code is unreachable");
+    EXPECT_TRUE(Sem().Get(decl_z)->IsReachable());
+    EXPECT_TRUE(Sem().Get(cont)->IsReachable());
+    EXPECT_FALSE(Sem().Get(assign_z)->IsReachable());
 }
 
-TEST_F(ResolverControlBlockValidationTest,
-       UnreachableCode_Loop_continue_InBlocks) {
-  // loop {
-  //   if (false) { break; }
-  //   var z: i32;
-  //   {{{continue;}}}
-  //   z = 1;
-  // }
-  auto* decl_z = Decl(Var("z", ty.i32()));
-  auto* cont = Continue();
-  auto* assign_z = Assign(Source{{12, 34}}, "z", 1);
-  WrapInFunction(Loop(Block(If(false, Block(Break())), decl_z,
-                            Block(Block(Block(cont))), assign_z)));
+TEST_F(ResolverControlBlockValidationTest, UnreachableCode_Loop_continue_InBlocks) {
+    // loop {
+    //   if (false) { break; }
+    //   var z: i32;
+    //   {{{continue;}}}
+    //   z = 1;
+    // }
+    auto* decl_z = Decl(Var("z", ty.i32()));
+    auto* cont = Continue();
+    auto* assign_z = Assign(Source{{12, 34}}, "z", 1_i);
+    WrapInFunction(
+        Loop(Block(If(false, Block(Break())), decl_z, Block(Block(Block(cont))), assign_z)));
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
-  EXPECT_EQ(r()->error(), "12:34 warning: code is unreachable");
-  EXPECT_TRUE(Sem().Get(decl_z)->IsReachable());
-  EXPECT_TRUE(Sem().Get(cont)->IsReachable());
-  EXPECT_FALSE(Sem().Get(assign_z)->IsReachable());
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_EQ(r()->error(), "12:34 warning: code is unreachable");
+    EXPECT_TRUE(Sem().Get(decl_z)->IsReachable());
+    EXPECT_TRUE(Sem().Get(cont)->IsReachable());
+    EXPECT_FALSE(Sem().Get(assign_z)->IsReachable());
 }
 
 TEST_F(ResolverControlBlockValidationTest, UnreachableCode_ForLoop_continue) {
-  // for (;false;) {
-  //   var z: i32;
-  //   continue;
-  //   z = 1;
-  // }
-  auto* decl_z = Decl(Var("z", ty.i32()));
-  auto* cont = Continue();
-  auto* assign_z = Assign(Source{{12, 34}}, "z", 1);
-  WrapInFunction(For(nullptr, false, nullptr,  //
-                     Block(decl_z, cont, assign_z)));
+    // for (;false;) {
+    //   var z: i32;
+    //   continue;
+    //   z = 1;
+    // }
+    auto* decl_z = Decl(Var("z", ty.i32()));
+    auto* cont = Continue();
+    auto* assign_z = Assign(Source{{12, 34}}, "z", 1_i);
+    WrapInFunction(For(nullptr, false, nullptr,  //
+                       Block(decl_z, cont, assign_z)));
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
-  EXPECT_EQ(r()->error(), "12:34 warning: code is unreachable");
-  EXPECT_TRUE(Sem().Get(decl_z)->IsReachable());
-  EXPECT_TRUE(Sem().Get(cont)->IsReachable());
-  EXPECT_FALSE(Sem().Get(assign_z)->IsReachable());
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_EQ(r()->error(), "12:34 warning: code is unreachable");
+    EXPECT_TRUE(Sem().Get(decl_z)->IsReachable());
+    EXPECT_TRUE(Sem().Get(cont)->IsReachable());
+    EXPECT_FALSE(Sem().Get(assign_z)->IsReachable());
 }
 
-TEST_F(ResolverControlBlockValidationTest,
-       UnreachableCode_ForLoop_continue_InBlocks) {
-  // for (;false;) {
-  //   var z: i32;
-  //   {{{continue;}}}
-  //   z = 1;
-  // }
-  auto* decl_z = Decl(Var("z", ty.i32()));
-  auto* cont = Continue();
-  auto* assign_z = Assign(Source{{12, 34}}, "z", 1);
-  WrapInFunction(For(nullptr, false, nullptr,
-                     Block(decl_z, Block(Block(Block(cont))), assign_z)));
+TEST_F(ResolverControlBlockValidationTest, UnreachableCode_ForLoop_continue_InBlocks) {
+    // for (;false;) {
+    //   var z: i32;
+    //   {{{continue;}}}
+    //   z = 1;
+    // }
+    auto* decl_z = Decl(Var("z", ty.i32()));
+    auto* cont = Continue();
+    auto* assign_z = Assign(Source{{12, 34}}, "z", 1_i);
+    WrapInFunction(
+        For(nullptr, false, nullptr, Block(decl_z, Block(Block(Block(cont))), assign_z)));
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
-  EXPECT_EQ(r()->error(), "12:34 warning: code is unreachable");
-  EXPECT_TRUE(Sem().Get(decl_z)->IsReachable());
-  EXPECT_TRUE(Sem().Get(cont)->IsReachable());
-  EXPECT_FALSE(Sem().Get(assign_z)->IsReachable());
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_EQ(r()->error(), "12:34 warning: code is unreachable");
+    EXPECT_TRUE(Sem().Get(decl_z)->IsReachable());
+    EXPECT_TRUE(Sem().Get(cont)->IsReachable());
+    EXPECT_FALSE(Sem().Get(assign_z)->IsReachable());
 }
 
 TEST_F(ResolverControlBlockValidationTest, UnreachableCode_break) {
-  // switch (1) {
-  //   case 1: {
-  //     var z: i32;
-  //     break;
-  //     z = 1;
-  //   default: {}
-  // }
-  auto* decl_z = Decl(Var("z", ty.i32()));
-  auto* brk = Break();
-  auto* assign_z = Assign(Source{{12, 34}}, "z", 1);
-  WrapInFunction(                                                //
-      Block(Switch(1,                                            //
-                   Case(Expr(1), Block(decl_z, brk, assign_z)),  //
-                   DefaultCase())));
+    // switch (1i) {
+    //   case 1i: {
+    //     var z: i32;
+    //     break;
+    //     z = 1i;
+    //   default: {}
+    // }
+    auto* decl_z = Decl(Var("z", ty.i32()));
+    auto* brk = Break();
+    auto* assign_z = Assign(Source{{12, 34}}, "z", 1_i);
+    WrapInFunction(                                                  //
+        Block(Switch(1_i,                                            //
+                     Case(Expr(1_i), Block(decl_z, brk, assign_z)),  //
+                     DefaultCase())));
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
-  EXPECT_EQ(r()->error(), "12:34 warning: code is unreachable");
-  EXPECT_TRUE(Sem().Get(decl_z)->IsReachable());
-  EXPECT_TRUE(Sem().Get(brk)->IsReachable());
-  EXPECT_FALSE(Sem().Get(assign_z)->IsReachable());
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_EQ(r()->error(), "12:34 warning: code is unreachable");
+    EXPECT_TRUE(Sem().Get(decl_z)->IsReachable());
+    EXPECT_TRUE(Sem().Get(brk)->IsReachable());
+    EXPECT_FALSE(Sem().Get(assign_z)->IsReachable());
 }
 
 TEST_F(ResolverControlBlockValidationTest, UnreachableCode_break_InBlocks) {
-  // loop {
-  //   switch (1) {
-  //     case 1: { {{{break;}}} var a : u32 = 2;}
-  //     default: {}
-  //   }
-  //   break;
-  // }
-  auto* decl_z = Decl(Var("z", ty.i32()));
-  auto* brk = Break();
-  auto* assign_z = Assign(Source{{12, 34}}, "z", 1);
-  WrapInFunction(Loop(Block(
-      Switch(1,  //
-             Case(Expr(1), Block(decl_z, Block(Block(Block(brk))), assign_z)),
-             DefaultCase()),  //
-      Break())));
+    // loop {
+    //   switch (1i) {
+    //     case 1i: { {{{break;}}} var a : u32 = 2;}
+    //     default: {}
+    //   }
+    //   break;
+    // }
+    auto* decl_z = Decl(Var("z", ty.i32()));
+    auto* brk = Break();
+    auto* assign_z = Assign(Source{{12, 34}}, "z", 1_i);
+    WrapInFunction(
+        Loop(Block(Switch(1_i,  //
+                          Case(Expr(1_i), Block(decl_z, Block(Block(Block(brk))), assign_z)),
+                          DefaultCase()),  //
+                   Break())));
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
-  EXPECT_EQ(r()->error(), "12:34 warning: code is unreachable");
-  EXPECT_TRUE(Sem().Get(decl_z)->IsReachable());
-  EXPECT_TRUE(Sem().Get(brk)->IsReachable());
-  EXPECT_FALSE(Sem().Get(assign_z)->IsReachable());
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_EQ(r()->error(), "12:34 warning: code is unreachable");
+    EXPECT_TRUE(Sem().Get(decl_z)->IsReachable());
+    EXPECT_TRUE(Sem().Get(brk)->IsReachable());
+    EXPECT_FALSE(Sem().Get(assign_z)->IsReachable());
 }
 
-TEST_F(ResolverControlBlockValidationTest,
-       SwitchConditionTypeMustMatchSelectorType2_Fail) {
-  // var a : u32 = 2;
-  // switch (a) {
-  //   case 1: {}
-  //   default: {}
-  // }
-  auto* var = Var("a", ty.i32(), Expr(2));
+TEST_F(ResolverControlBlockValidationTest, SwitchConditionTypeMustMatchSelectorType2_Fail) {
+    // var a : u32 = 2;
+    // switch (a) {
+    //   case 1i: {}
+    //   default: {}
+    // }
+    auto* var = Var("a", ty.i32(), Expr(2_i));
 
-  auto* block = Block(Decl(var), Switch("a",                                 //
-                                        Case(Source{{12, 34}}, {Expr(1u)}),  //
-                                        DefaultCase()));
-  WrapInFunction(block);
+    auto* block = Block(Decl(var), Switch("a",                                  //
+                                          Case(Source{{12, 34}}, {Expr(1_u)}),  //
+                                          DefaultCase()));
+    WrapInFunction(block);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: the case selector values must have the same type as "
-            "the selector expression.");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: the case selector values must have the same type as "
+              "the selector expression.");
 }
 
-TEST_F(ResolverControlBlockValidationTest,
-       SwitchConditionTypeMustMatchSelectorType_Fail) {
-  // var a : u32 = 2;
-  // switch (a) {
-  //   case -1: {}
-  //   default: {}
-  // }
-  auto* var = Var("a", ty.u32(), Expr(2u));
+TEST_F(ResolverControlBlockValidationTest, SwitchConditionTypeMustMatchSelectorType_Fail) {
+    // var a : u32 = 2;
+    // switch (a) {
+    //   case -1i: {}
+    //   default: {}
+    // }
+    auto* var = Var("a", ty.u32(), Expr(2_u));
 
-  auto* block = Block(Decl(var),                                  //
-                      Switch("a",                                 //
-                             Case(Source{{12, 34}}, {Expr(-1)}),  //
-                             DefaultCase()));
-  WrapInFunction(block);
+    auto* block = Block(Decl(var),                                       //
+                        Switch("a",                                      //
+                               Case(Source{{12, 34}}, {Expr(i32(-1))}),  //
+                               DefaultCase()));
+    WrapInFunction(block);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: the case selector values must have the same type as "
-            "the selector expression.");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: the case selector values must have the same type as "
+              "the selector expression.");
 }
 
-TEST_F(ResolverControlBlockValidationTest,
-       NonUniqueCaseSelectorValueUint_Fail) {
-  // var a : u32 = 3;
-  // switch (a) {
-  //   case 0u: {}
-  //   case 2u, 3u, 2u: {}
-  //   default: {}
-  // }
-  auto* var = Var("a", ty.u32(), Expr(3u));
+TEST_F(ResolverControlBlockValidationTest, NonUniqueCaseSelectorValueUint_Fail) {
+    // var a : u32 = 3;
+    // switch (a) {
+    //   case 0u: {}
+    //   case 2u, 3u, 2u: {}
+    //   default: {}
+    // }
+    auto* var = Var("a", ty.u32(), Expr(3_u));
 
-  auto* block = Block(Decl(var),   //
-                      Switch("a",  //
-                             Case(Expr(0u)),
-                             Case({
-                                 Expr(Source{{12, 34}}, 2u),
-                                 Expr(3u),
-                                 Expr(Source{{56, 78}}, 2u),
-                             }),
-                             DefaultCase()));
-  WrapInFunction(block);
+    auto* block = Block(Decl(var),   //
+                        Switch("a",  //
+                               Case(Expr(0_u)),
+                               Case({
+                                   Expr(Source{{12, 34}}, 2_u),
+                                   Expr(3_u),
+                                   Expr(Source{{56, 78}}, 2_u),
+                               }),
+                               DefaultCase()));
+    WrapInFunction(block);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "56:78 error: duplicate switch case '2'\n"
-            "12:34 note: previous case declared here");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "56:78 error: duplicate switch case '2'\n"
+              "12:34 note: previous case declared here");
 }
 
-TEST_F(ResolverControlBlockValidationTest,
-       NonUniqueCaseSelectorValueSint_Fail) {
-  // var a : i32 = 2;
-  // switch (a) {
-  //   case -10: {}
-  //   case 0,1,2,-10: {}
-  //   default: {}
-  // }
-  auto* var = Var("a", ty.i32(), Expr(2));
+TEST_F(ResolverControlBlockValidationTest, NonUniqueCaseSelectorValueSint_Fail) {
+    // var a : i32 = 2;
+    // switch (a) {
+    //   case -10: {}
+    //   case 0,1,2,-10: {}
+    //   default: {}
+    // }
+    auto* var = Var("a", ty.i32(), Expr(2_i));
 
-  auto* block = Block(Decl(var),   //
-                      Switch("a",  //
-                             Case(Expr(Source{{12, 34}}, -10)),
-                             Case({
-                                 Expr(0),
-                                 Expr(1),
-                                 Expr(2),
-                                 Expr(Source{{56, 78}}, -10),
-                             }),
-                             DefaultCase()));
-  WrapInFunction(block);
+    auto* block = Block(Decl(var),   //
+                        Switch("a",  //
+                               Case(Expr(Source{{12, 34}}, i32(-10))),
+                               Case({
+                                   Expr(0_i),
+                                   Expr(1_i),
+                                   Expr(2_i),
+                                   Expr(Source{{56, 78}}, i32(-10)),
+                               }),
+                               DefaultCase()));
+    WrapInFunction(block);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "56:78 error: duplicate switch case '-10'\n"
-            "12:34 note: previous case declared here");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "56:78 error: duplicate switch case '-10'\n"
+              "12:34 note: previous case declared here");
 }
 
-TEST_F(ResolverControlBlockValidationTest,
-       LastClauseLastStatementIsFallthrough_Fail) {
-  // var a : i32 = 2;
-  // switch (a) {
-  //   default: { fallthrough; }
-  // }
-  auto* var = Var("a", ty.i32(), Expr(2));
-  auto* fallthrough = create<ast::FallthroughStatement>(Source{{12, 34}});
-  auto* block = Block(Decl(var),   //
-                      Switch("a",  //
-                             DefaultCase(Block(fallthrough))));
-  WrapInFunction(block);
+TEST_F(ResolverControlBlockValidationTest, LastClauseLastStatementIsFallthrough_Fail) {
+    // var a : i32 = 2;
+    // switch (a) {
+    //   default: { fallthrough; }
+    // }
+    auto* var = Var("a", ty.i32(), Expr(2_i));
+    auto* fallthrough = create<ast::FallthroughStatement>(Source{{12, 34}});
+    auto* block = Block(Decl(var),   //
+                        Switch("a",  //
+                               DefaultCase(Block(fallthrough))));
+    WrapInFunction(block);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: a fallthrough statement must not be used in the last "
-            "switch case");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: a fallthrough statement must not be used in the last "
+              "switch case");
 }
 
 TEST_F(ResolverControlBlockValidationTest, SwitchCase_Pass) {
-  // var a : i32 = 2;
-  // switch (a) {
-  //   default: {}
-  //   case 5: {}
-  // }
-  auto* var = Var("a", ty.i32(), Expr(2));
+    // var a : i32 = 2;
+    // switch (a) {
+    //   default: {}
+    //   case 5: {}
+    // }
+    auto* var = Var("a", ty.i32(), Expr(2_i));
 
-  auto* block = Block(Decl(var),                             //
-                      Switch("a",                            //
-                             DefaultCase(Source{{12, 34}}),  //
-                             Case(Expr(5))));
-  WrapInFunction(block);
+    auto* block = Block(Decl(var),                             //
+                        Switch("a",                            //
+                               DefaultCase(Source{{12, 34}}),  //
+                               Case(Expr(5_i))));
+    WrapInFunction(block);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverControlBlockValidationTest, SwitchCaseAlias_Pass) {
-  // type MyInt = u32;
-  // var v: MyInt;
-  // switch(v){
-  //   default: {}
-  // }
+    // type MyInt = u32;
+    // var v: MyInt;
+    // switch(v){
+    //   default: {}
+    // }
 
-  auto* my_int = Alias("MyInt", ty.u32());
-  auto* var = Var("a", ty.Of(my_int), Expr(2u));
-  auto* block = Block(Decl(var),  //
-                      Switch("a", DefaultCase(Source{{12, 34}})));
+    auto* my_int = Alias("MyInt", ty.u32());
+    auto* var = Var("a", ty.Of(my_int), Expr(2_u));
+    auto* block = Block(Decl(var),  //
+                        Switch("a", DefaultCase(Source{{12, 34}})));
 
-  WrapInFunction(block);
+    WrapInFunction(block);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 }  // namespace
diff --git a/src/tint/resolver/dependency_graph.cc b/src/tint/resolver/dependency_graph.cc
index fd71ebe..0a9bdc0 100644
--- a/src/tint/resolver/dependency_graph.cc
+++ b/src/tint/resolver/dependency_graph.cc
@@ -40,48 +40,46 @@
 
 /// Dependency describes how one global depends on another global
 struct DependencyInfo {
-  /// The source of the symbol that forms the dependency
-  Source source;
-  /// A string describing how the dependency is referenced. e.g. 'calls'
-  const char* action = nullptr;
+    /// The source of the symbol that forms the dependency
+    Source source;
+    /// A string describing how the dependency is referenced. e.g. 'calls'
+    const char* action = nullptr;
 };
 
 /// DependencyEdge describes the two Globals used to define a dependency
 /// relationship.
 struct DependencyEdge {
-  /// The Global that depends on #to
-  const Global* from;
-  /// The Global that is depended on by #from
-  const Global* to;
+    /// The Global that depends on #to
+    const Global* from;
+    /// The Global that is depended on by #from
+    const Global* to;
 };
 
 /// DependencyEdgeCmp implements the contracts of std::equal_to<DependencyEdge>
 /// and std::hash<DependencyEdge>.
 struct DependencyEdgeCmp {
-  /// Equality operator
-  bool operator()(const DependencyEdge& lhs, const DependencyEdge& rhs) const {
-    return lhs.from == rhs.from && lhs.to == rhs.to;
-  }
-  /// Hashing operator
-  inline std::size_t operator()(const DependencyEdge& d) const {
-    return utils::Hash(d.from, d.to);
-  }
+    /// Equality operator
+    bool operator()(const DependencyEdge& lhs, const DependencyEdge& rhs) const {
+        return lhs.from == rhs.from && lhs.to == rhs.to;
+    }
+    /// Hashing operator
+    inline std::size_t operator()(const DependencyEdge& d) const {
+        return utils::Hash(d.from, d.to);
+    }
 };
 
 /// A map of DependencyEdge to DependencyInfo
-using DependencyEdges = std::unordered_map<DependencyEdge,
-                                           DependencyInfo,
-                                           DependencyEdgeCmp,
-                                           DependencyEdgeCmp>;
+using DependencyEdges =
+    std::unordered_map<DependencyEdge, DependencyInfo, DependencyEdgeCmp, DependencyEdgeCmp>;
 
 /// Global describes a module-scope variable, type or function.
 struct Global {
-  explicit Global(const ast::Node* n) : node(n) {}
+    explicit Global(const ast::Node* n) : node(n) {}
 
-  /// The declaration ast::Node
-  const ast::Node* node;
-  /// A list of dependencies that this global depends on
-  std::vector<Global*> deps;
+    /// The declaration ast::Node
+    const ast::Node* node;
+    /// A list of dependencies that this global depends on
+    std::vector<Global*> deps;
 };
 
 /// A map of global name to Global
@@ -89,638 +87,614 @@
 
 /// Raises an ICE that a global ast::Node type was not handled by this system.
 void UnhandledNode(diag::List& diagnostics, const ast::Node* node) {
-  TINT_ICE(Resolver, diagnostics)
-      << "unhandled node type: " << node->TypeInfo().name;
+    TINT_ICE(Resolver, diagnostics) << "unhandled node type: " << node->TypeInfo().name;
 }
 
 /// Raises an error diagnostic with the given message and source.
-void AddError(diag::List& diagnostics,
-              const std::string& msg,
-              const Source& source) {
-  diagnostics.add_error(diag::System::Resolver, msg, source);
+void AddError(diag::List& diagnostics, const std::string& msg, const Source& source) {
+    diagnostics.add_error(diag::System::Resolver, msg, source);
 }
 
 /// Raises a note diagnostic with the given message and source.
-void AddNote(diag::List& diagnostics,
-             const std::string& msg,
-             const Source& source) {
-  diagnostics.add_note(diag::System::Resolver, msg, source);
+void AddNote(diag::List& diagnostics, const std::string& msg, const Source& source) {
+    diagnostics.add_note(diag::System::Resolver, msg, source);
 }
 
 /// DependencyScanner is used to traverse a module to build the list of
 /// global-to-global dependencies.
 class DependencyScanner {
- public:
-  /// Constructor
-  /// @param syms the program symbol table
-  /// @param globals_by_name map of global symbol to Global pointer
-  /// @param diagnostics diagnostic messages, appended with any errors found
-  /// @param graph the dependency graph to populate with resolved symbols
-  /// @param edges the map of globals-to-global dependency edges, which will
-  /// be populated by calls to Scan()
-  DependencyScanner(const SymbolTable& syms,
-                    const GlobalMap& globals_by_name,
-                    diag::List& diagnostics,
-                    DependencyGraph& graph,
-                    DependencyEdges& edges)
-      : symbols_(syms),
-        globals_(globals_by_name),
-        diagnostics_(diagnostics),
-        graph_(graph),
-        dependency_edges_(edges) {
-    // Register all the globals at global-scope
-    for (auto it : globals_by_name) {
-      scope_stack_.Set(it.first, it.second->node);
+  public:
+    /// Constructor
+    /// @param syms the program symbol table
+    /// @param globals_by_name map of global symbol to Global pointer
+    /// @param diagnostics diagnostic messages, appended with any errors found
+    /// @param graph the dependency graph to populate with resolved symbols
+    /// @param edges the map of globals-to-global dependency edges, which will
+    /// be populated by calls to Scan()
+    DependencyScanner(const SymbolTable& syms,
+                      const GlobalMap& globals_by_name,
+                      diag::List& diagnostics,
+                      DependencyGraph& graph,
+                      DependencyEdges& edges)
+        : symbols_(syms),
+          globals_(globals_by_name),
+          diagnostics_(diagnostics),
+          graph_(graph),
+          dependency_edges_(edges) {
+        // Register all the globals at global-scope
+        for (auto it : globals_by_name) {
+            scope_stack_.Set(it.first, it.second->node);
+        }
     }
-  }
 
-  /// Walks the global declarations, resolving symbols, and determining the
-  /// dependencies of each global.
-  void Scan(Global* global) {
-    TINT_SCOPED_ASSIGNMENT(current_global_, global);
-    Switch(
-        global->node,
-        [&](const ast::Struct* str) {
-          Declare(str->name, str);
-          for (auto* member : str->members) {
-            TraverseType(member->type);
-          }
-        },
-        [&](const ast::Alias* alias) {
-          Declare(alias->name, alias);
-          TraverseType(alias->type);
-        },
-        [&](const ast::Function* func) {
-          Declare(func->symbol, func);
-          TraverseAttributes(func->attributes);
-          TraverseFunction(func);
-        },
-        [&](const ast::Variable* var) {
-          Declare(var->symbol, var);
-          TraverseType(var->type);
-          if (var->constructor) {
-            TraverseExpression(var->constructor);
-          }
-        },
-        [&](Default) { UnhandledNode(diagnostics_, global->node); });
-  }
-
- private:
-  /// Traverses the function, performing symbol resolution and determining
-  /// global dependencies.
-  void TraverseFunction(const ast::Function* func) {
-    // Perform symbol resolution on all the parameter types before registering
-    // the parameters themselves. This allows the case of declaring a parameter
-    // with the same identifier as its type.
-    for (auto* param : func->params) {
-      TraverseType(param->type);
+    /// Walks the global declarations, resolving symbols, and determining the
+    /// dependencies of each global.
+    void Scan(Global* global) {
+        TINT_SCOPED_ASSIGNMENT(current_global_, global);
+        Switch(
+            global->node,
+            [&](const ast::Struct* str) {
+                Declare(str->name, str);
+                for (auto* member : str->members) {
+                    TraverseType(member->type);
+                }
+            },
+            [&](const ast::Alias* alias) {
+                Declare(alias->name, alias);
+                TraverseType(alias->type);
+            },
+            [&](const ast::Function* func) {
+                Declare(func->symbol, func);
+                TraverseAttributes(func->attributes);
+                TraverseFunction(func);
+            },
+            [&](const ast::Variable* var) {
+                Declare(var->symbol, var);
+                TraverseType(var->type);
+                if (var->constructor) {
+                    TraverseExpression(var->constructor);
+                }
+            },
+            [&](const ast::Enable*) {
+                // Enable directives do not effect the dependency graph.
+            },
+            [&](Default) { UnhandledNode(diagnostics_, global->node); });
     }
-    // Resolve the return type
-    TraverseType(func->return_type);
 
-    // Push the scope stack for the parameters and function body.
-    scope_stack_.Push();
-    TINT_DEFER(scope_stack_.Pop());
+  private:
+    /// Traverses the function, performing symbol resolution and determining
+    /// global dependencies.
+    void TraverseFunction(const ast::Function* func) {
+        // Perform symbol resolution on all the parameter types before registering
+        // the parameters themselves. This allows the case of declaring a parameter
+        // with the same identifier as its type.
+        for (auto* param : func->params) {
+            TraverseType(param->type);
+        }
+        // Resolve the return type
+        TraverseType(func->return_type);
 
-    for (auto* param : func->params) {
-      if (auto* shadows = scope_stack_.Get(param->symbol)) {
-        graph_.shadows.emplace(param, shadows);
-      }
-      Declare(param->symbol, param);
-    }
-    if (func->body) {
-      TraverseStatements(func->body->statements);
-    }
-  }
+        // Push the scope stack for the parameters and function body.
+        scope_stack_.Push();
+        TINT_DEFER(scope_stack_.Pop());
 
-  /// Traverses the statements, performing symbol resolution and determining
-  /// global dependencies.
-  void TraverseStatements(const ast::StatementList& stmts) {
-    for (auto* s : stmts) {
-      TraverseStatement(s);
-    }
-  }
-
-  /// Traverses the statement, performing symbol resolution and determining
-  /// global dependencies.
-  void TraverseStatement(const ast::Statement* stmt) {
-    if (!stmt) {
-      return;
-    }
-    Switch(
-        stmt,  //
-        [&](const ast::AssignmentStatement* a) {
-          TraverseExpression(a->lhs);
-          TraverseExpression(a->rhs);
-        },
-        [&](const ast::BlockStatement* b) {
-          scope_stack_.Push();
-          TINT_DEFER(scope_stack_.Pop());
-          TraverseStatements(b->statements);
-        },
-        [&](const ast::CallStatement* r) {  //
-          TraverseExpression(r->expr);
-        },
-        [&](const ast::CompoundAssignmentStatement* a) {
-          TraverseExpression(a->lhs);
-          TraverseExpression(a->rhs);
-        },
-        [&](const ast::ForLoopStatement* l) {
-          scope_stack_.Push();
-          TINT_DEFER(scope_stack_.Pop());
-          TraverseStatement(l->initializer);
-          TraverseExpression(l->condition);
-          TraverseStatement(l->continuing);
-          TraverseStatement(l->body);
-        },
-        [&](const ast::IncrementDecrementStatement* i) {
-          TraverseExpression(i->lhs);
-        },
-        [&](const ast::LoopStatement* l) {
-          scope_stack_.Push();
-          TINT_DEFER(scope_stack_.Pop());
-          TraverseStatements(l->body->statements);
-          TraverseStatement(l->continuing);
-        },
-        [&](const ast::IfStatement* i) {
-          TraverseExpression(i->condition);
-          TraverseStatement(i->body);
-          for (auto* e : i->else_statements) {
-            TraverseExpression(e->condition);
-            TraverseStatement(e->body);
-          }
-        },
-        [&](const ast::ReturnStatement* r) {  //
-          TraverseExpression(r->value);
-        },
-        [&](const ast::SwitchStatement* s) {
-          TraverseExpression(s->condition);
-          for (auto* c : s->body) {
-            for (auto* sel : c->selectors) {
-              TraverseExpression(sel);
+        for (auto* param : func->params) {
+            if (auto* shadows = scope_stack_.Get(param->symbol)) {
+                graph_.shadows.emplace(param, shadows);
             }
-            TraverseStatement(c->body);
-          }
-        },
-        [&](const ast::VariableDeclStatement* v) {
-          if (auto* shadows = scope_stack_.Get(v->variable->symbol)) {
-            graph_.shadows.emplace(v->variable, shadows);
-          }
-          TraverseType(v->variable->type);
-          TraverseExpression(v->variable->constructor);
-          Declare(v->variable->symbol, v->variable);
-        },
-        [&](Default) {
-          if (!stmt->IsAnyOf<ast::BreakStatement, ast::ContinueStatement,
-                             ast::DiscardStatement,
-                             ast::FallthroughStatement>()) {
-            UnhandledNode(diagnostics_, stmt);
-          }
-        });
-  }
-
-  /// Adds the symbol definition to the current scope, raising an error if two
-  /// symbols collide within the same scope.
-  void Declare(Symbol symbol, const ast::Node* node) {
-    auto* old = scope_stack_.Set(symbol, node);
-    if (old != nullptr && node != old) {
-      auto name = symbols_.NameFor(symbol);
-      AddError(diagnostics_, "redeclaration of '" + name + "'", node->source);
-      AddNote(diagnostics_, "'" + name + "' previously declared here",
-              old->source);
+            Declare(param->symbol, param);
+        }
+        if (func->body) {
+            TraverseStatements(func->body->statements);
+        }
     }
-  }
 
-  /// Traverses the expression, performing symbol resolution and determining
-  /// global dependencies.
-  void TraverseExpression(const ast::Expression* root) {
-    if (!root) {
-      return;
+    /// Traverses the statements, performing symbol resolution and determining
+    /// global dependencies.
+    void TraverseStatements(const ast::StatementList& stmts) {
+        for (auto* s : stmts) {
+            TraverseStatement(s);
+        }
     }
-    ast::TraverseExpressions(
-        root, diagnostics_, [&](const ast::Expression* expr) {
-          Switch(
-              expr,
-              [&](const ast::IdentifierExpression* ident) {
-                AddDependency(ident, ident->symbol, "identifier", "references");
-              },
-              [&](const ast::CallExpression* call) {
-                if (call->target.name) {
-                  AddDependency(call->target.name, call->target.name->symbol,
-                                "function", "calls");
+
+    /// Traverses the statement, performing symbol resolution and determining
+    /// global dependencies.
+    void TraverseStatement(const ast::Statement* stmt) {
+        if (!stmt) {
+            return;
+        }
+        Switch(
+            stmt,  //
+            [&](const ast::AssignmentStatement* a) {
+                TraverseExpression(a->lhs);
+                TraverseExpression(a->rhs);
+            },
+            [&](const ast::BlockStatement* b) {
+                scope_stack_.Push();
+                TINT_DEFER(scope_stack_.Pop());
+                TraverseStatements(b->statements);
+            },
+            [&](const ast::CallStatement* r) {  //
+                TraverseExpression(r->expr);
+            },
+            [&](const ast::CompoundAssignmentStatement* a) {
+                TraverseExpression(a->lhs);
+                TraverseExpression(a->rhs);
+            },
+            [&](const ast::ForLoopStatement* l) {
+                scope_stack_.Push();
+                TINT_DEFER(scope_stack_.Pop());
+                TraverseStatement(l->initializer);
+                TraverseExpression(l->condition);
+                TraverseStatement(l->continuing);
+                TraverseStatement(l->body);
+            },
+            [&](const ast::IncrementDecrementStatement* i) { TraverseExpression(i->lhs); },
+            [&](const ast::LoopStatement* l) {
+                scope_stack_.Push();
+                TINT_DEFER(scope_stack_.Pop());
+                TraverseStatements(l->body->statements);
+                TraverseStatement(l->continuing);
+            },
+            [&](const ast::IfStatement* i) {
+                TraverseExpression(i->condition);
+                TraverseStatement(i->body);
+                if (i->else_statement) {
+                    TraverseStatement(i->else_statement);
                 }
-                if (call->target.type) {
-                  TraverseType(call->target.type);
+            },
+            [&](const ast::ReturnStatement* r) {  //
+                TraverseExpression(r->value);
+            },
+            [&](const ast::SwitchStatement* s) {
+                TraverseExpression(s->condition);
+                for (auto* c : s->body) {
+                    for (auto* sel : c->selectors) {
+                        TraverseExpression(sel);
+                    }
+                    TraverseStatement(c->body);
                 }
-              },
-              [&](const ast::BitcastExpression* cast) {
-                TraverseType(cast->type);
-              });
-          return ast::TraverseAction::Descend;
+            },
+            [&](const ast::VariableDeclStatement* v) {
+                if (auto* shadows = scope_stack_.Get(v->variable->symbol)) {
+                    graph_.shadows.emplace(v->variable, shadows);
+                }
+                TraverseType(v->variable->type);
+                TraverseExpression(v->variable->constructor);
+                Declare(v->variable->symbol, v->variable);
+            },
+            [&](Default) {
+                if (!stmt->IsAnyOf<ast::BreakStatement, ast::ContinueStatement,
+                                   ast::DiscardStatement, ast::FallthroughStatement>()) {
+                    UnhandledNode(diagnostics_, stmt);
+                }
+            });
+    }
+
+    /// Adds the symbol definition to the current scope, raising an error if two
+    /// symbols collide within the same scope.
+    void Declare(Symbol symbol, const ast::Node* node) {
+        auto* old = scope_stack_.Set(symbol, node);
+        if (old != nullptr && node != old) {
+            auto name = symbols_.NameFor(symbol);
+            AddError(diagnostics_, "redeclaration of '" + name + "'", node->source);
+            AddNote(diagnostics_, "'" + name + "' previously declared here", old->source);
+        }
+    }
+
+    /// Traverses the expression, performing symbol resolution and determining
+    /// global dependencies.
+    void TraverseExpression(const ast::Expression* root) {
+        if (!root) {
+            return;
+        }
+        ast::TraverseExpressions(root, diagnostics_, [&](const ast::Expression* expr) {
+            Switch(
+                expr,
+                [&](const ast::IdentifierExpression* ident) {
+                    AddDependency(ident, ident->symbol, "identifier", "references");
+                },
+                [&](const ast::CallExpression* call) {
+                    if (call->target.name) {
+                        AddDependency(call->target.name, call->target.name->symbol, "function",
+                                      "calls");
+                    }
+                    if (call->target.type) {
+                        TraverseType(call->target.type);
+                    }
+                },
+                [&](const ast::BitcastExpression* cast) { TraverseType(cast->type); });
+            return ast::TraverseAction::Descend;
         });
-  }
-
-  /// Traverses the type node, performing symbol resolution and determining
-  /// global dependencies.
-  void TraverseType(const ast::Type* ty) {
-    if (!ty) {
-      return;
-    }
-    Switch(
-        ty,  //
-        [&](const ast::Array* arr) {
-          TraverseType(arr->type);  //
-          TraverseExpression(arr->count);
-        },
-        [&](const ast::Atomic* atomic) {  //
-          TraverseType(atomic->type);
-        },
-        [&](const ast::Matrix* mat) {  //
-          TraverseType(mat->type);
-        },
-        [&](const ast::Pointer* ptr) {  //
-          TraverseType(ptr->type);
-        },
-        [&](const ast::TypeName* tn) {  //
-          AddDependency(tn, tn->name, "type", "references");
-        },
-        [&](const ast::Vector* vec) {  //
-          TraverseType(vec->type);
-        },
-        [&](const ast::SampledTexture* tex) {  //
-          TraverseType(tex->type);
-        },
-        [&](const ast::MultisampledTexture* tex) {  //
-          TraverseType(tex->type);
-        },
-        [&](Default) {
-          if (!ty->IsAnyOf<ast::Void, ast::Bool, ast::I32, ast::U32, ast::F32,
-                           ast::DepthTexture, ast::DepthMultisampledTexture,
-                           ast::StorageTexture, ast::ExternalTexture,
-                           ast::Sampler>()) {
-            UnhandledNode(diagnostics_, ty);
-          }
-        });
-  }
-
-  /// Traverses the attribute list, performing symbol resolution and
-  /// determining global dependencies.
-  void TraverseAttributes(const ast::AttributeList& attrs) {
-    for (auto* attr : attrs) {
-      TraverseAttribute(attr);
-    }
-  }
-
-  /// Traverses the attribute, performing symbol resolution and determining
-  /// global dependencies.
-  void TraverseAttribute(const ast::Attribute* attr) {
-    if (auto* wg = attr->As<ast::WorkgroupAttribute>()) {
-      TraverseExpression(wg->x);
-      TraverseExpression(wg->y);
-      TraverseExpression(wg->z);
-      return;
-    }
-    if (attr->IsAnyOf<
-            ast::BindingAttribute, ast::BuiltinAttribute, ast::GroupAttribute,
-            ast::IdAttribute, ast::InternalAttribute, ast::InterpolateAttribute,
-            ast::InvariantAttribute, ast::LocationAttribute,
-            ast::StageAttribute, ast::StrideAttribute,
-            ast::StructMemberAlignAttribute, ast::StructMemberOffsetAttribute,
-            ast::StructMemberSizeAttribute>()) {
-      return;
     }
 
-    UnhandledNode(diagnostics_, attr);
-  }
-
-  /// Adds the dependency from `from` to `to`, erroring if `to` cannot be
-  /// resolved.
-  void AddDependency(const ast::Node* from,
-                     Symbol to,
-                     const char* use,
-                     const char* action) {
-    auto* resolved = scope_stack_.Get(to);
-    if (!resolved) {
-      if (!IsBuiltin(to)) {
-        UnknownSymbol(to, from->source, use);
-        return;
-      }
+    /// Traverses the type node, performing symbol resolution and determining
+    /// global dependencies.
+    void TraverseType(const ast::Type* ty) {
+        if (!ty) {
+            return;
+        }
+        Switch(
+            ty,  //
+            [&](const ast::Array* arr) {
+                TraverseType(arr->type);  //
+                TraverseExpression(arr->count);
+            },
+            [&](const ast::Atomic* atomic) {  //
+                TraverseType(atomic->type);
+            },
+            [&](const ast::Matrix* mat) {  //
+                TraverseType(mat->type);
+            },
+            [&](const ast::Pointer* ptr) {  //
+                TraverseType(ptr->type);
+            },
+            [&](const ast::TypeName* tn) {  //
+                AddDependency(tn, tn->name, "type", "references");
+            },
+            [&](const ast::Vector* vec) {  //
+                TraverseType(vec->type);
+            },
+            [&](const ast::SampledTexture* tex) {  //
+                TraverseType(tex->type);
+            },
+            [&](const ast::MultisampledTexture* tex) {  //
+                TraverseType(tex->type);
+            },
+            [&](Default) {
+                if (!ty->IsAnyOf<ast::Void, ast::Bool, ast::I32, ast::U32, ast::F32,
+                                 ast::DepthTexture, ast::DepthMultisampledTexture,
+                                 ast::StorageTexture, ast::ExternalTexture, ast::Sampler>()) {
+                    UnhandledNode(diagnostics_, ty);
+                }
+            });
     }
 
-    if (auto* global = utils::Lookup(globals_, to);
-        global && global->node == resolved) {
-      if (dependency_edges_
-              .emplace(DependencyEdge{current_global_, global},
-                       DependencyInfo{from->source, action})
-              .second) {
-        current_global_->deps.emplace_back(global);
-      }
+    /// Traverses the attribute list, performing symbol resolution and
+    /// determining global dependencies.
+    void TraverseAttributes(const ast::AttributeList& attrs) {
+        for (auto* attr : attrs) {
+            TraverseAttribute(attr);
+        }
     }
 
-    graph_.resolved_symbols.emplace(from, resolved);
-  }
+    /// Traverses the attribute, performing symbol resolution and determining
+    /// global dependencies.
+    void TraverseAttribute(const ast::Attribute* attr) {
+        if (auto* wg = attr->As<ast::WorkgroupAttribute>()) {
+            TraverseExpression(wg->x);
+            TraverseExpression(wg->y);
+            TraverseExpression(wg->z);
+            return;
+        }
+        if (attr->IsAnyOf<ast::BindingAttribute, ast::BuiltinAttribute, ast::GroupAttribute,
+                          ast::IdAttribute, ast::InternalAttribute, ast::InterpolateAttribute,
+                          ast::InvariantAttribute, ast::LocationAttribute, ast::StageAttribute,
+                          ast::StrideAttribute, ast::StructMemberAlignAttribute,
+                          ast::StructMemberOffsetAttribute, ast::StructMemberSizeAttribute>()) {
+            return;
+        }
 
-  /// @returns true if `name` is the name of a builtin function
-  bool IsBuiltin(Symbol name) const {
-    return sem::ParseBuiltinType(symbols_.NameFor(name)) !=
-           sem::BuiltinType::kNone;
-  }
+        UnhandledNode(diagnostics_, attr);
+    }
 
-  /// Appends an error to the diagnostics that the given symbol cannot be
-  /// resolved.
-  void UnknownSymbol(Symbol name, Source source, const char* use) {
-    AddError(
-        diagnostics_,
-        "unknown " + std::string(use) + ": '" + symbols_.NameFor(name) + "'",
-        source);
-  }
+    /// Adds the dependency from `from` to `to`, erroring if `to` cannot be
+    /// resolved.
+    void AddDependency(const ast::Node* from, Symbol to, const char* use, const char* action) {
+        auto* resolved = scope_stack_.Get(to);
+        if (!resolved) {
+            if (!IsBuiltin(to)) {
+                UnknownSymbol(to, from->source, use);
+                return;
+            }
+        }
 
-  using VariableMap = std::unordered_map<Symbol, const ast::Variable*>;
-  const SymbolTable& symbols_;
-  const GlobalMap& globals_;
-  diag::List& diagnostics_;
-  DependencyGraph& graph_;
-  DependencyEdges& dependency_edges_;
+        if (auto* global = utils::Lookup(globals_, to); global && global->node == resolved) {
+            if (dependency_edges_
+                    .emplace(DependencyEdge{current_global_, global},
+                             DependencyInfo{from->source, action})
+                    .second) {
+                current_global_->deps.emplace_back(global);
+            }
+        }
 
-  ScopeStack<const ast::Node*> scope_stack_;
-  Global* current_global_ = nullptr;
+        graph_.resolved_symbols.emplace(from, resolved);
+    }
+
+    /// @returns true if `name` is the name of a builtin function
+    bool IsBuiltin(Symbol name) const {
+        return sem::ParseBuiltinType(symbols_.NameFor(name)) != sem::BuiltinType::kNone;
+    }
+
+    /// Appends an error to the diagnostics that the given symbol cannot be
+    /// resolved.
+    void UnknownSymbol(Symbol name, Source source, const char* use) {
+        AddError(diagnostics_, "unknown " + std::string(use) + ": '" + symbols_.NameFor(name) + "'",
+                 source);
+    }
+
+    using VariableMap = std::unordered_map<Symbol, const ast::Variable*>;
+    const SymbolTable& symbols_;
+    const GlobalMap& globals_;
+    diag::List& diagnostics_;
+    DependencyGraph& graph_;
+    DependencyEdges& dependency_edges_;
+
+    ScopeStack<const ast::Node*> scope_stack_;
+    Global* current_global_ = nullptr;
 };
 
 /// The global dependency analysis system
 struct DependencyAnalysis {
- public:
-  /// Constructor
-  DependencyAnalysis(const SymbolTable& symbols,
-                     diag::List& diagnostics,
-                     DependencyGraph& graph)
-      : symbols_(symbols), diagnostics_(diagnostics), graph_(graph) {}
+  public:
+    /// Constructor
+    DependencyAnalysis(const SymbolTable& symbols, diag::List& diagnostics, DependencyGraph& graph)
+        : symbols_(symbols), diagnostics_(diagnostics), graph_(graph) {}
 
-  /// Performs global dependency analysis on the module, emitting any errors to
-  /// #diagnostics.
-  /// @returns true if analysis found no errors, otherwise false.
-  bool Run(const ast::Module& module) {
-    // Collect all the named globals from the AST module
-    GatherGlobals(module);
+    /// Performs global dependency analysis on the module, emitting any errors to
+    /// #diagnostics.
+    /// @returns true if analysis found no errors, otherwise false.
+    bool Run(const ast::Module& module) {
+        // Collect all the named globals from the AST module
+        GatherGlobals(module);
 
-    // Traverse the named globals to build the dependency graph
-    DetermineDependencies();
+        // Traverse the named globals to build the dependency graph
+        DetermineDependencies();
 
-    // Sort the globals into dependency order
-    SortGlobals();
+        // Sort the globals into dependency order
+        SortGlobals();
 
-    // Dump the dependency graph if TINT_DUMP_DEPENDENCY_GRAPH is non-zero
-    DumpDependencyGraph();
+        // Dump the dependency graph if TINT_DUMP_DEPENDENCY_GRAPH is non-zero
+        DumpDependencyGraph();
 
-    graph_.ordered_globals = std::move(sorted_);
+        graph_.ordered_globals = std::move(sorted_);
 
-    return !diagnostics_.contains_errors();
-  }
-
- private:
-  /// @param node the ast::Node of the global declaration
-  /// @returns the symbol of the global declaration node
-  /// @note will raise an ICE if the node is not a type, function or variable
-  /// declaration
-  Symbol SymbolOf(const ast::Node* node) const {
-    return Switch(
-        node,  //
-        [&](const ast::TypeDecl* td) { return td->name; },
-        [&](const ast::Function* func) { return func->symbol; },
-        [&](const ast::Variable* var) { return var->symbol; },
-        [&](Default) {
-          UnhandledNode(diagnostics_, node);
-          return Symbol{};
-        });
-  }
-
-  /// @param node the ast::Node of the global declaration
-  /// @returns the name of the global declaration node
-  /// @note will raise an ICE if the node is not a type, function or variable
-  /// declaration
-  std::string NameOf(const ast::Node* node) const {
-    return symbols_.NameFor(SymbolOf(node));
-  }
-
-  /// @param node the ast::Node of the global declaration
-  /// @returns a string representation of the global declaration kind
-  /// @note will raise an ICE if the node is not a type, function or variable
-  /// declaration
-  std::string KindOf(const ast::Node* node) {
-    return Switch(
-        node,  //
-        [&](const ast::Struct*) { return "struct"; },
-        [&](const ast::Alias*) { return "alias"; },
-        [&](const ast::Function*) { return "function"; },
-        [&](const ast::Variable* var) { return var->is_const ? "let" : "var"; },
-        [&](Default) {
-          UnhandledNode(diagnostics_, node);
-          return "<error>";
-        });
-  }
-
-  /// Traverses `module`, collecting all the global declarations and populating
-  /// the #globals and #declaration_order fields.
-  void GatherGlobals(const ast::Module& module) {
-    for (auto* node : module.GlobalDeclarations()) {
-      auto* global = allocator_.Create(node);
-      globals_.emplace(SymbolOf(node), global);
-      declaration_order_.emplace_back(global);
-    }
-  }
-
-  /// Walks the global declarations, determining the dependencies of each global
-  /// and adding these to each global's Global::deps field.
-  void DetermineDependencies() {
-    DependencyScanner scanner(symbols_, globals_, diagnostics_, graph_,
-                              dependency_edges_);
-    for (auto* global : declaration_order_) {
-      scanner.Scan(global);
-    }
-  }
-
-  /// Performs a depth-first traversal of `root`'s dependencies, calling `enter`
-  /// as the function decends into each dependency and `exit` when bubbling back
-  /// up towards the root.
-  /// @param enter is a function with the signature: `bool(Global*)`. The
-  /// `enter` function returns true if TraverseDependencies() should traverse
-  /// the dependency, otherwise it will be skipped.
-  /// @param exit is a function with the signature: `void(Global*)`. The `exit`
-  /// function is only called if the corresponding `enter` call returned true.
-  template <typename ENTER, typename EXIT>
-  void TraverseDependencies(const Global* root, ENTER&& enter, EXIT&& exit) {
-    // Entry is a single entry in the traversal stack. Entry points to a
-    // dep_idx'th dependency of Entry::global.
-    struct Entry {
-      const Global* global;  // The parent global
-      size_t dep_idx;        // The dependency index in `global->deps`
-    };
-
-    if (!enter(root)) {
-      return;
+        return !diagnostics_.contains_errors();
     }
 
-    std::vector<Entry> stack{Entry{root, 0}};
-    while (true) {
-      auto& entry = stack.back();
-      // Have we exhausted the dependencies of entry.global?
-      if (entry.dep_idx < entry.global->deps.size()) {
-        // No, there's more dependencies to traverse.
-        auto& dep = entry.global->deps[entry.dep_idx];
-        // Does the caller want to enter this dependency?
-        if (enter(dep)) {                  // Yes.
-          stack.push_back(Entry{dep, 0});  // Enter the dependency.
-        } else {
-          entry.dep_idx++;  // No. Skip this node.
-        }
-      } else {
-        // Yes. Time to back up.
-        // Exit this global, pop the stack, and if there's another parent node,
-        // increment its dependency index, and loop again.
-        exit(entry.global);
-        stack.pop_back();
-        if (stack.empty()) {
-          return;  // All done.
-        }
-        stack.back().dep_idx++;
-      }
-    }
-  }
-
-  /// SortGlobals sorts the globals into dependency order, erroring if cyclic
-  /// dependencies are found. The sorted dependencies are assigned to #sorted.
-  void SortGlobals() {
-    if (diagnostics_.contains_errors()) {
-      return;  // This code assumes there are no undeclared identifiers.
+  private:
+    /// @param node the ast::Node of the global declaration
+    /// @returns the symbol of the global declaration node
+    /// @note will raise an ICE if the node is not a type, function or variable
+    /// declaration
+    Symbol SymbolOf(const ast::Node* node) const {
+        return Switch(
+            node,  //
+            [&](const ast::TypeDecl* td) { return td->name; },
+            [&](const ast::Function* func) { return func->symbol; },
+            [&](const ast::Variable* var) { return var->symbol; },
+            [&](Default) {
+                UnhandledNode(diagnostics_, node);
+                return Symbol{};
+            });
     }
 
-    std::unordered_set<const Global*> visited;
-    for (auto* global : declaration_order_) {
-      utils::UniqueVector<const Global*> stack;
-      TraverseDependencies(
-          global,
-          [&](const Global* g) {  // Enter
-            if (!stack.add(g)) {
-              CyclicDependencyFound(g, stack);
-              return false;
+    /// @param node the ast::Node of the global declaration
+    /// @returns the name of the global declaration node
+    /// @note will raise an ICE if the node is not a type, function or variable
+    /// declaration
+    std::string NameOf(const ast::Node* node) const { return symbols_.NameFor(SymbolOf(node)); }
+
+    /// @param node the ast::Node of the global declaration
+    /// @returns a string representation of the global declaration kind
+    /// @note will raise an ICE if the node is not a type, function or variable
+    /// declaration
+    std::string KindOf(const ast::Node* node) {
+        return Switch(
+            node,  //
+            [&](const ast::Struct*) { return "struct"; },
+            [&](const ast::Alias*) { return "alias"; },
+            [&](const ast::Function*) { return "function"; },
+            [&](const ast::Variable* var) { return var->is_const ? "let" : "var"; },
+            [&](Default) {
+                UnhandledNode(diagnostics_, node);
+                return "<error>";
+            });
+    }
+
+    /// Traverses `module`, collecting all the global declarations and populating
+    /// the #globals and #declaration_order fields.
+    void GatherGlobals(const ast::Module& module) {
+        for (auto* node : module.GlobalDeclarations()) {
+            auto* global = allocator_.Create(node);
+            // Enable directives do not form a symbol. Skip them.
+            if (!node->Is<ast::Enable>()) {
+                globals_.emplace(SymbolOf(node), global);
             }
-            if (sorted_.contains(g->node)) {
-              // Visited this global already.
-              // stack was pushed, but exit() will not be called when we return
-              // false, so pop here.
-              stack.pop_back();
-              return false;
+            declaration_order_.emplace_back(global);
+        }
+    }
+
+    /// Walks the global declarations, determining the dependencies of each global
+    /// and adding these to each global's Global::deps field.
+    void DetermineDependencies() {
+        DependencyScanner scanner(symbols_, globals_, diagnostics_, graph_, dependency_edges_);
+        for (auto* global : declaration_order_) {
+            scanner.Scan(global);
+        }
+    }
+
+    /// Performs a depth-first traversal of `root`'s dependencies, calling `enter`
+    /// as the function decends into each dependency and `exit` when bubbling back
+    /// up towards the root.
+    /// @param enter is a function with the signature: `bool(Global*)`. The
+    /// `enter` function returns true if TraverseDependencies() should traverse
+    /// the dependency, otherwise it will be skipped.
+    /// @param exit is a function with the signature: `void(Global*)`. The `exit`
+    /// function is only called if the corresponding `enter` call returned true.
+    template <typename ENTER, typename EXIT>
+    void TraverseDependencies(const Global* root, ENTER&& enter, EXIT&& exit) {
+        // Entry is a single entry in the traversal stack. Entry points to a
+        // dep_idx'th dependency of Entry::global.
+        struct Entry {
+            const Global* global;  // The parent global
+            size_t dep_idx;        // The dependency index in `global->deps`
+        };
+
+        if (!enter(root)) {
+            return;
+        }
+
+        std::vector<Entry> stack{Entry{root, 0}};
+        while (true) {
+            auto& entry = stack.back();
+            // Have we exhausted the dependencies of entry.global?
+            if (entry.dep_idx < entry.global->deps.size()) {
+                // No, there's more dependencies to traverse.
+                auto& dep = entry.global->deps[entry.dep_idx];
+                // Does the caller want to enter this dependency?
+                if (enter(dep)) {                    // Yes.
+                    stack.push_back(Entry{dep, 0});  // Enter the dependency.
+                } else {
+                    entry.dep_idx++;  // No. Skip this node.
+                }
+            } else {
+                // Yes. Time to back up.
+                // Exit this global, pop the stack, and if there's another parent node,
+                // increment its dependency index, and loop again.
+                exit(entry.global);
+                stack.pop_back();
+                if (stack.empty()) {
+                    return;  // All done.
+                }
+                stack.back().dep_idx++;
             }
-            return true;
-          },
-          [&](const Global* g) {  // Exit. Only called if Enter returned true.
-            sorted_.add(g->node);
-            stack.pop_back();
-          });
+        }
+    }
 
-      sorted_.add(global->node);
+    /// SortGlobals sorts the globals into dependency order, erroring if cyclic
+    /// dependencies are found. The sorted dependencies are assigned to #sorted.
+    void SortGlobals() {
+        if (diagnostics_.contains_errors()) {
+            return;  // This code assumes there are no undeclared identifiers.
+        }
 
-      if (!stack.empty()) {
-        // Each stack.push() must have a corresponding stack.pop_back().
+        std::unordered_set<const Global*> visited;
+        for (auto* global : declaration_order_) {
+            utils::UniqueVector<const Global*> stack;
+            TraverseDependencies(
+                global,
+                [&](const Global* g) {  // Enter
+                    if (!stack.add(g)) {
+                        CyclicDependencyFound(g, stack);
+                        return false;
+                    }
+                    if (sorted_.contains(g->node)) {
+                        // Visited this global already.
+                        // stack was pushed, but exit() will not be called when we return
+                        // false, so pop here.
+                        stack.pop_back();
+                        return false;
+                    }
+                    return true;
+                },
+                [&](const Global* g) {  // Exit. Only called if Enter returned true.
+                    sorted_.add(g->node);
+                    stack.pop_back();
+                });
+
+            sorted_.add(global->node);
+
+            if (!stack.empty()) {
+                // Each stack.push() must have a corresponding stack.pop_back().
+                TINT_ICE(Resolver, diagnostics_)
+                    << "stack not empty after returning from TraverseDependencies()";
+            }
+        }
+    }
+
+    /// DepInfoFor() looks up the global dependency information for the dependency
+    /// of global `from` depending on `to`.
+    /// @note will raise an ICE if the edge is not found.
+    DependencyInfo DepInfoFor(const Global* from, const Global* to) const {
+        auto it = dependency_edges_.find(DependencyEdge{from, to});
+        if (it != dependency_edges_.end()) {
+            return it->second;
+        }
         TINT_ICE(Resolver, diagnostics_)
-            << "stack not empty after returning from TraverseDependencies()";
-      }
+            << "failed to find dependency info for edge: '" << NameOf(from->node) << "' -> '"
+            << NameOf(to->node) << "'";
+        return {};
     }
-  }
 
-  /// DepInfoFor() looks up the global dependency information for the dependency
-  /// of global `from` depending on `to`.
-  /// @note will raise an ICE if the edge is not found.
-  DependencyInfo DepInfoFor(const Global* from, const Global* to) const {
-    auto it = dependency_edges_.find(DependencyEdge{from, to});
-    if (it != dependency_edges_.end()) {
-      return it->second;
+    /// CyclicDependencyFound() emits an error diagnostic for a cyclic dependency.
+    /// @param root is the global that starts the cyclic dependency, which must be
+    /// found in `stack`.
+    /// @param stack is the global dependency stack that contains a loop.
+    void CyclicDependencyFound(const Global* root, const std::vector<const Global*>& stack) {
+        std::stringstream msg;
+        msg << "cyclic dependency found: ";
+        constexpr size_t kLoopNotStarted = ~0u;
+        size_t loop_start = kLoopNotStarted;
+        for (size_t i = 0; i < stack.size(); i++) {
+            auto* e = stack[i];
+            if (loop_start == kLoopNotStarted && e == root) {
+                loop_start = i;
+            }
+            if (loop_start != kLoopNotStarted) {
+                msg << "'" << NameOf(e->node) << "' -> ";
+            }
+        }
+        msg << "'" << NameOf(root->node) << "'";
+        AddError(diagnostics_, msg.str(), root->node->source);
+        for (size_t i = loop_start; i < stack.size(); i++) {
+            auto* from = stack[i];
+            auto* to = (i + 1 < stack.size()) ? stack[i + 1] : stack[loop_start];
+            auto info = DepInfoFor(from, to);
+            AddNote(diagnostics_,
+                    KindOf(from->node) + " '" + NameOf(from->node) + "' " + info.action + " " +
+                        KindOf(to->node) + " '" + NameOf(to->node) + "' here",
+                    info.source);
+        }
     }
-    TINT_ICE(Resolver, diagnostics_)
-        << "failed to find dependency info for edge: '" << NameOf(from->node)
-        << "' -> '" << NameOf(to->node) << "'";
-    return {};
-  }
 
-  /// CyclicDependencyFound() emits an error diagnostic for a cyclic dependency.
-  /// @param root is the global that starts the cyclic dependency, which must be
-  /// found in `stack`.
-  /// @param stack is the global dependency stack that contains a loop.
-  void CyclicDependencyFound(const Global* root,
-                             const std::vector<const Global*>& stack) {
-    std::stringstream msg;
-    msg << "cyclic dependency found: ";
-    constexpr size_t kLoopNotStarted = ~0u;
-    size_t loop_start = kLoopNotStarted;
-    for (size_t i = 0; i < stack.size(); i++) {
-      auto* e = stack[i];
-      if (loop_start == kLoopNotStarted && e == root) {
-        loop_start = i;
-      }
-      if (loop_start != kLoopNotStarted) {
-        msg << "'" << NameOf(e->node) << "' -> ";
-      }
-    }
-    msg << "'" << NameOf(root->node) << "'";
-    AddError(diagnostics_, msg.str(), root->node->source);
-    for (size_t i = loop_start; i < stack.size(); i++) {
-      auto* from = stack[i];
-      auto* to = (i + 1 < stack.size()) ? stack[i + 1] : stack[loop_start];
-      auto info = DepInfoFor(from, to);
-      AddNote(diagnostics_,
-              KindOf(from->node) + " '" + NameOf(from->node) + "' " +
-                  info.action + " " + KindOf(to->node) + " '" +
-                  NameOf(to->node) + "' here",
-              info.source);
-    }
-  }
-
-  void DumpDependencyGraph() {
+    void DumpDependencyGraph() {
 #if TINT_DUMP_DEPENDENCY_GRAPH == 0
-    if ((true)) {
-      return;
-    }
+        if ((true)) {
+            return;
+        }
 #endif  // TINT_DUMP_DEPENDENCY_GRAPH
-    printf("=========================\n");
-    printf("------ declaration ------ \n");
-    for (auto* global : declaration_order_) {
-      printf("%s\n", NameOf(global->node).c_str());
+        printf("=========================\n");
+        printf("------ declaration ------ \n");
+        for (auto* global : declaration_order_) {
+            printf("%s\n", NameOf(global->node).c_str());
+        }
+        printf("------ dependencies ------ \n");
+        for (auto* node : sorted_) {
+            auto symbol = SymbolOf(node);
+            auto* global = globals_.at(symbol);
+            printf("%s depends on:\n", symbols_.NameFor(symbol).c_str());
+            for (auto* dep : global->deps) {
+                printf("  %s\n", NameOf(dep->node).c_str());
+            }
+        }
+        printf("=========================\n");
     }
-    printf("------ dependencies ------ \n");
-    for (auto* node : sorted_) {
-      auto symbol = SymbolOf(node);
-      auto* global = globals_.at(symbol);
-      printf("%s depends on:\n", symbols_.NameFor(symbol).c_str());
-      for (auto* dep : global->deps) {
-        printf("  %s\n", NameOf(dep->node).c_str());
-      }
-    }
-    printf("=========================\n");
-  }
 
-  /// Program symbols
-  const SymbolTable& symbols_;
+    /// Program symbols
+    const SymbolTable& symbols_;
 
-  /// Program diagnostics
-  diag::List& diagnostics_;
+    /// Program diagnostics
+    diag::List& diagnostics_;
 
-  /// The resulting dependency graph
-  DependencyGraph& graph_;
+    /// The resulting dependency graph
+    DependencyGraph& graph_;
 
-  /// Allocator of Globals
-  utils::BlockAllocator<Global> allocator_;
+    /// Allocator of Globals
+    utils::BlockAllocator<Global> allocator_;
 
-  /// Global map, keyed by name. Populated by GatherGlobals().
-  GlobalMap globals_;
+    /// Global map, keyed by name. Populated by GatherGlobals().
+    GlobalMap globals_;
 
-  /// Map of DependencyEdge to DependencyInfo. Populated by
-  /// DetermineDependencies().
-  DependencyEdges dependency_edges_;
+    /// Map of DependencyEdge to DependencyInfo. Populated by
+    /// DetermineDependencies().
+    DependencyEdges dependency_edges_;
 
-  /// Globals in declaration order. Populated by GatherGlobals().
-  std::vector<Global*> declaration_order_;
+    /// Globals in declaration order. Populated by GatherGlobals().
+    std::vector<Global*> declaration_order_;
 
-  /// Globals in sorted dependency order. Populated by SortGlobals().
-  utils::UniqueVector<const ast::Node*> sorted_;
+    /// Globals in sorted dependency order. Populated by SortGlobals().
+    utils::UniqueVector<const ast::Node*> sorted_;
 };
 
 }  // namespace
@@ -733,8 +707,8 @@
                             const SymbolTable& symbols,
                             diag::List& diagnostics,
                             DependencyGraph& output) {
-  DependencyAnalysis da{symbols, diagnostics, output};
-  return da.Run(module);
+    DependencyAnalysis da{symbols, diagnostics, output};
+    return da.Run(module);
 }
 
 }  // namespace tint::resolver
diff --git a/src/tint/resolver/dependency_graph.h b/src/tint/resolver/dependency_graph.h
index e8042f1..0554817 100644
--- a/src/tint/resolver/dependency_graph.h
+++ b/src/tint/resolver/dependency_graph.h
@@ -26,37 +26,37 @@
 /// DependencyGraph holds information about module-scope declaration dependency
 /// analysis and symbol resolutions.
 struct DependencyGraph {
-  /// Constructor
-  DependencyGraph();
-  /// Move-constructor
-  DependencyGraph(DependencyGraph&&);
-  /// Destructor
-  ~DependencyGraph();
+    /// Constructor
+    DependencyGraph();
+    /// Move-constructor
+    DependencyGraph(DependencyGraph&&);
+    /// Destructor
+    ~DependencyGraph();
 
-  /// Build() performs symbol resolution and dependency analysis on `module`,
-  /// populating `output` with the resulting dependency graph.
-  /// @param module the AST module to analyse
-  /// @param symbols the symbol table
-  /// @param diagnostics the diagnostic list to populate with errors / warnings
-  /// @param output the resulting DependencyGraph
-  /// @returns true on success, false on error
-  static bool Build(const ast::Module& module,
-                    const SymbolTable& symbols,
-                    diag::List& diagnostics,
-                    DependencyGraph& output);
+    /// Build() performs symbol resolution and dependency analysis on `module`,
+    /// populating `output` with the resulting dependency graph.
+    /// @param module the AST module to analyse
+    /// @param symbols the symbol table
+    /// @param diagnostics the diagnostic list to populate with errors / warnings
+    /// @param output the resulting DependencyGraph
+    /// @returns true on success, false on error
+    static bool Build(const ast::Module& module,
+                      const SymbolTable& symbols,
+                      diag::List& diagnostics,
+                      DependencyGraph& output);
 
-  /// All globals in dependency-sorted order.
-  std::vector<const ast::Node*> ordered_globals;
+    /// All globals in dependency-sorted order.
+    std::vector<const ast::Node*> ordered_globals;
 
-  /// Map of ast::IdentifierExpression or ast::TypeName to a type, function, or
-  /// variable that declares the symbol.
-  std::unordered_map<const ast::Node*, const ast::Node*> resolved_symbols;
+    /// Map of ast::IdentifierExpression or ast::TypeName to a type, function, or
+    /// variable that declares the symbol.
+    std::unordered_map<const ast::Node*, const ast::Node*> resolved_symbols;
 
-  /// Map of ast::Variable to a type, function, or variable that is shadowed by
-  /// the variable key. A declaration (X) shadows another (Y) if X and Y use
-  /// the same symbol, and X is declared in a sub-scope of the scope that
-  /// declares Y.
-  std::unordered_map<const ast::Variable*, const ast::Node*> shadows;
+    /// Map of ast::Variable to a type, function, or variable that is shadowed by
+    /// the variable key. A declaration (X) shadows another (Y) if X and Y use
+    /// the same symbol, and X is declared in a sub-scope of the scope that
+    /// declares Y.
+    std::unordered_map<const ast::Variable*, const ast::Node*> shadows;
 };
 
 }  // namespace tint::resolver
diff --git a/src/tint/resolver/dependency_graph_test.cc b/src/tint/resolver/dependency_graph_test.cc
index 606fc59..248dc87 100644
--- a/src/tint/resolver/dependency_graph_test.cc
+++ b/src/tint/resolver/dependency_graph_test.cc
@@ -20,6 +20,8 @@
 #include "src/tint/resolver/dependency_graph.h"
 #include "src/tint/resolver/resolver_test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::resolver {
 namespace {
 
@@ -27,23 +29,22 @@
 
 template <typename T>
 class ResolverDependencyGraphTestWithParam : public ResolverTestWithParam<T> {
- public:
-  DependencyGraph Build(std::string expected_error = "") {
-    DependencyGraph graph;
-    auto result = DependencyGraph::Build(this->AST(), this->Symbols(),
-                                         this->Diagnostics(), graph);
-    if (expected_error.empty()) {
-      EXPECT_TRUE(result) << this->Diagnostics().str();
-    } else {
-      EXPECT_FALSE(result);
-      EXPECT_EQ(expected_error, this->Diagnostics().str());
+  public:
+    DependencyGraph Build(std::string expected_error = "") {
+        DependencyGraph graph;
+        auto result =
+            DependencyGraph::Build(this->AST(), this->Symbols(), this->Diagnostics(), graph);
+        if (expected_error.empty()) {
+            EXPECT_TRUE(result) << this->Diagnostics().str();
+        } else {
+            EXPECT_FALSE(result);
+            EXPECT_EQ(expected_error, this->Diagnostics().str());
+        }
+        return graph;
     }
-    return graph;
-  }
 };
 
-using ResolverDependencyGraphTest =
-    ResolverDependencyGraphTestWithParam<::testing::Test>;
+using ResolverDependencyGraphTest = ResolverDependencyGraphTestWithParam<::testing::Test>;
 
 ////////////////////////////////////////////////////////////////////////////////
 // Parameterized test helpers
@@ -52,24 +53,23 @@
 /// SymbolDeclKind is used by parameterized tests to enumerate the different
 /// kinds of symbol declarations.
 enum class SymbolDeclKind {
-  GlobalVar,
-  GlobalLet,
-  Alias,
-  Struct,
-  Function,
-  Parameter,
-  LocalVar,
-  LocalLet,
-  NestedLocalVar,
-  NestedLocalLet,
+    GlobalVar,
+    GlobalConst,
+    Alias,
+    Struct,
+    Function,
+    Parameter,
+    LocalVar,
+    LocalLet,
+    NestedLocalVar,
+    NestedLocalLet,
 };
 
 static constexpr SymbolDeclKind kAllSymbolDeclKinds[] = {
-    SymbolDeclKind::GlobalVar,      SymbolDeclKind::GlobalLet,
-    SymbolDeclKind::Alias,          SymbolDeclKind::Struct,
-    SymbolDeclKind::Function,       SymbolDeclKind::Parameter,
-    SymbolDeclKind::LocalVar,       SymbolDeclKind::LocalLet,
-    SymbolDeclKind::NestedLocalVar, SymbolDeclKind::NestedLocalLet,
+    SymbolDeclKind::GlobalVar,      SymbolDeclKind::GlobalConst, SymbolDeclKind::Alias,
+    SymbolDeclKind::Struct,         SymbolDeclKind::Function,    SymbolDeclKind::Parameter,
+    SymbolDeclKind::LocalVar,       SymbolDeclKind::LocalLet,    SymbolDeclKind::NestedLocalVar,
+    SymbolDeclKind::NestedLocalLet,
 };
 
 static constexpr SymbolDeclKind kTypeDeclKinds[] = {
@@ -78,26 +78,24 @@
 };
 
 static constexpr SymbolDeclKind kValueDeclKinds[] = {
-    SymbolDeclKind::GlobalVar,      SymbolDeclKind::GlobalLet,
-    SymbolDeclKind::Parameter,      SymbolDeclKind::LocalVar,
-    SymbolDeclKind::LocalLet,       SymbolDeclKind::NestedLocalVar,
+    SymbolDeclKind::GlobalVar,      SymbolDeclKind::GlobalConst, SymbolDeclKind::Parameter,
+    SymbolDeclKind::LocalVar,       SymbolDeclKind::LocalLet,    SymbolDeclKind::NestedLocalVar,
     SymbolDeclKind::NestedLocalLet,
 };
 
 static constexpr SymbolDeclKind kGlobalDeclKinds[] = {
-    SymbolDeclKind::GlobalVar, SymbolDeclKind::GlobalLet, SymbolDeclKind::Alias,
+    SymbolDeclKind::GlobalVar, SymbolDeclKind::GlobalConst, SymbolDeclKind::Alias,
     SymbolDeclKind::Struct,    SymbolDeclKind::Function,
 };
 
 static constexpr SymbolDeclKind kLocalDeclKinds[] = {
-    SymbolDeclKind::Parameter,      SymbolDeclKind::LocalVar,
-    SymbolDeclKind::LocalLet,       SymbolDeclKind::NestedLocalVar,
-    SymbolDeclKind::NestedLocalLet,
+    SymbolDeclKind::Parameter,      SymbolDeclKind::LocalVar,       SymbolDeclKind::LocalLet,
+    SymbolDeclKind::NestedLocalVar, SymbolDeclKind::NestedLocalLet,
 };
 
 static constexpr SymbolDeclKind kGlobalValueDeclKinds[] = {
     SymbolDeclKind::GlobalVar,
-    SymbolDeclKind::GlobalLet,
+    SymbolDeclKind::GlobalConst,
 };
 
 static constexpr SymbolDeclKind kFuncDeclKinds[] = {
@@ -107,37 +105,37 @@
 /// SymbolUseKind is used by parameterized tests to enumerate the different
 /// kinds of symbol uses.
 enum class SymbolUseKind {
-  GlobalVarType,
-  GlobalVarArrayElemType,
-  GlobalVarArraySizeValue,
-  GlobalVarVectorElemType,
-  GlobalVarMatrixElemType,
-  GlobalVarSampledTexElemType,
-  GlobalVarMultisampledTexElemType,
-  GlobalVarValue,
-  GlobalLetType,
-  GlobalLetArrayElemType,
-  GlobalLetArraySizeValue,
-  GlobalLetVectorElemType,
-  GlobalLetMatrixElemType,
-  GlobalLetValue,
-  AliasType,
-  StructMemberType,
-  CallFunction,
-  ParameterType,
-  LocalVarType,
-  LocalVarArrayElemType,
-  LocalVarArraySizeValue,
-  LocalVarVectorElemType,
-  LocalVarMatrixElemType,
-  LocalVarValue,
-  LocalLetType,
-  LocalLetValue,
-  NestedLocalVarType,
-  NestedLocalVarValue,
-  NestedLocalLetType,
-  NestedLocalLetValue,
-  WorkgroupSizeValue,
+    GlobalVarType,
+    GlobalVarArrayElemType,
+    GlobalVarArraySizeValue,
+    GlobalVarVectorElemType,
+    GlobalVarMatrixElemType,
+    GlobalVarSampledTexElemType,
+    GlobalVarMultisampledTexElemType,
+    GlobalVarValue,
+    GlobalLetType,
+    GlobalLetArrayElemType,
+    GlobalLetArraySizeValue,
+    GlobalLetVectorElemType,
+    GlobalLetMatrixElemType,
+    GlobalLetValue,
+    AliasType,
+    StructMemberType,
+    CallFunction,
+    ParameterType,
+    LocalVarType,
+    LocalVarArrayElemType,
+    LocalVarArraySizeValue,
+    LocalVarVectorElemType,
+    LocalVarMatrixElemType,
+    LocalVarValue,
+    LocalLetType,
+    LocalLetValue,
+    NestedLocalVarType,
+    NestedLocalVarValue,
+    NestedLocalLetType,
+    NestedLocalLetValue,
+    WorkgroupSizeValue,
 };
 
 static constexpr SymbolUseKind kTypeUseKinds[] = {
@@ -180,474 +178,466 @@
 /// @returns the description of the symbol declaration kind.
 /// @note: This differs from the strings used in diagnostic messages.
 std::ostream& operator<<(std::ostream& out, SymbolDeclKind kind) {
-  switch (kind) {
-    case SymbolDeclKind::GlobalVar:
-      return out << "global var";
-    case SymbolDeclKind::GlobalLet:
-      return out << "global let";
-    case SymbolDeclKind::Alias:
-      return out << "alias";
-    case SymbolDeclKind::Struct:
-      return out << "struct";
-    case SymbolDeclKind::Function:
-      return out << "function";
-    case SymbolDeclKind::Parameter:
-      return out << "parameter";
-    case SymbolDeclKind::LocalVar:
-      return out << "local var";
-    case SymbolDeclKind::LocalLet:
-      return out << "local let";
-    case SymbolDeclKind::NestedLocalVar:
-      return out << "nested local var";
-    case SymbolDeclKind::NestedLocalLet:
-      return out << "nested local let";
-  }
-  return out << "<unknown>";
+    switch (kind) {
+        case SymbolDeclKind::GlobalVar:
+            return out << "global var";
+        case SymbolDeclKind::GlobalConst:
+            return out << "global let";
+        case SymbolDeclKind::Alias:
+            return out << "alias";
+        case SymbolDeclKind::Struct:
+            return out << "struct";
+        case SymbolDeclKind::Function:
+            return out << "function";
+        case SymbolDeclKind::Parameter:
+            return out << "parameter";
+        case SymbolDeclKind::LocalVar:
+            return out << "local var";
+        case SymbolDeclKind::LocalLet:
+            return out << "local let";
+        case SymbolDeclKind::NestedLocalVar:
+            return out << "nested local var";
+        case SymbolDeclKind::NestedLocalLet:
+            return out << "nested local let";
+    }
+    return out << "<unknown>";
 }
 
 /// @returns the description of the symbol use kind.
 /// @note: This differs from the strings used in diagnostic messages.
 std::ostream& operator<<(std::ostream& out, SymbolUseKind kind) {
-  switch (kind) {
-    case SymbolUseKind::GlobalVarType:
-      return out << "global var type";
-    case SymbolUseKind::GlobalVarValue:
-      return out << "global var value";
-    case SymbolUseKind::GlobalVarArrayElemType:
-      return out << "global var array element type";
-    case SymbolUseKind::GlobalVarArraySizeValue:
-      return out << "global var array size value";
-    case SymbolUseKind::GlobalVarVectorElemType:
-      return out << "global var vector element type";
-    case SymbolUseKind::GlobalVarMatrixElemType:
-      return out << "global var matrix element type";
-    case SymbolUseKind::GlobalVarSampledTexElemType:
-      return out << "global var sampled_texture element type";
-    case SymbolUseKind::GlobalVarMultisampledTexElemType:
-      return out << "global var multisampled_texture element type";
-    case SymbolUseKind::GlobalLetType:
-      return out << "global let type";
-    case SymbolUseKind::GlobalLetValue:
-      return out << "global let value";
-    case SymbolUseKind::GlobalLetArrayElemType:
-      return out << "global let array element type";
-    case SymbolUseKind::GlobalLetArraySizeValue:
-      return out << "global let array size value";
-    case SymbolUseKind::GlobalLetVectorElemType:
-      return out << "global let vector element type";
-    case SymbolUseKind::GlobalLetMatrixElemType:
-      return out << "global let matrix element type";
-    case SymbolUseKind::AliasType:
-      return out << "alias type";
-    case SymbolUseKind::StructMemberType:
-      return out << "struct member type";
-    case SymbolUseKind::CallFunction:
-      return out << "call function";
-    case SymbolUseKind::ParameterType:
-      return out << "parameter type";
-    case SymbolUseKind::LocalVarType:
-      return out << "local var type";
-    case SymbolUseKind::LocalVarArrayElemType:
-      return out << "local var array element type";
-    case SymbolUseKind::LocalVarArraySizeValue:
-      return out << "local var array size value";
-    case SymbolUseKind::LocalVarVectorElemType:
-      return out << "local var vector element type";
-    case SymbolUseKind::LocalVarMatrixElemType:
-      return out << "local var matrix element type";
-    case SymbolUseKind::LocalVarValue:
-      return out << "local var value";
-    case SymbolUseKind::LocalLetType:
-      return out << "local let type";
-    case SymbolUseKind::LocalLetValue:
-      return out << "local let value";
-    case SymbolUseKind::NestedLocalVarType:
-      return out << "nested local var type";
-    case SymbolUseKind::NestedLocalVarValue:
-      return out << "nested local var value";
-    case SymbolUseKind::NestedLocalLetType:
-      return out << "nested local let type";
-    case SymbolUseKind::NestedLocalLetValue:
-      return out << "nested local let value";
-    case SymbolUseKind::WorkgroupSizeValue:
-      return out << "workgroup size value";
-  }
-  return out << "<unknown>";
+    switch (kind) {
+        case SymbolUseKind::GlobalVarType:
+            return out << "global var type";
+        case SymbolUseKind::GlobalVarValue:
+            return out << "global var value";
+        case SymbolUseKind::GlobalVarArrayElemType:
+            return out << "global var array element type";
+        case SymbolUseKind::GlobalVarArraySizeValue:
+            return out << "global var array size value";
+        case SymbolUseKind::GlobalVarVectorElemType:
+            return out << "global var vector element type";
+        case SymbolUseKind::GlobalVarMatrixElemType:
+            return out << "global var matrix element type";
+        case SymbolUseKind::GlobalVarSampledTexElemType:
+            return out << "global var sampled_texture element type";
+        case SymbolUseKind::GlobalVarMultisampledTexElemType:
+            return out << "global var multisampled_texture element type";
+        case SymbolUseKind::GlobalLetType:
+            return out << "global let type";
+        case SymbolUseKind::GlobalLetValue:
+            return out << "global let value";
+        case SymbolUseKind::GlobalLetArrayElemType:
+            return out << "global let array element type";
+        case SymbolUseKind::GlobalLetArraySizeValue:
+            return out << "global let array size value";
+        case SymbolUseKind::GlobalLetVectorElemType:
+            return out << "global let vector element type";
+        case SymbolUseKind::GlobalLetMatrixElemType:
+            return out << "global let matrix element type";
+        case SymbolUseKind::AliasType:
+            return out << "alias type";
+        case SymbolUseKind::StructMemberType:
+            return out << "struct member type";
+        case SymbolUseKind::CallFunction:
+            return out << "call function";
+        case SymbolUseKind::ParameterType:
+            return out << "parameter type";
+        case SymbolUseKind::LocalVarType:
+            return out << "local var type";
+        case SymbolUseKind::LocalVarArrayElemType:
+            return out << "local var array element type";
+        case SymbolUseKind::LocalVarArraySizeValue:
+            return out << "local var array size value";
+        case SymbolUseKind::LocalVarVectorElemType:
+            return out << "local var vector element type";
+        case SymbolUseKind::LocalVarMatrixElemType:
+            return out << "local var matrix element type";
+        case SymbolUseKind::LocalVarValue:
+            return out << "local var value";
+        case SymbolUseKind::LocalLetType:
+            return out << "local let type";
+        case SymbolUseKind::LocalLetValue:
+            return out << "local let value";
+        case SymbolUseKind::NestedLocalVarType:
+            return out << "nested local var type";
+        case SymbolUseKind::NestedLocalVarValue:
+            return out << "nested local var value";
+        case SymbolUseKind::NestedLocalLetType:
+            return out << "nested local let type";
+        case SymbolUseKind::NestedLocalLetValue:
+            return out << "nested local let value";
+        case SymbolUseKind::WorkgroupSizeValue:
+            return out << "workgroup size value";
+    }
+    return out << "<unknown>";
 }
 
 /// @returns the the diagnostic message name used for the given use
 std::string DiagString(SymbolUseKind kind) {
-  switch (kind) {
-    case SymbolUseKind::GlobalVarType:
-    case SymbolUseKind::GlobalVarArrayElemType:
-    case SymbolUseKind::GlobalVarVectorElemType:
-    case SymbolUseKind::GlobalVarMatrixElemType:
-    case SymbolUseKind::GlobalVarSampledTexElemType:
-    case SymbolUseKind::GlobalVarMultisampledTexElemType:
-    case SymbolUseKind::GlobalLetType:
-    case SymbolUseKind::GlobalLetArrayElemType:
-    case SymbolUseKind::GlobalLetVectorElemType:
-    case SymbolUseKind::GlobalLetMatrixElemType:
-    case SymbolUseKind::AliasType:
-    case SymbolUseKind::StructMemberType:
-    case SymbolUseKind::ParameterType:
-    case SymbolUseKind::LocalVarType:
-    case SymbolUseKind::LocalVarArrayElemType:
-    case SymbolUseKind::LocalVarVectorElemType:
-    case SymbolUseKind::LocalVarMatrixElemType:
-    case SymbolUseKind::LocalLetType:
-    case SymbolUseKind::NestedLocalVarType:
-    case SymbolUseKind::NestedLocalLetType:
-      return "type";
-    case SymbolUseKind::GlobalVarValue:
-    case SymbolUseKind::GlobalVarArraySizeValue:
-    case SymbolUseKind::GlobalLetValue:
-    case SymbolUseKind::GlobalLetArraySizeValue:
-    case SymbolUseKind::LocalVarValue:
-    case SymbolUseKind::LocalVarArraySizeValue:
-    case SymbolUseKind::LocalLetValue:
-    case SymbolUseKind::NestedLocalVarValue:
-    case SymbolUseKind::NestedLocalLetValue:
-    case SymbolUseKind::WorkgroupSizeValue:
-      return "identifier";
-    case SymbolUseKind::CallFunction:
-      return "function";
-  }
-  return "<unknown>";
+    switch (kind) {
+        case SymbolUseKind::GlobalVarType:
+        case SymbolUseKind::GlobalVarArrayElemType:
+        case SymbolUseKind::GlobalVarVectorElemType:
+        case SymbolUseKind::GlobalVarMatrixElemType:
+        case SymbolUseKind::GlobalVarSampledTexElemType:
+        case SymbolUseKind::GlobalVarMultisampledTexElemType:
+        case SymbolUseKind::GlobalLetType:
+        case SymbolUseKind::GlobalLetArrayElemType:
+        case SymbolUseKind::GlobalLetVectorElemType:
+        case SymbolUseKind::GlobalLetMatrixElemType:
+        case SymbolUseKind::AliasType:
+        case SymbolUseKind::StructMemberType:
+        case SymbolUseKind::ParameterType:
+        case SymbolUseKind::LocalVarType:
+        case SymbolUseKind::LocalVarArrayElemType:
+        case SymbolUseKind::LocalVarVectorElemType:
+        case SymbolUseKind::LocalVarMatrixElemType:
+        case SymbolUseKind::LocalLetType:
+        case SymbolUseKind::NestedLocalVarType:
+        case SymbolUseKind::NestedLocalLetType:
+            return "type";
+        case SymbolUseKind::GlobalVarValue:
+        case SymbolUseKind::GlobalVarArraySizeValue:
+        case SymbolUseKind::GlobalLetValue:
+        case SymbolUseKind::GlobalLetArraySizeValue:
+        case SymbolUseKind::LocalVarValue:
+        case SymbolUseKind::LocalVarArraySizeValue:
+        case SymbolUseKind::LocalLetValue:
+        case SymbolUseKind::NestedLocalVarValue:
+        case SymbolUseKind::NestedLocalLetValue:
+        case SymbolUseKind::WorkgroupSizeValue:
+            return "identifier";
+        case SymbolUseKind::CallFunction:
+            return "function";
+    }
+    return "<unknown>";
 }
 
 /// @returns the declaration scope depth for the symbol declaration kind.
 ///          Globals are at depth 0, parameters and locals are at depth 1,
 ///          nested locals are at depth 2.
 int ScopeDepth(SymbolDeclKind kind) {
-  switch (kind) {
-    case SymbolDeclKind::GlobalVar:
-    case SymbolDeclKind::GlobalLet:
-    case SymbolDeclKind::Alias:
-    case SymbolDeclKind::Struct:
-    case SymbolDeclKind::Function:
-      return 0;
-    case SymbolDeclKind::Parameter:
-    case SymbolDeclKind::LocalVar:
-    case SymbolDeclKind::LocalLet:
-      return 1;
-    case SymbolDeclKind::NestedLocalVar:
-    case SymbolDeclKind::NestedLocalLet:
-      return 2;
-  }
-  return -1;
+    switch (kind) {
+        case SymbolDeclKind::GlobalVar:
+        case SymbolDeclKind::GlobalConst:
+        case SymbolDeclKind::Alias:
+        case SymbolDeclKind::Struct:
+        case SymbolDeclKind::Function:
+            return 0;
+        case SymbolDeclKind::Parameter:
+        case SymbolDeclKind::LocalVar:
+        case SymbolDeclKind::LocalLet:
+            return 1;
+        case SymbolDeclKind::NestedLocalVar:
+        case SymbolDeclKind::NestedLocalLet:
+            return 2;
+    }
+    return -1;
 }
 
 /// @returns the use depth for the symbol use kind.
 ///          Globals are at depth 0, parameters and locals are at depth 1,
 ///          nested locals are at depth 2.
 int ScopeDepth(SymbolUseKind kind) {
-  switch (kind) {
-    case SymbolUseKind::GlobalVarType:
-    case SymbolUseKind::GlobalVarValue:
-    case SymbolUseKind::GlobalVarArrayElemType:
-    case SymbolUseKind::GlobalVarArraySizeValue:
-    case SymbolUseKind::GlobalVarVectorElemType:
-    case SymbolUseKind::GlobalVarMatrixElemType:
-    case SymbolUseKind::GlobalVarSampledTexElemType:
-    case SymbolUseKind::GlobalVarMultisampledTexElemType:
-    case SymbolUseKind::GlobalLetType:
-    case SymbolUseKind::GlobalLetValue:
-    case SymbolUseKind::GlobalLetArrayElemType:
-    case SymbolUseKind::GlobalLetArraySizeValue:
-    case SymbolUseKind::GlobalLetVectorElemType:
-    case SymbolUseKind::GlobalLetMatrixElemType:
-    case SymbolUseKind::AliasType:
-    case SymbolUseKind::StructMemberType:
-    case SymbolUseKind::WorkgroupSizeValue:
-      return 0;
-    case SymbolUseKind::CallFunction:
-    case SymbolUseKind::ParameterType:
-    case SymbolUseKind::LocalVarType:
-    case SymbolUseKind::LocalVarArrayElemType:
-    case SymbolUseKind::LocalVarArraySizeValue:
-    case SymbolUseKind::LocalVarVectorElemType:
-    case SymbolUseKind::LocalVarMatrixElemType:
-    case SymbolUseKind::LocalVarValue:
-    case SymbolUseKind::LocalLetType:
-    case SymbolUseKind::LocalLetValue:
-      return 1;
-    case SymbolUseKind::NestedLocalVarType:
-    case SymbolUseKind::NestedLocalVarValue:
-    case SymbolUseKind::NestedLocalLetType:
-    case SymbolUseKind::NestedLocalLetValue:
-      return 2;
-  }
-  return -1;
+    switch (kind) {
+        case SymbolUseKind::GlobalVarType:
+        case SymbolUseKind::GlobalVarValue:
+        case SymbolUseKind::GlobalVarArrayElemType:
+        case SymbolUseKind::GlobalVarArraySizeValue:
+        case SymbolUseKind::GlobalVarVectorElemType:
+        case SymbolUseKind::GlobalVarMatrixElemType:
+        case SymbolUseKind::GlobalVarSampledTexElemType:
+        case SymbolUseKind::GlobalVarMultisampledTexElemType:
+        case SymbolUseKind::GlobalLetType:
+        case SymbolUseKind::GlobalLetValue:
+        case SymbolUseKind::GlobalLetArrayElemType:
+        case SymbolUseKind::GlobalLetArraySizeValue:
+        case SymbolUseKind::GlobalLetVectorElemType:
+        case SymbolUseKind::GlobalLetMatrixElemType:
+        case SymbolUseKind::AliasType:
+        case SymbolUseKind::StructMemberType:
+        case SymbolUseKind::WorkgroupSizeValue:
+            return 0;
+        case SymbolUseKind::CallFunction:
+        case SymbolUseKind::ParameterType:
+        case SymbolUseKind::LocalVarType:
+        case SymbolUseKind::LocalVarArrayElemType:
+        case SymbolUseKind::LocalVarArraySizeValue:
+        case SymbolUseKind::LocalVarVectorElemType:
+        case SymbolUseKind::LocalVarMatrixElemType:
+        case SymbolUseKind::LocalVarValue:
+        case SymbolUseKind::LocalLetType:
+        case SymbolUseKind::LocalLetValue:
+            return 1;
+        case SymbolUseKind::NestedLocalVarType:
+        case SymbolUseKind::NestedLocalVarValue:
+        case SymbolUseKind::NestedLocalLetType:
+        case SymbolUseKind::NestedLocalLetValue:
+            return 2;
+    }
+    return -1;
 }
 
 /// A helper for building programs that exercise symbol declaration tests.
 struct SymbolTestHelper {
-  /// The program builder
-  ProgramBuilder* const builder;
-  /// Parameters to a function that may need to be built
-  std::vector<const ast::Variable*> parameters;
-  /// Shallow function var / let declaration statements
-  std::vector<const ast::Statement*> statements;
-  /// Nested function local var / let declaration statements
-  std::vector<const ast::Statement*> nested_statements;
-  /// Function attributes
-  ast::AttributeList func_attrs;
+    /// The program builder
+    ProgramBuilder* const builder;
+    /// Parameters to a function that may need to be built
+    std::vector<const ast::Variable*> parameters;
+    /// Shallow function var / let declaration statements
+    std::vector<const ast::Statement*> statements;
+    /// Nested function local var / let declaration statements
+    std::vector<const ast::Statement*> nested_statements;
+    /// Function attributes
+    ast::AttributeList func_attrs;
 
-  /// Constructor
-  /// @param builder the program builder
-  explicit SymbolTestHelper(ProgramBuilder* builder);
+    /// Constructor
+    /// @param builder the program builder
+    explicit SymbolTestHelper(ProgramBuilder* builder);
 
-  /// Destructor.
-  ~SymbolTestHelper();
+    /// Destructor.
+    ~SymbolTestHelper();
 
-  /// Declares a symbol with the given kind
-  /// @param kind the kind of symbol declaration
-  /// @param symbol the symbol to use for the declaration
-  /// @param source the source of the declaration
-  /// @returns the declaration node
-  const ast::Node* Add(SymbolDeclKind kind, Symbol symbol, Source source);
+    /// Declares a symbol with the given kind
+    /// @param kind the kind of symbol declaration
+    /// @param symbol the symbol to use for the declaration
+    /// @param source the source of the declaration
+    /// @returns the declaration node
+    const ast::Node* Add(SymbolDeclKind kind, Symbol symbol, Source source);
 
-  /// Declares a use of a symbol with the given kind
-  /// @param kind the kind of symbol use
-  /// @param symbol the declaration symbol to use
-  /// @param source the source of the use
-  /// @returns the use node
-  const ast::Node* Add(SymbolUseKind kind, Symbol symbol, Source source);
+    /// Declares a use of a symbol with the given kind
+    /// @param kind the kind of symbol use
+    /// @param symbol the declaration symbol to use
+    /// @param source the source of the use
+    /// @returns the use node
+    const ast::Node* Add(SymbolUseKind kind, Symbol symbol, Source source);
 
-  /// Builds a function, if any parameter or local declarations have been added
-  void Build();
+    /// Builds a function, if any parameter or local declarations have been added
+    void Build();
 };
 
 SymbolTestHelper::SymbolTestHelper(ProgramBuilder* b) : builder(b) {}
 
 SymbolTestHelper::~SymbolTestHelper() {}
 
-const ast::Node* SymbolTestHelper::Add(SymbolDeclKind kind,
-                                       Symbol symbol,
-                                       Source source) {
-  auto& b = *builder;
-  switch (kind) {
-    case SymbolDeclKind::GlobalVar:
-      return b.Global(source, symbol, b.ty.i32(), ast::StorageClass::kPrivate);
-    case SymbolDeclKind::GlobalLet:
-      return b.GlobalConst(source, symbol, b.ty.i32(), b.Expr(1));
-    case SymbolDeclKind::Alias:
-      return b.Alias(source, symbol, b.ty.i32());
-    case SymbolDeclKind::Struct:
-      return b.Structure(source, symbol, {b.Member("m", b.ty.i32())});
-    case SymbolDeclKind::Function:
-      return b.Func(source, symbol, {}, b.ty.void_(), {});
-    case SymbolDeclKind::Parameter: {
-      auto* node = b.Param(source, symbol, b.ty.i32());
-      parameters.emplace_back(node);
-      return node;
+const ast::Node* SymbolTestHelper::Add(SymbolDeclKind kind, Symbol symbol, Source source) {
+    auto& b = *builder;
+    switch (kind) {
+        case SymbolDeclKind::GlobalVar:
+            return b.Global(source, symbol, b.ty.i32(), ast::StorageClass::kPrivate);
+        case SymbolDeclKind::GlobalConst:
+            return b.GlobalConst(source, symbol, b.ty.i32(), b.Expr(1_i));
+        case SymbolDeclKind::Alias:
+            return b.Alias(source, symbol, b.ty.i32());
+        case SymbolDeclKind::Struct:
+            return b.Structure(source, symbol, {b.Member("m", b.ty.i32())});
+        case SymbolDeclKind::Function:
+            return b.Func(source, symbol, {}, b.ty.void_(), {});
+        case SymbolDeclKind::Parameter: {
+            auto* node = b.Param(source, symbol, b.ty.i32());
+            parameters.emplace_back(node);
+            return node;
+        }
+        case SymbolDeclKind::LocalVar: {
+            auto* node = b.Var(source, symbol, b.ty.i32());
+            statements.emplace_back(b.Decl(node));
+            return node;
+        }
+        case SymbolDeclKind::LocalLet: {
+            auto* node = b.Let(source, symbol, b.ty.i32(), b.Expr(1_i));
+            statements.emplace_back(b.Decl(node));
+            return node;
+        }
+        case SymbolDeclKind::NestedLocalVar: {
+            auto* node = b.Var(source, symbol, b.ty.i32());
+            nested_statements.emplace_back(b.Decl(node));
+            return node;
+        }
+        case SymbolDeclKind::NestedLocalLet: {
+            auto* node = b.Let(source, symbol, b.ty.i32(), b.Expr(1_i));
+            nested_statements.emplace_back(b.Decl(node));
+            return node;
+        }
     }
-    case SymbolDeclKind::LocalVar: {
-      auto* node = b.Var(source, symbol, b.ty.i32());
-      statements.emplace_back(b.Decl(node));
-      return node;
-    }
-    case SymbolDeclKind::LocalLet: {
-      auto* node = b.Const(source, symbol, b.ty.i32(), b.Expr(1));
-      statements.emplace_back(b.Decl(node));
-      return node;
-    }
-    case SymbolDeclKind::NestedLocalVar: {
-      auto* node = b.Var(source, symbol, b.ty.i32());
-      nested_statements.emplace_back(b.Decl(node));
-      return node;
-    }
-    case SymbolDeclKind::NestedLocalLet: {
-      auto* node = b.Const(source, symbol, b.ty.i32(), b.Expr(1));
-      nested_statements.emplace_back(b.Decl(node));
-      return node;
-    }
-  }
-  return nullptr;
+    return nullptr;
 }
 
-const ast::Node* SymbolTestHelper::Add(SymbolUseKind kind,
-                                       Symbol symbol,
-                                       Source source) {
-  auto& b = *builder;
-  switch (kind) {
-    case SymbolUseKind::GlobalVarType: {
-      auto* node = b.ty.type_name(source, symbol);
-      b.Global(b.Sym(), node, ast::StorageClass::kPrivate);
-      return node;
+const ast::Node* SymbolTestHelper::Add(SymbolUseKind kind, Symbol symbol, Source source) {
+    auto& b = *builder;
+    switch (kind) {
+        case SymbolUseKind::GlobalVarType: {
+            auto* node = b.ty.type_name(source, symbol);
+            b.Global(b.Sym(), node, ast::StorageClass::kPrivate);
+            return node;
+        }
+        case SymbolUseKind::GlobalVarArrayElemType: {
+            auto* node = b.ty.type_name(source, symbol);
+            b.Global(b.Sym(), b.ty.array(node, 4_i), ast::StorageClass::kPrivate);
+            return node;
+        }
+        case SymbolUseKind::GlobalVarArraySizeValue: {
+            auto* node = b.Expr(source, symbol);
+            b.Global(b.Sym(), b.ty.array(b.ty.i32(), node), ast::StorageClass::kPrivate);
+            return node;
+        }
+        case SymbolUseKind::GlobalVarVectorElemType: {
+            auto* node = b.ty.type_name(source, symbol);
+            b.Global(b.Sym(), b.ty.vec3(node), ast::StorageClass::kPrivate);
+            return node;
+        }
+        case SymbolUseKind::GlobalVarMatrixElemType: {
+            auto* node = b.ty.type_name(source, symbol);
+            b.Global(b.Sym(), b.ty.mat3x4(node), ast::StorageClass::kPrivate);
+            return node;
+        }
+        case SymbolUseKind::GlobalVarSampledTexElemType: {
+            auto* node = b.ty.type_name(source, symbol);
+            b.Global(b.Sym(), b.ty.sampled_texture(ast::TextureDimension::k2d, node));
+            return node;
+        }
+        case SymbolUseKind::GlobalVarMultisampledTexElemType: {
+            auto* node = b.ty.type_name(source, symbol);
+            b.Global(b.Sym(), b.ty.multisampled_texture(ast::TextureDimension::k2d, node));
+            return node;
+        }
+        case SymbolUseKind::GlobalVarValue: {
+            auto* node = b.Expr(source, symbol);
+            b.Global(b.Sym(), b.ty.i32(), ast::StorageClass::kPrivate, node);
+            return node;
+        }
+        case SymbolUseKind::GlobalLetType: {
+            auto* node = b.ty.type_name(source, symbol);
+            b.GlobalConst(b.Sym(), node, b.Expr(1_i));
+            return node;
+        }
+        case SymbolUseKind::GlobalLetArrayElemType: {
+            auto* node = b.ty.type_name(source, symbol);
+            b.GlobalConst(b.Sym(), b.ty.array(node, 4_i), b.Expr(1_i));
+            return node;
+        }
+        case SymbolUseKind::GlobalLetArraySizeValue: {
+            auto* node = b.Expr(source, symbol);
+            b.GlobalConst(b.Sym(), b.ty.array(b.ty.i32(), node), b.Expr(1_i));
+            return node;
+        }
+        case SymbolUseKind::GlobalLetVectorElemType: {
+            auto* node = b.ty.type_name(source, symbol);
+            b.GlobalConst(b.Sym(), b.ty.vec3(node), b.Expr(1_i));
+            return node;
+        }
+        case SymbolUseKind::GlobalLetMatrixElemType: {
+            auto* node = b.ty.type_name(source, symbol);
+            b.GlobalConst(b.Sym(), b.ty.mat3x4(node), b.Expr(1_i));
+            return node;
+        }
+        case SymbolUseKind::GlobalLetValue: {
+            auto* node = b.Expr(source, symbol);
+            b.GlobalConst(b.Sym(), b.ty.i32(), node);
+            return node;
+        }
+        case SymbolUseKind::AliasType: {
+            auto* node = b.ty.type_name(source, symbol);
+            b.Alias(b.Sym(), node);
+            return node;
+        }
+        case SymbolUseKind::StructMemberType: {
+            auto* node = b.ty.type_name(source, symbol);
+            b.Structure(b.Sym(), {b.Member("m", node)});
+            return node;
+        }
+        case SymbolUseKind::CallFunction: {
+            auto* node = b.Expr(source, symbol);
+            statements.emplace_back(b.CallStmt(b.Call(node)));
+            return node;
+        }
+        case SymbolUseKind::ParameterType: {
+            auto* node = b.ty.type_name(source, symbol);
+            parameters.emplace_back(b.Param(b.Sym(), node));
+            return node;
+        }
+        case SymbolUseKind::LocalVarType: {
+            auto* node = b.ty.type_name(source, symbol);
+            statements.emplace_back(b.Decl(b.Var(b.Sym(), node)));
+            return node;
+        }
+        case SymbolUseKind::LocalVarArrayElemType: {
+            auto* node = b.ty.type_name(source, symbol);
+            statements.emplace_back(b.Decl(b.Var(b.Sym(), b.ty.array(node, 4_u), b.Expr(1_i))));
+            return node;
+        }
+        case SymbolUseKind::LocalVarArraySizeValue: {
+            auto* node = b.Expr(source, symbol);
+            statements.emplace_back(
+                b.Decl(b.Var(b.Sym(), b.ty.array(b.ty.i32(), node), b.Expr(1_i))));
+            return node;
+        }
+        case SymbolUseKind::LocalVarVectorElemType: {
+            auto* node = b.ty.type_name(source, symbol);
+            statements.emplace_back(b.Decl(b.Var(b.Sym(), b.ty.vec3(node))));
+            return node;
+        }
+        case SymbolUseKind::LocalVarMatrixElemType: {
+            auto* node = b.ty.type_name(source, symbol);
+            statements.emplace_back(b.Decl(b.Var(b.Sym(), b.ty.mat3x4(node))));
+            return node;
+        }
+        case SymbolUseKind::LocalVarValue: {
+            auto* node = b.Expr(source, symbol);
+            statements.emplace_back(b.Decl(b.Var(b.Sym(), b.ty.i32(), node)));
+            return node;
+        }
+        case SymbolUseKind::LocalLetType: {
+            auto* node = b.ty.type_name(source, symbol);
+            statements.emplace_back(b.Decl(b.Let(b.Sym(), node, b.Expr(1_i))));
+            return node;
+        }
+        case SymbolUseKind::LocalLetValue: {
+            auto* node = b.Expr(source, symbol);
+            statements.emplace_back(b.Decl(b.Let(b.Sym(), b.ty.i32(), node)));
+            return node;
+        }
+        case SymbolUseKind::NestedLocalVarType: {
+            auto* node = b.ty.type_name(source, symbol);
+            nested_statements.emplace_back(b.Decl(b.Var(b.Sym(), node)));
+            return node;
+        }
+        case SymbolUseKind::NestedLocalVarValue: {
+            auto* node = b.Expr(source, symbol);
+            nested_statements.emplace_back(b.Decl(b.Var(b.Sym(), b.ty.i32(), node)));
+            return node;
+        }
+        case SymbolUseKind::NestedLocalLetType: {
+            auto* node = b.ty.type_name(source, symbol);
+            nested_statements.emplace_back(b.Decl(b.Let(b.Sym(), node, b.Expr(1_i))));
+            return node;
+        }
+        case SymbolUseKind::NestedLocalLetValue: {
+            auto* node = b.Expr(source, symbol);
+            nested_statements.emplace_back(b.Decl(b.Let(b.Sym(), b.ty.i32(), node)));
+            return node;
+        }
+        case SymbolUseKind::WorkgroupSizeValue: {
+            auto* node = b.Expr(source, symbol);
+            func_attrs.emplace_back(b.WorkgroupSize(1_i, node, 2_i));
+            return node;
+        }
     }
-    case SymbolUseKind::GlobalVarArrayElemType: {
-      auto* node = b.ty.type_name(source, symbol);
-      b.Global(b.Sym(), b.ty.array(node, 4), ast::StorageClass::kPrivate);
-      return node;
-    }
-    case SymbolUseKind::GlobalVarArraySizeValue: {
-      auto* node = b.Expr(source, symbol);
-      b.Global(b.Sym(), b.ty.array(b.ty.i32(), node),
-               ast::StorageClass::kPrivate);
-      return node;
-    }
-    case SymbolUseKind::GlobalVarVectorElemType: {
-      auto* node = b.ty.type_name(source, symbol);
-      b.Global(b.Sym(), b.ty.vec3(node), ast::StorageClass::kPrivate);
-      return node;
-    }
-    case SymbolUseKind::GlobalVarMatrixElemType: {
-      auto* node = b.ty.type_name(source, symbol);
-      b.Global(b.Sym(), b.ty.mat3x4(node), ast::StorageClass::kPrivate);
-      return node;
-    }
-    case SymbolUseKind::GlobalVarSampledTexElemType: {
-      auto* node = b.ty.type_name(source, symbol);
-      b.Global(b.Sym(), b.ty.sampled_texture(ast::TextureDimension::k2d, node));
-      return node;
-    }
-    case SymbolUseKind::GlobalVarMultisampledTexElemType: {
-      auto* node = b.ty.type_name(source, symbol);
-      b.Global(b.Sym(),
-               b.ty.multisampled_texture(ast::TextureDimension::k2d, node));
-      return node;
-    }
-    case SymbolUseKind::GlobalVarValue: {
-      auto* node = b.Expr(source, symbol);
-      b.Global(b.Sym(), b.ty.i32(), ast::StorageClass::kPrivate, node);
-      return node;
-    }
-    case SymbolUseKind::GlobalLetType: {
-      auto* node = b.ty.type_name(source, symbol);
-      b.GlobalConst(b.Sym(), node, b.Expr(1));
-      return node;
-    }
-    case SymbolUseKind::GlobalLetArrayElemType: {
-      auto* node = b.ty.type_name(source, symbol);
-      b.GlobalConst(b.Sym(), b.ty.array(node, 4), b.Expr(1));
-      return node;
-    }
-    case SymbolUseKind::GlobalLetArraySizeValue: {
-      auto* node = b.Expr(source, symbol);
-      b.GlobalConst(b.Sym(), b.ty.array(b.ty.i32(), node), b.Expr(1));
-      return node;
-    }
-    case SymbolUseKind::GlobalLetVectorElemType: {
-      auto* node = b.ty.type_name(source, symbol);
-      b.GlobalConst(b.Sym(), b.ty.vec3(node), b.Expr(1));
-      return node;
-    }
-    case SymbolUseKind::GlobalLetMatrixElemType: {
-      auto* node = b.ty.type_name(source, symbol);
-      b.GlobalConst(b.Sym(), b.ty.mat3x4(node), b.Expr(1));
-      return node;
-    }
-    case SymbolUseKind::GlobalLetValue: {
-      auto* node = b.Expr(source, symbol);
-      b.GlobalConst(b.Sym(), b.ty.i32(), node);
-      return node;
-    }
-    case SymbolUseKind::AliasType: {
-      auto* node = b.ty.type_name(source, symbol);
-      b.Alias(b.Sym(), node);
-      return node;
-    }
-    case SymbolUseKind::StructMemberType: {
-      auto* node = b.ty.type_name(source, symbol);
-      b.Structure(b.Sym(), {b.Member("m", node)});
-      return node;
-    }
-    case SymbolUseKind::CallFunction: {
-      auto* node = b.Expr(source, symbol);
-      statements.emplace_back(b.CallStmt(b.Call(node)));
-      return node;
-    }
-    case SymbolUseKind::ParameterType: {
-      auto* node = b.ty.type_name(source, symbol);
-      parameters.emplace_back(b.Param(b.Sym(), node));
-      return node;
-    }
-    case SymbolUseKind::LocalVarType: {
-      auto* node = b.ty.type_name(source, symbol);
-      statements.emplace_back(b.Decl(b.Var(b.Sym(), node)));
-      return node;
-    }
-    case SymbolUseKind::LocalVarArrayElemType: {
-      auto* node = b.ty.type_name(source, symbol);
-      statements.emplace_back(
-          b.Decl(b.Var(b.Sym(), b.ty.array(node, 4), b.Expr(1))));
-      return node;
-    }
-    case SymbolUseKind::LocalVarArraySizeValue: {
-      auto* node = b.Expr(source, symbol);
-      statements.emplace_back(
-          b.Decl(b.Var(b.Sym(), b.ty.array(b.ty.i32(), node), b.Expr(1))));
-      return node;
-    }
-    case SymbolUseKind::LocalVarVectorElemType: {
-      auto* node = b.ty.type_name(source, symbol);
-      statements.emplace_back(b.Decl(b.Var(b.Sym(), b.ty.vec3(node))));
-      return node;
-    }
-    case SymbolUseKind::LocalVarMatrixElemType: {
-      auto* node = b.ty.type_name(source, symbol);
-      statements.emplace_back(b.Decl(b.Var(b.Sym(), b.ty.mat3x4(node))));
-      return node;
-    }
-    case SymbolUseKind::LocalVarValue: {
-      auto* node = b.Expr(source, symbol);
-      statements.emplace_back(b.Decl(b.Var(b.Sym(), b.ty.i32(), node)));
-      return node;
-    }
-    case SymbolUseKind::LocalLetType: {
-      auto* node = b.ty.type_name(source, symbol);
-      statements.emplace_back(b.Decl(b.Const(b.Sym(), node, b.Expr(1))));
-      return node;
-    }
-    case SymbolUseKind::LocalLetValue: {
-      auto* node = b.Expr(source, symbol);
-      statements.emplace_back(b.Decl(b.Const(b.Sym(), b.ty.i32(), node)));
-      return node;
-    }
-    case SymbolUseKind::NestedLocalVarType: {
-      auto* node = b.ty.type_name(source, symbol);
-      nested_statements.emplace_back(b.Decl(b.Var(b.Sym(), node)));
-      return node;
-    }
-    case SymbolUseKind::NestedLocalVarValue: {
-      auto* node = b.Expr(source, symbol);
-      nested_statements.emplace_back(b.Decl(b.Var(b.Sym(), b.ty.i32(), node)));
-      return node;
-    }
-    case SymbolUseKind::NestedLocalLetType: {
-      auto* node = b.ty.type_name(source, symbol);
-      nested_statements.emplace_back(b.Decl(b.Const(b.Sym(), node, b.Expr(1))));
-      return node;
-    }
-    case SymbolUseKind::NestedLocalLetValue: {
-      auto* node = b.Expr(source, symbol);
-      nested_statements.emplace_back(
-          b.Decl(b.Const(b.Sym(), b.ty.i32(), node)));
-      return node;
-    }
-    case SymbolUseKind::WorkgroupSizeValue: {
-      auto* node = b.Expr(source, symbol);
-      func_attrs.emplace_back(b.WorkgroupSize(1, node, 2));
-      return node;
-    }
-  }
-  return nullptr;
+    return nullptr;
 }
 
 void SymbolTestHelper::Build() {
-  auto& b = *builder;
-  if (!nested_statements.empty()) {
-    statements.emplace_back(b.Block(nested_statements));
-    nested_statements.clear();
-  }
-  if (!parameters.empty() || !statements.empty() || !func_attrs.empty()) {
-    b.Func("func", parameters, b.ty.void_(), statements, func_attrs);
-    parameters.clear();
-    statements.clear();
-    func_attrs.clear();
-  }
+    auto& b = *builder;
+    if (!nested_statements.empty()) {
+        statements.emplace_back(b.Block(nested_statements));
+        nested_statements.clear();
+    }
+    if (!parameters.empty() || !statements.empty() || !func_attrs.empty()) {
+        b.Func("func", parameters, b.ty.void_(), statements, func_attrs);
+        parameters.clear();
+        statements.clear();
+        func_attrs.clear();
+    }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -658,84 +648,80 @@
 using ResolverDependencyGraphUsedBeforeDeclTest = ResolverDependencyGraphTest;
 
 TEST_F(ResolverDependencyGraphUsedBeforeDeclTest, FuncCall) {
-  // fn A() { B(); }
-  // fn B() {}
+    // fn A() { B(); }
+    // fn B() {}
 
-  Func("A", {}, ty.void_(), {CallStmt(Call(Expr(Source{{12, 34}}, "B")))});
-  Func(Source{{56, 78}}, "B", {}, ty.void_(), {Return()});
+    Func("A", {}, ty.void_(), {CallStmt(Call(Expr(Source{{12, 34}}, "B")))});
+    Func(Source{{56, 78}}, "B", {}, ty.void_(), {Return()});
 
-  Build();
+    Build();
 }
 
 TEST_F(ResolverDependencyGraphUsedBeforeDeclTest, TypeConstructed) {
-  // fn F() {
-  //   { _ = T(); }
-  // }
-  // type T = i32;
+    // fn F() {
+    //   { _ = T(); }
+    // }
+    // type T = i32;
 
-  Func("F", {}, ty.void_(),
-       {Block(Ignore(Construct(ty.type_name(Source{{12, 34}}, "T"))))});
-  Alias(Source{{56, 78}}, "T", ty.i32());
+    Func("F", {}, ty.void_(), {Block(Ignore(Construct(ty.type_name(Source{{12, 34}}, "T"))))});
+    Alias(Source{{56, 78}}, "T", ty.i32());
 
-  Build();
+    Build();
 }
 
 TEST_F(ResolverDependencyGraphUsedBeforeDeclTest, TypeUsedByLocal) {
-  // fn F() {
-  //   { var v : T; }
-  // }
-  // type T = i32;
+    // fn F() {
+    //   { var v : T; }
+    // }
+    // type T = i32;
 
-  Func("F", {}, ty.void_(),
-       {Block(Decl(Var("v", ty.type_name(Source{{12, 34}}, "T"))))});
-  Alias(Source{{56, 78}}, "T", ty.i32());
+    Func("F", {}, ty.void_(), {Block(Decl(Var("v", ty.type_name(Source{{12, 34}}, "T"))))});
+    Alias(Source{{56, 78}}, "T", ty.i32());
 
-  Build();
+    Build();
 }
 
 TEST_F(ResolverDependencyGraphUsedBeforeDeclTest, TypeUsedByParam) {
-  // fn F(p : T) {}
-  // type T = i32;
+    // fn F(p : T) {}
+    // type T = i32;
 
-  Func("F", {Param("p", ty.type_name(Source{{12, 34}}, "T"))}, ty.void_(), {});
-  Alias(Source{{56, 78}}, "T", ty.i32());
+    Func("F", {Param("p", ty.type_name(Source{{12, 34}}, "T"))}, ty.void_(), {});
+    Alias(Source{{56, 78}}, "T", ty.i32());
 
-  Build();
+    Build();
 }
 
 TEST_F(ResolverDependencyGraphUsedBeforeDeclTest, TypeUsedAsReturnType) {
-  // fn F() -> T {}
-  // type T = i32;
+    // fn F() -> T {}
+    // type T = i32;
 
-  Func("F", {}, ty.type_name(Source{{12, 34}}, "T"), {});
-  Alias(Source{{56, 78}}, "T", ty.i32());
+    Func("F", {}, ty.type_name(Source{{12, 34}}, "T"), {});
+    Alias(Source{{56, 78}}, "T", ty.i32());
 
-  Build();
+    Build();
 }
 
 TEST_F(ResolverDependencyGraphUsedBeforeDeclTest, TypeByStructMember) {
-  // struct S { m : T };
-  // type T = i32;
+    // struct S { m : T };
+    // type T = i32;
 
-  Structure("S", {Member("m", ty.type_name(Source{{12, 34}}, "T"))});
-  Alias(Source{{56, 78}}, "T", ty.i32());
+    Structure("S", {Member("m", ty.type_name(Source{{12, 34}}, "T"))});
+    Alias(Source{{56, 78}}, "T", ty.i32());
 
-  Build();
+    Build();
 }
 
 TEST_F(ResolverDependencyGraphUsedBeforeDeclTest, VarUsed) {
-  // fn F() {
-  //   { G = 3.14f; }
-  // }
-  // var G: f32 = 2.1;
+    // fn F() {
+    //   { G = 3.14f; }
+    // }
+    // var G: f32 = 2.1;
 
-  Func("F", ast::VariableList{}, ty.void_(),
-       {Block(Assign(Expr(Source{{12, 34}}, "G"), 3.14f))});
+    Func("F", ast::VariableList{}, ty.void_(), {Block(Assign(Expr(Source{{12, 34}}, "G"), 3.14f))});
 
-  Global(Source{{56, 78}}, "G", ty.f32(), ast::StorageClass::kPrivate,
-         Expr(2.1f));
+    Global(Source{{56, 78}}, "G", ty.f32(), ast::StorageClass::kPrivate, Expr(2.1f));
 
-  Build();
+    Build();
 }
 
 }  // namespace used_before_decl_tests
@@ -749,15 +735,15 @@
     ResolverDependencyGraphTestWithParam<SymbolUseKind>;
 
 TEST_P(ResolverDependencyGraphUndeclaredSymbolTest, Test) {
-  const Symbol symbol = Sym("SYMBOL");
-  const auto use_kind = GetParam();
+    const Symbol symbol = Sym("SYMBOL");
+    const auto use_kind = GetParam();
 
-  // Build a use of a non-existent symbol
-  SymbolTestHelper helper(this);
-  helper.Add(use_kind, symbol, Source{{56, 78}});
-  helper.Build();
+    // Build a use of a non-existent symbol
+    SymbolTestHelper helper(this);
+    helper.Add(use_kind, symbol, Source{{56, 78}});
+    helper.Build();
 
-  Build("56:78 error: unknown " + DiagString(use_kind) + ": 'SYMBOL'");
+    Build("56:78 error: unknown " + DiagString(use_kind) + ": 'SYMBOL'");
 }
 
 INSTANTIATE_TEST_SUITE_P(Types,
@@ -782,31 +768,29 @@
 using ResolverDependencyGraphDeclSelfUse = ResolverDependencyGraphTest;
 
 TEST_F(ResolverDependencyGraphDeclSelfUse, GlobalVar) {
-  const Symbol symbol = Sym("SYMBOL");
-  Global(symbol, ty.i32(), Mul(Expr(Source{{12, 34}}, symbol), 123));
-  Build(R"(error: cyclic dependency found: 'SYMBOL' -> 'SYMBOL'
+    const Symbol symbol = Sym("SYMBOL");
+    Global(symbol, ty.i32(), Mul(Expr(Source{{12, 34}}, symbol), 123_i));
+    Build(R"(error: cyclic dependency found: 'SYMBOL' -> 'SYMBOL'
 12:34 note: var 'SYMBOL' references var 'SYMBOL' here)");
 }
 
-TEST_F(ResolverDependencyGraphDeclSelfUse, GlobalLet) {
-  const Symbol symbol = Sym("SYMBOL");
-  GlobalConst(symbol, ty.i32(), Mul(Expr(Source{{12, 34}}, symbol), 123));
-  Build(R"(error: cyclic dependency found: 'SYMBOL' -> 'SYMBOL'
+TEST_F(ResolverDependencyGraphDeclSelfUse, GlobalConst) {
+    const Symbol symbol = Sym("SYMBOL");
+    GlobalConst(symbol, ty.i32(), Mul(Expr(Source{{12, 34}}, symbol), 123_i));
+    Build(R"(error: cyclic dependency found: 'SYMBOL' -> 'SYMBOL'
 12:34 note: let 'SYMBOL' references let 'SYMBOL' here)");
 }
 
 TEST_F(ResolverDependencyGraphDeclSelfUse, LocalVar) {
-  const Symbol symbol = Sym("SYMBOL");
-  WrapInFunction(
-      Decl(Var(symbol, ty.i32(), Mul(Expr(Source{{12, 34}}, symbol), 123))));
-  Build("12:34 error: unknown identifier: 'SYMBOL'");
+    const Symbol symbol = Sym("SYMBOL");
+    WrapInFunction(Decl(Var(symbol, ty.i32(), Mul(Expr(Source{{12, 34}}, symbol), 123_i))));
+    Build("12:34 error: unknown identifier: 'SYMBOL'");
 }
 
 TEST_F(ResolverDependencyGraphDeclSelfUse, LocalLet) {
-  const Symbol symbol = Sym("SYMBOL");
-  WrapInFunction(
-      Decl(Const(symbol, ty.i32(), Mul(Expr(Source{{12, 34}}, symbol), 123))));
-  Build("12:34 error: unknown identifier: 'SYMBOL'");
+    const Symbol symbol = Sym("SYMBOL");
+    WrapInFunction(Decl(Let(symbol, ty.i32(), Mul(Expr(Source{{12, 34}}, symbol), 123_i))));
+    Build("12:34 error: unknown identifier: 'SYMBOL'");
 }
 
 }  // namespace undeclared_tests
@@ -819,180 +803,171 @@
 using ResolverDependencyGraphCyclicRefTest = ResolverDependencyGraphTest;
 
 TEST_F(ResolverDependencyGraphCyclicRefTest, DirectCall) {
-  // fn main() { main(); }
+    // fn main() { main(); }
 
-  Func(Source{{12, 34}}, "main", {}, ty.void_(),
-       {CallStmt(Call(Expr(Source{{56, 78}}, "main")))});
+    Func(Source{{12, 34}}, "main", {}, ty.void_(),
+         {CallStmt(Call(Expr(Source{{56, 78}}, "main")))});
 
-  Build(R"(12:34 error: cyclic dependency found: 'main' -> 'main'
+    Build(R"(12:34 error: cyclic dependency found: 'main' -> 'main'
 56:78 note: function 'main' calls function 'main' here)");
 }
 
 TEST_F(ResolverDependencyGraphCyclicRefTest, IndirectCall) {
-  // 1: fn a() { b(); }
-  // 2: fn e() { }
-  // 3: fn d() { e(); b(); }
-  // 4: fn c() { d(); }
-  // 5: fn b() { c(); }
+    // 1: fn a() { b(); }
+    // 2: fn e() { }
+    // 3: fn d() { e(); b(); }
+    // 4: fn c() { d(); }
+    // 5: fn b() { c(); }
 
-  Func(Source{{1, 1}}, "a", {}, ty.void_(),
-       {CallStmt(Call(Expr(Source{{1, 10}}, "b")))});
-  Func(Source{{2, 1}}, "e", {}, ty.void_(), {});
-  Func(Source{{3, 1}}, "d", {}, ty.void_(),
-       {
-           CallStmt(Call(Expr(Source{{3, 10}}, "e"))),
-           CallStmt(Call(Expr(Source{{3, 10}}, "b"))),
-       });
-  Func(Source{{4, 1}}, "c", {}, ty.void_(),
-       {CallStmt(Call(Expr(Source{{4, 10}}, "d")))});
-  Func(Source{{5, 1}}, "b", {}, ty.void_(),
-       {CallStmt(Call(Expr(Source{{5, 10}}, "c")))});
+    Func(Source{{1, 1}}, "a", {}, ty.void_(), {CallStmt(Call(Expr(Source{{1, 10}}, "b")))});
+    Func(Source{{2, 1}}, "e", {}, ty.void_(), {});
+    Func(Source{{3, 1}}, "d", {}, ty.void_(),
+         {
+             CallStmt(Call(Expr(Source{{3, 10}}, "e"))),
+             CallStmt(Call(Expr(Source{{3, 10}}, "b"))),
+         });
+    Func(Source{{4, 1}}, "c", {}, ty.void_(), {CallStmt(Call(Expr(Source{{4, 10}}, "d")))});
+    Func(Source{{5, 1}}, "b", {}, ty.void_(), {CallStmt(Call(Expr(Source{{5, 10}}, "c")))});
 
-  Build(R"(5:1 error: cyclic dependency found: 'b' -> 'c' -> 'd' -> 'b'
+    Build(R"(5:1 error: cyclic dependency found: 'b' -> 'c' -> 'd' -> 'b'
 5:10 note: function 'b' calls function 'c' here
 4:10 note: function 'c' calls function 'd' here
 3:10 note: function 'd' calls function 'b' here)");
 }
 
 TEST_F(ResolverDependencyGraphCyclicRefTest, Alias_Direct) {
-  // type T = T;
+    // type T = T;
 
-  Alias(Source{{12, 34}}, "T", ty.type_name(Source{{56, 78}}, "T"));
+    Alias(Source{{12, 34}}, "T", ty.type_name(Source{{56, 78}}, "T"));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            R"(12:34 error: cyclic dependency found: 'T' -> 'T'
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: cyclic dependency found: 'T' -> 'T'
 56:78 note: alias 'T' references alias 'T' here)");
 }
 
 TEST_F(ResolverDependencyGraphCyclicRefTest, Alias_Indirect) {
-  // 1: type Y = Z;
-  // 2: type X = Y;
-  // 3: type Z = X;
+    // 1: type Y = Z;
+    // 2: type X = Y;
+    // 3: type Z = X;
 
-  Alias(Source{{1, 1}}, "Y", ty.type_name(Source{{1, 10}}, "Z"));
-  Alias(Source{{2, 1}}, "X", ty.type_name(Source{{2, 10}}, "Y"));
-  Alias(Source{{3, 1}}, "Z", ty.type_name(Source{{3, 10}}, "X"));
+    Alias(Source{{1, 1}}, "Y", ty.type_name(Source{{1, 10}}, "Z"));
+    Alias(Source{{2, 1}}, "X", ty.type_name(Source{{2, 10}}, "Y"));
+    Alias(Source{{3, 1}}, "Z", ty.type_name(Source{{3, 10}}, "X"));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            R"(1:1 error: cyclic dependency found: 'Y' -> 'Z' -> 'X' -> 'Y'
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(1:1 error: cyclic dependency found: 'Y' -> 'Z' -> 'X' -> 'Y'
 1:10 note: alias 'Y' references alias 'Z' here
 3:10 note: alias 'Z' references alias 'X' here
 2:10 note: alias 'X' references alias 'Y' here)");
 }
 
 TEST_F(ResolverDependencyGraphCyclicRefTest, Struct_Direct) {
-  // struct S {
-  //   a: S;
-  // };
+    // struct S {
+    //   a: S;
+    // };
 
-  Structure(Source{{12, 34}}, "S",
-            {Member("a", ty.type_name(Source{{56, 78}}, "S"))});
+    Structure(Source{{12, 34}}, "S", {Member("a", ty.type_name(Source{{56, 78}}, "S"))});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            R"(12:34 error: cyclic dependency found: 'S' -> 'S'
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: cyclic dependency found: 'S' -> 'S'
 56:78 note: struct 'S' references struct 'S' here)");
 }
 
 TEST_F(ResolverDependencyGraphCyclicRefTest, Struct_Indirect) {
-  // 1: struct Y { z: Z; };
-  // 2: struct X { y: Y; };
-  // 3: struct Z { x: X; };
+    // 1: struct Y { z: Z; };
+    // 2: struct X { y: Y; };
+    // 3: struct Z { x: X; };
 
-  Structure(Source{{1, 1}}, "Y",
-            {Member("z", ty.type_name(Source{{1, 10}}, "Z"))});
-  Structure(Source{{2, 1}}, "X",
-            {Member("y", ty.type_name(Source{{2, 10}}, "Y"))});
-  Structure(Source{{3, 1}}, "Z",
-            {Member("x", ty.type_name(Source{{3, 10}}, "X"))});
+    Structure(Source{{1, 1}}, "Y", {Member("z", ty.type_name(Source{{1, 10}}, "Z"))});
+    Structure(Source{{2, 1}}, "X", {Member("y", ty.type_name(Source{{2, 10}}, "Y"))});
+    Structure(Source{{3, 1}}, "Z", {Member("x", ty.type_name(Source{{3, 10}}, "X"))});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            R"(1:1 error: cyclic dependency found: 'Y' -> 'Z' -> 'X' -> 'Y'
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(1:1 error: cyclic dependency found: 'Y' -> 'Z' -> 'X' -> 'Y'
 1:10 note: struct 'Y' references struct 'Z' here
 3:10 note: struct 'Z' references struct 'X' here
 2:10 note: struct 'X' references struct 'Y' here)");
 }
 
 TEST_F(ResolverDependencyGraphCyclicRefTest, GlobalVar_Direct) {
-  // var<private> V : i32 = V;
+    // var<private> V : i32 = V;
 
-  Global(Source{{12, 34}}, "V", ty.i32(), Expr(Source{{56, 78}}, "V"));
+    Global(Source{{12, 34}}, "V", ty.i32(), Expr(Source{{56, 78}}, "V"));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            R"(12:34 error: cyclic dependency found: 'V' -> 'V'
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: cyclic dependency found: 'V' -> 'V'
 56:78 note: var 'V' references var 'V' here)");
 }
 
 TEST_F(ResolverDependencyGraphCyclicRefTest, GlobalLet_Direct) {
-  // let V : i32 = V;
+    // let V : i32 = V;
 
-  GlobalConst(Source{{12, 34}}, "V", ty.i32(), Expr(Source{{56, 78}}, "V"));
+    GlobalConst(Source{{12, 34}}, "V", ty.i32(), Expr(Source{{56, 78}}, "V"));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            R"(12:34 error: cyclic dependency found: 'V' -> 'V'
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: cyclic dependency found: 'V' -> 'V'
 56:78 note: let 'V' references let 'V' here)");
 }
 
 TEST_F(ResolverDependencyGraphCyclicRefTest, GlobalVar_Indirect) {
-  // 1: var<private> Y : i32 = Z;
-  // 2: var<private> X : i32 = Y;
-  // 3: var<private> Z : i32 = X;
+    // 1: var<private> Y : i32 = Z;
+    // 2: var<private> X : i32 = Y;
+    // 3: var<private> Z : i32 = X;
 
-  Global(Source{{1, 1}}, "Y", ty.i32(), Expr(Source{{1, 10}}, "Z"));
-  Global(Source{{2, 1}}, "X", ty.i32(), Expr(Source{{2, 10}}, "Y"));
-  Global(Source{{3, 1}}, "Z", ty.i32(), Expr(Source{{3, 10}}, "X"));
+    Global(Source{{1, 1}}, "Y", ty.i32(), Expr(Source{{1, 10}}, "Z"));
+    Global(Source{{2, 1}}, "X", ty.i32(), Expr(Source{{2, 10}}, "Y"));
+    Global(Source{{3, 1}}, "Z", ty.i32(), Expr(Source{{3, 10}}, "X"));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            R"(1:1 error: cyclic dependency found: 'Y' -> 'Z' -> 'X' -> 'Y'
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(1:1 error: cyclic dependency found: 'Y' -> 'Z' -> 'X' -> 'Y'
 1:10 note: var 'Y' references var 'Z' here
 3:10 note: var 'Z' references var 'X' here
 2:10 note: var 'X' references var 'Y' here)");
 }
 
 TEST_F(ResolverDependencyGraphCyclicRefTest, GlobalLet_Indirect) {
-  // 1: let Y : i32 = Z;
-  // 2: let X : i32 = Y;
-  // 3: let Z : i32 = X;
+    // 1: let Y : i32 = Z;
+    // 2: let X : i32 = Y;
+    // 3: let Z : i32 = X;
 
-  GlobalConst(Source{{1, 1}}, "Y", ty.i32(), Expr(Source{{1, 10}}, "Z"));
-  GlobalConst(Source{{2, 1}}, "X", ty.i32(), Expr(Source{{2, 10}}, "Y"));
-  GlobalConst(Source{{3, 1}}, "Z", ty.i32(), Expr(Source{{3, 10}}, "X"));
+    GlobalConst(Source{{1, 1}}, "Y", ty.i32(), Expr(Source{{1, 10}}, "Z"));
+    GlobalConst(Source{{2, 1}}, "X", ty.i32(), Expr(Source{{2, 10}}, "Y"));
+    GlobalConst(Source{{3, 1}}, "Z", ty.i32(), Expr(Source{{3, 10}}, "X"));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            R"(1:1 error: cyclic dependency found: 'Y' -> 'Z' -> 'X' -> 'Y'
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(1:1 error: cyclic dependency found: 'Y' -> 'Z' -> 'X' -> 'Y'
 1:10 note: let 'Y' references let 'Z' here
 3:10 note: let 'Z' references let 'X' here
 2:10 note: let 'X' references let 'Y' here)");
 }
 
 TEST_F(ResolverDependencyGraphCyclicRefTest, Mixed_RecursiveDependencies) {
-  // 1: fn F() -> R { return Z; }
-  // 2: type A = S;
-  // 3: struct S { a : A };
-  // 4: var Z = L;
-  // 5: type R = A;
-  // 6: let L : S = Z;
+    // 1: fn F() -> R { return Z; }
+    // 2: type A = S;
+    // 3: struct S { a : A };
+    // 4: var Z = L;
+    // 5: type R = A;
+    // 6: let L : S = Z;
 
-  Func(Source{{1, 1}}, "F", {}, ty.type_name(Source{{1, 5}}, "R"),
-       {Return(Expr(Source{{1, 10}}, "Z"))});
-  Alias(Source{{2, 1}}, "A", ty.type_name(Source{{2, 10}}, "S"));
-  Structure(Source{{3, 1}}, "S",
-            {Member("a", ty.type_name(Source{{3, 10}}, "A"))});
-  Global(Source{{4, 1}}, "Z", nullptr, Expr(Source{{4, 10}}, "L"));
-  Alias(Source{{5, 1}}, "R", ty.type_name(Source{{5, 10}}, "A"));
-  GlobalConst(Source{{6, 1}}, "L", ty.type_name(Source{{5, 5}}, "S"),
-              Expr(Source{{5, 10}}, "Z"));
+    Func(Source{{1, 1}}, "F", {}, ty.type_name(Source{{1, 5}}, "R"),
+         {Return(Expr(Source{{1, 10}}, "Z"))});
+    Alias(Source{{2, 1}}, "A", ty.type_name(Source{{2, 10}}, "S"));
+    Structure(Source{{3, 1}}, "S", {Member("a", ty.type_name(Source{{3, 10}}, "A"))});
+    Global(Source{{4, 1}}, "Z", nullptr, Expr(Source{{4, 10}}, "L"));
+    Alias(Source{{5, 1}}, "R", ty.type_name(Source{{5, 10}}, "A"));
+    GlobalConst(Source{{6, 1}}, "L", ty.type_name(Source{{5, 5}}, "S"), Expr(Source{{5, 10}}, "Z"));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            R"(2:1 error: cyclic dependency found: 'A' -> 'S' -> 'A'
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(2:1 error: cyclic dependency found: 'A' -> 'S' -> 'A'
 2:10 note: alias 'A' references struct 'S' here
 3:10 note: struct 'S' references alias 'A' here
 4:1 error: cyclic dependency found: 'Z' -> 'L' -> 'Z'
@@ -1008,40 +983,37 @@
 namespace redeclaration_tests {
 
 using ResolverDependencyGraphRedeclarationTest =
-    ResolverDependencyGraphTestWithParam<
-        std::tuple<SymbolDeclKind, SymbolDeclKind>>;
+    ResolverDependencyGraphTestWithParam<std::tuple<SymbolDeclKind, SymbolDeclKind>>;
 
 TEST_P(ResolverDependencyGraphRedeclarationTest, Test) {
-  const auto symbol = Sym("SYMBOL");
+    const auto symbol = Sym("SYMBOL");
 
-  auto a_kind = std::get<0>(GetParam());
-  auto b_kind = std::get<1>(GetParam());
+    auto a_kind = std::get<0>(GetParam());
+    auto b_kind = std::get<1>(GetParam());
 
-  auto a_source = Source{{12, 34}};
-  auto b_source = Source{{56, 78}};
+    auto a_source = Source{{12, 34}};
+    auto b_source = Source{{56, 78}};
 
-  if (a_kind != SymbolDeclKind::Parameter &&
-      b_kind == SymbolDeclKind::Parameter) {
-    std::swap(a_source, b_source);  // Parameters are declared before locals
-  }
+    if (a_kind != SymbolDeclKind::Parameter && b_kind == SymbolDeclKind::Parameter) {
+        std::swap(a_source, b_source);  // Parameters are declared before locals
+    }
 
-  SymbolTestHelper helper(this);
-  helper.Add(a_kind, symbol, a_source);
-  helper.Add(b_kind, symbol, b_source);
-  helper.Build();
+    SymbolTestHelper helper(this);
+    helper.Add(a_kind, symbol, a_source);
+    helper.Add(b_kind, symbol, b_source);
+    helper.Build();
 
-  bool error = ScopeDepth(a_kind) == ScopeDepth(b_kind);
+    bool error = ScopeDepth(a_kind) == ScopeDepth(b_kind);
 
-  Build(error ? R"(56:78 error: redeclaration of 'SYMBOL'
+    Build(error ? R"(56:78 error: redeclaration of 'SYMBOL'
 12:34 note: 'SYMBOL' previously declared here)"
-              : "");
+                : "");
 }
 
-INSTANTIATE_TEST_SUITE_P(
-    ResolverTest,
-    ResolverDependencyGraphRedeclarationTest,
-    testing::Combine(testing::ValuesIn(kAllSymbolDeclKinds),
-                     testing::ValuesIn(kAllSymbolDeclKinds)));
+INSTANTIATE_TEST_SUITE_P(ResolverTest,
+                         ResolverDependencyGraphRedeclarationTest,
+                         testing::Combine(testing::ValuesIn(kAllSymbolDeclKinds),
+                                          testing::ValuesIn(kAllSymbolDeclKinds)));
 
 }  // namespace redeclaration_tests
 
@@ -1051,45 +1023,44 @@
 namespace ordered_globals {
 
 using ResolverDependencyGraphOrderedGlobalsTest =
-    ResolverDependencyGraphTestWithParam<
-        std::tuple<SymbolDeclKind, SymbolUseKind>>;
+    ResolverDependencyGraphTestWithParam<std::tuple<SymbolDeclKind, SymbolUseKind>>;
 
 TEST_P(ResolverDependencyGraphOrderedGlobalsTest, InOrder) {
-  const Symbol symbol = Sym("SYMBOL");
-  const auto decl_kind = std::get<0>(GetParam());
-  const auto use_kind = std::get<1>(GetParam());
+    const Symbol symbol = Sym("SYMBOL");
+    const auto decl_kind = std::get<0>(GetParam());
+    const auto use_kind = std::get<1>(GetParam());
 
-  // Declaration before use
-  SymbolTestHelper helper(this);
-  helper.Add(decl_kind, symbol, Source{{12, 34}});
-  helper.Add(use_kind, symbol, Source{{56, 78}});
-  helper.Build();
+    // Declaration before use
+    SymbolTestHelper helper(this);
+    helper.Add(decl_kind, symbol, Source{{12, 34}});
+    helper.Add(use_kind, symbol, Source{{56, 78}});
+    helper.Build();
 
-  ASSERT_EQ(AST().GlobalDeclarations().size(), 2u);
+    ASSERT_EQ(AST().GlobalDeclarations().size(), 2u);
 
-  auto* decl = AST().GlobalDeclarations()[0];
-  auto* use = AST().GlobalDeclarations()[1];
-  EXPECT_THAT(Build().ordered_globals, ElementsAre(decl, use));
+    auto* decl = AST().GlobalDeclarations()[0];
+    auto* use = AST().GlobalDeclarations()[1];
+    EXPECT_THAT(Build().ordered_globals, ElementsAre(decl, use));
 }
 
 TEST_P(ResolverDependencyGraphOrderedGlobalsTest, OutOfOrder) {
-  const Symbol symbol = Sym("SYMBOL");
-  const auto decl_kind = std::get<0>(GetParam());
-  const auto use_kind = std::get<1>(GetParam());
+    const Symbol symbol = Sym("SYMBOL");
+    const auto decl_kind = std::get<0>(GetParam());
+    const auto use_kind = std::get<1>(GetParam());
 
-  // Use before declaration
-  SymbolTestHelper helper(this);
-  helper.Add(use_kind, symbol, Source{{56, 78}});
-  helper.Build();  // If the use is in a function, then ensure this function is
-                   // built before the symbol declaration
-  helper.Add(decl_kind, symbol, Source{{12, 34}});
-  helper.Build();
+    // Use before declaration
+    SymbolTestHelper helper(this);
+    helper.Add(use_kind, symbol, Source{{56, 78}});
+    helper.Build();  // If the use is in a function, then ensure this function is
+                     // built before the symbol declaration
+    helper.Add(decl_kind, symbol, Source{{12, 34}});
+    helper.Build();
 
-  ASSERT_EQ(AST().GlobalDeclarations().size(), 2u);
+    ASSERT_EQ(AST().GlobalDeclarations().size(), 2u);
 
-  auto* use = AST().GlobalDeclarations()[0];
-  auto* decl = AST().GlobalDeclarations()[1];
-  EXPECT_THAT(Build().ordered_globals, ElementsAre(decl, use));
+    auto* use = AST().GlobalDeclarations()[0];
+    auto* decl = AST().GlobalDeclarations()[1];
+    EXPECT_THAT(Build().ordered_globals, ElementsAre(decl, use));
 }
 
 INSTANTIATE_TEST_SUITE_P(Types,
@@ -1097,11 +1068,10 @@
                          testing::Combine(testing::ValuesIn(kTypeDeclKinds),
                                           testing::ValuesIn(kTypeUseKinds)));
 
-INSTANTIATE_TEST_SUITE_P(
-    Values,
-    ResolverDependencyGraphOrderedGlobalsTest,
-    testing::Combine(testing::ValuesIn(kGlobalValueDeclKinds),
-                     testing::ValuesIn(kValueUseKinds)));
+INSTANTIATE_TEST_SUITE_P(Values,
+                         ResolverDependencyGraphOrderedGlobalsTest,
+                         testing::Combine(testing::ValuesIn(kGlobalValueDeclKinds),
+                                          testing::ValuesIn(kValueUseKinds)));
 
 INSTANTIATE_TEST_SUITE_P(Functions,
                          ResolverDependencyGraphOrderedGlobalsTest,
@@ -1115,35 +1085,32 @@
 namespace resolved_symbols {
 
 using ResolverDependencyGraphResolvedSymbolTest =
-    ResolverDependencyGraphTestWithParam<
-        std::tuple<SymbolDeclKind, SymbolUseKind>>;
+    ResolverDependencyGraphTestWithParam<std::tuple<SymbolDeclKind, SymbolUseKind>>;
 
 TEST_P(ResolverDependencyGraphResolvedSymbolTest, Test) {
-  const Symbol symbol = Sym("SYMBOL");
-  const auto decl_kind = std::get<0>(GetParam());
-  const auto use_kind = std::get<1>(GetParam());
+    const Symbol symbol = Sym("SYMBOL");
+    const auto decl_kind = std::get<0>(GetParam());
+    const auto use_kind = std::get<1>(GetParam());
 
-  // Build a symbol declaration and a use of that symbol
-  SymbolTestHelper helper(this);
-  auto* decl = helper.Add(decl_kind, symbol, Source{{12, 34}});
-  auto* use = helper.Add(use_kind, symbol, Source{{56, 78}});
-  helper.Build();
+    // Build a symbol declaration and a use of that symbol
+    SymbolTestHelper helper(this);
+    auto* decl = helper.Add(decl_kind, symbol, Source{{12, 34}});
+    auto* use = helper.Add(use_kind, symbol, Source{{56, 78}});
+    helper.Build();
 
-  // If the declaration is visible to the use, then we expect the analysis to
-  // succeed.
-  bool expect_pass = ScopeDepth(decl_kind) <= ScopeDepth(use_kind);
-  auto graph =
-      Build(expect_pass ? "" : "56:78 error: unknown identifier: 'SYMBOL'");
+    // If the declaration is visible to the use, then we expect the analysis to
+    // succeed.
+    bool expect_pass = ScopeDepth(decl_kind) <= ScopeDepth(use_kind);
+    auto graph = Build(expect_pass ? "" : "56:78 error: unknown identifier: 'SYMBOL'");
 
-  if (expect_pass) {
-    // Check that the use resolves to the declaration
-    auto* resolved_symbol = graph.resolved_symbols[use];
-    EXPECT_EQ(resolved_symbol, decl)
-        << "resolved: "
-        << (resolved_symbol ? resolved_symbol->TypeInfo().name : "<null>")
-        << "\n"
-        << "decl:     " << decl->TypeInfo().name;
-  }
+    if (expect_pass) {
+        // Check that the use resolves to the declaration
+        auto* resolved_symbol = graph.resolved_symbols[use];
+        EXPECT_EQ(resolved_symbol, decl)
+            << "resolved: " << (resolved_symbol ? resolved_symbol->TypeInfo().name : "<null>")
+            << "\n"
+            << "decl:     " << decl->TypeInfo().name;
+    }
 }
 
 INSTANTIATE_TEST_SUITE_P(Types,
@@ -1168,30 +1135,26 @@
 ////////////////////////////////////////////////////////////////////////////////
 namespace shadowing {
 
-using ResolverDependencyShadowTest = ResolverDependencyGraphTestWithParam<
-    std::tuple<SymbolDeclKind, SymbolDeclKind>>;
+using ResolverDependencyShadowTest =
+    ResolverDependencyGraphTestWithParam<std::tuple<SymbolDeclKind, SymbolDeclKind>>;
 
 TEST_P(ResolverDependencyShadowTest, Test) {
-  const Symbol symbol = Sym("SYMBOL");
-  const auto outer_kind = std::get<0>(GetParam());
-  const auto inner_kind = std::get<1>(GetParam());
+    const Symbol symbol = Sym("SYMBOL");
+    const auto outer_kind = std::get<0>(GetParam());
+    const auto inner_kind = std::get<1>(GetParam());
 
-  // Build a symbol declaration and a use of that symbol
-  SymbolTestHelper helper(this);
-  auto* outer = helper.Add(outer_kind, symbol, Source{{12, 34}});
-  helper.Add(inner_kind, symbol, Source{{56, 78}});
-  auto* inner_var = helper.nested_statements.size()
-                        ? helper.nested_statements[0]
-                              ->As<ast::VariableDeclStatement>()
-                              ->variable
-                        : helper.statements.size()
-                              ? helper.statements[0]
-                                    ->As<ast::VariableDeclStatement>()
-                                    ->variable
-                              : helper.parameters[0];
-  helper.Build();
+    // Build a symbol declaration and a use of that symbol
+    SymbolTestHelper helper(this);
+    auto* outer = helper.Add(outer_kind, symbol, Source{{12, 34}});
+    helper.Add(inner_kind, symbol, Source{{56, 78}});
+    auto* inner_var = helper.nested_statements.size()
+                          ? helper.nested_statements[0]->As<ast::VariableDeclStatement>()->variable
+                      : helper.statements.size()
+                          ? helper.statements[0]->As<ast::VariableDeclStatement>()->variable
+                          : helper.parameters[0];
+    helper.Build();
 
-  EXPECT_EQ(Build().shadows[inner_var], outer);
+    EXPECT_EQ(Build().shadows[inner_var], outer);
 }
 
 INSTANTIATE_TEST_SUITE_P(LocalShadowGlobal,
@@ -1199,14 +1162,13 @@
                          testing::Combine(testing::ValuesIn(kGlobalDeclKinds),
                                           testing::ValuesIn(kLocalDeclKinds)));
 
-INSTANTIATE_TEST_SUITE_P(
-    NestedLocalShadowLocal,
-    ResolverDependencyShadowTest,
-    testing::Combine(testing::Values(SymbolDeclKind::Parameter,
-                                     SymbolDeclKind::LocalVar,
-                                     SymbolDeclKind::LocalLet),
-                     testing::Values(SymbolDeclKind::NestedLocalVar,
-                                     SymbolDeclKind::NestedLocalLet)));
+INSTANTIATE_TEST_SUITE_P(NestedLocalShadowLocal,
+                         ResolverDependencyShadowTest,
+                         testing::Combine(testing::Values(SymbolDeclKind::Parameter,
+                                                          SymbolDeclKind::LocalVar,
+                                                          SymbolDeclKind::LocalLet),
+                                          testing::Values(SymbolDeclKind::NestedLocalVar,
+                                                          SymbolDeclKind::NestedLocalLet)));
 
 }  // namespace shadowing
 
@@ -1218,120 +1180,116 @@
 using ResolverDependencyGraphTraversalTest = ResolverDependencyGraphTest;
 
 TEST_F(ResolverDependencyGraphTraversalTest, SymbolsReached) {
-  const auto value_sym = Sym("VALUE");
-  const auto type_sym = Sym("TYPE");
-  const auto func_sym = Sym("FUNC");
+    const auto value_sym = Sym("VALUE");
+    const auto type_sym = Sym("TYPE");
+    const auto func_sym = Sym("FUNC");
 
-  const auto* value_decl =
-      Global(value_sym, ty.i32(), ast::StorageClass::kPrivate);
-  const auto* type_decl = Alias(type_sym, ty.i32());
-  const auto* func_decl = Func(func_sym, {}, ty.void_(), {});
+    const auto* value_decl = Global(value_sym, ty.i32(), ast::StorageClass::kPrivate);
+    const auto* type_decl = Alias(type_sym, ty.i32());
+    const auto* func_decl = Func(func_sym, {}, ty.void_(), {});
 
-  struct SymbolUse {
-    const ast::Node* decl = nullptr;
-    const ast::Node* use = nullptr;
-    std::string where;
-  };
+    struct SymbolUse {
+        const ast::Node* decl = nullptr;
+        const ast::Node* use = nullptr;
+        std::string where;
+    };
 
-  std::vector<SymbolUse> symbol_uses;
+    std::vector<SymbolUse> symbol_uses;
 
-  auto add_use = [&](const ast::Node* decl, auto* use, int line,
-                     const char* kind) {
-    symbol_uses.emplace_back(SymbolUse{
-        decl, use,
-        std::string(__FILE__) + ":" + std::to_string(line) + ": " + kind});
-    return use;
-  };
+    auto add_use = [&](const ast::Node* decl, auto* use, int line, const char* kind) {
+        symbol_uses.emplace_back(
+            SymbolUse{decl, use, std::string(__FILE__) + ":" + std::to_string(line) + ": " + kind});
+        return use;
+    };
 #define V add_use(value_decl, Expr(value_sym), __LINE__, "V()")
 #define T add_use(type_decl, ty.type_name(type_sym), __LINE__, "T()")
 #define F add_use(func_decl, Expr(func_sym), __LINE__, "F()")
 
-  Alias(Sym(), T);
-  Structure(Sym(), {Member(Sym(), T)});
-  Global(Sym(), T, V);
-  GlobalConst(Sym(), T, V);
-  Func(Sym(),              //
-       {Param(Sym(), T)},  //
-       T,                  // Return type
-       {
-           Decl(Var(Sym(), T, V)),                    //
-           Decl(Const(Sym(), T, V)),                  //
-           CallStmt(Call(F, V)),                      //
-           Block(                                     //
-               Assign(V, V)),                         //
-           If(V,                                      //
-              Block(Assign(V, V)),                    //
-              Else(V,                                 //
-                   Block(Assign(V, V)))),             //
-           Ignore(Bitcast(T, V)),                     //
-           For(Decl(Var(Sym(), T, V)),                //
-               Equal(V, V),                           //
-               Assign(V, V),                          //
-               Block(                                 //
-                   Assign(V, V))),                    //
-           Loop(Block(Assign(V, V)),                  //
-                Block(Assign(V, V))),                 //
-           Switch(V,                                  //
-                  Case(Expr(1),                       //
-                       Block(Assign(V, V))),          //
-                  Case(Expr(2),                       //
-                       Block(Fallthrough())),         //
-                  DefaultCase(Block(Assign(V, V)))),  //
-           Return(V),                                 //
-           Break(),                                   //
-           Discard(),                                 //
-       });                                            //
-  // Exercise type traversal
-  Global(Sym(), ty.atomic(T));
-  Global(Sym(), ty.bool_());
-  Global(Sym(), ty.i32());
-  Global(Sym(), ty.u32());
-  Global(Sym(), ty.f32());
-  Global(Sym(), ty.array(T, V, 4));
-  Global(Sym(), ty.vec3(T));
-  Global(Sym(), ty.mat3x2(T));
-  Global(Sym(), ty.pointer(T, ast::StorageClass::kPrivate));
-  Global(Sym(), ty.sampled_texture(ast::TextureDimension::k2d, T));
-  Global(Sym(), ty.depth_texture(ast::TextureDimension::k2d));
-  Global(Sym(), ty.depth_multisampled_texture(ast::TextureDimension::k2d));
-  Global(Sym(), ty.external_texture());
-  Global(Sym(), ty.multisampled_texture(ast::TextureDimension::k2d, T));
-  Global(Sym(), ty.storage_texture(ast::TextureDimension::k2d,
-                                   ast::TexelFormat::kR32Float,
-                                   ast::Access::kRead));  //
-  Global(Sym(), ty.sampler(ast::SamplerKind::kSampler));
-  Func(Sym(), {}, ty.void_(), {});
+    Alias(Sym(), T);
+    Structure(Sym(), {Member(Sym(), T)});
+    Global(Sym(), T, V);
+    GlobalConst(Sym(), T, V);
+    Func(Sym(),              //
+         {Param(Sym(), T)},  //
+         T,                  // Return type
+         {
+             Decl(Var(Sym(), T, V)),                    //
+             Decl(Let(Sym(), T, V)),                    //
+             CallStmt(Call(F, V)),                      //
+             Block(                                     //
+                 Assign(V, V)),                         //
+             If(V,                                      //
+                Block(Assign(V, V)),                    //
+                Else(If(V,                              //
+                        Block(Assign(V, V))))),         //
+             Ignore(Bitcast(T, V)),                     //
+             For(Decl(Var(Sym(), T, V)),                //
+                 Equal(V, V),                           //
+                 Assign(V, V),                          //
+                 Block(                                 //
+                     Assign(V, V))),                    //
+             Loop(Block(Assign(V, V)),                  //
+                  Block(Assign(V, V))),                 //
+             Switch(V,                                  //
+                    Case(Expr(1_i),                     //
+                         Block(Assign(V, V))),          //
+                    Case(Expr(2_i),                     //
+                         Block(Fallthrough())),         //
+                    DefaultCase(Block(Assign(V, V)))),  //
+             Return(V),                                 //
+             Break(),                                   //
+             Discard(),                                 //
+         });                                            //
+    // Exercise type traversal
+    Global(Sym(), ty.atomic(T));
+    Global(Sym(), ty.bool_());
+    Global(Sym(), ty.i32());
+    Global(Sym(), ty.u32());
+    Global(Sym(), ty.f32());
+    Global(Sym(), ty.array(T, V, 4));
+    Global(Sym(), ty.vec3(T));
+    Global(Sym(), ty.mat3x2(T));
+    Global(Sym(), ty.pointer(T, ast::StorageClass::kPrivate));
+    Global(Sym(), ty.sampled_texture(ast::TextureDimension::k2d, T));
+    Global(Sym(), ty.depth_texture(ast::TextureDimension::k2d));
+    Global(Sym(), ty.depth_multisampled_texture(ast::TextureDimension::k2d));
+    Global(Sym(), ty.external_texture());
+    Global(Sym(), ty.multisampled_texture(ast::TextureDimension::k2d, T));
+    Global(Sym(), ty.storage_texture(ast::TextureDimension::k2d, ast::TexelFormat::kR32Float,
+                                     ast::Access::kRead));  //
+    Global(Sym(), ty.sampler(ast::SamplerKind::kSampler));
+    Func(Sym(), {}, ty.void_(), {});
 #undef V
 #undef T
 #undef F
 
-  auto graph = Build();
-  for (auto use : symbol_uses) {
-    auto* resolved_symbol = graph.resolved_symbols[use.use];
-    EXPECT_EQ(resolved_symbol, use.decl) << use.where;
-  }
+    auto graph = Build();
+    for (auto use : symbol_uses) {
+        auto* resolved_symbol = graph.resolved_symbols[use.use];
+        EXPECT_EQ(resolved_symbol, use.decl) << use.where;
+    }
 }
 
 TEST_F(ResolverDependencyGraphTraversalTest, InferredType) {
-  // Check that the nullptr of the var / let type doesn't make things explode
-  Global("a", nullptr, Expr(1));
-  GlobalConst("b", nullptr, Expr(1));
-  WrapInFunction(Var("c", nullptr, Expr(1)),  //
-                 Const("d", nullptr, Expr(1)));
-  Build();
+    // Check that the nullptr of the var / let type doesn't make things explode
+    Global("a", nullptr, Expr(1_i));
+    GlobalConst("b", nullptr, Expr(1_i));
+    WrapInFunction(Var("c", nullptr, Expr(1_i)),  //
+                   Let("d", nullptr, Expr(1_i)));
+    Build();
 }
 
 // Reproduces an unbalanced stack push / pop bug in
 // DependencyAnalysis::SortGlobals(), found by clusterfuzz.
 // See: crbug.com/chromium/1273451
 TEST_F(ResolverDependencyGraphTraversalTest, chromium_1273451) {
-  Structure("A", {Member("a", ty.i32())});
-  Structure("B", {Member("b", ty.i32())});
-  Func("f", {Param("a", ty.type_name("A"))}, ty.type_name("B"),
-       {
-           Return(Construct(ty.type_name("B"))),
-       });
-  Build();
+    Structure("A", {Member("a", ty.i32())});
+    Structure("B", {Member("b", ty.i32())});
+    Func("f", {Param("a", ty.type_name("A"))}, ty.type_name("B"),
+         {
+             Return(Construct(ty.type_name("B"))),
+         });
+    Build();
 }
 
 }  // namespace ast_traversal
diff --git a/src/tint/resolver/entry_point_validation_test.cc b/src/tint/resolver/entry_point_validation_test.cc
index 8458a10..d1d9a48 100644
--- a/src/tint/resolver/entry_point_validation_test.cc
+++ b/src/tint/resolver/entry_point_validation_test.cc
@@ -21,6 +21,8 @@
 
 #include "gmock/gmock.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::resolver {
 namespace {
 
@@ -41,311 +43,278 @@
 using mat4x4 = builder::mat4x4<T>;
 template <typename T>
 using alias = builder::alias<T>;
-using f32 = builder::f32;
-using i32 = builder::i32;
-using u32 = builder::u32;
 
-class ResolverEntryPointValidationTest : public TestHelper,
-                                         public testing::Test {};
+class ResolverEntryPointValidationTest : public TestHelper, public testing::Test {};
 
 TEST_F(ResolverEntryPointValidationTest, ReturnTypeAttribute_Location) {
-  // @stage(fragment)
-  // fn main() -> @location(0) f32 { return 1.0; }
-  Func(Source{{12, 34}}, "main", {}, ty.f32(), {Return(1.0f)},
-       {Stage(ast::PipelineStage::kFragment)}, {Location(0)});
+    // @stage(fragment)
+    // fn main() -> @location(0) f32 { return 1.0; }
+    Func(Source{{12, 34}}, "main", {}, ty.f32(), {Return(1.0f)},
+         {Stage(ast::PipelineStage::kFragment)}, {Location(0)});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverEntryPointValidationTest, ReturnTypeAttribute_Builtin) {
-  // @stage(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(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)});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverEntryPointValidationTest, ReturnTypeAttribute_Missing) {
-  // @stage(vertex)
-  // fn main() -> f32 {
-  //   return 1.0;
-  // }
-  Func(Source{{12, 34}}, "main", {}, ty.vec4<f32>(),
-       {Return(Construct(ty.vec4<f32>()))},
-       {Stage(ast::PipelineStage::kVertex)});
+    // @stage(vertex)
+    // fn main() -> f32 {
+    //   return 1.0;
+    // }
+    Func(Source{{12, 34}}, "main", {}, ty.vec4<f32>(), {Return(Construct(ty.vec4<f32>()))},
+         {Stage(ast::PipelineStage::kVertex)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: missing entry point IO attribute on return type");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: missing entry point IO attribute on return type");
 }
 
 TEST_F(ResolverEntryPointValidationTest, ReturnTypeAttribute_Multiple) {
-  // @stage(vertex)
-  // fn main() -> @location(0) @builtin(position) vec4<f32> {
-  //   return vec4<f32>();
-  // }
-  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)});
+    // @stage(vertex)
+    // fn main() -> @location(0) @builtin(position) vec4<f32> {
+    //   return vec4<f32>();
+    // }
+    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)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), R"(14:52 error: multiple entry point IO attributes
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), R"(14:52 error: multiple entry point IO attributes
 13:43 note: previously consumed location(0))");
 }
 
 TEST_F(ResolverEntryPointValidationTest, ReturnType_Struct_Valid) {
-  // struct Output {
-  //   @location(0) a : f32;
-  //   @builtin(frag_depth) b : f32;
-  // };
-  // @stage(fragment)
-  // fn main() -> Output {
-  //   return Output();
-  // }
-  auto* output = Structure(
-      "Output", {Member("a", ty.f32(), {Location(0)}),
-                 Member("b", ty.f32(), {Builtin(ast::Builtin::kFragDepth)})});
-  Func(Source{{12, 34}}, "main", {}, ty.Of(output),
-       {Return(Construct(ty.Of(output)))},
-       {Stage(ast::PipelineStage::kFragment)});
+    // struct Output {
+    //   @location(0) a : f32;
+    //   @builtin(frag_depth) b : f32;
+    // };
+    // @stage(fragment)
+    // fn main() -> Output {
+    //   return Output();
+    // }
+    auto* output =
+        Structure("Output", {Member("a", ty.f32(), {Location(0)}),
+                             Member("b", ty.f32(), {Builtin(ast::Builtin::kFragDepth)})});
+    Func(Source{{12, 34}}, "main", {}, ty.Of(output), {Return(Construct(ty.Of(output)))},
+         {Stage(ast::PipelineStage::kFragment)});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
-TEST_F(ResolverEntryPointValidationTest,
-       ReturnType_Struct_MemberMultipleAttributes) {
-  // struct Output {
-  //   @location(0) @builtin(frag_depth) a : f32;
-  // };
-  // @stage(fragment)
-  // fn main() -> Output {
-  //   return Output();
-  // }
-  auto* output = Structure(
-      "Output",
-      {Member("a", ty.f32(),
-              {Location(Source{{13, 43}}, 0),
-               Builtin(Source{{14, 52}}, ast::Builtin::kFragDepth)})});
-  Func(Source{{12, 34}}, "main", {}, ty.Of(output),
-       {Return(Construct(ty.Of(output)))},
-       {Stage(ast::PipelineStage::kFragment)});
+TEST_F(ResolverEntryPointValidationTest, ReturnType_Struct_MemberMultipleAttributes) {
+    // struct Output {
+    //   @location(0) @builtin(frag_depth) a : f32;
+    // };
+    // @stage(fragment)
+    // fn main() -> Output {
+    //   return Output();
+    // }
+    auto* output =
+        Structure("Output", {Member("a", ty.f32(),
+                                    {Location(Source{{13, 43}}, 0),
+                                     Builtin(Source{{14, 52}}, ast::Builtin::kFragDepth)})});
+    Func(Source{{12, 34}}, "main", {}, ty.Of(output), {Return(Construct(ty.Of(output)))},
+         {Stage(ast::PipelineStage::kFragment)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), R"(14:52 error: multiple entry point IO attributes
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), R"(14:52 error: multiple entry point IO attributes
 13:43 note: previously consumed location(0)
 12:34 note: while analysing entry point 'main')");
 }
 
-TEST_F(ResolverEntryPointValidationTest,
-       ReturnType_Struct_MemberMissingAttribute) {
-  // struct Output {
-  //   @location(0) a : f32;
-  //   b : f32;
-  // };
-  // @stage(fragment)
-  // fn main() -> Output {
-  //   return Output();
-  // }
-  auto* output = Structure(
-      "Output", {Member(Source{{13, 43}}, "a", ty.f32(), {Location(0)}),
-                 Member(Source{{14, 52}}, "b", ty.f32(), {})});
-  Func(Source{{12, 34}}, "main", {}, ty.Of(output),
-       {Return(Construct(ty.Of(output)))},
-       {Stage(ast::PipelineStage::kFragment)});
+TEST_F(ResolverEntryPointValidationTest, ReturnType_Struct_MemberMissingAttribute) {
+    // struct Output {
+    //   @location(0) a : f32;
+    //   b : f32;
+    // };
+    // @stage(fragment)
+    // fn main() -> Output {
+    //   return Output();
+    // }
+    auto* output = Structure("Output", {Member(Source{{13, 43}}, "a", ty.f32(), {Location(0)}),
+                                        Member(Source{{14, 52}}, "b", ty.f32(), {})});
+    Func(Source{{12, 34}}, "main", {}, ty.Of(output), {Return(Construct(ty.Of(output)))},
+         {Stage(ast::PipelineStage::kFragment)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            R"(14:52 error: missing entry point IO attribute
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(14:52 error: missing entry point IO attribute
 12:34 note: while analysing entry point 'main')");
 }
 
 TEST_F(ResolverEntryPointValidationTest, ReturnType_Struct_DuplicateBuiltins) {
-  // struct Output {
-  //   @builtin(frag_depth) a : f32;
-  //   @builtin(frag_depth) b : f32;
-  // };
-  // @stage(fragment)
-  // fn main() -> Output {
-  //   return Output();
-  // }
-  auto* output = Structure(
-      "Output", {Member("a", ty.f32(), {Builtin(ast::Builtin::kFragDepth)}),
-                 Member("b", ty.f32(), {Builtin(ast::Builtin::kFragDepth)})});
-  Func(Source{{12, 34}}, "main", {}, ty.Of(output),
-       {Return(Construct(ty.Of(output)))},
-       {Stage(ast::PipelineStage::kFragment)});
+    // struct Output {
+    //   @builtin(frag_depth) a : f32;
+    //   @builtin(frag_depth) b : f32;
+    // };
+    // @stage(fragment)
+    // fn main() -> Output {
+    //   return Output();
+    // }
+    auto* output =
+        Structure("Output", {Member("a", ty.f32(), {Builtin(ast::Builtin::kFragDepth)}),
+                             Member("b", ty.f32(), {Builtin(ast::Builtin::kFragDepth)})});
+    Func(Source{{12, 34}}, "main", {}, ty.Of(output), {Return(Construct(ty.Of(output)))},
+         {Stage(ast::PipelineStage::kFragment)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: builtin(frag_depth) attribute appears multiple times as pipeline output
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(
+        r()->error(),
+        R"(12:34 error: builtin(frag_depth) attribute appears multiple times as pipeline output
 12:34 note: while analysing entry point 'main')");
 }
 
 TEST_F(ResolverEntryPointValidationTest, ParameterAttribute_Location) {
-  // @stage(fragment)
-  // fn main(@location(0) param : f32) {}
-  auto* param = Param("param", ty.f32(), {Location(0)});
-  Func(Source{{12, 34}}, "main", {param}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kFragment)});
+    // @stage(fragment)
+    // fn main(@location(0) param : f32) {}
+    auto* param = Param("param", ty.f32(), {Location(0)});
+    Func(Source{{12, 34}}, "main", {param}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverEntryPointValidationTest, ParameterAttribute_Missing) {
-  // @stage(fragment)
-  // fn main(param : f32) {}
-  auto* param = Param(Source{{13, 43}}, "param", ty.vec4<f32>());
-  Func(Source{{12, 34}}, "main", {param}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kFragment)});
+    // @stage(fragment)
+    // fn main(param : f32) {}
+    auto* param = Param(Source{{13, 43}}, "param", ty.vec4<f32>());
+    Func(Source{{12, 34}}, "main", {param}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "13:43 error: missing entry point IO attribute on parameter");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "13:43 error: missing entry point IO attribute on parameter");
 }
 
 TEST_F(ResolverEntryPointValidationTest, ParameterAttribute_Multiple) {
-  // @stage(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)});
-  Func(Source{{12, 34}}, "main", {param}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kFragment)});
+    // @stage(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)});
+    Func(Source{{12, 34}}, "main", {param}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), R"(14:52 error: multiple entry point IO attributes
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), R"(14:52 error: multiple entry point IO attributes
 13:43 note: previously consumed location(0))");
 }
 
 TEST_F(ResolverEntryPointValidationTest, Parameter_Struct_Valid) {
-  // struct Input {
-  //   @location(0) a : f32;
-  //   @builtin(sample_index) b : u32;
-  // };
-  // @stage(fragment)
-  // fn main(param : Input) {}
-  auto* input = Structure(
-      "Input", {Member("a", ty.f32(), {Location(0)}),
-                Member("b", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)})});
-  auto* param = Param("param", ty.Of(input));
-  Func(Source{{12, 34}}, "main", {param}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kFragment)});
+    // struct Input {
+    //   @location(0) a : f32;
+    //   @builtin(sample_index) b : u32;
+    // };
+    // @stage(fragment)
+    // fn main(param : Input) {}
+    auto* input =
+        Structure("Input", {Member("a", ty.f32(), {Location(0)}),
+                            Member("b", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)})});
+    auto* param = Param("param", ty.Of(input));
+    Func(Source{{12, 34}}, "main", {param}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
-TEST_F(ResolverEntryPointValidationTest,
-       Parameter_Struct_MemberMultipleAttributes) {
-  // struct Input {
-  //   @location(0) @builtin(sample_index) a : u32;
-  // };
-  // @stage(fragment)
-  // fn main(param : Input) {}
-  auto* input = Structure(
-      "Input",
-      {Member("a", ty.u32(),
-              {Location(Source{{13, 43}}, 0),
-               Builtin(Source{{14, 52}}, ast::Builtin::kSampleIndex)})});
-  auto* param = Param("param", ty.Of(input));
-  Func(Source{{12, 34}}, "main", {param}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kFragment)});
+TEST_F(ResolverEntryPointValidationTest, Parameter_Struct_MemberMultipleAttributes) {
+    // struct Input {
+    //   @location(0) @builtin(sample_index) a : u32;
+    // };
+    // @stage(fragment)
+    // fn main(param : Input) {}
+    auto* input =
+        Structure("Input", {Member("a", ty.u32(),
+                                   {Location(Source{{13, 43}}, 0),
+                                    Builtin(Source{{14, 52}}, ast::Builtin::kSampleIndex)})});
+    auto* param = Param("param", ty.Of(input));
+    Func(Source{{12, 34}}, "main", {param}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), R"(14:52 error: multiple entry point IO attributes
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), R"(14:52 error: multiple entry point IO attributes
 13:43 note: previously consumed location(0)
 12:34 note: while analysing entry point 'main')");
 }
 
-TEST_F(ResolverEntryPointValidationTest,
-       Parameter_Struct_MemberMissingAttribute) {
-  // struct Input {
-  //   @location(0) a : f32;
-  //   b : f32;
-  // };
-  // @stage(fragment)
-  // fn main(param : Input) {}
-  auto* input = Structure(
-      "Input", {Member(Source{{13, 43}}, "a", ty.f32(), {Location(0)}),
-                Member(Source{{14, 52}}, "b", ty.f32(), {})});
-  auto* param = Param("param", ty.Of(input));
-  Func(Source{{12, 34}}, "main", {param}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kFragment)});
+TEST_F(ResolverEntryPointValidationTest, Parameter_Struct_MemberMissingAttribute) {
+    // struct Input {
+    //   @location(0) a : f32;
+    //   b : f32;
+    // };
+    // @stage(fragment)
+    // fn main(param : Input) {}
+    auto* input = Structure("Input", {Member(Source{{13, 43}}, "a", ty.f32(), {Location(0)}),
+                                      Member(Source{{14, 52}}, "b", ty.f32(), {})});
+    auto* param = Param("param", ty.Of(input));
+    Func(Source{{12, 34}}, "main", {param}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), R"(14:52 error: missing entry point IO attribute
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), R"(14:52 error: missing entry point IO attribute
 12:34 note: while analysing entry point 'main')");
 }
 
 TEST_F(ResolverEntryPointValidationTest, Parameter_DuplicateBuiltins) {
-  // @stage(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)});
-  Func(Source{{12, 34}}, "main", {param_a, param_b}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kFragment)});
+    // @stage(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)});
+    Func(Source{{12, 34}}, "main", {param_a, param_b}, ty.void_(), {},
+         {Stage(ast::PipelineStage::kFragment)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: builtin(sample_index) attribute appears multiple times as "
-      "pipeline input");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: builtin(sample_index) attribute appears multiple times as "
+              "pipeline input");
 }
 
 TEST_F(ResolverEntryPointValidationTest, Parameter_Struct_DuplicateBuiltins) {
-  // struct InputA {
-  //   @builtin(sample_index) a : u32;
-  // };
-  // struct InputB {
-  //   @builtin(sample_index) a : u32;
-  // };
-  // @stage(fragment)
-  // fn main(param_a : InputA, param_b : InputB) {}
-  auto* input_a = Structure(
-      "InputA", {Member("a", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)})});
-  auto* input_b = Structure(
-      "InputB", {Member("a", ty.u32(), {Builtin(ast::Builtin::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_(), {},
-       {Stage(ast::PipelineStage::kFragment)});
+    // struct InputA {
+    //   @builtin(sample_index) a : u32;
+    // };
+    // struct InputB {
+    //   @builtin(sample_index) a : u32;
+    // };
+    // @stage(fragment)
+    // fn main(param_a : InputA, param_b : InputB) {}
+    auto* input_a =
+        Structure("InputA", {Member("a", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)})});
+    auto* input_b =
+        Structure("InputB", {Member("a", ty.u32(), {Builtin(ast::Builtin::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_(), {},
+         {Stage(ast::PipelineStage::kFragment)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: builtin(sample_index) attribute appears multiple times as pipeline input
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(
+        r()->error(),
+        R"(12:34 error: builtin(sample_index) attribute appears multiple times as pipeline input
 12:34 note: while analysing entry point 'main')");
 }
 
 TEST_F(ResolverEntryPointValidationTest, VertexShaderMustReturnPosition) {
-  // @stage(vertex)
-  // fn main() {}
-  Func(Source{{12, 34}}, "main", {}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kVertex)});
+    // @stage(vertex)
+    // fn main() {}
+    Func(Source{{12, 34}}, "main", {}, ty.void_(), {}, {Stage(ast::PipelineStage::kVertex)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: a vertex shader must include the 'position' builtin "
-            "in its return type");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: a vertex shader must include the 'position' builtin "
+              "in its return type");
 }
 
 namespace TypeValidationTests {
 struct Params {
-  builder::ast_type_func_ptr create_ast_type;
-  bool is_valid;
+    builder::ast_type_func_ptr create_ast_type;
+    bool is_valid;
 };
 
 template <typename T>
 constexpr Params ParamsFor(bool is_valid) {
-  return Params{DataType<T>::AST, is_valid};
+    return Params{DataType<T>::AST, is_valid};
 }
 
 using TypeValidationTest = resolver::ResolverTestWithParam<Params>;
@@ -368,77 +337,73 @@
 };
 
 TEST_P(TypeValidationTest, BareInputs) {
-  // @stage(fragment)
-  // fn main(@location(0) @interpolate(flat) a : *) {}
-  auto params = GetParam();
-  auto* a = Param("a", params.create_ast_type(*this), {Location(0), Flat()});
-  Func(Source{{12, 34}}, "main", {a}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kFragment)});
+    // @stage(fragment)
+    // fn main(@location(0) @interpolate(flat) a : *) {}
+    auto params = GetParam();
+    auto* a = Param("a", params.create_ast_type(*this), {Location(0), Flat()});
+    Func(Source{{12, 34}}, "main", {a}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
 
-  if (params.is_valid) {
-    EXPECT_TRUE(r()->Resolve()) << r()->error();
-  } else {
-    EXPECT_FALSE(r()->Resolve());
-  }
+    if (params.is_valid) {
+        EXPECT_TRUE(r()->Resolve()) << r()->error();
+    } else {
+        EXPECT_FALSE(r()->Resolve());
+    }
 }
 
 TEST_P(TypeValidationTest, StructInputs) {
-  // struct Input {
-  //   @location(0) @interpolate(flat) a : *;
-  // };
-  // @stage(fragment)
-  // fn main(a : Input) {}
-  auto params = GetParam();
-  auto* input = Structure("Input", {Member("a", params.create_ast_type(*this),
-                                           {Location(0), Flat()})});
-  auto* a = Param("a", ty.Of(input), {});
-  Func(Source{{12, 34}}, "main", {a}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kFragment)});
+    // struct Input {
+    //   @location(0) @interpolate(flat) a : *;
+    // };
+    // @stage(fragment)
+    // fn main(a : Input) {}
+    auto params = GetParam();
+    auto* input =
+        Structure("Input", {Member("a", params.create_ast_type(*this), {Location(0), Flat()})});
+    auto* a = Param("a", ty.Of(input), {});
+    Func(Source{{12, 34}}, "main", {a}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
 
-  if (params.is_valid) {
-    EXPECT_TRUE(r()->Resolve()) << r()->error();
-  } else {
-    EXPECT_FALSE(r()->Resolve());
-  }
+    if (params.is_valid) {
+        EXPECT_TRUE(r()->Resolve()) << r()->error();
+    } else {
+        EXPECT_FALSE(r()->Resolve());
+    }
 }
 
 TEST_P(TypeValidationTest, BareOutputs) {
-  // @stage(fragment)
-  // fn main() -> @location(0) * {
-  //   return *();
-  // }
-  auto params = GetParam();
-  Func(Source{{12, 34}}, "main", {}, params.create_ast_type(*this),
-       {Return(Construct(params.create_ast_type(*this)))},
-       {Stage(ast::PipelineStage::kFragment)}, {Location(0)});
+    // @stage(fragment)
+    // fn main() -> @location(0) * {
+    //   return *();
+    // }
+    auto params = GetParam();
+    Func(Source{{12, 34}}, "main", {}, params.create_ast_type(*this),
+         {Return(Construct(params.create_ast_type(*this)))}, {Stage(ast::PipelineStage::kFragment)},
+         {Location(0)});
 
-  if (params.is_valid) {
-    EXPECT_TRUE(r()->Resolve()) << r()->error();
-  } else {
-    EXPECT_FALSE(r()->Resolve());
-  }
+    if (params.is_valid) {
+        EXPECT_TRUE(r()->Resolve()) << r()->error();
+    } else {
+        EXPECT_FALSE(r()->Resolve());
+    }
 }
 
 TEST_P(TypeValidationTest, StructOutputs) {
-  // struct Output {
-  //   @location(0) a : *;
-  // };
-  // @stage(fragment)
-  // fn main() -> Output {
-  //   return Output();
-  // }
-  auto params = GetParam();
-  auto* output = Structure(
-      "Output", {Member("a", params.create_ast_type(*this), {Location(0)})});
-  Func(Source{{12, 34}}, "main", {}, ty.Of(output),
-       {Return(Construct(ty.Of(output)))},
-       {Stage(ast::PipelineStage::kFragment)});
+    // struct Output {
+    //   @location(0) a : *;
+    // };
+    // @stage(fragment)
+    // fn main() -> Output {
+    //   return Output();
+    // }
+    auto params = GetParam();
+    auto* output = Structure("Output", {Member("a", params.create_ast_type(*this), {Location(0)})});
+    Func(Source{{12, 34}}, "main", {}, ty.Of(output), {Return(Construct(ty.Of(output)))},
+         {Stage(ast::PipelineStage::kFragment)});
 
-  if (params.is_valid) {
-    EXPECT_TRUE(r()->Resolve()) << r()->error();
-  } else {
-    EXPECT_FALSE(r()->Resolve());
-  }
+    if (params.is_valid) {
+        EXPECT_TRUE(r()->Resolve()) << r()->error();
+    } else {
+        EXPECT_FALSE(r()->Resolve());
+    }
 }
 INSTANTIATE_TEST_SUITE_P(ResolverEntryPointValidationTest,
                          TypeValidationTest,
@@ -451,341 +416,317 @@
 using LocationAttributeTests = ResolverTest;
 
 TEST_F(LocationAttributeTests, Pass) {
-  // @stage(fragment)
-  // fn frag_main(@location(0) @interpolate(flat) a: i32) {}
+    // @stage(fragment)
+    // fn frag_main(@location(0) @interpolate(flat) a: i32) {}
 
-  auto* p = Param(Source{{12, 34}}, "a", ty.i32(), {Location(0), Flat()});
-  Func("frag_main", {p}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kFragment)});
+    auto* p = Param(Source{{12, 34}}, "a", ty.i32(), {Location(0), Flat()});
+    Func("frag_main", {p}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(LocationAttributeTests, BadType_Input_bool) {
-  // @stage(fragment)
-  // fn frag_main(@location(0) a: bool) {}
+    // @stage(fragment)
+    // fn frag_main(@location(0) a: bool) {}
 
-  auto* p =
-      Param(Source{{12, 34}}, "a", ty.bool_(), {Location(Source{{34, 56}}, 0)});
-  Func("frag_main", {p}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kFragment)});
+    auto* p = Param(Source{{12, 34}}, "a", ty.bool_(), {Location(Source{{34, 56}}, 0)});
+    Func("frag_main", {p}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: cannot apply 'location' attribute to declaration of "
-            "type 'bool'\n"
-            "34:56 note: 'location' attribute must only be applied to "
-            "declarations of numeric scalar or numeric vector type");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: cannot apply 'location' attribute to declaration of "
+              "type 'bool'\n"
+              "34:56 note: 'location' attribute must only be applied to "
+              "declarations of numeric scalar or numeric vector type");
 }
 
 TEST_F(LocationAttributeTests, BadType_Output_Array) {
-  // @stage(fragment)
-  // fn frag_main()->@location(0) array<f32, 2> { return array<f32, 2>(); }
+    // @stage(fragment)
+    // fn frag_main()->@location(0) array<f32, 2> { return array<f32, 2>(); }
 
-  Func(Source{{12, 34}}, "frag_main", {}, ty.array<f32, 2>(),
-       {Return(Construct(ty.array<f32, 2>()))},
-       {Stage(ast::PipelineStage::kFragment)}, {Location(Source{{34, 56}}, 0)});
+    Func(Source{{12, 34}}, "frag_main", {}, ty.array<f32, 2>(),
+         {Return(Construct(ty.array<f32, 2>()))}, {Stage(ast::PipelineStage::kFragment)},
+         {Location(Source{{34, 56}}, 0)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: cannot apply 'location' attribute to declaration of "
-            "type 'array<f32, 2>'\n"
-            "34:56 note: 'location' attribute must only be applied to "
-            "declarations of numeric scalar or numeric vector type");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: cannot apply 'location' attribute to declaration of "
+              "type 'array<f32, 2>'\n"
+              "34:56 note: 'location' attribute must only be applied to "
+              "declarations of numeric scalar or numeric vector type");
 }
 
 TEST_F(LocationAttributeTests, BadType_Input_Struct) {
-  // struct Input {
-  //   a : f32;
-  // };
-  // @stage(fragment)
-  // fn main(@location(0) param : Input) {}
-  auto* input = Structure("Input", {Member("a", ty.f32())});
-  auto* param = Param(Source{{12, 34}}, "param", ty.Of(input),
-                      {Location(Source{{13, 43}}, 0)});
-  Func(Source{{12, 34}}, "main", {param}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kFragment)});
+    // struct Input {
+    //   a : f32;
+    // };
+    // @stage(fragment)
+    // fn main(@location(0) param : Input) {}
+    auto* input = Structure("Input", {Member("a", ty.f32())});
+    auto* param = Param(Source{{12, 34}}, "param", ty.Of(input), {Location(Source{{13, 43}}, 0)});
+    Func(Source{{12, 34}}, "main", {param}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: cannot apply 'location' attribute to declaration of "
-            "type 'Input'\n"
-            "13:43 note: 'location' attribute must only be applied to "
-            "declarations of numeric scalar or numeric vector type");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: cannot apply 'location' attribute to declaration of "
+              "type 'Input'\n"
+              "13:43 note: 'location' attribute must only be applied to "
+              "declarations of numeric scalar or numeric vector type");
 }
 
 TEST_F(LocationAttributeTests, BadType_Input_Struct_NestedStruct) {
-  // struct Inner {
-  //   @location(0) b : f32;
-  // };
-  // struct Input {
-  //   a : Inner;
-  // };
-  // @stage(fragment)
-  // fn main(param : Input) {}
-  auto* inner = Structure(
-      "Inner", {Member(Source{{13, 43}}, "a", ty.f32(), {Location(0)})});
-  auto* input =
-      Structure("Input", {Member(Source{{14, 52}}, "a", ty.Of(inner))});
-  auto* param = Param("param", ty.Of(input));
-  Func(Source{{12, 34}}, "main", {param}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kFragment)});
+    // struct Inner {
+    //   @location(0) b : f32;
+    // };
+    // struct Input {
+    //   a : Inner;
+    // };
+    // @stage(fragment)
+    // fn main(param : Input) {}
+    auto* inner = Structure("Inner", {Member(Source{{13, 43}}, "a", ty.f32(), {Location(0)})});
+    auto* input = Structure("Input", {Member(Source{{14, 52}}, "a", ty.Of(inner))});
+    auto* param = Param("param", ty.Of(input));
+    Func(Source{{12, 34}}, "main", {param}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "14:52 error: nested structures cannot be used for entry point IO\n"
-            "12:34 note: while analysing entry point 'main'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "14:52 error: nested structures cannot be used for entry point IO\n"
+              "12:34 note: while analysing entry point 'main'");
 }
 
 TEST_F(LocationAttributeTests, BadType_Input_Struct_RuntimeArray) {
-  // struct Input {
-  //   @location(0) a : array<f32>;
-  // };
-  // @stage(fragment)
-  // fn main(param : Input) {}
-  auto* input = Structure("Input", {Member(Source{{13, 43}}, "a",
-                                           ty.array<float>(), {Location(0)})});
-  auto* param = Param("param", ty.Of(input));
-  Func(Source{{12, 34}}, "main", {param}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kFragment)});
+    // struct Input {
+    //   @location(0) a : array<f32>;
+    // };
+    // @stage(fragment)
+    // fn main(param : Input) {}
+    auto* input =
+        Structure("Input", {Member(Source{{13, 43}}, "a", ty.array<float>(), {Location(0)})});
+    auto* param = Param("param", ty.Of(input));
+    Func(Source{{12, 34}}, "main", {param}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "13:43 error: cannot apply 'location' attribute to declaration of "
-            "type 'array<f32>'\n"
-            "note: 'location' attribute must only be applied to declarations "
-            "of numeric scalar or numeric vector type");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "13:43 error: cannot apply 'location' attribute to declaration of "
+              "type 'array<f32>'\n"
+              "note: 'location' attribute must only be applied to declarations "
+              "of numeric scalar or numeric vector type");
 }
 
 TEST_F(LocationAttributeTests, BadMemberType_Input) {
-  // struct S { @location(0) m: array<i32>; };
-  // @stage(fragment)
-  // fn frag_main( a: S) {}
+    // struct S { @location(0) m: array<i32>; };
+    // @stage(fragment)
+    // fn frag_main( a: S) {}
 
-  auto* m = Member(Source{{34, 56}}, "m", ty.array<i32>(),
-                   ast::AttributeList{Location(Source{{12, 34}}, 0u)});
-  auto* s = Structure("S", {m});
-  auto* p = Param("a", ty.Of(s));
+    auto* m = Member(Source{{34, 56}}, "m", ty.array<i32>(),
+                     ast::AttributeList{Location(Source{{12, 34}}, 0u)});
+    auto* s = Structure("S", {m});
+    auto* p = Param("a", ty.Of(s));
 
-  Func("frag_main", {p}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kFragment)});
+    Func("frag_main", {p}, ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "34:56 error: cannot apply 'location' attribute to declaration of "
-            "type 'array<i32>'\n"
-            "12:34 note: 'location' attribute must only be applied to "
-            "declarations of numeric scalar or numeric vector type");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "34:56 error: cannot apply 'location' attribute to declaration of "
+              "type 'array<i32>'\n"
+              "12:34 note: 'location' attribute must only be applied to "
+              "declarations of numeric scalar or numeric vector type");
 }
 
 TEST_F(LocationAttributeTests, BadMemberType_Output) {
-  // struct S { @location(0) m: atomic<i32>; };
-  // @stage(fragment)
-  // fn frag_main() -> S {}
-  auto* m = Member(Source{{34, 56}}, "m", ty.atomic<i32>(),
-                   ast::AttributeList{Location(Source{{12, 34}}, 0u)});
-  auto* s = Structure("S", {m});
+    // struct S { @location(0) m: atomic<i32>; };
+    // @stage(fragment)
+    // fn frag_main() -> S {}
+    auto* m = Member(Source{{34, 56}}, "m", ty.atomic<i32>(),
+                     ast::AttributeList{Location(Source{{12, 34}}, 0u)});
+    auto* s = Structure("S", {m});
 
-  Func("frag_main", {}, ty.Of(s), {Return(Construct(ty.Of(s)))},
-       {Stage(ast::PipelineStage::kFragment)}, {});
+    Func("frag_main", {}, ty.Of(s), {Return(Construct(ty.Of(s)))},
+         {Stage(ast::PipelineStage::kFragment)}, {});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "34:56 error: cannot apply 'location' attribute to declaration of "
-            "type 'atomic<i32>'\n"
-            "12:34 note: 'location' attribute must only be applied to "
-            "declarations of numeric scalar or numeric vector type");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "34:56 error: cannot apply 'location' attribute to declaration of "
+              "type 'atomic<i32>'\n"
+              "12:34 note: 'location' attribute must only be applied to "
+              "declarations of numeric scalar or numeric vector type");
 }
 
 TEST_F(LocationAttributeTests, BadMemberType_Unused) {
-  // struct S { @location(0) m: mat3x2<f32>; };
+    // struct S { @location(0) m: mat3x2<f32>; };
 
-  auto* m = Member(Source{{34, 56}}, "m", ty.mat3x2<f32>(),
-                   ast::AttributeList{Location(Source{{12, 34}}, 0u)});
-  Structure("S", {m});
+    auto* m = Member(Source{{34, 56}}, "m", ty.mat3x2<f32>(),
+                     ast::AttributeList{Location(Source{{12, 34}}, 0u)});
+    Structure("S", {m});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "34:56 error: cannot apply 'location' attribute to declaration of "
-            "type 'mat3x2<f32>'\n"
-            "12:34 note: 'location' attribute must only be applied to "
-            "declarations of numeric scalar or numeric vector type");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "34:56 error: cannot apply 'location' attribute to declaration of "
+              "type 'mat3x2<f32>'\n"
+              "12:34 note: 'location' attribute must only be applied to "
+              "declarations of numeric scalar or numeric vector type");
 }
 
 TEST_F(LocationAttributeTests, ReturnType_Struct_Valid) {
-  // struct Output {
-  //   @location(0) a : f32;
-  //   @builtin(frag_depth) b : f32;
-  // };
-  // @stage(fragment)
-  // fn main() -> Output {
-  //   return Output();
-  // }
-  auto* output = Structure(
-      "Output", {Member("a", ty.f32(), {Location(0)}),
-                 Member("b", ty.f32(), {Builtin(ast::Builtin::kFragDepth)})});
-  Func(Source{{12, 34}}, "main", {}, ty.Of(output),
-       {Return(Construct(ty.Of(output)))},
-       {Stage(ast::PipelineStage::kFragment)});
+    // struct Output {
+    //   @location(0) a : f32;
+    //   @builtin(frag_depth) b : f32;
+    // };
+    // @stage(fragment)
+    // fn main() -> Output {
+    //   return Output();
+    // }
+    auto* output =
+        Structure("Output", {Member("a", ty.f32(), {Location(0)}),
+                             Member("b", ty.f32(), {Builtin(ast::Builtin::kFragDepth)})});
+    Func(Source{{12, 34}}, "main", {}, ty.Of(output), {Return(Construct(ty.Of(output)))},
+         {Stage(ast::PipelineStage::kFragment)});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(LocationAttributeTests, ReturnType_Struct) {
-  // struct Output {
-  //   a : f32;
-  // };
-  // @stage(vertex)
-  // fn main() -> @location(0) Output {
-  //   return Output();
-  // }
-  auto* output = Structure("Output", {Member("a", ty.f32())});
-  Func(Source{{12, 34}}, "main", {}, ty.Of(output),
-       {Return(Construct(ty.Of(output)))}, {Stage(ast::PipelineStage::kVertex)},
-       {Location(Source{{13, 43}}, 0)});
+    // struct Output {
+    //   a : f32;
+    // };
+    // @stage(vertex)
+    // fn main() -> @location(0) Output {
+    //   return Output();
+    // }
+    auto* output = Structure("Output", {Member("a", ty.f32())});
+    Func(Source{{12, 34}}, "main", {}, ty.Of(output), {Return(Construct(ty.Of(output)))},
+         {Stage(ast::PipelineStage::kVertex)}, {Location(Source{{13, 43}}, 0)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: cannot apply 'location' attribute to declaration of "
-            "type 'Output'\n"
-            "13:43 note: 'location' attribute must only be applied to "
-            "declarations of numeric scalar or numeric vector type");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: cannot apply 'location' attribute to declaration of "
+              "type 'Output'\n"
+              "13:43 note: 'location' attribute must only be applied to "
+              "declarations of numeric scalar or numeric vector type");
 }
 
 TEST_F(LocationAttributeTests, ReturnType_Struct_NestedStruct) {
-  // struct Inner {
-  //   @location(0) b : f32;
-  // };
-  // struct Output {
-  //   a : Inner;
-  // };
-  // @stage(fragment)
-  // fn main() -> Output { return Output(); }
-  auto* inner = Structure(
-      "Inner", {Member(Source{{13, 43}}, "a", ty.f32(), {Location(0)})});
-  auto* output =
-      Structure("Output", {Member(Source{{14, 52}}, "a", ty.Of(inner))});
-  Func(Source{{12, 34}}, "main", {}, ty.Of(output),
-       {Return(Construct(ty.Of(output)))},
-       {Stage(ast::PipelineStage::kFragment)});
+    // struct Inner {
+    //   @location(0) b : f32;
+    // };
+    // struct Output {
+    //   a : Inner;
+    // };
+    // @stage(fragment)
+    // fn main() -> Output { return Output(); }
+    auto* inner = Structure("Inner", {Member(Source{{13, 43}}, "a", ty.f32(), {Location(0)})});
+    auto* output = Structure("Output", {Member(Source{{14, 52}}, "a", ty.Of(inner))});
+    Func(Source{{12, 34}}, "main", {}, ty.Of(output), {Return(Construct(ty.Of(output)))},
+         {Stage(ast::PipelineStage::kFragment)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "14:52 error: nested structures cannot be used for entry point IO\n"
-            "12:34 note: while analysing entry point 'main'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "14:52 error: nested structures cannot be used for entry point IO\n"
+              "12:34 note: while analysing entry point 'main'");
 }
 
 TEST_F(LocationAttributeTests, ReturnType_Struct_RuntimeArray) {
-  // struct Output {
-  //   @location(0) a : array<f32>;
-  // };
-  // @stage(fragment)
-  // fn main() -> Output {
-  //   return Output();
-  // }
-  auto* output =
-      Structure("Output", {Member(Source{{13, 43}}, "a", ty.array<float>(),
-                                  {Location(Source{{12, 34}}, 0)})});
-  Func(Source{{12, 34}}, "main", {}, ty.Of(output),
-       {Return(Construct(ty.Of(output)))},
-       {Stage(ast::PipelineStage::kFragment)});
+    // struct Output {
+    //   @location(0) a : array<f32>;
+    // };
+    // @stage(fragment)
+    // fn main() -> Output {
+    //   return Output();
+    // }
+    auto* output = Structure("Output", {Member(Source{{13, 43}}, "a", ty.array<float>(),
+                                               {Location(Source{{12, 34}}, 0)})});
+    Func(Source{{12, 34}}, "main", {}, ty.Of(output), {Return(Construct(ty.Of(output)))},
+         {Stage(ast::PipelineStage::kFragment)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "13:43 error: cannot apply 'location' attribute to declaration of "
-            "type 'array<f32>'\n"
-            "12:34 note: 'location' attribute must only be applied to "
-            "declarations of numeric scalar or numeric vector type");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "13:43 error: cannot apply 'location' attribute to declaration of "
+              "type 'array<f32>'\n"
+              "12:34 note: 'location' attribute must only be applied to "
+              "declarations of numeric scalar or numeric vector type");
 }
 
 TEST_F(LocationAttributeTests, ComputeShaderLocation_Input) {
-  Func("main", {}, ty.i32(), {Return(Expr(1))},
-       {Stage(ast::PipelineStage::kCompute),
-        create<ast::WorkgroupAttribute>(Source{{12, 34}}, Expr(1))},
-       ast::AttributeList{Location(Source{{12, 34}}, 1)});
+    Func("main", {}, ty.i32(), {Return(Expr(1_i))},
+         {Stage(ast::PipelineStage::kCompute),
+          create<ast::WorkgroupAttribute>(Source{{12, 34}}, Expr(1_i))},
+         ast::AttributeList{Location(Source{{12, 34}}, 1)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: attribute is not valid for compute shader output");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: attribute is not valid for compute shader output");
 }
 
 TEST_F(LocationAttributeTests, ComputeShaderLocation_Output) {
-  auto* input = Param("input", ty.i32(),
-                      ast::AttributeList{Location(Source{{12, 34}}, 0u)});
-  Func("main", {input}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kCompute),
-        create<ast::WorkgroupAttribute>(Source{{12, 34}}, Expr(1))});
+    auto* input = Param("input", ty.i32(), ast::AttributeList{Location(Source{{12, 34}}, 0u)});
+    Func("main", {input}, ty.void_(), {},
+         {Stage(ast::PipelineStage::kCompute),
+          create<ast::WorkgroupAttribute>(Source{{12, 34}}, Expr(1_i))});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: attribute is not valid for compute shader inputs");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: attribute is not valid for compute shader inputs");
 }
 
 TEST_F(LocationAttributeTests, ComputeShaderLocationStructMember_Output) {
-  auto* m =
-      Member("m", ty.i32(), ast::AttributeList{Location(Source{{12, 34}}, 0u)});
-  auto* s = Structure("S", {m});
-  Func(Source{{56, 78}}, "main", {}, ty.Of(s),
-       ast::StatementList{Return(Expr(Construct(ty.Of(s))))},
-       {Stage(ast::PipelineStage::kCompute),
-        create<ast::WorkgroupAttribute>(Source{{12, 34}}, Expr(1))});
+    auto* m = Member("m", ty.i32(), ast::AttributeList{Location(Source{{12, 34}}, 0u)});
+    auto* s = Structure("S", {m});
+    Func(Source{{56, 78}}, "main", {}, ty.Of(s),
+         ast::StatementList{Return(Expr(Construct(ty.Of(s))))},
+         {Stage(ast::PipelineStage::kCompute),
+          create<ast::WorkgroupAttribute>(Source{{12, 34}}, Expr(1_i))});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: attribute is not valid for compute shader output\n"
-            "56:78 note: while analysing entry point 'main'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: attribute is not valid for compute shader output\n"
+              "56:78 note: while analysing entry point 'main'");
 }
 
 TEST_F(LocationAttributeTests, ComputeShaderLocationStructMember_Input) {
-  auto* m =
-      Member("m", ty.i32(), ast::AttributeList{Location(Source{{12, 34}}, 0u)});
-  auto* s = Structure("S", {m});
-  auto* input = Param("input", ty.Of(s));
-  Func(Source{{56, 78}}, "main", {input}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kCompute),
-        create<ast::WorkgroupAttribute>(Source{{12, 34}}, Expr(1))});
+    auto* m = Member("m", ty.i32(), ast::AttributeList{Location(Source{{12, 34}}, 0u)});
+    auto* s = Structure("S", {m});
+    auto* input = Param("input", ty.Of(s));
+    Func(Source{{56, 78}}, "main", {input}, ty.void_(), {},
+         {Stage(ast::PipelineStage::kCompute),
+          create<ast::WorkgroupAttribute>(Source{{12, 34}}, Expr(1_i))});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: attribute is not valid for compute shader inputs\n"
-            "56:78 note: while analysing entry point 'main'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: attribute is not valid for compute shader inputs\n"
+              "56:78 note: while analysing entry point 'main'");
 }
 
 TEST_F(LocationAttributeTests, Duplicate_input) {
-  // @stage(fragment)
-  // fn main(@location(1) param_a : f32,
-  //         @location(1) param_b : f32) {}
-  auto* param_a = Param("param_a", ty.f32(), {Location(1)});
-  auto* param_b = Param("param_b", ty.f32(), {Location(Source{{12, 34}}, 1)});
-  Func(Source{{12, 34}}, "main", {param_a, param_b}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kFragment)});
+    // @stage(fragment)
+    // fn main(@location(1) param_a : f32,
+    //         @location(1) param_b : f32) {}
+    auto* param_a = Param("param_a", ty.f32(), {Location(1)});
+    auto* param_b = Param("param_b", ty.f32(), {Location(Source{{12, 34}}, 1)});
+    Func(Source{{12, 34}}, "main", {param_a, param_b}, ty.void_(), {},
+         {Stage(ast::PipelineStage::kFragment)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: location(1) attribute appears multiple times");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: location(1) attribute appears multiple times");
 }
 
 TEST_F(LocationAttributeTests, Duplicate_struct) {
-  // struct InputA {
-  //   @location(1) a : f32;
-  // };
-  // struct InputB {
-  //   @location(1) a : f32;
-  // };
-  // @stage(fragment)
-  // fn main(param_a : InputA, param_b : InputB) {}
-  auto* input_a = Structure("InputA", {Member("a", ty.f32(), {Location(1)})});
-  auto* input_b = Structure(
-      "InputB", {Member("a", ty.f32(), {Location(Source{{34, 56}}, 1)})});
-  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_(), {},
-       {Stage(ast::PipelineStage::kFragment)});
+    // struct InputA {
+    //   @location(1) a : f32;
+    // };
+    // struct InputB {
+    //   @location(1) a : f32;
+    // };
+    // @stage(fragment)
+    // fn main(param_a : InputA, param_b : InputB) {}
+    auto* input_a = Structure("InputA", {Member("a", ty.f32(), {Location(1)})});
+    auto* input_b = Structure("InputB", {Member("a", ty.f32(), {Location(Source{{34, 56}}, 1)})});
+    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_(), {},
+         {Stage(ast::PipelineStage::kFragment)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "34:56 error: location(1) attribute appears multiple times\n"
-            "12:34 note: while analysing entry point 'main'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "34:56 error: location(1) attribute appears multiple times\n"
+              "12:34 note: while analysing entry point 'main'");
 }
 
 }  // namespace
diff --git a/src/tint/resolver/function_validation_test.cc b/src/tint/resolver/function_validation_test.cc
index d694f0e..1bc70a5 100644
--- a/src/tint/resolver/function_validation_test.cc
+++ b/src/tint/resolver/function_validation_test.cc
@@ -20,811 +20,770 @@
 
 #include "gmock/gmock.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::resolver {
 namespace {
 
-class ResolverFunctionValidationTest : public TestHelper,
-                                       public testing::Test {};
+class ResolverFunctionValidationTest : public TestHelper, public testing::Test {};
 
 TEST_F(ResolverFunctionValidationTest, DuplicateParameterName) {
-  // fn func_a(common_name : f32) { }
-  // fn func_b(common_name : f32) { }
-  Func("func_a", {Param("common_name", ty.f32())}, ty.void_(), {});
-  Func("func_b", {Param("common_name", ty.f32())}, ty.void_(), {});
+    // fn func_a(common_name : f32) { }
+    // fn func_b(common_name : f32) { }
+    Func("func_a", {Param("common_name", ty.f32())}, ty.void_(), {});
+    Func("func_b", {Param("common_name", ty.f32())}, ty.void_(), {});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverFunctionValidationTest, ParameterMayShadowGlobal) {
-  // var<private> common_name : f32;
-  // fn func(common_name : f32) { }
-  Global("common_name", ty.f32(), ast::StorageClass::kPrivate);
-  Func("func", {Param("common_name", ty.f32())}, ty.void_(), {});
+    // var<private> common_name : f32;
+    // fn func(common_name : f32) { }
+    Global("common_name", ty.f32(), ast::StorageClass::kPrivate);
+    Func("func", {Param("common_name", ty.f32())}, ty.void_(), {});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverFunctionValidationTest, LocalConflictsWithParameter) {
-  // fn func(common_name : f32) {
-  //   let common_name = 1;
-  // }
-  Func("func", {Param(Source{{12, 34}}, "common_name", ty.f32())}, ty.void_(),
-       {Decl(Const(Source{{56, 78}}, "common_name", nullptr, Expr(1)))});
+    // fn func(common_name : f32) {
+    //   let common_name = 1i;
+    // }
+    Func("func", {Param(Source{{12, 34}}, "common_name", ty.f32())}, ty.void_(),
+         {Decl(Let(Source{{56, 78}}, "common_name", nullptr, Expr(1_i)))});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), R"(56:78 error: redeclaration of 'common_name'
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), R"(56:78 error: redeclaration of 'common_name'
 12:34 note: 'common_name' previously declared here)");
 }
 
 TEST_F(ResolverFunctionValidationTest, NestedLocalMayShadowParameter) {
-  // fn func(common_name : f32) {
-  //   {
-  //     let common_name = 1;
-  //   }
-  // }
-  Func("func", {Param(Source{{12, 34}}, "common_name", ty.f32())}, ty.void_(),
-       {Block(Decl(Const(Source{{56, 78}}, "common_name", nullptr, Expr(1))))});
+    // fn func(common_name : f32) {
+    //   {
+    //     let common_name = 1i;
+    //   }
+    // }
+    Func("func", {Param(Source{{12, 34}}, "common_name", ty.f32())}, ty.void_(),
+         {Block(Decl(Let(Source{{56, 78}}, "common_name", nullptr, Expr(1_i))))});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
-TEST_F(ResolverFunctionValidationTest,
-       VoidFunctionEndWithoutReturnStatement_Pass) {
-  // fn func { var a:i32 = 2; }
-  auto* var = Var("a", ty.i32(), Expr(2));
+TEST_F(ResolverFunctionValidationTest, VoidFunctionEndWithoutReturnStatement_Pass) {
+    // fn func { var a:i32 = 2i; }
+    auto* var = Var("a", ty.i32(), Expr(2_i));
 
-  Func(Source{{12, 34}}, "func", ast::VariableList{}, ty.void_(),
-       ast::StatementList{
-           Decl(var),
-       });
+    Func(Source{{12, 34}}, "func", ast::VariableList{}, ty.void_(),
+         ast::StatementList{
+             Decl(var),
+         });
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverFunctionValidationTest, FunctionUsingSameVariableName_Pass) {
-  // fn func() -> i32 {
-  //   var func:i32 = 0;
-  //   return func;
-  // }
+    // fn func() -> i32 {
+    //   var func:i32 = 0i;
+    //   return func;
+    // }
 
-  auto* var = Var("func", ty.i32(), Expr(0));
-  Func("func", ast::VariableList{}, ty.i32(),
-       ast::StatementList{
-           Decl(var),
-           Return(Source{{12, 34}}, Expr("func")),
-       },
-       ast::AttributeList{});
+    auto* var = Var("func", ty.i32(), Expr(0_i));
+    Func("func", ast::VariableList{}, ty.i32(),
+         ast::StatementList{
+             Decl(var),
+             Return(Source{{12, 34}}, Expr("func")),
+         },
+         ast::AttributeList{});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
-TEST_F(ResolverFunctionValidationTest,
-       FunctionNameSameAsFunctionScopeVariableName_Pass) {
-  // fn a() -> void { var b:i32 = 0; }
-  // fn b() -> i32 { return 2; }
+TEST_F(ResolverFunctionValidationTest, FunctionNameSameAsFunctionScopeVariableName_Pass) {
+    // fn a() -> void { var b:i32 = 0i; }
+    // fn b() -> i32 { return 2; }
 
-  auto* var = Var("b", ty.i32(), Expr(0));
-  Func("a", ast::VariableList{}, ty.void_(),
-       ast::StatementList{
-           Decl(var),
-       },
-       ast::AttributeList{});
+    auto* var = Var("b", ty.i32(), Expr(0_i));
+    Func("a", ast::VariableList{}, ty.void_(),
+         ast::StatementList{
+             Decl(var),
+         },
+         ast::AttributeList{});
 
-  Func(Source{{12, 34}}, "b", ast::VariableList{}, ty.i32(),
-       ast::StatementList{
-           Return(2),
-       },
-       ast::AttributeList{});
+    Func(Source{{12, 34}}, "b", ast::VariableList{}, ty.i32(),
+         ast::StatementList{
+             Return(2_i),
+         },
+         ast::AttributeList{});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverFunctionValidationTest, UnreachableCode_return) {
-  // fn func() -> {
-  //  var a : i32;
-  //  return;
-  //  a = 2;
-  //}
+    // fn func() -> {
+    //  var a : i32;
+    //  return;
+    //  a = 2i;
+    //}
 
-  auto* decl_a = Decl(Var("a", ty.i32()));
-  auto* ret = Return();
-  auto* assign_a = Assign(Source{{12, 34}}, "a", 2);
+    auto* decl_a = Decl(Var("a", ty.i32()));
+    auto* ret = Return();
+    auto* assign_a = Assign(Source{{12, 34}}, "a", 2_i);
 
-  Func("func", ast::VariableList{}, ty.void_(), {decl_a, ret, assign_a});
+    Func("func", ast::VariableList{}, ty.void_(), {decl_a, ret, assign_a});
 
-  ASSERT_TRUE(r()->Resolve());
+    ASSERT_TRUE(r()->Resolve());
 
-  EXPECT_EQ(r()->error(), "12:34 warning: code is unreachable");
-  EXPECT_TRUE(Sem().Get(decl_a)->IsReachable());
-  EXPECT_TRUE(Sem().Get(ret)->IsReachable());
-  EXPECT_FALSE(Sem().Get(assign_a)->IsReachable());
+    EXPECT_EQ(r()->error(), "12:34 warning: code is unreachable");
+    EXPECT_TRUE(Sem().Get(decl_a)->IsReachable());
+    EXPECT_TRUE(Sem().Get(ret)->IsReachable());
+    EXPECT_FALSE(Sem().Get(assign_a)->IsReachable());
 }
 
 TEST_F(ResolverFunctionValidationTest, UnreachableCode_return_InBlocks) {
-  // fn func() -> {
-  //  var a : i32;
-  //  {{{return;}}}
-  //  a = 2;
-  //}
+    // fn func() -> {
+    //  var a : i32;
+    //  {{{return;}}}
+    //  a = 2i;
+    //}
 
-  auto* decl_a = Decl(Var("a", ty.i32()));
-  auto* ret = Return();
-  auto* assign_a = Assign(Source{{12, 34}}, "a", 2);
+    auto* decl_a = Decl(Var("a", ty.i32()));
+    auto* ret = Return();
+    auto* assign_a = Assign(Source{{12, 34}}, "a", 2_i);
 
-  Func("func", ast::VariableList{}, ty.void_(),
-       {decl_a, Block(Block(Block(ret))), assign_a});
+    Func("func", ast::VariableList{}, ty.void_(), {decl_a, Block(Block(Block(ret))), assign_a});
 
-  ASSERT_TRUE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 warning: code is unreachable");
-  EXPECT_TRUE(Sem().Get(decl_a)->IsReachable());
-  EXPECT_TRUE(Sem().Get(ret)->IsReachable());
-  EXPECT_FALSE(Sem().Get(assign_a)->IsReachable());
+    ASSERT_TRUE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 warning: code is unreachable");
+    EXPECT_TRUE(Sem().Get(decl_a)->IsReachable());
+    EXPECT_TRUE(Sem().Get(ret)->IsReachable());
+    EXPECT_FALSE(Sem().Get(assign_a)->IsReachable());
 }
 
 TEST_F(ResolverFunctionValidationTest, UnreachableCode_discard) {
-  // fn func() -> {
-  //  var a : i32;
-  //  discard;
-  //  a = 2;
-  //}
+    // fn func() -> {
+    //  var a : i32;
+    //  discard;
+    //  a = 2i;
+    //}
 
-  auto* decl_a = Decl(Var("a", ty.i32()));
-  auto* discard = Discard();
-  auto* assign_a = Assign(Source{{12, 34}}, "a", 2);
+    auto* decl_a = Decl(Var("a", ty.i32()));
+    auto* discard = Discard();
+    auto* assign_a = Assign(Source{{12, 34}}, "a", 2_i);
 
-  Func("func", ast::VariableList{}, ty.void_(), {decl_a, discard, assign_a});
+    Func("func", ast::VariableList{}, ty.void_(), {decl_a, discard, assign_a});
 
-  ASSERT_TRUE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 warning: code is unreachable");
-  EXPECT_TRUE(Sem().Get(decl_a)->IsReachable());
-  EXPECT_TRUE(Sem().Get(discard)->IsReachable());
-  EXPECT_FALSE(Sem().Get(assign_a)->IsReachable());
+    ASSERT_TRUE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 warning: code is unreachable");
+    EXPECT_TRUE(Sem().Get(decl_a)->IsReachable());
+    EXPECT_TRUE(Sem().Get(discard)->IsReachable());
+    EXPECT_FALSE(Sem().Get(assign_a)->IsReachable());
 }
 
 TEST_F(ResolverFunctionValidationTest, UnreachableCode_discard_InBlocks) {
-  // fn func() -> {
-  //  var a : i32;
-  //  {{{discard;}}}
-  //  a = 2;
-  //}
+    // fn func() -> {
+    //  var a : i32;
+    //  {{{discard;}}}
+    //  a = 2i;
+    //}
 
-  auto* decl_a = Decl(Var("a", ty.i32()));
-  auto* discard = Discard();
-  auto* assign_a = Assign(Source{{12, 34}}, "a", 2);
+    auto* decl_a = Decl(Var("a", ty.i32()));
+    auto* discard = Discard();
+    auto* assign_a = Assign(Source{{12, 34}}, "a", 2_i);
 
-  Func("func", ast::VariableList{}, ty.void_(),
-       {decl_a, Block(Block(Block(discard))), assign_a});
+    Func("func", ast::VariableList{}, ty.void_(), {decl_a, Block(Block(Block(discard))), assign_a});
 
-  ASSERT_TRUE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 warning: code is unreachable");
-  EXPECT_TRUE(Sem().Get(decl_a)->IsReachable());
-  EXPECT_TRUE(Sem().Get(discard)->IsReachable());
-  EXPECT_FALSE(Sem().Get(assign_a)->IsReachable());
+    ASSERT_TRUE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 warning: code is unreachable");
+    EXPECT_TRUE(Sem().Get(decl_a)->IsReachable());
+    EXPECT_TRUE(Sem().Get(discard)->IsReachable());
+    EXPECT_FALSE(Sem().Get(assign_a)->IsReachable());
 }
 
 TEST_F(ResolverFunctionValidationTest, FunctionEndWithoutReturnStatement_Fail) {
-  // fn func() -> int { var a:i32 = 2; }
+    // fn func() -> int { var a:i32 = 2i; }
 
-  auto* var = Var("a", ty.i32(), Expr(2));
+    auto* var = Var("a", ty.i32(), Expr(2_i));
 
-  Func(Source{{12, 34}}, "func", ast::VariableList{}, ty.i32(),
-       ast::StatementList{
-           Decl(var),
-       },
-       ast::AttributeList{});
+    Func(Source{{12, 34}}, "func", ast::VariableList{}, ty.i32(),
+         ast::StatementList{
+             Decl(var),
+         },
+         ast::AttributeList{});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: missing return at end of function");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: missing return at end of function");
 }
 
-TEST_F(ResolverFunctionValidationTest,
-       VoidFunctionEndWithoutReturnStatementEmptyBody_Pass) {
-  // fn func {}
+TEST_F(ResolverFunctionValidationTest, VoidFunctionEndWithoutReturnStatementEmptyBody_Pass) {
+    // fn func {}
 
-  Func(Source{{12, 34}}, "func", ast::VariableList{}, ty.void_(),
-       ast::StatementList{});
+    Func(Source{{12, 34}}, "func", ast::VariableList{}, ty.void_(), ast::StatementList{});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
-TEST_F(ResolverFunctionValidationTest,
-       FunctionEndWithoutReturnStatementEmptyBody_Fail) {
-  // fn func() -> int {}
+TEST_F(ResolverFunctionValidationTest, FunctionEndWithoutReturnStatementEmptyBody_Fail) {
+    // fn func() -> int {}
 
-  Func(Source{{12, 34}}, "func", ast::VariableList{}, ty.i32(),
-       ast::StatementList{}, ast::AttributeList{});
+    Func(Source{{12, 34}}, "func", ast::VariableList{}, ty.i32(), ast::StatementList{},
+         ast::AttributeList{});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: missing return at end of function");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: missing return at end of function");
 }
 
-TEST_F(ResolverFunctionValidationTest,
-       FunctionTypeMustMatchReturnStatementType_Pass) {
-  // fn func { return; }
+TEST_F(ResolverFunctionValidationTest, FunctionTypeMustMatchReturnStatementType_Pass) {
+    // fn func { return; }
 
-  Func("func", ast::VariableList{}, ty.void_(),
-       ast::StatementList{
-           Return(),
-       });
+    Func("func", ast::VariableList{}, ty.void_(),
+         ast::StatementList{
+             Return(),
+         });
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
-TEST_F(ResolverFunctionValidationTest,
-       FunctionTypeMustMatchReturnStatementType_fail) {
-  // fn func { return 2; }
-  Func("func", ast::VariableList{}, ty.void_(),
-       ast::StatementList{
-           Return(Source{{12, 34}}, Expr(2)),
-       },
-       ast::AttributeList{});
+TEST_F(ResolverFunctionValidationTest, FunctionTypeMustMatchReturnStatementType_fail) {
+    // fn func { return 2i; }
+    Func("func", ast::VariableList{}, ty.void_(),
+         ast::StatementList{
+             Return(Source{{12, 34}}, Expr(2_i)),
+         },
+         ast::AttributeList{});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: return statement type must match its function return "
-            "type, returned 'i32', expected 'void'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: return statement type must match its function return "
+              "type, returned 'i32', expected 'void'");
 }
 
-TEST_F(ResolverFunctionValidationTest,
-       FunctionTypeMustMatchReturnStatementType_void_fail) {
-  // fn v { return; }
-  // fn func { return v(); }
-  Func("v", {}, ty.void_(), {Return()});
-  Func("func", {}, ty.void_(),
-       {
-           Return(Call(Source{{12, 34}}, "v")),
-       });
+TEST_F(ResolverFunctionValidationTest, FunctionTypeMustMatchReturnStatementType_void_fail) {
+    // fn v { return; }
+    // fn func { return v(); }
+    Func("v", {}, ty.void_(), {Return()});
+    Func("func", {}, ty.void_(),
+         {
+             Return(Call(Source{{12, 34}}, "v")),
+         });
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: function 'v' does not return a value");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: function 'v' does not return a value");
 }
 
-TEST_F(ResolverFunctionValidationTest,
-       FunctionTypeMustMatchReturnStatementTypeMissing_fail) {
-  // fn func() -> f32 { return; }
-  Func("func", ast::VariableList{}, ty.f32(),
-       ast::StatementList{
-           Return(Source{{12, 34}}, nullptr),
-       },
-       ast::AttributeList{});
+TEST_F(ResolverFunctionValidationTest, FunctionTypeMustMatchReturnStatementTypeMissing_fail) {
+    // fn func() -> f32 { return; }
+    Func("func", ast::VariableList{}, ty.f32(),
+         ast::StatementList{
+             Return(Source{{12, 34}}, nullptr),
+         },
+         ast::AttributeList{});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: return statement type must match its function return "
-            "type, returned 'void', expected 'f32'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: return statement type must match its function return "
+              "type, returned 'void', expected 'f32'");
 }
 
-TEST_F(ResolverFunctionValidationTest,
-       FunctionTypeMustMatchReturnStatementTypeF32_pass) {
-  // fn func() -> f32 { return 2.0; }
-  Func("func", ast::VariableList{}, ty.f32(),
-       ast::StatementList{
-           Return(Source{{12, 34}}, Expr(2.f)),
-       },
-       ast::AttributeList{});
+TEST_F(ResolverFunctionValidationTest, FunctionTypeMustMatchReturnStatementTypeF32_pass) {
+    // fn func() -> f32 { return 2.0; }
+    Func("func", ast::VariableList{}, ty.f32(),
+         ast::StatementList{
+             Return(Source{{12, 34}}, Expr(2.f)),
+         },
+         ast::AttributeList{});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
-TEST_F(ResolverFunctionValidationTest,
-       FunctionTypeMustMatchReturnStatementTypeF32_fail) {
-  // fn func() -> f32 { return 2; }
-  Func("func", ast::VariableList{}, ty.f32(),
-       ast::StatementList{
-           Return(Source{{12, 34}}, Expr(2)),
-       },
-       ast::AttributeList{});
+TEST_F(ResolverFunctionValidationTest, FunctionTypeMustMatchReturnStatementTypeF32_fail) {
+    // fn func() -> f32 { return 2i; }
+    Func("func", ast::VariableList{}, ty.f32(),
+         ast::StatementList{
+             Return(Source{{12, 34}}, Expr(2_i)),
+         },
+         ast::AttributeList{});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: return statement type must match its function return "
-            "type, returned 'i32', expected 'f32'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: return statement type must match its function return "
+              "type, returned 'i32', expected 'f32'");
 }
 
-TEST_F(ResolverFunctionValidationTest,
-       FunctionTypeMustMatchReturnStatementTypeF32Alias_pass) {
-  // type myf32 = f32;
-  // fn func() -> myf32 { return 2.0; }
-  auto* myf32 = Alias("myf32", ty.f32());
-  Func("func", ast::VariableList{}, ty.Of(myf32),
-       ast::StatementList{
-           Return(Source{{12, 34}}, Expr(2.f)),
-       },
-       ast::AttributeList{});
+TEST_F(ResolverFunctionValidationTest, FunctionTypeMustMatchReturnStatementTypeF32Alias_pass) {
+    // type myf32 = f32;
+    // fn func() -> myf32 { return 2.0; }
+    auto* myf32 = Alias("myf32", ty.f32());
+    Func("func", ast::VariableList{}, ty.Of(myf32),
+         ast::StatementList{
+             Return(Source{{12, 34}}, Expr(2.f)),
+         },
+         ast::AttributeList{});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
-TEST_F(ResolverFunctionValidationTest,
-       FunctionTypeMustMatchReturnStatementTypeF32Alias_fail) {
-  // type myf32 = f32;
-  // fn func() -> myf32 { return 2; }
-  auto* myf32 = Alias("myf32", ty.f32());
-  Func("func", ast::VariableList{}, ty.Of(myf32),
-       ast::StatementList{
-           Return(Source{{12, 34}}, Expr(2u)),
-       },
-       ast::AttributeList{});
+TEST_F(ResolverFunctionValidationTest, FunctionTypeMustMatchReturnStatementTypeF32Alias_fail) {
+    // type myf32 = f32;
+    // fn func() -> myf32 { return 2u; }
+    auto* myf32 = Alias("myf32", ty.f32());
+    Func("func", ast::VariableList{}, ty.Of(myf32),
+         ast::StatementList{
+             Return(Source{{12, 34}}, Expr(2_u)),
+         },
+         ast::AttributeList{});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: return statement type must match its function return "
-            "type, returned 'u32', expected 'f32'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: return statement type must match its function return "
+              "type, returned 'u32', expected 'f32'");
 }
 
 TEST_F(ResolverFunctionValidationTest, CannotCallEntryPoint) {
-  // @stage(compute) @workgroup_size(1) fn entrypoint() {}
-  // fn func() { return entrypoint(); }
-  Func("entrypoint", ast::VariableList{}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
+    // @stage(compute) @workgroup_size(1) fn entrypoint() {}
+    // fn func() { return entrypoint(); }
+    Func("entrypoint", ast::VariableList{}, ty.void_(), {},
+         {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
 
-  Func("func", ast::VariableList{}, ty.void_(),
-       {
-           CallStmt(Call(Source{{12, 34}}, "entrypoint")),
-       });
+    Func("func", ast::VariableList{}, ty.void_(),
+         {
+             CallStmt(Call(Source{{12, 34}}, "entrypoint")),
+         });
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
 
-      R"(12:34 error: entry point functions cannot be the target of a function call)");
+              R"(12:34 error: entry point functions cannot be the target of a function call)");
 }
 
 TEST_F(ResolverFunctionValidationTest, PipelineStage_MustBeUnique_Fail) {
-  // @stage(fragment)
-  // @stage(vertex)
-  // fn main() { return; }
-  Func(Source{{12, 34}}, "main", ast::VariableList{}, ty.void_(),
-       ast::StatementList{
-           Return(),
-       },
-       ast::AttributeList{
-           Stage(Source{{12, 34}}, ast::PipelineStage::kVertex),
-           Stage(Source{{56, 78}}, ast::PipelineStage::kFragment),
-       });
+    // @stage(fragment)
+    // @stage(vertex)
+    // fn main() { return; }
+    Func(Source{{12, 34}}, "main", ast::VariableList{}, ty.void_(),
+         ast::StatementList{
+             Return(),
+         },
+         ast::AttributeList{
+             Stage(Source{{12, 34}}, ast::PipelineStage::kVertex),
+             Stage(Source{{56, 78}}, ast::PipelineStage::kFragment),
+         });
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            R"(56:78 error: duplicate stage attribute
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(56:78 error: duplicate stage attribute
 12:34 note: first attribute declared here)");
 }
 
 TEST_F(ResolverFunctionValidationTest, NoPipelineEntryPoints) {
-  Func("vtx_func", ast::VariableList{}, ty.void_(),
-       ast::StatementList{
-           Return(),
-       },
-       ast::AttributeList{});
+    Func("vtx_func", ast::VariableList{}, ty.void_(),
+         ast::StatementList{
+             Return(),
+         },
+         ast::AttributeList{});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverFunctionValidationTest, FunctionVarInitWithParam) {
-  // fn foo(bar : f32){
-  //   var baz : f32 = bar;
-  // }
+    // fn foo(bar : f32){
+    //   var baz : f32 = bar;
+    // }
 
-  auto* bar = Param("bar", ty.f32());
-  auto* baz = Var("baz", ty.f32(), Expr("bar"));
+    auto* bar = Param("bar", ty.f32());
+    auto* baz = Var("baz", ty.f32(), Expr("bar"));
 
-  Func("foo", ast::VariableList{bar}, ty.void_(), ast::StatementList{Decl(baz)},
-       ast::AttributeList{});
+    Func("foo", ast::VariableList{bar}, ty.void_(), ast::StatementList{Decl(baz)},
+         ast::AttributeList{});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverFunctionValidationTest, FunctionConstInitWithParam) {
-  // fn foo(bar : f32){
-  //   let baz : f32 = bar;
-  // }
+    // fn foo(bar : f32){
+    //   let baz : f32 = bar;
+    // }
 
-  auto* bar = Param("bar", ty.f32());
-  auto* baz = Const("baz", ty.f32(), Expr("bar"));
+    auto* bar = Param("bar", ty.f32());
+    auto* baz = Let("baz", ty.f32(), Expr("bar"));
 
-  Func("foo", ast::VariableList{bar}, ty.void_(), ast::StatementList{Decl(baz)},
-       ast::AttributeList{});
+    Func("foo", ast::VariableList{bar}, ty.void_(), ast::StatementList{Decl(baz)},
+         ast::AttributeList{});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverFunctionValidationTest, FunctionParamsConst) {
-  Func("foo", {Param(Sym("arg"), ty.i32())}, ty.void_(),
-       {Assign(Expr(Source{{12, 34}}, "arg"), Expr(1)), Return()});
+    Func("foo", {Param(Sym("arg"), ty.i32())}, ty.void_(),
+         {Assign(Expr(Source{{12, 34}}, "arg"), Expr(1_i)), Return()});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: cannot assign to function parameter\nnote: 'arg' is "
-            "declared here:");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: cannot assign to function parameter\nnote: 'arg' is "
+              "declared here:");
 }
 
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_GoodType_ConstU32) {
-  // let x = 4u;
-  // let x = 8u;
-  // @stage(compute) @workgroup_size(x, y, 16u)
-  // fn main() {}
-  auto* x = GlobalConst("x", ty.u32(), Expr(4u));
-  auto* y = GlobalConst("y", ty.u32(), Expr(8u));
-  auto* func = Func("main", {}, ty.void_(), {},
-                    {Stage(ast::PipelineStage::kCompute),
-                     WorkgroupSize(Expr("x"), Expr("y"), Expr(16u))});
+    // let x = 4u;
+    // let x = 8u;
+    // @stage(compute) @workgroup_size(x, y, 16u)
+    // fn main() {}
+    auto* x = GlobalConst("x", ty.u32(), Expr(4_u));
+    auto* y = GlobalConst("y", ty.u32(), Expr(8_u));
+    auto* func = Func(
+        "main", {}, ty.void_(), {},
+        {Stage(ast::PipelineStage::kCompute), WorkgroupSize(Expr("x"), Expr("y"), Expr(16_u))});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem_func = Sem().Get(func);
-  auto* sem_x = Sem().Get<sem::GlobalVariable>(x);
-  auto* sem_y = Sem().Get<sem::GlobalVariable>(y);
+    auto* sem_func = Sem().Get(func);
+    auto* sem_x = Sem().Get<sem::GlobalVariable>(x);
+    auto* sem_y = Sem().Get<sem::GlobalVariable>(y);
 
-  ASSERT_NE(sem_func, nullptr);
-  ASSERT_NE(sem_x, nullptr);
-  ASSERT_NE(sem_y, nullptr);
+    ASSERT_NE(sem_func, nullptr);
+    ASSERT_NE(sem_x, nullptr);
+    ASSERT_NE(sem_y, nullptr);
 
-  EXPECT_TRUE(sem_func->DirectlyReferencedGlobals().contains(sem_x));
-  EXPECT_TRUE(sem_func->DirectlyReferencedGlobals().contains(sem_y));
+    EXPECT_TRUE(sem_func->DirectlyReferencedGlobals().contains(sem_x));
+    EXPECT_TRUE(sem_func->DirectlyReferencedGlobals().contains(sem_y));
 }
 
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_GoodType_U32) {
-  // @stage(compute) @workgroup_size(1u, 2u, 3u)
-  // fn main() {}
+    // @stage(compute) @workgroup_size(1u, 2u, 3u)
+    // fn main() {}
 
-  Func("main", {}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kCompute),
-        WorkgroupSize(Source{{12, 34}}, Expr(1u), Expr(2u), Expr(3u))});
+    Func("main", {}, ty.void_(), {},
+         {Stage(ast::PipelineStage::kCompute),
+          WorkgroupSize(Source{{12, 34}}, Expr(1_u), Expr(2_u), Expr(3_u))});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_MismatchTypeU32) {
-  // @stage(compute) @workgroup_size(1u, 2u, 3)
-  // fn main() {}
+    // @stage(compute) @workgroup_size(1u, 2u, 3_i)
+    // fn main() {}
 
-  Func("main", {}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kCompute),
-        WorkgroupSize(Expr(1u), Expr(2u), Expr(Source{{12, 34}}, 3))});
+    Func("main", {}, ty.void_(), {},
+         {Stage(ast::PipelineStage::kCompute),
+          WorkgroupSize(Expr(1_u), Expr(2_u), Expr(Source{{12, 34}}, 3_i))});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: workgroup_size arguments must be of the same type, "
-            "either i32 or u32");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: workgroup_size arguments must be of the same type, "
+              "either i32 or u32");
 }
 
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_MismatchTypeI32) {
-  // @stage(compute) @workgroup_size(1, 2u, 3)
-  // fn main() {}
+    // @stage(compute) @workgroup_size(1_i, 2u, 3_i)
+    // fn main() {}
 
-  Func("main", {}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kCompute),
-        WorkgroupSize(Expr(1), Expr(Source{{12, 34}}, 2u), Expr(3))});
+    Func("main", {}, ty.void_(), {},
+         {Stage(ast::PipelineStage::kCompute),
+          WorkgroupSize(Expr(1_i), Expr(Source{{12, 34}}, 2_u), Expr(3_i))});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: workgroup_size arguments must be of the same type, "
-            "either i32 or u32");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: workgroup_size arguments must be of the same type, "
+              "either i32 or u32");
 }
 
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Const_TypeMismatch) {
-  // let x = 64u;
-  // @stage(compute) @workgroup_size(1, x)
-  // fn main() {}
-  GlobalConst("x", ty.u32(), Expr(64u));
-  Func("main", {}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kCompute),
-        WorkgroupSize(Expr(1), Expr(Source{{12, 34}}, "x"))});
+    // let x = 64u;
+    // @stage(compute) @workgroup_size(1i, x)
+    // fn main() {}
+    GlobalConst("x", ty.u32(), Expr(64_u));
+    Func("main", {}, ty.void_(), {},
+         {Stage(ast::PipelineStage::kCompute),
+          WorkgroupSize(Expr(1_i), Expr(Source{{12, 34}}, "x"))});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: workgroup_size arguments must be of the same type, "
-            "either i32 or u32");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: workgroup_size arguments must be of the same type, "
+              "either i32 or u32");
 }
 
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Const_TypeMismatch2) {
-  // let x = 64u;
-  // let y = 32;
-  // @stage(compute) @workgroup_size(x, y)
-  // fn main() {}
-  GlobalConst("x", ty.u32(), Expr(64u));
-  GlobalConst("y", ty.i32(), Expr(32));
-  Func("main", {}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kCompute),
-        WorkgroupSize(Expr("x"), Expr(Source{{12, 34}}, "y"))});
+    // let x = 64u;
+    // let y = 32i;
+    // @stage(compute) @workgroup_size(x, y)
+    // fn main() {}
+    GlobalConst("x", ty.u32(), Expr(64_u));
+    GlobalConst("y", ty.i32(), Expr(32_i));
+    Func("main", {}, ty.void_(), {},
+         {Stage(ast::PipelineStage::kCompute),
+          WorkgroupSize(Expr("x"), Expr(Source{{12, 34}}, "y"))});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: workgroup_size arguments must be of the same type, "
-            "either i32 or u32");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: workgroup_size arguments must be of the same type, "
+              "either i32 or u32");
 }
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Mismatch_ConstU32) {
-  // let x = 4u;
-  // let x = 8u;
-  // @stage(compute) @workgroup_size(x, y, 16
-  // fn main() {}
-  GlobalConst("x", ty.u32(), Expr(4u));
-  GlobalConst("y", ty.u32(), Expr(8u));
-  Func("main", {}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kCompute),
-        WorkgroupSize(Expr("x"), Expr("y"), Expr(Source{{12, 34}}, 16))});
+    // let x = 4u;
+    // let x = 8u;
+    // @stage(compute) @workgroup_size(x, y, 16i)
+    // fn main() {}
+    GlobalConst("x", ty.u32(), Expr(4_u));
+    GlobalConst("y", ty.u32(), Expr(8_u));
+    Func("main", {}, ty.void_(), {},
+         {Stage(ast::PipelineStage::kCompute),
+          WorkgroupSize(Expr("x"), Expr("y"), Expr(Source{{12, 34}}, 16_i))});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: workgroup_size arguments must be of the same type, "
-            "either i32 or u32");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: workgroup_size arguments must be of the same type, "
+              "either i32 or u32");
 }
 
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Literal_BadType) {
-  // @stage(compute) @workgroup_size(64.0)
-  // fn main() {}
+    // @stage(compute) @workgroup_size(64.0)
+    // fn main() {}
 
-  Func("main", {}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kCompute),
-        WorkgroupSize(Expr(Source{{12, 34}}, 64.f))});
+    Func("main", {}, ty.void_(), {},
+         {Stage(ast::PipelineStage::kCompute), WorkgroupSize(Expr(Source{{12, 34}}, 64.f))});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: workgroup_size argument must be either literal or "
-            "module-scope constant of type i32 or u32");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: workgroup_size argument must be either literal or "
+              "module-scope constant of type i32 or u32");
 }
 
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Literal_Negative) {
-  // @stage(compute) @workgroup_size(-2)
-  // fn main() {}
+    // @stage(compute) @workgroup_size(-2i)
+    // fn main() {}
 
-  Func("main", {}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kCompute),
-        WorkgroupSize(Expr(Source{{12, 34}}, -2))});
+    Func("main", {}, ty.void_(), {},
+         {Stage(ast::PipelineStage::kCompute), WorkgroupSize(Expr(Source{{12, 34}}, i32(-2)))});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: workgroup_size argument must be at least 1");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: workgroup_size argument must be at least 1");
 }
 
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Literal_Zero) {
-  // @stage(compute) @workgroup_size(0)
-  // fn main() {}
+    // @stage(compute) @workgroup_size(0i)
+    // fn main() {}
 
-  Func("main", {}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kCompute),
-        WorkgroupSize(Expr(Source{{12, 34}}, 0))});
+    Func("main", {}, ty.void_(), {},
+         {Stage(ast::PipelineStage::kCompute), WorkgroupSize(Expr(Source{{12, 34}}, 0_i))});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: workgroup_size argument must be at least 1");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: workgroup_size argument must be at least 1");
 }
 
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Const_BadType) {
-  // let x = 64.0;
-  // @stage(compute) @workgroup_size(x)
-  // fn main() {}
-  GlobalConst("x", ty.f32(), Expr(64.f));
-  Func("main", {}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kCompute),
-        WorkgroupSize(Expr(Source{{12, 34}}, "x"))});
+    // let x = 64.0;
+    // @stage(compute) @workgroup_size(x)
+    // fn main() {}
+    GlobalConst("x", ty.f32(), Expr(64.f));
+    Func("main", {}, ty.void_(), {},
+         {Stage(ast::PipelineStage::kCompute), WorkgroupSize(Expr(Source{{12, 34}}, "x"))});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: workgroup_size argument must be either literal or "
-            "module-scope constant of type i32 or u32");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: workgroup_size argument must be either literal or "
+              "module-scope constant of type i32 or u32");
 }
 
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Const_Negative) {
-  // let x = -2;
-  // @stage(compute) @workgroup_size(x)
-  // fn main() {}
-  GlobalConst("x", ty.i32(), Expr(-2));
-  Func("main", {}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kCompute),
-        WorkgroupSize(Expr(Source{{12, 34}}, "x"))});
+    // let x = -2i;
+    // @stage(compute) @workgroup_size(x)
+    // fn main() {}
+    GlobalConst("x", ty.i32(), Expr(i32(-2)));
+    Func("main", {}, ty.void_(), {},
+         {Stage(ast::PipelineStage::kCompute), WorkgroupSize(Expr(Source{{12, 34}}, "x"))});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: workgroup_size argument must be at least 1");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: workgroup_size argument must be at least 1");
 }
 
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Const_Zero) {
-  // let x = 0;
-  // @stage(compute) @workgroup_size(x)
-  // fn main() {}
-  GlobalConst("x", ty.i32(), Expr(0));
-  Func("main", {}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kCompute),
-        WorkgroupSize(Expr(Source{{12, 34}}, "x"))});
+    // let x = 0i;
+    // @stage(compute) @workgroup_size(x)
+    // fn main() {}
+    GlobalConst("x", ty.i32(), Expr(0_i));
+    Func("main", {}, ty.void_(), {},
+         {Stage(ast::PipelineStage::kCompute), WorkgroupSize(Expr(Source{{12, 34}}, "x"))});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: workgroup_size argument must be at least 1");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: workgroup_size argument must be at least 1");
 }
 
-TEST_F(ResolverFunctionValidationTest,
-       WorkgroupSize_Const_NestedZeroValueConstructor) {
-  // let x = i32(i32(i32()));
-  // @stage(compute) @workgroup_size(x)
-  // fn main() {}
-  GlobalConst("x", ty.i32(),
-              Construct(ty.i32(), Construct(ty.i32(), Construct(ty.i32()))));
-  Func("main", {}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kCompute),
-        WorkgroupSize(Expr(Source{{12, 34}}, "x"))});
+TEST_F(ResolverFunctionValidationTest, WorkgroupSize_Const_NestedZeroValueConstructor) {
+    // let x = i32(i32(i32()));
+    // @stage(compute) @workgroup_size(x)
+    // fn main() {}
+    GlobalConst("x", ty.i32(), Construct(ty.i32(), Construct(ty.i32(), Construct(ty.i32()))));
+    Func("main", {}, ty.void_(), {},
+         {Stage(ast::PipelineStage::kCompute), WorkgroupSize(Expr(Source{{12, 34}}, "x"))});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: workgroup_size argument must be at least 1");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: workgroup_size argument must be at least 1");
 }
 
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_NonConst) {
-  // var<private> x = 0;
-  // @stage(compute) @workgroup_size(x)
-  // fn main() {}
-  Global("x", ty.i32(), ast::StorageClass::kPrivate, Expr(64));
-  Func("main", {}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kCompute),
-        WorkgroupSize(Expr(Source{{12, 34}}, "x"))});
+    // var<private> x = 64i;
+    // @stage(compute) @workgroup_size(x)
+    // fn main() {}
+    Global("x", ty.i32(), ast::StorageClass::kPrivate, Expr(64_i));
+    Func("main", {}, ty.void_(), {},
+         {Stage(ast::PipelineStage::kCompute), WorkgroupSize(Expr(Source{{12, 34}}, "x"))});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: workgroup_size argument must be either literal or "
-            "module-scope constant of type i32 or u32");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: workgroup_size argument must be either literal or "
+              "module-scope constant of type i32 or u32");
 }
 
 TEST_F(ResolverFunctionValidationTest, WorkgroupSize_InvalidExpr) {
-  // @stage(compute) @workgroup_size(i32(1))
-  // fn main() {}
-  Func("main", {}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kCompute),
-        WorkgroupSize(Construct(Source{{12, 34}}, ty.i32(), 1))});
+    // @stage(compute) @workgroup_size(i32(1))
+    // fn main() {}
+    Func("main", {}, ty.void_(), {},
+         {Stage(ast::PipelineStage::kCompute),
+          WorkgroupSize(Construct(Source{{12, 34}}, ty.i32(), 1_i))});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: workgroup_size argument must be either a literal or "
-            "a module-scope constant");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: workgroup_size argument must be either a literal or "
+              "a module-scope constant");
 }
 
 TEST_F(ResolverFunctionValidationTest, ReturnIsConstructible_NonPlain) {
-  auto* ret_type =
-      ty.pointer(Source{{12, 34}}, ty.i32(), ast::StorageClass::kFunction);
-  Func("f", {}, ret_type, {});
+    auto* ret_type = ty.pointer(Source{{12, 34}}, ty.i32(), ast::StorageClass::kFunction);
+    Func("f", {}, ret_type, {});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: function return type must be a constructible type");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: function return type must be a constructible type");
 }
 
 TEST_F(ResolverFunctionValidationTest, ReturnIsConstructible_AtomicInt) {
-  auto* ret_type = ty.atomic(Source{{12, 34}}, ty.i32());
-  Func("f", {}, ret_type, {});
+    auto* ret_type = ty.atomic(Source{{12, 34}}, ty.i32());
+    Func("f", {}, ret_type, {});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: function return type must be a constructible type");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: function return type must be a constructible type");
 }
 
 TEST_F(ResolverFunctionValidationTest, ReturnIsConstructible_ArrayOfAtomic) {
-  auto* ret_type = ty.array(Source{{12, 34}}, ty.atomic(ty.i32()), 10);
-  Func("f", {}, ret_type, {});
+    auto* ret_type = ty.array(Source{{12, 34}}, ty.atomic(ty.i32()), 10_u);
+    Func("f", {}, ret_type, {});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: function return type must be a constructible type");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: function return type must be a constructible type");
 }
 
 TEST_F(ResolverFunctionValidationTest, ReturnIsConstructible_StructOfAtomic) {
-  Structure("S", {Member("m", ty.atomic(ty.i32()))});
-  auto* ret_type = ty.type_name(Source{{12, 34}}, "S");
-  Func("f", {}, ret_type, {});
+    Structure("S", {Member("m", ty.atomic(ty.i32()))});
+    auto* ret_type = ty.type_name(Source{{12, 34}}, "S");
+    Func("f", {}, ret_type, {});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: function return type must be a constructible type");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: function return type must be a constructible type");
 }
 
 TEST_F(ResolverFunctionValidationTest, ReturnIsConstructible_RuntimeArray) {
-  auto* ret_type = ty.array(Source{{12, 34}}, ty.i32());
-  Func("f", {}, ret_type, {});
+    auto* ret_type = ty.array(Source{{12, 34}}, ty.i32());
+    Func("f", {}, ret_type, {});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: function return type must be a constructible type");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: function return type must be a constructible type");
 }
 
 TEST_F(ResolverFunctionValidationTest, ParameterStoreType_NonAtomicFree) {
-  Structure("S", {Member("m", ty.atomic(ty.i32()))});
-  auto* ret_type = ty.type_name(Source{{12, 34}}, "S");
-  auto* bar = Param(Source{{12, 34}}, "bar", ret_type);
-  Func("f", ast::VariableList{bar}, ty.void_(), {});
+    Structure("S", {Member("m", ty.atomic(ty.i32()))});
+    auto* ret_type = ty.type_name(Source{{12, 34}}, "S");
+    auto* bar = Param(Source{{12, 34}}, "bar", ret_type);
+    Func("f", ast::VariableList{bar}, ty.void_(), {});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: store type of function parameter must be a "
-            "constructible type");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: store type of function parameter must be a "
+              "constructible type");
 }
 
 TEST_F(ResolverFunctionValidationTest, ParameterSotreType_AtomicFree) {
-  Structure("S", {Member("m", ty.i32())});
-  auto* ret_type = ty.type_name(Source{{12, 34}}, "S");
-  auto* bar = Param(Source{{12, 34}}, "bar", ret_type);
-  Func("f", ast::VariableList{bar}, ty.void_(), {});
+    Structure("S", {Member("m", ty.i32())});
+    auto* ret_type = ty.type_name(Source{{12, 34}}, "S");
+    auto* bar = Param(Source{{12, 34}}, "bar", ret_type);
+    Func("f", ast::VariableList{bar}, ty.void_(), {});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverFunctionValidationTest, ParametersAtLimit) {
-  ast::VariableList params;
-  for (int i = 0; i < 255; i++) {
-    params.emplace_back(Param("param_" + std::to_string(i), ty.i32()));
-  }
-  Func(Source{{12, 34}}, "f", params, ty.void_(), {});
+    ast::VariableList params;
+    for (int i = 0; i < 255; i++) {
+        params.emplace_back(Param("param_" + std::to_string(i), ty.i32()));
+    }
+    Func(Source{{12, 34}}, "f", params, ty.void_(), {});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverFunctionValidationTest, ParametersOverLimit) {
-  ast::VariableList params;
-  for (int i = 0; i < 256; i++) {
-    params.emplace_back(Param("param_" + std::to_string(i), ty.i32()));
-  }
-  Func(Source{{12, 34}}, "f", params, ty.void_(), {});
+    ast::VariableList params;
+    for (int i = 0; i < 256; i++) {
+        params.emplace_back(Param("param_" + std::to_string(i), ty.i32()));
+    }
+    Func(Source{{12, 34}}, "f", params, ty.void_(), {});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: functions may declare at most 255 parameters");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: functions may declare at most 255 parameters");
 }
 
 TEST_F(ResolverFunctionValidationTest, ParameterVectorNoType) {
-  // fn f(p : vec3) {}
+    // fn f(p : vec3) {}
 
-  Func(Source{{12, 34}}, "f",
-       {Param("p", create<ast::Vector>(Source{{12, 34}}, nullptr, 3))},
-       ty.void_(), {});
+    Func(Source{{12, 34}}, "f", {Param("p", create<ast::Vector>(Source{{12, 34}}, nullptr, 3))},
+         ty.void_(), {});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: missing vector element type");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: missing vector element type");
 }
 
 TEST_F(ResolverFunctionValidationTest, ParameterMatrixNoType) {
-  // fn f(p : vec3) {}
+    // fn f(p : vec3) {}
 
-  Func(Source{{12, 34}}, "f",
-       {Param("p", create<ast::Matrix>(Source{{12, 34}}, nullptr, 3, 3))},
-       ty.void_(), {});
+    Func(Source{{12, 34}}, "f", {Param("p", create<ast::Matrix>(Source{{12, 34}}, nullptr, 3, 3))},
+         ty.void_(), {});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: missing matrix element type");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: missing matrix element type");
 }
 
 struct TestParams {
-  ast::StorageClass storage_class;
-  bool should_pass;
+    ast::StorageClass storage_class;
+    bool should_pass;
 };
 
 struct TestWithParams : ResolverTestWithParam<TestParams> {};
 
 using ResolverFunctionParameterValidationTest = TestWithParams;
 TEST_P(ResolverFunctionParameterValidationTest, StorageClass) {
-  auto& param = GetParam();
-  auto* ptr_type = ty.pointer(Source{{12, 34}}, ty.i32(), param.storage_class);
-  auto* arg = Param(Source{{12, 34}}, "p", ptr_type);
-  Func("f", ast::VariableList{arg}, ty.void_(), {});
+    auto& param = GetParam();
+    auto* ptr_type = ty.pointer(Source{{12, 34}}, ty.i32(), param.storage_class);
+    auto* arg = Param(Source{{12, 34}}, "p", ptr_type);
+    Func("f", ast::VariableList{arg}, ty.void_(), {});
 
-  if (param.should_pass) {
-    ASSERT_TRUE(r()->Resolve()) << r()->error();
-  } else {
-    std::stringstream ss;
-    ss << param.storage_class;
-    EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              "12:34 error: function parameter of pointer type cannot be in '" +
-                  ss.str() + "' storage class");
-  }
+    if (param.should_pass) {
+        ASSERT_TRUE(r()->Resolve()) << r()->error();
+    } else {
+        std::stringstream ss;
+        ss << param.storage_class;
+        EXPECT_FALSE(r()->Resolve());
+        EXPECT_EQ(r()->error(), "12:34 error: function parameter of pointer type cannot be in '" +
+                                    ss.str() + "' storage class");
+    }
 }
-INSTANTIATE_TEST_SUITE_P(
-    ResolverTest,
-    ResolverFunctionParameterValidationTest,
-    testing::Values(TestParams{ast::StorageClass::kNone, false},
-                    TestParams{ast::StorageClass::kInput, false},
-                    TestParams{ast::StorageClass::kOutput, false},
-                    TestParams{ast::StorageClass::kUniform, false},
-                    TestParams{ast::StorageClass::kWorkgroup, true},
-                    TestParams{ast::StorageClass::kUniformConstant, false},
-                    TestParams{ast::StorageClass::kStorage, false},
-                    TestParams{ast::StorageClass::kPrivate, true},
-                    TestParams{ast::StorageClass::kFunction, true}));
+INSTANTIATE_TEST_SUITE_P(ResolverTest,
+                         ResolverFunctionParameterValidationTest,
+                         testing::Values(TestParams{ast::StorageClass::kNone, false},
+                                         TestParams{ast::StorageClass::kInput, false},
+                                         TestParams{ast::StorageClass::kOutput, false},
+                                         TestParams{ast::StorageClass::kUniform, false},
+                                         TestParams{ast::StorageClass::kWorkgroup, true},
+                                         TestParams{ast::StorageClass::kHandle, false},
+                                         TestParams{ast::StorageClass::kStorage, false},
+                                         TestParams{ast::StorageClass::kPrivate, true},
+                                         TestParams{ast::StorageClass::kFunction, true}));
 
 }  // namespace
 }  // namespace tint::resolver
diff --git a/src/tint/resolver/host_shareable_validation_test.cc b/src/tint/resolver/host_shareable_validation_test.cc
index 80254f6..01fbfb0 100644
--- a/src/tint/resolver/host_shareable_validation_test.cc
+++ b/src/tint/resolver/host_shareable_validation_test.cc
@@ -24,82 +24,78 @@
 using ResolverHostShareableValidationTest = ResolverTest;
 
 TEST_F(ResolverHostShareableValidationTest, BoolMember) {
-  auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.bool_())});
+    auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.bool_())});
 
-  Global(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kStorage,
-         ast::Access::kRead,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    Global(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  ASSERT_FALSE(r()->Resolve());
+    ASSERT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(
-      r()->error(),
-      R"(56:78 error: Type 'bool' cannot be used in storage class 'storage' as it is non-host-shareable
+    EXPECT_EQ(
+        r()->error(),
+        R"(56:78 error: Type 'bool' cannot be used in storage class 'storage' as it is non-host-shareable
 12:34 note: while analysing structure member S.x
 56:78 note: while instantiating variable g)");
 }
 
 TEST_F(ResolverHostShareableValidationTest, BoolVectorMember) {
-  auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.vec3<bool>())});
+    auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.vec3<bool>())});
 
-  Global(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kStorage,
-         ast::Access::kRead,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    Global(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  ASSERT_FALSE(r()->Resolve());
+    ASSERT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(
-      r()->error(),
-      R"(56:78 error: Type 'vec3<bool>' cannot be used in storage class 'storage' as it is non-host-shareable
+    EXPECT_EQ(
+        r()->error(),
+        R"(56:78 error: Type 'vec3<bool>' cannot be used in storage class 'storage' as it is non-host-shareable
 12:34 note: while analysing structure member S.x
 56:78 note: while instantiating variable g)");
 }
 
 TEST_F(ResolverHostShareableValidationTest, Aliases) {
-  auto* a1 = Alias("a1", ty.bool_());
-  auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.Of(a1))});
-  auto* a2 = Alias("a2", ty.Of(s));
-  Global(Source{{56, 78}}, "g", ty.Of(a2), ast::StorageClass::kStorage,
-         ast::Access::kRead,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    auto* a1 = Alias("a1", ty.bool_());
+    auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.Of(a1))});
+    auto* a2 = Alias("a2", ty.Of(s));
+    Global(Source{{56, 78}}, "g", ty.Of(a2), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  ASSERT_FALSE(r()->Resolve());
+    ASSERT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(
-      r()->error(),
-      R"(56:78 error: Type 'bool' cannot be used in storage class 'storage' as it is non-host-shareable
+    EXPECT_EQ(
+        r()->error(),
+        R"(56:78 error: Type 'bool' cannot be used in storage class 'storage' as it is non-host-shareable
 12:34 note: while analysing structure member S.x
 56:78 note: while instantiating variable g)");
 }
 
 TEST_F(ResolverHostShareableValidationTest, NestedStructures) {
-  auto* i1 = Structure("I1", {Member(Source{{1, 2}}, "x", ty.bool_())});
-  auto* i2 = Structure("I2", {Member(Source{{3, 4}}, "y", ty.Of(i1))});
-  auto* i3 = Structure("I3", {Member(Source{{5, 6}}, "z", ty.Of(i2))});
+    auto* i1 = Structure("I1", {Member(Source{{1, 2}}, "x", ty.bool_())});
+    auto* i2 = Structure("I2", {Member(Source{{3, 4}}, "y", ty.Of(i1))});
+    auto* i3 = Structure("I3", {Member(Source{{5, 6}}, "z", ty.Of(i2))});
 
-  auto* s = Structure("S", {Member(Source{{7, 8}}, "m", ty.Of(i3))});
+    auto* s = Structure("S", {Member(Source{{7, 8}}, "m", ty.Of(i3))});
 
-  Global(Source{{9, 10}}, "g", ty.Of(s), ast::StorageClass::kStorage,
-         ast::Access::kRead,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    Global(Source{{9, 10}}, "g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  ASSERT_FALSE(r()->Resolve());
+    ASSERT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(
-      r()->error(),
-      R"(9:10 error: Type 'bool' cannot be used in storage class 'storage' as it is non-host-shareable
+    EXPECT_EQ(
+        r()->error(),
+        R"(9:10 error: Type 'bool' cannot be used in storage class 'storage' as it is non-host-shareable
 1:2 note: while analysing structure member I1.x
 3:4 note: while analysing structure member I2.y
 5:6 note: while analysing structure member I3.z
@@ -108,35 +104,33 @@
 }
 
 TEST_F(ResolverHostShareableValidationTest, NoError) {
-  auto* i1 =
-      Structure("I1", {
-                          Member(Source{{1, 1}}, "x1", ty.f32()),
-                          Member(Source{{2, 1}}, "y1", ty.vec3<f32>()),
-                          Member(Source{{3, 1}}, "z1", ty.array<i32, 4>()),
-                      });
-  auto* a1 = Alias("a1", ty.Of(i1));
-  auto* i2 = Structure("I2", {
-                                 Member(Source{{4, 1}}, "x2", ty.mat2x2<f32>()),
-                                 Member(Source{{5, 1}}, "y2", ty.Of(i1)),
-                             });
-  auto* a2 = Alias("a2", ty.Of(i2));
-  auto* i3 = Structure("I3", {
-                                 Member(Source{{4, 1}}, "x3", ty.Of(a1)),
-                                 Member(Source{{5, 1}}, "y3", ty.Of(i2)),
-                                 Member(Source{{6, 1}}, "z3", ty.Of(a2)),
-                             });
+    auto* i1 = Structure("I1", {
+                                   Member(Source{{1, 1}}, "x1", ty.f32()),
+                                   Member(Source{{2, 1}}, "y1", ty.vec3<f32>()),
+                                   Member(Source{{3, 1}}, "z1", ty.array<i32, 4>()),
+                               });
+    auto* a1 = Alias("a1", ty.Of(i1));
+    auto* i2 = Structure("I2", {
+                                   Member(Source{{4, 1}}, "x2", ty.mat2x2<f32>()),
+                                   Member(Source{{5, 1}}, "y2", ty.Of(i1)),
+                               });
+    auto* a2 = Alias("a2", ty.Of(i2));
+    auto* i3 = Structure("I3", {
+                                   Member(Source{{4, 1}}, "x3", ty.Of(a1)),
+                                   Member(Source{{5, 1}}, "y3", ty.Of(i2)),
+                                   Member(Source{{6, 1}}, "z3", ty.Of(a2)),
+                               });
 
-  auto* s = Structure("S", {Member(Source{{7, 8}}, "m", ty.Of(i3))});
+    auto* s = Structure("S", {Member(Source{{7, 8}}, "m", ty.Of(i3))});
 
-  Global(Source{{9, 10}}, "g", ty.Of(s), ast::StorageClass::kStorage,
-         ast::Access::kRead,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
-  WrapInFunction();
+    Global(Source{{9, 10}}, "g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
+    WrapInFunction();
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 }  // namespace
diff --git a/src/tint/resolver/increment_decrement_validation_test.cc b/src/tint/resolver/increment_decrement_validation_test.cc
index d97facf..37033c5 100644
--- a/src/tint/resolver/increment_decrement_validation_test.cc
+++ b/src/tint/resolver/increment_decrement_validation_test.cc
@@ -17,217 +17,213 @@
 #include "gmock/gmock.h"
 #include "src/tint/resolver/resolver_test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::resolver {
 namespace {
 
 using ResolverIncrementDecrementValidationTest = ResolverTest;
 
 TEST_F(ResolverIncrementDecrementValidationTest, Increment_Signed) {
-  // var a : i32 = 2;
-  // a++;
-  auto* var = Var("a", ty.i32(), ast::StorageClass::kNone, Expr(2));
-  WrapInFunction(var, Increment(Source{{12, 34}}, "a"));
+    // var a : i32 = 2;
+    // a++;
+    auto* var = Var("a", ty.i32(), ast::StorageClass::kNone, Expr(2_i));
+    WrapInFunction(var, Increment(Source{{12, 34}}, "a"));
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverIncrementDecrementValidationTest, Decrement_Signed) {
-  // var a : i32 = 2;
-  // a--;
-  auto* var = Var("a", ty.i32(), ast::StorageClass::kNone, Expr(2));
-  WrapInFunction(var, Decrement(Source{{12, 34}}, "a"));
+    // var a : i32 = 2;
+    // a--;
+    auto* var = Var("a", ty.i32(), ast::StorageClass::kNone, Expr(2_i));
+    WrapInFunction(var, Decrement(Source{{12, 34}}, "a"));
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverIncrementDecrementValidationTest, Increment_Unsigned) {
-  // var a : u32 = 2u;
-  // a++;
-  auto* var = Var("a", ty.u32(), ast::StorageClass::kNone, Expr(2u));
-  WrapInFunction(var, Increment(Source{{12, 34}}, "a"));
+    // var a : u32 = 2u;
+    // a++;
+    auto* var = Var("a", ty.u32(), ast::StorageClass::kNone, Expr(2_u));
+    WrapInFunction(var, Increment(Source{{12, 34}}, "a"));
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverIncrementDecrementValidationTest, Decrement_Unsigned) {
-  // var a : u32 = 2u;
-  // a--;
-  auto* var = Var("a", ty.u32(), ast::StorageClass::kNone, Expr(2u));
-  WrapInFunction(var, Decrement(Source{{12, 34}}, "a"));
+    // var a : u32 = 2u;
+    // a--;
+    auto* var = Var("a", ty.u32(), ast::StorageClass::kNone, Expr(2_u));
+    WrapInFunction(var, Decrement(Source{{12, 34}}, "a"));
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverIncrementDecrementValidationTest, ThroughPointer) {
-  // var a : i32;
-  // let b : ptr<function,i32> = &a;
-  // *b++;
-  auto* var_a = Var("a", ty.i32(), ast::StorageClass::kFunction);
-  auto* var_b = Const("b", ty.pointer<int>(ast::StorageClass::kFunction),
-                      AddressOf(Expr("a")));
-  WrapInFunction(var_a, var_b, Increment(Source{{12, 34}}, Deref("b")));
+    // var a : i32;
+    // let b : ptr<function,i32> = &a;
+    // *b++;
+    auto* var_a = Var("a", ty.i32(), ast::StorageClass::kFunction);
+    auto* var_b = Let("b", ty.pointer<i32>(ast::StorageClass::kFunction), AddressOf(Expr("a")));
+    WrapInFunction(var_a, var_b, Increment(Source{{12, 34}}, Deref("b")));
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverIncrementDecrementValidationTest, ThroughArray) {
-  // var a : array<i32, 4>;
-  // a[1]++;
-  auto* var_a = Var("a", ty.array(ty.i32(), 4), ast::StorageClass::kNone);
-  WrapInFunction(var_a, Increment(Source{{12, 34}}, IndexAccessor("a", 1)));
+    // var a : array<i32, 4_u>;
+    // a[1i]++;
+    auto* var_a = Var("a", ty.array(ty.i32(), 4_u), ast::StorageClass::kNone);
+    WrapInFunction(var_a, Increment(Source{{12, 34}}, IndexAccessor("a", 1_i)));
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverIncrementDecrementValidationTest, ThroughVector_Index) {
-  // var a : vec4<i32>;
-  // a.y++;
-  auto* var_a = Var("a", ty.vec4(ty.i32()), ast::StorageClass::kNone);
-  WrapInFunction(var_a, Increment(Source{{12, 34}}, IndexAccessor("a", 1)));
+    // var a : vec4<i32>;
+    // a[1i]++;
+    auto* var_a = Var("a", ty.vec4(ty.i32()), ast::StorageClass::kNone);
+    WrapInFunction(var_a, Increment(Source{{12, 34}}, IndexAccessor("a", 1_i)));
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverIncrementDecrementValidationTest, ThroughVector_Member) {
-  // var a : vec4<i32>;
-  // a.y++;
-  auto* var_a = Var("a", ty.vec4(ty.i32()), ast::StorageClass::kNone);
-  WrapInFunction(var_a, Increment(Source{{12, 34}}, MemberAccessor("a", "y")));
+    // var a : vec4<i32>;
+    // a.y++;
+    auto* var_a = Var("a", ty.vec4(ty.i32()), ast::StorageClass::kNone);
+    WrapInFunction(var_a, Increment(Source{{12, 34}}, MemberAccessor("a", "y")));
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverIncrementDecrementValidationTest, Float) {
-  // var a : f32 = 2.0;
-  // a++;
-  auto* var = Var("a", ty.f32(), ast::StorageClass::kNone, Expr(2.f));
-  auto* inc = Increment(Expr(Source{{12, 34}}, "a"));
-  WrapInFunction(var, inc);
+    // var a : f32 = 2.0;
+    // a++;
+    auto* var = Var("a", ty.f32(), ast::StorageClass::kNone, Expr(2.f));
+    auto* inc = Increment(Expr(Source{{12, 34}}, "a"));
+    WrapInFunction(var, inc);
 
-  ASSERT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: increment statement can only be applied to an "
-            "integer scalar");
+    ASSERT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: increment statement can only be applied to an "
+              "integer scalar");
 }
 
 TEST_F(ResolverIncrementDecrementValidationTest, Vector) {
-  // var a : vec4<f32>;
-  // a++;
-  auto* var = Var("a", ty.vec4<i32>(), ast::StorageClass::kNone);
-  auto* inc = Increment(Expr(Source{{12, 34}}, "a"));
-  WrapInFunction(var, inc);
+    // var a : vec4<f32>;
+    // a++;
+    auto* var = Var("a", ty.vec4<i32>(), ast::StorageClass::kNone);
+    auto* inc = Increment(Expr(Source{{12, 34}}, "a"));
+    WrapInFunction(var, inc);
 
-  ASSERT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: increment statement can only be applied to an "
-            "integer scalar");
+    ASSERT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: increment statement can only be applied to an "
+              "integer scalar");
 }
 
 TEST_F(ResolverIncrementDecrementValidationTest, Atomic) {
-  // var<workgroup> a : atomic<i32>;
-  // a++;
-  Global(Source{{12, 34}}, "a", ty.atomic(ty.i32()),
-         ast::StorageClass::kWorkgroup);
-  WrapInFunction(Increment(Expr(Source{{56, 78}}, "a")));
+    // var<workgroup> a : atomic<i32>;
+    // a++;
+    Global(Source{{12, 34}}, "a", ty.atomic(ty.i32()), ast::StorageClass::kWorkgroup);
+    WrapInFunction(Increment(Expr(Source{{56, 78}}, "a")));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "56:78 error: increment statement can only be applied to an "
-            "integer scalar");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "56:78 error: increment statement can only be applied to an "
+              "integer scalar");
 }
 
 TEST_F(ResolverIncrementDecrementValidationTest, Literal) {
-  // 1++;
-  WrapInFunction(Increment(Expr(Source{{56, 78}}, 1)));
+    // 1++;
+    WrapInFunction(Increment(Expr(Source{{56, 78}}, 1_i)));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "56:78 error: cannot modify value of type 'i32'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "56:78 error: cannot modify value of type 'i32'");
 }
 
 TEST_F(ResolverIncrementDecrementValidationTest, Constant) {
-  // let a = 1;
-  // a++;
-  auto* a = Const(Source{{12, 34}}, "a", nullptr, Expr(1));
-  WrapInFunction(a, Increment(Expr(Source{{56, 78}}, "a")));
+    // let a = 1;
+    // a++;
+    auto* a = Let(Source{{12, 34}}, "a", nullptr, Expr(1_i));
+    WrapInFunction(a, Increment(Expr(Source{{56, 78}}, "a")));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), R"(56:78 error: cannot modify constant value
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), R"(56:78 error: cannot modify constant value
 12:34 note: 'a' is declared here:)");
 }
 
 TEST_F(ResolverIncrementDecrementValidationTest, Parameter) {
-  // fn func(a : i32)
-  // {
-  //   a++;
-  // }
-  auto* a = Param(Source{{12, 34}}, "a", ty.i32());
-  Func("func", {a}, ty.void_(), {Increment(Expr(Source{{56, 78}}, "a"))});
+    // fn func(a : i32)
+    // {
+    //   a++;
+    // }
+    auto* a = Param(Source{{12, 34}}, "a", ty.i32());
+    Func("func", {a}, ty.void_(), {Increment(Expr(Source{{56, 78}}, "a"))});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), R"(56:78 error: cannot modify function parameter
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), R"(56:78 error: cannot modify function parameter
 12:34 note: 'a' is declared here:)");
 }
 
 TEST_F(ResolverIncrementDecrementValidationTest, ReturnValue) {
-  // fn func() -> i32 {
-  //   return 0;
-  // }
-  // {
-  //   a++;
-  // }
-  Func("func", {}, ty.i32(), {Return(0)});
-  WrapInFunction(Increment(Call(Source{{56, 78}}, "func")));
+    // fn func() -> i32 {
+    //   return 0;
+    // }
+    // {
+    //   a++;
+    // }
+    Func("func", {}, ty.i32(), {Return(0_i)});
+    WrapInFunction(Increment(Call(Source{{56, 78}}, "func")));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), R"(56:78 error: cannot modify value of type 'i32')");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), R"(56:78 error: cannot modify value of type 'i32')");
 }
 
 TEST_F(ResolverIncrementDecrementValidationTest, ReadOnlyBuffer) {
-  // @group(0) @binding(0) var<storage,read> a : i32;
-  // {
-  //   a++;
-  // }
-  Global(Source{{12, 34}}, "a", ty.i32(), ast::StorageClass::kStorage,
-         ast::Access::kRead, GroupAndBinding(0, 0));
-  WrapInFunction(Increment(Source{{56, 78}}, "a"));
+    // @group(0) @binding(0) var<storage,read> a : i32;
+    // {
+    //   a++;
+    // }
+    Global(Source{{12, 34}}, "a", ty.i32(), ast::StorageClass::kStorage, ast::Access::kRead,
+           GroupAndBinding(0, 0));
+    WrapInFunction(Increment(Source{{56, 78}}, "a"));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "56:78 error: cannot modify read-only type 'ref<storage, i32, read>'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "56:78 error: cannot modify read-only type 'ref<storage, i32, read>'");
 }
 
 TEST_F(ResolverIncrementDecrementValidationTest, Phony) {
-  // _++;
-  WrapInFunction(Increment(Phony(Source{{56, 78}})));
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "56:78 error: cannot modify value of type 'void'");
+    // _++;
+    WrapInFunction(Increment(Phony(Source{{56, 78}})));
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "56:78 error: cannot modify value of type 'void'");
 }
 
 TEST_F(ResolverIncrementDecrementValidationTest, InForLoopInit) {
-  // var a : i32 = 2;
-  // for (a++; ; ) {
-  //   break;
-  // }
-  auto* a = Var("a", ty.i32(), ast::StorageClass::kNone, Expr(2));
-  auto* loop =
-      For(Increment(Source{{56, 78}}, "a"), nullptr, nullptr, Block(Break()));
-  WrapInFunction(a, loop);
+    // var a : i32 = 2;
+    // for (a++; ; ) {
+    //   break;
+    // }
+    auto* a = Var("a", ty.i32(), ast::StorageClass::kNone, Expr(2_i));
+    auto* loop = For(Increment(Source{{56, 78}}, "a"), nullptr, nullptr, Block(Break()));
+    WrapInFunction(a, loop);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverIncrementDecrementValidationTest, InForLoopCont) {
-  // var a : i32 = 2;
-  // for (; ; a++) {
-  //   break;
-  // }
-  auto* a = Var("a", ty.i32(), ast::StorageClass::kNone, Expr(2));
-  auto* loop =
-      For(nullptr, nullptr, Increment(Source{{56, 78}}, "a"), Block(Break()));
-  WrapInFunction(a, loop);
+    // var a : i32 = 2;
+    // for (; ; a++) {
+    //   break;
+    // }
+    auto* a = Var("a", ty.i32(), ast::StorageClass::kNone, Expr(2_i));
+    auto* loop = For(nullptr, nullptr, Increment(Source{{56, 78}}, "a"), Block(Break()));
+    WrapInFunction(a, loop);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 }  // namespace
diff --git a/src/tint/resolver/inferred_type_test.cc b/src/tint/resolver/inferred_type_test.cc
index 32ed284..d8cc649 100644
--- a/src/tint/resolver/inferred_type_test.cc
+++ b/src/tint/resolver/inferred_type_test.cc
@@ -17,6 +17,8 @@
 
 #include "gmock/gmock.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::resolver {
 namespace {
 
@@ -37,21 +39,17 @@
 using mat4x4 = builder::mat4x4<T>;
 template <typename T>
 using alias = builder::alias<T>;
-using f32 = builder::f32;
-using i32 = builder::i32;
-using u32 = builder::u32;
 
-struct ResolverInferredTypeTest : public resolver::TestHelper,
-                                  public testing::Test {};
+struct ResolverInferredTypeTest : public resolver::TestHelper, public testing::Test {};
 
 struct Params {
-  builder::ast_expr_func_ptr create_value;
-  builder::sem_type_func_ptr create_expected_type;
+    builder::ast_expr_func_ptr create_value;
+    builder::sem_type_func_ptr create_expected_type;
 };
 
 template <typename T>
 constexpr Params ParamsFor() {
-  return Params{DataType<T>::Expr, DataType<T>::Sem};
+    return Params{DataType<T>::Expr, DataType<T>::Sem};
 }
 
 Params all_cases[] = {
@@ -78,95 +76,90 @@
 using ResolverInferredTypeParamTest = ResolverTestWithParam<Params>;
 
 TEST_P(ResolverInferredTypeParamTest, GlobalLet_Pass) {
-  auto& params = GetParam();
+    auto& params = GetParam();
 
-  auto* expected_type = params.create_expected_type(*this);
+    auto* expected_type = params.create_expected_type(*this);
 
-  // let a = <type constructor>;
-  auto* ctor_expr = params.create_value(*this, 0);
-  auto* var = GlobalConst("a", nullptr, ctor_expr);
-  WrapInFunction();
+    // let a = <type constructor>;
+    auto* ctor_expr = params.create_value(*this, 0);
+    auto* var = GlobalConst("a", nullptr, ctor_expr);
+    WrapInFunction();
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  EXPECT_EQ(TypeOf(var), expected_type);
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_EQ(TypeOf(var), expected_type);
 }
 
 TEST_P(ResolverInferredTypeParamTest, GlobalVar_Fail) {
-  auto& params = GetParam();
+    auto& params = GetParam();
 
-  // var a = <type constructor>;
-  auto* ctor_expr = params.create_value(*this, 0);
-  Global(Source{{12, 34}}, "a", nullptr, ast::StorageClass::kPrivate,
-         ctor_expr);
-  WrapInFunction();
+    // var a = <type constructor>;
+    auto* ctor_expr = params.create_value(*this, 0);
+    Global(Source{{12, 34}}, "a", nullptr, ast::StorageClass::kPrivate, ctor_expr);
+    WrapInFunction();
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: global var declaration must specify a type");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: global var declaration must specify a type");
 }
 
 TEST_P(ResolverInferredTypeParamTest, LocalLet_Pass) {
-  auto& params = GetParam();
+    auto& params = GetParam();
 
-  auto* expected_type = params.create_expected_type(*this);
+    auto* expected_type = params.create_expected_type(*this);
 
-  // let a = <type constructor>;
-  auto* ctor_expr = params.create_value(*this, 0);
-  auto* var = Const("a", nullptr, ctor_expr);
-  WrapInFunction(var);
+    // let a = <type constructor>;
+    auto* ctor_expr = params.create_value(*this, 0);
+    auto* var = Let("a", nullptr, ctor_expr);
+    WrapInFunction(var);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  EXPECT_EQ(TypeOf(var), expected_type);
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_EQ(TypeOf(var), expected_type);
 }
 
 TEST_P(ResolverInferredTypeParamTest, LocalVar_Pass) {
-  auto& params = GetParam();
+    auto& params = GetParam();
 
-  auto* expected_type = params.create_expected_type(*this);
+    auto* expected_type = params.create_expected_type(*this);
 
-  // var a = <type constructor>;
-  auto* ctor_expr = params.create_value(*this, 0);
-  auto* var = Var("a", nullptr, ast::StorageClass::kFunction, ctor_expr);
-  WrapInFunction(var);
+    // var a = <type constructor>;
+    auto* ctor_expr = params.create_value(*this, 0);
+    auto* var = Var("a", nullptr, ast::StorageClass::kFunction, ctor_expr);
+    WrapInFunction(var);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  EXPECT_EQ(TypeOf(var)->UnwrapRef(), expected_type);
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_EQ(TypeOf(var)->UnwrapRef(), expected_type);
 }
 
-INSTANTIATE_TEST_SUITE_P(ResolverTest,
-                         ResolverInferredTypeParamTest,
-                         testing::ValuesIn(all_cases));
+INSTANTIATE_TEST_SUITE_P(ResolverTest, ResolverInferredTypeParamTest, testing::ValuesIn(all_cases));
 
 TEST_F(ResolverInferredTypeTest, InferArray_Pass) {
-  auto* type = ty.array(ty.u32(), 10);
-  auto* expected_type =
-      create<sem::Array>(create<sem::U32>(), 10u, 4u, 4u * 10u, 4u, 4u);
+    auto* type = ty.array(ty.u32(), 10_u);
+    auto* expected_type = create<sem::Array>(create<sem::U32>(), 10u, 4u, 4u * 10u, 4u, 4u);
 
-  auto* ctor_expr = Construct(type);
-  auto* var = Var("a", nullptr, ast::StorageClass::kFunction, ctor_expr);
-  WrapInFunction(var);
+    auto* ctor_expr = Construct(type);
+    auto* var = Var("a", nullptr, ast::StorageClass::kFunction, ctor_expr);
+    WrapInFunction(var);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  EXPECT_EQ(TypeOf(var)->UnwrapRef(), expected_type);
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_EQ(TypeOf(var)->UnwrapRef(), expected_type);
 }
 
 TEST_F(ResolverInferredTypeTest, InferStruct_Pass) {
-  auto* member = Member("x", ty.i32());
-  auto* str = Structure("S", {member});
+    auto* member = Member("x", ty.i32());
+    auto* str = Structure("S", {member});
 
-  auto* expected_type = create<sem::Struct>(
-      str, str->name,
-      sem::StructMemberList{create<sem::StructMember>(
-          member, member->symbol, create<sem::I32>(), 0u, 0u, 0u, 4u)},
-      0u, 4u, 4u);
+    auto* expected_type =
+        create<sem::Struct>(str, str->name,
+                            sem::StructMemberList{create<sem::StructMember>(
+                                member, member->symbol, create<sem::I32>(), 0u, 0u, 0u, 4u)},
+                            0u, 4u, 4u);
 
-  auto* ctor_expr = Construct(ty.Of(str));
+    auto* ctor_expr = Construct(ty.Of(str));
 
-  auto* var = Var("a", nullptr, ast::StorageClass::kFunction, ctor_expr);
-  WrapInFunction(var);
+    auto* var = Var("a", nullptr, ast::StorageClass::kFunction, ctor_expr);
+    WrapInFunction(var);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  EXPECT_EQ(TypeOf(var)->UnwrapRef(), expected_type);
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_EQ(TypeOf(var)->UnwrapRef(), expected_type);
 }
 
 }  // namespace
diff --git a/src/tint/resolver/is_host_shareable_test.cc b/src/tint/resolver/is_host_shareable_test.cc
index df28e72..a167903 100644
--- a/src/tint/resolver/is_host_shareable_test.cc
+++ b/src/tint/resolver/is_host_shareable_test.cc
@@ -16,7 +16,7 @@
 
 #include "gmock/gmock.h"
 #include "src/tint/resolver/resolver_test_helper.h"
-#include "src/tint/sem/atomic_type.h"
+#include "src/tint/sem/atomic.h"
 
 namespace tint::resolver {
 namespace {
@@ -24,96 +24,78 @@
 using ResolverIsHostShareable = ResolverTest;
 
 TEST_F(ResolverIsHostShareable, Void) {
-  EXPECT_FALSE(r()->IsHostShareable(create<sem::Void>()));
+    EXPECT_FALSE(r()->IsHostShareable(create<sem::Void>()));
 }
 
 TEST_F(ResolverIsHostShareable, Bool) {
-  EXPECT_FALSE(r()->IsHostShareable(create<sem::Bool>()));
+    EXPECT_FALSE(r()->IsHostShareable(create<sem::Bool>()));
 }
 
 TEST_F(ResolverIsHostShareable, NumericScalar) {
-  EXPECT_TRUE(r()->IsHostShareable(create<sem::I32>()));
-  EXPECT_TRUE(r()->IsHostShareable(create<sem::U32>()));
-  EXPECT_TRUE(r()->IsHostShareable(create<sem::F32>()));
+    EXPECT_TRUE(r()->IsHostShareable(create<sem::I32>()));
+    EXPECT_TRUE(r()->IsHostShareable(create<sem::U32>()));
+    EXPECT_TRUE(r()->IsHostShareable(create<sem::F32>()));
 }
 
 TEST_F(ResolverIsHostShareable, NumericVector) {
-  EXPECT_TRUE(
-      r()->IsHostShareable(create<sem::Vector>(create<sem::I32>(), 2u)));
-  EXPECT_TRUE(
-      r()->IsHostShareable(create<sem::Vector>(create<sem::I32>(), 3u)));
-  EXPECT_TRUE(
-      r()->IsHostShareable(create<sem::Vector>(create<sem::I32>(), 4u)));
-  EXPECT_TRUE(
-      r()->IsHostShareable(create<sem::Vector>(create<sem::U32>(), 2u)));
-  EXPECT_TRUE(
-      r()->IsHostShareable(create<sem::Vector>(create<sem::U32>(), 3u)));
-  EXPECT_TRUE(
-      r()->IsHostShareable(create<sem::Vector>(create<sem::U32>(), 4u)));
-  EXPECT_TRUE(
-      r()->IsHostShareable(create<sem::Vector>(create<sem::F32>(), 2u)));
-  EXPECT_TRUE(
-      r()->IsHostShareable(create<sem::Vector>(create<sem::F32>(), 3u)));
-  EXPECT_TRUE(
-      r()->IsHostShareable(create<sem::Vector>(create<sem::F32>(), 4u)));
+    EXPECT_TRUE(r()->IsHostShareable(create<sem::Vector>(create<sem::I32>(), 2u)));
+    EXPECT_TRUE(r()->IsHostShareable(create<sem::Vector>(create<sem::I32>(), 3u)));
+    EXPECT_TRUE(r()->IsHostShareable(create<sem::Vector>(create<sem::I32>(), 4u)));
+    EXPECT_TRUE(r()->IsHostShareable(create<sem::Vector>(create<sem::U32>(), 2u)));
+    EXPECT_TRUE(r()->IsHostShareable(create<sem::Vector>(create<sem::U32>(), 3u)));
+    EXPECT_TRUE(r()->IsHostShareable(create<sem::Vector>(create<sem::U32>(), 4u)));
+    EXPECT_TRUE(r()->IsHostShareable(create<sem::Vector>(create<sem::F32>(), 2u)));
+    EXPECT_TRUE(r()->IsHostShareable(create<sem::Vector>(create<sem::F32>(), 3u)));
+    EXPECT_TRUE(r()->IsHostShareable(create<sem::Vector>(create<sem::F32>(), 4u)));
 }
 
 TEST_F(ResolverIsHostShareable, BoolVector) {
-  EXPECT_FALSE(
-      r()->IsHostShareable(create<sem::Vector>(create<sem::Bool>(), 2u)));
-  EXPECT_FALSE(
-      r()->IsHostShareable(create<sem::Vector>(create<sem::Bool>(), 3u)));
-  EXPECT_FALSE(
-      r()->IsHostShareable(create<sem::Vector>(create<sem::Bool>(), 4u)));
-  EXPECT_FALSE(
-      r()->IsHostShareable(create<sem::Vector>(create<sem::Bool>(), 2u)));
-  EXPECT_FALSE(
-      r()->IsHostShareable(create<sem::Vector>(create<sem::Bool>(), 3u)));
-  EXPECT_FALSE(
-      r()->IsHostShareable(create<sem::Vector>(create<sem::Bool>(), 4u)));
-  EXPECT_FALSE(
-      r()->IsHostShareable(create<sem::Vector>(create<sem::Bool>(), 2u)));
-  EXPECT_FALSE(
-      r()->IsHostShareable(create<sem::Vector>(create<sem::Bool>(), 3u)));
-  EXPECT_FALSE(
-      r()->IsHostShareable(create<sem::Vector>(create<sem::Bool>(), 4u)));
+    EXPECT_FALSE(r()->IsHostShareable(create<sem::Vector>(create<sem::Bool>(), 2u)));
+    EXPECT_FALSE(r()->IsHostShareable(create<sem::Vector>(create<sem::Bool>(), 3u)));
+    EXPECT_FALSE(r()->IsHostShareable(create<sem::Vector>(create<sem::Bool>(), 4u)));
+    EXPECT_FALSE(r()->IsHostShareable(create<sem::Vector>(create<sem::Bool>(), 2u)));
+    EXPECT_FALSE(r()->IsHostShareable(create<sem::Vector>(create<sem::Bool>(), 3u)));
+    EXPECT_FALSE(r()->IsHostShareable(create<sem::Vector>(create<sem::Bool>(), 4u)));
+    EXPECT_FALSE(r()->IsHostShareable(create<sem::Vector>(create<sem::Bool>(), 2u)));
+    EXPECT_FALSE(r()->IsHostShareable(create<sem::Vector>(create<sem::Bool>(), 3u)));
+    EXPECT_FALSE(r()->IsHostShareable(create<sem::Vector>(create<sem::Bool>(), 4u)));
 }
 
 TEST_F(ResolverIsHostShareable, Matrix) {
-  auto* vec2 = create<sem::Vector>(create<sem::F32>(), 2u);
-  auto* vec3 = create<sem::Vector>(create<sem::F32>(), 3u);
-  auto* vec4 = create<sem::Vector>(create<sem::F32>(), 4u);
+    auto* vec2 = create<sem::Vector>(create<sem::F32>(), 2u);
+    auto* vec3 = create<sem::Vector>(create<sem::F32>(), 3u);
+    auto* vec4 = create<sem::Vector>(create<sem::F32>(), 4u);
 
-  EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec2, 2u)));
-  EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec2, 3u)));
-  EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec2, 4u)));
-  EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec3, 2u)));
-  EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec3, 3u)));
-  EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec3, 4u)));
-  EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec4, 2u)));
-  EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec4, 3u)));
-  EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec4, 4u)));
+    EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec2, 2u)));
+    EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec2, 3u)));
+    EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec2, 4u)));
+    EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec3, 2u)));
+    EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec3, 3u)));
+    EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec3, 4u)));
+    EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec4, 2u)));
+    EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec4, 3u)));
+    EXPECT_TRUE(r()->IsHostShareable(create<sem::Matrix>(vec4, 4u)));
 }
 
 TEST_F(ResolverIsHostShareable, Pointer) {
-  auto* ptr = create<sem::Pointer>(
-      create<sem::I32>(), ast::StorageClass::kPrivate, ast::Access::kReadWrite);
-  EXPECT_FALSE(r()->IsHostShareable(ptr));
+    auto* ptr = create<sem::Pointer>(create<sem::I32>(), ast::StorageClass::kPrivate,
+                                     ast::Access::kReadWrite);
+    EXPECT_FALSE(r()->IsHostShareable(ptr));
 }
 
 TEST_F(ResolverIsHostShareable, Atomic) {
-  EXPECT_TRUE(r()->IsHostShareable(create<sem::Atomic>(create<sem::I32>())));
-  EXPECT_TRUE(r()->IsHostShareable(create<sem::Atomic>(create<sem::U32>())));
+    EXPECT_TRUE(r()->IsHostShareable(create<sem::Atomic>(create<sem::I32>())));
+    EXPECT_TRUE(r()->IsHostShareable(create<sem::Atomic>(create<sem::U32>())));
 }
 
 TEST_F(ResolverIsHostShareable, ArraySizedOfHostShareable) {
-  auto* arr = create<sem::Array>(create<sem::I32>(), 5u, 4u, 20u, 4u, 4u);
-  EXPECT_TRUE(r()->IsHostShareable(arr));
+    auto* arr = create<sem::Array>(create<sem::I32>(), 5u, 4u, 20u, 4u, 4u);
+    EXPECT_TRUE(r()->IsHostShareable(arr));
 }
 
 TEST_F(ResolverIsHostShareable, ArrayUnsizedOfHostShareable) {
-  auto* arr = create<sem::Array>(create<sem::I32>(), 0u, 4u, 4u, 4u, 4u);
-  EXPECT_TRUE(r()->IsHostShareable(arr));
+    auto* arr = create<sem::Array>(create<sem::I32>(), 0u, 4u, 4u, 4u, 4u);
+    EXPECT_TRUE(r()->IsHostShareable(arr));
 }
 
 // Note: Structure tests covered in host_shareable_validation_test.cc
diff --git a/src/tint/resolver/is_storeable_test.cc b/src/tint/resolver/is_storeable_test.cc
index c9691f7..2d37d8b 100644
--- a/src/tint/resolver/is_storeable_test.cc
+++ b/src/tint/resolver/is_storeable_test.cc
@@ -16,7 +16,7 @@
 
 #include "gmock/gmock.h"
 #include "src/tint/resolver/resolver_test_helper.h"
-#include "src/tint/sem/atomic_type.h"
+#include "src/tint/sem/atomic.h"
 
 namespace tint::resolver {
 namespace {
@@ -24,114 +24,113 @@
 using ResolverIsStorableTest = ResolverTest;
 
 TEST_F(ResolverIsStorableTest, Void) {
-  EXPECT_FALSE(r()->IsStorable(create<sem::Void>()));
+    EXPECT_FALSE(r()->IsStorable(create<sem::Void>()));
 }
 
 TEST_F(ResolverIsStorableTest, Scalar) {
-  EXPECT_TRUE(r()->IsStorable(create<sem::Bool>()));
-  EXPECT_TRUE(r()->IsStorable(create<sem::I32>()));
-  EXPECT_TRUE(r()->IsStorable(create<sem::U32>()));
-  EXPECT_TRUE(r()->IsStorable(create<sem::F32>()));
+    EXPECT_TRUE(r()->IsStorable(create<sem::Bool>()));
+    EXPECT_TRUE(r()->IsStorable(create<sem::I32>()));
+    EXPECT_TRUE(r()->IsStorable(create<sem::U32>()));
+    EXPECT_TRUE(r()->IsStorable(create<sem::F32>()));
 }
 
 TEST_F(ResolverIsStorableTest, Vector) {
-  EXPECT_TRUE(r()->IsStorable(create<sem::Vector>(create<sem::I32>(), 2u)));
-  EXPECT_TRUE(r()->IsStorable(create<sem::Vector>(create<sem::I32>(), 3u)));
-  EXPECT_TRUE(r()->IsStorable(create<sem::Vector>(create<sem::I32>(), 4u)));
-  EXPECT_TRUE(r()->IsStorable(create<sem::Vector>(create<sem::U32>(), 2u)));
-  EXPECT_TRUE(r()->IsStorable(create<sem::Vector>(create<sem::U32>(), 3u)));
-  EXPECT_TRUE(r()->IsStorable(create<sem::Vector>(create<sem::U32>(), 4u)));
-  EXPECT_TRUE(r()->IsStorable(create<sem::Vector>(create<sem::F32>(), 2u)));
-  EXPECT_TRUE(r()->IsStorable(create<sem::Vector>(create<sem::F32>(), 3u)));
-  EXPECT_TRUE(r()->IsStorable(create<sem::Vector>(create<sem::F32>(), 4u)));
+    EXPECT_TRUE(r()->IsStorable(create<sem::Vector>(create<sem::I32>(), 2u)));
+    EXPECT_TRUE(r()->IsStorable(create<sem::Vector>(create<sem::I32>(), 3u)));
+    EXPECT_TRUE(r()->IsStorable(create<sem::Vector>(create<sem::I32>(), 4u)));
+    EXPECT_TRUE(r()->IsStorable(create<sem::Vector>(create<sem::U32>(), 2u)));
+    EXPECT_TRUE(r()->IsStorable(create<sem::Vector>(create<sem::U32>(), 3u)));
+    EXPECT_TRUE(r()->IsStorable(create<sem::Vector>(create<sem::U32>(), 4u)));
+    EXPECT_TRUE(r()->IsStorable(create<sem::Vector>(create<sem::F32>(), 2u)));
+    EXPECT_TRUE(r()->IsStorable(create<sem::Vector>(create<sem::F32>(), 3u)));
+    EXPECT_TRUE(r()->IsStorable(create<sem::Vector>(create<sem::F32>(), 4u)));
 }
 
 TEST_F(ResolverIsStorableTest, Matrix) {
-  auto* vec2 = create<sem::Vector>(create<sem::F32>(), 2u);
-  auto* vec3 = create<sem::Vector>(create<sem::F32>(), 3u);
-  auto* vec4 = create<sem::Vector>(create<sem::F32>(), 4u);
-  EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec2, 2u)));
-  EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec2, 3u)));
-  EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec2, 4u)));
-  EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec3, 2u)));
-  EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec3, 3u)));
-  EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec3, 4u)));
-  EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec4, 2u)));
-  EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec4, 3u)));
-  EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec4, 4u)));
+    auto* vec2 = create<sem::Vector>(create<sem::F32>(), 2u);
+    auto* vec3 = create<sem::Vector>(create<sem::F32>(), 3u);
+    auto* vec4 = create<sem::Vector>(create<sem::F32>(), 4u);
+    EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec2, 2u)));
+    EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec2, 3u)));
+    EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec2, 4u)));
+    EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec3, 2u)));
+    EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec3, 3u)));
+    EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec3, 4u)));
+    EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec4, 2u)));
+    EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec4, 3u)));
+    EXPECT_TRUE(r()->IsStorable(create<sem::Matrix>(vec4, 4u)));
 }
 
 TEST_F(ResolverIsStorableTest, Pointer) {
-  auto* ptr = create<sem::Pointer>(
-      create<sem::I32>(), ast::StorageClass::kPrivate, ast::Access::kReadWrite);
-  EXPECT_FALSE(r()->IsStorable(ptr));
+    auto* ptr = create<sem::Pointer>(create<sem::I32>(), ast::StorageClass::kPrivate,
+                                     ast::Access::kReadWrite);
+    EXPECT_FALSE(r()->IsStorable(ptr));
 }
 
 TEST_F(ResolverIsStorableTest, Atomic) {
-  EXPECT_TRUE(r()->IsStorable(create<sem::Atomic>(create<sem::I32>())));
-  EXPECT_TRUE(r()->IsStorable(create<sem::Atomic>(create<sem::U32>())));
+    EXPECT_TRUE(r()->IsStorable(create<sem::Atomic>(create<sem::I32>())));
+    EXPECT_TRUE(r()->IsStorable(create<sem::Atomic>(create<sem::U32>())));
 }
 
 TEST_F(ResolverIsStorableTest, ArraySizedOfStorable) {
-  auto* arr = create<sem::Array>(create<sem::I32>(), 5u, 4u, 20u, 4u, 4u);
-  EXPECT_TRUE(r()->IsStorable(arr));
+    auto* arr = create<sem::Array>(create<sem::I32>(), 5u, 4u, 20u, 4u, 4u);
+    EXPECT_TRUE(r()->IsStorable(arr));
 }
 
 TEST_F(ResolverIsStorableTest, ArrayUnsizedOfStorable) {
-  auto* arr = create<sem::Array>(create<sem::I32>(), 0u, 4u, 4u, 4u, 4u);
-  EXPECT_TRUE(r()->IsStorable(arr));
+    auto* arr = create<sem::Array>(create<sem::I32>(), 0u, 4u, 4u, 4u, 4u);
+    EXPECT_TRUE(r()->IsStorable(arr));
 }
 
 TEST_F(ResolverIsStorableTest, Struct_AllMembersStorable) {
-  Structure("S", {
-                     Member("a", ty.i32()),
-                     Member("b", ty.f32()),
-                 });
+    Structure("S", {
+                       Member("a", ty.i32()),
+                       Member("b", ty.f32()),
+                   });
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverIsStorableTest, Struct_SomeMembersNonStorable) {
-  Structure("S", {
-                     Member("a", ty.i32()),
-                     Member("b", ty.pointer<i32>(ast::StorageClass::kPrivate)),
-                 });
+    Structure("S", {
+                       Member("a", ty.i32()),
+                       Member("b", ty.pointer<i32>(ast::StorageClass::kPrivate)),
+                   });
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(error: ptr<private, i32, read_write> cannot be used as the type of a structure member)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(
+        r()->error(),
+        R"(error: ptr<private, i32, read_write> cannot be used as the type of a structure member)");
 }
 
 TEST_F(ResolverIsStorableTest, Struct_NestedStorable) {
-  auto* storable = Structure("Storable", {
-                                             Member("a", ty.i32()),
-                                             Member("b", ty.f32()),
-                                         });
-  Structure("S", {
-                     Member("a", ty.i32()),
-                     Member("b", ty.Of(storable)),
-                 });
+    auto* storable = Structure("Storable", {
+                                               Member("a", ty.i32()),
+                                               Member("b", ty.f32()),
+                                           });
+    Structure("S", {
+                       Member("a", ty.i32()),
+                       Member("b", ty.Of(storable)),
+                   });
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverIsStorableTest, Struct_NestedNonStorable) {
-  auto* non_storable =
-      Structure("nonstorable",
-                {
-                    Member("a", ty.i32()),
-                    Member("b", ty.pointer<i32>(ast::StorageClass::kPrivate)),
-                });
-  Structure("S", {
-                     Member("a", ty.i32()),
-                     Member("b", ty.Of(non_storable)),
-                 });
+    auto* non_storable =
+        Structure("nonstorable", {
+                                     Member("a", ty.i32()),
+                                     Member("b", ty.pointer<i32>(ast::StorageClass::kPrivate)),
+                                 });
+    Structure("S", {
+                       Member("a", ty.i32()),
+                       Member("b", ty.Of(non_storable)),
+                   });
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(error: ptr<private, i32, read_write> cannot be used as the type of a structure member)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(
+        r()->error(),
+        R"(error: ptr<private, i32, read_write> cannot be used as the type of a structure member)");
 }
 
 }  // namespace
diff --git a/src/tint/resolver/pipeline_overridable_constant_test.cc b/src/tint/resolver/pipeline_overridable_constant_test.cc
index 222a5c0..35c145e 100644
--- a/src/tint/resolver/pipeline_overridable_constant_test.cc
+++ b/src/tint/resolver/pipeline_overridable_constant_test.cc
@@ -20,86 +20,85 @@
 namespace {
 
 class ResolverPipelineOverridableConstantTest : 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) {
-    auto* sem = Sem().Get<sem::GlobalVariable>(var);
-    ASSERT_NE(sem, nullptr);
-    EXPECT_EQ(sem->Declaration(), var);
-    EXPECT_TRUE(sem->IsOverridable());
-    EXPECT_EQ(sem->ConstantId(), id);
-    EXPECT_FALSE(sem->ConstantValue());
-  }
+  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) {
+        auto* sem = Sem().Get<sem::GlobalVariable>(var);
+        ASSERT_NE(sem, nullptr);
+        EXPECT_EQ(sem->Declaration(), var);
+        EXPECT_TRUE(sem->IsOverridable());
+        EXPECT_EQ(sem->ConstantId(), id);
+        EXPECT_FALSE(sem->ConstantValue());
+    }
 };
 
 TEST_F(ResolverPipelineOverridableConstantTest, NonOverridable) {
-  auto* a = GlobalConst("a", ty.f32(), Expr(1.f));
+    auto* a = GlobalConst("a", ty.f32(), Expr(1.f));
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem_a = Sem().Get<sem::GlobalVariable>(a);
-  ASSERT_NE(sem_a, nullptr);
-  EXPECT_EQ(sem_a->Declaration(), a);
-  EXPECT_FALSE(sem_a->IsOverridable());
-  EXPECT_TRUE(sem_a->ConstantValue());
+    auto* sem_a = Sem().Get<sem::GlobalVariable>(a);
+    ASSERT_NE(sem_a, nullptr);
+    EXPECT_EQ(sem_a->Declaration(), a);
+    EXPECT_FALSE(sem_a->IsOverridable());
+    EXPECT_TRUE(sem_a->ConstantValue());
 }
 
 TEST_F(ResolverPipelineOverridableConstantTest, WithId) {
-  auto* a = Override("a", ty.f32(), Expr(1.f), {Id(7u)});
+    auto* a = Override("a", ty.f32(), Expr(1.f), {Id(7u)});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ExpectConstantId(a, 7u);
+    ExpectConstantId(a, 7u);
 }
 
 TEST_F(ResolverPipelineOverridableConstantTest, WithoutId) {
-  auto* a = Override("a", ty.f32(), Expr(1.f));
+    auto* a = Override("a", ty.f32(), Expr(1.f));
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ExpectConstantId(a, 0u);
+    ExpectConstantId(a, 0u);
 }
 
 TEST_F(ResolverPipelineOverridableConstantTest, WithAndWithoutIds) {
-  std::vector<ast::Variable*> variables;
-  auto* a = Override("a", ty.f32(), Expr(1.f));
-  auto* b = Override("b", ty.f32(), Expr(1.f));
-  auto* c = Override("c", ty.f32(), Expr(1.f), {Id(2u)});
-  auto* d = Override("d", ty.f32(), Expr(1.f), {Id(4u)});
-  auto* e = Override("e", ty.f32(), Expr(1.f));
-  auto* f = Override("f", ty.f32(), Expr(1.f), {Id(1u)});
+    std::vector<ast::Variable*> variables;
+    auto* a = Override("a", ty.f32(), Expr(1.f));
+    auto* b = Override("b", ty.f32(), Expr(1.f));
+    auto* c = Override("c", ty.f32(), Expr(1.f), {Id(2u)});
+    auto* d = Override("d", ty.f32(), Expr(1.f), {Id(4u)});
+    auto* e = Override("e", ty.f32(), Expr(1.f));
+    auto* f = Override("f", ty.f32(), Expr(1.f), {Id(1u)});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    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);
+    // 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);
 }
 
 TEST_F(ResolverPipelineOverridableConstantTest, 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)});
+    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_FALSE(r()->Resolve());
 
-  EXPECT_EQ(r()->error(), R"(56:78 error: pipeline constant IDs must be unique
+    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:)");
 }
 
 TEST_F(ResolverPipelineOverridableConstantTest, IdTooLarge) {
-  Override("a", ty.f32(), Expr(1.f), {Id(Source{{12, 34}}, 65536u)});
+    Override("a", ty.f32(), Expr(1.f), {Id(Source{{12, 34}}, 65536u)});
 
-  EXPECT_FALSE(r()->Resolve());
+    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: pipeline constant IDs must be between 0 and 65535");
 }
 
 }  // namespace
diff --git a/src/tint/resolver/ptr_ref_test.cc b/src/tint/resolver/ptr_ref_test.cc
index f19f964..69b7e54 100644
--- a/src/tint/resolver/ptr_ref_test.cc
+++ b/src/tint/resolver/ptr_ref_test.cc
@@ -14,108 +14,95 @@
 
 #include "src/tint/resolver/resolver.h"
 #include "src/tint/resolver/resolver_test_helper.h"
-#include "src/tint/sem/reference_type.h"
+#include "src/tint/sem/reference.h"
 
 #include "gmock/gmock.h"
 
 namespace tint::resolver {
 namespace {
 
-struct ResolverPtrRefTest : public resolver::TestHelper,
-                            public testing::Test {};
+struct ResolverPtrRefTest : public resolver::TestHelper, public testing::Test {};
 
 TEST_F(ResolverPtrRefTest, AddressOf) {
-  // var v : i32;
-  // &v
+    // var v : i32;
+    // &v
 
-  auto* v = Var("v", ty.i32(), ast::StorageClass::kNone);
-  auto* expr = AddressOf(v);
+    auto* v = Var("v", ty.i32(), ast::StorageClass::kNone);
+    auto* expr = AddressOf(v);
 
-  WrapInFunction(v, expr);
+    WrapInFunction(v, expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_TRUE(TypeOf(expr)->Is<sem::Pointer>());
-  EXPECT_TRUE(TypeOf(expr)->As<sem::Pointer>()->StoreType()->Is<sem::I32>());
-  EXPECT_EQ(TypeOf(expr)->As<sem::Pointer>()->StorageClass(),
-            ast::StorageClass::kFunction);
+    ASSERT_TRUE(TypeOf(expr)->Is<sem::Pointer>());
+    EXPECT_TRUE(TypeOf(expr)->As<sem::Pointer>()->StoreType()->Is<sem::I32>());
+    EXPECT_EQ(TypeOf(expr)->As<sem::Pointer>()->StorageClass(), ast::StorageClass::kFunction);
 }
 
 TEST_F(ResolverPtrRefTest, AddressOfThenDeref) {
-  // var v : i32;
-  // *(&v)
+    // var v : i32;
+    // *(&v)
 
-  auto* v = Var("v", ty.i32(), ast::StorageClass::kNone);
-  auto* expr = Deref(AddressOf(v));
+    auto* v = Var("v", ty.i32(), ast::StorageClass::kNone);
+    auto* expr = Deref(AddressOf(v));
 
-  WrapInFunction(v, expr);
+    WrapInFunction(v, expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_TRUE(TypeOf(expr)->Is<sem::Reference>());
-  EXPECT_TRUE(TypeOf(expr)->As<sem::Reference>()->StoreType()->Is<sem::I32>());
+    ASSERT_TRUE(TypeOf(expr)->Is<sem::Reference>());
+    EXPECT_TRUE(TypeOf(expr)->As<sem::Reference>()->StoreType()->Is<sem::I32>());
 }
 
 TEST_F(ResolverPtrRefTest, DefaultPtrStorageClass) {
-  // https://gpuweb.github.io/gpuweb/wgsl/#storage-class
+    // https://gpuweb.github.io/gpuweb/wgsl/#storage-class
 
-  auto* buf = Structure("S", {Member("m", ty.i32())});
-  auto* function = Var("f", ty.i32());
-  auto* private_ = Global("p", ty.i32(), ast::StorageClass::kPrivate);
-  auto* workgroup = Global("w", ty.i32(), ast::StorageClass::kWorkgroup);
-  auto* uniform = Global("ub", ty.Of(buf), ast::StorageClass::kUniform,
-                         ast::AttributeList{
-                             create<ast::BindingAttribute>(0),
-                             create<ast::GroupAttribute>(0),
-                         });
-  auto* storage = Global("sb", ty.Of(buf), ast::StorageClass::kStorage,
-                         ast::AttributeList{
-                             create<ast::BindingAttribute>(1),
-                             create<ast::GroupAttribute>(0),
-                         });
+    auto* buf = Structure("S", {Member("m", ty.i32())});
+    auto* function = Var("f", ty.i32());
+    auto* private_ = Global("p", ty.i32(), ast::StorageClass::kPrivate);
+    auto* workgroup = Global("w", ty.i32(), ast::StorageClass::kWorkgroup);
+    auto* uniform = Global("ub", ty.Of(buf), ast::StorageClass::kUniform,
+                           ast::AttributeList{
+                               create<ast::BindingAttribute>(0),
+                               create<ast::GroupAttribute>(0),
+                           });
+    auto* storage = Global("sb", ty.Of(buf), ast::StorageClass::kStorage,
+                           ast::AttributeList{
+                               create<ast::BindingAttribute>(1),
+                               create<ast::GroupAttribute>(0),
+                           });
 
-  auto* function_ptr =
-      Const("f_ptr", ty.pointer(ty.i32(), ast::StorageClass::kFunction),
-            AddressOf(function));
-  auto* private_ptr =
-      Const("p_ptr", ty.pointer(ty.i32(), ast::StorageClass::kPrivate),
-            AddressOf(private_));
-  auto* workgroup_ptr =
-      Const("w_ptr", ty.pointer(ty.i32(), ast::StorageClass::kWorkgroup),
-            AddressOf(workgroup));
-  auto* uniform_ptr =
-      Const("ub_ptr", ty.pointer(ty.Of(buf), ast::StorageClass::kUniform),
-            AddressOf(uniform));
-  auto* storage_ptr =
-      Const("sb_ptr", ty.pointer(ty.Of(buf), ast::StorageClass::kStorage),
-            AddressOf(storage));
+    auto* function_ptr =
+        Let("f_ptr", ty.pointer(ty.i32(), ast::StorageClass::kFunction), AddressOf(function));
+    auto* private_ptr =
+        Let("p_ptr", ty.pointer(ty.i32(), ast::StorageClass::kPrivate), AddressOf(private_));
+    auto* workgroup_ptr =
+        Let("w_ptr", ty.pointer(ty.i32(), ast::StorageClass::kWorkgroup), AddressOf(workgroup));
+    auto* uniform_ptr =
+        Let("ub_ptr", ty.pointer(ty.Of(buf), ast::StorageClass::kUniform), AddressOf(uniform));
+    auto* storage_ptr =
+        Let("sb_ptr", ty.pointer(ty.Of(buf), ast::StorageClass::kStorage), AddressOf(storage));
 
-  WrapInFunction(function, function_ptr, private_ptr, workgroup_ptr,
-                 uniform_ptr, storage_ptr);
+    WrapInFunction(function, function_ptr, private_ptr, workgroup_ptr, uniform_ptr, storage_ptr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_TRUE(TypeOf(function_ptr)->Is<sem::Pointer>())
-      << "function_ptr is " << TypeOf(function_ptr)->TypeInfo().name;
-  ASSERT_TRUE(TypeOf(private_ptr)->Is<sem::Pointer>())
-      << "private_ptr is " << TypeOf(private_ptr)->TypeInfo().name;
-  ASSERT_TRUE(TypeOf(workgroup_ptr)->Is<sem::Pointer>())
-      << "workgroup_ptr is " << TypeOf(workgroup_ptr)->TypeInfo().name;
-  ASSERT_TRUE(TypeOf(uniform_ptr)->Is<sem::Pointer>())
-      << "uniform_ptr is " << TypeOf(uniform_ptr)->TypeInfo().name;
-  ASSERT_TRUE(TypeOf(storage_ptr)->Is<sem::Pointer>())
-      << "storage_ptr is " << TypeOf(storage_ptr)->TypeInfo().name;
+    ASSERT_TRUE(TypeOf(function_ptr)->Is<sem::Pointer>())
+        << "function_ptr is " << TypeOf(function_ptr)->TypeInfo().name;
+    ASSERT_TRUE(TypeOf(private_ptr)->Is<sem::Pointer>())
+        << "private_ptr is " << TypeOf(private_ptr)->TypeInfo().name;
+    ASSERT_TRUE(TypeOf(workgroup_ptr)->Is<sem::Pointer>())
+        << "workgroup_ptr is " << TypeOf(workgroup_ptr)->TypeInfo().name;
+    ASSERT_TRUE(TypeOf(uniform_ptr)->Is<sem::Pointer>())
+        << "uniform_ptr is " << TypeOf(uniform_ptr)->TypeInfo().name;
+    ASSERT_TRUE(TypeOf(storage_ptr)->Is<sem::Pointer>())
+        << "storage_ptr is " << TypeOf(storage_ptr)->TypeInfo().name;
 
-  EXPECT_EQ(TypeOf(function_ptr)->As<sem::Pointer>()->Access(),
-            ast::Access::kReadWrite);
-  EXPECT_EQ(TypeOf(private_ptr)->As<sem::Pointer>()->Access(),
-            ast::Access::kReadWrite);
-  EXPECT_EQ(TypeOf(workgroup_ptr)->As<sem::Pointer>()->Access(),
-            ast::Access::kReadWrite);
-  EXPECT_EQ(TypeOf(uniform_ptr)->As<sem::Pointer>()->Access(),
-            ast::Access::kRead);
-  EXPECT_EQ(TypeOf(storage_ptr)->As<sem::Pointer>()->Access(),
-            ast::Access::kRead);
+    EXPECT_EQ(TypeOf(function_ptr)->As<sem::Pointer>()->Access(), ast::Access::kReadWrite);
+    EXPECT_EQ(TypeOf(private_ptr)->As<sem::Pointer>()->Access(), ast::Access::kReadWrite);
+    EXPECT_EQ(TypeOf(workgroup_ptr)->As<sem::Pointer>()->Access(), ast::Access::kReadWrite);
+    EXPECT_EQ(TypeOf(uniform_ptr)->As<sem::Pointer>()->Access(), ast::Access::kRead);
+    EXPECT_EQ(TypeOf(storage_ptr)->As<sem::Pointer>()->Access(), ast::Access::kRead);
 }
 
 }  // namespace
diff --git a/src/tint/resolver/ptr_ref_validation_test.cc b/src/tint/resolver/ptr_ref_validation_test.cc
index f86f6e2..b011dd0 100644
--- a/src/tint/resolver/ptr_ref_validation_test.cc
+++ b/src/tint/resolver/ptr_ref_validation_test.cc
@@ -15,157 +15,149 @@
 #include "src/tint/ast/bitcast_expression.h"
 #include "src/tint/resolver/resolver.h"
 #include "src/tint/resolver/resolver_test_helper.h"
-#include "src/tint/sem/reference_type.h"
+#include "src/tint/sem/reference.h"
 
 #include "gmock/gmock.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::resolver {
 namespace {
 
-struct ResolverPtrRefValidationTest : public resolver::TestHelper,
-                                      public testing::Test {};
+struct ResolverPtrRefValidationTest : public resolver::TestHelper, public testing::Test {};
 
 TEST_F(ResolverPtrRefValidationTest, AddressOfLiteral) {
-  // &1
+    // &1
 
-  auto* expr = AddressOf(Expr(Source{{12, 34}}, 1));
+    auto* expr = AddressOf(Expr(Source{{12, 34}}, 1_i));
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(r()->error(), "12:34 error: cannot take the address of expression");
+    EXPECT_EQ(r()->error(), "12:34 error: cannot take the address of expression");
 }
 
 TEST_F(ResolverPtrRefValidationTest, AddressOfLet) {
-  // let l : i32 = 1;
-  // &l
-  auto* l = Const("l", ty.i32(), Expr(1));
-  auto* expr = AddressOf(Expr(Source{{12, 34}}, "l"));
+    // let l : i32 = 1;
+    // &l
+    auto* l = Let("l", ty.i32(), Expr(1_i));
+    auto* expr = AddressOf(Expr(Source{{12, 34}}, "l"));
 
-  WrapInFunction(l, expr);
+    WrapInFunction(l, expr);
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(r()->error(), "12:34 error: cannot take the address of expression");
+    EXPECT_EQ(r()->error(), "12:34 error: cannot take the address of expression");
 }
 
 TEST_F(ResolverPtrRefValidationTest, AddressOfHandle) {
-  // @group(0) @binding(0) var t: texture_3d<f32>;
-  // &t
-  Global("t", ty.sampled_texture(ast::TextureDimension::k3d, ty.f32()),
-         GroupAndBinding(0u, 0u));
-  auto* expr = AddressOf(Expr(Source{{12, 34}}, "t"));
-  WrapInFunction(expr);
+    // @group(0) @binding(0) var t: texture_3d<f32>;
+    // &t
+    Global("t", ty.sampled_texture(ast::TextureDimension::k3d, ty.f32()), GroupAndBinding(0u, 0u));
+    auto* expr = AddressOf(Expr(Source{{12, 34}}, "t"));
+    WrapInFunction(expr);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: cannot take the address of expression in handle "
-            "storage class");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: cannot take the address of expression in handle "
+              "storage class");
 }
 
 TEST_F(ResolverPtrRefValidationTest, AddressOfVectorComponent_MemberAccessor) {
-  // var v : vec4<i32>;
-  // &v.y
-  auto* v = Var("v", ty.vec4<i32>());
-  auto* expr = AddressOf(MemberAccessor(Source{{12, 34}}, "v", "y"));
+    // var v : vec4<i32>;
+    // &v.y
+    auto* v = Var("v", ty.vec4<i32>());
+    auto* expr = AddressOf(MemberAccessor(Source{{12, 34}}, "v", "y"));
 
-  WrapInFunction(v, expr);
+    WrapInFunction(v, expr);
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(r()->error(),
-            "12:34 error: cannot take the address of a vector component");
+    EXPECT_EQ(r()->error(), "12:34 error: cannot take the address of a vector component");
 }
 
 TEST_F(ResolverPtrRefValidationTest, AddressOfVectorComponent_IndexAccessor) {
-  // var v : vec4<i32>;
-  // &v[2]
-  auto* v = Var("v", ty.vec4<i32>());
-  auto* expr = AddressOf(IndexAccessor(Source{{12, 34}}, "v", 2));
+    // var v : vec4<i32>;
+    // &v[2i]
+    auto* v = Var("v", ty.vec4<i32>());
+    auto* expr = AddressOf(IndexAccessor(Source{{12, 34}}, "v", 2_i));
 
-  WrapInFunction(v, expr);
+    WrapInFunction(v, expr);
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(r()->error(),
-            "12:34 error: cannot take the address of a vector component");
+    EXPECT_EQ(r()->error(), "12:34 error: cannot take the address of a vector component");
 }
 
 TEST_F(ResolverPtrRefValidationTest, IndirectOfAddressOfHandle) {
-  // @group(0) @binding(0) var t: texture_3d<f32>;
-  // *&t
-  Global("t", ty.sampled_texture(ast::TextureDimension::k3d, ty.f32()),
-         GroupAndBinding(0u, 0u));
-  auto* expr = Deref(AddressOf(Expr(Source{{12, 34}}, "t")));
-  WrapInFunction(expr);
+    // @group(0) @binding(0) var t: texture_3d<f32>;
+    // *&t
+    Global("t", ty.sampled_texture(ast::TextureDimension::k3d, ty.f32()), GroupAndBinding(0u, 0u));
+    auto* expr = Deref(AddressOf(Expr(Source{{12, 34}}, "t")));
+    WrapInFunction(expr);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: cannot take the address of expression in handle "
-            "storage class");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: cannot take the address of expression in handle "
+              "storage class");
 }
 
 TEST_F(ResolverPtrRefValidationTest, DerefOfLiteral) {
-  // *1
+    // *1
 
-  auto* expr = Deref(Expr(Source{{12, 34}}, 1));
+    auto* expr = Deref(Expr(Source{{12, 34}}, 1_i));
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(r()->error(),
-            "12:34 error: cannot dereference expression of type 'i32'");
+    EXPECT_EQ(r()->error(), "12:34 error: cannot dereference expression of type 'i32'");
 }
 
 TEST_F(ResolverPtrRefValidationTest, DerefOfVar) {
-  // var v : i32 = 1;
-  // *1
-  auto* v = Var("v", ty.i32());
-  auto* expr = Deref(Expr(Source{{12, 34}}, "v"));
+    // var v : i32;
+    // *v
+    auto* v = Var("v", ty.i32());
+    auto* expr = Deref(Expr(Source{{12, 34}}, "v"));
 
-  WrapInFunction(v, expr);
+    WrapInFunction(v, expr);
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(r()->error(),
-            "12:34 error: cannot dereference expression of type 'i32'");
+    EXPECT_EQ(r()->error(), "12:34 error: cannot dereference expression of type 'i32'");
 }
 
 TEST_F(ResolverPtrRefValidationTest, InferredPtrAccessMismatch) {
-  // struct Inner {
-  //    arr: array<i32, 4>;
-  // }
-  // struct S {
-  //    inner: Inner;
-  // }
-  // @group(0) @binding(0) var<storage, read_write> s : S;
-  // fn f() {
-  //   let p : pointer<storage, i32> = &s.inner.arr[2];
-  // }
-  auto* inner = Structure("Inner", {Member("arr", ty.array<i32, 4>())});
-  auto* buf = Structure("S", {Member("inner", ty.Of(inner))});
-  auto* storage = Global("s", ty.Of(buf), ast::StorageClass::kStorage,
-                         ast::Access::kReadWrite,
-                         ast::AttributeList{
-                             create<ast::BindingAttribute>(0),
-                             create<ast::GroupAttribute>(0),
-                         });
+    // struct Inner {
+    //    arr: array<i32, 4u>;
+    // }
+    // struct S {
+    //    inner: Inner;
+    // }
+    // @group(0) @binding(0) var<storage, read_write> s : S;
+    // fn f() {
+    //   let p : pointer<storage, i32> = &s.inner.arr[2i];
+    // }
+    auto* inner = Structure("Inner", {Member("arr", ty.array<i32, 4>())});
+    auto* buf = Structure("S", {Member("inner", ty.Of(inner))});
+    auto* storage = Global("s", ty.Of(buf), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+                           ast::AttributeList{
+                               create<ast::BindingAttribute>(0),
+                               create<ast::GroupAttribute>(0),
+                           });
 
-  auto* expr =
-      IndexAccessor(MemberAccessor(MemberAccessor(storage, "inner"), "arr"), 4);
-  auto* ptr =
-      Const(Source{{12, 34}}, "p", ty.pointer<i32>(ast::StorageClass::kStorage),
-            AddressOf(expr));
+    auto* expr = IndexAccessor(MemberAccessor(MemberAccessor(storage, "inner"), "arr"), 2_i);
+    auto* ptr =
+        Let(Source{{12, 34}}, "p", ty.pointer<i32>(ast::StorageClass::kStorage), AddressOf(expr));
 
-  WrapInFunction(ptr);
+    WrapInFunction(ptr);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: cannot initialize let of type "
-            "'ptr<storage, i32, read>' with value of type "
-            "'ptr<storage, i32, read_write>'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: cannot initialize let of type "
+              "'ptr<storage, i32, read>' with value of type "
+              "'ptr<storage, i32, read_write>'");
 }
 
 }  // namespace
diff --git a/src/tint/resolver/resolver.cc b/src/tint/resolver/resolver.cc
index 4f7c08d..dc1007b 100644
--- a/src/tint/resolver/resolver.cc
+++ b/src/tint/resolver/resolver.cc
@@ -51,23 +51,23 @@
 #include "src/tint/ast/vector.h"
 #include "src/tint/ast/workgroup_attribute.h"
 #include "src/tint/sem/array.h"
-#include "src/tint/sem/atomic_type.h"
+#include "src/tint/sem/atomic.h"
 #include "src/tint/sem/call.h"
-#include "src/tint/sem/depth_multisampled_texture_type.h"
-#include "src/tint/sem/depth_texture_type.h"
+#include "src/tint/sem/depth_multisampled_texture.h"
+#include "src/tint/sem/depth_texture.h"
 #include "src/tint/sem/for_loop_statement.h"
 #include "src/tint/sem/function.h"
 #include "src/tint/sem/if_statement.h"
 #include "src/tint/sem/loop_statement.h"
 #include "src/tint/sem/member_accessor_expression.h"
 #include "src/tint/sem/module.h"
-#include "src/tint/sem/multisampled_texture_type.h"
-#include "src/tint/sem/pointer_type.h"
-#include "src/tint/sem/reference_type.h"
-#include "src/tint/sem/sampled_texture_type.h"
-#include "src/tint/sem/sampler_type.h"
+#include "src/tint/sem/multisampled_texture.h"
+#include "src/tint/sem/pointer.h"
+#include "src/tint/sem/reference.h"
+#include "src/tint/sem/sampled_texture.h"
+#include "src/tint/sem/sampler.h"
 #include "src/tint/sem/statement.h"
-#include "src/tint/sem/storage_texture_type.h"
+#include "src/tint/sem/storage_texture.h"
 #include "src/tint/sem/struct.h"
 #include "src/tint/sem/switch_statement.h"
 #include "src/tint/sem/type_constructor.h"
@@ -85,2820 +85,2586 @@
     : builder_(builder),
       diagnostics_(builder->Diagnostics()),
       builtin_table_(BuiltinTable::Create(*builder)),
-      sem_(builder) {}
+      sem_(builder, dependencies_),
+      validator_(builder, sem_) {}
 
 Resolver::~Resolver() = default;
 
 bool Resolver::Resolve() {
-  if (builder_->Diagnostics().contains_errors()) {
-    return false;
-  }
+    if (builder_->Diagnostics().contains_errors()) {
+        return false;
+    }
 
-  if (!DependencyGraph::Build(builder_->AST(), builder_->Symbols(),
-                              builder_->Diagnostics(), dependencies_)) {
-    return false;
-  }
+    if (!DependencyGraph::Build(builder_->AST(), builder_->Symbols(), builder_->Diagnostics(),
+                                dependencies_)) {
+        return false;
+    }
 
-  // Create the semantic module
-  builder_->Sem().SetModule(
-      builder_->create<sem::Module>(dependencies_.ordered_globals));
+    // Create the semantic module
+    builder_->Sem().SetModule(builder_->create<sem::Module>(dependencies_.ordered_globals));
 
-  bool result = ResolveInternal();
+    bool result = ResolveInternal();
 
-  if (!result && !diagnostics_.contains_errors()) {
-    TINT_ICE(Resolver, diagnostics_)
-        << "resolving failed, but no error was raised";
-    return false;
-  }
+    if (!result && !diagnostics_.contains_errors()) {
+        TINT_ICE(Resolver, diagnostics_) << "resolving failed, but no error was raised";
+        return false;
+    }
 
-  return result;
+    return result;
 }
 
 bool Resolver::ResolveInternal() {
-  Mark(&builder_->AST());
+    Mark(&builder_->AST());
 
-  // Process all module-scope declarations in dependency order.
-  for (auto* decl : dependencies_.ordered_globals) {
-    Mark(decl);
-    if (!Switch(
-            decl,  //
-            [&](const ast::TypeDecl* td) { return TypeDecl(td); },
-            [&](const ast::Function* func) { return Function(func); },
-            [&](const ast::Variable* var) { return GlobalVariable(var); },
-            [&](Default) {
-              TINT_UNREACHABLE(Resolver, diagnostics_)
-                  << "unhandled global declaration: " << decl->TypeInfo().name;
-              return nullptr;
-            })) {
-      return false;
+    // Process all module-scope declarations in dependency order.
+    for (auto* decl : dependencies_.ordered_globals) {
+        Mark(decl);
+        // Enable directives don't have sem node.
+        if (decl->Is<ast::Enable>()) {
+            continue;
+        }
+        if (!Switch(
+                decl,  //
+                [&](const ast::TypeDecl* td) { return TypeDecl(td); },
+                [&](const ast::Function* func) { return Function(func); },
+                [&](const ast::Variable* var) { return GlobalVariable(var); },
+                [&](Default) {
+                    TINT_UNREACHABLE(Resolver, diagnostics_)
+                        << "unhandled global declaration: " << decl->TypeInfo().name;
+                    return nullptr;
+                })) {
+            return false;
+        }
     }
-  }
 
-  AllocateOverridableConstantIds();
+    AllocateOverridableConstantIds();
 
-  SetShadows();
+    SetShadows();
 
-  if (!ValidatePipelineStages()) {
-    return false;
-  }
-
-  bool result = true;
-  for (auto* node : builder_->ASTNodes().Objects()) {
-    if (marked_.count(node) == 0) {
-      TINT_ICE(Resolver, diagnostics_) << "AST node '" << node->TypeInfo().name
-                                       << "' was not reached by the resolver\n"
-                                       << "At: " << node->source << "\n"
-                                       << "Pointer: " << node;
-      result = false;
+    if (!validator_.PipelineStages(entry_points_)) {
+        return false;
     }
-  }
 
-  return result;
+    bool result = true;
+    for (auto* node : builder_->ASTNodes().Objects()) {
+        if (marked_.count(node) == 0) {
+            TINT_ICE(Resolver, diagnostics_)
+                << "AST node '" << node->TypeInfo().name << "' was not reached by the resolver\n"
+                << "At: " << node->source << "\n"
+                << "Pointer: " << node;
+            result = false;
+        }
+    }
+
+    return result;
 }
 
 sem::Type* Resolver::Type(const ast::Type* ty) {
-  Mark(ty);
-  auto* s = Switch(
-      ty,  //
-      [&](const ast::Void*) { return builder_->create<sem::Void>(); },
-      [&](const ast::Bool*) { return builder_->create<sem::Bool>(); },
-      [&](const ast::I32*) { return builder_->create<sem::I32>(); },
-      [&](const ast::U32*) { return builder_->create<sem::U32>(); },
-      [&](const ast::F32*) { return builder_->create<sem::F32>(); },
-      [&](const ast::Vector* t) -> sem::Vector* {
-        if (!t->type) {
-          AddError("missing vector element type", t->source.End());
-          return nullptr;
-        }
-        if (auto* el = Type(t->type)) {
-          if (auto* vector = builder_->create<sem::Vector>(el, t->width)) {
-            if (ValidateVector(vector, t->source)) {
-              return vector;
+    Mark(ty);
+    auto* s = Switch(
+        ty,  //
+        [&](const ast::Void*) { return builder_->create<sem::Void>(); },
+        [&](const ast::Bool*) { return builder_->create<sem::Bool>(); },
+        [&](const ast::I32*) { return builder_->create<sem::I32>(); },
+        [&](const ast::U32*) { return builder_->create<sem::U32>(); },
+        [&](const ast::F32*) { return builder_->create<sem::F32>(); },
+        [&](const ast::Vector* t) -> sem::Vector* {
+            if (!t->type) {
+                AddError("missing vector element type", t->source.End());
+                return nullptr;
             }
-          }
-        }
-        return nullptr;
-      },
-      [&](const ast::Matrix* t) -> sem::Matrix* {
-        if (!t->type) {
-          AddError("missing matrix element type", t->source.End());
-          return nullptr;
-        }
-        if (auto* el = Type(t->type)) {
-          if (auto* column_type = builder_->create<sem::Vector>(el, t->rows)) {
-            if (auto* matrix =
-                    builder_->create<sem::Matrix>(column_type, t->columns)) {
-              if (ValidateMatrix(matrix, t->source)) {
-                return matrix;
-              }
-            }
-          }
-        }
-        return nullptr;
-      },
-      [&](const ast::Array* t) { return Array(t); },
-      [&](const ast::Atomic* t) -> sem::Atomic* {
-        if (auto* el = Type(t->type)) {
-          auto* a = builder_->create<sem::Atomic>(el);
-          if (!ValidateAtomic(t, a)) {
-            return nullptr;
-          }
-          return a;
-        }
-        return nullptr;
-      },
-      [&](const ast::Pointer* t) -> sem::Pointer* {
-        if (auto* el = Type(t->type)) {
-          auto access = t->access;
-          if (access == ast::kUndefined) {
-            access = DefaultAccessForStorageClass(t->storage_class);
-          }
-          return builder_->create<sem::Pointer>(el, t->storage_class, access);
-        }
-        return nullptr;
-      },
-      [&](const ast::Sampler* t) {
-        return builder_->create<sem::Sampler>(t->kind);
-      },
-      [&](const ast::SampledTexture* t) -> sem::SampledTexture* {
-        if (auto* el = Type(t->type)) {
-          return builder_->create<sem::SampledTexture>(t->dim, el);
-        }
-        return nullptr;
-      },
-      [&](const ast::MultisampledTexture* t) -> sem::MultisampledTexture* {
-        if (auto* el = Type(t->type)) {
-          return builder_->create<sem::MultisampledTexture>(t->dim, el);
-        }
-        return nullptr;
-      },
-      [&](const ast::DepthTexture* t) {
-        return builder_->create<sem::DepthTexture>(t->dim);
-      },
-      [&](const ast::DepthMultisampledTexture* t) {
-        return builder_->create<sem::DepthMultisampledTexture>(t->dim);
-      },
-      [&](const ast::StorageTexture* t) -> sem::StorageTexture* {
-        if (auto* el = Type(t->type)) {
-          if (!ValidateStorageTexture(t)) {
-            return nullptr;
-          }
-          return builder_->create<sem::StorageTexture>(t->dim, t->format,
-                                                       t->access, el);
-        }
-        return nullptr;
-      },
-      [&](const ast::ExternalTexture*) {
-        return builder_->create<sem::ExternalTexture>();
-      },
-      [&](Default) {
-        auto* resolved = ResolvedSymbol(ty);
-        return Switch(
-            resolved,  //
-            [&](sem::Type* type) { return type; },
-            [&](sem::Variable* var) {
-              auto name =
-                  builder_->Symbols().NameFor(var->Declaration()->symbol);
-              AddError("cannot use variable '" + name + "' as type",
-                       ty->source);
-              AddNote("'" + name + "' declared here",
-                      var->Declaration()->source);
-              return nullptr;
-            },
-            [&](sem::Function* func) {
-              auto name =
-                  builder_->Symbols().NameFor(func->Declaration()->symbol);
-              AddError("cannot use function '" + name + "' as type",
-                       ty->source);
-              AddNote("'" + name + "' declared here",
-                      func->Declaration()->source);
-              return nullptr;
-            },
-            [&](Default) {
-              if (auto* tn = ty->As<ast::TypeName>()) {
-                if (IsBuiltin(tn->name)) {
-                  auto name = builder_->Symbols().NameFor(tn->name);
-                  AddError("cannot use builtin '" + name + "' as type",
-                           ty->source);
-                  return nullptr;
+            if (auto* el = Type(t->type)) {
+                if (auto* vector = builder_->create<sem::Vector>(el, t->width)) {
+                    if (validator_.Vector(vector, t->source)) {
+                        return vector;
+                    }
                 }
-              }
-              TINT_UNREACHABLE(Resolver, diagnostics_)
-                  << "Unhandled resolved type '"
-                  << (resolved ? resolved->TypeInfo().name : "<null>")
-                  << "' resolved from ast::Type '" << ty->TypeInfo().name
-                  << "'";
-              return nullptr;
-            });
-      });
+            }
+            return nullptr;
+        },
+        [&](const ast::Matrix* t) -> sem::Matrix* {
+            if (!t->type) {
+                AddError("missing matrix element type", t->source.End());
+                return nullptr;
+            }
+            if (auto* el = Type(t->type)) {
+                if (auto* column_type = builder_->create<sem::Vector>(el, t->rows)) {
+                    if (auto* matrix = builder_->create<sem::Matrix>(column_type, t->columns)) {
+                        if (validator_.Matrix(matrix, t->source)) {
+                            return matrix;
+                        }
+                    }
+                }
+            }
+            return nullptr;
+        },
+        [&](const ast::Array* t) { return Array(t); },
+        [&](const ast::Atomic* t) -> sem::Atomic* {
+            if (auto* el = Type(t->type)) {
+                auto* a = builder_->create<sem::Atomic>(el);
+                if (!validator_.Atomic(t, a)) {
+                    return nullptr;
+                }
+                return a;
+            }
+            return nullptr;
+        },
+        [&](const ast::Pointer* t) -> sem::Pointer* {
+            if (auto* el = Type(t->type)) {
+                auto access = t->access;
+                if (access == ast::kUndefined) {
+                    access = DefaultAccessForStorageClass(t->storage_class);
+                }
+                return builder_->create<sem::Pointer>(el, t->storage_class, access);
+            }
+            return nullptr;
+        },
+        [&](const ast::Sampler* t) { return builder_->create<sem::Sampler>(t->kind); },
+        [&](const ast::SampledTexture* t) -> sem::SampledTexture* {
+            if (auto* el = Type(t->type)) {
+                return builder_->create<sem::SampledTexture>(t->dim, el);
+            }
+            return nullptr;
+        },
+        [&](const ast::MultisampledTexture* t) -> sem::MultisampledTexture* {
+            if (auto* el = Type(t->type)) {
+                return builder_->create<sem::MultisampledTexture>(t->dim, el);
+            }
+            return nullptr;
+        },
+        [&](const ast::DepthTexture* t) { return builder_->create<sem::DepthTexture>(t->dim); },
+        [&](const ast::DepthMultisampledTexture* t) {
+            return builder_->create<sem::DepthMultisampledTexture>(t->dim);
+        },
+        [&](const ast::StorageTexture* t) -> sem::StorageTexture* {
+            if (auto* el = Type(t->type)) {
+                if (!validator_.StorageTexture(t)) {
+                    return nullptr;
+                }
+                return builder_->create<sem::StorageTexture>(t->dim, t->format, t->access, el);
+            }
+            return nullptr;
+        },
+        [&](const ast::ExternalTexture*) { return builder_->create<sem::ExternalTexture>(); },
+        [&](Default) {
+            auto* resolved = sem_.ResolvedSymbol(ty);
+            return Switch(
+                resolved,  //
+                [&](sem::Type* type) { return type; },
+                [&](sem::Variable* var) {
+                    auto name = builder_->Symbols().NameFor(var->Declaration()->symbol);
+                    AddError("cannot use variable '" + name + "' as type", ty->source);
+                    AddNote("'" + name + "' declared here", var->Declaration()->source);
+                    return nullptr;
+                },
+                [&](sem::Function* func) {
+                    auto name = builder_->Symbols().NameFor(func->Declaration()->symbol);
+                    AddError("cannot use function '" + name + "' as type", ty->source);
+                    AddNote("'" + name + "' declared here", func->Declaration()->source);
+                    return nullptr;
+                },
+                [&](Default) {
+                    if (auto* tn = ty->As<ast::TypeName>()) {
+                        if (IsBuiltin(tn->name)) {
+                            auto name = builder_->Symbols().NameFor(tn->name);
+                            AddError("cannot use builtin '" + name + "' as type", ty->source);
+                            return nullptr;
+                        }
+                    }
+                    TINT_UNREACHABLE(Resolver, diagnostics_)
+                        << "Unhandled resolved type '"
+                        << (resolved ? resolved->TypeInfo().name : "<null>")
+                        << "' resolved from ast::Type '" << ty->TypeInfo().name << "'";
+                    return nullptr;
+                });
+        });
 
-  if (s) {
-    builder_->Sem().Add(ty, s);
-  }
-  return s;
+    if (s) {
+        builder_->Sem().Add(ty, s);
+    }
+    return s;
 }
 
 sem::Variable* Resolver::Variable(const ast::Variable* var,
                                   VariableKind kind,
                                   uint32_t index /* = 0 */) {
-  const sem::Type* storage_ty = nullptr;
+    const sem::Type* storage_ty = nullptr;
 
-  // If the variable has a declared type, resolve it.
-  if (auto* ty = var->type) {
-    storage_ty = Type(ty);
-    if (!storage_ty) {
-      return nullptr;
-    }
-  }
-
-  const sem::Expression* rhs = nullptr;
-
-  // Does the variable have a constructor?
-  if (var->constructor) {
-    rhs = Expression(var->constructor);
-    if (!rhs) {
-      return nullptr;
+    // If the variable has a declared type, resolve it.
+    if (auto* ty = var->type) {
+        storage_ty = Type(ty);
+        if (!storage_ty) {
+            return nullptr;
+        }
     }
 
-    // If the variable has no declared type, infer it from the RHS
-    if (!storage_ty) {
-      if (!var->is_const && kind == VariableKind::kGlobal) {
-        AddError("global var declaration must specify a type", var->source);
+    const sem::Expression* rhs = nullptr;
+
+    // Does the variable have a constructor?
+    if (var->constructor) {
+        rhs = Expression(var->constructor);
+        if (!rhs) {
+            return nullptr;
+        }
+
+        // If the variable has no declared type, infer it from the RHS
+        if (!storage_ty) {
+            if (!var->is_const && kind == VariableKind::kGlobal) {
+                AddError("global var declaration must specify a type", var->source);
+                return nullptr;
+            }
+
+            storage_ty = rhs->Type()->UnwrapRef();  // Implicit load of RHS
+        }
+    } else if (var->is_const && !var->is_overridable && kind != VariableKind::kParameter) {
+        AddError("let declaration must have an initializer", var->source);
         return nullptr;
-      }
-
-      storage_ty = rhs->Type()->UnwrapRef();  // Implicit load of RHS
+    } else if (!var->type) {
+        AddError((kind == VariableKind::kGlobal)
+                     ? "module scope var declaration requires a type and initializer"
+                     : "function scope var declaration requires a type or initializer",
+                 var->source);
+        return nullptr;
     }
-  } else if (var->is_const && !var->is_overridable &&
-             kind != VariableKind::kParameter) {
-    AddError("let declaration must have an initializer", var->source);
-    return nullptr;
-  } else if (!var->type) {
-    AddError(
-        (kind == VariableKind::kGlobal)
-            ? "module scope var declaration requires a type and initializer"
-            : "function scope var declaration requires a type or initializer",
-        var->source);
-    return nullptr;
-  }
 
-  if (!storage_ty) {
-    TINT_ICE(Resolver, diagnostics_)
-        << "failed to determine storage type for variable '" +
-               builder_->Symbols().NameFor(var->symbol) + "'\n"
-        << "Source: " << var->source;
-    return nullptr;
-  }
-
-  auto storage_class = var->declared_storage_class;
-  if (storage_class == ast::StorageClass::kNone && !var->is_const) {
-    // No declared storage class. Infer from usage / type.
-    if (kind == VariableKind::kLocal) {
-      storage_class = ast::StorageClass::kFunction;
-    } else if (storage_ty->UnwrapRef()->is_handle()) {
-      // https://gpuweb.github.io/gpuweb/wgsl/#module-scope-variables
-      // If the store type is a texture type or a sampler type, then the
-      // variable declaration must not have a storage class attribute. The
-      // storage class will always be handle.
-      storage_class = ast::StorageClass::kUniformConstant;
+    if (!storage_ty) {
+        TINT_ICE(Resolver, diagnostics_) << "failed to determine storage type for variable '" +
+                                                builder_->Symbols().NameFor(var->symbol) + "'\n"
+                                         << "Source: " << var->source;
+        return nullptr;
     }
-  }
 
-  if (kind == VariableKind::kLocal && !var->is_const &&
-      storage_class != ast::StorageClass::kFunction &&
-      IsValidationEnabled(var->attributes,
-                          ast::DisabledValidation::kIgnoreStorageClass)) {
-    AddError("function variable has a non-function storage class", var->source);
-    return nullptr;
-  }
+    auto storage_class = var->declared_storage_class;
+    if (storage_class == ast::StorageClass::kNone && !var->is_const) {
+        // No declared storage class. Infer from usage / type.
+        if (kind == VariableKind::kLocal) {
+            storage_class = ast::StorageClass::kFunction;
+        } else if (storage_ty->UnwrapRef()->is_handle()) {
+            // https://gpuweb.github.io/gpuweb/wgsl/#module-scope-variables
+            // If the store type is a texture type or a sampler type, then the
+            // variable declaration must not have a storage class attribute. The
+            // storage class will always be handle.
+            storage_class = ast::StorageClass::kHandle;
+        }
+    }
 
-  auto access = var->declared_access;
-  if (access == ast::Access::kUndefined) {
-    access = DefaultAccessForStorageClass(storage_class);
-  }
+    if (kind == VariableKind::kLocal && !var->is_const &&
+        storage_class != ast::StorageClass::kFunction &&
+        validator_.IsValidationEnabled(var->attributes,
+                                       ast::DisabledValidation::kIgnoreStorageClass)) {
+        AddError("function variable has a non-function storage class", var->source);
+        return nullptr;
+    }
 
-  auto* var_ty = storage_ty;
-  if (!var->is_const) {
-    // Variable declaration. Unlike `let`, `var` has storage.
-    // Variables are always of a reference type to the declared storage type.
-    var_ty =
-        builder_->create<sem::Reference>(storage_ty, storage_class, access);
-  }
+    auto access = var->declared_access;
+    if (access == ast::Access::kUndefined) {
+        access = DefaultAccessForStorageClass(storage_class);
+    }
 
-  if (rhs && !ValidateVariableConstructorOrCast(var, storage_class, storage_ty,
-                                                rhs->Type())) {
-    return nullptr;
-  }
+    auto* var_ty = storage_ty;
+    if (!var->is_const) {
+        // Variable declaration. Unlike `let`, `var` has storage.
+        // Variables are always of a reference type to the declared storage type.
+        var_ty = builder_->create<sem::Reference>(storage_ty, storage_class, access);
+    }
 
-  if (!ApplyStorageClassUsageToType(
-          storage_class, const_cast<sem::Type*>(var_ty), var->source)) {
-    AddNote(
-        std::string("while instantiating ") +
-            ((kind == VariableKind::kParameter) ? "parameter " : "variable ") +
-            builder_->Symbols().NameFor(var->symbol),
-        var->source);
-    return nullptr;
-  }
+    if (rhs && !validator_.VariableConstructorOrCast(var, storage_class, storage_ty, rhs->Type())) {
+        return nullptr;
+    }
 
-  if (kind == VariableKind::kParameter) {
-    if (auto* ptr = var_ty->As<sem::Pointer>()) {
-      // For MSL, we push module-scope variables into the entry point as pointer
-      // parameters, so we also need to handle their store type.
-      if (!ApplyStorageClassUsageToType(
-              ptr->StorageClass(), const_cast<sem::Type*>(ptr->StoreType()),
-              var->source)) {
-        AddNote("while instantiating parameter " +
+    if (!ApplyStorageClassUsageToType(storage_class, const_cast<sem::Type*>(var_ty), var->source)) {
+        AddNote(std::string("while instantiating ") +
+                    ((kind == VariableKind::kParameter) ? "parameter " : "variable ") +
                     builder_->Symbols().NameFor(var->symbol),
                 var->source);
         return nullptr;
-      }
     }
-  }
 
-  switch (kind) {
-    case VariableKind::kGlobal: {
-      sem::BindingPoint binding_point;
-      if (auto bp = var->BindingPoint()) {
-        binding_point = {bp.group->value, bp.binding->value};
-      }
-
-      bool has_const_val = rhs && var->is_const && !var->is_overridable;
-      auto* global = builder_->create<sem::GlobalVariable>(
-          var, var_ty, storage_class, access,
-          has_const_val ? rhs->ConstantValue() : sem::Constant{},
-          binding_point);
-
-      if (var->is_overridable) {
-        global->SetIsOverridable();
-        if (auto* id = ast::GetAttribute<ast::IdAttribute>(var->attributes)) {
-          global->SetConstantId(static_cast<uint16_t>(id->value));
+    if (kind == VariableKind::kParameter) {
+        if (auto* ptr = var_ty->As<sem::Pointer>()) {
+            // For MSL, we push module-scope variables into the entry point as pointer
+            // parameters, so we also need to handle their store type.
+            if (!ApplyStorageClassUsageToType(
+                    ptr->StorageClass(), const_cast<sem::Type*>(ptr->StoreType()), var->source)) {
+                AddNote("while instantiating parameter " + builder_->Symbols().NameFor(var->symbol),
+                        var->source);
+                return nullptr;
+            }
         }
-      }
-
-      global->SetConstructor(rhs);
-
-      builder_->Sem().Add(var, global);
-      return global;
     }
-    case VariableKind::kLocal: {
-      auto* local = builder_->create<sem::LocalVariable>(
-          var, var_ty, storage_class, access, current_statement_,
-          (rhs && var->is_const) ? rhs->ConstantValue() : sem::Constant{});
-      builder_->Sem().Add(var, local);
-      local->SetConstructor(rhs);
-      return local;
-    }
-    case VariableKind::kParameter: {
-      auto* param = builder_->create<sem::Parameter>(var, index, var_ty,
-                                                     storage_class, access);
-      builder_->Sem().Add(var, param);
-      return param;
-    }
-  }
 
-  TINT_UNREACHABLE(Resolver, diagnostics_)
-      << "unhandled VariableKind " << static_cast<int>(kind);
-  return nullptr;
+    switch (kind) {
+        case VariableKind::kGlobal: {
+            sem::BindingPoint binding_point;
+            if (auto bp = var->BindingPoint()) {
+                binding_point = {bp.group->value, bp.binding->value};
+            }
+
+            bool has_const_val = rhs && var->is_const && !var->is_overridable;
+            auto* global = builder_->create<sem::GlobalVariable>(
+                var, var_ty, storage_class, access,
+                has_const_val ? rhs->ConstantValue() : sem::Constant{}, binding_point);
+
+            if (var->is_overridable) {
+                global->SetIsOverridable();
+                if (auto* id = ast::GetAttribute<ast::IdAttribute>(var->attributes)) {
+                    global->SetConstantId(static_cast<uint16_t>(id->value));
+                }
+            }
+
+            global->SetConstructor(rhs);
+
+            builder_->Sem().Add(var, global);
+            return global;
+        }
+        case VariableKind::kLocal: {
+            auto* local = builder_->create<sem::LocalVariable>(
+                var, var_ty, storage_class, access, current_statement_,
+                (rhs && var->is_const) ? rhs->ConstantValue() : sem::Constant{});
+            builder_->Sem().Add(var, local);
+            local->SetConstructor(rhs);
+            return local;
+        }
+        case VariableKind::kParameter: {
+            auto* param =
+                builder_->create<sem::Parameter>(var, index, var_ty, storage_class, access);
+            builder_->Sem().Add(var, param);
+            return param;
+        }
+    }
+
+    TINT_UNREACHABLE(Resolver, diagnostics_) << "unhandled VariableKind " << static_cast<int>(kind);
+    return nullptr;
 }
 
-ast::Access Resolver::DefaultAccessForStorageClass(
-    ast::StorageClass storage_class) {
-  // https://gpuweb.github.io/gpuweb/wgsl/#storage-class
-  switch (storage_class) {
-    case ast::StorageClass::kStorage:
-    case ast::StorageClass::kUniform:
-    case ast::StorageClass::kUniformConstant:
-      return ast::Access::kRead;
-    default:
-      break;
-  }
-  return ast::Access::kReadWrite;
+ast::Access Resolver::DefaultAccessForStorageClass(ast::StorageClass storage_class) {
+    // https://gpuweb.github.io/gpuweb/wgsl/#storage-class
+    switch (storage_class) {
+        case ast::StorageClass::kStorage:
+        case ast::StorageClass::kUniform:
+        case ast::StorageClass::kHandle:
+            return ast::Access::kRead;
+        default:
+            break;
+    }
+    return ast::Access::kReadWrite;
 }
 
 void Resolver::AllocateOverridableConstantIds() {
-  // The next pipeline constant ID to try to allocate.
-  uint16_t next_constant_id = 0;
+    // The next pipeline constant ID to try to allocate.
+    uint16_t next_constant_id = 0;
 
-  // Allocate constant IDs in global declaration order, so that they are
-  // deterministic.
-  // TODO(crbug.com/tint/1192): If a transform changes the order or removes an
-  // unused constant, the allocation may change on the next Resolver pass.
-  for (auto* decl : builder_->AST().GlobalDeclarations()) {
-    auto* var = decl->As<ast::Variable>();
-    if (!var || !var->is_overridable) {
-      continue;
-    }
-
-    uint16_t constant_id;
-    if (auto* id_attr = ast::GetAttribute<ast::IdAttribute>(var->attributes)) {
-      constant_id = static_cast<uint16_t>(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;
+    // Allocate constant IDs in global declaration order, so that they are
+    // deterministic.
+    // TODO(crbug.com/tint/1192): If a transform changes the order or removes an
+    // unused constant, the allocation may change on the next Resolver pass.
+    for (auto* decl : builder_->AST().GlobalDeclarations()) {
+        auto* var = decl->As<ast::Variable>();
+        if (!var || !var->is_overridable) {
+            continue;
         }
-        constant_id++;
-      }
-      next_constant_id = constant_id + 1;
-    }
 
-    auto* sem = sem_.Get<sem::GlobalVariable>(var);
-    const_cast<sem::GlobalVariable*>(sem)->SetConstantId(constant_id);
-  }
+        uint16_t constant_id;
+        if (auto* id_attr = ast::GetAttribute<ast::IdAttribute>(var->attributes)) {
+            constant_id = static_cast<uint16_t>(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++;
+            }
+            next_constant_id = constant_id + 1;
+        }
+
+        auto* sem = sem_.Get<sem::GlobalVariable>(var);
+        const_cast<sem::GlobalVariable*>(sem)->SetConstantId(constant_id);
+    }
 }
 
 void Resolver::SetShadows() {
-  for (auto it : dependencies_.shadows) {
-    Switch(
-        sem_.Get(it.first),  //
-        [&](sem::LocalVariable* local) {
-          local->SetShadows(sem_.Get(it.second));
-        },
-        [&](sem::Parameter* param) { param->SetShadows(sem_.Get(it.second)); });
-  }
+    for (auto it : dependencies_.shadows) {
+        Switch(
+            sem_.Get(it.first),  //
+            [&](sem::LocalVariable* local) { local->SetShadows(sem_.Get(it.second)); },
+            [&](sem::Parameter* param) { param->SetShadows(sem_.Get(it.second)); });
+    }
 }
 
 sem::GlobalVariable* Resolver::GlobalVariable(const ast::Variable* var) {
-  auto* sem = Variable(var, VariableKind::kGlobal);
-  if (!sem) {
-    return nullptr;
-  }
-
-  auto storage_class = sem->StorageClass();
-  if (!var->is_const && storage_class == ast::StorageClass::kNone) {
-    AddError("global variables must have a storage class", var->source);
-    return nullptr;
-  }
-  if (var->is_const && storage_class != ast::StorageClass::kNone) {
-    AddError("global constants shouldn't have a storage class", var->source);
-    return nullptr;
-  }
-
-  for (auto* attr : var->attributes) {
-    Mark(attr);
-
-    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);
+    auto* sem = Variable(var, VariableKind::kGlobal);
+    if (!sem) {
+        return nullptr;
     }
-  }
 
-  if (!ValidateNoDuplicateAttributes(var->attributes)) {
-    return nullptr;
-  }
+    auto storage_class = sem->StorageClass();
+    if (!var->is_const && storage_class == ast::StorageClass::kNone) {
+        AddError("global variables must have a storage class", var->source);
+        return nullptr;
+    }
+    if (var->is_const && storage_class != ast::StorageClass::kNone) {
+        AddError("global constants shouldn't have a storage class", var->source);
+        return nullptr;
+    }
 
-  if (!ValidateGlobalVariable(sem)) {
-    return nullptr;
-  }
+    for (auto* attr : var->attributes) {
+        Mark(attr);
 
-  // TODO(bclayton): Call this at the end of resolve on all uniform and storage
-  // referenced structs
-  if (!ValidateStorageClassLayout(sem, valid_type_storage_layouts_)) {
-    return nullptr;
-  }
+        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);
+        }
+    }
 
-  return sem->As<sem::GlobalVariable>();
+    if (!validator_.NoDuplicateAttributes(var->attributes)) {
+        return nullptr;
+    }
+
+    if (!validator_.GlobalVariable(sem, constant_ids_, atomic_composite_info_)) {
+        return nullptr;
+    }
+
+    // TODO(bclayton): Call this at the end of resolve on all uniform and storage
+    // referenced structs
+    if (!validator_.StorageClassLayout(sem, valid_type_storage_layouts_)) {
+        return nullptr;
+    }
+
+    return sem->As<sem::GlobalVariable>();
 }
 
 sem::Function* Resolver::Function(const ast::Function* decl) {
-  uint32_t parameter_index = 0;
-  std::unordered_map<Symbol, Source> parameter_names;
-  std::vector<sem::Parameter*> parameters;
+    uint32_t parameter_index = 0;
+    std::unordered_map<Symbol, Source> parameter_names;
+    std::vector<sem::Parameter*> parameters;
 
-  // Resolve all the parameters
-  for (auto* param : decl->params) {
-    Mark(param);
+    // Resolve all the parameters
+    for (auto* param : decl->params) {
+        Mark(param);
 
-    {  // Check the parameter name is unique for the function
-      auto emplaced = parameter_names.emplace(param->symbol, param->source);
-      if (!emplaced.second) {
-        auto name = builder_->Symbols().NameFor(param->symbol);
-        AddError("redefinition of parameter '" + name + "'", param->source);
-        AddNote("previous definition is here", emplaced.first->second);
+        {  // Check the parameter name is unique for the function
+            auto emplaced = parameter_names.emplace(param->symbol, param->source);
+            if (!emplaced.second) {
+                auto name = builder_->Symbols().NameFor(param->symbol);
+                AddError("redefinition of parameter '" + name + "'", param->source);
+                AddNote("previous definition is here", emplaced.first->second);
+                return nullptr;
+            }
+        }
+
+        auto* var =
+            As<sem::Parameter>(Variable(param, VariableKind::kParameter, parameter_index++));
+        if (!var) {
+            return nullptr;
+        }
+
+        for (auto* attr : param->attributes) {
+            Mark(attr);
+        }
+        if (!validator_.NoDuplicateAttributes(param->attributes)) {
+            return nullptr;
+        }
+
+        parameters.emplace_back(var);
+
+        auto* var_ty = const_cast<sem::Type*>(var->Type());
+        if (auto* str = var_ty->As<sem::Struct>()) {
+            switch (decl->PipelineStage()) {
+                case ast::PipelineStage::kVertex:
+                    str->AddUsage(sem::PipelineStageUsage::kVertexInput);
+                    break;
+                case ast::PipelineStage::kFragment:
+                    str->AddUsage(sem::PipelineStageUsage::kFragmentInput);
+                    break;
+                case ast::PipelineStage::kCompute:
+                    str->AddUsage(sem::PipelineStageUsage::kComputeInput);
+                    break;
+                case ast::PipelineStage::kNone:
+                    break;
+            }
+        }
+    }
+
+    // Resolve the return type
+    sem::Type* return_type = nullptr;
+    if (auto* ty = decl->return_type) {
+        return_type = Type(ty);
+        if (!return_type) {
+            return nullptr;
+        }
+    } else {
+        return_type = builder_->create<sem::Void>();
+    }
+
+    if (auto* str = return_type->As<sem::Struct>()) {
+        if (!ApplyStorageClassUsageToType(ast::StorageClass::kNone, str, decl->source)) {
+            AddNote(
+                "while instantiating return type for " + builder_->Symbols().NameFor(decl->symbol),
+                decl->source);
+            return nullptr;
+        }
+
+        switch (decl->PipelineStage()) {
+            case ast::PipelineStage::kVertex:
+                str->AddUsage(sem::PipelineStageUsage::kVertexOutput);
+                break;
+            case ast::PipelineStage::kFragment:
+                str->AddUsage(sem::PipelineStageUsage::kFragmentOutput);
+                break;
+            case ast::PipelineStage::kCompute:
+                str->AddUsage(sem::PipelineStageUsage::kComputeOutput);
+                break;
+            case ast::PipelineStage::kNone:
+                break;
+        }
+    }
+
+    auto* func = builder_->create<sem::Function>(decl, return_type, parameters);
+    builder_->Sem().Add(decl, func);
+
+    TINT_SCOPED_ASSIGNMENT(current_function_, func);
+
+    if (!WorkgroupSize(decl)) {
         return nullptr;
-      }
     }
 
-    auto* var = As<sem::Parameter>(
-        Variable(param, VariableKind::kParameter, parameter_index++));
-    if (!var) {
-      return nullptr;
+    if (decl->IsEntryPoint()) {
+        entry_points_.emplace_back(func);
     }
 
-    for (auto* attr : param->attributes) {
-      Mark(attr);
-    }
-    if (!ValidateNoDuplicateAttributes(param->attributes)) {
-      return nullptr;
+    if (decl->body) {
+        Mark(decl->body);
+        if (current_compound_statement_) {
+            TINT_ICE(Resolver, diagnostics_)
+                << "Resolver::Function() called with a current compound statement";
+            return nullptr;
+        }
+        auto* body = StatementScope(decl->body, builder_->create<sem::FunctionBlockStatement>(func),
+                                    [&] { return Statements(decl->body->statements); });
+        if (!body) {
+            return nullptr;
+        }
+        func->Behaviors() = body->Behaviors();
+        if (func->Behaviors().Contains(sem::Behavior::kReturn)) {
+            // https://www.w3.org/TR/WGSL/#behaviors-rules
+            // We assign a behavior to each function: it is its body’s behavior
+            // (treating the body as a regular statement), with any "Return" replaced
+            // by "Next".
+            func->Behaviors().Remove(sem::Behavior::kReturn);
+            func->Behaviors().Add(sem::Behavior::kNext);
+        }
     }
 
-    parameters.emplace_back(var);
-
-    auto* var_ty = const_cast<sem::Type*>(var->Type());
-    if (auto* str = var_ty->As<sem::Struct>()) {
-      switch (decl->PipelineStage()) {
-        case ast::PipelineStage::kVertex:
-          str->AddUsage(sem::PipelineStageUsage::kVertexInput);
-          break;
-        case ast::PipelineStage::kFragment:
-          str->AddUsage(sem::PipelineStageUsage::kFragmentInput);
-          break;
-        case ast::PipelineStage::kCompute:
-          str->AddUsage(sem::PipelineStageUsage::kComputeInput);
-          break;
-        case ast::PipelineStage::kNone:
-          break;
-      }
+    for (auto* attr : decl->attributes) {
+        Mark(attr);
     }
-  }
-
-  // Resolve the return type
-  sem::Type* return_type = nullptr;
-  if (auto* ty = decl->return_type) {
-    return_type = Type(ty);
-    if (!return_type) {
-      return nullptr;
-    }
-  } else {
-    return_type = builder_->create<sem::Void>();
-  }
-
-  if (auto* str = return_type->As<sem::Struct>()) {
-    if (!ApplyStorageClassUsageToType(ast::StorageClass::kNone, str,
-                                      decl->source)) {
-      AddNote("while instantiating return type for " +
-                  builder_->Symbols().NameFor(decl->symbol),
-              decl->source);
-      return nullptr;
+    if (!validator_.NoDuplicateAttributes(decl->attributes)) {
+        return nullptr;
     }
 
-    switch (decl->PipelineStage()) {
-      case ast::PipelineStage::kVertex:
-        str->AddUsage(sem::PipelineStageUsage::kVertexOutput);
-        break;
-      case ast::PipelineStage::kFragment:
-        str->AddUsage(sem::PipelineStageUsage::kFragmentOutput);
-        break;
-      case ast::PipelineStage::kCompute:
-        str->AddUsage(sem::PipelineStageUsage::kComputeOutput);
-        break;
-      case ast::PipelineStage::kNone:
-        break;
+    for (auto* attr : decl->return_type_attributes) {
+        Mark(attr);
     }
-  }
-
-  auto* func = builder_->create<sem::Function>(decl, return_type, parameters);
-  builder_->Sem().Add(decl, func);
-
-  TINT_SCOPED_ASSIGNMENT(current_function_, func);
-
-  if (!WorkgroupSize(decl)) {
-    return nullptr;
-  }
-
-  if (decl->IsEntryPoint()) {
-    entry_points_.emplace_back(func);
-  }
-
-  if (decl->body) {
-    Mark(decl->body);
-    if (current_compound_statement_) {
-      TINT_ICE(Resolver, diagnostics_)
-          << "Resolver::Function() called with a current compound statement";
-      return nullptr;
+    if (!validator_.NoDuplicateAttributes(decl->return_type_attributes)) {
+        return nullptr;
     }
-    auto* body = StatementScope(
-        decl->body, builder_->create<sem::FunctionBlockStatement>(func),
-        [&] { return Statements(decl->body->statements); });
-    if (!body) {
-      return nullptr;
+
+    auto stage = current_function_ ? current_function_->Declaration()->PipelineStage()
+                                   : ast::PipelineStage::kNone;
+    if (!validator_.Function(func, stage)) {
+        return nullptr;
     }
-    func->Behaviors() = body->Behaviors();
-    if (func->Behaviors().Contains(sem::Behavior::kReturn)) {
-      // https://www.w3.org/TR/WGSL/#behaviors-rules
-      // We assign a behavior to each function: it is its body’s behavior
-      // (treating the body as a regular statement), with any "Return" replaced
-      // by "Next".
-      func->Behaviors().Remove(sem::Behavior::kReturn);
-      func->Behaviors().Add(sem::Behavior::kNext);
+
+    // If this is an entry point, mark all transitively called functions as being
+    // used by this entry point.
+    if (decl->IsEntryPoint()) {
+        for (auto* f : func->TransitivelyCalledFunctions()) {
+            const_cast<sem::Function*>(f)->AddAncestorEntryPoint(func);
+        }
     }
-  }
 
-  for (auto* attr : decl->attributes) {
-    Mark(attr);
-  }
-  if (!ValidateNoDuplicateAttributes(decl->attributes)) {
-    return nullptr;
-  }
-
-  for (auto* attr : decl->return_type_attributes) {
-    Mark(attr);
-  }
-  if (!ValidateNoDuplicateAttributes(decl->return_type_attributes)) {
-    return nullptr;
-  }
-
-  auto stage = current_function_
-                   ? current_function_->Declaration()->PipelineStage()
-                   : ast::PipelineStage::kNone;
-  if (!ValidateFunction(func, stage)) {
-    return nullptr;
-  }
-
-  // If this is an entry point, mark all transitively called functions as being
-  // used by this entry point.
-  if (decl->IsEntryPoint()) {
-    for (auto* f : func->TransitivelyCalledFunctions()) {
-      const_cast<sem::Function*>(f)->AddAncestorEntryPoint(func);
-    }
-  }
-
-  return func;
+    return func;
 }
 
 bool Resolver::WorkgroupSize(const ast::Function* func) {
-  // Set work-group size defaults.
-  sem::WorkgroupSize ws;
-  for (int i = 0; i < 3; i++) {
-    ws[i].value = 1;
-    ws[i].overridable_const = nullptr;
-  }
+    // Set work-group size defaults.
+    sem::WorkgroupSize ws;
+    for (int i = 0; i < 3; i++) {
+        ws[i].value = 1;
+        ws[i].overridable_const = nullptr;
+    }
 
-  auto* attr = ast::GetAttribute<ast::WorkgroupAttribute>(func->attributes);
-  if (!attr) {
+    auto* attr = ast::GetAttribute<ast::WorkgroupAttribute>(func->attributes);
+    if (!attr) {
+        return true;
+    }
+
+    auto values = attr->Values();
+    auto any_i32 = false;
+    auto any_u32 = false;
+    for (int i = 0; i < 3; i++) {
+        // Each argument to this attribute can either be a literal, an
+        // identifier for a module-scope constants, or nullptr if not specified.
+
+        auto* expr = values[i];
+        if (!expr) {
+            // Not specified, just use the default.
+            continue;
+        }
+
+        auto* expr_sem = Expression(expr);
+        if (!expr_sem) {
+            return false;
+        }
+
+        constexpr const char* kErrBadType =
+            "workgroup_size argument must be either literal or module-scope "
+            "constant of type i32 or u32";
+        constexpr const char* kErrInconsistentType =
+            "workgroup_size arguments must be of the same type, either i32 "
+            "or u32";
+
+        auto* ty = sem_.TypeOf(expr);
+        bool is_i32 = ty->UnwrapRef()->Is<sem::I32>();
+        bool is_u32 = ty->UnwrapRef()->Is<sem::U32>();
+        if (!is_i32 && !is_u32) {
+            AddError(kErrBadType, expr->source);
+            return false;
+        }
+
+        any_i32 = any_i32 || is_i32;
+        any_u32 = any_u32 || is_u32;
+        if (any_i32 && any_u32) {
+            AddError(kErrInconsistentType, expr->source);
+            return false;
+        }
+
+        sem::Constant value;
+
+        if (auto* user = sem_.Get(expr)->As<sem::VariableUser>()) {
+            // We have an variable of a module-scope constant.
+            auto* decl = user->Variable()->Declaration();
+            if (!decl->is_const) {
+                AddError(kErrBadType, expr->source);
+                return false;
+            }
+            // Capture the constant if it is pipeline-overridable.
+            if (decl->is_overridable) {
+                ws[i].overridable_const = decl;
+            }
+
+            if (decl->constructor) {
+                value = sem_.Get(decl->constructor)->ConstantValue();
+            } else {
+                // No constructor means this value must be overriden by the user.
+                ws[i].value = 0;
+                continue;
+            }
+        } else if (expr->Is<ast::LiteralExpression>()) {
+            value = sem_.Get(expr)->ConstantValue();
+        } else {
+            AddError(
+                "workgroup_size argument must be either a literal or a "
+                "module-scope constant",
+                values[i]->source);
+            return false;
+        }
+
+        if (!value) {
+            TINT_ICE(Resolver, diagnostics_)
+                << "could not resolve constant workgroup_size constant value";
+            continue;
+        }
+        // validator_.Validate and set the default value for this dimension.
+        if (is_i32 ? value.Elements()[0].i32 < 1 : value.Elements()[0].u32 < 1) {
+            AddError("workgroup_size argument must be at least 1", values[i]->source);
+            return false;
+        }
+
+        ws[i].value =
+            is_i32 ? static_cast<uint32_t>(value.Elements()[0].i32) : value.Elements()[0].u32;
+    }
+
+    current_function_->SetWorkgroupSize(std::move(ws));
     return true;
-  }
-
-  auto values = attr->Values();
-  auto any_i32 = false;
-  auto any_u32 = false;
-  for (int i = 0; i < 3; i++) {
-    // Each argument to this attribute can either be a literal, an
-    // identifier for a module-scope constants, or nullptr if not specified.
-
-    auto* expr = values[i];
-    if (!expr) {
-      // Not specified, just use the default.
-      continue;
-    }
-
-    auto* expr_sem = Expression(expr);
-    if (!expr_sem) {
-      return false;
-    }
-
-    constexpr const char* kErrBadType =
-        "workgroup_size argument must be either literal or module-scope "
-        "constant of type i32 or u32";
-    constexpr const char* kErrInconsistentType =
-        "workgroup_size arguments must be of the same type, either i32 "
-        "or u32";
-
-    auto* ty = sem_.TypeOf(expr);
-    bool is_i32 = ty->UnwrapRef()->Is<sem::I32>();
-    bool is_u32 = ty->UnwrapRef()->Is<sem::U32>();
-    if (!is_i32 && !is_u32) {
-      AddError(kErrBadType, expr->source);
-      return false;
-    }
-
-    any_i32 = any_i32 || is_i32;
-    any_u32 = any_u32 || is_u32;
-    if (any_i32 && any_u32) {
-      AddError(kErrInconsistentType, expr->source);
-      return false;
-    }
-
-    sem::Constant value;
-
-    if (auto* user = sem_.Get(expr)->As<sem::VariableUser>()) {
-      // We have an variable of a module-scope constant.
-      auto* decl = user->Variable()->Declaration();
-      if (!decl->is_const) {
-        AddError(kErrBadType, expr->source);
-        return false;
-      }
-      // Capture the constant if it is pipeline-overridable.
-      if (decl->is_overridable) {
-        ws[i].overridable_const = decl;
-      }
-
-      if (decl->constructor) {
-        value = sem_.Get(decl->constructor)->ConstantValue();
-      } else {
-        // No constructor means this value must be overriden by the user.
-        ws[i].value = 0;
-        continue;
-      }
-    } else if (expr->Is<ast::LiteralExpression>()) {
-      value = sem_.Get(expr)->ConstantValue();
-    } else {
-      AddError(
-          "workgroup_size argument must be either a literal or a "
-          "module-scope constant",
-          values[i]->source);
-      return false;
-    }
-
-    if (!value) {
-      TINT_ICE(Resolver, diagnostics_)
-          << "could not resolve constant workgroup_size constant value";
-      continue;
-    }
-    // Validate and set the default value for this dimension.
-    if (is_i32 ? value.Elements()[0].i32 < 1 : value.Elements()[0].u32 < 1) {
-      AddError("workgroup_size argument must be at least 1", values[i]->source);
-      return false;
-    }
-
-    ws[i].value = is_i32 ? static_cast<uint32_t>(value.Elements()[0].i32)
-                         : value.Elements()[0].u32;
-  }
-
-  current_function_->SetWorkgroupSize(std::move(ws));
-  return true;
 }
 
 bool Resolver::Statements(const ast::StatementList& stmts) {
-  sem::Behaviors behaviors{sem::Behavior::kNext};
+    sem::Behaviors behaviors{sem::Behavior::kNext};
 
-  bool reachable = true;
-  for (auto* stmt : stmts) {
-    Mark(stmt);
-    auto* sem = Statement(stmt);
-    if (!sem) {
-      return false;
+    bool reachable = true;
+    for (auto* stmt : stmts) {
+        Mark(stmt);
+        auto* sem = Statement(stmt);
+        if (!sem) {
+            return false;
+        }
+        // s1 s2:(B1∖{Next}) ∪ B2
+        sem->SetIsReachable(reachable);
+        if (reachable) {
+            behaviors = (behaviors - sem::Behavior::kNext) + sem->Behaviors();
+        }
+        reachable = reachable && sem->Behaviors().Contains(sem::Behavior::kNext);
     }
-    // s1 s2:(B1∖{Next}) ∪ B2
-    sem->SetIsReachable(reachable);
-    if (reachable) {
-      behaviors = (behaviors - sem::Behavior::kNext) + sem->Behaviors();
+
+    current_statement_->Behaviors() = behaviors;
+
+    if (!validator_.Statements(stmts)) {
+        return false;
     }
-    reachable = reachable && sem->Behaviors().Contains(sem::Behavior::kNext);
-  }
 
-  current_statement_->Behaviors() = behaviors;
-
-  if (!ValidateStatements(stmts)) {
-    return false;
-  }
-
-  return true;
+    return true;
 }
 
 sem::Statement* Resolver::Statement(const ast::Statement* stmt) {
-  return Switch(
-      stmt,
-      // Compound statements. These create their own sem::CompoundStatement
-      // bindings.
-      [&](const ast::BlockStatement* b) { return BlockStatement(b); },
-      [&](const ast::ForLoopStatement* l) { return ForLoopStatement(l); },
-      [&](const ast::LoopStatement* l) { return LoopStatement(l); },
-      [&](const ast::IfStatement* i) { return IfStatement(i); },
-      [&](const ast::SwitchStatement* s) { return SwitchStatement(s); },
+    return Switch(
+        stmt,
+        // Compound statements. These create their own sem::CompoundStatement
+        // bindings.
+        [&](const ast::BlockStatement* b) { return BlockStatement(b); },
+        [&](const ast::ForLoopStatement* l) { return ForLoopStatement(l); },
+        [&](const ast::LoopStatement* l) { return LoopStatement(l); },
+        [&](const ast::IfStatement* i) { return IfStatement(i); },
+        [&](const ast::SwitchStatement* s) { return SwitchStatement(s); },
 
-      // Non-Compound statements
-      [&](const ast::AssignmentStatement* a) { return AssignmentStatement(a); },
-      [&](const ast::BreakStatement* b) { return BreakStatement(b); },
-      [&](const ast::CallStatement* c) { return CallStatement(c); },
-      [&](const ast::CompoundAssignmentStatement* c) {
-        return CompoundAssignmentStatement(c);
-      },
-      [&](const ast::ContinueStatement* c) { return ContinueStatement(c); },
-      [&](const ast::DiscardStatement* d) { return DiscardStatement(d); },
-      [&](const ast::FallthroughStatement* f) {
-        return FallthroughStatement(f);
-      },
-      [&](const ast::IncrementDecrementStatement* i) {
-        return IncrementDecrementStatement(i);
-      },
-      [&](const ast::ReturnStatement* r) { return ReturnStatement(r); },
-      [&](const ast::VariableDeclStatement* v) {
-        return VariableDeclStatement(v);
-      },
+        // Non-Compound statements
+        [&](const ast::AssignmentStatement* a) { return AssignmentStatement(a); },
+        [&](const ast::BreakStatement* b) { return BreakStatement(b); },
+        [&](const ast::CallStatement* c) { return CallStatement(c); },
+        [&](const ast::CompoundAssignmentStatement* c) { return CompoundAssignmentStatement(c); },
+        [&](const ast::ContinueStatement* c) { return ContinueStatement(c); },
+        [&](const ast::DiscardStatement* d) { return DiscardStatement(d); },
+        [&](const ast::FallthroughStatement* f) { return FallthroughStatement(f); },
+        [&](const ast::IncrementDecrementStatement* i) { return IncrementDecrementStatement(i); },
+        [&](const ast::ReturnStatement* r) { return ReturnStatement(r); },
+        [&](const ast::VariableDeclStatement* v) { return VariableDeclStatement(v); },
 
-      // Error cases
-      [&](const ast::CaseStatement*) {
-        AddError("case statement can only be used inside a switch statement",
-                 stmt->source);
-        return nullptr;
-      },
-      [&](const ast::ElseStatement*) {
-        TINT_ICE(Resolver, diagnostics_)
-            << "Resolver::Statement() encountered an Else statement. Else "
-               "statements are embedded in If statements, so should never be "
-               "encountered as top-level statements";
-        return nullptr;
-      },
-      [&](Default) {
-        AddError(
-            "unknown statement type: " + std::string(stmt->TypeInfo().name),
-            stmt->source);
-        return nullptr;
-      });
+        // Error cases
+        [&](const ast::CaseStatement*) {
+            AddError("case statement can only be used inside a switch statement", stmt->source);
+            return nullptr;
+        },
+        [&](Default) {
+            AddError("unknown statement type: " + std::string(stmt->TypeInfo().name), stmt->source);
+            return nullptr;
+        });
 }
 
 sem::CaseStatement* Resolver::CaseStatement(const ast::CaseStatement* stmt) {
-  auto* sem = builder_->create<sem::CaseStatement>(
-      stmt, current_compound_statement_, current_function_);
-  return StatementScope(stmt, sem, [&] {
-    for (auto* sel : stmt->selectors) {
-      Mark(sel);
-    }
-    Mark(stmt->body);
-    auto* body = BlockStatement(stmt->body);
-    if (!body) {
-      return false;
-    }
-    sem->SetBlock(body);
-    sem->Behaviors() = body->Behaviors();
-    return true;
-  });
+    auto* sem =
+        builder_->create<sem::CaseStatement>(stmt, current_compound_statement_, current_function_);
+    return StatementScope(stmt, sem, [&] {
+        for (auto* sel : stmt->selectors) {
+            if (!Expression(sel)) {
+                return false;
+            }
+        }
+        Mark(stmt->body);
+        auto* body = BlockStatement(stmt->body);
+        if (!body) {
+            return false;
+        }
+        sem->SetBlock(body);
+        sem->Behaviors() = body->Behaviors();
+        return true;
+    });
 }
 
 sem::IfStatement* Resolver::IfStatement(const ast::IfStatement* stmt) {
-  auto* sem = builder_->create<sem::IfStatement>(
-      stmt, current_compound_statement_, current_function_);
-  return StatementScope(stmt, sem, [&] {
-    auto* cond = Expression(stmt->condition);
-    if (!cond) {
-      return false;
-    }
-    sem->SetCondition(cond);
-    sem->Behaviors() = cond->Behaviors();
-    sem->Behaviors().Remove(sem::Behavior::kNext);
+    auto* sem =
+        builder_->create<sem::IfStatement>(stmt, current_compound_statement_, current_function_);
+    return StatementScope(stmt, sem, [&] {
+        auto* cond = Expression(stmt->condition);
+        if (!cond) {
+            return false;
+        }
+        sem->SetCondition(cond);
+        sem->Behaviors() = cond->Behaviors();
+        sem->Behaviors().Remove(sem::Behavior::kNext);
 
-    Mark(stmt->body);
-    auto* body = builder_->create<sem::BlockStatement>(
-        stmt->body, current_compound_statement_, current_function_);
-    if (!StatementScope(stmt->body, body,
-                        [&] { return Statements(stmt->body->statements); })) {
-      return false;
-    }
-    sem->Behaviors().Add(body->Behaviors());
+        Mark(stmt->body);
+        auto* body = builder_->create<sem::BlockStatement>(stmt->body, current_compound_statement_,
+                                                           current_function_);
+        if (!StatementScope(stmt->body, body, [&] { return Statements(stmt->body->statements); })) {
+            return false;
+        }
+        sem->Behaviors().Add(body->Behaviors());
 
-    for (auto* else_stmt : stmt->else_statements) {
-      Mark(else_stmt);
-      auto* else_sem = ElseStatement(else_stmt);
-      if (!else_sem) {
-        return false;
-      }
-      sem->Behaviors().Add(else_sem->Behaviors());
-    }
+        if (stmt->else_statement) {
+            Mark(stmt->else_statement);
+            auto* else_sem = Statement(stmt->else_statement);
+            if (!else_sem) {
+                return false;
+            }
+            sem->Behaviors().Add(else_sem->Behaviors());
+        } else {
+            // https://www.w3.org/TR/WGSL/#behaviors-rules
+            // if statements without an else branch are treated as if they had an
+            // empty else branch (which adds Next to their behavior)
+            sem->Behaviors().Add(sem::Behavior::kNext);
+        }
 
-    if (stmt->else_statements.empty() ||
-        stmt->else_statements.back()->condition != nullptr) {
-      // https://www.w3.org/TR/WGSL/#behaviors-rules
-      // if statements without an else branch are treated as if they had an
-      // empty else branch (which adds Next to their behavior)
-      sem->Behaviors().Add(sem::Behavior::kNext);
-    }
-
-    return ValidateIfStatement(sem);
-  });
-}
-
-sem::ElseStatement* Resolver::ElseStatement(const ast::ElseStatement* stmt) {
-  auto* sem = builder_->create<sem::ElseStatement>(
-      stmt, current_compound_statement_->As<sem::IfStatement>(),
-      current_function_);
-  return StatementScope(stmt, sem, [&] {
-    if (auto* cond_expr = stmt->condition) {
-      auto* cond = Expression(cond_expr);
-      if (!cond) {
-        return false;
-      }
-      sem->SetCondition(cond);
-      // https://www.w3.org/TR/WGSL/#behaviors-rules
-      // if statements with else if branches are treated as if they were nested
-      // simple if/else statements
-      sem->Behaviors() = cond->Behaviors();
-    }
-    sem->Behaviors().Remove(sem::Behavior::kNext);
-
-    Mark(stmt->body);
-    auto* body = builder_->create<sem::BlockStatement>(
-        stmt->body, current_compound_statement_, current_function_);
-    if (!StatementScope(stmt->body, body,
-                        [&] { return Statements(stmt->body->statements); })) {
-      return false;
-    }
-    sem->Behaviors().Add(body->Behaviors());
-
-    return ValidateElseStatement(sem);
-  });
+        return validator_.IfStatement(sem);
+    });
 }
 
 sem::BlockStatement* Resolver::BlockStatement(const ast::BlockStatement* stmt) {
-  auto* sem = builder_->create<sem::BlockStatement>(
-      stmt->As<ast::BlockStatement>(), current_compound_statement_,
-      current_function_);
-  return StatementScope(stmt, sem,
-                        [&] { return Statements(stmt->statements); });
+    auto* sem = builder_->create<sem::BlockStatement>(
+        stmt->As<ast::BlockStatement>(), current_compound_statement_, current_function_);
+    return StatementScope(stmt, sem, [&] { return Statements(stmt->statements); });
 }
 
 sem::LoopStatement* Resolver::LoopStatement(const ast::LoopStatement* stmt) {
-  auto* sem = builder_->create<sem::LoopStatement>(
-      stmt, current_compound_statement_, current_function_);
-  return StatementScope(stmt, sem, [&] {
-    Mark(stmt->body);
+    auto* sem =
+        builder_->create<sem::LoopStatement>(stmt, current_compound_statement_, current_function_);
+    return StatementScope(stmt, sem, [&] {
+        Mark(stmt->body);
 
-    auto* body = builder_->create<sem::LoopBlockStatement>(
-        stmt->body, current_compound_statement_, current_function_);
-    return StatementScope(stmt->body, body, [&] {
-      if (!Statements(stmt->body->statements)) {
-        return false;
-      }
-      auto& behaviors = sem->Behaviors();
-      behaviors = body->Behaviors();
+        auto* body = builder_->create<sem::LoopBlockStatement>(
+            stmt->body, current_compound_statement_, current_function_);
+        return StatementScope(stmt->body, body, [&] {
+            if (!Statements(stmt->body->statements)) {
+                return false;
+            }
+            auto& behaviors = sem->Behaviors();
+            behaviors = body->Behaviors();
 
-      if (stmt->continuing) {
-        Mark(stmt->continuing);
-        if (!stmt->continuing->Empty()) {
-          auto* continuing = StatementScope(
-              stmt->continuing,
-              builder_->create<sem::LoopContinuingBlockStatement>(
-                  stmt->continuing, current_compound_statement_,
-                  current_function_),
-              [&] { return Statements(stmt->continuing->statements); });
-          if (!continuing) {
-            return false;
-          }
-          behaviors.Add(continuing->Behaviors());
-        }
-      }
+            if (stmt->continuing) {
+                Mark(stmt->continuing);
+                if (!stmt->continuing->Empty()) {
+                    auto* continuing = StatementScope(
+                        stmt->continuing,
+                        builder_->create<sem::LoopContinuingBlockStatement>(
+                            stmt->continuing, current_compound_statement_, current_function_),
+                        [&] { return Statements(stmt->continuing->statements); });
+                    if (!continuing) {
+                        return false;
+                    }
+                    behaviors.Add(continuing->Behaviors());
+                }
+            }
 
-      if (behaviors.Contains(sem::Behavior::kBreak)) {  // Does the loop exit?
-        behaviors.Add(sem::Behavior::kNext);
-      } else {
-        behaviors.Remove(sem::Behavior::kNext);
-      }
-      behaviors.Remove(sem::Behavior::kBreak, sem::Behavior::kContinue);
+            if (behaviors.Contains(sem::Behavior::kBreak)) {  // Does the loop exit?
+                behaviors.Add(sem::Behavior::kNext);
+            } else {
+                behaviors.Remove(sem::Behavior::kNext);
+            }
+            behaviors.Remove(sem::Behavior::kBreak, sem::Behavior::kContinue);
 
-      return ValidateLoopStatement(sem);
+            return validator_.LoopStatement(sem);
+        });
     });
-  });
 }
 
-sem::ForLoopStatement* Resolver::ForLoopStatement(
-    const ast::ForLoopStatement* stmt) {
-  auto* sem = builder_->create<sem::ForLoopStatement>(
-      stmt, current_compound_statement_, current_function_);
-  return StatementScope(stmt, sem, [&] {
-    auto& behaviors = sem->Behaviors();
-    if (auto* initializer = stmt->initializer) {
-      Mark(initializer);
-      auto* init = Statement(initializer);
-      if (!init) {
-        return false;
-      }
-      behaviors.Add(init->Behaviors());
-    }
+sem::ForLoopStatement* Resolver::ForLoopStatement(const ast::ForLoopStatement* stmt) {
+    auto* sem = builder_->create<sem::ForLoopStatement>(stmt, current_compound_statement_,
+                                                        current_function_);
+    return StatementScope(stmt, sem, [&] {
+        auto& behaviors = sem->Behaviors();
+        if (auto* initializer = stmt->initializer) {
+            Mark(initializer);
+            auto* init = Statement(initializer);
+            if (!init) {
+                return false;
+            }
+            behaviors.Add(init->Behaviors());
+        }
 
-    if (auto* cond_expr = stmt->condition) {
-      auto* cond = Expression(cond_expr);
-      if (!cond) {
-        return false;
-      }
-      sem->SetCondition(cond);
-      behaviors.Add(cond->Behaviors());
-    }
+        if (auto* cond_expr = stmt->condition) {
+            auto* cond = Expression(cond_expr);
+            if (!cond) {
+                return false;
+            }
+            sem->SetCondition(cond);
+            behaviors.Add(cond->Behaviors());
+        }
 
-    if (auto* continuing = stmt->continuing) {
-      Mark(continuing);
-      auto* cont = Statement(continuing);
-      if (!cont) {
-        return false;
-      }
-      behaviors.Add(cont->Behaviors());
-    }
+        if (auto* continuing = stmt->continuing) {
+            Mark(continuing);
+            auto* cont = Statement(continuing);
+            if (!cont) {
+                return false;
+            }
+            behaviors.Add(cont->Behaviors());
+        }
 
-    Mark(stmt->body);
+        Mark(stmt->body);
 
-    auto* body = builder_->create<sem::LoopBlockStatement>(
-        stmt->body, current_compound_statement_, current_function_);
-    if (!StatementScope(stmt->body, body,
-                        [&] { return Statements(stmt->body->statements); })) {
-      return false;
-    }
+        auto* body = builder_->create<sem::LoopBlockStatement>(
+            stmt->body, current_compound_statement_, current_function_);
+        if (!StatementScope(stmt->body, body, [&] { return Statements(stmt->body->statements); })) {
+            return false;
+        }
 
-    behaviors.Add(body->Behaviors());
-    if (stmt->condition ||
-        behaviors.Contains(sem::Behavior::kBreak)) {  // Does the loop exit?
-      behaviors.Add(sem::Behavior::kNext);
-    } else {
-      behaviors.Remove(sem::Behavior::kNext);
-    }
-    behaviors.Remove(sem::Behavior::kBreak, sem::Behavior::kContinue);
+        behaviors.Add(body->Behaviors());
+        if (stmt->condition || behaviors.Contains(sem::Behavior::kBreak)) {  // Does the loop exit?
+            behaviors.Add(sem::Behavior::kNext);
+        } else {
+            behaviors.Remove(sem::Behavior::kNext);
+        }
+        behaviors.Remove(sem::Behavior::kBreak, sem::Behavior::kContinue);
 
-    return ValidateForLoopStatement(sem);
-  });
+        return validator_.ForLoopStatement(sem);
+    });
 }
 
 sem::Expression* Resolver::Expression(const ast::Expression* root) {
-  std::vector<const ast::Expression*> sorted;
-  bool mark_failed = false;
-  if (!ast::TraverseExpressions<ast::TraverseOrder::RightToLeft>(
-          root, diagnostics_, [&](const ast::Expression* expr) {
-            if (!Mark(expr)) {
-              mark_failed = true;
-              return ast::TraverseAction::Stop;
-            }
-            sorted.emplace_back(expr);
-            return ast::TraverseAction::Descend;
-          })) {
-    return nullptr;
-  }
-
-  if (mark_failed) {
-    return nullptr;
-  }
-
-  for (auto* expr : utils::Reverse(sorted)) {
-    auto* sem_expr = Switch(
-        expr,
-        [&](const ast::IndexAccessorExpression* array) -> sem::Expression* {
-          return IndexAccessor(array);
-        },
-        [&](const ast::BinaryExpression* bin_op) -> sem::Expression* {
-          return Binary(bin_op);
-        },
-        [&](const ast::BitcastExpression* bitcast) -> sem::Expression* {
-          return Bitcast(bitcast);
-        },
-        [&](const ast::CallExpression* call) -> sem::Expression* {
-          return Call(call);
-        },
-        [&](const ast::IdentifierExpression* ident) -> sem::Expression* {
-          return Identifier(ident);
-        },
-        [&](const ast::LiteralExpression* literal) -> sem::Expression* {
-          return Literal(literal);
-        },
-        [&](const ast::MemberAccessorExpression* member) -> sem::Expression* {
-          return MemberAccessor(member);
-        },
-        [&](const ast::UnaryOpExpression* unary) -> sem::Expression* {
-          return UnaryOp(unary);
-        },
-        [&](const ast::PhonyExpression*) -> sem::Expression* {
-          return builder_->create<sem::Expression>(
-              expr, builder_->create<sem::Void>(), current_statement_,
-              sem::Constant{}, /* has_side_effects */ false);
-        },
-        [&](Default) {
-          TINT_ICE(Resolver, diagnostics_)
-              << "unhandled expression type: " << expr->TypeInfo().name;
-          return nullptr;
-        });
-    if (!sem_expr) {
-      return nullptr;
+    std::vector<const ast::Expression*> sorted;
+    bool mark_failed = false;
+    if (!ast::TraverseExpressions<ast::TraverseOrder::RightToLeft>(
+            root, diagnostics_, [&](const ast::Expression* expr) {
+                if (!Mark(expr)) {
+                    mark_failed = true;
+                    return ast::TraverseAction::Stop;
+                }
+                sorted.emplace_back(expr);
+                return ast::TraverseAction::Descend;
+            })) {
+        return nullptr;
     }
 
-    builder_->Sem().Add(expr, sem_expr);
-    if (expr == root) {
-      return sem_expr;
+    if (mark_failed) {
+        return nullptr;
     }
-  }
 
-  TINT_ICE(Resolver, diagnostics_) << "Expression() did not find root node";
-  return nullptr;
+    for (auto* expr : utils::Reverse(sorted)) {
+        auto* sem_expr = Switch(
+            expr,
+            [&](const ast::IndexAccessorExpression* array) -> sem::Expression* {
+                return IndexAccessor(array);
+            },
+            [&](const ast::BinaryExpression* bin_op) -> sem::Expression* { return Binary(bin_op); },
+            [&](const ast::BitcastExpression* bitcast) -> sem::Expression* {
+                return Bitcast(bitcast);
+            },
+            [&](const ast::CallExpression* call) -> sem::Expression* { return Call(call); },
+            [&](const ast::IdentifierExpression* ident) -> sem::Expression* {
+                return Identifier(ident);
+            },
+            [&](const ast::LiteralExpression* literal) -> sem::Expression* {
+                return Literal(literal);
+            },
+            [&](const ast::MemberAccessorExpression* member) -> sem::Expression* {
+                return MemberAccessor(member);
+            },
+            [&](const ast::UnaryOpExpression* unary) -> sem::Expression* { return UnaryOp(unary); },
+            [&](const ast::PhonyExpression*) -> sem::Expression* {
+                return builder_->create<sem::Expression>(expr, builder_->create<sem::Void>(),
+                                                         current_statement_, sem::Constant{},
+                                                         /* has_side_effects */ false);
+            },
+            [&](Default) {
+                TINT_ICE(Resolver, diagnostics_)
+                    << "unhandled expression type: " << expr->TypeInfo().name;
+                return nullptr;
+            });
+        if (!sem_expr) {
+            return nullptr;
+        }
+
+        builder_->Sem().Add(expr, sem_expr);
+        if (expr == root) {
+            return sem_expr;
+        }
+    }
+
+    TINT_ICE(Resolver, diagnostics_) << "Expression() did not find root node";
+    return nullptr;
 }
 
-sem::Expression* Resolver::IndexAccessor(
-    const ast::IndexAccessorExpression* expr) {
-  auto* idx = sem_.Get(expr->index);
-  auto* obj = sem_.Get(expr->object);
-  auto* obj_raw_ty = obj->Type();
-  auto* obj_ty = obj_raw_ty->UnwrapRef();
-  auto* ty = Switch(
-      obj_ty,  //
-      [&](const sem::Array* arr) { return arr->ElemType(); },
-      [&](const sem::Vector* vec) { return vec->type(); },
-      [&](const sem::Matrix* mat) {
-        return builder_->create<sem::Vector>(mat->type(), mat->rows());
-      },
-      [&](Default) {
-        AddError("cannot index type '" + sem_.TypeNameOf(obj_ty) + "'",
-                 expr->source);
+sem::Expression* Resolver::IndexAccessor(const ast::IndexAccessorExpression* expr) {
+    auto* idx = sem_.Get(expr->index);
+    auto* obj = sem_.Get(expr->object);
+    auto* obj_raw_ty = obj->Type();
+    auto* obj_ty = obj_raw_ty->UnwrapRef();
+    auto* ty = Switch(
+        obj_ty,  //
+        [&](const sem::Array* arr) { return arr->ElemType(); },
+        [&](const sem::Vector* vec) { return vec->type(); },
+        [&](const sem::Matrix* mat) {
+            return builder_->create<sem::Vector>(mat->type(), mat->rows());
+        },
+        [&](Default) {
+            AddError("cannot index type '" + sem_.TypeNameOf(obj_ty) + "'", expr->source);
+            return nullptr;
+        });
+    if (ty == nullptr) {
         return nullptr;
-      });
-  if (ty == nullptr) {
-    return nullptr;
-  }
+    }
 
-  auto* idx_ty = idx->Type()->UnwrapRef();
-  if (!idx_ty->IsAnyOf<sem::I32, sem::U32>()) {
-    AddError("index must be of type 'i32' or 'u32', found: '" +
-                 sem_.TypeNameOf(idx_ty) + "'",
-             idx->Declaration()->source);
-    return nullptr;
-  }
+    auto* idx_ty = idx->Type()->UnwrapRef();
+    if (!idx_ty->IsAnyOf<sem::I32, sem::U32>()) {
+        AddError("index must be of type 'i32' or 'u32', found: '" + sem_.TypeNameOf(idx_ty) + "'",
+                 idx->Declaration()->source);
+        return nullptr;
+    }
 
-  // If we're extracting from a reference, we return a reference.
-  if (auto* ref = obj_raw_ty->As<sem::Reference>()) {
-    ty = builder_->create<sem::Reference>(ty, ref->StorageClass(),
-                                          ref->Access());
-  }
+    // If we're extracting from a reference, we return a reference.
+    if (auto* ref = obj_raw_ty->As<sem::Reference>()) {
+        ty = builder_->create<sem::Reference>(ty, ref->StorageClass(), ref->Access());
+    }
 
-  auto val = EvaluateConstantValue(expr, ty);
-  bool has_side_effects = idx->HasSideEffects() || obj->HasSideEffects();
-  auto* sem = builder_->create<sem::Expression>(expr, ty, current_statement_,
-                                                val, has_side_effects);
-  sem->Behaviors() = idx->Behaviors() + obj->Behaviors();
-  return sem;
+    auto val = EvaluateConstantValue(expr, ty);
+    bool has_side_effects = idx->HasSideEffects() || obj->HasSideEffects();
+    auto* sem = builder_->create<sem::Expression>(expr, ty, current_statement_, val,
+                                                  has_side_effects, obj->SourceVariable());
+    sem->Behaviors() = idx->Behaviors() + obj->Behaviors();
+    return sem;
 }
 
 sem::Expression* Resolver::Bitcast(const ast::BitcastExpression* expr) {
-  auto* inner = sem_.Get(expr->expr);
-  auto* ty = Type(expr->type);
-  if (!ty) {
-    return nullptr;
-  }
+    auto* inner = sem_.Get(expr->expr);
+    auto* ty = Type(expr->type);
+    if (!ty) {
+        return nullptr;
+    }
 
-  auto val = EvaluateConstantValue(expr, ty);
-  auto* sem = builder_->create<sem::Expression>(expr, ty, current_statement_,
-                                                val, inner->HasSideEffects());
+    auto val = EvaluateConstantValue(expr, ty);
+    auto* sem = builder_->create<sem::Expression>(expr, ty, current_statement_, val,
+                                                  inner->HasSideEffects());
 
-  sem->Behaviors() = inner->Behaviors();
+    sem->Behaviors() = inner->Behaviors();
 
-  if (!ValidateBitcast(expr, ty)) {
-    return nullptr;
-  }
+    if (!validator_.Bitcast(expr, ty)) {
+        return nullptr;
+    }
 
-  return sem;
+    return sem;
 }
 
 sem::Call* Resolver::Call(const ast::CallExpression* expr) {
-  std::vector<const sem::Expression*> args(expr->args.size());
-  std::vector<const sem::Type*> arg_tys(args.size());
-  sem::Behaviors arg_behaviors;
+    std::vector<const sem::Expression*> args(expr->args.size());
+    std::vector<const sem::Type*> arg_tys(args.size());
+    sem::Behaviors arg_behaviors;
 
-  // The element type of all the arguments. Nullptr if argument types are
-  // different.
-  const sem::Type* arg_el_ty = nullptr;
+    // The element type of all the arguments. Nullptr if argument types are
+    // different.
+    const sem::Type* arg_el_ty = nullptr;
 
-  for (size_t i = 0; i < expr->args.size(); i++) {
-    auto* arg = sem_.Get(expr->args[i]);
-    if (!arg) {
-      return nullptr;
+    for (size_t i = 0; i < expr->args.size(); i++) {
+        auto* arg = sem_.Get(expr->args[i]);
+        if (!arg) {
+            return nullptr;
+        }
+        args[i] = arg;
+        arg_tys[i] = args[i]->Type();
+        arg_behaviors.Add(arg->Behaviors());
+
+        // Determine the common argument element type
+        auto* el_ty = arg_tys[i]->UnwrapRef();
+        if (auto* vec = el_ty->As<sem::Vector>()) {
+            el_ty = vec->type();
+        } else if (auto* mat = el_ty->As<sem::Matrix>()) {
+            el_ty = mat->type();
+        }
+        if (i == 0) {
+            arg_el_ty = el_ty;
+        } else if (arg_el_ty != el_ty) {
+            arg_el_ty = nullptr;
+        }
     }
-    args[i] = arg;
-    arg_tys[i] = args[i]->Type();
-    arg_behaviors.Add(arg->Behaviors());
 
-    // Determine the common argument element type
-    auto* el_ty = arg_tys[i]->UnwrapRef();
-    if (auto* vec = el_ty->As<sem::Vector>()) {
-      el_ty = vec->type();
-    } else if (auto* mat = el_ty->As<sem::Matrix>()) {
-      el_ty = mat->type();
-    }
-    if (i == 0) {
-      arg_el_ty = el_ty;
-    } else if (arg_el_ty != el_ty) {
-      arg_el_ty = nullptr;
-    }
-  }
+    arg_behaviors.Remove(sem::Behavior::kNext);
 
-  arg_behaviors.Remove(sem::Behavior::kNext);
-
-  auto type_ctor_or_conv = [&](const sem::Type* ty) -> sem::Call* {
-    // The call has resolved to a type constructor or cast.
-    if (args.size() == 1) {
-      auto* target = ty;
-      auto* source = args[0]->Type()->UnwrapRef();
-      if ((source != target) &&  //
-          ((source->is_scalar() && target->is_scalar()) ||
-           (source->Is<sem::Vector>() && target->Is<sem::Vector>()) ||
-           (source->Is<sem::Matrix>() && target->Is<sem::Matrix>()))) {
-        // Note: Matrix types currently cannot be converted (the element type
-        // must only be f32). We implement this for the day we support other
-        // matrix element types.
-        return TypeConversion(expr, ty, args[0], arg_tys[0]);
-      }
-    }
-    return TypeConstructor(expr, ty, std::move(args), std::move(arg_tys));
-  };
-
-  // Resolve the target of the CallExpression to determine whether this is a
-  // function call, cast or type constructor expression.
-  if (expr->target.type) {
-    const sem::Type* ty = nullptr;
-
-    auto err_cannot_infer_el_ty = [&](std::string name) {
-      AddError(
-          "cannot infer " + name +
-              " element type, as constructor arguments have different types",
-          expr->source);
-      for (size_t i = 0; i < args.size(); i++) {
-        auto* arg = args[i];
-        AddNote("argument " + std::to_string(i) + " has type " +
-                    arg->Type()->FriendlyName(builder_->Symbols()),
-                arg->Declaration()->source);
-      }
+    auto type_ctor_or_conv = [&](const sem::Type* ty) -> sem::Call* {
+        // The call has resolved to a type constructor or cast.
+        if (args.size() == 1) {
+            auto* target = ty;
+            auto* source = args[0]->Type()->UnwrapRef();
+            if ((source != target) &&  //
+                ((source->is_scalar() && target->is_scalar()) ||
+                 (source->Is<sem::Vector>() && target->Is<sem::Vector>()) ||
+                 (source->Is<sem::Matrix>() && target->Is<sem::Matrix>()))) {
+                // Note: Matrix types currently cannot be converted (the element type
+                // must only be f32). We implement this for the day we support other
+                // matrix element types.
+                return TypeConversion(expr, ty, args[0], arg_tys[0]);
+            }
+        }
+        return TypeConstructor(expr, ty, std::move(args), std::move(arg_tys));
     };
 
-    if (!expr->args.empty()) {
-      // vecN() without explicit element type?
-      // Try to infer element type from args
-      if (auto* vec = expr->target.type->As<ast::Vector>()) {
-        if (!vec->type) {
-          if (!arg_el_ty) {
-            err_cannot_infer_el_ty("vector");
-            return nullptr;
-          }
+    // Resolve the target of the CallExpression to determine whether this is a
+    // function call, cast or type constructor expression.
+    if (expr->target.type) {
+        const sem::Type* ty = nullptr;
 
-          Mark(vec);
-          auto* v = builder_->create<sem::Vector>(
-              arg_el_ty, static_cast<uint32_t>(vec->width));
-          if (!ValidateVector(v, vec->source)) {
-            return nullptr;
-          }
-          builder_->Sem().Add(vec, v);
-          ty = v;
+        auto err_cannot_infer_el_ty = [&](std::string name) {
+            AddError("cannot infer " + name +
+                         " element type, as constructor arguments have different types",
+                     expr->source);
+            for (size_t i = 0; i < args.size(); i++) {
+                auto* arg = args[i];
+                AddNote("argument " + std::to_string(i) + " has type " +
+                            arg->Type()->FriendlyName(builder_->Symbols()),
+                        arg->Declaration()->source);
+            }
+        };
+
+        if (!expr->args.empty()) {
+            // vecN() without explicit element type?
+            // Try to infer element type from args
+            if (auto* vec = expr->target.type->As<ast::Vector>()) {
+                if (!vec->type) {
+                    if (!arg_el_ty) {
+                        err_cannot_infer_el_ty("vector");
+                        return nullptr;
+                    }
+
+                    Mark(vec);
+                    auto* v =
+                        builder_->create<sem::Vector>(arg_el_ty, static_cast<uint32_t>(vec->width));
+                    if (!validator_.Vector(v, vec->source)) {
+                        return nullptr;
+                    }
+                    builder_->Sem().Add(vec, v);
+                    ty = v;
+                }
+            }
+
+            // matNxM() without explicit element type?
+            // Try to infer element type from args
+            if (auto* mat = expr->target.type->As<ast::Matrix>()) {
+                if (!mat->type) {
+                    if (!arg_el_ty) {
+                        err_cannot_infer_el_ty("matrix");
+                        return nullptr;
+                    }
+
+                    Mark(mat);
+                    auto* column_type = builder_->create<sem::Vector>(arg_el_ty, mat->rows);
+                    auto* m = builder_->create<sem::Matrix>(column_type, mat->columns);
+                    if (!validator_.Matrix(m, mat->source)) {
+                        return nullptr;
+                    }
+                    builder_->Sem().Add(mat, m);
+                    ty = m;
+                }
+            }
         }
-      }
 
-      // matNxM() without explicit element type?
-      // Try to infer element type from args
-      if (auto* mat = expr->target.type->As<ast::Matrix>()) {
-        if (!mat->type) {
-          if (!arg_el_ty) {
-            err_cannot_infer_el_ty("matrix");
-            return nullptr;
-          }
-
-          Mark(mat);
-          auto* column_type =
-              builder_->create<sem::Vector>(arg_el_ty, mat->rows);
-          auto* m = builder_->create<sem::Matrix>(column_type, mat->columns);
-          if (!ValidateMatrix(m, mat->source)) {
-            return nullptr;
-          }
-          builder_->Sem().Add(mat, m);
-          ty = m;
+        if (ty == nullptr) {
+            ty = Type(expr->target.type);
+            if (!ty) {
+                return nullptr;
+            }
         }
-      }
+
+        return type_ctor_or_conv(ty);
     }
 
-    if (ty == nullptr) {
-      ty = Type(expr->target.type);
-      if (!ty) {
-        return nullptr;
-      }
-    }
+    auto* ident = expr->target.name;
+    Mark(ident);
 
-    return type_ctor_or_conv(ty);
-  }
+    auto* resolved = sem_.ResolvedSymbol(ident);
+    return Switch(
+        resolved,  //
+        [&](sem::Type* type) { return type_ctor_or_conv(type); },
+        [&](sem::Function* func) {
+            return FunctionCall(expr, func, std::move(args), arg_behaviors);
+        },
+        [&](sem::Variable* var) {
+            auto name = builder_->Symbols().NameFor(var->Declaration()->symbol);
+            AddError("cannot call variable '" + name + "'", ident->source);
+            AddNote("'" + name + "' declared here", var->Declaration()->source);
+            return nullptr;
+        },
+        [&](Default) -> sem::Call* {
+            auto name = builder_->Symbols().NameFor(ident->symbol);
+            auto builtin_type = sem::ParseBuiltinType(name);
+            if (builtin_type != sem::BuiltinType::kNone) {
+                return BuiltinCall(expr, builtin_type, std::move(args), std::move(arg_tys));
+            }
 
-  auto* ident = expr->target.name;
-  Mark(ident);
-
-  auto* resolved = ResolvedSymbol(ident);
-  return Switch(
-      resolved,  //
-      [&](sem::Type* type) { return type_ctor_or_conv(type); },
-      [&](sem::Function* func) {
-        return FunctionCall(expr, func, std::move(args), arg_behaviors);
-      },
-      [&](sem::Variable* var) {
-        auto name = builder_->Symbols().NameFor(var->Declaration()->symbol);
-        AddError("cannot call variable '" + name + "'", ident->source);
-        AddNote("'" + name + "' declared here", var->Declaration()->source);
-        return nullptr;
-      },
-      [&](Default) -> sem::Call* {
-        auto name = builder_->Symbols().NameFor(ident->symbol);
-        auto builtin_type = sem::ParseBuiltinType(name);
-        if (builtin_type != sem::BuiltinType::kNone) {
-          return BuiltinCall(expr, builtin_type, std::move(args),
-                             std::move(arg_tys));
-        }
-
-        TINT_ICE(Resolver, diagnostics_)
-            << expr->source << " unresolved CallExpression target:\n"
-            << "resolved: " << (resolved ? resolved->TypeInfo().name : "<null>")
-            << "\n"
-            << "name: " << builder_->Symbols().NameFor(ident->symbol);
-        return nullptr;
-      });
+            TINT_ICE(Resolver, diagnostics_)
+                << expr->source << " unresolved CallExpression target:\n"
+                << "resolved: " << (resolved ? resolved->TypeInfo().name : "<null>") << "\n"
+                << "name: " << builder_->Symbols().NameFor(ident->symbol);
+            return nullptr;
+        });
 }
 
 sem::Call* Resolver::BuiltinCall(const ast::CallExpression* expr,
                                  sem::BuiltinType builtin_type,
                                  const std::vector<const sem::Expression*> args,
                                  const std::vector<const sem::Type*> arg_tys) {
-  auto* builtin =
-      builtin_table_->Lookup(builtin_type, std::move(arg_tys), expr->source);
-  if (!builtin) {
-    return nullptr;
-  }
-
-  if (builtin->IsDeprecated()) {
-    AddWarning("use of deprecated builtin", expr->source);
-  }
-
-  bool has_side_effects = builtin->HasSideEffects() ||
-                          std::any_of(args.begin(), args.end(), [](auto* e) {
-                            return e->HasSideEffects();
-                          });
-  auto* call = builder_->create<sem::Call>(expr, builtin, std::move(args),
-                                           current_statement_, sem::Constant{},
-                                           has_side_effects);
-
-  current_function_->AddDirectlyCalledBuiltin(builtin);
-
-  if (IsTextureBuiltin(builtin_type)) {
-    if (!ValidateTextureBuiltinFunction(call)) {
-      return nullptr;
-    }
-    // Collect a texture/sampler pair for this builtin.
-    const auto& signature = builtin->Signature();
-    int texture_index = signature.IndexOf(sem::ParameterUsage::kTexture);
-    if (texture_index == -1) {
-      TINT_ICE(Resolver, diagnostics_)
-          << "texture builtin without texture parameter";
+    auto* builtin = builtin_table_->Lookup(builtin_type, std::move(arg_tys), expr->source);
+    if (!builtin) {
+        return nullptr;
     }
 
-    auto* texture = args[texture_index]->As<sem::VariableUser>()->Variable();
-    if (!texture->Type()->UnwrapRef()->Is<sem::StorageTexture>()) {
-      int sampler_index = signature.IndexOf(sem::ParameterUsage::kSampler);
-      const sem::Variable* sampler =
-          sampler_index != -1
-              ? args[sampler_index]->As<sem::VariableUser>()->Variable()
-              : nullptr;
-      current_function_->AddTextureSamplerPair(texture, sampler);
+    if (builtin->IsDeprecated()) {
+        AddWarning("use of deprecated builtin", expr->source);
     }
-  }
 
-  if (!ValidateBuiltinCall(call)) {
-    return nullptr;
-  }
+    bool has_side_effects =
+        builtin->HasSideEffects() ||
+        std::any_of(args.begin(), args.end(), [](auto* e) { return e->HasSideEffects(); });
+    auto* call = builder_->create<sem::Call>(expr, builtin, std::move(args), current_statement_,
+                                             sem::Constant{}, has_side_effects);
 
-  current_function_->AddDirectCall(call);
+    current_function_->AddDirectlyCalledBuiltin(builtin);
 
-  return call;
+    if (IsTextureBuiltin(builtin_type)) {
+        if (!validator_.TextureBuiltinFunction(call)) {
+            return nullptr;
+        }
+        // Collect a texture/sampler pair for this builtin.
+        const auto& signature = builtin->Signature();
+        int texture_index = signature.IndexOf(sem::ParameterUsage::kTexture);
+        if (texture_index == -1) {
+            TINT_ICE(Resolver, diagnostics_) << "texture builtin without texture parameter";
+        }
+
+        auto* texture = args[texture_index]->As<sem::VariableUser>()->Variable();
+        if (!texture->Type()->UnwrapRef()->Is<sem::StorageTexture>()) {
+            int sampler_index = signature.IndexOf(sem::ParameterUsage::kSampler);
+            const sem::Variable* sampler =
+                sampler_index != -1 ? args[sampler_index]->As<sem::VariableUser>()->Variable()
+                                    : nullptr;
+            current_function_->AddTextureSamplerPair(texture, sampler);
+        }
+    }
+
+    if (!validator_.BuiltinCall(call)) {
+        return nullptr;
+    }
+
+    current_function_->AddDirectCall(call);
+
+    return call;
 }
 
-sem::Call* Resolver::FunctionCall(
-    const ast::CallExpression* expr,
-    sem::Function* target,
-    const std::vector<const sem::Expression*> args,
-    sem::Behaviors arg_behaviors) {
-  auto sym = expr->target.name->symbol;
-  auto name = builder_->Symbols().NameFor(sym);
+sem::Call* Resolver::FunctionCall(const ast::CallExpression* expr,
+                                  sem::Function* target,
+                                  const std::vector<const sem::Expression*> args,
+                                  sem::Behaviors arg_behaviors) {
+    auto sym = expr->target.name->symbol;
+    auto name = builder_->Symbols().NameFor(sym);
 
-  // TODO(crbug.com/tint/1420): For now, assume all function calls have side
-  // effects.
-  bool has_side_effects = true;
-  auto* call = builder_->create<sem::Call>(expr, target, std::move(args),
-                                           current_statement_, sem::Constant{},
-                                           has_side_effects);
+    // TODO(crbug.com/tint/1420): For now, assume all function calls have side
+    // effects.
+    bool has_side_effects = true;
+    auto* call = builder_->create<sem::Call>(expr, target, std::move(args), current_statement_,
+                                             sem::Constant{}, has_side_effects);
 
-  if (current_function_) {
-    // Note: Requires called functions to be resolved first.
-    // This is currently guaranteed as functions must be declared before
-    // use.
-    current_function_->AddTransitivelyCalledFunction(target);
-    current_function_->AddDirectCall(call);
-    for (auto* transitive_call : target->TransitivelyCalledFunctions()) {
-      current_function_->AddTransitivelyCalledFunction(transitive_call);
-    }
-
-    // We inherit any referenced variables from the callee.
-    for (auto* var : target->TransitivelyReferencedGlobals()) {
-      current_function_->AddTransitivelyReferencedGlobal(var);
-    }
-
-    // Map all texture/sampler pairs from the target function to the
-    // current function. These can only be global or parameter
-    // variables. Resolve any parameter variables to the corresponding
-    // argument passed to the current function. Leave global variables
-    // as-is. Then add the mapped pair to the current function's list of
-    // texture/sampler pairs.
-    for (sem::VariablePair pair : target->TextureSamplerPairs()) {
-      const sem::Variable* texture = pair.first;
-      const sem::Variable* sampler = pair.second;
-      if (auto* param = texture->As<sem::Parameter>()) {
-        texture = args[param->Index()]->As<sem::VariableUser>()->Variable();
-      }
-      if (sampler) {
-        if (auto* param = sampler->As<sem::Parameter>()) {
-          sampler = args[param->Index()]->As<sem::VariableUser>()->Variable();
+    if (current_function_) {
+        // Note: Requires called functions to be resolved first.
+        // This is currently guaranteed as functions must be declared before
+        // use.
+        current_function_->AddTransitivelyCalledFunction(target);
+        current_function_->AddDirectCall(call);
+        for (auto* transitive_call : target->TransitivelyCalledFunctions()) {
+            current_function_->AddTransitivelyCalledFunction(transitive_call);
         }
-      }
-      current_function_->AddTextureSamplerPair(texture, sampler);
+
+        // We inherit any referenced variables from the callee.
+        for (auto* var : target->TransitivelyReferencedGlobals()) {
+            current_function_->AddTransitivelyReferencedGlobal(var);
+        }
+
+        // Map all texture/sampler pairs from the target function to the
+        // current function. These can only be global or parameter
+        // variables. Resolve any parameter variables to the corresponding
+        // argument passed to the current function. Leave global variables
+        // as-is. Then add the mapped pair to the current function's list of
+        // texture/sampler pairs.
+        for (sem::VariablePair pair : target->TextureSamplerPairs()) {
+            const sem::Variable* texture = pair.first;
+            const sem::Variable* sampler = pair.second;
+            if (auto* param = texture->As<sem::Parameter>()) {
+                texture = args[param->Index()]->As<sem::VariableUser>()->Variable();
+            }
+            if (sampler) {
+                if (auto* param = sampler->As<sem::Parameter>()) {
+                    sampler = args[param->Index()]->As<sem::VariableUser>()->Variable();
+                }
+            }
+            current_function_->AddTextureSamplerPair(texture, sampler);
+        }
     }
-  }
 
-  target->AddCallSite(call);
+    target->AddCallSite(call);
 
-  call->Behaviors() = arg_behaviors + target->Behaviors();
+    call->Behaviors() = arg_behaviors + target->Behaviors();
 
-  if (!ValidateFunctionCall(call)) {
-    return nullptr;
-  }
+    if (!validator_.FunctionCall(call, current_statement_)) {
+        return nullptr;
+    }
 
-  return call;
+    return call;
 }
 
 sem::Call* Resolver::TypeConversion(const ast::CallExpression* expr,
                                     const sem::Type* target,
                                     const sem::Expression* arg,
                                     const sem::Type* source) {
-  // It is not valid to have a type-cast call expression inside a call
-  // statement.
-  if (IsCallStatement(expr)) {
-    AddError("type cast evaluated but not used", expr->source);
-    return nullptr;
-  }
+    // It is not valid to have a type-cast call expression inside a call
+    // statement.
+    if (IsCallStatement(expr)) {
+        AddError("type cast evaluated but not used", expr->source);
+        return nullptr;
+    }
 
-  auto* call_target = utils::GetOrCreate(
-      type_conversions_, TypeConversionSig{target, source},
-      [&]() -> sem::TypeConversion* {
-        // Now that the argument types have been determined, make sure that
-        // they obey the conversion rules laid out in
-        // https://gpuweb.github.io/gpuweb/wgsl/#conversion-expr.
-        bool ok = Switch(
-            target,
-            [&](const sem::Vector* vec_type) {
-              return ValidateVectorConstructorOrCast(expr, vec_type);
-            },
-            [&](const sem::Matrix* mat_type) {
-              // Note: Matrix types currently cannot be converted (the element
-              // type must only be f32). We implement this for the day we
-              // support other matrix element types.
-              return ValidateMatrixConstructorOrCast(expr, mat_type);
-            },
-            [&](const sem::Array* arr_type) {
-              return ValidateArrayConstructorOrCast(expr, arr_type);
-            },
-            [&](const sem::Struct* struct_type) {
-              return ValidateStructureConstructorOrCast(expr, struct_type);
-            },
-            [&](Default) {
-              if (target->is_scalar()) {
-                return ValidateScalarConstructorOrCast(expr, target);
-              }
-              AddError("type is not constructible", expr->source);
-              return false;
-            });
-        if (!ok) {
-          return nullptr;
-        }
+    auto* call_target = utils::GetOrCreate(
+        type_conversions_, TypeConversionSig{target, source}, [&]() -> sem::TypeConversion* {
+            // Now that the argument types have been determined, make sure that
+            // they obey the conversion rules laid out in
+            // https://gpuweb.github.io/gpuweb/wgsl/#conversion-expr.
+            bool ok = Switch(
+                target,
+                [&](const sem::Vector* vec_type) {
+                    return validator_.VectorConstructorOrCast(expr, vec_type);
+                },
+                [&](const sem::Matrix* mat_type) {
+                    // Note: Matrix types currently cannot be converted (the element
+                    // type must only be f32). We implement this for the day we
+                    // support other matrix element types.
+                    return validator_.MatrixConstructorOrCast(expr, mat_type);
+                },
+                [&](const sem::Array* arr_type) {
+                    return validator_.ArrayConstructorOrCast(expr, arr_type);
+                },
+                [&](const sem::Struct* struct_type) {
+                    return validator_.StructureConstructorOrCast(expr, struct_type);
+                },
+                [&](Default) {
+                    if (target->is_scalar()) {
+                        return validator_.ScalarConstructorOrCast(expr, target);
+                    }
+                    AddError("type is not constructible", expr->source);
+                    return false;
+                });
+            if (!ok) {
+                return nullptr;
+            }
 
-        auto* param = builder_->create<sem::Parameter>(
-            nullptr,                   // declaration
-            0,                         // index
-            source->UnwrapRef(),       // type
-            ast::StorageClass::kNone,  // storage_class
-            ast::Access::kUndefined);  // access
-        return builder_->create<sem::TypeConversion>(target, param);
-      });
+            auto* param =
+                builder_->create<sem::Parameter>(nullptr,                   // declaration
+                                                 0,                         // index
+                                                 source->UnwrapRef(),       // type
+                                                 ast::StorageClass::kNone,  // storage_class
+                                                 ast::Access::kUndefined);  // access
+            return builder_->create<sem::TypeConversion>(target, param);
+        });
 
-  if (!call_target) {
-    return nullptr;
-  }
+    if (!call_target) {
+        return nullptr;
+    }
 
-  auto val = EvaluateConstantValue(expr, target);
-  bool has_side_effects = arg->HasSideEffects();
-  return builder_->create<sem::Call>(expr, call_target,
-                                     std::vector<const sem::Expression*>{arg},
-                                     current_statement_, val, has_side_effects);
+    auto val = EvaluateConstantValue(expr, target);
+    bool has_side_effects = arg->HasSideEffects();
+    return builder_->create<sem::Call>(expr, call_target, std::vector<const sem::Expression*>{arg},
+                                       current_statement_, val, has_side_effects);
 }
 
-sem::Call* Resolver::TypeConstructor(
-    const ast::CallExpression* expr,
-    const sem::Type* ty,
-    const std::vector<const sem::Expression*> args,
-    const std::vector<const sem::Type*> arg_tys) {
-  // It is not valid to have a type-constructor call expression as a call
-  // statement.
-  if (IsCallStatement(expr)) {
-    AddError("type constructor evaluated but not used", expr->source);
-    return nullptr;
-  }
+sem::Call* Resolver::TypeConstructor(const ast::CallExpression* expr,
+                                     const sem::Type* ty,
+                                     const std::vector<const sem::Expression*> args,
+                                     const std::vector<const sem::Type*> arg_tys) {
+    // It is not valid to have a type-constructor call expression as a call
+    // statement.
+    if (IsCallStatement(expr)) {
+        AddError("type constructor evaluated but not used", expr->source);
+        return nullptr;
+    }
 
-  auto* call_target = utils::GetOrCreate(
-      type_ctors_, TypeConstructorSig{ty, arg_tys},
-      [&]() -> sem::TypeConstructor* {
-        // Now that the argument types have been determined, make sure that
-        // they obey the constructor type rules laid out in
-        // https://gpuweb.github.io/gpuweb/wgsl/#type-constructor-expr.
-        bool ok = Switch(
-            ty,
-            [&](const sem::Vector* vec_type) {
-              return ValidateVectorConstructorOrCast(expr, vec_type);
-            },
-            [&](const sem::Matrix* mat_type) {
-              return ValidateMatrixConstructorOrCast(expr, mat_type);
-            },
-            [&](const sem::Array* arr_type) {
-              return ValidateArrayConstructorOrCast(expr, arr_type);
-            },
-            [&](const sem::Struct* struct_type) {
-              return ValidateStructureConstructorOrCast(expr, struct_type);
-            },
-            [&](Default) {
-              if (ty->is_scalar()) {
-                return ValidateScalarConstructorOrCast(expr, ty);
-              }
-              AddError("type is not constructible", expr->source);
-              return false;
-            });
-        if (!ok) {
-          return nullptr;
-        }
+    auto* call_target = utils::GetOrCreate(
+        type_ctors_, TypeConstructorSig{ty, arg_tys}, [&]() -> sem::TypeConstructor* {
+            // Now that the argument types have been determined, make sure that
+            // they obey the constructor type rules laid out in
+            // https://gpuweb.github.io/gpuweb/wgsl/#type-constructor-expr.
+            bool ok = Switch(
+                ty,
+                [&](const sem::Vector* vec_type) {
+                    return validator_.VectorConstructorOrCast(expr, vec_type);
+                },
+                [&](const sem::Matrix* mat_type) {
+                    return validator_.MatrixConstructorOrCast(expr, mat_type);
+                },
+                [&](const sem::Array* arr_type) {
+                    return validator_.ArrayConstructorOrCast(expr, arr_type);
+                },
+                [&](const sem::Struct* struct_type) {
+                    return validator_.StructureConstructorOrCast(expr, struct_type);
+                },
+                [&](Default) {
+                    if (ty->is_scalar()) {
+                        return validator_.ScalarConstructorOrCast(expr, ty);
+                    }
+                    AddError("type is not constructible", expr->source);
+                    return false;
+                });
+            if (!ok) {
+                return nullptr;
+            }
 
-        return builder_->create<sem::TypeConstructor>(
-            ty, utils::Transform(
-                    arg_tys,
-                    [&](const sem::Type* t, size_t i) -> const sem::Parameter* {
-                      return builder_->create<sem::Parameter>(
-                          nullptr,                   // declaration
-                          static_cast<uint32_t>(i),  // index
-                          t->UnwrapRef(),            // type
-                          ast::StorageClass::kNone,  // storage_class
-                          ast::Access::kUndefined);  // access
-                    }));
-      });
+            return builder_->create<sem::TypeConstructor>(
+                ty, utils::Transform(arg_tys,
+                                     [&](const sem::Type* t, size_t i) -> const sem::Parameter* {
+                                         return builder_->create<sem::Parameter>(
+                                             nullptr,                   // declaration
+                                             static_cast<uint32_t>(i),  // index
+                                             t->UnwrapRef(),            // type
+                                             ast::StorageClass::kNone,  // storage_class
+                                             ast::Access::kUndefined);  // access
+                                     }));
+        });
 
-  if (!call_target) {
-    return nullptr;
-  }
+    if (!call_target) {
+        return nullptr;
+    }
 
-  auto val = EvaluateConstantValue(expr, ty);
-  bool has_side_effects = std::any_of(
-      args.begin(), args.end(), [](auto* e) { return e->HasSideEffects(); });
-  return builder_->create<sem::Call>(expr, call_target, std::move(args),
-                                     current_statement_, val, has_side_effects);
+    auto val = EvaluateConstantValue(expr, ty);
+    bool has_side_effects =
+        std::any_of(args.begin(), args.end(), [](auto* e) { return e->HasSideEffects(); });
+    return builder_->create<sem::Call>(expr, call_target, std::move(args), current_statement_, val,
+                                       has_side_effects);
 }
 
 sem::Expression* Resolver::Literal(const ast::LiteralExpression* literal) {
-  auto* ty = sem_.TypeOf(literal);
-  if (!ty) {
-    return nullptr;
-  }
+    auto* ty = Switch(
+        literal,
+        [&](const ast::IntLiteralExpression* i) -> sem::Type* {
+            switch (i->suffix) {
+                case ast::IntLiteralExpression::Suffix::kNone:
+                // TODO(crbug.com/tint/1504): This will need to become abstract-int.
+                // For now, treat as 'i32'.
+                case ast::IntLiteralExpression::Suffix::kI:
+                    return builder_->create<sem::I32>();
+                case ast::IntLiteralExpression::Suffix::kU:
+                    return builder_->create<sem::U32>();
+            }
+            return nullptr;
+        },
+        [&](const ast::FloatLiteralExpression*) { return builder_->create<sem::F32>(); },
+        [&](const ast::BoolLiteralExpression*) { return builder_->create<sem::Bool>(); },
+        [&](Default) { return nullptr; });
 
-  auto val = EvaluateConstantValue(literal, ty);
-  return builder_->create<sem::Expression>(literal, ty, current_statement_, val,
-                                           /* has_side_effects */ false);
+    if (ty == nullptr) {
+        TINT_UNREACHABLE(Resolver, builder_->Diagnostics())
+            << "Unhandled literal type: " << literal->TypeInfo().name;
+        return nullptr;
+    }
+
+    auto val = EvaluateConstantValue(literal, ty);
+    return builder_->create<sem::Expression>(literal, ty, current_statement_, val,
+                                             /* has_side_effects */ false);
 }
 
 sem::Expression* Resolver::Identifier(const ast::IdentifierExpression* expr) {
-  auto symbol = expr->symbol;
-  auto* resolved = ResolvedSymbol(expr);
-  if (auto* var = As<sem::Variable>(resolved)) {
-    auto* user =
-        builder_->create<sem::VariableUser>(expr, current_statement_, var);
+    auto symbol = expr->symbol;
+    auto* resolved = sem_.ResolvedSymbol(expr);
+    if (auto* var = As<sem::Variable>(resolved)) {
+        auto* user = builder_->create<sem::VariableUser>(expr, current_statement_, var);
 
-    if (current_statement_) {
-      // If identifier is part of a loop continuing block, make sure it
-      // doesn't refer to a variable that is bypassed by a continue statement
-      // in the loop's body block.
-      if (auto* continuing_block =
-              current_statement_
-                  ->FindFirstParent<sem::LoopContinuingBlockStatement>()) {
-        auto* loop_block =
-            continuing_block->FindFirstParent<sem::LoopBlockStatement>();
-        if (loop_block->FirstContinue()) {
-          auto& decls = loop_block->Decls();
-          // If our identifier is in loop_block->decls, make sure its index is
-          // less than first_continue
-          auto iter =
-              std::find_if(decls.begin(), decls.end(),
-                           [&symbol](auto* v) { return v->symbol == symbol; });
-          if (iter != decls.end()) {
-            auto var_decl_index =
-                static_cast<size_t>(std::distance(decls.begin(), iter));
-            if (var_decl_index >= loop_block->NumDeclsAtFirstContinue()) {
-              AddError("continue statement bypasses declaration of '" +
-                           builder_->Symbols().NameFor(symbol) + "'",
-                       loop_block->FirstContinue()->source);
-              AddNote("identifier '" + builder_->Symbols().NameFor(symbol) +
-                          "' declared here",
-                      (*iter)->source);
-              AddNote("identifier '" + builder_->Symbols().NameFor(symbol) +
-                          "' referenced in continuing block here",
-                      expr->source);
-              return nullptr;
+        if (current_statement_) {
+            // If identifier is part of a loop continuing block, make sure it
+            // doesn't refer to a variable that is bypassed by a continue statement
+            // in the loop's body block.
+            if (auto* continuing_block =
+                    current_statement_->FindFirstParent<sem::LoopContinuingBlockStatement>()) {
+                auto* loop_block = continuing_block->FindFirstParent<sem::LoopBlockStatement>();
+                if (loop_block->FirstContinue()) {
+                    auto& decls = loop_block->Decls();
+                    // If our identifier is in loop_block->decls, make sure its index is
+                    // less than first_continue
+                    auto iter = std::find_if(decls.begin(), decls.end(),
+                                             [&symbol](auto* v) { return v->symbol == symbol; });
+                    if (iter != decls.end()) {
+                        auto var_decl_index =
+                            static_cast<size_t>(std::distance(decls.begin(), iter));
+                        if (var_decl_index >= loop_block->NumDeclsAtFirstContinue()) {
+                            AddError("continue statement bypasses declaration of '" +
+                                         builder_->Symbols().NameFor(symbol) + "'",
+                                     loop_block->FirstContinue()->source);
+                            AddNote("identifier '" + builder_->Symbols().NameFor(symbol) +
+                                        "' declared here",
+                                    (*iter)->source);
+                            AddNote("identifier '" + builder_->Symbols().NameFor(symbol) +
+                                        "' referenced in continuing block here",
+                                    expr->source);
+                            return nullptr;
+                        }
+                    }
+                }
             }
-          }
         }
-      }
+
+        if (current_function_) {
+            if (auto* global = var->As<sem::GlobalVariable>()) {
+                current_function_->AddDirectlyReferencedGlobal(global);
+            }
+        }
+
+        var->AddUser(user);
+        return user;
     }
 
-    if (current_function_) {
-      if (auto* global = var->As<sem::GlobalVariable>()) {
-        current_function_->AddDirectlyReferencedGlobal(global);
-      }
+    if (Is<sem::Function>(resolved)) {
+        AddError("missing '(' for function call", expr->source.End());
+        return nullptr;
     }
 
-    var->AddUser(user);
-    return user;
-  }
+    if (IsBuiltin(symbol)) {
+        AddError("missing '(' for builtin call", expr->source.End());
+        return nullptr;
+    }
 
-  if (Is<sem::Function>(resolved)) {
-    AddError("missing '(' for function call", expr->source.End());
+    if (resolved->Is<sem::Type>()) {
+        AddError("missing '(' for type constructor or cast", expr->source.End());
+        return nullptr;
+    }
+
+    TINT_ICE(Resolver, diagnostics_)
+        << expr->source << " unresolved identifier:\n"
+        << "resolved: " << (resolved ? resolved->TypeInfo().name : "<null>") << "\n"
+        << "name: " << builder_->Symbols().NameFor(symbol);
     return nullptr;
-  }
-
-  if (IsBuiltin(symbol)) {
-    AddError("missing '(' for builtin call", expr->source.End());
-    return nullptr;
-  }
-
-  if (resolved->Is<sem::Type>()) {
-    AddError("missing '(' for type constructor or cast", expr->source.End());
-    return nullptr;
-  }
-
-  TINT_ICE(Resolver, diagnostics_)
-      << expr->source << " unresolved identifier:\n"
-      << "resolved: " << (resolved ? resolved->TypeInfo().name : "<null>")
-      << "\n"
-      << "name: " << builder_->Symbols().NameFor(symbol);
-  return nullptr;
 }
 
-sem::Expression* Resolver::MemberAccessor(
-    const ast::MemberAccessorExpression* expr) {
-  auto* structure = sem_.TypeOf(expr->structure);
-  auto* storage_ty = structure->UnwrapRef();
+sem::Expression* Resolver::MemberAccessor(const ast::MemberAccessorExpression* expr) {
+    auto* structure = sem_.TypeOf(expr->structure);
+    auto* storage_ty = structure->UnwrapRef();
+    auto* source_var = sem_.Get(expr->structure)->SourceVariable();
 
-  const sem::Type* ret = nullptr;
-  std::vector<uint32_t> swizzle;
+    const sem::Type* ret = nullptr;
+    std::vector<uint32_t> swizzle;
 
-  // Structure may be a side-effecting expression (e.g. function call).
-  auto* sem_structure = sem_.Get(expr->structure);
-  bool has_side_effects = sem_structure && sem_structure->HasSideEffects();
+    // Structure may be a side-effecting expression (e.g. function call).
+    auto* sem_structure = sem_.Get(expr->structure);
+    bool has_side_effects = sem_structure && sem_structure->HasSideEffects();
 
-  if (auto* str = storage_ty->As<sem::Struct>()) {
-    Mark(expr->member);
-    auto symbol = expr->member->symbol;
+    if (auto* str = storage_ty->As<sem::Struct>()) {
+        Mark(expr->member);
+        auto symbol = expr->member->symbol;
 
-    const sem::StructMember* member = nullptr;
-    for (auto* m : str->Members()) {
-      if (m->Name() == symbol) {
-        ret = m->Type();
-        member = m;
-        break;
-      }
+        const sem::StructMember* member = nullptr;
+        for (auto* m : str->Members()) {
+            if (m->Name() == symbol) {
+                ret = m->Type();
+                member = m;
+                break;
+            }
+        }
+
+        if (ret == nullptr) {
+            AddError("struct member " + builder_->Symbols().NameFor(symbol) + " not found",
+                     expr->source);
+            return nullptr;
+        }
+
+        // If we're extracting from a reference, we return a reference.
+        if (auto* ref = structure->As<sem::Reference>()) {
+            ret = builder_->create<sem::Reference>(ret, ref->StorageClass(), ref->Access());
+        }
+
+        return builder_->create<sem::StructMemberAccess>(expr, ret, current_statement_, member,
+                                                         has_side_effects, source_var);
     }
 
-    if (ret == nullptr) {
-      AddError(
-          "struct member " + builder_->Symbols().NameFor(symbol) + " not found",
-          expr->source);
-      return nullptr;
+    if (auto* vec = storage_ty->As<sem::Vector>()) {
+        Mark(expr->member);
+        std::string s = builder_->Symbols().NameFor(expr->member->symbol);
+        auto size = s.size();
+        swizzle.reserve(s.size());
+
+        for (auto c : s) {
+            switch (c) {
+                case 'x':
+                case 'r':
+                    swizzle.emplace_back(0);
+                    break;
+                case 'y':
+                case 'g':
+                    swizzle.emplace_back(1);
+                    break;
+                case 'z':
+                case 'b':
+                    swizzle.emplace_back(2);
+                    break;
+                case 'w':
+                case 'a':
+                    swizzle.emplace_back(3);
+                    break;
+                default:
+                    AddError("invalid vector swizzle character",
+                             expr->member->source.Begin() + swizzle.size());
+                    return nullptr;
+            }
+
+            if (swizzle.back() >= vec->Width()) {
+                AddError("invalid vector swizzle member", expr->member->source);
+                return nullptr;
+            }
+        }
+
+        if (size < 1 || size > 4) {
+            AddError("invalid vector swizzle size", expr->member->source);
+            return nullptr;
+        }
+
+        // All characters are valid, check if they're being mixed
+        auto is_rgba = [](char c) { return c == 'r' || c == 'g' || c == 'b' || c == 'a'; };
+        auto is_xyzw = [](char c) { return c == 'x' || c == 'y' || c == 'z' || c == 'w'; };
+        if (!std::all_of(s.begin(), s.end(), is_rgba) &&
+            !std::all_of(s.begin(), s.end(), is_xyzw)) {
+            AddError("invalid mixing of vector swizzle characters rgba with xyzw",
+                     expr->member->source);
+            return nullptr;
+        }
+
+        if (size == 1) {
+            // A single element swizzle is just the type of the vector.
+            ret = vec->type();
+            // If we're extracting from a reference, we return a reference.
+            if (auto* ref = structure->As<sem::Reference>()) {
+                ret = builder_->create<sem::Reference>(ret, ref->StorageClass(), ref->Access());
+            }
+        } else {
+            // The vector will have a number of components equal to the length of
+            // the swizzle.
+            ret = builder_->create<sem::Vector>(vec->type(), static_cast<uint32_t>(size));
+        }
+        return builder_->create<sem::Swizzle>(expr, ret, current_statement_, std::move(swizzle),
+                                              has_side_effects, source_var);
     }
 
-    // If we're extracting from a reference, we return a reference.
-    if (auto* ref = structure->As<sem::Reference>()) {
-      ret = builder_->create<sem::Reference>(ret, ref->StorageClass(),
-                                             ref->Access());
-    }
-
-    return builder_->create<sem::StructMemberAccess>(
-        expr, ret, current_statement_, member, has_side_effects);
-  }
-
-  if (auto* vec = storage_ty->As<sem::Vector>()) {
-    Mark(expr->member);
-    std::string s = builder_->Symbols().NameFor(expr->member->symbol);
-    auto size = s.size();
-    swizzle.reserve(s.size());
-
-    for (auto c : s) {
-      switch (c) {
-        case 'x':
-        case 'r':
-          swizzle.emplace_back(0);
-          break;
-        case 'y':
-        case 'g':
-          swizzle.emplace_back(1);
-          break;
-        case 'z':
-        case 'b':
-          swizzle.emplace_back(2);
-          break;
-        case 'w':
-        case 'a':
-          swizzle.emplace_back(3);
-          break;
-        default:
-          AddError("invalid vector swizzle character",
-                   expr->member->source.Begin() + swizzle.size());
-          return nullptr;
-      }
-
-      if (swizzle.back() >= vec->Width()) {
-        AddError("invalid vector swizzle member", expr->member->source);
-        return nullptr;
-      }
-    }
-
-    if (size < 1 || size > 4) {
-      AddError("invalid vector swizzle size", expr->member->source);
-      return nullptr;
-    }
-
-    // All characters are valid, check if they're being mixed
-    auto is_rgba = [](char c) {
-      return c == 'r' || c == 'g' || c == 'b' || c == 'a';
-    };
-    auto is_xyzw = [](char c) {
-      return c == 'x' || c == 'y' || c == 'z' || c == 'w';
-    };
-    if (!std::all_of(s.begin(), s.end(), is_rgba) &&
-        !std::all_of(s.begin(), s.end(), is_xyzw)) {
-      AddError("invalid mixing of vector swizzle characters rgba with xyzw",
-               expr->member->source);
-      return nullptr;
-    }
-
-    if (size == 1) {
-      // A single element swizzle is just the type of the vector.
-      ret = vec->type();
-      // If we're extracting from a reference, we return a reference.
-      if (auto* ref = structure->As<sem::Reference>()) {
-        ret = builder_->create<sem::Reference>(ret, ref->StorageClass(),
-                                               ref->Access());
-      }
-    } else {
-      // The vector will have a number of components equal to the length of
-      // the swizzle.
-      ret = builder_->create<sem::Vector>(vec->type(),
-                                          static_cast<uint32_t>(size));
-    }
-    return builder_->create<sem::Swizzle>(expr, ret, current_statement_,
-                                          std::move(swizzle), has_side_effects);
-  }
-
-  AddError(
-      "invalid member accessor expression. Expected vector or struct, got '" +
-          sem_.TypeNameOf(storage_ty) + "'",
-      expr->structure->source);
-  return nullptr;
+    AddError("invalid member accessor expression. Expected vector or struct, got '" +
+                 sem_.TypeNameOf(storage_ty) + "'",
+             expr->structure->source);
+    return nullptr;
 }
 
 sem::Expression* Resolver::Binary(const ast::BinaryExpression* expr) {
-  auto* lhs = sem_.Get(expr->lhs);
-  auto* rhs = sem_.Get(expr->rhs);
-  auto* lhs_ty = lhs->Type()->UnwrapRef();
-  auto* rhs_ty = rhs->Type()->UnwrapRef();
+    auto* lhs = sem_.Get(expr->lhs);
+    auto* rhs = sem_.Get(expr->rhs);
+    auto* lhs_ty = lhs->Type()->UnwrapRef();
+    auto* rhs_ty = rhs->Type()->UnwrapRef();
 
-  auto* ty = BinaryOpType(lhs_ty, rhs_ty, expr->op);
-  if (!ty) {
-    AddError(
-        "Binary expression operand types are invalid for this operation: " +
-            sem_.TypeNameOf(lhs_ty) + " " + FriendlyName(expr->op) + " " +
-            sem_.TypeNameOf(rhs_ty),
-        expr->source);
-    return nullptr;
-  }
+    auto* ty = BinaryOpType(lhs_ty, rhs_ty, expr->op);
+    if (!ty) {
+        AddError("Binary expression operand types are invalid for this operation: " +
+                     sem_.TypeNameOf(lhs_ty) + " " + FriendlyName(expr->op) + " " +
+                     sem_.TypeNameOf(rhs_ty),
+                 expr->source);
+        return nullptr;
+    }
 
-  auto val = EvaluateConstantValue(expr, ty);
-  bool has_side_effects = lhs->HasSideEffects() || rhs->HasSideEffects();
-  auto* sem = builder_->create<sem::Expression>(expr, ty, current_statement_,
-                                                val, has_side_effects);
-  sem->Behaviors() = lhs->Behaviors() + rhs->Behaviors();
+    auto val = EvaluateConstantValue(expr, ty);
+    bool has_side_effects = lhs->HasSideEffects() || rhs->HasSideEffects();
+    auto* sem =
+        builder_->create<sem::Expression>(expr, ty, current_statement_, val, has_side_effects);
+    sem->Behaviors() = lhs->Behaviors() + rhs->Behaviors();
 
-  return sem;
+    return sem;
 }
 
 const sem::Type* Resolver::BinaryOpType(const sem::Type* lhs_ty,
                                         const sem::Type* rhs_ty,
                                         ast::BinaryOp op) {
-  using Bool = sem::Bool;
-  using F32 = sem::F32;
-  using I32 = sem::I32;
-  using U32 = sem::U32;
-  using Matrix = sem::Matrix;
-  using Vector = sem::Vector;
+    using Bool = sem::Bool;
+    using F32 = sem::F32;
+    using I32 = sem::I32;
+    using U32 = sem::U32;
+    using Matrix = sem::Matrix;
+    using Vector = sem::Vector;
 
-  auto* lhs_vec = lhs_ty->As<Vector>();
-  auto* lhs_vec_elem_type = lhs_vec ? lhs_vec->type() : nullptr;
-  auto* rhs_vec = rhs_ty->As<Vector>();
-  auto* rhs_vec_elem_type = rhs_vec ? rhs_vec->type() : nullptr;
+    auto* lhs_vec = lhs_ty->As<Vector>();
+    auto* lhs_vec_elem_type = lhs_vec ? lhs_vec->type() : nullptr;
+    auto* rhs_vec = rhs_ty->As<Vector>();
+    auto* rhs_vec_elem_type = rhs_vec ? rhs_vec->type() : nullptr;
 
-  const bool matching_vec_elem_types =
-      lhs_vec_elem_type && rhs_vec_elem_type &&
-      (lhs_vec_elem_type == rhs_vec_elem_type) &&
-      (lhs_vec->Width() == rhs_vec->Width());
+    const bool matching_vec_elem_types = lhs_vec_elem_type && rhs_vec_elem_type &&
+                                         (lhs_vec_elem_type == rhs_vec_elem_type) &&
+                                         (lhs_vec->Width() == rhs_vec->Width());
 
-  const bool matching_types = matching_vec_elem_types || (lhs_ty == rhs_ty);
+    const bool matching_types = matching_vec_elem_types || (lhs_ty == rhs_ty);
 
-  // Binary logical expressions
-  if (op == ast::BinaryOp::kLogicalAnd || op == ast::BinaryOp::kLogicalOr) {
-    if (matching_types && lhs_ty->Is<Bool>()) {
-      return lhs_ty;
+    // Binary logical expressions
+    if (op == ast::BinaryOp::kLogicalAnd || op == ast::BinaryOp::kLogicalOr) {
+        if (matching_types && lhs_ty->Is<Bool>()) {
+            return lhs_ty;
+        }
     }
-  }
-  if (op == ast::BinaryOp::kOr || op == ast::BinaryOp::kAnd) {
-    if (matching_types && lhs_ty->Is<Bool>()) {
-      return lhs_ty;
-    }
-    if (matching_types && lhs_vec_elem_type && lhs_vec_elem_type->Is<Bool>()) {
-      return lhs_ty;
-    }
-  }
-
-  // Arithmetic expressions
-  if (ast::IsArithmetic(op)) {
-    // Binary arithmetic expressions over scalars
-    if (matching_types && lhs_ty->is_numeric_scalar()) {
-      return lhs_ty;
+    if (op == ast::BinaryOp::kOr || op == ast::BinaryOp::kAnd) {
+        if (matching_types && lhs_ty->Is<Bool>()) {
+            return lhs_ty;
+        }
+        if (matching_types && lhs_vec_elem_type && lhs_vec_elem_type->Is<Bool>()) {
+            return lhs_ty;
+        }
     }
 
-    // Binary arithmetic expressions over vectors
-    if (matching_types && lhs_vec_elem_type &&
-        lhs_vec_elem_type->is_numeric_scalar()) {
-      return lhs_ty;
+    // Arithmetic expressions
+    if (ast::IsArithmetic(op)) {
+        // Binary arithmetic expressions over scalars
+        if (matching_types && lhs_ty->is_numeric_scalar()) {
+            return lhs_ty;
+        }
+
+        // Binary arithmetic expressions over vectors
+        if (matching_types && lhs_vec_elem_type && lhs_vec_elem_type->is_numeric_scalar()) {
+            return lhs_ty;
+        }
+
+        // Binary arithmetic expressions with mixed scalar and vector operands
+        if (lhs_vec_elem_type && (lhs_vec_elem_type == rhs_ty) && rhs_ty->is_numeric_scalar()) {
+            return lhs_ty;
+        }
+        if (rhs_vec_elem_type && (rhs_vec_elem_type == lhs_ty) && lhs_ty->is_numeric_scalar()) {
+            return rhs_ty;
+        }
     }
 
-    // Binary arithmetic expressions with mixed scalar and vector operands
-    if (lhs_vec_elem_type && (lhs_vec_elem_type == rhs_ty) &&
-        rhs_ty->is_numeric_scalar()) {
-      return lhs_ty;
+    // Matrix arithmetic
+    auto* lhs_mat = lhs_ty->As<Matrix>();
+    auto* lhs_mat_elem_type = lhs_mat ? lhs_mat->type() : nullptr;
+    auto* rhs_mat = rhs_ty->As<Matrix>();
+    auto* rhs_mat_elem_type = rhs_mat ? rhs_mat->type() : nullptr;
+    // Addition and subtraction of float matrices
+    if ((op == ast::BinaryOp::kAdd || op == ast::BinaryOp::kSubtract) && lhs_mat_elem_type &&
+        lhs_mat_elem_type->Is<F32>() && rhs_mat_elem_type && rhs_mat_elem_type->Is<F32>() &&
+        (lhs_mat->columns() == rhs_mat->columns()) && (lhs_mat->rows() == rhs_mat->rows())) {
+        return rhs_ty;
     }
-    if (rhs_vec_elem_type && (rhs_vec_elem_type == lhs_ty) &&
-        lhs_ty->is_numeric_scalar()) {
-      return rhs_ty;
-    }
-  }
+    if (op == ast::BinaryOp::kMultiply) {
+        // Multiplication of a matrix and a scalar
+        if (lhs_ty->Is<F32>() && rhs_mat_elem_type && rhs_mat_elem_type->Is<F32>()) {
+            return rhs_ty;
+        }
+        if (lhs_mat_elem_type && lhs_mat_elem_type->Is<F32>() && rhs_ty->Is<F32>()) {
+            return lhs_ty;
+        }
 
-  // Matrix arithmetic
-  auto* lhs_mat = lhs_ty->As<Matrix>();
-  auto* lhs_mat_elem_type = lhs_mat ? lhs_mat->type() : nullptr;
-  auto* rhs_mat = rhs_ty->As<Matrix>();
-  auto* rhs_mat_elem_type = rhs_mat ? rhs_mat->type() : nullptr;
-  // Addition and subtraction of float matrices
-  if ((op == ast::BinaryOp::kAdd || op == ast::BinaryOp::kSubtract) &&
-      lhs_mat_elem_type && lhs_mat_elem_type->Is<F32>() && rhs_mat_elem_type &&
-      rhs_mat_elem_type->Is<F32>() &&
-      (lhs_mat->columns() == rhs_mat->columns()) &&
-      (lhs_mat->rows() == rhs_mat->rows())) {
-    return rhs_ty;
-  }
-  if (op == ast::BinaryOp::kMultiply) {
-    // Multiplication of a matrix and a scalar
-    if (lhs_ty->Is<F32>() && rhs_mat_elem_type &&
-        rhs_mat_elem_type->Is<F32>()) {
-      return rhs_ty;
-    }
-    if (lhs_mat_elem_type && lhs_mat_elem_type->Is<F32>() &&
-        rhs_ty->Is<F32>()) {
-      return lhs_ty;
+        // Vector times matrix
+        if (lhs_vec_elem_type && lhs_vec_elem_type->Is<F32>() && rhs_mat_elem_type &&
+            rhs_mat_elem_type->Is<F32>() && (lhs_vec->Width() == rhs_mat->rows())) {
+            return builder_->create<sem::Vector>(lhs_vec->type(), rhs_mat->columns());
+        }
+
+        // Matrix times vector
+        if (lhs_mat_elem_type && lhs_mat_elem_type->Is<F32>() && rhs_vec_elem_type &&
+            rhs_vec_elem_type->Is<F32>() && (lhs_mat->columns() == rhs_vec->Width())) {
+            return builder_->create<sem::Vector>(rhs_vec->type(), lhs_mat->rows());
+        }
+
+        // Matrix times matrix
+        if (lhs_mat_elem_type && lhs_mat_elem_type->Is<F32>() && rhs_mat_elem_type &&
+            rhs_mat_elem_type->Is<F32>() && (lhs_mat->columns() == rhs_mat->rows())) {
+            return builder_->create<sem::Matrix>(
+                builder_->create<sem::Vector>(lhs_mat_elem_type, lhs_mat->rows()),
+                rhs_mat->columns());
+        }
     }
 
-    // Vector times matrix
-    if (lhs_vec_elem_type && lhs_vec_elem_type->Is<F32>() &&
-        rhs_mat_elem_type && rhs_mat_elem_type->Is<F32>() &&
-        (lhs_vec->Width() == rhs_mat->rows())) {
-      return builder_->create<sem::Vector>(lhs_vec->type(), rhs_mat->columns());
+    // Comparison expressions
+    if (ast::IsComparison(op)) {
+        if (matching_types) {
+            // Special case for bools: only == and !=
+            if (lhs_ty->Is<Bool>() &&
+                (op == ast::BinaryOp::kEqual || op == ast::BinaryOp::kNotEqual)) {
+                return builder_->create<sem::Bool>();
+            }
+
+            // For the rest, we can compare i32, u32, and f32
+            if (lhs_ty->IsAnyOf<I32, U32, F32>()) {
+                return builder_->create<sem::Bool>();
+            }
+        }
+
+        // Same for vectors
+        if (matching_vec_elem_types) {
+            if (lhs_vec_elem_type->Is<Bool>() &&
+                (op == ast::BinaryOp::kEqual || op == ast::BinaryOp::kNotEqual)) {
+                return builder_->create<sem::Vector>(builder_->create<sem::Bool>(),
+                                                     lhs_vec->Width());
+            }
+
+            if (lhs_vec_elem_type->is_numeric_scalar()) {
+                return builder_->create<sem::Vector>(builder_->create<sem::Bool>(),
+                                                     lhs_vec->Width());
+            }
+        }
     }
 
-    // Matrix times vector
-    if (lhs_mat_elem_type && lhs_mat_elem_type->Is<F32>() &&
-        rhs_vec_elem_type && rhs_vec_elem_type->Is<F32>() &&
-        (lhs_mat->columns() == rhs_vec->Width())) {
-      return builder_->create<sem::Vector>(rhs_vec->type(), lhs_mat->rows());
+    // Binary bitwise operations
+    if (ast::IsBitwise(op)) {
+        if (matching_types && lhs_ty->is_integer_scalar_or_vector()) {
+            return lhs_ty;
+        }
     }
 
-    // Matrix times matrix
-    if (lhs_mat_elem_type && lhs_mat_elem_type->Is<F32>() &&
-        rhs_mat_elem_type && rhs_mat_elem_type->Is<F32>() &&
-        (lhs_mat->columns() == rhs_mat->rows())) {
-      return builder_->create<sem::Matrix>(
-          builder_->create<sem::Vector>(lhs_mat_elem_type, lhs_mat->rows()),
-          rhs_mat->columns());
-    }
-  }
+    // Bit shift expressions
+    if (ast::IsBitshift(op)) {
+        // Type validation rules are the same for left or right shift, despite
+        // differences in computation rules (i.e. right shift can be arithmetic or
+        // logical depending on lhs type).
 
-  // Comparison expressions
-  if (ast::IsComparison(op)) {
-    if (matching_types) {
-      // Special case for bools: only == and !=
-      if (lhs_ty->Is<Bool>() &&
-          (op == ast::BinaryOp::kEqual || op == ast::BinaryOp::kNotEqual)) {
-        return builder_->create<sem::Bool>();
-      }
+        if (lhs_ty->IsAnyOf<I32, U32>() && rhs_ty->Is<U32>()) {
+            return lhs_ty;
+        }
 
-      // For the rest, we can compare i32, u32, and f32
-      if (lhs_ty->IsAnyOf<I32, U32, F32>()) {
-        return builder_->create<sem::Bool>();
-      }
+        if (lhs_vec_elem_type && lhs_vec_elem_type->IsAnyOf<I32, U32>() && rhs_vec_elem_type &&
+            rhs_vec_elem_type->Is<U32>()) {
+            return lhs_ty;
+        }
     }
 
-    // Same for vectors
-    if (matching_vec_elem_types) {
-      if (lhs_vec_elem_type->Is<Bool>() &&
-          (op == ast::BinaryOp::kEqual || op == ast::BinaryOp::kNotEqual)) {
-        return builder_->create<sem::Vector>(builder_->create<sem::Bool>(),
-                                             lhs_vec->Width());
-      }
-
-      if (lhs_vec_elem_type->is_numeric_scalar()) {
-        return builder_->create<sem::Vector>(builder_->create<sem::Bool>(),
-                                             lhs_vec->Width());
-      }
-    }
-  }
-
-  // Binary bitwise operations
-  if (ast::IsBitwise(op)) {
-    if (matching_types && lhs_ty->is_integer_scalar_or_vector()) {
-      return lhs_ty;
-    }
-  }
-
-  // Bit shift expressions
-  if (ast::IsBitshift(op)) {
-    // Type validation rules are the same for left or right shift, despite
-    // differences in computation rules (i.e. right shift can be arithmetic or
-    // logical depending on lhs type).
-
-    if (lhs_ty->IsAnyOf<I32, U32>() && rhs_ty->Is<U32>()) {
-      return lhs_ty;
-    }
-
-    if (lhs_vec_elem_type && lhs_vec_elem_type->IsAnyOf<I32, U32>() &&
-        rhs_vec_elem_type && rhs_vec_elem_type->Is<U32>()) {
-      return lhs_ty;
-    }
-  }
-
-  return nullptr;
+    return nullptr;
 }
 
 sem::Expression* Resolver::UnaryOp(const ast::UnaryOpExpression* unary) {
-  auto* expr = sem_.Get(unary->expr);
-  auto* expr_ty = expr->Type();
-  if (!expr_ty) {
-    return nullptr;
-  }
-
-  const sem::Type* ty = nullptr;
-
-  switch (unary->op) {
-    case ast::UnaryOp::kNot:
-      // Result type matches the deref'd inner type.
-      ty = expr_ty->UnwrapRef();
-      if (!ty->Is<sem::Bool>() && !ty->is_bool_vector()) {
-        AddError("cannot logical negate expression of type '" +
-                     sem_.TypeNameOf(expr_ty),
-                 unary->expr->source);
+    auto* expr = sem_.Get(unary->expr);
+    auto* expr_ty = expr->Type();
+    if (!expr_ty) {
         return nullptr;
-      }
-      break;
+    }
 
-    case ast::UnaryOp::kComplement:
-      // Result type matches the deref'd inner type.
-      ty = expr_ty->UnwrapRef();
-      if (!ty->is_integer_scalar_or_vector()) {
-        AddError("cannot bitwise complement expression of type '" +
-                     sem_.TypeNameOf(expr_ty),
-                 unary->expr->source);
-        return nullptr;
-      }
-      break;
+    const sem::Type* ty = nullptr;
+    const sem::Variable* source_var = nullptr;
 
-    case ast::UnaryOp::kNegation:
-      // Result type matches the deref'd inner type.
-      ty = expr_ty->UnwrapRef();
-      if (!(ty->IsAnyOf<sem::F32, sem::I32>() ||
-            ty->is_signed_integer_vector() || ty->is_float_vector())) {
-        AddError(
-            "cannot negate expression of type '" + sem_.TypeNameOf(expr_ty),
-            unary->expr->source);
-        return nullptr;
-      }
-      break;
+    switch (unary->op) {
+        case ast::UnaryOp::kNot:
+            // Result type matches the deref'd inner type.
+            ty = expr_ty->UnwrapRef();
+            if (!ty->Is<sem::Bool>() && !ty->is_bool_vector()) {
+                AddError("cannot logical negate expression of type '" + sem_.TypeNameOf(expr_ty),
+                         unary->expr->source);
+                return nullptr;
+            }
+            break;
 
-    case ast::UnaryOp::kAddressOf:
-      if (auto* ref = expr_ty->As<sem::Reference>()) {
-        if (ref->StoreType()->UnwrapRef()->is_handle()) {
-          AddError(
-              "cannot take the address of expression in handle storage class",
-              unary->expr->source);
-          return nullptr;
-        }
+        case ast::UnaryOp::kComplement:
+            // Result type matches the deref'd inner type.
+            ty = expr_ty->UnwrapRef();
+            if (!ty->is_integer_scalar_or_vector()) {
+                AddError(
+                    "cannot bitwise complement expression of type '" + sem_.TypeNameOf(expr_ty),
+                    unary->expr->source);
+                return nullptr;
+            }
+            break;
 
-        auto* array = unary->expr->As<ast::IndexAccessorExpression>();
-        auto* member = unary->expr->As<ast::MemberAccessorExpression>();
-        if ((array &&
-             sem_.TypeOf(array->object)->UnwrapRef()->Is<sem::Vector>()) ||
-            (member &&
-             sem_.TypeOf(member->structure)->UnwrapRef()->Is<sem::Vector>())) {
-          AddError("cannot take the address of a vector component",
-                   unary->expr->source);
-          return nullptr;
-        }
+        case ast::UnaryOp::kNegation:
+            // Result type matches the deref'd inner type.
+            ty = expr_ty->UnwrapRef();
+            if (!(ty->IsAnyOf<sem::F32, sem::I32>() || ty->is_signed_integer_vector() ||
+                  ty->is_float_vector())) {
+                AddError("cannot negate expression of type '" + sem_.TypeNameOf(expr_ty),
+                         unary->expr->source);
+                return nullptr;
+            }
+            break;
 
-        ty = builder_->create<sem::Pointer>(ref->StoreType(),
-                                            ref->StorageClass(), ref->Access());
-      } else {
-        AddError("cannot take the address of expression", unary->expr->source);
-        return nullptr;
-      }
-      break;
+        case ast::UnaryOp::kAddressOf:
+            if (auto* ref = expr_ty->As<sem::Reference>()) {
+                if (ref->StoreType()->UnwrapRef()->is_handle()) {
+                    AddError("cannot take the address of expression in handle storage class",
+                             unary->expr->source);
+                    return nullptr;
+                }
 
-    case ast::UnaryOp::kIndirection:
-      if (auto* ptr = expr_ty->As<sem::Pointer>()) {
-        ty = builder_->create<sem::Reference>(
-            ptr->StoreType(), ptr->StorageClass(), ptr->Access());
-      } else {
-        AddError("cannot dereference expression of type '" +
-                     sem_.TypeNameOf(expr_ty) + "'",
-                 unary->expr->source);
-        return nullptr;
-      }
-      break;
-  }
+                auto* array = unary->expr->As<ast::IndexAccessorExpression>();
+                auto* member = unary->expr->As<ast::MemberAccessorExpression>();
+                if ((array && sem_.TypeOf(array->object)->UnwrapRef()->Is<sem::Vector>()) ||
+                    (member && sem_.TypeOf(member->structure)->UnwrapRef()->Is<sem::Vector>())) {
+                    AddError("cannot take the address of a vector component", unary->expr->source);
+                    return nullptr;
+                }
 
-  auto val = EvaluateConstantValue(unary, ty);
-  auto* sem = builder_->create<sem::Expression>(unary, ty, current_statement_,
-                                                val, expr->HasSideEffects());
-  sem->Behaviors() = expr->Behaviors();
-  return sem;
+                ty = builder_->create<sem::Pointer>(ref->StoreType(), ref->StorageClass(),
+                                                    ref->Access());
+
+                source_var = expr->SourceVariable();
+            } else {
+                AddError("cannot take the address of expression", unary->expr->source);
+                return nullptr;
+            }
+            break;
+
+        case ast::UnaryOp::kIndirection:
+            if (auto* ptr = expr_ty->As<sem::Pointer>()) {
+                ty = builder_->create<sem::Reference>(ptr->StoreType(), ptr->StorageClass(),
+                                                      ptr->Access());
+                source_var = expr->SourceVariable();
+            } else {
+                AddError("cannot dereference expression of type '" + sem_.TypeNameOf(expr_ty) + "'",
+                         unary->expr->source);
+                return nullptr;
+            }
+            break;
+    }
+
+    auto val = EvaluateConstantValue(unary, ty);
+    auto* sem = builder_->create<sem::Expression>(unary, ty, current_statement_, val,
+                                                  expr->HasSideEffects(), source_var);
+    sem->Behaviors() = expr->Behaviors();
+    return sem;
 }
 
 sem::Type* Resolver::TypeDecl(const ast::TypeDecl* named_type) {
-  sem::Type* result = nullptr;
-  if (auto* alias = named_type->As<ast::Alias>()) {
-    result = Alias(alias);
-  } else if (auto* str = named_type->As<ast::Struct>()) {
-    result = Structure(str);
-  } else {
-    TINT_UNREACHABLE(Resolver, diagnostics_) << "Unhandled TypeDecl";
-  }
+    sem::Type* result = nullptr;
+    if (auto* alias = named_type->As<ast::Alias>()) {
+        result = Alias(alias);
+    } else if (auto* str = named_type->As<ast::Struct>()) {
+        result = Structure(str);
+    } else {
+        TINT_UNREACHABLE(Resolver, diagnostics_) << "Unhandled TypeDecl";
+    }
 
-  if (!result) {
-    return nullptr;
-  }
+    if (!result) {
+        return nullptr;
+    }
 
-  builder_->Sem().Add(named_type, result);
-  return result;
+    builder_->Sem().Add(named_type, result);
+    return result;
 }
 
 sem::Array* Resolver::Array(const ast::Array* arr) {
-  auto source = arr->source;
+    auto source = arr->source;
 
-  auto* elem_type = Type(arr->type);
-  if (!elem_type) {
-    return nullptr;
-  }
-
-  if (!IsPlain(elem_type)) {  // Check must come before GetDefaultAlignAndSize()
-    AddError(sem_.TypeNameOf(elem_type) +
-                 " cannot be used as an element type of an array",
-             source);
-    return nullptr;
-  }
-
-  uint32_t el_align = elem_type->Align();
-  uint32_t el_size = elem_type->Size();
-
-  if (!ValidateNoDuplicateAttributes(arr->attributes)) {
-    return nullptr;
-  }
-
-  // Look for explicit stride via @stride(n) attribute
-  uint32_t explicit_stride = 0;
-  for (auto* attr : arr->attributes) {
-    Mark(attr);
-    if (auto* sd = attr->As<ast::StrideAttribute>()) {
-      explicit_stride = sd->stride;
-      if (!ValidateArrayStrideAttribute(sd, el_size, el_align, source)) {
+    auto* elem_type = Type(arr->type);
+    if (!elem_type) {
         return nullptr;
-      }
-      continue;
     }
 
-    AddError("attribute is not valid for array types", attr->source);
-    return nullptr;
-  }
-
-  // Calculate implicit stride
-  uint64_t implicit_stride = utils::RoundUp<uint64_t>(el_align, el_size);
-
-  uint64_t stride = explicit_stride ? explicit_stride : implicit_stride;
-
-  // Evaluate the constant array size expression.
-  // sem::Array uses a size of 0 for a runtime-sized array.
-  uint32_t count = 0;
-  if (auto* count_expr = arr->count) {
-    auto* count_sem = Expression(count_expr);
-    if (!count_sem) {
-      return nullptr;
-    }
-
-    auto size_source = count_expr->source;
-
-    auto* ty = count_sem->Type()->UnwrapRef();
-    if (!ty->is_integer_scalar()) {
-      AddError("array size must be integer scalar", size_source);
-      return nullptr;
-    }
-
-    if (auto* ident = count_expr->As<ast::IdentifierExpression>()) {
-      // Make sure the identifier is a non-overridable module-scope constant.
-      auto* var = ResolvedSymbol<sem::GlobalVariable>(ident);
-      if (!var || !var->Declaration()->is_const) {
-        AddError("array size identifier must be a module-scope constant",
-                 size_source);
+    if (!validator_.IsPlain(elem_type)) {  // Check must come before GetDefaultAlignAndSize()
+        AddError(sem_.TypeNameOf(elem_type) + " cannot be used as an element type of an array",
+                 source);
         return nullptr;
-      }
-      if (var->IsOverridable()) {
-        AddError("array size expression must not be pipeline-overridable",
-                 size_source);
+    }
+
+    uint32_t el_align = elem_type->Align();
+    uint32_t el_size = elem_type->Size();
+
+    if (!validator_.NoDuplicateAttributes(arr->attributes)) {
         return nullptr;
-      }
-
-      count_expr = var->Declaration()->constructor;
-    } else if (!count_expr->Is<ast::LiteralExpression>()) {
-      AddError(
-          "array size expression must be either a literal or a module-scope "
-          "constant",
-          size_source);
-      return nullptr;
     }
 
-    auto count_val = count_sem->ConstantValue();
-    if (!count_val) {
-      TINT_ICE(Resolver, diagnostics_)
-          << "could not resolve array size expression";
-      return nullptr;
+    // Look for explicit stride via @stride(n) attribute
+    uint32_t explicit_stride = 0;
+    for (auto* attr : arr->attributes) {
+        Mark(attr);
+        if (auto* sd = attr->As<ast::StrideAttribute>()) {
+            explicit_stride = sd->stride;
+            if (!validator_.ArrayStrideAttribute(sd, el_size, el_align, source)) {
+                return nullptr;
+            }
+            continue;
+        }
+
+        AddError("attribute is not valid for array types", attr->source);
+        return nullptr;
     }
 
-    if (ty->is_signed_integer_scalar() ? count_val.Elements()[0].i32 < 1
-                                       : count_val.Elements()[0].u32 < 1u) {
-      AddError("array size must be at least 1", size_source);
-      return nullptr;
+    // Calculate implicit stride
+    uint64_t implicit_stride = utils::RoundUp<uint64_t>(el_align, el_size);
+
+    uint64_t stride = explicit_stride ? explicit_stride : implicit_stride;
+
+    // Evaluate the constant array size expression.
+    // sem::Array uses a size of 0 for a runtime-sized array.
+    uint32_t count = 0;
+    if (auto* count_expr = arr->count) {
+        auto* count_sem = Expression(count_expr);
+        if (!count_sem) {
+            return nullptr;
+        }
+
+        auto size_source = count_expr->source;
+
+        auto* ty = count_sem->Type()->UnwrapRef();
+        if (!ty->is_integer_scalar()) {
+            AddError("array size must be integer scalar", size_source);
+            return nullptr;
+        }
+
+        if (auto* ident = count_expr->As<ast::IdentifierExpression>()) {
+            // Make sure the identifier is a non-overridable module-scope constant.
+            auto* var = sem_.ResolvedSymbol<sem::GlobalVariable>(ident);
+            if (!var || !var->Declaration()->is_const) {
+                AddError("array size identifier must be a module-scope constant", size_source);
+                return nullptr;
+            }
+            if (var->IsOverridable()) {
+                AddError("array size expression must not be pipeline-overridable", size_source);
+                return nullptr;
+            }
+
+            count_expr = var->Declaration()->constructor;
+        } else if (!count_expr->Is<ast::LiteralExpression>()) {
+            AddError(
+                "array size expression must be either a literal or a module-scope "
+                "constant",
+                size_source);
+            return nullptr;
+        }
+
+        auto count_val = count_sem->ConstantValue();
+        if (!count_val) {
+            TINT_ICE(Resolver, diagnostics_) << "could not resolve array size expression";
+            return nullptr;
+        }
+
+        if (ty->is_signed_integer_scalar() ? count_val.Elements()[0].i32 < 1
+                                           : count_val.Elements()[0].u32 < 1u) {
+            AddError("array size must be at least 1", size_source);
+            return nullptr;
+        }
+
+        count = count_val.Elements()[0].u32;
     }
 
-    count = count_val.Elements()[0].u32;
-  }
-
-  auto size = std::max<uint64_t>(count, 1) * stride;
-  if (size > std::numeric_limits<uint32_t>::max()) {
-    std::stringstream msg;
-    msg << "array size in bytes must not exceed 0x" << std::hex
-        << std::numeric_limits<uint32_t>::max() << ", but is 0x" << std::hex
-        << size;
-    AddError(msg.str(), arr->source);
-    return nullptr;
-  }
-  if (stride > std::numeric_limits<uint32_t>::max() ||
-      implicit_stride > std::numeric_limits<uint32_t>::max()) {
-    TINT_ICE(Resolver, diagnostics_)
-        << "calculated array stride exceeds uint32";
-    return nullptr;
-  }
-  auto* out = builder_->create<sem::Array>(
-      elem_type, count, el_align, static_cast<uint32_t>(size),
-      static_cast<uint32_t>(stride), static_cast<uint32_t>(implicit_stride));
-
-  if (!ValidateArray(out, source)) {
-    return nullptr;
-  }
-
-  if (elem_type->Is<sem::Atomic>()) {
-    atomic_composite_info_.emplace(out, arr->type->source);
-  } else {
-    auto found = atomic_composite_info_.find(elem_type);
-    if (found != atomic_composite_info_.end()) {
-      atomic_composite_info_.emplace(out, found->second);
+    auto size = std::max<uint64_t>(count, 1) * stride;
+    if (size > std::numeric_limits<uint32_t>::max()) {
+        std::stringstream msg;
+        msg << "array size in bytes must not exceed 0x" << std::hex
+            << std::numeric_limits<uint32_t>::max() << ", but is 0x" << std::hex << size;
+        AddError(msg.str(), arr->source);
+        return nullptr;
     }
-  }
+    if (stride > std::numeric_limits<uint32_t>::max() ||
+        implicit_stride > std::numeric_limits<uint32_t>::max()) {
+        TINT_ICE(Resolver, diagnostics_) << "calculated array stride exceeds uint32";
+        return nullptr;
+    }
+    auto* out = builder_->create<sem::Array>(
+        elem_type, count, el_align, static_cast<uint32_t>(size), static_cast<uint32_t>(stride),
+        static_cast<uint32_t>(implicit_stride));
 
-  return out;
+    if (!validator_.Array(out, source)) {
+        return nullptr;
+    }
+
+    if (elem_type->Is<sem::Atomic>()) {
+        atomic_composite_info_.emplace(out, arr->type->source);
+    } else {
+        auto found = atomic_composite_info_.find(elem_type);
+        if (found != atomic_composite_info_.end()) {
+            atomic_composite_info_.emplace(out, found->second);
+        }
+    }
+
+    return out;
 }
 
 sem::Type* Resolver::Alias(const ast::Alias* alias) {
-  auto* ty = Type(alias->type);
-  if (!ty) {
-    return nullptr;
-  }
-  if (!ValidateAlias(alias)) {
-    return nullptr;
-  }
-  return ty;
+    auto* ty = Type(alias->type);
+    if (!ty) {
+        return nullptr;
+    }
+    if (!validator_.Alias(alias)) {
+        return nullptr;
+    }
+    return ty;
 }
 
 sem::Struct* Resolver::Structure(const ast::Struct* str) {
-  if (!ValidateNoDuplicateAttributes(str->attributes)) {
-    return nullptr;
-  }
-  for (auto* attr : str->attributes) {
-    Mark(attr);
-  }
-
-  sem::StructMemberList sem_members;
-  sem_members.reserve(str->members.size());
-
-  // Calculate the effective size and alignment of each field, and the overall
-  // size of the structure.
-  // For size, use the size attribute if provided, otherwise use the default
-  // size for the type.
-  // For alignment, use the alignment attribute if provided, otherwise use the
-  // default alignment for the member type.
-  // Diagnostic errors are raised if a basic rule is violated.
-  // Validation of storage-class rules requires analysing the actual variable
-  // usage of the structure, and so is performed as part of the variable
-  // validation.
-  uint64_t struct_size = 0;
-  uint64_t struct_align = 1;
-  std::unordered_map<Symbol, const ast::StructMember*> member_map;
-
-  for (auto* member : str->members) {
-    Mark(member);
-    auto result = member_map.emplace(member->symbol, member);
-    if (!result.second) {
-      AddError("redefinition of '" +
-                   builder_->Symbols().NameFor(member->symbol) + "'",
-               member->source);
-      AddNote("previous definition is here", result.first->second->source);
-      return nullptr;
+    if (!validator_.NoDuplicateAttributes(str->attributes)) {
+        return nullptr;
+    }
+    for (auto* attr : str->attributes) {
+        Mark(attr);
     }
 
-    // Resolve member type
-    auto* type = Type(member->type);
-    if (!type) {
-      return nullptr;
-    }
+    sem::StructMemberList sem_members;
+    sem_members.reserve(str->members.size());
 
-    // Validate member type
-    if (!IsPlain(type)) {
-      AddError(sem_.TypeNameOf(type) +
-                   " cannot be used as the type of a structure member",
-               member->source);
-      return nullptr;
-    }
+    // Calculate the effective size and alignment of each field, and the overall
+    // size of the structure.
+    // For size, use the size attribute if provided, otherwise use the default
+    // size for the type.
+    // For alignment, use the alignment attribute if provided, otherwise use the
+    // default alignment for the member type.
+    // Diagnostic errors are raised if a basic rule is violated.
+    // Validation of storage-class rules requires analysing the actual variable
+    // usage of the structure, and so is performed as part of the variable
+    // validation.
+    uint64_t struct_size = 0;
+    uint64_t struct_align = 1;
+    std::unordered_map<Symbol, const ast::StructMember*> member_map;
 
-    uint64_t offset = struct_size;
-    uint64_t align = type->Align();
-    uint64_t size = type->Size();
-
-    if (!ValidateNoDuplicateAttributes(member->attributes)) {
-      return nullptr;
-    }
-
-    bool has_offset_attr = false;
-    bool has_align_attr = false;
-    bool has_size_attr = false;
-    for (auto* attr : member->attributes) {
-      Mark(attr);
-      if (auto* o = attr->As<ast::StructMemberOffsetAttribute>()) {
-        // Offset attributes are not part of the WGSL spec, but are emitted
-        // by the SPIR-V reader.
-        if (o->offset < struct_size) {
-          AddError("offsets must be in ascending order", o->source);
-          return nullptr;
+    for (auto* member : str->members) {
+        Mark(member);
+        auto result = member_map.emplace(member->symbol, member);
+        if (!result.second) {
+            AddError("redefinition of '" + builder_->Symbols().NameFor(member->symbol) + "'",
+                     member->source);
+            AddNote("previous definition is here", result.first->second->source);
+            return nullptr;
         }
-        offset = o->offset;
-        align = 1;
-        has_offset_attr = true;
-      } else if (auto* a = attr->As<ast::StructMemberAlignAttribute>()) {
-        if (a->align <= 0 || !utils::IsPowerOfTwo(a->align)) {
-          AddError("align value must be a positive, power-of-two integer",
-                   a->source);
-          return nullptr;
+
+        // Resolve member type
+        auto* type = Type(member->type);
+        if (!type) {
+            return nullptr;
         }
-        align = a->align;
-        has_align_attr = true;
-      } else if (auto* s = attr->As<ast::StructMemberSizeAttribute>()) {
-        if (s->size < size) {
-          AddError("size must be at least as big as the type's size (" +
-                       std::to_string(size) + ")",
-                   s->source);
-          return nullptr;
+
+        // validator_.Validate member type
+        if (!validator_.IsPlain(type)) {
+            AddError(sem_.TypeNameOf(type) + " cannot be used as the type of a structure member",
+                     member->source);
+            return nullptr;
         }
-        size = s->size;
-        has_size_attr = true;
-      }
+
+        uint64_t offset = struct_size;
+        uint64_t align = type->Align();
+        uint64_t size = type->Size();
+
+        if (!validator_.NoDuplicateAttributes(member->attributes)) {
+            return nullptr;
+        }
+
+        bool has_offset_attr = false;
+        bool has_align_attr = false;
+        bool has_size_attr = false;
+        for (auto* attr : member->attributes) {
+            Mark(attr);
+            if (auto* o = attr->As<ast::StructMemberOffsetAttribute>()) {
+                // Offset attributes are not part of the WGSL spec, but are emitted
+                // by the SPIR-V reader.
+                if (o->offset < struct_size) {
+                    AddError("offsets must be in ascending order", o->source);
+                    return nullptr;
+                }
+                offset = o->offset;
+                align = 1;
+                has_offset_attr = true;
+            } else if (auto* a = attr->As<ast::StructMemberAlignAttribute>()) {
+                if (a->align <= 0 || !utils::IsPowerOfTwo(a->align)) {
+                    AddError("align value must be a positive, power-of-two integer", a->source);
+                    return nullptr;
+                }
+                align = a->align;
+                has_align_attr = true;
+            } else if (auto* s = attr->As<ast::StructMemberSizeAttribute>()) {
+                if (s->size < size) {
+                    AddError("size must be at least as big as the type's size (" +
+                                 std::to_string(size) + ")",
+                             s->source);
+                    return nullptr;
+                }
+                size = s->size;
+                has_size_attr = true;
+            }
+        }
+
+        if (has_offset_attr && (has_align_attr || has_size_attr)) {
+            AddError("offset attributes cannot be used with align or size attributes",
+                     member->source);
+            return nullptr;
+        }
+
+        offset = utils::RoundUp(align, offset);
+        if (offset > std::numeric_limits<uint32_t>::max()) {
+            std::stringstream msg;
+            msg << "struct member has byte offset 0x" << std::hex << offset
+                << ", but must not exceed 0x" << std::hex << std::numeric_limits<uint32_t>::max();
+            AddError(msg.str(), member->source);
+            return nullptr;
+        }
+
+        auto* sem_member = builder_->create<sem::StructMember>(
+            member, member->symbol, type, static_cast<uint32_t>(sem_members.size()),
+            static_cast<uint32_t>(offset), static_cast<uint32_t>(align),
+            static_cast<uint32_t>(size));
+        builder_->Sem().Add(member, sem_member);
+        sem_members.emplace_back(sem_member);
+
+        struct_size = offset + size;
+        struct_align = std::max(struct_align, align);
     }
 
-    if (has_offset_attr && (has_align_attr || has_size_attr)) {
-      AddError("offset attributes cannot be used with align or size attributes",
-               member->source);
-      return nullptr;
+    uint64_t size_no_padding = struct_size;
+    struct_size = utils::RoundUp(struct_align, struct_size);
+
+    if (struct_size > std::numeric_limits<uint32_t>::max()) {
+        std::stringstream msg;
+        msg << "struct size in bytes must not exceed 0x" << std::hex
+            << std::numeric_limits<uint32_t>::max() << ", but is 0x" << std::hex << struct_size;
+        AddError(msg.str(), str->source);
+        return nullptr;
+    }
+    if (struct_align > std::numeric_limits<uint32_t>::max()) {
+        TINT_ICE(Resolver, diagnostics_) << "calculated struct stride exceeds uint32";
+        return nullptr;
     }
 
-    offset = utils::RoundUp(align, offset);
-    if (offset > std::numeric_limits<uint32_t>::max()) {
-      std::stringstream msg;
-      msg << "struct member has byte offset 0x" << std::hex << offset
-          << ", but must not exceed 0x" << std::hex
-          << std::numeric_limits<uint32_t>::max();
-      AddError(msg.str(), member->source);
-      return nullptr;
+    auto* out = builder_->create<sem::Struct>(
+        str, str->name, sem_members, static_cast<uint32_t>(struct_align),
+        static_cast<uint32_t>(struct_size), static_cast<uint32_t>(size_no_padding));
+
+    for (size_t i = 0; i < sem_members.size(); i++) {
+        auto* mem_type = sem_members[i]->Type();
+        if (mem_type->Is<sem::Atomic>()) {
+            atomic_composite_info_.emplace(out, sem_members[i]->Declaration()->source);
+            break;
+        } else {
+            auto found = atomic_composite_info_.find(mem_type);
+            if (found != atomic_composite_info_.end()) {
+                atomic_composite_info_.emplace(out, found->second);
+                break;
+            }
+        }
     }
 
-    auto* sem_member = builder_->create<sem::StructMember>(
-        member, member->symbol, type, static_cast<uint32_t>(sem_members.size()),
-        static_cast<uint32_t>(offset), static_cast<uint32_t>(align),
-        static_cast<uint32_t>(size));
-    builder_->Sem().Add(member, sem_member);
-    sem_members.emplace_back(sem_member);
-
-    struct_size = offset + size;
-    struct_align = std::max(struct_align, align);
-  }
-
-  uint64_t size_no_padding = struct_size;
-  struct_size = utils::RoundUp(struct_align, struct_size);
-
-  if (struct_size > std::numeric_limits<uint32_t>::max()) {
-    std::stringstream msg;
-    msg << "struct size in bytes must not exceed 0x" << std::hex
-        << std::numeric_limits<uint32_t>::max() << ", but is 0x" << std::hex
-        << struct_size;
-    AddError(msg.str(), str->source);
-    return nullptr;
-  }
-  if (struct_align > std::numeric_limits<uint32_t>::max()) {
-    TINT_ICE(Resolver, diagnostics_)
-        << "calculated struct stride exceeds uint32";
-    return nullptr;
-  }
-
-  auto* out = builder_->create<sem::Struct>(
-      str, str->name, sem_members, static_cast<uint32_t>(struct_align),
-      static_cast<uint32_t>(struct_size),
-      static_cast<uint32_t>(size_no_padding));
-
-  for (size_t i = 0; i < sem_members.size(); i++) {
-    auto* mem_type = sem_members[i]->Type();
-    if (mem_type->Is<sem::Atomic>()) {
-      atomic_composite_info_.emplace(out,
-                                     sem_members[i]->Declaration()->source);
-      break;
-    } else {
-      auto found = atomic_composite_info_.find(mem_type);
-      if (found != atomic_composite_info_.end()) {
-        atomic_composite_info_.emplace(out, found->second);
-        break;
-      }
+    auto stage = current_function_ ? current_function_->Declaration()->PipelineStage()
+                                   : ast::PipelineStage::kNone;
+    if (!validator_.Structure(out, stage)) {
+        return nullptr;
     }
-  }
 
-  auto stage = current_function_
-                   ? current_function_->Declaration()->PipelineStage()
-                   : ast::PipelineStage::kNone;
-  if (!ValidateStructure(out, stage)) {
-    return nullptr;
-  }
-
-  return out;
+    return out;
 }
 
 sem::Statement* Resolver::ReturnStatement(const ast::ReturnStatement* stmt) {
-  auto* sem = builder_->create<sem::Statement>(
-      stmt, current_compound_statement_, current_function_);
-  return StatementScope(stmt, sem, [&] {
-    auto& behaviors = current_statement_->Behaviors();
-    behaviors = sem::Behavior::kReturn;
+    auto* sem =
+        builder_->create<sem::Statement>(stmt, current_compound_statement_, current_function_);
+    return StatementScope(stmt, sem, [&] {
+        auto& behaviors = current_statement_->Behaviors();
+        behaviors = sem::Behavior::kReturn;
 
-    if (auto* value = stmt->value) {
-      auto* expr = Expression(value);
-      if (!expr) {
-        return false;
-      }
-      behaviors.Add(expr->Behaviors() - sem::Behavior::kNext);
-    }
+        if (auto* value = stmt->value) {
+            auto* expr = Expression(value);
+            if (!expr) {
+                return false;
+            }
+            behaviors.Add(expr->Behaviors() - sem::Behavior::kNext);
+        }
 
-    // Validate after processing the return value expression so that its type
-    // is available for validation.
-    auto* ret_type = stmt->value ? sem_.TypeOf(stmt->value)->UnwrapRef()
-                                 : builder_->create<sem::Void>();
-    return ValidateReturn(stmt, current_function_->ReturnType(), ret_type);
-  });
+        // Validate after processing the return value expression so that its type
+        // is available for validation.
+        auto* ret_type =
+            stmt->value ? sem_.TypeOf(stmt->value)->UnwrapRef() : builder_->create<sem::Void>();
+        return validator_.Return(stmt, current_function_->ReturnType(), ret_type,
+                                 current_statement_);
+    });
 }
 
-sem::SwitchStatement* Resolver::SwitchStatement(
-    const ast::SwitchStatement* stmt) {
-  auto* sem = builder_->create<sem::SwitchStatement>(
-      stmt, current_compound_statement_, current_function_);
-  return StatementScope(stmt, sem, [&] {
-    auto& behaviors = sem->Behaviors();
+sem::SwitchStatement* Resolver::SwitchStatement(const ast::SwitchStatement* stmt) {
+    auto* sem = builder_->create<sem::SwitchStatement>(stmt, current_compound_statement_,
+                                                       current_function_);
+    return StatementScope(stmt, sem, [&] {
+        auto& behaviors = sem->Behaviors();
 
-    auto* cond = Expression(stmt->condition);
-    if (!cond) {
-      return false;
-    }
-    behaviors = cond->Behaviors() - sem::Behavior::kNext;
+        auto* cond = Expression(stmt->condition);
+        if (!cond) {
+            return false;
+        }
+        behaviors = cond->Behaviors() - sem::Behavior::kNext;
 
-    for (auto* case_stmt : stmt->body) {
-      Mark(case_stmt);
-      auto* c = CaseStatement(case_stmt);
-      if (!c) {
-        return false;
-      }
-      behaviors.Add(c->Behaviors());
-    }
+        for (auto* case_stmt : stmt->body) {
+            Mark(case_stmt);
+            auto* c = CaseStatement(case_stmt);
+            if (!c) {
+                return false;
+            }
+            behaviors.Add(c->Behaviors());
+        }
 
-    if (behaviors.Contains(sem::Behavior::kBreak)) {
-      behaviors.Add(sem::Behavior::kNext);
-    }
-    behaviors.Remove(sem::Behavior::kBreak, sem::Behavior::kFallthrough);
+        if (behaviors.Contains(sem::Behavior::kBreak)) {
+            behaviors.Add(sem::Behavior::kNext);
+        }
+        behaviors.Remove(sem::Behavior::kBreak, sem::Behavior::kFallthrough);
 
-    return ValidateSwitch(stmt);
-  });
+        return validator_.SwitchStatement(stmt);
+    });
 }
 
-sem::Statement* Resolver::VariableDeclStatement(
-    const ast::VariableDeclStatement* stmt) {
-  auto* sem = builder_->create<sem::Statement>(
-      stmt, current_compound_statement_, current_function_);
-  return StatementScope(stmt, sem, [&] {
-    Mark(stmt->variable);
+sem::Statement* Resolver::VariableDeclStatement(const ast::VariableDeclStatement* stmt) {
+    auto* sem =
+        builder_->create<sem::Statement>(stmt, current_compound_statement_, current_function_);
+    return StatementScope(stmt, sem, [&] {
+        Mark(stmt->variable);
 
-    auto* var = Variable(stmt->variable, VariableKind::kLocal);
-    if (!var) {
-      return false;
-    }
+        auto* var = Variable(stmt->variable, VariableKind::kLocal);
+        if (!var) {
+            return false;
+        }
 
-    for (auto* attr : stmt->variable->attributes) {
-      Mark(attr);
-      if (!attr->Is<ast::InternalAttribute>()) {
-        AddError("attributes are not valid on local variables", attr->source);
-        return false;
-      }
-    }
+        for (auto* attr : stmt->variable->attributes) {
+            Mark(attr);
+            if (!attr->Is<ast::InternalAttribute>()) {
+                AddError("attributes are not valid on local variables", attr->source);
+                return false;
+            }
+        }
 
-    if (current_block_) {  // Not all statements are inside a block
-      current_block_->AddDecl(stmt->variable);
-    }
+        if (current_block_) {  // Not all statements are inside a block
+            current_block_->AddDecl(stmt->variable);
+        }
 
-    if (auto* ctor = var->Constructor()) {
-      sem->Behaviors() = ctor->Behaviors();
-    }
+        if (auto* ctor = var->Constructor()) {
+            sem->Behaviors() = ctor->Behaviors();
+        }
 
-    return ValidateVariable(var);
-  });
+        return validator_.Variable(var);
+    });
 }
 
-sem::Statement* Resolver::AssignmentStatement(
-    const ast::AssignmentStatement* stmt) {
-  auto* sem = builder_->create<sem::Statement>(
-      stmt, current_compound_statement_, current_function_);
-  return StatementScope(stmt, sem, [&] {
-    auto* lhs = Expression(stmt->lhs);
-    if (!lhs) {
-      return false;
-    }
+sem::Statement* Resolver::AssignmentStatement(const ast::AssignmentStatement* stmt) {
+    auto* sem =
+        builder_->create<sem::Statement>(stmt, current_compound_statement_, current_function_);
+    return StatementScope(stmt, sem, [&] {
+        auto* lhs = Expression(stmt->lhs);
+        if (!lhs) {
+            return false;
+        }
 
-    auto* rhs = Expression(stmt->rhs);
-    if (!rhs) {
-      return false;
-    }
+        auto* rhs = Expression(stmt->rhs);
+        if (!rhs) {
+            return false;
+        }
 
-    auto& behaviors = sem->Behaviors();
-    behaviors = rhs->Behaviors();
-    if (!stmt->lhs->Is<ast::PhonyExpression>()) {
-      behaviors.Add(lhs->Behaviors());
-    }
+        auto& behaviors = sem->Behaviors();
+        behaviors = rhs->Behaviors();
+        if (!stmt->lhs->Is<ast::PhonyExpression>()) {
+            behaviors.Add(lhs->Behaviors());
+        }
 
-    return ValidateAssignment(stmt, sem_.TypeOf(stmt->rhs));
-  });
+        return validator_.Assignment(stmt, sem_.TypeOf(stmt->rhs));
+    });
 }
 
 sem::Statement* Resolver::BreakStatement(const ast::BreakStatement* stmt) {
-  auto* sem = builder_->create<sem::Statement>(
-      stmt, current_compound_statement_, current_function_);
-  return StatementScope(stmt, sem, [&] {
-    sem->Behaviors() = sem::Behavior::kBreak;
+    auto* sem =
+        builder_->create<sem::Statement>(stmt, current_compound_statement_, current_function_);
+    return StatementScope(stmt, sem, [&] {
+        sem->Behaviors() = sem::Behavior::kBreak;
 
-    return ValidateBreakStatement(sem);
-  });
+        return validator_.BreakStatement(sem, current_statement_);
+    });
 }
 
 sem::Statement* Resolver::CallStatement(const ast::CallStatement* stmt) {
-  auto* sem = builder_->create<sem::Statement>(
-      stmt, current_compound_statement_, current_function_);
-  return StatementScope(stmt, sem, [&] {
-    if (auto* expr = Expression(stmt->expr)) {
-      sem->Behaviors() = expr->Behaviors();
-      return true;
-    }
-    return false;
-  });
+    auto* sem =
+        builder_->create<sem::Statement>(stmt, current_compound_statement_, current_function_);
+    return StatementScope(stmt, sem, [&] {
+        if (auto* expr = Expression(stmt->expr)) {
+            sem->Behaviors() = expr->Behaviors();
+            return true;
+        }
+        return false;
+    });
 }
 
 sem::Statement* Resolver::CompoundAssignmentStatement(
     const ast::CompoundAssignmentStatement* stmt) {
-  auto* sem = builder_->create<sem::Statement>(
-      stmt, current_compound_statement_, current_function_);
-  return StatementScope(stmt, sem, [&] {
-    auto* lhs = Expression(stmt->lhs);
-    if (!lhs) {
-      return false;
-    }
+    auto* sem =
+        builder_->create<sem::Statement>(stmt, current_compound_statement_, current_function_);
+    return StatementScope(stmt, sem, [&] {
+        auto* lhs = Expression(stmt->lhs);
+        if (!lhs) {
+            return false;
+        }
 
-    auto* rhs = Expression(stmt->rhs);
-    if (!rhs) {
-      return false;
-    }
+        auto* rhs = Expression(stmt->rhs);
+        if (!rhs) {
+            return false;
+        }
 
-    sem->Behaviors() = rhs->Behaviors() + lhs->Behaviors();
+        sem->Behaviors() = rhs->Behaviors() + lhs->Behaviors();
 
-    auto* lhs_ty = lhs->Type()->UnwrapRef();
-    auto* rhs_ty = rhs->Type()->UnwrapRef();
-    auto* ty = BinaryOpType(lhs_ty, rhs_ty, stmt->op);
-    if (!ty) {
-      AddError("compound assignment operand types are invalid: " +
-                   sem_.TypeNameOf(lhs_ty) + " " + FriendlyName(stmt->op) +
-                   " " + sem_.TypeNameOf(rhs_ty),
-               stmt->source);
-      return false;
-    }
-    return ValidateAssignment(stmt, ty);
-  });
+        auto* lhs_ty = lhs->Type()->UnwrapRef();
+        auto* rhs_ty = rhs->Type()->UnwrapRef();
+        auto* ty = BinaryOpType(lhs_ty, rhs_ty, stmt->op);
+        if (!ty) {
+            AddError("compound assignment operand types are invalid: " + sem_.TypeNameOf(lhs_ty) +
+                         " " + FriendlyName(stmt->op) + " " + sem_.TypeNameOf(rhs_ty),
+                     stmt->source);
+            return false;
+        }
+        return validator_.Assignment(stmt, ty);
+    });
 }
 
-sem::Statement* Resolver::ContinueStatement(
-    const ast::ContinueStatement* stmt) {
-  auto* sem = builder_->create<sem::Statement>(
-      stmt, current_compound_statement_, current_function_);
-  return StatementScope(stmt, sem, [&] {
-    sem->Behaviors() = sem::Behavior::kContinue;
+sem::Statement* Resolver::ContinueStatement(const ast::ContinueStatement* stmt) {
+    auto* sem =
+        builder_->create<sem::Statement>(stmt, current_compound_statement_, current_function_);
+    return StatementScope(stmt, sem, [&] {
+        sem->Behaviors() = sem::Behavior::kContinue;
 
-    // Set if we've hit the first continue statement in our parent loop
-    if (auto* block = sem->FindFirstParent<sem::LoopBlockStatement>()) {
-      if (!block->FirstContinue()) {
-        const_cast<sem::LoopBlockStatement*>(block)->SetFirstContinue(
-            stmt, block->Decls().size());
-      }
-    }
+        // Set if we've hit the first continue statement in our parent loop
+        if (auto* block = sem->FindFirstParent<sem::LoopBlockStatement>()) {
+            if (!block->FirstContinue()) {
+                const_cast<sem::LoopBlockStatement*>(block)->SetFirstContinue(
+                    stmt, block->Decls().size());
+            }
+        }
 
-    return ValidateContinueStatement(sem);
-  });
+        return validator_.ContinueStatement(sem, current_statement_);
+    });
 }
 
 sem::Statement* Resolver::DiscardStatement(const ast::DiscardStatement* stmt) {
-  auto* sem = builder_->create<sem::Statement>(
-      stmt, current_compound_statement_, current_function_);
-  return StatementScope(stmt, sem, [&] {
-    sem->Behaviors() = sem::Behavior::kDiscard;
-    current_function_->SetHasDiscard();
+    auto* sem =
+        builder_->create<sem::Statement>(stmt, current_compound_statement_, current_function_);
+    return StatementScope(stmt, sem, [&] {
+        sem->Behaviors() = sem::Behavior::kDiscard;
+        current_function_->SetHasDiscard();
 
-    return ValidateDiscardStatement(sem);
-  });
+        return validator_.DiscardStatement(sem, current_statement_);
+    });
 }
 
-sem::Statement* Resolver::FallthroughStatement(
-    const ast::FallthroughStatement* stmt) {
-  auto* sem = builder_->create<sem::Statement>(
-      stmt, current_compound_statement_, current_function_);
-  return StatementScope(stmt, sem, [&] {
-    sem->Behaviors() = sem::Behavior::kFallthrough;
+sem::Statement* Resolver::FallthroughStatement(const ast::FallthroughStatement* stmt) {
+    auto* sem =
+        builder_->create<sem::Statement>(stmt, current_compound_statement_, current_function_);
+    return StatementScope(stmt, sem, [&] {
+        sem->Behaviors() = sem::Behavior::kFallthrough;
 
-    return ValidateFallthroughStatement(sem);
-  });
+        return validator_.FallthroughStatement(sem);
+    });
 }
 
 sem::Statement* Resolver::IncrementDecrementStatement(
     const ast::IncrementDecrementStatement* stmt) {
-  auto* sem = builder_->create<sem::Statement>(
-      stmt, current_compound_statement_, current_function_);
-  return StatementScope(stmt, sem, [&] {
-    auto* lhs = Expression(stmt->lhs);
-    if (!lhs) {
-      return false;
-    }
-    sem->Behaviors() = lhs->Behaviors();
+    auto* sem =
+        builder_->create<sem::Statement>(stmt, current_compound_statement_, current_function_);
+    return StatementScope(stmt, sem, [&] {
+        auto* lhs = Expression(stmt->lhs);
+        if (!lhs) {
+            return false;
+        }
+        sem->Behaviors() = lhs->Behaviors();
 
-    return ValidateIncrementDecrementStatement(stmt);
-  });
+        return validator_.IncrementDecrementStatement(stmt);
+    });
 }
 
 bool Resolver::ApplyStorageClassUsageToType(ast::StorageClass sc,
                                             sem::Type* ty,
                                             const Source& usage) {
-  ty = const_cast<sem::Type*>(ty->UnwrapRef());
+    ty = const_cast<sem::Type*>(ty->UnwrapRef());
 
-  if (auto* str = ty->As<sem::Struct>()) {
-    if (str->StorageClassUsage().count(sc)) {
-      return true;  // Already applied
+    if (auto* str = ty->As<sem::Struct>()) {
+        if (str->StorageClassUsage().count(sc)) {
+            return true;  // Already applied
+        }
+
+        str->AddUsage(sc);
+
+        for (auto* member : str->Members()) {
+            if (!ApplyStorageClassUsageToType(sc, member->Type(), usage)) {
+                std::stringstream err;
+                err << "while analysing structure member " << sem_.TypeNameOf(str) << "."
+                    << builder_->Symbols().NameFor(member->Declaration()->symbol);
+                AddNote(err.str(), member->Declaration()->source);
+                return false;
+            }
+        }
+        return true;
     }
 
-    str->AddUsage(sc);
+    if (auto* arr = ty->As<sem::Array>()) {
+        if (arr->IsRuntimeSized() && sc != ast::StorageClass::kStorage) {
+            AddError(
+                "runtime-sized arrays can only be used in the <storage> storage "
+                "class",
+                usage);
+            return false;
+        }
 
-    for (auto* member : str->Members()) {
-      if (!ApplyStorageClassUsageToType(sc, member->Type(), usage)) {
+        return ApplyStorageClassUsageToType(sc, const_cast<sem::Type*>(arr->ElemType()), usage);
+    }
+
+    if (ast::IsHostShareable(sc) && !validator_.IsHostShareable(ty)) {
         std::stringstream err;
-        err << "while analysing structure member " << sem_.TypeNameOf(str)
-            << "."
-            << builder_->Symbols().NameFor(member->Declaration()->symbol);
-        AddNote(err.str(), member->Declaration()->source);
+        err << "Type '" << sem_.TypeNameOf(ty) << "' cannot be used in storage class '" << sc
+            << "' as it is non-host-shareable";
+        AddError(err.str(), usage);
         return false;
-      }
     }
+
     return true;
-  }
-
-  if (auto* arr = ty->As<sem::Array>()) {
-    if (arr->IsRuntimeSized() && sc != ast::StorageClass::kStorage) {
-      AddError(
-          "runtime-sized arrays can only be used in the <storage> storage "
-          "class",
-          usage);
-      return false;
-    }
-
-    return ApplyStorageClassUsageToType(
-        sc, const_cast<sem::Type*>(arr->ElemType()), usage);
-  }
-
-  if (ast::IsHostShareable(sc) && !IsHostShareable(ty)) {
-    std::stringstream err;
-    err << "Type '" << sem_.TypeNameOf(ty)
-        << "' cannot be used in storage class '" << sc
-        << "' as it is non-host-shareable";
-    AddError(err.str(), usage);
-    return false;
-  }
-
-  return true;
 }
 
 template <typename SEM, typename F>
-SEM* Resolver::StatementScope(const ast::Statement* ast,
-                              SEM* sem,
-                              F&& callback) {
-  builder_->Sem().Add(ast, sem);
+SEM* Resolver::StatementScope(const ast::Statement* ast, SEM* sem, F&& callback) {
+    builder_->Sem().Add(ast, sem);
 
-  auto* as_compound =
-      As<sem::CompoundStatement, CastFlags::kDontErrorOnImpossibleCast>(sem);
-  auto* as_block =
-      As<sem::BlockStatement, CastFlags::kDontErrorOnImpossibleCast>(sem);
+    auto* as_compound = As<sem::CompoundStatement, CastFlags::kDontErrorOnImpossibleCast>(sem);
+    auto* as_block = As<sem::BlockStatement, CastFlags::kDontErrorOnImpossibleCast>(sem);
 
-  TINT_SCOPED_ASSIGNMENT(current_statement_, sem);
-  TINT_SCOPED_ASSIGNMENT(
-      current_compound_statement_,
-      as_compound ? as_compound : current_compound_statement_);
-  TINT_SCOPED_ASSIGNMENT(current_block_, as_block ? as_block : current_block_);
+    TINT_SCOPED_ASSIGNMENT(current_statement_, sem);
+    TINT_SCOPED_ASSIGNMENT(current_compound_statement_,
+                           as_compound ? as_compound : current_compound_statement_);
+    TINT_SCOPED_ASSIGNMENT(current_block_, as_block ? as_block : current_block_);
 
-  if (!callback()) {
-    return nullptr;
-  }
+    if (!callback()) {
+        return nullptr;
+    }
 
-  return sem;
+    return sem;
 }
 
 bool Resolver::Mark(const ast::Node* node) {
-  if (node == nullptr) {
-    TINT_ICE(Resolver, diagnostics_) << "Resolver::Mark() called with nullptr";
+    if (node == nullptr) {
+        TINT_ICE(Resolver, diagnostics_) << "Resolver::Mark() called with nullptr";
+        return false;
+    }
+    if (marked_.emplace(node).second) {
+        return true;
+    }
+    TINT_ICE(Resolver, diagnostics_) << "AST node '" << node->TypeInfo().name
+                                     << "' was encountered twice in the same AST of a Program\n"
+                                     << "At: " << node->source << "\n"
+                                     << "Pointer: " << node;
     return false;
-  }
-  if (marked_.emplace(node).second) {
-    return true;
-  }
-  TINT_ICE(Resolver, diagnostics_)
-      << "AST node '" << node->TypeInfo().name
-      << "' was encountered twice in the same AST of a Program\n"
-      << "At: " << node->source << "\n"
-      << "Pointer: " << node;
-  return false;
 }
 
 void Resolver::AddError(const std::string& msg, const Source& source) const {
-  diagnostics_.add_error(diag::System::Resolver, msg, source);
+    diagnostics_.add_error(diag::System::Resolver, msg, source);
 }
 
 void Resolver::AddWarning(const std::string& msg, const Source& source) const {
-  diagnostics_.add_warning(diag::System::Resolver, msg, source);
+    diagnostics_.add_warning(diag::System::Resolver, msg, source);
 }
 
 void Resolver::AddNote(const std::string& msg, const Source& source) const {
-  diagnostics_.add_note(diag::System::Resolver, msg, source);
-}
-
-// https://gpuweb.github.io/gpuweb/wgsl/#plain-types-section
-bool Resolver::IsPlain(const sem::Type* type) const {
-  return type->is_scalar() ||
-         type->IsAnyOf<sem::Atomic, sem::Vector, sem::Matrix, sem::Array,
-                       sem::Struct>();
-}
-
-// https://gpuweb.github.io/gpuweb/wgsl/#fixed-footprint-types
-bool Resolver::IsFixedFootprint(const sem::Type* type) const {
-  return Switch(
-      type,                                      //
-      [&](const sem::Vector*) { return true; },  //
-      [&](const sem::Matrix*) { return true; },  //
-      [&](const sem::Atomic*) { return true; },
-      [&](const sem::Array* arr) {
-        return !arr->IsRuntimeSized() && IsFixedFootprint(arr->ElemType());
-      },
-      [&](const sem::Struct* str) {
-        for (auto* member : str->Members()) {
-          if (!IsFixedFootprint(member->Type())) {
-            return false;
-          }
-        }
-        return true;
-      },
-      [&](Default) { return type->is_scalar(); });
-}
-
-// https://gpuweb.github.io/gpuweb/wgsl.html#storable-types
-bool Resolver::IsStorable(const sem::Type* type) const {
-  return IsPlain(type) || type->IsAnyOf<sem::Texture, sem::Sampler>();
-}
-
-// https://gpuweb.github.io/gpuweb/wgsl.html#host-shareable-types
-bool Resolver::IsHostShareable(const sem::Type* type) const {
-  if (type->IsAnyOf<sem::I32, sem::U32, sem::F32>()) {
-    return true;
-  }
-  return Switch(
-      type,  //
-      [&](const sem::Vector* vec) { return IsHostShareable(vec->type()); },
-      [&](const sem::Matrix* mat) { return IsHostShareable(mat->type()); },
-      [&](const sem::Array* arr) { return IsHostShareable(arr->ElemType()); },
-      [&](const sem::Struct* str) {
-        for (auto* member : str->Members()) {
-          if (!IsHostShareable(member->Type())) {
-            return false;
-          }
-        }
-        return true;
-      },
-      [&](const sem::Atomic* atomic) {
-        return IsHostShareable(atomic->Type());
-      });
+    diagnostics_.add_note(diag::System::Resolver, msg, source);
 }
 
 bool Resolver::IsBuiltin(Symbol symbol) const {
-  std::string name = builder_->Symbols().NameFor(symbol);
-  return sem::ParseBuiltinType(name) != sem::BuiltinType::kNone;
+    std::string name = builder_->Symbols().NameFor(symbol);
+    return sem::ParseBuiltinType(name) != sem::BuiltinType::kNone;
 }
 
 bool Resolver::IsCallStatement(const ast::Expression* expr) const {
-  return current_statement_ &&
-         Is<ast::CallStatement>(current_statement_->Declaration(),
-                                [&](auto* stmt) { return stmt->expr == expr; });
-}
-
-const ast::Statement* Resolver::ClosestContinuing(bool stop_at_loop) const {
-  for (const auto* s = current_statement_; s != nullptr; s = s->Parent()) {
-    if (stop_at_loop && s->Is<sem::LoopStatement>()) {
-      break;
-    }
-    if (s->Is<sem::LoopContinuingBlockStatement>()) {
-      return s->Declaration();
-    }
-    if (auto* f = As<sem::ForLoopStatement>(s->Parent())) {
-      if (f->Declaration()->continuing == s->Declaration()) {
-        return s->Declaration();
-      }
-      if (stop_at_loop) {
-        break;
-      }
-    }
-  }
-  return nullptr;
+    return current_statement_ &&
+           Is<ast::CallStatement>(current_statement_->Declaration(),
+                                  [&](auto* stmt) { return stmt->expr == expr; });
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // Resolver::TypeConversionSig
 ////////////////////////////////////////////////////////////////////////////////
-bool Resolver::TypeConversionSig::operator==(
-    const TypeConversionSig& rhs) const {
-  return target == rhs.target && source == rhs.source;
+bool Resolver::TypeConversionSig::operator==(const TypeConversionSig& rhs) const {
+    return target == rhs.target && source == rhs.source;
 }
-std::size_t Resolver::TypeConversionSig::Hasher::operator()(
-    const TypeConversionSig& sig) const {
-  return utils::Hash(sig.target, sig.source);
+std::size_t Resolver::TypeConversionSig::Hasher::operator()(const TypeConversionSig& sig) const {
+    return utils::Hash(sig.target, sig.source);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // Resolver::TypeConstructorSig
 ////////////////////////////////////////////////////////////////////////////////
-Resolver::TypeConstructorSig::TypeConstructorSig(
-    const sem::Type* ty,
-    const std::vector<const sem::Type*> params)
+Resolver::TypeConstructorSig::TypeConstructorSig(const sem::Type* ty,
+                                                 const std::vector<const sem::Type*> params)
     : type(ty), parameters(params) {}
-Resolver::TypeConstructorSig::TypeConstructorSig(const TypeConstructorSig&) =
-    default;
+Resolver::TypeConstructorSig::TypeConstructorSig(const TypeConstructorSig&) = default;
 Resolver::TypeConstructorSig::~TypeConstructorSig() = default;
 
-bool Resolver::TypeConstructorSig::operator==(
-    const TypeConstructorSig& rhs) const {
-  return type == rhs.type && parameters == rhs.parameters;
+bool Resolver::TypeConstructorSig::operator==(const TypeConstructorSig& rhs) const {
+    return type == rhs.type && parameters == rhs.parameters;
 }
-std::size_t Resolver::TypeConstructorSig::Hasher::operator()(
-    const TypeConstructorSig& sig) const {
-  return utils::Hash(sig.type, sig.parameters);
+std::size_t Resolver::TypeConstructorSig::Hasher::operator()(const TypeConstructorSig& sig) const {
+    return utils::Hash(sig.type, sig.parameters);
 }
 
 }  // namespace tint::resolver
diff --git a/src/tint/resolver/resolver.h b/src/tint/resolver/resolver.h
index 95dd5ff..f8dec15 100644
--- a/src/tint/resolver/resolver.h
+++ b/src/tint/resolver/resolver.h
@@ -16,7 +16,6 @@
 #define SRC_TINT_RESOLVER_RESOLVER_H_
 
 #include <memory>
-#include <set>
 #include <string>
 #include <unordered_map>
 #include <unordered_set>
@@ -27,13 +26,13 @@
 #include "src/tint/program_builder.h"
 #include "src/tint/resolver/dependency_graph.h"
 #include "src/tint/resolver/sem_helper.h"
+#include "src/tint/resolver/validator.h"
 #include "src/tint/scope_stack.h"
 #include "src/tint/sem/binding_point.h"
 #include "src/tint/sem/block_statement.h"
 #include "src/tint/sem/constant.h"
 #include "src/tint/sem/function.h"
 #include "src/tint/sem/struct.h"
-#include "src/tint/utils/map.h"
 #include "src/tint/utils/unique_vector.h"
 
 // Forward declarations
@@ -60,7 +59,6 @@
 class BlockStatement;
 class Builtin;
 class CaseStatement;
-class ElseStatement;
 class ForLoopStatement;
 class IfStatement;
 class LoopStatement;
@@ -73,461 +71,330 @@
 
 /// Resolves types for all items in the given tint program
 class Resolver {
- public:
-  /// Constructor
-  /// @param builder the program builder
-  explicit Resolver(ProgramBuilder* builder);
+  public:
+    /// Constructor
+    /// @param builder the program builder
+    explicit Resolver(ProgramBuilder* builder);
 
-  /// Destructor
-  ~Resolver();
+    /// Destructor
+    ~Resolver();
 
-  /// @returns error messages from the resolver
-  std::string error() const { return diagnostics_.str(); }
+    /// @returns error messages from the resolver
+    std::string error() const { return diagnostics_.str(); }
 
-  /// @returns true if the resolver was successful
-  bool Resolve();
+    /// @returns true if the resolver was successful
+    bool Resolve();
 
-  /// @param type the given type
-  /// @returns true if the given type is a plain type
-  bool IsPlain(const sem::Type* type) const;
+    /// @param type the given type
+    /// @returns true if the given type is a plain type
+    bool IsPlain(const sem::Type* type) const { return validator_.IsPlain(type); }
 
-  /// @param type the given type
-  /// @returns true if the given type is a fixed-footprint type
-  bool IsFixedFootprint(const sem::Type* type) const;
+    /// @param type the given type
+    /// @returns true if the given type is a fixed-footprint type
+    bool IsFixedFootprint(const sem::Type* type) const { return validator_.IsFixedFootprint(type); }
 
-  /// @param type the given type
-  /// @returns true if the given type is storable
-  bool IsStorable(const sem::Type* type) const;
+    /// @param type the given type
+    /// @returns true if the given type is storable
+    bool IsStorable(const sem::Type* type) const { return validator_.IsStorable(type); }
 
-  /// @param type the given type
-  /// @returns true if the given type is host-shareable
-  bool IsHostShareable(const sem::Type* type) const;
+    /// @param type the given type
+    /// @returns true if the given type is host-shareable
+    bool IsHostShareable(const sem::Type* type) const { return validator_.IsHostShareable(type); }
 
- private:
-  /// Describes the context in which a variable is declared
-  enum class VariableKind { kParameter, kLocal, kGlobal };
+    /// @returns the validator for testing
+    const Validator* GetValidatorForTesting() const { return &validator_; }
 
-  using ValidTypeStorageLayouts =
-      std::set<std::pair<const sem::Type*, ast::StorageClass>>;
-  ValidTypeStorageLayouts valid_type_storage_layouts_;
+  private:
+    /// Describes the context in which a variable is declared
+    enum class VariableKind { kParameter, kLocal, kGlobal };
 
-  /// Structure holding semantic information about a block (i.e. scope), such as
-  /// parent block and variables declared in the block.
-  /// Used to validate variable scoping rules.
-  struct BlockInfo {
-    enum class Type { kGeneric, kLoop, kLoopContinuing, kSwitchCase };
+    Validator::ValidTypeStorageLayouts valid_type_storage_layouts_;
 
-    BlockInfo(const ast::BlockStatement* block, Type type, BlockInfo* parent);
-    ~BlockInfo();
+    /// Structure holding semantic information about a block (i.e. scope), such as
+    /// parent block and variables declared in the block.
+    /// Used to validate variable scoping rules.
+    struct BlockInfo {
+        enum class Type { kGeneric, kLoop, kLoopContinuing, kSwitchCase };
 
-    template <typename Pred>
-    BlockInfo* FindFirstParent(Pred&& pred) {
-      BlockInfo* curr = this;
-      while (curr && !pred(curr)) {
-        curr = curr->parent;
-      }
-      return curr;
-    }
+        BlockInfo(const ast::BlockStatement* block, Type type, BlockInfo* parent);
+        ~BlockInfo();
 
-    BlockInfo* FindFirstParent(BlockInfo::Type ty) {
-      return FindFirstParent(
-          [ty](auto* block_info) { return block_info->type == ty; });
-    }
+        template <typename Pred>
+        BlockInfo* FindFirstParent(Pred&& pred) {
+            BlockInfo* curr = this;
+            while (curr && !pred(curr)) {
+                curr = curr->parent;
+            }
+            return curr;
+        }
 
-    ast::BlockStatement const* const block;
-    const Type type;
-    BlockInfo* const parent;
-    std::vector<const ast::Variable*> decls;
+        BlockInfo* FindFirstParent(BlockInfo::Type ty) {
+            return FindFirstParent([ty](auto* block_info) { return block_info->type == ty; });
+        }
 
-    // first_continue is set to the index of the first variable in decls
-    // declared after the first continue statement in a loop block, if any.
-    constexpr static size_t kNoContinue = size_t(~0);
-    size_t first_continue = kNoContinue;
-  };
+        ast::BlockStatement const* const block;
+        const Type type;
+        BlockInfo* const parent;
+        std::vector<const ast::Variable*> decls;
 
-  // Structure holding information for a TypeDecl
-  struct TypeDeclInfo {
-    ast::TypeDecl const* const ast;
-    sem::Type* const sem;
-  };
-
-  /// Resolves the program, without creating final the semantic nodes.
-  /// @returns true on success, false on error
-  bool ResolveInternal();
-
-  /// Creates the nodes and adds them to the sem::Info mappings of the
-  /// ProgramBuilder.
-  void CreateSemanticNodes() const;
-
-  /// Retrieves information for the requested import.
-  /// @param src the source of the import
-  /// @param path the import path
-  /// @param name the method name to get information on
-  /// @param params the parameters to the method call
-  /// @param id out parameter for the external call ID. Must not be a nullptr.
-  /// @returns the return type of `name` in `path` or nullptr on error.
-  sem::Type* GetImportData(const Source& src,
-                           const std::string& path,
-                           const std::string& name,
-                           const ast::ExpressionList& params,
-                           uint32_t* id);
-
-  //////////////////////////////////////////////////////////////////////////////
-  // AST and Type traversal methods
-  //////////////////////////////////////////////////////////////////////////////
-
-  // Expression resolving methods
-  // Returns the semantic node pointer on success, nullptr on failure.
-  sem::Expression* IndexAccessor(const ast::IndexAccessorExpression*);
-  sem::Expression* Binary(const ast::BinaryExpression*);
-  sem::Expression* Bitcast(const ast::BitcastExpression*);
-  sem::Call* Call(const ast::CallExpression*);
-  sem::Expression* Expression(const ast::Expression*);
-  sem::Function* Function(const ast::Function*);
-  sem::Call* FunctionCall(const ast::CallExpression*,
-                          sem::Function* target,
-                          const std::vector<const sem::Expression*> args,
-                          sem::Behaviors arg_behaviors);
-  sem::Expression* Identifier(const ast::IdentifierExpression*);
-  sem::Call* BuiltinCall(const ast::CallExpression*,
-                         sem::BuiltinType,
-                         const std::vector<const sem::Expression*> args,
-                         const std::vector<const sem::Type*> arg_tys);
-  sem::Expression* Literal(const ast::LiteralExpression*);
-  sem::Expression* MemberAccessor(const ast::MemberAccessorExpression*);
-  sem::Call* TypeConversion(const ast::CallExpression* expr,
-                            const sem::Type* ty,
-                            const sem::Expression* arg,
-                            const sem::Type* arg_ty);
-  sem::Call* TypeConstructor(const ast::CallExpression* expr,
-                             const sem::Type* ty,
-                             const std::vector<const sem::Expression*> args,
-                             const std::vector<const sem::Type*> arg_tys);
-  sem::Expression* UnaryOp(const ast::UnaryOpExpression*);
-
-  // Statement resolving methods
-  // Each return true on success, false on failure.
-  sem::Statement* AssignmentStatement(const ast::AssignmentStatement*);
-  sem::BlockStatement* BlockStatement(const ast::BlockStatement*);
-  sem::Statement* BreakStatement(const ast::BreakStatement*);
-  sem::Statement* CallStatement(const ast::CallStatement*);
-  sem::CaseStatement* CaseStatement(const ast::CaseStatement*);
-  sem::Statement* CompoundAssignmentStatement(
-      const ast::CompoundAssignmentStatement*);
-  sem::Statement* ContinueStatement(const ast::ContinueStatement*);
-  sem::Statement* DiscardStatement(const ast::DiscardStatement*);
-  sem::ElseStatement* ElseStatement(const ast::ElseStatement*);
-  sem::Statement* FallthroughStatement(const ast::FallthroughStatement*);
-  sem::ForLoopStatement* ForLoopStatement(const ast::ForLoopStatement*);
-  sem::GlobalVariable* GlobalVariable(const ast::Variable*);
-  sem::Statement* Parameter(const ast::Variable*);
-  sem::IfStatement* IfStatement(const ast::IfStatement*);
-  sem::Statement* IncrementDecrementStatement(
-      const ast::IncrementDecrementStatement*);
-  sem::LoopStatement* LoopStatement(const ast::LoopStatement*);
-  sem::Statement* ReturnStatement(const ast::ReturnStatement*);
-  sem::Statement* Statement(const ast::Statement*);
-  sem::SwitchStatement* SwitchStatement(const ast::SwitchStatement* s);
-  sem::Statement* VariableDeclStatement(const ast::VariableDeclStatement*);
-  bool Statements(const ast::StatementList&);
-
-  // Resolve the result type of a binary operator.
-  // Returns nullptr if the types are not valid for this operator.
-  const sem::Type* BinaryOpType(const sem::Type* lhs_ty,
-                                const sem::Type* rhs_ty,
-                                ast::BinaryOp op);
-
-  // AST and Type validation methods
-  // Each return true on success, false on failure.
-  bool ValidatePipelineStages() const;
-  bool ValidateAlias(const ast::Alias*) const;
-  bool ValidateArray(const sem::Array* arr, const Source& source) const;
-  bool ValidateArrayStrideAttribute(const ast::StrideAttribute* attr,
-                                    uint32_t el_size,
-                                    uint32_t el_align,
-                                    const Source& source) const;
-  bool ValidateAtomic(const ast::Atomic* a, const sem::Atomic* s) const;
-  bool ValidateAtomicVariable(const sem::Variable* var) const;
-  bool ValidateAssignment(const ast::Statement* a,
-                          const sem::Type* rhs_ty) const;
-  bool ValidateBitcast(const ast::BitcastExpression* cast,
-                       const sem::Type* to) const;
-  bool ValidateBreakStatement(const sem::Statement* stmt) const;
-  bool ValidateBuiltinAttribute(const ast::BuiltinAttribute* attr,
-                                const sem::Type* storage_type,
-                                ast::PipelineStage stage,
-                                const bool is_input) const;
-  bool ValidateContinueStatement(const sem::Statement* stmt) const;
-  bool ValidateDiscardStatement(const sem::Statement* stmt) const;
-  bool ValidateElseStatement(const sem::ElseStatement* stmt) const;
-  bool ValidateEntryPoint(const sem::Function* func,
-                          ast::PipelineStage stage) const;
-  bool ValidateForLoopStatement(const sem::ForLoopStatement* stmt) const;
-  bool ValidateFallthroughStatement(const sem::Statement* stmt) const;
-  bool ValidateFunction(const sem::Function* func,
-                        ast::PipelineStage stage) const;
-  bool ValidateFunctionCall(const sem::Call* call) const;
-  bool ValidateGlobalVariable(const sem::Variable* var) const;
-  bool ValidateIfStatement(const sem::IfStatement* stmt) const;
-  bool ValidateIncrementDecrementStatement(
-      const ast::IncrementDecrementStatement* stmt) const;
-  bool ValidateInterpolateAttribute(const ast::InterpolateAttribute* attr,
-                                    const sem::Type* storage_type) const;
-  bool ValidateBuiltinCall(const sem::Call* call) const;
-  bool ValidateLocationAttribute(const ast::LocationAttribute* location,
-                                 const sem::Type* type,
-                                 std::unordered_set<uint32_t>& locations,
-                                 ast::PipelineStage stage,
-                                 const Source& source,
-                                 const bool is_input = false) const;
-  bool ValidateLoopStatement(const sem::LoopStatement* stmt) const;
-  bool ValidateMatrix(const sem::Matrix* ty, const Source& source) const;
-  bool ValidateFunctionParameter(const ast::Function* func,
-                                 const sem::Variable* var) const;
-  bool ValidateReturn(const ast::ReturnStatement* ret,
-                      const sem::Type* func_type,
-                      const sem::Type* ret_type) const;
-  bool ValidateStatements(const ast::StatementList& stmts) const;
-  bool ValidateStorageTexture(const ast::StorageTexture* t) const;
-  bool ValidateStructure(const sem::Struct* str,
-                         ast::PipelineStage stage) const;
-  bool ValidateStructureConstructorOrCast(const ast::CallExpression* ctor,
-                                          const sem::Struct* struct_type) const;
-  bool ValidateSwitch(const ast::SwitchStatement* s);
-  bool ValidateVariable(const sem::Variable* var) const;
-  bool ValidateVariableConstructorOrCast(const ast::Variable* var,
-                                         ast::StorageClass storage_class,
-                                         const sem::Type* storage_type,
-                                         const sem::Type* rhs_type) const;
-  bool ValidateVector(const sem::Vector* ty, const Source& source) const;
-  bool ValidateVectorConstructorOrCast(const ast::CallExpression* ctor,
-                                       const sem::Vector* vec_type) const;
-  bool ValidateMatrixConstructorOrCast(const ast::CallExpression* ctor,
-                                       const sem::Matrix* matrix_type) const;
-  bool ValidateScalarConstructorOrCast(const ast::CallExpression* ctor,
-                                       const sem::Type* type) const;
-  bool ValidateArrayConstructorOrCast(const ast::CallExpression* ctor,
-                                      const sem::Array* arr_type) const;
-  bool ValidateTextureBuiltinFunction(const sem::Call* call) const;
-  bool ValidateNoDuplicateAttributes(
-      const ast::AttributeList& attributes) const;
-  bool ValidateStorageClassLayout(const sem::Type* type,
-                                  ast::StorageClass sc,
-                                  Source source,
-                                  ValidTypeStorageLayouts& layouts) const;
-  bool ValidateStorageClassLayout(const sem::Variable* var,
-                                  ValidTypeStorageLayouts& layouts) const;
-
-  /// @returns true if the attribute list contains a
-  /// ast::DisableValidationAttribute with the validation mode equal to
-  /// `validation`
-  bool IsValidationDisabled(const ast::AttributeList& attributes,
-                            ast::DisabledValidation validation) const;
-
-  /// @returns true if the attribute list does not contains a
-  /// ast::DisableValidationAttribute with the validation mode equal to
-  /// `validation`
-  bool IsValidationEnabled(const ast::AttributeList& attributes,
-                           ast::DisabledValidation validation) const;
-
-  /// Returns a human-readable string representation of the vector type name
-  /// with the given parameters.
-  /// @param size the vector dimension
-  /// @param element_type scalar vector sub-element type
-  /// @return pretty string representation
-  std::string VectorPretty(uint32_t size, const sem::Type* element_type) const;
-
-  /// Resolves the WorkgroupSize for the given function, assigning it to
-  /// current_function_
-  bool WorkgroupSize(const ast::Function*);
-
-  /// @returns the sem::Type for the ast::Type `ty`, building it if it
-  /// hasn't been constructed already. If an error is raised, nullptr is
-  /// returned.
-  /// @param ty the ast::Type
-  sem::Type* Type(const ast::Type* ty);
-
-  /// @param named_type the named type to resolve
-  /// @returns the resolved semantic type
-  sem::Type* TypeDecl(const ast::TypeDecl* named_type);
-
-  /// Builds and returns the semantic information for the array `arr`.
-  /// This method does not mark the ast::Array node, nor attach the generated
-  /// semantic information to the AST node.
-  /// @returns the semantic Array information, or nullptr if an error is
-  /// raised.
-  /// @param arr the Array to get semantic information for
-  sem::Array* Array(const ast::Array* arr);
-
-  /// Builds and returns the semantic information for the alias `alias`.
-  /// This method does not mark the ast::Alias node, nor attach the generated
-  /// semantic information to the AST node.
-  /// @returns the aliased type, or nullptr if an error is raised.
-  sem::Type* Alias(const ast::Alias* alias);
-
-  /// Builds and returns the semantic information for the structure `str`.
-  /// This method does not mark the ast::Struct node, nor attach the generated
-  /// semantic information to the AST node.
-  /// @returns the semantic Struct information, or nullptr if an error is
-  /// raised.
-  sem::Struct* Structure(const ast::Struct* str);
-
-  /// @returns the semantic info for the variable `var`. If an error is
-  /// raised, nullptr is returned.
-  /// @note this method does not resolve the attributes as these are
-  /// context-dependent (global, local, parameter)
-  /// @param var the variable to create or return the `VariableInfo` for
-  /// @param kind what kind of variable we are declaring
-  /// @param index the index of the parameter, if this variable is a parameter
-  sem::Variable* Variable(const ast::Variable* var,
-                          VariableKind kind,
-                          uint32_t index = 0);
-
-  /// Records the storage class usage for the given type, and any transient
-  /// dependencies of the type. Validates that the type can be used for the
-  /// given storage class, erroring if it cannot.
-  /// @param sc the storage class to apply to the type and transitent types
-  /// @param ty the type to apply the storage class on
-  /// @param usage the Source of the root variable declaration that uses the
-  /// given type and storage class. Used for generating sensible error
-  /// messages.
-  /// @returns true on success, false on error
-  bool ApplyStorageClassUsageToType(ast::StorageClass sc,
-                                    sem::Type* ty,
-                                    const Source& usage);
-
-  /// @param storage_class the storage class
-  /// @returns the default access control for the given storage class
-  ast::Access DefaultAccessForStorageClass(ast::StorageClass storage_class);
-
-  /// Allocate constant IDs for pipeline-overridable constants.
-  void AllocateOverridableConstantIds();
-
-  /// Set the shadowing information on variable declarations.
-  /// @note this method must only be called after all semantic nodes are built.
-  void SetShadows();
-  /// StatementScope() does the following:
-  /// * Creates the AST -> SEM mapping.
-  /// * Assigns `sem` to #current_statement_
-  /// * Assigns `sem` to #current_compound_statement_ if `sem` derives from
-  ///   sem::CompoundStatement.
-  /// * Assigns `sem` to #current_block_ if `sem` derives from
-  ///   sem::BlockStatement.
-  /// * Then calls `callback`.
-  /// * Before returning #current_statement_, #current_compound_statement_, and
-  ///   #current_block_ are restored to their original values.
-  /// @returns `sem` if `callback` returns true, otherwise `nullptr`.
-  template <typename SEM, typename F>
-  SEM* StatementScope(const ast::Statement* ast, SEM* sem, F&& callback);
-
-  /// Mark records that the given AST node has been visited, and asserts that
-  /// the given node has not already been seen. Diamonds in the AST are
-  /// illegal.
-  /// @param node the AST node.
-  /// @returns true on success, false on error
-  bool Mark(const ast::Node* node);
-
-  /// Adds the given error message to the diagnostics
-  void AddError(const std::string& msg, const Source& source) const;
-
-  /// Adds the given warning message to the diagnostics
-  void AddWarning(const std::string& msg, const Source& source) const;
-
-  /// Adds the given note message to the diagnostics
-  void AddNote(const std::string& msg, const Source& source) const;
-
-  //////////////////////////////////////////////////////////////////////////////
-  /// Constant value evaluation methods
-  //////////////////////////////////////////////////////////////////////////////
-  /// Cast `Value` to `target_type`
-  /// @return the casted value
-  sem::Constant ConstantCast(const sem::Constant& value,
-                             const sem::Type* target_elem_type);
-
-  sem::Constant EvaluateConstantValue(const ast::Expression* expr,
-                                      const sem::Type* type);
-  sem::Constant EvaluateConstantValue(const ast::LiteralExpression* literal,
-                                      const sem::Type* type);
-  sem::Constant EvaluateConstantValue(const ast::CallExpression* call,
-                                      const sem::Type* type);
-
-  /// @returns true if the symbol is the name of a builtin function.
-  bool IsBuiltin(Symbol) const;
-
-  /// @returns true if `expr` is the current CallStatement's CallExpression
-  bool IsCallStatement(const ast::Expression* expr) const;
-
-  /// Searches the current statement and up through parents of the current
-  /// statement looking for a loop or for-loop continuing statement.
-  /// @returns the closest continuing statement to the current statement that
-  /// (transitively) owns the current statement.
-  /// @param stop_at_loop if true then the function will return nullptr if a
-  /// loop or for-loop was found before the continuing.
-  const ast::Statement* ClosestContinuing(bool stop_at_loop) const;
-
-  /// @returns the resolved symbol (function, type or variable) for the given
-  /// ast::Identifier or ast::TypeName cast to the given semantic type.
-  template <typename SEM = sem::Node>
-  SEM* ResolvedSymbol(const ast::Node* node) const {
-    auto* resolved = utils::Lookup(dependencies_.resolved_symbols, node);
-    return resolved ? const_cast<SEM*>(builder_->Sem().Get<SEM>(resolved))
-                    : nullptr;
-  }
-
-  struct TypeConversionSig {
-    const sem::Type* target;
-    const sem::Type* source;
-
-    bool operator==(const TypeConversionSig&) const;
-
-    /// Hasher provides a hash function for the TypeConversionSig
-    struct Hasher {
-      /// @param sig the TypeConversionSig to create a hash for
-      /// @return the hash value
-      std::size_t operator()(const TypeConversionSig& sig) const;
+        // first_continue is set to the index of the first variable in decls
+        // declared after the first continue statement in a loop block, if any.
+        constexpr static size_t kNoContinue = size_t(~0);
+        size_t first_continue = kNoContinue;
     };
-  };
 
-  struct TypeConstructorSig {
-    const sem::Type* type;
-    const std::vector<const sem::Type*> parameters;
-
-    TypeConstructorSig(const sem::Type* ty,
-                       const std::vector<const sem::Type*> params);
-    TypeConstructorSig(const TypeConstructorSig&);
-    ~TypeConstructorSig();
-    bool operator==(const TypeConstructorSig&) const;
-
-    /// Hasher provides a hash function for the TypeConstructorSig
-    struct Hasher {
-      /// @param sig the TypeConstructorSig to create a hash for
-      /// @return the hash value
-      std::size_t operator()(const TypeConstructorSig& sig) const;
+    // Structure holding information for a TypeDecl
+    struct TypeDeclInfo {
+        ast::TypeDecl const* const ast;
+        sem::Type* const sem;
     };
-  };
 
-  ProgramBuilder* const builder_;
-  diag::List& diagnostics_;
-  std::unique_ptr<BuiltinTable> const builtin_table_;
-  DependencyGraph dependencies_;
-  SemHelper sem_;
-  std::vector<sem::Function*> entry_points_;
-  std::unordered_map<const sem::Type*, const Source&> atomic_composite_info_;
-  std::unordered_set<const ast::Node*> marked_;
-  std::unordered_map<uint32_t, const sem::Variable*> constant_ids_;
-  std::unordered_map<TypeConversionSig,
-                     sem::CallTarget*,
-                     TypeConversionSig::Hasher>
-      type_conversions_;
-  std::unordered_map<TypeConstructorSig,
-                     sem::CallTarget*,
-                     TypeConstructorSig::Hasher>
-      type_ctors_;
+    /// Resolves the program, without creating final the semantic nodes.
+    /// @returns true on success, false on error
+    bool ResolveInternal();
 
-  sem::Function* current_function_ = nullptr;
-  sem::Statement* current_statement_ = nullptr;
-  sem::CompoundStatement* current_compound_statement_ = nullptr;
-  sem::BlockStatement* current_block_ = nullptr;
+    /// Creates the nodes and adds them to the sem::Info mappings of the
+    /// ProgramBuilder.
+    void CreateSemanticNodes() const;
+
+    /// Retrieves information for the requested import.
+    /// @param src the source of the import
+    /// @param path the import path
+    /// @param name the method name to get information on
+    /// @param params the parameters to the method call
+    /// @param id out parameter for the external call ID. Must not be a nullptr.
+    /// @returns the return type of `name` in `path` or nullptr on error.
+    sem::Type* GetImportData(const Source& src,
+                             const std::string& path,
+                             const std::string& name,
+                             const ast::ExpressionList& params,
+                             uint32_t* id);
+
+    //////////////////////////////////////////////////////////////////////////////
+    // AST and Type traversal methods
+    //////////////////////////////////////////////////////////////////////////////
+
+    // Expression resolving methods
+    // Returns the semantic node pointer on success, nullptr on failure.
+    sem::Expression* IndexAccessor(const ast::IndexAccessorExpression*);
+    sem::Expression* Binary(const ast::BinaryExpression*);
+    sem::Expression* Bitcast(const ast::BitcastExpression*);
+    sem::Call* Call(const ast::CallExpression*);
+    sem::Expression* Expression(const ast::Expression*);
+    sem::Function* Function(const ast::Function*);
+    sem::Call* FunctionCall(const ast::CallExpression*,
+                            sem::Function* target,
+                            const std::vector<const sem::Expression*> args,
+                            sem::Behaviors arg_behaviors);
+    sem::Expression* Identifier(const ast::IdentifierExpression*);
+    sem::Call* BuiltinCall(const ast::CallExpression*,
+                           sem::BuiltinType,
+                           const std::vector<const sem::Expression*> args,
+                           const std::vector<const sem::Type*> arg_tys);
+    sem::Expression* Literal(const ast::LiteralExpression*);
+    sem::Expression* MemberAccessor(const ast::MemberAccessorExpression*);
+    sem::Call* TypeConversion(const ast::CallExpression* expr,
+                              const sem::Type* ty,
+                              const sem::Expression* arg,
+                              const sem::Type* arg_ty);
+    sem::Call* TypeConstructor(const ast::CallExpression* expr,
+                               const sem::Type* ty,
+                               const std::vector<const sem::Expression*> args,
+                               const std::vector<const sem::Type*> arg_tys);
+    sem::Expression* UnaryOp(const ast::UnaryOpExpression*);
+
+    // Statement resolving methods
+    // Each return true on success, false on failure.
+    sem::Statement* AssignmentStatement(const ast::AssignmentStatement*);
+    sem::BlockStatement* BlockStatement(const ast::BlockStatement*);
+    sem::Statement* BreakStatement(const ast::BreakStatement*);
+    sem::Statement* CallStatement(const ast::CallStatement*);
+    sem::CaseStatement* CaseStatement(const ast::CaseStatement*);
+    sem::Statement* CompoundAssignmentStatement(const ast::CompoundAssignmentStatement*);
+    sem::Statement* ContinueStatement(const ast::ContinueStatement*);
+    sem::Statement* DiscardStatement(const ast::DiscardStatement*);
+    sem::Statement* FallthroughStatement(const ast::FallthroughStatement*);
+    sem::ForLoopStatement* ForLoopStatement(const ast::ForLoopStatement*);
+    sem::GlobalVariable* GlobalVariable(const ast::Variable*);
+    sem::Statement* Parameter(const ast::Variable*);
+    sem::IfStatement* IfStatement(const ast::IfStatement*);
+    sem::Statement* IncrementDecrementStatement(const ast::IncrementDecrementStatement*);
+    sem::LoopStatement* LoopStatement(const ast::LoopStatement*);
+    sem::Statement* ReturnStatement(const ast::ReturnStatement*);
+    sem::Statement* Statement(const ast::Statement*);
+    sem::SwitchStatement* SwitchStatement(const ast::SwitchStatement* s);
+    sem::Statement* VariableDeclStatement(const ast::VariableDeclStatement*);
+    bool Statements(const ast::StatementList&);
+
+    // Resolve the result type of a binary operator.
+    // Returns nullptr if the types are not valid for this operator.
+    const sem::Type* BinaryOpType(const sem::Type* lhs_ty,
+                                  const sem::Type* rhs_ty,
+                                  ast::BinaryOp op);
+
+    /// Resolves the WorkgroupSize for the given function, assigning it to
+    /// current_function_
+    bool WorkgroupSize(const ast::Function*);
+
+    /// @returns the sem::Type for the ast::Type `ty`, building it if it
+    /// hasn't been constructed already. If an error is raised, nullptr is
+    /// returned.
+    /// @param ty the ast::Type
+    sem::Type* Type(const ast::Type* ty);
+
+    /// @param named_type the named type to resolve
+    /// @returns the resolved semantic type
+    sem::Type* TypeDecl(const ast::TypeDecl* named_type);
+
+    /// Builds and returns the semantic information for the array `arr`.
+    /// This method does not mark the ast::Array node, nor attach the generated
+    /// semantic information to the AST node.
+    /// @returns the semantic Array information, or nullptr if an error is
+    /// raised.
+    /// @param arr the Array to get semantic information for
+    sem::Array* Array(const ast::Array* arr);
+
+    /// Builds and returns the semantic information for the alias `alias`.
+    /// This method does not mark the ast::Alias node, nor attach the generated
+    /// semantic information to the AST node.
+    /// @returns the aliased type, or nullptr if an error is raised.
+    sem::Type* Alias(const ast::Alias* alias);
+
+    /// Builds and returns the semantic information for the structure `str`.
+    /// This method does not mark the ast::Struct node, nor attach the generated
+    /// semantic information to the AST node.
+    /// @returns the semantic Struct information, or nullptr if an error is
+    /// raised.
+    sem::Struct* Structure(const ast::Struct* str);
+
+    /// @returns the semantic info for the variable `var`. If an error is
+    /// raised, nullptr is returned.
+    /// @note this method does not resolve the attributes as these are
+    /// context-dependent (global, local, parameter)
+    /// @param var the variable to create or return the `VariableInfo` for
+    /// @param kind what kind of variable we are declaring
+    /// @param index the index of the parameter, if this variable is a parameter
+    sem::Variable* Variable(const ast::Variable* var, VariableKind kind, uint32_t index = 0);
+
+    /// Records the storage class usage for the given type, and any transient
+    /// dependencies of the type. Validates that the type can be used for the
+    /// given storage class, erroring if it cannot.
+    /// @param sc the storage class to apply to the type and transitent types
+    /// @param ty the type to apply the storage class on
+    /// @param usage the Source of the root variable declaration that uses the
+    /// given type and storage class. Used for generating sensible error
+    /// messages.
+    /// @returns true on success, false on error
+    bool ApplyStorageClassUsageToType(ast::StorageClass sc, sem::Type* ty, const Source& usage);
+
+    /// @param storage_class the storage class
+    /// @returns the default access control for the given storage class
+    ast::Access DefaultAccessForStorageClass(ast::StorageClass storage_class);
+
+    /// Allocate constant IDs for pipeline-overridable constants.
+    void AllocateOverridableConstantIds();
+
+    /// Set the shadowing information on variable declarations.
+    /// @note this method must only be called after all semantic nodes are built.
+    void SetShadows();
+    /// StatementScope() does the following:
+    /// * Creates the AST -> SEM mapping.
+    /// * Assigns `sem` to #current_statement_
+    /// * Assigns `sem` to #current_compound_statement_ if `sem` derives from
+    ///   sem::CompoundStatement.
+    /// * Assigns `sem` to #current_block_ if `sem` derives from
+    ///   sem::BlockStatement.
+    /// * Then calls `callback`.
+    /// * Before returning #current_statement_, #current_compound_statement_, and
+    ///   #current_block_ are restored to their original values.
+    /// @returns `sem` if `callback` returns true, otherwise `nullptr`.
+    template <typename SEM, typename F>
+    SEM* StatementScope(const ast::Statement* ast, SEM* sem, F&& callback);
+
+    /// Mark records that the given AST node has been visited, and asserts that
+    /// the given node has not already been seen. Diamonds in the AST are
+    /// illegal.
+    /// @param node the AST node.
+    /// @returns true on success, false on error
+    bool Mark(const ast::Node* node);
+
+    /// Adds the given error message to the diagnostics
+    void AddError(const std::string& msg, const Source& source) const;
+
+    /// Adds the given warning message to the diagnostics
+    void AddWarning(const std::string& msg, const Source& source) const;
+
+    /// Adds the given note message to the diagnostics
+    void AddNote(const std::string& msg, const Source& source) const;
+
+    //////////////////////////////////////////////////////////////////////////////
+    /// Constant value evaluation methods
+    //////////////////////////////////////////////////////////////////////////////
+    /// Cast `Value` to `target_type`
+    /// @return the casted value
+    sem::Constant ConstantCast(const sem::Constant& value, const sem::Type* target_elem_type);
+
+    sem::Constant EvaluateConstantValue(const ast::Expression* expr, const sem::Type* type);
+    sem::Constant EvaluateConstantValue(const ast::LiteralExpression* literal,
+                                        const sem::Type* type);
+    sem::Constant EvaluateConstantValue(const ast::CallExpression* call, const sem::Type* type);
+
+    /// @returns true if the symbol is the name of a builtin function.
+    bool IsBuiltin(Symbol) const;
+
+    /// @returns true if `expr` is the current CallStatement's CallExpression
+    bool IsCallStatement(const ast::Expression* expr) const;
+
+    struct TypeConversionSig {
+        const sem::Type* target;
+        const sem::Type* source;
+
+        bool operator==(const TypeConversionSig&) const;
+
+        /// Hasher provides a hash function for the TypeConversionSig
+        struct Hasher {
+            /// @param sig the TypeConversionSig to create a hash for
+            /// @return the hash value
+            std::size_t operator()(const TypeConversionSig& sig) const;
+        };
+    };
+
+    struct TypeConstructorSig {
+        const sem::Type* type;
+        const std::vector<const sem::Type*> parameters;
+
+        TypeConstructorSig(const sem::Type* ty, const std::vector<const sem::Type*> params);
+        TypeConstructorSig(const TypeConstructorSig&);
+        ~TypeConstructorSig();
+        bool operator==(const TypeConstructorSig&) const;
+
+        /// Hasher provides a hash function for the TypeConstructorSig
+        struct Hasher {
+            /// @param sig the TypeConstructorSig to create a hash for
+            /// @return the hash value
+            std::size_t operator()(const TypeConstructorSig& sig) const;
+        };
+    };
+
+    ProgramBuilder* const builder_;
+    diag::List& diagnostics_;
+    std::unique_ptr<BuiltinTable> const builtin_table_;
+    DependencyGraph dependencies_;
+    SemHelper sem_;
+    Validator validator_;
+    std::vector<sem::Function*> entry_points_;
+    std::unordered_map<const sem::Type*, const Source&> atomic_composite_info_;
+    std::unordered_set<const ast::Node*> marked_;
+    std::unordered_map<uint32_t, const sem::Variable*> constant_ids_;
+    std::unordered_map<TypeConversionSig, sem::CallTarget*, TypeConversionSig::Hasher>
+        type_conversions_;
+    std::unordered_map<TypeConstructorSig, sem::CallTarget*, TypeConstructorSig::Hasher>
+        type_ctors_;
+
+    sem::Function* current_function_ = nullptr;
+    sem::Statement* current_statement_ = nullptr;
+    sem::CompoundStatement* current_compound_statement_ = nullptr;
+    sem::BlockStatement* current_block_ = nullptr;
 };
 
 }  // namespace tint::resolver
diff --git a/src/tint/resolver/resolver_behavior_test.cc b/src/tint/resolver/resolver_behavior_test.cc
index af0c9ce..9cb26dc 100644
--- a/src/tint/resolver/resolver_behavior_test.cc
+++ b/src/tint/resolver/resolver_behavior_test.cc
@@ -20,637 +20,606 @@
 #include "src/tint/sem/for_loop_statement.h"
 #include "src/tint/sem/if_statement.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::resolver {
 namespace {
 
 class ResolverBehaviorTest : public ResolverTest {
- protected:
-  void SetUp() override {
-    // Create a function called 'DiscardOrNext' which returns an i32, and has
-    // the behavior of {Discard, Return}, which when called, will have the
-    // behavior {Discard, Next}.
-    Func("DiscardOrNext", {}, ty.i32(),
-         {
-             If(true, Block(Discard())),
-             Return(1),
-         });
-  }
+  protected:
+    void SetUp() override {
+        // Create a function called 'DiscardOrNext' which returns an i32, and has
+        // the behavior of {Discard, Return}, which when called, will have the
+        // behavior {Discard, Next}.
+        Func("DiscardOrNext", {}, ty.i32(),
+             {
+                 If(true, Block(Discard())),
+                 Return(1_i),
+             });
+    }
 };
 
 TEST_F(ResolverBehaviorTest, ExprBinaryOp_LHS) {
-  auto* stmt = Decl(Var("lhs", ty.i32(), Add(Call("DiscardOrNext"), 1)));
-  WrapInFunction(stmt);
+    auto* stmt = Decl(Var("lhs", ty.i32(), Add(Call("DiscardOrNext"), 1_i)));
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(),
-            sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
 }
 
 TEST_F(ResolverBehaviorTest, ExprBinaryOp_RHS) {
-  auto* stmt = Decl(Var("lhs", ty.i32(), Add(1, Call("DiscardOrNext"))));
-  WrapInFunction(stmt);
+    auto* stmt = Decl(Var("lhs", ty.i32(), Add(1_i, Call("DiscardOrNext"))));
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(),
-            sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
 }
 
 TEST_F(ResolverBehaviorTest, ExprBitcastOp) {
-  auto* stmt = Decl(Var("lhs", ty.u32(), Bitcast<u32>(Call("DiscardOrNext"))));
-  WrapInFunction(stmt);
+    auto* stmt = Decl(Var("lhs", ty.u32(), Bitcast<u32>(Call("DiscardOrNext"))));
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(),
-            sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
 }
 
 TEST_F(ResolverBehaviorTest, ExprIndex_Arr) {
-  Func("ArrayDiscardOrNext", {}, ty.array<i32, 4>(),
-       {
-           If(true, Block(Discard())),
-           Return(Construct(ty.array<i32, 4>())),
-       });
+    Func("ArrayDiscardOrNext", {}, ty.array<i32, 4>(),
+         {
+             If(true, Block(Discard())),
+             Return(Construct(ty.array<i32, 4>())),
+         });
 
-  auto* stmt =
-      Decl(Var("lhs", ty.i32(), IndexAccessor(Call("ArrayDiscardOrNext"), 1)));
-  WrapInFunction(stmt);
+    auto* stmt = Decl(Var("lhs", ty.i32(), IndexAccessor(Call("ArrayDiscardOrNext"), 1_i)));
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(),
-            sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
 }
 
 TEST_F(ResolverBehaviorTest, ExprIndex_Idx) {
-  auto* stmt =
-      Decl(Var("lhs", ty.i32(), IndexAccessor("arr", Call("DiscardOrNext"))));
-  WrapInFunction(Decl(Var("arr", ty.array<i32, 4>())),  //
-                 stmt);
+    auto* stmt = Decl(Var("lhs", ty.i32(), IndexAccessor("arr", Call("DiscardOrNext"))));
+    WrapInFunction(Decl(Var("arr", ty.array<i32, 4>())),  //
+                   stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(),
-            sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
 }
 
 TEST_F(ResolverBehaviorTest, ExprUnaryOp) {
-  auto* stmt = Decl(Var("lhs", ty.i32(),
-                        create<ast::UnaryOpExpression>(
-                            ast::UnaryOp::kComplement, Call("DiscardOrNext"))));
-  WrapInFunction(stmt);
+    auto* stmt =
+        Decl(Var("lhs", ty.i32(),
+                 create<ast::UnaryOpExpression>(ast::UnaryOp::kComplement, Call("DiscardOrNext"))));
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(),
-            sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
 }
 
 TEST_F(ResolverBehaviorTest, StmtAssign) {
-  auto* stmt = Assign("lhs", "rhs");
-  WrapInFunction(Decl(Var("lhs", ty.i32())),  //
-                 Decl(Var("rhs", ty.i32())),  //
-                 stmt);
+    auto* stmt = Assign("lhs", "rhs");
+    WrapInFunction(Decl(Var("lhs", ty.i32())),  //
+                   Decl(Var("rhs", ty.i32())),  //
+                   stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(), sem::Behavior::kNext);
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kNext);
 }
 
 TEST_F(ResolverBehaviorTest, StmtAssign_LHSDiscardOrNext) {
-  auto* stmt = Assign(IndexAccessor("lhs", Call("DiscardOrNext")), 1);
-  WrapInFunction(Decl(Var("lhs", ty.array<i32, 4>())),  //
-                 stmt);
+    auto* stmt = Assign(IndexAccessor("lhs", Call("DiscardOrNext")), 1_i);
+    WrapInFunction(Decl(Var("lhs", ty.array<i32, 4>())),  //
+                   stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(),
-            sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
 }
 
 TEST_F(ResolverBehaviorTest, StmtAssign_RHSDiscardOrNext) {
-  auto* stmt = Assign("lhs", Call("DiscardOrNext"));
-  WrapInFunction(Decl(Var("lhs", ty.i32())),  //
-                 stmt);
+    auto* stmt = Assign("lhs", Call("DiscardOrNext"));
+    WrapInFunction(Decl(Var("lhs", ty.i32())),  //
+                   stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(),
-            sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
 }
 
 TEST_F(ResolverBehaviorTest, StmtBlockEmpty) {
-  auto* stmt = Block();
-  WrapInFunction(stmt);
+    auto* stmt = Block();
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(), sem::Behavior::kNext);
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kNext);
 }
 
 TEST_F(ResolverBehaviorTest, StmtBlockSingleStmt) {
-  auto* stmt = Block(Discard());
-  WrapInFunction(stmt);
+    auto* stmt = Block(Discard());
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(), sem::Behavior::kDiscard);
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kDiscard);
 }
 
 TEST_F(ResolverBehaviorTest, StmtCallReturn) {
-  Func("f", {}, ty.void_(), {Return()});
-  auto* stmt = CallStmt(Call("f"));
-  WrapInFunction(stmt);
+    Func("f", {}, ty.void_(), {Return()});
+    auto* stmt = CallStmt(Call("f"));
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(), sem::Behavior::kNext);
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kNext);
 }
 
 TEST_F(ResolverBehaviorTest, StmtCallFuncDiscard) {
-  Func("f", {}, ty.void_(), {Discard()});
-  auto* stmt = CallStmt(Call("f"));
-  WrapInFunction(stmt);
+    Func("f", {}, ty.void_(), {Discard()});
+    auto* stmt = CallStmt(Call("f"));
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(), sem::Behavior::kDiscard);
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kDiscard);
 }
 
 TEST_F(ResolverBehaviorTest, StmtCallFuncMayDiscard) {
-  auto* stmt = For(Decl(Var("v", ty.i32(), Call("DiscardOrNext"))), nullptr,
-                   nullptr, Block(Break()));
-  WrapInFunction(stmt);
+    auto* stmt =
+        For(Decl(Var("v", ty.i32(), Call("DiscardOrNext"))), nullptr, nullptr, Block(Break()));
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(),
-            sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
 }
 
 TEST_F(ResolverBehaviorTest, StmtBreak) {
-  auto* stmt = Break();
-  WrapInFunction(Loop(Block(stmt)));
+    auto* stmt = Break();
+    WrapInFunction(Loop(Block(stmt)));
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(), sem::Behavior::kBreak);
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kBreak);
 }
 
 TEST_F(ResolverBehaviorTest, StmtContinue) {
-  auto* stmt = Continue();
-  WrapInFunction(Loop(Block(If(true, Block(Break())),  //
-                            stmt)));
+    auto* stmt = Continue();
+    WrapInFunction(Loop(Block(If(true, Block(Break())),  //
+                              stmt)));
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(), sem::Behavior::kContinue);
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kContinue);
 }
 
 TEST_F(ResolverBehaviorTest, StmtDiscard) {
-  auto* stmt = Discard();
-  WrapInFunction(stmt);
+    auto* stmt = Discard();
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(), sem::Behavior::kDiscard);
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kDiscard);
 }
 
 TEST_F(ResolverBehaviorTest, StmtForLoopEmpty_NoExit) {
-  auto* stmt = For(Source{{12, 34}}, nullptr, nullptr, nullptr, Block());
-  WrapInFunction(stmt);
+    auto* stmt = For(Source{{12, 34}}, nullptr, nullptr, nullptr, Block());
+    WrapInFunction(stmt);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: for-loop does not exit");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: for-loop does not exit");
 }
 
 TEST_F(ResolverBehaviorTest, StmtForLoopBreak) {
-  auto* stmt = For(nullptr, nullptr, nullptr, Block(Break()));
-  WrapInFunction(stmt);
+    auto* stmt = For(nullptr, nullptr, nullptr, Block(Break()));
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(), sem::Behavior::kNext);
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kNext);
 }
 
 TEST_F(ResolverBehaviorTest, StmtForLoopContinue_NoExit) {
-  auto* stmt =
-      For(Source{{12, 34}}, nullptr, nullptr, nullptr, Block(Continue()));
-  WrapInFunction(stmt);
+    auto* stmt = For(Source{{12, 34}}, nullptr, nullptr, nullptr, Block(Continue()));
+    WrapInFunction(stmt);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: for-loop does not exit");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: for-loop does not exit");
 }
 
 TEST_F(ResolverBehaviorTest, StmtForLoopDiscard) {
-  auto* stmt = For(nullptr, nullptr, nullptr, Block(Discard()));
-  WrapInFunction(stmt);
+    auto* stmt = For(nullptr, nullptr, nullptr, Block(Discard()));
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(), sem::Behavior::kDiscard);
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kDiscard);
 }
 
 TEST_F(ResolverBehaviorTest, StmtForLoopReturn) {
-  auto* stmt = For(nullptr, nullptr, nullptr, Block(Return()));
-  WrapInFunction(stmt);
+    auto* stmt = For(nullptr, nullptr, nullptr, Block(Return()));
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(), sem::Behavior::kReturn);
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kReturn);
 }
 
 TEST_F(ResolverBehaviorTest, StmtForLoopBreak_InitCallFuncMayDiscard) {
-  auto* stmt = For(Decl(Var("v", ty.i32(), Call("DiscardOrNext"))), nullptr,
-                   nullptr, Block(Break()));
-  WrapInFunction(stmt);
+    auto* stmt =
+        For(Decl(Var("v", ty.i32(), Call("DiscardOrNext"))), nullptr, nullptr, Block(Break()));
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(),
-            sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
 }
 
 TEST_F(ResolverBehaviorTest, StmtForLoopEmpty_InitCallFuncMayDiscard) {
-  auto* stmt = For(Decl(Var("v", ty.i32(), Call("DiscardOrNext"))), nullptr,
-                   nullptr, Block());
-  WrapInFunction(stmt);
+    auto* stmt = For(Decl(Var("v", ty.i32(), Call("DiscardOrNext"))), nullptr, nullptr, Block());
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(), sem::Behavior::kDiscard);
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kDiscard);
 }
 
 TEST_F(ResolverBehaviorTest, StmtForLoopEmpty_CondTrue) {
-  auto* stmt = For(nullptr, true, nullptr, Block());
-  WrapInFunction(stmt);
+    auto* stmt = For(nullptr, true, nullptr, Block());
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kNext));
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kNext));
 }
 
 TEST_F(ResolverBehaviorTest, StmtForLoopEmpty_CondCallFuncMayDiscard) {
-  auto* stmt = For(nullptr, Equal(Call("DiscardOrNext"), 1), nullptr, Block());
-  WrapInFunction(stmt);
+    auto* stmt = For(nullptr, Equal(Call("DiscardOrNext"), 1_i), nullptr, Block());
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(),
-            sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
 }
 
 TEST_F(ResolverBehaviorTest, StmtIfTrue_ThenEmptyBlock) {
-  auto* stmt = If(true, Block());
-  WrapInFunction(stmt);
+    auto* stmt = If(true, Block());
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(), sem::Behavior::kNext);
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kNext);
 }
 
 TEST_F(ResolverBehaviorTest, StmtIfTrue_ThenDiscard) {
-  auto* stmt = If(true, Block(Discard()));
-  WrapInFunction(stmt);
+    auto* stmt = If(true, Block(Discard()));
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(),
-            sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
 }
 
 TEST_F(ResolverBehaviorTest, StmtIfTrue_ThenEmptyBlock_ElseDiscard) {
-  auto* stmt = If(true, Block(), Else(Block(Discard())));
-  WrapInFunction(stmt);
+    auto* stmt = If(true, Block(), Else(Block(Discard())));
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(),
-            sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
 }
 
 TEST_F(ResolverBehaviorTest, StmtIfTrue_ThenDiscard_ElseDiscard) {
-  auto* stmt = If(true, Block(Discard()), Else(Block(Discard())));
-  WrapInFunction(stmt);
+    auto* stmt = If(true, Block(Discard()), Else(Block(Discard())));
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(), sem::Behavior::kDiscard);
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kDiscard);
 }
 
 TEST_F(ResolverBehaviorTest, StmtIfCallFuncMayDiscard_ThenEmptyBlock) {
-  auto* stmt = If(Equal(Call("DiscardOrNext"), 1), Block());
-  WrapInFunction(stmt);
+    auto* stmt = If(Equal(Call("DiscardOrNext"), 1_i), Block());
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(),
-            sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
 }
 
 TEST_F(ResolverBehaviorTest, StmtIfTrue_ThenEmptyBlock_ElseCallFuncMayDiscard) {
-  auto* stmt = If(true, Block(),  //
-                  Else(Equal(Call("DiscardOrNext"), 1), Block()));
-  WrapInFunction(stmt);
+    auto* stmt = If(true, Block(),  //
+                    Else(If(Equal(Call("DiscardOrNext"), 1_i), Block())));
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(),
-            sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
 }
 
 TEST_F(ResolverBehaviorTest, StmtLetDecl) {
-  auto* stmt = Decl(Const("v", ty.i32(), Expr(1)));
-  WrapInFunction(stmt);
+    auto* stmt = Decl(Let("v", ty.i32(), Expr(1_i)));
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(), sem::Behavior::kNext);
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kNext);
 }
 
 TEST_F(ResolverBehaviorTest, StmtLetDecl_RHSDiscardOrNext) {
-  auto* stmt = Decl(Const("lhs", ty.i32(), Call("DiscardOrNext")));
-  WrapInFunction(stmt);
+    auto* stmt = Decl(Let("lhs", ty.i32(), Call("DiscardOrNext")));
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(),
-            sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
 }
 
 TEST_F(ResolverBehaviorTest, StmtLoopEmpty_NoExit) {
-  auto* stmt = Loop(Source{{12, 34}}, Block());
-  WrapInFunction(stmt);
+    auto* stmt = Loop(Source{{12, 34}}, Block());
+    WrapInFunction(stmt);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: loop does not exit");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: loop does not exit");
 }
 
 TEST_F(ResolverBehaviorTest, StmtLoopBreak) {
-  auto* stmt = Loop(Block(Break()));
-  WrapInFunction(stmt);
+    auto* stmt = Loop(Block(Break()));
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(), sem::Behavior::kNext);
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kNext);
 }
 
 TEST_F(ResolverBehaviorTest, StmtLoopContinue_NoExit) {
-  auto* stmt = Loop(Source{{12, 34}}, Block(Continue()));
-  WrapInFunction(stmt);
+    auto* stmt = Loop(Source{{12, 34}}, Block(Continue()));
+    WrapInFunction(stmt);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: loop does not exit");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: loop does not exit");
 }
 
 TEST_F(ResolverBehaviorTest, StmtLoopDiscard) {
-  auto* stmt = Loop(Block(Discard()));
-  WrapInFunction(stmt);
+    auto* stmt = Loop(Block(Discard()));
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(), sem::Behavior::kDiscard);
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kDiscard);
 }
 
 TEST_F(ResolverBehaviorTest, StmtLoopReturn) {
-  auto* stmt = Loop(Block(Return()));
-  WrapInFunction(stmt);
+    auto* stmt = Loop(Block(Return()));
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(), sem::Behavior::kReturn);
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kReturn);
 }
 
 TEST_F(ResolverBehaviorTest, StmtLoopEmpty_ContEmpty_NoExit) {
-  auto* stmt = Loop(Source{{12, 34}}, Block(), Block());
-  WrapInFunction(stmt);
+    auto* stmt = Loop(Source{{12, 34}}, Block(), Block());
+    WrapInFunction(stmt);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: loop does not exit");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: loop does not exit");
 }
 
 TEST_F(ResolverBehaviorTest, StmtLoopEmpty_ContIfTrueBreak) {
-  auto* stmt = Loop(Block(), Block(If(true, Block(Break()))));
-  WrapInFunction(stmt);
+    auto* stmt = Loop(Block(), Block(If(true, Block(Break()))));
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(), sem::Behavior::kNext);
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kNext);
 }
 
 TEST_F(ResolverBehaviorTest, StmtReturn) {
-  auto* stmt = Return();
-  WrapInFunction(stmt);
+    auto* stmt = Return();
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(), sem::Behavior::kReturn);
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kReturn);
 }
 
 TEST_F(ResolverBehaviorTest, StmtReturn_DiscardOrNext) {
-  auto* stmt = Return(Call("DiscardOrNext"));
-  Func("F", {}, ty.i32(), {stmt});
+    auto* stmt = Return(Call("DiscardOrNext"));
+    Func("F", {}, ty.i32(), {stmt});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(),
-            sem::Behaviors(sem::Behavior::kReturn, sem::Behavior::kDiscard));
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kReturn, sem::Behavior::kDiscard));
 }
 
 TEST_F(ResolverBehaviorTest, StmtSwitch_CondTrue_DefaultEmpty) {
-  auto* stmt = Switch(1, DefaultCase(Block()));
-  WrapInFunction(stmt);
+    auto* stmt = Switch(1_i, DefaultCase(Block()));
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(), sem::Behavior::kNext);
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kNext);
 }
 
 TEST_F(ResolverBehaviorTest, StmtSwitch_CondLiteral_DefaultEmpty) {
-  auto* stmt = Switch(1, DefaultCase(Block()));
-  WrapInFunction(stmt);
+    auto* stmt = Switch(1_i, DefaultCase(Block()));
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(), sem::Behavior::kNext);
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kNext);
 }
 
 TEST_F(ResolverBehaviorTest, StmtSwitch_CondLiteral_DefaultDiscard) {
-  auto* stmt = Switch(1, DefaultCase(Block(Discard())));
-  WrapInFunction(stmt);
+    auto* stmt = Switch(1_i, DefaultCase(Block(Discard())));
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(), sem::Behavior::kDiscard);
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kDiscard);
 }
 
 TEST_F(ResolverBehaviorTest, StmtSwitch_CondLiteral_DefaultReturn) {
-  auto* stmt = Switch(1, DefaultCase(Block(Return())));
-  WrapInFunction(stmt);
+    auto* stmt = Switch(1_i, DefaultCase(Block(Return())));
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(), sem::Behavior::kReturn);
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kReturn);
 }
 
 TEST_F(ResolverBehaviorTest, StmtSwitch_CondLiteral_Case0Empty_DefaultEmpty) {
-  auto* stmt = Switch(1, Case(Expr(0), Block()), DefaultCase(Block()));
-  WrapInFunction(stmt);
+    auto* stmt = Switch(1_i, Case(Expr(0_i), Block()), DefaultCase(Block()));
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(), sem::Behavior::kNext);
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kNext);
 }
 
 TEST_F(ResolverBehaviorTest, StmtSwitch_CondLiteral_Case0Empty_DefaultDiscard) {
-  auto* stmt = Switch(1, Case(Expr(0), Block()), DefaultCase(Block(Discard())));
-  WrapInFunction(stmt);
+    auto* stmt = Switch(1_i, Case(Expr(0_i), Block()), DefaultCase(Block(Discard())));
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(),
-            sem::Behaviors(sem::Behavior::kNext, sem::Behavior::kDiscard));
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kNext, sem::Behavior::kDiscard));
 }
 
 TEST_F(ResolverBehaviorTest, StmtSwitch_CondLiteral_Case0Empty_DefaultReturn) {
-  auto* stmt = Switch(1, Case(Expr(0), Block()), DefaultCase(Block(Return())));
-  WrapInFunction(stmt);
+    auto* stmt = Switch(1_i, Case(Expr(0_i), Block()), DefaultCase(Block(Return())));
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(),
-            sem::Behaviors(sem::Behavior::kNext, sem::Behavior::kReturn));
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kNext, sem::Behavior::kReturn));
 }
 
 TEST_F(ResolverBehaviorTest, StmtSwitch_CondLiteral_Case0Discard_DefaultEmpty) {
-  auto* stmt = Switch(1, Case(Expr(0), Block(Discard())), DefaultCase(Block()));
-  WrapInFunction(stmt);
+    auto* stmt = Switch(1_i, Case(Expr(0_i), Block(Discard())), DefaultCase(Block()));
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(),
-            sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
 }
 
-TEST_F(ResolverBehaviorTest,
-       StmtSwitch_CondLiteral_Case0Discard_DefaultDiscard) {
-  auto* stmt =
-      Switch(1, Case(Expr(0), Block(Discard())), DefaultCase(Block(Discard())));
-  WrapInFunction(stmt);
+TEST_F(ResolverBehaviorTest, StmtSwitch_CondLiteral_Case0Discard_DefaultDiscard) {
+    auto* stmt = Switch(1_i, Case(Expr(0_i), Block(Discard())), DefaultCase(Block(Discard())));
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(), sem::Behavior::kDiscard);
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kDiscard);
 }
 
-TEST_F(ResolverBehaviorTest,
-       StmtSwitch_CondLiteral_Case0Discard_DefaultReturn) {
-  auto* stmt =
-      Switch(1, Case(Expr(0), Block(Discard())), DefaultCase(Block(Return())));
-  WrapInFunction(stmt);
+TEST_F(ResolverBehaviorTest, StmtSwitch_CondLiteral_Case0Discard_DefaultReturn) {
+    auto* stmt = Switch(1_i, Case(Expr(0_i), Block(Discard())), DefaultCase(Block(Return())));
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(),
-            sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kReturn));
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kReturn));
 }
 
-TEST_F(ResolverBehaviorTest,
-       StmtSwitch_CondLiteral_Case0Discard_Case1Return_DefaultEmpty) {
-  auto* stmt = Switch(1,                                //
-                      Case(Expr(0), Block(Discard())),  //
-                      Case(Expr(1), Block(Return())),   //
-                      DefaultCase(Block()));
-  WrapInFunction(stmt);
+TEST_F(ResolverBehaviorTest, StmtSwitch_CondLiteral_Case0Discard_Case1Return_DefaultEmpty) {
+    auto* stmt = Switch(1_i,                                //
+                        Case(Expr(0_i), Block(Discard())),  //
+                        Case(Expr(1_i), Block(Return())),   //
+                        DefaultCase(Block()));
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(),
-            sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext,
-                           sem::Behavior::kReturn));
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext,
+                                               sem::Behavior::kReturn));
 }
 
 TEST_F(ResolverBehaviorTest, StmtSwitch_CondCallFuncMayDiscard_DefaultEmpty) {
-  auto* stmt = Switch(Call("DiscardOrNext"), DefaultCase(Block()));
-  WrapInFunction(stmt);
+    auto* stmt = Switch(Call("DiscardOrNext"), DefaultCase(Block()));
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(),
-            sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
 }
 
 TEST_F(ResolverBehaviorTest, StmtVarDecl) {
-  auto* stmt = Decl(Var("v", ty.i32()));
-  WrapInFunction(stmt);
+    auto* stmt = Decl(Var("v", ty.i32()));
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(), sem::Behavior::kNext);
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behavior::kNext);
 }
 
 TEST_F(ResolverBehaviorTest, StmtVarDecl_RHSDiscardOrNext) {
-  auto* stmt = Decl(Var("lhs", ty.i32(), Call("DiscardOrNext")));
-  WrapInFunction(stmt);
+    auto* stmt = Decl(Var("lhs", ty.i32(), Call("DiscardOrNext")));
+    WrapInFunction(stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(stmt);
-  EXPECT_EQ(sem->Behaviors(),
-            sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
+    auto* sem = Sem().Get(stmt);
+    EXPECT_EQ(sem->Behaviors(), sem::Behaviors(sem::Behavior::kDiscard, sem::Behavior::kNext));
 }
 
 }  // namespace
diff --git a/src/tint/resolver/resolver_constants.cc b/src/tint/resolver/resolver_constants.cc
index 85f0abd..f5346d1 100644
--- a/src/tint/resolver/resolver_constants.cc
+++ b/src/tint/resolver/resolver_constants.cc
@@ -18,125 +18,132 @@
 #include "src/tint/sem/type_constructor.h"
 #include "src/tint/utils/map.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::resolver {
-namespace {
 
-using i32 = ProgramBuilder::i32;
-using u32 = ProgramBuilder::u32;
-using f32 = ProgramBuilder::f32;
-
-}  // namespace
-
-sem::Constant Resolver::EvaluateConstantValue(const ast::Expression* expr,
-                                              const sem::Type* type) {
-  if (auto* e = expr->As<ast::LiteralExpression>()) {
-    return EvaluateConstantValue(e, type);
-  }
-  if (auto* e = expr->As<ast::CallExpression>()) {
-    return EvaluateConstantValue(e, type);
-  }
-  return {};
+sem::Constant Resolver::EvaluateConstantValue(const ast::Expression* expr, const sem::Type* type) {
+    if (auto* e = expr->As<ast::LiteralExpression>()) {
+        return EvaluateConstantValue(e, type);
+    }
+    if (auto* e = expr->As<ast::CallExpression>()) {
+        return EvaluateConstantValue(e, type);
+    }
+    return {};
 }
 
-sem::Constant Resolver::EvaluateConstantValue(
-    const ast::LiteralExpression* literal,
-    const sem::Type* type) {
-  if (auto* lit = literal->As<ast::SintLiteralExpression>()) {
-    return {type, {lit->ValueAsI32()}};
-  }
-  if (auto* lit = literal->As<ast::UintLiteralExpression>()) {
-    return {type, {lit->ValueAsU32()}};
-  }
-  if (auto* lit = literal->As<ast::FloatLiteralExpression>()) {
-    return {type, {lit->value}};
-  }
-  if (auto* lit = literal->As<ast::BoolLiteralExpression>()) {
-    return {type, {lit->value}};
-  }
-  TINT_UNREACHABLE(Resolver, builder_->Diagnostics());
-  return {};
+sem::Constant Resolver::EvaluateConstantValue(const ast::LiteralExpression* literal,
+                                              const sem::Type* type) {
+    return Switch(
+        literal,
+        [&](const ast::IntLiteralExpression* lit) {
+            if (lit->suffix == ast::IntLiteralExpression::Suffix::kU) {
+                return sem::Constant{type, {u32(static_cast<uint32_t>(lit->value))}};
+            }
+            return sem::Constant{type, {i32(static_cast<int32_t>(lit->value))}};
+        },
+        [&](const ast::FloatLiteralExpression* lit) {
+            return sem::Constant{type, {lit->value}};
+        },
+        [&](const ast::BoolLiteralExpression* lit) {
+            return sem::Constant{type, {lit->value}};
+        });
 }
 
 sem::Constant Resolver::EvaluateConstantValue(const ast::CallExpression* call,
                                               const sem::Type* type) {
-  auto* vec = type->As<sem::Vector>();
+    auto* vec = type->As<sem::Vector>();
 
-  // For now, only fold scalars and vectors
-  if (!type->is_scalar() && !vec) {
-    return {};
-  }
+    // For now, only fold scalars and vectors
+    if (!type->is_scalar() && !vec) {
+        return {};
+    }
 
-  auto* elem_type = vec ? vec->type() : type;
-  int result_size = vec ? static_cast<int>(vec->Width()) : 1;
+    auto* elem_type = vec ? vec->type() : type;
+    int result_size = vec ? static_cast<int>(vec->Width()) : 1;
 
-  // For zero value init, return 0s
-  if (call->args.empty()) {
-    if (elem_type->Is<sem::I32>()) {
-      return sem::Constant(type, sem::Constant::Scalars(result_size, 0));
+    // For zero value init, return 0s
+    if (call->args.empty()) {
+        if (elem_type->Is<sem::I32>()) {
+            return sem::Constant(type, sem::Constant::Scalars(result_size, 0_i));
+        }
+        if (elem_type->Is<sem::U32>()) {
+            return sem::Constant(type, sem::Constant::Scalars(result_size, 0_u));
+        }
+        if (elem_type->Is<sem::F32>()) {
+            return sem::Constant(type, sem::Constant::Scalars(result_size, 0.f));
+        }
+        if (elem_type->Is<sem::Bool>()) {
+            return sem::Constant(type, sem::Constant::Scalars(result_size, false));
+        }
     }
-    if (elem_type->Is<sem::U32>()) {
-      return sem::Constant(type, sem::Constant::Scalars(result_size, 0u));
-    }
-    if (elem_type->Is<sem::F32>()) {
-      return sem::Constant(type, sem::Constant::Scalars(result_size, 0.f));
-    }
-    if (elem_type->Is<sem::Bool>()) {
-      return sem::Constant(type, sem::Constant::Scalars(result_size, false));
-    }
-  }
 
-  // Build value for type_ctor from each child value by casting to
-  // type_ctor's type.
-  sem::Constant::Scalars elems;
-  for (auto* expr : call->args) {
-    auto* arg = builder_->Sem().Get(expr);
-    if (!arg || !arg->ConstantValue()) {
-      return {};
+    // Build value for type_ctor from each child value by casting to
+    // type_ctor's type.
+    sem::Constant::Scalars elems;
+    for (auto* expr : call->args) {
+        auto* arg = builder_->Sem().Get(expr);
+        if (!arg || !arg->ConstantValue()) {
+            return {};
+        }
+        auto cast = ConstantCast(arg->ConstantValue(), elem_type);
+        elems.insert(elems.end(), cast.Elements().begin(), cast.Elements().end());
     }
-    auto cast = ConstantCast(arg->ConstantValue(), elem_type);
-    elems.insert(elems.end(), cast.Elements().begin(), cast.Elements().end());
-  }
 
-  // Splat single-value initializers
-  if (elems.size() == 1) {
-    for (int i = 0; i < result_size - 1; ++i) {
-      elems.emplace_back(elems[0]);
+    // Splat single-value initializers
+    if (elems.size() == 1) {
+        for (int i = 0; i < result_size - 1; ++i) {
+            elems.emplace_back(elems[0]);
+        }
     }
-  }
 
-  return sem::Constant(type, std::move(elems));
+    return sem::Constant(type, std::move(elems));
 }
 
 sem::Constant Resolver::ConstantCast(const sem::Constant& value,
                                      const sem::Type* target_elem_type) {
-  if (value.ElementType() == target_elem_type) {
-    return value;
-  }
-
-  sem::Constant::Scalars elems;
-  for (size_t i = 0; i < value.Elements().size(); ++i) {
-    if (target_elem_type->Is<sem::I32>()) {
-      elems.emplace_back(
-          value.WithScalarAt(i, [](auto&& s) { return static_cast<i32>(s); }));
-    } else if (target_elem_type->Is<sem::U32>()) {
-      elems.emplace_back(
-          value.WithScalarAt(i, [](auto&& s) { return static_cast<u32>(s); }));
-    } else if (target_elem_type->Is<sem::F32>()) {
-      elems.emplace_back(
-          value.WithScalarAt(i, [](auto&& s) { return static_cast<f32>(s); }));
-    } else if (target_elem_type->Is<sem::Bool>()) {
-      elems.emplace_back(
-          value.WithScalarAt(i, [](auto&& s) { return static_cast<bool>(s); }));
+    if (value.ElementType() == target_elem_type) {
+        return value;
     }
-  }
 
-  auto* target_type =
-      value.Type()->Is<sem::Vector>()
-          ? builder_->create<sem::Vector>(target_elem_type,
-                                          static_cast<uint32_t>(elems.size()))
-          : target_elem_type;
+    sem::Constant::Scalars elems;
+    for (size_t i = 0; i < value.Elements().size(); ++i) {
+        elems.emplace_back(Switch<sem::Constant::Scalar>(
+            target_elem_type,
+            [&](const sem::I32*) {
+                return value.WithScalarAt(i, [](auto&& s) {  //
+                    return i32(static_cast<int32_t>(s));
+                });
+            },
+            [&](const sem::U32*) {
+                return value.WithScalarAt(i, [](auto&& s) {  //
+                    return u32(static_cast<uint32_t>(s));
+                });
+            },
+            [&](const sem::F32*) {
+                return value.WithScalarAt(i, [](auto&& s) {  //
+                    return static_cast<f32>(s);
+                });
+            },
+            [&](const sem::Bool*) {
+                return value.WithScalarAt(i, [](auto&& s) {  //
+                    return static_cast<bool>(s);
+                });
+            },
+            [&](Default) {
+                diag::List diags;
+                TINT_UNREACHABLE(Semantic, diags)
+                    << "invalid element type " << target_elem_type->TypeInfo().name;
+                return sem::Constant::Scalar(false);
+            }));
+    }
 
-  return sem::Constant(target_type, elems);
+    auto* target_type =
+        value.Type()->Is<sem::Vector>()
+            ? builder_->create<sem::Vector>(target_elem_type, static_cast<uint32_t>(elems.size()))
+            : target_elem_type;
+
+    return sem::Constant(target_type, elems);
 }
 
 }  // namespace tint::resolver
diff --git a/src/tint/resolver/resolver_constants_test.cc b/src/tint/resolver/resolver_constants_test.cc
index b3a1be7..798de0a 100644
--- a/src/tint/resolver/resolver_constants_test.cc
+++ b/src/tint/resolver/resolver_constants_test.cc
@@ -18,6 +18,8 @@
 #include "src/tint/resolver/resolver_test_helper.h"
 #include "src/tint/sem/expression.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::resolver {
 namespace {
 
@@ -26,405 +28,405 @@
 using ResolverConstantsTest = ResolverTest;
 
 TEST_F(ResolverConstantsTest, Scalar_i32) {
-  auto* expr = Expr(99);
-  WrapInFunction(expr);
+    auto* expr = Expr(99_i);
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(expr);
-  EXPECT_NE(sem, nullptr);
-  EXPECT_TRUE(sem->Type()->Is<sem::I32>());
-  EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
-  EXPECT_EQ(sem->ConstantValue().ElementType(), sem->Type());
-  ASSERT_EQ(sem->ConstantValue().Elements().size(), 1u);
-  EXPECT_EQ(sem->ConstantValue().Elements()[0].i32, 99);
+    auto* sem = Sem().Get(expr);
+    EXPECT_NE(sem, nullptr);
+    EXPECT_TRUE(sem->Type()->Is<sem::I32>());
+    EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
+    EXPECT_EQ(sem->ConstantValue().ElementType(), sem->Type());
+    ASSERT_EQ(sem->ConstantValue().Elements().size(), 1u);
+    EXPECT_EQ(sem->ConstantValue().Elements()[0].i32, 99);
 }
 
 TEST_F(ResolverConstantsTest, Scalar_u32) {
-  auto* expr = Expr(99u);
-  WrapInFunction(expr);
+    auto* expr = Expr(99_u);
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(expr);
-  EXPECT_NE(sem, nullptr);
-  EXPECT_TRUE(sem->Type()->Is<sem::U32>());
-  EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
-  EXPECT_EQ(sem->ConstantValue().ElementType(), sem->Type());
-  ASSERT_EQ(sem->ConstantValue().Elements().size(), 1u);
-  EXPECT_EQ(sem->ConstantValue().Elements()[0].u32, 99u);
+    auto* sem = Sem().Get(expr);
+    EXPECT_NE(sem, nullptr);
+    EXPECT_TRUE(sem->Type()->Is<sem::U32>());
+    EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
+    EXPECT_EQ(sem->ConstantValue().ElementType(), sem->Type());
+    ASSERT_EQ(sem->ConstantValue().Elements().size(), 1u);
+    EXPECT_EQ(sem->ConstantValue().Elements()[0].u32, 99u);
 }
 
 TEST_F(ResolverConstantsTest, Scalar_f32) {
-  auto* expr = Expr(9.9f);
-  WrapInFunction(expr);
+    auto* expr = Expr(9.9f);
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(expr);
-  EXPECT_NE(sem, nullptr);
-  EXPECT_TRUE(sem->Type()->Is<sem::F32>());
-  EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
-  EXPECT_EQ(sem->ConstantValue().ElementType(), sem->Type());
-  ASSERT_EQ(sem->ConstantValue().Elements().size(), 1u);
-  EXPECT_EQ(sem->ConstantValue().Elements()[0].f32, 9.9f);
+    auto* sem = Sem().Get(expr);
+    EXPECT_NE(sem, nullptr);
+    EXPECT_TRUE(sem->Type()->Is<sem::F32>());
+    EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
+    EXPECT_EQ(sem->ConstantValue().ElementType(), sem->Type());
+    ASSERT_EQ(sem->ConstantValue().Elements().size(), 1u);
+    EXPECT_EQ(sem->ConstantValue().Elements()[0].f32, 9.9f);
 }
 
 TEST_F(ResolverConstantsTest, Scalar_bool) {
-  auto* expr = Expr(true);
-  WrapInFunction(expr);
+    auto* expr = Expr(true);
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(expr);
-  EXPECT_NE(sem, nullptr);
-  EXPECT_TRUE(sem->Type()->Is<sem::Bool>());
-  EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
-  EXPECT_EQ(sem->ConstantValue().ElementType(), sem->Type());
-  ASSERT_EQ(sem->ConstantValue().Elements().size(), 1u);
-  EXPECT_EQ(sem->ConstantValue().Elements()[0].bool_, true);
+    auto* sem = Sem().Get(expr);
+    EXPECT_NE(sem, nullptr);
+    EXPECT_TRUE(sem->Type()->Is<sem::Bool>());
+    EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
+    EXPECT_EQ(sem->ConstantValue().ElementType(), sem->Type());
+    ASSERT_EQ(sem->ConstantValue().Elements().size(), 1u);
+    EXPECT_EQ(sem->ConstantValue().Elements()[0].bool_, true);
 }
 
 TEST_F(ResolverConstantsTest, Vec3_ZeroInit_i32) {
-  auto* expr = vec3<i32>();
-  WrapInFunction(expr);
+    auto* expr = vec3<i32>();
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(expr);
-  EXPECT_NE(sem, nullptr);
-  ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
-  EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::I32>());
-  EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
-  EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
-  EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::I32>());
-  ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
-  EXPECT_EQ(sem->ConstantValue().Elements()[0].i32, 0);
-  EXPECT_EQ(sem->ConstantValue().Elements()[1].i32, 0);
-  EXPECT_EQ(sem->ConstantValue().Elements()[2].i32, 0);
+    auto* sem = Sem().Get(expr);
+    EXPECT_NE(sem, nullptr);
+    ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
+    EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::I32>());
+    EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
+    EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
+    EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::I32>());
+    ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
+    EXPECT_EQ(sem->ConstantValue().Elements()[0].i32, 0);
+    EXPECT_EQ(sem->ConstantValue().Elements()[1].i32, 0);
+    EXPECT_EQ(sem->ConstantValue().Elements()[2].i32, 0);
 }
 
 TEST_F(ResolverConstantsTest, Vec3_ZeroInit_u32) {
-  auto* expr = vec3<u32>();
-  WrapInFunction(expr);
+    auto* expr = vec3<u32>();
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(expr);
-  EXPECT_NE(sem, nullptr);
-  ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
-  EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::U32>());
-  EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
-  EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
-  EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::U32>());
-  ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
-  EXPECT_EQ(sem->ConstantValue().Elements()[0].u32, 0u);
-  EXPECT_EQ(sem->ConstantValue().Elements()[1].u32, 0u);
-  EXPECT_EQ(sem->ConstantValue().Elements()[2].u32, 0u);
+    auto* sem = Sem().Get(expr);
+    EXPECT_NE(sem, nullptr);
+    ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
+    EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::U32>());
+    EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
+    EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
+    EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::U32>());
+    ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
+    EXPECT_EQ(sem->ConstantValue().Elements()[0].u32, 0u);
+    EXPECT_EQ(sem->ConstantValue().Elements()[1].u32, 0u);
+    EXPECT_EQ(sem->ConstantValue().Elements()[2].u32, 0u);
 }
 
 TEST_F(ResolverConstantsTest, Vec3_ZeroInit_f32) {
-  auto* expr = vec3<f32>();
-  WrapInFunction(expr);
+    auto* expr = vec3<f32>();
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(expr);
-  EXPECT_NE(sem, nullptr);
-  ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
-  EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
-  EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
-  EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
-  ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
-  EXPECT_EQ(sem->ConstantValue().Elements()[0].f32, 0u);
-  EXPECT_EQ(sem->ConstantValue().Elements()[1].f32, 0u);
-  EXPECT_EQ(sem->ConstantValue().Elements()[2].f32, 0u);
+    auto* sem = Sem().Get(expr);
+    EXPECT_NE(sem, nullptr);
+    ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
+    EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
+    EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
+    EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
+    ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
+    EXPECT_EQ(sem->ConstantValue().Elements()[0].f32, 0u);
+    EXPECT_EQ(sem->ConstantValue().Elements()[1].f32, 0u);
+    EXPECT_EQ(sem->ConstantValue().Elements()[2].f32, 0u);
 }
 
 TEST_F(ResolverConstantsTest, Vec3_ZeroInit_bool) {
-  auto* expr = vec3<bool>();
-  WrapInFunction(expr);
+    auto* expr = vec3<bool>();
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(expr);
-  EXPECT_NE(sem, nullptr);
-  ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
-  EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::Bool>());
-  EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
-  EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
-  EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::Bool>());
-  ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
-  EXPECT_EQ(sem->ConstantValue().Elements()[0].bool_, false);
-  EXPECT_EQ(sem->ConstantValue().Elements()[1].bool_, false);
-  EXPECT_EQ(sem->ConstantValue().Elements()[2].bool_, false);
+    auto* sem = Sem().Get(expr);
+    EXPECT_NE(sem, nullptr);
+    ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
+    EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::Bool>());
+    EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
+    EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
+    EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::Bool>());
+    ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
+    EXPECT_EQ(sem->ConstantValue().Elements()[0].bool_, false);
+    EXPECT_EQ(sem->ConstantValue().Elements()[1].bool_, false);
+    EXPECT_EQ(sem->ConstantValue().Elements()[2].bool_, false);
 }
 
 TEST_F(ResolverConstantsTest, Vec3_Splat_i32) {
-  auto* expr = vec3<i32>(99);
-  WrapInFunction(expr);
+    auto* expr = vec3<i32>(99_i);
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(expr);
-  EXPECT_NE(sem, nullptr);
-  ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
-  EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::I32>());
-  EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
-  EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
-  EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::I32>());
-  ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
-  EXPECT_EQ(sem->ConstantValue().Elements()[0].i32, 99);
-  EXPECT_EQ(sem->ConstantValue().Elements()[1].i32, 99);
-  EXPECT_EQ(sem->ConstantValue().Elements()[2].i32, 99);
+    auto* sem = Sem().Get(expr);
+    EXPECT_NE(sem, nullptr);
+    ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
+    EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::I32>());
+    EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
+    EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
+    EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::I32>());
+    ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
+    EXPECT_EQ(sem->ConstantValue().Elements()[0].i32, 99);
+    EXPECT_EQ(sem->ConstantValue().Elements()[1].i32, 99);
+    EXPECT_EQ(sem->ConstantValue().Elements()[2].i32, 99);
 }
 
 TEST_F(ResolverConstantsTest, Vec3_Splat_u32) {
-  auto* expr = vec3<u32>(99u);
-  WrapInFunction(expr);
+    auto* expr = vec3<u32>(99_u);
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(expr);
-  EXPECT_NE(sem, nullptr);
-  ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
-  EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::U32>());
-  EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
-  EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
-  EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::U32>());
-  ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
-  EXPECT_EQ(sem->ConstantValue().Elements()[0].u32, 99u);
-  EXPECT_EQ(sem->ConstantValue().Elements()[1].u32, 99u);
-  EXPECT_EQ(sem->ConstantValue().Elements()[2].u32, 99u);
+    auto* sem = Sem().Get(expr);
+    EXPECT_NE(sem, nullptr);
+    ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
+    EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::U32>());
+    EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
+    EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
+    EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::U32>());
+    ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
+    EXPECT_EQ(sem->ConstantValue().Elements()[0].u32, 99u);
+    EXPECT_EQ(sem->ConstantValue().Elements()[1].u32, 99u);
+    EXPECT_EQ(sem->ConstantValue().Elements()[2].u32, 99u);
 }
 
 TEST_F(ResolverConstantsTest, Vec3_Splat_f32) {
-  auto* expr = vec3<f32>(9.9f);
-  WrapInFunction(expr);
+    auto* expr = vec3<f32>(9.9f);
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(expr);
-  EXPECT_NE(sem, nullptr);
-  ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
-  EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
-  EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
-  EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
-  ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
-  EXPECT_EQ(sem->ConstantValue().Elements()[0].f32, 9.9f);
-  EXPECT_EQ(sem->ConstantValue().Elements()[1].f32, 9.9f);
-  EXPECT_EQ(sem->ConstantValue().Elements()[2].f32, 9.9f);
+    auto* sem = Sem().Get(expr);
+    EXPECT_NE(sem, nullptr);
+    ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
+    EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
+    EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
+    EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
+    ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
+    EXPECT_EQ(sem->ConstantValue().Elements()[0].f32, 9.9f);
+    EXPECT_EQ(sem->ConstantValue().Elements()[1].f32, 9.9f);
+    EXPECT_EQ(sem->ConstantValue().Elements()[2].f32, 9.9f);
 }
 
 TEST_F(ResolverConstantsTest, Vec3_Splat_bool) {
-  auto* expr = vec3<bool>(true);
-  WrapInFunction(expr);
+    auto* expr = vec3<bool>(true);
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(expr);
-  EXPECT_NE(sem, nullptr);
-  ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
-  EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::Bool>());
-  EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
-  EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
-  EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::Bool>());
-  ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
-  EXPECT_EQ(sem->ConstantValue().Elements()[0].bool_, true);
-  EXPECT_EQ(sem->ConstantValue().Elements()[1].bool_, true);
-  EXPECT_EQ(sem->ConstantValue().Elements()[2].bool_, true);
+    auto* sem = Sem().Get(expr);
+    EXPECT_NE(sem, nullptr);
+    ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
+    EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::Bool>());
+    EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
+    EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
+    EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::Bool>());
+    ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
+    EXPECT_EQ(sem->ConstantValue().Elements()[0].bool_, true);
+    EXPECT_EQ(sem->ConstantValue().Elements()[1].bool_, true);
+    EXPECT_EQ(sem->ConstantValue().Elements()[2].bool_, true);
 }
 
 TEST_F(ResolverConstantsTest, Vec3_FullConstruct_i32) {
-  auto* expr = vec3<i32>(1, 2, 3);
-  WrapInFunction(expr);
+    auto* expr = vec3<i32>(1_i, 2_i, 3_i);
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(expr);
-  EXPECT_NE(sem, nullptr);
-  ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
-  EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::I32>());
-  EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
-  EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
-  EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::I32>());
-  ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
-  EXPECT_EQ(sem->ConstantValue().Elements()[0].i32, 1);
-  EXPECT_EQ(sem->ConstantValue().Elements()[1].i32, 2);
-  EXPECT_EQ(sem->ConstantValue().Elements()[2].i32, 3);
+    auto* sem = Sem().Get(expr);
+    EXPECT_NE(sem, nullptr);
+    ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
+    EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::I32>());
+    EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
+    EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
+    EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::I32>());
+    ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
+    EXPECT_EQ(sem->ConstantValue().Elements()[0].i32, 1);
+    EXPECT_EQ(sem->ConstantValue().Elements()[1].i32, 2);
+    EXPECT_EQ(sem->ConstantValue().Elements()[2].i32, 3);
 }
 
 TEST_F(ResolverConstantsTest, Vec3_FullConstruct_u32) {
-  auto* expr = vec3<u32>(1u, 2u, 3u);
-  WrapInFunction(expr);
+    auto* expr = vec3<u32>(1_u, 2_u, 3_u);
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(expr);
-  EXPECT_NE(sem, nullptr);
-  ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
-  EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::U32>());
-  EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
-  EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
-  EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::U32>());
-  ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
-  EXPECT_EQ(sem->ConstantValue().Elements()[0].u32, 1u);
-  EXPECT_EQ(sem->ConstantValue().Elements()[1].u32, 2u);
-  EXPECT_EQ(sem->ConstantValue().Elements()[2].u32, 3u);
+    auto* sem = Sem().Get(expr);
+    EXPECT_NE(sem, nullptr);
+    ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
+    EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::U32>());
+    EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
+    EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
+    EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::U32>());
+    ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
+    EXPECT_EQ(sem->ConstantValue().Elements()[0].u32, 1u);
+    EXPECT_EQ(sem->ConstantValue().Elements()[1].u32, 2u);
+    EXPECT_EQ(sem->ConstantValue().Elements()[2].u32, 3u);
 }
 
 TEST_F(ResolverConstantsTest, Vec3_FullConstruct_f32) {
-  auto* expr = vec3<f32>(1.f, 2.f, 3.f);
-  WrapInFunction(expr);
+    auto* expr = vec3<f32>(1.f, 2.f, 3.f);
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(expr);
-  EXPECT_NE(sem, nullptr);
-  ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
-  EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
-  EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
-  EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
-  ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
-  EXPECT_EQ(sem->ConstantValue().Elements()[0].f32, 1.f);
-  EXPECT_EQ(sem->ConstantValue().Elements()[1].f32, 2.f);
-  EXPECT_EQ(sem->ConstantValue().Elements()[2].f32, 3.f);
+    auto* sem = Sem().Get(expr);
+    EXPECT_NE(sem, nullptr);
+    ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
+    EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
+    EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
+    EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
+    ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
+    EXPECT_EQ(sem->ConstantValue().Elements()[0].f32, 1.f);
+    EXPECT_EQ(sem->ConstantValue().Elements()[1].f32, 2.f);
+    EXPECT_EQ(sem->ConstantValue().Elements()[2].f32, 3.f);
 }
 
 TEST_F(ResolverConstantsTest, Vec3_FullConstruct_bool) {
-  auto* expr = vec3<bool>(true, false, true);
-  WrapInFunction(expr);
+    auto* expr = vec3<bool>(true, false, true);
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(expr);
-  EXPECT_NE(sem, nullptr);
-  ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
-  EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::Bool>());
-  EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
-  EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
-  EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::Bool>());
-  ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
-  EXPECT_EQ(sem->ConstantValue().Elements()[0].bool_, true);
-  EXPECT_EQ(sem->ConstantValue().Elements()[1].bool_, false);
-  EXPECT_EQ(sem->ConstantValue().Elements()[2].bool_, true);
+    auto* sem = Sem().Get(expr);
+    EXPECT_NE(sem, nullptr);
+    ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
+    EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::Bool>());
+    EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
+    EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
+    EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::Bool>());
+    ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
+    EXPECT_EQ(sem->ConstantValue().Elements()[0].bool_, true);
+    EXPECT_EQ(sem->ConstantValue().Elements()[1].bool_, false);
+    EXPECT_EQ(sem->ConstantValue().Elements()[2].bool_, true);
 }
 
 TEST_F(ResolverConstantsTest, Vec3_MixConstruct_i32) {
-  auto* expr = vec3<i32>(1, vec2<i32>(2, 3));
-  WrapInFunction(expr);
+    auto* expr = vec3<i32>(1_i, vec2<i32>(2_i, 3_i));
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(expr);
-  EXPECT_NE(sem, nullptr);
-  ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
-  EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::I32>());
-  EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
-  EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
-  EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::I32>());
-  ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
-  EXPECT_EQ(sem->ConstantValue().Elements()[0].i32, 1);
-  EXPECT_EQ(sem->ConstantValue().Elements()[1].i32, 2);
-  EXPECT_EQ(sem->ConstantValue().Elements()[2].i32, 3);
+    auto* sem = Sem().Get(expr);
+    EXPECT_NE(sem, nullptr);
+    ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
+    EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::I32>());
+    EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
+    EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
+    EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::I32>());
+    ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
+    EXPECT_EQ(sem->ConstantValue().Elements()[0].i32, 1);
+    EXPECT_EQ(sem->ConstantValue().Elements()[1].i32, 2);
+    EXPECT_EQ(sem->ConstantValue().Elements()[2].i32, 3);
 }
 
 TEST_F(ResolverConstantsTest, Vec3_MixConstruct_u32) {
-  auto* expr = vec3<u32>(vec2<u32>(1u, 2u), 3u);
-  WrapInFunction(expr);
+    auto* expr = vec3<u32>(vec2<u32>(1_u, 2_u), 3_u);
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(expr);
-  EXPECT_NE(sem, nullptr);
-  ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
-  EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::U32>());
-  EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
-  EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
-  EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::U32>());
-  ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
-  EXPECT_EQ(sem->ConstantValue().Elements()[0].u32, 1u);
-  EXPECT_EQ(sem->ConstantValue().Elements()[1].u32, 2u);
-  EXPECT_EQ(sem->ConstantValue().Elements()[2].u32, 3u);
+    auto* sem = Sem().Get(expr);
+    EXPECT_NE(sem, nullptr);
+    ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
+    EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::U32>());
+    EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
+    EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
+    EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::U32>());
+    ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
+    EXPECT_EQ(sem->ConstantValue().Elements()[0].u32, 1u);
+    EXPECT_EQ(sem->ConstantValue().Elements()[1].u32, 2u);
+    EXPECT_EQ(sem->ConstantValue().Elements()[2].u32, 3u);
 }
 
 TEST_F(ResolverConstantsTest, Vec3_MixConstruct_f32) {
-  auto* expr = vec3<f32>(1.f, vec2<f32>(2.f, 3.f));
-  WrapInFunction(expr);
+    auto* expr = vec3<f32>(1.f, vec2<f32>(2.f, 3.f));
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(expr);
-  EXPECT_NE(sem, nullptr);
-  ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
-  EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
-  EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
-  EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
-  ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
-  EXPECT_EQ(sem->ConstantValue().Elements()[0].f32, 1.f);
-  EXPECT_EQ(sem->ConstantValue().Elements()[1].f32, 2.f);
-  EXPECT_EQ(sem->ConstantValue().Elements()[2].f32, 3.f);
+    auto* sem = Sem().Get(expr);
+    EXPECT_NE(sem, nullptr);
+    ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
+    EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
+    EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
+    EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
+    ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
+    EXPECT_EQ(sem->ConstantValue().Elements()[0].f32, 1.f);
+    EXPECT_EQ(sem->ConstantValue().Elements()[1].f32, 2.f);
+    EXPECT_EQ(sem->ConstantValue().Elements()[2].f32, 3.f);
 }
 
 TEST_F(ResolverConstantsTest, Vec3_MixConstruct_bool) {
-  auto* expr = vec3<bool>(vec2<bool>(true, false), true);
-  WrapInFunction(expr);
+    auto* expr = vec3<bool>(vec2<bool>(true, false), true);
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(expr);
-  EXPECT_NE(sem, nullptr);
-  ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
-  EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::Bool>());
-  EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
-  EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
-  EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::Bool>());
-  ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
-  EXPECT_EQ(sem->ConstantValue().Elements()[0].bool_, true);
-  EXPECT_EQ(sem->ConstantValue().Elements()[1].bool_, false);
-  EXPECT_EQ(sem->ConstantValue().Elements()[2].bool_, true);
+    auto* sem = Sem().Get(expr);
+    EXPECT_NE(sem, nullptr);
+    ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
+    EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::Bool>());
+    EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
+    EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
+    EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::Bool>());
+    ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
+    EXPECT_EQ(sem->ConstantValue().Elements()[0].bool_, true);
+    EXPECT_EQ(sem->ConstantValue().Elements()[1].bool_, false);
+    EXPECT_EQ(sem->ConstantValue().Elements()[2].bool_, true);
 }
 
 TEST_F(ResolverConstantsTest, Vec3_Cast_f32_to_32) {
-  auto* expr = vec3<i32>(vec3<f32>(1.1f, 2.2f, 3.3f));
-  WrapInFunction(expr);
+    auto* expr = vec3<i32>(vec3<f32>(1.1f, 2.2f, 3.3f));
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(expr);
-  EXPECT_NE(sem, nullptr);
-  ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
-  EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::I32>());
-  EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
-  EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
-  EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::I32>());
-  ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
-  EXPECT_EQ(sem->ConstantValue().Elements()[0].i32, 1);
-  EXPECT_EQ(sem->ConstantValue().Elements()[1].i32, 2);
-  EXPECT_EQ(sem->ConstantValue().Elements()[2].i32, 3);
+    auto* sem = Sem().Get(expr);
+    EXPECT_NE(sem, nullptr);
+    ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
+    EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::I32>());
+    EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
+    EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
+    EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::I32>());
+    ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
+    EXPECT_EQ(sem->ConstantValue().Elements()[0].i32, 1);
+    EXPECT_EQ(sem->ConstantValue().Elements()[1].i32, 2);
+    EXPECT_EQ(sem->ConstantValue().Elements()[2].i32, 3);
 }
 
 TEST_F(ResolverConstantsTest, Vec3_Cast_u32_to_f32) {
-  auto* expr = vec3<f32>(vec3<u32>(10u, 20u, 30u));
-  WrapInFunction(expr);
+    auto* expr = vec3<f32>(vec3<u32>(10_u, 20_u, 30_u));
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = Sem().Get(expr);
-  EXPECT_NE(sem, nullptr);
-  ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
-  EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
-  EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
-  EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
-  ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
-  EXPECT_EQ(sem->ConstantValue().Elements()[0].f32, 10.f);
-  EXPECT_EQ(sem->ConstantValue().Elements()[1].f32, 20.f);
-  EXPECT_EQ(sem->ConstantValue().Elements()[2].f32, 30.f);
+    auto* sem = Sem().Get(expr);
+    EXPECT_NE(sem, nullptr);
+    ASSERT_TRUE(sem->Type()->Is<sem::Vector>());
+    EXPECT_TRUE(sem->Type()->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(sem->Type()->As<sem::Vector>()->Width(), 3u);
+    EXPECT_EQ(sem->ConstantValue().Type(), sem->Type());
+    EXPECT_TRUE(sem->ConstantValue().ElementType()->Is<sem::F32>());
+    ASSERT_EQ(sem->ConstantValue().Elements().size(), 3u);
+    EXPECT_EQ(sem->ConstantValue().Elements()[0].f32, 10.f);
+    EXPECT_EQ(sem->ConstantValue().Elements()[1].f32, 20.f);
+    EXPECT_EQ(sem->ConstantValue().Elements()[2].f32, 30.f);
 }
 
 }  // namespace
diff --git a/src/tint/resolver/resolver_is_storeable_test.cc b/src/tint/resolver/resolver_is_storeable_test.cc
new file mode 100644
index 0000000..f4cde70
--- /dev/null
+++ b/src/tint/resolver/resolver_is_storeable_test.cc
@@ -0,0 +1,78 @@
+// Copyright 2021 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/resolver/resolver.h"
+
+#include "gmock/gmock.h"
+#include "src/tint/resolver/resolver_test_helper.h"
+#include "src/tint/sem/atomic.h"
+
+namespace tint::resolver {
+namespace {
+
+using ResolverIsStorableTest = ResolverTest;
+
+TEST_F(ResolverIsStorableTest, Struct_AllMembersStorable) {
+    Structure("S", {
+                       Member("a", ty.i32()),
+                       Member("b", ty.f32()),
+                   });
+
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
+}
+
+TEST_F(ResolverIsStorableTest, Struct_SomeMembersNonStorable) {
+    Structure("S", {
+                       Member("a", ty.i32()),
+                       Member("b", ty.pointer<i32>(ast::StorageClass::kPrivate)),
+                   });
+
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(
+        r()->error(),
+        R"(error: ptr<private, i32, read_write> cannot be used as the type of a structure member)");
+}
+
+TEST_F(ResolverIsStorableTest, Struct_NestedStorable) {
+    auto* storable = Structure("Storable", {
+                                               Member("a", ty.i32()),
+                                               Member("b", ty.f32()),
+                                           });
+    Structure("S", {
+                       Member("a", ty.i32()),
+                       Member("b", ty.Of(storable)),
+                   });
+
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
+}
+
+TEST_F(ResolverIsStorableTest, Struct_NestedNonStorable) {
+    auto* non_storable =
+        Structure("nonstorable", {
+                                     Member("a", ty.i32()),
+                                     Member("b", ty.pointer<i32>(ast::StorageClass::kPrivate)),
+                                 });
+    Structure("S", {
+                       Member("a", ty.i32()),
+                       Member("b", ty.Of(non_storable)),
+                   });
+
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(
+        r()->error(),
+        R"(error: ptr<private, i32, read_write> cannot be used as the type of a structure member)");
+}
+
+}  // namespace
+}  // namespace tint::resolver
diff --git a/src/tint/resolver/resolver_test.cc b/src/tint/resolver/resolver_test.cc
index e7c2fb4..f9055fd 100644
--- a/src/tint/resolver/resolver_test.cc
+++ b/src/tint/resolver/resolver_test.cc
@@ -39,14 +39,16 @@
 #include "src/tint/sem/function.h"
 #include "src/tint/sem/member_accessor_expression.h"
 #include "src/tint/sem/module.h"
-#include "src/tint/sem/reference_type.h"
-#include "src/tint/sem/sampled_texture_type.h"
+#include "src/tint/sem/reference.h"
+#include "src/tint/sem/sampled_texture.h"
 #include "src/tint/sem/statement.h"
 #include "src/tint/sem/variable.h"
 
 using ::testing::ElementsAre;
 using ::testing::HasSubstr;
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::resolver {
 namespace {
 
@@ -81,1169 +83,1148 @@
 using alias2 = builder::alias2<T>;
 template <typename T>
 using alias3 = builder::alias3<T>;
-using f32 = builder::f32;
-using i32 = builder::i32;
-using u32 = builder::u32;
 using Op = ast::BinaryOp;
 
 TEST_F(ResolverTest, Stmt_Assign) {
-  auto* v = Var("v", ty.f32());
-  auto* lhs = Expr("v");
-  auto* rhs = Expr(2.3f);
+    auto* v = Var("v", ty.f32());
+    auto* lhs = Expr("v");
+    auto* rhs = Expr(2.3f);
 
-  auto* assign = Assign(lhs, rhs);
-  WrapInFunction(v, assign);
+    auto* assign = Assign(lhs, rhs);
+    WrapInFunction(v, assign);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(lhs), nullptr);
-  ASSERT_NE(TypeOf(rhs), nullptr);
+    ASSERT_NE(TypeOf(lhs), nullptr);
+    ASSERT_NE(TypeOf(rhs), nullptr);
 
-  EXPECT_TRUE(TypeOf(lhs)->UnwrapRef()->Is<sem::F32>());
-  EXPECT_TRUE(TypeOf(rhs)->Is<sem::F32>());
-  EXPECT_EQ(StmtOf(lhs), assign);
-  EXPECT_EQ(StmtOf(rhs), assign);
+    EXPECT_TRUE(TypeOf(lhs)->UnwrapRef()->Is<sem::F32>());
+    EXPECT_TRUE(TypeOf(rhs)->Is<sem::F32>());
+    EXPECT_EQ(StmtOf(lhs), assign);
+    EXPECT_EQ(StmtOf(rhs), assign);
 }
 
 TEST_F(ResolverTest, Stmt_Case) {
-  auto* v = Var("v", ty.f32());
-  auto* lhs = Expr("v");
-  auto* rhs = Expr(2.3f);
+    auto* v = Var("v", ty.f32());
+    auto* lhs = Expr("v");
+    auto* rhs = Expr(2.3f);
 
-  auto* assign = Assign(lhs, rhs);
-  auto* block = Block(assign);
-  ast::CaseSelectorList lit;
-  lit.push_back(create<ast::SintLiteralExpression>(3));
-  auto* cse = create<ast::CaseStatement>(lit, block);
-  auto* cond_var = Var("c", ty.i32());
-  auto* sw = Switch(cond_var, cse, DefaultCase());
-  WrapInFunction(v, cond_var, sw);
+    auto* assign = Assign(lhs, rhs);
+    auto* block = Block(assign);
+    ast::CaseSelectorList lit;
+    lit.push_back(Expr(3_i));
+    auto* cse = create<ast::CaseStatement>(lit, block);
+    auto* cond_var = Var("c", ty.i32());
+    auto* sw = Switch(cond_var, cse, DefaultCase());
+    WrapInFunction(v, cond_var, sw);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(lhs), nullptr);
-  ASSERT_NE(TypeOf(rhs), nullptr);
-  EXPECT_TRUE(TypeOf(lhs)->UnwrapRef()->Is<sem::F32>());
-  EXPECT_TRUE(TypeOf(rhs)->Is<sem::F32>());
-  EXPECT_EQ(StmtOf(lhs), assign);
-  EXPECT_EQ(StmtOf(rhs), assign);
-  EXPECT_EQ(BlockOf(assign), block);
+    ASSERT_NE(TypeOf(lhs), nullptr);
+    ASSERT_NE(TypeOf(rhs), nullptr);
+    EXPECT_TRUE(TypeOf(lhs)->UnwrapRef()->Is<sem::F32>());
+    EXPECT_TRUE(TypeOf(rhs)->Is<sem::F32>());
+    EXPECT_EQ(StmtOf(lhs), assign);
+    EXPECT_EQ(StmtOf(rhs), assign);
+    EXPECT_EQ(BlockOf(assign), block);
 }
 
 TEST_F(ResolverTest, Stmt_Block) {
-  auto* v = Var("v", ty.f32());
-  auto* lhs = Expr("v");
-  auto* rhs = Expr(2.3f);
+    auto* v = Var("v", ty.f32());
+    auto* lhs = Expr("v");
+    auto* rhs = Expr(2.3f);
 
-  auto* assign = Assign(lhs, rhs);
-  auto* block = Block(assign);
-  WrapInFunction(v, block);
+    auto* assign = Assign(lhs, rhs);
+    auto* block = Block(assign);
+    WrapInFunction(v, block);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(lhs), nullptr);
-  ASSERT_NE(TypeOf(rhs), nullptr);
-  EXPECT_TRUE(TypeOf(lhs)->UnwrapRef()->Is<sem::F32>());
-  EXPECT_TRUE(TypeOf(rhs)->Is<sem::F32>());
-  EXPECT_EQ(StmtOf(lhs), assign);
-  EXPECT_EQ(StmtOf(rhs), assign);
-  EXPECT_EQ(BlockOf(lhs), block);
-  EXPECT_EQ(BlockOf(rhs), block);
-  EXPECT_EQ(BlockOf(assign), block);
+    ASSERT_NE(TypeOf(lhs), nullptr);
+    ASSERT_NE(TypeOf(rhs), nullptr);
+    EXPECT_TRUE(TypeOf(lhs)->UnwrapRef()->Is<sem::F32>());
+    EXPECT_TRUE(TypeOf(rhs)->Is<sem::F32>());
+    EXPECT_EQ(StmtOf(lhs), assign);
+    EXPECT_EQ(StmtOf(rhs), assign);
+    EXPECT_EQ(BlockOf(lhs), block);
+    EXPECT_EQ(BlockOf(rhs), block);
+    EXPECT_EQ(BlockOf(assign), block);
 }
 
 TEST_F(ResolverTest, Stmt_If) {
-  auto* v = Var("v", ty.f32());
-  auto* else_lhs = Expr("v");
-  auto* else_rhs = Expr(2.3f);
+    auto* v = Var("v", ty.f32());
+    auto* else_lhs = Expr("v");
+    auto* else_rhs = Expr(2.3f);
 
-  auto* else_body = Block(Assign(else_lhs, else_rhs));
+    auto* else_body = Block(Assign(else_lhs, else_rhs));
 
-  auto* else_cond = Expr(true);
-  auto* else_stmt = create<ast::ElseStatement>(else_cond, else_body);
+    auto* else_cond = Expr(true);
+    auto* else_stmt = If(else_cond, else_body);
 
-  auto* lhs = Expr("v");
-  auto* rhs = Expr(2.3f);
+    auto* lhs = Expr("v");
+    auto* rhs = Expr(2.3f);
 
-  auto* assign = Assign(lhs, rhs);
-  auto* body = Block(assign);
-  auto* cond = Expr(true);
-  auto* stmt =
-      create<ast::IfStatement>(cond, body, ast::ElseStatementList{else_stmt});
-  WrapInFunction(v, stmt);
+    auto* assign = Assign(lhs, rhs);
+    auto* body = Block(assign);
+    auto* cond = Expr(true);
+    auto* stmt = If(cond, body, Else(else_stmt));
+    WrapInFunction(v, stmt);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(stmt->condition), nullptr);
-  ASSERT_NE(TypeOf(else_lhs), nullptr);
-  ASSERT_NE(TypeOf(else_rhs), nullptr);
-  ASSERT_NE(TypeOf(lhs), nullptr);
-  ASSERT_NE(TypeOf(rhs), nullptr);
-  EXPECT_TRUE(TypeOf(stmt->condition)->Is<sem::Bool>());
-  EXPECT_TRUE(TypeOf(else_lhs)->UnwrapRef()->Is<sem::F32>());
-  EXPECT_TRUE(TypeOf(else_rhs)->Is<sem::F32>());
-  EXPECT_TRUE(TypeOf(lhs)->UnwrapRef()->Is<sem::F32>());
-  EXPECT_TRUE(TypeOf(rhs)->Is<sem::F32>());
-  EXPECT_EQ(StmtOf(lhs), assign);
-  EXPECT_EQ(StmtOf(rhs), assign);
-  EXPECT_EQ(StmtOf(cond), stmt);
-  EXPECT_EQ(StmtOf(else_cond), else_stmt);
-  EXPECT_EQ(BlockOf(lhs), body);
-  EXPECT_EQ(BlockOf(rhs), body);
-  EXPECT_EQ(BlockOf(else_lhs), else_body);
-  EXPECT_EQ(BlockOf(else_rhs), else_body);
+    ASSERT_NE(TypeOf(stmt->condition), nullptr);
+    ASSERT_NE(TypeOf(else_lhs), nullptr);
+    ASSERT_NE(TypeOf(else_rhs), nullptr);
+    ASSERT_NE(TypeOf(lhs), nullptr);
+    ASSERT_NE(TypeOf(rhs), nullptr);
+    EXPECT_TRUE(TypeOf(stmt->condition)->Is<sem::Bool>());
+    EXPECT_TRUE(TypeOf(else_lhs)->UnwrapRef()->Is<sem::F32>());
+    EXPECT_TRUE(TypeOf(else_rhs)->Is<sem::F32>());
+    EXPECT_TRUE(TypeOf(lhs)->UnwrapRef()->Is<sem::F32>());
+    EXPECT_TRUE(TypeOf(rhs)->Is<sem::F32>());
+    EXPECT_EQ(StmtOf(lhs), assign);
+    EXPECT_EQ(StmtOf(rhs), assign);
+    EXPECT_EQ(StmtOf(cond), stmt);
+    EXPECT_EQ(StmtOf(else_cond), else_stmt);
+    EXPECT_EQ(BlockOf(lhs), body);
+    EXPECT_EQ(BlockOf(rhs), body);
+    EXPECT_EQ(BlockOf(else_lhs), else_body);
+    EXPECT_EQ(BlockOf(else_rhs), else_body);
 }
 
 TEST_F(ResolverTest, Stmt_Loop) {
-  auto* v = Var("v", ty.f32());
-  auto* body_lhs = Expr("v");
-  auto* body_rhs = Expr(2.3f);
+    auto* v = Var("v", ty.f32());
+    auto* body_lhs = Expr("v");
+    auto* body_rhs = Expr(2.3f);
 
-  auto* body = Block(Assign(body_lhs, body_rhs), Break());
-  auto* continuing_lhs = Expr("v");
-  auto* continuing_rhs = Expr(2.3f);
+    auto* body = Block(Assign(body_lhs, body_rhs), Break());
+    auto* continuing_lhs = Expr("v");
+    auto* continuing_rhs = Expr(2.3f);
 
-  auto* continuing = Block(Assign(continuing_lhs, continuing_rhs));
-  auto* stmt = Loop(body, continuing);
-  WrapInFunction(v, stmt);
+    auto* continuing = Block(Assign(continuing_lhs, continuing_rhs));
+    auto* stmt = Loop(body, continuing);
+    WrapInFunction(v, stmt);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(body_lhs), nullptr);
-  ASSERT_NE(TypeOf(body_rhs), nullptr);
-  ASSERT_NE(TypeOf(continuing_lhs), nullptr);
-  ASSERT_NE(TypeOf(continuing_rhs), nullptr);
-  EXPECT_TRUE(TypeOf(body_lhs)->UnwrapRef()->Is<sem::F32>());
-  EXPECT_TRUE(TypeOf(body_rhs)->Is<sem::F32>());
-  EXPECT_TRUE(TypeOf(continuing_lhs)->UnwrapRef()->Is<sem::F32>());
-  EXPECT_TRUE(TypeOf(continuing_rhs)->Is<sem::F32>());
-  EXPECT_EQ(BlockOf(body_lhs), body);
-  EXPECT_EQ(BlockOf(body_rhs), body);
-  EXPECT_EQ(BlockOf(continuing_lhs), continuing);
-  EXPECT_EQ(BlockOf(continuing_rhs), continuing);
+    ASSERT_NE(TypeOf(body_lhs), nullptr);
+    ASSERT_NE(TypeOf(body_rhs), nullptr);
+    ASSERT_NE(TypeOf(continuing_lhs), nullptr);
+    ASSERT_NE(TypeOf(continuing_rhs), nullptr);
+    EXPECT_TRUE(TypeOf(body_lhs)->UnwrapRef()->Is<sem::F32>());
+    EXPECT_TRUE(TypeOf(body_rhs)->Is<sem::F32>());
+    EXPECT_TRUE(TypeOf(continuing_lhs)->UnwrapRef()->Is<sem::F32>());
+    EXPECT_TRUE(TypeOf(continuing_rhs)->Is<sem::F32>());
+    EXPECT_EQ(BlockOf(body_lhs), body);
+    EXPECT_EQ(BlockOf(body_rhs), body);
+    EXPECT_EQ(BlockOf(continuing_lhs), continuing);
+    EXPECT_EQ(BlockOf(continuing_rhs), continuing);
 }
 
 TEST_F(ResolverTest, Stmt_Return) {
-  auto* cond = Expr(2);
+    auto* cond = Expr(2_i);
 
-  auto* ret = Return(cond);
-  Func("test", {}, ty.i32(), {ret}, {});
+    auto* ret = Return(cond);
+    Func("test", {}, ty.i32(), {ret}, {});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(cond), nullptr);
-  EXPECT_TRUE(TypeOf(cond)->Is<sem::I32>());
+    ASSERT_NE(TypeOf(cond), nullptr);
+    EXPECT_TRUE(TypeOf(cond)->Is<sem::I32>());
 }
 
 TEST_F(ResolverTest, Stmt_Return_WithoutValue) {
-  auto* ret = Return();
-  WrapInFunction(ret);
+    auto* ret = Return();
+    WrapInFunction(ret);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverTest, Stmt_Switch) {
-  auto* v = Var("v", ty.f32());
-  auto* lhs = Expr("v");
-  auto* rhs = Expr(2.3f);
-  auto* case_block = Block(Assign(lhs, rhs));
-  auto* stmt = Switch(Expr(2), Case(Expr(3), case_block), DefaultCase());
-  WrapInFunction(v, stmt);
+    auto* v = Var("v", ty.f32());
+    auto* lhs = Expr("v");
+    auto* rhs = Expr(2.3f);
+    auto* case_block = Block(Assign(lhs, rhs));
+    auto* stmt = Switch(Expr(2_i), Case(Expr(3_i), case_block), DefaultCase());
+    WrapInFunction(v, stmt);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(stmt->condition), nullptr);
-  ASSERT_NE(TypeOf(lhs), nullptr);
-  ASSERT_NE(TypeOf(rhs), nullptr);
+    ASSERT_NE(TypeOf(stmt->condition), nullptr);
+    ASSERT_NE(TypeOf(lhs), nullptr);
+    ASSERT_NE(TypeOf(rhs), nullptr);
 
-  EXPECT_TRUE(TypeOf(stmt->condition)->Is<sem::I32>());
-  EXPECT_TRUE(TypeOf(lhs)->UnwrapRef()->Is<sem::F32>());
-  EXPECT_TRUE(TypeOf(rhs)->Is<sem::F32>());
-  EXPECT_EQ(BlockOf(lhs), case_block);
-  EXPECT_EQ(BlockOf(rhs), case_block);
+    EXPECT_TRUE(TypeOf(stmt->condition)->Is<sem::I32>());
+    EXPECT_TRUE(TypeOf(lhs)->UnwrapRef()->Is<sem::F32>());
+    EXPECT_TRUE(TypeOf(rhs)->Is<sem::F32>());
+    EXPECT_EQ(BlockOf(lhs), case_block);
+    EXPECT_EQ(BlockOf(rhs), case_block);
 }
 
 TEST_F(ResolverTest, Stmt_Call) {
-  ast::VariableList params;
-  Func("my_func", params, ty.void_(), {Return()}, ast::AttributeList{});
+    ast::VariableList params;
+    Func("my_func", params, ty.void_(), {Return()}, ast::AttributeList{});
 
-  auto* expr = Call("my_func");
+    auto* expr = Call("my_func");
 
-  auto* call = CallStmt(expr);
-  WrapInFunction(call);
+    auto* call = CallStmt(expr);
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(expr), nullptr);
-  EXPECT_TRUE(TypeOf(expr)->Is<sem::Void>());
-  EXPECT_EQ(StmtOf(expr), call);
+    ASSERT_NE(TypeOf(expr), nullptr);
+    EXPECT_TRUE(TypeOf(expr)->Is<sem::Void>());
+    EXPECT_EQ(StmtOf(expr), call);
 }
 
 TEST_F(ResolverTest, Stmt_VariableDecl) {
-  auto* var = Var("my_var", ty.i32(), ast::StorageClass::kNone, Expr(2));
-  auto* init = var->constructor;
+    auto* var = Var("my_var", ty.i32(), ast::StorageClass::kNone, Expr(2_i));
+    auto* init = var->constructor;
 
-  auto* decl = Decl(var);
-  WrapInFunction(decl);
+    auto* decl = Decl(var);
+    WrapInFunction(decl);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(init), nullptr);
-  EXPECT_TRUE(TypeOf(init)->Is<sem::I32>());
+    ASSERT_NE(TypeOf(init), nullptr);
+    EXPECT_TRUE(TypeOf(init)->Is<sem::I32>());
 }
 
 TEST_F(ResolverTest, Stmt_VariableDecl_Alias) {
-  auto* my_int = Alias("MyInt", ty.i32());
-  auto* var = Var("my_var", ty.Of(my_int), ast::StorageClass::kNone, Expr(2));
-  auto* init = var->constructor;
+    auto* my_int = Alias("MyInt", ty.i32());
+    auto* var = Var("my_var", ty.Of(my_int), ast::StorageClass::kNone, Expr(2_i));
+    auto* init = var->constructor;
 
-  auto* decl = Decl(var);
-  WrapInFunction(decl);
+    auto* decl = Decl(var);
+    WrapInFunction(decl);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(init), nullptr);
-  EXPECT_TRUE(TypeOf(init)->Is<sem::I32>());
+    ASSERT_NE(TypeOf(init), nullptr);
+    EXPECT_TRUE(TypeOf(init)->Is<sem::I32>());
 }
 
 TEST_F(ResolverTest, Stmt_VariableDecl_ModuleScope) {
-  auto* init = Expr(2);
-  Global("my_var", ty.i32(), ast::StorageClass::kPrivate, init);
+    auto* init = Expr(2_i);
+    Global("my_var", ty.i32(), ast::StorageClass::kPrivate, init);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(init), nullptr);
-  EXPECT_TRUE(TypeOf(init)->Is<sem::I32>());
-  EXPECT_EQ(StmtOf(init), nullptr);
+    ASSERT_NE(TypeOf(init), nullptr);
+    EXPECT_TRUE(TypeOf(init)->Is<sem::I32>());
+    EXPECT_EQ(StmtOf(init), nullptr);
 }
 
 TEST_F(ResolverTest, Stmt_VariableDecl_OuterScopeAfterInnerScope) {
-  // fn func_i32() {
-  //   {
-  //     var foo : i32 = 2;
-  //     var bar : i32 = foo;
-  //   }
-  //   var foo : f32 = 2.0;
-  //   var bar : f32 = foo;
-  // }
+    // fn func_i32() {
+    //   {
+    //     var foo : i32 = 2;
+    //     var bar : i32 = foo;
+    //   }
+    //   var foo : f32 = 2.0;
+    //   var bar : f32 = foo;
+    // }
 
-  ast::VariableList params;
+    ast::VariableList params;
 
-  // Declare i32 "foo" inside a block
-  auto* foo_i32 = Var("foo", ty.i32(), ast::StorageClass::kNone, Expr(2));
-  auto* foo_i32_init = foo_i32->constructor;
-  auto* foo_i32_decl = Decl(foo_i32);
+    // Declare i32 "foo" inside a block
+    auto* foo_i32 = Var("foo", ty.i32(), ast::StorageClass::kNone, Expr(2_i));
+    auto* foo_i32_init = foo_i32->constructor;
+    auto* foo_i32_decl = Decl(foo_i32);
 
-  // Reference "foo" inside the block
-  auto* bar_i32 = Var("bar", ty.i32(), ast::StorageClass::kNone, Expr("foo"));
-  auto* bar_i32_init = bar_i32->constructor;
-  auto* bar_i32_decl = Decl(bar_i32);
+    // Reference "foo" inside the block
+    auto* bar_i32 = Var("bar", ty.i32(), ast::StorageClass::kNone, Expr("foo"));
+    auto* bar_i32_init = bar_i32->constructor;
+    auto* bar_i32_decl = Decl(bar_i32);
 
-  auto* inner = Block(foo_i32_decl, bar_i32_decl);
+    auto* inner = Block(foo_i32_decl, bar_i32_decl);
 
-  // Declare f32 "foo" at function scope
-  auto* foo_f32 = Var("foo", ty.f32(), ast::StorageClass::kNone, Expr(2.f));
-  auto* foo_f32_init = foo_f32->constructor;
-  auto* foo_f32_decl = Decl(foo_f32);
+    // Declare f32 "foo" at function scope
+    auto* foo_f32 = Var("foo", ty.f32(), ast::StorageClass::kNone, Expr(2.f));
+    auto* foo_f32_init = foo_f32->constructor;
+    auto* foo_f32_decl = Decl(foo_f32);
 
-  // Reference "foo" at function scope
-  auto* bar_f32 = Var("bar", ty.f32(), ast::StorageClass::kNone, Expr("foo"));
-  auto* bar_f32_init = bar_f32->constructor;
-  auto* bar_f32_decl = Decl(bar_f32);
+    // Reference "foo" at function scope
+    auto* bar_f32 = Var("bar", ty.f32(), ast::StorageClass::kNone, Expr("foo"));
+    auto* bar_f32_init = bar_f32->constructor;
+    auto* bar_f32_decl = Decl(bar_f32);
 
-  Func("func", params, ty.void_(), {inner, foo_f32_decl, bar_f32_decl},
-       ast::AttributeList{});
+    Func("func", params, ty.void_(), {inner, foo_f32_decl, bar_f32_decl}, ast::AttributeList{});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  ASSERT_NE(TypeOf(foo_i32_init), nullptr);
-  EXPECT_TRUE(TypeOf(foo_i32_init)->Is<sem::I32>());
-  ASSERT_NE(TypeOf(foo_f32_init), nullptr);
-  EXPECT_TRUE(TypeOf(foo_f32_init)->Is<sem::F32>());
-  ASSERT_NE(TypeOf(bar_i32_init), nullptr);
-  EXPECT_TRUE(TypeOf(bar_i32_init)->UnwrapRef()->Is<sem::I32>());
-  ASSERT_NE(TypeOf(bar_f32_init), nullptr);
-  EXPECT_TRUE(TypeOf(bar_f32_init)->UnwrapRef()->Is<sem::F32>());
-  EXPECT_EQ(StmtOf(foo_i32_init), foo_i32_decl);
-  EXPECT_EQ(StmtOf(bar_i32_init), bar_i32_decl);
-  EXPECT_EQ(StmtOf(foo_f32_init), foo_f32_decl);
-  EXPECT_EQ(StmtOf(bar_f32_init), bar_f32_decl);
-  EXPECT_TRUE(CheckVarUsers(foo_i32, {bar_i32->constructor}));
-  EXPECT_TRUE(CheckVarUsers(foo_f32, {bar_f32->constructor}));
-  ASSERT_NE(VarOf(bar_i32->constructor), nullptr);
-  EXPECT_EQ(VarOf(bar_i32->constructor)->Declaration(), foo_i32);
-  ASSERT_NE(VarOf(bar_f32->constructor), nullptr);
-  EXPECT_EQ(VarOf(bar_f32->constructor)->Declaration(), foo_f32);
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_NE(TypeOf(foo_i32_init), nullptr);
+    EXPECT_TRUE(TypeOf(foo_i32_init)->Is<sem::I32>());
+    ASSERT_NE(TypeOf(foo_f32_init), nullptr);
+    EXPECT_TRUE(TypeOf(foo_f32_init)->Is<sem::F32>());
+    ASSERT_NE(TypeOf(bar_i32_init), nullptr);
+    EXPECT_TRUE(TypeOf(bar_i32_init)->UnwrapRef()->Is<sem::I32>());
+    ASSERT_NE(TypeOf(bar_f32_init), nullptr);
+    EXPECT_TRUE(TypeOf(bar_f32_init)->UnwrapRef()->Is<sem::F32>());
+    EXPECT_EQ(StmtOf(foo_i32_init), foo_i32_decl);
+    EXPECT_EQ(StmtOf(bar_i32_init), bar_i32_decl);
+    EXPECT_EQ(StmtOf(foo_f32_init), foo_f32_decl);
+    EXPECT_EQ(StmtOf(bar_f32_init), bar_f32_decl);
+    EXPECT_TRUE(CheckVarUsers(foo_i32, {bar_i32->constructor}));
+    EXPECT_TRUE(CheckVarUsers(foo_f32, {bar_f32->constructor}));
+    ASSERT_NE(VarOf(bar_i32->constructor), nullptr);
+    EXPECT_EQ(VarOf(bar_i32->constructor)->Declaration(), foo_i32);
+    ASSERT_NE(VarOf(bar_f32->constructor), nullptr);
+    EXPECT_EQ(VarOf(bar_f32->constructor)->Declaration(), foo_f32);
 }
 
 TEST_F(ResolverTest, Stmt_VariableDecl_ModuleScopeAfterFunctionScope) {
-  // fn func_i32() {
-  //   var foo : i32 = 2;
-  // }
-  // var foo : f32 = 2.0;
-  // fn func_f32() {
-  //   var bar : f32 = foo;
-  // }
+    // fn func_i32() {
+    //   var foo : i32 = 2;
+    // }
+    // var foo : f32 = 2.0;
+    // fn func_f32() {
+    //   var bar : f32 = foo;
+    // }
 
-  ast::VariableList params;
+    ast::VariableList params;
 
-  // Declare i32 "foo" inside a function
-  auto* fn_i32 = Var("foo", ty.i32(), ast::StorageClass::kNone, Expr(2));
-  auto* fn_i32_init = fn_i32->constructor;
-  auto* fn_i32_decl = Decl(fn_i32);
-  Func("func_i32", params, ty.void_(), {fn_i32_decl}, ast::AttributeList{});
+    // Declare i32 "foo" inside a function
+    auto* fn_i32 = Var("foo", ty.i32(), ast::StorageClass::kNone, Expr(2_i));
+    auto* fn_i32_init = fn_i32->constructor;
+    auto* fn_i32_decl = Decl(fn_i32);
+    Func("func_i32", params, ty.void_(), {fn_i32_decl}, ast::AttributeList{});
 
-  // Declare f32 "foo" at module scope
-  auto* mod_f32 = Var("foo", ty.f32(), ast::StorageClass::kPrivate, Expr(2.f));
-  auto* mod_init = mod_f32->constructor;
-  AST().AddGlobalVariable(mod_f32);
+    // Declare f32 "foo" at module scope
+    auto* mod_f32 = Var("foo", ty.f32(), ast::StorageClass::kPrivate, Expr(2.f));
+    auto* mod_init = mod_f32->constructor;
+    AST().AddGlobalVariable(mod_f32);
 
-  // Reference "foo" in another function
-  auto* fn_f32 = Var("bar", ty.f32(), ast::StorageClass::kNone, Expr("foo"));
-  auto* fn_f32_init = fn_f32->constructor;
-  auto* fn_f32_decl = Decl(fn_f32);
-  Func("func_f32", params, ty.void_(), {fn_f32_decl}, ast::AttributeList{});
+    // Reference "foo" in another function
+    auto* fn_f32 = Var("bar", ty.f32(), ast::StorageClass::kNone, Expr("foo"));
+    auto* fn_f32_init = fn_f32->constructor;
+    auto* fn_f32_decl = Decl(fn_f32);
+    Func("func_f32", params, ty.void_(), {fn_f32_decl}, ast::AttributeList{});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  ASSERT_NE(TypeOf(mod_init), nullptr);
-  EXPECT_TRUE(TypeOf(mod_init)->Is<sem::F32>());
-  ASSERT_NE(TypeOf(fn_i32_init), nullptr);
-  EXPECT_TRUE(TypeOf(fn_i32_init)->Is<sem::I32>());
-  ASSERT_NE(TypeOf(fn_f32_init), nullptr);
-  EXPECT_TRUE(TypeOf(fn_f32_init)->UnwrapRef()->Is<sem::F32>());
-  EXPECT_EQ(StmtOf(fn_i32_init), fn_i32_decl);
-  EXPECT_EQ(StmtOf(mod_init), nullptr);
-  EXPECT_EQ(StmtOf(fn_f32_init), fn_f32_decl);
-  EXPECT_TRUE(CheckVarUsers(fn_i32, {}));
-  EXPECT_TRUE(CheckVarUsers(mod_f32, {fn_f32->constructor}));
-  ASSERT_NE(VarOf(fn_f32->constructor), nullptr);
-  EXPECT_EQ(VarOf(fn_f32->constructor)->Declaration(), mod_f32);
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_NE(TypeOf(mod_init), nullptr);
+    EXPECT_TRUE(TypeOf(mod_init)->Is<sem::F32>());
+    ASSERT_NE(TypeOf(fn_i32_init), nullptr);
+    EXPECT_TRUE(TypeOf(fn_i32_init)->Is<sem::I32>());
+    ASSERT_NE(TypeOf(fn_f32_init), nullptr);
+    EXPECT_TRUE(TypeOf(fn_f32_init)->UnwrapRef()->Is<sem::F32>());
+    EXPECT_EQ(StmtOf(fn_i32_init), fn_i32_decl);
+    EXPECT_EQ(StmtOf(mod_init), nullptr);
+    EXPECT_EQ(StmtOf(fn_f32_init), fn_f32_decl);
+    EXPECT_TRUE(CheckVarUsers(fn_i32, {}));
+    EXPECT_TRUE(CheckVarUsers(mod_f32, {fn_f32->constructor}));
+    ASSERT_NE(VarOf(fn_f32->constructor), nullptr);
+    EXPECT_EQ(VarOf(fn_f32->constructor)->Declaration(), mod_f32);
 }
 
 TEST_F(ResolverTest, ArraySize_UnsignedLiteral) {
-  // var<private> a : array<f32, 10u>;
-  auto* a =
-      Global("a", ty.array(ty.f32(), Expr(10u)), ast::StorageClass::kPrivate);
+    // var<private> a : array<f32, 10u>;
+    auto* a = Global("a", ty.array(ty.f32(), Expr(10_u)), ast::StorageClass::kPrivate);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(a), nullptr);
-  auto* ref = TypeOf(a)->As<sem::Reference>();
-  ASSERT_NE(ref, nullptr);
-  auto* ary = ref->StoreType()->As<sem::Array>();
-  EXPECT_EQ(ary->Count(), 10u);
+    ASSERT_NE(TypeOf(a), nullptr);
+    auto* ref = TypeOf(a)->As<sem::Reference>();
+    ASSERT_NE(ref, nullptr);
+    auto* ary = ref->StoreType()->As<sem::Array>();
+    EXPECT_EQ(ary->Count(), 10u);
 }
 
 TEST_F(ResolverTest, ArraySize_SignedLiteral) {
-  // var<private> a : array<f32, 10>;
-  auto* a =
-      Global("a", ty.array(ty.f32(), Expr(10)), ast::StorageClass::kPrivate);
+    // var<private> a : array<f32, 10i>;
+    auto* a = Global("a", ty.array(ty.f32(), Expr(10_i)), ast::StorageClass::kPrivate);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(a), nullptr);
-  auto* ref = TypeOf(a)->As<sem::Reference>();
-  ASSERT_NE(ref, nullptr);
-  auto* ary = ref->StoreType()->As<sem::Array>();
-  EXPECT_EQ(ary->Count(), 10u);
+    ASSERT_NE(TypeOf(a), nullptr);
+    auto* ref = TypeOf(a)->As<sem::Reference>();
+    ASSERT_NE(ref, nullptr);
+    auto* ary = ref->StoreType()->As<sem::Array>();
+    EXPECT_EQ(ary->Count(), 10u);
 }
 
 TEST_F(ResolverTest, ArraySize_UnsignedConstant) {
-  // let size = 0u;
-  // var<private> a : array<f32, 10u>;
-  GlobalConst("size", nullptr, Expr(10u));
-  auto* a = Global("a", ty.array(ty.f32(), Expr("size")),
-                   ast::StorageClass::kPrivate);
+    // let size = 0u;
+    // var<private> a : array<f32, size>;
+    GlobalConst("size", nullptr, Expr(10_u));
+    auto* a = Global("a", ty.array(ty.f32(), Expr("size")), ast::StorageClass::kPrivate);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(a), nullptr);
-  auto* ref = TypeOf(a)->As<sem::Reference>();
-  ASSERT_NE(ref, nullptr);
-  auto* ary = ref->StoreType()->As<sem::Array>();
-  EXPECT_EQ(ary->Count(), 10u);
+    ASSERT_NE(TypeOf(a), nullptr);
+    auto* ref = TypeOf(a)->As<sem::Reference>();
+    ASSERT_NE(ref, nullptr);
+    auto* ary = ref->StoreType()->As<sem::Array>();
+    EXPECT_EQ(ary->Count(), 10u);
 }
 
 TEST_F(ResolverTest, ArraySize_SignedConstant) {
-  // let size = 0;
-  // var<private> a : array<f32, 10>;
-  GlobalConst("size", nullptr, Expr(10));
-  auto* a = Global("a", ty.array(ty.f32(), Expr("size")),
-                   ast::StorageClass::kPrivate);
+    // let size = 0;
+    // var<private> a : array<f32, size>;
+    GlobalConst("size", nullptr, Expr(10_i));
+    auto* a = Global("a", ty.array(ty.f32(), Expr("size")), ast::StorageClass::kPrivate);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(a), nullptr);
-  auto* ref = TypeOf(a)->As<sem::Reference>();
-  ASSERT_NE(ref, nullptr);
-  auto* ary = ref->StoreType()->As<sem::Array>();
-  EXPECT_EQ(ary->Count(), 10u);
+    ASSERT_NE(TypeOf(a), nullptr);
+    auto* ref = TypeOf(a)->As<sem::Reference>();
+    ASSERT_NE(ref, nullptr);
+    auto* ary = ref->StoreType()->As<sem::Array>();
+    EXPECT_EQ(ary->Count(), 10u);
 }
 
 TEST_F(ResolverTest, Expr_Bitcast) {
-  Global("name", ty.f32(), ast::StorageClass::kPrivate);
+    Global("name", ty.f32(), ast::StorageClass::kPrivate);
 
-  auto* bitcast = create<ast::BitcastExpression>(ty.f32(), Expr("name"));
-  WrapInFunction(bitcast);
+    auto* bitcast = create<ast::BitcastExpression>(ty.f32(), Expr("name"));
+    WrapInFunction(bitcast);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(bitcast), nullptr);
-  EXPECT_TRUE(TypeOf(bitcast)->Is<sem::F32>());
+    ASSERT_NE(TypeOf(bitcast), nullptr);
+    EXPECT_TRUE(TypeOf(bitcast)->Is<sem::F32>());
 }
 
 TEST_F(ResolverTest, Expr_Call) {
-  ast::VariableList params;
-  Func("my_func", params, ty.f32(), {Return(0.0f)}, ast::AttributeList{});
+    ast::VariableList params;
+    Func("my_func", params, ty.f32(), {Return(0.0f)}, ast::AttributeList{});
 
-  auto* call = Call("my_func");
-  WrapInFunction(call);
+    auto* call = Call("my_func");
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(call), nullptr);
-  EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
 }
 
 TEST_F(ResolverTest, Expr_Call_InBinaryOp) {
-  ast::VariableList params;
-  Func("func", params, ty.f32(), {Return(0.0f)}, ast::AttributeList{});
+    ast::VariableList params;
+    Func("func", params, ty.f32(), {Return(0.0f)}, ast::AttributeList{});
 
-  auto* expr = Add(Call("func"), Call("func"));
-  WrapInFunction(expr);
+    auto* expr = Add(Call("func"), Call("func"));
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(expr), nullptr);
-  EXPECT_TRUE(TypeOf(expr)->Is<sem::F32>());
+    ASSERT_NE(TypeOf(expr), nullptr);
+    EXPECT_TRUE(TypeOf(expr)->Is<sem::F32>());
 }
 
 TEST_F(ResolverTest, Expr_Call_WithParams) {
-  Func("my_func", {Param(Sym(), ty.f32())}, ty.f32(),
-       {
-           Return(1.2f),
-       });
+    Func("my_func", {Param(Sym(), ty.f32())}, ty.f32(),
+         {
+             Return(1.2f),
+         });
 
-  auto* param = Expr(2.4f);
+    auto* param = Expr(2.4f);
 
-  auto* call = Call("my_func", param);
-  WrapInFunction(call);
+    auto* call = Call("my_func", param);
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(param), nullptr);
-  EXPECT_TRUE(TypeOf(param)->Is<sem::F32>());
+    ASSERT_NE(TypeOf(param), nullptr);
+    EXPECT_TRUE(TypeOf(param)->Is<sem::F32>());
 }
 
 TEST_F(ResolverTest, Expr_Call_Builtin) {
-  auto* call = Call("round", 2.4f);
-  WrapInFunction(call);
+    auto* call = Call("round", 2.4f);
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(call), nullptr);
-  EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
 }
 
 TEST_F(ResolverTest, Expr_Cast) {
-  Global("name", ty.f32(), ast::StorageClass::kPrivate);
+    Global("name", ty.f32(), ast::StorageClass::kPrivate);
 
-  auto* cast = Construct(ty.f32(), "name");
-  WrapInFunction(cast);
+    auto* cast = Construct(ty.f32(), "name");
+    WrapInFunction(cast);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(cast), nullptr);
-  EXPECT_TRUE(TypeOf(cast)->Is<sem::F32>());
+    ASSERT_NE(TypeOf(cast), nullptr);
+    EXPECT_TRUE(TypeOf(cast)->Is<sem::F32>());
 }
 
 TEST_F(ResolverTest, Expr_Constructor_Scalar) {
-  auto* s = Expr(1.0f);
-  WrapInFunction(s);
+    auto* s = Expr(1.0f);
+    WrapInFunction(s);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(s), nullptr);
-  EXPECT_TRUE(TypeOf(s)->Is<sem::F32>());
+    ASSERT_NE(TypeOf(s), nullptr);
+    EXPECT_TRUE(TypeOf(s)->Is<sem::F32>());
 }
 
 TEST_F(ResolverTest, Expr_Constructor_Type_Vec2) {
-  auto* tc = vec2<f32>(1.0f, 1.0f);
-  WrapInFunction(tc);
+    auto* tc = vec2<f32>(1.0f, 1.0f);
+    WrapInFunction(tc);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(tc), nullptr);
-  ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 2u);
+    ASSERT_NE(TypeOf(tc), nullptr);
+    ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 2u);
 }
 
 TEST_F(ResolverTest, Expr_Constructor_Type_Vec3) {
-  auto* tc = vec3<f32>(1.0f, 1.0f, 1.0f);
-  WrapInFunction(tc);
+    auto* tc = vec3<f32>(1.0f, 1.0f, 1.0f);
+    WrapInFunction(tc);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(tc), nullptr);
-  ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 3u);
+    ASSERT_NE(TypeOf(tc), nullptr);
+    ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 3u);
 }
 
 TEST_F(ResolverTest, Expr_Constructor_Type_Vec4) {
-  auto* tc = vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f);
-  WrapInFunction(tc);
+    auto* tc = vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f);
+    WrapInFunction(tc);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(tc), nullptr);
-  ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
+    ASSERT_NE(TypeOf(tc), nullptr);
+    ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
 }
 
 TEST_F(ResolverTest, Expr_Identifier_GlobalVariable) {
-  auto* my_var = Global("my_var", ty.f32(), ast::StorageClass::kPrivate);
+    auto* my_var = Global("my_var", ty.f32(), ast::StorageClass::kPrivate);
 
-  auto* ident = Expr("my_var");
-  WrapInFunction(ident);
+    auto* ident = Expr("my_var");
+    WrapInFunction(ident);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(ident), nullptr);
-  ASSERT_TRUE(TypeOf(ident)->Is<sem::Reference>());
-  EXPECT_TRUE(TypeOf(ident)->UnwrapRef()->Is<sem::F32>());
-  EXPECT_TRUE(CheckVarUsers(my_var, {ident}));
-  ASSERT_NE(VarOf(ident), nullptr);
-  EXPECT_EQ(VarOf(ident)->Declaration(), my_var);
+    ASSERT_NE(TypeOf(ident), nullptr);
+    ASSERT_TRUE(TypeOf(ident)->Is<sem::Reference>());
+    EXPECT_TRUE(TypeOf(ident)->UnwrapRef()->Is<sem::F32>());
+    EXPECT_TRUE(CheckVarUsers(my_var, {ident}));
+    ASSERT_NE(VarOf(ident), nullptr);
+    EXPECT_EQ(VarOf(ident)->Declaration(), my_var);
 }
 
 TEST_F(ResolverTest, Expr_Identifier_GlobalConstant) {
-  auto* my_var = GlobalConst("my_var", ty.f32(), Construct(ty.f32()));
+    auto* my_var = GlobalConst("my_var", ty.f32(), Construct(ty.f32()));
 
-  auto* ident = Expr("my_var");
-  WrapInFunction(ident);
+    auto* ident = Expr("my_var");
+    WrapInFunction(ident);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(ident), nullptr);
-  EXPECT_TRUE(TypeOf(ident)->Is<sem::F32>());
-  EXPECT_TRUE(CheckVarUsers(my_var, {ident}));
-  ASSERT_NE(VarOf(ident), nullptr);
-  EXPECT_EQ(VarOf(ident)->Declaration(), my_var);
+    ASSERT_NE(TypeOf(ident), nullptr);
+    EXPECT_TRUE(TypeOf(ident)->Is<sem::F32>());
+    EXPECT_TRUE(CheckVarUsers(my_var, {ident}));
+    ASSERT_NE(VarOf(ident), nullptr);
+    EXPECT_EQ(VarOf(ident)->Declaration(), my_var);
 }
 
 TEST_F(ResolverTest, Expr_Identifier_FunctionVariable_Const) {
-  auto* my_var_a = Expr("my_var");
-  auto* var = Const("my_var", ty.f32(), Construct(ty.f32()));
-  auto* decl = Decl(Var("b", ty.f32(), ast::StorageClass::kNone, my_var_a));
+    auto* my_var_a = Expr("my_var");
+    auto* var = Let("my_var", ty.f32(), Construct(ty.f32()));
+    auto* decl = Decl(Var("b", ty.f32(), ast::StorageClass::kNone, my_var_a));
 
-  Func("my_func", ast::VariableList{}, ty.void_(),
-       {
-           Decl(var),
-           decl,
-       },
-       ast::AttributeList{});
+    Func("my_func", ast::VariableList{}, ty.void_(),
+         {
+             Decl(var),
+             decl,
+         },
+         ast::AttributeList{});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(my_var_a), nullptr);
-  EXPECT_TRUE(TypeOf(my_var_a)->Is<sem::F32>());
-  EXPECT_EQ(StmtOf(my_var_a), decl);
-  EXPECT_TRUE(CheckVarUsers(var, {my_var_a}));
-  ASSERT_NE(VarOf(my_var_a), nullptr);
-  EXPECT_EQ(VarOf(my_var_a)->Declaration(), var);
+    ASSERT_NE(TypeOf(my_var_a), nullptr);
+    EXPECT_TRUE(TypeOf(my_var_a)->Is<sem::F32>());
+    EXPECT_EQ(StmtOf(my_var_a), decl);
+    EXPECT_TRUE(CheckVarUsers(var, {my_var_a}));
+    ASSERT_NE(VarOf(my_var_a), nullptr);
+    EXPECT_EQ(VarOf(my_var_a)->Declaration(), var);
 }
 
 TEST_F(ResolverTest, IndexAccessor_Dynamic_Ref_F32) {
-  // var a : array<bool, 10> = 0;
-  // var idx : f32 = f32();
-  // var f : f32 = a[idx];
-  auto* a = Var("a", ty.array<bool, 10>(), array<bool, 10>());
-  auto* idx = Var("idx", ty.f32(), Construct(ty.f32()));
-  auto* f = Var("f", ty.f32(), IndexAccessor("a", Expr(Source{{12, 34}}, idx)));
-  Func("my_func", ast::VariableList{}, ty.void_(),
-       {
-           Decl(a),
-           Decl(idx),
-           Decl(f),
-       },
-       ast::AttributeList{});
+    // var a : array<bool, 10u> = 0;
+    // var idx : f32 = f32();
+    // var f : f32 = a[idx];
+    auto* a = Var("a", ty.array<bool, 10>(), array<bool, 10>());
+    auto* idx = Var("idx", ty.f32(), Construct(ty.f32()));
+    auto* f = Var("f", ty.f32(), IndexAccessor("a", Expr(Source{{12, 34}}, idx)));
+    Func("my_func", ast::VariableList{}, ty.void_(),
+         {
+             Decl(a),
+             Decl(idx),
+             Decl(f),
+         },
+         ast::AttributeList{});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: index must be of type 'i32' or 'u32', found: 'f32'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: index must be of type 'i32' or 'u32', found: 'f32'");
 }
 
 TEST_F(ResolverTest, Expr_Identifier_FunctionVariable) {
-  auto* my_var_a = Expr("my_var");
-  auto* my_var_b = Expr("my_var");
-  auto* assign = Assign(my_var_a, my_var_b);
+    auto* my_var_a = Expr("my_var");
+    auto* my_var_b = Expr("my_var");
+    auto* assign = Assign(my_var_a, my_var_b);
 
-  auto* var = Var("my_var", ty.f32());
+    auto* var = Var("my_var", ty.f32());
 
-  Func("my_func", ast::VariableList{}, ty.void_(),
-       {
-           Decl(var),
-           assign,
-       },
-       ast::AttributeList{});
+    Func("my_func", ast::VariableList{}, ty.void_(),
+         {
+             Decl(var),
+             assign,
+         },
+         ast::AttributeList{});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(my_var_a), nullptr);
-  ASSERT_TRUE(TypeOf(my_var_a)->Is<sem::Reference>());
-  EXPECT_TRUE(TypeOf(my_var_a)->UnwrapRef()->Is<sem::F32>());
-  EXPECT_EQ(StmtOf(my_var_a), assign);
-  ASSERT_NE(TypeOf(my_var_b), nullptr);
-  ASSERT_TRUE(TypeOf(my_var_b)->Is<sem::Reference>());
-  EXPECT_TRUE(TypeOf(my_var_b)->UnwrapRef()->Is<sem::F32>());
-  EXPECT_EQ(StmtOf(my_var_b), assign);
-  EXPECT_TRUE(CheckVarUsers(var, {my_var_a, my_var_b}));
-  ASSERT_NE(VarOf(my_var_a), nullptr);
-  EXPECT_EQ(VarOf(my_var_a)->Declaration(), var);
-  ASSERT_NE(VarOf(my_var_b), nullptr);
-  EXPECT_EQ(VarOf(my_var_b)->Declaration(), var);
+    ASSERT_NE(TypeOf(my_var_a), nullptr);
+    ASSERT_TRUE(TypeOf(my_var_a)->Is<sem::Reference>());
+    EXPECT_TRUE(TypeOf(my_var_a)->UnwrapRef()->Is<sem::F32>());
+    EXPECT_EQ(StmtOf(my_var_a), assign);
+    ASSERT_NE(TypeOf(my_var_b), nullptr);
+    ASSERT_TRUE(TypeOf(my_var_b)->Is<sem::Reference>());
+    EXPECT_TRUE(TypeOf(my_var_b)->UnwrapRef()->Is<sem::F32>());
+    EXPECT_EQ(StmtOf(my_var_b), assign);
+    EXPECT_TRUE(CheckVarUsers(var, {my_var_a, my_var_b}));
+    ASSERT_NE(VarOf(my_var_a), nullptr);
+    EXPECT_EQ(VarOf(my_var_a)->Declaration(), var);
+    ASSERT_NE(VarOf(my_var_b), nullptr);
+    EXPECT_EQ(VarOf(my_var_b)->Declaration(), var);
 }
 
 TEST_F(ResolverTest, Expr_Identifier_Function_Ptr) {
-  auto* v = Expr("v");
-  auto* p = Expr("p");
-  auto* v_decl = Decl(Var("v", ty.f32()));
-  auto* p_decl = Decl(
-      Const("p", ty.pointer<f32>(ast::StorageClass::kFunction), AddressOf(v)));
-  auto* assign = Assign(Deref(p), 1.23f);
-  Func("my_func", ast::VariableList{}, ty.void_(),
-       {
-           v_decl,
-           p_decl,
-           assign,
-       },
-       ast::AttributeList{});
+    auto* v = Expr("v");
+    auto* p = Expr("p");
+    auto* v_decl = Decl(Var("v", ty.f32()));
+    auto* p_decl = Decl(Let("p", ty.pointer<f32>(ast::StorageClass::kFunction), AddressOf(v)));
+    auto* assign = Assign(Deref(p), 1.23f);
+    Func("my_func", ast::VariableList{}, ty.void_(),
+         {
+             v_decl,
+             p_decl,
+             assign,
+         },
+         ast::AttributeList{});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(v), nullptr);
-  ASSERT_TRUE(TypeOf(v)->Is<sem::Reference>());
-  EXPECT_TRUE(TypeOf(v)->UnwrapRef()->Is<sem::F32>());
-  EXPECT_EQ(StmtOf(v), p_decl);
-  ASSERT_NE(TypeOf(p), nullptr);
-  ASSERT_TRUE(TypeOf(p)->Is<sem::Pointer>());
-  EXPECT_TRUE(TypeOf(p)->UnwrapPtr()->Is<sem::F32>());
-  EXPECT_EQ(StmtOf(p), assign);
+    ASSERT_NE(TypeOf(v), nullptr);
+    ASSERT_TRUE(TypeOf(v)->Is<sem::Reference>());
+    EXPECT_TRUE(TypeOf(v)->UnwrapRef()->Is<sem::F32>());
+    EXPECT_EQ(StmtOf(v), p_decl);
+    ASSERT_NE(TypeOf(p), nullptr);
+    ASSERT_TRUE(TypeOf(p)->Is<sem::Pointer>());
+    EXPECT_TRUE(TypeOf(p)->UnwrapPtr()->Is<sem::F32>());
+    EXPECT_EQ(StmtOf(p), assign);
 }
 
 TEST_F(ResolverTest, Expr_Call_Function) {
-  Func("my_func", ast::VariableList{}, ty.f32(), {Return(0.0f)},
-       ast::AttributeList{});
+    Func("my_func", ast::VariableList{}, ty.f32(), {Return(0.0f)}, ast::AttributeList{});
 
-  auto* call = Call("my_func");
-  WrapInFunction(call);
+    auto* call = Call("my_func");
+    WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(call), nullptr);
-  EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
+    ASSERT_NE(TypeOf(call), nullptr);
+    EXPECT_TRUE(TypeOf(call)->Is<sem::F32>());
 }
 
 TEST_F(ResolverTest, Expr_Identifier_Unknown) {
-  auto* a = Expr("a");
-  WrapInFunction(a);
+    auto* a = Expr("a");
+    WrapInFunction(a);
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 }
 
 TEST_F(ResolverTest, Function_Parameters) {
-  auto* param_a = Param("a", ty.f32());
-  auto* param_b = Param("b", ty.i32());
-  auto* param_c = Param("c", ty.u32());
+    auto* param_a = Param("a", ty.f32());
+    auto* param_b = Param("b", ty.i32());
+    auto* param_c = Param("c", ty.u32());
 
-  auto* func = Func("my_func",
-                    ast::VariableList{
-                        param_a,
-                        param_b,
-                        param_c,
-                    },
-                    ty.void_(), {});
+    auto* func = Func("my_func",
+                      ast::VariableList{
+                          param_a,
+                          param_b,
+                          param_c,
+                      },
+                      ty.void_(), {});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* func_sem = Sem().Get(func);
-  ASSERT_NE(func_sem, nullptr);
-  EXPECT_EQ(func_sem->Parameters().size(), 3u);
-  EXPECT_TRUE(func_sem->Parameters()[0]->Type()->Is<sem::F32>());
-  EXPECT_TRUE(func_sem->Parameters()[1]->Type()->Is<sem::I32>());
-  EXPECT_TRUE(func_sem->Parameters()[2]->Type()->Is<sem::U32>());
-  EXPECT_EQ(func_sem->Parameters()[0]->Declaration(), param_a);
-  EXPECT_EQ(func_sem->Parameters()[1]->Declaration(), param_b);
-  EXPECT_EQ(func_sem->Parameters()[2]->Declaration(), param_c);
-  EXPECT_TRUE(func_sem->ReturnType()->Is<sem::Void>());
+    auto* func_sem = Sem().Get(func);
+    ASSERT_NE(func_sem, nullptr);
+    EXPECT_EQ(func_sem->Parameters().size(), 3u);
+    EXPECT_TRUE(func_sem->Parameters()[0]->Type()->Is<sem::F32>());
+    EXPECT_TRUE(func_sem->Parameters()[1]->Type()->Is<sem::I32>());
+    EXPECT_TRUE(func_sem->Parameters()[2]->Type()->Is<sem::U32>());
+    EXPECT_EQ(func_sem->Parameters()[0]->Declaration(), param_a);
+    EXPECT_EQ(func_sem->Parameters()[1]->Declaration(), param_b);
+    EXPECT_EQ(func_sem->Parameters()[2]->Declaration(), param_c);
+    EXPECT_TRUE(func_sem->ReturnType()->Is<sem::Void>());
 }
 
 TEST_F(ResolverTest, Function_RegisterInputOutputVariables) {
-  auto* s = Structure("S", {Member("m", ty.u32())});
+    auto* s = Structure("S", {Member("m", ty.u32())});
 
-  auto* sb_var = Global("sb_var", ty.Of(s), ast::StorageClass::kStorage,
-                        ast::Access::kReadWrite,
-                        ast::AttributeList{
-                            create<ast::BindingAttribute>(0),
-                            create<ast::GroupAttribute>(0),
-                        });
-  auto* wg_var = Global("wg_var", ty.f32(), ast::StorageClass::kWorkgroup);
-  auto* priv_var = Global("priv_var", ty.f32(), ast::StorageClass::kPrivate);
+    auto* sb_var = Global("sb_var", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+                          ast::AttributeList{
+                              create<ast::BindingAttribute>(0),
+                              create<ast::GroupAttribute>(0),
+                          });
+    auto* wg_var = Global("wg_var", ty.f32(), ast::StorageClass::kWorkgroup);
+    auto* priv_var = Global("priv_var", ty.f32(), ast::StorageClass::kPrivate);
 
-  auto* func = Func("my_func", ast::VariableList{}, ty.void_(),
-                    {
-                        Assign("wg_var", "wg_var"),
-                        Assign("sb_var", "sb_var"),
-                        Assign("priv_var", "priv_var"),
-                    });
+    auto* func = Func("my_func", ast::VariableList{}, ty.void_(),
+                      {
+                          Assign("wg_var", "wg_var"),
+                          Assign("sb_var", "sb_var"),
+                          Assign("priv_var", "priv_var"),
+                      });
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* func_sem = Sem().Get(func);
-  ASSERT_NE(func_sem, nullptr);
-  EXPECT_EQ(func_sem->Parameters().size(), 0u);
-  EXPECT_TRUE(func_sem->ReturnType()->Is<sem::Void>());
+    auto* func_sem = Sem().Get(func);
+    ASSERT_NE(func_sem, nullptr);
+    EXPECT_EQ(func_sem->Parameters().size(), 0u);
+    EXPECT_TRUE(func_sem->ReturnType()->Is<sem::Void>());
 
-  const auto& vars = func_sem->TransitivelyReferencedGlobals();
-  ASSERT_EQ(vars.size(), 3u);
-  EXPECT_EQ(vars[0]->Declaration(), wg_var);
-  EXPECT_EQ(vars[1]->Declaration(), sb_var);
-  EXPECT_EQ(vars[2]->Declaration(), priv_var);
+    const auto& vars = func_sem->TransitivelyReferencedGlobals();
+    ASSERT_EQ(vars.size(), 3u);
+    EXPECT_EQ(vars[0]->Declaration(), wg_var);
+    EXPECT_EQ(vars[1]->Declaration(), sb_var);
+    EXPECT_EQ(vars[2]->Declaration(), priv_var);
 }
 
 TEST_F(ResolverTest, Function_RegisterInputOutputVariables_SubFunction) {
-  auto* s = Structure("S", {Member("m", ty.u32())});
+    auto* s = Structure("S", {Member("m", ty.u32())});
 
-  auto* sb_var = Global("sb_var", ty.Of(s), ast::StorageClass::kStorage,
-                        ast::Access::kReadWrite,
-                        ast::AttributeList{
-                            create<ast::BindingAttribute>(0),
-                            create<ast::GroupAttribute>(0),
-                        });
-  auto* wg_var = Global("wg_var", ty.f32(), ast::StorageClass::kWorkgroup);
-  auto* priv_var = Global("priv_var", ty.f32(), ast::StorageClass::kPrivate);
+    auto* sb_var = Global("sb_var", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+                          ast::AttributeList{
+                              create<ast::BindingAttribute>(0),
+                              create<ast::GroupAttribute>(0),
+                          });
+    auto* wg_var = Global("wg_var", ty.f32(), ast::StorageClass::kWorkgroup);
+    auto* priv_var = Global("priv_var", ty.f32(), ast::StorageClass::kPrivate);
 
-  Func("my_func", ast::VariableList{}, ty.f32(),
-       {Assign("wg_var", "wg_var"), Assign("sb_var", "sb_var"),
-        Assign("priv_var", "priv_var"), Return(0.0f)},
-       ast::AttributeList{});
+    Func("my_func", ast::VariableList{}, ty.f32(),
+         {Assign("wg_var", "wg_var"), Assign("sb_var", "sb_var"), Assign("priv_var", "priv_var"),
+          Return(0.0f)},
+         ast::AttributeList{});
 
-  auto* func2 = Func("func", ast::VariableList{}, ty.void_(),
-                     {
-                         WrapInStatement(Call("my_func")),
-                     },
-                     ast::AttributeList{});
+    auto* func2 = Func("func", ast::VariableList{}, ty.void_(),
+                       {
+                           WrapInStatement(Call("my_func")),
+                       },
+                       ast::AttributeList{});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* func2_sem = Sem().Get(func2);
-  ASSERT_NE(func2_sem, nullptr);
-  EXPECT_EQ(func2_sem->Parameters().size(), 0u);
+    auto* func2_sem = Sem().Get(func2);
+    ASSERT_NE(func2_sem, nullptr);
+    EXPECT_EQ(func2_sem->Parameters().size(), 0u);
 
-  const auto& vars = func2_sem->TransitivelyReferencedGlobals();
-  ASSERT_EQ(vars.size(), 3u);
-  EXPECT_EQ(vars[0]->Declaration(), wg_var);
-  EXPECT_EQ(vars[1]->Declaration(), sb_var);
-  EXPECT_EQ(vars[2]->Declaration(), priv_var);
+    const auto& vars = func2_sem->TransitivelyReferencedGlobals();
+    ASSERT_EQ(vars.size(), 3u);
+    EXPECT_EQ(vars[0]->Declaration(), wg_var);
+    EXPECT_EQ(vars[1]->Declaration(), sb_var);
+    EXPECT_EQ(vars[2]->Declaration(), priv_var);
 }
 
 TEST_F(ResolverTest, Function_NotRegisterFunctionVariable) {
-  auto* func = Func("my_func", ast::VariableList{}, ty.void_(),
-                    {
-                        Decl(Var("var", ty.f32())),
-                        Assign("var", 1.f),
-                    });
+    auto* func = Func("my_func", ast::VariableList{}, ty.void_(),
+                      {
+                          Decl(Var("var", ty.f32())),
+                          Assign("var", 1.f),
+                      });
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* func_sem = Sem().Get(func);
-  ASSERT_NE(func_sem, nullptr);
+    auto* func_sem = Sem().Get(func);
+    ASSERT_NE(func_sem, nullptr);
 
-  EXPECT_EQ(func_sem->TransitivelyReferencedGlobals().size(), 0u);
-  EXPECT_TRUE(func_sem->ReturnType()->Is<sem::Void>());
+    EXPECT_EQ(func_sem->TransitivelyReferencedGlobals().size(), 0u);
+    EXPECT_TRUE(func_sem->ReturnType()->Is<sem::Void>());
 }
 
 TEST_F(ResolverTest, Function_NotRegisterFunctionConstant) {
-  auto* func = Func("my_func", ast::VariableList{}, ty.void_(),
-                    {
-                        Decl(Const("var", ty.f32(), Construct(ty.f32()))),
-                    });
+    auto* func = Func("my_func", ast::VariableList{}, ty.void_(),
+                      {
+                          Decl(Let("var", ty.f32(), Construct(ty.f32()))),
+                      });
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* func_sem = Sem().Get(func);
-  ASSERT_NE(func_sem, nullptr);
+    auto* func_sem = Sem().Get(func);
+    ASSERT_NE(func_sem, nullptr);
 
-  EXPECT_EQ(func_sem->TransitivelyReferencedGlobals().size(), 0u);
-  EXPECT_TRUE(func_sem->ReturnType()->Is<sem::Void>());
+    EXPECT_EQ(func_sem->TransitivelyReferencedGlobals().size(), 0u);
+    EXPECT_TRUE(func_sem->ReturnType()->Is<sem::Void>());
 }
 
 TEST_F(ResolverTest, Function_NotRegisterFunctionParams) {
-  auto* func = Func("my_func", {Const("var", ty.f32(), Construct(ty.f32()))},
-                    ty.void_(), {});
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* func = Func("my_func", {Let("var", ty.f32(), Construct(ty.f32()))}, ty.void_(), {});
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* func_sem = Sem().Get(func);
-  ASSERT_NE(func_sem, nullptr);
+    auto* func_sem = Sem().Get(func);
+    ASSERT_NE(func_sem, nullptr);
 
-  EXPECT_EQ(func_sem->TransitivelyReferencedGlobals().size(), 0u);
-  EXPECT_TRUE(func_sem->ReturnType()->Is<sem::Void>());
+    EXPECT_EQ(func_sem->TransitivelyReferencedGlobals().size(), 0u);
+    EXPECT_TRUE(func_sem->ReturnType()->Is<sem::Void>());
 }
 
 TEST_F(ResolverTest, Function_CallSites) {
-  auto* foo = Func("foo", ast::VariableList{}, ty.void_(), {});
+    auto* foo = Func("foo", ast::VariableList{}, ty.void_(), {});
 
-  auto* call_1 = Call("foo");
-  auto* call_2 = Call("foo");
-  auto* bar = Func("bar", ast::VariableList{}, ty.void_(),
-                   {
-                       CallStmt(call_1),
-                       CallStmt(call_2),
-                   });
+    auto* call_1 = Call("foo");
+    auto* call_2 = Call("foo");
+    auto* bar = Func("bar", ast::VariableList{}, ty.void_(),
+                     {
+                         CallStmt(call_1),
+                         CallStmt(call_2),
+                     });
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* foo_sem = Sem().Get(foo);
-  ASSERT_NE(foo_sem, nullptr);
-  ASSERT_EQ(foo_sem->CallSites().size(), 2u);
-  EXPECT_EQ(foo_sem->CallSites()[0]->Declaration(), call_1);
-  EXPECT_EQ(foo_sem->CallSites()[1]->Declaration(), call_2);
+    auto* foo_sem = Sem().Get(foo);
+    ASSERT_NE(foo_sem, nullptr);
+    ASSERT_EQ(foo_sem->CallSites().size(), 2u);
+    EXPECT_EQ(foo_sem->CallSites()[0]->Declaration(), call_1);
+    EXPECT_EQ(foo_sem->CallSites()[1]->Declaration(), call_2);
 
-  auto* bar_sem = Sem().Get(bar);
-  ASSERT_NE(bar_sem, nullptr);
-  EXPECT_EQ(bar_sem->CallSites().size(), 0u);
+    auto* bar_sem = Sem().Get(bar);
+    ASSERT_NE(bar_sem, nullptr);
+    EXPECT_EQ(bar_sem->CallSites().size(), 0u);
 }
 
 TEST_F(ResolverTest, Function_WorkgroupSize_NotSet) {
-  // @stage(compute) @workgroup_size(1)
-  // fn main() {}
-  auto* func = Func("main", ast::VariableList{}, ty.void_(), {}, {});
+    // @stage(compute) @workgroup_size(1)
+    // fn main() {}
+    auto* func = Func("main", ast::VariableList{}, ty.void_(), {}, {});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* func_sem = Sem().Get(func);
-  ASSERT_NE(func_sem, nullptr);
+    auto* func_sem = Sem().Get(func);
+    ASSERT_NE(func_sem, nullptr);
 
-  EXPECT_EQ(func_sem->WorkgroupSize()[0].value, 1u);
-  EXPECT_EQ(func_sem->WorkgroupSize()[1].value, 1u);
-  EXPECT_EQ(func_sem->WorkgroupSize()[2].value, 1u);
-  EXPECT_EQ(func_sem->WorkgroupSize()[0].overridable_const, nullptr);
-  EXPECT_EQ(func_sem->WorkgroupSize()[1].overridable_const, nullptr);
-  EXPECT_EQ(func_sem->WorkgroupSize()[2].overridable_const, nullptr);
+    EXPECT_EQ(func_sem->WorkgroupSize()[0].value, 1u);
+    EXPECT_EQ(func_sem->WorkgroupSize()[1].value, 1u);
+    EXPECT_EQ(func_sem->WorkgroupSize()[2].value, 1u);
+    EXPECT_EQ(func_sem->WorkgroupSize()[0].overridable_const, nullptr);
+    EXPECT_EQ(func_sem->WorkgroupSize()[1].overridable_const, nullptr);
+    EXPECT_EQ(func_sem->WorkgroupSize()[2].overridable_const, nullptr);
 }
 
 TEST_F(ResolverTest, Function_WorkgroupSize_Literals) {
-  // @stage(compute) @workgroup_size(8, 2, 3)
-  // fn main() {}
-  auto* func =
-      Func("main", ast::VariableList{}, ty.void_(), {},
-           {Stage(ast::PipelineStage::kCompute), WorkgroupSize(8, 2, 3)});
+    // @stage(compute) @workgroup_size(8, 2, 3)
+    // fn main() {}
+    auto* func = Func("main", ast::VariableList{}, ty.void_(), {},
+                      {Stage(ast::PipelineStage::kCompute), WorkgroupSize(8_i, 2_i, 3_i)});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* func_sem = Sem().Get(func);
-  ASSERT_NE(func_sem, nullptr);
+    auto* func_sem = Sem().Get(func);
+    ASSERT_NE(func_sem, nullptr);
 
-  EXPECT_EQ(func_sem->WorkgroupSize()[0].value, 8u);
-  EXPECT_EQ(func_sem->WorkgroupSize()[1].value, 2u);
-  EXPECT_EQ(func_sem->WorkgroupSize()[2].value, 3u);
-  EXPECT_EQ(func_sem->WorkgroupSize()[0].overridable_const, nullptr);
-  EXPECT_EQ(func_sem->WorkgroupSize()[1].overridable_const, nullptr);
-  EXPECT_EQ(func_sem->WorkgroupSize()[2].overridable_const, nullptr);
+    EXPECT_EQ(func_sem->WorkgroupSize()[0].value, 8u);
+    EXPECT_EQ(func_sem->WorkgroupSize()[1].value, 2u);
+    EXPECT_EQ(func_sem->WorkgroupSize()[2].value, 3u);
+    EXPECT_EQ(func_sem->WorkgroupSize()[0].overridable_const, nullptr);
+    EXPECT_EQ(func_sem->WorkgroupSize()[1].overridable_const, nullptr);
+    EXPECT_EQ(func_sem->WorkgroupSize()[2].overridable_const, nullptr);
 }
 
 TEST_F(ResolverTest, Function_WorkgroupSize_Consts) {
-  // let width = 16;
-  // let height = 8;
-  // let depth = 2;
-  // @stage(compute) @workgroup_size(width, height, depth)
-  // fn main() {}
-  GlobalConst("width", ty.i32(), Expr(16));
-  GlobalConst("height", ty.i32(), Expr(8));
-  GlobalConst("depth", ty.i32(), Expr(2));
-  auto* func = Func("main", ast::VariableList{}, ty.void_(), {},
-                    {Stage(ast::PipelineStage::kCompute),
-                     WorkgroupSize("width", "height", "depth")});
+    // let width = 16i;
+    // let height = 8i;
+    // let depth = 2i;
+    // @stage(compute) @workgroup_size(width, height, depth)
+    // fn main() {}
+    GlobalConst("width", ty.i32(), Expr(16_i));
+    GlobalConst("height", ty.i32(), Expr(8_i));
+    GlobalConst("depth", ty.i32(), Expr(2_i));
+    auto* func =
+        Func("main", ast::VariableList{}, ty.void_(), {},
+             {Stage(ast::PipelineStage::kCompute), WorkgroupSize("width", "height", "depth")});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* func_sem = Sem().Get(func);
-  ASSERT_NE(func_sem, nullptr);
+    auto* func_sem = Sem().Get(func);
+    ASSERT_NE(func_sem, nullptr);
 
-  EXPECT_EQ(func_sem->WorkgroupSize()[0].value, 16u);
-  EXPECT_EQ(func_sem->WorkgroupSize()[1].value, 8u);
-  EXPECT_EQ(func_sem->WorkgroupSize()[2].value, 2u);
-  EXPECT_EQ(func_sem->WorkgroupSize()[0].overridable_const, nullptr);
-  EXPECT_EQ(func_sem->WorkgroupSize()[1].overridable_const, nullptr);
-  EXPECT_EQ(func_sem->WorkgroupSize()[2].overridable_const, nullptr);
+    EXPECT_EQ(func_sem->WorkgroupSize()[0].value, 16u);
+    EXPECT_EQ(func_sem->WorkgroupSize()[1].value, 8u);
+    EXPECT_EQ(func_sem->WorkgroupSize()[2].value, 2u);
+    EXPECT_EQ(func_sem->WorkgroupSize()[0].overridable_const, nullptr);
+    EXPECT_EQ(func_sem->WorkgroupSize()[1].overridable_const, nullptr);
+    EXPECT_EQ(func_sem->WorkgroupSize()[2].overridable_const, nullptr);
 }
 
 TEST_F(ResolverTest, Function_WorkgroupSize_Consts_NestedInitializer) {
-  // let width = i32(i32(i32(8)));
-  // let height = i32(i32(i32(4)));
-  // @stage(compute) @workgroup_size(width, height)
-  // fn main() {}
-  GlobalConst("width", ty.i32(),
-              Construct(ty.i32(), Construct(ty.i32(), Construct(ty.i32(), 8))));
-  GlobalConst("height", ty.i32(),
-              Construct(ty.i32(), Construct(ty.i32(), Construct(ty.i32(), 4))));
-  auto* func = Func(
-      "main", ast::VariableList{}, ty.void_(), {},
-      {Stage(ast::PipelineStage::kCompute), WorkgroupSize("width", "height")});
+    // let width = i32(i32(i32(8i)));
+    // let height = i32(i32(i32(4i)));
+    // @stage(compute) @workgroup_size(width, height)
+    // fn main() {}
+    GlobalConst("width", ty.i32(),
+                Construct(ty.i32(), Construct(ty.i32(), Construct(ty.i32(), 8_i))));
+    GlobalConst("height", ty.i32(),
+                Construct(ty.i32(), Construct(ty.i32(), Construct(ty.i32(), 4_i))));
+    auto* func = Func("main", ast::VariableList{}, ty.void_(), {},
+                      {Stage(ast::PipelineStage::kCompute), WorkgroupSize("width", "height")});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* func_sem = Sem().Get(func);
-  ASSERT_NE(func_sem, nullptr);
+    auto* func_sem = Sem().Get(func);
+    ASSERT_NE(func_sem, nullptr);
 
-  EXPECT_EQ(func_sem->WorkgroupSize()[0].value, 8u);
-  EXPECT_EQ(func_sem->WorkgroupSize()[1].value, 4u);
-  EXPECT_EQ(func_sem->WorkgroupSize()[2].value, 1u);
-  EXPECT_EQ(func_sem->WorkgroupSize()[0].overridable_const, nullptr);
-  EXPECT_EQ(func_sem->WorkgroupSize()[1].overridable_const, nullptr);
-  EXPECT_EQ(func_sem->WorkgroupSize()[2].overridable_const, nullptr);
+    EXPECT_EQ(func_sem->WorkgroupSize()[0].value, 8u);
+    EXPECT_EQ(func_sem->WorkgroupSize()[1].value, 4u);
+    EXPECT_EQ(func_sem->WorkgroupSize()[2].value, 1u);
+    EXPECT_EQ(func_sem->WorkgroupSize()[0].overridable_const, nullptr);
+    EXPECT_EQ(func_sem->WorkgroupSize()[1].overridable_const, nullptr);
+    EXPECT_EQ(func_sem->WorkgroupSize()[2].overridable_const, nullptr);
 }
 
 TEST_F(ResolverTest, Function_WorkgroupSize_OverridableConsts) {
-  // @id(0) override width = 16;
-  // @id(1) override height = 8;
-  // @id(2) override depth = 2;
-  // @stage(compute) @workgroup_size(width, height, depth)
-  // fn main() {}
-  auto* width = Override("width", ty.i32(), Expr(16), {Id(0)});
-  auto* height = Override("height", ty.i32(), Expr(8), {Id(1)});
-  auto* depth = Override("depth", ty.i32(), Expr(2), {Id(2)});
-  auto* func = Func("main", ast::VariableList{}, ty.void_(), {},
-                    {Stage(ast::PipelineStage::kCompute),
-                     WorkgroupSize("width", "height", "depth")});
+    // @id(0) override width = 16i;
+    // @id(1) override height = 8i;
+    // @id(2) override depth = 2i;
+    // @stage(compute) @workgroup_size(width, height, depth)
+    // fn main() {}
+    auto* width = Override("width", ty.i32(), Expr(16_i), {Id(0)});
+    auto* height = Override("height", ty.i32(), Expr(8_i), {Id(1)});
+    auto* depth = Override("depth", ty.i32(), Expr(2_i), {Id(2)});
+    auto* func =
+        Func("main", ast::VariableList{}, ty.void_(), {},
+             {Stage(ast::PipelineStage::kCompute), WorkgroupSize("width", "height", "depth")});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* func_sem = Sem().Get(func);
-  ASSERT_NE(func_sem, nullptr);
+    auto* func_sem = Sem().Get(func);
+    ASSERT_NE(func_sem, nullptr);
 
-  EXPECT_EQ(func_sem->WorkgroupSize()[0].value, 16u);
-  EXPECT_EQ(func_sem->WorkgroupSize()[1].value, 8u);
-  EXPECT_EQ(func_sem->WorkgroupSize()[2].value, 2u);
-  EXPECT_EQ(func_sem->WorkgroupSize()[0].overridable_const, width);
-  EXPECT_EQ(func_sem->WorkgroupSize()[1].overridable_const, height);
-  EXPECT_EQ(func_sem->WorkgroupSize()[2].overridable_const, depth);
+    EXPECT_EQ(func_sem->WorkgroupSize()[0].value, 16u);
+    EXPECT_EQ(func_sem->WorkgroupSize()[1].value, 8u);
+    EXPECT_EQ(func_sem->WorkgroupSize()[2].value, 2u);
+    EXPECT_EQ(func_sem->WorkgroupSize()[0].overridable_const, width);
+    EXPECT_EQ(func_sem->WorkgroupSize()[1].overridable_const, height);
+    EXPECT_EQ(func_sem->WorkgroupSize()[2].overridable_const, depth);
 }
 
 TEST_F(ResolverTest, Function_WorkgroupSize_OverridableConsts_NoInit) {
-  // @id(0) override width : i32;
-  // @id(1) override height : i32;
-  // @id(2) override depth : i32;
-  // @stage(compute) @workgroup_size(width, height, depth)
-  // fn main() {}
-  auto* width = Override("width", ty.i32(), nullptr, {Id(0)});
-  auto* height = Override("height", ty.i32(), nullptr, {Id(1)});
-  auto* depth = Override("depth", ty.i32(), nullptr, {Id(2)});
-  auto* func = Func("main", ast::VariableList{}, ty.void_(), {},
-                    {Stage(ast::PipelineStage::kCompute),
-                     WorkgroupSize("width", "height", "depth")});
+    // @id(0) override width : i32;
+    // @id(1) override height : i32;
+    // @id(2) override depth : i32;
+    // @stage(compute) @workgroup_size(width, height, depth)
+    // fn main() {}
+    auto* width = Override("width", ty.i32(), nullptr, {Id(0)});
+    auto* height = Override("height", ty.i32(), nullptr, {Id(1)});
+    auto* depth = Override("depth", ty.i32(), nullptr, {Id(2)});
+    auto* func =
+        Func("main", ast::VariableList{}, ty.void_(), {},
+             {Stage(ast::PipelineStage::kCompute), WorkgroupSize("width", "height", "depth")});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* func_sem = Sem().Get(func);
-  ASSERT_NE(func_sem, nullptr);
+    auto* func_sem = Sem().Get(func);
+    ASSERT_NE(func_sem, nullptr);
 
-  EXPECT_EQ(func_sem->WorkgroupSize()[0].value, 0u);
-  EXPECT_EQ(func_sem->WorkgroupSize()[1].value, 0u);
-  EXPECT_EQ(func_sem->WorkgroupSize()[2].value, 0u);
-  EXPECT_EQ(func_sem->WorkgroupSize()[0].overridable_const, width);
-  EXPECT_EQ(func_sem->WorkgroupSize()[1].overridable_const, height);
-  EXPECT_EQ(func_sem->WorkgroupSize()[2].overridable_const, depth);
+    EXPECT_EQ(func_sem->WorkgroupSize()[0].value, 0u);
+    EXPECT_EQ(func_sem->WorkgroupSize()[1].value, 0u);
+    EXPECT_EQ(func_sem->WorkgroupSize()[2].value, 0u);
+    EXPECT_EQ(func_sem->WorkgroupSize()[0].overridable_const, width);
+    EXPECT_EQ(func_sem->WorkgroupSize()[1].overridable_const, height);
+    EXPECT_EQ(func_sem->WorkgroupSize()[2].overridable_const, depth);
 }
 
 TEST_F(ResolverTest, Function_WorkgroupSize_Mixed) {
-  // @id(1) override height = 2;
-  // let depth = 3;
-  // @stage(compute) @workgroup_size(8, height, depth)
-  // fn main() {}
-  auto* height = Override("height", ty.i32(), Expr(2), {Id(0)});
-  GlobalConst("depth", ty.i32(), Expr(3));
-  auto* func = Func("main", ast::VariableList{}, ty.void_(), {},
-                    {Stage(ast::PipelineStage::kCompute),
-                     WorkgroupSize(8, "height", "depth")});
+    // @id(1) override height = 2i;
+    // let depth = 3i;
+    // @stage(compute) @workgroup_size(8, height, depth)
+    // fn main() {}
+    auto* height = Override("height", ty.i32(), Expr(2_i), {Id(0)});
+    GlobalConst("depth", ty.i32(), Expr(3_i));
+    auto* func = Func("main", ast::VariableList{}, ty.void_(), {},
+                      {Stage(ast::PipelineStage::kCompute), WorkgroupSize(8_i, "height", "depth")});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* func_sem = Sem().Get(func);
-  ASSERT_NE(func_sem, nullptr);
+    auto* func_sem = Sem().Get(func);
+    ASSERT_NE(func_sem, nullptr);
 
-  EXPECT_EQ(func_sem->WorkgroupSize()[0].value, 8u);
-  EXPECT_EQ(func_sem->WorkgroupSize()[1].value, 2u);
-  EXPECT_EQ(func_sem->WorkgroupSize()[2].value, 3u);
-  EXPECT_EQ(func_sem->WorkgroupSize()[0].overridable_const, nullptr);
-  EXPECT_EQ(func_sem->WorkgroupSize()[1].overridable_const, height);
-  EXPECT_EQ(func_sem->WorkgroupSize()[2].overridable_const, nullptr);
+    EXPECT_EQ(func_sem->WorkgroupSize()[0].value, 8u);
+    EXPECT_EQ(func_sem->WorkgroupSize()[1].value, 2u);
+    EXPECT_EQ(func_sem->WorkgroupSize()[2].value, 3u);
+    EXPECT_EQ(func_sem->WorkgroupSize()[0].overridable_const, nullptr);
+    EXPECT_EQ(func_sem->WorkgroupSize()[1].overridable_const, height);
+    EXPECT_EQ(func_sem->WorkgroupSize()[2].overridable_const, nullptr);
 }
 
 TEST_F(ResolverTest, Expr_MemberAccessor_Struct) {
-  auto* st = Structure("S", {Member("first_member", ty.i32()),
-                             Member("second_member", ty.f32())});
-  Global("my_struct", ty.Of(st), ast::StorageClass::kPrivate);
+    auto* st =
+        Structure("S", {Member("first_member", ty.i32()), Member("second_member", ty.f32())});
+    Global("my_struct", ty.Of(st), ast::StorageClass::kPrivate);
 
-  auto* mem = MemberAccessor("my_struct", "second_member");
-  WrapInFunction(mem);
+    auto* mem = MemberAccessor("my_struct", "second_member");
+    WrapInFunction(mem);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(mem), nullptr);
-  ASSERT_TRUE(TypeOf(mem)->Is<sem::Reference>());
+    ASSERT_NE(TypeOf(mem), nullptr);
+    ASSERT_TRUE(TypeOf(mem)->Is<sem::Reference>());
 
-  auto* ref = TypeOf(mem)->As<sem::Reference>();
-  EXPECT_TRUE(ref->StoreType()->Is<sem::F32>());
-  auto* sma = Sem().Get(mem)->As<sem::StructMemberAccess>();
-  ASSERT_NE(sma, nullptr);
-  EXPECT_TRUE(sma->Member()->Type()->Is<sem::F32>());
-  EXPECT_EQ(sma->Member()->Index(), 1u);
-  EXPECT_EQ(sma->Member()->Declaration()->symbol,
-            Symbols().Get("second_member"));
+    auto* ref = TypeOf(mem)->As<sem::Reference>();
+    EXPECT_TRUE(ref->StoreType()->Is<sem::F32>());
+    auto* sma = Sem().Get(mem)->As<sem::StructMemberAccess>();
+    ASSERT_NE(sma, nullptr);
+    EXPECT_TRUE(sma->Member()->Type()->Is<sem::F32>());
+    EXPECT_EQ(sma->Member()->Index(), 1u);
+    EXPECT_EQ(sma->Member()->Declaration()->symbol, Symbols().Get("second_member"));
 }
 
 TEST_F(ResolverTest, Expr_MemberAccessor_Struct_Alias) {
-  auto* st = Structure("S", {Member("first_member", ty.i32()),
-                             Member("second_member", ty.f32())});
-  auto* alias = Alias("alias", ty.Of(st));
-  Global("my_struct", ty.Of(alias), ast::StorageClass::kPrivate);
+    auto* st =
+        Structure("S", {Member("first_member", ty.i32()), Member("second_member", ty.f32())});
+    auto* alias = Alias("alias", ty.Of(st));
+    Global("my_struct", ty.Of(alias), ast::StorageClass::kPrivate);
 
-  auto* mem = MemberAccessor("my_struct", "second_member");
-  WrapInFunction(mem);
+    auto* mem = MemberAccessor("my_struct", "second_member");
+    WrapInFunction(mem);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(mem), nullptr);
-  ASSERT_TRUE(TypeOf(mem)->Is<sem::Reference>());
+    ASSERT_NE(TypeOf(mem), nullptr);
+    ASSERT_TRUE(TypeOf(mem)->Is<sem::Reference>());
 
-  auto* ref = TypeOf(mem)->As<sem::Reference>();
-  EXPECT_TRUE(ref->StoreType()->Is<sem::F32>());
-  auto* sma = Sem().Get(mem)->As<sem::StructMemberAccess>();
-  ASSERT_NE(sma, nullptr);
-  EXPECT_TRUE(sma->Member()->Type()->Is<sem::F32>());
-  EXPECT_EQ(sma->Member()->Index(), 1u);
+    auto* ref = TypeOf(mem)->As<sem::Reference>();
+    EXPECT_TRUE(ref->StoreType()->Is<sem::F32>());
+    auto* sma = Sem().Get(mem)->As<sem::StructMemberAccess>();
+    ASSERT_NE(sma, nullptr);
+    EXPECT_TRUE(sma->Member()->Type()->Is<sem::F32>());
+    EXPECT_EQ(sma->Member()->Index(), 1u);
 }
 
 TEST_F(ResolverTest, Expr_MemberAccessor_VectorSwizzle) {
-  Global("my_vec", ty.vec4<f32>(), ast::StorageClass::kPrivate);
+    Global("my_vec", ty.vec4<f32>(), ast::StorageClass::kPrivate);
 
-  auto* mem = MemberAccessor("my_vec", "xzyw");
-  WrapInFunction(mem);
+    auto* mem = MemberAccessor("my_vec", "xzyw");
+    WrapInFunction(mem);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(mem), nullptr);
-  ASSERT_TRUE(TypeOf(mem)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(mem)->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(TypeOf(mem)->As<sem::Vector>()->Width(), 4u);
-  ASSERT_TRUE(Sem().Get(mem)->Is<sem::Swizzle>());
-  EXPECT_THAT(Sem().Get(mem)->As<sem::Swizzle>()->Indices(),
-              ElementsAre(0, 2, 1, 3));
+    ASSERT_NE(TypeOf(mem), nullptr);
+    ASSERT_TRUE(TypeOf(mem)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(mem)->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(TypeOf(mem)->As<sem::Vector>()->Width(), 4u);
+    ASSERT_TRUE(Sem().Get(mem)->Is<sem::Swizzle>());
+    EXPECT_THAT(Sem().Get(mem)->As<sem::Swizzle>()->Indices(), ElementsAre(0, 2, 1, 3));
 }
 
 TEST_F(ResolverTest, Expr_MemberAccessor_VectorSwizzle_SingleElement) {
-  Global("my_vec", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+    Global("my_vec", ty.vec3<f32>(), ast::StorageClass::kPrivate);
 
-  auto* mem = MemberAccessor("my_vec", "b");
-  WrapInFunction(mem);
+    auto* mem = MemberAccessor("my_vec", "b");
+    WrapInFunction(mem);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(mem), nullptr);
-  ASSERT_TRUE(TypeOf(mem)->Is<sem::Reference>());
+    ASSERT_NE(TypeOf(mem), nullptr);
+    ASSERT_TRUE(TypeOf(mem)->Is<sem::Reference>());
 
-  auto* ref = TypeOf(mem)->As<sem::Reference>();
-  ASSERT_TRUE(ref->StoreType()->Is<sem::F32>());
-  ASSERT_TRUE(Sem().Get(mem)->Is<sem::Swizzle>());
-  EXPECT_THAT(Sem().Get(mem)->As<sem::Swizzle>()->Indices(), ElementsAre(2));
+    auto* ref = TypeOf(mem)->As<sem::Reference>();
+    ASSERT_TRUE(ref->StoreType()->Is<sem::F32>());
+    ASSERT_TRUE(Sem().Get(mem)->Is<sem::Swizzle>());
+    EXPECT_THAT(Sem().Get(mem)->As<sem::Swizzle>()->Indices(), ElementsAre(2));
 }
 
 TEST_F(ResolverTest, Expr_Accessor_MultiLevel) {
-  // struct b {
-  //   vec4<f32> foo
-  // }
-  // struct A {
-  //   array<b, 3> mem
-  // }
-  // var c : A
-  // c.mem[0].foo.yx
-  //   -> vec2<f32>
-  //
-  // fn f() {
-  //   c.mem[0].foo
-  // }
-  //
+    // struct b {
+    //   vec4<f32> foo
+    // }
+    // struct A {
+    //   array<b, 3u> mem
+    // }
+    // var c : A
+    // c.mem[0].foo.yx
+    //   -> vec2<f32>
+    //
+    // fn f() {
+    //   c.mem[0].foo
+    // }
+    //
 
-  auto* stB = Structure("B", {Member("foo", ty.vec4<f32>())});
-  auto* stA = Structure("A", {Member("mem", ty.array(ty.Of(stB), 3))});
-  Global("c", ty.Of(stA), ast::StorageClass::kPrivate);
+    auto* stB = Structure("B", {Member("foo", ty.vec4<f32>())});
+    auto* stA = Structure("A", {Member("mem", ty.array(ty.Of(stB), 3_i))});
+    Global("c", ty.Of(stA), ast::StorageClass::kPrivate);
 
-  auto* mem = MemberAccessor(
-      MemberAccessor(IndexAccessor(MemberAccessor("c", "mem"), 0), "foo"),
-      "yx");
-  WrapInFunction(mem);
+    auto* mem =
+        MemberAccessor(MemberAccessor(IndexAccessor(MemberAccessor("c", "mem"), 0_i), "foo"), "yx");
+    WrapInFunction(mem);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(mem), nullptr);
-  ASSERT_TRUE(TypeOf(mem)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(mem)->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(TypeOf(mem)->As<sem::Vector>()->Width(), 2u);
-  ASSERT_TRUE(Sem().Get(mem)->Is<sem::Swizzle>());
+    ASSERT_NE(TypeOf(mem), nullptr);
+    ASSERT_TRUE(TypeOf(mem)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(mem)->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(TypeOf(mem)->As<sem::Vector>()->Width(), 2u);
+    ASSERT_TRUE(Sem().Get(mem)->Is<sem::Swizzle>());
 }
 
 TEST_F(ResolverTest, Expr_MemberAccessor_InBinaryOp) {
-  auto* st = Structure("S", {Member("first_member", ty.f32()),
-                             Member("second_member", ty.f32())});
-  Global("my_struct", ty.Of(st), ast::StorageClass::kPrivate);
+    auto* st =
+        Structure("S", {Member("first_member", ty.f32()), Member("second_member", ty.f32())});
+    Global("my_struct", ty.Of(st), ast::StorageClass::kPrivate);
 
-  auto* expr = Add(MemberAccessor("my_struct", "first_member"),
-                   MemberAccessor("my_struct", "second_member"));
-  WrapInFunction(expr);
+    auto* expr = Add(MemberAccessor("my_struct", "first_member"),
+                     MemberAccessor("my_struct", "second_member"));
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(expr), nullptr);
-  EXPECT_TRUE(TypeOf(expr)->Is<sem::F32>());
+    ASSERT_NE(TypeOf(expr), nullptr);
+    EXPECT_TRUE(TypeOf(expr)->Is<sem::F32>());
 }
 
 namespace ExprBinaryTest {
 
 template <typename T, int ID>
 struct Aliased {
-  using type = alias<T, ID>;
+    using type = alias<T, ID>;
 };
 
 template <int N, typename T, int ID>
 struct Aliased<vec<N, T>, ID> {
-  using type = vec<N, alias<T, ID>>;
+    using type = vec<N, alias<T, ID>>;
 };
 
 template <int N, int M, typename T, int ID>
 struct Aliased<mat<N, M, T>, ID> {
-  using type = mat<N, M, alias<T, ID>>;
+    using type = mat<N, M, alias<T, ID>>;
 };
 
 struct Params {
-  ast::BinaryOp op;
-  builder::ast_type_func_ptr create_lhs_type;
-  builder::ast_type_func_ptr create_rhs_type;
-  builder::ast_type_func_ptr create_lhs_alias_type;
-  builder::ast_type_func_ptr create_rhs_alias_type;
-  builder::sem_type_func_ptr create_result_type;
+    ast::BinaryOp op;
+    builder::ast_type_func_ptr create_lhs_type;
+    builder::ast_type_func_ptr create_rhs_type;
+    builder::ast_type_func_ptr create_lhs_alias_type;
+    builder::ast_type_func_ptr create_rhs_alias_type;
+    builder::sem_type_func_ptr create_result_type;
 };
 
 template <typename LHS, typename RHS, typename RES>
 constexpr Params ParamsFor(ast::BinaryOp op) {
-  return Params{op,
-                DataType<LHS>::AST,
-                DataType<RHS>::AST,
-                DataType<typename Aliased<LHS, 0>::type>::AST,
-                DataType<typename Aliased<RHS, 1>::type>::AST,
-                DataType<RES>::Sem};
+    return Params{op,
+                  DataType<LHS>::AST,
+                  DataType<RHS>::AST,
+                  DataType<typename Aliased<LHS, 0>::type>::AST,
+                  DataType<typename Aliased<RHS, 1>::type>::AST,
+                  DataType<RES>::Sem};
 }
 
 static constexpr ast::BinaryOp all_ops[] = {
@@ -1491,174 +1472,158 @@
 
 using Expr_Binary_Test_Valid = ResolverTestWithParam<Params>;
 TEST_P(Expr_Binary_Test_Valid, All) {
-  auto& params = GetParam();
+    auto& params = GetParam();
 
-  auto* lhs_type = params.create_lhs_type(*this);
-  auto* rhs_type = params.create_rhs_type(*this);
-  auto* result_type = params.create_result_type(*this);
+    auto* lhs_type = params.create_lhs_type(*this);
+    auto* rhs_type = params.create_rhs_type(*this);
+    auto* result_type = params.create_result_type(*this);
 
-  std::stringstream ss;
-  ss << FriendlyName(lhs_type) << " " << params.op << " "
-     << FriendlyName(rhs_type);
-  SCOPED_TRACE(ss.str());
+    std::stringstream ss;
+    ss << FriendlyName(lhs_type) << " " << params.op << " " << FriendlyName(rhs_type);
+    SCOPED_TRACE(ss.str());
 
-  Global("lhs", lhs_type, ast::StorageClass::kPrivate);
-  Global("rhs", rhs_type, ast::StorageClass::kPrivate);
+    Global("lhs", lhs_type, ast::StorageClass::kPrivate);
+    Global("rhs", rhs_type, ast::StorageClass::kPrivate);
 
-  auto* expr =
-      create<ast::BinaryExpression>(params.op, Expr("lhs"), Expr("rhs"));
-  WrapInFunction(expr);
+    auto* expr = create<ast::BinaryExpression>(params.op, Expr("lhs"), Expr("rhs"));
+    WrapInFunction(expr);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
-  ASSERT_NE(TypeOf(expr), nullptr);
-  ASSERT_TRUE(TypeOf(expr) == result_type);
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_NE(TypeOf(expr), nullptr);
+    ASSERT_TRUE(TypeOf(expr) == result_type);
 }
-INSTANTIATE_TEST_SUITE_P(ResolverTest,
-                         Expr_Binary_Test_Valid,
-                         testing::ValuesIn(all_valid_cases));
+INSTANTIATE_TEST_SUITE_P(ResolverTest, Expr_Binary_Test_Valid, testing::ValuesIn(all_valid_cases));
 
 enum class BinaryExprSide { Left, Right, Both };
-using Expr_Binary_Test_WithAlias_Valid =
-    ResolverTestWithParam<std::tuple<Params, BinaryExprSide>>;
+using Expr_Binary_Test_WithAlias_Valid = ResolverTestWithParam<std::tuple<Params, BinaryExprSide>>;
 TEST_P(Expr_Binary_Test_WithAlias_Valid, All) {
-  const Params& params = std::get<0>(GetParam());
-  BinaryExprSide side = std::get<1>(GetParam());
+    const Params& params = std::get<0>(GetParam());
+    BinaryExprSide side = std::get<1>(GetParam());
 
-  auto* create_lhs_type =
-      (side == BinaryExprSide::Left || side == BinaryExprSide::Both)
-          ? params.create_lhs_alias_type
-          : params.create_lhs_type;
-  auto* create_rhs_type =
-      (side == BinaryExprSide::Right || side == BinaryExprSide::Both)
-          ? params.create_rhs_alias_type
-          : params.create_rhs_type;
+    auto* create_lhs_type = (side == BinaryExprSide::Left || side == BinaryExprSide::Both)
+                                ? params.create_lhs_alias_type
+                                : params.create_lhs_type;
+    auto* create_rhs_type = (side == BinaryExprSide::Right || side == BinaryExprSide::Both)
+                                ? params.create_rhs_alias_type
+                                : params.create_rhs_type;
 
-  auto* lhs_type = create_lhs_type(*this);
-  auto* rhs_type = create_rhs_type(*this);
+    auto* lhs_type = create_lhs_type(*this);
+    auto* rhs_type = create_rhs_type(*this);
 
-  std::stringstream ss;
-  ss << FriendlyName(lhs_type) << " " << params.op << " "
-     << FriendlyName(rhs_type);
+    std::stringstream ss;
+    ss << FriendlyName(lhs_type) << " " << params.op << " " << FriendlyName(rhs_type);
 
-  ss << ", After aliasing: " << FriendlyName(lhs_type) << " " << params.op
-     << " " << FriendlyName(rhs_type);
-  SCOPED_TRACE(ss.str());
+    ss << ", After aliasing: " << FriendlyName(lhs_type) << " " << params.op << " "
+       << FriendlyName(rhs_type);
+    SCOPED_TRACE(ss.str());
 
-  Global("lhs", lhs_type, ast::StorageClass::kPrivate);
-  Global("rhs", rhs_type, ast::StorageClass::kPrivate);
+    Global("lhs", lhs_type, ast::StorageClass::kPrivate);
+    Global("rhs", rhs_type, ast::StorageClass::kPrivate);
 
-  auto* expr =
-      create<ast::BinaryExpression>(params.op, Expr("lhs"), Expr("rhs"));
-  WrapInFunction(expr);
+    auto* expr = create<ast::BinaryExpression>(params.op, Expr("lhs"), Expr("rhs"));
+    WrapInFunction(expr);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
-  ASSERT_NE(TypeOf(expr), nullptr);
-  // TODO(amaiorano): Bring this back once we have a way to get the canonical
-  // type
-  // auto* *result_type = params.create_result_type(*this);
-  // ASSERT_TRUE(TypeOf(expr) == result_type);
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_NE(TypeOf(expr), nullptr);
+    // TODO(amaiorano): Bring this back once we have a way to get the canonical
+    // type
+    // auto* *result_type = params.create_result_type(*this);
+    // ASSERT_TRUE(TypeOf(expr) == result_type);
 }
-INSTANTIATE_TEST_SUITE_P(
-    ResolverTest,
-    Expr_Binary_Test_WithAlias_Valid,
-    testing::Combine(testing::ValuesIn(all_valid_cases),
-                     testing::Values(BinaryExprSide::Left,
-                                     BinaryExprSide::Right,
-                                     BinaryExprSide::Both)));
+INSTANTIATE_TEST_SUITE_P(ResolverTest,
+                         Expr_Binary_Test_WithAlias_Valid,
+                         testing::Combine(testing::ValuesIn(all_valid_cases),
+                                          testing::Values(BinaryExprSide::Left,
+                                                          BinaryExprSide::Right,
+                                                          BinaryExprSide::Both)));
 
 // This test works by taking the cartesian product of all possible
 // (type * type * op), and processing only the triplets that are not found in
 // the `all_valid_cases` table.
-using Expr_Binary_Test_Invalid =
-    ResolverTestWithParam<std::tuple<builder::ast_type_func_ptr,
-                                     builder::ast_type_func_ptr,
-                                     ast::BinaryOp>>;
+using Expr_Binary_Test_Invalid = ResolverTestWithParam<
+    std::tuple<builder::ast_type_func_ptr, builder::ast_type_func_ptr, ast::BinaryOp>>;
 TEST_P(Expr_Binary_Test_Invalid, All) {
-  const builder::ast_type_func_ptr& lhs_create_type_func =
-      std::get<0>(GetParam());
-  const builder::ast_type_func_ptr& rhs_create_type_func =
-      std::get<1>(GetParam());
-  const ast::BinaryOp op = std::get<2>(GetParam());
+    const builder::ast_type_func_ptr& lhs_create_type_func = std::get<0>(GetParam());
+    const builder::ast_type_func_ptr& rhs_create_type_func = std::get<1>(GetParam());
+    const ast::BinaryOp op = std::get<2>(GetParam());
 
-  // Skip if valid case
-  // TODO(amaiorano): replace linear lookup with O(1) if too slow
-  for (auto& c : all_valid_cases) {
-    if (c.create_lhs_type == lhs_create_type_func &&
-        c.create_rhs_type == rhs_create_type_func && c.op == op) {
-      return;
+    // Skip if valid case
+    // TODO(amaiorano): replace linear lookup with O(1) if too slow
+    for (auto& c : all_valid_cases) {
+        if (c.create_lhs_type == lhs_create_type_func &&
+            c.create_rhs_type == rhs_create_type_func && c.op == op) {
+            return;
+        }
     }
-  }
 
-  auto* lhs_type = lhs_create_type_func(*this);
-  auto* rhs_type = rhs_create_type_func(*this);
+    auto* lhs_type = lhs_create_type_func(*this);
+    auto* rhs_type = rhs_create_type_func(*this);
 
-  std::stringstream ss;
-  ss << FriendlyName(lhs_type) << " " << op << " " << FriendlyName(rhs_type);
-  SCOPED_TRACE(ss.str());
+    std::stringstream ss;
+    ss << FriendlyName(lhs_type) << " " << op << " " << FriendlyName(rhs_type);
+    SCOPED_TRACE(ss.str());
 
-  Global("lhs", lhs_type, ast::StorageClass::kPrivate);
-  Global("rhs", rhs_type, ast::StorageClass::kPrivate);
+    Global("lhs", lhs_type, ast::StorageClass::kPrivate);
+    Global("rhs", rhs_type, ast::StorageClass::kPrivate);
 
-  auto* expr = create<ast::BinaryExpression>(Source{{12, 34}}, op, Expr("lhs"),
-                                             Expr("rhs"));
-  WrapInFunction(expr);
+    auto* expr = create<ast::BinaryExpression>(Source{{12, 34}}, op, Expr("lhs"), Expr("rhs"));
+    WrapInFunction(expr);
 
-  ASSERT_FALSE(r()->Resolve());
-  ASSERT_EQ(r()->error(),
-            "12:34 error: Binary expression operand types are invalid for "
-            "this operation: " +
-                FriendlyName(lhs_type) + " " + ast::FriendlyName(expr->op) +
-                " " + FriendlyName(rhs_type));
-}
-INSTANTIATE_TEST_SUITE_P(
-    ResolverTest,
-    Expr_Binary_Test_Invalid,
-    testing::Combine(testing::ValuesIn(all_create_type_funcs),
-                     testing::ValuesIn(all_create_type_funcs),
-                     testing::ValuesIn(all_ops)));
-
-using Expr_Binary_Test_Invalid_VectorMatrixMultiply =
-    ResolverTestWithParam<std::tuple<bool, uint32_t, uint32_t, uint32_t>>;
-TEST_P(Expr_Binary_Test_Invalid_VectorMatrixMultiply, All) {
-  bool vec_by_mat = std::get<0>(GetParam());
-  uint32_t vec_size = std::get<1>(GetParam());
-  uint32_t mat_rows = std::get<2>(GetParam());
-  uint32_t mat_cols = std::get<3>(GetParam());
-
-  const ast::Type* lhs_type = nullptr;
-  const ast::Type* rhs_type = nullptr;
-  const sem::Type* result_type = nullptr;
-  bool is_valid_expr;
-
-  if (vec_by_mat) {
-    lhs_type = ty.vec<f32>(vec_size);
-    rhs_type = ty.mat<f32>(mat_cols, mat_rows);
-    result_type = create<sem::Vector>(create<sem::F32>(), mat_cols);
-    is_valid_expr = vec_size == mat_rows;
-  } else {
-    lhs_type = ty.mat<f32>(mat_cols, mat_rows);
-    rhs_type = ty.vec<f32>(vec_size);
-    result_type = create<sem::Vector>(create<sem::F32>(), mat_rows);
-    is_valid_expr = vec_size == mat_cols;
-  }
-
-  Global("lhs", lhs_type, ast::StorageClass::kPrivate);
-  Global("rhs", rhs_type, ast::StorageClass::kPrivate);
-
-  auto* expr = Mul(Source{{12, 34}}, Expr("lhs"), Expr("rhs"));
-  WrapInFunction(expr);
-
-  if (is_valid_expr) {
-    ASSERT_TRUE(r()->Resolve()) << r()->error();
-    ASSERT_TRUE(TypeOf(expr) == result_type);
-  } else {
     ASSERT_FALSE(r()->Resolve());
     ASSERT_EQ(r()->error(),
               "12:34 error: Binary expression operand types are invalid for "
               "this operation: " +
-                  FriendlyName(lhs_type) + " " + ast::FriendlyName(expr->op) +
-                  " " + FriendlyName(rhs_type));
-  }
+                  FriendlyName(lhs_type) + " " + ast::FriendlyName(expr->op) + " " +
+                  FriendlyName(rhs_type));
+}
+INSTANTIATE_TEST_SUITE_P(ResolverTest,
+                         Expr_Binary_Test_Invalid,
+                         testing::Combine(testing::ValuesIn(all_create_type_funcs),
+                                          testing::ValuesIn(all_create_type_funcs),
+                                          testing::ValuesIn(all_ops)));
+
+using Expr_Binary_Test_Invalid_VectorMatrixMultiply =
+    ResolverTestWithParam<std::tuple<bool, uint32_t, uint32_t, uint32_t>>;
+TEST_P(Expr_Binary_Test_Invalid_VectorMatrixMultiply, All) {
+    bool vec_by_mat = std::get<0>(GetParam());
+    uint32_t vec_size = std::get<1>(GetParam());
+    uint32_t mat_rows = std::get<2>(GetParam());
+    uint32_t mat_cols = std::get<3>(GetParam());
+
+    const ast::Type* lhs_type = nullptr;
+    const ast::Type* rhs_type = nullptr;
+    const sem::Type* result_type = nullptr;
+    bool is_valid_expr;
+
+    if (vec_by_mat) {
+        lhs_type = ty.vec<f32>(vec_size);
+        rhs_type = ty.mat<f32>(mat_cols, mat_rows);
+        result_type = create<sem::Vector>(create<sem::F32>(), mat_cols);
+        is_valid_expr = vec_size == mat_rows;
+    } else {
+        lhs_type = ty.mat<f32>(mat_cols, mat_rows);
+        rhs_type = ty.vec<f32>(vec_size);
+        result_type = create<sem::Vector>(create<sem::F32>(), mat_rows);
+        is_valid_expr = vec_size == mat_cols;
+    }
+
+    Global("lhs", lhs_type, ast::StorageClass::kPrivate);
+    Global("rhs", rhs_type, ast::StorageClass::kPrivate);
+
+    auto* expr = Mul(Source{{12, 34}}, Expr("lhs"), Expr("rhs"));
+    WrapInFunction(expr);
+
+    if (is_valid_expr) {
+        ASSERT_TRUE(r()->Resolve()) << r()->error();
+        ASSERT_TRUE(TypeOf(expr) == result_type);
+    } else {
+        ASSERT_FALSE(r()->Resolve());
+        ASSERT_EQ(r()->error(),
+                  "12:34 error: Binary expression operand types are invalid for "
+                  "this operation: " +
+                      FriendlyName(lhs_type) + " " + ast::FriendlyName(expr->op) + " " +
+                      FriendlyName(rhs_type));
+    }
 }
 auto all_dimension_values = testing::Values(2u, 3u, 4u);
 INSTANTIATE_TEST_SUITE_P(ResolverTest,
@@ -1671,36 +1636,36 @@
 using Expr_Binary_Test_Invalid_MatrixMatrixMultiply =
     ResolverTestWithParam<std::tuple<uint32_t, uint32_t, uint32_t, uint32_t>>;
 TEST_P(Expr_Binary_Test_Invalid_MatrixMatrixMultiply, All) {
-  uint32_t lhs_mat_rows = std::get<0>(GetParam());
-  uint32_t lhs_mat_cols = std::get<1>(GetParam());
-  uint32_t rhs_mat_rows = std::get<2>(GetParam());
-  uint32_t rhs_mat_cols = std::get<3>(GetParam());
+    uint32_t lhs_mat_rows = std::get<0>(GetParam());
+    uint32_t lhs_mat_cols = std::get<1>(GetParam());
+    uint32_t rhs_mat_rows = std::get<2>(GetParam());
+    uint32_t rhs_mat_cols = std::get<3>(GetParam());
 
-  auto* lhs_type = ty.mat<f32>(lhs_mat_cols, lhs_mat_rows);
-  auto* rhs_type = ty.mat<f32>(rhs_mat_cols, rhs_mat_rows);
+    auto* lhs_type = ty.mat<f32>(lhs_mat_cols, lhs_mat_rows);
+    auto* rhs_type = ty.mat<f32>(rhs_mat_cols, rhs_mat_rows);
 
-  auto* f32 = create<sem::F32>();
-  auto* col = create<sem::Vector>(f32, lhs_mat_rows);
-  auto* result_type = create<sem::Matrix>(col, rhs_mat_cols);
+    auto* f32 = create<sem::F32>();
+    auto* col = create<sem::Vector>(f32, lhs_mat_rows);
+    auto* result_type = create<sem::Matrix>(col, rhs_mat_cols);
 
-  Global("lhs", lhs_type, ast::StorageClass::kPrivate);
-  Global("rhs", rhs_type, ast::StorageClass::kPrivate);
+    Global("lhs", lhs_type, ast::StorageClass::kPrivate);
+    Global("rhs", rhs_type, ast::StorageClass::kPrivate);
 
-  auto* expr = Mul(Source{{12, 34}}, Expr("lhs"), Expr("rhs"));
-  WrapInFunction(expr);
+    auto* expr = Mul(Source{{12, 34}}, Expr("lhs"), Expr("rhs"));
+    WrapInFunction(expr);
 
-  bool is_valid_expr = lhs_mat_cols == rhs_mat_rows;
-  if (is_valid_expr) {
-    ASSERT_TRUE(r()->Resolve()) << r()->error();
-    ASSERT_TRUE(TypeOf(expr) == result_type);
-  } else {
-    ASSERT_FALSE(r()->Resolve());
-    ASSERT_EQ(r()->error(),
-              "12:34 error: Binary expression operand types are invalid for "
-              "this operation: " +
-                  FriendlyName(lhs_type) + " " + ast::FriendlyName(expr->op) +
-                  " " + FriendlyName(rhs_type));
-  }
+    bool is_valid_expr = lhs_mat_cols == rhs_mat_rows;
+    if (is_valid_expr) {
+        ASSERT_TRUE(r()->Resolve()) << r()->error();
+        ASSERT_TRUE(TypeOf(expr) == result_type);
+    } else {
+        ASSERT_FALSE(r()->Resolve());
+        ASSERT_EQ(r()->error(),
+                  "12:34 error: Binary expression operand types are invalid for "
+                  "this operation: " +
+                      FriendlyName(lhs_type) + " " + ast::FriendlyName(expr->op) + " " +
+                      FriendlyName(rhs_type));
+    }
 }
 INSTANTIATE_TEST_SUITE_P(ResolverTest,
                          Expr_Binary_Test_Invalid_MatrixMatrixMultiply,
@@ -1713,30 +1678,30 @@
 
 using UnaryOpExpressionTest = ResolverTestWithParam<ast::UnaryOp>;
 TEST_P(UnaryOpExpressionTest, Expr_UnaryOp) {
-  auto op = GetParam();
+    auto op = GetParam();
 
-  if (op == ast::UnaryOp::kNot) {
-    Global("ident", ty.vec4<bool>(), ast::StorageClass::kPrivate);
-  } else if (op == ast::UnaryOp::kNegation || op == ast::UnaryOp::kComplement) {
-    Global("ident", ty.vec4<i32>(), ast::StorageClass::kPrivate);
-  } else {
-    Global("ident", ty.vec4<f32>(), ast::StorageClass::kPrivate);
-  }
-  auto* der = create<ast::UnaryOpExpression>(op, Expr("ident"));
-  WrapInFunction(der);
+    if (op == ast::UnaryOp::kNot) {
+        Global("ident", ty.vec4<bool>(), ast::StorageClass::kPrivate);
+    } else if (op == ast::UnaryOp::kNegation || op == ast::UnaryOp::kComplement) {
+        Global("ident", ty.vec4<i32>(), ast::StorageClass::kPrivate);
+    } else {
+        Global("ident", ty.vec4<f32>(), ast::StorageClass::kPrivate);
+    }
+    auto* der = create<ast::UnaryOpExpression>(op, Expr("ident"));
+    WrapInFunction(der);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(der), nullptr);
-  ASSERT_TRUE(TypeOf(der)->Is<sem::Vector>());
-  if (op == ast::UnaryOp::kNot) {
-    EXPECT_TRUE(TypeOf(der)->As<sem::Vector>()->type()->Is<sem::Bool>());
-  } else if (op == ast::UnaryOp::kNegation || op == ast::UnaryOp::kComplement) {
-    EXPECT_TRUE(TypeOf(der)->As<sem::Vector>()->type()->Is<sem::I32>());
-  } else {
-    EXPECT_TRUE(TypeOf(der)->As<sem::Vector>()->type()->Is<sem::F32>());
-  }
-  EXPECT_EQ(TypeOf(der)->As<sem::Vector>()->Width(), 4u);
+    ASSERT_NE(TypeOf(der), nullptr);
+    ASSERT_TRUE(TypeOf(der)->Is<sem::Vector>());
+    if (op == ast::UnaryOp::kNot) {
+        EXPECT_TRUE(TypeOf(der)->As<sem::Vector>()->type()->Is<sem::Bool>());
+    } else if (op == ast::UnaryOp::kNegation || op == ast::UnaryOp::kComplement) {
+        EXPECT_TRUE(TypeOf(der)->As<sem::Vector>()->type()->Is<sem::I32>());
+    } else {
+        EXPECT_TRUE(TypeOf(der)->As<sem::Vector>()->type()->Is<sem::F32>());
+    }
+    EXPECT_EQ(TypeOf(der)->As<sem::Vector>()->Width(), 4u);
 }
 INSTANTIATE_TEST_SUITE_P(ResolverTest,
                          UnaryOpExpressionTest,
@@ -1745,436 +1710,404 @@
                                          ast::UnaryOp::kNot));
 
 TEST_F(ResolverTest, StorageClass_SetsIfMissing) {
-  auto* var = Var("var", ty.i32());
+    auto* var = Var("var", ty.i32());
 
-  auto* stmt = Decl(var);
-  Func("func", ast::VariableList{}, ty.void_(), {stmt}, ast::AttributeList{});
+    auto* stmt = Decl(var);
+    Func("func", ast::VariableList{}, ty.void_(), {stmt}, ast::AttributeList{});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  EXPECT_EQ(Sem().Get(var)->StorageClass(), ast::StorageClass::kFunction);
+    EXPECT_EQ(Sem().Get(var)->StorageClass(), ast::StorageClass::kFunction);
 }
 
 TEST_F(ResolverTest, StorageClass_SetForSampler) {
-  auto* t = ty.sampler(ast::SamplerKind::kSampler);
-  auto* var = Global("var", t,
-                     ast::AttributeList{
-                         create<ast::BindingAttribute>(0),
-                         create<ast::GroupAttribute>(0),
-                     });
+    auto* t = ty.sampler(ast::SamplerKind::kSampler);
+    auto* var = Global("var", t,
+                       ast::AttributeList{
+                           create<ast::BindingAttribute>(0),
+                           create<ast::GroupAttribute>(0),
+                       });
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  EXPECT_EQ(Sem().Get(var)->StorageClass(),
-            ast::StorageClass::kUniformConstant);
+    EXPECT_EQ(Sem().Get(var)->StorageClass(), ast::StorageClass::kHandle);
 }
 
 TEST_F(ResolverTest, StorageClass_SetForTexture) {
-  auto* t = ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
-  auto* var = Global("var", t,
-                     ast::AttributeList{
-                         create<ast::BindingAttribute>(0),
-                         create<ast::GroupAttribute>(0),
-                     });
+    auto* t = ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
+    auto* var = Global("var", t,
+                       ast::AttributeList{
+                           create<ast::BindingAttribute>(0),
+                           create<ast::GroupAttribute>(0),
+                       });
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  EXPECT_EQ(Sem().Get(var)->StorageClass(),
-            ast::StorageClass::kUniformConstant);
+    EXPECT_EQ(Sem().Get(var)->StorageClass(), ast::StorageClass::kHandle);
 }
 
 TEST_F(ResolverTest, StorageClass_DoesNotSetOnConst) {
-  auto* var = Const("var", ty.i32(), Construct(ty.i32()));
-  auto* stmt = Decl(var);
-  Func("func", ast::VariableList{}, ty.void_(), {stmt}, ast::AttributeList{});
+    auto* var = Let("var", ty.i32(), Construct(ty.i32()));
+    auto* stmt = Decl(var);
+    Func("func", ast::VariableList{}, ty.void_(), {stmt}, ast::AttributeList{});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  EXPECT_EQ(Sem().Get(var)->StorageClass(), ast::StorageClass::kNone);
+    EXPECT_EQ(Sem().Get(var)->StorageClass(), ast::StorageClass::kNone);
 }
 
 TEST_F(ResolverTest, Access_SetForStorageBuffer) {
-  // struct S { x : i32 };
-  // var<storage> g : S;
-  auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())});
-  auto* var =
-      Global(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kStorage,
-             ast::AttributeList{
-                 create<ast::BindingAttribute>(0),
-                 create<ast::GroupAttribute>(0),
-             });
+    // struct S { x : i32 };
+    // var<storage> g : S;
+    auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())});
+    auto* var = Global(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kStorage,
+                       ast::AttributeList{
+                           create<ast::BindingAttribute>(0),
+                           create<ast::GroupAttribute>(0),
+                       });
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  EXPECT_EQ(Sem().Get(var)->Access(), ast::Access::kRead);
+    EXPECT_EQ(Sem().Get(var)->Access(), ast::Access::kRead);
 }
 
 TEST_F(ResolverTest, BindingPoint_SetForResources) {
-  // @group(1) @binding(2) var s1 : sampler;
-  // @group(3) @binding(4) var s2 : sampler;
-  auto* s1 = Global(Sym(), ty.sampler(ast::SamplerKind::kSampler),
-                    ast::AttributeList{create<ast::GroupAttribute>(1),
-                                       create<ast::BindingAttribute>(2)});
-  auto* s2 = Global(Sym(), ty.sampler(ast::SamplerKind::kSampler),
-                    ast::AttributeList{create<ast::GroupAttribute>(3),
-                                       create<ast::BindingAttribute>(4)});
+    // @group(1) @binding(2) var s1 : sampler;
+    // @group(3) @binding(4) var s2 : sampler;
+    auto* s1 = Global(
+        Sym(), ty.sampler(ast::SamplerKind::kSampler),
+        ast::AttributeList{create<ast::GroupAttribute>(1), create<ast::BindingAttribute>(2)});
+    auto* s2 = Global(
+        Sym(), ty.sampler(ast::SamplerKind::kSampler),
+        ast::AttributeList{create<ast::GroupAttribute>(3), create<ast::BindingAttribute>(4)});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  EXPECT_EQ(Sem().Get<sem::GlobalVariable>(s1)->BindingPoint(),
-            (sem::BindingPoint{1u, 2u}));
-  EXPECT_EQ(Sem().Get<sem::GlobalVariable>(s2)->BindingPoint(),
-            (sem::BindingPoint{3u, 4u}));
+    EXPECT_EQ(Sem().Get<sem::GlobalVariable>(s1)->BindingPoint(), (sem::BindingPoint{1u, 2u}));
+    EXPECT_EQ(Sem().Get<sem::GlobalVariable>(s2)->BindingPoint(), (sem::BindingPoint{3u, 4u}));
 }
 
 TEST_F(ResolverTest, Function_EntryPoints_StageAttribute) {
-  // fn b() {}
-  // fn c() { b(); }
-  // fn a() { c(); }
-  // fn ep_1() { a(); b(); }
-  // fn ep_2() { c();}
-  //
-  // c -> {ep_1, ep_2}
-  // a -> {ep_1}
-  // b -> {ep_1, ep_2}
-  // ep_1 -> {}
-  // ep_2 -> {}
+    // fn b() {}
+    // fn c() { b(); }
+    // fn a() { c(); }
+    // fn ep_1() { a(); b(); }
+    // fn ep_2() { c();}
+    //
+    // c -> {ep_1, ep_2}
+    // a -> {ep_1}
+    // b -> {ep_1, ep_2}
+    // ep_1 -> {}
+    // ep_2 -> {}
 
-  Global("first", ty.f32(), ast::StorageClass::kPrivate);
-  Global("second", ty.f32(), ast::StorageClass::kPrivate);
-  Global("call_a", ty.f32(), ast::StorageClass::kPrivate);
-  Global("call_b", ty.f32(), ast::StorageClass::kPrivate);
-  Global("call_c", ty.f32(), ast::StorageClass::kPrivate);
+    Global("first", ty.f32(), ast::StorageClass::kPrivate);
+    Global("second", ty.f32(), ast::StorageClass::kPrivate);
+    Global("call_a", ty.f32(), ast::StorageClass::kPrivate);
+    Global("call_b", ty.f32(), ast::StorageClass::kPrivate);
+    Global("call_c", ty.f32(), ast::StorageClass::kPrivate);
 
-  ast::VariableList params;
-  auto* func_b =
-      Func("b", params, ty.f32(), {Return(0.0f)}, ast::AttributeList{});
-  auto* func_c =
-      Func("c", params, ty.f32(), {Assign("second", Call("b")), Return(0.0f)},
-           ast::AttributeList{});
+    ast::VariableList params;
+    auto* func_b = Func("b", params, ty.f32(), {Return(0.0f)}, ast::AttributeList{});
+    auto* func_c = Func("c", params, ty.f32(), {Assign("second", Call("b")), Return(0.0f)},
+                        ast::AttributeList{});
 
-  auto* func_a =
-      Func("a", params, ty.f32(), {Assign("first", Call("c")), Return(0.0f)},
-           ast::AttributeList{});
+    auto* func_a = Func("a", params, ty.f32(), {Assign("first", Call("c")), Return(0.0f)},
+                        ast::AttributeList{});
 
-  auto* ep_1 = Func("ep_1", params, ty.void_(),
-                    {
-                        Assign("call_a", Call("a")),
-                        Assign("call_b", Call("b")),
-                    },
-                    ast::AttributeList{Stage(ast::PipelineStage::kCompute),
-                                       WorkgroupSize(1)});
+    auto* ep_1 = Func("ep_1", params, ty.void_(),
+                      {
+                          Assign("call_a", Call("a")),
+                          Assign("call_b", Call("b")),
+                      },
+                      ast::AttributeList{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
 
-  auto* ep_2 = Func("ep_2", params, ty.void_(),
-                    {
-                        Assign("call_c", Call("c")),
-                    },
-                    ast::AttributeList{Stage(ast::PipelineStage::kCompute),
-                                       WorkgroupSize(1)});
+    auto* ep_2 = Func("ep_2", params, ty.void_(),
+                      {
+                          Assign("call_c", Call("c")),
+                      },
+                      ast::AttributeList{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* func_b_sem = Sem().Get(func_b);
-  auto* func_a_sem = Sem().Get(func_a);
-  auto* func_c_sem = Sem().Get(func_c);
-  auto* ep_1_sem = Sem().Get(ep_1);
-  auto* ep_2_sem = Sem().Get(ep_2);
-  ASSERT_NE(func_b_sem, nullptr);
-  ASSERT_NE(func_a_sem, nullptr);
-  ASSERT_NE(func_c_sem, nullptr);
-  ASSERT_NE(ep_1_sem, nullptr);
-  ASSERT_NE(ep_2_sem, nullptr);
+    auto* func_b_sem = Sem().Get(func_b);
+    auto* func_a_sem = Sem().Get(func_a);
+    auto* func_c_sem = Sem().Get(func_c);
+    auto* ep_1_sem = Sem().Get(ep_1);
+    auto* ep_2_sem = Sem().Get(ep_2);
+    ASSERT_NE(func_b_sem, nullptr);
+    ASSERT_NE(func_a_sem, nullptr);
+    ASSERT_NE(func_c_sem, nullptr);
+    ASSERT_NE(ep_1_sem, nullptr);
+    ASSERT_NE(ep_2_sem, nullptr);
 
-  EXPECT_EQ(func_b_sem->Parameters().size(), 0u);
-  EXPECT_EQ(func_a_sem->Parameters().size(), 0u);
-  EXPECT_EQ(func_c_sem->Parameters().size(), 0u);
+    EXPECT_EQ(func_b_sem->Parameters().size(), 0u);
+    EXPECT_EQ(func_a_sem->Parameters().size(), 0u);
+    EXPECT_EQ(func_c_sem->Parameters().size(), 0u);
 
-  const auto& b_eps = func_b_sem->AncestorEntryPoints();
-  ASSERT_EQ(2u, b_eps.size());
-  EXPECT_EQ(Symbols().Register("ep_1"), b_eps[0]->Declaration()->symbol);
-  EXPECT_EQ(Symbols().Register("ep_2"), b_eps[1]->Declaration()->symbol);
+    const auto& b_eps = func_b_sem->AncestorEntryPoints();
+    ASSERT_EQ(2u, b_eps.size());
+    EXPECT_EQ(Symbols().Register("ep_1"), b_eps[0]->Declaration()->symbol);
+    EXPECT_EQ(Symbols().Register("ep_2"), b_eps[1]->Declaration()->symbol);
 
-  const auto& a_eps = func_a_sem->AncestorEntryPoints();
-  ASSERT_EQ(1u, a_eps.size());
-  EXPECT_EQ(Symbols().Register("ep_1"), a_eps[0]->Declaration()->symbol);
+    const auto& a_eps = func_a_sem->AncestorEntryPoints();
+    ASSERT_EQ(1u, a_eps.size());
+    EXPECT_EQ(Symbols().Register("ep_1"), a_eps[0]->Declaration()->symbol);
 
-  const auto& c_eps = func_c_sem->AncestorEntryPoints();
-  ASSERT_EQ(2u, c_eps.size());
-  EXPECT_EQ(Symbols().Register("ep_1"), c_eps[0]->Declaration()->symbol);
-  EXPECT_EQ(Symbols().Register("ep_2"), c_eps[1]->Declaration()->symbol);
+    const auto& c_eps = func_c_sem->AncestorEntryPoints();
+    ASSERT_EQ(2u, c_eps.size());
+    EXPECT_EQ(Symbols().Register("ep_1"), c_eps[0]->Declaration()->symbol);
+    EXPECT_EQ(Symbols().Register("ep_2"), c_eps[1]->Declaration()->symbol);
 
-  EXPECT_TRUE(ep_1_sem->AncestorEntryPoints().empty());
-  EXPECT_TRUE(ep_2_sem->AncestorEntryPoints().empty());
+    EXPECT_TRUE(ep_1_sem->AncestorEntryPoints().empty());
+    EXPECT_TRUE(ep_2_sem->AncestorEntryPoints().empty());
 }
 
 // Check for linear-time traversal of functions reachable from entry points.
 // See: crbug.com/tint/245
 TEST_F(ResolverTest, Function_EntryPoints_LinearTime) {
-  // fn lNa() { }
-  // fn lNb() { }
-  // ...
-  // fn l2a() { l3a(); l3b(); }
-  // fn l2b() { l3a(); l3b(); }
-  // fn l1a() { l2a(); l2b(); }
-  // fn l1b() { l2a(); l2b(); }
-  // fn main() { l1a(); l1b(); }
+    // fn lNa() { }
+    // fn lNb() { }
+    // ...
+    // fn l2a() { l3a(); l3b(); }
+    // fn l2b() { l3a(); l3b(); }
+    // fn l1a() { l2a(); l2b(); }
+    // fn l1b() { l2a(); l2b(); }
+    // fn main() { l1a(); l1b(); }
 
-  static constexpr int levels = 64;
+    static constexpr int levels = 64;
 
-  auto fn_a = [](int level) { return "l" + std::to_string(level + 1) + "a"; };
-  auto fn_b = [](int level) { return "l" + std::to_string(level + 1) + "b"; };
+    auto fn_a = [](int level) { return "l" + std::to_string(level + 1) + "a"; };
+    auto fn_b = [](int level) { return "l" + std::to_string(level + 1) + "b"; };
 
-  Func(fn_a(levels), {}, ty.void_(), {}, {});
-  Func(fn_b(levels), {}, ty.void_(), {}, {});
+    Func(fn_a(levels), {}, ty.void_(), {}, {});
+    Func(fn_b(levels), {}, ty.void_(), {}, {});
 
-  for (int i = levels - 1; i >= 0; i--) {
-    Func(fn_a(i), {}, ty.void_(),
+    for (int i = levels - 1; i >= 0; i--) {
+        Func(fn_a(i), {}, ty.void_(),
+             {
+                 CallStmt(Call(fn_a(i + 1))),
+                 CallStmt(Call(fn_b(i + 1))),
+             },
+             {});
+        Func(fn_b(i), {}, ty.void_(),
+             {
+                 CallStmt(Call(fn_a(i + 1))),
+                 CallStmt(Call(fn_b(i + 1))),
+             },
+             {});
+    }
+
+    Func("main", {}, ty.void_(),
          {
-             CallStmt(Call(fn_a(i + 1))),
-             CallStmt(Call(fn_b(i + 1))),
+             CallStmt(Call(fn_a(0))),
+             CallStmt(Call(fn_b(0))),
          },
-         {});
-    Func(fn_b(i), {}, ty.void_(),
-         {
-             CallStmt(Call(fn_a(i + 1))),
-             CallStmt(Call(fn_b(i + 1))),
-         },
-         {});
-  }
+         {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
 
-  Func("main", {}, ty.void_(),
-       {
-           CallStmt(Call(fn_a(0))),
-           CallStmt(Call(fn_b(0))),
-       },
-       {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
-
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 // Test for crbug.com/tint/728
 TEST_F(ResolverTest, ASTNodesAreReached) {
-  Structure("A", {Member("x", ty.array<f32, 4>(4))});
-  Structure("B", {Member("x", ty.array<f32, 4>(4))});
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    Structure("A", {Member("x", ty.array<f32, 4>(4))});
+    Structure("B", {Member("x", ty.array<f32, 4>(4))});
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverTest, ASTNodeNotReached) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.Expr("expr");
-        Resolver(&b).Resolve();
-      },
-      "internal compiler error: AST node 'tint::ast::IdentifierExpression' was "
-      "not reached by the resolver");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.Expr("expr");
+            Resolver(&b).Resolve();
+        },
+        "internal compiler error: AST node 'tint::ast::IdentifierExpression' was not reached by "
+        "the resolver");
 }
 
 TEST_F(ResolverTest, ASTNodeReachedTwice) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        auto* expr = b.Expr(1);
-        b.Global("a", b.ty.i32(), ast::StorageClass::kPrivate, expr);
-        b.Global("b", b.ty.i32(), ast::StorageClass::kPrivate, expr);
-        Resolver(&b).Resolve();
-      },
-      "internal compiler error: AST node 'tint::ast::SintLiteralExpression' "
-      "was encountered twice in the same AST of a Program");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            auto* expr = b.Expr(1_i);
+            b.Global("a", b.ty.i32(), ast::StorageClass::kPrivate, expr);
+            b.Global("b", b.ty.i32(), ast::StorageClass::kPrivate, expr);
+            Resolver(&b).Resolve();
+        },
+        "internal compiler error: AST node 'tint::ast::IntLiteralExpression' was encountered twice "
+        "in the same AST of a Program");
 }
 
 TEST_F(ResolverTest, UnaryOp_Not) {
-  Global("ident", ty.vec4<f32>(), ast::StorageClass::kPrivate);
-  auto* der = create<ast::UnaryOpExpression>(ast::UnaryOp::kNot,
-                                             Expr(Source{{12, 34}}, "ident"));
-  WrapInFunction(der);
+    Global("ident", ty.vec4<f32>(), ast::StorageClass::kPrivate);
+    auto* der = create<ast::UnaryOpExpression>(ast::UnaryOp::kNot, Expr(Source{{12, 34}}, "ident"));
+    WrapInFunction(der);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: cannot logical negate expression of type 'vec4<f32>");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: cannot logical negate expression of type 'vec4<f32>");
 }
 
 TEST_F(ResolverTest, UnaryOp_Complement) {
-  Global("ident", ty.vec4<f32>(), ast::StorageClass::kPrivate);
-  auto* der = create<ast::UnaryOpExpression>(ast::UnaryOp::kComplement,
-                                             Expr(Source{{12, 34}}, "ident"));
-  WrapInFunction(der);
+    Global("ident", ty.vec4<f32>(), ast::StorageClass::kPrivate);
+    auto* der =
+        create<ast::UnaryOpExpression>(ast::UnaryOp::kComplement, Expr(Source{{12, 34}}, "ident"));
+    WrapInFunction(der);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: cannot bitwise complement expression of type 'vec4<f32>");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: cannot bitwise complement expression of type 'vec4<f32>");
 }
 
 TEST_F(ResolverTest, UnaryOp_Negation) {
-  Global("ident", ty.u32(), ast::StorageClass::kPrivate);
-  auto* der = create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation,
-                                             Expr(Source{{12, 34}}, "ident"));
-  WrapInFunction(der);
+    Global("ident", ty.u32(), ast::StorageClass::kPrivate);
+    auto* der =
+        create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation, Expr(Source{{12, 34}}, "ident"));
+    WrapInFunction(der);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: cannot negate expression of type 'u32");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: cannot negate expression of type 'u32");
 }
 
 TEST_F(ResolverTest, TextureSampler_TextureSample) {
-  Global("t", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
-         GroupAndBinding(1, 1));
-  Global("s", ty.sampler(ast::SamplerKind::kSampler), GroupAndBinding(1, 2));
+    Global("t", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()), GroupAndBinding(1, 1));
+    Global("s", ty.sampler(ast::SamplerKind::kSampler), GroupAndBinding(1, 2));
 
-  auto* call = CallStmt(Call("textureSample", "t", "s", vec2<f32>(1.0f, 2.0f)));
-  const ast::Function* f = Func("test_function", {}, ty.void_(), {call},
-                                {Stage(ast::PipelineStage::kFragment)});
+    auto* call = CallStmt(Call("textureSample", "t", "s", vec2<f32>(1.0f, 2.0f)));
+    const ast::Function* f =
+        Func("test_function", {}, ty.void_(), {call}, {Stage(ast::PipelineStage::kFragment)});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  const sem::Function* sf = Sem().Get(f);
-  auto pairs = sf->TextureSamplerPairs();
-  ASSERT_EQ(pairs.size(), 1u);
-  EXPECT_TRUE(pairs[0].first != nullptr);
-  EXPECT_TRUE(pairs[0].second != nullptr);
+    const sem::Function* sf = Sem().Get(f);
+    auto pairs = sf->TextureSamplerPairs();
+    ASSERT_EQ(pairs.size(), 1u);
+    EXPECT_TRUE(pairs[0].first != nullptr);
+    EXPECT_TRUE(pairs[0].second != nullptr);
 }
 
 TEST_F(ResolverTest, TextureSampler_TextureSampleInFunction) {
-  Global("t", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
-         GroupAndBinding(1, 1));
-  Global("s", ty.sampler(ast::SamplerKind::kSampler), GroupAndBinding(1, 2));
+    Global("t", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()), GroupAndBinding(1, 1));
+    Global("s", ty.sampler(ast::SamplerKind::kSampler), GroupAndBinding(1, 2));
 
-  auto* inner_call =
-      CallStmt(Call("textureSample", "t", "s", vec2<f32>(1.0f, 2.0f)));
-  const ast::Function* inner_func =
-      Func("inner_func", {}, ty.void_(), {inner_call});
-  auto* outer_call = CallStmt(Call("inner_func"));
-  const ast::Function* outer_func =
-      Func("outer_func", {}, ty.void_(), {outer_call},
-           {Stage(ast::PipelineStage::kFragment)});
+    auto* inner_call = CallStmt(Call("textureSample", "t", "s", vec2<f32>(1.0f, 2.0f)));
+    const ast::Function* inner_func = Func("inner_func", {}, ty.void_(), {inner_call});
+    auto* outer_call = CallStmt(Call("inner_func"));
+    const ast::Function* outer_func =
+        Func("outer_func", {}, ty.void_(), {outer_call}, {Stage(ast::PipelineStage::kFragment)});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto inner_pairs = Sem().Get(inner_func)->TextureSamplerPairs();
-  ASSERT_EQ(inner_pairs.size(), 1u);
-  EXPECT_TRUE(inner_pairs[0].first != nullptr);
-  EXPECT_TRUE(inner_pairs[0].second != nullptr);
+    auto inner_pairs = Sem().Get(inner_func)->TextureSamplerPairs();
+    ASSERT_EQ(inner_pairs.size(), 1u);
+    EXPECT_TRUE(inner_pairs[0].first != nullptr);
+    EXPECT_TRUE(inner_pairs[0].second != nullptr);
 
-  auto outer_pairs = Sem().Get(outer_func)->TextureSamplerPairs();
-  ASSERT_EQ(outer_pairs.size(), 1u);
-  EXPECT_TRUE(outer_pairs[0].first != nullptr);
-  EXPECT_TRUE(outer_pairs[0].second != nullptr);
+    auto outer_pairs = Sem().Get(outer_func)->TextureSamplerPairs();
+    ASSERT_EQ(outer_pairs.size(), 1u);
+    EXPECT_TRUE(outer_pairs[0].first != nullptr);
+    EXPECT_TRUE(outer_pairs[0].second != nullptr);
 }
 
 TEST_F(ResolverTest, TextureSampler_TextureSampleFunctionDiamondSameVariables) {
-  Global("t", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
-         GroupAndBinding(1, 1));
-  Global("s", ty.sampler(ast::SamplerKind::kSampler), GroupAndBinding(1, 2));
+    Global("t", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()), GroupAndBinding(1, 1));
+    Global("s", ty.sampler(ast::SamplerKind::kSampler), GroupAndBinding(1, 2));
 
-  auto* inner_call_1 =
-      CallStmt(Call("textureSample", "t", "s", vec2<f32>(1.0f, 2.0f)));
-  const ast::Function* inner_func_1 =
-      Func("inner_func_1", {}, ty.void_(), {inner_call_1});
-  auto* inner_call_2 =
-      CallStmt(Call("textureSample", "t", "s", vec2<f32>(3.0f, 4.0f)));
-  const ast::Function* inner_func_2 =
-      Func("inner_func_2", {}, ty.void_(), {inner_call_2});
-  auto* outer_call_1 = CallStmt(Call("inner_func_1"));
-  auto* outer_call_2 = CallStmt(Call("inner_func_2"));
-  const ast::Function* outer_func =
-      Func("outer_func", {}, ty.void_(), {outer_call_1, outer_call_2},
-           {Stage(ast::PipelineStage::kFragment)});
+    auto* inner_call_1 = CallStmt(Call("textureSample", "t", "s", vec2<f32>(1.0f, 2.0f)));
+    const ast::Function* inner_func_1 = Func("inner_func_1", {}, ty.void_(), {inner_call_1});
+    auto* inner_call_2 = CallStmt(Call("textureSample", "t", "s", vec2<f32>(3.0f, 4.0f)));
+    const ast::Function* inner_func_2 = Func("inner_func_2", {}, ty.void_(), {inner_call_2});
+    auto* outer_call_1 = CallStmt(Call("inner_func_1"));
+    auto* outer_call_2 = CallStmt(Call("inner_func_2"));
+    const ast::Function* outer_func =
+        Func("outer_func", {}, ty.void_(), {outer_call_1, outer_call_2},
+             {Stage(ast::PipelineStage::kFragment)});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto inner_pairs_1 = Sem().Get(inner_func_1)->TextureSamplerPairs();
-  ASSERT_EQ(inner_pairs_1.size(), 1u);
-  EXPECT_TRUE(inner_pairs_1[0].first != nullptr);
-  EXPECT_TRUE(inner_pairs_1[0].second != nullptr);
+    auto inner_pairs_1 = Sem().Get(inner_func_1)->TextureSamplerPairs();
+    ASSERT_EQ(inner_pairs_1.size(), 1u);
+    EXPECT_TRUE(inner_pairs_1[0].first != nullptr);
+    EXPECT_TRUE(inner_pairs_1[0].second != nullptr);
 
-  auto inner_pairs_2 = Sem().Get(inner_func_2)->TextureSamplerPairs();
-  ASSERT_EQ(inner_pairs_1.size(), 1u);
-  EXPECT_TRUE(inner_pairs_2[0].first != nullptr);
-  EXPECT_TRUE(inner_pairs_2[0].second != nullptr);
+    auto inner_pairs_2 = Sem().Get(inner_func_2)->TextureSamplerPairs();
+    ASSERT_EQ(inner_pairs_1.size(), 1u);
+    EXPECT_TRUE(inner_pairs_2[0].first != nullptr);
+    EXPECT_TRUE(inner_pairs_2[0].second != nullptr);
 
-  auto outer_pairs = Sem().Get(outer_func)->TextureSamplerPairs();
-  ASSERT_EQ(outer_pairs.size(), 1u);
-  EXPECT_TRUE(outer_pairs[0].first != nullptr);
-  EXPECT_TRUE(outer_pairs[0].second != nullptr);
+    auto outer_pairs = Sem().Get(outer_func)->TextureSamplerPairs();
+    ASSERT_EQ(outer_pairs.size(), 1u);
+    EXPECT_TRUE(outer_pairs[0].first != nullptr);
+    EXPECT_TRUE(outer_pairs[0].second != nullptr);
 }
 
-TEST_F(ResolverTest,
-       TextureSampler_TextureSampleFunctionDiamondDifferentVariables) {
-  Global("t1", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
-         GroupAndBinding(1, 1));
-  Global("t2", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
-         GroupAndBinding(1, 2));
-  Global("s", ty.sampler(ast::SamplerKind::kSampler), GroupAndBinding(1, 3));
+TEST_F(ResolverTest, TextureSampler_TextureSampleFunctionDiamondDifferentVariables) {
+    Global("t1", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()), GroupAndBinding(1, 1));
+    Global("t2", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()), GroupAndBinding(1, 2));
+    Global("s", ty.sampler(ast::SamplerKind::kSampler), GroupAndBinding(1, 3));
 
-  auto* inner_call_1 =
-      CallStmt(Call("textureSample", "t1", "s", vec2<f32>(1.0f, 2.0f)));
-  const ast::Function* inner_func_1 =
-      Func("inner_func_1", {}, ty.void_(), {inner_call_1});
-  auto* inner_call_2 =
-      CallStmt(Call("textureSample", "t2", "s", vec2<f32>(3.0f, 4.0f)));
-  const ast::Function* inner_func_2 =
-      Func("inner_func_2", {}, ty.void_(), {inner_call_2});
-  auto* outer_call_1 = CallStmt(Call("inner_func_1"));
-  auto* outer_call_2 = CallStmt(Call("inner_func_2"));
-  const ast::Function* outer_func =
-      Func("outer_func", {}, ty.void_(), {outer_call_1, outer_call_2},
-           {Stage(ast::PipelineStage::kFragment)});
+    auto* inner_call_1 = CallStmt(Call("textureSample", "t1", "s", vec2<f32>(1.0f, 2.0f)));
+    const ast::Function* inner_func_1 = Func("inner_func_1", {}, ty.void_(), {inner_call_1});
+    auto* inner_call_2 = CallStmt(Call("textureSample", "t2", "s", vec2<f32>(3.0f, 4.0f)));
+    const ast::Function* inner_func_2 = Func("inner_func_2", {}, ty.void_(), {inner_call_2});
+    auto* outer_call_1 = CallStmt(Call("inner_func_1"));
+    auto* outer_call_2 = CallStmt(Call("inner_func_2"));
+    const ast::Function* outer_func =
+        Func("outer_func", {}, ty.void_(), {outer_call_1, outer_call_2},
+             {Stage(ast::PipelineStage::kFragment)});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto inner_pairs_1 = Sem().Get(inner_func_1)->TextureSamplerPairs();
-  ASSERT_EQ(inner_pairs_1.size(), 1u);
-  EXPECT_TRUE(inner_pairs_1[0].first != nullptr);
-  EXPECT_TRUE(inner_pairs_1[0].second != nullptr);
+    auto inner_pairs_1 = Sem().Get(inner_func_1)->TextureSamplerPairs();
+    ASSERT_EQ(inner_pairs_1.size(), 1u);
+    EXPECT_TRUE(inner_pairs_1[0].first != nullptr);
+    EXPECT_TRUE(inner_pairs_1[0].second != nullptr);
 
-  auto inner_pairs_2 = Sem().Get(inner_func_2)->TextureSamplerPairs();
-  ASSERT_EQ(inner_pairs_2.size(), 1u);
-  EXPECT_TRUE(inner_pairs_2[0].first != nullptr);
-  EXPECT_TRUE(inner_pairs_2[0].second != nullptr);
+    auto inner_pairs_2 = Sem().Get(inner_func_2)->TextureSamplerPairs();
+    ASSERT_EQ(inner_pairs_2.size(), 1u);
+    EXPECT_TRUE(inner_pairs_2[0].first != nullptr);
+    EXPECT_TRUE(inner_pairs_2[0].second != nullptr);
 
-  auto outer_pairs = Sem().Get(outer_func)->TextureSamplerPairs();
-  ASSERT_EQ(outer_pairs.size(), 2u);
-  EXPECT_TRUE(outer_pairs[0].first == inner_pairs_1[0].first);
-  EXPECT_TRUE(outer_pairs[0].second == inner_pairs_1[0].second);
-  EXPECT_TRUE(outer_pairs[1].first == inner_pairs_2[0].first);
-  EXPECT_TRUE(outer_pairs[1].second == inner_pairs_2[0].second);
+    auto outer_pairs = Sem().Get(outer_func)->TextureSamplerPairs();
+    ASSERT_EQ(outer_pairs.size(), 2u);
+    EXPECT_TRUE(outer_pairs[0].first == inner_pairs_1[0].first);
+    EXPECT_TRUE(outer_pairs[0].second == inner_pairs_1[0].second);
+    EXPECT_TRUE(outer_pairs[1].first == inner_pairs_2[0].first);
+    EXPECT_TRUE(outer_pairs[1].second == inner_pairs_2[0].second);
 }
 
 TEST_F(ResolverTest, TextureSampler_TextureDimensions) {
-  Global("t", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
-         GroupAndBinding(1, 2));
+    Global("t", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()), GroupAndBinding(1, 2));
 
-  auto* call = Call("textureDimensions", "t");
-  const ast::Function* f = WrapInFunction(call);
+    auto* call = Call("textureDimensions", "t");
+    const ast::Function* f = WrapInFunction(call);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  const sem::Function* sf = Sem().Get(f);
-  auto pairs = sf->TextureSamplerPairs();
-  ASSERT_EQ(pairs.size(), 1u);
-  EXPECT_TRUE(pairs[0].first != nullptr);
-  EXPECT_TRUE(pairs[0].second == nullptr);
+    const sem::Function* sf = Sem().Get(f);
+    auto pairs = sf->TextureSamplerPairs();
+    ASSERT_EQ(pairs.size(), 1u);
+    EXPECT_TRUE(pairs[0].first != nullptr);
+    EXPECT_TRUE(pairs[0].second == nullptr);
 }
 
 TEST_F(ResolverTest, ModuleDependencyOrderedDeclarations) {
-  auto* f0 = Func("f0", {}, ty.void_(), {});
-  auto* v0 = Global("v0", ty.i32(), ast::StorageClass::kPrivate);
-  auto* a0 = Alias("a0", ty.i32());
-  auto* s0 = Structure("s0", {Member("m", ty.i32())});
-  auto* f1 = Func("f1", {}, ty.void_(), {});
-  auto* v1 = Global("v1", ty.i32(), ast::StorageClass::kPrivate);
-  auto* a1 = Alias("a1", ty.i32());
-  auto* s1 = Structure("s1", {Member("m", ty.i32())});
-  auto* f2 = Func("f2", {}, ty.void_(), {});
-  auto* v2 = Global("v2", ty.i32(), ast::StorageClass::kPrivate);
-  auto* a2 = Alias("a2", ty.i32());
-  auto* s2 = Structure("s2", {Member("m", ty.i32())});
+    auto* f0 = Func("f0", {}, ty.void_(), {});
+    auto* v0 = Global("v0", ty.i32(), ast::StorageClass::kPrivate);
+    auto* a0 = Alias("a0", ty.i32());
+    auto* s0 = Structure("s0", {Member("m", ty.i32())});
+    auto* f1 = Func("f1", {}, ty.void_(), {});
+    auto* v1 = Global("v1", ty.i32(), ast::StorageClass::kPrivate);
+    auto* a1 = Alias("a1", ty.i32());
+    auto* s1 = Structure("s1", {Member("m", ty.i32())});
+    auto* f2 = Func("f2", {}, ty.void_(), {});
+    auto* v2 = Global("v2", ty.i32(), ast::StorageClass::kPrivate);
+    auto* a2 = Alias("a2", ty.i32());
+    auto* s2 = Structure("s2", {Member("m", ty.i32())});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(Sem().Module(), nullptr);
-  EXPECT_THAT(Sem().Module()->DependencyOrderedDeclarations(),
-              ElementsAre(f0, v0, a0, s0, f1, v1, a1, s1, f2, v2, a2, s2));
+    ASSERT_NE(Sem().Module(), nullptr);
+    EXPECT_THAT(Sem().Module()->DependencyOrderedDeclarations(),
+                ElementsAre(f0, v0, a0, s0, f1, v1, a1, s1, f2, v2, a2, s2));
 }
 
 }  // namespace
diff --git a/src/tint/resolver/resolver_test_helper.h b/src/tint/resolver/resolver_test_helper.h
index 236b854..d54e57c 100644
--- a/src/tint/resolver/resolver_test_helper.h
+++ b/src/tint/resolver/resolver_test_helper.h
@@ -30,101 +30,95 @@
 
 /// Helper class for testing
 class TestHelper : public ProgramBuilder {
- public:
-  /// Constructor
-  TestHelper();
+  public:
+    /// Constructor
+    TestHelper();
 
-  /// Destructor
-  ~TestHelper() override;
+    /// Destructor
+    ~TestHelper() override;
 
-  /// @return a pointer to the Resolver
-  Resolver* r() const { return resolver_.get(); }
+    /// @return a pointer to the Resolver
+    Resolver* r() const { return resolver_.get(); }
 
-  /// Returns the statement that holds the given expression.
-  /// @param expr the ast::Expression
-  /// @return the ast::Statement of the ast::Expression, or nullptr if the
-  /// expression is not owned by a statement.
-  const ast::Statement* StmtOf(const ast::Expression* expr) {
-    auto* sem_stmt = Sem().Get(expr)->Stmt();
-    return sem_stmt ? sem_stmt->Declaration() : nullptr;
-  }
+    /// @return a pointer to the validator
+    const Validator* v() const { return resolver_->GetValidatorForTesting(); }
 
-  /// Returns the BlockStatement that holds the given statement.
-  /// @param stmt the ast::Statement
-  /// @return the ast::BlockStatement that holds the ast::Statement, or nullptr
-  /// if the statement is not owned by a BlockStatement.
-  const ast::BlockStatement* BlockOf(const ast::Statement* stmt) {
-    auto* sem_stmt = Sem().Get(stmt);
-    return sem_stmt ? sem_stmt->Block()->Declaration() : nullptr;
-  }
-
-  /// Returns the BlockStatement that holds the given expression.
-  /// @param expr the ast::Expression
-  /// @return the ast::Statement of the ast::Expression, or nullptr if the
-  /// expression is not indirectly owned by a BlockStatement.
-  const ast::BlockStatement* BlockOf(const ast::Expression* expr) {
-    auto* sem_stmt = Sem().Get(expr)->Stmt();
-    return sem_stmt ? sem_stmt->Block()->Declaration() : nullptr;
-  }
-
-  /// Returns the semantic variable for the given identifier expression.
-  /// @param expr the identifier expression
-  /// @return the resolved sem::Variable of the identifier, or nullptr if
-  /// the expression did not resolve to a variable.
-  const sem::Variable* VarOf(const ast::Expression* expr) {
-    auto* sem_ident = Sem().Get(expr);
-    auto* var_user = sem_ident ? sem_ident->As<sem::VariableUser>() : nullptr;
-    return var_user ? var_user->Variable() : nullptr;
-  }
-
-  /// Checks that all the users of the given variable are as expected
-  /// @param var the variable to check
-  /// @param expected_users the expected users of the variable
-  /// @return true if all users are as expected
-  bool CheckVarUsers(const ast::Variable* var,
-                     std::vector<const ast::Expression*>&& expected_users) {
-    auto& var_users = Sem().Get(var)->Users();
-    if (var_users.size() != expected_users.size()) {
-      return false;
+    /// Returns the statement that holds the given expression.
+    /// @param expr the ast::Expression
+    /// @return the ast::Statement of the ast::Expression, or nullptr if the
+    /// expression is not owned by a statement.
+    const ast::Statement* StmtOf(const ast::Expression* expr) {
+        auto* sem_stmt = Sem().Get(expr)->Stmt();
+        return sem_stmt ? sem_stmt->Declaration() : nullptr;
     }
-    for (size_t i = 0; i < var_users.size(); i++) {
-      if (var_users[i]->Declaration() != expected_users[i]) {
-        return false;
-      }
+
+    /// Returns the BlockStatement that holds the given statement.
+    /// @param stmt the ast::Statement
+    /// @return the ast::BlockStatement that holds the ast::Statement, or nullptr
+    /// if the statement is not owned by a BlockStatement.
+    const ast::BlockStatement* BlockOf(const ast::Statement* stmt) {
+        auto* sem_stmt = Sem().Get(stmt);
+        return sem_stmt ? sem_stmt->Block()->Declaration() : nullptr;
     }
-    return true;
-  }
 
-  /// @param type a type
-  /// @returns the name for `type` that closely resembles how it would be
-  /// declared in WGSL.
-  std::string FriendlyName(const ast::Type* type) {
-    return type->FriendlyName(Symbols());
-  }
+    /// Returns the BlockStatement that holds the given expression.
+    /// @param expr the ast::Expression
+    /// @return the ast::Statement of the ast::Expression, or nullptr if the
+    /// expression is not indirectly owned by a BlockStatement.
+    const ast::BlockStatement* BlockOf(const ast::Expression* expr) {
+        auto* sem_stmt = Sem().Get(expr)->Stmt();
+        return sem_stmt ? sem_stmt->Block()->Declaration() : nullptr;
+    }
 
-  /// @param type a type
-  /// @returns the name for `type` that closely resembles how it would be
-  /// declared in WGSL.
-  std::string FriendlyName(const sem::Type* type) {
-    return type->FriendlyName(Symbols());
-  }
+    /// Returns the semantic variable for the given identifier expression.
+    /// @param expr the identifier expression
+    /// @return the resolved sem::Variable of the identifier, or nullptr if
+    /// the expression did not resolve to a variable.
+    const sem::Variable* VarOf(const ast::Expression* expr) {
+        auto* sem_ident = Sem().Get(expr);
+        auto* var_user = sem_ident ? sem_ident->As<sem::VariableUser>() : nullptr;
+        return var_user ? var_user->Variable() : nullptr;
+    }
 
- private:
-  std::unique_ptr<Resolver> resolver_;
+    /// Checks that all the users of the given variable are as expected
+    /// @param var the variable to check
+    /// @param expected_users the expected users of the variable
+    /// @return true if all users are as expected
+    bool CheckVarUsers(const ast::Variable* var,
+                       std::vector<const ast::Expression*>&& expected_users) {
+        auto& var_users = Sem().Get(var)->Users();
+        if (var_users.size() != expected_users.size()) {
+            return false;
+        }
+        for (size_t i = 0; i < var_users.size(); i++) {
+            if (var_users[i]->Declaration() != expected_users[i]) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /// @param type a type
+    /// @returns the name for `type` that closely resembles how it would be
+    /// declared in WGSL.
+    std::string FriendlyName(const ast::Type* type) { return type->FriendlyName(Symbols()); }
+
+    /// @param type a type
+    /// @returns the name for `type` that closely resembles how it would be
+    /// declared in WGSL.
+    std::string FriendlyName(const sem::Type* type) { return type->FriendlyName(Symbols()); }
+
+  private:
+    std::unique_ptr<Resolver> resolver_;
 };
 
 class ResolverTest : public TestHelper, public testing::Test {};
 
 template <typename T>
-class ResolverTestWithParam : public TestHelper,
-                              public testing::TestWithParam<T> {};
+class ResolverTestWithParam : public TestHelper, public testing::TestWithParam<T> {};
 
 namespace builder {
 
-using i32 = ProgramBuilder::i32;
-using u32 = ProgramBuilder::u32;
-using f32 = ProgramBuilder::f32;
-
 template <uint32_t N, typename T>
 struct vec {};
 
@@ -174,8 +168,7 @@
 struct ptr {};
 
 using ast_type_func_ptr = const ast::Type* (*)(ProgramBuilder& b);
-using ast_expr_func_ptr = const ast::Expression* (*)(ProgramBuilder& b,
-                                                     int elem_value);
+using ast_expr_func_ptr = const ast::Expression* (*)(ProgramBuilder& b, int elem_value);
 using sem_type_func_ptr = const sem::Type* (*)(ProgramBuilder& b);
 
 template <typename T>
@@ -184,300 +177,283 @@
 /// Helper for building bool types and expressions
 template <>
 struct DataType<bool> {
-  /// false as bool is not a composite type
-  static constexpr bool is_composite = false;
+    /// false as bool is not a composite type
+    static constexpr bool is_composite = false;
 
-  /// @param b the ProgramBuilder
-  /// @return a new AST bool type
-  static inline const ast::Type* AST(ProgramBuilder& b) { return b.ty.bool_(); }
-  /// @param b the ProgramBuilder
-  /// @return the semantic bool type
-  static inline const sem::Type* Sem(ProgramBuilder& b) {
-    return b.create<sem::Bool>();
-  }
-  /// @param b the ProgramBuilder
-  /// @param elem_value the b
-  /// @return a new AST expression of the bool type
-  static inline const ast::Expression* Expr(ProgramBuilder& b, int elem_value) {
-    return b.Expr(elem_value == 0);
-  }
+    /// @param b the ProgramBuilder
+    /// @return a new AST bool type
+    static inline const ast::Type* AST(ProgramBuilder& b) { return b.ty.bool_(); }
+    /// @param b the ProgramBuilder
+    /// @return the semantic bool type
+    static inline const sem::Type* Sem(ProgramBuilder& b) { return b.create<sem::Bool>(); }
+    /// @param b the ProgramBuilder
+    /// @param elem_value the b
+    /// @return a new AST expression of the bool type
+    static inline const ast::Expression* Expr(ProgramBuilder& b, int elem_value) {
+        return b.Expr(elem_value == 0);
+    }
 };
 
 /// Helper for building i32 types and expressions
 template <>
 struct DataType<i32> {
-  /// false as i32 is not a composite type
-  static constexpr bool is_composite = false;
+    /// false as i32 is not a composite type
+    static constexpr bool is_composite = false;
 
-  /// @param b the ProgramBuilder
-  /// @return a new AST i32 type
-  static inline const ast::Type* AST(ProgramBuilder& b) { return b.ty.i32(); }
-  /// @param b the ProgramBuilder
-  /// @return the semantic i32 type
-  static inline const sem::Type* Sem(ProgramBuilder& b) {
-    return b.create<sem::I32>();
-  }
-  /// @param b the ProgramBuilder
-  /// @param elem_value the value i32 will be initialized with
-  /// @return a new AST i32 literal value expression
-  static inline const ast::Expression* Expr(ProgramBuilder& b, int elem_value) {
-    return b.Expr(static_cast<i32>(elem_value));
-  }
+    /// @param b the ProgramBuilder
+    /// @return a new AST i32 type
+    static inline const ast::Type* AST(ProgramBuilder& b) { return b.ty.i32(); }
+    /// @param b the ProgramBuilder
+    /// @return the semantic i32 type
+    static inline const sem::Type* Sem(ProgramBuilder& b) { return b.create<sem::I32>(); }
+    /// @param b the ProgramBuilder
+    /// @param elem_value the value i32 will be initialized with
+    /// @return a new AST i32 literal value expression
+    static inline const ast::Expression* Expr(ProgramBuilder& b, int elem_value) {
+        return b.Expr(static_cast<i32>(elem_value));
+    }
 };
 
 /// Helper for building u32 types and expressions
 template <>
 struct DataType<u32> {
-  /// false as u32 is not a composite type
-  static constexpr bool is_composite = false;
+    /// false as u32 is not a composite type
+    static constexpr bool is_composite = false;
 
-  /// @param b the ProgramBuilder
-  /// @return a new AST u32 type
-  static inline const ast::Type* AST(ProgramBuilder& b) { return b.ty.u32(); }
-  /// @param b the ProgramBuilder
-  /// @return the semantic u32 type
-  static inline const sem::Type* Sem(ProgramBuilder& b) {
-    return b.create<sem::U32>();
-  }
-  /// @param b the ProgramBuilder
-  /// @param elem_value the value u32 will be initialized with
-  /// @return a new AST u32 literal value expression
-  static inline const ast::Expression* Expr(ProgramBuilder& b, int elem_value) {
-    return b.Expr(static_cast<u32>(elem_value));
-  }
+    /// @param b the ProgramBuilder
+    /// @return a new AST u32 type
+    static inline const ast::Type* AST(ProgramBuilder& b) { return b.ty.u32(); }
+    /// @param b the ProgramBuilder
+    /// @return the semantic u32 type
+    static inline const sem::Type* Sem(ProgramBuilder& b) { return b.create<sem::U32>(); }
+    /// @param b the ProgramBuilder
+    /// @param elem_value the value u32 will be initialized with
+    /// @return a new AST u32 literal value expression
+    static inline const ast::Expression* Expr(ProgramBuilder& b, int elem_value) {
+        return b.Expr(static_cast<u32>(elem_value));
+    }
 };
 
 /// Helper for building f32 types and expressions
 template <>
 struct DataType<f32> {
-  /// false as f32 is not a composite type
-  static constexpr bool is_composite = false;
+    /// false as f32 is not a composite type
+    static constexpr bool is_composite = false;
 
-  /// @param b the ProgramBuilder
-  /// @return a new AST f32 type
-  static inline const ast::Type* AST(ProgramBuilder& b) { return b.ty.f32(); }
-  /// @param b the ProgramBuilder
-  /// @return the semantic f32 type
-  static inline const sem::Type* Sem(ProgramBuilder& b) {
-    return b.create<sem::F32>();
-  }
-  /// @param b the ProgramBuilder
-  /// @param elem_value the value f32 will be initialized with
-  /// @return a new AST f32 literal value expression
-  static inline const ast::Expression* Expr(ProgramBuilder& b, int elem_value) {
-    return b.Expr(static_cast<f32>(elem_value));
-  }
+    /// @param b the ProgramBuilder
+    /// @return a new AST f32 type
+    static inline const ast::Type* AST(ProgramBuilder& b) { return b.ty.f32(); }
+    /// @param b the ProgramBuilder
+    /// @return the semantic f32 type
+    static inline const sem::Type* Sem(ProgramBuilder& b) { return b.create<sem::F32>(); }
+    /// @param b the ProgramBuilder
+    /// @param elem_value the value f32 will be initialized with
+    /// @return a new AST f32 literal value expression
+    static inline const ast::Expression* Expr(ProgramBuilder& b, int elem_value) {
+        return b.Expr(static_cast<f32>(elem_value));
+    }
 };
 
 /// Helper for building vector types and expressions
 template <uint32_t N, typename T>
 struct DataType<vec<N, T>> {
-  /// true as vectors are a composite type
-  static constexpr bool is_composite = true;
+    /// true as vectors are a composite type
+    static constexpr bool is_composite = true;
 
-  /// @param b the ProgramBuilder
-  /// @return a new AST vector type
-  static inline const ast::Type* AST(ProgramBuilder& b) {
-    return b.ty.vec(DataType<T>::AST(b), N);
-  }
-  /// @param b the ProgramBuilder
-  /// @return the semantic vector type
-  static inline const sem::Type* Sem(ProgramBuilder& b) {
-    return b.create<sem::Vector>(DataType<T>::Sem(b), N);
-  }
-  /// @param b the ProgramBuilder
-  /// @param elem_value the value each element in the vector will be initialized
-  /// with
-  /// @return a new AST vector value expression
-  static inline const ast::Expression* Expr(ProgramBuilder& b, int elem_value) {
-    return b.Construct(AST(b), ExprArgs(b, elem_value));
-  }
-
-  /// @param b the ProgramBuilder
-  /// @param elem_value the value each element will be initialized with
-  /// @return the list of expressions that are used to construct the vector
-  static inline ast::ExpressionList ExprArgs(ProgramBuilder& b,
-                                             int elem_value) {
-    ast::ExpressionList args;
-    for (uint32_t i = 0; i < N; i++) {
-      args.emplace_back(DataType<T>::Expr(b, elem_value));
+    /// @param b the ProgramBuilder
+    /// @return a new AST vector type
+    static inline const ast::Type* AST(ProgramBuilder& b) {
+        return b.ty.vec(DataType<T>::AST(b), N);
     }
-    return args;
-  }
+    /// @param b the ProgramBuilder
+    /// @return the semantic vector type
+    static inline const sem::Type* Sem(ProgramBuilder& b) {
+        return b.create<sem::Vector>(DataType<T>::Sem(b), N);
+    }
+    /// @param b the ProgramBuilder
+    /// @param elem_value the value each element in the vector will be initialized
+    /// with
+    /// @return a new AST vector value expression
+    static inline const ast::Expression* Expr(ProgramBuilder& b, int elem_value) {
+        return b.Construct(AST(b), ExprArgs(b, elem_value));
+    }
+
+    /// @param b the ProgramBuilder
+    /// @param elem_value the value each element will be initialized with
+    /// @return the list of expressions that are used to construct the vector
+    static inline ast::ExpressionList ExprArgs(ProgramBuilder& b, int elem_value) {
+        ast::ExpressionList args;
+        for (uint32_t i = 0; i < N; i++) {
+            args.emplace_back(DataType<T>::Expr(b, elem_value));
+        }
+        return args;
+    }
 };
 
 /// Helper for building matrix types and expressions
 template <uint32_t N, uint32_t M, typename T>
 struct DataType<mat<N, M, T>> {
-  /// true as matrices are a composite type
-  static constexpr bool is_composite = true;
+    /// true as matrices are a composite type
+    static constexpr bool is_composite = true;
 
-  /// @param b the ProgramBuilder
-  /// @return a new AST matrix type
-  static inline const ast::Type* AST(ProgramBuilder& b) {
-    return b.ty.mat(DataType<T>::AST(b), N, M);
-  }
-  /// @param b the ProgramBuilder
-  /// @return the semantic matrix type
-  static inline const sem::Type* Sem(ProgramBuilder& b) {
-    auto* column_type = b.create<sem::Vector>(DataType<T>::Sem(b), M);
-    return b.create<sem::Matrix>(column_type, N);
-  }
-  /// @param b the ProgramBuilder
-  /// @param elem_value the value each element in the matrix will be initialized
-  /// with
-  /// @return a new AST matrix value expression
-  static inline const ast::Expression* Expr(ProgramBuilder& b, int elem_value) {
-    return b.Construct(AST(b), ExprArgs(b, elem_value));
-  }
-
-  /// @param b the ProgramBuilder
-  /// @param elem_value the value each element will be initialized with
-  /// @return the list of expressions that are used to construct the matrix
-  static inline ast::ExpressionList ExprArgs(ProgramBuilder& b,
-                                             int elem_value) {
-    ast::ExpressionList args;
-    for (uint32_t i = 0; i < N; i++) {
-      args.emplace_back(DataType<vec<M, T>>::Expr(b, elem_value));
+    /// @param b the ProgramBuilder
+    /// @return a new AST matrix type
+    static inline const ast::Type* AST(ProgramBuilder& b) {
+        return b.ty.mat(DataType<T>::AST(b), N, M);
     }
-    return args;
-  }
+    /// @param b the ProgramBuilder
+    /// @return the semantic matrix type
+    static inline const sem::Type* Sem(ProgramBuilder& b) {
+        auto* column_type = b.create<sem::Vector>(DataType<T>::Sem(b), M);
+        return b.create<sem::Matrix>(column_type, N);
+    }
+    /// @param b the ProgramBuilder
+    /// @param elem_value the value each element in the matrix will be initialized
+    /// with
+    /// @return a new AST matrix value expression
+    static inline const ast::Expression* Expr(ProgramBuilder& b, int elem_value) {
+        return b.Construct(AST(b), ExprArgs(b, elem_value));
+    }
+
+    /// @param b the ProgramBuilder
+    /// @param elem_value the value each element will be initialized with
+    /// @return the list of expressions that are used to construct the matrix
+    static inline ast::ExpressionList ExprArgs(ProgramBuilder& b, int elem_value) {
+        ast::ExpressionList args;
+        for (uint32_t i = 0; i < N; i++) {
+            args.emplace_back(DataType<vec<M, T>>::Expr(b, elem_value));
+        }
+        return args;
+    }
 };
 
 /// Helper for building alias types and expressions
 template <typename T, int ID>
 struct DataType<alias<T, ID>> {
-  /// true if the aliased type is a composite type
-  static constexpr bool is_composite = DataType<T>::is_composite;
+    /// true if the aliased type is a composite type
+    static constexpr bool is_composite = DataType<T>::is_composite;
 
-  /// @param b the ProgramBuilder
-  /// @return a new AST alias type
-  static inline const ast::Type* AST(ProgramBuilder& b) {
-    auto name = b.Symbols().Register("alias_" + std::to_string(ID));
-    if (!b.AST().LookupType(name)) {
-      auto* type = DataType<T>::AST(b);
-      b.AST().AddTypeDecl(b.ty.alias(name, type));
+    /// @param b the ProgramBuilder
+    /// @return a new AST alias type
+    static inline const ast::Type* AST(ProgramBuilder& b) {
+        auto name = b.Symbols().Register("alias_" + std::to_string(ID));
+        if (!b.AST().LookupType(name)) {
+            auto* type = DataType<T>::AST(b);
+            b.AST().AddTypeDecl(b.ty.alias(name, type));
+        }
+        return b.create<ast::TypeName>(name);
     }
-    return b.create<ast::TypeName>(name);
-  }
-  /// @param b the ProgramBuilder
-  /// @return the semantic aliased type
-  static inline const sem::Type* Sem(ProgramBuilder& b) {
-    return DataType<T>::Sem(b);
-  }
+    /// @param b the ProgramBuilder
+    /// @return the semantic aliased type
+    static inline const sem::Type* Sem(ProgramBuilder& b) { return DataType<T>::Sem(b); }
 
-  /// @param b the ProgramBuilder
-  /// @param elem_value the value nested elements will be initialized with
-  /// @return a new AST expression of the alias type
-  template <bool IS_COMPOSITE = is_composite>
-  static inline traits::EnableIf<!IS_COMPOSITE, const ast::Expression*> Expr(
-      ProgramBuilder& b,
-      int elem_value) {
-    // Cast
-    return b.Construct(AST(b), DataType<T>::Expr(b, elem_value));
-  }
+    /// @param b the ProgramBuilder
+    /// @param elem_value the value nested elements will be initialized with
+    /// @return a new AST expression of the alias type
+    template <bool IS_COMPOSITE = is_composite>
+    static inline traits::EnableIf<!IS_COMPOSITE, const ast::Expression*> Expr(ProgramBuilder& b,
+                                                                               int elem_value) {
+        // Cast
+        return b.Construct(AST(b), DataType<T>::Expr(b, elem_value));
+    }
 
-  /// @param b the ProgramBuilder
-  /// @param elem_value the value nested elements will be initialized with
-  /// @return a new AST expression of the alias type
-  template <bool IS_COMPOSITE = is_composite>
-  static inline traits::EnableIf<IS_COMPOSITE, const ast::Expression*> Expr(
-      ProgramBuilder& b,
-      int elem_value) {
-    // Construct
-    return b.Construct(AST(b), DataType<T>::ExprArgs(b, elem_value));
-  }
+    /// @param b the ProgramBuilder
+    /// @param elem_value the value nested elements will be initialized with
+    /// @return a new AST expression of the alias type
+    template <bool IS_COMPOSITE = is_composite>
+    static inline traits::EnableIf<IS_COMPOSITE, const ast::Expression*> Expr(ProgramBuilder& b,
+                                                                              int elem_value) {
+        // Construct
+        return b.Construct(AST(b), DataType<T>::ExprArgs(b, elem_value));
+    }
 };
 
 /// Helper for building pointer types and expressions
 template <typename T>
 struct DataType<ptr<T>> {
-  /// true if the pointer type is a composite type
-  static constexpr bool is_composite = false;
+    /// true if the pointer type is a composite type
+    static constexpr bool is_composite = false;
 
-  /// @param b the ProgramBuilder
-  /// @return a new AST alias type
-  static inline const ast::Type* AST(ProgramBuilder& b) {
-    return b.create<ast::Pointer>(DataType<T>::AST(b),
-                                  ast::StorageClass::kPrivate,
-                                  ast::Access::kReadWrite);
-  }
-  /// @param b the ProgramBuilder
-  /// @return the semantic aliased type
-  static inline const sem::Type* Sem(ProgramBuilder& b) {
-    return b.create<sem::Pointer>(DataType<T>::Sem(b),
-                                  ast::StorageClass::kPrivate,
-                                  ast::Access::kReadWrite);
-  }
+    /// @param b the ProgramBuilder
+    /// @return a new AST alias type
+    static inline const ast::Type* AST(ProgramBuilder& b) {
+        return b.create<ast::Pointer>(DataType<T>::AST(b), ast::StorageClass::kPrivate,
+                                      ast::Access::kReadWrite);
+    }
+    /// @param b the ProgramBuilder
+    /// @return the semantic aliased type
+    static inline const sem::Type* Sem(ProgramBuilder& b) {
+        return b.create<sem::Pointer>(DataType<T>::Sem(b), ast::StorageClass::kPrivate,
+                                      ast::Access::kReadWrite);
+    }
 
-  /// @param b the ProgramBuilder
-  /// @return a new AST expression of the alias type
-  static inline const ast::Expression* Expr(ProgramBuilder& b, int /*unused*/) {
-    auto sym = b.Symbols().New("global_for_ptr");
-    b.Global(sym, DataType<T>::AST(b), ast::StorageClass::kPrivate);
-    return b.AddressOf(sym);
-  }
+    /// @param b the ProgramBuilder
+    /// @return a new AST expression of the alias type
+    static inline const ast::Expression* Expr(ProgramBuilder& b, int /*unused*/) {
+        auto sym = b.Symbols().New("global_for_ptr");
+        b.Global(sym, DataType<T>::AST(b), ast::StorageClass::kPrivate);
+        return b.AddressOf(sym);
+    }
 };
 
 /// Helper for building array types and expressions
 template <uint32_t N, typename T>
 struct DataType<array<N, T>> {
-  /// true as arrays are a composite type
-  static constexpr bool is_composite = true;
+    /// true as arrays are a composite type
+    static constexpr bool is_composite = true;
 
-  /// @param b the ProgramBuilder
-  /// @return a new AST array type
-  static inline const ast::Type* AST(ProgramBuilder& b) {
-    return b.ty.array(DataType<T>::AST(b), N);
-  }
-  /// @param b the ProgramBuilder
-  /// @return the semantic array type
-  static inline const sem::Type* Sem(ProgramBuilder& b) {
-    auto* el = DataType<T>::Sem(b);
-    return b.create<sem::Array>(
-        /* element */ el,
-        /* count */ N,
-        /* align */ el->Align(),
-        /* size */ el->Size(),
-        /* stride */ el->Align(),
-        /* implicit_stride */ el->Align());
-  }
-  /// @param b the ProgramBuilder
-  /// @param elem_value the value each element in the array will be initialized
-  /// with
-  /// @return a new AST array value expression
-  static inline const ast::Expression* Expr(ProgramBuilder& b, int elem_value) {
-    return b.Construct(AST(b), ExprArgs(b, elem_value));
-  }
-
-  /// @param b the ProgramBuilder
-  /// @param elem_value the value each element will be initialized with
-  /// @return the list of expressions that are used to construct the array
-  static inline ast::ExpressionList ExprArgs(ProgramBuilder& b,
-                                             int elem_value) {
-    ast::ExpressionList args;
-    for (uint32_t i = 0; i < N; i++) {
-      args.emplace_back(DataType<T>::Expr(b, elem_value));
+    /// @param b the ProgramBuilder
+    /// @return a new AST array type
+    static inline const ast::Type* AST(ProgramBuilder& b) {
+        return b.ty.array(DataType<T>::AST(b), u32(N));
     }
-    return args;
-  }
+    /// @param b the ProgramBuilder
+    /// @return the semantic array type
+    static inline const sem::Type* Sem(ProgramBuilder& b) {
+        auto* el = DataType<T>::Sem(b);
+        return b.create<sem::Array>(
+            /* element */ el,
+            /* count */ N,
+            /* align */ el->Align(),
+            /* size */ el->Size(),
+            /* stride */ el->Align(),
+            /* implicit_stride */ el->Align());
+    }
+    /// @param b the ProgramBuilder
+    /// @param elem_value the value each element in the array will be initialized
+    /// with
+    /// @return a new AST array value expression
+    static inline const ast::Expression* Expr(ProgramBuilder& b, int elem_value) {
+        return b.Construct(AST(b), ExprArgs(b, elem_value));
+    }
+
+    /// @param b the ProgramBuilder
+    /// @param elem_value the value each element will be initialized with
+    /// @return the list of expressions that are used to construct the array
+    static inline ast::ExpressionList ExprArgs(ProgramBuilder& b, int elem_value) {
+        ast::ExpressionList args;
+        for (uint32_t i = 0; i < N; i++) {
+            args.emplace_back(DataType<T>::Expr(b, elem_value));
+        }
+        return args;
+    }
 };
 
 /// Struct of all creation pointer types
 struct CreatePtrs {
-  /// ast node type create function
-  ast_type_func_ptr ast;
-  /// ast expression type create function
-  ast_expr_func_ptr expr;
-  /// sem type create function
-  sem_type_func_ptr sem;
+    /// ast node type create function
+    ast_type_func_ptr ast;
+    /// ast expression type create function
+    ast_expr_func_ptr expr;
+    /// sem type create function
+    sem_type_func_ptr sem;
 };
 
 /// Returns a CreatePtrs struct instance with all creation pointer types for
 /// type `T`
 template <typename T>
 constexpr CreatePtrs CreatePtrsFor() {
-  return {DataType<T>::AST, DataType<T>::Expr, DataType<T>::Sem};
+    return {DataType<T>::AST, DataType<T>::Expr, DataType<T>::Sem};
 }
 
 }  // namespace builder
diff --git a/src/tint/resolver/resolver_validation.cc b/src/tint/resolver/resolver_validation.cc
deleted file mode 100644
index 44e0a2f..0000000
--- a/src/tint/resolver/resolver_validation.cc
+++ /dev/null
@@ -1,2455 +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/resolver/resolver.h"
-
-#include <algorithm>
-#include <limits>
-#include <utility>
-
-#include "src/tint/ast/alias.h"
-#include "src/tint/ast/array.h"
-#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/call_statement.h"
-#include "src/tint/ast/continue_statement.h"
-#include "src/tint/ast/depth_texture.h"
-#include "src/tint/ast/disable_validation_attribute.h"
-#include "src/tint/ast/discard_statement.h"
-#include "src/tint/ast/fallthrough_statement.h"
-#include "src/tint/ast/for_loop_statement.h"
-#include "src/tint/ast/id_attribute.h"
-#include "src/tint/ast/if_statement.h"
-#include "src/tint/ast/internal_attribute.h"
-#include "src/tint/ast/interpolate_attribute.h"
-#include "src/tint/ast/loop_statement.h"
-#include "src/tint/ast/matrix.h"
-#include "src/tint/ast/pointer.h"
-#include "src/tint/ast/return_statement.h"
-#include "src/tint/ast/sampled_texture.h"
-#include "src/tint/ast/sampler.h"
-#include "src/tint/ast/storage_texture.h"
-#include "src/tint/ast/switch_statement.h"
-#include "src/tint/ast/traverse_expressions.h"
-#include "src/tint/ast/type_name.h"
-#include "src/tint/ast/unary_op_expression.h"
-#include "src/tint/ast/variable_decl_statement.h"
-#include "src/tint/ast/vector.h"
-#include "src/tint/ast/workgroup_attribute.h"
-#include "src/tint/sem/array.h"
-#include "src/tint/sem/atomic_type.h"
-#include "src/tint/sem/call.h"
-#include "src/tint/sem/depth_multisampled_texture_type.h"
-#include "src/tint/sem/depth_texture_type.h"
-#include "src/tint/sem/for_loop_statement.h"
-#include "src/tint/sem/function.h"
-#include "src/tint/sem/if_statement.h"
-#include "src/tint/sem/loop_statement.h"
-#include "src/tint/sem/member_accessor_expression.h"
-#include "src/tint/sem/multisampled_texture_type.h"
-#include "src/tint/sem/pointer_type.h"
-#include "src/tint/sem/reference_type.h"
-#include "src/tint/sem/sampled_texture_type.h"
-#include "src/tint/sem/sampler_type.h"
-#include "src/tint/sem/statement.h"
-#include "src/tint/sem/storage_texture_type.h"
-#include "src/tint/sem/struct.h"
-#include "src/tint/sem/switch_statement.h"
-#include "src/tint/sem/type_constructor.h"
-#include "src/tint/sem/type_conversion.h"
-#include "src/tint/sem/variable.h"
-#include "src/tint/utils/defer.h"
-#include "src/tint/utils/map.h"
-#include "src/tint/utils/math.h"
-#include "src/tint/utils/reverse.h"
-#include "src/tint/utils/scoped_assignment.h"
-#include "src/tint/utils/transform.h"
-
-namespace tint::resolver {
-namespace {
-
-bool IsValidStorageTextureDimension(ast::TextureDimension dim) {
-  switch (dim) {
-    case ast::TextureDimension::k1d:
-    case ast::TextureDimension::k2d:
-    case ast::TextureDimension::k2dArray:
-    case ast::TextureDimension::k3d:
-      return true;
-    default:
-      return false;
-  }
-}
-
-bool IsValidStorageTextureTexelFormat(ast::TexelFormat format) {
-  switch (format) {
-    case ast::TexelFormat::kR32Uint:
-    case ast::TexelFormat::kR32Sint:
-    case ast::TexelFormat::kR32Float:
-    case ast::TexelFormat::kRg32Uint:
-    case ast::TexelFormat::kRg32Sint:
-    case ast::TexelFormat::kRg32Float:
-    case ast::TexelFormat::kRgba8Unorm:
-    case ast::TexelFormat::kRgba8Snorm:
-    case ast::TexelFormat::kRgba8Uint:
-    case ast::TexelFormat::kRgba8Sint:
-    case ast::TexelFormat::kRgba16Uint:
-    case ast::TexelFormat::kRgba16Sint:
-    case ast::TexelFormat::kRgba16Float:
-    case ast::TexelFormat::kRgba32Uint:
-    case ast::TexelFormat::kRgba32Sint:
-    case ast::TexelFormat::kRgba32Float:
-      return true;
-    default:
-      return false;
-  }
-}
-
-// Helper to stringify a pipeline IO attribute.
-std::string attr_to_str(const ast::Attribute* attr) {
-  std::stringstream str;
-  if (auto* builtin = attr->As<ast::BuiltinAttribute>()) {
-    str << "builtin(" << builtin->builtin << ")";
-  } else if (auto* location = attr->As<ast::LocationAttribute>()) {
-    str << "location(" << location->value << ")";
-  }
-  return str.str();
-}
-
-template <typename CALLBACK>
-void TraverseCallChain(diag::List& diagnostics,
-                       const sem::Function* from,
-                       const sem::Function* to,
-                       CALLBACK&& callback) {
-  for (auto* f : from->TransitivelyCalledFunctions()) {
-    if (f == to) {
-      callback(f);
-      return;
-    }
-    if (f->TransitivelyCalledFunctions().contains(to)) {
-      TraverseCallChain(diagnostics, f, to, callback);
-      callback(f);
-      return;
-    }
-  }
-  TINT_ICE(Resolver, diagnostics)
-      << "TraverseCallChain() 'from' does not transitively call 'to'";
-}
-
-}  // namespace
-
-bool Resolver::ValidateAtomic(const ast::Atomic* a,
-                              const sem::Atomic* s) const {
-  // https://gpuweb.github.io/gpuweb/wgsl/#atomic-types
-  // T must be either u32 or i32.
-  if (!s->Type()->IsAnyOf<sem::U32, sem::I32>()) {
-    AddError("atomic only supports i32 or u32 types",
-             a->type ? a->type->source : a->source);
-    return false;
-  }
-  return true;
-}
-
-bool Resolver::ValidateStorageTexture(const ast::StorageTexture* t) const {
-  switch (t->access) {
-    case ast::Access::kWrite:
-      break;
-    case ast::Access::kUndefined:
-      AddError("storage texture missing access control", t->source);
-      return false;
-    default:
-      AddError("storage textures currently only support 'write' access control",
-               t->source);
-      return false;
-  }
-
-  if (!IsValidStorageTextureDimension(t->dim)) {
-    AddError("cube dimensions for storage textures are not supported",
-             t->source);
-    return false;
-  }
-
-  if (!IsValidStorageTextureTexelFormat(t->format)) {
-    AddError(
-        "image format must be one of the texel formats specified for storage "
-        "textues in https://gpuweb.github.io/gpuweb/wgsl/#texel-formats",
-        t->source);
-    return false;
-  }
-  return true;
-}
-
-bool Resolver::ValidateVariableConstructorOrCast(
-    const ast::Variable* var,
-    ast::StorageClass storage_class,
-    const sem::Type* storage_ty,
-    const sem::Type* rhs_ty) const {
-  auto* value_type = rhs_ty->UnwrapRef();  // Implicit load of RHS
-
-  // Value type has to match storage type
-  if (storage_ty != value_type) {
-    std::string decl = var->is_const ? "let" : "var";
-    AddError("cannot initialize " + decl + " of type '" +
-                 sem_.TypeNameOf(storage_ty) + "' with value of type '" +
-                 sem_.TypeNameOf(rhs_ty) + "'",
-             var->source);
-    return false;
-  }
-
-  if (!var->is_const) {
-    switch (storage_class) {
-      case ast::StorageClass::kPrivate:
-      case ast::StorageClass::kFunction:
-        break;  // Allowed an initializer
-      default:
-        // https://gpuweb.github.io/gpuweb/wgsl/#var-and-let
-        // Optionally has an initializer expression, if the variable is in the
-        // private or function storage classes.
-        AddError("var of storage class '" +
-                     std::string(ast::ToString(storage_class)) +
-                     "' cannot have an initializer. var initializers are only "
-                     "supported for the storage classes "
-                     "'private' and 'function'",
-                 var->source);
-        return false;
-    }
-  }
-
-  return true;
-}
-
-bool Resolver::ValidateStorageClassLayout(
-    const sem::Type* store_ty,
-    ast::StorageClass sc,
-    Source source,
-    ValidTypeStorageLayouts& layouts) const {
-  // https://gpuweb.github.io/gpuweb/wgsl/#storage-class-layout-constraints
-
-  auto is_uniform_struct_or_array = [sc](const sem::Type* ty) {
-    return sc == ast::StorageClass::kUniform &&
-           ty->IsAnyOf<sem::Array, sem::Struct>();
-  };
-
-  auto is_uniform_struct = [sc](const sem::Type* ty) {
-    return sc == ast::StorageClass::kUniform && ty->Is<sem::Struct>();
-  };
-
-  auto required_alignment_of = [&](const sem::Type* ty) {
-    uint32_t actual_align = ty->Align();
-    uint32_t required_align = actual_align;
-    if (is_uniform_struct_or_array(ty)) {
-      required_align = utils::RoundUp(16u, actual_align);
-    }
-    return required_align;
-  };
-
-  auto member_name_of = [this](const sem::StructMember* sm) {
-    return builder_->Symbols().NameFor(sm->Declaration()->symbol);
-  };
-
-  // Cache result of type + storage class pair.
-  if (!layouts.emplace(store_ty, sc).second) {
-    return true;
-  }
-
-  if (!ast::IsHostShareable(sc)) {
-    return true;
-  }
-
-  if (auto* str = store_ty->As<sem::Struct>()) {
-    for (size_t i = 0; i < str->Members().size(); ++i) {
-      auto* const m = str->Members()[i];
-      uint32_t required_align = required_alignment_of(m->Type());
-
-      // Recurse into the member type.
-      if (!ValidateStorageClassLayout(
-              m->Type(), sc, m->Declaration()->type->source, layouts)) {
-        AddNote("see layout of struct:\n" + str->Layout(builder_->Symbols()),
-                str->Declaration()->source);
-        return false;
-      }
-
-      // Validate that member is at a valid byte offset
-      if (m->Offset() % required_align != 0) {
-        AddError("the offset of a struct member of type '" +
-                     m->Type()->UnwrapRef()->FriendlyName(builder_->Symbols()) +
-                     "' in storage class '" + ast::ToString(sc) +
-                     "' must be a multiple of " +
-                     std::to_string(required_align) + " bytes, but '" +
-                     member_name_of(m) + "' is currently at offset " +
-                     std::to_string(m->Offset()) +
-                     ". Consider setting @align(" +
-                     std::to_string(required_align) + ") on this member",
-                 m->Declaration()->source);
-
-        AddNote("see layout of struct:\n" + str->Layout(builder_->Symbols()),
-                str->Declaration()->source);
-
-        if (auto* member_str = m->Type()->As<sem::Struct>()) {
-          AddNote("and layout of struct member:\n" +
-                      member_str->Layout(builder_->Symbols()),
-                  member_str->Declaration()->source);
-        }
-
-        return false;
-      }
-
-      // For uniform buffers, validate that the number of bytes between the
-      // previous member of type struct and the current is a multiple of 16
-      // bytes.
-      auto* const prev_member = (i == 0) ? nullptr : str->Members()[i - 1];
-      if (prev_member && is_uniform_struct(prev_member->Type())) {
-        const uint32_t prev_to_curr_offset =
-            m->Offset() - prev_member->Offset();
-        if (prev_to_curr_offset % 16 != 0) {
-          AddError(
-              "uniform storage requires that the number of bytes between the "
-              "start of the previous member of type struct and the current "
-              "member be a multiple of 16 bytes, but there are currently " +
-                  std::to_string(prev_to_curr_offset) + " bytes between '" +
-                  member_name_of(prev_member) + "' and '" + member_name_of(m) +
-                  "'. Consider setting @align(16) on this member",
-              m->Declaration()->source);
-
-          AddNote("see layout of struct:\n" + str->Layout(builder_->Symbols()),
-                  str->Declaration()->source);
-
-          auto* prev_member_str = prev_member->Type()->As<sem::Struct>();
-          AddNote("and layout of previous member struct:\n" +
-                      prev_member_str->Layout(builder_->Symbols()),
-                  prev_member_str->Declaration()->source);
-          return false;
-        }
-      }
-    }
-  }
-
-  // For uniform buffer array members, validate that array elements are
-  // aligned to 16 bytes
-  if (auto* arr = store_ty->As<sem::Array>()) {
-    // Recurse into the element type.
-    // TODO(crbug.com/tint/1388): Ideally we'd pass the source for nested
-    // element type here, but we can't easily get that from the semantic node.
-    // We should consider recursing through the AST type nodes instead.
-    if (!ValidateStorageClassLayout(arr->ElemType(), sc, source, layouts)) {
-      return false;
-    }
-
-    if (sc == ast::StorageClass::kUniform) {
-      // We already validated that this array member is itself aligned to 16
-      // bytes above, so we only need to validate that stride is a multiple
-      // of 16 bytes.
-      if (arr->Stride() % 16 != 0) {
-        // Since WGSL has no stride attribute, try to provide a useful hint
-        // for how the shader author can resolve the issue.
-        std::string hint;
-        if (arr->ElemType()->is_scalar()) {
-          hint =
-              "Consider using a vector or struct as the element type "
-              "instead.";
-        } else if (auto* vec = arr->ElemType()->As<sem::Vector>();
-                   vec && vec->type()->Size() == 4) {
-          hint = "Consider using a vec4 instead.";
-        } else if (arr->ElemType()->Is<sem::Struct>()) {
-          hint =
-              "Consider using the @size attribute on the last struct "
-              "member.";
-        } else {
-          hint =
-              "Consider wrapping the element type in a struct and using "
-              "the "
-              "@size attribute.";
-        }
-        AddError(
-            "uniform storage requires that array elements be aligned to 16 "
-            "bytes, but array element alignment is currently " +
-                std::to_string(arr->Stride()) + ". " + hint,
-            source);
-        return false;
-      }
-    }
-  }
-
-  return true;
-}
-
-bool Resolver::ValidateStorageClassLayout(
-    const sem::Variable* var,
-    ValidTypeStorageLayouts& layouts) const {
-  if (auto* str = var->Type()->UnwrapRef()->As<sem::Struct>()) {
-    if (!ValidateStorageClassLayout(str, var->StorageClass(),
-                                    str->Declaration()->source, layouts)) {
-      AddNote("see declaration of variable", var->Declaration()->source);
-      return false;
-    }
-  } else {
-    Source source = var->Declaration()->source;
-    if (var->Declaration()->type) {
-      source = var->Declaration()->type->source;
-    }
-    if (!ValidateStorageClassLayout(var->Type()->UnwrapRef(),
-                                    var->StorageClass(), source, layouts)) {
-      return false;
-    }
-  }
-
-  return true;
-}
-
-bool Resolver::ValidateGlobalVariable(const sem::Variable* var) const {
-  auto* decl = var->Declaration();
-  if (!ValidateNoDuplicateAttributes(decl->attributes)) {
-    return false;
-  }
-
-  for (auto* attr : decl->attributes) {
-    if (decl->is_const) {
-      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 != var) {
-          AddError("pipeline constant IDs must be unique", attr->source);
-          AddNote("a pipeline constant 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 constants", attr->source);
-        return false;
-      }
-    } else {
-      bool is_shader_io_attribute =
-          attr->IsAnyOf<ast::BuiltinAttribute, ast::InterpolateAttribute,
-                        ast::InvariantAttribute, ast::LocationAttribute>();
-      bool has_io_storage_class =
-          var->StorageClass() == ast::StorageClass::kInput ||
-          var->StorageClass() == ast::StorageClass::kOutput;
-      if (!(attr->IsAnyOf<ast::BindingAttribute, ast::GroupAttribute,
-                          ast::InternalAttribute>()) &&
-          (!is_shader_io_attribute || !has_io_storage_class)) {
-        AddError("attribute is not valid for variables", attr->source);
-        return false;
-      }
-    }
-  }
-
-  if (var->StorageClass() == ast::StorageClass::kFunction) {
-    AddError(
-        "variables declared at module scope must not be in the function "
-        "storage class",
-        decl->source);
-    return false;
-  }
-
-  auto binding_point = decl->BindingPoint();
-  switch (var->StorageClass()) {
-    case ast::StorageClass::kUniform:
-    case ast::StorageClass::kStorage:
-    case ast::StorageClass::kUniformConstant: {
-      // https://gpuweb.github.io/gpuweb/wgsl/#resource-interface
-      // Each resource variable must be declared with both group and binding
-      // attributes.
-      if (!binding_point) {
-        AddError(
-            "resource variables require @group and @binding "
-            "attributes",
-            decl->source);
-        return false;
-      }
-      break;
-    }
-    default:
-      if (binding_point.binding || binding_point.group) {
-        // https://gpuweb.github.io/gpuweb/wgsl/#attribute-binding
-        // Must only be applied to a resource variable
-        AddError(
-            "non-resource variables must not have @group or @binding "
-            "attributes",
-            decl->source);
-        return false;
-      }
-  }
-
-  // https://gpuweb.github.io/gpuweb/wgsl/#variable-declaration
-  // The access mode always has a default, and except for variables in the
-  // storage storage class, must not be written.
-  if (var->StorageClass() != ast::StorageClass::kStorage &&
-      decl->declared_access != ast::Access::kUndefined) {
-    AddError(
-        "only variables in <storage> storage class may declare an access mode",
-        decl->source);
-    return false;
-  }
-
-  if (!decl->is_const) {
-    if (!ValidateAtomicVariable(var)) {
-      return false;
-    }
-  }
-
-  return ValidateVariable(var);
-}
-
-// https://gpuweb.github.io/gpuweb/wgsl/#atomic-types
-// Atomic types may only be instantiated by variables in the workgroup storage
-// class or by storage buffer variables with a read_write access mode.
-bool Resolver::ValidateAtomicVariable(const sem::Variable* var) const {
-  auto sc = var->StorageClass();
-  auto* decl = var->Declaration();
-  auto access = var->Access();
-  auto* type = var->Type()->UnwrapRef();
-  auto source = decl->type ? decl->type->source : decl->source;
-
-  if (type->Is<sem::Atomic>()) {
-    if (sc != ast::StorageClass::kWorkgroup &&
-        sc != ast::StorageClass::kStorage) {
-      AddError(
-          "atomic variables must have <storage> or <workgroup> storage class",
-          source);
-      return false;
-    }
-  } else if (type->IsAnyOf<sem::Struct, sem::Array>()) {
-    auto found = atomic_composite_info_.find(type);
-    if (found != atomic_composite_info_.end()) {
-      if (sc != ast::StorageClass::kStorage &&
-          sc != ast::StorageClass::kWorkgroup) {
-        AddError(
-            "atomic variables must have <storage> or <workgroup> storage class",
-            source);
-        AddNote("atomic sub-type of '" + sem_.TypeNameOf(type) +
-                    "' is declared here",
-                found->second);
-        return false;
-      } else if (sc == ast::StorageClass::kStorage &&
-                 access != ast::Access::kReadWrite) {
-        AddError(
-            "atomic variables in <storage> storage class must have read_write "
-            "access mode",
-            source);
-        AddNote("atomic sub-type of '" + sem_.TypeNameOf(type) +
-                    "' is declared here",
-                found->second);
-        return false;
-      }
-    }
-  }
-
-  return true;
-}
-
-bool Resolver::ValidateVariable(const sem::Variable* var) const {
-  auto* decl = var->Declaration();
-  auto* storage_ty = var->Type()->UnwrapRef();
-
-  if (var->Is<sem::GlobalVariable>()) {
-    auto name = builder_->Symbols().NameFor(decl->symbol);
-    if (sem::ParseBuiltinType(name) != sem::BuiltinType::kNone) {
-      auto* kind = var->Declaration()->is_const ? "let" : "var";
-      AddError(
-          "'" + name +
-              "' is a builtin and cannot be redeclared as a module-scope " +
-              kind,
-          decl->source);
-      return false;
-    }
-  }
-
-  if (!decl->is_const && !IsStorable(storage_ty)) {
-    AddError(
-        sem_.TypeNameOf(storage_ty) + " cannot be used as the type of a var",
-        decl->source);
-    return false;
-  }
-
-  if (decl->is_const && !var->Is<sem::Parameter>() &&
-      !(storage_ty->IsConstructible() || storage_ty->Is<sem::Pointer>())) {
-    AddError(
-        sem_.TypeNameOf(storage_ty) + " cannot be used as the type of a let",
-        decl->source);
-    return false;
-  }
-
-  if (auto* r = storage_ty->As<sem::MultisampledTexture>()) {
-    if (r->dim() != ast::TextureDimension::k2d) {
-      AddError("only 2d multisampled textures are supported", decl->source);
-      return false;
-    }
-
-    if (!r->type()->UnwrapRef()->is_numeric_scalar()) {
-      AddError("texture_multisampled_2d<type>: type must be f32, i32 or u32",
-               decl->source);
-      return false;
-    }
-  }
-
-  if (var->Is<sem::LocalVariable>() && !decl->is_const &&
-      IsValidationEnabled(decl->attributes,
-                          ast::DisabledValidation::kIgnoreStorageClass)) {
-    if (!var->Type()->UnwrapRef()->IsConstructible()) {
-      AddError("function variable must have a constructible type",
-               decl->type ? decl->type->source : decl->source);
-      return false;
-    }
-  }
-
-  if (storage_ty->is_handle() &&
-      decl->declared_storage_class != ast::StorageClass::kNone) {
-    // https://gpuweb.github.io/gpuweb/wgsl/#module-scope-variables
-    // If the store type is a texture type or a sampler type, then the
-    // variable declaration must not have a storage class attribute. The
-    // storage class will always be handle.
-    AddError("variables of type '" + sem_.TypeNameOf(storage_ty) +
-                 "' must not have a storage class",
-             decl->source);
-    return false;
-  }
-
-  if (IsValidationEnabled(decl->attributes,
-                          ast::DisabledValidation::kIgnoreStorageClass) &&
-      (decl->declared_storage_class == ast::StorageClass::kInput ||
-       decl->declared_storage_class == ast::StorageClass::kOutput)) {
-    AddError("invalid use of input/output storage class", decl->source);
-    return false;
-  }
-  return true;
-}
-
-bool Resolver::ValidateFunctionParameter(const ast::Function* func,
-                                         const sem::Variable* var) const {
-  if (!ValidateVariable(var)) {
-    return false;
-  }
-
-  auto* decl = var->Declaration();
-
-  for (auto* attr : decl->attributes) {
-    if (!func->IsEntryPoint() && !attr->Is<ast::InternalAttribute>()) {
-      AddError("attribute is not valid for non-entry point function parameters",
-               attr->source);
-      return false;
-    } else if (!attr->IsAnyOf<ast::BuiltinAttribute, ast::InvariantAttribute,
-                              ast::LocationAttribute, ast::InterpolateAttribute,
-                              ast::InternalAttribute>() &&
-               (IsValidationEnabled(
-                    decl->attributes,
-                    ast::DisabledValidation::kEntryPointParameter) &&
-                IsValidationEnabled(
-                    decl->attributes,
-                    ast::DisabledValidation::
-                        kIgnoreConstructibleFunctionParameter))) {
-      AddError("attribute is not valid for function parameters", attr->source);
-      return false;
-    }
-  }
-
-  if (auto* ref = var->Type()->As<sem::Pointer>()) {
-    auto sc = ref->StorageClass();
-    if (!(sc == ast::StorageClass::kFunction ||
-          sc == ast::StorageClass::kPrivate ||
-          sc == ast::StorageClass::kWorkgroup) &&
-        IsValidationEnabled(decl->attributes,
-                            ast::DisabledValidation::kIgnoreStorageClass)) {
-      std::stringstream ss;
-      ss << "function parameter of pointer type cannot be in '" << sc
-         << "' storage class";
-      AddError(ss.str(), decl->source);
-      return false;
-    }
-  }
-
-  if (IsPlain(var->Type())) {
-    if (!var->Type()->IsConstructible() &&
-        IsValidationEnabled(
-            decl->attributes,
-            ast::DisabledValidation::kIgnoreConstructibleFunctionParameter)) {
-      AddError("store type of function parameter must be a constructible type",
-               decl->source);
-      return false;
-    }
-  } else if (!var->Type()
-                  ->IsAnyOf<sem::Texture, sem::Sampler, sem::Pointer>()) {
-    AddError("store type of function parameter cannot be " +
-                 sem_.TypeNameOf(var->Type()),
-             decl->source);
-    return false;
-  }
-
-  return true;
-}
-
-bool Resolver::ValidateBuiltinAttribute(const ast::BuiltinAttribute* attr,
-                                        const sem::Type* storage_ty,
-                                        ast::PipelineStage stage,
-                                        const bool is_input) const {
-  auto* type = storage_ty->UnwrapRef();
-  std::stringstream stage_name;
-  stage_name << stage;
-  bool is_stage_mismatch = false;
-  bool is_output = !is_input;
-  switch (attr->builtin) {
-    case ast::Builtin::kPosition:
-      if (stage != ast::PipelineStage::kNone &&
-          !((is_input && stage == ast::PipelineStage::kFragment) ||
-            (is_output && stage == ast::PipelineStage::kVertex))) {
-        is_stage_mismatch = true;
-      }
-      if (!(type->is_float_vector() && type->As<sem::Vector>()->Width() == 4)) {
-        AddError("store type of " + attr_to_str(attr) + " must be 'vec4<f32>'",
-                 attr->source);
-        return false;
-      }
-      break;
-    case ast::Builtin::kGlobalInvocationId:
-    case ast::Builtin::kLocalInvocationId:
-    case ast::Builtin::kNumWorkgroups:
-    case ast::Builtin::kWorkgroupId:
-      if (stage != ast::PipelineStage::kNone &&
-          !(stage == ast::PipelineStage::kCompute && is_input)) {
-        is_stage_mismatch = true;
-      }
-      if (!(type->is_unsigned_integer_vector() &&
-            type->As<sem::Vector>()->Width() == 3)) {
-        AddError("store type of " + attr_to_str(attr) + " must be 'vec3<u32>'",
-                 attr->source);
-        return false;
-      }
-      break;
-    case ast::Builtin::kFragDepth:
-      if (stage != ast::PipelineStage::kNone &&
-          !(stage == ast::PipelineStage::kFragment && !is_input)) {
-        is_stage_mismatch = true;
-      }
-      if (!type->Is<sem::F32>()) {
-        AddError("store type of " + attr_to_str(attr) + " must be 'f32'",
-                 attr->source);
-        return false;
-      }
-      break;
-    case ast::Builtin::kFrontFacing:
-      if (stage != ast::PipelineStage::kNone &&
-          !(stage == ast::PipelineStage::kFragment && is_input)) {
-        is_stage_mismatch = true;
-      }
-      if (!type->Is<sem::Bool>()) {
-        AddError("store type of " + attr_to_str(attr) + " must be 'bool'",
-                 attr->source);
-        return false;
-      }
-      break;
-    case ast::Builtin::kLocalInvocationIndex:
-      if (stage != ast::PipelineStage::kNone &&
-          !(stage == ast::PipelineStage::kCompute && is_input)) {
-        is_stage_mismatch = true;
-      }
-      if (!type->Is<sem::U32>()) {
-        AddError("store type of " + attr_to_str(attr) + " must be 'u32'",
-                 attr->source);
-        return false;
-      }
-      break;
-    case ast::Builtin::kVertexIndex:
-    case ast::Builtin::kInstanceIndex:
-      if (stage != ast::PipelineStage::kNone &&
-          !(stage == ast::PipelineStage::kVertex && is_input)) {
-        is_stage_mismatch = true;
-      }
-      if (!type->Is<sem::U32>()) {
-        AddError("store type of " + attr_to_str(attr) + " must be 'u32'",
-                 attr->source);
-        return false;
-      }
-      break;
-    case ast::Builtin::kSampleMask:
-      if (stage != ast::PipelineStage::kNone &&
-          !(stage == ast::PipelineStage::kFragment)) {
-        is_stage_mismatch = true;
-      }
-      if (!type->Is<sem::U32>()) {
-        AddError("store type of " + attr_to_str(attr) + " must be 'u32'",
-                 attr->source);
-        return false;
-      }
-      break;
-    case ast::Builtin::kSampleIndex:
-      if (stage != ast::PipelineStage::kNone &&
-          !(stage == ast::PipelineStage::kFragment && is_input)) {
-        is_stage_mismatch = true;
-      }
-      if (!type->Is<sem::U32>()) {
-        AddError("store type of " + attr_to_str(attr) + " must be 'u32'",
-                 attr->source);
-        return false;
-      }
-      break;
-    default:
-      break;
-  }
-
-  if (is_stage_mismatch) {
-    AddError(attr_to_str(attr) + " cannot be used in " +
-                 (is_input ? "input of " : "output of ") + stage_name.str() +
-                 " pipeline stage",
-             attr->source);
-    return false;
-  }
-
-  return true;
-}
-
-bool Resolver::ValidateInterpolateAttribute(
-    const ast::InterpolateAttribute* attr,
-    const sem::Type* storage_ty) const {
-  auto* type = storage_ty->UnwrapRef();
-
-  if (type->is_integer_scalar_or_vector() &&
-      attr->type != ast::InterpolationType::kFlat) {
-    AddError(
-        "interpolation type must be 'flat' for integral user-defined IO types",
-        attr->source);
-    return false;
-  }
-
-  if (attr->type == ast::InterpolationType::kFlat &&
-      attr->sampling != ast::InterpolationSampling::kNone) {
-    AddError("flat interpolation attribute must not have a sampling parameter",
-             attr->source);
-    return false;
-  }
-
-  return true;
-}
-
-bool Resolver::ValidateFunction(const sem::Function* func,
-                                ast::PipelineStage stage) const {
-  auto* decl = func->Declaration();
-
-  auto name = builder_->Symbols().NameFor(decl->symbol);
-  if (sem::ParseBuiltinType(name) != sem::BuiltinType::kNone) {
-    AddError(
-        "'" + name + "' is a builtin and cannot be redeclared as a function",
-        decl->source);
-    return false;
-  }
-
-  auto workgroup_attr_count = 0;
-  for (auto* attr : decl->attributes) {
-    if (attr->Is<ast::WorkgroupAttribute>()) {
-      workgroup_attr_count++;
-      if (decl->PipelineStage() != ast::PipelineStage::kCompute) {
-        AddError(
-            "the workgroup_size attribute is only valid for compute stages",
-            attr->source);
-        return false;
-      }
-    } else if (!attr->IsAnyOf<ast::StageAttribute, ast::InternalAttribute>()) {
-      AddError("attribute is not valid for functions", attr->source);
-      return false;
-    }
-  }
-
-  if (decl->params.size() > 255) {
-    AddError("functions may declare at most 255 parameters", decl->source);
-    return false;
-  }
-
-  for (size_t i = 0; i < decl->params.size(); i++) {
-    if (!ValidateFunctionParameter(decl, func->Parameters()[i])) {
-      return false;
-    }
-  }
-
-  if (!func->ReturnType()->Is<sem::Void>()) {
-    if (!func->ReturnType()->IsConstructible()) {
-      AddError("function return type must be a constructible type",
-               decl->return_type->source);
-      return false;
-    }
-
-    if (decl->body) {
-      sem::Behaviors behaviors{sem::Behavior::kNext};
-      if (auto* last = decl->body->Last()) {
-        behaviors = sem_.Get(last)->Behaviors();
-      }
-      if (behaviors.Contains(sem::Behavior::kNext)) {
-        AddError("missing return at end of function", decl->source);
-        return false;
-      }
-    } else if (IsValidationEnabled(
-                   decl->attributes,
-                   ast::DisabledValidation::kFunctionHasNoBody)) {
-      TINT_ICE(Resolver, diagnostics_)
-          << "Function " << builder_->Symbols().NameFor(decl->symbol)
-          << " has no body";
-    }
-
-    for (auto* attr : decl->return_type_attributes) {
-      if (!decl->IsEntryPoint()) {
-        AddError(
-            "attribute is not valid for non-entry point function return types",
-            attr->source);
-        return false;
-      }
-      if (!attr->IsAnyOf<ast::BuiltinAttribute, ast::InternalAttribute,
-                         ast::LocationAttribute, ast::InterpolateAttribute,
-                         ast::InvariantAttribute>() &&
-          (IsValidationEnabled(decl->attributes,
-                               ast::DisabledValidation::kEntryPointParameter) &&
-           IsValidationEnabled(decl->attributes,
-                               ast::DisabledValidation::
-                                   kIgnoreConstructibleFunctionParameter))) {
-        AddError("attribute is not valid for entry point return types",
-                 attr->source);
-        return false;
-      }
-    }
-  }
-
-  if (decl->IsEntryPoint()) {
-    if (!ValidateEntryPoint(func, stage)) {
-      return false;
-    }
-  }
-
-  // https://www.w3.org/TR/WGSL/#behaviors-rules
-  // a function behavior is always one of {}, {Next}, {Discard}, or
-  // {Next, Discard}.
-  if (func->Behaviors() != sem::Behaviors{} &&  // NOLINT: bad warning
-      func->Behaviors() != sem::Behavior::kNext &&
-      func->Behaviors() != sem::Behavior::kDiscard &&
-      func->Behaviors() != sem::Behaviors{sem::Behavior::kNext,  //
-                                          sem::Behavior::kDiscard}) {
-    TINT_ICE(Resolver, diagnostics_)
-        << "function '" << name << "' behaviors are: " << func->Behaviors();
-  }
-
-  return true;
-}
-
-bool Resolver::ValidateEntryPoint(const sem::Function* func,
-                                  ast::PipelineStage stage) const {
-  auto* decl = func->Declaration();
-
-  // Use a lambda to validate the entry point attributes for a type.
-  // Persistent state is used to track which builtins and locations have
-  // 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<uint32_t> locations;
-  enum class ParamOrRetType {
-    kParameter,
-    kReturnType,
-  };
-
-  // Inner lambda that is applied to a type and all of its members.
-  auto validate_entry_point_attributes_inner = [&](const ast::AttributeList&
-                                                       attrs,
-                                                   const sem::Type* ty,
-                                                   Source source,
-                                                   ParamOrRetType param_or_ret,
-                                                   bool is_struct_member) {
-    // Scan attributes for pipeline IO attributes.
-    // Check for overlap with attributes that have been seen previously.
-    const ast::Attribute* pipeline_io_attribute = nullptr;
-    const ast::InterpolateAttribute* interpolate_attribute = nullptr;
-    const ast::InvariantAttribute* invariant_attribute = nullptr;
-    for (auto* attr : attrs) {
-      auto is_invalid_compute_shader_attribute = false;
-
-      if (auto* builtin = attr->As<ast::BuiltinAttribute>()) {
-        if (pipeline_io_attribute) {
-          AddError("multiple entry point IO attributes", attr->source);
-          AddNote("previously consumed " + attr_to_str(pipeline_io_attribute),
-                  pipeline_io_attribute->source);
-          return false;
-        }
-        pipeline_io_attribute = attr;
-
-        if (builtins.count(builtin->builtin)) {
-          AddError(attr_to_str(builtin) +
-                       " attribute appears multiple times as pipeline " +
-                       (param_or_ret == ParamOrRetType::kParameter ? "input"
-                                                                   : "output"),
-                   decl->source);
-          return false;
-        }
-
-        if (!ValidateBuiltinAttribute(
-                builtin, ty, stage,
-                /* is_input */ param_or_ret == ParamOrRetType::kParameter)) {
-          return false;
-        }
-        builtins.emplace(builtin->builtin);
-      } else if (auto* location = attr->As<ast::LocationAttribute>()) {
-        if (pipeline_io_attribute) {
-          AddError("multiple entry point IO attributes", attr->source);
-          AddNote("previously consumed " + attr_to_str(pipeline_io_attribute),
-                  pipeline_io_attribute->source);
-          return false;
-        }
-        pipeline_io_attribute = attr;
-
-        bool is_input = param_or_ret == ParamOrRetType::kParameter;
-
-        if (!ValidateLocationAttribute(location, ty, locations, stage, source,
-                                       is_input)) {
-          return false;
-        }
-      } else if (auto* interpolate = attr->As<ast::InterpolateAttribute>()) {
-        if (decl->PipelineStage() == ast::PipelineStage::kCompute) {
-          is_invalid_compute_shader_attribute = true;
-        } else if (!ValidateInterpolateAttribute(interpolate, ty)) {
-          return false;
-        }
-        interpolate_attribute = interpolate;
-      } else if (auto* invariant = attr->As<ast::InvariantAttribute>()) {
-        if (decl->PipelineStage() == ast::PipelineStage::kCompute) {
-          is_invalid_compute_shader_attribute = true;
-        }
-        invariant_attribute = invariant;
-      }
-      if (is_invalid_compute_shader_attribute) {
-        std::string input_or_output =
-            param_or_ret == ParamOrRetType::kParameter ? "inputs" : "output";
-        AddError("attribute is not valid for compute shader " + input_or_output,
-                 attr->source);
-        return false;
-      }
-    }
-
-    if (IsValidationEnabled(attrs,
-                            ast::DisabledValidation::kEntryPointParameter)) {
-      if (is_struct_member && ty->Is<sem::Struct>()) {
-        AddError("nested structures cannot be used for entry point IO", source);
-        return false;
-      }
-
-      if (!ty->Is<sem::Struct>() && !pipeline_io_attribute) {
-        std::string err = "missing entry point IO attribute";
-        if (!is_struct_member) {
-          err +=
-              (param_or_ret == ParamOrRetType::kParameter ? " on parameter"
-                                                          : " on return type");
-        }
-        AddError(err, source);
-        return false;
-      }
-
-      if (pipeline_io_attribute &&
-          pipeline_io_attribute->Is<ast::LocationAttribute>()) {
-        if (ty->is_integer_scalar_or_vector() && !interpolate_attribute) {
-          if (decl->PipelineStage() == ast::PipelineStage::kVertex &&
-              param_or_ret == ParamOrRetType::kReturnType) {
-            AddError(
-                "integral user-defined vertex outputs must have a flat "
-                "interpolation attribute",
-                source);
-            return false;
-          }
-          if (decl->PipelineStage() == ast::PipelineStage::kFragment &&
-              param_or_ret == ParamOrRetType::kParameter) {
-            AddError(
-                "integral user-defined fragment inputs must have a flat "
-                "interpolation attribute",
-                source);
-            return false;
-          }
-        }
-      }
-
-      if (interpolate_attribute) {
-        if (!pipeline_io_attribute ||
-            !pipeline_io_attribute->Is<ast::LocationAttribute>()) {
-          AddError("interpolate attribute must only be used with @location",
-                   interpolate_attribute->source);
-          return false;
-        }
-      }
-
-      if (invariant_attribute) {
-        bool has_position = false;
-        if (pipeline_io_attribute) {
-          if (auto* builtin =
-                  pipeline_io_attribute->As<ast::BuiltinAttribute>()) {
-            has_position = (builtin->builtin == ast::Builtin::kPosition);
-          }
-        }
-        if (!has_position) {
-          AddError(
-              "invariant attribute must only be applied to a position "
-              "builtin",
-              invariant_attribute->source);
-          return false;
-        }
-      }
-    }
-    return true;
-  };
-
-  // Outer lambda for validating the entry point attributes for a type.
-  auto validate_entry_point_attributes = [&](const ast::AttributeList& attrs,
-                                             const sem::Type* ty, Source source,
-                                             ParamOrRetType param_or_ret) {
-    if (!validate_entry_point_attributes_inner(attrs, ty, source, param_or_ret,
-                                               /*is_struct_member*/ false)) {
-      return false;
-    }
-
-    if (auto* str = ty->As<sem::Struct>()) {
-      for (auto* member : str->Members()) {
-        if (!validate_entry_point_attributes_inner(
-                member->Declaration()->attributes, member->Type(),
-                member->Declaration()->source, param_or_ret,
-                /*is_struct_member*/ true)) {
-          AddNote("while analysing entry point '" +
-                      builder_->Symbols().NameFor(decl->symbol) + "'",
-                  decl->source);
-          return false;
-        }
-      }
-    }
-
-    return true;
-  };
-
-  for (auto* param : func->Parameters()) {
-    auto* param_decl = param->Declaration();
-    if (!validate_entry_point_attributes(param_decl->attributes, param->Type(),
-                                         param_decl->source,
-                                         ParamOrRetType::kParameter)) {
-      return false;
-    }
-  }
-
-  // Clear IO sets after parameter validation. Builtin and location attributes
-  // in return types should be validated independently from those used in
-  // parameters.
-  builtins.clear();
-  locations.clear();
-
-  if (!func->ReturnType()->Is<sem::Void>()) {
-    if (!validate_entry_point_attributes(decl->return_type_attributes,
-                                         func->ReturnType(), decl->source,
-                                         ParamOrRetType::kReturnType)) {
-      return false;
-    }
-  }
-
-  if (decl->PipelineStage() == ast::PipelineStage::kVertex &&
-      builtins.count(ast::Builtin::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) {
-          found = true;
-          break;
-        }
-      }
-    }
-    if (!found) {
-      AddError(
-          "a vertex shader must include the 'position' builtin in its return "
-          "type",
-          decl->source);
-      return false;
-    }
-  }
-
-  if (decl->PipelineStage() == ast::PipelineStage::kCompute) {
-    if (!ast::HasAttribute<ast::WorkgroupAttribute>(decl->attributes)) {
-      AddError(
-          "a compute shader must include 'workgroup_size' in its "
-          "attributes",
-          decl->source);
-      return false;
-    }
-  }
-
-  // Validate there are no resource variable binding collisions
-  std::unordered_map<sem::BindingPoint, const ast::Variable*> binding_points;
-  for (auto* var : func->TransitivelyReferencedGlobals()) {
-    auto* var_decl = var->Declaration();
-    if (!var_decl->BindingPoint()) {
-      continue;
-    }
-    auto bp = var->BindingPoint();
-    auto res = binding_points.emplace(bp, var_decl);
-    if (!res.second &&
-        IsValidationEnabled(decl->attributes,
-                            ast::DisabledValidation::kBindingPointCollision) &&
-        IsValidationEnabled(res.first->second->attributes,
-                            ast::DisabledValidation::kBindingPointCollision)) {
-      // https://gpuweb.github.io/gpuweb/wgsl/#resource-interface
-      // Bindings must not alias within a shader stage: two different
-      // variables in the resource interface of a given shader must not have
-      // the same group and binding values, when considered as a pair of
-      // values.
-      auto func_name = builder_->Symbols().NameFor(decl->symbol);
-      AddError("entry point '" + func_name +
-                   "' references multiple variables that use the "
-                   "same resource binding @group(" +
-                   std::to_string(bp.group) + "), @binding(" +
-                   std::to_string(bp.binding) + ")",
-               var_decl->source);
-      AddNote("first resource binding usage declared here",
-              res.first->second->source);
-      return false;
-    }
-  }
-
-  return true;
-}
-
-bool Resolver::ValidateStatements(const ast::StatementList& stmts) const {
-  for (auto* stmt : stmts) {
-    if (!sem_.Get(stmt)->IsReachable()) {
-      /// TODO(https://github.com/gpuweb/gpuweb/issues/2378): This may need to
-      /// become an error.
-      AddWarning("code is unreachable", stmt->source);
-      break;
-    }
-  }
-  return true;
-}
-
-bool Resolver::ValidateBitcast(const ast::BitcastExpression* cast,
-                               const sem::Type* to) const {
-  auto* from = sem_.TypeOf(cast->expr)->UnwrapRef();
-  if (!from->is_numeric_scalar_or_vector()) {
-    AddError("'" + sem_.TypeNameOf(from) + "' cannot be bitcast",
-             cast->expr->source);
-    return false;
-  }
-  if (!to->is_numeric_scalar_or_vector()) {
-    AddError("cannot bitcast to '" + sem_.TypeNameOf(to) + "'",
-             cast->type->source);
-    return false;
-  }
-
-  auto width = [&](const sem::Type* ty) {
-    if (auto* vec = ty->As<sem::Vector>()) {
-      return vec->Width();
-    }
-    return 1u;
-  };
-
-  if (width(from) != width(to)) {
-    AddError("cannot bitcast from '" + sem_.TypeNameOf(from) + "' to '" +
-                 sem_.TypeNameOf(to) + "'",
-             cast->source);
-    return false;
-  }
-
-  return true;
-}
-
-bool Resolver::ValidateBreakStatement(const sem::Statement* stmt) const {
-  if (!stmt->FindFirstParent<sem::LoopBlockStatement, sem::CaseStatement>()) {
-    AddError("break statement must be in a loop or switch case",
-             stmt->Declaration()->source);
-    return false;
-  }
-  if (auto* continuing = ClosestContinuing(/*stop_at_loop*/ true)) {
-    auto fail = [&](const char* note_msg, const Source& note_src) {
-      constexpr const char* kErrorMsg =
-          "break statement in a continuing block must be the single statement "
-          "of an if statement's true or false block, and that if statement "
-          "must be the last statement of the continuing block";
-      AddError(kErrorMsg, stmt->Declaration()->source);
-      AddNote(note_msg, note_src);
-      return false;
-    };
-
-    if (auto* block = stmt->Parent()->As<sem::BlockStatement>()) {
-      auto* block_parent = block->Parent();
-      auto* if_stmt = block_parent->As<sem::IfStatement>();
-      auto* el_stmt = block_parent->As<sem::ElseStatement>();
-      if (el_stmt) {
-        if_stmt = el_stmt->Parent();
-      }
-      if (!if_stmt) {
-        return fail("break statement is not directly in if statement block",
-                    stmt->Declaration()->source);
-      }
-      if (block->Declaration()->statements.size() != 1) {
-        return fail("if statement block contains multiple statements",
-                    block->Declaration()->source);
-      }
-      for (auto* el : if_stmt->Declaration()->else_statements) {
-        if (el->condition) {
-          return fail("else has condition", el->condition->source);
-        }
-        bool el_contains_break = el_stmt && el == el_stmt->Declaration();
-        if (el_contains_break) {
-          if (auto* true_block = if_stmt->Declaration()->body;
-              !true_block->Empty()) {
-            return fail("non-empty true block", true_block->source);
-          }
-        } else {
-          if (!el->body->Empty()) {
-            return fail("non-empty false block", el->body->source);
-          }
-        }
-      }
-      if (if_stmt->Parent()->Declaration() != continuing) {
-        return fail(
-            "if statement containing break statement is not directly in "
-            "continuing block",
-            if_stmt->Declaration()->source);
-      }
-      if (auto* cont_block = continuing->As<ast::BlockStatement>()) {
-        if (if_stmt->Declaration() != cont_block->Last()) {
-          return fail(
-              "if statement containing break statement is not the last "
-              "statement of the continuing block",
-              if_stmt->Declaration()->source);
-        }
-      }
-    }
-  }
-  return true;
-}
-
-bool Resolver::ValidateContinueStatement(const sem::Statement* stmt) const {
-  if (auto* continuing = ClosestContinuing(/*stop_at_loop*/ true)) {
-    AddError("continuing blocks must not contain a continue statement",
-             stmt->Declaration()->source);
-    if (continuing != stmt->Declaration() &&
-        continuing != stmt->Parent()->Declaration()) {
-      AddNote("see continuing block here", continuing->source);
-    }
-    return false;
-  }
-
-  if (!stmt->FindFirstParent<sem::LoopBlockStatement>()) {
-    AddError("continue statement must be in a loop",
-             stmt->Declaration()->source);
-    return false;
-  }
-
-  return true;
-}
-
-bool Resolver::ValidateDiscardStatement(const sem::Statement* stmt) const {
-  if (auto* continuing = ClosestContinuing(/*stop_at_loop*/ false)) {
-    AddError("continuing blocks must not contain a discard statement",
-             stmt->Declaration()->source);
-    if (continuing != stmt->Declaration() &&
-        continuing != stmt->Parent()->Declaration()) {
-      AddNote("see continuing block here", continuing->source);
-    }
-    return false;
-  }
-  return true;
-}
-
-bool Resolver::ValidateFallthroughStatement(const sem::Statement* stmt) const {
-  if (auto* block = As<sem::BlockStatement>(stmt->Parent())) {
-    if (auto* c = As<sem::CaseStatement>(block->Parent())) {
-      if (block->Declaration()->Last() == stmt->Declaration()) {
-        if (auto* s = As<sem::SwitchStatement>(c->Parent())) {
-          if (c->Declaration() != s->Declaration()->body.back()) {
-            return true;
-          }
-          AddError(
-              "a fallthrough statement must not be used in the last switch "
-              "case",
-              stmt->Declaration()->source);
-          return false;
-        }
-      }
-    }
-  }
-  AddError(
-      "fallthrough must only be used as the last statement of a case block",
-      stmt->Declaration()->source);
-  return false;
-}
-
-bool Resolver::ValidateElseStatement(const sem::ElseStatement* stmt) const {
-  if (auto* cond = stmt->Condition()) {
-    auto* cond_ty = cond->Type()->UnwrapRef();
-    if (!cond_ty->Is<sem::Bool>()) {
-      AddError("else statement condition must be bool, got " +
-                   sem_.TypeNameOf(cond_ty),
-               stmt->Condition()->Declaration()->source);
-      return false;
-    }
-  }
-  return true;
-}
-
-bool Resolver::ValidateLoopStatement(const sem::LoopStatement* stmt) const {
-  if (stmt->Behaviors().Empty()) {
-    AddError("loop does not exit", stmt->Declaration()->source.Begin());
-    return false;
-  }
-  return true;
-}
-
-bool Resolver::ValidateForLoopStatement(
-    const sem::ForLoopStatement* stmt) const {
-  if (stmt->Behaviors().Empty()) {
-    AddError("for-loop does not exit", stmt->Declaration()->source.Begin());
-    return false;
-  }
-  if (auto* cond = stmt->Condition()) {
-    auto* cond_ty = cond->Type()->UnwrapRef();
-    if (!cond_ty->Is<sem::Bool>()) {
-      AddError(
-          "for-loop condition must be bool, got " + sem_.TypeNameOf(cond_ty),
-          stmt->Condition()->Declaration()->source);
-      return false;
-    }
-  }
-  return true;
-}
-
-bool Resolver::ValidateIfStatement(const sem::IfStatement* stmt) const {
-  auto* cond_ty = stmt->Condition()->Type()->UnwrapRef();
-  if (!cond_ty->Is<sem::Bool>()) {
-    AddError(
-        "if statement condition must be bool, got " + sem_.TypeNameOf(cond_ty),
-        stmt->Condition()->Declaration()->source);
-    return false;
-  }
-  return true;
-}
-
-bool Resolver::ValidateBuiltinCall(const sem::Call* call) const {
-  if (call->Type()->Is<sem::Void>()) {
-    bool is_call_statement = false;
-    if (auto* call_stmt = As<ast::CallStatement>(call->Stmt()->Declaration())) {
-      if (call_stmt->expr == call->Declaration()) {
-        is_call_statement = true;
-      }
-    }
-    if (!is_call_statement) {
-      // https://gpuweb.github.io/gpuweb/wgsl/#function-call-expr
-      // If the called function does not return a value, a function call
-      // statement should be used instead.
-      auto* ident = call->Declaration()->target.name;
-      auto name = builder_->Symbols().NameFor(ident->symbol);
-      AddError("builtin '" + name + "' does not return a value",
-               call->Declaration()->source);
-      return false;
-    }
-  }
-
-  return true;
-}
-
-bool Resolver::ValidateTextureBuiltinFunction(const sem::Call* call) const {
-  auto* builtin = call->Target()->As<sem::Builtin>();
-  if (!builtin) {
-    return false;
-  }
-
-  std::string func_name = builtin->str();
-  auto& signature = builtin->Signature();
-
-  auto check_arg_is_constexpr = [&](sem::ParameterUsage usage, int min,
-                                    int max) {
-    auto index = signature.IndexOf(usage);
-    if (index < 0) {
-      return true;
-    }
-    std::string name = sem::str(usage);
-    auto* arg = call->Arguments()[index];
-    if (auto values = arg->ConstantValue()) {
-      // Assert that the constant values are of the expected type.
-      if (!values.Type()->IsAnyOf<sem::I32, sem::Vector>() ||
-          !values.ElementType()->Is<sem::I32>()) {
-        TINT_ICE(Resolver, diagnostics_)
-            << "failed to resolve '" + func_name + "' " << name
-            << " parameter type";
-        return false;
-      }
-
-      // Currently const_expr is restricted to literals and type constructors.
-      // Check that that's all we have for the parameter.
-      bool is_const_expr = true;
-      ast::TraverseExpressions(
-          arg->Declaration(), diagnostics_, [&](const ast::Expression* e) {
-            if (e->IsAnyOf<ast::LiteralExpression, ast::CallExpression>()) {
-              return ast::TraverseAction::Descend;
-            }
-            is_const_expr = false;
-            return ast::TraverseAction::Stop;
-          });
-      if (is_const_expr) {
-        auto vector = builtin->Parameters()[index]->Type()->Is<sem::Vector>();
-        for (size_t i = 0; i < values.Elements().size(); i++) {
-          auto value = values.Elements()[i].i32;
-          if (value < min || value > max) {
-            if (vector) {
-              AddError("each component of the " + name +
-                           " argument must be at least " + std::to_string(min) +
-                           " and at most " + std::to_string(max) + ". " + name +
-                           " component " + std::to_string(i) + " is " +
-                           std::to_string(value),
-                       arg->Declaration()->source);
-            } else {
-              AddError("the " + name + " argument must be at least " +
-                           std::to_string(min) + " and at most " +
-                           std::to_string(max) + ". " + name + " is " +
-                           std::to_string(value),
-                       arg->Declaration()->source);
-            }
-            return false;
-          }
-        }
-        return true;
-      }
-    }
-    AddError("the " + name + " argument must be a const_expression",
-             arg->Declaration()->source);
-    return false;
-  };
-
-  return check_arg_is_constexpr(sem::ParameterUsage::kOffset, -8, 7) &&
-         check_arg_is_constexpr(sem::ParameterUsage::kComponent, 0, 3);
-}
-
-bool Resolver::ValidateFunctionCall(const sem::Call* call) const {
-  auto* decl = call->Declaration();
-  auto* target = call->Target()->As<sem::Function>();
-  auto sym = decl->target.name->symbol;
-  auto name = builder_->Symbols().NameFor(sym);
-
-  if (target->Declaration()->IsEntryPoint()) {
-    // https://www.w3.org/TR/WGSL/#function-restriction
-    // An entry point must never be the target of a function call.
-    AddError("entry point functions cannot be the target of a function call",
-             decl->source);
-    return false;
-  }
-
-  if (decl->args.size() != target->Parameters().size()) {
-    bool more = decl->args.size() > target->Parameters().size();
-    AddError("too " + (more ? std::string("many") : std::string("few")) +
-                 " arguments in call to '" + name + "', expected " +
-                 std::to_string(target->Parameters().size()) + ", got " +
-                 std::to_string(call->Arguments().size()),
-             decl->source);
-    return false;
-  }
-
-  for (size_t i = 0; i < call->Arguments().size(); ++i) {
-    const sem::Variable* param = target->Parameters()[i];
-    const ast::Expression* arg_expr = decl->args[i];
-    auto* param_type = param->Type();
-    auto* arg_type = sem_.TypeOf(arg_expr)->UnwrapRef();
-
-    if (param_type != arg_type) {
-      AddError("type mismatch for argument " + std::to_string(i + 1) +
-                   " in call to '" + name + "', expected '" +
-                   sem_.TypeNameOf(param_type) + "', got '" +
-                   sem_.TypeNameOf(arg_type) + "'",
-               arg_expr->source);
-      return false;
-    }
-
-    if (param_type->Is<sem::Pointer>()) {
-      auto is_valid = false;
-      if (auto* ident_expr = arg_expr->As<ast::IdentifierExpression>()) {
-        auto* var = ResolvedSymbol<sem::Variable>(ident_expr);
-        if (!var) {
-          TINT_ICE(Resolver, diagnostics_) << "failed to resolve identifier";
-          return false;
-        }
-        if (var->Is<sem::Parameter>()) {
-          is_valid = true;
-        }
-      } else if (auto* unary = arg_expr->As<ast::UnaryOpExpression>()) {
-        if (unary->op == ast::UnaryOp::kAddressOf) {
-          if (auto* ident_unary =
-                  unary->expr->As<ast::IdentifierExpression>()) {
-            auto* var = ResolvedSymbol<sem::Variable>(ident_unary);
-            if (!var) {
-              TINT_ICE(Resolver, diagnostics_)
-                  << "failed to resolve identifier";
-              return false;
-            }
-            if (var->Declaration()->is_const) {
-              TINT_ICE(Resolver, diagnostics_)
-                  << "Resolver::FunctionCall() encountered an address-of "
-                     "expression of a constant identifier expression";
-              return false;
-            }
-            is_valid = true;
-          }
-        }
-      }
-
-      if (!is_valid &&
-          IsValidationEnabled(
-              param->Declaration()->attributes,
-              ast::DisabledValidation::kIgnoreInvalidPointerArgument)) {
-        AddError(
-            "expected an address-of expression of a variable identifier "
-            "expression or a function parameter",
-            arg_expr->source);
-        return false;
-      }
-    }
-  }
-
-  if (call->Type()->Is<sem::Void>()) {
-    bool is_call_statement = false;
-    if (auto* call_stmt = As<ast::CallStatement>(call->Stmt()->Declaration())) {
-      if (call_stmt->expr == call->Declaration()) {
-        is_call_statement = true;
-      }
-    }
-    if (!is_call_statement) {
-      // https://gpuweb.github.io/gpuweb/wgsl/#function-call-expr
-      // If the called function does not return a value, a function call
-      // statement should be used instead.
-      AddError("function '" + name + "' does not return a value", decl->source);
-      return false;
-    }
-  }
-
-  if (call->Behaviors().Contains(sem::Behavior::kDiscard)) {
-    if (auto* continuing = ClosestContinuing(/*stop_at_loop*/ false)) {
-      AddError(
-          "cannot call a function that may discard inside a continuing block",
-          call->Declaration()->source);
-      if (continuing != call->Stmt()->Declaration() &&
-          continuing != call->Stmt()->Parent()->Declaration()) {
-        AddNote("see continuing block here", continuing->source);
-      }
-      return false;
-    }
-  }
-
-  return true;
-}
-
-bool Resolver::ValidateStructureConstructorOrCast(
-    const ast::CallExpression* ctor,
-    const sem::Struct* struct_type) const {
-  if (!struct_type->IsConstructible()) {
-    AddError("struct constructor has non-constructible type", ctor->source);
-    return false;
-  }
-
-  if (ctor->args.size() > 0) {
-    if (ctor->args.size() != struct_type->Members().size()) {
-      std::string fm =
-          ctor->args.size() < struct_type->Members().size() ? "few" : "many";
-      AddError("struct constructor has too " + fm + " inputs: expected " +
-                   std::to_string(struct_type->Members().size()) + ", found " +
-                   std::to_string(ctor->args.size()),
-               ctor->source);
-      return false;
-    }
-    for (auto* member : struct_type->Members()) {
-      auto* value = ctor->args[member->Index()];
-      auto* value_ty = sem_.TypeOf(value);
-      if (member->Type() != value_ty->UnwrapRef()) {
-        AddError(
-            "type in struct constructor does not match struct member type: "
-            "expected '" +
-                sem_.TypeNameOf(member->Type()) + "', found '" +
-                sem_.TypeNameOf(value_ty) + "'",
-            value->source);
-        return false;
-      }
-    }
-  }
-  return true;
-}
-
-bool Resolver::ValidateArrayConstructorOrCast(
-    const ast::CallExpression* ctor,
-    const sem::Array* array_type) const {
-  auto& values = ctor->args;
-  auto* elem_ty = array_type->ElemType();
-  for (auto* value : values) {
-    auto* value_ty = sem_.TypeOf(value)->UnwrapRef();
-    if (value_ty != elem_ty) {
-      AddError(
-          "type in array constructor does not match array type: "
-          "expected '" +
-              sem_.TypeNameOf(elem_ty) + "', found '" +
-              sem_.TypeNameOf(value_ty) + "'",
-          value->source);
-      return false;
-    }
-  }
-
-  if (array_type->IsRuntimeSized()) {
-    AddError("cannot init a runtime-sized array", ctor->source);
-    return false;
-  } else if (!elem_ty->IsConstructible()) {
-    AddError("array constructor has non-constructible element type",
-             ctor->source);
-    return false;
-  } else if (!values.empty() && (values.size() != array_type->Count())) {
-    std::string fm = values.size() < array_type->Count() ? "few" : "many";
-    AddError("array constructor has too " + fm + " elements: expected " +
-                 std::to_string(array_type->Count()) + ", found " +
-                 std::to_string(values.size()),
-             ctor->source);
-    return false;
-  } else if (values.size() > array_type->Count()) {
-    AddError("array constructor has too many elements: expected " +
-                 std::to_string(array_type->Count()) + ", found " +
-                 std::to_string(values.size()),
-             ctor->source);
-    return false;
-  }
-  return true;
-}
-
-bool Resolver::ValidateVectorConstructorOrCast(
-    const ast::CallExpression* ctor,
-    const sem::Vector* vec_type) const {
-  auto& values = ctor->args;
-  auto* elem_ty = vec_type->type();
-  size_t value_cardinality_sum = 0;
-  for (auto* value : values) {
-    auto* value_ty = sem_.TypeOf(value)->UnwrapRef();
-    if (value_ty->is_scalar()) {
-      if (elem_ty != value_ty) {
-        AddError(
-            "type in vector constructor does not match vector type: "
-            "expected '" +
-                sem_.TypeNameOf(elem_ty) + "', found '" +
-                sem_.TypeNameOf(value_ty) + "'",
-            value->source);
-        return false;
-      }
-
-      value_cardinality_sum++;
-    } else if (auto* value_vec = value_ty->As<sem::Vector>()) {
-      auto* value_elem_ty = value_vec->type();
-      // A mismatch of vector type parameter T is only an error if multiple
-      // arguments are present. A single argument constructor constitutes a
-      // type conversion expression.
-      if (elem_ty != value_elem_ty && values.size() > 1u) {
-        AddError(
-            "type in vector constructor does not match vector type: "
-            "expected '" +
-                sem_.TypeNameOf(elem_ty) + "', found '" +
-                sem_.TypeNameOf(value_elem_ty) + "'",
-            value->source);
-        return false;
-      }
-
-      value_cardinality_sum += value_vec->Width();
-    } else {
-      // A vector constructor can only accept vectors and scalars.
-      AddError("expected vector or scalar type in vector constructor; found: " +
-                   sem_.TypeNameOf(value_ty),
-               value->source);
-      return false;
-    }
-  }
-
-  // A correct vector constructor must either be a zero-value expression,
-  // a single-value initializer (splat) expression, or the number of components
-  // of all constructor arguments must add up to the vector cardinality.
-  if (value_cardinality_sum > 1 && value_cardinality_sum != vec_type->Width()) {
-    if (values.empty()) {
-      TINT_ICE(Resolver, diagnostics_)
-          << "constructor arguments expected to be non-empty!";
-    }
-    const Source& values_start = values[0]->source;
-    const Source& values_end = values[values.size() - 1]->source;
-    AddError("attempted to construct '" + sem_.TypeNameOf(vec_type) +
-                 "' with " + std::to_string(value_cardinality_sum) +
-                 " component(s)",
-             Source::Combine(values_start, values_end));
-    return false;
-  }
-  return true;
-}
-
-bool Resolver::ValidateVector(const sem::Vector* ty,
-                              const Source& source) const {
-  if (!ty->type()->is_scalar()) {
-    AddError("vector element type must be 'bool', 'f32', 'i32' or 'u32'",
-             source);
-    return false;
-  }
-  return true;
-}
-
-bool Resolver::ValidateMatrix(const sem::Matrix* ty,
-                              const Source& source) const {
-  if (!ty->is_float_matrix()) {
-    AddError("matrix element type must be 'f32'", source);
-    return false;
-  }
-  return true;
-}
-
-bool Resolver::ValidateMatrixConstructorOrCast(
-    const ast::CallExpression* ctor,
-    const sem::Matrix* matrix_ty) const {
-  auto& values = ctor->args;
-  // Zero Value expression
-  if (values.empty()) {
-    return true;
-  }
-
-  if (!ValidateMatrix(matrix_ty, ctor->source)) {
-    return false;
-  }
-
-  std::vector<const sem::Type*> arg_tys;
-  arg_tys.reserve(values.size());
-  for (auto* value : values) {
-    arg_tys.emplace_back(sem_.TypeOf(value)->UnwrapRef());
-  }
-
-  auto* elem_type = matrix_ty->type();
-  auto num_elements = matrix_ty->columns() * matrix_ty->rows();
-
-  // Print a generic error for an invalid matrix constructor, showing the
-  // available overloads.
-  auto print_error = [&]() {
-    const Source& values_start = values[0]->source;
-    const Source& values_end = values[values.size() - 1]->source;
-    auto type_name = sem_.TypeNameOf(matrix_ty);
-    auto elem_type_name = sem_.TypeNameOf(elem_type);
-    std::stringstream ss;
-    ss << "no matching constructor " + type_name << "(";
-    for (size_t i = 0; i < values.size(); i++) {
-      if (i > 0) {
-        ss << ", ";
-      }
-      ss << arg_tys[i]->FriendlyName(builder_->Symbols());
-    }
-    ss << ")" << std::endl << std::endl;
-    ss << "3 candidates available:" << std::endl;
-    ss << "  " << type_name << "()" << std::endl;
-    ss << "  " << type_name << "(" << elem_type_name << ",...,"
-       << elem_type_name << ")"
-       << " // " << std::to_string(num_elements) << " arguments" << std::endl;
-    ss << "  " << type_name << "(";
-    for (uint32_t c = 0; c < matrix_ty->columns(); c++) {
-      if (c > 0) {
-        ss << ", ";
-      }
-      ss << VectorPretty(matrix_ty->rows(), elem_type);
-    }
-    ss << ")" << std::endl;
-    AddError(ss.str(), Source::Combine(values_start, values_end));
-  };
-
-  const sem::Type* expected_arg_type = nullptr;
-  if (num_elements == values.size()) {
-    // Column-major construction from scalar elements.
-    expected_arg_type = matrix_ty->type();
-  } else if (matrix_ty->columns() == values.size()) {
-    // Column-by-column construction from vectors.
-    expected_arg_type = matrix_ty->ColumnType();
-  } else {
-    print_error();
-    return false;
-  }
-
-  for (auto* arg_ty : arg_tys) {
-    if (arg_ty != expected_arg_type) {
-      print_error();
-      return false;
-    }
-  }
-
-  return true;
-}
-
-bool Resolver::ValidateScalarConstructorOrCast(const ast::CallExpression* ctor,
-                                               const sem::Type* ty) const {
-  if (ctor->args.size() == 0) {
-    return true;
-  }
-  if (ctor->args.size() > 1) {
-    AddError("expected zero or one value in constructor, got " +
-                 std::to_string(ctor->args.size()),
-             ctor->source);
-    return false;
-  }
-
-  // Validate constructor
-  auto* value = ctor->args[0];
-  auto* value_ty = sem_.TypeOf(value)->UnwrapRef();
-
-  using Bool = sem::Bool;
-  using I32 = sem::I32;
-  using U32 = sem::U32;
-  using F32 = sem::F32;
-
-  const bool is_valid = (ty->Is<Bool>() && value_ty->is_scalar()) ||
-                        (ty->Is<I32>() && value_ty->is_scalar()) ||
-                        (ty->Is<U32>() && value_ty->is_scalar()) ||
-                        (ty->Is<F32>() && value_ty->is_scalar());
-  if (!is_valid) {
-    AddError("cannot construct '" + sem_.TypeNameOf(ty) +
-                 "' with a value of type '" + sem_.TypeNameOf(value_ty) + "'",
-             ctor->source);
-
-    return false;
-  }
-
-  return true;
-}
-
-bool Resolver::ValidatePipelineStages() const {
-  auto check_workgroup_storage = [&](const sem::Function* func,
-                                     const sem::Function* entry_point) {
-    auto stage = entry_point->Declaration()->PipelineStage();
-    if (stage != ast::PipelineStage::kCompute) {
-      for (auto* var : func->DirectlyReferencedGlobals()) {
-        if (var->StorageClass() == ast::StorageClass::kWorkgroup) {
-          std::stringstream stage_name;
-          stage_name << stage;
-          for (auto* user : var->Users()) {
-            if (func == user->Stmt()->Function()) {
-              AddError("workgroup memory cannot be used by " +
-                           stage_name.str() + " pipeline stage",
-                       user->Declaration()->source);
-              break;
-            }
-          }
-          AddNote("variable is declared here", var->Declaration()->source);
-          if (func != entry_point) {
-            TraverseCallChain(diagnostics_, entry_point, func,
-                              [&](const sem::Function* f) {
-                                AddNote("called by function '" +
-                                            builder_->Symbols().NameFor(
-                                                f->Declaration()->symbol) +
-                                            "'",
-                                        f->Declaration()->source);
-                              });
-            AddNote("called by entry point '" +
-                        builder_->Symbols().NameFor(
-                            entry_point->Declaration()->symbol) +
-                        "'",
-                    entry_point->Declaration()->source);
-          }
-          return false;
-        }
-      }
-    }
-    return true;
-  };
-
-  for (auto* entry_point : entry_points_) {
-    if (!check_workgroup_storage(entry_point, entry_point)) {
-      return false;
-    }
-    for (auto* func : entry_point->TransitivelyCalledFunctions()) {
-      if (!check_workgroup_storage(func, entry_point)) {
-        return false;
-      }
-    }
-  }
-
-  auto check_builtin_calls = [&](const sem::Function* func,
-                                 const sem::Function* entry_point) {
-    auto stage = entry_point->Declaration()->PipelineStage();
-    for (auto* builtin : func->DirectlyCalledBuiltins()) {
-      if (!builtin->SupportedStages().Contains(stage)) {
-        auto* call = func->FindDirectCallTo(builtin);
-        std::stringstream err;
-        err << "built-in cannot be used by " << stage << " pipeline stage";
-        AddError(err.str(), call ? call->Declaration()->source
-                                 : func->Declaration()->source);
-        if (func != entry_point) {
-          TraverseCallChain(
-              diagnostics_, entry_point, func, [&](const sem::Function* f) {
-                AddNote(
-                    "called by function '" +
-                        builder_->Symbols().NameFor(f->Declaration()->symbol) +
-                        "'",
-                    f->Declaration()->source);
-              });
-          AddNote("called by entry point '" +
-                      builder_->Symbols().NameFor(
-                          entry_point->Declaration()->symbol) +
-                      "'",
-                  entry_point->Declaration()->source);
-        }
-        return false;
-      }
-    }
-    return true;
-  };
-
-  for (auto* entry_point : entry_points_) {
-    if (!check_builtin_calls(entry_point, entry_point)) {
-      return false;
-    }
-    for (auto* func : entry_point->TransitivelyCalledFunctions()) {
-      if (!check_builtin_calls(func, entry_point)) {
-        return false;
-      }
-    }
-  }
-  return true;
-}
-
-bool Resolver::ValidateArray(const sem::Array* arr,
-                             const Source& source) const {
-  auto* el_ty = arr->ElemType();
-
-  if (!IsFixedFootprint(el_ty)) {
-    AddError("an array element type cannot contain a runtime-sized array",
-             source);
-    return false;
-  }
-  return true;
-}
-
-bool Resolver::ValidateArrayStrideAttribute(const ast::StrideAttribute* attr,
-                                            uint32_t el_size,
-                                            uint32_t el_align,
-                                            const Source& source) const {
-  auto stride = attr->stride;
-  bool is_valid_stride =
-      (stride >= el_size) && (stride >= el_align) && (stride % el_align == 0);
-  if (!is_valid_stride) {
-    // https://gpuweb.github.io/gpuweb/wgsl/#array-layout-rules
-    // Arrays decorated with the stride attribute must have a stride that is
-    // at least the size of the element type, and be a multiple of the
-    // element type's alignment value.
-    AddError(
-        "arrays decorated with the stride attribute must have a stride "
-        "that is at least the size of the element type, and be a multiple "
-        "of the element type's alignment value.",
-        source);
-    return false;
-  }
-  return true;
-}
-
-bool Resolver::ValidateAlias(const ast::Alias* alias) const {
-  auto name = builder_->Symbols().NameFor(alias->name);
-  if (sem::ParseBuiltinType(name) != sem::BuiltinType::kNone) {
-    AddError("'" + name + "' is a builtin and cannot be redeclared as an alias",
-             alias->source);
-    return false;
-  }
-
-  return true;
-}
-
-bool Resolver::ValidateStructure(const sem::Struct* str,
-                                 ast::PipelineStage stage) const {
-  auto name = builder_->Symbols().NameFor(str->Declaration()->name);
-  if (sem::ParseBuiltinType(name) != sem::BuiltinType::kNone) {
-    AddError("'" + name + "' is a builtin and cannot be redeclared as a struct",
-             str->Declaration()->source);
-    return false;
-  }
-
-  if (str->Members().empty()) {
-    AddError("structures must have at least one member",
-             str->Declaration()->source);
-    return false;
-  }
-
-  std::unordered_set<uint32_t> locations;
-  for (auto* member : str->Members()) {
-    if (auto* r = member->Type()->As<sem::Array>()) {
-      if (r->IsRuntimeSized()) {
-        if (member != str->Members().back()) {
-          AddError(
-              "runtime arrays may only appear as the last member of a struct",
-              member->Declaration()->source);
-          return false;
-        }
-      }
-    } else if (!IsFixedFootprint(member->Type())) {
-      AddError(
-          "a struct that contains a runtime array cannot be nested inside "
-          "another struct",
-          member->Declaration()->source);
-      return false;
-    }
-
-    auto has_location = false;
-    auto has_position = false;
-    const ast::InvariantAttribute* invariant_attribute = nullptr;
-    const ast::InterpolateAttribute* interpolate_attribute = nullptr;
-    for (auto* attr : member->Declaration()->attributes) {
-      if (!attr->IsAnyOf<ast::BuiltinAttribute,             //
-                         ast::InternalAttribute,            //
-                         ast::InterpolateAttribute,         //
-                         ast::InvariantAttribute,           //
-                         ast::LocationAttribute,            //
-                         ast::StructMemberOffsetAttribute,  //
-                         ast::StructMemberSizeAttribute,    //
-                         ast::StructMemberAlignAttribute>()) {
-        if (attr->Is<ast::StrideAttribute>() &&
-            IsValidationDisabled(
-                member->Declaration()->attributes,
-                ast::DisabledValidation::kIgnoreStrideAttribute)) {
-          continue;
-        }
-        AddError("attribute is not valid for structure members", attr->source);
-        return false;
-      }
-
-      if (auto* invariant = attr->As<ast::InvariantAttribute>()) {
-        invariant_attribute = invariant;
-      } else if (auto* location = attr->As<ast::LocationAttribute>()) {
-        has_location = true;
-        if (!ValidateLocationAttribute(location, member->Type(), locations,
-                                       stage, member->Declaration()->source)) {
-          return false;
-        }
-      } else if (auto* builtin = attr->As<ast::BuiltinAttribute>()) {
-        if (!ValidateBuiltinAttribute(builtin, member->Type(), stage,
-                                      /* is_input */ false)) {
-          return false;
-        }
-        if (builtin->builtin == ast::Builtin::kPosition) {
-          has_position = true;
-        }
-      } else if (auto* interpolate = attr->As<ast::InterpolateAttribute>()) {
-        interpolate_attribute = interpolate;
-        if (!ValidateInterpolateAttribute(interpolate, member->Type())) {
-          return false;
-        }
-      }
-    }
-
-    if (invariant_attribute && !has_position) {
-      AddError("invariant attribute must only be applied to a position builtin",
-               invariant_attribute->source);
-      return false;
-    }
-
-    if (interpolate_attribute && !has_location) {
-      AddError("interpolate attribute must only be used with @location",
-               interpolate_attribute->source);
-      return false;
-    }
-  }
-
-  for (auto* attr : str->Declaration()->attributes) {
-    if (!(attr->IsAnyOf<ast::InternalAttribute>())) {
-      AddError("attribute is not valid for struct declarations", attr->source);
-      return false;
-    }
-  }
-
-  return true;
-}
-
-bool Resolver::ValidateLocationAttribute(
-    const ast::LocationAttribute* location,
-    const sem::Type* type,
-    std::unordered_set<uint32_t>& locations,
-    ast::PipelineStage stage,
-    const Source& source,
-    const bool is_input) const {
-  std::string inputs_or_output = is_input ? "inputs" : "output";
-  if (stage == ast::PipelineStage::kCompute) {
-    AddError("attribute is not valid for compute shader " + inputs_or_output,
-             location->source);
-    return false;
-  }
-
-  if (!type->is_numeric_scalar_or_vector()) {
-    std::string invalid_type = sem_.TypeNameOf(type);
-    AddError("cannot apply 'location' attribute to declaration of type '" +
-                 invalid_type + "'",
-             source);
-    AddNote(
-        "'location' attribute must only be applied to declarations of "
-        "numeric scalar or numeric vector type",
-        location->source);
-    return false;
-  }
-
-  if (locations.count(location->value)) {
-    AddError(attr_to_str(location) + " attribute appears multiple times",
-             location->source);
-    return false;
-  }
-  locations.emplace(location->value);
-
-  return true;
-}
-
-bool Resolver::ValidateReturn(const ast::ReturnStatement* ret,
-                              const sem::Type* func_type,
-                              const sem::Type* ret_type) const {
-  if (func_type->UnwrapRef() != ret_type) {
-    AddError(
-        "return statement type must match its function "
-        "return type, returned '" +
-            sem_.TypeNameOf(ret_type) + "', expected '" +
-            sem_.TypeNameOf(func_type) + "'",
-        ret->source);
-    return false;
-  }
-
-  auto* sem = sem_.Get(ret);
-  if (auto* continuing = ClosestContinuing(/*stop_at_loop*/ false)) {
-    AddError("continuing blocks must not contain a return statement",
-             ret->source);
-    if (continuing != sem->Declaration() &&
-        continuing != sem->Parent()->Declaration()) {
-      AddNote("see continuing block here", continuing->source);
-    }
-    return false;
-  }
-
-  return true;
-}
-
-bool Resolver::ValidateSwitch(const ast::SwitchStatement* s) {
-  auto* cond_ty = sem_.TypeOf(s->condition)->UnwrapRef();
-  if (!cond_ty->is_integer_scalar()) {
-    AddError(
-        "switch statement selector expression must be of a "
-        "scalar integer type",
-        s->condition->source);
-    return false;
-  }
-
-  bool has_default = false;
-  std::unordered_map<uint32_t, Source> selectors;
-
-  for (auto* case_stmt : s->body) {
-    if (case_stmt->IsDefault()) {
-      if (has_default) {
-        // More than one default clause
-        AddError("switch statement must have exactly one default clause",
-                 case_stmt->source);
-        return false;
-      }
-      has_default = true;
-    }
-
-    for (auto* selector : case_stmt->selectors) {
-      if (cond_ty != sem_.TypeOf(selector)) {
-        AddError(
-            "the case selector values must have the same "
-            "type as the selector expression.",
-            case_stmt->source);
-        return false;
-      }
-
-      auto v = selector->ValueAsU32();
-      auto it = selectors.find(v);
-      if (it != selectors.end()) {
-        auto val = selector->Is<ast::IntLiteralExpression>()
-                       ? std::to_string(selector->ValueAsI32())
-                       : std::to_string(selector->ValueAsU32());
-        AddError("duplicate switch case '" + val + "'", selector->source);
-        AddNote("previous case declared here", it->second);
-        return false;
-      }
-      selectors.emplace(v, selector->source);
-    }
-  }
-
-  if (!has_default) {
-    // No default clause
-    AddError("switch statement must have a default clause", s->source);
-    return false;
-  }
-
-  return true;
-}
-
-bool Resolver::ValidateAssignment(const ast::Statement* a,
-                                  const sem::Type* rhs_ty) const {
-  const ast::Expression* lhs;
-  const ast::Expression* rhs;
-  if (auto* assign = a->As<ast::AssignmentStatement>()) {
-    lhs = assign->lhs;
-    rhs = assign->rhs;
-  } else if (auto* compound = a->As<ast::CompoundAssignmentStatement>()) {
-    lhs = compound->lhs;
-    rhs = compound->rhs;
-  } else {
-    TINT_ICE(Resolver, diagnostics_) << "invalid assignment statement";
-    return false;
-  }
-
-  if (lhs->Is<ast::PhonyExpression>()) {
-    // https://www.w3.org/TR/WGSL/#phony-assignment-section
-    auto* ty = rhs_ty->UnwrapRef();
-    if (!ty->IsConstructible() &&
-        !ty->IsAnyOf<sem::Pointer, sem::Texture, sem::Sampler>()) {
-      AddError(
-          "cannot assign '" + sem_.TypeNameOf(rhs_ty) +
-              "' to '_'. '_' can only be assigned a constructible, pointer, "
-              "texture or sampler type",
-          rhs->source);
-      return false;
-    }
-    return true;  // RHS can be anything.
-  }
-
-  // https://gpuweb.github.io/gpuweb/wgsl/#assignment-statement
-  auto const* lhs_ty = sem_.TypeOf(lhs);
-
-  if (auto* var = ResolvedSymbol<sem::Variable>(lhs)) {
-    auto* decl = var->Declaration();
-    if (var->Is<sem::Parameter>()) {
-      AddError("cannot assign to function parameter", lhs->source);
-      AddNote("'" + builder_->Symbols().NameFor(decl->symbol) +
-                  "' is declared here:",
-              decl->source);
-      return false;
-    }
-    if (decl->is_const) {
-      AddError("cannot assign to const", lhs->source);
-      AddNote("'" + builder_->Symbols().NameFor(decl->symbol) +
-                  "' is declared here:",
-              decl->source);
-      return false;
-    }
-  }
-
-  auto* lhs_ref = lhs_ty->As<sem::Reference>();
-  if (!lhs_ref) {
-    // LHS is not a reference, so it has no storage.
-    AddError("cannot assign to value of type '" + sem_.TypeNameOf(lhs_ty) + "'",
-             lhs->source);
-    return false;
-  }
-
-  auto* storage_ty = lhs_ref->StoreType();
-  auto* value_type = rhs_ty->UnwrapRef();  // Implicit load of RHS
-
-  // Value type has to match storage type
-  if (storage_ty != value_type) {
-    AddError("cannot assign '" + sem_.TypeNameOf(rhs_ty) + "' to '" +
-                 sem_.TypeNameOf(lhs_ty) + "'",
-             a->source);
-    return false;
-  }
-  if (!storage_ty->IsConstructible()) {
-    AddError("storage type of assignment must be constructible", a->source);
-    return false;
-  }
-  if (lhs_ref->Access() == ast::Access::kRead) {
-    AddError("cannot store into a read-only type '" +
-                 sem_.RawTypeNameOf(lhs_ty) + "'",
-             a->source);
-    return false;
-  }
-  return true;
-}
-
-bool Resolver::ValidateIncrementDecrementStatement(
-    const ast::IncrementDecrementStatement* inc) const {
-  const ast::Expression* lhs = inc->lhs;
-
-  // https://gpuweb.github.io/gpuweb/wgsl/#increment-decrement
-
-  if (auto* var = ResolvedSymbol<sem::Variable>(lhs)) {
-    auto* decl = var->Declaration();
-    if (var->Is<sem::Parameter>()) {
-      AddError("cannot modify function parameter", lhs->source);
-      AddNote("'" + builder_->Symbols().NameFor(decl->symbol) +
-                  "' is declared here:",
-              decl->source);
-      return false;
-    }
-    if (decl->is_const) {
-      AddError("cannot modify constant value", lhs->source);
-      AddNote("'" + builder_->Symbols().NameFor(decl->symbol) +
-                  "' is declared here:",
-              decl->source);
-      return false;
-    }
-  }
-
-  auto const* lhs_ty = sem_.TypeOf(lhs);
-  auto* lhs_ref = lhs_ty->As<sem::Reference>();
-  if (!lhs_ref) {
-    // LHS is not a reference, so it has no storage.
-    AddError("cannot modify value of type '" + sem_.TypeNameOf(lhs_ty) + "'",
-             lhs->source);
-    return false;
-  }
-
-  if (!lhs_ref->StoreType()->is_integer_scalar()) {
-    const std::string kind = inc->increment ? "increment" : "decrement";
-    AddError(kind + " statement can only be applied to an integer scalar",
-             lhs->source);
-    return false;
-  }
-
-  if (lhs_ref->Access() == ast::Access::kRead) {
-    AddError(
-        "cannot modify read-only type '" + sem_.RawTypeNameOf(lhs_ty) + "'",
-        inc->source);
-    return false;
-  }
-  return true;
-}
-
-bool Resolver::ValidateNoDuplicateAttributes(
-    const ast::AttributeList& attributes) const {
-  std::unordered_map<const TypeInfo*, Source> seen;
-  for (auto* d : attributes) {
-    auto res = seen.emplace(&d->TypeInfo(), d->source);
-    if (!res.second && !d->Is<ast::InternalAttribute>()) {
-      AddError("duplicate " + d->Name() + " attribute", d->source);
-      AddNote("first attribute declared here", res.first->second);
-      return false;
-    }
-  }
-  return true;
-}
-
-bool Resolver::IsValidationDisabled(const ast::AttributeList& attributes,
-                                    ast::DisabledValidation validation) const {
-  for (auto* attribute : attributes) {
-    if (auto* dv = attribute->As<ast::DisableValidationAttribute>()) {
-      if (dv->validation == validation) {
-        return true;
-      }
-    }
-  }
-  return false;
-}
-
-bool Resolver::IsValidationEnabled(const ast::AttributeList& attributes,
-                                   ast::DisabledValidation validation) const {
-  return !IsValidationDisabled(attributes, validation);
-}
-
-std::string Resolver::VectorPretty(uint32_t size,
-                                   const sem::Type* element_type) const {
-  sem::Vector vec_type(element_type, size);
-  return vec_type.FriendlyName(builder_->Symbols());
-}
-
-}  // namespace tint::resolver
diff --git a/src/tint/resolver/sem_helper.cc b/src/tint/resolver/sem_helper.cc
index 74b3c5b..01a5480 100644
--- a/src/tint/resolver/sem_helper.cc
+++ b/src/tint/resolver/sem_helper.cc
@@ -18,43 +18,22 @@
 
 namespace tint::resolver {
 
-SemHelper::SemHelper(ProgramBuilder* builder) : builder_(builder) {}
+SemHelper::SemHelper(ProgramBuilder* builder, DependencyGraph& dependencies)
+    : builder_(builder), dependencies_(dependencies) {}
 
 SemHelper::~SemHelper() = default;
 
 std::string SemHelper::TypeNameOf(const sem::Type* ty) const {
-  return RawTypeNameOf(ty->UnwrapRef());
+    return RawTypeNameOf(ty->UnwrapRef());
 }
 
 std::string SemHelper::RawTypeNameOf(const sem::Type* ty) const {
-  return ty->FriendlyName(builder_->Symbols());
+    return ty->FriendlyName(builder_->Symbols());
 }
 
 sem::Type* SemHelper::TypeOf(const ast::Expression* expr) const {
-  auto* sem = Get(expr);
-  return sem ? const_cast<sem::Type*>(sem->Type()) : nullptr;
-}
-
-sem::Type* SemHelper::TypeOf(const ast::LiteralExpression* lit) {
-  return Switch(
-      lit,
-      [&](const ast::SintLiteralExpression*) {
-        return builder_->create<sem::I32>();
-      },
-      [&](const ast::UintLiteralExpression*) {
-        return builder_->create<sem::U32>();
-      },
-      [&](const ast::FloatLiteralExpression*) {
-        return builder_->create<sem::F32>();
-      },
-      [&](const ast::BoolLiteralExpression*) {
-        return builder_->create<sem::Bool>();
-      },
-      [&](Default) {
-        TINT_UNREACHABLE(Resolver, builder_->Diagnostics())
-            << "Unhandled literal type: " << lit->TypeInfo().name;
-        return nullptr;
-      });
+    auto* sem = Get(expr);
+    return sem ? const_cast<sem::Type*>(sem->Type()) : nullptr;
 }
 
 }  // namespace tint::resolver
diff --git a/src/tint/resolver/sem_helper.h b/src/tint/resolver/sem_helper.h
index 0e95397..9b0967b 100644
--- a/src/tint/resolver/sem_helper.h
+++ b/src/tint/resolver/sem_helper.h
@@ -19,54 +19,62 @@
 
 #include "src/tint/diagnostic/diagnostic.h"
 #include "src/tint/program_builder.h"
+#include "src/tint/resolver/dependency_graph.h"
+#include "src/tint/utils/map.h"
 
 namespace tint::resolver {
 
 /// Helper class to retrieve sem information.
 class SemHelper {
- public:
-  /// Constructor
-  /// @param builder the program builder
-  explicit SemHelper(ProgramBuilder* builder);
-  ~SemHelper();
+  public:
+    /// Constructor
+    /// @param builder the program builder
+    /// @param dependencies the program dependency graph
+    explicit SemHelper(ProgramBuilder* builder, DependencyGraph& dependencies);
+    ~SemHelper();
 
-  /// Get is a helper for obtaining the semantic node for the given AST node.
-  /// @param ast the ast node to get the sem for
-  /// @returns the sem node for the provided |ast|
-  template <typename SEM = sem::Info::InferFromAST,
-            typename AST_OR_TYPE = CastableBase>
-  auto* Get(const AST_OR_TYPE* ast) const {
-    using T = sem::Info::GetResultType<SEM, AST_OR_TYPE>;
-    auto* sem = builder_->Sem().Get(ast);
-    if (!sem) {
-      TINT_ICE(Resolver, builder_->Diagnostics())
-          << "AST node '" << ast->TypeInfo().name << "' had no semantic info\n"
-          << "At: " << ast->source << "\n"
-          << "Pointer: " << ast;
+    /// Get is a helper for obtaining the semantic node for the given AST node.
+    /// @param ast the ast node to get the sem for
+    /// @returns the sem node for the provided |ast|
+    template <typename SEM = sem::Info::InferFromAST, typename AST_OR_TYPE = CastableBase>
+    auto* Get(const AST_OR_TYPE* ast) const {
+        using T = sem::Info::GetResultType<SEM, AST_OR_TYPE>;
+        auto* sem = builder_->Sem().Get(ast);
+        if (!sem) {
+            TINT_ICE(Resolver, builder_->Diagnostics())
+                << "AST node '" << ast->TypeInfo().name << "' had no semantic info\n"
+                << "At: " << ast->source << "\n"
+                << "Pointer: " << ast;
+        }
+        return const_cast<T*>(As<T>(sem));
     }
-    return const_cast<T*>(As<T>(sem));
-  }
 
-  /// @returns the resolved type of the ast::Expression `expr`
-  /// @param expr the expression
-  sem::Type* TypeOf(const ast::Expression* expr) const;
+    /// @returns the resolved symbol (function, type or variable) for the given
+    /// ast::Identifier or ast::TypeName cast to the given semantic type.
+    /// @param node the node to retrieve
+    template <typename SEM = sem::Node>
+    SEM* ResolvedSymbol(const ast::Node* node) const {
+        auto* resolved = utils::Lookup(dependencies_.resolved_symbols, node);
+        return resolved ? const_cast<SEM*>(builder_->Sem().Get<SEM>(resolved)) : nullptr;
+    }
 
-  /// @returns the semantic type of the AST literal `lit`
-  /// @param lit the literal
-  sem::Type* TypeOf(const ast::LiteralExpression* lit);
+    /// @returns the resolved type of the ast::Expression `expr`
+    /// @param expr the expression
+    sem::Type* TypeOf(const ast::Expression* expr) const;
 
-  /// @returns the type name of the given semantic type, unwrapping
-  /// references.
-  /// @param ty the type to look up
-  std::string TypeNameOf(const sem::Type* ty) const;
+    /// @returns the type name of the given semantic type, unwrapping
+    /// references.
+    /// @param ty the type to look up
+    std::string TypeNameOf(const sem::Type* ty) const;
 
-  /// @returns the type name of the given semantic type, without unwrapping
-  /// references.
-  /// @param ty the type to look up
-  std::string RawTypeNameOf(const sem::Type* ty) const;
+    /// @returns the type name of the given semantic type, without unwrapping
+    /// references.
+    /// @param ty the type to look up
+    std::string RawTypeNameOf(const sem::Type* ty) const;
 
- private:
-  ProgramBuilder* builder_;
+  private:
+    ProgramBuilder* builder_;
+    DependencyGraph& dependencies_;
 };
 
 }  // namespace tint::resolver
diff --git a/src/tint/resolver/side_effects_test.cc b/src/tint/resolver/side_effects_test.cc
index 50f4e99..a50d904 100644
--- a/src/tint/resolver/side_effects_test.cc
+++ b/src/tint/resolver/side_effects_test.cc
@@ -19,364 +19,366 @@
 #include "src/tint/sem/expression.h"
 #include "src/tint/sem/member_accessor_expression.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::resolver {
 namespace {
 
 struct SideEffectsTest : ResolverTest {
-  template <typename T>
-  void MakeSideEffectFunc(const char* name) {
-    auto global = Sym();
-    Global(global, ty.Of<T>(), ast::StorageClass::kPrivate);
-    auto local = Sym();
-    Func(name, {}, ty.Of<T>(),
-         {
-             Decl(Var(local, ty.Of<T>())),
-             Assign(global, local),
-             Return(global),
-         });
-  }
+    template <typename T>
+    void MakeSideEffectFunc(const char* name) {
+        auto global = Sym();
+        Global(global, ty.Of<T>(), ast::StorageClass::kPrivate);
+        auto local = Sym();
+        Func(name, {}, ty.Of<T>(),
+             {
+                 Decl(Var(local, ty.Of<T>())),
+                 Assign(global, local),
+                 Return(global),
+             });
+    }
 
-  template <typename MAKE_TYPE_FUNC>
-  void MakeSideEffectFunc(const char* name, MAKE_TYPE_FUNC make_type) {
-    auto global = Sym();
-    Global(global, make_type(), ast::StorageClass::kPrivate);
-    auto local = Sym();
-    Func(name, {}, make_type(),
-         {
-             Decl(Var(local, make_type())),
-             Assign(global, local),
-             Return(global),
-         });
-  }
+    template <typename MAKE_TYPE_FUNC>
+    void MakeSideEffectFunc(const char* name, MAKE_TYPE_FUNC make_type) {
+        auto global = Sym();
+        Global(global, make_type(), ast::StorageClass::kPrivate);
+        auto local = Sym();
+        Func(name, {}, make_type(),
+             {
+                 Decl(Var(local, make_type())),
+                 Assign(global, local),
+                 Return(global),
+             });
+    }
 };
 
 TEST_F(SideEffectsTest, Phony) {
-  auto* expr = Phony();
-  auto* body = Assign(expr, 1);
-  WrapInFunction(body);
+    auto* expr = Phony();
+    auto* body = Assign(expr, 1_i);
+    WrapInFunction(body);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  auto* sem = Sem().Get(expr);
-  ASSERT_NE(sem, nullptr);
-  EXPECT_FALSE(sem->HasSideEffects());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* sem = Sem().Get(expr);
+    ASSERT_NE(sem, nullptr);
+    EXPECT_FALSE(sem->HasSideEffects());
 }
 
 TEST_F(SideEffectsTest, Literal) {
-  auto* expr = Expr(1);
-  WrapInFunction(expr);
+    auto* expr = Expr(1_i);
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  auto* sem = Sem().Get(expr);
-  ASSERT_NE(sem, nullptr);
-  EXPECT_FALSE(sem->HasSideEffects());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* sem = Sem().Get(expr);
+    ASSERT_NE(sem, nullptr);
+    EXPECT_FALSE(sem->HasSideEffects());
 }
 
 TEST_F(SideEffectsTest, VariableUser) {
-  auto* var = Decl(Var("a", ty.i32()));
-  auto* expr = Expr("a");
-  WrapInFunction(var, expr);
+    auto* var = Decl(Var("a", ty.i32()));
+    auto* expr = Expr("a");
+    WrapInFunction(var, expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  auto* sem = Sem().Get(expr);
-  ASSERT_NE(sem, nullptr);
-  EXPECT_TRUE(sem->Is<sem::VariableUser>());
-  EXPECT_FALSE(sem->HasSideEffects());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* sem = Sem().Get(expr);
+    ASSERT_NE(sem, nullptr);
+    EXPECT_TRUE(sem->Is<sem::VariableUser>());
+    EXPECT_FALSE(sem->HasSideEffects());
 }
 
 TEST_F(SideEffectsTest, Call_Builtin_NoSE) {
-  Global("a", ty.f32(), ast::StorageClass::kPrivate);
-  auto* expr = Call("dpdx", "a");
-  Func("f", {}, ty.void_(), {Ignore(expr)},
-       {create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
+    Global("a", ty.f32(), ast::StorageClass::kPrivate);
+    auto* expr = Call("dpdx", "a");
+    Func("f", {}, ty.void_(), {Ignore(expr)},
+         {create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  auto* sem = Sem().Get(expr);
-  ASSERT_NE(sem, nullptr);
-  EXPECT_TRUE(sem->Is<sem::Call>());
-  EXPECT_FALSE(sem->HasSideEffects());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* sem = Sem().Get(expr);
+    ASSERT_NE(sem, nullptr);
+    EXPECT_TRUE(sem->Is<sem::Call>());
+    EXPECT_FALSE(sem->HasSideEffects());
 }
 
 TEST_F(SideEffectsTest, Call_Builtin_NoSE_WithSEArg) {
-  MakeSideEffectFunc<f32>("se");
-  auto* expr = Call("dpdx", Call("se"));
-  Func("f", {}, ty.void_(), {Ignore(expr)},
-       {create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
+    MakeSideEffectFunc<f32>("se");
+    auto* expr = Call("dpdx", Call("se"));
+    Func("f", {}, ty.void_(), {Ignore(expr)},
+         {create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  auto* sem = Sem().Get(expr);
-  ASSERT_NE(sem, nullptr);
-  EXPECT_TRUE(sem->Is<sem::Call>());
-  EXPECT_TRUE(sem->HasSideEffects());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* sem = Sem().Get(expr);
+    ASSERT_NE(sem, nullptr);
+    EXPECT_TRUE(sem->Is<sem::Call>());
+    EXPECT_TRUE(sem->HasSideEffects());
 }
 
 TEST_F(SideEffectsTest, Call_Builtin_SE) {
-  Global("a", ty.atomic(ty.i32()), ast::StorageClass::kWorkgroup);
-  auto* expr = Call("atomicAdd", AddressOf("a"), 1);
-  WrapInFunction(expr);
+    Global("a", ty.atomic(ty.i32()), ast::StorageClass::kWorkgroup);
+    auto* expr = Call("atomicAdd", AddressOf("a"), 1_i);
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  auto* sem = Sem().Get(expr);
-  ASSERT_NE(sem, nullptr);
-  EXPECT_TRUE(sem->Is<sem::Call>());
-  EXPECT_TRUE(sem->HasSideEffects());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* sem = Sem().Get(expr);
+    ASSERT_NE(sem, nullptr);
+    EXPECT_TRUE(sem->Is<sem::Call>());
+    EXPECT_TRUE(sem->HasSideEffects());
 }
 
 TEST_F(SideEffectsTest, Call_Function) {
-  Func("f", {}, ty.i32(), {Return(1)});
-  auto* expr = Call("f");
-  WrapInFunction(expr);
+    Func("f", {}, ty.i32(), {Return(1_i)});
+    auto* expr = Call("f");
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  auto* sem = Sem().Get(expr);
-  ASSERT_NE(sem, nullptr);
-  EXPECT_TRUE(sem->Is<sem::Call>());
-  EXPECT_TRUE(sem->HasSideEffects());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* sem = Sem().Get(expr);
+    ASSERT_NE(sem, nullptr);
+    EXPECT_TRUE(sem->Is<sem::Call>());
+    EXPECT_TRUE(sem->HasSideEffects());
 }
 
 TEST_F(SideEffectsTest, Call_TypeConversion_NoSE) {
-  auto* var = Decl(Var("a", ty.i32()));
-  auto* expr = Construct(ty.f32(), "a");
-  WrapInFunction(var, expr);
+    auto* var = Decl(Var("a", ty.i32()));
+    auto* expr = Construct(ty.f32(), "a");
+    WrapInFunction(var, expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  auto* sem = Sem().Get(expr);
-  ASSERT_NE(sem, nullptr);
-  EXPECT_TRUE(sem->Is<sem::Call>());
-  EXPECT_FALSE(sem->HasSideEffects());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* sem = Sem().Get(expr);
+    ASSERT_NE(sem, nullptr);
+    EXPECT_TRUE(sem->Is<sem::Call>());
+    EXPECT_FALSE(sem->HasSideEffects());
 }
 
 TEST_F(SideEffectsTest, Call_TypeConversion_SE) {
-  MakeSideEffectFunc<i32>("se");
-  auto* expr = Construct(ty.f32(), Call("se"));
-  WrapInFunction(expr);
+    MakeSideEffectFunc<i32>("se");
+    auto* expr = Construct(ty.f32(), Call("se"));
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  auto* sem = Sem().Get(expr);
-  ASSERT_NE(sem, nullptr);
-  EXPECT_TRUE(sem->Is<sem::Call>());
-  EXPECT_TRUE(sem->HasSideEffects());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* sem = Sem().Get(expr);
+    ASSERT_NE(sem, nullptr);
+    EXPECT_TRUE(sem->Is<sem::Call>());
+    EXPECT_TRUE(sem->HasSideEffects());
 }
 
 TEST_F(SideEffectsTest, Call_TypeConstructor_NoSE) {
-  auto* var = Decl(Var("a", ty.f32()));
-  auto* expr = Construct(ty.f32(), "a");
-  WrapInFunction(var, expr);
+    auto* var = Decl(Var("a", ty.f32()));
+    auto* expr = Construct(ty.f32(), "a");
+    WrapInFunction(var, expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  auto* sem = Sem().Get(expr);
-  ASSERT_NE(sem, nullptr);
-  EXPECT_TRUE(sem->Is<sem::Call>());
-  EXPECT_FALSE(sem->HasSideEffects());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* sem = Sem().Get(expr);
+    ASSERT_NE(sem, nullptr);
+    EXPECT_TRUE(sem->Is<sem::Call>());
+    EXPECT_FALSE(sem->HasSideEffects());
 }
 
 TEST_F(SideEffectsTest, Call_TypeConstructor_SE) {
-  MakeSideEffectFunc<f32>("se");
-  auto* expr = Construct(ty.f32(), Call("se"));
-  WrapInFunction(expr);
+    MakeSideEffectFunc<f32>("se");
+    auto* expr = Construct(ty.f32(), Call("se"));
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  auto* sem = Sem().Get(expr);
-  ASSERT_NE(sem, nullptr);
-  EXPECT_TRUE(sem->Is<sem::Call>());
-  EXPECT_TRUE(sem->HasSideEffects());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* sem = Sem().Get(expr);
+    ASSERT_NE(sem, nullptr);
+    EXPECT_TRUE(sem->Is<sem::Call>());
+    EXPECT_TRUE(sem->HasSideEffects());
 }
 
 TEST_F(SideEffectsTest, MemberAccessor_Struct_NoSE) {
-  auto* s = Structure("S", {Member("m", ty.i32())});
-  auto* var = Decl(Var("a", ty.Of(s)));
-  auto* expr = MemberAccessor("a", "m");
-  WrapInFunction(var, expr);
+    auto* s = Structure("S", {Member("m", ty.i32())});
+    auto* var = Decl(Var("a", ty.Of(s)));
+    auto* expr = MemberAccessor("a", "m");
+    WrapInFunction(var, expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  auto* sem = Sem().Get(expr);
-  ASSERT_NE(sem, nullptr);
-  EXPECT_FALSE(sem->HasSideEffects());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* sem = Sem().Get(expr);
+    ASSERT_NE(sem, nullptr);
+    EXPECT_FALSE(sem->HasSideEffects());
 }
 
 TEST_F(SideEffectsTest, MemberAccessor_Struct_SE) {
-  auto* s = Structure("S", {Member("m", ty.i32())});
-  MakeSideEffectFunc("se", [&] { return ty.Of(s); });
-  auto* expr = MemberAccessor(Call("se"), "m");
-  WrapInFunction(expr);
+    auto* s = Structure("S", {Member("m", ty.i32())});
+    MakeSideEffectFunc("se", [&] { return ty.Of(s); });
+    auto* expr = MemberAccessor(Call("se"), "m");
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  auto* sem = Sem().Get(expr);
-  ASSERT_NE(sem, nullptr);
-  EXPECT_TRUE(sem->HasSideEffects());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* sem = Sem().Get(expr);
+    ASSERT_NE(sem, nullptr);
+    EXPECT_TRUE(sem->HasSideEffects());
 }
 
 TEST_F(SideEffectsTest, MemberAccessor_Vector) {
-  auto* var = Decl(Var("a", ty.vec4<f32>()));
-  auto* expr = MemberAccessor("a", "x");
-  WrapInFunction(var, expr);
+    auto* var = Decl(Var("a", ty.vec4<f32>()));
+    auto* expr = MemberAccessor("a", "x");
+    WrapInFunction(var, expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  auto* sem = Sem().Get(expr);
-  EXPECT_TRUE(sem->Is<sem::MemberAccessorExpression>());
-  ASSERT_NE(sem, nullptr);
-  EXPECT_FALSE(sem->HasSideEffects());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* sem = Sem().Get(expr);
+    EXPECT_TRUE(sem->Is<sem::MemberAccessorExpression>());
+    ASSERT_NE(sem, nullptr);
+    EXPECT_FALSE(sem->HasSideEffects());
 }
 
 TEST_F(SideEffectsTest, MemberAccessor_VectorSwizzleNoSE) {
-  auto* var = Decl(Var("a", ty.vec4<f32>()));
-  auto* expr = MemberAccessor("a", "xzyw");
-  WrapInFunction(var, expr);
+    auto* var = Decl(Var("a", ty.vec4<f32>()));
+    auto* expr = MemberAccessor("a", "xzyw");
+    WrapInFunction(var, expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  auto* sem = Sem().Get(expr);
-  EXPECT_TRUE(sem->Is<sem::Swizzle>());
-  ASSERT_NE(sem, nullptr);
-  EXPECT_FALSE(sem->HasSideEffects());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* sem = Sem().Get(expr);
+    EXPECT_TRUE(sem->Is<sem::Swizzle>());
+    ASSERT_NE(sem, nullptr);
+    EXPECT_FALSE(sem->HasSideEffects());
 }
 
 TEST_F(SideEffectsTest, MemberAccessor_VectorSwizzleSE) {
-  MakeSideEffectFunc("se", [&] { return ty.vec4<f32>(); });
-  auto* expr = MemberAccessor(Call("se"), "xzyw");
-  WrapInFunction(expr);
+    MakeSideEffectFunc("se", [&] { return ty.vec4<f32>(); });
+    auto* expr = MemberAccessor(Call("se"), "xzyw");
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  auto* sem = Sem().Get(expr);
-  EXPECT_TRUE(sem->Is<sem::Swizzle>());
-  ASSERT_NE(sem, nullptr);
-  EXPECT_TRUE(sem->HasSideEffects());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* sem = Sem().Get(expr);
+    EXPECT_TRUE(sem->Is<sem::Swizzle>());
+    ASSERT_NE(sem, nullptr);
+    EXPECT_TRUE(sem->HasSideEffects());
 }
 
 TEST_F(SideEffectsTest, Binary_NoSE) {
-  auto* a = Decl(Var("a", ty.i32()));
-  auto* b = Decl(Var("b", ty.i32()));
-  auto* expr = Add("a", "b");
-  WrapInFunction(a, b, expr);
+    auto* a = Decl(Var("a", ty.i32()));
+    auto* b = Decl(Var("b", ty.i32()));
+    auto* expr = Add("a", "b");
+    WrapInFunction(a, b, expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  auto* sem = Sem().Get(expr);
-  ASSERT_NE(sem, nullptr);
-  EXPECT_FALSE(sem->HasSideEffects());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* sem = Sem().Get(expr);
+    ASSERT_NE(sem, nullptr);
+    EXPECT_FALSE(sem->HasSideEffects());
 }
 
 TEST_F(SideEffectsTest, Binary_LeftSE) {
-  MakeSideEffectFunc<i32>("se");
-  auto* b = Decl(Var("b", ty.i32()));
-  auto* expr = Add(Call("se"), "b");
-  WrapInFunction(b, expr);
+    MakeSideEffectFunc<i32>("se");
+    auto* b = Decl(Var("b", ty.i32()));
+    auto* expr = Add(Call("se"), "b");
+    WrapInFunction(b, expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  auto* sem = Sem().Get(expr);
-  ASSERT_NE(sem, nullptr);
-  EXPECT_TRUE(sem->HasSideEffects());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* sem = Sem().Get(expr);
+    ASSERT_NE(sem, nullptr);
+    EXPECT_TRUE(sem->HasSideEffects());
 }
 
 TEST_F(SideEffectsTest, Binary_RightSE) {
-  MakeSideEffectFunc<i32>("se");
-  auto* a = Decl(Var("a", ty.i32()));
-  auto* expr = Add("a", Call("se"));
-  WrapInFunction(a, expr);
+    MakeSideEffectFunc<i32>("se");
+    auto* a = Decl(Var("a", ty.i32()));
+    auto* expr = Add("a", Call("se"));
+    WrapInFunction(a, expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  auto* sem = Sem().Get(expr);
-  ASSERT_NE(sem, nullptr);
-  EXPECT_TRUE(sem->HasSideEffects());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* sem = Sem().Get(expr);
+    ASSERT_NE(sem, nullptr);
+    EXPECT_TRUE(sem->HasSideEffects());
 }
 
 TEST_F(SideEffectsTest, Binary_BothSE) {
-  MakeSideEffectFunc<i32>("se1");
-  MakeSideEffectFunc<i32>("se2");
-  auto* expr = Add(Call("se1"), Call("se2"));
-  WrapInFunction(expr);
+    MakeSideEffectFunc<i32>("se1");
+    MakeSideEffectFunc<i32>("se2");
+    auto* expr = Add(Call("se1"), Call("se2"));
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  auto* sem = Sem().Get(expr);
-  ASSERT_NE(sem, nullptr);
-  EXPECT_TRUE(sem->HasSideEffects());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* sem = Sem().Get(expr);
+    ASSERT_NE(sem, nullptr);
+    EXPECT_TRUE(sem->HasSideEffects());
 }
 
 TEST_F(SideEffectsTest, Unary_NoSE) {
-  auto* var = Decl(Var("a", ty.bool_()));
-  auto* expr = Not("a");
-  WrapInFunction(var, expr);
+    auto* var = Decl(Var("a", ty.bool_()));
+    auto* expr = Not("a");
+    WrapInFunction(var, expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  auto* sem = Sem().Get(expr);
-  ASSERT_NE(sem, nullptr);
-  EXPECT_FALSE(sem->HasSideEffects());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* sem = Sem().Get(expr);
+    ASSERT_NE(sem, nullptr);
+    EXPECT_FALSE(sem->HasSideEffects());
 }
 
 TEST_F(SideEffectsTest, Unary_SE) {
-  MakeSideEffectFunc<bool>("se");
-  auto* expr = Not(Call("se"));
-  WrapInFunction(expr);
+    MakeSideEffectFunc<bool>("se");
+    auto* expr = Not(Call("se"));
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  auto* sem = Sem().Get(expr);
-  ASSERT_NE(sem, nullptr);
-  EXPECT_TRUE(sem->HasSideEffects());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* sem = Sem().Get(expr);
+    ASSERT_NE(sem, nullptr);
+    EXPECT_TRUE(sem->HasSideEffects());
 }
 
 TEST_F(SideEffectsTest, IndexAccessor_NoSE) {
-  auto* var = Decl(Var("a", ty.array<i32, 10>()));
-  auto* expr = IndexAccessor("a", 0);
-  WrapInFunction(var, expr);
+    auto* var = Decl(Var("a", ty.array<i32, 10>()));
+    auto* expr = IndexAccessor("a", 0_i);
+    WrapInFunction(var, expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  auto* sem = Sem().Get(expr);
-  ASSERT_NE(sem, nullptr);
-  EXPECT_FALSE(sem->HasSideEffects());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* sem = Sem().Get(expr);
+    ASSERT_NE(sem, nullptr);
+    EXPECT_FALSE(sem->HasSideEffects());
 }
 
 TEST_F(SideEffectsTest, IndexAccessor_ObjSE) {
-  MakeSideEffectFunc("se", [&] { return ty.array<i32, 10>(); });
-  auto* expr = IndexAccessor(Call("se"), 0);
-  WrapInFunction(expr);
+    MakeSideEffectFunc("se", [&] { return ty.array<i32, 10>(); });
+    auto* expr = IndexAccessor(Call("se"), 0_i);
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  auto* sem = Sem().Get(expr);
-  ASSERT_NE(sem, nullptr);
-  EXPECT_TRUE(sem->HasSideEffects());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* sem = Sem().Get(expr);
+    ASSERT_NE(sem, nullptr);
+    EXPECT_TRUE(sem->HasSideEffects());
 }
 
 TEST_F(SideEffectsTest, IndexAccessor_IndexSE) {
-  MakeSideEffectFunc<i32>("se");
-  auto* var = Decl(Var("a", ty.array<i32, 10>()));
-  auto* expr = IndexAccessor("a", Call("se"));
-  WrapInFunction(var, expr);
+    MakeSideEffectFunc<i32>("se");
+    auto* var = Decl(Var("a", ty.array<i32, 10>()));
+    auto* expr = IndexAccessor("a", Call("se"));
+    WrapInFunction(var, expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  auto* sem = Sem().Get(expr);
-  ASSERT_NE(sem, nullptr);
-  EXPECT_TRUE(sem->HasSideEffects());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* sem = Sem().Get(expr);
+    ASSERT_NE(sem, nullptr);
+    EXPECT_TRUE(sem->HasSideEffects());
 }
 
 TEST_F(SideEffectsTest, IndexAccessor_BothSE) {
-  MakeSideEffectFunc("se1", [&] { return ty.array<i32, 10>(); });
-  MakeSideEffectFunc<i32>("se2");
-  auto* expr = IndexAccessor(Call("se1"), Call("se2"));
-  WrapInFunction(expr);
+    MakeSideEffectFunc("se1", [&] { return ty.array<i32, 10>(); });
+    MakeSideEffectFunc<i32>("se2");
+    auto* expr = IndexAccessor(Call("se1"), Call("se2"));
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  auto* sem = Sem().Get(expr);
-  ASSERT_NE(sem, nullptr);
-  EXPECT_TRUE(sem->HasSideEffects());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* sem = Sem().Get(expr);
+    ASSERT_NE(sem, nullptr);
+    EXPECT_TRUE(sem->HasSideEffects());
 }
 
 TEST_F(SideEffectsTest, Bitcast_NoSE) {
-  auto* var = Decl(Var("a", ty.i32()));
-  auto* expr = Bitcast<f32>("a");
-  WrapInFunction(var, expr);
+    auto* var = Decl(Var("a", ty.i32()));
+    auto* expr = Bitcast<f32>("a");
+    WrapInFunction(var, expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  auto* sem = Sem().Get(expr);
-  ASSERT_NE(sem, nullptr);
-  EXPECT_FALSE(sem->HasSideEffects());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* sem = Sem().Get(expr);
+    ASSERT_NE(sem, nullptr);
+    EXPECT_FALSE(sem->HasSideEffects());
 }
 
 TEST_F(SideEffectsTest, Bitcast_SE) {
-  MakeSideEffectFunc<i32>("se");
-  auto* expr = Bitcast<f32>(Call("se"));
-  WrapInFunction(expr);
+    MakeSideEffectFunc<i32>("se");
+    auto* expr = Bitcast<f32>(Call("se"));
+    WrapInFunction(expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  auto* sem = Sem().Get(expr);
-  ASSERT_NE(sem, nullptr);
-  EXPECT_TRUE(sem->HasSideEffects());
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* sem = Sem().Get(expr);
+    ASSERT_NE(sem, nullptr);
+    EXPECT_TRUE(sem->HasSideEffects());
 }
 
 }  // namespace
diff --git a/src/tint/resolver/source_variable_test.cc b/src/tint/resolver/source_variable_test.cc
new file mode 100644
index 0000000..f9fe2fb
--- /dev/null
+++ b/src/tint/resolver/source_variable_test.cc
@@ -0,0 +1,291 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/resolver/resolver.h"
+
+#include "src/tint/resolver/resolver_test_helper.h"
+#include "src/tint/sem/member_accessor_expression.h"
+
+using namespace tint::number_suffixes;  // NOLINT
+
+namespace tint::resolver {
+namespace {
+
+class ResolverSourceVariableTest : public ResolverTest {};
+
+TEST_F(ResolverSourceVariableTest, GlobalPrivateVar) {
+    auto* a = Global("a", ty.f32(), ast::StorageClass::kPrivate);
+    auto* expr = Expr(a);
+    WrapInFunction(expr);
+
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+    auto* sem_a = Sem().Get(a);
+    EXPECT_EQ(Sem().Get(expr)->SourceVariable(), sem_a);
+}
+
+TEST_F(ResolverSourceVariableTest, GlobalWorkgroupVar) {
+    auto* a = Global("a", ty.f32(), ast::StorageClass::kWorkgroup);
+    auto* expr = Expr(a);
+    WrapInFunction(expr);
+
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+    auto* sem_a = Sem().Get(a);
+    EXPECT_EQ(Sem().Get(expr)->SourceVariable(), sem_a);
+}
+
+TEST_F(ResolverSourceVariableTest, GlobalStorageVar) {
+    auto* a = Global("a", ty.f32(), ast::StorageClass::kStorage, GroupAndBinding(0, 0));
+    auto* expr = Expr(a);
+    WrapInFunction(expr);
+
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+    auto* sem_a = Sem().Get(a);
+    EXPECT_EQ(Sem().Get(expr)->SourceVariable(), sem_a);
+}
+
+TEST_F(ResolverSourceVariableTest, GlobalUniformVar) {
+    auto* a = Global("a", ty.f32(), ast::StorageClass::kUniform, GroupAndBinding(0, 0));
+    auto* expr = Expr(a);
+    WrapInFunction(expr);
+
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+    auto* sem_a = Sem().Get(a);
+    EXPECT_EQ(Sem().Get(expr)->SourceVariable(), sem_a);
+}
+
+TEST_F(ResolverSourceVariableTest, GlobalTextureVar) {
+    auto* a = Global("a", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
+                     ast::StorageClass::kNone, GroupAndBinding(0, 0));
+    auto* expr = Expr(a);
+    WrapInFunction(Call("textureDimensions", expr));
+
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+    auto* sem_a = Sem().Get(a);
+    EXPECT_EQ(Sem().Get(expr)->SourceVariable(), sem_a);
+}
+
+TEST_F(ResolverSourceVariableTest, GlobalOverride) {
+    auto* a = Override("a", ty.f32(), Expr(1.f));
+    auto* expr = Expr(a);
+    WrapInFunction(expr);
+
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+    auto* sem_a = Sem().Get(a);
+    EXPECT_EQ(Sem().Get(expr)->SourceVariable(), sem_a);
+}
+
+TEST_F(ResolverSourceVariableTest, GlobalConst) {
+    auto* a = GlobalConst("a", ty.f32(), Expr(1.f));
+    auto* expr = Expr(a);
+    WrapInFunction(expr);
+
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+    auto* sem_a = Sem().Get(a);
+    EXPECT_EQ(Sem().Get(expr)->SourceVariable(), sem_a);
+}
+
+TEST_F(ResolverSourceVariableTest, FunctionVar) {
+    auto* a = Var("a", ty.f32(), ast::StorageClass::kNone);
+    auto* expr = Expr(a);
+    WrapInFunction(a, expr);
+
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+    auto* sem_a = Sem().Get(a);
+    EXPECT_EQ(Sem().Get(expr)->SourceVariable(), sem_a);
+}
+
+TEST_F(ResolverSourceVariableTest, FunctionLet) {
+    auto* a = Let("a", ty.f32(), Expr(1.f));
+    auto* expr = Expr(a);
+    WrapInFunction(a, expr);
+
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+    auto* sem_a = Sem().Get(a);
+    EXPECT_EQ(Sem().Get(expr)->SourceVariable(), sem_a);
+}
+
+TEST_F(ResolverSourceVariableTest, Parameter) {
+    auto* a = Param("a", ty.f32());
+    auto* expr = Expr(a);
+    Func("foo", {a}, ty.void_(), {WrapInStatement(expr)});
+
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+    auto* sem_a = Sem().Get(a);
+    EXPECT_EQ(Sem().Get(expr)->SourceVariable(), sem_a);
+}
+
+TEST_F(ResolverSourceVariableTest, PointerParameter) {
+    // fn foo(a : ptr<function, f32>)
+    // {
+    //   let b = a;
+    // }
+    auto* param = Param("a", ty.pointer(ty.f32(), ast::StorageClass::kFunction));
+    auto* expr_param = Expr(param);
+    auto* let = Let("b", nullptr, expr_param);
+    auto* expr_let = Expr("b");
+    Func("foo", {param}, ty.void_(), {WrapInStatement(let), WrapInStatement(expr_let)});
+
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+    auto* sem_param = Sem().Get(param);
+    EXPECT_EQ(Sem().Get(expr_param)->SourceVariable(), sem_param);
+    EXPECT_EQ(Sem().Get(expr_let)->SourceVariable(), sem_param);
+}
+
+TEST_F(ResolverSourceVariableTest, VarCopyVar) {
+    // {
+    //   var a : f32;
+    //   var b = a;
+    // }
+    auto* a = Var("a", ty.f32(), ast::StorageClass::kNone);
+    auto* expr_a = Expr(a);
+    auto* b = Var("b", ty.f32(), ast::StorageClass::kNone, expr_a);
+    auto* expr_b = Expr(b);
+    WrapInFunction(a, b, expr_b);
+
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+    auto* sem_a = Sem().Get(a);
+    auto* sem_b = Sem().Get(b);
+    EXPECT_EQ(Sem().Get(expr_a)->SourceVariable(), sem_a);
+    EXPECT_EQ(Sem().Get(expr_b)->SourceVariable(), sem_b);
+}
+
+TEST_F(ResolverSourceVariableTest, LetCopyVar) {
+    // {
+    //   var a : f32;
+    //   let b = a;
+    // }
+    auto* a = Var("a", ty.f32(), ast::StorageClass::kNone);
+    auto* expr_a = Expr(a);
+    auto* b = Let("b", ty.f32(), expr_a);
+    auto* expr_b = Expr(b);
+    WrapInFunction(a, b, expr_b);
+
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+    auto* sem_a = Sem().Get(a);
+    auto* sem_b = Sem().Get(b);
+    EXPECT_EQ(Sem().Get(expr_a)->SourceVariable(), sem_a);
+    EXPECT_EQ(Sem().Get(expr_b)->SourceVariable(), sem_b);
+}
+
+TEST_F(ResolverSourceVariableTest, ThroughIndexAccessor) {
+    // var<private> a : array<f32, 4u>;
+    // {
+    //   a[2i]
+    // }
+    auto* a = Global("a", ty.array(ty.f32(), 4_u), ast::StorageClass::kPrivate);
+    auto* expr = IndexAccessor(a, 2_i);
+    WrapInFunction(expr);
+
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+    auto* sem_a = Sem().Get(a);
+    EXPECT_EQ(Sem().Get(expr)->SourceVariable(), sem_a);
+}
+
+TEST_F(ResolverSourceVariableTest, ThroughMemberAccessor) {
+    // struct S { f : f32 }
+    // var<private> a : S;
+    // {
+    //   a.f
+    // }
+    auto* S = Structure("S", {Member("f", ty.f32())});
+    auto* a = Global("a", ty.Of(S), ast::StorageClass::kPrivate);
+    auto* expr = MemberAccessor(a, "f");
+    WrapInFunction(expr);
+
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+    auto* sem_a = Sem().Get(a);
+    EXPECT_EQ(Sem().Get(expr)->SourceVariable(), sem_a);
+}
+
+TEST_F(ResolverSourceVariableTest, ThroughPointers) {
+    // var<private> a : f32;
+    // {
+    //   let a_ptr1 = &*&a;
+    //   let a_ptr2 = &*a_ptr1;
+    // }
+    auto* a = Global("a", ty.f32(), ast::StorageClass::kPrivate);
+    auto* address_of_1 = AddressOf(a);
+    auto* deref_1 = Deref(address_of_1);
+    auto* address_of_2 = AddressOf(deref_1);
+    auto* a_ptr1 = Let("a_ptr1", nullptr, address_of_2);
+    auto* deref_2 = Deref(a_ptr1);
+    auto* address_of_3 = AddressOf(deref_2);
+    auto* a_ptr2 = Let("a_ptr2", nullptr, address_of_3);
+    WrapInFunction(a_ptr1, a_ptr2);
+
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+    auto* sem_a = Sem().Get(a);
+    EXPECT_EQ(Sem().Get(address_of_1)->SourceVariable(), sem_a);
+    EXPECT_EQ(Sem().Get(address_of_2)->SourceVariable(), sem_a);
+    EXPECT_EQ(Sem().Get(address_of_3)->SourceVariable(), sem_a);
+    EXPECT_EQ(Sem().Get(deref_1)->SourceVariable(), sem_a);
+    EXPECT_EQ(Sem().Get(deref_2)->SourceVariable(), sem_a);
+}
+
+TEST_F(ResolverSourceVariableTest, Literal) {
+    auto* expr = Expr(1.f);
+    WrapInFunction(expr);
+
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+    EXPECT_EQ(Sem().Get(expr)->SourceVariable(), nullptr);
+}
+
+TEST_F(ResolverSourceVariableTest, FunctionReturnValue) {
+    auto* expr = Call("min", 1.f, 2.f);
+    WrapInFunction(expr);
+
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+    EXPECT_EQ(Sem().Get(expr)->SourceVariable(), nullptr);
+}
+
+TEST_F(ResolverSourceVariableTest, BinaryExpression) {
+    auto* a = Var("a", ty.f32(), ast::StorageClass::kNone);
+    auto* expr = Add(a, Expr(1.f));
+    WrapInFunction(a, expr);
+
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+    EXPECT_EQ(Sem().Get(expr)->SourceVariable(), nullptr);
+}
+
+TEST_F(ResolverSourceVariableTest, UnaryExpression) {
+    auto* a = Var("a", ty.f32(), ast::StorageClass::kNone);
+    auto* expr = create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation, Expr(a));
+    WrapInFunction(a, expr);
+
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+
+    EXPECT_EQ(Sem().Get(expr)->SourceVariable(), nullptr);
+}
+
+}  // namespace
+}  // namespace tint::resolver
diff --git a/src/tint/resolver/storage_class_layout_validation_test.cc b/src/tint/resolver/storage_class_layout_validation_test.cc
index 23d4c87..db379a0 100644
--- a/src/tint/resolver/storage_class_layout_validation_test.cc
+++ b/src/tint/resolver/storage_class_layout_validation_test.cc
@@ -17,32 +17,33 @@
 #include "gmock/gmock.h"
 #include "src/tint/resolver/resolver_test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::resolver {
 namespace {
 
 using ResolverStorageClassLayoutValidationTest = ResolverTest;
 
 // Detect unaligned member for storage buffers
-TEST_F(ResolverStorageClassLayoutValidationTest,
-       StorageBuffer_UnalignedMember) {
-  // struct S {
-  //     @size(5) a : f32;
-  //     @align(1) b : f32;
-  // };
-  // @group(0) @binding(0)
-  // var<storage> a : S;
+TEST_F(ResolverStorageClassLayoutValidationTest, StorageBuffer_UnalignedMember) {
+    // struct S {
+    //     @size(5) a : f32;
+    //     @align(1) b : f32;
+    // };
+    // @group(0) @binding(0)
+    // var<storage> a : S;
 
-  Structure(Source{{12, 34}}, "S",
-            {Member("a", ty.f32(), {MemberSize(5)}),
-             Member(Source{{34, 56}}, "b", ty.f32(), {MemberAlign(1)})});
+    Structure(Source{{12, 34}}, "S",
+              {Member("a", ty.f32(), {MemberSize(5)}),
+               Member(Source{{34, 56}}, "b", ty.f32(), {MemberAlign(1)})});
 
-  Global(Source{{78, 90}}, "a", ty.type_name("S"), ast::StorageClass::kStorage,
-         GroupAndBinding(0, 0));
+    Global(Source{{78, 90}}, "a", ty.type_name("S"), ast::StorageClass::kStorage,
+           GroupAndBinding(0, 0));
 
-  ASSERT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(34:56 error: the offset of a struct member of type 'f32' in storage class 'storage' must be a multiple of 4 bytes, but 'b' is currently at offset 5. Consider setting @align(4) on this member
+    ASSERT_FALSE(r()->Resolve());
+    EXPECT_EQ(
+        r()->error(),
+        R"(34:56 error: the offset of a struct member of type 'f32' in storage class 'storage' must be a multiple of 4 bytes, but 'b' is currently at offset 5. Consider setting @align(4) on this member
 12:34 note: see layout of struct:
 /*           align(4) size(12) */ struct S {
 /* offset(0) align(4) size( 5) */   a : f32;
@@ -52,55 +53,53 @@
 78:90 note: see declaration of variable)");
 }
 
-TEST_F(ResolverStorageClassLayoutValidationTest,
-       StorageBuffer_UnalignedMember_SuggestedFix) {
-  // struct S {
-  //     @size(5) a : f32;
-  //     @align(4) b : f32;
-  // };
-  // @group(0) @binding(0)
-  // var<storage> a : S;
+TEST_F(ResolverStorageClassLayoutValidationTest, StorageBuffer_UnalignedMember_SuggestedFix) {
+    // struct S {
+    //     @size(5) a : f32;
+    //     @align(4) b : f32;
+    // };
+    // @group(0) @binding(0)
+    // var<storage> a : S;
 
-  Structure(Source{{12, 34}}, "S",
-            {Member("a", ty.f32(), {MemberSize(5)}),
-             Member(Source{{34, 56}}, "b", ty.f32(), {MemberAlign(4)})});
+    Structure(Source{{12, 34}}, "S",
+              {Member("a", ty.f32(), {MemberSize(5)}),
+               Member(Source{{34, 56}}, "b", ty.f32(), {MemberAlign(4)})});
 
-  Global(Source{{78, 90}}, "a", ty.type_name("S"), ast::StorageClass::kStorage,
-         GroupAndBinding(0, 0));
+    Global(Source{{78, 90}}, "a", ty.type_name("S"), ast::StorageClass::kStorage,
+           GroupAndBinding(0, 0));
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 // Detect unaligned struct member for uniform buffers
-TEST_F(ResolverStorageClassLayoutValidationTest,
-       UniformBuffer_UnalignedMember_Struct) {
-  // struct Inner {
-  //   scalar : i32;
-  // };
-  //
-  // struct Outer {
-  //   scalar : f32;
-  //   inner : Inner;
-  // };
-  //
-  // @group(0) @binding(0)
-  // var<uniform> a : Outer;
+TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_UnalignedMember_Struct) {
+    // struct Inner {
+    //   scalar : i32;
+    // };
+    //
+    // struct Outer {
+    //   scalar : f32;
+    //   inner : Inner;
+    // };
+    //
+    // @group(0) @binding(0)
+    // var<uniform> a : Outer;
 
-  Structure(Source{{12, 34}}, "Inner", {Member("scalar", ty.i32())});
+    Structure(Source{{12, 34}}, "Inner", {Member("scalar", ty.i32())});
 
-  Structure(Source{{34, 56}}, "Outer",
-            {
-                Member("scalar", ty.f32()),
-                Member(Source{{56, 78}}, "inner", ty.type_name("Inner")),
-            });
+    Structure(Source{{34, 56}}, "Outer",
+              {
+                  Member("scalar", ty.f32()),
+                  Member(Source{{56, 78}}, "inner", ty.type_name("Inner")),
+              });
 
-  Global(Source{{78, 90}}, "a", ty.type_name("Outer"),
-         ast::StorageClass::kUniform, GroupAndBinding(0, 0));
+    Global(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform,
+           GroupAndBinding(0, 0));
 
-  ASSERT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(56:78 error: the offset of a struct member of type 'Inner' in storage class 'uniform' must be a multiple of 16 bytes, but 'inner' is currently at offset 4. Consider setting @align(16) on this member
+    ASSERT_FALSE(r()->Resolve());
+    EXPECT_EQ(
+        r()->error(),
+        R"(56:78 error: the offset of a struct member of type 'Inner' in storage class 'uniform' must be a multiple of 16 bytes, but 'inner' is currently at offset 4. Consider setting @align(16) on this member
 34:56 note: see layout of struct:
 /*           align(4) size(8) */ struct Outer {
 /* offset(0) align(4) size(4) */   scalar : f32;
@@ -115,60 +114,58 @@
 
 TEST_F(ResolverStorageClassLayoutValidationTest,
        UniformBuffer_UnalignedMember_Struct_SuggestedFix) {
-  // struct Inner {
-  //   scalar : i32;
-  // };
-  //
-  // struct Outer {
-  //   scalar : f32;
-  //   @align(16) inner : Inner;
-  // };
-  //
-  // @group(0) @binding(0)
-  // var<uniform> a : Outer;
+    // struct Inner {
+    //   scalar : i32;
+    // };
+    //
+    // struct Outer {
+    //   scalar : f32;
+    //   @align(16) inner : Inner;
+    // };
+    //
+    // @group(0) @binding(0)
+    // var<uniform> a : Outer;
 
-  Structure(Source{{12, 34}}, "Inner", {Member("scalar", ty.i32())});
+    Structure(Source{{12, 34}}, "Inner", {Member("scalar", ty.i32())});
 
-  Structure(Source{{34, 56}}, "Outer",
-            {
-                Member("scalar", ty.f32()),
-                Member(Source{{56, 78}}, "inner", ty.type_name("Inner"),
-                       {MemberAlign(16)}),
-            });
+    Structure(Source{{34, 56}}, "Outer",
+              {
+                  Member("scalar", ty.f32()),
+                  Member(Source{{56, 78}}, "inner", ty.type_name("Inner"), {MemberAlign(16)}),
+              });
 
-  Global(Source{{78, 90}}, "a", ty.type_name("Outer"),
-         ast::StorageClass::kUniform, GroupAndBinding(0, 0));
+    Global(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform,
+           GroupAndBinding(0, 0));
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 // Detect unaligned array member for uniform buffers
-TEST_F(ResolverStorageClassLayoutValidationTest,
-       UniformBuffer_UnalignedMember_Array) {
-  // type Inner = @stride(16) array<f32, 10>;
-  //
-  // struct Outer {
-  //   scalar : f32;
-  //   inner : Inner;
-  // };
-  //
-  // @group(0) @binding(0)
-  // var<uniform> a : Outer;
-  Alias("Inner", ty.array(ty.f32(), 10, 16));
+TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_UnalignedMember_Array) {
+    // type Inner = @stride(16) array<f32, 10u>;
+    //
+    // struct Outer {
+    //   scalar : f32;
+    //   inner : Inner;
+    // };
+    //
+    // @group(0) @binding(0)
+    // var<uniform> a : Outer;
+    Alias("Inner", ty.array(ty.f32(), 10_u, 16));
 
-  Structure(Source{{12, 34}}, "Outer",
-            {
-                Member("scalar", ty.f32()),
-                Member(Source{{56, 78}}, "inner", ty.type_name("Inner")),
-            });
+    Structure(Source{{12, 34}}, "Outer",
+              {
+                  Member("scalar", ty.f32()),
+                  Member(Source{{56, 78}}, "inner", ty.type_name("Inner")),
+              });
 
-  Global(Source{{78, 90}}, "a", ty.type_name("Outer"),
-         ast::StorageClass::kUniform, GroupAndBinding(0, 0));
+    Global(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform,
+           GroupAndBinding(0, 0));
 
-  ASSERT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(56:78 error: the offset of a struct member of type '@stride(16) array<f32, 10>' in storage class 'uniform' must be a multiple of 16 bytes, but 'inner' is currently at offset 4. Consider setting @align(16) on this member
+    ASSERT_FALSE(r()->Resolve());
+    EXPECT_EQ(
+        r()->error(),
+        R"(56:78 error: the offset of a struct member of type '@stride(16) array<f32, 10>' in storage class 'uniform' must be a multiple of 16 bytes, but 'inner' is currently at offset 4. Consider setting @align(16) on this member
 12:34 note: see layout of struct:
 /*             align(4) size(164) */ struct Outer {
 /* offset(  0) align(4) size(  4) */   scalar : f32;
@@ -177,64 +174,61 @@
 78:90 note: see declaration of variable)");
 }
 
-TEST_F(ResolverStorageClassLayoutValidationTest,
-       UniformBuffer_UnalignedMember_Array_SuggestedFix) {
-  // type Inner = @stride(16) array<f32, 10>;
-  //
-  // struct Outer {
-  //   scalar : f32;
-  //   @align(16) inner : Inner;
-  // };
-  //
-  // @group(0) @binding(0)
-  // var<uniform> a : Outer;
-  Alias("Inner", ty.array(ty.f32(), 10, 16));
+TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_UnalignedMember_Array_SuggestedFix) {
+    // type Inner = @stride(16) array<f32, 10u>;
+    //
+    // struct Outer {
+    //   scalar : f32;
+    //   @align(16) inner : Inner;
+    // };
+    //
+    // @group(0) @binding(0)
+    // var<uniform> a : Outer;
+    Alias("Inner", ty.array(ty.f32(), 10_u, 16));
 
-  Structure(Source{{12, 34}}, "Outer",
-            {
-                Member("scalar", ty.f32()),
-                Member(Source{{34, 56}}, "inner", ty.type_name("Inner"),
-                       {MemberAlign(16)}),
-            });
+    Structure(Source{{12, 34}}, "Outer",
+              {
+                  Member("scalar", ty.f32()),
+                  Member(Source{{34, 56}}, "inner", ty.type_name("Inner"), {MemberAlign(16)}),
+              });
 
-  Global(Source{{78, 90}}, "a", ty.type_name("Outer"),
-         ast::StorageClass::kUniform, GroupAndBinding(0, 0));
+    Global(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform,
+           GroupAndBinding(0, 0));
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 // Detect uniform buffers with byte offset between 2 members that is not a
 // multiple of 16 bytes
-TEST_F(ResolverStorageClassLayoutValidationTest,
-       UniformBuffer_MembersOffsetNotMultipleOf16) {
-  // struct Inner {
-  //   @align(1) @size(5) scalar : i32;
-  // };
-  //
-  // struct Outer {
-  //   inner : Inner;
-  //   scalar : i32;
-  // };
-  //
-  // @group(0) @binding(0)
-  // var<uniform> a : Outer;
+TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_MembersOffsetNotMultipleOf16) {
+    // struct Inner {
+    //   @align(1) @size(5) scalar : i32;
+    // };
+    //
+    // struct Outer {
+    //   inner : Inner;
+    //   scalar : i32;
+    // };
+    //
+    // @group(0) @binding(0)
+    // var<uniform> a : Outer;
 
-  Structure(Source{{12, 34}}, "Inner",
-            {Member("scalar", ty.i32(), {MemberAlign(1), MemberSize(5)})});
+    Structure(Source{{12, 34}}, "Inner",
+              {Member("scalar", ty.i32(), {MemberAlign(1), MemberSize(5)})});
 
-  Structure(Source{{34, 56}}, "Outer",
-            {
-                Member(Source{{56, 78}}, "inner", ty.type_name("Inner")),
-                Member(Source{{78, 90}}, "scalar", ty.i32()),
-            });
+    Structure(Source{{34, 56}}, "Outer",
+              {
+                  Member(Source{{56, 78}}, "inner", ty.type_name("Inner")),
+                  Member(Source{{78, 90}}, "scalar", ty.i32()),
+              });
 
-  Global(Source{{22, 24}}, "a", ty.type_name("Outer"),
-         ast::StorageClass::kUniform, GroupAndBinding(0, 0));
+    Global(Source{{22, 24}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform,
+           GroupAndBinding(0, 0));
 
-  ASSERT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(78:90 error: uniform storage requires that the number of bytes between the start of the previous member of type struct and the current member be a multiple of 16 bytes, but there are currently 8 bytes between 'inner' and 'scalar'. Consider setting @align(16) on this member
+    ASSERT_FALSE(r()->Resolve());
+    EXPECT_EQ(
+        r()->error(),
+        R"(78:90 error: uniform storage requires that the number of bytes between the start of the previous member of type struct and the current member be a multiple of 16 bytes, but there are currently 8 bytes between 'inner' and 'scalar'. Consider setting @align(16) on this member
 34:56 note: see layout of struct:
 /*            align(4) size(12) */ struct Outer {
 /* offset( 0) align(1) size( 5) */   inner : Inner;
@@ -251,42 +245,42 @@
 // See https://crbug.com/tint/1344
 TEST_F(ResolverStorageClassLayoutValidationTest,
        UniformBuffer_MembersOffsetNotMultipleOf16_InnerMoreMembersThanOuter) {
-  // struct Inner {
-  //   a : i32;
-  //   b : i32;
-  //   c : i32;
-  //   @align(1) @size(5) scalar : i32;
-  // };
-  //
-  // struct Outer {
-  //   inner : Inner;
-  //   scalar : i32;
-  // };
-  //
-  // @group(0) @binding(0)
-  // var<uniform> a : Outer;
+    // struct Inner {
+    //   a : i32;
+    //   b : i32;
+    //   c : i32;
+    //   @align(1) @size(5) scalar : i32;
+    // };
+    //
+    // struct Outer {
+    //   inner : Inner;
+    //   scalar : i32;
+    // };
+    //
+    // @group(0) @binding(0)
+    // var<uniform> a : Outer;
 
-  Structure(Source{{12, 34}}, "Inner",
-            {
-                Member("a", ty.i32()),
-                Member("b", ty.i32()),
-                Member("c", ty.i32()),
-                Member("scalar", ty.i32(), {MemberAlign(1), MemberSize(5)}),
-            });
+    Structure(Source{{12, 34}}, "Inner",
+              {
+                  Member("a", ty.i32()),
+                  Member("b", ty.i32()),
+                  Member("c", ty.i32()),
+                  Member("scalar", ty.i32(), {MemberAlign(1), MemberSize(5)}),
+              });
 
-  Structure(Source{{34, 56}}, "Outer",
-            {
-                Member(Source{{56, 78}}, "inner", ty.type_name("Inner")),
-                Member(Source{{78, 90}}, "scalar", ty.i32()),
-            });
+    Structure(Source{{34, 56}}, "Outer",
+              {
+                  Member(Source{{56, 78}}, "inner", ty.type_name("Inner")),
+                  Member(Source{{78, 90}}, "scalar", ty.i32()),
+              });
 
-  Global(Source{{22, 24}}, "a", ty.type_name("Outer"),
-         ast::StorageClass::kUniform, GroupAndBinding(0, 0));
+    Global(Source{{22, 24}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform,
+           GroupAndBinding(0, 0));
 
-  ASSERT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(78:90 error: uniform storage requires that the number of bytes between the start of the previous member of type struct and the current member be a multiple of 16 bytes, but there are currently 20 bytes between 'inner' and 'scalar'. Consider setting @align(16) on this member
+    ASSERT_FALSE(r()->Resolve());
+    EXPECT_EQ(
+        r()->error(),
+        R"(78:90 error: uniform storage requires that the number of bytes between the start of the previous member of type struct and the current member be a multiple of 16 bytes, but there are currently 20 bytes between 'inner' and 'scalar'. Consider setting @align(16) on this member
 34:56 note: see layout of struct:
 /*            align(4) size(24) */ struct Outer {
 /* offset( 0) align(4) size(20) */   inner : Inner;
@@ -305,83 +299,81 @@
 
 TEST_F(ResolverStorageClassLayoutValidationTest,
        UniformBuffer_MembersOffsetNotMultipleOf16_SuggestedFix) {
-  // struct Inner {
-  //   @align(1) @size(5) scalar : i32;
-  // };
-  //
-  // struct Outer {
-  //   @align(16) inner : Inner;
-  //   scalar : i32;
-  // };
-  //
-  // @group(0) @binding(0)
-  // var<uniform> a : Outer;
+    // struct Inner {
+    //   @align(1) @size(5) scalar : i32;
+    // };
+    //
+    // struct Outer {
+    //   @align(16) inner : Inner;
+    //   scalar : i32;
+    // };
+    //
+    // @group(0) @binding(0)
+    // var<uniform> a : Outer;
 
-  Structure(Source{{12, 34}}, "Inner",
-            {Member("scalar", ty.i32(), {MemberAlign(1), MemberSize(5)})});
+    Structure(Source{{12, 34}}, "Inner",
+              {Member("scalar", ty.i32(), {MemberAlign(1), MemberSize(5)})});
 
-  Structure(Source{{34, 56}}, "Outer",
-            {
-                Member(Source{{56, 78}}, "inner", ty.type_name("Inner")),
-                Member(Source{{78, 90}}, "scalar", ty.i32(), {MemberAlign(16)}),
-            });
+    Structure(Source{{34, 56}}, "Outer",
+              {
+                  Member(Source{{56, 78}}, "inner", ty.type_name("Inner")),
+                  Member(Source{{78, 90}}, "scalar", ty.i32(), {MemberAlign(16)}),
+              });
 
-  Global(Source{{22, 34}}, "a", ty.type_name("Outer"),
-         ast::StorageClass::kUniform, GroupAndBinding(0, 0));
+    Global(Source{{22, 34}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform,
+           GroupAndBinding(0, 0));
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 // Make sure that this doesn't fail validation because vec3's align is 16, but
 // size is 12. 's' should be at offset 12, which is okay here.
-TEST_F(ResolverStorageClassLayoutValidationTest,
-       UniformBuffer_Vec3MemberOffset_NoFail) {
-  // struct ScalarPackedAtEndOfVec3 {
-  //     v : vec3<f32>;
-  //     s : f32;
-  // };
-  // @group(0) @binding(0)
-  // var<uniform> a : ScalarPackedAtEndOfVec3;
+TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_Vec3MemberOffset_NoFail) {
+    // struct ScalarPackedAtEndOfVec3 {
+    //     v : vec3<f32>;
+    //     s : f32;
+    // };
+    // @group(0) @binding(0)
+    // var<uniform> a : ScalarPackedAtEndOfVec3;
 
-  Structure("ScalarPackedAtEndOfVec3", {
-                                           Member("v", ty.vec3(ty.f32())),
-                                           Member("s", ty.f32()),
-                                       });
+    Structure("ScalarPackedAtEndOfVec3", {
+                                             Member("v", ty.vec3(ty.f32())),
+                                             Member("s", ty.f32()),
+                                         });
 
-  Global(Source{{78, 90}}, "a", ty.type_name("ScalarPackedAtEndOfVec3"),
-         ast::StorageClass::kUniform, GroupAndBinding(0, 0));
+    Global(Source{{78, 90}}, "a", ty.type_name("ScalarPackedAtEndOfVec3"),
+           ast::StorageClass::kUniform, GroupAndBinding(0, 0));
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 // Detect array stride must be a multiple of 16 bytes for uniform buffers
-TEST_F(ResolverStorageClassLayoutValidationTest,
-       UniformBuffer_InvalidArrayStride_Scalar) {
-  // type Inner = array<f32, 10>;
-  //
-  // struct Outer {
-  //   inner : Inner;
-  //   scalar : i32;
-  // };
-  //
-  // @group(0) @binding(0)
-  // var<uniform> a : Outer;
+TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_InvalidArrayStride_Scalar) {
+    // type Inner = array<f32, 10u>;
+    //
+    // struct Outer {
+    //   inner : Inner;
+    //   scalar : i32;
+    // };
+    //
+    // @group(0) @binding(0)
+    // var<uniform> a : Outer;
 
-  Alias("Inner", ty.array(ty.f32(), 10));
+    Alias("Inner", ty.array(ty.f32(), 10_u));
 
-  Structure(Source{{12, 34}}, "Outer",
-            {
-                Member("inner", ty.type_name(Source{{34, 56}}, "Inner")),
-                Member("scalar", ty.i32()),
-            });
+    Structure(Source{{12, 34}}, "Outer",
+              {
+                  Member("inner", ty.type_name(Source{{34, 56}}, "Inner")),
+                  Member("scalar", ty.i32()),
+              });
 
-  Global(Source{{78, 90}}, "a", ty.type_name("Outer"),
-         ast::StorageClass::kUniform, GroupAndBinding(0, 0));
+    Global(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform,
+           GroupAndBinding(0, 0));
 
-  ASSERT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(34:56 error: uniform storage requires that array elements be aligned to 16 bytes, but array element alignment is currently 4. Consider using a vector or struct as the element type instead.
+    ASSERT_FALSE(r()->Resolve());
+    EXPECT_EQ(
+        r()->error(),
+        R"(34:56 error: uniform storage requires that array elements be aligned to 16 bytes, but array element alignment is currently 4. Consider using a vector or struct as the element type instead.
 12:34 note: see layout of struct:
 /*            align(4) size(44) */ struct Outer {
 /* offset( 0) align(4) size(40) */   inner : array<f32, 10>;
@@ -390,33 +382,32 @@
 78:90 note: see declaration of variable)");
 }
 
-TEST_F(ResolverStorageClassLayoutValidationTest,
-       UniformBuffer_InvalidArrayStride_Vector) {
-  // type Inner = array<vec2<f32>, 10>;
-  //
-  // struct Outer {
-  //   inner : Inner;
-  //   scalar : i32;
-  // };
-  //
-  // @group(0) @binding(0)
-  // var<uniform> a : Outer;
+TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_InvalidArrayStride_Vector) {
+    // type Inner = array<vec2<f32>, 10u>;
+    //
+    // struct Outer {
+    //   inner : Inner;
+    //   scalar : i32;
+    // };
+    //
+    // @group(0) @binding(0)
+    // var<uniform> a : Outer;
 
-  Alias("Inner", ty.array(ty.vec2<f32>(), 10));
+    Alias("Inner", ty.array(ty.vec2<f32>(), 10_u));
 
-  Structure(Source{{12, 34}}, "Outer",
-            {
-                Member("inner", ty.type_name(Source{{34, 56}}, "Inner")),
-                Member("scalar", ty.i32()),
-            });
+    Structure(Source{{12, 34}}, "Outer",
+              {
+                  Member("inner", ty.type_name(Source{{34, 56}}, "Inner")),
+                  Member("scalar", ty.i32()),
+              });
 
-  Global(Source{{78, 90}}, "a", ty.type_name("Outer"),
-         ast::StorageClass::kUniform, GroupAndBinding(0, 0));
+    Global(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform,
+           GroupAndBinding(0, 0));
 
-  ASSERT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(34:56 error: uniform storage requires that array elements be aligned to 16 bytes, but array element alignment is currently 8. Consider using a vec4 instead.
+    ASSERT_FALSE(r()->Resolve());
+    EXPECT_EQ(
+        r()->error(),
+        R"(34:56 error: uniform storage requires that array elements be aligned to 16 bytes, but array element alignment is currently 8. Consider using a vec4 instead.
 12:34 note: see layout of struct:
 /*            align(8) size(88) */ struct Outer {
 /* offset( 0) align(8) size(80) */   inner : array<vec2<f32>, 10>;
@@ -426,41 +417,40 @@
 78:90 note: see declaration of variable)");
 }
 
-TEST_F(ResolverStorageClassLayoutValidationTest,
-       UniformBuffer_InvalidArrayStride_Struct) {
-  // struct ArrayElem {
-  //   a : f32;
-  //   b : i32;
-  // }
-  // type Inner = array<ArrayElem, 10>;
-  //
-  // struct Outer {
-  //   inner : Inner;
-  //   scalar : i32;
-  // };
-  //
-  // @group(0) @binding(0)
-  // var<uniform> a : Outer;
+TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_InvalidArrayStride_Struct) {
+    // struct ArrayElem {
+    //   a : f32;
+    //   b : i32;
+    // }
+    // type Inner = array<ArrayElem, 10u>;
+    //
+    // struct Outer {
+    //   inner : Inner;
+    //   scalar : i32;
+    // };
+    //
+    // @group(0) @binding(0)
+    // var<uniform> a : Outer;
 
-  auto* array_elem = Structure("ArrayElem", {
-                                                Member("a", ty.f32()),
-                                                Member("b", ty.i32()),
-                                            });
-  Alias("Inner", ty.array(ty.Of(array_elem), 10));
+    auto* array_elem = Structure("ArrayElem", {
+                                                  Member("a", ty.f32()),
+                                                  Member("b", ty.i32()),
+                                              });
+    Alias("Inner", ty.array(ty.Of(array_elem), 10_u));
 
-  Structure(Source{{12, 34}}, "Outer",
-            {
-                Member("inner", ty.type_name(Source{{34, 56}}, "Inner")),
-                Member("scalar", ty.i32()),
-            });
+    Structure(Source{{12, 34}}, "Outer",
+              {
+                  Member("inner", ty.type_name(Source{{34, 56}}, "Inner")),
+                  Member("scalar", ty.i32()),
+              });
 
-  Global(Source{{78, 90}}, "a", ty.type_name("Outer"),
-         ast::StorageClass::kUniform, GroupAndBinding(0, 0));
+    Global(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform,
+           GroupAndBinding(0, 0));
 
-  ASSERT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(34:56 error: uniform storage requires that array elements be aligned to 16 bytes, but array element alignment is currently 8. Consider using the @size attribute on the last struct member.
+    ASSERT_FALSE(r()->Resolve());
+    EXPECT_EQ(
+        r()->error(),
+        R"(34:56 error: uniform storage requires that array elements be aligned to 16 bytes, but array element alignment is currently 8. Consider using the @size attribute on the last struct member.
 12:34 note: see layout of struct:
 /*            align(4) size(84) */ struct Outer {
 /* offset( 0) align(4) size(80) */   inner : array<ArrayElem, 10>;
@@ -469,41 +459,38 @@
 78:90 note: see declaration of variable)");
 }
 
-TEST_F(ResolverStorageClassLayoutValidationTest,
-       UniformBuffer_InvalidArrayStride_TopLevelArray) {
-  // @group(0) @binding(0)
-  // var<uniform> a : array<f32, 4>;
-  Global(Source{{78, 90}}, "a", ty.array(Source{{34, 56}}, ty.f32(), 4),
-         ast::StorageClass::kUniform, GroupAndBinding(0, 0));
+TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_InvalidArrayStride_TopLevelArray) {
+    // @group(0) @binding(0)
+    // var<uniform> a : array<f32, 4u>;
+    Global(Source{{78, 90}}, "a", ty.array(Source{{34, 56}}, ty.f32(), 4_u),
+           ast::StorageClass::kUniform, GroupAndBinding(0, 0));
 
-  ASSERT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(34:56 error: uniform storage requires that array elements be aligned to 16 bytes, but array element alignment is currently 4. Consider using a vector or struct as the element type instead.)");
+    ASSERT_FALSE(r()->Resolve());
+    EXPECT_EQ(
+        r()->error(),
+        R"(34:56 error: uniform storage requires that array elements be aligned to 16 bytes, but array element alignment is currently 4. Consider using a vector or struct as the element type instead.)");
 }
 
-TEST_F(ResolverStorageClassLayoutValidationTest,
-       UniformBuffer_InvalidArrayStride_NestedArray) {
-  // struct Outer {
-  //   inner : array<array<f32, 4>, 4>
-  // };
-  //
-  // @group(0) @binding(0)
-  // var<uniform> a : array<Outer, 4>;
+TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_InvalidArrayStride_NestedArray) {
+    // struct Outer {
+    //   inner : array<array<f32, 4u>, 4u>
+    // };
+    //
+    // @group(0) @binding(0)
+    // var<uniform> a : array<Outer, 4u>;
 
-  Structure(
-      Source{{12, 34}}, "Outer",
-      {
-          Member("inner", ty.array(Source{{34, 56}}, ty.array(ty.f32(), 4), 4)),
-      });
+    Structure(Source{{12, 34}}, "Outer",
+              {
+                  Member("inner", ty.array(Source{{34, 56}}, ty.array(ty.f32(), 4_u), 4_u)),
+              });
 
-  Global(Source{{78, 90}}, "a", ty.type_name("Outer"),
-         ast::StorageClass::kUniform, GroupAndBinding(0, 0));
+    Global(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform,
+           GroupAndBinding(0, 0));
 
-  ASSERT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(34:56 error: uniform storage requires that array elements be aligned to 16 bytes, but array element alignment is currently 4. Consider using a vector or struct as the element type instead.
+    ASSERT_FALSE(r()->Resolve());
+    EXPECT_EQ(
+        r()->error(),
+        R"(34:56 error: uniform storage requires that array elements be aligned to 16 bytes, but array element alignment is currently 4. Consider using a vector or struct as the element type instead.
 12:34 note: see layout of struct:
 /*            align(4) size(64) */ struct Outer {
 /* offset( 0) align(4) size(64) */   inner : array<array<f32, 4>, 4>;
@@ -511,30 +498,29 @@
 78:90 note: see declaration of variable)");
 }
 
-TEST_F(ResolverStorageClassLayoutValidationTest,
-       UniformBuffer_InvalidArrayStride_SuggestedFix) {
-  // type Inner = @stride(16) array<f32, 10>;
-  //
-  // struct Outer {
-  //   inner : Inner;
-  //   scalar : i32;
-  // };
-  //
-  // @group(0) @binding(0)
-  // var<uniform> a : Outer;
+TEST_F(ResolverStorageClassLayoutValidationTest, UniformBuffer_InvalidArrayStride_SuggestedFix) {
+    // type Inner = @stride(16) array<f32, 10u>;
+    //
+    // struct Outer {
+    //   inner : Inner;
+    //   scalar : i32;
+    // };
+    //
+    // @group(0) @binding(0)
+    // var<uniform> a : Outer;
 
-  Alias("Inner", ty.array(ty.f32(), 10, 16));
+    Alias("Inner", ty.array(ty.f32(), 10_u, 16));
 
-  Structure(Source{{12, 34}}, "Outer",
-            {
-                Member("inner", ty.type_name(Source{{34, 56}}, "Inner")),
-                Member("scalar", ty.i32()),
-            });
+    Structure(Source{{12, 34}}, "Outer",
+              {
+                  Member("inner", ty.type_name(Source{{34, 56}}, "Inner")),
+                  Member("scalar", ty.i32()),
+              });
 
-  Global(Source{{78, 90}}, "a", ty.type_name("Outer"),
-         ast::StorageClass::kUniform, GroupAndBinding(0, 0));
+    Global(Source{{78, 90}}, "a", ty.type_name("Outer"), ast::StorageClass::kUniform,
+           GroupAndBinding(0, 0));
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 }  // namespace
diff --git a/src/tint/resolver/storage_class_validation_test.cc b/src/tint/resolver/storage_class_validation_test.cc
index 1173578..2d75167 100644
--- a/src/tint/resolver/storage_class_validation_test.cc
+++ b/src/tint/resolver/storage_class_validation_test.cc
@@ -18,344 +18,331 @@
 #include "src/tint/resolver/resolver_test_helper.h"
 #include "src/tint/sem/struct.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::resolver {
 namespace {
 
 using ResolverStorageClassValidationTest = ResolverTest;
 
 TEST_F(ResolverStorageClassValidationTest, GlobalVariableNoStorageClass_Fail) {
-  // var g : f32;
-  Global(Source{{12, 34}}, "g", ty.f32(), ast::StorageClass::kNone);
+    // var g : f32;
+    Global(Source{{12, 34}}, "g", ty.f32(), ast::StorageClass::kNone);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: global variables must have a storage class");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: global variables must have a storage class");
 }
 
-TEST_F(ResolverStorageClassValidationTest,
-       GlobalVariableFunctionStorageClass_Fail) {
-  // var<function> g : f32;
-  Global(Source{{12, 34}}, "g", ty.f32(), ast::StorageClass::kFunction);
+TEST_F(ResolverStorageClassValidationTest, GlobalVariableFunctionStorageClass_Fail) {
+    // var<function> g : f32;
+    Global(Source{{12, 34}}, "g", ty.f32(), ast::StorageClass::kFunction);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: variables declared at module scope must not be in "
-            "the function storage class");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: variables declared at module scope must not be in "
+              "the function storage class");
 }
 
 TEST_F(ResolverStorageClassValidationTest, Private_RuntimeArray) {
-  Global(Source{{12, 34}}, "v", ty.array(ty.i32()),
-         ast::StorageClass::kPrivate);
+    Global(Source{{12, 34}}, "v", ty.array(ty.i32()), ast::StorageClass::kPrivate);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: runtime-sized arrays can only be used in the <storage> storage class
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: runtime-sized arrays can only be used in the <storage> storage class
 12:34 note: while instantiating variable v)");
 }
 
 TEST_F(ResolverStorageClassValidationTest, Private_RuntimeArrayInStruct) {
-  auto* s = Structure("S", {Member("m", ty.array(ty.i32()))});
-  Global(Source{{12, 34}}, "v", ty.Of(s), ast::StorageClass::kPrivate);
+    auto* s = Structure("S", {Member("m", ty.array(ty.i32()))});
+    Global(Source{{12, 34}}, "v", ty.Of(s), ast::StorageClass::kPrivate);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: runtime-sized arrays can only be used in the <storage> storage class
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: runtime-sized arrays can only be used in the <storage> storage class
 note: while analysing structure member S.m
 12:34 note: while instantiating variable v)");
 }
 
 TEST_F(ResolverStorageClassValidationTest, Workgroup_RuntimeArray) {
-  Global(Source{{12, 34}}, "v", ty.array(ty.i32()),
-         ast::StorageClass::kWorkgroup);
+    Global(Source{{12, 34}}, "v", ty.array(ty.i32()), ast::StorageClass::kWorkgroup);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: runtime-sized arrays can only be used in the <storage> storage class
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: runtime-sized arrays can only be used in the <storage> storage class
 12:34 note: while instantiating variable v)");
 }
 
 TEST_F(ResolverStorageClassValidationTest, Workgroup_RuntimeArrayInStruct) {
-  auto* s = Structure("S", {Member("m", ty.array(ty.i32()))});
-  Global(Source{{12, 34}}, "v", ty.Of(s), ast::StorageClass::kWorkgroup);
+    auto* s = Structure("S", {Member("m", ty.array(ty.i32()))});
+    Global(Source{{12, 34}}, "v", ty.Of(s), ast::StorageClass::kWorkgroup);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: runtime-sized arrays can only be used in the <storage> storage class
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: runtime-sized arrays can only be used in the <storage> storage class
 note: while analysing structure member S.m
 12:34 note: while instantiating variable v)");
 }
 
 TEST_F(ResolverStorageClassValidationTest, StorageBufferBool) {
-  // var<storage> g : bool;
-  Global(Source{{56, 78}}, "g", ty.bool_(), ast::StorageClass::kStorage,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    // var<storage> g : bool;
+    Global(Source{{56, 78}}, "g", ty.bool_(), ast::StorageClass::kStorage,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  ASSERT_FALSE(r()->Resolve());
+    ASSERT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(
-      r()->error(),
-      R"(56:78 error: Type 'bool' cannot be used in storage class 'storage' as it is non-host-shareable
+    EXPECT_EQ(
+        r()->error(),
+        R"(56:78 error: Type 'bool' cannot be used in storage class 'storage' as it is non-host-shareable
 56:78 note: while instantiating variable g)");
 }
 
 TEST_F(ResolverStorageClassValidationTest, StorageBufferPointer) {
-  // var<storage> g : ptr<private, f32>;
-  Global(Source{{56, 78}}, "g",
-         ty.pointer(ty.f32(), ast::StorageClass::kPrivate),
-         ast::StorageClass::kStorage,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    // var<storage> g : ptr<private, f32>;
+    Global(Source{{56, 78}}, "g", ty.pointer(ty.f32(), ast::StorageClass::kPrivate),
+           ast::StorageClass::kStorage,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  ASSERT_FALSE(r()->Resolve());
+    ASSERT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(
-      r()->error(),
-      R"(56:78 error: Type 'ptr<private, f32, read_write>' cannot be used in storage class 'storage' as it is non-host-shareable
+    EXPECT_EQ(
+        r()->error(),
+        R"(56:78 error: Type 'ptr<private, f32, read_write>' cannot be used in storage class 'storage' as it is non-host-shareable
 56:78 note: while instantiating variable g)");
 }
 
 TEST_F(ResolverStorageClassValidationTest, StorageBufferIntScalar) {
-  // var<storage> g : i32;
-  Global(Source{{56, 78}}, "g", ty.i32(), ast::StorageClass::kStorage,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    // var<storage> g : i32;
+    Global(Source{{56, 78}}, "g", ty.i32(), ast::StorageClass::kStorage,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverStorageClassValidationTest, StorageBufferVector) {
-  // var<storage> g : vec4<f32>;
-  Global(Source{{56, 78}}, "g", ty.vec4<f32>(), ast::StorageClass::kStorage,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    // var<storage> g : vec4<f32>;
+    Global(Source{{56, 78}}, "g", ty.vec4<f32>(), ast::StorageClass::kStorage,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverStorageClassValidationTest, StorageBufferArray) {
-  // var<storage, read> g : array<S, 3>;
-  auto* s = Structure("S", {Member("a", ty.f32())});
-  auto* a = ty.array(ty.Of(s), 3);
-  Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage,
-         ast::Access::kRead,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    // var<storage, read> g : array<S, 3u>;
+    auto* s = Structure("S", {Member("a", ty.f32())});
+    auto* a = ty.array(ty.Of(s), 3_u);
+    Global(Source{{56, 78}}, "g", a, ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverStorageClassValidationTest, StorageBufferBoolAlias) {
-  // type a = bool;
-  // var<storage, read> g : a;
-  auto* a = Alias("a", ty.bool_());
-  Global(Source{{56, 78}}, "g", ty.Of(a), ast::StorageClass::kStorage,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    // type a = bool;
+    // var<storage, read> g : a;
+    auto* a = Alias("a", ty.bool_());
+    Global(Source{{56, 78}}, "g", ty.Of(a), ast::StorageClass::kStorage,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  ASSERT_FALSE(r()->Resolve());
+    ASSERT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(
-      r()->error(),
-      R"(56:78 error: Type 'bool' cannot be used in storage class 'storage' as it is non-host-shareable
+    EXPECT_EQ(
+        r()->error(),
+        R"(56:78 error: Type 'bool' cannot be used in storage class 'storage' as it is non-host-shareable
 56:78 note: while instantiating variable g)");
 }
 
 TEST_F(ResolverStorageClassValidationTest, NotStorage_AccessMode) {
-  // var<private, read> g : a;
-  Global(Source{{56, 78}}, "g", ty.i32(), ast::StorageClass::kPrivate,
-         ast::Access::kRead);
+    // var<private, read> g : a;
+    Global(Source{{56, 78}}, "g", ty.i32(), ast::StorageClass::kPrivate, ast::Access::kRead);
 
-  ASSERT_FALSE(r()->Resolve());
+    ASSERT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(
-      r()->error(),
-      R"(56:78 error: only variables in <storage> storage class may declare an access mode)");
+    EXPECT_EQ(
+        r()->error(),
+        R"(56:78 error: only variables in <storage> storage class may declare an access mode)");
 }
 
 TEST_F(ResolverStorageClassValidationTest, StorageBufferNoError_Basic) {
-  // struct S { x : i32 };
-  // var<storage, read> g : S;
-  auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())});
-  Global(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kStorage,
-         ast::Access::kRead,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    // struct S { x : i32 };
+    // var<storage, read> g : S;
+    auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())});
+    Global(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  ASSERT_TRUE(r()->Resolve());
+    ASSERT_TRUE(r()->Resolve());
 }
 
 TEST_F(ResolverStorageClassValidationTest, StorageBufferNoError_Aliases) {
-  // struct S { x : i32 };
-  // type a1 = S;
-  // var<storage, read> g : a1;
-  auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())});
-  auto* a1 = Alias("a1", ty.Of(s));
-  auto* a2 = Alias("a2", ty.Of(a1));
-  Global(Source{{56, 78}}, "g", ty.Of(a2), ast::StorageClass::kStorage,
-         ast::Access::kRead,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    // struct S { x : i32 };
+    // type a1 = S;
+    // var<storage, read> g : a1;
+    auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())});
+    auto* a1 = Alias("a1", ty.Of(s));
+    auto* a2 = Alias("a2", ty.Of(a1));
+    Global(Source{{56, 78}}, "g", ty.Of(a2), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  ASSERT_TRUE(r()->Resolve());
+    ASSERT_TRUE(r()->Resolve());
 }
 
 TEST_F(ResolverStorageClassValidationTest, UniformBuffer_Struct_Runtime) {
-  // struct S { m:  array<f32>; };
-  // @group(0) @binding(0) var<uniform, > svar : S;
+    // struct S { m:  array<f32>; };
+    // @group(0) @binding(0) var<uniform, > svar : S;
 
-  auto* s = Structure(Source{{12, 34}}, "S", {Member("m", ty.array<i32>())});
+    auto* s = Structure(Source{{12, 34}}, "S", {Member("m", ty.array<i32>())});
 
-  Global(Source{{56, 78}}, "svar", ty.Of(s), ast::StorageClass::kUniform,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    Global(Source{{56, 78}}, "svar", ty.Of(s), ast::StorageClass::kUniform,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  ASSERT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(56:78 error: runtime-sized arrays can only be used in the <storage> storage class
+    ASSERT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(56:78 error: runtime-sized arrays can only be used in the <storage> storage class
 note: while analysing structure member S.m
 56:78 note: while instantiating variable svar)");
 }
 
 TEST_F(ResolverStorageClassValidationTest, UniformBufferBool) {
-  // var<uniform> g : bool;
-  Global(Source{{56, 78}}, "g", ty.bool_(), ast::StorageClass::kUniform,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    // var<uniform> g : bool;
+    Global(Source{{56, 78}}, "g", ty.bool_(), ast::StorageClass::kUniform,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  ASSERT_FALSE(r()->Resolve());
+    ASSERT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(
-      r()->error(),
-      R"(56:78 error: Type 'bool' cannot be used in storage class 'uniform' as it is non-host-shareable
+    EXPECT_EQ(
+        r()->error(),
+        R"(56:78 error: Type 'bool' cannot be used in storage class 'uniform' as it is non-host-shareable
 56:78 note: while instantiating variable g)");
 }
 
 TEST_F(ResolverStorageClassValidationTest, UniformBufferPointer) {
-  // var<uniform> g : ptr<private, f32>;
-  Global(Source{{56, 78}}, "g",
-         ty.pointer(ty.f32(), ast::StorageClass::kPrivate),
-         ast::StorageClass::kUniform,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    // var<uniform> g : ptr<private, f32>;
+    Global(Source{{56, 78}}, "g", ty.pointer(ty.f32(), ast::StorageClass::kPrivate),
+           ast::StorageClass::kUniform,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  ASSERT_FALSE(r()->Resolve());
+    ASSERT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(
-      r()->error(),
-      R"(56:78 error: Type 'ptr<private, f32, read_write>' cannot be used in storage class 'uniform' as it is non-host-shareable
+    EXPECT_EQ(
+        r()->error(),
+        R"(56:78 error: Type 'ptr<private, f32, read_write>' cannot be used in storage class 'uniform' as it is non-host-shareable
 56:78 note: while instantiating variable g)");
 }
 
 TEST_F(ResolverStorageClassValidationTest, UniformBufferIntScalar) {
-  // var<uniform> g : i32;
-  Global(Source{{56, 78}}, "g", ty.i32(), ast::StorageClass::kUniform,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    // var<uniform> g : i32;
+    Global(Source{{56, 78}}, "g", ty.i32(), ast::StorageClass::kUniform,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverStorageClassValidationTest, UniformBufferVector) {
-  // var<uniform> g : vec4<f32>;
-  Global(Source{{56, 78}}, "g", ty.vec4<f32>(), ast::StorageClass::kUniform,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    // var<uniform> g : vec4<f32>;
+    Global(Source{{56, 78}}, "g", ty.vec4<f32>(), ast::StorageClass::kUniform,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverStorageClassValidationTest, UniformBufferArray) {
-  // struct S {
-  //   @size(16) f : f32;
-  // }
-  // var<uniform> g : array<S, 3>;
-  auto* s = Structure("S", {Member("a", ty.f32(), {MemberSize(16)})});
-  auto* a = ty.array(ty.Of(s), 3);
-  Global(Source{{56, 78}}, "g", a, ast::StorageClass::kUniform,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    // struct S {
+    //   @size(16) f : f32;
+    // }
+    // var<uniform> g : array<S, 3u>;
+    auto* s = Structure("S", {Member("a", ty.f32(), {MemberSize(16)})});
+    auto* a = ty.array(ty.Of(s), 3_u);
+    Global(Source{{56, 78}}, "g", a, ast::StorageClass::kUniform,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverStorageClassValidationTest, UniformBufferBoolAlias) {
-  // type a = bool;
-  // var<uniform> g : a;
-  auto* a = Alias("a", ty.bool_());
-  Global(Source{{56, 78}}, "g", ty.Of(a), ast::StorageClass::kUniform,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    // type a = bool;
+    // var<uniform> g : a;
+    auto* a = Alias("a", ty.bool_());
+    Global(Source{{56, 78}}, "g", ty.Of(a), ast::StorageClass::kUniform,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  ASSERT_FALSE(r()->Resolve());
+    ASSERT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(
-      r()->error(),
-      R"(56:78 error: Type 'bool' cannot be used in storage class 'uniform' as it is non-host-shareable
+    EXPECT_EQ(
+        r()->error(),
+        R"(56:78 error: Type 'bool' cannot be used in storage class 'uniform' as it is non-host-shareable
 56:78 note: while instantiating variable g)");
 }
 
 TEST_F(ResolverStorageClassValidationTest, UniformBufferNoError_Basic) {
-  // struct S { x : i32 };
-  // var<uniform> g :  S;
-  auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())});
-  Global(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kUniform,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    // struct S { x : i32 };
+    // var<uniform> g :  S;
+    auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())});
+    Global(Source{{56, 78}}, "g", ty.Of(s), ast::StorageClass::kUniform,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverStorageClassValidationTest, UniformBufferNoError_Aliases) {
-  // struct S { x : i32 };
-  // type a1 = S;
-  // var<uniform> g : a1;
-  auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())});
-  auto* a1 = Alias("a1", ty.Of(s));
-  Global(Source{{56, 78}}, "g", ty.Of(a1), ast::StorageClass::kUniform,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    // struct S { x : i32 };
+    // type a1 = S;
+    // var<uniform> g : a1;
+    auto* s = Structure("S", {Member(Source{{12, 34}}, "x", ty.i32())});
+    auto* a1 = Alias("a1", ty.Of(s));
+    Global(Source{{56, 78}}, "g", ty.Of(a1), ast::StorageClass::kUniform,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 }  // namespace
diff --git a/src/tint/resolver/struct_layout_test.cc b/src/tint/resolver/struct_layout_test.cc
index 7c2f450..854e87a 100644
--- a/src/tint/resolver/struct_layout_test.cc
+++ b/src/tint/resolver/struct_layout_test.cc
@@ -18,385 +18,387 @@
 #include "src/tint/resolver/resolver_test_helper.h"
 #include "src/tint/sem/struct.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::resolver {
 namespace {
 
 using ResolverStructLayoutTest = ResolverTest;
 
 TEST_F(ResolverStructLayoutTest, Scalars) {
-  auto* s = Structure("S", {
-                               Member("a", ty.f32()),
-                               Member("b", ty.u32()),
-                               Member("c", ty.i32()),
-                           });
+    auto* s = Structure("S", {
+                                 Member("a", ty.f32()),
+                                 Member("b", ty.u32()),
+                                 Member("c", ty.i32()),
+                             });
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = TypeOf(s)->As<sem::Struct>();
-  ASSERT_NE(sem, nullptr);
-  EXPECT_EQ(sem->Size(), 12u);
-  EXPECT_EQ(sem->SizeNoPadding(), 12u);
-  EXPECT_EQ(sem->Align(), 4u);
-  ASSERT_EQ(sem->Members().size(), 3u);
-  EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
-  EXPECT_EQ(sem->Members()[0]->Align(), 4u);
-  EXPECT_EQ(sem->Members()[0]->Size(), 4u);
-  EXPECT_EQ(sem->Members()[1]->Offset(), 4u);
-  EXPECT_EQ(sem->Members()[1]->Align(), 4u);
-  EXPECT_EQ(sem->Members()[1]->Size(), 4u);
-  EXPECT_EQ(sem->Members()[2]->Offset(), 8u);
-  EXPECT_EQ(sem->Members()[2]->Align(), 4u);
-  EXPECT_EQ(sem->Members()[2]->Size(), 4u);
+    auto* sem = TypeOf(s)->As<sem::Struct>();
+    ASSERT_NE(sem, nullptr);
+    EXPECT_EQ(sem->Size(), 12u);
+    EXPECT_EQ(sem->SizeNoPadding(), 12u);
+    EXPECT_EQ(sem->Align(), 4u);
+    ASSERT_EQ(sem->Members().size(), 3u);
+    EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
+    EXPECT_EQ(sem->Members()[0]->Align(), 4u);
+    EXPECT_EQ(sem->Members()[0]->Size(), 4u);
+    EXPECT_EQ(sem->Members()[1]->Offset(), 4u);
+    EXPECT_EQ(sem->Members()[1]->Align(), 4u);
+    EXPECT_EQ(sem->Members()[1]->Size(), 4u);
+    EXPECT_EQ(sem->Members()[2]->Offset(), 8u);
+    EXPECT_EQ(sem->Members()[2]->Align(), 4u);
+    EXPECT_EQ(sem->Members()[2]->Size(), 4u);
 }
 
 TEST_F(ResolverStructLayoutTest, Alias) {
-  auto* alias_a = Alias("a", ty.f32());
-  auto* alias_b = Alias("b", ty.f32());
+    auto* alias_a = Alias("a", ty.f32());
+    auto* alias_b = Alias("b", ty.f32());
 
-  auto* s = Structure("S", {
-                               Member("a", ty.Of(alias_a)),
-                               Member("b", ty.Of(alias_b)),
-                           });
+    auto* s = Structure("S", {
+                                 Member("a", ty.Of(alias_a)),
+                                 Member("b", ty.Of(alias_b)),
+                             });
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = TypeOf(s)->As<sem::Struct>();
-  ASSERT_NE(sem, nullptr);
-  EXPECT_EQ(sem->Size(), 8u);
-  EXPECT_EQ(sem->SizeNoPadding(), 8u);
-  EXPECT_EQ(sem->Align(), 4u);
-  ASSERT_EQ(sem->Members().size(), 2u);
-  EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
-  EXPECT_EQ(sem->Members()[0]->Align(), 4u);
-  EXPECT_EQ(sem->Members()[0]->Size(), 4u);
-  EXPECT_EQ(sem->Members()[1]->Offset(), 4u);
-  EXPECT_EQ(sem->Members()[1]->Align(), 4u);
-  EXPECT_EQ(sem->Members()[1]->Size(), 4u);
+    auto* sem = TypeOf(s)->As<sem::Struct>();
+    ASSERT_NE(sem, nullptr);
+    EXPECT_EQ(sem->Size(), 8u);
+    EXPECT_EQ(sem->SizeNoPadding(), 8u);
+    EXPECT_EQ(sem->Align(), 4u);
+    ASSERT_EQ(sem->Members().size(), 2u);
+    EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
+    EXPECT_EQ(sem->Members()[0]->Align(), 4u);
+    EXPECT_EQ(sem->Members()[0]->Size(), 4u);
+    EXPECT_EQ(sem->Members()[1]->Offset(), 4u);
+    EXPECT_EQ(sem->Members()[1]->Align(), 4u);
+    EXPECT_EQ(sem->Members()[1]->Size(), 4u);
 }
 
 TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayStaticSize) {
-  auto* s = Structure("S", {
-                               Member("a", ty.array<i32, 3>()),
-                               Member("b", ty.array<f32, 5>()),
-                               Member("c", ty.array<f32, 1>()),
-                           });
+    auto* s = Structure("S", {
+                                 Member("a", ty.array<i32, 3>()),
+                                 Member("b", ty.array<f32, 5>()),
+                                 Member("c", ty.array<f32, 1>()),
+                             });
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = TypeOf(s)->As<sem::Struct>();
-  ASSERT_NE(sem, nullptr);
-  EXPECT_EQ(sem->Size(), 36u);
-  EXPECT_EQ(sem->SizeNoPadding(), 36u);
-  EXPECT_EQ(sem->Align(), 4u);
-  ASSERT_EQ(sem->Members().size(), 3u);
-  EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
-  EXPECT_EQ(sem->Members()[0]->Align(), 4u);
-  EXPECT_EQ(sem->Members()[0]->Size(), 12u);
-  EXPECT_EQ(sem->Members()[1]->Offset(), 12u);
-  EXPECT_EQ(sem->Members()[1]->Align(), 4u);
-  EXPECT_EQ(sem->Members()[1]->Size(), 20u);
-  EXPECT_EQ(sem->Members()[2]->Offset(), 32u);
-  EXPECT_EQ(sem->Members()[2]->Align(), 4u);
-  EXPECT_EQ(sem->Members()[2]->Size(), 4u);
+    auto* sem = TypeOf(s)->As<sem::Struct>();
+    ASSERT_NE(sem, nullptr);
+    EXPECT_EQ(sem->Size(), 36u);
+    EXPECT_EQ(sem->SizeNoPadding(), 36u);
+    EXPECT_EQ(sem->Align(), 4u);
+    ASSERT_EQ(sem->Members().size(), 3u);
+    EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
+    EXPECT_EQ(sem->Members()[0]->Align(), 4u);
+    EXPECT_EQ(sem->Members()[0]->Size(), 12u);
+    EXPECT_EQ(sem->Members()[1]->Offset(), 12u);
+    EXPECT_EQ(sem->Members()[1]->Align(), 4u);
+    EXPECT_EQ(sem->Members()[1]->Size(), 20u);
+    EXPECT_EQ(sem->Members()[2]->Offset(), 32u);
+    EXPECT_EQ(sem->Members()[2]->Align(), 4u);
+    EXPECT_EQ(sem->Members()[2]->Size(), 4u);
 }
 
 TEST_F(ResolverStructLayoutTest, ExplicitStrideArrayStaticSize) {
-  auto* s = Structure("S", {
-                               Member("a", ty.array<i32, 3>(/*stride*/ 8)),
-                               Member("b", ty.array<f32, 5>(/*stride*/ 16)),
-                               Member("c", ty.array<f32, 1>(/*stride*/ 32)),
-                           });
+    auto* s = Structure("S", {
+                                 Member("a", ty.array<i32, 3>(/*stride*/ 8)),
+                                 Member("b", ty.array<f32, 5>(/*stride*/ 16)),
+                                 Member("c", ty.array<f32, 1>(/*stride*/ 32)),
+                             });
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = TypeOf(s)->As<sem::Struct>();
-  ASSERT_NE(sem, nullptr);
-  EXPECT_EQ(sem->Size(), 136u);
-  EXPECT_EQ(sem->SizeNoPadding(), 136u);
-  EXPECT_EQ(sem->Align(), 4u);
-  ASSERT_EQ(sem->Members().size(), 3u);
-  EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
-  EXPECT_EQ(sem->Members()[0]->Align(), 4u);
-  EXPECT_EQ(sem->Members()[0]->Size(), 24u);
-  EXPECT_EQ(sem->Members()[1]->Offset(), 24u);
-  EXPECT_EQ(sem->Members()[1]->Align(), 4u);
-  EXPECT_EQ(sem->Members()[1]->Size(), 80u);
-  EXPECT_EQ(sem->Members()[2]->Offset(), 104u);
-  EXPECT_EQ(sem->Members()[2]->Align(), 4u);
-  EXPECT_EQ(sem->Members()[2]->Size(), 32u);
+    auto* sem = TypeOf(s)->As<sem::Struct>();
+    ASSERT_NE(sem, nullptr);
+    EXPECT_EQ(sem->Size(), 136u);
+    EXPECT_EQ(sem->SizeNoPadding(), 136u);
+    EXPECT_EQ(sem->Align(), 4u);
+    ASSERT_EQ(sem->Members().size(), 3u);
+    EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
+    EXPECT_EQ(sem->Members()[0]->Align(), 4u);
+    EXPECT_EQ(sem->Members()[0]->Size(), 24u);
+    EXPECT_EQ(sem->Members()[1]->Offset(), 24u);
+    EXPECT_EQ(sem->Members()[1]->Align(), 4u);
+    EXPECT_EQ(sem->Members()[1]->Size(), 80u);
+    EXPECT_EQ(sem->Members()[2]->Offset(), 104u);
+    EXPECT_EQ(sem->Members()[2]->Align(), 4u);
+    EXPECT_EQ(sem->Members()[2]->Size(), 32u);
 }
 
 TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayRuntimeSized) {
-  auto* s = Structure("S", {
-                               Member("c", ty.array<f32>()),
-                           });
+    auto* s = Structure("S", {
+                                 Member("c", ty.array<f32>()),
+                             });
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = TypeOf(s)->As<sem::Struct>();
-  ASSERT_NE(sem, nullptr);
-  EXPECT_EQ(sem->Size(), 4u);
-  EXPECT_EQ(sem->SizeNoPadding(), 4u);
-  EXPECT_EQ(sem->Align(), 4u);
-  ASSERT_EQ(sem->Members().size(), 1u);
-  EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
-  EXPECT_EQ(sem->Members()[0]->Align(), 4u);
-  EXPECT_EQ(sem->Members()[0]->Size(), 4u);
+    auto* sem = TypeOf(s)->As<sem::Struct>();
+    ASSERT_NE(sem, nullptr);
+    EXPECT_EQ(sem->Size(), 4u);
+    EXPECT_EQ(sem->SizeNoPadding(), 4u);
+    EXPECT_EQ(sem->Align(), 4u);
+    ASSERT_EQ(sem->Members().size(), 1u);
+    EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
+    EXPECT_EQ(sem->Members()[0]->Align(), 4u);
+    EXPECT_EQ(sem->Members()[0]->Size(), 4u);
 }
 
 TEST_F(ResolverStructLayoutTest, ExplicitStrideArrayRuntimeSized) {
-  auto* s = Structure("S", {
-                               Member("c", ty.array<f32>(/*stride*/ 32)),
-                           });
+    auto* s = Structure("S", {
+                                 Member("c", ty.array<f32>(/*stride*/ 32)),
+                             });
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = TypeOf(s)->As<sem::Struct>();
-  ASSERT_NE(sem, nullptr);
-  EXPECT_EQ(sem->Size(), 32u);
-  EXPECT_EQ(sem->SizeNoPadding(), 32u);
-  EXPECT_EQ(sem->Align(), 4u);
-  ASSERT_EQ(sem->Members().size(), 1u);
-  EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
-  EXPECT_EQ(sem->Members()[0]->Align(), 4u);
-  EXPECT_EQ(sem->Members()[0]->Size(), 32u);
+    auto* sem = TypeOf(s)->As<sem::Struct>();
+    ASSERT_NE(sem, nullptr);
+    EXPECT_EQ(sem->Size(), 32u);
+    EXPECT_EQ(sem->SizeNoPadding(), 32u);
+    EXPECT_EQ(sem->Align(), 4u);
+    ASSERT_EQ(sem->Members().size(), 1u);
+    EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
+    EXPECT_EQ(sem->Members()[0]->Align(), 4u);
+    EXPECT_EQ(sem->Members()[0]->Size(), 32u);
 }
 
 TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayOfExplicitStrideArray) {
-  auto* inner = ty.array<i32, 2>(/*stride*/ 16);  // size: 32
-  auto* outer = ty.array(inner, 12);              // size: 12 * 32
-  auto* s = Structure("S", {
-                               Member("c", outer),
-                           });
+    auto* inner = ty.array<i32, 2>(/*stride*/ 16);  // size: 32
+    auto* outer = ty.array(inner, 12_u);            // size: 12 * 32
+    auto* s = Structure("S", {
+                                 Member("c", outer),
+                             });
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = TypeOf(s)->As<sem::Struct>();
-  ASSERT_NE(sem, nullptr);
-  EXPECT_EQ(sem->Size(), 384u);
-  EXPECT_EQ(sem->SizeNoPadding(), 384u);
-  EXPECT_EQ(sem->Align(), 4u);
-  ASSERT_EQ(sem->Members().size(), 1u);
-  EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
-  EXPECT_EQ(sem->Members()[0]->Align(), 4u);
-  EXPECT_EQ(sem->Members()[0]->Size(), 384u);
+    auto* sem = TypeOf(s)->As<sem::Struct>();
+    ASSERT_NE(sem, nullptr);
+    EXPECT_EQ(sem->Size(), 384u);
+    EXPECT_EQ(sem->SizeNoPadding(), 384u);
+    EXPECT_EQ(sem->Align(), 4u);
+    ASSERT_EQ(sem->Members().size(), 1u);
+    EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
+    EXPECT_EQ(sem->Members()[0]->Align(), 4u);
+    EXPECT_EQ(sem->Members()[0]->Size(), 384u);
 }
 
 TEST_F(ResolverStructLayoutTest, ImplicitStrideArrayOfStructure) {
-  auto* inner = Structure("Inner", {
-                                       Member("a", ty.vec2<i32>()),
-                                       Member("b", ty.vec3<i32>()),
-                                       Member("c", ty.vec4<i32>()),
-                                   });       // size: 48
-  auto* outer = ty.array(ty.Of(inner), 12);  // size: 12 * 48
-  auto* s = Structure("S", {
-                               Member("c", outer),
-                           });
+    auto* inner = Structure("Inner", {
+                                         Member("a", ty.vec2<i32>()),
+                                         Member("b", ty.vec3<i32>()),
+                                         Member("c", ty.vec4<i32>()),
+                                     });         // size: 48
+    auto* outer = ty.array(ty.Of(inner), 12_u);  // size: 12 * 48
+    auto* s = Structure("S", {
+                                 Member("c", outer),
+                             });
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = TypeOf(s)->As<sem::Struct>();
-  ASSERT_NE(sem, nullptr);
-  EXPECT_EQ(sem->Size(), 576u);
-  EXPECT_EQ(sem->SizeNoPadding(), 576u);
-  EXPECT_EQ(sem->Align(), 16u);
-  ASSERT_EQ(sem->Members().size(), 1u);
-  EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
-  EXPECT_EQ(sem->Members()[0]->Align(), 16u);
-  EXPECT_EQ(sem->Members()[0]->Size(), 576u);
+    auto* sem = TypeOf(s)->As<sem::Struct>();
+    ASSERT_NE(sem, nullptr);
+    EXPECT_EQ(sem->Size(), 576u);
+    EXPECT_EQ(sem->SizeNoPadding(), 576u);
+    EXPECT_EQ(sem->Align(), 16u);
+    ASSERT_EQ(sem->Members().size(), 1u);
+    EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
+    EXPECT_EQ(sem->Members()[0]->Align(), 16u);
+    EXPECT_EQ(sem->Members()[0]->Size(), 576u);
 }
 
 TEST_F(ResolverStructLayoutTest, Vector) {
-  auto* s = Structure("S", {
-                               Member("a", ty.vec2<i32>()),
-                               Member("b", ty.vec3<i32>()),
-                               Member("c", ty.vec4<i32>()),
-                           });
+    auto* s = Structure("S", {
+                                 Member("a", ty.vec2<i32>()),
+                                 Member("b", ty.vec3<i32>()),
+                                 Member("c", ty.vec4<i32>()),
+                             });
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = TypeOf(s)->As<sem::Struct>();
-  ASSERT_NE(sem, nullptr);
-  EXPECT_EQ(sem->Size(), 48u);
-  EXPECT_EQ(sem->SizeNoPadding(), 48u);
-  EXPECT_EQ(sem->Align(), 16u);
-  ASSERT_EQ(sem->Members().size(), 3u);
-  EXPECT_EQ(sem->Members()[0]->Offset(), 0u);  // vec2
-  EXPECT_EQ(sem->Members()[0]->Align(), 8u);
-  EXPECT_EQ(sem->Members()[0]->Size(), 8u);
-  EXPECT_EQ(sem->Members()[1]->Offset(), 16u);  // vec3
-  EXPECT_EQ(sem->Members()[1]->Align(), 16u);
-  EXPECT_EQ(sem->Members()[1]->Size(), 12u);
-  EXPECT_EQ(sem->Members()[2]->Offset(), 32u);  // vec4
-  EXPECT_EQ(sem->Members()[2]->Align(), 16u);
-  EXPECT_EQ(sem->Members()[2]->Size(), 16u);
+    auto* sem = TypeOf(s)->As<sem::Struct>();
+    ASSERT_NE(sem, nullptr);
+    EXPECT_EQ(sem->Size(), 48u);
+    EXPECT_EQ(sem->SizeNoPadding(), 48u);
+    EXPECT_EQ(sem->Align(), 16u);
+    ASSERT_EQ(sem->Members().size(), 3u);
+    EXPECT_EQ(sem->Members()[0]->Offset(), 0u);  // vec2
+    EXPECT_EQ(sem->Members()[0]->Align(), 8u);
+    EXPECT_EQ(sem->Members()[0]->Size(), 8u);
+    EXPECT_EQ(sem->Members()[1]->Offset(), 16u);  // vec3
+    EXPECT_EQ(sem->Members()[1]->Align(), 16u);
+    EXPECT_EQ(sem->Members()[1]->Size(), 12u);
+    EXPECT_EQ(sem->Members()[2]->Offset(), 32u);  // vec4
+    EXPECT_EQ(sem->Members()[2]->Align(), 16u);
+    EXPECT_EQ(sem->Members()[2]->Size(), 16u);
 }
 
 TEST_F(ResolverStructLayoutTest, Matrix) {
-  auto* s = Structure("S", {
-                               Member("a", ty.mat2x2<f32>()),
-                               Member("b", ty.mat2x3<f32>()),
-                               Member("c", ty.mat2x4<f32>()),
-                               Member("d", ty.mat3x2<f32>()),
-                               Member("e", ty.mat3x3<f32>()),
-                               Member("f", ty.mat3x4<f32>()),
-                               Member("g", ty.mat4x2<f32>()),
-                               Member("h", ty.mat4x3<f32>()),
-                               Member("i", ty.mat4x4<f32>()),
-                           });
+    auto* s = Structure("S", {
+                                 Member("a", ty.mat2x2<f32>()),
+                                 Member("b", ty.mat2x3<f32>()),
+                                 Member("c", ty.mat2x4<f32>()),
+                                 Member("d", ty.mat3x2<f32>()),
+                                 Member("e", ty.mat3x3<f32>()),
+                                 Member("f", ty.mat3x4<f32>()),
+                                 Member("g", ty.mat4x2<f32>()),
+                                 Member("h", ty.mat4x3<f32>()),
+                                 Member("i", ty.mat4x4<f32>()),
+                             });
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = TypeOf(s)->As<sem::Struct>();
-  ASSERT_NE(sem, nullptr);
-  EXPECT_EQ(sem->Size(), 368u);
-  EXPECT_EQ(sem->SizeNoPadding(), 368u);
-  EXPECT_EQ(sem->Align(), 16u);
-  ASSERT_EQ(sem->Members().size(), 9u);
-  EXPECT_EQ(sem->Members()[0]->Offset(), 0u);  // mat2x2
-  EXPECT_EQ(sem->Members()[0]->Align(), 8u);
-  EXPECT_EQ(sem->Members()[0]->Size(), 16u);
-  EXPECT_EQ(sem->Members()[1]->Offset(), 16u);  // mat2x3
-  EXPECT_EQ(sem->Members()[1]->Align(), 16u);
-  EXPECT_EQ(sem->Members()[1]->Size(), 32u);
-  EXPECT_EQ(sem->Members()[2]->Offset(), 48u);  // mat2x4
-  EXPECT_EQ(sem->Members()[2]->Align(), 16u);
-  EXPECT_EQ(sem->Members()[2]->Size(), 32u);
-  EXPECT_EQ(sem->Members()[3]->Offset(), 80u);  // mat3x2
-  EXPECT_EQ(sem->Members()[3]->Align(), 8u);
-  EXPECT_EQ(sem->Members()[3]->Size(), 24u);
-  EXPECT_EQ(sem->Members()[4]->Offset(), 112u);  // mat3x3
-  EXPECT_EQ(sem->Members()[4]->Align(), 16u);
-  EXPECT_EQ(sem->Members()[4]->Size(), 48u);
-  EXPECT_EQ(sem->Members()[5]->Offset(), 160u);  // mat3x4
-  EXPECT_EQ(sem->Members()[5]->Align(), 16u);
-  EXPECT_EQ(sem->Members()[5]->Size(), 48u);
-  EXPECT_EQ(sem->Members()[6]->Offset(), 208u);  // mat4x2
-  EXPECT_EQ(sem->Members()[6]->Align(), 8u);
-  EXPECT_EQ(sem->Members()[6]->Size(), 32u);
-  EXPECT_EQ(sem->Members()[7]->Offset(), 240u);  // mat4x3
-  EXPECT_EQ(sem->Members()[7]->Align(), 16u);
-  EXPECT_EQ(sem->Members()[7]->Size(), 64u);
-  EXPECT_EQ(sem->Members()[8]->Offset(), 304u);  // mat4x4
-  EXPECT_EQ(sem->Members()[8]->Align(), 16u);
-  EXPECT_EQ(sem->Members()[8]->Size(), 64u);
+    auto* sem = TypeOf(s)->As<sem::Struct>();
+    ASSERT_NE(sem, nullptr);
+    EXPECT_EQ(sem->Size(), 368u);
+    EXPECT_EQ(sem->SizeNoPadding(), 368u);
+    EXPECT_EQ(sem->Align(), 16u);
+    ASSERT_EQ(sem->Members().size(), 9u);
+    EXPECT_EQ(sem->Members()[0]->Offset(), 0u);  // mat2x2
+    EXPECT_EQ(sem->Members()[0]->Align(), 8u);
+    EXPECT_EQ(sem->Members()[0]->Size(), 16u);
+    EXPECT_EQ(sem->Members()[1]->Offset(), 16u);  // mat2x3
+    EXPECT_EQ(sem->Members()[1]->Align(), 16u);
+    EXPECT_EQ(sem->Members()[1]->Size(), 32u);
+    EXPECT_EQ(sem->Members()[2]->Offset(), 48u);  // mat2x4
+    EXPECT_EQ(sem->Members()[2]->Align(), 16u);
+    EXPECT_EQ(sem->Members()[2]->Size(), 32u);
+    EXPECT_EQ(sem->Members()[3]->Offset(), 80u);  // mat3x2
+    EXPECT_EQ(sem->Members()[3]->Align(), 8u);
+    EXPECT_EQ(sem->Members()[3]->Size(), 24u);
+    EXPECT_EQ(sem->Members()[4]->Offset(), 112u);  // mat3x3
+    EXPECT_EQ(sem->Members()[4]->Align(), 16u);
+    EXPECT_EQ(sem->Members()[4]->Size(), 48u);
+    EXPECT_EQ(sem->Members()[5]->Offset(), 160u);  // mat3x4
+    EXPECT_EQ(sem->Members()[5]->Align(), 16u);
+    EXPECT_EQ(sem->Members()[5]->Size(), 48u);
+    EXPECT_EQ(sem->Members()[6]->Offset(), 208u);  // mat4x2
+    EXPECT_EQ(sem->Members()[6]->Align(), 8u);
+    EXPECT_EQ(sem->Members()[6]->Size(), 32u);
+    EXPECT_EQ(sem->Members()[7]->Offset(), 240u);  // mat4x3
+    EXPECT_EQ(sem->Members()[7]->Align(), 16u);
+    EXPECT_EQ(sem->Members()[7]->Size(), 64u);
+    EXPECT_EQ(sem->Members()[8]->Offset(), 304u);  // mat4x4
+    EXPECT_EQ(sem->Members()[8]->Align(), 16u);
+    EXPECT_EQ(sem->Members()[8]->Size(), 64u);
 }
 
 TEST_F(ResolverStructLayoutTest, NestedStruct) {
-  auto* inner = Structure("Inner", {
-                                       Member("a", ty.mat3x3<f32>()),
-                                   });
-  auto* s = Structure("S", {
-                               Member("a", ty.i32()),
-                               Member("b", ty.Of(inner)),
-                               Member("c", ty.i32()),
-                           });
+    auto* inner = Structure("Inner", {
+                                         Member("a", ty.mat3x3<f32>()),
+                                     });
+    auto* s = Structure("S", {
+                                 Member("a", ty.i32()),
+                                 Member("b", ty.Of(inner)),
+                                 Member("c", ty.i32()),
+                             });
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = TypeOf(s)->As<sem::Struct>();
-  ASSERT_NE(sem, nullptr);
-  EXPECT_EQ(sem->Size(), 80u);
-  EXPECT_EQ(sem->SizeNoPadding(), 68u);
-  EXPECT_EQ(sem->Align(), 16u);
-  ASSERT_EQ(sem->Members().size(), 3u);
-  EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
-  EXPECT_EQ(sem->Members()[0]->Align(), 4u);
-  EXPECT_EQ(sem->Members()[0]->Size(), 4u);
-  EXPECT_EQ(sem->Members()[1]->Offset(), 16u);
-  EXPECT_EQ(sem->Members()[1]->Align(), 16u);
-  EXPECT_EQ(sem->Members()[1]->Size(), 48u);
-  EXPECT_EQ(sem->Members()[2]->Offset(), 64u);
-  EXPECT_EQ(sem->Members()[2]->Align(), 4u);
-  EXPECT_EQ(sem->Members()[2]->Size(), 4u);
+    auto* sem = TypeOf(s)->As<sem::Struct>();
+    ASSERT_NE(sem, nullptr);
+    EXPECT_EQ(sem->Size(), 80u);
+    EXPECT_EQ(sem->SizeNoPadding(), 68u);
+    EXPECT_EQ(sem->Align(), 16u);
+    ASSERT_EQ(sem->Members().size(), 3u);
+    EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
+    EXPECT_EQ(sem->Members()[0]->Align(), 4u);
+    EXPECT_EQ(sem->Members()[0]->Size(), 4u);
+    EXPECT_EQ(sem->Members()[1]->Offset(), 16u);
+    EXPECT_EQ(sem->Members()[1]->Align(), 16u);
+    EXPECT_EQ(sem->Members()[1]->Size(), 48u);
+    EXPECT_EQ(sem->Members()[2]->Offset(), 64u);
+    EXPECT_EQ(sem->Members()[2]->Align(), 4u);
+    EXPECT_EQ(sem->Members()[2]->Size(), 4u);
 }
 
 TEST_F(ResolverStructLayoutTest, SizeAttributes) {
-  auto* inner = Structure("Inner", {
-                                       Member("a", ty.f32(), {MemberSize(8)}),
-                                       Member("b", ty.f32(), {MemberSize(16)}),
-                                       Member("c", ty.f32(), {MemberSize(8)}),
-                                   });
-  auto* s = Structure("S", {
-                               Member("a", ty.f32(), {MemberSize(4)}),
-                               Member("b", ty.u32(), {MemberSize(8)}),
-                               Member("c", ty.Of(inner)),
-                               Member("d", ty.i32(), {MemberSize(32)}),
-                           });
+    auto* inner = Structure("Inner", {
+                                         Member("a", ty.f32(), {MemberSize(8)}),
+                                         Member("b", ty.f32(), {MemberSize(16)}),
+                                         Member("c", ty.f32(), {MemberSize(8)}),
+                                     });
+    auto* s = Structure("S", {
+                                 Member("a", ty.f32(), {MemberSize(4)}),
+                                 Member("b", ty.u32(), {MemberSize(8)}),
+                                 Member("c", ty.Of(inner)),
+                                 Member("d", ty.i32(), {MemberSize(32)}),
+                             });
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = TypeOf(s)->As<sem::Struct>();
-  ASSERT_NE(sem, nullptr);
-  EXPECT_EQ(sem->Size(), 76u);
-  EXPECT_EQ(sem->SizeNoPadding(), 76u);
-  EXPECT_EQ(sem->Align(), 4u);
-  ASSERT_EQ(sem->Members().size(), 4u);
-  EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
-  EXPECT_EQ(sem->Members()[0]->Align(), 4u);
-  EXPECT_EQ(sem->Members()[0]->Size(), 4u);
-  EXPECT_EQ(sem->Members()[1]->Offset(), 4u);
-  EXPECT_EQ(sem->Members()[1]->Align(), 4u);
-  EXPECT_EQ(sem->Members()[1]->Size(), 8u);
-  EXPECT_EQ(sem->Members()[2]->Offset(), 12u);
-  EXPECT_EQ(sem->Members()[2]->Align(), 4u);
-  EXPECT_EQ(sem->Members()[2]->Size(), 32u);
-  EXPECT_EQ(sem->Members()[3]->Offset(), 44u);
-  EXPECT_EQ(sem->Members()[3]->Align(), 4u);
-  EXPECT_EQ(sem->Members()[3]->Size(), 32u);
+    auto* sem = TypeOf(s)->As<sem::Struct>();
+    ASSERT_NE(sem, nullptr);
+    EXPECT_EQ(sem->Size(), 76u);
+    EXPECT_EQ(sem->SizeNoPadding(), 76u);
+    EXPECT_EQ(sem->Align(), 4u);
+    ASSERT_EQ(sem->Members().size(), 4u);
+    EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
+    EXPECT_EQ(sem->Members()[0]->Align(), 4u);
+    EXPECT_EQ(sem->Members()[0]->Size(), 4u);
+    EXPECT_EQ(sem->Members()[1]->Offset(), 4u);
+    EXPECT_EQ(sem->Members()[1]->Align(), 4u);
+    EXPECT_EQ(sem->Members()[1]->Size(), 8u);
+    EXPECT_EQ(sem->Members()[2]->Offset(), 12u);
+    EXPECT_EQ(sem->Members()[2]->Align(), 4u);
+    EXPECT_EQ(sem->Members()[2]->Size(), 32u);
+    EXPECT_EQ(sem->Members()[3]->Offset(), 44u);
+    EXPECT_EQ(sem->Members()[3]->Align(), 4u);
+    EXPECT_EQ(sem->Members()[3]->Size(), 32u);
 }
 
 TEST_F(ResolverStructLayoutTest, AlignAttributes) {
-  auto* inner = Structure("Inner", {
-                                       Member("a", ty.f32(), {MemberAlign(8)}),
-                                       Member("b", ty.f32(), {MemberAlign(16)}),
-                                       Member("c", ty.f32(), {MemberAlign(4)}),
-                                   });
-  auto* s = Structure("S", {
-                               Member("a", ty.f32(), {MemberAlign(4)}),
-                               Member("b", ty.u32(), {MemberAlign(8)}),
-                               Member("c", ty.Of(inner)),
-                               Member("d", ty.i32(), {MemberAlign(32)}),
-                           });
+    auto* inner = Structure("Inner", {
+                                         Member("a", ty.f32(), {MemberAlign(8)}),
+                                         Member("b", ty.f32(), {MemberAlign(16)}),
+                                         Member("c", ty.f32(), {MemberAlign(4)}),
+                                     });
+    auto* s = Structure("S", {
+                                 Member("a", ty.f32(), {MemberAlign(4)}),
+                                 Member("b", ty.u32(), {MemberAlign(8)}),
+                                 Member("c", ty.Of(inner)),
+                                 Member("d", ty.i32(), {MemberAlign(32)}),
+                             });
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = TypeOf(s)->As<sem::Struct>();
-  ASSERT_NE(sem, nullptr);
-  EXPECT_EQ(sem->Size(), 96u);
-  EXPECT_EQ(sem->SizeNoPadding(), 68u);
-  EXPECT_EQ(sem->Align(), 32u);
-  ASSERT_EQ(sem->Members().size(), 4u);
-  EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
-  EXPECT_EQ(sem->Members()[0]->Align(), 4u);
-  EXPECT_EQ(sem->Members()[0]->Size(), 4u);
-  EXPECT_EQ(sem->Members()[1]->Offset(), 8u);
-  EXPECT_EQ(sem->Members()[1]->Align(), 8u);
-  EXPECT_EQ(sem->Members()[1]->Size(), 4u);
-  EXPECT_EQ(sem->Members()[2]->Offset(), 16u);
-  EXPECT_EQ(sem->Members()[2]->Align(), 16u);
-  EXPECT_EQ(sem->Members()[2]->Size(), 32u);
-  EXPECT_EQ(sem->Members()[3]->Offset(), 64u);
-  EXPECT_EQ(sem->Members()[3]->Align(), 32u);
-  EXPECT_EQ(sem->Members()[3]->Size(), 4u);
+    auto* sem = TypeOf(s)->As<sem::Struct>();
+    ASSERT_NE(sem, nullptr);
+    EXPECT_EQ(sem->Size(), 96u);
+    EXPECT_EQ(sem->SizeNoPadding(), 68u);
+    EXPECT_EQ(sem->Align(), 32u);
+    ASSERT_EQ(sem->Members().size(), 4u);
+    EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
+    EXPECT_EQ(sem->Members()[0]->Align(), 4u);
+    EXPECT_EQ(sem->Members()[0]->Size(), 4u);
+    EXPECT_EQ(sem->Members()[1]->Offset(), 8u);
+    EXPECT_EQ(sem->Members()[1]->Align(), 8u);
+    EXPECT_EQ(sem->Members()[1]->Size(), 4u);
+    EXPECT_EQ(sem->Members()[2]->Offset(), 16u);
+    EXPECT_EQ(sem->Members()[2]->Align(), 16u);
+    EXPECT_EQ(sem->Members()[2]->Size(), 32u);
+    EXPECT_EQ(sem->Members()[3]->Offset(), 64u);
+    EXPECT_EQ(sem->Members()[3]->Align(), 32u);
+    EXPECT_EQ(sem->Members()[3]->Size(), 4u);
 }
 
 TEST_F(ResolverStructLayoutTest, StructWithLotsOfPadding) {
-  auto* s = Structure("S", {
-                               Member("a", ty.i32(), {MemberAlign(1024)}),
-                           });
+    auto* s = Structure("S", {
+                                 Member("a", ty.i32(), {MemberAlign(1024)}),
+                             });
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = TypeOf(s)->As<sem::Struct>();
-  ASSERT_NE(sem, nullptr);
-  EXPECT_EQ(sem->Size(), 1024u);
-  EXPECT_EQ(sem->SizeNoPadding(), 4u);
-  EXPECT_EQ(sem->Align(), 1024u);
-  ASSERT_EQ(sem->Members().size(), 1u);
-  EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
-  EXPECT_EQ(sem->Members()[0]->Align(), 1024u);
-  EXPECT_EQ(sem->Members()[0]->Size(), 4u);
+    auto* sem = TypeOf(s)->As<sem::Struct>();
+    ASSERT_NE(sem, nullptr);
+    EXPECT_EQ(sem->Size(), 1024u);
+    EXPECT_EQ(sem->SizeNoPadding(), 4u);
+    EXPECT_EQ(sem->Align(), 1024u);
+    ASSERT_EQ(sem->Members().size(), 1u);
+    EXPECT_EQ(sem->Members()[0]->Offset(), 0u);
+    EXPECT_EQ(sem->Members()[0]->Align(), 1024u);
+    EXPECT_EQ(sem->Members()[0]->Size(), 4u);
 }
 
 }  // namespace
diff --git a/src/tint/resolver/struct_pipeline_stage_use_test.cc b/src/tint/resolver/struct_pipeline_stage_use_test.cc
index b843cea..6b9ede9 100644
--- a/src/tint/resolver/struct_pipeline_stage_use_test.cc
+++ b/src/tint/resolver/struct_pipeline_stage_use_test.cc
@@ -21,168 +21,163 @@
 
 using ::testing::UnorderedElementsAre;
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::resolver {
 namespace {
 
 using ResolverPipelineStageUseTest = ResolverTest;
 
 TEST_F(ResolverPipelineStageUseTest, UnusedStruct) {
-  auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
+    auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = TypeOf(s)->As<sem::Struct>();
-  ASSERT_NE(sem, nullptr);
-  EXPECT_TRUE(sem->PipelineStageUses().empty());
+    auto* sem = TypeOf(s)->As<sem::Struct>();
+    ASSERT_NE(sem, nullptr);
+    EXPECT_TRUE(sem->PipelineStageUses().empty());
 }
 
 TEST_F(ResolverPipelineStageUseTest, StructUsedAsNonEntryPointParam) {
-  auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
+    auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
 
-  Func("foo", {Param("param", ty.Of(s))}, ty.void_(), {}, {});
+    Func("foo", {Param("param", ty.Of(s))}, ty.void_(), {}, {});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = TypeOf(s)->As<sem::Struct>();
-  ASSERT_NE(sem, nullptr);
-  EXPECT_TRUE(sem->PipelineStageUses().empty());
+    auto* sem = TypeOf(s)->As<sem::Struct>();
+    ASSERT_NE(sem, nullptr);
+    EXPECT_TRUE(sem->PipelineStageUses().empty());
 }
 
 TEST_F(ResolverPipelineStageUseTest, StructUsedAsNonEntryPointReturnType) {
-  auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
+    auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
 
-  Func("foo", {}, ty.Of(s), {Return(Construct(ty.Of(s), Expr(0.f)))}, {});
+    Func("foo", {}, ty.Of(s), {Return(Construct(ty.Of(s), Expr(0.f)))}, {});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = TypeOf(s)->As<sem::Struct>();
-  ASSERT_NE(sem, nullptr);
-  EXPECT_TRUE(sem->PipelineStageUses().empty());
+    auto* sem = TypeOf(s)->As<sem::Struct>();
+    ASSERT_NE(sem, nullptr);
+    EXPECT_TRUE(sem->PipelineStageUses().empty());
 }
 
 TEST_F(ResolverPipelineStageUseTest, StructUsedAsVertexShaderParam) {
-  auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
+    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)});
+    Func("main", {Param("param", ty.Of(s))}, ty.vec4<f32>(), {Return(Construct(ty.vec4<f32>()))},
+         {Stage(ast::PipelineStage::kVertex)}, {Builtin(ast::Builtin::kPosition)});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = TypeOf(s)->As<sem::Struct>();
-  ASSERT_NE(sem, nullptr);
-  EXPECT_THAT(sem->PipelineStageUses(),
-              UnorderedElementsAre(sem::PipelineStageUsage::kVertexInput));
+    auto* sem = TypeOf(s)->As<sem::Struct>();
+    ASSERT_NE(sem, nullptr);
+    EXPECT_THAT(sem->PipelineStageUses(),
+                UnorderedElementsAre(sem::PipelineStageUsage::kVertexInput));
 }
 
 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::Builtin::kPosition)})});
 
-  Func("main", {}, ty.Of(s), {Return(Construct(ty.Of(s)))},
-       {Stage(ast::PipelineStage::kVertex)});
+    Func("main", {}, ty.Of(s), {Return(Construct(ty.Of(s)))}, {Stage(ast::PipelineStage::kVertex)});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = TypeOf(s)->As<sem::Struct>();
-  ASSERT_NE(sem, nullptr);
-  EXPECT_THAT(sem->PipelineStageUses(),
-              UnorderedElementsAre(sem::PipelineStageUsage::kVertexOutput));
+    auto* sem = TypeOf(s)->As<sem::Struct>();
+    ASSERT_NE(sem, nullptr);
+    EXPECT_THAT(sem->PipelineStageUses(),
+                UnorderedElementsAre(sem::PipelineStageUsage::kVertexOutput));
 }
 
 TEST_F(ResolverPipelineStageUseTest, StructUsedAsFragmentShaderParam) {
-  auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
+    auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
 
-  Func("main", {Param("param", ty.Of(s))}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kFragment)});
+    Func("main", {Param("param", ty.Of(s))}, ty.void_(), {},
+         {Stage(ast::PipelineStage::kFragment)});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = TypeOf(s)->As<sem::Struct>();
-  ASSERT_NE(sem, nullptr);
-  EXPECT_THAT(sem->PipelineStageUses(),
-              UnorderedElementsAre(sem::PipelineStageUsage::kFragmentInput));
+    auto* sem = TypeOf(s)->As<sem::Struct>();
+    ASSERT_NE(sem, nullptr);
+    EXPECT_THAT(sem->PipelineStageUses(),
+                UnorderedElementsAre(sem::PipelineStageUsage::kFragmentInput));
 }
 
 TEST_F(ResolverPipelineStageUseTest, StructUsedAsFragmentShaderReturnType) {
-  auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
+    auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
 
-  Func("main", {}, ty.Of(s), {Return(Construct(ty.Of(s), Expr(0.f)))},
-       {Stage(ast::PipelineStage::kFragment)});
+    Func("main", {}, ty.Of(s), {Return(Construct(ty.Of(s), Expr(0.f)))},
+         {Stage(ast::PipelineStage::kFragment)});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = TypeOf(s)->As<sem::Struct>();
-  ASSERT_NE(sem, nullptr);
-  EXPECT_THAT(sem->PipelineStageUses(),
-              UnorderedElementsAre(sem::PipelineStageUsage::kFragmentOutput));
+    auto* sem = TypeOf(s)->As<sem::Struct>();
+    ASSERT_NE(sem, nullptr);
+    EXPECT_THAT(sem->PipelineStageUses(),
+                UnorderedElementsAre(sem::PipelineStageUsage::kFragmentOutput));
 }
 
 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::Builtin::kLocalInvocationIndex)})});
 
-  Func("main", {Param("param", ty.Of(s))}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
+    Func("main", {Param("param", ty.Of(s))}, ty.void_(), {},
+         {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = TypeOf(s)->As<sem::Struct>();
-  ASSERT_NE(sem, nullptr);
-  EXPECT_THAT(sem->PipelineStageUses(),
-              UnorderedElementsAre(sem::PipelineStageUsage::kComputeInput));
+    auto* sem = TypeOf(s)->As<sem::Struct>();
+    ASSERT_NE(sem, nullptr);
+    EXPECT_THAT(sem->PipelineStageUses(),
+                UnorderedElementsAre(sem::PipelineStageUsage::kComputeInput));
 }
 
 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::Builtin::kPosition)})});
 
-  Func("vert_main", {}, ty.Of(s), {Return(Construct(ty.Of(s)))},
-       {Stage(ast::PipelineStage::kVertex)});
+    Func("vert_main", {}, ty.Of(s), {Return(Construct(ty.Of(s)))},
+         {Stage(ast::PipelineStage::kVertex)});
 
-  Func("frag_main", {Param("param", ty.Of(s))}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kFragment)});
+    Func("frag_main", {Param("param", ty.Of(s))}, ty.void_(), {},
+         {Stage(ast::PipelineStage::kFragment)});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = TypeOf(s)->As<sem::Struct>();
-  ASSERT_NE(sem, nullptr);
-  EXPECT_THAT(sem->PipelineStageUses(),
-              UnorderedElementsAre(sem::PipelineStageUsage::kVertexOutput,
-                                   sem::PipelineStageUsage::kFragmentInput));
+    auto* sem = TypeOf(s)->As<sem::Struct>();
+    ASSERT_NE(sem, nullptr);
+    EXPECT_THAT(sem->PipelineStageUses(),
+                UnorderedElementsAre(sem::PipelineStageUsage::kVertexOutput,
+                                     sem::PipelineStageUsage::kFragmentInput));
 }
 
 TEST_F(ResolverPipelineStageUseTest, StructUsedAsShaderParamViaAlias) {
-  auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
-  auto* s_alias = Alias("S_alias", ty.Of(s));
+    auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
+    auto* s_alias = Alias("S_alias", ty.Of(s));
 
-  Func("main", {Param("param", ty.Of(s_alias))}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kFragment)});
+    Func("main", {Param("param", ty.Of(s_alias))}, ty.void_(), {},
+         {Stage(ast::PipelineStage::kFragment)});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = TypeOf(s)->As<sem::Struct>();
-  ASSERT_NE(sem, nullptr);
-  EXPECT_THAT(sem->PipelineStageUses(),
-              UnorderedElementsAre(sem::PipelineStageUsage::kFragmentInput));
+    auto* sem = TypeOf(s)->As<sem::Struct>();
+    ASSERT_NE(sem, nullptr);
+    EXPECT_THAT(sem->PipelineStageUses(),
+                UnorderedElementsAre(sem::PipelineStageUsage::kFragmentInput));
 }
 
 TEST_F(ResolverPipelineStageUseTest, StructUsedAsShaderReturnTypeViaAlias) {
-  auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
-  auto* s_alias = Alias("S_alias", ty.Of(s));
+    auto* s = Structure("S", {Member("a", ty.f32(), {Location(0)})});
+    auto* s_alias = Alias("S_alias", ty.Of(s));
 
-  Func("main", {}, ty.Of(s_alias),
-       {Return(Construct(ty.Of(s_alias), Expr(0.f)))},
-       {Stage(ast::PipelineStage::kFragment)});
+    Func("main", {}, ty.Of(s_alias), {Return(Construct(ty.Of(s_alias), Expr(0.f)))},
+         {Stage(ast::PipelineStage::kFragment)});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = TypeOf(s)->As<sem::Struct>();
-  ASSERT_NE(sem, nullptr);
-  EXPECT_THAT(sem->PipelineStageUses(),
-              UnorderedElementsAre(sem::PipelineStageUsage::kFragmentOutput));
+    auto* sem = TypeOf(s)->As<sem::Struct>();
+    ASSERT_NE(sem, nullptr);
+    EXPECT_THAT(sem->PipelineStageUses(),
+                UnorderedElementsAre(sem::PipelineStageUsage::kFragmentOutput));
 }
 
 }  // namespace
diff --git a/src/tint/resolver/struct_storage_class_use_test.cc b/src/tint/resolver/struct_storage_class_use_test.cc
index bc7e7a0..72ed546 100644
--- a/src/tint/resolver/struct_storage_class_use_test.cc
+++ b/src/tint/resolver/struct_storage_class_use_test.cc
@@ -20,173 +20,164 @@
 
 using ::testing::UnorderedElementsAre;
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::resolver {
 namespace {
 
 using ResolverStorageClassUseTest = ResolverTest;
 
 TEST_F(ResolverStorageClassUseTest, UnreachableStruct) {
-  auto* s = Structure("S", {Member("a", ty.f32())});
+    auto* s = Structure("S", {Member("a", ty.f32())});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = TypeOf(s)->As<sem::Struct>();
-  ASSERT_NE(sem, nullptr);
-  EXPECT_TRUE(sem->StorageClassUsage().empty());
+    auto* sem = TypeOf(s)->As<sem::Struct>();
+    ASSERT_NE(sem, nullptr);
+    EXPECT_TRUE(sem->StorageClassUsage().empty());
 }
 
 TEST_F(ResolverStorageClassUseTest, StructReachableFromParameter) {
-  auto* s = Structure("S", {Member("a", ty.f32())});
+    auto* s = Structure("S", {Member("a", ty.f32())});
 
-  Func("f", {Param("param", ty.Of(s))}, ty.void_(), {}, {});
+    Func("f", {Param("param", ty.Of(s))}, ty.void_(), {}, {});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = TypeOf(s)->As<sem::Struct>();
-  ASSERT_NE(sem, nullptr);
-  EXPECT_THAT(sem->StorageClassUsage(),
-              UnorderedElementsAre(ast::StorageClass::kNone));
+    auto* sem = TypeOf(s)->As<sem::Struct>();
+    ASSERT_NE(sem, nullptr);
+    EXPECT_THAT(sem->StorageClassUsage(), UnorderedElementsAre(ast::StorageClass::kNone));
 }
 
 TEST_F(ResolverStorageClassUseTest, StructReachableFromReturnType) {
-  auto* s = Structure("S", {Member("a", ty.f32())});
+    auto* s = Structure("S", {Member("a", ty.f32())});
 
-  Func("f", {}, ty.Of(s), {Return(Construct(ty.Of(s)))}, {});
+    Func("f", {}, ty.Of(s), {Return(Construct(ty.Of(s)))}, {});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = TypeOf(s)->As<sem::Struct>();
-  ASSERT_NE(sem, nullptr);
-  EXPECT_THAT(sem->StorageClassUsage(),
-              UnorderedElementsAre(ast::StorageClass::kNone));
+    auto* sem = TypeOf(s)->As<sem::Struct>();
+    ASSERT_NE(sem, nullptr);
+    EXPECT_THAT(sem->StorageClassUsage(), UnorderedElementsAre(ast::StorageClass::kNone));
 }
 
 TEST_F(ResolverStorageClassUseTest, StructReachableFromGlobal) {
-  auto* s = Structure("S", {Member("a", ty.f32())});
+    auto* s = Structure("S", {Member("a", ty.f32())});
 
-  Global("g", ty.Of(s), ast::StorageClass::kPrivate);
+    Global("g", ty.Of(s), ast::StorageClass::kPrivate);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = TypeOf(s)->As<sem::Struct>();
-  ASSERT_NE(sem, nullptr);
-  EXPECT_THAT(sem->StorageClassUsage(),
-              UnorderedElementsAre(ast::StorageClass::kPrivate));
+    auto* sem = TypeOf(s)->As<sem::Struct>();
+    ASSERT_NE(sem, nullptr);
+    EXPECT_THAT(sem->StorageClassUsage(), UnorderedElementsAre(ast::StorageClass::kPrivate));
 }
 
 TEST_F(ResolverStorageClassUseTest, StructReachableViaGlobalAlias) {
-  auto* s = Structure("S", {Member("a", ty.f32())});
-  auto* a = Alias("A", ty.Of(s));
-  Global("g", ty.Of(a), ast::StorageClass::kPrivate);
+    auto* s = Structure("S", {Member("a", ty.f32())});
+    auto* a = Alias("A", ty.Of(s));
+    Global("g", ty.Of(a), ast::StorageClass::kPrivate);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = TypeOf(s)->As<sem::Struct>();
-  ASSERT_NE(sem, nullptr);
-  EXPECT_THAT(sem->StorageClassUsage(),
-              UnorderedElementsAre(ast::StorageClass::kPrivate));
+    auto* sem = TypeOf(s)->As<sem::Struct>();
+    ASSERT_NE(sem, nullptr);
+    EXPECT_THAT(sem->StorageClassUsage(), UnorderedElementsAre(ast::StorageClass::kPrivate));
 }
 
 TEST_F(ResolverStorageClassUseTest, StructReachableViaGlobalStruct) {
-  auto* s = Structure("S", {Member("a", ty.f32())});
-  auto* o = Structure("O", {Member("a", ty.Of(s))});
-  Global("g", ty.Of(o), ast::StorageClass::kPrivate);
+    auto* s = Structure("S", {Member("a", ty.f32())});
+    auto* o = Structure("O", {Member("a", ty.Of(s))});
+    Global("g", ty.Of(o), ast::StorageClass::kPrivate);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = TypeOf(s)->As<sem::Struct>();
-  ASSERT_NE(sem, nullptr);
-  EXPECT_THAT(sem->StorageClassUsage(),
-              UnorderedElementsAre(ast::StorageClass::kPrivate));
+    auto* sem = TypeOf(s)->As<sem::Struct>();
+    ASSERT_NE(sem, nullptr);
+    EXPECT_THAT(sem->StorageClassUsage(), UnorderedElementsAre(ast::StorageClass::kPrivate));
 }
 
 TEST_F(ResolverStorageClassUseTest, StructReachableViaGlobalArray) {
-  auto* s = Structure("S", {Member("a", ty.f32())});
-  auto* a = ty.array(ty.Of(s), 3);
-  Global("g", a, ast::StorageClass::kPrivate);
+    auto* s = Structure("S", {Member("a", ty.f32())});
+    auto* a = ty.array(ty.Of(s), 3_u);
+    Global("g", a, ast::StorageClass::kPrivate);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = TypeOf(s)->As<sem::Struct>();
-  ASSERT_NE(sem, nullptr);
-  EXPECT_THAT(sem->StorageClassUsage(),
-              UnorderedElementsAre(ast::StorageClass::kPrivate));
+    auto* sem = TypeOf(s)->As<sem::Struct>();
+    ASSERT_NE(sem, nullptr);
+    EXPECT_THAT(sem->StorageClassUsage(), UnorderedElementsAre(ast::StorageClass::kPrivate));
 }
 
 TEST_F(ResolverStorageClassUseTest, StructReachableFromLocal) {
-  auto* s = Structure("S", {Member("a", ty.f32())});
+    auto* s = Structure("S", {Member("a", ty.f32())});
 
-  WrapInFunction(Var("g", ty.Of(s)));
+    WrapInFunction(Var("g", ty.Of(s)));
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = TypeOf(s)->As<sem::Struct>();
-  ASSERT_NE(sem, nullptr);
-  EXPECT_THAT(sem->StorageClassUsage(),
-              UnorderedElementsAre(ast::StorageClass::kFunction));
+    auto* sem = TypeOf(s)->As<sem::Struct>();
+    ASSERT_NE(sem, nullptr);
+    EXPECT_THAT(sem->StorageClassUsage(), UnorderedElementsAre(ast::StorageClass::kFunction));
 }
 
 TEST_F(ResolverStorageClassUseTest, StructReachableViaLocalAlias) {
-  auto* s = Structure("S", {Member("a", ty.f32())});
-  auto* a = Alias("A", ty.Of(s));
-  WrapInFunction(Var("g", ty.Of(a)));
+    auto* s = Structure("S", {Member("a", ty.f32())});
+    auto* a = Alias("A", ty.Of(s));
+    WrapInFunction(Var("g", ty.Of(a)));
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = TypeOf(s)->As<sem::Struct>();
-  ASSERT_NE(sem, nullptr);
-  EXPECT_THAT(sem->StorageClassUsage(),
-              UnorderedElementsAre(ast::StorageClass::kFunction));
+    auto* sem = TypeOf(s)->As<sem::Struct>();
+    ASSERT_NE(sem, nullptr);
+    EXPECT_THAT(sem->StorageClassUsage(), UnorderedElementsAre(ast::StorageClass::kFunction));
 }
 
 TEST_F(ResolverStorageClassUseTest, StructReachableViaLocalStruct) {
-  auto* s = Structure("S", {Member("a", ty.f32())});
-  auto* o = Structure("O", {Member("a", ty.Of(s))});
-  WrapInFunction(Var("g", ty.Of(o)));
+    auto* s = Structure("S", {Member("a", ty.f32())});
+    auto* o = Structure("O", {Member("a", ty.Of(s))});
+    WrapInFunction(Var("g", ty.Of(o)));
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = TypeOf(s)->As<sem::Struct>();
-  ASSERT_NE(sem, nullptr);
-  EXPECT_THAT(sem->StorageClassUsage(),
-              UnorderedElementsAre(ast::StorageClass::kFunction));
+    auto* sem = TypeOf(s)->As<sem::Struct>();
+    ASSERT_NE(sem, nullptr);
+    EXPECT_THAT(sem->StorageClassUsage(), UnorderedElementsAre(ast::StorageClass::kFunction));
 }
 
 TEST_F(ResolverStorageClassUseTest, StructReachableViaLocalArray) {
-  auto* s = Structure("S", {Member("a", ty.f32())});
-  auto* a = ty.array(ty.Of(s), 3);
-  WrapInFunction(Var("g", a));
+    auto* s = Structure("S", {Member("a", ty.f32())});
+    auto* a = ty.array(ty.Of(s), 3_u);
+    WrapInFunction(Var("g", a));
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = TypeOf(s)->As<sem::Struct>();
-  ASSERT_NE(sem, nullptr);
-  EXPECT_THAT(sem->StorageClassUsage(),
-              UnorderedElementsAre(ast::StorageClass::kFunction));
+    auto* sem = TypeOf(s)->As<sem::Struct>();
+    ASSERT_NE(sem, nullptr);
+    EXPECT_THAT(sem->StorageClassUsage(), UnorderedElementsAre(ast::StorageClass::kFunction));
 }
 
 TEST_F(ResolverStorageClassUseTest, StructMultipleStorageClassUses) {
-  auto* s = Structure("S", {Member("a", ty.f32())});
-  Global("x", ty.Of(s), ast::StorageClass::kUniform,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
-  Global("y", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(1),
-             create<ast::GroupAttribute>(0),
-         });
-  WrapInFunction(Var("g", ty.Of(s)));
+    auto* s = Structure("S", {Member("a", ty.f32())});
+    Global("x", ty.Of(s), ast::StorageClass::kUniform,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
+    Global("y", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(1),
+               create<ast::GroupAttribute>(0),
+           });
+    WrapInFunction(Var("g", ty.Of(s)));
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* sem = TypeOf(s)->As<sem::Struct>();
-  ASSERT_NE(sem, nullptr);
-  EXPECT_THAT(sem->StorageClassUsage(),
-              UnorderedElementsAre(ast::StorageClass::kUniform,
-                                   ast::StorageClass::kStorage,
-                                   ast::StorageClass::kFunction));
+    auto* sem = TypeOf(s)->As<sem::Struct>();
+    ASSERT_NE(sem, nullptr);
+    EXPECT_THAT(sem->StorageClassUsage(),
+                UnorderedElementsAre(ast::StorageClass::kUniform, ast::StorageClass::kStorage,
+                                     ast::StorageClass::kFunction));
 }
 
 }  // namespace
diff --git a/src/tint/resolver/type_constructor_validation_test.cc b/src/tint/resolver/type_constructor_validation_test.cc
index 07bc95e..edfce46 100644
--- a/src/tint/resolver/type_constructor_validation_test.cc
+++ b/src/tint/resolver/type_constructor_validation_test.cc
@@ -14,10 +14,12 @@
 
 #include "gmock/gmock.h"
 #include "src/tint/resolver/resolver_test_helper.h"
-#include "src/tint/sem/reference_type.h"
+#include "src/tint/sem/reference.h"
 #include "src/tint/sem/type_constructor.h"
 #include "src/tint/sem/type_conversion.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::resolver {
 namespace {
 
@@ -31,79 +33,70 @@
 using builder::CreatePtrs;
 using builder::CreatePtrsFor;
 using builder::DataType;
-using builder::f32;
-using builder::i32;
 using builder::mat2x2;
 using builder::mat2x3;
 using builder::mat3x2;
 using builder::mat3x3;
 using builder::mat4x4;
-using builder::u32;
 using builder::vec2;
 using builder::vec3;
 using builder::vec4;
 
-class ResolverTypeConstructorValidationTest : public resolver::TestHelper,
-                                              public testing::Test {};
+class ResolverTypeConstructorValidationTest : public resolver::TestHelper, public testing::Test {};
 
 namespace InferTypeTest {
 struct Params {
-  builder::ast_type_func_ptr create_rhs_ast_type;
-  builder::ast_expr_func_ptr create_rhs_ast_value;
-  builder::sem_type_func_ptr create_rhs_sem_type;
+    builder::ast_type_func_ptr create_rhs_ast_type;
+    builder::ast_expr_func_ptr create_rhs_ast_value;
+    builder::sem_type_func_ptr create_rhs_sem_type;
 };
 
 template <typename T>
 constexpr Params ParamsFor() {
-  return Params{DataType<T>::AST, DataType<T>::Expr, DataType<T>::Sem};
+    return Params{DataType<T>::AST, DataType<T>::Expr, DataType<T>::Sem};
 }
 
 TEST_F(ResolverTypeConstructorValidationTest, InferTypeTest_Simple) {
-  // var a = 1;
-  // var b = a;
-  auto* a = Var("a", nullptr, ast::StorageClass::kNone, Expr(1));
-  auto* b = Var("b", nullptr, ast::StorageClass::kNone, Expr("a"));
-  auto* a_ident = Expr("a");
-  auto* b_ident = Expr("b");
+    // var a = 1;
+    // var b = a;
+    auto* a = Var("a", nullptr, ast::StorageClass::kNone, Expr(1_i));
+    auto* b = Var("b", nullptr, ast::StorageClass::kNone, Expr("a"));
+    auto* a_ident = Expr("a");
+    auto* b_ident = Expr("b");
 
-  WrapInFunction(a, b, Assign(a_ident, "a"), Assign(b_ident, "b"));
+    WrapInFunction(a, b, Assign(a_ident, "a"), Assign(b_ident, "b"));
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
-  ASSERT_TRUE(TypeOf(a_ident)->Is<sem::Reference>());
-  EXPECT_TRUE(
-      TypeOf(a_ident)->As<sem::Reference>()->StoreType()->Is<sem::I32>());
-  EXPECT_EQ(TypeOf(a_ident)->As<sem::Reference>()->StorageClass(),
-            ast::StorageClass::kFunction);
-  ASSERT_TRUE(TypeOf(b_ident)->Is<sem::Reference>());
-  EXPECT_TRUE(
-      TypeOf(b_ident)->As<sem::Reference>()->StoreType()->Is<sem::I32>());
-  EXPECT_EQ(TypeOf(b_ident)->As<sem::Reference>()->StorageClass(),
-            ast::StorageClass::kFunction);
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(TypeOf(a_ident)->Is<sem::Reference>());
+    EXPECT_TRUE(TypeOf(a_ident)->As<sem::Reference>()->StoreType()->Is<sem::I32>());
+    EXPECT_EQ(TypeOf(a_ident)->As<sem::Reference>()->StorageClass(), ast::StorageClass::kFunction);
+    ASSERT_TRUE(TypeOf(b_ident)->Is<sem::Reference>());
+    EXPECT_TRUE(TypeOf(b_ident)->As<sem::Reference>()->StoreType()->Is<sem::I32>());
+    EXPECT_EQ(TypeOf(b_ident)->As<sem::Reference>()->StorageClass(), ast::StorageClass::kFunction);
 }
 
 using InferTypeTest_FromConstructorExpression = ResolverTestWithParam<Params>;
 TEST_P(InferTypeTest_FromConstructorExpression, All) {
-  // e.g. for vec3<f32>
-  // {
-  //   var a = vec3<f32>(0.0, 0.0, 0.0)
-  // }
-  auto& params = GetParam();
+    // e.g. for vec3<f32>
+    // {
+    //   var a = vec3<f32>(0.0, 0.0, 0.0)
+    // }
+    auto& params = GetParam();
 
-  auto* constructor_expr = params.create_rhs_ast_value(*this, 0);
+    auto* constructor_expr = params.create_rhs_ast_value(*this, 0);
 
-  auto* a = Var("a", nullptr, ast::StorageClass::kNone, constructor_expr);
-  // Self-assign 'a' to force the expression to be resolved so we can test its
-  // type below
-  auto* a_ident = Expr("a");
-  WrapInFunction(Decl(a), Assign(a_ident, "a"));
+    auto* a = Var("a", nullptr, ast::StorageClass::kNone, constructor_expr);
+    // Self-assign 'a' to force the expression to be resolved so we can test its
+    // type below
+    auto* a_ident = Expr("a");
+    WrapInFunction(Decl(a), Assign(a_ident, "a"));
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
-  auto* got = TypeOf(a_ident);
-  auto* expected = create<sem::Reference>(params.create_rhs_sem_type(*this),
-                                          ast::StorageClass::kFunction,
-                                          ast::Access::kReadWrite);
-  ASSERT_EQ(got, expected) << "got:      " << FriendlyName(got) << "\n"
-                           << "expected: " << FriendlyName(expected) << "\n";
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
+    auto* got = TypeOf(a_ident);
+    auto* expected = create<sem::Reference>(params.create_rhs_sem_type(*this),
+                                            ast::StorageClass::kFunction, ast::Access::kReadWrite);
+    ASSERT_EQ(got, expected) << "got:      " << FriendlyName(got) << "\n"
+                             << "expected: " << FriendlyName(expected) << "\n";
 }
 
 static constexpr Params from_constructor_expression_cases[] = {
@@ -130,29 +123,28 @@
 
 using InferTypeTest_FromArithmeticExpression = ResolverTestWithParam<Params>;
 TEST_P(InferTypeTest_FromArithmeticExpression, All) {
-  // e.g. for vec3<f32>
-  // {
-  //   var a = vec3<f32>(2.0, 2.0, 2.0) * 3.0;
-  // }
-  auto& params = GetParam();
+    // e.g. for vec3<f32>
+    // {
+    //   var a = vec3<f32>(2.0, 2.0, 2.0) * 3.0;
+    // }
+    auto& params = GetParam();
 
-  auto* arith_lhs_expr = params.create_rhs_ast_value(*this, 2);
-  auto* arith_rhs_expr = params.create_rhs_ast_value(*this, 3);
-  auto* constructor_expr = Mul(arith_lhs_expr, arith_rhs_expr);
+    auto* arith_lhs_expr = params.create_rhs_ast_value(*this, 2);
+    auto* arith_rhs_expr = params.create_rhs_ast_value(*this, 3);
+    auto* constructor_expr = Mul(arith_lhs_expr, arith_rhs_expr);
 
-  auto* a = Var("a", nullptr, constructor_expr);
-  // Self-assign 'a' to force the expression to be resolved so we can test its
-  // type below
-  auto* a_ident = Expr("a");
-  WrapInFunction(Decl(a), Assign(a_ident, "a"));
+    auto* a = Var("a", nullptr, constructor_expr);
+    // Self-assign 'a' to force the expression to be resolved so we can test its
+    // type below
+    auto* a_ident = Expr("a");
+    WrapInFunction(Decl(a), Assign(a_ident, "a"));
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
-  auto* got = TypeOf(a_ident);
-  auto* expected = create<sem::Reference>(params.create_rhs_sem_type(*this),
-                                          ast::StorageClass::kFunction,
-                                          ast::Access::kReadWrite);
-  ASSERT_EQ(got, expected) << "got:      " << FriendlyName(got) << "\n"
-                           << "expected: " << FriendlyName(expected) << "\n";
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
+    auto* got = TypeOf(a_ident);
+    auto* expected = create<sem::Reference>(params.create_rhs_sem_type(*this),
+                                            ast::StorageClass::kFunction, ast::Access::kReadWrite);
+    ASSERT_EQ(got, expected) << "got:      " << FriendlyName(got) << "\n"
+                             << "expected: " << FriendlyName(expected) << "\n";
 }
 static constexpr Params from_arithmetic_expression_cases[] = {
     ParamsFor<i32>(),       ParamsFor<u32>(),         ParamsFor<f32>(),
@@ -171,34 +163,33 @@
 
 using InferTypeTest_FromCallExpression = ResolverTestWithParam<Params>;
 TEST_P(InferTypeTest_FromCallExpression, All) {
-  // e.g. for vec3<f32>
-  //
-  // fn foo() -> vec3<f32> {
-  //   return vec3<f32>();
-  // }
-  //
-  // fn bar()
-  // {
-  //   var a = foo();
-  // }
-  auto& params = GetParam();
+    // e.g. for vec3<f32>
+    //
+    // fn foo() -> vec3<f32> {
+    //   return vec3<f32>();
+    // }
+    //
+    // fn bar()
+    // {
+    //   var a = foo();
+    // }
+    auto& params = GetParam();
 
-  Func("foo", {}, params.create_rhs_ast_type(*this),
-       {Return(Construct(params.create_rhs_ast_type(*this)))}, {});
+    Func("foo", {}, params.create_rhs_ast_type(*this),
+         {Return(Construct(params.create_rhs_ast_type(*this)))}, {});
 
-  auto* a = Var("a", nullptr, Call("foo"));
-  // Self-assign 'a' to force the expression to be resolved so we can test its
-  // type below
-  auto* a_ident = Expr("a");
-  WrapInFunction(Decl(a), Assign(a_ident, "a"));
+    auto* a = Var("a", nullptr, Call("foo"));
+    // Self-assign 'a' to force the expression to be resolved so we can test its
+    // type below
+    auto* a_ident = Expr("a");
+    WrapInFunction(Decl(a), Assign(a_ident, "a"));
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
-  auto* got = TypeOf(a_ident);
-  auto* expected = create<sem::Reference>(params.create_rhs_sem_type(*this),
-                                          ast::StorageClass::kFunction,
-                                          ast::Access::kReadWrite);
-  ASSERT_EQ(got, expected) << "got:      " << FriendlyName(got) << "\n"
-                           << "expected: " << FriendlyName(expected) << "\n";
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
+    auto* got = TypeOf(a_ident);
+    auto* expected = create<sem::Reference>(params.create_rhs_sem_type(*this),
+                                            ast::StorageClass::kFunction, ast::Access::kReadWrite);
+    ASSERT_EQ(got, expected) << "got:      " << FriendlyName(got) << "\n"
+                             << "expected: " << FriendlyName(expected) << "\n";
 }
 static constexpr Params from_call_expression_cases[] = {
     ParamsFor<bool>(),
@@ -226,21 +217,20 @@
 
 namespace ConversionConstructTest {
 enum class Kind {
-  Construct,
-  Conversion,
+    Construct,
+    Conversion,
 };
 
 struct Params {
-  Kind kind;
-  builder::ast_type_func_ptr lhs_type;
-  builder::ast_type_func_ptr rhs_type;
-  builder::ast_expr_func_ptr rhs_value_expr;
+    Kind kind;
+    builder::ast_type_func_ptr lhs_type;
+    builder::ast_type_func_ptr rhs_type;
+    builder::ast_expr_func_ptr rhs_value_expr;
 };
 
 template <typename LhsType, typename RhsType>
 constexpr Params ParamsFor(Kind kind) {
-  return Params{kind, DataType<LhsType>::AST, DataType<RhsType>::AST,
-                DataType<RhsType>::Expr};
+    return Params{kind, DataType<LhsType>::AST, DataType<RhsType>::AST, DataType<RhsType>::Expr};
 }
 
 static constexpr Params valid_cases[] = {
@@ -296,50 +286,50 @@
 
 using ConversionConstructorValidTest = ResolverTestWithParam<Params>;
 TEST_P(ConversionConstructorValidTest, All) {
-  auto& params = GetParam();
+    auto& params = GetParam();
 
-  // var a : <lhs_type1> = <lhs_type2>(<rhs_type>(<rhs_value_expr>));
-  auto* lhs_type1 = params.lhs_type(*this);
-  auto* lhs_type2 = params.lhs_type(*this);
-  auto* rhs_type = params.rhs_type(*this);
-  auto* rhs_value_expr = params.rhs_value_expr(*this, 0);
+    // var a : <lhs_type1> = <lhs_type2>(<rhs_type>(<rhs_value_expr>));
+    auto* lhs_type1 = params.lhs_type(*this);
+    auto* lhs_type2 = params.lhs_type(*this);
+    auto* rhs_type = params.rhs_type(*this);
+    auto* rhs_value_expr = params.rhs_value_expr(*this, 0);
 
-  std::stringstream ss;
-  ss << FriendlyName(lhs_type1) << " = " << FriendlyName(lhs_type2) << "("
-     << FriendlyName(rhs_type) << "(<rhs value expr>))";
-  SCOPED_TRACE(ss.str());
+    std::stringstream ss;
+    ss << FriendlyName(lhs_type1) << " = " << FriendlyName(lhs_type2) << "("
+       << FriendlyName(rhs_type) << "(<rhs value expr>))";
+    SCOPED_TRACE(ss.str());
 
-  auto* arg = Construct(rhs_type, rhs_value_expr);
-  auto* tc = Construct(lhs_type2, arg);
-  auto* a = Var("a", lhs_type1, ast::StorageClass::kNone, tc);
+    auto* arg = Construct(rhs_type, rhs_value_expr);
+    auto* tc = Construct(lhs_type2, arg);
+    auto* a = Var("a", lhs_type1, ast::StorageClass::kNone, tc);
 
-  // Self-assign 'a' to force the expression to be resolved so we can test its
-  // type below
-  auto* a_ident = Expr("a");
-  WrapInFunction(Decl(a), Assign(a_ident, "a"));
+    // Self-assign 'a' to force the expression to be resolved so we can test its
+    // type below
+    auto* a_ident = Expr("a");
+    WrapInFunction(Decl(a), Assign(a_ident, "a"));
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* call = Sem().Get(tc);
-  ASSERT_NE(call, nullptr);
-  switch (params.kind) {
-    case Kind::Construct: {
-      auto* ctor = call->Target()->As<sem::TypeConstructor>();
-      ASSERT_NE(ctor, nullptr);
-      EXPECT_EQ(call->Type(), ctor->ReturnType());
-      ASSERT_EQ(ctor->Parameters().size(), 1u);
-      EXPECT_EQ(ctor->Parameters()[0]->Type(), TypeOf(arg));
-      break;
+    auto* call = Sem().Get(tc);
+    ASSERT_NE(call, nullptr);
+    switch (params.kind) {
+        case Kind::Construct: {
+            auto* ctor = call->Target()->As<sem::TypeConstructor>();
+            ASSERT_NE(ctor, nullptr);
+            EXPECT_EQ(call->Type(), ctor->ReturnType());
+            ASSERT_EQ(ctor->Parameters().size(), 1u);
+            EXPECT_EQ(ctor->Parameters()[0]->Type(), TypeOf(arg));
+            break;
+        }
+        case Kind::Conversion: {
+            auto* conv = call->Target()->As<sem::TypeConversion>();
+            ASSERT_NE(conv, nullptr);
+            EXPECT_EQ(call->Type(), conv->ReturnType());
+            ASSERT_EQ(conv->Parameters().size(), 1u);
+            EXPECT_EQ(conv->Parameters()[0]->Type(), TypeOf(arg));
+            break;
+        }
     }
-    case Kind::Conversion: {
-      auto* conv = call->Target()->As<sem::TypeConversion>();
-      ASSERT_NE(conv, nullptr);
-      EXPECT_EQ(call->Type(), conv->ReturnType());
-      ASSERT_EQ(conv->Parameters().size(), 1u);
-      EXPECT_EQ(conv->Parameters()[0]->Type(), TypeOf(arg));
-      break;
-    }
-  }
 }
 INSTANTIATE_TEST_SUITE_P(ResolverTypeConstructorValidationTest,
                          ConversionConstructorValidTest,
@@ -365,272 +355,258 @@
     CreatePtrsFor<mat3x2<f32>>()   //
 };
 
-using ConversionConstructorInvalidTest =
-    ResolverTestWithParam<std::tuple<CreatePtrs,  // lhs
-                                     CreatePtrs   // rhs
-                                     >>;
+using ConversionConstructorInvalidTest = ResolverTestWithParam<std::tuple<CreatePtrs,  // lhs
+                                                                          CreatePtrs   // rhs
+                                                                          >>;
 TEST_P(ConversionConstructorInvalidTest, All) {
-  auto& params = GetParam();
+    auto& params = GetParam();
 
-  auto& lhs_params = std::get<0>(params);
-  auto& rhs_params = std::get<1>(params);
+    auto& lhs_params = std::get<0>(params);
+    auto& rhs_params = std::get<1>(params);
 
-  // Skip test for valid cases
-  for (auto& v : valid_cases) {
-    if (v.lhs_type == lhs_params.ast && v.rhs_type == rhs_params.ast &&
-        v.rhs_value_expr == rhs_params.expr) {
-      return;
+    // Skip test for valid cases
+    for (auto& v : valid_cases) {
+        if (v.lhs_type == lhs_params.ast && v.rhs_type == rhs_params.ast &&
+            v.rhs_value_expr == rhs_params.expr) {
+            return;
+        }
     }
-  }
-  // Skip non-conversions
-  if (lhs_params.ast == rhs_params.ast) {
-    return;
-  }
+    // Skip non-conversions
+    if (lhs_params.ast == rhs_params.ast) {
+        return;
+    }
 
-  // var a : <lhs_type1> = <lhs_type2>(<rhs_type>(<rhs_value_expr>));
-  auto* lhs_type1 = lhs_params.ast(*this);
-  auto* lhs_type2 = lhs_params.ast(*this);
-  auto* rhs_type = rhs_params.ast(*this);
-  auto* rhs_value_expr = rhs_params.expr(*this, 0);
+    // var a : <lhs_type1> = <lhs_type2>(<rhs_type>(<rhs_value_expr>));
+    auto* lhs_type1 = lhs_params.ast(*this);
+    auto* lhs_type2 = lhs_params.ast(*this);
+    auto* rhs_type = rhs_params.ast(*this);
+    auto* rhs_value_expr = rhs_params.expr(*this, 0);
 
-  std::stringstream ss;
-  ss << FriendlyName(lhs_type1) << " = " << FriendlyName(lhs_type2) << "("
-     << FriendlyName(rhs_type) << "(<rhs value expr>))";
-  SCOPED_TRACE(ss.str());
+    std::stringstream ss;
+    ss << FriendlyName(lhs_type1) << " = " << FriendlyName(lhs_type2) << "("
+       << FriendlyName(rhs_type) << "(<rhs value expr>))";
+    SCOPED_TRACE(ss.str());
 
-  auto* a = Var("a", lhs_type1, ast::StorageClass::kNone,
-                Construct(lhs_type2, Construct(rhs_type, rhs_value_expr)));
+    auto* a = Var("a", lhs_type1, ast::StorageClass::kNone,
+                  Construct(lhs_type2, Construct(rhs_type, rhs_value_expr)));
 
-  // Self-assign 'a' to force the expression to be resolved so we can test its
-  // type below
-  auto* a_ident = Expr("a");
-  WrapInFunction(Decl(a), Assign(a_ident, "a"));
+    // Self-assign 'a' to force the expression to be resolved so we can test its
+    // type below
+    auto* a_ident = Expr("a");
+    WrapInFunction(Decl(a), Assign(a_ident, "a"));
 
-  ASSERT_FALSE(r()->Resolve());
+    ASSERT_FALSE(r()->Resolve());
 }
 INSTANTIATE_TEST_SUITE_P(ResolverTypeConstructorValidationTest,
                          ConversionConstructorInvalidTest,
                          testing::Combine(testing::ValuesIn(all_types),
                                           testing::ValuesIn(all_types)));
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       ConversionConstructorInvalid_TooManyInitializers) {
-  auto* a = Var("a", ty.f32(), ast::StorageClass::kNone,
-                Construct(Source{{12, 34}}, ty.f32(), Expr(1.0f), Expr(2.0f)));
-  WrapInFunction(a);
+TEST_F(ResolverTypeConstructorValidationTest, ConversionConstructorInvalid_TooManyInitializers) {
+    auto* a = Var("a", ty.f32(), ast::StorageClass::kNone,
+                  Construct(Source{{12, 34}}, ty.f32(), Expr(1.0f), Expr(2.0f)));
+    WrapInFunction(a);
 
-  ASSERT_FALSE(r()->Resolve());
-  ASSERT_EQ(r()->error(),
-            "12:34 error: expected zero or one value in constructor, got 2");
+    ASSERT_FALSE(r()->Resolve());
+    ASSERT_EQ(r()->error(), "12:34 error: expected zero or one value in constructor, got 2");
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       ConversionConstructorInvalid_InvalidInitializer) {
-  auto* a =
-      Var("a", ty.f32(), ast::StorageClass::kNone,
-          Construct(Source{{12, 34}}, ty.f32(), Construct(ty.array<f32, 4>())));
-  WrapInFunction(a);
+TEST_F(ResolverTypeConstructorValidationTest, ConversionConstructorInvalid_InvalidInitializer) {
+    auto* a = Var("a", ty.f32(), ast::StorageClass::kNone,
+                  Construct(Source{{12, 34}}, ty.f32(), Construct(ty.array<f32, 4>())));
+    WrapInFunction(a);
 
-  ASSERT_FALSE(r()->Resolve());
-  ASSERT_EQ(r()->error(),
-            "12:34 error: cannot construct 'f32' with a value of type "
-            "'array<f32, 4>'");
+    ASSERT_FALSE(r()->Resolve());
+    ASSERT_EQ(r()->error(),
+              "12:34 error: cannot construct 'f32' with a value of type "
+              "'array<f32, 4>'");
 }
 
 }  // namespace ConversionConstructTest
 
 namespace ArrayConstructor {
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Array_ZeroValue_Pass) {
-  // array<u32, 10>();
-  auto* tc = array<u32, 10>();
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Array_ZeroValue_Pass) {
+    // array<u32, 10u>();
+    auto* tc = array<u32, 10>();
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* call = Sem().Get(tc);
-  ASSERT_NE(call, nullptr);
-  EXPECT_TRUE(call->Type()->Is<sem::Array>());
-  auto* ctor = call->Target()->As<sem::TypeConstructor>();
-  ASSERT_NE(ctor, nullptr);
-  EXPECT_EQ(call->Type(), ctor->ReturnType());
-  ASSERT_EQ(ctor->Parameters().size(), 0u);
+    auto* call = Sem().Get(tc);
+    ASSERT_NE(call, nullptr);
+    EXPECT_TRUE(call->Type()->Is<sem::Array>());
+    auto* ctor = call->Target()->As<sem::TypeConstructor>();
+    ASSERT_NE(ctor, nullptr);
+    EXPECT_EQ(call->Type(), ctor->ReturnType());
+    ASSERT_EQ(ctor->Parameters().size(), 0u);
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Array_type_match) {
-  // array<u32, 3>(0u, 10u. 20u);
-  auto* tc = array<u32, 3>(Expr(0u), Expr(10u), Expr(20u));
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Array_type_match) {
+    // array<u32, 3u>(0u, 10u. 20u);
+    auto* tc = array<u32, 3>(Expr(0_u), Expr(10_u), Expr(20_u));
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* call = Sem().Get(tc);
-  ASSERT_NE(call, nullptr);
-  EXPECT_TRUE(call->Type()->Is<sem::Array>());
-  auto* ctor = call->Target()->As<sem::TypeConstructor>();
-  ASSERT_NE(ctor, nullptr);
-  EXPECT_EQ(call->Type(), ctor->ReturnType());
-  ASSERT_EQ(ctor->Parameters().size(), 3u);
-  EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::U32>());
-  EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::U32>());
-  EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::U32>());
+    auto* call = Sem().Get(tc);
+    ASSERT_NE(call, nullptr);
+    EXPECT_TRUE(call->Type()->Is<sem::Array>());
+    auto* ctor = call->Target()->As<sem::TypeConstructor>();
+    ASSERT_NE(ctor, nullptr);
+    EXPECT_EQ(call->Type(), ctor->ReturnType());
+    ASSERT_EQ(ctor->Parameters().size(), 3u);
+    EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::U32>());
+    EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::U32>());
+    EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::U32>());
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Array_type_Mismatch_U32F32) {
-  // array<u32, 3>(0u, 1.0f, 20u);
-  auto* tc = array<u32, 3>(Expr(0u), Expr(Source{{12, 34}}, 1.0f), Expr(20u));
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Array_type_Mismatch_U32F32) {
+    // array<u32, 3u>(0u, 1.0f, 20u);
+    auto* tc = array<u32, 3>(Expr(0_u), Expr(Source{{12, 34}}, 1.0f), Expr(20_u));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: type in array constructor does not match array type: "
-            "expected 'u32', found 'f32'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: type in array constructor does not match array type: "
+              "expected 'u32', found 'f32'");
 }
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Array_ScalarArgumentTypeMismatch_F32I32) {
-  // array<f32, 1>(1);
-  auto* tc = array<f32, 1>(Expr(Source{{12, 34}}, 1));
-  WrapInFunction(tc);
+    // array<f32, 1u>(1i);
+    auto* tc = array<f32, 1>(Expr(Source{{12, 34}}, 1_i));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: type in array constructor does not match array type: "
-            "expected 'f32', found 'i32'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: type in array constructor does not match array type: "
+              "expected 'f32', found 'i32'");
 }
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Array_ScalarArgumentTypeMismatch_U32I32) {
-  // array<u32, 6>(1, 0u, 0u, 0u, 0u, 0u);
-  auto* tc = array<u32, 1>(Expr(Source{{12, 34}}, 1), Expr(0u), Expr(0u),
-                           Expr(0u), Expr(0u));
-  WrapInFunction(tc);
+    // array<u32, 1u>(1i, 0u, 0u, 0u, 0u, 0u);
+    auto* tc =
+        array<u32, 1>(Expr(Source{{12, 34}}, 1_i), Expr(0_u), Expr(0_u), Expr(0_u), Expr(0_u));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: type in array constructor does not match array type: "
-            "expected 'u32', found 'i32'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: type in array constructor does not match array type: "
+              "expected 'u32', found 'i32'");
 }
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Array_ScalarArgumentTypeMismatch_Vec2) {
-  // array<i32, 3>(1, vec2<i32>());
-  auto* tc =
-      array<i32, 3>(Expr(1), Construct(Source{{12, 34}}, ty.vec2<i32>()));
-  WrapInFunction(tc);
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: type in array constructor does not match array type: "
-            "expected 'i32', found 'vec2<i32>'");
+    // array<i32, 3u>(1i, vec2<i32>());
+    auto* tc = array<i32, 3>(Expr(1_i), Construct(Source{{12, 34}}, ty.vec2<i32>()));
+    WrapInFunction(tc);
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: type in array constructor does not match array type: "
+              "expected 'i32', found 'vec2<i32>'");
 }
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_ArrayOfVector_SubElemTypeMismatch_I32U32) {
-  // array<vec3<i32>, 2>(vec3<i32>(), vec3<u32>());
-  auto* e0 = vec3<i32>();
-  SetSource(Source::Location({12, 34}));
-  auto* e1 = vec3<u32>();
-  auto* t = Construct(ty.array(ty.vec3<i32>(), 2), e0, e1);
-  WrapInFunction(t);
+    // array<vec3<i32>, 2u>(vec3<i32>(), vec3<u32>());
+    auto* e0 = vec3<i32>();
+    SetSource(Source::Location({12, 34}));
+    auto* e1 = vec3<u32>();
+    auto* t = Construct(ty.array(ty.vec3<i32>(), 2_i), e0, e1);
+    WrapInFunction(t);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: type in array constructor does not match array type: "
-            "expected 'vec3<i32>', found 'vec3<u32>'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: type in array constructor does not match array type: "
+              "expected 'vec3<i32>', found 'vec3<u32>'");
 }
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_ArrayOfVector_SubElemTypeMismatch_I32Bool) {
-  // array<vec3<i32>, 2>(vec3<i32>(), vec3<bool>(true, true, false));
-  SetSource(Source::Location({12, 34}));
-  auto* e0 = vec3<bool>(true, true, false);
-  auto* e1 = vec3<i32>();
-  auto* t = Construct(ty.array(ty.vec3<i32>(), 2), e0, e1);
-  WrapInFunction(t);
+    // array<vec3<i32>, 2u>(vec3<i32>(), vec3<bool>(true, true, false));
+    SetSource(Source::Location({12, 34}));
+    auto* e0 = vec3<bool>(true, true, false);
+    auto* e1 = vec3<i32>();
+    auto* t = Construct(ty.array(ty.vec3<i32>(), 2_i), e0, e1);
+    WrapInFunction(t);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: type in array constructor does not match array type: "
-            "expected 'vec3<i32>', found 'vec3<bool>'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: type in array constructor does not match array type: "
+              "expected 'vec3<i32>', found 'vec3<bool>'");
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_ArrayOfArray_SubElemSizeMismatch) {
-  // array<array<i32, 2>, 2>(array<i32, 3>(), array<i32, 2>());
-  SetSource(Source::Location({12, 34}));
-  auto* e0 = array<i32, 3>();
-  auto* e1 = array<i32, 2>();
-  auto* t = Construct(ty.array(ty.array<i32, 2>(), 2), e0, e1);
-  WrapInFunction(t);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_ArrayOfArray_SubElemSizeMismatch) {
+    // array<array<i32, 2u>, 2u>(array<i32, 3u>(), array<i32, 2u>());
+    SetSource(Source::Location({12, 34}));
+    auto* e0 = array<i32, 3>();
+    auto* e1 = array<i32, 2>();
+    auto* t = Construct(ty.array(ty.array<i32, 2>(), 2_i), e0, e1);
+    WrapInFunction(t);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: type in array constructor does not match array type: "
-            "expected 'array<i32, 2>', found 'array<i32, 3>'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: type in array constructor does not match array type: "
+              "expected 'array<i32, 2>', found 'array<i32, 3>'");
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_ArrayOfArray_SubElemTypeMismatch) {
-  // array<array<i32, 2>, 2>(array<i32, 2>(), array<u32, 2>());
-  auto* e0 = array<i32, 2>();
-  SetSource(Source::Location({12, 34}));
-  auto* e1 = array<u32, 2>();
-  auto* t = Construct(ty.array(ty.array<i32, 2>(), 2), e0, e1);
-  WrapInFunction(t);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_ArrayOfArray_SubElemTypeMismatch) {
+    // array<array<i32, 2u>, 2u>(array<i32, 2u>(), array<u32, 2u>());
+    auto* e0 = array<i32, 2>();
+    SetSource(Source::Location({12, 34}));
+    auto* e1 = array<u32, 2>();
+    auto* t = Construct(ty.array(ty.array<i32, 2>(), 2_i), e0, e1);
+    WrapInFunction(t);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: type in array constructor does not match array type: "
-            "expected 'array<i32, 2>', found 'array<u32, 2>'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: type in array constructor does not match array type: "
+              "expected 'array<i32, 2>', found 'array<u32, 2>'");
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Array_TooFewElements) {
-  // array<i32, 4>(1, 2, 3);
-  SetSource(Source::Location({12, 34}));
-  auto* tc = array<i32, 4>(Expr(1), Expr(2), Expr(3));
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Array_TooFewElements) {
+    // array<i32, 4u>(1i, 2i, 3i);
+    SetSource(Source::Location({12, 34}));
+    auto* tc = array<i32, 4>(Expr(1_i), Expr(2_i), Expr(3_i));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: array constructor has too few elements: expected 4, "
-            "found 3");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: array constructor has too few elements: expected 4, "
+              "found 3");
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Array_TooManyElements) {
-  // array<i32, 4>(1, 2, 3, 4, 5);
-  SetSource(Source::Location({12, 34}));
-  auto* tc = array<i32, 4>(Expr(1), Expr(2), Expr(3), Expr(4), Expr(5));
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Array_TooManyElements) {
+    // array<i32, 4u>(1i, 2i, 3i, 4i, 5i);
+    SetSource(Source::Location({12, 34}));
+    auto* tc = array<i32, 4>(Expr(1_i), Expr(2_i), Expr(3_i), Expr(4_i), Expr(5_i));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: array constructor has too many "
-            "elements: expected 4, "
-            "found 5");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: array constructor has too many "
+              "elements: expected 4, "
+              "found 5");
 }
 
 TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Array_Runtime) {
-  // array<i32>(1);
-  auto* tc = array(ty.i32(), nullptr, Expr(Source{{12, 34}}, 1));
-  WrapInFunction(tc);
+    // array<i32>(1i);
+    auto* tc = array(ty.i32(), nullptr, Expr(Source{{12, 34}}, 1_i));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "error: cannot init a runtime-sized array");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "error: cannot init a runtime-sized array");
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Array_RuntimeZeroValue) {
-  // array<i32>();
-  auto* tc = array(ty.i32(), nullptr);
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Array_RuntimeZeroValue) {
+    // array<i32>();
+    auto* tc = array(ty.i32(), nullptr);
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "error: cannot init a runtime-sized array");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "error: cannot init a runtime-sized array");
 }
 
 }  // namespace ArrayConstructor
@@ -638,111 +614,111 @@
 namespace ScalarConstructor {
 
 TEST_F(ResolverTypeConstructorValidationTest, Expr_Construct_i32_Success) {
-  auto* expr = Construct<i32>(Expr(123));
-  WrapInFunction(expr);
+    auto* expr = Construct<i32>(Expr(123_i));
+    WrapInFunction(expr);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(expr), nullptr);
-  ASSERT_TRUE(TypeOf(expr)->Is<sem::I32>());
+    ASSERT_NE(TypeOf(expr), nullptr);
+    ASSERT_TRUE(TypeOf(expr)->Is<sem::I32>());
 
-  auto* call = Sem().Get(expr);
-  ASSERT_NE(call, nullptr);
-  auto* ctor = call->Target()->As<sem::TypeConstructor>();
-  ASSERT_NE(ctor, nullptr);
-  EXPECT_EQ(call->Type(), ctor->ReturnType());
-  ASSERT_EQ(ctor->Parameters().size(), 1u);
-  EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::I32>());
+    auto* call = Sem().Get(expr);
+    ASSERT_NE(call, nullptr);
+    auto* ctor = call->Target()->As<sem::TypeConstructor>();
+    ASSERT_NE(ctor, nullptr);
+    EXPECT_EQ(call->Type(), ctor->ReturnType());
+    ASSERT_EQ(ctor->Parameters().size(), 1u);
+    EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::I32>());
 }
 
 TEST_F(ResolverTypeConstructorValidationTest, Expr_Construct_u32_Success) {
-  auto* expr = Construct<u32>(Expr(123u));
-  WrapInFunction(expr);
+    auto* expr = Construct<u32>(Expr(123_u));
+    WrapInFunction(expr);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(expr), nullptr);
-  ASSERT_TRUE(TypeOf(expr)->Is<sem::U32>());
+    ASSERT_NE(TypeOf(expr), nullptr);
+    ASSERT_TRUE(TypeOf(expr)->Is<sem::U32>());
 
-  auto* call = Sem().Get(expr);
-  ASSERT_NE(call, nullptr);
-  auto* ctor = call->Target()->As<sem::TypeConstructor>();
-  ASSERT_NE(ctor, nullptr);
-  EXPECT_EQ(call->Type(), ctor->ReturnType());
-  ASSERT_EQ(ctor->Parameters().size(), 1u);
-  EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::U32>());
+    auto* call = Sem().Get(expr);
+    ASSERT_NE(call, nullptr);
+    auto* ctor = call->Target()->As<sem::TypeConstructor>();
+    ASSERT_NE(ctor, nullptr);
+    EXPECT_EQ(call->Type(), ctor->ReturnType());
+    ASSERT_EQ(ctor->Parameters().size(), 1u);
+    EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::U32>());
 }
 
 TEST_F(ResolverTypeConstructorValidationTest, Expr_Construct_f32_Success) {
-  auto* expr = Construct<f32>(Expr(1.23f));
-  WrapInFunction(expr);
+    auto* expr = Construct<f32>(Expr(1.23f));
+    WrapInFunction(expr);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(expr), nullptr);
-  ASSERT_TRUE(TypeOf(expr)->Is<sem::F32>());
+    ASSERT_NE(TypeOf(expr), nullptr);
+    ASSERT_TRUE(TypeOf(expr)->Is<sem::F32>());
 
-  auto* call = Sem().Get(expr);
-  ASSERT_NE(call, nullptr);
-  auto* ctor = call->Target()->As<sem::TypeConstructor>();
-  ASSERT_NE(ctor, nullptr);
-  EXPECT_EQ(call->Type(), ctor->ReturnType());
-  ASSERT_EQ(ctor->Parameters().size(), 1u);
-  EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::F32>());
+    auto* call = Sem().Get(expr);
+    ASSERT_NE(call, nullptr);
+    auto* ctor = call->Target()->As<sem::TypeConstructor>();
+    ASSERT_NE(ctor, nullptr);
+    EXPECT_EQ(call->Type(), ctor->ReturnType());
+    ASSERT_EQ(ctor->Parameters().size(), 1u);
+    EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::F32>());
 }
 
 TEST_F(ResolverTypeConstructorValidationTest, Expr_Convert_f32_to_i32_Success) {
-  auto* expr = Construct<i32>(1.23f);
-  WrapInFunction(expr);
+    auto* expr = Construct<i32>(1.23f);
+    WrapInFunction(expr);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(expr), nullptr);
-  ASSERT_TRUE(TypeOf(expr)->Is<sem::I32>());
+    ASSERT_NE(TypeOf(expr), nullptr);
+    ASSERT_TRUE(TypeOf(expr)->Is<sem::I32>());
 
-  auto* call = Sem().Get(expr);
-  ASSERT_NE(call, nullptr);
-  auto* ctor = call->Target()->As<sem::TypeConversion>();
-  ASSERT_NE(ctor, nullptr);
-  EXPECT_EQ(call->Type(), ctor->ReturnType());
-  ASSERT_EQ(ctor->Parameters().size(), 1u);
-  EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::F32>());
+    auto* call = Sem().Get(expr);
+    ASSERT_NE(call, nullptr);
+    auto* ctor = call->Target()->As<sem::TypeConversion>();
+    ASSERT_NE(ctor, nullptr);
+    EXPECT_EQ(call->Type(), ctor->ReturnType());
+    ASSERT_EQ(ctor->Parameters().size(), 1u);
+    EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::F32>());
 }
 
 TEST_F(ResolverTypeConstructorValidationTest, Expr_Convert_i32_to_u32_Success) {
-  auto* expr = Construct<u32>(123);
-  WrapInFunction(expr);
+    auto* expr = Construct<u32>(123_i);
+    WrapInFunction(expr);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(expr), nullptr);
-  ASSERT_TRUE(TypeOf(expr)->Is<sem::U32>());
+    ASSERT_NE(TypeOf(expr), nullptr);
+    ASSERT_TRUE(TypeOf(expr)->Is<sem::U32>());
 
-  auto* call = Sem().Get(expr);
-  ASSERT_NE(call, nullptr);
-  auto* ctor = call->Target()->As<sem::TypeConversion>();
-  ASSERT_NE(ctor, nullptr);
-  EXPECT_EQ(call->Type(), ctor->ReturnType());
-  ASSERT_EQ(ctor->Parameters().size(), 1u);
-  EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::I32>());
+    auto* call = Sem().Get(expr);
+    ASSERT_NE(call, nullptr);
+    auto* ctor = call->Target()->As<sem::TypeConversion>();
+    ASSERT_NE(ctor, nullptr);
+    EXPECT_EQ(call->Type(), ctor->ReturnType());
+    ASSERT_EQ(ctor->Parameters().size(), 1u);
+    EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::I32>());
 }
 
 TEST_F(ResolverTypeConstructorValidationTest, Expr_Convert_u32_to_f32_Success) {
-  auto* expr = Construct<f32>(123u);
-  WrapInFunction(expr);
+    auto* expr = Construct<f32>(123_u);
+    WrapInFunction(expr);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(expr), nullptr);
-  ASSERT_TRUE(TypeOf(expr)->Is<sem::F32>());
+    ASSERT_NE(TypeOf(expr), nullptr);
+    ASSERT_TRUE(TypeOf(expr)->Is<sem::F32>());
 
-  auto* call = Sem().Get(expr);
-  ASSERT_NE(call, nullptr);
-  auto* ctor = call->Target()->As<sem::TypeConversion>();
-  ASSERT_NE(ctor, nullptr);
-  EXPECT_EQ(call->Type(), ctor->ReturnType());
-  ASSERT_EQ(ctor->Parameters().size(), 1u);
-  EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::U32>());
+    auto* call = Sem().Get(expr);
+    ASSERT_NE(call, nullptr);
+    auto* ctor = call->Target()->As<sem::TypeConversion>();
+    ASSERT_NE(ctor, nullptr);
+    EXPECT_EQ(call->Type(), ctor->ReturnType());
+    ASSERT_EQ(ctor->Parameters().size(), 1u);
+    EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::U32>());
 }
 
 }  // namespace ScalarConstructor
@@ -751,1451 +727,1312 @@
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec2F32_Error_ScalarArgumentTypeMismatch) {
-  auto* tc = vec2<f32>(Expr(Source{{12, 34}}, 1), 1.0f);
-  WrapInFunction(tc);
+    auto* tc = vec2<f32>(Expr(Source{{12, 34}}, 1_i), 1.0f);
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: type in vector constructor does not match vector "
-            "type: expected 'f32', found 'i32'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: type in vector constructor does not match vector "
+              "type: expected 'f32', found 'i32'");
 }
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec2U32_Error_ScalarArgumentTypeMismatch) {
-  auto* tc = vec2<u32>(1u, Expr(Source{{12, 34}}, 1));
-  WrapInFunction(tc);
+    auto* tc = vec2<u32>(1_u, Expr(Source{{12, 34}}, 1_i));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: type in vector constructor does not match vector "
-            "type: expected 'u32', found 'i32'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: type in vector constructor does not match vector "
+              "type: expected 'u32', found 'i32'");
 }
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec2I32_Error_ScalarArgumentTypeMismatch) {
-  auto* tc = vec2<i32>(Expr(Source{{12, 34}}, 1u), 1);
-  WrapInFunction(tc);
+    auto* tc = vec2<i32>(Expr(Source{{12, 34}}, 1_u), 1_i);
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: type in vector constructor does not match vector "
-            "type: expected 'i32', found 'u32'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: type in vector constructor does not match vector "
+              "type: expected 'i32', found 'u32'");
 }
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec2Bool_Error_ScalarArgumentTypeMismatch) {
-  auto* tc = vec2<bool>(true, Expr(Source{{12, 34}}, 1));
-  WrapInFunction(tc);
+    auto* tc = vec2<bool>(true, Expr(Source{{12, 34}}, 1_i));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: type in vector constructor does not match vector "
-            "type: expected 'bool', found 'i32'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: type in vector constructor does not match vector "
+              "type: expected 'bool', found 'i32'");
 }
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec2_Error_Vec3ArgumentCardinalityTooLarge) {
-  auto* tc = vec2<f32>(Construct(Source{{12, 34}}, ty.vec3<f32>()));
-  WrapInFunction(tc);
+    auto* tc = vec2<f32>(Construct(Source{{12, 34}}, ty.vec3<f32>()));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: attempted to construct 'vec2<f32>' with 3 component(s)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: attempted to construct 'vec2<f32>' with 3 component(s)");
 }
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec2_Error_Vec4ArgumentCardinalityTooLarge) {
-  auto* tc = vec2<f32>(Construct(Source{{12, 34}}, ty.vec4<f32>()));
-  WrapInFunction(tc);
+    auto* tc = vec2<f32>(Construct(Source{{12, 34}}, ty.vec4<f32>()));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: attempted to construct 'vec2<f32>' with 4 component(s)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: attempted to construct 'vec2<f32>' with 4 component(s)");
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec2_Error_TooManyArgumentsScalar) {
-  auto* tc =
-      vec2<f32>(Expr(Source{{12, 34}}, 1.0f), Expr(Source{{12, 40}}, 1.0f),
-                Expr(Source{{12, 46}}, 1.0f));
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec2_Error_TooManyArgumentsScalar) {
+    auto* tc = vec2<f32>(Expr(Source{{12, 34}}, 1.0f), Expr(Source{{12, 40}}, 1.0f),
+                         Expr(Source{{12, 46}}, 1.0f));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: attempted to construct 'vec2<f32>' with 3 component(s)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: attempted to construct 'vec2<f32>' with 3 component(s)");
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec2_Error_TooManyArgumentsVector) {
-  auto* tc = vec2<f32>(Construct(Source{{12, 34}}, ty.vec2<f32>()),
-                       Construct(Source{{12, 40}}, ty.vec2<f32>()));
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec2_Error_TooManyArgumentsVector) {
+    auto* tc = vec2<f32>(Construct(Source{{12, 34}}, ty.vec2<f32>()),
+                         Construct(Source{{12, 40}}, ty.vec2<f32>()));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: attempted to construct 'vec2<f32>' with 4 component(s)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: attempted to construct 'vec2<f32>' with 4 component(s)");
 }
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec2_Error_TooManyArgumentsVectorAndScalar) {
-  auto* tc = vec2<f32>(Construct(Source{{12, 34}}, ty.vec2<f32>()),
-                       Expr(Source{{12, 40}}, 1.0f));
-  WrapInFunction(tc);
+    auto* tc = vec2<f32>(Construct(Source{{12, 34}}, ty.vec2<f32>()), Expr(Source{{12, 40}}, 1.0f));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: attempted to construct 'vec2<f32>' with 3 component(s)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: attempted to construct 'vec2<f32>' with 3 component(s)");
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec2_Error_InvalidArgumentType) {
-  auto* tc = vec2<f32>(Construct(Source{{12, 34}}, ty.mat2x2<f32>()));
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec2_Error_InvalidArgumentType) {
+    auto* tc = vec2<f32>(Construct(Source{{12, 34}}, ty.mat2x2<f32>()));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: expected vector or scalar type in vector "
-            "constructor; found: mat2x2<f32>");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: expected vector or scalar type in vector "
+              "constructor; found: mat2x2<f32>");
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec2_Success_ZeroValue) {
-  auto* tc = vec2<f32>();
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec2_Success_ZeroValue) {
+    auto* tc = vec2<f32>();
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(tc), nullptr);
-  ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 2u);
+    ASSERT_NE(TypeOf(tc), nullptr);
+    ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 2u);
 
-  auto* call = Sem().Get(tc);
-  ASSERT_NE(call, nullptr);
-  auto* ctor = call->Target()->As<sem::TypeConstructor>();
-  ASSERT_NE(ctor, nullptr);
-  EXPECT_EQ(call->Type(), ctor->ReturnType());
-  ASSERT_EQ(ctor->Parameters().size(), 0u);
+    auto* call = Sem().Get(tc);
+    ASSERT_NE(call, nullptr);
+    auto* ctor = call->Target()->As<sem::TypeConstructor>();
+    ASSERT_NE(ctor, nullptr);
+    EXPECT_EQ(call->Type(), ctor->ReturnType());
+    ASSERT_EQ(ctor->Parameters().size(), 0u);
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec2F32_Success_Scalar) {
-  auto* tc = vec2<f32>(1.0f, 1.0f);
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec2F32_Success_Scalar) {
+    auto* tc = vec2<f32>(1.0f, 1.0f);
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(tc), nullptr);
-  ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 2u);
+    ASSERT_NE(TypeOf(tc), nullptr);
+    ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 2u);
 
-  auto* call = Sem().Get(tc);
-  ASSERT_NE(call, nullptr);
-  auto* ctor = call->Target()->As<sem::TypeConstructor>();
-  ASSERT_NE(ctor, nullptr);
-  EXPECT_EQ(call->Type(), ctor->ReturnType());
-  ASSERT_EQ(ctor->Parameters().size(), 2u);
-  EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::F32>());
-  EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::F32>());
+    auto* call = Sem().Get(tc);
+    ASSERT_NE(call, nullptr);
+    auto* ctor = call->Target()->As<sem::TypeConstructor>();
+    ASSERT_NE(ctor, nullptr);
+    EXPECT_EQ(call->Type(), ctor->ReturnType());
+    ASSERT_EQ(ctor->Parameters().size(), 2u);
+    EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::F32>());
+    EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::F32>());
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec2U32_Success_Scalar) {
-  auto* tc = vec2<u32>(1u, 1u);
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec2U32_Success_Scalar) {
+    auto* tc = vec2<u32>(1_u, 1_u);
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(tc), nullptr);
-  ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::U32>());
-  EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 2u);
+    ASSERT_NE(TypeOf(tc), nullptr);
+    ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::U32>());
+    EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 2u);
 
-  auto* call = Sem().Get(tc);
-  ASSERT_NE(call, nullptr);
-  auto* ctor = call->Target()->As<sem::TypeConstructor>();
-  ASSERT_NE(ctor, nullptr);
-  EXPECT_EQ(call->Type(), ctor->ReturnType());
-  ASSERT_EQ(ctor->Parameters().size(), 2u);
-  EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::U32>());
-  EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::U32>());
+    auto* call = Sem().Get(tc);
+    ASSERT_NE(call, nullptr);
+    auto* ctor = call->Target()->As<sem::TypeConstructor>();
+    ASSERT_NE(ctor, nullptr);
+    EXPECT_EQ(call->Type(), ctor->ReturnType());
+    ASSERT_EQ(ctor->Parameters().size(), 2u);
+    EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::U32>());
+    EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::U32>());
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec2I32_Success_Scalar) {
-  auto* tc = vec2<i32>(1, 1);
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec2I32_Success_Scalar) {
+    auto* tc = vec2<i32>(1_i, 1_i);
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(tc), nullptr);
-  ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::I32>());
-  EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 2u);
+    ASSERT_NE(TypeOf(tc), nullptr);
+    ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::I32>());
+    EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 2u);
 
-  auto* call = Sem().Get(tc);
-  ASSERT_NE(call, nullptr);
-  auto* ctor = call->Target()->As<sem::TypeConstructor>();
-  ASSERT_NE(ctor, nullptr);
-  EXPECT_EQ(call->Type(), ctor->ReturnType());
-  ASSERT_EQ(ctor->Parameters().size(), 2u);
-  EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::I32>());
-  EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::I32>());
+    auto* call = Sem().Get(tc);
+    ASSERT_NE(call, nullptr);
+    auto* ctor = call->Target()->As<sem::TypeConstructor>();
+    ASSERT_NE(ctor, nullptr);
+    EXPECT_EQ(call->Type(), ctor->ReturnType());
+    ASSERT_EQ(ctor->Parameters().size(), 2u);
+    EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::I32>());
+    EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::I32>());
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec2Bool_Success_Scalar) {
-  auto* tc = vec2<bool>(true, false);
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec2Bool_Success_Scalar) {
+    auto* tc = vec2<bool>(true, false);
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(tc), nullptr);
-  ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::Bool>());
-  EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 2u);
+    ASSERT_NE(TypeOf(tc), nullptr);
+    ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::Bool>());
+    EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 2u);
 
-  auto* call = Sem().Get(tc);
-  ASSERT_NE(call, nullptr);
-  auto* ctor = call->Target()->As<sem::TypeConstructor>();
-  ASSERT_NE(ctor, nullptr);
-  EXPECT_EQ(call->Type(), ctor->ReturnType());
-  ASSERT_EQ(ctor->Parameters().size(), 2u);
-  EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Bool>());
-  EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::Bool>());
+    auto* call = Sem().Get(tc);
+    ASSERT_NE(call, nullptr);
+    auto* ctor = call->Target()->As<sem::TypeConstructor>();
+    ASSERT_NE(ctor, nullptr);
+    EXPECT_EQ(call->Type(), ctor->ReturnType());
+    ASSERT_EQ(ctor->Parameters().size(), 2u);
+    EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Bool>());
+    EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::Bool>());
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec2_Success_Identity) {
-  auto* tc = vec2<f32>(vec2<f32>());
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec2_Success_Identity) {
+    auto* tc = vec2<f32>(vec2<f32>());
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(tc), nullptr);
-  ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 2u);
+    ASSERT_NE(TypeOf(tc), nullptr);
+    ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 2u);
 
-  auto* call = Sem().Get(tc);
-  ASSERT_NE(call, nullptr);
-  auto* ctor = call->Target()->As<sem::TypeConstructor>();
-  ASSERT_NE(ctor, nullptr);
-  EXPECT_EQ(call->Type(), ctor->ReturnType());
-  ASSERT_EQ(ctor->Parameters().size(), 1u);
-  EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Vector>());
+    auto* call = Sem().Get(tc);
+    ASSERT_NE(call, nullptr);
+    auto* ctor = call->Target()->As<sem::TypeConstructor>();
+    ASSERT_NE(ctor, nullptr);
+    EXPECT_EQ(call->Type(), ctor->ReturnType());
+    ASSERT_EQ(ctor->Parameters().size(), 1u);
+    EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Vector>());
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec2_Success_Vec2TypeConversion) {
-  auto* tc = vec2<f32>(vec2<i32>());
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec2_Success_Vec2TypeConversion) {
+    auto* tc = vec2<f32>(vec2<i32>());
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(tc), nullptr);
-  ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 2u);
+    ASSERT_NE(TypeOf(tc), nullptr);
+    ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 2u);
 
-  auto* call = Sem().Get(tc);
-  ASSERT_NE(call, nullptr);
-  auto* ctor = call->Target()->As<sem::TypeConversion>();
-  ASSERT_NE(ctor, nullptr);
-  EXPECT_EQ(call->Type(), ctor->ReturnType());
-  ASSERT_EQ(ctor->Parameters().size(), 1u);
-  EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Vector>());
+    auto* call = Sem().Get(tc);
+    ASSERT_NE(call, nullptr);
+    auto* ctor = call->Target()->As<sem::TypeConversion>();
+    ASSERT_NE(ctor, nullptr);
+    EXPECT_EQ(call->Type(), ctor->ReturnType());
+    ASSERT_EQ(ctor->Parameters().size(), 1u);
+    EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Vector>());
 }
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec3F32_Error_ScalarArgumentTypeMismatch) {
-  auto* tc = vec3<f32>(1.0f, 1.0f, Expr(Source{{12, 34}}, 1));
-  WrapInFunction(tc);
+    auto* tc = vec3<f32>(1.0f, 1.0f, Expr(Source{{12, 34}}, 1_i));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: type in vector constructor does not match vector "
-            "type: expected 'f32', found 'i32'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: type in vector constructor does not match vector "
+              "type: expected 'f32', found 'i32'");
 }
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec3U32_Error_ScalarArgumentTypeMismatch) {
-  auto* tc = vec3<u32>(1u, Expr(Source{{12, 34}}, 1), 1u);
-  WrapInFunction(tc);
+    auto* tc = vec3<u32>(1_u, Expr(Source{{12, 34}}, 1_i), 1_u);
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: type in vector constructor does not match vector "
-            "type: expected 'u32', found 'i32'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: type in vector constructor does not match vector "
+              "type: expected 'u32', found 'i32'");
 }
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec3I32_Error_ScalarArgumentTypeMismatch) {
-  auto* tc = vec3<i32>(1, Expr(Source{{12, 34}}, 1u), 1);
-  WrapInFunction(tc);
+    auto* tc = vec3<i32>(1_i, Expr(Source{{12, 34}}, 1_u), 1_i);
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: type in vector constructor does not match vector "
-            "type: expected 'i32', found 'u32'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: type in vector constructor does not match vector "
+              "type: expected 'i32', found 'u32'");
 }
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec3Bool_Error_ScalarArgumentTypeMismatch) {
-  auto* tc = vec3<bool>(true, Expr(Source{{12, 34}}, 1), false);
-  WrapInFunction(tc);
+    auto* tc = vec3<bool>(true, Expr(Source{{12, 34}}, 1_i), false);
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: type in vector constructor does not match vector "
-            "type: expected 'bool', found 'i32'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: type in vector constructor does not match vector "
+              "type: expected 'bool', found 'i32'");
 }
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec3_Error_Vec4ArgumentCardinalityTooLarge) {
-  auto* tc = vec3<f32>(Construct(Source{{12, 34}}, ty.vec4<f32>()));
-  WrapInFunction(tc);
+    auto* tc = vec3<f32>(Construct(Source{{12, 34}}, ty.vec4<f32>()));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: attempted to construct 'vec3<f32>' with 4 component(s)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: attempted to construct 'vec3<f32>' with 4 component(s)");
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec3_Error_TooFewArgumentsScalar) {
-  auto* tc =
-      vec3<f32>(Expr(Source{{12, 34}}, 1.0f), Expr(Source{{12, 40}}, 1.0f));
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3_Error_TooFewArgumentsScalar) {
+    auto* tc = vec3<f32>(Expr(Source{{12, 34}}, 1.0f), Expr(Source{{12, 40}}, 1.0f));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: attempted to construct 'vec3<f32>' with 2 component(s)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: attempted to construct 'vec3<f32>' with 2 component(s)");
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec3_Error_TooManyArgumentsScalar) {
-  auto* tc =
-      vec3<f32>(Expr(Source{{12, 34}}, 1.0f), Expr(Source{{12, 40}}, 1.0f),
-                Expr(Source{{12, 46}}, 1.0f), Expr(Source{{12, 52}}, 1.0f));
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3_Error_TooManyArgumentsScalar) {
+    auto* tc = vec3<f32>(Expr(Source{{12, 34}}, 1.0f), Expr(Source{{12, 40}}, 1.0f),
+                         Expr(Source{{12, 46}}, 1.0f), Expr(Source{{12, 52}}, 1.0f));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: attempted to construct 'vec3<f32>' with 4 component(s)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: attempted to construct 'vec3<f32>' with 4 component(s)");
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec3_Error_TooFewArgumentsVec2) {
-  auto* tc = vec3<f32>(Construct(Source{{12, 34}}, ty.vec2<f32>()));
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3_Error_TooFewArgumentsVec2) {
+    auto* tc = vec3<f32>(Construct(Source{{12, 34}}, ty.vec2<f32>()));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: attempted to construct 'vec3<f32>' with 2 component(s)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: attempted to construct 'vec3<f32>' with 2 component(s)");
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec3_Error_TooManyArgumentsVec2) {
-  auto* tc = vec3<f32>(Construct(Source{{12, 34}}, ty.vec2<f32>()),
-                       Construct(Source{{12, 40}}, ty.vec2<f32>()));
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3_Error_TooManyArgumentsVec2) {
+    auto* tc = vec3<f32>(Construct(Source{{12, 34}}, ty.vec2<f32>()),
+                         Construct(Source{{12, 40}}, ty.vec2<f32>()));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: attempted to construct 'vec3<f32>' with 4 component(s)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: attempted to construct 'vec3<f32>' with 4 component(s)");
 }
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec3_Error_TooManyArgumentsVec2AndScalar) {
-  auto* tc =
-      vec3<f32>(Construct(Source{{12, 34}}, ty.vec2<f32>()),
-                Expr(Source{{12, 40}}, 1.0f), Expr(Source{{12, 46}}, 1.0f));
-  WrapInFunction(tc);
+    auto* tc = vec3<f32>(Construct(Source{{12, 34}}, ty.vec2<f32>()), Expr(Source{{12, 40}}, 1.0f),
+                         Expr(Source{{12, 46}}, 1.0f));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: attempted to construct 'vec3<f32>' with 4 component(s)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: attempted to construct 'vec3<f32>' with 4 component(s)");
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec3_Error_TooManyArgumentsVec3) {
-  auto* tc = vec3<f32>(Construct(Source{{12, 34}}, ty.vec3<f32>()),
-                       Expr(Source{{12, 40}}, 1.0f));
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3_Error_TooManyArgumentsVec3) {
+    auto* tc = vec3<f32>(Construct(Source{{12, 34}}, ty.vec3<f32>()), Expr(Source{{12, 40}}, 1.0f));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: attempted to construct 'vec3<f32>' with 4 component(s)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: attempted to construct 'vec3<f32>' with 4 component(s)");
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec3_Error_InvalidArgumentType) {
-  auto* tc = vec3<f32>(Construct(Source{{12, 34}}, ty.mat2x2<f32>()));
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3_Error_InvalidArgumentType) {
+    auto* tc = vec3<f32>(Construct(Source{{12, 34}}, ty.mat2x2<f32>()));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: expected vector or scalar type in vector "
-            "constructor; found: mat2x2<f32>");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: expected vector or scalar type in vector "
+              "constructor; found: mat2x2<f32>");
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec3_Success_ZeroValue) {
-  auto* tc = vec3<f32>();
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3_Success_ZeroValue) {
+    auto* tc = vec3<f32>();
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(tc), nullptr);
-  ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 3u);
+    ASSERT_NE(TypeOf(tc), nullptr);
+    ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 3u);
 
-  auto* call = Sem().Get(tc);
-  ASSERT_NE(call, nullptr);
-  auto* ctor = call->Target()->As<sem::TypeConstructor>();
-  ASSERT_NE(ctor, nullptr);
-  EXPECT_EQ(call->Type(), ctor->ReturnType());
-  ASSERT_EQ(ctor->Parameters().size(), 0u);
+    auto* call = Sem().Get(tc);
+    ASSERT_NE(call, nullptr);
+    auto* ctor = call->Target()->As<sem::TypeConstructor>();
+    ASSERT_NE(ctor, nullptr);
+    EXPECT_EQ(call->Type(), ctor->ReturnType());
+    ASSERT_EQ(ctor->Parameters().size(), 0u);
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec3F32_Success_Scalar) {
-  auto* tc = vec3<f32>(1.0f, 1.0f, 1.0f);
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3F32_Success_Scalar) {
+    auto* tc = vec3<f32>(1.0f, 1.0f, 1.0f);
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(tc), nullptr);
-  ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 3u);
+    ASSERT_NE(TypeOf(tc), nullptr);
+    ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 3u);
 
-  auto* call = Sem().Get(tc);
-  ASSERT_NE(call, nullptr);
-  auto* ctor = call->Target()->As<sem::TypeConstructor>();
-  ASSERT_NE(ctor, nullptr);
-  EXPECT_EQ(call->Type(), ctor->ReturnType());
-  ASSERT_EQ(ctor->Parameters().size(), 3u);
-  EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::F32>());
-  EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::F32>());
-  EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::F32>());
+    auto* call = Sem().Get(tc);
+    ASSERT_NE(call, nullptr);
+    auto* ctor = call->Target()->As<sem::TypeConstructor>();
+    ASSERT_NE(ctor, nullptr);
+    EXPECT_EQ(call->Type(), ctor->ReturnType());
+    ASSERT_EQ(ctor->Parameters().size(), 3u);
+    EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::F32>());
+    EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::F32>());
+    EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::F32>());
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec3U32_Success_Scalar) {
-  auto* tc = vec3<u32>(1u, 1u, 1u);
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3U32_Success_Scalar) {
+    auto* tc = vec3<u32>(1_u, 1_u, 1_u);
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(tc), nullptr);
-  ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::U32>());
-  EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 3u);
+    ASSERT_NE(TypeOf(tc), nullptr);
+    ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::U32>());
+    EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 3u);
 
-  auto* call = Sem().Get(tc);
-  ASSERT_NE(call, nullptr);
-  auto* ctor = call->Target()->As<sem::TypeConstructor>();
-  ASSERT_NE(ctor, nullptr);
-  EXPECT_EQ(call->Type(), ctor->ReturnType());
-  ASSERT_EQ(ctor->Parameters().size(), 3u);
-  EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::U32>());
-  EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::U32>());
-  EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::U32>());
+    auto* call = Sem().Get(tc);
+    ASSERT_NE(call, nullptr);
+    auto* ctor = call->Target()->As<sem::TypeConstructor>();
+    ASSERT_NE(ctor, nullptr);
+    EXPECT_EQ(call->Type(), ctor->ReturnType());
+    ASSERT_EQ(ctor->Parameters().size(), 3u);
+    EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::U32>());
+    EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::U32>());
+    EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::U32>());
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec3I32_Success_Scalar) {
-  auto* tc = vec3<i32>(1, 1, 1);
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3I32_Success_Scalar) {
+    auto* tc = vec3<i32>(1_i, 1_i, 1_i);
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(tc), nullptr);
-  ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::I32>());
-  EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 3u);
+    ASSERT_NE(TypeOf(tc), nullptr);
+    ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::I32>());
+    EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 3u);
 
-  auto* call = Sem().Get(tc);
-  ASSERT_NE(call, nullptr);
-  auto* ctor = call->Target()->As<sem::TypeConstructor>();
-  ASSERT_NE(ctor, nullptr);
-  EXPECT_EQ(call->Type(), ctor->ReturnType());
-  ASSERT_EQ(ctor->Parameters().size(), 3u);
-  EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::I32>());
-  EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::I32>());
-  EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::I32>());
+    auto* call = Sem().Get(tc);
+    ASSERT_NE(call, nullptr);
+    auto* ctor = call->Target()->As<sem::TypeConstructor>();
+    ASSERT_NE(ctor, nullptr);
+    EXPECT_EQ(call->Type(), ctor->ReturnType());
+    ASSERT_EQ(ctor->Parameters().size(), 3u);
+    EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::I32>());
+    EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::I32>());
+    EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::I32>());
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec3Bool_Success_Scalar) {
-  auto* tc = vec3<bool>(true, false, true);
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3Bool_Success_Scalar) {
+    auto* tc = vec3<bool>(true, false, true);
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(tc), nullptr);
-  ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::Bool>());
-  EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 3u);
+    ASSERT_NE(TypeOf(tc), nullptr);
+    ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::Bool>());
+    EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 3u);
 
-  auto* call = Sem().Get(tc);
-  ASSERT_NE(call, nullptr);
-  auto* ctor = call->Target()->As<sem::TypeConstructor>();
-  ASSERT_NE(ctor, nullptr);
-  EXPECT_EQ(call->Type(), ctor->ReturnType());
-  ASSERT_EQ(ctor->Parameters().size(), 3u);
-  EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Bool>());
-  EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::Bool>());
-  EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::Bool>());
+    auto* call = Sem().Get(tc);
+    ASSERT_NE(call, nullptr);
+    auto* ctor = call->Target()->As<sem::TypeConstructor>();
+    ASSERT_NE(ctor, nullptr);
+    EXPECT_EQ(call->Type(), ctor->ReturnType());
+    ASSERT_EQ(ctor->Parameters().size(), 3u);
+    EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Bool>());
+    EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::Bool>());
+    EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::Bool>());
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec3_Success_Vec2AndScalar) {
-  auto* tc = vec3<f32>(vec2<f32>(), 1.0f);
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3_Success_Vec2AndScalar) {
+    auto* tc = vec3<f32>(vec2<f32>(), 1.0f);
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(tc), nullptr);
-  ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 3u);
+    ASSERT_NE(TypeOf(tc), nullptr);
+    ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 3u);
 
-  auto* call = Sem().Get(tc);
-  ASSERT_NE(call, nullptr);
-  auto* ctor = call->Target()->As<sem::TypeConstructor>();
-  ASSERT_NE(ctor, nullptr);
-  EXPECT_EQ(call->Type(), ctor->ReturnType());
-  ASSERT_EQ(ctor->Parameters().size(), 2u);
-  EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Vector>());
-  EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::F32>());
+    auto* call = Sem().Get(tc);
+    ASSERT_NE(call, nullptr);
+    auto* ctor = call->Target()->As<sem::TypeConstructor>();
+    ASSERT_NE(ctor, nullptr);
+    EXPECT_EQ(call->Type(), ctor->ReturnType());
+    ASSERT_EQ(ctor->Parameters().size(), 2u);
+    EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Vector>());
+    EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::F32>());
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec3_Success_ScalarAndVec2) {
-  auto* tc = vec3<f32>(1.0f, vec2<f32>());
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3_Success_ScalarAndVec2) {
+    auto* tc = vec3<f32>(1.0f, vec2<f32>());
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(tc), nullptr);
-  ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 3u);
+    ASSERT_NE(TypeOf(tc), nullptr);
+    ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 3u);
 
-  auto* call = Sem().Get(tc);
-  ASSERT_NE(call, nullptr);
-  auto* ctor = call->Target()->As<sem::TypeConstructor>();
-  ASSERT_NE(ctor, nullptr);
-  EXPECT_EQ(call->Type(), ctor->ReturnType());
-  ASSERT_EQ(ctor->Parameters().size(), 2u);
-  EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::F32>());
-  EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::Vector>());
+    auto* call = Sem().Get(tc);
+    ASSERT_NE(call, nullptr);
+    auto* ctor = call->Target()->As<sem::TypeConstructor>();
+    ASSERT_NE(ctor, nullptr);
+    EXPECT_EQ(call->Type(), ctor->ReturnType());
+    ASSERT_EQ(ctor->Parameters().size(), 2u);
+    EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::F32>());
+    EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::Vector>());
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec3_Success_Identity) {
-  auto* tc = vec3<f32>(vec3<f32>());
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3_Success_Identity) {
+    auto* tc = vec3<f32>(vec3<f32>());
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(tc), nullptr);
-  ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 3u);
+    ASSERT_NE(TypeOf(tc), nullptr);
+    ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 3u);
 
-  auto* call = Sem().Get(tc);
-  ASSERT_NE(call, nullptr);
-  auto* ctor = call->Target()->As<sem::TypeConstructor>();
-  ASSERT_NE(ctor, nullptr);
-  EXPECT_EQ(call->Type(), ctor->ReturnType());
-  ASSERT_EQ(ctor->Parameters().size(), 1u);
-  EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Vector>());
+    auto* call = Sem().Get(tc);
+    ASSERT_NE(call, nullptr);
+    auto* ctor = call->Target()->As<sem::TypeConstructor>();
+    ASSERT_NE(ctor, nullptr);
+    EXPECT_EQ(call->Type(), ctor->ReturnType());
+    ASSERT_EQ(ctor->Parameters().size(), 1u);
+    EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Vector>());
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec3_Success_Vec3TypeConversion) {
-  auto* tc = vec3<f32>(vec3<i32>());
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec3_Success_Vec3TypeConversion) {
+    auto* tc = vec3<f32>(vec3<i32>());
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(tc), nullptr);
-  ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 3u);
+    ASSERT_NE(TypeOf(tc), nullptr);
+    ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 3u);
 
-  auto* call = Sem().Get(tc);
-  ASSERT_NE(call, nullptr);
-  auto* ctor = call->Target()->As<sem::TypeConversion>();
-  ASSERT_NE(ctor, nullptr);
-  EXPECT_EQ(call->Type(), ctor->ReturnType());
-  ASSERT_EQ(ctor->Parameters().size(), 1u);
-  EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Vector>());
+    auto* call = Sem().Get(tc);
+    ASSERT_NE(call, nullptr);
+    auto* ctor = call->Target()->As<sem::TypeConversion>();
+    ASSERT_NE(ctor, nullptr);
+    EXPECT_EQ(call->Type(), ctor->ReturnType());
+    ASSERT_EQ(ctor->Parameters().size(), 1u);
+    EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Vector>());
 }
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec4F32_Error_ScalarArgumentTypeMismatch) {
-  auto* tc = vec4<f32>(1.0f, 1.0f, Expr(Source{{12, 34}}, 1), 1.0f);
-  WrapInFunction(tc);
+    auto* tc = vec4<f32>(1.0f, 1.0f, Expr(Source{{12, 34}}, 1_i), 1.0f);
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: type in vector constructor does not match vector "
-            "type: expected 'f32', found 'i32'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: type in vector constructor does not match vector "
+              "type: expected 'f32', found 'i32'");
 }
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec4U32_Error_ScalarArgumentTypeMismatch) {
-  auto* tc = vec4<u32>(1u, 1u, Expr(Source{{12, 34}}, 1), 1u);
-  WrapInFunction(tc);
+    auto* tc = vec4<u32>(1_u, 1_u, Expr(Source{{12, 34}}, 1_i), 1_u);
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: type in vector constructor does not match vector "
-            "type: expected 'u32', found 'i32'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: type in vector constructor does not match vector "
+              "type: expected 'u32', found 'i32'");
 }
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec4I32_Error_ScalarArgumentTypeMismatch) {
-  auto* tc = vec4<i32>(1, 1, Expr(Source{{12, 34}}, 1u), 1);
-  WrapInFunction(tc);
+    auto* tc = vec4<i32>(1_i, 1_i, Expr(Source{{12, 34}}, 1_u), 1_i);
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: type in vector constructor does not match vector "
-            "type: expected 'i32', found 'u32'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: type in vector constructor does not match vector "
+              "type: expected 'i32', found 'u32'");
 }
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec4Bool_Error_ScalarArgumentTypeMismatch) {
-  auto* tc = vec4<bool>(true, false, Expr(Source{{12, 34}}, 1), true);
-  WrapInFunction(tc);
+    auto* tc = vec4<bool>(true, false, Expr(Source{{12, 34}}, 1_i), true);
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: type in vector constructor does not match vector "
-            "type: expected 'bool', found 'i32'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: type in vector constructor does not match vector "
+              "type: expected 'bool', found 'i32'");
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec4_Error_TooFewArgumentsScalar) {
-  auto* tc =
-      vec4<f32>(Expr(Source{{12, 34}}, 1.0f), Expr(Source{{12, 40}}, 1.0f),
-                Expr(Source{{12, 46}}, 1.0f));
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4_Error_TooFewArgumentsScalar) {
+    auto* tc = vec4<f32>(Expr(Source{{12, 34}}, 1.0f), Expr(Source{{12, 40}}, 1.0f),
+                         Expr(Source{{12, 46}}, 1.0f));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: attempted to construct 'vec4<f32>' with 3 component(s)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: attempted to construct 'vec4<f32>' with 3 component(s)");
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec4_Error_TooManyArgumentsScalar) {
-  auto* tc =
-      vec4<f32>(Expr(Source{{12, 34}}, 1.0f), Expr(Source{{12, 40}}, 1.0f),
-                Expr(Source{{12, 46}}, 1.0f), Expr(Source{{12, 52}}, 1.0f),
-                Expr(Source{{12, 58}}, 1.0f));
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4_Error_TooManyArgumentsScalar) {
+    auto* tc = vec4<f32>(Expr(Source{{12, 34}}, 1.0f), Expr(Source{{12, 40}}, 1.0f),
+                         Expr(Source{{12, 46}}, 1.0f), Expr(Source{{12, 52}}, 1.0f),
+                         Expr(Source{{12, 58}}, 1.0f));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: attempted to construct 'vec4<f32>' with 5 component(s)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: attempted to construct 'vec4<f32>' with 5 component(s)");
 }
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec4_Error_TooFewArgumentsVec2AndScalar) {
-  auto* tc = vec4<f32>(Construct(Source{{12, 34}}, ty.vec2<f32>()),
-                       Expr(Source{{12, 40}}, 1.0f));
-  WrapInFunction(tc);
+    auto* tc = vec4<f32>(Construct(Source{{12, 34}}, ty.vec2<f32>()), Expr(Source{{12, 40}}, 1.0f));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: attempted to construct 'vec4<f32>' with 3 component(s)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: attempted to construct 'vec4<f32>' with 3 component(s)");
 }
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec4_Error_TooManyArgumentsVec2AndScalars) {
-  auto* tc = vec4<f32>(
-      Construct(Source{{12, 34}}, ty.vec2<f32>()), Expr(Source{{12, 40}}, 1.0f),
-      Expr(Source{{12, 46}}, 1.0f), Expr(Source{{12, 52}}, 1.0f));
-  WrapInFunction(tc);
+    auto* tc = vec4<f32>(Construct(Source{{12, 34}}, ty.vec2<f32>()), Expr(Source{{12, 40}}, 1.0f),
+                         Expr(Source{{12, 46}}, 1.0f), Expr(Source{{12, 52}}, 1.0f));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: attempted to construct 'vec4<f32>' with 5 component(s)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: attempted to construct 'vec4<f32>' with 5 component(s)");
 }
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec4_Error_TooManyArgumentsVec2Vec2Scalar) {
-  auto* tc = vec4<f32>(Construct(Source{{12, 34}}, ty.vec2<f32>()),
-                       Construct(Source{{12, 40}}, ty.vec2<f32>()),
-                       Expr(Source{{12, 46}}, 1.0f));
-  WrapInFunction(tc);
+    auto* tc = vec4<f32>(Construct(Source{{12, 34}}, ty.vec2<f32>()),
+                         Construct(Source{{12, 40}}, ty.vec2<f32>()), Expr(Source{{12, 46}}, 1.0f));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: attempted to construct 'vec4<f32>' with 5 component(s)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: attempted to construct 'vec4<f32>' with 5 component(s)");
 }
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec4_Error_TooManyArgumentsVec2Vec2Vec2) {
-  auto* tc = vec4<f32>(Construct(Source{{12, 34}}, ty.vec2<f32>()),
-                       Construct(Source{{12, 40}}, ty.vec2<f32>()),
-                       Construct(Source{{12, 40}}, ty.vec2<f32>()));
-  WrapInFunction(tc);
+    auto* tc = vec4<f32>(Construct(Source{{12, 34}}, ty.vec2<f32>()),
+                         Construct(Source{{12, 40}}, ty.vec2<f32>()),
+                         Construct(Source{{12, 40}}, ty.vec2<f32>()));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: attempted to construct 'vec4<f32>' with 6 component(s)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: attempted to construct 'vec4<f32>' with 6 component(s)");
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec4_Error_TooFewArgumentsVec3) {
-  auto* tc = vec4<f32>(Construct(Source{{12, 34}}, ty.vec3<f32>()));
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4_Error_TooFewArgumentsVec3) {
+    auto* tc = vec4<f32>(Construct(Source{{12, 34}}, ty.vec3<f32>()));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: attempted to construct 'vec4<f32>' with 3 component(s)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: attempted to construct 'vec4<f32>' with 3 component(s)");
 }
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec4_Error_TooManyArgumentsVec3AndScalars) {
-  auto* tc =
-      vec4<f32>(Construct(Source{{12, 34}}, ty.vec3<f32>()),
-                Expr(Source{{12, 40}}, 1.0f), Expr(Source{{12, 46}}, 1.0f));
-  WrapInFunction(tc);
+    auto* tc = vec4<f32>(Construct(Source{{12, 34}}, ty.vec3<f32>()), Expr(Source{{12, 40}}, 1.0f),
+                         Expr(Source{{12, 46}}, 1.0f));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: attempted to construct 'vec4<f32>' with 5 component(s)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: attempted to construct 'vec4<f32>' with 5 component(s)");
 }
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec4_Error_TooManyArgumentsVec3AndVec2) {
-  auto* tc = vec4<f32>(Construct(Source{{12, 34}}, ty.vec3<f32>()),
-                       Construct(Source{{12, 40}}, ty.vec2<f32>()));
-  WrapInFunction(tc);
+    auto* tc = vec4<f32>(Construct(Source{{12, 34}}, ty.vec3<f32>()),
+                         Construct(Source{{12, 40}}, ty.vec2<f32>()));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: attempted to construct 'vec4<f32>' with 5 component(s)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: attempted to construct 'vec4<f32>' with 5 component(s)");
 }
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec4_Error_TooManyArgumentsVec2AndVec3) {
-  auto* tc = vec4<f32>(Construct(Source{{12, 34}}, ty.vec2<f32>()),
-                       Construct(Source{{12, 40}}, ty.vec3<f32>()));
-  WrapInFunction(tc);
+    auto* tc = vec4<f32>(Construct(Source{{12, 34}}, ty.vec2<f32>()),
+                         Construct(Source{{12, 40}}, ty.vec3<f32>()));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: attempted to construct 'vec4<f32>' with 5 component(s)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: attempted to construct 'vec4<f32>' with 5 component(s)");
 }
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vec4_Error_TooManyArgumentsVec3AndVec3) {
-  auto* tc = vec4<f32>(Construct(Source{{12, 34}}, ty.vec3<f32>()),
-                       Construct(Source{{12, 40}}, ty.vec3<f32>()));
-  WrapInFunction(tc);
+    auto* tc = vec4<f32>(Construct(Source{{12, 34}}, ty.vec3<f32>()),
+                         Construct(Source{{12, 40}}, ty.vec3<f32>()));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: attempted to construct 'vec4<f32>' with 6 component(s)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: attempted to construct 'vec4<f32>' with 6 component(s)");
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec4_Error_InvalidArgumentType) {
-  auto* tc = vec4<f32>(Construct(Source{{12, 34}}, ty.mat2x2<f32>()));
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4_Error_InvalidArgumentType) {
+    auto* tc = vec4<f32>(Construct(Source{{12, 34}}, ty.mat2x2<f32>()));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: expected vector or scalar type in vector "
-            "constructor; found: mat2x2<f32>");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: expected vector or scalar type in vector "
+              "constructor; found: mat2x2<f32>");
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec4_Success_ZeroValue) {
-  auto* tc = vec4<f32>();
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4_Success_ZeroValue) {
+    auto* tc = vec4<f32>();
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(tc), nullptr);
-  ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
+    ASSERT_NE(TypeOf(tc), nullptr);
+    ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec4F32_Success_Scalar) {
-  auto* tc = vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f);
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4F32_Success_Scalar) {
+    auto* tc = vec4<f32>(1.0f, 1.0f, 1.0f, 1.0f);
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(tc), nullptr);
-  ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
+    ASSERT_NE(TypeOf(tc), nullptr);
+    ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec4U32_Success_Scalar) {
-  auto* tc = vec4<u32>(1u, 1u, 1u, 1u);
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4U32_Success_Scalar) {
+    auto* tc = vec4<u32>(1_u, 1_u, 1_u, 1_u);
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(tc), nullptr);
-  ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::U32>());
-  EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
+    ASSERT_NE(TypeOf(tc), nullptr);
+    ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::U32>());
+    EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec4I32_Success_Scalar) {
-  auto* tc = vec4<i32>(1, 1, 1, 1);
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4I32_Success_Scalar) {
+    auto* tc = vec4<i32>(1_i, 1_i, 1_i, 1_i);
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(tc), nullptr);
-  ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::I32>());
-  EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
+    ASSERT_NE(TypeOf(tc), nullptr);
+    ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::I32>());
+    EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec4Bool_Success_Scalar) {
-  auto* tc = vec4<bool>(true, false, true, false);
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4Bool_Success_Scalar) {
+    auto* tc = vec4<bool>(true, false, true, false);
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(tc), nullptr);
-  ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::Bool>());
-  EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
+    ASSERT_NE(TypeOf(tc), nullptr);
+    ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::Bool>());
+    EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec4_Success_Vec2ScalarScalar) {
-  auto* tc = vec4<f32>(vec2<f32>(), 1.0f, 1.0f);
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4_Success_Vec2ScalarScalar) {
+    auto* tc = vec4<f32>(vec2<f32>(), 1.0f, 1.0f);
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(tc), nullptr);
-  ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
+    ASSERT_NE(TypeOf(tc), nullptr);
+    ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec4_Success_ScalarVec2Scalar) {
-  auto* tc = vec4<f32>(1.0f, vec2<f32>(), 1.0f);
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4_Success_ScalarVec2Scalar) {
+    auto* tc = vec4<f32>(1.0f, vec2<f32>(), 1.0f);
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(tc), nullptr);
-  ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
+    ASSERT_NE(TypeOf(tc), nullptr);
+    ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec4_Success_ScalarScalarVec2) {
-  auto* tc = vec4<f32>(1.0f, 1.0f, vec2<f32>());
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4_Success_ScalarScalarVec2) {
+    auto* tc = vec4<f32>(1.0f, 1.0f, vec2<f32>());
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(tc), nullptr);
-  ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
+    ASSERT_NE(TypeOf(tc), nullptr);
+    ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec4_Success_Vec2AndVec2) {
-  auto* tc = vec4<f32>(vec2<f32>(), vec2<f32>());
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4_Success_Vec2AndVec2) {
+    auto* tc = vec4<f32>(vec2<f32>(), vec2<f32>());
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(tc), nullptr);
-  ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
+    ASSERT_NE(TypeOf(tc), nullptr);
+    ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec4_Success_Vec3AndScalar) {
-  auto* tc = vec4<f32>(vec3<f32>(), 1.0f);
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4_Success_Vec3AndScalar) {
+    auto* tc = vec4<f32>(vec3<f32>(), 1.0f);
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(tc), nullptr);
-  ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
+    ASSERT_NE(TypeOf(tc), nullptr);
+    ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec4_Success_ScalarAndVec3) {
-  auto* tc = vec4<f32>(1.0f, vec3<f32>());
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4_Success_ScalarAndVec3) {
+    auto* tc = vec4<f32>(1.0f, vec3<f32>());
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(tc), nullptr);
-  ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
+    ASSERT_NE(TypeOf(tc), nullptr);
+    ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec4_Success_Identity) {
-  auto* tc = vec4<f32>(vec4<f32>());
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4_Success_Identity) {
+    auto* tc = vec4<f32>(vec4<f32>());
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(tc), nullptr);
-  ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
+    ASSERT_NE(TypeOf(tc), nullptr);
+    ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vec4_Success_Vec4TypeConversion) {
-  auto* tc = vec4<f32>(vec4<i32>());
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vec4_Success_Vec4TypeConversion) {
+    auto* tc = vec4<f32>(vec4<i32>());
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(tc), nullptr);
-  ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
+    ASSERT_NE(TypeOf(tc), nullptr);
+    ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
 }
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_NestedVectorConstructors_InnerError) {
-  auto* tc = vec4<f32>(vec4<f32>(1.0f, 1.0f,
-                                 vec3<f32>(Expr(Source{{12, 34}}, 1.0f),
-                                           Expr(Source{{12, 34}}, 1.0f))),
-                       1.0f);
-  WrapInFunction(tc);
+    auto* tc =
+        vec4<f32>(vec4<f32>(1.0f, 1.0f,
+                            vec3<f32>(Expr(Source{{12, 34}}, 1.0f), Expr(Source{{12, 34}}, 1.0f))),
+                  1.0f);
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: attempted to construct 'vec3<f32>' with 2 component(s)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: attempted to construct 'vec3<f32>' with 2 component(s)");
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_NestedVectorConstructors_Success) {
-  auto* tc = vec4<f32>(vec3<f32>(vec2<f32>(1.0f, 1.0f), 1.0f), 1.0f);
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_NestedVectorConstructors_Success) {
+    auto* tc = vec4<f32>(vec3<f32>(vec2<f32>(1.0f, 1.0f), 1.0f), 1.0f);
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_NE(TypeOf(tc), nullptr);
-  ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
+    ASSERT_NE(TypeOf(tc), nullptr);
+    ASSERT_TRUE(TypeOf(tc)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(tc)->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(TypeOf(tc)->As<sem::Vector>()->Width(), 4u);
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vector_Alias_Argument_Error) {
-  auto* alias = Alias("UnsignedInt", ty.u32());
-  Global("uint_var", ty.Of(alias), ast::StorageClass::kPrivate);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vector_Alias_Argument_Error) {
+    auto* alias = Alias("UnsignedInt", ty.u32());
+    Global("uint_var", ty.Of(alias), ast::StorageClass::kPrivate);
 
-  auto* tc = vec2<f32>(Expr(Source{{12, 34}}, "uint_var"));
-  WrapInFunction(tc);
+    auto* tc = vec2<f32>(Expr(Source{{12, 34}}, "uint_var"));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: type in vector constructor does not match vector "
-            "type: expected 'f32', found 'u32'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: type in vector constructor does not match vector "
+              "type: expected 'f32', found 'u32'");
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vector_Alias_Argument_Success) {
-  auto* f32_alias = Alias("Float32", ty.f32());
-  auto* vec2_alias = Alias("VectorFloat2", ty.vec2<f32>());
-  Global("my_f32", ty.Of(f32_alias), ast::StorageClass::kPrivate);
-  Global("my_vec2", ty.Of(vec2_alias), ast::StorageClass::kPrivate);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vector_Alias_Argument_Success) {
+    auto* f32_alias = Alias("Float32", ty.f32());
+    auto* vec2_alias = Alias("VectorFloat2", ty.vec2<f32>());
+    Global("my_f32", ty.Of(f32_alias), ast::StorageClass::kPrivate);
+    Global("my_vec2", ty.Of(vec2_alias), ast::StorageClass::kPrivate);
 
-  auto* tc = vec3<f32>("my_vec2", "my_f32");
-  WrapInFunction(tc);
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    auto* tc = vec3<f32>("my_vec2", "my_f32");
+    WrapInFunction(tc);
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vector_ElementTypeAlias_Error) {
-  auto* f32_alias = Alias("Float32", ty.f32());
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vector_ElementTypeAlias_Error) {
+    auto* f32_alias = Alias("Float32", ty.f32());
 
-  // vec2<Float32>(1.0f, 1u)
-  auto* vec_type = ty.vec(ty.Of(f32_alias), 2);
-  auto* tc =
-      Construct(Source{{12, 34}}, vec_type, 1.0f, Expr(Source{{12, 40}}, 1u));
-  WrapInFunction(tc);
+    // vec2<Float32>(1.0f, 1u)
+    auto* vec_type = ty.vec(ty.Of(f32_alias), 2);
+    auto* tc = Construct(Source{{12, 34}}, vec_type, 1.0f, Expr(Source{{12, 40}}, 1_u));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:40 error: type in vector constructor does not match vector "
-            "type: expected 'f32', found 'u32'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:40 error: type in vector constructor does not match vector "
+              "type: expected 'f32', found 'u32'");
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_Constructor_Vector_ElementTypeAlias_Success) {
-  auto* f32_alias = Alias("Float32", ty.f32());
+TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Vector_ElementTypeAlias_Success) {
+    auto* f32_alias = Alias("Float32", ty.f32());
 
-  // vec2<Float32>(1.0f, 1.0f)
-  auto* vec_type = ty.vec(ty.Of(f32_alias), 2);
-  auto* tc = Construct(Source{{12, 34}}, vec_type, 1.0f, 1.0f);
-  WrapInFunction(tc);
+    // vec2<Float32>(1.0f, 1.0f)
+    auto* vec_type = ty.vec(ty.Of(f32_alias), 2);
+    auto* tc = Construct(Source{{12, 34}}, vec_type, 1.0f, 1.0f);
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vector_ArgumentElementTypeAlias_Error) {
-  auto* f32_alias = Alias("Float32", ty.f32());
+    auto* f32_alias = Alias("Float32", ty.f32());
 
-  // vec3<u32>(vec<Float32>(), 1.0f)
-  auto* vec_type = ty.vec(ty.Of(f32_alias), 2);
-  auto* tc = vec3<u32>(Construct(Source{{12, 34}}, vec_type), 1.0f);
-  WrapInFunction(tc);
+    // vec3<u32>(vec<Float32>(), 1.0f)
+    auto* vec_type = ty.vec(ty.Of(f32_alias), 2);
+    auto* tc = vec3<u32>(Construct(Source{{12, 34}}, vec_type), 1.0f);
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: type in vector constructor does not match vector "
-            "type: expected 'u32', found 'f32'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: type in vector constructor does not match vector "
+              "type: expected 'u32', found 'f32'");
 }
 
 TEST_F(ResolverTypeConstructorValidationTest,
        Expr_Constructor_Vector_ArgumentElementTypeAlias_Success) {
-  auto* f32_alias = Alias("Float32", ty.f32());
+    auto* f32_alias = Alias("Float32", ty.f32());
 
-  // vec3<f32>(vec<Float32>(), 1.0f)
-  auto* vec_type = ty.vec(ty.Of(f32_alias), 2);
-  auto* tc = vec3<f32>(Construct(Source{{12, 34}}, vec_type), 1.0f);
-  WrapInFunction(tc);
+    // vec3<f32>(vec<Float32>(), 1.0f)
+    auto* vec_type = ty.vec(ty.Of(f32_alias), 2);
+    auto* tc = vec3<f32>(Construct(Source{{12, 34}}, vec_type), 1.0f);
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverTypeConstructorValidationTest, InferVec2ElementTypeFromScalars) {
-  auto* vec2_bool =
-      Construct(create<ast::Vector>(nullptr, 2), Expr(true), Expr(false));
-  auto* vec2_i32 = Construct(create<ast::Vector>(nullptr, 2), Expr(1), Expr(2));
-  auto* vec2_u32 =
-      Construct(create<ast::Vector>(nullptr, 2), Expr(1u), Expr(2u));
-  auto* vec2_f32 =
-      Construct(create<ast::Vector>(nullptr, 2), Expr(1.0f), Expr(2.0f));
-  WrapInFunction(vec2_bool, vec2_i32, vec2_u32, vec2_f32);
+    auto* vec2_bool = Construct(create<ast::Vector>(nullptr, 2), Expr(true), Expr(false));
+    auto* vec2_i32 = Construct(create<ast::Vector>(nullptr, 2), Expr(1_i), Expr(2_i));
+    auto* vec2_u32 = Construct(create<ast::Vector>(nullptr, 2), Expr(1_u), Expr(2_u));
+    auto* vec2_f32 = Construct(create<ast::Vector>(nullptr, 2), Expr(1.0f), Expr(2.0f));
+    WrapInFunction(vec2_bool, vec2_i32, vec2_u32, vec2_f32);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_TRUE(TypeOf(vec2_bool)->Is<sem::Vector>());
-  ASSERT_TRUE(TypeOf(vec2_i32)->Is<sem::Vector>());
-  ASSERT_TRUE(TypeOf(vec2_u32)->Is<sem::Vector>());
-  ASSERT_TRUE(TypeOf(vec2_f32)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(vec2_bool)->As<sem::Vector>()->type()->Is<sem::Bool>());
-  EXPECT_TRUE(TypeOf(vec2_i32)->As<sem::Vector>()->type()->Is<sem::I32>());
-  EXPECT_TRUE(TypeOf(vec2_u32)->As<sem::Vector>()->type()->Is<sem::U32>());
-  EXPECT_TRUE(TypeOf(vec2_f32)->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(TypeOf(vec2_bool)->As<sem::Vector>()->Width(), 2u);
-  EXPECT_EQ(TypeOf(vec2_i32)->As<sem::Vector>()->Width(), 2u);
-  EXPECT_EQ(TypeOf(vec2_u32)->As<sem::Vector>()->Width(), 2u);
-  EXPECT_EQ(TypeOf(vec2_f32)->As<sem::Vector>()->Width(), 2u);
-  EXPECT_EQ(TypeOf(vec2_bool), TypeOf(vec2_bool->target.type));
-  EXPECT_EQ(TypeOf(vec2_i32), TypeOf(vec2_i32->target.type));
-  EXPECT_EQ(TypeOf(vec2_u32), TypeOf(vec2_u32->target.type));
-  EXPECT_EQ(TypeOf(vec2_f32), TypeOf(vec2_f32->target.type));
+    ASSERT_TRUE(TypeOf(vec2_bool)->Is<sem::Vector>());
+    ASSERT_TRUE(TypeOf(vec2_i32)->Is<sem::Vector>());
+    ASSERT_TRUE(TypeOf(vec2_u32)->Is<sem::Vector>());
+    ASSERT_TRUE(TypeOf(vec2_f32)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(vec2_bool)->As<sem::Vector>()->type()->Is<sem::Bool>());
+    EXPECT_TRUE(TypeOf(vec2_i32)->As<sem::Vector>()->type()->Is<sem::I32>());
+    EXPECT_TRUE(TypeOf(vec2_u32)->As<sem::Vector>()->type()->Is<sem::U32>());
+    EXPECT_TRUE(TypeOf(vec2_f32)->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(TypeOf(vec2_bool)->As<sem::Vector>()->Width(), 2u);
+    EXPECT_EQ(TypeOf(vec2_i32)->As<sem::Vector>()->Width(), 2u);
+    EXPECT_EQ(TypeOf(vec2_u32)->As<sem::Vector>()->Width(), 2u);
+    EXPECT_EQ(TypeOf(vec2_f32)->As<sem::Vector>()->Width(), 2u);
+    EXPECT_EQ(TypeOf(vec2_bool), TypeOf(vec2_bool->target.type));
+    EXPECT_EQ(TypeOf(vec2_i32), TypeOf(vec2_i32->target.type));
+    EXPECT_EQ(TypeOf(vec2_u32), TypeOf(vec2_u32->target.type));
+    EXPECT_EQ(TypeOf(vec2_f32), TypeOf(vec2_f32->target.type));
 }
 
 TEST_F(ResolverTypeConstructorValidationTest, InferVec2ElementTypeFromVec2) {
-  auto* vec2_bool =
-      Construct(create<ast::Vector>(nullptr, 2), vec2<bool>(true, false));
-  auto* vec2_i32 = Construct(create<ast::Vector>(nullptr, 2), vec2<i32>(1, 2));
-  auto* vec2_u32 =
-      Construct(create<ast::Vector>(nullptr, 2), vec2<u32>(1u, 2u));
-  auto* vec2_f32 =
-      Construct(create<ast::Vector>(nullptr, 2), vec2<f32>(1.0f, 2.0f));
-  WrapInFunction(vec2_bool, vec2_i32, vec2_u32, vec2_f32);
+    auto* vec2_bool = Construct(create<ast::Vector>(nullptr, 2), vec2<bool>(true, false));
+    auto* vec2_i32 = Construct(create<ast::Vector>(nullptr, 2), vec2<i32>(1_i, 2_i));
+    auto* vec2_u32 = Construct(create<ast::Vector>(nullptr, 2), vec2<u32>(1_u, 2_u));
+    auto* vec2_f32 = Construct(create<ast::Vector>(nullptr, 2), vec2<f32>(1.0f, 2.0f));
+    WrapInFunction(vec2_bool, vec2_i32, vec2_u32, vec2_f32);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_TRUE(TypeOf(vec2_bool)->Is<sem::Vector>());
-  ASSERT_TRUE(TypeOf(vec2_i32)->Is<sem::Vector>());
-  ASSERT_TRUE(TypeOf(vec2_u32)->Is<sem::Vector>());
-  ASSERT_TRUE(TypeOf(vec2_f32)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(vec2_bool)->As<sem::Vector>()->type()->Is<sem::Bool>());
-  EXPECT_TRUE(TypeOf(vec2_i32)->As<sem::Vector>()->type()->Is<sem::I32>());
-  EXPECT_TRUE(TypeOf(vec2_u32)->As<sem::Vector>()->type()->Is<sem::U32>());
-  EXPECT_TRUE(TypeOf(vec2_f32)->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(TypeOf(vec2_bool)->As<sem::Vector>()->Width(), 2u);
-  EXPECT_EQ(TypeOf(vec2_i32)->As<sem::Vector>()->Width(), 2u);
-  EXPECT_EQ(TypeOf(vec2_u32)->As<sem::Vector>()->Width(), 2u);
-  EXPECT_EQ(TypeOf(vec2_f32)->As<sem::Vector>()->Width(), 2u);
-  EXPECT_EQ(TypeOf(vec2_bool), TypeOf(vec2_bool->target.type));
-  EXPECT_EQ(TypeOf(vec2_i32), TypeOf(vec2_i32->target.type));
-  EXPECT_EQ(TypeOf(vec2_u32), TypeOf(vec2_u32->target.type));
-  EXPECT_EQ(TypeOf(vec2_f32), TypeOf(vec2_f32->target.type));
+    ASSERT_TRUE(TypeOf(vec2_bool)->Is<sem::Vector>());
+    ASSERT_TRUE(TypeOf(vec2_i32)->Is<sem::Vector>());
+    ASSERT_TRUE(TypeOf(vec2_u32)->Is<sem::Vector>());
+    ASSERT_TRUE(TypeOf(vec2_f32)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(vec2_bool)->As<sem::Vector>()->type()->Is<sem::Bool>());
+    EXPECT_TRUE(TypeOf(vec2_i32)->As<sem::Vector>()->type()->Is<sem::I32>());
+    EXPECT_TRUE(TypeOf(vec2_u32)->As<sem::Vector>()->type()->Is<sem::U32>());
+    EXPECT_TRUE(TypeOf(vec2_f32)->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(TypeOf(vec2_bool)->As<sem::Vector>()->Width(), 2u);
+    EXPECT_EQ(TypeOf(vec2_i32)->As<sem::Vector>()->Width(), 2u);
+    EXPECT_EQ(TypeOf(vec2_u32)->As<sem::Vector>()->Width(), 2u);
+    EXPECT_EQ(TypeOf(vec2_f32)->As<sem::Vector>()->Width(), 2u);
+    EXPECT_EQ(TypeOf(vec2_bool), TypeOf(vec2_bool->target.type));
+    EXPECT_EQ(TypeOf(vec2_i32), TypeOf(vec2_i32->target.type));
+    EXPECT_EQ(TypeOf(vec2_u32), TypeOf(vec2_u32->target.type));
+    EXPECT_EQ(TypeOf(vec2_f32), TypeOf(vec2_f32->target.type));
 }
 
 TEST_F(ResolverTypeConstructorValidationTest, InferVec3ElementTypeFromScalars) {
-  auto* vec3_bool = Construct(create<ast::Vector>(nullptr, 3), Expr(true),
-                              Expr(false), Expr(true));
-  auto* vec3_i32 =
-      Construct(create<ast::Vector>(nullptr, 3), Expr(1), Expr(2), Expr(3));
-  auto* vec3_u32 =
-      Construct(create<ast::Vector>(nullptr, 3), Expr(1u), Expr(2u), Expr(3u));
-  auto* vec3_f32 = Construct(create<ast::Vector>(nullptr, 3), Expr(1.0f),
-                             Expr(2.0f), Expr(3.0f));
-  WrapInFunction(vec3_bool, vec3_i32, vec3_u32, vec3_f32);
+    auto* vec3_bool =
+        Construct(create<ast::Vector>(nullptr, 3), Expr(true), Expr(false), Expr(true));
+    auto* vec3_i32 = Construct(create<ast::Vector>(nullptr, 3), Expr(1_i), Expr(2_i), Expr(3_i));
+    auto* vec3_u32 = Construct(create<ast::Vector>(nullptr, 3), Expr(1_u), Expr(2_u), Expr(3_u));
+    auto* vec3_f32 = Construct(create<ast::Vector>(nullptr, 3), Expr(1.0f), Expr(2.0f), Expr(3.0f));
+    WrapInFunction(vec3_bool, vec3_i32, vec3_u32, vec3_f32);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_TRUE(TypeOf(vec3_bool)->Is<sem::Vector>());
-  ASSERT_TRUE(TypeOf(vec3_i32)->Is<sem::Vector>());
-  ASSERT_TRUE(TypeOf(vec3_u32)->Is<sem::Vector>());
-  ASSERT_TRUE(TypeOf(vec3_f32)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(vec3_bool)->As<sem::Vector>()->type()->Is<sem::Bool>());
-  EXPECT_TRUE(TypeOf(vec3_i32)->As<sem::Vector>()->type()->Is<sem::I32>());
-  EXPECT_TRUE(TypeOf(vec3_u32)->As<sem::Vector>()->type()->Is<sem::U32>());
-  EXPECT_TRUE(TypeOf(vec3_f32)->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(TypeOf(vec3_bool)->As<sem::Vector>()->Width(), 3u);
-  EXPECT_EQ(TypeOf(vec3_i32)->As<sem::Vector>()->Width(), 3u);
-  EXPECT_EQ(TypeOf(vec3_u32)->As<sem::Vector>()->Width(), 3u);
-  EXPECT_EQ(TypeOf(vec3_f32)->As<sem::Vector>()->Width(), 3u);
-  EXPECT_EQ(TypeOf(vec3_bool), TypeOf(vec3_bool->target.type));
-  EXPECT_EQ(TypeOf(vec3_i32), TypeOf(vec3_i32->target.type));
-  EXPECT_EQ(TypeOf(vec3_u32), TypeOf(vec3_u32->target.type));
-  EXPECT_EQ(TypeOf(vec3_f32), TypeOf(vec3_f32->target.type));
+    ASSERT_TRUE(TypeOf(vec3_bool)->Is<sem::Vector>());
+    ASSERT_TRUE(TypeOf(vec3_i32)->Is<sem::Vector>());
+    ASSERT_TRUE(TypeOf(vec3_u32)->Is<sem::Vector>());
+    ASSERT_TRUE(TypeOf(vec3_f32)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(vec3_bool)->As<sem::Vector>()->type()->Is<sem::Bool>());
+    EXPECT_TRUE(TypeOf(vec3_i32)->As<sem::Vector>()->type()->Is<sem::I32>());
+    EXPECT_TRUE(TypeOf(vec3_u32)->As<sem::Vector>()->type()->Is<sem::U32>());
+    EXPECT_TRUE(TypeOf(vec3_f32)->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(TypeOf(vec3_bool)->As<sem::Vector>()->Width(), 3u);
+    EXPECT_EQ(TypeOf(vec3_i32)->As<sem::Vector>()->Width(), 3u);
+    EXPECT_EQ(TypeOf(vec3_u32)->As<sem::Vector>()->Width(), 3u);
+    EXPECT_EQ(TypeOf(vec3_f32)->As<sem::Vector>()->Width(), 3u);
+    EXPECT_EQ(TypeOf(vec3_bool), TypeOf(vec3_bool->target.type));
+    EXPECT_EQ(TypeOf(vec3_i32), TypeOf(vec3_i32->target.type));
+    EXPECT_EQ(TypeOf(vec3_u32), TypeOf(vec3_u32->target.type));
+    EXPECT_EQ(TypeOf(vec3_f32), TypeOf(vec3_f32->target.type));
 }
 
 TEST_F(ResolverTypeConstructorValidationTest, InferVec3ElementTypeFromVec3) {
-  auto* vec3_bool =
-      Construct(create<ast::Vector>(nullptr, 3), vec3<bool>(true, false, true));
-  auto* vec3_i32 =
-      Construct(create<ast::Vector>(nullptr, 3), vec3<i32>(1, 2, 3));
-  auto* vec3_u32 =
-      Construct(create<ast::Vector>(nullptr, 3), vec3<u32>(1u, 2u, 3u));
-  auto* vec3_f32 =
-      Construct(create<ast::Vector>(nullptr, 3), vec3<f32>(1.0f, 2.0f, 3.0f));
-  WrapInFunction(vec3_bool, vec3_i32, vec3_u32, vec3_f32);
+    auto* vec3_bool = Construct(create<ast::Vector>(nullptr, 3), vec3<bool>(true, false, true));
+    auto* vec3_i32 = Construct(create<ast::Vector>(nullptr, 3), vec3<i32>(1_i, 2_i, 3_i));
+    auto* vec3_u32 = Construct(create<ast::Vector>(nullptr, 3), vec3<u32>(1_u, 2_u, 3_u));
+    auto* vec3_f32 = Construct(create<ast::Vector>(nullptr, 3), vec3<f32>(1.0f, 2.0f, 3.0f));
+    WrapInFunction(vec3_bool, vec3_i32, vec3_u32, vec3_f32);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_TRUE(TypeOf(vec3_bool)->Is<sem::Vector>());
-  ASSERT_TRUE(TypeOf(vec3_i32)->Is<sem::Vector>());
-  ASSERT_TRUE(TypeOf(vec3_u32)->Is<sem::Vector>());
-  ASSERT_TRUE(TypeOf(vec3_f32)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(vec3_bool)->As<sem::Vector>()->type()->Is<sem::Bool>());
-  EXPECT_TRUE(TypeOf(vec3_i32)->As<sem::Vector>()->type()->Is<sem::I32>());
-  EXPECT_TRUE(TypeOf(vec3_u32)->As<sem::Vector>()->type()->Is<sem::U32>());
-  EXPECT_TRUE(TypeOf(vec3_f32)->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(TypeOf(vec3_bool)->As<sem::Vector>()->Width(), 3u);
-  EXPECT_EQ(TypeOf(vec3_i32)->As<sem::Vector>()->Width(), 3u);
-  EXPECT_EQ(TypeOf(vec3_u32)->As<sem::Vector>()->Width(), 3u);
-  EXPECT_EQ(TypeOf(vec3_f32)->As<sem::Vector>()->Width(), 3u);
-  EXPECT_EQ(TypeOf(vec3_bool), TypeOf(vec3_bool->target.type));
-  EXPECT_EQ(TypeOf(vec3_i32), TypeOf(vec3_i32->target.type));
-  EXPECT_EQ(TypeOf(vec3_u32), TypeOf(vec3_u32->target.type));
-  EXPECT_EQ(TypeOf(vec3_f32), TypeOf(vec3_f32->target.type));
+    ASSERT_TRUE(TypeOf(vec3_bool)->Is<sem::Vector>());
+    ASSERT_TRUE(TypeOf(vec3_i32)->Is<sem::Vector>());
+    ASSERT_TRUE(TypeOf(vec3_u32)->Is<sem::Vector>());
+    ASSERT_TRUE(TypeOf(vec3_f32)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(vec3_bool)->As<sem::Vector>()->type()->Is<sem::Bool>());
+    EXPECT_TRUE(TypeOf(vec3_i32)->As<sem::Vector>()->type()->Is<sem::I32>());
+    EXPECT_TRUE(TypeOf(vec3_u32)->As<sem::Vector>()->type()->Is<sem::U32>());
+    EXPECT_TRUE(TypeOf(vec3_f32)->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(TypeOf(vec3_bool)->As<sem::Vector>()->Width(), 3u);
+    EXPECT_EQ(TypeOf(vec3_i32)->As<sem::Vector>()->Width(), 3u);
+    EXPECT_EQ(TypeOf(vec3_u32)->As<sem::Vector>()->Width(), 3u);
+    EXPECT_EQ(TypeOf(vec3_f32)->As<sem::Vector>()->Width(), 3u);
+    EXPECT_EQ(TypeOf(vec3_bool), TypeOf(vec3_bool->target.type));
+    EXPECT_EQ(TypeOf(vec3_i32), TypeOf(vec3_i32->target.type));
+    EXPECT_EQ(TypeOf(vec3_u32), TypeOf(vec3_u32->target.type));
+    EXPECT_EQ(TypeOf(vec3_f32), TypeOf(vec3_f32->target.type));
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       InferVec3ElementTypeFromScalarAndVec2) {
-  auto* vec3_bool = Construct(create<ast::Vector>(nullptr, 3), Expr(true),
-                              vec2<bool>(false, true));
-  auto* vec3_i32 =
-      Construct(create<ast::Vector>(nullptr, 3), Expr(1), vec2<i32>(2, 3));
-  auto* vec3_u32 =
-      Construct(create<ast::Vector>(nullptr, 3), Expr(1u), vec2<u32>(2u, 3u));
-  auto* vec3_f32 = Construct(create<ast::Vector>(nullptr, 3), Expr(1.0f),
-                             vec2<f32>(2.0f, 3.0f));
-  WrapInFunction(vec3_bool, vec3_i32, vec3_u32, vec3_f32);
+TEST_F(ResolverTypeConstructorValidationTest, InferVec3ElementTypeFromScalarAndVec2) {
+    auto* vec3_bool =
+        Construct(create<ast::Vector>(nullptr, 3), Expr(true), vec2<bool>(false, true));
+    auto* vec3_i32 = Construct(create<ast::Vector>(nullptr, 3), Expr(1_i), vec2<i32>(2_i, 3_i));
+    auto* vec3_u32 = Construct(create<ast::Vector>(nullptr, 3), Expr(1_u), vec2<u32>(2_u, 3_u));
+    auto* vec3_f32 = Construct(create<ast::Vector>(nullptr, 3), Expr(1.0f), vec2<f32>(2.0f, 3.0f));
+    WrapInFunction(vec3_bool, vec3_i32, vec3_u32, vec3_f32);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_TRUE(TypeOf(vec3_bool)->Is<sem::Vector>());
-  ASSERT_TRUE(TypeOf(vec3_i32)->Is<sem::Vector>());
-  ASSERT_TRUE(TypeOf(vec3_u32)->Is<sem::Vector>());
-  ASSERT_TRUE(TypeOf(vec3_f32)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(vec3_bool)->As<sem::Vector>()->type()->Is<sem::Bool>());
-  EXPECT_TRUE(TypeOf(vec3_i32)->As<sem::Vector>()->type()->Is<sem::I32>());
-  EXPECT_TRUE(TypeOf(vec3_u32)->As<sem::Vector>()->type()->Is<sem::U32>());
-  EXPECT_TRUE(TypeOf(vec3_f32)->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(TypeOf(vec3_bool)->As<sem::Vector>()->Width(), 3u);
-  EXPECT_EQ(TypeOf(vec3_i32)->As<sem::Vector>()->Width(), 3u);
-  EXPECT_EQ(TypeOf(vec3_u32)->As<sem::Vector>()->Width(), 3u);
-  EXPECT_EQ(TypeOf(vec3_f32)->As<sem::Vector>()->Width(), 3u);
-  EXPECT_EQ(TypeOf(vec3_bool), TypeOf(vec3_bool->target.type));
-  EXPECT_EQ(TypeOf(vec3_i32), TypeOf(vec3_i32->target.type));
-  EXPECT_EQ(TypeOf(vec3_u32), TypeOf(vec3_u32->target.type));
-  EXPECT_EQ(TypeOf(vec3_f32), TypeOf(vec3_f32->target.type));
+    ASSERT_TRUE(TypeOf(vec3_bool)->Is<sem::Vector>());
+    ASSERT_TRUE(TypeOf(vec3_i32)->Is<sem::Vector>());
+    ASSERT_TRUE(TypeOf(vec3_u32)->Is<sem::Vector>());
+    ASSERT_TRUE(TypeOf(vec3_f32)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(vec3_bool)->As<sem::Vector>()->type()->Is<sem::Bool>());
+    EXPECT_TRUE(TypeOf(vec3_i32)->As<sem::Vector>()->type()->Is<sem::I32>());
+    EXPECT_TRUE(TypeOf(vec3_u32)->As<sem::Vector>()->type()->Is<sem::U32>());
+    EXPECT_TRUE(TypeOf(vec3_f32)->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(TypeOf(vec3_bool)->As<sem::Vector>()->Width(), 3u);
+    EXPECT_EQ(TypeOf(vec3_i32)->As<sem::Vector>()->Width(), 3u);
+    EXPECT_EQ(TypeOf(vec3_u32)->As<sem::Vector>()->Width(), 3u);
+    EXPECT_EQ(TypeOf(vec3_f32)->As<sem::Vector>()->Width(), 3u);
+    EXPECT_EQ(TypeOf(vec3_bool), TypeOf(vec3_bool->target.type));
+    EXPECT_EQ(TypeOf(vec3_i32), TypeOf(vec3_i32->target.type));
+    EXPECT_EQ(TypeOf(vec3_u32), TypeOf(vec3_u32->target.type));
+    EXPECT_EQ(TypeOf(vec3_f32), TypeOf(vec3_f32->target.type));
 }
 
 TEST_F(ResolverTypeConstructorValidationTest, InferVec4ElementTypeFromScalars) {
-  auto* vec4_bool = Construct(create<ast::Vector>(nullptr, 4), Expr(true),
-                              Expr(false), Expr(true), Expr(false));
-  auto* vec4_i32 = Construct(create<ast::Vector>(nullptr, 4), Expr(1), Expr(2),
-                             Expr(3), Expr(4));
-  auto* vec4_u32 = Construct(create<ast::Vector>(nullptr, 4), Expr(1u),
-                             Expr(2u), Expr(3u), Expr(4u));
-  auto* vec4_f32 = Construct(create<ast::Vector>(nullptr, 4), Expr(1.0f),
-                             Expr(2.0f), Expr(3.0f), Expr(4.0f));
-  WrapInFunction(vec4_bool, vec4_i32, vec4_u32, vec4_f32);
+    auto* vec4_bool = Construct(create<ast::Vector>(nullptr, 4), Expr(true), Expr(false),
+                                Expr(true), Expr(false));
+    auto* vec4_i32 =
+        Construct(create<ast::Vector>(nullptr, 4), Expr(1_i), Expr(2_i), Expr(3_i), Expr(4_i));
+    auto* vec4_u32 =
+        Construct(create<ast::Vector>(nullptr, 4), Expr(1_u), Expr(2_u), Expr(3_u), Expr(4_u));
+    auto* vec4_f32 =
+        Construct(create<ast::Vector>(nullptr, 4), Expr(1.0f), Expr(2.0f), Expr(3.0f), Expr(4.0f));
+    WrapInFunction(vec4_bool, vec4_i32, vec4_u32, vec4_f32);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_TRUE(TypeOf(vec4_bool)->Is<sem::Vector>());
-  ASSERT_TRUE(TypeOf(vec4_i32)->Is<sem::Vector>());
-  ASSERT_TRUE(TypeOf(vec4_u32)->Is<sem::Vector>());
-  ASSERT_TRUE(TypeOf(vec4_f32)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(vec4_bool)->As<sem::Vector>()->type()->Is<sem::Bool>());
-  EXPECT_TRUE(TypeOf(vec4_i32)->As<sem::Vector>()->type()->Is<sem::I32>());
-  EXPECT_TRUE(TypeOf(vec4_u32)->As<sem::Vector>()->type()->Is<sem::U32>());
-  EXPECT_TRUE(TypeOf(vec4_f32)->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(TypeOf(vec4_bool)->As<sem::Vector>()->Width(), 4u);
-  EXPECT_EQ(TypeOf(vec4_i32)->As<sem::Vector>()->Width(), 4u);
-  EXPECT_EQ(TypeOf(vec4_u32)->As<sem::Vector>()->Width(), 4u);
-  EXPECT_EQ(TypeOf(vec4_f32)->As<sem::Vector>()->Width(), 4u);
-  EXPECT_EQ(TypeOf(vec4_bool), TypeOf(vec4_bool->target.type));
-  EXPECT_EQ(TypeOf(vec4_i32), TypeOf(vec4_i32->target.type));
-  EXPECT_EQ(TypeOf(vec4_u32), TypeOf(vec4_u32->target.type));
-  EXPECT_EQ(TypeOf(vec4_f32), TypeOf(vec4_f32->target.type));
+    ASSERT_TRUE(TypeOf(vec4_bool)->Is<sem::Vector>());
+    ASSERT_TRUE(TypeOf(vec4_i32)->Is<sem::Vector>());
+    ASSERT_TRUE(TypeOf(vec4_u32)->Is<sem::Vector>());
+    ASSERT_TRUE(TypeOf(vec4_f32)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(vec4_bool)->As<sem::Vector>()->type()->Is<sem::Bool>());
+    EXPECT_TRUE(TypeOf(vec4_i32)->As<sem::Vector>()->type()->Is<sem::I32>());
+    EXPECT_TRUE(TypeOf(vec4_u32)->As<sem::Vector>()->type()->Is<sem::U32>());
+    EXPECT_TRUE(TypeOf(vec4_f32)->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(TypeOf(vec4_bool)->As<sem::Vector>()->Width(), 4u);
+    EXPECT_EQ(TypeOf(vec4_i32)->As<sem::Vector>()->Width(), 4u);
+    EXPECT_EQ(TypeOf(vec4_u32)->As<sem::Vector>()->Width(), 4u);
+    EXPECT_EQ(TypeOf(vec4_f32)->As<sem::Vector>()->Width(), 4u);
+    EXPECT_EQ(TypeOf(vec4_bool), TypeOf(vec4_bool->target.type));
+    EXPECT_EQ(TypeOf(vec4_i32), TypeOf(vec4_i32->target.type));
+    EXPECT_EQ(TypeOf(vec4_u32), TypeOf(vec4_u32->target.type));
+    EXPECT_EQ(TypeOf(vec4_f32), TypeOf(vec4_f32->target.type));
 }
 
 TEST_F(ResolverTypeConstructorValidationTest, InferVec4ElementTypeFromVec4) {
-  auto* vec4_bool = Construct(create<ast::Vector>(nullptr, 4),
-                              vec4<bool>(true, false, true, false));
-  auto* vec4_i32 =
-      Construct(create<ast::Vector>(nullptr, 4), vec4<i32>(1, 2, 3, 4));
-  auto* vec4_u32 =
-      Construct(create<ast::Vector>(nullptr, 4), vec4<u32>(1u, 2u, 3u, 4u));
-  auto* vec4_f32 = Construct(create<ast::Vector>(nullptr, 4),
-                             vec4<f32>(1.0f, 2.0f, 3.0f, 4.0f));
-  WrapInFunction(vec4_bool, vec4_i32, vec4_u32, vec4_f32);
+    auto* vec4_bool =
+        Construct(create<ast::Vector>(nullptr, 4), vec4<bool>(true, false, true, false));
+    auto* vec4_i32 = Construct(create<ast::Vector>(nullptr, 4), vec4<i32>(1_i, 2_i, 3_i, 4_i));
+    auto* vec4_u32 = Construct(create<ast::Vector>(nullptr, 4), vec4<u32>(1_u, 2_u, 3_u, 4_u));
+    auto* vec4_f32 = Construct(create<ast::Vector>(nullptr, 4), vec4<f32>(1.0f, 2.0f, 3.0f, 4.0f));
+    WrapInFunction(vec4_bool, vec4_i32, vec4_u32, vec4_f32);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_TRUE(TypeOf(vec4_bool)->Is<sem::Vector>());
-  ASSERT_TRUE(TypeOf(vec4_i32)->Is<sem::Vector>());
-  ASSERT_TRUE(TypeOf(vec4_u32)->Is<sem::Vector>());
-  ASSERT_TRUE(TypeOf(vec4_f32)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(vec4_bool)->As<sem::Vector>()->type()->Is<sem::Bool>());
-  EXPECT_TRUE(TypeOf(vec4_i32)->As<sem::Vector>()->type()->Is<sem::I32>());
-  EXPECT_TRUE(TypeOf(vec4_u32)->As<sem::Vector>()->type()->Is<sem::U32>());
-  EXPECT_TRUE(TypeOf(vec4_f32)->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(TypeOf(vec4_bool)->As<sem::Vector>()->Width(), 4u);
-  EXPECT_EQ(TypeOf(vec4_i32)->As<sem::Vector>()->Width(), 4u);
-  EXPECT_EQ(TypeOf(vec4_u32)->As<sem::Vector>()->Width(), 4u);
-  EXPECT_EQ(TypeOf(vec4_f32)->As<sem::Vector>()->Width(), 4u);
-  EXPECT_EQ(TypeOf(vec4_bool), TypeOf(vec4_bool->target.type));
-  EXPECT_EQ(TypeOf(vec4_i32), TypeOf(vec4_i32->target.type));
-  EXPECT_EQ(TypeOf(vec4_u32), TypeOf(vec4_u32->target.type));
-  EXPECT_EQ(TypeOf(vec4_f32), TypeOf(vec4_f32->target.type));
+    ASSERT_TRUE(TypeOf(vec4_bool)->Is<sem::Vector>());
+    ASSERT_TRUE(TypeOf(vec4_i32)->Is<sem::Vector>());
+    ASSERT_TRUE(TypeOf(vec4_u32)->Is<sem::Vector>());
+    ASSERT_TRUE(TypeOf(vec4_f32)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(vec4_bool)->As<sem::Vector>()->type()->Is<sem::Bool>());
+    EXPECT_TRUE(TypeOf(vec4_i32)->As<sem::Vector>()->type()->Is<sem::I32>());
+    EXPECT_TRUE(TypeOf(vec4_u32)->As<sem::Vector>()->type()->Is<sem::U32>());
+    EXPECT_TRUE(TypeOf(vec4_f32)->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(TypeOf(vec4_bool)->As<sem::Vector>()->Width(), 4u);
+    EXPECT_EQ(TypeOf(vec4_i32)->As<sem::Vector>()->Width(), 4u);
+    EXPECT_EQ(TypeOf(vec4_u32)->As<sem::Vector>()->Width(), 4u);
+    EXPECT_EQ(TypeOf(vec4_f32)->As<sem::Vector>()->Width(), 4u);
+    EXPECT_EQ(TypeOf(vec4_bool), TypeOf(vec4_bool->target.type));
+    EXPECT_EQ(TypeOf(vec4_i32), TypeOf(vec4_i32->target.type));
+    EXPECT_EQ(TypeOf(vec4_u32), TypeOf(vec4_u32->target.type));
+    EXPECT_EQ(TypeOf(vec4_f32), TypeOf(vec4_f32->target.type));
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       InferVec4ElementTypeFromScalarAndVec3) {
-  auto* vec4_bool = Construct(create<ast::Vector>(nullptr, 4), Expr(true),
-                              vec3<bool>(false, true, false));
-  auto* vec4_i32 =
-      Construct(create<ast::Vector>(nullptr, 4), Expr(1), vec3<i32>(2, 3, 4));
-  auto* vec4_u32 = Construct(create<ast::Vector>(nullptr, 4), Expr(1u),
-                             vec3<u32>(2u, 3u, 4u));
-  auto* vec4_f32 = Construct(create<ast::Vector>(nullptr, 4), Expr(1.0f),
-                             vec3<f32>(2.0f, 3.0f, 4.0f));
-  WrapInFunction(vec4_bool, vec4_i32, vec4_u32, vec4_f32);
+TEST_F(ResolverTypeConstructorValidationTest, InferVec4ElementTypeFromScalarAndVec3) {
+    auto* vec4_bool =
+        Construct(create<ast::Vector>(nullptr, 4), Expr(true), vec3<bool>(false, true, false));
+    auto* vec4_i32 =
+        Construct(create<ast::Vector>(nullptr, 4), Expr(1_i), vec3<i32>(2_i, 3_i, 4_i));
+    auto* vec4_u32 =
+        Construct(create<ast::Vector>(nullptr, 4), Expr(1_u), vec3<u32>(2_u, 3_u, 4_u));
+    auto* vec4_f32 =
+        Construct(create<ast::Vector>(nullptr, 4), Expr(1.0f), vec3<f32>(2.0f, 3.0f, 4.0f));
+    WrapInFunction(vec4_bool, vec4_i32, vec4_u32, vec4_f32);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_TRUE(TypeOf(vec4_bool)->Is<sem::Vector>());
-  ASSERT_TRUE(TypeOf(vec4_i32)->Is<sem::Vector>());
-  ASSERT_TRUE(TypeOf(vec4_u32)->Is<sem::Vector>());
-  ASSERT_TRUE(TypeOf(vec4_f32)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(vec4_bool)->As<sem::Vector>()->type()->Is<sem::Bool>());
-  EXPECT_TRUE(TypeOf(vec4_i32)->As<sem::Vector>()->type()->Is<sem::I32>());
-  EXPECT_TRUE(TypeOf(vec4_u32)->As<sem::Vector>()->type()->Is<sem::U32>());
-  EXPECT_TRUE(TypeOf(vec4_f32)->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(TypeOf(vec4_bool)->As<sem::Vector>()->Width(), 4u);
-  EXPECT_EQ(TypeOf(vec4_i32)->As<sem::Vector>()->Width(), 4u);
-  EXPECT_EQ(TypeOf(vec4_u32)->As<sem::Vector>()->Width(), 4u);
-  EXPECT_EQ(TypeOf(vec4_f32)->As<sem::Vector>()->Width(), 4u);
-  EXPECT_EQ(TypeOf(vec4_bool), TypeOf(vec4_bool->target.type));
-  EXPECT_EQ(TypeOf(vec4_i32), TypeOf(vec4_i32->target.type));
-  EXPECT_EQ(TypeOf(vec4_u32), TypeOf(vec4_u32->target.type));
-  EXPECT_EQ(TypeOf(vec4_f32), TypeOf(vec4_f32->target.type));
+    ASSERT_TRUE(TypeOf(vec4_bool)->Is<sem::Vector>());
+    ASSERT_TRUE(TypeOf(vec4_i32)->Is<sem::Vector>());
+    ASSERT_TRUE(TypeOf(vec4_u32)->Is<sem::Vector>());
+    ASSERT_TRUE(TypeOf(vec4_f32)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(vec4_bool)->As<sem::Vector>()->type()->Is<sem::Bool>());
+    EXPECT_TRUE(TypeOf(vec4_i32)->As<sem::Vector>()->type()->Is<sem::I32>());
+    EXPECT_TRUE(TypeOf(vec4_u32)->As<sem::Vector>()->type()->Is<sem::U32>());
+    EXPECT_TRUE(TypeOf(vec4_f32)->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(TypeOf(vec4_bool)->As<sem::Vector>()->Width(), 4u);
+    EXPECT_EQ(TypeOf(vec4_i32)->As<sem::Vector>()->Width(), 4u);
+    EXPECT_EQ(TypeOf(vec4_u32)->As<sem::Vector>()->Width(), 4u);
+    EXPECT_EQ(TypeOf(vec4_f32)->As<sem::Vector>()->Width(), 4u);
+    EXPECT_EQ(TypeOf(vec4_bool), TypeOf(vec4_bool->target.type));
+    EXPECT_EQ(TypeOf(vec4_i32), TypeOf(vec4_i32->target.type));
+    EXPECT_EQ(TypeOf(vec4_u32), TypeOf(vec4_u32->target.type));
+    EXPECT_EQ(TypeOf(vec4_f32), TypeOf(vec4_f32->target.type));
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       InferVec4ElementTypeFromVec2AndVec2) {
-  auto* vec4_bool = Construct(create<ast::Vector>(nullptr, 4),
-                              vec2<bool>(true, false), vec2<bool>(true, false));
-  auto* vec4_i32 = Construct(create<ast::Vector>(nullptr, 4), vec2<i32>(1, 2),
-                             vec2<i32>(3, 4));
-  auto* vec4_u32 = Construct(create<ast::Vector>(nullptr, 4), vec2<u32>(1u, 2u),
-                             vec2<u32>(3u, 4u));
-  auto* vec4_f32 = Construct(create<ast::Vector>(nullptr, 4),
-                             vec2<f32>(1.0f, 2.0f), vec2<f32>(3.0f, 4.0f));
-  WrapInFunction(vec4_bool, vec4_i32, vec4_u32, vec4_f32);
+TEST_F(ResolverTypeConstructorValidationTest, InferVec4ElementTypeFromVec2AndVec2) {
+    auto* vec4_bool = Construct(create<ast::Vector>(nullptr, 4), vec2<bool>(true, false),
+                                vec2<bool>(true, false));
+    auto* vec4_i32 =
+        Construct(create<ast::Vector>(nullptr, 4), vec2<i32>(1_i, 2_i), vec2<i32>(3_i, 4_i));
+    auto* vec4_u32 =
+        Construct(create<ast::Vector>(nullptr, 4), vec2<u32>(1_u, 2_u), vec2<u32>(3_u, 4_u));
+    auto* vec4_f32 =
+        Construct(create<ast::Vector>(nullptr, 4), vec2<f32>(1.0f, 2.0f), vec2<f32>(3.0f, 4.0f));
+    WrapInFunction(vec4_bool, vec4_i32, vec4_u32, vec4_f32);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_TRUE(TypeOf(vec4_bool)->Is<sem::Vector>());
-  ASSERT_TRUE(TypeOf(vec4_i32)->Is<sem::Vector>());
-  ASSERT_TRUE(TypeOf(vec4_u32)->Is<sem::Vector>());
-  ASSERT_TRUE(TypeOf(vec4_f32)->Is<sem::Vector>());
-  EXPECT_TRUE(TypeOf(vec4_bool)->As<sem::Vector>()->type()->Is<sem::Bool>());
-  EXPECT_TRUE(TypeOf(vec4_i32)->As<sem::Vector>()->type()->Is<sem::I32>());
-  EXPECT_TRUE(TypeOf(vec4_u32)->As<sem::Vector>()->type()->Is<sem::U32>());
-  EXPECT_TRUE(TypeOf(vec4_f32)->As<sem::Vector>()->type()->Is<sem::F32>());
-  EXPECT_EQ(TypeOf(vec4_bool)->As<sem::Vector>()->Width(), 4u);
-  EXPECT_EQ(TypeOf(vec4_i32)->As<sem::Vector>()->Width(), 4u);
-  EXPECT_EQ(TypeOf(vec4_u32)->As<sem::Vector>()->Width(), 4u);
-  EXPECT_EQ(TypeOf(vec4_f32)->As<sem::Vector>()->Width(), 4u);
-  EXPECT_EQ(TypeOf(vec4_bool), TypeOf(vec4_bool->target.type));
-  EXPECT_EQ(TypeOf(vec4_i32), TypeOf(vec4_i32->target.type));
-  EXPECT_EQ(TypeOf(vec4_u32), TypeOf(vec4_u32->target.type));
-  EXPECT_EQ(TypeOf(vec4_f32), TypeOf(vec4_f32->target.type));
+    ASSERT_TRUE(TypeOf(vec4_bool)->Is<sem::Vector>());
+    ASSERT_TRUE(TypeOf(vec4_i32)->Is<sem::Vector>());
+    ASSERT_TRUE(TypeOf(vec4_u32)->Is<sem::Vector>());
+    ASSERT_TRUE(TypeOf(vec4_f32)->Is<sem::Vector>());
+    EXPECT_TRUE(TypeOf(vec4_bool)->As<sem::Vector>()->type()->Is<sem::Bool>());
+    EXPECT_TRUE(TypeOf(vec4_i32)->As<sem::Vector>()->type()->Is<sem::I32>());
+    EXPECT_TRUE(TypeOf(vec4_u32)->As<sem::Vector>()->type()->Is<sem::U32>());
+    EXPECT_TRUE(TypeOf(vec4_f32)->As<sem::Vector>()->type()->Is<sem::F32>());
+    EXPECT_EQ(TypeOf(vec4_bool)->As<sem::Vector>()->Width(), 4u);
+    EXPECT_EQ(TypeOf(vec4_i32)->As<sem::Vector>()->Width(), 4u);
+    EXPECT_EQ(TypeOf(vec4_u32)->As<sem::Vector>()->Width(), 4u);
+    EXPECT_EQ(TypeOf(vec4_f32)->As<sem::Vector>()->Width(), 4u);
+    EXPECT_EQ(TypeOf(vec4_bool), TypeOf(vec4_bool->target.type));
+    EXPECT_EQ(TypeOf(vec4_i32), TypeOf(vec4_i32->target.type));
+    EXPECT_EQ(TypeOf(vec4_u32), TypeOf(vec4_u32->target.type));
+    EXPECT_EQ(TypeOf(vec4_f32), TypeOf(vec4_f32->target.type));
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       CannotInferVectorElementTypeWithoutArgs) {
-  WrapInFunction(Construct(create<ast::Vector>(Source{{12, 34}}, nullptr, 3)));
+TEST_F(ResolverTypeConstructorValidationTest, CannotInferVectorElementTypeWithoutArgs) {
+    WrapInFunction(Construct(create<ast::Vector>(Source{{12, 34}}, nullptr, 3)));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: missing vector element type");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: missing vector element type");
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       CannotInferVec2ElementTypeFromScalarsMismatch) {
-  WrapInFunction(Construct(Source{{1, 1}}, create<ast::Vector>(nullptr, 2),
-                           Expr(Source{{1, 2}}, 1),  //
-                           Expr(Source{{1, 3}}, 2u)));
+TEST_F(ResolverTypeConstructorValidationTest, CannotInferVec2ElementTypeFromScalarsMismatch) {
+    WrapInFunction(Construct(Source{{1, 1}}, create<ast::Vector>(nullptr, 2),
+                             Expr(Source{{1, 2}}, 1_i),  //
+                             Expr(Source{{1, 3}}, 2_u)));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(1:1 error: cannot infer vector element type, as constructor arguments have different types
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(
+        r()->error(),
+        R"(1:1 error: cannot infer vector element type, as constructor arguments have different types
 1:2 note: argument 0 has type i32
 1:3 note: argument 1 has type u32)");
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       CannotInferVec3ElementTypeFromScalarsMismatch) {
-  WrapInFunction(Construct(Source{{1, 1}}, create<ast::Vector>(nullptr, 3),
-                           Expr(Source{{1, 2}}, 1),   //
-                           Expr(Source{{1, 3}}, 2u),  //
-                           Expr(Source{{1, 4}}, 3)));
+TEST_F(ResolverTypeConstructorValidationTest, CannotInferVec3ElementTypeFromScalarsMismatch) {
+    WrapInFunction(Construct(Source{{1, 1}}, create<ast::Vector>(nullptr, 3),
+                             Expr(Source{{1, 2}}, 1_i),  //
+                             Expr(Source{{1, 3}}, 2_u),  //
+                             Expr(Source{{1, 4}}, 3_i)));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(1:1 error: cannot infer vector element type, as constructor arguments have different types
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(
+        r()->error(),
+        R"(1:1 error: cannot infer vector element type, as constructor arguments have different types
 1:2 note: argument 0 has type i32
 1:3 note: argument 1 has type u32
 1:4 note: argument 2 has type i32)");
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       CannotInferVec3ElementTypeFromScalarAndVec2Mismatch) {
-  WrapInFunction(
-      Construct(Source{{1, 1}}, create<ast::Vector>(nullptr, 3),
-                Expr(Source{{1, 2}}, 1),  //
-                Construct(Source{{1, 3}}, ty.vec2<f32>(), 2.0f, 3.0f)));
+TEST_F(ResolverTypeConstructorValidationTest, CannotInferVec3ElementTypeFromScalarAndVec2Mismatch) {
+    WrapInFunction(Construct(Source{{1, 1}}, create<ast::Vector>(nullptr, 3),
+                             Expr(Source{{1, 2}}, 1_i),  //
+                             Construct(Source{{1, 3}}, ty.vec2<f32>(), 2.0f, 3.0f)));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(1:1 error: cannot infer vector element type, as constructor arguments have different types
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(
+        r()->error(),
+        R"(1:1 error: cannot infer vector element type, as constructor arguments have different types
 1:2 note: argument 0 has type i32
 1:3 note: argument 1 has type vec2<f32>)");
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       CannotInferVec4ElementTypeFromScalarsMismatch) {
-  WrapInFunction(Construct(Source{{1, 1}}, create<ast::Vector>(nullptr, 4),
-                           Expr(Source{{1, 2}}, 1),     //
-                           Expr(Source{{1, 3}}, 2),     //
-                           Expr(Source{{1, 4}}, 3.0f),  //
-                           Expr(Source{{1, 5}}, 4)));
+TEST_F(ResolverTypeConstructorValidationTest, CannotInferVec4ElementTypeFromScalarsMismatch) {
+    WrapInFunction(Construct(Source{{1, 1}}, create<ast::Vector>(nullptr, 4),
+                             Expr(Source{{1, 2}}, 1_i),   //
+                             Expr(Source{{1, 3}}, 2_i),   //
+                             Expr(Source{{1, 4}}, 3.0f),  //
+                             Expr(Source{{1, 5}}, 4_i)));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(1:1 error: cannot infer vector element type, as constructor arguments have different types
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(
+        r()->error(),
+        R"(1:1 error: cannot infer vector element type, as constructor arguments have different types
 1:2 note: argument 0 has type i32
 1:3 note: argument 1 has type i32
 1:4 note: argument 2 has type f32
 1:5 note: argument 3 has type i32)");
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       CannotInferVec4ElementTypeFromScalarAndVec3Mismatch) {
-  WrapInFunction(
-      Construct(Source{{1, 1}}, create<ast::Vector>(nullptr, 4),
-                Expr(Source{{1, 2}}, 1),  //
-                Construct(Source{{1, 3}}, ty.vec3<u32>(), 2u, 3u, 4u)));
+TEST_F(ResolverTypeConstructorValidationTest, CannotInferVec4ElementTypeFromScalarAndVec3Mismatch) {
+    WrapInFunction(Construct(Source{{1, 1}}, create<ast::Vector>(nullptr, 4),
+                             Expr(Source{{1, 2}}, 1_i),  //
+                             Construct(Source{{1, 3}}, ty.vec3<u32>(), 2_u, 3_u, 4_u)));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(1:1 error: cannot infer vector element type, as constructor arguments have different types
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(
+        r()->error(),
+        R"(1:1 error: cannot infer vector element type, as constructor arguments have different types
 1:2 note: argument 0 has type i32
 1:3 note: argument 1 has type vec3<u32>)");
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       CannotInferVec4ElementTypeFromVec2AndVec2Mismatch) {
-  WrapInFunction(Construct(Source{{1, 1}}, create<ast::Vector>(nullptr, 4),
-                           Construct(Source{{1, 2}}, ty.vec2<i32>(), 3, 4),  //
-                           Construct(Source{{1, 3}}, ty.vec2<u32>(), 3u, 4u)));
+TEST_F(ResolverTypeConstructorValidationTest, CannotInferVec4ElementTypeFromVec2AndVec2Mismatch) {
+    WrapInFunction(Construct(Source{{1, 1}}, create<ast::Vector>(nullptr, 4),
+                             Construct(Source{{1, 2}}, ty.vec2<i32>(), 3_i, 4_i),  //
+                             Construct(Source{{1, 3}}, ty.vec2<u32>(), 3_u, 4_u)));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(1:1 error: cannot infer vector element type, as constructor arguments have different types
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(
+        r()->error(),
+        R"(1:1 error: cannot infer vector element type, as constructor arguments have different types
 1:2 note: argument 0 has type vec2<i32>
 1:3 note: argument 1 has type vec2<u32>)");
 }
@@ -2204,347 +2041,331 @@
 
 namespace MatrixConstructor {
 struct MatrixDimensions {
-  uint32_t rows;
-  uint32_t columns;
+    uint32_t rows;
+    uint32_t columns;
 };
 
 static std::string MatrixStr(const MatrixDimensions& dimensions) {
-  return "mat" + std::to_string(dimensions.columns) + "x" +
-         std::to_string(dimensions.rows) + "<f32>";
+    return "mat" + std::to_string(dimensions.columns) + "x" + std::to_string(dimensions.rows) +
+           "<f32>";
 }
 
 using MatrixConstructorTest = ResolverTestWithParam<MatrixDimensions>;
 
 TEST_P(MatrixConstructorTest, Expr_ColumnConstructor_Error_TooFewArguments) {
-  // matNxM<f32>(vecM<f32>(), ...); with N - 1 arguments
+    // matNxM<f32>(vecM<f32>(), ...); with N - 1 arguments
 
-  const auto param = GetParam();
+    const auto param = GetParam();
 
-  std::stringstream args_tys;
-  ast::ExpressionList args;
-  for (uint32_t i = 1; i <= param.columns - 1; i++) {
-    auto* vec_type = ty.vec<f32>(param.rows);
-    args.push_back(Construct(Source{{12, i}}, vec_type));
-    if (i > 1) {
-      args_tys << ", ";
+    std::stringstream args_tys;
+    ast::ExpressionList args;
+    for (uint32_t i = 1; i <= param.columns - 1; i++) {
+        auto* vec_type = ty.vec<f32>(param.rows);
+        args.push_back(Construct(Source{{12, i}}, vec_type));
+        if (i > 1) {
+            args_tys << ", ";
+        }
+        args_tys << "vec" << param.rows << "<f32>";
     }
-    args_tys << "vec" << param.rows << "<f32>";
-  }
 
-  auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
-  auto* tc = Construct(Source{}, matrix_type, std::move(args));
-  WrapInFunction(tc);
+    auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
+    auto* tc = Construct(Source{}, matrix_type, std::move(args));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_THAT(r()->error(), HasSubstr("12:1 error: no matching constructor " +
-                                      MatrixStr(param) + "(" + args_tys.str() +
-                                      ")\n\n3 candidates available:"));
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_THAT(r()->error(), HasSubstr("12:1 error: no matching constructor " + MatrixStr(param) +
+                                        "(" + args_tys.str() + ")\n\n3 candidates available:"));
 }
 
 TEST_P(MatrixConstructorTest, Expr_ElementConstructor_Error_TooFewArguments) {
-  // matNxM<f32>(f32,...,f32); with N*M - 1 arguments
+    // matNxM<f32>(f32,...,f32); with N*M - 1 arguments
 
-  const auto param = GetParam();
+    const auto param = GetParam();
 
-  std::stringstream args_tys;
-  ast::ExpressionList args;
-  for (uint32_t i = 1; i <= param.columns * param.rows - 1; i++) {
-    args.push_back(Construct(Source{{12, i}}, ty.f32()));
-    if (i > 1) {
-      args_tys << ", ";
+    std::stringstream args_tys;
+    ast::ExpressionList args;
+    for (uint32_t i = 1; i <= param.columns * param.rows - 1; i++) {
+        args.push_back(Construct(Source{{12, i}}, ty.f32()));
+        if (i > 1) {
+            args_tys << ", ";
+        }
+        args_tys << "f32";
     }
-    args_tys << "f32";
-  }
 
-  auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
-  auto* tc = Construct(Source{}, matrix_type, std::move(args));
-  WrapInFunction(tc);
+    auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
+    auto* tc = Construct(Source{}, matrix_type, std::move(args));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_THAT(r()->error(), HasSubstr("12:1 error: no matching constructor " +
-                                      MatrixStr(param) + "(" + args_tys.str() +
-                                      ")\n\n3 candidates available:"));
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_THAT(r()->error(), HasSubstr("12:1 error: no matching constructor " + MatrixStr(param) +
+                                        "(" + args_tys.str() + ")\n\n3 candidates available:"));
 }
 
 TEST_P(MatrixConstructorTest, Expr_ColumnConstructor_Error_TooManyArguments) {
-  // matNxM<f32>(vecM<f32>(), ...); with N + 1 arguments
+    // matNxM<f32>(vecM<f32>(), ...); with N + 1 arguments
 
-  const auto param = GetParam();
+    const auto param = GetParam();
 
-  std::stringstream args_tys;
-  ast::ExpressionList args;
-  for (uint32_t i = 1; i <= param.columns + 1; i++) {
-    auto* vec_type = ty.vec<f32>(param.rows);
-    args.push_back(Construct(Source{{12, i}}, vec_type));
-    if (i > 1) {
-      args_tys << ", ";
+    std::stringstream args_tys;
+    ast::ExpressionList args;
+    for (uint32_t i = 1; i <= param.columns + 1; i++) {
+        auto* vec_type = ty.vec<f32>(param.rows);
+        args.push_back(Construct(Source{{12, i}}, vec_type));
+        if (i > 1) {
+            args_tys << ", ";
+        }
+        args_tys << "vec" << param.rows << "<f32>";
     }
-    args_tys << "vec" << param.rows << "<f32>";
-  }
 
-  auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
-  auto* tc = Construct(Source{}, matrix_type, std::move(args));
-  WrapInFunction(tc);
+    auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
+    auto* tc = Construct(Source{}, matrix_type, std::move(args));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_THAT(r()->error(), HasSubstr("12:1 error: no matching constructor " +
-                                      MatrixStr(param) + "(" + args_tys.str() +
-                                      ")\n\n3 candidates available:"));
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_THAT(r()->error(), HasSubstr("12:1 error: no matching constructor " + MatrixStr(param) +
+                                        "(" + args_tys.str() + ")\n\n3 candidates available:"));
 }
 
 TEST_P(MatrixConstructorTest, Expr_ElementConstructor_Error_TooManyArguments) {
-  // matNxM<f32>(f32,...,f32); with N*M + 1 arguments
+    // matNxM<f32>(f32,...,f32); with N*M + 1 arguments
 
-  const auto param = GetParam();
+    const auto param = GetParam();
 
-  std::stringstream args_tys;
-  ast::ExpressionList args;
-  for (uint32_t i = 1; i <= param.columns * param.rows + 1; i++) {
-    args.push_back(Construct(Source{{12, i}}, ty.f32()));
-    if (i > 1) {
-      args_tys << ", ";
+    std::stringstream args_tys;
+    ast::ExpressionList args;
+    for (uint32_t i = 1; i <= param.columns * param.rows + 1; i++) {
+        args.push_back(Construct(Source{{12, i}}, ty.f32()));
+        if (i > 1) {
+            args_tys << ", ";
+        }
+        args_tys << "f32";
     }
-    args_tys << "f32";
-  }
 
-  auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
-  auto* tc = Construct(Source{}, matrix_type, std::move(args));
-  WrapInFunction(tc);
+    auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
+    auto* tc = Construct(Source{}, matrix_type, std::move(args));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_THAT(r()->error(), HasSubstr("12:1 error: no matching constructor " +
-                                      MatrixStr(param) + "(" + args_tys.str() +
-                                      ")\n\n3 candidates available:"));
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_THAT(r()->error(), HasSubstr("12:1 error: no matching constructor " + MatrixStr(param) +
+                                        "(" + args_tys.str() + ")\n\n3 candidates available:"));
 }
 
-TEST_P(MatrixConstructorTest,
-       Expr_ColumnConstructor_Error_InvalidArgumentType) {
-  // matNxM<f32>(vec<u32>, vec<u32>, ...); N arguments
+TEST_P(MatrixConstructorTest, Expr_ColumnConstructor_Error_InvalidArgumentType) {
+    // matNxM<f32>(vec<u32>, vec<u32>, ...); N arguments
 
-  const auto param = GetParam();
+    const auto param = GetParam();
 
-  std::stringstream args_tys;
-  ast::ExpressionList args;
-  for (uint32_t i = 1; i <= param.columns; i++) {
-    auto* vec_type = ty.vec<u32>(param.rows);
-    args.push_back(Construct(Source{{12, i}}, vec_type));
-    if (i > 1) {
-      args_tys << ", ";
+    std::stringstream args_tys;
+    ast::ExpressionList args;
+    for (uint32_t i = 1; i <= param.columns; i++) {
+        auto* vec_type = ty.vec<u32>(param.rows);
+        args.push_back(Construct(Source{{12, i}}, vec_type));
+        if (i > 1) {
+            args_tys << ", ";
+        }
+        args_tys << "vec" << param.rows << "<u32>";
     }
-    args_tys << "vec" << param.rows << "<u32>";
-  }
 
-  auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
-  auto* tc = Construct(Source{}, matrix_type, std::move(args));
-  WrapInFunction(tc);
+    auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
+    auto* tc = Construct(Source{}, matrix_type, std::move(args));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_THAT(r()->error(), HasSubstr("12:1 error: no matching constructor " +
-                                      MatrixStr(param) + "(" + args_tys.str() +
-                                      ")\n\n3 candidates available:"));
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_THAT(r()->error(), HasSubstr("12:1 error: no matching constructor " + MatrixStr(param) +
+                                        "(" + args_tys.str() + ")\n\n3 candidates available:"));
 }
 
-TEST_P(MatrixConstructorTest,
-       Expr_ElementConstructor_Error_InvalidArgumentType) {
-  // matNxM<f32>(u32, u32, ...); N*M arguments
+TEST_P(MatrixConstructorTest, Expr_ElementConstructor_Error_InvalidArgumentType) {
+    // matNxM<f32>(u32, u32, ...); N*M arguments
 
-  const auto param = GetParam();
+    const auto param = GetParam();
 
-  std::stringstream args_tys;
-  ast::ExpressionList args;
-  for (uint32_t i = 1; i <= param.columns; i++) {
-    args.push_back(Expr(Source{{12, i}}, 1u));
-    if (i > 1) {
-      args_tys << ", ";
+    std::stringstream args_tys;
+    ast::ExpressionList args;
+    for (uint32_t i = 1; i <= param.columns; i++) {
+        args.push_back(Expr(Source{{12, i}}, 1_u));
+        if (i > 1) {
+            args_tys << ", ";
+        }
+        args_tys << "u32";
     }
-    args_tys << "u32";
-  }
 
-  auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
-  auto* tc = Construct(Source{}, matrix_type, std::move(args));
-  WrapInFunction(tc);
+    auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
+    auto* tc = Construct(Source{}, matrix_type, std::move(args));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_THAT(r()->error(), HasSubstr("12:1 error: no matching constructor " +
-                                      MatrixStr(param) + "(" + args_tys.str() +
-                                      ")\n\n3 candidates available:"));
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_THAT(r()->error(), HasSubstr("12:1 error: no matching constructor " + MatrixStr(param) +
+                                        "(" + args_tys.str() + ")\n\n3 candidates available:"));
 }
 
-TEST_P(MatrixConstructorTest,
-       Expr_ColumnConstructor_Error_TooFewRowsInVectorArgument) {
-  // matNxM<f32>(vecM<f32>(),...,vecM-1<f32>());
+TEST_P(MatrixConstructorTest, Expr_ColumnConstructor_Error_TooFewRowsInVectorArgument) {
+    // matNxM<f32>(vecM<f32>(),...,vecM-1<f32>());
 
-  const auto param = GetParam();
+    const auto param = GetParam();
 
-  // Skip the test if parameters would have resulted in an invalid vec1 type.
-  if (param.rows == 2) {
-    return;
-  }
-
-  std::stringstream args_tys;
-  ast::ExpressionList args;
-  for (uint32_t i = 1; i <= param.columns - 1; i++) {
-    auto* valid_vec_type = ty.vec<f32>(param.rows);
-    args.push_back(Construct(Source{{12, i}}, valid_vec_type));
-    if (i > 1) {
-      args_tys << ", ";
+    // Skip the test if parameters would have resulted in an invalid vec1 type.
+    if (param.rows == 2) {
+        return;
     }
-    args_tys << "vec" << param.rows << "<f32>";
-  }
-  const size_t kInvalidLoc = 2 * (param.columns - 1);
-  auto* invalid_vec_type = ty.vec<f32>(param.rows - 1);
-  args.push_back(Construct(Source{{12, kInvalidLoc}}, invalid_vec_type));
-  args_tys << ", vec" << (param.rows - 1) << "<f32>";
 
-  auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
-  auto* tc = Construct(Source{}, matrix_type, std::move(args));
-  WrapInFunction(tc);
+    std::stringstream args_tys;
+    ast::ExpressionList args;
+    for (uint32_t i = 1; i <= param.columns - 1; i++) {
+        auto* valid_vec_type = ty.vec<f32>(param.rows);
+        args.push_back(Construct(Source{{12, i}}, valid_vec_type));
+        if (i > 1) {
+            args_tys << ", ";
+        }
+        args_tys << "vec" << param.rows << "<f32>";
+    }
+    const size_t kInvalidLoc = 2 * (param.columns - 1);
+    auto* invalid_vec_type = ty.vec<f32>(param.rows - 1);
+    args.push_back(Construct(Source{{12, kInvalidLoc}}, invalid_vec_type));
+    args_tys << ", vec" << (param.rows - 1) << "<f32>";
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_THAT(r()->error(), HasSubstr("12:1 error: no matching constructor " +
-                                      MatrixStr(param) + "(" + args_tys.str() +
-                                      ")\n\n3 candidates available:"));
+    auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
+    auto* tc = Construct(Source{}, matrix_type, std::move(args));
+    WrapInFunction(tc);
+
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_THAT(r()->error(), HasSubstr("12:1 error: no matching constructor " + MatrixStr(param) +
+                                        "(" + args_tys.str() + ")\n\n3 candidates available:"));
 }
 
-TEST_P(MatrixConstructorTest,
-       Expr_ColumnConstructor_Error_TooManyRowsInVectorArgument) {
-  // matNxM<f32>(vecM<f32>(),...,vecM+1<f32>());
+TEST_P(MatrixConstructorTest, Expr_ColumnConstructor_Error_TooManyRowsInVectorArgument) {
+    // matNxM<f32>(vecM<f32>(),...,vecM+1<f32>());
 
-  const auto param = GetParam();
+    const auto param = GetParam();
 
-  // Skip the test if parameters would have resulted in an invalid vec5 type.
-  if (param.rows == 4) {
-    return;
-  }
-
-  std::stringstream args_tys;
-  ast::ExpressionList args;
-  for (uint32_t i = 1; i <= param.columns - 1; i++) {
-    auto* valid_vec_type = ty.vec<f32>(param.rows);
-    args.push_back(Construct(Source{{12, i}}, valid_vec_type));
-    if (i > 1) {
-      args_tys << ", ";
+    // Skip the test if parameters would have resulted in an invalid vec5 type.
+    if (param.rows == 4) {
+        return;
     }
-    args_tys << "vec" << param.rows << "<f32>";
-  }
-  const size_t kInvalidLoc = 2 * (param.columns - 1);
-  auto* invalid_vec_type = ty.vec<f32>(param.rows + 1);
-  args.push_back(Construct(Source{{12, kInvalidLoc}}, invalid_vec_type));
-  args_tys << ", vec" << (param.rows + 1) << "<f32>";
 
-  auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
-  auto* tc = Construct(Source{}, matrix_type, std::move(args));
-  WrapInFunction(tc);
+    std::stringstream args_tys;
+    ast::ExpressionList args;
+    for (uint32_t i = 1; i <= param.columns - 1; i++) {
+        auto* valid_vec_type = ty.vec<f32>(param.rows);
+        args.push_back(Construct(Source{{12, i}}, valid_vec_type));
+        if (i > 1) {
+            args_tys << ", ";
+        }
+        args_tys << "vec" << param.rows << "<f32>";
+    }
+    const size_t kInvalidLoc = 2 * (param.columns - 1);
+    auto* invalid_vec_type = ty.vec<f32>(param.rows + 1);
+    args.push_back(Construct(Source{{12, kInvalidLoc}}, invalid_vec_type));
+    args_tys << ", vec" << (param.rows + 1) << "<f32>";
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_THAT(r()->error(), HasSubstr("12:1 error: no matching constructor " +
-                                      MatrixStr(param) + "(" + args_tys.str() +
-                                      ")\n\n3 candidates available:"));
+    auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
+    auto* tc = Construct(Source{}, matrix_type, std::move(args));
+    WrapInFunction(tc);
+
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_THAT(r()->error(), HasSubstr("12:1 error: no matching constructor " + MatrixStr(param) +
+                                        "(" + args_tys.str() + ")\n\n3 candidates available:"));
 }
 
 TEST_P(MatrixConstructorTest, Expr_Constructor_ZeroValue_Success) {
-  // matNxM<f32>();
+    // matNxM<f32>();
 
-  const auto param = GetParam();
-  auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
-  auto* tc = Construct(Source{{12, 40}}, matrix_type);
-  WrapInFunction(tc);
+    const auto param = GetParam();
+    auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
+    auto* tc = Construct(Source{{12, 40}}, matrix_type);
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_P(MatrixConstructorTest, Expr_Constructor_WithColumns_Success) {
-  // matNxM<f32>(vecM<f32>(), ...); with N arguments
+    // matNxM<f32>(vecM<f32>(), ...); with N arguments
 
-  const auto param = GetParam();
+    const auto param = GetParam();
 
-  ast::ExpressionList args;
-  for (uint32_t i = 1; i <= param.columns; i++) {
-    auto* vec_type = ty.vec<f32>(param.rows);
-    args.push_back(Construct(Source{{12, i}}, vec_type));
-  }
+    ast::ExpressionList args;
+    for (uint32_t i = 1; i <= param.columns; i++) {
+        auto* vec_type = ty.vec<f32>(param.rows);
+        args.push_back(Construct(Source{{12, i}}, vec_type));
+    }
 
-  auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
-  auto* tc = Construct(Source{}, matrix_type, std::move(args));
-  WrapInFunction(tc);
+    auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
+    auto* tc = Construct(Source{}, matrix_type, std::move(args));
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_P(MatrixConstructorTest, Expr_Constructor_WithElements_Success) {
-  // matNxM<f32>(f32,...,f32); with N*M arguments
+    // matNxM<f32>(f32,...,f32); with N*M arguments
 
-  const auto param = GetParam();
+    const auto param = GetParam();
 
-  ast::ExpressionList args;
-  for (uint32_t i = 1; i <= param.columns * param.rows; i++) {
-    args.push_back(Construct(Source{{12, i}}, ty.f32()));
-  }
+    ast::ExpressionList args;
+    for (uint32_t i = 1; i <= param.columns * param.rows; i++) {
+        args.push_back(Construct(Source{{12, i}}, ty.f32()));
+    }
 
-  auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
-  auto* tc = Construct(Source{}, matrix_type, std::move(args));
-  WrapInFunction(tc);
+    auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
+    auto* tc = Construct(Source{}, matrix_type, std::move(args));
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_P(MatrixConstructorTest, Expr_Constructor_ElementTypeAlias_Error) {
-  // matNxM<Float32>(vecM<u32>(), ...); with N arguments
+    // matNxM<Float32>(vecM<u32>(), ...); with N arguments
 
-  const auto param = GetParam();
-  auto* f32_alias = Alias("Float32", ty.f32());
+    const auto param = GetParam();
+    auto* f32_alias = Alias("Float32", ty.f32());
 
-  std::stringstream args_tys;
-  ast::ExpressionList args;
-  for (uint32_t i = 1; i <= param.columns; i++) {
-    auto* vec_type = ty.vec(ty.u32(), param.rows);
-    args.push_back(Construct(Source{{12, i}}, vec_type));
-    if (i > 1) {
-      args_tys << ", ";
+    std::stringstream args_tys;
+    ast::ExpressionList args;
+    for (uint32_t i = 1; i <= param.columns; i++) {
+        auto* vec_type = ty.vec(ty.u32(), param.rows);
+        args.push_back(Construct(Source{{12, i}}, vec_type));
+        if (i > 1) {
+            args_tys << ", ";
+        }
+        args_tys << "vec" << param.rows << "<u32>";
     }
-    args_tys << "vec" << param.rows << "<u32>";
-  }
 
-  auto* matrix_type = ty.mat(ty.Of(f32_alias), param.columns, param.rows);
-  auto* tc = Construct(Source{}, matrix_type, std::move(args));
-  WrapInFunction(tc);
+    auto* matrix_type = ty.mat(ty.Of(f32_alias), param.columns, param.rows);
+    auto* tc = Construct(Source{}, matrix_type, std::move(args));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_THAT(r()->error(), HasSubstr("12:1 error: no matching constructor " +
-                                      MatrixStr(param) + "(" + args_tys.str() +
-                                      ")\n\n3 candidates available:"));
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_THAT(r()->error(), HasSubstr("12:1 error: no matching constructor " + MatrixStr(param) +
+                                        "(" + args_tys.str() + ")\n\n3 candidates available:"));
 }
 
 TEST_P(MatrixConstructorTest, Expr_Constructor_ElementTypeAlias_Success) {
-  // matNxM<Float32>(vecM<f32>(), ...); with N arguments
+    // matNxM<Float32>(vecM<f32>(), ...); with N arguments
 
-  const auto param = GetParam();
-  auto* f32_alias = Alias("Float32", ty.f32());
+    const auto param = GetParam();
+    auto* f32_alias = Alias("Float32", ty.f32());
 
-  ast::ExpressionList args;
-  for (uint32_t i = 1; i <= param.columns; i++) {
-    auto* vec_type = ty.vec<f32>(param.rows);
-    args.push_back(Construct(Source{{12, i}}, vec_type));
-  }
+    ast::ExpressionList args;
+    for (uint32_t i = 1; i <= param.columns; i++) {
+        auto* vec_type = ty.vec<f32>(param.rows);
+        args.push_back(Construct(Source{{12, i}}, vec_type));
+    }
 
-  auto* matrix_type = ty.mat(ty.Of(f32_alias), param.columns, param.rows);
-  auto* tc = Construct(Source{}, matrix_type, std::move(args));
-  WrapInFunction(tc);
+    auto* matrix_type = ty.mat(ty.Of(f32_alias), param.columns, param.rows);
+    auto* tc = Construct(Source{}, matrix_type, std::move(args));
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       Expr_MatrixConstructor_ArgumentTypeAlias_Error) {
-  auto* alias = Alias("VectorUnsigned2", ty.vec2<u32>());
-  auto* tc =
-      mat2x2<f32>(Construct(Source{{12, 34}}, ty.Of(alias)), vec2<f32>());
-  WrapInFunction(tc);
+TEST_F(ResolverTypeConstructorValidationTest, Expr_MatrixConstructor_ArgumentTypeAlias_Error) {
+    auto* alias = Alias("VectorUnsigned2", ty.vec2<u32>());
+    auto* tc = mat2x2<f32>(Construct(Source{{12, 34}}, ty.Of(alias)), vec2<f32>());
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: no matching constructor mat2x2<f32>(vec2<u32>, vec2<f32>)
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: no matching constructor mat2x2<f32>(vec2<u32>, vec2<f32>)
 
 3 candidates available:
   mat2x2<f32>()
@@ -2554,148 +2375,144 @@
 }
 
 TEST_P(MatrixConstructorTest, Expr_Constructor_ArgumentTypeAlias_Success) {
-  const auto param = GetParam();
-  auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
-  auto* vec_type = ty.vec<f32>(param.rows);
-  auto* vec_alias = Alias("VectorFloat2", vec_type);
+    const auto param = GetParam();
+    auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
+    auto* vec_type = ty.vec<f32>(param.rows);
+    auto* vec_alias = Alias("VectorFloat2", vec_type);
 
-  ast::ExpressionList args;
-  for (uint32_t i = 1; i <= param.columns; i++) {
-    args.push_back(Construct(Source{{12, i}}, ty.Of(vec_alias)));
-  }
+    ast::ExpressionList args;
+    for (uint32_t i = 1; i <= param.columns; i++) {
+        args.push_back(Construct(Source{{12, i}}, ty.Of(vec_alias)));
+    }
 
-  auto* tc = Construct(Source{}, matrix_type, std::move(args));
-  WrapInFunction(tc);
+    auto* tc = Construct(Source{}, matrix_type, std::move(args));
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_P(MatrixConstructorTest, Expr_Constructor_ArgumentElementTypeAlias_Error) {
-  const auto param = GetParam();
-  auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
-  auto* f32_alias = Alias("UnsignedInt", ty.u32());
+    const auto param = GetParam();
+    auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
+    auto* f32_alias = Alias("UnsignedInt", ty.u32());
 
-  std::stringstream args_tys;
-  ast::ExpressionList args;
-  for (uint32_t i = 1; i <= param.columns; i++) {
-    auto* vec_type = ty.vec(ty.Of(f32_alias), param.rows);
-    args.push_back(Construct(Source{{12, i}}, vec_type));
-    if (i > 1) {
-      args_tys << ", ";
+    std::stringstream args_tys;
+    ast::ExpressionList args;
+    for (uint32_t i = 1; i <= param.columns; i++) {
+        auto* vec_type = ty.vec(ty.Of(f32_alias), param.rows);
+        args.push_back(Construct(Source{{12, i}}, vec_type));
+        if (i > 1) {
+            args_tys << ", ";
+        }
+        args_tys << "vec" << param.rows << "<u32>";
     }
-    args_tys << "vec" << param.rows << "<u32>";
-  }
 
-  auto* tc = Construct(Source{}, matrix_type, std::move(args));
-  WrapInFunction(tc);
+    auto* tc = Construct(Source{}, matrix_type, std::move(args));
+    WrapInFunction(tc);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_THAT(r()->error(), HasSubstr("12:1 error: no matching constructor " +
-                                      MatrixStr(param) + "(" + args_tys.str() +
-                                      ")\n\n3 candidates available:"));
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_THAT(r()->error(), HasSubstr("12:1 error: no matching constructor " + MatrixStr(param) +
+                                        "(" + args_tys.str() + ")\n\n3 candidates available:"));
 }
 
-TEST_P(MatrixConstructorTest,
-       Expr_Constructor_ArgumentElementTypeAlias_Success) {
-  const auto param = GetParam();
-  auto* f32_alias = Alias("Float32", ty.f32());
+TEST_P(MatrixConstructorTest, Expr_Constructor_ArgumentElementTypeAlias_Success) {
+    const auto param = GetParam();
+    auto* f32_alias = Alias("Float32", ty.f32());
 
-  ast::ExpressionList args;
-  for (uint32_t i = 1; i <= param.columns; i++) {
-    auto* vec_type = ty.vec(ty.Of(f32_alias), param.rows);
-    args.push_back(Construct(Source{{12, i}}, vec_type));
-  }
+    ast::ExpressionList args;
+    for (uint32_t i = 1; i <= param.columns; i++) {
+        auto* vec_type = ty.vec(ty.Of(f32_alias), param.rows);
+        args.push_back(Construct(Source{{12, i}}, vec_type));
+    }
 
-  auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
-  auto* tc = Construct(Source{}, matrix_type, std::move(args));
-  WrapInFunction(tc);
+    auto* matrix_type = ty.mat<f32>(param.columns, param.rows);
+    auto* tc = Construct(Source{}, matrix_type, std::move(args));
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_P(MatrixConstructorTest, InferElementTypeFromVectors) {
-  const auto param = GetParam();
+    const auto param = GetParam();
 
-  ast::ExpressionList args;
-  for (uint32_t i = 1; i <= param.columns; i++) {
-    args.push_back(Construct(ty.vec<f32>(param.rows)));
-  }
+    ast::ExpressionList args;
+    for (uint32_t i = 1; i <= param.columns; i++) {
+        args.push_back(Construct(ty.vec<f32>(param.rows)));
+    }
 
-  auto* matrix_type = create<ast::Matrix>(nullptr, param.rows, param.columns);
-  auto* tc = Construct(Source{}, matrix_type, std::move(args));
-  WrapInFunction(tc);
+    auto* matrix_type = create<ast::Matrix>(nullptr, param.rows, param.columns);
+    auto* tc = Construct(Source{}, matrix_type, std::move(args));
+    WrapInFunction(tc);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_P(MatrixConstructorTest, InferElementTypeFromScalars) {
-  const auto param = GetParam();
+    const auto param = GetParam();
 
-  ast::ExpressionList args;
-  for (uint32_t i = 0; i < param.rows * param.columns; i++) {
-    args.push_back(Expr(static_cast<f32>(i)));
-  }
+    ast::ExpressionList args;
+    for (uint32_t i = 0; i < param.rows * param.columns; i++) {
+        args.push_back(Expr(static_cast<f32>(i)));
+    }
 
-  auto* matrix_type = create<ast::Matrix>(nullptr, param.rows, param.columns);
-  WrapInFunction(Construct(Source{{12, 34}}, matrix_type, std::move(args)));
+    auto* matrix_type = create<ast::Matrix>(nullptr, param.rows, param.columns);
+    WrapInFunction(Construct(Source{{12, 34}}, matrix_type, std::move(args)));
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_P(MatrixConstructorTest, CannotInferElementTypeFromVectors_Mismatch) {
-  const auto param = GetParam();
+    const auto param = GetParam();
 
-  std::stringstream err;
-  err << "12:34 error: cannot infer matrix element type, as constructor "
-         "arguments have different types";
+    std::stringstream err;
+    err << "12:34 error: cannot infer matrix element type, as constructor "
+           "arguments have different types";
 
-  ast::ExpressionList args;
-  for (uint32_t i = 0; i < param.columns; i++) {
-    err << "\n";
-    auto src = Source{{1, 10 + i}};
-    if (i == 1) {
-      // Odd one out
-      args.push_back(Construct(src, ty.vec<i32>(param.rows)));
-      err << src << " note: argument " << i << " has type vec" << param.rows
-          << "<i32>";
-    } else {
-      args.push_back(Construct(src, ty.vec<f32>(param.rows)));
-      err << src << " note: argument " << i << " has type vec" << param.rows
-          << "<f32>";
+    ast::ExpressionList args;
+    for (uint32_t i = 0; i < param.columns; i++) {
+        err << "\n";
+        auto src = Source{{1, 10 + i}};
+        if (i == 1) {
+            // Odd one out
+            args.push_back(Construct(src, ty.vec<i32>(param.rows)));
+            err << src << " note: argument " << i << " has type vec" << param.rows << "<i32>";
+        } else {
+            args.push_back(Construct(src, ty.vec<f32>(param.rows)));
+            err << src << " note: argument " << i << " has type vec" << param.rows << "<f32>";
+        }
     }
-  }
 
-  auto* matrix_type = create<ast::Matrix>(nullptr, param.rows, param.columns);
-  WrapInFunction(Construct(Source{{12, 34}}, matrix_type, std::move(args)));
+    auto* matrix_type = create<ast::Matrix>(nullptr, param.rows, param.columns);
+    WrapInFunction(Construct(Source{{12, 34}}, matrix_type, std::move(args)));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_THAT(r()->error(), err.str());
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_THAT(r()->error(), err.str());
 }
 
 TEST_P(MatrixConstructorTest, CannotInferElementTypeFromScalars_Mismatch) {
-  const auto param = GetParam();
+    const auto param = GetParam();
 
-  std::stringstream err;
-  err << "12:34 error: cannot infer matrix element type, as constructor "
-         "arguments have different types";
-  ast::ExpressionList args;
-  for (uint32_t i = 0; i < param.rows * param.columns; i++) {
-    err << "\n";
-    auto src = Source{{1, 10 + i}};
-    if (i == 3) {
-      args.push_back(Expr(src, static_cast<i32>(i)));  // The odd one out
-      err << src << " note: argument " << i << " has type i32";
-    } else {
-      args.push_back(Expr(src, static_cast<f32>(i)));
-      err << src << " note: argument " << i << " has type f32";
+    std::stringstream err;
+    err << "12:34 error: cannot infer matrix element type, as constructor "
+           "arguments have different types";
+    ast::ExpressionList args;
+    for (uint32_t i = 0; i < param.rows * param.columns; i++) {
+        err << "\n";
+        auto src = Source{{1, 10 + i}};
+        if (i == 3) {
+            args.push_back(Expr(src, static_cast<i32>(i)));  // The odd one out
+            err << src << " note: argument " << i << " has type i32";
+        } else {
+            args.push_back(Expr(src, static_cast<f32>(i)));
+            err << src << " note: argument " << i << " has type f32";
+        }
     }
-  }
 
-  auto* matrix_type = create<ast::Matrix>(nullptr, param.rows, param.columns);
-  WrapInFunction(Construct(Source{{12, 34}}, matrix_type, std::move(args)));
+    auto* matrix_type = create<ast::Matrix>(nullptr, param.rows, param.columns);
+    WrapInFunction(Construct(Source{{12, 34}}, matrix_type, std::move(args)));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_THAT(r()->error(), err.str());
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_THAT(r()->error(), err.str());
 }
 
 INSTANTIATE_TEST_SUITE_P(ResolverTypeConstructorValidationTest,
@@ -2714,12 +2531,9 @@
 namespace StructConstructor {
 using builder::CreatePtrs;
 using builder::CreatePtrsFor;
-using builder::f32;
-using builder::i32;
 using builder::mat2x2;
 using builder::mat3x3;
 using builder::mat4x4;
-using builder::u32;
 using builder::vec2;
 using builder::vec3;
 using builder::vec4;
@@ -2744,94 +2558,91 @@
     ResolverTestWithParam<std::tuple<CreatePtrs,  // struct member type
                                      uint32_t>>;  // number of struct members
 TEST_P(StructConstructorInputsTest, TooFew) {
-  auto& param = GetParam();
-  auto& str_params = std::get<0>(param);
-  uint32_t N = std::get<1>(param);
+    auto& param = GetParam();
+    auto& str_params = std::get<0>(param);
+    uint32_t N = std::get<1>(param);
 
-  ast::StructMemberList members;
-  ast::ExpressionList values;
-  for (uint32_t i = 0; i < N; i++) {
-    auto* struct_type = str_params.ast(*this);
-    members.push_back(Member("member_" + std::to_string(i), struct_type));
-    if (i < N - 1) {
-      auto* ctor_value_expr = str_params.expr(*this, 0);
-      values.push_back(ctor_value_expr);
+    ast::StructMemberList members;
+    ast::ExpressionList values;
+    for (uint32_t i = 0; i < N; i++) {
+        auto* struct_type = str_params.ast(*this);
+        members.push_back(Member("member_" + std::to_string(i), struct_type));
+        if (i < N - 1) {
+            auto* ctor_value_expr = str_params.expr(*this, 0);
+            values.push_back(ctor_value_expr);
+        }
     }
-  }
-  auto* s = Structure("s", members);
-  auto* tc = Construct(Source{{12, 34}}, ty.Of(s), values);
-  WrapInFunction(tc);
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: struct constructor has too few inputs: expected " +
-                std::to_string(N) + ", found " + std::to_string(N - 1));
+    auto* s = Structure("s", members);
+    auto* tc = Construct(Source{{12, 34}}, ty.Of(s), values);
+    WrapInFunction(tc);
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: struct constructor has too few inputs: expected " +
+                                std::to_string(N) + ", found " + std::to_string(N - 1));
 }
 
 TEST_P(StructConstructorInputsTest, TooMany) {
-  auto& param = GetParam();
-  auto& str_params = std::get<0>(param);
-  uint32_t N = std::get<1>(param);
+    auto& param = GetParam();
+    auto& str_params = std::get<0>(param);
+    uint32_t N = std::get<1>(param);
 
-  ast::StructMemberList members;
-  ast::ExpressionList values;
-  for (uint32_t i = 0; i < N + 1; i++) {
-    if (i < N) {
-      auto* struct_type = str_params.ast(*this);
-      members.push_back(Member("member_" + std::to_string(i), struct_type));
+    ast::StructMemberList members;
+    ast::ExpressionList values;
+    for (uint32_t i = 0; i < N + 1; i++) {
+        if (i < N) {
+            auto* struct_type = str_params.ast(*this);
+            members.push_back(Member("member_" + std::to_string(i), struct_type));
+        }
+        auto* ctor_value_expr = str_params.expr(*this, 0);
+        values.push_back(ctor_value_expr);
     }
-    auto* ctor_value_expr = str_params.expr(*this, 0);
-    values.push_back(ctor_value_expr);
-  }
-  auto* s = Structure("s", members);
-  auto* tc = Construct(Source{{12, 34}}, ty.Of(s), values);
-  WrapInFunction(tc);
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: struct constructor has too many inputs: expected " +
-                std::to_string(N) + ", found " + std::to_string(N + 1));
+    auto* s = Structure("s", members);
+    auto* tc = Construct(Source{{12, 34}}, ty.Of(s), values);
+    WrapInFunction(tc);
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: struct constructor has too many inputs: expected " +
+                                std::to_string(N) + ", found " + std::to_string(N + 1));
 }
 
 INSTANTIATE_TEST_SUITE_P(ResolverTypeConstructorValidationTest,
                          StructConstructorInputsTest,
-                         testing::Combine(testing::ValuesIn(all_types),
-                                          number_of_members));
+                         testing::Combine(testing::ValuesIn(all_types), number_of_members));
 using StructConstructorTypeTest =
     ResolverTestWithParam<std::tuple<CreatePtrs,  // struct member type
                                      CreatePtrs,  // constructor value type
                                      uint32_t>>;  // number of struct members
 TEST_P(StructConstructorTypeTest, AllTypes) {
-  auto& param = GetParam();
-  auto& str_params = std::get<0>(param);
-  auto& ctor_params = std::get<1>(param);
-  uint32_t N = std::get<2>(param);
+    auto& param = GetParam();
+    auto& str_params = std::get<0>(param);
+    auto& ctor_params = std::get<1>(param);
+    uint32_t N = std::get<2>(param);
 
-  if (str_params.ast == ctor_params.ast) {
-    return;
-  }
+    if (str_params.ast == ctor_params.ast) {
+        return;
+    }
 
-  ast::StructMemberList members;
-  ast::ExpressionList values;
-  // make the last value of the constructor to have a different type
-  uint32_t constructor_value_with_different_type = N - 1;
-  for (uint32_t i = 0; i < N; i++) {
-    auto* struct_type = str_params.ast(*this);
-    members.push_back(Member("member_" + std::to_string(i), struct_type));
-    auto* ctor_value_expr = (i == constructor_value_with_different_type)
-                                ? ctor_params.expr(*this, 0)
-                                : str_params.expr(*this, 0);
-    values.push_back(ctor_value_expr);
-  }
-  auto* s = Structure("s", members);
-  auto* tc = Construct(ty.Of(s), values);
-  WrapInFunction(tc);
+    ast::StructMemberList members;
+    ast::ExpressionList values;
+    // make the last value of the constructor to have a different type
+    uint32_t constructor_value_with_different_type = N - 1;
+    for (uint32_t i = 0; i < N; i++) {
+        auto* struct_type = str_params.ast(*this);
+        members.push_back(Member("member_" + std::to_string(i), struct_type));
+        auto* ctor_value_expr = (i == constructor_value_with_different_type)
+                                    ? ctor_params.expr(*this, 0)
+                                    : str_params.expr(*this, 0);
+        values.push_back(ctor_value_expr);
+    }
+    auto* s = Structure("s", members);
+    auto* tc = Construct(ty.Of(s), values);
+    WrapInFunction(tc);
 
-  std::string found = FriendlyName(ctor_params.ast(*this));
-  std::string expected = FriendlyName(str_params.ast(*this));
-  std::stringstream err;
-  err << "error: type in struct constructor does not match struct member ";
-  err << "type: expected '" << expected << "', found '" << found << "'";
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), err.str());
+    std::string found = FriendlyName(ctor_params.ast(*this));
+    std::string expected = FriendlyName(str_params.ast(*this));
+    std::stringstream err;
+    err << "error: type in struct constructor does not match struct member ";
+    err << "type: expected '" << expected << "', found '" << found << "'";
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), err.str());
 }
 
 INSTANTIATE_TEST_SUITE_P(ResolverTypeConstructorValidationTest,
@@ -2841,94 +2652,85 @@
                                           number_of_members));
 
 TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Struct_Nested) {
-  auto* inner_m = Member("m", ty.i32());
-  auto* inner_s = Structure("inner_s", {inner_m});
+    auto* inner_m = Member("m", ty.i32());
+    auto* inner_s = Structure("inner_s", {inner_m});
 
-  auto* m0 = Member("m0", ty.i32());
-  auto* m1 = Member("m1", ty.Of(inner_s));
-  auto* m2 = Member("m2", ty.i32());
-  auto* s = Structure("s", {m0, m1, m2});
+    auto* m0 = Member("m0", ty.i32());
+    auto* m1 = Member("m1", ty.Of(inner_s));
+    auto* m2 = Member("m2", ty.i32());
+    auto* s = Structure("s", {m0, m1, m2});
 
-  auto* tc = Construct(Source{{12, 34}}, ty.Of(s), 1, 1, 1);
-  WrapInFunction(tc);
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "error: type in struct constructor does not match struct member "
-            "type: expected 'inner_s', found 'i32'");
+    auto* tc = Construct(Source{{12, 34}}, ty.Of(s), 1_i, 1_i, 1_i);
+    WrapInFunction(tc);
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "error: type in struct constructor does not match struct member "
+              "type: expected 'inner_s', found 'i32'");
 }
 
 TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Struct) {
-  auto* m = Member("m", ty.i32());
-  auto* s = Structure("MyInputs", {m});
-  auto* tc = Construct(Source{{12, 34}}, ty.Of(s));
-  WrapInFunction(tc);
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    auto* m = Member("m", ty.i32());
+    auto* s = Structure("MyInputs", {m});
+    auto* tc = Construct(Source{{12, 34}}, ty.Of(s));
+    WrapInFunction(tc);
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverTypeConstructorValidationTest, Expr_Constructor_Struct_Empty) {
-  auto* str = Structure("S", {
-                                 Member("a", ty.i32()),
-                                 Member("b", ty.f32()),
-                                 Member("c", ty.vec3<i32>()),
-                             });
+    auto* str = Structure("S", {
+                                   Member("a", ty.i32()),
+                                   Member("b", ty.f32()),
+                                   Member("c", ty.vec3<i32>()),
+                               });
 
-  WrapInFunction(Construct(ty.Of(str)));
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    WrapInFunction(Construct(ty.Of(str)));
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 }  // namespace StructConstructor
 
 TEST_F(ResolverTypeConstructorValidationTest, NonConstructibleType_Atomic) {
-  WrapInFunction(
-      Assign(Phony(), Construct(Source{{12, 34}}, ty.atomic(ty.i32()))));
+    WrapInFunction(Assign(Phony(), Construct(Source{{12, 34}}, ty.atomic(ty.i32()))));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: type is not constructible");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: type is not constructible");
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       NonConstructibleType_AtomicArray) {
-  WrapInFunction(Assign(
-      Phony(), Construct(Source{{12, 34}}, ty.array(ty.atomic(ty.i32()), 4))));
+TEST_F(ResolverTypeConstructorValidationTest, NonConstructibleType_AtomicArray) {
+    WrapInFunction(
+        Assign(Phony(), Construct(Source{{12, 34}}, ty.array(ty.atomic(ty.i32()), 4_i))));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: array constructor has non-constructible element type");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: array constructor has non-constructible element type");
 }
 
-TEST_F(ResolverTypeConstructorValidationTest,
-       NonConstructibleType_AtomicStructMember) {
-  auto* str = Structure("S", {Member("a", ty.atomic(ty.i32()))});
-  WrapInFunction(Assign(Phony(), Construct(Source{{12, 34}}, ty.Of(str))));
+TEST_F(ResolverTypeConstructorValidationTest, NonConstructibleType_AtomicStructMember) {
+    auto* str = Structure("S", {Member("a", ty.atomic(ty.i32()))});
+    WrapInFunction(Assign(Phony(), Construct(Source{{12, 34}}, ty.Of(str))));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: struct constructor has non-constructible type");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: struct constructor has non-constructible type");
 }
 
 TEST_F(ResolverTypeConstructorValidationTest, NonConstructibleType_Sampler) {
-  WrapInFunction(Assign(
-      Phony(),
-      Construct(Source{{12, 34}}, ty.sampler(ast::SamplerKind::kSampler))));
+    WrapInFunction(
+        Assign(Phony(), Construct(Source{{12, 34}}, ty.sampler(ast::SamplerKind::kSampler))));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: type is not constructible");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: type is not constructible");
 }
 
 TEST_F(ResolverTypeConstructorValidationTest, TypeConstructorAsStatement) {
-  WrapInFunction(
-      CallStmt(Construct(Source{{12, 34}}, ty.vec2<f32>(), 1.f, 2.f)));
+    WrapInFunction(CallStmt(Construct(Source{{12, 34}}, ty.vec2<f32>(), 1.f, 2.f)));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: type constructor evaluated but not used");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: type constructor evaluated but not used");
 }
 
 TEST_F(ResolverTypeConstructorValidationTest, TypeConversionAsStatement) {
-  WrapInFunction(CallStmt(Construct(Source{{12, 34}}, ty.f32(), 1)));
+    WrapInFunction(CallStmt(Construct(Source{{12, 34}}, ty.f32(), 1_i)));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: type cast evaluated but not used");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: type cast evaluated but not used");
 }
 
 }  // namespace
diff --git a/src/tint/resolver/type_validation_test.cc b/src/tint/resolver/type_validation_test.cc
index dadd7d2..2af2c0e 100644
--- a/src/tint/resolver/type_validation_test.cc
+++ b/src/tint/resolver/type_validation_test.cc
@@ -17,11 +17,13 @@
 #include "src/tint/ast/stage_attribute.h"
 #include "src/tint/resolver/resolver.h"
 #include "src/tint/resolver/resolver_test_helper.h"
-#include "src/tint/sem/multisampled_texture_type.h"
-#include "src/tint/sem/storage_texture_type.h"
+#include "src/tint/sem/multisampled_texture.h"
+#include "src/tint/sem/storage_texture.h"
 
 #include "gmock/gmock.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::resolver {
 namespace {
 
@@ -50,677 +52,625 @@
 using alias2 = builder::alias2<T>;
 template <typename T>
 using alias3 = builder::alias3<T>;
-using f32 = builder::f32;
-using i32 = builder::i32;
-using u32 = builder::u32;
 
-class ResolverTypeValidationTest : public resolver::TestHelper,
-                                   public testing::Test {};
+class ResolverTypeValidationTest : public resolver::TestHelper, public testing::Test {};
 
 TEST_F(ResolverTypeValidationTest, VariableDeclNoConstructor_Pass) {
-  // {
-  // var a :i32;
-  // a = 2;
-  // }
-  auto* var = Var("a", ty.i32(), ast::StorageClass::kNone, nullptr);
-  auto* lhs = Expr("a");
-  auto* rhs = Expr(2);
+    // {
+    // var a :i32;
+    // a = 2;
+    // }
+    auto* var = Var("a", ty.i32(), ast::StorageClass::kNone, nullptr);
+    auto* lhs = Expr("a");
+    auto* rhs = Expr(2_i);
 
-  auto* body =
-      Block(Decl(var), Assign(Source{Source::Location{12, 34}}, lhs, rhs));
+    auto* body = Block(Decl(var), Assign(Source{Source::Location{12, 34}}, lhs, rhs));
 
-  WrapInFunction(body);
+    WrapInFunction(body);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-  ASSERT_NE(TypeOf(lhs), nullptr);
-  ASSERT_NE(TypeOf(rhs), nullptr);
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_NE(TypeOf(lhs), nullptr);
+    ASSERT_NE(TypeOf(rhs), nullptr);
 }
 
 TEST_F(ResolverTypeValidationTest, GlobalConstantNoConstructor_Pass) {
-  // @id(0) override a :i32;
-  Override(Source{{12, 34}}, "a", ty.i32(), nullptr, ast::AttributeList{Id(0)});
+    // @id(0) override a :i32;
+    Override(Source{{12, 34}}, "a", ty.i32(), nullptr, ast::AttributeList{Id(0)});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverTypeValidationTest, GlobalVariableWithStorageClass_Pass) {
-  // var<private> global_var: f32;
-  Global(Source{{12, 34}}, "global_var", ty.f32(), ast::StorageClass::kPrivate);
+    // var<private> global_var: f32;
+    Global(Source{{12, 34}}, "global_var", ty.f32(), ast::StorageClass::kPrivate);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverTypeValidationTest, GlobalConstantWithStorageClass_Fail) {
-  // const<private> global_var: f32;
-  AST().AddGlobalVariable(create<ast::Variable>(
-      Source{{12, 34}}, Symbols().Register("global_var"),
-      ast::StorageClass::kPrivate, ast::Access::kUndefined, ty.f32(), true,
-      false, Expr(1.23f), ast::AttributeList{}));
+    // const<private> global_var: f32;
+    AST().AddGlobalVariable(create<ast::Variable>(
+        Source{{12, 34}}, Symbols().Register("global_var"), ast::StorageClass::kPrivate,
+        ast::Access::kUndefined, ty.f32(), true, false, Expr(1.23f), ast::AttributeList{}));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: global constants shouldn't have a storage class");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: global constants shouldn't have a storage class");
 }
 
 TEST_F(ResolverTypeValidationTest, GlobalConstNoStorageClass_Pass) {
-  // let global_var: f32;
-  GlobalConst(Source{{12, 34}}, "global_var", ty.f32(), Construct(ty.f32()));
+    // let global_var: f32;
+    GlobalConst(Source{{12, 34}}, "global_var", ty.f32(), Construct(ty.f32()));
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverTypeValidationTest, GlobalVariableUnique_Pass) {
-  // var global_var0 : f32 = 0.1;
-  // var global_var1 : i32 = 0;
+    // var global_var0 : f32 = 0.1;
+    // var global_var1 : i32 = 0;
 
-  Global("global_var0", ty.f32(), ast::StorageClass::kPrivate, Expr(0.1f));
+    Global("global_var0", ty.f32(), ast::StorageClass::kPrivate, Expr(0.1f));
 
-  Global(Source{{12, 34}}, "global_var1", ty.f32(), ast::StorageClass::kPrivate,
-         Expr(1.0f));
+    Global(Source{{12, 34}}, "global_var1", ty.f32(), ast::StorageClass::kPrivate, Expr(1.0f));
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
-TEST_F(ResolverTypeValidationTest,
-       GlobalVariableFunctionVariableNotUnique_Pass) {
-  // fn my_func() {
-  //   var a: f32 = 2.0;
-  // }
-  // var a: f32 = 2.1;
+TEST_F(ResolverTypeValidationTest, GlobalVariableFunctionVariableNotUnique_Pass) {
+    // fn my_func() {
+    //   var a: f32 = 2.0;
+    // }
+    // var a: f32 = 2.1;
 
-  auto* var = Var("a", ty.f32(), ast::StorageClass::kNone, Expr(2.0f));
+    auto* var = Var("a", ty.f32(), ast::StorageClass::kNone, Expr(2.0f));
 
-  Func("my_func", ast::VariableList{}, ty.void_(), {Decl(var)});
+    Func("my_func", ast::VariableList{}, ty.void_(), {Decl(var)});
 
-  Global("a", ty.f32(), ast::StorageClass::kPrivate, Expr(2.1f));
+    Global("a", ty.f32(), ast::StorageClass::kPrivate, Expr(2.1f));
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverTypeValidationTest, RedeclaredIdentifierInnerScope_Pass) {
-  // {
-  // if (true) { var a : f32 = 2.0; }
-  // var a : f32 = 3.14;
-  // }
-  auto* var = Var("a", ty.f32(), ast::StorageClass::kNone, Expr(2.0f));
+    // {
+    // if (true) { var a : f32 = 2.0; }
+    // var a : f32 = 3.14;
+    // }
+    auto* var = Var("a", ty.f32(), ast::StorageClass::kNone, Expr(2.0f));
 
-  auto* cond = Expr(true);
-  auto* body = Block(Decl(var));
+    auto* cond = Expr(true);
+    auto* body = Block(Decl(var));
 
-  auto* var_a_float = Var("a", ty.f32(), ast::StorageClass::kNone, Expr(3.1f));
+    auto* var_a_float = Var("a", ty.f32(), ast::StorageClass::kNone, Expr(3.1f));
 
-  auto* outer_body =
-      Block(create<ast::IfStatement>(cond, body, ast::ElseStatementList{}),
-            Decl(Source{{12, 34}}, var_a_float));
+    auto* outer_body = Block(If(cond, body), Decl(Source{{12, 34}}, var_a_float));
 
-  WrapInFunction(outer_body);
+    WrapInFunction(outer_body);
 
-  EXPECT_TRUE(r()->Resolve());
+    EXPECT_TRUE(r()->Resolve());
 }
 
 TEST_F(ResolverTypeValidationTest, RedeclaredIdentifierInnerScopeBlock_Pass) {
-  // {
-  //  { var a : f32; }
-  //  var a : f32;
-  // }
-  auto* var_inner = Var("a", ty.f32(), ast::StorageClass::kNone);
-  auto* inner = Block(Decl(Source{{12, 34}}, var_inner));
+    // {
+    //  { var a : f32; }
+    //  var a : f32;
+    // }
+    auto* var_inner = Var("a", ty.f32(), ast::StorageClass::kNone);
+    auto* inner = Block(Decl(Source{{12, 34}}, var_inner));
 
-  auto* var_outer = Var("a", ty.f32(), ast::StorageClass::kNone);
-  auto* outer_body = Block(inner, Decl(var_outer));
+    auto* var_outer = Var("a", ty.f32(), ast::StorageClass::kNone);
+    auto* outer_body = Block(inner, Decl(var_outer));
 
-  WrapInFunction(outer_body);
+    WrapInFunction(outer_body);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
-TEST_F(ResolverTypeValidationTest,
-       RedeclaredIdentifierDifferentFunctions_Pass) {
-  // func0 { var a : f32 = 2.0; return; }
-  // func1 { var a : f32 = 3.0; return; }
-  auto* var0 = Var("a", ty.f32(), ast::StorageClass::kNone, Expr(2.0f));
+TEST_F(ResolverTypeValidationTest, RedeclaredIdentifierDifferentFunctions_Pass) {
+    // func0 { var a : f32 = 2.0; return; }
+    // func1 { var a : f32 = 3.0; return; }
+    auto* var0 = Var("a", ty.f32(), ast::StorageClass::kNone, Expr(2.0f));
 
-  auto* var1 = Var("a", ty.f32(), ast::StorageClass::kNone, Expr(1.0f));
+    auto* var1 = Var("a", ty.f32(), ast::StorageClass::kNone, Expr(1.0f));
 
-  Func("func0", ast::VariableList{}, ty.void_(),
-       ast::StatementList{
-           Decl(Source{{12, 34}}, var0),
-           Return(),
-       },
-       ast::AttributeList{});
+    Func("func0", ast::VariableList{}, ty.void_(),
+         ast::StatementList{
+             Decl(Source{{12, 34}}, var0),
+             Return(),
+         },
+         ast::AttributeList{});
 
-  Func("func1", ast::VariableList{}, ty.void_(),
-       ast::StatementList{
-           Decl(Source{{13, 34}}, var1),
-           Return(),
-       });
+    Func("func1", ast::VariableList{}, ty.void_(),
+         ast::StatementList{
+             Decl(Source{{13, 34}}, var1),
+             Return(),
+         });
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverTypeValidationTest, ArraySize_UnsignedLiteral_Pass) {
-  // var<private> a : array<f32, 4u>;
-  Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 4u)),
-         ast::StorageClass::kPrivate);
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    // var<private> a : array<f32, 4u>;
+    Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 4_u)), ast::StorageClass::kPrivate);
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverTypeValidationTest, ArraySize_SignedLiteral_Pass) {
-  // var<private> a : array<f32, 4>;
-  Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 4)),
-         ast::StorageClass::kPrivate);
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    // var<private> a : array<f32, 4i>;
+    Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 4_i)), ast::StorageClass::kPrivate);
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverTypeValidationTest, ArraySize_UnsignedConstant_Pass) {
-  // let size = 4u;
-  // var<private> a : array<f32, size>;
-  GlobalConst("size", nullptr, Expr(4u));
-  Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")),
-         ast::StorageClass::kPrivate);
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    // let size = 4u;
+    // var<private> a : array<f32, size>;
+    GlobalConst("size", nullptr, Expr(4_u));
+    Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::StorageClass::kPrivate);
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverTypeValidationTest, ArraySize_SignedConstant_Pass) {
-  // let size = 4;
-  // var<private> a : array<f32, size>;
-  GlobalConst("size", nullptr, Expr(4));
-  Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")),
-         ast::StorageClass::kPrivate);
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    // let size = 4i;
+    // var<private> a : array<f32, size>;
+    GlobalConst("size", nullptr, Expr(4_i));
+    Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::StorageClass::kPrivate);
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverTypeValidationTest, ArraySize_UnsignedLiteral_Zero) {
-  // var<private> a : array<f32, 0u>;
-  Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 0u)),
-         ast::StorageClass::kPrivate);
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: array size must be at least 1");
+    // var<private> a : array<f32, 0u>;
+    Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 0_u)), ast::StorageClass::kPrivate);
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: array size must be at least 1");
 }
 
 TEST_F(ResolverTypeValidationTest, ArraySize_SignedLiteral_Zero) {
-  // var<private> a : array<f32, 0>;
-  Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 0)),
-         ast::StorageClass::kPrivate);
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: array size must be at least 1");
+    // var<private> a : array<f32, 0i>;
+    Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 0_i)), ast::StorageClass::kPrivate);
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: array size must be at least 1");
 }
 
 TEST_F(ResolverTypeValidationTest, ArraySize_SignedLiteral_Negative) {
-  // var<private> a : array<f32, -10>;
-  Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, -10)),
-         ast::StorageClass::kPrivate);
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: array size must be at least 1");
+    // var<private> a : array<f32, -10i>;
+    Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, i32(-10))), ast::StorageClass::kPrivate);
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: array size must be at least 1");
 }
 
 TEST_F(ResolverTypeValidationTest, ArraySize_UnsignedConstant_Zero) {
-  // let size = 0u;
-  // var<private> a : array<f32, size>;
-  GlobalConst("size", nullptr, Expr(0u));
-  Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")),
-         ast::StorageClass::kPrivate);
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: array size must be at least 1");
+    // let size = 0u;
+    // var<private> a : array<f32, size>;
+    GlobalConst("size", nullptr, Expr(0_u));
+    Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::StorageClass::kPrivate);
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: array size must be at least 1");
 }
 
 TEST_F(ResolverTypeValidationTest, ArraySize_SignedConstant_Zero) {
-  // let size = 0;
-  // var<private> a : array<f32, size>;
-  GlobalConst("size", nullptr, Expr(0));
-  Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")),
-         ast::StorageClass::kPrivate);
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: array size must be at least 1");
+    // let size = 0i;
+    // var<private> a : array<f32, size>;
+    GlobalConst("size", nullptr, Expr(0_i));
+    Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::StorageClass::kPrivate);
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: array size must be at least 1");
 }
 
 TEST_F(ResolverTypeValidationTest, ArraySize_SignedConstant_Negative) {
-  // let size = -10;
-  // var<private> a : array<f32, size>;
-  GlobalConst("size", nullptr, Expr(-10));
-  Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")),
-         ast::StorageClass::kPrivate);
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: array size must be at least 1");
+    // let size = -10i;
+    // var<private> a : array<f32, size>;
+    GlobalConst("size", nullptr, Expr(i32(-10)));
+    Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::StorageClass::kPrivate);
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: array size must be at least 1");
 }
 
 TEST_F(ResolverTypeValidationTest, ArraySize_FloatLiteral) {
-  // var<private> a : array<f32, 10.0>;
-  Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 10.f)),
-         ast::StorageClass::kPrivate);
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: array size must be integer scalar");
+    // var<private> a : array<f32, 10.0>;
+    Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, 10.f)), ast::StorageClass::kPrivate);
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: array size must be integer scalar");
 }
 
 TEST_F(ResolverTypeValidationTest, ArraySize_IVecLiteral) {
-  // var<private> a : array<f32, vec2<i32>(10, 10)>;
-  Global(
-      "a",
-      ty.array(ty.f32(), Construct(Source{{12, 34}}, ty.vec2<i32>(), 10, 10)),
-      ast::StorageClass::kPrivate);
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: array size must be integer scalar");
+    // var<private> a : array<f32, vec2<i32>(10, 10)>;
+    Global("a", ty.array(ty.f32(), Construct(Source{{12, 34}}, ty.vec2<i32>(), 10_i, 10_i)),
+           ast::StorageClass::kPrivate);
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: array size must be integer scalar");
 }
 
 TEST_F(ResolverTypeValidationTest, ArraySize_FloatConstant) {
-  // let size = 10.0;
-  // var<private> a : array<f32, size>;
-  GlobalConst("size", nullptr, Expr(10.f));
-  Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")),
-         ast::StorageClass::kPrivate);
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: array size must be integer scalar");
+    // let size = 10.0;
+    // var<private> a : array<f32, size>;
+    GlobalConst("size", nullptr, Expr(10.f));
+    Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::StorageClass::kPrivate);
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: array size must be integer scalar");
 }
 
 TEST_F(ResolverTypeValidationTest, ArraySize_IVecConstant) {
-  // let size = vec2<i32>(100, 100);
-  // var<private> a : array<f32, size>;
-  GlobalConst("size", nullptr, Construct(ty.vec2<i32>(), 100, 100));
-  Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")),
-         ast::StorageClass::kPrivate);
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: array size must be integer scalar");
+    // let size = vec2<i32>(100, 100);
+    // var<private> a : array<f32, size>;
+    GlobalConst("size", nullptr, Construct(ty.vec2<i32>(), 100_i, 100_i));
+    Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::StorageClass::kPrivate);
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: array size must be integer scalar");
 }
 
 TEST_F(ResolverTypeValidationTest, ArraySize_TooBig_ImplicitStride) {
-  // var<private> a : array<f32, 0x40000000>;
-  Global("a", ty.array(Source{{12, 34}}, ty.f32(), 0x40000000),
-         ast::StorageClass::kPrivate);
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: array size in bytes must not exceed 0xffffffff, but "
-            "is 0x100000000");
+    // var<private> a : array<f32, 0x40000000u>;
+    Global("a", ty.array(Source{{12, 34}}, ty.f32(), 0x40000000_u), ast::StorageClass::kPrivate);
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: array size in bytes must not exceed 0xffffffff, but "
+              "is 0x100000000");
 }
 
 TEST_F(ResolverTypeValidationTest, ArraySize_TooBig_ExplicitStride) {
-  // var<private> a : @stride(8) array<f32, 0x20000000>;
-  Global("a", ty.array(Source{{12, 34}}, ty.f32(), 0x20000000, 8),
-         ast::StorageClass::kPrivate);
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: array size in bytes must not exceed 0xffffffff, but "
-            "is 0x100000000");
+    // var<private> a : @stride(8) array<f32, 0x20000000u>;
+    Global("a", ty.array(Source{{12, 34}}, ty.f32(), 0x20000000_u, 8), ast::StorageClass::kPrivate);
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: array size in bytes must not exceed 0xffffffff, but "
+              "is 0x100000000");
 }
 
 TEST_F(ResolverTypeValidationTest, ArraySize_OverridableConstant) {
-  // override size = 10;
-  // var<private> a : array<f32, size>;
-  Override("size", nullptr, Expr(10));
-  Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")),
-         ast::StorageClass::kPrivate);
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: array size expression must not be pipeline-overridable");
+    // override size = 10i;
+    // var<private> a : array<f32, size>;
+    Override("size", nullptr, Expr(10_i));
+    Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::StorageClass::kPrivate);
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: array size expression must not be pipeline-overridable");
 }
 
 TEST_F(ResolverTypeValidationTest, ArraySize_ModuleVar) {
-  // var<private> size : i32 = 10;
-  // var<private> a : array<f32, size>;
-  Global("size", ty.i32(), Expr(10), ast::StorageClass::kPrivate);
-  Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")),
-         ast::StorageClass::kPrivate);
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: array size identifier must be a module-scope constant");
+    // var<private> size : i32 = 10i;
+    // var<private> a : array<f32, size>;
+    Global("size", ty.i32(), Expr(10_i), ast::StorageClass::kPrivate);
+    Global("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")), ast::StorageClass::kPrivate);
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: array size identifier must be a module-scope constant");
 }
 
 TEST_F(ResolverTypeValidationTest, ArraySize_FunctionConstant) {
-  // {
-  //   let size = 10;
-  //   var a : array<f32, size>;
-  // }
-  auto* size = Const("size", nullptr, Expr(10));
-  auto* a = Var("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")));
-  WrapInFunction(Block(Decl(size), Decl(a)));
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: array size identifier must be a module-scope constant");
+    // {
+    //   let size = 10;
+    //   var a : array<f32, size>;
+    // }
+    auto* size = Let("size", nullptr, Expr(10_i));
+    auto* a = Var("a", ty.array(ty.f32(), Expr(Source{{12, 34}}, "size")));
+    WrapInFunction(Block(Decl(size), Decl(a)));
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: array size identifier must be a module-scope constant");
 }
 
 TEST_F(ResolverTypeValidationTest, ArraySize_InvalidExpr) {
-  // var a : array<f32, i32(4)>;
-  auto* size = Const("size", nullptr, Expr(10));
-  auto* a =
-      Var("a", ty.array(ty.f32(), Construct(Source{{12, 34}}, ty.i32(), 4)));
-  WrapInFunction(Block(Decl(size), Decl(a)));
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: array size expression must be either a literal or a "
-            "module-scope constant");
+    // var a : array<f32, i32(4i)>;
+    auto* a = Var("a", ty.array(ty.f32(), Construct(Source{{12, 34}}, ty.i32(), 4_i)));
+    WrapInFunction(Block(Decl(a)));
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: array size expression must be either a literal or a "
+              "module-scope constant");
 }
 
 TEST_F(ResolverTypeValidationTest, RuntimeArrayInFunction_Fail) {
-  /// @stage(vertex)
-  // fn func() { var a : array<i32>; }
+    /// @stage(vertex)
+    // fn func() { var a : array<i32>; }
 
-  auto* var =
-      Var(Source{{12, 34}}, "a", ty.array<i32>(), ast::StorageClass::kNone);
+    auto* var = Var(Source{{12, 34}}, "a", ty.array<i32>(), ast::StorageClass::kNone);
 
-  Func("func", ast::VariableList{}, ty.void_(),
-       ast::StatementList{
-           Decl(var),
-       },
-       ast::AttributeList{
-           Stage(ast::PipelineStage::kVertex),
-       });
+    Func("func", ast::VariableList{}, ty.void_(),
+         ast::StatementList{
+             Decl(var),
+         },
+         ast::AttributeList{
+             Stage(ast::PipelineStage::kVertex),
+         });
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: runtime-sized arrays can only be used in the <storage> storage class
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: runtime-sized arrays can only be used in the <storage> storage class
 12:34 note: while instantiating variable a)");
 }
 
 TEST_F(ResolverTypeValidationTest, Struct_Member_VectorNoType) {
-  // struct S {
-  //   a: vec3;
-  // };
+    // struct S {
+    //   a: vec3;
+    // };
 
-  Structure("S",
-            {Member("a", create<ast::Vector>(Source{{12, 34}}, nullptr, 3))});
+    Structure("S", {Member("a", create<ast::Vector>(Source{{12, 34}}, nullptr, 3))});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: missing vector element type");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: missing vector element type");
 }
 
 TEST_F(ResolverTypeValidationTest, Struct_Member_MatrixNoType) {
-  // struct S {
-  //   a: mat3x3;
-  // };
-  Structure(
-      "S", {Member("a", create<ast::Matrix>(Source{{12, 34}}, nullptr, 3, 3))});
+    // struct S {
+    //   a: mat3x3;
+    // };
+    Structure("S", {Member("a", create<ast::Matrix>(Source{{12, 34}}, nullptr, 3, 3))});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: missing matrix element type");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: missing matrix element type");
 }
 
 TEST_F(ResolverTypeValidationTest, Struct_TooBig) {
-  // struct Foo {
-  //   a: array<f32, 0x20000000>;
-  //   b: array<f32, 0x20000000>;
-  // };
+    // struct Foo {
+    //   a: array<f32, 0x20000000>;
+    //   b: array<f32, 0x20000000>;
+    // };
 
-  Structure(Source{{12, 34}}, "Foo",
-            {
-                Member("a", ty.array<f32, 0x20000000>()),
-                Member("b", ty.array<f32, 0x20000000>()),
-            });
+    Structure(Source{{12, 34}}, "Foo",
+              {
+                  Member("a", ty.array<f32, 0x20000000>()),
+                  Member("b", ty.array<f32, 0x20000000>()),
+              });
 
-  WrapInFunction();
+    WrapInFunction();
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: struct size in bytes must not exceed 0xffffffff, but "
-            "is 0x100000000");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: struct size in bytes must not exceed 0xffffffff, but "
+              "is 0x100000000");
 }
 
 TEST_F(ResolverTypeValidationTest, Struct_MemberOffset_TooBig) {
-  // struct Foo {
-  //   a: array<f32, 0x3fffffff>;
-  //   b: f32;
-  //   c: f32;
-  // };
+    // struct Foo {
+    //   a: array<f32, 0x3fffffff>;
+    //   b: f32;
+    //   c: f32;
+    // };
 
-  Structure("Foo", {
-                       Member("a", ty.array<f32, 0x3fffffff>()),
-                       Member("b", ty.f32()),
-                       Member(Source{{12, 34}}, "c", ty.f32()),
-                   });
+    Structure("Foo", {
+                         Member("a", ty.array<f32, 0x3fffffff>()),
+                         Member("b", ty.f32()),
+                         Member(Source{{12, 34}}, "c", ty.f32()),
+                     });
 
-  WrapInFunction();
+    WrapInFunction();
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: struct member has byte offset 0x100000000, but must "
-            "not exceed 0xffffffff");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: struct member has byte offset 0x100000000, but must "
+              "not exceed 0xffffffff");
 }
 
 TEST_F(ResolverTypeValidationTest, RuntimeArrayIsLast_Pass) {
-  // struct Foo {
-  //   vf: f32;
-  //   rt: array<f32>;
-  // };
+    // struct Foo {
+    //   vf: f32;
+    //   rt: array<f32>;
+    // };
 
-  Structure("Foo", {
-                       Member("vf", ty.f32()),
-                       Member("rt", ty.array<f32>()),
-                   });
+    Structure("Foo", {
+                         Member("vf", ty.f32()),
+                         Member("rt", ty.array<f32>()),
+                     });
 
-  WrapInFunction();
+    WrapInFunction();
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverTypeValidationTest, RuntimeArrayInArray) {
-  // struct Foo {
-  //   rt : array<array<f32>, 4>;
-  // };
+    // struct Foo {
+    //   rt : array<array<f32>, 4u>;
+    // };
 
-  Structure("Foo",
-            {Member("rt", ty.array(Source{{12, 34}}, ty.array<f32>(), 4))});
+    Structure("Foo", {Member("rt", ty.array(Source{{12, 34}}, ty.array<f32>(), 4_u))});
 
-  EXPECT_FALSE(r()->Resolve()) << r()->error();
-  EXPECT_EQ(r()->error(),
-            "12:34 error: an array element type cannot contain a runtime-sized "
-            "array");
+    EXPECT_FALSE(r()->Resolve()) << r()->error();
+    EXPECT_EQ(r()->error(),
+              "12:34 error: an array element type cannot contain a runtime-sized "
+              "array");
 }
 
 TEST_F(ResolverTypeValidationTest, RuntimeArrayInStructInArray) {
-  // struct Foo {
-  //   rt : array<f32>;
-  // };
-  // var<private> a : array<Foo, 4>;
+    // struct Foo {
+    //   rt : array<f32>;
+    // };
+    // var<private> a : array<Foo, 4>;
 
-  auto* foo = Structure("Foo", {Member("rt", ty.array<f32>())});
-  Global("v", ty.array(Source{{12, 34}}, ty.Of(foo), 4),
-         ast::StorageClass::kPrivate);
+    auto* foo = Structure("Foo", {Member("rt", ty.array<f32>())});
+    Global("v", ty.array(Source{{12, 34}}, ty.Of(foo), 4_u), ast::StorageClass::kPrivate);
 
-  EXPECT_FALSE(r()->Resolve()) << r()->error();
-  EXPECT_EQ(r()->error(),
-            "12:34 error: an array element type cannot contain a runtime-sized "
-            "array");
+    EXPECT_FALSE(r()->Resolve()) << r()->error();
+    EXPECT_EQ(r()->error(),
+              "12:34 error: an array element type cannot contain a runtime-sized "
+              "array");
 }
 
 TEST_F(ResolverTypeValidationTest, RuntimeArrayInStructInStruct) {
-  // struct Foo {
-  //   rt : array<f32>;
-  // };
-  // struct Outer {
-  //   inner : Foo;
-  // };
+    // struct Foo {
+    //   rt : array<f32>;
+    // };
+    // struct Outer {
+    //   inner : Foo;
+    // };
 
-  auto* foo = Structure("Foo", {Member("rt", ty.array<f32>())});
-  Structure("Outer", {Member(Source{{12, 34}}, "inner", ty.Of(foo))});
+    auto* foo = Structure("Foo", {Member("rt", ty.array<f32>())});
+    Structure("Outer", {Member(Source{{12, 34}}, "inner", ty.Of(foo))});
 
-  EXPECT_FALSE(r()->Resolve()) << r()->error();
-  EXPECT_EQ(r()->error(),
-            "12:34 error: a struct that contains a runtime array cannot be "
-            "nested inside another struct");
+    EXPECT_FALSE(r()->Resolve()) << r()->error();
+    EXPECT_EQ(r()->error(),
+              "12:34 error: a struct that contains a runtime array cannot be "
+              "nested inside another struct");
 }
 
 TEST_F(ResolverTypeValidationTest, RuntimeArrayIsNotLast_Fail) {
-  // struct Foo {
-  //   rt: array<f32>;
-  //   vf: f32;
-  // };
+    // struct Foo {
+    //   rt: array<f32>;
+    //   vf: f32;
+    // };
 
-  Structure("Foo", {
-                       Member(Source{{12, 34}}, "rt", ty.array<f32>()),
-                       Member("vf", ty.f32()),
-                   });
+    Structure("Foo", {
+                         Member(Source{{12, 34}}, "rt", ty.array<f32>()),
+                         Member("vf", ty.f32()),
+                     });
 
-  WrapInFunction();
+    WrapInFunction();
 
-  EXPECT_FALSE(r()->Resolve()) << r()->error();
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: runtime arrays may only appear as the last member of a struct)");
+    EXPECT_FALSE(r()->Resolve()) << r()->error();
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: runtime arrays may only appear as the last member of a struct)");
 }
 
 TEST_F(ResolverTypeValidationTest, RuntimeArrayAsGlobalVariable) {
-  Global(Source{{56, 78}}, "g", ty.array<i32>(), ast::StorageClass::kPrivate);
+    Global(Source{{56, 78}}, "g", ty.array<i32>(), ast::StorageClass::kPrivate);
 
-  ASSERT_FALSE(r()->Resolve());
+    ASSERT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(
-      r()->error(),
-      R"(56:78 error: runtime-sized arrays can only be used in the <storage> storage class
+    EXPECT_EQ(r()->error(),
+              R"(56:78 error: runtime-sized arrays can only be used in the <storage> storage class
 56:78 note: while instantiating variable g)");
 }
 
 TEST_F(ResolverTypeValidationTest, RuntimeArrayAsLocalVariable) {
-  auto* v = Var(Source{{56, 78}}, "g", ty.array<i32>());
-  WrapInFunction(v);
+    auto* v = Var(Source{{56, 78}}, "g", ty.array<i32>());
+    WrapInFunction(v);
 
-  ASSERT_FALSE(r()->Resolve());
+    ASSERT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(
-      r()->error(),
-      R"(56:78 error: runtime-sized arrays can only be used in the <storage> storage class
+    EXPECT_EQ(r()->error(),
+              R"(56:78 error: runtime-sized arrays can only be used in the <storage> storage class
 56:78 note: while instantiating variable g)");
 }
 
 TEST_F(ResolverTypeValidationTest, RuntimeArrayAsParameter_Fail) {
-  // fn func(a : array<u32>) {}
-  // @stage(vertex) fn main() {}
+    // fn func(a : array<u32>) {}
+    // @stage(vertex) fn main() {}
 
-  auto* param = Param(Source{{12, 34}}, "a", ty.array<i32>());
+    auto* param = Param(Source{{12, 34}}, "a", ty.array<i32>());
 
-  Func("func", ast::VariableList{param}, ty.void_(),
-       ast::StatementList{
-           Return(),
-       },
-       ast::AttributeList{});
+    Func("func", ast::VariableList{param}, ty.void_(),
+         ast::StatementList{
+             Return(),
+         },
+         ast::AttributeList{});
 
-  Func("main", ast::VariableList{}, ty.void_(),
-       ast::StatementList{
-           Return(),
-       },
-       ast::AttributeList{
-           Stage(ast::PipelineStage::kVertex),
-       });
+    Func("main", ast::VariableList{}, ty.void_(),
+         ast::StatementList{
+             Return(),
+         },
+         ast::AttributeList{
+             Stage(ast::PipelineStage::kVertex),
+         });
 
-  EXPECT_FALSE(r()->Resolve()) << r()->error();
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: runtime-sized arrays can only be used in the <storage> storage class
+    EXPECT_FALSE(r()->Resolve()) << r()->error();
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: runtime-sized arrays can only be used in the <storage> storage class
 12:34 note: while instantiating parameter a)");
 }
 
 TEST_F(ResolverTypeValidationTest, PtrToRuntimeArrayAsParameter_Fail) {
-  // fn func(a : ptr<workgroup, array<u32>>) {}
+    // fn func(a : ptr<workgroup, array<u32>>) {}
 
-  auto* param =
-      Param(Source{{12, 34}}, "a",
-            ty.pointer(ty.array<i32>(), ast::StorageClass::kWorkgroup));
+    auto* param =
+        Param(Source{{12, 34}}, "a", ty.pointer(ty.array<i32>(), ast::StorageClass::kWorkgroup));
 
-  Func("func", ast::VariableList{param}, ty.void_(),
-       ast::StatementList{
-           Return(),
-       },
-       ast::AttributeList{});
+    Func("func", ast::VariableList{param}, ty.void_(),
+         ast::StatementList{
+             Return(),
+         },
+         ast::AttributeList{});
 
-  EXPECT_FALSE(r()->Resolve()) << r()->error();
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: runtime-sized arrays can only be used in the <storage> storage class
+    EXPECT_FALSE(r()->Resolve()) << r()->error();
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: runtime-sized arrays can only be used in the <storage> storage class
 12:34 note: while instantiating parameter a)");
 }
 
 TEST_F(ResolverTypeValidationTest, AliasRuntimeArrayIsNotLast_Fail) {
-  // type RTArr = array<u32>;
-  // struct s {
-  //  b: RTArr;
-  //  a: u32;
-  //}
+    // type RTArr = array<u32>;
+    // struct s {
+    //  b: RTArr;
+    //  a: u32;
+    //}
 
-  auto* alias = Alias("RTArr", ty.array<u32>());
-  Structure("s", {
-                     Member(Source{{12, 34}}, "b", ty.Of(alias)),
-                     Member("a", ty.u32()),
-                 });
+    auto* alias = Alias("RTArr", ty.array<u32>());
+    Structure("s", {
+                       Member(Source{{12, 34}}, "b", ty.Of(alias)),
+                       Member("a", ty.u32()),
+                   });
 
-  WrapInFunction();
+    WrapInFunction();
 
-  EXPECT_FALSE(r()->Resolve()) << r()->error();
-  EXPECT_EQ(r()->error(),
-            "12:34 error: runtime arrays may only appear as the last member of "
-            "a struct");
+    EXPECT_FALSE(r()->Resolve()) << r()->error();
+    EXPECT_EQ(r()->error(),
+              "12:34 error: runtime arrays may only appear as the last member of "
+              "a struct");
 }
 
 TEST_F(ResolverTypeValidationTest, AliasRuntimeArrayIsLast_Pass) {
-  // type RTArr = array<u32>;
-  // struct s {
-  //  a: u32;
-  //  b: RTArr;
-  //}
+    // type RTArr = array<u32>;
+    // struct s {
+    //  a: u32;
+    //  b: RTArr;
+    //}
 
-  auto* alias = Alias("RTArr", ty.array<u32>());
-  Structure("s", {
-                     Member("a", ty.u32()),
-                     Member("b", ty.Of(alias)),
-                 });
+    auto* alias = Alias("RTArr", ty.array<u32>());
+    Structure("s", {
+                       Member("a", ty.u32()),
+                       Member("b", ty.Of(alias)),
+                   });
 
-  WrapInFunction();
+    WrapInFunction();
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverTypeValidationTest, ArrayOfNonStorableType) {
-  auto* tex_ty = ty.sampled_texture(ast::TextureDimension::k2d, ty.f32());
-  Global("arr", ty.array(Source{{12, 34}}, tex_ty, 4),
-         ast::StorageClass::kPrivate);
+    auto* tex_ty = ty.sampled_texture(ast::TextureDimension::k2d, ty.f32());
+    Global("arr", ty.array(Source{{12, 34}}, tex_ty, 4_i), ast::StorageClass::kPrivate);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: texture_2d<f32> cannot be used as an element type of "
-            "an array");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: texture_2d<f32> cannot be used as an element type of "
+              "an array");
 }
 
 TEST_F(ResolverTypeValidationTest, VariableAsType) {
-  // var<private> a : i32;
-  // var<private> b : a;
-  Global("a", ty.i32(), ast::StorageClass::kPrivate);
-  Global("b", ty.type_name("a"), ast::StorageClass::kPrivate);
+    // var<private> a : i32;
+    // var<private> b : a;
+    Global("a", ty.i32(), ast::StorageClass::kPrivate);
+    Global("b", ty.type_name("a"), ast::StorageClass::kPrivate);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            R"(error: cannot use variable 'a' as type
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(error: cannot use variable 'a' as type
 note: 'a' declared here)");
 }
 
 TEST_F(ResolverTypeValidationTest, FunctionAsType) {
-  // fn f() {}
-  // var<private> v : f;
-  Func("f", {}, ty.void_(), {});
-  Global("v", ty.type_name("f"), ast::StorageClass::kPrivate);
+    // fn f() {}
+    // var<private> v : f;
+    Func("f", {}, ty.void_(), {});
+    Global("v", ty.type_name("f"), ast::StorageClass::kPrivate);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            R"(error: cannot use function 'f' as type
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(error: cannot use function 'f' as type
 note: 'f' declared here)");
 }
 
 TEST_F(ResolverTypeValidationTest, BuiltinAsType) {
-  // var<private> v : max;
-  Global("v", ty.type_name("max"), ast::StorageClass::kPrivate);
+    // var<private> v : max;
+    Global("v", ty.type_name("max"), ast::StorageClass::kPrivate);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "error: cannot use builtin 'max' as type");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "error: cannot use builtin 'max' as type");
 }
 
 namespace GetCanonicalTests {
 struct Params {
-  builder::ast_type_func_ptr create_ast_type;
-  builder::sem_type_func_ptr create_sem_type;
+    builder::ast_type_func_ptr create_ast_type;
+    builder::sem_type_func_ptr create_sem_type;
 };
 
 template <typename T>
 constexpr Params ParamsFor() {
-  return Params{DataType<T>::AST, DataType<T>::Sem};
+    return Params{DataType<T>::AST, DataType<T>::Sem};
 }
 
 static constexpr Params cases[] = {
@@ -749,32 +699,30 @@
 
 using CanonicalTest = ResolverTestWithParam<Params>;
 TEST_P(CanonicalTest, All) {
-  auto& params = GetParam();
+    auto& params = GetParam();
 
-  auto* type = params.create_ast_type(*this);
+    auto* type = params.create_ast_type(*this);
 
-  auto* var = Var("v", type);
-  auto* expr = Expr("v");
-  WrapInFunction(var, expr);
+    auto* var = Var("v", type);
+    auto* expr = Expr("v");
+    WrapInFunction(var, expr);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* got = TypeOf(expr)->UnwrapRef();
-  auto* expected = params.create_sem_type(*this);
+    auto* got = TypeOf(expr)->UnwrapRef();
+    auto* expected = params.create_sem_type(*this);
 
-  EXPECT_EQ(got, expected) << "got:      " << FriendlyName(got) << "\n"
-                           << "expected: " << FriendlyName(expected) << "\n";
+    EXPECT_EQ(got, expected) << "got:      " << FriendlyName(got) << "\n"
+                             << "expected: " << FriendlyName(expected) << "\n";
 }
-INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
-                         CanonicalTest,
-                         testing::ValuesIn(cases));
+INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest, CanonicalTest, testing::ValuesIn(cases));
 
 }  // namespace GetCanonicalTests
 
 namespace MultisampledTextureTests {
 struct DimensionParams {
-  ast::TextureDimension dim;
-  bool is_valid;
+    ast::TextureDimension dim;
+    bool is_valid;
 };
 
 static constexpr DimensionParams dimension_cases[] = {
@@ -787,31 +735,29 @@
 
 using MultisampledTextureDimensionTest = ResolverTestWithParam<DimensionParams>;
 TEST_P(MultisampledTextureDimensionTest, All) {
-  auto& params = GetParam();
-  Global(Source{{12, 34}}, "a", ty.multisampled_texture(params.dim, ty.i32()),
-         ast::StorageClass::kNone, nullptr,
-         ast::AttributeList{GroupAndBinding(0, 0)});
+    auto& params = GetParam();
+    Global(Source{{12, 34}}, "a", ty.multisampled_texture(params.dim, ty.i32()),
+           ast::StorageClass::kNone, nullptr, ast::AttributeList{GroupAndBinding(0, 0)});
 
-  if (params.is_valid) {
-    EXPECT_TRUE(r()->Resolve()) << r()->error();
-  } else {
-    EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              "12:34 error: only 2d multisampled textures are supported");
-  }
+    if (params.is_valid) {
+        EXPECT_TRUE(r()->Resolve()) << r()->error();
+    } else {
+        EXPECT_FALSE(r()->Resolve());
+        EXPECT_EQ(r()->error(), "12:34 error: only 2d multisampled textures are supported");
+    }
 }
 INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
                          MultisampledTextureDimensionTest,
                          testing::ValuesIn(dimension_cases));
 
 struct TypeParams {
-  builder::ast_type_func_ptr type_func;
-  bool is_valid;
+    builder::ast_type_func_ptr type_func;
+    bool is_valid;
 };
 
 template <typename T>
 constexpr TypeParams TypeParamsFor(bool is_valid) {
-  return TypeParams{DataType<T>::AST, is_valid};
+    return TypeParams{DataType<T>::AST, is_valid};
 }
 
 static constexpr TypeParams type_cases[] = {
@@ -834,21 +780,19 @@
 
 using MultisampledTextureTypeTest = ResolverTestWithParam<TypeParams>;
 TEST_P(MultisampledTextureTypeTest, All) {
-  auto& params = GetParam();
-  Global(Source{{12, 34}}, "a",
-         ty.multisampled_texture(ast::TextureDimension::k2d,
-                                 params.type_func(*this)),
-         ast::StorageClass::kNone, nullptr,
-         ast::AttributeList{GroupAndBinding(0, 0)});
+    auto& params = GetParam();
+    Global(Source{{12, 34}}, "a",
+           ty.multisampled_texture(ast::TextureDimension::k2d, params.type_func(*this)),
+           ast::StorageClass::kNone, nullptr, ast::AttributeList{GroupAndBinding(0, 0)});
 
-  if (params.is_valid) {
-    EXPECT_TRUE(r()->Resolve()) << r()->error();
-  } else {
-    EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              "12:34 error: texture_multisampled_2d<type>: type must be f32, "
-              "i32 or u32");
-  }
+    if (params.is_valid) {
+        EXPECT_TRUE(r()->Resolve()) << r()->error();
+    } else {
+        EXPECT_FALSE(r()->Resolve());
+        EXPECT_EQ(r()->error(),
+                  "12:34 error: texture_multisampled_2d<type>: type must be f32, "
+                  "i32 or u32");
+    }
 }
 INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
                          MultisampledTextureTypeTest,
@@ -858,8 +802,8 @@
 
 namespace StorageTextureTests {
 struct DimensionParams {
-  ast::TextureDimension dim;
-  bool is_valid;
+    ast::TextureDimension dim;
+    bool is_valid;
 };
 
 static constexpr DimensionParams Dimension_cases[] = {
@@ -872,94 +816,85 @@
 
 using StorageTextureDimensionTest = ResolverTestWithParam<DimensionParams>;
 TEST_P(StorageTextureDimensionTest, All) {
-  // @group(0) @binding(0)
-  // var a : texture_storage_*<ru32int, write>;
-  auto& params = GetParam();
+    // @group(0) @binding(0)
+    // var a : texture_storage_*<ru32int, write>;
+    auto& params = GetParam();
 
-  auto* st =
-      ty.storage_texture(Source{{12, 34}}, params.dim,
-                         ast::TexelFormat::kR32Uint, ast::Access::kWrite);
+    auto* st = ty.storage_texture(Source{{12, 34}}, params.dim, ast::TexelFormat::kR32Uint,
+                                  ast::Access::kWrite);
 
-  Global("a", st, ast::StorageClass::kNone,
-         ast::AttributeList{GroupAndBinding(0, 0)});
+    Global("a", st, ast::StorageClass::kNone, ast::AttributeList{GroupAndBinding(0, 0)});
 
-  if (params.is_valid) {
-    EXPECT_TRUE(r()->Resolve()) << r()->error();
-  } else {
-    EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              "12:34 error: cube dimensions for storage textures are not "
-              "supported");
-  }
+    if (params.is_valid) {
+        EXPECT_TRUE(r()->Resolve()) << r()->error();
+    } else {
+        EXPECT_FALSE(r()->Resolve());
+        EXPECT_EQ(r()->error(),
+                  "12:34 error: cube dimensions for storage textures are not "
+                  "supported");
+    }
 }
 INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
                          StorageTextureDimensionTest,
                          testing::ValuesIn(Dimension_cases));
 
 struct FormatParams {
-  ast::TexelFormat format;
-  bool is_valid;
+    ast::TexelFormat format;
+    bool is_valid;
 };
 
-static constexpr FormatParams format_cases[] = {
-    FormatParams{ast::TexelFormat::kR32Float, true},
-    FormatParams{ast::TexelFormat::kR32Sint, true},
-    FormatParams{ast::TexelFormat::kR32Uint, true},
-    FormatParams{ast::TexelFormat::kRg32Float, true},
-    FormatParams{ast::TexelFormat::kRg32Sint, true},
-    FormatParams{ast::TexelFormat::kRg32Uint, true},
-    FormatParams{ast::TexelFormat::kRgba16Float, true},
-    FormatParams{ast::TexelFormat::kRgba16Sint, true},
-    FormatParams{ast::TexelFormat::kRgba16Uint, true},
-    FormatParams{ast::TexelFormat::kRgba32Float, true},
-    FormatParams{ast::TexelFormat::kRgba32Sint, true},
-    FormatParams{ast::TexelFormat::kRgba32Uint, true},
-    FormatParams{ast::TexelFormat::kRgba8Sint, true},
-    FormatParams{ast::TexelFormat::kRgba8Snorm, true},
-    FormatParams{ast::TexelFormat::kRgba8Uint, true},
-    FormatParams{ast::TexelFormat::kRgba8Unorm, true}};
+static constexpr FormatParams format_cases[] = {FormatParams{ast::TexelFormat::kR32Float, true},
+                                                FormatParams{ast::TexelFormat::kR32Sint, true},
+                                                FormatParams{ast::TexelFormat::kR32Uint, true},
+                                                FormatParams{ast::TexelFormat::kRg32Float, true},
+                                                FormatParams{ast::TexelFormat::kRg32Sint, true},
+                                                FormatParams{ast::TexelFormat::kRg32Uint, true},
+                                                FormatParams{ast::TexelFormat::kRgba16Float, true},
+                                                FormatParams{ast::TexelFormat::kRgba16Sint, true},
+                                                FormatParams{ast::TexelFormat::kRgba16Uint, true},
+                                                FormatParams{ast::TexelFormat::kRgba32Float, true},
+                                                FormatParams{ast::TexelFormat::kRgba32Sint, true},
+                                                FormatParams{ast::TexelFormat::kRgba32Uint, true},
+                                                FormatParams{ast::TexelFormat::kRgba8Sint, true},
+                                                FormatParams{ast::TexelFormat::kRgba8Snorm, true},
+                                                FormatParams{ast::TexelFormat::kRgba8Uint, true},
+                                                FormatParams{ast::TexelFormat::kRgba8Unorm, true}};
 
 using StorageTextureFormatTest = ResolverTestWithParam<FormatParams>;
 TEST_P(StorageTextureFormatTest, All) {
-  auto& params = GetParam();
-  // @group(0) @binding(0)
-  // var a : texture_storage_1d<*, write>;
-  // @group(0) @binding(1)
-  // var b : texture_storage_2d<*, write>;
-  // @group(0) @binding(2)
-  // var c : texture_storage_2d_array<*, write>;
-  // @group(0) @binding(3)
-  // var d : texture_storage_3d<*, write>;
+    auto& params = GetParam();
+    // @group(0) @binding(0)
+    // var a : texture_storage_1d<*, write>;
+    // @group(0) @binding(1)
+    // var b : texture_storage_2d<*, write>;
+    // @group(0) @binding(2)
+    // var c : texture_storage_2d_array<*, write>;
+    // @group(0) @binding(3)
+    // var d : texture_storage_3d<*, write>;
 
-  auto* st_a = ty.storage_texture(Source{{12, 34}}, ast::TextureDimension::k1d,
-                                  params.format, ast::Access::kWrite);
-  Global("a", st_a, ast::StorageClass::kNone,
-         ast::AttributeList{GroupAndBinding(0, 0)});
+    auto* st_a = ty.storage_texture(Source{{12, 34}}, ast::TextureDimension::k1d, params.format,
+                                    ast::Access::kWrite);
+    Global("a", st_a, ast::StorageClass::kNone, ast::AttributeList{GroupAndBinding(0, 0)});
 
-  auto* st_b = ty.storage_texture(ast::TextureDimension::k2d, params.format,
-                                  ast::Access::kWrite);
-  Global("b", st_b, ast::StorageClass::kNone,
-         ast::AttributeList{GroupAndBinding(0, 1)});
+    auto* st_b = ty.storage_texture(ast::TextureDimension::k2d, params.format, ast::Access::kWrite);
+    Global("b", st_b, ast::StorageClass::kNone, ast::AttributeList{GroupAndBinding(0, 1)});
 
-  auto* st_c = ty.storage_texture(ast::TextureDimension::k2dArray,
-                                  params.format, ast::Access::kWrite);
-  Global("c", st_c, ast::StorageClass::kNone,
-         ast::AttributeList{GroupAndBinding(0, 2)});
+    auto* st_c =
+        ty.storage_texture(ast::TextureDimension::k2dArray, params.format, ast::Access::kWrite);
+    Global("c", st_c, ast::StorageClass::kNone, ast::AttributeList{GroupAndBinding(0, 2)});
 
-  auto* st_d = ty.storage_texture(ast::TextureDimension::k3d, params.format,
-                                  ast::Access::kWrite);
-  Global("d", st_d, ast::StorageClass::kNone,
-         ast::AttributeList{GroupAndBinding(0, 3)});
+    auto* st_d = ty.storage_texture(ast::TextureDimension::k3d, params.format, ast::Access::kWrite);
+    Global("d", st_d, ast::StorageClass::kNone, ast::AttributeList{GroupAndBinding(0, 3)});
 
-  if (params.is_valid) {
-    EXPECT_TRUE(r()->Resolve()) << r()->error();
-  } else {
-    EXPECT_FALSE(r()->Resolve());
-    EXPECT_EQ(r()->error(),
-              "12:34 error: image format must be one of the texel formats "
-              "specified for storage textues in "
-              "https://gpuweb.github.io/gpuweb/wgsl/#texel-formats");
-  }
+    if (params.is_valid) {
+        EXPECT_TRUE(r()->Resolve()) << r()->error();
+    } else {
+        EXPECT_FALSE(r()->Resolve());
+        EXPECT_EQ(r()->error(),
+                  "12:34 error: image format must be one of the texel formats "
+                  "specified for storage textues in "
+                  "https://gpuweb.github.io/gpuweb/wgsl/#texel-formats");
+    }
 }
 INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
                          StorageTextureFormatTest,
@@ -968,89 +903,81 @@
 using StorageTextureAccessTest = ResolverTest;
 
 TEST_F(StorageTextureAccessTest, MissingAccess_Fail) {
-  // @group(0) @binding(0)
-  // var a : texture_storage_1d<ru32int>;
+    // @group(0) @binding(0)
+    // var a : texture_storage_1d<ru32int>;
 
-  auto* st =
-      ty.storage_texture(Source{{12, 34}}, ast::TextureDimension::k1d,
-                         ast::TexelFormat::kR32Uint, ast::Access::kUndefined);
+    auto* st = ty.storage_texture(Source{{12, 34}}, ast::TextureDimension::k1d,
+                                  ast::TexelFormat::kR32Uint, ast::Access::kUndefined);
 
-  Global("a", st, ast::StorageClass::kNone,
-         ast::AttributeList{GroupAndBinding(0, 0)});
+    Global("a", st, ast::StorageClass::kNone, ast::AttributeList{GroupAndBinding(0, 0)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: storage texture missing access control");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: storage texture missing access control");
 }
 
 TEST_F(StorageTextureAccessTest, RWAccess_Fail) {
-  // @group(0) @binding(0)
-  // var a : texture_storage_1d<ru32int, read_write>;
+    // @group(0) @binding(0)
+    // var a : texture_storage_1d<ru32int, read_write>;
 
-  auto* st =
-      ty.storage_texture(Source{{12, 34}}, ast::TextureDimension::k1d,
-                         ast::TexelFormat::kR32Uint, ast::Access::kReadWrite);
+    auto* st = ty.storage_texture(Source{{12, 34}}, ast::TextureDimension::k1d,
+                                  ast::TexelFormat::kR32Uint, ast::Access::kReadWrite);
 
-  Global("a", st, ast::StorageClass::kNone, nullptr,
-         ast::AttributeList{GroupAndBinding(0, 0)});
+    Global("a", st, ast::StorageClass::kNone, nullptr, ast::AttributeList{GroupAndBinding(0, 0)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: storage textures currently only support 'write' "
-            "access control");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: storage textures currently only support 'write' "
+              "access control");
 }
 
 TEST_F(StorageTextureAccessTest, ReadOnlyAccess_Fail) {
-  // @group(0) @binding(0)
-  // var a : texture_storage_1d<ru32int, read>;
+    // @group(0) @binding(0)
+    // var a : texture_storage_1d<ru32int, read>;
 
-  auto* st = ty.storage_texture(Source{{12, 34}}, ast::TextureDimension::k1d,
-                                ast::TexelFormat::kR32Uint, ast::Access::kRead);
+    auto* st = ty.storage_texture(Source{{12, 34}}, ast::TextureDimension::k1d,
+                                  ast::TexelFormat::kR32Uint, ast::Access::kRead);
 
-  Global("a", st, ast::StorageClass::kNone, nullptr,
-         ast::AttributeList{GroupAndBinding(0, 0)});
+    Global("a", st, ast::StorageClass::kNone, nullptr, ast::AttributeList{GroupAndBinding(0, 0)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: storage textures currently only support 'write' "
-            "access control");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: storage textures currently only support 'write' "
+              "access control");
 }
 
 TEST_F(StorageTextureAccessTest, WriteOnlyAccess_Pass) {
-  // @group(0) @binding(0)
-  // var a : texture_storage_1d<ru32int, write>;
+    // @group(0) @binding(0)
+    // var a : texture_storage_1d<ru32int, write>;
 
-  auto* st =
-      ty.storage_texture(ast::TextureDimension::k1d, ast::TexelFormat::kR32Uint,
-                         ast::Access::kWrite);
+    auto* st = ty.storage_texture(ast::TextureDimension::k1d, ast::TexelFormat::kR32Uint,
+                                  ast::Access::kWrite);
 
-  Global("a", st, ast::StorageClass::kNone, nullptr,
-         ast::AttributeList{GroupAndBinding(0, 0)});
+    Global("a", st, ast::StorageClass::kNone, nullptr, ast::AttributeList{GroupAndBinding(0, 0)});
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 }  // namespace StorageTextureTests
 
 namespace MatrixTests {
 struct Params {
-  uint32_t columns;
-  uint32_t rows;
-  builder::ast_type_func_ptr elem_ty;
+    uint32_t columns;
+    uint32_t rows;
+    builder::ast_type_func_ptr elem_ty;
 };
 
 template <typename T>
 constexpr Params ParamsFor(uint32_t columns, uint32_t rows) {
-  return Params{columns, rows, DataType<T>::AST};
+    return Params{columns, rows, DataType<T>::AST};
 }
 
 using ValidMatrixTypes = ResolverTestWithParam<Params>;
 TEST_P(ValidMatrixTypes, Okay) {
-  // var a : matNxM<EL_TY>;
-  auto& params = GetParam();
-  Global("a", ty.mat(params.elem_ty(*this), params.columns, params.rows),
-         ast::StorageClass::kPrivate);
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    // var a : matNxM<EL_TY>;
+    auto& params = GetParam();
+    Global("a", ty.mat(params.elem_ty(*this), params.columns, params.rows),
+           ast::StorageClass::kPrivate);
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
                          ValidMatrixTypes,
@@ -1069,14 +996,12 @@
 
 using InvalidMatrixElementTypes = ResolverTestWithParam<Params>;
 TEST_P(InvalidMatrixElementTypes, InvalidElementType) {
-  // var a : matNxM<EL_TY>;
-  auto& params = GetParam();
-  Global("a",
-         ty.mat(Source{{12, 34}}, params.elem_ty(*this), params.columns,
-                params.rows),
-         ast::StorageClass::kPrivate);
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: matrix element type must be 'f32'");
+    // var a : matNxM<EL_TY>;
+    auto& params = GetParam();
+    Global("a", ty.mat(Source{{12, 34}}, params.elem_ty(*this), params.columns, params.rows),
+           ast::StorageClass::kPrivate);
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: matrix element type must be 'f32'");
 }
 INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
                          InvalidMatrixElementTypes,
@@ -1094,22 +1019,21 @@
 
 namespace VectorTests {
 struct Params {
-  uint32_t width;
-  builder::ast_type_func_ptr elem_ty;
+    uint32_t width;
+    builder::ast_type_func_ptr elem_ty;
 };
 
 template <typename T>
 constexpr Params ParamsFor(uint32_t width) {
-  return Params{width, DataType<T>::AST};
+    return Params{width, DataType<T>::AST};
 }
 
 using ValidVectorTypes = ResolverTestWithParam<Params>;
 TEST_P(ValidVectorTypes, Okay) {
-  // var a : vecN<EL_TY>;
-  auto& params = GetParam();
-  Global("a", ty.vec(params.elem_ty(*this), params.width),
-         ast::StorageClass::kPrivate);
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    // var a : vecN<EL_TY>;
+    auto& params = GetParam();
+    Global("a", ty.vec(params.elem_ty(*this), params.width), ast::StorageClass::kPrivate);
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
                          ValidVectorTypes,
@@ -1132,14 +1056,14 @@
 
 using InvalidVectorElementTypes = ResolverTestWithParam<Params>;
 TEST_P(InvalidVectorElementTypes, InvalidElementType) {
-  // var a : vecN<EL_TY>;
-  auto& params = GetParam();
-  Global("a", ty.vec(Source{{12, 34}}, params.elem_ty(*this), params.width),
-         ast::StorageClass::kPrivate);
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: vector element type must be 'bool', 'f32', 'i32' "
-            "or 'u32'");
+    // var a : vecN<EL_TY>;
+    auto& params = GetParam();
+    Global("a", ty.vec(Source{{12, 34}}, params.elem_ty(*this), params.width),
+           ast::StorageClass::kPrivate);
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: vector element type must be 'bool', 'f32', 'i32' "
+              "or 'u32'");
 }
 INSTANTIATE_TEST_SUITE_P(ResolverTypeValidationTest,
                          InvalidVectorElementTypes,
diff --git a/src/tint/resolver/validation_test.cc b/src/tint/resolver/validation_test.cc
index 8b89f99..65d73c4 100644
--- a/src/tint/resolver/validation_test.cc
+++ b/src/tint/resolver/validation_test.cc
@@ -34,69 +34,69 @@
 #include "src/tint/sem/call.h"
 #include "src/tint/sem/function.h"
 #include "src/tint/sem/member_accessor_expression.h"
-#include "src/tint/sem/sampled_texture_type.h"
+#include "src/tint/sem/sampled_texture.h"
 #include "src/tint/sem/statement.h"
 #include "src/tint/sem/variable.h"
 
 using ::testing::ElementsAre;
 using ::testing::HasSubstr;
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::resolver {
 namespace {
 
 using ResolverValidationTest = ResolverTest;
 
 class FakeStmt final : public Castable<FakeStmt, ast::Statement> {
- public:
-  FakeStmt(ProgramID pid, Source src) : Base(pid, src) {}
-  FakeStmt* Clone(CloneContext*) const override { return nullptr; }
+  public:
+    FakeStmt(ProgramID pid, Source src) : Base(pid, src) {}
+    FakeStmt* Clone(CloneContext*) const override { return nullptr; }
 };
 
 class FakeExpr final : public Castable<FakeExpr, ast::Expression> {
- public:
-  FakeExpr(ProgramID pid, Source src) : Base(pid, src) {}
-  FakeExpr* Clone(CloneContext*) const override { return nullptr; }
+  public:
+    FakeExpr(ProgramID pid, Source src) : Base(pid, src) {}
+    FakeExpr* Clone(CloneContext*) const override { return nullptr; }
 };
 
 TEST_F(ResolverValidationTest, WorkgroupMemoryUsedInVertexStage) {
-  Global(Source{{1, 2}}, "wg", ty.vec4<f32>(), ast::StorageClass::kWorkgroup);
-  Global("dst", ty.vec4<f32>(), ast::StorageClass::kPrivate);
-  auto* stmt = Assign(Expr("dst"), Expr(Source{{3, 4}}, "wg"));
+    Global(Source{{1, 2}}, "wg", ty.vec4<f32>(), ast::StorageClass::kWorkgroup);
+    Global("dst", ty.vec4<f32>(), ast::StorageClass::kPrivate);
+    auto* stmt = Assign(Expr("dst"), Expr(Source{{3, 4}}, "wg"));
 
-  Func(Source{{9, 10}}, "f0", ast::VariableList{}, ty.vec4<f32>(),
-       {stmt, Return(Expr("dst"))},
-       ast::AttributeList{Stage(ast::PipelineStage::kVertex)},
-       ast::AttributeList{Builtin(ast::Builtin::kPosition)});
+    Func(Source{{9, 10}}, "f0", ast::VariableList{}, ty.vec4<f32>(), {stmt, Return(Expr("dst"))},
+         ast::AttributeList{Stage(ast::PipelineStage::kVertex)},
+         ast::AttributeList{Builtin(ast::Builtin::kPosition)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "3:4 error: workgroup memory cannot be used by vertex pipeline "
-            "stage\n1:2 note: variable is declared here");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "3:4 error: workgroup memory cannot be used by vertex pipeline "
+              "stage\n1:2 note: variable is declared here");
 }
 
 TEST_F(ResolverValidationTest, WorkgroupMemoryUsedInFragmentStage) {
-  // var<workgroup> wg : vec4<f32>;
-  // var<workgroup> dst : vec4<f32>;
-  // fn f2(){ dst = wg; }
-  // fn f1() { f2(); }
-  // @stage(fragment)
-  // fn f0() {
-  //  f1();
-  //}
+    // var<workgroup> wg : vec4<f32>;
+    // var<workgroup> dst : vec4<f32>;
+    // fn f2(){ dst = wg; }
+    // fn f1() { f2(); }
+    // @stage(fragment)
+    // fn f0() {
+    //  f1();
+    //}
 
-  Global(Source{{1, 2}}, "wg", ty.vec4<f32>(), ast::StorageClass::kWorkgroup);
-  Global("dst", ty.vec4<f32>(), ast::StorageClass::kPrivate);
-  auto* stmt = Assign(Expr("dst"), Expr(Source{{3, 4}}, "wg"));
+    Global(Source{{1, 2}}, "wg", ty.vec4<f32>(), ast::StorageClass::kWorkgroup);
+    Global("dst", ty.vec4<f32>(), ast::StorageClass::kPrivate);
+    auto* stmt = Assign(Expr("dst"), Expr(Source{{3, 4}}, "wg"));
 
-  Func(Source{{5, 6}}, "f2", {}, ty.void_(), {stmt});
-  Func(Source{{7, 8}}, "f1", {}, ty.void_(), {CallStmt(Call("f2"))});
-  Func(Source{{9, 10}}, "f0", {}, ty.void_(), {CallStmt(Call("f1"))},
-       ast::AttributeList{Stage(ast::PipelineStage::kFragment)});
+    Func(Source{{5, 6}}, "f2", {}, ty.void_(), {stmt});
+    Func(Source{{7, 8}}, "f1", {}, ty.void_(), {CallStmt(Call("f2"))});
+    Func(Source{{9, 10}}, "f0", {}, ty.void_(), {CallStmt(Call("f1"))},
+         ast::AttributeList{Stage(ast::PipelineStage::kFragment)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(3:4 error: workgroup memory cannot be used by fragment pipeline stage
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(3:4 error: workgroup memory cannot be used by fragment pipeline stage
 1:2 note: variable is declared here
 5:6 note: called by function 'f2'
 7:8 note: called by function 'f1'
@@ -104,1211 +104,1150 @@
 }
 
 TEST_F(ResolverValidationTest, UnhandledStmt) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.WrapInFunction(b.create<FakeStmt>());
-        Program(std::move(b));
-      },
-      "internal compiler error: unhandled node type: tint::resolver::FakeStmt");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.WrapInFunction(b.create<FakeStmt>());
+            Program(std::move(b));
+        },
+        "internal compiler error: unhandled node type: tint::resolver::FakeStmt");
 }
 
 TEST_F(ResolverValidationTest, Stmt_If_NonBool) {
-  // if (1.23f) {}
+    // if (1.23f) {}
 
-  WrapInFunction(If(Expr(Source{{12, 34}}, 1.23f), Block()));
+    WrapInFunction(If(Expr(Source{{12, 34}}, 1.23f), Block()));
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(r()->error(),
-            "12:34 error: if statement condition must be bool, got f32");
+    EXPECT_EQ(r()->error(), "12:34 error: if statement condition must be bool, got f32");
 }
 
-TEST_F(ResolverValidationTest, Stmt_Else_NonBool) {
-  // else (1.23f) {}
+TEST_F(ResolverValidationTest, Stmt_ElseIf_NonBool) {
+    // else if (1.23f) {}
 
-  WrapInFunction(
-      If(Expr(true), Block(), Else(Expr(Source{{12, 34}}, 1.23f), Block())));
+    WrapInFunction(If(Expr(true), Block(), Else(If(Expr(Source{{12, 34}}, 1.23f), Block()))));
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(r()->error(),
-            "12:34 error: else statement condition must be bool, got f32");
+    EXPECT_EQ(r()->error(), "12:34 error: if statement condition must be bool, got f32");
 }
 
 TEST_F(ResolverValidationTest, Expr_ErrUnknownExprType) {
-  EXPECT_FATAL_FAILURE(
-      {
-        ProgramBuilder b;
-        b.WrapInFunction(b.create<FakeExpr>());
-        Resolver(&b).Resolve();
-      },
-      "internal compiler error: unhandled expression type: "
-      "tint::resolver::FakeExpr");
+    EXPECT_FATAL_FAILURE(
+        {
+            ProgramBuilder b;
+            b.WrapInFunction(b.create<FakeExpr>());
+            Resolver(&b).Resolve();
+        },
+        "internal compiler error: unhandled expression type: "
+        "tint::resolver::FakeExpr");
 }
 
 TEST_F(ResolverValidationTest, Expr_DontCall_Function) {
-  Func("func", {}, ty.void_(), {}, {});
-  WrapInFunction(Expr(Source{{{3, 3}, {3, 8}}}, "func"));
+    Func("func", {}, ty.void_(), {}, {});
+    WrapInFunction(Expr(Source{{{3, 3}, {3, 8}}}, "func"));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "3:8 error: missing '(' for function call");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "3:8 error: missing '(' for function call");
 }
 
 TEST_F(ResolverValidationTest, Expr_DontCall_Builtin) {
-  WrapInFunction(Expr(Source{{{3, 3}, {3, 8}}}, "round"));
+    WrapInFunction(Expr(Source{{{3, 3}, {3, 8}}}, "round"));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "3:8 error: missing '(' for builtin call");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "3:8 error: missing '(' for builtin call");
 }
 
 TEST_F(ResolverValidationTest, Expr_DontCall_Type) {
-  Alias("T", ty.u32());
-  WrapInFunction(Expr(Source{{{3, 3}, {3, 8}}}, "T"));
+    Alias("T", ty.u32());
+    WrapInFunction(Expr(Source{{{3, 3}, {3, 8}}}, "T"));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "3:8 error: missing '(' for type constructor or cast");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "3:8 error: missing '(' for type constructor or cast");
 }
 
 TEST_F(ResolverValidationTest, AssignmentStmt_InvalidLHS_BuiltinFunctionName) {
-  // normalize = 2;
+    // normalize = 2;
 
-  auto* lhs = Expr(Source{{12, 34}}, "normalize");
-  auto* rhs = Expr(2);
-  auto* assign = Assign(lhs, rhs);
-  WrapInFunction(assign);
+    auto* lhs = Expr(Source{{12, 34}}, "normalize");
+    auto* rhs = Expr(2_i);
+    auto* assign = Assign(lhs, rhs);
+    WrapInFunction(assign);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: missing '(' for builtin call");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: missing '(' for builtin call");
 }
 
 TEST_F(ResolverValidationTest, UsingUndefinedVariable_Fail) {
-  // b = 2;
+    // b = 2;
 
-  auto* lhs = Expr(Source{{12, 34}}, "b");
-  auto* rhs = Expr(2);
-  auto* assign = Assign(lhs, rhs);
-  WrapInFunction(assign);
+    auto* lhs = Expr(Source{{12, 34}}, "b");
+    auto* rhs = Expr(2_i);
+    auto* assign = Assign(lhs, rhs);
+    WrapInFunction(assign);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: unknown identifier: 'b'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: unknown identifier: 'b'");
 }
 
 TEST_F(ResolverValidationTest, UsingUndefinedVariableInBlockStatement_Fail) {
-  // {
-  //  b = 2;
-  // }
+    // {
+    //  b = 2;
+    // }
 
-  auto* lhs = Expr(Source{{12, 34}}, "b");
-  auto* rhs = Expr(2);
+    auto* lhs = Expr(Source{{12, 34}}, "b");
+    auto* rhs = Expr(2_i);
 
-  auto* body = Block(Assign(lhs, rhs));
-  WrapInFunction(body);
+    auto* body = Block(Assign(lhs, rhs));
+    WrapInFunction(body);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: unknown identifier: 'b'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: unknown identifier: 'b'");
 }
 
 TEST_F(ResolverValidationTest, UsingUndefinedVariableGlobalVariable_Pass) {
-  // var global_var: f32 = 2.1;
-  // fn my_func() {
-  //   global_var = 3.14;
-  //   return;
-  // }
+    // var global_var: f32 = 2.1;
+    // fn my_func() {
+    //   global_var = 3.14;
+    //   return;
+    // }
 
-  Global("global_var", ty.f32(), ast::StorageClass::kPrivate, Expr(2.1f));
+    Global("global_var", ty.f32(), ast::StorageClass::kPrivate, Expr(2.1f));
 
-  Func("my_func", ast::VariableList{}, ty.void_(),
-       {
-           Assign(Expr(Source{{12, 34}}, "global_var"), 3.14f),
-           Return(),
-       });
+    Func("my_func", ast::VariableList{}, ty.void_(),
+         {
+             Assign(Expr(Source{{12, 34}}, "global_var"), 3.14f),
+             Return(),
+         });
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverValidationTest, UsingUndefinedVariableInnerScope_Fail) {
-  // {
-  //   if (true) { var a : f32 = 2.0; }
-  //   a = 3.14;
-  // }
-  auto* var = Var("a", ty.f32(), ast::StorageClass::kNone, Expr(2.0f));
+    // {
+    //   if (true) { var a : f32 = 2.0; }
+    //   a = 3.14;
+    // }
+    auto* var = Var("a", ty.f32(), ast::StorageClass::kNone, Expr(2.0f));
 
-  auto* cond = Expr(true);
-  auto* body = Block(Decl(var));
+    auto* cond = Expr(true);
+    auto* body = Block(Decl(var));
 
-  SetSource(Source{{12, 34}});
-  auto* lhs = Expr(Source{{12, 34}}, "a");
-  auto* rhs = Expr(3.14f);
+    SetSource(Source{{12, 34}});
+    auto* lhs = Expr(Source{{12, 34}}, "a");
+    auto* rhs = Expr(3.14f);
 
-  auto* outer_body =
-      Block(create<ast::IfStatement>(cond, body, ast::ElseStatementList{}),
-            Assign(lhs, rhs));
+    auto* outer_body = Block(If(cond, body), Assign(lhs, rhs));
 
-  WrapInFunction(outer_body);
+    WrapInFunction(outer_body);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: unknown identifier: 'a'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: unknown identifier: 'a'");
 }
 
 TEST_F(ResolverValidationTest, UsingUndefinedVariableOuterScope_Pass) {
-  // {
-  //   var a : f32 = 2.0;
-  //   if (true) { a = 3.14; }
-  // }
-  auto* var = Var("a", ty.f32(), ast::StorageClass::kNone, Expr(2.0f));
+    // {
+    //   var a : f32 = 2.0;
+    //   if (true) { a = 3.14; }
+    // }
+    auto* var = Var("a", ty.f32(), ast::StorageClass::kNone, Expr(2.0f));
 
-  auto* lhs = Expr(Source{{12, 34}}, "a");
-  auto* rhs = Expr(3.14f);
+    auto* lhs = Expr(Source{{12, 34}}, "a");
+    auto* rhs = Expr(3.14f);
 
-  auto* cond = Expr(true);
-  auto* body = Block(Assign(lhs, rhs));
+    auto* cond = Expr(true);
+    auto* body = Block(Assign(lhs, rhs));
 
-  auto* outer_body =
-      Block(Decl(var),
-            create<ast::IfStatement>(cond, body, ast::ElseStatementList{}));
+    auto* outer_body = Block(Decl(var), If(cond, body));
 
-  WrapInFunction(outer_body);
+    WrapInFunction(outer_body);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverValidationTest, UsingUndefinedVariableDifferentScope_Fail) {
-  // {
-  //  { var a : f32 = 2.0; }
-  //  { a = 3.14; }
-  // }
-  auto* var = Var("a", ty.f32(), ast::StorageClass::kNone, Expr(2.0f));
-  auto* first_body = Block(Decl(var));
+    // {
+    //  { var a : f32 = 2.0; }
+    //  { a = 3.14; }
+    // }
+    auto* var = Var("a", ty.f32(), ast::StorageClass::kNone, Expr(2.0f));
+    auto* first_body = Block(Decl(var));
 
-  auto* lhs = Expr(Source{{12, 34}}, "a");
-  auto* rhs = Expr(3.14f);
-  auto* second_body = Block(Assign(lhs, rhs));
+    auto* lhs = Expr(Source{{12, 34}}, "a");
+    auto* rhs = Expr(3.14f);
+    auto* second_body = Block(Assign(lhs, rhs));
 
-  auto* outer_body = Block(first_body, second_body);
+    auto* outer_body = Block(first_body, second_body);
 
-  WrapInFunction(outer_body);
+    WrapInFunction(outer_body);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: unknown identifier: 'a'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: unknown identifier: 'a'");
 }
 
 TEST_F(ResolverValidationTest, StorageClass_FunctionVariableWorkgroupClass) {
-  auto* var = Var("var", ty.i32(), ast::StorageClass::kWorkgroup);
+    auto* var = Var("var", ty.i32(), ast::StorageClass::kWorkgroup);
 
-  auto* stmt = Decl(var);
-  Func("func", ast::VariableList{}, ty.void_(), {stmt}, ast::AttributeList{});
+    auto* stmt = Decl(var);
+    Func("func", ast::VariableList{}, ty.void_(), {stmt}, ast::AttributeList{});
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(r()->error(),
-            "error: function variable has a non-function storage class");
+    EXPECT_EQ(r()->error(), "error: function variable has a non-function storage class");
 }
 
 TEST_F(ResolverValidationTest, StorageClass_FunctionVariableI32) {
-  auto* var = Var("s", ty.i32(), ast::StorageClass::kPrivate);
+    auto* var = Var("s", ty.i32(), ast::StorageClass::kPrivate);
 
-  auto* stmt = Decl(var);
-  Func("func", ast::VariableList{}, ty.void_(), {stmt}, ast::AttributeList{});
+    auto* stmt = Decl(var);
+    Func("func", ast::VariableList{}, ty.void_(), {stmt}, ast::AttributeList{});
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(r()->error(),
-            "error: function variable has a non-function storage class");
+    EXPECT_EQ(r()->error(), "error: function variable has a non-function storage class");
 }
 
 TEST_F(ResolverValidationTest, StorageClass_SamplerExplicitStorageClass) {
-  auto* t = ty.sampler(ast::SamplerKind::kSampler);
-  Global(Source{{12, 34}}, "var", t, ast::StorageClass::kUniformConstant,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    auto* t = ty.sampler(ast::SamplerKind::kSampler);
+    Global(Source{{12, 34}}, "var", t, ast::StorageClass::kHandle,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  EXPECT_FALSE(r()->Resolve());
+    EXPECT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: variables of type 'sampler' must not have a storage class)");
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: variables of type 'sampler' must not have a storage class)");
 }
 
 TEST_F(ResolverValidationTest, StorageClass_TextureExplicitStorageClass) {
-  auto* t = ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
-  Global(Source{{12, 34}}, "var", t, ast::StorageClass::kUniformConstant,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    auto* t = ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
+    Global(Source{{12, 34}}, "var", t, ast::StorageClass::kHandle,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  EXPECT_FALSE(r()->Resolve()) << r()->error();
+    EXPECT_FALSE(r()->Resolve()) << r()->error();
 
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: variables of type 'texture_1d<f32>' must not have a storage class)");
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: variables of type 'texture_1d<f32>' must not have a storage class)");
 }
 
 TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_BadChar) {
-  Global("my_vec", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+    Global("my_vec", ty.vec3<f32>(), ast::StorageClass::kPrivate);
 
-  auto* ident = Expr(Source{{{3, 3}, {3, 7}}}, "xyqz");
+    auto* ident = Expr(Source{{{3, 3}, {3, 7}}}, "xyqz");
 
-  auto* mem = MemberAccessor("my_vec", ident);
-  WrapInFunction(mem);
+    auto* mem = MemberAccessor("my_vec", ident);
+    WrapInFunction(mem);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "3:5 error: invalid vector swizzle character");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "3:5 error: invalid vector swizzle character");
 }
 
 TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_MixedChars) {
-  Global("my_vec", ty.vec4<f32>(), ast::StorageClass::kPrivate);
+    Global("my_vec", ty.vec4<f32>(), ast::StorageClass::kPrivate);
 
-  auto* ident = Expr(Source{{{3, 3}, {3, 7}}}, "rgyw");
+    auto* ident = Expr(Source{{{3, 3}, {3, 7}}}, "rgyw");
 
-  auto* mem = MemberAccessor("my_vec", ident);
-  WrapInFunction(mem);
+    auto* mem = MemberAccessor("my_vec", ident);
+    WrapInFunction(mem);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "3:3 error: invalid mixing of vector swizzle characters rgba with xyzw");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "3:3 error: invalid mixing of vector swizzle characters rgba with xyzw");
 }
 
 TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_BadLength) {
-  Global("my_vec", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+    Global("my_vec", ty.vec3<f32>(), ast::StorageClass::kPrivate);
 
-  auto* ident = Expr(Source{{{3, 3}, {3, 8}}}, "zzzzz");
-  auto* mem = MemberAccessor("my_vec", ident);
-  WrapInFunction(mem);
+    auto* ident = Expr(Source{{{3, 3}, {3, 8}}}, "zzzzz");
+    auto* mem = MemberAccessor("my_vec", ident);
+    WrapInFunction(mem);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "3:3 error: invalid vector swizzle size");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "3:3 error: invalid vector swizzle size");
 }
 
 TEST_F(ResolverValidationTest, Expr_MemberAccessor_VectorSwizzle_BadIndex) {
-  Global("my_vec", ty.vec2<f32>(), ast::StorageClass::kPrivate);
+    Global("my_vec", ty.vec2<f32>(), ast::StorageClass::kPrivate);
 
-  auto* ident = Expr(Source{{3, 3}}, "z");
-  auto* mem = MemberAccessor("my_vec", ident);
-  WrapInFunction(mem);
+    auto* ident = Expr(Source{{3, 3}}, "z");
+    auto* mem = MemberAccessor("my_vec", ident);
+    WrapInFunction(mem);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "3:3 error: invalid vector swizzle member");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "3:3 error: invalid vector swizzle member");
 }
 
 TEST_F(ResolverValidationTest, Expr_MemberAccessor_BadParent) {
-  // var param: vec4<f32>
-  // let ret: f32 = *(&param).x;
-  auto* param = Var("param", ty.vec4<f32>());
-  auto* x = Expr(Source{{{3, 3}, {3, 8}}}, "x");
+    // var param: vec4<f32>
+    // let ret: f32 = *(&param).x;
+    auto* param = Var("param", ty.vec4<f32>());
+    auto* x = Expr(Source{{{3, 3}, {3, 8}}}, "x");
 
-  auto* addressOf_expr = AddressOf(Source{{12, 34}}, param);
-  auto* accessor_expr = MemberAccessor(addressOf_expr, x);
-  auto* star_p = Deref(accessor_expr);
-  auto* ret = Var("r", ty.f32(), star_p);
-  WrapInFunction(Decl(param), Decl(ret));
+    auto* addressOf_expr = AddressOf(Source{{12, 34}}, param);
+    auto* accessor_expr = MemberAccessor(addressOf_expr, x);
+    auto* star_p = Deref(accessor_expr);
+    auto* ret = Var("r", ty.f32(), star_p);
+    WrapInFunction(Decl(param), Decl(ret));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: invalid member accessor expression. Expected vector "
-            "or struct, got 'ptr<function, vec4<f32>, read_write>'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: invalid member accessor expression. Expected vector "
+              "or struct, got 'ptr<function, vec4<f32>, read_write>'");
 }
 
 TEST_F(ResolverValidationTest, EXpr_MemberAccessor_FuncGoodParent) {
-  // fn func(p: ptr<function, vec4<f32>>) -> f32 {
-  //     let x: f32 = (*p).z;
-  //     return x;
-  // }
-  auto* p =
-      Param("p", ty.pointer(ty.vec4<f32>(), ast::StorageClass::kFunction));
-  auto* star_p = Deref(p);
-  auto* z = Expr(Source{{{3, 3}, {3, 8}}}, "z");
-  auto* accessor_expr = MemberAccessor(star_p, z);
-  auto* x = Var("x", ty.f32(), accessor_expr);
-  Func("func", {p}, ty.f32(), {Decl(x), Return(x)});
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    // fn func(p: ptr<function, vec4<f32>>) -> f32 {
+    //     let x: f32 = (*p).z;
+    //     return x;
+    // }
+    auto* p = Param("p", ty.pointer(ty.vec4<f32>(), ast::StorageClass::kFunction));
+    auto* star_p = Deref(p);
+    auto* z = Expr(Source{{{3, 3}, {3, 8}}}, "z");
+    auto* accessor_expr = MemberAccessor(star_p, z);
+    auto* x = Var("x", ty.f32(), accessor_expr);
+    Func("func", {p}, ty.f32(), {Decl(x), Return(x)});
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverValidationTest, EXpr_MemberAccessor_FuncBadParent) {
-  // fn func(p: ptr<function, vec4<f32>>) -> f32 {
-  //     let x: f32 = *p.z;
-  //     return x;
-  // }
-  auto* p =
-      Param("p", ty.pointer(ty.vec4<f32>(), ast::StorageClass::kFunction));
-  auto* z = Expr(Source{{{3, 3}, {3, 8}}}, "z");
-  auto* accessor_expr = MemberAccessor(p, z);
-  auto* star_p = Deref(accessor_expr);
-  auto* x = Var("x", ty.f32(), star_p);
-  Func("func", {p}, ty.f32(), {Decl(x), Return(x)});
+    // fn func(p: ptr<function, vec4<f32>>) -> f32 {
+    //     let x: f32 = *p.z;
+    //     return x;
+    // }
+    auto* p = Param("p", ty.pointer(ty.vec4<f32>(), ast::StorageClass::kFunction));
+    auto* z = Expr(Source{{{3, 3}, {3, 8}}}, "z");
+    auto* accessor_expr = MemberAccessor(p, z);
+    auto* star_p = Deref(accessor_expr);
+    auto* x = Var("x", ty.f32(), star_p);
+    Func("func", {p}, ty.f32(), {Decl(x), Return(x)});
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "error: invalid member accessor expression. "
-      "Expected vector or struct, got 'ptr<function, vec4<f32>, read_write>'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "error: invalid member accessor expression. "
+              "Expected vector or struct, got 'ptr<function, vec4<f32>, read_write>'");
 }
 
 TEST_F(ResolverValidationTest,
        Stmt_Loop_ContinueInLoopBodyBeforeDeclAndAfterDecl_UsageInContinuing) {
-  // loop  {
-  //     continue; // Bypasses z decl
-  //     var z : i32; // unreachable
-  //
-  //     continuing {
-  //         z = 2;
-  //     }
-  // }
+    // loop  {
+    //     continue; // Bypasses z decl
+    //     var z : i32; // unreachable
+    //
+    //     continuing {
+    //         z = 2;
+    //     }
+    // }
 
-  auto error_loc = Source{{12, 34}};
-  auto* body =
-      Block(Continue(),
-            Decl(error_loc, Var("z", ty.i32(), ast::StorageClass::kNone)));
-  auto* continuing = Block(Assign(Expr("z"), 2));
-  auto* loop_stmt = Loop(body, continuing);
-  WrapInFunction(loop_stmt);
+    auto error_loc = Source{{12, 34}};
+    auto* body = Block(Continue(), Decl(error_loc, Var("z", ty.i32(), ast::StorageClass::kNone)));
+    auto* continuing = Block(Assign(Expr("z"), 2_i));
+    auto* loop_stmt = Loop(body, continuing);
+    WrapInFunction(loop_stmt);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            R"(12:34 warning: code is unreachable
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(12:34 warning: code is unreachable
 error: continue statement bypasses declaration of 'z'
 note: identifier 'z' declared here
 note: identifier 'z' referenced in continuing block here)");
 }
 
-TEST_F(ResolverValidationTest,
-       Stmt_Loop_ContinueInLoopBodyAfterDecl_UsageInContinuing_InBlocks) {
-  // loop  {
-  //     if (false) { break; }
-  //     var z : i32;
-  //     {{{continue;}}}
-  //     continue; // Ok
-  //
-  //     continuing {
-  //         z = 2;
-  //     }
-  // }
+TEST_F(ResolverValidationTest, Stmt_Loop_ContinueInLoopBodyAfterDecl_UsageInContinuing_InBlocks) {
+    // loop  {
+    //     if (false) { break; }
+    //     var z : i32;
+    //     {{{continue;}}}
+    //     continue; // Ok
+    //
+    //     continuing {
+    //         z = 2i;
+    //     }
+    // }
 
-  auto* body = Block(If(false, Block(Break())),  //
-                     Decl(Var("z", ty.i32(), ast::StorageClass::kNone)),
-                     Block(Block(Block(Continue()))));
-  auto* continuing = Block(Assign(Expr("z"), 2));
-  auto* loop_stmt = Loop(body, continuing);
-  WrapInFunction(loop_stmt);
+    auto* body =
+        Block(If(false, Block(Break())),  //
+              Decl(Var("z", ty.i32(), ast::StorageClass::kNone)), Block(Block(Block(Continue()))));
+    auto* continuing = Block(Assign(Expr("z"), 2_i));
+    auto* loop_stmt = Loop(body, continuing);
+    WrapInFunction(loop_stmt);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 }
 
-TEST_F(ResolverValidationTest,
-       Stmt_Loop_ContinueInLoopBodySubscopeBeforeDecl_UsageInContinuing) {
-  // loop  {
-  //     if (true) {
-  //         continue; // Still bypasses z decl (if we reach here)
-  //     }
-  //     var z : i32;
-  //     continuing {
-  //         z = 2;
-  //     }
-  // }
+TEST_F(ResolverValidationTest, Stmt_Loop_ContinueInLoopBodySubscopeBeforeDecl_UsageInContinuing) {
+    // loop  {
+    //     if (true) {
+    //         continue; // Still bypasses z decl (if we reach here)
+    //     }
+    //     var z : i32;
+    //     continuing {
+    //         z = 2i;
+    //     }
+    // }
 
-  auto cont_loc = Source{{12, 34}};
-  auto decl_loc = Source{{56, 78}};
-  auto ref_loc = Source{{90, 12}};
-  auto* body =
-      Block(If(Expr(true), Block(Continue(cont_loc))),
-            Decl(Var(decl_loc, "z", ty.i32(), ast::StorageClass::kNone)));
-  auto* continuing = Block(Assign(Expr(ref_loc, "z"), 2));
-  auto* loop_stmt = Loop(body, continuing);
-  WrapInFunction(loop_stmt);
+    auto cont_loc = Source{{12, 34}};
+    auto decl_loc = Source{{56, 78}};
+    auto ref_loc = Source{{90, 12}};
+    auto* body = Block(If(Expr(true), Block(Continue(cont_loc))),
+                       Decl(Var(decl_loc, "z", ty.i32(), ast::StorageClass::kNone)));
+    auto* continuing = Block(Assign(Expr(ref_loc, "z"), 2_i));
+    auto* loop_stmt = Loop(body, continuing);
+    WrapInFunction(loop_stmt);
 
-  EXPECT_FALSE(r()->Resolve()) << r()->error();
-  EXPECT_EQ(r()->error(),
-            R"(12:34 error: continue statement bypasses declaration of 'z'
-56:78 note: identifier 'z' declared here
-90:12 note: identifier 'z' referenced in continuing block here)");
-}
-
-TEST_F(
-    ResolverValidationTest,
-    Stmt_Loop_ContinueInLoopBodySubscopeBeforeDecl_UsageInContinuingSubscope) {
-  // loop  {
-  //     if (true) {
-  //         continue; // Still bypasses z decl (if we reach here)
-  //     }
-  //     var z : i32;
-  //     continuing {
-  //         if (true) {
-  //             z = 2; // Must fail even if z is in a sub-scope
-  //         }
-  //     }
-  // }
-
-  auto cont_loc = Source{{12, 34}};
-  auto decl_loc = Source{{56, 78}};
-  auto ref_loc = Source{{90, 12}};
-  auto* body =
-      Block(If(Expr(true), Block(Continue(cont_loc))),
-            Decl(Var(decl_loc, "z", ty.i32(), ast::StorageClass::kNone)));
-
-  auto* continuing =
-      Block(If(Expr(true), Block(Assign(Expr(ref_loc, "z"), 2))));
-  auto* loop_stmt = Loop(body, continuing);
-  WrapInFunction(loop_stmt);
-
-  EXPECT_FALSE(r()->Resolve()) << r()->error();
-  EXPECT_EQ(r()->error(),
-            R"(12:34 error: continue statement bypasses declaration of 'z'
+    EXPECT_FALSE(r()->Resolve()) << r()->error();
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: continue statement bypasses declaration of 'z'
 56:78 note: identifier 'z' declared here
 90:12 note: identifier 'z' referenced in continuing block here)");
 }
 
 TEST_F(ResolverValidationTest,
-       Stmt_Loop_ContinueInLoopBodySubscopeBeforeDecl_UsageOutsideBlock) {
-  // loop  {
-  //     if (true) {
-  //         continue; // bypasses z decl (if we reach here)
-  //     }
-  //     var z : i32;
-  //     continuing {
-  //         // Must fail even if z is used in an expression that isn't
-  //         // directly contained inside a block.
-  //         if (z < 2) {
-  //         }
-  //     }
-  // }
+       Stmt_Loop_ContinueInLoopBodySubscopeBeforeDecl_UsageInContinuingSubscope) {
+    // loop  {
+    //     if (true) {
+    //         continue; // Still bypasses z decl (if we reach here)
+    //     }
+    //     var z : i32;
+    //     continuing {
+    //         if (true) {
+    //             z = 2i; // Must fail even if z is in a sub-scope
+    //         }
+    //     }
+    // }
 
-  auto cont_loc = Source{{12, 34}};
-  auto decl_loc = Source{{56, 78}};
-  auto ref_loc = Source{{90, 12}};
-  auto* body =
-      Block(If(Expr(true), Block(Continue(cont_loc))),
-            Decl(Var(decl_loc, "z", ty.i32(), ast::StorageClass::kNone)));
-  auto* compare = create<ast::BinaryExpression>(ast::BinaryOp::kLessThan,
-                                                Expr(ref_loc, "z"), Expr(2));
-  auto* continuing = Block(If(compare, Block()));
-  auto* loop_stmt = Loop(body, continuing);
-  WrapInFunction(loop_stmt);
+    auto cont_loc = Source{{12, 34}};
+    auto decl_loc = Source{{56, 78}};
+    auto ref_loc = Source{{90, 12}};
+    auto* body = Block(If(Expr(true), Block(Continue(cont_loc))),
+                       Decl(Var(decl_loc, "z", ty.i32(), ast::StorageClass::kNone)));
 
-  EXPECT_FALSE(r()->Resolve()) << r()->error();
-  EXPECT_EQ(r()->error(),
-            R"(12:34 error: continue statement bypasses declaration of 'z'
+    auto* continuing = Block(If(Expr(true), Block(Assign(Expr(ref_loc, "z"), 2_i))));
+    auto* loop_stmt = Loop(body, continuing);
+    WrapInFunction(loop_stmt);
+
+    EXPECT_FALSE(r()->Resolve()) << r()->error();
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: continue statement bypasses declaration of 'z'
+56:78 note: identifier 'z' declared here
+90:12 note: identifier 'z' referenced in continuing block here)");
+}
+
+TEST_F(ResolverValidationTest, Stmt_Loop_ContinueInLoopBodySubscopeBeforeDecl_UsageOutsideBlock) {
+    // loop  {
+    //     if (true) {
+    //         continue; // bypasses z decl (if we reach here)
+    //     }
+    //     var z : i32;
+    //     continuing {
+    //         // Must fail even if z is used in an expression that isn't
+    //         // directly contained inside a block.
+    //         if (z < 2i) {
+    //         }
+    //     }
+    // }
+
+    auto cont_loc = Source{{12, 34}};
+    auto decl_loc = Source{{56, 78}};
+    auto ref_loc = Source{{90, 12}};
+    auto* body = Block(If(Expr(true), Block(Continue(cont_loc))),
+                       Decl(Var(decl_loc, "z", ty.i32(), ast::StorageClass::kNone)));
+    auto* compare =
+        create<ast::BinaryExpression>(ast::BinaryOp::kLessThan, Expr(ref_loc, "z"), Expr(2_i));
+    auto* continuing = Block(If(compare, Block()));
+    auto* loop_stmt = Loop(body, continuing);
+    WrapInFunction(loop_stmt);
+
+    EXPECT_FALSE(r()->Resolve()) << r()->error();
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: continue statement bypasses declaration of 'z'
 56:78 note: identifier 'z' declared here
 90:12 note: identifier 'z' referenced in continuing block here)");
 }
 
 TEST_F(ResolverValidationTest,
        Stmt_Loop_ContinueInLoopBodySubscopeBeforeDecl_UsageInContinuingLoop) {
-  // loop  {
-  //     if (true) {
-  //         continue; // Still bypasses z decl (if we reach here)
-  //     }
-  //     var z : i32;
-  //     continuing {
-  //         loop {
-  //             z = 2; // Must fail even if z is in a sub-scope
-  //         }
-  //     }
-  // }
+    // loop  {
+    //     if (true) {
+    //         continue; // Still bypasses z decl (if we reach here)
+    //     }
+    //     var z : i32;
+    //     continuing {
+    //         loop {
+    //             z = 2i; // Must fail even if z is in a sub-scope
+    //         }
+    //     }
+    // }
 
-  auto cont_loc = Source{{12, 34}};
-  auto decl_loc = Source{{56, 78}};
-  auto ref_loc = Source{{90, 12}};
-  auto* body =
-      Block(If(Expr(true), Block(Continue(cont_loc))),
-            Decl(Var(decl_loc, "z", ty.i32(), ast::StorageClass::kNone)));
+    auto cont_loc = Source{{12, 34}};
+    auto decl_loc = Source{{56, 78}};
+    auto ref_loc = Source{{90, 12}};
+    auto* body = Block(If(Expr(true), Block(Continue(cont_loc))),
+                       Decl(Var(decl_loc, "z", ty.i32(), ast::StorageClass::kNone)));
 
-  auto* continuing = Block(Loop(Block(Assign(Expr(ref_loc, "z"), 2))));
-  auto* loop_stmt = Loop(body, continuing);
-  WrapInFunction(loop_stmt);
+    auto* continuing = Block(Loop(Block(Assign(Expr(ref_loc, "z"), 2_i))));
+    auto* loop_stmt = Loop(body, continuing);
+    WrapInFunction(loop_stmt);
 
-  EXPECT_FALSE(r()->Resolve()) << r()->error();
-  EXPECT_EQ(r()->error(),
-            R"(12:34 error: continue statement bypasses declaration of 'z'
+    EXPECT_FALSE(r()->Resolve()) << r()->error();
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: continue statement bypasses declaration of 'z'
 56:78 note: identifier 'z' declared here
 90:12 note: identifier 'z' referenced in continuing block here)");
 }
 
-TEST_F(ResolverValidationTest,
-       Stmt_Loop_ContinueInNestedLoopBodyBeforeDecl_UsageInContinuing) {
-  // loop  {
-  //     loop {
-  //         if (true) { continue; } // OK: not part of the outer loop
-  //         break;
-  //     }
-  //     var z : i32;
-  //     break;
-  //     continuing {
-  //         z = 2;
-  //     }
-  // }
+TEST_F(ResolverValidationTest, Stmt_Loop_ContinueInNestedLoopBodyBeforeDecl_UsageInContinuing) {
+    // loop  {
+    //     loop {
+    //         if (true) { continue; } // OK: not part of the outer loop
+    //         break;
+    //     }
+    //     var z : i32;
+    //     break;
+    //     continuing {
+    //         z = 2i;
+    //     }
+    // }
 
-  auto* inner_loop = Loop(Block(    //
-      If(true, Block(Continue())),  //
-      Break()));
-  auto* body = Block(inner_loop,                                          //
-                     Decl(Var("z", ty.i32(), ast::StorageClass::kNone)),  //
-                     Break());
-  auto* continuing = Block(Assign("z", 2));
-  auto* loop_stmt = Loop(body, continuing);
-  WrapInFunction(loop_stmt);
+    auto* inner_loop = Loop(Block(    //
+        If(true, Block(Continue())),  //
+        Break()));
+    auto* body = Block(inner_loop,                                          //
+                       Decl(Var("z", ty.i32(), ast::StorageClass::kNone)),  //
+                       Break());
+    auto* continuing = Block(Assign("z", 2_i));
+    auto* loop_stmt = Loop(body, continuing);
+    WrapInFunction(loop_stmt);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverValidationTest,
        Stmt_Loop_ContinueInNestedLoopBodyBeforeDecl_UsageInContinuingSubscope) {
-  // loop  {
-  //     loop {
-  //         if (true) { continue; } // OK: not part of the outer loop
-  //         break;
-  //     }
-  //     var z : i32;
-  //     break;
-  //     continuing {
-  //         if (true) {
-  //             z = 2;
-  //         }
-  //     }
-  // }
+    // loop  {
+    //     loop {
+    //         if (true) { continue; } // OK: not part of the outer loop
+    //         break;
+    //     }
+    //     var z : i32;
+    //     break;
+    //     continuing {
+    //         if (true) {
+    //             z = 2i;
+    //         }
+    //     }
+    // }
 
-  auto* inner_loop = Loop(Block(If(true, Block(Continue())),  //
-                                Break()));
-  auto* body = Block(inner_loop,                                          //
-                     Decl(Var("z", ty.i32(), ast::StorageClass::kNone)),  //
-                     Break());
-  auto* continuing = Block(If(Expr(true), Block(Assign("z", 2))));
-  auto* loop_stmt = Loop(body, continuing);
-  WrapInFunction(loop_stmt);
+    auto* inner_loop = Loop(Block(If(true, Block(Continue())),  //
+                                  Break()));
+    auto* body = Block(inner_loop,                                          //
+                       Decl(Var("z", ty.i32(), ast::StorageClass::kNone)),  //
+                       Break());
+    auto* continuing = Block(If(Expr(true), Block(Assign("z", 2_i))));
+    auto* loop_stmt = Loop(body, continuing);
+    WrapInFunction(loop_stmt);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
-TEST_F(ResolverValidationTest,
-       Stmt_Loop_ContinueInNestedLoopBodyBeforeDecl_UsageInContinuingLoop) {
-  // loop  {
-  //     loop {
-  //         if (true) { continue; } // OK: not part of the outer loop
-  //         break;
-  //     }
-  //     var z : i32;
-  //     break;
-  //     continuing {
-  //         loop {
-  //             z = 2;
-  //             break;
-  //         }
-  //     }
-  // }
+TEST_F(ResolverValidationTest, Stmt_Loop_ContinueInNestedLoopBodyBeforeDecl_UsageInContinuingLoop) {
+    // loop  {
+    //     loop {
+    //         if (true) { continue; } // OK: not part of the outer loop
+    //         break;
+    //     }
+    //     var z : i32;
+    //     break;
+    //     continuing {
+    //         loop {
+    //             z = 2i;
+    //             break;
+    //         }
+    //     }
+    // }
 
-  auto* inner_loop = Loop(Block(If(true, Block(Continue())),  //
-                                Break()));
-  auto* body = Block(inner_loop,                                          //
-                     Decl(Var("z", ty.i32(), ast::StorageClass::kNone)),  //
-                     Break());
-  auto* continuing = Block(Loop(Block(Assign("z", 2),  //
-                                      Break())));
-  auto* loop_stmt = Loop(body, continuing);
-  WrapInFunction(loop_stmt);
+    auto* inner_loop = Loop(Block(If(true, Block(Continue())),  //
+                                  Break()));
+    auto* body = Block(inner_loop,                                          //
+                       Decl(Var("z", ty.i32(), ast::StorageClass::kNone)),  //
+                       Break());
+    auto* continuing = Block(Loop(Block(Assign("z", 2_i),  //
+                                        Break())));
+    auto* loop_stmt = Loop(body, continuing);
+    WrapInFunction(loop_stmt);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverTest, Stmt_Loop_ContinueInLoopBodyAfterDecl_UsageInContinuing) {
-  // loop  {
-  //     var z : i32;
-  //     if (true) { continue; }
-  //     break;
-  //     continuing {
-  //         z = 2;
-  //     }
-  // }
+    // loop  {
+    //     var z : i32;
+    //     if (true) { continue; }
+    //     break;
+    //     continuing {
+    //         z = 2i;
+    //     }
+    // }
 
-  auto error_loc = Source{{12, 34}};
-  auto* body = Block(Decl(Var("z", ty.i32(), ast::StorageClass::kNone)),
-                     If(true, Block(Continue())),  //
-                     Break());
-  auto* continuing = Block(Assign(Expr(error_loc, "z"), 2));
-  auto* loop_stmt = Loop(body, continuing);
-  WrapInFunction(loop_stmt);
+    auto error_loc = Source{{12, 34}};
+    auto* body =
+        Block(Decl(Var("z", ty.i32(), ast::StorageClass::kNone)), If(true, Block(Continue())),  //
+              Break());
+    auto* continuing = Block(Assign(Expr(error_loc, "z"), 2_i));
+    auto* loop_stmt = Loop(body, continuing);
+    WrapInFunction(loop_stmt);
 
-  EXPECT_TRUE(r()->Resolve());
+    EXPECT_TRUE(r()->Resolve());
 }
 
 TEST_F(ResolverTest, Stmt_Loop_ReturnInContinuing_Direct) {
-  // loop  {
-  //   continuing {
-  //     return;
-  //   }
-  // }
+    // loop  {
+    //   continuing {
+    //     return;
+    //   }
+    // }
 
-  WrapInFunction(Loop(  // loop
-      Block(),          //   loop block
-      Block(            //   loop continuing block
-          Return(Source{{12, 34}}))));
+    WrapInFunction(Loop(  // loop
+        Block(),          //   loop block
+        Block(            //   loop continuing block
+            Return(Source{{12, 34}}))));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: continuing blocks must not contain a return statement)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: continuing blocks must not contain a return statement)");
 }
 
 TEST_F(ResolverTest, Stmt_Loop_ReturnInContinuing_Indirect) {
-  // loop {
-  //   if (false) { break; }
-  //   continuing {
-  //     loop {
-  //       return;
-  //     }
-  //   }
-  // }
+    // loop {
+    //   if (false) { break; }
+    //   continuing {
+    //     loop {
+    //       return;
+    //     }
+    //   }
+    // }
 
-  WrapInFunction(Loop(                   // outer loop
-      Block(If(false, Block(Break()))),  //   outer loop block
-      Block(Source{{56, 78}},            //   outer loop continuing block
-            Loop(                        //     inner loop
-                Block(                   //       inner loop block
-                    Return(Source{{12, 34}}))))));
+    WrapInFunction(Loop(                   // outer loop
+        Block(If(false, Block(Break()))),  //   outer loop block
+        Block(Source{{56, 78}},            //   outer loop continuing block
+              Loop(                        //     inner loop
+                  Block(                   //       inner loop block
+                      Return(Source{{12, 34}}))))));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: continuing blocks must not contain a return statement
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: continuing blocks must not contain a return statement
 56:78 note: see continuing block here)");
 }
 
 TEST_F(ResolverTest, Stmt_Loop_DiscardInContinuing_Direct) {
-  // loop  {
-  //   continuing {
-  //     discard;
-  //   }
-  // }
+    // loop  {
+    //   continuing {
+    //     discard;
+    //   }
+    // }
 
-  WrapInFunction(Loop(  // loop
-      Block(),          //   loop block
-      Block(            //   loop continuing block
-          Discard(Source{{12, 34}}))));
+    WrapInFunction(Loop(  // loop
+        Block(),          //   loop block
+        Block(            //   loop continuing block
+            Discard(Source{{12, 34}}))));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: continuing blocks must not contain a discard statement)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: continuing blocks must not contain a discard statement)");
 }
 
 TEST_F(ResolverTest, Stmt_Loop_DiscardInContinuing_Indirect) {
-  // loop {
-  //   if (false) { break; }
-  //   continuing {
-  //     loop { discard; }
-  //   }
-  // }
+    // loop {
+    //   if (false) { break; }
+    //   continuing {
+    //     loop { discard; }
+    //   }
+    // }
 
-  WrapInFunction(Loop(                   // outer loop
-      Block(If(false, Block(Break()))),  //   outer loop block
-      Block(Source{{56, 78}},            //   outer loop continuing block
-            Loop(                        //     inner loop
-                Block(                   //       inner loop block
-                    Discard(Source{{12, 34}}))))));
+    WrapInFunction(Loop(                   // outer loop
+        Block(If(false, Block(Break()))),  //   outer loop block
+        Block(Source{{56, 78}},            //   outer loop continuing block
+              Loop(                        //     inner loop
+                  Block(                   //       inner loop block
+                      Discard(Source{{12, 34}}))))));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: continuing blocks must not contain a discard statement
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: continuing blocks must not contain a discard statement
 56:78 note: see continuing block here)");
 }
 
 TEST_F(ResolverTest, Stmt_Loop_DiscardInContinuing_Indirect_ViaCall) {
-  // fn MayDiscard() { if (true) { discard; } }
-  // fn F() { MayDiscard(); }
-  // loop {
-  //   continuing {
-  //     loop { F(); }
-  //   }
-  // }
+    // fn MayDiscard() { if (true) { discard; } }
+    // fn F() { MayDiscard(); }
+    // loop {
+    //   continuing {
+    //     loop { F(); }
+    //   }
+    // }
 
-  Func("MayDiscard", {}, ty.void_(), {If(true, Block(Discard()))});
-  Func("SomeFunc", {}, ty.void_(), {CallStmt(Call("MayDiscard"))});
+    Func("MayDiscard", {}, ty.void_(), {If(true, Block(Discard()))});
+    Func("SomeFunc", {}, ty.void_(), {CallStmt(Call("MayDiscard"))});
 
-  WrapInFunction(Loop(         // outer loop
-      Block(),                 //   outer loop block
-      Block(Source{{56, 78}},  //   outer loop continuing block
-            Loop(              //     inner loop
-                Block(         //       inner loop block
-                    CallStmt(Call(Source{{12, 34}}, "SomeFunc")))))));
+    WrapInFunction(Loop(         // outer loop
+        Block(),                 //   outer loop block
+        Block(Source{{56, 78}},  //   outer loop continuing block
+              Loop(              //     inner loop
+                  Block(         //       inner loop block
+                      CallStmt(Call(Source{{12, 34}}, "SomeFunc")))))));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: cannot call a function that may discard inside a continuing block
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: cannot call a function that may discard inside a continuing block
 56:78 note: see continuing block here)");
 }
 
 TEST_F(ResolverTest, Stmt_Loop_ContinueInContinuing_Direct) {
-  // loop  {
-  //     continuing {
-  //         continue;
-  //     }
-  // }
+    // loop  {
+    //     continuing {
+    //         continue;
+    //     }
+    // }
 
-  WrapInFunction(Loop(         // loop
-      Block(),                 //   loop block
-      Block(Source{{56, 78}},  //   loop continuing block
-            Continue(Source{{12, 34}}))));
+    WrapInFunction(Loop(         // loop
+        Block(),                 //   loop block
+        Block(Source{{56, 78}},  //   loop continuing block
+              Continue(Source{{12, 34}}))));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: continuing blocks must not contain a continue statement");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: continuing blocks must not contain a continue statement");
 }
 
 TEST_F(ResolverTest, Stmt_Loop_ContinueInContinuing_Indirect) {
-  // loop {
-  //   if (false) { break; }
-  //   continuing {
-  //     loop {
-  //       if (false) { break; }
-  //       continue;
-  //     }
-  //   }
-  // }
+    // loop {
+    //   if (false) { break; }
+    //   continuing {
+    //     loop {
+    //       if (false) { break; }
+    //       continue;
+    //     }
+    //   }
+    // }
 
-  WrapInFunction(Loop(                        // outer loop
-      Block(                                  //   outer loop block
-          If(false, Block(Break()))),         //     if (false) { break; }
-      Block(                                  //   outer loop continuing block
-          Loop(                               //     inner loop
-              Block(                          //       inner loop block
-                  If(false, Block(Break())),  //          if (false) { break; }
-                  Continue(Source{{12, 34}}))))));  //    continue
+    WrapInFunction(Loop(                              // outer loop
+        Block(                                        //   outer loop block
+            If(false, Block(Break()))),               //     if (false) { break; }
+        Block(                                        //   outer loop continuing block
+            Loop(                                     //     inner loop
+                Block(                                //       inner loop block
+                    If(false, Block(Break())),        //          if (false) { break; }
+                    Continue(Source{{12, 34}}))))));  //    continue
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverTest, Stmt_ForLoop_ReturnInContinuing_Direct) {
-  // for(;; return) {
-  //   break;
-  // }
+    // for(;; return) {
+    //   break;
+    // }
 
-  WrapInFunction(For(nullptr, nullptr, Return(Source{{12, 34}}),  //
-                     Block(Break())));
+    WrapInFunction(For(nullptr, nullptr, Return(Source{{12, 34}}),  //
+                       Block(Break())));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: continuing blocks must not contain a return statement)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: continuing blocks must not contain a return statement)");
 }
 
 TEST_F(ResolverTest, Stmt_ForLoop_ReturnInContinuing_Indirect) {
-  // for(;; loop { return }) {
-  //   break;
-  // }
+    // for(;; loop { return }) {
+    //   break;
+    // }
 
-  WrapInFunction(For(nullptr, nullptr,
-                     Loop(Source{{56, 78}},                  //
-                          Block(Return(Source{{12, 34}}))),  //
-                     Block(Break())));
+    WrapInFunction(For(nullptr, nullptr,
+                       Loop(Source{{56, 78}},                  //
+                            Block(Return(Source{{12, 34}}))),  //
+                       Block(Break())));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: continuing blocks must not contain a return statement
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: continuing blocks must not contain a return statement
 56:78 note: see continuing block here)");
 }
 
 TEST_F(ResolverTest, Stmt_ForLoop_DiscardInContinuing_Direct) {
-  // for(;; discard) {
-  //   break;
-  // }
+    // for(;; discard) {
+    //   break;
+    // }
 
-  WrapInFunction(For(nullptr, nullptr, Discard(Source{{12, 34}}),  //
-                     Block(Break())));
+    WrapInFunction(For(nullptr, nullptr, Discard(Source{{12, 34}}),  //
+                       Block(Break())));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: continuing blocks must not contain a discard statement)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: continuing blocks must not contain a discard statement)");
 }
 
 TEST_F(ResolverTest, Stmt_ForLoop_DiscardInContinuing_Indirect) {
-  // for(;; loop { discard }) {
-  //   break;
-  // }
+    // for(;; loop { discard }) {
+    //   break;
+    // }
 
-  WrapInFunction(For(nullptr, nullptr,
-                     Loop(Source{{56, 78}},                   //
-                          Block(Discard(Source{{12, 34}}))),  //
-                     Block(Break())));
+    WrapInFunction(For(nullptr, nullptr,
+                       Loop(Source{{56, 78}},                   //
+                            Block(Discard(Source{{12, 34}}))),  //
+                       Block(Break())));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: continuing blocks must not contain a discard statement
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: continuing blocks must not contain a discard statement
 56:78 note: see continuing block here)");
 }
 
 TEST_F(ResolverTest, Stmt_ForLoop_DiscardInContinuing_Indirect_ViaCall) {
-  // fn MayDiscard() { if (true) { discard; } }
-  // fn F() { MayDiscard(); }
-  // for(;; loop { F() }) {
-  //   break;
-  // }
+    // fn MayDiscard() { if (true) { discard; } }
+    // fn F() { MayDiscard(); }
+    // for(;; loop { F() }) {
+    //   break;
+    // }
 
-  Func("MayDiscard", {}, ty.void_(), {If(true, Block(Discard()))});
-  Func("F", {}, ty.void_(), {CallStmt(Call("MayDiscard"))});
+    Func("MayDiscard", {}, ty.void_(), {If(true, Block(Discard()))});
+    Func("F", {}, ty.void_(), {CallStmt(Call("MayDiscard"))});
 
-  WrapInFunction(For(nullptr, nullptr,
-                     Loop(Source{{56, 78}},                               //
-                          Block(CallStmt(Call(Source{{12, 34}}, "F")))),  //
-                     Block(Break())));
+    WrapInFunction(For(nullptr, nullptr,
+                       Loop(Source{{56, 78}},                               //
+                            Block(CallStmt(Call(Source{{12, 34}}, "F")))),  //
+                       Block(Break())));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: cannot call a function that may discard inside a continuing block
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: cannot call a function that may discard inside a continuing block
 56:78 note: see continuing block here)");
 }
 
 TEST_F(ResolverTest, Stmt_ForLoop_ContinueInContinuing_Direct) {
-  // for(;; continue) {
-  //   break;
-  // }
+    // for(;; continue) {
+    //   break;
+    // }
 
-  WrapInFunction(For(nullptr, nullptr, Continue(Source{{12, 34}}),  //
-                     Block(Break())));
+    WrapInFunction(For(nullptr, nullptr, Continue(Source{{12, 34}}),  //
+                       Block(Break())));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: continuing blocks must not contain a continue statement");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: continuing blocks must not contain a continue statement");
 }
 
 TEST_F(ResolverTest, Stmt_ForLoop_ContinueInContinuing_Indirect) {
-  // for(;; loop { if (false) { break; } continue }) {
-  //   break;
-  // }
+    // for(;; loop { if (false) { break; } continue }) {
+    //   break;
+    // }
 
-  WrapInFunction(For(nullptr, nullptr,
-                     Loop(                                    //
-                         Block(If(false, Block(Break())),     //
-                               Continue(Source{{12, 34}}))),  //
-                     Block(Break())));
+    WrapInFunction(For(nullptr, nullptr,
+                       Loop(                                    //
+                           Block(If(false, Block(Break())),     //
+                                 Continue(Source{{12, 34}}))),  //
+                       Block(Break())));
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverTest, Stmt_ForLoop_CondIsBoolRef) {
-  // var cond : bool = true;
-  // for (; cond; ) {
-  // }
+    // var cond : bool = true;
+    // for (; cond; ) {
+    // }
 
-  auto* cond = Var("cond", ty.bool_(), Expr(true));
-  WrapInFunction(Decl(cond), For(nullptr, "cond", nullptr, Block()));
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    auto* cond = Var("cond", ty.bool_(), Expr(true));
+    WrapInFunction(Decl(cond), For(nullptr, "cond", nullptr, Block()));
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverTest, Stmt_ForLoop_CondIsNotBool) {
-  // for (; 1.0f; ) {
-  // }
+    // for (; 1.0f; ) {
+    // }
 
-  WrapInFunction(For(nullptr, Expr(Source{{12, 34}}, 1.0f), nullptr, Block()));
+    WrapInFunction(For(nullptr, Expr(Source{{12, 34}}, 1.0f), nullptr, Block()));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: for-loop condition must be bool, got f32");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: for-loop condition must be bool, got f32");
 }
 
 TEST_F(ResolverValidationTest, Stmt_ContinueInLoop) {
-  WrapInFunction(Loop(Block(If(false, Block(Break())),  //
-                            Continue(Source{{12, 34}}))));
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    WrapInFunction(Loop(Block(If(false, Block(Break())),  //
+                              Continue(Source{{12, 34}}))));
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverValidationTest, Stmt_ContinueNotInLoop) {
-  WrapInFunction(Continue(Source{{12, 34}}));
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: continue statement must be in a loop");
+    WrapInFunction(Continue(Source{{12, 34}}));
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: continue statement must be in a loop");
 }
 
 TEST_F(ResolverValidationTest, Stmt_BreakInLoop) {
-  WrapInFunction(Loop(Block(Break(Source{{12, 34}}))));
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    WrapInFunction(Loop(Block(Break(Source{{12, 34}}))));
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverValidationTest, Stmt_BreakInSwitch) {
-  WrapInFunction(Loop(Block(Switch(Expr(1),               //
-                                   Case(Expr(1),          //
-                                        Block(Break())),  //
-                                   DefaultCase()),        //
-                            Break())));                   //
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    WrapInFunction(Loop(Block(Switch(Expr(1_i),             //
+                                     Case(Expr(1_i),        //
+                                          Block(Break())),  //
+                                     DefaultCase()),        //
+                              Break())));                   //
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverValidationTest, Stmt_BreakInIfTrueInContinuing) {
-  auto* cont = Block(                           // continuing {
-      If(true, Block(                           //   if(true) {
-                   Break(Source{{12, 34}}))));  //     break;
-                                                //   }
-                                                // }
-  WrapInFunction(Loop(Block(), cont));
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-}
-
-TEST_F(ResolverValidationTest, Stmt_BreakInIfElseInContinuing) {
-  auto* cont = Block(                      // continuing {
-      If(true, Block(),                    //   if(true) {
-         Else(Block(                       //   } else {
-             Break(Source{{12, 34}})))));  //     break;
-                                           //   }
-                                           // }
-  WrapInFunction(Loop(Block(), cont));
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
-}
-
-TEST_F(ResolverValidationTest, Stmt_BreakInContinuing) {
-  auto* cont = Block(                   // continuing {
-      Block(Break(Source{{12, 34}})));  //   break;
-                                        // }
-  WrapInFunction(Loop(Block(), cont));
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: break statement in a continuing block must be the single "
-      "statement of an if statement's true or false block, and that if "
-      "statement must be the last statement of the continuing block\n"
-      "12:34 note: break statement is not directly in if statement block");
-}
-
-TEST_F(ResolverValidationTest, Stmt_BreakInIfInIfInContinuing) {
-  auto* cont = Block(                                      // continuing {
-      If(true, Block(                                      //   if(true) {
-                   If(Source{{56, 78}}, true,              //     if(true) {
-                      Block(Break(Source{{12, 34}}))))));  //       break;
-                                                           //     }
-                                                           //   }
-                                                           // }
-  WrapInFunction(Loop(Block(), cont));
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: break statement in a continuing block must be the single "
-      "statement of an if statement's true or false block, and that if "
-      "statement must be the last statement of the continuing block\n"
-      "56:78 note: if statement containing break statement is not directly in "
-      "continuing block");
-}
-
-TEST_F(ResolverValidationTest, Stmt_BreakInIfTrueMultipleStmtsInContinuing) {
-  auto* cont = Block(                             // continuing {
-      If(true, Block(Source{{56, 78}},            //   if(true) {
-                     Assign(Phony(), 1),          //     _ = 1;
+    auto* cont = Block(                           // continuing {
+        If(true, Block(                           //   if(true) {
                      Break(Source{{12, 34}}))));  //     break;
                                                   //   }
                                                   // }
-  WrapInFunction(Loop(Block(), cont));
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: break statement in a continuing block must be the single "
-      "statement of an if statement's true or false block, and that if "
-      "statement must be the last statement of the continuing block\n"
-      "56:78 note: if statement block contains multiple statements");
+    WrapInFunction(Loop(Block(), cont));
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+}
+
+TEST_F(ResolverValidationTest, Stmt_BreakInIfElseInContinuing) {
+    auto* cont = Block(                      // continuing {
+        If(true, Block(),                    //   if(true) {
+           Else(Block(                       //   } else {
+               Break(Source{{12, 34}})))));  //     break;
+                                             //   }
+                                             // }
+    WrapInFunction(Loop(Block(), cont));
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
+}
+
+TEST_F(ResolverValidationTest, Stmt_BreakInContinuing) {
+    auto* cont = Block(                   // continuing {
+        Block(Break(Source{{12, 34}})));  //   break;
+                                          // }
+    WrapInFunction(Loop(Block(), cont));
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: break statement in a continuing block must be the single "
+              "statement of an if statement's true or false block, and that if "
+              "statement must be the last statement of the continuing block\n"
+              "12:34 note: break statement is not directly in if statement block");
+}
+
+TEST_F(ResolverValidationTest, Stmt_BreakInIfInIfInContinuing) {
+    auto* cont = Block(                                      // continuing {
+        If(true, Block(                                      //   if(true) {
+                     If(Source{{56, 78}}, true,              //     if(true) {
+                        Block(Break(Source{{12, 34}}))))));  //       break;
+                                                             //     }
+                                                             //   }
+                                                             // }
+    WrapInFunction(Loop(Block(), cont));
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: break statement in a continuing block must be the single "
+              "statement of an if statement's true or false block, and that if "
+              "statement must be the last statement of the continuing block\n"
+              "56:78 note: if statement containing break statement is not directly in "
+              "continuing block");
+}
+
+TEST_F(ResolverValidationTest, Stmt_BreakInIfTrueMultipleStmtsInContinuing) {
+    auto* cont = Block(                             // continuing {
+        If(true, Block(Source{{56, 78}},            //   if(true) {
+                       Assign(Phony(), 1_i),        //     _ = 1i;
+                       Break(Source{{12, 34}}))));  //     break;
+                                                    //   }
+                                                    // }
+    WrapInFunction(Loop(Block(), cont));
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: break statement in a continuing block must be the single "
+              "statement of an if statement's true or false block, and that if "
+              "statement must be the last statement of the continuing block\n"
+              "56:78 note: if statement block contains multiple statements");
 }
 
 TEST_F(ResolverValidationTest, Stmt_BreakInIfElseMultipleStmtsInContinuing) {
-  auto* cont = Block(                             // continuing {
-      If(true, Block(),                           //   if(true) {
-         Else(Block(Source{{56, 78}},             //   } else {
-                    Assign(Phony(), 1),           //     _ = 1;
-                    Break(Source{{12, 34}})))));  //     break;
-                                                  //   }
-                                                  // }
-  WrapInFunction(Loop(Block(), cont));
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: break statement in a continuing block must be the single "
-      "statement of an if statement's true or false block, and that if "
-      "statement must be the last statement of the continuing block\n"
-      "56:78 note: if statement block contains multiple statements");
+    auto* cont = Block(                             // continuing {
+        If(true, Block(),                           //   if(true) {
+           Else(Block(Source{{56, 78}},             //   } else {
+                      Assign(Phony(), 1_i),         //     _ = 1i;
+                      Break(Source{{12, 34}})))));  //     break;
+                                                    //   }
+                                                    // }
+    WrapInFunction(Loop(Block(), cont));
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: break statement in a continuing block must be the single "
+              "statement of an if statement's true or false block, and that if "
+              "statement must be the last statement of the continuing block\n"
+              "56:78 note: if statement block contains multiple statements");
 }
 
 TEST_F(ResolverValidationTest, Stmt_BreakInIfElseIfInContinuing) {
-  auto* cont = Block(                             // continuing {
-      If(true, Block(),                           //   if(true) {
-         Else(Expr(Source{{56, 78}}, true),       //   } else if (true) {
-              Block(Break(Source{{12, 34}})))));  //     break;
-                                                  //   }
-                                                  // }
-  WrapInFunction(Loop(Block(), cont));
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: break statement in a continuing block must be the single "
-      "statement of an if statement's true or false block, and that if "
-      "statement must be the last statement of the continuing block\n"
-      "56:78 note: else has condition");
+    auto* cont = Block(                                 // continuing {
+        If(true, Block(),                               //   if(true) {
+           Else(If(Source{{56, 78}}, Expr(true),        //   } else if (true) {
+                   Block(Break(Source{{12, 34}}))))));  //     break;
+                                                        //   }
+                                                        // }
+    WrapInFunction(Loop(Block(), cont));
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: break statement in a continuing block must be the single "
+              "statement of an if statement's true or false block, and that if "
+              "statement must be the last statement of the continuing block\n"
+              "56:78 note: else has condition");
 }
 
 TEST_F(ResolverValidationTest, Stmt_BreakInIfNonEmptyElseInContinuing) {
-  auto* cont = Block(                        // continuing {
-      If(true,                               //   if(true) {
-         Block(Break(Source{{12, 34}})),     //     break;
-         Else(Block(Source{{56, 78}},        //   } else {
-                    Assign(Phony(), 1)))));  //     _ = 1;
-                                             //   }
-                                             // }
-  WrapInFunction(Loop(Block(), cont));
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: break statement in a continuing block must be the single "
-      "statement of an if statement's true or false block, and that if "
-      "statement must be the last statement of the continuing block\n"
-      "56:78 note: non-empty false block");
+    auto* cont = Block(                          // continuing {
+        If(true,                                 //   if(true) {
+           Block(Break(Source{{12, 34}})),       //     break;
+           Else(Block(Source{{56, 78}},          //   } else {
+                      Assign(Phony(), 1_i)))));  //     _ = 1i;
+                                                 //   }
+                                                 // }
+    WrapInFunction(Loop(Block(), cont));
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: break statement in a continuing block must be the single "
+              "statement of an if statement's true or false block, and that if "
+              "statement must be the last statement of the continuing block\n"
+              "56:78 note: non-empty false block");
 }
 
 TEST_F(ResolverValidationTest, Stmt_BreakInIfElseNonEmptyTrueInContinuing) {
-  auto* cont = Block(                                  // continuing {
-      If(true,                                         //   if(true) {
-         Block(Source{{56, 78}}, Assign(Phony(), 1)),  //     _ = 1;
-         Else(Block(                                   //   } else {
-             Break(Source{{12, 34}})))));              //     break;
-                                                       //   }
-                                                       // }
-  WrapInFunction(Loop(Block(), cont));
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: break statement in a continuing block must be the single "
-      "statement of an if statement's true or false block, and that if "
-      "statement must be the last statement of the continuing block\n"
-      "56:78 note: non-empty true block");
+    auto* cont = Block(                                    // continuing {
+        If(true,                                           //   if(true) {
+           Block(Source{{56, 78}}, Assign(Phony(), 1_i)),  //     _ = 1i;
+           Else(Block(                                     //   } else {
+               Break(Source{{12, 34}})))));                //     break;
+                                                           //   }
+                                                           // }
+    WrapInFunction(Loop(Block(), cont));
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: break statement in a continuing block must be the single "
+              "statement of an if statement's true or false block, and that if "
+              "statement must be the last statement of the continuing block\n"
+              "56:78 note: non-empty true block");
 }
 
 TEST_F(ResolverValidationTest, Stmt_BreakInIfInContinuingNotLast) {
-  auto* cont = Block(                      // continuing {
-      If(Source{{56, 78}}, true,           //   if(true) {
-         Block(Break(Source{{12, 34}}))),  //     break;
-                                           //   }
-      Assign(Phony(), 1));                 //   _ = 1;
-                                           // }
-  WrapInFunction(Loop(Block(), cont));
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: break statement in a continuing block must be the single "
-      "statement of an if statement's true or false block, and that if "
-      "statement must be the last statement of the continuing block\n"
-      "56:78 note: if statement containing break statement is not the last "
-      "statement of the continuing block");
+    auto* cont = Block(                      // continuing {
+        If(Source{{56, 78}}, true,           //   if(true) {
+           Block(Break(Source{{12, 34}}))),  //     break;
+                                             //   }
+        Assign(Phony(), 1_i));               //   _ = 1i;
+                                             // }
+    WrapInFunction(Loop(Block(), cont));
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: break statement in a continuing block must be the single "
+              "statement of an if statement's true or false block, and that if "
+              "statement must be the last statement of the continuing block\n"
+              "56:78 note: if statement containing break statement is not the last "
+              "statement of the continuing block");
 }
 
 TEST_F(ResolverValidationTest, Stmt_BreakNotInLoopOrSwitch) {
-  WrapInFunction(Break(Source{{12, 34}}));
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: break statement must be in a loop or switch case");
+    WrapInFunction(Break(Source{{12, 34}}));
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: break statement must be in a loop or switch case");
 }
 
 TEST_F(ResolverValidationTest, StructMemberDuplicateName) {
-  Structure("S", {Member(Source{{12, 34}}, "a", ty.i32()),
-                  Member(Source{{56, 78}}, "a", ty.i32())});
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "56:78 error: redefinition of 'a'\n12:34 note: previous definition "
-            "is here");
+    Structure("S",
+              {Member(Source{{12, 34}}, "a", ty.i32()), Member(Source{{56, 78}}, "a", ty.i32())});
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "56:78 error: redefinition of 'a'\n12:34 note: previous definition "
+              "is here");
 }
 TEST_F(ResolverValidationTest, StructMemberDuplicateNameDifferentTypes) {
-  Structure("S", {Member(Source{{12, 34}}, "a", ty.bool_()),
-                  Member(Source{{12, 34}}, "a", ty.vec3<f32>())});
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: redefinition of 'a'\n12:34 note: previous definition "
-            "is here");
+    Structure("S", {Member(Source{{12, 34}}, "a", ty.bool_()),
+                    Member(Source{{12, 34}}, "a", ty.vec3<f32>())});
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: redefinition of 'a'\n12:34 note: previous definition "
+              "is here");
 }
 TEST_F(ResolverValidationTest, StructMemberDuplicateNamePass) {
-  Structure("S", {Member("a", ty.i32()), Member("b", ty.f32())});
-  Structure("S1", {Member("a", ty.i32()), Member("b", ty.f32())});
-  EXPECT_TRUE(r()->Resolve());
+    Structure("S", {Member("a", ty.i32()), Member("b", ty.f32())});
+    Structure("S1", {Member("a", ty.i32()), Member("b", ty.f32())});
+    EXPECT_TRUE(r()->Resolve());
 }
 
 TEST_F(ResolverValidationTest, NonPOTStructMemberAlignAttribute) {
-  Structure("S", {
-                     Member("a", ty.f32(), {MemberAlign(Source{{12, 34}}, 3)}),
-                 });
+    Structure("S", {
+                       Member("a", ty.f32(), {MemberAlign(Source{{12, 34}}, 3)}),
+                   });
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: align value must be a positive, power-of-two integer");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: align value must be a positive, power-of-two integer");
 }
 
 TEST_F(ResolverValidationTest, ZeroStructMemberAlignAttribute) {
-  Structure("S", {
-                     Member("a", ty.f32(), {MemberAlign(Source{{12, 34}}, 0)}),
-                 });
+    Structure("S", {
+                       Member("a", ty.f32(), {MemberAlign(Source{{12, 34}}, 0)}),
+                   });
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: align value must be a positive, power-of-two integer");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: align value must be a positive, power-of-two integer");
 }
 
 TEST_F(ResolverValidationTest, ZeroStructMemberSizeAttribute) {
-  Structure("S", {
-                     Member("a", ty.f32(), {MemberSize(Source{{12, 34}}, 0)}),
-                 });
+    Structure("S", {
+                       Member("a", ty.f32(), {MemberSize(Source{{12, 34}}, 0)}),
+                   });
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: size must be at least as big as the type's size (4)");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: size must be at least as big as the type's size (4)");
 }
 
 TEST_F(ResolverValidationTest, OffsetAndSizeAttribute) {
-  Structure("S", {
-                     Member(Source{{12, 34}}, "a", ty.f32(),
-                            {MemberOffset(0), MemberSize(4)}),
-                 });
+    Structure("S", {
+                       Member(Source{{12, 34}}, "a", ty.f32(), {MemberOffset(0), MemberSize(4)}),
+                   });
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: offset attributes cannot be used with align or size "
-            "attributes");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: offset attributes cannot be used with align or size "
+              "attributes");
 }
 
 TEST_F(ResolverValidationTest, OffsetAndAlignAttribute) {
-  Structure("S", {
-                     Member(Source{{12, 34}}, "a", ty.f32(),
-                            {MemberOffset(0), MemberAlign(4)}),
-                 });
+    Structure("S", {
+                       Member(Source{{12, 34}}, "a", ty.f32(), {MemberOffset(0), MemberAlign(4)}),
+                   });
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: offset attributes cannot be used with align or size "
-            "attributes");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: offset attributes cannot be used with align or size "
+              "attributes");
 }
 
 TEST_F(ResolverValidationTest, OffsetAndAlignAndSizeAttribute) {
-  Structure("S", {
-                     Member(Source{{12, 34}}, "a", ty.f32(),
-                            {MemberOffset(0), MemberAlign(4), MemberSize(4)}),
-                 });
+    Structure("S", {
+                       Member(Source{{12, 34}}, "a", ty.f32(),
+                              {MemberOffset(0), MemberAlign(4), MemberSize(4)}),
+                   });
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: offset attributes cannot be used with align or size "
-            "attributes");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: offset attributes cannot be used with align or size "
+              "attributes");
 }
 
 TEST_F(ResolverTest, Expr_Constructor_Cast_Pointer) {
-  auto* vf = Var("vf", ty.f32());
-  auto* c =
-      Construct(Source{{12, 34}}, ty.pointer<i32>(ast::StorageClass::kFunction),
-                ExprList(vf));
-  auto* ip = Const("ip", ty.pointer<i32>(ast::StorageClass::kFunction), c);
-  WrapInFunction(Decl(vf), Decl(ip));
+    auto* vf = Var("vf", ty.f32());
+    auto* c =
+        Construct(Source{{12, 34}}, ty.pointer<i32>(ast::StorageClass::kFunction), ExprList(vf));
+    auto* ip = Let("ip", ty.pointer<i32>(ast::StorageClass::kFunction), c);
+    WrapInFunction(Decl(vf), Decl(ip));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: type is not constructible");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: type is not constructible");
 }
 
 }  // namespace
diff --git a/src/tint/resolver/validator.cc b/src/tint/resolver/validator.cc
new file mode 100644
index 0000000..a97c2bd
--- /dev/null
+++ b/src/tint/resolver/validator.cc
@@ -0,0 +1,2371 @@
+// 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/resolver/validator.h"
+
+#include <algorithm>
+#include <limits>
+#include <utility>
+
+#include "src/tint/ast/alias.h"
+#include "src/tint/ast/array.h"
+#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/call_statement.h"
+#include "src/tint/ast/continue_statement.h"
+#include "src/tint/ast/depth_texture.h"
+#include "src/tint/ast/disable_validation_attribute.h"
+#include "src/tint/ast/discard_statement.h"
+#include "src/tint/ast/fallthrough_statement.h"
+#include "src/tint/ast/for_loop_statement.h"
+#include "src/tint/ast/id_attribute.h"
+#include "src/tint/ast/if_statement.h"
+#include "src/tint/ast/internal_attribute.h"
+#include "src/tint/ast/interpolate_attribute.h"
+#include "src/tint/ast/loop_statement.h"
+#include "src/tint/ast/matrix.h"
+#include "src/tint/ast/pointer.h"
+#include "src/tint/ast/return_statement.h"
+#include "src/tint/ast/sampled_texture.h"
+#include "src/tint/ast/sampler.h"
+#include "src/tint/ast/storage_texture.h"
+#include "src/tint/ast/switch_statement.h"
+#include "src/tint/ast/traverse_expressions.h"
+#include "src/tint/ast/type_name.h"
+#include "src/tint/ast/unary_op_expression.h"
+#include "src/tint/ast/variable_decl_statement.h"
+#include "src/tint/ast/vector.h"
+#include "src/tint/ast/workgroup_attribute.h"
+#include "src/tint/sem/array.h"
+#include "src/tint/sem/atomic.h"
+#include "src/tint/sem/call.h"
+#include "src/tint/sem/depth_multisampled_texture.h"
+#include "src/tint/sem/depth_texture.h"
+#include "src/tint/sem/for_loop_statement.h"
+#include "src/tint/sem/function.h"
+#include "src/tint/sem/if_statement.h"
+#include "src/tint/sem/loop_statement.h"
+#include "src/tint/sem/member_accessor_expression.h"
+#include "src/tint/sem/multisampled_texture.h"
+#include "src/tint/sem/pointer.h"
+#include "src/tint/sem/reference.h"
+#include "src/tint/sem/sampled_texture.h"
+#include "src/tint/sem/sampler.h"
+#include "src/tint/sem/statement.h"
+#include "src/tint/sem/storage_texture.h"
+#include "src/tint/sem/struct.h"
+#include "src/tint/sem/switch_statement.h"
+#include "src/tint/sem/type_constructor.h"
+#include "src/tint/sem/type_conversion.h"
+#include "src/tint/sem/variable.h"
+#include "src/tint/utils/defer.h"
+#include "src/tint/utils/map.h"
+#include "src/tint/utils/math.h"
+#include "src/tint/utils/reverse.h"
+#include "src/tint/utils/scoped_assignment.h"
+#include "src/tint/utils/transform.h"
+
+namespace tint::resolver {
+namespace {
+
+bool IsValidStorageTextureDimension(ast::TextureDimension dim) {
+    switch (dim) {
+        case ast::TextureDimension::k1d:
+        case ast::TextureDimension::k2d:
+        case ast::TextureDimension::k2dArray:
+        case ast::TextureDimension::k3d:
+            return true;
+        default:
+            return false;
+    }
+}
+
+bool IsValidStorageTextureTexelFormat(ast::TexelFormat format) {
+    switch (format) {
+        case ast::TexelFormat::kR32Uint:
+        case ast::TexelFormat::kR32Sint:
+        case ast::TexelFormat::kR32Float:
+        case ast::TexelFormat::kRg32Uint:
+        case ast::TexelFormat::kRg32Sint:
+        case ast::TexelFormat::kRg32Float:
+        case ast::TexelFormat::kRgba8Unorm:
+        case ast::TexelFormat::kRgba8Snorm:
+        case ast::TexelFormat::kRgba8Uint:
+        case ast::TexelFormat::kRgba8Sint:
+        case ast::TexelFormat::kRgba16Uint:
+        case ast::TexelFormat::kRgba16Sint:
+        case ast::TexelFormat::kRgba16Float:
+        case ast::TexelFormat::kRgba32Uint:
+        case ast::TexelFormat::kRgba32Sint:
+        case ast::TexelFormat::kRgba32Float:
+            return true;
+        default:
+            return false;
+    }
+}
+
+// Helper to stringify a pipeline IO attribute.
+std::string attr_to_str(const ast::Attribute* attr) {
+    std::stringstream str;
+    if (auto* builtin = attr->As<ast::BuiltinAttribute>()) {
+        str << "builtin(" << builtin->builtin << ")";
+    } else if (auto* location = attr->As<ast::LocationAttribute>()) {
+        str << "location(" << location->value << ")";
+    }
+    return str.str();
+}
+
+template <typename CALLBACK>
+void TraverseCallChain(diag::List& diagnostics,
+                       const sem::Function* from,
+                       const sem::Function* to,
+                       CALLBACK&& callback) {
+    for (auto* f : from->TransitivelyCalledFunctions()) {
+        if (f == to) {
+            callback(f);
+            return;
+        }
+        if (f->TransitivelyCalledFunctions().contains(to)) {
+            TraverseCallChain(diagnostics, f, to, callback);
+            callback(f);
+            return;
+        }
+    }
+    TINT_ICE(Resolver, diagnostics) << "TraverseCallChain() 'from' does not transitively call 'to'";
+}
+
+}  // namespace
+
+Validator::Validator(ProgramBuilder* builder, SemHelper& sem)
+    : symbols_(builder->Symbols()), diagnostics_(builder->Diagnostics()), sem_(sem) {}
+
+Validator::~Validator() = default;
+
+void Validator::AddError(const std::string& msg, const Source& source) const {
+    diagnostics_.add_error(diag::System::Resolver, msg, source);
+}
+
+void Validator::AddWarning(const std::string& msg, const Source& source) const {
+    diagnostics_.add_warning(diag::System::Resolver, msg, source);
+}
+
+void Validator::AddNote(const std::string& msg, const Source& source) const {
+    diagnostics_.add_note(diag::System::Resolver, msg, source);
+}
+
+// https://gpuweb.github.io/gpuweb/wgsl/#plain-types-section
+bool Validator::IsPlain(const sem::Type* type) const {
+    return type->is_scalar() ||
+           type->IsAnyOf<sem::Atomic, sem::Vector, sem::Matrix, sem::Array, sem::Struct>();
+}
+
+// https://gpuweb.github.io/gpuweb/wgsl/#fixed-footprint-types
+bool Validator::IsFixedFootprint(const sem::Type* type) const {
+    return Switch(
+        type,                                      //
+        [&](const sem::Vector*) { return true; },  //
+        [&](const sem::Matrix*) { return true; },  //
+        [&](const sem::Atomic*) { return true; },
+        [&](const sem::Array* arr) {
+            return !arr->IsRuntimeSized() && IsFixedFootprint(arr->ElemType());
+        },
+        [&](const sem::Struct* str) {
+            for (auto* member : str->Members()) {
+                if (!IsFixedFootprint(member->Type())) {
+                    return false;
+                }
+            }
+            return true;
+        },
+        [&](Default) { return type->is_scalar(); });
+}
+
+// https://gpuweb.github.io/gpuweb/wgsl.html#host-shareable-types
+bool Validator::IsHostShareable(const sem::Type* type) const {
+    if (type->IsAnyOf<sem::I32, sem::U32, sem::F32>()) {
+        return true;
+    }
+    return Switch(
+        type,  //
+        [&](const sem::Vector* vec) { return IsHostShareable(vec->type()); },
+        [&](const sem::Matrix* mat) { return IsHostShareable(mat->type()); },
+        [&](const sem::Array* arr) { return IsHostShareable(arr->ElemType()); },
+        [&](const sem::Struct* str) {
+            for (auto* member : str->Members()) {
+                if (!IsHostShareable(member->Type())) {
+                    return false;
+                }
+            }
+            return true;
+        },
+        [&](const sem::Atomic* atomic) { return IsHostShareable(atomic->Type()); });
+}
+
+// https://gpuweb.github.io/gpuweb/wgsl.html#storable-types
+bool Validator::IsStorable(const sem::Type* type) const {
+    return IsPlain(type) || type->IsAnyOf<sem::Texture, sem::Sampler>();
+}
+
+const ast::Statement* Validator::ClosestContinuing(bool stop_at_loop,
+                                                   sem::Statement* current_statement) const {
+    for (const auto* s = current_statement; s != nullptr; s = s->Parent()) {
+        if (stop_at_loop && s->Is<sem::LoopStatement>()) {
+            break;
+        }
+        if (s->Is<sem::LoopContinuingBlockStatement>()) {
+            return s->Declaration();
+        }
+        if (auto* f = As<sem::ForLoopStatement>(s->Parent())) {
+            if (f->Declaration()->continuing == s->Declaration()) {
+                return s->Declaration();
+            }
+            if (stop_at_loop) {
+                break;
+            }
+        }
+    }
+    return nullptr;
+}
+
+bool Validator::Atomic(const ast::Atomic* a, const sem::Atomic* s) const {
+    // https://gpuweb.github.io/gpuweb/wgsl/#atomic-types
+    // T must be either u32 or i32.
+    if (!s->Type()->IsAnyOf<sem::U32, sem::I32>()) {
+        AddError("atomic only supports i32 or u32 types", a->type ? a->type->source : a->source);
+        return false;
+    }
+    return true;
+}
+
+bool Validator::StorageTexture(const ast::StorageTexture* t) const {
+    switch (t->access) {
+        case ast::Access::kWrite:
+            break;
+        case ast::Access::kUndefined:
+            AddError("storage texture missing access control", t->source);
+            return false;
+        default:
+            AddError("storage textures currently only support 'write' access control", t->source);
+            return false;
+    }
+
+    if (!IsValidStorageTextureDimension(t->dim)) {
+        AddError("cube dimensions for storage textures are not supported", t->source);
+        return false;
+    }
+
+    if (!IsValidStorageTextureTexelFormat(t->format)) {
+        AddError(
+            "image format must be one of the texel formats specified for storage "
+            "textues in https://gpuweb.github.io/gpuweb/wgsl/#texel-formats",
+            t->source);
+        return false;
+    }
+    return true;
+}
+
+bool Validator::VariableConstructorOrCast(const ast::Variable* var,
+                                          ast::StorageClass storage_class,
+                                          const sem::Type* storage_ty,
+                                          const sem::Type* rhs_ty) const {
+    auto* value_type = rhs_ty->UnwrapRef();  // Implicit load of RHS
+
+    // Value type has to match storage type
+    if (storage_ty != value_type) {
+        std::string decl = var->is_const ? "let" : "var";
+        AddError("cannot initialize " + decl + " of type '" + sem_.TypeNameOf(storage_ty) +
+                     "' with value of type '" + sem_.TypeNameOf(rhs_ty) + "'",
+                 var->source);
+        return false;
+    }
+
+    if (!var->is_const) {
+        switch (storage_class) {
+            case ast::StorageClass::kPrivate:
+            case ast::StorageClass::kFunction:
+                break;  // Allowed an initializer
+            default:
+                // https://gpuweb.github.io/gpuweb/wgsl/#var-and-let
+                // Optionally has an initializer expression, if the variable is in the
+                // private or function storage classes.
+                AddError("var of storage class '" + std::string(ast::ToString(storage_class)) +
+                             "' cannot have an initializer. var initializers are only "
+                             "supported for the storage classes "
+                             "'private' and 'function'",
+                         var->source);
+                return false;
+        }
+    }
+
+    return true;
+}
+
+bool Validator::StorageClassLayout(const sem::Type* store_ty,
+                                   ast::StorageClass sc,
+                                   Source source,
+                                   ValidTypeStorageLayouts& layouts) const {
+    // https://gpuweb.github.io/gpuweb/wgsl/#storage-class-layout-constraints
+
+    auto is_uniform_struct_or_array = [sc](const sem::Type* ty) {
+        return sc == ast::StorageClass::kUniform && ty->IsAnyOf<sem::Array, sem::Struct>();
+    };
+
+    auto is_uniform_struct = [sc](const sem::Type* ty) {
+        return sc == ast::StorageClass::kUniform && ty->Is<sem::Struct>();
+    };
+
+    auto required_alignment_of = [&](const sem::Type* ty) {
+        uint32_t actual_align = ty->Align();
+        uint32_t required_align = actual_align;
+        if (is_uniform_struct_or_array(ty)) {
+            required_align = utils::RoundUp(16u, actual_align);
+        }
+        return required_align;
+    };
+
+    auto member_name_of = [this](const sem::StructMember* sm) {
+        return symbols_.NameFor(sm->Declaration()->symbol);
+    };
+
+    // Cache result of type + storage class pair.
+    if (!layouts.emplace(store_ty, sc).second) {
+        return true;
+    }
+
+    if (!ast::IsHostShareable(sc)) {
+        return true;
+    }
+
+    if (auto* str = store_ty->As<sem::Struct>()) {
+        for (size_t i = 0; i < str->Members().size(); ++i) {
+            auto* const m = str->Members()[i];
+            uint32_t required_align = required_alignment_of(m->Type());
+
+            // Recurse into the member type.
+            if (!StorageClassLayout(m->Type(), sc, m->Declaration()->type->source, layouts)) {
+                AddNote("see layout of struct:\n" + str->Layout(symbols_),
+                        str->Declaration()->source);
+                return false;
+            }
+
+            // Validate that member is at a valid byte offset
+            if (m->Offset() % required_align != 0) {
+                AddError("the offset of a struct member of type '" +
+                             m->Type()->UnwrapRef()->FriendlyName(symbols_) +
+                             "' in storage class '" + ast::ToString(sc) +
+                             "' must be a multiple of " + std::to_string(required_align) +
+                             " bytes, but '" + member_name_of(m) + "' is currently at offset " +
+                             std::to_string(m->Offset()) + ". Consider setting @align(" +
+                             std::to_string(required_align) + ") on this member",
+                         m->Declaration()->source);
+
+                AddNote("see layout of struct:\n" + str->Layout(symbols_),
+                        str->Declaration()->source);
+
+                if (auto* member_str = m->Type()->As<sem::Struct>()) {
+                    AddNote("and layout of struct member:\n" + member_str->Layout(symbols_),
+                            member_str->Declaration()->source);
+                }
+
+                return false;
+            }
+
+            // For uniform buffers, validate that the number of bytes between the
+            // previous member of type struct and the current is a multiple of 16
+            // bytes.
+            auto* const prev_member = (i == 0) ? nullptr : str->Members()[i - 1];
+            if (prev_member && is_uniform_struct(prev_member->Type())) {
+                const uint32_t prev_to_curr_offset = m->Offset() - prev_member->Offset();
+                if (prev_to_curr_offset % 16 != 0) {
+                    AddError(
+                        "uniform storage requires that the number of bytes between the "
+                        "start of the previous member of type struct and the current "
+                        "member be a multiple of 16 bytes, but there are currently " +
+                            std::to_string(prev_to_curr_offset) + " bytes between '" +
+                            member_name_of(prev_member) + "' and '" + member_name_of(m) +
+                            "'. Consider setting @align(16) on this member",
+                        m->Declaration()->source);
+
+                    AddNote("see layout of struct:\n" + str->Layout(symbols_),
+                            str->Declaration()->source);
+
+                    auto* prev_member_str = prev_member->Type()->As<sem::Struct>();
+                    AddNote("and layout of previous member struct:\n" +
+                                prev_member_str->Layout(symbols_),
+                            prev_member_str->Declaration()->source);
+                    return false;
+                }
+            }
+        }
+    }
+
+    // For uniform buffer array members, validate that array elements are
+    // aligned to 16 bytes
+    if (auto* arr = store_ty->As<sem::Array>()) {
+        // Recurse into the element type.
+        // TODO(crbug.com/tint/1388): Ideally we'd pass the source for nested
+        // element type here, but we can't easily get that from the semantic node.
+        // We should consider recursing through the AST type nodes instead.
+        if (!StorageClassLayout(arr->ElemType(), sc, source, layouts)) {
+            return false;
+        }
+
+        if (sc == ast::StorageClass::kUniform) {
+            // We already validated that this array member is itself aligned to 16
+            // bytes above, so we only need to validate that stride is a multiple
+            // of 16 bytes.
+            if (arr->Stride() % 16 != 0) {
+                // Since WGSL has no stride attribute, try to provide a useful hint
+                // for how the shader author can resolve the issue.
+                std::string hint;
+                if (arr->ElemType()->is_scalar()) {
+                    hint =
+                        "Consider using a vector or struct as the element type "
+                        "instead.";
+                } else if (auto* vec = arr->ElemType()->As<sem::Vector>();
+                           vec && vec->type()->Size() == 4) {
+                    hint = "Consider using a vec4 instead.";
+                } else if (arr->ElemType()->Is<sem::Struct>()) {
+                    hint =
+                        "Consider using the @size attribute on the last struct "
+                        "member.";
+                } else {
+                    hint =
+                        "Consider wrapping the element type in a struct and using "
+                        "the "
+                        "@size attribute.";
+                }
+                AddError(
+                    "uniform storage requires that array elements be aligned to 16 "
+                    "bytes, but array element alignment is currently " +
+                        std::to_string(arr->Stride()) + ". " + hint,
+                    source);
+                return false;
+            }
+        }
+    }
+
+    return true;
+}
+
+bool Validator::StorageClassLayout(const sem::Variable* var,
+                                   ValidTypeStorageLayouts& layouts) const {
+    if (auto* str = var->Type()->UnwrapRef()->As<sem::Struct>()) {
+        if (!StorageClassLayout(str, var->StorageClass(), str->Declaration()->source, layouts)) {
+            AddNote("see declaration of variable", var->Declaration()->source);
+            return false;
+        }
+    } else {
+        Source source = var->Declaration()->source;
+        if (var->Declaration()->type) {
+            source = var->Declaration()->type->source;
+        }
+        if (!StorageClassLayout(var->Type()->UnwrapRef(), var->StorageClass(), source, layouts)) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+bool Validator::GlobalVariable(
+    const sem::Variable* var,
+    std::unordered_map<uint32_t, const sem::Variable*> constant_ids,
+    std::unordered_map<const sem::Type*, const Source&> atomic_composite_info) const {
+    auto* decl = var->Declaration();
+    if (!NoDuplicateAttributes(decl->attributes)) {
+        return false;
+    }
+
+    for (auto* attr : decl->attributes) {
+        if (decl->is_const) {
+            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 != var) {
+                    AddError("pipeline constant IDs must be unique", attr->source);
+                    AddNote(
+                        "a pipeline constant 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 constants", attr->source);
+                return false;
+            }
+        } else {
+            bool is_shader_io_attribute =
+                attr->IsAnyOf<ast::BuiltinAttribute, ast::InterpolateAttribute,
+                              ast::InvariantAttribute, ast::LocationAttribute>();
+            bool has_io_storage_class = var->StorageClass() == ast::StorageClass::kInput ||
+                                        var->StorageClass() == ast::StorageClass::kOutput;
+            if (!(attr->IsAnyOf<ast::BindingAttribute, ast::GroupAttribute,
+                                ast::InternalAttribute>()) &&
+                (!is_shader_io_attribute || !has_io_storage_class)) {
+                AddError("attribute is not valid for variables", attr->source);
+                return false;
+            }
+        }
+    }
+
+    if (var->StorageClass() == ast::StorageClass::kFunction) {
+        AddError(
+            "variables declared at module scope must not be in the function "
+            "storage class",
+            decl->source);
+        return false;
+    }
+
+    auto binding_point = decl->BindingPoint();
+    switch (var->StorageClass()) {
+        case ast::StorageClass::kUniform:
+        case ast::StorageClass::kStorage:
+        case ast::StorageClass::kHandle: {
+            // https://gpuweb.github.io/gpuweb/wgsl/#resource-interface
+            // Each resource variable must be declared with both group and binding
+            // attributes.
+            if (!binding_point) {
+                AddError(
+                    "resource variables require @group and @binding "
+                    "attributes",
+                    decl->source);
+                return false;
+            }
+            break;
+        }
+        default:
+            if (binding_point.binding || binding_point.group) {
+                // https://gpuweb.github.io/gpuweb/wgsl/#attribute-binding
+                // Must only be applied to a resource variable
+                AddError(
+                    "non-resource variables must not have @group or @binding "
+                    "attributes",
+                    decl->source);
+                return false;
+            }
+    }
+
+    // https://gpuweb.github.io/gpuweb/wgsl/#variable-declaration
+    // The access mode always has a default, and except for variables in the
+    // storage storage class, must not be written.
+    if (var->StorageClass() != ast::StorageClass::kStorage &&
+        decl->declared_access != ast::Access::kUndefined) {
+        AddError("only variables in <storage> storage class may declare an access mode",
+                 decl->source);
+        return false;
+    }
+
+    if (!decl->is_const) {
+        if (!AtomicVariable(var, atomic_composite_info)) {
+            return false;
+        }
+    }
+
+    return Variable(var);
+}
+
+// https://gpuweb.github.io/gpuweb/wgsl/#atomic-types
+// Atomic types may only be instantiated by variables in the workgroup storage
+// class or by storage buffer variables with a read_write access mode.
+bool Validator::AtomicVariable(
+    const sem::Variable* var,
+    std::unordered_map<const sem::Type*, const Source&> atomic_composite_info) const {
+    auto sc = var->StorageClass();
+    auto* decl = var->Declaration();
+    auto access = var->Access();
+    auto* type = var->Type()->UnwrapRef();
+    auto source = decl->type ? decl->type->source : decl->source;
+
+    if (type->Is<sem::Atomic>()) {
+        if (sc != ast::StorageClass::kWorkgroup && sc != ast::StorageClass::kStorage) {
+            AddError("atomic variables must have <storage> or <workgroup> storage class", source);
+            return false;
+        }
+    } else if (type->IsAnyOf<sem::Struct, sem::Array>()) {
+        auto found = atomic_composite_info.find(type);
+        if (found != atomic_composite_info.end()) {
+            if (sc != ast::StorageClass::kStorage && sc != ast::StorageClass::kWorkgroup) {
+                AddError("atomic variables must have <storage> or <workgroup> storage class",
+                         source);
+                AddNote("atomic sub-type of '" + sem_.TypeNameOf(type) + "' is declared here",
+                        found->second);
+                return false;
+            } else if (sc == ast::StorageClass::kStorage && access != ast::Access::kReadWrite) {
+                AddError(
+                    "atomic variables in <storage> storage class must have read_write "
+                    "access mode",
+                    source);
+                AddNote("atomic sub-type of '" + sem_.TypeNameOf(type) + "' is declared here",
+                        found->second);
+                return false;
+            }
+        }
+    }
+
+    return true;
+}
+
+bool Validator::Variable(const sem::Variable* var) const {
+    auto* decl = var->Declaration();
+    auto* storage_ty = var->Type()->UnwrapRef();
+
+    if (var->Is<sem::GlobalVariable>()) {
+        auto name = symbols_.NameFor(decl->symbol);
+        if (sem::ParseBuiltinType(name) != sem::BuiltinType::kNone) {
+            auto* kind = var->Declaration()->is_const ? "let" : "var";
+            AddError(
+                "'" + name + "' is a builtin and cannot be redeclared as a module-scope " + kind,
+                decl->source);
+            return false;
+        }
+    }
+
+    if (!decl->is_const && !IsStorable(storage_ty)) {
+        AddError(sem_.TypeNameOf(storage_ty) + " cannot be used as the type of a var",
+                 decl->source);
+        return false;
+    }
+
+    if (decl->is_const && !var->Is<sem::Parameter>() &&
+        !(storage_ty->IsConstructible() || storage_ty->Is<sem::Pointer>())) {
+        AddError(sem_.TypeNameOf(storage_ty) + " cannot be used as the type of a let",
+                 decl->source);
+        return false;
+    }
+
+    if (auto* r = storage_ty->As<sem::MultisampledTexture>()) {
+        if (r->dim() != ast::TextureDimension::k2d) {
+            AddError("only 2d multisampled textures are supported", decl->source);
+            return false;
+        }
+
+        if (!r->type()->UnwrapRef()->is_numeric_scalar()) {
+            AddError("texture_multisampled_2d<type>: type must be f32, i32 or u32", decl->source);
+            return false;
+        }
+    }
+
+    if (var->Is<sem::LocalVariable>() && !decl->is_const &&
+        IsValidationEnabled(decl->attributes, ast::DisabledValidation::kIgnoreStorageClass)) {
+        if (!var->Type()->UnwrapRef()->IsConstructible()) {
+            AddError("function variable must have a constructible type",
+                     decl->type ? decl->type->source : decl->source);
+            return false;
+        }
+    }
+
+    if (storage_ty->is_handle() && decl->declared_storage_class != ast::StorageClass::kNone) {
+        // https://gpuweb.github.io/gpuweb/wgsl/#module-scope-variables
+        // If the store type is a texture type or a sampler type, then the
+        // variable declaration must not have a storage class attribute. The
+        // storage class will always be handle.
+        AddError(
+            "variables of type '" + sem_.TypeNameOf(storage_ty) + "' must not have a storage class",
+            decl->source);
+        return false;
+    }
+
+    if (IsValidationEnabled(decl->attributes, ast::DisabledValidation::kIgnoreStorageClass) &&
+        (decl->declared_storage_class == ast::StorageClass::kInput ||
+         decl->declared_storage_class == ast::StorageClass::kOutput)) {
+        AddError("invalid use of input/output storage class", decl->source);
+        return false;
+    }
+    return true;
+}
+
+bool Validator::FunctionParameter(const ast::Function* func, const sem::Variable* var) const {
+    if (!Variable(var)) {
+        return false;
+    }
+
+    auto* decl = var->Declaration();
+
+    for (auto* attr : decl->attributes) {
+        if (!func->IsEntryPoint() && !attr->Is<ast::InternalAttribute>()) {
+            AddError("attribute is not valid for non-entry point function parameters",
+                     attr->source);
+            return false;
+        } else if (!attr->IsAnyOf<ast::BuiltinAttribute, ast::InvariantAttribute,
+                                  ast::LocationAttribute, ast::InterpolateAttribute,
+                                  ast::InternalAttribute>() &&
+                   (IsValidationEnabled(decl->attributes,
+                                        ast::DisabledValidation::kEntryPointParameter) &&
+                    IsValidationEnabled(
+                        decl->attributes,
+                        ast::DisabledValidation::kIgnoreConstructibleFunctionParameter))) {
+            AddError("attribute is not valid for function parameters", attr->source);
+            return false;
+        }
+    }
+
+    if (auto* ref = var->Type()->As<sem::Pointer>()) {
+        auto sc = ref->StorageClass();
+        if (!(sc == ast::StorageClass::kFunction || sc == ast::StorageClass::kPrivate ||
+              sc == ast::StorageClass::kWorkgroup) &&
+            IsValidationEnabled(decl->attributes, ast::DisabledValidation::kIgnoreStorageClass)) {
+            std::stringstream ss;
+            ss << "function parameter of pointer type cannot be in '" << sc << "' storage class";
+            AddError(ss.str(), decl->source);
+            return false;
+        }
+    }
+
+    if (IsPlain(var->Type())) {
+        if (!var->Type()->IsConstructible() &&
+            IsValidationEnabled(decl->attributes,
+                                ast::DisabledValidation::kIgnoreConstructibleFunctionParameter)) {
+            AddError("store type of function parameter must be a constructible type", decl->source);
+            return false;
+        }
+    } else if (!var->Type()->IsAnyOf<sem::Texture, sem::Sampler, sem::Pointer>()) {
+        AddError("store type of function parameter cannot be " + sem_.TypeNameOf(var->Type()),
+                 decl->source);
+        return false;
+    }
+
+    return true;
+}
+
+bool Validator::BuiltinAttribute(const ast::BuiltinAttribute* attr,
+                                 const sem::Type* storage_ty,
+                                 ast::PipelineStage stage,
+                                 const bool is_input) const {
+    auto* type = storage_ty->UnwrapRef();
+    std::stringstream stage_name;
+    stage_name << stage;
+    bool is_stage_mismatch = false;
+    bool is_output = !is_input;
+    switch (attr->builtin) {
+        case ast::Builtin::kPosition:
+            if (stage != ast::PipelineStage::kNone &&
+                !((is_input && stage == ast::PipelineStage::kFragment) ||
+                  (is_output && stage == ast::PipelineStage::kVertex))) {
+                is_stage_mismatch = true;
+            }
+            if (!(type->is_float_vector() && type->As<sem::Vector>()->Width() == 4)) {
+                AddError("store type of " + attr_to_str(attr) + " must be 'vec4<f32>'",
+                         attr->source);
+                return false;
+            }
+            break;
+        case ast::Builtin::kGlobalInvocationId:
+        case ast::Builtin::kLocalInvocationId:
+        case ast::Builtin::kNumWorkgroups:
+        case ast::Builtin::kWorkgroupId:
+            if (stage != ast::PipelineStage::kNone &&
+                !(stage == ast::PipelineStage::kCompute && is_input)) {
+                is_stage_mismatch = true;
+            }
+            if (!(type->is_unsigned_integer_vector() && type->As<sem::Vector>()->Width() == 3)) {
+                AddError("store type of " + attr_to_str(attr) + " must be 'vec3<u32>'",
+                         attr->source);
+                return false;
+            }
+            break;
+        case ast::Builtin::kFragDepth:
+            if (stage != ast::PipelineStage::kNone &&
+                !(stage == ast::PipelineStage::kFragment && !is_input)) {
+                is_stage_mismatch = true;
+            }
+            if (!type->Is<sem::F32>()) {
+                AddError("store type of " + attr_to_str(attr) + " must be 'f32'", attr->source);
+                return false;
+            }
+            break;
+        case ast::Builtin::kFrontFacing:
+            if (stage != ast::PipelineStage::kNone &&
+                !(stage == ast::PipelineStage::kFragment && is_input)) {
+                is_stage_mismatch = true;
+            }
+            if (!type->Is<sem::Bool>()) {
+                AddError("store type of " + attr_to_str(attr) + " must be 'bool'", attr->source);
+                return false;
+            }
+            break;
+        case ast::Builtin::kLocalInvocationIndex:
+            if (stage != ast::PipelineStage::kNone &&
+                !(stage == ast::PipelineStage::kCompute && is_input)) {
+                is_stage_mismatch = true;
+            }
+            if (!type->Is<sem::U32>()) {
+                AddError("store type of " + attr_to_str(attr) + " must be 'u32'", attr->source);
+                return false;
+            }
+            break;
+        case ast::Builtin::kVertexIndex:
+        case ast::Builtin::kInstanceIndex:
+            if (stage != ast::PipelineStage::kNone &&
+                !(stage == ast::PipelineStage::kVertex && is_input)) {
+                is_stage_mismatch = true;
+            }
+            if (!type->Is<sem::U32>()) {
+                AddError("store type of " + attr_to_str(attr) + " must be 'u32'", attr->source);
+                return false;
+            }
+            break;
+        case ast::Builtin::kSampleMask:
+            if (stage != ast::PipelineStage::kNone && !(stage == ast::PipelineStage::kFragment)) {
+                is_stage_mismatch = true;
+            }
+            if (!type->Is<sem::U32>()) {
+                AddError("store type of " + attr_to_str(attr) + " must be 'u32'", attr->source);
+                return false;
+            }
+            break;
+        case ast::Builtin::kSampleIndex:
+            if (stage != ast::PipelineStage::kNone &&
+                !(stage == ast::PipelineStage::kFragment && is_input)) {
+                is_stage_mismatch = true;
+            }
+            if (!type->Is<sem::U32>()) {
+                AddError("store type of " + attr_to_str(attr) + " must be 'u32'", attr->source);
+                return false;
+            }
+            break;
+        default:
+            break;
+    }
+
+    if (is_stage_mismatch) {
+        AddError(attr_to_str(attr) + " cannot be used in " +
+                     (is_input ? "input of " : "output of ") + stage_name.str() + " pipeline stage",
+                 attr->source);
+        return false;
+    }
+
+    return true;
+}
+
+bool Validator::InterpolateAttribute(const ast::InterpolateAttribute* attr,
+                                     const sem::Type* storage_ty) const {
+    auto* type = storage_ty->UnwrapRef();
+
+    if (type->is_integer_scalar_or_vector() && attr->type != ast::InterpolationType::kFlat) {
+        AddError("interpolation type must be 'flat' for integral user-defined IO types",
+                 attr->source);
+        return false;
+    }
+
+    if (attr->type == ast::InterpolationType::kFlat &&
+        attr->sampling != ast::InterpolationSampling::kNone) {
+        AddError("flat interpolation attribute must not have a sampling parameter", attr->source);
+        return false;
+    }
+
+    return true;
+}
+
+bool Validator::Function(const sem::Function* func, ast::PipelineStage stage) const {
+    auto* decl = func->Declaration();
+
+    auto name = symbols_.NameFor(decl->symbol);
+    if (sem::ParseBuiltinType(name) != sem::BuiltinType::kNone) {
+        AddError("'" + name + "' is a builtin and cannot be redeclared as a function",
+                 decl->source);
+        return false;
+    }
+
+    for (auto* attr : decl->attributes) {
+        if (attr->Is<ast::WorkgroupAttribute>()) {
+            if (decl->PipelineStage() != ast::PipelineStage::kCompute) {
+                AddError("the workgroup_size attribute is only valid for compute stages",
+                         attr->source);
+                return false;
+            }
+        } else if (!attr->IsAnyOf<ast::StageAttribute, ast::InternalAttribute>()) {
+            AddError("attribute is not valid for functions", attr->source);
+            return false;
+        }
+    }
+
+    if (decl->params.size() > 255) {
+        AddError("functions may declare at most 255 parameters", decl->source);
+        return false;
+    }
+
+    for (size_t i = 0; i < decl->params.size(); i++) {
+        if (!FunctionParameter(decl, func->Parameters()[i])) {
+            return false;
+        }
+    }
+
+    if (!func->ReturnType()->Is<sem::Void>()) {
+        if (!func->ReturnType()->IsConstructible()) {
+            AddError("function return type must be a constructible type",
+                     decl->return_type->source);
+            return false;
+        }
+
+        if (decl->body) {
+            sem::Behaviors behaviors{sem::Behavior::kNext};
+            if (auto* last = decl->body->Last()) {
+                behaviors = sem_.Get(last)->Behaviors();
+            }
+            if (behaviors.Contains(sem::Behavior::kNext)) {
+                AddError("missing return at end of function", decl->source);
+                return false;
+            }
+        } else if (IsValidationEnabled(decl->attributes,
+                                       ast::DisabledValidation::kFunctionHasNoBody)) {
+            TINT_ICE(Resolver, diagnostics_)
+                << "Function " << symbols_.NameFor(decl->symbol) << " has no body";
+        }
+
+        for (auto* attr : decl->return_type_attributes) {
+            if (!decl->IsEntryPoint()) {
+                AddError("attribute is not valid for non-entry point function return types",
+                         attr->source);
+                return false;
+            }
+            if (!attr->IsAnyOf<ast::BuiltinAttribute, ast::InternalAttribute,
+                               ast::LocationAttribute, ast::InterpolateAttribute,
+                               ast::InvariantAttribute>() &&
+                (IsValidationEnabled(decl->attributes,
+                                     ast::DisabledValidation::kEntryPointParameter) &&
+                 IsValidationEnabled(
+                     decl->attributes,
+                     ast::DisabledValidation::kIgnoreConstructibleFunctionParameter))) {
+                AddError("attribute is not valid for entry point return types", attr->source);
+                return false;
+            }
+        }
+    }
+
+    if (decl->IsEntryPoint()) {
+        if (!EntryPoint(func, stage)) {
+            return false;
+        }
+    }
+
+    // https://www.w3.org/TR/WGSL/#behaviors-rules
+    // a function behavior is always one of {}, {Next}, {Discard}, or
+    // {Next, Discard}.
+    if (func->Behaviors() != sem::Behaviors{} &&  // NOLINT: bad warning
+        func->Behaviors() != sem::Behavior::kNext && func->Behaviors() != sem::Behavior::kDiscard &&
+        func->Behaviors() != sem::Behaviors{sem::Behavior::kNext,  //
+                                            sem::Behavior::kDiscard}) {
+        TINT_ICE(Resolver, diagnostics_)
+            << "function '" << name << "' behaviors are: " << func->Behaviors();
+    }
+
+    return true;
+}
+
+bool Validator::EntryPoint(const sem::Function* func, ast::PipelineStage stage) const {
+    auto* decl = func->Declaration();
+
+    // Use a lambda to validate the entry point attributes for a type.
+    // Persistent state is used to track which builtins and locations have
+    // 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<uint32_t> locations;
+    enum class ParamOrRetType {
+        kParameter,
+        kReturnType,
+    };
+
+    // Inner lambda that is applied to a type and all of its members.
+    auto validate_entry_point_attributes_inner = [&](const ast::AttributeList& attrs,
+                                                     const sem::Type* ty, Source source,
+                                                     ParamOrRetType param_or_ret,
+                                                     bool is_struct_member) {
+        // Scan attributes for pipeline IO attributes.
+        // Check for overlap with attributes that have been seen previously.
+        const ast::Attribute* pipeline_io_attribute = nullptr;
+        const ast::InterpolateAttribute* interpolate_attribute = nullptr;
+        const ast::InvariantAttribute* invariant_attribute = nullptr;
+        for (auto* attr : attrs) {
+            auto is_invalid_compute_shader_attribute = false;
+
+            if (auto* builtin = attr->As<ast::BuiltinAttribute>()) {
+                if (pipeline_io_attribute) {
+                    AddError("multiple entry point IO attributes", attr->source);
+                    AddNote("previously consumed " + attr_to_str(pipeline_io_attribute),
+                            pipeline_io_attribute->source);
+                    return false;
+                }
+                pipeline_io_attribute = attr;
+
+                if (builtins.count(builtin->builtin)) {
+                    AddError(attr_to_str(builtin) +
+                                 " attribute appears multiple times as pipeline " +
+                                 (param_or_ret == ParamOrRetType::kParameter ? "input" : "output"),
+                             decl->source);
+                    return false;
+                }
+
+                if (!BuiltinAttribute(builtin, ty, stage,
+                                      /* is_input */ param_or_ret == ParamOrRetType::kParameter)) {
+                    return false;
+                }
+                builtins.emplace(builtin->builtin);
+            } else if (auto* location = attr->As<ast::LocationAttribute>()) {
+                if (pipeline_io_attribute) {
+                    AddError("multiple entry point IO attributes", attr->source);
+                    AddNote("previously consumed " + attr_to_str(pipeline_io_attribute),
+                            pipeline_io_attribute->source);
+                    return false;
+                }
+                pipeline_io_attribute = attr;
+
+                bool is_input = param_or_ret == ParamOrRetType::kParameter;
+
+                if (!LocationAttribute(location, ty, locations, stage, source, is_input)) {
+                    return false;
+                }
+            } else if (auto* interpolate = attr->As<ast::InterpolateAttribute>()) {
+                if (decl->PipelineStage() == ast::PipelineStage::kCompute) {
+                    is_invalid_compute_shader_attribute = true;
+                } else if (!InterpolateAttribute(interpolate, ty)) {
+                    return false;
+                }
+                interpolate_attribute = interpolate;
+            } else if (auto* invariant = attr->As<ast::InvariantAttribute>()) {
+                if (decl->PipelineStage() == ast::PipelineStage::kCompute) {
+                    is_invalid_compute_shader_attribute = true;
+                }
+                invariant_attribute = invariant;
+            }
+            if (is_invalid_compute_shader_attribute) {
+                std::string input_or_output =
+                    param_or_ret == ParamOrRetType::kParameter ? "inputs" : "output";
+                AddError("attribute is not valid for compute shader " + input_or_output,
+                         attr->source);
+                return false;
+            }
+        }
+
+        if (IsValidationEnabled(attrs, ast::DisabledValidation::kEntryPointParameter)) {
+            if (is_struct_member && ty->Is<sem::Struct>()) {
+                AddError("nested structures cannot be used for entry point IO", source);
+                return false;
+            }
+
+            if (!ty->Is<sem::Struct>() && !pipeline_io_attribute) {
+                std::string err = "missing entry point IO attribute";
+                if (!is_struct_member) {
+                    err += (param_or_ret == ParamOrRetType::kParameter ? " on parameter"
+                                                                       : " on return type");
+                }
+                AddError(err, source);
+                return false;
+            }
+
+            if (pipeline_io_attribute && pipeline_io_attribute->Is<ast::LocationAttribute>()) {
+                if (ty->is_integer_scalar_or_vector() && !interpolate_attribute) {
+                    if (decl->PipelineStage() == ast::PipelineStage::kVertex &&
+                        param_or_ret == ParamOrRetType::kReturnType) {
+                        AddError(
+                            "integral user-defined vertex outputs must have a flat "
+                            "interpolation attribute",
+                            source);
+                        return false;
+                    }
+                    if (decl->PipelineStage() == ast::PipelineStage::kFragment &&
+                        param_or_ret == ParamOrRetType::kParameter) {
+                        AddError(
+                            "integral user-defined fragment inputs must have a flat "
+                            "interpolation attribute",
+                            source);
+                        return false;
+                    }
+                }
+            }
+
+            if (interpolate_attribute) {
+                if (!pipeline_io_attribute ||
+                    !pipeline_io_attribute->Is<ast::LocationAttribute>()) {
+                    AddError("interpolate attribute must only be used with @location",
+                             interpolate_attribute->source);
+                    return false;
+                }
+            }
+
+            if (invariant_attribute) {
+                bool has_position = false;
+                if (pipeline_io_attribute) {
+                    if (auto* builtin = pipeline_io_attribute->As<ast::BuiltinAttribute>()) {
+                        has_position = (builtin->builtin == ast::Builtin::kPosition);
+                    }
+                }
+                if (!has_position) {
+                    AddError(
+                        "invariant attribute must only be applied to a position "
+                        "builtin",
+                        invariant_attribute->source);
+                    return false;
+                }
+            }
+        }
+        return true;
+    };
+
+    // Outer lambda for validating the entry point attributes for a type.
+    auto validate_entry_point_attributes = [&](const ast::AttributeList& attrs, const sem::Type* ty,
+                                               Source source, ParamOrRetType param_or_ret) {
+        if (!validate_entry_point_attributes_inner(attrs, ty, source, param_or_ret,
+                                                   /*is_struct_member*/ false)) {
+            return false;
+        }
+
+        if (auto* str = ty->As<sem::Struct>()) {
+            for (auto* member : str->Members()) {
+                if (!validate_entry_point_attributes_inner(
+                        member->Declaration()->attributes, member->Type(),
+                        member->Declaration()->source, param_or_ret,
+                        /*is_struct_member*/ true)) {
+                    AddNote("while analysing entry point '" + symbols_.NameFor(decl->symbol) + "'",
+                            decl->source);
+                    return false;
+                }
+            }
+        }
+
+        return true;
+    };
+
+    for (auto* param : func->Parameters()) {
+        auto* param_decl = param->Declaration();
+        if (!validate_entry_point_attributes(param_decl->attributes, param->Type(),
+                                             param_decl->source, ParamOrRetType::kParameter)) {
+            return false;
+        }
+    }
+
+    // Clear IO sets after parameter validation. Builtin and location attributes
+    // in return types should be validated independently from those used in
+    // parameters.
+    builtins.clear();
+    locations.clear();
+
+    if (!func->ReturnType()->Is<sem::Void>()) {
+        if (!validate_entry_point_attributes(decl->return_type_attributes, func->ReturnType(),
+                                             decl->source, ParamOrRetType::kReturnType)) {
+            return false;
+        }
+    }
+
+    if (decl->PipelineStage() == ast::PipelineStage::kVertex &&
+        builtins.count(ast::Builtin::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) {
+                    found = true;
+                    break;
+                }
+            }
+        }
+        if (!found) {
+            AddError(
+                "a vertex shader must include the 'position' builtin in its return "
+                "type",
+                decl->source);
+            return false;
+        }
+    }
+
+    if (decl->PipelineStage() == ast::PipelineStage::kCompute) {
+        if (!ast::HasAttribute<ast::WorkgroupAttribute>(decl->attributes)) {
+            AddError(
+                "a compute shader must include 'workgroup_size' in its "
+                "attributes",
+                decl->source);
+            return false;
+        }
+    }
+
+    // Validate there are no resource variable binding collisions
+    std::unordered_map<sem::BindingPoint, const ast::Variable*> binding_points;
+    for (auto* var : func->TransitivelyReferencedGlobals()) {
+        auto* var_decl = var->Declaration();
+        if (!var_decl->BindingPoint()) {
+            continue;
+        }
+        auto bp = var->BindingPoint();
+        auto res = binding_points.emplace(bp, var_decl);
+        if (!res.second &&
+            IsValidationEnabled(decl->attributes,
+                                ast::DisabledValidation::kBindingPointCollision) &&
+            IsValidationEnabled(res.first->second->attributes,
+                                ast::DisabledValidation::kBindingPointCollision)) {
+            // https://gpuweb.github.io/gpuweb/wgsl/#resource-interface
+            // Bindings must not alias within a shader stage: two different
+            // variables in the resource interface of a given shader must not have
+            // the same group and binding values, when considered as a pair of
+            // values.
+            auto func_name = symbols_.NameFor(decl->symbol);
+            AddError("entry point '" + func_name +
+                         "' references multiple variables that use the "
+                         "same resource binding @group(" +
+                         std::to_string(bp.group) + "), @binding(" + std::to_string(bp.binding) +
+                         ")",
+                     var_decl->source);
+            AddNote("first resource binding usage declared here", res.first->second->source);
+            return false;
+        }
+    }
+
+    return true;
+}
+
+bool Validator::Statements(const ast::StatementList& stmts) const {
+    for (auto* stmt : stmts) {
+        if (!sem_.Get(stmt)->IsReachable()) {
+            /// TODO(https://github.com/gpuweb/gpuweb/issues/2378): This may need to
+            /// become an error.
+            AddWarning("code is unreachable", stmt->source);
+            break;
+        }
+    }
+    return true;
+}
+
+bool Validator::Bitcast(const ast::BitcastExpression* cast, const sem::Type* to) const {
+    auto* from = sem_.TypeOf(cast->expr)->UnwrapRef();
+    if (!from->is_numeric_scalar_or_vector()) {
+        AddError("'" + sem_.TypeNameOf(from) + "' cannot be bitcast", cast->expr->source);
+        return false;
+    }
+    if (!to->is_numeric_scalar_or_vector()) {
+        AddError("cannot bitcast to '" + sem_.TypeNameOf(to) + "'", cast->type->source);
+        return false;
+    }
+
+    auto width = [&](const sem::Type* ty) {
+        if (auto* vec = ty->As<sem::Vector>()) {
+            return vec->Width();
+        }
+        return 1u;
+    };
+
+    if (width(from) != width(to)) {
+        AddError(
+            "cannot bitcast from '" + sem_.TypeNameOf(from) + "' to '" + sem_.TypeNameOf(to) + "'",
+            cast->source);
+        return false;
+    }
+
+    return true;
+}
+
+bool Validator::BreakStatement(const sem::Statement* stmt,
+                               sem::Statement* current_statement) const {
+    if (!stmt->FindFirstParent<sem::LoopBlockStatement, sem::CaseStatement>()) {
+        AddError("break statement must be in a loop or switch case", stmt->Declaration()->source);
+        return false;
+    }
+    if (auto* continuing = ClosestContinuing(/*stop_at_loop*/ true, current_statement)) {
+        auto fail = [&](const char* note_msg, const Source& note_src) {
+            constexpr const char* kErrorMsg =
+                "break statement in a continuing block must be the single statement "
+                "of an if statement's true or false block, and that if statement "
+                "must be the last statement of the continuing block";
+            AddError(kErrorMsg, stmt->Declaration()->source);
+            AddNote(note_msg, note_src);
+            return false;
+        };
+
+        if (auto* block = stmt->Parent()->As<sem::BlockStatement>()) {
+            auto* block_parent = block->Parent();
+            auto* if_stmt = block_parent->As<sem::IfStatement>();
+            if (!if_stmt) {
+                return fail("break statement is not directly in if statement block",
+                            stmt->Declaration()->source);
+            }
+            if (block->Declaration()->statements.size() != 1) {
+                return fail("if statement block contains multiple statements",
+                            block->Declaration()->source);
+            }
+
+            if (if_stmt->Parent()->Is<sem::IfStatement>()) {
+                return fail("else has condition", if_stmt->Declaration()->source);
+            }
+
+            bool el_contains_break = block->Declaration() == if_stmt->Declaration()->else_statement;
+            if (el_contains_break) {
+                if (auto* true_block = if_stmt->Declaration()->body; !true_block->Empty()) {
+                    return fail("non-empty true block", true_block->source);
+                }
+            } else {
+                auto* else_stmt = if_stmt->Declaration()->else_statement;
+                if (else_stmt) {
+                    return fail("non-empty false block", else_stmt->source);
+                }
+            }
+
+            if (if_stmt->Parent()->Declaration() != continuing) {
+                return fail(
+                    "if statement containing break statement is not directly in "
+                    "continuing block",
+                    if_stmt->Declaration()->source);
+            }
+            if (auto* cont_block = continuing->As<ast::BlockStatement>()) {
+                if (if_stmt->Declaration() != cont_block->Last()) {
+                    return fail(
+                        "if statement containing break statement is not the last "
+                        "statement of the continuing block",
+                        if_stmt->Declaration()->source);
+                }
+            }
+        }
+    }
+    return true;
+}
+
+bool Validator::ContinueStatement(const sem::Statement* stmt,
+                                  sem::Statement* current_statement) const {
+    if (auto* continuing = ClosestContinuing(/*stop_at_loop*/ true, current_statement)) {
+        AddError("continuing blocks must not contain a continue statement",
+                 stmt->Declaration()->source);
+        if (continuing != stmt->Declaration() && continuing != stmt->Parent()->Declaration()) {
+            AddNote("see continuing block here", continuing->source);
+        }
+        return false;
+    }
+
+    if (!stmt->FindFirstParent<sem::LoopBlockStatement>()) {
+        AddError("continue statement must be in a loop", stmt->Declaration()->source);
+        return false;
+    }
+
+    return true;
+}
+
+bool Validator::DiscardStatement(const sem::Statement* stmt,
+                                 sem::Statement* current_statement) const {
+    if (auto* continuing = ClosestContinuing(/*stop_at_loop*/ false, current_statement)) {
+        AddError("continuing blocks must not contain a discard statement",
+                 stmt->Declaration()->source);
+        if (continuing != stmt->Declaration() && continuing != stmt->Parent()->Declaration()) {
+            AddNote("see continuing block here", continuing->source);
+        }
+        return false;
+    }
+    return true;
+}
+
+bool Validator::FallthroughStatement(const sem::Statement* stmt) const {
+    if (auto* block = As<sem::BlockStatement>(stmt->Parent())) {
+        if (auto* c = As<sem::CaseStatement>(block->Parent())) {
+            if (block->Declaration()->Last() == stmt->Declaration()) {
+                if (auto* s = As<sem::SwitchStatement>(c->Parent())) {
+                    if (c->Declaration() != s->Declaration()->body.back()) {
+                        return true;
+                    }
+                    AddError(
+                        "a fallthrough statement must not be used in the last switch "
+                        "case",
+                        stmt->Declaration()->source);
+                    return false;
+                }
+            }
+        }
+    }
+    AddError("fallthrough must only be used as the last statement of a case block",
+             stmt->Declaration()->source);
+    return false;
+}
+
+bool Validator::LoopStatement(const sem::LoopStatement* stmt) const {
+    if (stmt->Behaviors().Empty()) {
+        AddError("loop does not exit", stmt->Declaration()->source.Begin());
+        return false;
+    }
+    return true;
+}
+
+bool Validator::ForLoopStatement(const sem::ForLoopStatement* stmt) const {
+    if (stmt->Behaviors().Empty()) {
+        AddError("for-loop does not exit", stmt->Declaration()->source.Begin());
+        return false;
+    }
+    if (auto* cond = stmt->Condition()) {
+        auto* cond_ty = cond->Type()->UnwrapRef();
+        if (!cond_ty->Is<sem::Bool>()) {
+            AddError("for-loop condition must be bool, got " + sem_.TypeNameOf(cond_ty),
+                     stmt->Condition()->Declaration()->source);
+            return false;
+        }
+    }
+    return true;
+}
+
+bool Validator::IfStatement(const sem::IfStatement* stmt) const {
+    auto* cond_ty = stmt->Condition()->Type()->UnwrapRef();
+    if (!cond_ty->Is<sem::Bool>()) {
+        AddError("if statement condition must be bool, got " + sem_.TypeNameOf(cond_ty),
+                 stmt->Condition()->Declaration()->source);
+        return false;
+    }
+    return true;
+}
+
+bool Validator::BuiltinCall(const sem::Call* call) const {
+    if (call->Type()->Is<sem::Void>()) {
+        bool is_call_statement = false;
+        if (auto* call_stmt = As<ast::CallStatement>(call->Stmt()->Declaration())) {
+            if (call_stmt->expr == call->Declaration()) {
+                is_call_statement = true;
+            }
+        }
+        if (!is_call_statement) {
+            // https://gpuweb.github.io/gpuweb/wgsl/#function-call-expr
+            // If the called function does not return a value, a function call
+            // statement should be used instead.
+            auto* ident = call->Declaration()->target.name;
+            auto name = symbols_.NameFor(ident->symbol);
+            AddError("builtin '" + name + "' does not return a value", call->Declaration()->source);
+            return false;
+        }
+    }
+
+    return true;
+}
+
+bool Validator::TextureBuiltinFunction(const sem::Call* call) const {
+    auto* builtin = call->Target()->As<sem::Builtin>();
+    if (!builtin) {
+        return false;
+    }
+
+    std::string func_name = builtin->str();
+    auto& signature = builtin->Signature();
+
+    auto check_arg_is_constexpr = [&](sem::ParameterUsage usage, int min, int max) {
+        auto index = signature.IndexOf(usage);
+        if (index < 0) {
+            return true;
+        }
+        std::string name = sem::str(usage);
+        auto* arg = call->Arguments()[index];
+        if (auto values = arg->ConstantValue()) {
+            // Assert that the constant values are of the expected type.
+            if (!values.Type()->IsAnyOf<sem::I32, sem::Vector>() ||
+                !values.ElementType()->Is<sem::I32>()) {
+                TINT_ICE(Resolver, diagnostics_)
+                    << "failed to resolve '" + func_name + "' " << name << " parameter type";
+                return false;
+            }
+
+            // Currently const_expr is restricted to literals and type constructors.
+            // Check that that's all we have for the parameter.
+            bool is_const_expr = true;
+            ast::TraverseExpressions(
+                arg->Declaration(), diagnostics_, [&](const ast::Expression* e) {
+                    if (e->IsAnyOf<ast::LiteralExpression, ast::CallExpression>()) {
+                        return ast::TraverseAction::Descend;
+                    }
+                    is_const_expr = false;
+                    return ast::TraverseAction::Stop;
+                });
+            if (is_const_expr) {
+                auto vector = builtin->Parameters()[index]->Type()->Is<sem::Vector>();
+                for (size_t i = 0; i < values.Elements().size(); i++) {
+                    auto value = values.Elements()[i].i32;
+                    if (value < min || value > max) {
+                        if (vector) {
+                            AddError("each component of the " + name +
+                                         " argument must be at least " + std::to_string(min) +
+                                         " and at most " + std::to_string(max) + ". " + name +
+                                         " component " + std::to_string(i) + " is " +
+                                         std::to_string(value),
+                                     arg->Declaration()->source);
+                        } else {
+                            AddError("the " + name + " argument must be at least " +
+                                         std::to_string(min) + " and at most " +
+                                         std::to_string(max) + ". " + name + " is " +
+                                         std::to_string(value),
+                                     arg->Declaration()->source);
+                        }
+                        return false;
+                    }
+                }
+                return true;
+            }
+        }
+        AddError("the " + name + " argument must be a const_expression",
+                 arg->Declaration()->source);
+        return false;
+    };
+
+    return check_arg_is_constexpr(sem::ParameterUsage::kOffset, -8, 7) &&
+           check_arg_is_constexpr(sem::ParameterUsage::kComponent, 0, 3);
+}
+
+bool Validator::FunctionCall(const sem::Call* call, sem::Statement* current_statement) const {
+    auto* decl = call->Declaration();
+    auto* target = call->Target()->As<sem::Function>();
+    auto sym = decl->target.name->symbol;
+    auto name = symbols_.NameFor(sym);
+
+    if (target->Declaration()->IsEntryPoint()) {
+        // https://www.w3.org/TR/WGSL/#function-restriction
+        // An entry point must never be the target of a function call.
+        AddError("entry point functions cannot be the target of a function call", decl->source);
+        return false;
+    }
+
+    if (decl->args.size() != target->Parameters().size()) {
+        bool more = decl->args.size() > target->Parameters().size();
+        AddError("too " + (more ? std::string("many") : std::string("few")) +
+                     " arguments in call to '" + name + "', expected " +
+                     std::to_string(target->Parameters().size()) + ", got " +
+                     std::to_string(call->Arguments().size()),
+                 decl->source);
+        return false;
+    }
+
+    for (size_t i = 0; i < call->Arguments().size(); ++i) {
+        const sem::Variable* param = target->Parameters()[i];
+        const ast::Expression* arg_expr = decl->args[i];
+        auto* param_type = param->Type();
+        auto* arg_type = sem_.TypeOf(arg_expr)->UnwrapRef();
+
+        if (param_type != arg_type) {
+            AddError("type mismatch for argument " + std::to_string(i + 1) + " in call to '" +
+                         name + "', expected '" + sem_.TypeNameOf(param_type) + "', got '" +
+                         sem_.TypeNameOf(arg_type) + "'",
+                     arg_expr->source);
+            return false;
+        }
+
+        if (param_type->Is<sem::Pointer>()) {
+            auto is_valid = false;
+            if (auto* ident_expr = arg_expr->As<ast::IdentifierExpression>()) {
+                auto* var = sem_.ResolvedSymbol<sem::Variable>(ident_expr);
+                if (!var) {
+                    TINT_ICE(Resolver, diagnostics_) << "failed to resolve identifier";
+                    return false;
+                }
+                if (var->Is<sem::Parameter>()) {
+                    is_valid = true;
+                }
+            } else if (auto* unary = arg_expr->As<ast::UnaryOpExpression>()) {
+                if (unary->op == ast::UnaryOp::kAddressOf) {
+                    if (auto* ident_unary = unary->expr->As<ast::IdentifierExpression>()) {
+                        auto* var = sem_.ResolvedSymbol<sem::Variable>(ident_unary);
+                        if (!var) {
+                            TINT_ICE(Resolver, diagnostics_) << "failed to resolve identifier";
+                            return false;
+                        }
+                        if (var->Declaration()->is_const) {
+                            TINT_ICE(Resolver, diagnostics_)
+                                << "Resolver::FunctionCall() encountered an address-of "
+                                   "expression of a constant identifier expression";
+                            return false;
+                        }
+                        is_valid = true;
+                    }
+                }
+            }
+
+            if (!is_valid &&
+                IsValidationEnabled(param->Declaration()->attributes,
+                                    ast::DisabledValidation::kIgnoreInvalidPointerArgument)) {
+                AddError(
+                    "expected an address-of expression of a variable identifier "
+                    "expression or a function parameter",
+                    arg_expr->source);
+                return false;
+            }
+        }
+    }
+
+    if (call->Type()->Is<sem::Void>()) {
+        bool is_call_statement = false;
+        if (auto* call_stmt = As<ast::CallStatement>(call->Stmt()->Declaration())) {
+            if (call_stmt->expr == call->Declaration()) {
+                is_call_statement = true;
+            }
+        }
+        if (!is_call_statement) {
+            // https://gpuweb.github.io/gpuweb/wgsl/#function-call-expr
+            // If the called function does not return a value, a function call
+            // statement should be used instead.
+            AddError("function '" + name + "' does not return a value", decl->source);
+            return false;
+        }
+    }
+
+    if (call->Behaviors().Contains(sem::Behavior::kDiscard)) {
+        if (auto* continuing = ClosestContinuing(/*stop_at_loop*/ false, current_statement)) {
+            AddError("cannot call a function that may discard inside a continuing block",
+                     call->Declaration()->source);
+            if (continuing != call->Stmt()->Declaration() &&
+                continuing != call->Stmt()->Parent()->Declaration()) {
+                AddNote("see continuing block here", continuing->source);
+            }
+            return false;
+        }
+    }
+
+    return true;
+}
+
+bool Validator::StructureConstructorOrCast(const ast::CallExpression* ctor,
+                                           const sem::Struct* struct_type) const {
+    if (!struct_type->IsConstructible()) {
+        AddError("struct constructor has non-constructible type", ctor->source);
+        return false;
+    }
+
+    if (ctor->args.size() > 0) {
+        if (ctor->args.size() != struct_type->Members().size()) {
+            std::string fm = ctor->args.size() < struct_type->Members().size() ? "few" : "many";
+            AddError("struct constructor has too " + fm + " inputs: expected " +
+                         std::to_string(struct_type->Members().size()) + ", found " +
+                         std::to_string(ctor->args.size()),
+                     ctor->source);
+            return false;
+        }
+        for (auto* member : struct_type->Members()) {
+            auto* value = ctor->args[member->Index()];
+            auto* value_ty = sem_.TypeOf(value);
+            if (member->Type() != value_ty->UnwrapRef()) {
+                AddError(
+                    "type in struct constructor does not match struct member type: "
+                    "expected '" +
+                        sem_.TypeNameOf(member->Type()) + "', found '" + sem_.TypeNameOf(value_ty) +
+                        "'",
+                    value->source);
+                return false;
+            }
+        }
+    }
+    return true;
+}
+
+bool Validator::ArrayConstructorOrCast(const ast::CallExpression* ctor,
+                                       const sem::Array* array_type) const {
+    auto& values = ctor->args;
+    auto* elem_ty = array_type->ElemType();
+    for (auto* value : values) {
+        auto* value_ty = sem_.TypeOf(value)->UnwrapRef();
+        if (value_ty != elem_ty) {
+            AddError(
+                "type in array constructor does not match array type: "
+                "expected '" +
+                    sem_.TypeNameOf(elem_ty) + "', found '" + sem_.TypeNameOf(value_ty) + "'",
+                value->source);
+            return false;
+        }
+    }
+
+    if (array_type->IsRuntimeSized()) {
+        AddError("cannot init a runtime-sized array", ctor->source);
+        return false;
+    } else if (!elem_ty->IsConstructible()) {
+        AddError("array constructor has non-constructible element type", ctor->source);
+        return false;
+    } else if (!values.empty() && (values.size() != array_type->Count())) {
+        std::string fm = values.size() < array_type->Count() ? "few" : "many";
+        AddError("array constructor has too " + fm + " elements: expected " +
+                     std::to_string(array_type->Count()) + ", found " +
+                     std::to_string(values.size()),
+                 ctor->source);
+        return false;
+    } else if (values.size() > array_type->Count()) {
+        AddError("array constructor has too many elements: expected " +
+                     std::to_string(array_type->Count()) + ", found " +
+                     std::to_string(values.size()),
+                 ctor->source);
+        return false;
+    }
+    return true;
+}
+
+bool Validator::VectorConstructorOrCast(const ast::CallExpression* ctor,
+                                        const sem::Vector* vec_type) const {
+    auto& values = ctor->args;
+    auto* elem_ty = vec_type->type();
+    size_t value_cardinality_sum = 0;
+    for (auto* value : values) {
+        auto* value_ty = sem_.TypeOf(value)->UnwrapRef();
+        if (value_ty->is_scalar()) {
+            if (elem_ty != value_ty) {
+                AddError(
+                    "type in vector constructor does not match vector type: "
+                    "expected '" +
+                        sem_.TypeNameOf(elem_ty) + "', found '" + sem_.TypeNameOf(value_ty) + "'",
+                    value->source);
+                return false;
+            }
+
+            value_cardinality_sum++;
+        } else if (auto* value_vec = value_ty->As<sem::Vector>()) {
+            auto* value_elem_ty = value_vec->type();
+            // A mismatch of vector type parameter T is only an error if multiple
+            // arguments are present. A single argument constructor constitutes a
+            // type conversion expression.
+            if (elem_ty != value_elem_ty && values.size() > 1u) {
+                AddError(
+                    "type in vector constructor does not match vector type: "
+                    "expected '" +
+                        sem_.TypeNameOf(elem_ty) + "', found '" + sem_.TypeNameOf(value_elem_ty) +
+                        "'",
+                    value->source);
+                return false;
+            }
+
+            value_cardinality_sum += value_vec->Width();
+        } else {
+            // A vector constructor can only accept vectors and scalars.
+            AddError("expected vector or scalar type in vector constructor; found: " +
+                         sem_.TypeNameOf(value_ty),
+                     value->source);
+            return false;
+        }
+    }
+
+    // A correct vector constructor must either be a zero-value expression,
+    // a single-value initializer (splat) expression, or the number of components
+    // of all constructor arguments must add up to the vector cardinality.
+    if (value_cardinality_sum > 1 && value_cardinality_sum != vec_type->Width()) {
+        if (values.empty()) {
+            TINT_ICE(Resolver, diagnostics_) << "constructor arguments expected to be non-empty!";
+        }
+        const Source& values_start = values[0]->source;
+        const Source& values_end = values[values.size() - 1]->source;
+        AddError("attempted to construct '" + sem_.TypeNameOf(vec_type) + "' with " +
+                     std::to_string(value_cardinality_sum) + " component(s)",
+                 Source::Combine(values_start, values_end));
+        return false;
+    }
+    return true;
+}
+
+bool Validator::Vector(const sem::Vector* ty, const Source& source) const {
+    if (!ty->type()->is_scalar()) {
+        AddError("vector element type must be 'bool', 'f32', 'i32' or 'u32'", source);
+        return false;
+    }
+    return true;
+}
+
+bool Validator::Matrix(const sem::Matrix* ty, const Source& source) const {
+    if (!ty->is_float_matrix()) {
+        AddError("matrix element type must be 'f32'", source);
+        return false;
+    }
+    return true;
+}
+
+bool Validator::MatrixConstructorOrCast(const ast::CallExpression* ctor,
+                                        const sem::Matrix* matrix_ty) const {
+    auto& values = ctor->args;
+    // Zero Value expression
+    if (values.empty()) {
+        return true;
+    }
+
+    if (!Matrix(matrix_ty, ctor->source)) {
+        return false;
+    }
+
+    std::vector<const sem::Type*> arg_tys;
+    arg_tys.reserve(values.size());
+    for (auto* value : values) {
+        arg_tys.emplace_back(sem_.TypeOf(value)->UnwrapRef());
+    }
+
+    auto* elem_type = matrix_ty->type();
+    auto num_elements = matrix_ty->columns() * matrix_ty->rows();
+
+    // Print a generic error for an invalid matrix constructor, showing the
+    // available overloads.
+    auto print_error = [&]() {
+        const Source& values_start = values[0]->source;
+        const Source& values_end = values[values.size() - 1]->source;
+        auto type_name = sem_.TypeNameOf(matrix_ty);
+        auto elem_type_name = sem_.TypeNameOf(elem_type);
+        std::stringstream ss;
+        ss << "no matching constructor " + type_name << "(";
+        for (size_t i = 0; i < values.size(); i++) {
+            if (i > 0) {
+                ss << ", ";
+            }
+            ss << arg_tys[i]->FriendlyName(symbols_);
+        }
+        ss << ")" << std::endl << std::endl;
+        ss << "3 candidates available:" << std::endl;
+        ss << "  " << type_name << "()" << std::endl;
+        ss << "  " << type_name << "(" << elem_type_name << ",...," << elem_type_name << ")"
+           << " // " << std::to_string(num_elements) << " arguments" << std::endl;
+        ss << "  " << type_name << "(";
+        for (uint32_t c = 0; c < matrix_ty->columns(); c++) {
+            if (c > 0) {
+                ss << ", ";
+            }
+            ss << VectorPretty(matrix_ty->rows(), elem_type);
+        }
+        ss << ")" << std::endl;
+        AddError(ss.str(), Source::Combine(values_start, values_end));
+    };
+
+    const sem::Type* expected_arg_type = nullptr;
+    if (num_elements == values.size()) {
+        // Column-major construction from scalar elements.
+        expected_arg_type = matrix_ty->type();
+    } else if (matrix_ty->columns() == values.size()) {
+        // Column-by-column construction from vectors.
+        expected_arg_type = matrix_ty->ColumnType();
+    } else {
+        print_error();
+        return false;
+    }
+
+    for (auto* arg_ty : arg_tys) {
+        if (arg_ty != expected_arg_type) {
+            print_error();
+            return false;
+        }
+    }
+
+    return true;
+}
+
+bool Validator::ScalarConstructorOrCast(const ast::CallExpression* ctor,
+                                        const sem::Type* ty) const {
+    if (ctor->args.size() == 0) {
+        return true;
+    }
+    if (ctor->args.size() > 1) {
+        AddError(
+            "expected zero or one value in constructor, got " + std::to_string(ctor->args.size()),
+            ctor->source);
+        return false;
+    }
+
+    // Validate constructor
+    auto* value = ctor->args[0];
+    auto* value_ty = sem_.TypeOf(value)->UnwrapRef();
+
+    using Bool = sem::Bool;
+    using I32 = sem::I32;
+    using U32 = sem::U32;
+    using F32 = sem::F32;
+
+    const bool is_valid =
+        (ty->Is<Bool>() && value_ty->is_scalar()) || (ty->Is<I32>() && value_ty->is_scalar()) ||
+        (ty->Is<U32>() && value_ty->is_scalar()) || (ty->Is<F32>() && value_ty->is_scalar());
+    if (!is_valid) {
+        AddError("cannot construct '" + sem_.TypeNameOf(ty) + "' with a value of type '" +
+                     sem_.TypeNameOf(value_ty) + "'",
+                 ctor->source);
+
+        return false;
+    }
+
+    return true;
+}
+
+bool Validator::PipelineStages(const std::vector<sem::Function*>& entry_points) const {
+    auto check_workgroup_storage = [&](const sem::Function* func,
+                                       const sem::Function* entry_point) {
+        auto stage = entry_point->Declaration()->PipelineStage();
+        if (stage != ast::PipelineStage::kCompute) {
+            for (auto* var : func->DirectlyReferencedGlobals()) {
+                if (var->StorageClass() == ast::StorageClass::kWorkgroup) {
+                    std::stringstream stage_name;
+                    stage_name << stage;
+                    for (auto* user : var->Users()) {
+                        if (func == user->Stmt()->Function()) {
+                            AddError("workgroup memory cannot be used by " + stage_name.str() +
+                                         " pipeline stage",
+                                     user->Declaration()->source);
+                            break;
+                        }
+                    }
+                    AddNote("variable is declared here", var->Declaration()->source);
+                    if (func != entry_point) {
+                        TraverseCallChain(
+                            diagnostics_, entry_point, func, [&](const sem::Function* f) {
+                                AddNote("called by function '" +
+                                            symbols_.NameFor(f->Declaration()->symbol) + "'",
+                                        f->Declaration()->source);
+                            });
+                        AddNote("called by entry point '" +
+                                    symbols_.NameFor(entry_point->Declaration()->symbol) + "'",
+                                entry_point->Declaration()->source);
+                    }
+                    return false;
+                }
+            }
+        }
+        return true;
+    };
+
+    for (auto* entry_point : entry_points) {
+        if (!check_workgroup_storage(entry_point, entry_point)) {
+            return false;
+        }
+        for (auto* func : entry_point->TransitivelyCalledFunctions()) {
+            if (!check_workgroup_storage(func, entry_point)) {
+                return false;
+            }
+        }
+    }
+
+    auto check_builtin_calls = [&](const sem::Function* func, const sem::Function* entry_point) {
+        auto stage = entry_point->Declaration()->PipelineStage();
+        for (auto* builtin : func->DirectlyCalledBuiltins()) {
+            if (!builtin->SupportedStages().Contains(stage)) {
+                auto* call = func->FindDirectCallTo(builtin);
+                std::stringstream err;
+                err << "built-in cannot be used by " << stage << " pipeline stage";
+                AddError(err.str(),
+                         call ? call->Declaration()->source : func->Declaration()->source);
+                if (func != entry_point) {
+                    TraverseCallChain(diagnostics_, entry_point, func, [&](const sem::Function* f) {
+                        AddNote("called by function '" +
+                                    symbols_.NameFor(f->Declaration()->symbol) + "'",
+                                f->Declaration()->source);
+                    });
+                    AddNote("called by entry point '" +
+                                symbols_.NameFor(entry_point->Declaration()->symbol) + "'",
+                            entry_point->Declaration()->source);
+                }
+                return false;
+            }
+        }
+        return true;
+    };
+
+    for (auto* entry_point : entry_points) {
+        if (!check_builtin_calls(entry_point, entry_point)) {
+            return false;
+        }
+        for (auto* func : entry_point->TransitivelyCalledFunctions()) {
+            if (!check_builtin_calls(func, entry_point)) {
+                return false;
+            }
+        }
+    }
+    return true;
+}
+
+bool Validator::Array(const sem::Array* arr, const Source& source) const {
+    auto* el_ty = arr->ElemType();
+
+    if (!IsFixedFootprint(el_ty)) {
+        AddError("an array element type cannot contain a runtime-sized array", source);
+        return false;
+    }
+    return true;
+}
+
+bool Validator::ArrayStrideAttribute(const ast::StrideAttribute* attr,
+                                     uint32_t el_size,
+                                     uint32_t el_align,
+                                     const Source& source) const {
+    auto stride = attr->stride;
+    bool is_valid_stride = (stride >= el_size) && (stride >= el_align) && (stride % el_align == 0);
+    if (!is_valid_stride) {
+        // https://gpuweb.github.io/gpuweb/wgsl/#array-layout-rules
+        // Arrays decorated with the stride attribute must have a stride that is
+        // at least the size of the element type, and be a multiple of the
+        // element type's alignment value.
+        AddError(
+            "arrays decorated with the stride attribute must have a stride "
+            "that is at least the size of the element type, and be a multiple "
+            "of the element type's alignment value.",
+            source);
+        return false;
+    }
+    return true;
+}
+
+bool Validator::Alias(const ast::Alias* alias) const {
+    auto name = symbols_.NameFor(alias->name);
+    if (sem::ParseBuiltinType(name) != sem::BuiltinType::kNone) {
+        AddError("'" + name + "' is a builtin and cannot be redeclared as an alias", alias->source);
+        return false;
+    }
+
+    return true;
+}
+
+bool Validator::Structure(const sem::Struct* str, ast::PipelineStage stage) const {
+    auto name = symbols_.NameFor(str->Declaration()->name);
+    if (sem::ParseBuiltinType(name) != sem::BuiltinType::kNone) {
+        AddError("'" + name + "' is a builtin and cannot be redeclared as a struct",
+                 str->Declaration()->source);
+        return false;
+    }
+
+    if (str->Members().empty()) {
+        AddError("structures must have at least one member", str->Declaration()->source);
+        return false;
+    }
+
+    std::unordered_set<uint32_t> locations;
+    for (auto* member : str->Members()) {
+        if (auto* r = member->Type()->As<sem::Array>()) {
+            if (r->IsRuntimeSized()) {
+                if (member != str->Members().back()) {
+                    AddError("runtime arrays may only appear as the last member of a struct",
+                             member->Declaration()->source);
+                    return false;
+                }
+            }
+        } else if (!IsFixedFootprint(member->Type())) {
+            AddError(
+                "a struct that contains a runtime array cannot be nested inside "
+                "another struct",
+                member->Declaration()->source);
+            return false;
+        }
+
+        auto has_location = false;
+        auto has_position = false;
+        const ast::InvariantAttribute* invariant_attribute = nullptr;
+        const ast::InterpolateAttribute* interpolate_attribute = nullptr;
+        for (auto* attr : member->Declaration()->attributes) {
+            if (!attr->IsAnyOf<ast::BuiltinAttribute,             //
+                               ast::InternalAttribute,            //
+                               ast::InterpolateAttribute,         //
+                               ast::InvariantAttribute,           //
+                               ast::LocationAttribute,            //
+                               ast::StructMemberOffsetAttribute,  //
+                               ast::StructMemberSizeAttribute,    //
+                               ast::StructMemberAlignAttribute>()) {
+                if (attr->Is<ast::StrideAttribute>() &&
+                    IsValidationDisabled(member->Declaration()->attributes,
+                                         ast::DisabledValidation::kIgnoreStrideAttribute)) {
+                    continue;
+                }
+                AddError("attribute is not valid for structure members", attr->source);
+                return false;
+            }
+
+            if (auto* invariant = attr->As<ast::InvariantAttribute>()) {
+                invariant_attribute = invariant;
+            } else if (auto* location = attr->As<ast::LocationAttribute>()) {
+                has_location = true;
+                if (!LocationAttribute(location, member->Type(), locations, stage,
+                                       member->Declaration()->source)) {
+                    return false;
+                }
+            } else if (auto* builtin = attr->As<ast::BuiltinAttribute>()) {
+                if (!BuiltinAttribute(builtin, member->Type(), stage,
+                                      /* is_input */ false)) {
+                    return false;
+                }
+                if (builtin->builtin == ast::Builtin::kPosition) {
+                    has_position = true;
+                }
+            } else if (auto* interpolate = attr->As<ast::InterpolateAttribute>()) {
+                interpolate_attribute = interpolate;
+                if (!InterpolateAttribute(interpolate, member->Type())) {
+                    return false;
+                }
+            }
+        }
+
+        if (invariant_attribute && !has_position) {
+            AddError("invariant attribute must only be applied to a position builtin",
+                     invariant_attribute->source);
+            return false;
+        }
+
+        if (interpolate_attribute && !has_location) {
+            AddError("interpolate attribute must only be used with @location",
+                     interpolate_attribute->source);
+            return false;
+        }
+    }
+
+    for (auto* attr : str->Declaration()->attributes) {
+        if (!(attr->IsAnyOf<ast::InternalAttribute>())) {
+            AddError("attribute is not valid for struct declarations", attr->source);
+            return false;
+        }
+    }
+
+    return true;
+}
+
+bool Validator::LocationAttribute(const ast::LocationAttribute* location,
+                                  const sem::Type* type,
+                                  std::unordered_set<uint32_t>& locations,
+                                  ast::PipelineStage stage,
+                                  const Source& source,
+                                  const bool is_input) const {
+    std::string inputs_or_output = is_input ? "inputs" : "output";
+    if (stage == ast::PipelineStage::kCompute) {
+        AddError("attribute is not valid for compute shader " + inputs_or_output, location->source);
+        return false;
+    }
+
+    if (!type->is_numeric_scalar_or_vector()) {
+        std::string invalid_type = sem_.TypeNameOf(type);
+        AddError("cannot apply 'location' attribute to declaration of type '" + invalid_type + "'",
+                 source);
+        AddNote(
+            "'location' attribute must only be applied to declarations of "
+            "numeric scalar or numeric vector type",
+            location->source);
+        return false;
+    }
+
+    if (locations.count(location->value)) {
+        AddError(attr_to_str(location) + " attribute appears multiple times", location->source);
+        return false;
+    }
+    locations.emplace(location->value);
+
+    return true;
+}
+
+bool Validator::Return(const ast::ReturnStatement* ret,
+                       const sem::Type* func_type,
+                       const sem::Type* ret_type,
+                       sem::Statement* current_statement) const {
+    if (func_type->UnwrapRef() != ret_type) {
+        AddError(
+            "return statement type must match its function "
+            "return type, returned '" +
+                sem_.TypeNameOf(ret_type) + "', expected '" + sem_.TypeNameOf(func_type) + "'",
+            ret->source);
+        return false;
+    }
+
+    auto* sem = sem_.Get(ret);
+    if (auto* continuing = ClosestContinuing(/*stop_at_loop*/ false, current_statement)) {
+        AddError("continuing blocks must not contain a return statement", ret->source);
+        if (continuing != sem->Declaration() && continuing != sem->Parent()->Declaration()) {
+            AddNote("see continuing block here", continuing->source);
+        }
+        return false;
+    }
+
+    return true;
+}
+
+bool Validator::SwitchStatement(const ast::SwitchStatement* s) {
+    auto* cond_ty = sem_.TypeOf(s->condition)->UnwrapRef();
+    if (!cond_ty->is_integer_scalar()) {
+        AddError(
+            "switch statement selector expression must be of a "
+            "scalar integer type",
+            s->condition->source);
+        return false;
+    }
+
+    bool has_default = false;
+    std::unordered_map<int64_t, Source> selectors;
+
+    for (auto* case_stmt : s->body) {
+        if (case_stmt->IsDefault()) {
+            if (has_default) {
+                // More than one default clause
+                AddError("switch statement must have exactly one default clause",
+                         case_stmt->source);
+                return false;
+            }
+            has_default = true;
+        }
+
+        for (auto* selector : case_stmt->selectors) {
+            if (cond_ty != sem_.TypeOf(selector)) {
+                AddError(
+                    "the case selector values must have the same "
+                    "type as the selector expression.",
+                    case_stmt->source);
+                return false;
+            }
+
+            auto it = selectors.find(selector->value);
+            if (it != selectors.end()) {
+                auto val = std::to_string(selector->value);
+                AddError("duplicate switch case '" + val + "'", selector->source);
+                AddNote("previous case declared here", it->second);
+                return false;
+            }
+            selectors.emplace(selector->value, selector->source);
+        }
+    }
+
+    if (!has_default) {
+        // No default clause
+        AddError("switch statement must have a default clause", s->source);
+        return false;
+    }
+
+    return true;
+}
+
+bool Validator::Assignment(const ast::Statement* a, const sem::Type* rhs_ty) const {
+    const ast::Expression* lhs;
+    const ast::Expression* rhs;
+    if (auto* assign = a->As<ast::AssignmentStatement>()) {
+        lhs = assign->lhs;
+        rhs = assign->rhs;
+    } else if (auto* compound = a->As<ast::CompoundAssignmentStatement>()) {
+        lhs = compound->lhs;
+        rhs = compound->rhs;
+    } else {
+        TINT_ICE(Resolver, diagnostics_) << "invalid assignment statement";
+        return false;
+    }
+
+    if (lhs->Is<ast::PhonyExpression>()) {
+        // https://www.w3.org/TR/WGSL/#phony-assignment-section
+        auto* ty = rhs_ty->UnwrapRef();
+        if (!ty->IsConstructible() && !ty->IsAnyOf<sem::Pointer, sem::Texture, sem::Sampler>()) {
+            AddError("cannot assign '" + sem_.TypeNameOf(rhs_ty) +
+                         "' to '_'. '_' can only be assigned a constructible, pointer, "
+                         "texture or sampler type",
+                     rhs->source);
+            return false;
+        }
+        return true;  // RHS can be anything.
+    }
+
+    // https://gpuweb.github.io/gpuweb/wgsl/#assignment-statement
+    auto const* lhs_ty = sem_.TypeOf(lhs);
+
+    if (auto* var = sem_.ResolvedSymbol<sem::Variable>(lhs)) {
+        auto* decl = var->Declaration();
+        if (var->Is<sem::Parameter>()) {
+            AddError("cannot assign to function parameter", lhs->source);
+            AddNote("'" + symbols_.NameFor(decl->symbol) + "' is declared here:", decl->source);
+            return false;
+        }
+        if (decl->is_const) {
+            AddError("cannot assign to const", lhs->source);
+            AddNote("'" + symbols_.NameFor(decl->symbol) + "' is declared here:", decl->source);
+            return false;
+        }
+    }
+
+    auto* lhs_ref = lhs_ty->As<sem::Reference>();
+    if (!lhs_ref) {
+        // LHS is not a reference, so it has no storage.
+        AddError("cannot assign to value of type '" + sem_.TypeNameOf(lhs_ty) + "'", lhs->source);
+        return false;
+    }
+
+    auto* storage_ty = lhs_ref->StoreType();
+    auto* value_type = rhs_ty->UnwrapRef();  // Implicit load of RHS
+
+    // Value type has to match storage type
+    if (storage_ty != value_type) {
+        AddError(
+            "cannot assign '" + sem_.TypeNameOf(rhs_ty) + "' to '" + sem_.TypeNameOf(lhs_ty) + "'",
+            a->source);
+        return false;
+    }
+    if (!storage_ty->IsConstructible()) {
+        AddError("storage type of assignment must be constructible", a->source);
+        return false;
+    }
+    if (lhs_ref->Access() == ast::Access::kRead) {
+        AddError("cannot store into a read-only type '" + sem_.RawTypeNameOf(lhs_ty) + "'",
+                 a->source);
+        return false;
+    }
+    return true;
+}
+
+bool Validator::IncrementDecrementStatement(const ast::IncrementDecrementStatement* inc) const {
+    const ast::Expression* lhs = inc->lhs;
+
+    // https://gpuweb.github.io/gpuweb/wgsl/#increment-decrement
+
+    if (auto* var = sem_.ResolvedSymbol<sem::Variable>(lhs)) {
+        auto* decl = var->Declaration();
+        if (var->Is<sem::Parameter>()) {
+            AddError("cannot modify function parameter", lhs->source);
+            AddNote("'" + symbols_.NameFor(decl->symbol) + "' is declared here:", decl->source);
+            return false;
+        }
+        if (decl->is_const) {
+            AddError("cannot modify constant value", lhs->source);
+            AddNote("'" + symbols_.NameFor(decl->symbol) + "' is declared here:", decl->source);
+            return false;
+        }
+    }
+
+    auto const* lhs_ty = sem_.TypeOf(lhs);
+    auto* lhs_ref = lhs_ty->As<sem::Reference>();
+    if (!lhs_ref) {
+        // LHS is not a reference, so it has no storage.
+        AddError("cannot modify value of type '" + sem_.TypeNameOf(lhs_ty) + "'", lhs->source);
+        return false;
+    }
+
+    if (!lhs_ref->StoreType()->is_integer_scalar()) {
+        const std::string kind = inc->increment ? "increment" : "decrement";
+        AddError(kind + " statement can only be applied to an integer scalar", lhs->source);
+        return false;
+    }
+
+    if (lhs_ref->Access() == ast::Access::kRead) {
+        AddError("cannot modify read-only type '" + sem_.RawTypeNameOf(lhs_ty) + "'", inc->source);
+        return false;
+    }
+    return true;
+}
+
+bool Validator::NoDuplicateAttributes(const ast::AttributeList& attributes) const {
+    std::unordered_map<const TypeInfo*, Source> seen;
+    for (auto* d : attributes) {
+        auto res = seen.emplace(&d->TypeInfo(), d->source);
+        if (!res.second && !d->Is<ast::InternalAttribute>()) {
+            AddError("duplicate " + d->Name() + " attribute", d->source);
+            AddNote("first attribute declared here", res.first->second);
+            return false;
+        }
+    }
+    return true;
+}
+
+bool Validator::IsValidationDisabled(const ast::AttributeList& attributes,
+                                     ast::DisabledValidation validation) const {
+    for (auto* attribute : attributes) {
+        if (auto* dv = attribute->As<ast::DisableValidationAttribute>()) {
+            if (dv->validation == validation) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+bool Validator::IsValidationEnabled(const ast::AttributeList& attributes,
+                                    ast::DisabledValidation validation) const {
+    return !IsValidationDisabled(attributes, validation);
+}
+
+std::string Validator::VectorPretty(uint32_t size, const sem::Type* element_type) const {
+    sem::Vector vec_type(element_type, size);
+    return vec_type.FriendlyName(symbols_);
+}
+
+}  // namespace tint::resolver
diff --git a/src/tint/resolver/validator.h b/src/tint/resolver/validator.h
new file mode 100644
index 0000000..9901dc9
--- /dev/null
+++ b/src/tint/resolver/validator.h
@@ -0,0 +1,439 @@
+// 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_RESOLVER_VALIDATOR_H_
+#define SRC_TINT_RESOLVER_VALIDATOR_H_
+
+#include <set>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include <utility>
+#include <vector>
+
+#include "src/tint/ast/pipeline_stage.h"
+#include "src/tint/program_builder.h"
+#include "src/tint/resolver/sem_helper.h"
+#include "src/tint/source.h"
+
+// Forward declarations
+namespace tint::ast {
+class IndexAccessorExpression;
+class BinaryExpression;
+class BitcastExpression;
+class CallExpression;
+class CallStatement;
+class CaseStatement;
+class ForLoopStatement;
+class Function;
+class IdentifierExpression;
+class LoopStatement;
+class MemberAccessorExpression;
+class ReturnStatement;
+class SwitchStatement;
+class UnaryOpExpression;
+class Variable;
+}  // namespace tint::ast
+namespace tint::sem {
+class Array;
+class Atomic;
+class BlockStatement;
+class Builtin;
+class CaseStatement;
+class ForLoopStatement;
+class IfStatement;
+class LoopStatement;
+class Statement;
+class SwitchStatement;
+class TypeConstructor;
+}  // namespace tint::sem
+
+namespace tint::resolver {
+
+/// Validation logic for various ast nodes. The validations in general should
+/// be shallow and depend on the resolver to call on children. The validations
+/// also assume that sem changes have already been made. The validation checks
+/// should not alter the AST or SEM trees.
+class Validator {
+  public:
+    /// The valid type storage layouts typedef
+    using ValidTypeStorageLayouts = std::set<std::pair<const sem::Type*, ast::StorageClass>>;
+
+    /// Constructor
+    /// @param builder the program builder
+    /// @param helper the SEM helper to validate with
+    Validator(ProgramBuilder* builder, SemHelper& helper);
+    ~Validator();
+
+    /// Adds the given error message to the diagnostics
+    /// @param msg the error message
+    /// @param source the error source
+    void AddError(const std::string& msg, const Source& source) const;
+
+    /// Adds the given warning message to the diagnostics
+    /// @param msg the warning message
+    /// @param source the warning source
+    void AddWarning(const std::string& msg, const Source& source) const;
+
+    /// Adds the given note message to the diagnostics
+    /// @param msg the note message
+    /// @param source the note source
+    void AddNote(const std::string& msg, const Source& source) const;
+
+    /// @param type the given type
+    /// @returns true if the given type is a plain type
+    bool IsPlain(const sem::Type* type) const;
+
+    /// @param type the given type
+    /// @returns true if the given type is a fixed-footprint type
+    bool IsFixedFootprint(const sem::Type* type) const;
+
+    /// @param type the given type
+    /// @returns true if the given type is storable
+    bool IsStorable(const sem::Type* type) const;
+
+    /// @param type the given type
+    /// @returns true if the given type is host-shareable
+    bool IsHostShareable(const sem::Type* type) const;
+
+    /// Validates pipeline stages
+    /// @param entry_points the entry points to the module
+    /// @returns true on success, false otherwise.
+    bool PipelineStages(const std::vector<sem::Function*>& entry_points) const;
+
+    /// Validates aliases
+    /// @param alias the alias to validate
+    /// @returns true on success, false otherwise.
+    bool Alias(const ast::Alias* alias) const;
+
+    /// Validates the array
+    /// @param arr the array to validate
+    /// @param source the source of the array
+    /// @returns true on success, false otherwise.
+    bool Array(const sem::Array* arr, const Source& source) const;
+
+    /// Validates an array stride attribute
+    /// @param attr the stride attribute to validate
+    /// @param el_size the element size
+    /// @param el_align the element alignment
+    /// @param source the source of the attribute
+    /// @returns true on success, false otherwise
+    bool ArrayStrideAttribute(const ast::StrideAttribute* attr,
+                              uint32_t el_size,
+                              uint32_t el_align,
+                              const Source& source) const;
+
+    /// Validates an atomic
+    /// @param a the atomic ast node to validate
+    /// @param s the atomic sem node
+    /// @returns true on success, false otherwise.
+    bool Atomic(const ast::Atomic* a, const sem::Atomic* s) const;
+
+    /// Validates an atoic variable
+    /// @param var the variable to validate
+    /// @param atomic_composite_info store atomic information
+    /// @returns true on success, false otherwise.
+    bool AtomicVariable(
+        const sem::Variable* var,
+        std::unordered_map<const sem::Type*, const Source&> atomic_composite_info) const;
+
+    /// Validates an assignment
+    /// @param a the assignment statement
+    /// @param rhs_ty the type of the right hand side
+    /// @returns true on success, false otherwise.
+    bool Assignment(const ast::Statement* a, const sem::Type* rhs_ty) const;
+
+    /// Validates a bitcase
+    /// @param cast the bitcast expression
+    /// @param to the destination type
+    /// @returns true on success, false otherwise
+    bool Bitcast(const ast::BitcastExpression* cast, const sem::Type* to) const;
+
+    /// Validates a break statement
+    /// @param stmt the break statement to validate
+    /// @param current_statement the current statement being resolved
+    /// @returns true on success, false otherwise.
+    bool BreakStatement(const sem::Statement* stmt, sem::Statement* current_statement) const;
+
+    /// Validates a builtin attribute
+    /// @param attr the attribute to validate
+    /// @param storage_type the attribute storage type
+    /// @param stage the current pipeline stage
+    /// @param is_input true if this is an input attribute
+    /// @returns true on success, false otherwise.
+    bool BuiltinAttribute(const ast::BuiltinAttribute* attr,
+                          const sem::Type* storage_type,
+                          ast::PipelineStage stage,
+                          const bool is_input) const;
+
+    /// Validates a continue statement
+    /// @param stmt the continue statement to validate
+    /// @param current_statement the current statement being resolved
+    /// @returns true on success, false otherwise
+    bool ContinueStatement(const sem::Statement* stmt, sem::Statement* current_statement) const;
+
+    /// Validates a discard statement
+    /// @param stmt the statement to validate
+    /// @param current_statement the current statement being resolved
+    /// @returns true on success, false otherwise
+    bool DiscardStatement(const sem::Statement* stmt, sem::Statement* current_statement) const;
+
+    /// Validates an entry point
+    /// @param func the entry point function to validate
+    /// @param stage the pipeline stage for the entry point
+    /// @returns true on success, false otherwise
+    bool EntryPoint(const sem::Function* func, ast::PipelineStage stage) const;
+
+    /// Validates a for loop
+    /// @param stmt the for loop statement to validate
+    /// @returns true on success, false otherwise
+    bool ForLoopStatement(const sem::ForLoopStatement* stmt) const;
+
+    /// Validates a fallthrough statement
+    /// @param stmt the fallthrough to validate
+    /// @returns true on success, false otherwise
+    bool FallthroughStatement(const sem::Statement* stmt) const;
+
+    /// Validates a function
+    /// @param func the function to validate
+    /// @param stage the current pipeline stage
+    /// @returns true on success, false otherwise.
+    bool Function(const sem::Function* func, ast::PipelineStage stage) const;
+
+    /// Validates a function call
+    /// @param call the function call to validate
+    /// @param current_statement the current statement being resolved
+    /// @returns true on success, false otherwise
+    bool FunctionCall(const sem::Call* call, sem::Statement* current_statement) const;
+
+    /// Validates a global variable
+    /// @param var the global variable to validate
+    /// @param constant_ids the set of constant ids in the module
+    /// @param atomic_composite_info atomic composite info in the module
+    /// @returns true on success, false otherwise
+    bool GlobalVariable(
+        const sem::Variable* var,
+        std::unordered_map<uint32_t, const sem::Variable*> constant_ids,
+        std::unordered_map<const sem::Type*, const Source&> atomic_composite_info) const;
+
+    /// Validates an if statement
+    /// @param stmt the statement to validate
+    /// @returns true on success, false otherwise
+    bool IfStatement(const sem::IfStatement* stmt) const;
+
+    /// Validates an increment or decrement statement
+    /// @param stmt the statement to validate
+    /// @returns true on success, false otherwise
+    bool IncrementDecrementStatement(const ast::IncrementDecrementStatement* stmt) const;
+
+    /// Validates an interpolate attribute
+    /// @param attr the interpolation attribute to validate
+    /// @param storage_type the storage type of the attached variable
+    /// @returns true on succes, false otherwise
+    bool InterpolateAttribute(const ast::InterpolateAttribute* attr,
+                              const sem::Type* storage_type) const;
+
+    /// Validates a builtin call
+    /// @param call the builtin call to validate
+    /// @returns true on success, false otherwise.
+    bool BuiltinCall(const sem::Call* call) const;
+
+    /// Validates a location attribute
+    /// @param location the location attribute to validate
+    /// @param type the variable type
+    /// @param locations the set of locations in the module
+    /// @param stage the current pipeline stage
+    /// @param source the source of the attribute
+    /// @param is_input true if this is an input variable
+    /// @returns true on success, false otherwise.
+    bool LocationAttribute(const ast::LocationAttribute* location,
+                           const sem::Type* type,
+                           std::unordered_set<uint32_t>& locations,
+                           ast::PipelineStage stage,
+                           const Source& source,
+                           const bool is_input = false) const;
+
+    /// Validates a loop statement
+    /// @param stmt the loop statement
+    /// @returns true on success, false otherwise.
+    bool LoopStatement(const sem::LoopStatement* stmt) const;
+
+    /// Validates a matrix
+    /// @param ty the matrix to validate
+    /// @param source the source of the matrix
+    /// @returns true on success, false otherwise
+    bool Matrix(const sem::Matrix* ty, const Source& source) const;
+
+    /// Validates a function parameter
+    /// @param func the function the variable is for
+    /// @param var the variable to validate
+    /// @returns true on success, false otherwise
+    bool FunctionParameter(const ast::Function* func, const sem::Variable* var) const;
+
+    /// Validates a return
+    /// @param ret the return statement to validate
+    /// @param func_type the return type of the curreunt function
+    /// @param ret_type the return type
+    /// @param current_statement the current statement being resolved
+    /// @returns true on success, false otherwise
+    bool Return(const ast::ReturnStatement* ret,
+                const sem::Type* func_type,
+                const sem::Type* ret_type,
+                sem::Statement* current_statement) const;
+
+    /// Validates a list of statements
+    /// @param stmts the statements to validate
+    /// @returns true on success, false otherwise
+    bool Statements(const ast::StatementList& stmts) const;
+
+    /// Validates a storage texture
+    /// @param t the texture to validate
+    /// @returns true on success, false otherwise
+    bool StorageTexture(const ast::StorageTexture* t) const;
+
+    /// Validates a structure
+    /// @param str the structure to validate
+    /// @param stage the current pipeline stage
+    /// @returns true on success, false otherwise.
+    bool Structure(const sem::Struct* str, ast::PipelineStage stage) const;
+
+    /// Validates a structure constructor or cast
+    /// @param ctor the call expression to validate
+    /// @param struct_type the type of the structure
+    /// @returns true on success, false otherwise
+    bool StructureConstructorOrCast(const ast::CallExpression* ctor,
+                                    const sem::Struct* struct_type) const;
+
+    /// Validates a switch statement
+    /// @param s the switch to validate
+    /// @returns true on success, false otherwise
+    bool SwitchStatement(const ast::SwitchStatement* s);
+
+    /// Validates a variable
+    /// @param var the variable to validate
+    /// @returns true on success, false otherwise.
+    bool Variable(const sem::Variable* var) const;
+
+    /// Validates a variable constructor or cast
+    /// @param var the variable to validate
+    /// @param storage_class the storage class of the variable
+    /// @param storage_type the type of the storage
+    /// @param rhs_type the right hand side of the expression
+    /// @returns true on succes, false otherwise
+    bool VariableConstructorOrCast(const ast::Variable* var,
+                                   ast::StorageClass storage_class,
+                                   const sem::Type* storage_type,
+                                   const sem::Type* rhs_type) const;
+
+    /// Validates a vector
+    /// @param ty the vector to validate
+    /// @param source the source of the vector
+    /// @returns true on success, false otherwise
+    bool Vector(const sem::Vector* ty, const Source& source) const;
+
+    /// Validates a vector constructor or cast
+    /// @param ctor the call expression to validate
+    /// @param vec_type the vector type
+    /// @returns true on success, false otherwise
+    bool VectorConstructorOrCast(const ast::CallExpression* ctor,
+                                 const sem::Vector* vec_type) const;
+
+    /// Validates a matrix constructor or cast
+    /// @param ctor the call expression to validate
+    /// @param matrix_type the type of the matrix
+    /// @returns true on success, false otherwise
+    bool MatrixConstructorOrCast(const ast::CallExpression* ctor,
+                                 const sem::Matrix* matrix_type) const;
+
+    /// Validates a scalar constructor or cast
+    /// @param ctor the call expression to validate
+    /// @param type the type of the scalar
+    /// @returns true on success, false otherwise.
+    bool ScalarConstructorOrCast(const ast::CallExpression* ctor, const sem::Type* type) const;
+
+    /// Validates an array constructor or cast
+    /// @param ctor the call expresion to validate
+    /// @param arr_type the type of the array
+    /// @returns true on success, false otherwise
+    bool ArrayConstructorOrCast(const ast::CallExpression* ctor, const sem::Array* arr_type) const;
+
+    /// Validates a texture builtin function
+    /// @param call the builtin call to validate
+    /// @returns true on success, false otherwise
+    bool TextureBuiltinFunction(const sem::Call* call) const;
+
+    /// Validates there are no duplicate attributes
+    /// @param attributes the list of attributes to validate
+    /// @returns true on success, false otherwise.
+    bool NoDuplicateAttributes(const ast::AttributeList& attributes) const;
+
+    /// Validates a storage class layout
+    /// @param type the type to validate
+    /// @param sc the storage class
+    /// @param source the source of the type
+    /// @param layouts previously validated storage layouts
+    /// @returns true on success, false otherwise
+    bool StorageClassLayout(const sem::Type* type,
+                            ast::StorageClass sc,
+                            Source source,
+                            ValidTypeStorageLayouts& layouts) const;
+
+    /// Validates a storage class layout
+    /// @param var the variable to validate
+    /// @param layouts previously validated storage layouts
+    /// @returns true on success, false otherwise.
+    bool StorageClassLayout(const sem::Variable* var, ValidTypeStorageLayouts& layouts) const;
+
+    /// @returns true if the attribute list contains a
+    /// ast::DisableValidationAttribute with the validation mode equal to
+    /// `validation`
+    /// @param attributes the attribute list to check
+    /// @param validation the validation mode to check
+    bool IsValidationDisabled(const ast::AttributeList& attributes,
+                              ast::DisabledValidation validation) const;
+
+    /// @returns true if the attribute list does not contains a
+    /// ast::DisableValidationAttribute with the validation mode equal to
+    /// `validation`
+    /// @param attributes the attribute list to check
+    /// @param validation the validation mode to check
+    bool IsValidationEnabled(const ast::AttributeList& attributes,
+                             ast::DisabledValidation validation) const;
+
+  private:
+    /// Searches the current statement and up through parents of the current
+    /// statement looking for a loop or for-loop continuing statement.
+    /// @returns the closest continuing statement to the current statement that
+    /// (transitively) owns the current statement.
+    /// @param stop_at_loop if true then the function will return nullptr if a
+    /// loop or for-loop was found before the continuing.
+    /// @param current_statement the current statement being resolved
+    const ast::Statement* ClosestContinuing(bool stop_at_loop,
+                                            sem::Statement* current_statement) const;
+
+    /// Returns a human-readable string representation of the vector type name
+    /// with the given parameters.
+    /// @param size the vector dimension
+    /// @param element_type scalar vector sub-element type
+    /// @return pretty string representation
+    std::string VectorPretty(uint32_t size, const sem::Type* element_type) const;
+
+    SymbolTable& symbols_;
+    diag::List& diagnostics_;
+    SemHelper& sem_;
+};
+
+}  // namespace tint::resolver
+
+#endif  // SRC_TINT_RESOLVER_VALIDATOR_H_
diff --git a/src/tint/resolver/validator_is_storeable_test.cc b/src/tint/resolver/validator_is_storeable_test.cc
new file mode 100644
index 0000000..a5f612c
--- /dev/null
+++ b/src/tint/resolver/validator_is_storeable_test.cc
@@ -0,0 +1,86 @@
+// Copyright 2021 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/resolver/validator.h"
+
+#include "gmock/gmock.h"
+#include "src/tint/resolver/resolver_test_helper.h"
+#include "src/tint/sem/atomic.h"
+
+namespace tint::resolver {
+namespace {
+
+using ValidatorIsStorableTest = ResolverTest;
+
+TEST_F(ValidatorIsStorableTest, Void) {
+    EXPECT_FALSE(v()->IsStorable(create<sem::Void>()));
+}
+
+TEST_F(ValidatorIsStorableTest, Scalar) {
+    EXPECT_TRUE(v()->IsStorable(create<sem::Bool>()));
+    EXPECT_TRUE(v()->IsStorable(create<sem::I32>()));
+    EXPECT_TRUE(v()->IsStorable(create<sem::U32>()));
+    EXPECT_TRUE(v()->IsStorable(create<sem::F32>()));
+}
+
+TEST_F(ValidatorIsStorableTest, Vector) {
+    EXPECT_TRUE(v()->IsStorable(create<sem::Vector>(create<sem::I32>(), 2u)));
+    EXPECT_TRUE(v()->IsStorable(create<sem::Vector>(create<sem::I32>(), 3u)));
+    EXPECT_TRUE(v()->IsStorable(create<sem::Vector>(create<sem::I32>(), 4u)));
+    EXPECT_TRUE(v()->IsStorable(create<sem::Vector>(create<sem::U32>(), 2u)));
+    EXPECT_TRUE(v()->IsStorable(create<sem::Vector>(create<sem::U32>(), 3u)));
+    EXPECT_TRUE(v()->IsStorable(create<sem::Vector>(create<sem::U32>(), 4u)));
+    EXPECT_TRUE(v()->IsStorable(create<sem::Vector>(create<sem::F32>(), 2u)));
+    EXPECT_TRUE(v()->IsStorable(create<sem::Vector>(create<sem::F32>(), 3u)));
+    EXPECT_TRUE(v()->IsStorable(create<sem::Vector>(create<sem::F32>(), 4u)));
+}
+
+TEST_F(ValidatorIsStorableTest, Matrix) {
+    auto* vec2 = create<sem::Vector>(create<sem::F32>(), 2u);
+    auto* vec3 = create<sem::Vector>(create<sem::F32>(), 3u);
+    auto* vec4 = create<sem::Vector>(create<sem::F32>(), 4u);
+    EXPECT_TRUE(v()->IsStorable(create<sem::Matrix>(vec2, 2u)));
+    EXPECT_TRUE(v()->IsStorable(create<sem::Matrix>(vec2, 3u)));
+    EXPECT_TRUE(v()->IsStorable(create<sem::Matrix>(vec2, 4u)));
+    EXPECT_TRUE(v()->IsStorable(create<sem::Matrix>(vec3, 2u)));
+    EXPECT_TRUE(v()->IsStorable(create<sem::Matrix>(vec3, 3u)));
+    EXPECT_TRUE(v()->IsStorable(create<sem::Matrix>(vec3, 4u)));
+    EXPECT_TRUE(v()->IsStorable(create<sem::Matrix>(vec4, 2u)));
+    EXPECT_TRUE(v()->IsStorable(create<sem::Matrix>(vec4, 3u)));
+    EXPECT_TRUE(v()->IsStorable(create<sem::Matrix>(vec4, 4u)));
+}
+
+TEST_F(ValidatorIsStorableTest, Pointer) {
+    auto* ptr = create<sem::Pointer>(create<sem::I32>(), ast::StorageClass::kPrivate,
+                                     ast::Access::kReadWrite);
+    EXPECT_FALSE(v()->IsStorable(ptr));
+}
+
+TEST_F(ValidatorIsStorableTest, Atomic) {
+    EXPECT_TRUE(v()->IsStorable(create<sem::Atomic>(create<sem::I32>())));
+    EXPECT_TRUE(v()->IsStorable(create<sem::Atomic>(create<sem::U32>())));
+}
+
+TEST_F(ValidatorIsStorableTest, ArraySizedOfStorable) {
+    auto* arr = create<sem::Array>(create<sem::I32>(), 5u, 4u, 20u, 4u, 4u);
+    EXPECT_TRUE(v()->IsStorable(arr));
+}
+
+TEST_F(ValidatorIsStorableTest, ArrayUnsizedOfStorable) {
+    auto* arr = create<sem::Array>(create<sem::I32>(), 0u, 4u, 4u, 4u, 4u);
+    EXPECT_TRUE(v()->IsStorable(arr));
+}
+
+}  // namespace
+}  // namespace tint::resolver
diff --git a/src/tint/resolver/var_let_test.cc b/src/tint/resolver/var_let_test.cc
index 2ace933..a59855a 100644
--- a/src/tint/resolver/var_let_test.cc
+++ b/src/tint/resolver/var_let_test.cc
@@ -14,681 +14,662 @@
 
 #include "src/tint/resolver/resolver.h"
 #include "src/tint/resolver/resolver_test_helper.h"
-#include "src/tint/sem/reference_type.h"
+#include "src/tint/sem/reference.h"
 
 #include "gmock/gmock.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::resolver {
 namespace {
 
-struct ResolverVarLetTest : public resolver::TestHelper,
-                            public testing::Test {};
+struct ResolverVarLetTest : public resolver::TestHelper, public testing::Test {};
 
 TEST_F(ResolverVarLetTest, VarDeclWithoutConstructor) {
-  // struct S { i : i32; }
-  // alias A = S;
-  // fn F(){
-  //   var i : i32;
-  //   var u : u32;
-  //   var f : f32;
-  //   var b : bool;
-  //   var s : S;
-  //   var a : A;
-  // }
+    // struct S { i : i32; }
+    // alias A = S;
+    // fn F(){
+    //   var i : i32;
+    //   var u : u32;
+    //   var f : f32;
+    //   var b : bool;
+    //   var s : S;
+    //   var a : A;
+    // }
 
-  auto* S = Structure("S", {Member("i", ty.i32())});
-  auto* A = Alias("A", ty.Of(S));
+    auto* S = Structure("S", {Member("i", ty.i32())});
+    auto* A = Alias("A", ty.Of(S));
 
-  auto* i = Var("i", ty.i32(), ast::StorageClass::kNone);
-  auto* u = Var("u", ty.u32(), ast::StorageClass::kNone);
-  auto* f = Var("f", ty.f32(), ast::StorageClass::kNone);
-  auto* b = Var("b", ty.bool_(), ast::StorageClass::kNone);
-  auto* s = Var("s", ty.Of(S), ast::StorageClass::kNone);
-  auto* a = Var("a", ty.Of(A), ast::StorageClass::kNone);
+    auto* i = Var("i", ty.i32(), ast::StorageClass::kNone);
+    auto* u = Var("u", ty.u32(), ast::StorageClass::kNone);
+    auto* f = Var("f", ty.f32(), ast::StorageClass::kNone);
+    auto* b = Var("b", ty.bool_(), ast::StorageClass::kNone);
+    auto* s = Var("s", ty.Of(S), ast::StorageClass::kNone);
+    auto* a = Var("a", ty.Of(A), ast::StorageClass::kNone);
 
-  Func("F", {}, ty.void_(),
-       {
-           Decl(i),
-           Decl(u),
-           Decl(f),
-           Decl(b),
-           Decl(s),
-           Decl(a),
-       });
+    Func("F", {}, ty.void_(),
+         {
+             Decl(i),
+             Decl(u),
+             Decl(f),
+             Decl(b),
+             Decl(s),
+             Decl(a),
+         });
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  // `var` declarations are always of reference type
-  ASSERT_TRUE(TypeOf(i)->Is<sem::Reference>());
-  ASSERT_TRUE(TypeOf(u)->Is<sem::Reference>());
-  ASSERT_TRUE(TypeOf(f)->Is<sem::Reference>());
-  ASSERT_TRUE(TypeOf(b)->Is<sem::Reference>());
-  ASSERT_TRUE(TypeOf(s)->Is<sem::Reference>());
-  ASSERT_TRUE(TypeOf(a)->Is<sem::Reference>());
+    // `var` declarations are always of reference type
+    ASSERT_TRUE(TypeOf(i)->Is<sem::Reference>());
+    ASSERT_TRUE(TypeOf(u)->Is<sem::Reference>());
+    ASSERT_TRUE(TypeOf(f)->Is<sem::Reference>());
+    ASSERT_TRUE(TypeOf(b)->Is<sem::Reference>());
+    ASSERT_TRUE(TypeOf(s)->Is<sem::Reference>());
+    ASSERT_TRUE(TypeOf(a)->Is<sem::Reference>());
 
-  EXPECT_TRUE(TypeOf(i)->As<sem::Reference>()->StoreType()->Is<sem::I32>());
-  EXPECT_TRUE(TypeOf(u)->As<sem::Reference>()->StoreType()->Is<sem::U32>());
-  EXPECT_TRUE(TypeOf(f)->As<sem::Reference>()->StoreType()->Is<sem::F32>());
-  EXPECT_TRUE(TypeOf(b)->As<sem::Reference>()->StoreType()->Is<sem::Bool>());
-  EXPECT_TRUE(TypeOf(s)->As<sem::Reference>()->StoreType()->Is<sem::Struct>());
-  EXPECT_TRUE(TypeOf(a)->As<sem::Reference>()->StoreType()->Is<sem::Struct>());
+    EXPECT_TRUE(TypeOf(i)->As<sem::Reference>()->StoreType()->Is<sem::I32>());
+    EXPECT_TRUE(TypeOf(u)->As<sem::Reference>()->StoreType()->Is<sem::U32>());
+    EXPECT_TRUE(TypeOf(f)->As<sem::Reference>()->StoreType()->Is<sem::F32>());
+    EXPECT_TRUE(TypeOf(b)->As<sem::Reference>()->StoreType()->Is<sem::Bool>());
+    EXPECT_TRUE(TypeOf(s)->As<sem::Reference>()->StoreType()->Is<sem::Struct>());
+    EXPECT_TRUE(TypeOf(a)->As<sem::Reference>()->StoreType()->Is<sem::Struct>());
 
-  EXPECT_EQ(Sem().Get(i)->Constructor(), nullptr);
-  EXPECT_EQ(Sem().Get(u)->Constructor(), nullptr);
-  EXPECT_EQ(Sem().Get(f)->Constructor(), nullptr);
-  EXPECT_EQ(Sem().Get(b)->Constructor(), nullptr);
-  EXPECT_EQ(Sem().Get(s)->Constructor(), nullptr);
-  EXPECT_EQ(Sem().Get(a)->Constructor(), nullptr);
+    EXPECT_EQ(Sem().Get(i)->Constructor(), nullptr);
+    EXPECT_EQ(Sem().Get(u)->Constructor(), nullptr);
+    EXPECT_EQ(Sem().Get(f)->Constructor(), nullptr);
+    EXPECT_EQ(Sem().Get(b)->Constructor(), nullptr);
+    EXPECT_EQ(Sem().Get(s)->Constructor(), nullptr);
+    EXPECT_EQ(Sem().Get(a)->Constructor(), nullptr);
 }
 
 TEST_F(ResolverVarLetTest, VarDeclWithConstructor) {
-  // struct S { i : i32; }
-  // alias A = S;
-  // fn F(){
-  //   var i : i32 = 1;
-  //   var u : u32 = 1u;
-  //   var f : f32 = 1.f;
-  //   var b : bool = true;
-  //   var s : S = S(1);
-  //   var a : A = A(1);
-  // }
+    // struct S { i : i32; }
+    // alias A = S;
+    // fn F(){
+    //   var i : i32 = 1;
+    //   var u : u32 = 1u;
+    //   var f : f32 = 1.f;
+    //   var b : bool = true;
+    //   var s : S = S(1);
+    //   var a : A = A(1);
+    // }
 
-  auto* S = Structure("S", {Member("i", ty.i32())});
-  auto* A = Alias("A", ty.Of(S));
+    auto* S = Structure("S", {Member("i", ty.i32())});
+    auto* A = Alias("A", ty.Of(S));
 
-  auto* i_c = Expr(1);
-  auto* u_c = Expr(1u);
-  auto* f_c = Expr(1.f);
-  auto* b_c = Expr(true);
-  auto* s_c = Construct(ty.Of(S), Expr(1));
-  auto* a_c = Construct(ty.Of(A), Expr(1));
+    auto* i_c = Expr(1_i);
+    auto* u_c = Expr(1_u);
+    auto* f_c = Expr(1.f);
+    auto* b_c = Expr(true);
+    auto* s_c = Construct(ty.Of(S), Expr(1_i));
+    auto* a_c = Construct(ty.Of(A), Expr(1_i));
 
-  auto* i = Var("i", ty.i32(), ast::StorageClass::kNone, i_c);
-  auto* u = Var("u", ty.u32(), ast::StorageClass::kNone, u_c);
-  auto* f = Var("f", ty.f32(), ast::StorageClass::kNone, f_c);
-  auto* b = Var("b", ty.bool_(), ast::StorageClass::kNone, b_c);
-  auto* s = Var("s", ty.Of(S), ast::StorageClass::kNone, s_c);
-  auto* a = Var("a", ty.Of(A), ast::StorageClass::kNone, a_c);
+    auto* i = Var("i", ty.i32(), ast::StorageClass::kNone, i_c);
+    auto* u = Var("u", ty.u32(), ast::StorageClass::kNone, u_c);
+    auto* f = Var("f", ty.f32(), ast::StorageClass::kNone, f_c);
+    auto* b = Var("b", ty.bool_(), ast::StorageClass::kNone, b_c);
+    auto* s = Var("s", ty.Of(S), ast::StorageClass::kNone, s_c);
+    auto* a = Var("a", ty.Of(A), ast::StorageClass::kNone, a_c);
 
-  Func("F", {}, ty.void_(),
-       {
-           Decl(i),
-           Decl(u),
-           Decl(f),
-           Decl(b),
-           Decl(s),
-           Decl(a),
-       });
+    Func("F", {}, ty.void_(),
+         {
+             Decl(i),
+             Decl(u),
+             Decl(f),
+             Decl(b),
+             Decl(s),
+             Decl(a),
+         });
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  // `var` declarations are always of reference type
-  ASSERT_TRUE(TypeOf(i)->Is<sem::Reference>());
-  ASSERT_TRUE(TypeOf(u)->Is<sem::Reference>());
-  ASSERT_TRUE(TypeOf(f)->Is<sem::Reference>());
-  ASSERT_TRUE(TypeOf(b)->Is<sem::Reference>());
-  ASSERT_TRUE(TypeOf(s)->Is<sem::Reference>());
-  ASSERT_TRUE(TypeOf(a)->Is<sem::Reference>());
+    // `var` declarations are always of reference type
+    ASSERT_TRUE(TypeOf(i)->Is<sem::Reference>());
+    ASSERT_TRUE(TypeOf(u)->Is<sem::Reference>());
+    ASSERT_TRUE(TypeOf(f)->Is<sem::Reference>());
+    ASSERT_TRUE(TypeOf(b)->Is<sem::Reference>());
+    ASSERT_TRUE(TypeOf(s)->Is<sem::Reference>());
+    ASSERT_TRUE(TypeOf(a)->Is<sem::Reference>());
 
-  EXPECT_TRUE(TypeOf(i)->As<sem::Reference>()->StoreType()->Is<sem::I32>());
-  EXPECT_TRUE(TypeOf(u)->As<sem::Reference>()->StoreType()->Is<sem::U32>());
-  EXPECT_TRUE(TypeOf(f)->As<sem::Reference>()->StoreType()->Is<sem::F32>());
-  EXPECT_TRUE(TypeOf(b)->As<sem::Reference>()->StoreType()->Is<sem::Bool>());
-  EXPECT_TRUE(TypeOf(s)->As<sem::Reference>()->StoreType()->Is<sem::Struct>());
-  EXPECT_TRUE(TypeOf(a)->As<sem::Reference>()->StoreType()->Is<sem::Struct>());
+    EXPECT_TRUE(TypeOf(i)->As<sem::Reference>()->StoreType()->Is<sem::I32>());
+    EXPECT_TRUE(TypeOf(u)->As<sem::Reference>()->StoreType()->Is<sem::U32>());
+    EXPECT_TRUE(TypeOf(f)->As<sem::Reference>()->StoreType()->Is<sem::F32>());
+    EXPECT_TRUE(TypeOf(b)->As<sem::Reference>()->StoreType()->Is<sem::Bool>());
+    EXPECT_TRUE(TypeOf(s)->As<sem::Reference>()->StoreType()->Is<sem::Struct>());
+    EXPECT_TRUE(TypeOf(a)->As<sem::Reference>()->StoreType()->Is<sem::Struct>());
 
-  EXPECT_EQ(Sem().Get(i)->Constructor()->Declaration(), i_c);
-  EXPECT_EQ(Sem().Get(u)->Constructor()->Declaration(), u_c);
-  EXPECT_EQ(Sem().Get(f)->Constructor()->Declaration(), f_c);
-  EXPECT_EQ(Sem().Get(b)->Constructor()->Declaration(), b_c);
-  EXPECT_EQ(Sem().Get(s)->Constructor()->Declaration(), s_c);
-  EXPECT_EQ(Sem().Get(a)->Constructor()->Declaration(), a_c);
+    EXPECT_EQ(Sem().Get(i)->Constructor()->Declaration(), i_c);
+    EXPECT_EQ(Sem().Get(u)->Constructor()->Declaration(), u_c);
+    EXPECT_EQ(Sem().Get(f)->Constructor()->Declaration(), f_c);
+    EXPECT_EQ(Sem().Get(b)->Constructor()->Declaration(), b_c);
+    EXPECT_EQ(Sem().Get(s)->Constructor()->Declaration(), s_c);
+    EXPECT_EQ(Sem().Get(a)->Constructor()->Declaration(), a_c);
 }
 
 TEST_F(ResolverVarLetTest, LetDecl) {
-  // struct S { i : i32; }
-  // fn F(){
-  //   var v : i32;
-  //   let i : i32 = 1;
-  //   let u : u32 = 1u;
-  //   let f : f32 = 1.;
-  //   let b : bool = true;
-  //   let s : S = S(1);
-  //   let a : A = A(1);
-  //   let p : pointer<function, i32> = &v;
-  // }
+    // struct S { i : i32; }
+    // fn F(){
+    //   var v : i32;
+    //   let i : i32 = 1i;
+    //   let u : u32 = 1u;
+    //   let f : f32 = 1.;
+    //   let b : bool = true;
+    //   let s : S = S(1);
+    //   let a : A = A(1);
+    //   let p : pointer<function, i32> = &v;
+    // }
 
-  auto* S = Structure("S", {Member("i", ty.i32())});
-  auto* A = Alias("A", ty.Of(S));
-  auto* v = Var("v", ty.i32(), ast::StorageClass::kNone);
+    auto* S = Structure("S", {Member("i", ty.i32())});
+    auto* A = Alias("A", ty.Of(S));
+    auto* v = Var("v", ty.i32(), ast::StorageClass::kNone);
 
-  auto* i_c = Expr(1);
-  auto* u_c = Expr(1u);
-  auto* f_c = Expr(1.f);
-  auto* b_c = Expr(true);
-  auto* s_c = Construct(ty.Of(S), Expr(1));
-  auto* a_c = Construct(ty.Of(A), Expr(1));
-  auto* p_c = AddressOf(v);
+    auto* i_c = Expr(1_i);
+    auto* u_c = Expr(1_u);
+    auto* f_c = Expr(1.f);
+    auto* b_c = Expr(true);
+    auto* s_c = Construct(ty.Of(S), Expr(1_i));
+    auto* a_c = Construct(ty.Of(A), Expr(1_i));
+    auto* p_c = AddressOf(v);
 
-  auto* i = Const("i", ty.i32(), i_c);
-  auto* u = Const("u", ty.u32(), u_c);
-  auto* f = Const("f", ty.f32(), f_c);
-  auto* b = Const("b", ty.bool_(), b_c);
-  auto* s = Const("s", ty.Of(S), s_c);
-  auto* a = Const("a", ty.Of(A), a_c);
-  auto* p = Const("p", ty.pointer<i32>(ast::StorageClass::kFunction), p_c);
+    auto* i = Let("i", ty.i32(), i_c);
+    auto* u = Let("u", ty.u32(), u_c);
+    auto* f = Let("f", ty.f32(), f_c);
+    auto* b = Let("b", ty.bool_(), b_c);
+    auto* s = Let("s", ty.Of(S), s_c);
+    auto* a = Let("a", ty.Of(A), a_c);
+    auto* p = Let("p", ty.pointer<i32>(ast::StorageClass::kFunction), p_c);
 
-  Func("F", {}, ty.void_(),
-       {
-           Decl(v),
-           Decl(i),
-           Decl(u),
-           Decl(f),
-           Decl(b),
-           Decl(s),
-           Decl(a),
-           Decl(p),
-       });
+    Func("F", {}, ty.void_(),
+         {
+             Decl(v),
+             Decl(i),
+             Decl(u),
+             Decl(f),
+             Decl(b),
+             Decl(s),
+             Decl(a),
+             Decl(p),
+         });
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  // `let` declarations are always of the storage type
-  ASSERT_TRUE(TypeOf(i)->Is<sem::I32>());
-  ASSERT_TRUE(TypeOf(u)->Is<sem::U32>());
-  ASSERT_TRUE(TypeOf(f)->Is<sem::F32>());
-  ASSERT_TRUE(TypeOf(b)->Is<sem::Bool>());
-  ASSERT_TRUE(TypeOf(s)->Is<sem::Struct>());
-  ASSERT_TRUE(TypeOf(a)->Is<sem::Struct>());
-  ASSERT_TRUE(TypeOf(p)->Is<sem::Pointer>());
-  ASSERT_TRUE(TypeOf(p)->As<sem::Pointer>()->StoreType()->Is<sem::I32>());
+    // `let` declarations are always of the storage type
+    ASSERT_TRUE(TypeOf(i)->Is<sem::I32>());
+    ASSERT_TRUE(TypeOf(u)->Is<sem::U32>());
+    ASSERT_TRUE(TypeOf(f)->Is<sem::F32>());
+    ASSERT_TRUE(TypeOf(b)->Is<sem::Bool>());
+    ASSERT_TRUE(TypeOf(s)->Is<sem::Struct>());
+    ASSERT_TRUE(TypeOf(a)->Is<sem::Struct>());
+    ASSERT_TRUE(TypeOf(p)->Is<sem::Pointer>());
+    ASSERT_TRUE(TypeOf(p)->As<sem::Pointer>()->StoreType()->Is<sem::I32>());
 
-  EXPECT_EQ(Sem().Get(i)->Constructor()->Declaration(), i_c);
-  EXPECT_EQ(Sem().Get(u)->Constructor()->Declaration(), u_c);
-  EXPECT_EQ(Sem().Get(f)->Constructor()->Declaration(), f_c);
-  EXPECT_EQ(Sem().Get(b)->Constructor()->Declaration(), b_c);
-  EXPECT_EQ(Sem().Get(s)->Constructor()->Declaration(), s_c);
-  EXPECT_EQ(Sem().Get(a)->Constructor()->Declaration(), a_c);
-  EXPECT_EQ(Sem().Get(p)->Constructor()->Declaration(), p_c);
+    EXPECT_EQ(Sem().Get(i)->Constructor()->Declaration(), i_c);
+    EXPECT_EQ(Sem().Get(u)->Constructor()->Declaration(), u_c);
+    EXPECT_EQ(Sem().Get(f)->Constructor()->Declaration(), f_c);
+    EXPECT_EQ(Sem().Get(b)->Constructor()->Declaration(), b_c);
+    EXPECT_EQ(Sem().Get(s)->Constructor()->Declaration(), s_c);
+    EXPECT_EQ(Sem().Get(a)->Constructor()->Declaration(), a_c);
+    EXPECT_EQ(Sem().Get(p)->Constructor()->Declaration(), p_c);
 }
 
 TEST_F(ResolverVarLetTest, DefaultVarStorageClass) {
-  // https://gpuweb.github.io/gpuweb/wgsl/#storage-class
+    // https://gpuweb.github.io/gpuweb/wgsl/#storage-class
 
-  auto* buf = Structure("S", {Member("m", ty.i32())});
-  auto* function = Var("f", ty.i32());
-  auto* private_ = Global("p", ty.i32(), ast::StorageClass::kPrivate);
-  auto* workgroup = Global("w", ty.i32(), ast::StorageClass::kWorkgroup);
-  auto* uniform = Global("ub", ty.Of(buf), ast::StorageClass::kUniform,
-                         ast::AttributeList{
-                             create<ast::BindingAttribute>(0),
-                             create<ast::GroupAttribute>(0),
-                         });
-  auto* storage = Global("sb", ty.Of(buf), ast::StorageClass::kStorage,
-                         ast::AttributeList{
-                             create<ast::BindingAttribute>(1),
-                             create<ast::GroupAttribute>(0),
-                         });
-  auto* handle = Global("h", ty.depth_texture(ast::TextureDimension::k2d),
-                        ast::AttributeList{
-                            create<ast::BindingAttribute>(2),
-                            create<ast::GroupAttribute>(0),
-                        });
+    auto* buf = Structure("S", {Member("m", ty.i32())});
+    auto* function = Var("f", ty.i32());
+    auto* private_ = Global("p", ty.i32(), ast::StorageClass::kPrivate);
+    auto* workgroup = Global("w", ty.i32(), ast::StorageClass::kWorkgroup);
+    auto* uniform = Global("ub", ty.Of(buf), ast::StorageClass::kUniform,
+                           ast::AttributeList{
+                               create<ast::BindingAttribute>(0),
+                               create<ast::GroupAttribute>(0),
+                           });
+    auto* storage = Global("sb", ty.Of(buf), ast::StorageClass::kStorage,
+                           ast::AttributeList{
+                               create<ast::BindingAttribute>(1),
+                               create<ast::GroupAttribute>(0),
+                           });
+    auto* handle = Global("h", ty.depth_texture(ast::TextureDimension::k2d),
+                          ast::AttributeList{
+                              create<ast::BindingAttribute>(2),
+                              create<ast::GroupAttribute>(0),
+                          });
 
-  WrapInFunction(function);
+    WrapInFunction(function);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_TRUE(TypeOf(function)->Is<sem::Reference>());
-  ASSERT_TRUE(TypeOf(private_)->Is<sem::Reference>());
-  ASSERT_TRUE(TypeOf(workgroup)->Is<sem::Reference>());
-  ASSERT_TRUE(TypeOf(uniform)->Is<sem::Reference>());
-  ASSERT_TRUE(TypeOf(storage)->Is<sem::Reference>());
-  ASSERT_TRUE(TypeOf(handle)->Is<sem::Reference>());
+    ASSERT_TRUE(TypeOf(function)->Is<sem::Reference>());
+    ASSERT_TRUE(TypeOf(private_)->Is<sem::Reference>());
+    ASSERT_TRUE(TypeOf(workgroup)->Is<sem::Reference>());
+    ASSERT_TRUE(TypeOf(uniform)->Is<sem::Reference>());
+    ASSERT_TRUE(TypeOf(storage)->Is<sem::Reference>());
+    ASSERT_TRUE(TypeOf(handle)->Is<sem::Reference>());
 
-  EXPECT_EQ(TypeOf(function)->As<sem::Reference>()->Access(),
-            ast::Access::kReadWrite);
-  EXPECT_EQ(TypeOf(private_)->As<sem::Reference>()->Access(),
-            ast::Access::kReadWrite);
-  EXPECT_EQ(TypeOf(workgroup)->As<sem::Reference>()->Access(),
-            ast::Access::kReadWrite);
-  EXPECT_EQ(TypeOf(uniform)->As<sem::Reference>()->Access(),
-            ast::Access::kRead);
-  EXPECT_EQ(TypeOf(storage)->As<sem::Reference>()->Access(),
-            ast::Access::kRead);
-  EXPECT_EQ(TypeOf(handle)->As<sem::Reference>()->Access(), ast::Access::kRead);
+    EXPECT_EQ(TypeOf(function)->As<sem::Reference>()->Access(), ast::Access::kReadWrite);
+    EXPECT_EQ(TypeOf(private_)->As<sem::Reference>()->Access(), ast::Access::kReadWrite);
+    EXPECT_EQ(TypeOf(workgroup)->As<sem::Reference>()->Access(), ast::Access::kReadWrite);
+    EXPECT_EQ(TypeOf(uniform)->As<sem::Reference>()->Access(), ast::Access::kRead);
+    EXPECT_EQ(TypeOf(storage)->As<sem::Reference>()->Access(), ast::Access::kRead);
+    EXPECT_EQ(TypeOf(handle)->As<sem::Reference>()->Access(), ast::Access::kRead);
 }
 
 TEST_F(ResolverVarLetTest, ExplicitVarStorageClass) {
-  // https://gpuweb.github.io/gpuweb/wgsl/#storage-class
+    // https://gpuweb.github.io/gpuweb/wgsl/#storage-class
 
-  auto* buf = Structure("S", {Member("m", ty.i32())});
-  auto* storage = Global("sb", ty.Of(buf), ast::StorageClass::kStorage,
-                         ast::Access::kReadWrite,
-                         ast::AttributeList{
-                             create<ast::BindingAttribute>(1),
-                             create<ast::GroupAttribute>(0),
-                         });
+    auto* buf = Structure("S", {Member("m", ty.i32())});
+    auto* storage = Global("sb", ty.Of(buf), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+                           ast::AttributeList{
+                               create<ast::BindingAttribute>(1),
+                               create<ast::GroupAttribute>(0),
+                           });
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_TRUE(TypeOf(storage)->Is<sem::Reference>());
+    ASSERT_TRUE(TypeOf(storage)->Is<sem::Reference>());
 
-  EXPECT_EQ(TypeOf(storage)->As<sem::Reference>()->Access(),
-            ast::Access::kReadWrite);
+    EXPECT_EQ(TypeOf(storage)->As<sem::Reference>()->Access(), ast::Access::kReadWrite);
 }
 
 TEST_F(ResolverVarLetTest, LetInheritsAccessFromOriginatingVariable) {
-  // struct Inner {
-  //    arr: array<i32, 4>;
-  // }
-  // struct S {
-  //    inner: Inner;
-  // }
-  // @group(0) @binding(0) var<storage, read_write> s : S;
-  // fn f() {
-  //   let p = &s.inner.arr[2];
-  // }
-  auto* inner = Structure("Inner", {Member("arr", ty.array<i32, 4>())});
-  auto* buf = Structure("S", {Member("inner", ty.Of(inner))});
-  auto* storage = Global("s", ty.Of(buf), ast::StorageClass::kStorage,
-                         ast::Access::kReadWrite,
-                         ast::AttributeList{
-                             create<ast::BindingAttribute>(0),
-                             create<ast::GroupAttribute>(0),
-                         });
+    // struct Inner {
+    //    arr: array<i32, 4>;
+    // }
+    // struct S {
+    //    inner: Inner;
+    // }
+    // @group(0) @binding(0) var<storage, read_write> s : S;
+    // fn f() {
+    //   let p = &s.inner.arr[4];
+    // }
+    auto* inner = Structure("Inner", {Member("arr", ty.array<i32, 4>())});
+    auto* buf = Structure("S", {Member("inner", ty.Of(inner))});
+    auto* storage = Global("s", ty.Of(buf), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+                           ast::AttributeList{
+                               create<ast::BindingAttribute>(0),
+                               create<ast::GroupAttribute>(0),
+                           });
 
-  auto* expr =
-      IndexAccessor(MemberAccessor(MemberAccessor(storage, "inner"), "arr"), 4);
-  auto* ptr = Const("p", nullptr, AddressOf(expr));
+    auto* expr = IndexAccessor(MemberAccessor(MemberAccessor(storage, "inner"), "arr"), 4_i);
+    auto* ptr = Let("p", nullptr, AddressOf(expr));
 
-  WrapInFunction(ptr);
+    WrapInFunction(ptr);
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  ASSERT_TRUE(TypeOf(expr)->Is<sem::Reference>());
-  ASSERT_TRUE(TypeOf(ptr)->Is<sem::Pointer>());
+    ASSERT_TRUE(TypeOf(expr)->Is<sem::Reference>());
+    ASSERT_TRUE(TypeOf(ptr)->Is<sem::Pointer>());
 
-  EXPECT_EQ(TypeOf(expr)->As<sem::Reference>()->Access(),
-            ast::Access::kReadWrite);
-  EXPECT_EQ(TypeOf(ptr)->As<sem::Pointer>()->Access(), ast::Access::kReadWrite);
+    EXPECT_EQ(TypeOf(expr)->As<sem::Reference>()->Access(), ast::Access::kReadWrite);
+    EXPECT_EQ(TypeOf(ptr)->As<sem::Pointer>()->Access(), ast::Access::kReadWrite);
 }
 
 TEST_F(ResolverVarLetTest, LocalShadowsAlias) {
-  // type a = i32;
-  //
-  // fn X() {
-  //   var a = false;
-  // }
-  //
-  // fn Y() {
-  //   let a = true;
-  // }
+    // type a = i32;
+    //
+    // fn X() {
+    //   var a = false;
+    // }
+    //
+    // fn Y() {
+    //   let a = true;
+    // }
 
-  auto* t = Alias("a", ty.i32());
-  auto* v = Var("a", nullptr, Expr(false));
-  auto* l = Const("a", nullptr, Expr(false));
-  Func("X", {}, ty.void_(), {Decl(v)});
-  Func("Y", {}, ty.void_(), {Decl(l)});
+    auto* t = Alias("a", ty.i32());
+    auto* v = Var("a", nullptr, Expr(false));
+    auto* l = Let("a", nullptr, Expr(false));
+    Func("X", {}, ty.void_(), {Decl(v)});
+    Func("Y", {}, ty.void_(), {Decl(l)});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* type_t = Sem().Get(t);
-  auto* local_v = Sem().Get<sem::LocalVariable>(v);
-  auto* local_l = Sem().Get<sem::LocalVariable>(l);
+    auto* type_t = Sem().Get(t);
+    auto* local_v = Sem().Get<sem::LocalVariable>(v);
+    auto* local_l = Sem().Get<sem::LocalVariable>(l);
 
-  ASSERT_NE(local_v, nullptr);
-  ASSERT_NE(local_l, nullptr);
+    ASSERT_NE(local_v, nullptr);
+    ASSERT_NE(local_l, nullptr);
 
-  EXPECT_EQ(local_v->Shadows(), type_t);
-  EXPECT_EQ(local_l->Shadows(), type_t);
+    EXPECT_EQ(local_v->Shadows(), type_t);
+    EXPECT_EQ(local_l->Shadows(), type_t);
 }
 
 TEST_F(ResolverVarLetTest, LocalShadowsStruct) {
-  // struct a {
-  //   m : i32;
-  // };
-  //
-  // fn X() {
-  //   var a = true;
-  // }
-  //
-  // fn Y() {
-  //   let a = false;
-  // }
+    // struct a {
+    //   m : i32;
+    // };
+    //
+    // fn X() {
+    //   var a = true;
+    // }
+    //
+    // fn Y() {
+    //   let a = false;
+    // }
 
-  auto* t = Structure("a", {Member("m", ty.i32())});
-  auto* v = Var("a", nullptr, Expr(false));
-  auto* l = Const("a", nullptr, Expr(false));
-  Func("X", {}, ty.void_(), {Decl(v)});
-  Func("Y", {}, ty.void_(), {Decl(l)});
+    auto* t = Structure("a", {Member("m", ty.i32())});
+    auto* v = Var("a", nullptr, Expr(false));
+    auto* l = Let("a", nullptr, Expr(false));
+    Func("X", {}, ty.void_(), {Decl(v)});
+    Func("Y", {}, ty.void_(), {Decl(l)});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* type_t = Sem().Get(t);
-  auto* local_v = Sem().Get<sem::LocalVariable>(v);
-  auto* local_l = Sem().Get<sem::LocalVariable>(l);
+    auto* type_t = Sem().Get(t);
+    auto* local_v = Sem().Get<sem::LocalVariable>(v);
+    auto* local_l = Sem().Get<sem::LocalVariable>(l);
 
-  ASSERT_NE(local_v, nullptr);
-  ASSERT_NE(local_l, nullptr);
+    ASSERT_NE(local_v, nullptr);
+    ASSERT_NE(local_l, nullptr);
 
-  EXPECT_EQ(local_v->Shadows(), type_t);
-  EXPECT_EQ(local_l->Shadows(), type_t);
+    EXPECT_EQ(local_v->Shadows(), type_t);
+    EXPECT_EQ(local_l->Shadows(), type_t);
 }
 
 TEST_F(ResolverVarLetTest, LocalShadowsFunction) {
-  // fn a() {
-  //   var a = true;
-  // }
-  //
-  // fn b() {
-  //   let b = false;
-  // }
+    // fn a() {
+    //   var a = true;
+    // }
+    //
+    // fn b() {
+    //   let b = false;
+    // }
 
-  auto* v = Var("a", nullptr, Expr(false));
-  auto* l = Const("b", nullptr, Expr(false));
-  auto* fa = Func("a", {}, ty.void_(), {Decl(v)});
-  auto* fb = Func("b", {}, ty.void_(), {Decl(l)});
+    auto* v = Var("a", nullptr, Expr(false));
+    auto* l = Let("b", nullptr, Expr(false));
+    auto* fa = Func("a", {}, ty.void_(), {Decl(v)});
+    auto* fb = Func("b", {}, ty.void_(), {Decl(l)});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* local_v = Sem().Get<sem::LocalVariable>(v);
-  auto* local_l = Sem().Get<sem::LocalVariable>(l);
-  auto* func_a = Sem().Get(fa);
-  auto* func_b = Sem().Get(fb);
+    auto* local_v = Sem().Get<sem::LocalVariable>(v);
+    auto* local_l = Sem().Get<sem::LocalVariable>(l);
+    auto* func_a = Sem().Get(fa);
+    auto* func_b = Sem().Get(fb);
 
-  ASSERT_NE(local_v, nullptr);
-  ASSERT_NE(local_l, nullptr);
-  ASSERT_NE(func_a, nullptr);
-  ASSERT_NE(func_b, nullptr);
+    ASSERT_NE(local_v, nullptr);
+    ASSERT_NE(local_l, nullptr);
+    ASSERT_NE(func_a, nullptr);
+    ASSERT_NE(func_b, nullptr);
 
-  EXPECT_EQ(local_v->Shadows(), func_a);
-  EXPECT_EQ(local_l->Shadows(), func_b);
+    EXPECT_EQ(local_v->Shadows(), func_a);
+    EXPECT_EQ(local_l->Shadows(), func_b);
 }
 
 TEST_F(ResolverVarLetTest, LocalShadowsGlobalVar) {
-  // var<private> a : i32;
-  //
-  // fn X() {
-  //   var a = a;
-  // }
-  //
-  // fn Y() {
-  //   let a = a;
-  // }
+    // var<private> a : i32;
+    //
+    // fn X() {
+    //   var a = a;
+    // }
+    //
+    // fn Y() {
+    //   let a = a;
+    // }
 
-  auto* g = Global("a", ty.i32(), ast::StorageClass::kPrivate);
-  auto* v = Var("a", nullptr, Expr("a"));
-  auto* l = Const("a", nullptr, Expr("a"));
-  Func("X", {}, ty.void_(), {Decl(v)});
-  Func("Y", {}, ty.void_(), {Decl(l)});
+    auto* g = Global("a", ty.i32(), ast::StorageClass::kPrivate);
+    auto* v = Var("a", nullptr, Expr("a"));
+    auto* l = Let("a", nullptr, Expr("a"));
+    Func("X", {}, ty.void_(), {Decl(v)});
+    Func("Y", {}, ty.void_(), {Decl(l)});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* global = Sem().Get(g);
-  auto* local_v = Sem().Get<sem::LocalVariable>(v);
-  auto* local_l = Sem().Get<sem::LocalVariable>(l);
+    auto* global = Sem().Get(g);
+    auto* local_v = Sem().Get<sem::LocalVariable>(v);
+    auto* local_l = Sem().Get<sem::LocalVariable>(l);
 
-  ASSERT_NE(local_v, nullptr);
-  ASSERT_NE(local_l, nullptr);
+    ASSERT_NE(local_v, nullptr);
+    ASSERT_NE(local_l, nullptr);
 
-  EXPECT_EQ(local_v->Shadows(), global);
-  EXPECT_EQ(local_l->Shadows(), global);
+    EXPECT_EQ(local_v->Shadows(), global);
+    EXPECT_EQ(local_l->Shadows(), global);
 
-  auto* user_v =
-      Sem().Get<sem::VariableUser>(local_v->Declaration()->constructor);
-  auto* user_l =
-      Sem().Get<sem::VariableUser>(local_l->Declaration()->constructor);
+    auto* user_v = Sem().Get<sem::VariableUser>(local_v->Declaration()->constructor);
+    auto* user_l = Sem().Get<sem::VariableUser>(local_l->Declaration()->constructor);
 
-  ASSERT_NE(user_v, nullptr);
-  ASSERT_NE(user_l, nullptr);
+    ASSERT_NE(user_v, nullptr);
+    ASSERT_NE(user_l, nullptr);
 
-  EXPECT_EQ(user_v->Variable(), global);
-  EXPECT_EQ(user_l->Variable(), global);
+    EXPECT_EQ(user_v->Variable(), global);
+    EXPECT_EQ(user_l->Variable(), global);
 }
 
 TEST_F(ResolverVarLetTest, LocalShadowsGlobalLet) {
-  // let a : i32 = 1;
-  //
-  // fn X() {
-  //   var a = (a == 123);
-  // }
-  //
-  // fn Y() {
-  //   let a = (a == 321);
-  // }
+    // let a : i32 = 1;
+    //
+    // fn X() {
+    //   var a = (a == 123);
+    // }
+    //
+    // fn Y() {
+    //   let a = (a == 321);
+    // }
 
-  auto* g = GlobalConst("a", ty.i32(), Expr(1));
-  auto* v = Var("a", nullptr, Expr("a"));
-  auto* l = Const("a", nullptr, Expr("a"));
-  Func("X", {}, ty.void_(), {Decl(v)});
-  Func("Y", {}, ty.void_(), {Decl(l)});
+    auto* g = GlobalConst("a", ty.i32(), Expr(1_i));
+    auto* v = Var("a", nullptr, Expr("a"));
+    auto* l = Let("a", nullptr, Expr("a"));
+    Func("X", {}, ty.void_(), {Decl(v)});
+    Func("Y", {}, ty.void_(), {Decl(l)});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* global = Sem().Get(g);
-  auto* local_v = Sem().Get<sem::LocalVariable>(v);
-  auto* local_l = Sem().Get<sem::LocalVariable>(l);
+    auto* global = Sem().Get(g);
+    auto* local_v = Sem().Get<sem::LocalVariable>(v);
+    auto* local_l = Sem().Get<sem::LocalVariable>(l);
 
-  ASSERT_NE(local_v, nullptr);
-  ASSERT_NE(local_l, nullptr);
+    ASSERT_NE(local_v, nullptr);
+    ASSERT_NE(local_l, nullptr);
 
-  EXPECT_EQ(local_v->Shadows(), global);
-  EXPECT_EQ(local_l->Shadows(), global);
+    EXPECT_EQ(local_v->Shadows(), global);
+    EXPECT_EQ(local_l->Shadows(), global);
 
-  auto* user_v =
-      Sem().Get<sem::VariableUser>(local_v->Declaration()->constructor);
-  auto* user_l =
-      Sem().Get<sem::VariableUser>(local_l->Declaration()->constructor);
+    auto* user_v = Sem().Get<sem::VariableUser>(local_v->Declaration()->constructor);
+    auto* user_l = Sem().Get<sem::VariableUser>(local_l->Declaration()->constructor);
 
-  ASSERT_NE(user_v, nullptr);
-  ASSERT_NE(user_l, nullptr);
+    ASSERT_NE(user_v, nullptr);
+    ASSERT_NE(user_l, nullptr);
 
-  EXPECT_EQ(user_v->Variable(), global);
-  EXPECT_EQ(user_l->Variable(), global);
+    EXPECT_EQ(user_v->Variable(), global);
+    EXPECT_EQ(user_l->Variable(), global);
 }
 
 TEST_F(ResolverVarLetTest, LocalShadowsLocalVar) {
-  // fn X() {
-  //   var a : i32;
-  //   {
-  //     var a = a;
-  //   }
-  //   {
-  //     let a = a;
-  //   }
-  // }
+    // fn X() {
+    //   var a : i32;
+    //   {
+    //     var a = a;
+    //   }
+    //   {
+    //     let a = a;
+    //   }
+    // }
 
-  auto* s = Var("a", ty.i32(), Expr(1));
-  auto* v = Var("a", nullptr, Expr("a"));
-  auto* l = Const("a", nullptr, Expr("a"));
-  Func("X", {}, ty.void_(), {Decl(s), Block(Decl(v)), Block(Decl(l))});
+    auto* s = Var("a", ty.i32(), Expr(1_i));
+    auto* v = Var("a", nullptr, Expr("a"));
+    auto* l = Let("a", nullptr, Expr("a"));
+    Func("X", {}, ty.void_(), {Decl(s), Block(Decl(v)), Block(Decl(l))});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* local_s = Sem().Get<sem::LocalVariable>(s);
-  auto* local_v = Sem().Get<sem::LocalVariable>(v);
-  auto* local_l = Sem().Get<sem::LocalVariable>(l);
+    auto* local_s = Sem().Get<sem::LocalVariable>(s);
+    auto* local_v = Sem().Get<sem::LocalVariable>(v);
+    auto* local_l = Sem().Get<sem::LocalVariable>(l);
 
-  ASSERT_NE(local_s, nullptr);
-  ASSERT_NE(local_v, nullptr);
-  ASSERT_NE(local_l, nullptr);
+    ASSERT_NE(local_s, nullptr);
+    ASSERT_NE(local_v, nullptr);
+    ASSERT_NE(local_l, nullptr);
 
-  EXPECT_EQ(local_v->Shadows(), local_s);
-  EXPECT_EQ(local_l->Shadows(), local_s);
+    EXPECT_EQ(local_v->Shadows(), local_s);
+    EXPECT_EQ(local_l->Shadows(), local_s);
 
-  auto* user_v =
-      Sem().Get<sem::VariableUser>(local_v->Declaration()->constructor);
-  auto* user_l =
-      Sem().Get<sem::VariableUser>(local_l->Declaration()->constructor);
+    auto* user_v = Sem().Get<sem::VariableUser>(local_v->Declaration()->constructor);
+    auto* user_l = Sem().Get<sem::VariableUser>(local_l->Declaration()->constructor);
 
-  ASSERT_NE(user_v, nullptr);
-  ASSERT_NE(user_l, nullptr);
+    ASSERT_NE(user_v, nullptr);
+    ASSERT_NE(user_l, nullptr);
 
-  EXPECT_EQ(user_v->Variable(), local_s);
-  EXPECT_EQ(user_l->Variable(), local_s);
+    EXPECT_EQ(user_v->Variable(), local_s);
+    EXPECT_EQ(user_l->Variable(), local_s);
 }
 
 TEST_F(ResolverVarLetTest, LocalShadowsLocalLet) {
-  // fn X() {
-  //   let a = 1;
-  //   {
-  //     var a = (a == 123);
-  //   }
-  //   {
-  //     let a = (a == 321);
-  //   }
-  // }
+    // fn X() {
+    //   let a = 1;
+    //   {
+    //     var a = (a == 123);
+    //   }
+    //   {
+    //     let a = (a == 321);
+    //   }
+    // }
 
-  auto* s = Const("a", ty.i32(), Expr(1));
-  auto* v = Var("a", nullptr, Expr("a"));
-  auto* l = Const("a", nullptr, Expr("a"));
-  Func("X", {}, ty.void_(), {Decl(s), Block(Decl(v)), Block(Decl(l))});
+    auto* s = Let("a", ty.i32(), Expr(1_i));
+    auto* v = Var("a", nullptr, Expr("a"));
+    auto* l = Let("a", nullptr, Expr("a"));
+    Func("X", {}, ty.void_(), {Decl(s), Block(Decl(v)), Block(Decl(l))});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* local_s = Sem().Get<sem::LocalVariable>(s);
-  auto* local_v = Sem().Get<sem::LocalVariable>(v);
-  auto* local_l = Sem().Get<sem::LocalVariable>(l);
+    auto* local_s = Sem().Get<sem::LocalVariable>(s);
+    auto* local_v = Sem().Get<sem::LocalVariable>(v);
+    auto* local_l = Sem().Get<sem::LocalVariable>(l);
 
-  ASSERT_NE(local_s, nullptr);
-  ASSERT_NE(local_v, nullptr);
-  ASSERT_NE(local_l, nullptr);
+    ASSERT_NE(local_s, nullptr);
+    ASSERT_NE(local_v, nullptr);
+    ASSERT_NE(local_l, nullptr);
 
-  EXPECT_EQ(local_v->Shadows(), local_s);
-  EXPECT_EQ(local_l->Shadows(), local_s);
+    EXPECT_EQ(local_v->Shadows(), local_s);
+    EXPECT_EQ(local_l->Shadows(), local_s);
 
-  auto* user_v =
-      Sem().Get<sem::VariableUser>(local_v->Declaration()->constructor);
-  auto* user_l =
-      Sem().Get<sem::VariableUser>(local_l->Declaration()->constructor);
+    auto* user_v = Sem().Get<sem::VariableUser>(local_v->Declaration()->constructor);
+    auto* user_l = Sem().Get<sem::VariableUser>(local_l->Declaration()->constructor);
 
-  ASSERT_NE(user_v, nullptr);
-  ASSERT_NE(user_l, nullptr);
+    ASSERT_NE(user_v, nullptr);
+    ASSERT_NE(user_l, nullptr);
 
-  EXPECT_EQ(user_v->Variable(), local_s);
-  EXPECT_EQ(user_l->Variable(), local_s);
+    EXPECT_EQ(user_v->Variable(), local_s);
+    EXPECT_EQ(user_l->Variable(), local_s);
 }
 
 TEST_F(ResolverVarLetTest, LocalShadowsParam) {
-  // fn F(a : i32) {
-  //   {
-  //     var a = a;
-  //   }
-  //   {
-  //     let a = a;
-  //   }
-  // }
+    // fn F(a : i32) {
+    //   {
+    //     var a = a;
+    //   }
+    //   {
+    //     let a = a;
+    //   }
+    // }
 
-  auto* p = Param("a", ty.i32());
-  auto* v = Var("a", nullptr, Expr("a"));
-  auto* l = Const("a", nullptr, Expr("a"));
-  Func("X", {p}, ty.void_(), {Block(Decl(v)), Block(Decl(l))});
+    auto* p = Param("a", ty.i32());
+    auto* v = Var("a", nullptr, Expr("a"));
+    auto* l = Let("a", nullptr, Expr("a"));
+    Func("X", {p}, ty.void_(), {Block(Decl(v)), Block(Decl(l))});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* param = Sem().Get<sem::Parameter>(p);
-  auto* local_v = Sem().Get<sem::LocalVariable>(v);
-  auto* local_l = Sem().Get<sem::LocalVariable>(l);
+    auto* param = Sem().Get<sem::Parameter>(p);
+    auto* local_v = Sem().Get<sem::LocalVariable>(v);
+    auto* local_l = Sem().Get<sem::LocalVariable>(l);
 
-  ASSERT_NE(param, nullptr);
-  ASSERT_NE(local_v, nullptr);
-  ASSERT_NE(local_l, nullptr);
+    ASSERT_NE(param, nullptr);
+    ASSERT_NE(local_v, nullptr);
+    ASSERT_NE(local_l, nullptr);
 
-  EXPECT_EQ(local_v->Shadows(), param);
-  EXPECT_EQ(local_l->Shadows(), param);
+    EXPECT_EQ(local_v->Shadows(), param);
+    EXPECT_EQ(local_l->Shadows(), param);
 
-  auto* user_v =
-      Sem().Get<sem::VariableUser>(local_v->Declaration()->constructor);
-  auto* user_l =
-      Sem().Get<sem::VariableUser>(local_l->Declaration()->constructor);
+    auto* user_v = Sem().Get<sem::VariableUser>(local_v->Declaration()->constructor);
+    auto* user_l = Sem().Get<sem::VariableUser>(local_l->Declaration()->constructor);
 
-  ASSERT_NE(user_v, nullptr);
-  ASSERT_NE(user_l, nullptr);
+    ASSERT_NE(user_v, nullptr);
+    ASSERT_NE(user_l, nullptr);
 
-  EXPECT_EQ(user_v->Variable(), param);
-  EXPECT_EQ(user_l->Variable(), param);
+    EXPECT_EQ(user_v->Variable(), param);
+    EXPECT_EQ(user_l->Variable(), param);
 }
 
 TEST_F(ResolverVarLetTest, ParamShadowsFunction) {
-  // fn a(a : bool) {
-  // }
+    // fn a(a : bool) {
+    // }
 
-  auto* p = Param("a", ty.bool_());
-  auto* f = Func("a", {p}, ty.void_(), {});
+    auto* p = Param("a", ty.bool_());
+    auto* f = Func("a", {p}, ty.void_(), {});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* func = Sem().Get(f);
-  auto* param = Sem().Get<sem::Parameter>(p);
+    auto* func = Sem().Get(f);
+    auto* param = Sem().Get<sem::Parameter>(p);
 
-  ASSERT_NE(func, nullptr);
-  ASSERT_NE(param, nullptr);
+    ASSERT_NE(func, nullptr);
+    ASSERT_NE(param, nullptr);
 
-  EXPECT_EQ(param->Shadows(), func);
+    EXPECT_EQ(param->Shadows(), func);
 }
 
 TEST_F(ResolverVarLetTest, ParamShadowsGlobalVar) {
-  // var<private> a : i32;
-  //
-  // fn F(a : bool) {
-  // }
+    // var<private> a : i32;
+    //
+    // fn F(a : bool) {
+    // }
 
-  auto* g = Global("a", ty.i32(), ast::StorageClass::kPrivate);
-  auto* p = Param("a", ty.bool_());
-  Func("F", {p}, ty.void_(), {});
+    auto* g = Global("a", ty.i32(), ast::StorageClass::kPrivate);
+    auto* p = Param("a", ty.bool_());
+    Func("F", {p}, ty.void_(), {});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* global = Sem().Get(g);
-  auto* param = Sem().Get<sem::Parameter>(p);
+    auto* global = Sem().Get(g);
+    auto* param = Sem().Get<sem::Parameter>(p);
 
-  ASSERT_NE(global, nullptr);
-  ASSERT_NE(param, nullptr);
+    ASSERT_NE(global, nullptr);
+    ASSERT_NE(param, nullptr);
 
-  EXPECT_EQ(param->Shadows(), global);
+    EXPECT_EQ(param->Shadows(), global);
 }
 
 TEST_F(ResolverVarLetTest, ParamShadowsGlobalLet) {
-  // let a : i32 = 1;
-  //
-  // fn F(a : bool) {
-  // }
+    // let a : i32 = 1;
+    //
+    // fn F(a : bool) {
+    // }
 
-  auto* g = GlobalConst("a", ty.i32(), Expr(1));
-  auto* p = Param("a", ty.bool_());
-  Func("F", {p}, ty.void_(), {});
+    auto* g = GlobalConst("a", ty.i32(), Expr(1_i));
+    auto* p = Param("a", ty.bool_());
+    Func("F", {p}, ty.void_(), {});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* global = Sem().Get(g);
-  auto* param = Sem().Get<sem::Parameter>(p);
+    auto* global = Sem().Get(g);
+    auto* param = Sem().Get<sem::Parameter>(p);
 
-  ASSERT_NE(global, nullptr);
-  ASSERT_NE(param, nullptr);
+    ASSERT_NE(global, nullptr);
+    ASSERT_NE(param, nullptr);
 
-  EXPECT_EQ(param->Shadows(), global);
+    EXPECT_EQ(param->Shadows(), global);
 }
 
 TEST_F(ResolverVarLetTest, ParamShadowsAlias) {
-  // type a = i32;
-  //
-  // fn F(a : a) {
-  // }
+    // type a = i32;
+    //
+    // fn F(a : a) {
+    // }
 
-  auto* a = Alias("a", ty.i32());
-  auto* p = Param("a", ty.type_name("a"));
-  Func("F", {p}, ty.void_(), {});
+    auto* a = Alias("a", ty.i32());
+    auto* p = Param("a", ty.type_name("a"));
+    Func("F", {p}, ty.void_(), {});
 
-  ASSERT_TRUE(r()->Resolve()) << r()->error();
+    ASSERT_TRUE(r()->Resolve()) << r()->error();
 
-  auto* alias = Sem().Get(a);
-  auto* param = Sem().Get<sem::Parameter>(p);
+    auto* alias = Sem().Get(a);
+    auto* param = Sem().Get<sem::Parameter>(p);
 
-  ASSERT_NE(alias, nullptr);
-  ASSERT_NE(param, nullptr);
+    ASSERT_NE(alias, nullptr);
+    ASSERT_NE(param, nullptr);
 
-  EXPECT_EQ(param->Shadows(), alias);
-  EXPECT_EQ(param->Type(), alias);
+    EXPECT_EQ(param->Shadows(), alias);
+    EXPECT_EQ(param->Type(), alias);
 }
 
 }  // namespace
diff --git a/src/tint/resolver/var_let_validation_test.cc b/src/tint/resolver/var_let_validation_test.cc
index 6b86529..ff63918 100644
--- a/src/tint/resolver/var_let_validation_test.cc
+++ b/src/tint/resolver/var_let_validation_test.cc
@@ -17,330 +17,302 @@
 
 #include "gmock/gmock.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::resolver {
 namespace {
 
-struct ResolverVarLetValidationTest : public resolver::TestHelper,
-                                      public testing::Test {};
+struct ResolverVarLetValidationTest : public resolver::TestHelper, public testing::Test {};
 
 TEST_F(ResolverVarLetValidationTest, LetNoInitializer) {
-  // let a : i32;
-  WrapInFunction(Const(Source{{12, 34}}, "a", ty.i32(), nullptr));
+    // let a : i32;
+    WrapInFunction(Let(Source{{12, 34}}, "a", ty.i32(), nullptr));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: let declaration must have an initializer");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: let declaration must have an initializer");
 }
 
 TEST_F(ResolverVarLetValidationTest, GlobalLetNoInitializer) {
-  // let a : i32;
-  GlobalConst(Source{{12, 34}}, "a", ty.i32(), nullptr);
+    // let a : i32;
+    GlobalConst(Source{{12, 34}}, "a", ty.i32(), nullptr);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: let declaration must have an initializer");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: let declaration must have an initializer");
 }
 
 TEST_F(ResolverVarLetValidationTest, VarNoInitializerNoType) {
-  // var a;
-  WrapInFunction(Var(Source{{12, 34}}, "a", nullptr));
+    // var a;
+    WrapInFunction(Var(Source{{12, 34}}, "a", nullptr));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: function scope var declaration requires a type or "
-            "initializer");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: function scope var declaration requires a type or "
+              "initializer");
 }
 
 TEST_F(ResolverVarLetValidationTest, GlobalVarNoInitializerNoType) {
-  // var a;
-  Global(Source{{12, 34}}, "a", nullptr);
+    // var a;
+    Global(Source{{12, 34}}, "a", nullptr);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: module scope var declaration requires a type and "
-            "initializer");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: module scope var declaration requires a type and "
+              "initializer");
 }
 
 TEST_F(ResolverVarLetValidationTest, VarTypeNotStorable) {
-  // var i : i32;
-  // var p : pointer<function, i32> = &v;
-  auto* i = Var("i", ty.i32(), ast::StorageClass::kNone);
-  auto* p =
-      Var(Source{{56, 78}}, "a", ty.pointer<i32>(ast::StorageClass::kFunction),
-          ast::StorageClass::kNone, AddressOf(Source{{12, 34}}, "i"));
-  WrapInFunction(i, p);
+    // var i : i32;
+    // var p : pointer<function, i32> = &v;
+    auto* i = Var("i", ty.i32(), ast::StorageClass::kNone);
+    auto* p = Var(Source{{56, 78}}, "a", ty.pointer<i32>(ast::StorageClass::kFunction),
+                  ast::StorageClass::kNone, AddressOf(Source{{12, 34}}, "i"));
+    WrapInFunction(i, p);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "56:78 error: ptr<function, i32, read_write> cannot be used as the "
-            "type of a var");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "56:78 error: ptr<function, i32, read_write> cannot be used as the "
+              "type of a var");
 }
 
 TEST_F(ResolverVarLetValidationTest, LetTypeNotConstructible) {
-  // @group(0) @binding(0) var t1 : texture_2d<f32>;
-  // let t2 : t1;
-  auto* t1 =
-      Global("t1", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
-             GroupAndBinding(0, 0));
-  auto* t2 = Const(Source{{56, 78}}, "t2", nullptr, Expr(t1));
-  WrapInFunction(t2);
+    // @group(0) @binding(0) var t1 : texture_2d<f32>;
+    // let t2 : t1;
+    auto* t1 = Global("t1", ty.sampled_texture(ast::TextureDimension::k2d, ty.f32()),
+                      GroupAndBinding(0, 0));
+    auto* t2 = Let(Source{{56, 78}}, "t2", nullptr, Expr(t1));
+    WrapInFunction(t2);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "56:78 error: texture_2d<f32> cannot be used as the type of a let");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "56:78 error: texture_2d<f32> cannot be used as the type of a let");
 }
 
 TEST_F(ResolverVarLetValidationTest, LetConstructorWrongType) {
-  // var v : i32 = 2u
-  WrapInFunction(Const(Source{{3, 3}}, "v", ty.i32(), Expr(2u)));
+    // var v : i32 = 2u
+    WrapInFunction(Let(Source{{3, 3}}, "v", ty.i32(), Expr(2_u)));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(3:3 error: cannot initialize let of type 'i32' with value of type 'u32')");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(3:3 error: cannot initialize let of type 'i32' with value of type 'u32')");
 }
 
 TEST_F(ResolverVarLetValidationTest, VarConstructorWrongType) {
-  // var v : i32 = 2u
-  WrapInFunction(
-      Var(Source{{3, 3}}, "v", ty.i32(), ast::StorageClass::kNone, Expr(2u)));
+    // var v : i32 = 2u
+    WrapInFunction(Var(Source{{3, 3}}, "v", ty.i32(), ast::StorageClass::kNone, Expr(2_u)));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(3:3 error: cannot initialize var of type 'i32' with value of type 'u32')");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(3:3 error: cannot initialize var of type 'i32' with value of type 'u32')");
 }
 
 TEST_F(ResolverVarLetValidationTest, LetConstructorWrongTypeViaAlias) {
-  auto* a = Alias("I32", ty.i32());
-  WrapInFunction(Const(Source{{3, 3}}, "v", ty.Of(a), Expr(2u)));
+    auto* a = Alias("I32", ty.i32());
+    WrapInFunction(Let(Source{{3, 3}}, "v", ty.Of(a), Expr(2_u)));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(3:3 error: cannot initialize let of type 'i32' with value of type 'u32')");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(3:3 error: cannot initialize let of type 'i32' with value of type 'u32')");
 }
 
 TEST_F(ResolverVarLetValidationTest, VarConstructorWrongTypeViaAlias) {
-  auto* a = Alias("I32", ty.i32());
-  WrapInFunction(
-      Var(Source{{3, 3}}, "v", ty.Of(a), ast::StorageClass::kNone, Expr(2u)));
+    auto* a = Alias("I32", ty.i32());
+    WrapInFunction(Var(Source{{3, 3}}, "v", ty.Of(a), ast::StorageClass::kNone, Expr(2_u)));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(3:3 error: cannot initialize var of type 'i32' with value of type 'u32')");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(3:3 error: cannot initialize var of type 'i32' with value of type 'u32')");
 }
 
 TEST_F(ResolverVarLetValidationTest, LetOfPtrConstructedWithRef) {
-  // var a : f32;
-  // let b : ptr<function,f32> = a;
-  const auto priv = ast::StorageClass::kFunction;
-  auto* var_a = Var("a", ty.f32(), priv);
-  auto* var_b =
-      Const(Source{{12, 34}}, "b", ty.pointer<float>(priv), Expr("a"), {});
-  WrapInFunction(var_a, var_b);
+    // var a : f32;
+    // let b : ptr<function,f32> = a;
+    const auto priv = ast::StorageClass::kFunction;
+    auto* var_a = Var("a", ty.f32(), priv);
+    auto* var_b = Let(Source{{12, 34}}, "b", ty.pointer<float>(priv), Expr("a"), {});
+    WrapInFunction(var_a, var_b);
 
-  ASSERT_FALSE(r()->Resolve());
+    ASSERT_FALSE(r()->Resolve());
 
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: cannot initialize let of type 'ptr<function, f32, read_write>' with value of type 'f32')");
+    EXPECT_EQ(
+        r()->error(),
+        R"(12:34 error: cannot initialize let of type 'ptr<function, f32, read_write>' with value of type 'f32')");
 }
 
 TEST_F(ResolverVarLetValidationTest, LocalLetRedeclared) {
-  // let l : f32 = 1.;
-  // let l : i32 = 0;
-  auto* l1 = Const("l", ty.f32(), Expr(1.f));
-  auto* l2 = Const(Source{{12, 34}}, "l", ty.i32(), Expr(0));
-  WrapInFunction(l1, l2);
+    // let l : f32 = 1.;
+    // let l : i32 = 0;
+    auto* l1 = Let("l", ty.f32(), Expr(1.f));
+    auto* l2 = Let(Source{{12, 34}}, "l", ty.i32(), Expr(0_i));
+    WrapInFunction(l1, l2);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      "12:34 error: redeclaration of 'l'\nnote: 'l' previously declared here");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: redeclaration of 'l'\nnote: 'l' previously declared here");
 }
 
 TEST_F(ResolverVarLetValidationTest, GlobalVarRedeclaredAsLocal) {
-  // var v : f32 = 2.1;
-  // fn my_func() {
-  //   var v : f32 = 2.0;
-  //   return 0;
-  // }
+    // var v : f32 = 2.1;
+    // fn my_func() {
+    //   var v : f32 = 2.0;
+    //   return 0;
+    // }
 
-  Global("v", ty.f32(), ast::StorageClass::kPrivate, Expr(2.1f));
+    Global("v", ty.f32(), ast::StorageClass::kPrivate, Expr(2.1f));
 
-  WrapInFunction(Var(Source{{12, 34}}, "v", ty.f32(), ast::StorageClass::kNone,
-                     Expr(2.0f)));
+    WrapInFunction(Var(Source{{12, 34}}, "v", ty.f32(), ast::StorageClass::kNone, Expr(2.0f)));
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverVarLetValidationTest, VarRedeclaredInInnerBlock) {
-  // {
-  //  var v : f32;
-  //  { var v : f32; }
-  // }
-  auto* var_outer = Var("v", ty.f32(), ast::StorageClass::kNone);
-  auto* var_inner =
-      Var(Source{{12, 34}}, "v", ty.f32(), ast::StorageClass::kNone);
-  auto* inner = Block(Decl(var_inner));
-  auto* outer_body = Block(Decl(var_outer), inner);
+    // {
+    //  var v : f32;
+    //  { var v : f32; }
+    // }
+    auto* var_outer = Var("v", ty.f32(), ast::StorageClass::kNone);
+    auto* var_inner = Var(Source{{12, 34}}, "v", ty.f32(), ast::StorageClass::kNone);
+    auto* inner = Block(Decl(var_inner));
+    auto* outer_body = Block(Decl(var_outer), inner);
 
-  WrapInFunction(outer_body);
+    WrapInFunction(outer_body);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverVarLetValidationTest, VarRedeclaredInIfBlock) {
-  // {
-  //   var v : f32 = 3.14;
-  //   if (true) { var v : f32 = 2.0; }
-  // }
-  auto* var_a_float = Var("v", ty.f32(), ast::StorageClass::kNone, Expr(3.1f));
+    // {
+    //   var v : f32 = 3.14;
+    //   if (true) { var v : f32 = 2.0; }
+    // }
+    auto* var_a_float = Var("v", ty.f32(), ast::StorageClass::kNone, Expr(3.1f));
 
-  auto* var = Var(Source{{12, 34}}, "v", ty.f32(), ast::StorageClass::kNone,
-                  Expr(2.0f));
+    auto* var = Var(Source{{12, 34}}, "v", ty.f32(), ast::StorageClass::kNone, Expr(2.0f));
 
-  auto* cond = Expr(true);
-  auto* body = Block(Decl(var));
+    auto* cond = Expr(true);
+    auto* body = Block(Decl(var));
 
-  auto* outer_body =
-      Block(Decl(var_a_float),
-            create<ast::IfStatement>(cond, body, ast::ElseStatementList{}));
+    auto* outer_body = Block(Decl(var_a_float), If(cond, body));
 
-  WrapInFunction(outer_body);
+    WrapInFunction(outer_body);
 
-  EXPECT_TRUE(r()->Resolve()) << r()->error();
+    EXPECT_TRUE(r()->Resolve()) << r()->error();
 }
 
 TEST_F(ResolverVarLetValidationTest, InferredPtrStorageAccessMismatch) {
-  // struct Inner {
-  //    arr: array<i32, 4>;
-  // }
-  // struct S {
-  //    inner: Inner;
-  // }
-  // @group(0) @binding(0) var<storage> s : S;
-  // fn f() {
-  //   let p : pointer<storage, i32, read_write> = &s.inner.arr[2];
-  // }
-  auto* inner = Structure("Inner", {Member("arr", ty.array<i32, 4>())});
-  auto* buf = Structure("S", {Member("inner", ty.Of(inner))});
-  auto* storage = Global("s", ty.Of(buf), ast::StorageClass::kStorage,
-                         ast::AttributeList{
-                             create<ast::BindingAttribute>(0),
-                             create<ast::GroupAttribute>(0),
-                         });
+    // struct Inner {
+    //    arr: array<i32, 4>;
+    // }
+    // struct S {
+    //    inner: Inner;
+    // }
+    // @group(0) @binding(0) var<storage> s : S;
+    // fn f() {
+    //   let p : pointer<storage, i32, read_write> = &s.inner.arr[2i];
+    // }
+    auto* inner = Structure("Inner", {Member("arr", ty.array<i32, 4>())});
+    auto* buf = Structure("S", {Member("inner", ty.Of(inner))});
+    auto* storage = Global("s", ty.Of(buf), ast::StorageClass::kStorage,
+                           ast::AttributeList{
+                               create<ast::BindingAttribute>(0),
+                               create<ast::GroupAttribute>(0),
+                           });
 
-  auto* expr =
-      IndexAccessor(MemberAccessor(MemberAccessor(storage, "inner"), "arr"), 4);
-  auto* ptr = Const(
-      Source{{12, 34}}, "p",
-      ty.pointer<i32>(ast::StorageClass::kStorage, ast::Access::kReadWrite),
-      AddressOf(expr));
+    auto* expr = IndexAccessor(MemberAccessor(MemberAccessor(storage, "inner"), "arr"), 2_i);
+    auto* ptr =
+        Let(Source{{12, 34}}, "p",
+            ty.pointer<i32>(ast::StorageClass::kStorage, ast::Access::kReadWrite), AddressOf(expr));
 
-  WrapInFunction(ptr);
+    WrapInFunction(ptr);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: cannot initialize let of type "
-            "'ptr<storage, i32, read_write>' with value of type "
-            "'ptr<storage, i32, read>'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: cannot initialize let of type "
+              "'ptr<storage, i32, read_write>' with value of type "
+              "'ptr<storage, i32, read>'");
 }
 
 TEST_F(ResolverVarLetValidationTest, NonConstructibleType_Atomic) {
-  auto* v = Var("v", ty.atomic(Source{{12, 34}}, ty.i32()));
-  WrapInFunction(v);
+    auto* v = Var("v", ty.atomic(Source{{12, 34}}, ty.i32()));
+    WrapInFunction(v);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: function variable must have a constructible type");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: function variable must have a constructible type");
 }
 
 TEST_F(ResolverVarLetValidationTest, NonConstructibleType_RuntimeArray) {
-  auto* s = Structure("S", {Member(Source{{56, 78}}, "m", ty.array(ty.i32()))});
-  auto* v = Var(Source{{12, 34}}, "v", ty.Of(s));
-  WrapInFunction(v);
+    auto* s = Structure("S", {Member(Source{{56, 78}}, "m", ty.array(ty.i32()))});
+    auto* v = Var(Source{{12, 34}}, "v", ty.Of(s));
+    WrapInFunction(v);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(
-      r()->error(),
-      R"(12:34 error: runtime-sized arrays can only be used in the <storage> storage class
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              R"(12:34 error: runtime-sized arrays can only be used in the <storage> storage class
 56:78 note: while analysing structure member S.m
 12:34 note: while instantiating variable v)");
 }
 
 TEST_F(ResolverVarLetValidationTest, NonConstructibleType_Struct_WithAtomic) {
-  auto* s = Structure("S", {Member("m", ty.atomic(ty.i32()))});
-  auto* v = Var("v", ty.Of(s));
-  WrapInFunction(v);
+    auto* s = Structure("S", {Member("m", ty.atomic(ty.i32()))});
+    auto* v = Var("v", ty.Of(s));
+    WrapInFunction(v);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "error: function variable must have a constructible type");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "error: function variable must have a constructible type");
 }
 
 TEST_F(ResolverVarLetValidationTest, NonConstructibleType_InferredType) {
-  // @group(0) @binding(0) var s : sampler;
-  // fn foo() {
-  //   var v = s;
-  // }
-  Global("s", ty.sampler(ast::SamplerKind::kSampler), GroupAndBinding(0, 0));
-  auto* v = Var(Source{{12, 34}}, "v", nullptr, Expr("s"));
-  WrapInFunction(v);
+    // @group(0) @binding(0) var s : sampler;
+    // fn foo() {
+    //   var v = s;
+    // }
+    Global("s", ty.sampler(ast::SamplerKind::kSampler), GroupAndBinding(0, 0));
+    auto* v = Var(Source{{12, 34}}, "v", nullptr, Expr("s"));
+    WrapInFunction(v);
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: function variable must have a constructible type");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: function variable must have a constructible type");
 }
 
 TEST_F(ResolverVarLetValidationTest, InvalidStorageClassForInitializer) {
-  // var<workgroup> v : f32 = 1.23;
-  Global(Source{{12, 34}}, "v", ty.f32(), ast::StorageClass::kWorkgroup,
-         Expr(1.23f));
+    // var<workgroup> v : f32 = 1.23;
+    Global(Source{{12, 34}}, "v", ty.f32(), ast::StorageClass::kWorkgroup, Expr(1.23f));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(),
-            "12:34 error: var of storage class 'workgroup' cannot have "
-            "an initializer. var initializers are only supported for the "
-            "storage classes 'private' and 'function'");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(),
+              "12:34 error: var of storage class 'workgroup' cannot have "
+              "an initializer. var initializers are only supported for the "
+              "storage classes 'private' and 'function'");
 }
 
 TEST_F(ResolverVarLetValidationTest, VectorLetNoType) {
-  // let a : mat3x3 = mat3x3<f32>();
-  WrapInFunction(Const("a", create<ast::Vector>(Source{{12, 34}}, nullptr, 3),
-                       vec3<f32>()));
+    // let a : mat3x3 = mat3x3<f32>();
+    WrapInFunction(Let("a", create<ast::Vector>(Source{{12, 34}}, nullptr, 3), vec3<f32>()));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: missing vector element type");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: missing vector element type");
 }
 
 TEST_F(ResolverVarLetValidationTest, VectorVarNoType) {
-  // var a : mat3x3;
-  WrapInFunction(Var("a", create<ast::Vector>(Source{{12, 34}}, nullptr, 3)));
+    // var a : mat3x3;
+    WrapInFunction(Var("a", create<ast::Vector>(Source{{12, 34}}, nullptr, 3)));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: missing vector element type");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: missing vector element type");
 }
 
 TEST_F(ResolverVarLetValidationTest, MatrixLetNoType) {
-  // let a : mat3x3 = mat3x3<f32>();
-  WrapInFunction(Const("a",
-                       create<ast::Matrix>(Source{{12, 34}}, nullptr, 3, 3),
-                       mat3x3<f32>()));
+    // let a : mat3x3 = mat3x3<f32>();
+    WrapInFunction(Let("a", create<ast::Matrix>(Source{{12, 34}}, nullptr, 3, 3), mat3x3<f32>()));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: missing matrix element type");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: missing matrix element type");
 }
 
 TEST_F(ResolverVarLetValidationTest, MatrixVarNoType) {
-  // var a : mat3x3;
-  WrapInFunction(
-      Var("a", create<ast::Matrix>(Source{{12, 34}}, nullptr, 3, 3)));
+    // var a : mat3x3;
+    WrapInFunction(Var("a", create<ast::Matrix>(Source{{12, 34}}, nullptr, 3, 3)));
 
-  EXPECT_FALSE(r()->Resolve());
-  EXPECT_EQ(r()->error(), "12:34 error: missing matrix element type");
+    EXPECT_FALSE(r()->Resolve());
+    EXPECT_EQ(r()->error(), "12:34 error: missing matrix element type");
 }
 
 }  // namespace
diff --git a/src/tint/scope_stack.h b/src/tint/scope_stack.h
index 1244584..8bc97a3 100644
--- a/src/tint/scope_stack.h
+++ b/src/tint/scope_stack.h
@@ -26,53 +26,53 @@
 /// The stack starts with a global scope which can not be popped.
 template <class T>
 class ScopeStack {
- public:
-  /// Constructor
-  ScopeStack() {
-    // Push global bucket
-    stack_.push_back({});
-  }
-  /// Copy Constructor
-  ScopeStack(const ScopeStack&) = default;
-  ~ScopeStack() = default;
-
-  /// Push a new scope on to the stack
-  void Push() { stack_.push_back({}); }
-
-  /// Pop the scope off the top of the stack
-  void Pop() {
-    if (stack_.size() > 1) {
-      stack_.pop_back();
+  public:
+    /// Constructor
+    ScopeStack() {
+        // Push global bucket
+        stack_.push_back({});
     }
-  }
+    /// Copy Constructor
+    ScopeStack(const ScopeStack&) = default;
+    ~ScopeStack() = default;
 
-  /// Assigns the value into the top most scope of the stack.
-  /// @param symbol the symbol of the value
-  /// @param val the value
-  /// @returns the old value if there was an existing symbol at the top of the
-  /// stack, otherwise the zero initializer for type T.
-  T Set(const Symbol& symbol, T val) {
-    std::swap(val, stack_.back()[symbol]);
-    return val;
-  }
+    /// Push a new scope on to the stack
+    void Push() { stack_.push_back({}); }
 
-  /// Retrieves a value from the stack
-  /// @param symbol the symbol to look for
-  /// @returns the value, or the zero initializer if the value was not found
-  T Get(const Symbol& symbol) const {
-    for (auto iter = stack_.rbegin(); iter != stack_.rend(); ++iter) {
-      auto& map = *iter;
-      auto val = map.find(symbol);
-      if (val != map.end()) {
-        return val->second;
-      }
+    /// Pop the scope off the top of the stack
+    void Pop() {
+        if (stack_.size() > 1) {
+            stack_.pop_back();
+        }
     }
 
-    return T{};
-  }
+    /// Assigns the value into the top most scope of the stack.
+    /// @param symbol the symbol of the value
+    /// @param val the value
+    /// @returns the old value if there was an existing symbol at the top of the
+    /// stack, otherwise the zero initializer for type T.
+    T Set(const Symbol& symbol, T val) {
+        std::swap(val, stack_.back()[symbol]);
+        return val;
+    }
 
- private:
-  std::vector<std::unordered_map<Symbol, T>> stack_;
+    /// Retrieves a value from the stack
+    /// @param symbol the symbol to look for
+    /// @returns the value, or the zero initializer if the value was not found
+    T Get(const Symbol& symbol) const {
+        for (auto iter = stack_.rbegin(); iter != stack_.rend(); ++iter) {
+            auto& map = *iter;
+            auto val = map.find(symbol);
+            if (val != map.end()) {
+                return val->second;
+            }
+        }
+
+        return T{};
+    }
+
+  private:
+    std::vector<std::unordered_map<Symbol, T>> stack_;
 };
 
 }  // namespace tint
diff --git a/src/tint/scope_stack_test.cc b/src/tint/scope_stack_test.cc
index 3754a41..8062807 100644
--- a/src/tint/scope_stack_test.cc
+++ b/src/tint/scope_stack_test.cc
@@ -22,49 +22,49 @@
 class ScopeStackTest : public ProgramBuilder, public testing::Test {};
 
 TEST_F(ScopeStackTest, Get) {
-  ScopeStack<uint32_t> s;
-  Symbol a(1, ID());
-  Symbol b(3, ID());
-  s.Push();
-  s.Set(a, 5u);
-  s.Set(b, 10u);
+    ScopeStack<uint32_t> s;
+    Symbol a(1, ID());
+    Symbol b(3, ID());
+    s.Push();
+    s.Set(a, 5u);
+    s.Set(b, 10u);
 
-  EXPECT_EQ(s.Get(a), 5u);
-  EXPECT_EQ(s.Get(b), 10u);
+    EXPECT_EQ(s.Get(a), 5u);
+    EXPECT_EQ(s.Get(b), 10u);
 
-  s.Push();
+    s.Push();
 
-  s.Set(a, 15u);
-  EXPECT_EQ(s.Get(a), 15u);
-  EXPECT_EQ(s.Get(b), 10u);
+    s.Set(a, 15u);
+    EXPECT_EQ(s.Get(a), 15u);
+    EXPECT_EQ(s.Get(b), 10u);
 
-  s.Pop();
-  EXPECT_EQ(s.Get(a), 5u);
-  EXPECT_EQ(s.Get(b), 10u);
+    s.Pop();
+    EXPECT_EQ(s.Get(a), 5u);
+    EXPECT_EQ(s.Get(b), 10u);
 }
 
 TEST_F(ScopeStackTest, Get_MissingSymbol) {
-  ScopeStack<uint32_t> s;
-  Symbol sym(1, ID());
-  EXPECT_EQ(s.Get(sym), 0u);
+    ScopeStack<uint32_t> s;
+    Symbol sym(1, ID());
+    EXPECT_EQ(s.Get(sym), 0u);
 }
 
 TEST_F(ScopeStackTest, Set) {
-  ScopeStack<uint32_t> s;
-  Symbol a(1, ID());
-  Symbol b(2, ID());
+    ScopeStack<uint32_t> s;
+    Symbol a(1, ID());
+    Symbol b(2, ID());
 
-  EXPECT_EQ(s.Set(a, 5u), 0u);
-  EXPECT_EQ(s.Get(a), 5u);
+    EXPECT_EQ(s.Set(a, 5u), 0u);
+    EXPECT_EQ(s.Get(a), 5u);
 
-  EXPECT_EQ(s.Set(b, 10u), 0u);
-  EXPECT_EQ(s.Get(b), 10u);
+    EXPECT_EQ(s.Set(b, 10u), 0u);
+    EXPECT_EQ(s.Get(b), 10u);
 
-  EXPECT_EQ(s.Set(a, 20u), 5u);
-  EXPECT_EQ(s.Get(a), 20u);
+    EXPECT_EQ(s.Set(a, 20u), 5u);
+    EXPECT_EQ(s.Get(a), 20u);
 
-  EXPECT_EQ(s.Set(b, 25u), 10u);
-  EXPECT_EQ(s.Get(b), 25u);
+    EXPECT_EQ(s.Set(b, 25u), 10u);
+    EXPECT_EQ(s.Get(b), 25u);
 }
 
 }  // namespace
diff --git a/src/tint/sem/abstract_float.cc b/src/tint/sem/abstract_float.cc
new file mode 100644
index 0000000..1f0c8b4
--- /dev/null
+++ b/src/tint/sem/abstract_float.cc
@@ -0,0 +1,40 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/sem/abstract_float.h"
+
+#include "src/tint/program_builder.h"
+#include "src/tint/utils/hash.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::sem::AbstractFloat);
+
+namespace tint::sem {
+
+AbstractFloat::AbstractFloat() = default;
+AbstractFloat::AbstractFloat(AbstractFloat&&) = default;
+AbstractFloat::~AbstractFloat() = default;
+
+size_t AbstractFloat::Hash() const {
+    return utils::Hash(TypeInfo::Of<AbstractFloat>().full_hashcode);
+}
+
+bool AbstractFloat::Equals(const sem::Type& other) const {
+    return other.Is<AbstractFloat>();
+}
+
+std::string AbstractFloat::FriendlyName(const SymbolTable&) const {
+    return "AbstractFloat";
+}
+
+}  // namespace tint::sem
diff --git a/src/tint/sem/abstract_float.h b/src/tint/sem/abstract_float.h
new file mode 100644
index 0000000..77b8a78
--- /dev/null
+++ b/src/tint/sem/abstract_float.h
@@ -0,0 +1,49 @@
+// 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_SEM_ABSTRACT_FLOAT_H_
+#define SRC_TINT_SEM_ABSTRACT_FLOAT_H_
+
+#include <string>
+
+#include "src/tint/sem/abstract_numeric.h"
+
+namespace tint::sem {
+
+/// An abstract-float type.
+/// @see https://www.w3.org/TR/WGSL/#abstractFloat
+class AbstractFloat final : public Castable<AbstractFloat, AbstractNumeric> {
+  public:
+    /// Constructor
+    AbstractFloat();
+
+    /// Move constructor
+    AbstractFloat(AbstractFloat&&);
+    ~AbstractFloat() override;
+
+    /// @returns a hash of the type.
+    size_t Hash() const override;
+
+    /// @param other the other type to compare against
+    /// @returns true if this type is equal to the given type
+    bool Equals(const Type& other) const override;
+
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type when printed in diagnostics.
+    std::string FriendlyName(const SymbolTable& symbols) const override;
+};
+
+}  // namespace tint::sem
+
+#endif  // SRC_TINT_SEM_ABSTRACT_FLOAT_H_
diff --git a/src/tint/sem/abstract_int.cc b/src/tint/sem/abstract_int.cc
new file mode 100644
index 0000000..6851514
--- /dev/null
+++ b/src/tint/sem/abstract_int.cc
@@ -0,0 +1,40 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/sem/abstract_int.h"
+
+#include "src/tint/program_builder.h"
+#include "src/tint/utils/hash.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::sem::AbstractInt);
+
+namespace tint::sem {
+
+AbstractInt::AbstractInt() = default;
+AbstractInt::AbstractInt(AbstractInt&&) = default;
+AbstractInt::~AbstractInt() = default;
+
+size_t AbstractInt::Hash() const {
+    return utils::Hash(TypeInfo::Of<AbstractInt>().full_hashcode);
+}
+
+bool AbstractInt::Equals(const sem::Type& other) const {
+    return other.Is<AbstractInt>();
+}
+
+std::string AbstractInt::FriendlyName(const SymbolTable&) const {
+    return "AbstractInt";
+}
+
+}  // namespace tint::sem
diff --git a/src/tint/sem/abstract_int.h b/src/tint/sem/abstract_int.h
new file mode 100644
index 0000000..91a6299
--- /dev/null
+++ b/src/tint/sem/abstract_int.h
@@ -0,0 +1,49 @@
+// 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_SEM_ABSTRACT_INT_H_
+#define SRC_TINT_SEM_ABSTRACT_INT_H_
+
+#include <string>
+
+#include "src/tint/sem/abstract_numeric.h"
+
+namespace tint::sem {
+
+/// An abstract-int type.
+/// @see https://www.w3.org/TR/WGSL/#abstractint
+class AbstractInt final : public Castable<AbstractInt, AbstractNumeric> {
+  public:
+    /// Constructor
+    AbstractInt();
+
+    /// Move constructor
+    AbstractInt(AbstractInt&&);
+    ~AbstractInt() override;
+
+    /// @returns a hash of the type.
+    size_t Hash() const override;
+
+    /// @param other the other type to compare against
+    /// @returns true if the this type is equal to the given type
+    bool Equals(const Type& other) const override;
+
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type when printed in diagnostics.
+    std::string FriendlyName(const SymbolTable& symbols) const override;
+};
+
+}  // namespace tint::sem
+
+#endif  // SRC_TINT_SEM_ABSTRACT_INT_H_
diff --git a/src/tint/sem/abstract_numeric.cc b/src/tint/sem/abstract_numeric.cc
new file mode 100644
index 0000000..6481a43
--- /dev/null
+++ b/src/tint/sem/abstract_numeric.cc
@@ -0,0 +1,37 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/sem/abstract_numeric.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::sem::AbstractNumeric);
+
+namespace tint::sem {
+
+AbstractNumeric::AbstractNumeric() = default;
+AbstractNumeric::AbstractNumeric(AbstractNumeric&&) = default;
+AbstractNumeric::~AbstractNumeric() = default;
+
+uint32_t AbstractNumeric::Size() const {
+    return 0;
+}
+
+uint32_t AbstractNumeric::Align() const {
+    return 0;
+}
+
+bool AbstractNumeric::IsConstructible() const {
+    return false;
+}
+
+}  // namespace tint::sem
diff --git a/src/tint/sem/abstract_numeric.h b/src/tint/sem/abstract_numeric.h
new file mode 100644
index 0000000..0b38448
--- /dev/null
+++ b/src/tint/sem/abstract_numeric.h
@@ -0,0 +1,47 @@
+// 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_SEM_ABSTRACT_NUMERIC_H_
+#define SRC_TINT_SEM_ABSTRACT_NUMERIC_H_
+
+#include <string>
+
+#include "src/tint/sem/type.h"
+
+namespace tint::sem {
+
+/// The base class for abstract-int and abstract-float types.
+/// @see https://www.w3.org/TR/WGSL/#types-for-creation-time-constants
+class AbstractNumeric : public Castable<AbstractNumeric, Type> {
+  public:
+    /// Constructor
+    AbstractNumeric();
+
+    /// Move constructor
+    AbstractNumeric(AbstractNumeric&&);
+    ~AbstractNumeric() override;
+
+    /// @returns 0, as the type is abstract.
+    uint32_t Size() const override;
+
+    /// @returns 0, as the type is abstract.
+    uint32_t Align() const override;
+
+    /// @returns 0, as the type is abstract.
+    bool IsConstructible() const override;
+};
+
+}  // namespace tint::sem
+
+#endif  // SRC_TINT_SEM_ABSTRACT_NUMERIC_H_
diff --git a/src/tint/sem/array.cc b/src/tint/sem/array.cc
index 296979c..624623a 100644
--- a/src/tint/sem/array.cc
+++ b/src/tint/sem/array.cc
@@ -37,47 +37,46 @@
       implicit_stride_(implicit_stride),
       constructible_(count > 0  // Runtime-sized arrays are not constructible
                      && element->IsConstructible()) {
-  TINT_ASSERT(Semantic, element_);
+    TINT_ASSERT(Semantic, element_);
 }
 
 size_t Array::Hash() const {
-  return utils::Hash(TypeInfo::Of<Array>().full_hashcode, count_, align_, size_,
-                     stride_);
+    return utils::Hash(TypeInfo::Of<Array>().full_hashcode, count_, align_, size_, stride_);
 }
 
 bool Array::Equals(const sem::Type& other) const {
-  if (auto* o = other.As<Array>()) {
-    // Note: implicit_stride is not part of the type_name string as this is
-    // derived from the element type
-    return o->element_ == element_ && o->count_ == count_ &&
-           o->align_ == align_ && o->size_ == size_ && o->stride_ == stride_;
-  }
-  return false;
+    if (auto* o = other.As<Array>()) {
+        // Note: implicit_stride is not part of the type_name string as this is
+        // derived from the element type
+        return o->element_ == element_ && o->count_ == count_ && o->align_ == align_ &&
+               o->size_ == size_ && o->stride_ == stride_;
+    }
+    return false;
 }
 
 bool Array::IsConstructible() const {
-  return constructible_;
+    return constructible_;
 }
 
 std::string Array::FriendlyName(const SymbolTable& symbols) const {
-  std::ostringstream out;
-  if (!IsStrideImplicit()) {
-    out << "@stride(" << stride_ << ") ";
-  }
-  out << "array<" << element_->FriendlyName(symbols);
-  if (!IsRuntimeSized()) {
-    out << ", " << count_;
-  }
-  out << ">";
-  return out.str();
+    std::ostringstream out;
+    if (!IsStrideImplicit()) {
+        out << "@stride(" << stride_ << ") ";
+    }
+    out << "array<" << element_->FriendlyName(symbols);
+    if (!IsRuntimeSized()) {
+        out << ", " << count_;
+    }
+    out << ">";
+    return out.str();
 }
 
 uint32_t Array::Align() const {
-  return align_;
+    return align_;
 }
 
 uint32_t Array::Size() const {
-  return size_;
+    return size_;
 }
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/array.h b/src/tint/sem/array.h
index e10777b..aeef3ce 100644
--- a/src/tint/sem/array.h
+++ b/src/tint/sem/array.h
@@ -30,82 +30,82 @@
 
 /// Array holds the semantic information for Array nodes.
 class Array final : public Castable<Array, Type> {
- public:
-  /// Constructor
-  /// @param element the array element type
-  /// @param count the number of elements in the array. 0 represents a
-  /// runtime-sized array.
-  /// @param align the byte alignment of the array
-  /// @param size the byte size of the array
-  /// @param stride the number of bytes from the start of one element of the
-  /// array to the start of the next element
-  /// @param implicit_stride the number of bytes from the start of one element
-  /// of the array to the start of the next element, if there was no `@stride`
-  /// attribute applied.
-  Array(Type const* element,
-        uint32_t count,
-        uint32_t align,
-        uint32_t size,
-        uint32_t stride,
-        uint32_t implicit_stride);
+  public:
+    /// Constructor
+    /// @param element the array element type
+    /// @param count the number of elements in the array. 0 represents a
+    /// runtime-sized array.
+    /// @param align the byte alignment of the array
+    /// @param size the byte size of the array
+    /// @param stride the number of bytes from the start of one element of the
+    /// array to the start of the next element
+    /// @param implicit_stride the number of bytes from the start of one element
+    /// of the array to the start of the next element, if there was no `@stride`
+    /// attribute applied.
+    Array(Type const* element,
+          uint32_t count,
+          uint32_t align,
+          uint32_t size,
+          uint32_t stride,
+          uint32_t implicit_stride);
 
-  /// @returns a hash of the type.
-  size_t Hash() const override;
+    /// @returns a hash of the type.
+    size_t Hash() const override;
 
-  /// @param other the other type to compare against
-  /// @returns true if the this type is equal to the given type
-  bool Equals(const Type& other) const override;
+    /// @param other the other type to compare against
+    /// @returns true if the this type is equal to the given type
+    bool Equals(const Type& other) const override;
 
-  /// @return the array element type
-  Type const* ElemType() const { return element_; }
+    /// @return the array element type
+    Type const* ElemType() const { return element_; }
 
-  /// @returns the number of elements in the array. 0 represents a runtime-sized
-  /// array.
-  uint32_t Count() const { return count_; }
+    /// @returns the number of elements in the array. 0 represents a runtime-sized
+    /// array.
+    uint32_t Count() const { return count_; }
 
-  /// @returns the byte alignment of the array
-  /// @note this may differ from the alignment of a structure member of this
-  /// array type, if the member is annotated with the `@align(n)` attribute.
-  uint32_t Align() const override;
+    /// @returns the byte alignment of the array
+    /// @note this may differ from the alignment of a structure member of this
+    /// array type, if the member is annotated with the `@align(n)` attribute.
+    uint32_t Align() const override;
 
-  /// @returns the byte size of the array
-  /// @note this may differ from the size of a structure member of this array
-  /// type, if the member is annotated with the `@size(n)` attribute.
-  uint32_t Size() const override;
+    /// @returns the byte size of the array
+    /// @note this may differ from the size of a structure member of this array
+    /// type, if the member is annotated with the `@size(n)` attribute.
+    uint32_t Size() const override;
 
-  /// @returns the number of bytes from the start of one element of the
-  /// array to the start of the next element
-  uint32_t Stride() const { return stride_; }
+    /// @returns the number of bytes from the start of one element of the
+    /// array to the start of the next element
+    uint32_t Stride() const { return stride_; }
 
-  /// @returns the number of bytes from the start of one element of the
-  /// array to the start of the next element, if there was no `@stride`
-  /// attribute applied
-  uint32_t ImplicitStride() const { return implicit_stride_; }
+    /// @returns the number of bytes from the start of one element of the
+    /// array to the start of the next element, if there was no `@stride`
+    /// attribute applied
+    uint32_t ImplicitStride() const { return implicit_stride_; }
 
-  /// @returns true if the value returned by Stride() matches the element's
-  /// natural stride
-  bool IsStrideImplicit() const { return stride_ == implicit_stride_; }
+    /// @returns true if the value returned by Stride() matches the element's
+    /// natural stride
+    bool IsStrideImplicit() const { return stride_ == implicit_stride_; }
 
-  /// @returns true if this array is runtime sized
-  bool IsRuntimeSized() const { return count_ == 0; }
+    /// @returns true if this array is runtime sized
+    bool IsRuntimeSized() const { return count_ == 0; }
 
-  /// @returns true if constructible as per
-  /// https://gpuweb.github.io/gpuweb/wgsl/#constructible-types
-  bool IsConstructible() const override;
+    /// @returns true if constructible as per
+    /// https://gpuweb.github.io/gpuweb/wgsl/#constructible-types
+    bool IsConstructible() const override;
 
-  /// @param symbols the program's symbol table
-  /// @returns the name for this type that closely resembles how it would be
-  /// declared in WGSL.
-  std::string FriendlyName(const SymbolTable& symbols) const override;
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type that closely resembles how it would be
+    /// declared in WGSL.
+    std::string FriendlyName(const SymbolTable& symbols) const override;
 
- private:
-  Type const* const element_;
-  const uint32_t count_;
-  const uint32_t align_;
-  const uint32_t size_;
-  const uint32_t stride_;
-  const uint32_t implicit_stride_;
-  const bool constructible_;
+  private:
+    Type const* const element_;
+    const uint32_t count_;
+    const uint32_t align_;
+    const uint32_t size_;
+    const uint32_t stride_;
+    const uint32_t implicit_stride_;
+    const bool constructible_;
 };
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/atomic_type.cc b/src/tint/sem/atomic.cc
similarity index 70%
rename from src/tint/sem/atomic_type.cc
rename to src/tint/sem/atomic.cc
index 6376a7b..52951f3 100644
--- a/src/tint/sem/atomic_type.cc
+++ b/src/tint/sem/atomic.cc
@@ -12,10 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/sem/atomic_type.h"
+#include "src/tint/sem/atomic.h"
 
 #include "src/tint/program_builder.h"
-#include "src/tint/sem/reference_type.h"
+#include "src/tint/sem/reference.h"
 #include "src/tint/utils/hash.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::sem::Atomic);
@@ -23,36 +23,36 @@
 namespace tint::sem {
 
 Atomic::Atomic(const sem::Type* subtype) : subtype_(subtype) {
-  TINT_ASSERT(AST, !subtype->Is<Reference>());
+    TINT_ASSERT(AST, !subtype->Is<Reference>());
 }
 
 size_t Atomic::Hash() const {
-  return utils::Hash(TypeInfo::Of<Atomic>().full_hashcode, subtype_);
+    return utils::Hash(TypeInfo::Of<Atomic>().full_hashcode, subtype_);
 }
 
 bool Atomic::Equals(const sem::Type& other) const {
-  if (auto* o = other.As<Atomic>()) {
-    return o->subtype_ == subtype_;
-  }
-  return false;
+    if (auto* o = other.As<Atomic>()) {
+        return o->subtype_ == subtype_;
+    }
+    return false;
 }
 
 std::string Atomic::FriendlyName(const SymbolTable& symbols) const {
-  std::ostringstream out;
-  out << "atomic<" << subtype_->FriendlyName(symbols) << ">";
-  return out.str();
+    std::ostringstream out;
+    out << "atomic<" << subtype_->FriendlyName(symbols) << ">";
+    return out.str();
 }
 
 uint32_t Atomic::Size() const {
-  return subtype_->Size();
+    return subtype_->Size();
 }
 
 uint32_t Atomic::Align() const {
-  return subtype_->Align();
+    return subtype_->Align();
 }
 
 bool Atomic::IsConstructible() const {
-  return false;
+    return false;
 }
 
 Atomic::Atomic(Atomic&&) = default;
diff --git a/src/tint/sem/atomic.h b/src/tint/sem/atomic.h
new file mode 100644
index 0000000..7f6c814
--- /dev/null
+++ b/src/tint/sem/atomic.h
@@ -0,0 +1,66 @@
+// Copyright 2021 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_SEM_ATOMIC_H_
+#define SRC_TINT_SEM_ATOMIC_H_
+
+#include <string>
+
+#include "src/tint/sem/type.h"
+
+namespace tint::sem {
+
+/// A atomic type.
+class Atomic final : public Castable<Atomic, Type> {
+  public:
+    /// Constructor
+    /// @param subtype the atomic type
+    explicit Atomic(const sem::Type* subtype);
+
+    /// Move constructor
+    Atomic(Atomic&&);
+    ~Atomic() override;
+
+    /// @returns a hash of the type.
+    size_t Hash() const override;
+
+    /// @param other the other type to compare against
+    /// @returns true if the this type is equal to the given type
+    bool Equals(const Type& other) const override;
+
+    /// @returns the atomic type
+    const sem::Type* Type() const { return subtype_; }
+
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type that closely resembles how it would be
+    /// declared in WGSL.
+    std::string FriendlyName(const SymbolTable& symbols) const override;
+
+    /// @returns the size in bytes of the type.
+    uint32_t Size() const override;
+
+    /// @returns the alignment in bytes of the type.
+    uint32_t Align() const override;
+
+    /// @returns true if constructible as per
+    /// https://gpuweb.github.io/gpuweb/wgsl/#constructible-types
+    bool IsConstructible() const override;
+
+  private:
+    sem::Type const* const subtype_;
+};
+
+}  // namespace tint::sem
+
+#endif  // SRC_TINT_SEM_ATOMIC_H_
diff --git a/src/tint/sem/atomic_test.cc b/src/tint/sem/atomic_test.cc
new file mode 100644
index 0000000..fbf9bc3
--- /dev/null
+++ b/src/tint/sem/atomic_test.cc
@@ -0,0 +1,56 @@
+// Copyright 2021 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/sem/atomic.h"
+
+#include "src/tint/sem/test_helper.h"
+
+namespace tint::sem {
+namespace {
+
+using AtomicTest = TestHelper;
+
+TEST_F(AtomicTest, Creation) {
+    auto* a = create<Atomic>(create<I32>());
+    auto* b = create<Atomic>(create<I32>());
+    auto* c = create<Atomic>(create<U32>());
+    EXPECT_TRUE(a->Type()->Is<sem::I32>());
+    EXPECT_EQ(a, b);
+    EXPECT_NE(a, c);
+}
+
+TEST_F(AtomicTest, Hash) {
+    auto* a = create<Atomic>(create<I32>());
+    auto* b = create<Atomic>(create<I32>());
+    auto* c = create<Atomic>(create<U32>());
+    EXPECT_EQ(a->Hash(), b->Hash());
+    EXPECT_NE(a->Hash(), c->Hash());
+}
+
+TEST_F(AtomicTest, Equals) {
+    auto* a = create<Atomic>(create<I32>());
+    auto* b = create<Atomic>(create<I32>());
+    auto* c = create<Atomic>(create<U32>());
+    EXPECT_TRUE(a->Equals(*b));
+    EXPECT_FALSE(a->Equals(*c));
+    EXPECT_FALSE(a->Equals(Void{}));
+}
+
+TEST_F(AtomicTest, FriendlyName) {
+    auto* a = create<Atomic>(create<I32>());
+    EXPECT_EQ(a->FriendlyName(Symbols()), "atomic<i32>");
+}
+
+}  // namespace
+}  // namespace tint::sem
diff --git a/src/tint/sem/atomic_type.h b/src/tint/sem/atomic_type.h
deleted file mode 100644
index e0dcb15..0000000
--- a/src/tint/sem/atomic_type.h
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2021 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SRC_TINT_SEM_ATOMIC_TYPE_H_
-#define SRC_TINT_SEM_ATOMIC_TYPE_H_
-
-#include <string>
-
-#include "src/tint/sem/type.h"
-
-namespace tint::sem {
-
-/// A atomic type.
-class Atomic final : public Castable<Atomic, Type> {
- public:
-  /// Constructor
-  /// @param subtype the atomic type
-  explicit Atomic(const sem::Type* subtype);
-
-  /// Move constructor
-  Atomic(Atomic&&);
-  ~Atomic() override;
-
-  /// @returns a hash of the type.
-  size_t Hash() const override;
-
-  /// @param other the other type to compare against
-  /// @returns true if the this type is equal to the given type
-  bool Equals(const Type& other) const override;
-
-  /// @returns the atomic type
-  const sem::Type* Type() const { return subtype_; }
-
-  /// @param symbols the program's symbol table
-  /// @returns the name for this type that closely resembles how it would be
-  /// declared in WGSL.
-  std::string FriendlyName(const SymbolTable& symbols) const override;
-
-  /// @returns the size in bytes of the type.
-  uint32_t Size() const override;
-
-  /// @returns the alignment in bytes of the type.
-  uint32_t Align() const override;
-
-  /// @returns true if constructible as per
-  /// https://gpuweb.github.io/gpuweb/wgsl/#constructible-typesd
-  bool IsConstructible() const override;
-
- private:
-  sem::Type const* const subtype_;
-};
-
-}  // namespace tint::sem
-
-#endif  // SRC_TINT_SEM_ATOMIC_TYPE_H_
diff --git a/src/tint/sem/atomic_type_test.cc b/src/tint/sem/atomic_type_test.cc
deleted file mode 100644
index 15aa484..0000000
--- a/src/tint/sem/atomic_type_test.cc
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2021 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/tint/sem/atomic_type.h"
-
-#include "src/tint/sem/test_helper.h"
-
-namespace tint::sem {
-namespace {
-
-using AtomicTest = TestHelper;
-
-TEST_F(AtomicTest, Creation) {
-  auto* a = create<Atomic>(create<I32>());
-  auto* b = create<Atomic>(create<I32>());
-  auto* c = create<Atomic>(create<U32>());
-  EXPECT_TRUE(a->Type()->Is<sem::I32>());
-  EXPECT_EQ(a, b);
-  EXPECT_NE(a, c);
-}
-
-TEST_F(AtomicTest, Hash) {
-  auto* a = create<Atomic>(create<I32>());
-  auto* b = create<Atomic>(create<I32>());
-  auto* c = create<Atomic>(create<U32>());
-  EXPECT_EQ(a->Hash(), b->Hash());
-  EXPECT_NE(a->Hash(), c->Hash());
-}
-
-TEST_F(AtomicTest, Equals) {
-  auto* a = create<Atomic>(create<I32>());
-  auto* b = create<Atomic>(create<I32>());
-  auto* c = create<Atomic>(create<U32>());
-  EXPECT_TRUE(a->Equals(*b));
-  EXPECT_FALSE(a->Equals(*c));
-  EXPECT_FALSE(a->Equals(Void{}));
-}
-
-TEST_F(AtomicTest, FriendlyName) {
-  auto* a = create<Atomic>(create<I32>());
-  EXPECT_EQ(a->FriendlyName(Symbols()), "atomic<i32>");
-}
-
-}  // namespace
-}  // namespace tint::sem
diff --git a/src/tint/sem/behavior.cc b/src/tint/sem/behavior.cc
index 628aa60..617794f 100644
--- a/src/tint/sem/behavior.cc
+++ b/src/tint/sem/behavior.cc
@@ -17,21 +17,21 @@
 namespace tint::sem {
 
 std::ostream& operator<<(std::ostream& out, Behavior behavior) {
-  switch (behavior) {
-    case Behavior::kReturn:
-      return out << "Return";
-    case Behavior::kDiscard:
-      return out << "Discard";
-    case Behavior::kBreak:
-      return out << "Break";
-    case Behavior::kContinue:
-      return out << "Continue";
-    case Behavior::kFallthrough:
-      return out << "Fallthrough";
-    case Behavior::kNext:
-      return out << "Next";
-  }
-  return out << "<unknown>";
+    switch (behavior) {
+        case Behavior::kReturn:
+            return out << "Return";
+        case Behavior::kDiscard:
+            return out << "Discard";
+        case Behavior::kBreak:
+            return out << "Break";
+        case Behavior::kContinue:
+            return out << "Continue";
+        case Behavior::kFallthrough:
+            return out << "Fallthrough";
+        case Behavior::kNext:
+            return out << "Next";
+    }
+    return out << "<unknown>";
 }
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/behavior.h b/src/tint/sem/behavior.h
index e8d158d..4acb8d5 100644
--- a/src/tint/sem/behavior.h
+++ b/src/tint/sem/behavior.h
@@ -22,12 +22,12 @@
 /// Behavior enumerates the possible behaviors of an expression or statement.
 /// @see https://www.w3.org/TR/WGSL/#behaviors
 enum class Behavior {
-  kReturn,
-  kDiscard,
-  kBreak,
-  kContinue,
-  kFallthrough,
-  kNext,
+    kReturn,
+    kDiscard,
+    kBreak,
+    kContinue,
+    kFallthrough,
+    kNext,
 };
 
 /// Behaviors is a set of Behavior
diff --git a/src/tint/sem/binding_point.h b/src/tint/sem/binding_point.h
index 8e8c6c7..993fb5e 100644
--- a/src/tint/sem/binding_point.h
+++ b/src/tint/sem/binding_point.h
@@ -25,24 +25,22 @@
 
 /// BindingPoint holds a group and binding index.
 struct BindingPoint {
-  /// The `@group` part of the binding point
-  uint32_t group = 0;
-  /// The `@binding` part of the binding point
-  uint32_t binding = 0;
+    /// The `@group` part of the binding point
+    uint32_t group = 0;
+    /// The `@binding` part of the binding point
+    uint32_t binding = 0;
 
-  /// Equality operator
-  /// @param rhs the BindingPoint to compare against
-  /// @returns true if this BindingPoint is equal to `rhs`
-  inline bool operator==(const BindingPoint& rhs) const {
-    return group == rhs.group && binding == rhs.binding;
-  }
+    /// Equality operator
+    /// @param rhs the BindingPoint to compare against
+    /// @returns true if this BindingPoint is equal to `rhs`
+    inline bool operator==(const BindingPoint& rhs) const {
+        return group == rhs.group && binding == rhs.binding;
+    }
 
-  /// Inequality operator
-  /// @param rhs the BindingPoint to compare against
-  /// @returns true if this BindingPoint is not equal to `rhs`
-  inline bool operator!=(const BindingPoint& rhs) const {
-    return !(*this == rhs);
-  }
+    /// Inequality operator
+    /// @param rhs the BindingPoint to compare against
+    /// @returns true if this BindingPoint is not equal to `rhs`
+    inline bool operator!=(const BindingPoint& rhs) const { return !(*this == rhs); }
 };
 
 }  // namespace tint::sem
@@ -54,13 +52,12 @@
 /// std::unordered_set.
 template <>
 class hash<tint::sem::BindingPoint> {
- public:
-  /// @param binding_point the binding point to create a hash for
-  /// @return the hash value
-  inline std::size_t operator()(
-      const tint::sem::BindingPoint& binding_point) const {
-    return tint::utils::Hash(binding_point.group, binding_point.binding);
-  }
+  public:
+    /// @param binding_point the binding point to create a hash for
+    /// @return the hash value
+    inline std::size_t operator()(const tint::sem::BindingPoint& binding_point) const {
+        return tint::utils::Hash(binding_point.group, binding_point.binding);
+    }
 };
 
 }  // namespace std
diff --git a/src/tint/sem/block_statement.cc b/src/tint/sem/block_statement.cc
index 7074483..51bad0f 100644
--- a/src/tint/sem/block_statement.cc
+++ b/src/tint/sem/block_statement.cc
@@ -32,16 +32,16 @@
 BlockStatement::~BlockStatement() = default;
 
 const ast::BlockStatement* BlockStatement::Declaration() const {
-  return Base::Declaration()->As<ast::BlockStatement>();
+    return Base::Declaration()->As<ast::BlockStatement>();
 }
 
 void BlockStatement::AddDecl(const ast::Variable* var) {
-  decls_.push_back(var);
+    decls_.push_back(var);
 }
 
 FunctionBlockStatement::FunctionBlockStatement(const sem::Function* function)
     : Base(function->Declaration()->body, nullptr, function) {
-  TINT_ASSERT(Semantic, function);
+    TINT_ASSERT(Semantic, function);
 }
 
 FunctionBlockStatement::~FunctionBlockStatement() = default;
@@ -50,16 +50,15 @@
                                        const CompoundStatement* parent,
                                        const sem::Function* function)
     : Base(declaration, parent, function) {
-  TINT_ASSERT(Semantic, parent);
-  TINT_ASSERT(Semantic, function);
+    TINT_ASSERT(Semantic, parent);
+    TINT_ASSERT(Semantic, function);
 }
 LoopBlockStatement::~LoopBlockStatement() = default;
 
-void LoopBlockStatement::SetFirstContinue(
-    const ast::ContinueStatement* first_continue,
-    size_t num_decls) {
-  first_continue_ = first_continue;
-  num_decls_at_first_continue_ = num_decls;
+void LoopBlockStatement::SetFirstContinue(const ast::ContinueStatement* first_continue,
+                                          size_t num_decls) {
+    first_continue_ = first_continue;
+    num_decls_at_first_continue_ = num_decls;
 }
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/block_statement.h b/src/tint/sem/block_statement.h
index 6b71baf..e87b225 100644
--- a/src/tint/sem/block_statement.h
+++ b/src/tint/sem/block_statement.h
@@ -33,85 +33,78 @@
 /// Holds semantic information about a block, such as parent block and variables
 /// declared in the block.
 class BlockStatement : public Castable<BlockStatement, CompoundStatement> {
- public:
-  /// Constructor
-  /// @param declaration the AST node for this block statement
-  /// @param parent the owning statement
-  /// @param function the owning function
-  BlockStatement(const ast::BlockStatement* declaration,
-                 const CompoundStatement* parent,
-                 const sem::Function* function);
+  public:
+    /// Constructor
+    /// @param declaration the AST node for this block statement
+    /// @param parent the owning statement
+    /// @param function the owning function
+    BlockStatement(const ast::BlockStatement* declaration,
+                   const CompoundStatement* parent,
+                   const sem::Function* function);
 
-  /// Destructor
-  ~BlockStatement() override;
+    /// Destructor
+    ~BlockStatement() override;
 
-  /// @returns the AST block statement associated with this semantic block
-  /// statement
-  const ast::BlockStatement* Declaration() const;
+    /// @returns the AST block statement associated with this semantic block
+    /// statement
+    const ast::BlockStatement* Declaration() const;
 
-  /// @returns the declarations associated with this block
-  const std::vector<const ast::Variable*>& Decls() const { return decls_; }
+    /// @returns the declarations associated with this block
+    const std::vector<const ast::Variable*>& Decls() const { return decls_; }
 
-  /// Associates a declaration with this block.
-  /// @param var a variable declaration to be added to the block
-  void AddDecl(const ast::Variable* var);
+    /// Associates a declaration with this block.
+    /// @param var a variable declaration to be added to the block
+    void AddDecl(const ast::Variable* var);
 
- private:
-  std::vector<const ast::Variable*> decls_;
+  private:
+    std::vector<const ast::Variable*> decls_;
 };
 
 /// The root block statement for a function
-class FunctionBlockStatement final
-    : public Castable<FunctionBlockStatement, BlockStatement> {
- public:
-  /// Constructor
-  /// @param function the owning function
-  explicit FunctionBlockStatement(const sem::Function* function);
+class FunctionBlockStatement final : public Castable<FunctionBlockStatement, BlockStatement> {
+  public:
+    /// Constructor
+    /// @param function the owning function
+    explicit FunctionBlockStatement(const sem::Function* function);
 
-  /// Destructor
-  ~FunctionBlockStatement() override;
+    /// Destructor
+    ~FunctionBlockStatement() override;
 };
 
 /// Holds semantic information about a loop body block or for-loop body block
-class LoopBlockStatement final
-    : public Castable<LoopBlockStatement, BlockStatement> {
- public:
-  /// Constructor
-  /// @param declaration the AST node for this block statement
-  /// @param parent the owning statement
-  /// @param function the owning function
-  LoopBlockStatement(const ast::BlockStatement* declaration,
-                     const CompoundStatement* parent,
-                     const sem::Function* function);
+class LoopBlockStatement final : public Castable<LoopBlockStatement, BlockStatement> {
+  public:
+    /// Constructor
+    /// @param declaration the AST node for this block statement
+    /// @param parent the owning statement
+    /// @param function the owning function
+    LoopBlockStatement(const ast::BlockStatement* declaration,
+                       const CompoundStatement* parent,
+                       const sem::Function* function);
 
-  /// Destructor
-  ~LoopBlockStatement() override;
+    /// Destructor
+    ~LoopBlockStatement() override;
 
-  /// @returns the first continue statement in this loop block, or nullptr if
-  /// there are no continue statements in the block
-  const ast::ContinueStatement* FirstContinue() const {
-    return first_continue_;
-  }
+    /// @returns the first continue statement in this loop block, or nullptr if
+    /// there are no continue statements in the block
+    const ast::ContinueStatement* FirstContinue() const { return first_continue_; }
 
-  /// @returns the number of variables declared before the first continue
-  /// statement
-  size_t NumDeclsAtFirstContinue() const {
-    return num_decls_at_first_continue_;
-  }
+    /// @returns the number of variables declared before the first continue
+    /// statement
+    size_t NumDeclsAtFirstContinue() const { return num_decls_at_first_continue_; }
 
-  /// Allows the resolver to record the first continue statement in the block
-  /// and the number of variables declared prior to that statement.
-  /// @param first_continue the first continue statement in the block
-  /// @param num_decls the number of variable declarations before that continue
-  void SetFirstContinue(const ast::ContinueStatement* first_continue,
-                        size_t num_decls);
+    /// Allows the resolver to record the first continue statement in the block
+    /// and the number of variables declared prior to that statement.
+    /// @param first_continue the first continue statement in the block
+    /// @param num_decls the number of variable declarations before that continue
+    void SetFirstContinue(const ast::ContinueStatement* first_continue, size_t num_decls);
 
- private:
-  /// The first continue statement in this loop block.
-  const ast::ContinueStatement* first_continue_ = nullptr;
+  private:
+    /// The first continue statement in this loop block.
+    const ast::ContinueStatement* first_continue_ = nullptr;
 
-  /// The number of variables declared before the first continue statement.
-  size_t num_decls_at_first_continue_ = 0;
+    /// The number of variables declared before the first continue statement.
+    size_t num_decls_at_first_continue_ = 0;
 };
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/bool_type.cc b/src/tint/sem/bool.cc
similarity index 84%
rename from src/tint/sem/bool_type.cc
rename to src/tint/sem/bool.cc
index 7a20768..938a935 100644
--- a/src/tint/sem/bool_type.cc
+++ b/src/tint/sem/bool.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/sem/bool_type.h"
+#include "src/tint/sem/bool.h"
 
 #include "src/tint/program_builder.h"
 
@@ -27,27 +27,27 @@
 Bool::~Bool() = default;
 
 size_t Bool::Hash() const {
-  return static_cast<size_t>(TypeInfo::Of<Bool>().full_hashcode);
+    return static_cast<size_t>(TypeInfo::Of<Bool>().full_hashcode);
 }
 
 bool Bool::Equals(const Type& other) const {
-  return other.Is<Bool>();
+    return other.Is<Bool>();
 }
 
 std::string Bool::FriendlyName(const SymbolTable&) const {
-  return "bool";
+    return "bool";
 }
 
 bool Bool::IsConstructible() const {
-  return true;
+    return true;
 }
 
 uint32_t Bool::Size() const {
-  return 4;
+    return 4;
 }
 
 uint32_t Bool::Align() const {
-  return 4;
+    return 4;
 }
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/bool.h b/src/tint/sem/bool.h
new file mode 100644
index 0000000..aae48d8
--- /dev/null
+++ b/src/tint/sem/bool.h
@@ -0,0 +1,68 @@
+// 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_SEM_BOOL_H_
+#define SRC_TINT_SEM_BOOL_H_
+
+#include <string>
+
+#include "src/tint/sem/type.h"
+
+// X11 likes to #define Bool leading to confusing error messages.
+// If its defined, undefine it.
+#ifdef Bool
+#undef Bool
+#endif
+
+namespace tint::sem {
+
+/// A boolean type
+class Bool final : public Castable<Bool, Type> {
+  public:
+    /// Constructor
+    Bool();
+    /// Move constructor
+    Bool(Bool&&);
+    ~Bool() override;
+
+    /// @returns a hash of the type.
+    size_t Hash() const override;
+
+    /// @param other the other type to compare against
+    /// @returns true if the this type is equal to the given type
+    bool Equals(const Type& other) const override;
+
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type that closely resembles how it would be
+    /// declared in WGSL.
+    std::string FriendlyName(const SymbolTable& symbols) const override;
+
+    /// @returns true if constructible as per
+    /// https://gpuweb.github.io/gpuweb/wgsl/#constructible-types
+    bool IsConstructible() const override;
+
+    /// @returns the size in bytes of the type.
+    /// @note: booleans are not host-sharable, but still may exist in workgroup
+    /// storage.
+    uint32_t Size() const override;
+
+    /// @returns the alignment in bytes of the type.
+    /// @note: booleans are not host-sharable, but still may exist in workgroup
+    /// storage.
+    uint32_t Align() const override;
+};
+
+}  // namespace tint::sem
+
+#endif  // SRC_TINT_SEM_BOOL_H_
diff --git a/src/tint/sem/bool_type_test.cc b/src/tint/sem/bool_test.cc
similarity index 68%
rename from src/tint/sem/bool_type_test.cc
rename to src/tint/sem/bool_test.cc
index 390de43..bbd7f74 100644
--- a/src/tint/sem/bool_type_test.cc
+++ b/src/tint/sem/bool_test.cc
@@ -13,7 +13,7 @@
 // limitations under the License.
 
 #include "src/tint/sem/test_helper.h"
-#include "src/tint/sem/texture_type.h"
+#include "src/tint/sem/texture.h"
 
 namespace tint::sem {
 namespace {
@@ -21,27 +21,27 @@
 using BoolTest = TestHelper;
 
 TEST_F(BoolTest, Creation) {
-  auto* a = create<Bool>();
-  auto* b = create<Bool>();
-  EXPECT_EQ(a, b);
+    auto* a = create<Bool>();
+    auto* b = create<Bool>();
+    EXPECT_EQ(a, b);
 }
 
 TEST_F(BoolTest, Hash) {
-  auto* a = create<Bool>();
-  auto* b = create<Bool>();
-  EXPECT_EQ(a->Hash(), b->Hash());
+    auto* a = create<Bool>();
+    auto* b = create<Bool>();
+    EXPECT_EQ(a->Hash(), b->Hash());
 }
 
 TEST_F(BoolTest, Equals) {
-  auto* a = create<Bool>();
-  auto* b = create<Bool>();
-  EXPECT_TRUE(a->Equals(*b));
-  EXPECT_FALSE(a->Equals(Void{}));
+    auto* a = create<Bool>();
+    auto* b = create<Bool>();
+    EXPECT_TRUE(a->Equals(*b));
+    EXPECT_FALSE(a->Equals(Void{}));
 }
 
 TEST_F(BoolTest, FriendlyName) {
-  Bool b;
-  EXPECT_EQ(b.FriendlyName(Symbols()), "bool");
+    Bool b;
+    EXPECT_EQ(b.FriendlyName(Symbols()), "bool");
 }
 
 }  // namespace
diff --git a/src/tint/sem/bool_type.h b/src/tint/sem/bool_type.h
deleted file mode 100644
index 9e949bd..0000000
--- a/src/tint/sem/bool_type.h
+++ /dev/null
@@ -1,68 +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_SEM_BOOL_TYPE_H_
-#define SRC_TINT_SEM_BOOL_TYPE_H_
-
-#include <string>
-
-#include "src/tint/sem/type.h"
-
-// X11 likes to #define Bool leading to confusing error messages.
-// If its defined, undefine it.
-#ifdef Bool
-#undef Bool
-#endif
-
-namespace tint::sem {
-
-/// A boolean type
-class Bool final : public Castable<Bool, Type> {
- public:
-  /// Constructor
-  Bool();
-  /// Move constructor
-  Bool(Bool&&);
-  ~Bool() override;
-
-  /// @returns a hash of the type.
-  size_t Hash() const override;
-
-  /// @param other the other type to compare against
-  /// @returns true if the this type is equal to the given type
-  bool Equals(const Type& other) const override;
-
-  /// @param symbols the program's symbol table
-  /// @returns the name for this type that closely resembles how it would be
-  /// declared in WGSL.
-  std::string FriendlyName(const SymbolTable& symbols) const override;
-
-  /// @returns true if constructible as per
-  /// https://gpuweb.github.io/gpuweb/wgsl/#constructible-types
-  bool IsConstructible() const override;
-
-  /// @returns the size in bytes of the type.
-  /// @note: booleans are not host-sharable, but still may exist in workgroup
-  /// storage.
-  uint32_t Size() const override;
-
-  /// @returns the alignment in bytes of the type.
-  /// @note: booleans are not host-sharable, but still may exist in workgroup
-  /// storage.
-  uint32_t Align() const override;
-};
-
-}  // namespace tint::sem
-
-#endif  // SRC_TINT_SEM_BOOL_TYPE_H_
diff --git a/src/tint/sem/builtin.cc b/src/tint/sem/builtin.cc
index a822be5..66b5b27 100644
--- a/src/tint/sem/builtin.cc
+++ b/src/tint/sem/builtin.cc
@@ -26,76 +26,61 @@
 namespace tint::sem {
 
 const char* Builtin::str() const {
-  return sem::str(type_);
+    return sem::str(type_);
 }
 
 bool IsCoarseDerivativeBuiltin(BuiltinType i) {
-  return i == BuiltinType::kDpdxCoarse || i == BuiltinType::kDpdyCoarse ||
-         i == BuiltinType::kFwidthCoarse;
+    return i == BuiltinType::kDpdxCoarse || i == BuiltinType::kDpdyCoarse ||
+           i == BuiltinType::kFwidthCoarse;
 }
 
 bool IsFineDerivativeBuiltin(BuiltinType i) {
-  return i == BuiltinType::kDpdxFine || i == BuiltinType::kDpdyFine ||
-         i == BuiltinType::kFwidthFine;
+    return i == BuiltinType::kDpdxFine || i == BuiltinType::kDpdyFine ||
+           i == BuiltinType::kFwidthFine;
 }
 
 bool IsDerivativeBuiltin(BuiltinType i) {
-  return i == BuiltinType::kDpdx || i == BuiltinType::kDpdy ||
-         i == BuiltinType::kFwidth || IsCoarseDerivativeBuiltin(i) ||
-         IsFineDerivativeBuiltin(i);
+    return i == BuiltinType::kDpdx || i == BuiltinType::kDpdy || i == BuiltinType::kFwidth ||
+           IsCoarseDerivativeBuiltin(i) || IsFineDerivativeBuiltin(i);
 }
 
 bool IsTextureBuiltin(BuiltinType i) {
-  return IsImageQueryBuiltin(i) || i == BuiltinType::kTextureLoad ||
-         i == BuiltinType::kTextureGather ||
-         i == BuiltinType::kTextureGatherCompare ||
-         i == BuiltinType::kTextureSample ||
-         i == BuiltinType::kTextureSampleLevel ||
-         i == BuiltinType::kTextureSampleBias ||
-         i == BuiltinType::kTextureSampleCompare ||
-         i == BuiltinType::kTextureSampleCompareLevel ||
-         i == BuiltinType::kTextureSampleGrad ||
-         i == BuiltinType::kTextureStore;
+    return IsImageQueryBuiltin(i) || i == BuiltinType::kTextureLoad ||
+           i == BuiltinType::kTextureGather || i == BuiltinType::kTextureGatherCompare ||
+           i == BuiltinType::kTextureSample || i == BuiltinType::kTextureSampleLevel ||
+           i == BuiltinType::kTextureSampleBias || i == BuiltinType::kTextureSampleCompare ||
+           i == BuiltinType::kTextureSampleCompareLevel || i == BuiltinType::kTextureSampleGrad ||
+           i == BuiltinType::kTextureStore;
 }
 
 bool IsImageQueryBuiltin(BuiltinType i) {
-  return i == BuiltinType::kTextureDimensions ||
-         i == BuiltinType::kTextureNumLayers ||
-         i == BuiltinType::kTextureNumLevels ||
-         i == BuiltinType::kTextureNumSamples;
+    return i == BuiltinType::kTextureDimensions || i == BuiltinType::kTextureNumLayers ||
+           i == BuiltinType::kTextureNumLevels || i == BuiltinType::kTextureNumSamples;
 }
 
 bool IsDataPackingBuiltin(BuiltinType i) {
-  return i == BuiltinType::kPack4x8snorm || i == BuiltinType::kPack4x8unorm ||
-         i == BuiltinType::kPack2x16snorm || i == BuiltinType::kPack2x16unorm ||
-         i == BuiltinType::kPack2x16float;
+    return i == BuiltinType::kPack4x8snorm || i == BuiltinType::kPack4x8unorm ||
+           i == BuiltinType::kPack2x16snorm || i == BuiltinType::kPack2x16unorm ||
+           i == BuiltinType::kPack2x16float;
 }
 
 bool IsDataUnpackingBuiltin(BuiltinType i) {
-  return i == BuiltinType::kUnpack4x8snorm ||
-         i == BuiltinType::kUnpack4x8unorm ||
-         i == BuiltinType::kUnpack2x16snorm ||
-         i == BuiltinType::kUnpack2x16unorm ||
-         i == BuiltinType::kUnpack2x16float;
+    return i == BuiltinType::kUnpack4x8snorm || i == BuiltinType::kUnpack4x8unorm ||
+           i == BuiltinType::kUnpack2x16snorm || i == BuiltinType::kUnpack2x16unorm ||
+           i == BuiltinType::kUnpack2x16float;
 }
 
 bool IsBarrierBuiltin(BuiltinType i) {
-  return i == BuiltinType::kWorkgroupBarrier ||
-         i == BuiltinType::kStorageBarrier;
+    return i == BuiltinType::kWorkgroupBarrier || i == BuiltinType::kStorageBarrier;
 }
 
 bool IsAtomicBuiltin(BuiltinType i) {
-  return i == sem::BuiltinType::kAtomicLoad ||
-         i == sem::BuiltinType::kAtomicStore ||
-         i == sem::BuiltinType::kAtomicAdd ||
-         i == sem::BuiltinType::kAtomicSub ||
-         i == sem::BuiltinType::kAtomicMax ||
-         i == sem::BuiltinType::kAtomicMin ||
-         i == sem::BuiltinType::kAtomicAnd ||
-         i == sem::BuiltinType::kAtomicOr ||
-         i == sem::BuiltinType::kAtomicXor ||
-         i == sem::BuiltinType::kAtomicExchange ||
-         i == sem::BuiltinType::kAtomicCompareExchangeWeak;
+    return i == sem::BuiltinType::kAtomicLoad || i == sem::BuiltinType::kAtomicStore ||
+           i == sem::BuiltinType::kAtomicAdd || i == sem::BuiltinType::kAtomicSub ||
+           i == sem::BuiltinType::kAtomicMax || i == sem::BuiltinType::kAtomicMin ||
+           i == sem::BuiltinType::kAtomicAnd || i == sem::BuiltinType::kAtomicOr ||
+           i == sem::BuiltinType::kAtomicXor || i == sem::BuiltinType::kAtomicExchange ||
+           i == sem::BuiltinType::kAtomicCompareExchangeWeak;
 }
 
 Builtin::Builtin(BuiltinType type,
@@ -107,57 +92,57 @@
       type_(type),
       supported_stages_(supported_stages),
       is_deprecated_(is_deprecated) {
-  for (auto* parameter : parameters) {
-    parameter->SetOwner(this);
-  }
+    for (auto* parameter : parameters) {
+        parameter->SetOwner(this);
+    }
 }
 
 Builtin::~Builtin() = default;
 
 bool Builtin::IsCoarseDerivative() const {
-  return IsCoarseDerivativeBuiltin(type_);
+    return IsCoarseDerivativeBuiltin(type_);
 }
 
 bool Builtin::IsFineDerivative() const {
-  return IsFineDerivativeBuiltin(type_);
+    return IsFineDerivativeBuiltin(type_);
 }
 
 bool Builtin::IsDerivative() const {
-  return IsDerivativeBuiltin(type_);
+    return IsDerivativeBuiltin(type_);
 }
 
 bool Builtin::IsTexture() const {
-  return IsTextureBuiltin(type_);
+    return IsTextureBuiltin(type_);
 }
 
 bool Builtin::IsImageQuery() const {
-  return IsImageQueryBuiltin(type_);
+    return IsImageQueryBuiltin(type_);
 }
 
 bool Builtin::IsDataPacking() const {
-  return IsDataPackingBuiltin(type_);
+    return IsDataPackingBuiltin(type_);
 }
 
 bool Builtin::IsDataUnpacking() const {
-  return IsDataUnpackingBuiltin(type_);
+    return IsDataUnpackingBuiltin(type_);
 }
 
 bool Builtin::IsBarrier() const {
-  return IsBarrierBuiltin(type_);
+    return IsBarrierBuiltin(type_);
 }
 
 bool Builtin::IsAtomic() const {
-  return IsAtomicBuiltin(type_);
+    return IsAtomicBuiltin(type_);
 }
 
 bool Builtin::HasSideEffects() const {
-  if (IsAtomic() && type_ != sem::BuiltinType::kAtomicLoad) {
-    return true;
-  }
-  if (type_ == sem::BuiltinType::kTextureStore) {
-    return true;
-  }
-  return false;
+    if (IsAtomic() && type_ != sem::BuiltinType::kAtomicLoad) {
+        return true;
+    }
+    if (type_ == sem::BuiltinType::kTextureStore) {
+        return true;
+    }
+    return false;
 }
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/builtin.h b/src/tint/sem/builtin.h
index 61589ee..d742f95 100644
--- a/src/tint/sem/builtin.h
+++ b/src/tint/sem/builtin.h
@@ -72,72 +72,72 @@
 
 /// Builtin holds the semantic information for a builtin function.
 class Builtin final : public Castable<Builtin, CallTarget> {
- public:
-  /// Constructor
-  /// @param type the builtin type
-  /// @param return_type the return type for the builtin call
-  /// @param parameters the parameters for the builtin overload
-  /// @param supported_stages the pipeline stages that this builtin can be
-  /// used in
-  /// @param is_deprecated true if the particular overload is considered
-  /// deprecated
-  Builtin(BuiltinType type,
-          const sem::Type* return_type,
-          std::vector<Parameter*> parameters,
-          PipelineStageSet supported_stages,
-          bool is_deprecated);
+  public:
+    /// Constructor
+    /// @param type the builtin type
+    /// @param return_type the return type for the builtin call
+    /// @param parameters the parameters for the builtin overload
+    /// @param supported_stages the pipeline stages that this builtin can be
+    /// used in
+    /// @param is_deprecated true if the particular overload is considered
+    /// deprecated
+    Builtin(BuiltinType type,
+            const sem::Type* return_type,
+            std::vector<Parameter*> parameters,
+            PipelineStageSet supported_stages,
+            bool is_deprecated);
 
-  /// Destructor
-  ~Builtin() override;
+    /// Destructor
+    ~Builtin() override;
 
-  /// @return the type of the builtin
-  BuiltinType Type() const { return type_; }
+    /// @return the type of the builtin
+    BuiltinType Type() const { return type_; }
 
-  /// @return the pipeline stages that this builtin can be used in
-  PipelineStageSet SupportedStages() const { return supported_stages_; }
+    /// @return the pipeline stages that this builtin can be used in
+    PipelineStageSet SupportedStages() const { return supported_stages_; }
 
-  /// @return true if the builtin overload is considered deprecated
-  bool IsDeprecated() const { return is_deprecated_; }
+    /// @return true if the builtin overload is considered deprecated
+    bool IsDeprecated() const { return is_deprecated_; }
 
-  /// @returns the name of the builtin function type. The spelling, including
-  /// case, matches the name in the WGSL spec.
-  const char* str() const;
+    /// @returns the name of the builtin function type. The spelling, including
+    /// case, matches the name in the WGSL spec.
+    const char* str() const;
 
-  /// @returns true if builtin is a coarse derivative builtin
-  bool IsCoarseDerivative() const;
+    /// @returns true if builtin is a coarse derivative builtin
+    bool IsCoarseDerivative() const;
 
-  /// @returns true if builtin is a fine a derivative builtin
-  bool IsFineDerivative() const;
+    /// @returns true if builtin is a fine a derivative builtin
+    bool IsFineDerivative() const;
 
-  /// @returns true if builtin is a derivative builtin
-  bool IsDerivative() const;
+    /// @returns true if builtin is a derivative builtin
+    bool IsDerivative() const;
 
-  /// @returns true if builtin is a texture operation builtin
-  bool IsTexture() const;
+    /// @returns true if builtin is a texture operation builtin
+    bool IsTexture() const;
 
-  /// @returns true if builtin is a image query builtin
-  bool IsImageQuery() const;
+    /// @returns true if builtin is a image query builtin
+    bool IsImageQuery() const;
 
-  /// @returns true if builtin is a data packing builtin
-  bool IsDataPacking() const;
+    /// @returns true if builtin is a data packing builtin
+    bool IsDataPacking() const;
 
-  /// @returns true if builtin is a data unpacking builtin
-  bool IsDataUnpacking() const;
+    /// @returns true if builtin is a data unpacking builtin
+    bool IsDataUnpacking() const;
 
-  /// @returns true if builtin is a barrier builtin
-  bool IsBarrier() const;
+    /// @returns true if builtin is a barrier builtin
+    bool IsBarrier() const;
 
-  /// @returns true if builtin is a atomic builtin
-  bool IsAtomic() const;
+    /// @returns true if builtin is a atomic builtin
+    bool IsAtomic() const;
 
-  /// @returns true if intrinsic may have side-effects (i.e. writes to at least
-  /// one of its inputs)
-  bool HasSideEffects() const;
+    /// @returns true if intrinsic may have side-effects (i.e. writes to at least
+    /// one of its inputs)
+    bool HasSideEffects() const;
 
- private:
-  const BuiltinType type_;
-  const PipelineStageSet supported_stages_;
-  const bool is_deprecated_;
+  private:
+    const BuiltinType type_;
+    const PipelineStageSet supported_stages_;
+    const bool is_deprecated_;
 };
 
 /// Constant value used by the degrees() builtin
@@ -153,13 +153,13 @@
 /// Custom std::hash specialization for tint::sem::Builtin
 template <>
 class hash<tint::sem::Builtin> {
- public:
-  /// @param i the Builtin to create a hash for
-  /// @return the hash value
-  inline std::size_t operator()(const tint::sem::Builtin& i) const {
-    return tint::utils::Hash(i.Type(), i.SupportedStages(), i.ReturnType(),
-                             i.Parameters(), i.IsDeprecated());
-  }
+  public:
+    /// @param i the Builtin to create a hash for
+    /// @return the hash value
+    inline std::size_t operator()(const tint::sem::Builtin& i) const {
+        return tint::utils::Hash(i.Type(), i.SupportedStages(), i.ReturnType(), i.Parameters(),
+                                 i.IsDeprecated());
+    }
 };
 
 }  // namespace std
diff --git a/src/tint/sem/builtin_test.cc b/src/tint/sem/builtin_test.cc
index d931bcf..f3cbae3 100644
--- a/src/tint/sem/builtin_test.cc
+++ b/src/tint/sem/builtin_test.cc
@@ -20,106 +20,105 @@
 namespace {
 
 struct BuiltinData {
-  const char* name;
-  BuiltinType builtin;
+    const char* name;
+    BuiltinType builtin;
 };
 
 inline std::ostream& operator<<(std::ostream& out, BuiltinData data) {
-  out << data.name;
-  return out;
+    out << data.name;
+    return out;
 }
 
 using BuiltinTypeTest = testing::TestWithParam<BuiltinData>;
 
 TEST_P(BuiltinTypeTest, Parse) {
-  auto param = GetParam();
-  EXPECT_EQ(ParseBuiltinType(param.name), param.builtin);
+    auto param = GetParam();
+    EXPECT_EQ(ParseBuiltinType(param.name), param.builtin);
 }
 
 INSTANTIATE_TEST_SUITE_P(
     BuiltinTypeTest,
     BuiltinTypeTest,
-    testing::Values(
-        BuiltinData{"abs", BuiltinType::kAbs},
-        BuiltinData{"acos", BuiltinType::kAcos},
-        BuiltinData{"all", BuiltinType::kAll},
-        BuiltinData{"any", BuiltinType::kAny},
-        BuiltinData{"arrayLength", BuiltinType::kArrayLength},
-        BuiltinData{"asin", BuiltinType::kAsin},
-        BuiltinData{"atan", BuiltinType::kAtan},
-        BuiltinData{"atan2", BuiltinType::kAtan2},
-        BuiltinData{"ceil", BuiltinType::kCeil},
-        BuiltinData{"clamp", BuiltinType::kClamp},
-        BuiltinData{"cos", BuiltinType::kCos},
-        BuiltinData{"cosh", BuiltinType::kCosh},
-        BuiltinData{"countOneBits", BuiltinType::kCountOneBits},
-        BuiltinData{"cross", BuiltinType::kCross},
-        BuiltinData{"determinant", BuiltinType::kDeterminant},
-        BuiltinData{"distance", BuiltinType::kDistance},
-        BuiltinData{"dot", BuiltinType::kDot},
-        BuiltinData{"dpdx", BuiltinType::kDpdx},
-        BuiltinData{"dpdxCoarse", BuiltinType::kDpdxCoarse},
-        BuiltinData{"dpdxFine", BuiltinType::kDpdxFine},
-        BuiltinData{"dpdy", BuiltinType::kDpdy},
-        BuiltinData{"dpdyCoarse", BuiltinType::kDpdyCoarse},
-        BuiltinData{"dpdyFine", BuiltinType::kDpdyFine},
-        BuiltinData{"exp", BuiltinType::kExp},
-        BuiltinData{"exp2", BuiltinType::kExp2},
-        BuiltinData{"faceForward", BuiltinType::kFaceForward},
-        BuiltinData{"floor", BuiltinType::kFloor},
-        BuiltinData{"fma", BuiltinType::kFma},
-        BuiltinData{"fract", BuiltinType::kFract},
-        BuiltinData{"frexp", BuiltinType::kFrexp},
-        BuiltinData{"fwidth", BuiltinType::kFwidth},
-        BuiltinData{"fwidthCoarse", BuiltinType::kFwidthCoarse},
-        BuiltinData{"fwidthFine", BuiltinType::kFwidthFine},
-        BuiltinData{"inverseSqrt", BuiltinType::kInverseSqrt},
-        BuiltinData{"ldexp", BuiltinType::kLdexp},
-        BuiltinData{"length", BuiltinType::kLength},
-        BuiltinData{"log", BuiltinType::kLog},
-        BuiltinData{"log2", BuiltinType::kLog2},
-        BuiltinData{"max", BuiltinType::kMax},
-        BuiltinData{"min", BuiltinType::kMin},
-        BuiltinData{"mix", BuiltinType::kMix},
-        BuiltinData{"modf", BuiltinType::kModf},
-        BuiltinData{"normalize", BuiltinType::kNormalize},
-        BuiltinData{"pow", BuiltinType::kPow},
-        BuiltinData{"reflect", BuiltinType::kReflect},
-        BuiltinData{"reverseBits", BuiltinType::kReverseBits},
-        BuiltinData{"round", BuiltinType::kRound},
-        BuiltinData{"select", BuiltinType::kSelect},
-        BuiltinData{"sign", BuiltinType::kSign},
-        BuiltinData{"sin", BuiltinType::kSin},
-        BuiltinData{"sinh", BuiltinType::kSinh},
-        BuiltinData{"smoothstep", BuiltinType::kSmoothstep},
-        BuiltinData{"smoothStep", BuiltinType::kSmoothStep},
-        BuiltinData{"sqrt", BuiltinType::kSqrt},
-        BuiltinData{"step", BuiltinType::kStep},
-        BuiltinData{"storageBarrier", BuiltinType::kStorageBarrier},
-        BuiltinData{"tan", BuiltinType::kTan},
-        BuiltinData{"tanh", BuiltinType::kTanh},
-        BuiltinData{"textureDimensions", BuiltinType::kTextureDimensions},
-        BuiltinData{"textureLoad", BuiltinType::kTextureLoad},
-        BuiltinData{"textureNumLayers", BuiltinType::kTextureNumLayers},
-        BuiltinData{"textureNumLevels", BuiltinType::kTextureNumLevels},
-        BuiltinData{"textureNumSamples", BuiltinType::kTextureNumSamples},
-        BuiltinData{"textureSample", BuiltinType::kTextureSample},
-        BuiltinData{"textureSampleBias", BuiltinType::kTextureSampleBias},
-        BuiltinData{"textureSampleCompare", BuiltinType::kTextureSampleCompare},
-        BuiltinData{"textureSampleCompareLevel",
-                    BuiltinType::kTextureSampleCompareLevel},
-        BuiltinData{"textureSampleGrad", BuiltinType::kTextureSampleGrad},
-        BuiltinData{"textureSampleLevel", BuiltinType::kTextureSampleLevel},
-        BuiltinData{"trunc", BuiltinType::kTrunc},
-        BuiltinData{"unpack2x16float", BuiltinType::kUnpack2x16float},
-        BuiltinData{"unpack2x16snorm", BuiltinType::kUnpack2x16snorm},
-        BuiltinData{"unpack2x16unorm", BuiltinType::kUnpack2x16unorm},
-        BuiltinData{"unpack4x8snorm", BuiltinType::kUnpack4x8snorm},
-        BuiltinData{"unpack4x8unorm", BuiltinType::kUnpack4x8unorm},
-        BuiltinData{"workgroupBarrier", BuiltinType::kWorkgroupBarrier}));
+    testing::Values(BuiltinData{"abs", BuiltinType::kAbs},
+                    BuiltinData{"acos", BuiltinType::kAcos},
+                    BuiltinData{"all", BuiltinType::kAll},
+                    BuiltinData{"any", BuiltinType::kAny},
+                    BuiltinData{"arrayLength", BuiltinType::kArrayLength},
+                    BuiltinData{"asin", BuiltinType::kAsin},
+                    BuiltinData{"atan", BuiltinType::kAtan},
+                    BuiltinData{"atan2", BuiltinType::kAtan2},
+                    BuiltinData{"ceil", BuiltinType::kCeil},
+                    BuiltinData{"clamp", BuiltinType::kClamp},
+                    BuiltinData{"cos", BuiltinType::kCos},
+                    BuiltinData{"cosh", BuiltinType::kCosh},
+                    BuiltinData{"countOneBits", BuiltinType::kCountOneBits},
+                    BuiltinData{"cross", BuiltinType::kCross},
+                    BuiltinData{"determinant", BuiltinType::kDeterminant},
+                    BuiltinData{"distance", BuiltinType::kDistance},
+                    BuiltinData{"dot", BuiltinType::kDot},
+                    BuiltinData{"dpdx", BuiltinType::kDpdx},
+                    BuiltinData{"dpdxCoarse", BuiltinType::kDpdxCoarse},
+                    BuiltinData{"dpdxFine", BuiltinType::kDpdxFine},
+                    BuiltinData{"dpdy", BuiltinType::kDpdy},
+                    BuiltinData{"dpdyCoarse", BuiltinType::kDpdyCoarse},
+                    BuiltinData{"dpdyFine", BuiltinType::kDpdyFine},
+                    BuiltinData{"exp", BuiltinType::kExp},
+                    BuiltinData{"exp2", BuiltinType::kExp2},
+                    BuiltinData{"faceForward", BuiltinType::kFaceForward},
+                    BuiltinData{"floor", BuiltinType::kFloor},
+                    BuiltinData{"fma", BuiltinType::kFma},
+                    BuiltinData{"fract", BuiltinType::kFract},
+                    BuiltinData{"frexp", BuiltinType::kFrexp},
+                    BuiltinData{"fwidth", BuiltinType::kFwidth},
+                    BuiltinData{"fwidthCoarse", BuiltinType::kFwidthCoarse},
+                    BuiltinData{"fwidthFine", BuiltinType::kFwidthFine},
+                    BuiltinData{"inverseSqrt", BuiltinType::kInverseSqrt},
+                    BuiltinData{"ldexp", BuiltinType::kLdexp},
+                    BuiltinData{"length", BuiltinType::kLength},
+                    BuiltinData{"log", BuiltinType::kLog},
+                    BuiltinData{"log2", BuiltinType::kLog2},
+                    BuiltinData{"max", BuiltinType::kMax},
+                    BuiltinData{"min", BuiltinType::kMin},
+                    BuiltinData{"mix", BuiltinType::kMix},
+                    BuiltinData{"modf", BuiltinType::kModf},
+                    BuiltinData{"normalize", BuiltinType::kNormalize},
+                    BuiltinData{"pow", BuiltinType::kPow},
+                    BuiltinData{"reflect", BuiltinType::kReflect},
+                    BuiltinData{"reverseBits", BuiltinType::kReverseBits},
+                    BuiltinData{"round", BuiltinType::kRound},
+                    BuiltinData{"select", BuiltinType::kSelect},
+                    BuiltinData{"sign", BuiltinType::kSign},
+                    BuiltinData{"sin", BuiltinType::kSin},
+                    BuiltinData{"sinh", BuiltinType::kSinh},
+                    BuiltinData{"smoothstep", BuiltinType::kSmoothstep},
+                    BuiltinData{"smoothStep", BuiltinType::kSmoothStep},
+                    BuiltinData{"sqrt", BuiltinType::kSqrt},
+                    BuiltinData{"step", BuiltinType::kStep},
+                    BuiltinData{"storageBarrier", BuiltinType::kStorageBarrier},
+                    BuiltinData{"tan", BuiltinType::kTan},
+                    BuiltinData{"tanh", BuiltinType::kTanh},
+                    BuiltinData{"textureDimensions", BuiltinType::kTextureDimensions},
+                    BuiltinData{"textureLoad", BuiltinType::kTextureLoad},
+                    BuiltinData{"textureNumLayers", BuiltinType::kTextureNumLayers},
+                    BuiltinData{"textureNumLevels", BuiltinType::kTextureNumLevels},
+                    BuiltinData{"textureNumSamples", BuiltinType::kTextureNumSamples},
+                    BuiltinData{"textureSample", BuiltinType::kTextureSample},
+                    BuiltinData{"textureSampleBias", BuiltinType::kTextureSampleBias},
+                    BuiltinData{"textureSampleCompare", BuiltinType::kTextureSampleCompare},
+                    BuiltinData{"textureSampleCompareLevel",
+                                BuiltinType::kTextureSampleCompareLevel},
+                    BuiltinData{"textureSampleGrad", BuiltinType::kTextureSampleGrad},
+                    BuiltinData{"textureSampleLevel", BuiltinType::kTextureSampleLevel},
+                    BuiltinData{"trunc", BuiltinType::kTrunc},
+                    BuiltinData{"unpack2x16float", BuiltinType::kUnpack2x16float},
+                    BuiltinData{"unpack2x16snorm", BuiltinType::kUnpack2x16snorm},
+                    BuiltinData{"unpack2x16unorm", BuiltinType::kUnpack2x16unorm},
+                    BuiltinData{"unpack4x8snorm", BuiltinType::kUnpack4x8snorm},
+                    BuiltinData{"unpack4x8unorm", BuiltinType::kUnpack4x8unorm},
+                    BuiltinData{"workgroupBarrier", BuiltinType::kWorkgroupBarrier}));
 
 TEST_F(BuiltinTypeTest, ParseNoMatch) {
-  EXPECT_EQ(ParseBuiltinType("not_builtin"), BuiltinType::kNone);
+    EXPECT_EQ(ParseBuiltinType("not_builtin"), BuiltinType::kNone);
 }
 
 }  // namespace
diff --git a/src/tint/sem/builtin_type.cc b/src/tint/sem/builtin_type.cc
index eb22a2f..820b3e6 100644
--- a/src/tint/sem/builtin_type.cc
+++ b/src/tint/sem/builtin_type.cc
@@ -29,545 +29,545 @@
 namespace tint::sem {
 
 BuiltinType ParseBuiltinType(const std::string& name) {
-  if (name == "abs") {
-    return BuiltinType::kAbs;
-  }
-  if (name == "acos") {
-    return BuiltinType::kAcos;
-  }
-  if (name == "all") {
-    return BuiltinType::kAll;
-  }
-  if (name == "any") {
-    return BuiltinType::kAny;
-  }
-  if (name == "arrayLength") {
-    return BuiltinType::kArrayLength;
-  }
-  if (name == "asin") {
-    return BuiltinType::kAsin;
-  }
-  if (name == "atan") {
-    return BuiltinType::kAtan;
-  }
-  if (name == "atan2") {
-    return BuiltinType::kAtan2;
-  }
-  if (name == "ceil") {
-    return BuiltinType::kCeil;
-  }
-  if (name == "clamp") {
-    return BuiltinType::kClamp;
-  }
-  if (name == "cos") {
-    return BuiltinType::kCos;
-  }
-  if (name == "cosh") {
-    return BuiltinType::kCosh;
-  }
-  if (name == "countLeadingZeros") {
-    return BuiltinType::kCountLeadingZeros;
-  }
-  if (name == "countOneBits") {
-    return BuiltinType::kCountOneBits;
-  }
-  if (name == "countTrailingZeros") {
-    return BuiltinType::kCountTrailingZeros;
-  }
-  if (name == "cross") {
-    return BuiltinType::kCross;
-  }
-  if (name == "degrees") {
-    return BuiltinType::kDegrees;
-  }
-  if (name == "determinant") {
-    return BuiltinType::kDeterminant;
-  }
-  if (name == "distance") {
-    return BuiltinType::kDistance;
-  }
-  if (name == "dot") {
-    return BuiltinType::kDot;
-  }
-  if (name == "dpdx") {
-    return BuiltinType::kDpdx;
-  }
-  if (name == "dpdxCoarse") {
-    return BuiltinType::kDpdxCoarse;
-  }
-  if (name == "dpdxFine") {
-    return BuiltinType::kDpdxFine;
-  }
-  if (name == "dpdy") {
-    return BuiltinType::kDpdy;
-  }
-  if (name == "dpdyCoarse") {
-    return BuiltinType::kDpdyCoarse;
-  }
-  if (name == "dpdyFine") {
-    return BuiltinType::kDpdyFine;
-  }
-  if (name == "exp") {
-    return BuiltinType::kExp;
-  }
-  if (name == "exp2") {
-    return BuiltinType::kExp2;
-  }
-  if (name == "extractBits") {
-    return BuiltinType::kExtractBits;
-  }
-  if (name == "faceForward") {
-    return BuiltinType::kFaceForward;
-  }
-  if (name == "firstLeadingBit") {
-    return BuiltinType::kFirstLeadingBit;
-  }
-  if (name == "firstTrailingBit") {
-    return BuiltinType::kFirstTrailingBit;
-  }
-  if (name == "floor") {
-    return BuiltinType::kFloor;
-  }
-  if (name == "fma") {
-    return BuiltinType::kFma;
-  }
-  if (name == "fract") {
-    return BuiltinType::kFract;
-  }
-  if (name == "frexp") {
-    return BuiltinType::kFrexp;
-  }
-  if (name == "fwidth") {
-    return BuiltinType::kFwidth;
-  }
-  if (name == "fwidthCoarse") {
-    return BuiltinType::kFwidthCoarse;
-  }
-  if (name == "fwidthFine") {
-    return BuiltinType::kFwidthFine;
-  }
-  if (name == "insertBits") {
-    return BuiltinType::kInsertBits;
-  }
-  if (name == "inverseSqrt") {
-    return BuiltinType::kInverseSqrt;
-  }
-  if (name == "ldexp") {
-    return BuiltinType::kLdexp;
-  }
-  if (name == "length") {
-    return BuiltinType::kLength;
-  }
-  if (name == "log") {
-    return BuiltinType::kLog;
-  }
-  if (name == "log2") {
-    return BuiltinType::kLog2;
-  }
-  if (name == "max") {
-    return BuiltinType::kMax;
-  }
-  if (name == "min") {
-    return BuiltinType::kMin;
-  }
-  if (name == "mix") {
-    return BuiltinType::kMix;
-  }
-  if (name == "modf") {
-    return BuiltinType::kModf;
-  }
-  if (name == "normalize") {
-    return BuiltinType::kNormalize;
-  }
-  if (name == "pack2x16float") {
-    return BuiltinType::kPack2x16float;
-  }
-  if (name == "pack2x16snorm") {
-    return BuiltinType::kPack2x16snorm;
-  }
-  if (name == "pack2x16unorm") {
-    return BuiltinType::kPack2x16unorm;
-  }
-  if (name == "pack4x8snorm") {
-    return BuiltinType::kPack4x8snorm;
-  }
-  if (name == "pack4x8unorm") {
-    return BuiltinType::kPack4x8unorm;
-  }
-  if (name == "pow") {
-    return BuiltinType::kPow;
-  }
-  if (name == "radians") {
-    return BuiltinType::kRadians;
-  }
-  if (name == "reflect") {
-    return BuiltinType::kReflect;
-  }
-  if (name == "refract") {
-    return BuiltinType::kRefract;
-  }
-  if (name == "reverseBits") {
-    return BuiltinType::kReverseBits;
-  }
-  if (name == "round") {
-    return BuiltinType::kRound;
-  }
-  if (name == "select") {
-    return BuiltinType::kSelect;
-  }
-  if (name == "sign") {
-    return BuiltinType::kSign;
-  }
-  if (name == "sin") {
-    return BuiltinType::kSin;
-  }
-  if (name == "sinh") {
-    return BuiltinType::kSinh;
-  }
-  if (name == "smoothstep") {
-    return BuiltinType::kSmoothstep;
-  }
-  if (name == "smoothStep") {
-    return BuiltinType::kSmoothStep;
-  }
-  if (name == "sqrt") {
-    return BuiltinType::kSqrt;
-  }
-  if (name == "step") {
-    return BuiltinType::kStep;
-  }
-  if (name == "storageBarrier") {
-    return BuiltinType::kStorageBarrier;
-  }
-  if (name == "tan") {
-    return BuiltinType::kTan;
-  }
-  if (name == "tanh") {
-    return BuiltinType::kTanh;
-  }
-  if (name == "transpose") {
-    return BuiltinType::kTranspose;
-  }
-  if (name == "trunc") {
-    return BuiltinType::kTrunc;
-  }
-  if (name == "unpack2x16float") {
-    return BuiltinType::kUnpack2x16float;
-  }
-  if (name == "unpack2x16snorm") {
-    return BuiltinType::kUnpack2x16snorm;
-  }
-  if (name == "unpack2x16unorm") {
-    return BuiltinType::kUnpack2x16unorm;
-  }
-  if (name == "unpack4x8snorm") {
-    return BuiltinType::kUnpack4x8snorm;
-  }
-  if (name == "unpack4x8unorm") {
-    return BuiltinType::kUnpack4x8unorm;
-  }
-  if (name == "workgroupBarrier") {
-    return BuiltinType::kWorkgroupBarrier;
-  }
-  if (name == "textureDimensions") {
-    return BuiltinType::kTextureDimensions;
-  }
-  if (name == "textureGather") {
-    return BuiltinType::kTextureGather;
-  }
-  if (name == "textureGatherCompare") {
-    return BuiltinType::kTextureGatherCompare;
-  }
-  if (name == "textureNumLayers") {
-    return BuiltinType::kTextureNumLayers;
-  }
-  if (name == "textureNumLevels") {
-    return BuiltinType::kTextureNumLevels;
-  }
-  if (name == "textureNumSamples") {
-    return BuiltinType::kTextureNumSamples;
-  }
-  if (name == "textureSample") {
-    return BuiltinType::kTextureSample;
-  }
-  if (name == "textureSampleBias") {
-    return BuiltinType::kTextureSampleBias;
-  }
-  if (name == "textureSampleCompare") {
-    return BuiltinType::kTextureSampleCompare;
-  }
-  if (name == "textureSampleCompareLevel") {
-    return BuiltinType::kTextureSampleCompareLevel;
-  }
-  if (name == "textureSampleGrad") {
-    return BuiltinType::kTextureSampleGrad;
-  }
-  if (name == "textureSampleLevel") {
-    return BuiltinType::kTextureSampleLevel;
-  }
-  if (name == "textureStore") {
-    return BuiltinType::kTextureStore;
-  }
-  if (name == "textureLoad") {
-    return BuiltinType::kTextureLoad;
-  }
-  if (name == "atomicLoad") {
-    return BuiltinType::kAtomicLoad;
-  }
-  if (name == "atomicStore") {
-    return BuiltinType::kAtomicStore;
-  }
-  if (name == "atomicAdd") {
-    return BuiltinType::kAtomicAdd;
-  }
-  if (name == "atomicSub") {
-    return BuiltinType::kAtomicSub;
-  }
-  if (name == "atomicMax") {
-    return BuiltinType::kAtomicMax;
-  }
-  if (name == "atomicMin") {
-    return BuiltinType::kAtomicMin;
-  }
-  if (name == "atomicAnd") {
-    return BuiltinType::kAtomicAnd;
-  }
-  if (name == "atomicOr") {
-    return BuiltinType::kAtomicOr;
-  }
-  if (name == "atomicXor") {
-    return BuiltinType::kAtomicXor;
-  }
-  if (name == "atomicExchange") {
-    return BuiltinType::kAtomicExchange;
-  }
-  if (name == "atomicCompareExchangeWeak") {
-    return BuiltinType::kAtomicCompareExchangeWeak;
-  }
-  return BuiltinType::kNone;
+    if (name == "abs") {
+        return BuiltinType::kAbs;
+    }
+    if (name == "acos") {
+        return BuiltinType::kAcos;
+    }
+    if (name == "all") {
+        return BuiltinType::kAll;
+    }
+    if (name == "any") {
+        return BuiltinType::kAny;
+    }
+    if (name == "arrayLength") {
+        return BuiltinType::kArrayLength;
+    }
+    if (name == "asin") {
+        return BuiltinType::kAsin;
+    }
+    if (name == "atan") {
+        return BuiltinType::kAtan;
+    }
+    if (name == "atan2") {
+        return BuiltinType::kAtan2;
+    }
+    if (name == "ceil") {
+        return BuiltinType::kCeil;
+    }
+    if (name == "clamp") {
+        return BuiltinType::kClamp;
+    }
+    if (name == "cos") {
+        return BuiltinType::kCos;
+    }
+    if (name == "cosh") {
+        return BuiltinType::kCosh;
+    }
+    if (name == "countLeadingZeros") {
+        return BuiltinType::kCountLeadingZeros;
+    }
+    if (name == "countOneBits") {
+        return BuiltinType::kCountOneBits;
+    }
+    if (name == "countTrailingZeros") {
+        return BuiltinType::kCountTrailingZeros;
+    }
+    if (name == "cross") {
+        return BuiltinType::kCross;
+    }
+    if (name == "degrees") {
+        return BuiltinType::kDegrees;
+    }
+    if (name == "determinant") {
+        return BuiltinType::kDeterminant;
+    }
+    if (name == "distance") {
+        return BuiltinType::kDistance;
+    }
+    if (name == "dot") {
+        return BuiltinType::kDot;
+    }
+    if (name == "dpdx") {
+        return BuiltinType::kDpdx;
+    }
+    if (name == "dpdxCoarse") {
+        return BuiltinType::kDpdxCoarse;
+    }
+    if (name == "dpdxFine") {
+        return BuiltinType::kDpdxFine;
+    }
+    if (name == "dpdy") {
+        return BuiltinType::kDpdy;
+    }
+    if (name == "dpdyCoarse") {
+        return BuiltinType::kDpdyCoarse;
+    }
+    if (name == "dpdyFine") {
+        return BuiltinType::kDpdyFine;
+    }
+    if (name == "exp") {
+        return BuiltinType::kExp;
+    }
+    if (name == "exp2") {
+        return BuiltinType::kExp2;
+    }
+    if (name == "extractBits") {
+        return BuiltinType::kExtractBits;
+    }
+    if (name == "faceForward") {
+        return BuiltinType::kFaceForward;
+    }
+    if (name == "firstLeadingBit") {
+        return BuiltinType::kFirstLeadingBit;
+    }
+    if (name == "firstTrailingBit") {
+        return BuiltinType::kFirstTrailingBit;
+    }
+    if (name == "floor") {
+        return BuiltinType::kFloor;
+    }
+    if (name == "fma") {
+        return BuiltinType::kFma;
+    }
+    if (name == "fract") {
+        return BuiltinType::kFract;
+    }
+    if (name == "frexp") {
+        return BuiltinType::kFrexp;
+    }
+    if (name == "fwidth") {
+        return BuiltinType::kFwidth;
+    }
+    if (name == "fwidthCoarse") {
+        return BuiltinType::kFwidthCoarse;
+    }
+    if (name == "fwidthFine") {
+        return BuiltinType::kFwidthFine;
+    }
+    if (name == "insertBits") {
+        return BuiltinType::kInsertBits;
+    }
+    if (name == "inverseSqrt") {
+        return BuiltinType::kInverseSqrt;
+    }
+    if (name == "ldexp") {
+        return BuiltinType::kLdexp;
+    }
+    if (name == "length") {
+        return BuiltinType::kLength;
+    }
+    if (name == "log") {
+        return BuiltinType::kLog;
+    }
+    if (name == "log2") {
+        return BuiltinType::kLog2;
+    }
+    if (name == "max") {
+        return BuiltinType::kMax;
+    }
+    if (name == "min") {
+        return BuiltinType::kMin;
+    }
+    if (name == "mix") {
+        return BuiltinType::kMix;
+    }
+    if (name == "modf") {
+        return BuiltinType::kModf;
+    }
+    if (name == "normalize") {
+        return BuiltinType::kNormalize;
+    }
+    if (name == "pack2x16float") {
+        return BuiltinType::kPack2x16float;
+    }
+    if (name == "pack2x16snorm") {
+        return BuiltinType::kPack2x16snorm;
+    }
+    if (name == "pack2x16unorm") {
+        return BuiltinType::kPack2x16unorm;
+    }
+    if (name == "pack4x8snorm") {
+        return BuiltinType::kPack4x8snorm;
+    }
+    if (name == "pack4x8unorm") {
+        return BuiltinType::kPack4x8unorm;
+    }
+    if (name == "pow") {
+        return BuiltinType::kPow;
+    }
+    if (name == "radians") {
+        return BuiltinType::kRadians;
+    }
+    if (name == "reflect") {
+        return BuiltinType::kReflect;
+    }
+    if (name == "refract") {
+        return BuiltinType::kRefract;
+    }
+    if (name == "reverseBits") {
+        return BuiltinType::kReverseBits;
+    }
+    if (name == "round") {
+        return BuiltinType::kRound;
+    }
+    if (name == "select") {
+        return BuiltinType::kSelect;
+    }
+    if (name == "sign") {
+        return BuiltinType::kSign;
+    }
+    if (name == "sin") {
+        return BuiltinType::kSin;
+    }
+    if (name == "sinh") {
+        return BuiltinType::kSinh;
+    }
+    if (name == "smoothstep") {
+        return BuiltinType::kSmoothstep;
+    }
+    if (name == "smoothStep") {
+        return BuiltinType::kSmoothStep;
+    }
+    if (name == "sqrt") {
+        return BuiltinType::kSqrt;
+    }
+    if (name == "step") {
+        return BuiltinType::kStep;
+    }
+    if (name == "storageBarrier") {
+        return BuiltinType::kStorageBarrier;
+    }
+    if (name == "tan") {
+        return BuiltinType::kTan;
+    }
+    if (name == "tanh") {
+        return BuiltinType::kTanh;
+    }
+    if (name == "transpose") {
+        return BuiltinType::kTranspose;
+    }
+    if (name == "trunc") {
+        return BuiltinType::kTrunc;
+    }
+    if (name == "unpack2x16float") {
+        return BuiltinType::kUnpack2x16float;
+    }
+    if (name == "unpack2x16snorm") {
+        return BuiltinType::kUnpack2x16snorm;
+    }
+    if (name == "unpack2x16unorm") {
+        return BuiltinType::kUnpack2x16unorm;
+    }
+    if (name == "unpack4x8snorm") {
+        return BuiltinType::kUnpack4x8snorm;
+    }
+    if (name == "unpack4x8unorm") {
+        return BuiltinType::kUnpack4x8unorm;
+    }
+    if (name == "workgroupBarrier") {
+        return BuiltinType::kWorkgroupBarrier;
+    }
+    if (name == "textureDimensions") {
+        return BuiltinType::kTextureDimensions;
+    }
+    if (name == "textureGather") {
+        return BuiltinType::kTextureGather;
+    }
+    if (name == "textureGatherCompare") {
+        return BuiltinType::kTextureGatherCompare;
+    }
+    if (name == "textureNumLayers") {
+        return BuiltinType::kTextureNumLayers;
+    }
+    if (name == "textureNumLevels") {
+        return BuiltinType::kTextureNumLevels;
+    }
+    if (name == "textureNumSamples") {
+        return BuiltinType::kTextureNumSamples;
+    }
+    if (name == "textureSample") {
+        return BuiltinType::kTextureSample;
+    }
+    if (name == "textureSampleBias") {
+        return BuiltinType::kTextureSampleBias;
+    }
+    if (name == "textureSampleCompare") {
+        return BuiltinType::kTextureSampleCompare;
+    }
+    if (name == "textureSampleCompareLevel") {
+        return BuiltinType::kTextureSampleCompareLevel;
+    }
+    if (name == "textureSampleGrad") {
+        return BuiltinType::kTextureSampleGrad;
+    }
+    if (name == "textureSampleLevel") {
+        return BuiltinType::kTextureSampleLevel;
+    }
+    if (name == "textureStore") {
+        return BuiltinType::kTextureStore;
+    }
+    if (name == "textureLoad") {
+        return BuiltinType::kTextureLoad;
+    }
+    if (name == "atomicLoad") {
+        return BuiltinType::kAtomicLoad;
+    }
+    if (name == "atomicStore") {
+        return BuiltinType::kAtomicStore;
+    }
+    if (name == "atomicAdd") {
+        return BuiltinType::kAtomicAdd;
+    }
+    if (name == "atomicSub") {
+        return BuiltinType::kAtomicSub;
+    }
+    if (name == "atomicMax") {
+        return BuiltinType::kAtomicMax;
+    }
+    if (name == "atomicMin") {
+        return BuiltinType::kAtomicMin;
+    }
+    if (name == "atomicAnd") {
+        return BuiltinType::kAtomicAnd;
+    }
+    if (name == "atomicOr") {
+        return BuiltinType::kAtomicOr;
+    }
+    if (name == "atomicXor") {
+        return BuiltinType::kAtomicXor;
+    }
+    if (name == "atomicExchange") {
+        return BuiltinType::kAtomicExchange;
+    }
+    if (name == "atomicCompareExchangeWeak") {
+        return BuiltinType::kAtomicCompareExchangeWeak;
+    }
+    return BuiltinType::kNone;
 }
 
 const char* str(BuiltinType i) {
-  switch (i) {
-    case BuiltinType::kNone:
-      return "<none>";
-    case BuiltinType::kAbs:
-      return "abs";
-    case BuiltinType::kAcos:
-      return "acos";
-    case BuiltinType::kAll:
-      return "all";
-    case BuiltinType::kAny:
-      return "any";
-    case BuiltinType::kArrayLength:
-      return "arrayLength";
-    case BuiltinType::kAsin:
-      return "asin";
-    case BuiltinType::kAtan:
-      return "atan";
-    case BuiltinType::kAtan2:
-      return "atan2";
-    case BuiltinType::kCeil:
-      return "ceil";
-    case BuiltinType::kClamp:
-      return "clamp";
-    case BuiltinType::kCos:
-      return "cos";
-    case BuiltinType::kCosh:
-      return "cosh";
-    case BuiltinType::kCountLeadingZeros:
-      return "countLeadingZeros";
-    case BuiltinType::kCountOneBits:
-      return "countOneBits";
-    case BuiltinType::kCountTrailingZeros:
-      return "countTrailingZeros";
-    case BuiltinType::kCross:
-      return "cross";
-    case BuiltinType::kDegrees:
-      return "degrees";
-    case BuiltinType::kDeterminant:
-      return "determinant";
-    case BuiltinType::kDistance:
-      return "distance";
-    case BuiltinType::kDot:
-      return "dot";
-    case BuiltinType::kDpdx:
-      return "dpdx";
-    case BuiltinType::kDpdxCoarse:
-      return "dpdxCoarse";
-    case BuiltinType::kDpdxFine:
-      return "dpdxFine";
-    case BuiltinType::kDpdy:
-      return "dpdy";
-    case BuiltinType::kDpdyCoarse:
-      return "dpdyCoarse";
-    case BuiltinType::kDpdyFine:
-      return "dpdyFine";
-    case BuiltinType::kExp:
-      return "exp";
-    case BuiltinType::kExp2:
-      return "exp2";
-    case BuiltinType::kExtractBits:
-      return "extractBits";
-    case BuiltinType::kFaceForward:
-      return "faceForward";
-    case BuiltinType::kFirstLeadingBit:
-      return "firstLeadingBit";
-    case BuiltinType::kFirstTrailingBit:
-      return "firstTrailingBit";
-    case BuiltinType::kFloor:
-      return "floor";
-    case BuiltinType::kFma:
-      return "fma";
-    case BuiltinType::kFract:
-      return "fract";
-    case BuiltinType::kFrexp:
-      return "frexp";
-    case BuiltinType::kFwidth:
-      return "fwidth";
-    case BuiltinType::kFwidthCoarse:
-      return "fwidthCoarse";
-    case BuiltinType::kFwidthFine:
-      return "fwidthFine";
-    case BuiltinType::kInsertBits:
-      return "insertBits";
-    case BuiltinType::kInverseSqrt:
-      return "inverseSqrt";
-    case BuiltinType::kLdexp:
-      return "ldexp";
-    case BuiltinType::kLength:
-      return "length";
-    case BuiltinType::kLog:
-      return "log";
-    case BuiltinType::kLog2:
-      return "log2";
-    case BuiltinType::kMax:
-      return "max";
-    case BuiltinType::kMin:
-      return "min";
-    case BuiltinType::kMix:
-      return "mix";
-    case BuiltinType::kModf:
-      return "modf";
-    case BuiltinType::kNormalize:
-      return "normalize";
-    case BuiltinType::kPack2x16float:
-      return "pack2x16float";
-    case BuiltinType::kPack2x16snorm:
-      return "pack2x16snorm";
-    case BuiltinType::kPack2x16unorm:
-      return "pack2x16unorm";
-    case BuiltinType::kPack4x8snorm:
-      return "pack4x8snorm";
-    case BuiltinType::kPack4x8unorm:
-      return "pack4x8unorm";
-    case BuiltinType::kPow:
-      return "pow";
-    case BuiltinType::kRadians:
-      return "radians";
-    case BuiltinType::kReflect:
-      return "reflect";
-    case BuiltinType::kRefract:
-      return "refract";
-    case BuiltinType::kReverseBits:
-      return "reverseBits";
-    case BuiltinType::kRound:
-      return "round";
-    case BuiltinType::kSelect:
-      return "select";
-    case BuiltinType::kSign:
-      return "sign";
-    case BuiltinType::kSin:
-      return "sin";
-    case BuiltinType::kSinh:
-      return "sinh";
-    case BuiltinType::kSmoothstep:
-      return "smoothstep";
-    case BuiltinType::kSmoothStep:
-      return "smoothStep";
-    case BuiltinType::kSqrt:
-      return "sqrt";
-    case BuiltinType::kStep:
-      return "step";
-    case BuiltinType::kStorageBarrier:
-      return "storageBarrier";
-    case BuiltinType::kTan:
-      return "tan";
-    case BuiltinType::kTanh:
-      return "tanh";
-    case BuiltinType::kTranspose:
-      return "transpose";
-    case BuiltinType::kTrunc:
-      return "trunc";
-    case BuiltinType::kUnpack2x16float:
-      return "unpack2x16float";
-    case BuiltinType::kUnpack2x16snorm:
-      return "unpack2x16snorm";
-    case BuiltinType::kUnpack2x16unorm:
-      return "unpack2x16unorm";
-    case BuiltinType::kUnpack4x8snorm:
-      return "unpack4x8snorm";
-    case BuiltinType::kUnpack4x8unorm:
-      return "unpack4x8unorm";
-    case BuiltinType::kWorkgroupBarrier:
-      return "workgroupBarrier";
-    case BuiltinType::kTextureDimensions:
-      return "textureDimensions";
-    case BuiltinType::kTextureGather:
-      return "textureGather";
-    case BuiltinType::kTextureGatherCompare:
-      return "textureGatherCompare";
-    case BuiltinType::kTextureNumLayers:
-      return "textureNumLayers";
-    case BuiltinType::kTextureNumLevels:
-      return "textureNumLevels";
-    case BuiltinType::kTextureNumSamples:
-      return "textureNumSamples";
-    case BuiltinType::kTextureSample:
-      return "textureSample";
-    case BuiltinType::kTextureSampleBias:
-      return "textureSampleBias";
-    case BuiltinType::kTextureSampleCompare:
-      return "textureSampleCompare";
-    case BuiltinType::kTextureSampleCompareLevel:
-      return "textureSampleCompareLevel";
-    case BuiltinType::kTextureSampleGrad:
-      return "textureSampleGrad";
-    case BuiltinType::kTextureSampleLevel:
-      return "textureSampleLevel";
-    case BuiltinType::kTextureStore:
-      return "textureStore";
-    case BuiltinType::kTextureLoad:
-      return "textureLoad";
-    case BuiltinType::kAtomicLoad:
-      return "atomicLoad";
-    case BuiltinType::kAtomicStore:
-      return "atomicStore";
-    case BuiltinType::kAtomicAdd:
-      return "atomicAdd";
-    case BuiltinType::kAtomicSub:
-      return "atomicSub";
-    case BuiltinType::kAtomicMax:
-      return "atomicMax";
-    case BuiltinType::kAtomicMin:
-      return "atomicMin";
-    case BuiltinType::kAtomicAnd:
-      return "atomicAnd";
-    case BuiltinType::kAtomicOr:
-      return "atomicOr";
-    case BuiltinType::kAtomicXor:
-      return "atomicXor";
-    case BuiltinType::kAtomicExchange:
-      return "atomicExchange";
-    case BuiltinType::kAtomicCompareExchangeWeak:
-      return "atomicCompareExchangeWeak";
-  }
-  return "<unknown>";
+    switch (i) {
+        case BuiltinType::kNone:
+            return "<none>";
+        case BuiltinType::kAbs:
+            return "abs";
+        case BuiltinType::kAcos:
+            return "acos";
+        case BuiltinType::kAll:
+            return "all";
+        case BuiltinType::kAny:
+            return "any";
+        case BuiltinType::kArrayLength:
+            return "arrayLength";
+        case BuiltinType::kAsin:
+            return "asin";
+        case BuiltinType::kAtan:
+            return "atan";
+        case BuiltinType::kAtan2:
+            return "atan2";
+        case BuiltinType::kCeil:
+            return "ceil";
+        case BuiltinType::kClamp:
+            return "clamp";
+        case BuiltinType::kCos:
+            return "cos";
+        case BuiltinType::kCosh:
+            return "cosh";
+        case BuiltinType::kCountLeadingZeros:
+            return "countLeadingZeros";
+        case BuiltinType::kCountOneBits:
+            return "countOneBits";
+        case BuiltinType::kCountTrailingZeros:
+            return "countTrailingZeros";
+        case BuiltinType::kCross:
+            return "cross";
+        case BuiltinType::kDegrees:
+            return "degrees";
+        case BuiltinType::kDeterminant:
+            return "determinant";
+        case BuiltinType::kDistance:
+            return "distance";
+        case BuiltinType::kDot:
+            return "dot";
+        case BuiltinType::kDpdx:
+            return "dpdx";
+        case BuiltinType::kDpdxCoarse:
+            return "dpdxCoarse";
+        case BuiltinType::kDpdxFine:
+            return "dpdxFine";
+        case BuiltinType::kDpdy:
+            return "dpdy";
+        case BuiltinType::kDpdyCoarse:
+            return "dpdyCoarse";
+        case BuiltinType::kDpdyFine:
+            return "dpdyFine";
+        case BuiltinType::kExp:
+            return "exp";
+        case BuiltinType::kExp2:
+            return "exp2";
+        case BuiltinType::kExtractBits:
+            return "extractBits";
+        case BuiltinType::kFaceForward:
+            return "faceForward";
+        case BuiltinType::kFirstLeadingBit:
+            return "firstLeadingBit";
+        case BuiltinType::kFirstTrailingBit:
+            return "firstTrailingBit";
+        case BuiltinType::kFloor:
+            return "floor";
+        case BuiltinType::kFma:
+            return "fma";
+        case BuiltinType::kFract:
+            return "fract";
+        case BuiltinType::kFrexp:
+            return "frexp";
+        case BuiltinType::kFwidth:
+            return "fwidth";
+        case BuiltinType::kFwidthCoarse:
+            return "fwidthCoarse";
+        case BuiltinType::kFwidthFine:
+            return "fwidthFine";
+        case BuiltinType::kInsertBits:
+            return "insertBits";
+        case BuiltinType::kInverseSqrt:
+            return "inverseSqrt";
+        case BuiltinType::kLdexp:
+            return "ldexp";
+        case BuiltinType::kLength:
+            return "length";
+        case BuiltinType::kLog:
+            return "log";
+        case BuiltinType::kLog2:
+            return "log2";
+        case BuiltinType::kMax:
+            return "max";
+        case BuiltinType::kMin:
+            return "min";
+        case BuiltinType::kMix:
+            return "mix";
+        case BuiltinType::kModf:
+            return "modf";
+        case BuiltinType::kNormalize:
+            return "normalize";
+        case BuiltinType::kPack2x16float:
+            return "pack2x16float";
+        case BuiltinType::kPack2x16snorm:
+            return "pack2x16snorm";
+        case BuiltinType::kPack2x16unorm:
+            return "pack2x16unorm";
+        case BuiltinType::kPack4x8snorm:
+            return "pack4x8snorm";
+        case BuiltinType::kPack4x8unorm:
+            return "pack4x8unorm";
+        case BuiltinType::kPow:
+            return "pow";
+        case BuiltinType::kRadians:
+            return "radians";
+        case BuiltinType::kReflect:
+            return "reflect";
+        case BuiltinType::kRefract:
+            return "refract";
+        case BuiltinType::kReverseBits:
+            return "reverseBits";
+        case BuiltinType::kRound:
+            return "round";
+        case BuiltinType::kSelect:
+            return "select";
+        case BuiltinType::kSign:
+            return "sign";
+        case BuiltinType::kSin:
+            return "sin";
+        case BuiltinType::kSinh:
+            return "sinh";
+        case BuiltinType::kSmoothstep:
+            return "smoothstep";
+        case BuiltinType::kSmoothStep:
+            return "smoothStep";
+        case BuiltinType::kSqrt:
+            return "sqrt";
+        case BuiltinType::kStep:
+            return "step";
+        case BuiltinType::kStorageBarrier:
+            return "storageBarrier";
+        case BuiltinType::kTan:
+            return "tan";
+        case BuiltinType::kTanh:
+            return "tanh";
+        case BuiltinType::kTranspose:
+            return "transpose";
+        case BuiltinType::kTrunc:
+            return "trunc";
+        case BuiltinType::kUnpack2x16float:
+            return "unpack2x16float";
+        case BuiltinType::kUnpack2x16snorm:
+            return "unpack2x16snorm";
+        case BuiltinType::kUnpack2x16unorm:
+            return "unpack2x16unorm";
+        case BuiltinType::kUnpack4x8snorm:
+            return "unpack4x8snorm";
+        case BuiltinType::kUnpack4x8unorm:
+            return "unpack4x8unorm";
+        case BuiltinType::kWorkgroupBarrier:
+            return "workgroupBarrier";
+        case BuiltinType::kTextureDimensions:
+            return "textureDimensions";
+        case BuiltinType::kTextureGather:
+            return "textureGather";
+        case BuiltinType::kTextureGatherCompare:
+            return "textureGatherCompare";
+        case BuiltinType::kTextureNumLayers:
+            return "textureNumLayers";
+        case BuiltinType::kTextureNumLevels:
+            return "textureNumLevels";
+        case BuiltinType::kTextureNumSamples:
+            return "textureNumSamples";
+        case BuiltinType::kTextureSample:
+            return "textureSample";
+        case BuiltinType::kTextureSampleBias:
+            return "textureSampleBias";
+        case BuiltinType::kTextureSampleCompare:
+            return "textureSampleCompare";
+        case BuiltinType::kTextureSampleCompareLevel:
+            return "textureSampleCompareLevel";
+        case BuiltinType::kTextureSampleGrad:
+            return "textureSampleGrad";
+        case BuiltinType::kTextureSampleLevel:
+            return "textureSampleLevel";
+        case BuiltinType::kTextureStore:
+            return "textureStore";
+        case BuiltinType::kTextureLoad:
+            return "textureLoad";
+        case BuiltinType::kAtomicLoad:
+            return "atomicLoad";
+        case BuiltinType::kAtomicStore:
+            return "atomicStore";
+        case BuiltinType::kAtomicAdd:
+            return "atomicAdd";
+        case BuiltinType::kAtomicSub:
+            return "atomicSub";
+        case BuiltinType::kAtomicMax:
+            return "atomicMax";
+        case BuiltinType::kAtomicMin:
+            return "atomicMin";
+        case BuiltinType::kAtomicAnd:
+            return "atomicAnd";
+        case BuiltinType::kAtomicOr:
+            return "atomicOr";
+        case BuiltinType::kAtomicXor:
+            return "atomicXor";
+        case BuiltinType::kAtomicExchange:
+            return "atomicExchange";
+        case BuiltinType::kAtomicCompareExchangeWeak:
+            return "atomicCompareExchangeWeak";
+    }
+    return "<unknown>";
 }
 
 std::ostream& operator<<(std::ostream& out, BuiltinType i) {
-  out << str(i);
-  return out;
+    out << str(i);
+    return out;
 }
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/builtin_type.cc.tmpl b/src/tint/sem/builtin_type.cc.tmpl
index ab072d9..2330c87 100644
--- a/src/tint/sem/builtin_type.cc.tmpl
+++ b/src/tint/sem/builtin_type.cc.tmpl
@@ -16,28 +16,28 @@
 
 BuiltinType ParseBuiltinType(const std::string& name) {
 {{- range .Sem.Functions  }}
-  if (name == "{{.Name}}") {
-    return BuiltinType::k{{Title .Name}};
-  }
+    if (name == "{{.Name}}") {
+        return BuiltinType::k{{Title .Name}};
+    }
 {{- end  }}
-  return BuiltinType::kNone;
+    return BuiltinType::kNone;
 }
 
 const char* str(BuiltinType i) {
-  switch (i) {
-    case BuiltinType::kNone:
-      return "<none>";
+    switch (i) {
+        case BuiltinType::kNone:
+            return "<none>";
 {{- range .Sem.Functions  }}
-    case BuiltinType::k{{Title .Name}}:
-      return "{{.Name}}";
+        case BuiltinType::k{{Title .Name}}:
+            return "{{.Name}}";
 {{- end  }}
-  }
-  return "<unknown>";
+    }
+    return "<unknown>";
 }
 
 std::ostream& operator<<(std::ostream& out, BuiltinType i) {
-  out << str(i);
-  return out;
+    out << str(i);
+    return out;
 }
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/builtin_type.h b/src/tint/sem/builtin_type.h
index e2d741f..ec07274 100644
--- a/src/tint/sem/builtin_type.h
+++ b/src/tint/sem/builtin_type.h
@@ -32,112 +32,112 @@
 
 /// Enumerator of all builtin functions
 enum class BuiltinType {
-  kNone = -1,
-  kAbs,
-  kAcos,
-  kAll,
-  kAny,
-  kArrayLength,
-  kAsin,
-  kAtan,
-  kAtan2,
-  kCeil,
-  kClamp,
-  kCos,
-  kCosh,
-  kCountLeadingZeros,
-  kCountOneBits,
-  kCountTrailingZeros,
-  kCross,
-  kDegrees,
-  kDeterminant,
-  kDistance,
-  kDot,
-  kDpdx,
-  kDpdxCoarse,
-  kDpdxFine,
-  kDpdy,
-  kDpdyCoarse,
-  kDpdyFine,
-  kExp,
-  kExp2,
-  kExtractBits,
-  kFaceForward,
-  kFirstLeadingBit,
-  kFirstTrailingBit,
-  kFloor,
-  kFma,
-  kFract,
-  kFrexp,
-  kFwidth,
-  kFwidthCoarse,
-  kFwidthFine,
-  kInsertBits,
-  kInverseSqrt,
-  kLdexp,
-  kLength,
-  kLog,
-  kLog2,
-  kMax,
-  kMin,
-  kMix,
-  kModf,
-  kNormalize,
-  kPack2x16float,
-  kPack2x16snorm,
-  kPack2x16unorm,
-  kPack4x8snorm,
-  kPack4x8unorm,
-  kPow,
-  kRadians,
-  kReflect,
-  kRefract,
-  kReverseBits,
-  kRound,
-  kSelect,
-  kSign,
-  kSin,
-  kSinh,
-  kSmoothstep,
-  kSmoothStep,
-  kSqrt,
-  kStep,
-  kStorageBarrier,
-  kTan,
-  kTanh,
-  kTranspose,
-  kTrunc,
-  kUnpack2x16float,
-  kUnpack2x16snorm,
-  kUnpack2x16unorm,
-  kUnpack4x8snorm,
-  kUnpack4x8unorm,
-  kWorkgroupBarrier,
-  kTextureDimensions,
-  kTextureGather,
-  kTextureGatherCompare,
-  kTextureNumLayers,
-  kTextureNumLevels,
-  kTextureNumSamples,
-  kTextureSample,
-  kTextureSampleBias,
-  kTextureSampleCompare,
-  kTextureSampleCompareLevel,
-  kTextureSampleGrad,
-  kTextureSampleLevel,
-  kTextureStore,
-  kTextureLoad,
-  kAtomicLoad,
-  kAtomicStore,
-  kAtomicAdd,
-  kAtomicSub,
-  kAtomicMax,
-  kAtomicMin,
-  kAtomicAnd,
-  kAtomicOr,
-  kAtomicXor,
-  kAtomicExchange,
-  kAtomicCompareExchangeWeak,
+    kNone = -1,
+    kAbs,
+    kAcos,
+    kAll,
+    kAny,
+    kArrayLength,
+    kAsin,
+    kAtan,
+    kAtan2,
+    kCeil,
+    kClamp,
+    kCos,
+    kCosh,
+    kCountLeadingZeros,
+    kCountOneBits,
+    kCountTrailingZeros,
+    kCross,
+    kDegrees,
+    kDeterminant,
+    kDistance,
+    kDot,
+    kDpdx,
+    kDpdxCoarse,
+    kDpdxFine,
+    kDpdy,
+    kDpdyCoarse,
+    kDpdyFine,
+    kExp,
+    kExp2,
+    kExtractBits,
+    kFaceForward,
+    kFirstLeadingBit,
+    kFirstTrailingBit,
+    kFloor,
+    kFma,
+    kFract,
+    kFrexp,
+    kFwidth,
+    kFwidthCoarse,
+    kFwidthFine,
+    kInsertBits,
+    kInverseSqrt,
+    kLdexp,
+    kLength,
+    kLog,
+    kLog2,
+    kMax,
+    kMin,
+    kMix,
+    kModf,
+    kNormalize,
+    kPack2x16float,
+    kPack2x16snorm,
+    kPack2x16unorm,
+    kPack4x8snorm,
+    kPack4x8unorm,
+    kPow,
+    kRadians,
+    kReflect,
+    kRefract,
+    kReverseBits,
+    kRound,
+    kSelect,
+    kSign,
+    kSin,
+    kSinh,
+    kSmoothstep,
+    kSmoothStep,
+    kSqrt,
+    kStep,
+    kStorageBarrier,
+    kTan,
+    kTanh,
+    kTranspose,
+    kTrunc,
+    kUnpack2x16float,
+    kUnpack2x16snorm,
+    kUnpack2x16unorm,
+    kUnpack4x8snorm,
+    kUnpack4x8unorm,
+    kWorkgroupBarrier,
+    kTextureDimensions,
+    kTextureGather,
+    kTextureGatherCompare,
+    kTextureNumLayers,
+    kTextureNumLevels,
+    kTextureNumSamples,
+    kTextureSample,
+    kTextureSampleBias,
+    kTextureSampleCompare,
+    kTextureSampleCompareLevel,
+    kTextureSampleGrad,
+    kTextureSampleLevel,
+    kTextureStore,
+    kTextureLoad,
+    kAtomicLoad,
+    kAtomicStore,
+    kAtomicAdd,
+    kAtomicSub,
+    kAtomicMax,
+    kAtomicMin,
+    kAtomicAnd,
+    kAtomicOr,
+    kAtomicXor,
+    kAtomicExchange,
+    kAtomicCompareExchangeWeak,
 };
 
 /// Matches the BuiltinType by name
diff --git a/src/tint/sem/builtin_type.h.tmpl b/src/tint/sem/builtin_type.h.tmpl
index 7b018df..b601c37 100644
--- a/src/tint/sem/builtin_type.h.tmpl
+++ b/src/tint/sem/builtin_type.h.tmpl
@@ -18,9 +18,9 @@
 
 /// Enumerator of all builtin functions
 enum class BuiltinType {
-  kNone = -1,
+    kNone = -1,
 {{- range .Sem.Functions }}
-  k{{Title .Name}},
+    k{{Title .Name}},
 {{- end }}
 };
 
diff --git a/src/tint/sem/call.cc b/src/tint/sem/call.cc
index 415316e..f688cce 100644
--- a/src/tint/sem/call.cc
+++ b/src/tint/sem/call.cc
@@ -27,11 +27,7 @@
            const Statement* statement,
            Constant constant,
            bool has_side_effects)
-    : Base(declaration,
-           target->ReturnType(),
-           statement,
-           std::move(constant),
-           has_side_effects),
+    : Base(declaration, target->ReturnType(), statement, std::move(constant), has_side_effects),
       target_(target),
       arguments_(std::move(arguments)) {}
 
diff --git a/src/tint/sem/call.h b/src/tint/sem/call.h
index 786bd25..c96179d 100644
--- a/src/tint/sem/call.h
+++ b/src/tint/sem/call.h
@@ -25,40 +25,38 @@
 /// Call is the base class for semantic nodes that hold semantic information for
 /// ast::CallExpression nodes.
 class Call final : public Castable<Call, Expression> {
- public:
-  /// Constructor
-  /// @param declaration the AST node
-  /// @param target the call target
-  /// @param arguments the call arguments
-  /// @param statement the statement that owns this expression
-  /// @param constant the constant value of this expression
-  /// @param has_side_effects whether this expression may have side effects
-  Call(const ast::CallExpression* declaration,
-       const CallTarget* target,
-       std::vector<const sem::Expression*> arguments,
-       const Statement* statement,
-       Constant constant,
-       bool has_side_effects);
+  public:
+    /// Constructor
+    /// @param declaration the AST node
+    /// @param target the call target
+    /// @param arguments the call arguments
+    /// @param statement the statement that owns this expression
+    /// @param constant the constant value of this expression
+    /// @param has_side_effects whether this expression may have side effects
+    Call(const ast::CallExpression* declaration,
+         const CallTarget* target,
+         std::vector<const sem::Expression*> arguments,
+         const Statement* statement,
+         Constant constant,
+         bool has_side_effects);
 
-  /// Destructor
-  ~Call() override;
+    /// Destructor
+    ~Call() override;
 
-  /// @return the target of the call
-  const CallTarget* Target() const { return target_; }
+    /// @return the target of the call
+    const CallTarget* Target() const { return target_; }
 
-  /// @return the call arguments
-  const std::vector<const sem::Expression*>& Arguments() const {
-    return arguments_;
-  }
+    /// @return the call arguments
+    const std::vector<const sem::Expression*>& Arguments() const { return arguments_; }
 
-  /// @returns the AST node
-  const ast::CallExpression* Declaration() const {
-    return static_cast<const ast::CallExpression*>(declaration_);
-  }
+    /// @returns the AST node
+    const ast::CallExpression* Declaration() const {
+        return static_cast<const ast::CallExpression*>(declaration_);
+    }
 
- private:
-  CallTarget const* const target_;
-  std::vector<const sem::Expression*> arguments_;
+  private:
+    CallTarget const* const target_;
+    std::vector<const sem::Expression*> arguments_;
 };
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/call_target.cc b/src/tint/sem/call_target.cc
index 7fc3c81..67bde0e 100644
--- a/src/tint/sem/call_target.cc
+++ b/src/tint/sem/call_target.cc
@@ -21,43 +21,40 @@
 
 namespace tint::sem {
 
-CallTarget::CallTarget(const sem::Type* return_type,
-                       const ParameterList& parameters)
+CallTarget::CallTarget(const sem::Type* return_type, const ParameterList& parameters)
     : signature_{return_type, parameters} {
-  TINT_ASSERT(Semantic, return_type);
+    TINT_ASSERT(Semantic, return_type);
 }
 
 CallTarget::CallTarget(const CallTarget&) = default;
 CallTarget::~CallTarget() = default;
 
-CallTargetSignature::CallTargetSignature(const sem::Type* ret_ty,
-                                         const ParameterList& params)
+CallTargetSignature::CallTargetSignature(const sem::Type* ret_ty, const ParameterList& params)
     : return_type(ret_ty), parameters(params) {}
 CallTargetSignature::CallTargetSignature(const CallTargetSignature&) = default;
 CallTargetSignature::~CallTargetSignature() = default;
 
 int CallTargetSignature::IndexOf(ParameterUsage usage) const {
-  for (size_t i = 0; i < parameters.size(); i++) {
-    if (parameters[i]->Usage() == usage) {
-      return static_cast<int>(i);
+    for (size_t i = 0; i < parameters.size(); i++) {
+        if (parameters[i]->Usage() == usage) {
+            return static_cast<int>(i);
+        }
     }
-  }
-  return -1;
+    return -1;
 }
 
 bool CallTargetSignature::operator==(const CallTargetSignature& other) const {
-  if (return_type != other.return_type ||
-      parameters.size() != other.parameters.size()) {
-    return false;
-  }
-  for (size_t i = 0; i < parameters.size(); i++) {
-    auto* a = parameters[i];
-    auto* b = other.parameters[i];
-    if (a->Type() != b->Type() || a->Usage() != b->Usage()) {
-      return false;
+    if (return_type != other.return_type || parameters.size() != other.parameters.size()) {
+        return false;
     }
-  }
-  return true;
+    for (size_t i = 0; i < parameters.size(); i++) {
+        auto* a = parameters[i];
+        auto* b = other.parameters[i];
+        if (a->Type() != b->Type() || a->Usage() != b->Usage()) {
+            return false;
+        }
+    }
+    return true;
 }
 
 }  // namespace tint::sem
@@ -66,11 +63,11 @@
 
 std::size_t hash<tint::sem::CallTargetSignature>::operator()(
     const tint::sem::CallTargetSignature& sig) const {
-  size_t hash = tint::utils::Hash(sig.parameters.size());
-  for (auto* p : sig.parameters) {
-    tint::utils::HashCombine(&hash, p->Type(), p->Usage());
-  }
-  return tint::utils::Hash(hash, sig.return_type);
+    size_t hash = tint::utils::Hash(sig.parameters.size());
+    for (auto* p : sig.parameters) {
+        tint::utils::HashCombine(&hash, p->Type(), p->Usage());
+    }
+    return tint::utils::Hash(hash, sig.return_type);
 }
 
 }  // namespace std
diff --git a/src/tint/sem/call_target.h b/src/tint/sem/call_target.h
index 01650eb..64716b2 100644
--- a/src/tint/sem/call_target.h
+++ b/src/tint/sem/call_target.h
@@ -18,7 +18,7 @@
 #include <vector>
 
 #include "src/tint/sem/node.h"
-#include "src/tint/sem/sampler_type.h"
+#include "src/tint/sem/sampler.h"
 #include "src/tint/sem/variable.h"
 #include "src/tint/utils/hash.h"
 
@@ -31,59 +31,59 @@
 
 /// CallTargetSignature holds the return type and parameters for a call target
 struct CallTargetSignature {
-  /// Constructor
-  /// @param ret_ty the call target return type
-  /// @param params the call target parameters
-  CallTargetSignature(const sem::Type* ret_ty, const ParameterList& params);
+    /// Constructor
+    /// @param ret_ty the call target return type
+    /// @param params the call target parameters
+    CallTargetSignature(const sem::Type* ret_ty, const ParameterList& params);
 
-  /// Copy constructor
-  CallTargetSignature(const CallTargetSignature&);
+    /// Copy constructor
+    CallTargetSignature(const CallTargetSignature&);
 
-  /// Destructor
-  ~CallTargetSignature();
+    /// Destructor
+    ~CallTargetSignature();
 
-  /// The type of the call target return value
-  const sem::Type* const return_type = nullptr;
-  /// The parameters of the call target
-  const ParameterList parameters;
+    /// The type of the call target return value
+    const sem::Type* const return_type = nullptr;
+    /// The parameters of the call target
+    const ParameterList parameters;
 
-  /// Equality operator
-  /// @param other the signature to compare this to
-  /// @returns true if this signature is equal to other
-  bool operator==(const CallTargetSignature& other) const;
+    /// Equality operator
+    /// @param other the signature to compare this to
+    /// @returns true if this signature is equal to other
+    bool operator==(const CallTargetSignature& other) const;
 
-  /// @param usage the parameter usage to find
-  /// @returns the index of the parameter with the given usage, or -1 if no
-  /// parameter with the given usage exists.
-  int IndexOf(ParameterUsage usage) const;
+    /// @param usage the parameter usage to find
+    /// @returns the index of the parameter with the given usage, or -1 if no
+    /// parameter with the given usage exists.
+    int IndexOf(ParameterUsage usage) const;
 };
 
 /// CallTarget is the base for callable functions, builtins, type constructors
 /// and type casts.
 class CallTarget : public Castable<CallTarget, Node> {
- public:
-  /// Constructor
-  /// @param return_type the return type of the call target
-  /// @param parameters the parameters for the call target
-  CallTarget(const sem::Type* return_type, const ParameterList& parameters);
+  public:
+    /// Constructor
+    /// @param return_type the return type of the call target
+    /// @param parameters the parameters for the call target
+    CallTarget(const sem::Type* return_type, const ParameterList& parameters);
 
-  /// Copy constructor
-  CallTarget(const CallTarget&);
+    /// Copy constructor
+    CallTarget(const CallTarget&);
 
-  /// Destructor
-  ~CallTarget() override;
+    /// Destructor
+    ~CallTarget() override;
 
-  /// @return the return type of the call target
-  const sem::Type* ReturnType() const { return signature_.return_type; }
+    /// @return the return type of the call target
+    const sem::Type* ReturnType() const { return signature_.return_type; }
 
-  /// @return the parameters of the call target
-  const ParameterList& Parameters() const { return signature_.parameters; }
+    /// @return the parameters of the call target
+    const ParameterList& Parameters() const { return signature_.parameters; }
 
-  /// @return the signature of the call target
-  const CallTargetSignature& Signature() const { return signature_; }
+    /// @return the signature of the call target
+    const CallTargetSignature& Signature() const { return signature_; }
 
- private:
-  CallTargetSignature signature_;
+  private:
+    CallTargetSignature signature_;
 };
 
 }  // namespace tint::sem
@@ -95,10 +95,10 @@
 /// std::unordered_set.
 template <>
 class hash<tint::sem::CallTargetSignature> {
- public:
-  /// @param sig the CallTargetSignature to hash
-  /// @return the hash value
-  std::size_t operator()(const tint::sem::CallTargetSignature& sig) const;
+  public:
+    /// @param sig the CallTargetSignature to hash
+    /// @return the hash value
+    std::size_t operator()(const tint::sem::CallTargetSignature& sig) const;
 };
 
 }  // namespace std
diff --git a/src/tint/sem/constant.cc b/src/tint/sem/constant.cc
index 3b23d05..f5c82a2 100644
--- a/src/tint/sem/constant.cc
+++ b/src/tint/sem/constant.cc
@@ -26,26 +26,24 @@
 namespace {
 
 const Type* ElemType(const Type* ty, size_t num_elements) {
-  diag::List diag;
-  if (ty->is_scalar()) {
-    if (num_elements != 1) {
-      TINT_ICE(Semantic, diag)
-          << "sem::Constant() type <-> num_element mismatch. type: '"
-          << ty->TypeInfo().name << "' num_elements: " << num_elements;
+    diag::List diag;
+    if (ty->is_scalar()) {
+        if (num_elements != 1) {
+            TINT_ICE(Semantic, diag) << "sem::Constant() type <-> num_element mismatch. type: '"
+                                     << ty->TypeInfo().name << "' num_elements: " << num_elements;
+        }
+        return ty;
     }
-    return ty;
-  }
-  if (auto* vec = ty->As<Vector>()) {
-    if (num_elements != vec->Width()) {
-      TINT_ICE(Semantic, diag)
-          << "sem::Constant() type <-> num_element mismatch. type: '"
-          << ty->TypeInfo().name << "' num_elements: " << num_elements;
+    if (auto* vec = ty->As<Vector>()) {
+        if (num_elements != vec->Width()) {
+            TINT_ICE(Semantic, diag) << "sem::Constant() type <-> num_element mismatch. type: '"
+                                     << ty->TypeInfo().name << "' num_elements: " << num_elements;
+        }
+        TINT_ASSERT(Semantic, vec->type()->is_scalar());
+        return vec->type();
     }
-    TINT_ASSERT(Semantic, vec->type()->is_scalar());
-    return vec->type();
-  }
-  TINT_UNREACHABLE(Semantic, diag) << "Unsupported sem::Constant type";
-  return nullptr;
+    TINT_UNREACHABLE(Semantic, diag) << "Unsupported sem::Constant type";
+    return nullptr;
 }
 
 }  // namespace
@@ -62,21 +60,20 @@
 Constant& Constant::operator=(const Constant& rhs) = default;
 
 bool Constant::AnyZero() const {
-  for (size_t i = 0; i < Elements().size(); ++i) {
-    if (WithScalarAt(i, [&](auto&& s) {
-          // Use std::equal_to to work around -Wfloat-equal warnings
-          auto equals_to =
-              std::equal_to<std::remove_reference_t<decltype(s)>>{};
-
-          if (equals_to(s, 0)) {
+    for (size_t i = 0; i < Elements().size(); ++i) {
+        if (WithScalarAt(i, [&](auto&& s) {
+                // Use std::equal_to to work around -Wfloat-equal warnings
+                using T = std::remove_reference_t<decltype(s)>;
+                auto equal_to = std::equal_to<T>{};
+                if (equal_to(s, T(0))) {
+                    return true;
+                }
+                return false;
+            })) {
             return true;
-          }
-          return false;
-        })) {
-      return true;
+        }
     }
-  }
-  return false;
+    return false;
 }
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/constant.h b/src/tint/sem/constant.h
index cfb6f1e..673446f 100644
--- a/src/tint/sem/constant.h
+++ b/src/tint/sem/constant.h
@@ -25,117 +25,108 @@
 /// A Constant is compile-time known expression value, expressed as a flattened
 /// list of scalar values. Value may be of a scalar or vector type.
 class Constant {
-  using i32 = ProgramBuilder::i32;
-  using u32 = ProgramBuilder::u32;
-  using f32 = ProgramBuilder::f32;
+  public:
+    /// Scalar holds a single constant scalar value, as a union of an i32, u32,
+    /// f32 or boolean.
+    union Scalar {
+        /// The scalar value as a i32
+        tint::i32 i32;
+        /// The scalar value as a u32
+        tint::u32 u32;
+        /// The scalar value as a f32
+        tint::f32 f32;
+        /// The scalar value as a bool
+        bool bool_;
 
- public:
-  /// Scalar holds a single constant scalar value, as a union of an i32, u32,
-  /// f32 or boolean.
-  union Scalar {
-    /// The scalar value as a i32
-    int32_t i32;
-    /// The scalar value as a u32
-    uint32_t u32;
-    /// The scalar value as a f32
-    float f32;
-    /// The scalar value as a bool
-    bool bool_;
+        /// Constructs the scalar with the i32 value `v`
+        /// @param v the value of the Scalar
+        Scalar(tint::i32 v) : i32(v) {}  // NOLINT
 
-    /// Constructs the scalar with the i32 value `v`
-    /// @param v the value of the Scalar
-    Scalar(ProgramBuilder::i32 v) : i32(v) {}  // NOLINT
+        /// Constructs the scalar with the u32 value `v`
+        /// @param v the value of the Scalar
+        Scalar(tint::u32 v) : u32(v) {}  // NOLINT
 
-    /// Constructs the scalar with the u32 value `v`
-    /// @param v the value of the Scalar
-    Scalar(ProgramBuilder::u32 v) : u32(v) {}  // NOLINT
+        /// Constructs the scalar with the f32 value `v`
+        /// @param v the value of the Scalar
+        Scalar(tint::f32 v) : f32(v) {}  // NOLINT
 
-    /// Constructs the scalar with the f32 value `v`
-    /// @param v the value of the Scalar
-    Scalar(ProgramBuilder::f32 v) : f32(v) {}  // NOLINT
+        /// Constructs the scalar with the bool value `v`
+        /// @param v the value of the Scalar
+        Scalar(bool v) : bool_(v) {}  // NOLINT
+    };
 
-    /// Constructs the scalar with the bool value `v`
-    /// @param v the value of the Scalar
-    Scalar(bool v) : bool_(v) {}  // NOLINT
-  };
+    /// Scalars is a list of scalar values
+    using Scalars = std::vector<Scalar>;
 
-  /// Scalars is a list of scalar values
-  using Scalars = std::vector<Scalar>;
+    /// Constructs an invalid Constant
+    Constant();
 
-  /// Constructs an invalid Constant
-  Constant();
+    /// Constructs a Constant of the given type and element values
+    /// @param ty the Constant type
+    /// @param els the Constant element values
+    Constant(const Type* ty, Scalars els);
 
-  /// Constructs a Constant of the given type and element values
-  /// @param ty the Constant type
-  /// @param els the Constant element values
-  Constant(const Type* ty, Scalars els);
+    /// Copy constructor
+    Constant(const Constant&);
 
-  /// Copy constructor
-  Constant(const Constant&);
+    /// Destructor
+    ~Constant();
 
-  /// Destructor
-  ~Constant();
+    /// Copy assignment
+    /// @param other the Constant to copy
+    /// @returns this Constant
+    Constant& operator=(const Constant& other);
 
-  /// Copy assignment
-  /// @param other the Constant to copy
-  /// @returns this Constant
-  Constant& operator=(const Constant& other);
+    /// @returns true if the Constant has been initialized
+    bool IsValid() const { return type_ != nullptr; }
 
-  /// @returns true if the Constant has been initialized
-  bool IsValid() const { return type_ != nullptr; }
+    /// @return true if the Constant has been initialized
+    operator bool() const { return IsValid(); }
 
-  /// @return true if the Constant has been initialized
-  operator bool() const { return IsValid(); }
+    /// @returns the type of the Constant
+    const sem::Type* Type() const { return type_; }
 
-  /// @returns the type of the Constant
-  const sem::Type* Type() const { return type_; }
+    /// @returns the element type of the Constant
+    const sem::Type* ElementType() const { return elem_type_; }
 
-  /// @returns the element type of the Constant
-  const sem::Type* ElementType() const { return elem_type_; }
+    /// @returns the constant's scalar elements
+    const Scalars& Elements() const { return elems_; }
 
-  /// @returns the constant's scalar elements
-  const Scalars& Elements() const { return elems_; }
+    /// @returns true if any scalar element is zero
+    bool AnyZero() const;
 
-  /// @returns true if any scalar element is zero
-  bool AnyZero() const;
-
-  /// Calls `func(s)` with s being the current scalar value at `index`.
-  /// `func` is typically a lambda of the form '[](auto&& s)'.
-  /// @param index the index of the scalar value
-  /// @param func a function with signature `T(S)`
-  /// @return the value returned by func.
-  template <typename Func>
-  auto WithScalarAt(size_t index, Func&& func) const {
-    auto* elem_type = ElementType();
-    if (elem_type->Is<I32>()) {
-      return func(elems_[index].i32);
+    /// Calls `func(s)` with s being the current scalar value at `index`.
+    /// `func` is typically a lambda of the form '[](auto&& s)'.
+    /// @param index the index of the scalar value
+    /// @param func a function with signature `T(S)`
+    /// @return the value returned by func.
+    template <typename Func>
+    auto WithScalarAt(size_t index, Func&& func) const {
+        return Switch(
+            ElementType(),  //
+            [&](const I32*) { return func(elems_[index].i32); },
+            [&](const U32*) { return func(elems_[index].u32); },
+            [&](const F32*) { return func(elems_[index].f32); },
+            [&](const Bool*) { return func(elems_[index].bool_); },
+            [&](Default) {
+                diag::List diags;
+                TINT_UNREACHABLE(Semantic, diags)
+                    << "invalid scalar type " << type_->TypeInfo().name;
+                return func(u32(0u));
+            });
     }
-    if (elem_type->Is<U32>()) {
-      return func(elems_[index].u32);
-    }
-    if (elem_type->Is<F32>()) {
-      return func(elems_[index].f32);
-    }
-    if (elem_type->Is<Bool>()) {
-      return func(elems_[index].bool_);
-    }
-    diag::List diags;
-    TINT_UNREACHABLE(Semantic, diags)
-        << "invalid scalar type " << type_->TypeInfo().name;
-    return func(~0);
-  }
 
-  /// @param index the index of the scalar value
-  /// @return the value of the scalar `static_cast` to type T.
-  template <typename T>
-  T ElementAs(size_t index) const {
-    return WithScalarAt(index, [](auto val) { return static_cast<T>(val); });
-  }
+    /// @param index the index of the scalar value
+    /// @return the value of the scalar `static_cast` to type T.
+    template <typename T>
+    T ElementAs(size_t index) const {
+        return WithScalarAt(index, [](auto val) { return static_cast<T>(val); });
+    }
 
- private:
-  const sem::Type* type_ = nullptr;
-  const sem::Type* elem_type_ = nullptr;
-  Scalars elems_;
+  private:
+    const sem::Type* type_ = nullptr;
+    const sem::Type* elem_type_ = nullptr;
+    Scalars elems_;
 };
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/depth_multisampled_texture_type.cc b/src/tint/sem/depth_multisampled_texture.cc
similarity index 70%
rename from src/tint/sem/depth_multisampled_texture_type.cc
rename to src/tint/sem/depth_multisampled_texture.cc
index bb5b8a7..dd4e108 100644
--- a/src/tint/sem/depth_multisampled_texture_type.cc
+++ b/src/tint/sem/depth_multisampled_texture.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/sem/depth_multisampled_texture_type.h"
+#include "src/tint/sem/depth_multisampled_texture.h"
 
 #include "src/tint/program_builder.h"
 #include "src/tint/utils/hash.h"
@@ -23,37 +23,34 @@
 namespace {
 
 bool IsValidDepthDimension(ast::TextureDimension dim) {
-  return dim == ast::TextureDimension::k2d;
+    return dim == ast::TextureDimension::k2d;
 }
 
 }  // namespace
 
-DepthMultisampledTexture::DepthMultisampledTexture(ast::TextureDimension dim)
-    : Base(dim) {
-  TINT_ASSERT(Semantic, IsValidDepthDimension(dim));
+DepthMultisampledTexture::DepthMultisampledTexture(ast::TextureDimension dim) : Base(dim) {
+    TINT_ASSERT(Semantic, IsValidDepthDimension(dim));
 }
 
-DepthMultisampledTexture::DepthMultisampledTexture(DepthMultisampledTexture&&) =
-    default;
+DepthMultisampledTexture::DepthMultisampledTexture(DepthMultisampledTexture&&) = default;
 
 DepthMultisampledTexture::~DepthMultisampledTexture() = default;
 
 size_t DepthMultisampledTexture::Hash() const {
-  return utils::Hash(TypeInfo::Of<DepthMultisampledTexture>().full_hashcode,
-                     dim());
+    return utils::Hash(TypeInfo::Of<DepthMultisampledTexture>().full_hashcode, dim());
 }
 
 bool DepthMultisampledTexture::Equals(const sem::Type& other) const {
-  if (auto* o = other.As<DepthMultisampledTexture>()) {
-    return o->dim() == dim();
-  }
-  return false;
+    if (auto* o = other.As<DepthMultisampledTexture>()) {
+        return o->dim() == dim();
+    }
+    return false;
 }
 
 std::string DepthMultisampledTexture::FriendlyName(const SymbolTable&) const {
-  std::ostringstream out;
-  out << "texture_depth_multisampled_" << dim();
-  return out.str();
+    std::ostringstream out;
+    out << "texture_depth_multisampled_" << dim();
+    return out.str();
 }
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/depth_multisampled_texture.h b/src/tint/sem/depth_multisampled_texture.h
new file mode 100644
index 0000000..a81954e
--- /dev/null
+++ b/src/tint/sem/depth_multisampled_texture.h
@@ -0,0 +1,49 @@
+// Copyright 2021 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_SEM_DEPTH_MULTISAMPLED_TEXTURE_H_
+#define SRC_TINT_SEM_DEPTH_MULTISAMPLED_TEXTURE_H_
+
+#include <string>
+
+#include "src/tint/sem/texture.h"
+
+namespace tint::sem {
+
+/// A multisampled depth texture type.
+class DepthMultisampledTexture final : public Castable<DepthMultisampledTexture, Texture> {
+  public:
+    /// Constructor
+    /// @param dim the dimensionality of the texture
+    explicit DepthMultisampledTexture(ast::TextureDimension dim);
+    /// Move constructor
+    DepthMultisampledTexture(DepthMultisampledTexture&&);
+    ~DepthMultisampledTexture() override;
+
+    /// @returns a hash of the type.
+    size_t Hash() const override;
+
+    /// @param other the other type to compare against
+    /// @returns true if the this type is equal to the given type
+    bool Equals(const Type& other) const override;
+
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type that closely resembles how it would be
+    /// declared in WGSL.
+    std::string FriendlyName(const SymbolTable& symbols) const override;
+};
+
+}  // namespace tint::sem
+
+#endif  // SRC_TINT_SEM_DEPTH_MULTISAMPLED_TEXTURE_H_
diff --git a/src/tint/sem/depth_multisampled_texture_test.cc b/src/tint/sem/depth_multisampled_texture_test.cc
new file mode 100644
index 0000000..0ee3dfd
--- /dev/null
+++ b/src/tint/sem/depth_multisampled_texture_test.cc
@@ -0,0 +1,62 @@
+// Copyright 2021 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/sem/depth_multisampled_texture.h"
+
+#include "src/tint/sem/test_helper.h"
+
+#include "src/tint/sem/external_texture.h"
+#include "src/tint/sem/sampled_texture.h"
+#include "src/tint/sem/storage_texture.h"
+
+namespace tint::sem {
+namespace {
+
+using DepthMultisampledTextureTest = TestHelper;
+
+TEST_F(DepthMultisampledTextureTest, Creation) {
+    auto* a = create<DepthMultisampledTexture>(ast::TextureDimension::k2d);
+    auto* b = create<DepthMultisampledTexture>(ast::TextureDimension::k2d);
+
+    EXPECT_EQ(a, b);
+}
+
+TEST_F(DepthMultisampledTextureTest, Hash) {
+    auto* a = create<DepthMultisampledTexture>(ast::TextureDimension::k2d);
+    auto* b = create<DepthMultisampledTexture>(ast::TextureDimension::k2d);
+
+    EXPECT_EQ(a->Hash(), b->Hash());
+}
+
+TEST_F(DepthMultisampledTextureTest, Equals) {
+    auto* a = create<DepthMultisampledTexture>(ast::TextureDimension::k2d);
+    auto* b = create<DepthMultisampledTexture>(ast::TextureDimension::k2d);
+
+    EXPECT_TRUE(a->Equals(*a));
+    EXPECT_TRUE(a->Equals(*b));
+    EXPECT_FALSE(a->Equals(Void{}));
+}
+
+TEST_F(DepthMultisampledTextureTest, Dim) {
+    DepthMultisampledTexture d(ast::TextureDimension::k2d);
+    EXPECT_EQ(d.dim(), ast::TextureDimension::k2d);
+}
+
+TEST_F(DepthMultisampledTextureTest, FriendlyName) {
+    DepthMultisampledTexture d(ast::TextureDimension::k2d);
+    EXPECT_EQ(d.FriendlyName(Symbols()), "texture_depth_multisampled_2d");
+}
+
+}  // namespace
+}  // namespace tint::sem
diff --git a/src/tint/sem/depth_multisampled_texture_type.h b/src/tint/sem/depth_multisampled_texture_type.h
deleted file mode 100644
index de23417..0000000
--- a/src/tint/sem/depth_multisampled_texture_type.h
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2021 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SRC_TINT_SEM_DEPTH_MULTISAMPLED_TEXTURE_TYPE_H_
-#define SRC_TINT_SEM_DEPTH_MULTISAMPLED_TEXTURE_TYPE_H_
-
-#include <string>
-
-#include "src/tint/sem/texture_type.h"
-
-namespace tint::sem {
-
-/// A multisampled depth texture type.
-class DepthMultisampledTexture final
-    : public Castable<DepthMultisampledTexture, Texture> {
- public:
-  /// Constructor
-  /// @param dim the dimensionality of the texture
-  explicit DepthMultisampledTexture(ast::TextureDimension dim);
-  /// Move constructor
-  DepthMultisampledTexture(DepthMultisampledTexture&&);
-  ~DepthMultisampledTexture() override;
-
-  /// @returns a hash of the type.
-  size_t Hash() const override;
-
-  /// @param other the other type to compare against
-  /// @returns true if the this type is equal to the given type
-  bool Equals(const Type& other) const override;
-
-  /// @param symbols the program's symbol table
-  /// @returns the name for this type that closely resembles how it would be
-  /// declared in WGSL.
-  std::string FriendlyName(const SymbolTable& symbols) const override;
-};
-
-}  // namespace tint::sem
-
-#endif  // SRC_TINT_SEM_DEPTH_MULTISAMPLED_TEXTURE_TYPE_H_
diff --git a/src/tint/sem/depth_multisampled_texture_type_test.cc b/src/tint/sem/depth_multisampled_texture_type_test.cc
deleted file mode 100644
index ea92986..0000000
--- a/src/tint/sem/depth_multisampled_texture_type_test.cc
+++ /dev/null
@@ -1,62 +0,0 @@
-// Copyright 2021 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/tint/sem/depth_multisampled_texture_type.h"
-
-#include "src/tint/sem/test_helper.h"
-
-#include "src/tint/sem/external_texture_type.h"
-#include "src/tint/sem/sampled_texture_type.h"
-#include "src/tint/sem/storage_texture_type.h"
-
-namespace tint::sem {
-namespace {
-
-using DepthMultisampledTextureTest = TestHelper;
-
-TEST_F(DepthMultisampledTextureTest, Creation) {
-  auto* a = create<DepthMultisampledTexture>(ast::TextureDimension::k2d);
-  auto* b = create<DepthMultisampledTexture>(ast::TextureDimension::k2d);
-
-  EXPECT_EQ(a, b);
-}
-
-TEST_F(DepthMultisampledTextureTest, Hash) {
-  auto* a = create<DepthMultisampledTexture>(ast::TextureDimension::k2d);
-  auto* b = create<DepthMultisampledTexture>(ast::TextureDimension::k2d);
-
-  EXPECT_EQ(a->Hash(), b->Hash());
-}
-
-TEST_F(DepthMultisampledTextureTest, Equals) {
-  auto* a = create<DepthMultisampledTexture>(ast::TextureDimension::k2d);
-  auto* b = create<DepthMultisampledTexture>(ast::TextureDimension::k2d);
-
-  EXPECT_TRUE(a->Equals(*a));
-  EXPECT_TRUE(a->Equals(*b));
-  EXPECT_FALSE(a->Equals(Void{}));
-}
-
-TEST_F(DepthMultisampledTextureTest, Dim) {
-  DepthMultisampledTexture d(ast::TextureDimension::k2d);
-  EXPECT_EQ(d.dim(), ast::TextureDimension::k2d);
-}
-
-TEST_F(DepthMultisampledTextureTest, FriendlyName) {
-  DepthMultisampledTexture d(ast::TextureDimension::k2d);
-  EXPECT_EQ(d.FriendlyName(Symbols()), "texture_depth_multisampled_2d");
-}
-
-}  // namespace
-}  // namespace tint::sem
diff --git a/src/tint/sem/depth_texture_type.cc b/src/tint/sem/depth_texture.cc
similarity index 68%
rename from src/tint/sem/depth_texture_type.cc
rename to src/tint/sem/depth_texture.cc
index 1ff0060..664a721 100644
--- a/src/tint/sem/depth_texture_type.cc
+++ b/src/tint/sem/depth_texture.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/sem/depth_texture_type.h"
+#include "src/tint/sem/depth_texture.h"
 
 #include "src/tint/program_builder.h"
 #include "src/tint/utils/hash.h"
@@ -23,16 +23,14 @@
 namespace {
 
 bool IsValidDepthDimension(ast::TextureDimension dim) {
-  return dim == ast::TextureDimension::k2d ||
-         dim == ast::TextureDimension::k2dArray ||
-         dim == ast::TextureDimension::kCube ||
-         dim == ast::TextureDimension::kCubeArray;
+    return dim == ast::TextureDimension::k2d || dim == ast::TextureDimension::k2dArray ||
+           dim == ast::TextureDimension::kCube || dim == ast::TextureDimension::kCubeArray;
 }
 
 }  // namespace
 
 DepthTexture::DepthTexture(ast::TextureDimension dim) : Base(dim) {
-  TINT_ASSERT(Semantic, IsValidDepthDimension(dim));
+    TINT_ASSERT(Semantic, IsValidDepthDimension(dim));
 }
 
 DepthTexture::DepthTexture(DepthTexture&&) = default;
@@ -40,20 +38,20 @@
 DepthTexture::~DepthTexture() = default;
 
 size_t DepthTexture::Hash() const {
-  return utils::Hash(TypeInfo::Of<DepthTexture>().full_hashcode, dim());
+    return utils::Hash(TypeInfo::Of<DepthTexture>().full_hashcode, dim());
 }
 
 bool DepthTexture::Equals(const sem::Type& other) const {
-  if (auto* o = other.As<DepthTexture>()) {
-    return o->dim() == dim();
-  }
-  return false;
+    if (auto* o = other.As<DepthTexture>()) {
+        return o->dim() == dim();
+    }
+    return false;
 }
 
 std::string DepthTexture::FriendlyName(const SymbolTable&) const {
-  std::ostringstream out;
-  out << "texture_depth_" << dim();
-  return out.str();
+    std::ostringstream out;
+    out << "texture_depth_" << dim();
+    return out.str();
 }
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/depth_texture.h b/src/tint/sem/depth_texture.h
new file mode 100644
index 0000000..9a2e6d0
--- /dev/null
+++ b/src/tint/sem/depth_texture.h
@@ -0,0 +1,49 @@
+// 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_SEM_DEPTH_TEXTURE_H_
+#define SRC_TINT_SEM_DEPTH_TEXTURE_H_
+
+#include <string>
+
+#include "src/tint/sem/texture.h"
+
+namespace tint::sem {
+
+/// A depth texture type.
+class DepthTexture final : public Castable<DepthTexture, Texture> {
+  public:
+    /// Constructor
+    /// @param dim the dimensionality of the texture
+    explicit DepthTexture(ast::TextureDimension dim);
+    /// Move constructor
+    DepthTexture(DepthTexture&&);
+    ~DepthTexture() override;
+
+    /// @returns a hash of the type.
+    size_t Hash() const override;
+
+    /// @param other the other type to compare against
+    /// @returns true if the this type is equal to the given type
+    bool Equals(const Type& other) const override;
+
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type that closely resembles how it would be
+    /// declared in WGSL.
+    std::string FriendlyName(const SymbolTable& symbols) const override;
+};
+
+}  // namespace tint::sem
+
+#endif  // SRC_TINT_SEM_DEPTH_TEXTURE_H_
diff --git a/src/tint/sem/depth_texture_test.cc b/src/tint/sem/depth_texture_test.cc
new file mode 100644
index 0000000..7a869fb
--- /dev/null
+++ b/src/tint/sem/depth_texture_test.cc
@@ -0,0 +1,76 @@
+// 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/sem/depth_texture.h"
+
+#include "src/tint/sem/test_helper.h"
+
+#include "src/tint/sem/external_texture.h"
+#include "src/tint/sem/sampled_texture.h"
+#include "src/tint/sem/storage_texture.h"
+
+namespace tint::sem {
+namespace {
+
+using DepthTextureTest = TestHelper;
+
+TEST_F(DepthTextureTest, Creation) {
+    auto* a = create<DepthTexture>(ast::TextureDimension::k2d);
+    auto* b = create<DepthTexture>(ast::TextureDimension::k2d);
+    auto* c = create<DepthTexture>(ast::TextureDimension::k2dArray);
+
+    EXPECT_EQ(a, b);
+    EXPECT_NE(a, c);
+}
+
+TEST_F(DepthTextureTest, Hash) {
+    auto* a = create<DepthTexture>(ast::TextureDimension::k2d);
+    auto* b = create<DepthTexture>(ast::TextureDimension::k2d);
+    auto* c = create<DepthTexture>(ast::TextureDimension::k2dArray);
+
+    EXPECT_EQ(a->Hash(), b->Hash());
+    EXPECT_NE(a->Hash(), c->Hash());
+}
+
+TEST_F(DepthTextureTest, Equals) {
+    auto* a = create<DepthTexture>(ast::TextureDimension::k2d);
+    auto* b = create<DepthTexture>(ast::TextureDimension::k2d);
+    auto* c = create<DepthTexture>(ast::TextureDimension::k2dArray);
+
+    EXPECT_TRUE(a->Equals(*b));
+    EXPECT_FALSE(a->Equals(*c));
+    EXPECT_FALSE(a->Equals(Void{}));
+}
+
+TEST_F(DepthTextureTest, IsTexture) {
+    DepthTexture d(ast::TextureDimension::kCube);
+    Texture* ty = &d;
+    EXPECT_TRUE(ty->Is<DepthTexture>());
+    EXPECT_FALSE(ty->Is<ExternalTexture>());
+    EXPECT_FALSE(ty->Is<SampledTexture>());
+    EXPECT_FALSE(ty->Is<StorageTexture>());
+}
+
+TEST_F(DepthTextureTest, Dim) {
+    DepthTexture d(ast::TextureDimension::kCube);
+    EXPECT_EQ(d.dim(), ast::TextureDimension::kCube);
+}
+
+TEST_F(DepthTextureTest, FriendlyName) {
+    DepthTexture d(ast::TextureDimension::kCube);
+    EXPECT_EQ(d.FriendlyName(Symbols()), "texture_depth_cube");
+}
+
+}  // namespace
+}  // namespace tint::sem
diff --git a/src/tint/sem/depth_texture_type.h b/src/tint/sem/depth_texture_type.h
deleted file mode 100644
index 0f25785..0000000
--- a/src/tint/sem/depth_texture_type.h
+++ /dev/null
@@ -1,49 +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_SEM_DEPTH_TEXTURE_TYPE_H_
-#define SRC_TINT_SEM_DEPTH_TEXTURE_TYPE_H_
-
-#include <string>
-
-#include "src/tint/sem/texture_type.h"
-
-namespace tint::sem {
-
-/// A depth texture type.
-class DepthTexture final : public Castable<DepthTexture, Texture> {
- public:
-  /// Constructor
-  /// @param dim the dimensionality of the texture
-  explicit DepthTexture(ast::TextureDimension dim);
-  /// Move constructor
-  DepthTexture(DepthTexture&&);
-  ~DepthTexture() override;
-
-  /// @returns a hash of the type.
-  size_t Hash() const override;
-
-  /// @param other the other type to compare against
-  /// @returns true if the this type is equal to the given type
-  bool Equals(const Type& other) const override;
-
-  /// @param symbols the program's symbol table
-  /// @returns the name for this type that closely resembles how it would be
-  /// declared in WGSL.
-  std::string FriendlyName(const SymbolTable& symbols) const override;
-};
-
-}  // namespace tint::sem
-
-#endif  // SRC_TINT_SEM_DEPTH_TEXTURE_TYPE_H_
diff --git a/src/tint/sem/depth_texture_type_test.cc b/src/tint/sem/depth_texture_type_test.cc
deleted file mode 100644
index 28bb84a..0000000
--- a/src/tint/sem/depth_texture_type_test.cc
+++ /dev/null
@@ -1,76 +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/sem/depth_texture_type.h"
-
-#include "src/tint/sem/test_helper.h"
-
-#include "src/tint/sem/external_texture_type.h"
-#include "src/tint/sem/sampled_texture_type.h"
-#include "src/tint/sem/storage_texture_type.h"
-
-namespace tint::sem {
-namespace {
-
-using DepthTextureTest = TestHelper;
-
-TEST_F(DepthTextureTest, Creation) {
-  auto* a = create<DepthTexture>(ast::TextureDimension::k2d);
-  auto* b = create<DepthTexture>(ast::TextureDimension::k2d);
-  auto* c = create<DepthTexture>(ast::TextureDimension::k2dArray);
-
-  EXPECT_EQ(a, b);
-  EXPECT_NE(a, c);
-}
-
-TEST_F(DepthTextureTest, Hash) {
-  auto* a = create<DepthTexture>(ast::TextureDimension::k2d);
-  auto* b = create<DepthTexture>(ast::TextureDimension::k2d);
-  auto* c = create<DepthTexture>(ast::TextureDimension::k2dArray);
-
-  EXPECT_EQ(a->Hash(), b->Hash());
-  EXPECT_NE(a->Hash(), c->Hash());
-}
-
-TEST_F(DepthTextureTest, Equals) {
-  auto* a = create<DepthTexture>(ast::TextureDimension::k2d);
-  auto* b = create<DepthTexture>(ast::TextureDimension::k2d);
-  auto* c = create<DepthTexture>(ast::TextureDimension::k2dArray);
-
-  EXPECT_TRUE(a->Equals(*b));
-  EXPECT_FALSE(a->Equals(*c));
-  EXPECT_FALSE(a->Equals(Void{}));
-}
-
-TEST_F(DepthTextureTest, IsTexture) {
-  DepthTexture d(ast::TextureDimension::kCube);
-  Texture* ty = &d;
-  EXPECT_TRUE(ty->Is<DepthTexture>());
-  EXPECT_FALSE(ty->Is<ExternalTexture>());
-  EXPECT_FALSE(ty->Is<SampledTexture>());
-  EXPECT_FALSE(ty->Is<StorageTexture>());
-}
-
-TEST_F(DepthTextureTest, Dim) {
-  DepthTexture d(ast::TextureDimension::kCube);
-  EXPECT_EQ(d.dim(), ast::TextureDimension::kCube);
-}
-
-TEST_F(DepthTextureTest, FriendlyName) {
-  DepthTexture d(ast::TextureDimension::kCube);
-  EXPECT_EQ(d.FriendlyName(Symbols()), "texture_depth_cube");
-}
-
-}  // namespace
-}  // namespace tint::sem
diff --git a/src/tint/sem/expression.cc b/src/tint/sem/expression.cc
index a5f2b1b..40fbb58 100644
--- a/src/tint/sem/expression.cc
+++ b/src/tint/sem/expression.cc
@@ -24,13 +24,15 @@
                        const sem::Type* type,
                        const Statement* statement,
                        Constant constant,
-                       bool has_side_effects)
+                       bool has_side_effects,
+                       const Variable* source_var /* = nullptr */)
     : declaration_(declaration),
+      source_variable_(source_var),
       type_(type),
       statement_(statement),
       constant_(std::move(constant)),
       has_side_effects_(has_side_effects) {
-  TINT_ASSERT(Semantic, type_);
+    TINT_ASSERT(Semantic, type_);
 }
 
 Expression::~Expression() = default;
diff --git a/src/tint/sem/expression.h b/src/tint/sem/expression.h
index 23eae1b..13f493b 100644
--- a/src/tint/sem/expression.h
+++ b/src/tint/sem/expression.h
@@ -24,58 +24,70 @@
 namespace tint::sem {
 class Statement;
 class Type;
+class Variable;
 }  // namespace tint::sem
 
 namespace tint::sem {
 /// Expression holds the semantic information for expression nodes.
 class Expression : public Castable<Expression, Node> {
- public:
-  /// Constructor
-  /// @param declaration the AST node
-  /// @param type the resolved type of the expression
-  /// @param statement the statement that owns this expression
-  /// @param constant the constant value of the expression. May be invalid
-  /// @param has_side_effects true if this expression may have side-effects
-  Expression(const ast::Expression* declaration,
-             const sem::Type* type,
-             const Statement* statement,
-             Constant constant,
-             bool has_side_effects);
+  public:
+    /// Constructor
+    /// @param declaration the AST node
+    /// @param type the resolved type of the expression
+    /// @param statement the statement that owns this expression
+    /// @param constant the constant value of the expression. May be invalid
+    /// @param has_side_effects true if this expression may have side-effects
+    /// @param source_var the (optional) source variable for this expression
+    Expression(const ast::Expression* declaration,
+               const sem::Type* type,
+               const Statement* statement,
+               Constant constant,
+               bool has_side_effects,
+               const Variable* source_var = nullptr);
 
-  /// Destructor
-  ~Expression() override;
+    /// Destructor
+    ~Expression() override;
 
-  /// @returns the AST node
-  const ast::Expression* Declaration() const { return declaration_; }
+    /// @returns the AST node
+    const ast::Expression* Declaration() const { return declaration_; }
 
-  /// @return the resolved type of the expression
-  const sem::Type* Type() const { return type_; }
+    /// @return the resolved type of the expression
+    const sem::Type* Type() const { return type_; }
 
-  /// @return the statement that owns this expression
-  const Statement* Stmt() const { return statement_; }
+    /// @return the statement that owns this expression
+    const Statement* Stmt() const { return statement_; }
 
-  /// @return the constant value of this expression
-  const Constant& ConstantValue() const { return constant_; }
+    /// @return the constant value of this expression
+    const Constant& ConstantValue() const { return constant_; }
 
-  /// @return the behaviors of this statement
-  const sem::Behaviors& Behaviors() const { return behaviors_; }
+    /// Returns the variable or parameter that this expression derives from.
+    /// For reference and pointer expressions, this will either be the originating
+    /// variable or a function parameter. For other types of expressions, it will
+    /// either be the parameter or constant declaration, or nullptr.
+    /// @return the source variable of this expression, or nullptr
+    const Variable* SourceVariable() const { return source_variable_; }
 
-  /// @return the behaviors of this statement
-  sem::Behaviors& Behaviors() { return behaviors_; }
+    /// @return the behaviors of this statement
+    const sem::Behaviors& Behaviors() const { return behaviors_; }
 
-  /// @return true of this expression may have side effects
-  bool HasSideEffects() const { return has_side_effects_; }
+    /// @return the behaviors of this statement
+    sem::Behaviors& Behaviors() { return behaviors_; }
 
- protected:
-  /// The AST expression node for this semantic expression
-  const ast::Expression* const declaration_;
+    /// @return true of this expression may have side effects
+    bool HasSideEffects() const { return has_side_effects_; }
 
- private:
-  const sem::Type* const type_;
-  const Statement* const statement_;
-  const Constant constant_;
-  sem::Behaviors behaviors_{sem::Behavior::kNext};
-  const bool has_side_effects_;
+  protected:
+    /// The AST expression node for this semantic expression
+    const ast::Expression* const declaration_;
+    /// The source variable for this semantic expression, or nullptr
+    const Variable* source_variable_;
+
+  private:
+    const sem::Type* const type_;
+    const Statement* const statement_;
+    const Constant constant_;
+    sem::Behaviors behaviors_{sem::Behavior::kNext};
+    const bool has_side_effects_;
 };
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/external_texture_type.cc b/src/tint/sem/external_texture.cc
similarity index 84%
rename from src/tint/sem/external_texture_type.cc
rename to src/tint/sem/external_texture.cc
index adfd373..d677f65 100644
--- a/src/tint/sem/external_texture_type.cc
+++ b/src/tint/sem/external_texture.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/sem/external_texture_type.h"
+#include "src/tint/sem/external_texture.h"
 
 #include "src/tint/program_builder.h"
 
@@ -27,15 +27,15 @@
 ExternalTexture::~ExternalTexture() = default;
 
 size_t ExternalTexture::Hash() const {
-  return static_cast<size_t>(TypeInfo::Of<ExternalTexture>().full_hashcode);
+    return static_cast<size_t>(TypeInfo::Of<ExternalTexture>().full_hashcode);
 }
 
 bool ExternalTexture::Equals(const sem::Type& other) const {
-  return other.Is<ExternalTexture>();
+    return other.Is<ExternalTexture>();
 }
 
 std::string ExternalTexture::FriendlyName(const SymbolTable&) const {
-  return "texture_external";
+    return "texture_external";
 }
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/external_texture.h b/src/tint/sem/external_texture.h
new file mode 100644
index 0000000..3cfbd41
--- /dev/null
+++ b/src/tint/sem/external_texture.h
@@ -0,0 +1,49 @@
+// Copyright 2021 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_SEM_EXTERNAL_TEXTURE_H_
+#define SRC_TINT_SEM_EXTERNAL_TEXTURE_H_
+
+#include <string>
+
+#include "src/tint/sem/texture.h"
+
+namespace tint::sem {
+
+/// An external texture type
+class ExternalTexture final : public Castable<ExternalTexture, Texture> {
+  public:
+    /// Constructor
+    ExternalTexture();
+
+    /// Move constructor
+    ExternalTexture(ExternalTexture&&);
+    ~ExternalTexture() override;
+
+    /// @returns a hash of the type.
+    size_t Hash() const override;
+
+    /// @param other the other type to compare against
+    /// @returns true if the this type is equal to the given type
+    bool Equals(const Type& other) const override;
+
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type that closely resembles how it would be
+    /// declared in WGSL.
+    std::string FriendlyName(const SymbolTable& symbols) const override;
+};
+
+}  // namespace tint::sem
+
+#endif  // SRC_TINT_SEM_EXTERNAL_TEXTURE_H_
diff --git a/src/tint/sem/external_texture_test.cc b/src/tint/sem/external_texture_test.cc
new file mode 100644
index 0000000..aecd58a
--- /dev/null
+++ b/src/tint/sem/external_texture_test.cc
@@ -0,0 +1,70 @@
+// Copyright 2021 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/sem/external_texture.h"
+
+#include "src/tint/sem/depth_texture.h"
+#include "src/tint/sem/multisampled_texture.h"
+#include "src/tint/sem/sampled_texture.h"
+#include "src/tint/sem/storage_texture.h"
+#include "src/tint/sem/test_helper.h"
+
+namespace tint::sem {
+namespace {
+
+using ExternalTextureTest = TestHelper;
+
+TEST_F(ExternalTextureTest, Creation) {
+    auto* a = create<ExternalTexture>();
+    auto* b = create<ExternalTexture>();
+    EXPECT_EQ(a, b);
+}
+
+TEST_F(ExternalTextureTest, Hash) {
+    auto* a = create<ExternalTexture>();
+    auto* b = create<ExternalTexture>();
+    EXPECT_EQ(a->Hash(), b->Hash());
+}
+
+TEST_F(ExternalTextureTest, Equals) {
+    auto* a = create<ExternalTexture>();
+    auto* b = create<ExternalTexture>();
+    EXPECT_TRUE(a->Equals(*b));
+    EXPECT_FALSE(a->Equals(Void{}));
+}
+
+TEST_F(ExternalTextureTest, IsTexture) {
+    F32 f32;
+    ExternalTexture s;
+    Texture* ty = &s;
+    EXPECT_FALSE(ty->Is<DepthTexture>());
+    EXPECT_TRUE(ty->Is<ExternalTexture>());
+    EXPECT_FALSE(ty->Is<MultisampledTexture>());
+    EXPECT_FALSE(ty->Is<SampledTexture>());
+    EXPECT_FALSE(ty->Is<StorageTexture>());
+}
+
+TEST_F(ExternalTextureTest, Dim) {
+    F32 f32;
+    ExternalTexture s;
+    EXPECT_EQ(s.dim(), ast::TextureDimension::k2d);
+}
+
+TEST_F(ExternalTextureTest, FriendlyName) {
+    ExternalTexture s;
+    EXPECT_EQ(s.FriendlyName(Symbols()), "texture_external");
+}
+
+}  // namespace
+}  // namespace tint::sem
diff --git a/src/tint/sem/external_texture_type.h b/src/tint/sem/external_texture_type.h
deleted file mode 100644
index 4a07005..0000000
--- a/src/tint/sem/external_texture_type.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright 2021 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SRC_TINT_SEM_EXTERNAL_TEXTURE_TYPE_H_
-#define SRC_TINT_SEM_EXTERNAL_TEXTURE_TYPE_H_
-
-#include <string>
-
-#include "src/tint/sem/texture_type.h"
-
-namespace tint::sem {
-
-/// An external texture type
-class ExternalTexture final : public Castable<ExternalTexture, Texture> {
- public:
-  /// Constructor
-  ExternalTexture();
-
-  /// Move constructor
-  ExternalTexture(ExternalTexture&&);
-  ~ExternalTexture() override;
-
-  /// @returns a hash of the type.
-  size_t Hash() const override;
-
-  /// @param other the other type to compare against
-  /// @returns true if the this type is equal to the given type
-  bool Equals(const Type& other) const override;
-
-  /// @param symbols the program's symbol table
-  /// @returns the name for this type that closely resembles how it would be
-  /// declared in WGSL.
-  std::string FriendlyName(const SymbolTable& symbols) const override;
-};
-
-}  // namespace tint::sem
-
-#endif  // SRC_TINT_SEM_EXTERNAL_TEXTURE_TYPE_H_
diff --git a/src/tint/sem/external_texture_type_test.cc b/src/tint/sem/external_texture_type_test.cc
deleted file mode 100644
index 439b3bc..0000000
--- a/src/tint/sem/external_texture_type_test.cc
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2021 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/tint/sem/external_texture_type.h"
-
-#include "src/tint/sem/depth_texture_type.h"
-#include "src/tint/sem/multisampled_texture_type.h"
-#include "src/tint/sem/sampled_texture_type.h"
-#include "src/tint/sem/storage_texture_type.h"
-#include "src/tint/sem/test_helper.h"
-
-namespace tint::sem {
-namespace {
-
-using ExternalTextureTest = TestHelper;
-
-TEST_F(ExternalTextureTest, Creation) {
-  auto* a = create<ExternalTexture>();
-  auto* b = create<ExternalTexture>();
-  EXPECT_EQ(a, b);
-}
-
-TEST_F(ExternalTextureTest, Hash) {
-  auto* a = create<ExternalTexture>();
-  auto* b = create<ExternalTexture>();
-  EXPECT_EQ(a->Hash(), b->Hash());
-}
-
-TEST_F(ExternalTextureTest, Equals) {
-  auto* a = create<ExternalTexture>();
-  auto* b = create<ExternalTexture>();
-  EXPECT_TRUE(a->Equals(*b));
-  EXPECT_FALSE(a->Equals(Void{}));
-}
-
-TEST_F(ExternalTextureTest, IsTexture) {
-  F32 f32;
-  ExternalTexture s;
-  Texture* ty = &s;
-  EXPECT_FALSE(ty->Is<DepthTexture>());
-  EXPECT_TRUE(ty->Is<ExternalTexture>());
-  EXPECT_FALSE(ty->Is<MultisampledTexture>());
-  EXPECT_FALSE(ty->Is<SampledTexture>());
-  EXPECT_FALSE(ty->Is<StorageTexture>());
-}
-
-TEST_F(ExternalTextureTest, Dim) {
-  F32 f32;
-  ExternalTexture s;
-  EXPECT_EQ(s.dim(), ast::TextureDimension::k2d);
-}
-
-TEST_F(ExternalTextureTest, FriendlyName) {
-  ExternalTexture s;
-  EXPECT_EQ(s.FriendlyName(Symbols()), "texture_external");
-}
-
-}  // namespace
-}  // namespace tint::sem
diff --git a/src/tint/sem/f32_type.cc b/src/tint/sem/f32.cc
similarity index 84%
rename from src/tint/sem/f32_type.cc
rename to src/tint/sem/f32.cc
index c5b013e..83fffcc 100644
--- a/src/tint/sem/f32_type.cc
+++ b/src/tint/sem/f32.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/sem/f32_type.h"
+#include "src/tint/sem/f32.h"
 
 #include "src/tint/program_builder.h"
 
@@ -27,27 +27,27 @@
 F32::~F32() = default;
 
 size_t F32::Hash() const {
-  return static_cast<size_t>(TypeInfo::Of<F32>().full_hashcode);
+    return static_cast<size_t>(TypeInfo::Of<F32>().full_hashcode);
 }
 
 bool F32::Equals(const Type& other) const {
-  return other.Is<F32>();
+    return other.Is<F32>();
 }
 
 std::string F32::FriendlyName(const SymbolTable&) const {
-  return "f32";
+    return "f32";
 }
 
 bool F32::IsConstructible() const {
-  return true;
+    return true;
 }
 
 uint32_t F32::Size() const {
-  return 4;
+    return 4;
 }
 
 uint32_t F32::Align() const {
-  return 4;
+    return 4;
 }
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/f32.h b/src/tint/sem/f32.h
new file mode 100644
index 0000000..c7d7ad6
--- /dev/null
+++ b/src/tint/sem/f32.h
@@ -0,0 +1,58 @@
+// 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_SEM_F32_H_
+#define SRC_TINT_SEM_F32_H_
+
+#include <string>
+
+#include "src/tint/sem/type.h"
+
+namespace tint::sem {
+
+/// A float 32 type
+class F32 final : public Castable<F32, Type> {
+  public:
+    /// Constructor
+    F32();
+    /// Move constructor
+    F32(F32&&);
+    ~F32() override;
+
+    /// @returns a hash of the type.
+    size_t Hash() const override;
+
+    /// @param other the other type to compare against
+    /// @returns true if the this type is equal to the given type
+    bool Equals(const Type& other) const override;
+
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type that closely resembles how it would be
+    /// declared in WGSL.
+    std::string FriendlyName(const SymbolTable& symbols) const override;
+
+    /// @returns true if constructible as per
+    /// https://gpuweb.github.io/gpuweb/wgsl/#constructible-types
+    bool IsConstructible() const override;
+
+    /// @returns the size in bytes of the type.
+    uint32_t Size() const override;
+
+    /// @returns the alignment in bytes of the type.
+    uint32_t Align() const override;
+};
+
+}  // namespace tint::sem
+
+#endif  // SRC_TINT_SEM_F32_H_
diff --git a/src/tint/sem/f32_type_test.cc b/src/tint/sem/f32_test.cc
similarity index 68%
rename from src/tint/sem/f32_type_test.cc
rename to src/tint/sem/f32_test.cc
index 7fd7b76..de4a3e8 100644
--- a/src/tint/sem/f32_type_test.cc
+++ b/src/tint/sem/f32_test.cc
@@ -13,7 +13,7 @@
 // limitations under the License.
 
 #include "src/tint/sem/test_helper.h"
-#include "src/tint/sem/texture_type.h"
+#include "src/tint/sem/texture.h"
 
 namespace tint::sem {
 namespace {
@@ -21,27 +21,27 @@
 using F32Test = TestHelper;
 
 TEST_F(F32Test, Creation) {
-  auto* a = create<F32>();
-  auto* b = create<F32>();
-  EXPECT_EQ(a, b);
+    auto* a = create<F32>();
+    auto* b = create<F32>();
+    EXPECT_EQ(a, b);
 }
 
 TEST_F(F32Test, Hash) {
-  auto* a = create<F32>();
-  auto* b = create<F32>();
-  EXPECT_EQ(a->Hash(), b->Hash());
+    auto* a = create<F32>();
+    auto* b = create<F32>();
+    EXPECT_EQ(a->Hash(), b->Hash());
 }
 
 TEST_F(F32Test, Equals) {
-  auto* a = create<F32>();
-  auto* b = create<F32>();
-  EXPECT_TRUE(a->Equals(*b));
-  EXPECT_FALSE(a->Equals(Void{}));
+    auto* a = create<F32>();
+    auto* b = create<F32>();
+    EXPECT_TRUE(a->Equals(*b));
+    EXPECT_FALSE(a->Equals(Void{}));
 }
 
 TEST_F(F32Test, FriendlyName) {
-  F32 f;
-  EXPECT_EQ(f.FriendlyName(Symbols()), "f32");
+    F32 f;
+    EXPECT_EQ(f.FriendlyName(Symbols()), "f32");
 }
 
 }  // namespace
diff --git a/src/tint/sem/f32_type.h b/src/tint/sem/f32_type.h
deleted file mode 100644
index 0d0fabf..0000000
--- a/src/tint/sem/f32_type.h
+++ /dev/null
@@ -1,58 +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_SEM_F32_TYPE_H_
-#define SRC_TINT_SEM_F32_TYPE_H_
-
-#include <string>
-
-#include "src/tint/sem/type.h"
-
-namespace tint::sem {
-
-/// A float 32 type
-class F32 final : public Castable<F32, Type> {
- public:
-  /// Constructor
-  F32();
-  /// Move constructor
-  F32(F32&&);
-  ~F32() override;
-
-  /// @returns a hash of the type.
-  size_t Hash() const override;
-
-  /// @param other the other type to compare against
-  /// @returns true if the this type is equal to the given type
-  bool Equals(const Type& other) const override;
-
-  /// @param symbols the program's symbol table
-  /// @returns the name for this type that closely resembles how it would be
-  /// declared in WGSL.
-  std::string FriendlyName(const SymbolTable& symbols) const override;
-
-  /// @returns true if constructible as per
-  /// https://gpuweb.github.io/gpuweb/wgsl/#constructible-types
-  bool IsConstructible() const override;
-
-  /// @returns the size in bytes of the type.
-  uint32_t Size() const override;
-
-  /// @returns the alignment in bytes of the type.
-  uint32_t Align() const override;
-};
-
-}  // namespace tint::sem
-
-#endif  // SRC_TINT_SEM_F32_TYPE_H_
diff --git a/src/tint/sem/for_loop_statement.cc b/src/tint/sem/for_loop_statement.cc
index 5599633..1e6aa6d 100644
--- a/src/tint/sem/for_loop_statement.cc
+++ b/src/tint/sem/for_loop_statement.cc
@@ -28,7 +28,7 @@
 ForLoopStatement::~ForLoopStatement() = default;
 
 const ast::ForLoopStatement* ForLoopStatement::Declaration() const {
-  return static_cast<const ast::ForLoopStatement*>(Base::Declaration());
+    return static_cast<const ast::ForLoopStatement*>(Base::Declaration());
 }
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/for_loop_statement.h b/src/tint/sem/for_loop_statement.h
index cd7b761..9f7d62a 100644
--- a/src/tint/sem/for_loop_statement.h
+++ b/src/tint/sem/for_loop_statement.h
@@ -28,32 +28,31 @@
 namespace tint::sem {
 
 /// Holds semantic information about a for-loop statement
-class ForLoopStatement final
-    : public Castable<ForLoopStatement, CompoundStatement> {
- public:
-  /// Constructor
-  /// @param declaration the AST node for this for-loop statement
-  /// @param parent the owning statement
-  /// @param function the owning function
-  ForLoopStatement(const ast::ForLoopStatement* declaration,
-                   const CompoundStatement* parent,
-                   const sem::Function* function);
+class ForLoopStatement final : public Castable<ForLoopStatement, CompoundStatement> {
+  public:
+    /// Constructor
+    /// @param declaration the AST node for this for-loop statement
+    /// @param parent the owning statement
+    /// @param function the owning function
+    ForLoopStatement(const ast::ForLoopStatement* declaration,
+                     const CompoundStatement* parent,
+                     const sem::Function* function);
 
-  /// Destructor
-  ~ForLoopStatement() override;
+    /// Destructor
+    ~ForLoopStatement() override;
 
-  /// @returns the AST node
-  const ast::ForLoopStatement* Declaration() const;
+    /// @returns the AST node
+    const ast::ForLoopStatement* Declaration() const;
 
-  /// @returns the for-loop condition expression
-  const Expression* Condition() const { return condition_; }
+    /// @returns the for-loop condition expression
+    const Expression* Condition() const { return condition_; }
 
-  /// Sets the for-loop condition expression
-  /// @param condition the for-loop condition expression
-  void SetCondition(const Expression* condition) { condition_ = condition; }
+    /// Sets the for-loop condition expression
+    /// @param condition the for-loop condition expression
+    void SetCondition(const Expression* condition) { condition_ = condition; }
 
- private:
-  const Expression* condition_ = nullptr;
+  private:
+    const Expression* condition_ = nullptr;
 };
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/function.cc b/src/tint/sem/function.cc
index 4ffda9a..790933b 100644
--- a/src/tint/sem/function.cc
+++ b/src/tint/sem/function.cc
@@ -15,11 +15,11 @@
 #include "src/tint/sem/function.h"
 
 #include "src/tint/ast/function.h"
-#include "src/tint/sem/depth_texture_type.h"
-#include "src/tint/sem/external_texture_type.h"
-#include "src/tint/sem/multisampled_texture_type.h"
-#include "src/tint/sem/sampled_texture_type.h"
-#include "src/tint/sem/storage_texture_type.h"
+#include "src/tint/sem/depth_texture.h"
+#include "src/tint/sem/external_texture.h"
+#include "src/tint/sem/multisampled_texture.h"
+#include "src/tint/sem/sampled_texture.h"
+#include "src/tint/sem/storage_texture.h"
 #include "src/tint/sem/variable.h"
 #include "src/tint/utils/to_const_ptr_vec.h"
 
@@ -32,164 +32,155 @@
                    std::vector<Parameter*> parameters)
     : Base(return_type, utils::ToConstPtrVec(parameters)),
       declaration_(declaration),
-      workgroup_size_{WorkgroupDimension{1}, WorkgroupDimension{1},
-                      WorkgroupDimension{1}} {
-  for (auto* parameter : parameters) {
-    parameter->SetOwner(this);
-  }
+      workgroup_size_{WorkgroupDimension{1}, WorkgroupDimension{1}, WorkgroupDimension{1}} {
+    for (auto* parameter : parameters) {
+        parameter->SetOwner(this);
+    }
 }
 
 Function::~Function() = default;
 
 std::vector<std::pair<const Variable*, const ast::LocationAttribute*>>
 Function::TransitivelyReferencedLocationVariables() const {
-  std::vector<std::pair<const Variable*, const ast::LocationAttribute*>> ret;
+    std::vector<std::pair<const Variable*, const ast::LocationAttribute*>> ret;
 
-  for (auto* var : TransitivelyReferencedGlobals()) {
-    for (auto* attr : var->Declaration()->attributes) {
-      if (auto* location = attr->As<ast::LocationAttribute>()) {
-        ret.push_back({var, location});
-        break;
-      }
+    for (auto* var : TransitivelyReferencedGlobals()) {
+        for (auto* attr : var->Declaration()->attributes) {
+            if (auto* location = attr->As<ast::LocationAttribute>()) {
+                ret.push_back({var, location});
+                break;
+            }
+        }
     }
-  }
-  return ret;
+    return ret;
 }
 
-Function::VariableBindings Function::TransitivelyReferencedUniformVariables()
-    const {
-  VariableBindings ret;
+Function::VariableBindings Function::TransitivelyReferencedUniformVariables() const {
+    VariableBindings ret;
 
-  for (auto* var : TransitivelyReferencedGlobals()) {
-    if (var->StorageClass() != ast::StorageClass::kUniform) {
-      continue;
-    }
+    for (auto* var : TransitivelyReferencedGlobals()) {
+        if (var->StorageClass() != ast::StorageClass::kUniform) {
+            continue;
+        }
 
-    if (auto binding_point = var->Declaration()->BindingPoint()) {
-      ret.push_back({var, binding_point});
+        if (auto binding_point = var->Declaration()->BindingPoint()) {
+            ret.push_back({var, binding_point});
+        }
     }
-  }
-  return ret;
+    return ret;
 }
 
-Function::VariableBindings
-Function::TransitivelyReferencedStorageBufferVariables() const {
-  VariableBindings ret;
+Function::VariableBindings Function::TransitivelyReferencedStorageBufferVariables() const {
+    VariableBindings ret;
 
-  for (auto* var : TransitivelyReferencedGlobals()) {
-    if (var->StorageClass() != ast::StorageClass::kStorage) {
-      continue;
-    }
+    for (auto* var : TransitivelyReferencedGlobals()) {
+        if (var->StorageClass() != ast::StorageClass::kStorage) {
+            continue;
+        }
 
-    if (auto binding_point = var->Declaration()->BindingPoint()) {
-      ret.push_back({var, binding_point});
+        if (auto binding_point = var->Declaration()->BindingPoint()) {
+            ret.push_back({var, binding_point});
+        }
     }
-  }
-  return ret;
+    return ret;
 }
 
 std::vector<std::pair<const Variable*, const ast::BuiltinAttribute*>>
 Function::TransitivelyReferencedBuiltinVariables() const {
-  std::vector<std::pair<const Variable*, const ast::BuiltinAttribute*>> ret;
+    std::vector<std::pair<const Variable*, const ast::BuiltinAttribute*>> ret;
 
-  for (auto* var : TransitivelyReferencedGlobals()) {
-    for (auto* attr : var->Declaration()->attributes) {
-      if (auto* builtin = attr->As<ast::BuiltinAttribute>()) {
-        ret.push_back({var, builtin});
-        break;
-      }
+    for (auto* var : TransitivelyReferencedGlobals()) {
+        for (auto* attr : var->Declaration()->attributes) {
+            if (auto* builtin = attr->As<ast::BuiltinAttribute>()) {
+                ret.push_back({var, builtin});
+                break;
+            }
+        }
     }
-  }
-  return ret;
+    return ret;
 }
 
-Function::VariableBindings Function::TransitivelyReferencedSamplerVariables()
-    const {
-  return TransitivelyReferencedSamplerVariablesImpl(ast::SamplerKind::kSampler);
+Function::VariableBindings Function::TransitivelyReferencedSamplerVariables() const {
+    return TransitivelyReferencedSamplerVariablesImpl(ast::SamplerKind::kSampler);
 }
 
-Function::VariableBindings
-Function::TransitivelyReferencedComparisonSamplerVariables() const {
-  return TransitivelyReferencedSamplerVariablesImpl(
-      ast::SamplerKind::kComparisonSampler);
+Function::VariableBindings Function::TransitivelyReferencedComparisonSamplerVariables() const {
+    return TransitivelyReferencedSamplerVariablesImpl(ast::SamplerKind::kComparisonSampler);
 }
 
-Function::VariableBindings
-Function::TransitivelyReferencedSampledTextureVariables() const {
-  return TransitivelyReferencedSampledTextureVariablesImpl(false);
+Function::VariableBindings Function::TransitivelyReferencedSampledTextureVariables() const {
+    return TransitivelyReferencedSampledTextureVariablesImpl(false);
 }
 
-Function::VariableBindings
-Function::TransitivelyReferencedMultisampledTextureVariables() const {
-  return TransitivelyReferencedSampledTextureVariablesImpl(true);
+Function::VariableBindings Function::TransitivelyReferencedMultisampledTextureVariables() const {
+    return TransitivelyReferencedSampledTextureVariablesImpl(true);
 }
 
 Function::VariableBindings Function::TransitivelyReferencedVariablesOfType(
     const tint::TypeInfo* type) const {
-  VariableBindings ret;
-  for (auto* var : TransitivelyReferencedGlobals()) {
-    auto* unwrapped_type = var->Type()->UnwrapRef();
-    if (unwrapped_type->TypeInfo().Is(type)) {
-      if (auto binding_point = var->Declaration()->BindingPoint()) {
-        ret.push_back({var, binding_point});
-      }
+    VariableBindings ret;
+    for (auto* var : TransitivelyReferencedGlobals()) {
+        auto* unwrapped_type = var->Type()->UnwrapRef();
+        if (unwrapped_type->TypeInfo().Is(type)) {
+            if (auto binding_point = var->Declaration()->BindingPoint()) {
+                ret.push_back({var, binding_point});
+            }
+        }
     }
-  }
-  return ret;
+    return ret;
 }
 
 bool Function::HasAncestorEntryPoint(Symbol symbol) const {
-  for (const auto* point : ancestor_entry_points_) {
-    if (point->Declaration()->symbol == symbol) {
-      return true;
+    for (const auto* point : ancestor_entry_points_) {
+        if (point->Declaration()->symbol == symbol) {
+            return true;
+        }
     }
-  }
-  return false;
+    return false;
 }
 
 Function::VariableBindings Function::TransitivelyReferencedSamplerVariablesImpl(
     ast::SamplerKind kind) const {
-  VariableBindings ret;
+    VariableBindings ret;
 
-  for (auto* var : TransitivelyReferencedGlobals()) {
-    auto* unwrapped_type = var->Type()->UnwrapRef();
-    auto* sampler = unwrapped_type->As<sem::Sampler>();
-    if (sampler == nullptr || sampler->kind() != kind) {
-      continue;
-    }
+    for (auto* var : TransitivelyReferencedGlobals()) {
+        auto* unwrapped_type = var->Type()->UnwrapRef();
+        auto* sampler = unwrapped_type->As<sem::Sampler>();
+        if (sampler == nullptr || sampler->kind() != kind) {
+            continue;
+        }
 
-    if (auto binding_point = var->Declaration()->BindingPoint()) {
-      ret.push_back({var, binding_point});
+        if (auto binding_point = var->Declaration()->BindingPoint()) {
+            ret.push_back({var, binding_point});
+        }
     }
-  }
-  return ret;
+    return ret;
 }
 
-Function::VariableBindings
-Function::TransitivelyReferencedSampledTextureVariablesImpl(
+Function::VariableBindings Function::TransitivelyReferencedSampledTextureVariablesImpl(
     bool multisampled) const {
-  VariableBindings ret;
+    VariableBindings ret;
 
-  for (auto* var : TransitivelyReferencedGlobals()) {
-    auto* unwrapped_type = var->Type()->UnwrapRef();
-    auto* texture = unwrapped_type->As<sem::Texture>();
-    if (texture == nullptr) {
-      continue;
+    for (auto* var : TransitivelyReferencedGlobals()) {
+        auto* unwrapped_type = var->Type()->UnwrapRef();
+        auto* texture = unwrapped_type->As<sem::Texture>();
+        if (texture == nullptr) {
+            continue;
+        }
+
+        auto is_multisampled = texture->Is<sem::MultisampledTexture>();
+        auto is_sampled = texture->Is<sem::SampledTexture>();
+
+        if ((multisampled && !is_multisampled) || (!multisampled && !is_sampled)) {
+            continue;
+        }
+
+        if (auto binding_point = var->Declaration()->BindingPoint()) {
+            ret.push_back({var, binding_point});
+        }
     }
 
-    auto is_multisampled = texture->Is<sem::MultisampledTexture>();
-    auto is_sampled = texture->Is<sem::SampledTexture>();
-
-    if ((multisampled && !is_multisampled) || (!multisampled && !is_sampled)) {
-      continue;
-    }
-
-    if (auto binding_point = var->Declaration()->BindingPoint()) {
-      ret.push_back({var, binding_point});
-    }
-  }
-
-  return ret;
+    return ret;
 }
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/function.h b/src/tint/sem/function.h
index 6813676..f95920a 100644
--- a/src/tint/sem/function.h
+++ b/src/tint/sem/function.h
@@ -40,11 +40,11 @@
 /// WorkgroupDimension describes the size of a single dimension of an entry
 /// point's workgroup size.
 struct WorkgroupDimension {
-  /// The size of this dimension.
-  uint32_t value;
-  /// A pipeline-overridable constant that overrides the size, or nullptr if
-  /// this dimension is not overridable.
-  const ast::Variable* overridable_const = nullptr;
+    /// The size of this dimension.
+    uint32_t value;
+    /// A pipeline-overridable constant that overrides the size, or nullptr if
+    /// this dimension is not overridable.
+    const ast::Variable* overridable_const = nullptr;
 };
 
 /// WorkgroupSize is a three-dimensional array of WorkgroupDimensions.
@@ -52,234 +52,222 @@
 
 /// Function holds the semantic information for function nodes.
 class Function final : public Castable<Function, CallTarget> {
- public:
-  /// A vector of [Variable*, ast::VariableBindingPoint] pairs
-  using VariableBindings =
-      std::vector<std::pair<const Variable*, ast::VariableBindingPoint>>;
+  public:
+    /// A vector of [Variable*, ast::VariableBindingPoint] pairs
+    using VariableBindings = std::vector<std::pair<const Variable*, ast::VariableBindingPoint>>;
 
-  /// Constructor
-  /// @param declaration the ast::Function
-  /// @param return_type the return type of the function
-  /// @param parameters the parameters to the function
-  Function(const ast::Function* declaration,
-           Type* return_type,
-           std::vector<Parameter*> parameters);
+    /// Constructor
+    /// @param declaration the ast::Function
+    /// @param return_type the return type of the function
+    /// @param parameters the parameters to the function
+    Function(const ast::Function* declaration,
+             Type* return_type,
+             std::vector<Parameter*> parameters);
 
-  /// Destructor
-  ~Function() override;
+    /// Destructor
+    ~Function() override;
 
-  /// @returns the ast::Function declaration
-  const ast::Function* Declaration() const { return declaration_; }
+    /// @returns the ast::Function declaration
+    const ast::Function* Declaration() const { return declaration_; }
 
-  /// @returns the workgroup size {x, y, z} for the function.
-  const sem::WorkgroupSize& WorkgroupSize() const { return workgroup_size_; }
+    /// @returns the workgroup size {x, y, z} for the function.
+    const sem::WorkgroupSize& WorkgroupSize() const { return workgroup_size_; }
 
-  /// Sets the workgroup size {x, y, z} for the function.
-  /// @param workgroup_size the new workgroup size of the function
-  void SetWorkgroupSize(sem::WorkgroupSize workgroup_size) {
-    workgroup_size_ = std::move(workgroup_size);
-  }
-
-  /// @returns all directly referenced global variables
-  const utils::UniqueVector<const GlobalVariable*>& DirectlyReferencedGlobals()
-      const {
-    return directly_referenced_globals_;
-  }
-
-  /// Records that this function directly references the given global variable.
-  /// Note: Implicitly adds this global to the transtively-called globals.
-  /// @param global the module-scope variable
-  void AddDirectlyReferencedGlobal(const sem::GlobalVariable* global) {
-    directly_referenced_globals_.add(global);
-    transitively_referenced_globals_.add(global);
-  }
-
-  /// @returns all transitively referenced global variables
-  const utils::UniqueVector<const GlobalVariable*>&
-  TransitivelyReferencedGlobals() const {
-    return transitively_referenced_globals_;
-  }
-
-  /// Records that this function transitively references the given global
-  /// variable.
-  /// @param global the module-scoped variable
-  void AddTransitivelyReferencedGlobal(const sem::GlobalVariable* global) {
-    transitively_referenced_globals_.add(global);
-  }
-
-  /// @returns the list of functions that this function transitively calls.
-  const utils::UniqueVector<const Function*>& TransitivelyCalledFunctions()
-      const {
-    return transitively_called_functions_;
-  }
-
-  /// Records that this function transitively calls `function`.
-  /// @param function the function this function transitively calls
-  void AddTransitivelyCalledFunction(const Function* function) {
-    transitively_called_functions_.add(function);
-  }
-
-  /// @returns the list of builtins that this function directly calls.
-  const utils::UniqueVector<const Builtin*>& DirectlyCalledBuiltins() const {
-    return directly_called_builtins_;
-  }
-
-  /// Records that this function transitively calls `builtin`.
-  /// @param builtin the builtin this function directly calls
-  void AddDirectlyCalledBuiltin(const Builtin* builtin) {
-    directly_called_builtins_.add(builtin);
-  }
-
-  /// Adds the given texture/sampler pair to the list of unique pairs
-  /// that this function uses (directly or indirectly). These can only
-  /// be parameters to this function or global variables. Uniqueness is
-  /// ensured by texture_sampler_pairs_ being a UniqueVector.
-  /// @param texture the texture (must be non-null)
-  /// @param sampler the sampler (null indicates a texture-only reference)
-  void AddTextureSamplerPair(const sem::Variable* texture,
-                             const sem::Variable* sampler) {
-    texture_sampler_pairs_.add(VariablePair(texture, sampler));
-  }
-
-  /// @returns the list of texture/sampler pairs that this function uses
-  /// (directly or indirectly).
-  const std::vector<VariablePair>& TextureSamplerPairs() const {
-    return texture_sampler_pairs_;
-  }
-
-  /// @returns the list of direct calls to functions / builtins made by this
-  /// function
-  std::vector<const Call*> DirectCallStatements() const {
-    return direct_calls_;
-  }
-
-  /// Adds a record of the direct function / builtin calls made by this
-  /// function
-  /// @param call the call
-  void AddDirectCall(const Call* call) { direct_calls_.emplace_back(call); }
-
-  /// @param target the target of a call
-  /// @returns the Call to the given CallTarget, or nullptr the target was not
-  /// called by this function.
-  const Call* FindDirectCallTo(const CallTarget* target) const {
-    for (auto* call : direct_calls_) {
-      if (call->Target() == target) {
-        return call;
-      }
+    /// Sets the workgroup size {x, y, z} for the function.
+    /// @param workgroup_size the new workgroup size of the function
+    void SetWorkgroupSize(sem::WorkgroupSize workgroup_size) {
+        workgroup_size_ = std::move(workgroup_size);
     }
-    return nullptr;
-  }
 
-  /// @returns the list of callsites of this function
-  std::vector<const Call*> CallSites() const { return callsites_; }
+    /// @returns all directly referenced global variables
+    const utils::UniqueVector<const GlobalVariable*>& DirectlyReferencedGlobals() const {
+        return directly_referenced_globals_;
+    }
 
-  /// Adds a record of a callsite to this function
-  /// @param call the callsite
-  void AddCallSite(const Call* call) { callsites_.emplace_back(call); }
+    /// Records that this function directly references the given global variable.
+    /// Note: Implicitly adds this global to the transtively-called globals.
+    /// @param global the module-scope variable
+    void AddDirectlyReferencedGlobal(const sem::GlobalVariable* global) {
+        directly_referenced_globals_.add(global);
+        transitively_referenced_globals_.add(global);
+    }
 
-  /// @returns the ancestor entry points
-  const std::vector<const Function*>& AncestorEntryPoints() const {
-    return ancestor_entry_points_;
-  }
+    /// @returns all transitively referenced global variables
+    const utils::UniqueVector<const GlobalVariable*>& TransitivelyReferencedGlobals() const {
+        return transitively_referenced_globals_;
+    }
 
-  /// Adds a record that the given entry point transitively calls this function
-  /// @param entry_point the entry point that transtively calls this function
-  void AddAncestorEntryPoint(const sem::Function* entry_point) {
-    ancestor_entry_points_.emplace_back(entry_point);
-  }
+    /// Records that this function transitively references the given global
+    /// variable.
+    /// @param global the module-scoped variable
+    void AddTransitivelyReferencedGlobal(const sem::GlobalVariable* global) {
+        transitively_referenced_globals_.add(global);
+    }
 
-  /// Retrieves any referenced location variables
-  /// @returns the <variable, attribute> pair.
-  std::vector<std::pair<const Variable*, const ast::LocationAttribute*>>
-  TransitivelyReferencedLocationVariables() const;
+    /// @returns the list of functions that this function transitively calls.
+    const utils::UniqueVector<const Function*>& TransitivelyCalledFunctions() const {
+        return transitively_called_functions_;
+    }
 
-  /// Retrieves any referenced builtin variables
-  /// @returns the <variable, attribute> pair.
-  std::vector<std::pair<const Variable*, const ast::BuiltinAttribute*>>
-  TransitivelyReferencedBuiltinVariables() const;
+    /// Records that this function transitively calls `function`.
+    /// @param function the function this function transitively calls
+    void AddTransitivelyCalledFunction(const Function* function) {
+        transitively_called_functions_.add(function);
+    }
 
-  /// Retrieves any referenced uniform variables. Note, the variables must be
-  /// decorated with both binding and group attributes.
-  /// @returns the referenced uniforms
-  VariableBindings TransitivelyReferencedUniformVariables() const;
+    /// @returns the list of builtins that this function directly calls.
+    const utils::UniqueVector<const Builtin*>& DirectlyCalledBuiltins() const {
+        return directly_called_builtins_;
+    }
 
-  /// Retrieves any referenced storagebuffer variables. Note, the variables
-  /// must be decorated with both binding and group attributes.
-  /// @returns the referenced storagebuffers
-  VariableBindings TransitivelyReferencedStorageBufferVariables() const;
+    /// Records that this function transitively calls `builtin`.
+    /// @param builtin the builtin this function directly calls
+    void AddDirectlyCalledBuiltin(const Builtin* builtin) {
+        directly_called_builtins_.add(builtin);
+    }
 
-  /// Retrieves any referenced regular Sampler variables. Note, the
-  /// variables must be decorated with both binding and group attributes.
-  /// @returns the referenced storagebuffers
-  VariableBindings TransitivelyReferencedSamplerVariables() const;
+    /// Adds the given texture/sampler pair to the list of unique pairs
+    /// that this function uses (directly or indirectly). These can only
+    /// be parameters to this function or global variables. Uniqueness is
+    /// ensured by texture_sampler_pairs_ being a UniqueVector.
+    /// @param texture the texture (must be non-null)
+    /// @param sampler the sampler (null indicates a texture-only reference)
+    void AddTextureSamplerPair(const sem::Variable* texture, const sem::Variable* sampler) {
+        texture_sampler_pairs_.add(VariablePair(texture, sampler));
+    }
 
-  /// Retrieves any referenced comparison Sampler variables. Note, the
-  /// variables must be decorated with both binding and group attributes.
-  /// @returns the referenced storagebuffers
-  VariableBindings TransitivelyReferencedComparisonSamplerVariables() const;
+    /// @returns the list of texture/sampler pairs that this function uses
+    /// (directly or indirectly).
+    const std::vector<VariablePair>& TextureSamplerPairs() const { return texture_sampler_pairs_; }
 
-  /// Retrieves any referenced sampled textures variables. Note, the
-  /// variables must be decorated with both binding and group attributes.
-  /// @returns the referenced sampled textures
-  VariableBindings TransitivelyReferencedSampledTextureVariables() const;
+    /// @returns the list of direct calls to functions / builtins made by this
+    /// function
+    std::vector<const Call*> DirectCallStatements() const { return direct_calls_; }
 
-  /// Retrieves any referenced multisampled textures variables. Note, the
-  /// variables must be decorated with both binding and group attributes.
-  /// @returns the referenced sampled textures
-  VariableBindings TransitivelyReferencedMultisampledTextureVariables() const;
+    /// Adds a record of the direct function / builtin calls made by this
+    /// function
+    /// @param call the call
+    void AddDirectCall(const Call* call) { direct_calls_.emplace_back(call); }
 
-  /// Retrieves any referenced variables of the given type. Note, the variables
-  /// must be decorated with both binding and group attributes.
-  /// @param type the type of the variables to find
-  /// @returns the referenced variables
-  VariableBindings TransitivelyReferencedVariablesOfType(
-      const tint::TypeInfo* type) const;
+    /// @param target the target of a call
+    /// @returns the Call to the given CallTarget, or nullptr the target was not
+    /// called by this function.
+    const Call* FindDirectCallTo(const CallTarget* target) const {
+        for (auto* call : direct_calls_) {
+            if (call->Target() == target) {
+                return call;
+            }
+        }
+        return nullptr;
+    }
 
-  /// Retrieves any referenced variables of the given type. Note, the variables
-  /// must be decorated with both binding and group attributes.
-  /// @returns the referenced variables
-  template <typename T>
-  VariableBindings TransitivelyReferencedVariablesOfType() const {
-    return TransitivelyReferencedVariablesOfType(&TypeInfo::Of<T>());
-  }
+    /// @returns the list of callsites of this function
+    std::vector<const Call*> CallSites() const { return callsites_; }
 
-  /// Checks if the given entry point is an ancestor
-  /// @param sym the entry point symbol
-  /// @returns true if `sym` is an ancestor entry point of this function
-  bool HasAncestorEntryPoint(Symbol sym) const;
+    /// Adds a record of a callsite to this function
+    /// @param call the callsite
+    void AddCallSite(const Call* call) { callsites_.emplace_back(call); }
 
-  /// Sets that this function has a discard statement
-  void SetHasDiscard() { has_discard_ = true; }
+    /// @returns the ancestor entry points
+    const std::vector<const Function*>& AncestorEntryPoints() const {
+        return ancestor_entry_points_;
+    }
 
-  /// Returns true if this function has a discard statement
-  /// @returns true if this function has a discard statement
-  bool HasDiscard() const { return has_discard_; }
+    /// Adds a record that the given entry point transitively calls this function
+    /// @param entry_point the entry point that transtively calls this function
+    void AddAncestorEntryPoint(const sem::Function* entry_point) {
+        ancestor_entry_points_.emplace_back(entry_point);
+    }
 
-  /// @return the behaviors of this function
-  const sem::Behaviors& Behaviors() const { return behaviors_; }
+    /// Retrieves any referenced location variables
+    /// @returns the <variable, attribute> pair.
+    std::vector<std::pair<const Variable*, const ast::LocationAttribute*>>
+    TransitivelyReferencedLocationVariables() const;
 
-  /// @return the behaviors of this function
-  sem::Behaviors& Behaviors() { return behaviors_; }
+    /// Retrieves any referenced builtin variables
+    /// @returns the <variable, attribute> pair.
+    std::vector<std::pair<const Variable*, const ast::BuiltinAttribute*>>
+    TransitivelyReferencedBuiltinVariables() const;
 
- private:
-  VariableBindings TransitivelyReferencedSamplerVariablesImpl(
-      ast::SamplerKind kind) const;
-  VariableBindings TransitivelyReferencedSampledTextureVariablesImpl(
-      bool multisampled) const;
+    /// Retrieves any referenced uniform variables. Note, the variables must be
+    /// decorated with both binding and group attributes.
+    /// @returns the referenced uniforms
+    VariableBindings TransitivelyReferencedUniformVariables() const;
 
-  const ast::Function* const declaration_;
+    /// Retrieves any referenced storagebuffer variables. Note, the variables
+    /// must be decorated with both binding and group attributes.
+    /// @returns the referenced storagebuffers
+    VariableBindings TransitivelyReferencedStorageBufferVariables() const;
 
-  sem::WorkgroupSize workgroup_size_;
-  utils::UniqueVector<const GlobalVariable*> directly_referenced_globals_;
-  utils::UniqueVector<const GlobalVariable*> transitively_referenced_globals_;
-  utils::UniqueVector<const Function*> transitively_called_functions_;
-  utils::UniqueVector<const Builtin*> directly_called_builtins_;
-  utils::UniqueVector<VariablePair> texture_sampler_pairs_;
-  std::vector<const Call*> direct_calls_;
-  std::vector<const Call*> callsites_;
-  std::vector<const Function*> ancestor_entry_points_;
-  bool has_discard_ = false;
-  sem::Behaviors behaviors_{sem::Behavior::kNext};
+    /// Retrieves any referenced regular Sampler variables. Note, the
+    /// variables must be decorated with both binding and group attributes.
+    /// @returns the referenced storagebuffers
+    VariableBindings TransitivelyReferencedSamplerVariables() const;
+
+    /// Retrieves any referenced comparison Sampler variables. Note, the
+    /// variables must be decorated with both binding and group attributes.
+    /// @returns the referenced storagebuffers
+    VariableBindings TransitivelyReferencedComparisonSamplerVariables() const;
+
+    /// Retrieves any referenced sampled textures variables. Note, the
+    /// variables must be decorated with both binding and group attributes.
+    /// @returns the referenced sampled textures
+    VariableBindings TransitivelyReferencedSampledTextureVariables() const;
+
+    /// Retrieves any referenced multisampled textures variables. Note, the
+    /// variables must be decorated with both binding and group attributes.
+    /// @returns the referenced sampled textures
+    VariableBindings TransitivelyReferencedMultisampledTextureVariables() const;
+
+    /// Retrieves any referenced variables of the given type. Note, the variables
+    /// must be decorated with both binding and group attributes.
+    /// @param type the type of the variables to find
+    /// @returns the referenced variables
+    VariableBindings TransitivelyReferencedVariablesOfType(const tint::TypeInfo* type) const;
+
+    /// Retrieves any referenced variables of the given type. Note, the variables
+    /// must be decorated with both binding and group attributes.
+    /// @returns the referenced variables
+    template <typename T>
+    VariableBindings TransitivelyReferencedVariablesOfType() const {
+        return TransitivelyReferencedVariablesOfType(&TypeInfo::Of<T>());
+    }
+
+    /// Checks if the given entry point is an ancestor
+    /// @param sym the entry point symbol
+    /// @returns true if `sym` is an ancestor entry point of this function
+    bool HasAncestorEntryPoint(Symbol sym) const;
+
+    /// Sets that this function has a discard statement
+    void SetHasDiscard() { has_discard_ = true; }
+
+    /// Returns true if this function has a discard statement
+    /// @returns true if this function has a discard statement
+    bool HasDiscard() const { return has_discard_; }
+
+    /// @return the behaviors of this function
+    const sem::Behaviors& Behaviors() const { return behaviors_; }
+
+    /// @return the behaviors of this function
+    sem::Behaviors& Behaviors() { return behaviors_; }
+
+  private:
+    VariableBindings TransitivelyReferencedSamplerVariablesImpl(ast::SamplerKind kind) const;
+    VariableBindings TransitivelyReferencedSampledTextureVariablesImpl(bool multisampled) const;
+
+    const ast::Function* const declaration_;
+
+    sem::WorkgroupSize workgroup_size_;
+    utils::UniqueVector<const GlobalVariable*> directly_referenced_globals_;
+    utils::UniqueVector<const GlobalVariable*> transitively_referenced_globals_;
+    utils::UniqueVector<const Function*> transitively_called_functions_;
+    utils::UniqueVector<const Builtin*> directly_called_builtins_;
+    utils::UniqueVector<VariablePair> texture_sampler_pairs_;
+    std::vector<const Call*> direct_calls_;
+    std::vector<const Call*> callsites_;
+    std::vector<const Function*> ancestor_entry_points_;
+    bool has_discard_ = false;
+    sem::Behaviors behaviors_{sem::Behavior::kNext};
 };
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/i32_type.cc b/src/tint/sem/i32.cc
similarity index 84%
rename from src/tint/sem/i32_type.cc
rename to src/tint/sem/i32.cc
index 0865c03..d5a1e26 100644
--- a/src/tint/sem/i32_type.cc
+++ b/src/tint/sem/i32.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/sem/i32_type.h"
+#include "src/tint/sem/i32.h"
 
 #include "src/tint/program_builder.h"
 
@@ -27,27 +27,27 @@
 I32::~I32() = default;
 
 size_t I32::Hash() const {
-  return static_cast<size_t>(TypeInfo::Of<I32>().full_hashcode);
+    return static_cast<size_t>(TypeInfo::Of<I32>().full_hashcode);
 }
 
 bool I32::Equals(const Type& other) const {
-  return other.Is<I32>();
+    return other.Is<I32>();
 }
 
 std::string I32::FriendlyName(const SymbolTable&) const {
-  return "i32";
+    return "i32";
 }
 
 bool I32::IsConstructible() const {
-  return true;
+    return true;
 }
 
 uint32_t I32::Size() const {
-  return 4;
+    return 4;
 }
 
 uint32_t I32::Align() const {
-  return 4;
+    return 4;
 }
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/i32.h b/src/tint/sem/i32.h
new file mode 100644
index 0000000..3b564db
--- /dev/null
+++ b/src/tint/sem/i32.h
@@ -0,0 +1,58 @@
+// 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_SEM_I32_H_
+#define SRC_TINT_SEM_I32_H_
+
+#include <string>
+
+#include "src/tint/sem/type.h"
+
+namespace tint::sem {
+
+/// A signed int 32 type.
+class I32 final : public Castable<I32, Type> {
+  public:
+    /// Constructor
+    I32();
+    /// Move constructor
+    I32(I32&&);
+    ~I32() override;
+
+    /// @returns a hash of the type.
+    size_t Hash() const override;
+
+    /// @param other the other type to compare against
+    /// @returns true if the this type is equal to the given type
+    bool Equals(const Type& other) const override;
+
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type that closely resembles how it would be
+    /// declared in WGSL.
+    std::string FriendlyName(const SymbolTable& symbols) const override;
+
+    /// @returns true if constructible as per
+    /// https://gpuweb.github.io/gpuweb/wgsl/#constructible-types
+    bool IsConstructible() const override;
+
+    /// @returns the size in bytes of the type.
+    uint32_t Size() const override;
+
+    /// @returns the alignment in bytes of the type.
+    uint32_t Align() const override;
+};
+
+}  // namespace tint::sem
+
+#endif  // SRC_TINT_SEM_I32_H_
diff --git a/src/tint/sem/i32_type_test.cc b/src/tint/sem/i32_test.cc
similarity index 68%
rename from src/tint/sem/i32_type_test.cc
rename to src/tint/sem/i32_test.cc
index 679331a..2ccc92c 100644
--- a/src/tint/sem/i32_type_test.cc
+++ b/src/tint/sem/i32_test.cc
@@ -13,7 +13,7 @@
 // limitations under the License.
 
 #include "src/tint/sem/test_helper.h"
-#include "src/tint/sem/texture_type.h"
+#include "src/tint/sem/texture.h"
 
 namespace tint::sem {
 namespace {
@@ -21,27 +21,27 @@
 using I32Test = TestHelper;
 
 TEST_F(I32Test, Creation) {
-  auto* a = create<I32>();
-  auto* b = create<I32>();
-  EXPECT_EQ(a, b);
+    auto* a = create<I32>();
+    auto* b = create<I32>();
+    EXPECT_EQ(a, b);
 }
 
 TEST_F(I32Test, Hash) {
-  auto* a = create<I32>();
-  auto* b = create<I32>();
-  EXPECT_EQ(a->Hash(), b->Hash());
+    auto* a = create<I32>();
+    auto* b = create<I32>();
+    EXPECT_EQ(a->Hash(), b->Hash());
 }
 
 TEST_F(I32Test, Equals) {
-  auto* a = create<I32>();
-  auto* b = create<I32>();
-  EXPECT_TRUE(a->Equals(*b));
-  EXPECT_FALSE(a->Equals(Void{}));
+    auto* a = create<I32>();
+    auto* b = create<I32>();
+    EXPECT_TRUE(a->Equals(*b));
+    EXPECT_FALSE(a->Equals(Void{}));
 }
 
 TEST_F(I32Test, FriendlyName) {
-  I32 i;
-  EXPECT_EQ(i.FriendlyName(Symbols()), "i32");
+    I32 i;
+    EXPECT_EQ(i.FriendlyName(Symbols()), "i32");
 }
 
 }  // namespace
diff --git a/src/tint/sem/i32_type.h b/src/tint/sem/i32_type.h
deleted file mode 100644
index f6747a2..0000000
--- a/src/tint/sem/i32_type.h
+++ /dev/null
@@ -1,58 +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_SEM_I32_TYPE_H_
-#define SRC_TINT_SEM_I32_TYPE_H_
-
-#include <string>
-
-#include "src/tint/sem/type.h"
-
-namespace tint::sem {
-
-/// A signed int 32 type.
-class I32 final : public Castable<I32, Type> {
- public:
-  /// Constructor
-  I32();
-  /// Move constructor
-  I32(I32&&);
-  ~I32() override;
-
-  /// @returns a hash of the type.
-  size_t Hash() const override;
-
-  /// @param other the other type to compare against
-  /// @returns true if the this type is equal to the given type
-  bool Equals(const Type& other) const override;
-
-  /// @param symbols the program's symbol table
-  /// @returns the name for this type that closely resembles how it would be
-  /// declared in WGSL.
-  std::string FriendlyName(const SymbolTable& symbols) const override;
-
-  /// @returns true if constructible as per
-  /// https://gpuweb.github.io/gpuweb/wgsl/#constructible-types
-  bool IsConstructible() const override;
-
-  /// @returns the size in bytes of the type.
-  uint32_t Size() const override;
-
-  /// @returns the alignment in bytes of the type.
-  uint32_t Align() const override;
-};
-
-}  // namespace tint::sem
-
-#endif  // SRC_TINT_SEM_I32_TYPE_H_
diff --git a/src/tint/sem/if_statement.cc b/src/tint/sem/if_statement.cc
index 5102b89..a79555a 100644
--- a/src/tint/sem/if_statement.cc
+++ b/src/tint/sem/if_statement.cc
@@ -17,7 +17,6 @@
 #include "src/tint/program_builder.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::sem::IfStatement);
-TINT_INSTANTIATE_TYPEINFO(tint::sem::ElseStatement);
 
 namespace tint::sem {
 
@@ -29,18 +28,7 @@
 IfStatement::~IfStatement() = default;
 
 const ast::IfStatement* IfStatement::Declaration() const {
-  return static_cast<const ast::IfStatement*>(Base::Declaration());
-}
-
-ElseStatement::ElseStatement(const ast::ElseStatement* declaration,
-                             const IfStatement* parent,
-                             const sem::Function* function)
-    : Base(declaration, parent, function) {}
-
-ElseStatement::~ElseStatement() = default;
-
-const ast::ElseStatement* ElseStatement::Declaration() const {
-  return static_cast<const ast::ElseStatement*>(Base::Declaration());
+    return static_cast<const ast::IfStatement*>(Base::Declaration());
 }
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/if_statement.h b/src/tint/sem/if_statement.h
index 8e4fb27..e9ecda0 100644
--- a/src/tint/sem/if_statement.h
+++ b/src/tint/sem/if_statement.h
@@ -20,7 +20,6 @@
 // Forward declarations
 namespace tint::ast {
 class IfStatement;
-class ElseStatement;
 }  // namespace tint::ast
 namespace tint::sem {
 class Expression;
@@ -30,63 +29,30 @@
 
 /// Holds semantic information about an if statement
 class IfStatement final : public Castable<IfStatement, CompoundStatement> {
- public:
-  /// Constructor
-  /// @param declaration the AST node for this if statement
-  /// @param parent the owning statement
-  /// @param function the owning function
-  IfStatement(const ast::IfStatement* declaration,
-              const CompoundStatement* parent,
-              const sem::Function* function);
-
-  /// Destructor
-  ~IfStatement() override;
-
-  /// @returns the AST node
-  const ast::IfStatement* Declaration() const;
-
-  /// @returns the if-statement condition expression
-  const Expression* Condition() const { return condition_; }
-
-  /// Sets the if-statement condition expression
-  /// @param condition the if condition expression
-  void SetCondition(const Expression* condition) { condition_ = condition; }
-
- private:
-  const Expression* condition_ = nullptr;
-};
-
-/// Holds semantic information about an else statement
-class ElseStatement final : public Castable<ElseStatement, CompoundStatement> {
- public:
-  /// Constructor
-  /// @param declaration the AST node for this else statement
-  /// @param parent the owning statement
-  /// @param function the owning function
-  ElseStatement(const ast::ElseStatement* declaration,
-                const IfStatement* parent,
+  public:
+    /// Constructor
+    /// @param declaration the AST node for this if statement
+    /// @param parent the owning statement
+    /// @param function the owning function
+    IfStatement(const ast::IfStatement* declaration,
+                const CompoundStatement* parent,
                 const sem::Function* function);
 
-  /// Destructor
-  ~ElseStatement() override;
+    /// Destructor
+    ~IfStatement() override;
 
-  /// @returns the AST node
-  const ast::ElseStatement* Declaration() const;
+    /// @returns the AST node
+    const ast::IfStatement* Declaration() const;
 
-  /// @returns the else-statement condition expression
-  const Expression* Condition() const { return condition_; }
+    /// @returns the if-statement condition expression
+    const Expression* Condition() const { return condition_; }
 
-  /// @return the statement that encloses this statement
-  const IfStatement* Parent() const {
-    return static_cast<const IfStatement*>(Statement::Parent());
-  }
+    /// Sets the if-statement condition expression
+    /// @param condition the if condition expression
+    void SetCondition(const Expression* condition) { condition_ = condition; }
 
-  /// Sets the else-statement condition expression
-  /// @param condition the else condition expression
-  void SetCondition(const Expression* condition) { condition_ = condition; }
-
- private:
-  const Expression* condition_ = nullptr;
+  private:
+    const Expression* condition_ = nullptr;
 };
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/info.h b/src/tint/sem/info.h
index 353f67f..66b2cd5 100644
--- a/src/tint/sem/info.h
+++ b/src/tint/sem/info.h
@@ -31,85 +31,83 @@
 
 /// Info holds all the resolved semantic information for a Program.
 class Info {
- public:
-  /// Placeholder type used by Get() to provide a default value for EXPLICIT_SEM
-  using InferFromAST = std::nullptr_t;
+  public:
+    /// Placeholder type used by Get() to provide a default value for EXPLICIT_SEM
+    using InferFromAST = std::nullptr_t;
 
-  /// Resolves to the return type of the Get() method given the desired sementic
-  /// type and AST type.
-  template <typename SEM, typename AST_OR_TYPE>
-  using GetResultType =
-      std::conditional_t<std::is_same<SEM, InferFromAST>::value,
-                         SemanticNodeTypeFor<AST_OR_TYPE>,
-                         SEM>;
+    /// Resolves to the return type of the Get() method given the desired sementic
+    /// type and AST type.
+    template <typename SEM, typename AST_OR_TYPE>
+    using GetResultType = std::conditional_t<std::is_same<SEM, InferFromAST>::value,
+                                             SemanticNodeTypeFor<AST_OR_TYPE>,
+                                             SEM>;
 
-  /// Constructor
-  Info();
+    /// Constructor
+    Info();
 
-  /// Move constructor
-  Info(Info&&);
+    /// Move constructor
+    Info(Info&&);
 
-  /// Destructor
-  ~Info();
+    /// Destructor
+    ~Info();
 
-  /// Move assignment operator
-  /// @param rhs the Program to move
-  /// @return this Program
-  Info& operator=(Info&& rhs);
+    /// Move assignment operator
+    /// @param rhs the Program to move
+    /// @return this Program
+    Info& operator=(Info&& rhs);
 
-  /// Get looks up the semantic information for the AST or type node `node`.
-  /// @param node the AST or type node
-  /// @returns a pointer to the semantic node if found, otherwise nullptr
-  template <typename SEM = InferFromAST,
-            typename AST_OR_TYPE = CastableBase,
-            typename RESULT = GetResultType<SEM, AST_OR_TYPE>>
-  const RESULT* Get(const AST_OR_TYPE* node) const {
-    auto it = map_.find(node);
-    if (it == map_.end()) {
-      return nullptr;
+    /// Get looks up the semantic information for the AST or type node `node`.
+    /// @param node the AST or type node
+    /// @returns a pointer to the semantic node if found, otherwise nullptr
+    template <typename SEM = InferFromAST,
+              typename AST_OR_TYPE = CastableBase,
+              typename RESULT = GetResultType<SEM, AST_OR_TYPE>>
+    const RESULT* Get(const AST_OR_TYPE* node) const {
+        auto it = map_.find(node);
+        if (it == map_.end()) {
+            return nullptr;
+        }
+        return As<RESULT>(it->second);
     }
-    return As<RESULT>(it->second);
-  }
 
-  /// Add registers the semantic node `sem_node` for the AST or type node
-  /// `node`.
-  /// @param node the AST or type node
-  /// @param sem_node the semantic node
-  template <typename AST_OR_TYPE>
-  void Add(const AST_OR_TYPE* node,
-           const SemanticNodeTypeFor<AST_OR_TYPE>* sem_node) {
-    // Check there's no semantic info already existing for the node
-    TINT_ASSERT(Semantic, Get(node) == nullptr);
-    map_.emplace(node, sem_node);
-  }
+    /// Add registers the semantic node `sem_node` for the AST or type node
+    /// `node`.
+    /// @param node the AST or type node
+    /// @param sem_node the semantic node
+    template <typename AST_OR_TYPE>
+    void Add(const AST_OR_TYPE* node, const SemanticNodeTypeFor<AST_OR_TYPE>* sem_node) {
+        // Check there's no semantic info already existing for the node
+        TINT_ASSERT(Semantic, Get(node) == nullptr);
+        map_.emplace(node, sem_node);
+    }
 
-  /// Wrap returns a new Info created with the contents of `inner`.
-  /// The Info returned by Wrap is intended to temporarily extend the contents
-  /// of an existing immutable Info.
-  /// As the copied contents are owned by `inner`, `inner` must not be
-  /// destructed or assigned while using the returned Info.
-  /// @param inner the immutable Info to extend
-  /// @return the Info that wraps `inner`
-  static Info Wrap(const Info& inner) {
-    Info out;
-    out.map_ = inner.map_;
-    out.module_ = inner.module_;
-    return out;
-  }
+    /// Wrap returns a new Info created with the contents of `inner`.
+    /// The Info returned by Wrap is intended to temporarily extend the contents
+    /// of an existing immutable Info.
+    /// As the copied contents are owned by `inner`, `inner` must not be
+    /// destructed or assigned while using the returned Info.
+    /// @param inner the immutable Info to extend
+    /// @return the Info that wraps `inner`
+    static Info Wrap(const Info& inner) {
+        Info out;
+        out.map_ = inner.map_;
+        out.module_ = inner.module_;
+        return out;
+    }
 
-  /// Assigns the semantic module.
-  /// @param module the module to assign.
-  void SetModule(sem::Module* module) { module_ = module; }
+    /// Assigns the semantic module.
+    /// @param module the module to assign.
+    void SetModule(sem::Module* module) { module_ = module; }
 
-  /// @returns the semantic module.
-  const sem::Module* Module() const { return module_; }
+    /// @returns the semantic module.
+    const sem::Module* Module() const { return module_; }
 
- private:
-  // TODO(crbug.com/tint/724): Once finished, this map should be:
-  // std::unordered_map<const ast::Node*, const sem::Node*>
-  std::unordered_map<const CastableBase*, const CastableBase*> map_;
-  // The semantic module
-  sem::Module* module_ = nullptr;
+  private:
+    // TODO(crbug.com/tint/724): Once finished, this map should be:
+    // std::unordered_map<const ast::Node*, const sem::Node*>
+    std::unordered_map<const CastableBase*, const CastableBase*> map_;
+    // The semantic module
+    sem::Module* module_ = nullptr;
 };
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/loop_statement.cc b/src/tint/sem/loop_statement.cc
index a26bf9e..eee735c 100644
--- a/src/tint/sem/loop_statement.cc
+++ b/src/tint/sem/loop_statement.cc
@@ -25,19 +25,18 @@
                              const CompoundStatement* parent,
                              const sem::Function* function)
     : Base(declaration, parent, function) {
-  TINT_ASSERT(Semantic, parent);
-  TINT_ASSERT(Semantic, function);
+    TINT_ASSERT(Semantic, parent);
+    TINT_ASSERT(Semantic, function);
 }
 
 LoopStatement::~LoopStatement() = default;
 
-LoopContinuingBlockStatement::LoopContinuingBlockStatement(
-    const ast::BlockStatement* declaration,
-    const CompoundStatement* parent,
-    const sem::Function* function)
+LoopContinuingBlockStatement::LoopContinuingBlockStatement(const ast::BlockStatement* declaration,
+                                                           const CompoundStatement* parent,
+                                                           const sem::Function* function)
     : Base(declaration, parent, function) {
-  TINT_ASSERT(Semantic, parent);
-  TINT_ASSERT(Semantic, function);
+    TINT_ASSERT(Semantic, parent);
+    TINT_ASSERT(Semantic, function);
 }
 LoopContinuingBlockStatement::~LoopContinuingBlockStatement() = default;
 
diff --git a/src/tint/sem/loop_statement.h b/src/tint/sem/loop_statement.h
index ccf3be0..502fa7c 100644
--- a/src/tint/sem/loop_statement.h
+++ b/src/tint/sem/loop_statement.h
@@ -26,33 +26,33 @@
 
 /// Holds semantic information about a loop statement
 class LoopStatement final : public Castable<LoopStatement, CompoundStatement> {
- public:
-  /// Constructor
-  /// @param declaration the AST node for this loop statement
-  /// @param parent the owning statement
-  /// @param function the owning function
-  LoopStatement(const ast::LoopStatement* declaration,
-                const CompoundStatement* parent,
-                const sem::Function* function);
+  public:
+    /// Constructor
+    /// @param declaration the AST node for this loop statement
+    /// @param parent the owning statement
+    /// @param function the owning function
+    LoopStatement(const ast::LoopStatement* declaration,
+                  const CompoundStatement* parent,
+                  const sem::Function* function);
 
-  /// Destructor
-  ~LoopStatement() override;
+    /// Destructor
+    ~LoopStatement() override;
 };
 
 /// Holds semantic information about a loop continuing block
 class LoopContinuingBlockStatement final
     : public Castable<LoopContinuingBlockStatement, BlockStatement> {
- public:
-  /// Constructor
-  /// @param declaration the AST node for this block statement
-  /// @param parent the owning statement
-  /// @param function the owning function
-  LoopContinuingBlockStatement(const ast::BlockStatement* declaration,
-                               const CompoundStatement* parent,
-                               const sem::Function* function);
+  public:
+    /// Constructor
+    /// @param declaration the AST node for this block statement
+    /// @param parent the owning statement
+    /// @param function the owning function
+    LoopContinuingBlockStatement(const ast::BlockStatement* declaration,
+                                 const CompoundStatement* parent,
+                                 const sem::Function* function);
 
-  /// Destructor
-  ~LoopContinuingBlockStatement() override;
+    /// Destructor
+    ~LoopContinuingBlockStatement() override;
 };
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/matrix_type.cc b/src/tint/sem/matrix.cc
similarity index 64%
rename from src/tint/sem/matrix_type.cc
rename to src/tint/sem/matrix.cc
index cfd9c1c..7f0383b 100644
--- a/src/tint/sem/matrix_type.cc
+++ b/src/tint/sem/matrix.cc
@@ -12,10 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/sem/matrix_type.h"
+#include "src/tint/sem/matrix.h"
 
 #include "src/tint/program_builder.h"
-#include "src/tint/sem/vector_type.h"
+#include "src/tint/sem/vector.h"
 #include "src/tint/utils/hash.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::sem::Matrix);
@@ -27,10 +27,10 @@
       column_type_(column_type),
       rows_(column_type->Width()),
       columns_(columns) {
-  TINT_ASSERT(AST, rows_ > 1);
-  TINT_ASSERT(AST, rows_ < 5);
-  TINT_ASSERT(AST, columns_ > 1);
-  TINT_ASSERT(AST, columns_ < 5);
+    TINT_ASSERT(AST, rows_ > 1);
+    TINT_ASSERT(AST, rows_ < 5);
+    TINT_ASSERT(AST, columns_ > 1);
+    TINT_ASSERT(AST, columns_ < 5);
 }
 
 Matrix::Matrix(Matrix&&) = default;
@@ -38,39 +38,36 @@
 Matrix::~Matrix() = default;
 
 size_t Matrix::Hash() const {
-  return utils::Hash(TypeInfo::Of<Vector>().full_hashcode, rows_, columns_,
-                     column_type_);
+    return utils::Hash(TypeInfo::Of<Vector>().full_hashcode, rows_, columns_, column_type_);
 }
 
 bool Matrix::Equals(const Type& other) const {
-  if (auto* v = other.As<Matrix>()) {
-    return v->rows_ == rows_ && v->columns_ == columns_ &&
-           v->column_type_ == column_type_;
-  }
-  return false;
+    if (auto* v = other.As<Matrix>()) {
+        return v->rows_ == rows_ && v->columns_ == columns_ && v->column_type_ == column_type_;
+    }
+    return false;
 }
 
 std::string Matrix::FriendlyName(const SymbolTable& symbols) const {
-  std::ostringstream out;
-  out << "mat" << columns_ << "x" << rows_ << "<"
-      << subtype_->FriendlyName(symbols) << ">";
-  return out.str();
+    std::ostringstream out;
+    out << "mat" << columns_ << "x" << rows_ << "<" << subtype_->FriendlyName(symbols) << ">";
+    return out.str();
 }
 
 bool Matrix::IsConstructible() const {
-  return true;
+    return true;
 }
 
 uint32_t Matrix::Size() const {
-  return column_type_->Align() * columns();
+    return column_type_->Align() * columns();
 }
 
 uint32_t Matrix::Align() const {
-  return column_type_->Align();
+    return column_type_->Align();
 }
 
 uint32_t Matrix::ColumnStride() const {
-  return column_type_->Align();
+    return column_type_->Align();
 }
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/matrix.h b/src/tint/sem/matrix.h
new file mode 100644
index 0000000..0321c4b
--- /dev/null
+++ b/src/tint/sem/matrix.h
@@ -0,0 +1,85 @@
+// 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_SEM_MATRIX_H_
+#define SRC_TINT_SEM_MATRIX_H_
+
+#include <string>
+
+#include "src/tint/sem/type.h"
+
+// Forward declarations
+namespace tint::sem {
+class Vector;
+}  // namespace tint::sem
+
+namespace tint::sem {
+
+/// A matrix type
+class Matrix final : public Castable<Matrix, Type> {
+  public:
+    /// Constructor
+    /// @param column_type the type of a column of the matrix
+    /// @param columns the number of columns in the matrix
+    Matrix(const Vector* column_type, uint32_t columns);
+    /// Move constructor
+    Matrix(Matrix&&);
+    ~Matrix() override;
+
+    /// @returns a hash of the type.
+    size_t Hash() const override;
+
+    /// @param other the other type to compare against
+    /// @returns true if the this type is equal to the given type
+    bool Equals(const Type& other) const override;
+
+    /// @returns the type of the matrix
+    const Type* type() const { return subtype_; }
+    /// @returns the number of rows in the matrix
+    uint32_t rows() const { return rows_; }
+    /// @returns the number of columns in the matrix
+    uint32_t columns() const { return columns_; }
+
+    /// @returns the column-vector type of the matrix
+    const Vector* ColumnType() const { return column_type_; }
+
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type that closely resembles how it would be
+    /// declared in WGSL.
+    std::string FriendlyName(const SymbolTable& symbols) const override;
+
+    /// @returns true if constructible as per
+    /// https://gpuweb.github.io/gpuweb/wgsl/#constructible-types
+    bool IsConstructible() const override;
+
+    /// @returns the size in bytes of the type. This may include tail padding.
+    uint32_t Size() const override;
+
+    /// @returns the alignment in bytes of the type. This may include tail
+    /// padding.
+    uint32_t Align() const override;
+
+    /// @returns the number of bytes between columns of the matrix
+    uint32_t ColumnStride() const;
+
+  private:
+    const Type* const subtype_;
+    const Vector* const column_type_;
+    const uint32_t rows_;
+    const uint32_t columns_;
+};
+
+}  // namespace tint::sem
+
+#endif  // SRC_TINT_SEM_MATRIX_H_
diff --git a/src/tint/sem/matrix_test.cc b/src/tint/sem/matrix_test.cc
new file mode 100644
index 0000000..a82a2d2
--- /dev/null
+++ b/src/tint/sem/matrix_test.cc
@@ -0,0 +1,75 @@
+// 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/sem/test_helper.h"
+#include "src/tint/sem/texture.h"
+
+namespace tint::sem {
+namespace {
+
+using MatrixTest = TestHelper;
+
+TEST_F(MatrixTest, Creation) {
+    auto* a = create<Matrix>(create<Vector>(create<I32>(), 3u), 4u);
+    auto* b = create<Matrix>(create<Vector>(create<I32>(), 3u), 4u);
+    auto* c = create<Matrix>(create<Vector>(create<F32>(), 3u), 4u);
+    auto* d = create<Matrix>(create<Vector>(create<I32>(), 2u), 4u);
+    auto* e = create<Matrix>(create<Vector>(create<I32>(), 3u), 2u);
+
+    EXPECT_EQ(a->type(), create<I32>());
+    EXPECT_EQ(a->rows(), 3u);
+    EXPECT_EQ(a->columns(), 4u);
+
+    EXPECT_EQ(a, b);
+    EXPECT_NE(a, c);
+    EXPECT_NE(a, d);
+    EXPECT_NE(a, e);
+}
+
+TEST_F(MatrixTest, Hash) {
+    auto* a = create<Matrix>(create<Vector>(create<I32>(), 3u), 4u);
+    auto* b = create<Matrix>(create<Vector>(create<I32>(), 3u), 4u);
+    auto* c = create<Matrix>(create<Vector>(create<F32>(), 3u), 4u);
+    auto* d = create<Matrix>(create<Vector>(create<I32>(), 2u), 4u);
+    auto* e = create<Matrix>(create<Vector>(create<I32>(), 3u), 2u);
+
+    EXPECT_EQ(a->Hash(), b->Hash());
+    EXPECT_NE(a->Hash(), c->Hash());
+    EXPECT_NE(a->Hash(), d->Hash());
+    EXPECT_NE(a->Hash(), e->Hash());
+}
+
+TEST_F(MatrixTest, Equals) {
+    auto* a = create<Matrix>(create<Vector>(create<I32>(), 3u), 4u);
+    auto* b = create<Matrix>(create<Vector>(create<I32>(), 3u), 4u);
+    auto* c = create<Matrix>(create<Vector>(create<F32>(), 3u), 4u);
+    auto* d = create<Matrix>(create<Vector>(create<I32>(), 2u), 4u);
+    auto* e = create<Matrix>(create<Vector>(create<I32>(), 3u), 2u);
+
+    EXPECT_TRUE(a->Equals(*b));
+    EXPECT_FALSE(a->Equals(*c));
+    EXPECT_FALSE(a->Equals(*d));
+    EXPECT_FALSE(a->Equals(*e));
+    EXPECT_FALSE(a->Equals(Void{}));
+}
+
+TEST_F(MatrixTest, FriendlyName) {
+    I32 i32;
+    Vector c{&i32, 3};
+    Matrix m{&c, 2};
+    EXPECT_EQ(m.FriendlyName(Symbols()), "mat2x3<i32>");
+}
+
+}  // namespace
+}  // namespace tint::sem
diff --git a/src/tint/sem/matrix_type.h b/src/tint/sem/matrix_type.h
deleted file mode 100644
index b5b9669..0000000
--- a/src/tint/sem/matrix_type.h
+++ /dev/null
@@ -1,85 +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_SEM_MATRIX_TYPE_H_
-#define SRC_TINT_SEM_MATRIX_TYPE_H_
-
-#include <string>
-
-#include "src/tint/sem/type.h"
-
-// Forward declarations
-namespace tint::sem {
-class Vector;
-}  // namespace tint::sem
-
-namespace tint::sem {
-
-/// A matrix type
-class Matrix final : public Castable<Matrix, Type> {
- public:
-  /// Constructor
-  /// @param column_type the type of a column of the matrix
-  /// @param columns the number of columns in the matrix
-  Matrix(const Vector* column_type, uint32_t columns);
-  /// Move constructor
-  Matrix(Matrix&&);
-  ~Matrix() override;
-
-  /// @returns a hash of the type.
-  size_t Hash() const override;
-
-  /// @param other the other type to compare against
-  /// @returns true if the this type is equal to the given type
-  bool Equals(const Type& other) const override;
-
-  /// @returns the type of the matrix
-  const Type* type() const { return subtype_; }
-  /// @returns the number of rows in the matrix
-  uint32_t rows() const { return rows_; }
-  /// @returns the number of columns in the matrix
-  uint32_t columns() const { return columns_; }
-
-  /// @returns the column-vector type of the matrix
-  const Vector* ColumnType() const { return column_type_; }
-
-  /// @param symbols the program's symbol table
-  /// @returns the name for this type that closely resembles how it would be
-  /// declared in WGSL.
-  std::string FriendlyName(const SymbolTable& symbols) const override;
-
-  /// @returns true if constructible as per
-  /// https://gpuweb.github.io/gpuweb/wgsl/#constructible-types
-  bool IsConstructible() const override;
-
-  /// @returns the size in bytes of the type. This may include tail padding.
-  uint32_t Size() const override;
-
-  /// @returns the alignment in bytes of the type. This may include tail
-  /// padding.
-  uint32_t Align() const override;
-
-  /// @returns the number of bytes between columns of the matrix
-  uint32_t ColumnStride() const;
-
- private:
-  const Type* const subtype_;
-  const Vector* const column_type_;
-  const uint32_t rows_;
-  const uint32_t columns_;
-};
-
-}  // namespace tint::sem
-
-#endif  // SRC_TINT_SEM_MATRIX_TYPE_H_
diff --git a/src/tint/sem/matrix_type_test.cc b/src/tint/sem/matrix_type_test.cc
deleted file mode 100644
index 52ae36b..0000000
--- a/src/tint/sem/matrix_type_test.cc
+++ /dev/null
@@ -1,75 +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/sem/test_helper.h"
-#include "src/tint/sem/texture_type.h"
-
-namespace tint::sem {
-namespace {
-
-using MatrixTest = TestHelper;
-
-TEST_F(MatrixTest, Creation) {
-  auto* a = create<Matrix>(create<Vector>(create<I32>(), 3u), 4u);
-  auto* b = create<Matrix>(create<Vector>(create<I32>(), 3u), 4u);
-  auto* c = create<Matrix>(create<Vector>(create<F32>(), 3u), 4u);
-  auto* d = create<Matrix>(create<Vector>(create<I32>(), 2u), 4u);
-  auto* e = create<Matrix>(create<Vector>(create<I32>(), 3u), 2u);
-
-  EXPECT_EQ(a->type(), create<I32>());
-  EXPECT_EQ(a->rows(), 3u);
-  EXPECT_EQ(a->columns(), 4u);
-
-  EXPECT_EQ(a, b);
-  EXPECT_NE(a, c);
-  EXPECT_NE(a, d);
-  EXPECT_NE(a, e);
-}
-
-TEST_F(MatrixTest, Hash) {
-  auto* a = create<Matrix>(create<Vector>(create<I32>(), 3u), 4u);
-  auto* b = create<Matrix>(create<Vector>(create<I32>(), 3u), 4u);
-  auto* c = create<Matrix>(create<Vector>(create<F32>(), 3u), 4u);
-  auto* d = create<Matrix>(create<Vector>(create<I32>(), 2u), 4u);
-  auto* e = create<Matrix>(create<Vector>(create<I32>(), 3u), 2u);
-
-  EXPECT_EQ(a->Hash(), b->Hash());
-  EXPECT_NE(a->Hash(), c->Hash());
-  EXPECT_NE(a->Hash(), d->Hash());
-  EXPECT_NE(a->Hash(), e->Hash());
-}
-
-TEST_F(MatrixTest, Equals) {
-  auto* a = create<Matrix>(create<Vector>(create<I32>(), 3u), 4u);
-  auto* b = create<Matrix>(create<Vector>(create<I32>(), 3u), 4u);
-  auto* c = create<Matrix>(create<Vector>(create<F32>(), 3u), 4u);
-  auto* d = create<Matrix>(create<Vector>(create<I32>(), 2u), 4u);
-  auto* e = create<Matrix>(create<Vector>(create<I32>(), 3u), 2u);
-
-  EXPECT_TRUE(a->Equals(*b));
-  EXPECT_FALSE(a->Equals(*c));
-  EXPECT_FALSE(a->Equals(*d));
-  EXPECT_FALSE(a->Equals(*e));
-  EXPECT_FALSE(a->Equals(Void{}));
-}
-
-TEST_F(MatrixTest, FriendlyName) {
-  I32 i32;
-  Vector c{&i32, 3};
-  Matrix m{&c, 2};
-  EXPECT_EQ(m.FriendlyName(Symbols()), "mat2x3<i32>");
-}
-
-}  // namespace
-}  // namespace tint::sem
diff --git a/src/tint/sem/member_accessor_expression.cc b/src/tint/sem/member_accessor_expression.cc
index 4e04ab4..9dcca76 100644
--- a/src/tint/sem/member_accessor_expression.cc
+++ b/src/tint/sem/member_accessor_expression.cc
@@ -23,22 +23,22 @@
 
 namespace tint::sem {
 
-MemberAccessorExpression::MemberAccessorExpression(
-    const ast::MemberAccessorExpression* declaration,
-    const sem::Type* type,
-    const Statement* statement,
-    bool has_side_effects)
-    : Base(declaration, type, statement, Constant{}, has_side_effects) {}
+MemberAccessorExpression::MemberAccessorExpression(const ast::MemberAccessorExpression* declaration,
+                                                   const sem::Type* type,
+                                                   const Statement* statement,
+                                                   bool has_side_effects,
+                                                   const Variable* source_var /* = nullptr */)
+    : Base(declaration, type, statement, Constant{}, has_side_effects, source_var) {}
 
 MemberAccessorExpression::~MemberAccessorExpression() = default;
 
-StructMemberAccess::StructMemberAccess(
-    const ast::MemberAccessorExpression* declaration,
-    const sem::Type* type,
-    const Statement* statement,
-    const StructMember* member,
-    bool has_side_effects)
-    : Base(declaration, type, statement, has_side_effects), member_(member) {}
+StructMemberAccess::StructMemberAccess(const ast::MemberAccessorExpression* declaration,
+                                       const sem::Type* type,
+                                       const Statement* statement,
+                                       const StructMember* member,
+                                       bool has_side_effects,
+                                       const Variable* source_var /* = nullptr */)
+    : Base(declaration, type, statement, has_side_effects, source_var), member_(member) {}
 
 StructMemberAccess::~StructMemberAccess() = default;
 
@@ -46,8 +46,9 @@
                  const sem::Type* type,
                  const Statement* statement,
                  std::vector<uint32_t> indices,
-                 bool has_side_effects)
-    : Base(declaration, type, statement, has_side_effects),
+                 bool has_side_effects,
+                 const Variable* source_var /* = nullptr */)
+    : Base(declaration, type, statement, has_side_effects, source_var),
       indices_(std::move(indices)) {}
 
 Swizzle::~Swizzle() = default;
diff --git a/src/tint/sem/member_accessor_expression.h b/src/tint/sem/member_accessor_expression.h
index 342acbe..0233541 100644
--- a/src/tint/sem/member_accessor_expression.h
+++ b/src/tint/sem/member_accessor_expression.h
@@ -32,75 +32,79 @@
 
 /// MemberAccessorExpression holds the semantic information for a
 /// ast::MemberAccessorExpression node.
-class MemberAccessorExpression
-    : public Castable<MemberAccessorExpression, Expression> {
- public:
-  /// Constructor
-  /// @param declaration the AST node
-  /// @param type the resolved type of the expression
-  /// @param statement the statement that owns this expression
-  /// @param has_side_effects whether this expression may have side effects
-  MemberAccessorExpression(const ast::MemberAccessorExpression* declaration,
-                           const sem::Type* type,
-                           const Statement* statement,
-                           bool has_side_effects);
+class MemberAccessorExpression : public Castable<MemberAccessorExpression, Expression> {
+  public:
+    /// Constructor
+    /// @param declaration the AST node
+    /// @param type the resolved type of the expression
+    /// @param statement the statement that owns this expression
+    /// @param has_side_effects whether this expression may have side effects
+    /// @param source_var the (optional) source variable for this expression
+    MemberAccessorExpression(const ast::MemberAccessorExpression* declaration,
+                             const sem::Type* type,
+                             const Statement* statement,
+                             bool has_side_effects,
+                             const Variable* source_var = nullptr);
 
-  /// Destructor
-  ~MemberAccessorExpression() override;
+    /// Destructor
+    ~MemberAccessorExpression() override;
 };
 
 /// StructMemberAccess holds the semantic information for a
 /// ast::MemberAccessorExpression node that represents an access to a structure
 /// member.
-class StructMemberAccess final
-    : public Castable<StructMemberAccess, MemberAccessorExpression> {
- public:
-  /// Constructor
-  /// @param declaration the AST node
-  /// @param type the resolved type of the expression
-  /// @param statement the statement that owns this expression
-  /// @param member the structure member
-  /// @param has_side_effects whether this expression may have side effects
-  StructMemberAccess(const ast::MemberAccessorExpression* declaration,
-                     const sem::Type* type,
-                     const Statement* statement,
-                     const StructMember* member,
-                     bool has_side_effects);
+class StructMemberAccess final : public Castable<StructMemberAccess, MemberAccessorExpression> {
+  public:
+    /// Constructor
+    /// @param declaration the AST node
+    /// @param type the resolved type of the expression
+    /// @param statement the statement that owns this expression
+    /// @param member the structure member
+    /// @param has_side_effects whether this expression may have side effects
+    /// @param source_var the (optional) source variable for this expression
+    StructMemberAccess(const ast::MemberAccessorExpression* declaration,
+                       const sem::Type* type,
+                       const Statement* statement,
+                       const StructMember* member,
+                       bool has_side_effects,
+                       const Variable* source_var = nullptr);
 
-  /// Destructor
-  ~StructMemberAccess() override;
+    /// Destructor
+    ~StructMemberAccess() override;
 
-  /// @returns the structure member
-  StructMember const* Member() const { return member_; }
+    /// @returns the structure member
+    StructMember const* Member() const { return member_; }
 
- private:
-  StructMember const* const member_;
+  private:
+    StructMember const* const member_;
 };
 
 /// Swizzle holds the semantic information for a ast::MemberAccessorExpression
 /// node that represents a vector swizzle.
 class Swizzle final : public Castable<Swizzle, MemberAccessorExpression> {
- public:
-  /// Constructor
-  /// @param declaration the AST node
-  /// @param type the resolved type of the expression
-  /// @param statement the statement that owns this expression
-  /// @param indices the swizzle indices
-  /// @param has_side_effects whether this expression may have side effects
-  Swizzle(const ast::MemberAccessorExpression* declaration,
-          const sem::Type* type,
-          const Statement* statement,
-          std::vector<uint32_t> indices,
-          bool has_side_effects);
+  public:
+    /// Constructor
+    /// @param declaration the AST node
+    /// @param type the resolved type of the expression
+    /// @param statement the statement that owns this expression
+    /// @param indices the swizzle indices
+    /// @param has_side_effects whether this expression may have side effects
+    /// @param source_var the (optional) source variable for this expression
+    Swizzle(const ast::MemberAccessorExpression* declaration,
+            const sem::Type* type,
+            const Statement* statement,
+            std::vector<uint32_t> indices,
+            bool has_side_effects,
+            const Variable* source_var = nullptr);
 
-  /// Destructor
-  ~Swizzle() override;
+    /// Destructor
+    ~Swizzle() override;
 
-  /// @return the swizzle indices, if this is a vector swizzle
-  const std::vector<uint32_t>& Indices() const { return indices_; }
+    /// @return the swizzle indices, if this is a vector swizzle
+    const std::vector<uint32_t>& Indices() const { return indices_; }
 
- private:
-  std::vector<uint32_t> const indices_;
+  private:
+    std::vector<uint32_t> const indices_;
 };
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/module.h b/src/tint/sem/module.h
index 1077b7e..c265d4e 100644
--- a/src/tint/sem/module.h
+++ b/src/tint/sem/module.h
@@ -30,21 +30,21 @@
 /// Module holds the top-level semantic types, functions and global variables
 /// used by a Program.
 class Module final : public Castable<Module, Node> {
- public:
-  /// Constructor
-  /// @param dep_ordered_decls the dependency-ordered module-scope declarations
-  explicit Module(std::vector<const ast::Node*> dep_ordered_decls);
+  public:
+    /// Constructor
+    /// @param dep_ordered_decls the dependency-ordered module-scope declarations
+    explicit Module(std::vector<const ast::Node*> dep_ordered_decls);
 
-  /// Destructor
-  ~Module() override;
+    /// Destructor
+    ~Module() override;
 
-  /// @returns the dependency-ordered global declarations for the module
-  const std::vector<const ast::Node*>& DependencyOrderedDeclarations() const {
-    return dep_ordered_decls_;
-  }
+    /// @returns the dependency-ordered global declarations for the module
+    const std::vector<const ast::Node*>& DependencyOrderedDeclarations() const {
+        return dep_ordered_decls_;
+    }
 
- private:
-  const std::vector<const ast::Node*> dep_ordered_decls_;
+  private:
+    const std::vector<const ast::Node*> dep_ordered_decls_;
 };
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/multisampled_texture_type.cc b/src/tint/sem/multisampled_texture.cc
similarity index 64%
rename from src/tint/sem/multisampled_texture_type.cc
rename to src/tint/sem/multisampled_texture.cc
index 72ce2f5..922b967 100644
--- a/src/tint/sem/multisampled_texture_type.cc
+++ b/src/tint/sem/multisampled_texture.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/sem/multisampled_texture_type.h"
+#include "src/tint/sem/multisampled_texture.h"
 
 #include "src/tint/program_builder.h"
 #include "src/tint/utils/hash.h"
@@ -21,10 +21,9 @@
 
 namespace tint::sem {
 
-MultisampledTexture::MultisampledTexture(ast::TextureDimension dim,
-                                         const Type* type)
+MultisampledTexture::MultisampledTexture(ast::TextureDimension dim, const Type* type)
     : Base(dim), type_(type) {
-  TINT_ASSERT(Semantic, type_);
+    TINT_ASSERT(Semantic, type_);
 }
 
 MultisampledTexture::MultisampledTexture(MultisampledTexture&&) = default;
@@ -32,23 +31,20 @@
 MultisampledTexture::~MultisampledTexture() = default;
 
 size_t MultisampledTexture::Hash() const {
-  return utils::Hash(TypeInfo::Of<MultisampledTexture>().full_hashcode, dim(),
-                     type_);
+    return utils::Hash(TypeInfo::Of<MultisampledTexture>().full_hashcode, dim(), type_);
 }
 
 bool MultisampledTexture::Equals(const sem::Type& other) const {
-  if (auto* o = other.As<MultisampledTexture>()) {
-    return o->dim() == dim() && o->type_ == type_;
-  }
-  return false;
+    if (auto* o = other.As<MultisampledTexture>()) {
+        return o->dim() == dim() && o->type_ == type_;
+    }
+    return false;
 }
 
-std::string MultisampledTexture::FriendlyName(
-    const SymbolTable& symbols) const {
-  std::ostringstream out;
-  out << "texture_multisampled_" << dim() << "<" << type_->FriendlyName(symbols)
-      << ">";
-  return out.str();
+std::string MultisampledTexture::FriendlyName(const SymbolTable& symbols) const {
+    std::ostringstream out;
+    out << "texture_multisampled_" << dim() << "<" << type_->FriendlyName(symbols) << ">";
+    return out.str();
 }
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/multisampled_texture.h b/src/tint/sem/multisampled_texture.h
new file mode 100644
index 0000000..f178056
--- /dev/null
+++ b/src/tint/sem/multisampled_texture.h
@@ -0,0 +1,56 @@
+// 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_SEM_MULTISAMPLED_TEXTURE_H_
+#define SRC_TINT_SEM_MULTISAMPLED_TEXTURE_H_
+
+#include <string>
+
+#include "src/tint/sem/texture.h"
+
+namespace tint::sem {
+
+/// A multisampled texture type.
+class MultisampledTexture final : public Castable<MultisampledTexture, Texture> {
+  public:
+    /// Constructor
+    /// @param dim the dimensionality of the texture
+    /// @param type the data type of the multisampled texture
+    MultisampledTexture(ast::TextureDimension dim, const Type* type);
+    /// Move constructor
+    MultisampledTexture(MultisampledTexture&&);
+    ~MultisampledTexture() override;
+
+    /// @returns a hash of the type.
+    size_t Hash() const override;
+
+    /// @param other the other type to compare against
+    /// @returns true if the this type is equal to the given type
+    bool Equals(const Type& other) const override;
+
+    /// @returns the subtype of the sampled texture
+    const Type* type() const { return type_; }
+
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type that closely resembles how it would be
+    /// declared in WGSL.
+    std::string FriendlyName(const SymbolTable& symbols) const override;
+
+  private:
+    const Type* const type_;
+};
+
+}  // namespace tint::sem
+
+#endif  // SRC_TINT_SEM_MULTISAMPLED_TEXTURE_H_
diff --git a/src/tint/sem/multisampled_texture_test.cc b/src/tint/sem/multisampled_texture_test.cc
new file mode 100644
index 0000000..3243a5f
--- /dev/null
+++ b/src/tint/sem/multisampled_texture_test.cc
@@ -0,0 +1,89 @@
+// 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/sem/multisampled_texture.h"
+
+#include "src/tint/sem/depth_texture.h"
+#include "src/tint/sem/external_texture.h"
+#include "src/tint/sem/sampled_texture.h"
+#include "src/tint/sem/storage_texture.h"
+#include "src/tint/sem/test_helper.h"
+
+namespace tint::sem {
+namespace {
+
+using MultisampledTextureTest = TestHelper;
+
+TEST_F(MultisampledTextureTest, Creation) {
+    auto* a = create<MultisampledTexture>(ast::TextureDimension::k2d, create<F32>());
+    auto* b = create<MultisampledTexture>(ast::TextureDimension::k2d, create<F32>());
+    auto* c = create<MultisampledTexture>(ast::TextureDimension::k3d, create<F32>());
+    auto* d = create<MultisampledTexture>(ast::TextureDimension::k2d, create<I32>());
+    EXPECT_EQ(a, b);
+    EXPECT_NE(a, c);
+    EXPECT_NE(a, d);
+}
+
+TEST_F(MultisampledTextureTest, Hash) {
+    auto* a = create<MultisampledTexture>(ast::TextureDimension::k2d, create<F32>());
+    auto* b = create<MultisampledTexture>(ast::TextureDimension::k2d, create<F32>());
+    auto* c = create<MultisampledTexture>(ast::TextureDimension::k3d, create<F32>());
+    auto* d = create<MultisampledTexture>(ast::TextureDimension::k2d, create<I32>());
+    EXPECT_EQ(a->Hash(), b->Hash());
+    EXPECT_NE(a->Hash(), c->Hash());
+    EXPECT_NE(a->Hash(), d->Hash());
+}
+
+TEST_F(MultisampledTextureTest, Equals) {
+    auto* a = create<MultisampledTexture>(ast::TextureDimension::k2d, create<F32>());
+    auto* b = create<MultisampledTexture>(ast::TextureDimension::k2d, create<F32>());
+    auto* c = create<MultisampledTexture>(ast::TextureDimension::k3d, create<F32>());
+    auto* d = create<MultisampledTexture>(ast::TextureDimension::k2d, create<I32>());
+    EXPECT_TRUE(a->Equals(*b));
+    EXPECT_FALSE(a->Equals(*c));
+    EXPECT_FALSE(a->Equals(*d));
+    EXPECT_FALSE(a->Equals(Void{}));
+}
+
+TEST_F(MultisampledTextureTest, IsTexture) {
+    F32 f32;
+    MultisampledTexture s(ast::TextureDimension::kCube, &f32);
+    Texture* ty = &s;
+    EXPECT_FALSE(ty->Is<DepthTexture>());
+    EXPECT_FALSE(ty->Is<ExternalTexture>());
+    EXPECT_TRUE(ty->Is<MultisampledTexture>());
+    EXPECT_FALSE(ty->Is<SampledTexture>());
+    EXPECT_FALSE(ty->Is<StorageTexture>());
+}
+
+TEST_F(MultisampledTextureTest, Dim) {
+    F32 f32;
+    MultisampledTexture s(ast::TextureDimension::k3d, &f32);
+    EXPECT_EQ(s.dim(), ast::TextureDimension::k3d);
+}
+
+TEST_F(MultisampledTextureTest, Type) {
+    F32 f32;
+    MultisampledTexture s(ast::TextureDimension::k3d, &f32);
+    EXPECT_EQ(s.type(), &f32);
+}
+
+TEST_F(MultisampledTextureTest, FriendlyName) {
+    F32 f32;
+    MultisampledTexture s(ast::TextureDimension::k3d, &f32);
+    EXPECT_EQ(s.FriendlyName(Symbols()), "texture_multisampled_3d<f32>");
+}
+
+}  // namespace
+}  // namespace tint::sem
diff --git a/src/tint/sem/multisampled_texture_type.h b/src/tint/sem/multisampled_texture_type.h
deleted file mode 100644
index 0e993ec..0000000
--- a/src/tint/sem/multisampled_texture_type.h
+++ /dev/null
@@ -1,57 +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_SEM_MULTISAMPLED_TEXTURE_TYPE_H_
-#define SRC_TINT_SEM_MULTISAMPLED_TEXTURE_TYPE_H_
-
-#include <string>
-
-#include "src/tint/sem/texture_type.h"
-
-namespace tint::sem {
-
-/// A multisampled texture type.
-class MultisampledTexture final
-    : public Castable<MultisampledTexture, Texture> {
- public:
-  /// Constructor
-  /// @param dim the dimensionality of the texture
-  /// @param type the data type of the multisampled texture
-  MultisampledTexture(ast::TextureDimension dim, const Type* type);
-  /// Move constructor
-  MultisampledTexture(MultisampledTexture&&);
-  ~MultisampledTexture() override;
-
-  /// @returns a hash of the type.
-  size_t Hash() const override;
-
-  /// @param other the other type to compare against
-  /// @returns true if the this type is equal to the given type
-  bool Equals(const Type& other) const override;
-
-  /// @returns the subtype of the sampled texture
-  const Type* type() const { return type_; }
-
-  /// @param symbols the program's symbol table
-  /// @returns the name for this type that closely resembles how it would be
-  /// declared in WGSL.
-  std::string FriendlyName(const SymbolTable& symbols) const override;
-
- private:
-  const Type* const type_;
-};
-
-}  // namespace tint::sem
-
-#endif  // SRC_TINT_SEM_MULTISAMPLED_TEXTURE_TYPE_H_
diff --git a/src/tint/sem/multisampled_texture_type_test.cc b/src/tint/sem/multisampled_texture_type_test.cc
deleted file mode 100644
index eb53ccd..0000000
--- a/src/tint/sem/multisampled_texture_type_test.cc
+++ /dev/null
@@ -1,101 +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/sem/multisampled_texture_type.h"
-
-#include "src/tint/sem/depth_texture_type.h"
-#include "src/tint/sem/external_texture_type.h"
-#include "src/tint/sem/sampled_texture_type.h"
-#include "src/tint/sem/storage_texture_type.h"
-#include "src/tint/sem/test_helper.h"
-
-namespace tint::sem {
-namespace {
-
-using MultisampledTextureTest = TestHelper;
-
-TEST_F(MultisampledTextureTest, Creation) {
-  auto* a =
-      create<MultisampledTexture>(ast::TextureDimension::k2d, create<F32>());
-  auto* b =
-      create<MultisampledTexture>(ast::TextureDimension::k2d, create<F32>());
-  auto* c =
-      create<MultisampledTexture>(ast::TextureDimension::k3d, create<F32>());
-  auto* d =
-      create<MultisampledTexture>(ast::TextureDimension::k2d, create<I32>());
-  EXPECT_EQ(a, b);
-  EXPECT_NE(a, c);
-  EXPECT_NE(a, d);
-}
-
-TEST_F(MultisampledTextureTest, Hash) {
-  auto* a =
-      create<MultisampledTexture>(ast::TextureDimension::k2d, create<F32>());
-  auto* b =
-      create<MultisampledTexture>(ast::TextureDimension::k2d, create<F32>());
-  auto* c =
-      create<MultisampledTexture>(ast::TextureDimension::k3d, create<F32>());
-  auto* d =
-      create<MultisampledTexture>(ast::TextureDimension::k2d, create<I32>());
-  EXPECT_EQ(a->Hash(), b->Hash());
-  EXPECT_NE(a->Hash(), c->Hash());
-  EXPECT_NE(a->Hash(), d->Hash());
-}
-
-TEST_F(MultisampledTextureTest, Equals) {
-  auto* a =
-      create<MultisampledTexture>(ast::TextureDimension::k2d, create<F32>());
-  auto* b =
-      create<MultisampledTexture>(ast::TextureDimension::k2d, create<F32>());
-  auto* c =
-      create<MultisampledTexture>(ast::TextureDimension::k3d, create<F32>());
-  auto* d =
-      create<MultisampledTexture>(ast::TextureDimension::k2d, create<I32>());
-  EXPECT_TRUE(a->Equals(*b));
-  EXPECT_FALSE(a->Equals(*c));
-  EXPECT_FALSE(a->Equals(*d));
-  EXPECT_FALSE(a->Equals(Void{}));
-}
-
-TEST_F(MultisampledTextureTest, IsTexture) {
-  F32 f32;
-  MultisampledTexture s(ast::TextureDimension::kCube, &f32);
-  Texture* ty = &s;
-  EXPECT_FALSE(ty->Is<DepthTexture>());
-  EXPECT_FALSE(ty->Is<ExternalTexture>());
-  EXPECT_TRUE(ty->Is<MultisampledTexture>());
-  EXPECT_FALSE(ty->Is<SampledTexture>());
-  EXPECT_FALSE(ty->Is<StorageTexture>());
-}
-
-TEST_F(MultisampledTextureTest, Dim) {
-  F32 f32;
-  MultisampledTexture s(ast::TextureDimension::k3d, &f32);
-  EXPECT_EQ(s.dim(), ast::TextureDimension::k3d);
-}
-
-TEST_F(MultisampledTextureTest, Type) {
-  F32 f32;
-  MultisampledTexture s(ast::TextureDimension::k3d, &f32);
-  EXPECT_EQ(s.type(), &f32);
-}
-
-TEST_F(MultisampledTextureTest, FriendlyName) {
-  F32 f32;
-  MultisampledTexture s(ast::TextureDimension::k3d, &f32);
-  EXPECT_EQ(s.FriendlyName(Symbols()), "texture_multisampled_3d<f32>");
-}
-
-}  // namespace
-}  // namespace tint::sem
diff --git a/src/tint/sem/node.h b/src/tint/sem/node.h
index d03b042..3f2df55 100644
--- a/src/tint/sem/node.h
+++ b/src/tint/sem/node.h
@@ -21,15 +21,15 @@
 
 /// Node is the base class for all semantic nodes
 class Node : public Castable<Node> {
- public:
-  /// Constructor
-  Node();
+  public:
+    /// Constructor
+    Node();
 
-  /// Copy constructor
-  Node(const Node&);
+    /// Copy constructor
+    Node(const Node&);
 
-  /// Destructor
-  ~Node() override;
+    /// Destructor
+    ~Node() override;
 };
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/parameter_usage.cc b/src/tint/sem/parameter_usage.cc
index 3bea237..0eef789 100644
--- a/src/tint/sem/parameter_usage.cc
+++ b/src/tint/sem/parameter_usage.cc
@@ -27,37 +27,37 @@
 namespace tint::sem {
 
 const char* str(ParameterUsage usage) {
-  switch (usage) {
-    case ParameterUsage::kNone:
-      return "none";
-    case ParameterUsage::kArrayIndex:
-      return "array_index";
-    case ParameterUsage::kBias:
-      return "bias";
-    case ParameterUsage::kComponent:
-      return "component";
-    case ParameterUsage::kCoords:
-      return "coords";
-    case ParameterUsage::kDdx:
-      return "ddx";
-    case ParameterUsage::kDdy:
-      return "ddy";
-    case ParameterUsage::kDepthRef:
-      return "depth_ref";
-    case ParameterUsage::kLevel:
-      return "level";
-    case ParameterUsage::kOffset:
-      return "offset";
-    case ParameterUsage::kSampleIndex:
-      return "sample_index";
-    case ParameterUsage::kSampler:
-      return "sampler";
-    case ParameterUsage::kTexture:
-      return "texture";
-    case ParameterUsage::kValue:
-      return "value";
-  }
-  return "<unknown>";
+    switch (usage) {
+        case ParameterUsage::kNone:
+            return "none";
+        case ParameterUsage::kArrayIndex:
+            return "array_index";
+        case ParameterUsage::kBias:
+            return "bias";
+        case ParameterUsage::kComponent:
+            return "component";
+        case ParameterUsage::kCoords:
+            return "coords";
+        case ParameterUsage::kDdx:
+            return "ddx";
+        case ParameterUsage::kDdy:
+            return "ddy";
+        case ParameterUsage::kDepthRef:
+            return "depth_ref";
+        case ParameterUsage::kLevel:
+            return "level";
+        case ParameterUsage::kOffset:
+            return "offset";
+        case ParameterUsage::kSampleIndex:
+            return "sample_index";
+        case ParameterUsage::kSampler:
+            return "sampler";
+        case ParameterUsage::kTexture:
+            return "texture";
+        case ParameterUsage::kValue:
+            return "value";
+    }
+    return "<unknown>";
 }
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/parameter_usage.cc.tmpl b/src/tint/sem/parameter_usage.cc.tmpl
index 1339171..bb767d4 100644
--- a/src/tint/sem/parameter_usage.cc.tmpl
+++ b/src/tint/sem/parameter_usage.cc.tmpl
@@ -13,15 +13,15 @@
 namespace tint::sem {
 
 const char* str(ParameterUsage usage) {
-  switch (usage) {
-    case ParameterUsage::kNone:
-      return "none";
+    switch (usage) {
+        case ParameterUsage::kNone:
+            return "none";
 {{- range .Sem.UniqueParameterNames  }}
-    case ParameterUsage::k{{PascalCase .}}:
-      return "{{.}}";
+        case ParameterUsage::k{{PascalCase .}}:
+            return "{{.}}";
 {{- end  }}
-  }
-  return "<unknown>";
+    }
+    return "<unknown>";
 }
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/parameter_usage.h b/src/tint/sem/parameter_usage.h
index 56f6e78..d4e99c1 100644
--- a/src/tint/sem/parameter_usage.h
+++ b/src/tint/sem/parameter_usage.h
@@ -30,20 +30,20 @@
 /// ParameterUsage is extra metadata for identifying a parameter based on its
 /// overload position
 enum class ParameterUsage {
-  kNone = -1,
-  kArrayIndex,
-  kBias,
-  kComponent,
-  kCoords,
-  kDdx,
-  kDdy,
-  kDepthRef,
-  kLevel,
-  kOffset,
-  kSampleIndex,
-  kSampler,
-  kTexture,
-  kValue,
+    kNone = -1,
+    kArrayIndex,
+    kBias,
+    kComponent,
+    kCoords,
+    kDdx,
+    kDdy,
+    kDepthRef,
+    kLevel,
+    kOffset,
+    kSampleIndex,
+    kSampler,
+    kTexture,
+    kValue,
 };
 
 /// @returns a string representation of the given parameter usage.
diff --git a/src/tint/sem/parameter_usage.h.tmpl b/src/tint/sem/parameter_usage.h.tmpl
index 1edb674..f7a3c28 100644
--- a/src/tint/sem/parameter_usage.h.tmpl
+++ b/src/tint/sem/parameter_usage.h.tmpl
@@ -16,9 +16,9 @@
 /// ParameterUsage is extra metadata for identifying a parameter based on its
 /// overload position
 enum class ParameterUsage {
-  kNone = -1,
+    kNone = -1,
 {{- range .Sem.UniqueParameterNames  }}
-  k{{PascalCase .}},
+    k{{PascalCase .}},
 {{- end  }}
 };
 
diff --git a/src/tint/sem/pointer.cc b/src/tint/sem/pointer.cc
new file mode 100644
index 0000000..e00a4bf
--- /dev/null
+++ b/src/tint/sem/pointer.cc
@@ -0,0 +1,58 @@
+// 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/sem/pointer.h"
+
+#include "src/tint/program_builder.h"
+#include "src/tint/sem/reference.h"
+#include "src/tint/utils/hash.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::sem::Pointer);
+
+namespace tint::sem {
+
+Pointer::Pointer(const Type* subtype, ast::StorageClass storage_class, ast::Access access)
+    : subtype_(subtype), storage_class_(storage_class), access_(access) {
+    TINT_ASSERT(Semantic, !subtype->Is<Reference>());
+    TINT_ASSERT(Semantic, access != ast::Access::kUndefined);
+}
+
+size_t Pointer::Hash() const {
+    return utils::Hash(TypeInfo::Of<Pointer>().full_hashcode, storage_class_, subtype_, access_);
+}
+
+bool Pointer::Equals(const sem::Type& other) const {
+    if (auto* o = other.As<Pointer>()) {
+        return o->storage_class_ == storage_class_ && o->subtype_ == subtype_ &&
+               o->access_ == access_;
+    }
+    return false;
+}
+
+std::string Pointer::FriendlyName(const SymbolTable& symbols) const {
+    std::ostringstream out;
+    out << "ptr<";
+    if (storage_class_ != ast::StorageClass::kNone) {
+        out << storage_class_ << ", ";
+    }
+    out << subtype_->FriendlyName(symbols) << ", " << access_;
+    out << ">";
+    return out.str();
+}
+
+Pointer::Pointer(Pointer&&) = default;
+
+Pointer::~Pointer() = default;
+
+}  // namespace tint::sem
diff --git a/src/tint/sem/pointer.h b/src/tint/sem/pointer.h
new file mode 100644
index 0000000..0c82e77
--- /dev/null
+++ b/src/tint/sem/pointer.h
@@ -0,0 +1,68 @@
+// 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_SEM_POINTER_H_
+#define SRC_TINT_SEM_POINTER_H_
+
+#include <string>
+
+#include "src/tint/ast/access.h"
+#include "src/tint/ast/storage_class.h"
+#include "src/tint/sem/type.h"
+
+namespace tint::sem {
+
+/// A pointer type.
+class Pointer final : public Castable<Pointer, Type> {
+  public:
+    /// Constructor
+    /// @param subtype the pointee type
+    /// @param storage_class the storage class of the pointer
+    /// @param access the resolved access control of the reference
+    Pointer(const Type* subtype, ast::StorageClass storage_class, ast::Access access);
+
+    /// Move constructor
+    Pointer(Pointer&&);
+    ~Pointer() override;
+
+    /// @returns a hash of the type.
+    size_t Hash() const override;
+
+    /// @param other the other type to compare against
+    /// @returns true if the this type is equal to the given type
+    bool Equals(const Type& other) const override;
+
+    /// @returns the pointee type
+    const Type* StoreType() const { return subtype_; }
+
+    /// @returns the storage class of the pointer
+    ast::StorageClass StorageClass() const { return storage_class_; }
+
+    /// @returns the access control of the reference
+    ast::Access Access() const { return access_; }
+
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type that closely resembles how it would be
+    /// declared in WGSL.
+    std::string FriendlyName(const SymbolTable& symbols) const override;
+
+  private:
+    Type const* const subtype_;
+    ast::StorageClass const storage_class_;
+    ast::Access const access_;
+};
+
+}  // namespace tint::sem
+
+#endif  // SRC_TINT_SEM_POINTER_H_
diff --git a/src/tint/sem/pointer_test.cc b/src/tint/sem/pointer_test.cc
new file mode 100644
index 0000000..575db41
--- /dev/null
+++ b/src/tint/sem/pointer_test.cc
@@ -0,0 +1,78 @@
+// 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/sem/test_helper.h"
+#include "src/tint/sem/texture.h"
+
+namespace tint::sem {
+namespace {
+
+using PointerTest = TestHelper;
+
+TEST_F(PointerTest, Creation) {
+    auto* a = create<Pointer>(create<I32>(), ast::StorageClass::kStorage, ast::Access::kReadWrite);
+    auto* b = create<Pointer>(create<I32>(), ast::StorageClass::kStorage, ast::Access::kReadWrite);
+    auto* c = create<Pointer>(create<F32>(), ast::StorageClass::kStorage, ast::Access::kReadWrite);
+    auto* d = create<Pointer>(create<I32>(), ast::StorageClass::kPrivate, ast::Access::kReadWrite);
+    auto* e = create<Pointer>(create<I32>(), ast::StorageClass::kStorage, ast::Access::kRead);
+
+    EXPECT_TRUE(a->StoreType()->Is<sem::I32>());
+    EXPECT_EQ(a->StorageClass(), ast::StorageClass::kStorage);
+    EXPECT_EQ(a->Access(), ast::Access::kReadWrite);
+
+    EXPECT_EQ(a, b);
+    EXPECT_NE(a, c);
+    EXPECT_NE(a, d);
+    EXPECT_NE(a, e);
+}
+
+TEST_F(PointerTest, Hash) {
+    auto* a = create<Pointer>(create<I32>(), ast::StorageClass::kStorage, ast::Access::kReadWrite);
+    auto* b = create<Pointer>(create<I32>(), ast::StorageClass::kStorage, ast::Access::kReadWrite);
+    auto* c = create<Pointer>(create<F32>(), ast::StorageClass::kStorage, ast::Access::kReadWrite);
+    auto* d = create<Pointer>(create<I32>(), ast::StorageClass::kPrivate, ast::Access::kReadWrite);
+    auto* e = create<Pointer>(create<I32>(), ast::StorageClass::kStorage, ast::Access::kRead);
+
+    EXPECT_EQ(a->Hash(), b->Hash());
+    EXPECT_NE(a->Hash(), c->Hash());
+    EXPECT_NE(a->Hash(), d->Hash());
+    EXPECT_NE(a->Hash(), e->Hash());
+}
+
+TEST_F(PointerTest, Equals) {
+    auto* a = create<Pointer>(create<I32>(), ast::StorageClass::kStorage, ast::Access::kReadWrite);
+    auto* b = create<Pointer>(create<I32>(), ast::StorageClass::kStorage, ast::Access::kReadWrite);
+    auto* c = create<Pointer>(create<F32>(), ast::StorageClass::kStorage, ast::Access::kReadWrite);
+    auto* d = create<Pointer>(create<I32>(), ast::StorageClass::kPrivate, ast::Access::kReadWrite);
+    auto* e = create<Pointer>(create<I32>(), ast::StorageClass::kStorage, ast::Access::kRead);
+
+    EXPECT_TRUE(a->Equals(*b));
+    EXPECT_FALSE(a->Equals(*c));
+    EXPECT_FALSE(a->Equals(*d));
+    EXPECT_FALSE(a->Equals(*e));
+    EXPECT_FALSE(a->Equals(Void{}));
+}
+
+TEST_F(PointerTest, FriendlyName) {
+    auto* r = create<Pointer>(create<I32>(), ast::StorageClass::kNone, ast::Access::kRead);
+    EXPECT_EQ(r->FriendlyName(Symbols()), "ptr<i32, read>");
+}
+
+TEST_F(PointerTest, FriendlyNameWithStorageClass) {
+    auto* r = create<Pointer>(create<I32>(), ast::StorageClass::kWorkgroup, ast::Access::kRead);
+    EXPECT_EQ(r->FriendlyName(Symbols()), "ptr<workgroup, i32, read>");
+}
+
+}  // namespace
+}  // namespace tint::sem
diff --git a/src/tint/sem/pointer_type.cc b/src/tint/sem/pointer_type.cc
deleted file mode 100644
index b1f137a..0000000
--- a/src/tint/sem/pointer_type.cc
+++ /dev/null
@@ -1,61 +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/sem/pointer_type.h"
-
-#include "src/tint/program_builder.h"
-#include "src/tint/sem/reference_type.h"
-#include "src/tint/utils/hash.h"
-
-TINT_INSTANTIATE_TYPEINFO(tint::sem::Pointer);
-
-namespace tint::sem {
-
-Pointer::Pointer(const Type* subtype,
-                 ast::StorageClass storage_class,
-                 ast::Access access)
-    : subtype_(subtype), storage_class_(storage_class), access_(access) {
-  TINT_ASSERT(Semantic, !subtype->Is<Reference>());
-  TINT_ASSERT(Semantic, access != ast::Access::kUndefined);
-}
-
-size_t Pointer::Hash() const {
-  return utils::Hash(TypeInfo::Of<Pointer>().full_hashcode, storage_class_,
-                     subtype_, access_);
-}
-
-bool Pointer::Equals(const sem::Type& other) const {
-  if (auto* o = other.As<Pointer>()) {
-    return o->storage_class_ == storage_class_ && o->subtype_ == subtype_ &&
-           o->access_ == access_;
-  }
-  return false;
-}
-
-std::string Pointer::FriendlyName(const SymbolTable& symbols) const {
-  std::ostringstream out;
-  out << "ptr<";
-  if (storage_class_ != ast::StorageClass::kNone) {
-    out << storage_class_ << ", ";
-  }
-  out << subtype_->FriendlyName(symbols) << ", " << access_;
-  out << ">";
-  return out.str();
-}
-
-Pointer::Pointer(Pointer&&) = default;
-
-Pointer::~Pointer() = default;
-
-}  // namespace tint::sem
diff --git a/src/tint/sem/pointer_type.h b/src/tint/sem/pointer_type.h
deleted file mode 100644
index c3697c1..0000000
--- a/src/tint/sem/pointer_type.h
+++ /dev/null
@@ -1,70 +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_SEM_POINTER_TYPE_H_
-#define SRC_TINT_SEM_POINTER_TYPE_H_
-
-#include <string>
-
-#include "src/tint/ast/access.h"
-#include "src/tint/ast/storage_class.h"
-#include "src/tint/sem/type.h"
-
-namespace tint::sem {
-
-/// A pointer type.
-class Pointer final : public Castable<Pointer, Type> {
- public:
-  /// Constructor
-  /// @param subtype the pointee type
-  /// @param storage_class the storage class of the pointer
-  /// @param access the resolved access control of the reference
-  Pointer(const Type* subtype,
-          ast::StorageClass storage_class,
-          ast::Access access);
-
-  /// Move constructor
-  Pointer(Pointer&&);
-  ~Pointer() override;
-
-  /// @returns a hash of the type.
-  size_t Hash() const override;
-
-  /// @param other the other type to compare against
-  /// @returns true if the this type is equal to the given type
-  bool Equals(const Type& other) const override;
-
-  /// @returns the pointee type
-  const Type* StoreType() const { return subtype_; }
-
-  /// @returns the storage class of the pointer
-  ast::StorageClass StorageClass() const { return storage_class_; }
-
-  /// @returns the access control of the reference
-  ast::Access Access() const { return access_; }
-
-  /// @param symbols the program's symbol table
-  /// @returns the name for this type that closely resembles how it would be
-  /// declared in WGSL.
-  std::string FriendlyName(const SymbolTable& symbols) const override;
-
- private:
-  Type const* const subtype_;
-  ast::StorageClass const storage_class_;
-  ast::Access const access_;
-};
-
-}  // namespace tint::sem
-
-#endif  // SRC_TINT_SEM_POINTER_TYPE_H_
diff --git a/src/tint/sem/pointer_type_test.cc b/src/tint/sem/pointer_type_test.cc
deleted file mode 100644
index 713677d..0000000
--- a/src/tint/sem/pointer_type_test.cc
+++ /dev/null
@@ -1,95 +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/sem/test_helper.h"
-#include "src/tint/sem/texture_type.h"
-
-namespace tint::sem {
-namespace {
-
-using PointerTest = TestHelper;
-
-TEST_F(PointerTest, Creation) {
-  auto* a = create<Pointer>(create<I32>(), ast::StorageClass::kStorage,
-                            ast::Access::kReadWrite);
-  auto* b = create<Pointer>(create<I32>(), ast::StorageClass::kStorage,
-                            ast::Access::kReadWrite);
-  auto* c = create<Pointer>(create<F32>(), ast::StorageClass::kStorage,
-                            ast::Access::kReadWrite);
-  auto* d = create<Pointer>(create<I32>(), ast::StorageClass::kPrivate,
-                            ast::Access::kReadWrite);
-  auto* e = create<Pointer>(create<I32>(), ast::StorageClass::kStorage,
-                            ast::Access::kRead);
-
-  EXPECT_TRUE(a->StoreType()->Is<sem::I32>());
-  EXPECT_EQ(a->StorageClass(), ast::StorageClass::kStorage);
-  EXPECT_EQ(a->Access(), ast::Access::kReadWrite);
-
-  EXPECT_EQ(a, b);
-  EXPECT_NE(a, c);
-  EXPECT_NE(a, d);
-  EXPECT_NE(a, e);
-}
-
-TEST_F(PointerTest, Hash) {
-  auto* a = create<Pointer>(create<I32>(), ast::StorageClass::kStorage,
-                            ast::Access::kReadWrite);
-  auto* b = create<Pointer>(create<I32>(), ast::StorageClass::kStorage,
-                            ast::Access::kReadWrite);
-  auto* c = create<Pointer>(create<F32>(), ast::StorageClass::kStorage,
-                            ast::Access::kReadWrite);
-  auto* d = create<Pointer>(create<I32>(), ast::StorageClass::kPrivate,
-                            ast::Access::kReadWrite);
-  auto* e = create<Pointer>(create<I32>(), ast::StorageClass::kStorage,
-                            ast::Access::kRead);
-
-  EXPECT_EQ(a->Hash(), b->Hash());
-  EXPECT_NE(a->Hash(), c->Hash());
-  EXPECT_NE(a->Hash(), d->Hash());
-  EXPECT_NE(a->Hash(), e->Hash());
-}
-
-TEST_F(PointerTest, Equals) {
-  auto* a = create<Pointer>(create<I32>(), ast::StorageClass::kStorage,
-                            ast::Access::kReadWrite);
-  auto* b = create<Pointer>(create<I32>(), ast::StorageClass::kStorage,
-                            ast::Access::kReadWrite);
-  auto* c = create<Pointer>(create<F32>(), ast::StorageClass::kStorage,
-                            ast::Access::kReadWrite);
-  auto* d = create<Pointer>(create<I32>(), ast::StorageClass::kPrivate,
-                            ast::Access::kReadWrite);
-  auto* e = create<Pointer>(create<I32>(), ast::StorageClass::kStorage,
-                            ast::Access::kRead);
-
-  EXPECT_TRUE(a->Equals(*b));
-  EXPECT_FALSE(a->Equals(*c));
-  EXPECT_FALSE(a->Equals(*d));
-  EXPECT_FALSE(a->Equals(*e));
-  EXPECT_FALSE(a->Equals(Void{}));
-}
-
-TEST_F(PointerTest, FriendlyName) {
-  auto* r = create<Pointer>(create<I32>(), ast::StorageClass::kNone,
-                            ast::Access::kRead);
-  EXPECT_EQ(r->FriendlyName(Symbols()), "ptr<i32, read>");
-}
-
-TEST_F(PointerTest, FriendlyNameWithStorageClass) {
-  auto* r = create<Pointer>(create<I32>(), ast::StorageClass::kWorkgroup,
-                            ast::Access::kRead);
-  EXPECT_EQ(r->FriendlyName(Symbols()), "ptr<workgroup, i32, read>");
-}
-
-}  // namespace
-}  // namespace tint::sem
diff --git a/src/tint/sem/reference.cc b/src/tint/sem/reference.cc
new file mode 100644
index 0000000..4751563
--- /dev/null
+++ b/src/tint/sem/reference.cc
@@ -0,0 +1,57 @@
+// Copyright 2021 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/sem/reference.h"
+
+#include "src/tint/program_builder.h"
+#include "src/tint/utils/hash.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::sem::Reference);
+
+namespace tint::sem {
+
+Reference::Reference(const Type* subtype, ast::StorageClass storage_class, ast::Access access)
+    : subtype_(subtype), storage_class_(storage_class), access_(access) {
+    TINT_ASSERT(Semantic, !subtype->Is<Reference>());
+    TINT_ASSERT(Semantic, access != ast::Access::kUndefined);
+}
+
+size_t Reference::Hash() const {
+    return utils::Hash(TypeInfo::Of<Reference>().full_hashcode, storage_class_, subtype_, access_);
+}
+
+bool Reference::Equals(const sem::Type& other) const {
+    if (auto* o = other.As<Reference>()) {
+        return o->storage_class_ == storage_class_ && o->subtype_ == subtype_ &&
+               o->access_ == access_;
+    }
+    return false;
+}
+
+std::string Reference::FriendlyName(const SymbolTable& symbols) const {
+    std::ostringstream out;
+    out << "ref<";
+    if (storage_class_ != ast::StorageClass::kNone) {
+        out << storage_class_ << ", ";
+    }
+    out << subtype_->FriendlyName(symbols) << ", " << access_;
+    out << ">";
+    return out.str();
+}
+
+Reference::Reference(Reference&&) = default;
+
+Reference::~Reference() = default;
+
+}  // namespace tint::sem
diff --git a/src/tint/sem/reference.h b/src/tint/sem/reference.h
new file mode 100644
index 0000000..5db9b62
--- /dev/null
+++ b/src/tint/sem/reference.h
@@ -0,0 +1,68 @@
+// Copyright 2021 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef SRC_TINT_SEM_REFERENCE_H_
+#define SRC_TINT_SEM_REFERENCE_H_
+
+#include <string>
+
+#include "src/tint/ast/access.h"
+#include "src/tint/ast/storage_class.h"
+#include "src/tint/sem/type.h"
+
+namespace tint::sem {
+
+/// A reference type.
+class Reference final : public Castable<Reference, Type> {
+  public:
+    /// Constructor
+    /// @param subtype the pointee type
+    /// @param storage_class the storage class of the reference
+    /// @param access the resolved access control of the reference
+    Reference(const Type* subtype, ast::StorageClass storage_class, ast::Access access);
+
+    /// Move constructor
+    Reference(Reference&&);
+    ~Reference() override;
+
+    /// @returns a hash of the type.
+    size_t Hash() const override;
+
+    /// @param other the other type to compare against
+    /// @returns true if the this type is equal to the given type
+    bool Equals(const Type& other) const override;
+
+    /// @returns the pointee type
+    const Type* StoreType() const { return subtype_; }
+
+    /// @returns the storage class of the reference
+    ast::StorageClass StorageClass() const { return storage_class_; }
+
+    /// @returns the resolved access control of the reference.
+    ast::Access Access() const { return access_; }
+
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type that closely resembles how it would be
+    /// declared in WGSL.
+    std::string FriendlyName(const SymbolTable& symbols) const override;
+
+  private:
+    Type const* const subtype_;
+    ast::StorageClass const storage_class_;
+    ast::Access const access_;
+};
+
+}  // namespace tint::sem
+
+#endif  // SRC_TINT_SEM_REFERENCE_H_
diff --git a/src/tint/sem/reference_test.cc b/src/tint/sem/reference_test.cc
new file mode 100644
index 0000000..27b1ebd
--- /dev/null
+++ b/src/tint/sem/reference_test.cc
@@ -0,0 +1,90 @@
+// Copyright 2021 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/sem/reference.h"
+#include "src/tint/sem/test_helper.h"
+
+namespace tint::sem {
+namespace {
+
+using ReferenceTest = TestHelper;
+
+TEST_F(ReferenceTest, Creation) {
+    auto* a =
+        create<Reference>(create<I32>(), ast::StorageClass::kStorage, ast::Access::kReadWrite);
+    auto* b =
+        create<Reference>(create<I32>(), ast::StorageClass::kStorage, ast::Access::kReadWrite);
+    auto* c =
+        create<Reference>(create<F32>(), ast::StorageClass::kStorage, ast::Access::kReadWrite);
+    auto* d =
+        create<Reference>(create<I32>(), ast::StorageClass::kPrivate, ast::Access::kReadWrite);
+    auto* e = create<Reference>(create<I32>(), ast::StorageClass::kStorage, ast::Access::kRead);
+
+    EXPECT_TRUE(a->StoreType()->Is<sem::I32>());
+    EXPECT_EQ(a->StorageClass(), ast::StorageClass::kStorage);
+    EXPECT_EQ(a->Access(), ast::Access::kReadWrite);
+
+    EXPECT_EQ(a, b);
+    EXPECT_NE(a, c);
+    EXPECT_NE(a, d);
+    EXPECT_NE(a, e);
+}
+
+TEST_F(ReferenceTest, Hash) {
+    auto* a =
+        create<Reference>(create<I32>(), ast::StorageClass::kStorage, ast::Access::kReadWrite);
+    auto* b =
+        create<Reference>(create<I32>(), ast::StorageClass::kStorage, ast::Access::kReadWrite);
+    auto* c =
+        create<Reference>(create<F32>(), ast::StorageClass::kStorage, ast::Access::kReadWrite);
+    auto* d =
+        create<Reference>(create<I32>(), ast::StorageClass::kPrivate, ast::Access::kReadWrite);
+    auto* e = create<Reference>(create<I32>(), ast::StorageClass::kStorage, ast::Access::kRead);
+
+    EXPECT_EQ(a->Hash(), b->Hash());
+    EXPECT_NE(a->Hash(), c->Hash());
+    EXPECT_NE(a->Hash(), d->Hash());
+    EXPECT_NE(a->Hash(), e->Hash());
+}
+
+TEST_F(ReferenceTest, Equals) {
+    auto* a =
+        create<Reference>(create<I32>(), ast::StorageClass::kStorage, ast::Access::kReadWrite);
+    auto* b =
+        create<Reference>(create<I32>(), ast::StorageClass::kStorage, ast::Access::kReadWrite);
+    auto* c =
+        create<Reference>(create<F32>(), ast::StorageClass::kStorage, ast::Access::kReadWrite);
+    auto* d =
+        create<Reference>(create<I32>(), ast::StorageClass::kPrivate, ast::Access::kReadWrite);
+    auto* e = create<Reference>(create<I32>(), ast::StorageClass::kStorage, ast::Access::kRead);
+
+    EXPECT_TRUE(a->Equals(*b));
+    EXPECT_FALSE(a->Equals(*c));
+    EXPECT_FALSE(a->Equals(*d));
+    EXPECT_FALSE(a->Equals(*e));
+    EXPECT_FALSE(a->Equals(Void{}));
+}
+
+TEST_F(ReferenceTest, FriendlyName) {
+    auto* r = create<Reference>(create<I32>(), ast::StorageClass::kNone, ast::Access::kRead);
+    EXPECT_EQ(r->FriendlyName(Symbols()), "ref<i32, read>");
+}
+
+TEST_F(ReferenceTest, FriendlyNameWithStorageClass) {
+    auto* r = create<Reference>(create<I32>(), ast::StorageClass::kWorkgroup, ast::Access::kRead);
+    EXPECT_EQ(r->FriendlyName(Symbols()), "ref<workgroup, i32, read>");
+}
+
+}  // namespace
+}  // namespace tint::sem
diff --git a/src/tint/sem/reference_type.cc b/src/tint/sem/reference_type.cc
deleted file mode 100644
index 6eaceda..0000000
--- a/src/tint/sem/reference_type.cc
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2021 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/tint/sem/reference_type.h"
-
-#include "src/tint/program_builder.h"
-#include "src/tint/utils/hash.h"
-
-TINT_INSTANTIATE_TYPEINFO(tint::sem::Reference);
-
-namespace tint::sem {
-
-Reference::Reference(const Type* subtype,
-                     ast::StorageClass storage_class,
-                     ast::Access access)
-    : subtype_(subtype), storage_class_(storage_class), access_(access) {
-  TINT_ASSERT(Semantic, !subtype->Is<Reference>());
-  TINT_ASSERT(Semantic, access != ast::Access::kUndefined);
-}
-
-size_t Reference::Hash() const {
-  return utils::Hash(TypeInfo::Of<Reference>().full_hashcode, storage_class_,
-                     subtype_, access_);
-}
-
-bool Reference::Equals(const sem::Type& other) const {
-  if (auto* o = other.As<Reference>()) {
-    return o->storage_class_ == storage_class_ && o->subtype_ == subtype_ &&
-           o->access_ == access_;
-  }
-  return false;
-}
-
-std::string Reference::FriendlyName(const SymbolTable& symbols) const {
-  std::ostringstream out;
-  out << "ref<";
-  if (storage_class_ != ast::StorageClass::kNone) {
-    out << storage_class_ << ", ";
-  }
-  out << subtype_->FriendlyName(symbols) << ", " << access_;
-  out << ">";
-  return out.str();
-}
-
-Reference::Reference(Reference&&) = default;
-
-Reference::~Reference() = default;
-
-}  // namespace tint::sem
diff --git a/src/tint/sem/reference_type.h b/src/tint/sem/reference_type.h
deleted file mode 100644
index d2639a4..0000000
--- a/src/tint/sem/reference_type.h
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2021 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#ifndef SRC_TINT_SEM_REFERENCE_TYPE_H_
-#define SRC_TINT_SEM_REFERENCE_TYPE_H_
-
-#include <string>
-
-#include "src/tint/ast/access.h"
-#include "src/tint/ast/storage_class.h"
-#include "src/tint/sem/type.h"
-
-namespace tint::sem {
-
-/// A reference type.
-class Reference final : public Castable<Reference, Type> {
- public:
-  /// Constructor
-  /// @param subtype the pointee type
-  /// @param storage_class the storage class of the reference
-  /// @param access the resolved access control of the reference
-  Reference(const Type* subtype,
-            ast::StorageClass storage_class,
-            ast::Access access);
-
-  /// Move constructor
-  Reference(Reference&&);
-  ~Reference() override;
-
-  /// @returns a hash of the type.
-  size_t Hash() const override;
-
-  /// @param other the other type to compare against
-  /// @returns true if the this type is equal to the given type
-  bool Equals(const Type& other) const override;
-
-  /// @returns the pointee type
-  const Type* StoreType() const { return subtype_; }
-
-  /// @returns the storage class of the reference
-  ast::StorageClass StorageClass() const { return storage_class_; }
-
-  /// @returns the resolved access control of the reference.
-  ast::Access Access() const { return access_; }
-
-  /// @param symbols the program's symbol table
-  /// @returns the name for this type that closely resembles how it would be
-  /// declared in WGSL.
-  std::string FriendlyName(const SymbolTable& symbols) const override;
-
- private:
-  Type const* const subtype_;
-  ast::StorageClass const storage_class_;
-  ast::Access const access_;
-};
-
-}  // namespace tint::sem
-
-#endif  // SRC_TINT_SEM_REFERENCE_TYPE_H_
diff --git a/src/tint/sem/reference_type_test.cc b/src/tint/sem/reference_type_test.cc
deleted file mode 100644
index 9d99598..0000000
--- a/src/tint/sem/reference_type_test.cc
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright 2021 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/tint/sem/reference_type.h"
-#include "src/tint/sem/test_helper.h"
-
-namespace tint::sem {
-namespace {
-
-using ReferenceTest = TestHelper;
-
-TEST_F(ReferenceTest, Creation) {
-  auto* a = create<Reference>(create<I32>(), ast::StorageClass::kStorage,
-                              ast::Access::kReadWrite);
-  auto* b = create<Reference>(create<I32>(), ast::StorageClass::kStorage,
-                              ast::Access::kReadWrite);
-  auto* c = create<Reference>(create<F32>(), ast::StorageClass::kStorage,
-                              ast::Access::kReadWrite);
-  auto* d = create<Reference>(create<I32>(), ast::StorageClass::kPrivate,
-                              ast::Access::kReadWrite);
-  auto* e = create<Reference>(create<I32>(), ast::StorageClass::kStorage,
-                              ast::Access::kRead);
-
-  EXPECT_TRUE(a->StoreType()->Is<sem::I32>());
-  EXPECT_EQ(a->StorageClass(), ast::StorageClass::kStorage);
-  EXPECT_EQ(a->Access(), ast::Access::kReadWrite);
-
-  EXPECT_EQ(a, b);
-  EXPECT_NE(a, c);
-  EXPECT_NE(a, d);
-  EXPECT_NE(a, e);
-}
-
-TEST_F(ReferenceTest, Hash) {
-  auto* a = create<Reference>(create<I32>(), ast::StorageClass::kStorage,
-                              ast::Access::kReadWrite);
-  auto* b = create<Reference>(create<I32>(), ast::StorageClass::kStorage,
-                              ast::Access::kReadWrite);
-  auto* c = create<Reference>(create<F32>(), ast::StorageClass::kStorage,
-                              ast::Access::kReadWrite);
-  auto* d = create<Reference>(create<I32>(), ast::StorageClass::kPrivate,
-                              ast::Access::kReadWrite);
-  auto* e = create<Reference>(create<I32>(), ast::StorageClass::kStorage,
-                              ast::Access::kRead);
-
-  EXPECT_EQ(a->Hash(), b->Hash());
-  EXPECT_NE(a->Hash(), c->Hash());
-  EXPECT_NE(a->Hash(), d->Hash());
-  EXPECT_NE(a->Hash(), e->Hash());
-}
-
-TEST_F(ReferenceTest, Equals) {
-  auto* a = create<Reference>(create<I32>(), ast::StorageClass::kStorage,
-                              ast::Access::kReadWrite);
-  auto* b = create<Reference>(create<I32>(), ast::StorageClass::kStorage,
-                              ast::Access::kReadWrite);
-  auto* c = create<Reference>(create<F32>(), ast::StorageClass::kStorage,
-                              ast::Access::kReadWrite);
-  auto* d = create<Reference>(create<I32>(), ast::StorageClass::kPrivate,
-                              ast::Access::kReadWrite);
-  auto* e = create<Reference>(create<I32>(), ast::StorageClass::kStorage,
-                              ast::Access::kRead);
-
-  EXPECT_TRUE(a->Equals(*b));
-  EXPECT_FALSE(a->Equals(*c));
-  EXPECT_FALSE(a->Equals(*d));
-  EXPECT_FALSE(a->Equals(*e));
-  EXPECT_FALSE(a->Equals(Void{}));
-}
-
-TEST_F(ReferenceTest, FriendlyName) {
-  auto* r = create<Reference>(create<I32>(), ast::StorageClass::kNone,
-                              ast::Access::kRead);
-  EXPECT_EQ(r->FriendlyName(Symbols()), "ref<i32, read>");
-}
-
-TEST_F(ReferenceTest, FriendlyNameWithStorageClass) {
-  auto* r = create<Reference>(create<I32>(), ast::StorageClass::kWorkgroup,
-                              ast::Access::kRead);
-  EXPECT_EQ(r->FriendlyName(Symbols()), "ref<workgroup, i32, read>");
-}
-
-}  // namespace
-}  // namespace tint::sem
diff --git a/src/tint/sem/sampled_texture_type.cc b/src/tint/sem/sampled_texture.cc
similarity index 73%
rename from src/tint/sem/sampled_texture_type.cc
rename to src/tint/sem/sampled_texture.cc
index 5d9d9c5..260901a 100644
--- a/src/tint/sem/sampled_texture_type.cc
+++ b/src/tint/sem/sampled_texture.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/sem/sampled_texture_type.h"
+#include "src/tint/sem/sampled_texture.h"
 
 #include "src/tint/program_builder.h"
 #include "src/tint/utils/hash.h"
@@ -23,7 +23,7 @@
 
 SampledTexture::SampledTexture(ast::TextureDimension dim, const Type* type)
     : Base(dim), type_(type) {
-  TINT_ASSERT(Semantic, type_);
+    TINT_ASSERT(Semantic, type_);
 }
 
 SampledTexture::SampledTexture(SampledTexture&&) = default;
@@ -31,21 +31,20 @@
 SampledTexture::~SampledTexture() = default;
 
 size_t SampledTexture::Hash() const {
-  return utils::Hash(TypeInfo::Of<SampledTexture>().full_hashcode, dim(),
-                     type_);
+    return utils::Hash(TypeInfo::Of<SampledTexture>().full_hashcode, dim(), type_);
 }
 
 bool SampledTexture::Equals(const sem::Type& other) const {
-  if (auto* o = other.As<SampledTexture>()) {
-    return o->dim() == dim() && o->type_ == type_;
-  }
-  return false;
+    if (auto* o = other.As<SampledTexture>()) {
+        return o->dim() == dim() && o->type_ == type_;
+    }
+    return false;
 }
 
 std::string SampledTexture::FriendlyName(const SymbolTable& symbols) const {
-  std::ostringstream out;
-  out << "texture_" << dim() << "<" << type_->FriendlyName(symbols) << ">";
-  return out.str();
+    std::ostringstream out;
+    out << "texture_" << dim() << "<" << type_->FriendlyName(symbols) << ">";
+    return out.str();
 }
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/sampled_texture.h b/src/tint/sem/sampled_texture.h
new file mode 100644
index 0000000..15e7949
--- /dev/null
+++ b/src/tint/sem/sampled_texture.h
@@ -0,0 +1,56 @@
+// 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_SEM_SAMPLED_TEXTURE_H_
+#define SRC_TINT_SEM_SAMPLED_TEXTURE_H_
+
+#include <string>
+
+#include "src/tint/sem/texture.h"
+
+namespace tint::sem {
+
+/// A sampled texture type.
+class SampledTexture final : public Castable<SampledTexture, Texture> {
+  public:
+    /// Constructor
+    /// @param dim the dimensionality of the texture
+    /// @param type the data type of the sampled texture
+    SampledTexture(ast::TextureDimension dim, const Type* type);
+    /// Move constructor
+    SampledTexture(SampledTexture&&);
+    ~SampledTexture() override;
+
+    /// @returns a hash of the type.
+    size_t Hash() const override;
+
+    /// @param other the other type to compare against
+    /// @returns true if the this type is equal to the given type
+    bool Equals(const Type& other) const override;
+
+    /// @returns the subtype of the sampled texture
+    Type* type() const { return const_cast<Type*>(type_); }
+
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type that closely resembles how it would be
+    /// declared in WGSL.
+    std::string FriendlyName(const SymbolTable& symbols) const override;
+
+  private:
+    const Type* const type_;
+};
+
+}  // namespace tint::sem
+
+#endif  // SRC_TINT_SEM_SAMPLED_TEXTURE_H_
diff --git a/src/tint/sem/sampled_texture_test.cc b/src/tint/sem/sampled_texture_test.cc
new file mode 100644
index 0000000..8a3321f
--- /dev/null
+++ b/src/tint/sem/sampled_texture_test.cc
@@ -0,0 +1,93 @@
+// 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/sem/sampled_texture.h"
+
+#include "src/tint/sem/depth_texture.h"
+#include "src/tint/sem/external_texture.h"
+#include "src/tint/sem/storage_texture.h"
+#include "src/tint/sem/test_helper.h"
+
+namespace tint::sem {
+namespace {
+
+using SampledTextureTest = TestHelper;
+
+TEST_F(SampledTextureTest, Creation) {
+    auto* a = create<SampledTexture>(ast::TextureDimension::kCube, create<F32>());
+    auto* b = create<SampledTexture>(ast::TextureDimension::kCube, create<F32>());
+    auto* c = create<SampledTexture>(ast::TextureDimension::k2d, create<F32>());
+    auto* d = create<SampledTexture>(ast::TextureDimension::kCube, create<I32>());
+
+    EXPECT_TRUE(a->type()->Is<F32>());
+    EXPECT_EQ(a->dim(), ast::TextureDimension::kCube);
+
+    EXPECT_EQ(a, b);
+    EXPECT_NE(a, c);
+    EXPECT_NE(a, d);
+}
+
+TEST_F(SampledTextureTest, Hash) {
+    auto* a = create<SampledTexture>(ast::TextureDimension::kCube, create<F32>());
+    auto* b = create<SampledTexture>(ast::TextureDimension::kCube, create<F32>());
+    auto* c = create<SampledTexture>(ast::TextureDimension::k2d, create<F32>());
+    auto* d = create<SampledTexture>(ast::TextureDimension::kCube, create<I32>());
+
+    EXPECT_EQ(a->Hash(), b->Hash());
+    EXPECT_NE(a->Hash(), c->Hash());
+    EXPECT_NE(a->Hash(), d->Hash());
+}
+
+TEST_F(SampledTextureTest, Equals) {
+    auto* a = create<SampledTexture>(ast::TextureDimension::kCube, create<F32>());
+    auto* b = create<SampledTexture>(ast::TextureDimension::kCube, create<F32>());
+    auto* c = create<SampledTexture>(ast::TextureDimension::k2d, create<F32>());
+    auto* d = create<SampledTexture>(ast::TextureDimension::kCube, create<I32>());
+
+    EXPECT_TRUE(a->Equals(*b));
+    EXPECT_FALSE(a->Equals(*c));
+    EXPECT_FALSE(a->Equals(*d));
+    EXPECT_FALSE(a->Equals(Void{}));
+}
+
+TEST_F(SampledTextureTest, IsTexture) {
+    F32 f32;
+    SampledTexture s(ast::TextureDimension::kCube, &f32);
+    Texture* ty = &s;
+    EXPECT_FALSE(ty->Is<DepthTexture>());
+    EXPECT_FALSE(ty->Is<ExternalTexture>());
+    EXPECT_TRUE(ty->Is<SampledTexture>());
+    EXPECT_FALSE(ty->Is<StorageTexture>());
+}
+
+TEST_F(SampledTextureTest, Dim) {
+    F32 f32;
+    SampledTexture s(ast::TextureDimension::k3d, &f32);
+    EXPECT_EQ(s.dim(), ast::TextureDimension::k3d);
+}
+
+TEST_F(SampledTextureTest, Type) {
+    F32 f32;
+    SampledTexture s(ast::TextureDimension::k3d, &f32);
+    EXPECT_EQ(s.type(), &f32);
+}
+
+TEST_F(SampledTextureTest, FriendlyName) {
+    F32 f32;
+    SampledTexture s(ast::TextureDimension::k3d, &f32);
+    EXPECT_EQ(s.FriendlyName(Symbols()), "texture_3d<f32>");
+}
+
+}  // namespace
+}  // namespace tint::sem
diff --git a/src/tint/sem/sampled_texture_type.h b/src/tint/sem/sampled_texture_type.h
deleted file mode 100644
index b67737e..0000000
--- a/src/tint/sem/sampled_texture_type.h
+++ /dev/null
@@ -1,56 +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_SEM_SAMPLED_TEXTURE_TYPE_H_
-#define SRC_TINT_SEM_SAMPLED_TEXTURE_TYPE_H_
-
-#include <string>
-
-#include "src/tint/sem/texture_type.h"
-
-namespace tint::sem {
-
-/// A sampled texture type.
-class SampledTexture final : public Castable<SampledTexture, Texture> {
- public:
-  /// Constructor
-  /// @param dim the dimensionality of the texture
-  /// @param type the data type of the sampled texture
-  SampledTexture(ast::TextureDimension dim, const Type* type);
-  /// Move constructor
-  SampledTexture(SampledTexture&&);
-  ~SampledTexture() override;
-
-  /// @returns a hash of the type.
-  size_t Hash() const override;
-
-  /// @param other the other type to compare against
-  /// @returns true if the this type is equal to the given type
-  bool Equals(const Type& other) const override;
-
-  /// @returns the subtype of the sampled texture
-  Type* type() const { return const_cast<Type*>(type_); }
-
-  /// @param symbols the program's symbol table
-  /// @returns the name for this type that closely resembles how it would be
-  /// declared in WGSL.
-  std::string FriendlyName(const SymbolTable& symbols) const override;
-
- private:
-  const Type* const type_;
-};
-
-}  // namespace tint::sem
-
-#endif  // SRC_TINT_SEM_SAMPLED_TEXTURE_TYPE_H_
diff --git a/src/tint/sem/sampled_texture_type_test.cc b/src/tint/sem/sampled_texture_type_test.cc
deleted file mode 100644
index 7ddb482..0000000
--- a/src/tint/sem/sampled_texture_type_test.cc
+++ /dev/null
@@ -1,93 +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/sem/sampled_texture_type.h"
-
-#include "src/tint/sem/depth_texture_type.h"
-#include "src/tint/sem/external_texture_type.h"
-#include "src/tint/sem/storage_texture_type.h"
-#include "src/tint/sem/test_helper.h"
-
-namespace tint::sem {
-namespace {
-
-using SampledTextureTest = TestHelper;
-
-TEST_F(SampledTextureTest, Creation) {
-  auto* a = create<SampledTexture>(ast::TextureDimension::kCube, create<F32>());
-  auto* b = create<SampledTexture>(ast::TextureDimension::kCube, create<F32>());
-  auto* c = create<SampledTexture>(ast::TextureDimension::k2d, create<F32>());
-  auto* d = create<SampledTexture>(ast::TextureDimension::kCube, create<I32>());
-
-  EXPECT_TRUE(a->type()->Is<F32>());
-  EXPECT_EQ(a->dim(), ast::TextureDimension::kCube);
-
-  EXPECT_EQ(a, b);
-  EXPECT_NE(a, c);
-  EXPECT_NE(a, d);
-}
-
-TEST_F(SampledTextureTest, Hash) {
-  auto* a = create<SampledTexture>(ast::TextureDimension::kCube, create<F32>());
-  auto* b = create<SampledTexture>(ast::TextureDimension::kCube, create<F32>());
-  auto* c = create<SampledTexture>(ast::TextureDimension::k2d, create<F32>());
-  auto* d = create<SampledTexture>(ast::TextureDimension::kCube, create<I32>());
-
-  EXPECT_EQ(a->Hash(), b->Hash());
-  EXPECT_NE(a->Hash(), c->Hash());
-  EXPECT_NE(a->Hash(), d->Hash());
-}
-
-TEST_F(SampledTextureTest, Equals) {
-  auto* a = create<SampledTexture>(ast::TextureDimension::kCube, create<F32>());
-  auto* b = create<SampledTexture>(ast::TextureDimension::kCube, create<F32>());
-  auto* c = create<SampledTexture>(ast::TextureDimension::k2d, create<F32>());
-  auto* d = create<SampledTexture>(ast::TextureDimension::kCube, create<I32>());
-
-  EXPECT_TRUE(a->Equals(*b));
-  EXPECT_FALSE(a->Equals(*c));
-  EXPECT_FALSE(a->Equals(*d));
-  EXPECT_FALSE(a->Equals(Void{}));
-}
-
-TEST_F(SampledTextureTest, IsTexture) {
-  F32 f32;
-  SampledTexture s(ast::TextureDimension::kCube, &f32);
-  Texture* ty = &s;
-  EXPECT_FALSE(ty->Is<DepthTexture>());
-  EXPECT_FALSE(ty->Is<ExternalTexture>());
-  EXPECT_TRUE(ty->Is<SampledTexture>());
-  EXPECT_FALSE(ty->Is<StorageTexture>());
-}
-
-TEST_F(SampledTextureTest, Dim) {
-  F32 f32;
-  SampledTexture s(ast::TextureDimension::k3d, &f32);
-  EXPECT_EQ(s.dim(), ast::TextureDimension::k3d);
-}
-
-TEST_F(SampledTextureTest, Type) {
-  F32 f32;
-  SampledTexture s(ast::TextureDimension::k3d, &f32);
-  EXPECT_EQ(s.type(), &f32);
-}
-
-TEST_F(SampledTextureTest, FriendlyName) {
-  F32 f32;
-  SampledTexture s(ast::TextureDimension::k3d, &f32);
-  EXPECT_EQ(s.FriendlyName(Symbols()), "texture_3d<f32>");
-}
-
-}  // namespace
-}  // namespace tint::sem
diff --git a/src/tint/sem/sampler_type.cc b/src/tint/sem/sampler.cc
similarity index 78%
rename from src/tint/sem/sampler_type.cc
rename to src/tint/sem/sampler.cc
index 6558a17..20993cc 100644
--- a/src/tint/sem/sampler_type.cc
+++ b/src/tint/sem/sampler.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/sem/sampler_type.h"
+#include "src/tint/sem/sampler.h"
 
 #include "src/tint/program_builder.h"
 #include "src/tint/utils/hash.h"
@@ -28,18 +28,18 @@
 Sampler::~Sampler() = default;
 
 size_t Sampler::Hash() const {
-  return utils::Hash(TypeInfo::Of<Sampler>().full_hashcode, kind_);
+    return utils::Hash(TypeInfo::Of<Sampler>().full_hashcode, kind_);
 }
 
 bool Sampler::Equals(const sem::Type& other) const {
-  if (auto* o = other.As<Sampler>()) {
-    return o->kind_ == kind_;
-  }
-  return false;
+    if (auto* o = other.As<Sampler>()) {
+        return o->kind_ == kind_;
+    }
+    return false;
 }
 
 std::string Sampler::FriendlyName(const SymbolTable&) const {
-  return kind_ == ast::SamplerKind::kSampler ? "sampler" : "sampler_comparison";
+    return kind_ == ast::SamplerKind::kSampler ? "sampler" : "sampler_comparison";
 }
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/sampler.h b/src/tint/sem/sampler.h
new file mode 100644
index 0000000..96c184f
--- /dev/null
+++ b/src/tint/sem/sampler.h
@@ -0,0 +1,59 @@
+// 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_SEM_SAMPLER_H_
+#define SRC_TINT_SEM_SAMPLER_H_
+
+#include <string>
+
+#include "src/tint/ast/sampler.h"
+#include "src/tint/sem/type.h"
+
+namespace tint::sem {
+
+/// A sampler type.
+class Sampler final : public Castable<Sampler, Type> {
+  public:
+    /// Constructor
+    /// @param kind the kind of sampler
+    explicit Sampler(ast::SamplerKind kind);
+    /// Move constructor
+    Sampler(Sampler&&);
+    ~Sampler() override;
+
+    /// @returns a hash of the type.
+    size_t Hash() const override;
+
+    /// @param other the other type to compare against
+    /// @returns true if the this type is equal to the given type
+    bool Equals(const Type& other) const override;
+
+    /// @returns the sampler type
+    ast::SamplerKind kind() const { return kind_; }
+
+    /// @returns true if this is a comparison sampler
+    bool IsComparison() const { return kind_ == ast::SamplerKind::kComparisonSampler; }
+
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type that closely resembles how it would be
+    /// declared in WGSL.
+    std::string FriendlyName(const SymbolTable& symbols) const override;
+
+  private:
+    ast::SamplerKind const kind_;
+};
+
+}  // namespace tint::sem
+
+#endif  // SRC_TINT_SEM_SAMPLER_H_
diff --git a/src/tint/sem/sampler_test.cc b/src/tint/sem/sampler_test.cc
new file mode 100644
index 0000000..caa61dc
--- /dev/null
+++ b/src/tint/sem/sampler_test.cc
@@ -0,0 +1,69 @@
+// 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/sem/sampler.h"
+#include "src/tint/sem/test_helper.h"
+#include "src/tint/sem/texture.h"
+
+namespace tint::sem {
+namespace {
+
+using SamplerTest = TestHelper;
+
+TEST_F(SamplerTest, Creation) {
+    auto* a = create<Sampler>(ast::SamplerKind::kSampler);
+    auto* b = create<Sampler>(ast::SamplerKind::kSampler);
+    auto* c = create<Sampler>(ast::SamplerKind::kComparisonSampler);
+
+    EXPECT_EQ(a->kind(), ast::SamplerKind::kSampler);
+    EXPECT_EQ(c->kind(), ast::SamplerKind::kComparisonSampler);
+
+    EXPECT_FALSE(a->IsComparison());
+    EXPECT_TRUE(c->IsComparison());
+
+    EXPECT_EQ(a, b);
+    EXPECT_NE(a, c);
+}
+
+TEST_F(SamplerTest, Hash) {
+    auto* a = create<Sampler>(ast::SamplerKind::kSampler);
+    auto* b = create<Sampler>(ast::SamplerKind::kSampler);
+    auto* c = create<Sampler>(ast::SamplerKind::kComparisonSampler);
+
+    EXPECT_EQ(a->Hash(), b->Hash());
+    EXPECT_NE(a->Hash(), c->Hash());
+}
+
+TEST_F(SamplerTest, Equals) {
+    auto* a = create<Sampler>(ast::SamplerKind::kSampler);
+    auto* b = create<Sampler>(ast::SamplerKind::kSampler);
+    auto* c = create<Sampler>(ast::SamplerKind::kComparisonSampler);
+
+    EXPECT_TRUE(a->Equals(*b));
+    EXPECT_FALSE(a->Equals(*c));
+    EXPECT_FALSE(a->Equals(Void{}));
+}
+
+TEST_F(SamplerTest, FriendlyNameSampler) {
+    Sampler s{ast::SamplerKind::kSampler};
+    EXPECT_EQ(s.FriendlyName(Symbols()), "sampler");
+}
+
+TEST_F(SamplerTest, FriendlyNameComparisonSampler) {
+    Sampler s{ast::SamplerKind::kComparisonSampler};
+    EXPECT_EQ(s.FriendlyName(Symbols()), "sampler_comparison");
+}
+
+}  // namespace
+}  // namespace tint::sem
diff --git a/src/tint/sem/sampler_texture_pair.h b/src/tint/sem/sampler_texture_pair.h
index f9b665f..71f3e3c 100644
--- a/src/tint/sem/sampler_texture_pair.h
+++ b/src/tint/sem/sampler_texture_pair.h
@@ -24,25 +24,23 @@
 
 /// Mapping of a sampler to a texture it samples.
 struct SamplerTexturePair {
-  /// group & binding values for a sampler.
-  BindingPoint sampler_binding_point;
-  /// group & binding values for a texture samepled by the sampler.
-  BindingPoint texture_binding_point;
+    /// group & binding values for a sampler.
+    BindingPoint sampler_binding_point;
+    /// group & binding values for a texture samepled by the sampler.
+    BindingPoint texture_binding_point;
 
-  /// Equality operator
-  /// @param rhs the SamplerTexturePair to compare against
-  /// @returns true if this SamplerTexturePair is equal to `rhs`
-  inline bool operator==(const SamplerTexturePair& rhs) const {
-    return sampler_binding_point == rhs.sampler_binding_point &&
-           texture_binding_point == rhs.texture_binding_point;
-  }
+    /// Equality operator
+    /// @param rhs the SamplerTexturePair to compare against
+    /// @returns true if this SamplerTexturePair is equal to `rhs`
+    inline bool operator==(const SamplerTexturePair& rhs) const {
+        return sampler_binding_point == rhs.sampler_binding_point &&
+               texture_binding_point == rhs.texture_binding_point;
+    }
 
-  /// Inequality operator
-  /// @param rhs the SamplerTexturePair to compare against
-  /// @returns true if this SamplerTexturePair is not equal to `rhs`
-  inline bool operator!=(const SamplerTexturePair& rhs) const {
-    return !(*this == rhs);
-  }
+    /// Inequality operator
+    /// @param rhs the SamplerTexturePair to compare against
+    /// @returns true if this SamplerTexturePair is not equal to `rhs`
+    inline bool operator!=(const SamplerTexturePair& rhs) const { return !(*this == rhs); }
 };
 
 }  // namespace tint::sem
@@ -54,14 +52,12 @@
 /// std::unordered_set.
 template <>
 class hash<tint::sem::SamplerTexturePair> {
- public:
-  /// @param stp the texture pair to create a hash for
-  /// @return the hash value
-  inline std::size_t operator()(
-      const tint::sem::SamplerTexturePair& stp) const {
-    return tint::utils::Hash(stp.sampler_binding_point,
-                             stp.texture_binding_point);
-  }
+  public:
+    /// @param stp the texture pair to create a hash for
+    /// @return the hash value
+    inline std::size_t operator()(const tint::sem::SamplerTexturePair& stp) const {
+        return tint::utils::Hash(stp.sampler_binding_point, stp.texture_binding_point);
+    }
 };
 
 }  // namespace std
diff --git a/src/tint/sem/sampler_type.h b/src/tint/sem/sampler_type.h
deleted file mode 100644
index d1fffab..0000000
--- a/src/tint/sem/sampler_type.h
+++ /dev/null
@@ -1,61 +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_SEM_SAMPLER_TYPE_H_
-#define SRC_TINT_SEM_SAMPLER_TYPE_H_
-
-#include <string>
-
-#include "src/tint/ast/sampler.h"
-#include "src/tint/sem/type.h"
-
-namespace tint::sem {
-
-/// A sampler type.
-class Sampler final : public Castable<Sampler, Type> {
- public:
-  /// Constructor
-  /// @param kind the kind of sampler
-  explicit Sampler(ast::SamplerKind kind);
-  /// Move constructor
-  Sampler(Sampler&&);
-  ~Sampler() override;
-
-  /// @returns a hash of the type.
-  size_t Hash() const override;
-
-  /// @param other the other type to compare against
-  /// @returns true if the this type is equal to the given type
-  bool Equals(const Type& other) const override;
-
-  /// @returns the sampler type
-  ast::SamplerKind kind() const { return kind_; }
-
-  /// @returns true if this is a comparison sampler
-  bool IsComparison() const {
-    return kind_ == ast::SamplerKind::kComparisonSampler;
-  }
-
-  /// @param symbols the program's symbol table
-  /// @returns the name for this type that closely resembles how it would be
-  /// declared in WGSL.
-  std::string FriendlyName(const SymbolTable& symbols) const override;
-
- private:
-  ast::SamplerKind const kind_;
-};
-
-}  // namespace tint::sem
-
-#endif  // SRC_TINT_SEM_SAMPLER_TYPE_H_
diff --git a/src/tint/sem/sampler_type_test.cc b/src/tint/sem/sampler_type_test.cc
deleted file mode 100644
index edd57d2..0000000
--- a/src/tint/sem/sampler_type_test.cc
+++ /dev/null
@@ -1,69 +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/sem/sampler_type.h"
-#include "src/tint/sem/test_helper.h"
-#include "src/tint/sem/texture_type.h"
-
-namespace tint::sem {
-namespace {
-
-using SamplerTest = TestHelper;
-
-TEST_F(SamplerTest, Creation) {
-  auto* a = create<Sampler>(ast::SamplerKind::kSampler);
-  auto* b = create<Sampler>(ast::SamplerKind::kSampler);
-  auto* c = create<Sampler>(ast::SamplerKind::kComparisonSampler);
-
-  EXPECT_EQ(a->kind(), ast::SamplerKind::kSampler);
-  EXPECT_EQ(c->kind(), ast::SamplerKind::kComparisonSampler);
-
-  EXPECT_FALSE(a->IsComparison());
-  EXPECT_TRUE(c->IsComparison());
-
-  EXPECT_EQ(a, b);
-  EXPECT_NE(a, c);
-}
-
-TEST_F(SamplerTest, Hash) {
-  auto* a = create<Sampler>(ast::SamplerKind::kSampler);
-  auto* b = create<Sampler>(ast::SamplerKind::kSampler);
-  auto* c = create<Sampler>(ast::SamplerKind::kComparisonSampler);
-
-  EXPECT_EQ(a->Hash(), b->Hash());
-  EXPECT_NE(a->Hash(), c->Hash());
-}
-
-TEST_F(SamplerTest, Equals) {
-  auto* a = create<Sampler>(ast::SamplerKind::kSampler);
-  auto* b = create<Sampler>(ast::SamplerKind::kSampler);
-  auto* c = create<Sampler>(ast::SamplerKind::kComparisonSampler);
-
-  EXPECT_TRUE(a->Equals(*b));
-  EXPECT_FALSE(a->Equals(*c));
-  EXPECT_FALSE(a->Equals(Void{}));
-}
-
-TEST_F(SamplerTest, FriendlyNameSampler) {
-  Sampler s{ast::SamplerKind::kSampler};
-  EXPECT_EQ(s.FriendlyName(Symbols()), "sampler");
-}
-
-TEST_F(SamplerTest, FriendlyNameComparisonSampler) {
-  Sampler s{ast::SamplerKind::kComparisonSampler};
-  EXPECT_EQ(s.FriendlyName(Symbols()), "sampler_comparison");
-}
-
-}  // namespace
-}  // namespace tint::sem
diff --git a/src/tint/sem/sem_array_test.cc b/src/tint/sem/sem_array_test.cc
index fc78f38..4b61fd7 100644
--- a/src/tint/sem/sem_array_test.cc
+++ b/src/tint/sem/sem_array_test.cc
@@ -13,7 +13,7 @@
 // limitations under the License.
 
 #include "src/tint/sem/test_helper.h"
-#include "src/tint/sem/texture_type.h"
+#include "src/tint/sem/texture.h"
 
 namespace tint::sem {
 namespace {
@@ -21,108 +21,108 @@
 using ArrayTest = TestHelper;
 
 TEST_F(ArrayTest, CreateSizedArray) {
-  auto* a = create<Array>(create<U32>(), 2u, 4u, 8u, 32u, 16u);
-  auto* b = create<Array>(create<U32>(), 2u, 4u, 8u, 32u, 16u);
-  auto* c = create<Array>(create<U32>(), 3u, 4u, 8u, 32u, 16u);
-  auto* d = create<Array>(create<U32>(), 2u, 5u, 8u, 32u, 16u);
-  auto* e = create<Array>(create<U32>(), 2u, 4u, 9u, 32u, 16u);
-  auto* f = create<Array>(create<U32>(), 2u, 4u, 8u, 33u, 16u);
-  auto* g = create<Array>(create<U32>(), 2u, 4u, 8u, 33u, 17u);
+    auto* a = create<Array>(create<U32>(), 2u, 4u, 8u, 32u, 16u);
+    auto* b = create<Array>(create<U32>(), 2u, 4u, 8u, 32u, 16u);
+    auto* c = create<Array>(create<U32>(), 3u, 4u, 8u, 32u, 16u);
+    auto* d = create<Array>(create<U32>(), 2u, 5u, 8u, 32u, 16u);
+    auto* e = create<Array>(create<U32>(), 2u, 4u, 9u, 32u, 16u);
+    auto* f = create<Array>(create<U32>(), 2u, 4u, 8u, 33u, 16u);
+    auto* g = create<Array>(create<U32>(), 2u, 4u, 8u, 33u, 17u);
 
-  EXPECT_EQ(a->ElemType(), create<U32>());
-  EXPECT_EQ(a->Count(), 2u);
-  EXPECT_EQ(a->Align(), 4u);
-  EXPECT_EQ(a->Size(), 8u);
-  EXPECT_EQ(a->Stride(), 32u);
-  EXPECT_EQ(a->ImplicitStride(), 16u);
-  EXPECT_FALSE(a->IsStrideImplicit());
-  EXPECT_FALSE(a->IsRuntimeSized());
+    EXPECT_EQ(a->ElemType(), create<U32>());
+    EXPECT_EQ(a->Count(), 2u);
+    EXPECT_EQ(a->Align(), 4u);
+    EXPECT_EQ(a->Size(), 8u);
+    EXPECT_EQ(a->Stride(), 32u);
+    EXPECT_EQ(a->ImplicitStride(), 16u);
+    EXPECT_FALSE(a->IsStrideImplicit());
+    EXPECT_FALSE(a->IsRuntimeSized());
 
-  EXPECT_EQ(a, b);
-  EXPECT_NE(a, c);
-  EXPECT_NE(a, d);
-  EXPECT_NE(a, e);
-  EXPECT_NE(a, f);
-  EXPECT_NE(a, g);
+    EXPECT_EQ(a, b);
+    EXPECT_NE(a, c);
+    EXPECT_NE(a, d);
+    EXPECT_NE(a, e);
+    EXPECT_NE(a, f);
+    EXPECT_NE(a, g);
 }
 
 TEST_F(ArrayTest, CreateRuntimeArray) {
-  auto* a = create<Array>(create<U32>(), 0u, 4u, 8u, 32u, 32u);
-  auto* b = create<Array>(create<U32>(), 0u, 4u, 8u, 32u, 32u);
-  auto* c = create<Array>(create<U32>(), 0u, 5u, 8u, 32u, 32u);
-  auto* d = create<Array>(create<U32>(), 0u, 4u, 9u, 32u, 32u);
-  auto* e = create<Array>(create<U32>(), 0u, 4u, 8u, 33u, 32u);
-  auto* f = create<Array>(create<U32>(), 0u, 4u, 8u, 33u, 17u);
+    auto* a = create<Array>(create<U32>(), 0u, 4u, 8u, 32u, 32u);
+    auto* b = create<Array>(create<U32>(), 0u, 4u, 8u, 32u, 32u);
+    auto* c = create<Array>(create<U32>(), 0u, 5u, 8u, 32u, 32u);
+    auto* d = create<Array>(create<U32>(), 0u, 4u, 9u, 32u, 32u);
+    auto* e = create<Array>(create<U32>(), 0u, 4u, 8u, 33u, 32u);
+    auto* f = create<Array>(create<U32>(), 0u, 4u, 8u, 33u, 17u);
 
-  EXPECT_EQ(a->ElemType(), create<U32>());
-  EXPECT_EQ(a->Count(), 0u);
-  EXPECT_EQ(a->Align(), 4u);
-  EXPECT_EQ(a->Size(), 8u);
-  EXPECT_EQ(a->Stride(), 32u);
-  EXPECT_EQ(a->ImplicitStride(), 32u);
-  EXPECT_TRUE(a->IsStrideImplicit());
-  EXPECT_TRUE(a->IsRuntimeSized());
+    EXPECT_EQ(a->ElemType(), create<U32>());
+    EXPECT_EQ(a->Count(), 0u);
+    EXPECT_EQ(a->Align(), 4u);
+    EXPECT_EQ(a->Size(), 8u);
+    EXPECT_EQ(a->Stride(), 32u);
+    EXPECT_EQ(a->ImplicitStride(), 32u);
+    EXPECT_TRUE(a->IsStrideImplicit());
+    EXPECT_TRUE(a->IsRuntimeSized());
 
-  EXPECT_EQ(a, b);
-  EXPECT_NE(a, c);
-  EXPECT_NE(a, d);
-  EXPECT_NE(a, e);
-  EXPECT_NE(a, f);
+    EXPECT_EQ(a, b);
+    EXPECT_NE(a, c);
+    EXPECT_NE(a, d);
+    EXPECT_NE(a, e);
+    EXPECT_NE(a, f);
 }
 
 TEST_F(ArrayTest, Hash) {
-  auto* a = create<Array>(create<U32>(), 2u, 4u, 8u, 32u, 16u);
-  auto* b = create<Array>(create<U32>(), 2u, 4u, 8u, 32u, 16u);
-  auto* c = create<Array>(create<U32>(), 3u, 4u, 8u, 32u, 16u);
-  auto* d = create<Array>(create<U32>(), 2u, 5u, 8u, 32u, 16u);
-  auto* e = create<Array>(create<U32>(), 2u, 4u, 9u, 32u, 16u);
-  auto* f = create<Array>(create<U32>(), 2u, 4u, 8u, 33u, 16u);
-  auto* g = create<Array>(create<U32>(), 2u, 4u, 8u, 33u, 17u);
+    auto* a = create<Array>(create<U32>(), 2u, 4u, 8u, 32u, 16u);
+    auto* b = create<Array>(create<U32>(), 2u, 4u, 8u, 32u, 16u);
+    auto* c = create<Array>(create<U32>(), 3u, 4u, 8u, 32u, 16u);
+    auto* d = create<Array>(create<U32>(), 2u, 5u, 8u, 32u, 16u);
+    auto* e = create<Array>(create<U32>(), 2u, 4u, 9u, 32u, 16u);
+    auto* f = create<Array>(create<U32>(), 2u, 4u, 8u, 33u, 16u);
+    auto* g = create<Array>(create<U32>(), 2u, 4u, 8u, 33u, 17u);
 
-  EXPECT_EQ(a->Hash(), b->Hash());
-  EXPECT_NE(a->Hash(), c->Hash());
-  EXPECT_NE(a->Hash(), d->Hash());
-  EXPECT_NE(a->Hash(), e->Hash());
-  EXPECT_NE(a->Hash(), f->Hash());
-  EXPECT_NE(a->Hash(), g->Hash());
+    EXPECT_EQ(a->Hash(), b->Hash());
+    EXPECT_NE(a->Hash(), c->Hash());
+    EXPECT_NE(a->Hash(), d->Hash());
+    EXPECT_NE(a->Hash(), e->Hash());
+    EXPECT_NE(a->Hash(), f->Hash());
+    EXPECT_NE(a->Hash(), g->Hash());
 }
 
 TEST_F(ArrayTest, Equals) {
-  auto* a = create<Array>(create<U32>(), 2u, 4u, 8u, 32u, 16u);
-  auto* b = create<Array>(create<U32>(), 2u, 4u, 8u, 32u, 16u);
-  auto* c = create<Array>(create<U32>(), 3u, 4u, 8u, 32u, 16u);
-  auto* d = create<Array>(create<U32>(), 2u, 5u, 8u, 32u, 16u);
-  auto* e = create<Array>(create<U32>(), 2u, 4u, 9u, 32u, 16u);
-  auto* f = create<Array>(create<U32>(), 2u, 4u, 8u, 33u, 16u);
-  auto* g = create<Array>(create<U32>(), 2u, 4u, 8u, 33u, 17u);
+    auto* a = create<Array>(create<U32>(), 2u, 4u, 8u, 32u, 16u);
+    auto* b = create<Array>(create<U32>(), 2u, 4u, 8u, 32u, 16u);
+    auto* c = create<Array>(create<U32>(), 3u, 4u, 8u, 32u, 16u);
+    auto* d = create<Array>(create<U32>(), 2u, 5u, 8u, 32u, 16u);
+    auto* e = create<Array>(create<U32>(), 2u, 4u, 9u, 32u, 16u);
+    auto* f = create<Array>(create<U32>(), 2u, 4u, 8u, 33u, 16u);
+    auto* g = create<Array>(create<U32>(), 2u, 4u, 8u, 33u, 17u);
 
-  EXPECT_TRUE(a->Equals(*b));
-  EXPECT_FALSE(a->Equals(*c));
-  EXPECT_FALSE(a->Equals(*d));
-  EXPECT_FALSE(a->Equals(*e));
-  EXPECT_FALSE(a->Equals(*f));
-  EXPECT_FALSE(a->Equals(*g));
-  EXPECT_FALSE(a->Equals(Void{}));
+    EXPECT_TRUE(a->Equals(*b));
+    EXPECT_FALSE(a->Equals(*c));
+    EXPECT_FALSE(a->Equals(*d));
+    EXPECT_FALSE(a->Equals(*e));
+    EXPECT_FALSE(a->Equals(*f));
+    EXPECT_FALSE(a->Equals(*g));
+    EXPECT_FALSE(a->Equals(Void{}));
 }
 
 TEST_F(ArrayTest, FriendlyNameRuntimeSized) {
-  auto* arr = create<Array>(create<I32>(), 0u, 0u, 4u, 4u, 4u);
-  EXPECT_EQ(arr->FriendlyName(Symbols()), "array<i32>");
+    auto* arr = create<Array>(create<I32>(), 0u, 0u, 4u, 4u, 4u);
+    EXPECT_EQ(arr->FriendlyName(Symbols()), "array<i32>");
 }
 
 TEST_F(ArrayTest, FriendlyNameStaticSized) {
-  auto* arr = create<Array>(create<I32>(), 5u, 4u, 20u, 4u, 4u);
-  EXPECT_EQ(arr->FriendlyName(Symbols()), "array<i32, 5>");
+    auto* arr = create<Array>(create<I32>(), 5u, 4u, 20u, 4u, 4u);
+    EXPECT_EQ(arr->FriendlyName(Symbols()), "array<i32, 5>");
 }
 
 TEST_F(ArrayTest, FriendlyNameRuntimeSizedNonImplicitStride) {
-  auto* arr = create<Array>(create<I32>(), 0u, 0u, 4u, 8u, 4u);
-  EXPECT_EQ(arr->FriendlyName(Symbols()), "@stride(8) array<i32>");
+    auto* arr = create<Array>(create<I32>(), 0u, 0u, 4u, 8u, 4u);
+    EXPECT_EQ(arr->FriendlyName(Symbols()), "@stride(8) array<i32>");
 }
 
 TEST_F(ArrayTest, FriendlyNameStaticSizedNonImplicitStride) {
-  auto* arr = create<Array>(create<I32>(), 5u, 4u, 20u, 8u, 4u);
-  EXPECT_EQ(arr->FriendlyName(Symbols()), "@stride(8) array<i32, 5>");
+    auto* arr = create<Array>(create<I32>(), 5u, 4u, 20u, 8u, 4u);
+    EXPECT_EQ(arr->FriendlyName(Symbols()), "@stride(8) array<i32, 5>");
 }
 
 }  // namespace
diff --git a/src/tint/sem/sem_struct_test.cc b/src/tint/sem/sem_struct_test.cc
index d788be9..4a63712 100644
--- a/src/tint/sem/sem_struct_test.cc
+++ b/src/tint/sem/sem_struct_test.cc
@@ -14,7 +14,7 @@
 
 #include "src/tint/sem/struct.h"
 #include "src/tint/sem/test_helper.h"
-#include "src/tint/sem/texture_type.h"
+#include "src/tint/sem/texture.h"
 
 namespace tint::sem {
 namespace {
@@ -22,85 +22,72 @@
 using StructTest = TestHelper;
 
 TEST_F(StructTest, Creation) {
-  auto name = Sym("S");
-  auto* impl =
-      create<ast::Struct>(name, ast::StructMemberList{}, ast::AttributeList{});
-  auto* ptr = impl;
-  auto* s =
-      create<sem::Struct>(impl, impl->name, StructMemberList{}, 4u /* align */,
-                          8u /* size */, 16u /* size_no_padding */);
-  EXPECT_EQ(s->Declaration(), ptr);
-  EXPECT_EQ(s->Align(), 4u);
-  EXPECT_EQ(s->Size(), 8u);
-  EXPECT_EQ(s->SizeNoPadding(), 16u);
+    auto name = Sym("S");
+    auto* impl = create<ast::Struct>(name, ast::StructMemberList{}, ast::AttributeList{});
+    auto* ptr = impl;
+    auto* s = create<sem::Struct>(impl, impl->name, StructMemberList{}, 4u /* align */,
+                                  8u /* size */, 16u /* size_no_padding */);
+    EXPECT_EQ(s->Declaration(), ptr);
+    EXPECT_EQ(s->Align(), 4u);
+    EXPECT_EQ(s->Size(), 8u);
+    EXPECT_EQ(s->SizeNoPadding(), 16u);
 }
 
 TEST_F(StructTest, Hash) {
-  auto* a_impl = create<ast::Struct>(Sym("a"), ast::StructMemberList{},
-                                     ast::AttributeList{});
-  auto* a = create<sem::Struct>(a_impl, a_impl->name, StructMemberList{},
-                                4u /* align */, 4u /* size */,
-                                4u /* size_no_padding */);
-  auto* b_impl = create<ast::Struct>(Sym("b"), ast::StructMemberList{},
-                                     ast::AttributeList{});
-  auto* b = create<sem::Struct>(b_impl, b_impl->name, StructMemberList{},
-                                4u /* align */, 4u /* size */,
-                                4u /* size_no_padding */);
+    auto* a_impl = create<ast::Struct>(Sym("a"), ast::StructMemberList{}, ast::AttributeList{});
+    auto* a = create<sem::Struct>(a_impl, a_impl->name, StructMemberList{}, 4u /* align */,
+                                  4u /* size */, 4u /* size_no_padding */);
+    auto* b_impl = create<ast::Struct>(Sym("b"), ast::StructMemberList{}, ast::AttributeList{});
+    auto* b = create<sem::Struct>(b_impl, b_impl->name, StructMemberList{}, 4u /* align */,
+                                  4u /* size */, 4u /* size_no_padding */);
 
-  EXPECT_NE(a->Hash(), b->Hash());
+    EXPECT_NE(a->Hash(), b->Hash());
 }
 
 TEST_F(StructTest, Equals) {
-  auto* a_impl = create<ast::Struct>(Sym("a"), ast::StructMemberList{},
-                                     ast::AttributeList{});
-  auto* a = create<sem::Struct>(a_impl, a_impl->name, StructMemberList{},
-                                4u /* align */, 4u /* size */,
-                                4u /* size_no_padding */);
-  auto* b_impl = create<ast::Struct>(Sym("b"), ast::StructMemberList{},
-                                     ast::AttributeList{});
-  auto* b = create<sem::Struct>(b_impl, b_impl->name, StructMemberList{},
-                                4u /* align */, 4u /* size */,
-                                4u /* size_no_padding */);
+    auto* a_impl = create<ast::Struct>(Sym("a"), ast::StructMemberList{}, ast::AttributeList{});
+    auto* a = create<sem::Struct>(a_impl, a_impl->name, StructMemberList{}, 4u /* align */,
+                                  4u /* size */, 4u /* size_no_padding */);
+    auto* b_impl = create<ast::Struct>(Sym("b"), ast::StructMemberList{}, ast::AttributeList{});
+    auto* b = create<sem::Struct>(b_impl, b_impl->name, StructMemberList{}, 4u /* align */,
+                                  4u /* size */, 4u /* size_no_padding */);
 
-  EXPECT_TRUE(a->Equals(*a));
-  EXPECT_FALSE(a->Equals(*b));
-  EXPECT_FALSE(a->Equals(Void{}));
+    EXPECT_TRUE(a->Equals(*a));
+    EXPECT_FALSE(a->Equals(*b));
+    EXPECT_FALSE(a->Equals(Void{}));
 }
 
 TEST_F(StructTest, FriendlyName) {
-  auto name = Sym("my_struct");
-  auto* impl =
-      create<ast::Struct>(name, ast::StructMemberList{}, ast::AttributeList{});
-  auto* s =
-      create<sem::Struct>(impl, impl->name, StructMemberList{}, 4u /* align */,
-                          4u /* size */, 4u /* size_no_padding */);
-  EXPECT_EQ(s->FriendlyName(Symbols()), "my_struct");
+    auto name = Sym("my_struct");
+    auto* impl = create<ast::Struct>(name, ast::StructMemberList{}, ast::AttributeList{});
+    auto* s = create<sem::Struct>(impl, impl->name, StructMemberList{}, 4u /* align */,
+                                  4u /* size */, 4u /* size_no_padding */);
+    EXPECT_EQ(s->FriendlyName(Symbols()), "my_struct");
 }
 
 TEST_F(StructTest, Layout) {
-  auto* inner_st =  //
-      Structure("Inner", {
-                             Member("a", ty.i32()),
-                             Member("b", ty.u32()),
-                             Member("c", ty.f32()),
-                             Member("d", ty.vec3<f32>()),
-                             Member("e", ty.mat4x2<f32>()),
-                         });
+    auto* inner_st =  //
+        Structure("Inner", {
+                               Member("a", ty.i32()),
+                               Member("b", ty.u32()),
+                               Member("c", ty.f32()),
+                               Member("d", ty.vec3<f32>()),
+                               Member("e", ty.mat4x2<f32>()),
+                           });
 
-  auto* outer_st =
-      Structure("Outer", {
-                             Member("inner", ty.type_name("Inner")),
-                             Member("a", ty.i32()),
-                         });
+    auto* outer_st = Structure("Outer", {
+                                            Member("inner", ty.type_name("Inner")),
+                                            Member("a", ty.i32()),
+                                        });
 
-  auto p = Build();
-  ASSERT_TRUE(p.IsValid()) << p.Diagnostics().str();
+    auto p = Build();
+    ASSERT_TRUE(p.IsValid()) << p.Diagnostics().str();
 
-  auto* sem_inner_st = p.Sem().Get(inner_st);
-  auto* sem_outer_st = p.Sem().Get(outer_st);
+    auto* sem_inner_st = p.Sem().Get(inner_st);
+    auto* sem_outer_st = p.Sem().Get(outer_st);
 
-  EXPECT_EQ(sem_inner_st->Layout(p.Symbols()),
-            R"(/*            align(16) size(64) */ struct Inner {
+    EXPECT_EQ(sem_inner_st->Layout(p.Symbols()),
+              R"(/*            align(16) size(64) */ struct Inner {
 /* offset( 0) align( 4) size( 4) */   a : i32;
 /* offset( 4) align( 4) size( 4) */   b : u32;
 /* offset( 8) align( 4) size( 4) */   c : f32;
@@ -110,8 +97,8 @@
 /* offset(32) align( 8) size(32) */   e : mat4x2<f32>;
 /*                               */ };)");
 
-  EXPECT_EQ(sem_outer_st->Layout(p.Symbols()),
-            R"(/*            align(16) size(80) */ struct Outer {
+    EXPECT_EQ(sem_outer_st->Layout(p.Symbols()),
+              R"(/*            align(16) size(80) */ struct Outer {
 /* offset( 0) align(16) size(64) */   inner : Inner;
 /* offset(64) align( 4) size( 4) */   a : i32;
 /* offset(68) align( 1) size(12) */   // -- implicit struct size padding --;
diff --git a/src/tint/sem/statement.cc b/src/tint/sem/statement.cc
index 2046f63..fb8e557 100644
--- a/src/tint/sem/statement.cc
+++ b/src/tint/sem/statement.cc
@@ -33,7 +33,7 @@
 Statement::~Statement() = default;
 
 const BlockStatement* Statement::Block() const {
-  return FindFirstParent<BlockStatement>();
+    return FindFirstParent<BlockStatement>();
 }
 
 CompoundStatement::CompoundStatement(const ast::Statement* declaration,
diff --git a/src/tint/sem/statement.h b/src/tint/sem/statement.h
index 76336d7..741a325 100644
--- a/src/tint/sem/statement.h
+++ b/src/tint/sem/statement.h
@@ -37,143 +37,141 @@
 /// resolves to CompoundStatement.
 template <typename... TYPES>
 struct FindFirstParentReturn {
-  /// The pointer type returned by Statement::FindFirstParent()
-  using type = CompoundStatement;
+    /// The pointer type returned by Statement::FindFirstParent()
+    using type = CompoundStatement;
 };
 
 /// A specialization of FindFirstParentReturn for a single template argument.
 /// FindFirstParentReturn::type resolves to the single template argument.
 template <typename T>
 struct FindFirstParentReturn<T> {
-  /// The pointer type returned by Statement::FindFirstParent()
-  using type = T;
+    /// The pointer type returned by Statement::FindFirstParent()
+    using type = T;
 };
 
 template <typename... TYPES>
-using FindFirstParentReturnType =
-    typename FindFirstParentReturn<TYPES...>::type;
+using FindFirstParentReturnType = typename FindFirstParentReturn<TYPES...>::type;
 }  // namespace detail
 
 /// Statement holds the semantic information for a statement.
 class Statement : public Castable<Statement, Node> {
- public:
-  /// Constructor
-  /// @param declaration the AST node for this statement
-  /// @param parent the owning statement
-  /// @param function the owning function
-  Statement(const ast::Statement* declaration,
-            const CompoundStatement* parent,
-            const sem::Function* function);
+  public:
+    /// Constructor
+    /// @param declaration the AST node for this statement
+    /// @param parent the owning statement
+    /// @param function the owning function
+    Statement(const ast::Statement* declaration,
+              const CompoundStatement* parent,
+              const sem::Function* function);
 
-  /// Destructor
-  ~Statement() override;
+    /// Destructor
+    ~Statement() override;
 
-  /// @return the AST node for this statement
-  const ast::Statement* Declaration() const { return declaration_; }
+    /// @return the AST node for this statement
+    const ast::Statement* Declaration() const { return declaration_; }
 
-  /// @return the statement that encloses this statement
-  const CompoundStatement* Parent() const { return parent_; }
+    /// @return the statement that encloses this statement
+    const CompoundStatement* Parent() const { return parent_; }
 
-  /// @returns the closest enclosing parent that satisfies the given predicate,
-  /// which may be the statement itself, or nullptr if no match is found.
-  /// @param pred a predicate that the resulting block must satisfy
-  template <typename Pred>
-  const CompoundStatement* FindFirstParent(Pred&& pred) const;
+    /// @returns the closest enclosing parent that satisfies the given predicate,
+    /// which may be the statement itself, or nullptr if no match is found.
+    /// @param pred a predicate that the resulting block must satisfy
+    template <typename Pred>
+    const CompoundStatement* FindFirstParent(Pred&& pred) const;
 
-  /// @returns the closest enclosing parent that is of one of the types in
-  /// `TYPES`, which may be the statement itself, or nullptr if no match is
-  /// found. If `TYPES` is a single template argument, the return type is a
-  /// pointer to that template argument type, otherwise a CompoundStatement
-  /// pointer is returned.
-  template <typename... TYPES>
-  const detail::FindFirstParentReturnType<TYPES...>* FindFirstParent() const;
+    /// @returns the closest enclosing parent that is of one of the types in
+    /// `TYPES`, which may be the statement itself, or nullptr if no match is
+    /// found. If `TYPES` is a single template argument, the return type is a
+    /// pointer to that template argument type, otherwise a CompoundStatement
+    /// pointer is returned.
+    template <typename... TYPES>
+    const detail::FindFirstParentReturnType<TYPES...>* FindFirstParent() const;
 
-  /// @return the closest enclosing block for this statement
-  const BlockStatement* Block() const;
+    /// @return the closest enclosing block for this statement
+    const BlockStatement* Block() const;
 
-  /// @returns the function that owns this statement
-  const sem::Function* Function() const { return function_; }
+    /// @returns the function that owns this statement
+    const sem::Function* Function() const { return function_; }
 
-  /// @return the behaviors of this statement
-  const sem::Behaviors& Behaviors() const { return behaviors_; }
+    /// @return the behaviors of this statement
+    const sem::Behaviors& Behaviors() const { return behaviors_; }
 
-  /// @return the behaviors of this statement
-  sem::Behaviors& Behaviors() { return behaviors_; }
+    /// @return the behaviors of this statement
+    sem::Behaviors& Behaviors() { return behaviors_; }
 
-  /// @returns true if this statement is reachable by control flow according to
-  /// the behavior analysis
-  bool IsReachable() const { return is_reachable_; }
+    /// @returns true if this statement is reachable by control flow according to
+    /// the behavior analysis
+    bool IsReachable() const { return is_reachable_; }
 
-  /// @param is_reachable whether this statement is reachable by control flow
-  /// according to the behavior analysis
-  void SetIsReachable(bool is_reachable) { is_reachable_ = is_reachable; }
+    /// @param is_reachable whether this statement is reachable by control flow
+    /// according to the behavior analysis
+    void SetIsReachable(bool is_reachable) { is_reachable_ = is_reachable; }
 
- private:
-  const ast::Statement* const declaration_;
-  const CompoundStatement* const parent_;
-  const sem::Function* const function_;
-  sem::Behaviors behaviors_{sem::Behavior::kNext};
-  bool is_reachable_ = true;
+  private:
+    const ast::Statement* const declaration_;
+    const CompoundStatement* const parent_;
+    const sem::Function* const function_;
+    sem::Behaviors behaviors_{sem::Behavior::kNext};
+    bool is_reachable_ = true;
 };
 
 /// CompoundStatement is the base class of statements that can hold other
 /// statements.
 class CompoundStatement : public Castable<Statement, Statement> {
- public:
-  /// Constructor
-  /// @param declaration the AST node for this statement
-  /// @param statement the owning statement
-  /// @param function the owning function
-  CompoundStatement(const ast::Statement* declaration,
-                    const CompoundStatement* statement,
-                    const sem::Function* function);
+  public:
+    /// Constructor
+    /// @param declaration the AST node for this statement
+    /// @param statement the owning statement
+    /// @param function the owning function
+    CompoundStatement(const ast::Statement* declaration,
+                      const CompoundStatement* statement,
+                      const sem::Function* function);
 
-  /// Destructor
-  ~CompoundStatement() override;
+    /// Destructor
+    ~CompoundStatement() override;
 };
 
 template <typename Pred>
 const CompoundStatement* Statement::FindFirstParent(Pred&& pred) const {
-  if (auto* self = As<CompoundStatement>()) {
-    if (pred(self)) {
-      return self;
+    if (auto* self = As<CompoundStatement>()) {
+        if (pred(self)) {
+            return self;
+        }
     }
-  }
-  const auto* curr = parent_;
-  while (curr && !pred(curr)) {
-    curr = curr->Parent();
-  }
-  return curr;
+    const auto* curr = parent_;
+    while (curr && !pred(curr)) {
+        curr = curr->Parent();
+    }
+    return curr;
 }
 
 template <typename... TYPES>
-const detail::FindFirstParentReturnType<TYPES...>* Statement::FindFirstParent()
-    const {
-  using ReturnType = detail::FindFirstParentReturnType<TYPES...>;
-  if (sizeof...(TYPES) == 1) {
-    if (auto* p = As<ReturnType>()) {
-      return p;
+const detail::FindFirstParentReturnType<TYPES...>* Statement::FindFirstParent() const {
+    using ReturnType = detail::FindFirstParentReturnType<TYPES...>;
+    if (sizeof...(TYPES) == 1) {
+        if (auto* p = As<ReturnType>()) {
+            return p;
+        }
+        const auto* curr = parent_;
+        while (curr) {
+            if (auto* p = curr->As<ReturnType>()) {
+                return p;
+            }
+            curr = curr->Parent();
+        }
+    } else {
+        if (IsAnyOf<TYPES...>()) {
+            return As<ReturnType>();
+        }
+        const auto* curr = parent_;
+        while (curr) {
+            if (curr->IsAnyOf<TYPES...>()) {
+                return curr->As<ReturnType>();
+            }
+            curr = curr->Parent();
+        }
     }
-    const auto* curr = parent_;
-    while (curr) {
-      if (auto* p = curr->As<ReturnType>()) {
-        return p;
-      }
-      curr = curr->Parent();
-    }
-  } else {
-    if (IsAnyOf<TYPES...>()) {
-      return As<ReturnType>();
-    }
-    const auto* curr = parent_;
-    while (curr) {
-      if (curr->IsAnyOf<TYPES...>()) {
-        return curr->As<ReturnType>();
-      }
-      curr = curr->Parent();
-    }
-  }
-  return nullptr;
+    return nullptr;
 }
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/storage_texture.cc b/src/tint/sem/storage_texture.cc
new file mode 100644
index 0000000..d8393d7
--- /dev/null
+++ b/src/tint/sem/storage_texture.cc
@@ -0,0 +1,85 @@
+// 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/sem/storage_texture.h"
+
+#include "src/tint/program_builder.h"
+#include "src/tint/utils/hash.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::sem::StorageTexture);
+
+namespace tint::sem {
+
+StorageTexture::StorageTexture(ast::TextureDimension dim,
+                               ast::TexelFormat format,
+                               ast::Access access,
+                               sem::Type* subtype)
+    : Base(dim), texel_format_(format), access_(access), subtype_(subtype) {}
+
+StorageTexture::StorageTexture(StorageTexture&&) = default;
+
+StorageTexture::~StorageTexture() = default;
+
+size_t StorageTexture::Hash() const {
+    return utils::Hash(TypeInfo::Of<StorageTexture>().full_hashcode, dim(), texel_format_, access_);
+}
+
+bool StorageTexture::Equals(const sem::Type& other) const {
+    if (auto* o = other.As<StorageTexture>()) {
+        return o->dim() == dim() && o->texel_format_ == texel_format_ && o->access_ == access_;
+    }
+    return false;
+}
+
+std::string StorageTexture::FriendlyName(const SymbolTable&) const {
+    std::ostringstream out;
+    out << "texture_storage_" << dim() << "<" << texel_format_ << ", " << access_ << ">";
+    return out.str();
+}
+
+sem::Type* StorageTexture::SubtypeFor(ast::TexelFormat format, sem::Manager& type_mgr) {
+    switch (format) {
+        case ast::TexelFormat::kR32Uint:
+        case ast::TexelFormat::kRgba8Uint:
+        case ast::TexelFormat::kRg32Uint:
+        case ast::TexelFormat::kRgba16Uint:
+        case ast::TexelFormat::kRgba32Uint: {
+            return type_mgr.Get<sem::U32>();
+        }
+
+        case ast::TexelFormat::kR32Sint:
+        case ast::TexelFormat::kRgba8Sint:
+        case ast::TexelFormat::kRg32Sint:
+        case ast::TexelFormat::kRgba16Sint:
+        case ast::TexelFormat::kRgba32Sint: {
+            return type_mgr.Get<sem::I32>();
+        }
+
+        case ast::TexelFormat::kRgba8Unorm:
+        case ast::TexelFormat::kRgba8Snorm:
+        case ast::TexelFormat::kR32Float:
+        case ast::TexelFormat::kRg32Float:
+        case ast::TexelFormat::kRgba16Float:
+        case ast::TexelFormat::kRgba32Float: {
+            return type_mgr.Get<sem::F32>();
+        }
+
+        case ast::TexelFormat::kNone:
+            break;
+    }
+
+    return nullptr;
+}
+
+}  // namespace tint::sem
diff --git a/src/tint/sem/storage_texture.h b/src/tint/sem/storage_texture.h
new file mode 100644
index 0000000..68dbff9
--- /dev/null
+++ b/src/tint/sem/storage_texture.h
@@ -0,0 +1,82 @@
+// 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_SEM_STORAGE_TEXTURE_H_
+#define SRC_TINT_SEM_STORAGE_TEXTURE_H_
+
+#include <string>
+
+#include "src/tint/ast/access.h"
+#include "src/tint/ast/storage_texture.h"
+#include "src/tint/sem/texture.h"
+
+// Forward declarations
+namespace tint::sem {
+class Manager;
+}  // namespace tint::sem
+
+namespace tint::sem {
+
+/// A storage texture type.
+class StorageTexture final : public Castable<StorageTexture, Texture> {
+  public:
+    /// Constructor
+    /// @param dim the dimensionality of the texture
+    /// @param format the texel format of the texture
+    /// @param access the access control type of the texture
+    /// @param subtype the storage subtype. Use SubtypeFor() to calculate this.
+    StorageTexture(ast::TextureDimension dim,
+                   ast::TexelFormat format,
+                   ast::Access access,
+                   sem::Type* subtype);
+
+    /// Move constructor
+    StorageTexture(StorageTexture&&);
+    ~StorageTexture() override;
+
+    /// @returns a hash of the type.
+    size_t Hash() const override;
+
+    /// @param other the other type to compare against
+    /// @returns true if the this type is equal to the given type
+    bool Equals(const Type& other) const override;
+
+    /// @returns the storage subtype
+    Type* type() const { return subtype_; }
+
+    /// @returns the texel format
+    ast::TexelFormat texel_format() const { return texel_format_; }
+
+    /// @returns the access control
+    ast::Access access() const { return access_; }
+
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type that closely resembles how it would be
+    /// declared in WGSL.
+    std::string FriendlyName(const SymbolTable& symbols) const override;
+
+    /// @param format the storage texture image format
+    /// @param type_mgr the sem::Manager used to build the returned type
+    /// @returns the storage texture subtype for the given TexelFormat
+    static sem::Type* SubtypeFor(ast::TexelFormat format, sem::Manager& type_mgr);
+
+  private:
+    ast::TexelFormat const texel_format_;
+    ast::Access const access_;
+    Type* const subtype_;
+};
+
+}  // namespace tint::sem
+
+#endif  // SRC_TINT_SEM_STORAGE_TEXTURE_H_
diff --git a/src/tint/sem/storage_texture_test.cc b/src/tint/sem/storage_texture_test.cc
new file mode 100644
index 0000000..8a9351e
--- /dev/null
+++ b/src/tint/sem/storage_texture_test.cc
@@ -0,0 +1,147 @@
+// 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/sem/storage_texture.h"
+
+#include "src/tint/sem/depth_texture.h"
+#include "src/tint/sem/external_texture.h"
+#include "src/tint/sem/sampled_texture.h"
+#include "src/tint/sem/test_helper.h"
+
+namespace tint::sem {
+namespace {
+
+struct StorageTextureTest : public TestHelper {
+    StorageTexture* Create(ast::TextureDimension dims, ast::TexelFormat fmt, ast::Access access) {
+        auto* subtype = StorageTexture::SubtypeFor(fmt, Types());
+        return create<StorageTexture>(dims, fmt, access, subtype);
+    }
+};
+
+TEST_F(StorageTextureTest, Creation) {
+    auto* a = Create(ast::TextureDimension::kCube, ast::TexelFormat::kRgba32Float,
+                     ast::Access::kReadWrite);
+    auto* b = Create(ast::TextureDimension::kCube, ast::TexelFormat::kRgba32Float,
+                     ast::Access::kReadWrite);
+    auto* c =
+        Create(ast::TextureDimension::k2d, ast::TexelFormat::kRgba32Float, ast::Access::kReadWrite);
+    auto* d =
+        Create(ast::TextureDimension::kCube, ast::TexelFormat::kR32Float, ast::Access::kReadWrite);
+    auto* e =
+        Create(ast::TextureDimension::kCube, ast::TexelFormat::kRgba32Float, ast::Access::kRead);
+
+    EXPECT_TRUE(a->type()->Is<F32>());
+    EXPECT_EQ(a->dim(), ast::TextureDimension::kCube);
+
+    EXPECT_EQ(a, b);
+    EXPECT_NE(a, c);
+    EXPECT_NE(a, d);
+    EXPECT_NE(a, e);
+}
+
+TEST_F(StorageTextureTest, Hash) {
+    auto* a = Create(ast::TextureDimension::kCube, ast::TexelFormat::kRgba32Float,
+                     ast::Access::kReadWrite);
+    auto* b = Create(ast::TextureDimension::kCube, ast::TexelFormat::kRgba32Float,
+                     ast::Access::kReadWrite);
+    auto* c =
+        Create(ast::TextureDimension::k2d, ast::TexelFormat::kRgba32Float, ast::Access::kReadWrite);
+    auto* d =
+        Create(ast::TextureDimension::kCube, ast::TexelFormat::kR32Float, ast::Access::kReadWrite);
+    auto* e =
+        Create(ast::TextureDimension::kCube, ast::TexelFormat::kRgba32Float, ast::Access::kRead);
+
+    EXPECT_EQ(a->Hash(), b->Hash());
+    EXPECT_NE(a->Hash(), c->Hash());
+    EXPECT_NE(a->Hash(), d->Hash());
+    EXPECT_NE(a->Hash(), e->Hash());
+}
+
+TEST_F(StorageTextureTest, Equals) {
+    auto* a = Create(ast::TextureDimension::kCube, ast::TexelFormat::kRgba32Float,
+                     ast::Access::kReadWrite);
+    auto* b = Create(ast::TextureDimension::kCube, ast::TexelFormat::kRgba32Float,
+                     ast::Access::kReadWrite);
+    auto* c =
+        Create(ast::TextureDimension::k2d, ast::TexelFormat::kRgba32Float, ast::Access::kReadWrite);
+    auto* d =
+        Create(ast::TextureDimension::kCube, ast::TexelFormat::kR32Float, ast::Access::kReadWrite);
+    auto* e =
+        Create(ast::TextureDimension::kCube, ast::TexelFormat::kRgba32Float, ast::Access::kRead);
+
+    EXPECT_TRUE(a->Equals(*b));
+    EXPECT_FALSE(a->Equals(*c));
+    EXPECT_FALSE(a->Equals(*d));
+    EXPECT_FALSE(a->Equals(*e));
+    EXPECT_FALSE(a->Equals(Void{}));
+}
+
+TEST_F(StorageTextureTest, Dim) {
+    auto* s = Create(ast::TextureDimension::k2dArray, ast::TexelFormat::kRgba32Float,
+                     ast::Access::kReadWrite);
+    EXPECT_EQ(s->dim(), ast::TextureDimension::k2dArray);
+}
+
+TEST_F(StorageTextureTest, Format) {
+    auto* s = Create(ast::TextureDimension::k2dArray, ast::TexelFormat::kRgba32Float,
+                     ast::Access::kReadWrite);
+    EXPECT_EQ(s->texel_format(), ast::TexelFormat::kRgba32Float);
+}
+
+TEST_F(StorageTextureTest, FriendlyName) {
+    auto* s = Create(ast::TextureDimension::k2dArray, ast::TexelFormat::kRgba32Float,
+                     ast::Access::kReadWrite);
+    EXPECT_EQ(s->FriendlyName(Symbols()), "texture_storage_2d_array<rgba32float, read_write>");
+}
+
+TEST_F(StorageTextureTest, F32) {
+    Type* s = Create(ast::TextureDimension::k2dArray, ast::TexelFormat::kRgba32Float,
+                     ast::Access::kReadWrite);
+
+    auto program = Build();
+
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    ASSERT_TRUE(s->Is<Texture>());
+    ASSERT_TRUE(s->Is<StorageTexture>());
+    EXPECT_TRUE(s->As<StorageTexture>()->type()->Is<F32>());
+}
+
+TEST_F(StorageTextureTest, U32) {
+    auto* subtype = sem::StorageTexture::SubtypeFor(ast::TexelFormat::kRg32Uint, Types());
+    Type* s = create<StorageTexture>(ast::TextureDimension::k2dArray, ast::TexelFormat::kRg32Uint,
+                                     ast::Access::kReadWrite, subtype);
+
+    auto program = Build();
+
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    ASSERT_TRUE(s->Is<Texture>());
+    ASSERT_TRUE(s->Is<StorageTexture>());
+    EXPECT_TRUE(s->As<StorageTexture>()->type()->Is<U32>());
+}
+
+TEST_F(StorageTextureTest, I32) {
+    auto* subtype = sem::StorageTexture::SubtypeFor(ast::TexelFormat::kRgba32Sint, Types());
+    Type* s = create<StorageTexture>(ast::TextureDimension::k2dArray, ast::TexelFormat::kRgba32Sint,
+                                     ast::Access::kReadWrite, subtype);
+
+    auto program = Build();
+
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    ASSERT_TRUE(s->Is<Texture>());
+    ASSERT_TRUE(s->Is<StorageTexture>());
+    EXPECT_TRUE(s->As<StorageTexture>()->type()->Is<I32>());
+}
+
+}  // namespace
+}  // namespace tint::sem
diff --git a/src/tint/sem/storage_texture_type.cc b/src/tint/sem/storage_texture_type.cc
deleted file mode 100644
index 1b017dd..0000000
--- a/src/tint/sem/storage_texture_type.cc
+++ /dev/null
@@ -1,89 +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/sem/storage_texture_type.h"
-
-#include "src/tint/program_builder.h"
-#include "src/tint/utils/hash.h"
-
-TINT_INSTANTIATE_TYPEINFO(tint::sem::StorageTexture);
-
-namespace tint::sem {
-
-StorageTexture::StorageTexture(ast::TextureDimension dim,
-                               ast::TexelFormat format,
-                               ast::Access access,
-                               sem::Type* subtype)
-    : Base(dim), texel_format_(format), access_(access), subtype_(subtype) {}
-
-StorageTexture::StorageTexture(StorageTexture&&) = default;
-
-StorageTexture::~StorageTexture() = default;
-
-size_t StorageTexture::Hash() const {
-  return utils::Hash(TypeInfo::Of<StorageTexture>().full_hashcode, dim(),
-                     texel_format_, access_);
-}
-
-bool StorageTexture::Equals(const sem::Type& other) const {
-  if (auto* o = other.As<StorageTexture>()) {
-    return o->dim() == dim() && o->texel_format_ == texel_format_ &&
-           o->access_ == access_;
-  }
-  return false;
-}
-
-std::string StorageTexture::FriendlyName(const SymbolTable&) const {
-  std::ostringstream out;
-  out << "texture_storage_" << dim() << "<" << texel_format_ << ", " << access_
-      << ">";
-  return out.str();
-}
-
-sem::Type* StorageTexture::SubtypeFor(ast::TexelFormat format,
-                                      sem::Manager& type_mgr) {
-  switch (format) {
-    case ast::TexelFormat::kR32Uint:
-    case ast::TexelFormat::kRgba8Uint:
-    case ast::TexelFormat::kRg32Uint:
-    case ast::TexelFormat::kRgba16Uint:
-    case ast::TexelFormat::kRgba32Uint: {
-      return type_mgr.Get<sem::U32>();
-    }
-
-    case ast::TexelFormat::kR32Sint:
-    case ast::TexelFormat::kRgba8Sint:
-    case ast::TexelFormat::kRg32Sint:
-    case ast::TexelFormat::kRgba16Sint:
-    case ast::TexelFormat::kRgba32Sint: {
-      return type_mgr.Get<sem::I32>();
-    }
-
-    case ast::TexelFormat::kRgba8Unorm:
-    case ast::TexelFormat::kRgba8Snorm:
-    case ast::TexelFormat::kR32Float:
-    case ast::TexelFormat::kRg32Float:
-    case ast::TexelFormat::kRgba16Float:
-    case ast::TexelFormat::kRgba32Float: {
-      return type_mgr.Get<sem::F32>();
-    }
-
-    case ast::TexelFormat::kNone:
-      break;
-  }
-
-  return nullptr;
-}
-
-}  // namespace tint::sem
diff --git a/src/tint/sem/storage_texture_type.h b/src/tint/sem/storage_texture_type.h
deleted file mode 100644
index 71569e7..0000000
--- a/src/tint/sem/storage_texture_type.h
+++ /dev/null
@@ -1,82 +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_SEM_STORAGE_TEXTURE_TYPE_H_
-#define SRC_TINT_SEM_STORAGE_TEXTURE_TYPE_H_
-
-#include <string>
-
-#include "src/tint/ast/access.h"
-#include "src/tint/ast/storage_texture.h"
-#include "src/tint/sem/texture_type.h"
-
-// Forward declarations
-namespace tint::sem {
-class Manager;
-}  // namespace tint::sem
-
-namespace tint::sem {
-
-/// A storage texture type.
-class StorageTexture final : public Castable<StorageTexture, Texture> {
- public:
-  /// Constructor
-  /// @param dim the dimensionality of the texture
-  /// @param format the texel format of the texture
-  /// @param access the access control type of the texture
-  /// @param subtype the storage subtype. Use SubtypeFor() to calculate this.
-  StorageTexture(ast::TextureDimension dim,
-                 ast::TexelFormat format,
-                 ast::Access access,
-                 sem::Type* subtype);
-
-  /// Move constructor
-  StorageTexture(StorageTexture&&);
-  ~StorageTexture() override;
-
-  /// @returns a hash of the type.
-  size_t Hash() const override;
-
-  /// @param other the other type to compare against
-  /// @returns true if the this type is equal to the given type
-  bool Equals(const Type& other) const override;
-
-  /// @returns the storage subtype
-  Type* type() const { return subtype_; }
-
-  /// @returns the texel format
-  ast::TexelFormat texel_format() const { return texel_format_; }
-
-  /// @returns the access control
-  ast::Access access() const { return access_; }
-
-  /// @param symbols the program's symbol table
-  /// @returns the name for this type that closely resembles how it would be
-  /// declared in WGSL.
-  std::string FriendlyName(const SymbolTable& symbols) const override;
-
-  /// @param format the storage texture image format
-  /// @param type_mgr the sem::Manager used to build the returned type
-  /// @returns the storage texture subtype for the given TexelFormat
-  static sem::Type* SubtypeFor(ast::TexelFormat format, sem::Manager& type_mgr);
-
- private:
-  ast::TexelFormat const texel_format_;
-  ast::Access const access_;
-  Type* const subtype_;
-};
-
-}  // namespace tint::sem
-
-#endif  // SRC_TINT_SEM_STORAGE_TEXTURE_TYPE_H_
diff --git a/src/tint/sem/storage_texture_type_test.cc b/src/tint/sem/storage_texture_type_test.cc
deleted file mode 100644
index 73361ce..0000000
--- a/src/tint/sem/storage_texture_type_test.cc
+++ /dev/null
@@ -1,154 +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/sem/storage_texture_type.h"
-
-#include "src/tint/sem/depth_texture_type.h"
-#include "src/tint/sem/external_texture_type.h"
-#include "src/tint/sem/sampled_texture_type.h"
-#include "src/tint/sem/test_helper.h"
-
-namespace tint::sem {
-namespace {
-
-struct StorageTextureTest : public TestHelper {
-  StorageTexture* Create(ast::TextureDimension dims,
-                         ast::TexelFormat fmt,
-                         ast::Access access) {
-    auto* subtype = StorageTexture::SubtypeFor(fmt, Types());
-    return create<StorageTexture>(dims, fmt, access, subtype);
-  }
-};
-
-TEST_F(StorageTextureTest, Creation) {
-  auto* a = Create(ast::TextureDimension::kCube, ast::TexelFormat::kRgba32Float,
-                   ast::Access::kReadWrite);
-  auto* b = Create(ast::TextureDimension::kCube, ast::TexelFormat::kRgba32Float,
-                   ast::Access::kReadWrite);
-  auto* c = Create(ast::TextureDimension::k2d, ast::TexelFormat::kRgba32Float,
-                   ast::Access::kReadWrite);
-  auto* d = Create(ast::TextureDimension::kCube, ast::TexelFormat::kR32Float,
-                   ast::Access::kReadWrite);
-  auto* e = Create(ast::TextureDimension::kCube, ast::TexelFormat::kRgba32Float,
-                   ast::Access::kRead);
-
-  EXPECT_TRUE(a->type()->Is<F32>());
-  EXPECT_EQ(a->dim(), ast::TextureDimension::kCube);
-
-  EXPECT_EQ(a, b);
-  EXPECT_NE(a, c);
-  EXPECT_NE(a, d);
-  EXPECT_NE(a, e);
-}
-
-TEST_F(StorageTextureTest, Hash) {
-  auto* a = Create(ast::TextureDimension::kCube, ast::TexelFormat::kRgba32Float,
-                   ast::Access::kReadWrite);
-  auto* b = Create(ast::TextureDimension::kCube, ast::TexelFormat::kRgba32Float,
-                   ast::Access::kReadWrite);
-  auto* c = Create(ast::TextureDimension::k2d, ast::TexelFormat::kRgba32Float,
-                   ast::Access::kReadWrite);
-  auto* d = Create(ast::TextureDimension::kCube, ast::TexelFormat::kR32Float,
-                   ast::Access::kReadWrite);
-  auto* e = Create(ast::TextureDimension::kCube, ast::TexelFormat::kRgba32Float,
-                   ast::Access::kRead);
-
-  EXPECT_EQ(a->Hash(), b->Hash());
-  EXPECT_NE(a->Hash(), c->Hash());
-  EXPECT_NE(a->Hash(), d->Hash());
-  EXPECT_NE(a->Hash(), e->Hash());
-}
-
-TEST_F(StorageTextureTest, Equals) {
-  auto* a = Create(ast::TextureDimension::kCube, ast::TexelFormat::kRgba32Float,
-                   ast::Access::kReadWrite);
-  auto* b = Create(ast::TextureDimension::kCube, ast::TexelFormat::kRgba32Float,
-                   ast::Access::kReadWrite);
-  auto* c = Create(ast::TextureDimension::k2d, ast::TexelFormat::kRgba32Float,
-                   ast::Access::kReadWrite);
-  auto* d = Create(ast::TextureDimension::kCube, ast::TexelFormat::kR32Float,
-                   ast::Access::kReadWrite);
-  auto* e = Create(ast::TextureDimension::kCube, ast::TexelFormat::kRgba32Float,
-                   ast::Access::kRead);
-
-  EXPECT_TRUE(a->Equals(*b));
-  EXPECT_FALSE(a->Equals(*c));
-  EXPECT_FALSE(a->Equals(*d));
-  EXPECT_FALSE(a->Equals(*e));
-  EXPECT_FALSE(a->Equals(Void{}));
-}
-
-TEST_F(StorageTextureTest, Dim) {
-  auto* s = Create(ast::TextureDimension::k2dArray,
-                   ast::TexelFormat::kRgba32Float, ast::Access::kReadWrite);
-  EXPECT_EQ(s->dim(), ast::TextureDimension::k2dArray);
-}
-
-TEST_F(StorageTextureTest, Format) {
-  auto* s = Create(ast::TextureDimension::k2dArray,
-                   ast::TexelFormat::kRgba32Float, ast::Access::kReadWrite);
-  EXPECT_EQ(s->texel_format(), ast::TexelFormat::kRgba32Float);
-}
-
-TEST_F(StorageTextureTest, FriendlyName) {
-  auto* s = Create(ast::TextureDimension::k2dArray,
-                   ast::TexelFormat::kRgba32Float, ast::Access::kReadWrite);
-  EXPECT_EQ(s->FriendlyName(Symbols()),
-            "texture_storage_2d_array<rgba32float, read_write>");
-}
-
-TEST_F(StorageTextureTest, F32) {
-  Type* s = Create(ast::TextureDimension::k2dArray,
-                   ast::TexelFormat::kRgba32Float, ast::Access::kReadWrite);
-
-  auto program = Build();
-
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
-  ASSERT_TRUE(s->Is<Texture>());
-  ASSERT_TRUE(s->Is<StorageTexture>());
-  EXPECT_TRUE(s->As<StorageTexture>()->type()->Is<F32>());
-}
-
-TEST_F(StorageTextureTest, U32) {
-  auto* subtype =
-      sem::StorageTexture::SubtypeFor(ast::TexelFormat::kRg32Uint, Types());
-  Type* s = create<StorageTexture>(ast::TextureDimension::k2dArray,
-                                   ast::TexelFormat::kRg32Uint,
-                                   ast::Access::kReadWrite, subtype);
-
-  auto program = Build();
-
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
-  ASSERT_TRUE(s->Is<Texture>());
-  ASSERT_TRUE(s->Is<StorageTexture>());
-  EXPECT_TRUE(s->As<StorageTexture>()->type()->Is<U32>());
-}
-
-TEST_F(StorageTextureTest, I32) {
-  auto* subtype =
-      sem::StorageTexture::SubtypeFor(ast::TexelFormat::kRgba32Sint, Types());
-  Type* s = create<StorageTexture>(ast::TextureDimension::k2dArray,
-                                   ast::TexelFormat::kRgba32Sint,
-                                   ast::Access::kReadWrite, subtype);
-
-  auto program = Build();
-
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
-  ASSERT_TRUE(s->Is<Texture>());
-  ASSERT_TRUE(s->Is<StorageTexture>());
-  EXPECT_TRUE(s->As<StorageTexture>()->type()->Is<I32>());
-}
-
-}  // namespace
-}  // namespace tint::sem
diff --git a/src/tint/sem/struct.cc b/src/tint/sem/struct.cc
index ce3029d3..eb0583b 100644
--- a/src/tint/sem/struct.cc
+++ b/src/tint/sem/struct.cc
@@ -40,127 +40,119 @@
       align_(align),
       size_(size),
       size_no_padding_(size_no_padding) {
-  constructible_ = true;
-  for (auto* member : members_) {
-    if (!member->Type()->IsConstructible()) {
-      constructible_ = false;
-      break;
+    constructible_ = true;
+    for (auto* member : members_) {
+        if (!member->Type()->IsConstructible()) {
+            constructible_ = false;
+            break;
+        }
     }
-  }
 }
 
 Struct::~Struct() = default;
 
 size_t Struct::Hash() const {
-  return utils::Hash(TypeInfo::Of<Struct>().full_hashcode, name_);
+    return utils::Hash(TypeInfo::Of<Struct>().full_hashcode, name_);
 }
 
 bool Struct::Equals(const sem::Type& other) const {
-  if (auto* o = other.As<Struct>()) {
-    return o->name_ == name_;
-  }
-  return false;
+    if (auto* o = other.As<Struct>()) {
+        return o->name_ == name_;
+    }
+    return false;
 }
 
 const StructMember* Struct::FindMember(Symbol name) const {
-  for (auto* member : members_) {
-    if (member->Declaration()->symbol == name) {
-      return member;
+    for (auto* member : members_) {
+        if (member->Declaration()->symbol == name) {
+            return member;
+        }
     }
-  }
-  return nullptr;
+    return nullptr;
 }
 
 uint32_t Struct::Align() const {
-  return align_;
+    return align_;
 }
 
 uint32_t Struct::Size() const {
-  return size_;
+    return size_;
 }
 
 std::string Struct::FriendlyName(const SymbolTable& symbols) const {
-  return symbols.NameFor(name_);
+    return symbols.NameFor(name_);
 }
 
 std::string Struct::Layout(const tint::SymbolTable& symbols) const {
-  std::stringstream ss;
+    std::stringstream ss;
 
-  auto member_name_of = [&](const sem::StructMember* sm) {
-    return symbols.NameFor(sm->Declaration()->symbol);
-  };
+    auto member_name_of = [&](const sem::StructMember* sm) {
+        return symbols.NameFor(sm->Declaration()->symbol);
+    };
 
-  if (Members().empty()) {
-    return {};
-  }
-  const auto* const last_member = Members().back();
-  const uint32_t last_member_struct_padding_offset =
-      last_member->Offset() + last_member->Size();
+    if (Members().empty()) {
+        return {};
+    }
+    const auto* const last_member = Members().back();
+    const uint32_t last_member_struct_padding_offset = last_member->Offset() + last_member->Size();
 
-  // Compute max widths to align output
-  const auto offset_w =
-      static_cast<int>(::log10(last_member_struct_padding_offset)) + 1;
-  const auto size_w = static_cast<int>(::log10(Size())) + 1;
-  const auto align_w = static_cast<int>(::log10(Align())) + 1;
+    // Compute max widths to align output
+    const auto offset_w = static_cast<int>(::log10(last_member_struct_padding_offset)) + 1;
+    const auto size_w = static_cast<int>(::log10(Size())) + 1;
+    const auto align_w = static_cast<int>(::log10(Align())) + 1;
 
-  auto print_struct_begin_line = [&](size_t align, size_t size,
-                                     std::string struct_name) {
-    ss << "/*          " << std::setw(offset_w) << " "
-       << "align(" << std::setw(align_w) << align << ") size("
-       << std::setw(size_w) << size << ") */ struct " << struct_name << " {\n";
-  };
+    auto print_struct_begin_line = [&](size_t align, size_t size, std::string struct_name) {
+        ss << "/*          " << std::setw(offset_w) << " "
+           << "align(" << std::setw(align_w) << align << ") size(" << std::setw(size_w) << size
+           << ") */ struct " << struct_name << " {\n";
+    };
 
-  auto print_struct_end_line = [&]() {
-    ss << "/*                         "
-       << std::setw(offset_w + size_w + align_w) << " "
-       << "*/ };";
-  };
+    auto print_struct_end_line = [&]() {
+        ss << "/*                         " << std::setw(offset_w + size_w + align_w) << " "
+           << "*/ };";
+    };
 
-  auto print_member_line = [&](size_t offset, size_t align, size_t size,
-                               std::string s) {
-    ss << "/* offset(" << std::setw(offset_w) << offset << ") align("
-       << std::setw(align_w) << align << ") size(" << std::setw(size_w) << size
-       << ") */   " << s << ";\n";
-  };
+    auto print_member_line = [&](size_t offset, size_t align, size_t size, std::string s) {
+        ss << "/* offset(" << std::setw(offset_w) << offset << ") align(" << std::setw(align_w)
+           << align << ") size(" << std::setw(size_w) << size << ") */   " << s << ";\n";
+    };
 
-  print_struct_begin_line(Align(), Size(), UnwrapRef()->FriendlyName(symbols));
+    print_struct_begin_line(Align(), Size(), UnwrapRef()->FriendlyName(symbols));
 
-  for (size_t i = 0; i < Members().size(); ++i) {
-    auto* const m = Members()[i];
+    for (size_t i = 0; i < Members().size(); ++i) {
+        auto* const m = Members()[i];
 
-    // Output field alignment padding, if any
-    auto* const prev_member = (i == 0) ? nullptr : Members()[i - 1];
-    if (prev_member) {
-      uint32_t padding =
-          m->Offset() - (prev_member->Offset() + prev_member->Size());
-      if (padding > 0) {
-        size_t padding_offset = m->Offset() - padding;
-        print_member_line(padding_offset, 1, padding,
-                          "// -- implicit field alignment padding --");
-      }
+        // Output field alignment padding, if any
+        auto* const prev_member = (i == 0) ? nullptr : Members()[i - 1];
+        if (prev_member) {
+            uint32_t padding = m->Offset() - (prev_member->Offset() + prev_member->Size());
+            if (padding > 0) {
+                size_t padding_offset = m->Offset() - padding;
+                print_member_line(padding_offset, 1, padding,
+                                  "// -- implicit field alignment padding --");
+            }
+        }
+
+        // Output member
+        std::string member_name = member_name_of(m);
+        print_member_line(m->Offset(), m->Align(), m->Size(),
+                          member_name + " : " + m->Type()->UnwrapRef()->FriendlyName(symbols));
     }
 
-    // Output member
-    std::string member_name = member_name_of(m);
-    print_member_line(
-        m->Offset(), m->Align(), m->Size(),
-        member_name + " : " + m->Type()->UnwrapRef()->FriendlyName(symbols));
-  }
+    // Output struct size padding, if any
+    uint32_t struct_padding = Size() - last_member_struct_padding_offset;
+    if (struct_padding > 0) {
+        print_member_line(last_member_struct_padding_offset, 1, struct_padding,
+                          "// -- implicit struct size padding --");
+    }
 
-  // Output struct size padding, if any
-  uint32_t struct_padding = Size() - last_member_struct_padding_offset;
-  if (struct_padding > 0) {
-    print_member_line(last_member_struct_padding_offset, 1, struct_padding,
-                      "// -- implicit struct size padding --");
-  }
+    print_struct_end_line();
 
-  print_struct_end_line();
-
-  return ss.str();
+    return ss.str();
 }
 
 bool Struct::IsConstructible() const {
-  return constructible_;
+    return constructible_;
 }
 
 StructMember::StructMember(const ast::StructMember* declaration,
diff --git a/src/tint/sem/struct.h b/src/tint/sem/struct.h
index f5e8081..fe9169d 100644
--- a/src/tint/sem/struct.h
+++ b/src/tint/sem/struct.h
@@ -43,189 +43,183 @@
 
 /// Metadata to capture how a structure is used in a shader module.
 enum class PipelineStageUsage {
-  kVertexInput,
-  kVertexOutput,
-  kFragmentInput,
-  kFragmentOutput,
-  kComputeInput,
-  kComputeOutput,
+    kVertexInput,
+    kVertexOutput,
+    kFragmentInput,
+    kFragmentOutput,
+    kComputeInput,
+    kComputeOutput,
 };
 
 /// Struct holds the semantic information for structures.
 class Struct final : public Castable<Struct, Type> {
- public:
-  /// Constructor
-  /// @param declaration the AST structure declaration
-  /// @param name the name of the structure
-  /// @param members the structure members
-  /// @param align the byte alignment of the structure
-  /// @param size the byte size of the structure
-  /// @param size_no_padding size of the members without the end of structure
-  /// alignment padding
-  Struct(const ast::Struct* declaration,
-         Symbol name,
-         StructMemberList members,
-         uint32_t align,
-         uint32_t size,
-         uint32_t size_no_padding);
+  public:
+    /// Constructor
+    /// @param declaration the AST structure declaration
+    /// @param name the name of the structure
+    /// @param members the structure members
+    /// @param align the byte alignment of the structure
+    /// @param size the byte size of the structure
+    /// @param size_no_padding size of the members without the end of structure
+    /// alignment padding
+    Struct(const ast::Struct* declaration,
+           Symbol name,
+           StructMemberList members,
+           uint32_t align,
+           uint32_t size,
+           uint32_t size_no_padding);
 
-  /// Destructor
-  ~Struct() override;
+    /// Destructor
+    ~Struct() override;
 
-  /// @returns a hash of the type.
-  size_t Hash() const override;
+    /// @returns a hash of the type.
+    size_t Hash() const override;
 
-  /// @param other the other type to compare against
-  /// @returns true if the this type is equal to the given type
-  bool Equals(const Type& other) const override;
+    /// @param other the other type to compare against
+    /// @returns true if the this type is equal to the given type
+    bool Equals(const Type& other) const override;
 
-  /// @returns the struct
-  const ast::Struct* Declaration() const { return declaration_; }
+    /// @returns the struct
+    const ast::Struct* Declaration() const { return declaration_; }
 
-  /// @returns the name of the structure
-  Symbol Name() const { return name_; }
+    /// @returns the name of the structure
+    Symbol Name() const { return name_; }
 
-  /// @returns the members of the structure
-  const StructMemberList& Members() const { return members_; }
+    /// @returns the members of the structure
+    const StructMemberList& Members() const { return members_; }
 
-  /// @param name the member name to look for
-  /// @returns the member with the given name, or nullptr if it was not found.
-  const StructMember* FindMember(Symbol name) const;
+    /// @param name the member name to look for
+    /// @returns the member with the given name, or nullptr if it was not found.
+    const StructMember* FindMember(Symbol name) const;
 
-  /// @returns the byte alignment of the structure
-  /// @note this may differ from the alignment of a structure member of this
-  /// structure type, if the member is annotated with the `@align(n)`
-  /// attribute.
-  uint32_t Align() const override;
+    /// @returns the byte alignment of the structure
+    /// @note this may differ from the alignment of a structure member of this
+    /// structure type, if the member is annotated with the `@align(n)`
+    /// attribute.
+    uint32_t Align() const override;
 
-  /// @returns the byte size of the structure
-  /// @note this may differ from the size of a structure member of this
-  /// structure type, if the member is annotated with the `@size(n)`
-  /// attribute.
-  uint32_t Size() const override;
+    /// @returns the byte size of the structure
+    /// @note this may differ from the size of a structure member of this
+    /// structure type, if the member is annotated with the `@size(n)`
+    /// attribute.
+    uint32_t Size() const override;
 
-  /// @returns the byte size of the members without the end of structure
-  /// alignment padding
-  uint32_t SizeNoPadding() const { return size_no_padding_; }
+    /// @returns the byte size of the members without the end of structure
+    /// alignment padding
+    uint32_t SizeNoPadding() const { return size_no_padding_; }
 
-  /// Adds the StorageClass usage to the structure.
-  /// @param usage the storage usage
-  void AddUsage(ast::StorageClass usage) {
-    storage_class_usage_.emplace(usage);
-  }
+    /// Adds the StorageClass usage to the structure.
+    /// @param usage the storage usage
+    void AddUsage(ast::StorageClass usage) { storage_class_usage_.emplace(usage); }
 
-  /// @returns the set of storage class uses of this structure
-  const std::unordered_set<ast::StorageClass>& StorageClassUsage() const {
-    return storage_class_usage_;
-  }
-
-  /// @param usage the ast::StorageClass usage type to query
-  /// @returns true iff this structure has been used as the given storage class
-  bool UsedAs(ast::StorageClass usage) const {
-    return storage_class_usage_.count(usage) > 0;
-  }
-
-  /// @returns true iff this structure has been used by storage class that's
-  /// host-shareable.
-  bool IsHostShareable() const {
-    for (auto sc : storage_class_usage_) {
-      if (ast::IsHostShareable(sc)) {
-        return true;
-      }
+    /// @returns the set of storage class uses of this structure
+    const std::unordered_set<ast::StorageClass>& StorageClassUsage() const {
+        return storage_class_usage_;
     }
-    return false;
-  }
 
-  /// Adds the pipeline stage usage to the structure.
-  /// @param usage the storage usage
-  void AddUsage(PipelineStageUsage usage) {
-    pipeline_stage_uses_.emplace(usage);
-  }
+    /// @param usage the ast::StorageClass usage type to query
+    /// @returns true iff this structure has been used as the given storage class
+    bool UsedAs(ast::StorageClass usage) const { return storage_class_usage_.count(usage) > 0; }
 
-  /// @returns the set of entry point uses of this structure
-  const std::unordered_set<PipelineStageUsage>& PipelineStageUses() const {
-    return pipeline_stage_uses_;
-  }
+    /// @returns true iff this structure has been used by storage class that's
+    /// host-shareable.
+    bool IsHostShareable() const {
+        for (auto sc : storage_class_usage_) {
+            if (ast::IsHostShareable(sc)) {
+                return true;
+            }
+        }
+        return false;
+    }
 
-  /// @param symbols the program's symbol table
-  /// @returns the name for this type that closely resembles how it would be
-  /// declared in WGSL.
-  std::string FriendlyName(const SymbolTable& symbols) const override;
+    /// Adds the pipeline stage usage to the structure.
+    /// @param usage the storage usage
+    void AddUsage(PipelineStageUsage usage) { pipeline_stage_uses_.emplace(usage); }
 
-  /// @param symbols the program's symbol table
-  /// @returns a multiline string that describes the layout of this struct,
-  /// including size and alignment information.
-  std::string Layout(const tint::SymbolTable& symbols) const;
+    /// @returns the set of entry point uses of this structure
+    const std::unordered_set<PipelineStageUsage>& PipelineStageUses() const {
+        return pipeline_stage_uses_;
+    }
 
-  /// @returns true if constructible as per
-  /// https://gpuweb.github.io/gpuweb/wgsl/#constructible-types
-  bool IsConstructible() const override;
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type that closely resembles how it would be
+    /// declared in WGSL.
+    std::string FriendlyName(const SymbolTable& symbols) const override;
 
- private:
-  uint64_t LargestMemberBaseAlignment(MemoryLayout mem_layout) const;
+    /// @param symbols the program's symbol table
+    /// @returns a multiline string that describes the layout of this struct,
+    /// including size and alignment information.
+    std::string Layout(const tint::SymbolTable& symbols) const;
 
-  ast::Struct const* const declaration_;
-  const Symbol name_;
-  const StructMemberList members_;
-  const uint32_t align_;
-  const uint32_t size_;
-  const uint32_t size_no_padding_;
-  std::unordered_set<ast::StorageClass> storage_class_usage_;
-  std::unordered_set<PipelineStageUsage> pipeline_stage_uses_;
-  bool constructible_;
+    /// @returns true if constructible as per
+    /// https://gpuweb.github.io/gpuweb/wgsl/#constructible-types
+    bool IsConstructible() const override;
+
+  private:
+    uint64_t LargestMemberBaseAlignment(MemoryLayout mem_layout) const;
+
+    ast::Struct const* const declaration_;
+    const Symbol name_;
+    const StructMemberList members_;
+    const uint32_t align_;
+    const uint32_t size_;
+    const uint32_t size_no_padding_;
+    std::unordered_set<ast::StorageClass> storage_class_usage_;
+    std::unordered_set<PipelineStageUsage> pipeline_stage_uses_;
+    bool constructible_;
 };
 
 /// StructMember holds the semantic information for structure members.
 class StructMember : public Castable<StructMember, Node> {
- public:
-  /// Constructor
-  /// @param declaration the AST declaration node
-  /// @param name the name of the structure
-  /// @param type the type of the member
-  /// @param index the index of the member in the structure
-  /// @param offset the byte offset from the base of the structure
-  /// @param align the byte alignment of the member
-  /// @param size the byte size of the member
-  StructMember(const ast::StructMember* declaration,
-               Symbol name,
-               sem::Type* type,
-               uint32_t index,
-               uint32_t offset,
-               uint32_t align,
-               uint32_t size);
+  public:
+    /// Constructor
+    /// @param declaration the AST declaration node
+    /// @param name the name of the structure
+    /// @param type the type of the member
+    /// @param index the index of the member in the structure
+    /// @param offset the byte offset from the base of the structure
+    /// @param align the byte alignment of the member
+    /// @param size the byte size of the member
+    StructMember(const ast::StructMember* declaration,
+                 Symbol name,
+                 sem::Type* type,
+                 uint32_t index,
+                 uint32_t offset,
+                 uint32_t align,
+                 uint32_t size);
 
-  /// Destructor
-  ~StructMember() override;
+    /// Destructor
+    ~StructMember() override;
 
-  /// @returns the AST declaration node
-  const ast::StructMember* Declaration() const { return declaration_; }
+    /// @returns the AST declaration node
+    const ast::StructMember* Declaration() const { return declaration_; }
 
-  /// @returns the name of the structure
-  Symbol Name() const { return name_; }
+    /// @returns the name of the structure
+    Symbol Name() const { return name_; }
 
-  /// @returns the type of the member
-  sem::Type* Type() const { return type_; }
+    /// @returns the type of the member
+    sem::Type* Type() const { return type_; }
 
-  /// @returns the member index
-  uint32_t Index() const { return index_; }
+    /// @returns the member index
+    uint32_t Index() const { return index_; }
 
-  /// @returns byte offset from base of structure
-  uint32_t Offset() const { return offset_; }
+    /// @returns byte offset from base of structure
+    uint32_t Offset() const { return offset_; }
 
-  /// @returns the alignment of the member in bytes
-  uint32_t Align() const { return align_; }
+    /// @returns the alignment of the member in bytes
+    uint32_t Align() const { return align_; }
 
-  /// @returns byte size
-  uint32_t Size() const { return size_; }
+    /// @returns byte size
+    uint32_t Size() const { return size_; }
 
- private:
-  const ast::StructMember* const declaration_;
-  const Symbol name_;
-  sem::Type* const type_;
-  const uint32_t index_;
-  const uint32_t offset_;
-  const uint32_t align_;
-  const uint32_t size_;
+  private:
+    const ast::StructMember* const declaration_;
+    const Symbol name_;
+    sem::Type* const type_;
+    const uint32_t index_;
+    const uint32_t offset_;
+    const uint32_t align_;
+    const uint32_t size_;
 };
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/switch_statement.cc b/src/tint/sem/switch_statement.cc
index 9800ed6..ed3942d 100644
--- a/src/tint/sem/switch_statement.cc
+++ b/src/tint/sem/switch_statement.cc
@@ -25,27 +25,27 @@
                                  const CompoundStatement* parent,
                                  const sem::Function* function)
     : Base(declaration, parent, function) {
-  TINT_ASSERT(Semantic, parent);
-  TINT_ASSERT(Semantic, function);
+    TINT_ASSERT(Semantic, parent);
+    TINT_ASSERT(Semantic, function);
 }
 
 SwitchStatement::~SwitchStatement() = default;
 
 const ast::SwitchStatement* SwitchStatement::Declaration() const {
-  return static_cast<const ast::SwitchStatement*>(Base::Declaration());
+    return static_cast<const ast::SwitchStatement*>(Base::Declaration());
 }
 
 CaseStatement::CaseStatement(const ast::CaseStatement* declaration,
                              const CompoundStatement* parent,
                              const sem::Function* function)
     : Base(declaration, parent, function) {
-  TINT_ASSERT(Semantic, parent);
-  TINT_ASSERT(Semantic, function);
+    TINT_ASSERT(Semantic, parent);
+    TINT_ASSERT(Semantic, function);
 }
 CaseStatement::~CaseStatement() = default;
 
 const ast::CaseStatement* CaseStatement::Declaration() const {
-  return static_cast<const ast::CaseStatement*>(Base::Declaration());
+    return static_cast<const ast::CaseStatement*>(Base::Declaration());
 }
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/switch_statement.h b/src/tint/sem/switch_statement.h
index b56bc85..a5ef659 100644
--- a/src/tint/sem/switch_statement.h
+++ b/src/tint/sem/switch_statement.h
@@ -26,49 +26,48 @@
 namespace tint::sem {
 
 /// Holds semantic information about an switch statement
-class SwitchStatement final
-    : public Castable<SwitchStatement, CompoundStatement> {
- public:
-  /// Constructor
-  /// @param declaration the AST node for this switch statement
-  /// @param parent the owning statement
-  /// @param function the owning function
-  SwitchStatement(const ast::SwitchStatement* declaration,
-                  const CompoundStatement* parent,
-                  const sem::Function* function);
+class SwitchStatement final : public Castable<SwitchStatement, CompoundStatement> {
+  public:
+    /// Constructor
+    /// @param declaration the AST node for this switch statement
+    /// @param parent the owning statement
+    /// @param function the owning function
+    SwitchStatement(const ast::SwitchStatement* declaration,
+                    const CompoundStatement* parent,
+                    const sem::Function* function);
 
-  /// Destructor
-  ~SwitchStatement() override;
+    /// Destructor
+    ~SwitchStatement() override;
 
-  /// @return the AST node for this statement
-  const ast::SwitchStatement* Declaration() const;
+    /// @return the AST node for this statement
+    const ast::SwitchStatement* Declaration() const;
 };
 
 /// Holds semantic information about a switch case statement
 class CaseStatement final : public Castable<CaseStatement, CompoundStatement> {
- public:
-  /// Constructor
-  /// @param declaration the AST node for this case statement
-  /// @param parent the owning statement
-  /// @param function the owning function
-  CaseStatement(const ast::CaseStatement* declaration,
-                const CompoundStatement* parent,
-                const sem::Function* function);
+  public:
+    /// Constructor
+    /// @param declaration the AST node for this case statement
+    /// @param parent the owning statement
+    /// @param function the owning function
+    CaseStatement(const ast::CaseStatement* declaration,
+                  const CompoundStatement* parent,
+                  const sem::Function* function);
 
-  /// Destructor
-  ~CaseStatement() override;
+    /// Destructor
+    ~CaseStatement() override;
 
-  /// @return the AST node for this statement
-  const ast::CaseStatement* Declaration() const;
+    /// @return the AST node for this statement
+    const ast::CaseStatement* Declaration() const;
 
-  /// @param body the case body block statement
-  void SetBlock(const BlockStatement* body) { body_ = body; }
+    /// @param body the case body block statement
+    void SetBlock(const BlockStatement* body) { body_ = body; }
 
-  /// @returns the case body block statement
-  const BlockStatement* Body() const { return body_; }
+    /// @returns the case body block statement
+    const BlockStatement* Body() const { return body_; }
 
- private:
-  const BlockStatement* body_ = nullptr;
+  private:
+    const BlockStatement* body_ = nullptr;
 };
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/test_helper.h b/src/tint/sem/test_helper.h
index 412e36a..94f66e4 100644
--- a/src/tint/sem/test_helper.h
+++ b/src/tint/sem/test_helper.h
@@ -25,17 +25,17 @@
 /// Helper class for testing
 template <typename BASE>
 class TestHelperBase : public BASE, public ProgramBuilder {
- public:
-  /// Builds and returns the program. Must only be called once per test
-  /// @return the built program
-  Program Build() {
-    diag::Formatter formatter;
-    [&]() {
-      ASSERT_TRUE(IsValid()) << "Builder program is not valid\n"
-                             << formatter.format(Diagnostics());
-    }();
-    return Program(std::move(*this));
-  }
+  public:
+    /// Builds and returns the program. Must only be called once per test
+    /// @return the built program
+    Program Build() {
+        diag::Formatter formatter;
+        [&]() {
+            ASSERT_TRUE(IsValid()) << "Builder program is not valid\n"
+                                   << formatter.format(Diagnostics());
+        }();
+        return Program(std::move(*this));
+    }
 };
 using TestHelper = TestHelperBase<testing::Test>;
 
diff --git a/src/tint/sem/texture_type.cc b/src/tint/sem/texture.cc
similarity index 95%
rename from src/tint/sem/texture_type.cc
rename to src/tint/sem/texture.cc
index e14b606..02fc918 100644
--- a/src/tint/sem/texture_type.cc
+++ b/src/tint/sem/texture.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/sem/texture_type.h"
+#include "src/tint/sem/texture.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::sem::Texture);
 
diff --git a/src/tint/sem/texture_type.h b/src/tint/sem/texture.h
similarity index 63%
rename from src/tint/sem/texture_type.h
rename to src/tint/sem/texture.h
index 9aa3330..67dd026 100644
--- a/src/tint/sem/texture_type.h
+++ b/src/tint/sem/texture.h
@@ -12,8 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef SRC_TINT_SEM_TEXTURE_TYPE_H_
-#define SRC_TINT_SEM_TEXTURE_TYPE_H_
+#ifndef SRC_TINT_SEM_TEXTURE_H_
+#define SRC_TINT_SEM_TEXTURE_H_
 
 #include "src/tint/ast/texture.h"
 #include "src/tint/sem/type.h"
@@ -22,21 +22,21 @@
 
 /// A texture type.
 class Texture : public Castable<Texture, Type> {
- public:
-  /// Constructor
-  /// @param dim the dimensionality of the texture
-  explicit Texture(ast::TextureDimension dim);
-  /// Move constructor
-  Texture(Texture&&);
-  ~Texture() override;
+  public:
+    /// Constructor
+    /// @param dim the dimensionality of the texture
+    explicit Texture(ast::TextureDimension dim);
+    /// Move constructor
+    Texture(Texture&&);
+    ~Texture() override;
 
-  /// @returns the texture dimension
-  ast::TextureDimension dim() const { return dim_; }
+    /// @returns the texture dimension
+    ast::TextureDimension dim() const { return dim_; }
 
- private:
-  ast::TextureDimension const dim_;
+  private:
+    ast::TextureDimension const dim_;
 };
 
 }  // namespace tint::sem
 
-#endif  // SRC_TINT_SEM_TEXTURE_TYPE_H_
+#endif  // SRC_TINT_SEM_TEXTURE_H_
diff --git a/src/tint/sem/texture_type_test.cc b/src/tint/sem/texture_test.cc
similarity index 80%
rename from src/tint/sem/texture_type_test.cc
rename to src/tint/sem/texture_test.cc
index 8737415..c948c32 100644
--- a/src/tint/sem/texture_type_test.cc
+++ b/src/tint/sem/texture_test.cc
@@ -12,9 +12,9 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/sem/texture_type.h"
+#include "src/tint/sem/texture.h"
 
-#include "src/tint/sem/sampled_texture_type.h"
+#include "src/tint/sem/sampled_texture.h"
 #include "src/tint/sem/test_helper.h"
 
 namespace tint::sem {
@@ -23,12 +23,12 @@
 using TextureTypeDimTest = TestParamHelper<ast::TextureDimension>;
 
 TEST_P(TextureTypeDimTest, DimMustMatch) {
-  // Check that the dim() query returns the right dimensionality.
-  F32 f32;
-  // TextureType is an abstract class, so use concrete class
-  // SampledTexture in its stead.
-  SampledTexture st(GetParam(), &f32);
-  EXPECT_EQ(st.dim(), GetParam());
+    // Check that the dim() query returns the right dimensionality.
+    F32 f32;
+    // TextureType is an abstract class, so use concrete class
+    // SampledTexture in its stead.
+    SampledTexture st(GetParam(), &f32);
+    EXPECT_EQ(st.dim(), GetParam());
 }
 
 INSTANTIATE_TEST_SUITE_P(Dimensions,
diff --git a/src/tint/sem/type.cc b/src/tint/sem/type.cc
index f8c32e7..5776ff4 100644
--- a/src/tint/sem/type.cc
+++ b/src/tint/sem/type.cc
@@ -14,16 +14,16 @@
 
 #include "src/tint/sem/type.h"
 
-#include "src/tint/sem/bool_type.h"
-#include "src/tint/sem/f32_type.h"
-#include "src/tint/sem/i32_type.h"
-#include "src/tint/sem/matrix_type.h"
-#include "src/tint/sem/pointer_type.h"
-#include "src/tint/sem/reference_type.h"
-#include "src/tint/sem/sampler_type.h"
-#include "src/tint/sem/texture_type.h"
-#include "src/tint/sem/u32_type.h"
-#include "src/tint/sem/vector_type.h"
+#include "src/tint/sem/bool.h"
+#include "src/tint/sem/f32.h"
+#include "src/tint/sem/i32.h"
+#include "src/tint/sem/matrix.h"
+#include "src/tint/sem/pointer.h"
+#include "src/tint/sem/reference.h"
+#include "src/tint/sem/sampler.h"
+#include "src/tint/sem/texture.h"
+#include "src/tint/sem/u32.h"
+#include "src/tint/sem/vector.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::sem::Type);
 
@@ -36,121 +36,120 @@
 Type::~Type() = default;
 
 const Type* Type::UnwrapPtr() const {
-  auto* type = this;
-  while (auto* ptr = type->As<sem::Pointer>()) {
-    type = ptr->StoreType();
-  }
-  return type;
+    auto* type = this;
+    while (auto* ptr = type->As<sem::Pointer>()) {
+        type = ptr->StoreType();
+    }
+    return type;
 }
 
 const Type* Type::UnwrapRef() const {
-  auto* type = this;
-  if (auto* ref = type->As<sem::Reference>()) {
-    type = ref->StoreType();
-  }
-  return type;
+    auto* type = this;
+    if (auto* ref = type->As<sem::Reference>()) {
+        type = ref->StoreType();
+    }
+    return type;
 }
 
 uint32_t Type::Size() const {
-  return 0;
+    return 0;
 }
 
 uint32_t Type::Align() const {
-  return 0;
+    return 0;
 }
 
 bool Type::IsConstructible() const {
-  return false;
+    return false;
 }
 
 bool Type::is_scalar() const {
-  return IsAnyOf<F32, U32, I32, Bool>();
+    return IsAnyOf<F32, U32, I32, Bool>();
 }
 
 bool Type::is_numeric_scalar() const {
-  return IsAnyOf<F32, U32, I32>();
+    return IsAnyOf<F32, U32, I32>();
 }
 
 bool Type::is_float_scalar() const {
-  return Is<F32>();
+    return Is<F32>();
 }
 
 bool Type::is_float_matrix() const {
-  return Is([](const Matrix* m) { return m->type()->is_float_scalar(); });
+    return Is([](const Matrix* m) { return m->type()->is_float_scalar(); });
 }
 
 bool Type::is_square_float_matrix() const {
-  return Is([](const Matrix* m) {
-    return m->type()->is_float_scalar() && m->rows() == m->columns();
-  });
+    return Is(
+        [](const Matrix* m) { return m->type()->is_float_scalar() && m->rows() == m->columns(); });
 }
 
 bool Type::is_float_vector() const {
-  return Is([](const Vector* v) { return v->type()->is_float_scalar(); });
+    return Is([](const Vector* v) { return v->type()->is_float_scalar(); });
 }
 
 bool Type::is_float_scalar_or_vector() const {
-  return is_float_scalar() || is_float_vector();
+    return is_float_scalar() || is_float_vector();
 }
 
 bool Type::is_float_scalar_or_vector_or_matrix() const {
-  return is_float_scalar() || is_float_vector() || is_float_matrix();
+    return is_float_scalar() || is_float_vector() || is_float_matrix();
 }
 
 bool Type::is_integer_scalar() const {
-  return IsAnyOf<U32, I32>();
+    return IsAnyOf<U32, I32>();
 }
 
 bool Type::is_signed_integer_scalar() const {
-  return Is<I32>();
+    return Is<I32>();
 }
 
 bool Type::is_unsigned_integer_scalar() const {
-  return Is<U32>();
+    return Is<U32>();
 }
 
 bool Type::is_signed_integer_vector() const {
-  return Is([](const Vector* v) { return v->type()->Is<I32>(); });
+    return Is([](const Vector* v) { return v->type()->Is<I32>(); });
 }
 
 bool Type::is_unsigned_integer_vector() const {
-  return Is([](const Vector* v) { return v->type()->Is<U32>(); });
+    return Is([](const Vector* v) { return v->type()->Is<U32>(); });
 }
 
 bool Type::is_unsigned_scalar_or_vector() const {
-  return Is<U32>() || is_unsigned_integer_vector();
+    return Is<U32>() || is_unsigned_integer_vector();
 }
 
 bool Type::is_signed_scalar_or_vector() const {
-  return Is<I32>() || is_signed_integer_vector();
+    return Is<I32>() || is_signed_integer_vector();
 }
 
 bool Type::is_integer_scalar_or_vector() const {
-  return is_unsigned_scalar_or_vector() || is_signed_scalar_or_vector();
+    return is_unsigned_scalar_or_vector() || is_signed_scalar_or_vector();
 }
 
 bool Type::is_bool_vector() const {
-  return Is([](const Vector* v) { return v->type()->Is<Bool>(); });
+    return Is([](const Vector* v) { return v->type()->Is<Bool>(); });
 }
 
 bool Type::is_bool_scalar_or_vector() const {
-  return Is<Bool>() || is_bool_vector();
+    return Is<Bool>() || is_bool_vector();
 }
 
 bool Type::is_numeric_vector() const {
-  return Is([](const Vector* v) { return v->type()->is_numeric_scalar(); });
+    return Is([](const Vector* v) { return v->type()->is_numeric_scalar(); });
 }
 
 bool Type::is_scalar_vector() const {
-  return Is([](const Vector* v) { return v->type()->is_scalar(); });
+    return Is([](const Vector* v) { return v->type()->is_scalar(); });
 }
 
 bool Type::is_numeric_scalar_or_vector() const {
-  return is_numeric_scalar() || is_numeric_vector();
+    return is_numeric_scalar() || is_numeric_vector();
 }
 
 bool Type::is_handle() const {
-  return IsAnyOf<Sampler, Texture>();
+    return IsAnyOf<Sampler, Texture>();
 }
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/type.h b/src/tint/sem/type.h
index c93c4e6..271e1d7 100644
--- a/src/tint/sem/type.h
+++ b/src/tint/sem/type.h
@@ -33,89 +33,89 @@
 
 /// Base class for a type in the system
 class Type : public Castable<Type, Node> {
- public:
-  /// Move constructor
-  Type(Type&&);
-  ~Type() override;
+  public:
+    /// Move constructor
+    Type(Type&&);
+    ~Type() override;
 
-  /// @returns a hash of the type.
-  virtual size_t Hash() const = 0;
+    /// @returns a hash of the type.
+    virtual size_t Hash() const = 0;
 
-  /// @returns true if the this type is equal to the given type
-  virtual bool Equals(const Type&) const = 0;
+    /// @returns true if the this type is equal to the given type
+    virtual bool Equals(const Type&) const = 0;
 
-  /// @param symbols the program's symbol table
-  /// @returns the name for this type that closely resembles how it would be
-  /// declared in WGSL.
-  virtual std::string FriendlyName(const SymbolTable& symbols) const = 0;
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type that closely resembles how it would be
+    /// declared in WGSL.
+    virtual std::string FriendlyName(const SymbolTable& symbols) const = 0;
 
-  /// @returns the inner most pointee type if this is a pointer, `this`
-  /// otherwise
-  const Type* UnwrapPtr() const;
+    /// @returns the inner most pointee type if this is a pointer, `this`
+    /// otherwise
+    const Type* UnwrapPtr() const;
 
-  /// @returns the inner type if this is a reference, `this` otherwise
-  const Type* UnwrapRef() const;
+    /// @returns the inner type if this is a reference, `this` otherwise
+    const Type* UnwrapRef() const;
 
-  /// @returns the size in bytes of the type. This may include tail padding.
-  /// @note opaque types will return a size of 0.
-  virtual uint32_t Size() const;
+    /// @returns the size in bytes of the type. This may include tail padding.
+    /// @note opaque types will return a size of 0.
+    virtual uint32_t Size() const;
 
-  /// @returns the alignment in bytes of the type. This may include tail
-  /// padding.
-  /// @note opaque types will return a size of 0.
-  virtual uint32_t Align() const;
+    /// @returns the alignment in bytes of the type. This may include tail
+    /// padding.
+    /// @note opaque types will return a size of 0.
+    virtual uint32_t Align() const;
 
-  /// @returns true if constructible as per
-  /// https://gpuweb.github.io/gpuweb/wgsl/#constructible-types
-  virtual bool IsConstructible() const;
+    /// @returns true if constructible as per
+    /// https://gpuweb.github.io/gpuweb/wgsl/#constructible-types
+    virtual bool IsConstructible() const;
 
-  /// @returns true if this type is a scalar
-  bool is_scalar() const;
-  /// @returns true if this type is a numeric scalar
-  bool is_numeric_scalar() const;
-  /// @returns true if this type is a float scalar
-  bool is_float_scalar() const;
-  /// @returns true if this type is a float matrix
-  bool is_float_matrix() const;
-  /// @returns true if this type is a square float matrix
-  bool is_square_float_matrix() const;
-  /// @returns true if this type is a float vector
-  bool is_float_vector() const;
-  /// @returns true if this type is a float scalar or vector
-  bool is_float_scalar_or_vector() const;
-  /// @returns true if this type is a float scalar or vector or matrix
-  bool is_float_scalar_or_vector_or_matrix() const;
-  /// @returns true if this type is an integer scalar
-  bool is_integer_scalar() const;
-  /// @returns true if this type is a signed integer scalar
-  bool is_signed_integer_scalar() const;
-  /// @returns true if this type is an unsigned integer scalar
-  bool is_unsigned_integer_scalar() const;
-  /// @returns true if this type is a signed integer vector
-  bool is_signed_integer_vector() const;
-  /// @returns true if this type is an unsigned vector
-  bool is_unsigned_integer_vector() const;
-  /// @returns true if this type is an unsigned scalar or vector
-  bool is_unsigned_scalar_or_vector() const;
-  /// @returns true if this type is a signed scalar or vector
-  bool is_signed_scalar_or_vector() const;
-  /// @returns true if this type is an integer scalar or vector
-  bool is_integer_scalar_or_vector() const;
-  /// @returns true if this type is a boolean vector
-  bool is_bool_vector() const;
-  /// @returns true if this type is boolean scalar or vector
-  bool is_bool_scalar_or_vector() const;
-  /// @returns true if this type is a numeric vector
-  bool is_numeric_vector() const;
-  /// @returns true if this type is a vector of scalar type
-  bool is_scalar_vector() const;
-  /// @returns true if this type is a numeric scale or vector
-  bool is_numeric_scalar_or_vector() const;
-  /// @returns true if this type is a handle type
-  bool is_handle() const;
+    /// @returns true if this type is a scalar
+    bool is_scalar() const;
+    /// @returns true if this type is a numeric scalar
+    bool is_numeric_scalar() const;
+    /// @returns true if this type is a float scalar
+    bool is_float_scalar() const;
+    /// @returns true if this type is a float matrix
+    bool is_float_matrix() const;
+    /// @returns true if this type is a square float matrix
+    bool is_square_float_matrix() const;
+    /// @returns true if this type is a float vector
+    bool is_float_vector() const;
+    /// @returns true if this type is a float scalar or vector
+    bool is_float_scalar_or_vector() const;
+    /// @returns true if this type is a float scalar or vector or matrix
+    bool is_float_scalar_or_vector_or_matrix() const;
+    /// @returns true if this type is an integer scalar
+    bool is_integer_scalar() const;
+    /// @returns true if this type is a signed integer scalar
+    bool is_signed_integer_scalar() const;
+    /// @returns true if this type is an unsigned integer scalar
+    bool is_unsigned_integer_scalar() const;
+    /// @returns true if this type is a signed integer vector
+    bool is_signed_integer_vector() const;
+    /// @returns true if this type is an unsigned vector
+    bool is_unsigned_integer_vector() const;
+    /// @returns true if this type is an unsigned scalar or vector
+    bool is_unsigned_scalar_or_vector() const;
+    /// @returns true if this type is a signed scalar or vector
+    bool is_signed_scalar_or_vector() const;
+    /// @returns true if this type is an integer scalar or vector
+    bool is_integer_scalar_or_vector() const;
+    /// @returns true if this type is a boolean vector
+    bool is_bool_vector() const;
+    /// @returns true if this type is boolean scalar or vector
+    bool is_bool_scalar_or_vector() const;
+    /// @returns true if this type is a numeric vector
+    bool is_numeric_vector() const;
+    /// @returns true if this type is a vector of scalar type
+    bool is_scalar_vector() const;
+    /// @returns true if this type is a numeric scale or vector
+    bool is_numeric_scalar_or_vector() const;
+    /// @returns true if this type is a handle type
+    bool is_handle() const;
 
- protected:
-  Type();
+  protected:
+    Type();
 };
 
 }  // namespace tint::sem
@@ -125,20 +125,20 @@
 /// std::hash specialization for tint::sem::Type
 template <>
 struct hash<tint::sem::Type> {
-  /// @param type the type to obtain a hash from
-  /// @returns the hash of the semantic type
-  size_t operator()(const tint::sem::Type& type) const { return type.Hash(); }
+    /// @param type the type to obtain a hash from
+    /// @returns the hash of the semantic type
+    size_t operator()(const tint::sem::Type& type) const { return type.Hash(); }
 };
 
 /// std::equal_to specialization for tint::sem::Type
 template <>
 struct equal_to<tint::sem::Type> {
-  /// @param a the first type to compare
-  /// @param b the second type to compare
-  /// @returns true if the two types are equal
-  bool operator()(const tint::sem::Type& a, const tint::sem::Type& b) const {
-    return a.Equals(b);
-  }
+    /// @param a the first type to compare
+    /// @param b the second type to compare
+    /// @returns true if the two types are equal
+    bool operator()(const tint::sem::Type& a, const tint::sem::Type& b) const {
+        return a.Equals(b);
+    }
 };
 
 }  // namespace std
diff --git a/src/tint/sem/type_constructor.cc b/src/tint/sem/type_constructor.cc
index 4213edb..34f6e2a 100644
--- a/src/tint/sem/type_constructor.cc
+++ b/src/tint/sem/type_constructor.cc
@@ -18,8 +18,7 @@
 
 namespace tint::sem {
 
-TypeConstructor::TypeConstructor(const sem::Type* type,
-                                 const ParameterList& parameters)
+TypeConstructor::TypeConstructor(const sem::Type* type, const ParameterList& parameters)
     : Base(type, parameters) {}
 
 TypeConstructor::~TypeConstructor() = default;
diff --git a/src/tint/sem/type_constructor.h b/src/tint/sem/type_constructor.h
index d9ff7a1..f3d4221 100644
--- a/src/tint/sem/type_constructor.h
+++ b/src/tint/sem/type_constructor.h
@@ -21,14 +21,14 @@
 
 /// TypeConstructor is the CallTarget for a type constructor.
 class TypeConstructor final : public Castable<TypeConstructor, CallTarget> {
- public:
-  /// Constructor
-  /// @param type the type that's being constructed
-  /// @param parameters the type constructor parameters
-  TypeConstructor(const sem::Type* type, const ParameterList& parameters);
+  public:
+    /// Constructor
+    /// @param type the type that's being constructed
+    /// @param parameters the type constructor parameters
+    TypeConstructor(const sem::Type* type, const ParameterList& parameters);
 
-  /// Destructor
-  ~TypeConstructor() override;
+    /// Destructor
+    ~TypeConstructor() override;
 };
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/type_conversion.cc b/src/tint/sem/type_conversion.cc
index 47a4a71..5da2928 100644
--- a/src/tint/sem/type_conversion.cc
+++ b/src/tint/sem/type_conversion.cc
@@ -18,8 +18,7 @@
 
 namespace tint::sem {
 
-TypeConversion::TypeConversion(const sem::Type* type,
-                               const sem::Parameter* parameter)
+TypeConversion::TypeConversion(const sem::Type* type, const sem::Parameter* parameter)
     : Base(type, ParameterList{parameter}) {}
 
 TypeConversion::~TypeConversion() = default;
diff --git a/src/tint/sem/type_conversion.h b/src/tint/sem/type_conversion.h
index 5433641..e400565 100644
--- a/src/tint/sem/type_conversion.h
+++ b/src/tint/sem/type_conversion.h
@@ -21,20 +21,20 @@
 
 /// TypeConversion is the CallTarget for a type conversion (cast).
 class TypeConversion final : public Castable<TypeConversion, CallTarget> {
- public:
-  /// Constructor
-  /// @param type the target type of the cast
-  /// @param parameter the type cast parameter
-  TypeConversion(const sem::Type* type, const sem::Parameter* parameter);
+  public:
+    /// Constructor
+    /// @param type the target type of the cast
+    /// @param parameter the type cast parameter
+    TypeConversion(const sem::Type* type, const sem::Parameter* parameter);
 
-  /// Destructor
-  ~TypeConversion() override;
+    /// Destructor
+    ~TypeConversion() override;
 
-  /// @returns the cast source type
-  const sem::Type* Source() const { return Parameters()[0]->Type(); }
+    /// @returns the cast source type
+    const sem::Type* Source() const { return Parameters()[0]->Type(); }
 
-  /// @returns the cast target type
-  const sem::Type* Target() const { return ReturnType(); }
+    /// @returns the cast target type
+    const sem::Type* Target() const { return ReturnType(); }
 };
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/type_manager.h b/src/tint/sem/type_manager.h
index 6d68af0..fb08689 100644
--- a/src/tint/sem/type_manager.h
+++ b/src/tint/sem/type_manager.h
@@ -26,43 +26,43 @@
 
 /// The type manager holds all the pointers to the known types.
 class Manager final : public utils::UniqueAllocator<Type> {
- public:
-  /// Iterator is the type returned by begin() and end()
-  using Iterator = utils::BlockAllocator<Type>::ConstIterator;
+  public:
+    /// Iterator is the type returned by begin() and end()
+    using Iterator = utils::BlockAllocator<Type>::ConstIterator;
 
-  /// Constructor
-  Manager();
+    /// Constructor
+    Manager();
 
-  /// Move constructor
-  Manager(Manager&&);
+    /// Move constructor
+    Manager(Manager&&);
 
-  /// Move assignment operator
-  /// @param rhs the Manager to move
-  /// @return this Manager
-  Manager& operator=(Manager&& rhs);
+    /// Move assignment operator
+    /// @param rhs the Manager to move
+    /// @return this Manager
+    Manager& operator=(Manager&& rhs);
 
-  /// Destructor
-  ~Manager();
+    /// Destructor
+    ~Manager();
 
-  /// Wrap returns a new Manager created with the types of `inner`.
-  /// The Manager returned by Wrap is intended to temporarily extend the types
-  /// of an existing immutable Manager.
-  /// As the copied types are owned by `inner`, `inner` must not be destructed
-  /// or assigned while using the returned Manager.
-  /// TODO(bclayton) - Evaluate whether there are safer alternatives to this
-  /// function. See crbug.com/tint/460.
-  /// @param inner the immutable Manager to extend
-  /// @return the Manager that wraps `inner`
-  static Manager Wrap(const Manager& inner) {
-    Manager out;
-    out.items = inner.items;
-    return out;
-  }
+    /// Wrap returns a new Manager created with the types of `inner`.
+    /// The Manager returned by Wrap is intended to temporarily extend the types
+    /// of an existing immutable Manager.
+    /// As the copied types are owned by `inner`, `inner` must not be destructed
+    /// or assigned while using the returned Manager.
+    /// TODO(bclayton) - Evaluate whether there are safer alternatives to this
+    /// function. See crbug.com/tint/460.
+    /// @param inner the immutable Manager to extend
+    /// @return the Manager that wraps `inner`
+    static Manager Wrap(const Manager& inner) {
+        Manager out;
+        out.items = inner.items;
+        return out;
+    }
 
-  /// @returns an iterator to the beginning of the types
-  Iterator begin() const { return allocator.Objects().begin(); }
-  /// @returns an iterator to the end of the types
-  Iterator end() const { return allocator.Objects().end(); }
+    /// @returns an iterator to the beginning of the types
+    Iterator begin() const { return allocator.Objects().begin(); }
+    /// @returns an iterator to the end of the types
+    Iterator end() const { return allocator.Objects().end(); }
 };
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/type_manager_test.cc b/src/tint/sem/type_manager_test.cc
index 6cbea9b..c670db0 100644
--- a/src/tint/sem/type_manager_test.cc
+++ b/src/tint/sem/type_manager_test.cc
@@ -15,66 +15,66 @@
 #include "src/tint/sem/type_manager.h"
 
 #include "gtest/gtest.h"
-#include "src/tint/sem/i32_type.h"
-#include "src/tint/sem/u32_type.h"
+#include "src/tint/sem/i32.h"
+#include "src/tint/sem/u32.h"
 
 namespace tint::sem {
 namespace {
 
 template <typename T>
 size_t count(const T& range_loopable) {
-  size_t n = 0;
-  for (auto it : range_loopable) {
-    (void)it;
-    n++;
-  }
-  return n;
+    size_t n = 0;
+    for (auto it : range_loopable) {
+        (void)it;
+        n++;
+    }
+    return n;
 }
 
 using TypeManagerTest = testing::Test;
 
 TEST_F(TypeManagerTest, GetUnregistered) {
-  Manager tm;
-  auto* t = tm.Get<I32>();
-  ASSERT_NE(t, nullptr);
-  EXPECT_TRUE(t->Is<I32>());
+    Manager tm;
+    auto* t = tm.Get<I32>();
+    ASSERT_NE(t, nullptr);
+    EXPECT_TRUE(t->Is<I32>());
 }
 
 TEST_F(TypeManagerTest, GetSameTypeReturnsSamePtr) {
-  Manager tm;
-  auto* t = tm.Get<I32>();
-  ASSERT_NE(t, nullptr);
-  EXPECT_TRUE(t->Is<I32>());
+    Manager tm;
+    auto* t = tm.Get<I32>();
+    ASSERT_NE(t, nullptr);
+    EXPECT_TRUE(t->Is<I32>());
 
-  auto* t2 = tm.Get<I32>();
-  EXPECT_EQ(t, t2);
+    auto* t2 = tm.Get<I32>();
+    EXPECT_EQ(t, t2);
 }
 
 TEST_F(TypeManagerTest, GetDifferentTypeReturnsDifferentPtr) {
-  Manager tm;
-  Type* t = tm.Get<I32>();
-  ASSERT_NE(t, nullptr);
-  EXPECT_TRUE(t->Is<I32>());
+    Manager tm;
+    Type* t = tm.Get<I32>();
+    ASSERT_NE(t, nullptr);
+    EXPECT_TRUE(t->Is<I32>());
 
-  Type* t2 = tm.Get<U32>();
-  ASSERT_NE(t2, nullptr);
-  EXPECT_NE(t, t2);
-  EXPECT_TRUE(t2->Is<U32>());
+    Type* t2 = tm.Get<U32>();
+    ASSERT_NE(t2, nullptr);
+    EXPECT_NE(t, t2);
+    EXPECT_TRUE(t2->Is<U32>());
 }
 
 TEST_F(TypeManagerTest, WrapDoesntAffectInner) {
-  Manager inner;
-  Manager outer = Manager::Wrap(inner);
+    Manager inner;
+    Manager outer = Manager::Wrap(inner);
 
-  inner.Get<I32>();
+    inner.Get<I32>();
 
-  EXPECT_EQ(count(inner), 1u);
-  EXPECT_EQ(count(outer), 0u);
+    EXPECT_EQ(count(inner), 1u);
+    EXPECT_EQ(count(outer), 0u);
 
-  outer.Get<U32>();
+    outer.Get<U32>();
 
-  EXPECT_EQ(count(inner), 1u);
-  EXPECT_EQ(count(outer), 1u);
+    EXPECT_EQ(count(inner), 1u);
+    EXPECT_EQ(count(outer), 1u);
 }
 
 }  // namespace
diff --git a/src/tint/sem/type_mappings.h b/src/tint/sem/type_mappings.h
index 1bbc46f..8425f14 100644
--- a/src/tint/sem/type_mappings.h
+++ b/src/tint/sem/type_mappings.h
@@ -22,7 +22,6 @@
 class Array;
 class CallExpression;
 class Expression;
-class ElseStatement;
 class ForLoopStatement;
 class Function;
 class IfStatement;
@@ -39,7 +38,6 @@
 class Array;
 class Call;
 class Expression;
-class ElseStatement;
 class ForLoopStatement;
 class Function;
 class IfStatement;
@@ -59,30 +57,29 @@
 /// corresponding semantic node types. The standard operator overload resolving
 /// rules will be used to infer the return type based on the argument type.
 struct TypeMappings {
-  //! @cond Doxygen_Suppress
-  Array* operator()(ast::Array*);
-  Call* operator()(ast::CallExpression*);
-  Expression* operator()(ast::Expression*);
-  ElseStatement* operator()(ast::ElseStatement*);
-  ForLoopStatement* operator()(ast::ForLoopStatement*);
-  Function* operator()(ast::Function*);
-  IfStatement* operator()(ast::IfStatement*);
-  MemberAccessorExpression* operator()(ast::MemberAccessorExpression*);
-  Node* operator()(ast::Node*);
-  Statement* operator()(ast::Statement*);
-  Struct* operator()(ast::Struct*);
-  StructMember* operator()(ast::StructMember*);
-  Type* operator()(ast::Type*);
-  Type* operator()(ast::TypeDecl*);
-  Variable* operator()(ast::Variable*);
-  //! @endcond
+    //! @cond Doxygen_Suppress
+    Array* operator()(ast::Array*);
+    Call* operator()(ast::CallExpression*);
+    Expression* operator()(ast::Expression*);
+    ForLoopStatement* operator()(ast::ForLoopStatement*);
+    Function* operator()(ast::Function*);
+    IfStatement* operator()(ast::IfStatement*);
+    MemberAccessorExpression* operator()(ast::MemberAccessorExpression*);
+    Node* operator()(ast::Node*);
+    Statement* operator()(ast::Statement*);
+    Struct* operator()(ast::Struct*);
+    StructMember* operator()(ast::StructMember*);
+    Type* operator()(ast::Type*);
+    Type* operator()(ast::TypeDecl*);
+    Variable* operator()(ast::Variable*);
+    //! @endcond
 };
 
 /// SemanticNodeTypeFor resolves to the appropriate sem::Node type for the
 /// AST or type node `AST_OR_TYPE`.
 template <typename AST_OR_TYPE>
-using SemanticNodeTypeFor = typename std::remove_pointer<decltype(
-    TypeMappings()(std::declval<AST_OR_TYPE*>()))>::type;
+using SemanticNodeTypeFor =
+    typename std::remove_pointer<decltype(TypeMappings()(std::declval<AST_OR_TYPE*>()))>::type;
 
 }  // namespace tint::sem
 
diff --git a/src/tint/sem/u32_type.cc b/src/tint/sem/u32.cc
similarity index 84%
rename from src/tint/sem/u32_type.cc
rename to src/tint/sem/u32.cc
index f73b617..dc3bd1d 100644
--- a/src/tint/sem/u32_type.cc
+++ b/src/tint/sem/u32.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/sem/u32_type.h"
+#include "src/tint/sem/u32.h"
 
 #include "src/tint/program_builder.h"
 
@@ -27,27 +27,27 @@
 U32::U32(U32&&) = default;
 
 size_t U32::Hash() const {
-  return static_cast<size_t>(TypeInfo::Of<U32>().full_hashcode);
+    return static_cast<size_t>(TypeInfo::Of<U32>().full_hashcode);
 }
 
 bool U32::Equals(const Type& other) const {
-  return other.Is<U32>();
+    return other.Is<U32>();
 }
 
 std::string U32::FriendlyName(const SymbolTable&) const {
-  return "u32";
+    return "u32";
 }
 
 bool U32::IsConstructible() const {
-  return true;
+    return true;
 }
 
 uint32_t U32::Size() const {
-  return 4;
+    return 4;
 }
 
 uint32_t U32::Align() const {
-  return 4;
+    return 4;
 }
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/u32.h b/src/tint/sem/u32.h
new file mode 100644
index 0000000..5ae01fb
--- /dev/null
+++ b/src/tint/sem/u32.h
@@ -0,0 +1,58 @@
+// 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_SEM_U32_H_
+#define SRC_TINT_SEM_U32_H_
+
+#include <string>
+
+#include "src/tint/sem/type.h"
+
+namespace tint::sem {
+
+/// A unsigned int 32 type.
+class U32 final : public Castable<U32, Type> {
+  public:
+    /// Constructor
+    U32();
+    /// Move constructor
+    U32(U32&&);
+    ~U32() override;
+
+    /// @returns a hash of the type.
+    size_t Hash() const override;
+
+    /// @param other the other type to compare against
+    /// @returns true if the this type is equal to the given type
+    bool Equals(const Type& other) const override;
+
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type that closely resembles how it would be
+    /// declared in WGSL.
+    std::string FriendlyName(const SymbolTable& symbols) const override;
+
+    /// @returns true if constructible as per
+    /// https://gpuweb.github.io/gpuweb/wgsl/#constructible-types
+    bool IsConstructible() const override;
+
+    /// @returns the size in bytes of the type.
+    uint32_t Size() const override;
+
+    /// @returns the alignment in bytes of the type.
+    uint32_t Align() const override;
+};
+
+}  // namespace tint::sem
+
+#endif  // SRC_TINT_SEM_U32_H_
diff --git a/src/tint/sem/u32_type_test.cc b/src/tint/sem/u32_test.cc
similarity index 68%
rename from src/tint/sem/u32_type_test.cc
rename to src/tint/sem/u32_test.cc
index dae4c42..1716aa5 100644
--- a/src/tint/sem/u32_type_test.cc
+++ b/src/tint/sem/u32_test.cc
@@ -13,7 +13,7 @@
 // limitations under the License.
 
 #include "src/tint/sem/test_helper.h"
-#include "src/tint/sem/texture_type.h"
+#include "src/tint/sem/texture.h"
 
 namespace tint::sem {
 namespace {
@@ -21,27 +21,27 @@
 using U32Test = TestHelper;
 
 TEST_F(U32Test, Creation) {
-  auto* a = create<U32>();
-  auto* b = create<U32>();
-  EXPECT_EQ(a, b);
+    auto* a = create<U32>();
+    auto* b = create<U32>();
+    EXPECT_EQ(a, b);
 }
 
 TEST_F(U32Test, Hash) {
-  auto* a = create<U32>();
-  auto* b = create<U32>();
-  EXPECT_EQ(a->Hash(), b->Hash());
+    auto* a = create<U32>();
+    auto* b = create<U32>();
+    EXPECT_EQ(a->Hash(), b->Hash());
 }
 
 TEST_F(U32Test, Equals) {
-  auto* a = create<U32>();
-  auto* b = create<U32>();
-  EXPECT_TRUE(a->Equals(*b));
-  EXPECT_FALSE(a->Equals(Void{}));
+    auto* a = create<U32>();
+    auto* b = create<U32>();
+    EXPECT_TRUE(a->Equals(*b));
+    EXPECT_FALSE(a->Equals(Void{}));
 }
 
 TEST_F(U32Test, FriendlyName) {
-  U32 u;
-  EXPECT_EQ(u.FriendlyName(Symbols()), "u32");
+    U32 u;
+    EXPECT_EQ(u.FriendlyName(Symbols()), "u32");
 }
 
 }  // namespace
diff --git a/src/tint/sem/u32_type.h b/src/tint/sem/u32_type.h
deleted file mode 100644
index d81886c..0000000
--- a/src/tint/sem/u32_type.h
+++ /dev/null
@@ -1,58 +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_SEM_U32_TYPE_H_
-#define SRC_TINT_SEM_U32_TYPE_H_
-
-#include <string>
-
-#include "src/tint/sem/type.h"
-
-namespace tint::sem {
-
-/// A unsigned int 32 type.
-class U32 final : public Castable<U32, Type> {
- public:
-  /// Constructor
-  U32();
-  /// Move constructor
-  U32(U32&&);
-  ~U32() override;
-
-  /// @returns a hash of the type.
-  size_t Hash() const override;
-
-  /// @param other the other type to compare against
-  /// @returns true if the this type is equal to the given type
-  bool Equals(const Type& other) const override;
-
-  /// @param symbols the program's symbol table
-  /// @returns the name for this type that closely resembles how it would be
-  /// declared in WGSL.
-  std::string FriendlyName(const SymbolTable& symbols) const override;
-
-  /// @returns true if constructible as per
-  /// https://gpuweb.github.io/gpuweb/wgsl/#constructible-types
-  bool IsConstructible() const override;
-
-  /// @returns the size in bytes of the type.
-  uint32_t Size() const override;
-
-  /// @returns the alignment in bytes of the type.
-  uint32_t Align() const override;
-};
-
-}  // namespace tint::sem
-
-#endif  // SRC_TINT_SEM_U32_TYPE_H_
diff --git a/src/tint/sem/variable.cc b/src/tint/sem/variable.cc
index af3deb9..0ada5ae 100644
--- a/src/tint/sem/variable.cc
+++ b/src/tint/sem/variable.cc
@@ -68,9 +68,7 @@
                      ast::StorageClass storage_class,
                      ast::Access access,
                      const ParameterUsage usage /* = ParameterUsage::kNone */)
-    : Base(declaration, type, storage_class, access, Constant{}),
-      index_(index),
-      usage_(usage) {}
+    : Base(declaration, type, storage_class, access, Constant{}), index_(index), usage_(usage) {}
 
 Parameter::~Parameter() = default;
 
@@ -82,6 +80,13 @@
            statement,
            variable->ConstantValue(),
            /* has_side_effects */ false),
-      variable_(variable) {}
+      variable_(variable) {
+    auto* type = variable->Type();
+    if (type->Is<sem::Pointer>() && variable->Constructor()) {
+        source_variable_ = variable->Constructor()->SourceVariable();
+    } else {
+        source_variable_ = variable;
+    }
+}
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/variable.h b/src/tint/sem/variable.h
index ca97d64..7026ca7 100644
--- a/src/tint/sem/variable.h
+++ b/src/tint/sem/variable.h
@@ -40,189 +40,185 @@
 /// Variable is the base class for local variables, global variables and
 /// parameters.
 class Variable : public Castable<Variable, Node> {
- public:
-  /// Constructor
-  /// @param declaration the AST declaration node
-  /// @param type the variable type
-  /// @param storage_class the variable storage class
-  /// @param access the variable access control type
-  /// @param constant_value the constant value for the variable. May be invalid
-  Variable(const ast::Variable* declaration,
-           const sem::Type* type,
-           ast::StorageClass storage_class,
-           ast::Access access,
-           Constant constant_value);
+  public:
+    /// Constructor
+    /// @param declaration the AST declaration node
+    /// @param type the variable type
+    /// @param storage_class the variable storage class
+    /// @param access the variable access control type
+    /// @param constant_value the constant value for the variable. May be invalid
+    Variable(const ast::Variable* declaration,
+             const sem::Type* type,
+             ast::StorageClass storage_class,
+             ast::Access access,
+             Constant constant_value);
 
-  /// Destructor
-  ~Variable() override;
+    /// Destructor
+    ~Variable() override;
 
-  /// @returns the AST declaration node
-  const ast::Variable* Declaration() const { return declaration_; }
+    /// @returns the AST declaration node
+    const ast::Variable* Declaration() const { return declaration_; }
 
-  /// @returns the canonical type for the variable
-  const sem::Type* Type() const { return type_; }
+    /// @returns the canonical type for the variable
+    const sem::Type* Type() const { return type_; }
 
-  /// @returns the storage class for the variable
-  ast::StorageClass StorageClass() const { return storage_class_; }
+    /// @returns the storage class for the variable
+    ast::StorageClass StorageClass() const { return storage_class_; }
 
-  /// @returns the access control for the variable
-  ast::Access Access() const { return access_; }
+    /// @returns the access control for the variable
+    ast::Access Access() const { return access_; }
 
-  /// @return the constant value of this expression
-  const Constant& ConstantValue() const { return constant_value_; }
+    /// @return the constant value of this expression
+    const Constant& ConstantValue() const { return constant_value_; }
 
-  /// @returns the variable constructor expression, or nullptr if the variable
-  /// does not have one.
-  const Expression* Constructor() const { return constructor_; }
+    /// @returns the variable constructor expression, or nullptr if the variable
+    /// does not have one.
+    const Expression* Constructor() const { return constructor_; }
 
-  /// Sets the variable constructor expression.
-  /// @param constructor the constructor expression to assign to this variable.
-  void SetConstructor(const Expression* constructor) {
-    constructor_ = constructor;
-  }
+    /// Sets the variable constructor expression.
+    /// @param constructor the constructor expression to assign to this variable.
+    void SetConstructor(const Expression* constructor) { constructor_ = constructor; }
 
-  /// @returns the expressions that use the variable
-  const std::vector<const VariableUser*>& Users() const { return users_; }
+    /// @returns the expressions that use the variable
+    const std::vector<const VariableUser*>& Users() const { return users_; }
 
-  /// @param user the user to add
-  void AddUser(const VariableUser* user) { users_.emplace_back(user); }
+    /// @param user the user to add
+    void AddUser(const VariableUser* user) { users_.emplace_back(user); }
 
- private:
-  const ast::Variable* const declaration_;
-  const sem::Type* const type_;
-  const ast::StorageClass storage_class_;
-  const ast::Access access_;
-  const Constant constant_value_;
-  const Expression* constructor_ = nullptr;
-  std::vector<const VariableUser*> users_;
+  private:
+    const ast::Variable* const declaration_;
+    const sem::Type* const type_;
+    const ast::StorageClass storage_class_;
+    const ast::Access access_;
+    const Constant constant_value_;
+    const Expression* constructor_ = nullptr;
+    std::vector<const VariableUser*> users_;
 };
 
 /// LocalVariable is a function-scope variable
 class LocalVariable final : public Castable<LocalVariable, Variable> {
- public:
-  /// Constructor
-  /// @param declaration the AST declaration node
-  /// @param type the variable type
-  /// @param storage_class the variable storage class
-  /// @param access the variable access control type
-  /// @param statement the statement that declared this local variable
-  /// @param constant_value the constant value for the variable. May be invalid
-  LocalVariable(const ast::Variable* declaration,
-                const sem::Type* type,
-                ast::StorageClass storage_class,
-                ast::Access access,
-                const sem::Statement* statement,
-                Constant constant_value);
+  public:
+    /// Constructor
+    /// @param declaration the AST declaration node
+    /// @param type the variable type
+    /// @param storage_class the variable storage class
+    /// @param access the variable access control type
+    /// @param statement the statement that declared this local variable
+    /// @param constant_value the constant value for the variable. May be invalid
+    LocalVariable(const ast::Variable* declaration,
+                  const sem::Type* type,
+                  ast::StorageClass storage_class,
+                  ast::Access access,
+                  const sem::Statement* statement,
+                  Constant constant_value);
 
-  /// Destructor
-  ~LocalVariable() override;
+    /// Destructor
+    ~LocalVariable() override;
 
-  /// @returns the statement that declares this local variable
-  const sem::Statement* Statement() const { return statement_; }
+    /// @returns the statement that declares this local variable
+    const sem::Statement* Statement() const { return statement_; }
 
-  /// @returns the Type, Function or Variable that this local variable shadows
-  const sem::Node* Shadows() const { return shadows_; }
+    /// @returns the Type, Function or Variable that this local variable shadows
+    const sem::Node* Shadows() const { return shadows_; }
 
-  /// Sets the Type, Function or Variable that this local variable shadows
-  /// @param shadows the Type, Function or Variable that this variable shadows
-  void SetShadows(const sem::Node* shadows) { shadows_ = shadows; }
+    /// Sets the Type, Function or Variable that this local variable shadows
+    /// @param shadows the Type, Function or Variable that this variable shadows
+    void SetShadows(const sem::Node* shadows) { shadows_ = shadows; }
 
- private:
-  const sem::Statement* const statement_;
-  const sem::Node* shadows_ = nullptr;
+  private:
+    const sem::Statement* const statement_;
+    const sem::Node* shadows_ = nullptr;
 };
 
 /// GlobalVariable is a module-scope variable
 class GlobalVariable final : public Castable<GlobalVariable, Variable> {
- public:
-  /// Constructor
-  /// @param declaration the AST declaration node
-  /// @param type the variable type
-  /// @param storage_class the variable storage class
-  /// @param access the variable access control type
-  /// @param constant_value the constant value for the variable. May be invalid
-  /// @param binding_point the optional resource binding point of the variable
-  GlobalVariable(const ast::Variable* declaration,
-                 const sem::Type* type,
-                 ast::StorageClass storage_class,
-                 ast::Access access,
-                 Constant constant_value,
-                 sem::BindingPoint binding_point = {});
+  public:
+    /// Constructor
+    /// @param declaration the AST declaration node
+    /// @param type the variable type
+    /// @param storage_class the variable storage class
+    /// @param access the variable access control type
+    /// @param constant_value the constant value for the variable. May be invalid
+    /// @param binding_point the optional resource binding point of the variable
+    GlobalVariable(const ast::Variable* declaration,
+                   const sem::Type* type,
+                   ast::StorageClass storage_class,
+                   ast::Access access,
+                   Constant constant_value,
+                   sem::BindingPoint binding_point = {});
 
-  /// Destructor
-  ~GlobalVariable() override;
+    /// Destructor
+    ~GlobalVariable() override;
 
-  /// @returns the resource binding point for the variable
-  sem::BindingPoint BindingPoint() const { return binding_point_; }
+    /// @returns the resource binding point for the variable
+    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;
-    is_overridable_ = true;
-  }
+    /// @param id the constant identifier to assign to this variable
+    void SetConstantId(uint16_t id) {
+        constant_id_ = id;
+        is_overridable_ = true;
+    }
 
-  /// @returns the pipeline constant ID associated with the variable
-  uint16_t ConstantId() const { return constant_id_; }
+    /// @returns the pipeline constant ID associated with the variable
+    uint16_t ConstantId() const { return constant_id_; }
 
-  /// @param is_overridable true if this is a pipeline overridable constant
-  void SetIsOverridable(bool is_overridable = true) {
-    is_overridable_ = is_overridable;
-  }
+    /// @param is_overridable true if this is a pipeline overridable constant
+    void SetIsOverridable(bool is_overridable = true) { is_overridable_ = is_overridable; }
 
-  /// @returns true if this is pipeline overridable constant
-  bool IsOverridable() const { return is_overridable_; }
+    /// @returns true if this is pipeline overridable constant
+    bool IsOverridable() const { return is_overridable_; }
 
- private:
-  const sem::BindingPoint binding_point_;
+  private:
+    const sem::BindingPoint binding_point_;
 
-  bool is_overridable_ = false;
-  uint16_t constant_id_ = 0;
+    bool is_overridable_ = false;
+    uint16_t constant_id_ = 0;
 };
 
 /// Parameter is a function parameter
 class Parameter final : public Castable<Parameter, Variable> {
- public:
-  /// Constructor for function parameters
-  /// @param declaration the AST declaration node
-  /// @param index the index of the parmeter in the function
-  /// @param type the variable type
-  /// @param storage_class the variable storage class
-  /// @param access the variable access control type
-  /// @param usage the semantic usage for the parameter
-  Parameter(const ast::Variable* declaration,
-            uint32_t index,
-            const sem::Type* type,
-            ast::StorageClass storage_class,
-            ast::Access access,
-            const ParameterUsage usage = ParameterUsage::kNone);
+  public:
+    /// Constructor for function parameters
+    /// @param declaration the AST declaration node
+    /// @param index the index of the parmeter in the function
+    /// @param type the variable type
+    /// @param storage_class the variable storage class
+    /// @param access the variable access control type
+    /// @param usage the semantic usage for the parameter
+    Parameter(const ast::Variable* declaration,
+              uint32_t index,
+              const sem::Type* type,
+              ast::StorageClass storage_class,
+              ast::Access access,
+              const ParameterUsage usage = ParameterUsage::kNone);
 
-  /// Destructor
-  ~Parameter() override;
+    /// Destructor
+    ~Parameter() override;
 
-  /// @return the index of the parmeter in the function
-  uint32_t Index() const { return index_; }
+    /// @return the index of the parmeter in the function
+    uint32_t Index() const { return index_; }
 
-  /// @returns the semantic usage for the parameter
-  ParameterUsage Usage() const { return usage_; }
+    /// @returns the semantic usage for the parameter
+    ParameterUsage Usage() const { return usage_; }
 
-  /// @returns the CallTarget owner of this parameter
-  CallTarget const* Owner() const { return owner_; }
+    /// @returns the CallTarget owner of this parameter
+    CallTarget const* Owner() const { return owner_; }
 
-  /// @param owner the CallTarget owner of this parameter
-  void SetOwner(CallTarget const* owner) { owner_ = owner; }
+    /// @param owner the CallTarget owner of this parameter
+    void SetOwner(CallTarget const* owner) { owner_ = owner; }
 
-  /// @returns the Type, Function or Variable that this local variable shadows
-  const sem::Node* Shadows() const { return shadows_; }
+    /// @returns the Type, Function or Variable that this local variable shadows
+    const sem::Node* Shadows() const { return shadows_; }
 
-  /// Sets the Type, Function or Variable that this local variable shadows
-  /// @param shadows the Type, Function or Variable that this variable shadows
-  void SetShadows(const sem::Node* shadows) { shadows_ = shadows; }
+    /// Sets the Type, Function or Variable that this local variable shadows
+    /// @param shadows the Type, Function or Variable that this variable shadows
+    void SetShadows(const sem::Node* shadows) { shadows_ = shadows; }
 
- private:
-  const uint32_t index_;
-  const ParameterUsage usage_;
-  CallTarget const* owner_ = nullptr;
-  const sem::Node* shadows_ = nullptr;
+  private:
+    const uint32_t index_;
+    const ParameterUsage usage_;
+    CallTarget const* owner_ = nullptr;
+    const sem::Node* shadows_ = nullptr;
 };
 
 /// ParameterList is a list of Parameter
@@ -231,20 +227,20 @@
 /// VariableUser holds the semantic information for an identifier expression
 /// node that resolves to a variable.
 class VariableUser final : public Castable<VariableUser, Expression> {
- public:
-  /// Constructor
-  /// @param declaration the AST identifier node
-  /// @param statement the statement that owns this expression
-  /// @param variable the semantic variable
-  VariableUser(const ast::IdentifierExpression* declaration,
-               Statement* statement,
-               sem::Variable* variable);
+  public:
+    /// Constructor
+    /// @param declaration the AST identifier node
+    /// @param statement the statement that owns this expression
+    /// @param variable the semantic variable
+    VariableUser(const ast::IdentifierExpression* declaration,
+                 Statement* statement,
+                 sem::Variable* variable);
 
-  /// @returns the variable that this expression refers to
-  const sem::Variable* Variable() const { return variable_; }
+    /// @returns the variable that this expression refers to
+    const sem::Variable* Variable() const { return variable_; }
 
- private:
-  const sem::Variable* const variable_;
+  private:
+    const sem::Variable* const variable_;
 };
 
 /// A pair of sem::Variables. Can be hashed.
@@ -257,12 +253,12 @@
 /// Custom std::hash specialization for VariablePair
 template <>
 class hash<tint::sem::VariablePair> {
- public:
-  /// @param i the variable pair to create a hash for
-  /// @return the hash value
-  inline std::size_t operator()(const tint::sem::VariablePair& i) const {
-    return tint::utils::Hash(i.first, i.second);
-  }
+  public:
+    /// @param i the variable pair to create a hash for
+    /// @return the hash value
+    inline std::size_t operator()(const tint::sem::VariablePair& i) const {
+        return tint::utils::Hash(i.first, i.second);
+    }
 };
 
 }  // namespace std
diff --git a/src/tint/sem/vector.cc b/src/tint/sem/vector.cc
new file mode 100644
index 0000000..6b4e15d
--- /dev/null
+++ b/src/tint/sem/vector.cc
@@ -0,0 +1,86 @@
+// 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/sem/vector.h"
+
+#include "src/tint/program_builder.h"
+#include "src/tint/utils/hash.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::sem::Vector);
+
+namespace tint::sem {
+
+Vector::Vector(Type const* subtype, uint32_t width) : subtype_(subtype), width_(width) {
+    TINT_ASSERT(Semantic, width_ > 1);
+    TINT_ASSERT(Semantic, width_ < 5);
+}
+
+Vector::Vector(Vector&&) = default;
+
+Vector::~Vector() = default;
+
+size_t Vector::Hash() const {
+    return utils::Hash(TypeInfo::Of<Vector>().full_hashcode, width_, subtype_);
+}
+
+bool Vector::Equals(const Type& other) const {
+    if (auto* v = other.As<Vector>()) {
+        return v->width_ == width_ && v->subtype_ == subtype_;
+    }
+    return false;
+}
+
+std::string Vector::FriendlyName(const SymbolTable& symbols) const {
+    std::ostringstream out;
+    out << "vec" << width_ << "<" << subtype_->FriendlyName(symbols) << ">";
+    return out.str();
+}
+
+bool Vector::IsConstructible() const {
+    return true;
+}
+
+uint32_t Vector::Size() const {
+    return SizeOf(width_);
+}
+
+uint32_t Vector::Align() const {
+    return AlignOf(width_);
+}
+
+uint32_t Vector::SizeOf(uint32_t width) {
+    switch (width) {
+        case 2:
+            return 8;
+        case 3:
+            return 12;
+        case 4:
+            return 16;
+    }
+    return 0;  // Unreachable
+}
+
+uint32_t Vector::AlignOf(uint32_t width) {
+    switch (width) {
+        case 2:
+            return 8;
+        case 3:
+            return 16;
+        case 4:
+            return 16;
+    }
+    return 0;  // Unreachable
+}
+
+}  // namespace tint::sem
diff --git a/src/tint/sem/vector.h b/src/tint/sem/vector.h
new file mode 100644
index 0000000..8d9e7a3
--- /dev/null
+++ b/src/tint/sem/vector.h
@@ -0,0 +1,79 @@
+// 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_SEM_VECTOR_H_
+#define SRC_TINT_SEM_VECTOR_H_
+
+#include <string>
+
+#include "src/tint/sem/type.h"
+
+namespace tint::sem {
+
+/// A vector type.
+class Vector final : public Castable<Vector, Type> {
+  public:
+    /// Constructor
+    /// @param subtype the vector element type
+    /// @param size the number of elements in the vector
+    Vector(Type const* subtype, uint32_t size);
+    /// Move constructor
+    Vector(Vector&&);
+    ~Vector() override;
+
+    /// @returns a hash of the type.
+    size_t Hash() const override;
+
+    /// @param other the other type to compare against
+    /// @returns true if the this type is equal to the given type
+    bool Equals(const Type& other) const override;
+
+    /// @returns the type of the vector elements
+    const Type* type() const { return subtype_; }
+
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type that closely resembles how it would be
+    /// declared in WGSL.
+    std::string FriendlyName(const SymbolTable& symbols) const override;
+
+    /// @returns true if constructible as per
+    /// https://gpuweb.github.io/gpuweb/wgsl/#constructible-types
+    bool IsConstructible() const override;
+
+    /// @returns the number of elements in the vector
+    uint32_t Width() const { return width_; }
+
+    /// @returns the size in bytes of the type. This may include tail padding.
+    uint32_t Size() const override;
+
+    /// @returns the alignment in bytes of the type. This may include tail
+    /// padding.
+    uint32_t Align() const override;
+
+    /// @param width the width of the vector
+    /// @returns the size in bytes of a vector of the given width.
+    static uint32_t SizeOf(uint32_t width);
+
+    /// @param width the width of the vector
+    /// @returns the alignment in bytes of a vector of the given width.
+    static uint32_t AlignOf(uint32_t width);
+
+  private:
+    Type const* const subtype_;
+    const uint32_t width_;
+};
+
+}  // namespace tint::sem
+
+#endif  // SRC_TINT_SEM_VECTOR_H_
diff --git a/src/tint/sem/vector_test.cc b/src/tint/sem/vector_test.cc
new file mode 100644
index 0000000..adeca55
--- /dev/null
+++ b/src/tint/sem/vector_test.cc
@@ -0,0 +1,67 @@
+// 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/sem/test_helper.h"
+#include "src/tint/sem/texture.h"
+
+namespace tint::sem {
+namespace {
+
+using VectorTest = TestHelper;
+
+TEST_F(VectorTest, Creation) {
+    auto* a = create<Vector>(create<I32>(), 2u);
+    auto* b = create<Vector>(create<I32>(), 2u);
+    auto* c = create<Vector>(create<F32>(), 2u);
+    auto* d = create<Vector>(create<F32>(), 3u);
+
+    EXPECT_EQ(a->type(), create<I32>());
+    EXPECT_EQ(a->Width(), 2u);
+
+    EXPECT_EQ(a, b);
+    EXPECT_NE(a, c);
+    EXPECT_NE(a, d);
+}
+
+TEST_F(VectorTest, Hash) {
+    auto* a = create<Vector>(create<I32>(), 2u);
+    auto* b = create<Vector>(create<I32>(), 2u);
+    auto* c = create<Vector>(create<F32>(), 2u);
+    auto* d = create<Vector>(create<F32>(), 3u);
+
+    EXPECT_EQ(a->Hash(), b->Hash());
+    EXPECT_NE(a->Hash(), c->Hash());
+    EXPECT_NE(a->Hash(), d->Hash());
+}
+
+TEST_F(VectorTest, Equals) {
+    auto* a = create<Vector>(create<I32>(), 2u);
+    auto* b = create<Vector>(create<I32>(), 2u);
+    auto* c = create<Vector>(create<F32>(), 2u);
+    auto* d = create<Vector>(create<F32>(), 3u);
+
+    EXPECT_TRUE(a->Equals(*b));
+    EXPECT_FALSE(a->Equals(*c));
+    EXPECT_FALSE(a->Equals(*d));
+    EXPECT_FALSE(a->Equals(Void{}));
+}
+
+TEST_F(VectorTest, FriendlyName) {
+    auto* f32 = create<F32>();
+    auto* v = create<Vector>(f32, 3u);
+    EXPECT_EQ(v->FriendlyName(Symbols()), "vec3<f32>");
+}
+
+}  // namespace
+}  // namespace tint::sem
diff --git a/src/tint/sem/vector_type.cc b/src/tint/sem/vector_type.cc
deleted file mode 100644
index 1df3945..0000000
--- a/src/tint/sem/vector_type.cc
+++ /dev/null
@@ -1,87 +0,0 @@
-// Copyright 2020 The Tint Authors.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include "src/tint/sem/vector_type.h"
-
-#include "src/tint/program_builder.h"
-#include "src/tint/utils/hash.h"
-
-TINT_INSTANTIATE_TYPEINFO(tint::sem::Vector);
-
-namespace tint::sem {
-
-Vector::Vector(Type const* subtype, uint32_t width)
-    : subtype_(subtype), width_(width) {
-  TINT_ASSERT(Semantic, width_ > 1);
-  TINT_ASSERT(Semantic, width_ < 5);
-}
-
-Vector::Vector(Vector&&) = default;
-
-Vector::~Vector() = default;
-
-size_t Vector::Hash() const {
-  return utils::Hash(TypeInfo::Of<Vector>().full_hashcode, width_, subtype_);
-}
-
-bool Vector::Equals(const Type& other) const {
-  if (auto* v = other.As<Vector>()) {
-    return v->width_ == width_ && v->subtype_ == subtype_;
-  }
-  return false;
-}
-
-std::string Vector::FriendlyName(const SymbolTable& symbols) const {
-  std::ostringstream out;
-  out << "vec" << width_ << "<" << subtype_->FriendlyName(symbols) << ">";
-  return out.str();
-}
-
-bool Vector::IsConstructible() const {
-  return true;
-}
-
-uint32_t Vector::Size() const {
-  return SizeOf(width_);
-}
-
-uint32_t Vector::Align() const {
-  return AlignOf(width_);
-}
-
-uint32_t Vector::SizeOf(uint32_t width) {
-  switch (width) {
-    case 2:
-      return 8;
-    case 3:
-      return 12;
-    case 4:
-      return 16;
-  }
-  return 0;  // Unreachable
-}
-
-uint32_t Vector::AlignOf(uint32_t width) {
-  switch (width) {
-    case 2:
-      return 8;
-    case 3:
-      return 16;
-    case 4:
-      return 16;
-  }
-  return 0;  // Unreachable
-}
-
-}  // namespace tint::sem
diff --git a/src/tint/sem/vector_type.h b/src/tint/sem/vector_type.h
deleted file mode 100644
index 4542c5b..0000000
--- a/src/tint/sem/vector_type.h
+++ /dev/null
@@ -1,79 +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_SEM_VECTOR_TYPE_H_
-#define SRC_TINT_SEM_VECTOR_TYPE_H_
-
-#include <string>
-
-#include "src/tint/sem/type.h"
-
-namespace tint::sem {
-
-/// A vector type.
-class Vector final : public Castable<Vector, Type> {
- public:
-  /// Constructor
-  /// @param subtype the vector element type
-  /// @param size the number of elements in the vector
-  Vector(Type const* subtype, uint32_t size);
-  /// Move constructor
-  Vector(Vector&&);
-  ~Vector() override;
-
-  /// @returns a hash of the type.
-  size_t Hash() const override;
-
-  /// @param other the other type to compare against
-  /// @returns true if the this type is equal to the given type
-  bool Equals(const Type& other) const override;
-
-  /// @returns the type of the vector elements
-  const Type* type() const { return subtype_; }
-
-  /// @param symbols the program's symbol table
-  /// @returns the name for this type that closely resembles how it would be
-  /// declared in WGSL.
-  std::string FriendlyName(const SymbolTable& symbols) const override;
-
-  /// @returns true if constructible as per
-  /// https://gpuweb.github.io/gpuweb/wgsl/#constructible-types
-  bool IsConstructible() const override;
-
-  /// @returns the number of elements in the vector
-  uint32_t Width() const { return width_; }
-
-  /// @returns the size in bytes of the type. This may include tail padding.
-  uint32_t Size() const override;
-
-  /// @returns the alignment in bytes of the type. This may include tail
-  /// padding.
-  uint32_t Align() const override;
-
-  /// @param width the width of the vector
-  /// @returns the size in bytes of a vector of the given width.
-  static uint32_t SizeOf(uint32_t width);
-
-  /// @param width the width of the vector
-  /// @returns the alignment in bytes of a vector of the given width.
-  static uint32_t AlignOf(uint32_t width);
-
- private:
-  Type const* const subtype_;
-  const uint32_t width_;
-};
-
-}  // namespace tint::sem
-
-#endif  // SRC_TINT_SEM_VECTOR_TYPE_H_
diff --git a/src/tint/sem/vector_type_test.cc b/src/tint/sem/vector_type_test.cc
deleted file mode 100644
index 4d53918..0000000
--- a/src/tint/sem/vector_type_test.cc
+++ /dev/null
@@ -1,67 +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/sem/test_helper.h"
-#include "src/tint/sem/texture_type.h"
-
-namespace tint::sem {
-namespace {
-
-using VectorTest = TestHelper;
-
-TEST_F(VectorTest, Creation) {
-  auto* a = create<Vector>(create<I32>(), 2u);
-  auto* b = create<Vector>(create<I32>(), 2u);
-  auto* c = create<Vector>(create<F32>(), 2u);
-  auto* d = create<Vector>(create<F32>(), 3u);
-
-  EXPECT_EQ(a->type(), create<I32>());
-  EXPECT_EQ(a->Width(), 2u);
-
-  EXPECT_EQ(a, b);
-  EXPECT_NE(a, c);
-  EXPECT_NE(a, d);
-}
-
-TEST_F(VectorTest, Hash) {
-  auto* a = create<Vector>(create<I32>(), 2u);
-  auto* b = create<Vector>(create<I32>(), 2u);
-  auto* c = create<Vector>(create<F32>(), 2u);
-  auto* d = create<Vector>(create<F32>(), 3u);
-
-  EXPECT_EQ(a->Hash(), b->Hash());
-  EXPECT_NE(a->Hash(), c->Hash());
-  EXPECT_NE(a->Hash(), d->Hash());
-}
-
-TEST_F(VectorTest, Equals) {
-  auto* a = create<Vector>(create<I32>(), 2u);
-  auto* b = create<Vector>(create<I32>(), 2u);
-  auto* c = create<Vector>(create<F32>(), 2u);
-  auto* d = create<Vector>(create<F32>(), 3u);
-
-  EXPECT_TRUE(a->Equals(*b));
-  EXPECT_FALSE(a->Equals(*c));
-  EXPECT_FALSE(a->Equals(*d));
-  EXPECT_FALSE(a->Equals(Void{}));
-}
-
-TEST_F(VectorTest, FriendlyName) {
-  auto* f32 = create<F32>();
-  auto* v = create<Vector>(f32, 3u);
-  EXPECT_EQ(v->FriendlyName(Symbols()), "vec3<f32>");
-}
-
-}  // namespace
-}  // namespace tint::sem
diff --git a/src/tint/sem/void_type.cc b/src/tint/sem/void.cc
similarity index 86%
rename from src/tint/sem/void_type.cc
rename to src/tint/sem/void.cc
index 6dae921..b20b96e 100644
--- a/src/tint/sem/void_type.cc
+++ b/src/tint/sem/void.cc
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/sem/void_type.h"
+#include "src/tint/sem/void.h"
 
 #include "src/tint/program_builder.h"
 
@@ -27,15 +27,15 @@
 Void::~Void() = default;
 
 size_t Void::Hash() const {
-  return static_cast<size_t>(TypeInfo::Of<Void>().full_hashcode);
+    return static_cast<size_t>(TypeInfo::Of<Void>().full_hashcode);
 }
 
 bool Void::Equals(const Type& other) const {
-  return other.Is<Void>();
+    return other.Is<Void>();
 }
 
 std::string Void::FriendlyName(const SymbolTable&) const {
-  return "void";
+    return "void";
 }
 
 }  // namespace tint::sem
diff --git a/src/tint/sem/void.h b/src/tint/sem/void.h
new file mode 100644
index 0000000..21cc3b1
--- /dev/null
+++ b/src/tint/sem/void.h
@@ -0,0 +1,48 @@
+// 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_SEM_VOID_H_
+#define SRC_TINT_SEM_VOID_H_
+
+#include <string>
+
+#include "src/tint/sem/type.h"
+
+namespace tint::sem {
+
+/// A void type
+class Void final : public Castable<Void, Type> {
+  public:
+    /// Constructor
+    Void();
+    /// Move constructor
+    Void(Void&&);
+    ~Void() override;
+
+    /// @returns a hash of the type.
+    size_t Hash() const override;
+
+    /// @param other the other type to compare against
+    /// @returns true if the this type is equal to the given type
+    bool Equals(const Type& other) const override;
+
+    /// @param symbols the program's symbol table
+    /// @returns the name for this type that closely resembles how it would be
+    /// declared in WGSL.
+    std::string FriendlyName(const SymbolTable& symbols) const override;
+};
+
+}  // namespace tint::sem
+
+#endif  // SRC_TINT_SEM_VOID_H_
diff --git a/src/tint/sem/void_type.h b/src/tint/sem/void_type.h
deleted file mode 100644
index 1131cb8..0000000
--- a/src/tint/sem/void_type.h
+++ /dev/null
@@ -1,48 +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_SEM_VOID_TYPE_H_
-#define SRC_TINT_SEM_VOID_TYPE_H_
-
-#include <string>
-
-#include "src/tint/sem/type.h"
-
-namespace tint::sem {
-
-/// A void type
-class Void final : public Castable<Void, Type> {
- public:
-  /// Constructor
-  Void();
-  /// Move constructor
-  Void(Void&&);
-  ~Void() override;
-
-  /// @returns a hash of the type.
-  size_t Hash() const override;
-
-  /// @param other the other type to compare against
-  /// @returns true if the this type is equal to the given type
-  bool Equals(const Type& other) const override;
-
-  /// @param symbols the program's symbol table
-  /// @returns the name for this type that closely resembles how it would be
-  /// declared in WGSL.
-  std::string FriendlyName(const SymbolTable& symbols) const override;
-};
-
-}  // namespace tint::sem
-
-#endif  // SRC_TINT_SEM_VOID_TYPE_H_
diff --git a/src/tint/source.cc b/src/tint/source.cc
index 9a172e3..5dbed6c 100644
--- a/src/tint/source.cc
+++ b/src/tint/source.cc
@@ -19,41 +19,96 @@
 #include <string_view>
 #include <utility>
 
+#include "src/tint/text/unicode.h"
+
 namespace tint {
 namespace {
-std::vector<std::string_view> SplitLines(std::string_view str) {
-  std::vector<std::string_view> lines;
 
-  size_t lineStart = 0;
-  for (size_t i = 0; i < str.size(); ++i) {
-    if (str[i] == '\n') {
-      // Handle CRLF on Windows
-      size_t curr = i;
-      if (i > 0 && str[i - 1] == '\r') {
-        --curr;
-      }
-      lines.push_back(str.substr(lineStart, curr - lineStart));
-      lineStart = i + 1;
+bool ParseLineBreak(std::string_view str, size_t i, bool* is_line_break, size_t* line_break_size) {
+    // See https://www.w3.org/TR/WGSL/#blankspace
+
+    auto* utf8 = reinterpret_cast<const uint8_t*>(&str[i]);
+    auto [cp, n] = text::utf8::Decode(utf8, str.size() - i);
+
+    if (n == 0) {
+        return false;
     }
-  }
-  if (lineStart < str.size()) {
-    lines.push_back(str.substr(lineStart));
-  }
 
-  return lines;
+    static const auto kLF = text::CodePoint(0x000A);    // line feed
+    static const auto kVTab = text::CodePoint(0x000B);  // vertical tab
+    static const auto kFF = text::CodePoint(0x000C);    // form feed
+    static const auto kNL = text::CodePoint(0x0085);    // next line
+    static const auto kCR = text::CodePoint(0x000D);    // carriage return
+    static const auto kLS = text::CodePoint(0x2028);    // line separator
+    static const auto kPS = text::CodePoint(0x2029);    // parargraph separator
+
+    if (cp == kLF || cp == kVTab || cp == kFF || cp == kNL || cp == kPS || cp == kLS) {
+        *is_line_break = true;
+        *line_break_size = n;
+        return true;
+    }
+
+    // Handle CRLF as one line break, and CR alone as one line break
+    if (cp == kCR) {
+        *is_line_break = true;
+        *line_break_size = n;
+
+        if (auto next_i = i + n; next_i < str.size()) {
+            auto* next_utf8 = reinterpret_cast<const uint8_t*>(&str[next_i]);
+            auto [next_cp, next_n] = text::utf8::Decode(next_utf8, str.size() - next_i);
+
+            if (next_n == 0) {
+                return false;
+            }
+
+            if (next_cp == kLF) {
+                // CRLF as one break
+                *line_break_size = n + next_n;
+            }
+        }
+
+        return true;
+    }
+
+    *is_line_break = false;
+    return true;
 }
 
-std::vector<std::string_view> CopyRelativeStringViews(
-    const std::vector<std::string_view>& src_list,
-    const std::string_view& src_view,
-    const std::string_view& dst_view) {
-  std::vector<std::string_view> out(src_list.size());
-  for (size_t i = 0; i < src_list.size(); i++) {
-    auto offset = static_cast<size_t>(&src_list[i].front() - &src_view.front());
-    auto count = src_list[i].length();
-    out[i] = dst_view.substr(offset, count);
-  }
-  return out;
+std::vector<std::string_view> SplitLines(std::string_view str) {
+    std::vector<std::string_view> lines;
+
+    size_t lineStart = 0;
+    for (size_t i = 0; i < str.size();) {
+        bool is_line_break{};
+        size_t line_break_size{};
+        // We don't handle decode errors from ParseLineBreak. Instead, we rely on
+        // the Lexer to do so.
+        ParseLineBreak(str, i, &is_line_break, &line_break_size);
+        if (is_line_break) {
+            lines.push_back(str.substr(lineStart, i - lineStart));
+            i += line_break_size;
+            lineStart = i;
+        } else {
+            ++i;
+        }
+    }
+    if (lineStart < str.size()) {
+        lines.push_back(str.substr(lineStart));
+    }
+
+    return lines;
+}
+
+std::vector<std::string_view> CopyRelativeStringViews(const std::vector<std::string_view>& src_list,
+                                                      const std::string_view& src_view,
+                                                      const std::string_view& dst_view) {
+    std::vector<std::string_view> out(src_list.size());
+    for (size_t i = 0; i < src_list.size(); i++) {
+        auto offset = static_cast<size_t>(&src_list[i].front() - &src_view.front());
+        auto count = src_list[i].length();
+        out[i] = dst_view.substr(offset, count);
+    }
+    return out;
 }
 
 }  // namespace
@@ -71,56 +126,56 @@
 Source::File::~File() = default;
 
 std::ostream& operator<<(std::ostream& out, const Source& source) {
-  auto rng = source.range;
-
-  if (source.file) {
-    out << source.file->path << ":";
-  }
-  if (rng.begin.line) {
-    out << rng.begin.line << ":";
-    if (rng.begin.column) {
-      out << rng.begin.column;
-    }
+    auto rng = source.range;
 
     if (source.file) {
-      out << std::endl << std::endl;
-
-      auto repeat = [&](char c, size_t n) {
-        while (n--) {
-          out << c;
-        }
-      };
-
-      for (size_t line = rng.begin.line; line <= rng.end.line; line++) {
-        if (line < source.file->content.lines.size() + 1) {
-          auto len = source.file->content.lines[line - 1].size();
-
-          out << source.file->content.lines[line - 1];
-
-          out << std::endl;
-
-          if (line == rng.begin.line && line == rng.end.line) {
-            // Single line
-            repeat(' ', rng.begin.column - 1);
-            repeat('^', std::max<size_t>(rng.end.column - rng.begin.column, 1));
-          } else if (line == rng.begin.line) {
-            // Start of multi-line
-            repeat(' ', rng.begin.column - 1);
-            repeat('^', len - (rng.begin.column - 1));
-          } else if (line == rng.end.line) {
-            // End of multi-line
-            repeat('^', rng.end.column - 1);
-          } else {
-            // Middle of multi-line
-            repeat('^', len);
-          }
-
-          out << std::endl;
-        }
-      }
+        out << source.file->path << ":";
     }
-  }
-  return out;
+    if (rng.begin.line) {
+        out << rng.begin.line << ":";
+        if (rng.begin.column) {
+            out << rng.begin.column;
+        }
+
+        if (source.file) {
+            out << std::endl << std::endl;
+
+            auto repeat = [&](char c, size_t n) {
+                while (n--) {
+                    out << c;
+                }
+            };
+
+            for (size_t line = rng.begin.line; line <= rng.end.line; line++) {
+                if (line < source.file->content.lines.size() + 1) {
+                    auto len = source.file->content.lines[line - 1].size();
+
+                    out << source.file->content.lines[line - 1];
+
+                    out << std::endl;
+
+                    if (line == rng.begin.line && line == rng.end.line) {
+                        // Single line
+                        repeat(' ', rng.begin.column - 1);
+                        repeat('^', std::max<size_t>(rng.end.column - rng.begin.column, 1));
+                    } else if (line == rng.begin.line) {
+                        // Start of multi-line
+                        repeat(' ', rng.begin.column - 1);
+                        repeat('^', len - (rng.begin.column - 1));
+                    } else if (line == rng.end.line) {
+                        // End of multi-line
+                        repeat('^', rng.end.column - 1);
+                    } else {
+                        // Middle of multi-line
+                        repeat('^', len);
+                    }
+
+                    out << std::endl;
+                }
+            }
+        }
+    }
+    return out;
 }
 
 }  // namespace tint
diff --git a/src/tint/source.h b/src/tint/source.h
index 931cdf1..734e693 100644
--- a/src/tint/source.h
+++ b/src/tint/source.h
@@ -26,186 +26,180 @@
 
 /// Source describes a range of characters within a source file.
 class Source {
- public:
-  /// FileContent describes the content of a source file encoded using utf-8.
-  class FileContent {
-   public:
-    /// Constructs the FileContent with the given file content.
-    /// @param data the file contents
-    explicit FileContent(const std::string& data);
+  public:
+    /// FileContent describes the content of a source file encoded using utf-8.
+    class FileContent {
+      public:
+        /// Constructs the FileContent with the given file content.
+        /// @param data the file contents
+        explicit FileContent(const std::string& data);
 
-    /// Copy constructor
-    /// @param rhs the FileContent to copy
-    FileContent(const FileContent& rhs);
+        /// Copy constructor
+        /// @param rhs the FileContent to copy
+        FileContent(const FileContent& rhs);
 
-    /// Destructor
-    ~FileContent();
+        /// Destructor
+        ~FileContent();
 
-    /// The original un-split file content
-    const std::string data;
-    /// A string_view over #data
-    const std::string_view data_view;
-    /// #data split by lines
-    const std::vector<std::string_view> lines;
-  };
+        /// The original un-split file content
+        const std::string data;
+        /// A string_view over #data
+        const std::string_view data_view;
+        /// #data split by lines
+        const std::vector<std::string_view> lines;
+    };
 
-  /// File describes a source file, including path and content.
-  class File {
-   public:
-    /// Constructs the File with the given file path and content.
-    /// @param p the path for this file
-    /// @param c the file contents
-    inline File(const std::string& p, const std::string& c)
-        : path(p), content(c) {}
+    /// File describes a source file, including path and content.
+    class File {
+      public:
+        /// Constructs the File with the given file path and content.
+        /// @param p the path for this file
+        /// @param c the file contents
+        inline File(const std::string& p, const std::string& c) : path(p), content(c) {}
 
-    /// Copy constructor
-    File(const File&) = default;
+        /// Copy constructor
+        File(const File&) = default;
 
-    /// Move constructor
-    File(File&&) = default;
+        /// Move constructor
+        File(File&&) = default;
 
-    /// Destructor
-    ~File();
+        /// Destructor
+        ~File();
 
-    /// file path
-    const std::string path;
-    /// file content
-    const FileContent content;
-  };
+        /// file path
+        const std::string path;
+        /// file content
+        const FileContent content;
+    };
 
-  /// Location holds a 1-based line and column index.
-  class Location {
-   public:
-    /// the 1-based line number. 0 represents no line information.
-    size_t line = 0;
-    /// the 1-based column number in utf8-code units (bytes).
-    /// 0 represents no column information.
-    size_t column = 0;
+    /// Location holds a 1-based line and column index.
+    class Location {
+      public:
+        /// the 1-based line number. 0 represents no line information.
+        size_t line = 0;
+        /// the 1-based column number in utf8-code units (bytes).
+        /// 0 represents no column information.
+        size_t column = 0;
 
-    /// Returns true of `this` location is lexicographically less than `rhs`
-    /// @param rhs location to compare against
-    /// @returns true if `this` < `rhs`
-    inline bool operator<(const Source::Location& rhs) {
-      return std::tie(line, column) < std::tie(rhs.line, rhs.column);
-    }
+        /// Returns true of `this` location is lexicographically less than `rhs`
+        /// @param rhs location to compare against
+        /// @returns true if `this` < `rhs`
+        inline bool operator<(const Source::Location& rhs) {
+            return std::tie(line, column) < std::tie(rhs.line, rhs.column);
+        }
 
-    /// Returns true of `this` location is equal to `rhs`
-    /// @param rhs location to compare against
-    /// @returns true if `this` == `rhs`
-    inline bool operator==(const Location& rhs) const {
-      return line == rhs.line && column == rhs.column;
-    }
+        /// Returns true of `this` location is equal to `rhs`
+        /// @param rhs location to compare against
+        /// @returns true if `this` == `rhs`
+        inline bool operator==(const Location& rhs) const {
+            return line == rhs.line && column == rhs.column;
+        }
 
-    /// Returns true of `this` location is not equal to `rhs`
-    /// @param rhs location to compare against
-    /// @returns true if `this` != `rhs`
-    inline bool operator!=(const Location& rhs) const {
-      return !(*this == rhs);
-    }
-  };
+        /// Returns true of `this` location is not equal to `rhs`
+        /// @param rhs location to compare against
+        /// @returns true if `this` != `rhs`
+        inline bool operator!=(const Location& rhs) const { return !(*this == rhs); }
+    };
 
-  /// Range holds a Location interval described by [begin, end).
-  class Range {
-   public:
-    /// Constructs a zero initialized Range.
-    inline Range() = default;
+    /// Range holds a Location interval described by [begin, end).
+    class Range {
+      public:
+        /// Constructs a zero initialized Range.
+        inline Range() = default;
 
-    /// Constructs a zero-length Range starting at `loc`
-    /// @param loc the start and end location for the range
-    inline constexpr explicit Range(const Location& loc)
-        : begin(loc), end(loc) {}
+        /// Constructs a zero-length Range starting at `loc`
+        /// @param loc the start and end location for the range
+        inline constexpr explicit Range(const Location& loc) : begin(loc), end(loc) {}
 
-    /// Constructs the Range beginning at `b` and ending at `e`
-    /// @param b the range start location
-    /// @param e the range end location
-    inline constexpr Range(const Location& b, const Location& e)
-        : begin(b), end(e) {}
+        /// Constructs the Range beginning at `b` and ending at `e`
+        /// @param b the range start location
+        /// @param e the range end location
+        inline constexpr Range(const Location& b, const Location& e) : begin(b), end(e) {}
 
-    /// Return a column-shifted Range
+        /// Return a column-shifted Range
+        /// @param n the number of characters to shift by
+        /// @returns a Range with a #begin and #end column shifted by `n`
+        inline Range operator+(size_t n) const {
+            return Range{{begin.line, begin.column + n}, {end.line, end.column + n}};
+        }
+
+        /// Returns true of `this` range is not equal to `rhs`
+        /// @param rhs range to compare against
+        /// @returns true if `this` != `rhs`
+        inline bool operator==(const Range& rhs) const {
+            return begin == rhs.begin && end == rhs.end;
+        }
+
+        /// Returns true of `this` range is equal to `rhs`
+        /// @param rhs range to compare against
+        /// @returns true if `this` == `rhs`
+        inline bool operator!=(const Range& rhs) const { return !(*this == rhs); }
+
+        /// The location of the first character in the range.
+        Location begin;
+        /// The location of one-past the last character in the range.
+        Location end;
+    };
+
+    /// Constructs the Source with an zero initialized Range and null File.
+    inline Source() : range() {}
+
+    /// Constructs the Source with the Range `rng` and a null File
+    /// @param rng the source range
+    inline explicit Source(const Range& rng) : range(rng) {}
+
+    /// Constructs the Source with the Range `loc` and a null File
+    /// @param loc the start and end location for the source range
+    inline explicit Source(const Location& loc) : range(Range(loc)) {}
+
+    /// Constructs the Source with the Range `rng` and File `file`
+    /// @param rng the source range
+    /// @param f the source file
+    inline Source(const Range& rng, File const* f) : range(rng), file(f) {}
+
+    /// @returns a Source that points to the begin range of this Source.
+    inline Source Begin() const { return Source(Range{range.begin}, file); }
+
+    /// @returns a Source that points to the end range of this Source.
+    inline Source End() const { return Source(Range{range.end}, file); }
+
+    /// Return a column-shifted Source
     /// @param n the number of characters to shift by
-    /// @returns a Range with a #begin and #end column shifted by `n`
-    inline Range operator+(size_t n) const {
-      return Range{{begin.line, begin.column + n}, {end.line, end.column + n}};
+    /// @returns a Source with the range's columns shifted by `n`
+    inline Source operator+(size_t n) const { return Source(range + n, file); }
+
+    /// Returns true of `this` Source is lexicographically less than `rhs`
+    /// @param rhs source to compare against
+    /// @returns true if `this` < `rhs`
+    inline bool operator<(const Source& rhs) {
+        if (file != rhs.file) {
+            return false;
+        }
+        return range.begin < rhs.range.begin;
     }
 
-    /// Returns true of `this` range is not equal to `rhs`
-    /// @param rhs range to compare against
-    /// @returns true if `this` != `rhs`
-    inline bool operator==(const Range& rhs) const {
-      return begin == rhs.begin && end == rhs.end;
+    /// Helper function that returns the range union of two source locations. The
+    /// `start` and `end` locations are assumed to refer to the same source file.
+    /// @param start the start source of the range
+    /// @param end the end source of the range
+    /// @returns the combined source
+    inline static Source Combine(const Source& start, const Source& end) {
+        return Source(Source::Range(start.range.begin, end.range.end), start.file);
     }
 
-    /// Returns true of `this` range is equal to `rhs`
-    /// @param rhs range to compare against
-    /// @returns true if `this` == `rhs`
-    inline bool operator!=(const Range& rhs) const { return !(*this == rhs); }
-
-    /// The location of the first character in the range.
-    Location begin;
-    /// The location of one-past the last character in the range.
-    Location end;
-  };
-
-  /// Constructs the Source with an zero initialized Range and null File.
-  inline Source() : range() {}
-
-  /// Constructs the Source with the Range `rng` and a null File
-  /// @param rng the source range
-  inline explicit Source(const Range& rng) : range(rng) {}
-
-  /// Constructs the Source with the Range `loc` and a null File
-  /// @param loc the start and end location for the source range
-  inline explicit Source(const Location& loc) : range(Range(loc)) {}
-
-  /// Constructs the Source with the Range `rng` and File `file`
-  /// @param rng the source range
-  /// @param f the source file
-  inline Source(const Range& rng, File const* f) : range(rng), file(f) {}
-
-  /// @returns a Source that points to the begin range of this Source.
-  inline Source Begin() const { return Source(Range{range.begin}, file); }
-
-  /// @returns a Source that points to the end range of this Source.
-  inline Source End() const { return Source(Range{range.end}, file); }
-
-  /// Return a column-shifted Source
-  /// @param n the number of characters to shift by
-  /// @returns a Source with the range's columns shifted by `n`
-  inline Source operator+(size_t n) const { return Source(range + n, file); }
-
-  /// Returns true of `this` Source is lexicographically less than `rhs`
-  /// @param rhs source to compare against
-  /// @returns true if `this` < `rhs`
-  inline bool operator<(const Source& rhs) {
-    if (file != rhs.file) {
-      return false;
-    }
-    return range.begin < rhs.range.begin;
-  }
-
-  /// Helper function that returns the range union of two source locations. The
-  /// `start` and `end` locations are assumed to refer to the same source file.
-  /// @param start the start source of the range
-  /// @param end the end source of the range
-  /// @returns the combined source
-  inline static Source Combine(const Source& start, const Source& end) {
-    return Source(Source::Range(start.range.begin, end.range.end), start.file);
-  }
-
-  /// range is the span of text this source refers to in #file
-  Range range;
-  /// file is the optional source content this source refers to
-  const File* file = nullptr;
+    /// range is the span of text this source refers to in #file
+    Range range;
+    /// file is the optional source content this source refers to
+    const File* file = nullptr;
 };
 
 /// Writes the Source::Location to the std::ostream.
 /// @param out the std::ostream to write to
 /// @param loc the location to write
 /// @returns out so calls can be chained
-inline std::ostream& operator<<(std::ostream& out,
-                                const Source::Location& loc) {
-  out << loc.line << ":" << loc.column;
-  return out;
+inline std::ostream& operator<<(std::ostream& out, const Source::Location& loc) {
+    out << loc.line << ":" << loc.column;
+    return out;
 }
 
 /// Writes the Source::Range to the std::ostream.
@@ -213,8 +207,8 @@
 /// @param range the range to write
 /// @returns out so calls can be chained
 inline std::ostream& operator<<(std::ostream& out, const Source::Range& range) {
-  out << "[" << range.begin << ", " << range.end << "]";
-  return out;
+    out << "[" << range.begin << ", " << range.end << "]";
+    return out;
 }
 
 /// Writes the Source to the std::ostream.
@@ -227,10 +221,9 @@
 /// @param out the std::ostream to write to
 /// @param content the file content to write
 /// @returns out so calls can be chained
-inline std::ostream& operator<<(std::ostream& out,
-                                const Source::FileContent& content) {
-  out << content.data;
-  return out;
+inline std::ostream& operator<<(std::ostream& out, const Source::FileContent& content) {
+    out << content.data;
+    return out;
 }
 
 }  // namespace tint
diff --git a/src/tint/source_test.cc b/src/tint/source_test.cc
index a3b9825..5cc0078 100644
--- a/src/tint/source_test.cc
+++ b/src/tint/source_test.cc
@@ -29,38 +29,74 @@
 using SourceFileContentTest = testing::Test;
 
 TEST_F(SourceFileContentTest, Ctor) {
-  Source::FileContent fc(kSource);
-  EXPECT_EQ(fc.data, kSource);
-  EXPECT_EQ(fc.data_view, kSource);
-  ASSERT_EQ(fc.lines.size(), 3u);
-  EXPECT_EQ(fc.lines[0], "line one");
-  EXPECT_EQ(fc.lines[1], "line two");
-  EXPECT_EQ(fc.lines[2], "line three");
+    Source::FileContent fc(kSource);
+    EXPECT_EQ(fc.data, kSource);
+    EXPECT_EQ(fc.data_view, kSource);
+    ASSERT_EQ(fc.lines.size(), 3u);
+    EXPECT_EQ(fc.lines[0], "line one");
+    EXPECT_EQ(fc.lines[1], "line two");
+    EXPECT_EQ(fc.lines[2], "line three");
 }
 
 TEST_F(SourceFileContentTest, CopyCtor) {
-  auto src = std::make_unique<Source::FileContent>(kSource);
-  Source::FileContent fc{*src};
-  src.reset();
-  EXPECT_EQ(fc.data, kSource);
-  EXPECT_EQ(fc.data_view, kSource);
-  ASSERT_EQ(fc.lines.size(), 3u);
-  EXPECT_EQ(fc.lines[0], "line one");
-  EXPECT_EQ(fc.lines[1], "line two");
-  EXPECT_EQ(fc.lines[2], "line three");
+    auto src = std::make_unique<Source::FileContent>(kSource);
+    Source::FileContent fc{*src};
+    src.reset();
+    EXPECT_EQ(fc.data, kSource);
+    EXPECT_EQ(fc.data_view, kSource);
+    ASSERT_EQ(fc.lines.size(), 3u);
+    EXPECT_EQ(fc.lines[0], "line one");
+    EXPECT_EQ(fc.lines[1], "line two");
+    EXPECT_EQ(fc.lines[2], "line three");
 }
 
 TEST_F(SourceFileContentTest, MoveCtor) {
-  auto src = std::make_unique<Source::FileContent>(kSource);
-  Source::FileContent fc{std::move(*src)};
-  src.reset();
-  EXPECT_EQ(fc.data, kSource);
-  EXPECT_EQ(fc.data_view, kSource);
-  ASSERT_EQ(fc.lines.size(), 3u);
-  EXPECT_EQ(fc.lines[0], "line one");
-  EXPECT_EQ(fc.lines[1], "line two");
-  EXPECT_EQ(fc.lines[2], "line three");
+    auto src = std::make_unique<Source::FileContent>(kSource);
+    Source::FileContent fc{std::move(*src)};
+    src.reset();
+    EXPECT_EQ(fc.data, kSource);
+    EXPECT_EQ(fc.data_view, kSource);
+    ASSERT_EQ(fc.lines.size(), 3u);
+    EXPECT_EQ(fc.lines[0], "line one");
+    EXPECT_EQ(fc.lines[1], "line two");
+    EXPECT_EQ(fc.lines[2], "line three");
 }
 
+// Line break code points
+#define kCR "\r"
+#define kLF "\n"
+#define kVTab "\x0B"
+#define kFF "\x0C"
+#define kNL "\xC2\x85"
+#define kLS "\xE2\x80\xA8"
+#define kPS "\xE2\x80\xA9"
+
+using LineBreakTest = testing::TestWithParam<const char*>;
+TEST_P(LineBreakTest, Single) {
+    std::string src = "line one";
+    src += GetParam();
+    src += "line two";
+
+    Source::FileContent fc(src);
+    EXPECT_EQ(fc.lines.size(), 2u);
+    EXPECT_EQ(fc.lines[0], "line one");
+    EXPECT_EQ(fc.lines[1], "line two");
+}
+TEST_P(LineBreakTest, Double) {
+    std::string src = "line one";
+    src += GetParam();
+    src += GetParam();
+    src += "line two";
+
+    Source::FileContent fc(src);
+    EXPECT_EQ(fc.lines.size(), 3u);
+    EXPECT_EQ(fc.lines[0], "line one");
+    EXPECT_EQ(fc.lines[1], "");
+    EXPECT_EQ(fc.lines[2], "line two");
+}
+INSTANTIATE_TEST_SUITE_P(SourceFileContentTest,
+                         LineBreakTest,
+                         testing::Values(kVTab, kFF, kNL, kLS, kPS, kLF, kCR, kCR kLF));
+
 }  // namespace
 }  // namespace tint
diff --git a/src/tint/symbol.cc b/src/tint/symbol.cc
index 43218a7..0965697 100644
--- a/src/tint/symbol.cc
+++ b/src/tint/symbol.cc
@@ -20,8 +20,7 @@
 
 Symbol::Symbol() = default;
 
-Symbol::Symbol(uint32_t val, tint::ProgramID program_id)
-    : val_(val), program_id_(program_id) {}
+Symbol::Symbol(uint32_t val, tint::ProgramID program_id) : val_(val), program_id_(program_id) {}
 
 #if TINT_SYMBOL_STORE_DEBUG_NAME
 Symbol::Symbol(uint32_t val, tint::ProgramID program_id, std::string debug_name)
@@ -39,19 +38,17 @@
 Symbol& Symbol::operator=(Symbol&& o) = default;
 
 bool Symbol::operator==(const Symbol& other) const {
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Symbol, program_id_,
-                                         other.program_id_);
-  return val_ == other.val_;
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Symbol, program_id_, other.program_id_);
+    return val_ == other.val_;
 }
 
 bool Symbol::operator<(const Symbol& other) const {
-  TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Symbol, program_id_,
-                                         other.program_id_);
-  return val_ < other.val_;
+    TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Symbol, program_id_, other.program_id_);
+    return val_ < other.val_;
 }
 
 std::string Symbol::to_str() const {
-  return "$" + std::to_string(val_);
+    return "$" + std::to_string(val_);
 }
 
 }  // namespace tint
diff --git a/src/tint/symbol.h b/src/tint/symbol.h
index 801fe62..1cbc6b2 100644
--- a/src/tint/symbol.h
+++ b/src/tint/symbol.h
@@ -30,74 +30,74 @@
 
 /// A symbol representing a string in the system
 class Symbol {
- public:
-  /// Constructor
-  /// An invalid symbol
-  Symbol();
-  /// Constructor
-  /// @param val the symbol value
-  /// @param program_id the identifier of the program that owns this Symbol
-  Symbol(uint32_t val, tint::ProgramID program_id);
+  public:
+    /// Constructor
+    /// An invalid symbol
+    Symbol();
+    /// Constructor
+    /// @param val the symbol value
+    /// @param program_id the identifier of the program that owns this Symbol
+    Symbol(uint32_t val, tint::ProgramID program_id);
 #if TINT_SYMBOL_STORE_DEBUG_NAME
-  /// Constructor
-  /// @param val the symbol value
-  /// @param program_id the identifier of the program that owns this Symbol
-  /// @param debug_name name of symbols used only for debugging
-  Symbol(uint32_t val, tint::ProgramID program_id, std::string debug_name);
+    /// Constructor
+    /// @param val the symbol value
+    /// @param program_id the identifier of the program that owns this Symbol
+    /// @param debug_name name of symbols used only for debugging
+    Symbol(uint32_t val, tint::ProgramID program_id, std::string debug_name);
 #endif
-  /// Copy constructor
-  /// @param o the symbol to copy
-  Symbol(const Symbol& o);
-  /// Move constructor
-  /// @param o the symbol to move
-  Symbol(Symbol&& o);
-  /// Destructor
-  ~Symbol();
+    /// Copy constructor
+    /// @param o the symbol to copy
+    Symbol(const Symbol& o);
+    /// Move constructor
+    /// @param o the symbol to move
+    Symbol(Symbol&& o);
+    /// Destructor
+    ~Symbol();
 
-  /// Copy assignment
-  /// @param o the other symbol
-  /// @returns the symbol after doing the copy
-  Symbol& operator=(const Symbol& o);
-  /// Move assignment
-  /// @param o the other symbol
-  /// @returns teh symbol after doing the move
-  Symbol& operator=(Symbol&& o);
+    /// Copy assignment
+    /// @param o the other symbol
+    /// @returns the symbol after doing the copy
+    Symbol& operator=(const Symbol& o);
+    /// Move assignment
+    /// @param o the other symbol
+    /// @returns teh symbol after doing the move
+    Symbol& operator=(Symbol&& o);
 
-  /// Comparison operator
-  /// @param o the other symbol
-  /// @returns true if the symbols are the same
-  bool operator==(const Symbol& o) const;
+    /// Comparison operator
+    /// @param o the other symbol
+    /// @returns true if the symbols are the same
+    bool operator==(const Symbol& o) const;
 
-  /// Less-than operator
-  /// @param o the other symbol
-  /// @returns true if this symbol is ordered before symbol `o`
-  bool operator<(const Symbol& o) const;
+    /// Less-than operator
+    /// @param o the other symbol
+    /// @returns true if this symbol is ordered before symbol `o`
+    bool operator<(const Symbol& o) const;
 
-  /// @returns true if the symbol is valid
-  bool IsValid() const { return val_ != static_cast<uint32_t>(-1); }
+    /// @returns true if the symbol is valid
+    bool IsValid() const { return val_ != static_cast<uint32_t>(-1); }
 
-  /// @returns the value for the symbol
-  uint32_t value() const { return val_; }
+    /// @returns the value for the symbol
+    uint32_t value() const { return val_; }
 
-  /// Convert the symbol to a string
-  /// @return the string representation of the symbol
-  std::string to_str() const;
+    /// Convert the symbol to a string
+    /// @return the string representation of the symbol
+    std::string to_str() const;
 
-  /// @returns the identifier of the Program that owns this symbol.
-  tint::ProgramID ProgramID() const { return program_id_; }
+    /// @returns the identifier of the Program that owns this symbol.
+    tint::ProgramID ProgramID() const { return program_id_; }
 
- private:
-  uint32_t val_ = static_cast<uint32_t>(-1);
-  tint::ProgramID program_id_;
+  private:
+    uint32_t val_ = static_cast<uint32_t>(-1);
+    tint::ProgramID program_id_;
 #if TINT_SYMBOL_STORE_DEBUG_NAME
-  std::string debug_name_;
+    std::string debug_name_;
 #endif
 };
 
 /// @param sym the Symbol
 /// @returns the ProgramID that owns the given Symbol
 inline ProgramID ProgramIDOf(Symbol sym) {
-  return sym.IsValid() ? sym.ProgramID() : ProgramID();
+    return sym.IsValid() ? sym.ProgramID() : ProgramID();
 }
 
 }  // namespace tint
@@ -108,12 +108,12 @@
 /// keys for std::unordered_map and std::unordered_set.
 template <>
 class hash<tint::Symbol> {
- public:
-  /// @param sym the symbol to return
-  /// @return the Symbol internal value
-  inline std::size_t operator()(const tint::Symbol& sym) const {
-    return static_cast<std::size_t>(sym.value());
-  }
+  public:
+    /// @param sym the symbol to return
+    /// @return the Symbol internal value
+    inline std::size_t operator()(const tint::Symbol& sym) const {
+        return static_cast<std::size_t>(sym.value());
+    }
 };
 
 }  // namespace std
diff --git a/src/tint/symbol_table.cc b/src/tint/symbol_table.cc
index 6b382dc..0a7fa5c 100644
--- a/src/tint/symbol_table.cc
+++ b/src/tint/symbol_table.cc
@@ -18,8 +18,7 @@
 
 namespace tint {
 
-SymbolTable::SymbolTable(tint::ProgramID program_id)
-    : program_id_(program_id) {}
+SymbolTable::SymbolTable(tint::ProgramID program_id) : program_id_(program_id) {}
 
 SymbolTable::SymbolTable(const SymbolTable&) = default;
 
@@ -32,54 +31,54 @@
 SymbolTable& SymbolTable::operator=(SymbolTable&&) = default;
 
 Symbol SymbolTable::Register(const std::string& name) {
-  TINT_ASSERT(Symbol, !name.empty());
+    TINT_ASSERT(Symbol, !name.empty());
 
-  auto it = name_to_symbol_.find(name);
-  if (it != name_to_symbol_.end())
-    return it->second;
+    auto it = name_to_symbol_.find(name);
+    if (it != name_to_symbol_.end())
+        return it->second;
 
 #if TINT_SYMBOL_STORE_DEBUG_NAME
-  Symbol sym(next_symbol_, program_id_, name);
+    Symbol sym(next_symbol_, program_id_, name);
 #else
-  Symbol sym(next_symbol_, program_id_);
+    Symbol sym(next_symbol_, program_id_);
 #endif
-  ++next_symbol_;
+    ++next_symbol_;
 
-  name_to_symbol_[name] = sym;
-  symbol_to_name_[sym] = name;
+    name_to_symbol_[name] = sym;
+    symbol_to_name_[sym] = name;
 
-  return sym;
+    return sym;
 }
 
 Symbol SymbolTable::Get(const std::string& name) const {
-  auto it = name_to_symbol_.find(name);
-  return it != name_to_symbol_.end() ? it->second : Symbol();
+    auto it = name_to_symbol_.find(name);
+    return it != name_to_symbol_.end() ? it->second : Symbol();
 }
 
 std::string SymbolTable::NameFor(const Symbol symbol) const {
-  TINT_ASSERT_PROGRAM_IDS_EQUAL(Symbol, program_id_, symbol);
-  auto it = symbol_to_name_.find(symbol);
-  if (it == symbol_to_name_.end()) {
-    return symbol.to_str();
-  }
+    TINT_ASSERT_PROGRAM_IDS_EQUAL(Symbol, program_id_, symbol);
+    auto it = symbol_to_name_.find(symbol);
+    if (it == symbol_to_name_.end()) {
+        return symbol.to_str();
+    }
 
-  return it->second;
+    return it->second;
 }
 
 Symbol SymbolTable::New(std::string prefix /* = "" */) {
-  if (prefix.empty()) {
-    prefix = "tint_symbol";
-  }
-  auto it = name_to_symbol_.find(prefix);
-  if (it == name_to_symbol_.end()) {
-    return Register(prefix);
-  }
-  std::string name;
-  size_t i = 1;
-  do {
-    name = prefix + "_" + std::to_string(i++);
-  } while (name_to_symbol_.count(name));
-  return Register(name);
+    if (prefix.empty()) {
+        prefix = "tint_symbol";
+    }
+    auto it = name_to_symbol_.find(prefix);
+    if (it == name_to_symbol_.end()) {
+        return Register(prefix);
+    }
+    std::string name;
+    size_t i = 1;
+    do {
+        name = prefix + "_" + std::to_string(i++);
+    } while (name_to_symbol_.count(name));
+    return Register(name);
 }
 
 }  // namespace tint
diff --git a/src/tint/symbol_table.h b/src/tint/symbol_table.h
index 214916e..e07d4df 100644
--- a/src/tint/symbol_table.h
+++ b/src/tint/symbol_table.h
@@ -24,76 +24,76 @@
 
 /// Holds mappings from symbols to their associated string names
 class SymbolTable {
- public:
-  /// Constructor
-  /// @param program_id the identifier of the program that owns this symbol
-  /// table
-  explicit SymbolTable(tint::ProgramID program_id);
-  /// Copy constructor
-  SymbolTable(const SymbolTable&);
-  /// Move Constructor
-  SymbolTable(SymbolTable&&);
-  /// Destructor
-  ~SymbolTable();
+  public:
+    /// Constructor
+    /// @param program_id the identifier of the program that owns this symbol
+    /// table
+    explicit SymbolTable(tint::ProgramID program_id);
+    /// Copy constructor
+    SymbolTable(const SymbolTable&);
+    /// Move Constructor
+    SymbolTable(SymbolTable&&);
+    /// Destructor
+    ~SymbolTable();
 
-  /// Copy assignment
-  /// @param other the symbol table to copy
-  /// @returns the new symbol table
-  SymbolTable& operator=(const SymbolTable& other);
-  /// Move assignment
-  /// @param other the symbol table to move
-  /// @returns the symbol table
-  SymbolTable& operator=(SymbolTable&& other);
+    /// Copy assignment
+    /// @param other the symbol table to copy
+    /// @returns the new symbol table
+    SymbolTable& operator=(const SymbolTable& other);
+    /// Move assignment
+    /// @param other the symbol table to move
+    /// @returns the symbol table
+    SymbolTable& operator=(SymbolTable&& other);
 
-  /// Registers a name into the symbol table, returning the Symbol.
-  /// @param name the name to register
-  /// @returns the symbol representing the given name
-  Symbol Register(const std::string& name);
+    /// Registers a name into the symbol table, returning the Symbol.
+    /// @param name the name to register
+    /// @returns the symbol representing the given name
+    Symbol Register(const std::string& name);
 
-  /// Returns the symbol for the given `name`
-  /// @param name the name to lookup
-  /// @returns the symbol for the name or symbol::kInvalid if not found.
-  Symbol Get(const std::string& name) const;
+    /// Returns the symbol for the given `name`
+    /// @param name the name to lookup
+    /// @returns the symbol for the name or symbol::kInvalid if not found.
+    Symbol Get(const std::string& name) const;
 
-  /// Returns the name for the given symbol
-  /// @param symbol the symbol to retrieve the name for
-  /// @returns the symbol name or "" if not found
-  std::string NameFor(const Symbol symbol) const;
+    /// Returns the name for the given symbol
+    /// @param symbol the symbol to retrieve the name for
+    /// @returns the symbol name or "" if not found
+    std::string NameFor(const Symbol symbol) const;
 
-  /// Returns a new unique symbol with the given name, possibly suffixed with a
-  /// unique number.
-  /// @param name the symbol name
-  /// @returns a new, unnamed symbol with the given name. If the name is already
-  /// taken then this will be suffixed with an underscore and a unique numerical
-  /// value
-  Symbol New(std::string name = "");
+    /// Returns a new unique symbol with the given name, possibly suffixed with a
+    /// unique number.
+    /// @param name the symbol name
+    /// @returns a new, unnamed symbol with the given name. If the name is already
+    /// taken then this will be suffixed with an underscore and a unique numerical
+    /// value
+    Symbol New(std::string name = "");
 
-  /// Foreach calls the callback function `F` for each symbol in the table.
-  /// @param callback must be a function or function-like object with the
-  /// signature: `void(Symbol, const std::string&)`
-  template <typename F>
-  void Foreach(F&& callback) const {
-    for (auto it : symbol_to_name_) {
-      callback(it.first, it.second);
+    /// Foreach calls the callback function `F` for each symbol in the table.
+    /// @param callback must be a function or function-like object with the
+    /// signature: `void(Symbol, const std::string&)`
+    template <typename F>
+    void Foreach(F&& callback) const {
+        for (auto it : symbol_to_name_) {
+            callback(it.first, it.second);
+        }
     }
-  }
 
-  /// @returns the identifier of the Program that owns this symbol table.
-  tint::ProgramID ProgramID() const { return program_id_; }
+    /// @returns the identifier of the Program that owns this symbol table.
+    tint::ProgramID ProgramID() const { return program_id_; }
 
- private:
-  // The value to be associated to the next registered symbol table entry.
-  uint32_t next_symbol_ = 1;
+  private:
+    // The value to be associated to the next registered symbol table entry.
+    uint32_t next_symbol_ = 1;
 
-  std::unordered_map<Symbol, std::string> symbol_to_name_;
-  std::unordered_map<std::string, Symbol> name_to_symbol_;
-  tint::ProgramID program_id_;
+    std::unordered_map<Symbol, std::string> symbol_to_name_;
+    std::unordered_map<std::string, Symbol> name_to_symbol_;
+    tint::ProgramID program_id_;
 };
 
 /// @param symbol_table the SymbolTable
 /// @returns the ProgramID that owns the given SymbolTable
 inline ProgramID ProgramIDOf(const SymbolTable& symbol_table) {
-  return symbol_table.ProgramID();
+    return symbol_table.ProgramID();
 }
 
 }  // namespace tint
diff --git a/src/tint/symbol_table_test.cc b/src/tint/symbol_table_test.cc
index 0905f8b..1cf6d1a 100644
--- a/src/tint/symbol_table_test.cc
+++ b/src/tint/symbol_table_test.cc
@@ -22,41 +22,41 @@
 using SymbolTableTest = testing::Test;
 
 TEST_F(SymbolTableTest, GeneratesSymbolForName) {
-  auto program_id = ProgramID::New();
-  SymbolTable s{program_id};
-  EXPECT_EQ(Symbol(1, program_id), s.Register("name"));
-  EXPECT_EQ(Symbol(2, program_id), s.Register("another_name"));
+    auto program_id = ProgramID::New();
+    SymbolTable s{program_id};
+    EXPECT_EQ(Symbol(1, program_id), s.Register("name"));
+    EXPECT_EQ(Symbol(2, program_id), s.Register("another_name"));
 }
 
 TEST_F(SymbolTableTest, DeduplicatesNames) {
-  auto program_id = ProgramID::New();
-  SymbolTable s{program_id};
-  EXPECT_EQ(Symbol(1, program_id), s.Register("name"));
-  EXPECT_EQ(Symbol(2, program_id), s.Register("another_name"));
-  EXPECT_EQ(Symbol(1, program_id), s.Register("name"));
+    auto program_id = ProgramID::New();
+    SymbolTable s{program_id};
+    EXPECT_EQ(Symbol(1, program_id), s.Register("name"));
+    EXPECT_EQ(Symbol(2, program_id), s.Register("another_name"));
+    EXPECT_EQ(Symbol(1, program_id), s.Register("name"));
 }
 
 TEST_F(SymbolTableTest, ReturnsNameForSymbol) {
-  auto program_id = ProgramID::New();
-  SymbolTable s{program_id};
-  auto sym = s.Register("name");
-  EXPECT_EQ("name", s.NameFor(sym));
+    auto program_id = ProgramID::New();
+    SymbolTable s{program_id};
+    auto sym = s.Register("name");
+    EXPECT_EQ("name", s.NameFor(sym));
 }
 
 TEST_F(SymbolTableTest, ReturnsBlankForMissingSymbol) {
-  auto program_id = ProgramID::New();
-  SymbolTable s{program_id};
-  EXPECT_EQ("$2", s.NameFor(Symbol(2, program_id)));
+    auto program_id = ProgramID::New();
+    SymbolTable s{program_id};
+    EXPECT_EQ("$2", s.NameFor(Symbol(2, program_id)));
 }
 
 TEST_F(SymbolTableTest, AssertsForBlankString) {
-  EXPECT_FATAL_FAILURE(
-      {
-        auto program_id = ProgramID::New();
-        SymbolTable s{program_id};
-        s.Register("");
-      },
-      "internal compiler error");
+    EXPECT_FATAL_FAILURE(
+        {
+            auto program_id = ProgramID::New();
+            SymbolTable s{program_id};
+            s.Register("");
+        },
+        "internal compiler error");
 }
 
 }  // namespace
diff --git a/src/tint/symbol_test.cc b/src/tint/symbol_test.cc
index 8e3f6c0..22135b5 100644
--- a/src/tint/symbol_test.cc
+++ b/src/tint/symbol_test.cc
@@ -22,29 +22,29 @@
 using SymbolTest = testing::Test;
 
 TEST_F(SymbolTest, ToStr) {
-  Symbol sym(1, ProgramID::New());
-  EXPECT_EQ("$1", sym.to_str());
+    Symbol sym(1, ProgramID::New());
+    EXPECT_EQ("$1", sym.to_str());
 }
 
 TEST_F(SymbolTest, CopyAssign) {
-  Symbol sym1(1, ProgramID::New());
-  Symbol sym2;
+    Symbol sym1(1, ProgramID::New());
+    Symbol sym2;
 
-  EXPECT_FALSE(sym2.IsValid());
-  sym2 = sym1;
-  EXPECT_TRUE(sym2.IsValid());
-  EXPECT_EQ(sym2, sym1);
+    EXPECT_FALSE(sym2.IsValid());
+    sym2 = sym1;
+    EXPECT_TRUE(sym2.IsValid());
+    EXPECT_EQ(sym2, sym1);
 }
 
 TEST_F(SymbolTest, Comparison) {
-  auto program_id = ProgramID::New();
-  Symbol sym1(1, program_id);
-  Symbol sym2(2, program_id);
-  Symbol sym3(1, program_id);
+    auto program_id = ProgramID::New();
+    Symbol sym1(1, program_id);
+    Symbol sym2(2, program_id);
+    Symbol sym3(1, program_id);
 
-  EXPECT_TRUE(sym1 == sym3);
-  EXPECT_FALSE(sym1 == sym2);
-  EXPECT_FALSE(sym3 == sym2);
+    EXPECT_TRUE(sym1 == sym3);
+    EXPECT_FALSE(sym1 == sym2);
+    EXPECT_FALSE(sym3 == sym2);
 }
 
 }  // namespace
diff --git a/src/tint/test_main.cc b/src/tint/test_main.cc
index d44f9c8..ca68271 100644
--- a/src/tint/test_main.cc
+++ b/src/tint/test_main.cc
@@ -26,58 +26,58 @@
 namespace {
 
 void TintInternalCompilerErrorReporter(const tint::diag::List& diagnostics) {
-  FAIL() << diagnostics.str();
+    FAIL() << diagnostics.str();
 }
 
 struct Flags {
-  bool spirv_reader_dump_converted = false;
+    bool spirv_reader_dump_converted = false;
 
-  bool parse(int argc, char** argv) {
-    bool errored = false;
-    for (int i = 1; i < argc && !errored; i++) {
-      auto match = [&](std::string name) { return name == argv[i]; };
+    bool parse(int argc, char** argv) {
+        bool errored = false;
+        for (int i = 1; i < argc && !errored; i++) {
+            auto match = [&](std::string name) { return name == argv[i]; };
 
-      if (match("--dump-spirv")) {
-        spirv_reader_dump_converted = true;
-      } else {
-        std::cout << "Unknown flag '" << argv[i] << "'" << std::endl;
-        return false;
-      }
+            if (match("--dump-spirv")) {
+                spirv_reader_dump_converted = true;
+            } else {
+                std::cout << "Unknown flag '" << argv[i] << "'" << std::endl;
+                return false;
+            }
+        }
+        return true;
     }
-    return true;
-  }
 };
 
 }  // namespace
 
 // Entry point for tint unit tests
 int main(int argc, char** argv) {
-  testing::InitGoogleMock(&argc, argv);
+    testing::InitGoogleMock(&argc, argv);
 
 #if TINT_BUILD_WGSL_WRITER
-  tint::Program::printer = [](const tint::Program* program) {
-    auto result = tint::writer::wgsl::Generate(program, {});
-    if (!result.error.empty()) {
-      return "error: " + result.error;
-    }
-    return result.wgsl;
-  };
+    tint::Program::printer = [](const tint::Program* program) {
+        auto result = tint::writer::wgsl::Generate(program, {});
+        if (!result.error.empty()) {
+            return "error: " + result.error;
+        }
+        return result.wgsl;
+    };
 #endif  // TINT_BUILD_WGSL_WRITER
 
-  Flags flags;
-  if (!flags.parse(argc, argv)) {
-    return -1;
-  }
+    Flags flags;
+    if (!flags.parse(argc, argv)) {
+        return -1;
+    }
 
 #if TINT_BUILD_SPV_READER
-  if (flags.spirv_reader_dump_converted) {
-    tint::reader::spirv::test::DumpSuccessfullyConvertedSpirv();
-  }
+    if (flags.spirv_reader_dump_converted) {
+        tint::reader::spirv::test::DumpSuccessfullyConvertedSpirv();
+    }
 #endif  // TINT_BUILD_SPV_READER
 
-  tint::SetInternalCompilerErrorReporter(&TintInternalCompilerErrorReporter);
+    tint::SetInternalCompilerErrorReporter(&TintInternalCompilerErrorReporter);
 
-  auto res = RUN_ALL_TESTS();
+    auto res = RUN_ALL_TESTS();
 
-  return res;
+    return res;
 }
diff --git a/src/tint/text/unicode.cc b/src/tint/text/unicode.cc
index b48f295..bf28c4e 100644
--- a/src/tint/text/unicode.cc
+++ b/src/tint/text/unicode.cc
@@ -20,493 +20,404 @@
 namespace {
 
 struct CodePointRange {
-  uint32_t first;  // First code point in the interval
-  uint32_t last;   // Last code point in the interval (inclusive)
+    uint32_t first;  // First code point in the interval
+    uint32_t last;   // Last code point in the interval (inclusive)
 };
 
 inline bool operator<(CodePoint code_point, CodePointRange range) {
-  return code_point < range.first;
+    return code_point < range.first;
 }
 inline bool operator<(CodePointRange range, CodePoint code_point) {
-  return range.last < code_point;
+    return range.last < code_point;
 }
 
 // Interval ranges of all code points in the Unicode 14 XID_Start set
 // This array needs to be in ascending order.
 constexpr CodePointRange kXIDStartRanges[] = {
-    {0x00041, 0x0005a}, {0x00061, 0x0007a}, {0x000aa, 0x000aa},
-    {0x000b5, 0x000b5}, {0x000ba, 0x000ba}, {0x000c0, 0x000d6},
-    {0x000d8, 0x000f6}, {0x000f8, 0x002c1}, {0x002c6, 0x002d1},
-    {0x002e0, 0x002e4}, {0x002ec, 0x002ec}, {0x002ee, 0x002ee},
-    {0x00370, 0x00374}, {0x00376, 0x00377}, {0x0037b, 0x0037d},
-    {0x0037f, 0x0037f}, {0x00386, 0x00386}, {0x00388, 0x0038a},
-    {0x0038c, 0x0038c}, {0x0038e, 0x003a1}, {0x003a3, 0x003f5},
-    {0x003f7, 0x00481}, {0x0048a, 0x0052f}, {0x00531, 0x00556},
-    {0x00559, 0x00559}, {0x00560, 0x00588}, {0x005d0, 0x005ea},
-    {0x005ef, 0x005f2}, {0x00620, 0x0064a}, {0x0066e, 0x0066f},
-    {0x00671, 0x006d3}, {0x006d5, 0x006d5}, {0x006e5, 0x006e6},
-    {0x006ee, 0x006ef}, {0x006fa, 0x006fc}, {0x006ff, 0x006ff},
-    {0x00710, 0x00710}, {0x00712, 0x0072f}, {0x0074d, 0x007a5},
-    {0x007b1, 0x007b1}, {0x007ca, 0x007ea}, {0x007f4, 0x007f5},
-    {0x007fa, 0x007fa}, {0x00800, 0x00815}, {0x0081a, 0x0081a},
-    {0x00824, 0x00824}, {0x00828, 0x00828}, {0x00840, 0x00858},
-    {0x00860, 0x0086a}, {0x00870, 0x00887}, {0x00889, 0x0088e},
-    {0x008a0, 0x008c9}, {0x00904, 0x00939}, {0x0093d, 0x0093d},
-    {0x00950, 0x00950}, {0x00958, 0x00961}, {0x00971, 0x00980},
-    {0x00985, 0x0098c}, {0x0098f, 0x00990}, {0x00993, 0x009a8},
-    {0x009aa, 0x009b0}, {0x009b2, 0x009b2}, {0x009b6, 0x009b9},
-    {0x009bd, 0x009bd}, {0x009ce, 0x009ce}, {0x009dc, 0x009dd},
-    {0x009df, 0x009e1}, {0x009f0, 0x009f1}, {0x009fc, 0x009fc},
-    {0x00a05, 0x00a0a}, {0x00a0f, 0x00a10}, {0x00a13, 0x00a28},
-    {0x00a2a, 0x00a30}, {0x00a32, 0x00a33}, {0x00a35, 0x00a36},
-    {0x00a38, 0x00a39}, {0x00a59, 0x00a5c}, {0x00a5e, 0x00a5e},
-    {0x00a72, 0x00a74}, {0x00a85, 0x00a8d}, {0x00a8f, 0x00a91},
-    {0x00a93, 0x00aa8}, {0x00aaa, 0x00ab0}, {0x00ab2, 0x00ab3},
-    {0x00ab5, 0x00ab9}, {0x00abd, 0x00abd}, {0x00ad0, 0x00ad0},
-    {0x00ae0, 0x00ae1}, {0x00af9, 0x00af9}, {0x00b05, 0x00b0c},
-    {0x00b0f, 0x00b10}, {0x00b13, 0x00b28}, {0x00b2a, 0x00b30},
-    {0x00b32, 0x00b33}, {0x00b35, 0x00b39}, {0x00b3d, 0x00b3d},
-    {0x00b5c, 0x00b5d}, {0x00b5f, 0x00b61}, {0x00b71, 0x00b71},
-    {0x00b83, 0x00b83}, {0x00b85, 0x00b8a}, {0x00b8e, 0x00b90},
-    {0x00b92, 0x00b95}, {0x00b99, 0x00b9a}, {0x00b9c, 0x00b9c},
-    {0x00b9e, 0x00b9f}, {0x00ba3, 0x00ba4}, {0x00ba8, 0x00baa},
-    {0x00bae, 0x00bb9}, {0x00bd0, 0x00bd0}, {0x00c05, 0x00c0c},
-    {0x00c0e, 0x00c10}, {0x00c12, 0x00c28}, {0x00c2a, 0x00c39},
-    {0x00c3d, 0x00c3d}, {0x00c58, 0x00c5a}, {0x00c5d, 0x00c5d},
-    {0x00c60, 0x00c61}, {0x00c80, 0x00c80}, {0x00c85, 0x00c8c},
-    {0x00c8e, 0x00c90}, {0x00c92, 0x00ca8}, {0x00caa, 0x00cb3},
-    {0x00cb5, 0x00cb9}, {0x00cbd, 0x00cbd}, {0x00cdd, 0x00cde},
-    {0x00ce0, 0x00ce1}, {0x00cf1, 0x00cf2}, {0x00d04, 0x00d0c},
-    {0x00d0e, 0x00d10}, {0x00d12, 0x00d3a}, {0x00d3d, 0x00d3d},
-    {0x00d4e, 0x00d4e}, {0x00d54, 0x00d56}, {0x00d5f, 0x00d61},
-    {0x00d7a, 0x00d7f}, {0x00d85, 0x00d96}, {0x00d9a, 0x00db1},
-    {0x00db3, 0x00dbb}, {0x00dbd, 0x00dbd}, {0x00dc0, 0x00dc6},
-    {0x00e01, 0x00e30}, {0x00e32, 0x00e32}, {0x00e40, 0x00e46},
-    {0x00e81, 0x00e82}, {0x00e84, 0x00e84}, {0x00e86, 0x00e8a},
-    {0x00e8c, 0x00ea3}, {0x00ea5, 0x00ea5}, {0x00ea7, 0x00eb0},
-    {0x00eb2, 0x00eb2}, {0x00ebd, 0x00ebd}, {0x00ec0, 0x00ec4},
-    {0x00ec6, 0x00ec6}, {0x00edc, 0x00edf}, {0x00f00, 0x00f00},
-    {0x00f40, 0x00f47}, {0x00f49, 0x00f6c}, {0x00f88, 0x00f8c},
-    {0x01000, 0x0102a}, {0x0103f, 0x0103f}, {0x01050, 0x01055},
-    {0x0105a, 0x0105d}, {0x01061, 0x01061}, {0x01065, 0x01066},
-    {0x0106e, 0x01070}, {0x01075, 0x01081}, {0x0108e, 0x0108e},
-    {0x010a0, 0x010c5}, {0x010c7, 0x010c7}, {0x010cd, 0x010cd},
-    {0x010d0, 0x010fa}, {0x010fc, 0x01248}, {0x0124a, 0x0124d},
-    {0x01250, 0x01256}, {0x01258, 0x01258}, {0x0125a, 0x0125d},
-    {0x01260, 0x01288}, {0x0128a, 0x0128d}, {0x01290, 0x012b0},
-    {0x012b2, 0x012b5}, {0x012b8, 0x012be}, {0x012c0, 0x012c0},
-    {0x012c2, 0x012c5}, {0x012c8, 0x012d6}, {0x012d8, 0x01310},
-    {0x01312, 0x01315}, {0x01318, 0x0135a}, {0x01380, 0x0138f},
-    {0x013a0, 0x013f5}, {0x013f8, 0x013fd}, {0x01401, 0x0166c},
-    {0x0166f, 0x0167f}, {0x01681, 0x0169a}, {0x016a0, 0x016ea},
-    {0x016ee, 0x016f8}, {0x01700, 0x01711}, {0x0171f, 0x01731},
-    {0x01740, 0x01751}, {0x01760, 0x0176c}, {0x0176e, 0x01770},
-    {0x01780, 0x017b3}, {0x017d7, 0x017d7}, {0x017dc, 0x017dc},
-    {0x01820, 0x01878}, {0x01880, 0x018a8}, {0x018aa, 0x018aa},
-    {0x018b0, 0x018f5}, {0x01900, 0x0191e}, {0x01950, 0x0196d},
-    {0x01970, 0x01974}, {0x01980, 0x019ab}, {0x019b0, 0x019c9},
-    {0x01a00, 0x01a16}, {0x01a20, 0x01a54}, {0x01aa7, 0x01aa7},
-    {0x01b05, 0x01b33}, {0x01b45, 0x01b4c}, {0x01b83, 0x01ba0},
-    {0x01bae, 0x01baf}, {0x01bba, 0x01be5}, {0x01c00, 0x01c23},
-    {0x01c4d, 0x01c4f}, {0x01c5a, 0x01c7d}, {0x01c80, 0x01c88},
-    {0x01c90, 0x01cba}, {0x01cbd, 0x01cbf}, {0x01ce9, 0x01cec},
-    {0x01cee, 0x01cf3}, {0x01cf5, 0x01cf6}, {0x01cfa, 0x01cfa},
-    {0x01d00, 0x01dbf}, {0x01e00, 0x01f15}, {0x01f18, 0x01f1d},
-    {0x01f20, 0x01f45}, {0x01f48, 0x01f4d}, {0x01f50, 0x01f57},
-    {0x01f59, 0x01f59}, {0x01f5b, 0x01f5b}, {0x01f5d, 0x01f5d},
-    {0x01f5f, 0x01f7d}, {0x01f80, 0x01fb4}, {0x01fb6, 0x01fbc},
-    {0x01fbe, 0x01fbe}, {0x01fc2, 0x01fc4}, {0x01fc6, 0x01fcc},
-    {0x01fd0, 0x01fd3}, {0x01fd6, 0x01fdb}, {0x01fe0, 0x01fec},
-    {0x01ff2, 0x01ff4}, {0x01ff6, 0x01ffc}, {0x02071, 0x02071},
-    {0x0207f, 0x0207f}, {0x02090, 0x0209c}, {0x02102, 0x02102},
-    {0x02107, 0x02107}, {0x0210a, 0x02113}, {0x02115, 0x02115},
-    {0x02118, 0x0211d}, {0x02124, 0x02124}, {0x02126, 0x02126},
-    {0x02128, 0x02128}, {0x0212a, 0x02139}, {0x0213c, 0x0213f},
-    {0x02145, 0x02149}, {0x0214e, 0x0214e}, {0x02160, 0x02188},
-    {0x02c00, 0x02ce4}, {0x02ceb, 0x02cee}, {0x02cf2, 0x02cf3},
-    {0x02d00, 0x02d25}, {0x02d27, 0x02d27}, {0x02d2d, 0x02d2d},
-    {0x02d30, 0x02d67}, {0x02d6f, 0x02d6f}, {0x02d80, 0x02d96},
-    {0x02da0, 0x02da6}, {0x02da8, 0x02dae}, {0x02db0, 0x02db6},
-    {0x02db8, 0x02dbe}, {0x02dc0, 0x02dc6}, {0x02dc8, 0x02dce},
-    {0x02dd0, 0x02dd6}, {0x02dd8, 0x02dde}, {0x03005, 0x03007},
-    {0x03021, 0x03029}, {0x03031, 0x03035}, {0x03038, 0x0303c},
-    {0x03041, 0x03096}, {0x0309d, 0x0309f}, {0x030a1, 0x030fa},
-    {0x030fc, 0x030ff}, {0x03105, 0x0312f}, {0x03131, 0x0318e},
-    {0x031a0, 0x031bf}, {0x031f0, 0x031ff}, {0x03400, 0x04dbf},
-    {0x04e00, 0x0a48c}, {0x0a4d0, 0x0a4fd}, {0x0a500, 0x0a60c},
-    {0x0a610, 0x0a61f}, {0x0a62a, 0x0a62b}, {0x0a640, 0x0a66e},
-    {0x0a67f, 0x0a69d}, {0x0a6a0, 0x0a6ef}, {0x0a717, 0x0a71f},
-    {0x0a722, 0x0a788}, {0x0a78b, 0x0a7ca}, {0x0a7d0, 0x0a7d1},
-    {0x0a7d3, 0x0a7d3}, {0x0a7d5, 0x0a7d9}, {0x0a7f2, 0x0a801},
-    {0x0a803, 0x0a805}, {0x0a807, 0x0a80a}, {0x0a80c, 0x0a822},
-    {0x0a840, 0x0a873}, {0x0a882, 0x0a8b3}, {0x0a8f2, 0x0a8f7},
-    {0x0a8fb, 0x0a8fb}, {0x0a8fd, 0x0a8fe}, {0x0a90a, 0x0a925},
-    {0x0a930, 0x0a946}, {0x0a960, 0x0a97c}, {0x0a984, 0x0a9b2},
-    {0x0a9cf, 0x0a9cf}, {0x0a9e0, 0x0a9e4}, {0x0a9e6, 0x0a9ef},
-    {0x0a9fa, 0x0a9fe}, {0x0aa00, 0x0aa28}, {0x0aa40, 0x0aa42},
-    {0x0aa44, 0x0aa4b}, {0x0aa60, 0x0aa76}, {0x0aa7a, 0x0aa7a},
-    {0x0aa7e, 0x0aaaf}, {0x0aab1, 0x0aab1}, {0x0aab5, 0x0aab6},
-    {0x0aab9, 0x0aabd}, {0x0aac0, 0x0aac0}, {0x0aac2, 0x0aac2},
-    {0x0aadb, 0x0aadd}, {0x0aae0, 0x0aaea}, {0x0aaf2, 0x0aaf4},
-    {0x0ab01, 0x0ab06}, {0x0ab09, 0x0ab0e}, {0x0ab11, 0x0ab16},
-    {0x0ab20, 0x0ab26}, {0x0ab28, 0x0ab2e}, {0x0ab30, 0x0ab5a},
-    {0x0ab5c, 0x0ab69}, {0x0ab70, 0x0abe2}, {0x0ac00, 0x0d7a3},
-    {0x0d7b0, 0x0d7c6}, {0x0d7cb, 0x0d7fb}, {0x0f900, 0x0fa6d},
-    {0x0fa70, 0x0fad9}, {0x0fb00, 0x0fb06}, {0x0fb13, 0x0fb17},
-    {0x0fb1d, 0x0fb1d}, {0x0fb1f, 0x0fb28}, {0x0fb2a, 0x0fb36},
-    {0x0fb38, 0x0fb3c}, {0x0fb3e, 0x0fb3e}, {0x0fb40, 0x0fb41},
-    {0x0fb43, 0x0fb44}, {0x0fb46, 0x0fbb1}, {0x0fbd3, 0x0fc5d},
-    {0x0fc64, 0x0fd3d}, {0x0fd50, 0x0fd8f}, {0x0fd92, 0x0fdc7},
-    {0x0fdf0, 0x0fdf9}, {0x0fe71, 0x0fe71}, {0x0fe73, 0x0fe73},
-    {0x0fe77, 0x0fe77}, {0x0fe79, 0x0fe79}, {0x0fe7b, 0x0fe7b},
-    {0x0fe7d, 0x0fe7d}, {0x0fe7f, 0x0fefc}, {0x0ff21, 0x0ff3a},
-    {0x0ff41, 0x0ff5a}, {0x0ff66, 0x0ff9d}, {0x0ffa0, 0x0ffbe},
-    {0x0ffc2, 0x0ffc7}, {0x0ffca, 0x0ffcf}, {0x0ffd2, 0x0ffd7},
-    {0x0ffda, 0x0ffdc}, {0x10000, 0x1000b}, {0x1000d, 0x10026},
-    {0x10028, 0x1003a}, {0x1003c, 0x1003d}, {0x1003f, 0x1004d},
-    {0x10050, 0x1005d}, {0x10080, 0x100fa}, {0x10140, 0x10174},
-    {0x10280, 0x1029c}, {0x102a0, 0x102d0}, {0x10300, 0x1031f},
-    {0x1032d, 0x1034a}, {0x10350, 0x10375}, {0x10380, 0x1039d},
-    {0x103a0, 0x103c3}, {0x103c8, 0x103cf}, {0x103d1, 0x103d5},
-    {0x10400, 0x1049d}, {0x104b0, 0x104d3}, {0x104d8, 0x104fb},
-    {0x10500, 0x10527}, {0x10530, 0x10563}, {0x10570, 0x1057a},
-    {0x1057c, 0x1058a}, {0x1058c, 0x10592}, {0x10594, 0x10595},
-    {0x10597, 0x105a1}, {0x105a3, 0x105b1}, {0x105b3, 0x105b9},
-    {0x105bb, 0x105bc}, {0x10600, 0x10736}, {0x10740, 0x10755},
-    {0x10760, 0x10767}, {0x10780, 0x10785}, {0x10787, 0x107b0},
-    {0x107b2, 0x107ba}, {0x10800, 0x10805}, {0x10808, 0x10808},
-    {0x1080a, 0x10835}, {0x10837, 0x10838}, {0x1083c, 0x1083c},
-    {0x1083f, 0x10855}, {0x10860, 0x10876}, {0x10880, 0x1089e},
-    {0x108e0, 0x108f2}, {0x108f4, 0x108f5}, {0x10900, 0x10915},
-    {0x10920, 0x10939}, {0x10980, 0x109b7}, {0x109be, 0x109bf},
-    {0x10a00, 0x10a00}, {0x10a10, 0x10a13}, {0x10a15, 0x10a17},
-    {0x10a19, 0x10a35}, {0x10a60, 0x10a7c}, {0x10a80, 0x10a9c},
-    {0x10ac0, 0x10ac7}, {0x10ac9, 0x10ae4}, {0x10b00, 0x10b35},
-    {0x10b40, 0x10b55}, {0x10b60, 0x10b72}, {0x10b80, 0x10b91},
-    {0x10c00, 0x10c48}, {0x10c80, 0x10cb2}, {0x10cc0, 0x10cf2},
-    {0x10d00, 0x10d23}, {0x10e80, 0x10ea9}, {0x10eb0, 0x10eb1},
-    {0x10f00, 0x10f1c}, {0x10f27, 0x10f27}, {0x10f30, 0x10f45},
-    {0x10f70, 0x10f81}, {0x10fb0, 0x10fc4}, {0x10fe0, 0x10ff6},
-    {0x11003, 0x11037}, {0x11071, 0x11072}, {0x11075, 0x11075},
-    {0x11083, 0x110af}, {0x110d0, 0x110e8}, {0x11103, 0x11126},
-    {0x11144, 0x11144}, {0x11147, 0x11147}, {0x11150, 0x11172},
-    {0x11176, 0x11176}, {0x11183, 0x111b2}, {0x111c1, 0x111c4},
-    {0x111da, 0x111da}, {0x111dc, 0x111dc}, {0x11200, 0x11211},
-    {0x11213, 0x1122b}, {0x11280, 0x11286}, {0x11288, 0x11288},
-    {0x1128a, 0x1128d}, {0x1128f, 0x1129d}, {0x1129f, 0x112a8},
-    {0x112b0, 0x112de}, {0x11305, 0x1130c}, {0x1130f, 0x11310},
-    {0x11313, 0x11328}, {0x1132a, 0x11330}, {0x11332, 0x11333},
-    {0x11335, 0x11339}, {0x1133d, 0x1133d}, {0x11350, 0x11350},
-    {0x1135d, 0x11361}, {0x11400, 0x11434}, {0x11447, 0x1144a},
-    {0x1145f, 0x11461}, {0x11480, 0x114af}, {0x114c4, 0x114c5},
-    {0x114c7, 0x114c7}, {0x11580, 0x115ae}, {0x115d8, 0x115db},
-    {0x11600, 0x1162f}, {0x11644, 0x11644}, {0x11680, 0x116aa},
-    {0x116b8, 0x116b8}, {0x11700, 0x1171a}, {0x11740, 0x11746},
-    {0x11800, 0x1182b}, {0x118a0, 0x118df}, {0x118ff, 0x11906},
-    {0x11909, 0x11909}, {0x1190c, 0x11913}, {0x11915, 0x11916},
-    {0x11918, 0x1192f}, {0x1193f, 0x1193f}, {0x11941, 0x11941},
-    {0x119a0, 0x119a7}, {0x119aa, 0x119d0}, {0x119e1, 0x119e1},
-    {0x119e3, 0x119e3}, {0x11a00, 0x11a00}, {0x11a0b, 0x11a32},
-    {0x11a3a, 0x11a3a}, {0x11a50, 0x11a50}, {0x11a5c, 0x11a89},
-    {0x11a9d, 0x11a9d}, {0x11ab0, 0x11af8}, {0x11c00, 0x11c08},
-    {0x11c0a, 0x11c2e}, {0x11c40, 0x11c40}, {0x11c72, 0x11c8f},
-    {0x11d00, 0x11d06}, {0x11d08, 0x11d09}, {0x11d0b, 0x11d30},
-    {0x11d46, 0x11d46}, {0x11d60, 0x11d65}, {0x11d67, 0x11d68},
-    {0x11d6a, 0x11d89}, {0x11d98, 0x11d98}, {0x11ee0, 0x11ef2},
-    {0x11fb0, 0x11fb0}, {0x12000, 0x12399}, {0x12400, 0x1246e},
-    {0x12480, 0x12543}, {0x12f90, 0x12ff0}, {0x13000, 0x1342e},
-    {0x14400, 0x14646}, {0x16800, 0x16a38}, {0x16a40, 0x16a5e},
-    {0x16a70, 0x16abe}, {0x16ad0, 0x16aed}, {0x16b00, 0x16b2f},
-    {0x16b40, 0x16b43}, {0x16b63, 0x16b77}, {0x16b7d, 0x16b8f},
-    {0x16e40, 0x16e7f}, {0x16f00, 0x16f4a}, {0x16f50, 0x16f50},
-    {0x16f93, 0x16f9f}, {0x16fe0, 0x16fe1}, {0x16fe3, 0x16fe3},
-    {0x17000, 0x187f7}, {0x18800, 0x18cd5}, {0x18d00, 0x18d08},
-    {0x1aff0, 0x1aff3}, {0x1aff5, 0x1affb}, {0x1affd, 0x1affe},
-    {0x1b000, 0x1b122}, {0x1b150, 0x1b152}, {0x1b164, 0x1b167},
-    {0x1b170, 0x1b2fb}, {0x1bc00, 0x1bc6a}, {0x1bc70, 0x1bc7c},
-    {0x1bc80, 0x1bc88}, {0x1bc90, 0x1bc99}, {0x1d400, 0x1d454},
-    {0x1d456, 0x1d49c}, {0x1d49e, 0x1d49f}, {0x1d4a2, 0x1d4a2},
-    {0x1d4a5, 0x1d4a6}, {0x1d4a9, 0x1d4ac}, {0x1d4ae, 0x1d4b9},
-    {0x1d4bb, 0x1d4bb}, {0x1d4bd, 0x1d4c3}, {0x1d4c5, 0x1d505},
-    {0x1d507, 0x1d50a}, {0x1d50d, 0x1d514}, {0x1d516, 0x1d51c},
-    {0x1d51e, 0x1d539}, {0x1d53b, 0x1d53e}, {0x1d540, 0x1d544},
-    {0x1d546, 0x1d546}, {0x1d54a, 0x1d550}, {0x1d552, 0x1d6a5},
-    {0x1d6a8, 0x1d6c0}, {0x1d6c2, 0x1d6da}, {0x1d6dc, 0x1d6fa},
-    {0x1d6fc, 0x1d714}, {0x1d716, 0x1d734}, {0x1d736, 0x1d74e},
-    {0x1d750, 0x1d76e}, {0x1d770, 0x1d788}, {0x1d78a, 0x1d7a8},
-    {0x1d7aa, 0x1d7c2}, {0x1d7c4, 0x1d7cb}, {0x1df00, 0x1df1e},
-    {0x1e100, 0x1e12c}, {0x1e137, 0x1e13d}, {0x1e14e, 0x1e14e},
-    {0x1e290, 0x1e2ad}, {0x1e2c0, 0x1e2eb}, {0x1e7e0, 0x1e7e6},
-    {0x1e7e8, 0x1e7eb}, {0x1e7ed, 0x1e7ee}, {0x1e7f0, 0x1e7fe},
-    {0x1e800, 0x1e8c4}, {0x1e900, 0x1e943}, {0x1e94b, 0x1e94b},
-    {0x1ee00, 0x1ee03}, {0x1ee05, 0x1ee1f}, {0x1ee21, 0x1ee22},
-    {0x1ee24, 0x1ee24}, {0x1ee27, 0x1ee27}, {0x1ee29, 0x1ee32},
-    {0x1ee34, 0x1ee37}, {0x1ee39, 0x1ee39}, {0x1ee3b, 0x1ee3b},
-    {0x1ee42, 0x1ee42}, {0x1ee47, 0x1ee47}, {0x1ee49, 0x1ee49},
-    {0x1ee4b, 0x1ee4b}, {0x1ee4d, 0x1ee4f}, {0x1ee51, 0x1ee52},
-    {0x1ee54, 0x1ee54}, {0x1ee57, 0x1ee57}, {0x1ee59, 0x1ee59},
-    {0x1ee5b, 0x1ee5b}, {0x1ee5d, 0x1ee5d}, {0x1ee5f, 0x1ee5f},
-    {0x1ee61, 0x1ee62}, {0x1ee64, 0x1ee64}, {0x1ee67, 0x1ee6a},
-    {0x1ee6c, 0x1ee72}, {0x1ee74, 0x1ee77}, {0x1ee79, 0x1ee7c},
-    {0x1ee7e, 0x1ee7e}, {0x1ee80, 0x1ee89}, {0x1ee8b, 0x1ee9b},
-    {0x1eea1, 0x1eea3}, {0x1eea5, 0x1eea9}, {0x1eeab, 0x1eebb},
-    {0x20000, 0x2a6df}, {0x2a700, 0x2b738}, {0x2b740, 0x2b81d},
-    {0x2b820, 0x2cea1}, {0x2ceb0, 0x2ebe0}, {0x2f800, 0x2fa1d},
-    {0x30000, 0x3134a},
+    {0x00041, 0x0005a}, {0x00061, 0x0007a}, {0x000aa, 0x000aa}, {0x000b5, 0x000b5},
+    {0x000ba, 0x000ba}, {0x000c0, 0x000d6}, {0x000d8, 0x000f6}, {0x000f8, 0x002c1},
+    {0x002c6, 0x002d1}, {0x002e0, 0x002e4}, {0x002ec, 0x002ec}, {0x002ee, 0x002ee},
+    {0x00370, 0x00374}, {0x00376, 0x00377}, {0x0037b, 0x0037d}, {0x0037f, 0x0037f},
+    {0x00386, 0x00386}, {0x00388, 0x0038a}, {0x0038c, 0x0038c}, {0x0038e, 0x003a1},
+    {0x003a3, 0x003f5}, {0x003f7, 0x00481}, {0x0048a, 0x0052f}, {0x00531, 0x00556},
+    {0x00559, 0x00559}, {0x00560, 0x00588}, {0x005d0, 0x005ea}, {0x005ef, 0x005f2},
+    {0x00620, 0x0064a}, {0x0066e, 0x0066f}, {0x00671, 0x006d3}, {0x006d5, 0x006d5},
+    {0x006e5, 0x006e6}, {0x006ee, 0x006ef}, {0x006fa, 0x006fc}, {0x006ff, 0x006ff},
+    {0x00710, 0x00710}, {0x00712, 0x0072f}, {0x0074d, 0x007a5}, {0x007b1, 0x007b1},
+    {0x007ca, 0x007ea}, {0x007f4, 0x007f5}, {0x007fa, 0x007fa}, {0x00800, 0x00815},
+    {0x0081a, 0x0081a}, {0x00824, 0x00824}, {0x00828, 0x00828}, {0x00840, 0x00858},
+    {0x00860, 0x0086a}, {0x00870, 0x00887}, {0x00889, 0x0088e}, {0x008a0, 0x008c9},
+    {0x00904, 0x00939}, {0x0093d, 0x0093d}, {0x00950, 0x00950}, {0x00958, 0x00961},
+    {0x00971, 0x00980}, {0x00985, 0x0098c}, {0x0098f, 0x00990}, {0x00993, 0x009a8},
+    {0x009aa, 0x009b0}, {0x009b2, 0x009b2}, {0x009b6, 0x009b9}, {0x009bd, 0x009bd},
+    {0x009ce, 0x009ce}, {0x009dc, 0x009dd}, {0x009df, 0x009e1}, {0x009f0, 0x009f1},
+    {0x009fc, 0x009fc}, {0x00a05, 0x00a0a}, {0x00a0f, 0x00a10}, {0x00a13, 0x00a28},
+    {0x00a2a, 0x00a30}, {0x00a32, 0x00a33}, {0x00a35, 0x00a36}, {0x00a38, 0x00a39},
+    {0x00a59, 0x00a5c}, {0x00a5e, 0x00a5e}, {0x00a72, 0x00a74}, {0x00a85, 0x00a8d},
+    {0x00a8f, 0x00a91}, {0x00a93, 0x00aa8}, {0x00aaa, 0x00ab0}, {0x00ab2, 0x00ab3},
+    {0x00ab5, 0x00ab9}, {0x00abd, 0x00abd}, {0x00ad0, 0x00ad0}, {0x00ae0, 0x00ae1},
+    {0x00af9, 0x00af9}, {0x00b05, 0x00b0c}, {0x00b0f, 0x00b10}, {0x00b13, 0x00b28},
+    {0x00b2a, 0x00b30}, {0x00b32, 0x00b33}, {0x00b35, 0x00b39}, {0x00b3d, 0x00b3d},
+    {0x00b5c, 0x00b5d}, {0x00b5f, 0x00b61}, {0x00b71, 0x00b71}, {0x00b83, 0x00b83},
+    {0x00b85, 0x00b8a}, {0x00b8e, 0x00b90}, {0x00b92, 0x00b95}, {0x00b99, 0x00b9a},
+    {0x00b9c, 0x00b9c}, {0x00b9e, 0x00b9f}, {0x00ba3, 0x00ba4}, {0x00ba8, 0x00baa},
+    {0x00bae, 0x00bb9}, {0x00bd0, 0x00bd0}, {0x00c05, 0x00c0c}, {0x00c0e, 0x00c10},
+    {0x00c12, 0x00c28}, {0x00c2a, 0x00c39}, {0x00c3d, 0x00c3d}, {0x00c58, 0x00c5a},
+    {0x00c5d, 0x00c5d}, {0x00c60, 0x00c61}, {0x00c80, 0x00c80}, {0x00c85, 0x00c8c},
+    {0x00c8e, 0x00c90}, {0x00c92, 0x00ca8}, {0x00caa, 0x00cb3}, {0x00cb5, 0x00cb9},
+    {0x00cbd, 0x00cbd}, {0x00cdd, 0x00cde}, {0x00ce0, 0x00ce1}, {0x00cf1, 0x00cf2},
+    {0x00d04, 0x00d0c}, {0x00d0e, 0x00d10}, {0x00d12, 0x00d3a}, {0x00d3d, 0x00d3d},
+    {0x00d4e, 0x00d4e}, {0x00d54, 0x00d56}, {0x00d5f, 0x00d61}, {0x00d7a, 0x00d7f},
+    {0x00d85, 0x00d96}, {0x00d9a, 0x00db1}, {0x00db3, 0x00dbb}, {0x00dbd, 0x00dbd},
+    {0x00dc0, 0x00dc6}, {0x00e01, 0x00e30}, {0x00e32, 0x00e32}, {0x00e40, 0x00e46},
+    {0x00e81, 0x00e82}, {0x00e84, 0x00e84}, {0x00e86, 0x00e8a}, {0x00e8c, 0x00ea3},
+    {0x00ea5, 0x00ea5}, {0x00ea7, 0x00eb0}, {0x00eb2, 0x00eb2}, {0x00ebd, 0x00ebd},
+    {0x00ec0, 0x00ec4}, {0x00ec6, 0x00ec6}, {0x00edc, 0x00edf}, {0x00f00, 0x00f00},
+    {0x00f40, 0x00f47}, {0x00f49, 0x00f6c}, {0x00f88, 0x00f8c}, {0x01000, 0x0102a},
+    {0x0103f, 0x0103f}, {0x01050, 0x01055}, {0x0105a, 0x0105d}, {0x01061, 0x01061},
+    {0x01065, 0x01066}, {0x0106e, 0x01070}, {0x01075, 0x01081}, {0x0108e, 0x0108e},
+    {0x010a0, 0x010c5}, {0x010c7, 0x010c7}, {0x010cd, 0x010cd}, {0x010d0, 0x010fa},
+    {0x010fc, 0x01248}, {0x0124a, 0x0124d}, {0x01250, 0x01256}, {0x01258, 0x01258},
+    {0x0125a, 0x0125d}, {0x01260, 0x01288}, {0x0128a, 0x0128d}, {0x01290, 0x012b0},
+    {0x012b2, 0x012b5}, {0x012b8, 0x012be}, {0x012c0, 0x012c0}, {0x012c2, 0x012c5},
+    {0x012c8, 0x012d6}, {0x012d8, 0x01310}, {0x01312, 0x01315}, {0x01318, 0x0135a},
+    {0x01380, 0x0138f}, {0x013a0, 0x013f5}, {0x013f8, 0x013fd}, {0x01401, 0x0166c},
+    {0x0166f, 0x0167f}, {0x01681, 0x0169a}, {0x016a0, 0x016ea}, {0x016ee, 0x016f8},
+    {0x01700, 0x01711}, {0x0171f, 0x01731}, {0x01740, 0x01751}, {0x01760, 0x0176c},
+    {0x0176e, 0x01770}, {0x01780, 0x017b3}, {0x017d7, 0x017d7}, {0x017dc, 0x017dc},
+    {0x01820, 0x01878}, {0x01880, 0x018a8}, {0x018aa, 0x018aa}, {0x018b0, 0x018f5},
+    {0x01900, 0x0191e}, {0x01950, 0x0196d}, {0x01970, 0x01974}, {0x01980, 0x019ab},
+    {0x019b0, 0x019c9}, {0x01a00, 0x01a16}, {0x01a20, 0x01a54}, {0x01aa7, 0x01aa7},
+    {0x01b05, 0x01b33}, {0x01b45, 0x01b4c}, {0x01b83, 0x01ba0}, {0x01bae, 0x01baf},
+    {0x01bba, 0x01be5}, {0x01c00, 0x01c23}, {0x01c4d, 0x01c4f}, {0x01c5a, 0x01c7d},
+    {0x01c80, 0x01c88}, {0x01c90, 0x01cba}, {0x01cbd, 0x01cbf}, {0x01ce9, 0x01cec},
+    {0x01cee, 0x01cf3}, {0x01cf5, 0x01cf6}, {0x01cfa, 0x01cfa}, {0x01d00, 0x01dbf},
+    {0x01e00, 0x01f15}, {0x01f18, 0x01f1d}, {0x01f20, 0x01f45}, {0x01f48, 0x01f4d},
+    {0x01f50, 0x01f57}, {0x01f59, 0x01f59}, {0x01f5b, 0x01f5b}, {0x01f5d, 0x01f5d},
+    {0x01f5f, 0x01f7d}, {0x01f80, 0x01fb4}, {0x01fb6, 0x01fbc}, {0x01fbe, 0x01fbe},
+    {0x01fc2, 0x01fc4}, {0x01fc6, 0x01fcc}, {0x01fd0, 0x01fd3}, {0x01fd6, 0x01fdb},
+    {0x01fe0, 0x01fec}, {0x01ff2, 0x01ff4}, {0x01ff6, 0x01ffc}, {0x02071, 0x02071},
+    {0x0207f, 0x0207f}, {0x02090, 0x0209c}, {0x02102, 0x02102}, {0x02107, 0x02107},
+    {0x0210a, 0x02113}, {0x02115, 0x02115}, {0x02118, 0x0211d}, {0x02124, 0x02124},
+    {0x02126, 0x02126}, {0x02128, 0x02128}, {0x0212a, 0x02139}, {0x0213c, 0x0213f},
+    {0x02145, 0x02149}, {0x0214e, 0x0214e}, {0x02160, 0x02188}, {0x02c00, 0x02ce4},
+    {0x02ceb, 0x02cee}, {0x02cf2, 0x02cf3}, {0x02d00, 0x02d25}, {0x02d27, 0x02d27},
+    {0x02d2d, 0x02d2d}, {0x02d30, 0x02d67}, {0x02d6f, 0x02d6f}, {0x02d80, 0x02d96},
+    {0x02da0, 0x02da6}, {0x02da8, 0x02dae}, {0x02db0, 0x02db6}, {0x02db8, 0x02dbe},
+    {0x02dc0, 0x02dc6}, {0x02dc8, 0x02dce}, {0x02dd0, 0x02dd6}, {0x02dd8, 0x02dde},
+    {0x03005, 0x03007}, {0x03021, 0x03029}, {0x03031, 0x03035}, {0x03038, 0x0303c},
+    {0x03041, 0x03096}, {0x0309d, 0x0309f}, {0x030a1, 0x030fa}, {0x030fc, 0x030ff},
+    {0x03105, 0x0312f}, {0x03131, 0x0318e}, {0x031a0, 0x031bf}, {0x031f0, 0x031ff},
+    {0x03400, 0x04dbf}, {0x04e00, 0x0a48c}, {0x0a4d0, 0x0a4fd}, {0x0a500, 0x0a60c},
+    {0x0a610, 0x0a61f}, {0x0a62a, 0x0a62b}, {0x0a640, 0x0a66e}, {0x0a67f, 0x0a69d},
+    {0x0a6a0, 0x0a6ef}, {0x0a717, 0x0a71f}, {0x0a722, 0x0a788}, {0x0a78b, 0x0a7ca},
+    {0x0a7d0, 0x0a7d1}, {0x0a7d3, 0x0a7d3}, {0x0a7d5, 0x0a7d9}, {0x0a7f2, 0x0a801},
+    {0x0a803, 0x0a805}, {0x0a807, 0x0a80a}, {0x0a80c, 0x0a822}, {0x0a840, 0x0a873},
+    {0x0a882, 0x0a8b3}, {0x0a8f2, 0x0a8f7}, {0x0a8fb, 0x0a8fb}, {0x0a8fd, 0x0a8fe},
+    {0x0a90a, 0x0a925}, {0x0a930, 0x0a946}, {0x0a960, 0x0a97c}, {0x0a984, 0x0a9b2},
+    {0x0a9cf, 0x0a9cf}, {0x0a9e0, 0x0a9e4}, {0x0a9e6, 0x0a9ef}, {0x0a9fa, 0x0a9fe},
+    {0x0aa00, 0x0aa28}, {0x0aa40, 0x0aa42}, {0x0aa44, 0x0aa4b}, {0x0aa60, 0x0aa76},
+    {0x0aa7a, 0x0aa7a}, {0x0aa7e, 0x0aaaf}, {0x0aab1, 0x0aab1}, {0x0aab5, 0x0aab6},
+    {0x0aab9, 0x0aabd}, {0x0aac0, 0x0aac0}, {0x0aac2, 0x0aac2}, {0x0aadb, 0x0aadd},
+    {0x0aae0, 0x0aaea}, {0x0aaf2, 0x0aaf4}, {0x0ab01, 0x0ab06}, {0x0ab09, 0x0ab0e},
+    {0x0ab11, 0x0ab16}, {0x0ab20, 0x0ab26}, {0x0ab28, 0x0ab2e}, {0x0ab30, 0x0ab5a},
+    {0x0ab5c, 0x0ab69}, {0x0ab70, 0x0abe2}, {0x0ac00, 0x0d7a3}, {0x0d7b0, 0x0d7c6},
+    {0x0d7cb, 0x0d7fb}, {0x0f900, 0x0fa6d}, {0x0fa70, 0x0fad9}, {0x0fb00, 0x0fb06},
+    {0x0fb13, 0x0fb17}, {0x0fb1d, 0x0fb1d}, {0x0fb1f, 0x0fb28}, {0x0fb2a, 0x0fb36},
+    {0x0fb38, 0x0fb3c}, {0x0fb3e, 0x0fb3e}, {0x0fb40, 0x0fb41}, {0x0fb43, 0x0fb44},
+    {0x0fb46, 0x0fbb1}, {0x0fbd3, 0x0fc5d}, {0x0fc64, 0x0fd3d}, {0x0fd50, 0x0fd8f},
+    {0x0fd92, 0x0fdc7}, {0x0fdf0, 0x0fdf9}, {0x0fe71, 0x0fe71}, {0x0fe73, 0x0fe73},
+    {0x0fe77, 0x0fe77}, {0x0fe79, 0x0fe79}, {0x0fe7b, 0x0fe7b}, {0x0fe7d, 0x0fe7d},
+    {0x0fe7f, 0x0fefc}, {0x0ff21, 0x0ff3a}, {0x0ff41, 0x0ff5a}, {0x0ff66, 0x0ff9d},
+    {0x0ffa0, 0x0ffbe}, {0x0ffc2, 0x0ffc7}, {0x0ffca, 0x0ffcf}, {0x0ffd2, 0x0ffd7},
+    {0x0ffda, 0x0ffdc}, {0x10000, 0x1000b}, {0x1000d, 0x10026}, {0x10028, 0x1003a},
+    {0x1003c, 0x1003d}, {0x1003f, 0x1004d}, {0x10050, 0x1005d}, {0x10080, 0x100fa},
+    {0x10140, 0x10174}, {0x10280, 0x1029c}, {0x102a0, 0x102d0}, {0x10300, 0x1031f},
+    {0x1032d, 0x1034a}, {0x10350, 0x10375}, {0x10380, 0x1039d}, {0x103a0, 0x103c3},
+    {0x103c8, 0x103cf}, {0x103d1, 0x103d5}, {0x10400, 0x1049d}, {0x104b0, 0x104d3},
+    {0x104d8, 0x104fb}, {0x10500, 0x10527}, {0x10530, 0x10563}, {0x10570, 0x1057a},
+    {0x1057c, 0x1058a}, {0x1058c, 0x10592}, {0x10594, 0x10595}, {0x10597, 0x105a1},
+    {0x105a3, 0x105b1}, {0x105b3, 0x105b9}, {0x105bb, 0x105bc}, {0x10600, 0x10736},
+    {0x10740, 0x10755}, {0x10760, 0x10767}, {0x10780, 0x10785}, {0x10787, 0x107b0},
+    {0x107b2, 0x107ba}, {0x10800, 0x10805}, {0x10808, 0x10808}, {0x1080a, 0x10835},
+    {0x10837, 0x10838}, {0x1083c, 0x1083c}, {0x1083f, 0x10855}, {0x10860, 0x10876},
+    {0x10880, 0x1089e}, {0x108e0, 0x108f2}, {0x108f4, 0x108f5}, {0x10900, 0x10915},
+    {0x10920, 0x10939}, {0x10980, 0x109b7}, {0x109be, 0x109bf}, {0x10a00, 0x10a00},
+    {0x10a10, 0x10a13}, {0x10a15, 0x10a17}, {0x10a19, 0x10a35}, {0x10a60, 0x10a7c},
+    {0x10a80, 0x10a9c}, {0x10ac0, 0x10ac7}, {0x10ac9, 0x10ae4}, {0x10b00, 0x10b35},
+    {0x10b40, 0x10b55}, {0x10b60, 0x10b72}, {0x10b80, 0x10b91}, {0x10c00, 0x10c48},
+    {0x10c80, 0x10cb2}, {0x10cc0, 0x10cf2}, {0x10d00, 0x10d23}, {0x10e80, 0x10ea9},
+    {0x10eb0, 0x10eb1}, {0x10f00, 0x10f1c}, {0x10f27, 0x10f27}, {0x10f30, 0x10f45},
+    {0x10f70, 0x10f81}, {0x10fb0, 0x10fc4}, {0x10fe0, 0x10ff6}, {0x11003, 0x11037},
+    {0x11071, 0x11072}, {0x11075, 0x11075}, {0x11083, 0x110af}, {0x110d0, 0x110e8},
+    {0x11103, 0x11126}, {0x11144, 0x11144}, {0x11147, 0x11147}, {0x11150, 0x11172},
+    {0x11176, 0x11176}, {0x11183, 0x111b2}, {0x111c1, 0x111c4}, {0x111da, 0x111da},
+    {0x111dc, 0x111dc}, {0x11200, 0x11211}, {0x11213, 0x1122b}, {0x11280, 0x11286},
+    {0x11288, 0x11288}, {0x1128a, 0x1128d}, {0x1128f, 0x1129d}, {0x1129f, 0x112a8},
+    {0x112b0, 0x112de}, {0x11305, 0x1130c}, {0x1130f, 0x11310}, {0x11313, 0x11328},
+    {0x1132a, 0x11330}, {0x11332, 0x11333}, {0x11335, 0x11339}, {0x1133d, 0x1133d},
+    {0x11350, 0x11350}, {0x1135d, 0x11361}, {0x11400, 0x11434}, {0x11447, 0x1144a},
+    {0x1145f, 0x11461}, {0x11480, 0x114af}, {0x114c4, 0x114c5}, {0x114c7, 0x114c7},
+    {0x11580, 0x115ae}, {0x115d8, 0x115db}, {0x11600, 0x1162f}, {0x11644, 0x11644},
+    {0x11680, 0x116aa}, {0x116b8, 0x116b8}, {0x11700, 0x1171a}, {0x11740, 0x11746},
+    {0x11800, 0x1182b}, {0x118a0, 0x118df}, {0x118ff, 0x11906}, {0x11909, 0x11909},
+    {0x1190c, 0x11913}, {0x11915, 0x11916}, {0x11918, 0x1192f}, {0x1193f, 0x1193f},
+    {0x11941, 0x11941}, {0x119a0, 0x119a7}, {0x119aa, 0x119d0}, {0x119e1, 0x119e1},
+    {0x119e3, 0x119e3}, {0x11a00, 0x11a00}, {0x11a0b, 0x11a32}, {0x11a3a, 0x11a3a},
+    {0x11a50, 0x11a50}, {0x11a5c, 0x11a89}, {0x11a9d, 0x11a9d}, {0x11ab0, 0x11af8},
+    {0x11c00, 0x11c08}, {0x11c0a, 0x11c2e}, {0x11c40, 0x11c40}, {0x11c72, 0x11c8f},
+    {0x11d00, 0x11d06}, {0x11d08, 0x11d09}, {0x11d0b, 0x11d30}, {0x11d46, 0x11d46},
+    {0x11d60, 0x11d65}, {0x11d67, 0x11d68}, {0x11d6a, 0x11d89}, {0x11d98, 0x11d98},
+    {0x11ee0, 0x11ef2}, {0x11fb0, 0x11fb0}, {0x12000, 0x12399}, {0x12400, 0x1246e},
+    {0x12480, 0x12543}, {0x12f90, 0x12ff0}, {0x13000, 0x1342e}, {0x14400, 0x14646},
+    {0x16800, 0x16a38}, {0x16a40, 0x16a5e}, {0x16a70, 0x16abe}, {0x16ad0, 0x16aed},
+    {0x16b00, 0x16b2f}, {0x16b40, 0x16b43}, {0x16b63, 0x16b77}, {0x16b7d, 0x16b8f},
+    {0x16e40, 0x16e7f}, {0x16f00, 0x16f4a}, {0x16f50, 0x16f50}, {0x16f93, 0x16f9f},
+    {0x16fe0, 0x16fe1}, {0x16fe3, 0x16fe3}, {0x17000, 0x187f7}, {0x18800, 0x18cd5},
+    {0x18d00, 0x18d08}, {0x1aff0, 0x1aff3}, {0x1aff5, 0x1affb}, {0x1affd, 0x1affe},
+    {0x1b000, 0x1b122}, {0x1b150, 0x1b152}, {0x1b164, 0x1b167}, {0x1b170, 0x1b2fb},
+    {0x1bc00, 0x1bc6a}, {0x1bc70, 0x1bc7c}, {0x1bc80, 0x1bc88}, {0x1bc90, 0x1bc99},
+    {0x1d400, 0x1d454}, {0x1d456, 0x1d49c}, {0x1d49e, 0x1d49f}, {0x1d4a2, 0x1d4a2},
+    {0x1d4a5, 0x1d4a6}, {0x1d4a9, 0x1d4ac}, {0x1d4ae, 0x1d4b9}, {0x1d4bb, 0x1d4bb},
+    {0x1d4bd, 0x1d4c3}, {0x1d4c5, 0x1d505}, {0x1d507, 0x1d50a}, {0x1d50d, 0x1d514},
+    {0x1d516, 0x1d51c}, {0x1d51e, 0x1d539}, {0x1d53b, 0x1d53e}, {0x1d540, 0x1d544},
+    {0x1d546, 0x1d546}, {0x1d54a, 0x1d550}, {0x1d552, 0x1d6a5}, {0x1d6a8, 0x1d6c0},
+    {0x1d6c2, 0x1d6da}, {0x1d6dc, 0x1d6fa}, {0x1d6fc, 0x1d714}, {0x1d716, 0x1d734},
+    {0x1d736, 0x1d74e}, {0x1d750, 0x1d76e}, {0x1d770, 0x1d788}, {0x1d78a, 0x1d7a8},
+    {0x1d7aa, 0x1d7c2}, {0x1d7c4, 0x1d7cb}, {0x1df00, 0x1df1e}, {0x1e100, 0x1e12c},
+    {0x1e137, 0x1e13d}, {0x1e14e, 0x1e14e}, {0x1e290, 0x1e2ad}, {0x1e2c0, 0x1e2eb},
+    {0x1e7e0, 0x1e7e6}, {0x1e7e8, 0x1e7eb}, {0x1e7ed, 0x1e7ee}, {0x1e7f0, 0x1e7fe},
+    {0x1e800, 0x1e8c4}, {0x1e900, 0x1e943}, {0x1e94b, 0x1e94b}, {0x1ee00, 0x1ee03},
+    {0x1ee05, 0x1ee1f}, {0x1ee21, 0x1ee22}, {0x1ee24, 0x1ee24}, {0x1ee27, 0x1ee27},
+    {0x1ee29, 0x1ee32}, {0x1ee34, 0x1ee37}, {0x1ee39, 0x1ee39}, {0x1ee3b, 0x1ee3b},
+    {0x1ee42, 0x1ee42}, {0x1ee47, 0x1ee47}, {0x1ee49, 0x1ee49}, {0x1ee4b, 0x1ee4b},
+    {0x1ee4d, 0x1ee4f}, {0x1ee51, 0x1ee52}, {0x1ee54, 0x1ee54}, {0x1ee57, 0x1ee57},
+    {0x1ee59, 0x1ee59}, {0x1ee5b, 0x1ee5b}, {0x1ee5d, 0x1ee5d}, {0x1ee5f, 0x1ee5f},
+    {0x1ee61, 0x1ee62}, {0x1ee64, 0x1ee64}, {0x1ee67, 0x1ee6a}, {0x1ee6c, 0x1ee72},
+    {0x1ee74, 0x1ee77}, {0x1ee79, 0x1ee7c}, {0x1ee7e, 0x1ee7e}, {0x1ee80, 0x1ee89},
+    {0x1ee8b, 0x1ee9b}, {0x1eea1, 0x1eea3}, {0x1eea5, 0x1eea9}, {0x1eeab, 0x1eebb},
+    {0x20000, 0x2a6df}, {0x2a700, 0x2b738}, {0x2b740, 0x2b81d}, {0x2b820, 0x2cea1},
+    {0x2ceb0, 0x2ebe0}, {0x2f800, 0x2fa1d}, {0x30000, 0x3134a},
 };
 
 // Number of ranges in kXIDStartRanges
-constexpr size_t kNumXIDStartRanges =
-    sizeof(kXIDStartRanges) / sizeof(kXIDStartRanges[0]);
+constexpr size_t kNumXIDStartRanges = sizeof(kXIDStartRanges) / sizeof(kXIDStartRanges[0]);
 
 // The additional code point interval ranges for the Unicode 14 XID_Continue
 // set. This extends the values in kXIDStartRanges.
 // This array needs to be in ascending order.
 constexpr CodePointRange kXIDContinueRanges[] = {
-    {0x00030, 0x00039}, {0x0005f, 0x0005f}, {0x000b7, 0x000b7},
-    {0x00300, 0x0036f}, {0x00387, 0x00387}, {0x00483, 0x00487},
-    {0x00591, 0x005bd}, {0x005bf, 0x005bf}, {0x005c1, 0x005c2},
-    {0x005c4, 0x005c5}, {0x005c7, 0x005c7}, {0x00610, 0x0061a},
-    {0x0064b, 0x00669}, {0x00670, 0x00670}, {0x006d6, 0x006dc},
-    {0x006df, 0x006e4}, {0x006e7, 0x006e8}, {0x006ea, 0x006ed},
-    {0x006f0, 0x006f9}, {0x00711, 0x00711}, {0x00730, 0x0074a},
-    {0x007a6, 0x007b0}, {0x007c0, 0x007c9}, {0x007eb, 0x007f3},
-    {0x007fd, 0x007fd}, {0x00816, 0x00819}, {0x0081b, 0x00823},
-    {0x00825, 0x00827}, {0x00829, 0x0082d}, {0x00859, 0x0085b},
-    {0x00898, 0x0089f}, {0x008ca, 0x008e1}, {0x008e3, 0x00903},
-    {0x0093a, 0x0093c}, {0x0093e, 0x0094f}, {0x00951, 0x00957},
-    {0x00962, 0x00963}, {0x00966, 0x0096f}, {0x00981, 0x00983},
-    {0x009bc, 0x009bc}, {0x009be, 0x009c4}, {0x009c7, 0x009c8},
-    {0x009cb, 0x009cd}, {0x009d7, 0x009d7}, {0x009e2, 0x009e3},
-    {0x009e6, 0x009ef}, {0x009fe, 0x009fe}, {0x00a01, 0x00a03},
-    {0x00a3c, 0x00a3c}, {0x00a3e, 0x00a42}, {0x00a47, 0x00a48},
-    {0x00a4b, 0x00a4d}, {0x00a51, 0x00a51}, {0x00a66, 0x00a71},
-    {0x00a75, 0x00a75}, {0x00a81, 0x00a83}, {0x00abc, 0x00abc},
-    {0x00abe, 0x00ac5}, {0x00ac7, 0x00ac9}, {0x00acb, 0x00acd},
-    {0x00ae2, 0x00ae3}, {0x00ae6, 0x00aef}, {0x00afa, 0x00aff},
-    {0x00b01, 0x00b03}, {0x00b3c, 0x00b3c}, {0x00b3e, 0x00b44},
-    {0x00b47, 0x00b48}, {0x00b4b, 0x00b4d}, {0x00b55, 0x00b57},
-    {0x00b62, 0x00b63}, {0x00b66, 0x00b6f}, {0x00b82, 0x00b82},
-    {0x00bbe, 0x00bc2}, {0x00bc6, 0x00bc8}, {0x00bca, 0x00bcd},
-    {0x00bd7, 0x00bd7}, {0x00be6, 0x00bef}, {0x00c00, 0x00c04},
-    {0x00c3c, 0x00c3c}, {0x00c3e, 0x00c44}, {0x00c46, 0x00c48},
-    {0x00c4a, 0x00c4d}, {0x00c55, 0x00c56}, {0x00c62, 0x00c63},
-    {0x00c66, 0x00c6f}, {0x00c81, 0x00c83}, {0x00cbc, 0x00cbc},
-    {0x00cbe, 0x00cc4}, {0x00cc6, 0x00cc8}, {0x00cca, 0x00ccd},
-    {0x00cd5, 0x00cd6}, {0x00ce2, 0x00ce3}, {0x00ce6, 0x00cef},
-    {0x00d00, 0x00d03}, {0x00d3b, 0x00d3c}, {0x00d3e, 0x00d44},
-    {0x00d46, 0x00d48}, {0x00d4a, 0x00d4d}, {0x00d57, 0x00d57},
-    {0x00d62, 0x00d63}, {0x00d66, 0x00d6f}, {0x00d81, 0x00d83},
-    {0x00dca, 0x00dca}, {0x00dcf, 0x00dd4}, {0x00dd6, 0x00dd6},
-    {0x00dd8, 0x00ddf}, {0x00de6, 0x00def}, {0x00df2, 0x00df3},
-    {0x00e31, 0x00e31}, {0x00e33, 0x00e3a}, {0x00e47, 0x00e4e},
-    {0x00e50, 0x00e59}, {0x00eb1, 0x00eb1}, {0x00eb3, 0x00ebc},
-    {0x00ec8, 0x00ecd}, {0x00ed0, 0x00ed9}, {0x00f18, 0x00f19},
-    {0x00f20, 0x00f29}, {0x00f35, 0x00f35}, {0x00f37, 0x00f37},
-    {0x00f39, 0x00f39}, {0x00f3e, 0x00f3f}, {0x00f71, 0x00f84},
-    {0x00f86, 0x00f87}, {0x00f8d, 0x00f97}, {0x00f99, 0x00fbc},
-    {0x00fc6, 0x00fc6}, {0x0102b, 0x0103e}, {0x01040, 0x01049},
-    {0x01056, 0x01059}, {0x0105e, 0x01060}, {0x01062, 0x01064},
-    {0x01067, 0x0106d}, {0x01071, 0x01074}, {0x01082, 0x0108d},
-    {0x0108f, 0x0109d}, {0x0135d, 0x0135f}, {0x01369, 0x01371},
-    {0x01712, 0x01715}, {0x01732, 0x01734}, {0x01752, 0x01753},
-    {0x01772, 0x01773}, {0x017b4, 0x017d3}, {0x017dd, 0x017dd},
-    {0x017e0, 0x017e9}, {0x0180b, 0x0180d}, {0x0180f, 0x01819},
-    {0x018a9, 0x018a9}, {0x01920, 0x0192b}, {0x01930, 0x0193b},
-    {0x01946, 0x0194f}, {0x019d0, 0x019da}, {0x01a17, 0x01a1b},
-    {0x01a55, 0x01a5e}, {0x01a60, 0x01a7c}, {0x01a7f, 0x01a89},
-    {0x01a90, 0x01a99}, {0x01ab0, 0x01abd}, {0x01abf, 0x01ace},
-    {0x01b00, 0x01b04}, {0x01b34, 0x01b44}, {0x01b50, 0x01b59},
-    {0x01b6b, 0x01b73}, {0x01b80, 0x01b82}, {0x01ba1, 0x01bad},
-    {0x01bb0, 0x01bb9}, {0x01be6, 0x01bf3}, {0x01c24, 0x01c37},
-    {0x01c40, 0x01c49}, {0x01c50, 0x01c59}, {0x01cd0, 0x01cd2},
-    {0x01cd4, 0x01ce8}, {0x01ced, 0x01ced}, {0x01cf4, 0x01cf4},
-    {0x01cf7, 0x01cf9}, {0x01dc0, 0x01dff}, {0x0203f, 0x02040},
-    {0x02054, 0x02054}, {0x020d0, 0x020dc}, {0x020e1, 0x020e1},
-    {0x020e5, 0x020f0}, {0x02cef, 0x02cf1}, {0x02d7f, 0x02d7f},
-    {0x02de0, 0x02dff}, {0x0302a, 0x0302f}, {0x03099, 0x0309a},
-    {0x0a620, 0x0a629}, {0x0a66f, 0x0a66f}, {0x0a674, 0x0a67d},
-    {0x0a69e, 0x0a69f}, {0x0a6f0, 0x0a6f1}, {0x0a802, 0x0a802},
-    {0x0a806, 0x0a806}, {0x0a80b, 0x0a80b}, {0x0a823, 0x0a827},
-    {0x0a82c, 0x0a82c}, {0x0a880, 0x0a881}, {0x0a8b4, 0x0a8c5},
-    {0x0a8d0, 0x0a8d9}, {0x0a8e0, 0x0a8f1}, {0x0a8ff, 0x0a909},
-    {0x0a926, 0x0a92d}, {0x0a947, 0x0a953}, {0x0a980, 0x0a983},
-    {0x0a9b3, 0x0a9c0}, {0x0a9d0, 0x0a9d9}, {0x0a9e5, 0x0a9e5},
-    {0x0a9f0, 0x0a9f9}, {0x0aa29, 0x0aa36}, {0x0aa43, 0x0aa43},
-    {0x0aa4c, 0x0aa4d}, {0x0aa50, 0x0aa59}, {0x0aa7b, 0x0aa7d},
-    {0x0aab0, 0x0aab0}, {0x0aab2, 0x0aab4}, {0x0aab7, 0x0aab8},
-    {0x0aabe, 0x0aabf}, {0x0aac1, 0x0aac1}, {0x0aaeb, 0x0aaef},
-    {0x0aaf5, 0x0aaf6}, {0x0abe3, 0x0abea}, {0x0abec, 0x0abed},
-    {0x0abf0, 0x0abf9}, {0x0fb1e, 0x0fb1e}, {0x0fe00, 0x0fe0f},
-    {0x0fe20, 0x0fe2f}, {0x0fe33, 0x0fe34}, {0x0fe4d, 0x0fe4f},
-    {0x0ff10, 0x0ff19}, {0x0ff3f, 0x0ff3f}, {0x0ff9e, 0x0ff9f},
-    {0x101fd, 0x101fd}, {0x102e0, 0x102e0}, {0x10376, 0x1037a},
-    {0x104a0, 0x104a9}, {0x10a01, 0x10a03}, {0x10a05, 0x10a06},
-    {0x10a0c, 0x10a0f}, {0x10a38, 0x10a3a}, {0x10a3f, 0x10a3f},
-    {0x10ae5, 0x10ae6}, {0x10d24, 0x10d27}, {0x10d30, 0x10d39},
-    {0x10eab, 0x10eac}, {0x10f46, 0x10f50}, {0x10f82, 0x10f85},
-    {0x11000, 0x11002}, {0x11038, 0x11046}, {0x11066, 0x11070},
-    {0x11073, 0x11074}, {0x1107f, 0x11082}, {0x110b0, 0x110ba},
-    {0x110c2, 0x110c2}, {0x110f0, 0x110f9}, {0x11100, 0x11102},
-    {0x11127, 0x11134}, {0x11136, 0x1113f}, {0x11145, 0x11146},
-    {0x11173, 0x11173}, {0x11180, 0x11182}, {0x111b3, 0x111c0},
-    {0x111c9, 0x111cc}, {0x111ce, 0x111d9}, {0x1122c, 0x11237},
-    {0x1123e, 0x1123e}, {0x112df, 0x112ea}, {0x112f0, 0x112f9},
-    {0x11300, 0x11303}, {0x1133b, 0x1133c}, {0x1133e, 0x11344},
-    {0x11347, 0x11348}, {0x1134b, 0x1134d}, {0x11357, 0x11357},
-    {0x11362, 0x11363}, {0x11366, 0x1136c}, {0x11370, 0x11374},
-    {0x11435, 0x11446}, {0x11450, 0x11459}, {0x1145e, 0x1145e},
-    {0x114b0, 0x114c3}, {0x114d0, 0x114d9}, {0x115af, 0x115b5},
-    {0x115b8, 0x115c0}, {0x115dc, 0x115dd}, {0x11630, 0x11640},
-    {0x11650, 0x11659}, {0x116ab, 0x116b7}, {0x116c0, 0x116c9},
-    {0x1171d, 0x1172b}, {0x11730, 0x11739}, {0x1182c, 0x1183a},
-    {0x118e0, 0x118e9}, {0x11930, 0x11935}, {0x11937, 0x11938},
-    {0x1193b, 0x1193e}, {0x11940, 0x11940}, {0x11942, 0x11943},
-    {0x11950, 0x11959}, {0x119d1, 0x119d7}, {0x119da, 0x119e0},
-    {0x119e4, 0x119e4}, {0x11a01, 0x11a0a}, {0x11a33, 0x11a39},
-    {0x11a3b, 0x11a3e}, {0x11a47, 0x11a47}, {0x11a51, 0x11a5b},
-    {0x11a8a, 0x11a99}, {0x11c2f, 0x11c36}, {0x11c38, 0x11c3f},
-    {0x11c50, 0x11c59}, {0x11c92, 0x11ca7}, {0x11ca9, 0x11cb6},
-    {0x11d31, 0x11d36}, {0x11d3a, 0x11d3a}, {0x11d3c, 0x11d3d},
-    {0x11d3f, 0x11d45}, {0x11d47, 0x11d47}, {0x11d50, 0x11d59},
-    {0x11d8a, 0x11d8e}, {0x11d90, 0x11d91}, {0x11d93, 0x11d97},
-    {0x11da0, 0x11da9}, {0x11ef3, 0x11ef6}, {0x16a60, 0x16a69},
-    {0x16ac0, 0x16ac9}, {0x16af0, 0x16af4}, {0x16b30, 0x16b36},
-    {0x16b50, 0x16b59}, {0x16f4f, 0x16f4f}, {0x16f51, 0x16f87},
-    {0x16f8f, 0x16f92}, {0x16fe4, 0x16fe4}, {0x16ff0, 0x16ff1},
-    {0x1bc9d, 0x1bc9e}, {0x1cf00, 0x1cf2d}, {0x1cf30, 0x1cf46},
-    {0x1d165, 0x1d169}, {0x1d16d, 0x1d172}, {0x1d17b, 0x1d182},
-    {0x1d185, 0x1d18b}, {0x1d1aa, 0x1d1ad}, {0x1d242, 0x1d244},
-    {0x1d7ce, 0x1d7ff}, {0x1da00, 0x1da36}, {0x1da3b, 0x1da6c},
-    {0x1da75, 0x1da75}, {0x1da84, 0x1da84}, {0x1da9b, 0x1da9f},
-    {0x1daa1, 0x1daaf}, {0x1e000, 0x1e006}, {0x1e008, 0x1e018},
-    {0x1e01b, 0x1e021}, {0x1e023, 0x1e024}, {0x1e026, 0x1e02a},
-    {0x1e130, 0x1e136}, {0x1e140, 0x1e149}, {0x1e2ae, 0x1e2ae},
-    {0x1e2ec, 0x1e2f9}, {0x1e8d0, 0x1e8d6}, {0x1e944, 0x1e94a},
+    {0x00030, 0x00039}, {0x0005f, 0x0005f}, {0x000b7, 0x000b7}, {0x00300, 0x0036f},
+    {0x00387, 0x00387}, {0x00483, 0x00487}, {0x00591, 0x005bd}, {0x005bf, 0x005bf},
+    {0x005c1, 0x005c2}, {0x005c4, 0x005c5}, {0x005c7, 0x005c7}, {0x00610, 0x0061a},
+    {0x0064b, 0x00669}, {0x00670, 0x00670}, {0x006d6, 0x006dc}, {0x006df, 0x006e4},
+    {0x006e7, 0x006e8}, {0x006ea, 0x006ed}, {0x006f0, 0x006f9}, {0x00711, 0x00711},
+    {0x00730, 0x0074a}, {0x007a6, 0x007b0}, {0x007c0, 0x007c9}, {0x007eb, 0x007f3},
+    {0x007fd, 0x007fd}, {0x00816, 0x00819}, {0x0081b, 0x00823}, {0x00825, 0x00827},
+    {0x00829, 0x0082d}, {0x00859, 0x0085b}, {0x00898, 0x0089f}, {0x008ca, 0x008e1},
+    {0x008e3, 0x00903}, {0x0093a, 0x0093c}, {0x0093e, 0x0094f}, {0x00951, 0x00957},
+    {0x00962, 0x00963}, {0x00966, 0x0096f}, {0x00981, 0x00983}, {0x009bc, 0x009bc},
+    {0x009be, 0x009c4}, {0x009c7, 0x009c8}, {0x009cb, 0x009cd}, {0x009d7, 0x009d7},
+    {0x009e2, 0x009e3}, {0x009e6, 0x009ef}, {0x009fe, 0x009fe}, {0x00a01, 0x00a03},
+    {0x00a3c, 0x00a3c}, {0x00a3e, 0x00a42}, {0x00a47, 0x00a48}, {0x00a4b, 0x00a4d},
+    {0x00a51, 0x00a51}, {0x00a66, 0x00a71}, {0x00a75, 0x00a75}, {0x00a81, 0x00a83},
+    {0x00abc, 0x00abc}, {0x00abe, 0x00ac5}, {0x00ac7, 0x00ac9}, {0x00acb, 0x00acd},
+    {0x00ae2, 0x00ae3}, {0x00ae6, 0x00aef}, {0x00afa, 0x00aff}, {0x00b01, 0x00b03},
+    {0x00b3c, 0x00b3c}, {0x00b3e, 0x00b44}, {0x00b47, 0x00b48}, {0x00b4b, 0x00b4d},
+    {0x00b55, 0x00b57}, {0x00b62, 0x00b63}, {0x00b66, 0x00b6f}, {0x00b82, 0x00b82},
+    {0x00bbe, 0x00bc2}, {0x00bc6, 0x00bc8}, {0x00bca, 0x00bcd}, {0x00bd7, 0x00bd7},
+    {0x00be6, 0x00bef}, {0x00c00, 0x00c04}, {0x00c3c, 0x00c3c}, {0x00c3e, 0x00c44},
+    {0x00c46, 0x00c48}, {0x00c4a, 0x00c4d}, {0x00c55, 0x00c56}, {0x00c62, 0x00c63},
+    {0x00c66, 0x00c6f}, {0x00c81, 0x00c83}, {0x00cbc, 0x00cbc}, {0x00cbe, 0x00cc4},
+    {0x00cc6, 0x00cc8}, {0x00cca, 0x00ccd}, {0x00cd5, 0x00cd6}, {0x00ce2, 0x00ce3},
+    {0x00ce6, 0x00cef}, {0x00d00, 0x00d03}, {0x00d3b, 0x00d3c}, {0x00d3e, 0x00d44},
+    {0x00d46, 0x00d48}, {0x00d4a, 0x00d4d}, {0x00d57, 0x00d57}, {0x00d62, 0x00d63},
+    {0x00d66, 0x00d6f}, {0x00d81, 0x00d83}, {0x00dca, 0x00dca}, {0x00dcf, 0x00dd4},
+    {0x00dd6, 0x00dd6}, {0x00dd8, 0x00ddf}, {0x00de6, 0x00def}, {0x00df2, 0x00df3},
+    {0x00e31, 0x00e31}, {0x00e33, 0x00e3a}, {0x00e47, 0x00e4e}, {0x00e50, 0x00e59},
+    {0x00eb1, 0x00eb1}, {0x00eb3, 0x00ebc}, {0x00ec8, 0x00ecd}, {0x00ed0, 0x00ed9},
+    {0x00f18, 0x00f19}, {0x00f20, 0x00f29}, {0x00f35, 0x00f35}, {0x00f37, 0x00f37},
+    {0x00f39, 0x00f39}, {0x00f3e, 0x00f3f}, {0x00f71, 0x00f84}, {0x00f86, 0x00f87},
+    {0x00f8d, 0x00f97}, {0x00f99, 0x00fbc}, {0x00fc6, 0x00fc6}, {0x0102b, 0x0103e},
+    {0x01040, 0x01049}, {0x01056, 0x01059}, {0x0105e, 0x01060}, {0x01062, 0x01064},
+    {0x01067, 0x0106d}, {0x01071, 0x01074}, {0x01082, 0x0108d}, {0x0108f, 0x0109d},
+    {0x0135d, 0x0135f}, {0x01369, 0x01371}, {0x01712, 0x01715}, {0x01732, 0x01734},
+    {0x01752, 0x01753}, {0x01772, 0x01773}, {0x017b4, 0x017d3}, {0x017dd, 0x017dd},
+    {0x017e0, 0x017e9}, {0x0180b, 0x0180d}, {0x0180f, 0x01819}, {0x018a9, 0x018a9},
+    {0x01920, 0x0192b}, {0x01930, 0x0193b}, {0x01946, 0x0194f}, {0x019d0, 0x019da},
+    {0x01a17, 0x01a1b}, {0x01a55, 0x01a5e}, {0x01a60, 0x01a7c}, {0x01a7f, 0x01a89},
+    {0x01a90, 0x01a99}, {0x01ab0, 0x01abd}, {0x01abf, 0x01ace}, {0x01b00, 0x01b04},
+    {0x01b34, 0x01b44}, {0x01b50, 0x01b59}, {0x01b6b, 0x01b73}, {0x01b80, 0x01b82},
+    {0x01ba1, 0x01bad}, {0x01bb0, 0x01bb9}, {0x01be6, 0x01bf3}, {0x01c24, 0x01c37},
+    {0x01c40, 0x01c49}, {0x01c50, 0x01c59}, {0x01cd0, 0x01cd2}, {0x01cd4, 0x01ce8},
+    {0x01ced, 0x01ced}, {0x01cf4, 0x01cf4}, {0x01cf7, 0x01cf9}, {0x01dc0, 0x01dff},
+    {0x0203f, 0x02040}, {0x02054, 0x02054}, {0x020d0, 0x020dc}, {0x020e1, 0x020e1},
+    {0x020e5, 0x020f0}, {0x02cef, 0x02cf1}, {0x02d7f, 0x02d7f}, {0x02de0, 0x02dff},
+    {0x0302a, 0x0302f}, {0x03099, 0x0309a}, {0x0a620, 0x0a629}, {0x0a66f, 0x0a66f},
+    {0x0a674, 0x0a67d}, {0x0a69e, 0x0a69f}, {0x0a6f0, 0x0a6f1}, {0x0a802, 0x0a802},
+    {0x0a806, 0x0a806}, {0x0a80b, 0x0a80b}, {0x0a823, 0x0a827}, {0x0a82c, 0x0a82c},
+    {0x0a880, 0x0a881}, {0x0a8b4, 0x0a8c5}, {0x0a8d0, 0x0a8d9}, {0x0a8e0, 0x0a8f1},
+    {0x0a8ff, 0x0a909}, {0x0a926, 0x0a92d}, {0x0a947, 0x0a953}, {0x0a980, 0x0a983},
+    {0x0a9b3, 0x0a9c0}, {0x0a9d0, 0x0a9d9}, {0x0a9e5, 0x0a9e5}, {0x0a9f0, 0x0a9f9},
+    {0x0aa29, 0x0aa36}, {0x0aa43, 0x0aa43}, {0x0aa4c, 0x0aa4d}, {0x0aa50, 0x0aa59},
+    {0x0aa7b, 0x0aa7d}, {0x0aab0, 0x0aab0}, {0x0aab2, 0x0aab4}, {0x0aab7, 0x0aab8},
+    {0x0aabe, 0x0aabf}, {0x0aac1, 0x0aac1}, {0x0aaeb, 0x0aaef}, {0x0aaf5, 0x0aaf6},
+    {0x0abe3, 0x0abea}, {0x0abec, 0x0abed}, {0x0abf0, 0x0abf9}, {0x0fb1e, 0x0fb1e},
+    {0x0fe00, 0x0fe0f}, {0x0fe20, 0x0fe2f}, {0x0fe33, 0x0fe34}, {0x0fe4d, 0x0fe4f},
+    {0x0ff10, 0x0ff19}, {0x0ff3f, 0x0ff3f}, {0x0ff9e, 0x0ff9f}, {0x101fd, 0x101fd},
+    {0x102e0, 0x102e0}, {0x10376, 0x1037a}, {0x104a0, 0x104a9}, {0x10a01, 0x10a03},
+    {0x10a05, 0x10a06}, {0x10a0c, 0x10a0f}, {0x10a38, 0x10a3a}, {0x10a3f, 0x10a3f},
+    {0x10ae5, 0x10ae6}, {0x10d24, 0x10d27}, {0x10d30, 0x10d39}, {0x10eab, 0x10eac},
+    {0x10f46, 0x10f50}, {0x10f82, 0x10f85}, {0x11000, 0x11002}, {0x11038, 0x11046},
+    {0x11066, 0x11070}, {0x11073, 0x11074}, {0x1107f, 0x11082}, {0x110b0, 0x110ba},
+    {0x110c2, 0x110c2}, {0x110f0, 0x110f9}, {0x11100, 0x11102}, {0x11127, 0x11134},
+    {0x11136, 0x1113f}, {0x11145, 0x11146}, {0x11173, 0x11173}, {0x11180, 0x11182},
+    {0x111b3, 0x111c0}, {0x111c9, 0x111cc}, {0x111ce, 0x111d9}, {0x1122c, 0x11237},
+    {0x1123e, 0x1123e}, {0x112df, 0x112ea}, {0x112f0, 0x112f9}, {0x11300, 0x11303},
+    {0x1133b, 0x1133c}, {0x1133e, 0x11344}, {0x11347, 0x11348}, {0x1134b, 0x1134d},
+    {0x11357, 0x11357}, {0x11362, 0x11363}, {0x11366, 0x1136c}, {0x11370, 0x11374},
+    {0x11435, 0x11446}, {0x11450, 0x11459}, {0x1145e, 0x1145e}, {0x114b0, 0x114c3},
+    {0x114d0, 0x114d9}, {0x115af, 0x115b5}, {0x115b8, 0x115c0}, {0x115dc, 0x115dd},
+    {0x11630, 0x11640}, {0x11650, 0x11659}, {0x116ab, 0x116b7}, {0x116c0, 0x116c9},
+    {0x1171d, 0x1172b}, {0x11730, 0x11739}, {0x1182c, 0x1183a}, {0x118e0, 0x118e9},
+    {0x11930, 0x11935}, {0x11937, 0x11938}, {0x1193b, 0x1193e}, {0x11940, 0x11940},
+    {0x11942, 0x11943}, {0x11950, 0x11959}, {0x119d1, 0x119d7}, {0x119da, 0x119e0},
+    {0x119e4, 0x119e4}, {0x11a01, 0x11a0a}, {0x11a33, 0x11a39}, {0x11a3b, 0x11a3e},
+    {0x11a47, 0x11a47}, {0x11a51, 0x11a5b}, {0x11a8a, 0x11a99}, {0x11c2f, 0x11c36},
+    {0x11c38, 0x11c3f}, {0x11c50, 0x11c59}, {0x11c92, 0x11ca7}, {0x11ca9, 0x11cb6},
+    {0x11d31, 0x11d36}, {0x11d3a, 0x11d3a}, {0x11d3c, 0x11d3d}, {0x11d3f, 0x11d45},
+    {0x11d47, 0x11d47}, {0x11d50, 0x11d59}, {0x11d8a, 0x11d8e}, {0x11d90, 0x11d91},
+    {0x11d93, 0x11d97}, {0x11da0, 0x11da9}, {0x11ef3, 0x11ef6}, {0x16a60, 0x16a69},
+    {0x16ac0, 0x16ac9}, {0x16af0, 0x16af4}, {0x16b30, 0x16b36}, {0x16b50, 0x16b59},
+    {0x16f4f, 0x16f4f}, {0x16f51, 0x16f87}, {0x16f8f, 0x16f92}, {0x16fe4, 0x16fe4},
+    {0x16ff0, 0x16ff1}, {0x1bc9d, 0x1bc9e}, {0x1cf00, 0x1cf2d}, {0x1cf30, 0x1cf46},
+    {0x1d165, 0x1d169}, {0x1d16d, 0x1d172}, {0x1d17b, 0x1d182}, {0x1d185, 0x1d18b},
+    {0x1d1aa, 0x1d1ad}, {0x1d242, 0x1d244}, {0x1d7ce, 0x1d7ff}, {0x1da00, 0x1da36},
+    {0x1da3b, 0x1da6c}, {0x1da75, 0x1da75}, {0x1da84, 0x1da84}, {0x1da9b, 0x1da9f},
+    {0x1daa1, 0x1daaf}, {0x1e000, 0x1e006}, {0x1e008, 0x1e018}, {0x1e01b, 0x1e021},
+    {0x1e023, 0x1e024}, {0x1e026, 0x1e02a}, {0x1e130, 0x1e136}, {0x1e140, 0x1e149},
+    {0x1e2ae, 0x1e2ae}, {0x1e2ec, 0x1e2f9}, {0x1e8d0, 0x1e8d6}, {0x1e944, 0x1e94a},
     {0x1e950, 0x1e959}, {0x1fbf0, 0x1fbf9}, {0xe0100, 0xe01ef},
 };
 
 // Number of ranges in kXIDContinueRanges
-constexpr size_t kNumXIDContinueRanges =
-    sizeof(kXIDContinueRanges) / sizeof(kXIDContinueRanges[0]);
+constexpr size_t kNumXIDContinueRanges = sizeof(kXIDContinueRanges) / sizeof(kXIDContinueRanges[0]);
 
 }  // namespace
 
 bool CodePoint::IsXIDStart() const {
-  return std::binary_search(kXIDStartRanges,
-                            kXIDStartRanges + kNumXIDStartRanges, *this);
+    return std::binary_search(kXIDStartRanges, kXIDStartRanges + kNumXIDStartRanges, *this);
 }
 
 bool CodePoint::IsXIDContinue() const {
-  return IsXIDStart() ||
-         std::binary_search(kXIDContinueRanges,
-                            kXIDContinueRanges + kNumXIDContinueRanges, *this);
+    return IsXIDStart() || std::binary_search(kXIDContinueRanges,
+                                              kXIDContinueRanges + kNumXIDContinueRanges, *this);
 }
 
 std::ostream& operator<<(std::ostream& out, CodePoint code_point) {
-  if (code_point < 0x7f) {
-    // See https://en.cppreference.com/w/cpp/language/escape
-    switch (code_point) {
-      case '\a':
-        return out << R"('\a')";
-      case '\b':
-        return out << R"('\b')";
-      case '\f':
-        return out << R"('\f')";
-      case '\n':
-        return out << R"('\n')";
-      case '\r':
-        return out << R"('\r')";
-      case '\t':
-        return out << R"('\t')";
-      case '\v':
-        return out << R"('\v')";
+    if (code_point < 0x7f) {
+        // See https://en.cppreference.com/w/cpp/language/escape
+        switch (code_point) {
+            case '\a':
+                return out << R"('\a')";
+            case '\b':
+                return out << R"('\b')";
+            case '\f':
+                return out << R"('\f')";
+            case '\n':
+                return out << R"('\n')";
+            case '\r':
+                return out << R"('\r')";
+            case '\t':
+                return out << R"('\t')";
+            case '\v':
+                return out << R"('\v')";
+        }
+        return out << "'" << static_cast<char>(code_point) << "'";
     }
-    return out << "'" << static_cast<char>(code_point) << "'";
-  }
-  return out << "'U+" << std::hex << code_point.value << "'";
+    return out << "'U+" << std::hex << code_point.value << "'";
 }
 
 namespace utf8 {
 
 std::pair<CodePoint, size_t> Decode(const uint8_t* ptr, size_t len) {
-  if (len < 1) {
-    return {};
-  }
+    if (len < 1) {
+        return {};
+    }
 
-  // Lookup table for the first byte of a UTF-8 sequence.
-  // 0 indicates an invalid length.
-  // Note that bit encodings that can fit in a smaller number of bytes are
-  // invalid (e.g. 0xc0). Code points that exceed the unicode maximum of
-  // 0x10FFFF are also invalid (0xf5+).
-  // See: https://en.wikipedia.org/wiki/UTF-8#Encoding and
-  //      https://datatracker.ietf.org/doc/html/rfc3629#section-3
-  static constexpr uint8_t kSequenceLength[256] = {
-      //         0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
-      /* 0x00 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-      /* 0x10 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-      /* 0x20 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-      /* 0x30 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-      /* 0x40 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-      /* 0x50 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-      /* 0x60 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-      /* 0x70 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
-      /* 0x80 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-      /* 0x90 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-      /* 0xa0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-      /* 0xb0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-      /* 0xc0 */ 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-      /* 0xd0 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
-      /* 0xe0 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
-      /* 0xf0 */ 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-  };
+    // Lookup table for the first byte of a UTF-8 sequence.
+    // 0 indicates an invalid length.
+    // Note that bit encodings that can fit in a smaller number of bytes are
+    // invalid (e.g. 0xc0). Code points that exceed the unicode maximum of
+    // 0x10FFFF are also invalid (0xf5+).
+    // See: https://en.wikipedia.org/wiki/UTF-8#Encoding and
+    //      https://datatracker.ietf.org/doc/html/rfc3629#section-3
+    static constexpr uint8_t kSequenceLength[256] = {
+        //         0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
+        /* 0x00 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        /* 0x10 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        /* 0x20 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        /* 0x30 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        /* 0x40 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        /* 0x50 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        /* 0x60 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        /* 0x70 */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+        /* 0x80 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        /* 0x90 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        /* 0xa0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        /* 0xb0 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+        /* 0xc0 */ 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+        /* 0xd0 */ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+        /* 0xe0 */ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+        /* 0xf0 */ 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+    };
 
-  uint8_t n = kSequenceLength[ptr[0]];
-  if (n > len) {
-    return {};
-  }
+    uint8_t n = kSequenceLength[ptr[0]];
+    if (n > len) {
+        return {};
+    }
 
-  CodePoint c;
+    CodePoint c;
 
-  uint8_t valid = 0x80;
-  switch (n) {
-    // Note: n=0 (invalid) is correctly handled without a case.
-    case 1:
-      c = CodePoint{ptr[0]};
-      break;
-    case 2:
-      valid &= ptr[1];
-      c = CodePoint{(static_cast<uint32_t>(ptr[0] & 0b00011111) << 6) |
-                    (static_cast<uint32_t>(ptr[1] & 0b00111111))};
-      break;
-    case 3:
-      valid &= ptr[1] & ptr[2];
-      c = CodePoint{(static_cast<uint32_t>(ptr[0] & 0b00001111) << 12) |
-                    (static_cast<uint32_t>(ptr[1] & 0b00111111) << 6) |
-                    (static_cast<uint32_t>(ptr[2] & 0b00111111))};
-      break;
-    case 4:
-      valid &= ptr[1] & ptr[2] & ptr[3];
-      c = CodePoint{(static_cast<uint32_t>(ptr[0] & 0b00000111) << 18) |
-                    (static_cast<uint32_t>(ptr[1] & 0b00111111) << 12) |
-                    (static_cast<uint32_t>(ptr[2] & 0b00111111) << 6) |
-                    (static_cast<uint32_t>(ptr[3] & 0b00111111))};
-      break;
-  }
-  if (!valid) {
-    n = 0;
-    c = 0;
-  }
-  return {c, n};
+    uint8_t valid = 0x80;
+    switch (n) {
+        // Note: n=0 (invalid) is correctly handled without a case.
+        case 1:
+            c = CodePoint{ptr[0]};
+            break;
+        case 2:
+            valid &= ptr[1];
+            c = CodePoint{(static_cast<uint32_t>(ptr[0] & 0b00011111) << 6) |
+                          (static_cast<uint32_t>(ptr[1] & 0b00111111))};
+            break;
+        case 3:
+            valid &= ptr[1] & ptr[2];
+            c = CodePoint{(static_cast<uint32_t>(ptr[0] & 0b00001111) << 12) |
+                          (static_cast<uint32_t>(ptr[1] & 0b00111111) << 6) |
+                          (static_cast<uint32_t>(ptr[2] & 0b00111111))};
+            break;
+        case 4:
+            valid &= ptr[1] & ptr[2] & ptr[3];
+            c = CodePoint{(static_cast<uint32_t>(ptr[0] & 0b00000111) << 18) |
+                          (static_cast<uint32_t>(ptr[1] & 0b00111111) << 12) |
+                          (static_cast<uint32_t>(ptr[2] & 0b00111111) << 6) |
+                          (static_cast<uint32_t>(ptr[3] & 0b00111111))};
+            break;
+    }
+    if (!valid) {
+        n = 0;
+        c = 0;
+    }
+    return {c, n};
 }
 
 bool IsASCII(std::string_view str) {
-  for (auto c : str) {
-    if (c & 0x80) {
-      return false;
+    for (auto c : str) {
+        if (c & 0x80) {
+            return false;
+        }
     }
-  }
-  return true;
+    return true;
 }
 
 }  // namespace utf8
diff --git a/src/tint/text/unicode.h b/src/tint/text/unicode.h
index 1d2a1b0..f0aa272 100644
--- a/src/tint/text/unicode.h
+++ b/src/tint/text/unicode.h
@@ -24,34 +24,34 @@
 
 /// CodePoint is a unicode code point.
 struct CodePoint {
-  /// Constructor
-  inline CodePoint() = default;
+    /// Constructor
+    inline CodePoint() = default;
 
-  /// Constructor
-  /// @param v the code point value
-  inline explicit CodePoint(uint32_t v) : value(v) {}
+    /// Constructor
+    /// @param v the code point value
+    inline explicit CodePoint(uint32_t v) : value(v) {}
 
-  /// @returns the code point value
-  inline operator uint32_t() const { return value; }
+    /// @returns the code point value
+    inline operator uint32_t() const { return value; }
 
-  /// Assignment operator
-  /// @param v the new value for the code point
-  /// @returns this CodePoint
-  inline CodePoint& operator=(uint32_t v) {
-    value = v;
-    return *this;
-  }
+    /// Assignment operator
+    /// @param v the new value for the code point
+    /// @returns this CodePoint
+    inline CodePoint& operator=(uint32_t v) {
+        value = v;
+        return *this;
+    }
 
-  /// @returns true if this CodePoint is in the XID_Start set.
-  /// @see https://unicode.org/reports/tr31/
-  bool IsXIDStart() const;
+    /// @returns true if this CodePoint is in the XID_Start set.
+    /// @see https://unicode.org/reports/tr31/
+    bool IsXIDStart() const;
 
-  /// @returns true if this CodePoint is in the XID_Continue set.
-  /// @see https://unicode.org/reports/tr31/
-  bool IsXIDContinue() const;
+    /// @returns true if this CodePoint is in the XID_Continue set.
+    /// @see https://unicode.org/reports/tr31/
+    bool IsXIDContinue() const;
 
-  /// The code point value
-  uint32_t value = 0;
+    /// The code point value
+    uint32_t value = 0;
 };
 
 /// Writes the CodePoint to the std::ostream.
diff --git a/src/tint/text/unicode_test.cc b/src/tint/text/unicode_test.cc
index 38221a4..67bbead 100644
--- a/src/tint/text/unicode_test.cc
+++ b/src/tint/text/unicode_test.cc
@@ -30,21 +30,21 @@
 namespace {
 
 struct CodePointCase {
-  CodePoint code_point;
-  bool is_xid_start;
-  bool is_xid_continue;
+    CodePoint code_point;
+    bool is_xid_start;
+    bool is_xid_continue;
 };
 
 std::ostream& operator<<(std::ostream& out, CodePointCase c) {
-  return out << c.code_point;
+    return out << c.code_point;
 }
 
 class CodePointTest : public testing::TestWithParam<CodePointCase> {};
 
 TEST_P(CodePointTest, CharacterSets) {
-  auto param = GetParam();
-  EXPECT_EQ(param.code_point.IsXIDStart(), param.is_xid_start);
-  EXPECT_EQ(param.code_point.IsXIDContinue(), param.is_xid_continue);
+    auto param = GetParam();
+    EXPECT_EQ(param.code_point.IsXIDStart(), param.is_xid_start);
+    EXPECT_EQ(param.code_point.IsXIDContinue(), param.is_xid_continue);
 }
 
 INSTANTIATE_TEST_SUITE_P(
@@ -222,136 +222,131 @@
 namespace {
 
 struct CodePointAndWidth {
-  CodePoint code_point;
-  size_t width;
+    CodePoint code_point;
+    size_t width;
 };
 
 bool operator==(const CodePointAndWidth& a, const CodePointAndWidth& b) {
-  return a.code_point == b.code_point && a.width == b.width;
+    return a.code_point == b.code_point && a.width == b.width;
 }
 
 std::ostream& operator<<(std::ostream& out, CodePointAndWidth cpw) {
-  return out << "code_point: " << cpw.code_point << ", width: " << cpw.width;
+    return out << "code_point: " << cpw.code_point << ", width: " << cpw.width;
 }
 
 struct DecodeUTF8Case {
-  std::string string;
-  std::vector<CodePointAndWidth> expected;
+    std::string string;
+    std::vector<CodePointAndWidth> expected;
 };
 
 std::ostream& operator<<(std::ostream& out, DecodeUTF8Case c) {
-  return out << "'" << c.string << "'";
+    return out << "'" << c.string << "'";
 }
 
 class DecodeUTF8Test : public testing::TestWithParam<DecodeUTF8Case> {};
 
 TEST_P(DecodeUTF8Test, Valid) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  const uint8_t* data = reinterpret_cast<const uint8_t*>(param.string.data());
-  const size_t len = param.string.size();
+    const uint8_t* data = reinterpret_cast<const uint8_t*>(param.string.data());
+    const size_t len = param.string.size();
 
-  std::vector<CodePointAndWidth> got;
-  size_t offset = 0;
-  while (offset < len) {
-    auto [code_point, width] = utf8::Decode(data + offset, len - offset);
-    if (width == 0) {
-      FAIL() << "Decode() failed at byte offset " << offset;
+    std::vector<CodePointAndWidth> got;
+    size_t offset = 0;
+    while (offset < len) {
+        auto [code_point, width] = utf8::Decode(data + offset, len - offset);
+        if (width == 0) {
+            FAIL() << "Decode() failed at byte offset " << offset;
+        }
+        offset += width;
+        got.emplace_back(CodePointAndWidth{code_point, width});
     }
-    offset += width;
-    got.emplace_back(CodePointAndWidth{code_point, width});
-  }
 
-  EXPECT_THAT(got, ::testing::ElementsAreArray(param.expected));
+    EXPECT_THAT(got, ::testing::ElementsAreArray(param.expected));
 }
 
-INSTANTIATE_TEST_SUITE_P(
-    AsciiLetters,
-    DecodeUTF8Test,
-    ::testing::ValuesIn({
-        DecodeUTF8Case{"a", {{C('a'), 1}}},
-        DecodeUTF8Case{"abc", {{C('a'), 1}, {C('b'), 1}, {C('c'), 1}}},
-        DecodeUTF8Case{"def", {{C('d'), 1}, {C('e'), 1}, {C('f'), 1}}},
-        DecodeUTF8Case{"gh", {{C('g'), 1}, {C('h'), 1}}},
-        DecodeUTF8Case{"ij", {{C('i'), 1}, {C('j'), 1}}},
-        DecodeUTF8Case{"klm", {{C('k'), 1}, {C('l'), 1}, {C('m'), 1}}},
-        DecodeUTF8Case{"nop", {{C('n'), 1}, {C('o'), 1}, {C('p'), 1}}},
-        DecodeUTF8Case{"qr", {{C('q'), 1}, {C('r'), 1}}},
-        DecodeUTF8Case{"stu", {{C('s'), 1}, {C('t'), 1}, {C('u'), 1}}},
-        DecodeUTF8Case{"vw", {{C('v'), 1}, {C('w'), 1}}},
-        DecodeUTF8Case{"xyz", {{C('x'), 1}, {C('y'), 1}, {C('z'), 1}}},
-        DecodeUTF8Case{"A", {{C('A'), 1}}},
-        DecodeUTF8Case{"ABC", {{C('A'), 1}, {C('B'), 1}, {C('C'), 1}}},
-        DecodeUTF8Case{"DEF", {{C('D'), 1}, {C('E'), 1}, {C('F'), 1}}},
-        DecodeUTF8Case{"GH", {{C('G'), 1}, {C('H'), 1}}},
-        DecodeUTF8Case{"IJ", {{C('I'), 1}, {C('J'), 1}}},
-        DecodeUTF8Case{"KLM", {{C('K'), 1}, {C('L'), 1}, {C('M'), 1}}},
-        DecodeUTF8Case{"NOP", {{C('N'), 1}, {C('O'), 1}, {C('P'), 1}}},
-        DecodeUTF8Case{"QR", {{C('Q'), 1}, {C('R'), 1}}},
-        DecodeUTF8Case{"STU", {{C('S'), 1}, {C('T'), 1}, {C('U'), 1}}},
-        DecodeUTF8Case{"VW", {{C('V'), 1}, {C('W'), 1}}},
-        DecodeUTF8Case{"XYZ", {{C('X'), 1}, {C('Y'), 1}, {C('Z'), 1}}},
-    }));
+INSTANTIATE_TEST_SUITE_P(AsciiLetters,
+                         DecodeUTF8Test,
+                         ::testing::ValuesIn({
+                             DecodeUTF8Case{"a", {{C('a'), 1}}},
+                             DecodeUTF8Case{"abc", {{C('a'), 1}, {C('b'), 1}, {C('c'), 1}}},
+                             DecodeUTF8Case{"def", {{C('d'), 1}, {C('e'), 1}, {C('f'), 1}}},
+                             DecodeUTF8Case{"gh", {{C('g'), 1}, {C('h'), 1}}},
+                             DecodeUTF8Case{"ij", {{C('i'), 1}, {C('j'), 1}}},
+                             DecodeUTF8Case{"klm", {{C('k'), 1}, {C('l'), 1}, {C('m'), 1}}},
+                             DecodeUTF8Case{"nop", {{C('n'), 1}, {C('o'), 1}, {C('p'), 1}}},
+                             DecodeUTF8Case{"qr", {{C('q'), 1}, {C('r'), 1}}},
+                             DecodeUTF8Case{"stu", {{C('s'), 1}, {C('t'), 1}, {C('u'), 1}}},
+                             DecodeUTF8Case{"vw", {{C('v'), 1}, {C('w'), 1}}},
+                             DecodeUTF8Case{"xyz", {{C('x'), 1}, {C('y'), 1}, {C('z'), 1}}},
+                             DecodeUTF8Case{"A", {{C('A'), 1}}},
+                             DecodeUTF8Case{"ABC", {{C('A'), 1}, {C('B'), 1}, {C('C'), 1}}},
+                             DecodeUTF8Case{"DEF", {{C('D'), 1}, {C('E'), 1}, {C('F'), 1}}},
+                             DecodeUTF8Case{"GH", {{C('G'), 1}, {C('H'), 1}}},
+                             DecodeUTF8Case{"IJ", {{C('I'), 1}, {C('J'), 1}}},
+                             DecodeUTF8Case{"KLM", {{C('K'), 1}, {C('L'), 1}, {C('M'), 1}}},
+                             DecodeUTF8Case{"NOP", {{C('N'), 1}, {C('O'), 1}, {C('P'), 1}}},
+                             DecodeUTF8Case{"QR", {{C('Q'), 1}, {C('R'), 1}}},
+                             DecodeUTF8Case{"STU", {{C('S'), 1}, {C('T'), 1}, {C('U'), 1}}},
+                             DecodeUTF8Case{"VW", {{C('V'), 1}, {C('W'), 1}}},
+                             DecodeUTF8Case{"XYZ", {{C('X'), 1}, {C('Y'), 1}, {C('Z'), 1}}},
+                         }));
 
-INSTANTIATE_TEST_SUITE_P(
-    AsciiNumbers,
-    DecodeUTF8Test,
-    ::testing::ValuesIn({
-        DecodeUTF8Case{"012", {{C('0'), 1}, {C('1'), 1}, {C('2'), 1}}},
-        DecodeUTF8Case{"345", {{C('3'), 1}, {C('4'), 1}, {C('5'), 1}}},
-        DecodeUTF8Case{"678", {{C('6'), 1}, {C('7'), 1}, {C('8'), 1}}},
-        DecodeUTF8Case{"9", {{C('9'), 1}}},
-    }));
+INSTANTIATE_TEST_SUITE_P(AsciiNumbers,
+                         DecodeUTF8Test,
+                         ::testing::ValuesIn({
+                             DecodeUTF8Case{"012", {{C('0'), 1}, {C('1'), 1}, {C('2'), 1}}},
+                             DecodeUTF8Case{"345", {{C('3'), 1}, {C('4'), 1}, {C('5'), 1}}},
+                             DecodeUTF8Case{"678", {{C('6'), 1}, {C('7'), 1}, {C('8'), 1}}},
+                             DecodeUTF8Case{"9", {{C('9'), 1}}},
+                         }));
 
-INSTANTIATE_TEST_SUITE_P(
-    AsciiSymbols,
-    DecodeUTF8Test,
-    ::testing::ValuesIn({
-        DecodeUTF8Case{"!\"#", {{C('!'), 1}, {C('"'), 1}, {C('#'), 1}}},
-        DecodeUTF8Case{"$%&", {{C('$'), 1}, {C('%'), 1}, {C('&'), 1}}},
-        DecodeUTF8Case{"'()", {{C('\''), 1}, {C('('), 1}, {C(')'), 1}}},
-        DecodeUTF8Case{"*,-", {{C('*'), 1}, {C(','), 1}, {C('-'), 1}}},
-        DecodeUTF8Case{"/`@", {{C('/'), 1}, {C('`'), 1}, {C('@'), 1}}},
-        DecodeUTF8Case{"^\\[", {{C('^'), 1}, {C('\\'), 1}, {C('['), 1}}},
-        DecodeUTF8Case{"]_|", {{C(']'), 1}, {C('_'), 1}, {C('|'), 1}}},
-        DecodeUTF8Case{"{}", {{C('{'), 1}, {C('}'), 1}}},
-    }));
+INSTANTIATE_TEST_SUITE_P(AsciiSymbols,
+                         DecodeUTF8Test,
+                         ::testing::ValuesIn({
+                             DecodeUTF8Case{"!\"#", {{C('!'), 1}, {C('"'), 1}, {C('#'), 1}}},
+                             DecodeUTF8Case{"$%&", {{C('$'), 1}, {C('%'), 1}, {C('&'), 1}}},
+                             DecodeUTF8Case{"'()", {{C('\''), 1}, {C('('), 1}, {C(')'), 1}}},
+                             DecodeUTF8Case{"*,-", {{C('*'), 1}, {C(','), 1}, {C('-'), 1}}},
+                             DecodeUTF8Case{"/`@", {{C('/'), 1}, {C('`'), 1}, {C('@'), 1}}},
+                             DecodeUTF8Case{"^\\[", {{C('^'), 1}, {C('\\'), 1}, {C('['), 1}}},
+                             DecodeUTF8Case{"]_|", {{C(']'), 1}, {C('_'), 1}, {C('|'), 1}}},
+                             DecodeUTF8Case{"{}", {{C('{'), 1}, {C('}'), 1}}},
+                         }));
 
-INSTANTIATE_TEST_SUITE_P(
-    AsciiSpecial,
-    DecodeUTF8Test,
-    ::testing::ValuesIn({
-        DecodeUTF8Case{"", {}},
-        DecodeUTF8Case{" \t\n", {{C(' '), 1}, {C('\t'), 1}, {C('\n'), 1}}},
-        DecodeUTF8Case{"\a\b\f", {{C('\a'), 1}, {C('\b'), 1}, {C('\f'), 1}}},
-        DecodeUTF8Case{"\n\r\t", {{C('\n'), 1}, {C('\r'), 1}, {C('\t'), 1}}},
-        DecodeUTF8Case{"\v", {{C('\v'), 1}}},
-    }));
+INSTANTIATE_TEST_SUITE_P(AsciiSpecial,
+                         DecodeUTF8Test,
+                         ::testing::ValuesIn({
+                             DecodeUTF8Case{"", {}},
+                             DecodeUTF8Case{" \t\n", {{C(' '), 1}, {C('\t'), 1}, {C('\n'), 1}}},
+                             DecodeUTF8Case{"\a\b\f", {{C('\a'), 1}, {C('\b'), 1}, {C('\f'), 1}}},
+                             DecodeUTF8Case{"\n\r\t", {{C('\n'), 1}, {C('\r'), 1}, {C('\t'), 1}}},
+                             DecodeUTF8Case{"\v", {{C('\v'), 1}}},
+                         }));
 
-INSTANTIATE_TEST_SUITE_P(
-    Hindi,
-    DecodeUTF8Test,
-    ::testing::ValuesIn({DecodeUTF8Case{
-        // नमस्ते दुनिया
-        "\xe0\xa4\xa8\xe0\xa4\xae\xe0\xa4\xb8\xe0\xa5\x8d\xe0\xa4\xa4\xe0\xa5"
-        "\x87\x20\xe0\xa4\xa6\xe0\xa5\x81\xe0\xa4\xa8\xe0\xa4\xbf\xe0\xa4\xaf"
-        "\xe0\xa4\xbe",
-        {
-            {C(0x0928), 3},  // न
-            {C(0x092e), 3},  // म
-            {C(0x0938), 3},  // स
-            {C(0x094d), 3},  // ्
-            {C(0x0924), 3},  // त
-            {C(0x0947), 3},  // े
-            {C(' '), 1},
-            {C(0x0926), 3},  // द
-            {C(0x0941), 3},  // ु
-            {C(0x0928), 3},  // न
-            {C(0x093f), 3},  // ि
-            {C(0x092f), 3},  // य
-            {C(0x093e), 3},  // ा
-        },
-    }}));
+INSTANTIATE_TEST_SUITE_P(Hindi,
+                         DecodeUTF8Test,
+                         ::testing::ValuesIn({DecodeUTF8Case{
+                             // नमस्ते दुनिया
+                             "\xe0\xa4\xa8\xe0\xa4\xae\xe0\xa4\xb8\xe0\xa5\x8d\xe0\xa4\xa4\xe0\xa5"
+                             "\x87\x20\xe0\xa4\xa6\xe0\xa5\x81\xe0\xa4\xa8\xe0\xa4\xbf\xe0\xa4\xaf"
+                             "\xe0\xa4\xbe",
+                             {
+                                 {C(0x0928), 3},  // न
+                                 {C(0x092e), 3},  // म
+                                 {C(0x0938), 3},  // स
+                                 {C(0x094d), 3},  // ्
+                                 {C(0x0924), 3},  // त
+                                 {C(0x0947), 3},  // े
+                                 {C(' '), 1},
+                                 {C(0x0926), 3},  // द
+                                 {C(0x0941), 3},  // ु
+                                 {C(0x0928), 3},  // न
+                                 {C(0x093f), 3},  // ि
+                                 {C(0x092f), 3},  // य
+                                 {C(0x093e), 3},  // ा
+                             },
+                         }}));
 
 INSTANTIATE_TEST_SUITE_P(Mandarin,
                          DecodeUTF8Test,
@@ -412,29 +407,28 @@
                              },
                          }}));
 
-INSTANTIATE_TEST_SUITE_P(
-    Random,
-    DecodeUTF8Test,
-    ::testing::ValuesIn({DecodeUTF8Case{
-        // Øⓑꚫ쁹Ǵ𐌒岾🥍ⴵ㍨又ᮗ
-        "\xc3\x98\xe2\x93\x91\xea\x9a\xab\xec\x81\xb9\xc7\xb4\xf0\x90\x8c\x92"
-        "\xe5\xb2\xbe\xf0\x9f\xa5\x8d\xe2\xb4\xb5\xe3\x8d\xa8\xe5\x8f\x88\xe1"
-        "\xae\x97",
-        {
-            {C(0x000d8), 2},  // Ø
-            {C(0x024d1), 3},  // ⓑ
-            {C(0x0a6ab), 3},  // ꚫ
-            {C(0x0c079), 3},  // 쁹
-            {C(0x001f4), 2},  // Ǵ
-            {C(0x10312), 4},  // 𐌒
-            {C(0x05cbe), 3},  // 岾
-            {C(0x1f94d), 4},  // 🥍
-            {C(0x02d35), 3},  // ⴵ
-            {C(0x03368), 3},  // ㍨
-            {C(0x053c8), 3},  // 又
-            {C(0x01b97), 3},  // ᮗ
-        },
-    }}));
+INSTANTIATE_TEST_SUITE_P(Random,
+                         DecodeUTF8Test,
+                         ::testing::ValuesIn({DecodeUTF8Case{
+                             // Øⓑꚫ쁹Ǵ𐌒岾🥍ⴵ㍨又ᮗ
+                             "\xc3\x98\xe2\x93\x91\xea\x9a\xab\xec\x81\xb9\xc7\xb4\xf0\x90\x8c\x92"
+                             "\xe5\xb2\xbe\xf0\x9f\xa5\x8d\xe2\xb4\xb5\xe3\x8d\xa8\xe5\x8f\x88\xe1"
+                             "\xae\x97",
+                             {
+                                 {C(0x000d8), 2},  // Ø
+                                 {C(0x024d1), 3},  // ⓑ
+                                 {C(0x0a6ab), 3},  // ꚫ
+                                 {C(0x0c079), 3},  // 쁹
+                                 {C(0x001f4), 2},  // Ǵ
+                                 {C(0x10312), 4},  // 𐌒
+                                 {C(0x05cbe), 3},  // 岾
+                                 {C(0x1f94d), 4},  // 🥍
+                                 {C(0x02d35), 3},  // ⴵ
+                                 {C(0x03368), 3},  // ㍨
+                                 {C(0x053c8), 3},  // 又
+                                 {C(0x01b97), 3},  // ᮗ
+                             },
+                         }}));
 
 }  // namespace
 
@@ -445,52 +439,51 @@
 class DecodeUTF8InvalidTest : public testing::TestWithParam<const char*> {};
 
 TEST_P(DecodeUTF8InvalidTest, Invalid) {
-  auto* param = GetParam();
+    auto* param = GetParam();
 
-  const uint8_t* data = reinterpret_cast<const uint8_t*>(param);
-  const size_t len = std::string(param).size();
+    const uint8_t* data = reinterpret_cast<const uint8_t*>(param);
+    const size_t len = std::string(param).size();
 
-  auto [code_point, width] = utf8::Decode(data, len);
-  EXPECT_EQ(code_point, CodePoint(0));
-  EXPECT_EQ(width, 0u);
+    auto [code_point, width] = utf8::Decode(data, len);
+    EXPECT_EQ(code_point, CodePoint(0));
+    EXPECT_EQ(width, 0u);
 }
 
-INSTANTIATE_TEST_SUITE_P(
-    Invalid,
-    DecodeUTF8InvalidTest,
-    ::testing::ValuesIn({
-        "\x80\x80\x80\x80",  // 10000000
-        "\x81\x80\x80\x80",  // 10000001
-        "\x8f\x80\x80\x80",  // 10001111
-        "\x90\x80\x80\x80",  // 10010000
-        "\x91\x80\x80\x80",  // 10010001
-        "\x9f\x80\x80\x80",  // 10011111
-        "\xa0\x80\x80\x80",  // 10100000
-        "\xa1\x80\x80\x80",  // 10100001
-        "\xaf\x80\x80\x80",  // 10101111
-        "\xb0\x80\x80\x80",  // 10110000
-        "\xb1\x80\x80\x80",  // 10110001
-        "\xbf\x80\x80\x80",  // 10111111
-        "\xc0\x80\x80\x80",  // 11000000
-        "\xc1\x80\x80\x80",  // 11000001
-        "\xf5\x80\x80\x80",  // 11110101
-        "\xf6\x80\x80\x80",  // 11110110
-        "\xf7\x80\x80\x80",  // 11110111
-        "\xf8\x80\x80\x80",  // 11111000
-        "\xfe\x80\x80\x80",  // 11111110
-        "\xff\x80\x80\x80",  // 11111111
+INSTANTIATE_TEST_SUITE_P(Invalid,
+                         DecodeUTF8InvalidTest,
+                         ::testing::ValuesIn({
+                             "\x80\x80\x80\x80",  // 10000000
+                             "\x81\x80\x80\x80",  // 10000001
+                             "\x8f\x80\x80\x80",  // 10001111
+                             "\x90\x80\x80\x80",  // 10010000
+                             "\x91\x80\x80\x80",  // 10010001
+                             "\x9f\x80\x80\x80",  // 10011111
+                             "\xa0\x80\x80\x80",  // 10100000
+                             "\xa1\x80\x80\x80",  // 10100001
+                             "\xaf\x80\x80\x80",  // 10101111
+                             "\xb0\x80\x80\x80",  // 10110000
+                             "\xb1\x80\x80\x80",  // 10110001
+                             "\xbf\x80\x80\x80",  // 10111111
+                             "\xc0\x80\x80\x80",  // 11000000
+                             "\xc1\x80\x80\x80",  // 11000001
+                             "\xf5\x80\x80\x80",  // 11110101
+                             "\xf6\x80\x80\x80",  // 11110110
+                             "\xf7\x80\x80\x80",  // 11110111
+                             "\xf8\x80\x80\x80",  // 11111000
+                             "\xfe\x80\x80\x80",  // 11111110
+                             "\xff\x80\x80\x80",  // 11111111
 
-        "\xd0",          // 2-bytes, missing second byte
-        "\xe8\x8f",      // 3-bytes, missing third byte
-        "\xf4\x8f\x8f",  // 4-bytes, missing fourth byte
+                             "\xd0",          // 2-bytes, missing second byte
+                             "\xe8\x8f",      // 3-bytes, missing third byte
+                             "\xf4\x8f\x8f",  // 4-bytes, missing fourth byte
 
-        "\xd0\x7f",          // 2-bytes, second byte MSB unset
-        "\xe8\x7f\x8f",      // 3-bytes, second byte MSB unset
-        "\xe8\x8f\x7f",      // 3-bytes, third byte MSB unset
-        "\xf4\x7f\x8f\x8f",  // 4-bytes, second byte MSB unset
-        "\xf4\x8f\x7f\x8f",  // 4-bytes, third byte MSB unset
-        "\xf4\x8f\x8f\x7f",  // 4-bytes, fourth byte MSB unset
-    }));
+                             "\xd0\x7f",          // 2-bytes, second byte MSB unset
+                             "\xe8\x7f\x8f",      // 3-bytes, second byte MSB unset
+                             "\xe8\x8f\x7f",      // 3-bytes, third byte MSB unset
+                             "\xf4\x7f\x8f\x8f",  // 4-bytes, second byte MSB unset
+                             "\xf4\x8f\x7f\x8f",  // 4-bytes, third byte MSB unset
+                             "\xf4\x8f\x8f\x7f",  // 4-bytes, fourth byte MSB unset
+                         }));
 
 }  // namespace
 
diff --git a/src/tint/traits.h b/src/tint/traits.h
index dc104cc..eb81b3f 100644
--- a/src/tint/traits.h
+++ b/src/tint/traits.h
@@ -31,47 +31,44 @@
 /// Signature describes the signature of a function.
 template <typename RETURN, typename... PARAMETERS>
 struct Signature {
-  /// The return type of the function signature
-  using ret = RETURN;
-  /// The parameters of the function signature held in a std::tuple
-  using parameters = std::tuple<PARAMETERS...>;
-  /// The type of the Nth parameter of function signature
-  template <std::size_t N>
-  using parameter = NthTypeOf<N, PARAMETERS...>;
-  /// The total number of parameters
-  static constexpr std::size_t parameter_count = sizeof...(PARAMETERS);
+    /// The return type of the function signature
+    using ret = RETURN;
+    /// The parameters of the function signature held in a std::tuple
+    using parameters = std::tuple<PARAMETERS...>;
+    /// The type of the Nth parameter of function signature
+    template <std::size_t N>
+    using parameter = NthTypeOf<N, PARAMETERS...>;
+    /// The total number of parameters
+    static constexpr std::size_t parameter_count = sizeof...(PARAMETERS);
 };
 
 /// SignatureOf is a traits helper that infers the signature of the function,
 /// method, static method, lambda, or function-like object `F`.
 template <typename F>
 struct SignatureOf {
-  /// The signature of the function-like object `F`
-  using type = typename SignatureOf<decltype(&F::operator())>::type;
+    /// The signature of the function-like object `F`
+    using type = typename SignatureOf<decltype(&F::operator())>::type;
 };
 
 /// SignatureOf specialization for a regular function or static method.
 template <typename R, typename... ARGS>
 struct SignatureOf<R (*)(ARGS...)> {
-  /// The signature of the function-like object `F`
-  using type = Signature<typename std::decay<R>::type,
-                         typename std::decay<ARGS>::type...>;
+    /// The signature of the function-like object `F`
+    using type = Signature<typename std::decay<R>::type, typename std::decay<ARGS>::type...>;
 };
 
 /// SignatureOf specialization for a non-static method.
 template <typename R, typename C, typename... ARGS>
 struct SignatureOf<R (C::*)(ARGS...)> {
-  /// The signature of the function-like object `F`
-  using type = Signature<typename std::decay<R>::type,
-                         typename std::decay<ARGS>::type...>;
+    /// The signature of the function-like object `F`
+    using type = Signature<typename std::decay<R>::type, typename std::decay<ARGS>::type...>;
 };
 
 /// SignatureOf specialization for a non-static, const method.
 template <typename R, typename C, typename... ARGS>
 struct SignatureOf<R (C::*)(ARGS...) const> {
-  /// The signature of the function-like object `F`
-  using type = Signature<typename std::decay<R>::type,
-                         typename std::decay<ARGS>::type...>;
+    /// The signature of the function-like object `F`
+    using type = Signature<typename std::decay<R>::type, typename std::decay<ARGS>::type...>;
 };
 
 /// SignatureOfT is an alias to `typename SignatureOf<F>::type`.
@@ -90,8 +87,7 @@
 /// `BASE`.
 template <typename T, typename BASE>
 static constexpr bool IsTypeOrDerived =
-    std::is_base_of<BASE, Decay<T>>::value ||
-    std::is_same<BASE, Decay<T>>::value;
+    std::is_base_of<BASE, Decay<T>>::value || std::is_same<BASE, Decay<T>>::value;
 
 /// If `CONDITION` is true then EnableIf resolves to type T, otherwise an
 /// invalid type.
@@ -111,13 +107,13 @@
 /// @returns the std::index_sequence with all the indices shifted by OFFSET.
 template <std::size_t OFFSET, std::size_t... INDICES>
 constexpr auto Shift(std::index_sequence<INDICES...>) {
-  return std::integer_sequence<std::size_t, OFFSET + INDICES...>{};
+    return std::integer_sequence<std::size_t, OFFSET + INDICES...>{};
 }
 
 /// @returns a std::integer_sequence with the integers `[OFFSET..OFFSET+COUNT)`
 template <std::size_t OFFSET, std::size_t COUNT>
 constexpr auto Range() {
-  return Shift<OFFSET>(std::make_index_sequence<COUNT>{});
+    return Shift<OFFSET>(std::make_index_sequence<COUNT>{});
 }
 
 namespace detail {
@@ -125,11 +121,9 @@
 /// @returns the tuple `t` swizzled by `INDICES`
 template <typename TUPLE, std::size_t... INDICES>
 constexpr auto Swizzle(TUPLE&& t, std::index_sequence<INDICES...>)
-    -> std::tuple<
-        std::tuple_element_t<INDICES, std::remove_reference_t<TUPLE>>...> {
-  return {std::forward<
-      std::tuple_element_t<INDICES, std::remove_reference_t<TUPLE>>>(
-      std::get<INDICES>(std::forward<TUPLE>(t)))...};
+    -> std::tuple<std::tuple_element_t<INDICES, std::remove_reference_t<TUPLE>>...> {
+    return {std::forward<std::tuple_element_t<INDICES, std::remove_reference_t<TUPLE>>>(
+        std::get<INDICES>(std::forward<TUPLE>(t)))...};
 }
 
 /// @returns a nullptr of the tuple type `TUPLE` swizzled by `INDICES`.
@@ -138,8 +132,8 @@
 /// types.
 template <typename TUPLE, std::size_t... INDICES>
 constexpr auto* SwizzlePtrTy(std::index_sequence<INDICES...>) {
-  using Swizzled = std::tuple<std::tuple_element_t<INDICES, TUPLE>...>;
-  return static_cast<Swizzled*>(nullptr);
+    using Swizzled = std::tuple<std::tuple_element_t<INDICES, TUPLE>...>;
+    return static_cast<Swizzled*>(nullptr);
 }
 
 }  // namespace detail
@@ -148,14 +142,14 @@
 /// `[OFFSET..OFFSET+COUNT)`
 template <std::size_t OFFSET, std::size_t COUNT, typename TUPLE>
 constexpr auto Slice(TUPLE&& t) {
-  return detail::Swizzle<TUPLE>(std::forward<TUPLE>(t), Range<OFFSET, COUNT>());
+    return detail::Swizzle<TUPLE>(std::forward<TUPLE>(t), Range<OFFSET, COUNT>());
 }
 
 /// Resolves to the slice of the tuple `t` with the tuple elements
 /// `[OFFSET..OFFSET+COUNT)`
 template <std::size_t OFFSET, std::size_t COUNT, typename TUPLE>
-using SliceTuple = std::remove_pointer_t<decltype(
-    detail::SwizzlePtrTy<TUPLE>(Range<OFFSET, COUNT>()))>;
+using SliceTuple =
+    std::remove_pointer_t<decltype(detail::SwizzlePtrTy<TUPLE>(Range<OFFSET, COUNT>()))>;
 
 }  // namespace tint::traits
 
diff --git a/src/tint/traits_test.cc b/src/tint/traits_test.cc
index 6af0bd4..c100107 100644
--- a/src/tint/traits_test.cc
+++ b/src/tint/traits_test.cc
@@ -25,209 +25,201 @@
 }  // namespace
 
 TEST(ParamType, Function) {
-  F1({});        // Avoid unused method warning
-  F3(0, {}, 0);  // Avoid unused method warning
-  static_assert(std::is_same_v<ParameterType<decltype(&F1), 0>, S>);
-  static_assert(std::is_same_v<ParameterType<decltype(&F3), 0>, int>);
-  static_assert(std::is_same_v<ParameterType<decltype(&F3), 1>, S>);
-  static_assert(std::is_same_v<ParameterType<decltype(&F3), 2>, float>);
-  static_assert(std::is_same_v<ReturnType<decltype(&F1)>, void>);
-  static_assert(std::is_same_v<ReturnType<decltype(&F3)>, void>);
-  static_assert(SignatureOfT<decltype(&F1)>::parameter_count == 1);
-  static_assert(SignatureOfT<decltype(&F3)>::parameter_count == 3);
+    F1({});        // Avoid unused method warning
+    F3(0, {}, 0);  // Avoid unused method warning
+    static_assert(std::is_same_v<ParameterType<decltype(&F1), 0>, S>);
+    static_assert(std::is_same_v<ParameterType<decltype(&F3), 0>, int>);
+    static_assert(std::is_same_v<ParameterType<decltype(&F3), 1>, S>);
+    static_assert(std::is_same_v<ParameterType<decltype(&F3), 2>, float>);
+    static_assert(std::is_same_v<ReturnType<decltype(&F1)>, void>);
+    static_assert(std::is_same_v<ReturnType<decltype(&F3)>, void>);
+    static_assert(SignatureOfT<decltype(&F1)>::parameter_count == 1);
+    static_assert(SignatureOfT<decltype(&F3)>::parameter_count == 3);
 }
 
 TEST(ParamType, Method) {
-  class C {
-   public:
-    void F1(S) {}
-    void F3(int, S, float) {}
-  };
-  C().F1({});        // Avoid unused method warning
-  C().F3(0, {}, 0);  // Avoid unused method warning
-  static_assert(std::is_same_v<ParameterType<decltype(&C::F1), 0>, S>);
-  static_assert(std::is_same_v<ParameterType<decltype(&C::F3), 0>, int>);
-  static_assert(std::is_same_v<ParameterType<decltype(&C::F3), 1>, S>);
-  static_assert(std::is_same_v<ParameterType<decltype(&C::F3), 2>, float>);
-  static_assert(std::is_same_v<ReturnType<decltype(&C::F1)>, void>);
-  static_assert(std::is_same_v<ReturnType<decltype(&C::F3)>, void>);
-  static_assert(SignatureOfT<decltype(&C::F1)>::parameter_count == 1);
-  static_assert(SignatureOfT<decltype(&C::F3)>::parameter_count == 3);
+    class C {
+      public:
+        void F1(S) {}
+        void F3(int, S, float) {}
+    };
+    C().F1({});        // Avoid unused method warning
+    C().F3(0, {}, 0);  // Avoid unused method warning
+    static_assert(std::is_same_v<ParameterType<decltype(&C::F1), 0>, S>);
+    static_assert(std::is_same_v<ParameterType<decltype(&C::F3), 0>, int>);
+    static_assert(std::is_same_v<ParameterType<decltype(&C::F3), 1>, S>);
+    static_assert(std::is_same_v<ParameterType<decltype(&C::F3), 2>, float>);
+    static_assert(std::is_same_v<ReturnType<decltype(&C::F1)>, void>);
+    static_assert(std::is_same_v<ReturnType<decltype(&C::F3)>, void>);
+    static_assert(SignatureOfT<decltype(&C::F1)>::parameter_count == 1);
+    static_assert(SignatureOfT<decltype(&C::F3)>::parameter_count == 3);
 }
 
 TEST(ParamType, ConstMethod) {
-  class C {
-   public:
-    void F1(S) const {}
-    void F3(int, S, float) const {}
-  };
-  C().F1({});        // Avoid unused method warning
-  C().F3(0, {}, 0);  // Avoid unused method warning
-  static_assert(std::is_same_v<ParameterType<decltype(&C::F1), 0>, S>);
-  static_assert(std::is_same_v<ParameterType<decltype(&C::F3), 0>, int>);
-  static_assert(std::is_same_v<ParameterType<decltype(&C::F3), 1>, S>);
-  static_assert(std::is_same_v<ParameterType<decltype(&C::F3), 2>, float>);
-  static_assert(std::is_same_v<ReturnType<decltype(&C::F1)>, void>);
-  static_assert(std::is_same_v<ReturnType<decltype(&C::F3)>, void>);
-  static_assert(SignatureOfT<decltype(&C::F1)>::parameter_count == 1);
-  static_assert(SignatureOfT<decltype(&C::F3)>::parameter_count == 3);
+    class C {
+      public:
+        void F1(S) const {}
+        void F3(int, S, float) const {}
+    };
+    C().F1({});        // Avoid unused method warning
+    C().F3(0, {}, 0);  // Avoid unused method warning
+    static_assert(std::is_same_v<ParameterType<decltype(&C::F1), 0>, S>);
+    static_assert(std::is_same_v<ParameterType<decltype(&C::F3), 0>, int>);
+    static_assert(std::is_same_v<ParameterType<decltype(&C::F3), 1>, S>);
+    static_assert(std::is_same_v<ParameterType<decltype(&C::F3), 2>, float>);
+    static_assert(std::is_same_v<ReturnType<decltype(&C::F1)>, void>);
+    static_assert(std::is_same_v<ReturnType<decltype(&C::F3)>, void>);
+    static_assert(SignatureOfT<decltype(&C::F1)>::parameter_count == 1);
+    static_assert(SignatureOfT<decltype(&C::F3)>::parameter_count == 3);
 }
 
 TEST(ParamType, StaticMethod) {
-  class C {
-   public:
-    static void F1(S) {}
-    static void F3(int, S, float) {}
-  };
-  C::F1({});        // Avoid unused method warning
-  C::F3(0, {}, 0);  // Avoid unused method warning
-  static_assert(std::is_same_v<ParameterType<decltype(&C::F1), 0>, S>);
-  static_assert(std::is_same_v<ParameterType<decltype(&C::F3), 0>, int>);
-  static_assert(std::is_same_v<ParameterType<decltype(&C::F3), 1>, S>);
-  static_assert(std::is_same_v<ParameterType<decltype(&C::F3), 2>, float>);
-  static_assert(std::is_same_v<ReturnType<decltype(&C::F1)>, void>);
-  static_assert(std::is_same_v<ReturnType<decltype(&C::F3)>, void>);
-  static_assert(SignatureOfT<decltype(&C::F1)>::parameter_count == 1);
-  static_assert(SignatureOfT<decltype(&C::F3)>::parameter_count == 3);
+    class C {
+      public:
+        static void F1(S) {}
+        static void F3(int, S, float) {}
+    };
+    C::F1({});        // Avoid unused method warning
+    C::F3(0, {}, 0);  // Avoid unused method warning
+    static_assert(std::is_same_v<ParameterType<decltype(&C::F1), 0>, S>);
+    static_assert(std::is_same_v<ParameterType<decltype(&C::F3), 0>, int>);
+    static_assert(std::is_same_v<ParameterType<decltype(&C::F3), 1>, S>);
+    static_assert(std::is_same_v<ParameterType<decltype(&C::F3), 2>, float>);
+    static_assert(std::is_same_v<ReturnType<decltype(&C::F1)>, void>);
+    static_assert(std::is_same_v<ReturnType<decltype(&C::F3)>, void>);
+    static_assert(SignatureOfT<decltype(&C::F1)>::parameter_count == 1);
+    static_assert(SignatureOfT<decltype(&C::F3)>::parameter_count == 3);
 }
 
 TEST(ParamType, FunctionLike) {
-  using F1 = std::function<void(S)>;
-  using F3 = std::function<void(int, S, float)>;
-  static_assert(std::is_same_v<ParameterType<F1, 0>, S>);
-  static_assert(std::is_same_v<ParameterType<F3, 0>, int>);
-  static_assert(std::is_same_v<ParameterType<F3, 1>, S>);
-  static_assert(std::is_same_v<ParameterType<F3, 2>, float>);
-  static_assert(std::is_same_v<ReturnType<F1>, void>);
-  static_assert(std::is_same_v<ReturnType<F3>, void>);
-  static_assert(SignatureOfT<F1>::parameter_count == 1);
-  static_assert(SignatureOfT<F3>::parameter_count == 3);
+    using F1 = std::function<void(S)>;
+    using F3 = std::function<void(int, S, float)>;
+    static_assert(std::is_same_v<ParameterType<F1, 0>, S>);
+    static_assert(std::is_same_v<ParameterType<F3, 0>, int>);
+    static_assert(std::is_same_v<ParameterType<F3, 1>, S>);
+    static_assert(std::is_same_v<ParameterType<F3, 2>, float>);
+    static_assert(std::is_same_v<ReturnType<F1>, void>);
+    static_assert(std::is_same_v<ReturnType<F3>, void>);
+    static_assert(SignatureOfT<F1>::parameter_count == 1);
+    static_assert(SignatureOfT<F3>::parameter_count == 3);
 }
 
 TEST(ParamType, Lambda) {
-  auto l1 = [](S) {};
-  auto l3 = [](int, S, float) {};
-  static_assert(std::is_same_v<ParameterType<decltype(l1), 0>, S>);
-  static_assert(std::is_same_v<ParameterType<decltype(l3), 0>, int>);
-  static_assert(std::is_same_v<ParameterType<decltype(l3), 1>, S>);
-  static_assert(std::is_same_v<ParameterType<decltype(l3), 2>, float>);
-  static_assert(std::is_same_v<ReturnType<decltype(l1)>, void>);
-  static_assert(std::is_same_v<ReturnType<decltype(l3)>, void>);
-  static_assert(SignatureOfT<decltype(l1)>::parameter_count == 1);
-  static_assert(SignatureOfT<decltype(l3)>::parameter_count == 3);
+    auto l1 = [](S) {};
+    auto l3 = [](int, S, float) {};
+    static_assert(std::is_same_v<ParameterType<decltype(l1), 0>, S>);
+    static_assert(std::is_same_v<ParameterType<decltype(l3), 0>, int>);
+    static_assert(std::is_same_v<ParameterType<decltype(l3), 1>, S>);
+    static_assert(std::is_same_v<ParameterType<decltype(l3), 2>, float>);
+    static_assert(std::is_same_v<ReturnType<decltype(l1)>, void>);
+    static_assert(std::is_same_v<ReturnType<decltype(l3)>, void>);
+    static_assert(SignatureOfT<decltype(l1)>::parameter_count == 1);
+    static_assert(SignatureOfT<decltype(l3)>::parameter_count == 3);
 }
 
 TEST(Slice, Empty) {
-  auto sliced = Slice<0, 0>(std::make_tuple<>());
-  static_assert(std::tuple_size_v<decltype(sliced)> == 0);
+    auto sliced = Slice<0, 0>(std::make_tuple<>());
+    static_assert(std::tuple_size_v<decltype(sliced)> == 0);
 }
 
 TEST(Slice, SingleElementSliceEmpty) {
-  auto sliced = Slice<0, 0>(std::make_tuple<int>(1));
-  static_assert(std::tuple_size_v<decltype(sliced)> == 0);
+    auto sliced = Slice<0, 0>(std::make_tuple<int>(1));
+    static_assert(std::tuple_size_v<decltype(sliced)> == 0);
 }
 
 TEST(Slice, SingleElementSliceFull) {
-  auto sliced = Slice<0, 1>(std::make_tuple<int>(1));
-  static_assert(std::tuple_size_v<decltype(sliced)> == 1);
-  static_assert(std::is_same_v<std::tuple_element_t<0, decltype(sliced)>, int>,
-                "");
-  EXPECT_EQ(std::get<0>(sliced), 1);
+    auto sliced = Slice<0, 1>(std::make_tuple<int>(1));
+    static_assert(std::tuple_size_v<decltype(sliced)> == 1);
+    static_assert(std::is_same_v<std::tuple_element_t<0, decltype(sliced)>, int>, "");
+    EXPECT_EQ(std::get<0>(sliced), 1);
 }
 
 TEST(Slice, MixedTupleSliceEmpty) {
-  auto sliced = Slice<1, 0>(std::make_tuple<int, bool, float>(1, true, 2.0f));
-  static_assert(std::tuple_size_v<decltype(sliced)> == 0);
+    auto sliced = Slice<1, 0>(std::make_tuple<int, bool, float>(1, true, 2.0f));
+    static_assert(std::tuple_size_v<decltype(sliced)> == 0);
 }
 
 TEST(Slice, MixedTupleSliceFull) {
-  auto sliced = Slice<0, 3>(std::make_tuple<int, bool, float>(1, true, 2.0f));
-  static_assert(std::tuple_size_v<decltype(sliced)> == 3);
-  static_assert(std::is_same_v<std::tuple_element_t<0, decltype(sliced)>, int>,
-                "");
-  static_assert(std::is_same_v<std::tuple_element_t<1, decltype(sliced)>, bool>,
-                "");
-  static_assert(
-      std::is_same_v<std::tuple_element_t<2, decltype(sliced)>, float>);
-  EXPECT_EQ(std::get<0>(sliced), 1);
-  EXPECT_EQ(std::get<1>(sliced), true);
-  EXPECT_EQ(std::get<2>(sliced), 2.0f);
+    auto sliced = Slice<0, 3>(std::make_tuple<int, bool, float>(1, true, 2.0f));
+    static_assert(std::tuple_size_v<decltype(sliced)> == 3);
+    static_assert(std::is_same_v<std::tuple_element_t<0, decltype(sliced)>, int>, "");
+    static_assert(std::is_same_v<std::tuple_element_t<1, decltype(sliced)>, bool>, "");
+    static_assert(std::is_same_v<std::tuple_element_t<2, decltype(sliced)>, float>);
+    EXPECT_EQ(std::get<0>(sliced), 1);
+    EXPECT_EQ(std::get<1>(sliced), true);
+    EXPECT_EQ(std::get<2>(sliced), 2.0f);
 }
 
 TEST(Slice, MixedTupleSliceLowPart) {
-  auto sliced = Slice<0, 2>(std::make_tuple<int, bool, float>(1, true, 2.0f));
-  static_assert(std::tuple_size_v<decltype(sliced)> == 2);
-  static_assert(std::is_same_v<std::tuple_element_t<0, decltype(sliced)>, int>,
-                "");
-  static_assert(std::is_same_v<std::tuple_element_t<1, decltype(sliced)>, bool>,
-                "");
-  EXPECT_EQ(std::get<0>(sliced), 1);
-  EXPECT_EQ(std::get<1>(sliced), true);
+    auto sliced = Slice<0, 2>(std::make_tuple<int, bool, float>(1, true, 2.0f));
+    static_assert(std::tuple_size_v<decltype(sliced)> == 2);
+    static_assert(std::is_same_v<std::tuple_element_t<0, decltype(sliced)>, int>, "");
+    static_assert(std::is_same_v<std::tuple_element_t<1, decltype(sliced)>, bool>, "");
+    EXPECT_EQ(std::get<0>(sliced), 1);
+    EXPECT_EQ(std::get<1>(sliced), true);
 }
 
 TEST(Slice, MixedTupleSliceHighPart) {
-  auto sliced = Slice<1, 2>(std::make_tuple<int, bool, float>(1, true, 2.0f));
-  static_assert(std::tuple_size_v<decltype(sliced)> == 2);
-  static_assert(std::is_same_v<std::tuple_element_t<0, decltype(sliced)>, bool>,
-                "");
-  static_assert(
-      std::is_same_v<std::tuple_element_t<1, decltype(sliced)>, float>);
-  EXPECT_EQ(std::get<0>(sliced), true);
-  EXPECT_EQ(std::get<1>(sliced), 2.0f);
+    auto sliced = Slice<1, 2>(std::make_tuple<int, bool, float>(1, true, 2.0f));
+    static_assert(std::tuple_size_v<decltype(sliced)> == 2);
+    static_assert(std::is_same_v<std::tuple_element_t<0, decltype(sliced)>, bool>, "");
+    static_assert(std::is_same_v<std::tuple_element_t<1, decltype(sliced)>, float>);
+    EXPECT_EQ(std::get<0>(sliced), true);
+    EXPECT_EQ(std::get<1>(sliced), 2.0f);
 }
 
 TEST(Slice, PreservesRValueRef) {
-  int i;
-  int& int_ref = i;
-  auto tuple = std::forward_as_tuple(std::move(int_ref));
-  static_assert(std::is_same_v<int&&,  //
-                               std::tuple_element_t<0, decltype(tuple)>>);
-  auto sliced = Slice<0, 1>(std::move(tuple));
-  static_assert(std::is_same_v<int&&,  //
-                               std::tuple_element_t<0, decltype(sliced)>>);
+    int i;
+    int& int_ref = i;
+    auto tuple = std::forward_as_tuple(std::move(int_ref));
+    static_assert(std::is_same_v<int&&,  //
+                                 std::tuple_element_t<0, decltype(tuple)>>);
+    auto sliced = Slice<0, 1>(std::move(tuple));
+    static_assert(std::is_same_v<int&&,  //
+                                 std::tuple_element_t<0, decltype(sliced)>>);
 }
 
 TEST(SliceTuple, Empty) {
-  using sliced = SliceTuple<0, 0, std::tuple<>>;
-  static_assert(std::tuple_size_v<sliced> == 0);
+    using sliced = SliceTuple<0, 0, std::tuple<>>;
+    static_assert(std::tuple_size_v<sliced> == 0);
 }
 
 TEST(SliceTuple, SingleElementSliceEmpty) {
-  using sliced = SliceTuple<0, 0, std::tuple<int>>;
-  static_assert(std::tuple_size_v<sliced> == 0);
+    using sliced = SliceTuple<0, 0, std::tuple<int>>;
+    static_assert(std::tuple_size_v<sliced> == 0);
 }
 
 TEST(SliceTuple, SingleElementSliceFull) {
-  using sliced = SliceTuple<0, 1, std::tuple<int>>;
-  static_assert(std::tuple_size_v<sliced> == 1);
-  static_assert(std::is_same_v<std::tuple_element_t<0, sliced>, int>);
+    using sliced = SliceTuple<0, 1, std::tuple<int>>;
+    static_assert(std::tuple_size_v<sliced> == 1);
+    static_assert(std::is_same_v<std::tuple_element_t<0, sliced>, int>);
 }
 
 TEST(SliceTuple, MixedTupleSliceEmpty) {
-  using sliced = SliceTuple<1, 0, std::tuple<int, bool, float>>;
-  static_assert(std::tuple_size_v<sliced> == 0);
+    using sliced = SliceTuple<1, 0, std::tuple<int, bool, float>>;
+    static_assert(std::tuple_size_v<sliced> == 0);
 }
 
 TEST(SliceTuple, MixedTupleSliceFull) {
-  using sliced = SliceTuple<0, 3, std::tuple<int, bool, float>>;
-  static_assert(std::tuple_size_v<sliced> == 3);
-  static_assert(std::is_same_v<std::tuple_element_t<0, sliced>, int>);
-  static_assert(std::is_same_v<std::tuple_element_t<1, sliced>, bool>);
-  static_assert(std::is_same_v<std::tuple_element_t<2, sliced>, float>);
+    using sliced = SliceTuple<0, 3, std::tuple<int, bool, float>>;
+    static_assert(std::tuple_size_v<sliced> == 3);
+    static_assert(std::is_same_v<std::tuple_element_t<0, sliced>, int>);
+    static_assert(std::is_same_v<std::tuple_element_t<1, sliced>, bool>);
+    static_assert(std::is_same_v<std::tuple_element_t<2, sliced>, float>);
 }
 
 TEST(SliceTuple, MixedTupleSliceLowPart) {
-  using sliced = SliceTuple<0, 2, std::tuple<int, bool, float>>;
-  static_assert(std::tuple_size_v<sliced> == 2);
-  static_assert(std::is_same_v<std::tuple_element_t<0, sliced>, int>);
-  static_assert(std::is_same_v<std::tuple_element_t<1, sliced>, bool>);
+    using sliced = SliceTuple<0, 2, std::tuple<int, bool, float>>;
+    static_assert(std::tuple_size_v<sliced> == 2);
+    static_assert(std::is_same_v<std::tuple_element_t<0, sliced>, int>);
+    static_assert(std::is_same_v<std::tuple_element_t<1, sliced>, bool>);
 }
 
 TEST(SliceTuple, MixedTupleSliceHighPart) {
-  using sliced = SliceTuple<1, 2, std::tuple<int, bool, float>>;
-  static_assert(std::tuple_size_v<sliced> == 2);
-  static_assert(std::is_same_v<std::tuple_element_t<0, sliced>, bool>);
-  static_assert(std::is_same_v<std::tuple_element_t<1, sliced>, float>);
+    using sliced = SliceTuple<1, 2, std::tuple<int, bool, float>>;
+    static_assert(std::tuple_size_v<sliced> == 2);
+    static_assert(std::is_same_v<std::tuple_element_t<0, sliced>, bool>);
+    static_assert(std::is_same_v<std::tuple_element_t<1, sliced>, float>);
 }
 
 }  // namespace tint::traits
diff --git a/src/tint/transform/add_empty_entry_point.cc b/src/tint/transform/add_empty_entry_point.cc
index 0710d2b..f037649 100644
--- a/src/tint/transform/add_empty_entry_point.cc
+++ b/src/tint/transform/add_empty_entry_point.cc
@@ -20,30 +20,27 @@
 
 TINT_INSTANTIATE_TYPEINFO(tint::transform::AddEmptyEntryPoint);
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::transform {
 
 AddEmptyEntryPoint::AddEmptyEntryPoint() = default;
 
 AddEmptyEntryPoint::~AddEmptyEntryPoint() = default;
 
-bool AddEmptyEntryPoint::ShouldRun(const Program* program,
-                                   const DataMap&) const {
-  for (auto* func : program->AST().Functions()) {
-    if (func->IsEntryPoint()) {
-      return false;
+bool AddEmptyEntryPoint::ShouldRun(const Program* program, const DataMap&) const {
+    for (auto* func : program->AST().Functions()) {
+        if (func->IsEntryPoint()) {
+            return false;
+        }
     }
-  }
-  return true;
+    return true;
 }
 
-void AddEmptyEntryPoint::Run(CloneContext& ctx,
-                             const DataMap&,
-                             DataMap&) const {
-  ctx.dst->Func(ctx.dst->Symbols().New("unused_entry_point"), {},
-                ctx.dst->ty.void_(), {},
-                {ctx.dst->Stage(ast::PipelineStage::kCompute),
-                 ctx.dst->WorkgroupSize(1)});
-  ctx.Clone();
+void AddEmptyEntryPoint::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
+    ctx.dst->Func(ctx.dst->Symbols().New("unused_entry_point"), {}, ctx.dst->ty.void_(), {},
+                  {ctx.dst->Stage(ast::PipelineStage::kCompute), ctx.dst->WorkgroupSize(1_i)});
+    ctx.Clone();
 }
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/add_empty_entry_point.h b/src/tint/transform/add_empty_entry_point.h
index eb9dccd..5530355 100644
--- a/src/tint/transform/add_empty_entry_point.h
+++ b/src/tint/transform/add_empty_entry_point.h
@@ -20,30 +20,26 @@
 namespace tint::transform {
 
 /// Add an empty entry point to the module, if no other entry points exist.
-class AddEmptyEntryPoint final
-    : public Castable<AddEmptyEntryPoint, Transform> {
- public:
-  /// Constructor
-  AddEmptyEntryPoint();
-  /// Destructor
-  ~AddEmptyEntryPoint() override;
+class AddEmptyEntryPoint final : public Castable<AddEmptyEntryPoint, Transform> {
+  public:
+    /// Constructor
+    AddEmptyEntryPoint();
+    /// Destructor
+    ~AddEmptyEntryPoint() override;
 
-  /// @param program the program to inspect
-  /// @param data optional extra transform-specific input data
-  /// @returns true if this transform should be run for the given program
-  bool ShouldRun(const Program* program,
-                 const DataMap& data = {}) const override;
+    /// @param program the program to inspect
+    /// @param data optional extra transform-specific input data
+    /// @returns true if this transform should be run for the given program
+    bool ShouldRun(const Program* program, const DataMap& data = {}) const override;
 
- protected:
-  /// Runs the transform using the CloneContext built for transforming a
-  /// program. Run() is responsible for calling Clone() on the CloneContext.
-  /// @param ctx the CloneContext primed with the input program and
-  /// ProgramBuilder
-  /// @param inputs optional extra transform-specific input data
-  /// @param outputs optional extra transform-specific output data
-  void Run(CloneContext& ctx,
-           const DataMap& inputs,
-           DataMap& outputs) const override;
+  protected:
+    /// Runs the transform using the CloneContext built for transforming a
+    /// program. Run() is responsible for calling Clone() on the CloneContext.
+    /// @param ctx the CloneContext primed with the input program and
+    /// ProgramBuilder
+    /// @param inputs optional extra transform-specific input data
+    /// @param outputs optional extra transform-specific output data
+    void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const override;
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/add_empty_entry_point_test.cc b/src/tint/transform/add_empty_entry_point_test.cc
index 0854251..2f8a7ad 100644
--- a/src/tint/transform/add_empty_entry_point_test.cc
+++ b/src/tint/transform/add_empty_entry_point_test.cc
@@ -24,62 +24,62 @@
 using AddEmptyEntryPointTest = TransformTest;
 
 TEST_F(AddEmptyEntryPointTest, ShouldRunEmptyModule) {
-  auto* src = R"()";
+    auto* src = R"()";
 
-  EXPECT_TRUE(ShouldRun<AddEmptyEntryPoint>(src));
+    EXPECT_TRUE(ShouldRun<AddEmptyEntryPoint>(src));
 }
 
 TEST_F(AddEmptyEntryPointTest, ShouldRunExistingEntryPoint) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn existing() {}
 )";
 
-  EXPECT_FALSE(ShouldRun<AddEmptyEntryPoint>(src));
+    EXPECT_FALSE(ShouldRun<AddEmptyEntryPoint>(src));
 }
 
 TEST_F(AddEmptyEntryPointTest, EmptyModule) {
-  auto* src = R"()";
+    auto* src = R"()";
 
-  auto* expect = R"(
-@stage(compute) @workgroup_size(1)
+    auto* expect = R"(
+@stage(compute) @workgroup_size(1i)
 fn unused_entry_point() {
 }
 )";
 
-  auto got = Run<AddEmptyEntryPoint>(src);
+    auto got = Run<AddEmptyEntryPoint>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(AddEmptyEntryPointTest, ExistingEntryPoint) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(fragment)
 fn main() {
 }
 )";
 
-  auto* expect = src;
+    auto* expect = src;
 
-  auto got = Run<AddEmptyEntryPoint>(src);
+    auto got = Run<AddEmptyEntryPoint>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(AddEmptyEntryPointTest, NameClash) {
-  auto* src = R"(var<private> unused_entry_point : f32;)";
+    auto* src = R"(var<private> unused_entry_point : f32;)";
 
-  auto* expect = R"(
-@stage(compute) @workgroup_size(1)
+    auto* expect = R"(
+@stage(compute) @workgroup_size(1i)
 fn unused_entry_point_1() {
 }
 
 var<private> unused_entry_point : f32;
 )";
 
-  auto got = Run<AddEmptyEntryPoint>(src);
+    auto got = Run<AddEmptyEntryPoint>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 }  // namespace
diff --git a/src/tint/transform/add_spirv_block_attribute.cc b/src/tint/transform/add_spirv_block_attribute.cc
index 91ab991..38e0de6 100644
--- a/src/tint/transform/add_spirv_block_attribute.cc
+++ b/src/tint/transform/add_spirv_block_attribute.cc
@@ -23,8 +23,7 @@
 #include "src/tint/utils/map.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::transform::AddSpirvBlockAttribute);
-TINT_INSTANTIATE_TYPEINFO(
-    tint::transform::AddSpirvBlockAttribute::SpirvBlockAttribute);
+TINT_INSTANTIATE_TYPEINFO(tint::transform::AddSpirvBlockAttribute::SpirvBlockAttribute);
 
 namespace tint::transform {
 
@@ -32,89 +31,81 @@
 
 AddSpirvBlockAttribute::~AddSpirvBlockAttribute() = default;
 
-void AddSpirvBlockAttribute::Run(CloneContext& ctx,
-                                 const DataMap&,
-                                 DataMap&) const {
-  auto& sem = ctx.src->Sem();
+void AddSpirvBlockAttribute::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
+    auto& sem = ctx.src->Sem();
 
-  // Collect the set of structs that are nested in other types.
-  std::unordered_set<const sem::Struct*> nested_structs;
-  for (auto* node : ctx.src->ASTNodes().Objects()) {
-    if (auto* arr = sem.Get<sem::Array>(node->As<ast::Array>())) {
-      if (auto* nested_str = arr->ElemType()->As<sem::Struct>()) {
-        nested_structs.insert(nested_str);
-      }
-    } else if (auto* str = sem.Get<sem::Struct>(node->As<ast::Struct>())) {
-      for (auto* member : str->Members()) {
-        if (auto* nested_str = member->Type()->As<sem::Struct>()) {
-          nested_structs.insert(nested_str);
+    // Collect the set of structs that are nested in other types.
+    std::unordered_set<const sem::Struct*> nested_structs;
+    for (auto* node : ctx.src->ASTNodes().Objects()) {
+        if (auto* arr = sem.Get<sem::Array>(node->As<ast::Array>())) {
+            if (auto* nested_str = arr->ElemType()->As<sem::Struct>()) {
+                nested_structs.insert(nested_str);
+            }
+        } else if (auto* str = sem.Get<sem::Struct>(node->As<ast::Struct>())) {
+            for (auto* member : str->Members()) {
+                if (auto* nested_str = member->Type()->As<sem::Struct>()) {
+                    nested_structs.insert(nested_str);
+                }
+            }
         }
-      }
-    }
-  }
-
-  // A map from a type in the source program to a block-decorated wrapper that
-  // contains it in the destination program.
-  std::unordered_map<const sem::Type*, const ast::Struct*> wrapper_structs;
-
-  // Process global variables that are buffers.
-  for (auto* var : ctx.src->AST().GlobalVariables()) {
-    auto* sem_var = sem.Get<sem::GlobalVariable>(var);
-    if (var->declared_storage_class != ast::StorageClass::kStorage &&
-        var->declared_storage_class != ast::StorageClass::kUniform) {
-      continue;
     }
 
-    auto* ty = sem.Get(var->type);
-    auto* str = ty->As<sem::Struct>();
-    if (!str || nested_structs.count(str)) {
-      const char* kMemberName = "inner";
+    // A map from a type in the source program to a block-decorated wrapper that
+    // contains it in the destination program.
+    std::unordered_map<const sem::Type*, const ast::Struct*> wrapper_structs;
 
-      // This is a non-struct or a struct that is nested somewhere else, so we
-      // need to wrap it first.
-      auto* wrapper = utils::GetOrCreate(wrapper_structs, ty, [&]() {
-        auto* block =
-            ctx.dst->ASTNodes().Create<SpirvBlockAttribute>(ctx.dst->ID());
-        auto wrapper_name = ctx.src->Symbols().NameFor(var->symbol) + "_block";
-        auto* ret = ctx.dst->create<ast::Struct>(
-            ctx.dst->Symbols().New(wrapper_name),
-            ast::StructMemberList{
-                ctx.dst->Member(kMemberName, CreateASTTypeFor(ctx, ty))},
-            ast::AttributeList{block});
-        ctx.InsertBefore(ctx.src->AST().GlobalDeclarations(), var, ret);
-        return ret;
-      });
-      ctx.Replace(var->type, ctx.dst->ty.Of(wrapper));
+    // Process global variables that are buffers.
+    for (auto* var : ctx.src->AST().GlobalVariables()) {
+        auto* sem_var = sem.Get<sem::GlobalVariable>(var);
+        if (var->declared_storage_class != ast::StorageClass::kStorage &&
+            var->declared_storage_class != ast::StorageClass::kUniform) {
+            continue;
+        }
 
-      // Insert a member accessor to get the original type from the wrapper at
-      // any usage of the original variable.
-      for (auto* user : sem_var->Users()) {
-        ctx.Replace(
-            user->Declaration(),
-            ctx.dst->MemberAccessor(ctx.Clone(var->symbol), kMemberName));
-      }
-    } else {
-      // Add a block attribute to this struct directly.
-      auto* block =
-          ctx.dst->ASTNodes().Create<SpirvBlockAttribute>(ctx.dst->ID());
-      ctx.InsertFront(str->Declaration()->attributes, block);
+        auto* ty = sem.Get(var->type);
+        auto* str = ty->As<sem::Struct>();
+        if (!str || nested_structs.count(str)) {
+            const char* kMemberName = "inner";
+
+            // This is a non-struct or a struct that is nested somewhere else, so we
+            // need to wrap it first.
+            auto* wrapper = utils::GetOrCreate(wrapper_structs, ty, [&]() {
+                auto* block = ctx.dst->ASTNodes().Create<SpirvBlockAttribute>(ctx.dst->ID());
+                auto wrapper_name = ctx.src->Symbols().NameFor(var->symbol) + "_block";
+                auto* ret = ctx.dst->create<ast::Struct>(
+                    ctx.dst->Symbols().New(wrapper_name),
+                    ast::StructMemberList{ctx.dst->Member(kMemberName, CreateASTTypeFor(ctx, ty))},
+                    ast::AttributeList{block});
+                ctx.InsertBefore(ctx.src->AST().GlobalDeclarations(), var, ret);
+                return ret;
+            });
+            ctx.Replace(var->type, ctx.dst->ty.Of(wrapper));
+
+            // Insert a member accessor to get the original type from the wrapper at
+            // any usage of the original variable.
+            for (auto* user : sem_var->Users()) {
+                ctx.Replace(user->Declaration(),
+                            ctx.dst->MemberAccessor(ctx.Clone(var->symbol), kMemberName));
+            }
+        } else {
+            // Add a block attribute to this struct directly.
+            auto* block = ctx.dst->ASTNodes().Create<SpirvBlockAttribute>(ctx.dst->ID());
+            ctx.InsertFront(str->Declaration()->attributes, block);
+        }
     }
-  }
 
-  ctx.Clone();
+    ctx.Clone();
 }
 
-AddSpirvBlockAttribute::SpirvBlockAttribute::SpirvBlockAttribute(ProgramID pid)
-    : Base(pid) {}
+AddSpirvBlockAttribute::SpirvBlockAttribute::SpirvBlockAttribute(ProgramID pid) : Base(pid) {}
 AddSpirvBlockAttribute::SpirvBlockAttribute::~SpirvBlockAttribute() = default;
 std::string AddSpirvBlockAttribute::SpirvBlockAttribute::InternalName() const {
-  return "spirv_block";
+    return "spirv_block";
 }
 
 const AddSpirvBlockAttribute::SpirvBlockAttribute*
 AddSpirvBlockAttribute::SpirvBlockAttribute::Clone(CloneContext* ctx) const {
-  return ctx->dst->ASTNodes()
-      .Create<AddSpirvBlockAttribute::SpirvBlockAttribute>(ctx->dst->ID());
+    return ctx->dst->ASTNodes().Create<AddSpirvBlockAttribute::SpirvBlockAttribute>(ctx->dst->ID());
 }
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/add_spirv_block_attribute.h b/src/tint/transform/add_spirv_block_attribute.h
index 386a341..67faaa5 100644
--- a/src/tint/transform/add_spirv_block_attribute.h
+++ b/src/tint/transform/add_spirv_block_attribute.h
@@ -27,46 +27,42 @@
 /// store type of a buffer. If that structure is nested inside another structure
 /// or an array, then it is wrapped inside another structure which gets the
 /// `@internal(spirv_block)` attribute instead.
-class AddSpirvBlockAttribute final
-    : public Castable<AddSpirvBlockAttribute, Transform> {
- public:
-  /// SpirvBlockAttribute is an InternalAttribute that is used to decorate a
-  // structure that needs a SPIR-V block attribute.
-  class SpirvBlockAttribute final
-      : public Castable<SpirvBlockAttribute, ast::InternalAttribute> {
-   public:
+class AddSpirvBlockAttribute final : public Castable<AddSpirvBlockAttribute, Transform> {
+  public:
+    /// SpirvBlockAttribute is an InternalAttribute that is used to decorate a
+    // structure that needs a SPIR-V block attribute.
+    class SpirvBlockAttribute final : public Castable<SpirvBlockAttribute, ast::InternalAttribute> {
+      public:
+        /// Constructor
+        /// @param program_id the identifier of the program that owns this node
+        explicit SpirvBlockAttribute(ProgramID program_id);
+        /// Destructor
+        ~SpirvBlockAttribute() override;
+
+        /// @return a short description of the internal attribute which will be
+        /// displayed as `@internal(<name>)`
+        std::string InternalName() const override;
+
+        /// Performs a deep clone of this object using the CloneContext `ctx`.
+        /// @param ctx the clone context
+        /// @return the newly cloned object
+        const SpirvBlockAttribute* Clone(CloneContext* ctx) const override;
+    };
+
     /// Constructor
-    /// @param program_id the identifier of the program that owns this node
-    explicit SpirvBlockAttribute(ProgramID program_id);
+    AddSpirvBlockAttribute();
+
     /// Destructor
-    ~SpirvBlockAttribute() override;
+    ~AddSpirvBlockAttribute() override;
 
-    /// @return a short description of the internal attribute which will be
-    /// displayed as `@internal(<name>)`
-    std::string InternalName() const override;
-
-    /// Performs a deep clone of this object using the CloneContext `ctx`.
-    /// @param ctx the clone context
-    /// @return the newly cloned object
-    const SpirvBlockAttribute* Clone(CloneContext* ctx) const override;
-  };
-
-  /// Constructor
-  AddSpirvBlockAttribute();
-
-  /// Destructor
-  ~AddSpirvBlockAttribute() override;
-
- protected:
-  /// Runs the transform using the CloneContext built for transforming a
-  /// program. Run() is responsible for calling Clone() on the CloneContext.
-  /// @param ctx the CloneContext primed with the input program and
-  /// ProgramBuilder
-  /// @param inputs optional extra transform-specific input data
-  /// @param outputs optional extra transform-specific output data
-  void Run(CloneContext& ctx,
-           const DataMap& inputs,
-           DataMap& outputs) const override;
+  protected:
+    /// Runs the transform using the CloneContext built for transforming a
+    /// program. Run() is responsible for calling Clone() on the CloneContext.
+    /// @param ctx the CloneContext primed with the input program and
+    /// ProgramBuilder
+    /// @param inputs optional extra transform-specific input data
+    /// @param outputs optional extra transform-specific output data
+    void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const override;
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/add_spirv_block_attribute_test.cc b/src/tint/transform/add_spirv_block_attribute_test.cc
index b68920c..14ba929 100644
--- a/src/tint/transform/add_spirv_block_attribute_test.cc
+++ b/src/tint/transform/add_spirv_block_attribute_test.cc
@@ -25,16 +25,16 @@
 using AddSpirvBlockAttributeTest = TransformTest;
 
 TEST_F(AddSpirvBlockAttributeTest, EmptyModule) {
-  auto* src = "";
-  auto* expect = "";
+    auto* src = "";
+    auto* expect = "";
 
-  auto got = Run<AddSpirvBlockAttribute>(src);
+    auto got = Run<AddSpirvBlockAttribute>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(AddSpirvBlockAttributeTest, Noop_UsedForPrivateVar) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   f : f32,
 }
@@ -46,15 +46,15 @@
   p.f = 1.0;
 }
 )";
-  auto* expect = src;
+    auto* expect = src;
 
-  auto got = Run<AddSpirvBlockAttribute>(src);
+    auto got = Run<AddSpirvBlockAttribute>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(AddSpirvBlockAttributeTest, Noop_UsedForShaderIO) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   @location(0)
   f : f32,
@@ -65,15 +65,15 @@
   return S();
 }
 )";
-  auto* expect = src;
+    auto* expect = src;
 
-  auto got = Run<AddSpirvBlockAttribute>(src);
+    auto got = Run<AddSpirvBlockAttribute>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(AddSpirvBlockAttributeTest, BasicScalar) {
-  auto* src = R"(
+    auto* src = R"(
 @group(0) @binding(0)
 var<uniform> u : f32;
 
@@ -82,7 +82,7 @@
   let f = u;
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 @internal(spirv_block)
 struct u_block {
   inner : f32,
@@ -96,13 +96,13 @@
 }
 )";
 
-  auto got = Run<AddSpirvBlockAttribute>(src);
+    auto got = Run<AddSpirvBlockAttribute>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(AddSpirvBlockAttributeTest, BasicArray) {
-  auto* src = R"(
+    auto* src = R"(
 @group(0) @binding(0)
 var<uniform> u : array<vec4<f32>, 4u>;
 
@@ -111,7 +111,7 @@
   let a = u;
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 @internal(spirv_block)
 struct u_block {
   inner : array<vec4<f32>, 4u>,
@@ -125,13 +125,13 @@
 }
 )";
 
-  auto got = Run<AddSpirvBlockAttribute>(src);
+    auto got = Run<AddSpirvBlockAttribute>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(AddSpirvBlockAttributeTest, BasicArray_Alias) {
-  auto* src = R"(
+    auto* src = R"(
 type Numbers = array<vec4<f32>, 4u>;
 
 @group(0) @binding(0)
@@ -142,7 +142,7 @@
   let a = u;
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 type Numbers = array<vec4<f32>, 4u>;
 
 @internal(spirv_block)
@@ -158,13 +158,13 @@
 }
 )";
 
-  auto got = Run<AddSpirvBlockAttribute>(src);
+    auto got = Run<AddSpirvBlockAttribute>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(AddSpirvBlockAttributeTest, BasicStruct) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   f : f32,
 };
@@ -177,7 +177,7 @@
   let f = u.f;
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 @internal(spirv_block)
 struct S {
   f : f32,
@@ -191,13 +191,13 @@
 }
 )";
 
-  auto got = Run<AddSpirvBlockAttribute>(src);
+    auto got = Run<AddSpirvBlockAttribute>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(AddSpirvBlockAttributeTest, Nested_OuterBuffer_InnerNotBuffer) {
-  auto* src = R"(
+    auto* src = R"(
 struct Inner {
   f : f32,
 };
@@ -214,7 +214,7 @@
   let f = u.i.f;
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 struct Inner {
   f : f32,
 }
@@ -232,13 +232,13 @@
 }
 )";
 
-  auto got = Run<AddSpirvBlockAttribute>(src);
+    auto got = Run<AddSpirvBlockAttribute>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(AddSpirvBlockAttributeTest, Nested_OuterBuffer_InnerBuffer) {
-  auto* src = R"(
+    auto* src = R"(
 struct Inner {
   f : f32,
 };
@@ -259,7 +259,7 @@
   let f1 = u1.f;
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 struct Inner {
   f : f32,
 }
@@ -285,13 +285,13 @@
 }
 )";
 
-  auto got = Run<AddSpirvBlockAttribute>(src);
+    auto got = Run<AddSpirvBlockAttribute>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(AddSpirvBlockAttributeTest, Nested_OuterNotBuffer_InnerBuffer) {
-  auto* src = R"(
+    auto* src = R"(
 struct Inner {
   f : f32,
 };
@@ -311,7 +311,7 @@
   let f1 = u.f;
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 struct Inner {
   f : f32,
 }
@@ -336,13 +336,13 @@
 }
 )";
 
-  auto got = Run<AddSpirvBlockAttribute>(src);
+    auto got = Run<AddSpirvBlockAttribute>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(AddSpirvBlockAttributeTest, Nested_InnerUsedForMultipleBuffers) {
-  auto* src = R"(
+    auto* src = R"(
 struct Inner {
   f : f32,
 };
@@ -367,7 +367,7 @@
   let f2 = u2.f;
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 struct Inner {
   f : f32,
 }
@@ -396,13 +396,13 @@
 }
 )";
 
-  auto got = Run<AddSpirvBlockAttribute>(src);
+    auto got = Run<AddSpirvBlockAttribute>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(AddSpirvBlockAttributeTest, StructInArray) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   f : f32,
 };
@@ -416,7 +416,7 @@
   let a = array<S, 4>();
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   f : f32,
 }
@@ -435,13 +435,13 @@
 }
 )";
 
-  auto got = Run<AddSpirvBlockAttribute>(src);
+    auto got = Run<AddSpirvBlockAttribute>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(AddSpirvBlockAttributeTest, StructInArray_MultipleBuffers) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   f : f32,
 };
@@ -459,7 +459,7 @@
   let a = array<S, 4>();
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   f : f32,
 }
@@ -481,13 +481,13 @@
 }
 )";
 
-  auto got = Run<AddSpirvBlockAttribute>(src);
+    auto got = Run<AddSpirvBlockAttribute>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(AddSpirvBlockAttributeTest, Aliases_Nested_OuterBuffer_InnerBuffer) {
-  auto* src = R"(
+    auto* src = R"(
 struct Inner {
   f : f32,
 };
@@ -512,7 +512,7 @@
   let f1 = u1.f;
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 struct Inner {
   f : f32,
 }
@@ -542,14 +542,13 @@
 }
 )";
 
-  auto got = Run<AddSpirvBlockAttribute>(src);
+    auto got = Run<AddSpirvBlockAttribute>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(AddSpirvBlockAttributeTest,
-       Aliases_Nested_OuterBuffer_InnerBuffer_OutOfOrder) {
-  auto* src = R"(
+TEST_F(AddSpirvBlockAttributeTest, Aliases_Nested_OuterBuffer_InnerBuffer_OutOfOrder) {
+    auto* src = R"(
 @stage(fragment)
 fn main() {
   let f0 = u0.i.f;
@@ -574,7 +573,7 @@
   f : f32,
 };
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 @stage(fragment)
 fn main() {
   let f0 = u0.i.f;
@@ -604,9 +603,9 @@
 }
 )";
 
-  auto got = Run<AddSpirvBlockAttribute>(src);
+    auto got = Run<AddSpirvBlockAttribute>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 }  // namespace
diff --git a/src/tint/transform/array_length_from_uniform.cc b/src/tint/transform/array_length_from_uniform.cc
index 52c68f2..dc19c5c 100644
--- a/src/tint/transform/array_length_from_uniform.cc
+++ b/src/tint/transform/array_length_from_uniform.cc
@@ -43,132 +43,124 @@
 /// sem::GlobalVariable for the storage buffer.
 template <typename F>
 static void IterateArrayLengthOnStorageVar(CloneContext& ctx, F&& functor) {
-  auto& sem = ctx.src->Sem();
+    auto& sem = ctx.src->Sem();
 
-  // Find all calls to the arrayLength() builtin.
-  for (auto* node : ctx.src->ASTNodes().Objects()) {
-    auto* call_expr = node->As<ast::CallExpression>();
-    if (!call_expr) {
-      continue;
-    }
-
-    auto* call = sem.Get(call_expr);
-    auto* builtin = call->Target()->As<sem::Builtin>();
-    if (!builtin || builtin->Type() != sem::BuiltinType::kArrayLength) {
-      continue;
-    }
-
-    // Get the storage buffer that contains the runtime array.
-    // Since we require SimplifyPointers, we can assume that the arrayLength()
-    // call has one of two forms:
-    //   arrayLength(&struct_var.array_member)
-    //   arrayLength(&array_var)
-    auto* param = call_expr->args[0]->As<ast::UnaryOpExpression>();
-    if (!param || param->op != ast::UnaryOp::kAddressOf) {
-      TINT_ICE(Transform, ctx.dst->Diagnostics())
-          << "expected form of arrayLength argument to be &array_var or "
-             "&struct_var.array_member";
-      break;
-    }
-    auto* storage_buffer_expr = param->expr;
-    if (auto* accessor = param->expr->As<ast::MemberAccessorExpression>()) {
-      storage_buffer_expr = accessor->structure;
-    }
-    auto* storage_buffer_sem = sem.Get<sem::VariableUser>(storage_buffer_expr);
-    if (!storage_buffer_sem) {
-      TINT_ICE(Transform, ctx.dst->Diagnostics())
-          << "expected form of arrayLength argument to be &array_var or "
-             "&struct_var.array_member";
-      break;
-    }
-
-    // Get the index to use for the buffer size array.
-    auto* var = tint::As<sem::GlobalVariable>(storage_buffer_sem->Variable());
-    if (!var) {
-      TINT_ICE(Transform, ctx.dst->Diagnostics())
-          << "storage buffer is not a global variable";
-      break;
-    }
-    functor(call_expr, storage_buffer_sem, var);
-  }
-}
-
-bool ArrayLengthFromUniform::ShouldRun(const Program* program,
-                                       const DataMap&) const {
-  for (auto* fn : program->AST().Functions()) {
-    if (auto* sem_fn = program->Sem().Get(fn)) {
-      for (auto* builtin : sem_fn->DirectlyCalledBuiltins()) {
-        if (builtin->Type() == sem::BuiltinType::kArrayLength) {
-          return true;
+    // Find all calls to the arrayLength() builtin.
+    for (auto* node : ctx.src->ASTNodes().Objects()) {
+        auto* call_expr = node->As<ast::CallExpression>();
+        if (!call_expr) {
+            continue;
         }
-      }
+
+        auto* call = sem.Get(call_expr);
+        auto* builtin = call->Target()->As<sem::Builtin>();
+        if (!builtin || builtin->Type() != sem::BuiltinType::kArrayLength) {
+            continue;
+        }
+
+        // Get the storage buffer that contains the runtime array.
+        // Since we require SimplifyPointers, we can assume that the arrayLength()
+        // call has one of two forms:
+        //   arrayLength(&struct_var.array_member)
+        //   arrayLength(&array_var)
+        auto* param = call_expr->args[0]->As<ast::UnaryOpExpression>();
+        if (!param || param->op != ast::UnaryOp::kAddressOf) {
+            TINT_ICE(Transform, ctx.dst->Diagnostics())
+                << "expected form of arrayLength argument to be &array_var or "
+                   "&struct_var.array_member";
+            break;
+        }
+        auto* storage_buffer_expr = param->expr;
+        if (auto* accessor = param->expr->As<ast::MemberAccessorExpression>()) {
+            storage_buffer_expr = accessor->structure;
+        }
+        auto* storage_buffer_sem = sem.Get<sem::VariableUser>(storage_buffer_expr);
+        if (!storage_buffer_sem) {
+            TINT_ICE(Transform, ctx.dst->Diagnostics())
+                << "expected form of arrayLength argument to be &array_var or "
+                   "&struct_var.array_member";
+            break;
+        }
+
+        // Get the index to use for the buffer size array.
+        auto* var = tint::As<sem::GlobalVariable>(storage_buffer_sem->Variable());
+        if (!var) {
+            TINT_ICE(Transform, ctx.dst->Diagnostics())
+                << "storage buffer is not a global variable";
+            break;
+        }
+        functor(call_expr, storage_buffer_sem, var);
     }
-  }
-  return false;
 }
 
-void ArrayLengthFromUniform::Run(CloneContext& ctx,
-                                 const DataMap& inputs,
-                                 DataMap& outputs) const {
-  auto* cfg = inputs.Get<Config>();
-  if (cfg == nullptr) {
-    ctx.dst->Diagnostics().add_error(
-        diag::System::Transform,
-        "missing transform data for " + std::string(TypeInfo().name));
-    return;
-  }
+bool ArrayLengthFromUniform::ShouldRun(const Program* program, const DataMap&) const {
+    for (auto* fn : program->AST().Functions()) {
+        if (auto* sem_fn = program->Sem().Get(fn)) {
+            for (auto* builtin : sem_fn->DirectlyCalledBuiltins()) {
+                if (builtin->Type() == sem::BuiltinType::kArrayLength) {
+                    return true;
+                }
+            }
+        }
+    }
+    return false;
+}
 
-  const char* kBufferSizeMemberName = "buffer_size";
+void ArrayLengthFromUniform::Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const {
+    auto* cfg = inputs.Get<Config>();
+    if (cfg == nullptr) {
+        ctx.dst->Diagnostics().add_error(
+            diag::System::Transform, "missing transform data for " + std::string(TypeInfo().name));
+        return;
+    }
 
-  // Determine the size of the buffer size array.
-  uint32_t max_buffer_size_index = 0;
+    const char* kBufferSizeMemberName = "buffer_size";
 
-  IterateArrayLengthOnStorageVar(
-      ctx, [&](const ast::CallExpression*, const sem::VariableUser*,
-               const sem::GlobalVariable* var) {
+    // Determine the size of the buffer size array.
+    uint32_t max_buffer_size_index = 0;
+
+    IterateArrayLengthOnStorageVar(ctx, [&](const ast::CallExpression*, const sem::VariableUser*,
+                                            const sem::GlobalVariable* var) {
         auto binding = var->BindingPoint();
         auto idx_itr = cfg->bindpoint_to_size_index.find(binding);
         if (idx_itr == cfg->bindpoint_to_size_index.end()) {
-          return;
+            return;
         }
         if (idx_itr->second > max_buffer_size_index) {
-          max_buffer_size_index = idx_itr->second;
+            max_buffer_size_index = idx_itr->second;
         }
-      });
+    });
 
-  // Get (or create, on first call) the uniform buffer that will receive the
-  // size of each storage buffer in the module.
-  const ast::Variable* buffer_size_ubo = nullptr;
-  auto get_ubo = [&]() {
-    if (!buffer_size_ubo) {
-      // Emit an array<vec4<u32>, N>, where N is 1/4 number of elements.
-      // We do this because UBOs require an element stride that is 16-byte
-      // aligned.
-      auto* buffer_size_struct = ctx.dst->Structure(
-          ctx.dst->Sym(),
-          {ctx.dst->Member(
-              kBufferSizeMemberName,
-              ctx.dst->ty.array(ctx.dst->ty.vec4(ctx.dst->ty.u32()),
-                                (max_buffer_size_index / 4) + 1))});
-      buffer_size_ubo = ctx.dst->Global(
-          ctx.dst->Sym(), ctx.dst->ty.Of(buffer_size_struct),
-          ast::StorageClass::kUniform,
-          ast::AttributeList{ctx.dst->GroupAndBinding(
-              cfg->ubo_binding.group, cfg->ubo_binding.binding)});
-    }
-    return buffer_size_ubo;
-  };
+    // Get (or create, on first call) the uniform buffer that will receive the
+    // size of each storage buffer in the module.
+    const ast::Variable* buffer_size_ubo = nullptr;
+    auto get_ubo = [&]() {
+        if (!buffer_size_ubo) {
+            // Emit an array<vec4<u32>, N>, where N is 1/4 number of elements.
+            // We do this because UBOs require an element stride that is 16-byte
+            // aligned.
+            auto* buffer_size_struct = ctx.dst->Structure(
+                ctx.dst->Sym(),
+                {ctx.dst->Member(kBufferSizeMemberName,
+                                 ctx.dst->ty.array(ctx.dst->ty.vec4(ctx.dst->ty.u32()),
+                                                   u32((max_buffer_size_index / 4) + 1)))});
+            buffer_size_ubo = ctx.dst->Global(
+                ctx.dst->Sym(), ctx.dst->ty.Of(buffer_size_struct), ast::StorageClass::kUniform,
+                ast::AttributeList{
+                    ctx.dst->GroupAndBinding(cfg->ubo_binding.group, cfg->ubo_binding.binding)});
+        }
+        return buffer_size_ubo;
+    };
 
-  std::unordered_set<uint32_t> used_size_indices;
+    std::unordered_set<uint32_t> used_size_indices;
 
-  IterateArrayLengthOnStorageVar(
-      ctx, [&](const ast::CallExpression* call_expr,
-               const sem::VariableUser* storage_buffer_sem,
-               const sem::GlobalVariable* var) {
+    IterateArrayLengthOnStorageVar(ctx, [&](const ast::CallExpression* call_expr,
+                                            const sem::VariableUser* storage_buffer_sem,
+                                            const sem::GlobalVariable* var) {
         auto binding = var->BindingPoint();
         auto idx_itr = cfg->bindpoint_to_size_index.find(binding);
         if (idx_itr == cfg->bindpoint_to_size_index.end()) {
-          return;
+            return;
         }
 
         uint32_t size_index = idx_itr->second;
@@ -177,11 +169,9 @@
         // Load the total storage buffer size from the UBO.
         uint32_t array_index = size_index / 4;
         auto* vec_expr = ctx.dst->IndexAccessor(
-            ctx.dst->MemberAccessor(get_ubo()->symbol, kBufferSizeMemberName),
-            array_index);
+            ctx.dst->MemberAccessor(get_ubo()->symbol, kBufferSizeMemberName), u32(array_index));
         uint32_t vec_index = size_index % 4;
-        auto* total_storage_buffer_size =
-            ctx.dst->IndexAccessor(vec_expr, vec_index);
+        auto* total_storage_buffer_size = ctx.dst->IndexAccessor(vec_expr, u32(vec_index));
 
         // Calculate actual array length
         //                total_storage_buffer_size - array_offset
@@ -191,39 +181,35 @@
         auto* storage_buffer_type = storage_buffer_sem->Type()->UnwrapRef();
         const sem::Array* array_type = nullptr;
         if (auto* str = storage_buffer_type->As<sem::Struct>()) {
-          // The variable is a struct, so subtract the byte offset of the array
-          // member.
-          auto* array_member_sem = str->Members().back();
-          array_type = array_member_sem->Type()->As<sem::Array>();
-          total_size = ctx.dst->Sub(total_storage_buffer_size,
-                                    array_member_sem->Offset());
+            // The variable is a struct, so subtract the byte offset of the array
+            // member.
+            auto* array_member_sem = str->Members().back();
+            array_type = array_member_sem->Type()->As<sem::Array>();
+            total_size = ctx.dst->Sub(total_storage_buffer_size, u32(array_member_sem->Offset()));
         } else if (auto* arr = storage_buffer_type->As<sem::Array>()) {
-          array_type = arr;
+            array_type = arr;
         } else {
-          TINT_ICE(Transform, ctx.dst->Diagnostics())
-              << "expected form of arrayLength argument to be &array_var or "
-                 "&struct_var.array_member";
-          return;
+            TINT_ICE(Transform, ctx.dst->Diagnostics())
+                << "expected form of arrayLength argument to be &array_var or "
+                   "&struct_var.array_member";
+            return;
         }
-        auto* array_length = ctx.dst->Div(total_size, array_type->Stride());
+        auto* array_length = ctx.dst->Div(total_size, u32(array_type->Stride()));
 
         ctx.Replace(call_expr, array_length);
-      });
+    });
 
-  ctx.Clone();
+    ctx.Clone();
 
-  outputs.Add<Result>(used_size_indices);
+    outputs.Add<Result>(used_size_indices);
 }
 
-ArrayLengthFromUniform::Config::Config(sem::BindingPoint ubo_bp)
-    : ubo_binding(ubo_bp) {}
+ArrayLengthFromUniform::Config::Config(sem::BindingPoint ubo_bp) : ubo_binding(ubo_bp) {}
 ArrayLengthFromUniform::Config::Config(const Config&) = default;
-ArrayLengthFromUniform::Config& ArrayLengthFromUniform::Config::operator=(
-    const Config&) = default;
+ArrayLengthFromUniform::Config& ArrayLengthFromUniform::Config::operator=(const Config&) = default;
 ArrayLengthFromUniform::Config::~Config() = default;
 
-ArrayLengthFromUniform::Result::Result(
-    std::unordered_set<uint32_t> used_size_indices_in)
+ArrayLengthFromUniform::Result::Result(std::unordered_set<uint32_t> used_size_indices_in)
     : used_size_indices(std::move(used_size_indices_in)) {}
 ArrayLengthFromUniform::Result::Result(const Result&) = default;
 ArrayLengthFromUniform::Result::~Result() = default;
diff --git a/src/tint/transform/array_length_from_uniform.h b/src/tint/transform/array_length_from_uniform.h
index 9a3a5d5..c34c529 100644
--- a/src/tint/transform/array_length_from_uniform.h
+++ b/src/tint/transform/array_length_from_uniform.h
@@ -52,71 +52,67 @@
 ///
 /// @note Depends on the following transforms to have been run first:
 /// * SimplifyPointers
-class ArrayLengthFromUniform final
-    : public Castable<ArrayLengthFromUniform, Transform> {
- public:
-  /// Constructor
-  ArrayLengthFromUniform();
-  /// Destructor
-  ~ArrayLengthFromUniform() override;
-
-  /// Configuration options for the ArrayLengthFromUniform transform.
-  struct Config final : public Castable<Data, transform::Data> {
+class ArrayLengthFromUniform final : public Castable<ArrayLengthFromUniform, Transform> {
+  public:
     /// Constructor
-    /// @param ubo_bp the binding point to use for the generated uniform buffer.
-    explicit Config(sem::BindingPoint ubo_bp);
-
-    /// Copy constructor
-    Config(const Config&);
-
-    /// Copy assignment
-    /// @return this Config
-    Config& operator=(const Config&);
-
+    ArrayLengthFromUniform();
     /// Destructor
-    ~Config() override;
+    ~ArrayLengthFromUniform() override;
 
-    /// The binding point to use for the generated uniform buffer.
-    sem::BindingPoint ubo_binding;
+    /// Configuration options for the ArrayLengthFromUniform transform.
+    struct Config final : public Castable<Data, transform::Data> {
+        /// Constructor
+        /// @param ubo_bp the binding point to use for the generated uniform buffer.
+        explicit Config(sem::BindingPoint ubo_bp);
 
-    /// The mapping from binding point to the index for the buffer size lookup.
-    std::unordered_map<sem::BindingPoint, uint32_t> bindpoint_to_size_index;
-  };
+        /// Copy constructor
+        Config(const Config&);
 
-  /// Information produced about what the transform did.
-  /// If there were no calls to the arrayLength() builtin, then no Result will
-  /// be emitted.
-  struct Result final : public Castable<Result, transform::Data> {
-    /// Constructor
-    /// @param used_size_indices Indices into the UBO that are statically used.
-    explicit Result(std::unordered_set<uint32_t> used_size_indices);
+        /// Copy assignment
+        /// @return this Config
+        Config& operator=(const Config&);
 
-    /// Copy constructor
-    Result(const Result&);
+        /// Destructor
+        ~Config() override;
 
-    /// Destructor
-    ~Result() override;
+        /// The binding point to use for the generated uniform buffer.
+        sem::BindingPoint ubo_binding;
 
-    /// Indices into the UBO that are statically used.
-    std::unordered_set<uint32_t> used_size_indices;
-  };
+        /// The mapping from binding point to the index for the buffer size lookup.
+        std::unordered_map<sem::BindingPoint, uint32_t> bindpoint_to_size_index;
+    };
 
-  /// @param program the program to inspect
-  /// @param data optional extra transform-specific input data
-  /// @returns true if this transform should be run for the given program
-  bool ShouldRun(const Program* program,
-                 const DataMap& data = {}) const override;
+    /// Information produced about what the transform did.
+    /// If there were no calls to the arrayLength() builtin, then no Result will
+    /// be emitted.
+    struct Result final : public Castable<Result, transform::Data> {
+        /// Constructor
+        /// @param used_size_indices Indices into the UBO that are statically used.
+        explicit Result(std::unordered_set<uint32_t> used_size_indices);
 
- protected:
-  /// Runs the transform using the CloneContext built for transforming a
-  /// program. Run() is responsible for calling Clone() on the CloneContext.
-  /// @param ctx the CloneContext primed with the input program and
-  /// ProgramBuilder
-  /// @param inputs optional extra transform-specific input data
-  /// @param outputs optional extra transform-specific output data
-  void Run(CloneContext& ctx,
-           const DataMap& inputs,
-           DataMap& outputs) const override;
+        /// Copy constructor
+        Result(const Result&);
+
+        /// Destructor
+        ~Result() override;
+
+        /// Indices into the UBO that are statically used.
+        std::unordered_set<uint32_t> used_size_indices;
+    };
+
+    /// @param program the program to inspect
+    /// @param data optional extra transform-specific input data
+    /// @returns true if this transform should be run for the given program
+    bool ShouldRun(const Program* program, const DataMap& data = {}) const override;
+
+  protected:
+    /// Runs the transform using the CloneContext built for transforming a
+    /// program. Run() is responsible for calling Clone() on the CloneContext.
+    /// @param ctx the CloneContext primed with the input program and
+    /// ProgramBuilder
+    /// @param inputs optional extra transform-specific input data
+    /// @param outputs optional extra transform-specific output data
+    void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const override;
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/array_length_from_uniform_test.cc b/src/tint/transform/array_length_from_uniform_test.cc
index 42a334c..ee0d4b1 100644
--- a/src/tint/transform/array_length_from_uniform_test.cc
+++ b/src/tint/transform/array_length_from_uniform_test.cc
@@ -26,13 +26,13 @@
 using ArrayLengthFromUniformTest = TransformTest;
 
 TEST_F(ArrayLengthFromUniformTest, ShouldRunEmptyModule) {
-  auto* src = R"()";
+    auto* src = R"()";
 
-  EXPECT_FALSE(ShouldRun<ArrayLengthFromUniform>(src));
+    EXPECT_FALSE(ShouldRun<ArrayLengthFromUniform>(src));
 }
 
 TEST_F(ArrayLengthFromUniformTest, ShouldRunNoArrayLength) {
-  auto* src = R"(
+    auto* src = R"(
 struct SB {
   x : i32,
   arr : array<i32>,
@@ -45,11 +45,11 @@
 }
 )";
 
-  EXPECT_FALSE(ShouldRun<ArrayLengthFromUniform>(src));
+    EXPECT_FALSE(ShouldRun<ArrayLengthFromUniform>(src));
 }
 
 TEST_F(ArrayLengthFromUniformTest, ShouldRunWithArrayLength) {
-  auto* src = R"(
+    auto* src = R"(
 struct SB {
   x : i32,
   arr : array<i32>,
@@ -63,11 +63,11 @@
 }
 )";
 
-  EXPECT_TRUE(ShouldRun<ArrayLengthFromUniform>(src));
+    EXPECT_TRUE(ShouldRun<ArrayLengthFromUniform>(src));
 }
 
 TEST_F(ArrayLengthFromUniformTest, Error_MissingTransformData) {
-  auto* src = R"(
+    auto* src = R"(
 struct SB {
   x : i32,
   arr : array<i32>,
@@ -81,17 +81,17 @@
 }
 )";
 
-  auto* expect =
-      "error: missing transform data for "
-      "tint::transform::ArrayLengthFromUniform";
+    auto* expect =
+        "error: missing transform data for "
+        "tint::transform::ArrayLengthFromUniform";
 
-  auto got = Run<Unshadow, SimplifyPointers, ArrayLengthFromUniform>(src);
+    auto got = Run<Unshadow, SimplifyPointers, ArrayLengthFromUniform>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ArrayLengthFromUniformTest, Basic) {
-  auto* src = R"(
+    auto* src = R"(
 @group(0) @binding(0) var<storage, read> sb : array<i32>;
 
 @stage(compute) @workgroup_size(1)
@@ -100,7 +100,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol {
   buffer_size : array<vec4<u32>, 1u>,
 }
@@ -115,21 +115,21 @@
 }
 )";
 
-  ArrayLengthFromUniform::Config cfg({0, 30u});
-  cfg.bindpoint_to_size_index.emplace(sem::BindingPoint{0, 0}, 0);
+    ArrayLengthFromUniform::Config cfg({0, 30u});
+    cfg.bindpoint_to_size_index.emplace(sem::BindingPoint{0, 0}, 0);
 
-  DataMap data;
-  data.Add<ArrayLengthFromUniform::Config>(std::move(cfg));
+    DataMap data;
+    data.Add<ArrayLengthFromUniform::Config>(std::move(cfg));
 
-  auto got = Run<Unshadow, SimplifyPointers, ArrayLengthFromUniform>(src, data);
+    auto got = Run<Unshadow, SimplifyPointers, ArrayLengthFromUniform>(src, data);
 
-  EXPECT_EQ(expect, str(got));
-  EXPECT_EQ(std::unordered_set<uint32_t>({0}),
-            got.data.Get<ArrayLengthFromUniform::Result>()->used_size_indices);
+    EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(std::unordered_set<uint32_t>({0}),
+              got.data.Get<ArrayLengthFromUniform::Result>()->used_size_indices);
 }
 
 TEST_F(ArrayLengthFromUniformTest, BasicInStruct) {
-  auto* src = R"(
+    auto* src = R"(
 struct SB {
   x : i32,
   arr : array<i32>,
@@ -143,7 +143,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol {
   buffer_size : array<vec4<u32>, 1u>,
 }
@@ -163,21 +163,21 @@
 }
 )";
 
-  ArrayLengthFromUniform::Config cfg({0, 30u});
-  cfg.bindpoint_to_size_index.emplace(sem::BindingPoint{0, 0}, 0);
+    ArrayLengthFromUniform::Config cfg({0, 30u});
+    cfg.bindpoint_to_size_index.emplace(sem::BindingPoint{0, 0}, 0);
 
-  DataMap data;
-  data.Add<ArrayLengthFromUniform::Config>(std::move(cfg));
+    DataMap data;
+    data.Add<ArrayLengthFromUniform::Config>(std::move(cfg));
 
-  auto got = Run<Unshadow, SimplifyPointers, ArrayLengthFromUniform>(src, data);
+    auto got = Run<Unshadow, SimplifyPointers, ArrayLengthFromUniform>(src, data);
 
-  EXPECT_EQ(expect, str(got));
-  EXPECT_EQ(std::unordered_set<uint32_t>({0}),
-            got.data.Get<ArrayLengthFromUniform::Result>()->used_size_indices);
+    EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(std::unordered_set<uint32_t>({0}),
+              got.data.Get<ArrayLengthFromUniform::Result>()->used_size_indices);
 }
 
 TEST_F(ArrayLengthFromUniformTest, MultipleStorageBuffers) {
-  auto* src = R"(
+    auto* src = R"(
 struct SB1 {
   x : i32,
   arr1 : array<i32>,
@@ -208,7 +208,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol {
   buffer_size : array<vec4<u32>, 2u>,
 }
@@ -251,25 +251,25 @@
 }
 )";
 
-  ArrayLengthFromUniform::Config cfg({0, 30u});
-  cfg.bindpoint_to_size_index.emplace(sem::BindingPoint{0, 2u}, 0);
-  cfg.bindpoint_to_size_index.emplace(sem::BindingPoint{1u, 2u}, 1);
-  cfg.bindpoint_to_size_index.emplace(sem::BindingPoint{2u, 2u}, 2);
-  cfg.bindpoint_to_size_index.emplace(sem::BindingPoint{3u, 2u}, 3);
-  cfg.bindpoint_to_size_index.emplace(sem::BindingPoint{4u, 2u}, 4);
+    ArrayLengthFromUniform::Config cfg({0, 30u});
+    cfg.bindpoint_to_size_index.emplace(sem::BindingPoint{0, 2u}, 0);
+    cfg.bindpoint_to_size_index.emplace(sem::BindingPoint{1u, 2u}, 1);
+    cfg.bindpoint_to_size_index.emplace(sem::BindingPoint{2u, 2u}, 2);
+    cfg.bindpoint_to_size_index.emplace(sem::BindingPoint{3u, 2u}, 3);
+    cfg.bindpoint_to_size_index.emplace(sem::BindingPoint{4u, 2u}, 4);
 
-  DataMap data;
-  data.Add<ArrayLengthFromUniform::Config>(std::move(cfg));
+    DataMap data;
+    data.Add<ArrayLengthFromUniform::Config>(std::move(cfg));
 
-  auto got = Run<Unshadow, SimplifyPointers, ArrayLengthFromUniform>(src, data);
+    auto got = Run<Unshadow, SimplifyPointers, ArrayLengthFromUniform>(src, data);
 
-  EXPECT_EQ(expect, str(got));
-  EXPECT_EQ(std::unordered_set<uint32_t>({0, 1, 2, 3, 4}),
-            got.data.Get<ArrayLengthFromUniform::Result>()->used_size_indices);
+    EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(std::unordered_set<uint32_t>({0, 1, 2, 3, 4}),
+              got.data.Get<ArrayLengthFromUniform::Result>()->used_size_indices);
 }
 
 TEST_F(ArrayLengthFromUniformTest, MultipleUnusedStorageBuffers) {
-  auto* src = R"(
+    auto* src = R"(
 struct SB1 {
   x : i32,
   arr1 : array<i32>,
@@ -297,7 +297,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol {
   buffer_size : array<vec4<u32>, 1u>,
 }
@@ -337,25 +337,25 @@
 }
 )";
 
-  ArrayLengthFromUniform::Config cfg({0, 30u});
-  cfg.bindpoint_to_size_index.emplace(sem::BindingPoint{0, 2u}, 0);
-  cfg.bindpoint_to_size_index.emplace(sem::BindingPoint{1u, 2u}, 1);
-  cfg.bindpoint_to_size_index.emplace(sem::BindingPoint{2u, 2u}, 2);
-  cfg.bindpoint_to_size_index.emplace(sem::BindingPoint{3u, 2u}, 3);
-  cfg.bindpoint_to_size_index.emplace(sem::BindingPoint{4u, 2u}, 4);
+    ArrayLengthFromUniform::Config cfg({0, 30u});
+    cfg.bindpoint_to_size_index.emplace(sem::BindingPoint{0, 2u}, 0);
+    cfg.bindpoint_to_size_index.emplace(sem::BindingPoint{1u, 2u}, 1);
+    cfg.bindpoint_to_size_index.emplace(sem::BindingPoint{2u, 2u}, 2);
+    cfg.bindpoint_to_size_index.emplace(sem::BindingPoint{3u, 2u}, 3);
+    cfg.bindpoint_to_size_index.emplace(sem::BindingPoint{4u, 2u}, 4);
 
-  DataMap data;
-  data.Add<ArrayLengthFromUniform::Config>(std::move(cfg));
+    DataMap data;
+    data.Add<ArrayLengthFromUniform::Config>(std::move(cfg));
 
-  auto got = Run<Unshadow, SimplifyPointers, ArrayLengthFromUniform>(src, data);
+    auto got = Run<Unshadow, SimplifyPointers, ArrayLengthFromUniform>(src, data);
 
-  EXPECT_EQ(expect, str(got));
-  EXPECT_EQ(std::unordered_set<uint32_t>({0, 2}),
-            got.data.Get<ArrayLengthFromUniform::Result>()->used_size_indices);
+    EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(std::unordered_set<uint32_t>({0, 2}),
+              got.data.Get<ArrayLengthFromUniform::Result>()->used_size_indices);
 }
 
 TEST_F(ArrayLengthFromUniformTest, NoArrayLengthCalls) {
-  auto* src = R"(
+    auto* src = R"(
 struct SB {
   x : i32,
   arr : array<i32>,
@@ -369,20 +369,20 @@
 }
 )";
 
-  ArrayLengthFromUniform::Config cfg({0, 30u});
-  cfg.bindpoint_to_size_index.emplace(sem::BindingPoint{0, 0}, 0);
+    ArrayLengthFromUniform::Config cfg({0, 30u});
+    cfg.bindpoint_to_size_index.emplace(sem::BindingPoint{0, 0}, 0);
 
-  DataMap data;
-  data.Add<ArrayLengthFromUniform::Config>(std::move(cfg));
+    DataMap data;
+    data.Add<ArrayLengthFromUniform::Config>(std::move(cfg));
 
-  auto got = Run<Unshadow, SimplifyPointers, ArrayLengthFromUniform>(src, data);
+    auto got = Run<Unshadow, SimplifyPointers, ArrayLengthFromUniform>(src, data);
 
-  EXPECT_EQ(src, str(got));
-  EXPECT_EQ(got.data.Get<ArrayLengthFromUniform::Result>(), nullptr);
+    EXPECT_EQ(src, str(got));
+    EXPECT_EQ(got.data.Get<ArrayLengthFromUniform::Result>(), nullptr);
 }
 
 TEST_F(ArrayLengthFromUniformTest, MissingBindingPointToIndexMapping) {
-  auto* src = R"(
+    auto* src = R"(
 struct SB1 {
   x : i32,
   arr1 : array<i32>,
@@ -405,7 +405,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol {
   buffer_size : array<vec4<u32>, 1u>,
 }
@@ -434,21 +434,21 @@
 }
 )";
 
-  ArrayLengthFromUniform::Config cfg({0, 30u});
-  cfg.bindpoint_to_size_index.emplace(sem::BindingPoint{0, 2}, 0);
+    ArrayLengthFromUniform::Config cfg({0, 30u});
+    cfg.bindpoint_to_size_index.emplace(sem::BindingPoint{0, 2}, 0);
 
-  DataMap data;
-  data.Add<ArrayLengthFromUniform::Config>(std::move(cfg));
+    DataMap data;
+    data.Add<ArrayLengthFromUniform::Config>(std::move(cfg));
 
-  auto got = Run<Unshadow, SimplifyPointers, ArrayLengthFromUniform>(src, data);
+    auto got = Run<Unshadow, SimplifyPointers, ArrayLengthFromUniform>(src, data);
 
-  EXPECT_EQ(expect, str(got));
-  EXPECT_EQ(std::unordered_set<uint32_t>({0}),
-            got.data.Get<ArrayLengthFromUniform::Result>()->used_size_indices);
+    EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(std::unordered_set<uint32_t>({0}),
+              got.data.Get<ArrayLengthFromUniform::Result>()->used_size_indices);
 }
 
 TEST_F(ArrayLengthFromUniformTest, OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   var len : u32 = arrayLength(&sb.arr);
@@ -462,7 +462,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol {
   buffer_size : array<vec4<u32>, 1u>,
 }
@@ -482,17 +482,17 @@
 }
 )";
 
-  ArrayLengthFromUniform::Config cfg({0, 30u});
-  cfg.bindpoint_to_size_index.emplace(sem::BindingPoint{0, 0}, 0);
+    ArrayLengthFromUniform::Config cfg({0, 30u});
+    cfg.bindpoint_to_size_index.emplace(sem::BindingPoint{0, 0}, 0);
 
-  DataMap data;
-  data.Add<ArrayLengthFromUniform::Config>(std::move(cfg));
+    DataMap data;
+    data.Add<ArrayLengthFromUniform::Config>(std::move(cfg));
 
-  auto got = Run<Unshadow, SimplifyPointers, ArrayLengthFromUniform>(src, data);
+    auto got = Run<Unshadow, SimplifyPointers, ArrayLengthFromUniform>(src, data);
 
-  EXPECT_EQ(expect, str(got));
-  EXPECT_EQ(std::unordered_set<uint32_t>({0}),
-            got.data.Get<ArrayLengthFromUniform::Result>()->used_size_indices);
+    EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(std::unordered_set<uint32_t>({0}),
+              got.data.Get<ArrayLengthFromUniform::Result>()->used_size_indices);
 }
 
 }  // namespace
diff --git a/src/tint/transform/binding_remapper.cc b/src/tint/transform/binding_remapper.cc
index 3934b20..e3b7afd 100644
--- a/src/tint/transform/binding_remapper.cc
+++ b/src/tint/transform/binding_remapper.cc
@@ -28,9 +28,7 @@
 
 namespace tint::transform {
 
-BindingRemapper::Remappings::Remappings(BindingPoints bp,
-                                        AccessControls ac,
-                                        bool may_collide)
+BindingRemapper::Remappings::Remappings(BindingPoints bp, AccessControls ac, bool may_collide)
     : binding_points(std::move(bp)),
       access_controls(std::move(ac)),
       allow_collisions(may_collide) {}
@@ -42,120 +40,112 @@
 BindingRemapper::~BindingRemapper() = default;
 
 bool BindingRemapper::ShouldRun(const Program*, const DataMap& inputs) const {
-  if (auto* remappings = inputs.Get<Remappings>()) {
-    return !remappings->binding_points.empty() ||
-           !remappings->access_controls.empty();
-  }
-  return false;
+    if (auto* remappings = inputs.Get<Remappings>()) {
+        return !remappings->binding_points.empty() || !remappings->access_controls.empty();
+    }
+    return false;
 }
 
-void BindingRemapper::Run(CloneContext& ctx,
-                          const DataMap& inputs,
-                          DataMap&) const {
-  auto* remappings = inputs.Get<Remappings>();
-  if (!remappings) {
-    ctx.dst->Diagnostics().add_error(
-        diag::System::Transform,
-        "missing transform data for " + std::string(TypeInfo().name));
-    return;
-  }
-
-  // A set of post-remapped binding points that need to be decorated with a
-  // DisableValidationAttribute to disable binding-point-collision validation
-  std::unordered_set<sem::BindingPoint> add_collision_attr;
-
-  if (remappings->allow_collisions) {
-    // Scan for binding point collisions generated by this transform.
-    // Populate all collisions in the `add_collision_attr` set.
-    for (auto* func_ast : ctx.src->AST().Functions()) {
-      if (!func_ast->IsEntryPoint()) {
-        continue;
-      }
-      auto* func = ctx.src->Sem().Get(func_ast);
-      std::unordered_map<sem::BindingPoint, int> binding_point_counts;
-      for (auto* var : func->TransitivelyReferencedGlobals()) {
-        if (auto binding_point = var->Declaration()->BindingPoint()) {
-          BindingPoint from{binding_point.group->value,
-                            binding_point.binding->value};
-          auto bp_it = remappings->binding_points.find(from);
-          if (bp_it != remappings->binding_points.end()) {
-            // Remapped
-            BindingPoint to = bp_it->second;
-            if (binding_point_counts[to]++) {
-              add_collision_attr.emplace(to);
-            }
-          } else {
-            // No remapping
-            if (binding_point_counts[from]++) {
-              add_collision_attr.emplace(from);
-            }
-          }
-        }
-      }
+void BindingRemapper::Run(CloneContext& ctx, const DataMap& inputs, DataMap&) const {
+    auto* remappings = inputs.Get<Remappings>();
+    if (!remappings) {
+        ctx.dst->Diagnostics().add_error(
+            diag::System::Transform, "missing transform data for " + std::string(TypeInfo().name));
+        return;
     }
-  }
 
-  for (auto* var : ctx.src->AST().GlobalVariables()) {
-    if (auto binding_point = var->BindingPoint()) {
-      // The original binding point
-      BindingPoint from{binding_point.group->value,
-                        binding_point.binding->value};
+    // A set of post-remapped binding points that need to be decorated with a
+    // DisableValidationAttribute to disable binding-point-collision validation
+    std::unordered_set<sem::BindingPoint> add_collision_attr;
 
-      // The binding point after remapping
-      BindingPoint bp = from;
-
-      // Replace any group or binding attributes.
-      // Note: This has to be performed *before* remapping access controls, as
-      // `ctx.Clone(var->attributes)` depend on these replacements.
-      auto bp_it = remappings->binding_points.find(from);
-      if (bp_it != remappings->binding_points.end()) {
-        BindingPoint to = bp_it->second;
-        auto* new_group = ctx.dst->create<ast::GroupAttribute>(to.group);
-        auto* new_binding = ctx.dst->create<ast::BindingAttribute>(to.binding);
-
-        ctx.Replace(binding_point.group, new_group);
-        ctx.Replace(binding_point.binding, new_binding);
-        bp = to;
-      }
-
-      // Replace any access controls.
-      auto ac_it = remappings->access_controls.find(from);
-      if (ac_it != remappings->access_controls.end()) {
-        ast::Access ac = ac_it->second;
-        if (ac > ast::Access::kLastValid) {
-          ctx.dst->Diagnostics().add_error(
-              diag::System::Transform,
-              "invalid access mode (" +
-                  std::to_string(static_cast<uint32_t>(ac)) + ")");
-          return;
+    if (remappings->allow_collisions) {
+        // Scan for binding point collisions generated by this transform.
+        // Populate all collisions in the `add_collision_attr` set.
+        for (auto* func_ast : ctx.src->AST().Functions()) {
+            if (!func_ast->IsEntryPoint()) {
+                continue;
+            }
+            auto* func = ctx.src->Sem().Get(func_ast);
+            std::unordered_map<sem::BindingPoint, int> binding_point_counts;
+            for (auto* var : func->TransitivelyReferencedGlobals()) {
+                if (auto binding_point = var->Declaration()->BindingPoint()) {
+                    BindingPoint from{binding_point.group->value, binding_point.binding->value};
+                    auto bp_it = remappings->binding_points.find(from);
+                    if (bp_it != remappings->binding_points.end()) {
+                        // Remapped
+                        BindingPoint to = bp_it->second;
+                        if (binding_point_counts[to]++) {
+                            add_collision_attr.emplace(to);
+                        }
+                    } else {
+                        // No remapping
+                        if (binding_point_counts[from]++) {
+                            add_collision_attr.emplace(from);
+                        }
+                    }
+                }
+            }
         }
-        auto* sem = ctx.src->Sem().Get(var);
-        if (sem->StorageClass() != ast::StorageClass::kStorage) {
-          ctx.dst->Diagnostics().add_error(
-              diag::System::Transform,
-              "cannot apply access control to variable with storage class " +
-                  std::string(ast::ToString(sem->StorageClass())));
-          return;
-        }
-        auto* ty = sem->Type()->UnwrapRef();
-        const ast::Type* inner_ty = CreateASTTypeFor(ctx, ty);
-        auto* new_var = ctx.dst->create<ast::Variable>(
-            ctx.Clone(var->source), ctx.Clone(var->symbol),
-            var->declared_storage_class, ac, inner_ty, false, false,
-            ctx.Clone(var->constructor), ctx.Clone(var->attributes));
-        ctx.Replace(var, new_var);
-      }
-
-      // Add `DisableValidationAttribute`s if required
-      if (add_collision_attr.count(bp)) {
-        auto* attribute =
-            ctx.dst->Disable(ast::DisabledValidation::kBindingPointCollision);
-        ctx.InsertBefore(var->attributes, *var->attributes.begin(), attribute);
-      }
     }
-  }
 
-  ctx.Clone();
+    for (auto* var : ctx.src->AST().GlobalVariables()) {
+        if (auto binding_point = var->BindingPoint()) {
+            // The original binding point
+            BindingPoint from{binding_point.group->value, binding_point.binding->value};
+
+            // The binding point after remapping
+            BindingPoint bp = from;
+
+            // Replace any group or binding attributes.
+            // Note: This has to be performed *before* remapping access controls, as
+            // `ctx.Clone(var->attributes)` depend on these replacements.
+            auto bp_it = remappings->binding_points.find(from);
+            if (bp_it != remappings->binding_points.end()) {
+                BindingPoint to = bp_it->second;
+                auto* new_group = ctx.dst->create<ast::GroupAttribute>(to.group);
+                auto* new_binding = ctx.dst->create<ast::BindingAttribute>(to.binding);
+
+                ctx.Replace(binding_point.group, new_group);
+                ctx.Replace(binding_point.binding, new_binding);
+                bp = to;
+            }
+
+            // Replace any access controls.
+            auto ac_it = remappings->access_controls.find(from);
+            if (ac_it != remappings->access_controls.end()) {
+                ast::Access ac = ac_it->second;
+                if (ac > ast::Access::kLastValid) {
+                    ctx.dst->Diagnostics().add_error(
+                        diag::System::Transform,
+                        "invalid access mode (" + std::to_string(static_cast<uint32_t>(ac)) + ")");
+                    return;
+                }
+                auto* sem = ctx.src->Sem().Get(var);
+                if (sem->StorageClass() != ast::StorageClass::kStorage) {
+                    ctx.dst->Diagnostics().add_error(
+                        diag::System::Transform,
+                        "cannot apply access control to variable with storage class " +
+                            std::string(ast::ToString(sem->StorageClass())));
+                    return;
+                }
+                auto* ty = sem->Type()->UnwrapRef();
+                const ast::Type* inner_ty = CreateASTTypeFor(ctx, ty);
+                auto* new_var = ctx.dst->create<ast::Variable>(
+                    ctx.Clone(var->source), ctx.Clone(var->symbol), var->declared_storage_class, ac,
+                    inner_ty, false, false, ctx.Clone(var->constructor),
+                    ctx.Clone(var->attributes));
+                ctx.Replace(var, new_var);
+            }
+
+            // Add `DisableValidationAttribute`s if required
+            if (add_collision_attr.count(bp)) {
+                auto* attribute = ctx.dst->Disable(ast::DisabledValidation::kBindingPointCollision);
+                ctx.InsertBefore(var->attributes, *var->attributes.begin(), attribute);
+            }
+        }
+    }
+
+    ctx.Clone();
 }
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/binding_remapper.h b/src/tint/transform/binding_remapper.h
index 3e9f613..77fc5bc 100644
--- a/src/tint/transform/binding_remapper.h
+++ b/src/tint/transform/binding_remapper.h
@@ -29,60 +29,57 @@
 /// BindingRemapper is a transform used to remap resource binding points and
 /// access controls.
 class BindingRemapper final : public Castable<BindingRemapper, Transform> {
- public:
-  /// BindingPoints is a map of old binding point to new binding point
-  using BindingPoints = std::unordered_map<BindingPoint, BindingPoint>;
+  public:
+    /// BindingPoints is a map of old binding point to new binding point
+    using BindingPoints = std::unordered_map<BindingPoint, BindingPoint>;
 
-  /// AccessControls is a map of old binding point to new access control
-  using AccessControls = std::unordered_map<BindingPoint, ast::Access>;
+    /// AccessControls is a map of old binding point to new access control
+    using AccessControls = std::unordered_map<BindingPoint, ast::Access>;
 
-  /// Remappings is consumed by the BindingRemapper transform.
-  /// Data holds information about shader usage and constant buffer offsets.
-  struct Remappings final : public Castable<Data, transform::Data> {
+    /// Remappings is consumed by the BindingRemapper transform.
+    /// Data holds information about shader usage and constant buffer offsets.
+    struct Remappings final : public Castable<Data, transform::Data> {
+        /// Constructor
+        /// @param bp a map of new binding points
+        /// @param ac a map of new access controls
+        /// @param may_collide If true, then validation will be disabled for
+        /// binding point collisions generated by this transform
+        Remappings(BindingPoints bp, AccessControls ac, bool may_collide = true);
+
+        /// Copy constructor
+        Remappings(const Remappings&);
+
+        /// Destructor
+        ~Remappings() override;
+
+        /// A map of old binding point to new binding point
+        const BindingPoints binding_points;
+
+        /// A map of old binding point to new access controls
+        const AccessControls access_controls;
+
+        /// If true, then validation will be disabled for binding point collisions
+        /// generated by this transform
+        const bool allow_collisions;
+    };
+
     /// Constructor
-    /// @param bp a map of new binding points
-    /// @param ac a map of new access controls
-    /// @param may_collide If true, then validation will be disabled for
-    /// binding point collisions generated by this transform
-    Remappings(BindingPoints bp, AccessControls ac, bool may_collide = true);
+    BindingRemapper();
+    ~BindingRemapper() override;
 
-    /// Copy constructor
-    Remappings(const Remappings&);
+    /// @param program the program to inspect
+    /// @param data optional extra transform-specific input data
+    /// @returns true if this transform should be run for the given program
+    bool ShouldRun(const Program* program, const DataMap& data = {}) const override;
 
-    /// Destructor
-    ~Remappings() override;
-
-    /// A map of old binding point to new binding point
-    const BindingPoints binding_points;
-
-    /// A map of old binding point to new access controls
-    const AccessControls access_controls;
-
-    /// If true, then validation will be disabled for binding point collisions
-    /// generated by this transform
-    const bool allow_collisions;
-  };
-
-  /// Constructor
-  BindingRemapper();
-  ~BindingRemapper() override;
-
-  /// @param program the program to inspect
-  /// @param data optional extra transform-specific input data
-  /// @returns true if this transform should be run for the given program
-  bool ShouldRun(const Program* program,
-                 const DataMap& data = {}) const override;
-
- protected:
-  /// Runs the transform using the CloneContext built for transforming a
-  /// program. Run() is responsible for calling Clone() on the CloneContext.
-  /// @param ctx the CloneContext primed with the input program and
-  /// ProgramBuilder
-  /// @param inputs optional extra transform-specific input data
-  /// @param outputs optional extra transform-specific output data
-  void Run(CloneContext& ctx,
-           const DataMap& inputs,
-           DataMap& outputs) const override;
+  protected:
+    /// Runs the transform using the CloneContext built for transforming a
+    /// program. Run() is responsible for calling Clone() on the CloneContext.
+    /// @param ctx the CloneContext primed with the input program and
+    /// ProgramBuilder
+    /// @param inputs optional extra transform-specific input data
+    /// @param outputs optional extra transform-specific output data
+    void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const override;
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/binding_remapper_test.cc b/src/tint/transform/binding_remapper_test.cc
index 70c7232..29a96c3 100644
--- a/src/tint/transform/binding_remapper_test.cc
+++ b/src/tint/transform/binding_remapper_test.cc
@@ -24,48 +24,48 @@
 using BindingRemapperTest = TransformTest;
 
 TEST_F(BindingRemapperTest, ShouldRunNoRemappings) {
-  auto* src = R"()";
+    auto* src = R"()";
 
-  EXPECT_FALSE(ShouldRun<BindingRemapper>(src));
+    EXPECT_FALSE(ShouldRun<BindingRemapper>(src));
 }
 
 TEST_F(BindingRemapperTest, ShouldRunEmptyRemappings) {
-  auto* src = R"()";
+    auto* src = R"()";
 
-  DataMap data;
-  data.Add<BindingRemapper::Remappings>(BindingRemapper::BindingPoints{},
-                                        BindingRemapper::AccessControls{});
+    DataMap data;
+    data.Add<BindingRemapper::Remappings>(BindingRemapper::BindingPoints{},
+                                          BindingRemapper::AccessControls{});
 
-  EXPECT_FALSE(ShouldRun<BindingRemapper>(src, data));
+    EXPECT_FALSE(ShouldRun<BindingRemapper>(src, data));
 }
 
 TEST_F(BindingRemapperTest, ShouldRunBindingPointRemappings) {
-  auto* src = R"()";
+    auto* src = R"()";
 
-  DataMap data;
-  data.Add<BindingRemapper::Remappings>(
-      BindingRemapper::BindingPoints{
-          {{2, 1}, {1, 2}},
-      },
-      BindingRemapper::AccessControls{});
+    DataMap data;
+    data.Add<BindingRemapper::Remappings>(
+        BindingRemapper::BindingPoints{
+            {{2, 1}, {1, 2}},
+        },
+        BindingRemapper::AccessControls{});
 
-  EXPECT_TRUE(ShouldRun<BindingRemapper>(src, data));
+    EXPECT_TRUE(ShouldRun<BindingRemapper>(src, data));
 }
 
 TEST_F(BindingRemapperTest, ShouldRunAccessControlRemappings) {
-  auto* src = R"()";
+    auto* src = R"()";
 
-  DataMap data;
-  data.Add<BindingRemapper::Remappings>(BindingRemapper::BindingPoints{},
-                                        BindingRemapper::AccessControls{
-                                            {{2, 1}, ast::Access::kWrite},
-                                        });
+    DataMap data;
+    data.Add<BindingRemapper::Remappings>(BindingRemapper::BindingPoints{},
+                                          BindingRemapper::AccessControls{
+                                              {{2, 1}, ast::Access::kWrite},
+                                          });
 
-  EXPECT_TRUE(ShouldRun<BindingRemapper>(src, data));
+    EXPECT_TRUE(ShouldRun<BindingRemapper>(src, data));
 }
 
 TEST_F(BindingRemapperTest, NoRemappings) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   a : f32,
 }
@@ -79,18 +79,18 @@
 }
 )";
 
-  auto* expect = src;
+    auto* expect = src;
 
-  DataMap data;
-  data.Add<BindingRemapper::Remappings>(BindingRemapper::BindingPoints{},
-                                        BindingRemapper::AccessControls{});
-  auto got = Run<BindingRemapper>(src, data);
+    DataMap data;
+    data.Add<BindingRemapper::Remappings>(BindingRemapper::BindingPoints{},
+                                          BindingRemapper::AccessControls{});
+    auto got = Run<BindingRemapper>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(BindingRemapperTest, RemapBindingPoints) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   a : f32,
 };
@@ -104,7 +104,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   a : f32,
 }
@@ -118,21 +118,21 @@
 }
 )";
 
-  DataMap data;
-  data.Add<BindingRemapper::Remappings>(
-      BindingRemapper::BindingPoints{
-          {{2, 1}, {1, 2}},  // Remap
-          {{4, 5}, {6, 7}},  // Not found
-                             // Keep @group(3) @binding(2) as is
-      },
-      BindingRemapper::AccessControls{});
-  auto got = Run<BindingRemapper>(src, data);
+    DataMap data;
+    data.Add<BindingRemapper::Remappings>(
+        BindingRemapper::BindingPoints{
+            {{2, 1}, {1, 2}},  // Remap
+            {{4, 5}, {6, 7}},  // Not found
+                               // Keep @group(3) @binding(2) as is
+        },
+        BindingRemapper::AccessControls{});
+    auto got = Run<BindingRemapper>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(BindingRemapperTest, RemapAccessControls) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   a : f32,
 };
@@ -148,7 +148,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   a : f32,
 }
@@ -164,21 +164,21 @@
 }
 )";
 
-  DataMap data;
-  data.Add<BindingRemapper::Remappings>(
-      BindingRemapper::BindingPoints{},
-      BindingRemapper::AccessControls{
-          {{2, 1}, ast::Access::kWrite},  // Modify access control
-          // Keep @group(3) @binding(2) as is
-          {{4, 3}, ast::Access::kRead},  // Add access control
-      });
-  auto got = Run<BindingRemapper>(src, data);
+    DataMap data;
+    data.Add<BindingRemapper::Remappings>(
+        BindingRemapper::BindingPoints{},
+        BindingRemapper::AccessControls{
+            {{2, 1}, ast::Access::kWrite},  // Modify access control
+            // Keep @group(3) @binding(2) as is
+            {{4, 3}, ast::Access::kRead},  // Add access control
+        });
+    auto got = Run<BindingRemapper>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(BindingRemapperTest, RemapAll) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   a : f32,
 };
@@ -192,7 +192,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   a : f32,
 }
@@ -206,23 +206,23 @@
 }
 )";
 
-  DataMap data;
-  data.Add<BindingRemapper::Remappings>(
-      BindingRemapper::BindingPoints{
-          {{2, 1}, {4, 5}},
-          {{3, 2}, {6, 7}},
-      },
-      BindingRemapper::AccessControls{
-          {{2, 1}, ast::Access::kWrite},
-          {{3, 2}, ast::Access::kWrite},
-      });
-  auto got = Run<BindingRemapper>(src, data);
+    DataMap data;
+    data.Add<BindingRemapper::Remappings>(
+        BindingRemapper::BindingPoints{
+            {{2, 1}, {4, 5}},
+            {{3, 2}, {6, 7}},
+        },
+        BindingRemapper::AccessControls{
+            {{2, 1}, ast::Access::kWrite},
+            {{3, 2}, ast::Access::kWrite},
+        });
+    auto got = Run<BindingRemapper>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(BindingRemapperTest, BindingCollisionsSameEntryPoint) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   i : i32,
 };
@@ -241,7 +241,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   i : i32,
 }
@@ -260,21 +260,21 @@
 }
 )";
 
-  DataMap data;
-  data.Add<BindingRemapper::Remappings>(
-      BindingRemapper::BindingPoints{
-          {{2, 1}, {1, 1}},
-          {{3, 2}, {1, 1}},
-          {{4, 3}, {5, 4}},
-      },
-      BindingRemapper::AccessControls{}, true);
-  auto got = Run<BindingRemapper>(src, data);
+    DataMap data;
+    data.Add<BindingRemapper::Remappings>(
+        BindingRemapper::BindingPoints{
+            {{2, 1}, {1, 1}},
+            {{3, 2}, {1, 1}},
+            {{4, 3}, {5, 4}},
+        },
+        BindingRemapper::AccessControls{}, true);
+    auto got = Run<BindingRemapper>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(BindingRemapperTest, BindingCollisionsDifferentEntryPoints) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   i : i32,
 };
@@ -298,7 +298,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   i : i32,
 }
@@ -322,21 +322,21 @@
 }
 )";
 
-  DataMap data;
-  data.Add<BindingRemapper::Remappings>(
-      BindingRemapper::BindingPoints{
-          {{2, 1}, {1, 1}},
-          {{3, 2}, {1, 1}},
-          {{4, 3}, {5, 4}},
-      },
-      BindingRemapper::AccessControls{}, true);
-  auto got = Run<BindingRemapper>(src, data);
+    DataMap data;
+    data.Add<BindingRemapper::Remappings>(
+        BindingRemapper::BindingPoints{
+            {{2, 1}, {1, 1}},
+            {{3, 2}, {1, 1}},
+            {{4, 3}, {5, 4}},
+        },
+        BindingRemapper::AccessControls{}, true);
+    auto got = Run<BindingRemapper>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(BindingRemapperTest, NoData) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   a : f32,
 }
@@ -350,11 +350,11 @@
 }
 )";
 
-  auto* expect = src;
+    auto* expect = src;
 
-  auto got = Run<BindingRemapper>(src);
+    auto got = Run<BindingRemapper>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 }  // namespace
diff --git a/src/tint/transform/builtin_polyfill.cc b/src/tint/transform/builtin_polyfill.cc
index c33d40f..9bde1cc 100644
--- a/src/tint/transform/builtin_polyfill.cc
+++ b/src/tint/transform/builtin_polyfill.cc
@@ -21,6 +21,8 @@
 #include "src/tint/sem/call.h"
 #include "src/tint/utils/map.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 TINT_INSTANTIATE_TYPEINFO(tint::transform::BuiltinPolyfill);
 TINT_INSTANTIATE_TYPEINFO(tint::transform::BuiltinPolyfill::Config);
 
@@ -28,569 +30,526 @@
 
 /// The PIMPL state for the BuiltinPolyfill transform
 struct BuiltinPolyfill::State {
-  /// Constructor
-  /// @param c the CloneContext
-  /// @param p the builtins to polyfill
-  State(CloneContext& c, Builtins p) : ctx(c), polyfill(p) {}
+    /// Constructor
+    /// @param c the CloneContext
+    /// @param p the builtins to polyfill
+    State(CloneContext& c, Builtins p) : ctx(c), polyfill(p) {}
 
-  /// The clone context
-  CloneContext& ctx;
-  /// The builtins to polyfill
-  Builtins polyfill;
-  /// The destination program builder
-  ProgramBuilder& b = *ctx.dst;
-  /// The source clone context
-  const sem::Info& sem = ctx.src->Sem();
+    /// The clone context
+    CloneContext& ctx;
+    /// The builtins to polyfill
+    Builtins polyfill;
+    /// The destination program builder
+    ProgramBuilder& b = *ctx.dst;
+    /// The source clone context
+    const sem::Info& sem = ctx.src->Sem();
 
-  /// Builds the polyfill function for the `countLeadingZeros` builtin
-  /// @param ty the parameter and return type for the function
-  /// @return the polyfill function name
-  Symbol countLeadingZeros(const sem::Type* ty) {
-    auto name = b.Symbols().New("tint_count_leading_zeros");
-    uint32_t width = WidthOf(ty);
+    /// Builds the polyfill function for the `countLeadingZeros` builtin
+    /// @param ty the parameter and return type for the function
+    /// @return the polyfill function name
+    Symbol countLeadingZeros(const sem::Type* ty) {
+        auto name = b.Symbols().New("tint_count_leading_zeros");
+        uint32_t width = WidthOf(ty);
 
-    // Returns either u32 or vecN<u32>
-    auto U = [&]() -> const ast::Type* {
-      if (width == 1) {
-        return b.ty.u32();
-      }
-      return b.ty.vec<u32>(width);
-    };
-    auto V = [&](uint32_t value) -> const ast::Expression* {
-      return ScalarOrVector(width, value);
-    };
-    b.Func(
-        name, {b.Param("v", T(ty))}, T(ty),
-        {
-            // var x = U(v);
-            b.Decl(b.Var("x", nullptr, b.Construct(U(), b.Expr("v")))),
-            // let b16 = select(0, 16, x <= 0x0000ffff);
-            b.Decl(b.Const("b16", nullptr,
-                           b.Call("select", V(0), V(16),
-                                  b.LessThanEqual("x", V(0x0000ffff))))),
-            // x = x << b16;
-            b.Assign("x", b.Shl("x", "b16")),
-            // let b8  = select(0, 8,  x <= 0x00ffffff);
-            b.Decl(b.Const("b8", nullptr,
-                           b.Call("select", V(0), V(8),
-                                  b.LessThanEqual("x", V(0x00ffffff))))),
-            // x = x << b8;
-            b.Assign("x", b.Shl("x", "b8")),
-            // let b4  = select(0, 4,  x <= 0x0fffffff);
-            b.Decl(b.Const("b4", nullptr,
-                           b.Call("select", V(0), V(4),
-                                  b.LessThanEqual("x", V(0x0fffffff))))),
-            // x = x << b4;
-            b.Assign("x", b.Shl("x", "b4")),
-            // let b2  = select(0, 2,  x <= 0x3fffffff);
-            b.Decl(b.Const("b2", nullptr,
-                           b.Call("select", V(0), V(2),
-                                  b.LessThanEqual("x", V(0x3fffffff))))),
-            // x = x << b2;
-            b.Assign("x", b.Shl("x", "b2")),
-            // let b1  = select(0, 1,  x <= 0x7fffffff);
-            b.Decl(b.Const("b1", nullptr,
-                           b.Call("select", V(0), V(1),
-                                  b.LessThanEqual("x", V(0x7fffffff))))),
-            // let is_zero  = select(0, 1, x == 0);
-            b.Decl(b.Const("is_zero", nullptr,
-                           b.Call("select", V(0), V(1), b.Equal("x", V(0))))),
-            // return R((b16 | b8 | b4 | b2 | b1) + zero);
-            b.Return(b.Construct(
-                T(ty),
-                b.Add(b.Or(b.Or(b.Or(b.Or("b16", "b8"), "b4"), "b2"), "b1"),
-                      "is_zero"))),
-        });
-    return name;
-  }
-
-  /// Builds the polyfill function for the `countTrailingZeros` builtin
-  /// @param ty the parameter and return type for the function
-  /// @return the polyfill function name
-  Symbol countTrailingZeros(const sem::Type* ty) {
-    auto name = b.Symbols().New("tint_count_trailing_zeros");
-    uint32_t width = WidthOf(ty);
-
-    // Returns either u32 or vecN<u32>
-    auto U = [&]() -> const ast::Type* {
-      if (width == 1) {
-        return b.ty.u32();
-      }
-      return b.ty.vec<u32>(width);
-    };
-    auto V = [&](uint32_t value) -> const ast::Expression* {
-      return ScalarOrVector(width, value);
-    };
-    auto B = [&](const ast::Expression* value) -> const ast::Expression* {
-      if (width == 1) {
-        return b.Construct<bool>(value);
-      }
-      return b.Construct(b.ty.vec<bool>(width), value);
-    };
-    b.Func(
-        name, {b.Param("v", T(ty))}, T(ty),
-        {
-            // var x = U(v);
-            b.Decl(b.Var("x", nullptr, b.Construct(U(), b.Expr("v")))),
-            // let b16 = select(16, 0, bool(x & 0x0000ffff));
-            b.Decl(b.Const(
-                "b16", nullptr,
-                b.Call("select", V(16), V(0), B(b.And("x", V(0x0000ffff)))))),
-            // x = x >> b16;
-            b.Assign("x", b.Shr("x", "b16")),
-            // let b8  = select(8,  0, bool(x & 0x000000ff));
-            b.Decl(b.Const(
-                "b8", nullptr,
-                b.Call("select", V(8), V(0), B(b.And("x", V(0x000000ff)))))),
-            // x = x >> b8;
-            b.Assign("x", b.Shr("x", "b8")),
-            // let b4  = select(4,  0, bool(x & 0x0000000f));
-            b.Decl(b.Const(
-                "b4", nullptr,
-                b.Call("select", V(4), V(0), B(b.And("x", V(0x0000000f)))))),
-            // x = x >> b4;
-            b.Assign("x", b.Shr("x", "b4")),
-            // let b2  = select(2,  0, bool(x & 0x00000003));
-            b.Decl(b.Const(
-                "b2", nullptr,
-                b.Call("select", V(2), V(0), B(b.And("x", V(0x00000003)))))),
-            // x = x >> b2;
-            b.Assign("x", b.Shr("x", "b2")),
-            // let b1  = select(1,  0, bool(x & 0x00000001));
-            b.Decl(b.Const(
-                "b1", nullptr,
-                b.Call("select", V(1), V(0), B(b.And("x", V(0x00000001)))))),
-            // let is_zero  = select(0, 1, x == 0);
-            b.Decl(b.Const("is_zero", nullptr,
-                           b.Call("select", V(0), V(1), b.Equal("x", V(0))))),
-            // return R((b16 | b8 | b4 | b2 | b1) + zero);
-            b.Return(b.Construct(
-                T(ty),
-                b.Add(b.Or(b.Or(b.Or(b.Or("b16", "b8"), "b4"), "b2"), "b1"),
-                      "is_zero"))),
-        });
-    return name;
-  }
-
-  /// Builds the polyfill function for the `extractBits` builtin
-  /// @param ty the parameter and return type for the function
-  /// @return the polyfill function name
-  Symbol extractBits(const sem::Type* ty) {
-    auto name = b.Symbols().New("tint_extract_bits");
-    uint32_t width = WidthOf(ty);
-
-    constexpr uint32_t W = 32u;  // 32-bit
-
-    auto vecN_u32 =
-        [&](const ast::Expression* value) -> const ast::Expression* {
-      if (width == 1) {
-        return value;
-      }
-      return b.Construct(b.ty.vec<u32>(width), value);
-    };
-
-    ast::StatementList body = {
-        b.Decl(b.Const("s", nullptr, b.Call("min", "offset", W))),
-        b.Decl(b.Const("e", nullptr, b.Call("min", W, b.Add("s", "count")))),
-    };
-
-    switch (polyfill.extract_bits) {
-      case Level::kFull:
-        body.emplace_back(b.Decl(b.Const("shl", nullptr, b.Sub(W, "e"))));
-        body.emplace_back(b.Decl(b.Const("shr", nullptr, b.Add("shl", "s"))));
-        body.emplace_back(b.Return(b.Shr(b.Shl("v", vecN_u32(b.Expr("shl"))),
-                                         vecN_u32(b.Expr("shr")))));
-        break;
-      case Level::kClampParameters:
-        body.emplace_back(
-            b.Return(b.Call("extractBits", "v", "s", b.Sub("e", "s"))));
-        break;
-      default:
-        TINT_ICE(Transform, b.Diagnostics())
-            << "unhandled polyfill level: "
-            << static_cast<int>(polyfill.extract_bits);
-        return {};
+        // Returns either u32 or vecN<u32>
+        auto U = [&]() -> const ast::Type* {
+            if (width == 1) {
+                return b.ty.u32();
+            }
+            return b.ty.vec<u32>(width);
+        };
+        auto V = [&](uint32_t value) -> const ast::Expression* {
+            return ScalarOrVector(width, u32(value));
+        };
+        b.Func(
+            name, {b.Param("v", T(ty))}, T(ty),
+            {
+                // var x = U(v);
+                b.Decl(b.Var("x", nullptr, b.Construct(U(), b.Expr("v")))),
+                // let b16 = select(0, 16, x <= 0x0000ffff);
+                b.Decl(b.Let("b16", nullptr,
+                             b.Call("select", V(0), V(16), b.LessThanEqual("x", V(0x0000ffff))))),
+                // x = x << b16;
+                b.Assign("x", b.Shl("x", "b16")),
+                // let b8  = select(0, 8,  x <= 0x00ffffff);
+                b.Decl(b.Let("b8", nullptr,
+                             b.Call("select", V(0), V(8), b.LessThanEqual("x", V(0x00ffffff))))),
+                // x = x << b8;
+                b.Assign("x", b.Shl("x", "b8")),
+                // let b4  = select(0, 4,  x <= 0x0fffffff);
+                b.Decl(b.Let("b4", nullptr,
+                             b.Call("select", V(0), V(4), b.LessThanEqual("x", V(0x0fffffff))))),
+                // x = x << b4;
+                b.Assign("x", b.Shl("x", "b4")),
+                // let b2  = select(0, 2,  x <= 0x3fffffff);
+                b.Decl(b.Let("b2", nullptr,
+                             b.Call("select", V(0), V(2), b.LessThanEqual("x", V(0x3fffffff))))),
+                // x = x << b2;
+                b.Assign("x", b.Shl("x", "b2")),
+                // let b1  = select(0, 1,  x <= 0x7fffffff);
+                b.Decl(b.Let("b1", nullptr,
+                             b.Call("select", V(0), V(1), b.LessThanEqual("x", V(0x7fffffff))))),
+                // let is_zero  = select(0, 1, x == 0);
+                b.Decl(b.Let("is_zero", nullptr, b.Call("select", V(0), V(1), b.Equal("x", V(0))))),
+                // return R((b16 | b8 | b4 | b2 | b1) + zero);
+                b.Return(b.Construct(
+                    T(ty),
+                    b.Add(b.Or(b.Or(b.Or(b.Or("b16", "b8"), "b4"), "b2"), "b1"), "is_zero"))),
+            });
+        return name;
     }
 
-    b.Func(name,
-           {
-               b.Param("v", T(ty)),
-               b.Param("offset", b.ty.u32()),
-               b.Param("count", b.ty.u32()),
-           },
-           T(ty), body);
+    /// Builds the polyfill function for the `countTrailingZeros` builtin
+    /// @param ty the parameter and return type for the function
+    /// @return the polyfill function name
+    Symbol countTrailingZeros(const sem::Type* ty) {
+        auto name = b.Symbols().New("tint_count_trailing_zeros");
+        uint32_t width = WidthOf(ty);
 
-    return name;
-  }
-
-  /// Builds the polyfill function for the `firstLeadingBit` builtin
-  /// @param ty the parameter and return type for the function
-  /// @return the polyfill function name
-  Symbol firstLeadingBit(const sem::Type* ty) {
-    auto name = b.Symbols().New("tint_first_leading_bit");
-    uint32_t width = WidthOf(ty);
-
-    // Returns either u32 or vecN<u32>
-    auto U = [&]() -> const ast::Type* {
-      if (width == 1) {
-        return b.ty.u32();
-      }
-      return b.ty.vec<u32>(width);
-    };
-    auto V = [&](uint32_t value) -> const ast::Expression* {
-      return ScalarOrVector(width, value);
-    };
-    auto B = [&](const ast::Expression* value) -> const ast::Expression* {
-      if (width == 1) {
-        return b.Construct<bool>(value);
-      }
-      return b.Construct(b.ty.vec<bool>(width), value);
-    };
-
-    const ast::Expression* x = nullptr;
-    if (ty->is_unsigned_scalar_or_vector()) {
-      x = b.Expr("v");
-    } else {
-      // If ty is signed, then the value is inverted if the sign is negative
-      x = b.Call("select",                             //
-                 b.Construct(U(), "v"),                //
-                 b.Construct(U(), b.Complement("v")),  //
-                 b.LessThan("v", ScalarOrVector(width, 0)));
+        // Returns either u32 or vecN<u32>
+        auto U = [&]() -> const ast::Type* {
+            if (width == 1) {
+                return b.ty.u32();
+            }
+            return b.ty.vec<u32>(width);
+        };
+        auto V = [&](uint32_t value) -> const ast::Expression* {
+            return ScalarOrVector(width, u32(value));
+        };
+        auto B = [&](const ast::Expression* value) -> const ast::Expression* {
+            if (width == 1) {
+                return b.Construct<bool>(value);
+            }
+            return b.Construct(b.ty.vec<bool>(width), value);
+        };
+        b.Func(
+            name, {b.Param("v", T(ty))}, T(ty),
+            {
+                // var x = U(v);
+                b.Decl(b.Var("x", nullptr, b.Construct(U(), b.Expr("v")))),
+                // let b16 = select(16, 0, bool(x & 0x0000ffff));
+                b.Decl(b.Let("b16", nullptr,
+                             b.Call("select", V(16), V(0), B(b.And("x", V(0x0000ffff)))))),
+                // x = x >> b16;
+                b.Assign("x", b.Shr("x", "b16")),
+                // let b8  = select(8,  0, bool(x & 0x000000ff));
+                b.Decl(b.Let("b8", nullptr,
+                             b.Call("select", V(8), V(0), B(b.And("x", V(0x000000ff)))))),
+                // x = x >> b8;
+                b.Assign("x", b.Shr("x", "b8")),
+                // let b4  = select(4,  0, bool(x & 0x0000000f));
+                b.Decl(b.Let("b4", nullptr,
+                             b.Call("select", V(4), V(0), B(b.And("x", V(0x0000000f)))))),
+                // x = x >> b4;
+                b.Assign("x", b.Shr("x", "b4")),
+                // let b2  = select(2,  0, bool(x & 0x00000003));
+                b.Decl(b.Let("b2", nullptr,
+                             b.Call("select", V(2), V(0), B(b.And("x", V(0x00000003)))))),
+                // x = x >> b2;
+                b.Assign("x", b.Shr("x", "b2")),
+                // let b1  = select(1,  0, bool(x & 0x00000001));
+                b.Decl(b.Let("b1", nullptr,
+                             b.Call("select", V(1), V(0), B(b.And("x", V(0x00000001)))))),
+                // let is_zero  = select(0, 1, x == 0);
+                b.Decl(b.Let("is_zero", nullptr, b.Call("select", V(0), V(1), b.Equal("x", V(0))))),
+                // return R((b16 | b8 | b4 | b2 | b1) + zero);
+                b.Return(b.Construct(
+                    T(ty),
+                    b.Add(b.Or(b.Or(b.Or(b.Or("b16", "b8"), "b4"), "b2"), "b1"), "is_zero"))),
+            });
+        return name;
     }
 
-    b.Func(name, {b.Param("v", T(ty))}, T(ty),
-           {
-               // var x = v;                          (unsigned)
-               // var x = select(U(v), ~U(v), v < 0); (signed)
-               b.Decl(b.Var("x", nullptr, x)),
-               // let b16 = select(0, 16, bool(x & 0xffff0000));
-               b.Decl(b.Const("b16", nullptr,
-                              b.Call("select", V(0), V(16),
-                                     B(b.And("x", V(0xffff0000)))))),
-               // x = x >> b16;
-               b.Assign("x", b.Shr("x", "b16")),
-               // let b8  = select(0, 8,  bool(x & 0x0000ff00));
-               b.Decl(b.Const(
-                   "b8", nullptr,
-                   b.Call("select", V(0), V(8), B(b.And("x", V(0x0000ff00)))))),
-               // x = x >> b8;
-               b.Assign("x", b.Shr("x", "b8")),
-               // let b4  = select(0, 4,  bool(x & 0x000000f0));
-               b.Decl(b.Const(
-                   "b4", nullptr,
-                   b.Call("select", V(0), V(4), B(b.And("x", V(0x000000f0)))))),
-               // x = x >> b4;
-               b.Assign("x", b.Shr("x", "b4")),
-               // let b2  = select(0, 2,  bool(x & 0x0000000c));
-               b.Decl(b.Const(
-                   "b2", nullptr,
-                   b.Call("select", V(0), V(2), B(b.And("x", V(0x0000000c)))))),
-               // x = x >> b2;
-               b.Assign("x", b.Shr("x", "b2")),
-               // let b1  = select(0, 1,  bool(x & 0x00000002));
-               b.Decl(b.Const(
-                   "b1", nullptr,
-                   b.Call("select", V(0), V(1), B(b.And("x", V(0x00000002)))))),
-               // let is_zero  = select(0, 0xffffffff, x == 0);
-               b.Decl(b.Const("is_zero", nullptr,
-                              b.Call("select", V(0), V(0xffffffff),
-                                     b.Equal("x", V(0))))),
-               // return R(b16 | b8 | b4 | b2 | b1 | zero);
-               b.Return(b.Construct(
-                   T(ty),
-                   b.Or(b.Or(b.Or(b.Or(b.Or("b16", "b8"), "b4"), "b2"), "b1"),
-                        "is_zero"))),
-           });
-    return name;
-  }
+    /// Builds the polyfill function for the `extractBits` builtin
+    /// @param ty the parameter and return type for the function
+    /// @return the polyfill function name
+    Symbol extractBits(const sem::Type* ty) {
+        auto name = b.Symbols().New("tint_extract_bits");
+        uint32_t width = WidthOf(ty);
 
-  /// Builds the polyfill function for the `firstTrailingBit` builtin
-  /// @param ty the parameter and return type for the function
-  /// @return the polyfill function name
-  Symbol firstTrailingBit(const sem::Type* ty) {
-    auto name = b.Symbols().New("tint_first_trailing_bit");
-    uint32_t width = WidthOf(ty);
+        constexpr uint32_t W = 32u;  // 32-bit
 
-    // Returns either u32 or vecN<u32>
-    auto U = [&]() -> const ast::Type* {
-      if (width == 1) {
-        return b.ty.u32();
-      }
-      return b.ty.vec<u32>(width);
-    };
-    auto V = [&](uint32_t value) -> const ast::Expression* {
-      return ScalarOrVector(width, value);
-    };
-    auto B = [&](const ast::Expression* value) -> const ast::Expression* {
-      if (width == 1) {
-        return b.Construct<bool>(value);
-      }
-      return b.Construct(b.ty.vec<bool>(width), value);
-    };
-    b.Func(name, {b.Param("v", T(ty))}, T(ty),
-           {
-               // var x = U(v);
-               b.Decl(b.Var("x", nullptr, b.Construct(U(), b.Expr("v")))),
-               // let b16 = select(16, 0, bool(x & 0x0000ffff));
-               b.Decl(b.Const("b16", nullptr,
-                              b.Call("select", V(16), V(0),
-                                     B(b.And("x", V(0x0000ffff)))))),
-               // x = x >> b16;
-               b.Assign("x", b.Shr("x", "b16")),
-               // let b8  = select(8,  0, bool(x & 0x000000ff));
-               b.Decl(b.Const(
-                   "b8", nullptr,
-                   b.Call("select", V(8), V(0), B(b.And("x", V(0x000000ff)))))),
-               // x = x >> b8;
-               b.Assign("x", b.Shr("x", "b8")),
-               // let b4  = select(4,  0, bool(x & 0x0000000f));
-               b.Decl(b.Const(
-                   "b4", nullptr,
-                   b.Call("select", V(4), V(0), B(b.And("x", V(0x0000000f)))))),
-               // x = x >> b4;
-               b.Assign("x", b.Shr("x", "b4")),
-               // let b2  = select(2,  0, bool(x & 0x00000003));
-               b.Decl(b.Const(
-                   "b2", nullptr,
-                   b.Call("select", V(2), V(0), B(b.And("x", V(0x00000003)))))),
-               // x = x >> b2;
-               b.Assign("x", b.Shr("x", "b2")),
-               // let b1  = select(1,  0, bool(x & 0x00000001));
-               b.Decl(b.Const(
-                   "b1", nullptr,
-                   b.Call("select", V(1), V(0), B(b.And("x", V(0x00000001)))))),
-               // let is_zero  = select(0, 0xffffffff, x == 0);
-               b.Decl(b.Const("is_zero", nullptr,
-                              b.Call("select", V(0), V(0xffffffff),
-                                     b.Equal("x", V(0))))),
-               // return R(b16 | b8 | b4 | b2 | b1 | is_zero);
-               b.Return(b.Construct(
-                   T(ty),
-                   b.Or(b.Or(b.Or(b.Or(b.Or("b16", "b8"), "b4"), "b2"), "b1"),
-                        "is_zero"))),
-           });
-    return name;
-  }
+        auto vecN_u32 = [&](const ast::Expression* value) -> const ast::Expression* {
+            if (width == 1) {
+                return value;
+            }
+            return b.Construct(b.ty.vec<u32>(width), value);
+        };
 
-  /// Builds the polyfill function for the `insertBits` builtin
-  /// @param ty the parameter and return type for the function
-  /// @return the polyfill function name
-  Symbol insertBits(const sem::Type* ty) {
-    auto name = b.Symbols().New("tint_insert_bits");
-    uint32_t width = WidthOf(ty);
+        ast::StatementList body = {
+            b.Decl(b.Let("s", nullptr, b.Call("min", "offset", u32(W)))),
+            b.Decl(b.Let("e", nullptr, b.Call("min", u32(W), b.Add("s", "count")))),
+        };
 
-    constexpr uint32_t W = 32u;  // 32-bit
+        switch (polyfill.extract_bits) {
+            case Level::kFull:
+                body.emplace_back(b.Decl(b.Let("shl", nullptr, b.Sub(u32(W), "e"))));
+                body.emplace_back(b.Decl(b.Let("shr", nullptr, b.Add("shl", "s"))));
+                body.emplace_back(
+                    b.Return(b.Shr(b.Shl("v", vecN_u32(b.Expr("shl"))), vecN_u32(b.Expr("shr")))));
+                break;
+            case Level::kClampParameters:
+                body.emplace_back(b.Return(b.Call("extractBits", "v", "s", b.Sub("e", "s"))));
+                break;
+            default:
+                TINT_ICE(Transform, b.Diagnostics())
+                    << "unhandled polyfill level: " << static_cast<int>(polyfill.extract_bits);
+                return {};
+        }
 
-    auto V = [&](auto value) -> const ast::Expression* {
-      const ast::Expression* expr = b.Expr(value);
-      if (!ty->is_unsigned_scalar_or_vector()) {
-        expr = b.Construct<i32>(expr);
-      }
-      if (ty->Is<sem::Vector>()) {
-        expr = b.Construct(T(ty), expr);
-      }
-      return expr;
-    };
-    auto U = [&](auto value) -> const ast::Expression* {
-      if (width == 1) {
-        return b.Expr(value);
-      }
-      return b.vec(b.ty.u32(), width, value);
-    };
+        b.Func(name,
+               {
+                   b.Param("v", T(ty)),
+                   b.Param("offset", b.ty.u32()),
+                   b.Param("count", b.ty.u32()),
+               },
+               T(ty), body);
 
-    ast::StatementList body = {
-        b.Decl(b.Const("s", nullptr, b.Call("min", "offset", W))),
-        b.Decl(b.Const("e", nullptr, b.Call("min", W, b.Add("s", "count")))),
-    };
-
-    switch (polyfill.insert_bits) {
-      case Level::kFull:
-        // let mask = ((1 << s) - 1) ^ ((1 << e) - 1)
-        body.emplace_back(b.Decl(b.Const(
-            "mask", nullptr,
-            b.Xor(b.Sub(b.Shl(1u, "s"), 1u), b.Sub(b.Shl(1u, "e"), 1u)))));
-        // return ((n << s) & mask) | (v & ~mask)
-        body.emplace_back(b.Return(b.Or(b.And(b.Shl("n", U("s")), V("mask")),
-                                        b.And("v", V(b.Complement("mask"))))));
-        break;
-      case Level::kClampParameters:
-        body.emplace_back(
-            b.Return(b.Call("insertBits", "v", "n", "s", b.Sub("e", "s"))));
-        break;
-      default:
-        TINT_ICE(Transform, b.Diagnostics())
-            << "unhandled polyfill level: "
-            << static_cast<int>(polyfill.insert_bits);
-        return {};
+        return name;
     }
 
-    b.Func(name,
-           {
-               b.Param("v", T(ty)),
-               b.Param("n", T(ty)),
-               b.Param("offset", b.ty.u32()),
-               b.Param("count", b.ty.u32()),
-           },
-           T(ty), body);
+    /// Builds the polyfill function for the `firstLeadingBit` builtin
+    /// @param ty the parameter and return type for the function
+    /// @return the polyfill function name
+    Symbol firstLeadingBit(const sem::Type* ty) {
+        auto name = b.Symbols().New("tint_first_leading_bit");
+        uint32_t width = WidthOf(ty);
 
-    return name;
-  }
+        // Returns either u32 or vecN<u32>
+        auto U = [&]() -> const ast::Type* {
+            if (width == 1) {
+                return b.ty.u32();
+            }
+            return b.ty.vec<u32>(width);
+        };
+        auto V = [&](uint32_t value) -> const ast::Expression* {
+            return ScalarOrVector(width, u32(value));
+        };
+        auto B = [&](const ast::Expression* value) -> const ast::Expression* {
+            if (width == 1) {
+                return b.Construct<bool>(value);
+            }
+            return b.Construct(b.ty.vec<bool>(width), value);
+        };
 
- private:
-  /// Aliases
-  using u32 = ProgramBuilder::u32;
-  using i32 = ProgramBuilder::i32;
+        const ast::Expression* x = nullptr;
+        if (ty->is_unsigned_scalar_or_vector()) {
+            x = b.Expr("v");
+        } else {
+            // If ty is signed, then the value is inverted if the sign is negative
+            x = b.Call("select",                             //
+                       b.Construct(U(), "v"),                //
+                       b.Construct(U(), b.Complement("v")),  //
+                       b.LessThan("v", ScalarOrVector(width, 0_i)));
+        }
 
-  /// @returns the AST type for the given sem type
-  const ast::Type* T(const sem::Type* ty) const {
-    return CreateASTTypeFor(ctx, ty);
-  }
-
-  /// @returns 1 if `ty` is not a vector, otherwise the vector width
-  uint32_t WidthOf(const sem::Type* ty) const {
-    if (auto* v = ty->As<sem::Vector>()) {
-      return v->Width();
+        b.Func(
+            name, {b.Param("v", T(ty))}, T(ty),
+            {
+                // var x = v;                          (unsigned)
+                // var x = select(U(v), ~U(v), v < 0); (signed)
+                b.Decl(b.Var("x", nullptr, x)),
+                // let b16 = select(0, 16, bool(x & 0xffff0000));
+                b.Decl(b.Let("b16", nullptr,
+                             b.Call("select", V(0), V(16), B(b.And("x", V(0xffff0000)))))),
+                // x = x >> b16;
+                b.Assign("x", b.Shr("x", "b16")),
+                // let b8  = select(0, 8,  bool(x & 0x0000ff00));
+                b.Decl(b.Let("b8", nullptr,
+                             b.Call("select", V(0), V(8), B(b.And("x", V(0x0000ff00)))))),
+                // x = x >> b8;
+                b.Assign("x", b.Shr("x", "b8")),
+                // let b4  = select(0, 4,  bool(x & 0x000000f0));
+                b.Decl(b.Let("b4", nullptr,
+                             b.Call("select", V(0), V(4), B(b.And("x", V(0x000000f0)))))),
+                // x = x >> b4;
+                b.Assign("x", b.Shr("x", "b4")),
+                // let b2  = select(0, 2,  bool(x & 0x0000000c));
+                b.Decl(b.Let("b2", nullptr,
+                             b.Call("select", V(0), V(2), B(b.And("x", V(0x0000000c)))))),
+                // x = x >> b2;
+                b.Assign("x", b.Shr("x", "b2")),
+                // let b1  = select(0, 1,  bool(x & 0x00000002));
+                b.Decl(b.Let("b1", nullptr,
+                             b.Call("select", V(0), V(1), B(b.And("x", V(0x00000002)))))),
+                // let is_zero  = select(0, 0xffffffff, x == 0);
+                b.Decl(b.Let("is_zero", nullptr,
+                             b.Call("select", V(0), V(0xffffffff), b.Equal("x", V(0))))),
+                // return R(b16 | b8 | b4 | b2 | b1 | zero);
+                b.Return(b.Construct(
+                    T(ty), b.Or(b.Or(b.Or(b.Or(b.Or("b16", "b8"), "b4"), "b2"), "b1"), "is_zero"))),
+            });
+        return name;
     }
-    return 1;
-  }
 
-  /// @returns a scalar or vector with the given width, with each element with
-  /// the given value.
-  template <typename T>
-  const ast::Expression* ScalarOrVector(uint32_t width, T value) const {
-    if (width == 1) {
-      return b.Expr(value);
+    /// Builds the polyfill function for the `firstTrailingBit` builtin
+    /// @param ty the parameter and return type for the function
+    /// @return the polyfill function name
+    Symbol firstTrailingBit(const sem::Type* ty) {
+        auto name = b.Symbols().New("tint_first_trailing_bit");
+        uint32_t width = WidthOf(ty);
+
+        // Returns either u32 or vecN<u32>
+        auto U = [&]() -> const ast::Type* {
+            if (width == 1) {
+                return b.ty.u32();
+            }
+            return b.ty.vec<u32>(width);
+        };
+        auto V = [&](uint32_t value) -> const ast::Expression* {
+            return ScalarOrVector(width, u32(value));
+        };
+        auto B = [&](const ast::Expression* value) -> const ast::Expression* {
+            if (width == 1) {
+                return b.Construct<bool>(value);
+            }
+            return b.Construct(b.ty.vec<bool>(width), value);
+        };
+        b.Func(
+            name, {b.Param("v", T(ty))}, T(ty),
+            {
+                // var x = U(v);
+                b.Decl(b.Var("x", nullptr, b.Construct(U(), b.Expr("v")))),
+                // let b16 = select(16, 0, bool(x & 0x0000ffff));
+                b.Decl(b.Let("b16", nullptr,
+                             b.Call("select", V(16), V(0), B(b.And("x", V(0x0000ffff)))))),
+                // x = x >> b16;
+                b.Assign("x", b.Shr("x", "b16")),
+                // let b8  = select(8,  0, bool(x & 0x000000ff));
+                b.Decl(b.Let("b8", nullptr,
+                             b.Call("select", V(8), V(0), B(b.And("x", V(0x000000ff)))))),
+                // x = x >> b8;
+                b.Assign("x", b.Shr("x", "b8")),
+                // let b4  = select(4,  0, bool(x & 0x0000000f));
+                b.Decl(b.Let("b4", nullptr,
+                             b.Call("select", V(4), V(0), B(b.And("x", V(0x0000000f)))))),
+                // x = x >> b4;
+                b.Assign("x", b.Shr("x", "b4")),
+                // let b2  = select(2,  0, bool(x & 0x00000003));
+                b.Decl(b.Let("b2", nullptr,
+                             b.Call("select", V(2), V(0), B(b.And("x", V(0x00000003)))))),
+                // x = x >> b2;
+                b.Assign("x", b.Shr("x", "b2")),
+                // let b1  = select(1,  0, bool(x & 0x00000001));
+                b.Decl(b.Let("b1", nullptr,
+                             b.Call("select", V(1), V(0), B(b.And("x", V(0x00000001)))))),
+                // let is_zero  = select(0, 0xffffffff, x == 0);
+                b.Decl(b.Let("is_zero", nullptr,
+                             b.Call("select", V(0), V(0xffffffff), b.Equal("x", V(0))))),
+                // return R(b16 | b8 | b4 | b2 | b1 | is_zero);
+                b.Return(b.Construct(
+                    T(ty), b.Or(b.Or(b.Or(b.Or(b.Or("b16", "b8"), "b4"), "b2"), "b1"), "is_zero"))),
+            });
+        return name;
     }
-    return b.Construct(b.ty.vec<T>(width), value);
-  }
+
+    /// Builds the polyfill function for the `insertBits` builtin
+    /// @param ty the parameter and return type for the function
+    /// @return the polyfill function name
+    Symbol insertBits(const sem::Type* ty) {
+        auto name = b.Symbols().New("tint_insert_bits");
+        uint32_t width = WidthOf(ty);
+
+        constexpr uint32_t W = 32u;  // 32-bit
+
+        auto V = [&](auto value) -> const ast::Expression* {
+            const ast::Expression* expr = b.Expr(value);
+            if (!ty->is_unsigned_scalar_or_vector()) {
+                expr = b.Construct<i32>(expr);
+            }
+            if (ty->Is<sem::Vector>()) {
+                expr = b.Construct(T(ty), expr);
+            }
+            return expr;
+        };
+        auto U = [&](auto value) -> const ast::Expression* {
+            if (width == 1) {
+                return b.Expr(value);
+            }
+            return b.vec(b.ty.u32(), width, value);
+        };
+
+        ast::StatementList body = {
+            b.Decl(b.Let("s", nullptr, b.Call("min", "offset", u32(W)))),
+            b.Decl(b.Let("e", nullptr, b.Call("min", u32(W), b.Add("s", "count")))),
+        };
+
+        switch (polyfill.insert_bits) {
+            case Level::kFull:
+                // let mask = ((1 << s) - 1) ^ ((1 << e) - 1)
+                body.emplace_back(
+                    b.Decl(b.Let("mask", nullptr,
+                                 b.Xor(b.Sub(b.Shl(1_u, "s"), 1_u), b.Sub(b.Shl(1_u, "e"), 1_u)))));
+                // return ((n << s) & mask) | (v & ~mask)
+                body.emplace_back(b.Return(b.Or(b.And(b.Shl("n", U("s")), V("mask")),
+                                                b.And("v", V(b.Complement("mask"))))));
+                break;
+            case Level::kClampParameters:
+                body.emplace_back(b.Return(b.Call("insertBits", "v", "n", "s", b.Sub("e", "s"))));
+                break;
+            default:
+                TINT_ICE(Transform, b.Diagnostics())
+                    << "unhandled polyfill level: " << static_cast<int>(polyfill.insert_bits);
+                return {};
+        }
+
+        b.Func(name,
+               {
+                   b.Param("v", T(ty)),
+                   b.Param("n", T(ty)),
+                   b.Param("offset", b.ty.u32()),
+                   b.Param("count", b.ty.u32()),
+               },
+               T(ty), body);
+
+        return name;
+    }
+
+  private:
+    /// @returns the AST type for the given sem type
+    const ast::Type* T(const sem::Type* ty) const { return CreateASTTypeFor(ctx, ty); }
+
+    /// @returns 1 if `ty` is not a vector, otherwise the vector width
+    uint32_t WidthOf(const sem::Type* ty) const {
+        if (auto* v = ty->As<sem::Vector>()) {
+            return v->Width();
+        }
+        return 1;
+    }
+
+    /// @returns a scalar or vector with the given width, with each element with
+    /// the given value.
+    template <typename T>
+    const ast::Expression* ScalarOrVector(uint32_t width, T value) const {
+        if (width == 1) {
+            return b.Expr(value);
+        }
+        return b.Construct(b.ty.vec<T>(width), value);
+    }
 };
 
 BuiltinPolyfill::BuiltinPolyfill() = default;
 
 BuiltinPolyfill::~BuiltinPolyfill() = default;
 
-bool BuiltinPolyfill::ShouldRun(const Program* program,
-                                const DataMap& data) const {
-  if (auto* cfg = data.Get<Config>()) {
-    auto builtins = cfg->builtins;
-    auto& sem = program->Sem();
-    for (auto* node : program->ASTNodes().Objects()) {
-      if (auto* call = sem.Get<sem::Call>(node)) {
-        if (auto* builtin = call->Target()->As<sem::Builtin>()) {
-          switch (builtin->Type()) {
-            case sem::BuiltinType::kCountLeadingZeros:
-              if (builtins.count_leading_zeros) {
-                return true;
-              }
-              break;
-            case sem::BuiltinType::kCountTrailingZeros:
-              if (builtins.count_trailing_zeros) {
-                return true;
-              }
-              break;
-            case sem::BuiltinType::kExtractBits:
-              if (builtins.extract_bits != Level::kNone) {
-                return true;
-              }
-              break;
-            case sem::BuiltinType::kFirstLeadingBit:
-              if (builtins.first_leading_bit) {
-                return true;
-              }
-              break;
-            case sem::BuiltinType::kFirstTrailingBit:
-              if (builtins.first_trailing_bit) {
-                return true;
-              }
-              break;
-            case sem::BuiltinType::kInsertBits:
-              if (builtins.insert_bits != Level::kNone) {
-                return true;
-              }
-              break;
-            default:
-              break;
-          }
+bool BuiltinPolyfill::ShouldRun(const Program* program, const DataMap& data) const {
+    if (auto* cfg = data.Get<Config>()) {
+        auto builtins = cfg->builtins;
+        auto& sem = program->Sem();
+        for (auto* node : program->ASTNodes().Objects()) {
+            if (auto* call = sem.Get<sem::Call>(node)) {
+                if (auto* builtin = call->Target()->As<sem::Builtin>()) {
+                    switch (builtin->Type()) {
+                        case sem::BuiltinType::kCountLeadingZeros:
+                            if (builtins.count_leading_zeros) {
+                                return true;
+                            }
+                            break;
+                        case sem::BuiltinType::kCountTrailingZeros:
+                            if (builtins.count_trailing_zeros) {
+                                return true;
+                            }
+                            break;
+                        case sem::BuiltinType::kExtractBits:
+                            if (builtins.extract_bits != Level::kNone) {
+                                return true;
+                            }
+                            break;
+                        case sem::BuiltinType::kFirstLeadingBit:
+                            if (builtins.first_leading_bit) {
+                                return true;
+                            }
+                            break;
+                        case sem::BuiltinType::kFirstTrailingBit:
+                            if (builtins.first_trailing_bit) {
+                                return true;
+                            }
+                            break;
+                        case sem::BuiltinType::kInsertBits:
+                            if (builtins.insert_bits != Level::kNone) {
+                                return true;
+                            }
+                            break;
+                        default:
+                            break;
+                    }
+                }
+            }
         }
-      }
     }
-  }
-  return false;
+    return false;
 }
 
-void BuiltinPolyfill::Run(CloneContext& ctx,
-                          const DataMap& data,
-                          DataMap&) const {
-  auto* cfg = data.Get<Config>();
-  if (!cfg) {
-    ctx.Clone();
-    return;
-  }
+void BuiltinPolyfill::Run(CloneContext& ctx, const DataMap& data, DataMap&) const {
+    auto* cfg = data.Get<Config>();
+    if (!cfg) {
+        ctx.Clone();
+        return;
+    }
 
-  std::unordered_map<const sem::Builtin*, Symbol> polyfills;
+    std::unordered_map<const sem::Builtin*, Symbol> polyfills;
 
-  ctx.ReplaceAll(
-      [&](const ast::CallExpression* expr) -> const ast::CallExpression* {
+    ctx.ReplaceAll([&](const ast::CallExpression* expr) -> const ast::CallExpression* {
         auto builtins = cfg->builtins;
         State s{ctx, builtins};
         if (auto* call = s.sem.Get<sem::Call>(expr)) {
-          if (auto* builtin = call->Target()->As<sem::Builtin>()) {
-            Symbol polyfill;
-            switch (builtin->Type()) {
-              case sem::BuiltinType::kCountLeadingZeros:
-                if (builtins.count_leading_zeros) {
-                  polyfill = utils::GetOrCreate(polyfills, builtin, [&] {
-                    return s.countLeadingZeros(builtin->ReturnType());
-                  });
+            if (auto* builtin = call->Target()->As<sem::Builtin>()) {
+                Symbol polyfill;
+                switch (builtin->Type()) {
+                    case sem::BuiltinType::kCountLeadingZeros:
+                        if (builtins.count_leading_zeros) {
+                            polyfill = utils::GetOrCreate(polyfills, builtin, [&] {
+                                return s.countLeadingZeros(builtin->ReturnType());
+                            });
+                        }
+                        break;
+                    case sem::BuiltinType::kCountTrailingZeros:
+                        if (builtins.count_trailing_zeros) {
+                            polyfill = utils::GetOrCreate(polyfills, builtin, [&] {
+                                return s.countTrailingZeros(builtin->ReturnType());
+                            });
+                        }
+                        break;
+                    case sem::BuiltinType::kExtractBits:
+                        if (builtins.extract_bits != Level::kNone) {
+                            polyfill = utils::GetOrCreate(polyfills, builtin, [&] {
+                                return s.extractBits(builtin->ReturnType());
+                            });
+                        }
+                        break;
+                    case sem::BuiltinType::kFirstLeadingBit:
+                        if (builtins.first_leading_bit) {
+                            polyfill = utils::GetOrCreate(polyfills, builtin, [&] {
+                                return s.firstLeadingBit(builtin->ReturnType());
+                            });
+                        }
+                        break;
+                    case sem::BuiltinType::kFirstTrailingBit:
+                        if (builtins.first_trailing_bit) {
+                            polyfill = utils::GetOrCreate(polyfills, builtin, [&] {
+                                return s.firstTrailingBit(builtin->ReturnType());
+                            });
+                        }
+                        break;
+                    case sem::BuiltinType::kInsertBits:
+                        if (builtins.insert_bits != Level::kNone) {
+                            polyfill = utils::GetOrCreate(polyfills, builtin, [&] {
+                                return s.insertBits(builtin->ReturnType());
+                            });
+                        }
+                        break;
+                    default:
+                        break;
                 }
-                break;
-              case sem::BuiltinType::kCountTrailingZeros:
-                if (builtins.count_trailing_zeros) {
-                  polyfill = utils::GetOrCreate(polyfills, builtin, [&] {
-                    return s.countTrailingZeros(builtin->ReturnType());
-                  });
+                if (polyfill.IsValid()) {
+                    return s.b.Call(polyfill, ctx.Clone(call->Declaration()->args));
                 }
-                break;
-              case sem::BuiltinType::kExtractBits:
-                if (builtins.extract_bits != Level::kNone) {
-                  polyfill = utils::GetOrCreate(polyfills, builtin, [&] {
-                    return s.extractBits(builtin->ReturnType());
-                  });
-                }
-                break;
-              case sem::BuiltinType::kFirstLeadingBit:
-                if (builtins.first_leading_bit) {
-                  polyfill = utils::GetOrCreate(polyfills, builtin, [&] {
-                    return s.firstLeadingBit(builtin->ReturnType());
-                  });
-                }
-                break;
-              case sem::BuiltinType::kFirstTrailingBit:
-                if (builtins.first_trailing_bit) {
-                  polyfill = utils::GetOrCreate(polyfills, builtin, [&] {
-                    return s.firstTrailingBit(builtin->ReturnType());
-                  });
-                }
-                break;
-              case sem::BuiltinType::kInsertBits:
-                if (builtins.insert_bits != Level::kNone) {
-                  polyfill = utils::GetOrCreate(polyfills, builtin, [&] {
-                    return s.insertBits(builtin->ReturnType());
-                  });
-                }
-                break;
-              default:
-                break;
             }
-            if (polyfill.IsValid()) {
-              return s.b.Call(polyfill, ctx.Clone(call->Declaration()->args));
-            }
-          }
         }
         return nullptr;
-      });
+    });
 
-  ctx.Clone();
+    ctx.Clone();
 }
 
 BuiltinPolyfill::Config::Config(const Builtins& b) : builtins(b) {}
diff --git a/src/tint/transform/builtin_polyfill.h b/src/tint/transform/builtin_polyfill.h
index ada1015..8453189 100644
--- a/src/tint/transform/builtin_polyfill.h
+++ b/src/tint/transform/builtin_polyfill.h
@@ -21,73 +21,70 @@
 
 /// Implements builtins for backends that do not have a native implementation.
 class BuiltinPolyfill final : public Castable<BuiltinPolyfill, Transform> {
- public:
-  /// Constructor
-  BuiltinPolyfill();
-  /// Destructor
-  ~BuiltinPolyfill() override;
-
-  /// Enumerator of polyfill levels
-  enum class Level {
-    /// No polyfill needed, supported by the backend.
-    kNone,
-    /// Clamp the parameters to the inner implementation.
-    kClampParameters,
-    /// Polyfill the entire function
-    kFull,
-  };
-
-  /// Specifies the builtins that should be polyfilled by the transform.
-  struct Builtins {
-    /// Should `countLeadingZeros()` be polyfilled?
-    bool count_leading_zeros = false;
-    /// Should `countTrailingZeros()` be polyfilled?
-    bool count_trailing_zeros = false;
-    /// What level should `extractBits()` be polyfilled?
-    Level extract_bits = Level::kNone;
-    /// Should `firstLeadingBit()` be polyfilled?
-    bool first_leading_bit = false;
-    /// Should `firstTrailingBit()` be polyfilled?
-    bool first_trailing_bit = false;
-    /// Should `insertBits()` be polyfilled?
-    Level insert_bits = Level::kNone;
-  };
-
-  /// Config is consumed by the BuiltinPolyfill transform.
-  /// Config specifies the builtins that should be polyfilled.
-  struct Config final : public Castable<Data, transform::Data> {
+  public:
     /// Constructor
-    /// @param b the list of builtins to polyfill
-    explicit Config(const Builtins& b);
-
-    /// Copy constructor
-    Config(const Config&);
-
+    BuiltinPolyfill();
     /// Destructor
-    ~Config() override;
+    ~BuiltinPolyfill() override;
 
-    /// The builtins to polyfill
-    const Builtins builtins;
-  };
+    /// Enumerator of polyfill levels
+    enum class Level {
+        /// No polyfill needed, supported by the backend.
+        kNone,
+        /// Clamp the parameters to the inner implementation.
+        kClampParameters,
+        /// Polyfill the entire function
+        kFull,
+    };
 
-  /// @param program the program to inspect
-  /// @param data optional extra transform-specific input data
-  /// @returns true if this transform should be run for the given program
-  bool ShouldRun(const Program* program,
-                 const DataMap& data = {}) const override;
+    /// Specifies the builtins that should be polyfilled by the transform.
+    struct Builtins {
+        /// Should `countLeadingZeros()` be polyfilled?
+        bool count_leading_zeros = false;
+        /// Should `countTrailingZeros()` be polyfilled?
+        bool count_trailing_zeros = false;
+        /// What level should `extractBits()` be polyfilled?
+        Level extract_bits = Level::kNone;
+        /// Should `firstLeadingBit()` be polyfilled?
+        bool first_leading_bit = false;
+        /// Should `firstTrailingBit()` be polyfilled?
+        bool first_trailing_bit = false;
+        /// Should `insertBits()` be polyfilled?
+        Level insert_bits = Level::kNone;
+    };
 
- protected:
-  struct State;
+    /// Config is consumed by the BuiltinPolyfill transform.
+    /// Config specifies the builtins that should be polyfilled.
+    struct Config final : public Castable<Data, transform::Data> {
+        /// Constructor
+        /// @param b the list of builtins to polyfill
+        explicit Config(const Builtins& b);
 
-  /// Runs the transform using the CloneContext built for transforming a
-  /// program. Run() is responsible for calling Clone() on the CloneContext.
-  /// @param ctx the CloneContext primed with the input program and
-  /// ProgramBuilder
-  /// @param inputs optional extra transform-specific input data
-  /// @param outputs optional extra transform-specific output data
-  void Run(CloneContext& ctx,
-           const DataMap& inputs,
-           DataMap& outputs) const override;
+        /// Copy constructor
+        Config(const Config&);
+
+        /// Destructor
+        ~Config() override;
+
+        /// The builtins to polyfill
+        const Builtins builtins;
+    };
+
+    /// @param program the program to inspect
+    /// @param data optional extra transform-specific input data
+    /// @returns true if this transform should be run for the given program
+    bool ShouldRun(const Program* program, const DataMap& data = {}) const override;
+
+  protected:
+    struct State;
+
+    /// Runs the transform using the CloneContext built for transforming a
+    /// program. Run() is responsible for calling Clone() on the CloneContext.
+    /// @param ctx the CloneContext primed with the input program and
+    /// ProgramBuilder
+    /// @param inputs optional extra transform-specific input data
+    /// @param outputs optional extra transform-specific output data
+    void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const override;
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/builtin_polyfill_test.cc b/src/tint/transform/builtin_polyfill_test.cc
index c5cc2c5..bc3dda8 100644
--- a/src/tint/transform/builtin_polyfill_test.cc
+++ b/src/tint/transform/builtin_polyfill_test.cc
@@ -26,51 +26,51 @@
 using BuiltinPolyfillTest = TransformTest;
 
 TEST_F(BuiltinPolyfillTest, ShouldRunEmptyModule) {
-  auto* src = R"()";
+    auto* src = R"()";
 
-  EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
+    EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
 }
 
 TEST_F(BuiltinPolyfillTest, EmptyModule) {
-  auto* src = R"()";
+    auto* src = R"()";
 
-  auto* expect = src;
+    auto* expect = src;
 
-  auto got = Run<BuiltinPolyfill>(src);
+    auto got = Run<BuiltinPolyfill>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // countLeadingZeros
 ////////////////////////////////////////////////////////////////////////////////
 DataMap polyfillCountLeadingZeros() {
-  BuiltinPolyfill::Builtins builtins;
-  builtins.count_leading_zeros = true;
-  DataMap data;
-  data.Add<BuiltinPolyfill::Config>(builtins);
-  return data;
+    BuiltinPolyfill::Builtins builtins;
+    builtins.count_leading_zeros = true;
+    DataMap data;
+    data.Add<BuiltinPolyfill::Config>(builtins);
+    return data;
 }
 
 TEST_F(BuiltinPolyfillTest, ShouldRunCountLeadingZeros) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   countLeadingZeros(0xf);
 }
 )";
 
-  EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
-  EXPECT_TRUE(ShouldRun<BuiltinPolyfill>(src, polyfillCountLeadingZeros()));
+    EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
+    EXPECT_TRUE(ShouldRun<BuiltinPolyfill>(src, polyfillCountLeadingZeros()));
 }
 
 TEST_F(BuiltinPolyfillTest, CountLeadingZeros_i32) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let r : i32 = countLeadingZeros(15);
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn tint_count_leading_zeros(v : i32) -> i32 {
   var x = u32(v);
   let b16 = select(0u, 16u, (x <= 65535u));
@@ -91,19 +91,19 @@
 }
 )";
 
-  auto got = Run<BuiltinPolyfill>(src, polyfillCountLeadingZeros());
+    auto got = Run<BuiltinPolyfill>(src, polyfillCountLeadingZeros());
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(BuiltinPolyfillTest, CountLeadingZeros_u32) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let r : u32 = countLeadingZeros(15u);
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn tint_count_leading_zeros(v : u32) -> u32 {
   var x = u32(v);
   let b16 = select(0u, 16u, (x <= 65535u));
@@ -124,19 +124,19 @@
 }
 )";
 
-  auto got = Run<BuiltinPolyfill>(src, polyfillCountLeadingZeros());
+    auto got = Run<BuiltinPolyfill>(src, polyfillCountLeadingZeros());
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(BuiltinPolyfillTest, CountLeadingZeros_vec3_i32) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let r : vec3<i32> = countLeadingZeros(vec3<i32>(15));
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn tint_count_leading_zeros(v : vec3<i32>) -> vec3<i32> {
   var x = vec3<u32>(v);
   let b16 = select(vec3<u32>(0u), vec3<u32>(16u), (x <= vec3<u32>(65535u)));
@@ -157,19 +157,19 @@
 }
 )";
 
-  auto got = Run<BuiltinPolyfill>(src, polyfillCountLeadingZeros());
+    auto got = Run<BuiltinPolyfill>(src, polyfillCountLeadingZeros());
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(BuiltinPolyfillTest, CountLeadingZeros_vec3_u32) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let r : vec3<u32> = countLeadingZeros(vec3<u32>(15u));
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn tint_count_leading_zeros(v : vec3<u32>) -> vec3<u32> {
   var x = vec3<u32>(v);
   let b16 = select(vec3<u32>(0u), vec3<u32>(16u), (x <= vec3<u32>(65535u)));
@@ -190,41 +190,41 @@
 }
 )";
 
-  auto got = Run<BuiltinPolyfill>(src, polyfillCountLeadingZeros());
+    auto got = Run<BuiltinPolyfill>(src, polyfillCountLeadingZeros());
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // countTrailingZeros
 ////////////////////////////////////////////////////////////////////////////////
 DataMap polyfillCountTrailingZeros() {
-  BuiltinPolyfill::Builtins builtins;
-  builtins.count_trailing_zeros = true;
-  DataMap data;
-  data.Add<BuiltinPolyfill::Config>(builtins);
-  return data;
+    BuiltinPolyfill::Builtins builtins;
+    builtins.count_trailing_zeros = true;
+    DataMap data;
+    data.Add<BuiltinPolyfill::Config>(builtins);
+    return data;
 }
 
 TEST_F(BuiltinPolyfillTest, ShouldRunCountTrailingZeros) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   countTrailingZeros(0xf);
 }
 )";
 
-  EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
-  EXPECT_TRUE(ShouldRun<BuiltinPolyfill>(src, polyfillCountTrailingZeros()));
+    EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
+    EXPECT_TRUE(ShouldRun<BuiltinPolyfill>(src, polyfillCountTrailingZeros()));
 }
 
 TEST_F(BuiltinPolyfillTest, CountTrailingZeros_i32) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let r : i32 = countTrailingZeros(15);
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn tint_count_trailing_zeros(v : i32) -> i32 {
   var x = u32(v);
   let b16 = select(16u, 0u, bool((x & 65535u)));
@@ -245,19 +245,19 @@
 }
 )";
 
-  auto got = Run<BuiltinPolyfill>(src, polyfillCountTrailingZeros());
+    auto got = Run<BuiltinPolyfill>(src, polyfillCountTrailingZeros());
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(BuiltinPolyfillTest, CountTrailingZeros_u32) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let r : u32 = countTrailingZeros(15u);
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn tint_count_trailing_zeros(v : u32) -> u32 {
   var x = u32(v);
   let b16 = select(16u, 0u, bool((x & 65535u)));
@@ -278,19 +278,19 @@
 }
 )";
 
-  auto got = Run<BuiltinPolyfill>(src, polyfillCountTrailingZeros());
+    auto got = Run<BuiltinPolyfill>(src, polyfillCountTrailingZeros());
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(BuiltinPolyfillTest, CountTrailingZeros_vec3_i32) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let r : vec3<i32> = countTrailingZeros(vec3<i32>(15));
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn tint_count_trailing_zeros(v : vec3<i32>) -> vec3<i32> {
   var x = vec3<u32>(v);
   let b16 = select(vec3<u32>(16u), vec3<u32>(0u), vec3<bool>((x & vec3<u32>(65535u))));
@@ -311,19 +311,19 @@
 }
 )";
 
-  auto got = Run<BuiltinPolyfill>(src, polyfillCountTrailingZeros());
+    auto got = Run<BuiltinPolyfill>(src, polyfillCountTrailingZeros());
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(BuiltinPolyfillTest, CountTrailingZeros_vec3_u32) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let r : vec3<u32> = countTrailingZeros(vec3<u32>(15u));
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn tint_count_trailing_zeros(v : vec3<u32>) -> vec3<u32> {
   var x = vec3<u32>(v);
   let b16 = select(vec3<u32>(16u), vec3<u32>(0u), vec3<bool>((x & vec3<u32>(65535u))));
@@ -344,46 +344,43 @@
 }
 )";
 
-  auto got = Run<BuiltinPolyfill>(src, polyfillCountTrailingZeros());
+    auto got = Run<BuiltinPolyfill>(src, polyfillCountTrailingZeros());
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // extractBits
 ////////////////////////////////////////////////////////////////////////////////
 DataMap polyfillExtractBits(Level level) {
-  BuiltinPolyfill::Builtins builtins;
-  builtins.extract_bits = level;
-  DataMap data;
-  data.Add<BuiltinPolyfill::Config>(builtins);
-  return data;
+    BuiltinPolyfill::Builtins builtins;
+    builtins.extract_bits = level;
+    DataMap data;
+    data.Add<BuiltinPolyfill::Config>(builtins);
+    return data;
 }
 
 TEST_F(BuiltinPolyfillTest, ShouldRunExtractBits) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   extractBits(1234, 5u, 6u);
 }
 )";
 
-  EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
-  EXPECT_FALSE(
-      ShouldRun<BuiltinPolyfill>(src, polyfillExtractBits(Level::kNone)));
-  EXPECT_TRUE(ShouldRun<BuiltinPolyfill>(
-      src, polyfillExtractBits(Level::kClampParameters)));
-  EXPECT_TRUE(
-      ShouldRun<BuiltinPolyfill>(src, polyfillExtractBits(Level::kFull)));
+    EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
+    EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src, polyfillExtractBits(Level::kNone)));
+    EXPECT_TRUE(ShouldRun<BuiltinPolyfill>(src, polyfillExtractBits(Level::kClampParameters)));
+    EXPECT_TRUE(ShouldRun<BuiltinPolyfill>(src, polyfillExtractBits(Level::kFull)));
 }
 
 TEST_F(BuiltinPolyfillTest, ExtractBits_Full_i32) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let r : i32 = extractBits(1234, 5u, 6u);
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn tint_extract_bits(v : i32, offset : u32, count : u32) -> i32 {
   let s = min(offset, 32u);
   let e = min(32u, (s + count));
@@ -397,19 +394,19 @@
 }
 )";
 
-  auto got = Run<BuiltinPolyfill>(src, polyfillExtractBits(Level::kFull));
+    auto got = Run<BuiltinPolyfill>(src, polyfillExtractBits(Level::kFull));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(BuiltinPolyfillTest, ExtractBits_Full_u32) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let r : u32 = extractBits(1234u, 5u, 6u);
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn tint_extract_bits(v : u32, offset : u32, count : u32) -> u32 {
   let s = min(offset, 32u);
   let e = min(32u, (s + count));
@@ -423,19 +420,19 @@
 }
 )";
 
-  auto got = Run<BuiltinPolyfill>(src, polyfillExtractBits(Level::kFull));
+    auto got = Run<BuiltinPolyfill>(src, polyfillExtractBits(Level::kFull));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(BuiltinPolyfillTest, ExtractBits_Full_vec3_i32) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let r : vec3<i32> = extractBits(vec3<i32>(1234), 5u, 6u);
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn tint_extract_bits(v : vec3<i32>, offset : u32, count : u32) -> vec3<i32> {
   let s = min(offset, 32u);
   let e = min(32u, (s + count));
@@ -449,19 +446,19 @@
 }
 )";
 
-  auto got = Run<BuiltinPolyfill>(src, polyfillExtractBits(Level::kFull));
+    auto got = Run<BuiltinPolyfill>(src, polyfillExtractBits(Level::kFull));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(BuiltinPolyfillTest, ExtractBits_Full_vec3_u32) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let r : vec3<u32> = extractBits(vec3<u32>(1234u), 5u, 6u);
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn tint_extract_bits(v : vec3<u32>, offset : u32, count : u32) -> vec3<u32> {
   let s = min(offset, 32u);
   let e = min(32u, (s + count));
@@ -475,19 +472,19 @@
 }
 )";
 
-  auto got = Run<BuiltinPolyfill>(src, polyfillExtractBits(Level::kFull));
+    auto got = Run<BuiltinPolyfill>(src, polyfillExtractBits(Level::kFull));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(BuiltinPolyfillTest, ExtractBits_Clamp_i32) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let r : i32 = extractBits(1234, 5u, 6u);
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn tint_extract_bits(v : i32, offset : u32, count : u32) -> i32 {
   let s = min(offset, 32u);
   let e = min(32u, (s + count));
@@ -499,20 +496,19 @@
 }
 )";
 
-  auto got =
-      Run<BuiltinPolyfill>(src, polyfillExtractBits(Level::kClampParameters));
+    auto got = Run<BuiltinPolyfill>(src, polyfillExtractBits(Level::kClampParameters));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(BuiltinPolyfillTest, ExtractBits_Clamp_u32) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let r : u32 = extractBits(1234u, 5u, 6u);
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn tint_extract_bits(v : u32, offset : u32, count : u32) -> u32 {
   let s = min(offset, 32u);
   let e = min(32u, (s + count));
@@ -524,20 +520,19 @@
 }
 )";
 
-  auto got =
-      Run<BuiltinPolyfill>(src, polyfillExtractBits(Level::kClampParameters));
+    auto got = Run<BuiltinPolyfill>(src, polyfillExtractBits(Level::kClampParameters));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(BuiltinPolyfillTest, ExtractBits_Clamp_vec3_i32) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let r : vec3<i32> = extractBits(vec3<i32>(1234), 5u, 6u);
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn tint_extract_bits(v : vec3<i32>, offset : u32, count : u32) -> vec3<i32> {
   let s = min(offset, 32u);
   let e = min(32u, (s + count));
@@ -549,20 +544,19 @@
 }
 )";
 
-  auto got =
-      Run<BuiltinPolyfill>(src, polyfillExtractBits(Level::kClampParameters));
+    auto got = Run<BuiltinPolyfill>(src, polyfillExtractBits(Level::kClampParameters));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(BuiltinPolyfillTest, ExtractBits_Clamp_vec3_u32) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let r : vec3<u32> = extractBits(vec3<u32>(1234u), 5u, 6u);
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn tint_extract_bits(v : vec3<u32>, offset : u32, count : u32) -> vec3<u32> {
   let s = min(offset, 32u);
   let e = min(32u, (s + count));
@@ -574,44 +568,43 @@
 }
 )";
 
-  auto got =
-      Run<BuiltinPolyfill>(src, polyfillExtractBits(Level::kClampParameters));
+    auto got = Run<BuiltinPolyfill>(src, polyfillExtractBits(Level::kClampParameters));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // firstLeadingBit
 ////////////////////////////////////////////////////////////////////////////////
 DataMap polyfillFirstLeadingBit() {
-  BuiltinPolyfill::Builtins builtins;
-  builtins.first_leading_bit = true;
-  DataMap data;
-  data.Add<BuiltinPolyfill::Config>(builtins);
-  return data;
+    BuiltinPolyfill::Builtins builtins;
+    builtins.first_leading_bit = true;
+    DataMap data;
+    data.Add<BuiltinPolyfill::Config>(builtins);
+    return data;
 }
 
 TEST_F(BuiltinPolyfillTest, ShouldRunFirstLeadingBit) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   firstLeadingBit(0xf);
 }
 )";
 
-  EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
-  EXPECT_TRUE(ShouldRun<BuiltinPolyfill>(src, polyfillFirstLeadingBit()));
+    EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
+    EXPECT_TRUE(ShouldRun<BuiltinPolyfill>(src, polyfillFirstLeadingBit()));
 }
 
 TEST_F(BuiltinPolyfillTest, FirstLeadingBit_i32) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let r : i32 = firstLeadingBit(15);
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn tint_first_leading_bit(v : i32) -> i32 {
-  var x = select(u32(v), u32(~(v)), (v < 0));
+  var x = select(u32(v), u32(~(v)), (v < 0i));
   let b16 = select(0u, 16u, bool((x & 4294901760u)));
   x = (x >> b16);
   let b8 = select(0u, 8u, bool((x & 65280u)));
@@ -630,19 +623,19 @@
 }
 )";
 
-  auto got = Run<BuiltinPolyfill>(src, polyfillFirstLeadingBit());
+    auto got = Run<BuiltinPolyfill>(src, polyfillFirstLeadingBit());
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(BuiltinPolyfillTest, FirstLeadingBit_u32) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let r : u32 = firstLeadingBit(15u);
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn tint_first_leading_bit(v : u32) -> u32 {
   var x = v;
   let b16 = select(0u, 16u, bool((x & 4294901760u)));
@@ -663,21 +656,21 @@
 }
 )";
 
-  auto got = Run<BuiltinPolyfill>(src, polyfillFirstLeadingBit());
+    auto got = Run<BuiltinPolyfill>(src, polyfillFirstLeadingBit());
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(BuiltinPolyfillTest, FirstLeadingBit_vec3_i32) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let r : vec3<i32> = firstLeadingBit(vec3<i32>(15));
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn tint_first_leading_bit(v : vec3<i32>) -> vec3<i32> {
-  var x = select(vec3<u32>(v), vec3<u32>(~(v)), (v < vec3<i32>(0)));
+  var x = select(vec3<u32>(v), vec3<u32>(~(v)), (v < vec3<i32>(0i)));
   let b16 = select(vec3<u32>(0u), vec3<u32>(16u), vec3<bool>((x & vec3<u32>(4294901760u))));
   x = (x >> b16);
   let b8 = select(vec3<u32>(0u), vec3<u32>(8u), vec3<bool>((x & vec3<u32>(65280u))));
@@ -696,19 +689,19 @@
 }
 )";
 
-  auto got = Run<BuiltinPolyfill>(src, polyfillFirstLeadingBit());
+    auto got = Run<BuiltinPolyfill>(src, polyfillFirstLeadingBit());
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(BuiltinPolyfillTest, FirstLeadingBit_vec3_u32) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let r : vec3<u32> = firstLeadingBit(vec3<u32>(15u));
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn tint_first_leading_bit(v : vec3<u32>) -> vec3<u32> {
   var x = v;
   let b16 = select(vec3<u32>(0u), vec3<u32>(16u), vec3<bool>((x & vec3<u32>(4294901760u))));
@@ -729,41 +722,41 @@
 }
 )";
 
-  auto got = Run<BuiltinPolyfill>(src, polyfillFirstLeadingBit());
+    auto got = Run<BuiltinPolyfill>(src, polyfillFirstLeadingBit());
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // firstTrailingBit
 ////////////////////////////////////////////////////////////////////////////////
 DataMap polyfillFirstTrailingBit() {
-  BuiltinPolyfill::Builtins builtins;
-  builtins.first_trailing_bit = true;
-  DataMap data;
-  data.Add<BuiltinPolyfill::Config>(builtins);
-  return data;
+    BuiltinPolyfill::Builtins builtins;
+    builtins.first_trailing_bit = true;
+    DataMap data;
+    data.Add<BuiltinPolyfill::Config>(builtins);
+    return data;
 }
 
 TEST_F(BuiltinPolyfillTest, ShouldRunFirstTrailingBit) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   firstTrailingBit(0xf);
 }
 )";
 
-  EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
-  EXPECT_TRUE(ShouldRun<BuiltinPolyfill>(src, polyfillFirstTrailingBit()));
+    EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
+    EXPECT_TRUE(ShouldRun<BuiltinPolyfill>(src, polyfillFirstTrailingBit()));
 }
 
 TEST_F(BuiltinPolyfillTest, FirstTrailingBit_i32) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let r : i32 = firstTrailingBit(15);
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn tint_first_trailing_bit(v : i32) -> i32 {
   var x = u32(v);
   let b16 = select(16u, 0u, bool((x & 65535u)));
@@ -784,19 +777,19 @@
 }
 )";
 
-  auto got = Run<BuiltinPolyfill>(src, polyfillFirstTrailingBit());
+    auto got = Run<BuiltinPolyfill>(src, polyfillFirstTrailingBit());
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(BuiltinPolyfillTest, FirstTrailingBit_u32) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let r : u32 = firstTrailingBit(15u);
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn tint_first_trailing_bit(v : u32) -> u32 {
   var x = u32(v);
   let b16 = select(16u, 0u, bool((x & 65535u)));
@@ -817,19 +810,19 @@
 }
 )";
 
-  auto got = Run<BuiltinPolyfill>(src, polyfillFirstTrailingBit());
+    auto got = Run<BuiltinPolyfill>(src, polyfillFirstTrailingBit());
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(BuiltinPolyfillTest, FirstTrailingBit_vec3_i32) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let r : vec3<i32> = firstTrailingBit(vec3<i32>(15));
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn tint_first_trailing_bit(v : vec3<i32>) -> vec3<i32> {
   var x = vec3<u32>(v);
   let b16 = select(vec3<u32>(16u), vec3<u32>(0u), vec3<bool>((x & vec3<u32>(65535u))));
@@ -850,19 +843,19 @@
 }
 )";
 
-  auto got = Run<BuiltinPolyfill>(src, polyfillFirstTrailingBit());
+    auto got = Run<BuiltinPolyfill>(src, polyfillFirstTrailingBit());
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(BuiltinPolyfillTest, FirstTrailingBit_vec3_u32) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let r : vec3<u32> = firstTrailingBit(vec3<u32>(15u));
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn tint_first_trailing_bit(v : vec3<u32>) -> vec3<u32> {
   var x = vec3<u32>(v);
   let b16 = select(vec3<u32>(16u), vec3<u32>(0u), vec3<bool>((x & vec3<u32>(65535u))));
@@ -883,46 +876,43 @@
 }
 )";
 
-  auto got = Run<BuiltinPolyfill>(src, polyfillFirstTrailingBit());
+    auto got = Run<BuiltinPolyfill>(src, polyfillFirstTrailingBit());
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // insertBits
 ////////////////////////////////////////////////////////////////////////////////
 DataMap polyfillInsertBits(Level level) {
-  BuiltinPolyfill::Builtins builtins;
-  builtins.insert_bits = level;
-  DataMap data;
-  data.Add<BuiltinPolyfill::Config>(builtins);
-  return data;
+    BuiltinPolyfill::Builtins builtins;
+    builtins.insert_bits = level;
+    DataMap data;
+    data.Add<BuiltinPolyfill::Config>(builtins);
+    return data;
 }
 
 TEST_F(BuiltinPolyfillTest, ShouldRunInsertBits) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   insertBits(1234, 5678, 5u, 6u);
 }
 )";
 
-  EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
-  EXPECT_FALSE(
-      ShouldRun<BuiltinPolyfill>(src, polyfillInsertBits(Level::kNone)));
-  EXPECT_TRUE(ShouldRun<BuiltinPolyfill>(
-      src, polyfillInsertBits(Level::kClampParameters)));
-  EXPECT_TRUE(
-      ShouldRun<BuiltinPolyfill>(src, polyfillInsertBits(Level::kFull)));
+    EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src));
+    EXPECT_FALSE(ShouldRun<BuiltinPolyfill>(src, polyfillInsertBits(Level::kNone)));
+    EXPECT_TRUE(ShouldRun<BuiltinPolyfill>(src, polyfillInsertBits(Level::kClampParameters)));
+    EXPECT_TRUE(ShouldRun<BuiltinPolyfill>(src, polyfillInsertBits(Level::kFull)));
 }
 
 TEST_F(BuiltinPolyfillTest, InsertBits_Full_i32) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let r : i32 = insertBits(1234, 5678, 5u, 6u);
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn tint_insert_bits(v : i32, n : i32, offset : u32, count : u32) -> i32 {
   let s = min(offset, 32u);
   let e = min(32u, (s + count));
@@ -935,19 +925,19 @@
 }
 )";
 
-  auto got = Run<BuiltinPolyfill>(src, polyfillInsertBits(Level::kFull));
+    auto got = Run<BuiltinPolyfill>(src, polyfillInsertBits(Level::kFull));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(BuiltinPolyfillTest, InsertBits_Full_u32) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let r : u32 = insertBits(1234u, 5678u, 5u, 6u);
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn tint_insert_bits(v : u32, n : u32, offset : u32, count : u32) -> u32 {
   let s = min(offset, 32u);
   let e = min(32u, (s + count));
@@ -960,19 +950,19 @@
 }
 )";
 
-  auto got = Run<BuiltinPolyfill>(src, polyfillInsertBits(Level::kFull));
+    auto got = Run<BuiltinPolyfill>(src, polyfillInsertBits(Level::kFull));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(BuiltinPolyfillTest, InsertBits_Full_vec3_i32) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let r : vec3<i32> = insertBits(vec3<i32>(1234), vec3<i32>(5678), 5u, 6u);
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn tint_insert_bits(v : vec3<i32>, n : vec3<i32>, offset : u32, count : u32) -> vec3<i32> {
   let s = min(offset, 32u);
   let e = min(32u, (s + count));
@@ -985,19 +975,19 @@
 }
 )";
 
-  auto got = Run<BuiltinPolyfill>(src, polyfillInsertBits(Level::kFull));
+    auto got = Run<BuiltinPolyfill>(src, polyfillInsertBits(Level::kFull));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(BuiltinPolyfillTest, InsertBits_Full_vec3_u32) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let r : vec3<u32> = insertBits(vec3<u32>(1234u), vec3<u32>(5678u), 5u, 6u);
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn tint_insert_bits(v : vec3<u32>, n : vec3<u32>, offset : u32, count : u32) -> vec3<u32> {
   let s = min(offset, 32u);
   let e = min(32u, (s + count));
@@ -1010,19 +1000,19 @@
 }
 )";
 
-  auto got = Run<BuiltinPolyfill>(src, polyfillInsertBits(Level::kFull));
+    auto got = Run<BuiltinPolyfill>(src, polyfillInsertBits(Level::kFull));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(BuiltinPolyfillTest, InsertBits_Clamp_i32) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let r : i32 = insertBits(1234, 5678, 5u, 6u);
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn tint_insert_bits(v : i32, n : i32, offset : u32, count : u32) -> i32 {
   let s = min(offset, 32u);
   let e = min(32u, (s + count));
@@ -1034,20 +1024,19 @@
 }
 )";
 
-  auto got =
-      Run<BuiltinPolyfill>(src, polyfillInsertBits(Level::kClampParameters));
+    auto got = Run<BuiltinPolyfill>(src, polyfillInsertBits(Level::kClampParameters));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(BuiltinPolyfillTest, InsertBits_Clamp_u32) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let r : u32 = insertBits(1234u, 5678u, 5u, 6u);
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn tint_insert_bits(v : u32, n : u32, offset : u32, count : u32) -> u32 {
   let s = min(offset, 32u);
   let e = min(32u, (s + count));
@@ -1059,20 +1048,19 @@
 }
 )";
 
-  auto got =
-      Run<BuiltinPolyfill>(src, polyfillInsertBits(Level::kClampParameters));
+    auto got = Run<BuiltinPolyfill>(src, polyfillInsertBits(Level::kClampParameters));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(BuiltinPolyfillTest, InsertBits_Clamp_vec3_i32) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let r : vec3<i32> = insertBits(vec3<i32>(1234), vec3<i32>(5678), 5u, 6u);
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn tint_insert_bits(v : vec3<i32>, n : vec3<i32>, offset : u32, count : u32) -> vec3<i32> {
   let s = min(offset, 32u);
   let e = min(32u, (s + count));
@@ -1084,20 +1072,19 @@
 }
 )";
 
-  auto got =
-      Run<BuiltinPolyfill>(src, polyfillInsertBits(Level::kClampParameters));
+    auto got = Run<BuiltinPolyfill>(src, polyfillInsertBits(Level::kClampParameters));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(BuiltinPolyfillTest, InsertBits_Clamp_vec3_u32) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let r : vec3<u32> = insertBits(vec3<u32>(1234u), vec3<u32>(5678u), 5u, 6u);
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn tint_insert_bits(v : vec3<u32>, n : vec3<u32>, offset : u32, count : u32) -> vec3<u32> {
   let s = min(offset, 32u);
   let e = min(32u, (s + count));
@@ -1109,10 +1096,9 @@
 }
 )";
 
-  auto got =
-      Run<BuiltinPolyfill>(src, polyfillInsertBits(Level::kClampParameters));
+    auto got = Run<BuiltinPolyfill>(src, polyfillInsertBits(Level::kClampParameters));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 }  // namespace
diff --git a/src/tint/transform/calculate_array_length.cc b/src/tint/transform/calculate_array_length.cc
index 589d21e..42a212c 100644
--- a/src/tint/transform/calculate_array_length.cc
+++ b/src/tint/transform/calculate_array_length.cc
@@ -31,8 +31,9 @@
 #include "src/tint/utils/map.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::transform::CalculateArrayLength);
-TINT_INSTANTIATE_TYPEINFO(
-    tint::transform::CalculateArrayLength::BufferSizeIntrinsic);
+TINT_INSTANTIATE_TYPEINFO(tint::transform::CalculateArrayLength::BufferSizeIntrinsic);
+
+using namespace tint::number_suffixes;  // NOLINT
 
 namespace tint::transform {
 
@@ -41,201 +42,191 @@
 /// ArrayUsage describes a runtime array usage.
 /// It is used as a key by the array_length_by_usage map.
 struct ArrayUsage {
-  ast::BlockStatement const* const block;
-  sem::Variable const* const buffer;
-  bool operator==(const ArrayUsage& rhs) const {
-    return block == rhs.block && buffer == rhs.buffer;
-  }
-  struct Hasher {
-    inline std::size_t operator()(const ArrayUsage& u) const {
-      return utils::Hash(u.block, u.buffer);
+    ast::BlockStatement const* const block;
+    sem::Variable const* const buffer;
+    bool operator==(const ArrayUsage& rhs) const {
+        return block == rhs.block && buffer == rhs.buffer;
     }
-  };
+    struct Hasher {
+        inline std::size_t operator()(const ArrayUsage& u) const {
+            return utils::Hash(u.block, u.buffer);
+        }
+    };
 };
 
 }  // namespace
 
-CalculateArrayLength::BufferSizeIntrinsic::BufferSizeIntrinsic(ProgramID pid)
-    : Base(pid) {}
+CalculateArrayLength::BufferSizeIntrinsic::BufferSizeIntrinsic(ProgramID pid) : Base(pid) {}
 CalculateArrayLength::BufferSizeIntrinsic::~BufferSizeIntrinsic() = default;
 std::string CalculateArrayLength::BufferSizeIntrinsic::InternalName() const {
-  return "intrinsic_buffer_size";
+    return "intrinsic_buffer_size";
 }
 
-const CalculateArrayLength::BufferSizeIntrinsic*
-CalculateArrayLength::BufferSizeIntrinsic::Clone(CloneContext* ctx) const {
-  return ctx->dst->ASTNodes().Create<CalculateArrayLength::BufferSizeIntrinsic>(
-      ctx->dst->ID());
+const CalculateArrayLength::BufferSizeIntrinsic* CalculateArrayLength::BufferSizeIntrinsic::Clone(
+    CloneContext* ctx) const {
+    return ctx->dst->ASTNodes().Create<CalculateArrayLength::BufferSizeIntrinsic>(ctx->dst->ID());
 }
 
 CalculateArrayLength::CalculateArrayLength() = default;
 CalculateArrayLength::~CalculateArrayLength() = default;
 
-bool CalculateArrayLength::ShouldRun(const Program* program,
-                                     const DataMap&) const {
-  for (auto* fn : program->AST().Functions()) {
-    if (auto* sem_fn = program->Sem().Get(fn)) {
-      for (auto* builtin : sem_fn->DirectlyCalledBuiltins()) {
-        if (builtin->Type() == sem::BuiltinType::kArrayLength) {
-          return true;
+bool CalculateArrayLength::ShouldRun(const Program* program, const DataMap&) const {
+    for (auto* fn : program->AST().Functions()) {
+        if (auto* sem_fn = program->Sem().Get(fn)) {
+            for (auto* builtin : sem_fn->DirectlyCalledBuiltins()) {
+                if (builtin->Type() == sem::BuiltinType::kArrayLength) {
+                    return true;
+                }
+            }
         }
-      }
     }
-  }
-  return false;
+    return false;
 }
 
-void CalculateArrayLength::Run(CloneContext& ctx,
-                               const DataMap&,
-                               DataMap&) const {
-  auto& sem = ctx.src->Sem();
+void CalculateArrayLength::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
+    auto& sem = ctx.src->Sem();
 
-  // get_buffer_size_intrinsic() emits the function decorated with
-  // BufferSizeIntrinsic that is transformed by the HLSL writer into a call to
-  // [RW]ByteAddressBuffer.GetDimensions().
-  std::unordered_map<const sem::Type*, Symbol> buffer_size_intrinsics;
-  auto get_buffer_size_intrinsic = [&](const sem::Type* buffer_type) {
-    return utils::GetOrCreate(buffer_size_intrinsics, buffer_type, [&] {
-      auto name = ctx.dst->Sym();
-      auto* type = CreateASTTypeFor(ctx, buffer_type);
-      auto* disable_validation = ctx.dst->Disable(
-          ast::DisabledValidation::kIgnoreConstructibleFunctionParameter);
-      ctx.dst->AST().AddFunction(ctx.dst->create<ast::Function>(
-          name,
-          ast::VariableList{
-              // Note: The buffer parameter requires the kStorage StorageClass
-              // in order for HLSL to emit this as a ByteAddressBuffer.
-              ctx.dst->create<ast::Variable>(
-                  ctx.dst->Sym("buffer"), ast::StorageClass::kStorage,
-                  ast::Access::kUndefined, type, true, false, nullptr,
-                  ast::AttributeList{disable_validation}),
-              ctx.dst->Param("result",
-                             ctx.dst->ty.pointer(ctx.dst->ty.u32(),
-                                                 ast::StorageClass::kFunction)),
-          },
-          ctx.dst->ty.void_(), nullptr,
-          ast::AttributeList{
-              ctx.dst->ASTNodes().Create<BufferSizeIntrinsic>(ctx.dst->ID()),
-          },
-          ast::AttributeList{}));
+    // get_buffer_size_intrinsic() emits the function decorated with
+    // BufferSizeIntrinsic that is transformed by the HLSL writer into a call to
+    // [RW]ByteAddressBuffer.GetDimensions().
+    std::unordered_map<const sem::Type*, Symbol> buffer_size_intrinsics;
+    auto get_buffer_size_intrinsic = [&](const sem::Type* buffer_type) {
+        return utils::GetOrCreate(buffer_size_intrinsics, buffer_type, [&] {
+            auto name = ctx.dst->Sym();
+            auto* type = CreateASTTypeFor(ctx, buffer_type);
+            auto* disable_validation =
+                ctx.dst->Disable(ast::DisabledValidation::kIgnoreConstructibleFunctionParameter);
+            ctx.dst->AST().AddFunction(ctx.dst->create<ast::Function>(
+                name,
+                ast::VariableList{
+                    // Note: The buffer parameter requires the kStorage StorageClass
+                    // in order for HLSL to emit this as a ByteAddressBuffer.
+                    ctx.dst->create<ast::Variable>(ctx.dst->Sym("buffer"),
+                                                   ast::StorageClass::kStorage,
+                                                   ast::Access::kUndefined, type, true, false,
+                                                   nullptr, ast::AttributeList{disable_validation}),
+                    ctx.dst->Param("result", ctx.dst->ty.pointer(ctx.dst->ty.u32(),
+                                                                 ast::StorageClass::kFunction)),
+                },
+                ctx.dst->ty.void_(), nullptr,
+                ast::AttributeList{
+                    ctx.dst->ASTNodes().Create<BufferSizeIntrinsic>(ctx.dst->ID()),
+                },
+                ast::AttributeList{}));
 
-      return name;
-    });
-  };
+            return name;
+        });
+    };
 
-  std::unordered_map<ArrayUsage, Symbol, ArrayUsage::Hasher>
-      array_length_by_usage;
+    std::unordered_map<ArrayUsage, Symbol, ArrayUsage::Hasher> array_length_by_usage;
 
-  // Find all the arrayLength() calls...
-  for (auto* node : ctx.src->ASTNodes().Objects()) {
-    if (auto* call_expr = node->As<ast::CallExpression>()) {
-      auto* call = sem.Get(call_expr);
-      if (auto* builtin = call->Target()->As<sem::Builtin>()) {
-        if (builtin->Type() == sem::BuiltinType::kArrayLength) {
-          // We're dealing with an arrayLength() call
+    // Find all the arrayLength() calls...
+    for (auto* node : ctx.src->ASTNodes().Objects()) {
+        if (auto* call_expr = node->As<ast::CallExpression>()) {
+            auto* call = sem.Get(call_expr);
+            if (auto* builtin = call->Target()->As<sem::Builtin>()) {
+                if (builtin->Type() == sem::BuiltinType::kArrayLength) {
+                    // We're dealing with an arrayLength() call
 
-          // A runtime-sized array can only appear as the store type of a
-          // variable, or the last element of a structure (which cannot itself
-          // be nested). Given that we require SimplifyPointers, we can assume
-          // that the arrayLength() call has one of two forms:
-          //   arrayLength(&struct_var.array_member)
-          //   arrayLength(&array_var)
-          auto* arg = call_expr->args[0];
-          auto* address_of = arg->As<ast::UnaryOpExpression>();
-          if (!address_of || address_of->op != ast::UnaryOp::kAddressOf) {
-            TINT_ICE(Transform, ctx.dst->Diagnostics())
-                << "arrayLength() expected address-of, got "
-                << arg->TypeInfo().name;
-          }
-          auto* storage_buffer_expr = address_of->expr;
-          if (auto* accessor =
-                  storage_buffer_expr->As<ast::MemberAccessorExpression>()) {
-            storage_buffer_expr = accessor->structure;
-          }
-          auto* storage_buffer_sem =
-              sem.Get<sem::VariableUser>(storage_buffer_expr);
-          if (!storage_buffer_sem) {
-            TINT_ICE(Transform, ctx.dst->Diagnostics())
-                << "expected form of arrayLength argument to be &array_var or "
-                   "&struct_var.array_member";
-            break;
-          }
-          auto* storage_buffer_var = storage_buffer_sem->Variable();
-          auto* storage_buffer_type = storage_buffer_sem->Type()->UnwrapRef();
+                    // A runtime-sized array can only appear as the store type of a
+                    // variable, or the last element of a structure (which cannot itself
+                    // be nested). Given that we require SimplifyPointers, we can assume
+                    // that the arrayLength() call has one of two forms:
+                    //   arrayLength(&struct_var.array_member)
+                    //   arrayLength(&array_var)
+                    auto* arg = call_expr->args[0];
+                    auto* address_of = arg->As<ast::UnaryOpExpression>();
+                    if (!address_of || address_of->op != ast::UnaryOp::kAddressOf) {
+                        TINT_ICE(Transform, ctx.dst->Diagnostics())
+                            << "arrayLength() expected address-of, got " << arg->TypeInfo().name;
+                    }
+                    auto* storage_buffer_expr = address_of->expr;
+                    if (auto* accessor = storage_buffer_expr->As<ast::MemberAccessorExpression>()) {
+                        storage_buffer_expr = accessor->structure;
+                    }
+                    auto* storage_buffer_sem = sem.Get<sem::VariableUser>(storage_buffer_expr);
+                    if (!storage_buffer_sem) {
+                        TINT_ICE(Transform, ctx.dst->Diagnostics())
+                            << "expected form of arrayLength argument to be &array_var or "
+                               "&struct_var.array_member";
+                        break;
+                    }
+                    auto* storage_buffer_var = storage_buffer_sem->Variable();
+                    auto* storage_buffer_type = storage_buffer_sem->Type()->UnwrapRef();
 
-          // Generate BufferSizeIntrinsic for this storage type if we haven't
-          // already
-          auto buffer_size = get_buffer_size_intrinsic(storage_buffer_type);
+                    // Generate BufferSizeIntrinsic for this storage type if we haven't
+                    // already
+                    auto buffer_size = get_buffer_size_intrinsic(storage_buffer_type);
 
-          // Find the current statement block
-          auto* block = call->Stmt()->Block()->Declaration();
+                    // Find the current statement block
+                    auto* block = call->Stmt()->Block()->Declaration();
 
-          auto array_length = utils::GetOrCreate(
-              array_length_by_usage, {block, storage_buffer_var}, [&] {
-                // First time this array length is used for this block.
-                // Let's calculate it.
+                    auto array_length =
+                        utils::GetOrCreate(array_length_by_usage, {block, storage_buffer_var}, [&] {
+                            // First time this array length is used for this block.
+                            // Let's calculate it.
 
-                // Construct the variable that'll hold the result of
-                // RWByteAddressBuffer.GetDimensions()
-                auto* buffer_size_result = ctx.dst->Decl(
-                    ctx.dst->Var(ctx.dst->Sym(), ctx.dst->ty.u32(),
-                                 ast::StorageClass::kNone, ctx.dst->Expr(0u)));
+                            // Construct the variable that'll hold the result of
+                            // RWByteAddressBuffer.GetDimensions()
+                            auto* buffer_size_result = ctx.dst->Decl(
+                                ctx.dst->Var(ctx.dst->Sym(), ctx.dst->ty.u32(),
+                                             ast::StorageClass::kNone, ctx.dst->Expr(0_u)));
 
-                // Call storage_buffer.GetDimensions(&buffer_size_result)
-                auto* call_get_dims = ctx.dst->CallStmt(ctx.dst->Call(
-                    // BufferSizeIntrinsic(X, ARGS...) is
-                    // translated to:
-                    //  X.GetDimensions(ARGS..) by the writer
-                    buffer_size, ctx.Clone(storage_buffer_expr),
-                    ctx.dst->AddressOf(
-                        ctx.dst->Expr(buffer_size_result->variable->symbol))));
+                            // Call storage_buffer.GetDimensions(&buffer_size_result)
+                            auto* call_get_dims = ctx.dst->CallStmt(ctx.dst->Call(
+                                // BufferSizeIntrinsic(X, ARGS...) is
+                                // translated to:
+                                //  X.GetDimensions(ARGS..) by the writer
+                                buffer_size, ctx.Clone(storage_buffer_expr),
+                                ctx.dst->AddressOf(
+                                    ctx.dst->Expr(buffer_size_result->variable->symbol))));
 
-                // Calculate actual array length
-                //                total_storage_buffer_size - array_offset
-                // array_length = ----------------------------------------
-                //                             array_stride
-                auto name = ctx.dst->Sym();
-                const ast::Expression* total_size =
-                    ctx.dst->Expr(buffer_size_result->variable);
-                const sem::Array* array_type = nullptr;
-                if (auto* str = storage_buffer_type->As<sem::Struct>()) {
-                  // The variable is a struct, so subtract the byte offset of
-                  // the array member.
-                  auto* array_member_sem = str->Members().back();
-                  array_type = array_member_sem->Type()->As<sem::Array>();
-                  total_size =
-                      ctx.dst->Sub(total_size, array_member_sem->Offset());
-                } else if (auto* arr = storage_buffer_type->As<sem::Array>()) {
-                  array_type = arr;
-                } else {
-                  TINT_ICE(Transform, ctx.dst->Diagnostics())
-                      << "expected form of arrayLength argument to be "
-                         "&array_var or &struct_var.array_member";
-                  return name;
+                            // Calculate actual array length
+                            //                total_storage_buffer_size - array_offset
+                            // array_length = ----------------------------------------
+                            //                             array_stride
+                            auto name = ctx.dst->Sym();
+                            const ast::Expression* total_size =
+                                ctx.dst->Expr(buffer_size_result->variable);
+                            const sem::Array* array_type = nullptr;
+                            if (auto* str = storage_buffer_type->As<sem::Struct>()) {
+                                // The variable is a struct, so subtract the byte offset of
+                                // the array member.
+                                auto* array_member_sem = str->Members().back();
+                                array_type = array_member_sem->Type()->As<sem::Array>();
+                                total_size =
+                                    ctx.dst->Sub(total_size, u32(array_member_sem->Offset()));
+                            } else if (auto* arr = storage_buffer_type->As<sem::Array>()) {
+                                array_type = arr;
+                            } else {
+                                TINT_ICE(Transform, ctx.dst->Diagnostics())
+                                    << "expected form of arrayLength argument to be "
+                                       "&array_var or &struct_var.array_member";
+                                return name;
+                            }
+                            uint32_t array_stride = array_type->Size();
+                            auto* array_length_var = ctx.dst->Decl(
+                                ctx.dst->Let(name, ctx.dst->ty.u32(),
+                                             ctx.dst->Div(total_size, u32(array_stride))));
+
+                            // Insert the array length calculations at the top of the block
+                            ctx.InsertBefore(block->statements, block->statements[0],
+                                             buffer_size_result);
+                            ctx.InsertBefore(block->statements, block->statements[0],
+                                             call_get_dims);
+                            ctx.InsertBefore(block->statements, block->statements[0],
+                                             array_length_var);
+                            return name;
+                        });
+
+                    // Replace the call to arrayLength() with the array length variable
+                    ctx.Replace(call_expr, ctx.dst->Expr(array_length));
                 }
-                uint32_t array_stride = array_type->Size();
-                auto* array_length_var = ctx.dst->Decl(
-                    ctx.dst->Const(name, ctx.dst->ty.u32(),
-                                   ctx.dst->Div(total_size, array_stride)));
-
-                // Insert the array length calculations at the top of the block
-                ctx.InsertBefore(block->statements, block->statements[0],
-                                 buffer_size_result);
-                ctx.InsertBefore(block->statements, block->statements[0],
-                                 call_get_dims);
-                ctx.InsertBefore(block->statements, block->statements[0],
-                                 array_length_var);
-                return name;
-              });
-
-          // Replace the call to arrayLength() with the array length variable
-          ctx.Replace(call_expr, ctx.dst->Expr(array_length));
+            }
         }
-      }
     }
-  }
 
-  ctx.Clone();
+    ctx.Clone();
 }
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/calculate_array_length.h b/src/tint/transform/calculate_array_length.h
index 344f6f0..401e081 100644
--- a/src/tint/transform/calculate_array_length.h
+++ b/src/tint/transform/calculate_array_length.h
@@ -32,50 +32,45 @@
 ///
 /// @note Depends on the following transforms to have been run first:
 /// * SimplifyPointers
-class CalculateArrayLength final
-    : public Castable<CalculateArrayLength, Transform> {
- public:
-  /// BufferSizeIntrinsic is an InternalAttribute that's applied to intrinsic
-  /// functions used to obtain the runtime size of a storage buffer.
-  class BufferSizeIntrinsic final
-      : public Castable<BufferSizeIntrinsic, ast::InternalAttribute> {
-   public:
+class CalculateArrayLength final : public Castable<CalculateArrayLength, Transform> {
+  public:
+    /// BufferSizeIntrinsic is an InternalAttribute that's applied to intrinsic
+    /// functions used to obtain the runtime size of a storage buffer.
+    class BufferSizeIntrinsic final : public Castable<BufferSizeIntrinsic, ast::InternalAttribute> {
+      public:
+        /// Constructor
+        /// @param program_id the identifier of the program that owns this node
+        explicit BufferSizeIntrinsic(ProgramID program_id);
+        /// Destructor
+        ~BufferSizeIntrinsic() override;
+
+        /// @return "buffer_size"
+        std::string InternalName() const override;
+
+        /// Performs a deep clone of this object using the CloneContext `ctx`.
+        /// @param ctx the clone context
+        /// @return the newly cloned object
+        const BufferSizeIntrinsic* Clone(CloneContext* ctx) const override;
+    };
+
     /// Constructor
-    /// @param program_id the identifier of the program that owns this node
-    explicit BufferSizeIntrinsic(ProgramID program_id);
+    CalculateArrayLength();
     /// Destructor
-    ~BufferSizeIntrinsic() override;
+    ~CalculateArrayLength() override;
 
-    /// @return "buffer_size"
-    std::string InternalName() const override;
+    /// @param program the program to inspect
+    /// @param data optional extra transform-specific input data
+    /// @returns true if this transform should be run for the given program
+    bool ShouldRun(const Program* program, const DataMap& data = {}) const override;
 
-    /// Performs a deep clone of this object using the CloneContext `ctx`.
-    /// @param ctx the clone context
-    /// @return the newly cloned object
-    const BufferSizeIntrinsic* Clone(CloneContext* ctx) const override;
-  };
-
-  /// Constructor
-  CalculateArrayLength();
-  /// Destructor
-  ~CalculateArrayLength() override;
-
-  /// @param program the program to inspect
-  /// @param data optional extra transform-specific input data
-  /// @returns true if this transform should be run for the given program
-  bool ShouldRun(const Program* program,
-                 const DataMap& data = {}) const override;
-
- protected:
-  /// Runs the transform using the CloneContext built for transforming a
-  /// program. Run() is responsible for calling Clone() on the CloneContext.
-  /// @param ctx the CloneContext primed with the input program and
-  /// ProgramBuilder
-  /// @param inputs optional extra transform-specific input data
-  /// @param outputs optional extra transform-specific output data
-  void Run(CloneContext& ctx,
-           const DataMap& inputs,
-           DataMap& outputs) const override;
+  protected:
+    /// Runs the transform using the CloneContext built for transforming a
+    /// program. Run() is responsible for calling Clone() on the CloneContext.
+    /// @param ctx the CloneContext primed with the input program and
+    /// ProgramBuilder
+    /// @param inputs optional extra transform-specific input data
+    /// @param outputs optional extra transform-specific output data
+    void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const override;
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/calculate_array_length_test.cc b/src/tint/transform/calculate_array_length_test.cc
index dec1698..9c7c3ac 100644
--- a/src/tint/transform/calculate_array_length_test.cc
+++ b/src/tint/transform/calculate_array_length_test.cc
@@ -24,13 +24,13 @@
 using CalculateArrayLengthTest = TransformTest;
 
 TEST_F(CalculateArrayLengthTest, ShouldRunEmptyModule) {
-  auto* src = R"()";
+    auto* src = R"()";
 
-  EXPECT_FALSE(ShouldRun<CalculateArrayLength>(src));
+    EXPECT_FALSE(ShouldRun<CalculateArrayLength>(src));
 }
 
 TEST_F(CalculateArrayLengthTest, ShouldRunNoArrayLength) {
-  auto* src = R"(
+    auto* src = R"(
 struct SB {
   x : i32,
   arr : array<i32>,
@@ -43,11 +43,11 @@
 }
 )";
 
-  EXPECT_FALSE(ShouldRun<CalculateArrayLength>(src));
+    EXPECT_FALSE(ShouldRun<CalculateArrayLength>(src));
 }
 
 TEST_F(CalculateArrayLengthTest, ShouldRunWithArrayLength) {
-  auto* src = R"(
+    auto* src = R"(
 struct SB {
   x : i32,
   arr : array<i32>,
@@ -61,11 +61,11 @@
 }
 )";
 
-  EXPECT_TRUE(ShouldRun<CalculateArrayLength>(src));
+    EXPECT_TRUE(ShouldRun<CalculateArrayLength>(src));
 }
 
 TEST_F(CalculateArrayLengthTest, BasicArray) {
-  auto* src = R"(
+    auto* src = R"(
 @group(0) @binding(0) var<storage, read> sb : array<i32>;
 
 @stage(compute) @workgroup_size(1)
@@ -74,7 +74,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @internal(intrinsic_buffer_size)
 fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : array<i32>, result : ptr<function, u32>)
 
@@ -89,13 +89,13 @@
 }
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers, CalculateArrayLength>(src);
+    auto got = Run<Unshadow, SimplifyPointers, CalculateArrayLength>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CalculateArrayLengthTest, BasicInStruct) {
-  auto* src = R"(
+    auto* src = R"(
 struct SB {
   x : i32,
   arr : array<i32>,
@@ -109,7 +109,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @internal(intrinsic_buffer_size)
 fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, result : ptr<function, u32>)
 
@@ -129,13 +129,13 @@
 }
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers, CalculateArrayLength>(src);
+    auto got = Run<Unshadow, SimplifyPointers, CalculateArrayLength>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CalculateArrayLengthTest, ArrayOfStruct) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   f : f32,
 }
@@ -147,7 +147,7 @@
   let len = arrayLength(&arr);
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 @internal(intrinsic_buffer_size)
 fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : array<S>, result : ptr<function, u32>)
 
@@ -166,13 +166,13 @@
 }
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers, CalculateArrayLength>(src);
+    auto got = Run<Unshadow, SimplifyPointers, CalculateArrayLength>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CalculateArrayLengthTest, ArrayOfArrayOfStruct) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   f : f32,
 }
@@ -184,7 +184,7 @@
   let len = arrayLength(&arr);
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 @internal(intrinsic_buffer_size)
 fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : array<array<S, 4u>>, result : ptr<function, u32>)
 
@@ -203,13 +203,13 @@
 }
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers, CalculateArrayLength>(src);
+    auto got = Run<Unshadow, SimplifyPointers, CalculateArrayLength>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CalculateArrayLengthTest, InSameBlock) {
-  auto* src = R"(
+    auto* src = R"(
 @group(0) @binding(0) var<storage, read> sb : array<i32>;;
 
 @stage(compute) @workgroup_size(1)
@@ -220,7 +220,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @internal(intrinsic_buffer_size)
 fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : array<i32>, result : ptr<function, u32>)
 
@@ -237,13 +237,13 @@
 }
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers, CalculateArrayLength>(src);
+    auto got = Run<Unshadow, SimplifyPointers, CalculateArrayLength>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CalculateArrayLengthTest, InSameBlock_Struct) {
-  auto* src = R"(
+    auto* src = R"(
 struct SB {
   x : i32,
   arr : array<i32>,
@@ -259,7 +259,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @internal(intrinsic_buffer_size)
 fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, result : ptr<function, u32>)
 
@@ -281,13 +281,13 @@
 }
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers, CalculateArrayLength>(src);
+    auto got = Run<Unshadow, SimplifyPointers, CalculateArrayLength>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CalculateArrayLengthTest, Nested) {
-  auto* src = R"(
+    auto* src = R"(
 struct SB {
   x : i32,
   arr : array<i32>,
@@ -307,7 +307,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @internal(intrinsic_buffer_size)
 fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, result : ptr<function, u32>)
 
@@ -336,13 +336,13 @@
 }
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers, CalculateArrayLength>(src);
+    auto got = Run<Unshadow, SimplifyPointers, CalculateArrayLength>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CalculateArrayLengthTest, MultipleStorageBuffers) {
-  auto* src = R"(
+    auto* src = R"(
 struct SB1 {
   x : i32,
   arr1 : array<i32>,
@@ -368,7 +368,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @internal(intrinsic_buffer_size)
 fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB1, result : ptr<function, u32>)
 
@@ -412,13 +412,13 @@
 }
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers, CalculateArrayLength>(src);
+    auto got = Run<Unshadow, SimplifyPointers, CalculateArrayLength>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CalculateArrayLengthTest, Shadowing) {
-  auto* src = R"(
+    auto* src = R"(
 struct SB {
   x : i32,
   arr : array<i32>,
@@ -437,8 +437,8 @@
 }
 )";
 
-  auto* expect =
-      R"(
+    auto* expect =
+        R"(
 @internal(intrinsic_buffer_size)
 fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, result : ptr<function, u32>)
 
@@ -466,13 +466,13 @@
 }
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers, CalculateArrayLength>(src);
+    auto got = Run<Unshadow, SimplifyPointers, CalculateArrayLength>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CalculateArrayLengthTest, OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   var len1 : u32 = arrayLength(&(sb1.arr1));
@@ -498,7 +498,7 @@
 @group(0) @binding(2) var<storage, read> sb3 : array<i32>;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @internal(intrinsic_buffer_size)
 fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB1, result : ptr<function, u32>)
 
@@ -542,9 +542,9 @@
 @group(0) @binding(2) var<storage, read> sb3 : array<i32>;
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers, CalculateArrayLength>(src);
+    auto got = Run<Unshadow, SimplifyPointers, CalculateArrayLength>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 }  // namespace
diff --git a/src/tint/transform/canonicalize_entry_point_io.cc b/src/tint/transform/canonicalize_entry_point_io.cc
index 9d72887..aeafa1b 100644
--- a/src/tint/transform/canonicalize_entry_point_io.cc
+++ b/src/tint/transform/canonicalize_entry_point_io.cc
@@ -25,6 +25,8 @@
 #include "src/tint/sem/function.h"
 #include "src/tint/transform/unshadow.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 TINT_INSTANTIATE_TYPEINFO(tint::transform::CanonicalizeEntryPointIO);
 TINT_INSTANTIATE_TYPEINFO(tint::transform::CanonicalizeEntryPointIO::Config);
 
@@ -38,730 +40,702 @@
 // Comparison function used to reorder struct members such that all members with
 // location attributes appear first (ordered by location slot), followed by
 // those with builtin attributes.
-bool StructMemberComparator(const ast::StructMember* a,
-                            const ast::StructMember* b) {
-  auto* a_loc = ast::GetAttribute<ast::LocationAttribute>(a->attributes);
-  auto* b_loc = ast::GetAttribute<ast::LocationAttribute>(b->attributes);
-  auto* a_blt = ast::GetAttribute<ast::BuiltinAttribute>(a->attributes);
-  auto* b_blt = ast::GetAttribute<ast::BuiltinAttribute>(b->attributes);
-  if (a_loc) {
-    if (!b_loc) {
-      // `a` has location attribute and `b` does not: `a` goes first.
-      return true;
+bool StructMemberComparator(const ast::StructMember* a, const ast::StructMember* b) {
+    auto* a_loc = ast::GetAttribute<ast::LocationAttribute>(a->attributes);
+    auto* b_loc = ast::GetAttribute<ast::LocationAttribute>(b->attributes);
+    auto* a_blt = ast::GetAttribute<ast::BuiltinAttribute>(a->attributes);
+    auto* b_blt = ast::GetAttribute<ast::BuiltinAttribute>(b->attributes);
+    if (a_loc) {
+        if (!b_loc) {
+            // `a` has location attribute and `b` does not: `a` goes first.
+            return true;
+        }
+        // Both have location attributes: smallest goes first.
+        return a_loc->value < b_loc->value;
+    } else {
+        if (b_loc) {
+            // `b` has location attribute and `a` does not: `b` goes first.
+            return false;
+        }
+        // Both are builtins: order doesn't matter, just use enum value.
+        return a_blt->builtin < b_blt->builtin;
     }
-    // Both have location attributes: smallest goes first.
-    return a_loc->value < b_loc->value;
-  } else {
-    if (b_loc) {
-      // `b` has location attribute and `a` does not: `b` goes first.
-      return false;
-    }
-    // Both are builtins: order doesn't matter, just use enum value.
-    return a_blt->builtin < b_blt->builtin;
-  }
 }
 
 // Returns true if `attr` is a shader IO attribute.
 bool IsShaderIOAttribute(const ast::Attribute* attr) {
-  return attr->IsAnyOf<ast::BuiltinAttribute, ast::InterpolateAttribute,
-                       ast::InvariantAttribute, ast::LocationAttribute>();
+    return attr->IsAnyOf<ast::BuiltinAttribute, ast::InterpolateAttribute, ast::InvariantAttribute,
+                         ast::LocationAttribute>();
 }
 
 // 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;
+    auto* builtin = ast::GetAttribute<ast::BuiltinAttribute>(attrs);
+    return builtin && builtin->builtin == ast::Builtin::kSampleMask;
 }
 
 }  // namespace
 
 /// State holds the current transform state for a single entry point.
 struct CanonicalizeEntryPointIO::State {
-  /// OutputValue represents a shader result that the wrapper function produces.
-  struct OutputValue {
-    /// The name of the output value.
-    std::string name;
-    /// The type of the output value.
-    const ast::Type* type;
-    /// The shader IO attributes.
-    ast::AttributeList attributes;
-    /// The value itself.
-    const ast::Expression* value;
-  };
-
-  /// The clone context.
-  CloneContext& ctx;
-  /// The transform config.
-  CanonicalizeEntryPointIO::Config const cfg;
-  /// The entry point function (AST).
-  const ast::Function* func_ast;
-  /// The entry point function (SEM).
-  const sem::Function* func_sem;
-
-  /// The new entry point wrapper function's parameters.
-  ast::VariableList wrapper_ep_parameters;
-  /// The members of the wrapper function's struct parameter.
-  ast::StructMemberList wrapper_struct_param_members;
-  /// The name of the wrapper function's struct parameter.
-  Symbol wrapper_struct_param_name;
-  /// The parameters that will be passed to the original function.
-  ast::ExpressionList inner_call_parameters;
-  /// The members of the wrapper function's struct return type.
-  ast::StructMemberList wrapper_struct_output_members;
-  /// The wrapper function output values.
-  std::vector<OutputValue> wrapper_output_values;
-  /// The body of the wrapper function.
-  ast::StatementList wrapper_body;
-  /// Input names used by the entrypoint
-  std::unordered_set<std::string> input_names;
-
-  /// Constructor
-  /// @param context the clone context
-  /// @param config the transform config
-  /// @param function the entry point function
-  State(CloneContext& context,
-        const CanonicalizeEntryPointIO::Config& config,
-        const ast::Function* function)
-      : ctx(context),
-        cfg(config),
-        func_ast(function),
-        func_sem(ctx.src->Sem().Get(function)) {}
-
-  /// Clones the shader IO attributes from `src`.
-  /// @param src the attributes to clone
-  /// @param do_interpolate whether to clone InterpolateAttribute
-  /// @return the cloned attributes
-  ast::AttributeList CloneShaderIOAttributes(const ast::AttributeList& src,
-                                             bool do_interpolate) {
-    ast::AttributeList new_attributes;
-    for (auto* attr : src) {
-      if (IsShaderIOAttribute(attr) &&
-          (do_interpolate || !attr->Is<ast::InterpolateAttribute>())) {
-        new_attributes.push_back(ctx.Clone(attr));
-      }
-    }
-    return new_attributes;
-  }
-
-  /// Create or return a symbol for the wrapper function's struct parameter.
-  /// @returns the symbol for the struct parameter
-  Symbol InputStructSymbol() {
-    if (!wrapper_struct_param_name.IsValid()) {
-      wrapper_struct_param_name = ctx.dst->Sym();
-    }
-    return wrapper_struct_param_name;
-  }
-
-  /// Add a shader input to the entry point.
-  /// @param name the name of the shader input
-  /// @param type the type of the shader input
-  /// @param attributes the attributes to apply to the shader input
-  /// @returns an expression which evaluates to the value of the shader input
-  const ast::Expression* AddInput(std::string name,
-                                  const sem::Type* type,
-                                  ast::AttributeList attributes) {
-    auto* ast_type = CreateASTTypeFor(ctx, type);
-    if (cfg.shader_style == ShaderStyle::kSpirv ||
-        cfg.shader_style == ShaderStyle::kGlsl) {
-      // Vulkan requires that integer user-defined fragment inputs are
-      // always decorated with `Flat`.
-      // TODO(crbug.com/tint/1224): Remove this once a flat interpolation
-      // attribute is required for integers.
-      if (type->is_integer_scalar_or_vector() &&
-          ast::HasAttribute<ast::LocationAttribute>(attributes) &&
-          !ast::HasAttribute<ast::InterpolateAttribute>(attributes) &&
-          func_ast->PipelineStage() == ast::PipelineStage::kFragment) {
-        attributes.push_back(ctx.dst->Interpolate(
-            ast::InterpolationType::kFlat, ast::InterpolationSampling::kNone));
-      }
-
-      // Disable validation for use of the `input` storage class.
-      attributes.push_back(
-          ctx.dst->Disable(ast::DisabledValidation::kIgnoreStorageClass));
-
-      // In GLSL, if it's a builtin, override the name with the
-      // corresponding gl_ builtin name
-      auto* builtin = ast::GetAttribute<ast::BuiltinAttribute>(attributes);
-      if (cfg.shader_style == ShaderStyle::kGlsl && builtin) {
-        name = GLSLBuiltinToString(builtin->builtin, func_ast->PipelineStage(),
-                                   ast::StorageClass::kInput);
-      }
-      auto symbol = ctx.dst->Symbols().New(name);
-
-      // Create the global variable and use its value for the shader input.
-      const ast::Expression* value = ctx.dst->Expr(symbol);
-
-      if (builtin) {
-        if (cfg.shader_style == ShaderStyle::kGlsl) {
-          value = FromGLSLBuiltin(builtin->builtin, value, ast_type);
-        } else if (builtin->builtin == ast::Builtin::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);
-          value = ctx.dst->IndexAccessor(value, 0);
-        }
-      }
-      ctx.dst->Global(symbol, ast_type, ast::StorageClass::kInput,
-                      std::move(attributes));
-      return value;
-    } else if (cfg.shader_style == ShaderStyle::kMsl &&
-               ast::HasAttribute<ast::BuiltinAttribute>(attributes)) {
-      // If this input is a builtin and we are targeting MSL, then add it to the
-      // parameter list and pass it directly to the inner function.
-      Symbol symbol = input_names.emplace(name).second
-                          ? ctx.dst->Symbols().Register(name)
-                          : ctx.dst->Symbols().New(name);
-      wrapper_ep_parameters.push_back(
-          ctx.dst->Param(symbol, ast_type, std::move(attributes)));
-      return ctx.dst->Expr(symbol);
-    } else {
-      // Otherwise, move it to the new structure member list.
-      Symbol symbol = input_names.emplace(name).second
-                          ? ctx.dst->Symbols().Register(name)
-                          : ctx.dst->Symbols().New(name);
-      wrapper_struct_param_members.push_back(
-          ctx.dst->Member(symbol, ast_type, std::move(attributes)));
-      return ctx.dst->MemberAccessor(InputStructSymbol(), symbol);
-    }
-  }
-
-  /// Add a shader output to the entry point.
-  /// @param name the name of the shader output
-  /// @param type the type of the shader output
-  /// @param attributes the attributes to apply to the shader output
-  /// @param value the value of the shader output
-  void AddOutput(std::string name,
-                 const sem::Type* type,
-                 ast::AttributeList attributes,
-                 const ast::Expression* value) {
-    // Vulkan requires that integer user-defined vertex outputs are
-    // always decorated with `Flat`.
-    // TODO(crbug.com/tint/1224): Remove this once a flat interpolation
-    // attribute is required for integers.
-    if (cfg.shader_style == ShaderStyle::kSpirv &&
-        type->is_integer_scalar_or_vector() &&
-        ast::HasAttribute<ast::LocationAttribute>(attributes) &&
-        !ast::HasAttribute<ast::InterpolateAttribute>(attributes) &&
-        func_ast->PipelineStage() == ast::PipelineStage::kVertex) {
-      attributes.push_back(ctx.dst->Interpolate(
-          ast::InterpolationType::kFlat, ast::InterpolationSampling::kNone));
-    }
-
-    // In GLSL, if it's a builtin, override the name with the
-    // corresponding gl_ builtin name
-    if (cfg.shader_style == ShaderStyle::kGlsl) {
-      if (auto* b = ast::GetAttribute<ast::BuiltinAttribute>(attributes)) {
-        name = GLSLBuiltinToString(b->builtin, func_ast->PipelineStage(),
-                                   ast::StorageClass::kOutput);
-        value = ToGLSLBuiltin(b->builtin, value, type);
-      }
-    }
-
-    OutputValue output;
-    output.name = name;
-    output.type = CreateASTTypeFor(ctx, type);
-    output.attributes = std::move(attributes);
-    output.value = value;
-    wrapper_output_values.push_back(output);
-  }
-
-  /// Process a non-struct parameter.
-  /// This creates a new object for the shader input, moving the shader IO
-  /// attributes to it. It also adds an expression to the list of parameters
-  /// that will be passed to the original function.
-  /// @param param the original function parameter
-  void ProcessNonStructParameter(const sem::Parameter* param) {
-    // Remove the shader IO attributes from the inner function parameter, and
-    // attach them to the new object instead.
-    ast::AttributeList attributes;
-    for (auto* attr : param->Declaration()->attributes) {
-      if (IsShaderIOAttribute(attr)) {
-        ctx.Remove(param->Declaration()->attributes, attr);
-        attributes.push_back(ctx.Clone(attr));
-      }
-    }
-
-    auto name = ctx.src->Symbols().NameFor(param->Declaration()->symbol);
-    auto* input_expr = AddInput(name, param->Type(), std::move(attributes));
-    inner_call_parameters.push_back(input_expr);
-  }
-
-  /// Process a struct parameter.
-  /// This creates new objects for each struct member, moving the shader IO
-  /// attributes to them. It also creates the structure that will be passed to
-  /// the original function.
-  /// @param param the original function parameter
-  void ProcessStructParameter(const sem::Parameter* param) {
-    auto* str = param->Type()->As<sem::Struct>();
-
-    // Recreate struct members in the outer entry point and build an initializer
-    // list to pass them through to the inner function.
-    ast::ExpressionList inner_struct_values;
-    for (auto* member : str->Members()) {
-      if (member->Type()->Is<sem::Struct>()) {
-        TINT_ICE(Transform, ctx.dst->Diagnostics()) << "nested IO struct";
-        continue;
-      }
-
-      auto* member_ast = member->Declaration();
-      auto name = ctx.src->Symbols().NameFor(member_ast->symbol);
-
-      // In GLSL, do not add interpolation attributes on vertex input
-      bool do_interpolate = true;
-      if (cfg.shader_style == ShaderStyle::kGlsl &&
-          func_ast->PipelineStage() == ast::PipelineStage::kVertex) {
-        do_interpolate = false;
-      }
-      auto attributes =
-          CloneShaderIOAttributes(member_ast->attributes, do_interpolate);
-      auto* input_expr = AddInput(name, member->Type(), std::move(attributes));
-      inner_struct_values.push_back(input_expr);
-    }
-
-    // Construct the original structure using the new shader input objects.
-    inner_call_parameters.push_back(ctx.dst->Construct(
-        ctx.Clone(param->Declaration()->type), inner_struct_values));
-  }
-
-  /// Process the entry point return type.
-  /// This generates a list of output values that are returned by the original
-  /// function.
-  /// @param inner_ret_type the original function return type
-  /// @param original_result the result object produced by the original function
-  void ProcessReturnType(const sem::Type* inner_ret_type,
-                         Symbol original_result) {
-    bool do_interpolate = true;
-    // In GLSL, do not add interpolation attributes on fragment output
-    if (cfg.shader_style == ShaderStyle::kGlsl &&
-        func_ast->PipelineStage() == ast::PipelineStage::kFragment) {
-      do_interpolate = false;
-    }
-    if (auto* str = inner_ret_type->As<sem::Struct>()) {
-      for (auto* member : str->Members()) {
-        if (member->Type()->Is<sem::Struct>()) {
-          TINT_ICE(Transform, ctx.dst->Diagnostics()) << "nested IO struct";
-          continue;
-        }
-
-        auto* member_ast = member->Declaration();
-        auto name = ctx.src->Symbols().NameFor(member_ast->symbol);
-        auto attributes =
-            CloneShaderIOAttributes(member_ast->attributes, do_interpolate);
-
-        // Extract the original structure member.
-        AddOutput(name, member->Type(), std::move(attributes),
-                  ctx.dst->MemberAccessor(original_result, name));
-      }
-    } else if (!inner_ret_type->Is<sem::Void>()) {
-      auto attributes = CloneShaderIOAttributes(
-          func_ast->return_type_attributes, do_interpolate);
-
-      // Propagate the non-struct return value as is.
-      AddOutput("value", func_sem->ReturnType(), std::move(attributes),
-                ctx.dst->Expr(original_result));
-    }
-  }
-
-  /// Add a fixed sample mask to the wrapper function output.
-  /// If there is already a sample mask, bitwise-and it with the fixed mask.
-  /// Otherwise, create a new output value from the fixed mask.
-  void AddFixedSampleMask() {
-    // Check the existing output values for a sample mask builtin.
-    for (auto& outval : wrapper_output_values) {
-      if (HasSampleMask(outval.attributes)) {
-        // Combine the authored sample mask with the fixed mask.
-        outval.value = ctx.dst->And(outval.value, cfg.fixed_sample_mask);
-        return;
-      }
-    }
-
-    // No existing sample mask builtin was found, so create a new output value
-    // using the fixed sample mask.
-    AddOutput("fixed_sample_mask", ctx.dst->create<sem::U32>(),
-              {ctx.dst->Builtin(ast::Builtin::kSampleMask)},
-              ctx.dst->Expr(cfg.fixed_sample_mask));
-  }
-
-  /// Add a point size builtin to the wrapper function output.
-  void AddVertexPointSize() {
-    // Create a new output value and assign it a literal 1.0 value.
-    AddOutput("vertex_point_size", ctx.dst->create<sem::F32>(),
-              {ctx.dst->Builtin(ast::Builtin::kPointSize)}, ctx.dst->Expr(1.f));
-  }
-
-  /// Create an expression for gl_Position.[component]
-  /// @param component the component of gl_Position to access
-  /// @returns the new expression
-  const ast::Expression* GLPosition(const char* component) {
-    Symbol pos = ctx.dst->Symbols().Register("gl_Position");
-    Symbol c = ctx.dst->Symbols().Register(component);
-    return ctx.dst->MemberAccessor(ctx.dst->Expr(pos), ctx.dst->Expr(c));
-  }
-
-  /// Create the wrapper function's struct parameter and type objects.
-  void CreateInputStruct() {
-    // Sort the struct members to satisfy HLSL interfacing matching rules.
-    std::sort(wrapper_struct_param_members.begin(),
-              wrapper_struct_param_members.end(), StructMemberComparator);
-
-    // Create the new struct type.
-    auto struct_name = ctx.dst->Sym();
-    auto* in_struct = ctx.dst->create<ast::Struct>(
-        struct_name, wrapper_struct_param_members, ast::AttributeList{});
-    ctx.InsertBefore(ctx.src->AST().GlobalDeclarations(), func_ast, in_struct);
-
-    // Create a new function parameter using this struct type.
-    auto* param =
-        ctx.dst->Param(InputStructSymbol(), ctx.dst->ty.type_name(struct_name));
-    wrapper_ep_parameters.push_back(param);
-  }
-
-  /// Create and return the wrapper function's struct result object.
-  /// @returns the struct type
-  ast::Struct* CreateOutputStruct() {
-    ast::StatementList assignments;
-
-    auto wrapper_result = ctx.dst->Symbols().New("wrapper_result");
-
-    // Create the struct members and their corresponding assignment statements.
-    std::unordered_set<std::string> member_names;
-    for (auto& outval : wrapper_output_values) {
-      // Use the original output name, unless that is already taken.
-      Symbol name;
-      if (member_names.count(outval.name)) {
-        name = ctx.dst->Symbols().New(outval.name);
-      } else {
-        name = ctx.dst->Symbols().Register(outval.name);
-      }
-      member_names.insert(ctx.dst->Symbols().NameFor(name));
-
-      wrapper_struct_output_members.push_back(
-          ctx.dst->Member(name, outval.type, std::move(outval.attributes)));
-      assignments.push_back(ctx.dst->Assign(
-          ctx.dst->MemberAccessor(wrapper_result, name), outval.value));
-    }
-
-    // Sort the struct members to satisfy HLSL interfacing matching rules.
-    std::sort(wrapper_struct_output_members.begin(),
-              wrapper_struct_output_members.end(), StructMemberComparator);
-
-    // Create the new struct type.
-    auto* out_struct = ctx.dst->create<ast::Struct>(
-        ctx.dst->Sym(), wrapper_struct_output_members, ast::AttributeList{});
-    ctx.InsertBefore(ctx.src->AST().GlobalDeclarations(), func_ast, out_struct);
-
-    // Create the output struct object, assign its members, and return it.
-    auto* result_object =
-        ctx.dst->Var(wrapper_result, ctx.dst->ty.type_name(out_struct->name));
-    wrapper_body.push_back(ctx.dst->Decl(result_object));
-    wrapper_body.insert(wrapper_body.end(), assignments.begin(),
-                        assignments.end());
-    wrapper_body.push_back(ctx.dst->Return(wrapper_result));
-
-    return out_struct;
-  }
-
-  /// Create and assign the wrapper function's output variables.
-  void CreateGlobalOutputVariables() {
-    for (auto& outval : wrapper_output_values) {
-      // Disable validation for use of the `output` storage class.
-      ast::AttributeList attributes = std::move(outval.attributes);
-      attributes.push_back(
-          ctx.dst->Disable(ast::DisabledValidation::kIgnoreStorageClass));
-
-      // Create the global variable and assign it the output value.
-      auto name = ctx.dst->Symbols().New(outval.name);
-      auto* type = outval.type;
-      const ast::Expression* lhs = ctx.dst->Expr(name);
-      if (HasSampleMask(attributes)) {
-        // Vulkan requires the type of a SampleMask builtin to be an array.
-        // Declare it as array<u32, 1> and then store to the first element.
-        type = ctx.dst->ty.array(type, 1);
-        lhs = ctx.dst->IndexAccessor(lhs, 0);
-      }
-      ctx.dst->Global(name, type, ast::StorageClass::kOutput,
-                      std::move(attributes));
-      wrapper_body.push_back(ctx.dst->Assign(lhs, outval.value));
-    }
-  }
-
-  // Recreate the original function without entry point attributes and call it.
-  /// @returns the inner function call expression
-  const ast::CallExpression* CallInnerFunction() {
-    Symbol inner_name;
-    if (cfg.shader_style == ShaderStyle::kGlsl) {
-      // In GLSL, clone the original entry point name, as the wrapper will be
-      // called "main".
-      inner_name = ctx.Clone(func_ast->symbol);
-    } else {
-      // Add a suffix to the function name, as the wrapper function will take
-      // the original entry point name.
-      auto ep_name = ctx.src->Symbols().NameFor(func_ast->symbol);
-      inner_name = ctx.dst->Symbols().New(ep_name + "_inner");
-    }
-
-    // Clone everything, dropping the function and return type attributes.
-    // The parameter attributes will have already been stripped during
-    // processing.
-    auto* inner_function = ctx.dst->create<ast::Function>(
-        inner_name, ctx.Clone(func_ast->params),
-        ctx.Clone(func_ast->return_type), ctx.Clone(func_ast->body),
-        ast::AttributeList{}, ast::AttributeList{});
-    ctx.Replace(func_ast, inner_function);
-
-    // Call the function.
-    return ctx.dst->Call(inner_function->symbol, inner_call_parameters);
-  }
-
-  /// Process the entry point function.
-  void Process() {
-    bool needs_fixed_sample_mask = false;
-    bool needs_vertex_point_size = false;
-    if (func_ast->PipelineStage() == ast::PipelineStage::kFragment &&
-        cfg.fixed_sample_mask != 0xFFFFFFFF) {
-      needs_fixed_sample_mask = true;
-    }
-    if (func_ast->PipelineStage() == ast::PipelineStage::kVertex &&
-        cfg.emit_vertex_point_size) {
-      needs_vertex_point_size = true;
-    }
-
-    // Exit early if there is no shader IO to handle.
-    if (func_sem->Parameters().size() == 0 &&
-        func_sem->ReturnType()->Is<sem::Void>() && !needs_fixed_sample_mask &&
-        !needs_vertex_point_size && cfg.shader_style != ShaderStyle::kGlsl) {
-      return;
-    }
-
-    // Process the entry point parameters, collecting those that need to be
-    // aggregated into a single structure.
-    if (!func_sem->Parameters().empty()) {
-      for (auto* param : func_sem->Parameters()) {
-        if (param->Type()->Is<sem::Struct>()) {
-          ProcessStructParameter(param);
-        } else {
-          ProcessNonStructParameter(param);
-        }
-      }
-
-      // Create a structure parameter for the outer entry point if necessary.
-      if (!wrapper_struct_param_members.empty()) {
-        CreateInputStruct();
-      }
-    }
-
-    // Recreate the original function and call it.
-    auto* call_inner = CallInnerFunction();
-
-    // Process the return type, and start building the wrapper function body.
-    std::function<const ast::Type*()> wrapper_ret_type = [&] {
-      return ctx.dst->ty.void_();
+    /// OutputValue represents a shader result that the wrapper function produces.
+    struct OutputValue {
+        /// The name of the output value.
+        std::string name;
+        /// The type of the output value.
+        const ast::Type* type;
+        /// The shader IO attributes.
+        ast::AttributeList attributes;
+        /// The value itself.
+        const ast::Expression* value;
     };
-    if (func_sem->ReturnType()->Is<sem::Void>()) {
-      // The function call is just a statement with no result.
-      wrapper_body.push_back(ctx.dst->CallStmt(call_inner));
-    } else {
-      // Capture the result of calling the original function.
-      auto* inner_result = ctx.dst->Const(
-          ctx.dst->Symbols().New("inner_result"), nullptr, call_inner);
-      wrapper_body.push_back(ctx.dst->Decl(inner_result));
 
-      // Process the original return type to determine the outputs that the
-      // outer function needs to produce.
-      ProcessReturnType(func_sem->ReturnType(), inner_result->symbol);
-    }
+    /// The clone context.
+    CloneContext& ctx;
+    /// The transform config.
+    CanonicalizeEntryPointIO::Config const cfg;
+    /// The entry point function (AST).
+    const ast::Function* func_ast;
+    /// The entry point function (SEM).
+    const sem::Function* func_sem;
 
-    // Add a fixed sample mask, if necessary.
-    if (needs_fixed_sample_mask) {
-      AddFixedSampleMask();
-    }
+    /// The new entry point wrapper function's parameters.
+    ast::VariableList wrapper_ep_parameters;
+    /// The members of the wrapper function's struct parameter.
+    ast::StructMemberList wrapper_struct_param_members;
+    /// The name of the wrapper function's struct parameter.
+    Symbol wrapper_struct_param_name;
+    /// The parameters that will be passed to the original function.
+    ast::ExpressionList inner_call_parameters;
+    /// The members of the wrapper function's struct return type.
+    ast::StructMemberList wrapper_struct_output_members;
+    /// The wrapper function output values.
+    std::vector<OutputValue> wrapper_output_values;
+    /// The body of the wrapper function.
+    ast::StatementList wrapper_body;
+    /// Input names used by the entrypoint
+    std::unordered_set<std::string> input_names;
 
-    // Add the pointsize builtin, if necessary.
-    if (needs_vertex_point_size) {
-      AddVertexPointSize();
-    }
+    /// Constructor
+    /// @param context the clone context
+    /// @param config the transform config
+    /// @param function the entry point function
+    State(CloneContext& context,
+          const CanonicalizeEntryPointIO::Config& config,
+          const ast::Function* function)
+        : ctx(context), cfg(config), func_ast(function), func_sem(ctx.src->Sem().Get(function)) {}
 
-    // Produce the entry point outputs, if necessary.
-    if (!wrapper_output_values.empty()) {
-      if (cfg.shader_style == ShaderStyle::kSpirv ||
-          cfg.shader_style == ShaderStyle::kGlsl) {
-        CreateGlobalOutputVariables();
-      } else {
-        auto* output_struct = CreateOutputStruct();
-        wrapper_ret_type = [&, output_struct] {
-          return ctx.dst->ty.type_name(output_struct->name);
-        };
-      }
-    }
-
-    if (cfg.shader_style == ShaderStyle::kGlsl &&
-        func_ast->PipelineStage() == ast::PipelineStage::kVertex) {
-      auto* pos_y = GLPosition("y");
-      auto* negate_pos_y = ctx.dst->create<ast::UnaryOpExpression>(
-          ast::UnaryOp::kNegation, GLPosition("y"));
-      wrapper_body.push_back(ctx.dst->Assign(pos_y, negate_pos_y));
-
-      auto* two_z = ctx.dst->Mul(ctx.dst->Expr(2.0f), GLPosition("z"));
-      auto* fixed_z = ctx.dst->Sub(two_z, GLPosition("w"));
-      wrapper_body.push_back(ctx.dst->Assign(GLPosition("z"), fixed_z));
-    }
-
-    // Create the wrapper entry point function.
-    // For GLSL, use "main", otherwise take the name of the original
-    // entry point function.
-    Symbol name;
-    if (cfg.shader_style == ShaderStyle::kGlsl) {
-      name = ctx.dst->Symbols().New("main");
-    } else {
-      name = ctx.Clone(func_ast->symbol);
-    }
-
-    auto* wrapper_func = ctx.dst->create<ast::Function>(
-        name, wrapper_ep_parameters, wrapper_ret_type(),
-        ctx.dst->Block(wrapper_body), ctx.Clone(func_ast->attributes),
-        ast::AttributeList{});
-    ctx.InsertAfter(ctx.src->AST().GlobalDeclarations(), func_ast,
-                    wrapper_func);
-  }
-
-  /// Retrieve the gl_ string corresponding to a builtin.
-  /// @param builtin the builtin
-  /// @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,
-                                  ast::PipelineStage stage,
-                                  ast::StorageClass storage_class) {
-    switch (builtin) {
-      case ast::Builtin::kPosition:
-        switch (stage) {
-          case ast::PipelineStage::kVertex:
-            return "gl_Position";
-          case ast::PipelineStage::kFragment:
-            return "gl_FragCoord";
-          default:
-            return "";
+    /// Clones the shader IO attributes from `src`.
+    /// @param src the attributes to clone
+    /// @param do_interpolate whether to clone InterpolateAttribute
+    /// @return the cloned attributes
+    ast::AttributeList CloneShaderIOAttributes(const ast::AttributeList& src, bool do_interpolate) {
+        ast::AttributeList new_attributes;
+        for (auto* attr : src) {
+            if (IsShaderIOAttribute(attr) &&
+                (do_interpolate || !attr->Is<ast::InterpolateAttribute>())) {
+                new_attributes.push_back(ctx.Clone(attr));
+            }
         }
-      case ast::Builtin::kVertexIndex:
-        return "gl_VertexID";
-      case ast::Builtin::kInstanceIndex:
-        return "gl_InstanceID";
-      case ast::Builtin::kFrontFacing:
-        return "gl_FrontFacing";
-      case ast::Builtin::kFragDepth:
-        return "gl_FragDepth";
-      case ast::Builtin::kLocalInvocationId:
-        return "gl_LocalInvocationID";
-      case ast::Builtin::kLocalInvocationIndex:
-        return "gl_LocalInvocationIndex";
-      case ast::Builtin::kGlobalInvocationId:
-        return "gl_GlobalInvocationID";
-      case ast::Builtin::kNumWorkgroups:
-        return "gl_NumWorkGroups";
-      case ast::Builtin::kWorkgroupId:
-        return "gl_WorkGroupID";
-      case ast::Builtin::kSampleIndex:
-        return "gl_SampleID";
-      case ast::Builtin::kSampleMask:
-        if (storage_class == ast::StorageClass::kInput) {
-          return "gl_SampleMaskIn";
+        return new_attributes;
+    }
+
+    /// Create or return a symbol for the wrapper function's struct parameter.
+    /// @returns the symbol for the struct parameter
+    Symbol InputStructSymbol() {
+        if (!wrapper_struct_param_name.IsValid()) {
+            wrapper_struct_param_name = ctx.dst->Sym();
+        }
+        return wrapper_struct_param_name;
+    }
+
+    /// Add a shader input to the entry point.
+    /// @param name the name of the shader input
+    /// @param type the type of the shader input
+    /// @param attributes the attributes to apply to the shader input
+    /// @returns an expression which evaluates to the value of the shader input
+    const ast::Expression* AddInput(std::string name,
+                                    const sem::Type* type,
+                                    ast::AttributeList attributes) {
+        auto* ast_type = CreateASTTypeFor(ctx, type);
+        if (cfg.shader_style == ShaderStyle::kSpirv || cfg.shader_style == ShaderStyle::kGlsl) {
+            // Vulkan requires that integer user-defined fragment inputs are
+            // always decorated with `Flat`.
+            // TODO(crbug.com/tint/1224): Remove this once a flat interpolation
+            // attribute is required for integers.
+            if (type->is_integer_scalar_or_vector() &&
+                ast::HasAttribute<ast::LocationAttribute>(attributes) &&
+                !ast::HasAttribute<ast::InterpolateAttribute>(attributes) &&
+                func_ast->PipelineStage() == ast::PipelineStage::kFragment) {
+                attributes.push_back(ctx.dst->Interpolate(ast::InterpolationType::kFlat,
+                                                          ast::InterpolationSampling::kNone));
+            }
+
+            // Disable validation for use of the `input` storage class.
+            attributes.push_back(ctx.dst->Disable(ast::DisabledValidation::kIgnoreStorageClass));
+
+            // In GLSL, if it's a builtin, override the name with the
+            // corresponding gl_ builtin name
+            auto* builtin = ast::GetAttribute<ast::BuiltinAttribute>(attributes);
+            if (cfg.shader_style == ShaderStyle::kGlsl && builtin) {
+                name = GLSLBuiltinToString(builtin->builtin, func_ast->PipelineStage(),
+                                           ast::StorageClass::kInput);
+            }
+            auto symbol = ctx.dst->Symbols().New(name);
+
+            // Create the global variable and use its value for the shader input.
+            const ast::Expression* value = ctx.dst->Expr(symbol);
+
+            if (builtin) {
+                if (cfg.shader_style == ShaderStyle::kGlsl) {
+                    value = FromGLSLBuiltin(builtin->builtin, value, ast_type);
+                } else if (builtin->builtin == ast::Builtin::kSampleMask) {
+                    // Vulkan requires the type of a SampleMask builtin to be an array.
+                    // Declare it as array<u32, 1> and then load the first element.
+                    ast_type = ctx.dst->ty.array(ast_type, 1_u);
+                    value = ctx.dst->IndexAccessor(value, 0_i);
+                }
+            }
+            ctx.dst->Global(symbol, ast_type, ast::StorageClass::kInput, std::move(attributes));
+            return value;
+        } else if (cfg.shader_style == ShaderStyle::kMsl &&
+                   ast::HasAttribute<ast::BuiltinAttribute>(attributes)) {
+            // If this input is a builtin and we are targeting MSL, then add it to the
+            // parameter list and pass it directly to the inner function.
+            Symbol symbol = input_names.emplace(name).second ? ctx.dst->Symbols().Register(name)
+                                                             : ctx.dst->Symbols().New(name);
+            wrapper_ep_parameters.push_back(
+                ctx.dst->Param(symbol, ast_type, std::move(attributes)));
+            return ctx.dst->Expr(symbol);
         } else {
-          return "gl_SampleMask";
+            // Otherwise, move it to the new structure member list.
+            Symbol symbol = input_names.emplace(name).second ? ctx.dst->Symbols().Register(name)
+                                                             : ctx.dst->Symbols().New(name);
+            wrapper_struct_param_members.push_back(
+                ctx.dst->Member(symbol, ast_type, std::move(attributes)));
+            return ctx.dst->MemberAccessor(InputStructSymbol(), symbol);
         }
-      default:
-        return "";
     }
-  }
 
-  /// Convert a given GLSL builtin value to the corresponding WGSL value.
-  /// @param builtin the builtin variable
-  /// @param value the value to convert
-  /// @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,
+    /// Add a shader output to the entry point.
+    /// @param name the name of the shader output
+    /// @param type the type of the shader output
+    /// @param attributes the attributes to apply to the shader output
+    /// @param value the value of the shader output
+    void AddOutput(std::string name,
+                   const sem::Type* type,
+                   ast::AttributeList attributes,
+                   const ast::Expression* value) {
+        // Vulkan requires that integer user-defined vertex outputs are
+        // always decorated with `Flat`.
+        // TODO(crbug.com/tint/1224): Remove this once a flat interpolation
+        // attribute is required for integers.
+        if (cfg.shader_style == ShaderStyle::kSpirv && type->is_integer_scalar_or_vector() &&
+            ast::HasAttribute<ast::LocationAttribute>(attributes) &&
+            !ast::HasAttribute<ast::InterpolateAttribute>(attributes) &&
+            func_ast->PipelineStage() == ast::PipelineStage::kVertex) {
+            attributes.push_back(ctx.dst->Interpolate(ast::InterpolationType::kFlat,
+                                                      ast::InterpolationSampling::kNone));
+        }
+
+        // In GLSL, if it's a builtin, override the name with the
+        // corresponding gl_ builtin name
+        if (cfg.shader_style == ShaderStyle::kGlsl) {
+            if (auto* b = ast::GetAttribute<ast::BuiltinAttribute>(attributes)) {
+                name = GLSLBuiltinToString(b->builtin, func_ast->PipelineStage(),
+                                           ast::StorageClass::kOutput);
+                value = ToGLSLBuiltin(b->builtin, value, type);
+            }
+        }
+
+        OutputValue output;
+        output.name = name;
+        output.type = CreateASTTypeFor(ctx, type);
+        output.attributes = std::move(attributes);
+        output.value = value;
+        wrapper_output_values.push_back(output);
+    }
+
+    /// Process a non-struct parameter.
+    /// This creates a new object for the shader input, moving the shader IO
+    /// attributes to it. It also adds an expression to the list of parameters
+    /// that will be passed to the original function.
+    /// @param param the original function parameter
+    void ProcessNonStructParameter(const sem::Parameter* param) {
+        // Remove the shader IO attributes from the inner function parameter, and
+        // attach them to the new object instead.
+        ast::AttributeList attributes;
+        for (auto* attr : param->Declaration()->attributes) {
+            if (IsShaderIOAttribute(attr)) {
+                ctx.Remove(param->Declaration()->attributes, attr);
+                attributes.push_back(ctx.Clone(attr));
+            }
+        }
+
+        auto name = ctx.src->Symbols().NameFor(param->Declaration()->symbol);
+        auto* input_expr = AddInput(name, param->Type(), std::move(attributes));
+        inner_call_parameters.push_back(input_expr);
+    }
+
+    /// Process a struct parameter.
+    /// This creates new objects for each struct member, moving the shader IO
+    /// attributes to them. It also creates the structure that will be passed to
+    /// the original function.
+    /// @param param the original function parameter
+    void ProcessStructParameter(const sem::Parameter* param) {
+        auto* str = param->Type()->As<sem::Struct>();
+
+        // Recreate struct members in the outer entry point and build an initializer
+        // list to pass them through to the inner function.
+        ast::ExpressionList inner_struct_values;
+        for (auto* member : str->Members()) {
+            if (member->Type()->Is<sem::Struct>()) {
+                TINT_ICE(Transform, ctx.dst->Diagnostics()) << "nested IO struct";
+                continue;
+            }
+
+            auto* member_ast = member->Declaration();
+            auto name = ctx.src->Symbols().NameFor(member_ast->symbol);
+
+            // In GLSL, do not add interpolation attributes on vertex input
+            bool do_interpolate = true;
+            if (cfg.shader_style == ShaderStyle::kGlsl &&
+                func_ast->PipelineStage() == ast::PipelineStage::kVertex) {
+                do_interpolate = false;
+            }
+            auto attributes = CloneShaderIOAttributes(member_ast->attributes, do_interpolate);
+            auto* input_expr = AddInput(name, member->Type(), std::move(attributes));
+            inner_struct_values.push_back(input_expr);
+        }
+
+        // Construct the original structure using the new shader input objects.
+        inner_call_parameters.push_back(
+            ctx.dst->Construct(ctx.Clone(param->Declaration()->type), inner_struct_values));
+    }
+
+    /// Process the entry point return type.
+    /// This generates a list of output values that are returned by the original
+    /// function.
+    /// @param inner_ret_type the original function return type
+    /// @param original_result the result object produced by the original function
+    void ProcessReturnType(const sem::Type* inner_ret_type, Symbol original_result) {
+        bool do_interpolate = true;
+        // In GLSL, do not add interpolation attributes on fragment output
+        if (cfg.shader_style == ShaderStyle::kGlsl &&
+            func_ast->PipelineStage() == ast::PipelineStage::kFragment) {
+            do_interpolate = false;
+        }
+        if (auto* str = inner_ret_type->As<sem::Struct>()) {
+            for (auto* member : str->Members()) {
+                if (member->Type()->Is<sem::Struct>()) {
+                    TINT_ICE(Transform, ctx.dst->Diagnostics()) << "nested IO struct";
+                    continue;
+                }
+
+                auto* member_ast = member->Declaration();
+                auto name = ctx.src->Symbols().NameFor(member_ast->symbol);
+                auto attributes = CloneShaderIOAttributes(member_ast->attributes, do_interpolate);
+
+                // Extract the original structure member.
+                AddOutput(name, member->Type(), std::move(attributes),
+                          ctx.dst->MemberAccessor(original_result, name));
+            }
+        } else if (!inner_ret_type->Is<sem::Void>()) {
+            auto attributes =
+                CloneShaderIOAttributes(func_ast->return_type_attributes, do_interpolate);
+
+            // Propagate the non-struct return value as is.
+            AddOutput("value", func_sem->ReturnType(), std::move(attributes),
+                      ctx.dst->Expr(original_result));
+        }
+    }
+
+    /// Add a fixed sample mask to the wrapper function output.
+    /// If there is already a sample mask, bitwise-and it with the fixed mask.
+    /// Otherwise, create a new output value from the fixed mask.
+    void AddFixedSampleMask() {
+        // Check the existing output values for a sample mask builtin.
+        for (auto& outval : wrapper_output_values) {
+            if (HasSampleMask(outval.attributes)) {
+                // Combine the authored sample mask with the fixed mask.
+                outval.value = ctx.dst->And(outval.value, u32(cfg.fixed_sample_mask));
+                return;
+            }
+        }
+
+        // No existing sample mask builtin was found, so create a new output value
+        // using the fixed sample mask.
+        AddOutput("fixed_sample_mask", ctx.dst->create<sem::U32>(),
+                  {ctx.dst->Builtin(ast::Builtin::kSampleMask)},
+                  ctx.dst->Expr(u32(cfg.fixed_sample_mask)));
+    }
+
+    /// Add a point size builtin to the wrapper function output.
+    void AddVertexPointSize() {
+        // Create a new output value and assign it a literal 1.0 value.
+        AddOutput("vertex_point_size", ctx.dst->create<sem::F32>(),
+                  {ctx.dst->Builtin(ast::Builtin::kPointSize)}, ctx.dst->Expr(1.f));
+    }
+
+    /// Create an expression for gl_Position.[component]
+    /// @param component the component of gl_Position to access
+    /// @returns the new expression
+    const ast::Expression* GLPosition(const char* component) {
+        Symbol pos = ctx.dst->Symbols().Register("gl_Position");
+        Symbol c = ctx.dst->Symbols().Register(component);
+        return ctx.dst->MemberAccessor(ctx.dst->Expr(pos), ctx.dst->Expr(c));
+    }
+
+    /// Create the wrapper function's struct parameter and type objects.
+    void CreateInputStruct() {
+        // Sort the struct members to satisfy HLSL interfacing matching rules.
+        std::sort(wrapper_struct_param_members.begin(), wrapper_struct_param_members.end(),
+                  StructMemberComparator);
+
+        // Create the new struct type.
+        auto struct_name = ctx.dst->Sym();
+        auto* in_struct = ctx.dst->create<ast::Struct>(struct_name, wrapper_struct_param_members,
+                                                       ast::AttributeList{});
+        ctx.InsertBefore(ctx.src->AST().GlobalDeclarations(), func_ast, in_struct);
+
+        // Create a new function parameter using this struct type.
+        auto* param = ctx.dst->Param(InputStructSymbol(), ctx.dst->ty.type_name(struct_name));
+        wrapper_ep_parameters.push_back(param);
+    }
+
+    /// Create and return the wrapper function's struct result object.
+    /// @returns the struct type
+    ast::Struct* CreateOutputStruct() {
+        ast::StatementList assignments;
+
+        auto wrapper_result = ctx.dst->Symbols().New("wrapper_result");
+
+        // Create the struct members and their corresponding assignment statements.
+        std::unordered_set<std::string> member_names;
+        for (auto& outval : wrapper_output_values) {
+            // Use the original output name, unless that is already taken.
+            Symbol name;
+            if (member_names.count(outval.name)) {
+                name = ctx.dst->Symbols().New(outval.name);
+            } else {
+                name = ctx.dst->Symbols().Register(outval.name);
+            }
+            member_names.insert(ctx.dst->Symbols().NameFor(name));
+
+            wrapper_struct_output_members.push_back(
+                ctx.dst->Member(name, outval.type, std::move(outval.attributes)));
+            assignments.push_back(
+                ctx.dst->Assign(ctx.dst->MemberAccessor(wrapper_result, name), outval.value));
+        }
+
+        // Sort the struct members to satisfy HLSL interfacing matching rules.
+        std::sort(wrapper_struct_output_members.begin(), wrapper_struct_output_members.end(),
+                  StructMemberComparator);
+
+        // Create the new struct type.
+        auto* out_struct = ctx.dst->create<ast::Struct>(
+            ctx.dst->Sym(), wrapper_struct_output_members, ast::AttributeList{});
+        ctx.InsertBefore(ctx.src->AST().GlobalDeclarations(), func_ast, out_struct);
+
+        // Create the output struct object, assign its members, and return it.
+        auto* result_object = ctx.dst->Var(wrapper_result, ctx.dst->ty.type_name(out_struct->name));
+        wrapper_body.push_back(ctx.dst->Decl(result_object));
+        wrapper_body.insert(wrapper_body.end(), assignments.begin(), assignments.end());
+        wrapper_body.push_back(ctx.dst->Return(wrapper_result));
+
+        return out_struct;
+    }
+
+    /// Create and assign the wrapper function's output variables.
+    void CreateGlobalOutputVariables() {
+        for (auto& outval : wrapper_output_values) {
+            // Disable validation for use of the `output` storage class.
+            ast::AttributeList attributes = std::move(outval.attributes);
+            attributes.push_back(ctx.dst->Disable(ast::DisabledValidation::kIgnoreStorageClass));
+
+            // Create the global variable and assign it the output value.
+            auto name = ctx.dst->Symbols().New(outval.name);
+            auto* type = outval.type;
+            const ast::Expression* lhs = ctx.dst->Expr(name);
+            if (HasSampleMask(attributes)) {
+                // Vulkan requires the type of a SampleMask builtin to be an array.
+                // Declare it as array<u32, 1> and then store to the first element.
+                type = ctx.dst->ty.array(type, 1_u);
+                lhs = ctx.dst->IndexAccessor(lhs, 0_i);
+            }
+            ctx.dst->Global(name, type, ast::StorageClass::kOutput, std::move(attributes));
+            wrapper_body.push_back(ctx.dst->Assign(lhs, outval.value));
+        }
+    }
+
+    // Recreate the original function without entry point attributes and call it.
+    /// @returns the inner function call expression
+    const ast::CallExpression* CallInnerFunction() {
+        Symbol inner_name;
+        if (cfg.shader_style == ShaderStyle::kGlsl) {
+            // In GLSL, clone the original entry point name, as the wrapper will be
+            // called "main".
+            inner_name = ctx.Clone(func_ast->symbol);
+        } else {
+            // Add a suffix to the function name, as the wrapper function will take
+            // the original entry point name.
+            auto ep_name = ctx.src->Symbols().NameFor(func_ast->symbol);
+            inner_name = ctx.dst->Symbols().New(ep_name + "_inner");
+        }
+
+        // Clone everything, dropping the function and return type attributes.
+        // The parameter attributes will have already been stripped during
+        // processing.
+        auto* inner_function = ctx.dst->create<ast::Function>(
+            inner_name, ctx.Clone(func_ast->params), ctx.Clone(func_ast->return_type),
+            ctx.Clone(func_ast->body), ast::AttributeList{}, ast::AttributeList{});
+        ctx.Replace(func_ast, inner_function);
+
+        // Call the function.
+        return ctx.dst->Call(inner_function->symbol, inner_call_parameters);
+    }
+
+    /// Process the entry point function.
+    void Process() {
+        bool needs_fixed_sample_mask = false;
+        bool needs_vertex_point_size = false;
+        if (func_ast->PipelineStage() == ast::PipelineStage::kFragment &&
+            cfg.fixed_sample_mask != 0xFFFFFFFF) {
+            needs_fixed_sample_mask = true;
+        }
+        if (func_ast->PipelineStage() == ast::PipelineStage::kVertex &&
+            cfg.emit_vertex_point_size) {
+            needs_vertex_point_size = true;
+        }
+
+        // Exit early if there is no shader IO to handle.
+        if (func_sem->Parameters().size() == 0 && func_sem->ReturnType()->Is<sem::Void>() &&
+            !needs_fixed_sample_mask && !needs_vertex_point_size &&
+            cfg.shader_style != ShaderStyle::kGlsl) {
+            return;
+        }
+
+        // Process the entry point parameters, collecting those that need to be
+        // aggregated into a single structure.
+        if (!func_sem->Parameters().empty()) {
+            for (auto* param : func_sem->Parameters()) {
+                if (param->Type()->Is<sem::Struct>()) {
+                    ProcessStructParameter(param);
+                } else {
+                    ProcessNonStructParameter(param);
+                }
+            }
+
+            // Create a structure parameter for the outer entry point if necessary.
+            if (!wrapper_struct_param_members.empty()) {
+                CreateInputStruct();
+            }
+        }
+
+        // Recreate the original function and call it.
+        auto* call_inner = CallInnerFunction();
+
+        // Process the return type, and start building the wrapper function body.
+        std::function<const ast::Type*()> wrapper_ret_type = [&] { return ctx.dst->ty.void_(); };
+        if (func_sem->ReturnType()->Is<sem::Void>()) {
+            // The function call is just a statement with no result.
+            wrapper_body.push_back(ctx.dst->CallStmt(call_inner));
+        } else {
+            // Capture the result of calling the original function.
+            auto* inner_result =
+                ctx.dst->Let(ctx.dst->Symbols().New("inner_result"), nullptr, call_inner);
+            wrapper_body.push_back(ctx.dst->Decl(inner_result));
+
+            // Process the original return type to determine the outputs that the
+            // outer function needs to produce.
+            ProcessReturnType(func_sem->ReturnType(), inner_result->symbol);
+        }
+
+        // Add a fixed sample mask, if necessary.
+        if (needs_fixed_sample_mask) {
+            AddFixedSampleMask();
+        }
+
+        // Add the pointsize builtin, if necessary.
+        if (needs_vertex_point_size) {
+            AddVertexPointSize();
+        }
+
+        // Produce the entry point outputs, if necessary.
+        if (!wrapper_output_values.empty()) {
+            if (cfg.shader_style == ShaderStyle::kSpirv || cfg.shader_style == ShaderStyle::kGlsl) {
+                CreateGlobalOutputVariables();
+            } else {
+                auto* output_struct = CreateOutputStruct();
+                wrapper_ret_type = [&, output_struct] {
+                    return ctx.dst->ty.type_name(output_struct->name);
+                };
+            }
+        }
+
+        if (cfg.shader_style == ShaderStyle::kGlsl &&
+            func_ast->PipelineStage() == ast::PipelineStage::kVertex) {
+            auto* pos_y = GLPosition("y");
+            auto* negate_pos_y =
+                ctx.dst->create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation, GLPosition("y"));
+            wrapper_body.push_back(ctx.dst->Assign(pos_y, negate_pos_y));
+
+            auto* two_z = ctx.dst->Mul(ctx.dst->Expr(2.0f), GLPosition("z"));
+            auto* fixed_z = ctx.dst->Sub(two_z, GLPosition("w"));
+            wrapper_body.push_back(ctx.dst->Assign(GLPosition("z"), fixed_z));
+        }
+
+        // Create the wrapper entry point function.
+        // For GLSL, use "main", otherwise take the name of the original
+        // entry point function.
+        Symbol name;
+        if (cfg.shader_style == ShaderStyle::kGlsl) {
+            name = ctx.dst->Symbols().New("main");
+        } else {
+            name = ctx.Clone(func_ast->symbol);
+        }
+
+        auto* wrapper_func = ctx.dst->create<ast::Function>(
+            name, wrapper_ep_parameters, wrapper_ret_type(), ctx.dst->Block(wrapper_body),
+            ctx.Clone(func_ast->attributes), ast::AttributeList{});
+        ctx.InsertAfter(ctx.src->AST().GlobalDeclarations(), func_ast, wrapper_func);
+    }
+
+    /// Retrieve the gl_ string corresponding to a builtin.
+    /// @param builtin the builtin
+    /// @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,
+                                    ast::PipelineStage stage,
+                                    ast::StorageClass storage_class) {
+        switch (builtin) {
+            case ast::Builtin::kPosition:
+                switch (stage) {
+                    case ast::PipelineStage::kVertex:
+                        return "gl_Position";
+                    case ast::PipelineStage::kFragment:
+                        return "gl_FragCoord";
+                    default:
+                        return "";
+                }
+            case ast::Builtin::kVertexIndex:
+                return "gl_VertexID";
+            case ast::Builtin::kInstanceIndex:
+                return "gl_InstanceID";
+            case ast::Builtin::kFrontFacing:
+                return "gl_FrontFacing";
+            case ast::Builtin::kFragDepth:
+                return "gl_FragDepth";
+            case ast::Builtin::kLocalInvocationId:
+                return "gl_LocalInvocationID";
+            case ast::Builtin::kLocalInvocationIndex:
+                return "gl_LocalInvocationIndex";
+            case ast::Builtin::kGlobalInvocationId:
+                return "gl_GlobalInvocationID";
+            case ast::Builtin::kNumWorkgroups:
+                return "gl_NumWorkGroups";
+            case ast::Builtin::kWorkgroupId:
+                return "gl_WorkGroupID";
+            case ast::Builtin::kSampleIndex:
+                return "gl_SampleID";
+            case ast::Builtin::kSampleMask:
+                if (storage_class == ast::StorageClass::kInput) {
+                    return "gl_SampleMaskIn";
+                } else {
+                    return "gl_SampleMask";
+                }
+            default:
+                return "";
+        }
+    }
+
+    /// Convert a given GLSL builtin value to the corresponding WGSL value.
+    /// @param builtin the builtin variable
+    /// @param value the value to convert
+    /// @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* value,
+                                           const ast::Type*& ast_type) {
+        switch (builtin) {
+            case ast::Builtin::kVertexIndex:
+            case ast::Builtin::kInstanceIndex:
+            case ast::Builtin::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:
+                // gl_SampleMask is an array of i32. Retrieve the first element and
+                // bitcast it to u32.
+                value = ctx.dst->IndexAccessor(value, 0_i);
+                value = ctx.dst->Bitcast(ast_type, value);
+                ast_type = ctx.dst->ty.array(ctx.dst->ty.i32(), 1_u);
+                break;
+            default:
+                break;
+        }
+        return value;
+    }
+
+    /// Convert a given WGSL value to the type expected when assigning to a
+    /// GLSL builtin.
+    /// @param builtin the builtin variable
+    /// @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* value,
-                                         const ast::Type*& ast_type) {
-    switch (builtin) {
-      case ast::Builtin::kVertexIndex:
-      case ast::Builtin::kInstanceIndex:
-      case ast::Builtin::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:
-        // gl_SampleMask is an array of i32. Retrieve the first element and
-        // bitcast it to u32.
-        value = ctx.dst->IndexAccessor(value, 0);
-        value = ctx.dst->Bitcast(ast_type, value);
-        ast_type = ctx.dst->ty.array(ctx.dst->ty.i32(), 1);
-        break;
-      default:
-        break;
+                                         const sem::Type*& type) {
+        switch (builtin) {
+            case ast::Builtin::kVertexIndex:
+            case ast::Builtin::kInstanceIndex:
+            case ast::Builtin::kSampleIndex:
+            case ast::Builtin::kSampleMask:
+                type = ctx.dst->create<sem::I32>();
+                value = ctx.dst->Bitcast(CreateASTTypeFor(ctx, type), value);
+                break;
+            default:
+                break;
+        }
+        return value;
     }
-    return value;
-  }
-
-  /// Convert a given WGSL value to the type expected when assigning to a
-  /// GLSL builtin.
-  /// @param builtin the builtin variable
-  /// @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* value,
-                                       const sem::Type*& type) {
-    switch (builtin) {
-      case ast::Builtin::kVertexIndex:
-      case ast::Builtin::kInstanceIndex:
-      case ast::Builtin::kSampleIndex:
-      case ast::Builtin::kSampleMask:
-        type = ctx.dst->create<sem::I32>();
-        value = ctx.dst->Bitcast(CreateASTTypeFor(ctx, type), value);
-        break;
-      default:
-        break;
-    }
-    return value;
-  }
 };
 
-void CanonicalizeEntryPointIO::Run(CloneContext& ctx,
-                                   const DataMap& inputs,
-                                   DataMap&) const {
-  auto* cfg = inputs.Get<Config>();
-  if (cfg == nullptr) {
-    ctx.dst->Diagnostics().add_error(
-        diag::System::Transform,
-        "missing transform data for " + std::string(TypeInfo().name));
-    return;
-  }
+void CanonicalizeEntryPointIO::Run(CloneContext& ctx, const DataMap& inputs, DataMap&) const {
+    auto* cfg = inputs.Get<Config>();
+    if (cfg == nullptr) {
+        ctx.dst->Diagnostics().add_error(
+            diag::System::Transform, "missing transform data for " + std::string(TypeInfo().name));
+        return;
+    }
 
-  // Remove entry point IO attributes from struct declarations.
-  // New structures will be created for each entry point, as necessary.
-  for (auto* ty : ctx.src->AST().TypeDecls()) {
-    if (auto* struct_ty = ty->As<ast::Struct>()) {
-      for (auto* member : struct_ty->members) {
-        for (auto* attr : member->attributes) {
-          if (IsShaderIOAttribute(attr)) {
-            ctx.Remove(member->attributes, attr);
-          }
+    // Remove entry point IO attributes from struct declarations.
+    // New structures will be created for each entry point, as necessary.
+    for (auto* ty : ctx.src->AST().TypeDecls()) {
+        if (auto* struct_ty = ty->As<ast::Struct>()) {
+            for (auto* member : struct_ty->members) {
+                for (auto* attr : member->attributes) {
+                    if (IsShaderIOAttribute(attr)) {
+                        ctx.Remove(member->attributes, attr);
+                    }
+                }
+            }
         }
-      }
-    }
-  }
-
-  for (auto* func_ast : ctx.src->AST().Functions()) {
-    if (!func_ast->IsEntryPoint()) {
-      continue;
     }
 
-    State state(ctx, *cfg, func_ast);
-    state.Process();
-  }
+    for (auto* func_ast : ctx.src->AST().Functions()) {
+        if (!func_ast->IsEntryPoint()) {
+            continue;
+        }
 
-  ctx.Clone();
+        State state(ctx, *cfg, func_ast);
+        state.Process();
+    }
+
+    ctx.Clone();
 }
 
 CanonicalizeEntryPointIO::Config::Config(ShaderStyle style,
diff --git a/src/tint/transform/canonicalize_entry_point_io.h b/src/tint/transform/canonicalize_entry_point_io.h
index eab4128..64a10f2 100644
--- a/src/tint/transform/canonicalize_entry_point_io.h
+++ b/src/tint/transform/canonicalize_entry_point_io.h
@@ -82,64 +82,61 @@
 ///
 /// @note Depends on the following transforms to have been run first:
 /// * Unshadow
-class CanonicalizeEntryPointIO final
-    : public Castable<CanonicalizeEntryPointIO, Transform> {
- public:
-  /// ShaderStyle is an enumerator of different ways to emit shader IO.
-  enum class ShaderStyle {
-    /// Target SPIR-V (using global variables).
-    kSpirv,
-    /// Target GLSL (using global variables).
-    kGlsl,
-    /// Target MSL (using non-struct function parameters for builtins).
-    kMsl,
-    /// Target HLSL (using structures for all IO).
-    kHlsl,
-  };
+class CanonicalizeEntryPointIO final : public Castable<CanonicalizeEntryPointIO, Transform> {
+  public:
+    /// ShaderStyle is an enumerator of different ways to emit shader IO.
+    enum class ShaderStyle {
+        /// Target SPIR-V (using global variables).
+        kSpirv,
+        /// Target GLSL (using global variables).
+        kGlsl,
+        /// Target MSL (using non-struct function parameters for builtins).
+        kMsl,
+        /// Target HLSL (using structures for all IO).
+        kHlsl,
+    };
 
-  /// Configuration options for the transform.
-  struct Config final : public Castable<Config, Data> {
+    /// Configuration options for the transform.
+    struct Config final : public Castable<Config, Data> {
+        /// Constructor
+        /// @param style the approach to use for emitting shader IO.
+        /// @param sample_mask an optional sample mask to combine with shader masks
+        /// @param emit_vertex_point_size `true` to generate a pointsize builtin
+        explicit Config(ShaderStyle style,
+                        uint32_t sample_mask = 0xFFFFFFFF,
+                        bool emit_vertex_point_size = false);
+
+        /// Copy constructor
+        Config(const Config&);
+
+        /// Destructor
+        ~Config() override;
+
+        /// The approach to use for emitting shader IO.
+        const ShaderStyle shader_style;
+
+        /// A fixed sample mask to combine into masks produced by fragment shaders.
+        const uint32_t fixed_sample_mask;
+
+        /// Set to `true` to generate a pointsize builtin and have it set to 1.0
+        /// from all vertex shaders in the module.
+        const bool emit_vertex_point_size;
+    };
+
     /// Constructor
-    /// @param style the approach to use for emitting shader IO.
-    /// @param sample_mask an optional sample mask to combine with shader masks
-    /// @param emit_vertex_point_size `true` to generate a pointsize builtin
-    explicit Config(ShaderStyle style,
-                    uint32_t sample_mask = 0xFFFFFFFF,
-                    bool emit_vertex_point_size = false);
+    CanonicalizeEntryPointIO();
+    ~CanonicalizeEntryPointIO() override;
 
-    /// Copy constructor
-    Config(const Config&);
+  protected:
+    /// Runs the transform using the CloneContext built for transforming a
+    /// program. Run() is responsible for calling Clone() on the CloneContext.
+    /// @param ctx the CloneContext primed with the input program and
+    /// ProgramBuilder
+    /// @param inputs optional extra transform-specific input data
+    /// @param outputs optional extra transform-specific output data
+    void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const override;
 
-    /// Destructor
-    ~Config() override;
-
-    /// The approach to use for emitting shader IO.
-    const ShaderStyle shader_style;
-
-    /// A fixed sample mask to combine into masks produced by fragment shaders.
-    const uint32_t fixed_sample_mask;
-
-    /// Set to `true` to generate a pointsize builtin and have it set to 1.0
-    /// from all vertex shaders in the module.
-    const bool emit_vertex_point_size;
-  };
-
-  /// Constructor
-  CanonicalizeEntryPointIO();
-  ~CanonicalizeEntryPointIO() override;
-
- protected:
-  /// Runs the transform using the CloneContext built for transforming a
-  /// program. Run() is responsible for calling Clone() on the CloneContext.
-  /// @param ctx the CloneContext primed with the input program and
-  /// ProgramBuilder
-  /// @param inputs optional extra transform-specific input data
-  /// @param outputs optional extra transform-specific output data
-  void Run(CloneContext& ctx,
-           const DataMap& inputs,
-           DataMap& outputs) const override;
-
-  struct State;
+    struct State;
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/canonicalize_entry_point_io_test.cc b/src/tint/transform/canonicalize_entry_point_io_test.cc
index bf4d699..d3fe95a 100644
--- a/src/tint/transform/canonicalize_entry_point_io_test.cc
+++ b/src/tint/transform/canonicalize_entry_point_io_test.cc
@@ -23,21 +23,21 @@
 using CanonicalizeEntryPointIOTest = TransformTest;
 
 TEST_F(CanonicalizeEntryPointIOTest, Error_MissingTransformData) {
-  auto* src = "";
+    auto* src = "";
 
-  auto* expect =
-      "error: missing transform data for "
-      "tint::transform::CanonicalizeEntryPointIO";
+    auto* expect =
+        "error: missing transform data for "
+        "tint::transform::CanonicalizeEntryPointIO";
 
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, NoShaderIO) {
-  // Test that we do not introduce wrapper functions when there is no shader IO
-  // to process.
-  auto* src = R"(
+    // Test that we do not introduce wrapper functions when there is no shader IO
+    // to process.
+    auto* src = R"(
 @stage(fragment)
 fn frag_main() {
 }
@@ -47,18 +47,17 @@
 }
 )";
 
-  auto* expect = src;
+    auto* expect = src;
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kMsl);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kMsl);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, Parameters_Spirv) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(fragment)
 fn frag_main(@location(1) loc1 : f32,
              @location(2) @interpolate(flat) loc2 : vec4<u32>,
@@ -67,7 +66,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @location(1) @internal(disable_validation__ignore_storage_class) var<in> loc1_1 : f32;
 
 @location(2) @interpolate(flat) @internal(disable_validation__ignore_storage_class) var<in> loc2_1 : vec4<u32>;
@@ -84,16 +83,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kSpirv);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kSpirv);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, Parameters_Msl) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(fragment)
 fn frag_main(@location(1) loc1 : f32,
              @location(2) @interpolate(flat) loc2 : vec4<u32>,
@@ -102,7 +100,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol_1 {
   @location(1)
   loc1 : f32,
@@ -120,16 +118,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kMsl);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kMsl);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, Parameters_Hlsl) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(fragment)
 fn frag_main(@location(1) loc1 : f32,
              @location(2) @interpolate(flat) loc2 : vec4<u32>,
@@ -138,7 +135,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol_1 {
   @location(1)
   loc1 : f32,
@@ -158,16 +155,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, Parameter_TypeAlias) {
-  auto* src = R"(
+    auto* src = R"(
 type myf32 = f32;
 
 @stage(fragment)
@@ -176,7 +172,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 type myf32 = f32;
 
 struct tint_symbol_1 {
@@ -194,16 +190,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kMsl);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kMsl);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, Parameter_TypeAlias_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(fragment)
 fn frag_main(@location(1) loc1 : myf32) {
   var x : myf32 = loc1;
@@ -212,7 +207,7 @@
 type myf32 = f32;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol_1 {
   @location(1)
   loc1 : f32,
@@ -230,16 +225,15 @@
 type myf32 = f32;
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kMsl);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kMsl);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, StructParameters_Spirv) {
-  auto* src = R"(
+    auto* src = R"(
 struct FragBuiltins {
   @builtin(position) coord : vec4<f32>,
 };
@@ -256,7 +250,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @location(0) @internal(disable_validation__ignore_storage_class) var<in> loc0_1 : f32;
 
 @location(1) @internal(disable_validation__ignore_storage_class) var<in> loc1_1 : f32;
@@ -284,16 +278,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kSpirv);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kSpirv);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, StructParameters_Spirv_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(fragment)
 fn frag_main(@location(0) loc0 : f32,
              locations : FragLocations,
@@ -310,7 +303,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @location(0) @internal(disable_validation__ignore_storage_class) var<in> loc0_1 : f32;
 
 @location(1) @internal(disable_validation__ignore_storage_class) var<in> loc1_1 : f32;
@@ -338,16 +331,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kSpirv);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kSpirv);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, StructParameters_kMsl) {
-  auto* src = R"(
+    auto* src = R"(
 struct FragBuiltins {
   @builtin(position) coord : vec4<f32>,
 };
@@ -364,7 +356,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct FragBuiltins {
   coord : vec4<f32>,
 }
@@ -393,16 +385,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kMsl);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kMsl);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, StructParameters_kMsl_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(fragment)
 fn frag_main(@location(0) loc0 : f32,
              locations : FragLocations,
@@ -419,7 +410,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol_1 {
   @location(0)
   loc0 : f32,
@@ -448,16 +439,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kMsl);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kMsl);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, StructParameters_Hlsl) {
-  auto* src = R"(
+    auto* src = R"(
 struct FragBuiltins {
   @builtin(position) coord : vec4<f32>,
 };
@@ -474,7 +464,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct FragBuiltins {
   coord : vec4<f32>,
 }
@@ -505,16 +495,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, StructParameters_Hlsl_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(fragment)
 fn frag_main(@location(0) loc0 : f32,
              locations : FragLocations,
@@ -531,7 +520,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol_1 {
   @location(0)
   loc0 : f32,
@@ -562,23 +551,22 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, Return_NonStruct_Spirv) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(fragment)
 fn frag_main() -> @builtin(frag_depth) f32 {
   return 1.0;
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @builtin(frag_depth) @internal(disable_validation__ignore_storage_class) var<out> value : f32;
 
 fn frag_main_inner() -> f32 {
@@ -592,23 +580,22 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kSpirv);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kSpirv);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, Return_NonStruct_Msl) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(fragment)
 fn frag_main() -> @builtin(frag_depth) f32 {
   return 1.0;
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol {
   @builtin(frag_depth)
   value : f32,
@@ -627,23 +614,22 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kMsl);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kMsl);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, Return_NonStruct_Hlsl) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(fragment)
 fn frag_main() -> @builtin(frag_depth) f32 {
   return 1.0;
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol {
   @builtin(frag_depth)
   value : f32,
@@ -662,16 +648,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, Return_Struct_Spirv) {
-  auto* src = R"(
+    auto* src = R"(
 struct FragOutput {
   @location(0) color : vec4<f32>,
   @builtin(frag_depth) depth : f32,
@@ -688,12 +673,12 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @location(0) @internal(disable_validation__ignore_storage_class) var<out> color_1 : vec4<f32>;
 
 @builtin(frag_depth) @internal(disable_validation__ignore_storage_class) var<out> depth_1 : f32;
 
-@builtin(sample_mask) @internal(disable_validation__ignore_storage_class) var<out> mask_1 : array<u32, 1>;
+@builtin(sample_mask) @internal(disable_validation__ignore_storage_class) var<out> mask_1 : array<u32, 1u>;
 
 struct FragOutput {
   color : vec4<f32>,
@@ -714,20 +699,19 @@
   let inner_result = frag_main_inner();
   color_1 = inner_result.color;
   depth_1 = inner_result.depth;
-  mask_1[0] = inner_result.mask;
+  mask_1[0i] = inner_result.mask;
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kSpirv);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kSpirv);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, Return_Struct_Spirv_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(fragment)
 fn frag_main() -> FragOutput {
   var output : FragOutput;
@@ -744,12 +728,12 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @location(0) @internal(disable_validation__ignore_storage_class) var<out> color_1 : vec4<f32>;
 
 @builtin(frag_depth) @internal(disable_validation__ignore_storage_class) var<out> depth_1 : f32;
 
-@builtin(sample_mask) @internal(disable_validation__ignore_storage_class) var<out> mask_1 : array<u32, 1>;
+@builtin(sample_mask) @internal(disable_validation__ignore_storage_class) var<out> mask_1 : array<u32, 1u>;
 
 fn frag_main_inner() -> FragOutput {
   var output : FragOutput;
@@ -764,7 +748,7 @@
   let inner_result = frag_main_inner();
   color_1 = inner_result.color;
   depth_1 = inner_result.depth;
-  mask_1[0] = inner_result.mask;
+  mask_1[0i] = inner_result.mask;
 }
 
 struct FragOutput {
@@ -774,16 +758,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kSpirv);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kSpirv);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, Return_Struct_Msl) {
-  auto* src = R"(
+    auto* src = R"(
 struct FragOutput {
   @location(0) color : vec4<f32>,
   @builtin(frag_depth) depth : f32,
@@ -800,7 +783,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct FragOutput {
   color : vec4<f32>,
   depth : f32,
@@ -835,16 +818,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kMsl);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kMsl);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, Return_Struct_Msl_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(fragment)
 fn frag_main() -> FragOutput {
   var output : FragOutput;
@@ -861,7 +843,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol {
   @location(0)
   color : vec4<f32>,
@@ -896,16 +878,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kMsl);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kMsl);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, Return_Struct_Hlsl) {
-  auto* src = R"(
+    auto* src = R"(
 struct FragOutput {
   @location(0) color : vec4<f32>,
   @builtin(frag_depth) depth : f32,
@@ -922,7 +903,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct FragOutput {
   color : vec4<f32>,
   depth : f32,
@@ -957,16 +938,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, Return_Struct_Hlsl_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(fragment)
 fn frag_main() -> FragOutput {
   var output : FragOutput;
@@ -983,7 +963,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol {
   @location(0)
   color : vec4<f32>,
@@ -1018,17 +998,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(CanonicalizeEntryPointIOTest,
-       StructParameters_SharedDeviceFunction_Spirv) {
-  auto* src = R"(
+TEST_F(CanonicalizeEntryPointIOTest, StructParameters_SharedDeviceFunction_Spirv) {
+    auto* src = R"(
 struct FragmentInput {
   @location(0) value : f32,
   @location(1) mul : f32,
@@ -1049,7 +1027,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @location(0) @internal(disable_validation__ignore_storage_class) var<in> value_1 : f32;
 
 @location(1) @internal(disable_validation__ignore_storage_class) var<in> mul_1 : f32;
@@ -1086,17 +1064,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kSpirv);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kSpirv);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(CanonicalizeEntryPointIOTest,
-       StructParameters_SharedDeviceFunction_Spirv_OutOfOrder) {
-  auto* src = R"(
+TEST_F(CanonicalizeEntryPointIOTest, StructParameters_SharedDeviceFunction_Spirv_OutOfOrder) {
+    auto* src = R"(
 @stage(fragment)
 fn frag_main1(inputs : FragmentInput) {
   var x : f32 = foo(inputs);
@@ -1117,7 +1093,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @location(0) @internal(disable_validation__ignore_storage_class) var<in> value_1 : f32;
 
 @location(1) @internal(disable_validation__ignore_storage_class) var<in> mul_1 : f32;
@@ -1154,17 +1130,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kSpirv);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kSpirv);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(CanonicalizeEntryPointIOTest,
-       StructParameters_SharedDeviceFunction_Msl) {
-  auto* src = R"(
+TEST_F(CanonicalizeEntryPointIOTest, StructParameters_SharedDeviceFunction_Msl) {
+    auto* src = R"(
 struct FragmentInput {
   @location(0) value : f32,
   @location(1) mul : f32,
@@ -1185,7 +1159,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct FragmentInput {
   value : f32,
   mul : f32,
@@ -1228,17 +1202,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kMsl);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kMsl);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(CanonicalizeEntryPointIOTest,
-       StructParameters_SharedDeviceFunction_Msl_OutOfOrder) {
-  auto* src = R"(
+TEST_F(CanonicalizeEntryPointIOTest, StructParameters_SharedDeviceFunction_Msl_OutOfOrder) {
+    auto* src = R"(
 @stage(fragment)
 fn frag_main1(inputs : FragmentInput) {
   var x : f32 = foo(inputs);
@@ -1259,7 +1231,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol_1 {
   @location(0)
   value : f32,
@@ -1302,17 +1274,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kMsl);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kMsl);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(CanonicalizeEntryPointIOTest,
-       StructParameters_SharedDeviceFunction_Hlsl) {
-  auto* src = R"(
+TEST_F(CanonicalizeEntryPointIOTest, StructParameters_SharedDeviceFunction_Hlsl) {
+    auto* src = R"(
 struct FragmentInput {
   @location(0) value : f32,
   @location(1) mul : f32,
@@ -1333,7 +1303,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct FragmentInput {
   value : f32,
   mul : f32,
@@ -1376,17 +1346,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(CanonicalizeEntryPointIOTest,
-       StructParameters_SharedDeviceFunction_Hlsl_OutOfOrder) {
-  auto* src = R"(
+TEST_F(CanonicalizeEntryPointIOTest, StructParameters_SharedDeviceFunction_Hlsl_OutOfOrder) {
+    auto* src = R"(
 @stage(fragment)
 fn frag_main1(inputs : FragmentInput) {
   var x : f32 = foo(inputs);
@@ -1407,7 +1375,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol_1 {
   @location(0)
   value : f32,
@@ -1450,16 +1418,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, Struct_ModuleScopeVariable) {
-  auto* src = R"(
+    auto* src = R"(
 struct FragmentInput {
   @location(0) col1 : f32,
   @location(1) col2 : f32,
@@ -1483,7 +1450,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct FragmentInput {
   col1 : f32,
   col2 : f32,
@@ -1518,16 +1485,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kMsl);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kMsl);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, Struct_ModuleScopeVariable_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(fragment)
 fn frag_main1(inputs : FragmentInput) {
  global_inputs = inputs;
@@ -1551,7 +1517,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol_1 {
   @location(0)
   col1 : f32,
@@ -1586,16 +1552,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kMsl);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kMsl);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, Struct_TypeAliases) {
-  auto* src = R"(
+    auto* src = R"(
 type myf32 = f32;
 
 struct FragmentInput {
@@ -1623,7 +1588,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 type myf32 = f32;
 
 struct FragmentInput {
@@ -1673,16 +1638,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kMsl);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kMsl);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, Struct_TypeAliases_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(fragment)
 fn frag_main(inputs : MyFragmentInput) -> MyFragmentOutput {
   var x : myf32 = foo(inputs);
@@ -1710,7 +1674,7 @@
 type myf32 = f32;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol_1 {
   @location(0)
   col1 : f32,
@@ -1760,16 +1724,15 @@
 type myf32 = f32;
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kMsl);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kMsl);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, InterpolateAttributes) {
-  auto* src = R"(
+    auto* src = R"(
 struct VertexOut {
   @builtin(position) pos : vec4<f32>,
   @location(1) @interpolate(flat) loc1 : f32,
@@ -1794,7 +1757,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct VertexOut {
   pos : vec4<f32>,
   loc1 : f32,
@@ -1852,16 +1815,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, InterpolateAttributes_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(fragment)
 fn frag_main(inputs : FragmentIn,
              @location(3) @interpolate(perspective, centroid) loc3 : f32) {
@@ -1886,7 +1848,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol_1 {
   @location(1) @interpolate(flat)
   loc1 : f32,
@@ -1944,18 +1906,17 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, InterpolateAttributes_Integers_Spirv) {
-  // Test that we add a Flat attribute to integers that are vertex outputs and
-  // fragment inputs, but not vertex inputs or fragment outputs.
-  auto* src = R"(
+    // Test that we add a Flat attribute to integers that are vertex outputs and
+    // fragment inputs, but not vertex inputs or fragment outputs.
+    auto* src = R"(
 struct VertexIn {
   @location(0) i : i32,
   @location(1) u : u32,
@@ -1989,8 +1950,8 @@
 }
 )";
 
-  auto* expect =
-      R"(
+    auto* expect =
+        R"(
 @location(0) @internal(disable_validation__ignore_storage_class) var<in> i_1 : i32;
 
 @location(1) @internal(disable_validation__ignore_storage_class) var<in> u_1 : u32;
@@ -2075,19 +2036,17 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kSpirv);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kSpirv);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(CanonicalizeEntryPointIOTest,
-       InterpolateAttributes_Integers_Spirv_OutOfOrder) {
-  // Test that we add a Flat attribute to integers that are vertex outputs and
-  // fragment inputs, but not vertex inputs or fragment outputs.
-  auto* src = R"(
+TEST_F(CanonicalizeEntryPointIOTest, InterpolateAttributes_Integers_Spirv_OutOfOrder) {
+    // Test that we add a Flat attribute to integers that are vertex outputs and
+    // fragment inputs, but not vertex inputs or fragment outputs.
+    auto* src = R"(
 @stage(vertex)
 fn vert_main(in : VertexIn) -> VertexOut {
   return VertexOut(in.i, in.u, in.vi, in.vu, vec4<f32>());
@@ -2121,8 +2080,8 @@
 };
 )";
 
-  auto* expect =
-      R"(
+    auto* expect =
+        R"(
 @location(0) @internal(disable_validation__ignore_storage_class) var<in> i_1 : i32;
 
 @location(1) @internal(disable_validation__ignore_storage_class) var<in> u_1 : u32;
@@ -2207,16 +2166,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kSpirv);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kSpirv);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, InvariantAttributes) {
-  auto* src = R"(
+    auto* src = R"(
 struct VertexOut {
   @builtin(position) @invariant pos : vec4<f32>,
 };
@@ -2232,7 +2190,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct VertexOut {
   pos : vec4<f32>,
 }
@@ -2272,16 +2230,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, InvariantAttributes_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(vertex)
 fn main1() -> VertexOut {
   return VertexOut();
@@ -2297,7 +2254,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol {
   @builtin(position) @invariant
   pos : vec4<f32>,
@@ -2337,16 +2294,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, Struct_LayoutAttributes) {
-  auto* src = R"(
+    auto* src = R"(
 struct FragmentInput {
   @size(16) @location(1) value : f32,
   @builtin(position) @align(32) coord : vec4<f32>,
@@ -2363,7 +2319,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct FragmentInput {
   @size(16)
   value : f32,
@@ -2405,16 +2361,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, Struct_LayoutAttributes_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(fragment)
 fn frag_main(inputs : FragmentInput) -> FragmentOutput {
   return FragmentOutput(inputs.coord.x * inputs.value + inputs.loc0);
@@ -2431,7 +2386,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol_1 {
   @location(0) @interpolate(linear, sample)
   loc0 : f32,
@@ -2473,16 +2428,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, SortedMembers) {
-  auto* src = R"(
+    auto* src = R"(
 struct VertexOutput {
   @location(1) @interpolate(flat) b : u32,
   @builtin(position) pos : vec4<f32>,
@@ -2510,7 +2464,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct VertexOutput {
   b : u32,
   pos : vec4<f32>,
@@ -2578,16 +2532,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, SortedMembers_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(vertex)
 fn vert_main() -> VertexOutput {
   return VertexOutput();
@@ -2615,7 +2568,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol {
   @location(0)
   a : f32,
@@ -2683,22 +2636,21 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, DontRenameSymbols) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(fragment)
 fn tint_symbol_1(@location(0) col : f32) {
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol_2 {
   @location(0)
   col : f32,
@@ -2713,22 +2665,21 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kMsl);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kMsl);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, FixedSampleMask_VoidNoReturn) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(fragment)
 fn frag_main() {
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol {
   @builtin(sample_mask)
   fixed_sample_mask : u32,
@@ -2746,23 +2697,22 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kMsl, 0x03u);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kMsl, 0x03u);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, FixedSampleMask_VoidWithReturn) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(fragment)
 fn frag_main() {
   return;
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol {
   @builtin(sample_mask)
   fixed_sample_mask : u32,
@@ -2781,23 +2731,22 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kMsl, 0x03u);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kMsl, 0x03u);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, FixedSampleMask_WithAuthoredMask) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(fragment)
 fn frag_main() -> @builtin(sample_mask) u32 {
   return 7u;
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol {
   @builtin(sample_mask)
   value : u32,
@@ -2816,23 +2765,22 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kMsl, 0x03u);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kMsl, 0x03u);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, FixedSampleMask_WithoutAuthoredMask) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(fragment)
 fn frag_main() -> @location(0) f32 {
   return 1.0;
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol {
   @location(0)
   value : f32,
@@ -2854,16 +2802,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kMsl, 0x03u);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kMsl, 0x03u);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, FixedSampleMask_StructWithAuthoredMask) {
-  auto* src = R"(
+    auto* src = R"(
 struct Output {
   @builtin(frag_depth) depth : f32,
   @builtin(sample_mask) mask : u32,
@@ -2876,7 +2823,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct Output {
   depth : f32,
   mask : u32,
@@ -2907,17 +2854,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kMsl, 0x03u);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kMsl, 0x03u);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(CanonicalizeEntryPointIOTest,
-       FixedSampleMask_StructWithAuthoredMask_OutOfOrder) {
-  auto* src = R"(
+TEST_F(CanonicalizeEntryPointIOTest, FixedSampleMask_StructWithAuthoredMask_OutOfOrder) {
+    auto* src = R"(
 @stage(fragment)
 fn frag_main() -> Output {
   return Output(0.5, 7u, 1.0);
@@ -2930,7 +2875,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol {
   @location(0)
   value : f32,
@@ -2961,17 +2906,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kMsl, 0x03u);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kMsl, 0x03u);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(CanonicalizeEntryPointIOTest,
-       FixedSampleMask_StructWithoutAuthoredMask) {
-  auto* src = R"(
+TEST_F(CanonicalizeEntryPointIOTest, FixedSampleMask_StructWithoutAuthoredMask) {
+    auto* src = R"(
 struct Output {
   @builtin(frag_depth) depth : f32,
   @location(0) value : f32,
@@ -2983,7 +2926,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct Output {
   depth : f32,
   value : f32,
@@ -3013,17 +2956,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kMsl, 0x03u);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kMsl, 0x03u);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(CanonicalizeEntryPointIOTest,
-       FixedSampleMask_StructWithoutAuthoredMask_OutOfOrder) {
-  auto* src = R"(
+TEST_F(CanonicalizeEntryPointIOTest, FixedSampleMask_StructWithoutAuthoredMask_OutOfOrder) {
+    auto* src = R"(
 @stage(fragment)
 fn frag_main() -> Output {
   return Output(0.5, 1.0);
@@ -3035,7 +2976,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol {
   @location(0)
   value : f32,
@@ -3065,16 +3006,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kMsl, 0x03u);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kMsl, 0x03u);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, FixedSampleMask_MultipleShaders) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(fragment)
 fn frag_main1() -> @builtin(sample_mask) u32 {
   return 7u;
@@ -3095,7 +3035,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol {
   @builtin(sample_mask)
   value : u32,
@@ -3155,16 +3095,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kMsl, 0x03u);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kMsl, 0x03u);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, FixedSampleMask_AvoidNameClash) {
-  auto* src = R"(
+    auto* src = R"(
 struct FragOut {
   @location(0) fixed_sample_mask : vec4<f32>,
   @location(1) fixed_sample_mask_1 : vec4<f32>,
@@ -3176,7 +3115,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct FragOut {
   fixed_sample_mask : vec4<f32>,
   fixed_sample_mask_1 : vec4<f32>,
@@ -3206,24 +3145,22 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kMsl, 0x03);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kMsl, 0x03);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(CanonicalizeEntryPointIOTest,
-       EmitVertexPointSize_ReturnNonStruct_Spirv) {
-  auto* src = R"(
+TEST_F(CanonicalizeEntryPointIOTest, EmitVertexPointSize_ReturnNonStruct_Spirv) {
+    auto* src = R"(
 @stage(vertex)
 fn vert_main() -> @builtin(position) vec4<f32> {
   return vec4<f32>();
 }
 )";
 
-  auto* expect = R"(
+    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;
@@ -3240,23 +3177,23 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kSpirv, 0xFFFFFFFF, true);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kSpirv,
+                                               0xFFFFFFFF, true);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, EmitVertexPointSize_ReturnNonStruct_Msl) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(vertex)
 fn vert_main() -> @builtin(position) vec4<f32> {
   return vec4<f32>();
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol {
   @builtin(position)
   value : vec4<f32>,
@@ -3278,16 +3215,16 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kMsl, 0xFFFFFFFF, true);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kMsl,
+                                               0xFFFFFFFF, true);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, EmitVertexPointSize_ReturnStruct_Spirv) {
-  auto* src = R"(
+    auto* src = R"(
 struct VertOut {
   @builtin(position) pos : vec4<f32>,
 };
@@ -3298,7 +3235,7 @@
 }
 )";
 
-  auto* expect = R"(
+    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;
@@ -3319,17 +3256,16 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kSpirv, 0xFFFFFFFF, true);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kSpirv,
+                                               0xFFFFFFFF, true);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(CanonicalizeEntryPointIOTest,
-       EmitVertexPointSize_ReturnStruct_Spirv_OutOfOrder) {
-  auto* src = R"(
+TEST_F(CanonicalizeEntryPointIOTest, EmitVertexPointSize_ReturnStruct_Spirv_OutOfOrder) {
+    auto* src = R"(
 @stage(vertex)
 fn vert_main() -> VertOut {
   return VertOut();
@@ -3340,7 +3276,7 @@
 };
 )";
 
-  auto* expect = R"(
+    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;
@@ -3361,16 +3297,16 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kSpirv, 0xFFFFFFFF, true);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kSpirv,
+                                               0xFFFFFFFF, true);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, EmitVertexPointSize_ReturnStruct_Msl) {
-  auto* src = R"(
+    auto* src = R"(
 struct VertOut {
   @builtin(position) pos : vec4<f32>,
 };
@@ -3381,7 +3317,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct VertOut {
   pos : vec4<f32>,
 }
@@ -3407,17 +3343,16 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kMsl, 0xFFFFFFFF, true);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kMsl,
+                                               0xFFFFFFFF, true);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(CanonicalizeEntryPointIOTest,
-       EmitVertexPointSize_ReturnStruct_Msl_OutOfOrder) {
-  auto* src = R"(
+TEST_F(CanonicalizeEntryPointIOTest, EmitVertexPointSize_ReturnStruct_Msl_OutOfOrder) {
+    auto* src = R"(
 @stage(vertex)
 fn vert_main() -> VertOut {
   return VertOut();
@@ -3428,7 +3363,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol {
   @builtin(position)
   pos : vec4<f32>,
@@ -3454,16 +3389,16 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kMsl, 0xFFFFFFFF, true);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kMsl,
+                                               0xFFFFFFFF, true);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, EmitVertexPointSize_AvoidNameClash_Spirv) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> vertex_point_size : f32;
 var<private> vertex_point_size_1 : f32;
 var<private> vertex_point_size_2 : f32;
@@ -3488,7 +3423,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @location(0) @internal(disable_validation__ignore_storage_class) var<in> collide_2 : f32;
 
 @location(1) @internal(disable_validation__ignore_storage_class) var<in> collide_3 : f32;
@@ -3532,17 +3467,16 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kSpirv, 0xFFFFFFFF, true);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kSpirv,
+                                               0xFFFFFFFF, true);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(CanonicalizeEntryPointIOTest,
-       EmitVertexPointSize_AvoidNameClash_Spirv_OutOfOrder) {
-  auto* src = R"(
+TEST_F(CanonicalizeEntryPointIOTest, EmitVertexPointSize_AvoidNameClash_Spirv_OutOfOrder) {
+    auto* src = R"(
 @stage(vertex)
 fn vert_main(collide : VertIn1, collide_1 : VertIn2) -> VertOut {
   let x = collide.collide + collide_1.collide;
@@ -3567,7 +3501,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @location(0) @internal(disable_validation__ignore_storage_class) var<in> collide_2 : f32;
 
 @location(1) @internal(disable_validation__ignore_storage_class) var<in> collide_3 : f32;
@@ -3611,16 +3545,16 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kSpirv, 0xFFFFFFFF, true);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kSpirv,
+                                               0xFFFFFFFF, true);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, EmitVertexPointSize_AvoidNameClash_Msl) {
-  auto* src = R"(
+    auto* src = R"(
 struct VertIn1 {
   @location(0) collide : f32,
 };
@@ -3641,7 +3575,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct VertIn1 {
   collide : f32,
 }
@@ -3687,17 +3621,16 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kMsl, 0xFFFFFFFF, true);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kMsl,
+                                               0xFFFFFFFF, true);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(CanonicalizeEntryPointIOTest,
-       EmitVertexPointSize_AvoidNameClash_Msl_OutOfOrder) {
-  auto* src = R"(
+TEST_F(CanonicalizeEntryPointIOTest, EmitVertexPointSize_AvoidNameClash_Msl_OutOfOrder) {
+    auto* src = R"(
 @stage(vertex)
 fn vert_main(collide : VertIn1, collide_1 : VertIn2) -> VertOut {
   let x = collide.collide + collide_1.collide;
@@ -3718,7 +3651,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol_1 {
   @location(0)
   collide : f32,
@@ -3764,16 +3697,16 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kMsl, 0xFFFFFFFF, true);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kMsl,
+                                               0xFFFFFFFF, true);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, EmitVertexPointSize_AvoidNameClash_Hlsl) {
-  auto* src = R"(
+    auto* src = R"(
 struct VertIn1 {
   @location(0) collide : f32,
 };
@@ -3794,7 +3727,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct VertIn1 {
   collide : f32,
 }
@@ -3840,17 +3773,16 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kHlsl, 0xFFFFFFFF, true);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kHlsl,
+                                               0xFFFFFFFF, true);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(CanonicalizeEntryPointIOTest,
-       EmitVertexPointSize_AvoidNameClash_Hlsl_OutOfOrder) {
-  auto* src = R"(
+TEST_F(CanonicalizeEntryPointIOTest, EmitVertexPointSize_AvoidNameClash_Hlsl_OutOfOrder) {
+    auto* src = R"(
 @stage(vertex)
 fn vert_main(collide : VertIn1, collide_1 : VertIn2) -> VertOut {
   let x = collide.collide + collide_1.collide;
@@ -3871,7 +3803,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol_1 {
   @location(0)
   collide : f32,
@@ -3917,16 +3849,16 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kHlsl, 0xFFFFFFFF, true);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kHlsl,
+                                               0xFFFFFFFF, true);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, SpirvSampleMaskBuiltins) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(fragment)
 fn main(@builtin(sample_index) sample_index : u32,
         @builtin(sample_mask) mask_in : u32
@@ -3935,12 +3867,12 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @builtin(sample_index) @internal(disable_validation__ignore_storage_class) var<in> sample_index_1 : u32;
 
-@builtin(sample_mask) @internal(disable_validation__ignore_storage_class) var<in> mask_in_1 : array<u32, 1>;
+@builtin(sample_mask) @internal(disable_validation__ignore_storage_class) var<in> mask_in_1 : array<u32, 1u>;
 
-@builtin(sample_mask) @internal(disable_validation__ignore_storage_class) var<out> value : array<u32, 1>;
+@builtin(sample_mask) @internal(disable_validation__ignore_storage_class) var<out> value : array<u32, 1u>;
 
 fn main_inner(sample_index : u32, mask_in : u32) -> u32 {
   return mask_in;
@@ -3948,21 +3880,20 @@
 
 @stage(fragment)
 fn main() {
-  let inner_result = main_inner(sample_index_1, mask_in_1[0]);
-  value[0] = inner_result;
+  let inner_result = main_inner(sample_index_1, mask_in_1[0i]);
+  value[0i] = inner_result;
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kSpirv);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kSpirv);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, GLSLSampleMaskBuiltins) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(fragment)
 fn fragment_main(@builtin(sample_index) sample_index : u32,
                  @builtin(sample_mask) mask_in : u32
@@ -3971,12 +3902,12 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @builtin(sample_index) @internal(disable_validation__ignore_storage_class) var<in> gl_SampleID : i32;
 
-@builtin(sample_mask) @internal(disable_validation__ignore_storage_class) var<in> gl_SampleMaskIn : array<i32, 1>;
+@builtin(sample_mask) @internal(disable_validation__ignore_storage_class) var<in> gl_SampleMaskIn : array<i32, 1u>;
 
-@builtin(sample_mask) @internal(disable_validation__ignore_storage_class) var<out> gl_SampleMask : array<i32, 1>;
+@builtin(sample_mask) @internal(disable_validation__ignore_storage_class) var<out> gl_SampleMask : array<i32, 1u>;
 
 fn fragment_main(sample_index : u32, mask_in : u32) -> u32 {
   return mask_in;
@@ -3984,21 +3915,20 @@
 
 @stage(fragment)
 fn main() {
-  let inner_result = fragment_main(bitcast<u32>(gl_SampleID), bitcast<u32>(gl_SampleMaskIn[0]));
-  gl_SampleMask[0] = bitcast<i32>(inner_result);
+  let inner_result = fragment_main(bitcast<u32>(gl_SampleID), bitcast<u32>(gl_SampleMaskIn[0i]));
+  gl_SampleMask[0i] = bitcast<i32>(inner_result);
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kGlsl);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kGlsl);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CanonicalizeEntryPointIOTest, GLSLVertexInstanceIndexBuiltins) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(vertex)
 fn vertex_main(@builtin(vertex_index) vertexID : u32,
                @builtin(instance_index) instanceID : u32
@@ -4007,7 +3937,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @builtin(vertex_index) @internal(disable_validation__ignore_storage_class) var<in> gl_VertexID : i32;
 
 @builtin(instance_index) @internal(disable_validation__ignore_storage_class) var<in> gl_InstanceID : i32;
@@ -4027,12 +3957,11 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kGlsl);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kGlsl);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 }  // namespace
diff --git a/src/tint/transform/combine_samplers.cc b/src/tint/transform/combine_samplers.cc
index 4b1e892..66b5b93 100644
--- a/src/tint/transform/combine_samplers.cc
+++ b/src/tint/transform/combine_samplers.cc
@@ -30,8 +30,8 @@
 namespace {
 
 bool IsGlobal(const tint::sem::VariablePair& pair) {
-  return pair.first->Is<tint::sem::GlobalVariable>() &&
-         (!pair.second || pair.second->Is<tint::sem::GlobalVariable>());
+    return pair.first->Is<tint::sem::GlobalVariable>() &&
+           (!pair.second || pair.second->Is<tint::sem::GlobalVariable>());
 }
 
 }  // namespace
@@ -46,308 +46,296 @@
 
 /// The PIMPL state for the CombineSamplers transform
 struct CombineSamplers::State {
-  /// The clone context
-  CloneContext& ctx;
+    /// The clone context
+    CloneContext& ctx;
 
-  /// The binding info
-  const BindingInfo* binding_info;
+    /// The binding info
+    const BindingInfo* binding_info;
 
-  /// Map from a texture/sampler pair to the corresponding combined sampler
-  /// variable
-  using CombinedTextureSamplerMap =
-      std::unordered_map<sem::VariablePair, const ast::Variable*>;
+    /// Map from a texture/sampler pair to the corresponding combined sampler
+    /// variable
+    using CombinedTextureSamplerMap = std::unordered_map<sem::VariablePair, const ast::Variable*>;
 
-  /// Use sem::BindingPoint without scope.
-  using BindingPoint = sem::BindingPoint;
+    /// Use sem::BindingPoint without scope.
+    using BindingPoint = sem::BindingPoint;
 
-  /// A map of all global texture/sampler variable pairs to the global
-  /// combined sampler variable that will replace it.
-  CombinedTextureSamplerMap global_combined_texture_samplers_;
+    /// A map of all global texture/sampler variable pairs to the global
+    /// combined sampler variable that will replace it.
+    CombinedTextureSamplerMap global_combined_texture_samplers_;
 
-  /// A map of all texture/sampler variable pairs that contain a function
-  /// parameter to the combined sampler function paramter that will replace it.
-  std::unordered_map<const sem::Function*, CombinedTextureSamplerMap>
-      function_combined_texture_samplers_;
+    /// A map of all texture/sampler variable pairs that contain a function
+    /// parameter to the combined sampler function paramter that will replace it.
+    std::unordered_map<const sem::Function*, CombinedTextureSamplerMap>
+        function_combined_texture_samplers_;
 
-  /// Placeholder global samplers used when a function contains texture-only
-  /// references (one comparison sampler, one regular). These are also used as
-  /// temporary sampler parameters to the texture builtins to satisfy the WGSL
-  /// resolver, but are then ignored and removed by the GLSL writer.
-  const ast::Variable* placeholder_samplers_[2] = {};
+    /// Placeholder global samplers used when a function contains texture-only
+    /// references (one comparison sampler, one regular). These are also used as
+    /// temporary sampler parameters to the texture builtins to satisfy the WGSL
+    /// resolver, but are then ignored and removed by the GLSL writer.
+    const ast::Variable* placeholder_samplers_[2] = {};
 
-  /// Group and binding attributes used by all combined sampler globals.
-  /// Group 0 and binding 0 are used, with collisions disabled.
-  /// @returns the newly-created attribute list
-  ast::AttributeList Attributes() const {
-    auto attributes = ctx.dst->GroupAndBinding(0, 0);
-    attributes.push_back(
-        ctx.dst->Disable(ast::DisabledValidation::kBindingPointCollision));
-    return attributes;
-  }
-
-  /// Constructor
-  /// @param context the clone context
-  /// @param info the binding map information
-  State(CloneContext& context, const BindingInfo* info)
-      : ctx(context), binding_info(info) {}
-
-  /// Creates a combined sampler global variables.
-  /// (Note this is actually a Texture node at the AST level, but it will be
-  /// written as the corresponding sampler (eg., sampler2D) on GLSL output.)
-  /// @param texture_var the texture (global) variable
-  /// @param sampler_var the sampler (global) variable
-  /// @param name the default name to use (may be overridden by map lookup)
-  /// @returns the newly-created global variable
-  const ast::Variable* CreateCombinedGlobal(const sem::Variable* texture_var,
-                                            const sem::Variable* sampler_var,
-                                            std::string name) {
-    SamplerTexturePair bp_pair;
-    bp_pair.texture_binding_point =
-        texture_var->As<sem::GlobalVariable>()->BindingPoint();
-    bp_pair.sampler_binding_point =
-        sampler_var ? sampler_var->As<sem::GlobalVariable>()->BindingPoint()
-                    : binding_info->placeholder_binding_point;
-    auto it = binding_info->binding_map.find(bp_pair);
-    if (it != binding_info->binding_map.end()) {
-      name = it->second;
-    }
-    const ast::Type* type = CreateCombinedASTTypeFor(texture_var, sampler_var);
-    Symbol symbol = ctx.dst->Symbols().New(name);
-    return ctx.dst->Global(symbol, type, Attributes());
-  }
-
-  /// Creates placeholder global sampler variables.
-  /// @param kind the sampler kind to create for
-  /// @returns the newly-created global variable
-  const ast::Variable* CreatePlaceholder(ast::SamplerKind kind) {
-    const ast::Type* type = ctx.dst->ty.sampler(kind);
-    const char* name = kind == ast::SamplerKind::kComparisonSampler
-                           ? "placeholder_comparison_sampler"
-                           : "placeholder_sampler";
-    Symbol symbol = ctx.dst->Symbols().New(name);
-    return ctx.dst->Global(symbol, type, Attributes());
-  }
-
-  /// Creates ast::Type for a given texture and sampler variable pair.
-  /// Depth textures with no samplers are turned into the corresponding
-  /// f32 texture (e.g., texture_depth_2d -> texture_2d<f32>).
-  /// @param texture the texture variable of interest
-  /// @param sampler the texture variable of interest
-  /// @returns the newly-created type
-  const ast::Type* CreateCombinedASTTypeFor(const sem::Variable* texture,
-                                            const sem::Variable* sampler) {
-    const sem::Type* texture_type = texture->Type()->UnwrapRef();
-    const sem::DepthTexture* depth = texture_type->As<sem::DepthTexture>();
-    if (depth && !sampler) {
-      return ctx.dst->create<ast::SampledTexture>(depth->dim(),
-                                                  ctx.dst->create<ast::F32>());
-    } else {
-      return CreateASTTypeFor(ctx, texture_type);
-    }
-  }
-
-  /// Performs the transformation
-  void Run() {
-    auto& sem = ctx.src->Sem();
-
-    // Remove all texture and sampler global variables. These will be replaced
-    // by combined samplers.
-    for (auto* var : ctx.src->AST().GlobalVariables()) {
-      auto* type = sem.Get(var->type);
-      if (type && type->IsAnyOf<sem::Texture, sem::Sampler>() &&
-          !type->Is<sem::StorageTexture>()) {
-        ctx.Remove(ctx.src->AST().GlobalDeclarations(), var);
-      } else if (auto binding_point = var->BindingPoint()) {
-        if (binding_point.group->value == 0 &&
-            binding_point.binding->value == 0) {
-          auto* attribute =
-              ctx.dst->Disable(ast::DisabledValidation::kBindingPointCollision);
-          ctx.InsertFront(var->attributes, attribute);
-        }
-      }
+    /// Group and binding attributes used by all combined sampler globals.
+    /// Group 0 and binding 0 are used, with collisions disabled.
+    /// @returns the newly-created attribute list
+    ast::AttributeList Attributes() const {
+        auto attributes = ctx.dst->GroupAndBinding(0, 0);
+        attributes.push_back(ctx.dst->Disable(ast::DisabledValidation::kBindingPointCollision));
+        return attributes;
     }
 
-    // Rewrite all function signatures to use combined samplers, and remove
-    // separate textures & samplers. Create new combined globals where found.
-    ctx.ReplaceAll([&](const ast::Function* src) -> const ast::Function* {
-      if (auto* func = sem.Get(src)) {
-        auto pairs = func->TextureSamplerPairs();
-        if (pairs.empty()) {
-          return nullptr;
-        }
-        ast::VariableList params;
-        for (auto pair : func->TextureSamplerPairs()) {
-          const sem::Variable* texture_var = pair.first;
-          const sem::Variable* sampler_var = pair.second;
-          std::string name =
-              ctx.src->Symbols().NameFor(texture_var->Declaration()->symbol);
-          if (sampler_var) {
-            name += "_" + ctx.src->Symbols().NameFor(
-                              sampler_var->Declaration()->symbol);
-          }
-          if (IsGlobal(pair)) {
-            // Both texture and sampler are global; add a new global variable
-            // to represent the combined sampler (if not already created).
-            utils::GetOrCreate(global_combined_texture_samplers_, pair, [&] {
-              return CreateCombinedGlobal(texture_var, sampler_var, name);
-            });
-          } else {
-            // Either texture or sampler (or both) is a function parameter;
-            // add a new function parameter to represent the combined sampler.
-            const ast::Type* type =
-                CreateCombinedASTTypeFor(texture_var, sampler_var);
-            const ast::Variable* var =
-                ctx.dst->Param(ctx.dst->Symbols().New(name), type);
-            params.push_back(var);
-            function_combined_texture_samplers_[func][pair] = var;
-          }
-        }
-        // Filter out separate textures and samplers from the original
-        // function signature.
-        for (auto* var : src->params) {
-          if (!sem.Get(var->type)->IsAnyOf<sem::Texture, sem::Sampler>()) {
-            params.push_back(ctx.Clone(var));
-          }
-        }
-        // Create a new function signature that differs only in the parameter
-        // list.
-        auto symbol = ctx.Clone(src->symbol);
-        auto* return_type = ctx.Clone(src->return_type);
-        auto* body = ctx.Clone(src->body);
-        auto attributes = ctx.Clone(src->attributes);
-        auto return_type_attributes = ctx.Clone(src->return_type_attributes);
-        return ctx.dst->create<ast::Function>(
-            symbol, params, return_type, body, std::move(attributes),
-            std::move(return_type_attributes));
-      }
-      return nullptr;
-    });
+    /// Constructor
+    /// @param context the clone context
+    /// @param info the binding map information
+    State(CloneContext& context, const BindingInfo* info) : ctx(context), binding_info(info) {}
 
-    // Replace all function call expressions containing texture or
-    // sampler parameters to use the current function's combined samplers or
-    // the combined global samplers, as appropriate.
-    ctx.ReplaceAll([&](const ast::CallExpression* expr)
-                       -> const ast::Expression* {
-      if (auto* call = sem.Get(expr)) {
-        ast::ExpressionList args;
-        // Replace all texture builtin calls.
-        if (auto* builtin = call->Target()->As<sem::Builtin>()) {
-          const auto& signature = builtin->Signature();
-          int sampler_index = signature.IndexOf(sem::ParameterUsage::kSampler);
-          int texture_index = signature.IndexOf(sem::ParameterUsage::kTexture);
-          if (texture_index == -1) {
+    /// Creates a combined sampler global variables.
+    /// (Note this is actually a Texture node at the AST level, but it will be
+    /// written as the corresponding sampler (eg., sampler2D) on GLSL output.)
+    /// @param texture_var the texture (global) variable
+    /// @param sampler_var the sampler (global) variable
+    /// @param name the default name to use (may be overridden by map lookup)
+    /// @returns the newly-created global variable
+    const ast::Variable* CreateCombinedGlobal(const sem::Variable* texture_var,
+                                              const sem::Variable* sampler_var,
+                                              std::string name) {
+        SamplerTexturePair bp_pair;
+        bp_pair.texture_binding_point = texture_var->As<sem::GlobalVariable>()->BindingPoint();
+        bp_pair.sampler_binding_point = sampler_var
+                                            ? sampler_var->As<sem::GlobalVariable>()->BindingPoint()
+                                            : binding_info->placeholder_binding_point;
+        auto it = binding_info->binding_map.find(bp_pair);
+        if (it != binding_info->binding_map.end()) {
+            name = it->second;
+        }
+        const ast::Type* type = CreateCombinedASTTypeFor(texture_var, sampler_var);
+        Symbol symbol = ctx.dst->Symbols().New(name);
+        return ctx.dst->Global(symbol, type, Attributes());
+    }
+
+    /// Creates placeholder global sampler variables.
+    /// @param kind the sampler kind to create for
+    /// @returns the newly-created global variable
+    const ast::Variable* CreatePlaceholder(ast::SamplerKind kind) {
+        const ast::Type* type = ctx.dst->ty.sampler(kind);
+        const char* name = kind == ast::SamplerKind::kComparisonSampler
+                               ? "placeholder_comparison_sampler"
+                               : "placeholder_sampler";
+        Symbol symbol = ctx.dst->Symbols().New(name);
+        return ctx.dst->Global(symbol, type, Attributes());
+    }
+
+    /// Creates ast::Type for a given texture and sampler variable pair.
+    /// Depth textures with no samplers are turned into the corresponding
+    /// f32 texture (e.g., texture_depth_2d -> texture_2d<f32>).
+    /// @param texture the texture variable of interest
+    /// @param sampler the texture variable of interest
+    /// @returns the newly-created type
+    const ast::Type* CreateCombinedASTTypeFor(const sem::Variable* texture,
+                                              const sem::Variable* sampler) {
+        const sem::Type* texture_type = texture->Type()->UnwrapRef();
+        const sem::DepthTexture* depth = texture_type->As<sem::DepthTexture>();
+        if (depth && !sampler) {
+            return ctx.dst->create<ast::SampledTexture>(depth->dim(), ctx.dst->create<ast::F32>());
+        } else {
+            return CreateASTTypeFor(ctx, texture_type);
+        }
+    }
+
+    /// Performs the transformation
+    void Run() {
+        auto& sem = ctx.src->Sem();
+
+        // Remove all texture and sampler global variables. These will be replaced
+        // by combined samplers.
+        for (auto* var : ctx.src->AST().GlobalVariables()) {
+            auto* type = sem.Get(var->type);
+            if (type && type->IsAnyOf<sem::Texture, sem::Sampler>() &&
+                !type->Is<sem::StorageTexture>()) {
+                ctx.Remove(ctx.src->AST().GlobalDeclarations(), var);
+            } else if (auto binding_point = var->BindingPoint()) {
+                if (binding_point.group->value == 0 && binding_point.binding->value == 0) {
+                    auto* attribute =
+                        ctx.dst->Disable(ast::DisabledValidation::kBindingPointCollision);
+                    ctx.InsertFront(var->attributes, attribute);
+                }
+            }
+        }
+
+        // Rewrite all function signatures to use combined samplers, and remove
+        // separate textures & samplers. Create new combined globals where found.
+        ctx.ReplaceAll([&](const ast::Function* src) -> const ast::Function* {
+            if (auto* func = sem.Get(src)) {
+                auto pairs = func->TextureSamplerPairs();
+                if (pairs.empty()) {
+                    return nullptr;
+                }
+                ast::VariableList params;
+                for (auto pair : func->TextureSamplerPairs()) {
+                    const sem::Variable* texture_var = pair.first;
+                    const sem::Variable* sampler_var = pair.second;
+                    std::string name =
+                        ctx.src->Symbols().NameFor(texture_var->Declaration()->symbol);
+                    if (sampler_var) {
+                        name +=
+                            "_" + ctx.src->Symbols().NameFor(sampler_var->Declaration()->symbol);
+                    }
+                    if (IsGlobal(pair)) {
+                        // Both texture and sampler are global; add a new global variable
+                        // to represent the combined sampler (if not already created).
+                        utils::GetOrCreate(global_combined_texture_samplers_, pair, [&] {
+                            return CreateCombinedGlobal(texture_var, sampler_var, name);
+                        });
+                    } else {
+                        // Either texture or sampler (or both) is a function parameter;
+                        // add a new function parameter to represent the combined sampler.
+                        const ast::Type* type = CreateCombinedASTTypeFor(texture_var, sampler_var);
+                        const ast::Variable* var =
+                            ctx.dst->Param(ctx.dst->Symbols().New(name), type);
+                        params.push_back(var);
+                        function_combined_texture_samplers_[func][pair] = var;
+                    }
+                }
+                // Filter out separate textures and samplers from the original
+                // function signature.
+                for (auto* var : src->params) {
+                    if (!sem.Get(var->type)->IsAnyOf<sem::Texture, sem::Sampler>()) {
+                        params.push_back(ctx.Clone(var));
+                    }
+                }
+                // Create a new function signature that differs only in the parameter
+                // list.
+                auto symbol = ctx.Clone(src->symbol);
+                auto* return_type = ctx.Clone(src->return_type);
+                auto* body = ctx.Clone(src->body);
+                auto attributes = ctx.Clone(src->attributes);
+                auto return_type_attributes = ctx.Clone(src->return_type_attributes);
+                return ctx.dst->create<ast::Function>(symbol, params, return_type, body,
+                                                      std::move(attributes),
+                                                      std::move(return_type_attributes));
+            }
             return nullptr;
-          }
-          const sem::Expression* texture = call->Arguments()[texture_index];
-          // We don't want to combine storage textures with anything, since
-          // they never have associated samplers in GLSL.
-          if (texture->Type()->UnwrapRef()->Is<sem::StorageTexture>()) {
-            return nullptr;
-          }
-          const sem::Expression* sampler =
-              sampler_index != -1 ? call->Arguments()[sampler_index] : nullptr;
-          auto* texture_var = texture->As<sem::VariableUser>()->Variable();
-          auto* sampler_var =
-              sampler ? sampler->As<sem::VariableUser>()->Variable() : nullptr;
-          sem::VariablePair new_pair(texture_var, sampler_var);
-          for (auto* arg : expr->args) {
-            auto* type = ctx.src->TypeOf(arg)->UnwrapRef();
-            if (type->Is<sem::Texture>()) {
-              const ast::Variable* var =
-                  IsGlobal(new_pair)
-                      ? global_combined_texture_samplers_[new_pair]
-                      : function_combined_texture_samplers_
-                            [call->Stmt()->Function()][new_pair];
-              args.push_back(ctx.dst->Expr(var->symbol));
-            } else if (auto* sampler_type = type->As<sem::Sampler>()) {
-              ast::SamplerKind kind = sampler_type->kind();
-              int index = (kind == ast::SamplerKind::kSampler) ? 0 : 1;
-              const ast::Variable*& p = placeholder_samplers_[index];
-              if (!p) {
-                p = CreatePlaceholder(kind);
-              }
-              args.push_back(ctx.dst->Expr(p->symbol));
-            } else {
-              args.push_back(ctx.Clone(arg));
-            }
-          }
-          const ast::Expression* value =
-              ctx.dst->Call(ctx.Clone(expr->target.name), args);
-          if (builtin->Type() == sem::BuiltinType::kTextureLoad &&
-              texture_var->Type()->UnwrapRef()->Is<sem::DepthTexture>() &&
-              !call->Stmt()->Declaration()->Is<ast::CallStatement>()) {
-            value = ctx.dst->MemberAccessor(value, "x");
-          }
-          return value;
-        }
-        // Replace all function calls.
-        if (auto* callee = call->Target()->As<sem::Function>()) {
-          for (auto pair : callee->TextureSamplerPairs()) {
-            // Global pairs used by the callee do not require a function
-            // parameter at the call site.
-            if (IsGlobal(pair)) {
-              continue;
-            }
-            const sem::Variable* texture_var = pair.first;
-            const sem::Variable* sampler_var = pair.second;
-            if (auto* param = texture_var->As<sem::Parameter>()) {
-              const sem::Expression* texture =
-                  call->Arguments()[param->Index()];
-              texture_var = texture->As<sem::VariableUser>()->Variable();
-            }
-            if (sampler_var) {
-              if (auto* param = sampler_var->As<sem::Parameter>()) {
-                const sem::Expression* sampler =
-                    call->Arguments()[param->Index()];
-                sampler_var = sampler->As<sem::VariableUser>()->Variable();
-              }
-            }
-            sem::VariablePair new_pair(texture_var, sampler_var);
-            // If both texture and sampler are (now) global, pass that
-            // global variable to the callee. Otherwise use the caller's
-            // function parameter for this pair.
-            const ast::Variable* var =
-                IsGlobal(new_pair) ? global_combined_texture_samplers_[new_pair]
-                                   : function_combined_texture_samplers_
-                                         [call->Stmt()->Function()][new_pair];
-            auto* arg = ctx.dst->Expr(var->symbol);
-            args.push_back(arg);
-          }
-          // Append all of the remaining non-texture and non-sampler
-          // parameters.
-          for (auto* arg : expr->args) {
-            if (!ctx.src->TypeOf(arg)
-                     ->UnwrapRef()
-                     ->IsAnyOf<sem::Texture, sem::Sampler>()) {
-              args.push_back(ctx.Clone(arg));
-            }
-          }
-          return ctx.dst->Call(ctx.Clone(expr->target.name), args);
-        }
-      }
-      return nullptr;
-    });
+        });
 
-    ctx.Clone();
-  }
+        // Replace all function call expressions containing texture or
+        // sampler parameters to use the current function's combined samplers or
+        // the combined global samplers, as appropriate.
+        ctx.ReplaceAll([&](const ast::CallExpression* expr) -> const ast::Expression* {
+            if (auto* call = sem.Get(expr)) {
+                ast::ExpressionList args;
+                // Replace all texture builtin calls.
+                if (auto* builtin = call->Target()->As<sem::Builtin>()) {
+                    const auto& signature = builtin->Signature();
+                    int sampler_index = signature.IndexOf(sem::ParameterUsage::kSampler);
+                    int texture_index = signature.IndexOf(sem::ParameterUsage::kTexture);
+                    if (texture_index == -1) {
+                        return nullptr;
+                    }
+                    const sem::Expression* texture = call->Arguments()[texture_index];
+                    // We don't want to combine storage textures with anything, since
+                    // they never have associated samplers in GLSL.
+                    if (texture->Type()->UnwrapRef()->Is<sem::StorageTexture>()) {
+                        return nullptr;
+                    }
+                    const sem::Expression* sampler =
+                        sampler_index != -1 ? call->Arguments()[sampler_index] : nullptr;
+                    auto* texture_var = texture->As<sem::VariableUser>()->Variable();
+                    auto* sampler_var =
+                        sampler ? sampler->As<sem::VariableUser>()->Variable() : nullptr;
+                    sem::VariablePair new_pair(texture_var, sampler_var);
+                    for (auto* arg : expr->args) {
+                        auto* type = ctx.src->TypeOf(arg)->UnwrapRef();
+                        if (type->Is<sem::Texture>()) {
+                            const ast::Variable* var =
+                                IsGlobal(new_pair)
+                                    ? global_combined_texture_samplers_[new_pair]
+                                    : function_combined_texture_samplers_[call->Stmt()->Function()]
+                                                                         [new_pair];
+                            args.push_back(ctx.dst->Expr(var->symbol));
+                        } else if (auto* sampler_type = type->As<sem::Sampler>()) {
+                            ast::SamplerKind kind = sampler_type->kind();
+                            int index = (kind == ast::SamplerKind::kSampler) ? 0 : 1;
+                            const ast::Variable*& p = placeholder_samplers_[index];
+                            if (!p) {
+                                p = CreatePlaceholder(kind);
+                            }
+                            args.push_back(ctx.dst->Expr(p->symbol));
+                        } else {
+                            args.push_back(ctx.Clone(arg));
+                        }
+                    }
+                    const ast::Expression* value =
+                        ctx.dst->Call(ctx.Clone(expr->target.name), args);
+                    if (builtin->Type() == sem::BuiltinType::kTextureLoad &&
+                        texture_var->Type()->UnwrapRef()->Is<sem::DepthTexture>() &&
+                        !call->Stmt()->Declaration()->Is<ast::CallStatement>()) {
+                        value = ctx.dst->MemberAccessor(value, "x");
+                    }
+                    return value;
+                }
+                // Replace all function calls.
+                if (auto* callee = call->Target()->As<sem::Function>()) {
+                    for (auto pair : callee->TextureSamplerPairs()) {
+                        // Global pairs used by the callee do not require a function
+                        // parameter at the call site.
+                        if (IsGlobal(pair)) {
+                            continue;
+                        }
+                        const sem::Variable* texture_var = pair.first;
+                        const sem::Variable* sampler_var = pair.second;
+                        if (auto* param = texture_var->As<sem::Parameter>()) {
+                            const sem::Expression* texture = call->Arguments()[param->Index()];
+                            texture_var = texture->As<sem::VariableUser>()->Variable();
+                        }
+                        if (sampler_var) {
+                            if (auto* param = sampler_var->As<sem::Parameter>()) {
+                                const sem::Expression* sampler = call->Arguments()[param->Index()];
+                                sampler_var = sampler->As<sem::VariableUser>()->Variable();
+                            }
+                        }
+                        sem::VariablePair new_pair(texture_var, sampler_var);
+                        // If both texture and sampler are (now) global, pass that
+                        // global variable to the callee. Otherwise use the caller's
+                        // function parameter for this pair.
+                        const ast::Variable* var =
+                            IsGlobal(new_pair)
+                                ? global_combined_texture_samplers_[new_pair]
+                                : function_combined_texture_samplers_[call->Stmt()->Function()]
+                                                                     [new_pair];
+                        auto* arg = ctx.dst->Expr(var->symbol);
+                        args.push_back(arg);
+                    }
+                    // Append all of the remaining non-texture and non-sampler
+                    // parameters.
+                    for (auto* arg : expr->args) {
+                        if (!ctx.src->TypeOf(arg)
+                                 ->UnwrapRef()
+                                 ->IsAnyOf<sem::Texture, sem::Sampler>()) {
+                            args.push_back(ctx.Clone(arg));
+                        }
+                    }
+                    return ctx.dst->Call(ctx.Clone(expr->target.name), args);
+                }
+            }
+            return nullptr;
+        });
+
+        ctx.Clone();
+    }
 };
 
 CombineSamplers::CombineSamplers() = default;
 
 CombineSamplers::~CombineSamplers() = default;
 
-void CombineSamplers::Run(CloneContext& ctx,
-                          const DataMap& inputs,
-                          DataMap&) const {
-  auto* binding_info = inputs.Get<BindingInfo>();
-  if (!binding_info) {
-    ctx.dst->Diagnostics().add_error(
-        diag::System::Transform,
-        "missing transform data for " + std::string(TypeInfo().name));
-    return;
-  }
+void CombineSamplers::Run(CloneContext& ctx, const DataMap& inputs, DataMap&) const {
+    auto* binding_info = inputs.Get<BindingInfo>();
+    if (!binding_info) {
+        ctx.dst->Diagnostics().add_error(
+            diag::System::Transform, "missing transform data for " + std::string(TypeInfo().name));
+        return;
+    }
 
-  State(ctx, binding_info).Run();
+    State(ctx, binding_info).Run();
 }
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/combine_samplers.h b/src/tint/transform/combine_samplers.h
index d15d2ab..8dfc098 100644
--- a/src/tint/transform/combine_samplers.h
+++ b/src/tint/transform/combine_samplers.h
@@ -53,54 +53,52 @@
 /// (dimensionality, component type, etc). The GLSL writer outputs such
 /// (Tint) Textures as (GLSL) Samplers.
 class CombineSamplers final : public Castable<CombineSamplers, Transform> {
- public:
-  /// A pair of binding points.
-  using SamplerTexturePair = sem::SamplerTexturePair;
+  public:
+    /// A pair of binding points.
+    using SamplerTexturePair = sem::SamplerTexturePair;
 
-  /// A map from a sampler/texture pair to a named global.
-  using BindingMap = std::unordered_map<SamplerTexturePair, std::string>;
+    /// A map from a sampler/texture pair to a named global.
+    using BindingMap = std::unordered_map<SamplerTexturePair, std::string>;
 
-  /// The client-provided mapping from separate texture and sampler binding
-  /// points to combined sampler binding point.
-  struct BindingInfo final : public Castable<Data, transform::Data> {
+    /// The client-provided mapping from separate texture and sampler binding
+    /// points to combined sampler binding point.
+    struct BindingInfo final : public Castable<Data, transform::Data> {
+        /// Constructor
+        /// @param map the map of all (texture, sampler) -> (combined) pairs
+        /// @param placeholder the binding point to use for placeholder samplers.
+        BindingInfo(const BindingMap& map, const sem::BindingPoint& placeholder);
+
+        /// Copy constructor
+        /// @param other the other BindingInfo to copy
+        BindingInfo(const BindingInfo& other);
+
+        /// Destructor
+        ~BindingInfo() override;
+
+        /// A map of bindings from (texture, sampler) -> combined sampler.
+        BindingMap binding_map;
+
+        /// The binding point to use for placeholder samplers.
+        sem::BindingPoint placeholder_binding_point;
+    };
+
     /// Constructor
-    /// @param map the map of all (texture, sampler) -> (combined) pairs
-    /// @param placeholder the binding point to use for placeholder samplers.
-    BindingInfo(const BindingMap& map, const sem::BindingPoint& placeholder);
-
-    /// Copy constructor
-    /// @param other the other BindingInfo to copy
-    BindingInfo(const BindingInfo& other);
+    CombineSamplers();
 
     /// Destructor
-    ~BindingInfo() override;
+    ~CombineSamplers() override;
 
-    /// A map of bindings from (texture, sampler) -> combined sampler.
-    BindingMap binding_map;
+  protected:
+    /// The PIMPL state for this transform
+    struct State;
 
-    /// The binding point to use for placeholder samplers.
-    sem::BindingPoint placeholder_binding_point;
-  };
-
-  /// Constructor
-  CombineSamplers();
-
-  /// Destructor
-  ~CombineSamplers() override;
-
- protected:
-  /// The PIMPL state for this transform
-  struct State;
-
-  /// Runs the transform using the CloneContext built for transforming a
-  /// program. Run() is responsible for calling Clone() on the CloneContext.
-  /// @param ctx the CloneContext primed with the input program and
-  /// ProgramBuilder
-  /// @param inputs optional extra transform-specific input data
-  /// @param outputs optional extra transform-specific output data
-  void Run(CloneContext& ctx,
-           const DataMap& inputs,
-           DataMap& outputs) const override;
+    /// Runs the transform using the CloneContext built for transforming a
+    /// program. Run() is responsible for calling Clone() on the CloneContext.
+    /// @param ctx the CloneContext primed with the input program and
+    /// ProgramBuilder
+    /// @param inputs optional extra transform-specific input data
+    /// @param outputs optional extra transform-specific output data
+    void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const override;
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/combine_samplers_test.cc b/src/tint/transform/combine_samplers_test.cc
index cb60103..1d84859 100644
--- a/src/tint/transform/combine_samplers_test.cc
+++ b/src/tint/transform/combine_samplers_test.cc
@@ -25,19 +25,18 @@
 using CombineSamplersTest = TransformTest;
 
 TEST_F(CombineSamplersTest, EmptyModule) {
-  auto* src = "";
-  auto* expect = "";
+    auto* src = "";
+    auto* expect = "";
 
-  DataMap data;
-  data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(),
-                                         sem::BindingPoint());
-  auto got = Run<CombineSamplers>(src, data);
+    DataMap data;
+    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), sem::BindingPoint());
+    auto got = Run<CombineSamplers>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CombineSamplersTest, SimplePair) {
-  auto* src = R"(
+    auto* src = R"(
 @group(0) @binding(0) var t : texture_2d<f32>;
 
 @group(0) @binding(1) var s : sampler;
@@ -46,7 +45,7 @@
   return textureSample(t, s, vec2<f32>(1.0, 2.0));
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 @group(0) @binding(0) @internal(disable_validation__binding_point_collision) var t_s : texture_2d<f32>;
 
 @group(0) @binding(0) @internal(disable_validation__binding_point_collision) var placeholder_sampler : sampler;
@@ -56,16 +55,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(),
-                                         sem::BindingPoint());
-  auto got = Run<CombineSamplers>(src, data);
+    DataMap data;
+    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), sem::BindingPoint());
+    auto got = Run<CombineSamplers>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CombineSamplersTest, SimplePair_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn main() -> vec4<f32> {
   return textureSample(t, s, vec2<f32>(1.0, 2.0));
 }
@@ -74,7 +72,7 @@
 
 @group(0) @binding(1) var s : sampler;
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 @group(0) @binding(0) @internal(disable_validation__binding_point_collision) var t_s : texture_2d<f32>;
 
 @group(0) @binding(0) @internal(disable_validation__binding_point_collision) var placeholder_sampler : sampler;
@@ -84,16 +82,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(),
-                                         sem::BindingPoint());
-  auto got = Run<CombineSamplers>(src, data);
+    DataMap data;
+    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), sem::BindingPoint());
+    auto got = Run<CombineSamplers>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CombineSamplersTest, SimplePairInAFunction) {
-  auto* src = R"(
+    auto* src = R"(
 @group(0) @binding(0) var t : texture_2d<f32>;
 
 @group(0) @binding(1) var s : sampler;
@@ -106,7 +103,7 @@
   return sample(t, s, vec2<f32>(1.0, 2.0));
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 @group(0) @binding(0) @internal(disable_validation__binding_point_collision) var placeholder_sampler : sampler;
 
 fn sample(t_s : texture_2d<f32>, coords : vec2<f32>) -> vec4<f32> {
@@ -120,16 +117,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(),
-                                         sem::BindingPoint());
-  auto got = Run<CombineSamplers>(src, data);
+    DataMap data;
+    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), sem::BindingPoint());
+    auto got = Run<CombineSamplers>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CombineSamplersTest, SimplePairInAFunction_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn main() -> vec4<f32> {
   return sample(t, s, vec2<f32>(1.0, 2.0));
 }
@@ -142,7 +138,7 @@
 
 @group(0) @binding(0) var t : texture_2d<f32>;
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 @group(0) @binding(0) @internal(disable_validation__binding_point_collision) var t_s : texture_2d<f32>;
 
 fn main() -> vec4<f32> {
@@ -156,16 +152,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(),
-                                         sem::BindingPoint());
-  auto got = Run<CombineSamplers>(src, data);
+    DataMap data;
+    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), sem::BindingPoint());
+    auto got = Run<CombineSamplers>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CombineSamplersTest, SimplePairRename) {
-  auto* src = R"(
+    auto* src = R"(
 @group(0) @binding(1) var t : texture_2d<f32>;
 
 @group(2) @binding(3) var s : sampler;
@@ -174,7 +169,7 @@
   return textureSample(t, s, vec2<f32>(1.0, 2.0));
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 @group(0) @binding(0) @internal(disable_validation__binding_point_collision) var fuzzy : texture_2d<f32>;
 
 @group(0) @binding(0) @internal(disable_validation__binding_point_collision) var placeholder_sampler : sampler;
@@ -184,23 +179,23 @@
 }
 )";
 
-  DataMap data;
-  CombineSamplers::BindingMap map;
-  sem::SamplerTexturePair pair;
-  pair.texture_binding_point.group = 0;
-  pair.texture_binding_point.binding = 1;
-  pair.sampler_binding_point.group = 2;
-  pair.sampler_binding_point.binding = 3;
-  map[pair] = "fuzzy";
-  sem::BindingPoint placeholder{1024, 0};
-  data.Add<CombineSamplers::BindingInfo>(map, placeholder);
-  auto got = Run<CombineSamplers>(src, data);
+    DataMap data;
+    CombineSamplers::BindingMap map;
+    sem::SamplerTexturePair pair;
+    pair.texture_binding_point.group = 0;
+    pair.texture_binding_point.binding = 1;
+    pair.sampler_binding_point.group = 2;
+    pair.sampler_binding_point.binding = 3;
+    map[pair] = "fuzzy";
+    sem::BindingPoint placeholder{1024, 0};
+    data.Add<CombineSamplers::BindingInfo>(map, placeholder);
+    auto got = Run<CombineSamplers>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CombineSamplersTest, SimplePairRenameMiss) {
-  auto* src = R"(
+    auto* src = R"(
 @group(0) @binding(1) var t : texture_2d<f32>;
 
 @group(2) @binding(3) var s : sampler;
@@ -209,7 +204,7 @@
   return textureSample(t, s, vec2<f32>(1.0, 2.0));
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 @group(0) @binding(0) @internal(disable_validation__binding_point_collision) var t_s : texture_2d<f32>;
 
 @group(0) @binding(0) @internal(disable_validation__binding_point_collision) var placeholder_sampler : sampler;
@@ -219,23 +214,23 @@
 }
 )";
 
-  DataMap data;
-  CombineSamplers::BindingMap map;
-  sem::SamplerTexturePair pair;
-  pair.texture_binding_point.group = 3;
-  pair.texture_binding_point.binding = 2;
-  pair.sampler_binding_point.group = 1;
-  pair.sampler_binding_point.binding = 0;
-  map[pair] = "fuzzy";
-  sem::BindingPoint placeholder{1024, 0};
-  data.Add<CombineSamplers::BindingInfo>(map, placeholder);
-  auto got = Run<CombineSamplers>(src, data);
+    DataMap data;
+    CombineSamplers::BindingMap map;
+    sem::SamplerTexturePair pair;
+    pair.texture_binding_point.group = 3;
+    pair.texture_binding_point.binding = 2;
+    pair.sampler_binding_point.group = 1;
+    pair.sampler_binding_point.binding = 0;
+    map[pair] = "fuzzy";
+    sem::BindingPoint placeholder{1024, 0};
+    data.Add<CombineSamplers::BindingInfo>(map, placeholder);
+    auto got = Run<CombineSamplers>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CombineSamplersTest, AliasedTypes) {
-  auto* src = R"(
+    auto* src = R"(
 
 type Tex2d = texture_2d<f32>;
 
@@ -251,7 +246,7 @@
   return sample(t, s, vec2<f32>(1.0, 2.0));
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 type Tex2d = texture_2d<f32>;
 
 @group(0) @binding(0) @internal(disable_validation__binding_point_collision) var placeholder_sampler : sampler;
@@ -267,16 +262,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(),
-                                         sem::BindingPoint());
-  auto got = Run<CombineSamplers>(src, data);
+    DataMap data;
+    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), sem::BindingPoint());
+    auto got = Run<CombineSamplers>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CombineSamplersTest, AliasedTypes_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn main() -> vec4<f32> {
   return sample(t, s, vec2<f32>(1.0, 2.0));
 }
@@ -290,7 +284,7 @@
 
 type Tex2d = texture_2d<f32>;
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 @group(0) @binding(0) @internal(disable_validation__binding_point_collision) var t_s : texture_2d<f32>;
 
 fn main() -> vec4<f32> {
@@ -306,16 +300,15 @@
 type Tex2d = texture_2d<f32>;
 )";
 
-  DataMap data;
-  data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(),
-                                         sem::BindingPoint());
-  auto got = Run<CombineSamplers>(src, data);
+    DataMap data;
+    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), sem::BindingPoint());
+    auto got = Run<CombineSamplers>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CombineSamplersTest, SimplePairInTwoFunctions) {
-  auto* src = R"(
+    auto* src = R"(
 @group(0) @binding(0) var t : texture_2d<f32>;
 
 @group(0) @binding(1) var s : sampler;
@@ -332,7 +325,7 @@
   return f(t, s, vec2<f32>(1.0, 2.0));
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 @group(0) @binding(0) @internal(disable_validation__binding_point_collision) var placeholder_sampler : sampler;
 
 fn g(t_s : texture_2d<f32>, coords : vec2<f32>) -> vec4<f32> {
@@ -350,16 +343,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(),
-                                         sem::BindingPoint());
-  auto got = Run<CombineSamplers>(src, data);
+    DataMap data;
+    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), sem::BindingPoint());
+    auto got = Run<CombineSamplers>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CombineSamplersTest, SimplePairInTwoFunctions_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn main() -> vec4<f32> {
   return f(t, s, vec2<f32>(1.0, 2.0));
 }
@@ -375,7 +367,7 @@
 @group(0) @binding(1) var s : sampler;
 @group(0) @binding(0) var t : texture_2d<f32>;
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 @group(0) @binding(0) @internal(disable_validation__binding_point_collision) var t_s : texture_2d<f32>;
 
 fn main() -> vec4<f32> {
@@ -393,16 +385,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(),
-                                         sem::BindingPoint());
-  auto got = Run<CombineSamplers>(src, data);
+    DataMap data;
+    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), sem::BindingPoint());
+    auto got = Run<CombineSamplers>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CombineSamplersTest, TwoFunctionsGenerateSamePair) {
-  auto* src = R"(
+    auto* src = R"(
 @group(1) @binding(0) var tex : texture_2d<f32>;
 
 @group(1) @binding(1) var samp : sampler;
@@ -419,7 +410,7 @@
   return f() + g();
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 @group(0) @binding(0) @internal(disable_validation__binding_point_collision) var tex_samp : texture_2d<f32>;
 
 @group(0) @binding(0) @internal(disable_validation__binding_point_collision) var placeholder_sampler : sampler;
@@ -437,16 +428,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(),
-                                         sem::BindingPoint());
-  auto got = Run<CombineSamplers>(src, data);
+    DataMap data;
+    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), sem::BindingPoint());
+    auto got = Run<CombineSamplers>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CombineSamplersTest, ThreeTexturesThreeSamplers) {
-  auto* src = R"(
+    auto* src = R"(
 @group(0) @binding(0) var tex1 : texture_2d<f32>;
 @group(0) @binding(1) var tex2 : texture_2d<f32>;
 @group(0) @binding(2) var tex3 : texture_2d<f32>;
@@ -471,7 +461,7 @@
        + sample(tex3, samp3);
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 @group(0) @binding(0) @internal(disable_validation__binding_point_collision) var placeholder_sampler : sampler;
 
 fn sample(t_s : texture_2d<f32>) -> vec4<f32> {
@@ -501,16 +491,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(),
-                                         sem::BindingPoint());
-  auto got = Run<CombineSamplers>(src, data);
+    DataMap data;
+    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), sem::BindingPoint());
+    auto got = Run<CombineSamplers>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CombineSamplersTest, TwoFunctionsTwoTexturesDiamond) {
-  auto* src = R"(
+    auto* src = R"(
 @group(0) @binding(0) var tex1 : texture_2d<f32>;
 
 @group(0) @binding(1) var tex2 : texture_2d<f32>;
@@ -529,7 +518,7 @@
   return f(tex1, tex2, samp, vec2<f32>(1.0, 2.0));
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 @group(0) @binding(0) @internal(disable_validation__binding_point_collision) var placeholder_sampler : sampler;
 
 fn sample(t_s : texture_2d<f32>, coords : vec2<f32>) -> vec4<f32> {
@@ -549,16 +538,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(),
-                                         sem::BindingPoint());
-  auto got = Run<CombineSamplers>(src, data);
+    DataMap data;
+    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), sem::BindingPoint());
+    auto got = Run<CombineSamplers>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CombineSamplersTest, TwoFunctionsTwoSamplersDiamond) {
-  auto* src = R"(
+    auto* src = R"(
 @group(0) @binding(0) var tex : texture_2d<f32>;
 
 @group(0) @binding(1) var samp1 : sampler;
@@ -577,7 +565,7 @@
   return f(tex, samp1, samp2, vec2<f32>(1.0, 2.0));
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 @group(0) @binding(0) @internal(disable_validation__binding_point_collision) var placeholder_sampler : sampler;
 
 fn sample(t_s : texture_2d<f32>, coords : vec2<f32>) -> vec4<f32> {
@@ -597,16 +585,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(),
-                                         sem::BindingPoint());
-  auto got = Run<CombineSamplers>(src, data);
+    DataMap data;
+    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), sem::BindingPoint());
+    auto got = Run<CombineSamplers>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CombineSamplersTest, GlobalTextureLocalSampler) {
-  auto* src = R"(
+    auto* src = R"(
 @group(0) @binding(0) var tex : texture_2d<f32>;
 
 @group(0) @binding(1) var samp1 : sampler;
@@ -621,7 +608,7 @@
   return f(samp1, samp2, vec2<f32>(1.0, 2.0));
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 @group(0) @binding(0) @internal(disable_validation__binding_point_collision) var placeholder_sampler : sampler;
 
 fn f(tex_s1 : texture_2d<f32>, tex_s2 : texture_2d<f32>, coords : vec2<f32>) -> vec4<f32> {
@@ -637,16 +624,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(),
-                                         sem::BindingPoint());
-  auto got = Run<CombineSamplers>(src, data);
+    DataMap data;
+    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), sem::BindingPoint());
+    auto got = Run<CombineSamplers>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CombineSamplersTest, GlobalTextureLocalSampler_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn main() -> vec4<f32> {
   return f(samp1, samp2, vec2<f32>(1.0, 2.0));
 }
@@ -659,7 +645,7 @@
 @group(0) @binding(2) var samp2 : sampler;
 @group(0) @binding(0) var tex : texture_2d<f32>;
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 @group(0) @binding(0) @internal(disable_validation__binding_point_collision) var tex_samp1 : texture_2d<f32>;
 
 @group(0) @binding(0) @internal(disable_validation__binding_point_collision) var tex_samp2 : texture_2d<f32>;
@@ -675,16 +661,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(),
-                                         sem::BindingPoint());
-  auto got = Run<CombineSamplers>(src, data);
+    DataMap data;
+    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), sem::BindingPoint());
+    auto got = Run<CombineSamplers>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CombineSamplersTest, LocalTextureGlobalSampler) {
-  auto* src = R"(
+    auto* src = R"(
 @group(0) @binding(0) var tex1 : texture_2d<f32>;
 
 @group(0) @binding(1) var tex2 : texture_2d<f32>;
@@ -699,7 +684,7 @@
   return f(tex1, tex2, vec2<f32>(1.0, 2.0));
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 @group(0) @binding(0) @internal(disable_validation__binding_point_collision) var placeholder_sampler : sampler;
 
 fn f(t1_samp : texture_2d<f32>, t2_samp : texture_2d<f32>, coords : vec2<f32>) -> vec4<f32> {
@@ -715,16 +700,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(),
-                                         sem::BindingPoint());
-  auto got = Run<CombineSamplers>(src, data);
+    DataMap data;
+    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), sem::BindingPoint());
+    auto got = Run<CombineSamplers>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CombineSamplersTest, LocalTextureGlobalSampler_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn main() -> vec4<f32> {
   return f(tex1, tex2, vec2<f32>(1.0, 2.0));
 }
@@ -737,7 +721,7 @@
 @group(0) @binding(0) var tex1 : texture_2d<f32>;
 @group(0) @binding(1) var tex2 : texture_2d<f32>;
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 @group(0) @binding(0) @internal(disable_validation__binding_point_collision) var tex1_samp : texture_2d<f32>;
 
 @group(0) @binding(0) @internal(disable_validation__binding_point_collision) var tex2_samp : texture_2d<f32>;
@@ -753,16 +737,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(),
-                                         sem::BindingPoint());
-  auto got = Run<CombineSamplers>(src, data);
+    DataMap data;
+    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), sem::BindingPoint());
+    auto got = Run<CombineSamplers>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CombineSamplersTest, TextureLoadNoSampler) {
-  auto* src = R"(
+    auto* src = R"(
 @group(0) @binding(0) var tex : texture_2d<f32>;
 
 fn f(t : texture_2d<f32>, coords : vec2<i32>) -> vec4<f32> {
@@ -773,7 +756,7 @@
   return f(tex, vec2<i32>(1, 2));
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 fn f(t_1 : texture_2d<f32>, coords : vec2<i32>) -> vec4<f32> {
   return textureLoad(t_1, coords, 0);
 }
@@ -785,23 +768,23 @@
 }
 )";
 
-  sem::BindingPoint placeholder{1024, 0};
-  sem::SamplerTexturePair pair;
-  pair.texture_binding_point.group = 0;
-  pair.texture_binding_point.binding = 0;
-  pair.sampler_binding_point.group = placeholder.group;
-  pair.sampler_binding_point.binding = placeholder.binding;
-  CombineSamplers::BindingMap map;
-  map[pair] = "fred";
-  DataMap data;
-  data.Add<CombineSamplers::BindingInfo>(map, placeholder);
-  auto got = Run<CombineSamplers>(src, data);
+    sem::BindingPoint placeholder{1024, 0};
+    sem::SamplerTexturePair pair;
+    pair.texture_binding_point.group = 0;
+    pair.texture_binding_point.binding = 0;
+    pair.sampler_binding_point.group = placeholder.group;
+    pair.sampler_binding_point.binding = placeholder.binding;
+    CombineSamplers::BindingMap map;
+    map[pair] = "fred";
+    DataMap data;
+    data.Add<CombineSamplers::BindingInfo>(map, placeholder);
+    auto got = Run<CombineSamplers>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CombineSamplersTest, TextureWithAndWithoutSampler) {
-  auto* src = R"(
+    auto* src = R"(
 @group(0) @binding(0) var tex : texture_2d<f32>;
 @group(0) @binding(1) var samp : sampler;
 
@@ -810,7 +793,7 @@
          textureSample(tex, samp, vec2<f32>());
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 @group(0) @binding(0) @internal(disable_validation__binding_point_collision) var fred : texture_2d<f32>;
 
 @group(0) @binding(0) @internal(disable_validation__binding_point_collision) var barney : texture_2d<f32>;
@@ -822,30 +805,30 @@
 }
 )";
 
-  sem::BindingPoint placeholder{1024, 0};
-  sem::BindingPoint tex{0, 0};
-  sem::BindingPoint samp{0, 1};
-  sem::SamplerTexturePair pair, placeholder_pair;
-  pair.texture_binding_point.group = tex.group;
-  pair.texture_binding_point.binding = tex.binding;
-  pair.sampler_binding_point.group = samp.group;
-  pair.sampler_binding_point.binding = samp.binding;
-  placeholder_pair.texture_binding_point.group = tex.group;
-  placeholder_pair.texture_binding_point.binding = tex.binding;
-  placeholder_pair.sampler_binding_point.group = placeholder.group;
-  placeholder_pair.sampler_binding_point.binding = placeholder.binding;
-  CombineSamplers::BindingMap map;
-  map[pair] = "barney";
-  map[placeholder_pair] = "fred";
-  DataMap data;
-  data.Add<CombineSamplers::BindingInfo>(map, placeholder);
-  auto got = Run<CombineSamplers>(src, data);
+    sem::BindingPoint placeholder{1024, 0};
+    sem::BindingPoint tex{0, 0};
+    sem::BindingPoint samp{0, 1};
+    sem::SamplerTexturePair pair, placeholder_pair;
+    pair.texture_binding_point.group = tex.group;
+    pair.texture_binding_point.binding = tex.binding;
+    pair.sampler_binding_point.group = samp.group;
+    pair.sampler_binding_point.binding = samp.binding;
+    placeholder_pair.texture_binding_point.group = tex.group;
+    placeholder_pair.texture_binding_point.binding = tex.binding;
+    placeholder_pair.sampler_binding_point.group = placeholder.group;
+    placeholder_pair.sampler_binding_point.binding = placeholder.binding;
+    CombineSamplers::BindingMap map;
+    map[pair] = "barney";
+    map[placeholder_pair] = "fred";
+    DataMap data;
+    data.Add<CombineSamplers::BindingInfo>(map, placeholder);
+    auto got = Run<CombineSamplers>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CombineSamplersTest, TextureSampleCompare) {
-  auto* src = R"(
+    auto* src = R"(
 @group(0) @binding(0) var tex : texture_depth_2d;
 
 @group(0) @binding(1) var samp : sampler_comparison;
@@ -854,7 +837,7 @@
   return vec4<f32>(textureSampleCompare(tex, samp, vec2<f32>(1.0, 2.0), 0.5));
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 @group(0) @binding(0) @internal(disable_validation__binding_point_collision) var tex_samp : texture_depth_2d;
 
 @group(0) @binding(0) @internal(disable_validation__binding_point_collision) var placeholder_comparison_sampler : sampler_comparison;
@@ -864,16 +847,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(),
-                                         sem::BindingPoint());
-  auto got = Run<CombineSamplers>(src, data);
+    DataMap data;
+    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), sem::BindingPoint());
+    auto got = Run<CombineSamplers>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CombineSamplersTest, TextureSampleCompareInAFunction) {
-  auto* src = R"(
+    auto* src = R"(
 @group(0) @binding(0) var tex : texture_depth_2d;
 
 @group(0) @binding(1) var samp : sampler_comparison;
@@ -886,7 +868,7 @@
   return vec4<f32>(f(tex, samp, vec2<f32>(1.0, 2.0)));
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 @group(0) @binding(0) @internal(disable_validation__binding_point_collision) var placeholder_comparison_sampler : sampler_comparison;
 
 fn f(t_s : texture_depth_2d, coords : vec2<f32>) -> f32 {
@@ -900,16 +882,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(),
-                                         sem::BindingPoint());
-  auto got = Run<CombineSamplers>(src, data);
+    DataMap data;
+    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), sem::BindingPoint());
+    auto got = Run<CombineSamplers>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CombineSamplersTest, TextureSampleCompareInAFunction_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn main() -> vec4<f32> {
   return vec4<f32>(f(tex, samp, vec2<f32>(1.0, 2.0)));
 }
@@ -921,7 +902,7 @@
 @group(0) @binding(0) var tex : texture_depth_2d;
 @group(0) @binding(1) var samp : sampler_comparison;
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 @group(0) @binding(0) @internal(disable_validation__binding_point_collision) var tex_samp : texture_depth_2d;
 
 fn main() -> vec4<f32> {
@@ -935,16 +916,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(),
-                                         sem::BindingPoint());
-  auto got = Run<CombineSamplers>(src, data);
+    DataMap data;
+    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), sem::BindingPoint());
+    auto got = Run<CombineSamplers>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CombineSamplersTest, BindingPointCollision) {
-  auto* src = R"(
+    auto* src = R"(
 @group(1) @binding(0) var tex : texture_2d<f32>;
 
 @group(1) @binding(1) var samp : sampler;
@@ -955,7 +935,7 @@
   return textureSample(tex, samp, gcoords);
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 @internal(disable_validation__binding_point_collision) @group(0) @binding(0) var<uniform> gcoords : vec2<f32>;
 
 @group(0) @binding(0) @internal(disable_validation__binding_point_collision) var tex_samp : texture_2d<f32>;
@@ -967,16 +947,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(),
-                                         sem::BindingPoint());
-  auto got = Run<CombineSamplers>(src, data);
+    DataMap data;
+    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), sem::BindingPoint());
+    auto got = Run<CombineSamplers>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(CombineSamplersTest, BindingPointCollision_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn main() -> vec4<f32> {
   return textureSample(tex, samp, gcoords);
 }
@@ -986,7 +965,7 @@
 @group(1) @binding(0) var tex : texture_2d<f32>;
 
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 @group(0) @binding(0) @internal(disable_validation__binding_point_collision) var tex_samp : texture_2d<f32>;
 
 @group(0) @binding(0) @internal(disable_validation__binding_point_collision) var placeholder_sampler : sampler;
@@ -998,12 +977,11 @@
 @internal(disable_validation__binding_point_collision) @group(0) @binding(0) var<uniform> gcoords : vec2<f32>;
 )";
 
-  DataMap data;
-  data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(),
-                                         sem::BindingPoint());
-  auto got = Run<CombineSamplers>(src, data);
+    DataMap data;
+    data.Add<CombineSamplers::BindingInfo>(CombineSamplers::BindingMap(), sem::BindingPoint());
+    auto got = Run<CombineSamplers>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 }  // namespace
diff --git a/src/tint/transform/decompose_memory_access.cc b/src/tint/transform/decompose_memory_access.cc
index 699eeb4..66c6073 100644
--- a/src/tint/transform/decompose_memory_access.cc
+++ b/src/tint/transform/decompose_memory_access.cc
@@ -27,10 +27,10 @@
 #include "src/tint/ast/unary_op.h"
 #include "src/tint/program_builder.h"
 #include "src/tint/sem/array.h"
-#include "src/tint/sem/atomic_type.h"
+#include "src/tint/sem/atomic.h"
 #include "src/tint/sem/call.h"
 #include "src/tint/sem/member_accessor_expression.h"
-#include "src/tint/sem/reference_type.h"
+#include "src/tint/sem/reference.h"
 #include "src/tint/sem/statement.h"
 #include "src/tint/sem/struct.h"
 #include "src/tint/sem/variable.h"
@@ -38,6 +38,8 @@
 #include "src/tint/utils/hash.h"
 #include "src/tint/utils/map.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 TINT_INSTANTIATE_TYPEINFO(tint::transform::DecomposeMemoryAccess);
 TINT_INSTANTIATE_TYPEINFO(tint::transform::DecomposeMemoryAccess::Intrinsic);
 
@@ -48,176 +50,169 @@
 /// Offset is a simple ast::Expression builder interface, used to build byte
 /// offsets for storage and uniform buffer accesses.
 struct Offset : Castable<Offset> {
-  /// @returns builds and returns the ast::Expression in `ctx.dst`
-  virtual const ast::Expression* Build(CloneContext& ctx) const = 0;
+    /// @returns builds and returns the ast::Expression in `ctx.dst`
+    virtual const ast::Expression* Build(CloneContext& ctx) const = 0;
 };
 
 /// OffsetExpr is an implementation of Offset that clones and casts the given
 /// expression to `u32`.
 struct OffsetExpr : Offset {
-  const ast::Expression* const expr = nullptr;
+    const ast::Expression* const expr = nullptr;
 
-  explicit OffsetExpr(const ast::Expression* e) : expr(e) {}
+    explicit OffsetExpr(const ast::Expression* e) : expr(e) {}
 
-  const ast::Expression* Build(CloneContext& ctx) const override {
-    auto* type = ctx.src->Sem().Get(expr)->Type()->UnwrapRef();
-    auto* res = ctx.Clone(expr);
-    if (!type->Is<sem::U32>()) {
-      res = ctx.dst->Construct<ProgramBuilder::u32>(res);
+    const ast::Expression* Build(CloneContext& ctx) const override {
+        auto* type = ctx.src->Sem().Get(expr)->Type()->UnwrapRef();
+        auto* res = ctx.Clone(expr);
+        if (!type->Is<sem::U32>()) {
+            res = ctx.dst->Construct<u32>(res);
+        }
+        return res;
     }
-    return res;
-  }
 };
 
 /// OffsetLiteral is an implementation of Offset that constructs a u32 literal
 /// value.
 struct OffsetLiteral : Castable<OffsetLiteral, Offset> {
-  uint32_t const literal = 0;
+    uint32_t const literal = 0;
 
-  explicit OffsetLiteral(uint32_t lit) : literal(lit) {}
+    explicit OffsetLiteral(uint32_t lit) : literal(lit) {}
 
-  const ast::Expression* Build(CloneContext& ctx) const override {
-    return ctx.dst->Expr(literal);
-  }
+    const ast::Expression* Build(CloneContext& ctx) const override {
+        return ctx.dst->Expr(u32(literal));
+    }
 };
 
 /// OffsetBinOp is an implementation of Offset that constructs a binary-op of
 /// two Offsets.
 struct OffsetBinOp : Offset {
-  ast::BinaryOp op;
-  Offset const* lhs = nullptr;
-  Offset const* rhs = nullptr;
+    ast::BinaryOp op;
+    Offset const* lhs = nullptr;
+    Offset const* rhs = nullptr;
 
-  const ast::Expression* Build(CloneContext& ctx) const override {
-    return ctx.dst->create<ast::BinaryExpression>(op, lhs->Build(ctx),
-                                                  rhs->Build(ctx));
-  }
+    const ast::Expression* Build(CloneContext& ctx) const override {
+        return ctx.dst->create<ast::BinaryExpression>(op, lhs->Build(ctx), rhs->Build(ctx));
+    }
 };
 
 /// LoadStoreKey is the unordered map key to a load or store intrinsic.
 struct LoadStoreKey {
-  ast::StorageClass const storage_class;  // buffer storage class
-  sem::Type const* buf_ty = nullptr;      // buffer type
-  sem::Type const* el_ty = nullptr;       // element type
-  bool operator==(const LoadStoreKey& rhs) const {
-    return storage_class == rhs.storage_class && buf_ty == rhs.buf_ty &&
-           el_ty == rhs.el_ty;
-  }
-  struct Hasher {
-    inline std::size_t operator()(const LoadStoreKey& u) const {
-      return utils::Hash(u.storage_class, u.buf_ty, u.el_ty);
+    ast::StorageClass const storage_class;  // buffer storage class
+    sem::Type const* buf_ty = nullptr;      // buffer type
+    sem::Type const* el_ty = nullptr;       // element type
+    bool operator==(const LoadStoreKey& rhs) const {
+        return storage_class == rhs.storage_class && buf_ty == rhs.buf_ty && el_ty == rhs.el_ty;
     }
-  };
+    struct Hasher {
+        inline std::size_t operator()(const LoadStoreKey& u) const {
+            return utils::Hash(u.storage_class, u.buf_ty, u.el_ty);
+        }
+    };
 };
 
 /// AtomicKey is the unordered map key to an atomic intrinsic.
 struct AtomicKey {
-  sem::Type const* buf_ty = nullptr;  // buffer type
-  sem::Type const* el_ty = nullptr;   // element type
-  sem::BuiltinType const op;          // atomic op
-  bool operator==(const AtomicKey& rhs) const {
-    return buf_ty == rhs.buf_ty && el_ty == rhs.el_ty && op == rhs.op;
-  }
-  struct Hasher {
-    inline std::size_t operator()(const AtomicKey& u) const {
-      return utils::Hash(u.buf_ty, u.el_ty, u.op);
+    sem::Type const* buf_ty = nullptr;  // buffer type
+    sem::Type const* el_ty = nullptr;   // element type
+    sem::BuiltinType const op;          // atomic op
+    bool operator==(const AtomicKey& rhs) const {
+        return buf_ty == rhs.buf_ty && el_ty == rhs.el_ty && op == rhs.op;
     }
-  };
+    struct Hasher {
+        inline std::size_t operator()(const AtomicKey& u) const {
+            return utils::Hash(u.buf_ty, u.el_ty, u.op);
+        }
+    };
 };
 
-bool IntrinsicDataTypeFor(const sem::Type* ty,
-                          DecomposeMemoryAccess::Intrinsic::DataType& out) {
-  if (ty->Is<sem::I32>()) {
-    out = DecomposeMemoryAccess::Intrinsic::DataType::kI32;
-    return true;
-  }
-  if (ty->Is<sem::U32>()) {
-    out = DecomposeMemoryAccess::Intrinsic::DataType::kU32;
-    return true;
-  }
-  if (ty->Is<sem::F32>()) {
-    out = DecomposeMemoryAccess::Intrinsic::DataType::kF32;
-    return true;
-  }
-  if (auto* vec = ty->As<sem::Vector>()) {
-    switch (vec->Width()) {
-      case 2:
-        if (vec->type()->Is<sem::I32>()) {
-          out = DecomposeMemoryAccess::Intrinsic::DataType::kVec2I32;
-          return true;
-        }
-        if (vec->type()->Is<sem::U32>()) {
-          out = DecomposeMemoryAccess::Intrinsic::DataType::kVec2U32;
-          return true;
-        }
-        if (vec->type()->Is<sem::F32>()) {
-          out = DecomposeMemoryAccess::Intrinsic::DataType::kVec2F32;
-          return true;
-        }
-        break;
-      case 3:
-        if (vec->type()->Is<sem::I32>()) {
-          out = DecomposeMemoryAccess::Intrinsic::DataType::kVec3I32;
-          return true;
-        }
-        if (vec->type()->Is<sem::U32>()) {
-          out = DecomposeMemoryAccess::Intrinsic::DataType::kVec3U32;
-          return true;
-        }
-        if (vec->type()->Is<sem::F32>()) {
-          out = DecomposeMemoryAccess::Intrinsic::DataType::kVec3F32;
-          return true;
-        }
-        break;
-      case 4:
-        if (vec->type()->Is<sem::I32>()) {
-          out = DecomposeMemoryAccess::Intrinsic::DataType::kVec4I32;
-          return true;
-        }
-        if (vec->type()->Is<sem::U32>()) {
-          out = DecomposeMemoryAccess::Intrinsic::DataType::kVec4U32;
-          return true;
-        }
-        if (vec->type()->Is<sem::F32>()) {
-          out = DecomposeMemoryAccess::Intrinsic::DataType::kVec4F32;
-          return true;
-        }
-        break;
+bool IntrinsicDataTypeFor(const sem::Type* ty, DecomposeMemoryAccess::Intrinsic::DataType& out) {
+    if (ty->Is<sem::I32>()) {
+        out = DecomposeMemoryAccess::Intrinsic::DataType::kI32;
+        return true;
     }
-    return false;
-  }
+    if (ty->Is<sem::U32>()) {
+        out = DecomposeMemoryAccess::Intrinsic::DataType::kU32;
+        return true;
+    }
+    if (ty->Is<sem::F32>()) {
+        out = DecomposeMemoryAccess::Intrinsic::DataType::kF32;
+        return true;
+    }
+    if (auto* vec = ty->As<sem::Vector>()) {
+        switch (vec->Width()) {
+            case 2:
+                if (vec->type()->Is<sem::I32>()) {
+                    out = DecomposeMemoryAccess::Intrinsic::DataType::kVec2I32;
+                    return true;
+                }
+                if (vec->type()->Is<sem::U32>()) {
+                    out = DecomposeMemoryAccess::Intrinsic::DataType::kVec2U32;
+                    return true;
+                }
+                if (vec->type()->Is<sem::F32>()) {
+                    out = DecomposeMemoryAccess::Intrinsic::DataType::kVec2F32;
+                    return true;
+                }
+                break;
+            case 3:
+                if (vec->type()->Is<sem::I32>()) {
+                    out = DecomposeMemoryAccess::Intrinsic::DataType::kVec3I32;
+                    return true;
+                }
+                if (vec->type()->Is<sem::U32>()) {
+                    out = DecomposeMemoryAccess::Intrinsic::DataType::kVec3U32;
+                    return true;
+                }
+                if (vec->type()->Is<sem::F32>()) {
+                    out = DecomposeMemoryAccess::Intrinsic::DataType::kVec3F32;
+                    return true;
+                }
+                break;
+            case 4:
+                if (vec->type()->Is<sem::I32>()) {
+                    out = DecomposeMemoryAccess::Intrinsic::DataType::kVec4I32;
+                    return true;
+                }
+                if (vec->type()->Is<sem::U32>()) {
+                    out = DecomposeMemoryAccess::Intrinsic::DataType::kVec4U32;
+                    return true;
+                }
+                if (vec->type()->Is<sem::F32>()) {
+                    out = DecomposeMemoryAccess::Intrinsic::DataType::kVec4F32;
+                    return true;
+                }
+                break;
+        }
+        return false;
+    }
 
-  return false;
+    return false;
 }
 
 /// @returns a DecomposeMemoryAccess::Intrinsic attribute that can be applied
 /// to a stub function to load the type `ty`.
-DecomposeMemoryAccess::Intrinsic* IntrinsicLoadFor(
-    ProgramBuilder* builder,
-    ast::StorageClass storage_class,
-    const sem::Type* ty) {
-  DecomposeMemoryAccess::Intrinsic::DataType type;
-  if (!IntrinsicDataTypeFor(ty, type)) {
-    return nullptr;
-  }
-  return builder->ASTNodes().Create<DecomposeMemoryAccess::Intrinsic>(
-      builder->ID(), DecomposeMemoryAccess::Intrinsic::Op::kLoad, storage_class,
-      type);
+DecomposeMemoryAccess::Intrinsic* IntrinsicLoadFor(ProgramBuilder* builder,
+                                                   ast::StorageClass storage_class,
+                                                   const sem::Type* ty) {
+    DecomposeMemoryAccess::Intrinsic::DataType type;
+    if (!IntrinsicDataTypeFor(ty, type)) {
+        return nullptr;
+    }
+    return builder->ASTNodes().Create<DecomposeMemoryAccess::Intrinsic>(
+        builder->ID(), DecomposeMemoryAccess::Intrinsic::Op::kLoad, storage_class, type);
 }
 
 /// @returns a DecomposeMemoryAccess::Intrinsic attribute that can be applied
 /// to a stub function to store the type `ty`.
-DecomposeMemoryAccess::Intrinsic* IntrinsicStoreFor(
-    ProgramBuilder* builder,
-    ast::StorageClass storage_class,
-    const sem::Type* ty) {
-  DecomposeMemoryAccess::Intrinsic::DataType type;
-  if (!IntrinsicDataTypeFor(ty, type)) {
-    return nullptr;
-  }
-  return builder->ASTNodes().Create<DecomposeMemoryAccess::Intrinsic>(
-      builder->ID(), DecomposeMemoryAccess::Intrinsic::Op::kStore,
-      storage_class, type);
+DecomposeMemoryAccess::Intrinsic* IntrinsicStoreFor(ProgramBuilder* builder,
+                                                    ast::StorageClass storage_class,
+                                                    const sem::Type* ty) {
+    DecomposeMemoryAccess::Intrinsic::DataType type;
+    if (!IntrinsicDataTypeFor(ty, type)) {
+        return nullptr;
+    }
+    return builder->ASTNodes().Create<DecomposeMemoryAccess::Intrinsic>(
+        builder->ID(), DecomposeMemoryAccess::Intrinsic::Op::kStore, storage_class, type);
 }
 
 /// @returns a DecomposeMemoryAccess::Intrinsic attribute that can be applied
@@ -225,769 +220,735 @@
 DecomposeMemoryAccess::Intrinsic* IntrinsicAtomicFor(ProgramBuilder* builder,
                                                      sem::BuiltinType ity,
                                                      const sem::Type* ty) {
-  auto op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicLoad;
-  switch (ity) {
-    case sem::BuiltinType::kAtomicLoad:
-      op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicLoad;
-      break;
-    case sem::BuiltinType::kAtomicStore:
-      op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicStore;
-      break;
-    case sem::BuiltinType::kAtomicAdd:
-      op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicAdd;
-      break;
-    case sem::BuiltinType::kAtomicSub:
-      op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicSub;
-      break;
-    case sem::BuiltinType::kAtomicMax:
-      op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicMax;
-      break;
-    case sem::BuiltinType::kAtomicMin:
-      op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicMin;
-      break;
-    case sem::BuiltinType::kAtomicAnd:
-      op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicAnd;
-      break;
-    case sem::BuiltinType::kAtomicOr:
-      op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicOr;
-      break;
-    case sem::BuiltinType::kAtomicXor:
-      op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicXor;
-      break;
-    case sem::BuiltinType::kAtomicExchange:
-      op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicExchange;
-      break;
-    case sem::BuiltinType::kAtomicCompareExchangeWeak:
-      op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicCompareExchangeWeak;
-      break;
-    default:
-      TINT_ICE(Transform, builder->Diagnostics())
-          << "invalid IntrinsicType for DecomposeMemoryAccess::Intrinsic: "
-          << ty->TypeInfo().name;
-      break;
-  }
+    auto op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicLoad;
+    switch (ity) {
+        case sem::BuiltinType::kAtomicLoad:
+            op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicLoad;
+            break;
+        case sem::BuiltinType::kAtomicStore:
+            op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicStore;
+            break;
+        case sem::BuiltinType::kAtomicAdd:
+            op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicAdd;
+            break;
+        case sem::BuiltinType::kAtomicSub:
+            op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicSub;
+            break;
+        case sem::BuiltinType::kAtomicMax:
+            op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicMax;
+            break;
+        case sem::BuiltinType::kAtomicMin:
+            op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicMin;
+            break;
+        case sem::BuiltinType::kAtomicAnd:
+            op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicAnd;
+            break;
+        case sem::BuiltinType::kAtomicOr:
+            op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicOr;
+            break;
+        case sem::BuiltinType::kAtomicXor:
+            op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicXor;
+            break;
+        case sem::BuiltinType::kAtomicExchange:
+            op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicExchange;
+            break;
+        case sem::BuiltinType::kAtomicCompareExchangeWeak:
+            op = DecomposeMemoryAccess::Intrinsic::Op::kAtomicCompareExchangeWeak;
+            break;
+        default:
+            TINT_ICE(Transform, builder->Diagnostics())
+                << "invalid IntrinsicType for DecomposeMemoryAccess::Intrinsic: "
+                << ty->TypeInfo().name;
+            break;
+    }
 
-  DecomposeMemoryAccess::Intrinsic::DataType type;
-  if (!IntrinsicDataTypeFor(ty, type)) {
-    return nullptr;
-  }
-  return builder->ASTNodes().Create<DecomposeMemoryAccess::Intrinsic>(
-      builder->ID(), op, ast::StorageClass::kStorage, type);
+    DecomposeMemoryAccess::Intrinsic::DataType type;
+    if (!IntrinsicDataTypeFor(ty, type)) {
+        return nullptr;
+    }
+    return builder->ASTNodes().Create<DecomposeMemoryAccess::Intrinsic>(
+        builder->ID(), op, ast::StorageClass::kStorage, type);
 }
 
 /// BufferAccess describes a single storage or uniform buffer access
 struct BufferAccess {
-  sem::Expression const* var = nullptr;  // Storage buffer variable
-  Offset const* offset = nullptr;        // The byte offset on var
-  sem::Type const* type = nullptr;       // The type of the access
-  operator bool() const { return var; }  // Returns true if valid
+    sem::Expression const* var = nullptr;  // Storage buffer variable
+    Offset const* offset = nullptr;        // The byte offset on var
+    sem::Type const* type = nullptr;       // The type of the access
+    operator bool() const { return var; }  // Returns true if valid
 };
 
 /// Store describes a single storage or uniform buffer write
 struct Store {
-  const ast::AssignmentStatement* assignment;  // The AST assignment statement
-  BufferAccess target;                         // The target for the write
+    const ast::AssignmentStatement* assignment;  // The AST assignment statement
+    BufferAccess target;                         // The target for the write
 };
 
 }  // namespace
 
 /// State holds the current transform state
 struct DecomposeMemoryAccess::State {
-  /// The clone context
-  CloneContext& ctx;
-  /// Alias to `*ctx.dst`
-  ProgramBuilder& b;
-  /// Map of AST expression to storage or uniform buffer access
-  /// This map has entries added when encountered, and removed when outer
-  /// expressions chain the access.
-  /// Subset of #expression_order, as expressions are not removed from
-  /// #expression_order.
-  std::unordered_map<const ast::Expression*, BufferAccess> accesses;
-  /// The visited order of AST expressions (superset of #accesses)
-  std::vector<const ast::Expression*> expression_order;
-  /// [buffer-type, element-type] -> load function name
-  std::unordered_map<LoadStoreKey, Symbol, LoadStoreKey::Hasher> load_funcs;
-  /// [buffer-type, element-type] -> store function name
-  std::unordered_map<LoadStoreKey, Symbol, LoadStoreKey::Hasher> store_funcs;
-  /// [buffer-type, element-type, atomic-op] -> load function name
-  std::unordered_map<AtomicKey, Symbol, AtomicKey::Hasher> atomic_funcs;
-  /// List of storage or uniform buffer writes
-  std::vector<Store> stores;
-  /// Allocations for offsets
-  utils::BlockAllocator<Offset> offsets_;
+    /// The clone context
+    CloneContext& ctx;
+    /// Alias to `*ctx.dst`
+    ProgramBuilder& b;
+    /// Map of AST expression to storage or uniform buffer access
+    /// This map has entries added when encountered, and removed when outer
+    /// expressions chain the access.
+    /// Subset of #expression_order, as expressions are not removed from
+    /// #expression_order.
+    std::unordered_map<const ast::Expression*, BufferAccess> accesses;
+    /// The visited order of AST expressions (superset of #accesses)
+    std::vector<const ast::Expression*> expression_order;
+    /// [buffer-type, element-type] -> load function name
+    std::unordered_map<LoadStoreKey, Symbol, LoadStoreKey::Hasher> load_funcs;
+    /// [buffer-type, element-type] -> store function name
+    std::unordered_map<LoadStoreKey, Symbol, LoadStoreKey::Hasher> store_funcs;
+    /// [buffer-type, element-type, atomic-op] -> load function name
+    std::unordered_map<AtomicKey, Symbol, AtomicKey::Hasher> atomic_funcs;
+    /// List of storage or uniform buffer writes
+    std::vector<Store> stores;
+    /// Allocations for offsets
+    utils::BlockAllocator<Offset> offsets_;
 
-  /// Constructor
-  /// @param context the CloneContext
-  explicit State(CloneContext& context) : ctx(context), b(*ctx.dst) {}
+    /// Constructor
+    /// @param context the CloneContext
+    explicit State(CloneContext& context) : ctx(context), b(*ctx.dst) {}
 
-  /// @param offset the offset value to wrap in an Offset
-  /// @returns an Offset for the given literal value
-  const Offset* ToOffset(uint32_t offset) {
-    return offsets_.Create<OffsetLiteral>(offset);
-  }
+    /// @param offset the offset value to wrap in an Offset
+    /// @returns an Offset for the given literal value
+    const Offset* ToOffset(uint32_t offset) { return offsets_.Create<OffsetLiteral>(offset); }
 
-  /// @param expr the expression to convert to an Offset
-  /// @returns an Offset for the given ast::Expression
-  const Offset* ToOffset(const ast::Expression* expr) {
-    if (auto* u32 = expr->As<ast::UintLiteralExpression>()) {
-      return offsets_.Create<OffsetLiteral>(u32->value);
-    } else if (auto* i32 = expr->As<ast::SintLiteralExpression>()) {
-      if (i32->value > 0) {
-        return offsets_.Create<OffsetLiteral>(i32->value);
-      }
-    }
-    return offsets_.Create<OffsetExpr>(expr);
-  }
-
-  /// @param offset the Offset that is returned
-  /// @returns the given offset (pass-through)
-  const Offset* ToOffset(const Offset* offset) { return offset; }
-
-  /// @param lhs_ the left-hand side of the add expression
-  /// @param rhs_ the right-hand side of the add expression
-  /// @return an Offset that is a sum of lhs and rhs, performing basic constant
-  /// folding if possible
-  template <typename LHS, typename RHS>
-  const Offset* Add(LHS&& lhs_, RHS&& rhs_) {
-    auto* lhs = ToOffset(std::forward<LHS>(lhs_));
-    auto* rhs = ToOffset(std::forward<RHS>(rhs_));
-    auto* lhs_lit = tint::As<OffsetLiteral>(lhs);
-    auto* rhs_lit = tint::As<OffsetLiteral>(rhs);
-    if (lhs_lit && lhs_lit->literal == 0) {
-      return rhs;
-    }
-    if (rhs_lit && rhs_lit->literal == 0) {
-      return lhs;
-    }
-    if (lhs_lit && rhs_lit) {
-      if (static_cast<uint64_t>(lhs_lit->literal) +
-              static_cast<uint64_t>(rhs_lit->literal) <=
-          0xffffffff) {
-        return offsets_.Create<OffsetLiteral>(lhs_lit->literal +
-                                              rhs_lit->literal);
-      }
-    }
-    auto* out = offsets_.Create<OffsetBinOp>();
-    out->op = ast::BinaryOp::kAdd;
-    out->lhs = lhs;
-    out->rhs = rhs;
-    return out;
-  }
-
-  /// @param lhs_ the left-hand side of the multiply expression
-  /// @param rhs_ the right-hand side of the multiply expression
-  /// @return an Offset that is the multiplication of lhs and rhs, performing
-  /// basic constant folding if possible
-  template <typename LHS, typename RHS>
-  const Offset* Mul(LHS&& lhs_, RHS&& rhs_) {
-    auto* lhs = ToOffset(std::forward<LHS>(lhs_));
-    auto* rhs = ToOffset(std::forward<RHS>(rhs_));
-    auto* lhs_lit = tint::As<OffsetLiteral>(lhs);
-    auto* rhs_lit = tint::As<OffsetLiteral>(rhs);
-    if (lhs_lit && lhs_lit->literal == 0) {
-      return offsets_.Create<OffsetLiteral>(0);
-    }
-    if (rhs_lit && rhs_lit->literal == 0) {
-      return offsets_.Create<OffsetLiteral>(0);
-    }
-    if (lhs_lit && lhs_lit->literal == 1) {
-      return rhs;
-    }
-    if (rhs_lit && rhs_lit->literal == 1) {
-      return lhs;
-    }
-    if (lhs_lit && rhs_lit) {
-      return offsets_.Create<OffsetLiteral>(lhs_lit->literal *
-                                            rhs_lit->literal);
-    }
-    auto* out = offsets_.Create<OffsetBinOp>();
-    out->op = ast::BinaryOp::kMultiply;
-    out->lhs = lhs;
-    out->rhs = rhs;
-    return out;
-  }
-
-  /// AddAccess() adds the `expr -> access` map item to #accesses, and `expr`
-  /// to #expression_order.
-  /// @param expr the expression that performs the access
-  /// @param access the access
-  void AddAccess(const ast::Expression* expr, const BufferAccess& access) {
-    TINT_ASSERT(Transform, access.type);
-    accesses.emplace(expr, access);
-    expression_order.emplace_back(expr);
-  }
-
-  /// TakeAccess() removes the `node` item from #accesses (if it exists),
-  /// returning the BufferAccess. If #accesses does not hold an item for
-  /// `node`, an invalid BufferAccess is returned.
-  /// @param node the expression that performed an access
-  /// @return the BufferAccess for the given expression
-  BufferAccess TakeAccess(const ast::Expression* node) {
-    auto lhs_it = accesses.find(node);
-    if (lhs_it == accesses.end()) {
-      return {};
-    }
-    auto access = lhs_it->second;
-    accesses.erase(node);
-    return access;
-  }
-
-  /// LoadFunc() returns a symbol to an intrinsic function that loads an element
-  /// of type `el_ty` from a storage or uniform buffer of type `buf_ty`.
-  /// The emitted function has the signature:
-  ///   `fn load(buf : buf_ty, offset : u32) -> el_ty`
-  /// @param buf_ty the storage or uniform buffer type
-  /// @param el_ty the storage or uniform buffer element type
-  /// @param var_user the variable user
-  /// @return the name of the function that performs the load
-  Symbol LoadFunc(const sem::Type* buf_ty,
-                  const sem::Type* el_ty,
-                  const sem::VariableUser* var_user) {
-    auto storage_class = var_user->Variable()->StorageClass();
-    return utils::GetOrCreate(
-        load_funcs, LoadStoreKey{storage_class, buf_ty, el_ty}, [&] {
-          auto* buf_ast_ty = CreateASTTypeFor(ctx, buf_ty);
-          auto* disable_validation = b.Disable(
-              ast::DisabledValidation::kIgnoreConstructibleFunctionParameter);
-
-          ast::VariableList params = {
-              // Note: The buffer parameter requires the StorageClass in
-              // order for HLSL to emit this as a ByteAddressBuffer or cbuffer
-              // array.
-              b.create<ast::Variable>(b.Sym("buffer"), storage_class,
-                                      var_user->Variable()->Access(),
-                                      buf_ast_ty, true, false, nullptr,
-                                      ast::AttributeList{disable_validation}),
-              b.Param("offset", b.ty.u32()),
-          };
-
-          auto name = b.Sym();
-
-          if (auto* intrinsic =
-                  IntrinsicLoadFor(ctx.dst, storage_class, el_ty)) {
-            auto* el_ast_ty = CreateASTTypeFor(ctx, el_ty);
-            auto* func = b.create<ast::Function>(
-                name, params, el_ast_ty, nullptr,
-                ast::AttributeList{
-                    intrinsic,
-                    b.Disable(ast::DisabledValidation::kFunctionHasNoBody),
-                },
-                ast::AttributeList{});
-            b.AST().AddFunction(func);
-          } else if (auto* arr_ty = el_ty->As<sem::Array>()) {
-            // fn load_func(buf : buf_ty, offset : u32) -> array<T, N> {
-            //   var arr : array<T, N>;
-            //   for (var i = 0u; i < array_count; i = i + 1) {
-            //     arr[i] = el_load_func(buf, offset + i * array_stride)
-            //   }
-            //   return arr;
-            // }
-            auto load =
-                LoadFunc(buf_ty, arr_ty->ElemType()->UnwrapRef(), var_user);
-            auto* arr =
-                b.Var(b.Symbols().New("arr"), CreateASTTypeFor(ctx, arr_ty));
-            auto* i = b.Var(b.Symbols().New("i"), nullptr, b.Expr(0u));
-            auto* for_init = b.Decl(i);
-            auto* for_cond = b.create<ast::BinaryExpression>(
-                ast::BinaryOp::kLessThan, b.Expr(i), b.Expr(arr_ty->Count()));
-            auto* for_cont = b.Assign(i, b.Add(i, 1u));
-            auto* arr_el = b.IndexAccessor(arr, i);
-            auto* el_offset =
-                b.Add(b.Expr("offset"), b.Mul(i, arr_ty->Stride()));
-            auto* el_val = b.Call(load, "buffer", el_offset);
-            auto* for_loop = b.For(for_init, for_cond, for_cont,
-                                   b.Block(b.Assign(arr_el, el_val)));
-
-            b.Func(name, params, CreateASTTypeFor(ctx, arr_ty),
-                   {
-                       b.Decl(arr),
-                       for_loop,
-                       b.Return(arr),
-                   });
-          } else {
-            ast::ExpressionList values;
-            if (auto* mat_ty = el_ty->As<sem::Matrix>()) {
-              auto* vec_ty = mat_ty->ColumnType();
-              Symbol load = LoadFunc(buf_ty, vec_ty, var_user);
-              for (uint32_t i = 0; i < mat_ty->columns(); i++) {
-                auto* offset = b.Add("offset", i * mat_ty->ColumnStride());
-                values.emplace_back(b.Call(load, "buffer", offset));
-              }
-            } else if (auto* str = el_ty->As<sem::Struct>()) {
-              for (auto* member : str->Members()) {
-                auto* offset = b.Add("offset", member->Offset());
-                Symbol load =
-                    LoadFunc(buf_ty, member->Type()->UnwrapRef(), var_user);
-                values.emplace_back(b.Call(load, "buffer", offset));
-              }
+    /// @param expr the expression to convert to an Offset
+    /// @returns an Offset for the given ast::Expression
+    const Offset* ToOffset(const ast::Expression* expr) {
+        if (auto* lit = expr->As<ast::IntLiteralExpression>()) {
+            if (lit->value > 0) {
+                return offsets_.Create<OffsetLiteral>(static_cast<uint32_t>(lit->value));
             }
-            b.Func(
-                name, params, CreateASTTypeFor(ctx, el_ty),
-                {
-                    b.Return(b.Construct(CreateASTTypeFor(ctx, el_ty), values)),
-                });
-          }
-          return name;
-        });
-  }
+        }
+        return offsets_.Create<OffsetExpr>(expr);
+    }
 
-  /// StoreFunc() returns a symbol to an intrinsic function that stores an
-  /// element of type `el_ty` to a storage buffer of type `buf_ty`.
-  /// The function has the signature:
-  ///   `fn store(buf : buf_ty, offset : u32, value : el_ty)`
-  /// @param buf_ty the storage buffer type
-  /// @param el_ty the storage buffer element type
-  /// @param var_user the variable user
-  /// @return the name of the function that performs the store
-  Symbol StoreFunc(const sem::Type* buf_ty,
-                   const sem::Type* el_ty,
-                   const sem::VariableUser* var_user) {
-    auto storage_class = var_user->Variable()->StorageClass();
-    return utils::GetOrCreate(
-        store_funcs, LoadStoreKey{storage_class, buf_ty, el_ty}, [&] {
-          auto* buf_ast_ty = CreateASTTypeFor(ctx, buf_ty);
-          auto* el_ast_ty = CreateASTTypeFor(ctx, el_ty);
-          auto* disable_validation = b.Disable(
-              ast::DisabledValidation::kIgnoreConstructibleFunctionParameter);
-          ast::VariableList params{
-              // Note: The buffer parameter requires the StorageClass in
-              // order for HLSL to emit this as a ByteAddressBuffer.
+    /// @param offset the Offset that is returned
+    /// @returns the given offset (pass-through)
+    const Offset* ToOffset(const Offset* offset) { return offset; }
 
-              b.create<ast::Variable>(b.Sym("buffer"), storage_class,
-                                      var_user->Variable()->Access(),
-                                      buf_ast_ty, true, false, nullptr,
-                                      ast::AttributeList{disable_validation}),
-              b.Param("offset", b.ty.u32()),
-              b.Param("value", el_ast_ty),
-          };
-
-          auto name = b.Sym();
-
-          if (auto* intrinsic =
-                  IntrinsicStoreFor(ctx.dst, storage_class, el_ty)) {
-            auto* func = b.create<ast::Function>(
-                name, params, b.ty.void_(), nullptr,
-                ast::AttributeList{
-                    intrinsic,
-                    b.Disable(ast::DisabledValidation::kFunctionHasNoBody),
-                },
-                ast::AttributeList{});
-            b.AST().AddFunction(func);
-          } else {
-            ast::StatementList body;
-            if (auto* arr_ty = el_ty->As<sem::Array>()) {
-              // fn store_func(buf : buf_ty, offset : u32, value : el_ty) {
-              //   var array = value; // No dynamic indexing on constant arrays
-              //   for (var i = 0u; i < array_count; i = i + 1) {
-              //     arr[i] = el_store_func(buf, offset + i * array_stride,
-              //                            value[i])
-              //   }
-              //   return arr;
-              // }
-              auto* array =
-                  b.Var(b.Symbols().New("array"), nullptr, b.Expr("value"));
-              auto store =
-                  StoreFunc(buf_ty, arr_ty->ElemType()->UnwrapRef(), var_user);
-              auto* i = b.Var(b.Symbols().New("i"), nullptr, b.Expr(0u));
-              auto* for_init = b.Decl(i);
-              auto* for_cond = b.create<ast::BinaryExpression>(
-                  ast::BinaryOp::kLessThan, b.Expr(i), b.Expr(arr_ty->Count()));
-              auto* for_cont = b.Assign(i, b.Add(i, 1u));
-              auto* arr_el = b.IndexAccessor(array, i);
-              auto* el_offset =
-                  b.Add(b.Expr("offset"), b.Mul(i, arr_ty->Stride()));
-              auto* store_stmt =
-                  b.CallStmt(b.Call(store, "buffer", el_offset, arr_el));
-              auto* for_loop =
-                  b.For(for_init, for_cond, for_cont, b.Block(store_stmt));
-
-              body = {b.Decl(array), for_loop};
-            } else if (auto* mat_ty = el_ty->As<sem::Matrix>()) {
-              auto* vec_ty = mat_ty->ColumnType();
-              Symbol store = StoreFunc(buf_ty, vec_ty, var_user);
-              for (uint32_t i = 0; i < mat_ty->columns(); i++) {
-                auto* offset = b.Add("offset", i * mat_ty->ColumnStride());
-                auto* access = b.IndexAccessor("value", i);
-                auto* call = b.Call(store, "buffer", offset, access);
-                body.emplace_back(b.CallStmt(call));
-              }
-            } else if (auto* str = el_ty->As<sem::Struct>()) {
-              for (auto* member : str->Members()) {
-                auto* offset = b.Add("offset", member->Offset());
-                auto* access = b.MemberAccessor(
-                    "value", ctx.Clone(member->Declaration()->symbol));
-                Symbol store =
-                    StoreFunc(buf_ty, member->Type()->UnwrapRef(), var_user);
-                auto* call = b.Call(store, "buffer", offset, access);
-                body.emplace_back(b.CallStmt(call));
-              }
+    /// @param lhs_ the left-hand side of the add expression
+    /// @param rhs_ the right-hand side of the add expression
+    /// @return an Offset that is a sum of lhs and rhs, performing basic constant
+    /// folding if possible
+    template <typename LHS, typename RHS>
+    const Offset* Add(LHS&& lhs_, RHS&& rhs_) {
+        auto* lhs = ToOffset(std::forward<LHS>(lhs_));
+        auto* rhs = ToOffset(std::forward<RHS>(rhs_));
+        auto* lhs_lit = tint::As<OffsetLiteral>(lhs);
+        auto* rhs_lit = tint::As<OffsetLiteral>(rhs);
+        if (lhs_lit && lhs_lit->literal == 0) {
+            return rhs;
+        }
+        if (rhs_lit && rhs_lit->literal == 0) {
+            return lhs;
+        }
+        if (lhs_lit && rhs_lit) {
+            if (static_cast<uint64_t>(lhs_lit->literal) + static_cast<uint64_t>(rhs_lit->literal) <=
+                0xffffffff) {
+                return offsets_.Create<OffsetLiteral>(lhs_lit->literal + rhs_lit->literal);
             }
-            b.Func(name, params, b.ty.void_(), body);
-          }
+        }
+        auto* out = offsets_.Create<OffsetBinOp>();
+        out->op = ast::BinaryOp::kAdd;
+        out->lhs = lhs;
+        out->rhs = rhs;
+        return out;
+    }
 
-          return name;
-        });
-  }
+    /// @param lhs_ the left-hand side of the multiply expression
+    /// @param rhs_ the right-hand side of the multiply expression
+    /// @return an Offset that is the multiplication of lhs and rhs, performing
+    /// basic constant folding if possible
+    template <typename LHS, typename RHS>
+    const Offset* Mul(LHS&& lhs_, RHS&& rhs_) {
+        auto* lhs = ToOffset(std::forward<LHS>(lhs_));
+        auto* rhs = ToOffset(std::forward<RHS>(rhs_));
+        auto* lhs_lit = tint::As<OffsetLiteral>(lhs);
+        auto* rhs_lit = tint::As<OffsetLiteral>(rhs);
+        if (lhs_lit && lhs_lit->literal == 0) {
+            return offsets_.Create<OffsetLiteral>(0);
+        }
+        if (rhs_lit && rhs_lit->literal == 0) {
+            return offsets_.Create<OffsetLiteral>(0);
+        }
+        if (lhs_lit && lhs_lit->literal == 1) {
+            return rhs;
+        }
+        if (rhs_lit && rhs_lit->literal == 1) {
+            return lhs;
+        }
+        if (lhs_lit && rhs_lit) {
+            return offsets_.Create<OffsetLiteral>(lhs_lit->literal * rhs_lit->literal);
+        }
+        auto* out = offsets_.Create<OffsetBinOp>();
+        out->op = ast::BinaryOp::kMultiply;
+        out->lhs = lhs;
+        out->rhs = rhs;
+        return out;
+    }
 
-  /// AtomicFunc() returns a symbol to an intrinsic function that performs an
-  /// atomic operation from a storage buffer of type `buf_ty`. The function has
-  /// the signature:
-  // `fn atomic_op(buf : buf_ty, offset : u32, ...) -> T`
-  /// @param buf_ty the storage buffer type
-  /// @param el_ty the storage buffer element type
-  /// @param intrinsic the atomic intrinsic
-  /// @param var_user the variable user
-  /// @return the name of the function that performs the load
-  Symbol AtomicFunc(const sem::Type* buf_ty,
+    /// AddAccess() adds the `expr -> access` map item to #accesses, and `expr`
+    /// to #expression_order.
+    /// @param expr the expression that performs the access
+    /// @param access the access
+    void AddAccess(const ast::Expression* expr, const BufferAccess& access) {
+        TINT_ASSERT(Transform, access.type);
+        accesses.emplace(expr, access);
+        expression_order.emplace_back(expr);
+    }
+
+    /// TakeAccess() removes the `node` item from #accesses (if it exists),
+    /// returning the BufferAccess. If #accesses does not hold an item for
+    /// `node`, an invalid BufferAccess is returned.
+    /// @param node the expression that performed an access
+    /// @return the BufferAccess for the given expression
+    BufferAccess TakeAccess(const ast::Expression* node) {
+        auto lhs_it = accesses.find(node);
+        if (lhs_it == accesses.end()) {
+            return {};
+        }
+        auto access = lhs_it->second;
+        accesses.erase(node);
+        return access;
+    }
+
+    /// LoadFunc() returns a symbol to an intrinsic function that loads an element
+    /// of type `el_ty` from a storage or uniform buffer of type `buf_ty`.
+    /// The emitted function has the signature:
+    ///   `fn load(buf : buf_ty, offset : u32) -> el_ty`
+    /// @param buf_ty the storage or uniform buffer type
+    /// @param el_ty the storage or uniform buffer element type
+    /// @param var_user the variable user
+    /// @return the name of the function that performs the load
+    Symbol LoadFunc(const sem::Type* buf_ty,
                     const sem::Type* el_ty,
-                    const sem::Builtin* intrinsic,
                     const sem::VariableUser* var_user) {
-    auto op = intrinsic->Type();
-    return utils::GetOrCreate(atomic_funcs, AtomicKey{buf_ty, el_ty, op}, [&] {
-      auto* buf_ast_ty = CreateASTTypeFor(ctx, buf_ty);
-      auto* disable_validation = b.Disable(
-          ast::DisabledValidation::kIgnoreConstructibleFunctionParameter);
-      // The first parameter to all WGSL atomics is the expression to the
-      // atomic. This is replaced with two parameters: the buffer and offset.
+        auto storage_class = var_user->Variable()->StorageClass();
+        return utils::GetOrCreate(load_funcs, LoadStoreKey{storage_class, buf_ty, el_ty}, [&] {
+            auto* buf_ast_ty = CreateASTTypeFor(ctx, buf_ty);
+            auto* disable_validation =
+                b.Disable(ast::DisabledValidation::kIgnoreConstructibleFunctionParameter);
 
-      ast::VariableList params = {
-          // Note: The buffer parameter requires the kStorage StorageClass in
-          // order for HLSL to emit this as a ByteAddressBuffer.
-          b.create<ast::Variable>(b.Sym("buffer"), ast::StorageClass::kStorage,
-                                  var_user->Variable()->Access(), buf_ast_ty,
-                                  true, false, nullptr,
-                                  ast::AttributeList{disable_validation}),
-          b.Param("offset", b.ty.u32()),
-      };
+            ast::VariableList params = {
+                // Note: The buffer parameter requires the StorageClass in
+                // order for HLSL to emit this as a ByteAddressBuffer or cbuffer
+                // array.
+                b.create<ast::Variable>(b.Sym("buffer"), storage_class,
+                                        var_user->Variable()->Access(), buf_ast_ty, true, false,
+                                        nullptr, ast::AttributeList{disable_validation}),
+                b.Param("offset", b.ty.u32()),
+            };
 
-      // Other parameters are copied as-is:
-      for (size_t i = 1; i < intrinsic->Parameters().size(); i++) {
-        auto* param = intrinsic->Parameters()[i];
-        auto* ty = CreateASTTypeFor(ctx, param->Type());
-        params.emplace_back(b.Param("param_" + std::to_string(i), ty));
-      }
+            auto name = b.Sym();
 
-      auto* atomic = IntrinsicAtomicFor(ctx.dst, op, el_ty);
-      if (atomic == nullptr) {
-        TINT_ICE(Transform, b.Diagnostics())
-            << "IntrinsicAtomicFor() returned nullptr for op " << op
-            << " and type " << el_ty->TypeInfo().name;
-      }
+            if (auto* intrinsic = IntrinsicLoadFor(ctx.dst, storage_class, el_ty)) {
+                auto* el_ast_ty = CreateASTTypeFor(ctx, el_ty);
+                auto* func = b.create<ast::Function>(
+                    name, params, el_ast_ty, nullptr,
+                    ast::AttributeList{
+                        intrinsic,
+                        b.Disable(ast::DisabledValidation::kFunctionHasNoBody),
+                    },
+                    ast::AttributeList{});
+                b.AST().AddFunction(func);
+            } else if (auto* arr_ty = el_ty->As<sem::Array>()) {
+                // fn load_func(buf : buf_ty, offset : u32) -> array<T, N> {
+                //   var arr : array<T, N>;
+                //   for (var i = 0u; i < array_count; i = i + 1) {
+                //     arr[i] = el_load_func(buf, offset + i * array_stride)
+                //   }
+                //   return arr;
+                // }
+                auto load = LoadFunc(buf_ty, arr_ty->ElemType()->UnwrapRef(), var_user);
+                auto* arr = b.Var(b.Symbols().New("arr"), CreateASTTypeFor(ctx, arr_ty));
+                auto* i = b.Var(b.Symbols().New("i"), nullptr, b.Expr(0_u));
+                auto* for_init = b.Decl(i);
+                auto* for_cond = b.create<ast::BinaryExpression>(
+                    ast::BinaryOp::kLessThan, b.Expr(i), b.Expr(u32(arr_ty->Count())));
+                auto* for_cont = b.Assign(i, b.Add(i, 1_u));
+                auto* arr_el = b.IndexAccessor(arr, i);
+                auto* el_offset = b.Add(b.Expr("offset"), b.Mul(i, u32(arr_ty->Stride())));
+                auto* el_val = b.Call(load, "buffer", el_offset);
+                auto* for_loop =
+                    b.For(for_init, for_cond, for_cont, b.Block(b.Assign(arr_el, el_val)));
 
-      auto* ret_ty = CreateASTTypeFor(ctx, intrinsic->ReturnType());
-      auto* func = b.create<ast::Function>(
-          b.Sym(), params, ret_ty, nullptr,
-          ast::AttributeList{
-              atomic,
-              b.Disable(ast::DisabledValidation::kFunctionHasNoBody),
-          },
-          ast::AttributeList{});
+                b.Func(name, params, CreateASTTypeFor(ctx, arr_ty),
+                       {
+                           b.Decl(arr),
+                           for_loop,
+                           b.Return(arr),
+                       });
+            } else {
+                ast::ExpressionList values;
+                if (auto* mat_ty = el_ty->As<sem::Matrix>()) {
+                    auto* vec_ty = mat_ty->ColumnType();
+                    Symbol load = LoadFunc(buf_ty, vec_ty, var_user);
+                    for (uint32_t i = 0; i < mat_ty->columns(); i++) {
+                        auto* offset = b.Add("offset", u32(i * mat_ty->ColumnStride()));
+                        values.emplace_back(b.Call(load, "buffer", offset));
+                    }
+                } else if (auto* str = el_ty->As<sem::Struct>()) {
+                    for (auto* member : str->Members()) {
+                        auto* offset = b.Add("offset", u32(member->Offset()));
+                        Symbol load = LoadFunc(buf_ty, member->Type()->UnwrapRef(), var_user);
+                        values.emplace_back(b.Call(load, "buffer", offset));
+                    }
+                }
+                b.Func(name, params, CreateASTTypeFor(ctx, el_ty),
+                       {
+                           b.Return(b.Construct(CreateASTTypeFor(ctx, el_ty), values)),
+                       });
+            }
+            return name;
+        });
+    }
 
-      b.AST().AddFunction(func);
-      return func->symbol;
-    });
-  }
+    /// StoreFunc() returns a symbol to an intrinsic function that stores an
+    /// element of type `el_ty` to a storage buffer of type `buf_ty`.
+    /// The function has the signature:
+    ///   `fn store(buf : buf_ty, offset : u32, value : el_ty)`
+    /// @param buf_ty the storage buffer type
+    /// @param el_ty the storage buffer element type
+    /// @param var_user the variable user
+    /// @return the name of the function that performs the store
+    Symbol StoreFunc(const sem::Type* buf_ty,
+                     const sem::Type* el_ty,
+                     const sem::VariableUser* var_user) {
+        auto storage_class = var_user->Variable()->StorageClass();
+        return utils::GetOrCreate(store_funcs, LoadStoreKey{storage_class, buf_ty, el_ty}, [&] {
+            auto* buf_ast_ty = CreateASTTypeFor(ctx, buf_ty);
+            auto* el_ast_ty = CreateASTTypeFor(ctx, el_ty);
+            auto* disable_validation =
+                b.Disable(ast::DisabledValidation::kIgnoreConstructibleFunctionParameter);
+            ast::VariableList params{
+                // Note: The buffer parameter requires the StorageClass in
+                // order for HLSL to emit this as a ByteAddressBuffer.
+
+                b.create<ast::Variable>(b.Sym("buffer"), storage_class,
+                                        var_user->Variable()->Access(), buf_ast_ty, true, false,
+                                        nullptr, ast::AttributeList{disable_validation}),
+                b.Param("offset", b.ty.u32()),
+                b.Param("value", el_ast_ty),
+            };
+
+            auto name = b.Sym();
+
+            if (auto* intrinsic = IntrinsicStoreFor(ctx.dst, storage_class, el_ty)) {
+                auto* func = b.create<ast::Function>(
+                    name, params, b.ty.void_(), nullptr,
+                    ast::AttributeList{
+                        intrinsic,
+                        b.Disable(ast::DisabledValidation::kFunctionHasNoBody),
+                    },
+                    ast::AttributeList{});
+                b.AST().AddFunction(func);
+            } else {
+                ast::StatementList body;
+                if (auto* arr_ty = el_ty->As<sem::Array>()) {
+                    // fn store_func(buf : buf_ty, offset : u32, value : el_ty) {
+                    //   var array = value; // No dynamic indexing on constant arrays
+                    //   for (var i = 0u; i < array_count; i = i + 1) {
+                    //     arr[i] = el_store_func(buf, offset + i * array_stride,
+                    //                            value[i])
+                    //   }
+                    //   return arr;
+                    // }
+                    auto* array = b.Var(b.Symbols().New("array"), nullptr, b.Expr("value"));
+                    auto store = StoreFunc(buf_ty, arr_ty->ElemType()->UnwrapRef(), var_user);
+                    auto* i = b.Var(b.Symbols().New("i"), nullptr, b.Expr(0_u));
+                    auto* for_init = b.Decl(i);
+                    auto* for_cond = b.create<ast::BinaryExpression>(
+                        ast::BinaryOp::kLessThan, b.Expr(i), b.Expr(u32(arr_ty->Count())));
+                    auto* for_cont = b.Assign(i, b.Add(i, 1_u));
+                    auto* arr_el = b.IndexAccessor(array, i);
+                    auto* el_offset = b.Add(b.Expr("offset"), b.Mul(i, u32(arr_ty->Stride())));
+                    auto* store_stmt = b.CallStmt(b.Call(store, "buffer", el_offset, arr_el));
+                    auto* for_loop = b.For(for_init, for_cond, for_cont, b.Block(store_stmt));
+
+                    body = {b.Decl(array), for_loop};
+                } else if (auto* mat_ty = el_ty->As<sem::Matrix>()) {
+                    auto* vec_ty = mat_ty->ColumnType();
+                    Symbol store = StoreFunc(buf_ty, vec_ty, var_user);
+                    for (uint32_t i = 0; i < mat_ty->columns(); i++) {
+                        auto* offset = b.Add("offset", u32(i * mat_ty->ColumnStride()));
+                        auto* access = b.IndexAccessor("value", u32(i));
+                        auto* call = b.Call(store, "buffer", offset, access);
+                        body.emplace_back(b.CallStmt(call));
+                    }
+                } else if (auto* str = el_ty->As<sem::Struct>()) {
+                    for (auto* member : str->Members()) {
+                        auto* offset = b.Add("offset", u32(member->Offset()));
+                        auto* access =
+                            b.MemberAccessor("value", ctx.Clone(member->Declaration()->symbol));
+                        Symbol store = StoreFunc(buf_ty, member->Type()->UnwrapRef(), var_user);
+                        auto* call = b.Call(store, "buffer", offset, access);
+                        body.emplace_back(b.CallStmt(call));
+                    }
+                }
+                b.Func(name, params, b.ty.void_(), body);
+            }
+
+            return name;
+        });
+    }
+
+    /// AtomicFunc() returns a symbol to an intrinsic function that performs an
+    /// atomic operation from a storage buffer of type `buf_ty`. The function has
+    /// the signature:
+    // `fn atomic_op(buf : buf_ty, offset : u32, ...) -> T`
+    /// @param buf_ty the storage buffer type
+    /// @param el_ty the storage buffer element type
+    /// @param intrinsic the atomic intrinsic
+    /// @param var_user the variable user
+    /// @return the name of the function that performs the load
+    Symbol AtomicFunc(const sem::Type* buf_ty,
+                      const sem::Type* el_ty,
+                      const sem::Builtin* intrinsic,
+                      const sem::VariableUser* var_user) {
+        auto op = intrinsic->Type();
+        return utils::GetOrCreate(atomic_funcs, AtomicKey{buf_ty, el_ty, op}, [&] {
+            auto* buf_ast_ty = CreateASTTypeFor(ctx, buf_ty);
+            auto* disable_validation =
+                b.Disable(ast::DisabledValidation::kIgnoreConstructibleFunctionParameter);
+            // The first parameter to all WGSL atomics is the expression to the
+            // atomic. This is replaced with two parameters: the buffer and offset.
+
+            ast::VariableList params = {
+                // Note: The buffer parameter requires the kStorage StorageClass in
+                // order for HLSL to emit this as a ByteAddressBuffer.
+                b.create<ast::Variable>(b.Sym("buffer"), ast::StorageClass::kStorage,
+                                        var_user->Variable()->Access(), buf_ast_ty, true, false,
+                                        nullptr, ast::AttributeList{disable_validation}),
+                b.Param("offset", b.ty.u32()),
+            };
+
+            // Other parameters are copied as-is:
+            for (size_t i = 1; i < intrinsic->Parameters().size(); i++) {
+                auto* param = intrinsic->Parameters()[i];
+                auto* ty = CreateASTTypeFor(ctx, param->Type());
+                params.emplace_back(b.Param("param_" + std::to_string(i), ty));
+            }
+
+            auto* atomic = IntrinsicAtomicFor(ctx.dst, op, el_ty);
+            if (atomic == nullptr) {
+                TINT_ICE(Transform, b.Diagnostics())
+                    << "IntrinsicAtomicFor() returned nullptr for op " << op << " and type "
+                    << el_ty->TypeInfo().name;
+            }
+
+            auto* ret_ty = CreateASTTypeFor(ctx, intrinsic->ReturnType());
+            auto* func =
+                b.create<ast::Function>(b.Sym(), params, ret_ty, nullptr,
+                                        ast::AttributeList{
+                                            atomic,
+                                            b.Disable(ast::DisabledValidation::kFunctionHasNoBody),
+                                        },
+                                        ast::AttributeList{});
+
+            b.AST().AddFunction(func);
+            return func->symbol;
+        });
+    }
 };
 
-DecomposeMemoryAccess::Intrinsic::Intrinsic(ProgramID pid,
-                                            Op o,
-                                            ast::StorageClass sc,
-                                            DataType ty)
+DecomposeMemoryAccess::Intrinsic::Intrinsic(ProgramID pid, Op o, ast::StorageClass sc, DataType ty)
     : Base(pid), op(o), storage_class(sc), type(ty) {}
 DecomposeMemoryAccess::Intrinsic::~Intrinsic() = default;
 std::string DecomposeMemoryAccess::Intrinsic::InternalName() const {
-  std::stringstream ss;
-  switch (op) {
-    case Op::kLoad:
-      ss << "intrinsic_load_";
-      break;
-    case Op::kStore:
-      ss << "intrinsic_store_";
-      break;
-    case Op::kAtomicLoad:
-      ss << "intrinsic_atomic_load_";
-      break;
-    case Op::kAtomicStore:
-      ss << "intrinsic_atomic_store_";
-      break;
-    case Op::kAtomicAdd:
-      ss << "intrinsic_atomic_add_";
-      break;
-    case Op::kAtomicSub:
-      ss << "intrinsic_atomic_sub_";
-      break;
-    case Op::kAtomicMax:
-      ss << "intrinsic_atomic_max_";
-      break;
-    case Op::kAtomicMin:
-      ss << "intrinsic_atomic_min_";
-      break;
-    case Op::kAtomicAnd:
-      ss << "intrinsic_atomic_and_";
-      break;
-    case Op::kAtomicOr:
-      ss << "intrinsic_atomic_or_";
-      break;
-    case Op::kAtomicXor:
-      ss << "intrinsic_atomic_xor_";
-      break;
-    case Op::kAtomicExchange:
-      ss << "intrinsic_atomic_exchange_";
-      break;
-    case Op::kAtomicCompareExchangeWeak:
-      ss << "intrinsic_atomic_compare_exchange_weak_";
-      break;
-  }
-  ss << storage_class << "_";
-  switch (type) {
-    case DataType::kU32:
-      ss << "u32";
-      break;
-    case DataType::kF32:
-      ss << "f32";
-      break;
-    case DataType::kI32:
-      ss << "i32";
-      break;
-    case DataType::kVec2U32:
-      ss << "vec2_u32";
-      break;
-    case DataType::kVec2F32:
-      ss << "vec2_f32";
-      break;
-    case DataType::kVec2I32:
-      ss << "vec2_i32";
-      break;
-    case DataType::kVec3U32:
-      ss << "vec3_u32";
-      break;
-    case DataType::kVec3F32:
-      ss << "vec3_f32";
-      break;
-    case DataType::kVec3I32:
-      ss << "vec3_i32";
-      break;
-    case DataType::kVec4U32:
-      ss << "vec4_u32";
-      break;
-    case DataType::kVec4F32:
-      ss << "vec4_f32";
-      break;
-    case DataType::kVec4I32:
-      ss << "vec4_i32";
-      break;
-  }
-  return ss.str();
+    std::stringstream ss;
+    switch (op) {
+        case Op::kLoad:
+            ss << "intrinsic_load_";
+            break;
+        case Op::kStore:
+            ss << "intrinsic_store_";
+            break;
+        case Op::kAtomicLoad:
+            ss << "intrinsic_atomic_load_";
+            break;
+        case Op::kAtomicStore:
+            ss << "intrinsic_atomic_store_";
+            break;
+        case Op::kAtomicAdd:
+            ss << "intrinsic_atomic_add_";
+            break;
+        case Op::kAtomicSub:
+            ss << "intrinsic_atomic_sub_";
+            break;
+        case Op::kAtomicMax:
+            ss << "intrinsic_atomic_max_";
+            break;
+        case Op::kAtomicMin:
+            ss << "intrinsic_atomic_min_";
+            break;
+        case Op::kAtomicAnd:
+            ss << "intrinsic_atomic_and_";
+            break;
+        case Op::kAtomicOr:
+            ss << "intrinsic_atomic_or_";
+            break;
+        case Op::kAtomicXor:
+            ss << "intrinsic_atomic_xor_";
+            break;
+        case Op::kAtomicExchange:
+            ss << "intrinsic_atomic_exchange_";
+            break;
+        case Op::kAtomicCompareExchangeWeak:
+            ss << "intrinsic_atomic_compare_exchange_weak_";
+            break;
+    }
+    ss << storage_class << "_";
+    switch (type) {
+        case DataType::kU32:
+            ss << "u32";
+            break;
+        case DataType::kF32:
+            ss << "f32";
+            break;
+        case DataType::kI32:
+            ss << "i32";
+            break;
+        case DataType::kVec2U32:
+            ss << "vec2_u32";
+            break;
+        case DataType::kVec2F32:
+            ss << "vec2_f32";
+            break;
+        case DataType::kVec2I32:
+            ss << "vec2_i32";
+            break;
+        case DataType::kVec3U32:
+            ss << "vec3_u32";
+            break;
+        case DataType::kVec3F32:
+            ss << "vec3_f32";
+            break;
+        case DataType::kVec3I32:
+            ss << "vec3_i32";
+            break;
+        case DataType::kVec4U32:
+            ss << "vec4_u32";
+            break;
+        case DataType::kVec4F32:
+            ss << "vec4_f32";
+            break;
+        case DataType::kVec4I32:
+            ss << "vec4_i32";
+            break;
+    }
+    return ss.str();
 }
 
 const DecomposeMemoryAccess::Intrinsic* DecomposeMemoryAccess::Intrinsic::Clone(
     CloneContext* ctx) const {
-  return ctx->dst->ASTNodes().Create<DecomposeMemoryAccess::Intrinsic>(
-      ctx->dst->ID(), op, storage_class, type);
+    return ctx->dst->ASTNodes().Create<DecomposeMemoryAccess::Intrinsic>(ctx->dst->ID(), op,
+                                                                         storage_class, type);
 }
 
 DecomposeMemoryAccess::DecomposeMemoryAccess() = default;
 DecomposeMemoryAccess::~DecomposeMemoryAccess() = default;
 
-bool DecomposeMemoryAccess::ShouldRun(const Program* program,
-                                      const DataMap&) const {
-  for (auto* decl : program->AST().GlobalDeclarations()) {
-    if (auto* var = program->Sem().Get<sem::Variable>(decl)) {
-      if (var->StorageClass() == ast::StorageClass::kStorage ||
-          var->StorageClass() == ast::StorageClass::kUniform) {
-        return true;
-      }
+bool DecomposeMemoryAccess::ShouldRun(const Program* program, const DataMap&) const {
+    for (auto* decl : program->AST().GlobalDeclarations()) {
+        if (auto* var = program->Sem().Get<sem::Variable>(decl)) {
+            if (var->StorageClass() == ast::StorageClass::kStorage ||
+                var->StorageClass() == ast::StorageClass::kUniform) {
+                return true;
+            }
+        }
     }
-  }
-  return false;
+    return false;
 }
 
-void DecomposeMemoryAccess::Run(CloneContext& ctx,
-                                const DataMap&,
-                                DataMap&) const {
-  auto& sem = ctx.src->Sem();
+void DecomposeMemoryAccess::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
+    auto& sem = ctx.src->Sem();
 
-  State state(ctx);
+    State state(ctx);
 
-  // Scan the AST nodes for storage and uniform buffer accesses. Complex
-  // expression chains (e.g. `storage_buffer.foo.bar[20].x`) are handled by
-  // maintaining an offset chain via the `state.TakeAccess()`,
-  // `state.AddAccess()` methods.
-  //
-  // Inner-most expression nodes are guaranteed to be visited first because AST
-  // nodes are fully immutable and require their children to be constructed
-  // first so their pointer can be passed to the parent's constructor.
-  for (auto* node : ctx.src->ASTNodes().Objects()) {
-    if (auto* ident = node->As<ast::IdentifierExpression>()) {
-      // X
-      if (auto* var = sem.Get<sem::VariableUser>(ident)) {
-        if (var->Variable()->StorageClass() == ast::StorageClass::kStorage ||
-            var->Variable()->StorageClass() == ast::StorageClass::kUniform) {
-          // Variable to a storage or uniform buffer
-          state.AddAccess(ident, {
-                                     var,
-                                     state.ToOffset(0u),
-                                     var->Type()->UnwrapRef(),
-                                 });
+    // Scan the AST nodes for storage and uniform buffer accesses. Complex
+    // expression chains (e.g. `storage_buffer.foo.bar[20].x`) are handled by
+    // maintaining an offset chain via the `state.TakeAccess()`,
+    // `state.AddAccess()` methods.
+    //
+    // Inner-most expression nodes are guaranteed to be visited first because AST
+    // nodes are fully immutable and require their children to be constructed
+    // first so their pointer can be passed to the parent's constructor.
+    for (auto* node : ctx.src->ASTNodes().Objects()) {
+        if (auto* ident = node->As<ast::IdentifierExpression>()) {
+            // X
+            if (auto* var = sem.Get<sem::VariableUser>(ident)) {
+                if (var->Variable()->StorageClass() == ast::StorageClass::kStorage ||
+                    var->Variable()->StorageClass() == ast::StorageClass::kUniform) {
+                    // Variable to a storage or uniform buffer
+                    state.AddAccess(ident, {
+                                               var,
+                                               state.ToOffset(0u),
+                                               var->Type()->UnwrapRef(),
+                                           });
+                }
+            }
+            continue;
         }
-      }
-      continue;
+
+        if (auto* accessor = node->As<ast::MemberAccessorExpression>()) {
+            // X.Y
+            auto* accessor_sem = sem.Get(accessor);
+            if (auto* swizzle = accessor_sem->As<sem::Swizzle>()) {
+                if (swizzle->Indices().size() == 1) {
+                    if (auto access = state.TakeAccess(accessor->structure)) {
+                        auto* vec_ty = access.type->As<sem::Vector>();
+                        auto* offset = state.Mul(vec_ty->type()->Size(), swizzle->Indices()[0]);
+                        state.AddAccess(accessor, {
+                                                      access.var,
+                                                      state.Add(access.offset, offset),
+                                                      vec_ty->type()->UnwrapRef(),
+                                                  });
+                    }
+                }
+            } else {
+                if (auto access = state.TakeAccess(accessor->structure)) {
+                    auto* str_ty = access.type->As<sem::Struct>();
+                    auto* member = str_ty->FindMember(accessor->member->symbol);
+                    auto offset = member->Offset();
+                    state.AddAccess(accessor, {
+                                                  access.var,
+                                                  state.Add(access.offset, offset),
+                                                  member->Type()->UnwrapRef(),
+                                              });
+                }
+            }
+            continue;
+        }
+
+        if (auto* accessor = node->As<ast::IndexAccessorExpression>()) {
+            if (auto access = state.TakeAccess(accessor->object)) {
+                // X[Y]
+                if (auto* arr = access.type->As<sem::Array>()) {
+                    auto* offset = state.Mul(arr->Stride(), accessor->index);
+                    state.AddAccess(accessor, {
+                                                  access.var,
+                                                  state.Add(access.offset, offset),
+                                                  arr->ElemType()->UnwrapRef(),
+                                              });
+                    continue;
+                }
+                if (auto* vec_ty = access.type->As<sem::Vector>()) {
+                    auto* offset = state.Mul(vec_ty->type()->Size(), accessor->index);
+                    state.AddAccess(accessor, {
+                                                  access.var,
+                                                  state.Add(access.offset, offset),
+                                                  vec_ty->type()->UnwrapRef(),
+                                              });
+                    continue;
+                }
+                if (auto* mat_ty = access.type->As<sem::Matrix>()) {
+                    auto* offset = state.Mul(mat_ty->ColumnStride(), accessor->index);
+                    state.AddAccess(accessor, {
+                                                  access.var,
+                                                  state.Add(access.offset, offset),
+                                                  mat_ty->ColumnType(),
+                                              });
+                    continue;
+                }
+            }
+        }
+
+        if (auto* op = node->As<ast::UnaryOpExpression>()) {
+            if (op->op == ast::UnaryOp::kAddressOf) {
+                // &X
+                if (auto access = state.TakeAccess(op->expr)) {
+                    // HLSL does not support pointers, so just take the access from the
+                    // reference and place it on the pointer.
+                    state.AddAccess(op, access);
+                    continue;
+                }
+            }
+        }
+
+        if (auto* assign = node->As<ast::AssignmentStatement>()) {
+            // X = Y
+            // Move the LHS access to a store.
+            if (auto lhs = state.TakeAccess(assign->lhs)) {
+                state.stores.emplace_back(Store{assign, lhs});
+            }
+        }
+
+        if (auto* call_expr = node->As<ast::CallExpression>()) {
+            auto* call = sem.Get(call_expr);
+            if (auto* builtin = call->Target()->As<sem::Builtin>()) {
+                if (builtin->Type() == sem::BuiltinType::kArrayLength) {
+                    // arrayLength(X)
+                    // Don't convert X into a load, this builtin actually requires the
+                    // real pointer.
+                    state.TakeAccess(call_expr->args[0]);
+                    continue;
+                }
+                if (builtin->IsAtomic()) {
+                    if (auto access = state.TakeAccess(call_expr->args[0])) {
+                        // atomic___(X)
+                        ctx.Replace(call_expr, [=, &ctx, &state] {
+                            auto* buf = access.var->Declaration();
+                            auto* offset = access.offset->Build(ctx);
+                            auto* buf_ty = access.var->Type()->UnwrapRef();
+                            auto* el_ty = access.type->UnwrapRef()->As<sem::Atomic>()->Type();
+                            Symbol func = state.AtomicFunc(buf_ty, el_ty, builtin,
+                                                           access.var->As<sem::VariableUser>());
+
+                            ast::ExpressionList args{ctx.Clone(buf), offset};
+                            for (size_t i = 1; i < call_expr->args.size(); i++) {
+                                auto* arg = call_expr->args[i];
+                                args.emplace_back(ctx.Clone(arg));
+                            }
+                            return ctx.dst->Call(func, args);
+                        });
+                    }
+                }
+            }
+        }
     }
 
-    if (auto* accessor = node->As<ast::MemberAccessorExpression>()) {
-      // X.Y
-      auto* accessor_sem = sem.Get(accessor);
-      if (auto* swizzle = accessor_sem->As<sem::Swizzle>()) {
-        if (swizzle->Indices().size() == 1) {
-          if (auto access = state.TakeAccess(accessor->structure)) {
-            auto* vec_ty = access.type->As<sem::Vector>();
-            auto* offset =
-                state.Mul(vec_ty->type()->Size(), swizzle->Indices()[0]);
-            state.AddAccess(accessor, {
-                                          access.var,
-                                          state.Add(access.offset, offset),
-                                          vec_ty->type()->UnwrapRef(),
-                                      });
-          }
+    // All remaining accesses are loads, transform these into calls to the
+    // corresponding load function
+    for (auto* expr : state.expression_order) {
+        auto access_it = state.accesses.find(expr);
+        if (access_it == state.accesses.end()) {
+            continue;
         }
-      } else {
-        if (auto access = state.TakeAccess(accessor->structure)) {
-          auto* str_ty = access.type->As<sem::Struct>();
-          auto* member = str_ty->FindMember(accessor->member->symbol);
-          auto offset = member->Offset();
-          state.AddAccess(accessor, {
-                                        access.var,
-                                        state.Add(access.offset, offset),
-                                        member->Type()->UnwrapRef(),
-                                    });
-        }
-      }
-      continue;
+        BufferAccess access = access_it->second;
+        ctx.Replace(expr, [=, &ctx, &state] {
+            auto* buf = access.var->Declaration();
+            auto* offset = access.offset->Build(ctx);
+            auto* buf_ty = access.var->Type()->UnwrapRef();
+            auto* el_ty = access.type->UnwrapRef();
+            Symbol func = state.LoadFunc(buf_ty, el_ty, access.var->As<sem::VariableUser>());
+            return ctx.dst->Call(func, ctx.CloneWithoutTransform(buf), offset);
+        });
     }
 
-    if (auto* accessor = node->As<ast::IndexAccessorExpression>()) {
-      if (auto access = state.TakeAccess(accessor->object)) {
-        // X[Y]
-        if (auto* arr = access.type->As<sem::Array>()) {
-          auto* offset = state.Mul(arr->Stride(), accessor->index);
-          state.AddAccess(accessor, {
-                                        access.var,
-                                        state.Add(access.offset, offset),
-                                        arr->ElemType()->UnwrapRef(),
-                                    });
-          continue;
-        }
-        if (auto* vec_ty = access.type->As<sem::Vector>()) {
-          auto* offset = state.Mul(vec_ty->type()->Size(), accessor->index);
-          state.AddAccess(accessor, {
-                                        access.var,
-                                        state.Add(access.offset, offset),
-                                        vec_ty->type()->UnwrapRef(),
-                                    });
-          continue;
-        }
-        if (auto* mat_ty = access.type->As<sem::Matrix>()) {
-          auto* offset = state.Mul(mat_ty->ColumnStride(), accessor->index);
-          state.AddAccess(accessor, {
-                                        access.var,
-                                        state.Add(access.offset, offset),
-                                        mat_ty->ColumnType(),
-                                    });
-          continue;
-        }
-      }
+    // And replace all storage and uniform buffer assignments with stores
+    for (auto store : state.stores) {
+        ctx.Replace(store.assignment, [=, &ctx, &state] {
+            auto* buf = store.target.var->Declaration();
+            auto* offset = store.target.offset->Build(ctx);
+            auto* buf_ty = store.target.var->Type()->UnwrapRef();
+            auto* el_ty = store.target.type->UnwrapRef();
+            auto* value = store.assignment->rhs;
+            Symbol func = state.StoreFunc(buf_ty, el_ty, store.target.var->As<sem::VariableUser>());
+            auto* call =
+                ctx.dst->Call(func, ctx.CloneWithoutTransform(buf), offset, ctx.Clone(value));
+            return ctx.dst->CallStmt(call);
+        });
     }
 
-    if (auto* op = node->As<ast::UnaryOpExpression>()) {
-      if (op->op == ast::UnaryOp::kAddressOf) {
-        // &X
-        if (auto access = state.TakeAccess(op->expr)) {
-          // HLSL does not support pointers, so just take the access from the
-          // reference and place it on the pointer.
-          state.AddAccess(op, access);
-          continue;
-        }
-      }
-    }
-
-    if (auto* assign = node->As<ast::AssignmentStatement>()) {
-      // X = Y
-      // Move the LHS access to a store.
-      if (auto lhs = state.TakeAccess(assign->lhs)) {
-        state.stores.emplace_back(Store{assign, lhs});
-      }
-    }
-
-    if (auto* call_expr = node->As<ast::CallExpression>()) {
-      auto* call = sem.Get(call_expr);
-      if (auto* builtin = call->Target()->As<sem::Builtin>()) {
-        if (builtin->Type() == sem::BuiltinType::kArrayLength) {
-          // arrayLength(X)
-          // Don't convert X into a load, this builtin actually requires the
-          // real pointer.
-          state.TakeAccess(call_expr->args[0]);
-          continue;
-        }
-        if (builtin->IsAtomic()) {
-          if (auto access = state.TakeAccess(call_expr->args[0])) {
-            // atomic___(X)
-            ctx.Replace(call_expr, [=, &ctx, &state] {
-              auto* buf = access.var->Declaration();
-              auto* offset = access.offset->Build(ctx);
-              auto* buf_ty = access.var->Type()->UnwrapRef();
-              auto* el_ty = access.type->UnwrapRef()->As<sem::Atomic>()->Type();
-              Symbol func = state.AtomicFunc(
-                  buf_ty, el_ty, builtin, access.var->As<sem::VariableUser>());
-
-              ast::ExpressionList args{ctx.Clone(buf), offset};
-              for (size_t i = 1; i < call_expr->args.size(); i++) {
-                auto* arg = call_expr->args[i];
-                args.emplace_back(ctx.Clone(arg));
-              }
-              return ctx.dst->Call(func, args);
-            });
-          }
-        }
-      }
-    }
-  }
-
-  // All remaining accesses are loads, transform these into calls to the
-  // corresponding load function
-  for (auto* expr : state.expression_order) {
-    auto access_it = state.accesses.find(expr);
-    if (access_it == state.accesses.end()) {
-      continue;
-    }
-    BufferAccess access = access_it->second;
-    ctx.Replace(expr, [=, &ctx, &state] {
-      auto* buf = access.var->Declaration();
-      auto* offset = access.offset->Build(ctx);
-      auto* buf_ty = access.var->Type()->UnwrapRef();
-      auto* el_ty = access.type->UnwrapRef();
-      Symbol func =
-          state.LoadFunc(buf_ty, el_ty, access.var->As<sem::VariableUser>());
-      return ctx.dst->Call(func, ctx.CloneWithoutTransform(buf), offset);
-    });
-  }
-
-  // And replace all storage and uniform buffer assignments with stores
-  for (auto store : state.stores) {
-    ctx.Replace(store.assignment, [=, &ctx, &state] {
-      auto* buf = store.target.var->Declaration();
-      auto* offset = store.target.offset->Build(ctx);
-      auto* buf_ty = store.target.var->Type()->UnwrapRef();
-      auto* el_ty = store.target.type->UnwrapRef();
-      auto* value = store.assignment->rhs;
-      Symbol func = state.StoreFunc(buf_ty, el_ty,
-                                    store.target.var->As<sem::VariableUser>());
-      auto* call = ctx.dst->Call(func, ctx.CloneWithoutTransform(buf), offset,
-                                 ctx.Clone(value));
-      return ctx.dst->CallStmt(call);
-    });
-  }
-
-  ctx.Clone();
+    ctx.Clone();
 }
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/decompose_memory_access.h b/src/tint/transform/decompose_memory_access.h
index 9aa0eb5..7a7b783 100644
--- a/src/tint/transform/decompose_memory_access.h
+++ b/src/tint/transform/decompose_memory_access.h
@@ -30,99 +30,95 @@
 /// DecomposeMemoryAccess is a transform used to replace storage and uniform
 /// buffer accesses with a combination of load, store or atomic functions on
 /// primitive types.
-class DecomposeMemoryAccess final
-    : public Castable<DecomposeMemoryAccess, Transform> {
- public:
-  /// Intrinsic is an InternalAttribute that's used to decorate a stub function
-  /// so that the HLSL transforms this into calls to
-  /// `[RW]ByteAddressBuffer.Load[N]()` or `[RW]ByteAddressBuffer.Store[N]()`,
-  /// with a possible cast.
-  class Intrinsic final : public Castable<Intrinsic, ast::InternalAttribute> {
-   public:
-    /// Intrinsic op
-    enum class Op {
-      kLoad,
-      kStore,
-      kAtomicLoad,
-      kAtomicStore,
-      kAtomicAdd,
-      kAtomicSub,
-      kAtomicMax,
-      kAtomicMin,
-      kAtomicAnd,
-      kAtomicOr,
-      kAtomicXor,
-      kAtomicExchange,
-      kAtomicCompareExchangeWeak,
-    };
+class DecomposeMemoryAccess final : public Castable<DecomposeMemoryAccess, Transform> {
+  public:
+    /// Intrinsic is an InternalAttribute that's used to decorate a stub function
+    /// so that the HLSL transforms this into calls to
+    /// `[RW]ByteAddressBuffer.Load[N]()` or `[RW]ByteAddressBuffer.Store[N]()`,
+    /// with a possible cast.
+    class Intrinsic final : public Castable<Intrinsic, ast::InternalAttribute> {
+      public:
+        /// Intrinsic op
+        enum class Op {
+            kLoad,
+            kStore,
+            kAtomicLoad,
+            kAtomicStore,
+            kAtomicAdd,
+            kAtomicSub,
+            kAtomicMax,
+            kAtomicMin,
+            kAtomicAnd,
+            kAtomicOr,
+            kAtomicXor,
+            kAtomicExchange,
+            kAtomicCompareExchangeWeak,
+        };
 
-    /// Intrinsic data type
-    enum class DataType {
-      kU32,
-      kF32,
-      kI32,
-      kVec2U32,
-      kVec2F32,
-      kVec2I32,
-      kVec3U32,
-      kVec3F32,
-      kVec3I32,
-      kVec4U32,
-      kVec4F32,
-      kVec4I32,
+        /// Intrinsic data type
+        enum class DataType {
+            kU32,
+            kF32,
+            kI32,
+            kVec2U32,
+            kVec2F32,
+            kVec2I32,
+            kVec3U32,
+            kVec3F32,
+            kVec3I32,
+            kVec4U32,
+            kVec4F32,
+            kVec4I32,
+        };
+
+        /// Constructor
+        /// @param program_id the identifier of the program that owns this node
+        /// @param o the op of the intrinsic
+        /// @param sc the storage class of the buffer
+        /// @param ty the data type of the intrinsic
+        Intrinsic(ProgramID program_id, Op o, ast::StorageClass sc, DataType ty);
+        /// Destructor
+        ~Intrinsic() override;
+
+        /// @return a short description of the internal attribute which will be
+        /// displayed as `@internal(<name>)`
+        std::string InternalName() const override;
+
+        /// Performs a deep clone of this object using the CloneContext `ctx`.
+        /// @param ctx the clone context
+        /// @return the newly cloned object
+        const Intrinsic* Clone(CloneContext* ctx) const override;
+
+        /// The op of the intrinsic
+        const Op op;
+
+        /// The storage class of the buffer this intrinsic operates on
+        ast::StorageClass const storage_class;
+
+        /// The type of the intrinsic
+        const DataType type;
     };
 
     /// Constructor
-    /// @param program_id the identifier of the program that owns this node
-    /// @param o the op of the intrinsic
-    /// @param sc the storage class of the buffer
-    /// @param ty the data type of the intrinsic
-    Intrinsic(ProgramID program_id, Op o, ast::StorageClass sc, DataType ty);
+    DecomposeMemoryAccess();
     /// Destructor
-    ~Intrinsic() override;
+    ~DecomposeMemoryAccess() override;
 
-    /// @return a short description of the internal attribute which will be
-    /// displayed as `@internal(<name>)`
-    std::string InternalName() const override;
+    /// @param program the program to inspect
+    /// @param data optional extra transform-specific input data
+    /// @returns true if this transform should be run for the given program
+    bool ShouldRun(const Program* program, const DataMap& data = {}) const override;
 
-    /// Performs a deep clone of this object using the CloneContext `ctx`.
-    /// @param ctx the clone context
-    /// @return the newly cloned object
-    const Intrinsic* Clone(CloneContext* ctx) const override;
+  protected:
+    /// Runs the transform using the CloneContext built for transforming a
+    /// program. Run() is responsible for calling Clone() on the CloneContext.
+    /// @param ctx the CloneContext primed with the input program and
+    /// ProgramBuilder
+    /// @param inputs optional extra transform-specific input data
+    /// @param outputs optional extra transform-specific output data
+    void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const override;
 
-    /// The op of the intrinsic
-    const Op op;
-
-    /// The storage class of the buffer this intrinsic operates on
-    ast::StorageClass const storage_class;
-
-    /// The type of the intrinsic
-    const DataType type;
-  };
-
-  /// Constructor
-  DecomposeMemoryAccess();
-  /// Destructor
-  ~DecomposeMemoryAccess() override;
-
-  /// @param program the program to inspect
-  /// @param data optional extra transform-specific input data
-  /// @returns true if this transform should be run for the given program
-  bool ShouldRun(const Program* program,
-                 const DataMap& data = {}) const override;
-
- protected:
-  /// Runs the transform using the CloneContext built for transforming a
-  /// program. Run() is responsible for calling Clone() on the CloneContext.
-  /// @param ctx the CloneContext primed with the input program and
-  /// ProgramBuilder
-  /// @param inputs optional extra transform-specific input data
-  /// @param outputs optional extra transform-specific output data
-  void Run(CloneContext& ctx,
-           const DataMap& inputs,
-           DataMap& outputs) const override;
-
-  struct State;
+    struct State;
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/decompose_memory_access_test.cc b/src/tint/transform/decompose_memory_access_test.cc
index dadb422..22b5da4 100644
--- a/src/tint/transform/decompose_memory_access_test.cc
+++ b/src/tint/transform/decompose_memory_access_test.cc
@@ -22,35 +22,35 @@
 using DecomposeMemoryAccessTest = TransformTest;
 
 TEST_F(DecomposeMemoryAccessTest, ShouldRunEmptyModule) {
-  auto* src = R"()";
+    auto* src = R"()";
 
-  EXPECT_FALSE(ShouldRun<DecomposeMemoryAccess>(src));
+    EXPECT_FALSE(ShouldRun<DecomposeMemoryAccess>(src));
 }
 
 TEST_F(DecomposeMemoryAccessTest, ShouldRunStorageBuffer) {
-  auto* src = R"(
+    auto* src = R"(
 struct Buffer {
   i : i32,
 };
 @group(0) @binding(0) var<storage, read_write> sb : Buffer;
 )";
 
-  EXPECT_TRUE(ShouldRun<DecomposeMemoryAccess>(src));
+    EXPECT_TRUE(ShouldRun<DecomposeMemoryAccess>(src));
 }
 
 TEST_F(DecomposeMemoryAccessTest, ShouldRunUniformBuffer) {
-  auto* src = R"(
+    auto* src = R"(
 struct Buffer {
   i : i32,
 };
 @group(0) @binding(0) var<uniform> ub : Buffer;
 )";
 
-  EXPECT_TRUE(ShouldRun<DecomposeMemoryAccess>(src));
+    EXPECT_TRUE(ShouldRun<DecomposeMemoryAccess>(src));
 }
 
 TEST_F(DecomposeMemoryAccessTest, SB_BasicLoad) {
-  auto* src = R"(
+    auto* src = R"(
 struct SB {
   a : i32,
   b : u32,
@@ -105,7 +105,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct SB {
   a : i32,
   b : u32,
@@ -240,13 +240,13 @@
 }
 )";
 
-  auto got = Run<DecomposeMemoryAccess>(src);
+    auto got = Run<DecomposeMemoryAccess>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(DecomposeMemoryAccessTest, SB_BasicLoad_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   var a : i32 = sb.a;
@@ -301,7 +301,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @internal(intrinsic_load_storage_i32) @internal(disable_validation__function_has_no_body)
 fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> i32
 
@@ -436,13 +436,13 @@
 }
 )";
 
-  auto got = Run<DecomposeMemoryAccess>(src);
+    auto got = Run<DecomposeMemoryAccess>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(DecomposeMemoryAccessTest, UB_BasicLoad) {
-  auto* src = R"(
+    auto* src = R"(
 struct UB {
   a : i32,
   b : u32,
@@ -497,7 +497,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct UB {
   a : i32,
   b : u32,
@@ -632,13 +632,13 @@
 }
 )";
 
-  auto got = Run<DecomposeMemoryAccess>(src);
+    auto got = Run<DecomposeMemoryAccess>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(DecomposeMemoryAccessTest, UB_BasicLoad_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   var a : i32 = ub.a;
@@ -693,7 +693,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @internal(intrinsic_load_uniform_i32) @internal(disable_validation__function_has_no_body)
 fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : UB, offset : u32) -> i32
 
@@ -828,13 +828,13 @@
 }
 )";
 
-  auto got = Run<DecomposeMemoryAccess>(src);
+    auto got = Run<DecomposeMemoryAccess>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(DecomposeMemoryAccessTest, SB_BasicStore) {
-  auto* src = R"(
+    auto* src = R"(
 struct SB {
   a : i32,
   b : u32,
@@ -889,7 +889,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct SB {
   a : i32,
   b : u32,
@@ -1041,13 +1041,13 @@
 }
 )";
 
-  auto got = Run<DecomposeMemoryAccess>(src);
+    auto got = Run<DecomposeMemoryAccess>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(DecomposeMemoryAccessTest, SB_BasicStore_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   sb.a = i32();
@@ -1102,7 +1102,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @internal(intrinsic_store_storage_i32) @internal(disable_validation__function_has_no_body)
 fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : i32)
 
@@ -1254,13 +1254,13 @@
 }
 )";
 
-  auto got = Run<DecomposeMemoryAccess>(src);
+    auto got = Run<DecomposeMemoryAccess>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(DecomposeMemoryAccessTest, LoadStructure) {
-  auto* src = R"(
+    auto* src = R"(
 struct SB {
   a : i32,
   b : u32,
@@ -1294,7 +1294,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct SB {
   a : i32,
   b : u32,
@@ -1412,13 +1412,13 @@
 }
 )";
 
-  auto got = Run<DecomposeMemoryAccess>(src);
+    auto got = Run<DecomposeMemoryAccess>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(DecomposeMemoryAccessTest, LoadStructure_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   var x : SB = sb;
@@ -1452,7 +1452,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @internal(intrinsic_load_storage_i32) @internal(disable_validation__function_has_no_body)
 fn tint_symbol_1(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> i32
 
@@ -1570,13 +1570,13 @@
 }
 )";
 
-  auto got = Run<DecomposeMemoryAccess>(src);
+    auto got = Run<DecomposeMemoryAccess>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(DecomposeMemoryAccessTest, StoreStructure) {
-  auto* src = R"(
+    auto* src = R"(
 struct SB {
   a : i32,
   b : u32,
@@ -1610,7 +1610,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct SB {
   a : i32,
   b : u32,
@@ -1766,13 +1766,13 @@
 }
 )";
 
-  auto got = Run<DecomposeMemoryAccess>(src);
+    auto got = Run<DecomposeMemoryAccess>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(DecomposeMemoryAccessTest, StoreStructure_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   sb = SB();
@@ -1806,7 +1806,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @internal(intrinsic_store_storage_i32) @internal(disable_validation__function_has_no_body)
 fn tint_symbol_1(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, value : i32)
 
@@ -1962,13 +1962,13 @@
 }
 )";
 
-  auto got = Run<DecomposeMemoryAccess>(src);
+    auto got = Run<DecomposeMemoryAccess>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(DecomposeMemoryAccessTest, ComplexStaticAccessChain) {
-  auto* src = R"(
+    auto* src = R"(
 // sizeof(S1) == 32
 // alignof(S1) == 16
 struct S1 {
@@ -1999,14 +1999,14 @@
 }
 )";
 
-  // sb.b[4].b[1].b.z
-  //    ^  ^ ^  ^ ^ ^
-  //    |  | |  | | |
-  //  128  | |688 | 712
-  //       | |    |
-  //     640 656  704
+    // sb.b[4].b[1].b.z
+    //    ^  ^ ^  ^ ^ ^
+    //    |  | |  | | |
+    //  128  | |688 | 712
+    //       | |    |
+    //     640 656  704
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S1 {
   a : i32,
   b : vec3<f32>,
@@ -2036,13 +2036,13 @@
 }
 )";
 
-  auto got = Run<DecomposeMemoryAccess>(src);
+    auto got = Run<DecomposeMemoryAccess>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(DecomposeMemoryAccessTest, ComplexStaticAccessChain_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   var x : f32 = sb.b[4].b[1].b.z;
@@ -2069,14 +2069,14 @@
 };
 )";
 
-  // sb.b[4].b[1].b.z
-  //    ^  ^ ^  ^ ^ ^
-  //    |  | |  | | |
-  //  128  | |688 | 712
-  //       | |    |
-  //     640 656  704
+    // sb.b[4].b[1].b.z
+    //    ^  ^ ^  ^ ^ ^
+    //    |  | |  | | |
+    //  128  | |688 | 712
+    //       | |    |
+    //     640 656  704
 
-  auto* expect = R"(
+    auto* expect = R"(
 @internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
 fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> f32
 
@@ -2106,13 +2106,13 @@
 }
 )";
 
-  auto got = Run<DecomposeMemoryAccess>(src);
+    auto got = Run<DecomposeMemoryAccess>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(DecomposeMemoryAccessTest, ComplexDynamicAccessChain) {
-  auto* src = R"(
+    auto* src = R"(
 struct S1 {
   a : i32,
   b : vec3<f32>,
@@ -2142,7 +2142,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S1 {
   a : i32,
   b : vec3<f32>,
@@ -2175,13 +2175,13 @@
 }
 )";
 
-  auto got = Run<DecomposeMemoryAccess>(src);
+    auto got = Run<DecomposeMemoryAccess>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(DecomposeMemoryAccessTest, ComplexDynamicAccessChain_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   var i : i32 = 4;
@@ -2211,7 +2211,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
 fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> f32
 
@@ -2244,13 +2244,13 @@
 }
 )";
 
-  auto got = Run<DecomposeMemoryAccess>(src);
+    auto got = Run<DecomposeMemoryAccess>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(DecomposeMemoryAccessTest, ComplexDynamicAccessChainWithAliases) {
-  auto* src = R"(
+    auto* src = R"(
 struct S1 {
   a : i32,
   b : vec3<f32>,
@@ -2288,7 +2288,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S1 {
   a : i32,
   b : vec3<f32>,
@@ -2329,14 +2329,13 @@
 }
 )";
 
-  auto got = Run<DecomposeMemoryAccess>(src);
+    auto got = Run<DecomposeMemoryAccess>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(DecomposeMemoryAccessTest,
-       ComplexDynamicAccessChainWithAliases_OutOfOrder) {
-  auto* src = R"(
+TEST_F(DecomposeMemoryAccessTest, ComplexDynamicAccessChainWithAliases_OutOfOrder) {
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   var i : i32 = 4;
@@ -2374,7 +2373,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @internal(intrinsic_load_storage_f32) @internal(disable_validation__function_has_no_body)
 fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32) -> f32
 
@@ -2415,13 +2414,13 @@
 }
 )";
 
-  auto got = Run<DecomposeMemoryAccess>(src);
+    auto got = Run<DecomposeMemoryAccess>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(DecomposeMemoryAccessTest, StorageBufferAtomics) {
-  auto* src = R"(
+    auto* src = R"(
 struct SB {
   padding : vec4<f32>,
   a : atomic<i32>,
@@ -2458,7 +2457,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct SB {
   padding : vec4<f32>,
   a : atomic<i32>,
@@ -2560,13 +2559,13 @@
 }
 )";
 
-  auto got = Run<DecomposeMemoryAccess>(src);
+    auto got = Run<DecomposeMemoryAccess>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(DecomposeMemoryAccessTest, StorageBufferAtomics_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   atomicStore(&sb.a, 123);
@@ -2603,7 +2602,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @internal(intrinsic_atomic_store_storage_i32) @internal(disable_validation__function_has_no_body)
 fn tint_symbol(@internal(disable_validation__ignore_constructible_function_parameter) buffer : SB, offset : u32, param_1 : i32)
 
@@ -2705,13 +2704,13 @@
 }
 )";
 
-  auto got = Run<DecomposeMemoryAccess>(src);
+    auto got = Run<DecomposeMemoryAccess>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(DecomposeMemoryAccessTest, WorkgroupBufferAtomics) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   padding : vec4<f32>,
   a : atomic<i32>,
@@ -2747,15 +2746,15 @@
 }
 )";
 
-  auto* expect = src;
+    auto* expect = src;
 
-  auto got = Run<DecomposeMemoryAccess>(src);
+    auto got = Run<DecomposeMemoryAccess>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(DecomposeMemoryAccessTest, WorkgroupBufferAtomics_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   atomicStore(&(w.a), 123);
@@ -2791,11 +2790,11 @@
 }
 )";
 
-  auto* expect = src;
+    auto* expect = src;
 
-  auto got = Run<DecomposeMemoryAccess>(src);
+    auto got = Run<DecomposeMemoryAccess>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 }  // namespace
diff --git a/src/tint/transform/decompose_strided_array.cc b/src/tint/transform/decompose_strided_array.cc
index 74b6903..bf36c06 100644
--- a/src/tint/transform/decompose_strided_array.cc
+++ b/src/tint/transform/decompose_strided_array.cc
@@ -40,121 +40,115 @@
 
 DecomposeStridedArray::~DecomposeStridedArray() = default;
 
-bool DecomposeStridedArray::ShouldRun(const Program* program,
-                                      const DataMap&) const {
-  for (auto* node : program->ASTNodes().Objects()) {
-    if (auto* ast = node->As<ast::Array>()) {
-      if (ast::GetAttribute<ast::StrideAttribute>(ast->attributes)) {
-        return true;
-      }
+bool DecomposeStridedArray::ShouldRun(const Program* program, const DataMap&) const {
+    for (auto* node : program->ASTNodes().Objects()) {
+        if (auto* ast = node->As<ast::Array>()) {
+            if (ast::GetAttribute<ast::StrideAttribute>(ast->attributes)) {
+                return true;
+            }
+        }
     }
-  }
-  return false;
+    return false;
 }
 
-void DecomposeStridedArray::Run(CloneContext& ctx,
-                                const DataMap&,
-                                DataMap&) const {
-  const auto& sem = ctx.src->Sem();
+void DecomposeStridedArray::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
+    const auto& sem = ctx.src->Sem();
 
-  static constexpr const char* kMemberName = "el";
+    static constexpr const char* kMemberName = "el";
 
-  // Maps an array type in the source program to the name of the struct wrapper
-  // type in the target program.
-  std::unordered_map<const sem::Array*, Symbol> decomposed;
+    // Maps an array type in the source program to the name of the struct wrapper
+    // type in the target program.
+    std::unordered_map<const sem::Array*, Symbol> decomposed;
 
-  // Find and replace all arrays with a @stride attribute with a array that has
-  // the @stride removed. If the source array stride does not match the natural
-  // stride for the array element type, then replace the array element type with
-  // a structure, holding a single field with a @size attribute equal to the
-  // array stride.
-  ctx.ReplaceAll([&](const ast::Array* ast) -> const ast::Array* {
-    if (auto* arr = sem.Get(ast)) {
-      if (!arr->IsStrideImplicit()) {
-        auto el_ty = utils::GetOrCreate(decomposed, arr, [&] {
-          auto name = ctx.dst->Symbols().New("strided_arr");
-          auto* member_ty = ctx.Clone(ast->type);
-          auto* member = ctx.dst->Member(kMemberName, member_ty,
-                                         {ctx.dst->MemberSize(arr->Stride())});
-          ctx.dst->Structure(name, {member});
-          return name;
-        });
-        auto* count = ctx.Clone(ast->count);
-        return ctx.dst->ty.array(ctx.dst->ty.type_name(el_ty), count);
-      }
-      if (ast::GetAttribute<ast::StrideAttribute>(ast->attributes)) {
-        // Strip the @stride attribute
-        auto* ty = ctx.Clone(ast->type);
-        auto* count = ctx.Clone(ast->count);
-        return ctx.dst->ty.array(ty, count);
-      }
-    }
-    return nullptr;
-  });
-
-  // Find all array index-accessors expressions for arrays that have had their
-  // element changed to a single field structure. These expressions are adjusted
-  // to insert an additional member accessor for the single structure field.
-  // Example: `arr[i]` -> `arr[i].el`
-  ctx.ReplaceAll(
-      [&](const ast::IndexAccessorExpression* idx) -> const ast::Expression* {
-        if (auto* ty = ctx.src->TypeOf(idx->object)) {
-          if (auto* arr = ty->UnwrapRef()->As<sem::Array>()) {
+    // Find and replace all arrays with a @stride attribute with a array that has
+    // the @stride removed. If the source array stride does not match the natural
+    // stride for the array element type, then replace the array element type with
+    // a structure, holding a single field with a @size attribute equal to the
+    // array stride.
+    ctx.ReplaceAll([&](const ast::Array* ast) -> const ast::Array* {
+        if (auto* arr = sem.Get(ast)) {
             if (!arr->IsStrideImplicit()) {
-              auto* expr = ctx.CloneWithoutTransform(idx);
-              return ctx.dst->MemberAccessor(expr, kMemberName);
+                auto el_ty = utils::GetOrCreate(decomposed, arr, [&] {
+                    auto name = ctx.dst->Symbols().New("strided_arr");
+                    auto* member_ty = ctx.Clone(ast->type);
+                    auto* member = ctx.dst->Member(kMemberName, member_ty,
+                                                   {ctx.dst->MemberSize(arr->Stride())});
+                    ctx.dst->Structure(name, {member});
+                    return name;
+                });
+                auto* count = ctx.Clone(ast->count);
+                return ctx.dst->ty.array(ctx.dst->ty.type_name(el_ty), count);
             }
-          }
+            if (ast::GetAttribute<ast::StrideAttribute>(ast->attributes)) {
+                // Strip the @stride attribute
+                auto* ty = ctx.Clone(ast->type);
+                auto* count = ctx.Clone(ast->count);
+                return ctx.dst->ty.array(ty, count);
+            }
         }
         return nullptr;
-      });
+    });
 
-  // Find all array type constructor expressions for array types that have had
-  // their element changed to a single field structure. These constructors are
-  // adjusted to wrap each of the arguments with an additional constructor for
-  // the new element structure type.
-  // Example:
-  //   `@stride(32) array<i32, 3>(1, 2, 3)`
-  // ->
-  //   `array<strided_arr, 3>(strided_arr(1), strided_arr(2), strided_arr(3))`
-  ctx.ReplaceAll(
-      [&](const ast::CallExpression* expr) -> const ast::Expression* {
+    // Find all array index-accessors expressions for arrays that have had their
+    // element changed to a single field structure. These expressions are adjusted
+    // to insert an additional member accessor for the single structure field.
+    // Example: `arr[i]` -> `arr[i].el`
+    ctx.ReplaceAll([&](const ast::IndexAccessorExpression* idx) -> const ast::Expression* {
+        if (auto* ty = ctx.src->TypeOf(idx->object)) {
+            if (auto* arr = ty->UnwrapRef()->As<sem::Array>()) {
+                if (!arr->IsStrideImplicit()) {
+                    auto* expr = ctx.CloneWithoutTransform(idx);
+                    return ctx.dst->MemberAccessor(expr, kMemberName);
+                }
+            }
+        }
+        return nullptr;
+    });
+
+    // Find all array type constructor expressions for array types that have had
+    // their element changed to a single field structure. These constructors are
+    // adjusted to wrap each of the arguments with an additional constructor for
+    // the new element structure type.
+    // Example:
+    //   `@stride(32) array<i32, 3>(1, 2, 3)`
+    // ->
+    //   `array<strided_arr, 3>(strided_arr(1), strided_arr(2), strided_arr(3))`
+    ctx.ReplaceAll([&](const ast::CallExpression* expr) -> const ast::Expression* {
         if (!expr->args.empty()) {
-          if (auto* call = sem.Get(expr)) {
-            if (auto* ctor = call->Target()->As<sem::TypeConstructor>()) {
-              if (auto* arr = ctor->ReturnType()->As<sem::Array>()) {
-                // Begin by cloning the array constructor type or name
-                // If this is an unaliased array, this may add a new entry to
-                // decomposed.
-                // If this is an aliased array, decomposed should already be
-                // populated with any strided aliases.
-                ast::CallExpression::Target target;
-                if (expr->target.type) {
-                  target.type = ctx.Clone(expr->target.type);
-                } else {
-                  target.name = ctx.Clone(expr->target.name);
-                }
+            if (auto* call = sem.Get(expr)) {
+                if (auto* ctor = call->Target()->As<sem::TypeConstructor>()) {
+                    if (auto* arr = ctor->ReturnType()->As<sem::Array>()) {
+                        // Begin by cloning the array constructor type or name
+                        // If this is an unaliased array, this may add a new entry to
+                        // decomposed.
+                        // If this is an aliased array, decomposed should already be
+                        // populated with any strided aliases.
+                        ast::CallExpression::Target target;
+                        if (expr->target.type) {
+                            target.type = ctx.Clone(expr->target.type);
+                        } else {
+                            target.name = ctx.Clone(expr->target.name);
+                        }
 
-                ast::ExpressionList args;
-                if (auto it = decomposed.find(arr); it != decomposed.end()) {
-                  args.reserve(expr->args.size());
-                  for (auto* arg : expr->args) {
-                    args.emplace_back(
-                        ctx.dst->Call(it->second, ctx.Clone(arg)));
-                  }
-                } else {
-                  args = ctx.Clone(expr->args);
-                }
+                        ast::ExpressionList args;
+                        if (auto it = decomposed.find(arr); it != decomposed.end()) {
+                            args.reserve(expr->args.size());
+                            for (auto* arg : expr->args) {
+                                args.emplace_back(ctx.dst->Call(it->second, ctx.Clone(arg)));
+                            }
+                        } else {
+                            args = ctx.Clone(expr->args);
+                        }
 
-                return target.type ? ctx.dst->Construct(target.type, args)
-                                   : ctx.dst->Call(target.name, args);
-              }
+                        return target.type ? ctx.dst->Construct(target.type, args)
+                                           : ctx.dst->Call(target.name, args);
+                    }
+                }
             }
-          }
         }
         return nullptr;
-      });
-  ctx.Clone();
+    });
+    ctx.Clone();
 }
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/decompose_strided_array.h b/src/tint/transform/decompose_strided_array.h
index 505f5cb..5dbaaa5 100644
--- a/src/tint/transform/decompose_strided_array.h
+++ b/src/tint/transform/decompose_strided_array.h
@@ -27,31 +27,27 @@
 ///
 /// @note Depends on the following transforms to have been run first:
 /// * SimplifyPointers
-class DecomposeStridedArray final
-    : public Castable<DecomposeStridedArray, Transform> {
- public:
-  /// Constructor
-  DecomposeStridedArray();
+class DecomposeStridedArray final : public Castable<DecomposeStridedArray, Transform> {
+  public:
+    /// Constructor
+    DecomposeStridedArray();
 
-  /// Destructor
-  ~DecomposeStridedArray() override;
+    /// Destructor
+    ~DecomposeStridedArray() override;
 
-  /// @param program the program to inspect
-  /// @param data optional extra transform-specific input data
-  /// @returns true if this transform should be run for the given program
-  bool ShouldRun(const Program* program,
-                 const DataMap& data = {}) const override;
+    /// @param program the program to inspect
+    /// @param data optional extra transform-specific input data
+    /// @returns true if this transform should be run for the given program
+    bool ShouldRun(const Program* program, const DataMap& data = {}) const override;
 
- protected:
-  /// Runs the transform using the CloneContext built for transforming a
-  /// program. Run() is responsible for calling Clone() on the CloneContext.
-  /// @param ctx the CloneContext primed with the input program and
-  /// ProgramBuilder
-  /// @param inputs optional extra transform-specific input data
-  /// @param outputs optional extra transform-specific output data
-  void Run(CloneContext& ctx,
-           const DataMap& inputs,
-           DataMap& outputs) const override;
+  protected:
+    /// Runs the transform using the CloneContext built for transforming a
+    /// program. Run() is responsible for calling Clone() on the CloneContext.
+    /// @param ctx the CloneContext primed with the input program and
+    /// ProgramBuilder
+    /// @param inputs optional extra transform-specific input data
+    /// @param outputs optional extra transform-specific output data
+    void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const override;
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/decompose_strided_array_test.cc b/src/tint/transform/decompose_strided_array_test.cc
index 98ef2c4..cd9d63c 100644
--- a/src/tint/transform/decompose_strided_array_test.cc
+++ b/src/tint/transform/decompose_strided_array_test.cc
@@ -23,549 +23,517 @@
 #include "src/tint/transform/test_helper.h"
 #include "src/tint/transform/unshadow.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::transform {
 namespace {
 
 using DecomposeStridedArrayTest = TransformTest;
-using f32 = ProgramBuilder::f32;
 
 TEST_F(DecomposeStridedArrayTest, ShouldRunEmptyModule) {
-  ProgramBuilder b;
-  EXPECT_FALSE(ShouldRun<DecomposeStridedArray>(Program(std::move(b))));
+    ProgramBuilder b;
+    EXPECT_FALSE(ShouldRun<DecomposeStridedArray>(Program(std::move(b))));
 }
 
 TEST_F(DecomposeStridedArrayTest, ShouldRunNonStridedArray) {
-  // var<private> arr : array<f32, 4>
+    // var<private> arr : array<f32, 4u>
 
-  ProgramBuilder b;
-  b.Global("arr", b.ty.array<f32, 4>(), ast::StorageClass::kPrivate);
-  EXPECT_FALSE(ShouldRun<DecomposeStridedArray>(Program(std::move(b))));
+    ProgramBuilder b;
+    b.Global("arr", b.ty.array<f32, 4u>(), ast::StorageClass::kPrivate);
+    EXPECT_FALSE(ShouldRun<DecomposeStridedArray>(Program(std::move(b))));
 }
 
 TEST_F(DecomposeStridedArrayTest, ShouldRunDefaultStridedArray) {
-  // var<private> arr : @stride(4) array<f32, 4>
+    // var<private> arr : @stride(4) array<f32, 4u>
 
-  ProgramBuilder b;
-  b.Global("arr", b.ty.array<f32, 4>(4), ast::StorageClass::kPrivate);
-  EXPECT_TRUE(ShouldRun<DecomposeStridedArray>(Program(std::move(b))));
+    ProgramBuilder b;
+    b.Global("arr", b.ty.array<f32, 4u>(4), ast::StorageClass::kPrivate);
+    EXPECT_TRUE(ShouldRun<DecomposeStridedArray>(Program(std::move(b))));
 }
 
 TEST_F(DecomposeStridedArrayTest, ShouldRunExplicitStridedArray) {
-  // var<private> arr : @stride(16) array<f32, 4>
+    // var<private> arr : @stride(16) array<f32, 4u>
 
-  ProgramBuilder b;
-  b.Global("arr", b.ty.array<f32, 4>(16), ast::StorageClass::kPrivate);
-  EXPECT_TRUE(ShouldRun<DecomposeStridedArray>(Program(std::move(b))));
+    ProgramBuilder b;
+    b.Global("arr", b.ty.array<f32, 4u>(16), ast::StorageClass::kPrivate);
+    EXPECT_TRUE(ShouldRun<DecomposeStridedArray>(Program(std::move(b))));
 }
 
 TEST_F(DecomposeStridedArrayTest, Empty) {
-  auto* src = R"()";
-  auto* expect = src;
+    auto* src = R"()";
+    auto* expect = src;
 
-  auto got = Run<DecomposeStridedArray>(src);
+    auto got = Run<DecomposeStridedArray>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(DecomposeStridedArrayTest, PrivateDefaultStridedArray) {
-  // var<private> arr : @stride(4) array<f32, 4>
-  //
-  // @stage(compute) @workgroup_size(1)
-  // fn f() {
-  //   let a : @stride(4) array<f32, 4> = a;
-  //   let b : f32 = arr[1];
-  // }
+    // var<private> arr : @stride(4) array<f32, 4u>
+    //
+    // @stage(compute) @workgroup_size(1)
+    // fn f() {
+    //   let a : @stride(4) array<f32, 4u> = a;
+    //   let b : f32 = arr[1];
+    // }
 
-  ProgramBuilder b;
-  b.Global("arr", b.ty.array<f32, 4>(4), ast::StorageClass::kPrivate);
-  b.Func("f", {}, b.ty.void_(),
-         {
-             b.Decl(b.Const("a", b.ty.array<f32, 4>(4), b.Expr("arr"))),
-             b.Decl(b.Const("b", b.ty.f32(), b.IndexAccessor("arr", 1))),
-         },
-         {
-             b.Stage(ast::PipelineStage::kCompute),
-             b.WorkgroupSize(1),
-         });
+    ProgramBuilder b;
+    b.Global("arr", b.ty.array<f32, 4u>(4), ast::StorageClass::kPrivate);
+    b.Func("f", {}, b.ty.void_(),
+           {
+               b.Decl(b.Let("a", b.ty.array<f32, 4u>(4), b.Expr("arr"))),
+               b.Decl(b.Let("b", b.ty.f32(), b.IndexAccessor("arr", 1_i))),
+           },
+           {
+               b.Stage(ast::PipelineStage::kCompute),
+               b.WorkgroupSize(1_i),
+           });
 
-  auto* expect = R"(
-var<private> arr : array<f32, 4>;
+    auto* expect = R"(
+var<private> arr : array<f32, 4u>;
 
-@stage(compute) @workgroup_size(1)
+@stage(compute) @workgroup_size(1i)
 fn f() {
-  let a : array<f32, 4> = arr;
-  let b : f32 = arr[1];
+  let a : array<f32, 4u> = arr;
+  let b : f32 = arr[1i];
 }
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedArray>(
-      Program(std::move(b)));
+    auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedArray>(Program(std::move(b)));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(DecomposeStridedArrayTest, PrivateStridedArray) {
-  // var<private> arr : @stride(32) array<f32, 4>
-  //
-  // @stage(compute) @workgroup_size(1)
-  // fn f() {
-  //   let a : @stride(32) array<f32, 4> = a;
-  //   let b : f32 = arr[1];
-  // }
+    // var<private> arr : @stride(32) array<f32, 4u>
+    //
+    // @stage(compute) @workgroup_size(1)
+    // fn f() {
+    //   let a : @stride(32) array<f32, 4u> = a;
+    //   let b : f32 = arr[1];
+    // }
 
-  ProgramBuilder b;
-  b.Global("arr", b.ty.array<f32, 4>(32), ast::StorageClass::kPrivate);
-  b.Func("f", {}, b.ty.void_(),
-         {
-             b.Decl(b.Const("a", b.ty.array<f32, 4>(32), b.Expr("arr"))),
-             b.Decl(b.Const("b", b.ty.f32(), b.IndexAccessor("arr", 1))),
-         },
-         {
-             b.Stage(ast::PipelineStage::kCompute),
-             b.WorkgroupSize(1),
-         });
+    ProgramBuilder b;
+    b.Global("arr", b.ty.array<f32, 4u>(32), ast::StorageClass::kPrivate);
+    b.Func("f", {}, b.ty.void_(),
+           {
+               b.Decl(b.Let("a", b.ty.array<f32, 4u>(32), b.Expr("arr"))),
+               b.Decl(b.Let("b", b.ty.f32(), b.IndexAccessor("arr", 1_i))),
+           },
+           {
+               b.Stage(ast::PipelineStage::kCompute),
+               b.WorkgroupSize(1_i),
+           });
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct strided_arr {
   @size(32)
   el : f32,
 }
 
-var<private> arr : array<strided_arr, 4>;
+var<private> arr : array<strided_arr, 4u>;
 
-@stage(compute) @workgroup_size(1)
+@stage(compute) @workgroup_size(1i)
 fn f() {
-  let a : array<strided_arr, 4> = arr;
-  let b : f32 = arr[1].el;
+  let a : array<strided_arr, 4u> = arr;
+  let b : f32 = arr[1i].el;
 }
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedArray>(
-      Program(std::move(b)));
+    auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedArray>(Program(std::move(b)));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(DecomposeStridedArrayTest, ReadUniformStridedArray) {
-  // struct S {
-  //   a : @stride(32) array<f32, 4>,
-  // };
-  // @group(0) @binding(0) var<uniform> s : S;
-  //
-  // @stage(compute) @workgroup_size(1)
-  // fn f() {
-  //   let a : @stride(32) array<f32, 4> = s.a;
-  //   let b : f32 = s.a[1];
-  // }
-  ProgramBuilder b;
-  auto* S = b.Structure("S", {b.Member("a", b.ty.array<f32, 4>(32))});
-  b.Global("s", b.ty.Of(S), ast::StorageClass::kUniform,
-           b.GroupAndBinding(0, 0));
-  b.Func("f", {}, b.ty.void_(),
-         {
-             b.Decl(b.Const("a", b.ty.array<f32, 4>(32),
-                            b.MemberAccessor("s", "a"))),
-             b.Decl(b.Const("b", b.ty.f32(),
-                            b.IndexAccessor(b.MemberAccessor("s", "a"), 1))),
-         },
-         {
-             b.Stage(ast::PipelineStage::kCompute),
-             b.WorkgroupSize(1),
-         });
+    // struct S {
+    //   a : @stride(32) array<f32, 4u>,
+    // };
+    // @group(0) @binding(0) var<uniform> s : S;
+    //
+    // @stage(compute) @workgroup_size(1)
+    // fn f() {
+    //   let a : @stride(32) array<f32, 4u> = s.a;
+    //   let b : f32 = s.a[1];
+    // }
+    ProgramBuilder b;
+    auto* S = b.Structure("S", {b.Member("a", b.ty.array<f32, 4u>(32))});
+    b.Global("s", b.ty.Of(S), ast::StorageClass::kUniform, b.GroupAndBinding(0, 0));
+    b.Func("f", {}, b.ty.void_(),
+           {
+               b.Decl(b.Let("a", b.ty.array<f32, 4u>(32), b.MemberAccessor("s", "a"))),
+               b.Decl(b.Let("b", b.ty.f32(), b.IndexAccessor(b.MemberAccessor("s", "a"), 1_i))),
+           },
+           {
+               b.Stage(ast::PipelineStage::kCompute),
+               b.WorkgroupSize(1_i),
+           });
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct strided_arr {
   @size(32)
   el : f32,
 }
 
 struct S {
-  a : array<strided_arr, 4>,
+  a : array<strided_arr, 4u>,
 }
 
 @group(0) @binding(0) var<uniform> s : S;
 
-@stage(compute) @workgroup_size(1)
+@stage(compute) @workgroup_size(1i)
 fn f() {
-  let a : array<strided_arr, 4> = s.a;
-  let b : f32 = s.a[1].el;
+  let a : array<strided_arr, 4u> = s.a;
+  let b : f32 = s.a[1i].el;
 }
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedArray>(
-      Program(std::move(b)));
+    auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedArray>(Program(std::move(b)));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(DecomposeStridedArrayTest, ReadUniformDefaultStridedArray) {
-  // struct S {
-  //   a : @stride(16) array<vec4<f32>, 4>,
-  // };
-  // @group(0) @binding(0) var<uniform> s : S;
-  //
-  // @stage(compute) @workgroup_size(1)
-  // fn f() {
-  //   let a : @stride(16) array<vec4<f32>, 4> = s.a;
-  //   let b : f32 = s.a[1][2];
-  // }
-  ProgramBuilder b;
-  auto* S =
-      b.Structure("S", {b.Member("a", b.ty.array(b.ty.vec4<f32>(), 4, 16))});
-  b.Global("s", b.ty.Of(S), ast::StorageClass::kUniform,
-           b.GroupAndBinding(0, 0));
-  b.Func("f", {}, b.ty.void_(),
-         {
-             b.Decl(b.Const("a", b.ty.array(b.ty.vec4<f32>(), 4, 16),
-                            b.MemberAccessor("s", "a"))),
-             b.Decl(b.Const(
-                 "b", b.ty.f32(),
-                 b.IndexAccessor(b.IndexAccessor(b.MemberAccessor("s", "a"), 1),
-                                 2))),
-         },
-         {
-             b.Stage(ast::PipelineStage::kCompute),
-             b.WorkgroupSize(1),
-         });
+    // struct S {
+    //   a : @stride(16) array<vec4<f32>, 4u>,
+    // };
+    // @group(0) @binding(0) var<uniform> s : S;
+    //
+    // @stage(compute) @workgroup_size(1)
+    // fn f() {
+    //   let a : @stride(16) array<vec4<f32>, 4u> = s.a;
+    //   let b : f32 = s.a[1][2];
+    // }
+    ProgramBuilder b;
+    auto* S = b.Structure("S", {b.Member("a", b.ty.array(b.ty.vec4<f32>(), 4_u, 16))});
+    b.Global("s", b.ty.Of(S), ast::StorageClass::kUniform, b.GroupAndBinding(0, 0));
+    b.Func(
+        "f", {}, b.ty.void_(),
+        {
+            b.Decl(b.Let("a", b.ty.array(b.ty.vec4<f32>(), 4_u, 16), b.MemberAccessor("s", "a"))),
+            b.Decl(b.Let("b", b.ty.f32(),
+                         b.IndexAccessor(b.IndexAccessor(b.MemberAccessor("s", "a"), 1_i), 2_i))),
+        },
+        {
+            b.Stage(ast::PipelineStage::kCompute),
+            b.WorkgroupSize(1_i),
+        });
 
-  auto* expect =
-      R"(
+    auto* expect =
+        R"(
 struct S {
-  a : array<vec4<f32>, 4>,
+  a : array<vec4<f32>, 4u>,
 }
 
 @group(0) @binding(0) var<uniform> s : S;
 
-@stage(compute) @workgroup_size(1)
+@stage(compute) @workgroup_size(1i)
 fn f() {
-  let a : array<vec4<f32>, 4> = s.a;
-  let b : f32 = s.a[1][2];
+  let a : array<vec4<f32>, 4u> = s.a;
+  let b : f32 = s.a[1i][2i];
 }
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedArray>(
-      Program(std::move(b)));
+    auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedArray>(Program(std::move(b)));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(DecomposeStridedArrayTest, ReadStorageStridedArray) {
-  // struct S {
-  //   a : @stride(32) array<f32, 4>,
-  // };
-  // @group(0) @binding(0) var<storage> s : S;
-  //
-  // @stage(compute) @workgroup_size(1)
-  // fn f() {
-  //   let a : @stride(32) array<f32, 4> = s.a;
-  //   let b : f32 = s.a[1];
-  // }
-  ProgramBuilder b;
-  auto* S = b.Structure("S", {b.Member("a", b.ty.array<f32, 4>(32))});
-  b.Global("s", b.ty.Of(S), ast::StorageClass::kStorage,
-           b.GroupAndBinding(0, 0));
-  b.Func("f", {}, b.ty.void_(),
-         {
-             b.Decl(b.Const("a", b.ty.array<f32, 4>(32),
-                            b.MemberAccessor("s", "a"))),
-             b.Decl(b.Const("b", b.ty.f32(),
-                            b.IndexAccessor(b.MemberAccessor("s", "a"), 1))),
-         },
-         {
-             b.Stage(ast::PipelineStage::kCompute),
-             b.WorkgroupSize(1),
-         });
+    // struct S {
+    //   a : @stride(32) array<f32, 4u>,
+    // };
+    // @group(0) @binding(0) var<storage> s : S;
+    //
+    // @stage(compute) @workgroup_size(1)
+    // fn f() {
+    //   let a : @stride(32) array<f32, 4u> = s.a;
+    //   let b : f32 = s.a[1];
+    // }
+    ProgramBuilder b;
+    auto* S = b.Structure("S", {b.Member("a", b.ty.array<f32, 4u>(32))});
+    b.Global("s", b.ty.Of(S), ast::StorageClass::kStorage, b.GroupAndBinding(0, 0));
+    b.Func("f", {}, b.ty.void_(),
+           {
+               b.Decl(b.Let("a", b.ty.array<f32, 4u>(32), b.MemberAccessor("s", "a"))),
+               b.Decl(b.Let("b", b.ty.f32(), b.IndexAccessor(b.MemberAccessor("s", "a"), 1_i))),
+           },
+           {
+               b.Stage(ast::PipelineStage::kCompute),
+               b.WorkgroupSize(1_i),
+           });
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct strided_arr {
   @size(32)
   el : f32,
 }
 
 struct S {
-  a : array<strided_arr, 4>,
+  a : array<strided_arr, 4u>,
 }
 
 @group(0) @binding(0) var<storage> s : S;
 
-@stage(compute) @workgroup_size(1)
+@stage(compute) @workgroup_size(1i)
 fn f() {
-  let a : array<strided_arr, 4> = s.a;
-  let b : f32 = s.a[1].el;
+  let a : array<strided_arr, 4u> = s.a;
+  let b : f32 = s.a[1i].el;
 }
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedArray>(
-      Program(std::move(b)));
+    auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedArray>(Program(std::move(b)));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(DecomposeStridedArrayTest, ReadStorageDefaultStridedArray) {
-  // struct S {
-  //   a : @stride(4) array<f32, 4>,
-  // };
-  // @group(0) @binding(0) var<storage> s : S;
-  //
-  // @stage(compute) @workgroup_size(1)
-  // fn f() {
-  //   let a : @stride(4) array<f32, 4> = s.a;
-  //   let b : f32 = s.a[1];
-  // }
-  ProgramBuilder b;
-  auto* S = b.Structure("S", {b.Member("a", b.ty.array<f32, 4>(4))});
-  b.Global("s", b.ty.Of(S), ast::StorageClass::kStorage,
-           b.GroupAndBinding(0, 0));
-  b.Func("f", {}, b.ty.void_(),
-         {
-             b.Decl(b.Const("a", b.ty.array<f32, 4>(4),
-                            b.MemberAccessor("s", "a"))),
-             b.Decl(b.Const("b", b.ty.f32(),
-                            b.IndexAccessor(b.MemberAccessor("s", "a"), 1))),
-         },
-         {
-             b.Stage(ast::PipelineStage::kCompute),
-             b.WorkgroupSize(1),
-         });
+    // struct S {
+    //   a : @stride(4) array<f32, 4u>,
+    // };
+    // @group(0) @binding(0) var<storage> s : S;
+    //
+    // @stage(compute) @workgroup_size(1)
+    // fn f() {
+    //   let a : @stride(4) array<f32, 4u> = s.a;
+    //   let b : f32 = s.a[1];
+    // }
+    ProgramBuilder b;
+    auto* S = b.Structure("S", {b.Member("a", b.ty.array<f32, 4u>(4))});
+    b.Global("s", b.ty.Of(S), ast::StorageClass::kStorage, b.GroupAndBinding(0, 0));
+    b.Func("f", {}, b.ty.void_(),
+           {
+               b.Decl(b.Let("a", b.ty.array<f32, 4u>(4), b.MemberAccessor("s", "a"))),
+               b.Decl(b.Let("b", b.ty.f32(), b.IndexAccessor(b.MemberAccessor("s", "a"), 1_i))),
+           },
+           {
+               b.Stage(ast::PipelineStage::kCompute),
+               b.WorkgroupSize(1_i),
+           });
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
-  a : array<f32, 4>,
+  a : array<f32, 4u>,
 }
 
 @group(0) @binding(0) var<storage> s : S;
 
-@stage(compute) @workgroup_size(1)
+@stage(compute) @workgroup_size(1i)
 fn f() {
-  let a : array<f32, 4> = s.a;
-  let b : f32 = s.a[1];
+  let a : array<f32, 4u> = s.a;
+  let b : f32 = s.a[1i];
 }
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedArray>(
-      Program(std::move(b)));
+    auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedArray>(Program(std::move(b)));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(DecomposeStridedArrayTest, WriteStorageStridedArray) {
-  // struct S {
-  //   a : @stride(32) array<f32, 4>,
-  // };
-  // @group(0) @binding(0) var<storage, read_write> s : S;
-  //
-  // @stage(compute) @workgroup_size(1)
-  // fn f() {
-  //   s.a = @stride(32) array<f32, 4>();
-  //   s.a = @stride(32) array<f32, 4>(1.0, 2.0, 3.0, 4.0);
-  //   s.a[1] = 5.0;
-  // }
-  ProgramBuilder b;
-  auto* S = b.Structure("S", {b.Member("a", b.ty.array<f32, 4>(32))});
-  b.Global("s", b.ty.Of(S), ast::StorageClass::kStorage,
-           ast::Access::kReadWrite, b.GroupAndBinding(0, 0));
-  b.Func(
-      "f", {}, b.ty.void_(),
-      {
-          b.Assign(b.MemberAccessor("s", "a"),
-                   b.Construct(b.ty.array<f32, 4>(32))),
-          b.Assign(b.MemberAccessor("s", "a"),
-                   b.Construct(b.ty.array<f32, 4>(32), 1.0f, 2.0f, 3.0f, 4.0f)),
-          b.Assign(b.IndexAccessor(b.MemberAccessor("s", "a"), 1), 5.0f),
-      },
-      {
-          b.Stage(ast::PipelineStage::kCompute),
-          b.WorkgroupSize(1),
-      });
+    // struct S {
+    //   a : @stride(32) array<f32, 4u>,
+    // };
+    // @group(0) @binding(0) var<storage, read_write> s : S;
+    //
+    // @stage(compute) @workgroup_size(1)
+    // fn f() {
+    //   s.a = @stride(32) array<f32, 4u>();
+    //   s.a = @stride(32) array<f32, 4u>(1.0, 2.0, 3.0, 4.0);
+    //   s.a[1i] = 5.0;
+    // }
+    ProgramBuilder b;
+    auto* S = b.Structure("S", {b.Member("a", b.ty.array<f32, 4u>(32))});
+    b.Global("s", b.ty.Of(S), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+             b.GroupAndBinding(0, 0));
+    b.Func("f", {}, b.ty.void_(),
+           {
+               b.Assign(b.MemberAccessor("s", "a"), b.Construct(b.ty.array<f32, 4u>(32))),
+               b.Assign(b.MemberAccessor("s", "a"),
+                        b.Construct(b.ty.array<f32, 4u>(32), 1.0f, 2.0f, 3.0f, 4.0f)),
+               b.Assign(b.IndexAccessor(b.MemberAccessor("s", "a"), 1_i), 5.0f),
+           },
+           {
+               b.Stage(ast::PipelineStage::kCompute),
+               b.WorkgroupSize(1_i),
+           });
 
-  auto* expect =
-      R"(
+    auto* expect =
+        R"(
 struct strided_arr {
   @size(32)
   el : f32,
 }
 
 struct S {
-  a : array<strided_arr, 4>,
+  a : array<strided_arr, 4u>,
 }
 
 @group(0) @binding(0) var<storage, read_write> s : S;
 
-@stage(compute) @workgroup_size(1)
+@stage(compute) @workgroup_size(1i)
 fn f() {
-  s.a = array<strided_arr, 4>();
-  s.a = array<strided_arr, 4>(strided_arr(1.0), strided_arr(2.0), strided_arr(3.0), strided_arr(4.0));
-  s.a[1].el = 5.0;
+  s.a = array<strided_arr, 4u>();
+  s.a = array<strided_arr, 4u>(strided_arr(1.0), strided_arr(2.0), strided_arr(3.0), strided_arr(4.0));
+  s.a[1i].el = 5.0;
 }
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedArray>(
-      Program(std::move(b)));
+    auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedArray>(Program(std::move(b)));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(DecomposeStridedArrayTest, WriteStorageDefaultStridedArray) {
-  // struct S {
-  //   a : @stride(4) array<f32, 4>,
-  // };
-  // @group(0) @binding(0) var<storage, read_write> s : S;
-  //
-  // @stage(compute) @workgroup_size(1)
-  // fn f() {
-  //   s.a = @stride(4) array<f32, 4>();
-  //   s.a = @stride(4) array<f32, 4>(1.0, 2.0, 3.0, 4.0);
-  //   s.a[1] = 5.0;
-  // }
-  ProgramBuilder b;
-  auto* S = b.Structure("S", {b.Member("a", b.ty.array<f32, 4>(4))});
-  b.Global("s", b.ty.Of(S), ast::StorageClass::kStorage,
-           ast::Access::kReadWrite, b.GroupAndBinding(0, 0));
-  b.Func(
-      "f", {}, b.ty.void_(),
-      {
-          b.Assign(b.MemberAccessor("s", "a"),
-                   b.Construct(b.ty.array<f32, 4>(4))),
-          b.Assign(b.MemberAccessor("s", "a"),
-                   b.Construct(b.ty.array<f32, 4>(4), 1.0f, 2.0f, 3.0f, 4.0f)),
-          b.Assign(b.IndexAccessor(b.MemberAccessor("s", "a"), 1), 5.0f),
-      },
-      {
-          b.Stage(ast::PipelineStage::kCompute),
-          b.WorkgroupSize(1),
-      });
+    // struct S {
+    //   a : @stride(4) array<f32, 4u>,
+    // };
+    // @group(0) @binding(0) var<storage, read_write> s : S;
+    //
+    // @stage(compute) @workgroup_size(1)
+    // fn f() {
+    //   s.a = @stride(4) array<f32, 4u>();
+    //   s.a = @stride(4) array<f32, 4u>(1.0, 2.0, 3.0, 4.0);
+    //   s.a[1] = 5.0;
+    // }
+    ProgramBuilder b;
+    auto* S = b.Structure("S", {b.Member("a", b.ty.array<f32, 4u>(4))});
+    b.Global("s", b.ty.Of(S), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+             b.GroupAndBinding(0, 0));
+    b.Func("f", {}, b.ty.void_(),
+           {
+               b.Assign(b.MemberAccessor("s", "a"), b.Construct(b.ty.array<f32, 4u>(4))),
+               b.Assign(b.MemberAccessor("s", "a"),
+                        b.Construct(b.ty.array<f32, 4u>(4), 1.0f, 2.0f, 3.0f, 4.0f)),
+               b.Assign(b.IndexAccessor(b.MemberAccessor("s", "a"), 1_i), 5.0f),
+           },
+           {
+               b.Stage(ast::PipelineStage::kCompute),
+               b.WorkgroupSize(1_i),
+           });
 
-  auto* expect =
-      R"(
+    auto* expect =
+        R"(
 struct S {
-  a : array<f32, 4>,
+  a : array<f32, 4u>,
 }
 
 @group(0) @binding(0) var<storage, read_write> s : S;
 
-@stage(compute) @workgroup_size(1)
+@stage(compute) @workgroup_size(1i)
 fn f() {
-  s.a = array<f32, 4>();
-  s.a = array<f32, 4>(1.0, 2.0, 3.0, 4.0);
-  s.a[1] = 5.0;
+  s.a = array<f32, 4u>();
+  s.a = array<f32, 4u>(1.0, 2.0, 3.0, 4.0);
+  s.a[1i] = 5.0;
 }
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedArray>(
-      Program(std::move(b)));
+    auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedArray>(Program(std::move(b)));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(DecomposeStridedArrayTest, ReadWriteViaPointerLets) {
-  // struct S {
-  //   a : @stride(32) array<f32, 4>,
-  // };
-  // @group(0) @binding(0) var<storage, read_write> s : S;
-  //
-  // @stage(compute) @workgroup_size(1)
-  // fn f() {
-  //   let a = &s.a;
-  //   let b = &*&*(a);
-  //   let c = *b;
-  //   let d = (*b)[1];
-  //   (*b) = @stride(32) array<f32, 4>(1.0, 2.0, 3.0, 4.0);
-  //   (*b)[1] = 5.0;
-  // }
-  ProgramBuilder b;
-  auto* S = b.Structure("S", {b.Member("a", b.ty.array<f32, 4>(32))});
-  b.Global("s", b.ty.Of(S), ast::StorageClass::kStorage,
-           ast::Access::kReadWrite, b.GroupAndBinding(0, 0));
-  b.Func("f", {}, b.ty.void_(),
-         {
-             b.Decl(b.Const("a", nullptr,
-                            b.AddressOf(b.MemberAccessor("s", "a")))),
-             b.Decl(b.Const("b", nullptr,
-                            b.AddressOf(b.Deref(b.AddressOf(b.Deref("a")))))),
-             b.Decl(b.Const("c", nullptr, b.Deref("b"))),
-             b.Decl(b.Const("d", nullptr, b.IndexAccessor(b.Deref("b"), 1))),
-             b.Assign(b.Deref("b"), b.Construct(b.ty.array<f32, 4>(32), 1.0f,
-                                                2.0f, 3.0f, 4.0f)),
-             b.Assign(b.IndexAccessor(b.Deref("b"), 1), 5.0f),
-         },
-         {
-             b.Stage(ast::PipelineStage::kCompute),
-             b.WorkgroupSize(1),
-         });
+    // struct S {
+    //   a : @stride(32) array<f32, 4u>,
+    // };
+    // @group(0) @binding(0) var<storage, read_write> s : S;
+    //
+    // @stage(compute) @workgroup_size(1)
+    // fn f() {
+    //   let a = &s.a;
+    //   let b = &*&*(a);
+    //   let c = *b;
+    //   let d = (*b)[1];
+    //   (*b) = @stride(32) array<f32, 4u>(1.0, 2.0, 3.0, 4.0);
+    //   (*b)[1] = 5.0;
+    // }
+    ProgramBuilder b;
+    auto* S = b.Structure("S", {b.Member("a", b.ty.array<f32, 4u>(32))});
+    b.Global("s", b.ty.Of(S), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+             b.GroupAndBinding(0, 0));
+    b.Func("f", {}, b.ty.void_(),
+           {
+               b.Decl(b.Let("a", nullptr, b.AddressOf(b.MemberAccessor("s", "a")))),
+               b.Decl(b.Let("b", nullptr, b.AddressOf(b.Deref(b.AddressOf(b.Deref("a")))))),
+               b.Decl(b.Let("c", nullptr, b.Deref("b"))),
+               b.Decl(b.Let("d", nullptr, b.IndexAccessor(b.Deref("b"), 1_i))),
+               b.Assign(b.Deref("b"), b.Construct(b.ty.array<f32, 4u>(32), 1.0f, 2.0f, 3.0f, 4.0f)),
+               b.Assign(b.IndexAccessor(b.Deref("b"), 1_i), 5.0f),
+           },
+           {
+               b.Stage(ast::PipelineStage::kCompute),
+               b.WorkgroupSize(1_i),
+           });
 
-  auto* expect =
-      R"(
+    auto* expect =
+        R"(
 struct strided_arr {
   @size(32)
   el : f32,
 }
 
 struct S {
-  a : array<strided_arr, 4>,
+  a : array<strided_arr, 4u>,
 }
 
 @group(0) @binding(0) var<storage, read_write> s : S;
 
-@stage(compute) @workgroup_size(1)
+@stage(compute) @workgroup_size(1i)
 fn f() {
   let c = s.a;
-  let d = s.a[1].el;
-  s.a = array<strided_arr, 4>(strided_arr(1.0), strided_arr(2.0), strided_arr(3.0), strided_arr(4.0));
-  s.a[1].el = 5.0;
+  let d = s.a[1i].el;
+  s.a = array<strided_arr, 4u>(strided_arr(1.0), strided_arr(2.0), strided_arr(3.0), strided_arr(4.0));
+  s.a[1i].el = 5.0;
 }
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedArray>(
-      Program(std::move(b)));
+    auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedArray>(Program(std::move(b)));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(DecomposeStridedArrayTest, PrivateAliasedStridedArray) {
-  // type ARR = @stride(32) array<f32, 4>;
-  // struct S {
-  //   a : ARR,
-  // };
-  // @group(0) @binding(0) var<storage, read_write> s : S;
-  //
-  // @stage(compute) @workgroup_size(1)
-  // fn f() {
-  //   let a : ARR = s.a;
-  //   let b : f32 = s.a[1];
-  //   s.a = ARR();
-  //   s.a = ARR(1.0, 2.0, 3.0, 4.0);
-  //   s.a[1] = 5.0;
-  // }
-  ProgramBuilder b;
-  b.Alias("ARR", b.ty.array<f32, 4>(32));
-  auto* S = b.Structure("S", {b.Member("a", b.ty.type_name("ARR"))});
-  b.Global("s", b.ty.Of(S), ast::StorageClass::kStorage,
-           ast::Access::kReadWrite, b.GroupAndBinding(0, 0));
-  b.Func(
-      "f", {}, b.ty.void_(),
-      {
-          b.Decl(
-              b.Const("a", b.ty.type_name("ARR"), b.MemberAccessor("s", "a"))),
-          b.Decl(b.Const("b", b.ty.f32(),
-                         b.IndexAccessor(b.MemberAccessor("s", "a"), 1))),
-          b.Assign(b.MemberAccessor("s", "a"),
-                   b.Construct(b.ty.type_name("ARR"))),
-          b.Assign(b.MemberAccessor("s", "a"),
-                   b.Construct(b.ty.type_name("ARR"), 1.0f, 2.0f, 3.0f, 4.0f)),
-          b.Assign(b.IndexAccessor(b.MemberAccessor("s", "a"), 1), 5.0f),
-      },
-      {
-          b.Stage(ast::PipelineStage::kCompute),
-          b.WorkgroupSize(1),
-      });
+    // type ARR = @stride(32) array<f32, 4u>;
+    // struct S {
+    //   a : ARR,
+    // };
+    // @group(0) @binding(0) var<storage, read_write> s : S;
+    //
+    // @stage(compute) @workgroup_size(1)
+    // fn f() {
+    //   let a : ARR = s.a;
+    //   let b : f32 = s.a[1];
+    //   s.a = ARR();
+    //   s.a = ARR(1.0, 2.0, 3.0, 4.0);
+    //   s.a[1] = 5.0;
+    // }
+    ProgramBuilder b;
+    b.Alias("ARR", b.ty.array<f32, 4u>(32));
+    auto* S = b.Structure("S", {b.Member("a", b.ty.type_name("ARR"))});
+    b.Global("s", b.ty.Of(S), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+             b.GroupAndBinding(0, 0));
+    b.Func("f", {}, b.ty.void_(),
+           {
+               b.Decl(b.Let("a", b.ty.type_name("ARR"), b.MemberAccessor("s", "a"))),
+               b.Decl(b.Let("b", b.ty.f32(), b.IndexAccessor(b.MemberAccessor("s", "a"), 1_i))),
+               b.Assign(b.MemberAccessor("s", "a"), b.Construct(b.ty.type_name("ARR"))),
+               b.Assign(b.MemberAccessor("s", "a"),
+                        b.Construct(b.ty.type_name("ARR"), 1.0f, 2.0f, 3.0f, 4.0f)),
+               b.Assign(b.IndexAccessor(b.MemberAccessor("s", "a"), 1_i), 5.0f),
+           },
+           {
+               b.Stage(ast::PipelineStage::kCompute),
+               b.WorkgroupSize(1_i),
+           });
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct strided_arr {
   @size(32)
   el : f32,
 }
 
-type ARR = array<strided_arr, 4>;
+type ARR = array<strided_arr, 4u>;
 
 struct S {
   a : ARR,
@@ -573,102 +541,99 @@
 
 @group(0) @binding(0) var<storage, read_write> s : S;
 
-@stage(compute) @workgroup_size(1)
+@stage(compute) @workgroup_size(1i)
 fn f() {
   let a : ARR = s.a;
-  let b : f32 = s.a[1].el;
+  let b : f32 = s.a[1i].el;
   s.a = ARR();
   s.a = ARR(strided_arr(1.0), strided_arr(2.0), strided_arr(3.0), strided_arr(4.0));
-  s.a[1].el = 5.0;
+  s.a[1i].el = 5.0;
 }
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedArray>(
-      Program(std::move(b)));
+    auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedArray>(Program(std::move(b)));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(DecomposeStridedArrayTest, PrivateNestedStridedArray) {
-  // type ARR_A = @stride(8) array<f32, 2>;
-  // type ARR_B = @stride(128) array<@stride(16) array<ARR_A, 3>, 4>;
-  // struct S {
-  //   a : ARR_B,
-  // };
-  // @group(0) @binding(0) var<storage, read_write> s : S;
-  //
-  // @stage(compute) @workgroup_size(1)
-  // fn f() {
-  //   let a : ARR_B = s.a;
-  //   let b : array<@stride(8) array<f32, 2>, 3> = s.a[3];
-  //   let c = s.a[3][2];
-  //   let d = s.a[3][2][1];
-  //   s.a = ARR_B();
-  //   s.a[3][2][1] = 5.0;
-  // }
+    // type ARR_A = @stride(8) array<f32, 2u>;
+    // type ARR_B = @stride(128) array<@stride(16) array<ARR_A, 3u>, 4u>;
+    // struct S {
+    //   a : ARR_B,
+    // };
+    // @group(0) @binding(0) var<storage, read_write> s : S;
+    //
+    // @stage(compute) @workgroup_size(1)
+    // fn f() {
+    //   let a : ARR_B = s.a;
+    //   let b : array<@stride(8) array<f32, 2u>, 3u> = s.a[3];
+    //   let c = s.a[3][2];
+    //   let d = s.a[3][2][1];
+    //   s.a = ARR_B();
+    //   s.a[3][2][1] = 5.0;
+    // }
 
-  ProgramBuilder b;
-  b.Alias("ARR_A", b.ty.array<f32, 2>(8));
-  b.Alias("ARR_B",
-          b.ty.array(                                      //
-              b.ty.array(b.ty.type_name("ARR_A"), 3, 16),  //
-              4, 128));
-  auto* S = b.Structure("S", {b.Member("a", b.ty.type_name("ARR_B"))});
-  b.Global("s", b.ty.Of(S), ast::StorageClass::kStorage,
-           ast::Access::kReadWrite, b.GroupAndBinding(0, 0));
-  b.Func("f", {}, b.ty.void_(),
-         {
-             b.Decl(b.Const("a", b.ty.type_name("ARR_B"),
-                            b.MemberAccessor("s", "a"))),
-             b.Decl(b.Const("b", b.ty.array(b.ty.type_name("ARR_A"), 3, 16),
+    ProgramBuilder b;
+    b.Alias("ARR_A", b.ty.array<f32, 2>(8));
+    b.Alias("ARR_B",
+            b.ty.array(                                        //
+                b.ty.array(b.ty.type_name("ARR_A"), 3_u, 16),  //
+                4_u, 128));
+    auto* S = b.Structure("S", {b.Member("a", b.ty.type_name("ARR_B"))});
+    b.Global("s", b.ty.Of(S), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+             b.GroupAndBinding(0, 0));
+    b.Func("f", {}, b.ty.void_(),
+           {
+               b.Decl(b.Let("a", b.ty.type_name("ARR_B"), b.MemberAccessor("s", "a"))),
+               b.Decl(b.Let("b", b.ty.array(b.ty.type_name("ARR_A"), 3_u, 16),
                             b.IndexAccessor(                 //
                                 b.MemberAccessor("s", "a"),  //
-                                3))),
-             b.Decl(b.Const("c", b.ty.type_name("ARR_A"),
+                                3_i))),
+               b.Decl(b.Let("c", b.ty.type_name("ARR_A"),
                             b.IndexAccessor(                     //
                                 b.IndexAccessor(                 //
                                     b.MemberAccessor("s", "a"),  //
-                                    3),
-                                2))),
-             b.Decl(b.Const("d", b.ty.f32(),
+                                    3_i),
+                                2_i))),
+               b.Decl(b.Let("d", b.ty.f32(),
                             b.IndexAccessor(                         //
                                 b.IndexAccessor(                     //
                                     b.IndexAccessor(                 //
                                         b.MemberAccessor("s", "a"),  //
-                                        3),
-                                    2),
-                                1))),
-             b.Assign(b.MemberAccessor("s", "a"),
-                      b.Construct(b.ty.type_name("ARR_B"))),
-             b.Assign(b.IndexAccessor(                         //
-                          b.IndexAccessor(                     //
-                              b.IndexAccessor(                 //
-                                  b.MemberAccessor("s", "a"),  //
-                                  3),
-                              2),
-                          1),
-                      5.0f),
-         },
-         {
-             b.Stage(ast::PipelineStage::kCompute),
-             b.WorkgroupSize(1),
-         });
+                                        3_i),
+                                    2_i),
+                                1_i))),
+               b.Assign(b.MemberAccessor("s", "a"), b.Construct(b.ty.type_name("ARR_B"))),
+               b.Assign(b.IndexAccessor(                         //
+                            b.IndexAccessor(                     //
+                                b.IndexAccessor(                 //
+                                    b.MemberAccessor("s", "a"),  //
+                                    3_i),
+                                2_i),
+                            1_i),
+                        5.0f),
+           },
+           {
+               b.Stage(ast::PipelineStage::kCompute),
+               b.WorkgroupSize(1_i),
+           });
 
-  auto* expect =
-      R"(
+    auto* expect =
+        R"(
 struct strided_arr {
   @size(8)
   el : f32,
 }
 
-type ARR_A = array<strided_arr, 2>;
+type ARR_A = array<strided_arr, 2u>;
 
 struct strided_arr_1 {
   @size(128)
-  el : array<ARR_A, 3>,
+  el : array<ARR_A, 3u>,
 }
 
-type ARR_B = array<strided_arr_1, 4>;
+type ARR_B = array<strided_arr_1, 4u>;
 
 struct S {
   a : ARR_B,
@@ -676,21 +641,20 @@
 
 @group(0) @binding(0) var<storage, read_write> s : S;
 
-@stage(compute) @workgroup_size(1)
+@stage(compute) @workgroup_size(1i)
 fn f() {
   let a : ARR_B = s.a;
-  let b : array<ARR_A, 3> = s.a[3].el;
-  let c : ARR_A = s.a[3].el[2];
-  let d : f32 = s.a[3].el[2][1].el;
+  let b : array<ARR_A, 3u> = s.a[3i].el;
+  let c : ARR_A = s.a[3i].el[2i];
+  let d : f32 = s.a[3i].el[2i][1i].el;
   s.a = ARR_B();
-  s.a[3].el[2][1].el = 5.0;
+  s.a[3i].el[2i][1i].el = 5.0;
 }
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedArray>(
-      Program(std::move(b)));
+    auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedArray>(Program(std::move(b)));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 }  // namespace
 }  // namespace tint::transform
diff --git a/src/tint/transform/decompose_strided_matrix.cc b/src/tint/transform/decompose_strided_matrix.cc
index fd7194d..4f9d6c8 100644
--- a/src/tint/transform/decompose_strided_matrix.cc
+++ b/src/tint/transform/decompose_strided_matrix.cc
@@ -32,28 +32,25 @@
 
 /// MatrixInfo describes a matrix member with a custom stride
 struct MatrixInfo {
-  /// The stride in bytes between columns of the matrix
-  uint32_t stride = 0;
-  /// The type of the matrix
-  const sem::Matrix* matrix = nullptr;
+    /// The stride in bytes between columns of the matrix
+    uint32_t stride = 0;
+    /// The type of the matrix
+    const sem::Matrix* matrix = nullptr;
 
-  /// @returns a new ast::Array that holds an vector column for each row of the
-  /// matrix.
-  const ast::Array* array(ProgramBuilder* b) const {
-    return b->ty.array(b->ty.vec<ProgramBuilder::f32>(matrix->rows()),
-                       matrix->columns(), stride);
-  }
-
-  /// Equality operator
-  bool operator==(const MatrixInfo& info) const {
-    return stride == info.stride && matrix == info.matrix;
-  }
-  /// Hash function
-  struct Hasher {
-    size_t operator()(const MatrixInfo& t) const {
-      return utils::Hash(t.stride, t.matrix);
+    /// @returns a new ast::Array that holds an vector column for each row of the
+    /// matrix.
+    const ast::Array* array(ProgramBuilder* b) const {
+        return b->ty.array(b->ty.vec<f32>(matrix->rows()), u32(matrix->columns()), stride);
     }
-  };
+
+    /// Equality operator
+    bool operator==(const MatrixInfo& info) const {
+        return stride == info.stride && matrix == info.matrix;
+    }
+    /// Hash function
+    struct Hasher {
+        size_t operator()(const MatrixInfo& t) const { return utils::Hash(t.stride, t.matrix); }
+    };
 };
 
 /// Return type of the callback function of GatherCustomStrideMatrixMembers
@@ -71,33 +68,33 @@
 /// scanning will continue.
 template <typename F>
 void GatherCustomStrideMatrixMembers(const Program* program, F&& callback) {
-  for (auto* node : program->ASTNodes().Objects()) {
-    if (auto* str = node->As<ast::Struct>()) {
-      auto* str_ty = program->Sem().Get(str);
-      if (!str_ty->UsedAs(ast::StorageClass::kUniform) &&
-          !str_ty->UsedAs(ast::StorageClass::kStorage)) {
-        continue;
-      }
-      for (auto* member : str_ty->Members()) {
-        auto* matrix = member->Type()->As<sem::Matrix>();
-        if (!matrix) {
-          continue;
+    for (auto* node : program->ASTNodes().Objects()) {
+        if (auto* str = node->As<ast::Struct>()) {
+            auto* str_ty = program->Sem().Get(str);
+            if (!str_ty->UsedAs(ast::StorageClass::kUniform) &&
+                !str_ty->UsedAs(ast::StorageClass::kStorage)) {
+                continue;
+            }
+            for (auto* member : str_ty->Members()) {
+                auto* matrix = member->Type()->As<sem::Matrix>();
+                if (!matrix) {
+                    continue;
+                }
+                auto* attr =
+                    ast::GetAttribute<ast::StrideAttribute>(member->Declaration()->attributes);
+                if (!attr) {
+                    continue;
+                }
+                uint32_t stride = attr->stride;
+                if (matrix->ColumnStride() == stride) {
+                    continue;
+                }
+                if (callback(member, matrix, stride) == GatherResult::kStop) {
+                    return;
+                }
+            }
         }
-        auto* attr = ast::GetAttribute<ast::StrideAttribute>(
-            member->Declaration()->attributes);
-        if (!attr) {
-          continue;
-        }
-        uint32_t stride = attr->stride;
-        if (matrix->ColumnStride() == stride) {
-          continue;
-        }
-        if (callback(member, matrix, stride) == GatherResult::kStop) {
-          return;
-        }
-      }
     }
-  }
 }
 
 }  // namespace
@@ -106,144 +103,133 @@
 
 DecomposeStridedMatrix::~DecomposeStridedMatrix() = default;
 
-bool DecomposeStridedMatrix::ShouldRun(const Program* program,
-                                       const DataMap&) const {
-  bool should_run = false;
-  GatherCustomStrideMatrixMembers(
-      program, [&](const sem::StructMember*, sem::Matrix*, uint32_t) {
+bool DecomposeStridedMatrix::ShouldRun(const Program* program, const DataMap&) const {
+    bool should_run = false;
+    GatherCustomStrideMatrixMembers(program, [&](const sem::StructMember*, sem::Matrix*, uint32_t) {
         should_run = true;
         return GatherResult::kStop;
-      });
-  return should_run;
+    });
+    return should_run;
 }
 
-void DecomposeStridedMatrix::Run(CloneContext& ctx,
-                                 const DataMap&,
-                                 DataMap&) const {
-  // Scan the program for all storage and uniform structure matrix members with
-  // a custom stride attribute. Replace these matrices with an equivalent array,
-  // and populate the `decomposed` map with the members that have been replaced.
-  std::unordered_map<const ast::StructMember*, MatrixInfo> decomposed;
-  GatherCustomStrideMatrixMembers(
-      ctx.src, [&](const sem::StructMember* member, sem::Matrix* matrix,
-                   uint32_t stride) {
-        // We've got ourselves a struct member of a matrix type with a custom
-        // stride. Replace this with an array of column vectors.
-        MatrixInfo info{stride, matrix};
-        auto* replacement = ctx.dst->Member(
-            member->Offset(), ctx.Clone(member->Name()), info.array(ctx.dst));
-        ctx.Replace(member->Declaration(), replacement);
-        decomposed.emplace(member->Declaration(), info);
-        return GatherResult::kContinue;
-      });
+void DecomposeStridedMatrix::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
+    // Scan the program for all storage and uniform structure matrix members with
+    // a custom stride attribute. Replace these matrices with an equivalent array,
+    // and populate the `decomposed` map with the members that have been replaced.
+    std::unordered_map<const ast::StructMember*, MatrixInfo> decomposed;
+    GatherCustomStrideMatrixMembers(
+        ctx.src, [&](const sem::StructMember* member, sem::Matrix* matrix, uint32_t stride) {
+            // We've got ourselves a struct member of a matrix type with a custom
+            // stride. Replace this with an array of column vectors.
+            MatrixInfo info{stride, matrix};
+            auto* replacement =
+                ctx.dst->Member(member->Offset(), ctx.Clone(member->Name()), info.array(ctx.dst));
+            ctx.Replace(member->Declaration(), replacement);
+            decomposed.emplace(member->Declaration(), info);
+            return GatherResult::kContinue;
+        });
 
-  // For all expressions where a single matrix column vector was indexed, we can
-  // preserve these without calling conversion functions.
-  // Example:
-  //   ssbo.mat[2] -> ssbo.mat[2]
-  ctx.ReplaceAll([&](const ast::IndexAccessorExpression* expr)
-                     -> const ast::IndexAccessorExpression* {
-    if (auto* access =
-            ctx.src->Sem().Get<sem::StructMemberAccess>(expr->object)) {
-      auto it = decomposed.find(access->Member()->Declaration());
-      if (it != decomposed.end()) {
-        auto* obj = ctx.CloneWithoutTransform(expr->object);
-        auto* idx = ctx.Clone(expr->index);
-        return ctx.dst->IndexAccessor(obj, idx);
-      }
-    }
-    return nullptr;
-  });
-
-  // For all struct member accesses to the matrix on the LHS of an assignment,
-  // we need to convert the matrix to the array before assigning to the
-  // structure.
-  // Example:
-  //   ssbo.mat = mat_to_arr(m)
-  std::unordered_map<MatrixInfo, Symbol, MatrixInfo::Hasher> mat_to_arr;
-  ctx.ReplaceAll([&](const ast::AssignmentStatement* stmt)
-                     -> const ast::Statement* {
-    if (auto* access = ctx.src->Sem().Get<sem::StructMemberAccess>(stmt->lhs)) {
-      auto it = decomposed.find(access->Member()->Declaration());
-      if (it == decomposed.end()) {
-        return nullptr;
-      }
-      MatrixInfo info = it->second;
-      auto fn = utils::GetOrCreate(mat_to_arr, info, [&] {
-        auto name = ctx.dst->Symbols().New(
-            "mat" + std::to_string(info.matrix->columns()) + "x" +
-            std::to_string(info.matrix->rows()) + "_stride_" +
-            std::to_string(info.stride) + "_to_arr");
-
-        auto matrix = [&] { return CreateASTTypeFor(ctx, info.matrix); };
-        auto array = [&] { return info.array(ctx.dst); };
-
-        auto mat = ctx.dst->Sym("m");
-        ast::ExpressionList columns(info.matrix->columns());
-        for (uint32_t i = 0; i < static_cast<uint32_t>(columns.size()); i++) {
-          columns[i] = ctx.dst->IndexAccessor(mat, i);
-        }
-        ctx.dst->Func(name,
-                      {
-                          ctx.dst->Param(mat, matrix()),
-                      },
-                      array(),
-                      {
-                          ctx.dst->Return(ctx.dst->Construct(array(), columns)),
-                      });
-        return name;
-      });
-      auto* lhs = ctx.CloneWithoutTransform(stmt->lhs);
-      auto* rhs = ctx.dst->Call(fn, ctx.Clone(stmt->rhs));
-      return ctx.dst->Assign(lhs, rhs);
-    }
-    return nullptr;
-  });
-
-  // For all other struct member accesses, we need to convert the array to the
-  // matrix type. Example:
-  //   m = arr_to_mat(ssbo.mat)
-  std::unordered_map<MatrixInfo, Symbol, MatrixInfo::Hasher> arr_to_mat;
-  ctx.ReplaceAll(
-      [&](const ast::MemberAccessorExpression* expr) -> const ast::Expression* {
-        if (auto* access = ctx.src->Sem().Get<sem::StructMemberAccess>(expr)) {
-          auto it = decomposed.find(access->Member()->Declaration());
-          if (it == decomposed.end()) {
-            return nullptr;
-          }
-          MatrixInfo info = it->second;
-          auto fn = utils::GetOrCreate(arr_to_mat, info, [&] {
-            auto name = ctx.dst->Symbols().New(
-                "arr_to_mat" + std::to_string(info.matrix->columns()) + "x" +
-                std::to_string(info.matrix->rows()) + "_stride_" +
-                std::to_string(info.stride));
-
-            auto matrix = [&] { return CreateASTTypeFor(ctx, info.matrix); };
-            auto array = [&] { return info.array(ctx.dst); };
-
-            auto arr = ctx.dst->Sym("arr");
-            ast::ExpressionList columns(info.matrix->columns());
-            for (uint32_t i = 0; i < static_cast<uint32_t>(columns.size());
-                 i++) {
-              columns[i] = ctx.dst->IndexAccessor(arr, i);
+    // For all expressions where a single matrix column vector was indexed, we can
+    // preserve these without calling conversion functions.
+    // Example:
+    //   ssbo.mat[2] -> ssbo.mat[2]
+    ctx.ReplaceAll(
+        [&](const ast::IndexAccessorExpression* expr) -> const ast::IndexAccessorExpression* {
+            if (auto* access = ctx.src->Sem().Get<sem::StructMemberAccess>(expr->object)) {
+                auto it = decomposed.find(access->Member()->Declaration());
+                if (it != decomposed.end()) {
+                    auto* obj = ctx.CloneWithoutTransform(expr->object);
+                    auto* idx = ctx.Clone(expr->index);
+                    return ctx.dst->IndexAccessor(obj, idx);
+                }
             }
-            ctx.dst->Func(
-                name,
-                {
-                    ctx.dst->Param(arr, array()),
-                },
-                matrix(),
-                {
-                    ctx.dst->Return(ctx.dst->Construct(matrix(), columns)),
-                });
-            return name;
-          });
-          return ctx.dst->Call(fn, ctx.CloneWithoutTransform(expr));
+            return nullptr;
+        });
+
+    // For all struct member accesses to the matrix on the LHS of an assignment,
+    // we need to convert the matrix to the array before assigning to the
+    // structure.
+    // Example:
+    //   ssbo.mat = mat_to_arr(m)
+    std::unordered_map<MatrixInfo, Symbol, MatrixInfo::Hasher> mat_to_arr;
+    ctx.ReplaceAll([&](const ast::AssignmentStatement* stmt) -> const ast::Statement* {
+        if (auto* access = ctx.src->Sem().Get<sem::StructMemberAccess>(stmt->lhs)) {
+            auto it = decomposed.find(access->Member()->Declaration());
+            if (it == decomposed.end()) {
+                return nullptr;
+            }
+            MatrixInfo info = it->second;
+            auto fn = utils::GetOrCreate(mat_to_arr, info, [&] {
+                auto name =
+                    ctx.dst->Symbols().New("mat" + std::to_string(info.matrix->columns()) + "x" +
+                                           std::to_string(info.matrix->rows()) + "_stride_" +
+                                           std::to_string(info.stride) + "_to_arr");
+
+                auto matrix = [&] { return CreateASTTypeFor(ctx, info.matrix); };
+                auto array = [&] { return info.array(ctx.dst); };
+
+                auto mat = ctx.dst->Sym("m");
+                ast::ExpressionList columns(info.matrix->columns());
+                for (uint32_t i = 0; i < static_cast<uint32_t>(columns.size()); i++) {
+                    columns[i] = ctx.dst->IndexAccessor(mat, u32(i));
+                }
+                ctx.dst->Func(name,
+                              {
+                                  ctx.dst->Param(mat, matrix()),
+                              },
+                              array(),
+                              {
+                                  ctx.dst->Return(ctx.dst->Construct(array(), columns)),
+                              });
+                return name;
+            });
+            auto* lhs = ctx.CloneWithoutTransform(stmt->lhs);
+            auto* rhs = ctx.dst->Call(fn, ctx.Clone(stmt->rhs));
+            return ctx.dst->Assign(lhs, rhs);
         }
         return nullptr;
-      });
+    });
 
-  ctx.Clone();
+    // For all other struct member accesses, we need to convert the array to the
+    // matrix type. Example:
+    //   m = arr_to_mat(ssbo.mat)
+    std::unordered_map<MatrixInfo, Symbol, MatrixInfo::Hasher> arr_to_mat;
+    ctx.ReplaceAll([&](const ast::MemberAccessorExpression* expr) -> const ast::Expression* {
+        if (auto* access = ctx.src->Sem().Get<sem::StructMemberAccess>(expr)) {
+            auto it = decomposed.find(access->Member()->Declaration());
+            if (it == decomposed.end()) {
+                return nullptr;
+            }
+            MatrixInfo info = it->second;
+            auto fn = utils::GetOrCreate(arr_to_mat, info, [&] {
+                auto name = ctx.dst->Symbols().New(
+                    "arr_to_mat" + std::to_string(info.matrix->columns()) + "x" +
+                    std::to_string(info.matrix->rows()) + "_stride_" + std::to_string(info.stride));
+
+                auto matrix = [&] { return CreateASTTypeFor(ctx, info.matrix); };
+                auto array = [&] { return info.array(ctx.dst); };
+
+                auto arr = ctx.dst->Sym("arr");
+                ast::ExpressionList columns(info.matrix->columns());
+                for (uint32_t i = 0; i < static_cast<uint32_t>(columns.size()); i++) {
+                    columns[i] = ctx.dst->IndexAccessor(arr, u32(i));
+                }
+                ctx.dst->Func(name,
+                              {
+                                  ctx.dst->Param(arr, array()),
+                              },
+                              matrix(),
+                              {
+                                  ctx.dst->Return(ctx.dst->Construct(matrix(), columns)),
+                              });
+                return name;
+            });
+            return ctx.dst->Call(fn, ctx.CloneWithoutTransform(expr));
+        }
+        return nullptr;
+    });
+
+    ctx.Clone();
 }
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/decompose_strided_matrix.h b/src/tint/transform/decompose_strided_matrix.h
index bcde5aa..40e9c3e 100644
--- a/src/tint/transform/decompose_strided_matrix.h
+++ b/src/tint/transform/decompose_strided_matrix.h
@@ -27,31 +27,27 @@
 ///
 /// @note Depends on the following transforms to have been run first:
 /// * SimplifyPointers
-class DecomposeStridedMatrix final
-    : public Castable<DecomposeStridedMatrix, Transform> {
- public:
-  /// Constructor
-  DecomposeStridedMatrix();
+class DecomposeStridedMatrix final : public Castable<DecomposeStridedMatrix, Transform> {
+  public:
+    /// Constructor
+    DecomposeStridedMatrix();
 
-  /// Destructor
-  ~DecomposeStridedMatrix() override;
+    /// Destructor
+    ~DecomposeStridedMatrix() override;
 
-  /// @param program the program to inspect
-  /// @param data optional extra transform-specific input data
-  /// @returns true if this transform should be run for the given program
-  bool ShouldRun(const Program* program,
-                 const DataMap& data = {}) const override;
+    /// @param program the program to inspect
+    /// @param data optional extra transform-specific input data
+    /// @returns true if this transform should be run for the given program
+    bool ShouldRun(const Program* program, const DataMap& data = {}) const override;
 
- protected:
-  /// Runs the transform using the CloneContext built for transforming a
-  /// program. Run() is responsible for calling Clone() on the CloneContext.
-  /// @param ctx the CloneContext primed with the input program and
-  /// ProgramBuilder
-  /// @param inputs optional extra transform-specific input data
-  /// @param outputs optional extra transform-specific output data
-  void Run(CloneContext& ctx,
-           const DataMap& inputs,
-           DataMap& outputs) const override;
+  protected:
+    /// Runs the transform using the CloneContext built for transforming a
+    /// program. Run() is responsible for calling Clone() on the CloneContext.
+    /// @param ctx the CloneContext primed with the input program and
+    /// ProgramBuilder
+    /// @param inputs optional extra transform-specific input data
+    /// @param outputs optional extra transform-specific output data
+    void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const override;
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/decompose_strided_matrix_test.cc b/src/tint/transform/decompose_strided_matrix_test.cc
index 7338999..23b30d5 100644
--- a/src/tint/transform/decompose_strided_matrix_test.cc
+++ b/src/tint/transform/decompose_strided_matrix_test.cc
@@ -24,72 +24,69 @@
 #include "src/tint/transform/test_helper.h"
 #include "src/tint/transform/unshadow.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::transform {
 namespace {
 
 using DecomposeStridedMatrixTest = TransformTest;
-using f32 = ProgramBuilder::f32;
 
 TEST_F(DecomposeStridedMatrixTest, ShouldRunEmptyModule) {
-  auto* src = R"()";
+    auto* src = R"()";
 
-  EXPECT_FALSE(ShouldRun<DecomposeStridedMatrix>(src));
+    EXPECT_FALSE(ShouldRun<DecomposeStridedMatrix>(src));
 }
 
 TEST_F(DecomposeStridedMatrixTest, ShouldRunNonStridedMatrox) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> m : mat3x2<f32>;
 )";
 
-  EXPECT_FALSE(ShouldRun<DecomposeStridedMatrix>(src));
+    EXPECT_FALSE(ShouldRun<DecomposeStridedMatrix>(src));
 }
 
 TEST_F(DecomposeStridedMatrixTest, Empty) {
-  auto* src = R"()";
-  auto* expect = src;
+    auto* src = R"()";
+    auto* expect = src;
 
-  auto got = Run<DecomposeStridedMatrix>(src);
+    auto got = Run<DecomposeStridedMatrix>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(DecomposeStridedMatrixTest, ReadUniformMatrix) {
-  // struct S {
-  //   @offset(16) @stride(32)
-  //   @internal(ignore_stride_attribute)
-  //   m : mat2x2<f32>,
-  // };
-  // @group(0) @binding(0) var<uniform> s : S;
-  //
-  // @stage(compute) @workgroup_size(1)
-  // fn f() {
-  //   let x : mat2x2<f32> = s.m;
-  // }
-  ProgramBuilder b;
-  auto* S = b.Structure(
-      "S",
-      {
-          b.Member(
-              "m", b.ty.mat2x2<f32>(),
-              {
-                  b.create<ast::StructMemberOffsetAttribute>(16),
-                  b.create<ast::StrideAttribute>(32),
-                  b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
-              }),
-      });
-  b.Global("s", b.ty.Of(S), ast::StorageClass::kUniform,
-           b.GroupAndBinding(0, 0));
-  b.Func(
-      "f", {}, b.ty.void_(),
-      {
-          b.Decl(b.Const("x", b.ty.mat2x2<f32>(), b.MemberAccessor("s", "m"))),
-      },
-      {
-          b.Stage(ast::PipelineStage::kCompute),
-          b.WorkgroupSize(1),
-      });
+    // struct S {
+    //   @offset(16) @stride(32)
+    //   @internal(ignore_stride_attribute)
+    //   m : mat2x2<f32>,
+    // };
+    // @group(0) @binding(0) var<uniform> s : S;
+    //
+    // @stage(compute) @workgroup_size(1)
+    // fn f() {
+    //   let x : mat2x2<f32> = s.m;
+    // }
+    ProgramBuilder b;
+    auto* S = b.Structure(
+        "S", {
+                 b.Member("m", b.ty.mat2x2<f32>(),
+                          {
+                              b.create<ast::StructMemberOffsetAttribute>(16),
+                              b.create<ast::StrideAttribute>(32),
+                              b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
+                          }),
+             });
+    b.Global("s", b.ty.Of(S), ast::StorageClass::kUniform, b.GroupAndBinding(0, 0));
+    b.Func("f", {}, b.ty.void_(),
+           {
+               b.Decl(b.Let("x", b.ty.mat2x2<f32>(), b.MemberAccessor("s", "m"))),
+           },
+           {
+               b.Stage(ast::PipelineStage::kCompute),
+               b.WorkgroupSize(1_i),
+           });
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   @size(16)
   padding : u32,
@@ -102,55 +99,51 @@
   return mat2x2<f32>(arr[0u], arr[1u]);
 }
 
-@stage(compute) @workgroup_size(1)
+@stage(compute) @workgroup_size(1i)
 fn f() {
   let x : mat2x2<f32> = arr_to_mat2x2_stride_32(s.m);
 }
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedMatrix>(
-      Program(std::move(b)));
+    auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedMatrix>(Program(std::move(b)));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(DecomposeStridedMatrixTest, ReadUniformColumn) {
-  // struct S {
-  //   @offset(16) @stride(32)
-  //   @internal(ignore_stride_attribute)
-  //   m : mat2x2<f32>,
-  // };
-  // @group(0) @binding(0) var<uniform> s : S;
-  //
-  // @stage(compute) @workgroup_size(1)
-  // fn f() {
-  //   let x : vec2<f32> = s.m[1];
-  // }
-  ProgramBuilder b;
-  auto* S = b.Structure(
-      "S",
-      {
-          b.Member(
-              "m", b.ty.mat2x2<f32>(),
-              {
-                  b.create<ast::StructMemberOffsetAttribute>(16),
-                  b.create<ast::StrideAttribute>(32),
-                  b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
-              }),
-      });
-  b.Global("s", b.ty.Of(S), ast::StorageClass::kUniform,
-           b.GroupAndBinding(0, 0));
-  b.Func("f", {}, b.ty.void_(),
-         {
-             b.Decl(b.Const("x", b.ty.vec2<f32>(),
-                            b.IndexAccessor(b.MemberAccessor("s", "m"), 1))),
-         },
-         {
-             b.Stage(ast::PipelineStage::kCompute),
-             b.WorkgroupSize(1),
-         });
+    // struct S {
+    //   @offset(16) @stride(32)
+    //   @internal(ignore_stride_attribute)
+    //   m : mat2x2<f32>,
+    // };
+    // @group(0) @binding(0) var<uniform> s : S;
+    //
+    // @stage(compute) @workgroup_size(1)
+    // fn f() {
+    //   let x : vec2<f32> = s.m[1];
+    // }
+    ProgramBuilder b;
+    auto* S = b.Structure(
+        "S", {
+                 b.Member("m", b.ty.mat2x2<f32>(),
+                          {
+                              b.create<ast::StructMemberOffsetAttribute>(16),
+                              b.create<ast::StrideAttribute>(32),
+                              b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
+                          }),
+             });
+    b.Global("s", b.ty.Of(S), ast::StorageClass::kUniform, b.GroupAndBinding(0, 0));
+    b.Func(
+        "f", {}, b.ty.void_(),
+        {
+            b.Decl(b.Let("x", b.ty.vec2<f32>(), b.IndexAccessor(b.MemberAccessor("s", "m"), 1_i))),
+        },
+        {
+            b.Stage(ast::PipelineStage::kCompute),
+            b.WorkgroupSize(1_i),
+        });
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   @size(16)
   padding : u32,
@@ -159,55 +152,50 @@
 
 @group(0) @binding(0) var<uniform> s : S;
 
-@stage(compute) @workgroup_size(1)
+@stage(compute) @workgroup_size(1i)
 fn f() {
-  let x : vec2<f32> = s.m[1];
+  let x : vec2<f32> = s.m[1i];
 }
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedMatrix>(
-      Program(std::move(b)));
+    auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedMatrix>(Program(std::move(b)));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(DecomposeStridedMatrixTest, ReadUniformMatrix_DefaultStride) {
-  // struct S {
-  //   @offset(16) @stride(8)
-  //   @internal(ignore_stride_attribute)
-  //   m : mat2x2<f32>,
-  // };
-  // @group(0) @binding(0) var<uniform> s : S;
-  //
-  // @stage(compute) @workgroup_size(1)
-  // fn f() {
-  //   let x : mat2x2<f32> = s.m;
-  // }
-  ProgramBuilder b;
-  auto* S = b.Structure(
-      "S",
-      {
-          b.Member(
-              "m", b.ty.mat2x2<f32>(),
-              {
-                  b.create<ast::StructMemberOffsetAttribute>(16),
-                  b.create<ast::StrideAttribute>(8),
-                  b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
-              }),
-      });
-  b.Global("s", b.ty.Of(S), ast::StorageClass::kUniform,
-           b.GroupAndBinding(0, 0));
-  b.Func(
-      "f", {}, b.ty.void_(),
-      {
-          b.Decl(b.Const("x", b.ty.mat2x2<f32>(), b.MemberAccessor("s", "m"))),
-      },
-      {
-          b.Stage(ast::PipelineStage::kCompute),
-          b.WorkgroupSize(1),
-      });
+    // struct S {
+    //   @offset(16) @stride(8)
+    //   @internal(ignore_stride_attribute)
+    //   m : mat2x2<f32>,
+    // };
+    // @group(0) @binding(0) var<uniform> s : S;
+    //
+    // @stage(compute) @workgroup_size(1)
+    // fn f() {
+    //   let x : mat2x2<f32> = s.m;
+    // }
+    ProgramBuilder b;
+    auto* S = b.Structure(
+        "S", {
+                 b.Member("m", b.ty.mat2x2<f32>(),
+                          {
+                              b.create<ast::StructMemberOffsetAttribute>(16),
+                              b.create<ast::StrideAttribute>(8),
+                              b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
+                          }),
+             });
+    b.Global("s", b.ty.Of(S), ast::StorageClass::kUniform, b.GroupAndBinding(0, 0));
+    b.Func("f", {}, b.ty.void_(),
+           {
+               b.Decl(b.Let("x", b.ty.mat2x2<f32>(), b.MemberAccessor("s", "m"))),
+           },
+           {
+               b.Stage(ast::PipelineStage::kCompute),
+               b.WorkgroupSize(1_i),
+           });
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   @size(16)
   padding : u32,
@@ -217,55 +205,51 @@
 
 @group(0) @binding(0) var<uniform> s : S;
 
-@stage(compute) @workgroup_size(1)
+@stage(compute) @workgroup_size(1i)
 fn f() {
   let x : mat2x2<f32> = s.m;
 }
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedMatrix>(
-      Program(std::move(b)));
+    auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedMatrix>(Program(std::move(b)));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(DecomposeStridedMatrixTest, ReadStorageMatrix) {
-  // struct S {
-  //   @offset(8) @stride(32)
-  //   @internal(ignore_stride_attribute)
-  //   m : mat2x2<f32>,
-  // };
-  // @group(0) @binding(0) var<storage, read_write> s : S;
-  //
-  // @stage(compute) @workgroup_size(1)
-  // fn f() {
-  //   let x : mat2x2<f32> = s.m;
-  // }
-  ProgramBuilder b;
-  auto* S = b.Structure(
-      "S",
-      {
-          b.Member(
-              "m", b.ty.mat2x2<f32>(),
-              {
-                  b.create<ast::StructMemberOffsetAttribute>(8),
-                  b.create<ast::StrideAttribute>(32),
-                  b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
-              }),
-      });
-  b.Global("s", b.ty.Of(S), ast::StorageClass::kStorage,
-           ast::Access::kReadWrite, b.GroupAndBinding(0, 0));
-  b.Func(
-      "f", {}, b.ty.void_(),
-      {
-          b.Decl(b.Const("x", b.ty.mat2x2<f32>(), b.MemberAccessor("s", "m"))),
-      },
-      {
-          b.Stage(ast::PipelineStage::kCompute),
-          b.WorkgroupSize(1),
-      });
+    // struct S {
+    //   @offset(8) @stride(32)
+    //   @internal(ignore_stride_attribute)
+    //   m : mat2x2<f32>,
+    // };
+    // @group(0) @binding(0) var<storage, read_write> s : S;
+    //
+    // @stage(compute) @workgroup_size(1)
+    // fn f() {
+    //   let x : mat2x2<f32> = s.m;
+    // }
+    ProgramBuilder b;
+    auto* S = b.Structure(
+        "S", {
+                 b.Member("m", b.ty.mat2x2<f32>(),
+                          {
+                              b.create<ast::StructMemberOffsetAttribute>(8),
+                              b.create<ast::StrideAttribute>(32),
+                              b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
+                          }),
+             });
+    b.Global("s", b.ty.Of(S), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+             b.GroupAndBinding(0, 0));
+    b.Func("f", {}, b.ty.void_(),
+           {
+               b.Decl(b.Let("x", b.ty.mat2x2<f32>(), b.MemberAccessor("s", "m"))),
+           },
+           {
+               b.Stage(ast::PipelineStage::kCompute),
+               b.WorkgroupSize(1_i),
+           });
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   @size(8)
   padding : u32,
@@ -278,55 +262,52 @@
   return mat2x2<f32>(arr[0u], arr[1u]);
 }
 
-@stage(compute) @workgroup_size(1)
+@stage(compute) @workgroup_size(1i)
 fn f() {
   let x : mat2x2<f32> = arr_to_mat2x2_stride_32(s.m);
 }
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedMatrix>(
-      Program(std::move(b)));
+    auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedMatrix>(Program(std::move(b)));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(DecomposeStridedMatrixTest, ReadStorageColumn) {
-  // struct S {
-  //   @offset(16) @stride(32)
-  //   @internal(ignore_stride_attribute)
-  //   m : mat2x2<f32>,
-  // };
-  // @group(0) @binding(0) var<storage, read_write> s : S;
-  //
-  // @stage(compute) @workgroup_size(1)
-  // fn f() {
-  //   let x : vec2<f32> = s.m[1];
-  // }
-  ProgramBuilder b;
-  auto* S = b.Structure(
-      "S",
-      {
-          b.Member(
-              "m", b.ty.mat2x2<f32>(),
-              {
-                  b.create<ast::StructMemberOffsetAttribute>(16),
-                  b.create<ast::StrideAttribute>(32),
-                  b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
-              }),
-      });
-  b.Global("s", b.ty.Of(S), ast::StorageClass::kStorage,
-           ast::Access::kReadWrite, b.GroupAndBinding(0, 0));
-  b.Func("f", {}, b.ty.void_(),
-         {
-             b.Decl(b.Const("x", b.ty.vec2<f32>(),
-                            b.IndexAccessor(b.MemberAccessor("s", "m"), 1))),
-         },
-         {
-             b.Stage(ast::PipelineStage::kCompute),
-             b.WorkgroupSize(1),
-         });
+    // struct S {
+    //   @offset(16) @stride(32)
+    //   @internal(ignore_stride_attribute)
+    //   m : mat2x2<f32>,
+    // };
+    // @group(0) @binding(0) var<storage, read_write> s : S;
+    //
+    // @stage(compute) @workgroup_size(1)
+    // fn f() {
+    //   let x : vec2<f32> = s.m[1];
+    // }
+    ProgramBuilder b;
+    auto* S = b.Structure(
+        "S", {
+                 b.Member("m", b.ty.mat2x2<f32>(),
+                          {
+                              b.create<ast::StructMemberOffsetAttribute>(16),
+                              b.create<ast::StrideAttribute>(32),
+                              b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
+                          }),
+             });
+    b.Global("s", b.ty.Of(S), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+             b.GroupAndBinding(0, 0));
+    b.Func(
+        "f", {}, b.ty.void_(),
+        {
+            b.Decl(b.Let("x", b.ty.vec2<f32>(), b.IndexAccessor(b.MemberAccessor("s", "m"), 1_i))),
+        },
+        {
+            b.Stage(ast::PipelineStage::kCompute),
+            b.WorkgroupSize(1_i),
+        });
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   @size(16)
   padding : u32,
@@ -335,56 +316,52 @@
 
 @group(0) @binding(0) var<storage, read_write> s : S;
 
-@stage(compute) @workgroup_size(1)
+@stage(compute) @workgroup_size(1i)
 fn f() {
-  let x : vec2<f32> = s.m[1];
+  let x : vec2<f32> = s.m[1i];
 }
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedMatrix>(
-      Program(std::move(b)));
+    auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedMatrix>(Program(std::move(b)));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(DecomposeStridedMatrixTest, WriteStorageMatrix) {
-  // struct S {
-  //   @offset(8) @stride(32)
-  //   @internal(ignore_stride_attribute)
-  //   m : mat2x2<f32>,
-  // };
-  // @group(0) @binding(0) var<storage, read_write> s : S;
-  //
-  // @stage(compute) @workgroup_size(1)
-  // fn f() {
-  //   s.m = mat2x2<f32>(vec2<f32>(1.0, 2.0), vec2<f32>(3.0, 4.0));
-  // }
-  ProgramBuilder b;
-  auto* S = b.Structure(
-      "S",
-      {
-          b.Member(
-              "m", b.ty.mat2x2<f32>(),
-              {
-                  b.create<ast::StructMemberOffsetAttribute>(8),
-                  b.create<ast::StrideAttribute>(32),
-                  b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
-              }),
-      });
-  b.Global("s", b.ty.Of(S), ast::StorageClass::kStorage,
-           ast::Access::kReadWrite, b.GroupAndBinding(0, 0));
-  b.Func("f", {}, b.ty.void_(),
-         {
-             b.Assign(b.MemberAccessor("s", "m"),
-                      b.mat2x2<f32>(b.vec2<f32>(1.0f, 2.0f),
-                                    b.vec2<f32>(3.0f, 4.0f))),
-         },
-         {
-             b.Stage(ast::PipelineStage::kCompute),
-             b.WorkgroupSize(1),
-         });
+    // struct S {
+    //   @offset(8) @stride(32)
+    //   @internal(ignore_stride_attribute)
+    //   m : mat2x2<f32>,
+    // };
+    // @group(0) @binding(0) var<storage, read_write> s : S;
+    //
+    // @stage(compute) @workgroup_size(1)
+    // fn f() {
+    //   s.m = mat2x2<f32>(vec2<f32>(1.0, 2.0), vec2<f32>(3.0, 4.0));
+    // }
+    ProgramBuilder b;
+    auto* S = b.Structure(
+        "S", {
+                 b.Member("m", b.ty.mat2x2<f32>(),
+                          {
+                              b.create<ast::StructMemberOffsetAttribute>(8),
+                              b.create<ast::StrideAttribute>(32),
+                              b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
+                          }),
+             });
+    b.Global("s", b.ty.Of(S), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+             b.GroupAndBinding(0, 0));
+    b.Func("f", {}, b.ty.void_(),
+           {
+               b.Assign(b.MemberAccessor("s", "m"),
+                        b.mat2x2<f32>(b.vec2<f32>(1.0f, 2.0f), b.vec2<f32>(3.0f, 4.0f))),
+           },
+           {
+               b.Stage(ast::PipelineStage::kCompute),
+               b.WorkgroupSize(1_i),
+           });
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   @size(8)
   padding : u32,
@@ -397,55 +374,51 @@
   return @stride(32) array<vec2<f32>, 2u>(m[0u], m[1u]);
 }
 
-@stage(compute) @workgroup_size(1)
+@stage(compute) @workgroup_size(1i)
 fn f() {
   s.m = mat2x2_stride_32_to_arr(mat2x2<f32>(vec2<f32>(1.0, 2.0), vec2<f32>(3.0, 4.0)));
 }
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedMatrix>(
-      Program(std::move(b)));
+    auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedMatrix>(Program(std::move(b)));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(DecomposeStridedMatrixTest, WriteStorageColumn) {
-  // struct S {
-  //   @offset(8) @stride(32)
-  //   @internal(ignore_stride_attribute)
-  //   m : mat2x2<f32>,
-  // };
-  // @group(0) @binding(0) var<storage, read_write> s : S;
-  //
-  // @stage(compute) @workgroup_size(1)
-  // fn f() {
-  //   s.m[1] = vec2<f32>(1.0, 2.0);
-  // }
-  ProgramBuilder b;
-  auto* S = b.Structure(
-      "S",
-      {
-          b.Member(
-              "m", b.ty.mat2x2<f32>(),
-              {
-                  b.create<ast::StructMemberOffsetAttribute>(8),
-                  b.create<ast::StrideAttribute>(32),
-                  b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
-              }),
-      });
-  b.Global("s", b.ty.Of(S), ast::StorageClass::kStorage,
-           ast::Access::kReadWrite, b.GroupAndBinding(0, 0));
-  b.Func("f", {}, b.ty.void_(),
-         {
-             b.Assign(b.IndexAccessor(b.MemberAccessor("s", "m"), 1),
-                      b.vec2<f32>(1.0f, 2.0f)),
-         },
-         {
-             b.Stage(ast::PipelineStage::kCompute),
-             b.WorkgroupSize(1),
-         });
+    // struct S {
+    //   @offset(8) @stride(32)
+    //   @internal(ignore_stride_attribute)
+    //   m : mat2x2<f32>,
+    // };
+    // @group(0) @binding(0) var<storage, read_write> s : S;
+    //
+    // @stage(compute) @workgroup_size(1)
+    // fn f() {
+    //   s.m[1] = vec2<f32>(1.0, 2.0);
+    // }
+    ProgramBuilder b;
+    auto* S = b.Structure(
+        "S", {
+                 b.Member("m", b.ty.mat2x2<f32>(),
+                          {
+                              b.create<ast::StructMemberOffsetAttribute>(8),
+                              b.create<ast::StrideAttribute>(32),
+                              b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
+                          }),
+             });
+    b.Global("s", b.ty.Of(S), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+             b.GroupAndBinding(0, 0));
+    b.Func("f", {}, b.ty.void_(),
+           {
+               b.Assign(b.IndexAccessor(b.MemberAccessor("s", "m"), 1_i), b.vec2<f32>(1.0f, 2.0f)),
+           },
+           {
+               b.Stage(ast::PipelineStage::kCompute),
+               b.WorkgroupSize(1_i),
+           });
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   @size(8)
   padding : u32,
@@ -454,70 +427,64 @@
 
 @group(0) @binding(0) var<storage, read_write> s : S;
 
-@stage(compute) @workgroup_size(1)
+@stage(compute) @workgroup_size(1i)
 fn f() {
-  s.m[1] = vec2<f32>(1.0, 2.0);
+  s.m[1i] = vec2<f32>(1.0, 2.0);
 }
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedMatrix>(
-      Program(std::move(b)));
+    auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedMatrix>(Program(std::move(b)));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(DecomposeStridedMatrixTest, ReadWriteViaPointerLets) {
-  // struct S {
-  //   @offset(8) @stride(32)
-  //   @internal(ignore_stride_attribute)
-  //   m : mat2x2<f32>,
-  // };
-  // @group(0) @binding(0) var<storage, read_write> s : S;
-  //
-  // @stage(compute) @workgroup_size(1)
-  // fn f() {
-  //   let a = &s.m;
-  //   let b = &*&*(a);
-  //   let x = *b;
-  //   let y = (*b)[1];
-  //   let z = x[1];
-  //   (*b) = mat2x2<f32>(vec2<f32>(1.0, 2.0), vec2<f32>(3.0, 4.0));
-  //   (*b)[1] = vec2<f32>(5.0, 6.0);
-  // }
-  ProgramBuilder b;
-  auto* S = b.Structure(
-      "S",
-      {
-          b.Member(
-              "m", b.ty.mat2x2<f32>(),
-              {
-                  b.create<ast::StructMemberOffsetAttribute>(8),
-                  b.create<ast::StrideAttribute>(32),
-                  b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
-              }),
-      });
-  b.Global("s", b.ty.Of(S), ast::StorageClass::kStorage,
-           ast::Access::kReadWrite, b.GroupAndBinding(0, 0));
-  b.Func(
-      "f", {}, b.ty.void_(),
-      {
-          b.Decl(
-              b.Const("a", nullptr, b.AddressOf(b.MemberAccessor("s", "m")))),
-          b.Decl(b.Const("b", nullptr,
-                         b.AddressOf(b.Deref(b.AddressOf(b.Deref("a")))))),
-          b.Decl(b.Const("x", nullptr, b.Deref("b"))),
-          b.Decl(b.Const("y", nullptr, b.IndexAccessor(b.Deref("b"), 1))),
-          b.Decl(b.Const("z", nullptr, b.IndexAccessor("x", 1))),
-          b.Assign(b.Deref("b"), b.mat2x2<f32>(b.vec2<f32>(1.0f, 2.0f),
-                                               b.vec2<f32>(3.0f, 4.0f))),
-          b.Assign(b.IndexAccessor(b.Deref("b"), 1), b.vec2<f32>(5.0f, 6.0f)),
-      },
-      {
-          b.Stage(ast::PipelineStage::kCompute),
-          b.WorkgroupSize(1),
-      });
+    // struct S {
+    //   @offset(8) @stride(32)
+    //   @internal(ignore_stride_attribute)
+    //   m : mat2x2<f32>,
+    // };
+    // @group(0) @binding(0) var<storage, read_write> s : S;
+    //
+    // @stage(compute) @workgroup_size(1)
+    // fn f() {
+    //   let a = &s.m;
+    //   let b = &*&*(a);
+    //   let x = *b;
+    //   let y = (*b)[1];
+    //   let z = x[1];
+    //   (*b) = mat2x2<f32>(vec2<f32>(1.0, 2.0), vec2<f32>(3.0, 4.0));
+    //   (*b)[1] = vec2<f32>(5.0, 6.0);
+    // }
+    ProgramBuilder b;
+    auto* S = b.Structure(
+        "S", {
+                 b.Member("m", b.ty.mat2x2<f32>(),
+                          {
+                              b.create<ast::StructMemberOffsetAttribute>(8),
+                              b.create<ast::StrideAttribute>(32),
+                              b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
+                          }),
+             });
+    b.Global("s", b.ty.Of(S), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+             b.GroupAndBinding(0, 0));
+    b.Func(
+        "f", {}, b.ty.void_(),
+        {
+            b.Decl(b.Let("a", nullptr, b.AddressOf(b.MemberAccessor("s", "m")))),
+            b.Decl(b.Let("b", nullptr, b.AddressOf(b.Deref(b.AddressOf(b.Deref("a")))))),
+            b.Decl(b.Let("x", nullptr, b.Deref("b"))),
+            b.Decl(b.Let("y", nullptr, b.IndexAccessor(b.Deref("b"), 1_i))),
+            b.Decl(b.Let("z", nullptr, b.IndexAccessor("x", 1_i))),
+            b.Assign(b.Deref("b"), b.mat2x2<f32>(b.vec2<f32>(1.0f, 2.0f), b.vec2<f32>(3.0f, 4.0f))),
+            b.Assign(b.IndexAccessor(b.Deref("b"), 1_i), b.vec2<f32>(5.0f, 6.0f)),
+        },
+        {
+            b.Stage(ast::PipelineStage::kCompute),
+            b.WorkgroupSize(1_i),
+        });
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   @size(8)
   padding : u32,
@@ -534,58 +501,54 @@
   return @stride(32) array<vec2<f32>, 2u>(m[0u], m[1u]);
 }
 
-@stage(compute) @workgroup_size(1)
+@stage(compute) @workgroup_size(1i)
 fn f() {
   let x = arr_to_mat2x2_stride_32(s.m);
-  let y = s.m[1];
-  let z = x[1];
+  let y = s.m[1i];
+  let z = x[1i];
   s.m = mat2x2_stride_32_to_arr(mat2x2<f32>(vec2<f32>(1.0, 2.0), vec2<f32>(3.0, 4.0)));
-  s.m[1] = vec2<f32>(5.0, 6.0);
+  s.m[1i] = vec2<f32>(5.0, 6.0);
 }
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedMatrix>(
-      Program(std::move(b)));
+    auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedMatrix>(Program(std::move(b)));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(DecomposeStridedMatrixTest, ReadPrivateMatrix) {
-  // struct S {
-  //   @offset(8) @stride(32)
-  //   @internal(ignore_stride_attribute)
-  //   m : mat2x2<f32>,
-  // };
-  // var<private> s : S;
-  //
-  // @stage(compute) @workgroup_size(1)
-  // fn f() {
-  //   let x : mat2x2<f32> = s.m;
-  // }
-  ProgramBuilder b;
-  auto* S = b.Structure(
-      "S",
-      {
-          b.Member(
-              "m", b.ty.mat2x2<f32>(),
-              {
-                  b.create<ast::StructMemberOffsetAttribute>(8),
-                  b.create<ast::StrideAttribute>(32),
-                  b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
-              }),
-      });
-  b.Global("s", b.ty.Of(S), ast::StorageClass::kPrivate);
-  b.Func(
-      "f", {}, b.ty.void_(),
-      {
-          b.Decl(b.Const("x", b.ty.mat2x2<f32>(), b.MemberAccessor("s", "m"))),
-      },
-      {
-          b.Stage(ast::PipelineStage::kCompute),
-          b.WorkgroupSize(1),
-      });
+    // struct S {
+    //   @offset(8) @stride(32)
+    //   @internal(ignore_stride_attribute)
+    //   m : mat2x2<f32>,
+    // };
+    // var<private> s : S;
+    //
+    // @stage(compute) @workgroup_size(1)
+    // fn f() {
+    //   let x : mat2x2<f32> = s.m;
+    // }
+    ProgramBuilder b;
+    auto* S = b.Structure(
+        "S", {
+                 b.Member("m", b.ty.mat2x2<f32>(),
+                          {
+                              b.create<ast::StructMemberOffsetAttribute>(8),
+                              b.create<ast::StrideAttribute>(32),
+                              b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
+                          }),
+             });
+    b.Global("s", b.ty.Of(S), ast::StorageClass::kPrivate);
+    b.Func("f", {}, b.ty.void_(),
+           {
+               b.Decl(b.Let("x", b.ty.mat2x2<f32>(), b.MemberAccessor("s", "m"))),
+           },
+           {
+               b.Stage(ast::PipelineStage::kCompute),
+               b.WorkgroupSize(1_i),
+           });
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   @size(8)
   padding : u32,
@@ -595,55 +558,51 @@
 
 var<private> s : S;
 
-@stage(compute) @workgroup_size(1)
+@stage(compute) @workgroup_size(1i)
 fn f() {
   let x : mat2x2<f32> = s.m;
 }
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedMatrix>(
-      Program(std::move(b)));
+    auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedMatrix>(Program(std::move(b)));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(DecomposeStridedMatrixTest, WritePrivateMatrix) {
-  // struct S {
-  //   @offset(8) @stride(32)
-  //   @internal(ignore_stride_attribute)
-  //   m : mat2x2<f32>,
-  // };
-  // var<private> s : S;
-  //
-  // @stage(compute) @workgroup_size(1)
-  // fn f() {
-  //   s.m = mat2x2<f32>(vec2<f32>(1.0, 2.0), vec2<f32>(3.0, 4.0));
-  // }
-  ProgramBuilder b;
-  auto* S = b.Structure(
-      "S",
-      {
-          b.Member(
-              "m", b.ty.mat2x2<f32>(),
-              {
-                  b.create<ast::StructMemberOffsetAttribute>(8),
-                  b.create<ast::StrideAttribute>(32),
-                  b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
-              }),
-      });
-  b.Global("s", b.ty.Of(S), ast::StorageClass::kPrivate);
-  b.Func("f", {}, b.ty.void_(),
-         {
-             b.Assign(b.MemberAccessor("s", "m"),
-                      b.mat2x2<f32>(b.vec2<f32>(1.0f, 2.0f),
-                                    b.vec2<f32>(3.0f, 4.0f))),
-         },
-         {
-             b.Stage(ast::PipelineStage::kCompute),
-             b.WorkgroupSize(1),
-         });
+    // struct S {
+    //   @offset(8) @stride(32)
+    //   @internal(ignore_stride_attribute)
+    //   m : mat2x2<f32>,
+    // };
+    // var<private> s : S;
+    //
+    // @stage(compute) @workgroup_size(1)
+    // fn f() {
+    //   s.m = mat2x2<f32>(vec2<f32>(1.0, 2.0), vec2<f32>(3.0, 4.0));
+    // }
+    ProgramBuilder b;
+    auto* S = b.Structure(
+        "S", {
+                 b.Member("m", b.ty.mat2x2<f32>(),
+                          {
+                              b.create<ast::StructMemberOffsetAttribute>(8),
+                              b.create<ast::StrideAttribute>(32),
+                              b.Disable(ast::DisabledValidation::kIgnoreStrideAttribute),
+                          }),
+             });
+    b.Global("s", b.ty.Of(S), ast::StorageClass::kPrivate);
+    b.Func("f", {}, b.ty.void_(),
+           {
+               b.Assign(b.MemberAccessor("s", "m"),
+                        b.mat2x2<f32>(b.vec2<f32>(1.0f, 2.0f), b.vec2<f32>(3.0f, 4.0f))),
+           },
+           {
+               b.Stage(ast::PipelineStage::kCompute),
+               b.WorkgroupSize(1_i),
+           });
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   @size(8)
   padding : u32,
@@ -653,16 +612,15 @@
 
 var<private> s : S;
 
-@stage(compute) @workgroup_size(1)
+@stage(compute) @workgroup_size(1i)
 fn f() {
   s.m = mat2x2<f32>(vec2<f32>(1.0, 2.0), vec2<f32>(3.0, 4.0));
 }
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedMatrix>(
-      Program(std::move(b)));
+    auto got = Run<Unshadow, SimplifyPointers, DecomposeStridedMatrix>(Program(std::move(b)));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 }  // namespace
diff --git a/src/tint/transform/expand_compound_assignment.cc b/src/tint/transform/expand_compound_assignment.cc
index 0473fae..2f775ca 100644
--- a/src/tint/transform/expand_compound_assignment.cc
+++ b/src/tint/transform/expand_compound_assignment.cc
@@ -27,168 +27,160 @@
 
 TINT_INSTANTIATE_TYPEINFO(tint::transform::ExpandCompoundAssignment);
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::transform {
 
 ExpandCompoundAssignment::ExpandCompoundAssignment() = default;
 
 ExpandCompoundAssignment::~ExpandCompoundAssignment() = default;
 
-bool ExpandCompoundAssignment::ShouldRun(const Program* program,
-                                         const DataMap&) const {
-  for (auto* node : program->ASTNodes().Objects()) {
-    if (node->IsAnyOf<ast::CompoundAssignmentStatement,
-                      ast::IncrementDecrementStatement>()) {
-      return true;
+bool ExpandCompoundAssignment::ShouldRun(const Program* program, const DataMap&) const {
+    for (auto* node : program->ASTNodes().Objects()) {
+        if (node->IsAnyOf<ast::CompoundAssignmentStatement, ast::IncrementDecrementStatement>()) {
+            return true;
+        }
     }
-  }
-  return false;
+    return false;
 }
 
 /// Internal class used to collect statement expansions during the transform.
 class State {
- private:
-  /// The clone context.
-  CloneContext& ctx;
+  private:
+    /// The clone context.
+    CloneContext& ctx;
 
-  /// The program builder.
-  ProgramBuilder& b;
+    /// The program builder.
+    ProgramBuilder& b;
 
-  /// The HoistToDeclBefore helper instance.
-  HoistToDeclBefore hoist_to_decl_before;
+    /// The HoistToDeclBefore helper instance.
+    HoistToDeclBefore hoist_to_decl_before;
 
- public:
-  /// Constructor
-  /// @param context the clone context
-  explicit State(CloneContext& context)
-      : ctx(context), b(*ctx.dst), hoist_to_decl_before(ctx) {}
+  public:
+    /// Constructor
+    /// @param context the clone context
+    explicit State(CloneContext& context) : ctx(context), b(*ctx.dst), hoist_to_decl_before(ctx) {}
 
-  /// Replace `stmt` with a regular assignment statement of the form:
-  ///     lhs = lhs op rhs
-  /// The LHS expression will only be evaluated once, and any side effects will
-  /// be hoisted to `let` declarations above the assignment statement.
-  /// @param stmt the statement to replace
-  /// @param lhs the lhs expression from the source statement
-  /// @param rhs the rhs expression in the destination module
-  /// @param op the binary operator
-  void Expand(const ast::Statement* stmt,
-              const ast::Expression* lhs,
-              const ast::Expression* rhs,
-              ast::BinaryOp op) {
-    // Helper function to create the new LHS expression. This will be called
-    // twice when building the non-compound assignment statement, so must
-    // not produce expressions that cause side effects.
-    std::function<const ast::Expression*()> new_lhs;
+    /// Replace `stmt` with a regular assignment statement of the form:
+    ///     lhs = lhs op rhs
+    /// The LHS expression will only be evaluated once, and any side effects will
+    /// be hoisted to `let` declarations above the assignment statement.
+    /// @param stmt the statement to replace
+    /// @param lhs the lhs expression from the source statement
+    /// @param rhs the rhs expression in the destination module
+    /// @param op the binary operator
+    void Expand(const ast::Statement* stmt,
+                const ast::Expression* lhs,
+                const ast::Expression* rhs,
+                ast::BinaryOp op) {
+        // Helper function to create the new LHS expression. This will be called
+        // twice when building the non-compound assignment statement, so must
+        // not produce expressions that cause side effects.
+        std::function<const ast::Expression*()> new_lhs;
 
-    // Helper function to create a variable that is a pointer to `expr`.
-    auto hoist_pointer_to = [&](const ast::Expression* expr) {
-      auto name = b.Sym();
-      auto* ptr = b.AddressOf(ctx.Clone(expr));
-      auto* decl = b.Decl(b.Const(name, nullptr, ptr));
-      hoist_to_decl_before.InsertBefore(ctx.src->Sem().Get(stmt), decl);
-      return name;
-    };
+        // Helper function to create a variable that is a pointer to `expr`.
+        auto hoist_pointer_to = [&](const ast::Expression* expr) {
+            auto name = b.Sym();
+            auto* ptr = b.AddressOf(ctx.Clone(expr));
+            auto* decl = b.Decl(b.Let(name, nullptr, ptr));
+            hoist_to_decl_before.InsertBefore(ctx.src->Sem().Get(stmt), decl);
+            return name;
+        };
 
-    // Helper function to hoist `expr` to a let declaration.
-    auto hoist_expr_to_let = [&](const ast::Expression* expr) {
-      auto name = b.Sym();
-      auto* decl = b.Decl(b.Const(name, nullptr, ctx.Clone(expr)));
-      hoist_to_decl_before.InsertBefore(ctx.src->Sem().Get(stmt), decl);
-      return name;
-    };
+        // Helper function to hoist `expr` to a let declaration.
+        auto hoist_expr_to_let = [&](const ast::Expression* expr) {
+            auto name = b.Sym();
+            auto* decl = b.Decl(b.Let(name, nullptr, ctx.Clone(expr)));
+            hoist_to_decl_before.InsertBefore(ctx.src->Sem().Get(stmt), decl);
+            return name;
+        };
 
-    // Helper function that returns `true` if the type of `expr` is a vector.
-    auto is_vec = [&](const ast::Expression* expr) {
-      return ctx.src->Sem().Get(expr)->Type()->UnwrapRef()->Is<sem::Vector>();
-    };
+        // Helper function that returns `true` if the type of `expr` is a vector.
+        auto is_vec = [&](const ast::Expression* expr) {
+            return ctx.src->Sem().Get(expr)->Type()->UnwrapRef()->Is<sem::Vector>();
+        };
 
-    // Hoist the LHS expression subtree into local constants to produce a new
-    // LHS that we can evaluate twice.
-    // We need to special case compound assignments to vector components since
-    // we cannot take the address of a vector component.
-    auto* index_accessor = lhs->As<ast::IndexAccessorExpression>();
-    auto* member_accessor = lhs->As<ast::MemberAccessorExpression>();
-    if (lhs->Is<ast::IdentifierExpression>() ||
-        (member_accessor &&
-         member_accessor->structure->Is<ast::IdentifierExpression>())) {
-      // This is the simple case with no side effects, so we can just use the
-      // original LHS expression directly.
-      // Before:
-      //     foo.bar += rhs;
-      // After:
-      //     foo.bar = foo.bar + rhs;
-      new_lhs = [&]() { return ctx.Clone(lhs); };
-    } else if (index_accessor && is_vec(index_accessor->object)) {
-      // This is the case for vector component via an array accessor. We need
-      // to capture a pointer to the vector and also the index value.
-      // Before:
-      //     v[idx()] += rhs;
-      // After:
-      //     let vec_ptr = &v;
-      //     let index = idx();
-      //     (*vec_ptr)[index] = (*vec_ptr)[index] + rhs;
-      auto lhs_ptr = hoist_pointer_to(index_accessor->object);
-      auto index = hoist_expr_to_let(index_accessor->index);
-      new_lhs = [&, lhs_ptr, index]() {
-        return b.IndexAccessor(b.Deref(lhs_ptr), index);
-      };
-    } else if (member_accessor && is_vec(member_accessor->structure)) {
-      // This is the case for vector component via a member accessor. We just
-      // need to capture a pointer to the vector.
-      // Before:
-      //     a[idx()].y += rhs;
-      // After:
-      //     let vec_ptr = &a[idx()];
-      //     (*vec_ptr).y = (*vec_ptr).y + rhs;
-      auto lhs_ptr = hoist_pointer_to(member_accessor->structure);
-      new_lhs = [&, lhs_ptr]() {
-        return b.MemberAccessor(b.Deref(lhs_ptr),
-                                ctx.Clone(member_accessor->member));
-      };
-    } else {
-      // For all other statements that may have side-effecting expressions, we
-      // just need to capture a pointer to the whole LHS.
-      // Before:
-      //     a[idx()] += rhs;
-      // After:
-      //     let lhs_ptr = &a[idx()];
-      //     (*lhs_ptr) = (*lhs_ptr) + rhs;
-      auto lhs_ptr = hoist_pointer_to(lhs);
-      new_lhs = [&, lhs_ptr]() { return b.Deref(lhs_ptr); };
+        // Hoist the LHS expression subtree into local constants to produce a new
+        // LHS that we can evaluate twice.
+        // We need to special case compound assignments to vector components since
+        // we cannot take the address of a vector component.
+        auto* index_accessor = lhs->As<ast::IndexAccessorExpression>();
+        auto* member_accessor = lhs->As<ast::MemberAccessorExpression>();
+        if (lhs->Is<ast::IdentifierExpression>() ||
+            (member_accessor && member_accessor->structure->Is<ast::IdentifierExpression>())) {
+            // This is the simple case with no side effects, so we can just use the
+            // original LHS expression directly.
+            // Before:
+            //     foo.bar += rhs;
+            // After:
+            //     foo.bar = foo.bar + rhs;
+            new_lhs = [&]() { return ctx.Clone(lhs); };
+        } else if (index_accessor && is_vec(index_accessor->object)) {
+            // This is the case for vector component via an array accessor. We need
+            // to capture a pointer to the vector and also the index value.
+            // Before:
+            //     v[idx()] += rhs;
+            // After:
+            //     let vec_ptr = &v;
+            //     let index = idx();
+            //     (*vec_ptr)[index] = (*vec_ptr)[index] + rhs;
+            auto lhs_ptr = hoist_pointer_to(index_accessor->object);
+            auto index = hoist_expr_to_let(index_accessor->index);
+            new_lhs = [&, lhs_ptr, index]() { return b.IndexAccessor(b.Deref(lhs_ptr), index); };
+        } else if (member_accessor && is_vec(member_accessor->structure)) {
+            // This is the case for vector component via a member accessor. We just
+            // need to capture a pointer to the vector.
+            // Before:
+            //     a[idx()].y += rhs;
+            // After:
+            //     let vec_ptr = &a[idx()];
+            //     (*vec_ptr).y = (*vec_ptr).y + rhs;
+            auto lhs_ptr = hoist_pointer_to(member_accessor->structure);
+            new_lhs = [&, lhs_ptr]() {
+                return b.MemberAccessor(b.Deref(lhs_ptr), ctx.Clone(member_accessor->member));
+            };
+        } else {
+            // For all other statements that may have side-effecting expressions, we
+            // just need to capture a pointer to the whole LHS.
+            // Before:
+            //     a[idx()] += rhs;
+            // After:
+            //     let lhs_ptr = &a[idx()];
+            //     (*lhs_ptr) = (*lhs_ptr) + rhs;
+            auto lhs_ptr = hoist_pointer_to(lhs);
+            new_lhs = [&, lhs_ptr]() { return b.Deref(lhs_ptr); };
+        }
+
+        // Replace the statement with a regular assignment statement.
+        auto* value = b.create<ast::BinaryExpression>(op, new_lhs(), rhs);
+        ctx.Replace(stmt, b.Assign(new_lhs(), value));
     }
 
-    // Replace the statement with a regular assignment statement.
-    auto* value = b.create<ast::BinaryExpression>(op, new_lhs(), rhs);
-    ctx.Replace(stmt, b.Assign(new_lhs(), value));
-  }
-
-  /// Finalize the transformation and clone the module.
-  void Finalize() {
-    hoist_to_decl_before.Apply();
-    ctx.Clone();
-  }
+    /// Finalize the transformation and clone the module.
+    void Finalize() {
+        hoist_to_decl_before.Apply();
+        ctx.Clone();
+    }
 };
 
-void ExpandCompoundAssignment::Run(CloneContext& ctx,
-                                   const DataMap&,
-                                   DataMap&) const {
-  State state(ctx);
-  for (auto* node : ctx.src->ASTNodes().Objects()) {
-    if (auto* assign = node->As<ast::CompoundAssignmentStatement>()) {
-      state.Expand(assign, assign->lhs, ctx.Clone(assign->rhs), assign->op);
-    } else if (auto* inc_dec = node->As<ast::IncrementDecrementStatement>()) {
-      // For increment/decrement statements, `i++` becomes `i = i + 1`.
-      // TODO(jrprice): Simplify this when we have untyped literals.
-      auto* sem_lhs = ctx.src->Sem().Get(inc_dec->lhs);
-      const ast::IntLiteralExpression* one =
-          sem_lhs->Type()->UnwrapRef()->is_signed_integer_scalar()
-              ? ctx.dst->Expr(1)->As<ast::IntLiteralExpression>()
-              : ctx.dst->Expr(1u)->As<ast::IntLiteralExpression>();
-      auto op =
-          inc_dec->increment ? ast::BinaryOp::kAdd : ast::BinaryOp::kSubtract;
-      state.Expand(inc_dec, inc_dec->lhs, one, op);
+void ExpandCompoundAssignment::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
+    State state(ctx);
+    for (auto* node : ctx.src->ASTNodes().Objects()) {
+        if (auto* assign = node->As<ast::CompoundAssignmentStatement>()) {
+            state.Expand(assign, assign->lhs, ctx.Clone(assign->rhs), assign->op);
+        } else if (auto* inc_dec = node->As<ast::IncrementDecrementStatement>()) {
+            // For increment/decrement statements, `i++` becomes `i = i + 1`.
+            // TODO(jrprice): Simplify this when we have untyped literals.
+            auto* sem_lhs = ctx.src->Sem().Get(inc_dec->lhs);
+            const ast::IntLiteralExpression* one =
+                sem_lhs->Type()->UnwrapRef()->is_signed_integer_scalar()
+                    ? ctx.dst->Expr(1_i)->As<ast::IntLiteralExpression>()
+                    : ctx.dst->Expr(1_u)->As<ast::IntLiteralExpression>();
+            auto op = inc_dec->increment ? ast::BinaryOp::kAdd : ast::BinaryOp::kSubtract;
+            state.Expand(inc_dec, inc_dec->lhs, one, op);
+        }
     }
-  }
-  state.Finalize();
+    state.Finalize();
 }
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/expand_compound_assignment.h b/src/tint/transform/expand_compound_assignment.h
index b461bed..d38d297 100644
--- a/src/tint/transform/expand_compound_assignment.h
+++ b/src/tint/transform/expand_compound_assignment.h
@@ -38,30 +38,26 @@
 ///
 /// This transform also handles increment and decrement statements in the same
 /// manner, by replacing `i++` with `i = i + 1`.
-class ExpandCompoundAssignment
-    : public Castable<ExpandCompoundAssignment, Transform> {
- public:
-  /// Constructor
-  ExpandCompoundAssignment();
-  /// Destructor
-  ~ExpandCompoundAssignment() override;
+class ExpandCompoundAssignment : public Castable<ExpandCompoundAssignment, Transform> {
+  public:
+    /// Constructor
+    ExpandCompoundAssignment();
+    /// Destructor
+    ~ExpandCompoundAssignment() override;
 
-  /// @param program the program to inspect
-  /// @param data optional extra transform-specific input data
-  /// @returns true if this transform should be run for the given program
-  bool ShouldRun(const Program* program,
-                 const DataMap& data = {}) const override;
+    /// @param program the program to inspect
+    /// @param data optional extra transform-specific input data
+    /// @returns true if this transform should be run for the given program
+    bool ShouldRun(const Program* program, const DataMap& data = {}) const override;
 
- protected:
-  /// Runs the transform using the CloneContext built for transforming a
-  /// program. Run() is responsible for calling Clone() on the CloneContext.
-  /// @param ctx the CloneContext primed with the input program and
-  /// ProgramBuilder
-  /// @param inputs optional extra transform-specific input data
-  /// @param outputs optional extra transform-specific output data
-  void Run(CloneContext& ctx,
-           const DataMap& inputs,
-           DataMap& outputs) const override;
+  protected:
+    /// Runs the transform using the CloneContext built for transforming a
+    /// program. Run() is responsible for calling Clone() on the CloneContext.
+    /// @param ctx the CloneContext primed with the input program and
+    /// ProgramBuilder
+    /// @param inputs optional extra transform-specific input data
+    /// @param outputs optional extra transform-specific output data
+    void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const override;
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/expand_compound_assignment_test.cc b/src/tint/transform/expand_compound_assignment_test.cc
index d3fa510..613a135 100644
--- a/src/tint/transform/expand_compound_assignment_test.cc
+++ b/src/tint/transform/expand_compound_assignment_test.cc
@@ -24,55 +24,55 @@
 using ExpandCompoundAssignmentTest = TransformTest;
 
 TEST_F(ExpandCompoundAssignmentTest, ShouldRunEmptyModule) {
-  auto* src = R"()";
+    auto* src = R"()";
 
-  EXPECT_FALSE(ShouldRun<ExpandCompoundAssignment>(src));
+    EXPECT_FALSE(ShouldRun<ExpandCompoundAssignment>(src));
 }
 
 TEST_F(ExpandCompoundAssignmentTest, ShouldRunHasCompoundAssignment) {
-  auto* src = R"(
+    auto* src = R"(
 fn foo() {
   var v : i32;
   v += 1;
 }
 )";
 
-  EXPECT_TRUE(ShouldRun<ExpandCompoundAssignment>(src));
+    EXPECT_TRUE(ShouldRun<ExpandCompoundAssignment>(src));
 }
 
 TEST_F(ExpandCompoundAssignmentTest, ShouldRunHasIncrementDecrement) {
-  auto* src = R"(
+    auto* src = R"(
 fn foo() {
   var v : i32;
   v++;
 }
 )";
 
-  EXPECT_TRUE(ShouldRun<ExpandCompoundAssignment>(src));
+    EXPECT_TRUE(ShouldRun<ExpandCompoundAssignment>(src));
 }
 
 TEST_F(ExpandCompoundAssignmentTest, Basic) {
-  auto* src = R"(
+    auto* src = R"(
 fn main() {
   var v : i32;
   v += 1;
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn main() {
   var v : i32;
   v = (v + 1);
 }
 )";
 
-  auto got = Run<ExpandCompoundAssignment>(src);
+    auto got = Run<ExpandCompoundAssignment>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ExpandCompoundAssignmentTest, LhsPointer) {
-  auto* src = R"(
+    auto* src = R"(
 fn main() {
   var v : i32;
   let p = &v;
@@ -80,7 +80,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn main() {
   var v : i32;
   let p = &(v);
@@ -89,13 +89,13 @@
 }
 )";
 
-  auto got = Run<ExpandCompoundAssignment>(src);
+    auto got = Run<ExpandCompoundAssignment>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ExpandCompoundAssignmentTest, LhsStructMember) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   m : f32,
 }
@@ -106,7 +106,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   m : f32,
 }
@@ -117,13 +117,13 @@
 }
 )";
 
-  auto got = Run<ExpandCompoundAssignment>(src);
+    auto got = Run<ExpandCompoundAssignment>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ExpandCompoundAssignmentTest, LhsArrayElement) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> a : array<i32, 4>;
 
 fn idx() -> i32 {
@@ -136,7 +136,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> a : array<i32, 4>;
 
 fn idx() -> i32 {
@@ -150,13 +150,13 @@
 }
 )";
 
-  auto got = Run<ExpandCompoundAssignment>(src);
+    auto got = Run<ExpandCompoundAssignment>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ExpandCompoundAssignmentTest, LhsVectorComponent_ArrayAccessor) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> v : vec4<i32>;
 
 fn idx() -> i32 {
@@ -169,7 +169,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> v : vec4<i32>;
 
 fn idx() -> i32 {
@@ -184,33 +184,33 @@
 }
 )";
 
-  auto got = Run<ExpandCompoundAssignment>(src);
+    auto got = Run<ExpandCompoundAssignment>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ExpandCompoundAssignmentTest, LhsVectorComponent_MemberAccessor) {
-  auto* src = R"(
+    auto* src = R"(
 fn main() {
   var v : vec4<i32>;
   v.y += 1;
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn main() {
   var v : vec4<i32>;
   v.y = (v.y + 1);
 }
 )";
 
-  auto got = Run<ExpandCompoundAssignment>(src);
+    auto got = Run<ExpandCompoundAssignment>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ExpandCompoundAssignmentTest, LhsMatrixColumn) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> m : mat4x4<f32>;
 
 fn idx() -> i32 {
@@ -223,7 +223,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> m : mat4x4<f32>;
 
 fn idx() -> i32 {
@@ -237,13 +237,13 @@
 }
 )";
 
-  auto got = Run<ExpandCompoundAssignment>(src);
+    auto got = Run<ExpandCompoundAssignment>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ExpandCompoundAssignmentTest, LhsMatrixElement) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> m : mat4x4<f32>;
 
 fn idx1() -> i32 {
@@ -261,7 +261,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> m : mat4x4<f32>;
 
 fn idx1() -> i32 {
@@ -281,13 +281,13 @@
 }
 )";
 
-  auto got = Run<ExpandCompoundAssignment>(src);
+    auto got = Run<ExpandCompoundAssignment>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ExpandCompoundAssignmentTest, LhsMultipleSideEffects) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   a : array<vec4<f32>, 3>,
 }
@@ -316,7 +316,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   a : array<vec4<f32>, 3>,
 }
@@ -347,13 +347,13 @@
 }
 )";
 
-  auto got = Run<ExpandCompoundAssignment>(src);
+    auto got = Run<ExpandCompoundAssignment>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ExpandCompoundAssignmentTest, ForLoopInit) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> a : array<vec4<i32>, 4>;
 
 var<private> p : i32;
@@ -375,7 +375,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> a : array<vec4<i32>, 4>;
 
 var<private> p : i32;
@@ -399,13 +399,13 @@
 }
 )";
 
-  auto got = Run<ExpandCompoundAssignment>(src);
+    auto got = Run<ExpandCompoundAssignment>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ExpandCompoundAssignmentTest, ForLoopCont) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> a : array<vec4<i32>, 4>;
 
 var<private> p : i32;
@@ -427,7 +427,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> a : array<vec4<i32>, 4>;
 
 var<private> p : i32;
@@ -457,93 +457,93 @@
 }
 )";
 
-  auto got = Run<ExpandCompoundAssignment>(src);
+    auto got = Run<ExpandCompoundAssignment>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ExpandCompoundAssignmentTest, Increment_I32) {
-  auto* src = R"(
+    auto* src = R"(
 fn main() {
   var v : i32;
   v++;
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn main() {
   var v : i32;
-  v = (v + 1);
+  v = (v + 1i);
 }
 )";
 
-  auto got = Run<ExpandCompoundAssignment>(src);
+    auto got = Run<ExpandCompoundAssignment>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ExpandCompoundAssignmentTest, Increment_U32) {
-  auto* src = R"(
+    auto* src = R"(
 fn main() {
   var v : u32;
   v++;
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn main() {
   var v : u32;
   v = (v + 1u);
 }
 )";
 
-  auto got = Run<ExpandCompoundAssignment>(src);
+    auto got = Run<ExpandCompoundAssignment>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ExpandCompoundAssignmentTest, Decrement_I32) {
-  auto* src = R"(
+    auto* src = R"(
 fn main() {
   var v : i32;
   v--;
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn main() {
   var v : i32;
-  v = (v - 1);
+  v = (v - 1i);
 }
 )";
 
-  auto got = Run<ExpandCompoundAssignment>(src);
+    auto got = Run<ExpandCompoundAssignment>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ExpandCompoundAssignmentTest, Decrement_U32) {
-  auto* src = R"(
+    auto* src = R"(
 fn main() {
   var v : u32;
   v--;
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn main() {
   var v : u32;
   v = (v - 1u);
 }
 )";
 
-  auto got = Run<ExpandCompoundAssignment>(src);
+    auto got = Run<ExpandCompoundAssignment>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ExpandCompoundAssignmentTest, Increment_LhsPointer) {
-  auto* src = R"(
+    auto* src = R"(
 fn main() {
   var v : i32;
   let p = &v;
@@ -551,22 +551,22 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn main() {
   var v : i32;
   let p = &(v);
   let tint_symbol = &(*(p));
-  *(tint_symbol) = (*(tint_symbol) + 1);
+  *(tint_symbol) = (*(tint_symbol) + 1i);
 }
 )";
 
-  auto got = Run<ExpandCompoundAssignment>(src);
+    auto got = Run<ExpandCompoundAssignment>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ExpandCompoundAssignmentTest, Increment_LhsStructMember) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   m : i32,
 }
@@ -577,24 +577,24 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   m : i32,
 }
 
 fn main() {
   var s : S;
-  s.m = (s.m + 1);
+  s.m = (s.m + 1i);
 }
 )";
 
-  auto got = Run<ExpandCompoundAssignment>(src);
+    auto got = Run<ExpandCompoundAssignment>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ExpandCompoundAssignmentTest, Increment_LhsArrayElement) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> a : array<i32, 4>;
 
 fn idx() -> i32 {
@@ -607,7 +607,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> a : array<i32, 4>;
 
 fn idx() -> i32 {
@@ -617,18 +617,17 @@
 
 fn main() {
   let tint_symbol = &(a[idx()]);
-  *(tint_symbol) = (*(tint_symbol) + 1);
+  *(tint_symbol) = (*(tint_symbol) + 1i);
 }
 )";
 
-  auto got = Run<ExpandCompoundAssignment>(src);
+    auto got = Run<ExpandCompoundAssignment>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(ExpandCompoundAssignmentTest,
-       Increment_LhsVectorComponent_ArrayAccessor) {
-  auto* src = R"(
+TEST_F(ExpandCompoundAssignmentTest, Increment_LhsVectorComponent_ArrayAccessor) {
+    auto* src = R"(
 var<private> v : vec4<i32>;
 
 fn idx() -> i32 {
@@ -641,7 +640,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> v : vec4<i32>;
 
 fn idx() -> i32 {
@@ -652,38 +651,37 @@
 fn main() {
   let tint_symbol = &(v);
   let tint_symbol_1 = idx();
-  (*(tint_symbol))[tint_symbol_1] = ((*(tint_symbol))[tint_symbol_1] + 1);
+  (*(tint_symbol))[tint_symbol_1] = ((*(tint_symbol))[tint_symbol_1] + 1i);
 }
 )";
 
-  auto got = Run<ExpandCompoundAssignment>(src);
+    auto got = Run<ExpandCompoundAssignment>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(ExpandCompoundAssignmentTest,
-       Increment_LhsVectorComponent_MemberAccessor) {
-  auto* src = R"(
+TEST_F(ExpandCompoundAssignmentTest, Increment_LhsVectorComponent_MemberAccessor) {
+    auto* src = R"(
 fn main() {
   var v : vec4<i32>;
   v.y++;
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn main() {
   var v : vec4<i32>;
-  v.y = (v.y + 1);
+  v.y = (v.y + 1i);
 }
 )";
 
-  auto got = Run<ExpandCompoundAssignment>(src);
+    auto got = Run<ExpandCompoundAssignment>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ExpandCompoundAssignmentTest, Increment_ForLoopCont) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> a : array<vec4<i32>, 4>;
 
 var<private> p : i32;
@@ -705,7 +703,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> a : array<vec4<i32>, 4>;
 
 var<private> p : i32;
@@ -729,15 +727,15 @@
     continuing {
       let tint_symbol = &(a[idx1()]);
       let tint_symbol_1 = idx2();
-      (*(tint_symbol))[tint_symbol_1] = ((*(tint_symbol))[tint_symbol_1] + 1);
+      (*(tint_symbol))[tint_symbol_1] = ((*(tint_symbol))[tint_symbol_1] + 1i);
     }
   }
 }
 )";
 
-  auto got = Run<ExpandCompoundAssignment>(src);
+    auto got = Run<ExpandCompoundAssignment>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 }  // namespace
diff --git a/src/tint/transform/first_index_offset.cc b/src/tint/transform/first_index_offset.cc
index 46a2dcd..9d89b83 100644
--- a/src/tint/transform/first_index_offset.cc
+++ b/src/tint/transform/first_index_offset.cc
@@ -38,18 +38,11 @@
 }  // namespace
 
 FirstIndexOffset::BindingPoint::BindingPoint() = default;
-FirstIndexOffset::BindingPoint::BindingPoint(uint32_t b, uint32_t g)
-    : binding(b), group(g) {}
+FirstIndexOffset::BindingPoint::BindingPoint(uint32_t b, uint32_t g) : binding(b), group(g) {}
 FirstIndexOffset::BindingPoint::~BindingPoint() = default;
 
-FirstIndexOffset::Data::Data(bool has_vtx_index,
-                             bool has_inst_index,
-                             uint32_t first_vtx_offset,
-                             uint32_t first_inst_offset)
-    : has_vertex_index(has_vtx_index),
-      has_instance_index(has_inst_index),
-      first_vertex_offset(first_vtx_offset),
-      first_instance_offset(first_inst_offset) {}
+FirstIndexOffset::Data::Data(bool has_vtx_or_inst_index)
+    : has_vertex_or_instance_index(has_vtx_or_inst_index) {}
 FirstIndexOffset::Data::Data(const Data&) = default;
 FirstIndexOffset::Data::~Data() = default;
 
@@ -57,130 +50,109 @@
 FirstIndexOffset::~FirstIndexOffset() = default;
 
 bool FirstIndexOffset::ShouldRun(const Program* program, const DataMap&) const {
-  for (auto* fn : program->AST().Functions()) {
-    if (fn->PipelineStage() == ast::PipelineStage::kVertex) {
-      return true;
+    for (auto* fn : program->AST().Functions()) {
+        if (fn->PipelineStage() == ast::PipelineStage::kVertex) {
+            return true;
+        }
     }
-  }
-  return false;
+    return false;
 }
 
-void FirstIndexOffset::Run(CloneContext& ctx,
-                           const DataMap& inputs,
-                           DataMap& outputs) const {
-  // Get the uniform buffer binding point
-  uint32_t ub_binding = binding_;
-  uint32_t ub_group = group_;
-  if (auto* binding_point = inputs.Get<BindingPoint>()) {
-    ub_binding = binding_point->binding;
-    ub_group = binding_point->group;
-  }
-
-  // Map of builtin usages
-  std::unordered_map<const sem::Variable*, const char*> builtin_vars;
-  std::unordered_map<const sem::StructMember*, const char*> builtin_members;
-
-  bool has_vertex_index = false;
-  bool has_instance_index = false;
-
-  // Traverse the AST scanning for builtin accesses via variables (includes
-  // parameters) or structure member accesses.
-  for (auto* node : ctx.src->ASTNodes().Objects()) {
-    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) {
-            auto* sem_var = ctx.src->Sem().Get(var);
-            builtin_vars.emplace(sem_var, kFirstVertexName);
-            has_vertex_index = true;
-          }
-          if (builtin == ast::Builtin::kInstanceIndex) {
-            auto* sem_var = ctx.src->Sem().Get(var);
-            builtin_vars.emplace(sem_var, kFirstInstanceName);
-            has_instance_index = true;
-          }
-        }
-      }
+void FirstIndexOffset::Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const {
+    // Get the uniform buffer binding point
+    uint32_t ub_binding = binding_;
+    uint32_t ub_group = group_;
+    if (auto* binding_point = inputs.Get<BindingPoint>()) {
+        ub_binding = binding_point->binding;
+        ub_group = binding_point->group;
     }
-    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) {
-            auto* sem_mem = ctx.src->Sem().Get(member);
-            builtin_members.emplace(sem_mem, kFirstVertexName);
-            has_vertex_index = true;
-          }
-          if (builtin == ast::Builtin::kInstanceIndex) {
-            auto* sem_mem = ctx.src->Sem().Get(member);
-            builtin_members.emplace(sem_mem, kFirstInstanceName);
-            has_instance_index = true;
-          }
-        }
-      }
-    }
-  }
 
-  // Byte offsets on the uniform buffer
-  uint32_t vertex_index_offset = 0;
-  uint32_t instance_index_offset = 0;
+    // Map of builtin usages
+    std::unordered_map<const sem::Variable*, const char*> builtin_vars;
+    std::unordered_map<const sem::StructMember*, const char*> builtin_members;
 
-  if (has_vertex_index || has_instance_index) {
-    // Add uniform buffer members and calculate byte offsets
-    uint32_t offset = 0;
-    ast::StructMemberList members;
-    if (has_vertex_index) {
-      members.push_back(ctx.dst->Member(kFirstVertexName, ctx.dst->ty.u32()));
-      vertex_index_offset = offset;
-      offset += 4;
-    }
-    if (has_instance_index) {
-      members.push_back(ctx.dst->Member(kFirstInstanceName, ctx.dst->ty.u32()));
-      instance_index_offset = offset;
-      offset += 4;
-    }
-    auto* struct_ = ctx.dst->Structure(ctx.dst->Sym(), std::move(members));
+    bool has_vertex_or_instance_index = false;
 
-    // Create a global to hold the uniform buffer
-    Symbol buffer_name = ctx.dst->Sym();
-    ctx.dst->Global(buffer_name, ctx.dst->ty.Of(struct_),
-                    ast::StorageClass::kUniform, nullptr,
-                    ast::AttributeList{
-                        ctx.dst->create<ast::BindingAttribute>(ub_binding),
-                        ctx.dst->create<ast::GroupAttribute>(ub_group),
-                    });
-
-    // Fix up all references to the builtins with the offsets
-    ctx.ReplaceAll(
-        [=, &ctx](const ast::Expression* expr) -> const ast::Expression* {
-          if (auto* sem = ctx.src->Sem().Get(expr)) {
-            if (auto* user = sem->As<sem::VariableUser>()) {
-              auto it = builtin_vars.find(user->Variable());
-              if (it != builtin_vars.end()) {
-                return ctx.dst->Add(
-                    ctx.CloneWithoutTransform(expr),
-                    ctx.dst->MemberAccessor(buffer_name, it->second));
-              }
+    // Traverse the AST scanning for builtin accesses via variables (includes
+    // parameters) or structure member accesses.
+    for (auto* node : ctx.src->ASTNodes().Objects()) {
+        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) {
+                        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) {
+                        auto* sem_var = ctx.src->Sem().Get(var);
+                        builtin_vars.emplace(sem_var, kFirstInstanceName);
+                        has_vertex_or_instance_index = true;
+                    }
+                }
             }
-            if (auto* access = sem->As<sem::StructMemberAccess>()) {
-              auto it = builtin_members.find(access->Member());
-              if (it != builtin_members.end()) {
-                return ctx.dst->Add(
-                    ctx.CloneWithoutTransform(expr),
-                    ctx.dst->MemberAccessor(buffer_name, it->second));
-              }
+        }
+        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) {
+                        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) {
+                        auto* sem_mem = ctx.src->Sem().Get(member);
+                        builtin_members.emplace(sem_mem, kFirstInstanceName);
+                        has_vertex_or_instance_index = true;
+                    }
+                }
             }
-          }
-          // Not interested in this experssion. Just clone.
-          return nullptr;
+        }
+    }
+
+    if (has_vertex_or_instance_index) {
+        // Add uniform buffer members and calculate byte offsets
+        ast::StructMemberList members;
+        members.push_back(ctx.dst->Member(kFirstVertexName, ctx.dst->ty.u32()));
+        members.push_back(ctx.dst->Member(kFirstInstanceName, ctx.dst->ty.u32()));
+        auto* struct_ = ctx.dst->Structure(ctx.dst->Sym(), std::move(members));
+
+        // Create a global to hold the uniform buffer
+        Symbol buffer_name = ctx.dst->Sym();
+        ctx.dst->Global(buffer_name, ctx.dst->ty.Of(struct_), ast::StorageClass::kUniform, nullptr,
+                        ast::AttributeList{
+                            ctx.dst->create<ast::BindingAttribute>(ub_binding),
+                            ctx.dst->create<ast::GroupAttribute>(ub_group),
+                        });
+
+        // Fix up all references to the builtins with the offsets
+        ctx.ReplaceAll([=, &ctx](const ast::Expression* expr) -> const ast::Expression* {
+            if (auto* sem = ctx.src->Sem().Get(expr)) {
+                if (auto* user = sem->As<sem::VariableUser>()) {
+                    auto it = builtin_vars.find(user->Variable());
+                    if (it != builtin_vars.end()) {
+                        return ctx.dst->Add(ctx.CloneWithoutTransform(expr),
+                                            ctx.dst->MemberAccessor(buffer_name, it->second));
+                    }
+                }
+                if (auto* access = sem->As<sem::StructMemberAccess>()) {
+                    auto it = builtin_members.find(access->Member());
+                    if (it != builtin_members.end()) {
+                        return ctx.dst->Add(ctx.CloneWithoutTransform(expr),
+                                            ctx.dst->MemberAccessor(buffer_name, it->second));
+                    }
+                }
+            }
+            // Not interested in this experssion. Just clone.
+            return nullptr;
         });
-  }
+    }
 
-  ctx.Clone();
+    ctx.Clone();
 
-  outputs.Add<Data>(has_vertex_index, has_instance_index, vertex_index_offset,
-                    instance_index_offset);
+    outputs.Add<Data>(has_vertex_or_instance_index);
 }
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/first_index_offset.h b/src/tint/transform/first_index_offset.h
index 43d003d..04758cd 100644
--- a/src/tint/transform/first_index_offset.h
+++ b/src/tint/transform/first_index_offset.h
@@ -58,82 +58,68 @@
 /// ```
 ///
 class FirstIndexOffset final : public Castable<FirstIndexOffset, Transform> {
- public:
-  /// BindingPoint is consumed by the FirstIndexOffset transform.
-  /// BindingPoint specifies the binding point of the first index uniform
-  /// buffer.
-  struct BindingPoint final : public Castable<BindingPoint, transform::Data> {
-    /// Constructor
-    BindingPoint();
+  public:
+    /// BindingPoint is consumed by the FirstIndexOffset transform.
+    /// BindingPoint specifies the binding point of the first index uniform
+    /// buffer.
+    struct BindingPoint final : public Castable<BindingPoint, transform::Data> {
+        /// Constructor
+        BindingPoint();
+
+        /// Constructor
+        /// @param b the binding index
+        /// @param g the binding group
+        BindingPoint(uint32_t b, uint32_t g);
+
+        /// Destructor
+        ~BindingPoint() override;
+
+        /// `@binding()` for the first vertex / first instance uniform buffer
+        uint32_t binding = 0;
+        /// `@group()` for the first vertex / first instance uniform buffer
+        uint32_t group = 0;
+    };
+
+    /// Data is outputted by the FirstIndexOffset transform.
+    /// Data holds information about shader usage and constant buffer offsets.
+    struct Data final : public Castable<Data, transform::Data> {
+        /// Constructor
+        /// @param has_vtx_or_inst_index True if the shader uses vertex_index or
+        /// instance_index
+        explicit Data(bool has_vtx_or_inst_index);
+
+        /// Copy constructor
+        Data(const Data&);
+
+        /// Destructor
+        ~Data() override;
+
+        /// True if the shader uses vertex_index
+        const bool has_vertex_or_instance_index;
+    };
 
     /// Constructor
-    /// @param b the binding index
-    /// @param g the binding group
-    BindingPoint(uint32_t b, uint32_t g);
-
+    FirstIndexOffset();
     /// Destructor
-    ~BindingPoint() override;
+    ~FirstIndexOffset() override;
 
-    /// `@binding()` for the first vertex / first instance uniform buffer
-    uint32_t binding = 0;
-    /// `@group()` for the first vertex / first instance uniform buffer
-    uint32_t group = 0;
-  };
+    /// @param program the program to inspect
+    /// @param data optional extra transform-specific input data
+    /// @returns true if this transform should be run for the given program
+    bool ShouldRun(const Program* program, const DataMap& data = {}) const override;
 
-  /// Data is outputted by the FirstIndexOffset transform.
-  /// Data holds information about shader usage and constant buffer offsets.
-  struct Data final : public Castable<Data, transform::Data> {
-    /// Constructor
-    /// @param has_vtx_index True if the shader uses vertex_index
-    /// @param has_inst_index True if the shader uses instance_index
-    /// @param first_vtx_offset Offset of first vertex into constant buffer
-    /// @param first_inst_offset Offset of first instance into constant buffer
-    Data(bool has_vtx_index,
-         bool has_inst_index,
-         uint32_t first_vtx_offset,
-         uint32_t first_inst_offset);
+  protected:
+    /// Runs the transform using the CloneContext built for transforming a
+    /// program. Run() is responsible for calling Clone() on the CloneContext.
+    /// @param ctx the CloneContext primed with the input program and
+    /// ProgramBuilder
+    /// @param inputs optional extra transform-specific input data
+    /// @param outputs optional extra transform-specific output data
+    void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const override;
 
-    /// Copy constructor
-    Data(const Data&);
-
-    /// Destructor
-    ~Data() override;
-
-    /// True if the shader uses vertex_index
-    const bool has_vertex_index;
-    /// True if the shader uses instance_index
-    const bool has_instance_index;
-    /// Offset of first vertex into constant buffer
-    const uint32_t first_vertex_offset;
-    /// Offset of first instance into constant buffer
-    const uint32_t first_instance_offset;
-  };
-
-  /// Constructor
-  FirstIndexOffset();
-  /// Destructor
-  ~FirstIndexOffset() override;
-
-  /// @param program the program to inspect
-  /// @param data optional extra transform-specific input data
-  /// @returns true if this transform should be run for the given program
-  bool ShouldRun(const Program* program,
-                 const DataMap& data = {}) const override;
-
- protected:
-  /// Runs the transform using the CloneContext built for transforming a
-  /// program. Run() is responsible for calling Clone() on the CloneContext.
-  /// @param ctx the CloneContext primed with the input program and
-  /// ProgramBuilder
-  /// @param inputs optional extra transform-specific input data
-  /// @param outputs optional extra transform-specific output data
-  void Run(CloneContext& ctx,
-           const DataMap& inputs,
-           DataMap& outputs) const override;
-
- private:
-  uint32_t binding_ = 0;
-  uint32_t group_ = 0;
+  private:
+    uint32_t binding_ = 0;
+    uint32_t group_ = 0;
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/first_index_offset_test.cc b/src/tint/transform/first_index_offset_test.cc
index ee91439..a467c17 100644
--- a/src/tint/transform/first_index_offset_test.cc
+++ b/src/tint/transform/first_index_offset_test.cc
@@ -26,74 +26,71 @@
 using FirstIndexOffsetTest = TransformTest;
 
 TEST_F(FirstIndexOffsetTest, ShouldRunEmptyModule) {
-  auto* src = R"()";
+    auto* src = R"()";
 
-  EXPECT_FALSE(ShouldRun<FirstIndexOffset>(src));
+    EXPECT_FALSE(ShouldRun<FirstIndexOffset>(src));
 }
 
 TEST_F(FirstIndexOffsetTest, ShouldRunFragmentStage) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(fragment)
 fn entry() {
   return;
 }
 )";
 
-  EXPECT_FALSE(ShouldRun<FirstIndexOffset>(src));
+    EXPECT_FALSE(ShouldRun<FirstIndexOffset>(src));
 }
 
 TEST_F(FirstIndexOffsetTest, ShouldRunVertexStage) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(vertex)
 fn entry() -> @builtin(position) vec4<f32> {
   return vec4<f32>();
 }
 )";
 
-  EXPECT_TRUE(ShouldRun<FirstIndexOffset>(src));
+    EXPECT_TRUE(ShouldRun<FirstIndexOffset>(src));
 }
 
 TEST_F(FirstIndexOffsetTest, EmptyModule) {
-  auto* src = "";
-  auto* expect = "";
+    auto* src = "";
+    auto* expect = "";
 
-  DataMap config;
-  config.Add<FirstIndexOffset::BindingPoint>(0, 0);
-  auto got = Run<FirstIndexOffset>(src, std::move(config));
+    DataMap config;
+    config.Add<FirstIndexOffset::BindingPoint>(0, 0);
+    auto got = Run<FirstIndexOffset>(src, std::move(config));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 
-  auto* data = got.data.Get<FirstIndexOffset::Data>();
+    auto* data = got.data.Get<FirstIndexOffset::Data>();
 
-  EXPECT_EQ(data, nullptr);
+    EXPECT_EQ(data, nullptr);
 }
 
 TEST_F(FirstIndexOffsetTest, BasicVertexShader) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(vertex)
 fn entry() -> @builtin(position) vec4<f32> {
   return vec4<f32>();
 }
 )";
-  auto* expect = src;
+    auto* expect = src;
 
-  DataMap config;
-  config.Add<FirstIndexOffset::BindingPoint>(0, 0);
-  auto got = Run<FirstIndexOffset>(src, std::move(config));
+    DataMap config;
+    config.Add<FirstIndexOffset::BindingPoint>(0, 0);
+    auto got = Run<FirstIndexOffset>(src, std::move(config));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 
-  auto* data = got.data.Get<FirstIndexOffset::Data>();
+    auto* data = got.data.Get<FirstIndexOffset::Data>();
 
-  ASSERT_NE(data, nullptr);
-  EXPECT_EQ(data->has_vertex_index, false);
-  EXPECT_EQ(data->has_instance_index, false);
-  EXPECT_EQ(data->first_vertex_offset, 0u);
-  EXPECT_EQ(data->first_instance_offset, 0u);
+    ASSERT_NE(data, nullptr);
+    EXPECT_EQ(data->has_vertex_or_instance_index, false);
 }
 
 TEST_F(FirstIndexOffsetTest, BasicModuleVertexIndex) {
-  auto* src = R"(
+    auto* src = R"(
 fn test(vert_idx : u32) -> u32 {
   return vert_idx;
 }
@@ -105,9 +102,10 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol {
   first_vertex_index : u32,
+  first_instance_index : u32,
 }
 
 @binding(1) @group(2) var<uniform> tint_symbol_1 : tint_symbol;
@@ -123,23 +121,20 @@
 }
 )";
 
-  DataMap config;
-  config.Add<FirstIndexOffset::BindingPoint>(1, 2);
-  auto got = Run<FirstIndexOffset>(src, std::move(config));
+    DataMap config;
+    config.Add<FirstIndexOffset::BindingPoint>(1, 2);
+    auto got = Run<FirstIndexOffset>(src, std::move(config));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 
-  auto* data = got.data.Get<FirstIndexOffset::Data>();
+    auto* data = got.data.Get<FirstIndexOffset::Data>();
 
-  ASSERT_NE(data, nullptr);
-  EXPECT_EQ(data->has_vertex_index, true);
-  EXPECT_EQ(data->has_instance_index, false);
-  EXPECT_EQ(data->first_vertex_offset, 0u);
-  EXPECT_EQ(data->first_instance_offset, 0u);
+    ASSERT_NE(data, nullptr);
+    EXPECT_EQ(data->has_vertex_or_instance_index, true);
 }
 
 TEST_F(FirstIndexOffsetTest, BasicModuleVertexIndex_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(vertex)
 fn entry(@builtin(vertex_index) vert_idx : u32) -> @builtin(position) vec4<f32> {
   test(vert_idx);
@@ -151,9 +146,10 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol {
   first_vertex_index : u32,
+  first_instance_index : u32,
 }
 
 @binding(1) @group(2) var<uniform> tint_symbol_1 : tint_symbol;
@@ -169,23 +165,20 @@
 }
 )";
 
-  DataMap config;
-  config.Add<FirstIndexOffset::BindingPoint>(1, 2);
-  auto got = Run<FirstIndexOffset>(src, std::move(config));
+    DataMap config;
+    config.Add<FirstIndexOffset::BindingPoint>(1, 2);
+    auto got = Run<FirstIndexOffset>(src, std::move(config));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 
-  auto* data = got.data.Get<FirstIndexOffset::Data>();
+    auto* data = got.data.Get<FirstIndexOffset::Data>();
 
-  ASSERT_NE(data, nullptr);
-  EXPECT_EQ(data->has_vertex_index, true);
-  EXPECT_EQ(data->has_instance_index, false);
-  EXPECT_EQ(data->first_vertex_offset, 0u);
-  EXPECT_EQ(data->first_instance_offset, 0u);
+    ASSERT_NE(data, nullptr);
+    EXPECT_EQ(data->has_vertex_or_instance_index, true);
 }
 
 TEST_F(FirstIndexOffsetTest, BasicModuleInstanceIndex) {
-  auto* src = R"(
+    auto* src = R"(
 fn test(inst_idx : u32) -> u32 {
   return inst_idx;
 }
@@ -197,8 +190,9 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol {
+  first_vertex_index : u32,
   first_instance_index : u32,
 }
 
@@ -215,23 +209,20 @@
 }
 )";
 
-  DataMap config;
-  config.Add<FirstIndexOffset::BindingPoint>(1, 7);
-  auto got = Run<FirstIndexOffset>(src, std::move(config));
+    DataMap config;
+    config.Add<FirstIndexOffset::BindingPoint>(1, 7);
+    auto got = Run<FirstIndexOffset>(src, std::move(config));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 
-  auto* data = got.data.Get<FirstIndexOffset::Data>();
+    auto* data = got.data.Get<FirstIndexOffset::Data>();
 
-  ASSERT_NE(data, nullptr);
-  EXPECT_EQ(data->has_vertex_index, false);
-  EXPECT_EQ(data->has_instance_index, true);
-  EXPECT_EQ(data->first_vertex_offset, 0u);
-  EXPECT_EQ(data->first_instance_offset, 0u);
+    ASSERT_NE(data, nullptr);
+    EXPECT_EQ(data->has_vertex_or_instance_index, true);
 }
 
 TEST_F(FirstIndexOffsetTest, BasicModuleInstanceIndex_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(vertex)
 fn entry(@builtin(instance_index) inst_idx : u32) -> @builtin(position) vec4<f32> {
   test(inst_idx);
@@ -243,8 +234,9 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol {
+  first_vertex_index : u32,
   first_instance_index : u32,
 }
 
@@ -261,23 +253,20 @@
 }
 )";
 
-  DataMap config;
-  config.Add<FirstIndexOffset::BindingPoint>(1, 7);
-  auto got = Run<FirstIndexOffset>(src, std::move(config));
+    DataMap config;
+    config.Add<FirstIndexOffset::BindingPoint>(1, 7);
+    auto got = Run<FirstIndexOffset>(src, std::move(config));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 
-  auto* data = got.data.Get<FirstIndexOffset::Data>();
+    auto* data = got.data.Get<FirstIndexOffset::Data>();
 
-  ASSERT_NE(data, nullptr);
-  EXPECT_EQ(data->has_vertex_index, false);
-  EXPECT_EQ(data->has_instance_index, true);
-  EXPECT_EQ(data->first_vertex_offset, 0u);
-  EXPECT_EQ(data->first_instance_offset, 0u);
+    ASSERT_NE(data, nullptr);
+    EXPECT_EQ(data->has_vertex_or_instance_index, true);
 }
 
 TEST_F(FirstIndexOffsetTest, BasicModuleBothIndex) {
-  auto* src = R"(
+    auto* src = R"(
 fn test(instance_idx : u32, vert_idx : u32) -> u32 {
   return instance_idx + vert_idx;
 }
@@ -294,7 +283,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol {
   first_vertex_index : u32,
   first_instance_index : u32,
@@ -320,23 +309,20 @@
 }
 )";
 
-  DataMap config;
-  config.Add<FirstIndexOffset::BindingPoint>(1, 2);
-  auto got = Run<FirstIndexOffset>(src, std::move(config));
+    DataMap config;
+    config.Add<FirstIndexOffset::BindingPoint>(1, 2);
+    auto got = Run<FirstIndexOffset>(src, std::move(config));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 
-  auto* data = got.data.Get<FirstIndexOffset::Data>();
+    auto* data = got.data.Get<FirstIndexOffset::Data>();
 
-  ASSERT_NE(data, nullptr);
-  EXPECT_EQ(data->has_vertex_index, true);
-  EXPECT_EQ(data->has_instance_index, true);
-  EXPECT_EQ(data->first_vertex_offset, 0u);
-  EXPECT_EQ(data->first_instance_offset, 4u);
+    ASSERT_NE(data, nullptr);
+    EXPECT_EQ(data->has_vertex_or_instance_index, true);
 }
 
 TEST_F(FirstIndexOffsetTest, BasicModuleBothIndex_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(vertex)
 fn entry(inputs : Inputs) -> @builtin(position) vec4<f32> {
   test(inputs.instance_idx, inputs.vert_idx);
@@ -353,7 +339,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol {
   first_vertex_index : u32,
   first_instance_index : u32,
@@ -379,23 +365,20 @@
 }
 )";
 
-  DataMap config;
-  config.Add<FirstIndexOffset::BindingPoint>(1, 2);
-  auto got = Run<FirstIndexOffset>(src, std::move(config));
+    DataMap config;
+    config.Add<FirstIndexOffset::BindingPoint>(1, 2);
+    auto got = Run<FirstIndexOffset>(src, std::move(config));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 
-  auto* data = got.data.Get<FirstIndexOffset::Data>();
+    auto* data = got.data.Get<FirstIndexOffset::Data>();
 
-  ASSERT_NE(data, nullptr);
-  EXPECT_EQ(data->has_vertex_index, true);
-  EXPECT_EQ(data->has_instance_index, true);
-  EXPECT_EQ(data->first_vertex_offset, 0u);
-  EXPECT_EQ(data->first_instance_offset, 4u);
+    ASSERT_NE(data, nullptr);
+    EXPECT_EQ(data->has_vertex_or_instance_index, true);
 }
 
 TEST_F(FirstIndexOffsetTest, NestedCalls) {
-  auto* src = R"(
+    auto* src = R"(
 fn func1(vert_idx : u32) -> u32 {
   return vert_idx;
 }
@@ -411,9 +394,10 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol {
   first_vertex_index : u32,
+  first_instance_index : u32,
 }
 
 @binding(1) @group(2) var<uniform> tint_symbol_1 : tint_symbol;
@@ -433,23 +417,20 @@
 }
 )";
 
-  DataMap config;
-  config.Add<FirstIndexOffset::BindingPoint>(1, 2);
-  auto got = Run<FirstIndexOffset>(src, std::move(config));
+    DataMap config;
+    config.Add<FirstIndexOffset::BindingPoint>(1, 2);
+    auto got = Run<FirstIndexOffset>(src, std::move(config));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 
-  auto* data = got.data.Get<FirstIndexOffset::Data>();
+    auto* data = got.data.Get<FirstIndexOffset::Data>();
 
-  ASSERT_NE(data, nullptr);
-  EXPECT_EQ(data->has_vertex_index, true);
-  EXPECT_EQ(data->has_instance_index, false);
-  EXPECT_EQ(data->first_vertex_offset, 0u);
-  EXPECT_EQ(data->first_instance_offset, 0u);
+    ASSERT_NE(data, nullptr);
+    EXPECT_EQ(data->has_vertex_or_instance_index, true);
 }
 
 TEST_F(FirstIndexOffsetTest, NestedCalls_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(vertex)
 fn entry(@builtin(vertex_index) vert_idx : u32) -> @builtin(position) vec4<f32> {
   func2(vert_idx);
@@ -465,9 +446,10 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol {
   first_vertex_index : u32,
+  first_instance_index : u32,
 }
 
 @binding(1) @group(2) var<uniform> tint_symbol_1 : tint_symbol;
@@ -487,23 +469,20 @@
 }
 )";
 
-  DataMap config;
-  config.Add<FirstIndexOffset::BindingPoint>(1, 2);
-  auto got = Run<FirstIndexOffset>(src, std::move(config));
+    DataMap config;
+    config.Add<FirstIndexOffset::BindingPoint>(1, 2);
+    auto got = Run<FirstIndexOffset>(src, std::move(config));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 
-  auto* data = got.data.Get<FirstIndexOffset::Data>();
+    auto* data = got.data.Get<FirstIndexOffset::Data>();
 
-  ASSERT_NE(data, nullptr);
-  EXPECT_EQ(data->has_vertex_index, true);
-  EXPECT_EQ(data->has_instance_index, false);
-  EXPECT_EQ(data->first_vertex_offset, 0u);
-  EXPECT_EQ(data->first_instance_offset, 0u);
+    ASSERT_NE(data, nullptr);
+    EXPECT_EQ(data->has_vertex_or_instance_index, true);
 }
 
 TEST_F(FirstIndexOffsetTest, MultipleEntryPoints) {
-  auto* src = R"(
+    auto* src = R"(
 fn func(i : u32) -> u32 {
   return i;
 }
@@ -527,7 +506,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol {
   first_vertex_index : u32,
   first_instance_index : u32,
@@ -558,23 +537,20 @@
 }
 )";
 
-  DataMap config;
-  config.Add<FirstIndexOffset::BindingPoint>(1, 2);
-  auto got = Run<FirstIndexOffset>(src, std::move(config));
+    DataMap config;
+    config.Add<FirstIndexOffset::BindingPoint>(1, 2);
+    auto got = Run<FirstIndexOffset>(src, std::move(config));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 
-  auto* data = got.data.Get<FirstIndexOffset::Data>();
+    auto* data = got.data.Get<FirstIndexOffset::Data>();
 
-  ASSERT_NE(data, nullptr);
-  EXPECT_EQ(data->has_vertex_index, true);
-  EXPECT_EQ(data->has_instance_index, true);
-  EXPECT_EQ(data->first_vertex_offset, 0u);
-  EXPECT_EQ(data->first_instance_offset, 4u);
+    ASSERT_NE(data, nullptr);
+    EXPECT_EQ(data->has_vertex_or_instance_index, true);
 }
 
 TEST_F(FirstIndexOffsetTest, MultipleEntryPoints_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(vertex)
 fn entry_a(@builtin(vertex_index) vert_idx : u32) -> @builtin(position) vec4<f32> {
   func(vert_idx);
@@ -598,7 +574,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol {
   first_vertex_index : u32,
   first_instance_index : u32,
@@ -629,19 +605,16 @@
 }
 )";
 
-  DataMap config;
-  config.Add<FirstIndexOffset::BindingPoint>(1, 2);
-  auto got = Run<FirstIndexOffset>(src, std::move(config));
+    DataMap config;
+    config.Add<FirstIndexOffset::BindingPoint>(1, 2);
+    auto got = Run<FirstIndexOffset>(src, std::move(config));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 
-  auto* data = got.data.Get<FirstIndexOffset::Data>();
+    auto* data = got.data.Get<FirstIndexOffset::Data>();
 
-  ASSERT_NE(data, nullptr);
-  EXPECT_EQ(data->has_vertex_index, true);
-  EXPECT_EQ(data->has_instance_index, true);
-  EXPECT_EQ(data->first_vertex_offset, 0u);
-  EXPECT_EQ(data->first_instance_offset, 4u);
+    ASSERT_NE(data, nullptr);
+    EXPECT_EQ(data->has_vertex_or_instance_index, true);
 }
 
 }  // namespace
diff --git a/src/tint/transform/fold_constants.cc b/src/tint/transform/fold_constants.cc
index b814c5c..be547b1 100644
--- a/src/tint/transform/fold_constants.cc
+++ b/src/tint/transform/fold_constants.cc
@@ -33,65 +33,62 @@
 FoldConstants::~FoldConstants() = default;
 
 void FoldConstants::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
-  ctx.ReplaceAll([&](const ast::Expression* expr) -> const ast::Expression* {
-    auto* call = ctx.src->Sem().Get<sem::Call>(expr);
-    if (!call) {
-      return nullptr;
-    }
+    ctx.ReplaceAll([&](const ast::Expression* expr) -> const ast::Expression* {
+        auto* call = ctx.src->Sem().Get<sem::Call>(expr);
+        if (!call) {
+            return nullptr;
+        }
 
-    auto value = call->ConstantValue();
-    if (!value.IsValid()) {
-      return nullptr;
-    }
+        auto value = call->ConstantValue();
+        if (!value.IsValid()) {
+            return nullptr;
+        }
 
-    auto* ty = call->Type();
+        auto* ty = call->Type();
 
-    if (!call->Target()->IsAnyOf<sem::TypeConversion, sem::TypeConstructor>()) {
-      return nullptr;
-    }
+        if (!call->Target()->IsAnyOf<sem::TypeConversion, sem::TypeConstructor>()) {
+            return nullptr;
+        }
 
-    // If original ctor expression had no init values, don't replace the
-    // expression
-    if (call->Arguments().empty()) {
-      return nullptr;
-    }
+        // If original ctor expression had no init values, don't replace the
+        // expression
+        if (call->Arguments().empty()) {
+            return nullptr;
+        }
 
-    if (auto* vec = ty->As<sem::Vector>()) {
-      uint32_t vec_size = static_cast<uint32_t>(vec->Width());
+        if (auto* vec = ty->As<sem::Vector>()) {
+            uint32_t vec_size = static_cast<uint32_t>(vec->Width());
 
-      // We'd like to construct the new vector with the same number of
-      // constructor args that the original node had, but after folding
-      // constants, cases like the following are problematic:
-      //
-      // vec3<f32> = vec3<f32>(vec2<f32>, 1.0) // vec_size=3, ctor_size=2
-      //
-      // In this case, creating a vec3 with 2 args is invalid, so we should
-      // create it with 3. So what we do is construct with vec_size args,
-      // except if the original vector was single-value initialized, in
-      // which case, we only construct with one arg again.
-      uint32_t ctor_size = (call->Arguments().size() == 1) ? 1 : vec_size;
+            // We'd like to construct the new vector with the same number of
+            // constructor args that the original node had, but after folding
+            // constants, cases like the following are problematic:
+            //
+            // vec3<f32> = vec3<f32>(vec2<f32>, 1.0) // vec_size=3, ctor_size=2
+            //
+            // In this case, creating a vec3 with 2 args is invalid, so we should
+            // create it with 3. So what we do is construct with vec_size args,
+            // except if the original vector was single-value initialized, in
+            // which case, we only construct with one arg again.
+            uint32_t ctor_size = (call->Arguments().size() == 1) ? 1 : vec_size;
 
-      ast::ExpressionList ctors;
-      for (uint32_t i = 0; i < ctor_size; ++i) {
-        value.WithScalarAt(
-            i, [&](auto&& s) { ctors.emplace_back(ctx.dst->Expr(s)); });
-      }
+            ast::ExpressionList ctors;
+            for (uint32_t i = 0; i < ctor_size; ++i) {
+                value.WithScalarAt(i, [&](auto&& s) { ctors.emplace_back(ctx.dst->Expr(s)); });
+            }
 
-      auto* el_ty = CreateASTTypeFor(ctx, vec->type());
-      return ctx.dst->vec(el_ty, vec_size, ctors);
-    }
+            auto* el_ty = CreateASTTypeFor(ctx, vec->type());
+            return ctx.dst->vec(el_ty, vec_size, ctors);
+        }
 
-    if (ty->is_scalar()) {
-      return value.WithScalarAt(0,
-                                [&](auto&& s) -> const ast::LiteralExpression* {
-                                  return ctx.dst->Expr(s);
-                                });
-    }
+        if (ty->is_scalar()) {
+            return value.WithScalarAt(
+                0, [&](auto&& s) -> const ast::LiteralExpression* { return ctx.dst->Expr(s); });
+        }
 
-    return nullptr;
-  });
+        return nullptr;
+    });
 
-  ctx.Clone();
+    ctx.Clone();
 }
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/fold_constants.h b/src/tint/transform/fold_constants.h
index fbe7abd..ed3e205 100644
--- a/src/tint/transform/fold_constants.h
+++ b/src/tint/transform/fold_constants.h
@@ -21,23 +21,21 @@
 
 /// FoldConstants transforms the AST by folding constant expressions
 class FoldConstants final : public Castable<FoldConstants, Transform> {
- public:
-  /// Constructor
-  FoldConstants();
+  public:
+    /// Constructor
+    FoldConstants();
 
-  /// Destructor
-  ~FoldConstants() override;
+    /// Destructor
+    ~FoldConstants() override;
 
- protected:
-  /// Runs the transform using the CloneContext built for transforming a
-  /// program. Run() is responsible for calling Clone() on the CloneContext.
-  /// @param ctx the CloneContext primed with the input program and
-  /// ProgramBuilder
-  /// @param inputs optional extra transform-specific input data
-  /// @param outputs optional extra transform-specific output data
-  void Run(CloneContext& ctx,
-           const DataMap& inputs,
-           DataMap& outputs) const override;
+  protected:
+    /// Runs the transform using the CloneContext built for transforming a
+    /// program. Run() is responsible for calling Clone() on the CloneContext.
+    /// @param ctx the CloneContext primed with the input program and
+    /// ProgramBuilder
+    /// @param inputs optional extra transform-specific input data
+    /// @param outputs optional extra transform-specific output data
+    void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const override;
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/fold_constants_test.cc b/src/tint/transform/fold_constants_test.cc
index d8121bc..f27ede6 100644
--- a/src/tint/transform/fold_constants_test.cc
+++ b/src/tint/transform/fold_constants_test.cc
@@ -26,7 +26,7 @@
 using FoldConstantsTest = TransformTest;
 
 TEST_F(FoldConstantsTest, Module_Scalar_NoConversion) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> a : i32 = i32(123);
 var<private> b : u32 = u32(123u);
 var<private> c : f32 = f32(123.0);
@@ -36,8 +36,8 @@
 }
 )";
 
-  auto* expect = R"(
-var<private> a : i32 = 123;
+    auto* expect = R"(
+var<private> a : i32 = 123i;
 
 var<private> b : u32 = 123u;
 
@@ -49,13 +49,13 @@
 }
 )";
 
-  auto got = Run<FoldConstants>(src);
+    auto got = Run<FoldConstants>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(FoldConstantsTest, Module_Scalar_Conversion) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> a : i32 = i32(123.0);
 var<private> b : u32 = u32(123);
 var<private> c : f32 = f32(123u);
@@ -65,8 +65,8 @@
 }
 )";
 
-  auto* expect = R"(
-var<private> a : i32 = 123;
+    auto* expect = R"(
+var<private> a : i32 = 123i;
 
 var<private> b : u32 = 123u;
 
@@ -78,13 +78,13 @@
 }
 )";
 
-  auto got = Run<FoldConstants>(src);
+    auto got = Run<FoldConstants>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(FoldConstantsTest, Module_Scalar_MultipleConversions) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> a : i32 = i32(u32(f32(u32(i32(123.0)))));
 var<private> b : u32 = u32(i32(f32(i32(u32(123)))));
 var<private> c : f32 = f32(u32(i32(u32(f32(123u)))));
@@ -94,8 +94,8 @@
 }
 )";
 
-  auto* expect = R"(
-var<private> a : i32 = 123;
+    auto* expect = R"(
+var<private> a : i32 = 123i;
 
 var<private> b : u32 = 123u;
 
@@ -107,13 +107,13 @@
 }
 )";
 
-  auto got = Run<FoldConstants>(src);
+    auto got = Run<FoldConstants>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(FoldConstantsTest, Module_Vector_NoConversion) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> a : vec3<i32> = vec3<i32>(123);
 var<private> b : vec3<u32> = vec3<u32>(123u);
 var<private> c : vec3<f32> = vec3<f32>(123.0);
@@ -123,8 +123,8 @@
 }
 )";
 
-  auto* expect = R"(
-var<private> a : vec3<i32> = vec3<i32>(123);
+    auto* expect = R"(
+var<private> a : vec3<i32> = vec3<i32>(123i);
 
 var<private> b : vec3<u32> = vec3<u32>(123u);
 
@@ -136,13 +136,13 @@
 }
 )";
 
-  auto got = Run<FoldConstants>(src);
+    auto got = Run<FoldConstants>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(FoldConstantsTest, Module_Vector_Conversion) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> a : vec3<i32> = vec3<i32>(vec3<f32>(123.0));
 var<private> b : vec3<u32> = vec3<u32>(vec3<i32>(123));
 var<private> c : vec3<f32> = vec3<f32>(vec3<u32>(123u));
@@ -152,8 +152,8 @@
 }
 )";
 
-  auto* expect = R"(
-var<private> a : vec3<i32> = vec3<i32>(123);
+    auto* expect = R"(
+var<private> a : vec3<i32> = vec3<i32>(123i);
 
 var<private> b : vec3<u32> = vec3<u32>(123u);
 
@@ -165,13 +165,13 @@
 }
 )";
 
-  auto got = Run<FoldConstants>(src);
+    auto got = Run<FoldConstants>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(FoldConstantsTest, Module_Vector_MultipleConversions) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> a : vec3<i32> = vec3<i32>(vec3<u32>(vec3<f32>(vec3<u32>(u32(123.0)))));
 var<private> b : vec3<u32> = vec3<u32>(vec3<i32>(vec3<f32>(vec3<i32>(i32(123)))));
 var<private> c : vec3<f32> = vec3<f32>(vec3<u32>(vec3<i32>(vec3<u32>(u32(123u)))));
@@ -181,8 +181,8 @@
 }
 )";
 
-  auto* expect = R"(
-var<private> a : vec3<i32> = vec3<i32>(123);
+    auto* expect = R"(
+var<private> a : vec3<i32> = vec3<i32>(123i);
 
 var<private> b : vec3<u32> = vec3<u32>(123u);
 
@@ -194,13 +194,13 @@
 }
 )";
 
-  auto got = Run<FoldConstants>(src);
+    auto got = Run<FoldConstants>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(FoldConstantsTest, Module_Vector_MixedSizeConversions) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> a : vec4<i32> = vec4<i32>(vec3<i32>(vec3<u32>(1u, 2u, 3u)), 4);
 var<private> b : vec4<i32> = vec4<i32>(vec2<i32>(vec2<u32>(1u, 2u)), vec2<i32>(4, 5));
 var<private> c : vec4<i32> = vec4<i32>(1, vec2<i32>(vec2<f32>(2.0, 3.0)), 4);
@@ -211,14 +211,14 @@
 }
 )";
 
-  auto* expect = R"(
-var<private> a : vec4<i32> = vec4<i32>(1, 2, 3, 4);
+    auto* expect = R"(
+var<private> a : vec4<i32> = vec4<i32>(1i, 2i, 3i, 4i);
 
-var<private> b : vec4<i32> = vec4<i32>(1, 2, 4, 5);
+var<private> b : vec4<i32> = vec4<i32>(1i, 2i, 4i, 5i);
 
-var<private> c : vec4<i32> = vec4<i32>(1, 2, 3, 4);
+var<private> c : vec4<i32> = vec4<i32>(1i, 2i, 3i, 4i);
 
-var<private> d : vec4<i32> = vec4<i32>(1, 2, 3, 4);
+var<private> d : vec4<i32> = vec4<i32>(1i, 2i, 3i, 4i);
 
 var<private> e : vec4<bool> = vec4<bool>(false, true, false, true);
 
@@ -226,13 +226,13 @@
 }
 )";
 
-  auto got = Run<FoldConstants>(src);
+    auto got = Run<FoldConstants>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(FoldConstantsTest, Function_Scalar_NoConversion) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var a : i32 = i32(123);
   var b : u32 = u32(123u);
@@ -241,22 +241,22 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
-  var a : i32 = 123;
+  var a : i32 = 123i;
   var b : u32 = 123u;
   var c : f32 = 123.0;
   var d : bool = true;
 }
 )";
 
-  auto got = Run<FoldConstants>(src);
+    auto got = Run<FoldConstants>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(FoldConstantsTest, Function_Scalar_Conversion) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var a : i32 = i32(123.0);
   var b : u32 = u32(123);
@@ -265,22 +265,22 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
-  var a : i32 = 123;
+  var a : i32 = 123i;
   var b : u32 = 123u;
   var c : f32 = 123.0;
   var d : bool = true;
 }
 )";
 
-  auto got = Run<FoldConstants>(src);
+    auto got = Run<FoldConstants>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(FoldConstantsTest, Function_Scalar_MultipleConversions) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var a : i32 = i32(u32(f32(u32(i32(123.0)))));
   var b : u32 = u32(i32(f32(i32(u32(123)))));
@@ -289,46 +289,46 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
-  var a : i32 = 123;
+  var a : i32 = 123i;
   var b : u32 = 123u;
   var c : f32 = 123.0;
   var d : bool = true;
 }
 )";
 
-  auto got = Run<FoldConstants>(src);
+    auto got = Run<FoldConstants>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(FoldConstantsTest, Function_Vector_NoConversion) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
-  var a : vec3<i32> = vec3<i32>(123);
+  var a : vec3<i32> = vec3<i32>(123i);
   var b : vec3<u32> = vec3<u32>(123u);
   var c : vec3<f32> = vec3<f32>(123.0);
   var d : vec3<bool> = vec3<bool>(true);
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
-  var a : vec3<i32> = vec3<i32>(123);
+  var a : vec3<i32> = vec3<i32>(123i);
   var b : vec3<u32> = vec3<u32>(123u);
   var c : vec3<f32> = vec3<f32>(123.0);
   var d : vec3<bool> = vec3<bool>(true);
 }
 )";
 
-  auto got = Run<FoldConstants>(src);
+    auto got = Run<FoldConstants>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(FoldConstantsTest, Function_Vector_Conversion) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var a : vec3<i32> = vec3<i32>(vec3<f32>(123.0));
   var b : vec3<u32> = vec3<u32>(vec3<i32>(123));
@@ -337,22 +337,22 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
-  var a : vec3<i32> = vec3<i32>(123);
+  var a : vec3<i32> = vec3<i32>(123i);
   var b : vec3<u32> = vec3<u32>(123u);
   var c : vec3<f32> = vec3<f32>(123.0);
   var d : vec3<bool> = vec3<bool>(true);
 }
 )";
 
-  auto got = Run<FoldConstants>(src);
+    auto got = Run<FoldConstants>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(FoldConstantsTest, Function_Vector_MultipleConversions) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var a : vec3<i32> = vec3<i32>(vec3<u32>(vec3<f32>(vec3<u32>(u32(123.0)))));
   var b : vec3<u32> = vec3<u32>(vec3<i32>(vec3<f32>(vec3<i32>(i32(123)))));
@@ -361,22 +361,22 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
-  var a : vec3<i32> = vec3<i32>(123);
+  var a : vec3<i32> = vec3<i32>(123i);
   var b : vec3<u32> = vec3<u32>(123u);
   var c : vec3<f32> = vec3<f32>(123.0);
   var d : vec3<bool> = vec3<bool>(true);
 }
 )";
 
-  auto got = Run<FoldConstants>(src);
+    auto got = Run<FoldConstants>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(FoldConstantsTest, Function_Vector_MixedSizeConversions) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var a : vec4<i32> = vec4<i32>(vec3<i32>(vec3<u32>(1u, 2u, 3u)), 4);
   var b : vec4<i32> = vec4<i32>(vec2<i32>(vec2<u32>(1u, 2u)), vec2<i32>(4, 5));
@@ -386,39 +386,39 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
-  var a : vec4<i32> = vec4<i32>(1, 2, 3, 4);
-  var b : vec4<i32> = vec4<i32>(1, 2, 4, 5);
-  var c : vec4<i32> = vec4<i32>(1, 2, 3, 4);
-  var d : vec4<i32> = vec4<i32>(1, 2, 3, 4);
+  var a : vec4<i32> = vec4<i32>(1i, 2i, 3i, 4i);
+  var b : vec4<i32> = vec4<i32>(1i, 2i, 4i, 5i);
+  var c : vec4<i32> = vec4<i32>(1i, 2i, 3i, 4i);
+  var d : vec4<i32> = vec4<i32>(1i, 2i, 3i, 4i);
   var e : vec4<bool> = vec4<bool>(false, true, false, true);
 }
 )";
 
-  auto got = Run<FoldConstants>(src);
+    auto got = Run<FoldConstants>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(FoldConstantsTest, Function_Vector_ConstantWithNonConstant) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var a : f32 = f32();
   var b : vec2<f32> = vec2<f32>(f32(i32(1)), a);
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var a : f32 = f32();
   var b : vec2<f32> = vec2<f32>(1.0, a);
 }
 )";
 
-  auto got = Run<FoldConstants>(src);
+    auto got = Run<FoldConstants>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 }  // namespace
diff --git a/src/tint/transform/fold_trivial_single_use_lets.cc b/src/tint/transform/fold_trivial_single_use_lets.cc
index a0f02a8..5bcdaa4 100644
--- a/src/tint/transform/fold_trivial_single_use_lets.cc
+++ b/src/tint/transform/fold_trivial_single_use_lets.cc
@@ -27,19 +27,19 @@
 namespace {
 
 const ast::VariableDeclStatement* AsTrivialLetDecl(const ast::Statement* stmt) {
-  auto* var_decl = stmt->As<ast::VariableDeclStatement>();
-  if (!var_decl) {
-    return nullptr;
-  }
-  auto* var = var_decl->variable;
-  if (!var->is_const) {
-    return nullptr;
-  }
-  auto* ctor = var->constructor;
-  if (!IsAnyOf<ast::IdentifierExpression, ast::LiteralExpression>(ctor)) {
-    return nullptr;
-  }
-  return var_decl;
+    auto* var_decl = stmt->As<ast::VariableDeclStatement>();
+    if (!var_decl) {
+        return nullptr;
+    }
+    auto* var = var_decl->variable;
+    if (!var->is_const) {
+        return nullptr;
+    }
+    auto* ctor = var->constructor;
+    if (!IsAnyOf<ast::IdentifierExpression, ast::LiteralExpression>(ctor)) {
+        return nullptr;
+    }
+    return var_decl;
 }
 
 }  // namespace
@@ -48,43 +48,41 @@
 
 FoldTrivialSingleUseLets::~FoldTrivialSingleUseLets() = default;
 
-void FoldTrivialSingleUseLets::Run(CloneContext& ctx,
-                                   const DataMap&,
-                                   DataMap&) const {
-  for (auto* node : ctx.src->ASTNodes().Objects()) {
-    if (auto* block = node->As<ast::BlockStatement>()) {
-      auto& stmts = block->statements;
-      for (size_t stmt_idx = 0; stmt_idx < stmts.size(); stmt_idx++) {
-        auto* stmt = stmts[stmt_idx];
-        if (auto* let_decl = AsTrivialLetDecl(stmt)) {
-          auto* let = let_decl->variable;
-          auto* sem_let = ctx.src->Sem().Get(let);
-          auto& users = sem_let->Users();
-          if (users.size() != 1) {
-            continue;  // Does not have a single user.
-          }
+void FoldTrivialSingleUseLets::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
+    for (auto* node : ctx.src->ASTNodes().Objects()) {
+        if (auto* block = node->As<ast::BlockStatement>()) {
+            auto& stmts = block->statements;
+            for (size_t stmt_idx = 0; stmt_idx < stmts.size(); stmt_idx++) {
+                auto* stmt = stmts[stmt_idx];
+                if (auto* let_decl = AsTrivialLetDecl(stmt)) {
+                    auto* let = let_decl->variable;
+                    auto* sem_let = ctx.src->Sem().Get(let);
+                    auto& users = sem_let->Users();
+                    if (users.size() != 1) {
+                        continue;  // Does not have a single user.
+                    }
 
-          auto* user = users[0];
-          auto* user_stmt = user->Stmt()->Declaration();
+                    auto* user = users[0];
+                    auto* user_stmt = user->Stmt()->Declaration();
 
-          for (size_t i = stmt_idx; i < stmts.size(); i++) {
-            if (user_stmt == stmts[i]) {
-              auto* user_expr = user->Declaration();
-              ctx.Remove(stmts, let_decl);
-              ctx.Replace(user_expr, ctx.Clone(let->constructor));
+                    for (size_t i = stmt_idx; i < stmts.size(); i++) {
+                        if (user_stmt == stmts[i]) {
+                            auto* user_expr = user->Declaration();
+                            ctx.Remove(stmts, let_decl);
+                            ctx.Replace(user_expr, ctx.Clone(let->constructor));
+                        }
+                        if (!AsTrivialLetDecl(stmts[i])) {
+                            // Stop if we hit a statement that isn't the single use of the
+                            // let, and isn't a let itself.
+                            break;
+                        }
+                    }
+                }
             }
-            if (!AsTrivialLetDecl(stmts[i])) {
-              // Stop if we hit a statement that isn't the single use of the
-              // let, and isn't a let itself.
-              break;
-            }
-          }
         }
-      }
     }
-  }
 
-  ctx.Clone();
+    ctx.Clone();
 }
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/fold_trivial_single_use_lets.h b/src/tint/transform/fold_trivial_single_use_lets.h
index d343b76..4036f02 100644
--- a/src/tint/transform/fold_trivial_single_use_lets.h
+++ b/src/tint/transform/fold_trivial_single_use_lets.h
@@ -33,25 +33,22 @@
 ///   single usage.
 /// These rules prevent any hoisting of the let that may affect execution
 /// behaviour.
-class FoldTrivialSingleUseLets final
-    : public Castable<FoldTrivialSingleUseLets, Transform> {
- public:
-  /// Constructor
-  FoldTrivialSingleUseLets();
+class FoldTrivialSingleUseLets final : public Castable<FoldTrivialSingleUseLets, Transform> {
+  public:
+    /// Constructor
+    FoldTrivialSingleUseLets();
 
-  /// Destructor
-  ~FoldTrivialSingleUseLets() override;
+    /// Destructor
+    ~FoldTrivialSingleUseLets() override;
 
- protected:
-  /// Runs the transform using the CloneContext built for transforming a
-  /// program. Run() is responsible for calling Clone() on the CloneContext.
-  /// @param ctx the CloneContext primed with the input program and
-  /// ProgramBuilder
-  /// @param inputs optional extra transform-specific input data
-  /// @param outputs optional extra transform-specific output data
-  void Run(CloneContext& ctx,
-           const DataMap& inputs,
-           DataMap& outputs) const override;
+  protected:
+    /// Runs the transform using the CloneContext built for transforming a
+    /// program. Run() is responsible for calling Clone() on the CloneContext.
+    /// @param ctx the CloneContext primed with the input program and
+    /// ProgramBuilder
+    /// @param inputs optional extra transform-specific input data
+    /// @param outputs optional extra transform-specific output data
+    void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const override;
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/fold_trivial_single_use_lets_test.cc b/src/tint/transform/fold_trivial_single_use_lets_test.cc
index e08c191..00159e9 100644
--- a/src/tint/transform/fold_trivial_single_use_lets_test.cc
+++ b/src/tint/transform/fold_trivial_single_use_lets_test.cc
@@ -22,35 +22,35 @@
 using FoldTrivialSingleUseLetsTest = TransformTest;
 
 TEST_F(FoldTrivialSingleUseLetsTest, EmptyModule) {
-  auto* src = "";
-  auto* expect = "";
+    auto* src = "";
+    auto* expect = "";
 
-  auto got = Run<FoldTrivialSingleUseLets>(src);
+    auto got = Run<FoldTrivialSingleUseLets>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(FoldTrivialSingleUseLetsTest, Single) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let x = 1;
   _ = x;
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   _ = 1;
 }
 )";
 
-  auto got = Run<FoldTrivialSingleUseLets>(src);
+    auto got = Run<FoldTrivialSingleUseLets>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(FoldTrivialSingleUseLetsTest, Multiple) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let x = 1;
   let y = 2;
@@ -59,19 +59,19 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   _ = ((1 + 2) + 3);
 }
 )";
 
-  auto got = Run<FoldTrivialSingleUseLets>(src);
+    auto got = Run<FoldTrivialSingleUseLets>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(FoldTrivialSingleUseLetsTest, Chained) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let x = 1;
   let y = x;
@@ -80,19 +80,19 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   _ = 1;
 }
 )";
 
-  auto got = Run<FoldTrivialSingleUseLets>(src);
+    auto got = Run<FoldTrivialSingleUseLets>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(FoldTrivialSingleUseLetsTest, NoFold_NonTrivialLet) {
-  auto* src = R"(
+    auto* src = R"(
 fn function_with_posssible_side_effect() -> i32 {
   return 1;
 }
@@ -104,15 +104,15 @@
 }
 )";
 
-  auto* expect = src;
+    auto* expect = src;
 
-  auto got = Run<FoldTrivialSingleUseLets>(src);
+    auto got = Run<FoldTrivialSingleUseLets>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(FoldTrivialSingleUseLetsTest, NoFold_NonTrivialLet_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let x = 1;
   let y = function_with_posssible_side_effect();
@@ -124,15 +124,15 @@
 }
 )";
 
-  auto* expect = src;
+    auto* expect = src;
 
-  auto got = Run<FoldTrivialSingleUseLets>(src);
+    auto got = Run<FoldTrivialSingleUseLets>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(FoldTrivialSingleUseLetsTest, NoFold_UseInSubBlock) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let x = 1;
   {
@@ -141,30 +141,30 @@
 }
 )";
 
-  auto* expect = src;
+    auto* expect = src;
 
-  auto got = Run<FoldTrivialSingleUseLets>(src);
+    auto got = Run<FoldTrivialSingleUseLets>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(FoldTrivialSingleUseLetsTest, NoFold_MultipleUses) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let x = 1;
   _ = (x + x);
 }
 )";
 
-  auto* expect = src;
+    auto* expect = src;
 
-  auto got = Run<FoldTrivialSingleUseLets>(src);
+    auto got = Run<FoldTrivialSingleUseLets>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(FoldTrivialSingleUseLetsTest, NoFold_Shadowing) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var y = 1;
   let x = y;
@@ -175,11 +175,11 @@
 }
 )";
 
-  auto* expect = src;
+    auto* expect = src;
 
-  auto got = Run<FoldTrivialSingleUseLets>(src);
+    auto got = Run<FoldTrivialSingleUseLets>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 }  // namespace
diff --git a/src/tint/transform/for_loop_to_loop.cc b/src/tint/transform/for_loop_to_loop.cc
index 14d5edb..8fff0a8 100644
--- a/src/tint/transform/for_loop_to_loop.cc
+++ b/src/tint/transform/for_loop_to_loop.cc
@@ -25,50 +25,48 @@
 ForLoopToLoop::~ForLoopToLoop() = default;
 
 bool ForLoopToLoop::ShouldRun(const Program* program, const DataMap&) const {
-  for (auto* node : program->ASTNodes().Objects()) {
-    if (node->Is<ast::ForLoopStatement>()) {
-      return true;
+    for (auto* node : program->ASTNodes().Objects()) {
+        if (node->Is<ast::ForLoopStatement>()) {
+            return true;
+        }
     }
-  }
-  return false;
+    return false;
 }
 
 void ForLoopToLoop::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
-  ctx.ReplaceAll(
-      [&](const ast::ForLoopStatement* for_loop) -> const ast::Statement* {
+    ctx.ReplaceAll([&](const ast::ForLoopStatement* for_loop) -> const ast::Statement* {
         ast::StatementList stmts;
         if (auto* cond = for_loop->condition) {
-          // !condition
-          auto* not_cond = ctx.dst->create<ast::UnaryOpExpression>(
-              ast::UnaryOp::kNot, ctx.Clone(cond));
+            // !condition
+            auto* not_cond =
+                ctx.dst->create<ast::UnaryOpExpression>(ast::UnaryOp::kNot, ctx.Clone(cond));
 
-          // { break; }
-          auto* break_body =
-              ctx.dst->Block(ctx.dst->create<ast::BreakStatement>());
+            // { break; }
+            auto* break_body = ctx.dst->Block(ctx.dst->create<ast::BreakStatement>());
 
-          // if (!condition) { break; }
-          stmts.emplace_back(ctx.dst->If(not_cond, break_body));
+            // if (!condition) { break; }
+            stmts.emplace_back(ctx.dst->If(not_cond, break_body));
         }
         for (auto* stmt : for_loop->body->statements) {
-          stmts.emplace_back(ctx.Clone(stmt));
+            stmts.emplace_back(ctx.Clone(stmt));
         }
 
         const ast::BlockStatement* continuing = nullptr;
         if (auto* cont = for_loop->continuing) {
-          continuing = ctx.dst->Block(ctx.Clone(cont));
+            continuing = ctx.dst->Block(ctx.Clone(cont));
         }
 
         auto* body = ctx.dst->Block(stmts);
         auto* loop = ctx.dst->create<ast::LoopStatement>(body, continuing);
 
         if (auto* init = for_loop->initializer) {
-          return ctx.dst->Block(ctx.Clone(init), loop);
+            return ctx.dst->Block(ctx.Clone(init), loop);
         }
 
         return loop;
-      });
+    });
 
-  ctx.Clone();
+    ctx.Clone();
 }
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/for_loop_to_loop.h b/src/tint/transform/for_loop_to_loop.h
index 54286d4..5ab690a 100644
--- a/src/tint/transform/for_loop_to_loop.h
+++ b/src/tint/transform/for_loop_to_loop.h
@@ -22,29 +22,26 @@
 /// ForLoopToLoop is a Transform that converts a for-loop statement into a loop
 /// statement. This is required by the SPIR-V writer.
 class ForLoopToLoop final : public Castable<ForLoopToLoop, Transform> {
- public:
-  /// Constructor
-  ForLoopToLoop();
+  public:
+    /// Constructor
+    ForLoopToLoop();
 
-  /// Destructor
-  ~ForLoopToLoop() override;
+    /// Destructor
+    ~ForLoopToLoop() override;
 
-  /// @param program the program to inspect
-  /// @param data optional extra transform-specific input data
-  /// @returns true if this transform should be run for the given program
-  bool ShouldRun(const Program* program,
-                 const DataMap& data = {}) const override;
+    /// @param program the program to inspect
+    /// @param data optional extra transform-specific input data
+    /// @returns true if this transform should be run for the given program
+    bool ShouldRun(const Program* program, const DataMap& data = {}) const override;
 
- protected:
-  /// Runs the transform using the CloneContext built for transforming a
-  /// program. Run() is responsible for calling Clone() on the CloneContext.
-  /// @param ctx the CloneContext primed with the input program and
-  /// ProgramBuilder
-  /// @param inputs optional extra transform-specific input data
-  /// @param outputs optional extra transform-specific output data
-  void Run(CloneContext& ctx,
-           const DataMap& inputs,
-           DataMap& outputs) const override;
+  protected:
+    /// Runs the transform using the CloneContext built for transforming a
+    /// program. Run() is responsible for calling Clone() on the CloneContext.
+    /// @param ctx the CloneContext primed with the input program and
+    /// ProgramBuilder
+    /// @param inputs optional extra transform-specific input data
+    /// @param outputs optional extra transform-specific output data
+    void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const override;
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/for_loop_to_loop_test.cc b/src/tint/transform/for_loop_to_loop_test.cc
index 84ffa98..172e1fc 100644
--- a/src/tint/transform/for_loop_to_loop_test.cc
+++ b/src/tint/transform/for_loop_to_loop_test.cc
@@ -22,13 +22,13 @@
 using ForLoopToLoopTest = TransformTest;
 
 TEST_F(ForLoopToLoopTest, ShouldRunEmptyModule) {
-  auto* src = R"()";
+    auto* src = R"()";
 
-  EXPECT_FALSE(ShouldRun<ForLoopToLoop>(src));
+    EXPECT_FALSE(ShouldRun<ForLoopToLoop>(src));
 }
 
 TEST_F(ForLoopToLoopTest, ShouldRunHasForLoop) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   for (;;) {
     break;
@@ -36,21 +36,21 @@
 }
 )";
 
-  EXPECT_TRUE(ShouldRun<ForLoopToLoop>(src));
+    EXPECT_TRUE(ShouldRun<ForLoopToLoop>(src));
 }
 
 TEST_F(ForLoopToLoopTest, EmptyModule) {
-  auto* src = "";
-  auto* expect = src;
+    auto* src = "";
+    auto* expect = src;
 
-  auto got = Run<ForLoopToLoop>(src);
+    auto got = Run<ForLoopToLoop>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 // Test an empty for loop.
 TEST_F(ForLoopToLoopTest, Empty) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   for (;;) {
     break;
@@ -58,7 +58,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   loop {
     break;
@@ -66,14 +66,14 @@
 }
 )";
 
-  auto got = Run<ForLoopToLoop>(src);
+    auto got = Run<ForLoopToLoop>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 // Test a for loop with non-empty body.
 TEST_F(ForLoopToLoopTest, Body) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   for (;;) {
     discard;
@@ -81,7 +81,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   loop {
     discard;
@@ -89,14 +89,14 @@
 }
 )";
 
-  auto got = Run<ForLoopToLoop>(src);
+    auto got = Run<ForLoopToLoop>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 // Test a for loop declaring a variable in the initializer statement.
 TEST_F(ForLoopToLoopTest, InitializerStatementDecl) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   for (var i: i32;;) {
     break;
@@ -104,7 +104,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   {
     var i : i32;
@@ -115,15 +115,15 @@
 }
 )";
 
-  auto got = Run<ForLoopToLoop>(src);
+    auto got = Run<ForLoopToLoop>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 // Test a for loop declaring and initializing a variable in the initializer
 // statement.
 TEST_F(ForLoopToLoopTest, InitializerStatementDeclEqual) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   for (var i: i32 = 0;;) {
     break;
@@ -131,7 +131,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   {
     var i : i32 = 0;
@@ -142,14 +142,14 @@
 }
 )";
 
-  auto got = Run<ForLoopToLoop>(src);
+    auto got = Run<ForLoopToLoop>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 // Test a for loop declaring a const variable in the initializer statement.
 TEST_F(ForLoopToLoopTest, InitializerStatementConstDecl) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   for (let i: i32 = 0;;) {
     break;
@@ -157,7 +157,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   {
     let i : i32 = 0;
@@ -168,14 +168,14 @@
 }
 )";
 
-  auto got = Run<ForLoopToLoop>(src);
+    auto got = Run<ForLoopToLoop>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 // Test a for loop assigning a variable in the initializer statement.
 TEST_F(ForLoopToLoopTest, InitializerStatementAssignment) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var i: i32;
   for (i = 0;;) {
@@ -184,7 +184,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var i : i32;
   {
@@ -196,14 +196,14 @@
 }
 )";
 
-  auto got = Run<ForLoopToLoop>(src);
+    auto got = Run<ForLoopToLoop>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 // Test a for loop calling a function in the initializer statement.
 TEST_F(ForLoopToLoopTest, InitializerStatementFuncCall) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(x : i32, y : i32) {
 }
 
@@ -216,7 +216,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(x : i32, y : i32) {
 }
 
@@ -232,21 +232,21 @@
 }
 )";
 
-  auto got = Run<ForLoopToLoop>(src);
+    auto got = Run<ForLoopToLoop>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 // Test a for loop with a break condition
 TEST_F(ForLoopToLoopTest, BreakCondition) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   for (; 0 == 1;) {
   }
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   loop {
     if (!((0 == 1))) {
@@ -256,14 +256,14 @@
 }
 )";
 
-  auto got = Run<ForLoopToLoop>(src);
+    auto got = Run<ForLoopToLoop>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 // Test a for loop assigning a variable in the continuing statement.
 TEST_F(ForLoopToLoopTest, ContinuingAssignment) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var x: i32;
   for (;;x = 2) {
@@ -272,7 +272,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var x : i32;
   loop {
@@ -285,14 +285,14 @@
 }
 )";
 
-  auto got = Run<ForLoopToLoop>(src);
+    auto got = Run<ForLoopToLoop>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 // Test a for loop calling a function in the continuing statement.
 TEST_F(ForLoopToLoopTest, ContinuingFuncCall) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(x : i32, y : i32) {
 }
 
@@ -305,7 +305,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(x : i32, y : i32) {
 }
 
@@ -322,14 +322,14 @@
 }
 )";
 
-  auto got = Run<ForLoopToLoop>(src);
+    auto got = Run<ForLoopToLoop>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 // Test a for loop with all statements non-empty.
 TEST_F(ForLoopToLoopTest, All) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var a : i32;
   for(var i : i32 = 0; i < 4; i = i + 1) {
@@ -341,7 +341,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var a : i32;
   {
@@ -363,9 +363,9 @@
 }
 )";
 
-  auto got = Run<ForLoopToLoop>(src);
+    auto got = Run<ForLoopToLoop>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 }  // namespace
diff --git a/src/tint/transform/localize_struct_array_assignment.cc b/src/tint/transform/localize_struct_array_assignment.cc
index e888c01..d6cdded 100644
--- a/src/tint/transform/localize_struct_array_assignment.cc
+++ b/src/tint/transform/localize_struct_array_assignment.cc
@@ -22,7 +22,7 @@
 #include "src/tint/program_builder.h"
 #include "src/tint/sem/expression.h"
 #include "src/tint/sem/member_accessor_expression.h"
-#include "src/tint/sem/reference_type.h"
+#include "src/tint/sem/reference.h"
 #include "src/tint/sem/statement.h"
 #include "src/tint/sem/variable.h"
 #include "src/tint/transform/simplify_pointers.h"
@@ -34,189 +34,166 @@
 
 /// Private implementation of LocalizeStructArrayAssignment transform
 class LocalizeStructArrayAssignment::State {
- private:
-  CloneContext& ctx;
-  ProgramBuilder& b;
+  private:
+    CloneContext& ctx;
+    ProgramBuilder& b;
 
-  /// Returns true if `expr` contains an index accessor expression to a
-  /// structure member of array type.
-  bool ContainsStructArrayIndex(const ast::Expression* expr) {
-    bool result = false;
-    ast::TraverseExpressions(
-        expr, b.Diagnostics(), [&](const ast::IndexAccessorExpression* ia) {
-          // Indexing using a runtime value?
-          auto* idx_sem = ctx.src->Sem().Get(ia->index);
-          if (!idx_sem->ConstantValue().IsValid()) {
-            // Indexing a member access expr?
-            if (auto* ma = ia->object->As<ast::MemberAccessorExpression>()) {
-              // That accesses an array?
-              if (ctx.src->TypeOf(ma)->UnwrapRef()->Is<sem::Array>()) {
-                result = true;
-                return ast::TraverseAction::Stop;
-              }
+    /// Returns true if `expr` contains an index accessor expression to a
+    /// structure member of array type.
+    bool ContainsStructArrayIndex(const ast::Expression* expr) {
+        bool result = false;
+        ast::TraverseExpressions(
+            expr, b.Diagnostics(), [&](const ast::IndexAccessorExpression* ia) {
+                // Indexing using a runtime value?
+                auto* idx_sem = ctx.src->Sem().Get(ia->index);
+                if (!idx_sem->ConstantValue().IsValid()) {
+                    // Indexing a member access expr?
+                    if (auto* ma = ia->object->As<ast::MemberAccessorExpression>()) {
+                        // That accesses an array?
+                        if (ctx.src->TypeOf(ma)->UnwrapRef()->Is<sem::Array>()) {
+                            result = true;
+                            return ast::TraverseAction::Stop;
+                        }
+                    }
+                }
+                return ast::TraverseAction::Descend;
+            });
+
+        return result;
+    }
+
+    // Returns the type and storage class of the originating variable of the lhs
+    // of the assignment statement.
+    // See https://www.w3.org/TR/WGSL/#originating-variable-section
+    std::pair<const sem::Type*, ast::StorageClass> GetOriginatingTypeAndStorageClass(
+        const ast::AssignmentStatement* assign_stmt) {
+        auto* source_var = ctx.src->Sem().Get(assign_stmt->lhs)->SourceVariable();
+        if (!source_var) {
+            TINT_ICE(Transform, b.Diagnostics())
+                << "Unable to determine originating variable for lhs of assignment "
+                   "statement";
+            return {};
+        }
+
+        auto* type = source_var->Type();
+        if (auto* ref = type->As<sem::Reference>()) {
+            return {ref->StoreType(), ref->StorageClass()};
+        } else if (auto* ptr = type->As<sem::Pointer>()) {
+            return {ptr->StoreType(), ptr->StorageClass()};
+        }
+
+        TINT_ICE(Transform, b.Diagnostics())
+            << "Expecting to find variable of type pointer or reference on lhs "
+               "of assignment statement";
+        return {};
+    }
+
+  public:
+    /// Constructor
+    /// @param ctx_in the CloneContext primed with the input program and
+    /// ProgramBuilder
+    explicit State(CloneContext& ctx_in) : ctx(ctx_in), b(*ctx_in.dst) {}
+
+    /// Runs the transform
+    void Run() {
+        struct Shared {
+            bool process_nested_nodes = false;
+            ast::StatementList insert_before_stmts;
+            ast::StatementList insert_after_stmts;
+        } s;
+
+        ctx.ReplaceAll([&](const ast::AssignmentStatement* assign_stmt) -> const ast::Statement* {
+            // Process if it's an assignment statement to a dynamically indexed array
+            // within a struct on a function or private storage variable. This
+            // specific use-case is what FXC fails to compile with:
+            // error X3500: array reference cannot be used as an l-value; not natively
+            // addressable
+            if (!ContainsStructArrayIndex(assign_stmt->lhs)) {
+                return nullptr;
             }
-          }
-          return ast::TraverseAction::Descend;
+            auto og = GetOriginatingTypeAndStorageClass(assign_stmt);
+            if (!(og.first->Is<sem::Struct>() && (og.second == ast::StorageClass::kFunction ||
+                                                  og.second == ast::StorageClass::kPrivate))) {
+                return nullptr;
+            }
+
+            // Reset shared state for this assignment statement
+            s = Shared{};
+
+            const ast::Expression* new_lhs = nullptr;
+            {
+                TINT_SCOPED_ASSIGNMENT(s.process_nested_nodes, true);
+                new_lhs = ctx.Clone(assign_stmt->lhs);
+            }
+
+            auto* new_assign_stmt = b.Assign(new_lhs, ctx.Clone(assign_stmt->rhs));
+
+            // Combine insert_before_stmts + new_assign_stmt + insert_after_stmts into
+            // a block and return it
+            ast::StatementList stmts = std::move(s.insert_before_stmts);
+            stmts.reserve(1 + s.insert_after_stmts.size());
+            stmts.emplace_back(new_assign_stmt);
+            stmts.insert(stmts.end(), s.insert_after_stmts.begin(), s.insert_after_stmts.end());
+
+            return b.Block(std::move(stmts));
         });
 
-    return result;
-  }
+        ctx.ReplaceAll(
+            [&](const ast::IndexAccessorExpression* index_access) -> const ast::Expression* {
+                if (!s.process_nested_nodes) {
+                    return nullptr;
+                }
 
-  // Returns the type and storage class of the originating variable of the lhs
-  // of the assignment statement.
-  // See https://www.w3.org/TR/WGSL/#originating-variable-section
-  std::pair<const sem::Type*, ast::StorageClass>
-  GetOriginatingTypeAndStorageClass(
-      const ast::AssignmentStatement* assign_stmt) {
-    // Get first IdentifierExpr from lhs of assignment, which should resolve to
-    // the pointer or reference of the originating variable of the assignment.
-    // TraverseExpressions traverses left to right, and this code depends on the
-    // fact that for an assignment statement, the variable will be the left-most
-    // expression.
-    // TODO(crbug.com/tint/1341): do this in the Resolver, setting the
-    // originating variable on sem::Expression.
-    const ast::IdentifierExpression* ident = nullptr;
-    ast::TraverseExpressions(assign_stmt->lhs, b.Diagnostics(),
-                             [&](const ast::IdentifierExpression* id) {
-                               ident = id;
-                               return ast::TraverseAction::Stop;
-                             });
-    auto* sem_var_user = ctx.src->Sem().Get<sem::VariableUser>(ident);
-    if (!sem_var_user) {
-      TINT_ICE(Transform, b.Diagnostics())
-          << "Expected to find variable of lhs of assignment statement";
-      return {};
+                // Indexing a member access expr?
+                auto* mem_access = index_access->object->As<ast::MemberAccessorExpression>();
+                if (!mem_access) {
+                    return nullptr;
+                }
+
+                // Process any nested IndexAccessorExpressions
+                mem_access = ctx.Clone(mem_access);
+
+                // Store the address of the member access into a let as we need to read
+                // the value twice e.g. let tint_symbol = &(s.a1);
+                auto mem_access_ptr = b.Sym();
+                s.insert_before_stmts.push_back(
+                    b.Decl(b.Let(mem_access_ptr, nullptr, b.AddressOf(mem_access))));
+
+                // Disable further transforms when cloning
+                TINT_SCOPED_ASSIGNMENT(s.process_nested_nodes, false);
+
+                // Copy entire array out of struct into local temp var
+                // e.g. var tint_symbol_1 = *(tint_symbol);
+                auto tmp_var = b.Sym();
+                s.insert_before_stmts.push_back(
+                    b.Decl(b.Var(tmp_var, nullptr, b.Deref(mem_access_ptr))));
+
+                // Replace input index_access with a clone of itself, but with its
+                // .object replaced by the new temp var. This is returned from this
+                // function to modify the original assignment statement. e.g.
+                // tint_symbol_1[uniforms.i]
+                auto* new_index_access = b.IndexAccessor(tmp_var, ctx.Clone(index_access->index));
+
+                // Assign temp var back to array
+                // e.g. *(tint_symbol) = tint_symbol_1;
+                auto* assign_rhs_to_temp = b.Assign(b.Deref(mem_access_ptr), tmp_var);
+                s.insert_after_stmts.insert(s.insert_after_stmts.begin(),
+                                            assign_rhs_to_temp);  // push_front
+
+                return new_index_access;
+            });
+
+        ctx.Clone();
     }
-
-    auto* var = sem_var_user->Variable();
-    if (auto* ptr = var->Type()->As<sem::Pointer>()) {
-      return {ptr->StoreType(), ptr->StorageClass()};
-    }
-
-    auto* ref = var->Type()->As<sem::Reference>();
-    if (!ref) {
-      TINT_ICE(Transform, b.Diagnostics())
-          << "Expecting to find variable of type pointer or reference on lhs "
-             "of assignment statement";
-      return {};
-    }
-
-    return {ref->StoreType(), ref->StorageClass()};
-  }
-
- public:
-  /// Constructor
-  /// @param ctx_in the CloneContext primed with the input program and
-  /// ProgramBuilder
-  explicit State(CloneContext& ctx_in) : ctx(ctx_in), b(*ctx_in.dst) {}
-
-  /// Runs the transform
-  void Run() {
-    struct Shared {
-      bool process_nested_nodes = false;
-      ast::StatementList insert_before_stmts;
-      ast::StatementList insert_after_stmts;
-    } s;
-
-    ctx.ReplaceAll([&](const ast::AssignmentStatement* assign_stmt)
-                       -> const ast::Statement* {
-      // Process if it's an assignment statement to a dynamically indexed array
-      // within a struct on a function or private storage variable. This
-      // specific use-case is what FXC fails to compile with:
-      // error X3500: array reference cannot be used as an l-value; not natively
-      // addressable
-      if (!ContainsStructArrayIndex(assign_stmt->lhs)) {
-        return nullptr;
-      }
-      auto og = GetOriginatingTypeAndStorageClass(assign_stmt);
-      if (!(og.first->Is<sem::Struct>() &&
-            (og.second == ast::StorageClass::kFunction ||
-             og.second == ast::StorageClass::kPrivate))) {
-        return nullptr;
-      }
-
-      // Reset shared state for this assignment statement
-      s = Shared{};
-
-      const ast::Expression* new_lhs = nullptr;
-      {
-        TINT_SCOPED_ASSIGNMENT(s.process_nested_nodes, true);
-        new_lhs = ctx.Clone(assign_stmt->lhs);
-      }
-
-      auto* new_assign_stmt = b.Assign(new_lhs, ctx.Clone(assign_stmt->rhs));
-
-      // Combine insert_before_stmts + new_assign_stmt + insert_after_stmts into
-      // a block and return it
-      ast::StatementList stmts = std::move(s.insert_before_stmts);
-      stmts.reserve(1 + s.insert_after_stmts.size());
-      stmts.emplace_back(new_assign_stmt);
-      stmts.insert(stmts.end(), s.insert_after_stmts.begin(),
-                   s.insert_after_stmts.end());
-
-      return b.Block(std::move(stmts));
-    });
-
-    ctx.ReplaceAll([&](const ast::IndexAccessorExpression* index_access)
-                       -> const ast::Expression* {
-      if (!s.process_nested_nodes) {
-        return nullptr;
-      }
-
-      // Indexing a member access expr?
-      auto* mem_access =
-          index_access->object->As<ast::MemberAccessorExpression>();
-      if (!mem_access) {
-        return nullptr;
-      }
-
-      // Process any nested IndexAccessorExpressions
-      mem_access = ctx.Clone(mem_access);
-
-      // Store the address of the member access into a let as we need to read
-      // the value twice e.g. let tint_symbol = &(s.a1);
-      auto mem_access_ptr = b.Sym();
-      s.insert_before_stmts.push_back(
-          b.Decl(b.Const(mem_access_ptr, nullptr, b.AddressOf(mem_access))));
-
-      // Disable further transforms when cloning
-      TINT_SCOPED_ASSIGNMENT(s.process_nested_nodes, false);
-
-      // Copy entire array out of struct into local temp var
-      // e.g. var tint_symbol_1 = *(tint_symbol);
-      auto tmp_var = b.Sym();
-      s.insert_before_stmts.push_back(
-          b.Decl(b.Var(tmp_var, nullptr, b.Deref(mem_access_ptr))));
-
-      // Replace input index_access with a clone of itself, but with its
-      // .object replaced by the new temp var. This is returned from this
-      // function to modify the original assignment statement. e.g.
-      // tint_symbol_1[uniforms.i]
-      auto* new_index_access =
-          b.IndexAccessor(tmp_var, ctx.Clone(index_access->index));
-
-      // Assign temp var back to array
-      // e.g. *(tint_symbol) = tint_symbol_1;
-      auto* assign_rhs_to_temp = b.Assign(b.Deref(mem_access_ptr), tmp_var);
-      s.insert_after_stmts.insert(s.insert_after_stmts.begin(),
-                                  assign_rhs_to_temp);  // push_front
-
-      return new_index_access;
-    });
-
-    ctx.Clone();
-  }
 };
 
 LocalizeStructArrayAssignment::LocalizeStructArrayAssignment() = default;
 
 LocalizeStructArrayAssignment::~LocalizeStructArrayAssignment() = default;
 
-void LocalizeStructArrayAssignment::Run(CloneContext& ctx,
-                                        const DataMap&,
-                                        DataMap&) const {
-  State state(ctx);
-  state.Run();
+void LocalizeStructArrayAssignment::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
+    State state(ctx);
+    state.Run();
 }
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/localize_struct_array_assignment.h b/src/tint/transform/localize_struct_array_assignment.h
index 2c45203..129c849 100644
--- a/src/tint/transform/localize_struct_array_assignment.h
+++ b/src/tint/transform/localize_struct_array_assignment.h
@@ -27,28 +27,25 @@
 ///
 /// @note Depends on the following transforms to have been run first:
 /// * SimplifyPointers
-class LocalizeStructArrayAssignment
-    : public Castable<LocalizeStructArrayAssignment, Transform> {
- public:
-  /// Constructor
-  LocalizeStructArrayAssignment();
+class LocalizeStructArrayAssignment : public Castable<LocalizeStructArrayAssignment, Transform> {
+  public:
+    /// Constructor
+    LocalizeStructArrayAssignment();
 
-  /// Destructor
-  ~LocalizeStructArrayAssignment() override;
+    /// Destructor
+    ~LocalizeStructArrayAssignment() override;
 
- protected:
-  /// Runs the transform using the CloneContext built for transforming a
-  /// program. Run() is responsible for calling Clone() on the CloneContext.
-  /// @param ctx the CloneContext primed with the input program and
-  /// ProgramBuilder
-  /// @param inputs optional extra transform-specific input data
-  /// @param outputs optional extra transform-specific output data
-  void Run(CloneContext& ctx,
-           const DataMap& inputs,
-           DataMap& outputs) const override;
+  protected:
+    /// Runs the transform using the CloneContext built for transforming a
+    /// program. Run() is responsible for calling Clone() on the CloneContext.
+    /// @param ctx the CloneContext primed with the input program and
+    /// ProgramBuilder
+    /// @param inputs optional extra transform-specific input data
+    /// @param outputs optional extra transform-specific output data
+    void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const override;
 
- private:
-  class State;
+  private:
+    class State;
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/localize_struct_array_assignment_test.cc b/src/tint/transform/localize_struct_array_assignment_test.cc
index d202785..ee6df9f 100644
--- a/src/tint/transform/localize_struct_array_assignment_test.cc
+++ b/src/tint/transform/localize_struct_array_assignment_test.cc
@@ -24,15 +24,14 @@
 using LocalizeStructArrayAssignmentTest = TransformTest;
 
 TEST_F(LocalizeStructArrayAssignmentTest, EmptyModule) {
-  auto* src = R"()";
-  auto* expect = src;
-  auto got =
-      Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
-  EXPECT_EQ(expect, str(got));
+    auto* src = R"()";
+    auto* expect = src;
+    auto got = Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(LocalizeStructArrayAssignmentTest, StructArray) {
-  auto* src = R"(
+    auto* src = R"(
 struct Uniforms {
   i : u32,
 };
@@ -55,7 +54,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct Uniforms {
   i : u32,
 }
@@ -83,13 +82,12 @@
 }
 )";
 
-  auto got =
-      Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
-  EXPECT_EQ(expect, str(got));
+    auto got = Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(LocalizeStructArrayAssignmentTest, StructArray_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   var v : InnerS;
@@ -112,7 +110,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   var v : InnerS;
@@ -140,13 +138,12 @@
 }
 )";
 
-  auto got =
-      Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
-  EXPECT_EQ(expect, str(got));
+    auto got = Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(LocalizeStructArrayAssignmentTest, StructStructArray) {
-  auto* src = R"(
+    auto* src = R"(
 struct Uniforms {
   i : u32,
 };
@@ -173,7 +170,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct Uniforms {
   i : u32,
 }
@@ -205,13 +202,12 @@
 }
 )";
 
-  auto got =
-      Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
-  EXPECT_EQ(expect, str(got));
+    auto got = Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(LocalizeStructArrayAssignmentTest, StructStructArray_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   var v : InnerS;
@@ -238,7 +234,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   var v : InnerS;
@@ -270,13 +266,12 @@
 }
 )";
 
-  auto got =
-      Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
-  EXPECT_EQ(expect, str(got));
+    auto got = Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(LocalizeStructArrayAssignmentTest, StructArrayArray) {
-  auto* src = R"(
+    auto* src = R"(
 struct Uniforms {
   i : u32,
   j : u32,
@@ -300,7 +295,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct Uniforms {
   i : u32,
   j : u32,
@@ -329,13 +324,12 @@
 }
 )";
 
-  auto got =
-      Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
-  EXPECT_EQ(expect, str(got));
+    auto got = Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(LocalizeStructArrayAssignmentTest, StructArrayStruct) {
-  auto* src = R"(
+    auto* src = R"(
 struct Uniforms {
   i : u32,
 };
@@ -362,7 +356,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct Uniforms {
   i : u32,
 }
@@ -394,13 +388,12 @@
 }
 )";
 
-  auto got =
-      Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
-  EXPECT_EQ(expect, str(got));
+    auto got = Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(LocalizeStructArrayAssignmentTest, StructArrayStructArray) {
-  auto* src = R"(
+    auto* src = R"(
 struct Uniforms {
   i : u32,
   j : u32,
@@ -428,7 +421,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct Uniforms {
   i : u32,
   j : u32,
@@ -464,13 +457,12 @@
 }
 )";
 
-  auto got =
-      Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
-  EXPECT_EQ(expect, str(got));
+    auto got = Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(LocalizeStructArrayAssignmentTest, IndexingWithSideEffectFunc) {
-  auto* src = R"(
+    auto* src = R"(
 struct Uniforms {
   i : u32,
   j : u32,
@@ -504,7 +496,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct Uniforms {
   i : u32,
   j : u32,
@@ -547,14 +539,12 @@
 }
 )";
 
-  auto got =
-      Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
-  EXPECT_EQ(expect, str(got));
+    auto got = Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(LocalizeStructArrayAssignmentTest,
-       IndexingWithSideEffectFunc_OutOfOrder) {
-  auto* src = R"(
+TEST_F(LocalizeStructArrayAssignmentTest, IndexingWithSideEffectFunc_OutOfOrder) {
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   var v : InnerS;
@@ -588,7 +578,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   var v : InnerS;
@@ -631,13 +621,12 @@
 }
 )";
 
-  auto got =
-      Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
-  EXPECT_EQ(expect, str(got));
+    auto got = Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(LocalizeStructArrayAssignmentTest, ViaPointerArg) {
-  auto* src = R"(
+    auto* src = R"(
 struct Uniforms {
   i : u32,
 };
@@ -661,7 +650,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct Uniforms {
   i : u32,
 }
@@ -693,13 +682,12 @@
 }
 )";
 
-  auto got =
-      Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
-  EXPECT_EQ(expect, str(got));
+    auto got = Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(LocalizeStructArrayAssignmentTest, ViaPointerArg_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   var s1 : OuterS;
@@ -725,7 +713,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   var s1 : OuterS;
@@ -757,13 +745,12 @@
 }
 )";
 
-  auto got =
-      Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
-  EXPECT_EQ(expect, str(got));
+    auto got = Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(LocalizeStructArrayAssignmentTest, ViaPointerVar) {
-  auto* src = R"(
+    auto* src = R"(
 struct Uniforms {
   i : u32,
 };
@@ -791,7 +778,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct Uniforms {
   i : u32,
 }
@@ -824,13 +811,12 @@
 }
 )";
 
-  auto got =
-      Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
-  EXPECT_EQ(expect, str(got));
+    auto got = Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(LocalizeStructArrayAssignmentTest, VectorAssignment) {
-  auto* src = R"(
+    auto* src = R"(
 struct Uniforms {
   i : u32,
 }
@@ -854,13 +840,12 @@
 }
 )";
 
-  // Transform does nothing here as we're not actually assigning to the array in
-  // the struct.
-  auto* expect = src;
+    // Transform does nothing here as we're not actually assigning to the array in
+    // the struct.
+    auto* expect = src;
 
-  auto got =
-      Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
-  EXPECT_EQ(expect, str(got));
+    auto got = Run<Unshadow, SimplifyPointers, LocalizeStructArrayAssignment>(src);
+    EXPECT_EQ(expect, str(got));
 }
 
 }  // namespace
diff --git a/src/tint/transform/loop_to_for_loop.cc b/src/tint/transform/loop_to_for_loop.cc
index d01ac48..3e0a4b5 100644
--- a/src/tint/transform/loop_to_for_loop.cc
+++ b/src/tint/transform/loop_to_for_loop.cc
@@ -29,24 +29,22 @@
 namespace {
 
 bool IsBlockWithSingleBreak(const ast::BlockStatement* block) {
-  if (block->statements.size() != 1) {
-    return false;
-  }
-  return block->statements[0]->Is<ast::BreakStatement>();
+    if (block->statements.size() != 1) {
+        return false;
+    }
+    return block->statements[0]->Is<ast::BreakStatement>();
 }
 
-bool IsVarUsedByStmt(const sem::Info& sem,
-                     const ast::Variable* var,
-                     const ast::Statement* stmt) {
-  auto* var_sem = sem.Get(var);
-  for (auto* user : var_sem->Users()) {
-    if (auto* s = user->Stmt()) {
-      if (s->Declaration() == stmt) {
-        return true;
-      }
+bool IsVarUsedByStmt(const sem::Info& sem, const ast::Variable* var, const ast::Statement* stmt) {
+    auto* var_sem = sem.Get(var);
+    for (auto* user : var_sem->Users()) {
+        if (auto* s = user->Stmt()) {
+            if (s->Declaration() == stmt) {
+                return true;
+            }
+        }
     }
-  }
-  return false;
+    return false;
 }
 
 }  // namespace
@@ -56,88 +54,83 @@
 LoopToForLoop::~LoopToForLoop() = default;
 
 bool LoopToForLoop::ShouldRun(const Program* program, const DataMap&) const {
-  for (auto* node : program->ASTNodes().Objects()) {
-    if (node->Is<ast::LoopStatement>()) {
-      return true;
+    for (auto* node : program->ASTNodes().Objects()) {
+        if (node->Is<ast::LoopStatement>()) {
+            return true;
+        }
     }
-  }
-  return false;
+    return false;
 }
 
 void LoopToForLoop::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
-  ctx.ReplaceAll([&](const ast::LoopStatement* loop) -> const ast::Statement* {
-    // For loop condition is taken from the first statement in the loop.
-    // This requires an if-statement with either:
-    //  * A true block with no else statements, and the true block contains a
-    //    single 'break' statement.
-    //  * An empty true block with a single, no-condition else statement
-    //    containing a single 'break' statement.
-    // Examples:
-    //   loop {  if (condition) { break; } ... }
-    //   loop {  if (condition) {} else { break; } ... }
-    auto& stmts = loop->body->statements;
-    if (stmts.empty()) {
-      return nullptr;
-    }
-    auto* if_stmt = stmts[0]->As<ast::IfStatement>();
-    if (!if_stmt) {
-      return nullptr;
-    }
-
-    bool negate_condition = false;
-    if (IsBlockWithSingleBreak(if_stmt->body) &&
-        if_stmt->else_statements.empty()) {
-      negate_condition = true;
-    } else if (if_stmt->body->Empty() && if_stmt->else_statements.size() == 1 &&
-               if_stmt->else_statements[0]->condition == nullptr &&
-               IsBlockWithSingleBreak(if_stmt->else_statements[0]->body)) {
-      negate_condition = false;
-    } else {
-      return nullptr;
-    }
-
-    // The continuing block must be empty or contain a single, assignment or
-    // function call statement.
-    const ast::Statement* continuing = nullptr;
-    if (auto* loop_cont = loop->continuing) {
-      if (loop_cont->statements.size() != 1) {
-        return nullptr;
-      }
-
-      continuing = loop_cont->statements[0];
-      if (!continuing
-               ->IsAnyOf<ast::AssignmentStatement, ast::CallStatement>()) {
-        return nullptr;
-      }
-
-      // And the continuing statement must not use any of the variables declared
-      // in the loop body.
-      for (auto* stmt : loop->body->statements) {
-        if (auto* var_decl = stmt->As<ast::VariableDeclStatement>()) {
-          if (IsVarUsedByStmt(ctx.src->Sem(), var_decl->variable, continuing)) {
+    ctx.ReplaceAll([&](const ast::LoopStatement* loop) -> const ast::Statement* {
+        // For loop condition is taken from the first statement in the loop.
+        // This requires an if-statement with either:
+        //  * A true block with no else statements, and the true block contains a
+        //    single 'break' statement.
+        //  * An empty true block with a single, no-condition else statement
+        //    containing a single 'break' statement.
+        // Examples:
+        //   loop {  if (condition) { break; } ... }
+        //   loop {  if (condition) {} else { break; } ... }
+        auto& stmts = loop->body->statements;
+        if (stmts.empty()) {
             return nullptr;
-          }
         }
-      }
+        auto* if_stmt = stmts[0]->As<ast::IfStatement>();
+        if (!if_stmt) {
+            return nullptr;
+        }
+        auto* else_stmt = tint::As<ast::BlockStatement>(if_stmt->else_statement);
 
-      continuing = ctx.Clone(continuing);
-    }
+        bool negate_condition = false;
+        if (IsBlockWithSingleBreak(if_stmt->body) && if_stmt->else_statement == nullptr) {
+            negate_condition = true;
+        } else if (if_stmt->body->Empty() && else_stmt && IsBlockWithSingleBreak(else_stmt)) {
+            negate_condition = false;
+        } else {
+            return nullptr;
+        }
 
-    auto* condition = ctx.Clone(if_stmt->condition);
-    if (negate_condition) {
-      condition = ctx.dst->create<ast::UnaryOpExpression>(ast::UnaryOp::kNot,
-                                                          condition);
-    }
+        // The continuing block must be empty or contain a single, assignment or
+        // function call statement.
+        const ast::Statement* continuing = nullptr;
+        if (auto* loop_cont = loop->continuing) {
+            if (loop_cont->statements.size() != 1) {
+                return nullptr;
+            }
 
-    ast::Statement* initializer = nullptr;
+            continuing = loop_cont->statements[0];
+            if (!continuing->IsAnyOf<ast::AssignmentStatement, ast::CallStatement>()) {
+                return nullptr;
+            }
 
-    ctx.Remove(loop->body->statements, if_stmt);
-    auto* body = ctx.Clone(loop->body);
-    return ctx.dst->create<ast::ForLoopStatement>(initializer, condition,
-                                                  continuing, body);
-  });
+            // And the continuing statement must not use any of the variables declared
+            // in the loop body.
+            for (auto* stmt : loop->body->statements) {
+                if (auto* var_decl = stmt->As<ast::VariableDeclStatement>()) {
+                    if (IsVarUsedByStmt(ctx.src->Sem(), var_decl->variable, continuing)) {
+                        return nullptr;
+                    }
+                }
+            }
 
-  ctx.Clone();
+            continuing = ctx.Clone(continuing);
+        }
+
+        auto* condition = ctx.Clone(if_stmt->condition);
+        if (negate_condition) {
+            condition = ctx.dst->create<ast::UnaryOpExpression>(ast::UnaryOp::kNot, condition);
+        }
+
+        ast::Statement* initializer = nullptr;
+
+        ctx.Remove(loop->body->statements, if_stmt);
+        auto* body = ctx.Clone(loop->body);
+        return ctx.dst->create<ast::ForLoopStatement>(initializer, condition, continuing, body);
+    });
+
+    ctx.Clone();
 }
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/loop_to_for_loop.h b/src/tint/transform/loop_to_for_loop.h
index b6482ae..0623d79 100644
--- a/src/tint/transform/loop_to_for_loop.h
+++ b/src/tint/transform/loop_to_for_loop.h
@@ -22,29 +22,26 @@
 /// LoopToForLoop is a Transform that attempts to convert WGSL `loop {}`
 /// statements into a for-loop statement.
 class LoopToForLoop : public Castable<LoopToForLoop, Transform> {
- public:
-  /// Constructor
-  LoopToForLoop();
+  public:
+    /// Constructor
+    LoopToForLoop();
 
-  /// Destructor
-  ~LoopToForLoop() override;
+    /// Destructor
+    ~LoopToForLoop() override;
 
-  /// @param program the program to inspect
-  /// @param data optional extra transform-specific input data
-  /// @returns true if this transform should be run for the given program
-  bool ShouldRun(const Program* program,
-                 const DataMap& data = {}) const override;
+    /// @param program the program to inspect
+    /// @param data optional extra transform-specific input data
+    /// @returns true if this transform should be run for the given program
+    bool ShouldRun(const Program* program, const DataMap& data = {}) const override;
 
- protected:
-  /// Runs the transform using the CloneContext built for transforming a
-  /// program. Run() is responsible for calling Clone() on the CloneContext.
-  /// @param ctx the CloneContext primed with the input program and
-  /// ProgramBuilder
-  /// @param inputs optional extra transform-specific input data
-  /// @param outputs optional extra transform-specific output data
-  void Run(CloneContext& ctx,
-           const DataMap& inputs,
-           DataMap& outputs) const override;
+  protected:
+    /// Runs the transform using the CloneContext built for transforming a
+    /// program. Run() is responsible for calling Clone() on the CloneContext.
+    /// @param ctx the CloneContext primed with the input program and
+    /// ProgramBuilder
+    /// @param inputs optional extra transform-specific input data
+    /// @param outputs optional extra transform-specific output data
+    void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const override;
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/loop_to_for_loop_test.cc b/src/tint/transform/loop_to_for_loop_test.cc
index c34b0e8..e3d7ecc 100644
--- a/src/tint/transform/loop_to_for_loop_test.cc
+++ b/src/tint/transform/loop_to_for_loop_test.cc
@@ -22,13 +22,13 @@
 using LoopToForLoopTest = TransformTest;
 
 TEST_F(LoopToForLoopTest, ShouldRunEmptyModule) {
-  auto* src = R"()";
+    auto* src = R"()";
 
-  EXPECT_FALSE(ShouldRun<LoopToForLoop>(src));
+    EXPECT_FALSE(ShouldRun<LoopToForLoop>(src));
 }
 
 TEST_F(LoopToForLoopTest, ShouldRunHasForLoop) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   loop {
     break;
@@ -36,20 +36,20 @@
 }
 )";
 
-  EXPECT_TRUE(ShouldRun<LoopToForLoop>(src));
+    EXPECT_TRUE(ShouldRun<LoopToForLoop>(src));
 }
 
 TEST_F(LoopToForLoopTest, EmptyModule) {
-  auto* src = "";
-  auto* expect = "";
+    auto* src = "";
+    auto* expect = "";
 
-  auto got = Run<LoopToForLoop>(src);
+    auto got = Run<LoopToForLoop>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(LoopToForLoopTest, IfBreak) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var i : i32;
   i = 0;
@@ -67,7 +67,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var i : i32;
   i = 0;
@@ -77,13 +77,13 @@
 }
 )";
 
-  auto got = Run<LoopToForLoop>(src);
+    auto got = Run<LoopToForLoop>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(LoopToForLoopTest, IfElseBreak) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var i : i32;
   i = 0;
@@ -102,7 +102,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var i : i32;
   i = 0;
@@ -112,13 +112,13 @@
 }
 )";
 
-  auto got = Run<LoopToForLoop>(src);
+    auto got = Run<LoopToForLoop>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(LoopToForLoopTest, Nested) {
-  auto* src = R"(
+    auto* src = R"(
 let N = 16u;
 
 fn f() {
@@ -150,7 +150,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 let N = 16u;
 
 fn f() {
@@ -167,13 +167,13 @@
 }
 )";
 
-  auto got = Run<LoopToForLoop>(src);
+    auto got = Run<LoopToForLoop>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(LoopToForLoopTest, NoTransform_IfMultipleStmts) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var i : i32;
   i = 0;
@@ -191,15 +191,15 @@
 }
 )";
 
-  auto* expect = src;
+    auto* expect = src;
 
-  auto got = Run<LoopToForLoop>(src);
+    auto got = Run<LoopToForLoop>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(LoopToForLoopTest, NoTransform_IfElseMultipleStmts) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var i : i32;
   i = 0;
@@ -218,15 +218,15 @@
 }
 )";
 
-  auto* expect = src;
+    auto* expect = src;
 
-  auto got = Run<LoopToForLoop>(src);
+    auto got = Run<LoopToForLoop>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(LoopToForLoopTest, NoTransform_ContinuingIsCompound) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var i : i32;
   i = 0;
@@ -244,15 +244,15 @@
 }
 )";
 
-  auto* expect = src;
+    auto* expect = src;
 
-  auto got = Run<LoopToForLoop>(src);
+    auto got = Run<LoopToForLoop>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(LoopToForLoopTest, NoTransform_ContinuingMultipleStmts) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var i : i32;
   i = 0;
@@ -270,15 +270,15 @@
 }
 )";
 
-  auto* expect = src;
+    auto* expect = src;
 
-  auto got = Run<LoopToForLoop>(src);
+    auto got = Run<LoopToForLoop>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(LoopToForLoopTest, NoTransform_ContinuingUsesVarDeclInLoopBody) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var i : i32;
   i = 0;
@@ -295,11 +295,63 @@
 }
 )";
 
-  auto* expect = src;
+    auto* expect = src;
 
-  auto got = Run<LoopToForLoop>(src);
+    auto got = Run<LoopToForLoop>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(LoopToForLoopTest, NoTransform_IfBreakWithElse) {
+    auto* src = R"(
+fn f() {
+  var i : i32;
+  i = 0;
+  loop {
+    if ((i > 15)) {
+      break;
+    } else {
+    }
+    _ = 123;
+
+    continuing {
+      i = (i + 1);
+    }
+  }
+}
+)";
+
+    auto* expect = src;
+
+    auto got = Run<LoopToForLoop>(src);
+
+    EXPECT_EQ(expect, str(got));
+}
+
+TEST_F(LoopToForLoopTest, NoTransform_IfBreakWithElseIf) {
+    auto* src = R"(
+fn f() {
+  var i : i32;
+  i = 0;
+  loop {
+    if ((i > 15)) {
+      break;
+    } else if (true) {
+    }
+    _ = 123;
+
+    continuing {
+      i = (i + 1);
+    }
+  }
+}
+)";
+
+    auto* expect = src;
+
+    auto got = Run<LoopToForLoop>(src);
+
+    EXPECT_EQ(expect, str(got));
 }
 
 }  // namespace
diff --git a/src/tint/transform/manager.cc b/src/tint/transform/manager.cc
index a52f175..823474c 100644
--- a/src/tint/transform/manager.cc
+++ b/src/tint/transform/manager.cc
@@ -32,53 +32,47 @@
 Manager::~Manager() = default;
 
 Output Manager::Run(const Program* program, const DataMap& data) const {
-  const Program* in = program;
+    const Program* in = program;
 
 #if TINT_PRINT_PROGRAM_FOR_EACH_TRANSFORM
-  auto print_program = [&](const char* msg, const Transform* transform) {
-    auto wgsl = Program::printer(in);
-    std::cout << "---------------------------------------------------------"
-              << std::endl;
-    std::cout << "-- " << msg << " " << transform->TypeInfo().name << ":"
-              << std::endl;
-    std::cout << "---------------------------------------------------------"
-              << std::endl;
-    std::cout << wgsl << std::endl;
-    std::cout << "---------------------------------------------------------"
-              << std::endl
-              << std::endl;
-  };
+    auto print_program = [&](const char* msg, const Transform* transform) {
+        auto wgsl = Program::printer(in);
+        std::cout << "---------------------------------------------------------" << std::endl;
+        std::cout << "-- " << msg << " " << transform->TypeInfo().name << ":" << std::endl;
+        std::cout << "---------------------------------------------------------" << std::endl;
+        std::cout << wgsl << std::endl;
+        std::cout << "---------------------------------------------------------" << std::endl
+                  << std::endl;
+    };
 #endif
 
-  Output out;
-  for (const auto& transform : transforms_) {
-    if (!transform->ShouldRun(in, data)) {
-      TINT_IF_PRINT_PROGRAM(std::cout << "Skipping "
-                                      << transform->TypeInfo().name);
-      continue;
-    }
-    TINT_IF_PRINT_PROGRAM(print_program("Input to", transform.get()));
+    Output out;
+    for (const auto& transform : transforms_) {
+        if (!transform->ShouldRun(in, data)) {
+            TINT_IF_PRINT_PROGRAM(std::cout << "Skipping " << transform->TypeInfo().name);
+            continue;
+        }
+        TINT_IF_PRINT_PROGRAM(print_program("Input to", transform.get()));
 
-    auto res = transform->Run(in, data);
-    out.program = std::move(res.program);
-    out.data.Add(std::move(res.data));
-    in = &out.program;
-    if (!in->IsValid()) {
-      TINT_IF_PRINT_PROGRAM(
-          print_program("Invalid output of", transform.get()));
-      return out;
+        auto res = transform->Run(in, data);
+        out.program = std::move(res.program);
+        out.data.Add(std::move(res.data));
+        in = &out.program;
+        if (!in->IsValid()) {
+            TINT_IF_PRINT_PROGRAM(print_program("Invalid output of", transform.get()));
+            return out;
+        }
+
+        if (transform == transforms_.back()) {
+            TINT_IF_PRINT_PROGRAM(print_program("Output of", transform.get()));
+        }
     }
 
-    if (transform == transforms_.back()) {
-      TINT_IF_PRINT_PROGRAM(print_program("Output of", transform.get()));
+    if (program == in) {
+        out.program = program->Clone();
     }
-  }
 
-  if (program == in) {
-    out.program = program->Clone();
-  }
-
-  return out;
+    return out;
 }
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/manager.h b/src/tint/transform/manager.h
index fb614d3..9f5c6bc 100644
--- a/src/tint/transform/manager.h
+++ b/src/tint/transform/manager.h
@@ -28,33 +28,33 @@
 /// If any inner transform fails the manager will return immediately and
 /// the error can be retrieved with the Output's diagnostics.
 class Manager : public Castable<Manager, Transform> {
- public:
-  /// Constructor
-  Manager();
-  ~Manager() override;
+  public:
+    /// Constructor
+    Manager();
+    ~Manager() override;
 
-  /// Add pass to the manager
-  /// @param transform the transform to append
-  void append(std::unique_ptr<Transform> transform) {
-    transforms_.push_back(std::move(transform));
-  }
+    /// Add pass to the manager
+    /// @param transform the transform to append
+    void append(std::unique_ptr<Transform> transform) {
+        transforms_.push_back(std::move(transform));
+    }
 
-  /// Add pass to the manager of type `T`, constructed with the provided
-  /// arguments.
-  /// @param args the arguments to forward to the `T` constructor
-  template <typename T, typename... ARGS>
-  void Add(ARGS&&... args) {
-    transforms_.emplace_back(std::make_unique<T>(std::forward<ARGS>(args)...));
-  }
+    /// Add pass to the manager of type `T`, constructed with the provided
+    /// arguments.
+    /// @param args the arguments to forward to the `T` constructor
+    template <typename T, typename... ARGS>
+    void Add(ARGS&&... args) {
+        transforms_.emplace_back(std::make_unique<T>(std::forward<ARGS>(args)...));
+    }
 
-  /// Runs the transforms on `program`, returning the transformation result.
-  /// @param program the source program to transform
-  /// @param data optional extra transform-specific input data
-  /// @returns the transformed program and diagnostics
-  Output Run(const Program* program, const DataMap& data = {}) const override;
+    /// Runs the transforms on `program`, returning the transformation result.
+    /// @param program the source program to transform
+    /// @param data optional extra transform-specific input data
+    /// @returns the transformed program and diagnostics
+    Output Run(const Program* program, const DataMap& data = {}) const override;
 
- private:
-  std::vector<std::unique_ptr<Transform>> transforms_;
+  private:
+    std::vector<std::unique_ptr<Transform>> transforms_;
 };
 
 }  // namespace tint::transform
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 b510d7d..22bcd5c 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
@@ -32,366 +32,350 @@
 namespace {
 // Returns `true` if `type` is or contains a matrix type.
 bool ContainsMatrix(const sem::Type* type) {
-  type = type->UnwrapRef();
-  if (type->Is<sem::Matrix>()) {
-    return true;
-  } else if (auto* ary = type->As<sem::Array>()) {
-    return ContainsMatrix(ary->ElemType());
-  } else if (auto* str = type->As<sem::Struct>()) {
-    for (auto* member : str->Members()) {
-      if (ContainsMatrix(member->Type())) {
+    type = type->UnwrapRef();
+    if (type->Is<sem::Matrix>()) {
         return true;
-      }
+    } else if (auto* ary = type->As<sem::Array>()) {
+        return ContainsMatrix(ary->ElemType());
+    } else if (auto* str = type->As<sem::Struct>()) {
+        for (auto* member : str->Members()) {
+            if (ContainsMatrix(member->Type())) {
+                return true;
+            }
+        }
     }
-  }
-  return false;
+    return false;
 }
 }  // namespace
 
 /// State holds the current transform state.
 struct ModuleScopeVarToEntryPointParam::State {
-  /// The clone context.
-  CloneContext& ctx;
+    /// The clone context.
+    CloneContext& ctx;
 
-  /// Constructor
-  /// @param context the clone context
-  explicit State(CloneContext& context) : ctx(context) {}
+    /// Constructor
+    /// @param context the clone context
+    explicit State(CloneContext& context) : ctx(context) {}
 
-  /// Clone any struct types that are contained in `ty` (including `ty` itself),
-  /// and add it to the global declarations now, so that they precede new global
-  /// declarations that need to reference them.
-  /// @param ty the type to clone
-  void CloneStructTypes(const sem::Type* ty) {
-    if (auto* str = ty->As<sem::Struct>()) {
-      if (!cloned_structs_.emplace(str).second) {
-        // The struct has already been cloned.
-        return;
-      }
-
-      // Recurse into members.
-      for (auto* member : str->Members()) {
-        CloneStructTypes(member->Type());
-      }
-
-      // Clone the struct and add it to the global declaration list.
-      // Remove the old declaration.
-      auto* ast_str = str->Declaration();
-      ctx.dst->AST().AddTypeDecl(ctx.Clone(ast_str));
-      ctx.Remove(ctx.src->AST().GlobalDeclarations(), ast_str);
-    } else if (auto* arr = ty->As<sem::Array>()) {
-      CloneStructTypes(arr->ElemType());
-    }
-  }
-
-  /// Process the module.
-  void Process() {
-    // Predetermine the list of function calls that need to be replaced.
-    using CallList = std::vector<const ast::CallExpression*>;
-    std::unordered_map<const ast::Function*, CallList> calls_to_replace;
-
-    std::vector<const ast::Function*> functions_to_process;
-
-    // Build a list of functions that transitively reference any module-scope
-    // variables.
-    for (auto* func_ast : ctx.src->AST().Functions()) {
-      auto* func_sem = ctx.src->Sem().Get(func_ast);
-
-      bool needs_processing = false;
-      for (auto* var : func_sem->TransitivelyReferencedGlobals()) {
-        if (var->StorageClass() != ast::StorageClass::kNone) {
-          needs_processing = true;
-          break;
-        }
-      }
-      if (needs_processing) {
-        functions_to_process.push_back(func_ast);
-
-        // Find all of the calls to this function that will need to be replaced.
-        for (auto* call : func_sem->CallSites()) {
-          calls_to_replace[call->Stmt()->Function()->Declaration()].push_back(
-              call->Declaration());
-        }
-      }
-    }
-
-    // Build a list of `&ident` expressions. We'll use this later to avoid
-    // generating expressions of the form `&*ident`, which break WGSL validation
-    // rules when this expression is passed to a function.
-    // TODO(jrprice): We should add support for bidirectional SEM tree traversal
-    // so that we can do this on the fly instead.
-    std::unordered_map<const ast::IdentifierExpression*,
-                       const ast::UnaryOpExpression*>
-        ident_to_address_of;
-    for (auto* node : ctx.src->ASTNodes().Objects()) {
-      auto* address_of = node->As<ast::UnaryOpExpression>();
-      if (!address_of || address_of->op != ast::UnaryOp::kAddressOf) {
-        continue;
-      }
-      if (auto* ident = address_of->expr->As<ast::IdentifierExpression>()) {
-        ident_to_address_of[ident] = address_of;
-      }
-    }
-
-    for (auto* func_ast : functions_to_process) {
-      auto* func_sem = ctx.src->Sem().Get(func_ast);
-      bool is_entry_point = func_ast->IsEntryPoint();
-
-      // Map module-scope variables onto their replacement.
-      struct NewVar {
-        Symbol symbol;
-        bool is_pointer;
-        bool is_wrapped;
-      };
-      const char* kWrappedArrayMemberName = "arr";
-      std::unordered_map<const sem::Variable*, NewVar> var_to_newvar;
-
-      // We aggregate all workgroup variables into a struct to avoid hitting
-      // MSL's limit for threadgroup memory arguments.
-      Symbol workgroup_parameter_symbol;
-      ast::StructMemberList workgroup_parameter_members;
-      auto workgroup_param = [&]() {
-        if (!workgroup_parameter_symbol.IsValid()) {
-          workgroup_parameter_symbol = ctx.dst->Sym();
-        }
-        return workgroup_parameter_symbol;
-      };
-
-      for (auto* var : func_sem->TransitivelyReferencedGlobals()) {
-        auto sc = var->StorageClass();
-        auto* ty = var->Type()->UnwrapRef();
-        if (sc == ast::StorageClass::kNone) {
-          continue;
-        }
-        if (sc != ast::StorageClass::kPrivate &&
-            sc != ast::StorageClass::kStorage &&
-            sc != ast::StorageClass::kUniform &&
-            sc != ast::StorageClass::kUniformConstant &&
-            sc != ast::StorageClass::kWorkgroup) {
-          TINT_ICE(Transform, ctx.dst->Diagnostics())
-              << "unhandled module-scope storage class (" << sc << ")";
-        }
-
-        // This is the symbol for the variable that replaces the module-scope
-        // var.
-        auto new_var_symbol = ctx.dst->Sym();
-
-        // Helper to create an AST node for the store type of the variable.
-        auto store_type = [&]() { return CreateASTTypeFor(ctx, ty); };
-
-        // Track whether the new variable is a pointer or not.
-        bool is_pointer = false;
-
-        // Track whether the new variable was wrapped in a struct or not.
-        bool is_wrapped = false;
-
-        if (is_entry_point) {
-          if (var->Type()->UnwrapRef()->is_handle()) {
-            // For a texture or sampler variable, redeclare it as an entry point
-            // parameter. Disable entry point parameter validation.
-            auto* disable_validation =
-                ctx.dst->Disable(ast::DisabledValidation::kEntryPointParameter);
-            auto attrs = ctx.Clone(var->Declaration()->attributes);
-            attrs.push_back(disable_validation);
-            auto* param = ctx.dst->Param(new_var_symbol, store_type(), attrs);
-            ctx.InsertFront(func_ast->params, param);
-          } else if (sc == ast::StorageClass::kStorage ||
-                     sc == ast::StorageClass::kUniform) {
-            // Variables into the Storage and Uniform storage classes are
-            // redeclared as entry point parameters with a pointer type.
-            auto attributes = ctx.Clone(var->Declaration()->attributes);
-            attributes.push_back(ctx.dst->Disable(
-                ast::DisabledValidation::kEntryPointParameter));
-            attributes.push_back(
-                ctx.dst->Disable(ast::DisabledValidation::kIgnoreStorageClass));
-
-            auto* param_type = store_type();
-            if (auto* arr = ty->As<sem::Array>();
-                arr && arr->IsRuntimeSized()) {
-              // Wrap runtime-sized arrays in structures, so that we can declare
-              // pointers to them. Ideally we'd just emit the array itself as a
-              // pointer, but this is not representable in Tint's AST.
-              CloneStructTypes(ty);
-              auto* wrapper = ctx.dst->Structure(
-                  ctx.dst->Sym(),
-                  {ctx.dst->Member(kWrappedArrayMemberName, param_type)});
-              param_type = ctx.dst->ty.Of(wrapper);
-              is_wrapped = true;
+    /// Clone any struct types that are contained in `ty` (including `ty` itself),
+    /// and add it to the global declarations now, so that they precede new global
+    /// declarations that need to reference them.
+    /// @param ty the type to clone
+    void CloneStructTypes(const sem::Type* ty) {
+        if (auto* str = ty->As<sem::Struct>()) {
+            if (!cloned_structs_.emplace(str).second) {
+                // The struct has already been cloned.
+                return;
             }
 
-            param_type = ctx.dst->ty.pointer(
-                param_type, sc, var->Declaration()->declared_access);
-            auto* param =
-                ctx.dst->Param(new_var_symbol, param_type, attributes);
-            ctx.InsertFront(func_ast->params, param);
-            is_pointer = true;
-          } else if (sc == ast::StorageClass::kWorkgroup &&
-                     ContainsMatrix(var->Type())) {
-            // Due to a bug in the MSL compiler, we use a threadgroup memory
-            // argument for any workgroup allocation that contains a matrix.
-            // See crbug.com/tint/938.
-            // TODO(jrprice): Do this for all other workgroup variables too.
+            // Recurse into members.
+            for (auto* member : str->Members()) {
+                CloneStructTypes(member->Type());
+            }
 
-            // Create a member in the workgroup parameter struct.
-            auto member = ctx.Clone(var->Declaration()->symbol);
-            workgroup_parameter_members.push_back(
-                ctx.dst->Member(member, store_type()));
-            CloneStructTypes(var->Type()->UnwrapRef());
+            // Clone the struct and add it to the global declaration list.
+            // Remove the old declaration.
+            auto* ast_str = str->Declaration();
+            ctx.dst->AST().AddTypeDecl(ctx.Clone(ast_str));
+            ctx.Remove(ctx.src->AST().GlobalDeclarations(), ast_str);
+        } else if (auto* arr = ty->As<sem::Array>()) {
+            CloneStructTypes(arr->ElemType());
+        }
+    }
 
-            // Create a function-scope variable that is a pointer to the member.
-            auto* member_ptr = ctx.dst->AddressOf(ctx.dst->MemberAccessor(
-                ctx.dst->Deref(workgroup_param()), member));
-            auto* local_var =
-                ctx.dst->Const(new_var_symbol,
-                               ctx.dst->ty.pointer(
-                                   store_type(), ast::StorageClass::kWorkgroup),
-                               member_ptr);
-            ctx.InsertFront(func_ast->body->statements,
-                            ctx.dst->Decl(local_var));
-            is_pointer = true;
-          } else {
-            // Variables in the Private and Workgroup storage classes are
-            // redeclared at function scope. Disable storage class validation on
-            // this variable.
-            auto* disable_validation =
-                ctx.dst->Disable(ast::DisabledValidation::kIgnoreStorageClass);
-            auto* constructor = ctx.Clone(var->Declaration()->constructor);
-            auto* local_var =
-                ctx.dst->Var(new_var_symbol, store_type(), sc, constructor,
-                             ast::AttributeList{disable_validation});
-            ctx.InsertFront(func_ast->body->statements,
-                            ctx.dst->Decl(local_var));
-          }
-        } else {
-          // For a regular function, redeclare the variable as a parameter.
-          // Use a pointer for non-handle types.
-          auto* param_type = store_type();
-          ast::AttributeList attributes;
-          if (!var->Type()->UnwrapRef()->is_handle()) {
-            param_type = ctx.dst->ty.pointer(
-                param_type, sc, var->Declaration()->declared_access);
-            is_pointer = true;
+    /// Process the module.
+    void Process() {
+        // Predetermine the list of function calls that need to be replaced.
+        using CallList = std::vector<const ast::CallExpression*>;
+        std::unordered_map<const ast::Function*, CallList> calls_to_replace;
 
-            // Disable validation of the parameter's storage class and of
-            // arguments passed it.
-            attributes.push_back(
-                ctx.dst->Disable(ast::DisabledValidation::kIgnoreStorageClass));
-            attributes.push_back(ctx.dst->Disable(
-                ast::DisabledValidation::kIgnoreInvalidPointerArgument));
-          }
-          ctx.InsertBack(
-              func_ast->params,
-              ctx.dst->Param(new_var_symbol, param_type, attributes));
+        std::vector<const ast::Function*> functions_to_process;
+
+        // Build a list of functions that transitively reference any module-scope
+        // variables.
+        for (auto* func_ast : ctx.src->AST().Functions()) {
+            auto* func_sem = ctx.src->Sem().Get(func_ast);
+
+            bool needs_processing = false;
+            for (auto* var : func_sem->TransitivelyReferencedGlobals()) {
+                if (var->StorageClass() != ast::StorageClass::kNone) {
+                    needs_processing = true;
+                    break;
+                }
+            }
+            if (needs_processing) {
+                functions_to_process.push_back(func_ast);
+
+                // Find all of the calls to this function that will need to be replaced.
+                for (auto* call : func_sem->CallSites()) {
+                    calls_to_replace[call->Stmt()->Function()->Declaration()].push_back(
+                        call->Declaration());
+                }
+            }
         }
 
-        // Replace all uses of the module-scope variable.
-        // For non-entry points, dereference non-handle pointer parameters.
-        for (auto* user : var->Users()) {
-          if (user->Stmt()->Function()->Declaration() == func_ast) {
-            const ast::Expression* expr = ctx.dst->Expr(new_var_symbol);
-            if (is_pointer) {
-              // If this identifier is used by an address-of operator, just
-              // remove the address-of instead of adding a deref, since we
-              // already have a pointer.
-              auto* ident =
-                  user->Declaration()->As<ast::IdentifierExpression>();
-              if (ident_to_address_of.count(ident)) {
-                ctx.Replace(ident_to_address_of[ident], expr);
+        // Build a list of `&ident` expressions. We'll use this later to avoid
+        // generating expressions of the form `&*ident`, which break WGSL validation
+        // rules when this expression is passed to a function.
+        // TODO(jrprice): We should add support for bidirectional SEM tree traversal
+        // so that we can do this on the fly instead.
+        std::unordered_map<const ast::IdentifierExpression*, const ast::UnaryOpExpression*>
+            ident_to_address_of;
+        for (auto* node : ctx.src->ASTNodes().Objects()) {
+            auto* address_of = node->As<ast::UnaryOpExpression>();
+            if (!address_of || address_of->op != ast::UnaryOp::kAddressOf) {
                 continue;
-              }
-
-              expr = ctx.dst->Deref(expr);
             }
-            if (is_wrapped) {
-              // Get the member from the wrapper structure.
-              expr = ctx.dst->MemberAccessor(expr, kWrappedArrayMemberName);
+            if (auto* ident = address_of->expr->As<ast::IdentifierExpression>()) {
+                ident_to_address_of[ident] = address_of;
             }
-            ctx.Replace(user->Declaration(), expr);
-          }
         }
 
-        var_to_newvar[var] = {new_var_symbol, is_pointer, is_wrapped};
-      }
+        for (auto* func_ast : functions_to_process) {
+            auto* func_sem = ctx.src->Sem().Get(func_ast);
+            bool is_entry_point = func_ast->IsEntryPoint();
 
-      if (!workgroup_parameter_members.empty()) {
-        // Create the workgroup memory parameter.
-        // The parameter is a struct that contains members for each workgroup
-        // variable.
-        auto* str = ctx.dst->Structure(ctx.dst->Sym(),
-                                       std::move(workgroup_parameter_members));
-        auto* param_type = ctx.dst->ty.pointer(ctx.dst->ty.Of(str),
-                                               ast::StorageClass::kWorkgroup);
-        auto* disable_validation =
-            ctx.dst->Disable(ast::DisabledValidation::kEntryPointParameter);
-        auto* param =
-            ctx.dst->Param(workgroup_param(), param_type, {disable_validation});
-        ctx.InsertFront(func_ast->params, param);
-      }
+            // Map module-scope variables onto their replacement.
+            struct NewVar {
+                Symbol symbol;
+                bool is_pointer;
+                bool is_wrapped;
+            };
+            const char* kWrappedArrayMemberName = "arr";
+            std::unordered_map<const sem::Variable*, NewVar> var_to_newvar;
 
-      // Pass the variables as pointers to any functions that need them.
-      for (auto* call : calls_to_replace[func_ast]) {
-        auto* target =
-            ctx.src->AST().Functions().Find(call->target.name->symbol);
-        auto* target_sem = ctx.src->Sem().Get(target);
+            // We aggregate all workgroup variables into a struct to avoid hitting
+            // MSL's limit for threadgroup memory arguments.
+            Symbol workgroup_parameter_symbol;
+            ast::StructMemberList workgroup_parameter_members;
+            auto workgroup_param = [&]() {
+                if (!workgroup_parameter_symbol.IsValid()) {
+                    workgroup_parameter_symbol = ctx.dst->Sym();
+                }
+                return workgroup_parameter_symbol;
+            };
 
-        // Add new arguments for any variables that are needed by the callee.
-        // For entry points, pass non-handle types as pointers.
-        for (auto* target_var : target_sem->TransitivelyReferencedGlobals()) {
-          auto sc = target_var->StorageClass();
-          if (sc == ast::StorageClass::kNone) {
-            continue;
-          }
+            for (auto* var : func_sem->TransitivelyReferencedGlobals()) {
+                auto sc = var->StorageClass();
+                auto* ty = var->Type()->UnwrapRef();
+                if (sc == ast::StorageClass::kNone) {
+                    continue;
+                }
+                if (sc != ast::StorageClass::kPrivate && sc != ast::StorageClass::kStorage &&
+                    sc != ast::StorageClass::kUniform && sc != ast::StorageClass::kHandle &&
+                    sc != ast::StorageClass::kWorkgroup) {
+                    TINT_ICE(Transform, ctx.dst->Diagnostics())
+                        << "unhandled module-scope storage class (" << sc << ")";
+                }
 
-          auto new_var = var_to_newvar[target_var];
-          bool is_handle = target_var->Type()->UnwrapRef()->is_handle();
-          const ast::Expression* arg = ctx.dst->Expr(new_var.symbol);
-          if (new_var.is_wrapped) {
-            // The variable is wrapped in a struct, so we need to pass a pointer
-            // to the struct member instead.
-            arg = ctx.dst->AddressOf(ctx.dst->MemberAccessor(
-                ctx.dst->Deref(arg), kWrappedArrayMemberName));
-          } else if (is_entry_point && !is_handle && !new_var.is_pointer) {
-            // We need to pass a pointer and we don't already have one, so take
-            // the address of the new variable.
-            arg = ctx.dst->AddressOf(arg);
-          }
-          ctx.InsertBack(call->args, arg);
+                // This is the symbol for the variable that replaces the module-scope
+                // var.
+                auto new_var_symbol = ctx.dst->Sym();
+
+                // Helper to create an AST node for the store type of the variable.
+                auto store_type = [&]() { return CreateASTTypeFor(ctx, ty); };
+
+                // Track whether the new variable is a pointer or not.
+                bool is_pointer = false;
+
+                // Track whether the new variable was wrapped in a struct or not.
+                bool is_wrapped = false;
+
+                if (is_entry_point) {
+                    if (var->Type()->UnwrapRef()->is_handle()) {
+                        // For a texture or sampler variable, redeclare it as an entry point
+                        // parameter. Disable entry point parameter validation.
+                        auto* disable_validation =
+                            ctx.dst->Disable(ast::DisabledValidation::kEntryPointParameter);
+                        auto attrs = ctx.Clone(var->Declaration()->attributes);
+                        attrs.push_back(disable_validation);
+                        auto* param = ctx.dst->Param(new_var_symbol, store_type(), attrs);
+                        ctx.InsertFront(func_ast->params, param);
+                    } else if (sc == ast::StorageClass::kStorage ||
+                               sc == ast::StorageClass::kUniform) {
+                        // Variables into the Storage and Uniform storage classes are
+                        // redeclared as entry point parameters with a pointer type.
+                        auto attributes = ctx.Clone(var->Declaration()->attributes);
+                        attributes.push_back(
+                            ctx.dst->Disable(ast::DisabledValidation::kEntryPointParameter));
+                        attributes.push_back(
+                            ctx.dst->Disable(ast::DisabledValidation::kIgnoreStorageClass));
+
+                        auto* param_type = store_type();
+                        if (auto* arr = ty->As<sem::Array>(); arr && arr->IsRuntimeSized()) {
+                            // Wrap runtime-sized arrays in structures, so that we can declare
+                            // pointers to them. Ideally we'd just emit the array itself as a
+                            // pointer, but this is not representable in Tint's AST.
+                            CloneStructTypes(ty);
+                            auto* wrapper = ctx.dst->Structure(
+                                ctx.dst->Sym(),
+                                {ctx.dst->Member(kWrappedArrayMemberName, param_type)});
+                            param_type = ctx.dst->ty.Of(wrapper);
+                            is_wrapped = true;
+                        }
+
+                        param_type = ctx.dst->ty.pointer(param_type, sc,
+                                                         var->Declaration()->declared_access);
+                        auto* param = ctx.dst->Param(new_var_symbol, param_type, attributes);
+                        ctx.InsertFront(func_ast->params, param);
+                        is_pointer = true;
+                    } else if (sc == ast::StorageClass::kWorkgroup && ContainsMatrix(var->Type())) {
+                        // Due to a bug in the MSL compiler, we use a threadgroup memory
+                        // argument for any workgroup allocation that contains a matrix.
+                        // See crbug.com/tint/938.
+                        // TODO(jrprice): Do this for all other workgroup variables too.
+
+                        // Create a member in the workgroup parameter struct.
+                        auto member = ctx.Clone(var->Declaration()->symbol);
+                        workgroup_parameter_members.push_back(
+                            ctx.dst->Member(member, store_type()));
+                        CloneStructTypes(var->Type()->UnwrapRef());
+
+                        // Create a function-scope variable that is a pointer to the member.
+                        auto* member_ptr = ctx.dst->AddressOf(
+                            ctx.dst->MemberAccessor(ctx.dst->Deref(workgroup_param()), member));
+                        auto* local_var = ctx.dst->Let(
+                            new_var_symbol,
+                            ctx.dst->ty.pointer(store_type(), ast::StorageClass::kWorkgroup),
+                            member_ptr);
+                        ctx.InsertFront(func_ast->body->statements, ctx.dst->Decl(local_var));
+                        is_pointer = true;
+                    } else {
+                        // Variables in the Private and Workgroup storage classes are
+                        // redeclared at function scope. Disable storage class validation on
+                        // this variable.
+                        auto* disable_validation =
+                            ctx.dst->Disable(ast::DisabledValidation::kIgnoreStorageClass);
+                        auto* constructor = ctx.Clone(var->Declaration()->constructor);
+                        auto* local_var =
+                            ctx.dst->Var(new_var_symbol, store_type(), sc, constructor,
+                                         ast::AttributeList{disable_validation});
+                        ctx.InsertFront(func_ast->body->statements, ctx.dst->Decl(local_var));
+                    }
+                } else {
+                    // For a regular function, redeclare the variable as a parameter.
+                    // Use a pointer for non-handle types.
+                    auto* param_type = store_type();
+                    ast::AttributeList attributes;
+                    if (!var->Type()->UnwrapRef()->is_handle()) {
+                        param_type = ctx.dst->ty.pointer(param_type, sc,
+                                                         var->Declaration()->declared_access);
+                        is_pointer = true;
+
+                        // Disable validation of the parameter's storage class and of
+                        // arguments passed it.
+                        attributes.push_back(
+                            ctx.dst->Disable(ast::DisabledValidation::kIgnoreStorageClass));
+                        attributes.push_back(ctx.dst->Disable(
+                            ast::DisabledValidation::kIgnoreInvalidPointerArgument));
+                    }
+                    ctx.InsertBack(func_ast->params,
+                                   ctx.dst->Param(new_var_symbol, param_type, attributes));
+                }
+
+                // Replace all uses of the module-scope variable.
+                // For non-entry points, dereference non-handle pointer parameters.
+                for (auto* user : var->Users()) {
+                    if (user->Stmt()->Function()->Declaration() == func_ast) {
+                        const ast::Expression* expr = ctx.dst->Expr(new_var_symbol);
+                        if (is_pointer) {
+                            // If this identifier is used by an address-of operator, just
+                            // remove the address-of instead of adding a deref, since we
+                            // already have a pointer.
+                            auto* ident = user->Declaration()->As<ast::IdentifierExpression>();
+                            if (ident_to_address_of.count(ident)) {
+                                ctx.Replace(ident_to_address_of[ident], expr);
+                                continue;
+                            }
+
+                            expr = ctx.dst->Deref(expr);
+                        }
+                        if (is_wrapped) {
+                            // Get the member from the wrapper structure.
+                            expr = ctx.dst->MemberAccessor(expr, kWrappedArrayMemberName);
+                        }
+                        ctx.Replace(user->Declaration(), expr);
+                    }
+                }
+
+                var_to_newvar[var] = {new_var_symbol, is_pointer, is_wrapped};
+            }
+
+            if (!workgroup_parameter_members.empty()) {
+                // Create the workgroup memory parameter.
+                // The parameter is a struct that contains members for each workgroup
+                // variable.
+                auto* str =
+                    ctx.dst->Structure(ctx.dst->Sym(), std::move(workgroup_parameter_members));
+                auto* param_type =
+                    ctx.dst->ty.pointer(ctx.dst->ty.Of(str), ast::StorageClass::kWorkgroup);
+                auto* disable_validation =
+                    ctx.dst->Disable(ast::DisabledValidation::kEntryPointParameter);
+                auto* param = ctx.dst->Param(workgroup_param(), param_type, {disable_validation});
+                ctx.InsertFront(func_ast->params, param);
+            }
+
+            // Pass the variables as pointers to any functions that need them.
+            for (auto* call : calls_to_replace[func_ast]) {
+                auto* target = ctx.src->AST().Functions().Find(call->target.name->symbol);
+                auto* target_sem = ctx.src->Sem().Get(target);
+
+                // Add new arguments for any variables that are needed by the callee.
+                // For entry points, pass non-handle types as pointers.
+                for (auto* target_var : target_sem->TransitivelyReferencedGlobals()) {
+                    auto sc = target_var->StorageClass();
+                    if (sc == ast::StorageClass::kNone) {
+                        continue;
+                    }
+
+                    auto new_var = var_to_newvar[target_var];
+                    bool is_handle = target_var->Type()->UnwrapRef()->is_handle();
+                    const ast::Expression* arg = ctx.dst->Expr(new_var.symbol);
+                    if (new_var.is_wrapped) {
+                        // The variable is wrapped in a struct, so we need to pass a pointer
+                        // to the struct member instead.
+                        arg = ctx.dst->AddressOf(
+                            ctx.dst->MemberAccessor(ctx.dst->Deref(arg), kWrappedArrayMemberName));
+                    } else if (is_entry_point && !is_handle && !new_var.is_pointer) {
+                        // We need to pass a pointer and we don't already have one, so take
+                        // the address of the new variable.
+                        arg = ctx.dst->AddressOf(arg);
+                    }
+                    ctx.InsertBack(call->args, arg);
+                }
+            }
         }
-      }
+
+        // Now remove all module-scope variables with these storage classes.
+        for (auto* var_ast : ctx.src->AST().GlobalVariables()) {
+            auto* var_sem = ctx.src->Sem().Get(var_ast);
+            if (var_sem->StorageClass() != ast::StorageClass::kNone) {
+                ctx.Remove(ctx.src->AST().GlobalDeclarations(), var_ast);
+            }
+        }
     }
 
-    // Now remove all module-scope variables with these storage classes.
-    for (auto* var_ast : ctx.src->AST().GlobalVariables()) {
-      auto* var_sem = ctx.src->Sem().Get(var_ast);
-      if (var_sem->StorageClass() != ast::StorageClass::kNone) {
-        ctx.Remove(ctx.src->AST().GlobalDeclarations(), var_ast);
-      }
-    }
-  }
-
- private:
-  std::unordered_set<const sem::Struct*> cloned_structs_;
+  private:
+    std::unordered_set<const sem::Struct*> cloned_structs_;
 };
 
 ModuleScopeVarToEntryPointParam::ModuleScopeVarToEntryPointParam() = default;
 
 ModuleScopeVarToEntryPointParam::~ModuleScopeVarToEntryPointParam() = default;
 
-bool ModuleScopeVarToEntryPointParam::ShouldRun(const Program* program,
-                                                const DataMap&) const {
-  for (auto* decl : program->AST().GlobalDeclarations()) {
-    if (decl->Is<ast::Variable>()) {
-      return true;
+bool ModuleScopeVarToEntryPointParam::ShouldRun(const Program* program, const DataMap&) const {
+    for (auto* decl : program->AST().GlobalDeclarations()) {
+        if (decl->Is<ast::Variable>()) {
+            return true;
+        }
     }
-  }
-  return false;
+    return false;
 }
 
-void ModuleScopeVarToEntryPointParam::Run(CloneContext& ctx,
-                                          const DataMap&,
-                                          DataMap&) const {
-  State state{ctx};
-  state.Process();
-  ctx.Clone();
+void ModuleScopeVarToEntryPointParam::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
+    State state{ctx};
+    state.Process();
+    ctx.Clone();
 }
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/module_scope_var_to_entry_point_param.h b/src/tint/transform/module_scope_var_to_entry_point_param.h
index 8297057..f268197 100644
--- a/src/tint/transform/module_scope_var_to_entry_point_param.h
+++ b/src/tint/transform/module_scope_var_to_entry_point_param.h
@@ -63,30 +63,27 @@
 /// ```
 class ModuleScopeVarToEntryPointParam
     : public Castable<ModuleScopeVarToEntryPointParam, Transform> {
- public:
-  /// Constructor
-  ModuleScopeVarToEntryPointParam();
-  /// Destructor
-  ~ModuleScopeVarToEntryPointParam() override;
+  public:
+    /// Constructor
+    ModuleScopeVarToEntryPointParam();
+    /// Destructor
+    ~ModuleScopeVarToEntryPointParam() override;
 
-  /// @param program the program to inspect
-  /// @param data optional extra transform-specific input data
-  /// @returns true if this transform should be run for the given program
-  bool ShouldRun(const Program* program,
-                 const DataMap& data = {}) const override;
+    /// @param program the program to inspect
+    /// @param data optional extra transform-specific input data
+    /// @returns true if this transform should be run for the given program
+    bool ShouldRun(const Program* program, const DataMap& data = {}) const override;
 
- protected:
-  /// Runs the transform using the CloneContext built for transforming a
-  /// program. Run() is responsible for calling Clone() on the CloneContext.
-  /// @param ctx the CloneContext primed with the input program and
-  /// ProgramBuilder
-  /// @param inputs optional extra transform-specific input data
-  /// @param outputs optional extra transform-specific output data
-  void Run(CloneContext& ctx,
-           const DataMap& inputs,
-           DataMap& outputs) const override;
+  protected:
+    /// Runs the transform using the CloneContext built for transforming a
+    /// program. Run() is responsible for calling Clone() on the CloneContext.
+    /// @param ctx the CloneContext primed with the input program and
+    /// ProgramBuilder
+    /// @param inputs optional extra transform-specific input data
+    /// @param outputs optional extra transform-specific output data
+    void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const override;
 
-  struct State;
+    struct State;
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/module_scope_var_to_entry_point_param_test.cc b/src/tint/transform/module_scope_var_to_entry_point_param_test.cc
index 3089355..580e695 100644
--- a/src/tint/transform/module_scope_var_to_entry_point_param_test.cc
+++ b/src/tint/transform/module_scope_var_to_entry_point_param_test.cc
@@ -24,21 +24,21 @@
 using ModuleScopeVarToEntryPointParamTest = TransformTest;
 
 TEST_F(ModuleScopeVarToEntryPointParamTest, ShouldRunEmptyModule) {
-  auto* src = R"()";
+    auto* src = R"()";
 
-  EXPECT_FALSE(ShouldRun<ModuleScopeVarToEntryPointParam>(src));
+    EXPECT_FALSE(ShouldRun<ModuleScopeVarToEntryPointParam>(src));
 }
 
 TEST_F(ModuleScopeVarToEntryPointParamTest, ShouldRunHasGlobal) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> v : i32;
 )";
 
-  EXPECT_TRUE(ShouldRun<ModuleScopeVarToEntryPointParam>(src));
+    EXPECT_TRUE(ShouldRun<ModuleScopeVarToEntryPointParam>(src));
 }
 
 TEST_F(ModuleScopeVarToEntryPointParamTest, Basic) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> p : f32;
 var<workgroup> w : f32;
 
@@ -48,7 +48,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   @internal(disable_validation__ignore_storage_class) var<workgroup> tint_symbol : f32;
@@ -57,13 +57,13 @@
 }
 )";
 
-  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+    auto got = Run<ModuleScopeVarToEntryPointParam>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ModuleScopeVarToEntryPointParamTest, Basic_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   w = p;
@@ -73,7 +73,7 @@
 var<private> p : f32;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   @internal(disable_validation__ignore_storage_class) var<workgroup> tint_symbol : f32;
@@ -82,13 +82,13 @@
 }
 )";
 
-  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+    auto got = Run<ModuleScopeVarToEntryPointParam>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ModuleScopeVarToEntryPointParamTest, FunctionCalls) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> p : f32;
 var<workgroup> w : f32;
 
@@ -112,7 +112,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn no_uses() {
 }
 
@@ -135,13 +135,13 @@
 }
 )";
 
-  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+    auto got = Run<ModuleScopeVarToEntryPointParam>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ModuleScopeVarToEntryPointParamTest, FunctionCalls_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   foo(1.0);
@@ -165,7 +165,7 @@
 var<workgroup> w : f32;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   @internal(disable_validation__ignore_storage_class) var<private> tint_symbol : f32;
@@ -188,13 +188,13 @@
 }
 )";
 
-  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+    auto got = Run<ModuleScopeVarToEntryPointParam>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ModuleScopeVarToEntryPointParamTest, Constructors) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> a : f32 = 1.0;
 var<private> b : f32 = f32();
 
@@ -204,7 +204,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   @internal(disable_validation__ignore_storage_class) var<private> tint_symbol : f32 = 1.0;
@@ -213,13 +213,13 @@
 }
 )";
 
-  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+    auto got = Run<ModuleScopeVarToEntryPointParam>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ModuleScopeVarToEntryPointParamTest, Constructors_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   let x : f32 = a + b;
@@ -229,7 +229,7 @@
 var<private> a : f32 = 1.0;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   @internal(disable_validation__ignore_storage_class) var<private> tint_symbol : f32 = 1.0;
@@ -238,13 +238,13 @@
 }
 )";
 
-  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+    auto got = Run<ModuleScopeVarToEntryPointParam>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ModuleScopeVarToEntryPointParamTest, Pointers) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> p : f32;
 var<workgroup> w : f32;
 
@@ -257,7 +257,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   @internal(disable_validation__ignore_storage_class) var<private> tint_symbol : f32;
@@ -269,13 +269,13 @@
 }
 )";
 
-  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+    auto got = Run<ModuleScopeVarToEntryPointParam>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ModuleScopeVarToEntryPointParamTest, Pointers_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   let p_ptr : ptr<private, f32> = &p;
@@ -288,7 +288,7 @@
 var<private> p : f32;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   @internal(disable_validation__ignore_storage_class) var<private> tint_symbol : f32;
@@ -300,13 +300,13 @@
 }
 )";
 
-  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+    auto got = Run<ModuleScopeVarToEntryPointParam>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ModuleScopeVarToEntryPointParamTest, FoldAddressOfDeref) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> v : f32;
 
 fn bar(p : ptr<private, f32>) {
@@ -323,7 +323,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn bar(p : ptr<private, f32>) {
   *(p) = 0.0;
 }
@@ -339,13 +339,13 @@
 }
 )";
 
-  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+    auto got = Run<ModuleScopeVarToEntryPointParam>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ModuleScopeVarToEntryPointParamTest, FoldAddressOfDeref_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   foo();
@@ -362,7 +362,7 @@
 var<private> v : f32;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   @internal(disable_validation__ignore_storage_class) var<private> tint_symbol : f32;
@@ -378,13 +378,13 @@
 }
 )";
 
-  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+    auto got = Run<ModuleScopeVarToEntryPointParam>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ModuleScopeVarToEntryPointParamTest, Buffers_Basic) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   a : f32,
 };
@@ -401,7 +401,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   a : f32,
 }
@@ -413,13 +413,13 @@
 }
 )";
 
-  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+    auto got = Run<ModuleScopeVarToEntryPointParam>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ModuleScopeVarToEntryPointParamTest, Buffers_Basic_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   _ = u;
@@ -435,7 +435,7 @@
 
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @stage(compute) @workgroup_size(1)
 fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_storage_class) tint_symbol : ptr<uniform, S>, @group(0) @binding(1) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_storage_class) tint_symbol_1 : ptr<storage, S>) {
   _ = *(tint_symbol);
@@ -447,13 +447,13 @@
 }
 )";
 
-  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+    auto got = Run<ModuleScopeVarToEntryPointParam>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ModuleScopeVarToEntryPointParamTest, Buffer_RuntimeArray) {
-  auto* src = R"(
+    auto* src = R"(
 @group(0) @binding(0)
 var<storage> buffer : array<f32>;
 
@@ -463,7 +463,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol_1 {
   arr : array<f32>,
 }
@@ -474,13 +474,13 @@
 }
 )";
 
-  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+    auto got = Run<ModuleScopeVarToEntryPointParam>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ModuleScopeVarToEntryPointParamTest, Buffer_RuntimeArray_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   _ = buffer[0];
@@ -490,7 +490,7 @@
 var<storage> buffer : array<f32>;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol_1 {
   arr : array<f32>,
 }
@@ -501,13 +501,13 @@
 }
 )";
 
-  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+    auto got = Run<ModuleScopeVarToEntryPointParam>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ModuleScopeVarToEntryPointParamTest, Buffer_RuntimeArrayInsideFunction) {
-  auto* src = R"(
+    auto* src = R"(
 @group(0) @binding(0)
 var<storage> buffer : array<f32>;
 
@@ -521,7 +521,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol_2 {
   arr : array<f32>,
 }
@@ -536,14 +536,13 @@
 }
 )";
 
-  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+    auto got = Run<ModuleScopeVarToEntryPointParam>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(ModuleScopeVarToEntryPointParamTest,
-       Buffer_RuntimeArrayInsideFunction_OutOfOrder) {
-  auto* src = R"(
+TEST_F(ModuleScopeVarToEntryPointParamTest, Buffer_RuntimeArrayInsideFunction_OutOfOrder) {
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   foo();
@@ -556,7 +555,7 @@
 @group(0) @binding(0) var<storage> buffer : array<f32>;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol_1 {
   arr : array<f32>,
 }
@@ -571,13 +570,13 @@
 }
 )";
 
-  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+    auto got = Run<ModuleScopeVarToEntryPointParam>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ModuleScopeVarToEntryPointParamTest, Buffer_RuntimeArray_Alias) {
-  auto* src = R"(
+    auto* src = R"(
 type myarray = array<f32>;
 
 @group(0) @binding(0)
@@ -589,7 +588,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol_1 {
   arr : array<f32>,
 }
@@ -602,14 +601,13 @@
 }
 )";
 
-  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+    auto got = Run<ModuleScopeVarToEntryPointParam>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(ModuleScopeVarToEntryPointParamTest,
-       Buffer_RuntimeArray_Alias_OutOfOrder) {
-  auto* src = R"(
+TEST_F(ModuleScopeVarToEntryPointParamTest, Buffer_RuntimeArray_Alias_OutOfOrder) {
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   _ = buffer[0];
@@ -620,7 +618,7 @@
 type myarray = array<f32>;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol_1 {
   arr : array<f32>,
 }
@@ -633,13 +631,13 @@
 type myarray = array<f32>;
 )";
 
-  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+    auto got = Run<ModuleScopeVarToEntryPointParam>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ModuleScopeVarToEntryPointParamTest, Buffer_ArrayOfStruct) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   f : f32,
 };
@@ -653,7 +651,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   f : f32,
 }
@@ -668,13 +666,13 @@
 }
 )";
 
-  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+    auto got = Run<ModuleScopeVarToEntryPointParam>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ModuleScopeVarToEntryPointParamTest, Buffer_ArrayOfStruct_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   _ = buffer[0];
@@ -687,7 +685,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   f : f32,
 }
@@ -702,13 +700,13 @@
 }
 )";
 
-  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+    auto got = Run<ModuleScopeVarToEntryPointParam>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ModuleScopeVarToEntryPointParamTest, Buffers_FunctionCalls) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   a : f32,
 };
@@ -739,7 +737,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   a : f32,
 }
@@ -765,13 +763,13 @@
 }
 )";
 
-  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+    auto got = Run<ModuleScopeVarToEntryPointParam>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ModuleScopeVarToEntryPointParamTest, Buffers_FunctionCalls_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   foo(1.0);
@@ -802,7 +800,7 @@
 var<storage> s : S;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @stage(compute) @workgroup_size(1)
 fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_storage_class) tint_symbol : ptr<uniform, S>, @group(0) @binding(1) @internal(disable_validation__entry_point_parameter) @internal(disable_validation__ignore_storage_class) tint_symbol_1 : ptr<storage, S>) {
   foo(1.0, tint_symbol, tint_symbol_1);
@@ -828,13 +826,13 @@
 }
 )";
 
-  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+    auto got = Run<ModuleScopeVarToEntryPointParam>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ModuleScopeVarToEntryPointParamTest, HandleTypes_Basic) {
-  auto* src = R"(
+    auto* src = R"(
 @group(0) @binding(0) var t : texture_2d<f32>;
 @group(0) @binding(1) var s : sampler;
 
@@ -845,7 +843,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @stage(compute) @workgroup_size(1)
 fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) tint_symbol : texture_2d<f32>, @group(0) @binding(1) @internal(disable_validation__entry_point_parameter) tint_symbol_1 : sampler) {
   _ = tint_symbol;
@@ -853,13 +851,13 @@
 }
 )";
 
-  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+    auto got = Run<ModuleScopeVarToEntryPointParam>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ModuleScopeVarToEntryPointParamTest, HandleTypes_FunctionCalls) {
-  auto* src = R"(
+    auto* src = R"(
 @group(0) @binding(0) var t : texture_2d<f32>;
 @group(0) @binding(1) var s : sampler;
 
@@ -884,7 +882,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn no_uses() {
 }
 
@@ -906,14 +904,13 @@
 }
 )";
 
-  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+    auto got = Run<ModuleScopeVarToEntryPointParam>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(ModuleScopeVarToEntryPointParamTest,
-       HandleTypes_FunctionCalls_OutOfOrder) {
-  auto* src = R"(
+TEST_F(ModuleScopeVarToEntryPointParamTest, HandleTypes_FunctionCalls_OutOfOrder) {
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   foo(1.0);
@@ -938,7 +935,7 @@
 @group(0) @binding(1) var s : sampler;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @stage(compute) @workgroup_size(1)
 fn main(@group(0) @binding(0) @internal(disable_validation__entry_point_parameter) tint_symbol : texture_2d<f32>, @group(0) @binding(1) @internal(disable_validation__entry_point_parameter) tint_symbol_1 : sampler) {
   foo(1.0, tint_symbol, tint_symbol_1);
@@ -960,13 +957,13 @@
 }
 )";
 
-  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+    auto got = Run<ModuleScopeVarToEntryPointParam>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ModuleScopeVarToEntryPointParamTest, Matrix) {
-  auto* src = R"(
+    auto* src = R"(
 var<workgroup> m : mat2x2<f32>;
 
 @stage(compute) @workgroup_size(1)
@@ -975,7 +972,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol_2 {
   m : mat2x2<f32>,
 }
@@ -987,13 +984,13 @@
 }
 )";
 
-  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+    auto got = Run<ModuleScopeVarToEntryPointParam>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ModuleScopeVarToEntryPointParamTest, NestedMatrix) {
-  auto* src = R"(
+    auto* src = R"(
 struct S1 {
   m : mat2x2<f32>,
 };
@@ -1008,7 +1005,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S1 {
   m : mat2x2<f32>,
 }
@@ -1028,15 +1025,15 @@
 }
 )";
 
-  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+    auto got = Run<ModuleScopeVarToEntryPointParam>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 // Test that we do not duplicate a struct type used by multiple workgroup
 // variables that are promoted to threadgroup memory arguments.
 TEST_F(ModuleScopeVarToEntryPointParamTest, DuplicateThreadgroupArgumentTypes) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   m : mat2x2<f32>,
 };
@@ -1052,7 +1049,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   m : mat2x2<f32>,
 }
@@ -1071,16 +1068,15 @@
 }
 )";
 
-  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+    auto got = Run<ModuleScopeVarToEntryPointParam>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 // Test that we do not duplicate a struct type used by multiple workgroup
 // variables that are promoted to threadgroup memory arguments.
-TEST_F(ModuleScopeVarToEntryPointParamTest,
-       DuplicateThreadgroupArgumentTypes_OutOfOrder) {
-  auto* src = R"(
+TEST_F(ModuleScopeVarToEntryPointParamTest, DuplicateThreadgroupArgumentTypes_OutOfOrder) {
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
   let x = a;
@@ -1095,7 +1091,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   m : mat2x2<f32>,
 }
@@ -1114,13 +1110,13 @@
 }
 )";
 
-  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+    auto got = Run<ModuleScopeVarToEntryPointParam>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ModuleScopeVarToEntryPointParamTest, UnusedVariables) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   a : f32,
 };
@@ -1141,7 +1137,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   a : f32,
 }
@@ -1151,17 +1147,17 @@
 }
 )";
 
-  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+    auto got = Run<ModuleScopeVarToEntryPointParam>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ModuleScopeVarToEntryPointParamTest, EmtpyModule) {
-  auto* src = "";
+    auto* src = "";
 
-  auto got = Run<ModuleScopeVarToEntryPointParam>(src);
+    auto got = Run<ModuleScopeVarToEntryPointParam>(src);
 
-  EXPECT_EQ(src, str(got));
+    EXPECT_EQ(src, str(got));
 }
 
 }  // namespace
diff --git a/src/tint/transform/multiplanar_external_texture.cc b/src/tint/transform/multiplanar_external_texture.cc
index 00466ac..47cc9ce 100644
--- a/src/tint/transform/multiplanar_external_texture.cc
+++ b/src/tint/transform/multiplanar_external_texture.cc
@@ -24,8 +24,9 @@
 #include "src/tint/sem/variable.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::transform::MultiplanarExternalTexture);
-TINT_INSTANTIATE_TYPEINFO(
-    tint::transform::MultiplanarExternalTexture::NewBindingPoints);
+TINT_INSTANTIATE_TYPEINFO(tint::transform::MultiplanarExternalTexture::NewBindingPoints);
+
+using namespace tint::number_suffixes;  // NOLINT
 
 namespace tint::transform {
 namespace {
@@ -33,394 +34,427 @@
 /// This struct stores symbols for new bindings created as a result of
 /// transforming a texture_external instance.
 struct NewBindingSymbols {
-  Symbol params;
-  Symbol plane_0;
-  Symbol plane_1;
+    Symbol params;
+    Symbol plane_0;
+    Symbol plane_1;
 };
 }  // namespace
 
 /// State holds the current transform state
 struct MultiplanarExternalTexture::State {
-  /// The clone context.
-  CloneContext& ctx;
+    /// The clone context.
+    CloneContext& ctx;
 
-  /// ProgramBuilder for the context
-  ProgramBuilder& b;
+    /// ProgramBuilder for the context
+    ProgramBuilder& b;
 
-  /// Destination binding locations for the expanded texture_external provided
-  /// as input into the transform.
-  const NewBindingPoints* new_binding_points;
+    /// Destination binding locations for the expanded texture_external provided
+    /// as input into the transform.
+    const NewBindingPoints* new_binding_points;
 
-  /// Symbol for the ExternalTextureParams struct
-  Symbol params_struct_sym;
+    /// Symbol for the GammaTransferParams
+    Symbol gamma_transfer_struct_sym;
 
-  /// Symbol for the textureLoadExternal function
-  Symbol texture_load_external_sym;
+    /// Symbol for the ExternalTextureParams struct
+    Symbol params_struct_sym;
 
-  /// Symbol for the textureSampleExternal function
-  Symbol texture_sample_external_sym;
+    /// Symbol for the textureLoadExternal function
+    Symbol texture_load_external_sym;
 
-  /// Storage for new bindings that have been created corresponding to an
-  /// original texture_external binding.
-  std::unordered_map<const sem::Variable*, NewBindingSymbols>
-      new_binding_symbols;
+    /// Symbol for the textureSampleExternal function
+    Symbol texture_sample_external_sym;
 
-  /// Constructor
-  /// @param context the clone
-  /// @param newBindingPoints the input destination binding locations for the
-  /// expanded texture_external
-  State(CloneContext& context, const NewBindingPoints* newBindingPoints)
-      : ctx(context), b(*context.dst), new_binding_points(newBindingPoints) {}
+    /// Symbol for the gammaCorrection function
+    Symbol gamma_correction_sym;
 
-  /// Processes the module
-  void Process() {
-    auto& sem = ctx.src->Sem();
+    /// Storage for new bindings that have been created corresponding to an
+    /// original texture_external binding.
+    std::unordered_map<const sem::Variable*, NewBindingSymbols> new_binding_symbols;
 
-    // For each texture_external binding, we replace it with a texture_2d<f32>
-    // binding and create two additional bindings (one texture_2d<f32> to
-    // represent the secondary plane and one uniform buffer for the
-    // ExternalTextureParams struct).
-    for (auto* var : ctx.src->AST().GlobalVariables()) {
-      auto* sem_var = sem.Get(var);
-      if (!sem_var->Type()->UnwrapRef()->Is<sem::ExternalTexture>()) {
-        continue;
-      }
+    /// Constructor
+    /// @param context the clone
+    /// @param newBindingPoints the input destination binding locations for the
+    /// expanded texture_external
+    State(CloneContext& context, const NewBindingPoints* newBindingPoints)
+        : ctx(context), b(*context.dst), new_binding_points(newBindingPoints) {}
 
-      // If the attributes are empty, then this must be a texture_external
-      // passed as a function parameter. These variables are transformed
-      // elsewhere.
-      if (var->attributes.empty()) {
-        continue;
-      }
+    /// Processes the module
+    void Process() {
+        auto& sem = ctx.src->Sem();
 
-      // If we find a texture_external binding, we know we must emit the
-      // ExternalTextureParams struct.
-      if (!params_struct_sym.IsValid()) {
-        createExtTexParamsStruct();
-      }
+        // For each texture_external binding, we replace it with a texture_2d<f32>
+        // binding and create two additional bindings (one texture_2d<f32> to
+        // represent the secondary plane and one uniform buffer for the
+        // ExternalTextureParams struct).
+        for (auto* var : ctx.src->AST().GlobalVariables()) {
+            auto* sem_var = sem.Get(var);
+            if (!sem_var->Type()->UnwrapRef()->Is<sem::ExternalTexture>()) {
+                continue;
+            }
 
-      // The binding points for the newly introduced bindings must have been
-      // provided to this transform. We fetch the new binding points by
-      // providing the original texture_external binding points into the
-      // passed map.
-      BindingPoint bp = {var->BindingPoint().group->value,
-                         var->BindingPoint().binding->value};
+            // If the attributes are empty, then this must be a texture_external
+            // passed as a function parameter. These variables are transformed
+            // elsewhere.
+            if (var->attributes.empty()) {
+                continue;
+            }
 
-      BindingsMap::const_iterator it =
-          new_binding_points->bindings_map.find(bp);
-      if (it == new_binding_points->bindings_map.end()) {
-        b.Diagnostics().add_error(
-            diag::System::Transform,
-            "missing new binding points for texture_external at binding {" +
-                std::to_string(bp.group) + "," + std::to_string(bp.binding) +
-                "}");
-        continue;
-      }
+            // If we find a texture_external binding, we know we must emit the
+            // ExternalTextureParams struct.
+            if (!params_struct_sym.IsValid()) {
+                createExtTexParamsStructs();
+            }
 
-      BindingPoints bps = it->second;
+            // The binding points for the newly introduced bindings must have been
+            // provided to this transform. We fetch the new binding points by
+            // providing the original texture_external binding points into the
+            // passed map.
+            BindingPoint bp = {var->BindingPoint().group->value,
+                               var->BindingPoint().binding->value};
 
-      // Symbols for the newly created bindings must be saved so they can be
-      // passed as parameters later. These are placed in a map and keyed by
-      // the source symbol associated with the texture_external binding that
-      // corresponds with the new destination bindings.
-      // NewBindingSymbols new_binding_syms;
-      auto& syms = new_binding_symbols[sem_var];
-      syms.plane_0 = ctx.Clone(var->symbol);
-      syms.plane_1 = b.Symbols().New("ext_tex_plane_1");
-      b.Global(syms.plane_1,
-               b.ty.sampled_texture(ast::TextureDimension::k2d, b.ty.f32()),
-               b.GroupAndBinding(bps.plane_1.group, bps.plane_1.binding));
-      syms.params = b.Symbols().New("ext_tex_params");
-      b.Global(syms.params, b.ty.type_name("ExternalTextureParams"),
-               ast::StorageClass::kUniform,
-               b.GroupAndBinding(bps.params.group, bps.params.binding));
+            BindingsMap::const_iterator it = new_binding_points->bindings_map.find(bp);
+            if (it == new_binding_points->bindings_map.end()) {
+                b.Diagnostics().add_error(
+                    diag::System::Transform,
+                    "missing new binding points for texture_external at binding {" +
+                        std::to_string(bp.group) + "," + std::to_string(bp.binding) + "}");
+                continue;
+            }
 
-      // Replace the original texture_external binding with a texture_2d<f32>
-      // binding.
-      ast::AttributeList cloned_attributes = ctx.Clone(var->attributes);
-      const ast::Expression* cloned_constructor = ctx.Clone(var->constructor);
+            BindingPoints bps = it->second;
 
-      auto* replacement =
-          b.Var(syms.plane_0,
-                b.ty.sampled_texture(ast::TextureDimension::k2d, b.ty.f32()),
-                cloned_constructor, cloned_attributes);
-      ctx.Replace(var, replacement);
-    }
+            // Symbols for the newly created bindings must be saved so they can be
+            // passed as parameters later. These are placed in a map and keyed by
+            // the source symbol associated with the texture_external binding that
+            // corresponds with the new destination bindings.
+            // NewBindingSymbols new_binding_syms;
+            auto& syms = new_binding_symbols[sem_var];
+            syms.plane_0 = ctx.Clone(var->symbol);
+            syms.plane_1 = b.Symbols().New("ext_tex_plane_1");
+            b.Global(syms.plane_1, b.ty.sampled_texture(ast::TextureDimension::k2d, b.ty.f32()),
+                     b.GroupAndBinding(bps.plane_1.group, bps.plane_1.binding));
+            syms.params = b.Symbols().New("ext_tex_params");
+            b.Global(syms.params, b.ty.type_name("ExternalTextureParams"),
+                     ast::StorageClass::kUniform,
+                     b.GroupAndBinding(bps.params.group, bps.params.binding));
 
-    // We must update all the texture_external parameters for user declared
-    // functions.
-    for (auto* fn : ctx.src->AST().Functions()) {
-      for (const ast::Variable* param : fn->params) {
-        if (auto* sem_var = sem.Get(param)) {
-          if (!sem_var->Type()->UnwrapRef()->Is<sem::ExternalTexture>()) {
-            continue;
-          }
-          // If we find a texture_external, we must ensure the
-          // ExternalTextureParams struct exists.
-          if (!params_struct_sym.IsValid()) {
-            createExtTexParamsStruct();
-          }
-          // When a texture_external is found, we insert all components
-          // the texture_external into the parameter list. We must also place
-          // the new symbols into the transform state so they can be used when
-          // transforming function calls.
-          auto& syms = new_binding_symbols[sem_var];
-          syms.plane_0 = ctx.Clone(param->symbol);
-          syms.plane_1 = b.Symbols().New("ext_tex_plane_1");
-          syms.params = b.Symbols().New("ext_tex_params");
-          auto tex2d_f32 = [&] {
-            return b.ty.sampled_texture(ast::TextureDimension::k2d, b.ty.f32());
-          };
-          ctx.Replace(param, b.Param(syms.plane_0, tex2d_f32()));
-          ctx.InsertAfter(fn->params, param,
-                          b.Param(syms.plane_1, tex2d_f32()));
-          ctx.InsertAfter(
-              fn->params, param,
-              b.Param(syms.params, b.ty.type_name(params_struct_sym)));
+            // Replace the original texture_external binding with a texture_2d<f32>
+            // binding.
+            ast::AttributeList cloned_attributes = ctx.Clone(var->attributes);
+            const ast::Expression* cloned_constructor = ctx.Clone(var->constructor);
+
+            auto* replacement =
+                b.Var(syms.plane_0, b.ty.sampled_texture(ast::TextureDimension::k2d, b.ty.f32()),
+                      cloned_constructor, cloned_attributes);
+            ctx.Replace(var, replacement);
         }
-      }
-    }
 
-    // Transform the original textureLoad and textureSampleLevel calls into
-    // textureLoadExternal and textureSampleExternal calls.
-    ctx.ReplaceAll(
-        [&](const ast::CallExpression* expr) -> const ast::CallExpression* {
-          auto* builtin = sem.Get(expr)->Target()->As<sem::Builtin>();
-
-          if (builtin && !builtin->Parameters().empty() &&
-              builtin->Parameters()[0]->Type()->Is<sem::ExternalTexture>() &&
-              builtin->Type() != sem::BuiltinType::kTextureDimensions) {
-            if (auto* var_user = sem.Get<sem::VariableUser>(expr->args[0])) {
-              auto it = new_binding_symbols.find(var_user->Variable());
-              if (it == new_binding_symbols.end()) {
-                // If valid new binding locations were not provided earlier, we
-                // would have been unable to create these symbols. An error
-                // message was emitted earlier, so just return early to avoid
-                // internal compiler errors and retain a clean error message.
-                return nullptr;
-              }
-              auto& syms = it->second;
-
-              if (builtin->Type() == sem::BuiltinType::kTextureLoad) {
-                return createTexLdExt(expr, syms);
-              }
-
-              if (builtin->Type() == sem::BuiltinType::kTextureSampleLevel) {
-                return createTexSmpExt(expr, syms);
-              }
-            }
-
-          } else if (sem.Get(expr)->Target()->Is<sem::Function>()) {
-            // The call expression may be to a user-defined function that
-            // contains a texture_external parameter. These need to be expanded
-            // out to multiple plane textures and the texture parameters
-            // structure.
-            for (auto* arg : expr->args) {
-              if (auto* var_user = sem.Get<sem::VariableUser>(arg)) {
-                // Check if a parameter is a texture_external by trying to find
-                // it in the transform state.
-                auto it = new_binding_symbols.find(var_user->Variable());
-                if (it != new_binding_symbols.end()) {
-                  auto& syms = it->second;
-                  // When we find a texture_external, we must unpack it into its
-                  // components.
-                  ctx.Replace(arg, b.Expr(syms.plane_0));
-                  ctx.InsertAfter(expr->args, arg, b.Expr(syms.plane_1));
-                  ctx.InsertAfter(expr->args, arg, b.Expr(syms.params));
+        // We must update all the texture_external parameters for user declared
+        // functions.
+        for (auto* fn : ctx.src->AST().Functions()) {
+            for (const ast::Variable* param : fn->params) {
+                if (auto* sem_var = sem.Get(param)) {
+                    if (!sem_var->Type()->UnwrapRef()->Is<sem::ExternalTexture>()) {
+                        continue;
+                    }
+                    // If we find a texture_external, we must ensure the
+                    // ExternalTextureParams struct exists.
+                    if (!params_struct_sym.IsValid()) {
+                        createExtTexParamsStructs();
+                    }
+                    // When a texture_external is found, we insert all components
+                    // the texture_external into the parameter list. We must also place
+                    // the new symbols into the transform state so they can be used when
+                    // transforming function calls.
+                    auto& syms = new_binding_symbols[sem_var];
+                    syms.plane_0 = ctx.Clone(param->symbol);
+                    syms.plane_1 = b.Symbols().New("ext_tex_plane_1");
+                    syms.params = b.Symbols().New("ext_tex_params");
+                    auto tex2d_f32 = [&] {
+                        return b.ty.sampled_texture(ast::TextureDimension::k2d, b.ty.f32());
+                    };
+                    ctx.Replace(param, b.Param(syms.plane_0, tex2d_f32()));
+                    ctx.InsertAfter(fn->params, param, b.Param(syms.plane_1, tex2d_f32()));
+                    ctx.InsertAfter(fn->params, param,
+                                    b.Param(syms.params, b.ty.type_name(params_struct_sym)));
                 }
-              }
             }
-          }
+        }
 
-          return nullptr;
+        // Transform the original textureLoad and textureSampleLevel calls into
+        // textureLoadExternal and textureSampleExternal calls.
+        ctx.ReplaceAll([&](const ast::CallExpression* expr) -> const ast::CallExpression* {
+            auto* builtin = sem.Get(expr)->Target()->As<sem::Builtin>();
+
+            if (builtin && !builtin->Parameters().empty() &&
+                builtin->Parameters()[0]->Type()->Is<sem::ExternalTexture>() &&
+                builtin->Type() != sem::BuiltinType::kTextureDimensions) {
+                if (auto* var_user = sem.Get<sem::VariableUser>(expr->args[0])) {
+                    auto it = new_binding_symbols.find(var_user->Variable());
+                    if (it == new_binding_symbols.end()) {
+                        // If valid new binding locations were not provided earlier, we
+                        // would have been unable to create these symbols. An error
+                        // message was emitted earlier, so just return early to avoid
+                        // internal compiler errors and retain a clean error message.
+                        return nullptr;
+                    }
+                    auto& syms = it->second;
+
+                    if (builtin->Type() == sem::BuiltinType::kTextureLoad) {
+                        return createTexLdExt(expr, syms);
+                    }
+
+                    if (builtin->Type() == sem::BuiltinType::kTextureSampleLevel) {
+                        return createTexSmpExt(expr, syms);
+                    }
+                }
+
+            } else if (sem.Get(expr)->Target()->Is<sem::Function>()) {
+                // The call expression may be to a user-defined function that
+                // contains a texture_external parameter. These need to be expanded
+                // out to multiple plane textures and the texture parameters
+                // structure.
+                for (auto* arg : expr->args) {
+                    if (auto* var_user = sem.Get<sem::VariableUser>(arg)) {
+                        // Check if a parameter is a texture_external by trying to find
+                        // it in the transform state.
+                        auto it = new_binding_symbols.find(var_user->Variable());
+                        if (it != new_binding_symbols.end()) {
+                            auto& syms = it->second;
+                            // When we find a texture_external, we must unpack it into its
+                            // components.
+                            ctx.Replace(arg, b.Expr(syms.plane_0));
+                            ctx.InsertAfter(expr->args, arg, b.Expr(syms.plane_1));
+                            ctx.InsertAfter(expr->args, arg, b.Expr(syms.params));
+                        }
+                    }
+                }
+            }
+
+            return nullptr;
         });
-  }
-
-  /// Creates the ExternalTextureParams struct.
-  void createExtTexParamsStruct() {
-    ast::StructMemberList member_list = {
-        b.Member("numPlanes", b.ty.u32()), b.Member("vr", b.ty.f32()),
-        b.Member("ug", b.ty.f32()), b.Member("vg", b.ty.f32()),
-        b.Member("ub", b.ty.f32())};
-
-    params_struct_sym = b.Symbols().New("ExternalTextureParams");
-
-    b.Structure(params_struct_sym, member_list);
-  }
-
-  /// Constructs a StatementList containing all the statements making up the
-  /// bodies of the textureSampleExternal and textureLoadExternal functions.
-  /// @param call_type determines which function body to generate
-  /// @returns a statement list that makes of the body of the chosen function
-  ast::StatementList createTexFnExtStatementList(sem::BuiltinType call_type) {
-    using f32 = ProgramBuilder::f32;
-    const ast::CallExpression* single_plane_call = nullptr;
-    const ast::CallExpression* plane_0_call = nullptr;
-    const ast::CallExpression* plane_1_call = nullptr;
-    if (call_type == sem::BuiltinType::kTextureSampleLevel) {
-      // textureSampleLevel(plane0, smp, coord.xy, 0.0);
-      single_plane_call =
-          b.Call("textureSampleLevel", "plane0", "smp", "coord", 0.0f);
-      // textureSampleLevel(plane0, smp, coord.xy, 0.0);
-      plane_0_call =
-          b.Call("textureSampleLevel", "plane0", "smp", "coord", 0.0f);
-      // textureSampleLevel(plane1, smp, coord.xy, 0.0);
-      plane_1_call =
-          b.Call("textureSampleLevel", "plane1", "smp", "coord", 0.0f);
-    } else if (call_type == sem::BuiltinType::kTextureLoad) {
-      // textureLoad(plane0, coords.xy, 0);
-      single_plane_call = b.Call("textureLoad", "plane0", "coord", 0);
-      // textureLoad(plane0, coords.xy, 0);
-      plane_0_call = b.Call("textureLoad", "plane0", "coord", 0);
-      // textureLoad(plane1, coords.xy, 0);
-      plane_1_call = b.Call("textureLoad", "plane1", "coord", 0);
-    } else {
-      TINT_ICE(Transform, b.Diagnostics())
-          << "unhandled builtin: " << call_type;
     }
 
-    return {
-        // if (params.numPlanes == 1u) {
-        //    return singlePlaneCall
-        // }
-        b.If(b.create<ast::BinaryExpression>(
-                 ast::BinaryOp::kEqual, b.MemberAccessor("params", "numPlanes"),
-                 b.Expr(1u)),
-             b.Block(b.Return(single_plane_call))),
-        // let y = plane0Call.r - 0.0625;
-        b.Decl(b.Const("y", nullptr,
-                       b.Sub(b.MemberAccessor(plane_0_call, "r"), 0.0625f))),
-        // let uv = plane1Call.rg - 0.5;
-        b.Decl(b.Const("uv", nullptr,
-                       b.Sub(b.MemberAccessor(plane_1_call, "rg"), 0.5f))),
-        // let u = uv.x;
-        b.Decl(b.Const("u", nullptr, b.MemberAccessor("uv", "x"))),
-        // let v = uv.y;
-        b.Decl(b.Const("v", nullptr, b.MemberAccessor("uv", "y"))),
-        // let r = 1.164 * y + params.vr * v;
-        b.Decl(b.Const("r", nullptr,
-                       b.Add(b.Mul(1.164f, "y"),
-                             b.Mul(b.MemberAccessor("params", "vr"), "v")))),
-        // let g = 1.164 * y - params.ug * u - params.vg * v;
-        b.Decl(
-            b.Const("g", nullptr,
-                    b.Sub(b.Sub(b.Mul(1.164f, "y"),
-                                b.Mul(b.MemberAccessor("params", "ug"), "u")),
-                          b.Mul(b.MemberAccessor("params", "vg"), "v")))),
-        // let b = 1.164 * y + params.ub * u;
-        b.Decl(b.Const("b", nullptr,
-                       b.Add(b.Mul(1.164f, "y"),
-                             b.Mul(b.MemberAccessor("params", "ub"), "u")))),
-        // return vec4<f32>(r, g, b, 1.0);
-        b.Return(b.vec4<f32>("r", "g", "b", 1.0f)),
-    };
-  }
+    /// Creates the parameter structs associated with the transform.
+    void createExtTexParamsStructs() {
+        // Create GammaTransferParams struct.
+        ast::StructMemberList gamma_transfer_member_list = {
+            b.Member("G", b.ty.f32()), b.Member("A", b.ty.f32()),      b.Member("B", b.ty.f32()),
+            b.Member("C", b.ty.f32()), b.Member("D", b.ty.f32()),      b.Member("E", b.ty.f32()),
+            b.Member("F", b.ty.f32()), b.Member("padding", b.ty.u32())};
 
-  /// Creates the textureSampleExternal function if needed and returns a call
-  /// expression to it.
-  /// @param expr the call expression being transformed
-  /// @param syms the expanded symbols to be used in the new call
-  /// @returns a call expression to textureSampleExternal
-  const ast::CallExpression* createTexSmpExt(const ast::CallExpression* expr,
-                                             NewBindingSymbols syms) {
-    ast::ExpressionList params;
-    const ast::Expression* plane_0_binding_param = ctx.Clone(expr->args[0]);
+        gamma_transfer_struct_sym = b.Symbols().New("GammaTransferParams");
 
-    if (expr->args.size() != 3) {
-      TINT_ICE(Transform, b.Diagnostics())
-          << "expected textureSampleLevel call with a "
-             "texture_external to have 3 parameters, found "
-          << expr->args.size() << " parameters";
+        b.Structure(gamma_transfer_struct_sym, gamma_transfer_member_list);
+
+        // Create ExternalTextureParams struct.
+        ast::StructMemberList ext_tex_params_member_list = {
+            b.Member("numPlanes", b.ty.u32()),
+            b.Member("yuvToRgbConversionMatrix", b.ty.mat3x4(b.ty.f32())),
+            b.Member("gammaDecodeParams", b.ty.type_name("GammaTransferParams")),
+            b.Member("gammaEncodeParams", b.ty.type_name("GammaTransferParams")),
+            b.Member("gamutConversionMatrix", b.ty.mat3x3(b.ty.f32()))};
+
+        params_struct_sym = b.Symbols().New("ExternalTextureParams");
+
+        b.Structure(params_struct_sym, ext_tex_params_member_list);
     }
 
-    if (!texture_sample_external_sym.IsValid()) {
-      texture_sample_external_sym = b.Symbols().New("textureSampleExternal");
+    /// Creates the gammaCorrection function if needed and returns a call
+    /// expression to it.
+    void createGammaCorrectionFn() {
+        ast::VariableList varList = {b.Param("v", b.ty.vec3<f32>()),
+                                     b.Param("params", b.ty.type_name(gamma_transfer_struct_sym))};
 
-      // Emit the textureSampleExternal function.
-      ast::VariableList varList = {
-          b.Param("plane0",
-                  b.ty.sampled_texture(ast::TextureDimension::k2d, b.ty.f32())),
-          b.Param("plane1",
-                  b.ty.sampled_texture(ast::TextureDimension::k2d, b.ty.f32())),
-          b.Param("smp", b.ty.sampler(ast::SamplerKind::kSampler)),
-          b.Param("coord", b.ty.vec2(b.ty.f32())),
-          b.Param("params", b.ty.type_name(params_struct_sym))};
+        ast::StatementList statementList = {
+            // let cond = abs(v) < vec3(params.D);
+            b.Decl(b.Let(
+                "cond", nullptr,
+                b.LessThan(b.Call("abs", "v"), b.vec3<f32>(b.MemberAccessor("params", "D"))))),
+            // let t = sign(v) * ((params.C * abs(v)) + params.F);
+            b.Decl(b.Let("t", nullptr,
+                         b.Mul(b.Call("sign", "v"),
+                               b.Add(b.Mul(b.MemberAccessor("params", "C"), b.Call("abs", "v")),
+                                     b.MemberAccessor("params", "F"))))),
+            // let f = (sign(v) * pow(((params.A * abs(v)) + params.B),
+            // vec3(params.G))) + params.E;
+            b.Decl(b.Let(
+                "f", nullptr,
+                b.Mul(b.Call("sign", "v"),
+                      b.Add(b.Call("pow",
+                                   b.Add(b.Mul(b.MemberAccessor("params", "A"), b.Call("abs", "v")),
+                                         b.MemberAccessor("params", "B")),
+                                   b.vec3<f32>(b.MemberAccessor("params", "G"))),
+                            b.MemberAccessor("params", "E"))))),
+            // return select(f, t, cond);
+            b.Return(b.Call("select", "f", "t", "cond"))};
 
-      ast::StatementList statementList =
-          createTexFnExtStatementList(sem::BuiltinType::kTextureSampleLevel);
+        gamma_correction_sym = b.Symbols().New("gammaCorrection");
 
-      b.Func(texture_sample_external_sym, varList, b.ty.vec4(b.ty.f32()),
-             statementList, {});
+        b.Func(gamma_correction_sym, varList, b.ty.vec3<f32>(), statementList, {});
     }
 
-    const ast::IdentifierExpression* exp = b.Expr(texture_sample_external_sym);
-    params = {plane_0_binding_param, b.Expr(syms.plane_1),
-              ctx.Clone(expr->args[1]), ctx.Clone(expr->args[2]),
-              b.Expr(syms.params)};
-    return b.Call(exp, params);
-  }
+    /// Constructs a StatementList containing all the statements making up the
+    /// bodies of the textureSampleExternal and textureLoadExternal functions.
+    /// @param call_type determines which function body to generate
+    /// @returns a statement list that makes of the body of the chosen function
+    ast::StatementList createTexFnExtStatementList(sem::BuiltinType call_type) {
+        const ast::CallExpression* single_plane_call = nullptr;
+        const ast::CallExpression* plane_0_call = nullptr;
+        const ast::CallExpression* plane_1_call = nullptr;
+        if (call_type == sem::BuiltinType::kTextureSampleLevel) {
+            // textureSampleLevel(plane0, smp, coord.xy, 0.0);
+            single_plane_call = b.Call("textureSampleLevel", "plane0", "smp", "coord", 0.0f);
+            // textureSampleLevel(plane0, smp, coord.xy, 0.0);
+            plane_0_call = b.Call("textureSampleLevel", "plane0", "smp", "coord", 0.0f);
+            // textureSampleLevel(plane1, smp, coord.xy, 0.0);
+            plane_1_call = b.Call("textureSampleLevel", "plane1", "smp", "coord", 0.0f);
+        } else if (call_type == sem::BuiltinType::kTextureLoad) {
+            // textureLoad(plane0, coords.xy, 0);
+            single_plane_call = b.Call("textureLoad", "plane0", "coord", 0_i);
+            // textureLoad(plane0, coords.xy, 0);
+            plane_0_call = b.Call("textureLoad", "plane0", "coord", 0_i);
+            // textureLoad(plane1, coords.xy, 0);
+            plane_1_call = b.Call("textureLoad", "plane1", "coord", 0_i);
+        } else {
+            TINT_ICE(Transform, b.Diagnostics()) << "unhandled builtin: " << call_type;
+        }
 
-  /// Creates the textureLoadExternal function if needed and returns a call
-  /// expression to it.
-  /// @param expr the call expression being transformed
-  /// @param syms the expanded symbols to be used in the new call
-  /// @returns a call expression to textureLoadExternal
-  const ast::CallExpression* createTexLdExt(const ast::CallExpression* expr,
-                                            NewBindingSymbols syms) {
-    ast::ExpressionList params;
-    const ast::Expression* plane_0_binding_param = ctx.Clone(expr->args[0]);
-
-    if (expr->args.size() != 2) {
-      TINT_ICE(Transform, b.Diagnostics())
-          << "expected textureLoad call with a texture_external "
-             "to have 2 parameters, found "
-          << expr->args.size() << " parameters";
+        return {
+            // var color: vec3<f32>;
+            b.Decl(b.Var("color", b.ty.vec3(b.ty.f32()))),
+            // if ((params.numPlanes == 1u))
+            b.If(b.create<ast::BinaryExpression>(
+                     ast::BinaryOp::kEqual, b.MemberAccessor("params", "numPlanes"), b.Expr(1_u)),
+                 b.Block(
+                     // color = textureLoad(plane0, coord, 0).rgb;
+                     b.Assign("color", b.MemberAccessor(single_plane_call, "rgb"))),
+                 b.Else(b.Block(
+                     // color = vec4<f32>(plane_0_call.r, plane_1_call.rg, 1.0) *
+                     //         params.yuvToRgbConversionMatrix;
+                     b.Assign("color",
+                              b.Mul(b.vec4<f32>(b.MemberAccessor(plane_0_call, "r"),
+                                                b.MemberAccessor(plane_1_call, "rg"), 1.0f),
+                                    b.MemberAccessor("params", "yuvToRgbConversionMatrix")))))),
+            // color = gammaConversion(color, gammaDecodeParams);
+            b.Assign("color", b.Call("gammaCorrection", "color",
+                                     b.MemberAccessor("params", "gammaDecodeParams"))),
+            // color = (params.gamutConversionMatrix * color);
+            b.Assign("color", b.Mul(b.MemberAccessor("params", "gamutConversionMatrix"), "color")),
+            // color = gammaConversion(color, gammaEncodeParams);
+            b.Assign("color", b.Call("gammaCorrection", "color",
+                                     b.MemberAccessor("params", "gammaEncodeParams"))),
+            // return vec4<f32>(color, 1.0f);
+            b.Return(b.vec4<f32>("color", 1.0f))};
     }
 
-    if (!texture_load_external_sym.IsValid()) {
-      texture_load_external_sym = b.Symbols().New("textureLoadExternal");
+    /// Creates the textureSampleExternal function if needed and returns a call
+    /// expression to it.
+    /// @param expr the call expression being transformed
+    /// @param syms the expanded symbols to be used in the new call
+    /// @returns a call expression to textureSampleExternal
+    const ast::CallExpression* createTexSmpExt(const ast::CallExpression* expr,
+                                               NewBindingSymbols syms) {
+        ast::ExpressionList params;
+        const ast::Expression* plane_0_binding_param = ctx.Clone(expr->args[0]);
 
-      // Emit the textureLoadExternal function.
-      ast::VariableList var_list = {
-          b.Param("plane0",
-                  b.ty.sampled_texture(ast::TextureDimension::k2d, b.ty.f32())),
-          b.Param("plane1",
-                  b.ty.sampled_texture(ast::TextureDimension::k2d, b.ty.f32())),
-          b.Param("coord", b.ty.vec2(b.ty.i32())),
-          b.Param("params", b.ty.type_name(params_struct_sym))};
+        if (expr->args.size() != 3) {
+            TINT_ICE(Transform, b.Diagnostics()) << "expected textureSampleLevel call with a "
+                                                    "texture_external to have 3 parameters, found "
+                                                 << expr->args.size() << " parameters";
+        }
 
-      ast::StatementList statement_list =
-          createTexFnExtStatementList(sem::BuiltinType::kTextureLoad);
+        // TextureSampleExternal calls the gammaCorrection function, so ensure it
+        // exists.
+        if (!gamma_correction_sym.IsValid()) {
+            createGammaCorrectionFn();
+        }
 
-      b.Func(texture_load_external_sym, var_list, b.ty.vec4(b.ty.f32()),
-             statement_list, {});
+        if (!texture_sample_external_sym.IsValid()) {
+            texture_sample_external_sym = b.Symbols().New("textureSampleExternal");
+
+            // Emit the textureSampleExternal function.
+            ast::VariableList varList = {
+                b.Param("plane0", b.ty.sampled_texture(ast::TextureDimension::k2d, b.ty.f32())),
+                b.Param("plane1", b.ty.sampled_texture(ast::TextureDimension::k2d, b.ty.f32())),
+                b.Param("smp", b.ty.sampler(ast::SamplerKind::kSampler)),
+                b.Param("coord", b.ty.vec2(b.ty.f32())),
+                b.Param("params", b.ty.type_name(params_struct_sym))};
+
+            ast::StatementList statementList =
+                createTexFnExtStatementList(sem::BuiltinType::kTextureSampleLevel);
+
+            b.Func(texture_sample_external_sym, varList, b.ty.vec4(b.ty.f32()), statementList, {});
+        }
+
+        const ast::IdentifierExpression* exp = b.Expr(texture_sample_external_sym);
+        params = {plane_0_binding_param, b.Expr(syms.plane_1), ctx.Clone(expr->args[1]),
+                  ctx.Clone(expr->args[2]), b.Expr(syms.params)};
+        return b.Call(exp, params);
     }
 
-    const ast::IdentifierExpression* exp = b.Expr(texture_load_external_sym);
-    params = {plane_0_binding_param, b.Expr(syms.plane_1),
-              ctx.Clone(expr->args[1]), b.Expr(syms.params)};
-    return b.Call(exp, params);
-  }
+    /// Creates the textureLoadExternal function if needed and returns a call
+    /// expression to it.
+    /// @param expr the call expression being transformed
+    /// @param syms the expanded symbols to be used in the new call
+    /// @returns a call expression to textureLoadExternal
+    const ast::CallExpression* createTexLdExt(const ast::CallExpression* expr,
+                                              NewBindingSymbols syms) {
+        ast::ExpressionList params;
+        const ast::Expression* plane_0_binding_param = ctx.Clone(expr->args[0]);
+
+        if (expr->args.size() != 2) {
+            TINT_ICE(Transform, b.Diagnostics())
+                << "expected textureLoad call with a texture_external "
+                   "to have 2 parameters, found "
+                << expr->args.size() << " parameters";
+        }
+
+        // TextureLoadExternal calls the gammaCorrection function, so ensure it
+        // exists.
+        if (!gamma_correction_sym.IsValid()) {
+            createGammaCorrectionFn();
+        }
+
+        if (!texture_load_external_sym.IsValid()) {
+            texture_load_external_sym = b.Symbols().New("textureLoadExternal");
+
+            // Emit the textureLoadExternal function.
+            ast::VariableList var_list = {
+                b.Param("plane0", b.ty.sampled_texture(ast::TextureDimension::k2d, b.ty.f32())),
+                b.Param("plane1", b.ty.sampled_texture(ast::TextureDimension::k2d, b.ty.f32())),
+                b.Param("coord", b.ty.vec2(b.ty.i32())),
+                b.Param("params", b.ty.type_name(params_struct_sym))};
+
+            ast::StatementList statement_list =
+                createTexFnExtStatementList(sem::BuiltinType::kTextureLoad);
+
+            b.Func(texture_load_external_sym, var_list, b.ty.vec4(b.ty.f32()), statement_list, {});
+        }
+
+        const ast::IdentifierExpression* exp = b.Expr(texture_load_external_sym);
+        params = {plane_0_binding_param, b.Expr(syms.plane_1), ctx.Clone(expr->args[1]),
+                  b.Expr(syms.params)};
+        return b.Call(exp, params);
+    }
 };
 
-MultiplanarExternalTexture::NewBindingPoints::NewBindingPoints(
-    BindingsMap inputBindingsMap)
+MultiplanarExternalTexture::NewBindingPoints::NewBindingPoints(BindingsMap inputBindingsMap)
     : bindings_map(std::move(inputBindingsMap)) {}
 MultiplanarExternalTexture::NewBindingPoints::~NewBindingPoints() = default;
 
 MultiplanarExternalTexture::MultiplanarExternalTexture() = default;
 MultiplanarExternalTexture::~MultiplanarExternalTexture() = default;
 
-bool MultiplanarExternalTexture::ShouldRun(const Program* program,
-                                           const DataMap&) const {
-  for (auto* node : program->ASTNodes().Objects()) {
-    if (auto* ty = node->As<ast::Type>()) {
-      if (program->Sem().Get<sem::ExternalTexture>(ty)) {
-        return true;
-      }
+bool MultiplanarExternalTexture::ShouldRun(const Program* program, const DataMap&) const {
+    for (auto* node : program->ASTNodes().Objects()) {
+        if (auto* ty = node->As<ast::Type>()) {
+            if (program->Sem().Get<sem::ExternalTexture>(ty)) {
+                return true;
+            }
+        }
     }
-  }
-  return false;
+    return false;
 }
 
 // Within this transform, an instance of a texture_external binding is unpacked
@@ -430,23 +464,21 @@
 // texture_external parameter will be transformed into a newly generated version
 // of the function, which can perform the desired operation on a single RGBA
 // plane or on separate Y and UV planes.
-void MultiplanarExternalTexture::Run(CloneContext& ctx,
-                                     const DataMap& inputs,
-                                     DataMap&) const {
-  auto* new_binding_points = inputs.Get<NewBindingPoints>();
+void MultiplanarExternalTexture::Run(CloneContext& ctx, const DataMap& inputs, DataMap&) const {
+    auto* new_binding_points = inputs.Get<NewBindingPoints>();
 
-  if (!new_binding_points) {
-    ctx.dst->Diagnostics().add_error(
-        diag::System::Transform,
-        "missing new binding point data for " + std::string(TypeInfo().name));
-    return;
-  }
+    if (!new_binding_points) {
+        ctx.dst->Diagnostics().add_error(
+            diag::System::Transform,
+            "missing new binding point data for " + std::string(TypeInfo().name));
+        return;
+    }
 
-  State state(ctx, new_binding_points);
+    State state(ctx, new_binding_points);
 
-  state.Process();
+    state.Process();
 
-  ctx.Clone();
+    ctx.Clone();
 }
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/multiplanar_external_texture.h b/src/tint/transform/multiplanar_external_texture.h
index ab2298c..88cbc98 100644
--- a/src/tint/transform/multiplanar_external_texture.h
+++ b/src/tint/transform/multiplanar_external_texture.h
@@ -31,12 +31,12 @@
 /// This struct identifies the binding groups and locations for new bindings to
 /// use when transforming a texture_external instance.
 struct BindingPoints {
-  /// The desired binding location of the texture_2d representing plane #1 when
-  /// a texture_external binding is expanded.
-  BindingPoint plane_1;
-  /// The desired binding location of the ExternalTextureParams uniform when a
-  /// texture_external binding is expanded.
-  BindingPoint params;
+    /// The desired binding location of the texture_2d representing plane #1 when
+    /// a texture_external binding is expanded.
+    BindingPoint plane_1;
+    /// The desired binding location of the ExternalTextureParams uniform when a
+    /// texture_external binding is expanded.
+    BindingPoint params;
 };
 
 /// Within the MultiplanarExternalTexture transform, each instance of a
@@ -47,52 +47,48 @@
 /// transformed into a newly generated version of the function, which can
 /// perform the desired operation on a single RGBA plane or on seperate Y and UV
 /// planes.
-class MultiplanarExternalTexture
-    : public Castable<MultiplanarExternalTexture, Transform> {
- public:
-  /// BindingsMap is a map where the key is the binding location of a
-  /// texture_external and the value is a struct containing the desired
-  /// locations for new bindings expanded from the texture_external instance.
-  using BindingsMap = std::unordered_map<BindingPoint, BindingPoints>;
+class MultiplanarExternalTexture : public Castable<MultiplanarExternalTexture, Transform> {
+  public:
+    /// BindingsMap is a map where the key is the binding location of a
+    /// texture_external and the value is a struct containing the desired
+    /// locations for new bindings expanded from the texture_external instance.
+    using BindingsMap = std::unordered_map<BindingPoint, BindingPoints>;
 
-  /// NewBindingPoints is consumed by the MultiplanarExternalTexture transform.
-  /// Data holds information about location of each texture_external binding and
-  /// which binding slots it should expand into.
-  struct NewBindingPoints : public Castable<Data, transform::Data> {
+    /// NewBindingPoints is consumed by the MultiplanarExternalTexture transform.
+    /// Data holds information about location of each texture_external binding and
+    /// which binding slots it should expand into.
+    struct NewBindingPoints : public Castable<Data, transform::Data> {
+        /// Constructor
+        /// @param bm a map to the new binding slots to use.
+        explicit NewBindingPoints(BindingsMap bm);
+
+        /// Destructor
+        ~NewBindingPoints() override;
+
+        /// A map of new binding points to use.
+        const BindingsMap bindings_map;
+    };
+
     /// Constructor
-    /// @param bm a map to the new binding slots to use.
-    explicit NewBindingPoints(BindingsMap bm);
-
+    MultiplanarExternalTexture();
     /// Destructor
-    ~NewBindingPoints() override;
+    ~MultiplanarExternalTexture() override;
 
-    /// A map of new binding points to use.
-    const BindingsMap bindings_map;
-  };
+    /// @param program the program to inspect
+    /// @param data optional extra transform-specific input data
+    /// @returns true if this transform should be run for the given program
+    bool ShouldRun(const Program* program, const DataMap& data = {}) const override;
 
-  /// Constructor
-  MultiplanarExternalTexture();
-  /// Destructor
-  ~MultiplanarExternalTexture() override;
+  protected:
+    struct State;
 
-  /// @param program the program to inspect
-  /// @param data optional extra transform-specific input data
-  /// @returns true if this transform should be run for the given program
-  bool ShouldRun(const Program* program,
-                 const DataMap& data = {}) const override;
-
- protected:
-  struct State;
-
-  /// Runs the transform using the CloneContext built for transforming a
-  /// program. Run() is responsible for calling Clone() on the CloneContext.
-  /// @param ctx the CloneContext primed with the input program and
-  /// ProgramBuilder
-  /// @param inputs optional extra transform-specific input data
-  /// @param outputs optional extra transform-specific output data
-  void Run(CloneContext& ctx,
-           const DataMap& inputs,
-           DataMap& outputs) const override;
+    /// Runs the transform using the CloneContext built for transforming a
+    /// program. Run() is responsible for calling Clone() on the CloneContext.
+    /// @param ctx the CloneContext primed with the input program and
+    /// ProgramBuilder
+    /// @param inputs optional extra transform-specific input data
+    /// @param outputs optional extra transform-specific output data
+    void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const override;
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/multiplanar_external_texture_test.cc b/src/tint/transform/multiplanar_external_texture_test.cc
index b0a79d6..171df8d 100644
--- a/src/tint/transform/multiplanar_external_texture_test.cc
+++ b/src/tint/transform/multiplanar_external_texture_test.cc
@@ -21,38 +21,38 @@
 using MultiplanarExternalTextureTest = TransformTest;
 
 TEST_F(MultiplanarExternalTextureTest, ShouldRunEmptyModule) {
-  auto* src = R"()";
+    auto* src = R"()";
 
-  EXPECT_FALSE(ShouldRun<MultiplanarExternalTexture>(src));
+    EXPECT_FALSE(ShouldRun<MultiplanarExternalTexture>(src));
 }
 
 TEST_F(MultiplanarExternalTextureTest, ShouldRunHasExternalTextureAlias) {
-  auto* src = R"(
+    auto* src = R"(
 type ET = texture_external;
 )";
 
-  EXPECT_TRUE(ShouldRun<MultiplanarExternalTexture>(src));
+    EXPECT_TRUE(ShouldRun<MultiplanarExternalTexture>(src));
 }
 TEST_F(MultiplanarExternalTextureTest, ShouldRunHasExternalTextureGlobal) {
-  auto* src = R"(
+    auto* src = R"(
 @group(0) @binding(0) var ext_tex : texture_external;
 )";
 
-  EXPECT_TRUE(ShouldRun<MultiplanarExternalTexture>(src));
+    EXPECT_TRUE(ShouldRun<MultiplanarExternalTexture>(src));
 }
 
 TEST_F(MultiplanarExternalTextureTest, ShouldRunHasExternalTextureParam) {
-  auto* src = R"(
+    auto* src = R"(
 fn f(ext_tex : texture_external) {}
 )";
 
-  EXPECT_TRUE(ShouldRun<MultiplanarExternalTexture>(src));
+    EXPECT_TRUE(ShouldRun<MultiplanarExternalTexture>(src));
 }
 
 // Running the transform without passing in data for the new bindings should
 // result in an error.
 TEST_F(MultiplanarExternalTextureTest, ErrorNoPassedData) {
-  auto* src = R"(
+    auto* src = R"(
 @group(0) @binding(0) var s : sampler;
 @group(0) @binding(1) var ext_tex : texture_external;
 
@@ -61,16 +61,16 @@
   return textureSampleLevel(ext_tex, s, coord.xy);
 }
 )";
-  auto* expect =
-      R"(error: missing new binding point data for tint::transform::MultiplanarExternalTexture)";
+    auto* expect =
+        R"(error: missing new binding point data for tint::transform::MultiplanarExternalTexture)";
 
-  auto got = Run<MultiplanarExternalTexture>(src);
-  EXPECT_EQ(expect, str(got));
+    auto got = Run<MultiplanarExternalTexture>(src);
+    EXPECT_EQ(expect, str(got));
 }
 
 // Running the transform with incorrect binding data should result in an error.
 TEST_F(MultiplanarExternalTextureTest, ErrorIncorrectBindingPont) {
-  auto* src = R"(
+    auto* src = R"(
 @group(0) @binding(0) var s : sampler;
 @group(0) @binding(1) var ext_tex : texture_external;
 
@@ -80,21 +80,20 @@
 }
 )";
 
-  auto* expect =
-      R"(error: missing new binding points for texture_external at binding {0,1})";
+    auto* expect = R"(error: missing new binding points for texture_external at binding {0,1})";
 
-  DataMap data;
-  // This bindings map specifies 0,0 as the location of the texture_external,
-  // which is incorrect.
-  data.Add<MultiplanarExternalTexture::NewBindingPoints>(
-      MultiplanarExternalTexture::BindingsMap{{{0, 0}, {{0, 1}, {0, 2}}}});
-  auto got = Run<MultiplanarExternalTexture>(src, data);
-  EXPECT_EQ(expect, str(got));
+    DataMap data;
+    // This bindings map specifies 0,0 as the location of the texture_external,
+    // which is incorrect.
+    data.Add<MultiplanarExternalTexture::NewBindingPoints>(
+        MultiplanarExternalTexture::BindingsMap{{{0, 0}, {{0, 1}, {0, 2}}}});
+    auto got = Run<MultiplanarExternalTexture>(src, data);
+    EXPECT_EQ(expect, str(got));
 }
 
 // Tests that the transform works with a textureDimensions call.
 TEST_F(MultiplanarExternalTextureTest, Dimensions) {
-  auto* src = R"(
+    auto* src = R"(
 @group(0) @binding(0) var ext_tex : texture_external;
 
 @stage(fragment)
@@ -105,13 +104,24 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
+struct GammaTransferParams {
+  G : f32,
+  A : f32,
+  B : f32,
+  C : f32,
+  D : f32,
+  E : f32,
+  F : f32,
+  padding : u32,
+}
+
 struct ExternalTextureParams {
   numPlanes : u32,
-  vr : f32,
-  ug : f32,
-  vg : f32,
-  ub : f32,
+  yuvToRgbConversionMatrix : mat3x4<f32>,
+  gammaDecodeParams : GammaTransferParams,
+  gammaEncodeParams : GammaTransferParams,
+  gamutConversionMatrix : mat3x3<f32>,
 }
 
 @group(0) @binding(1) var ext_tex_plane_1 : texture_2d<f32>;
@@ -128,16 +138,16 @@
 }
 )";
 
-  DataMap data;
-  data.Add<MultiplanarExternalTexture::NewBindingPoints>(
-      MultiplanarExternalTexture::BindingsMap{{{0, 0}, {{0, 1}, {0, 2}}}});
-  auto got = Run<MultiplanarExternalTexture>(src, data);
-  EXPECT_EQ(expect, str(got));
+    DataMap data;
+    data.Add<MultiplanarExternalTexture::NewBindingPoints>(
+        MultiplanarExternalTexture::BindingsMap{{{0, 0}, {{0, 1}, {0, 2}}}});
+    auto got = Run<MultiplanarExternalTexture>(src, data);
+    EXPECT_EQ(expect, str(got));
 }
 
 // Tests that the transform works with a textureDimensions call.
 TEST_F(MultiplanarExternalTextureTest, Dimensions_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(fragment)
 fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
   var dim : vec2<i32>;
@@ -148,13 +158,24 @@
 @group(0) @binding(0) var ext_tex : texture_external;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
+struct GammaTransferParams {
+  G : f32,
+  A : f32,
+  B : f32,
+  C : f32,
+  D : f32,
+  E : f32,
+  F : f32,
+  padding : u32,
+}
+
 struct ExternalTextureParams {
   numPlanes : u32,
-  vr : f32,
-  ug : f32,
-  vg : f32,
-  ub : f32,
+  yuvToRgbConversionMatrix : mat3x4<f32>,
+  gammaDecodeParams : GammaTransferParams,
+  gammaEncodeParams : GammaTransferParams,
+  gamutConversionMatrix : mat3x3<f32>,
 }
 
 @group(0) @binding(1) var ext_tex_plane_1 : texture_2d<f32>;
@@ -171,16 +192,16 @@
 @group(0) @binding(0) var ext_tex : texture_2d<f32>;
 )";
 
-  DataMap data;
-  data.Add<MultiplanarExternalTexture::NewBindingPoints>(
-      MultiplanarExternalTexture::BindingsMap{{{0, 0}, {{0, 1}, {0, 2}}}});
-  auto got = Run<MultiplanarExternalTexture>(src, data);
-  EXPECT_EQ(expect, str(got));
+    DataMap data;
+    data.Add<MultiplanarExternalTexture::NewBindingPoints>(
+        MultiplanarExternalTexture::BindingsMap{{{0, 0}, {{0, 1}, {0, 2}}}});
+    auto got = Run<MultiplanarExternalTexture>(src, data);
+    EXPECT_EQ(expect, str(got));
 }
 
 // Test that the transform works with a textureSampleLevel call.
 TEST_F(MultiplanarExternalTextureTest, BasicTextureSampleLevel) {
-  auto* src = R"(
+    auto* src = R"(
 @group(0) @binding(0) var s : sampler;
 @group(0) @binding(1) var ext_tex : texture_external;
 
@@ -190,13 +211,24 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
+struct GammaTransferParams {
+  G : f32,
+  A : f32,
+  B : f32,
+  C : f32,
+  D : f32,
+  E : f32,
+  F : f32,
+  padding : u32,
+}
+
 struct ExternalTextureParams {
   numPlanes : u32,
-  vr : f32,
-  ug : f32,
-  vg : f32,
-  ub : f32,
+  yuvToRgbConversionMatrix : mat3x4<f32>,
+  gammaDecodeParams : GammaTransferParams,
+  gammaEncodeParams : GammaTransferParams,
+  gamutConversionMatrix : mat3x3<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@@ -207,18 +239,24 @@
 
 @group(0) @binding(1) var ext_tex : texture_2d<f32>;
 
+fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
+  let cond = (abs(v) < vec3<f32>(params.D));
+  let t = (sign(v) * ((params.C * abs(v)) + params.F));
+  let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
+  return select(f, t, cond);
+}
+
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
+  var color : vec3<f32>;
   if ((params.numPlanes == 1u)) {
-    return textureSampleLevel(plane0, smp, coord, 0.0);
+    color = textureSampleLevel(plane0, smp, coord, 0.0).rgb;
+  } else {
+    color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
-  let y = (textureSampleLevel(plane0, smp, coord, 0.0).r - 0.0625);
-  let uv = (textureSampleLevel(plane1, smp, coord, 0.0).rg - 0.5);
-  let u = uv.x;
-  let v = uv.y;
-  let r = ((1.164000034 * y) + (params.vr * v));
-  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
-  let b = ((1.164000034 * y) + (params.ub * u));
-  return vec4<f32>(r, g, b, 1.0);
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = (params.gamutConversionMatrix * color);
+  color = gammaCorrection(color, params.gammaEncodeParams);
+  return vec4<f32>(color, 1.0);
 }
 
 @stage(fragment)
@@ -227,16 +265,16 @@
 }
 )";
 
-  DataMap data;
-  data.Add<MultiplanarExternalTexture::NewBindingPoints>(
-      MultiplanarExternalTexture::BindingsMap{{{0, 1}, {{0, 2}, {0, 3}}}});
-  auto got = Run<MultiplanarExternalTexture>(src, data);
-  EXPECT_EQ(expect, str(got));
+    DataMap data;
+    data.Add<MultiplanarExternalTexture::NewBindingPoints>(
+        MultiplanarExternalTexture::BindingsMap{{{0, 1}, {{0, 2}, {0, 3}}}});
+    auto got = Run<MultiplanarExternalTexture>(src, data);
+    EXPECT_EQ(expect, str(got));
 }
 
 // Test that the transform works with a textureSampleLevel call.
 TEST_F(MultiplanarExternalTextureTest, BasicTextureSampleLevel_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(fragment)
 fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
   return textureSampleLevel(ext_tex, s, coord.xy);
@@ -246,31 +284,48 @@
 @group(0) @binding(0) var s : sampler;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
+struct GammaTransferParams {
+  G : f32,
+  A : f32,
+  B : f32,
+  C : f32,
+  D : f32,
+  E : f32,
+  F : f32,
+  padding : u32,
+}
+
 struct ExternalTextureParams {
   numPlanes : u32,
-  vr : f32,
-  ug : f32,
-  vg : f32,
-  ub : f32,
+  yuvToRgbConversionMatrix : mat3x4<f32>,
+  gammaDecodeParams : GammaTransferParams,
+  gammaEncodeParams : GammaTransferParams,
+  gamutConversionMatrix : mat3x3<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
 
 @group(0) @binding(3) var<uniform> ext_tex_params : ExternalTextureParams;
 
+fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
+  let cond = (abs(v) < vec3<f32>(params.D));
+  let t = (sign(v) * ((params.C * abs(v)) + params.F));
+  let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
+  return select(f, t, cond);
+}
+
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
+  var color : vec3<f32>;
   if ((params.numPlanes == 1u)) {
-    return textureSampleLevel(plane0, smp, coord, 0.0);
+    color = textureSampleLevel(plane0, smp, coord, 0.0).rgb;
+  } else {
+    color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
-  let y = (textureSampleLevel(plane0, smp, coord, 0.0).r - 0.0625);
-  let uv = (textureSampleLevel(plane1, smp, coord, 0.0).rg - 0.5);
-  let u = uv.x;
-  let v = uv.y;
-  let r = ((1.164000034 * y) + (params.vr * v));
-  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
-  let b = ((1.164000034 * y) + (params.ub * u));
-  return vec4<f32>(r, g, b, 1.0);
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = (params.gamutConversionMatrix * color);
+  color = gammaCorrection(color, params.gammaEncodeParams);
+  return vec4<f32>(color, 1.0);
 }
 
 @stage(fragment)
@@ -283,16 +338,16 @@
 @group(0) @binding(0) var s : sampler;
 )";
 
-  DataMap data;
-  data.Add<MultiplanarExternalTexture::NewBindingPoints>(
-      MultiplanarExternalTexture::BindingsMap{{{0, 1}, {{0, 2}, {0, 3}}}});
-  auto got = Run<MultiplanarExternalTexture>(src, data);
-  EXPECT_EQ(expect, str(got));
+    DataMap data;
+    data.Add<MultiplanarExternalTexture::NewBindingPoints>(
+        MultiplanarExternalTexture::BindingsMap{{{0, 1}, {{0, 2}, {0, 3}}}});
+    auto got = Run<MultiplanarExternalTexture>(src, data);
+    EXPECT_EQ(expect, str(got));
 }
 
 // Tests that the transform works with a textureLoad call.
 TEST_F(MultiplanarExternalTextureTest, BasicTextureLoad) {
-  auto* src = R"(
+    auto* src = R"(
 @group(0) @binding(0) var ext_tex : texture_external;
 
 @stage(fragment)
@@ -301,13 +356,24 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
+struct GammaTransferParams {
+  G : f32,
+  A : f32,
+  B : f32,
+  C : f32,
+  D : f32,
+  E : f32,
+  F : f32,
+  padding : u32,
+}
+
 struct ExternalTextureParams {
   numPlanes : u32,
-  vr : f32,
-  ug : f32,
-  vg : f32,
-  ub : f32,
+  yuvToRgbConversionMatrix : mat3x4<f32>,
+  gammaDecodeParams : GammaTransferParams,
+  gammaEncodeParams : GammaTransferParams,
+  gamutConversionMatrix : mat3x3<f32>,
 }
 
 @group(0) @binding(1) var ext_tex_plane_1 : texture_2d<f32>;
@@ -316,18 +382,24 @@
 
 @group(0) @binding(0) var ext_tex : texture_2d<f32>;
 
+fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
+  let cond = (abs(v) < vec3<f32>(params.D));
+  let t = (sign(v) * ((params.C * abs(v)) + params.F));
+  let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
+  return select(f, t, cond);
+}
+
 fn textureLoadExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, coord : vec2<i32>, params : ExternalTextureParams) -> vec4<f32> {
+  var color : vec3<f32>;
   if ((params.numPlanes == 1u)) {
-    return textureLoad(plane0, coord, 0);
+    color = textureLoad(plane0, coord, 0i).rgb;
+  } else {
+    color = (vec4<f32>(textureLoad(plane0, coord, 0i).r, textureLoad(plane1, coord, 0i).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
-  let y = (textureLoad(plane0, coord, 0).r - 0.0625);
-  let uv = (textureLoad(plane1, coord, 0).rg - 0.5);
-  let u = uv.x;
-  let v = uv.y;
-  let r = ((1.164000034 * y) + (params.vr * v));
-  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
-  let b = ((1.164000034 * y) + (params.ub * u));
-  return vec4<f32>(r, g, b, 1.0);
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = (params.gamutConversionMatrix * color);
+  color = gammaCorrection(color, params.gammaEncodeParams);
+  return vec4<f32>(color, 1.0);
 }
 
 @stage(fragment)
@@ -336,16 +408,16 @@
 }
 )";
 
-  DataMap data;
-  data.Add<MultiplanarExternalTexture::NewBindingPoints>(
-      MultiplanarExternalTexture::BindingsMap{{{0, 0}, {{0, 1}, {0, 2}}}});
-  auto got = Run<MultiplanarExternalTexture>(src, data);
-  EXPECT_EQ(expect, str(got));
+    DataMap data;
+    data.Add<MultiplanarExternalTexture::NewBindingPoints>(
+        MultiplanarExternalTexture::BindingsMap{{{0, 0}, {{0, 1}, {0, 2}}}});
+    auto got = Run<MultiplanarExternalTexture>(src, data);
+    EXPECT_EQ(expect, str(got));
 }
 
 // Tests that the transform works with a textureLoad call.
 TEST_F(MultiplanarExternalTextureTest, BasicTextureLoad_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(fragment)
 fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
   return textureLoad(ext_tex, vec2<i32>(1, 1));
@@ -354,31 +426,48 @@
 @group(0) @binding(0) var ext_tex : texture_external;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
+struct GammaTransferParams {
+  G : f32,
+  A : f32,
+  B : f32,
+  C : f32,
+  D : f32,
+  E : f32,
+  F : f32,
+  padding : u32,
+}
+
 struct ExternalTextureParams {
   numPlanes : u32,
-  vr : f32,
-  ug : f32,
-  vg : f32,
-  ub : f32,
+  yuvToRgbConversionMatrix : mat3x4<f32>,
+  gammaDecodeParams : GammaTransferParams,
+  gammaEncodeParams : GammaTransferParams,
+  gamutConversionMatrix : mat3x3<f32>,
 }
 
 @group(0) @binding(1) var ext_tex_plane_1 : texture_2d<f32>;
 
 @group(0) @binding(2) var<uniform> ext_tex_params : ExternalTextureParams;
 
+fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
+  let cond = (abs(v) < vec3<f32>(params.D));
+  let t = (sign(v) * ((params.C * abs(v)) + params.F));
+  let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
+  return select(f, t, cond);
+}
+
 fn textureLoadExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, coord : vec2<i32>, params : ExternalTextureParams) -> vec4<f32> {
+  var color : vec3<f32>;
   if ((params.numPlanes == 1u)) {
-    return textureLoad(plane0, coord, 0);
+    color = textureLoad(plane0, coord, 0i).rgb;
+  } else {
+    color = (vec4<f32>(textureLoad(plane0, coord, 0i).r, textureLoad(plane1, coord, 0i).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
-  let y = (textureLoad(plane0, coord, 0).r - 0.0625);
-  let uv = (textureLoad(plane1, coord, 0).rg - 0.5);
-  let u = uv.x;
-  let v = uv.y;
-  let r = ((1.164000034 * y) + (params.vr * v));
-  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
-  let b = ((1.164000034 * y) + (params.ub * u));
-  return vec4<f32>(r, g, b, 1.0);
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = (params.gamutConversionMatrix * color);
+  color = gammaCorrection(color, params.gammaEncodeParams);
+  return vec4<f32>(color, 1.0);
 }
 
 @stage(fragment)
@@ -389,17 +478,17 @@
 @group(0) @binding(0) var ext_tex : texture_2d<f32>;
 )";
 
-  DataMap data;
-  data.Add<MultiplanarExternalTexture::NewBindingPoints>(
-      MultiplanarExternalTexture::BindingsMap{{{0, 0}, {{0, 1}, {0, 2}}}});
-  auto got = Run<MultiplanarExternalTexture>(src, data);
-  EXPECT_EQ(expect, str(got));
+    DataMap data;
+    data.Add<MultiplanarExternalTexture::NewBindingPoints>(
+        MultiplanarExternalTexture::BindingsMap{{{0, 0}, {{0, 1}, {0, 2}}}});
+    auto got = Run<MultiplanarExternalTexture>(src, data);
+    EXPECT_EQ(expect, str(got));
 }
 
 // Tests that the transform works with both a textureSampleLevel and textureLoad
 // call.
 TEST_F(MultiplanarExternalTextureTest, TextureSampleAndTextureLoad) {
-  auto* src = R"(
+    auto* src = R"(
 @group(0) @binding(0) var s : sampler;
 @group(0) @binding(1) var ext_tex : texture_external;
 
@@ -409,13 +498,24 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
+struct GammaTransferParams {
+  G : f32,
+  A : f32,
+  B : f32,
+  C : f32,
+  D : f32,
+  E : f32,
+  F : f32,
+  padding : u32,
+}
+
 struct ExternalTextureParams {
   numPlanes : u32,
-  vr : f32,
-  ug : f32,
-  vg : f32,
-  ub : f32,
+  yuvToRgbConversionMatrix : mat3x4<f32>,
+  gammaDecodeParams : GammaTransferParams,
+  gammaEncodeParams : GammaTransferParams,
+  gamutConversionMatrix : mat3x3<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@@ -426,32 +526,37 @@
 
 @group(0) @binding(1) var ext_tex : texture_2d<f32>;
 
+fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
+  let cond = (abs(v) < vec3<f32>(params.D));
+  let t = (sign(v) * ((params.C * abs(v)) + params.F));
+  let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
+  return select(f, t, cond);
+}
+
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
+  var color : vec3<f32>;
   if ((params.numPlanes == 1u)) {
-    return textureSampleLevel(plane0, smp, coord, 0.0);
+    color = textureSampleLevel(plane0, smp, coord, 0.0).rgb;
+  } else {
+    color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
-  let y = (textureSampleLevel(plane0, smp, coord, 0.0).r - 0.0625);
-  let uv = (textureSampleLevel(plane1, smp, coord, 0.0).rg - 0.5);
-  let u = uv.x;
-  let v = uv.y;
-  let r = ((1.164000034 * y) + (params.vr * v));
-  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
-  let b = ((1.164000034 * y) + (params.ub * u));
-  return vec4<f32>(r, g, b, 1.0);
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = (params.gamutConversionMatrix * color);
+  color = gammaCorrection(color, params.gammaEncodeParams);
+  return vec4<f32>(color, 1.0);
 }
 
 fn textureLoadExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, coord : vec2<i32>, params : ExternalTextureParams) -> vec4<f32> {
+  var color : vec3<f32>;
   if ((params.numPlanes == 1u)) {
-    return textureLoad(plane0, coord, 0);
+    color = textureLoad(plane0, coord, 0i).rgb;
+  } else {
+    color = (vec4<f32>(textureLoad(plane0, coord, 0i).r, textureLoad(plane1, coord, 0i).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
-  let y = (textureLoad(plane0, coord, 0).r - 0.0625);
-  let uv = (textureLoad(plane1, coord, 0).rg - 0.5);
-  let u = uv.x;
-  let v = uv.y;
-  let r = ((1.164000034 * y) + (params.vr * v));
-  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
-  let b = ((1.164000034 * y) + (params.ub * u));
-  return vec4<f32>(r, g, b, 1.0);
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = (params.gamutConversionMatrix * color);
+  color = gammaCorrection(color, params.gammaEncodeParams);
+  return vec4<f32>(color, 1.0);
 }
 
 @stage(fragment)
@@ -460,17 +565,17 @@
 }
 )";
 
-  DataMap data;
-  data.Add<MultiplanarExternalTexture::NewBindingPoints>(
-      MultiplanarExternalTexture::BindingsMap{{{0, 1}, {{0, 2}, {0, 3}}}});
-  auto got = Run<MultiplanarExternalTexture>(src, data);
-  EXPECT_EQ(expect, str(got));
+    DataMap data;
+    data.Add<MultiplanarExternalTexture::NewBindingPoints>(
+        MultiplanarExternalTexture::BindingsMap{{{0, 1}, {{0, 2}, {0, 3}}}});
+    auto got = Run<MultiplanarExternalTexture>(src, data);
+    EXPECT_EQ(expect, str(got));
 }
 
 // Tests that the transform works with both a textureSampleLevel and textureLoad
 // call.
 TEST_F(MultiplanarExternalTextureTest, TextureSampleAndTextureLoad_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(fragment)
 fn main(@builtin(position) coord : vec4<f32>) -> @location(0) vec4<f32> {
   return textureSampleLevel(ext_tex, s, coord.xy) + textureLoad(ext_tex, vec2<i32>(1, 1));
@@ -480,45 +585,61 @@
 @group(0) @binding(1) var ext_tex : texture_external;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
+struct GammaTransferParams {
+  G : f32,
+  A : f32,
+  B : f32,
+  C : f32,
+  D : f32,
+  E : f32,
+  F : f32,
+  padding : u32,
+}
+
 struct ExternalTextureParams {
   numPlanes : u32,
-  vr : f32,
-  ug : f32,
-  vg : f32,
-  ub : f32,
+  yuvToRgbConversionMatrix : mat3x4<f32>,
+  gammaDecodeParams : GammaTransferParams,
+  gammaEncodeParams : GammaTransferParams,
+  gamutConversionMatrix : mat3x3<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
 
 @group(0) @binding(3) var<uniform> ext_tex_params : ExternalTextureParams;
 
+fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
+  let cond = (abs(v) < vec3<f32>(params.D));
+  let t = (sign(v) * ((params.C * abs(v)) + params.F));
+  let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
+  return select(f, t, cond);
+}
+
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
+  var color : vec3<f32>;
   if ((params.numPlanes == 1u)) {
-    return textureSampleLevel(plane0, smp, coord, 0.0);
+    color = textureSampleLevel(plane0, smp, coord, 0.0).rgb;
+  } else {
+    color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
-  let y = (textureSampleLevel(plane0, smp, coord, 0.0).r - 0.0625);
-  let uv = (textureSampleLevel(plane1, smp, coord, 0.0).rg - 0.5);
-  let u = uv.x;
-  let v = uv.y;
-  let r = ((1.164000034 * y) + (params.vr * v));
-  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
-  let b = ((1.164000034 * y) + (params.ub * u));
-  return vec4<f32>(r, g, b, 1.0);
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = (params.gamutConversionMatrix * color);
+  color = gammaCorrection(color, params.gammaEncodeParams);
+  return vec4<f32>(color, 1.0);
 }
 
 fn textureLoadExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, coord : vec2<i32>, params : ExternalTextureParams) -> vec4<f32> {
+  var color : vec3<f32>;
   if ((params.numPlanes == 1u)) {
-    return textureLoad(plane0, coord, 0);
+    color = textureLoad(plane0, coord, 0i).rgb;
+  } else {
+    color = (vec4<f32>(textureLoad(plane0, coord, 0i).r, textureLoad(plane1, coord, 0i).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
-  let y = (textureLoad(plane0, coord, 0).r - 0.0625);
-  let uv = (textureLoad(plane1, coord, 0).rg - 0.5);
-  let u = uv.x;
-  let v = uv.y;
-  let r = ((1.164000034 * y) + (params.vr * v));
-  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
-  let b = ((1.164000034 * y) + (params.ub * u));
-  return vec4<f32>(r, g, b, 1.0);
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = (params.gamutConversionMatrix * color);
+  color = gammaCorrection(color, params.gammaEncodeParams);
+  return vec4<f32>(color, 1.0);
 }
 
 @stage(fragment)
@@ -531,16 +652,16 @@
 @group(0) @binding(1) var ext_tex : texture_2d<f32>;
 )";
 
-  DataMap data;
-  data.Add<MultiplanarExternalTexture::NewBindingPoints>(
-      MultiplanarExternalTexture::BindingsMap{{{0, 1}, {{0, 2}, {0, 3}}}});
-  auto got = Run<MultiplanarExternalTexture>(src, data);
-  EXPECT_EQ(expect, str(got));
+    DataMap data;
+    data.Add<MultiplanarExternalTexture::NewBindingPoints>(
+        MultiplanarExternalTexture::BindingsMap{{{0, 1}, {{0, 2}, {0, 3}}}});
+    auto got = Run<MultiplanarExternalTexture>(src, data);
+    EXPECT_EQ(expect, str(got));
 }
 
 // Tests that the transform works with many instances of texture_external.
 TEST_F(MultiplanarExternalTextureTest, ManyTextureSampleLevel) {
-  auto* src = R"(
+    auto* src = R"(
 @group(0) @binding(0) var s : sampler;
 @group(0) @binding(1) var ext_tex : texture_external;
 @group(0) @binding(2) var ext_tex_1 : texture_external;
@@ -553,13 +674,24 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
+struct GammaTransferParams {
+  G : f32,
+  A : f32,
+  B : f32,
+  C : f32,
+  D : f32,
+  E : f32,
+  F : f32,
+  padding : u32,
+}
+
 struct ExternalTextureParams {
   numPlanes : u32,
-  vr : f32,
-  ug : f32,
-  vg : f32,
-  ub : f32,
+  yuvToRgbConversionMatrix : mat3x4<f32>,
+  gammaDecodeParams : GammaTransferParams,
+  gammaEncodeParams : GammaTransferParams,
+  gamutConversionMatrix : mat3x3<f32>,
 }
 
 @group(0) @binding(4) var ext_tex_plane_1 : texture_2d<f32>;
@@ -588,18 +720,24 @@
 
 @group(1) @binding(0) var ext_tex_3 : texture_2d<f32>;
 
+fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
+  let cond = (abs(v) < vec3<f32>(params.D));
+  let t = (sign(v) * ((params.C * abs(v)) + params.F));
+  let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
+  return select(f, t, cond);
+}
+
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
+  var color : vec3<f32>;
   if ((params.numPlanes == 1u)) {
-    return textureSampleLevel(plane0, smp, coord, 0.0);
+    color = textureSampleLevel(plane0, smp, coord, 0.0).rgb;
+  } else {
+    color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
-  let y = (textureSampleLevel(plane0, smp, coord, 0.0).r - 0.0625);
-  let uv = (textureSampleLevel(plane1, smp, coord, 0.0).rg - 0.5);
-  let u = uv.x;
-  let v = uv.y;
-  let r = ((1.164000034 * y) + (params.vr * v));
-  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
-  let b = ((1.164000034 * y) + (params.ub * u));
-  return vec4<f32>(r, g, b, 1.0);
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = (params.gamutConversionMatrix * color);
+  color = gammaCorrection(color, params.gammaEncodeParams);
+  return vec4<f32>(color, 1.0);
 }
 
 @stage(fragment)
@@ -608,22 +746,21 @@
 }
 )";
 
-  DataMap data;
-  data.Add<MultiplanarExternalTexture::NewBindingPoints>(
-      MultiplanarExternalTexture::BindingsMap{
-          {{0, 1}, {{0, 4}, {0, 5}}},
-          {{0, 2}, {{0, 6}, {0, 7}}},
-          {{0, 3}, {{0, 8}, {0, 9}}},
-          {{1, 0}, {{1, 1}, {1, 2}}},
-      });
-  auto got = Run<MultiplanarExternalTexture>(src, data);
-  EXPECT_EQ(expect, str(got));
+    DataMap data;
+    data.Add<MultiplanarExternalTexture::NewBindingPoints>(MultiplanarExternalTexture::BindingsMap{
+        {{0, 1}, {{0, 4}, {0, 5}}},
+        {{0, 2}, {{0, 6}, {0, 7}}},
+        {{0, 3}, {{0, 8}, {0, 9}}},
+        {{1, 0}, {{1, 1}, {1, 2}}},
+    });
+    auto got = Run<MultiplanarExternalTexture>(src, data);
+    EXPECT_EQ(expect, str(got));
 }
 
 // Tests that the texture_external passed as a function parameter produces the
 // correct output.
 TEST_F(MultiplanarExternalTextureTest, ExternalTexturePassedAsParam) {
-  auto* src = R"(
+    auto* src = R"(
 fn f(t : texture_external, s : sampler) {
   textureSampleLevel(t, s, vec2<f32>(1.0, 2.0));
 }
@@ -637,31 +774,48 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
+struct GammaTransferParams {
+  G : f32,
+  A : f32,
+  B : f32,
+  C : f32,
+  D : f32,
+  E : f32,
+  F : f32,
+  padding : u32,
+}
+
 struct ExternalTextureParams {
   numPlanes : u32,
-  vr : f32,
-  ug : f32,
-  vg : f32,
-  ub : f32,
+  yuvToRgbConversionMatrix : mat3x4<f32>,
+  gammaDecodeParams : GammaTransferParams,
+  gammaEncodeParams : GammaTransferParams,
+  gamutConversionMatrix : mat3x3<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
 
 @group(0) @binding(3) var<uniform> ext_tex_params : ExternalTextureParams;
 
+fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
+  let cond = (abs(v) < vec3<f32>(params.D));
+  let t = (sign(v) * ((params.C * abs(v)) + params.F));
+  let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
+  return select(f, t, cond);
+}
+
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
+  var color : vec3<f32>;
   if ((params.numPlanes == 1u)) {
-    return textureSampleLevel(plane0, smp, coord, 0.0);
+    color = textureSampleLevel(plane0, smp, coord, 0.0).rgb;
+  } else {
+    color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
-  let y = (textureSampleLevel(plane0, smp, coord, 0.0).r - 0.0625);
-  let uv = (textureSampleLevel(plane1, smp, coord, 0.0).rg - 0.5);
-  let u = uv.x;
-  let v = uv.y;
-  let r = ((1.164000034 * y) + (params.vr * v));
-  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
-  let b = ((1.164000034 * y) + (params.ub * u));
-  return vec4<f32>(r, g, b, 1.0);
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = (params.gamutConversionMatrix * color);
+  color = gammaCorrection(color, params.gammaEncodeParams);
+  return vec4<f32>(color, 1.0);
 }
 
 fn f(t : texture_2d<f32>, ext_tex_plane_1_1 : texture_2d<f32>, ext_tex_params_1 : ExternalTextureParams, s : sampler) {
@@ -677,20 +831,18 @@
   f(ext_tex, ext_tex_plane_1, ext_tex_params, smp);
 }
 )";
-  DataMap data;
-  data.Add<MultiplanarExternalTexture::NewBindingPoints>(
-      MultiplanarExternalTexture::BindingsMap{
-          {{0, 0}, {{0, 2}, {0, 3}}},
-      });
-  auto got = Run<MultiplanarExternalTexture>(src, data);
-  EXPECT_EQ(expect, str(got));
+    DataMap data;
+    data.Add<MultiplanarExternalTexture::NewBindingPoints>(MultiplanarExternalTexture::BindingsMap{
+        {{0, 0}, {{0, 2}, {0, 3}}},
+    });
+    auto got = Run<MultiplanarExternalTexture>(src, data);
+    EXPECT_EQ(expect, str(got));
 }
 
 // Tests that the texture_external passed as a function parameter produces the
 // correct output.
-TEST_F(MultiplanarExternalTextureTest,
-       ExternalTexturePassedAsParam_OutOfOrder) {
-  auto* src = R"(
+TEST_F(MultiplanarExternalTextureTest, ExternalTexturePassedAsParam_OutOfOrder) {
+    auto* src = R"(
 @stage(fragment)
 fn main() {
   f(ext_tex, smp);
@@ -704,13 +856,24 @@
 @group(0) @binding(1) var smp : sampler;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
+struct GammaTransferParams {
+  G : f32,
+  A : f32,
+  B : f32,
+  C : f32,
+  D : f32,
+  E : f32,
+  F : f32,
+  padding : u32,
+}
+
 struct ExternalTextureParams {
   numPlanes : u32,
-  vr : f32,
-  ug : f32,
-  vg : f32,
-  ub : f32,
+  yuvToRgbConversionMatrix : mat3x4<f32>,
+  gammaDecodeParams : GammaTransferParams,
+  gammaEncodeParams : GammaTransferParams,
+  gamutConversionMatrix : mat3x3<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@@ -722,18 +885,24 @@
   f(ext_tex, ext_tex_plane_1, ext_tex_params, smp);
 }
 
+fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
+  let cond = (abs(v) < vec3<f32>(params.D));
+  let t = (sign(v) * ((params.C * abs(v)) + params.F));
+  let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
+  return select(f, t, cond);
+}
+
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
+  var color : vec3<f32>;
   if ((params.numPlanes == 1u)) {
-    return textureSampleLevel(plane0, smp, coord, 0.0);
+    color = textureSampleLevel(plane0, smp, coord, 0.0).rgb;
+  } else {
+    color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
-  let y = (textureSampleLevel(plane0, smp, coord, 0.0).r - 0.0625);
-  let uv = (textureSampleLevel(plane1, smp, coord, 0.0).rg - 0.5);
-  let u = uv.x;
-  let v = uv.y;
-  let r = ((1.164000034 * y) + (params.vr * v));
-  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
-  let b = ((1.164000034 * y) + (params.ub * u));
-  return vec4<f32>(r, g, b, 1.0);
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = (params.gamutConversionMatrix * color);
+  color = gammaCorrection(color, params.gammaEncodeParams);
+  return vec4<f32>(color, 1.0);
 }
 
 fn f(t : texture_2d<f32>, ext_tex_plane_1_1 : texture_2d<f32>, ext_tex_params_1 : ExternalTextureParams, s : sampler) {
@@ -744,19 +913,18 @@
 
 @group(0) @binding(1) var smp : sampler;
 )";
-  DataMap data;
-  data.Add<MultiplanarExternalTexture::NewBindingPoints>(
-      MultiplanarExternalTexture::BindingsMap{
-          {{0, 0}, {{0, 2}, {0, 3}}},
-      });
-  auto got = Run<MultiplanarExternalTexture>(src, data);
-  EXPECT_EQ(expect, str(got));
+    DataMap data;
+    data.Add<MultiplanarExternalTexture::NewBindingPoints>(MultiplanarExternalTexture::BindingsMap{
+        {{0, 0}, {{0, 2}, {0, 3}}},
+    });
+    auto got = Run<MultiplanarExternalTexture>(src, data);
+    EXPECT_EQ(expect, str(got));
 }
 
 // Tests that the texture_external passed as a parameter not in the first
 // position produces the correct output.
 TEST_F(MultiplanarExternalTextureTest, ExternalTexturePassedAsSecondParam) {
-  auto* src = R"(
+    auto* src = R"(
 fn f(s : sampler, t : texture_external) {
   textureSampleLevel(t, s, vec2<f32>(1.0, 2.0));
 }
@@ -770,31 +938,48 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
+struct GammaTransferParams {
+  G : f32,
+  A : f32,
+  B : f32,
+  C : f32,
+  D : f32,
+  E : f32,
+  F : f32,
+  padding : u32,
+}
+
 struct ExternalTextureParams {
   numPlanes : u32,
-  vr : f32,
-  ug : f32,
-  vg : f32,
-  ub : f32,
+  yuvToRgbConversionMatrix : mat3x4<f32>,
+  gammaDecodeParams : GammaTransferParams,
+  gammaEncodeParams : GammaTransferParams,
+  gamutConversionMatrix : mat3x3<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
 
 @group(0) @binding(3) var<uniform> ext_tex_params : ExternalTextureParams;
 
+fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
+  let cond = (abs(v) < vec3<f32>(params.D));
+  let t = (sign(v) * ((params.C * abs(v)) + params.F));
+  let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
+  return select(f, t, cond);
+}
+
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
+  var color : vec3<f32>;
   if ((params.numPlanes == 1u)) {
-    return textureSampleLevel(plane0, smp, coord, 0.0);
+    color = textureSampleLevel(plane0, smp, coord, 0.0).rgb;
+  } else {
+    color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
-  let y = (textureSampleLevel(plane0, smp, coord, 0.0).r - 0.0625);
-  let uv = (textureSampleLevel(plane1, smp, coord, 0.0).rg - 0.5);
-  let u = uv.x;
-  let v = uv.y;
-  let r = ((1.164000034 * y) + (params.vr * v));
-  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
-  let b = ((1.164000034 * y) + (params.ub * u));
-  return vec4<f32>(r, g, b, 1.0);
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = (params.gamutConversionMatrix * color);
+  color = gammaCorrection(color, params.gammaEncodeParams);
+  return vec4<f32>(color, 1.0);
 }
 
 fn f(s : sampler, t : texture_2d<f32>, ext_tex_plane_1_1 : texture_2d<f32>, ext_tex_params_1 : ExternalTextureParams) {
@@ -810,19 +995,18 @@
   f(smp, ext_tex, ext_tex_plane_1, ext_tex_params);
 }
 )";
-  DataMap data;
-  data.Add<MultiplanarExternalTexture::NewBindingPoints>(
-      MultiplanarExternalTexture::BindingsMap{
-          {{0, 0}, {{0, 2}, {0, 3}}},
-      });
-  auto got = Run<MultiplanarExternalTexture>(src, data);
-  EXPECT_EQ(expect, str(got));
+    DataMap data;
+    data.Add<MultiplanarExternalTexture::NewBindingPoints>(MultiplanarExternalTexture::BindingsMap{
+        {{0, 0}, {{0, 2}, {0, 3}}},
+    });
+    auto got = Run<MultiplanarExternalTexture>(src, data);
+    EXPECT_EQ(expect, str(got));
 }
 
 // Tests that multiple texture_external params passed to a function produces the
 // correct output.
 TEST_F(MultiplanarExternalTextureTest, ExternalTexturePassedAsParamMultiple) {
-  auto* src = R"(
+    auto* src = R"(
 fn f(t : texture_external, s : sampler, t2 : texture_external) {
   textureSampleLevel(t, s, vec2<f32>(1.0, 2.0));
   textureSampleLevel(t2, s, vec2<f32>(1.0, 2.0));
@@ -838,13 +1022,24 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
+struct GammaTransferParams {
+  G : f32,
+  A : f32,
+  B : f32,
+  C : f32,
+  D : f32,
+  E : f32,
+  F : f32,
+  padding : u32,
+}
+
 struct ExternalTextureParams {
   numPlanes : u32,
-  vr : f32,
-  ug : f32,
-  vg : f32,
-  ub : f32,
+  yuvToRgbConversionMatrix : mat3x4<f32>,
+  gammaDecodeParams : GammaTransferParams,
+  gammaEncodeParams : GammaTransferParams,
+  gamutConversionMatrix : mat3x3<f32>,
 }
 
 @group(0) @binding(3) var ext_tex_plane_1 : texture_2d<f32>;
@@ -855,18 +1050,24 @@
 
 @group(0) @binding(6) var<uniform> ext_tex_params_1 : ExternalTextureParams;
 
+fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
+  let cond = (abs(v) < vec3<f32>(params.D));
+  let t = (sign(v) * ((params.C * abs(v)) + params.F));
+  let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
+  return select(f, t, cond);
+}
+
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
+  var color : vec3<f32>;
   if ((params.numPlanes == 1u)) {
-    return textureSampleLevel(plane0, smp, coord, 0.0);
+    color = textureSampleLevel(plane0, smp, coord, 0.0).rgb;
+  } else {
+    color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
-  let y = (textureSampleLevel(plane0, smp, coord, 0.0).r - 0.0625);
-  let uv = (textureSampleLevel(plane1, smp, coord, 0.0).rg - 0.5);
-  let u = uv.x;
-  let v = uv.y;
-  let r = ((1.164000034 * y) + (params.vr * v));
-  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
-  let b = ((1.164000034 * y) + (params.ub * u));
-  return vec4<f32>(r, g, b, 1.0);
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = (params.gamutConversionMatrix * color);
+  color = gammaCorrection(color, params.gammaEncodeParams);
+  return vec4<f32>(color, 1.0);
 }
 
 fn f(t : texture_2d<f32>, ext_tex_plane_1_2 : texture_2d<f32>, ext_tex_params_2 : ExternalTextureParams, s : sampler, t2 : texture_2d<f32>, ext_tex_plane_1_3 : texture_2d<f32>, ext_tex_params_3 : ExternalTextureParams) {
@@ -885,21 +1086,19 @@
   f(ext_tex, ext_tex_plane_1, ext_tex_params, smp, ext_tex2, ext_tex_plane_1_1, ext_tex_params_1);
 }
 )";
-  DataMap data;
-  data.Add<MultiplanarExternalTexture::NewBindingPoints>(
-      MultiplanarExternalTexture::BindingsMap{
-          {{0, 0}, {{0, 3}, {0, 4}}},
-          {{0, 2}, {{0, 5}, {0, 6}}},
-      });
-  auto got = Run<MultiplanarExternalTexture>(src, data);
-  EXPECT_EQ(expect, str(got));
+    DataMap data;
+    data.Add<MultiplanarExternalTexture::NewBindingPoints>(MultiplanarExternalTexture::BindingsMap{
+        {{0, 0}, {{0, 3}, {0, 4}}},
+        {{0, 2}, {{0, 5}, {0, 6}}},
+    });
+    auto got = Run<MultiplanarExternalTexture>(src, data);
+    EXPECT_EQ(expect, str(got));
 }
 
 // Tests that multiple texture_external params passed to a function produces the
 // correct output.
-TEST_F(MultiplanarExternalTextureTest,
-       ExternalTexturePassedAsParamMultiple_OutOfOrder) {
-  auto* src = R"(
+TEST_F(MultiplanarExternalTextureTest, ExternalTexturePassedAsParamMultiple_OutOfOrder) {
+    auto* src = R"(
 @stage(fragment)
 fn main() {
   f(ext_tex, smp, ext_tex2);
@@ -916,13 +1115,24 @@
 
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
+struct GammaTransferParams {
+  G : f32,
+  A : f32,
+  B : f32,
+  C : f32,
+  D : f32,
+  E : f32,
+  F : f32,
+  padding : u32,
+}
+
 struct ExternalTextureParams {
   numPlanes : u32,
-  vr : f32,
-  ug : f32,
-  vg : f32,
-  ub : f32,
+  yuvToRgbConversionMatrix : mat3x4<f32>,
+  gammaDecodeParams : GammaTransferParams,
+  gammaEncodeParams : GammaTransferParams,
+  gamutConversionMatrix : mat3x3<f32>,
 }
 
 @group(0) @binding(3) var ext_tex_plane_1 : texture_2d<f32>;
@@ -938,18 +1148,24 @@
   f(ext_tex, ext_tex_plane_1, ext_tex_params, smp, ext_tex2, ext_tex_plane_1_1, ext_tex_params_1);
 }
 
+fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
+  let cond = (abs(v) < vec3<f32>(params.D));
+  let t = (sign(v) * ((params.C * abs(v)) + params.F));
+  let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
+  return select(f, t, cond);
+}
+
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
+  var color : vec3<f32>;
   if ((params.numPlanes == 1u)) {
-    return textureSampleLevel(plane0, smp, coord, 0.0);
+    color = textureSampleLevel(plane0, smp, coord, 0.0).rgb;
+  } else {
+    color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
-  let y = (textureSampleLevel(plane0, smp, coord, 0.0).r - 0.0625);
-  let uv = (textureSampleLevel(plane1, smp, coord, 0.0).rg - 0.5);
-  let u = uv.x;
-  let v = uv.y;
-  let r = ((1.164000034 * y) + (params.vr * v));
-  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
-  let b = ((1.164000034 * y) + (params.ub * u));
-  return vec4<f32>(r, g, b, 1.0);
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = (params.gamutConversionMatrix * color);
+  color = gammaCorrection(color, params.gammaEncodeParams);
+  return vec4<f32>(color, 1.0);
 }
 
 fn f(t : texture_2d<f32>, ext_tex_plane_1_2 : texture_2d<f32>, ext_tex_params_2 : ExternalTextureParams, s : sampler, t2 : texture_2d<f32>, ext_tex_plane_1_3 : texture_2d<f32>, ext_tex_params_3 : ExternalTextureParams) {
@@ -963,20 +1179,19 @@
 
 @group(0) @binding(2) var ext_tex2 : texture_2d<f32>;
 )";
-  DataMap data;
-  data.Add<MultiplanarExternalTexture::NewBindingPoints>(
-      MultiplanarExternalTexture::BindingsMap{
-          {{0, 0}, {{0, 3}, {0, 4}}},
-          {{0, 2}, {{0, 5}, {0, 6}}},
-      });
-  auto got = Run<MultiplanarExternalTexture>(src, data);
-  EXPECT_EQ(expect, str(got));
+    DataMap data;
+    data.Add<MultiplanarExternalTexture::NewBindingPoints>(MultiplanarExternalTexture::BindingsMap{
+        {{0, 0}, {{0, 3}, {0, 4}}},
+        {{0, 2}, {{0, 5}, {0, 6}}},
+    });
+    auto got = Run<MultiplanarExternalTexture>(src, data);
+    EXPECT_EQ(expect, str(got));
 }
 
 // Tests that the texture_external passed to as a parameter to multiple
 // functions produces the correct output.
 TEST_F(MultiplanarExternalTextureTest, ExternalTexturePassedAsParamNested) {
-  auto* src = R"(
+    auto* src = R"(
 fn nested(t : texture_external, s : sampler) {
   textureSampleLevel(t, s, vec2<f32>(1.0, 2.0));
 }
@@ -994,31 +1209,48 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
+struct GammaTransferParams {
+  G : f32,
+  A : f32,
+  B : f32,
+  C : f32,
+  D : f32,
+  E : f32,
+  F : f32,
+  padding : u32,
+}
+
 struct ExternalTextureParams {
   numPlanes : u32,
-  vr : f32,
-  ug : f32,
-  vg : f32,
-  ub : f32,
+  yuvToRgbConversionMatrix : mat3x4<f32>,
+  gammaDecodeParams : GammaTransferParams,
+  gammaEncodeParams : GammaTransferParams,
+  gamutConversionMatrix : mat3x3<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
 
 @group(0) @binding(3) var<uniform> ext_tex_params : ExternalTextureParams;
 
+fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
+  let cond = (abs(v) < vec3<f32>(params.D));
+  let t = (sign(v) * ((params.C * abs(v)) + params.F));
+  let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
+  return select(f, t, cond);
+}
+
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
+  var color : vec3<f32>;
   if ((params.numPlanes == 1u)) {
-    return textureSampleLevel(plane0, smp, coord, 0.0);
+    color = textureSampleLevel(plane0, smp, coord, 0.0).rgb;
+  } else {
+    color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
-  let y = (textureSampleLevel(plane0, smp, coord, 0.0).r - 0.0625);
-  let uv = (textureSampleLevel(plane1, smp, coord, 0.0).rg - 0.5);
-  let u = uv.x;
-  let v = uv.y;
-  let r = ((1.164000034 * y) + (params.vr * v));
-  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
-  let b = ((1.164000034 * y) + (params.ub * u));
-  return vec4<f32>(r, g, b, 1.0);
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = (params.gamutConversionMatrix * color);
+  color = gammaCorrection(color, params.gammaEncodeParams);
+  return vec4<f32>(color, 1.0);
 }
 
 fn nested(t : texture_2d<f32>, ext_tex_plane_1_1 : texture_2d<f32>, ext_tex_params_1 : ExternalTextureParams, s : sampler) {
@@ -1038,20 +1270,18 @@
   f(ext_tex, ext_tex_plane_1, ext_tex_params, smp);
 }
 )";
-  DataMap data;
-  data.Add<MultiplanarExternalTexture::NewBindingPoints>(
-      MultiplanarExternalTexture::BindingsMap{
-          {{0, 0}, {{0, 2}, {0, 3}}},
-      });
-  auto got = Run<MultiplanarExternalTexture>(src, data);
-  EXPECT_EQ(expect, str(got));
+    DataMap data;
+    data.Add<MultiplanarExternalTexture::NewBindingPoints>(MultiplanarExternalTexture::BindingsMap{
+        {{0, 0}, {{0, 2}, {0, 3}}},
+    });
+    auto got = Run<MultiplanarExternalTexture>(src, data);
+    EXPECT_EQ(expect, str(got));
 }
 
 // Tests that the texture_external passed to as a parameter to multiple
 // functions produces the correct output.
-TEST_F(MultiplanarExternalTextureTest,
-       ExternalTexturePassedAsParamNested_OutOfOrder) {
-  auto* src = R"(
+TEST_F(MultiplanarExternalTextureTest, ExternalTexturePassedAsParamNested_OutOfOrder) {
+    auto* src = R"(
 fn nested(t : texture_external, s : sampler) {
   textureSampleLevel(t, s, vec2<f32>(1.0, 2.0));
 }
@@ -1069,31 +1299,48 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
+struct GammaTransferParams {
+  G : f32,
+  A : f32,
+  B : f32,
+  C : f32,
+  D : f32,
+  E : f32,
+  F : f32,
+  padding : u32,
+}
+
 struct ExternalTextureParams {
   numPlanes : u32,
-  vr : f32,
-  ug : f32,
-  vg : f32,
-  ub : f32,
+  yuvToRgbConversionMatrix : mat3x4<f32>,
+  gammaDecodeParams : GammaTransferParams,
+  gammaEncodeParams : GammaTransferParams,
+  gamutConversionMatrix : mat3x3<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
 
 @group(0) @binding(3) var<uniform> ext_tex_params : ExternalTextureParams;
 
+fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
+  let cond = (abs(v) < vec3<f32>(params.D));
+  let t = (sign(v) * ((params.C * abs(v)) + params.F));
+  let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
+  return select(f, t, cond);
+}
+
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
+  var color : vec3<f32>;
   if ((params.numPlanes == 1u)) {
-    return textureSampleLevel(plane0, smp, coord, 0.0);
+    color = textureSampleLevel(plane0, smp, coord, 0.0).rgb;
+  } else {
+    color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
-  let y = (textureSampleLevel(plane0, smp, coord, 0.0).r - 0.0625);
-  let uv = (textureSampleLevel(plane1, smp, coord, 0.0).rg - 0.5);
-  let u = uv.x;
-  let v = uv.y;
-  let r = ((1.164000034 * y) + (params.vr * v));
-  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
-  let b = ((1.164000034 * y) + (params.ub * u));
-  return vec4<f32>(r, g, b, 1.0);
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = (params.gamutConversionMatrix * color);
+  color = gammaCorrection(color, params.gammaEncodeParams);
+  return vec4<f32>(color, 1.0);
 }
 
 fn nested(t : texture_2d<f32>, ext_tex_plane_1_1 : texture_2d<f32>, ext_tex_params_1 : ExternalTextureParams, s : sampler) {
@@ -1113,32 +1360,41 @@
   f(ext_tex, ext_tex_plane_1, ext_tex_params, smp);
 }
 )";
-  DataMap data;
-  data.Add<MultiplanarExternalTexture::NewBindingPoints>(
-      MultiplanarExternalTexture::BindingsMap{
-          {{0, 0}, {{0, 2}, {0, 3}}},
-      });
-  auto got = Run<MultiplanarExternalTexture>(src, data);
-  EXPECT_EQ(expect, str(got));
+    DataMap data;
+    data.Add<MultiplanarExternalTexture::NewBindingPoints>(MultiplanarExternalTexture::BindingsMap{
+        {{0, 0}, {{0, 2}, {0, 3}}},
+    });
+    auto got = Run<MultiplanarExternalTexture>(src, data);
+    EXPECT_EQ(expect, str(got));
 }
 
 // Tests that the transform works with a function using an external texture,
 // even if there's no external texture declared at module scope.
-TEST_F(MultiplanarExternalTextureTest,
-       ExternalTexturePassedAsParamWithoutGlobalDecl) {
-  auto* src = R"(
+TEST_F(MultiplanarExternalTextureTest, ExternalTexturePassedAsParamWithoutGlobalDecl) {
+    auto* src = R"(
 fn f(ext_tex : texture_external) -> vec2<i32> {
   return textureDimensions(ext_tex);
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
+struct GammaTransferParams {
+  G : f32,
+  A : f32,
+  B : f32,
+  C : f32,
+  D : f32,
+  E : f32,
+  F : f32,
+  padding : u32,
+}
+
 struct ExternalTextureParams {
   numPlanes : u32,
-  vr : f32,
-  ug : f32,
-  vg : f32,
-  ub : f32,
+  yuvToRgbConversionMatrix : mat3x4<f32>,
+  gammaDecodeParams : GammaTransferParams,
+  gammaEncodeParams : GammaTransferParams,
+  gamutConversionMatrix : mat3x3<f32>,
 }
 
 fn f(ext_tex : texture_2d<f32>, ext_tex_plane_1 : texture_2d<f32>, ext_tex_params : ExternalTextureParams) -> vec2<i32> {
@@ -1146,16 +1402,16 @@
 }
 )";
 
-  DataMap data;
-  data.Add<MultiplanarExternalTexture::NewBindingPoints>(
-      MultiplanarExternalTexture::BindingsMap{{{0, 0}, {{0, 1}, {0, 2}}}});
-  auto got = Run<MultiplanarExternalTexture>(src, data);
-  EXPECT_EQ(expect, str(got));
+    DataMap data;
+    data.Add<MultiplanarExternalTexture::NewBindingPoints>(
+        MultiplanarExternalTexture::BindingsMap{{{0, 0}, {{0, 1}, {0, 2}}}});
+    auto got = Run<MultiplanarExternalTexture>(src, data);
+    EXPECT_EQ(expect, str(got));
 }
 
 // Tests that the the transform handles aliases to external textures
 TEST_F(MultiplanarExternalTextureTest, ExternalTextureAlias) {
-  auto* src = R"(
+    auto* src = R"(
 type ET = texture_external;
 
 fn f(t : ET, s : sampler) {
@@ -1171,13 +1427,24 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
+struct GammaTransferParams {
+  G : f32,
+  A : f32,
+  B : f32,
+  C : f32,
+  D : f32,
+  E : f32,
+  F : f32,
+  padding : u32,
+}
+
 struct ExternalTextureParams {
   numPlanes : u32,
-  vr : f32,
-  ug : f32,
-  vg : f32,
-  ub : f32,
+  yuvToRgbConversionMatrix : mat3x4<f32>,
+  gammaDecodeParams : GammaTransferParams,
+  gammaEncodeParams : GammaTransferParams,
+  gamutConversionMatrix : mat3x3<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@@ -1186,18 +1453,24 @@
 
 type ET = texture_external;
 
+fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
+  let cond = (abs(v) < vec3<f32>(params.D));
+  let t = (sign(v) * ((params.C * abs(v)) + params.F));
+  let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
+  return select(f, t, cond);
+}
+
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
+  var color : vec3<f32>;
   if ((params.numPlanes == 1u)) {
-    return textureSampleLevel(plane0, smp, coord, 0.0);
+    color = textureSampleLevel(plane0, smp, coord, 0.0).rgb;
+  } else {
+    color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
-  let y = (textureSampleLevel(plane0, smp, coord, 0.0).r - 0.0625);
-  let uv = (textureSampleLevel(plane1, smp, coord, 0.0).rg - 0.5);
-  let u = uv.x;
-  let v = uv.y;
-  let r = ((1.164000034 * y) + (params.vr * v));
-  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
-  let b = ((1.164000034 * y) + (params.ub * u));
-  return vec4<f32>(r, g, b, 1.0);
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = (params.gamutConversionMatrix * color);
+  color = gammaCorrection(color, params.gammaEncodeParams);
+  return vec4<f32>(color, 1.0);
 }
 
 fn f(t : texture_2d<f32>, ext_tex_plane_1_1 : texture_2d<f32>, ext_tex_params_1 : ExternalTextureParams, s : sampler) {
@@ -1213,18 +1486,17 @@
   f(ext_tex, ext_tex_plane_1, ext_tex_params, smp);
 }
 )";
-  DataMap data;
-  data.Add<MultiplanarExternalTexture::NewBindingPoints>(
-      MultiplanarExternalTexture::BindingsMap{
-          {{0, 0}, {{0, 2}, {0, 3}}},
-      });
-  auto got = Run<MultiplanarExternalTexture>(src, data);
-  EXPECT_EQ(expect, str(got));
+    DataMap data;
+    data.Add<MultiplanarExternalTexture::NewBindingPoints>(MultiplanarExternalTexture::BindingsMap{
+        {{0, 0}, {{0, 2}, {0, 3}}},
+    });
+    auto got = Run<MultiplanarExternalTexture>(src, data);
+    EXPECT_EQ(expect, str(got));
 }
 
 // Tests that the the transform handles aliases to external textures
 TEST_F(MultiplanarExternalTextureTest, ExternalTextureAlias_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(fragment)
 fn main() {
   f(ext_tex, smp);
@@ -1240,13 +1512,24 @@
 type ET = texture_external;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
+struct GammaTransferParams {
+  G : f32,
+  A : f32,
+  B : f32,
+  C : f32,
+  D : f32,
+  E : f32,
+  F : f32,
+  padding : u32,
+}
+
 struct ExternalTextureParams {
   numPlanes : u32,
-  vr : f32,
-  ug : f32,
-  vg : f32,
-  ub : f32,
+  yuvToRgbConversionMatrix : mat3x4<f32>,
+  gammaDecodeParams : GammaTransferParams,
+  gammaEncodeParams : GammaTransferParams,
+  gamutConversionMatrix : mat3x3<f32>,
 }
 
 @group(0) @binding(2) var ext_tex_plane_1 : texture_2d<f32>;
@@ -1258,18 +1541,24 @@
   f(ext_tex, ext_tex_plane_1, ext_tex_params, smp);
 }
 
+fn gammaCorrection(v : vec3<f32>, params : GammaTransferParams) -> vec3<f32> {
+  let cond = (abs(v) < vec3<f32>(params.D));
+  let t = (sign(v) * ((params.C * abs(v)) + params.F));
+  let f = (sign(v) * (pow(((params.A * abs(v)) + params.B), vec3<f32>(params.G)) + params.E));
+  return select(f, t, cond);
+}
+
 fn textureSampleExternal(plane0 : texture_2d<f32>, plane1 : texture_2d<f32>, smp : sampler, coord : vec2<f32>, params : ExternalTextureParams) -> vec4<f32> {
+  var color : vec3<f32>;
   if ((params.numPlanes == 1u)) {
-    return textureSampleLevel(plane0, smp, coord, 0.0);
+    color = textureSampleLevel(plane0, smp, coord, 0.0).rgb;
+  } else {
+    color = (vec4<f32>(textureSampleLevel(plane0, smp, coord, 0.0).r, textureSampleLevel(plane1, smp, coord, 0.0).rg, 1.0) * params.yuvToRgbConversionMatrix);
   }
-  let y = (textureSampleLevel(plane0, smp, coord, 0.0).r - 0.0625);
-  let uv = (textureSampleLevel(plane1, smp, coord, 0.0).rg - 0.5);
-  let u = uv.x;
-  let v = uv.y;
-  let r = ((1.164000034 * y) + (params.vr * v));
-  let g = (((1.164000034 * y) - (params.ug * u)) - (params.vg * v));
-  let b = ((1.164000034 * y) + (params.ub * u));
-  return vec4<f32>(r, g, b, 1.0);
+  color = gammaCorrection(color, params.gammaDecodeParams);
+  color = (params.gamutConversionMatrix * color);
+  color = gammaCorrection(color, params.gammaEncodeParams);
+  return vec4<f32>(color, 1.0);
 }
 
 fn f(t : texture_2d<f32>, ext_tex_plane_1_1 : texture_2d<f32>, ext_tex_params_1 : ExternalTextureParams, s : sampler) {
@@ -1282,13 +1571,12 @@
 
 type ET = texture_external;
 )";
-  DataMap data;
-  data.Add<MultiplanarExternalTexture::NewBindingPoints>(
-      MultiplanarExternalTexture::BindingsMap{
-          {{0, 0}, {{0, 2}, {0, 3}}},
-      });
-  auto got = Run<MultiplanarExternalTexture>(src, data);
-  EXPECT_EQ(expect, str(got));
+    DataMap data;
+    data.Add<MultiplanarExternalTexture::NewBindingPoints>(MultiplanarExternalTexture::BindingsMap{
+        {{0, 0}, {{0, 2}, {0, 3}}},
+    });
+    auto got = Run<MultiplanarExternalTexture>(src, data);
+    EXPECT_EQ(expect, str(got));
 }
 
 }  // namespace
diff --git a/src/tint/transform/num_workgroups_from_uniform.cc b/src/tint/transform/num_workgroups_from_uniform.cc
index 72f7fb8..17814df 100644
--- a/src/tint/transform/num_workgroups_from_uniform.cc
+++ b/src/tint/transform/num_workgroups_from_uniform.cc
@@ -32,136 +32,126 @@
 /// Accessor describes the identifiers used in a member accessor that is being
 /// used to retrieve the num_workgroups builtin from a parameter.
 struct Accessor {
-  Symbol param;
-  Symbol member;
+    Symbol param;
+    Symbol member;
 
-  /// Equality operator
-  bool operator==(const Accessor& other) const {
-    return param == other.param && member == other.member;
-  }
-  /// Hash function
-  struct Hasher {
-    size_t operator()(const Accessor& a) const {
-      return utils::Hash(a.param, a.member);
+    /// Equality operator
+    bool operator==(const Accessor& other) const {
+        return param == other.param && member == other.member;
     }
-  };
+    /// Hash function
+    struct Hasher {
+        size_t operator()(const Accessor& a) const { return utils::Hash(a.param, a.member); }
+    };
 };
 }  // namespace
 
 NumWorkgroupsFromUniform::NumWorkgroupsFromUniform() = default;
 NumWorkgroupsFromUniform::~NumWorkgroupsFromUniform() = default;
 
-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) {
-        return true;
-      }
+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) {
+                return true;
+            }
+        }
     }
-  }
-  return false;
+    return false;
 }
 
-void NumWorkgroupsFromUniform::Run(CloneContext& ctx,
-                                   const DataMap& inputs,
-                                   DataMap&) const {
-  auto* cfg = inputs.Get<Config>();
-  if (cfg == nullptr) {
-    ctx.dst->Diagnostics().add_error(
-        diag::System::Transform,
-        "missing transform data for " + std::string(TypeInfo().name));
-    return;
-  }
-
-  const char* kNumWorkgroupsMemberName = "num_workgroups";
-
-  // Find all entry point parameters that declare the num_workgroups builtin.
-  std::unordered_set<Accessor, Accessor::Hasher> to_replace;
-  for (auto* func : ctx.src->AST().Functions()) {
-    // num_workgroups is only valid for compute stages.
-    if (func->PipelineStage() != ast::PipelineStage::kCompute) {
-      continue;
+void NumWorkgroupsFromUniform::Run(CloneContext& ctx, const DataMap& inputs, DataMap&) const {
+    auto* cfg = inputs.Get<Config>();
+    if (cfg == nullptr) {
+        ctx.dst->Diagnostics().add_error(
+            diag::System::Transform, "missing transform data for " + std::string(TypeInfo().name));
+        return;
     }
 
-    for (auto* param : ctx.src->Sem().Get(func)->Parameters()) {
-      // Because the CanonicalizeEntryPointIO transform has been run, builtins
-      // will only appear as struct members.
-      auto* str = param->Type()->As<sem::Struct>();
-      if (!str) {
-        continue;
-      }
+    const char* kNumWorkgroupsMemberName = "num_workgroups";
 
-      for (auto* member : str->Members()) {
-        auto* builtin = ast::GetAttribute<ast::BuiltinAttribute>(
-            member->Declaration()->attributes);
-        if (!builtin || builtin->builtin != ast::Builtin::kNumWorkgroups) {
-          continue;
+    // Find all entry point parameters that declare the num_workgroups builtin.
+    std::unordered_set<Accessor, Accessor::Hasher> to_replace;
+    for (auto* func : ctx.src->AST().Functions()) {
+        // num_workgroups is only valid for compute stages.
+        if (func->PipelineStage() != ast::PipelineStage::kCompute) {
+            continue;
         }
 
-        // Capture the symbols that would be used to access this member, which
-        // we will replace later. We currently have no way to get from the
-        // parameter directly to the member accessor expressions that use it.
-        to_replace.insert(
-            {param->Declaration()->symbol, member->Declaration()->symbol});
+        for (auto* param : ctx.src->Sem().Get(func)->Parameters()) {
+            // Because the CanonicalizeEntryPointIO transform has been run, builtins
+            // will only appear as struct members.
+            auto* str = param->Type()->As<sem::Struct>();
+            if (!str) {
+                continue;
+            }
 
-        // Remove the struct member.
-        // The CanonicalizeEntryPointIO transform will have generated this
-        // struct uniquely for this particular entry point, so we know that
-        // there will be no other uses of this struct in the module and that we
-        // can safely modify it here.
-        ctx.Remove(str->Declaration()->members, member->Declaration());
+            for (auto* member : str->Members()) {
+                auto* builtin =
+                    ast::GetAttribute<ast::BuiltinAttribute>(member->Declaration()->attributes);
+                if (!builtin || builtin->builtin != ast::Builtin::kNumWorkgroups) {
+                    continue;
+                }
 
-        // If this is the only member, remove the struct and parameter too.
-        if (str->Members().size() == 1) {
-          ctx.Remove(func->params, param->Declaration());
-          ctx.Remove(ctx.src->AST().GlobalDeclarations(), str->Declaration());
+                // Capture the symbols that would be used to access this member, which
+                // we will replace later. We currently have no way to get from the
+                // parameter directly to the member accessor expressions that use it.
+                to_replace.insert({param->Declaration()->symbol, member->Declaration()->symbol});
+
+                // Remove the struct member.
+                // The CanonicalizeEntryPointIO transform will have generated this
+                // struct uniquely for this particular entry point, so we know that
+                // there will be no other uses of this struct in the module and that we
+                // can safely modify it here.
+                ctx.Remove(str->Declaration()->members, member->Declaration());
+
+                // If this is the only member, remove the struct and parameter too.
+                if (str->Members().size() == 1) {
+                    ctx.Remove(func->params, param->Declaration());
+                    ctx.Remove(ctx.src->AST().GlobalDeclarations(), str->Declaration());
+                }
+            }
         }
-      }
-    }
-  }
-
-  // Get (or create, on first call) the uniform buffer that will receive the
-  // number of workgroups.
-  const ast::Variable* num_workgroups_ubo = nullptr;
-  auto get_ubo = [&]() {
-    if (!num_workgroups_ubo) {
-      auto* num_workgroups_struct = ctx.dst->Structure(
-          ctx.dst->Sym(),
-          {ctx.dst->Member(kNumWorkgroupsMemberName,
-                           ctx.dst->ty.vec3(ctx.dst->ty.u32()))});
-      num_workgroups_ubo = ctx.dst->Global(
-          ctx.dst->Sym(), ctx.dst->ty.Of(num_workgroups_struct),
-          ast::StorageClass::kUniform,
-          ast::AttributeList{ctx.dst->GroupAndBinding(
-              cfg->ubo_binding.group, cfg->ubo_binding.binding)});
-    }
-    return num_workgroups_ubo;
-  };
-
-  // Now replace all the places where the builtins are accessed with the value
-  // loaded from the uniform buffer.
-  for (auto* node : ctx.src->ASTNodes().Objects()) {
-    auto* accessor = node->As<ast::MemberAccessorExpression>();
-    if (!accessor) {
-      continue;
-    }
-    auto* ident = accessor->structure->As<ast::IdentifierExpression>();
-    if (!ident) {
-      continue;
     }
 
-    if (to_replace.count({ident->symbol, accessor->member->symbol})) {
-      ctx.Replace(accessor, ctx.dst->MemberAccessor(get_ubo()->symbol,
-                                                    kNumWorkgroupsMemberName));
-    }
-  }
+    // Get (or create, on first call) the uniform buffer that will receive the
+    // number of workgroups.
+    const ast::Variable* num_workgroups_ubo = nullptr;
+    auto get_ubo = [&]() {
+        if (!num_workgroups_ubo) {
+            auto* num_workgroups_struct = ctx.dst->Structure(
+                ctx.dst->Sym(),
+                {ctx.dst->Member(kNumWorkgroupsMemberName, ctx.dst->ty.vec3(ctx.dst->ty.u32()))});
+            num_workgroups_ubo = ctx.dst->Global(
+                ctx.dst->Sym(), ctx.dst->ty.Of(num_workgroups_struct), ast::StorageClass::kUniform,
+                ast::AttributeList{
+                    ctx.dst->GroupAndBinding(cfg->ubo_binding.group, cfg->ubo_binding.binding)});
+        }
+        return num_workgroups_ubo;
+    };
 
-  ctx.Clone();
+    // Now replace all the places where the builtins are accessed with the value
+    // loaded from the uniform buffer.
+    for (auto* node : ctx.src->ASTNodes().Objects()) {
+        auto* accessor = node->As<ast::MemberAccessorExpression>();
+        if (!accessor) {
+            continue;
+        }
+        auto* ident = accessor->structure->As<ast::IdentifierExpression>();
+        if (!ident) {
+            continue;
+        }
+
+        if (to_replace.count({ident->symbol, accessor->member->symbol})) {
+            ctx.Replace(accessor,
+                        ctx.dst->MemberAccessor(get_ubo()->symbol, kNumWorkgroupsMemberName));
+        }
+    }
+
+    ctx.Clone();
 }
 
-NumWorkgroupsFromUniform::Config::Config(sem::BindingPoint ubo_bp)
-    : ubo_binding(ubo_bp) {}
+NumWorkgroupsFromUniform::Config::Config(sem::BindingPoint ubo_bp) : ubo_binding(ubo_bp) {}
 NumWorkgroupsFromUniform::Config::Config(const Config&) = default;
 NumWorkgroupsFromUniform::Config::~Config() = default;
 
diff --git a/src/tint/transform/num_workgroups_from_uniform.h b/src/tint/transform/num_workgroups_from_uniform.h
index e4cf20e..93c4f15 100644
--- a/src/tint/transform/num_workgroups_from_uniform.h
+++ b/src/tint/transform/num_workgroups_from_uniform.h
@@ -42,46 +42,42 @@
 ///
 /// @note Depends on the following transforms to have been run first:
 /// * CanonicalizeEntryPointIO
-class NumWorkgroupsFromUniform
-    : public Castable<NumWorkgroupsFromUniform, Transform> {
- public:
-  /// Constructor
-  NumWorkgroupsFromUniform();
-  /// Destructor
-  ~NumWorkgroupsFromUniform() override;
-
-  /// Configuration options for the NumWorkgroupsFromUniform transform.
-  struct Config : public Castable<Data, transform::Data> {
+class NumWorkgroupsFromUniform : public Castable<NumWorkgroupsFromUniform, Transform> {
+  public:
     /// Constructor
-    /// @param ubo_bp the binding point to use for the generated uniform buffer.
-    explicit Config(sem::BindingPoint ubo_bp);
-
-    /// Copy constructor
-    Config(const Config&);
-
+    NumWorkgroupsFromUniform();
     /// Destructor
-    ~Config() override;
+    ~NumWorkgroupsFromUniform() override;
 
-    /// The binding point to use for the generated uniform buffer.
-    sem::BindingPoint ubo_binding;
-  };
+    /// Configuration options for the NumWorkgroupsFromUniform transform.
+    struct Config : public Castable<Data, transform::Data> {
+        /// Constructor
+        /// @param ubo_bp the binding point to use for the generated uniform buffer.
+        explicit Config(sem::BindingPoint ubo_bp);
 
-  /// @param program the program to inspect
-  /// @param data optional extra transform-specific input data
-  /// @returns true if this transform should be run for the given program
-  bool ShouldRun(const Program* program,
-                 const DataMap& data = {}) const override;
+        /// Copy constructor
+        Config(const Config&);
 
- protected:
-  /// Runs the transform using the CloneContext built for transforming a
-  /// program. Run() is responsible for calling Clone() on the CloneContext.
-  /// @param ctx the CloneContext primed with the input program and
-  /// ProgramBuilder
-  /// @param inputs optional extra transform-specific input data
-  /// @param outputs optional extra transform-specific output data
-  void Run(CloneContext& ctx,
-           const DataMap& inputs,
-           DataMap& outputs) const override;
+        /// Destructor
+        ~Config() override;
+
+        /// The binding point to use for the generated uniform buffer.
+        sem::BindingPoint ubo_binding;
+    };
+
+    /// @param program the program to inspect
+    /// @param data optional extra transform-specific input data
+    /// @returns true if this transform should be run for the given program
+    bool ShouldRun(const Program* program, const DataMap& data = {}) const override;
+
+  protected:
+    /// Runs the transform using the CloneContext built for transforming a
+    /// program. Run() is responsible for calling Clone() on the CloneContext.
+    /// @param ctx the CloneContext primed with the input program and
+    /// ProgramBuilder
+    /// @param inputs optional extra transform-specific input data
+    /// @param outputs optional extra transform-specific output data
+    void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const override;
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/num_workgroups_from_uniform_test.cc b/src/tint/transform/num_workgroups_from_uniform_test.cc
index 734d11b..de6c665 100644
--- a/src/tint/transform/num_workgroups_from_uniform_test.cc
+++ b/src/tint/transform/num_workgroups_from_uniform_test.cc
@@ -26,43 +26,41 @@
 using NumWorkgroupsFromUniformTest = TransformTest;
 
 TEST_F(NumWorkgroupsFromUniformTest, ShouldRunEmptyModule) {
-  auto* src = R"()";
+    auto* src = R"()";
 
-  EXPECT_FALSE(ShouldRun<NumWorkgroupsFromUniform>(src));
+    EXPECT_FALSE(ShouldRun<NumWorkgroupsFromUniform>(src));
 }
 
 TEST_F(NumWorkgroupsFromUniformTest, ShouldRunHasNumWorkgroups) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn main(@builtin(num_workgroups) num_wgs : vec3<u32>) {
 }
 )";
 
-  EXPECT_TRUE(ShouldRun<NumWorkgroupsFromUniform>(src));
+    EXPECT_TRUE(ShouldRun<NumWorkgroupsFromUniform>(src));
 }
 
 TEST_F(NumWorkgroupsFromUniformTest, Error_MissingTransformData) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn main(@builtin(num_workgroups) num_wgs : vec3<u32>) {
 }
 )";
 
-  auto* expect =
-      "error: missing transform data for "
-      "tint::transform::NumWorkgroupsFromUniform";
+    auto* expect =
+        "error: missing transform data for "
+        "tint::transform::NumWorkgroupsFromUniform";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO, NumWorkgroupsFromUniform>(
-      src, data);
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO, NumWorkgroupsFromUniform>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(NumWorkgroupsFromUniformTest, Basic) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn main(@builtin(num_workgroups) num_wgs : vec3<u32>) {
   let groups_x = num_wgs.x;
@@ -71,7 +69,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol_2 {
   num_workgroups : vec3<u32>,
 }
@@ -90,17 +88,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
-  data.Add<NumWorkgroupsFromUniform::Config>(sem::BindingPoint{0, 30u});
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO, NumWorkgroupsFromUniform>(
-      src, data);
-  EXPECT_EQ(expect, str(got));
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
+    data.Add<NumWorkgroupsFromUniform::Config>(sem::BindingPoint{0, 30u});
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO, NumWorkgroupsFromUniform>(src, data);
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(NumWorkgroupsFromUniformTest, StructOnlyMember) {
-  auto* src = R"(
+    auto* src = R"(
 struct Builtins {
   @builtin(num_workgroups) num_wgs : vec3<u32>,
 };
@@ -113,7 +109,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol_2 {
   num_workgroups : vec3<u32>,
 }
@@ -136,17 +132,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
-  data.Add<NumWorkgroupsFromUniform::Config>(sem::BindingPoint{0, 30u});
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO, NumWorkgroupsFromUniform>(
-      src, data);
-  EXPECT_EQ(expect, str(got));
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
+    data.Add<NumWorkgroupsFromUniform::Config>(sem::BindingPoint{0, 30u});
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO, NumWorkgroupsFromUniform>(src, data);
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(NumWorkgroupsFromUniformTest, StructOnlyMember_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn main(in : Builtins) {
   let groups_x = in.num_wgs.x;
@@ -159,7 +153,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol_2 {
   num_workgroups : vec3<u32>,
 }
@@ -182,17 +176,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
-  data.Add<NumWorkgroupsFromUniform::Config>(sem::BindingPoint{0, 30u});
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO, NumWorkgroupsFromUniform>(
-      src, data);
-  EXPECT_EQ(expect, str(got));
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
+    data.Add<NumWorkgroupsFromUniform::Config>(sem::BindingPoint{0, 30u});
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO, NumWorkgroupsFromUniform>(src, data);
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(NumWorkgroupsFromUniformTest, StructMultipleMembers) {
-  auto* src = R"(
+    auto* src = R"(
 struct Builtins {
   @builtin(global_invocation_id) gid : vec3<u32>,
   @builtin(num_workgroups) num_wgs : vec3<u32>,
@@ -207,7 +199,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol_2 {
   num_workgroups : vec3<u32>,
 }
@@ -239,17 +231,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
-  data.Add<NumWorkgroupsFromUniform::Config>(sem::BindingPoint{0, 30u});
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO, NumWorkgroupsFromUniform>(
-      src, data);
-  EXPECT_EQ(expect, str(got));
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
+    data.Add<NumWorkgroupsFromUniform::Config>(sem::BindingPoint{0, 30u});
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO, NumWorkgroupsFromUniform>(src, data);
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(NumWorkgroupsFromUniformTest, StructMultipleMembers_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn main(in : Builtins) {
   let groups_x = in.num_wgs.x;
@@ -265,7 +255,7 @@
 
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol_2 {
   num_workgroups : vec3<u32>,
 }
@@ -297,17 +287,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
-  data.Add<NumWorkgroupsFromUniform::Config>(sem::BindingPoint{0, 30u});
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO, NumWorkgroupsFromUniform>(
-      src, data);
-  EXPECT_EQ(expect, str(got));
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
+    data.Add<NumWorkgroupsFromUniform::Config>(sem::BindingPoint{0, 30u});
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO, NumWorkgroupsFromUniform>(src, data);
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(NumWorkgroupsFromUniformTest, MultipleEntryPoints) {
-  auto* src = R"(
+    auto* src = R"(
 struct Builtins1 {
   @builtin(num_workgroups) num_wgs : vec3<u32>,
 };
@@ -340,7 +328,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_symbol_6 {
   num_workgroups : vec3<u32>,
 }
@@ -398,17 +386,15 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
-  data.Add<NumWorkgroupsFromUniform::Config>(sem::BindingPoint{0, 30u});
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO, NumWorkgroupsFromUniform>(
-      src, data);
-  EXPECT_EQ(expect, str(got));
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
+    data.Add<NumWorkgroupsFromUniform::Config>(sem::BindingPoint{0, 30u});
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO, NumWorkgroupsFromUniform>(src, data);
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(NumWorkgroupsFromUniformTest, NoUsages) {
-  auto* src = R"(
+    auto* src = R"(
 struct Builtins {
   @builtin(global_invocation_id) gid : vec3<u32>,
   @builtin(workgroup_id) wgid : vec3<u32>,
@@ -419,7 +405,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct Builtins {
   gid : vec3<u32>,
   wgid : vec3<u32>,
@@ -441,13 +427,11 @@
 }
 )";
 
-  DataMap data;
-  data.Add<CanonicalizeEntryPointIO::Config>(
-      CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
-  data.Add<NumWorkgroupsFromUniform::Config>(sem::BindingPoint{0, 30u});
-  auto got = Run<Unshadow, CanonicalizeEntryPointIO, NumWorkgroupsFromUniform>(
-      src, data);
-  EXPECT_EQ(expect, str(got));
+    DataMap data;
+    data.Add<CanonicalizeEntryPointIO::Config>(CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
+    data.Add<NumWorkgroupsFromUniform::Config>(sem::BindingPoint{0, 30u});
+    auto got = Run<Unshadow, CanonicalizeEntryPointIO, NumWorkgroupsFromUniform>(src, data);
+    EXPECT_EQ(expect, str(got));
 }
 
 }  // namespace
diff --git a/src/tint/transform/promote_initializers_to_const_var.cc b/src/tint/transform/promote_initializers_to_const_var.cc
index a60dd6b..81b5603 100644
--- a/src/tint/transform/promote_initializers_to_const_var.cc
+++ b/src/tint/transform/promote_initializers_to_const_var.cc
@@ -27,57 +27,55 @@
 
 PromoteInitializersToConstVar::~PromoteInitializersToConstVar() = default;
 
-void PromoteInitializersToConstVar::Run(CloneContext& ctx,
-                                        const DataMap&,
-                                        DataMap&) const {
-  HoistToDeclBefore hoist_to_decl_before(ctx);
+void PromoteInitializersToConstVar::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
+    HoistToDeclBefore hoist_to_decl_before(ctx);
 
-  // Hoists array and structure initializers to a constant variable, declared
-  // just before the statement of usage.
-  auto type_ctor_to_let = [&](const ast::CallExpression* expr) {
-    auto* ctor = ctx.src->Sem().Get(expr);
-    if (!ctor->Target()->Is<sem::TypeConstructor>()) {
-      return true;
-    }
-    auto* sem_stmt = ctor->Stmt();
-    if (!sem_stmt) {
-      // Expression is outside of a statement. This usually means the
-      // expression is part of a global (module-scope) constant declaration.
-      // These must be constexpr, and so cannot contain the type of
-      // expressions that must be sanitized.
-      return true;
+    // Hoists array and structure initializers to a constant variable, declared
+    // just before the statement of usage.
+    auto type_ctor_to_let = [&](const ast::CallExpression* expr) {
+        auto* ctor = ctx.src->Sem().Get(expr);
+        if (!ctor->Target()->Is<sem::TypeConstructor>()) {
+            return true;
+        }
+        auto* sem_stmt = ctor->Stmt();
+        if (!sem_stmt) {
+            // Expression is outside of a statement. This usually means the
+            // expression is part of a global (module-scope) constant declaration.
+            // These must be constexpr, and so cannot contain the type of
+            // expressions that must be sanitized.
+            return true;
+        }
+
+        auto* stmt = sem_stmt->Declaration();
+
+        if (auto* src_var_decl = stmt->As<ast::VariableDeclStatement>()) {
+            if (src_var_decl->variable->constructor == expr) {
+                // This statement is just a variable declaration with the
+                // initializer as the constructor value. This is what we're
+                // attempting to transform to, and so ignore.
+                return true;
+            }
+        }
+
+        auto* src_ty = ctor->Type();
+        if (!src_ty->IsAnyOf<sem::Array, sem::Struct>()) {
+            // We only care about array and struct initializers
+            return true;
+        }
+
+        return hoist_to_decl_before.Add(ctor, expr, true);
+    };
+
+    for (auto* node : ctx.src->ASTNodes().Objects()) {
+        if (auto* call_expr = node->As<ast::CallExpression>()) {
+            if (!type_ctor_to_let(call_expr)) {
+                return;
+            }
+        }
     }
 
-    auto* stmt = sem_stmt->Declaration();
-
-    if (auto* src_var_decl = stmt->As<ast::VariableDeclStatement>()) {
-      if (src_var_decl->variable->constructor == expr) {
-        // This statement is just a variable declaration with the
-        // initializer as the constructor value. This is what we're
-        // attempting to transform to, and so ignore.
-        return true;
-      }
-    }
-
-    auto* src_ty = ctor->Type();
-    if (!src_ty->IsAnyOf<sem::Array, sem::Struct>()) {
-      // We only care about array and struct initializers
-      return true;
-    }
-
-    return hoist_to_decl_before.Add(ctor, expr, true);
-  };
-
-  for (auto* node : ctx.src->ASTNodes().Objects()) {
-    if (auto* call_expr = node->As<ast::CallExpression>()) {
-      if (!type_ctor_to_let(call_expr)) {
-        return;
-      }
-    }
-  }
-
-  hoist_to_decl_before.Apply();
-  ctx.Clone();
+    hoist_to_decl_before.Apply();
+    ctx.Clone();
 }
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/promote_initializers_to_const_var.h b/src/tint/transform/promote_initializers_to_const_var.h
index 586e27d..67a32c4 100644
--- a/src/tint/transform/promote_initializers_to_const_var.h
+++ b/src/tint/transform/promote_initializers_to_const_var.h
@@ -22,25 +22,22 @@
 /// A transform that hoists the array and structure initializers to a constant
 /// variable, declared just before the statement of usage.
 /// @see crbug.com/tint/406
-class PromoteInitializersToConstVar
-    : public Castable<PromoteInitializersToConstVar, Transform> {
- public:
-  /// Constructor
-  PromoteInitializersToConstVar();
+class PromoteInitializersToConstVar : public Castable<PromoteInitializersToConstVar, Transform> {
+  public:
+    /// Constructor
+    PromoteInitializersToConstVar();
 
-  /// Destructor
-  ~PromoteInitializersToConstVar() override;
+    /// Destructor
+    ~PromoteInitializersToConstVar() override;
 
- protected:
-  /// Runs the transform using the CloneContext built for transforming a
-  /// program. Run() is responsible for calling Clone() on the CloneContext.
-  /// @param ctx the CloneContext primed with the input program and
-  /// ProgramBuilder
-  /// @param inputs optional extra transform-specific input data
-  /// @param outputs optional extra transform-specific output data
-  void Run(CloneContext& ctx,
-           const DataMap& inputs,
-           DataMap& outputs) const override;
+  protected:
+    /// Runs the transform using the CloneContext built for transforming a
+    /// program. Run() is responsible for calling Clone() on the CloneContext.
+    /// @param ctx the CloneContext primed with the input program and
+    /// ProgramBuilder
+    /// @param inputs optional extra transform-specific input data
+    /// @param outputs optional extra transform-specific output data
+    void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const override;
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/promote_initializers_to_const_var_test.cc b/src/tint/transform/promote_initializers_to_const_var_test.cc
index 87b9edc..f322478 100644
--- a/src/tint/transform/promote_initializers_to_const_var_test.cc
+++ b/src/tint/transform/promote_initializers_to_const_var_test.cc
@@ -22,16 +22,16 @@
 using PromoteInitializersToConstVarTest = TransformTest;
 
 TEST_F(PromoteInitializersToConstVarTest, EmptyModule) {
-  auto* src = "";
-  auto* expect = "";
+    auto* src = "";
+    auto* expect = "";
 
-  auto got = Run<PromoteInitializersToConstVar>(src);
+    auto got = Run<PromoteInitializersToConstVar>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteInitializersToConstVarTest, BasicArray) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var f0 = 1.0;
   var f1 = 2.0;
@@ -41,7 +41,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var f0 = 1.0;
   var f1 = 2.0;
@@ -52,14 +52,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteInitializersToConstVar>(src);
+    DataMap data;
+    auto got = Run<PromoteInitializersToConstVar>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteInitializersToConstVarTest, BasicStruct) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   a : i32,
   b : f32,
@@ -71,7 +71,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   a : i32,
   b : f32,
@@ -84,14 +84,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteInitializersToConstVar>(src);
+    DataMap data;
+    auto got = Run<PromoteInitializersToConstVar>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteInitializersToConstVarTest, BasicStruct_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var x = S(1, 2.0, vec3<f32>()).b;
 }
@@ -103,7 +103,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   let tint_symbol = S(1, 2.0, vec3<f32>());
   var x = tint_symbol.b;
@@ -116,14 +116,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteInitializersToConstVar>(src);
+    DataMap data;
+    auto got = Run<PromoteInitializersToConstVar>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteInitializersToConstVarTest, ArrayInForLoopInit) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var insert_after = 1;
   for(var i = array<f32, 4u>(0.0, 1.0, 2.0, 3.0)[2]; ; ) {
@@ -132,7 +132,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var insert_after = 1;
   let tint_symbol = array<f32, 4u>(0.0, 1.0, 2.0, 3.0);
@@ -142,14 +142,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteInitializersToConstVar>(src);
+    DataMap data;
+    auto got = Run<PromoteInitializersToConstVar>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteInitializersToConstVarTest, StructInForLoopInit) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   a : i32,
   b : f32,
@@ -164,7 +164,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   a : i32,
   b : f32,
@@ -180,14 +180,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteInitializersToConstVar>(src);
+    DataMap data;
+    auto got = Run<PromoteInitializersToConstVar>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteInitializersToConstVarTest, StructInForLoopInit_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var insert_after = 1;
   for(var x = S(1, 2.0, vec3<f32>()).b; ; ) {
@@ -202,7 +202,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var insert_after = 1;
   let tint_symbol = S(1, 2.0, vec3<f32>());
@@ -218,14 +218,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteInitializersToConstVar>(src);
+    DataMap data;
+    auto got = Run<PromoteInitializersToConstVar>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteInitializersToConstVarTest, ArrayInForLoopCond) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var f = 1.0;
   for(; f == array<f32, 1u>(f)[0]; f = f + 1.0) {
@@ -234,7 +234,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var f = 1.0;
   loop {
@@ -253,14 +253,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteInitializersToConstVar>(src);
+    DataMap data;
+    auto got = Run<PromoteInitializersToConstVar>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteInitializersToConstVarTest, ArrayInForLoopCont) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var f = 0.0;
   for(; f < 10.0; f = f + array<f32, 1u>(1.0)[0]) {
@@ -269,7 +269,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var f = 0.0;
   loop {
@@ -288,14 +288,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteInitializersToConstVar>(src);
+    DataMap data;
+    auto got = Run<PromoteInitializersToConstVar>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteInitializersToConstVarTest, ArrayInForLoopInitCondCont) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   for(var f = array<f32, 1u>(0.0)[0];
       f < array<f32, 1u>(1.0)[0];
@@ -305,7 +305,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   let tint_symbol = array<f32, 1u>(0.0);
   {
@@ -328,14 +328,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteInitializersToConstVar>(src);
+    DataMap data;
+    auto got = Run<PromoteInitializersToConstVar>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteInitializersToConstVarTest, ArrayInElseIf) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var f = 1.0;
   if (true) {
@@ -346,7 +346,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var f = 1.0;
   if (true) {
@@ -360,14 +360,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteInitializersToConstVar>(src);
+    DataMap data;
+    auto got = Run<PromoteInitializersToConstVar>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteInitializersToConstVarTest, ArrayInElseIfChain) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var f = 1.0;
   if (true) {
@@ -386,7 +386,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var f = 1.0;
   if (true) {
@@ -411,20 +411,20 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteInitializersToConstVar>(src);
+    DataMap data;
+    auto got = Run<PromoteInitializersToConstVar>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteInitializersToConstVarTest, ArrayInArrayArray) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var i = array<array<f32, 2u>, 2u>(array<f32, 2u>(1.0, 2.0), array<f32, 2u>(3.0, 4.0))[0][1];
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   let tint_symbol = array<f32, 2u>(1.0, 2.0);
   let tint_symbol_1 = array<f32, 2u>(3.0, 4.0);
@@ -433,14 +433,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteInitializersToConstVar>(src);
+    DataMap data;
+    auto got = Run<PromoteInitializersToConstVar>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteInitializersToConstVarTest, StructNested) {
-  auto* src = R"(
+    auto* src = R"(
 struct S1 {
   a : i32,
 };
@@ -460,7 +460,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S1 {
   a : i32,
 }
@@ -483,14 +483,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteInitializersToConstVar>(src);
+    DataMap data;
+    auto got = Run<PromoteInitializersToConstVar>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteInitializersToConstVarTest, Mixed) {
-  auto* src = R"(
+    auto* src = R"(
 struct S1 {
   a : i32,
 };
@@ -504,7 +504,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S1 {
   a : i32,
 }
@@ -523,14 +523,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteInitializersToConstVar>(src);
+    DataMap data;
+    auto got = Run<PromoteInitializersToConstVar>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteInitializersToConstVarTest, Mixed_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var x = S2(array<S1, 3u>(S1(1), S1(2), S1(3))).a[1].a;
 }
@@ -544,7 +544,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   let tint_symbol = S1(1);
   let tint_symbol_1 = S1(2);
@@ -563,14 +563,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteInitializersToConstVar>(src);
+    DataMap data;
+    auto got = Run<PromoteInitializersToConstVar>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteInitializersToConstVarTest, NoChangeOnVarDecl) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   a : i32,
   b : f32,
@@ -587,16 +587,16 @@
 let module_str : S = S(1, 2.0, 3);
 )";
 
-  auto* expect = src;
+    auto* expect = src;
 
-  DataMap data;
-  auto got = Run<PromoteInitializersToConstVar>(src);
+    DataMap data;
+    auto got = Run<PromoteInitializersToConstVar>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteInitializersToConstVarTest, NoChangeOnVarDecl_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var local_arr = array<f32, 4u>(0.0, 1.0, 2.0, 3.0);
   var local_str = S(1, 2.0, 3);
@@ -613,12 +613,12 @@
 let module_arr : array<f32, 4u> = array<f32, 4u>(0.0, 1.0, 2.0, 3.0);
 )";
 
-  auto* expect = src;
+    auto* expect = src;
 
-  DataMap data;
-  auto got = Run<PromoteInitializersToConstVar>(src);
+    DataMap data;
+    auto got = Run<PromoteInitializersToConstVar>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 }  // namespace
diff --git a/src/tint/transform/promote_side_effects_to_decl.cc b/src/tint/transform/promote_side_effects_to_decl.cc
index 9fd19db..6f1cc4c 100644
--- a/src/tint/transform/promote_side_effects_to_decl.cc
+++ b/src/tint/transform/promote_side_effects_to_decl.cc
@@ -39,62 +39,58 @@
 
 // Base state class for common members
 class StateBase {
- protected:
-  CloneContext& ctx;
-  ProgramBuilder& b;
-  const sem::Info& sem;
+  protected:
+    CloneContext& ctx;
+    ProgramBuilder& b;
+    const sem::Info& sem;
 
-  explicit StateBase(CloneContext& ctx_in)
-      : ctx(ctx_in), b(*ctx_in.dst), sem(ctx_in.src->Sem()) {}
+    explicit StateBase(CloneContext& ctx_in)
+        : ctx(ctx_in), b(*ctx_in.dst), sem(ctx_in.src->Sem()) {}
 };
 
 // This first transform converts side-effecting for-loops to loops and else-ifs
 // to else {if}s so that the next transform, DecomposeSideEffects, can insert
 // hoisted expressions above their current location.
-struct SimplifySideEffectStatements
-    : Castable<PromoteSideEffectsToDecl, Transform> {
-  class State;
-  void Run(CloneContext& ctx, const DataMap& inputs, DataMap&) const override;
+struct SimplifySideEffectStatements : Castable<PromoteSideEffectsToDecl, Transform> {
+    class State;
+    void Run(CloneContext& ctx, const DataMap& inputs, DataMap&) const override;
 };
 
 class SimplifySideEffectStatements::State : public StateBase {
-  HoistToDeclBefore hoist_to_decl_before;
+    HoistToDeclBefore hoist_to_decl_before;
 
- public:
-  explicit State(CloneContext& ctx_in)
-      : StateBase(ctx_in), hoist_to_decl_before(ctx_in) {}
+  public:
+    explicit State(CloneContext& ctx_in) : StateBase(ctx_in), hoist_to_decl_before(ctx_in) {}
 
-  void Run() {
-    for (auto* node : ctx.src->ASTNodes().Objects()) {
-      if (auto* expr = node->As<ast::Expression>()) {
-        auto* sem_expr = sem.Get(expr);
-        if (!sem_expr || !sem_expr->HasSideEffects()) {
-          continue;
+    void Run() {
+        for (auto* node : ctx.src->ASTNodes().Objects()) {
+            if (auto* expr = node->As<ast::Expression>()) {
+                auto* sem_expr = sem.Get(expr);
+                if (!sem_expr || !sem_expr->HasSideEffects()) {
+                    continue;
+                }
+
+                hoist_to_decl_before.Prepare(sem_expr);
+            }
         }
 
-        hoist_to_decl_before.Prepare(sem_expr);
-      }
+        hoist_to_decl_before.Apply();
+        ctx.Clone();
     }
-
-    hoist_to_decl_before.Apply();
-    ctx.Clone();
-  }
 };
 
-void SimplifySideEffectStatements::Run(CloneContext& ctx,
-                                       const DataMap&,
-                                       DataMap&) const {
-  State state(ctx);
-  state.Run();
+void SimplifySideEffectStatements::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
+    State state(ctx);
+    state.Run();
 }
 
 // Decomposes side-effecting expressions to ensure order of evaluation. This
 // handles both breaking down logical binary expressions for short-circuit
 // evaluation, as well as hoisting expressions to ensure order of evaluation.
 struct DecomposeSideEffects : Castable<PromoteSideEffectsToDecl, Transform> {
-  class CollectHoistsState;
-  class DecomposeState;
-  void Run(CloneContext& ctx, const DataMap& inputs, DataMap&) const override;
+    class CollectHoistsState;
+    class DecomposeState;
+    void Run(CloneContext& ctx, const DataMap& inputs, DataMap&) const override;
 };
 
 // CollectHoistsState traverses the AST top-down, identifying which expressions
@@ -103,604 +99,567 @@
 // expressions.
 using ToHoistSet = std::unordered_set<const ast::Expression*>;
 class DecomposeSideEffects::CollectHoistsState : public StateBase {
-  // Expressions to hoist because they either cause or receive side-effects.
-  ToHoistSet to_hoist;
+    // Expressions to hoist because they either cause or receive side-effects.
+    ToHoistSet to_hoist;
 
-  // Used to mark expressions as not or no longer having side-effects.
-  std::unordered_set<const ast::Expression*> no_side_effects;
+    // Used to mark expressions as not or no longer having side-effects.
+    std::unordered_set<const ast::Expression*> no_side_effects;
 
-  // Returns true if `expr` has side-effects. Unlike invoking
-  // sem::Expression::HasSideEffects(), this function takes into account whether
-  // `expr` has been hoisted, returning false in that case. Furthermore, it
-  // returns the correct result on parent expression nodes by traversing the
-  // expression tree, memoizing the results to ensure O(1) amortized lookup.
-  bool HasSideEffects(const ast::Expression* expr) {
-    if (no_side_effects.count(expr)) {
-      return false;
-    }
-
-    return Switch(
-        expr,
-        [&](const ast::CallExpression* e) -> bool {
-          return sem.Get(e)->HasSideEffects();
-        },
-        [&](const ast::BinaryExpression* e) {
-          if (HasSideEffects(e->lhs) || HasSideEffects(e->rhs)) {
-            return true;
-          }
-          no_side_effects.insert(e);
-          return false;
-        },
-        [&](const ast::IndexAccessorExpression* e) {
-          if (HasSideEffects(e->object) || HasSideEffects(e->index)) {
-            return true;
-          }
-          no_side_effects.insert(e);
-          return false;
-        },
-        [&](const ast::MemberAccessorExpression* e) {
-          if (HasSideEffects(e->structure) || HasSideEffects(e->member)) {
-            return true;
-          }
-          no_side_effects.insert(e);
-          return false;
-        },
-        [&](const ast::BitcastExpression* e) {  //
-          if (HasSideEffects(e->expr)) {
-            return true;
-          }
-          no_side_effects.insert(e);
-          return false;
-        },
-
-        [&](const ast::UnaryOpExpression* e) {  //
-          if (HasSideEffects(e->expr)) {
-            return true;
-          }
-          no_side_effects.insert(e);
-          return false;
-        },
-        [&](const ast::IdentifierExpression* e) {
-          no_side_effects.insert(e);
-          return false;
-        },
-        [&](const ast::LiteralExpression* e) {
-          no_side_effects.insert(e);
-          return false;
-        },
-        [&](const ast::PhonyExpression* e) {
-          no_side_effects.insert(e);
-          return false;
-        },
-        [&](Default) {
-          TINT_ICE(Transform, b.Diagnostics()) << "Unhandled expression type";
-          return false;
-        });
-  }
-
-  // Adds `e` to `to_hoist` for hoisting to a let later on.
-  void Hoist(const ast::Expression* e) {
-    no_side_effects.insert(e);
-    to_hoist.emplace(e);
-  }
-
-  // Hoists any expressions in `maybe_hoist` and clears it
-  void Flush(ast::ExpressionList& maybe_hoist) {
-    for (auto* m : maybe_hoist) {
-      Hoist(m);
-    }
-    maybe_hoist.clear();
-  }
-
-  // Recursive function that processes expressions for side-effects. It
-  // traverses the expression tree child before parent, left-to-right. Each call
-  // returns whether the input expression should maybe be hoisted, allowing the
-  // parent node to decide whether to hoist or not. Generally:
-  // * When 'true' is returned, the expression is added to the maybe_hoist list.
-  // * When a side-effecting expression is met, we flush the expressions in the
-  // maybe_hoist list, as they are potentially receivers of the side-effects.
-  // * For index and member accessor expressions, special care is taken to not
-  // over-hoist the lhs expressions, as these may be be chained to refer to a
-  // single memory location.
-  bool ProcessExpression(const ast::Expression* expr,
-                         ast::ExpressionList& maybe_hoist) {
-    auto process = [&](const ast::Expression* e) -> bool {
-      return ProcessExpression(e, maybe_hoist);
-    };
-
-    auto default_process = [&](const ast::Expression* e) {
-      auto maybe = process(e);
-      if (maybe) {
-        maybe_hoist.emplace_back(e);
-      }
-      if (HasSideEffects(e)) {
-        Flush(maybe_hoist);
-      }
-      return false;
-    };
-
-    auto binary_process = [&](auto* lhs, auto* rhs) {
-      // If neither side causes side-effects, but at least one receives them,
-      // let parent node hoist. This avoids over-hoisting side-effect receivers
-      // of compound binary expressions (e.g. for "((a && b) && c) && f()", we
-      // don't want to hoist each of "a", "b", and "c" separately, but want to
-      // hoist "((a && b) && c)".
-      if (!HasSideEffects(lhs) && !HasSideEffects(rhs)) {
-        auto lhs_maybe = process(lhs);
-        auto rhs_maybe = process(rhs);
-        if (lhs_maybe || rhs_maybe) {
-          return true;
+    // Returns true if `expr` has side-effects. Unlike invoking
+    // sem::Expression::HasSideEffects(), this function takes into account whether
+    // `expr` has been hoisted, returning false in that case. Furthermore, it
+    // returns the correct result on parent expression nodes by traversing the
+    // expression tree, memoizing the results to ensure O(1) amortized lookup.
+    bool HasSideEffects(const ast::Expression* expr) {
+        if (no_side_effects.count(expr)) {
+            return false;
         }
-        return false;
-      }
 
-      default_process(lhs);
-      default_process(rhs);
-      return false;
-    };
-
-    auto accessor_process = [&](auto* lhs, auto* rhs) {
-      auto maybe = process(lhs);
-      // If lhs is a variable, let parent node hoist otherwise flush it right
-      // away. This is to avoid over-hoisting the lhs of accessor chains (e.g.
-      // for "v[a][b][c] + g()" we want to hoist all of "v[a][b][c]", not "t1 =
-      // v[a]", then "t2 = t1[b]" then "t3 = t2[c]").
-      if (maybe && HasSideEffects(lhs)) {
-        maybe_hoist.emplace_back(lhs);
-        Flush(maybe_hoist);
-        maybe = false;
-      }
-      default_process(rhs);
-      return maybe;
-    };
-
-    return Switch(
-        expr,
-        [&](const ast::CallExpression* e) -> bool {
-          // We eagerly flush any variables in maybe_hoist for the current
-          // call expression. Then we scope maybe_hoist to the processing of
-          // the call args. This ensures that given: g(c, a(0), d) we hoist
-          // 'c' because of 'a(0)', but not 'd' because there's no need, since
-          // the call to g() will be hoisted if necessary.
-          if (HasSideEffects(e)) {
-            Flush(maybe_hoist);
-          }
-
-          TINT_SCOPED_ASSIGNMENT(maybe_hoist, {});
-          for (auto* a : e->args) {
-            default_process(a);
-          }
-
-          // Always hoist this call, even if it has no side-effects to ensure
-          // left-to-right order of evaluation.
-          // E.g. for "no_side_effects() + side_effects()", we want to hoist
-          // no_side_effects() first.
-          return true;
-        },
-        [&](const ast::IdentifierExpression* e) {
-          if (auto* sem_e = sem.Get(e)) {
-            if (auto* var_user = sem_e->As<sem::VariableUser>()) {
-              // Don't hoist constants.
-              if (var_user->ConstantValue().IsValid()) {
+        return Switch(
+            expr,
+            [&](const ast::CallExpression* e) -> bool { return sem.Get(e)->HasSideEffects(); },
+            [&](const ast::BinaryExpression* e) {
+                if (HasSideEffects(e->lhs) || HasSideEffects(e->rhs)) {
+                    return true;
+                }
+                no_side_effects.insert(e);
                 return false;
-              }
-              // Don't hoist read-only variables as they cannot receive
-              // side-effects.
-              if (var_user->Variable()->Access() == ast::Access::kRead) {
+            },
+            [&](const ast::IndexAccessorExpression* e) {
+                if (HasSideEffects(e->object) || HasSideEffects(e->index)) {
+                    return true;
+                }
+                no_side_effects.insert(e);
                 return false;
-              }
-              return true;
+            },
+            [&](const ast::MemberAccessorExpression* e) {
+                if (HasSideEffects(e->structure) || HasSideEffects(e->member)) {
+                    return true;
+                }
+                no_side_effects.insert(e);
+                return false;
+            },
+            [&](const ast::BitcastExpression* e) {  //
+                if (HasSideEffects(e->expr)) {
+                    return true;
+                }
+                no_side_effects.insert(e);
+                return false;
+            },
+
+            [&](const ast::UnaryOpExpression* e) {  //
+                if (HasSideEffects(e->expr)) {
+                    return true;
+                }
+                no_side_effects.insert(e);
+                return false;
+            },
+            [&](const ast::IdentifierExpression* e) {
+                no_side_effects.insert(e);
+                return false;
+            },
+            [&](const ast::LiteralExpression* e) {
+                no_side_effects.insert(e);
+                return false;
+            },
+            [&](const ast::PhonyExpression* e) {
+                no_side_effects.insert(e);
+                return false;
+            },
+            [&](Default) {
+                TINT_ICE(Transform, b.Diagnostics()) << "Unhandled expression type";
+                return false;
+            });
+    }
+
+    // Adds `e` to `to_hoist` for hoisting to a let later on.
+    void Hoist(const ast::Expression* e) {
+        no_side_effects.insert(e);
+        to_hoist.emplace(e);
+    }
+
+    // Hoists any expressions in `maybe_hoist` and clears it
+    void Flush(ast::ExpressionList& maybe_hoist) {
+        for (auto* m : maybe_hoist) {
+            Hoist(m);
+        }
+        maybe_hoist.clear();
+    }
+
+    // Recursive function that processes expressions for side-effects. It
+    // traverses the expression tree child before parent, left-to-right. Each call
+    // returns whether the input expression should maybe be hoisted, allowing the
+    // parent node to decide whether to hoist or not. Generally:
+    // * When 'true' is returned, the expression is added to the maybe_hoist list.
+    // * When a side-effecting expression is met, we flush the expressions in the
+    // maybe_hoist list, as they are potentially receivers of the side-effects.
+    // * For index and member accessor expressions, special care is taken to not
+    // over-hoist the lhs expressions, as these may be be chained to refer to a
+    // single memory location.
+    bool ProcessExpression(const ast::Expression* expr, ast::ExpressionList& maybe_hoist) {
+        auto process = [&](const ast::Expression* e) -> bool {
+            return ProcessExpression(e, maybe_hoist);
+        };
+
+        auto default_process = [&](const ast::Expression* e) {
+            auto maybe = process(e);
+            if (maybe) {
+                maybe_hoist.emplace_back(e);
             }
-          }
-          return false;
-        },
-        [&](const ast::BinaryExpression* e) {
-          if (e->IsLogical() && HasSideEffects(e)) {
-            // Don't hoist children of logical binary expressions with
-            // side-effects. These will be handled by DecomposeState.
-            process(e->lhs);
-            process(e->rhs);
+            if (HasSideEffects(e)) {
+                Flush(maybe_hoist);
+            }
             return false;
-          }
-          return binary_process(e->lhs, e->rhs);
-        },
-        [&](const ast::BitcastExpression* e) {  //
-          return process(e->expr);
-        },
-        [&](const ast::UnaryOpExpression* e) {  //
-          auto r = process(e->expr);
-          // Don't hoist address-of expressions.
-          // E.g. for "g(&b, a(0))", we hoist "a(0)" only.
-          if (e->op == ast::UnaryOp::kAddressOf) {
+        };
+
+        auto binary_process = [&](auto* lhs, auto* rhs) {
+            // If neither side causes side-effects, but at least one receives them,
+            // let parent node hoist. This avoids over-hoisting side-effect receivers
+            // of compound binary expressions (e.g. for "((a && b) && c) && f()", we
+            // don't want to hoist each of "a", "b", and "c" separately, but want to
+            // hoist "((a && b) && c)".
+            if (!HasSideEffects(lhs) && !HasSideEffects(rhs)) {
+                auto lhs_maybe = process(lhs);
+                auto rhs_maybe = process(rhs);
+                if (lhs_maybe || rhs_maybe) {
+                    return true;
+                }
+                return false;
+            }
+
+            default_process(lhs);
+            default_process(rhs);
             return false;
-          }
-          return r;
-        },
-        [&](const ast::IndexAccessorExpression* e) {
-          return accessor_process(e->object, e->index);
-        },
-        [&](const ast::MemberAccessorExpression* e) {
-          return accessor_process(e->structure, e->member);
-        },
-        [&](const ast::LiteralExpression*) {
-          // Leaf
-          return false;
-        },
-        [&](const ast::PhonyExpression*) {
-          // Leaf
-          return false;
-        },
-        [&](Default) {
-          TINT_ICE(Transform, b.Diagnostics()) << "Unhandled expression type";
-          return false;
-        });
-  }
+        };
 
-  // Starts the recursive processing of a statement's expression(s) to hoist
-  // side-effects to lets.
-  void ProcessStatement(const ast::Expression* expr) {
-    if (!expr) {
-      return;
+        auto accessor_process = [&](auto* lhs, auto* rhs) {
+            auto maybe = process(lhs);
+            // If lhs is a variable, let parent node hoist otherwise flush it right
+            // away. This is to avoid over-hoisting the lhs of accessor chains (e.g.
+            // for "v[a][b][c] + g()" we want to hoist all of "v[a][b][c]", not "t1 =
+            // v[a]", then "t2 = t1[b]" then "t3 = t2[c]").
+            if (maybe && HasSideEffects(lhs)) {
+                maybe_hoist.emplace_back(lhs);
+                Flush(maybe_hoist);
+                maybe = false;
+            }
+            default_process(rhs);
+            return maybe;
+        };
+
+        return Switch(
+            expr,
+            [&](const ast::CallExpression* e) -> bool {
+                // We eagerly flush any variables in maybe_hoist for the current
+                // call expression. Then we scope maybe_hoist to the processing of
+                // the call args. This ensures that given: g(c, a(0), d) we hoist
+                // 'c' because of 'a(0)', but not 'd' because there's no need, since
+                // the call to g() will be hoisted if necessary.
+                if (HasSideEffects(e)) {
+                    Flush(maybe_hoist);
+                }
+
+                TINT_SCOPED_ASSIGNMENT(maybe_hoist, {});
+                for (auto* a : e->args) {
+                    default_process(a);
+                }
+
+                // Always hoist this call, even if it has no side-effects to ensure
+                // left-to-right order of evaluation.
+                // E.g. for "no_side_effects() + side_effects()", we want to hoist
+                // no_side_effects() first.
+                return true;
+            },
+            [&](const ast::IdentifierExpression* e) {
+                if (auto* sem_e = sem.Get(e)) {
+                    if (auto* var_user = sem_e->As<sem::VariableUser>()) {
+                        // Don't hoist constants.
+                        if (var_user->ConstantValue().IsValid()) {
+                            return false;
+                        }
+                        // Don't hoist read-only variables as they cannot receive
+                        // side-effects.
+                        if (var_user->Variable()->Access() == ast::Access::kRead) {
+                            return false;
+                        }
+                        return true;
+                    }
+                }
+                return false;
+            },
+            [&](const ast::BinaryExpression* e) {
+                if (e->IsLogical() && HasSideEffects(e)) {
+                    // Don't hoist children of logical binary expressions with
+                    // side-effects. These will be handled by DecomposeState.
+                    process(e->lhs);
+                    process(e->rhs);
+                    return false;
+                }
+                return binary_process(e->lhs, e->rhs);
+            },
+            [&](const ast::BitcastExpression* e) {  //
+                return process(e->expr);
+            },
+            [&](const ast::UnaryOpExpression* e) {  //
+                auto r = process(e->expr);
+                // Don't hoist address-of expressions.
+                // E.g. for "g(&b, a(0))", we hoist "a(0)" only.
+                if (e->op == ast::UnaryOp::kAddressOf) {
+                    return false;
+                }
+                return r;
+            },
+            [&](const ast::IndexAccessorExpression* e) {
+                return accessor_process(e->object, e->index);
+            },
+            [&](const ast::MemberAccessorExpression* e) {
+                return accessor_process(e->structure, e->member);
+            },
+            [&](const ast::LiteralExpression*) {
+                // Leaf
+                return false;
+            },
+            [&](const ast::PhonyExpression*) {
+                // Leaf
+                return false;
+            },
+            [&](Default) {
+                TINT_ICE(Transform, b.Diagnostics()) << "Unhandled expression type";
+                return false;
+            });
     }
 
-    ast::ExpressionList maybe_hoist;
-    ProcessExpression(expr, maybe_hoist);
-  }
+    // Starts the recursive processing of a statement's expression(s) to hoist
+    // side-effects to lets.
+    void ProcessStatement(const ast::Expression* expr) {
+        if (!expr) {
+            return;
+        }
 
-  // Special case for processing assignment statement expressions, as we must
-  // evaluate the rhs before the lhs, and possibly hoist the rhs expression.
-  void ProcessAssignment(const ast::Expression* lhs,
-                         const ast::Expression* rhs) {
-    // Evaluate rhs before lhs
-    ast::ExpressionList maybe_hoist;
-    if (ProcessExpression(rhs, maybe_hoist)) {
-      maybe_hoist.emplace_back(rhs);
+        ast::ExpressionList maybe_hoist;
+        ProcessExpression(expr, maybe_hoist);
     }
 
-    // If the rhs has side-effects, it may affect the lhs, so hoist it right
-    // away. e.g. "b[c] = a(0);"
-    if (HasSideEffects(rhs)) {
-      // Technically, we can always hoist rhs, but don't bother doing so when
-      // the lhs is just a variable or phony.
-      if (!lhs->IsAnyOf<ast::IdentifierExpression, ast::PhonyExpression>()) {
-        Flush(maybe_hoist);
-      }
+    // Special case for processing assignment statement expressions, as we must
+    // evaluate the rhs before the lhs, and possibly hoist the rhs expression.
+    void ProcessAssignment(const ast::Expression* lhs, const ast::Expression* rhs) {
+        // Evaluate rhs before lhs
+        ast::ExpressionList maybe_hoist;
+        if (ProcessExpression(rhs, maybe_hoist)) {
+            maybe_hoist.emplace_back(rhs);
+        }
+
+        // If the rhs has side-effects, it may affect the lhs, so hoist it right
+        // away. e.g. "b[c] = a(0);"
+        if (HasSideEffects(rhs)) {
+            // Technically, we can always hoist rhs, but don't bother doing so when
+            // the lhs is just a variable or phony.
+            if (!lhs->IsAnyOf<ast::IdentifierExpression, ast::PhonyExpression>()) {
+                Flush(maybe_hoist);
+            }
+        }
+
+        // If maybe_hoist still has values, it means they are potential side-effect
+        // receivers. We pass this in while processing the lhs, in which case they
+        // may get hoisted if the lhs has side-effects. E.g. "b[a(0)] = c;".
+        ProcessExpression(lhs, maybe_hoist);
     }
 
-    // If maybe_hoist still has values, it means they are potential side-effect
-    // receivers. We pass this in while processing the lhs, in which case they
-    // may get hoisted if the lhs has side-effects. E.g. "b[a(0)] = c;".
-    ProcessExpression(lhs, maybe_hoist);
-  }
+  public:
+    explicit CollectHoistsState(CloneContext& ctx_in) : StateBase(ctx_in) {}
 
- public:
-  explicit CollectHoistsState(CloneContext& ctx_in) : StateBase(ctx_in) {}
+    ToHoistSet Run() {
+        // Traverse all statements, recursively processing their expression tree(s)
+        // to hoist side-effects to lets.
+        for (auto* node : ctx.src->ASTNodes().Objects()) {
+            auto* stmt = node->As<ast::Statement>();
+            if (!stmt) {
+                continue;
+            }
 
-  ToHoistSet Run() {
-    // Traverse all statements, recursively processing their expression tree(s)
-    // to hoist side-effects to lets.
-    for (auto* node : ctx.src->ASTNodes().Objects()) {
-      auto* stmt = node->As<ast::Statement>();
-      if (!stmt) {
-        continue;
-      }
+            Switch(
+                stmt, [&](const ast::AssignmentStatement* s) { ProcessAssignment(s->lhs, s->rhs); },
+                [&](const ast::CallStatement* s) {  //
+                    ProcessStatement(s->expr);
+                },
+                [&](const ast::ForLoopStatement* s) { ProcessStatement(s->condition); },
+                [&](const ast::IfStatement* s) {  //
+                    ProcessStatement(s->condition);
+                },
+                [&](const ast::ReturnStatement* s) {  //
+                    ProcessStatement(s->value);
+                },
+                [&](const ast::SwitchStatement* s) { ProcessStatement(s->condition); },
+                [&](const ast::VariableDeclStatement* s) {
+                    ProcessStatement(s->variable->constructor);
+                });
+        }
 
-      Switch(
-          stmt,
-          [&](const ast::AssignmentStatement* s) {
-            ProcessAssignment(s->lhs, s->rhs);
-          },
-          [&](const ast::CallStatement* s) {  //
-            ProcessStatement(s->expr);
-          },
-          [&](const ast::ElseStatement* s) {  //
-            ProcessStatement(s->condition);
-          },
-          [&](const ast::ForLoopStatement* s) {
-            ProcessStatement(s->condition);
-          },
-          [&](const ast::IfStatement* s) {  //
-            ProcessStatement(s->condition);
-          },
-          [&](const ast::ReturnStatement* s) {  //
-            ProcessStatement(s->value);
-          },
-          [&](const ast::SwitchStatement* s) {
-            ProcessStatement(s->condition);
-          },
-          [&](const ast::VariableDeclStatement* s) {
-            ProcessStatement(s->variable->constructor);
-          });
+        return std::move(to_hoist);
     }
-
-    return std::move(to_hoist);
-  }
 };
 
 // DecomposeState performs the actual transforming of the AST to ensure order of
 // evaluation, using the set of expressions to hoist collected by
 // CollectHoistsState.
 class DecomposeSideEffects::DecomposeState : public StateBase {
-  ToHoistSet to_hoist;
+    ToHoistSet to_hoist;
 
-  // Returns true if `binary_expr` should be decomposed for short-circuit eval.
-  bool IsLogicalWithSideEffects(const ast::BinaryExpression* binary_expr) {
-    return binary_expr->IsLogical() &&
-           (sem.Get(binary_expr->lhs)->HasSideEffects() ||
-            sem.Get(binary_expr->rhs)->HasSideEffects());
-  }
-
-  // Recursive function used to decompose an expression for short-circuit eval.
-  const ast::Expression* Decompose(const ast::Expression* expr,
-                                   ast::StatementList* curr_stmts) {
-    // Helper to avoid passing in same args.
-    auto decompose = [&](auto& e) { return Decompose(e, curr_stmts); };
-
-    // Clones `expr`, possibly hoisting it to a let.
-    auto clone_maybe_hoisted =
-        [&](const ast::Expression* e) -> const ast::Expression* {
-      if (to_hoist.count(e)) {
-        auto name = b.Symbols().New();
-        auto* v = b.Const(name, nullptr, ctx.Clone(e));
-        auto* decl = b.Decl(v);
-        curr_stmts->push_back(decl);
-        return b.Expr(name);
-      }
-      return ctx.Clone(e);
-    };
-
-    return Switch(
-        expr,
-        [&](const ast::BinaryExpression* bin_expr) -> const ast::Expression* {
-          if (!IsLogicalWithSideEffects(bin_expr)) {
-            // No short-circuit, emit usual binary expr
-            ctx.Replace(bin_expr->lhs, decompose(bin_expr->lhs));
-            ctx.Replace(bin_expr->rhs, decompose(bin_expr->rhs));
-            return clone_maybe_hoisted(bin_expr);
-          }
-
-          // Decompose into ifs to implement short-circuiting
-          // For example, 'let r = a && b' becomes:
-          //
-          // var temp = a;
-          // if (temp) {
-          //   temp = b;
-          // }
-          // let r = temp;
-          //
-          // and similarly, 'let r = a || b' becomes:
-          //
-          // var temp = a;
-          // if (!temp) {
-          //     temp = b;
-          // }
-          // let r = temp;
-          //
-          // Further, compound logical binary expressions are also handled
-          // recursively, for example, 'let r = (a && (b && c))' becomes:
-          //
-          // var temp = a;
-          // if (temp) {
-          //     var temp2 = b;
-          //     if (temp2) {
-          //         temp2 = c;
-          //     }
-          //     temp = temp2;
-          // }
-          // let r = temp;
-
-          auto name = b.Sym();
-          curr_stmts->push_back(
-              b.Decl(b.Var(name, nullptr, decompose(bin_expr->lhs))));
-
-          const ast::Expression* if_cond = nullptr;
-          if (bin_expr->IsLogicalOr()) {
-            if_cond = b.Not(name);
-          } else {
-            if_cond = b.Expr(name);
-          }
-
-          const ast::BlockStatement* if_body = nullptr;
-          {
-            ast::StatementList stmts;
-            TINT_SCOPED_ASSIGNMENT(curr_stmts, &stmts);
-            auto* new_rhs = decompose(bin_expr->rhs);
-            curr_stmts->push_back(b.Assign(name, new_rhs));
-            if_body = b.Block(std::move(*curr_stmts));
-          }
-
-          curr_stmts->push_back(b.If(if_cond, if_body));
-
-          return b.Expr(name);
-        },
-        [&](const ast::IndexAccessorExpression* idx) {
-          ctx.Replace(idx->object, decompose(idx->object));
-          ctx.Replace(idx->index, decompose(idx->index));
-          return clone_maybe_hoisted(idx);
-        },
-        [&](const ast::BitcastExpression* bitcast) {
-          ctx.Replace(bitcast->expr, decompose(bitcast->expr));
-          return clone_maybe_hoisted(bitcast);
-        },
-        [&](const ast::CallExpression* call) {
-          if (call->target.name) {
-            ctx.Replace(call->target.name, decompose(call->target.name));
-          }
-          for (auto* a : call->args) {
-            ctx.Replace(a, decompose(a));
-          }
-          return clone_maybe_hoisted(call);
-        },
-        [&](const ast::MemberAccessorExpression* member) {
-          ctx.Replace(member->structure, decompose(member->structure));
-          ctx.Replace(member->member, decompose(member->member));
-          return clone_maybe_hoisted(member);
-        },
-        [&](const ast::UnaryOpExpression* unary) {
-          ctx.Replace(unary->expr, decompose(unary->expr));
-          return clone_maybe_hoisted(unary);
-        },
-        [&](const ast::LiteralExpression* lit) {
-          return clone_maybe_hoisted(lit);  // Leaf expression, just clone as is
-        },
-        [&](const ast::IdentifierExpression* id) {
-          return clone_maybe_hoisted(id);  // Leaf expression, just clone as is
-        },
-        [&](const ast::PhonyExpression* phony) {
-          return clone_maybe_hoisted(
-              phony);  // Leaf expression, just clone as is
-        },
-        [&](Default) {
-          TINT_ICE(AST, b.Diagnostics())
-              << "unhandled expression type: " << expr->TypeInfo().name;
-          return nullptr;
-        });
-  }
-
-  // Inserts statements in `stmts` before `stmt`
-  void InsertBefore(const ast::StatementList& stmts,
-                    const ast::Statement* stmt) {
-    if (!stmts.empty()) {
-      auto ip = utils::GetInsertionPoint(ctx, stmt);
-      for (auto* s : stmts) {
-        ctx.InsertBefore(ip.first->Declaration()->statements, ip.second, s);
-      }
+    // Returns true if `binary_expr` should be decomposed for short-circuit eval.
+    bool IsLogicalWithSideEffects(const ast::BinaryExpression* binary_expr) {
+        return binary_expr->IsLogical() && (sem.Get(binary_expr->lhs)->HasSideEffects() ||
+                                            sem.Get(binary_expr->rhs)->HasSideEffects());
     }
-  }
 
-  // Decomposes expressions of `stmt`, returning a replacement statement or
-  // nullptr if not replacing it.
-  const ast::Statement* DecomposeStatement(const ast::Statement* stmt) {
-    return Switch(
-        stmt,
-        [&](const ast::AssignmentStatement* s) -> const ast::Statement* {
-          if (!sem.Get(s->lhs)->HasSideEffects() &&
-              !sem.Get(s->rhs)->HasSideEffects()) {
-            return nullptr;
-          }
-          // rhs before lhs
-          ast::StatementList stmts;
-          ctx.Replace(s->rhs, Decompose(s->rhs, &stmts));
-          ctx.Replace(s->lhs, Decompose(s->lhs, &stmts));
-          InsertBefore(stmts, s);
-          return ctx.CloneWithoutTransform(s);
-        },
-        [&](const ast::CallStatement* s) -> const ast::Statement* {
-          if (!sem.Get(s->expr)->HasSideEffects()) {
-            return nullptr;
-          }
-          ast::StatementList stmts;
-          ctx.Replace(s->expr, Decompose(s->expr, &stmts));
-          InsertBefore(stmts, s);
-          return ctx.CloneWithoutTransform(s);
-        },
-        [&](const ast::ElseStatement* s) -> const ast::Statement* {
-          if (!s->condition || !sem.Get(s->condition)->HasSideEffects()) {
-            return nullptr;
-          }
-          // NOTE: We shouldn't reach here as else-if with side-effect
-          // conditions are simplified to else { if } by
-          // SimplifySideEffectStatements.
-          ast::StatementList stmts;
-          ctx.Replace(s->condition, Decompose(s->condition, &stmts));
-          InsertBefore(stmts, s);
-          return ctx.CloneWithoutTransform(s);
-        },
-        [&](const ast::ForLoopStatement* s) -> const ast::Statement* {
-          if (!s->condition || !sem.Get(s->condition)->HasSideEffects()) {
-            return nullptr;
-          }
-          ast::StatementList stmts;
-          ctx.Replace(s->condition, Decompose(s->condition, &stmts));
-          InsertBefore(stmts, s);
-          return ctx.CloneWithoutTransform(s);
-        },
-        [&](const ast::IfStatement* s) -> const ast::Statement* {
-          if (!sem.Get(s->condition)->HasSideEffects()) {
-            return nullptr;
-          }
-          ast::StatementList stmts;
-          ctx.Replace(s->condition, Decompose(s->condition, &stmts));
-          InsertBefore(stmts, s);
-          return ctx.CloneWithoutTransform(s);
-        },
-        [&](const ast::ReturnStatement* s) -> const ast::Statement* {
-          if (!s->value || !sem.Get(s->value)->HasSideEffects()) {
-            return nullptr;
-          }
-          ast::StatementList stmts;
-          ctx.Replace(s->value, Decompose(s->value, &stmts));
-          InsertBefore(stmts, s);
-          return ctx.CloneWithoutTransform(s);
-        },
-        [&](const ast::SwitchStatement* s) -> const ast::Statement* {
-          if (!sem.Get(s->condition)) {
-            return nullptr;
-          }
-          ast::StatementList stmts;
-          ctx.Replace(s->condition, Decompose(s->condition, &stmts));
-          InsertBefore(stmts, s);
-          return ctx.CloneWithoutTransform(s);
-        },
-        [&](const ast::VariableDeclStatement* s) -> const ast::Statement* {
-          auto* var = s->variable;
-          if (!var->constructor ||
-              !sem.Get(var->constructor)->HasSideEffects()) {
-            return nullptr;
-          }
-          ast::StatementList stmts;
-          ctx.Replace(var->constructor, Decompose(var->constructor, &stmts));
-          InsertBefore(stmts, s);
-          return b.Decl(ctx.CloneWithoutTransform(var));
-        },
-        [](Default) -> const ast::Statement* {
-          // Other statement types don't have expressions
-          return nullptr;
-        });
-  }
+    // Recursive function used to decompose an expression for short-circuit eval.
+    const ast::Expression* Decompose(const ast::Expression* expr, ast::StatementList* curr_stmts) {
+        // Helper to avoid passing in same args.
+        auto decompose = [&](auto& e) { return Decompose(e, curr_stmts); };
 
- public:
-  explicit DecomposeState(CloneContext& ctx_in, ToHoistSet to_hoist_in)
-      : StateBase(ctx_in), to_hoist(std::move(to_hoist_in)) {}
-
-  void Run() {
-    // We replace all BlockStatements as this allows us to iterate over the
-    // block statements and ctx.InsertBefore hoisted declarations on them.
-    ctx.ReplaceAll(
-        [&](const ast::BlockStatement* block) -> const ast::Statement* {
-          for (auto* stmt : block->statements) {
-            if (auto* new_stmt = DecomposeStatement(stmt)) {
-              ctx.Replace(stmt, new_stmt);
+        // Clones `expr`, possibly hoisting it to a let.
+        auto clone_maybe_hoisted = [&](const ast::Expression* e) -> const ast::Expression* {
+            if (to_hoist.count(e)) {
+                auto name = b.Symbols().New();
+                auto* v = b.Let(name, nullptr, ctx.Clone(e));
+                auto* decl = b.Decl(v);
+                curr_stmts->push_back(decl);
+                return b.Expr(name);
             }
+            return ctx.Clone(e);
+        };
 
-            // Handle for loops, as they are the only other AST node that
-            // contains statements outside of BlockStatements.
-            if (auto* fl = stmt->As<ast::ForLoopStatement>()) {
-              if (auto* new_stmt = DecomposeStatement(fl->initializer)) {
-                ctx.Replace(fl->initializer, new_stmt);
-              }
-              if (auto* new_stmt = DecomposeStatement(fl->continuing)) {
-                ctx.Replace(fl->continuing, new_stmt);
-              }
+        return Switch(
+            expr,
+            [&](const ast::BinaryExpression* bin_expr) -> const ast::Expression* {
+                if (!IsLogicalWithSideEffects(bin_expr)) {
+                    // No short-circuit, emit usual binary expr
+                    ctx.Replace(bin_expr->lhs, decompose(bin_expr->lhs));
+                    ctx.Replace(bin_expr->rhs, decompose(bin_expr->rhs));
+                    return clone_maybe_hoisted(bin_expr);
+                }
+
+                // Decompose into ifs to implement short-circuiting
+                // For example, 'let r = a && b' becomes:
+                //
+                // var temp = a;
+                // if (temp) {
+                //   temp = b;
+                // }
+                // let r = temp;
+                //
+                // and similarly, 'let r = a || b' becomes:
+                //
+                // var temp = a;
+                // if (!temp) {
+                //     temp = b;
+                // }
+                // let r = temp;
+                //
+                // Further, compound logical binary expressions are also handled
+                // recursively, for example, 'let r = (a && (b && c))' becomes:
+                //
+                // var temp = a;
+                // if (temp) {
+                //     var temp2 = b;
+                //     if (temp2) {
+                //         temp2 = c;
+                //     }
+                //     temp = temp2;
+                // }
+                // let r = temp;
+
+                auto name = b.Sym();
+                curr_stmts->push_back(b.Decl(b.Var(name, nullptr, decompose(bin_expr->lhs))));
+
+                const ast::Expression* if_cond = nullptr;
+                if (bin_expr->IsLogicalOr()) {
+                    if_cond = b.Not(name);
+                } else {
+                    if_cond = b.Expr(name);
+                }
+
+                const ast::BlockStatement* if_body = nullptr;
+                {
+                    ast::StatementList stmts;
+                    TINT_SCOPED_ASSIGNMENT(curr_stmts, &stmts);
+                    auto* new_rhs = decompose(bin_expr->rhs);
+                    curr_stmts->push_back(b.Assign(name, new_rhs));
+                    if_body = b.Block(std::move(*curr_stmts));
+                }
+
+                curr_stmts->push_back(b.If(if_cond, if_body));
+
+                return b.Expr(name);
+            },
+            [&](const ast::IndexAccessorExpression* idx) {
+                ctx.Replace(idx->object, decompose(idx->object));
+                ctx.Replace(idx->index, decompose(idx->index));
+                return clone_maybe_hoisted(idx);
+            },
+            [&](const ast::BitcastExpression* bitcast) {
+                ctx.Replace(bitcast->expr, decompose(bitcast->expr));
+                return clone_maybe_hoisted(bitcast);
+            },
+            [&](const ast::CallExpression* call) {
+                if (call->target.name) {
+                    ctx.Replace(call->target.name, decompose(call->target.name));
+                }
+                for (auto* a : call->args) {
+                    ctx.Replace(a, decompose(a));
+                }
+                return clone_maybe_hoisted(call);
+            },
+            [&](const ast::MemberAccessorExpression* member) {
+                ctx.Replace(member->structure, decompose(member->structure));
+                ctx.Replace(member->member, decompose(member->member));
+                return clone_maybe_hoisted(member);
+            },
+            [&](const ast::UnaryOpExpression* unary) {
+                ctx.Replace(unary->expr, decompose(unary->expr));
+                return clone_maybe_hoisted(unary);
+            },
+            [&](const ast::LiteralExpression* lit) {
+                return clone_maybe_hoisted(lit);  // Leaf expression, just clone as is
+            },
+            [&](const ast::IdentifierExpression* id) {
+                return clone_maybe_hoisted(id);  // Leaf expression, just clone as is
+            },
+            [&](const ast::PhonyExpression* phony) {
+                return clone_maybe_hoisted(phony);  // Leaf expression, just clone as is
+            },
+            [&](Default) {
+                TINT_ICE(AST, b.Diagnostics())
+                    << "unhandled expression type: " << expr->TypeInfo().name;
+                return nullptr;
+            });
+    }
+
+    // Inserts statements in `stmts` before `stmt`
+    void InsertBefore(const ast::StatementList& stmts, const ast::Statement* stmt) {
+        if (!stmts.empty()) {
+            auto ip = utils::GetInsertionPoint(ctx, stmt);
+            for (auto* s : stmts) {
+                ctx.InsertBefore(ip.first->Declaration()->statements, ip.second, s);
             }
-          }
-          return nullptr;
+        }
+    }
+
+    // Decomposes expressions of `stmt`, returning a replacement statement or
+    // nullptr if not replacing it.
+    const ast::Statement* DecomposeStatement(const ast::Statement* stmt) {
+        return Switch(
+            stmt,
+            [&](const ast::AssignmentStatement* s) -> const ast::Statement* {
+                if (!sem.Get(s->lhs)->HasSideEffects() && !sem.Get(s->rhs)->HasSideEffects()) {
+                    return nullptr;
+                }
+                // rhs before lhs
+                ast::StatementList stmts;
+                ctx.Replace(s->rhs, Decompose(s->rhs, &stmts));
+                ctx.Replace(s->lhs, Decompose(s->lhs, &stmts));
+                InsertBefore(stmts, s);
+                return ctx.CloneWithoutTransform(s);
+            },
+            [&](const ast::CallStatement* s) -> const ast::Statement* {
+                if (!sem.Get(s->expr)->HasSideEffects()) {
+                    return nullptr;
+                }
+                ast::StatementList stmts;
+                ctx.Replace(s->expr, Decompose(s->expr, &stmts));
+                InsertBefore(stmts, s);
+                return ctx.CloneWithoutTransform(s);
+            },
+            [&](const ast::ForLoopStatement* s) -> const ast::Statement* {
+                if (!s->condition || !sem.Get(s->condition)->HasSideEffects()) {
+                    return nullptr;
+                }
+                ast::StatementList stmts;
+                ctx.Replace(s->condition, Decompose(s->condition, &stmts));
+                InsertBefore(stmts, s);
+                return ctx.CloneWithoutTransform(s);
+            },
+            [&](const ast::IfStatement* s) -> const ast::Statement* {
+                if (!sem.Get(s->condition)->HasSideEffects()) {
+                    return nullptr;
+                }
+                ast::StatementList stmts;
+                ctx.Replace(s->condition, Decompose(s->condition, &stmts));
+                InsertBefore(stmts, s);
+                return ctx.CloneWithoutTransform(s);
+            },
+            [&](const ast::ReturnStatement* s) -> const ast::Statement* {
+                if (!s->value || !sem.Get(s->value)->HasSideEffects()) {
+                    return nullptr;
+                }
+                ast::StatementList stmts;
+                ctx.Replace(s->value, Decompose(s->value, &stmts));
+                InsertBefore(stmts, s);
+                return ctx.CloneWithoutTransform(s);
+            },
+            [&](const ast::SwitchStatement* s) -> const ast::Statement* {
+                if (!sem.Get(s->condition)) {
+                    return nullptr;
+                }
+                ast::StatementList stmts;
+                ctx.Replace(s->condition, Decompose(s->condition, &stmts));
+                InsertBefore(stmts, s);
+                return ctx.CloneWithoutTransform(s);
+            },
+            [&](const ast::VariableDeclStatement* s) -> const ast::Statement* {
+                auto* var = s->variable;
+                if (!var->constructor || !sem.Get(var->constructor)->HasSideEffects()) {
+                    return nullptr;
+                }
+                ast::StatementList stmts;
+                ctx.Replace(var->constructor, Decompose(var->constructor, &stmts));
+                InsertBefore(stmts, s);
+                return b.Decl(ctx.CloneWithoutTransform(var));
+            },
+            [](Default) -> const ast::Statement* {
+                // Other statement types don't have expressions
+                return nullptr;
+            });
+    }
+
+  public:
+    explicit DecomposeState(CloneContext& ctx_in, ToHoistSet to_hoist_in)
+        : StateBase(ctx_in), to_hoist(std::move(to_hoist_in)) {}
+
+    void Run() {
+        // We replace all BlockStatements as this allows us to iterate over the
+        // block statements and ctx.InsertBefore hoisted declarations on them.
+        ctx.ReplaceAll([&](const ast::BlockStatement* block) -> const ast::Statement* {
+            for (auto* stmt : block->statements) {
+                if (auto* new_stmt = DecomposeStatement(stmt)) {
+                    ctx.Replace(stmt, new_stmt);
+                }
+
+                // Handle for loops, as they are the only other AST node that
+                // contains statements outside of BlockStatements.
+                if (auto* fl = stmt->As<ast::ForLoopStatement>()) {
+                    if (auto* new_stmt = DecomposeStatement(fl->initializer)) {
+                        ctx.Replace(fl->initializer, new_stmt);
+                    }
+                    if (auto* new_stmt = DecomposeStatement(fl->continuing)) {
+                        ctx.Replace(fl->continuing, new_stmt);
+                    }
+                }
+            }
+            return nullptr;
         });
 
-    ctx.Clone();
-  }
+        ctx.Clone();
+    }
 };
 
-void DecomposeSideEffects::Run(CloneContext& ctx,
-                               const DataMap&,
-                               DataMap&) const {
-  // First collect side-effecting expressions to hoist
-  CollectHoistsState collect_hoists_state{ctx};
-  auto to_hoist = collect_hoists_state.Run();
+void DecomposeSideEffects::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
+    // First collect side-effecting expressions to hoist
+    CollectHoistsState collect_hoists_state{ctx};
+    auto to_hoist = collect_hoists_state.Run();
 
-  // Now decompose these expressions
-  DecomposeState decompose_state{ctx, std::move(to_hoist)};
-  decompose_state.Run();
+    // Now decompose these expressions
+    DecomposeState decompose_state{ctx, std::move(to_hoist)};
+    decompose_state.Run();
 }
 
 }  // namespace
@@ -708,14 +667,13 @@
 PromoteSideEffectsToDecl::PromoteSideEffectsToDecl() = default;
 PromoteSideEffectsToDecl::~PromoteSideEffectsToDecl() = default;
 
-Output PromoteSideEffectsToDecl::Run(const Program* program,
-                                     const DataMap& data) const {
-  transform::Manager manager;
-  manager.Add<SimplifySideEffectStatements>();
-  manager.Add<DecomposeSideEffects>();
+Output PromoteSideEffectsToDecl::Run(const Program* program, const DataMap& data) const {
+    transform::Manager manager;
+    manager.Add<SimplifySideEffectStatements>();
+    manager.Add<DecomposeSideEffects>();
 
-  auto output = manager.Run(program, data);
-  return output;
+    auto output = manager.Run(program, data);
+    return output;
 }
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/promote_side_effects_to_decl.h b/src/tint/transform/promote_side_effects_to_decl.h
index cdc9241..1e629b3 100644
--- a/src/tint/transform/promote_side_effects_to_decl.h
+++ b/src/tint/transform/promote_side_effects_to_decl.h
@@ -23,21 +23,20 @@
 /// declarations before the statement of usage with the goal of ensuring
 /// left-to-right order of evaluation, while respecting short-circuit
 /// evaluation.
-class PromoteSideEffectsToDecl
-    : public Castable<PromoteSideEffectsToDecl, Transform> {
- public:
-  /// Constructor
-  PromoteSideEffectsToDecl();
+class PromoteSideEffectsToDecl : public Castable<PromoteSideEffectsToDecl, Transform> {
+  public:
+    /// Constructor
+    PromoteSideEffectsToDecl();
 
-  /// Destructor
-  ~PromoteSideEffectsToDecl() override;
+    /// Destructor
+    ~PromoteSideEffectsToDecl() override;
 
- protected:
-  /// Runs the transform on `program`, returning the transformation result.
-  /// @param program the source program to transform
-  /// @param data optional extra transform-specific data
-  /// @returns the transformation result
-  Output Run(const Program* program, const DataMap& data = {}) const override;
+  protected:
+    /// Runs the transform on `program`, returning the transformation result.
+    /// @param program the source program to transform
+    /// @param data optional extra transform-specific data
+    /// @returns the transformation result
+    Output Run(const Program* program, const DataMap& data = {}) const override;
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/promote_side_effects_to_decl_test.cc b/src/tint/transform/promote_side_effects_to_decl_test.cc
index 299d706..9d9115f 100644
--- a/src/tint/transform/promote_side_effects_to_decl_test.cc
+++ b/src/tint/transform/promote_side_effects_to_decl_test.cc
@@ -22,17 +22,17 @@
 using PromoteSideEffectsToDeclTest = TransformTest;
 
 TEST_F(PromoteSideEffectsToDeclTest, EmptyModule) {
-  auto* src = "";
-  auto* expect = "";
+    auto* src = "";
+    auto* expect = "";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Unary_Arith_SE) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -42,16 +42,16 @@
 }
 )";
 
-  auto* expect = src;
+    auto* expect = src;
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Arith_BothSE) {
-  auto* src = R"(
+    auto* src = R"(
 fn a() -> i32 {
   return 1;
 }
@@ -65,7 +65,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a() -> i32 {
   return 1;
 }
@@ -81,14 +81,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Arith_LeftSE) {
-  auto* src = R"(
+    auto* src = R"(
 fn a() -> i32 {
   return 1;
 }
@@ -99,7 +99,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a() -> i32 {
   return 1;
 }
@@ -111,14 +111,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Arith_RightSE) {
-  auto* src = R"(
+    auto* src = R"(
 fn a() -> i32 {
   return 1;
 }
@@ -129,7 +129,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a() -> i32 {
   return 1;
 }
@@ -142,14 +142,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Arith_LeftmostSE) {
-  auto* src = R"(
+    auto* src = R"(
 fn a() -> i32 {
   return 1;
 }
@@ -162,7 +162,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a() -> i32 {
   return 1;
 }
@@ -176,14 +176,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Arith_RightmostSE) {
-  auto* src = R"(
+    auto* src = R"(
 fn a() -> i32 {
   return 1;
 }
@@ -196,7 +196,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a() -> i32 {
   return 1;
 }
@@ -211,14 +211,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Arith_MiddleSE) {
-  auto* src = R"(
+    auto* src = R"(
 fn a() -> i32 {
   return 1;
 }
@@ -232,7 +232,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a() -> i32 {
   return 1;
 }
@@ -248,14 +248,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Arith_ThreeSE) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(v : i32) -> i32 {
   return v;
 }
@@ -265,7 +265,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(v : i32) -> i32 {
   return v;
 }
@@ -278,14 +278,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Arith_Constants_NoRecvSE) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -295,7 +295,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -306,14 +306,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Arith_Constants_RecvSE) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -324,7 +324,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -338,14 +338,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Arith_Constants_ConstAndSEAndVar) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -357,7 +357,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -370,14 +370,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Arith_Constants_VarAndSEAndConst) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -388,7 +388,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -401,15 +401,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(PromoteSideEffectsToDeclTest,
-       Binary_Arith_Constants_SEAndVarAndConstAndVar) {
-  auto* src = R"(
+TEST_F(PromoteSideEffectsToDeclTest, Binary_Arith_Constants_SEAndVarAndConstAndVar) {
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -421,7 +420,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -434,14 +433,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Arith_Builtins_WithSE) {
-  auto* src = R"(
+    auto* src = R"(
 struct SB {
   a : atomic<i32>,
 }
@@ -454,7 +453,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct SB {
   a : atomic<i32>,
 }
@@ -468,14 +467,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Arith_Builtins_NoSEAndVar) {
-  auto* src = R"(
+    auto* src = R"(
 struct SB {
   a : atomic<i32>,
 }
@@ -488,16 +487,16 @@
 }
 )";
 
-  auto* expect = src;
+    auto* expect = src;
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Arith_Builtins_NoSEAndSE) {
-  auto* src = R"(
+    auto* src = R"(
 struct SB {
   a : atomic<i32>,
 }
@@ -514,7 +513,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct SB {
   a : atomic<i32>,
 }
@@ -533,14 +532,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Arith_Vector_RightSE) {
-  auto* src = R"(
+    auto* src = R"(
 fn a() -> i32 {
   return 1;
 }
@@ -552,7 +551,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a() -> i32 {
   return 1;
 }
@@ -567,14 +566,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Arith_InCall) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -589,7 +588,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -609,14 +608,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Arith_InTypeCtor) {
-  auto* src = R"(
+    auto* src = R"(
 
 fn a(i : i32) -> i32 {
   return 1;
@@ -628,7 +627,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -646,14 +645,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Arith_InTypeConversion) {
-  auto* src = R"(
+    auto* src = R"(
 
 fn a(i : i32) -> i32 {
   return 1;
@@ -665,7 +664,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -680,14 +679,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Arith_InIntrinsic) {
-  auto* src = R"(
+    auto* src = R"(
 
 fn a(i : i32) -> i32 {
   return i;
@@ -699,7 +698,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -717,14 +716,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Arith_InMemberAccessor) {
-  auto* src = R"(
+    auto* src = R"(
 
 struct S {
   v : i32,
@@ -740,7 +739,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   v : i32,
 }
@@ -758,14 +757,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Arith_InUnary) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -776,7 +775,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -790,14 +789,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Arith_InBitcast) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -808,7 +807,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -821,14 +820,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Arith_InForLoopInit) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -842,7 +841,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -857,14 +856,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Arith_InForLoopCond) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -877,7 +876,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -896,14 +895,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Arith_InForLoopCont) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -918,7 +917,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -940,14 +939,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Arith_InForLoopInitCondCont) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -963,7 +962,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -994,14 +993,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Arith_InElseIf) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -1016,7 +1015,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -1034,14 +1033,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Arith_InElseIfChain) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -1064,7 +1063,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -1094,14 +1093,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Arith_InReturn) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -1112,7 +1111,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -1125,14 +1124,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Arith_InSwitch) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -1146,7 +1145,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -1162,14 +1161,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Logical_LeftSE) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -1180,7 +1179,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -1195,14 +1194,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Logical_RightSE) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -1213,7 +1212,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -1228,14 +1227,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Logical_BothSE) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -1245,7 +1244,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -1259,14 +1258,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Logical_LeftmostSE) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -1279,7 +1278,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -1304,14 +1303,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Logical_RightmostSE) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -1324,7 +1323,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -1341,14 +1340,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Logical_MiddleSE) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -1361,7 +1360,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -1386,14 +1385,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Logical_Constants_NoRecvSE) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -1403,7 +1402,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -1425,14 +1424,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Logical_Constants_RecvSE) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -1443,7 +1442,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -1466,15 +1465,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(PromoteSideEffectsToDeclTest,
-       Binary_Logical_Constants_ConstAndSEAndVar) {
-  auto* src = R"(
+TEST_F(PromoteSideEffectsToDeclTest, Binary_Logical_Constants_ConstAndSEAndVar) {
+    auto* src = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -1486,7 +1484,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -1506,15 +1504,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(PromoteSideEffectsToDeclTest,
-       Binary_Logical_Constants_VarAndSEAndConst) {
-  auto* src = R"(
+TEST_F(PromoteSideEffectsToDeclTest, Binary_Logical_Constants_VarAndSEAndConst) {
+    auto* src = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -1525,7 +1522,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -1544,15 +1541,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(PromoteSideEffectsToDeclTest,
-       Binary_Logical_Constants_SEAndVarAndConstAndVar) {
-  auto* src = R"(
+TEST_F(PromoteSideEffectsToDeclTest, Binary_Logical_Constants_SEAndVarAndConstAndVar) {
+    auto* src = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -1564,7 +1560,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -1588,14 +1584,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Logical_MixedSE) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -1608,7 +1604,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -1645,14 +1641,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Logical_NestedAnds) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -1662,7 +1658,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -1692,14 +1688,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Logical_NestedOrs) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -1709,7 +1705,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -1739,14 +1735,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Logical_MultipleStatements) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -1758,7 +1754,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -1778,14 +1774,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Logical_InCall) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -1800,7 +1796,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -1819,14 +1815,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Logical_InTypeCtor) {
-  auto* src = R"(
+    auto* src = R"(
 
 fn a(i : i32) -> bool {
   return true;
@@ -1838,7 +1834,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -1866,14 +1862,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Logical_InTypeConversion) {
-  auto* src = R"(
+    auto* src = R"(
 
 fn a(i : i32) -> i32 {
   return 1;
@@ -1885,7 +1881,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -1906,16 +1902,16 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 // Make sure we process logical binary expressions of non-logical binary
 // expressions.
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Logical_OfNonLogical) {
-  auto* src = R"(
+    auto* src = R"(
 
 fn a(i : i32) -> i32 {
   return 1;
@@ -1927,7 +1923,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -1944,14 +1940,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Logical_InIntrinsic) {
-  auto* src = R"(
+    auto* src = R"(
 
 fn a(i : i32) -> bool {
   return true;
@@ -1963,7 +1959,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -1991,14 +1987,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Logical_InMemberAccessor) {
-  auto* src = R"(
+    auto* src = R"(
 
 struct S {
   v : bool,
@@ -2014,7 +2010,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   v : bool,
 }
@@ -2039,14 +2035,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Logical_InUnary) {
-  auto* src = R"(
+    auto* src = R"(
 
 fn a(i : i32) -> bool {
   return true;
@@ -2058,7 +2054,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -2073,14 +2069,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Logical_InBitcast) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -2091,7 +2087,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -2106,14 +2102,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Logical_InForLoopInit) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -2127,7 +2123,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -2145,14 +2141,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Logical_InForLoopCond) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -2165,7 +2161,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -2187,14 +2183,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Logical_InForLoopCont) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -2209,7 +2205,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -2234,14 +2230,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Logical_InForLoopInitCondCont) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -2257,7 +2253,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -2297,14 +2293,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Logical_InElseIf) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -2319,7 +2315,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -2340,14 +2336,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Logical_InElseIfChain) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -2370,7 +2366,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> bool {
   return true;
 }
@@ -2405,14 +2401,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Call_NoSE) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -2428,16 +2424,16 @@
 }
 )";
 
-  auto* expect = src;
+    auto* expect = src;
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Call_OneSE) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -2452,7 +2448,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -2468,14 +2464,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Call_AllSE) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -2489,7 +2485,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -2506,14 +2502,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Call_MiddleNotSE) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -2529,7 +2525,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -2547,14 +2543,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Call_InBinary) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -2571,7 +2567,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -2593,14 +2589,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, IndexAccessor_2D_LeftSE) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -2612,7 +2608,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -2625,14 +2621,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, IndexAccessor_2D_RightSE) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -2646,7 +2642,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -2660,14 +2656,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, IndexAccessor_2D_BothSE) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -2678,7 +2674,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -2691,14 +2687,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Assignment_ToPhony) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -2708,7 +2704,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -2718,14 +2714,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Assignment_ToArray1D) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -2736,7 +2732,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -2749,14 +2745,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Assignment_ToArray2D) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -2767,7 +2763,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -2781,14 +2777,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Assignment_ToArray3D) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -2799,7 +2795,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -2814,14 +2810,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Assignment_ToArray_FromArray) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -2834,7 +2830,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -2851,14 +2847,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Assignment_ToVec_BothSE) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -2869,7 +2865,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -2882,14 +2878,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Assignment_ToVec_LeftSE) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -2901,7 +2897,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -2915,14 +2911,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Assignment_ToVec_RightSE) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -2934,7 +2930,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -2947,14 +2943,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, TypeConstructor_Struct) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -2970,7 +2966,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -2989,14 +2985,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, TypeConstructor_Array1D) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -3006,7 +3002,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -3019,14 +3015,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, TypeConstructor_Array2D) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -3036,7 +3032,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return 1;
 }
@@ -3052,14 +3048,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, MemberAccessor_Vec) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> vec3<i32> {
   return vec3<i32>();
 }
@@ -3069,7 +3065,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> vec3<i32> {
   return vec3<i32>();
 }
@@ -3081,14 +3077,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, MemberAccessor_Struct) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   x : i32,
   y : i32,
@@ -3103,7 +3099,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   x : i32,
   y : i32,
@@ -3120,14 +3116,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, MemberAccessor_Struct_Mixed) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   x : i32,
   y : i32,
@@ -3152,7 +3148,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   x : i32,
   y : i32,
@@ -3184,14 +3180,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, IndexAccessor_Plus_SE) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -3202,7 +3198,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -3215,14 +3211,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, IndexAccessor_Of_SE) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -3233,7 +3229,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -3245,14 +3241,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, IndexAccessor2_Of_LeftSE) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -3263,7 +3259,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -3275,14 +3271,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, IndexAccessor2_Of_RightSE) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -3293,7 +3289,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -3305,14 +3301,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, IndexAccessor2_Of_SEAndVar) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -3324,7 +3320,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -3337,14 +3333,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, IndexAccessor2_Of_VarAndSE) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -3356,7 +3352,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -3370,14 +3366,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, IndexAccessorOfVar_Plus_SE) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -3389,7 +3385,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -3404,14 +3400,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, IndexAccessor_Plus_IndexAccessorOfSE) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -3422,7 +3418,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -3435,15 +3431,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(PromoteSideEffectsToDeclTest,
-       AssignTo_IndexAccessorOfIndexAccessorOfSE) {
-  auto* src = R"(
+TEST_F(PromoteSideEffectsToDeclTest, AssignTo_IndexAccessorOfIndexAccessorOfSE) {
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -3455,7 +3450,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -3468,15 +3463,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(PromoteSideEffectsToDeclTest,
-       AssignTo_IndexAccessorOfIndexAccessorOfLiteralPlusSE) {
-  auto* src = R"(
+TEST_F(PromoteSideEffectsToDeclTest, AssignTo_IndexAccessorOfIndexAccessorOfLiteralPlusSE) {
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -3488,7 +3482,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -3502,15 +3496,15 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest,
        AssignTo_IndexAccessorOfIndexAccessorOfLiteralPlusIndexAccessorOfSE) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -3522,7 +3516,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -3536,14 +3530,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, IndexAccessorOfLhsSERhsSE) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -3557,7 +3551,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -3573,14 +3567,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, BinaryIndexAccessorOfLhsSERhsSE) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -3594,7 +3588,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return i;
 }
@@ -3610,16 +3604,16 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, BinaryMemberAccessorPlusSE) {
-  // bclayton@'s example:
-  // https://dawn-review.googlesource.com/c/tint/+/78620/6..8/src/transform/promote_side_effects_to_decl.cc#b490
-  auto* src = R"(
+    // bclayton@'s example:
+    // https://dawn-review.googlesource.com/c/tint/+/78620/6..8/src/transform/promote_side_effects_to_decl.cc#b490
+    auto* src = R"(
 fn modify_vec(p : ptr<function, vec4<i32>>) -> i32 {
   (*p).x = 42;
   return 0;
@@ -3632,7 +3626,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn modify_vec(p : ptr<function, vec4<i32>>) -> i32 {
   (*(p)).x = 42;
   return 0;
@@ -3646,15 +3640,15 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Call_ReadOnlyArgAndSE) {
-  // Make sure that read-only args don't get hoisted (tex and samp)
-  auto* src = R"(
+    // Make sure that read-only args don't get hoisted (tex and samp)
+    auto* src = R"(
 @group(1) @binding(1) var tex: texture_2d_array<u32>;
 @group(1) @binding(2) var samp: sampler;
 
@@ -3667,7 +3661,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @group(1) @binding(1) var tex : texture_2d_array<u32>;
 
 @group(1) @binding(2) var samp : sampler;
@@ -3682,15 +3676,15 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Call_PtrArgAndSE) {
-  // Make sure that read-only args don't get hoisted (tex and samp)
-  auto* src = R"(
+    // Make sure that read-only args don't get hoisted (tex and samp)
+    auto* src = R"(
 
 var<private> b : i32 = 0;
 
@@ -3710,7 +3704,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> b : i32 = 0;
 
 fn a(i : i32) -> i32 {
@@ -3728,14 +3722,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, TypeCtor_VarPlusI32CtorPlusVar) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var b = 0;
   var c = 0;
@@ -3744,16 +3738,16 @@
 }
 )";
 
-  auto* expect = src;
+    auto* expect = src;
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Mixed_ArithPlusLogical) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return 0;
 }
@@ -3771,7 +3765,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return 0;
 }
@@ -3795,14 +3789,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Mixed_LogicalPlusArith) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return 0;
 }
@@ -3820,7 +3814,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return 0;
 }
@@ -3844,14 +3838,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Mixed_ArithAndLogicalArgs) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return 0;
 }
@@ -3869,7 +3863,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return 0;
 }
@@ -3892,14 +3886,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Mixed_LogicalAndArithArgs) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return 0;
 }
@@ -3917,7 +3911,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return 0;
 }
@@ -3940,14 +3934,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(PromoteSideEffectsToDeclTest, Binary_Mixed_Complex) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(i : i32) -> i32 {
   return 0;
 }
@@ -3969,7 +3963,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(i : i32) -> i32 {
   return 0;
 }
@@ -4001,10 +3995,10 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 }  // namespace
 }  // namespace tint::transform
diff --git a/src/tint/transform/remove_continue_in_switch.cc b/src/tint/transform/remove_continue_in_switch.cc
index 9ee05c0..5c2413e 100644
--- a/src/tint/transform/remove_continue_in_switch.cc
+++ b/src/tint/transform/remove_continue_in_switch.cc
@@ -34,95 +34,89 @@
 namespace {
 
 class State {
- private:
-  CloneContext& ctx;
-  ProgramBuilder& b;
-  const sem::Info& sem;
+  private:
+    CloneContext& ctx;
+    ProgramBuilder& b;
+    const sem::Info& sem;
 
-  // Map of switch statement to 'tint_continue' variable.
-  std::unordered_map<const ast::SwitchStatement*, Symbol>
-      switch_to_cont_var_name;
+    // Map of switch statement to 'tint_continue' variable.
+    std::unordered_map<const ast::SwitchStatement*, Symbol> switch_to_cont_var_name;
 
-  // If `cont` is within a switch statement within a loop, returns a pointer to
-  // that switch statement.
-  static const ast::SwitchStatement* GetParentSwitchInLoop(
-      const sem::Info& sem,
-      const ast::ContinueStatement* cont) {
-    // Find whether first parent is a switch or a loop
-    auto* sem_stmt = sem.Get(cont);
-    auto* sem_parent =
-        sem_stmt->FindFirstParent<sem::SwitchStatement, sem::LoopBlockStatement,
-                                  sem::ForLoopStatement>();
-    if (!sem_parent) {
-      return nullptr;
-    }
-    return sem_parent->Declaration()->As<ast::SwitchStatement>();
-  }
-
- public:
-  /// Constructor
-  /// @param ctx_in the context
-  explicit State(CloneContext& ctx_in)
-      : ctx(ctx_in), b(*ctx_in.dst), sem(ctx_in.src->Sem()) {}
-
-  /// Returns true if this transform should be run for the given program
-  static bool ShouldRun(const Program* program) {
-    for (auto* node : program->ASTNodes().Objects()) {
-      auto* stmt = node->As<ast::ContinueStatement>();
-      if (!stmt) {
-        continue;
-      }
-      if (GetParentSwitchInLoop(program->Sem(), stmt)) {
-        return true;
-      }
-    }
-    return false;
-  }
-
-  /// Runs the transform
-  void Run() {
-    for (auto* node : ctx.src->ASTNodes().Objects()) {
-      auto* cont = node->As<ast::ContinueStatement>();
-      if (!cont) {
-        continue;
-      }
-
-      // If first parent is not a switch within a loop, skip
-      auto* switch_stmt = GetParentSwitchInLoop(sem, cont);
-      if (!switch_stmt) {
-        continue;
-      }
-
-      auto cont_var_name =
-          tint::utils::GetOrCreate(switch_to_cont_var_name, switch_stmt, [&]() {
-            // Create and insert 'var tint_continue : bool = false;' before the
-            // switch.
-            auto var_name = b.Symbols().New("tint_continue");
-            auto* decl = b.Decl(b.Var(var_name, b.ty.bool_(), b.Expr(false)));
-            auto ip = utils::GetInsertionPoint(ctx, switch_stmt);
-            ctx.InsertBefore(ip.first->Declaration()->statements, ip.second,
-                             decl);
-
-            // Create and insert 'if (tint_continue) { continue; }' after
-            // switch.
-            auto* if_stmt = b.If(b.Expr(var_name), b.Block(b.Continue()));
-            ctx.InsertAfter(ip.first->Declaration()->statements, ip.second,
-                            if_stmt);
-
-            // Return the new var name
-            return var_name;
-          });
-
-      // Replace 'continue;' with '{ tint_continue = true; break; }'
-      auto* new_stmt = b.Block(                   //
-          b.Assign(b.Expr(cont_var_name), true),  //
-          b.Break());
-
-      ctx.Replace(cont, new_stmt);
+    // If `cont` is within a switch statement within a loop, returns a pointer to
+    // that switch statement.
+    static const ast::SwitchStatement* GetParentSwitchInLoop(const sem::Info& sem,
+                                                             const ast::ContinueStatement* cont) {
+        // Find whether first parent is a switch or a loop
+        auto* sem_stmt = sem.Get(cont);
+        auto* sem_parent = sem_stmt->FindFirstParent<sem::SwitchStatement, sem::LoopBlockStatement,
+                                                     sem::ForLoopStatement>();
+        if (!sem_parent) {
+            return nullptr;
+        }
+        return sem_parent->Declaration()->As<ast::SwitchStatement>();
     }
 
-    ctx.Clone();
-  }
+  public:
+    /// Constructor
+    /// @param ctx_in the context
+    explicit State(CloneContext& ctx_in) : ctx(ctx_in), b(*ctx_in.dst), sem(ctx_in.src->Sem()) {}
+
+    /// Returns true if this transform should be run for the given program
+    static bool ShouldRun(const Program* program) {
+        for (auto* node : program->ASTNodes().Objects()) {
+            auto* stmt = node->As<ast::ContinueStatement>();
+            if (!stmt) {
+                continue;
+            }
+            if (GetParentSwitchInLoop(program->Sem(), stmt)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /// Runs the transform
+    void Run() {
+        for (auto* node : ctx.src->ASTNodes().Objects()) {
+            auto* cont = node->As<ast::ContinueStatement>();
+            if (!cont) {
+                continue;
+            }
+
+            // If first parent is not a switch within a loop, skip
+            auto* switch_stmt = GetParentSwitchInLoop(sem, cont);
+            if (!switch_stmt) {
+                continue;
+            }
+
+            auto cont_var_name =
+                tint::utils::GetOrCreate(switch_to_cont_var_name, switch_stmt, [&]() {
+                    // Create and insert 'var tint_continue : bool = false;' before the
+                    // switch.
+                    auto var_name = b.Symbols().New("tint_continue");
+                    auto* decl = b.Decl(b.Var(var_name, b.ty.bool_(), b.Expr(false)));
+                    auto ip = utils::GetInsertionPoint(ctx, switch_stmt);
+                    ctx.InsertBefore(ip.first->Declaration()->statements, ip.second, decl);
+
+                    // Create and insert 'if (tint_continue) { continue; }' after
+                    // switch.
+                    auto* if_stmt = b.If(b.Expr(var_name), b.Block(b.Continue()));
+                    ctx.InsertAfter(ip.first->Declaration()->statements, ip.second, if_stmt);
+
+                    // Return the new var name
+                    return var_name;
+                });
+
+            // Replace 'continue;' with '{ tint_continue = true; break; }'
+            auto* new_stmt = b.Block(                   //
+                b.Assign(b.Expr(cont_var_name), true),  //
+                b.Break());
+
+            ctx.Replace(cont, new_stmt);
+        }
+
+        ctx.Clone();
+    }
 };
 
 }  // namespace
@@ -130,16 +124,13 @@
 RemoveContinueInSwitch::RemoveContinueInSwitch() = default;
 RemoveContinueInSwitch::~RemoveContinueInSwitch() = default;
 
-bool RemoveContinueInSwitch::ShouldRun(const Program* program,
-                                       const DataMap& /*data*/) const {
-  return State::ShouldRun(program);
+bool RemoveContinueInSwitch::ShouldRun(const Program* program, const DataMap& /*data*/) const {
+    return State::ShouldRun(program);
 }
 
-void RemoveContinueInSwitch::Run(CloneContext& ctx,
-                                 const DataMap&,
-                                 DataMap&) const {
-  State state(ctx);
-  state.Run();
+void RemoveContinueInSwitch::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
+    State state(ctx);
+    state.Run();
 }
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/remove_continue_in_switch.h b/src/tint/transform/remove_continue_in_switch.h
index f875660..e706225 100644
--- a/src/tint/transform/remove_continue_in_switch.h
+++ b/src/tint/transform/remove_continue_in_switch.h
@@ -23,31 +23,27 @@
 /// bool variable, and checking if the variable is set after the switch to
 /// continue. It is necessary to work around FXC "error X3708: continue cannot
 /// be used in a switch". See crbug.com/tint/1080.
-class RemoveContinueInSwitch
-    : public Castable<RemoveContinueInSwitch, Transform> {
- public:
-  /// Constructor
-  RemoveContinueInSwitch();
+class RemoveContinueInSwitch : public Castable<RemoveContinueInSwitch, Transform> {
+  public:
+    /// Constructor
+    RemoveContinueInSwitch();
 
-  /// Destructor
-  ~RemoveContinueInSwitch() override;
+    /// Destructor
+    ~RemoveContinueInSwitch() override;
 
- protected:
-  /// @param program the program to inspect
-  /// @param data optional extra transform-specific input data
-  /// @returns true if this transform should be run for the given program
-  bool ShouldRun(const Program* program,
-                 const DataMap& data = {}) const override;
+  protected:
+    /// @param program the program to inspect
+    /// @param data optional extra transform-specific input data
+    /// @returns true if this transform should be run for the given program
+    bool ShouldRun(const Program* program, const DataMap& data = {}) const override;
 
-  /// Runs the transform using the CloneContext built for transforming a
-  /// program. Run() is responsible for calling Clone() on the CloneContext.
-  /// @param ctx the CloneContext primed with the input program and
-  /// ProgramBuilder
-  /// @param inputs optional extra transform-specific input data
-  /// @param outputs optional extra transform-specific output data
-  void Run(CloneContext& ctx,
-           const DataMap& inputs,
-           DataMap& outputs) const override;
+    /// Runs the transform using the CloneContext built for transforming a
+    /// program. Run() is responsible for calling Clone() on the CloneContext.
+    /// @param ctx the CloneContext primed with the input program and
+    /// ProgramBuilder
+    /// @param inputs optional extra transform-specific input data
+    /// @param outputs optional extra transform-specific output data
+    void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const override;
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/remove_continue_in_switch_test.cc b/src/tint/transform/remove_continue_in_switch_test.cc
index 70f167d..a1e7b6e 100644
--- a/src/tint/transform/remove_continue_in_switch_test.cc
+++ b/src/tint/transform/remove_continue_in_switch_test.cc
@@ -21,7 +21,7 @@
 using RemoveContinueInSwitchTest = TransformTest;
 
 TEST_F(RemoveContinueInSwitchTest, ShouldRun_True) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var i = 0;
   loop {
@@ -39,17 +39,17 @@
 }
 )";
 
-  EXPECT_TRUE(ShouldRun<RemoveContinueInSwitch>(src));
+    EXPECT_TRUE(ShouldRun<RemoveContinueInSwitch>(src));
 }
 
 TEST_F(RemoveContinueInSwitchTest, ShouldRunEmptyModule_False) {
-  auto* src = "";
+    auto* src = "";
 
-  EXPECT_FALSE(ShouldRun<RemoveContinueInSwitch>(src));
+    EXPECT_FALSE(ShouldRun<RemoveContinueInSwitch>(src));
 }
 
 TEST_F(RemoveContinueInSwitchTest, ShouldRunContinueNotInSwitch_False) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var i = 0;
   loop {
@@ -70,11 +70,11 @@
 }
 )";
 
-  EXPECT_FALSE(ShouldRun<RemoveContinueInSwitch>(src));
+    EXPECT_FALSE(ShouldRun<RemoveContinueInSwitch>(src));
 }
 
 TEST_F(RemoveContinueInSwitchTest, ShouldRunContinueInLoopInSwitch_False) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var i = 0;
   switch(i) {
@@ -94,21 +94,21 @@
 }
 )";
 
-  EXPECT_FALSE(ShouldRun<RemoveContinueInSwitch>(src));
+    EXPECT_FALSE(ShouldRun<RemoveContinueInSwitch>(src));
 }
 
 TEST_F(RemoveContinueInSwitchTest, EmptyModule) {
-  auto* src = "";
-  auto* expect = src;
+    auto* src = "";
+    auto* expect = src;
 
-  DataMap data;
-  auto got = Run<RemoveContinueInSwitch>(src, data);
+    DataMap data;
+    auto got = Run<RemoveContinueInSwitch>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RemoveContinueInSwitchTest, SingleContinue) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var i = 0;
   loop {
@@ -132,7 +132,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var i = 0;
   loop {
@@ -163,14 +163,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<RemoveContinueInSwitch>(src, data);
+    DataMap data;
+    auto got = Run<RemoveContinueInSwitch>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RemoveContinueInSwitchTest, MultipleContinues) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var i = 0;
   loop {
@@ -202,7 +202,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var i = 0;
   loop {
@@ -247,14 +247,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<RemoveContinueInSwitch>(src, data);
+    DataMap data;
+    auto got = Run<RemoveContinueInSwitch>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RemoveContinueInSwitchTest, MultipleSwitch) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var i = 0;
   loop {
@@ -287,7 +287,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var i = 0;
   loop {
@@ -332,14 +332,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<RemoveContinueInSwitch>(src, data);
+    DataMap data;
+    auto got = Run<RemoveContinueInSwitch>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RemoveContinueInSwitchTest, NestedLoopSwitch) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var i = 0;
   loop {
@@ -374,7 +374,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var i = 0;
   loop {
@@ -423,14 +423,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<RemoveContinueInSwitch>(src, data);
+    DataMap data;
+    auto got = Run<RemoveContinueInSwitch>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RemoveContinueInSwitchTest, ExtraScopes) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var i = 0;
   var a = true;
@@ -462,7 +462,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var i = 0;
   var a = true;
@@ -501,14 +501,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<RemoveContinueInSwitch>(src, data);
+    DataMap data;
+    auto got = Run<RemoveContinueInSwitch>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RemoveContinueInSwitchTest, ForLoop) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   for (var i = 0; i < 4; i = i + 1) {
     let marker1 = 0;
@@ -527,7 +527,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   for(var i = 0; (i < 4); i = (i + 1)) {
     let marker1 = 0;
@@ -553,10 +553,10 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<RemoveContinueInSwitch>(src, data);
+    DataMap data;
+    auto got = Run<RemoveContinueInSwitch>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 }  // namespace
diff --git a/src/tint/transform/remove_phonies.cc b/src/tint/transform/remove_phonies.cc
index 9904e34..dc5c092 100644
--- a/src/tint/transform/remove_phonies.cc
+++ b/src/tint/transform/remove_phonies.cc
@@ -34,31 +34,31 @@
 namespace {
 
 struct SinkSignature {
-  std::vector<const sem::Type*> types;
+    std::vector<const sem::Type*> types;
 
-  bool operator==(const SinkSignature& other) const {
-    if (types.size() != other.types.size()) {
-      return false;
+    bool operator==(const SinkSignature& other) const {
+        if (types.size() != other.types.size()) {
+            return false;
+        }
+        for (size_t i = 0; i < types.size(); i++) {
+            if (types[i] != other.types[i]) {
+                return false;
+            }
+        }
+        return true;
     }
-    for (size_t i = 0; i < types.size(); i++) {
-      if (types[i] != other.types[i]) {
-        return false;
-      }
-    }
-    return true;
-  }
 
-  struct Hasher {
-    /// @param sig the CallTargetSignature to hash
-    /// @return the hash value
-    std::size_t operator()(const SinkSignature& sig) const {
-      size_t hash = tint::utils::Hash(sig.types.size());
-      for (auto* ty : sig.types) {
-        tint::utils::HashCombine(&hash, ty);
-      }
-      return hash;
-    }
-  };
+    struct Hasher {
+        /// @param sig the CallTargetSignature to hash
+        /// @return the hash value
+        std::size_t operator()(const SinkSignature& sig) const {
+            size_t hash = tint::utils::Hash(sig.types.size());
+            for (auto* ty : sig.types) {
+                tint::utils::HashCombine(&hash, ty);
+            }
+            return hash;
+        }
+    };
 };
 
 }  // namespace
@@ -68,87 +68,83 @@
 RemovePhonies::~RemovePhonies() = default;
 
 bool RemovePhonies::ShouldRun(const Program* program, const DataMap&) const {
-  for (auto* node : program->ASTNodes().Objects()) {
-    if (node->Is<ast::PhonyExpression>()) {
-      return true;
+    for (auto* node : program->ASTNodes().Objects()) {
+        if (node->Is<ast::PhonyExpression>()) {
+            return true;
+        }
     }
-  }
-  return false;
+    return false;
 }
 
 void RemovePhonies::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
-  auto& sem = ctx.src->Sem();
+    auto& sem = ctx.src->Sem();
 
-  std::unordered_map<SinkSignature, Symbol, SinkSignature::Hasher> sinks;
+    std::unordered_map<SinkSignature, Symbol, SinkSignature::Hasher> sinks;
 
-  for (auto* node : ctx.src->ASTNodes().Objects()) {
-    if (auto* stmt = node->As<ast::AssignmentStatement>()) {
-      if (stmt->lhs->Is<ast::PhonyExpression>()) {
-        std::vector<const ast::Expression*> side_effects;
-        if (!ast::TraverseExpressions(
-                stmt->rhs, ctx.dst->Diagnostics(),
-                [&](const ast::CallExpression* call) {
-                  // ast::CallExpression may map to a function or builtin call
-                  // (both may have side-effects), or a type constructor or
-                  // type conversion (both do not have side effects).
-                  if (sem.Get(call)
-                          ->Target()
-                          ->IsAnyOf<sem::Function, sem::Builtin>()) {
-                    side_effects.push_back(call);
-                    return ast::TraverseAction::Skip;
-                  }
-                  return ast::TraverseAction::Descend;
-                })) {
-          return;
-        }
+    for (auto* node : ctx.src->ASTNodes().Objects()) {
+        if (auto* stmt = node->As<ast::AssignmentStatement>()) {
+            if (stmt->lhs->Is<ast::PhonyExpression>()) {
+                std::vector<const ast::Expression*> side_effects;
+                if (!ast::TraverseExpressions(
+                        stmt->rhs, ctx.dst->Diagnostics(), [&](const ast::CallExpression* call) {
+                            // ast::CallExpression may map to a function or builtin call
+                            // (both may have side-effects), or a type constructor or
+                            // type conversion (both do not have side effects).
+                            if (sem.Get(call)->Target()->IsAnyOf<sem::Function, sem::Builtin>()) {
+                                side_effects.push_back(call);
+                                return ast::TraverseAction::Skip;
+                            }
+                            return ast::TraverseAction::Descend;
+                        })) {
+                    return;
+                }
 
-        if (side_effects.empty()) {
-          // Phony assignment with no side effects.
-          // Just remove it.
-          RemoveStatement(ctx, stmt);
-          continue;
-        }
+                if (side_effects.empty()) {
+                    // Phony assignment with no side effects.
+                    // Just remove it.
+                    RemoveStatement(ctx, stmt);
+                    continue;
+                }
 
-        if (side_effects.size() == 1) {
-          if (auto* call = side_effects[0]->As<ast::CallExpression>()) {
-            // Phony assignment with single call side effect.
-            // Replace phony assignment with call.
-            ctx.Replace(
-                stmt, [&, call] { return ctx.dst->CallStmt(ctx.Clone(call)); });
-            continue;
-          }
-        }
+                if (side_effects.size() == 1) {
+                    if (auto* call = side_effects[0]->As<ast::CallExpression>()) {
+                        // Phony assignment with single call side effect.
+                        // Replace phony assignment with call.
+                        ctx.Replace(stmt, [&, call] { return ctx.dst->CallStmt(ctx.Clone(call)); });
+                        continue;
+                    }
+                }
 
-        // Phony assignment with multiple side effects.
-        // Generate a call to a placeholder function with the side
-        // effects as arguments.
-        ctx.Replace(stmt, [&, side_effects] {
-          SinkSignature sig;
-          for (auto* arg : side_effects) {
-            sig.types.push_back(sem.Get(arg)->Type()->UnwrapRef());
-          }
-          auto sink = utils::GetOrCreate(sinks, sig, [&] {
-            auto name = ctx.dst->Symbols().New("phony_sink");
-            ast::VariableList params;
-            for (auto* ty : sig.types) {
-              auto* ast_ty = CreateASTTypeFor(ctx, ty);
-              params.push_back(
-                  ctx.dst->Param("p" + std::to_string(params.size()), ast_ty));
+                // Phony assignment with multiple side effects.
+                // Generate a call to a placeholder function with the side
+                // effects as arguments.
+                ctx.Replace(stmt, [&, side_effects] {
+                    SinkSignature sig;
+                    for (auto* arg : side_effects) {
+                        sig.types.push_back(sem.Get(arg)->Type()->UnwrapRef());
+                    }
+                    auto sink = utils::GetOrCreate(sinks, sig, [&] {
+                        auto name = ctx.dst->Symbols().New("phony_sink");
+                        ast::VariableList params;
+                        for (auto* ty : sig.types) {
+                            auto* ast_ty = CreateASTTypeFor(ctx, ty);
+                            params.push_back(
+                                ctx.dst->Param("p" + std::to_string(params.size()), ast_ty));
+                        }
+                        ctx.dst->Func(name, params, ctx.dst->ty.void_(), {});
+                        return name;
+                    });
+                    ast::ExpressionList args;
+                    for (auto* arg : side_effects) {
+                        args.push_back(ctx.Clone(arg));
+                    }
+                    return ctx.dst->CallStmt(ctx.dst->Call(sink, args));
+                });
             }
-            ctx.dst->Func(name, params, ctx.dst->ty.void_(), {});
-            return name;
-          });
-          ast::ExpressionList args;
-          for (auto* arg : side_effects) {
-            args.push_back(ctx.Clone(arg));
-          }
-          return ctx.dst->CallStmt(ctx.dst->Call(sink, args));
-        });
-      }
+        }
     }
-  }
 
-  ctx.Clone();
+    ctx.Clone();
 }
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/remove_phonies.h b/src/tint/transform/remove_phonies.h
index 6e355f1..20128a0 100644
--- a/src/tint/transform/remove_phonies.h
+++ b/src/tint/transform/remove_phonies.h
@@ -26,29 +26,26 @@
 /// while preserving function call expressions in the RHS of the assignment that
 /// may have side-effects.
 class RemovePhonies : public Castable<RemovePhonies, Transform> {
- public:
-  /// Constructor
-  RemovePhonies();
+  public:
+    /// Constructor
+    RemovePhonies();
 
-  /// Destructor
-  ~RemovePhonies() override;
+    /// Destructor
+    ~RemovePhonies() override;
 
-  /// @param program the program to inspect
-  /// @param data optional extra transform-specific input data
-  /// @returns true if this transform should be run for the given program
-  bool ShouldRun(const Program* program,
-                 const DataMap& data = {}) const override;
+    /// @param program the program to inspect
+    /// @param data optional extra transform-specific input data
+    /// @returns true if this transform should be run for the given program
+    bool ShouldRun(const Program* program, const DataMap& data = {}) const override;
 
- protected:
-  /// Runs the transform using the CloneContext built for transforming a
-  /// program. Run() is responsible for calling Clone() on the CloneContext.
-  /// @param ctx the CloneContext primed with the input program and
-  /// ProgramBuilder
-  /// @param inputs optional extra transform-specific input data
-  /// @param outputs optional extra transform-specific output data
-  void Run(CloneContext& ctx,
-           const DataMap& inputs,
-           DataMap& outputs) const override;
+  protected:
+    /// Runs the transform using the CloneContext built for transforming a
+    /// program. Run() is responsible for calling Clone() on the CloneContext.
+    /// @param ctx the CloneContext primed with the input program and
+    /// ProgramBuilder
+    /// @param inputs optional extra transform-specific input data
+    /// @param outputs optional extra transform-specific output data
+    void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const override;
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/remove_phonies_test.cc b/src/tint/transform/remove_phonies_test.cc
index e6faa3e..220f1db 100644
--- a/src/tint/transform/remove_phonies_test.cc
+++ b/src/tint/transform/remove_phonies_test.cc
@@ -26,32 +26,32 @@
 using RemovePhoniesTest = TransformTest;
 
 TEST_F(RemovePhoniesTest, ShouldRunEmptyModule) {
-  auto* src = R"()";
+    auto* src = R"()";
 
-  EXPECT_FALSE(ShouldRun<RemovePhonies>(src));
+    EXPECT_FALSE(ShouldRun<RemovePhonies>(src));
 }
 
 TEST_F(RemovePhoniesTest, ShouldRunHasPhony) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   _ = 1;
 }
 )";
 
-  EXPECT_TRUE(ShouldRun<RemovePhonies>(src));
+    EXPECT_TRUE(ShouldRun<RemovePhonies>(src));
 }
 
 TEST_F(RemovePhoniesTest, EmptyModule) {
-  auto* src = "";
-  auto* expect = "";
+    auto* src = "";
+    auto* expect = "";
 
-  auto got = Run<RemovePhonies>(src);
+    auto got = Run<RemovePhonies>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RemovePhoniesTest, NoSideEffects) {
-  auto* src = R"(
+    auto* src = R"(
 @group(0) @binding(0) var t : texture_2d<f32>;
 
 fn f() {
@@ -68,7 +68,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @group(0) @binding(0) var t : texture_2d<f32>;
 
 fn f() {
@@ -76,13 +76,13 @@
 }
 )";
 
-  auto got = Run<RemovePhonies>(src);
+    auto got = Run<RemovePhonies>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RemovePhoniesTest, SingleSideEffects) {
-  auto* src = R"(
+    auto* src = R"(
 fn neg(a : i32) -> i32 {
   return -(a);
 }
@@ -103,7 +103,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn neg(a : i32) -> i32 {
   return -(a);
 }
@@ -124,13 +124,13 @@
 }
 )";
 
-  auto got = Run<RemovePhonies>(src);
+    auto got = Run<RemovePhonies>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RemovePhoniesTest, SingleSideEffects_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   _ = neg(1);
   _ = add(2, 3);
@@ -151,7 +151,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   neg(1);
   add(2, 3);
@@ -172,13 +172,13 @@
 }
 )";
 
-  auto got = Run<RemovePhonies>(src);
+    auto got = Run<RemovePhonies>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RemovePhoniesTest, MultipleSideEffects) {
-  auto* src = R"(
+    auto* src = R"(
 fn neg(a : i32) -> i32 {
   return -(a);
 }
@@ -199,7 +199,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn neg(a : i32) -> i32 {
   return -(a);
 }
@@ -229,13 +229,13 @@
 }
 )";
 
-  auto got = Run<RemovePhonies>(src);
+    auto got = Run<RemovePhonies>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RemovePhoniesTest, MultipleSideEffects_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   _ = (1 + add(2 + add(3, 4), 5)) * add(6, 7) * neg(8);
   _ = add(9, neg(10)) + neg(11);
@@ -256,7 +256,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn phony_sink(p0 : i32, p1 : i32, p2 : i32) {
 }
 
@@ -286,13 +286,13 @@
 }
 )";
 
-  auto got = Run<RemovePhonies>(src);
+    auto got = Run<RemovePhonies>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RemovePhoniesTest, ForLoop) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   arr : array<i32>,
 };
@@ -321,7 +321,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   arr : array<i32>,
 }
@@ -353,13 +353,13 @@
 }
 )";
 
-  auto got = Run<RemovePhonies>(src);
+    auto got = Run<RemovePhonies>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RemovePhoniesTest, ForLoop_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   for (_ = &s.arr; ;_ = &s.arr) {
     break;
@@ -388,7 +388,7 @@
 @group(0) @binding(0) var<storage, read_write> s : S;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn phony_sink(p0 : i32, p1 : i32) {
 }
 
@@ -420,9 +420,9 @@
 @group(0) @binding(0) var<storage, read_write> s : S;
 )";
 
-  auto got = Run<RemovePhonies>(src);
+    auto got = Run<RemovePhonies>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 }  // namespace
diff --git a/src/tint/transform/remove_unreachable_statements.cc b/src/tint/transform/remove_unreachable_statements.cc
index 3e13ad7..964d767 100644
--- a/src/tint/transform/remove_unreachable_statements.cc
+++ b/src/tint/transform/remove_unreachable_statements.cc
@@ -36,30 +36,27 @@
 
 RemoveUnreachableStatements::~RemoveUnreachableStatements() = default;
 
-bool RemoveUnreachableStatements::ShouldRun(const Program* program,
-                                            const DataMap&) const {
-  for (auto* node : program->ASTNodes().Objects()) {
-    if (auto* stmt = program->Sem().Get<sem::Statement>(node)) {
-      if (!stmt->IsReachable()) {
-        return true;
-      }
+bool RemoveUnreachableStatements::ShouldRun(const Program* program, const DataMap&) const {
+    for (auto* node : program->ASTNodes().Objects()) {
+        if (auto* stmt = program->Sem().Get<sem::Statement>(node)) {
+            if (!stmt->IsReachable()) {
+                return true;
+            }
+        }
     }
-  }
-  return false;
+    return false;
 }
 
-void RemoveUnreachableStatements::Run(CloneContext& ctx,
-                                      const DataMap&,
-                                      DataMap&) const {
-  for (auto* node : ctx.src->ASTNodes().Objects()) {
-    if (auto* stmt = ctx.src->Sem().Get<sem::Statement>(node)) {
-      if (!stmt->IsReachable()) {
-        RemoveStatement(ctx, stmt->Declaration());
-      }
+void RemoveUnreachableStatements::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
+    for (auto* node : ctx.src->ASTNodes().Objects()) {
+        if (auto* stmt = ctx.src->Sem().Get<sem::Statement>(node)) {
+            if (!stmt->IsReachable()) {
+                RemoveStatement(ctx, stmt->Declaration());
+            }
+        }
     }
-  }
 
-  ctx.Clone();
+    ctx.Clone();
 }
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/remove_unreachable_statements.h b/src/tint/transform/remove_unreachable_statements.h
index a474efb..c75da3d 100644
--- a/src/tint/transform/remove_unreachable_statements.h
+++ b/src/tint/transform/remove_unreachable_statements.h
@@ -24,31 +24,27 @@
 
 /// RemoveUnreachableStatements is a Transform that removes all statements
 /// marked as unreachable.
-class RemoveUnreachableStatements
-    : public Castable<RemoveUnreachableStatements, Transform> {
- public:
-  /// Constructor
-  RemoveUnreachableStatements();
+class RemoveUnreachableStatements : public Castable<RemoveUnreachableStatements, Transform> {
+  public:
+    /// Constructor
+    RemoveUnreachableStatements();
 
-  /// Destructor
-  ~RemoveUnreachableStatements() override;
+    /// Destructor
+    ~RemoveUnreachableStatements() override;
 
-  /// @param program the program to inspect
-  /// @param data optional extra transform-specific input data
-  /// @returns true if this transform should be run for the given program
-  bool ShouldRun(const Program* program,
-                 const DataMap& data = {}) const override;
+    /// @param program the program to inspect
+    /// @param data optional extra transform-specific input data
+    /// @returns true if this transform should be run for the given program
+    bool ShouldRun(const Program* program, const DataMap& data = {}) const override;
 
- protected:
-  /// Runs the transform using the CloneContext built for transforming a
-  /// program. Run() is responsible for calling Clone() on the CloneContext.
-  /// @param ctx the CloneContext primed with the input program and
-  /// ProgramBuilder
-  /// @param inputs optional extra transform-specific input data
-  /// @param outputs optional extra transform-specific output data
-  void Run(CloneContext& ctx,
-           const DataMap& inputs,
-           DataMap& outputs) const override;
+  protected:
+    /// Runs the transform using the CloneContext built for transforming a
+    /// program. Run() is responsible for calling Clone() on the CloneContext.
+    /// @param ctx the CloneContext primed with the input program and
+    /// ProgramBuilder
+    /// @param inputs optional extra transform-specific input data
+    /// @param outputs optional extra transform-specific output data
+    void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const override;
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/remove_unreachable_statements_test.cc b/src/tint/transform/remove_unreachable_statements_test.cc
index 43c1950..4b0a265 100644
--- a/src/tint/transform/remove_unreachable_statements_test.cc
+++ b/src/tint/transform/remove_unreachable_statements_test.cc
@@ -22,13 +22,13 @@
 using RemoveUnreachableStatementsTest = TransformTest;
 
 TEST_F(RemoveUnreachableStatementsTest, ShouldRunEmptyModule) {
-  auto* src = R"()";
+    auto* src = R"()";
 
-  EXPECT_FALSE(ShouldRun<RemoveUnreachableStatements>(src));
+    EXPECT_FALSE(ShouldRun<RemoveUnreachableStatements>(src));
 }
 
 TEST_F(RemoveUnreachableStatementsTest, ShouldRunHasNoUnreachable) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   if (true) {
     var x = 1;
@@ -36,11 +36,11 @@
 }
 )";
 
-  EXPECT_FALSE(ShouldRun<RemoveUnreachableStatements>(src));
+    EXPECT_FALSE(ShouldRun<RemoveUnreachableStatements>(src));
 }
 
 TEST_F(RemoveUnreachableStatementsTest, ShouldRunHasUnreachable) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   return;
   if (true) {
@@ -49,20 +49,20 @@
 }
 )";
 
-  EXPECT_TRUE(ShouldRun<RemoveUnreachableStatements>(src));
+    EXPECT_TRUE(ShouldRun<RemoveUnreachableStatements>(src));
 }
 
 TEST_F(RemoveUnreachableStatementsTest, EmptyModule) {
-  auto* src = "";
-  auto* expect = "";
+    auto* src = "";
+    auto* expect = "";
 
-  auto got = Run<RemoveUnreachableStatements>(src);
+    auto got = Run<RemoveUnreachableStatements>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RemoveUnreachableStatementsTest, Return) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   return;
   var remove_me = 1;
@@ -72,19 +72,19 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   return;
 }
 )";
 
-  auto got = Run<RemoveUnreachableStatements>(src);
+    auto got = Run<RemoveUnreachableStatements>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RemoveUnreachableStatementsTest, NestedReturn) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   {
     {
@@ -98,7 +98,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   {
     {
@@ -108,13 +108,13 @@
 }
 )";
 
-  auto got = Run<RemoveUnreachableStatements>(src);
+    auto got = Run<RemoveUnreachableStatements>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RemoveUnreachableStatementsTest, Discard) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   discard;
   var remove_me = 1;
@@ -124,19 +124,19 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   discard;
 }
 )";
 
-  auto got = Run<RemoveUnreachableStatements>(src);
+    auto got = Run<RemoveUnreachableStatements>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RemoveUnreachableStatementsTest, NestedDiscard) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   {
     {
@@ -150,7 +150,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   {
     {
@@ -160,13 +160,13 @@
 }
 )";
 
-  auto got = Run<RemoveUnreachableStatements>(src);
+    auto got = Run<RemoveUnreachableStatements>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RemoveUnreachableStatementsTest, CallToFuncWithDiscard) {
-  auto* src = R"(
+    auto* src = R"(
 fn DISCARD() {
   discard;
 }
@@ -180,7 +180,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn DISCARD() {
   discard;
 }
@@ -190,13 +190,13 @@
 }
 )";
 
-  auto got = Run<RemoveUnreachableStatements>(src);
+    auto got = Run<RemoveUnreachableStatements>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RemoveUnreachableStatementsTest, CallToFuncWithIfDiscard) {
-  auto* src = R"(
+    auto* src = R"(
 fn DISCARD() {
   if (true) {
     discard;
@@ -212,15 +212,15 @@
 }
 )";
 
-  auto* expect = src;
+    auto* expect = src;
 
-  auto got = Run<RemoveUnreachableStatements>(src);
+    auto got = Run<RemoveUnreachableStatements>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RemoveUnreachableStatementsTest, IfDiscardElseDiscard) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   if (true) {
     discard;
@@ -234,7 +234,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   if (true) {
     discard;
@@ -244,13 +244,13 @@
 }
 )";
 
-  auto got = Run<RemoveUnreachableStatements>(src);
+    auto got = Run<RemoveUnreachableStatements>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RemoveUnreachableStatementsTest, IfDiscardElseReturn) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   if (true) {
     discard;
@@ -264,7 +264,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   if (true) {
     discard;
@@ -274,13 +274,13 @@
 }
 )";
 
-  auto got = Run<RemoveUnreachableStatements>(src);
+    auto got = Run<RemoveUnreachableStatements>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RemoveUnreachableStatementsTest, IfDiscard) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   if (true) {
     discard;
@@ -292,15 +292,15 @@
 }
 )";
 
-  auto* expect = src;
+    auto* expect = src;
 
-  auto got = Run<RemoveUnreachableStatements>(src);
+    auto got = Run<RemoveUnreachableStatements>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RemoveUnreachableStatementsTest, IfReturn) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   if (true) {
     return;
@@ -312,15 +312,15 @@
 }
 )";
 
-  auto* expect = src;
+    auto* expect = src;
 
-  auto got = Run<RemoveUnreachableStatements>(src);
+    auto got = Run<RemoveUnreachableStatements>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RemoveUnreachableStatementsTest, IfElseDiscard) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   if (true) {
   } else {
@@ -333,15 +333,15 @@
 }
 )";
 
-  auto* expect = src;
+    auto* expect = src;
 
-  auto got = Run<RemoveUnreachableStatements>(src);
+    auto got = Run<RemoveUnreachableStatements>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RemoveUnreachableStatementsTest, IfElseReturn) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   if (true) {
   } else {
@@ -354,15 +354,15 @@
 }
 )";
 
-  auto* expect = src;
+    auto* expect = src;
 
-  auto got = Run<RemoveUnreachableStatements>(src);
+    auto got = Run<RemoveUnreachableStatements>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RemoveUnreachableStatementsTest, LoopWithDiscard) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   loop {
     var a = 1;
@@ -379,7 +379,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   loop {
     var a = 1;
@@ -392,13 +392,13 @@
 }
 )";
 
-  auto got = Run<RemoveUnreachableStatements>(src);
+    auto got = Run<RemoveUnreachableStatements>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RemoveUnreachableStatementsTest, LoopWithConditionalBreak) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   loop {
     var a = 1;
@@ -417,15 +417,15 @@
 }
 )";
 
-  auto* expect = src;
+    auto* expect = src;
 
-  auto got = Run<RemoveUnreachableStatements>(src);
+    auto got = Run<RemoveUnreachableStatements>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RemoveUnreachableStatementsTest, LoopWithConditionalBreakInContinuing) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   loop {
 
@@ -442,15 +442,15 @@
 }
 )";
 
-  auto* expect = src;
+    auto* expect = src;
 
-  auto got = Run<RemoveUnreachableStatements>(src);
+    auto got = Run<RemoveUnreachableStatements>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RemoveUnreachableStatementsTest, SwitchDefaultDiscard) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   switch(1) {
     default: {
@@ -464,7 +464,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   switch(1) {
     default: {
@@ -474,13 +474,13 @@
 }
 )";
 
-  auto got = Run<RemoveUnreachableStatements>(src);
+    auto got = Run<RemoveUnreachableStatements>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RemoveUnreachableStatementsTest, SwitchCaseReturnDefaultDiscard) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   switch(1) {
     case 0: {
@@ -497,7 +497,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   switch(1) {
     case 0: {
@@ -510,13 +510,13 @@
 }
 )";
 
-  auto got = Run<RemoveUnreachableStatements>(src);
+    auto got = Run<RemoveUnreachableStatements>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RemoveUnreachableStatementsTest, SwitchCaseBreakDefaultDiscard) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   switch(1) {
     case 0: {
@@ -533,15 +533,15 @@
 }
 )";
 
-  auto* expect = src;
+    auto* expect = src;
 
-  auto got = Run<RemoveUnreachableStatements>(src);
+    auto got = Run<RemoveUnreachableStatements>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RemoveUnreachableStatementsTest, SwitchCaseReturnDefaultBreak) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   switch(1) {
     case 0: {
@@ -558,11 +558,11 @@
 }
 )";
 
-  auto* expect = src;
+    auto* expect = src;
 
-  auto got = Run<RemoveUnreachableStatements>(src);
+    auto got = Run<RemoveUnreachableStatements>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 }  // namespace
diff --git a/src/tint/transform/renamer.cc b/src/tint/transform/renamer.cc
index 9627911..50cd781 100644
--- a/src/tint/transform/renamer.cc
+++ b/src/tint/transform/renamer.cc
@@ -1253,114 +1253,107 @@
 Renamer::~Renamer() = default;
 
 Output Renamer::Run(const Program* in, const DataMap& inputs) const {
-  ProgramBuilder out;
-  // Disable auto-cloning of symbols, since we want to rename them.
-  CloneContext ctx(&out, in, false);
+    ProgramBuilder out;
+    // Disable auto-cloning of symbols, since we want to rename them.
+    CloneContext ctx(&out, in, false);
 
-  // Swizzles, builtin calls and builtin structure members need to keep their
-  // symbols preserved.
-  std::unordered_set<const ast::IdentifierExpression*> preserve;
-  for (auto* node : in->ASTNodes().Objects()) {
-    if (auto* member = node->As<ast::MemberAccessorExpression>()) {
-      auto* sem = in->Sem().Get(member);
-      if (!sem) {
-        TINT_ICE(Transform, out.Diagnostics())
-            << "MemberAccessorExpression has no semantic info";
-        continue;
-      }
-      if (sem->Is<sem::Swizzle>()) {
-        preserve.emplace(member->member);
-      } else if (auto* str_expr = in->Sem().Get(member->structure)) {
-        if (auto* ty = str_expr->Type()->UnwrapRef()->As<sem::Struct>()) {
-          if (ty->Declaration() == nullptr) {  // Builtin structure
-            preserve.emplace(member->member);
-          }
+    // Swizzles, builtin calls and builtin structure members need to keep their
+    // symbols preserved.
+    std::unordered_set<const ast::IdentifierExpression*> preserve;
+    for (auto* node : in->ASTNodes().Objects()) {
+        if (auto* member = node->As<ast::MemberAccessorExpression>()) {
+            auto* sem = in->Sem().Get(member);
+            if (!sem) {
+                TINT_ICE(Transform, out.Diagnostics())
+                    << "MemberAccessorExpression has no semantic info";
+                continue;
+            }
+            if (sem->Is<sem::Swizzle>()) {
+                preserve.emplace(member->member);
+            } else if (auto* str_expr = in->Sem().Get(member->structure)) {
+                if (auto* ty = str_expr->Type()->UnwrapRef()->As<sem::Struct>()) {
+                    if (ty->Declaration() == nullptr) {  // Builtin structure
+                        preserve.emplace(member->member);
+                    }
+                }
+            }
+        } else if (auto* call = node->As<ast::CallExpression>()) {
+            auto* sem = in->Sem().Get(call);
+            if (!sem) {
+                TINT_ICE(Transform, out.Diagnostics()) << "CallExpression has no semantic info";
+                continue;
+            }
+            if (sem->Target()->Is<sem::Builtin>()) {
+                preserve.emplace(call->target.name);
+            }
         }
-      }
-    } else if (auto* call = node->As<ast::CallExpression>()) {
-      auto* sem = in->Sem().Get(call);
-      if (!sem) {
-        TINT_ICE(Transform, out.Diagnostics())
-            << "CallExpression has no semantic info";
-        continue;
-      }
-      if (sem->Target()->Is<sem::Builtin>()) {
-        preserve.emplace(call->target.name);
-      }
-    }
-  }
-
-  Data::Remappings remappings;
-
-  Target target = Target::kAll;
-  bool preserve_unicode = false;
-
-  if (auto* cfg = inputs.Get<Config>()) {
-    target = cfg->target;
-    preserve_unicode = cfg->preserve_unicode;
-  }
-
-  ctx.ReplaceAll([&](Symbol sym_in) {
-    auto name_in = ctx.src->Symbols().NameFor(sym_in);
-    if (preserve_unicode || text::utf8::IsASCII(name_in)) {
-      switch (target) {
-        case Target::kAll:
-          // Always rename.
-          break;
-        case Target::kGlslKeywords:
-          if (!std::binary_search(
-                  kReservedKeywordsGLSL,
-                  kReservedKeywordsGLSL +
-                      sizeof(kReservedKeywordsGLSL) / sizeof(const char*),
-                  name_in) &&
-              name_in.compare(0, 3, "gl_")) {
-            // No match, just reuse the original name.
-            return ctx.dst->Symbols().New(name_in);
-          }
-          break;
-        case Target::kHlslKeywords:
-          if (!std::binary_search(
-                  kReservedKeywordsHLSL,
-                  kReservedKeywordsHLSL +
-                      sizeof(kReservedKeywordsHLSL) / sizeof(const char*),
-                  name_in)) {
-            // No match, just reuse the original name.
-            return ctx.dst->Symbols().New(name_in);
-          }
-          break;
-        case Target::kMslKeywords:
-          if (!std::binary_search(
-                  kReservedKeywordsMSL,
-                  kReservedKeywordsMSL +
-                      sizeof(kReservedKeywordsMSL) / sizeof(const char*),
-                  name_in)) {
-            // No match, just reuse the original name.
-            return ctx.dst->Symbols().New(name_in);
-          }
-          break;
-      }
     }
 
-    auto sym_out = ctx.dst->Sym();
-    remappings.emplace(name_in, ctx.dst->Symbols().NameFor(sym_out));
-    return sym_out;
-  });
+    Data::Remappings remappings;
 
-  ctx.ReplaceAll([&](const ast::IdentifierExpression* ident)
-                     -> const ast::IdentifierExpression* {
-    if (preserve.count(ident)) {
-      auto sym_in = ident->symbol;
-      auto str = in->Symbols().NameFor(sym_in);
-      auto sym_out = out.Symbols().Register(str);
-      return ctx.dst->create<ast::IdentifierExpression>(
-          ctx.Clone(ident->source), sym_out);
+    Target target = Target::kAll;
+    bool preserve_unicode = false;
+
+    if (auto* cfg = inputs.Get<Config>()) {
+        target = cfg->target;
+        preserve_unicode = cfg->preserve_unicode;
     }
-    return nullptr;  // Clone ident. Uses the symbol remapping above.
-  });
-  ctx.Clone();
 
-  return Output(Program(std::move(out)),
-                std::make_unique<Data>(std::move(remappings)));
+    ctx.ReplaceAll([&](Symbol sym_in) {
+        auto name_in = ctx.src->Symbols().NameFor(sym_in);
+        if (preserve_unicode || text::utf8::IsASCII(name_in)) {
+            switch (target) {
+                case Target::kAll:
+                    // Always rename.
+                    break;
+                case Target::kGlslKeywords:
+                    if (!std::binary_search(kReservedKeywordsGLSL,
+                                            kReservedKeywordsGLSL +
+                                                sizeof(kReservedKeywordsGLSL) / sizeof(const char*),
+                                            name_in) &&
+                        name_in.compare(0, 3, "gl_")) {
+                        // No match, just reuse the original name.
+                        return ctx.dst->Symbols().New(name_in);
+                    }
+                    break;
+                case Target::kHlslKeywords:
+                    if (!std::binary_search(kReservedKeywordsHLSL,
+                                            kReservedKeywordsHLSL +
+                                                sizeof(kReservedKeywordsHLSL) / sizeof(const char*),
+                                            name_in)) {
+                        // No match, just reuse the original name.
+                        return ctx.dst->Symbols().New(name_in);
+                    }
+                    break;
+                case Target::kMslKeywords:
+                    if (!std::binary_search(kReservedKeywordsMSL,
+                                            kReservedKeywordsMSL +
+                                                sizeof(kReservedKeywordsMSL) / sizeof(const char*),
+                                            name_in)) {
+                        // No match, just reuse the original name.
+                        return ctx.dst->Symbols().New(name_in);
+                    }
+                    break;
+            }
+        }
+
+        auto sym_out = ctx.dst->Sym();
+        remappings.emplace(name_in, ctx.dst->Symbols().NameFor(sym_out));
+        return sym_out;
+    });
+
+    ctx.ReplaceAll([&](const ast::IdentifierExpression* ident) -> const ast::IdentifierExpression* {
+        if (preserve.count(ident)) {
+            auto sym_in = ident->symbol;
+            auto str = in->Symbols().NameFor(sym_in);
+            auto sym_out = out.Symbols().Register(str);
+            return ctx.dst->create<ast::IdentifierExpression>(ctx.Clone(ident->source), sym_out);
+        }
+        return nullptr;  // Clone ident. Uses the symbol remapping above.
+    });
+    ctx.Clone();
+
+    return Output(Program(std::move(out)), std::make_unique<Data>(std::move(remappings)));
 }
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/renamer.h b/src/tint/transform/renamer.h
index ad37b0c..354acda 100644
--- a/src/tint/transform/renamer.h
+++ b/src/tint/transform/renamer.h
@@ -24,72 +24,72 @@
 
 /// Renamer is a Transform that renames all the symbols in a program.
 class Renamer : public Castable<Renamer, Transform> {
- public:
-  /// Data is outputted by the Renamer transform.
-  /// Data holds information about shader usage and constant buffer offsets.
-  struct Data : public Castable<Data, transform::Data> {
-    /// Remappings is a map of old symbol name to new symbol name
-    using Remappings = std::unordered_map<std::string, std::string>;
+  public:
+    /// Data is outputted by the Renamer transform.
+    /// Data holds information about shader usage and constant buffer offsets.
+    struct Data : public Castable<Data, transform::Data> {
+        /// Remappings is a map of old symbol name to new symbol name
+        using Remappings = std::unordered_map<std::string, std::string>;
 
-    /// Constructor
-    /// @param remappings the symbol remappings
-    explicit Data(Remappings&& remappings);
+        /// Constructor
+        /// @param remappings the symbol remappings
+        explicit Data(Remappings&& remappings);
 
-    /// Copy constructor
-    Data(const Data&);
+        /// Copy constructor
+        Data(const Data&);
+
+        /// Destructor
+        ~Data() override;
+
+        /// A map of old symbol name to new symbol name
+        const Remappings remappings;
+    };
+
+    /// Target is an enumerator of rename targets that can be used
+    enum class Target {
+        /// Rename every symbol.
+        kAll,
+        /// Only rename symbols that are reserved keywords in GLSL.
+        kGlslKeywords,
+        /// Only rename symbols that are reserved keywords in HLSL.
+        kHlslKeywords,
+        /// Only rename symbols that are reserved keywords in MSL.
+        kMslKeywords,
+    };
+
+    /// Optional configuration options for the transform.
+    /// If omitted, then the renamer will use Target::kAll.
+    struct Config : public Castable<Config, transform::Data> {
+        /// Constructor
+        /// @param tgt the targets to rename
+        /// @param keep_unicode if false, symbols with non-ascii code-points are
+        /// renamed
+        explicit Config(Target tgt, bool keep_unicode = false);
+
+        /// Copy constructor
+        Config(const Config&);
+
+        /// Destructor
+        ~Config() override;
+
+        /// The targets to rename
+        Target const target = Target::kAll;
+
+        /// If false, symbols with non-ascii code-points are renamed.
+        bool preserve_unicode = false;
+    };
+
+    /// Constructor using a the configuration provided in the input Data
+    Renamer();
 
     /// Destructor
-    ~Data() override;
+    ~Renamer() override;
 
-    /// A map of old symbol name to new symbol name
-    const Remappings remappings;
-  };
-
-  /// Target is an enumerator of rename targets that can be used
-  enum class Target {
-    /// Rename every symbol.
-    kAll,
-    /// Only rename symbols that are reserved keywords in GLSL.
-    kGlslKeywords,
-    /// Only rename symbols that are reserved keywords in HLSL.
-    kHlslKeywords,
-    /// Only rename symbols that are reserved keywords in MSL.
-    kMslKeywords,
-  };
-
-  /// Optional configuration options for the transform.
-  /// If omitted, then the renamer will use Target::kAll.
-  struct Config : public Castable<Config, transform::Data> {
-    /// Constructor
-    /// @param tgt the targets to rename
-    /// @param keep_unicode if false, symbols with non-ascii code-points are
-    /// renamed
-    explicit Config(Target tgt, bool keep_unicode = false);
-
-    /// Copy constructor
-    Config(const Config&);
-
-    /// Destructor
-    ~Config() override;
-
-    /// The targets to rename
-    Target const target = Target::kAll;
-
-    /// If false, symbols with non-ascii code-points are renamed.
-    bool preserve_unicode = false;
-  };
-
-  /// Constructor using a the configuration provided in the input Data
-  Renamer();
-
-  /// Destructor
-  ~Renamer() override;
-
-  /// Runs the transform on `program`, returning the transformation result.
-  /// @param program the source program to transform
-  /// @param data optional extra transform-specific input data
-  /// @returns the transformation result
-  Output Run(const Program* program, const DataMap& data = {}) const override;
+    /// Runs the transform on `program`, returning the transformation result.
+    /// @param program the source program to transform
+    /// @param data optional extra transform-specific input data
+    /// @returns the transformation result
+    Output Run(const Program* program, const DataMap& data = {}) const override;
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/renamer_test.cc b/src/tint/transform/renamer_test.cc
index e3f9458..f56971e 100644
--- a/src/tint/transform/renamer_test.cc
+++ b/src/tint/transform/renamer_test.cc
@@ -32,20 +32,20 @@
 using RenamerTest = TransformTest;
 
 TEST_F(RenamerTest, EmptyModule) {
-  auto* src = "";
-  auto* expect = "";
+    auto* src = "";
+    auto* expect = "";
 
-  auto got = Run<Renamer>(src);
+    auto got = Run<Renamer>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 
-  auto* data = got.data.Get<Renamer::Data>();
+    auto* data = got.data.Get<Renamer::Data>();
 
-  ASSERT_EQ(data->remappings.size(), 0u);
+    ASSERT_EQ(data->remappings.size(), 0u);
 }
 
 TEST_F(RenamerTest, BasicModuleVertexIndex) {
-  auto* src = R"(
+    auto* src = R"(
 fn test(vert_idx : u32) -> u32 {
   return vert_idx;
 }
@@ -58,7 +58,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn tint_symbol(tint_symbol_1 : u32) -> u32 {
   return tint_symbol_1;
 }
@@ -70,23 +70,23 @@
 }
 )";
 
-  auto got = Run<Renamer>(src);
+    auto got = Run<Renamer>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 
-  auto* data = got.data.Get<Renamer::Data>();
+    auto* data = got.data.Get<Renamer::Data>();
 
-  ASSERT_NE(data, nullptr);
-  Renamer::Data::Remappings expected_remappings = {
-      {"vert_idx", "tint_symbol_1"},
-      {"test", "tint_symbol"},
-      {"entry", "tint_symbol_2"},
-  };
-  EXPECT_THAT(data->remappings, ContainerEq(expected_remappings));
+    ASSERT_NE(data, nullptr);
+    Renamer::Data::Remappings expected_remappings = {
+        {"vert_idx", "tint_symbol_1"},
+        {"test", "tint_symbol"},
+        {"entry", "tint_symbol_2"},
+    };
+    EXPECT_THAT(data->remappings, ContainerEq(expected_remappings));
 }
 
 TEST_F(RenamerTest, PreserveSwizzles) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(vertex)
 fn entry() -> @builtin(position) vec4<f32> {
   var v : vec4<f32>;
@@ -96,7 +96,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @stage(vertex)
 fn tint_symbol() -> @builtin(position) vec4<f32> {
   var tint_symbol_1 : vec4<f32>;
@@ -106,24 +106,24 @@
 }
 )";
 
-  auto got = Run<Renamer>(src);
+    auto got = Run<Renamer>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 
-  auto* data = got.data.Get<Renamer::Data>();
+    auto* data = got.data.Get<Renamer::Data>();
 
-  ASSERT_NE(data, nullptr);
-  Renamer::Data::Remappings expected_remappings = {
-      {"entry", "tint_symbol"},
-      {"v", "tint_symbol_1"},
-      {"rgba", "tint_symbol_2"},
-      {"xyzw", "tint_symbol_3"},
-  };
-  EXPECT_THAT(data->remappings, ContainerEq(expected_remappings));
+    ASSERT_NE(data, nullptr);
+    Renamer::Data::Remappings expected_remappings = {
+        {"entry", "tint_symbol"},
+        {"v", "tint_symbol_1"},
+        {"rgba", "tint_symbol_2"},
+        {"xyzw", "tint_symbol_3"},
+    };
+    EXPECT_THAT(data->remappings, ContainerEq(expected_remappings));
 }
 
 TEST_F(RenamerTest, PreserveBuiltins) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(vertex)
 fn entry() -> @builtin(position) vec4<f32> {
   var blah : vec4<f32>;
@@ -131,7 +131,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @stage(vertex)
 fn tint_symbol() -> @builtin(position) vec4<f32> {
   var tint_symbol_1 : vec4<f32>;
@@ -139,22 +139,22 @@
 }
 )";
 
-  auto got = Run<Renamer>(src);
+    auto got = Run<Renamer>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 
-  auto* data = got.data.Get<Renamer::Data>();
+    auto* data = got.data.Get<Renamer::Data>();
 
-  ASSERT_NE(data, nullptr);
-  Renamer::Data::Remappings expected_remappings = {
-      {"entry", "tint_symbol"},
-      {"blah", "tint_symbol_1"},
-  };
-  EXPECT_THAT(data->remappings, ContainerEq(expected_remappings));
+    ASSERT_NE(data, nullptr);
+    Renamer::Data::Remappings expected_remappings = {
+        {"entry", "tint_symbol"},
+        {"blah", "tint_symbol_1"},
+    };
+    EXPECT_THAT(data->remappings, ContainerEq(expected_remappings));
 }
 
 TEST_F(RenamerTest, PreserveBuiltinTypes) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn entry() {
   var a = modf(1.0).whole;
@@ -164,7 +164,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @stage(compute) @workgroup_size(1)
 fn tint_symbol() {
   var tint_symbol_1 = modf(1.0).whole;
@@ -174,41 +174,41 @@
 }
 )";
 
-  auto got = Run<Renamer>(src);
+    auto got = Run<Renamer>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 
-  auto* data = got.data.Get<Renamer::Data>();
+    auto* data = got.data.Get<Renamer::Data>();
 
-  ASSERT_NE(data, nullptr);
-  Renamer::Data::Remappings expected_remappings = {
-      {"entry", "tint_symbol"}, {"a", "tint_symbol_1"}, {"b", "tint_symbol_2"},
-      {"c", "tint_symbol_3"},   {"d", "tint_symbol_4"},
-  };
-  EXPECT_THAT(data->remappings, ContainerEq(expected_remappings));
+    ASSERT_NE(data, nullptr);
+    Renamer::Data::Remappings expected_remappings = {
+        {"entry", "tint_symbol"}, {"a", "tint_symbol_1"}, {"b", "tint_symbol_2"},
+        {"c", "tint_symbol_3"},   {"d", "tint_symbol_4"},
+    };
+    EXPECT_THAT(data->remappings, ContainerEq(expected_remappings));
 }
 
 TEST_F(RenamerTest, PreserveUnicode) {
-  auto src = R"(
+    auto src = R"(
 @stage(fragment)
 fn frag_main() {
   var )" + std::string(kUnicodeIdentifier) +
-             R"( : i32;
+               R"( : i32;
 }
 )";
 
-  auto expect = src;
+    auto expect = src;
 
-  DataMap inputs;
-  inputs.Add<Renamer::Config>(Renamer::Target::kMslKeywords,
-                              /* preserve_unicode */ true);
-  auto got = Run<Renamer>(src, inputs);
+    DataMap inputs;
+    inputs.Add<Renamer::Config>(Renamer::Target::kMslKeywords,
+                                /* preserve_unicode */ true);
+    auto got = Run<Renamer>(src, inputs);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RenamerTest, AttemptSymbolCollision) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(vertex)
 fn entry() -> @builtin(position) vec4<f32> {
   var tint_symbol : vec4<f32>;
@@ -218,7 +218,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @stage(vertex)
 fn tint_symbol() -> @builtin(position) vec4<f32> {
   var tint_symbol_1 : vec4<f32>;
@@ -228,20 +228,20 @@
 }
 )";
 
-  auto got = Run<Renamer>(src);
+    auto got = Run<Renamer>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 
-  auto* data = got.data.Get<Renamer::Data>();
+    auto* data = got.data.Get<Renamer::Data>();
 
-  ASSERT_NE(data, nullptr);
-  Renamer::Data::Remappings expected_remappings = {
-      {"entry", "tint_symbol"},
-      {"tint_symbol", "tint_symbol_1"},
-      {"tint_symbol_2", "tint_symbol_2"},
-      {"tint_symbol_4", "tint_symbol_3"},
-  };
-  EXPECT_THAT(data->remappings, ContainerEq(expected_remappings));
+    ASSERT_NE(data, nullptr);
+    Renamer::Data::Remappings expected_remappings = {
+        {"entry", "tint_symbol"},
+        {"tint_symbol", "tint_symbol_1"},
+        {"tint_symbol_2", "tint_symbol_2"},
+        {"tint_symbol_4", "tint_symbol_3"},
+    };
+    EXPECT_THAT(data->remappings, ContainerEq(expected_remappings));
 }
 
 using RenamerTestGlsl = TransformTestWithParam<std::string>;
@@ -249,81 +249,81 @@
 using RenamerTestMsl = TransformTestWithParam<std::string>;
 
 TEST_P(RenamerTestGlsl, Keywords) {
-  auto keyword = GetParam();
+    auto keyword = GetParam();
 
-  auto src = R"(
+    auto src = R"(
 @stage(fragment)
 fn frag_main() {
   var )" + keyword +
-             R"( : i32;
+               R"( : i32;
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @stage(fragment)
 fn frag_main() {
   var tint_symbol : i32;
 }
 )";
 
-  DataMap inputs;
-  inputs.Add<Renamer::Config>(Renamer::Target::kGlslKeywords,
-                              /* preserve_unicode */ false);
-  auto got = Run<Renamer>(src, inputs);
+    DataMap inputs;
+    inputs.Add<Renamer::Config>(Renamer::Target::kGlslKeywords,
+                                /* preserve_unicode */ false);
+    auto got = Run<Renamer>(src, inputs);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_P(RenamerTestHlsl, Keywords) {
-  auto keyword = GetParam();
+    auto keyword = GetParam();
 
-  auto src = R"(
+    auto src = R"(
 @stage(fragment)
 fn frag_main() {
   var )" + keyword +
-             R"( : i32;
+               R"( : i32;
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @stage(fragment)
 fn frag_main() {
   var tint_symbol : i32;
 }
 )";
 
-  DataMap inputs;
-  inputs.Add<Renamer::Config>(Renamer::Target::kHlslKeywords,
-                              /* preserve_unicode */ false);
-  auto got = Run<Renamer>(src, inputs);
+    DataMap inputs;
+    inputs.Add<Renamer::Config>(Renamer::Target::kHlslKeywords,
+                                /* preserve_unicode */ false);
+    auto got = Run<Renamer>(src, inputs);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_P(RenamerTestMsl, Keywords) {
-  auto keyword = GetParam();
+    auto keyword = GetParam();
 
-  auto src = R"(
+    auto src = R"(
 @stage(fragment)
 fn frag_main() {
   var )" + keyword +
-             R"( : i32;
+               R"( : i32;
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @stage(fragment)
 fn frag_main() {
   var tint_symbol : i32;
 }
 )";
 
-  DataMap inputs;
-  inputs.Add<Renamer::Config>(Renamer::Target::kMslKeywords,
-                              /* preserve_unicode */ false);
-  auto got = Run<Renamer>(src, inputs);
+    DataMap inputs;
+    inputs.Add<Renamer::Config>(Renamer::Target::kMslKeywords,
+                                /* preserve_unicode */ false);
+    auto got = Run<Renamer>(src, inputs);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 INSTANTIATE_TEST_SUITE_P(RenamerTestGlsl,
diff --git a/src/tint/transform/robustness.cc b/src/tint/transform/robustness.cc
index 4a67d49..a7f2a4a 100644
--- a/src/tint/transform/robustness.cc
+++ b/src/tint/transform/robustness.cc
@@ -22,265 +22,258 @@
 #include "src/tint/sem/block_statement.h"
 #include "src/tint/sem/call.h"
 #include "src/tint/sem/expression.h"
-#include "src/tint/sem/reference_type.h"
+#include "src/tint/sem/reference.h"
 #include "src/tint/sem/statement.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::transform::Robustness);
 TINT_INSTANTIATE_TYPEINFO(tint::transform::Robustness::Config);
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::transform {
 
 /// State holds the current transform state
 struct Robustness::State {
-  /// The clone context
-  CloneContext& ctx;
+    /// The clone context
+    CloneContext& ctx;
 
-  /// Set of storage classes to not apply the transform to
-  std::unordered_set<ast::StorageClass> omitted_classes;
+    /// Set of storage classes to not apply the transform to
+    std::unordered_set<ast::StorageClass> omitted_classes;
 
-  /// Applies the transformation state to `ctx`.
-  void Transform() {
-    ctx.ReplaceAll([&](const ast::IndexAccessorExpression* expr) {
-      return Transform(expr);
-    });
-    ctx.ReplaceAll(
-        [&](const ast::CallExpression* expr) { return Transform(expr); });
-  }
-
-  /// Apply bounds clamping to array, vector and matrix indexing
-  /// @param expr the array, vector or matrix index expression
-  /// @return the clamped replacement expression, or nullptr if `expr` should be
-  /// cloned without changes.
-  const ast::IndexAccessorExpression* Transform(
-      const ast::IndexAccessorExpression* expr) {
-    auto* ret_type = ctx.src->Sem().Get(expr->object)->Type();
-
-    auto* ref = ret_type->As<sem::Reference>();
-    if (ref && omitted_classes.count(ref->StorageClass()) != 0) {
-      return nullptr;
+    /// Applies the transformation state to `ctx`.
+    void Transform() {
+        ctx.ReplaceAll([&](const ast::IndexAccessorExpression* expr) { return Transform(expr); });
+        ctx.ReplaceAll([&](const ast::CallExpression* expr) { return Transform(expr); });
     }
 
-    auto* ret_unwrapped = ret_type->UnwrapRef();
+    /// Apply bounds clamping to array, vector and matrix indexing
+    /// @param expr the array, vector or matrix index expression
+    /// @return the clamped replacement expression, or nullptr if `expr` should be
+    /// cloned without changes.
+    const ast::IndexAccessorExpression* Transform(const ast::IndexAccessorExpression* expr) {
+        auto* ret_type = ctx.src->Sem().Get(expr->object)->Type();
 
-    ProgramBuilder& b = *ctx.dst;
-    using u32 = ProgramBuilder::u32;
-
-    struct Value {
-      const ast::Expression* expr = nullptr;  // If null, then is a constant
-      union {
-        uint32_t u32 = 0;  // use if is_signed == false
-        int32_t i32;       // use if is_signed == true
-      };
-      bool is_signed = false;
-    };
-
-    Value size;              // size of the array, vector or matrix
-    size.is_signed = false;  // size is always unsigned
-    if (auto* vec = ret_unwrapped->As<sem::Vector>()) {
-      size.u32 = vec->Width();
-
-    } else if (auto* arr = ret_unwrapped->As<sem::Array>()) {
-      size.u32 = arr->Count();
-    } else if (auto* mat = ret_unwrapped->As<sem::Matrix>()) {
-      // The row accessor would have been an embedded index accessor and already
-      // handled, so we just need to do columns here.
-      size.u32 = mat->columns();
-    } else {
-      return nullptr;
-    }
-
-    if (size.u32 == 0) {
-      if (!ret_unwrapped->Is<sem::Array>()) {
-        b.Diagnostics().add_error(diag::System::Transform,
-                                  "invalid 0 sized non-array", expr->source);
-        return nullptr;
-      }
-      // Runtime sized array
-      auto* arr = ctx.Clone(expr->object);
-      size.expr = b.Call("arrayLength", b.AddressOf(arr));
-    }
-
-    // Calculate the maximum possible index value (size-1u)
-    // Size must be positive (non-zero), so we can safely subtract 1 here
-    // without underflow.
-    Value limit;
-    limit.is_signed = false;  // Like size, limit is always unsigned.
-    if (size.expr) {
-      // Dynamic size
-      limit.expr = b.Sub(size.expr, 1u);
-    } else {
-      // Constant size
-      limit.u32 = size.u32 - 1u;
-    }
-
-    Value idx;  // index value
-
-    auto* idx_sem = ctx.src->Sem().Get(expr->index);
-    auto* idx_ty = idx_sem->Type()->UnwrapRef();
-    if (!idx_ty->IsAnyOf<sem::I32, sem::U32>()) {
-      TINT_ICE(Transform, b.Diagnostics()) << "index must be u32 or i32, got "
-                                           << idx_sem->Type()->TypeInfo().name;
-      return nullptr;
-    }
-
-    if (auto idx_constant = idx_sem->ConstantValue()) {
-      // Constant value index
-      if (idx_constant.Type()->Is<sem::I32>()) {
-        idx.i32 = idx_constant.Elements()[0].i32;
-        idx.is_signed = true;
-      } else if (idx_constant.Type()->Is<sem::U32>()) {
-        idx.u32 = idx_constant.Elements()[0].u32;
-        idx.is_signed = false;
-      } else {
-        TINT_ICE(Transform, b.Diagnostics())
-            << "unsupported constant value for accessor "
-            << idx_constant.Type()->TypeInfo().name;
-        return nullptr;
-      }
-    } else {
-      // Dynamic value index
-      idx.expr = ctx.Clone(expr->index);
-      idx.is_signed = idx_ty->Is<sem::I32>();
-    }
-
-    // Clamp the index so that it cannot exceed limit.
-    if (idx.expr || limit.expr) {
-      // One of, or both of idx and limit are non-constant.
-
-      // If the index is signed, cast it to a u32 (with clamping if constant).
-      if (idx.is_signed) {
-        if (idx.expr) {
-          // We don't use a max(idx, 0) here, as that incurs a runtime
-          // performance cost, and if the unsigned value will be clamped by
-          // limit, resulting in a value between [0..limit)
-          idx.expr = b.Construct<u32>(idx.expr);
-          idx.is_signed = false;
-        } else {
-          idx.u32 = static_cast<uint32_t>(std::max(idx.i32, 0));
-          idx.is_signed = false;
+        auto* ref = ret_type->As<sem::Reference>();
+        if (ref && omitted_classes.count(ref->StorageClass()) != 0) {
+            return nullptr;
         }
-      }
 
-      // Convert idx and limit to expressions, so we can emit `min(idx, limit)`.
-      if (!idx.expr) {
-        idx.expr = b.Expr(idx.u32);
-      }
-      if (!limit.expr) {
-        limit.expr = b.Expr(limit.u32);
-      }
+        auto* ret_unwrapped = ret_type->UnwrapRef();
 
-      // Perform the clamp with `min(idx, limit)`
-      idx.expr = b.Call("min", idx.expr, limit.expr);
-    } else {
-      // Both idx and max are constant.
-      if (idx.is_signed) {
-        // The index is signed. Calculate limit as signed.
-        int32_t signed_limit = static_cast<int32_t>(
-            std::min<uint32_t>(limit.u32, std::numeric_limits<int32_t>::max()));
-        idx.i32 = std::max(idx.i32, 0);
-        idx.i32 = std::min(idx.i32, signed_limit);
-      } else {
-        // The index is unsigned.
-        idx.u32 = std::min(idx.u32, limit.u32);
-      }
+        ProgramBuilder& b = *ctx.dst;
+
+        struct Value {
+            const ast::Expression* expr = nullptr;  // If null, then is a constant
+            union {
+                uint32_t u32 = 0;  // use if is_signed == false
+                int32_t i32;       // use if is_signed == true
+            };
+            bool is_signed = false;
+        };
+
+        Value size;              // size of the array, vector or matrix
+        size.is_signed = false;  // size is always unsigned
+        if (auto* vec = ret_unwrapped->As<sem::Vector>()) {
+            size.u32 = vec->Width();
+
+        } else if (auto* arr = ret_unwrapped->As<sem::Array>()) {
+            size.u32 = arr->Count();
+        } else if (auto* mat = ret_unwrapped->As<sem::Matrix>()) {
+            // The row accessor would have been an embedded index accessor and already
+            // handled, so we just need to do columns here.
+            size.u32 = mat->columns();
+        } else {
+            return nullptr;
+        }
+
+        if (size.u32 == 0) {
+            if (!ret_unwrapped->Is<sem::Array>()) {
+                b.Diagnostics().add_error(diag::System::Transform, "invalid 0 sized non-array",
+                                          expr->source);
+                return nullptr;
+            }
+            // Runtime sized array
+            auto* arr = ctx.Clone(expr->object);
+            size.expr = b.Call("arrayLength", b.AddressOf(arr));
+        }
+
+        // Calculate the maximum possible index value (size-1u)
+        // Size must be positive (non-zero), so we can safely subtract 1 here
+        // without underflow.
+        Value limit;
+        limit.is_signed = false;  // Like size, limit is always unsigned.
+        if (size.expr) {
+            // Dynamic size
+            limit.expr = b.Sub(size.expr, 1_u);
+        } else {
+            // Constant size
+            limit.u32 = size.u32 - 1u;
+        }
+
+        Value idx;  // index value
+
+        auto* idx_sem = ctx.src->Sem().Get(expr->index);
+        auto* idx_ty = idx_sem->Type()->UnwrapRef();
+        if (!idx_ty->IsAnyOf<sem::I32, sem::U32>()) {
+            TINT_ICE(Transform, b.Diagnostics())
+                << "index must be u32 or i32, got " << idx_sem->Type()->TypeInfo().name;
+            return nullptr;
+        }
+
+        if (auto idx_constant = idx_sem->ConstantValue()) {
+            // Constant value index
+            if (idx_constant.Type()->Is<sem::I32>()) {
+                idx.i32 = idx_constant.Elements()[0].i32;
+                idx.is_signed = true;
+            } else if (idx_constant.Type()->Is<sem::U32>()) {
+                idx.u32 = idx_constant.Elements()[0].u32;
+                idx.is_signed = false;
+            } else {
+                TINT_ICE(Transform, b.Diagnostics()) << "unsupported constant value for accessor "
+                                                     << idx_constant.Type()->TypeInfo().name;
+                return nullptr;
+            }
+        } else {
+            // Dynamic value index
+            idx.expr = ctx.Clone(expr->index);
+            idx.is_signed = idx_ty->Is<sem::I32>();
+        }
+
+        // Clamp the index so that it cannot exceed limit.
+        if (idx.expr || limit.expr) {
+            // One of, or both of idx and limit are non-constant.
+
+            // If the index is signed, cast it to a u32 (with clamping if constant).
+            if (idx.is_signed) {
+                if (idx.expr) {
+                    // We don't use a max(idx, 0) here, as that incurs a runtime
+                    // performance cost, and if the unsigned value will be clamped by
+                    // limit, resulting in a value between [0..limit)
+                    idx.expr = b.Construct<u32>(idx.expr);
+                    idx.is_signed = false;
+                } else {
+                    idx.u32 = static_cast<uint32_t>(std::max(idx.i32, 0));
+                    idx.is_signed = false;
+                }
+            }
+
+            // Convert idx and limit to expressions, so we can emit `min(idx, limit)`.
+            if (!idx.expr) {
+                idx.expr = b.Expr(u32(idx.u32));
+            }
+            if (!limit.expr) {
+                limit.expr = b.Expr(u32(limit.u32));
+            }
+
+            // Perform the clamp with `min(idx, limit)`
+            idx.expr = b.Call("min", idx.expr, limit.expr);
+        } else {
+            // Both idx and max are constant.
+            if (idx.is_signed) {
+                // The index is signed. Calculate limit as signed.
+                int32_t signed_limit = static_cast<int32_t>(
+                    std::min<uint32_t>(limit.u32, std::numeric_limits<int32_t>::max()));
+                idx.i32 = std::max(idx.i32, 0);
+                idx.i32 = std::min(idx.i32, signed_limit);
+            } else {
+                // The index is unsigned.
+                idx.u32 = std::min(idx.u32, limit.u32);
+            }
+        }
+
+        // Convert idx to an expression, so we can emit the new accessor.
+        if (!idx.expr) {
+            idx.expr = idx.is_signed ? static_cast<const ast::Expression*>(b.Expr(i32(idx.i32)))
+                                     : static_cast<const ast::Expression*>(b.Expr(u32(idx.u32)));
+        }
+
+        // Clone arguments outside of create() call to have deterministic ordering
+        auto src = ctx.Clone(expr->source);
+        auto* obj = ctx.Clone(expr->object);
+        return b.IndexAccessor(src, obj, idx.expr);
     }
 
-    // Convert idx to an expression, so we can emit the new accessor.
-    if (!idx.expr) {
-      idx.expr = idx.is_signed
-                     ? static_cast<const ast::Expression*>(b.Expr(idx.i32))
-                     : static_cast<const ast::Expression*>(b.Expr(idx.u32));
+    /// @param type builtin type
+    /// @returns true if the given builtin is a texture function that requires
+    /// argument clamping,
+    bool TextureBuiltinNeedsClamping(sem::BuiltinType type) {
+        return type == sem::BuiltinType::kTextureLoad || type == sem::BuiltinType::kTextureStore;
     }
 
-    // Clone arguments outside of create() call to have deterministic ordering
-    auto src = ctx.Clone(expr->source);
-    auto* obj = ctx.Clone(expr->object);
-    return b.IndexAccessor(src, obj, idx.expr);
-  }
+    /// Apply bounds clamping to the coordinates, array index and level arguments
+    /// of the `textureLoad()` and `textureStore()` builtins.
+    /// @param expr the builtin call expression
+    /// @return the clamped replacement call expression, or nullptr if `expr`
+    /// should be cloned without changes.
+    const ast::CallExpression* Transform(const ast::CallExpression* expr) {
+        auto* call = ctx.src->Sem().Get(expr);
+        auto* call_target = call->Target();
+        auto* builtin = call_target->As<sem::Builtin>();
+        if (!builtin || !TextureBuiltinNeedsClamping(builtin->Type())) {
+            return nullptr;  // No transform, just clone.
+        }
 
-  /// @param type builtin type
-  /// @returns true if the given builtin is a texture function that requires
-  /// argument clamping,
-  bool TextureBuiltinNeedsClamping(sem::BuiltinType type) {
-    return type == sem::BuiltinType::kTextureLoad ||
-           type == sem::BuiltinType::kTextureStore;
-  }
+        ProgramBuilder& b = *ctx.dst;
 
-  /// Apply bounds clamping to the coordinates, array index and level arguments
-  /// of the `textureLoad()` and `textureStore()` builtins.
-  /// @param expr the builtin call expression
-  /// @return the clamped replacement call expression, or nullptr if `expr`
-  /// should be cloned without changes.
-  const ast::CallExpression* Transform(const ast::CallExpression* expr) {
-    auto* call = ctx.src->Sem().Get(expr);
-    auto* call_target = call->Target();
-    auto* builtin = call_target->As<sem::Builtin>();
-    if (!builtin || !TextureBuiltinNeedsClamping(builtin->Type())) {
-      return nullptr;  // No transform, just clone.
+        // Indices of the mandatory texture and coords parameters, and the optional
+        // array and level parameters.
+        auto& signature = builtin->Signature();
+        auto texture_idx = signature.IndexOf(sem::ParameterUsage::kTexture);
+        auto coords_idx = signature.IndexOf(sem::ParameterUsage::kCoords);
+        auto array_idx = signature.IndexOf(sem::ParameterUsage::kArrayIndex);
+        auto level_idx = signature.IndexOf(sem::ParameterUsage::kLevel);
+
+        auto* texture_arg = expr->args[texture_idx];
+        auto* coords_arg = expr->args[coords_idx];
+        auto* coords_ty = builtin->Parameters()[coords_idx]->Type();
+
+        // If the level is provided, then we need to clamp this. As the level is
+        // used by textureDimensions() and the texture[Load|Store]() calls, we need
+        // to clamp both usages.
+        // TODO(bclayton): We probably want to place this into a let so that the
+        // calculation can be reused. This is fiddly to get right.
+        std::function<const ast::Expression*()> level_arg;
+        if (level_idx >= 0) {
+            level_arg = [&] {
+                auto* arg = expr->args[level_idx];
+                auto* num_levels = b.Call("textureNumLevels", ctx.Clone(texture_arg));
+                auto* zero = b.Expr(0_i);
+                auto* max = ctx.dst->Sub(num_levels, 1_i);
+                auto* clamped = b.Call("clamp", ctx.Clone(arg), zero, max);
+                return clamped;
+            };
+        }
+
+        // Clamp the coordinates argument
+        {
+            auto* texture_dims =
+                level_arg ? b.Call("textureDimensions", ctx.Clone(texture_arg), level_arg())
+                          : b.Call("textureDimensions", ctx.Clone(texture_arg));
+            auto* zero = b.Construct(CreateASTTypeFor(ctx, coords_ty));
+            auto* max =
+                ctx.dst->Sub(texture_dims, b.Construct(CreateASTTypeFor(ctx, coords_ty), 1_i));
+            auto* clamped_coords = b.Call("clamp", ctx.Clone(coords_arg), zero, max);
+            ctx.Replace(coords_arg, clamped_coords);
+        }
+
+        // Clamp the array_index argument, if provided
+        if (array_idx >= 0) {
+            auto* arg = expr->args[array_idx];
+            auto* num_layers = b.Call("textureNumLayers", ctx.Clone(texture_arg));
+            auto* zero = b.Expr(0_i);
+            auto* max = ctx.dst->Sub(num_layers, 1_i);
+            auto* clamped = b.Call("clamp", ctx.Clone(arg), zero, max);
+            ctx.Replace(arg, clamped);
+        }
+
+        // Clamp the level argument, if provided
+        if (level_idx >= 0) {
+            auto* arg = expr->args[level_idx];
+            ctx.Replace(arg, level_arg ? level_arg() : ctx.dst->Expr(0_i));
+        }
+
+        return nullptr;  // Clone, which will use the argument replacements above.
     }
-
-    ProgramBuilder& b = *ctx.dst;
-
-    // Indices of the mandatory texture and coords parameters, and the optional
-    // array and level parameters.
-    auto& signature = builtin->Signature();
-    auto texture_idx = signature.IndexOf(sem::ParameterUsage::kTexture);
-    auto coords_idx = signature.IndexOf(sem::ParameterUsage::kCoords);
-    auto array_idx = signature.IndexOf(sem::ParameterUsage::kArrayIndex);
-    auto level_idx = signature.IndexOf(sem::ParameterUsage::kLevel);
-
-    auto* texture_arg = expr->args[texture_idx];
-    auto* coords_arg = expr->args[coords_idx];
-    auto* coords_ty = builtin->Parameters()[coords_idx]->Type();
-
-    // If the level is provided, then we need to clamp this. As the level is
-    // used by textureDimensions() and the texture[Load|Store]() calls, we need
-    // to clamp both usages.
-    // TODO(bclayton): We probably want to place this into a let so that the
-    // calculation can be reused. This is fiddly to get right.
-    std::function<const ast::Expression*()> level_arg;
-    if (level_idx >= 0) {
-      level_arg = [&] {
-        auto* arg = expr->args[level_idx];
-        auto* num_levels = b.Call("textureNumLevels", ctx.Clone(texture_arg));
-        auto* zero = b.Expr(0);
-        auto* max = ctx.dst->Sub(num_levels, 1);
-        auto* clamped = b.Call("clamp", ctx.Clone(arg), zero, max);
-        return clamped;
-      };
-    }
-
-    // Clamp the coordinates argument
-    {
-      auto* texture_dims =
-          level_arg
-              ? b.Call("textureDimensions", ctx.Clone(texture_arg), level_arg())
-              : b.Call("textureDimensions", ctx.Clone(texture_arg));
-      auto* zero = b.Construct(CreateASTTypeFor(ctx, coords_ty));
-      auto* max = ctx.dst->Sub(
-          texture_dims, b.Construct(CreateASTTypeFor(ctx, coords_ty), 1));
-      auto* clamped_coords = b.Call("clamp", ctx.Clone(coords_arg), zero, max);
-      ctx.Replace(coords_arg, clamped_coords);
-    }
-
-    // Clamp the array_index argument, if provided
-    if (array_idx >= 0) {
-      auto* arg = expr->args[array_idx];
-      auto* num_layers = b.Call("textureNumLayers", ctx.Clone(texture_arg));
-      auto* zero = b.Expr(0);
-      auto* max = ctx.dst->Sub(num_layers, 1);
-      auto* clamped = b.Call("clamp", ctx.Clone(arg), zero, max);
-      ctx.Replace(arg, clamped);
-    }
-
-    // Clamp the level argument, if provided
-    if (level_idx >= 0) {
-      auto* arg = expr->args[level_idx];
-      ctx.Replace(arg, level_arg ? level_arg() : ctx.dst->Expr(0));
-    }
-
-    return nullptr;  // Clone, which will use the argument replacements above.
-  }
 };
 
 Robustness::Config::Config() = default;
@@ -292,27 +285,27 @@
 Robustness::~Robustness() = default;
 
 void Robustness::Run(CloneContext& ctx, const DataMap& inputs, DataMap&) const {
-  Config cfg;
-  if (auto* cfg_data = inputs.Get<Config>()) {
-    cfg = *cfg_data;
-  }
-
-  std::unordered_set<ast::StorageClass> omitted_classes;
-  for (auto sc : cfg.omitted_classes) {
-    switch (sc) {
-      case StorageClass::kUniform:
-        omitted_classes.insert(ast::StorageClass::kUniform);
-        break;
-      case StorageClass::kStorage:
-        omitted_classes.insert(ast::StorageClass::kStorage);
-        break;
+    Config cfg;
+    if (auto* cfg_data = inputs.Get<Config>()) {
+        cfg = *cfg_data;
     }
-  }
 
-  State state{ctx, std::move(omitted_classes)};
+    std::unordered_set<ast::StorageClass> omitted_classes;
+    for (auto sc : cfg.omitted_classes) {
+        switch (sc) {
+            case StorageClass::kUniform:
+                omitted_classes.insert(ast::StorageClass::kUniform);
+                break;
+            case StorageClass::kStorage:
+                omitted_classes.insert(ast::StorageClass::kStorage);
+                break;
+        }
+    }
 
-  state.Transform();
-  ctx.Clone();
+    State state{ctx, std::move(omitted_classes)};
+
+    state.Transform();
+    ctx.Clone();
 }
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/robustness.h b/src/tint/transform/robustness.h
index 79ddf08..138b48c 100644
--- a/src/tint/transform/robustness.h
+++ b/src/tint/transform/robustness.h
@@ -32,51 +32,49 @@
 /// to zero and any access past the end of the array will clamp to
 /// (array length - 1).
 class Robustness : public Castable<Robustness, Transform> {
- public:
-  /// Storage class to be skipped in the transform
-  enum class StorageClass {
-    kUniform,
-    kStorage,
-  };
+  public:
+    /// Storage class to be skipped in the transform
+    enum class StorageClass {
+        kUniform,
+        kStorage,
+    };
 
-  /// Configuration options for the transform
-  struct Config : public Castable<Config, Data> {
+    /// Configuration options for the transform
+    struct Config : public Castable<Config, Data> {
+        /// Constructor
+        Config();
+
+        /// Copy constructor
+        Config(const Config&);
+
+        /// Destructor
+        ~Config() override;
+
+        /// Assignment operator
+        /// @returns this Config
+        Config& operator=(const Config&);
+
+        /// Storage classes to omit from apply the transform to.
+        /// This allows for optimizing on hardware that provide safe accesses.
+        std::unordered_set<StorageClass> omitted_classes;
+    };
+
     /// Constructor
-    Config();
-
-    /// Copy constructor
-    Config(const Config&);
-
+    Robustness();
     /// Destructor
-    ~Config() override;
+    ~Robustness() override;
 
-    /// Assignment operator
-    /// @returns this Config
-    Config& operator=(const Config&);
+  protected:
+    /// Runs the transform using the CloneContext built for transforming a
+    /// program. Run() is responsible for calling Clone() on the CloneContext.
+    /// @param ctx the CloneContext primed with the input program and
+    /// ProgramBuilder
+    /// @param inputs optional extra transform-specific input data
+    /// @param outputs optional extra transform-specific output data
+    void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const override;
 
-    /// Storage classes to omit from apply the transform to.
-    /// This allows for optimizing on hardware that provide safe accesses.
-    std::unordered_set<StorageClass> omitted_classes;
-  };
-
-  /// Constructor
-  Robustness();
-  /// Destructor
-  ~Robustness() override;
-
- protected:
-  /// Runs the transform using the CloneContext built for transforming a
-  /// program. Run() is responsible for calling Clone() on the CloneContext.
-  /// @param ctx the CloneContext primed with the input program and
-  /// ProgramBuilder
-  /// @param inputs optional extra transform-specific input data
-  /// @param outputs optional extra transform-specific output data
-  void Run(CloneContext& ctx,
-           const DataMap& inputs,
-           DataMap& outputs) const override;
-
- private:
-  struct State;
+  private:
+    struct State;
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/robustness_test.cc b/src/tint/transform/robustness_test.cc
index db113b2..fb0e5a4 100644
--- a/src/tint/transform/robustness_test.cc
+++ b/src/tint/transform/robustness_test.cc
@@ -22,7 +22,7 @@
 using RobustnessTest = TransformTest;
 
 TEST_F(RobustnessTest, Array_Idx_Clamp) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> a : array<f32, 3>;
 
 let c : u32 = 1u;
@@ -32,7 +32,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> a : array<f32, 3>;
 
 let c : u32 = 1u;
@@ -42,13 +42,13 @@
 }
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, Array_Idx_Clamp_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let b : f32 = a[c];
 }
@@ -58,7 +58,7 @@
 var<private> a : array<f32, 3>;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   let b : f32 = a[1u];
 }
@@ -68,13 +68,13 @@
 var<private> a : array<f32, 3>;
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, Array_Idx_Nested_Scalar) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> a : array<f32, 3>;
 
 var<private> b : array<i32, 5>;
@@ -86,7 +86,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> a : array<f32, 3>;
 
 var<private> b : array<i32, 5>;
@@ -98,13 +98,13 @@
 }
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, Array_Idx_Nested_Scalar_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var c : f32 = a[ b[i] ];
 }
@@ -116,7 +116,7 @@
 var<private> a : array<f32, 3>;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var c : f32 = a[min(u32(b[min(i, 4u)]), 2u)];
 }
@@ -128,57 +128,57 @@
 var<private> a : array<f32, 3>;
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, Array_Idx_Scalar) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> a : array<f32, 3>;
 
 fn f() {
-  var b : f32 = a[1];
+  var b : f32 = a[1i];
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> a : array<f32, 3>;
 
 fn f() {
-  var b : f32 = a[1];
+  var b : f32 = a[1i];
 }
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, Array_Idx_Scalar_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
-  var b : f32 = a[1];
+  var b : f32 = a[1i];
 }
 
 var<private> a : array<f32, 3>;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
-  var b : f32 = a[1];
+  var b : f32 = a[1i];
 }
 
 var<private> a : array<f32, 3>;
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, Array_Idx_Expr) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> a : array<f32, 3>;
 
 var<private> c : i32;
@@ -188,7 +188,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> a : array<f32, 3>;
 
 var<private> c : i32;
@@ -198,13 +198,13 @@
 }
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, Array_Idx_Expr_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var b : f32 = a[c + 2 - 3];
 }
@@ -214,7 +214,7 @@
 var<private> a : array<f32, 3>;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var b : f32 = a[min(u32(((c + 2) - 3)), 2u)];
 }
@@ -224,13 +224,13 @@
 var<private> a : array<f32, 3>;
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, Array_Idx_Negative) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> a : array<f32, 3>;
 
 fn f() {
@@ -238,21 +238,21 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> a : array<f32, 3>;
 
 fn f() {
-  var b : f32 = a[0];
+  var b : f32 = a[0i];
 }
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, Array_Idx_Negative_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var b : f32 = a[-1];
 }
@@ -260,21 +260,21 @@
 var<private> a : array<f32, 3>;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
-  var b : f32 = a[0];
+  var b : f32 = a[0i];
 }
 
 var<private> a : array<f32, 3>;
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, Array_Idx_OutOfBounds) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> a : array<f32, 3>;
 
 fn f() {
@@ -282,21 +282,21 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> a : array<f32, 3>;
 
 fn f() {
-  var b : f32 = a[2];
+  var b : f32 = a[2i];
 }
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, Array_Idx_OutOfBounds_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var b : f32 = a[3];
 }
@@ -304,23 +304,23 @@
 var<private> a : array<f32, 3>;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
-  var b : f32 = a[2];
+  var b : f32 = a[2i];
 }
 
 var<private> a : array<f32, 3>;
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 // TODO(crbug.com/tint/1177) - Validation currently forbids arrays larger than
 // 0xffffffff. If WGSL supports 64-bit indexing, re-enable this test.
 TEST_F(RobustnessTest, DISABLED_LargeArrays_Idx) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   a : array<f32, 0x7fffffff>,
   b : array<f32>,
@@ -358,7 +358,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   a : array<f32, 2147483647>,
   b : array<f32>,
@@ -392,57 +392,57 @@
 }
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, Vector_Idx_Scalar) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> a : vec3<f32>;
 
 fn f() {
-  var b : f32 = a[1];
+  var b : f32 = a[1i];
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> a : vec3<f32>;
 
 fn f() {
-  var b : f32 = a[1];
+  var b : f32 = a[1i];
 }
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, Vector_Idx_Scalar_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
-  var b : f32 = a[1];
+  var b : f32 = a[1i];
 }
 
 var<private> a : vec3<f32>;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
-  var b : f32 = a[1];
+  var b : f32 = a[1i];
 }
 
 var<private> a : vec3<f32>;
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, Vector_Idx_Expr) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> a : vec3<f32>;
 
 var<private> c : i32;
@@ -452,7 +452,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> a : vec3<f32>;
 
 var<private> c : i32;
@@ -462,13 +462,13 @@
 }
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, Vector_Idx_Expr_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var b : f32 = a[c + 2 - 3];
 }
@@ -478,7 +478,7 @@
 var<private> a : vec3<f32>;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var b : f32 = a[min(u32(((c + 2) - 3)), 2u)];
 }
@@ -488,13 +488,13 @@
 var<private> a : vec3<f32>;
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, Vector_Swizzle_Idx_Scalar) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> a : vec3<f32>;
 
 fn f() {
@@ -502,21 +502,21 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> a : vec3<f32>;
 
 fn f() {
-  var b : f32 = a.xy[1];
+  var b : f32 = a.xy[1i];
 }
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, Vector_Swizzle_Idx_Scalar_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var b : f32 = a.xy[2];
 }
@@ -524,21 +524,21 @@
 var<private> a : vec3<f32>;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
-  var b : f32 = a.xy[1];
+  var b : f32 = a.xy[1i];
 }
 
 var<private> a : vec3<f32>;
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, Vector_Swizzle_Idx_Var) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> a : vec3<f32>;
 
 var<private> c : i32;
@@ -548,7 +548,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> a : vec3<f32>;
 
 var<private> c : i32;
@@ -558,13 +558,13 @@
 }
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, Vector_Swizzle_Idx_Var_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var b : f32 = a.xy[c];
 }
@@ -574,7 +574,7 @@
 var<private> a : vec3<f32>;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var b : f32 = a.xy[min(u32(c), 1u)];
 }
@@ -584,13 +584,13 @@
 var<private> a : vec3<f32>;
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, Vector_Swizzle_Idx_Expr) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> a : vec3<f32>;
 
 var<private> c : i32;
@@ -600,7 +600,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> a : vec3<f32>;
 
 var<private> c : i32;
@@ -610,13 +610,13 @@
 }
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, Vector_Swizzle_Idx_Expr_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var b : f32 = a.xy[c + 2 - 3];
 }
@@ -626,7 +626,7 @@
 var<private> a : vec3<f32>;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var b : f32 = a.xy[min(u32(((c + 2) - 3)), 1u)];
 }
@@ -636,13 +636,13 @@
 var<private> a : vec3<f32>;
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, Vector_Idx_Negative) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> a : vec3<f32>;
 
 fn f() {
@@ -650,21 +650,21 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> a : vec3<f32>;
 
 fn f() {
-  var b : f32 = a[0];
+  var b : f32 = a[0i];
 }
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, Vector_Idx_Negative_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var b : f32 = a[-1];
 }
@@ -672,21 +672,21 @@
 var<private> a : vec3<f32>;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
-  var b : f32 = a[0];
+  var b : f32 = a[0i];
 }
 
 var<private> a : vec3<f32>;
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, Vector_Idx_OutOfBounds) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> a : vec3<f32>;
 
 fn f() {
@@ -694,21 +694,21 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> a : vec3<f32>;
 
 fn f() {
-  var b : f32 = a[2];
+  var b : f32 = a[2i];
 }
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, Vector_Idx_OutOfBounds_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var b : f32 = a[3];
 }
@@ -716,65 +716,65 @@
 var<private> a : vec3<f32>;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
-  var b : f32 = a[2];
+  var b : f32 = a[2i];
 }
 
 var<private> a : vec3<f32>;
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, Matrix_Idx_Scalar) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> a : mat3x2<f32>;
 
 fn f() {
-  var b : f32 = a[2][1];
+  var b : f32 = a[2i][1i];
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> a : mat3x2<f32>;
 
 fn f() {
-  var b : f32 = a[2][1];
+  var b : f32 = a[2i][1i];
 }
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, Matrix_Idx_Scalar_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
-  var b : f32 = a[2][1];
+  var b : f32 = a[2i][1i];
 }
 
 var<private> a : mat3x2<f32>;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
-  var b : f32 = a[2][1];
+  var b : f32 = a[2i][1i];
 }
 
 var<private> a : mat3x2<f32>;
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, Matrix_Idx_Expr_Column) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> a : mat3x2<f32>;
 
 var<private> c : i32;
@@ -784,23 +784,23 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> a : mat3x2<f32>;
 
 var<private> c : i32;
 
 fn f() {
-  var b : f32 = a[min(u32(((c + 2) - 3)), 2u)][1];
+  var b : f32 = a[min(u32(((c + 2) - 3)), 2u)][1i];
 }
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, Matrix_Idx_Expr_Column_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var b : f32 = a[c + 2 - 3][1];
 }
@@ -810,9 +810,9 @@
 var<private> a : mat3x2<f32>;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
-  var b : f32 = a[min(u32(((c + 2) - 3)), 2u)][1];
+  var b : f32 = a[min(u32(((c + 2) - 3)), 2u)][1i];
 }
 
 var<private> c : i32;
@@ -820,13 +820,13 @@
 var<private> a : mat3x2<f32>;
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, Matrix_Idx_Expr_Row) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> a : mat3x2<f32>;
 
 var<private> c : i32;
@@ -836,23 +836,23 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> a : mat3x2<f32>;
 
 var<private> c : i32;
 
 fn f() {
-  var b : f32 = a[1][min(u32(((c + 2) - 3)), 1u)];
+  var b : f32 = a[1i][min(u32(((c + 2) - 3)), 1u)];
 }
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, Matrix_Idx_Expr_Row_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var b : f32 = a[1][c + 2 - 3];
 }
@@ -862,9 +862,9 @@
 var<private> a : mat3x2<f32>;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
-  var b : f32 = a[1][min(u32(((c + 2) - 3)), 1u)];
+  var b : f32 = a[1i][min(u32(((c + 2) - 3)), 1u)];
 }
 
 var<private> c : i32;
@@ -872,13 +872,13 @@
 var<private> a : mat3x2<f32>;
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, Matrix_Idx_Negative_Column) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> a : mat3x2<f32>;
 
 fn f() {
@@ -886,21 +886,21 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> a : mat3x2<f32>;
 
 fn f() {
-  var b : f32 = a[0][1];
+  var b : f32 = a[0i][1i];
 }
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, Matrix_Idx_Negative_Column_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var b : f32 = a[-1][1];
 }
@@ -908,21 +908,21 @@
 var<private> a : mat3x2<f32>;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
-  var b : f32 = a[0][1];
+  var b : f32 = a[0i][1i];
 }
 
 var<private> a : mat3x2<f32>;
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, Matrix_Idx_Negative_Row) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> a : mat3x2<f32>;
 
 fn f() {
@@ -930,21 +930,21 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> a : mat3x2<f32>;
 
 fn f() {
-  var b : f32 = a[2][0];
+  var b : f32 = a[2i][0i];
 }
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, Matrix_Idx_Negative_Row_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var b : f32 = a[2][-1];
 }
@@ -952,21 +952,21 @@
 var<private> a : mat3x2<f32>;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
-  var b : f32 = a[2][0];
+  var b : f32 = a[2i][0i];
 }
 
 var<private> a : mat3x2<f32>;
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, Matrix_Idx_OutOfBounds_Column) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> a : mat3x2<f32>;
 
 fn f() {
@@ -974,21 +974,21 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> a : mat3x2<f32>;
 
 fn f() {
-  var b : f32 = a[2][1];
+  var b : f32 = a[2i][1i];
 }
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, Matrix_Idx_OutOfBounds_Column_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var b : f32 = a[5][1];
 }
@@ -996,21 +996,21 @@
 var<private> a : mat3x2<f32>;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
-  var b : f32 = a[2][1];
+  var b : f32 = a[2i][1i];
 }
 
 var<private> a : mat3x2<f32>;
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, Matrix_Idx_OutOfBounds_Row) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> a : mat3x2<f32>;
 
 fn f() {
@@ -1018,21 +1018,21 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> a : mat3x2<f32>;
 
 fn f() {
-  var b : f32 = a[2][1];
+  var b : f32 = a[2i][1i];
 }
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, Matrix_Idx_OutOfBounds_Row_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var b : f32 = a[2][5];
 }
@@ -1040,57 +1040,57 @@
 var<private> a : mat3x2<f32>;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
-  var b : f32 = a[2][1];
+  var b : f32 = a[2i][1i];
 }
 
 var<private> a : mat3x2<f32>;
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 // TODO(dsinclair): Implement when constant_id exists
 TEST_F(RobustnessTest, DISABLED_Vector_Constant_Id_Clamps) {
-  // @id(1300) override idx : i32;
-  // var a : vec3<f32>
-  // var b : f32 = a[idx]
-  //
-  // ->var b : f32 = a[min(u32(idx), 2)]
+    // @id(1300) override idx : i32;
+    // var a : vec3<f32>
+    // var b : f32 = a[idx]
+    //
+    // ->var b : f32 = a[min(u32(idx), 2)]
 }
 
 // TODO(dsinclair): Implement when constant_id exists
 TEST_F(RobustnessTest, DISABLED_Array_Constant_Id_Clamps) {
-  // @id(1300) override idx : i32;
-  // var a : array<f32, 4>
-  // var b : f32 = a[idx]
-  //
-  // -> var b : f32 = a[min(u32(idx), 3)]
+    // @id(1300) override idx : i32;
+    // var a : array<f32, 4>
+    // var b : f32 = a[idx]
+    //
+    // -> var b : f32 = a[min(u32(idx), 3)]
 }
 
 // TODO(dsinclair): Implement when constant_id exists
 TEST_F(RobustnessTest, DISABLED_Matrix_Column_Constant_Id_Clamps) {
-  // @id(1300) override idx : i32;
-  // var a : mat3x2<f32>
-  // var b : f32 = a[idx][1]
-  //
-  // -> var b : f32 = a[min(u32(idx), 2)][1]
+    // @id(1300) override idx : i32;
+    // var a : mat3x2<f32>
+    // var b : f32 = a[idx][1]
+    //
+    // -> var b : f32 = a[min(u32(idx), 2)][1]
 }
 
 // TODO(dsinclair): Implement when constant_id exists
 TEST_F(RobustnessTest, DISABLED_Matrix_Row_Constant_Id_Clamps) {
-  // @id(1300) override idx : i32;
-  // var a : mat3x2<f32>
-  // var b : f32 = a[1][idx]
-  //
-  // -> var b : f32 = a[1][min(u32(idx), 0, 1)]
+    // @id(1300) override idx : i32;
+    // var a : mat3x2<f32>
+    // var b : f32 = a[1][idx]
+    //
+    // -> var b : f32 = a[1][min(u32(idx), 0, 1)]
 }
 
 TEST_F(RobustnessTest, RuntimeArray_Clamps) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   a : f32,
   b : array<f32>,
@@ -1102,7 +1102,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   a : f32,
   b : array<f32>,
@@ -1115,13 +1115,13 @@
 }
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, RuntimeArray_Clamps_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var d : f32 = s.b[25];
 }
@@ -1134,7 +1134,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var d : f32 = s.b[min(25u, (arrayLength(&(s.b)) - 1u))];
 }
@@ -1147,14 +1147,14 @@
 }
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 // Clamp textureLoad() coord, array_index and level values
 TEST_F(RobustnessTest, TextureLoad_Clamp) {
-  auto* src = R"(
+    auto* src = R"(
 @group(0) @binding(0) var tex_1d : texture_1d<f32>;
 @group(0) @binding(0) var tex_2d : texture_2d<f32>;
 @group(0) @binding(0) var tex_2d_arr : texture_2d_array<f32>;
@@ -1180,8 +1180,8 @@
 }
 )";
 
-  auto* expect =
-      R"(
+    auto* expect =
+        R"(
 @group(0) @binding(0) var tex_1d : texture_1d<f32>;
 
 @group(0) @binding(0) var tex_2d : texture_2d<f32>;
@@ -1202,25 +1202,25 @@
   var array_idx : i32;
   var level_idx : i32;
   var sample_idx : i32;
-  textureLoad(tex_1d, clamp(1, i32(), (textureDimensions(tex_1d, clamp(level_idx, 0, (textureNumLevels(tex_1d) - 1))) - i32(1))), clamp(level_idx, 0, (textureNumLevels(tex_1d) - 1)));
-  textureLoad(tex_2d, clamp(vec2<i32>(1, 2), vec2<i32>(), (textureDimensions(tex_2d, clamp(level_idx, 0, (textureNumLevels(tex_2d) - 1))) - vec2<i32>(1))), clamp(level_idx, 0, (textureNumLevels(tex_2d) - 1)));
-  textureLoad(tex_2d_arr, clamp(vec2<i32>(1, 2), vec2<i32>(), (textureDimensions(tex_2d_arr, clamp(level_idx, 0, (textureNumLevels(tex_2d_arr) - 1))) - vec2<i32>(1))), clamp(array_idx, 0, (textureNumLayers(tex_2d_arr) - 1)), clamp(level_idx, 0, (textureNumLevels(tex_2d_arr) - 1)));
-  textureLoad(tex_3d, clamp(vec3<i32>(1, 2, 3), vec3<i32>(), (textureDimensions(tex_3d, clamp(level_idx, 0, (textureNumLevels(tex_3d) - 1))) - vec3<i32>(1))), clamp(level_idx, 0, (textureNumLevels(tex_3d) - 1)));
-  textureLoad(tex_ms_2d, clamp(vec2<i32>(1, 2), vec2<i32>(), (textureDimensions(tex_ms_2d) - vec2<i32>(1))), sample_idx);
-  textureLoad(tex_depth_2d, clamp(vec2<i32>(1, 2), vec2<i32>(), (textureDimensions(tex_depth_2d, clamp(level_idx, 0, (textureNumLevels(tex_depth_2d) - 1))) - vec2<i32>(1))), clamp(level_idx, 0, (textureNumLevels(tex_depth_2d) - 1)));
-  textureLoad(tex_depth_2d_arr, clamp(vec2<i32>(1, 2), vec2<i32>(), (textureDimensions(tex_depth_2d_arr, clamp(level_idx, 0, (textureNumLevels(tex_depth_2d_arr) - 1))) - vec2<i32>(1))), clamp(array_idx, 0, (textureNumLayers(tex_depth_2d_arr) - 1)), clamp(level_idx, 0, (textureNumLevels(tex_depth_2d_arr) - 1)));
-  textureLoad(tex_external, clamp(vec2<i32>(1, 2), vec2<i32>(), (textureDimensions(tex_external) - vec2<i32>(1))));
+  textureLoad(tex_1d, clamp(1, i32(), (textureDimensions(tex_1d, clamp(level_idx, 0i, (textureNumLevels(tex_1d) - 1i))) - i32(1i))), clamp(level_idx, 0i, (textureNumLevels(tex_1d) - 1i)));
+  textureLoad(tex_2d, clamp(vec2<i32>(1, 2), vec2<i32>(), (textureDimensions(tex_2d, clamp(level_idx, 0i, (textureNumLevels(tex_2d) - 1i))) - vec2<i32>(1i))), clamp(level_idx, 0i, (textureNumLevels(tex_2d) - 1i)));
+  textureLoad(tex_2d_arr, clamp(vec2<i32>(1, 2), vec2<i32>(), (textureDimensions(tex_2d_arr, clamp(level_idx, 0i, (textureNumLevels(tex_2d_arr) - 1i))) - vec2<i32>(1i))), clamp(array_idx, 0i, (textureNumLayers(tex_2d_arr) - 1i)), clamp(level_idx, 0i, (textureNumLevels(tex_2d_arr) - 1i)));
+  textureLoad(tex_3d, clamp(vec3<i32>(1, 2, 3), vec3<i32>(), (textureDimensions(tex_3d, clamp(level_idx, 0i, (textureNumLevels(tex_3d) - 1i))) - vec3<i32>(1i))), clamp(level_idx, 0i, (textureNumLevels(tex_3d) - 1i)));
+  textureLoad(tex_ms_2d, clamp(vec2<i32>(1, 2), vec2<i32>(), (textureDimensions(tex_ms_2d) - vec2<i32>(1i))), sample_idx);
+  textureLoad(tex_depth_2d, clamp(vec2<i32>(1, 2), vec2<i32>(), (textureDimensions(tex_depth_2d, clamp(level_idx, 0i, (textureNumLevels(tex_depth_2d) - 1i))) - vec2<i32>(1i))), clamp(level_idx, 0i, (textureNumLevels(tex_depth_2d) - 1i)));
+  textureLoad(tex_depth_2d_arr, clamp(vec2<i32>(1, 2), vec2<i32>(), (textureDimensions(tex_depth_2d_arr, clamp(level_idx, 0i, (textureNumLevels(tex_depth_2d_arr) - 1i))) - vec2<i32>(1i))), clamp(array_idx, 0i, (textureNumLayers(tex_depth_2d_arr) - 1i)), clamp(level_idx, 0i, (textureNumLevels(tex_depth_2d_arr) - 1i)));
+  textureLoad(tex_external, clamp(vec2<i32>(1, 2), vec2<i32>(), (textureDimensions(tex_external) - vec2<i32>(1i))));
 }
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 // Clamp textureLoad() coord, array_index and level values
 TEST_F(RobustnessTest, TextureLoad_Clamp_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var array_idx : i32;
   var level_idx : i32;
@@ -1246,20 +1246,20 @@
 @group(0) @binding(0) var tex_external : texture_external;
 )";
 
-  auto* expect =
-      R"(
+    auto* expect =
+        R"(
 fn f() {
   var array_idx : i32;
   var level_idx : i32;
   var sample_idx : i32;
-  textureLoad(tex_1d, clamp(1, i32(), (textureDimensions(tex_1d, clamp(level_idx, 0, (textureNumLevels(tex_1d) - 1))) - i32(1))), clamp(level_idx, 0, (textureNumLevels(tex_1d) - 1)));
-  textureLoad(tex_2d, clamp(vec2<i32>(1, 2), vec2<i32>(), (textureDimensions(tex_2d, clamp(level_idx, 0, (textureNumLevels(tex_2d) - 1))) - vec2<i32>(1))), clamp(level_idx, 0, (textureNumLevels(tex_2d) - 1)));
-  textureLoad(tex_2d_arr, clamp(vec2<i32>(1, 2), vec2<i32>(), (textureDimensions(tex_2d_arr, clamp(level_idx, 0, (textureNumLevels(tex_2d_arr) - 1))) - vec2<i32>(1))), clamp(array_idx, 0, (textureNumLayers(tex_2d_arr) - 1)), clamp(level_idx, 0, (textureNumLevels(tex_2d_arr) - 1)));
-  textureLoad(tex_3d, clamp(vec3<i32>(1, 2, 3), vec3<i32>(), (textureDimensions(tex_3d, clamp(level_idx, 0, (textureNumLevels(tex_3d) - 1))) - vec3<i32>(1))), clamp(level_idx, 0, (textureNumLevels(tex_3d) - 1)));
-  textureLoad(tex_ms_2d, clamp(vec2<i32>(1, 2), vec2<i32>(), (textureDimensions(tex_ms_2d) - vec2<i32>(1))), sample_idx);
-  textureLoad(tex_depth_2d, clamp(vec2<i32>(1, 2), vec2<i32>(), (textureDimensions(tex_depth_2d, clamp(level_idx, 0, (textureNumLevels(tex_depth_2d) - 1))) - vec2<i32>(1))), clamp(level_idx, 0, (textureNumLevels(tex_depth_2d) - 1)));
-  textureLoad(tex_depth_2d_arr, clamp(vec2<i32>(1, 2), vec2<i32>(), (textureDimensions(tex_depth_2d_arr, clamp(level_idx, 0, (textureNumLevels(tex_depth_2d_arr) - 1))) - vec2<i32>(1))), clamp(array_idx, 0, (textureNumLayers(tex_depth_2d_arr) - 1)), clamp(level_idx, 0, (textureNumLevels(tex_depth_2d_arr) - 1)));
-  textureLoad(tex_external, clamp(vec2<i32>(1, 2), vec2<i32>(), (textureDimensions(tex_external) - vec2<i32>(1))));
+  textureLoad(tex_1d, clamp(1, i32(), (textureDimensions(tex_1d, clamp(level_idx, 0i, (textureNumLevels(tex_1d) - 1i))) - i32(1i))), clamp(level_idx, 0i, (textureNumLevels(tex_1d) - 1i)));
+  textureLoad(tex_2d, clamp(vec2<i32>(1, 2), vec2<i32>(), (textureDimensions(tex_2d, clamp(level_idx, 0i, (textureNumLevels(tex_2d) - 1i))) - vec2<i32>(1i))), clamp(level_idx, 0i, (textureNumLevels(tex_2d) - 1i)));
+  textureLoad(tex_2d_arr, clamp(vec2<i32>(1, 2), vec2<i32>(), (textureDimensions(tex_2d_arr, clamp(level_idx, 0i, (textureNumLevels(tex_2d_arr) - 1i))) - vec2<i32>(1i))), clamp(array_idx, 0i, (textureNumLayers(tex_2d_arr) - 1i)), clamp(level_idx, 0i, (textureNumLevels(tex_2d_arr) - 1i)));
+  textureLoad(tex_3d, clamp(vec3<i32>(1, 2, 3), vec3<i32>(), (textureDimensions(tex_3d, clamp(level_idx, 0i, (textureNumLevels(tex_3d) - 1i))) - vec3<i32>(1i))), clamp(level_idx, 0i, (textureNumLevels(tex_3d) - 1i)));
+  textureLoad(tex_ms_2d, clamp(vec2<i32>(1, 2), vec2<i32>(), (textureDimensions(tex_ms_2d) - vec2<i32>(1i))), sample_idx);
+  textureLoad(tex_depth_2d, clamp(vec2<i32>(1, 2), vec2<i32>(), (textureDimensions(tex_depth_2d, clamp(level_idx, 0i, (textureNumLevels(tex_depth_2d) - 1i))) - vec2<i32>(1i))), clamp(level_idx, 0i, (textureNumLevels(tex_depth_2d) - 1i)));
+  textureLoad(tex_depth_2d_arr, clamp(vec2<i32>(1, 2), vec2<i32>(), (textureDimensions(tex_depth_2d_arr, clamp(level_idx, 0i, (textureNumLevels(tex_depth_2d_arr) - 1i))) - vec2<i32>(1i))), clamp(array_idx, 0i, (textureNumLayers(tex_depth_2d_arr) - 1i)), clamp(level_idx, 0i, (textureNumLevels(tex_depth_2d_arr) - 1i)));
+  textureLoad(tex_external, clamp(vec2<i32>(1, 2), vec2<i32>(), (textureDimensions(tex_external) - vec2<i32>(1i))));
 }
 
 @group(0) @binding(0) var tex_1d : texture_1d<f32>;
@@ -1279,14 +1279,14 @@
 @group(0) @binding(0) var tex_external : texture_external;
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 // Clamp textureStore() coord, array_index and level values
 TEST_F(RobustnessTest, TextureStore_Clamp) {
-  auto* src = R"(
+    auto* src = R"(
 @group(0) @binding(0) var tex1d : texture_storage_1d<rgba8sint, write>;
 
 @group(0) @binding(1) var tex2d : texture_storage_2d<rgba8sint, write>;
@@ -1303,7 +1303,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @group(0) @binding(0) var tex1d : texture_storage_1d<rgba8sint, write>;
 
 @group(0) @binding(1) var tex2d : texture_storage_2d<rgba8sint, write>;
@@ -1313,21 +1313,21 @@
 @group(0) @binding(3) var tex3d : texture_storage_3d<rgba8sint, write>;
 
 fn f() {
-  textureStore(tex1d, clamp(10, i32(), (textureDimensions(tex1d) - i32(1))), vec4<i32>());
-  textureStore(tex2d, clamp(vec2<i32>(10, 20), vec2<i32>(), (textureDimensions(tex2d) - vec2<i32>(1))), vec4<i32>());
-  textureStore(tex2d_arr, clamp(vec2<i32>(10, 20), vec2<i32>(), (textureDimensions(tex2d_arr) - vec2<i32>(1))), clamp(50, 0, (textureNumLayers(tex2d_arr) - 1)), vec4<i32>());
-  textureStore(tex3d, clamp(vec3<i32>(10, 20, 30), vec3<i32>(), (textureDimensions(tex3d) - vec3<i32>(1))), vec4<i32>());
+  textureStore(tex1d, clamp(10, i32(), (textureDimensions(tex1d) - i32(1i))), vec4<i32>());
+  textureStore(tex2d, clamp(vec2<i32>(10, 20), vec2<i32>(), (textureDimensions(tex2d) - vec2<i32>(1i))), vec4<i32>());
+  textureStore(tex2d_arr, clamp(vec2<i32>(10, 20), vec2<i32>(), (textureDimensions(tex2d_arr) - vec2<i32>(1i))), clamp(50, 0i, (textureNumLayers(tex2d_arr) - 1i)), vec4<i32>());
+  textureStore(tex3d, clamp(vec3<i32>(10, 20, 30), vec3<i32>(), (textureDimensions(tex3d) - vec3<i32>(1i))), vec4<i32>());
 }
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 // Clamp textureStore() coord, array_index and level values
 TEST_F(RobustnessTest, TextureStore_Clamp_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   textureStore(tex1d, 10, vec4<i32>());
   textureStore(tex2d, vec2<i32>(10, 20), vec4<i32>());
@@ -1345,12 +1345,12 @@
 
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
-  textureStore(tex1d, clamp(10, i32(), (textureDimensions(tex1d) - i32(1))), vec4<i32>());
-  textureStore(tex2d, clamp(vec2<i32>(10, 20), vec2<i32>(), (textureDimensions(tex2d) - vec2<i32>(1))), vec4<i32>());
-  textureStore(tex2d_arr, clamp(vec2<i32>(10, 20), vec2<i32>(), (textureDimensions(tex2d_arr) - vec2<i32>(1))), clamp(50, 0, (textureNumLayers(tex2d_arr) - 1)), vec4<i32>());
-  textureStore(tex3d, clamp(vec3<i32>(10, 20, 30), vec3<i32>(), (textureDimensions(tex3d) - vec3<i32>(1))), vec4<i32>());
+  textureStore(tex1d, clamp(10, i32(), (textureDimensions(tex1d) - i32(1i))), vec4<i32>());
+  textureStore(tex2d, clamp(vec2<i32>(10, 20), vec2<i32>(), (textureDimensions(tex2d) - vec2<i32>(1i))), vec4<i32>());
+  textureStore(tex2d_arr, clamp(vec2<i32>(10, 20), vec2<i32>(), (textureDimensions(tex2d_arr) - vec2<i32>(1i))), clamp(50, 0i, (textureNumLayers(tex2d_arr) - 1i)), vec4<i32>());
+  textureStore(tex3d, clamp(vec3<i32>(10, 20, 30), vec3<i32>(), (textureDimensions(tex3d) - vec3<i32>(1i))), vec4<i32>());
 }
 
 @group(0) @binding(0) var tex1d : texture_storage_1d<rgba8sint, write>;
@@ -1362,29 +1362,29 @@
 @group(0) @binding(3) var tex3d : texture_storage_3d<rgba8sint, write>;
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 // TODO(dsinclair): Test for scoped variables when shadowing is implemented
 TEST_F(RobustnessTest, DISABLED_Shadowed_Variable) {
-  // var a : array<f32, 3>;
-  // var i : u32;
-  // {
-  //    var a : array<f32, 5>;
-  //    var b : f32 = a[i];
-  // }
-  // var c : f32 = a[i];
-  //
-  // -> var b : f32 = a[min(u32(i), 4)];
-  //    var c : f32 = a[min(u32(i), 2)];
-  FAIL();
+    // var a : array<f32, 3>;
+    // var i : u32;
+    // {
+    //    var a : array<f32, 5>;
+    //    var b : f32 = a[i];
+    // }
+    // var c : f32 = a[i];
+    //
+    // -> var b : f32 = a[min(u32(i), 4)];
+    //    var c : f32 = a[min(u32(i), 2)];
+    FAIL();
 }
 
 // Check that existing use of min() and arrayLength() do not get renamed.
 TEST_F(RobustnessTest, DontRenameSymbols) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   a : f32,
   b : array<f32>,
@@ -1401,7 +1401,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   a : f32,
   b : array<f32>,
@@ -1418,9 +1418,9 @@
 }
 )";
 
-  auto got = Run<Robustness>(src);
+    auto got = Run<Robustness>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 const char* kOmitSourceShader = R"(
@@ -1481,7 +1481,7 @@
 )";
 
 TEST_F(RobustnessTest, OmitNone) {
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   a : array<f32, 4>,
   b : array<f32>,
@@ -1498,21 +1498,21 @@
 @group(1) @binding(0) var<uniform> u : U;
 
 fn f() {
-  var i32_sa1 : f32 = s.a[3];
-  var i32_sa2 : f32 = s.a[1];
-  var i32_sa3 : f32 = s.a[0];
-  var i32_sa4 : f32 = s.a[0];
-  var i32_sa5 : f32 = s.a[0];
+  var i32_sa1 : f32 = s.a[3i];
+  var i32_sa2 : f32 = s.a[1i];
+  var i32_sa3 : f32 = s.a[0i];
+  var i32_sa4 : f32 = s.a[0i];
+  var i32_sa5 : f32 = s.a[0i];
   var i32_sb1 : f32 = s.b[min(4u, (arrayLength(&(s.b)) - 1u))];
   var i32_sb2 : f32 = s.b[min(1u, (arrayLength(&(s.b)) - 1u))];
   var i32_sb3 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))];
   var i32_sb4 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))];
   var i32_sb5 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))];
-  var i32_ua1 : f32 = u.a[3].x;
-  var i32_ua2 : f32 = u.a[1].x;
-  var i32_ua3 : f32 = u.a[0].x;
-  var i32_ua4 : f32 = u.a[0].x;
-  var i32_ua5 : f32 = u.a[0].x;
+  var i32_ua1 : f32 = u.a[3i].x;
+  var i32_ua2 : f32 = u.a[1i].x;
+  var i32_ua3 : f32 = u.a[0i].x;
+  var i32_ua4 : f32 = u.a[0i].x;
+  var i32_ua5 : f32 = u.a[0i].x;
   var u32_sa1 : f32 = s.a[0u];
   var u32_sa2 : f32 = s.a[1u];
   var u32_sa3 : f32 = s.a[3u];
@@ -1534,17 +1534,17 @@
 }
 )";
 
-  Robustness::Config cfg;
-  DataMap data;
-  data.Add<Robustness::Config>(cfg);
+    Robustness::Config cfg;
+    DataMap data;
+    data.Add<Robustness::Config>(cfg);
 
-  auto got = Run<Robustness>(kOmitSourceShader, data);
+    auto got = Run<Robustness>(kOmitSourceShader, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, OmitStorage) {
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   a : array<f32, 4>,
   b : array<f32>,
@@ -1571,11 +1571,11 @@
   var i32_sb3 : f32 = s.b[0];
   var i32_sb4 : f32 = s.b[-1];
   var i32_sb5 : f32 = s.b[-4];
-  var i32_ua1 : f32 = u.a[3].x;
-  var i32_ua2 : f32 = u.a[1].x;
-  var i32_ua3 : f32 = u.a[0].x;
-  var i32_ua4 : f32 = u.a[0].x;
-  var i32_ua5 : f32 = u.a[0].x;
+  var i32_ua1 : f32 = u.a[3i].x;
+  var i32_ua2 : f32 = u.a[1i].x;
+  var i32_ua3 : f32 = u.a[0i].x;
+  var i32_ua4 : f32 = u.a[0i].x;
+  var i32_ua5 : f32 = u.a[0i].x;
   var u32_sa1 : f32 = s.a[0u];
   var u32_sa2 : f32 = s.a[1u];
   var u32_sa3 : f32 = s.a[3u];
@@ -1597,19 +1597,19 @@
 }
 )";
 
-  Robustness::Config cfg;
-  cfg.omitted_classes.insert(Robustness::StorageClass::kStorage);
+    Robustness::Config cfg;
+    cfg.omitted_classes.insert(Robustness::StorageClass::kStorage);
 
-  DataMap data;
-  data.Add<Robustness::Config>(cfg);
+    DataMap data;
+    data.Add<Robustness::Config>(cfg);
 
-  auto got = Run<Robustness>(kOmitSourceShader, data);
+    auto got = Run<Robustness>(kOmitSourceShader, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, OmitUniform) {
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   a : array<f32, 4>,
   b : array<f32>,
@@ -1626,11 +1626,11 @@
 @group(1) @binding(0) var<uniform> u : U;
 
 fn f() {
-  var i32_sa1 : f32 = s.a[3];
-  var i32_sa2 : f32 = s.a[1];
-  var i32_sa3 : f32 = s.a[0];
-  var i32_sa4 : f32 = s.a[0];
-  var i32_sa5 : f32 = s.a[0];
+  var i32_sa1 : f32 = s.a[3i];
+  var i32_sa2 : f32 = s.a[1i];
+  var i32_sa3 : f32 = s.a[0i];
+  var i32_sa4 : f32 = s.a[0i];
+  var i32_sa5 : f32 = s.a[0i];
   var i32_sb1 : f32 = s.b[min(4u, (arrayLength(&(s.b)) - 1u))];
   var i32_sb2 : f32 = s.b[min(1u, (arrayLength(&(s.b)) - 1u))];
   var i32_sb3 : f32 = s.b[min(0u, (arrayLength(&(s.b)) - 1u))];
@@ -1662,19 +1662,19 @@
 }
 )";
 
-  Robustness::Config cfg;
-  cfg.omitted_classes.insert(Robustness::StorageClass::kUniform);
+    Robustness::Config cfg;
+    cfg.omitted_classes.insert(Robustness::StorageClass::kUniform);
 
-  DataMap data;
-  data.Add<Robustness::Config>(cfg);
+    DataMap data;
+    data.Add<Robustness::Config>(cfg);
 
-  auto got = Run<Robustness>(kOmitSourceShader, data);
+    auto got = Run<Robustness>(kOmitSourceShader, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(RobustnessTest, OmitBoth) {
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   a : array<f32, 4>,
   b : array<f32>,
@@ -1727,16 +1727,16 @@
 }
 )";
 
-  Robustness::Config cfg;
-  cfg.omitted_classes.insert(Robustness::StorageClass::kStorage);
-  cfg.omitted_classes.insert(Robustness::StorageClass::kUniform);
+    Robustness::Config cfg;
+    cfg.omitted_classes.insert(Robustness::StorageClass::kStorage);
+    cfg.omitted_classes.insert(Robustness::StorageClass::kUniform);
 
-  DataMap data;
-  data.Add<Robustness::Config>(cfg);
+    DataMap data;
+    data.Add<Robustness::Config>(cfg);
 
-  auto got = Run<Robustness>(kOmitSourceShader, data);
+    auto got = Run<Robustness>(kOmitSourceShader, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 }  // namespace
diff --git a/src/tint/transform/simplify_pointers.cc b/src/tint/transform/simplify_pointers.cc
index 4cc9391..b8f82bc 100644
--- a/src/tint/transform/simplify_pointers.cc
+++ b/src/tint/transform/simplify_pointers.cc
@@ -35,195 +35,193 @@
 /// PointerOp describes either possible indirection or address-of action on an
 /// expression.
 struct PointerOp {
-  /// Positive: Number of times the `expr` was dereferenced (*expr)
-  /// Negative: Number of times the `expr` was 'addressed-of' (&expr)
-  /// Zero: no pointer op on `expr`
-  int indirections = 0;
-  /// The expression being operated on
-  const ast::Expression* expr = nullptr;
+    /// Positive: Number of times the `expr` was dereferenced (*expr)
+    /// Negative: Number of times the `expr` was 'addressed-of' (&expr)
+    /// Zero: no pointer op on `expr`
+    int indirections = 0;
+    /// The expression being operated on
+    const ast::Expression* expr = nullptr;
 };
 
 }  // namespace
 
 /// The PIMPL state for the SimplifyPointers transform
 struct SimplifyPointers::State {
-  /// The clone context
-  CloneContext& ctx;
+    /// The clone context
+    CloneContext& ctx;
 
-  /// Constructor
-  /// @param context the clone context
-  explicit State(CloneContext& context) : ctx(context) {}
+    /// Constructor
+    /// @param context the clone context
+    explicit State(CloneContext& context) : ctx(context) {}
 
-  /// Traverses the expression `expr` looking for non-literal array indexing
-  /// expressions that would affect the computed address of a pointer
-  /// expression. The function-like argument `cb` is called for each found.
-  /// @param expr the expression to traverse
-  /// @param cb a function-like object with the signature
-  /// `void(const ast::Expression*)`, which is called for each array index
-  /// expression
-  template <typename F>
-  static void CollectSavedArrayIndices(const ast::Expression* expr, F&& cb) {
-    if (auto* a = expr->As<ast::IndexAccessorExpression>()) {
-      CollectSavedArrayIndices(a->object, cb);
-      if (!a->index->Is<ast::LiteralExpression>()) {
-        cb(a->index);
-      }
-      return;
-    }
-
-    if (auto* m = expr->As<ast::MemberAccessorExpression>()) {
-      CollectSavedArrayIndices(m->structure, cb);
-      return;
-    }
-
-    if (auto* u = expr->As<ast::UnaryOpExpression>()) {
-      CollectSavedArrayIndices(u->expr, cb);
-      return;
-    }
-
-    // Note: Other ast::Expression types can be safely ignored as they cannot be
-    // used to generate a reference or pointer.
-    // See https://gpuweb.github.io/gpuweb/wgsl/#forming-references-and-pointers
-  }
-
-  /// Reduce walks the expression chain, collapsing all address-of and
-  /// indirection ops into a PointerOp.
-  /// @param in the expression to walk
-  /// @returns the reduced PointerOp
-  PointerOp Reduce(const ast::Expression* in) const {
-    PointerOp op{0, in};
-    while (true) {
-      if (auto* unary = op.expr->As<ast::UnaryOpExpression>()) {
-        switch (unary->op) {
-          case ast::UnaryOp::kIndirection:
-            op.indirections++;
-            op.expr = unary->expr;
-            continue;
-          case ast::UnaryOp::kAddressOf:
-            op.indirections--;
-            op.expr = unary->expr;
-            continue;
-          default:
-            break;
-        }
-      }
-      if (auto* user = ctx.src->Sem().Get<sem::VariableUser>(op.expr)) {
-        auto* var = user->Variable();
-        if (var->Is<sem::LocalVariable>() &&  //
-            var->Declaration()->is_const &&   //
-            var->Type()->Is<sem::Pointer>()) {
-          op.expr = var->Declaration()->constructor;
-          continue;
-        }
-      }
-      return op;
-    }
-  }
-
-  /// Performs the transformation
-  void Run() {
-    // A map of saved expressions to their saved variable name
-    std::unordered_map<const ast::Expression*, Symbol> saved_vars;
-
-    // Register the ast::Expression transform handler.
-    // This performs two different transformations:
-    // * Identifiers that resolve to the pointer-typed `let` declarations are
-    // replaced with the recursively inlined initializer expression for the
-    // `let` declaration.
-    // * Sub-expressions inside the pointer-typed `let` initializer expression
-    // that have been hoisted to a saved variable are replaced with the saved
-    // variable identifier.
-    ctx.ReplaceAll([&](const ast::Expression* expr) -> const ast::Expression* {
-      // Look to see if we need to swap this Expression with a saved variable.
-      auto it = saved_vars.find(expr);
-      if (it != saved_vars.end()) {
-        return ctx.dst->Expr(it->second);
-      }
-
-      // Reduce the expression, folding away chains of address-of / indirections
-      auto op = Reduce(expr);
-
-      // Clone the reduced root expression
-      expr = ctx.CloneWithoutTransform(op.expr);
-
-      // And reapply the minimum number of address-of / indirections
-      for (int i = 0; i < op.indirections; i++) {
-        expr = ctx.dst->Deref(expr);
-      }
-      for (int i = 0; i > op.indirections; i--) {
-        expr = ctx.dst->AddressOf(expr);
-      }
-      return expr;
-    });
-
-    // Find all the pointer-typed `let` declarations.
-    // Note that these must be function-scoped, as module-scoped `let`s are not
-    // permitted.
-    for (auto* node : ctx.src->ASTNodes().Objects()) {
-      if (auto* let = node->As<ast::VariableDeclStatement>()) {
-        if (!let->variable->is_const) {
-          continue;  // Not a `let` declaration. Ignore.
+    /// Traverses the expression `expr` looking for non-literal array indexing
+    /// expressions that would affect the computed address of a pointer
+    /// expression. The function-like argument `cb` is called for each found.
+    /// @param expr the expression to traverse
+    /// @param cb a function-like object with the signature
+    /// `void(const ast::Expression*)`, which is called for each array index
+    /// expression
+    template <typename F>
+    static void CollectSavedArrayIndices(const ast::Expression* expr, F&& cb) {
+        if (auto* a = expr->As<ast::IndexAccessorExpression>()) {
+            CollectSavedArrayIndices(a->object, cb);
+            if (!a->index->Is<ast::LiteralExpression>()) {
+                cb(a->index);
+            }
+            return;
         }
 
-        auto* var = ctx.src->Sem().Get(let->variable);
-        if (!var->Type()->Is<sem::Pointer>()) {
-          continue;  // Not a pointer type. Ignore.
+        if (auto* m = expr->As<ast::MemberAccessorExpression>()) {
+            CollectSavedArrayIndices(m->structure, cb);
+            return;
         }
 
-        // We're dealing with a pointer-typed `let` declaration.
-
-        // Scan the initializer expression for array index expressions that need
-        // to be hoist to temporary "saved" variables.
-        std::vector<const ast::VariableDeclStatement*> saved;
-        CollectSavedArrayIndices(
-            var->Declaration()->constructor,
-            [&](const ast::Expression* idx_expr) {
-              // We have a sub-expression that needs to be saved.
-              // Create a new variable
-              auto saved_name = ctx.dst->Symbols().New(
-                  ctx.src->Symbols().NameFor(var->Declaration()->symbol) +
-                  "_save");
-              auto* decl = ctx.dst->Decl(
-                  ctx.dst->Const(saved_name, nullptr, ctx.Clone(idx_expr)));
-              saved.emplace_back(decl);
-              // Record the substitution of `idx_expr` to the saved variable
-              // with the symbol `saved_name`. This will be used by the
-              // ReplaceAll() handler above.
-              saved_vars.emplace(idx_expr, saved_name);
-            });
-
-        // Find the place to insert the saved declarations.
-        // Special care needs to be made for lets declared as the initializer
-        // part of for-loops. In this case the block will hold the for-loop
-        // statement, not the let.
-        if (!saved.empty()) {
-          auto* stmt = ctx.src->Sem().Get(let);
-          auto* block = stmt->Block();
-          // Find the statement owned by the block (either the let decl or a
-          // for-loop)
-          while (block != stmt->Parent()) {
-            stmt = stmt->Parent();
-          }
-          // Declare the stored variables just before stmt. Order here is
-          // important as order-of-operations needs to be preserved.
-          // CollectSavedArrayIndices() visits the LHS of an index accessor
-          // before the index expression.
-          for (auto* decl : saved) {
-            // Note that repeated calls to InsertBefore() with the same `before`
-            // argument will result in nodes to inserted in the order the
-            // calls are made (last call is inserted last).
-            ctx.InsertBefore(block->Declaration()->statements,
-                             stmt->Declaration(), decl);
-          }
+        if (auto* u = expr->As<ast::UnaryOpExpression>()) {
+            CollectSavedArrayIndices(u->expr, cb);
+            return;
         }
 
-        // As the original `let` declaration will be fully inlined, there's no
-        // need for the original declaration to exist. Remove it.
-        RemoveStatement(ctx, let);
-      }
+        // Note: Other ast::Expression types can be safely ignored as they cannot be
+        // used to generate a reference or pointer.
+        // See https://gpuweb.github.io/gpuweb/wgsl/#forming-references-and-pointers
     }
-    ctx.Clone();
-  }
+
+    /// Reduce walks the expression chain, collapsing all address-of and
+    /// indirection ops into a PointerOp.
+    /// @param in the expression to walk
+    /// @returns the reduced PointerOp
+    PointerOp Reduce(const ast::Expression* in) const {
+        PointerOp op{0, in};
+        while (true) {
+            if (auto* unary = op.expr->As<ast::UnaryOpExpression>()) {
+                switch (unary->op) {
+                    case ast::UnaryOp::kIndirection:
+                        op.indirections++;
+                        op.expr = unary->expr;
+                        continue;
+                    case ast::UnaryOp::kAddressOf:
+                        op.indirections--;
+                        op.expr = unary->expr;
+                        continue;
+                    default:
+                        break;
+                }
+            }
+            if (auto* user = ctx.src->Sem().Get<sem::VariableUser>(op.expr)) {
+                auto* var = user->Variable();
+                if (var->Is<sem::LocalVariable>() &&  //
+                    var->Declaration()->is_const &&   //
+                    var->Type()->Is<sem::Pointer>()) {
+                    op.expr = var->Declaration()->constructor;
+                    continue;
+                }
+            }
+            return op;
+        }
+    }
+
+    /// Performs the transformation
+    void Run() {
+        // A map of saved expressions to their saved variable name
+        std::unordered_map<const ast::Expression*, Symbol> saved_vars;
+
+        // Register the ast::Expression transform handler.
+        // This performs two different transformations:
+        // * Identifiers that resolve to the pointer-typed `let` declarations are
+        // replaced with the recursively inlined initializer expression for the
+        // `let` declaration.
+        // * Sub-expressions inside the pointer-typed `let` initializer expression
+        // that have been hoisted to a saved variable are replaced with the saved
+        // variable identifier.
+        ctx.ReplaceAll([&](const ast::Expression* expr) -> const ast::Expression* {
+            // Look to see if we need to swap this Expression with a saved variable.
+            auto it = saved_vars.find(expr);
+            if (it != saved_vars.end()) {
+                return ctx.dst->Expr(it->second);
+            }
+
+            // Reduce the expression, folding away chains of address-of / indirections
+            auto op = Reduce(expr);
+
+            // Clone the reduced root expression
+            expr = ctx.CloneWithoutTransform(op.expr);
+
+            // And reapply the minimum number of address-of / indirections
+            for (int i = 0; i < op.indirections; i++) {
+                expr = ctx.dst->Deref(expr);
+            }
+            for (int i = 0; i > op.indirections; i--) {
+                expr = ctx.dst->AddressOf(expr);
+            }
+            return expr;
+        });
+
+        // Find all the pointer-typed `let` declarations.
+        // Note that these must be function-scoped, as module-scoped `let`s are not
+        // permitted.
+        for (auto* node : ctx.src->ASTNodes().Objects()) {
+            if (auto* let = node->As<ast::VariableDeclStatement>()) {
+                if (!let->variable->is_const) {
+                    continue;  // Not a `let` declaration. Ignore.
+                }
+
+                auto* var = ctx.src->Sem().Get(let->variable);
+                if (!var->Type()->Is<sem::Pointer>()) {
+                    continue;  // Not a pointer type. Ignore.
+                }
+
+                // We're dealing with a pointer-typed `let` declaration.
+
+                // Scan the initializer expression for array index expressions that need
+                // to be hoist to temporary "saved" variables.
+                std::vector<const ast::VariableDeclStatement*> saved;
+                CollectSavedArrayIndices(
+                    var->Declaration()->constructor, [&](const ast::Expression* idx_expr) {
+                        // We have a sub-expression that needs to be saved.
+                        // Create a new variable
+                        auto saved_name = ctx.dst->Symbols().New(
+                            ctx.src->Symbols().NameFor(var->Declaration()->symbol) + "_save");
+                        auto* decl =
+                            ctx.dst->Decl(ctx.dst->Let(saved_name, nullptr, ctx.Clone(idx_expr)));
+                        saved.emplace_back(decl);
+                        // Record the substitution of `idx_expr` to the saved variable
+                        // with the symbol `saved_name`. This will be used by the
+                        // ReplaceAll() handler above.
+                        saved_vars.emplace(idx_expr, saved_name);
+                    });
+
+                // Find the place to insert the saved declarations.
+                // Special care needs to be made for lets declared as the initializer
+                // part of for-loops. In this case the block will hold the for-loop
+                // statement, not the let.
+                if (!saved.empty()) {
+                    auto* stmt = ctx.src->Sem().Get(let);
+                    auto* block = stmt->Block();
+                    // Find the statement owned by the block (either the let decl or a
+                    // for-loop)
+                    while (block != stmt->Parent()) {
+                        stmt = stmt->Parent();
+                    }
+                    // Declare the stored variables just before stmt. Order here is
+                    // important as order-of-operations needs to be preserved.
+                    // CollectSavedArrayIndices() visits the LHS of an index accessor
+                    // before the index expression.
+                    for (auto* decl : saved) {
+                        // Note that repeated calls to InsertBefore() with the same `before`
+                        // argument will result in nodes to inserted in the order the
+                        // calls are made (last call is inserted last).
+                        ctx.InsertBefore(block->Declaration()->statements, stmt->Declaration(),
+                                         decl);
+                    }
+                }
+
+                // As the original `let` declaration will be fully inlined, there's no
+                // need for the original declaration to exist. Remove it.
+                RemoveStatement(ctx, let);
+            }
+        }
+        ctx.Clone();
+    }
 };
 
 SimplifyPointers::SimplifyPointers() = default;
@@ -231,7 +229,7 @@
 SimplifyPointers::~SimplifyPointers() = default;
 
 void SimplifyPointers::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
-  State(ctx).Run();
+    State(ctx).Run();
 }
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/simplify_pointers.h b/src/tint/transform/simplify_pointers.h
index 3bd4950..267b7b2 100644
--- a/src/tint/transform/simplify_pointers.h
+++ b/src/tint/transform/simplify_pointers.h
@@ -32,25 +32,23 @@
 /// @note Depends on the following transforms to have been run first:
 /// * Unshadow
 class SimplifyPointers : public Castable<SimplifyPointers, Transform> {
- public:
-  /// Constructor
-  SimplifyPointers();
+  public:
+    /// Constructor
+    SimplifyPointers();
 
-  /// Destructor
-  ~SimplifyPointers() override;
+    /// Destructor
+    ~SimplifyPointers() override;
 
- protected:
-  struct State;
+  protected:
+    struct State;
 
-  /// Runs the transform using the CloneContext built for transforming a
-  /// program. Run() is responsible for calling Clone() on the CloneContext.
-  /// @param ctx the CloneContext primed with the input program and
-  /// ProgramBuilder
-  /// @param inputs optional extra transform-specific input data
-  /// @param outputs optional extra transform-specific output data
-  void Run(CloneContext& ctx,
-           const DataMap& inputs,
-           DataMap& outputs) const override;
+    /// Runs the transform using the CloneContext built for transforming a
+    /// program. Run() is responsible for calling Clone() on the CloneContext.
+    /// @param ctx the CloneContext primed with the input program and
+    /// ProgramBuilder
+    /// @param inputs optional extra transform-specific input data
+    /// @param outputs optional extra transform-specific output data
+    void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const override;
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/simplify_pointers_test.cc b/src/tint/transform/simplify_pointers_test.cc
index 6266b6f..f5658de 100644
--- a/src/tint/transform/simplify_pointers_test.cc
+++ b/src/tint/transform/simplify_pointers_test.cc
@@ -23,16 +23,16 @@
 using SimplifyPointersTest = TransformTest;
 
 TEST_F(SimplifyPointersTest, EmptyModule) {
-  auto* src = "";
-  auto* expect = "";
+    auto* src = "";
+    auto* expect = "";
 
-  auto got = Run<Unshadow, SimplifyPointers>(src);
+    auto got = Run<Unshadow, SimplifyPointers>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(SimplifyPointersTest, FoldPointer) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var v : i32;
   let p : ptr<function, i32> = &v;
@@ -40,20 +40,20 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var v : i32;
   let x : i32 = v;
 }
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers>(src);
+    auto got = Run<Unshadow, SimplifyPointers>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(SimplifyPointersTest, AddressOfDeref) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var v : i32;
   let p : ptr<function, i32> = &(v);
@@ -66,7 +66,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var v : i32;
   var a = v;
@@ -75,13 +75,13 @@
 }
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers>(src);
+    auto got = Run<Unshadow, SimplifyPointers>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(SimplifyPointersTest, DerefAddressOf) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var v : i32;
   let x : i32 = *(&(v));
@@ -90,7 +90,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var v : i32;
   let x : i32 = v;
@@ -99,13 +99,13 @@
 }
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers>(src);
+    auto got = Run<Unshadow, SimplifyPointers>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(SimplifyPointersTest, ComplexChain) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var a : array<mat4x4<f32>, 4>;
   let ap : ptr<function, array<mat4x4<f32>, 4>> = &a;
@@ -115,20 +115,20 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var a : array<mat4x4<f32>, 4>;
   let v : vec4<f32> = a[3][2];
 }
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers>(src);
+    auto got = Run<Unshadow, SimplifyPointers>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(SimplifyPointersTest, SavedVars) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   i : i32,
 };
@@ -152,7 +152,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   i : i32,
 }
@@ -176,13 +176,13 @@
 }
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers>(src);
+    auto got = Run<Unshadow, SimplifyPointers>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(SimplifyPointersTest, DontSaveLiterals) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var arr : array<i32, 2>;
   let p1 : ptr<function, i32> = &arr[1];
@@ -190,20 +190,20 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var arr : array<i32, 2>;
   arr[1] = 4;
 }
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers>(src);
+    auto got = Run<Unshadow, SimplifyPointers>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(SimplifyPointersTest, SavedVarsChain) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var arr : array<array<i32, 2>, 2>;
   let i : i32 = 0;
@@ -214,7 +214,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var arr : array<array<i32, 2>, 2>;
   let i : i32 = 0;
@@ -225,13 +225,13 @@
 }
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers>(src);
+    auto got = Run<Unshadow, SimplifyPointers>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(SimplifyPointersTest, ForLoopInit) {
-  auto* src = R"(
+    auto* src = R"(
 fn foo() -> i32 {
   return 1;
 }
@@ -246,7 +246,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn foo() -> i32 {
   return 1;
 }
@@ -262,13 +262,13 @@
 }
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers>(src);
+    auto got = Run<Unshadow, SimplifyPointers>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(SimplifyPointersTest, MultiSavedVarsInSinglePtrLetExpr) {
-  auto* src = R"(
+    auto* src = R"(
 fn x() -> i32 {
   return 1;
 }
@@ -297,7 +297,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn x() -> i32 {
   return 1;
 }
@@ -328,13 +328,13 @@
 }
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers>(src);
+    auto got = Run<Unshadow, SimplifyPointers>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(SimplifyPointersTest, ShadowPointer) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> a : array<i32, 2>;
 
 @stage(compute) @workgroup_size(1)
@@ -347,7 +347,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> a : array<i32, 2>;
 
 @stage(compute) @workgroup_size(1)
@@ -359,9 +359,9 @@
 }
 )";
 
-  auto got = Run<Unshadow, SimplifyPointers>(src);
+    auto got = Run<Unshadow, SimplifyPointers>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 }  // namespace
diff --git a/src/tint/transform/single_entry_point.cc b/src/tint/transform/single_entry_point.cc
index fe92483..82324c7 100644
--- a/src/tint/transform/single_entry_point.cc
+++ b/src/tint/transform/single_entry_point.cc
@@ -30,86 +30,82 @@
 
 SingleEntryPoint::~SingleEntryPoint() = default;
 
-void SingleEntryPoint::Run(CloneContext& ctx,
-                           const DataMap& inputs,
-                           DataMap&) const {
-  auto* cfg = inputs.Get<Config>();
-  if (cfg == nullptr) {
-    ctx.dst->Diagnostics().add_error(
-        diag::System::Transform,
-        "missing transform data for " + std::string(TypeInfo().name));
+void SingleEntryPoint::Run(CloneContext& ctx, const DataMap& inputs, DataMap&) const {
+    auto* cfg = inputs.Get<Config>();
+    if (cfg == nullptr) {
+        ctx.dst->Diagnostics().add_error(
+            diag::System::Transform, "missing transform data for " + std::string(TypeInfo().name));
 
-    return;
-  }
-
-  // Find the target entry point.
-  const ast::Function* entry_point = nullptr;
-  for (auto* f : ctx.src->AST().Functions()) {
-    if (!f->IsEntryPoint()) {
-      continue;
+        return;
     }
-    if (ctx.src->Symbols().NameFor(f->symbol) == cfg->entry_point_name) {
-      entry_point = f;
-      break;
-    }
-  }
-  if (entry_point == nullptr) {
-    ctx.dst->Diagnostics().add_error(
-        diag::System::Transform,
-        "entry point '" + cfg->entry_point_name + "' not found");
-    return;
-  }
 
-  auto& sem = ctx.src->Sem();
-
-  // Build set of referenced module-scope variables for faster lookups later.
-  std::unordered_set<const ast::Variable*> referenced_vars;
-  for (auto* var : sem.Get(entry_point)->TransitivelyReferencedGlobals()) {
-    referenced_vars.emplace(var->Declaration());
-  }
-
-  // Clone any module-scope variables, types, and functions that are statically
-  // referenced by the target entry point.
-  for (auto* decl : ctx.src->AST().GlobalDeclarations()) {
-    if (auto* ty = decl->As<ast::TypeDecl>()) {
-      // TODO(jrprice): Strip unused types.
-      ctx.dst->AST().AddTypeDecl(ctx.Clone(ty));
-    } else if (auto* var = decl->As<ast::Variable>()) {
-      if (referenced_vars.count(var)) {
-        if (var->is_overridable) {
-          // It is an overridable constant
-          if (!ast::HasAttribute<ast::IdAttribute>(var->attributes)) {
-            // If the constant 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
-            auto* global = sem.Get(var)->As<sem::GlobalVariable>();
-            const auto* id = ctx.dst->Id(global->ConstantId());
-            ctx.InsertFront(var->attributes, id);
-          }
+    // Find the target entry point.
+    const ast::Function* entry_point = nullptr;
+    for (auto* f : ctx.src->AST().Functions()) {
+        if (!f->IsEntryPoint()) {
+            continue;
         }
-        ctx.dst->AST().AddGlobalVariable(ctx.Clone(var));
-      }
-    } else if (auto* func = decl->As<ast::Function>()) {
-      if (sem.Get(func)->HasAncestorEntryPoint(entry_point->symbol)) {
-        ctx.dst->AST().AddFunction(ctx.Clone(func));
-      }
-    } else {
-      TINT_UNREACHABLE(Transform, ctx.dst->Diagnostics())
-          << "unhandled global declaration: " << decl->TypeInfo().name;
-      return;
+        if (ctx.src->Symbols().NameFor(f->symbol) == cfg->entry_point_name) {
+            entry_point = f;
+            break;
+        }
     }
-  }
+    if (entry_point == nullptr) {
+        ctx.dst->Diagnostics().add_error(diag::System::Transform,
+                                         "entry point '" + cfg->entry_point_name + "' not found");
+        return;
+    }
 
-  // Clone the entry point.
-  ctx.dst->AST().AddFunction(ctx.Clone(entry_point));
+    auto& sem = ctx.src->Sem();
+
+    // Build set of referenced module-scope variables for faster lookups later.
+    std::unordered_set<const ast::Variable*> referenced_vars;
+    for (auto* var : sem.Get(entry_point)->TransitivelyReferencedGlobals()) {
+        referenced_vars.emplace(var->Declaration());
+    }
+
+    // Clone any module-scope variables, types, and functions that are statically
+    // referenced by the target entry point.
+    for (auto* decl : ctx.src->AST().GlobalDeclarations()) {
+        if (auto* ty = decl->As<ast::TypeDecl>()) {
+            // TODO(jrprice): Strip unused types.
+            ctx.dst->AST().AddTypeDecl(ctx.Clone(ty));
+        } else if (auto* var = decl->As<ast::Variable>()) {
+            if (referenced_vars.count(var)) {
+                if (var->is_overridable) {
+                    // It is an overridable constant
+                    if (!ast::HasAttribute<ast::IdAttribute>(var->attributes)) {
+                        // If the constant 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
+                        auto* global = sem.Get(var)->As<sem::GlobalVariable>();
+                        const auto* id = ctx.dst->Id(global->ConstantId());
+                        ctx.InsertFront(var->attributes, id);
+                    }
+                }
+                ctx.dst->AST().AddGlobalVariable(ctx.Clone(var));
+            }
+        } else if (auto* func = decl->As<ast::Function>()) {
+            if (sem.Get(func)->HasAncestorEntryPoint(entry_point->symbol)) {
+                ctx.dst->AST().AddFunction(ctx.Clone(func));
+            }
+        } else if (auto* ext = decl->As<ast::Enable>()) {
+            ctx.dst->AST().AddEnable(ctx.Clone(ext));
+        } else {
+            TINT_UNREACHABLE(Transform, ctx.dst->Diagnostics())
+                << "unhandled global declaration: " << decl->TypeInfo().name;
+            return;
+        }
+    }
+
+    // Clone the entry point.
+    ctx.dst->AST().AddFunction(ctx.Clone(entry_point));
 }
 
-SingleEntryPoint::Config::Config(std::string entry_point)
-    : entry_point_name(entry_point) {}
+SingleEntryPoint::Config::Config(std::string entry_point) : entry_point_name(entry_point) {}
 
 SingleEntryPoint::Config::Config(const Config&) = default;
 SingleEntryPoint::Config::~Config() = default;
-SingleEntryPoint::Config& SingleEntryPoint::Config::operator=(const Config&) =
-    default;
+SingleEntryPoint::Config& SingleEntryPoint::Config::operator=(const Config&) = default;
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/single_entry_point.h b/src/tint/transform/single_entry_point.h
index b5aed68..0a922a7 100644
--- a/src/tint/transform/single_entry_point.h
+++ b/src/tint/transform/single_entry_point.h
@@ -26,43 +26,41 @@
 /// All module-scope variables, types, and functions that are not used by the
 /// target entry point will also be removed.
 class SingleEntryPoint : public Castable<SingleEntryPoint, Transform> {
- public:
-  /// Configuration options for the transform
-  struct Config : public Castable<Config, Data> {
-    /// Constructor
-    /// @param entry_point the name of the entry point to keep
-    explicit Config(std::string entry_point = "");
+  public:
+    /// Configuration options for the transform
+    struct Config : public Castable<Config, Data> {
+        /// Constructor
+        /// @param entry_point the name of the entry point to keep
+        explicit Config(std::string entry_point = "");
 
-    /// Copy constructor
-    Config(const Config&);
+        /// Copy constructor
+        Config(const Config&);
+
+        /// Destructor
+        ~Config() override;
+
+        /// Assignment operator
+        /// @returns this Config
+        Config& operator=(const Config&);
+
+        /// The name of the entry point to keep.
+        std::string entry_point_name;
+    };
+
+    /// Constructor
+    SingleEntryPoint();
 
     /// Destructor
-    ~Config() override;
+    ~SingleEntryPoint() override;
 
-    /// Assignment operator
-    /// @returns this Config
-    Config& operator=(const Config&);
-
-    /// The name of the entry point to keep.
-    std::string entry_point_name;
-  };
-
-  /// Constructor
-  SingleEntryPoint();
-
-  /// Destructor
-  ~SingleEntryPoint() override;
-
- protected:
-  /// Runs the transform using the CloneContext built for transforming a
-  /// program. Run() is responsible for calling Clone() on the CloneContext.
-  /// @param ctx the CloneContext primed with the input program and
-  /// ProgramBuilder
-  /// @param inputs optional extra transform-specific input data
-  /// @param outputs optional extra transform-specific output data
-  void Run(CloneContext& ctx,
-           const DataMap& inputs,
-           DataMap& outputs) const override;
+  protected:
+    /// Runs the transform using the CloneContext built for transforming a
+    /// program. Run() is responsible for calling Clone() on the CloneContext.
+    /// @param ctx the CloneContext primed with the input program and
+    /// ProgramBuilder
+    /// @param inputs optional extra transform-specific input data
+    /// @param outputs optional extra transform-specific output data
+    void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const override;
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/single_entry_point_test.cc b/src/tint/transform/single_entry_point_test.cc
index 750f5c3..8044621 100644
--- a/src/tint/transform/single_entry_point_test.cc
+++ b/src/tint/transform/single_entry_point_test.cc
@@ -24,84 +24,83 @@
 using SingleEntryPointTest = TransformTest;
 
 TEST_F(SingleEntryPointTest, Error_MissingTransformData) {
-  auto* src = "";
+    auto* src = "";
 
-  auto* expect =
-      "error: missing transform data for tint::transform::SingleEntryPoint";
+    auto* expect = "error: missing transform data for tint::transform::SingleEntryPoint";
 
-  auto got = Run<SingleEntryPoint>(src);
+    auto got = Run<SingleEntryPoint>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(SingleEntryPointTest, Error_NoEntryPoints) {
-  auto* src = "";
+    auto* src = "";
 
-  auto* expect = "error: entry point 'main' not found";
+    auto* expect = "error: entry point 'main' not found";
 
-  DataMap data;
-  data.Add<SingleEntryPoint::Config>("main");
-  auto got = Run<SingleEntryPoint>(src, data);
+    DataMap data;
+    data.Add<SingleEntryPoint::Config>("main");
+    auto got = Run<SingleEntryPoint>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(SingleEntryPointTest, Error_InvalidEntryPoint) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(vertex)
 fn main() -> @builtin(position) vec4<f32> {
   return vec4<f32>();
 }
 )";
 
-  auto* expect = "error: entry point '_' not found";
+    auto* expect = "error: entry point '_' not found";
 
-  SingleEntryPoint::Config cfg("_");
+    SingleEntryPoint::Config cfg("_");
 
-  DataMap data;
-  data.Add<SingleEntryPoint::Config>(cfg);
-  auto got = Run<SingleEntryPoint>(src, data);
+    DataMap data;
+    data.Add<SingleEntryPoint::Config>(cfg);
+    auto got = Run<SingleEntryPoint>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(SingleEntryPointTest, Error_NotAnEntryPoint) {
-  auto* src = R"(
+    auto* src = R"(
 fn foo() {}
 
 @stage(fragment)
 fn main() {}
 )";
 
-  auto* expect = "error: entry point 'foo' not found";
+    auto* expect = "error: entry point 'foo' not found";
 
-  SingleEntryPoint::Config cfg("foo");
+    SingleEntryPoint::Config cfg("foo");
 
-  DataMap data;
-  data.Add<SingleEntryPoint::Config>(cfg);
-  auto got = Run<SingleEntryPoint>(src, data);
+    DataMap data;
+    data.Add<SingleEntryPoint::Config>(cfg);
+    auto got = Run<SingleEntryPoint>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(SingleEntryPointTest, SingleEntryPoint) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn main() {
 }
 )";
 
-  SingleEntryPoint::Config cfg("main");
+    SingleEntryPoint::Config cfg("main");
 
-  DataMap data;
-  data.Add<SingleEntryPoint::Config>(cfg);
-  auto got = Run<SingleEntryPoint>(src, data);
+    DataMap data;
+    data.Add<SingleEntryPoint::Config>(cfg);
+    auto got = Run<SingleEntryPoint>(src, data);
 
-  EXPECT_EQ(src, str(got));
+    EXPECT_EQ(src, str(got));
 }
 
 TEST_F(SingleEntryPointTest, MultipleEntryPoints) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(vertex)
 fn vert_main() -> @builtin(position) vec4<f32> {
   return vec4<f32>();
@@ -120,23 +119,23 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 @stage(compute) @workgroup_size(1)
 fn comp_main1() {
 }
 )";
 
-  SingleEntryPoint::Config cfg("comp_main1");
+    SingleEntryPoint::Config cfg("comp_main1");
 
-  DataMap data;
-  data.Add<SingleEntryPoint::Config>(cfg);
-  auto got = Run<SingleEntryPoint>(src, data);
+    DataMap data;
+    data.Add<SingleEntryPoint::Config>(cfg);
+    auto got = Run<SingleEntryPoint>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(SingleEntryPointTest, GlobalVariables) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> a : f32;
 
 var<private> b : f32;
@@ -167,7 +166,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> c : f32;
 
 @stage(compute) @workgroup_size(1)
@@ -176,17 +175,17 @@
 }
 )";
 
-  SingleEntryPoint::Config cfg("comp_main1");
+    SingleEntryPoint::Config cfg("comp_main1");
 
-  DataMap data;
-  data.Add<SingleEntryPoint::Config>(cfg);
-  auto got = Run<SingleEntryPoint>(src, data);
+    DataMap data;
+    data.Add<SingleEntryPoint::Config>(cfg);
+    auto got = Run<SingleEntryPoint>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(SingleEntryPointTest, GlobalConstants) {
-  auto* src = R"(
+    auto* src = R"(
 let a : f32 = 1.0;
 
 let b : f32 = 1.0;
@@ -217,7 +216,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 let c : f32 = 1.0;
 
 @stage(compute) @workgroup_size(1)
@@ -226,17 +225,17 @@
 }
 )";
 
-  SingleEntryPoint::Config cfg("comp_main1");
+    SingleEntryPoint::Config cfg("comp_main1");
 
-  DataMap data;
-  data.Add<SingleEntryPoint::Config>(cfg);
-  auto got = Run<SingleEntryPoint>(src, data);
+    DataMap data;
+    data.Add<SingleEntryPoint::Config>(cfg);
+    auto got = Run<SingleEntryPoint>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(SingleEntryPointTest, WorkgroupSizeLetPreserved) {
-  auto* src = R"(
+    auto* src = R"(
 let size : i32 = 1;
 
 @stage(compute) @workgroup_size(size)
@@ -244,19 +243,19 @@
 }
 )";
 
-  auto* expect = src;
+    auto* expect = src;
 
-  SingleEntryPoint::Config cfg("main");
+    SingleEntryPoint::Config cfg("main");
 
-  DataMap data;
-  data.Add<SingleEntryPoint::Config>(cfg);
-  auto got = Run<SingleEntryPoint>(src, data);
+    DataMap data;
+    data.Add<SingleEntryPoint::Config>(cfg);
+    auto got = Run<SingleEntryPoint>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(SingleEntryPointTest, OverridableConstants) {
-  auto* src = R"(
+    auto* src = R"(
 @id(1001) override c1 : u32 = 1u;
           override c2 : u32 = 1u;
 @id(0)    override c3 : u32 = 1u;
@@ -288,9 +287,9 @@
 }
 )";
 
-  {
-    SingleEntryPoint::Config cfg("comp_main1");
-    auto* expect = R"(
+    {
+        SingleEntryPoint::Config cfg("comp_main1");
+        auto* expect = R"(
 @id(1001) override c1 : u32 = 1u;
 
 @stage(compute) @workgroup_size(1)
@@ -298,17 +297,17 @@
   let local_d = c1;
 }
 )";
-    DataMap data;
-    data.Add<SingleEntryPoint::Config>(cfg);
-    auto got = Run<SingleEntryPoint>(src, data);
-    EXPECT_EQ(expect, str(got));
-  }
+        DataMap data;
+        data.Add<SingleEntryPoint::Config>(cfg);
+        auto got = Run<SingleEntryPoint>(src, data);
+        EXPECT_EQ(expect, str(got));
+    }
 
-  {
-    SingleEntryPoint::Config cfg("comp_main2");
-    // The decorator is replaced with the one with explicit id
-    // And should not be affected by other constants stripped away
-    auto* expect = R"(
+    {
+        SingleEntryPoint::Config cfg("comp_main2");
+        // The decorator is replaced with the one with explicit id
+        // And should not be affected by other constants stripped away
+        auto* expect = R"(
 @id(1) override c2 : u32 = 1u;
 
 @stage(compute) @workgroup_size(1)
@@ -316,15 +315,15 @@
   let local_d = c2;
 }
 )";
-    DataMap data;
-    data.Add<SingleEntryPoint::Config>(cfg);
-    auto got = Run<SingleEntryPoint>(src, data);
-    EXPECT_EQ(expect, str(got));
-  }
+        DataMap data;
+        data.Add<SingleEntryPoint::Config>(cfg);
+        auto got = Run<SingleEntryPoint>(src, data);
+        EXPECT_EQ(expect, str(got));
+    }
 
-  {
-    SingleEntryPoint::Config cfg("comp_main3");
-    auto* expect = R"(
+    {
+        SingleEntryPoint::Config cfg("comp_main3");
+        auto* expect = R"(
 @id(0) override c3 : u32 = 1u;
 
 @stage(compute) @workgroup_size(1)
@@ -332,15 +331,15 @@
   let local_d = c3;
 }
 )";
-    DataMap data;
-    data.Add<SingleEntryPoint::Config>(cfg);
-    auto got = Run<SingleEntryPoint>(src, data);
-    EXPECT_EQ(expect, str(got));
-  }
+        DataMap data;
+        data.Add<SingleEntryPoint::Config>(cfg);
+        auto got = Run<SingleEntryPoint>(src, data);
+        EXPECT_EQ(expect, str(got));
+    }
 
-  {
-    SingleEntryPoint::Config cfg("comp_main4");
-    auto* expect = R"(
+    {
+        SingleEntryPoint::Config cfg("comp_main4");
+        auto* expect = R"(
 @id(9999) override c4 : u32 = 1u;
 
 @stage(compute) @workgroup_size(1)
@@ -348,29 +347,29 @@
   let local_d = c4;
 }
 )";
-    DataMap data;
-    data.Add<SingleEntryPoint::Config>(cfg);
-    auto got = Run<SingleEntryPoint>(src, data);
-    EXPECT_EQ(expect, str(got));
-  }
+        DataMap data;
+        data.Add<SingleEntryPoint::Config>(cfg);
+        auto got = Run<SingleEntryPoint>(src, data);
+        EXPECT_EQ(expect, str(got));
+    }
 
-  {
-    SingleEntryPoint::Config cfg("comp_main5");
-    auto* expect = R"(
+    {
+        SingleEntryPoint::Config cfg("comp_main5");
+        auto* expect = R"(
 @stage(compute) @workgroup_size(1)
 fn comp_main5() {
   let local_d = 1u;
 }
 )";
-    DataMap data;
-    data.Add<SingleEntryPoint::Config>(cfg);
-    auto got = Run<SingleEntryPoint>(src, data);
-    EXPECT_EQ(expect, str(got));
-  }
+        DataMap data;
+        data.Add<SingleEntryPoint::Config>(cfg);
+        auto got = Run<SingleEntryPoint>(src, data);
+        EXPECT_EQ(expect, str(got));
+    }
 }
 
 TEST_F(SingleEntryPointTest, CalledFunctions) {
-  auto* src = R"(
+    auto* src = R"(
 fn inner1() {
 }
 
@@ -401,7 +400,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn inner1() {
 }
 
@@ -419,17 +418,17 @@
 }
 )";
 
-  SingleEntryPoint::Config cfg("comp_main1");
+    SingleEntryPoint::Config cfg("comp_main1");
 
-  DataMap data;
-  data.Add<SingleEntryPoint::Config>(cfg);
-  auto got = Run<SingleEntryPoint>(src, data);
+    DataMap data;
+    data.Add<SingleEntryPoint::Config>(cfg);
+    auto got = Run<SingleEntryPoint>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(SingleEntryPointTest, GlobalsReferencedByCalledFunctions) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> inner1_var : f32;
 
 var<private> inner2_var : f32;
@@ -475,7 +474,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> inner1_var : f32;
 
 var<private> inner_shared_var : f32;
@@ -502,13 +501,13 @@
 }
 )";
 
-  SingleEntryPoint::Config cfg("comp_main1");
+    SingleEntryPoint::Config cfg("comp_main1");
 
-  DataMap data;
-  data.Add<SingleEntryPoint::Config>(cfg);
-  auto got = Run<SingleEntryPoint>(src, data);
+    DataMap data;
+    data.Add<SingleEntryPoint::Config>(cfg);
+    auto got = Run<SingleEntryPoint>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 }  // namespace
diff --git a/src/tint/transform/test_helper.h b/src/tint/transform/test_helper.h
index 7d7015c..42218a7 100644
--- a/src/tint/transform/test_helper.h
+++ b/src/tint/transform/test_helper.h
@@ -31,115 +31,112 @@
 /// @returns the output program as a WGSL string, or an error string if the
 /// program is not valid.
 inline std::string str(const Program& program) {
-  diag::Formatter::Style style;
-  style.print_newline_at_end = false;
+    diag::Formatter::Style style;
+    style.print_newline_at_end = false;
 
-  if (!program.IsValid()) {
-    return diag::Formatter(style).format(program.Diagnostics());
-  }
+    if (!program.IsValid()) {
+        return diag::Formatter(style).format(program.Diagnostics());
+    }
 
-  writer::wgsl::Options options;
-  auto result = writer::wgsl::Generate(&program, options);
-  if (!result.success) {
-    return "WGSL writer failed:\n" + result.error;
-  }
+    writer::wgsl::Options options;
+    auto result = writer::wgsl::Generate(&program, options);
+    if (!result.success) {
+        return "WGSL writer failed:\n" + result.error;
+    }
 
-  auto res = result.wgsl;
-  if (res.empty()) {
-    return res;
-  }
-  // The WGSL sometimes has two trailing newlines. Strip them
-  while (res.back() == '\n') {
-    res.pop_back();
-  }
-  if (res.empty()) {
-    return res;
-  }
-  return "\n" + res + "\n";
+    auto res = result.wgsl;
+    if (res.empty()) {
+        return res;
+    }
+    // The WGSL sometimes has two trailing newlines. Strip them
+    while (res.back() == '\n') {
+        res.pop_back();
+    }
+    if (res.empty()) {
+        return res;
+    }
+    return "\n" + res + "\n";
 }
 
 /// Helper class for testing transforms
 template <typename BASE>
 class TransformTestBase : public BASE {
- public:
-  /// Transforms and returns the WGSL source `in`, transformed using
-  /// `transform`.
-  /// @param transform the transform to apply
-  /// @param in the input WGSL source
-  /// @param data the optional DataMap to pass to Transform::Run()
-  /// @return the transformed output
-  Output Run(std::string in,
-             std::unique_ptr<transform::Transform> transform,
-             const DataMap& data = {}) {
-    std::vector<std::unique_ptr<transform::Transform>> transforms;
-    transforms.emplace_back(std::move(transform));
-    return Run(std::move(in), std::move(transforms), data);
-  }
-
-  /// Transforms and returns the WGSL source `in`, transformed using
-  /// a transform of type `TRANSFORM`.
-  /// @param in the input WGSL source
-  /// @param data the optional DataMap to pass to Transform::Run()
-  /// @return the transformed output
-  template <typename... TRANSFORMS>
-  Output Run(std::string in, const DataMap& data = {}) {
-    auto file = std::make_unique<Source::File>("test", in);
-    auto program = reader::wgsl::Parse(file.get());
-
-    // Keep this pointer alive after Transform() returns
-    files_.emplace_back(std::move(file));
-
-    return Run<TRANSFORMS...>(std::move(program), data);
-  }
-
-  /// Transforms and returns program `program`, transformed using a transform of
-  /// type `TRANSFORM`.
-  /// @param program the input Program
-  /// @param data the optional DataMap to pass to Transform::Run()
-  /// @return the transformed output
-  template <typename... TRANSFORMS>
-  Output Run(Program&& program, const DataMap& data = {}) {
-    if (!program.IsValid()) {
-      return Output(std::move(program));
+  public:
+    /// Transforms and returns the WGSL source `in`, transformed using
+    /// `transform`.
+    /// @param transform the transform to apply
+    /// @param in the input WGSL source
+    /// @param data the optional DataMap to pass to Transform::Run()
+    /// @return the transformed output
+    Output Run(std::string in,
+               std::unique_ptr<transform::Transform> transform,
+               const DataMap& data = {}) {
+        std::vector<std::unique_ptr<transform::Transform>> transforms;
+        transforms.emplace_back(std::move(transform));
+        return Run(std::move(in), std::move(transforms), data);
     }
 
-    Manager manager;
-    for (auto* transform_ptr :
-         std::initializer_list<Transform*>{new TRANSFORMS()...}) {
-      manager.append(std::unique_ptr<Transform>(transform_ptr));
+    /// Transforms and returns the WGSL source `in`, transformed using
+    /// a transform of type `TRANSFORM`.
+    /// @param in the input WGSL source
+    /// @param data the optional DataMap to pass to Transform::Run()
+    /// @return the transformed output
+    template <typename... TRANSFORMS>
+    Output Run(std::string in, const DataMap& data = {}) {
+        auto file = std::make_unique<Source::File>("test", in);
+        auto program = reader::wgsl::Parse(file.get());
+
+        // Keep this pointer alive after Transform() returns
+        files_.emplace_back(std::move(file));
+
+        return Run<TRANSFORMS...>(std::move(program), data);
     }
-    return manager.Run(&program, data);
-  }
 
-  /// @param program the input program
-  /// @param data the optional DataMap to pass to Transform::Run()
-  /// @return true if the transform should be run for the given input.
-  template <typename TRANSFORM>
-  bool ShouldRun(Program&& program, const DataMap& data = {}) {
-    EXPECT_TRUE(program.IsValid()) << program.Diagnostics().str();
-    const Transform& t = TRANSFORM();
-    return t.ShouldRun(&program, data);
-  }
+    /// Transforms and returns program `program`, transformed using a transform of
+    /// type `TRANSFORM`.
+    /// @param program the input Program
+    /// @param data the optional DataMap to pass to Transform::Run()
+    /// @return the transformed output
+    template <typename... TRANSFORMS>
+    Output Run(Program&& program, const DataMap& data = {}) {
+        if (!program.IsValid()) {
+            return Output(std::move(program));
+        }
 
-  /// @param in the input WGSL source
-  /// @param data the optional DataMap to pass to Transform::Run()
-  /// @return true if the transform should be run for the given input.
-  template <typename TRANSFORM>
-  bool ShouldRun(std::string in, const DataMap& data = {}) {
-    auto file = std::make_unique<Source::File>("test", in);
-    auto program = reader::wgsl::Parse(file.get());
-    return ShouldRun<TRANSFORM>(std::move(program), data);
-  }
+        Manager manager;
+        for (auto* transform_ptr : std::initializer_list<Transform*>{new TRANSFORMS()...}) {
+            manager.append(std::unique_ptr<Transform>(transform_ptr));
+        }
+        return manager.Run(&program, data);
+    }
 
-  /// @param output the output of the transform
-  /// @returns the output program as a WGSL string, or an error string if the
-  /// program is not valid.
-  std::string str(const Output& output) {
-    return transform::str(output.program);
-  }
+    /// @param program the input program
+    /// @param data the optional DataMap to pass to Transform::Run()
+    /// @return true if the transform should be run for the given input.
+    template <typename TRANSFORM>
+    bool ShouldRun(Program&& program, const DataMap& data = {}) {
+        EXPECT_TRUE(program.IsValid()) << program.Diagnostics().str();
+        const Transform& t = TRANSFORM();
+        return t.ShouldRun(&program, data);
+    }
 
- private:
-  std::vector<std::unique_ptr<Source::File>> files_;
+    /// @param in the input WGSL source
+    /// @param data the optional DataMap to pass to Transform::Run()
+    /// @return true if the transform should be run for the given input.
+    template <typename TRANSFORM>
+    bool ShouldRun(std::string in, const DataMap& data = {}) {
+        auto file = std::make_unique<Source::File>("test", in);
+        auto program = reader::wgsl::Parse(file.get());
+        return ShouldRun<TRANSFORM>(std::move(program), data);
+    }
+
+    /// @param output the output of the transform
+    /// @returns the output program as a WGSL string, or an error string if the
+    /// program is not valid.
+    std::string str(const Output& output) { return transform::str(output.program); }
+
+  private:
+    std::vector<std::unique_ptr<Source::File>> files_;
 };
 
 using TransformTest = TransformTestBase<testing::Test>;
diff --git a/src/tint/transform/transform.cc b/src/tint/transform/transform.cc
index 018bc95..e3d0ea9 100644
--- a/src/tint/transform/transform.cc
+++ b/src/tint/transform/transform.cc
@@ -18,12 +18,12 @@
 #include <string>
 
 #include "src/tint/program_builder.h"
-#include "src/tint/sem/atomic_type.h"
+#include "src/tint/sem/atomic.h"
 #include "src/tint/sem/block_statement.h"
-#include "src/tint/sem/depth_multisampled_texture_type.h"
+#include "src/tint/sem/depth_multisampled_texture.h"
 #include "src/tint/sem/for_loop_statement.h"
-#include "src/tint/sem/reference_type.h"
-#include "src/tint/sem/sampler_type.h"
+#include "src/tint/sem/reference.h"
+#include "src/tint/sem/sampler.h"
 
 TINT_INSTANTIATE_TYPEINFO(tint::transform::Transform);
 TINT_INSTANTIATE_TYPEINFO(tint::transform::Data);
@@ -45,114 +45,109 @@
 Transform::Transform() = default;
 Transform::~Transform() = default;
 
-Output Transform::Run(const Program* program,
-                      const DataMap& data /* = {} */) const {
-  ProgramBuilder builder;
-  CloneContext ctx(&builder, program);
-  Output output;
-  Run(ctx, data, output.data);
-  output.program = Program(std::move(builder));
-  return output;
+Output Transform::Run(const Program* program, const DataMap& data /* = {} */) const {
+    ProgramBuilder builder;
+    CloneContext ctx(&builder, program);
+    Output output;
+    Run(ctx, data, output.data);
+    output.program = Program(std::move(builder));
+    return output;
 }
 
 void Transform::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
-  TINT_UNIMPLEMENTED(Transform, ctx.dst->Diagnostics())
-      << "Transform::Run() unimplemented for " << TypeInfo().name;
+    TINT_UNIMPLEMENTED(Transform, ctx.dst->Diagnostics())
+        << "Transform::Run() unimplemented for " << TypeInfo().name;
 }
 
 bool Transform::ShouldRun(const Program*, const DataMap&) const {
-  return true;
+    return true;
 }
 
 void Transform::RemoveStatement(CloneContext& ctx, const ast::Statement* stmt) {
-  auto* sem = ctx.src->Sem().Get(stmt);
-  if (auto* block = tint::As<sem::BlockStatement>(sem->Parent())) {
-    ctx.Remove(block->Declaration()->statements, stmt);
-    return;
-  }
-  if (tint::Is<sem::ForLoopStatement>(sem->Parent())) {
-    ctx.Replace(stmt, static_cast<ast::Expression*>(nullptr));
-    return;
-  }
-  TINT_ICE(Transform, ctx.dst->Diagnostics())
-      << "unable to remove statement from parent of type "
-      << sem->TypeInfo().name;
+    auto* sem = ctx.src->Sem().Get(stmt);
+    if (auto* block = tint::As<sem::BlockStatement>(sem->Parent())) {
+        ctx.Remove(block->Declaration()->statements, stmt);
+        return;
+    }
+    if (tint::Is<sem::ForLoopStatement>(sem->Parent())) {
+        ctx.Replace(stmt, static_cast<ast::Expression*>(nullptr));
+        return;
+    }
+    TINT_ICE(Transform, ctx.dst->Diagnostics())
+        << "unable to remove statement from parent of type " << sem->TypeInfo().name;
 }
 
-const ast::Type* Transform::CreateASTTypeFor(CloneContext& ctx,
-                                             const sem::Type* ty) {
-  if (ty->Is<sem::Void>()) {
-    return ctx.dst->create<ast::Void>();
-  }
-  if (ty->Is<sem::I32>()) {
-    return ctx.dst->create<ast::I32>();
-  }
-  if (ty->Is<sem::U32>()) {
-    return ctx.dst->create<ast::U32>();
-  }
-  if (ty->Is<sem::F32>()) {
-    return ctx.dst->create<ast::F32>();
-  }
-  if (ty->Is<sem::Bool>()) {
-    return ctx.dst->create<ast::Bool>();
-  }
-  if (auto* m = ty->As<sem::Matrix>()) {
-    auto* el = CreateASTTypeFor(ctx, m->type());
-    return ctx.dst->create<ast::Matrix>(el, m->rows(), m->columns());
-  }
-  if (auto* v = ty->As<sem::Vector>()) {
-    auto* el = CreateASTTypeFor(ctx, v->type());
-    return ctx.dst->create<ast::Vector>(el, v->Width());
-  }
-  if (auto* a = ty->As<sem::Array>()) {
-    auto* el = CreateASTTypeFor(ctx, a->ElemType());
-    ast::AttributeList attrs;
-    if (!a->IsStrideImplicit()) {
-      attrs.emplace_back(ctx.dst->create<ast::StrideAttribute>(a->Stride()));
+const ast::Type* Transform::CreateASTTypeFor(CloneContext& ctx, const sem::Type* ty) {
+    if (ty->Is<sem::Void>()) {
+        return ctx.dst->create<ast::Void>();
     }
-    if (a->IsRuntimeSized()) {
-      return ctx.dst->ty.array(el, nullptr, std::move(attrs));
-    } else {
-      return ctx.dst->ty.array(el, a->Count(), std::move(attrs));
+    if (ty->Is<sem::I32>()) {
+        return ctx.dst->create<ast::I32>();
     }
-  }
-  if (auto* s = ty->As<sem::Struct>()) {
-    return ctx.dst->create<ast::TypeName>(ctx.Clone(s->Declaration()->name));
-  }
-  if (auto* s = ty->As<sem::Reference>()) {
-    return CreateASTTypeFor(ctx, s->StoreType());
-  }
-  if (auto* a = ty->As<sem::Atomic>()) {
-    return ctx.dst->create<ast::Atomic>(CreateASTTypeFor(ctx, a->Type()));
-  }
-  if (auto* t = ty->As<sem::DepthTexture>()) {
-    return ctx.dst->create<ast::DepthTexture>(t->dim());
-  }
-  if (auto* t = ty->As<sem::DepthMultisampledTexture>()) {
-    return ctx.dst->create<ast::DepthMultisampledTexture>(t->dim());
-  }
-  if (ty->Is<sem::ExternalTexture>()) {
-    return ctx.dst->create<ast::ExternalTexture>();
-  }
-  if (auto* t = ty->As<sem::MultisampledTexture>()) {
-    return ctx.dst->create<ast::MultisampledTexture>(
-        t->dim(), CreateASTTypeFor(ctx, t->type()));
-  }
-  if (auto* t = ty->As<sem::SampledTexture>()) {
-    return ctx.dst->create<ast::SampledTexture>(
-        t->dim(), CreateASTTypeFor(ctx, t->type()));
-  }
-  if (auto* t = ty->As<sem::StorageTexture>()) {
-    return ctx.dst->create<ast::StorageTexture>(
-        t->dim(), t->texel_format(), CreateASTTypeFor(ctx, t->type()),
-        t->access());
-  }
-  if (auto* s = ty->As<sem::Sampler>()) {
-    return ctx.dst->create<ast::Sampler>(s->kind());
-  }
-  TINT_UNREACHABLE(Transform, ctx.dst->Diagnostics())
-      << "Unhandled type: " << ty->TypeInfo().name;
-  return nullptr;
+    if (ty->Is<sem::U32>()) {
+        return ctx.dst->create<ast::U32>();
+    }
+    if (ty->Is<sem::F32>()) {
+        return ctx.dst->create<ast::F32>();
+    }
+    if (ty->Is<sem::Bool>()) {
+        return ctx.dst->create<ast::Bool>();
+    }
+    if (auto* m = ty->As<sem::Matrix>()) {
+        auto* el = CreateASTTypeFor(ctx, m->type());
+        return ctx.dst->create<ast::Matrix>(el, m->rows(), m->columns());
+    }
+    if (auto* v = ty->As<sem::Vector>()) {
+        auto* el = CreateASTTypeFor(ctx, v->type());
+        return ctx.dst->create<ast::Vector>(el, v->Width());
+    }
+    if (auto* a = ty->As<sem::Array>()) {
+        auto* el = CreateASTTypeFor(ctx, a->ElemType());
+        ast::AttributeList attrs;
+        if (!a->IsStrideImplicit()) {
+            attrs.emplace_back(ctx.dst->create<ast::StrideAttribute>(a->Stride()));
+        }
+        if (a->IsRuntimeSized()) {
+            return ctx.dst->ty.array(el, nullptr, std::move(attrs));
+        } else {
+            return ctx.dst->ty.array(el, u32(a->Count()), std::move(attrs));
+        }
+    }
+    if (auto* s = ty->As<sem::Struct>()) {
+        return ctx.dst->create<ast::TypeName>(ctx.Clone(s->Declaration()->name));
+    }
+    if (auto* s = ty->As<sem::Reference>()) {
+        return CreateASTTypeFor(ctx, s->StoreType());
+    }
+    if (auto* a = ty->As<sem::Atomic>()) {
+        return ctx.dst->create<ast::Atomic>(CreateASTTypeFor(ctx, a->Type()));
+    }
+    if (auto* t = ty->As<sem::DepthTexture>()) {
+        return ctx.dst->create<ast::DepthTexture>(t->dim());
+    }
+    if (auto* t = ty->As<sem::DepthMultisampledTexture>()) {
+        return ctx.dst->create<ast::DepthMultisampledTexture>(t->dim());
+    }
+    if (ty->Is<sem::ExternalTexture>()) {
+        return ctx.dst->create<ast::ExternalTexture>();
+    }
+    if (auto* t = ty->As<sem::MultisampledTexture>()) {
+        return ctx.dst->create<ast::MultisampledTexture>(t->dim(),
+                                                         CreateASTTypeFor(ctx, t->type()));
+    }
+    if (auto* t = ty->As<sem::SampledTexture>()) {
+        return ctx.dst->create<ast::SampledTexture>(t->dim(), CreateASTTypeFor(ctx, t->type()));
+    }
+    if (auto* t = ty->As<sem::StorageTexture>()) {
+        return ctx.dst->create<ast::StorageTexture>(t->dim(), t->texel_format(),
+                                                    CreateASTTypeFor(ctx, t->type()), t->access());
+    }
+    if (auto* s = ty->As<sem::Sampler>()) {
+        return ctx.dst->create<ast::Sampler>(s->kind());
+    }
+    TINT_UNREACHABLE(Transform, ctx.dst->Diagnostics())
+        << "Unhandled type: " << ty->TypeInfo().name;
+    return nullptr;
 }
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/transform.h b/src/tint/transform/transform.h
index 0a3b4f0..de57617 100644
--- a/src/tint/transform/transform.h
+++ b/src/tint/transform/transform.h
@@ -27,176 +27,171 @@
 /// Data is the base class for transforms that accept extra input or emit extra
 /// output information along with a Program.
 class Data : public Castable<Data> {
- public:
-  /// Constructor
-  Data();
+  public:
+    /// Constructor
+    Data();
 
-  /// Copy constructor
-  Data(const Data&);
+    /// Copy constructor
+    Data(const Data&);
 
-  /// Destructor
-  ~Data() override;
+    /// Destructor
+    ~Data() override;
 
-  /// Assignment operator
-  /// @returns this Data
-  Data& operator=(const Data&);
+    /// Assignment operator
+    /// @returns this Data
+    Data& operator=(const Data&);
 };
 
 /// DataMap is a map of Data unique pointers keyed by the Data's ClassID.
 class DataMap {
- public:
-  /// Constructor
-  DataMap();
+  public:
+    /// Constructor
+    DataMap();
 
-  /// Move constructor
-  DataMap(DataMap&&);
+    /// Move constructor
+    DataMap(DataMap&&);
 
-  /// Constructor
-  /// @param data_unique_ptrs a variadic list of additional data unique_ptrs
-  /// produced by the transform
-  template <typename... DATA>
-  explicit DataMap(DATA... data_unique_ptrs) {
-    PutAll(std::forward<DATA>(data_unique_ptrs)...);
-  }
-
-  /// Destructor
-  ~DataMap();
-
-  /// Move assignment operator
-  /// @param rhs the DataMap to move into this DataMap
-  /// @return this DataMap
-  DataMap& operator=(DataMap&& rhs);
-
-  /// Adds the data into DataMap keyed by the ClassID of type T.
-  /// @param data the data to add to the DataMap
-  template <typename T>
-  void Put(std::unique_ptr<T>&& data) {
-    static_assert(std::is_base_of<Data, T>::value,
-                  "T does not derive from Data");
-    map_[&TypeInfo::Of<T>()] = std::move(data);
-  }
-
-  /// Creates the data of type `T` with the provided arguments and adds it into
-  /// DataMap keyed by the ClassID of type T.
-  /// @param args the arguments forwarded to the constructor for type T
-  template <typename T, typename... ARGS>
-  void Add(ARGS&&... args) {
-    Put(std::make_unique<T>(std::forward<ARGS>(args)...));
-  }
-
-  /// @returns a pointer to the Data placed into the DataMap with a call to
-  /// Put()
-  template <typename T>
-  T const* Get() const {
-    return const_cast<DataMap*>(this)->Get<T>();
-  }
-
-  /// @returns a pointer to the Data placed into the DataMap with a call to
-  /// Put()
-  template <typename T>
-  T* Get() {
-    auto it = map_.find(&TypeInfo::Of<T>());
-    if (it == map_.end()) {
-      return nullptr;
+    /// Constructor
+    /// @param data_unique_ptrs a variadic list of additional data unique_ptrs
+    /// produced by the transform
+    template <typename... DATA>
+    explicit DataMap(DATA... data_unique_ptrs) {
+        PutAll(std::forward<DATA>(data_unique_ptrs)...);
     }
-    return static_cast<T*>(it->second.get());
-  }
 
-  /// Add moves all the data from other into this DataMap
-  /// @param other the DataMap to move into this DataMap
-  void Add(DataMap&& other) {
-    for (auto& it : other.map_) {
-      map_.emplace(it.first, std::move(it.second));
+    /// Destructor
+    ~DataMap();
+
+    /// Move assignment operator
+    /// @param rhs the DataMap to move into this DataMap
+    /// @return this DataMap
+    DataMap& operator=(DataMap&& rhs);
+
+    /// Adds the data into DataMap keyed by the ClassID of type T.
+    /// @param data the data to add to the DataMap
+    template <typename T>
+    void Put(std::unique_ptr<T>&& data) {
+        static_assert(std::is_base_of<Data, T>::value, "T does not derive from Data");
+        map_[&TypeInfo::Of<T>()] = std::move(data);
     }
-    other.map_.clear();
-  }
 
- private:
-  template <typename T0>
-  void PutAll(T0&& first) {
-    Put(std::forward<T0>(first));
-  }
+    /// Creates the data of type `T` with the provided arguments and adds it into
+    /// DataMap keyed by the ClassID of type T.
+    /// @param args the arguments forwarded to the constructor for type T
+    template <typename T, typename... ARGS>
+    void Add(ARGS&&... args) {
+        Put(std::make_unique<T>(std::forward<ARGS>(args)...));
+    }
 
-  template <typename T0, typename... Tn>
-  void PutAll(T0&& first, Tn&&... remainder) {
-    Put(std::forward<T0>(first));
-    PutAll(std::forward<Tn>(remainder)...);
-  }
+    /// @returns a pointer to the Data placed into the DataMap with a call to
+    /// Put()
+    template <typename T>
+    T const* Get() const {
+        return const_cast<DataMap*>(this)->Get<T>();
+    }
 
-  std::unordered_map<const TypeInfo*, std::unique_ptr<Data>> map_;
+    /// @returns a pointer to the Data placed into the DataMap with a call to
+    /// Put()
+    template <typename T>
+    T* Get() {
+        auto it = map_.find(&TypeInfo::Of<T>());
+        if (it == map_.end()) {
+            return nullptr;
+        }
+        return static_cast<T*>(it->second.get());
+    }
+
+    /// Add moves all the data from other into this DataMap
+    /// @param other the DataMap to move into this DataMap
+    void Add(DataMap&& other) {
+        for (auto& it : other.map_) {
+            map_.emplace(it.first, std::move(it.second));
+        }
+        other.map_.clear();
+    }
+
+  private:
+    template <typename T0>
+    void PutAll(T0&& first) {
+        Put(std::forward<T0>(first));
+    }
+
+    template <typename T0, typename... Tn>
+    void PutAll(T0&& first, Tn&&... remainder) {
+        Put(std::forward<T0>(first));
+        PutAll(std::forward<Tn>(remainder)...);
+    }
+
+    std::unordered_map<const TypeInfo*, std::unique_ptr<Data>> map_;
 };
 
 /// The return type of Run()
 class Output {
- public:
-  /// Constructor
-  Output();
+  public:
+    /// Constructor
+    Output();
 
-  /// Constructor
-  /// @param program the program to move into this Output
-  explicit Output(Program&& program);
+    /// Constructor
+    /// @param program the program to move into this Output
+    explicit Output(Program&& program);
 
-  /// Constructor
-  /// @param program_ the program to move into this Output
-  /// @param data_ a variadic list of additional data unique_ptrs produced by
-  /// the transform
-  template <typename... DATA>
-  Output(Program&& program_, DATA... data_)
-      : program(std::move(program_)), data(std::forward<DATA>(data_)...) {}
+    /// Constructor
+    /// @param program_ the program to move into this Output
+    /// @param data_ a variadic list of additional data unique_ptrs produced by
+    /// the transform
+    template <typename... DATA>
+    Output(Program&& program_, DATA... data_)
+        : program(std::move(program_)), data(std::forward<DATA>(data_)...) {}
 
-  /// The transformed program. May be empty on error.
-  Program program;
+    /// The transformed program. May be empty on error.
+    Program program;
 
-  /// Extra output generated by the transforms.
-  DataMap data;
+    /// Extra output generated by the transforms.
+    DataMap data;
 };
 
 /// Interface for Program transforms
 class Transform : public Castable<Transform> {
- public:
-  /// Constructor
-  Transform();
-  /// Destructor
-  ~Transform() override;
+  public:
+    /// Constructor
+    Transform();
+    /// Destructor
+    ~Transform() override;
 
-  /// Runs the transform on `program`, returning the transformation result.
-  /// @param program the source program to transform
-  /// @param data optional extra transform-specific input data
-  /// @returns the transformation result
-  virtual Output Run(const Program* program, const DataMap& data = {}) const;
+    /// Runs the transform on `program`, returning the transformation result.
+    /// @param program the source program to transform
+    /// @param data optional extra transform-specific input data
+    /// @returns the transformation result
+    virtual Output Run(const Program* program, const DataMap& data = {}) const;
 
-  /// @param program the program to inspect
-  /// @param data optional extra transform-specific input data
-  /// @returns true if this transform should be run for the given program
-  virtual bool ShouldRun(const Program* program,
-                         const DataMap& data = {}) const;
+    /// @param program the program to inspect
+    /// @param data optional extra transform-specific input data
+    /// @returns true if this transform should be run for the given program
+    virtual bool ShouldRun(const Program* program, const DataMap& data = {}) const;
 
- protected:
-  /// Runs the transform using the CloneContext built for transforming a
-  /// program. Run() is responsible for calling Clone() on the CloneContext.
-  /// @param ctx the CloneContext primed with the input program and
-  /// ProgramBuilder
-  /// @param inputs optional extra transform-specific input data
-  /// @param outputs optional extra transform-specific output data
-  virtual void Run(CloneContext& ctx,
-                   const DataMap& inputs,
-                   DataMap& outputs) const;
+  protected:
+    /// Runs the transform using the CloneContext built for transforming a
+    /// program. Run() is responsible for calling Clone() on the CloneContext.
+    /// @param ctx the CloneContext primed with the input program and
+    /// ProgramBuilder
+    /// @param inputs optional extra transform-specific input data
+    /// @param outputs optional extra transform-specific output data
+    virtual void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const;
 
-  /// Removes the statement `stmt` from the transformed program.
-  /// RemoveStatement handles edge cases, like statements in the initializer and
-  /// continuing of for-loops.
-  /// @param ctx the clone context
-  /// @param stmt the statement to remove when the program is cloned
-  static void RemoveStatement(CloneContext& ctx, const ast::Statement* stmt);
+    /// Removes the statement `stmt` from the transformed program.
+    /// RemoveStatement handles edge cases, like statements in the initializer and
+    /// continuing of for-loops.
+    /// @param ctx the clone context
+    /// @param stmt the statement to remove when the program is cloned
+    static void RemoveStatement(CloneContext& ctx, const ast::Statement* stmt);
 
-  /// CreateASTTypeFor constructs new ast::Type nodes that reconstructs the
-  /// semantic type `ty`.
-  /// @param ctx the clone context
-  /// @param ty the semantic type to reconstruct
-  /// @returns a ast::Type that when resolved, will produce the semantic type
-  /// `ty`.
-  static const ast::Type* CreateASTTypeFor(CloneContext& ctx,
-                                           const sem::Type* ty);
+    /// CreateASTTypeFor constructs new ast::Type nodes that reconstructs the
+    /// semantic type `ty`.
+    /// @param ctx the clone context
+    /// @param ty the semantic type to reconstruct
+    /// @returns a ast::Type that when resolved, will produce the semantic type
+    /// `ty`.
+    static const ast::Type* CreateASTTypeFor(CloneContext& ctx, const sem::Type* ty);
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/transform_test.cc b/src/tint/transform/transform_test.cc
index c100c09..3e342c5 100644
--- a/src/tint/transform/transform_test.cc
+++ b/src/tint/transform/transform_test.cc
@@ -23,98 +23,82 @@
 
 // Inherit from Transform so we have access to protected methods
 struct CreateASTTypeForTest : public testing::Test, public Transform {
-  Output Run(const Program*, const DataMap&) const override { return {}; }
+    Output Run(const Program*, const DataMap&) const override { return {}; }
 
-  const ast::Type* create(
-      std::function<sem::Type*(ProgramBuilder&)> create_sem_type) {
-    ProgramBuilder sem_type_builder;
-    auto* sem_type = create_sem_type(sem_type_builder);
-    Program program(std::move(sem_type_builder));
-    CloneContext ctx(&ast_type_builder, &program, false);
-    return CreateASTTypeFor(ctx, sem_type);
-  }
+    const ast::Type* create(std::function<sem::Type*(ProgramBuilder&)> create_sem_type) {
+        ProgramBuilder sem_type_builder;
+        auto* sem_type = create_sem_type(sem_type_builder);
+        Program program(std::move(sem_type_builder));
+        CloneContext ctx(&ast_type_builder, &program, false);
+        return CreateASTTypeFor(ctx, sem_type);
+    }
 
-  ProgramBuilder ast_type_builder;
+    ProgramBuilder ast_type_builder;
 };
 
 TEST_F(CreateASTTypeForTest, Basic) {
-  EXPECT_TRUE(create([](ProgramBuilder& b) {
-                return b.create<sem::I32>();
-              })->Is<ast::I32>());
-  EXPECT_TRUE(create([](ProgramBuilder& b) {
-                return b.create<sem::U32>();
-              })->Is<ast::U32>());
-  EXPECT_TRUE(create([](ProgramBuilder& b) {
-                return b.create<sem::F32>();
-              })->Is<ast::F32>());
-  EXPECT_TRUE(create([](ProgramBuilder& b) {
-                return b.create<sem::Bool>();
-              })->Is<ast::Bool>());
-  EXPECT_TRUE(create([](ProgramBuilder& b) {
-                return b.create<sem::Void>();
-              })->Is<ast::Void>());
+    EXPECT_TRUE(create([](ProgramBuilder& b) { return b.create<sem::I32>(); })->Is<ast::I32>());
+    EXPECT_TRUE(create([](ProgramBuilder& b) { return b.create<sem::U32>(); })->Is<ast::U32>());
+    EXPECT_TRUE(create([](ProgramBuilder& b) { return b.create<sem::F32>(); })->Is<ast::F32>());
+    EXPECT_TRUE(create([](ProgramBuilder& b) { return b.create<sem::Bool>(); })->Is<ast::Bool>());
+    EXPECT_TRUE(create([](ProgramBuilder& b) { return b.create<sem::Void>(); })->Is<ast::Void>());
 }
 
 TEST_F(CreateASTTypeForTest, Matrix) {
-  auto* mat = create([](ProgramBuilder& b) {
-    auto* column_type = b.create<sem::Vector>(b.create<sem::F32>(), 2u);
-    return b.create<sem::Matrix>(column_type, 3u);
-  });
-  ASSERT_TRUE(mat->Is<ast::Matrix>());
-  ASSERT_TRUE(mat->As<ast::Matrix>()->type->Is<ast::F32>());
-  ASSERT_EQ(mat->As<ast::Matrix>()->columns, 3u);
-  ASSERT_EQ(mat->As<ast::Matrix>()->rows, 2u);
+    auto* mat = create([](ProgramBuilder& b) {
+        auto* column_type = b.create<sem::Vector>(b.create<sem::F32>(), 2u);
+        return b.create<sem::Matrix>(column_type, 3u);
+    });
+    ASSERT_TRUE(mat->Is<ast::Matrix>());
+    ASSERT_TRUE(mat->As<ast::Matrix>()->type->Is<ast::F32>());
+    ASSERT_EQ(mat->As<ast::Matrix>()->columns, 3u);
+    ASSERT_EQ(mat->As<ast::Matrix>()->rows, 2u);
 }
 
 TEST_F(CreateASTTypeForTest, Vector) {
-  auto* vec = create([](ProgramBuilder& b) {
-    return b.create<sem::Vector>(b.create<sem::F32>(), 2u);
-  });
-  ASSERT_TRUE(vec->Is<ast::Vector>());
-  ASSERT_TRUE(vec->As<ast::Vector>()->type->Is<ast::F32>());
-  ASSERT_EQ(vec->As<ast::Vector>()->width, 2u);
+    auto* vec =
+        create([](ProgramBuilder& b) { return b.create<sem::Vector>(b.create<sem::F32>(), 2u); });
+    ASSERT_TRUE(vec->Is<ast::Vector>());
+    ASSERT_TRUE(vec->As<ast::Vector>()->type->Is<ast::F32>());
+    ASSERT_EQ(vec->As<ast::Vector>()->width, 2u);
 }
 
 TEST_F(CreateASTTypeForTest, ArrayImplicitStride) {
-  auto* arr = create([](ProgramBuilder& b) {
-    return b.create<sem::Array>(b.create<sem::F32>(), 2u, 4u, 4u, 32u, 32u);
-  });
-  ASSERT_TRUE(arr->Is<ast::Array>());
-  ASSERT_TRUE(arr->As<ast::Array>()->type->Is<ast::F32>());
-  ASSERT_EQ(arr->As<ast::Array>()->attributes.size(), 0u);
+    auto* arr = create([](ProgramBuilder& b) {
+        return b.create<sem::Array>(b.create<sem::F32>(), 2u, 4u, 4u, 32u, 32u);
+    });
+    ASSERT_TRUE(arr->Is<ast::Array>());
+    ASSERT_TRUE(arr->As<ast::Array>()->type->Is<ast::F32>());
+    ASSERT_EQ(arr->As<ast::Array>()->attributes.size(), 0u);
 
-  auto* size = arr->As<ast::Array>()->count->As<ast::IntLiteralExpression>();
-  ASSERT_NE(size, nullptr);
-  EXPECT_EQ(size->ValueAsI32(), 2);
+    auto* size = arr->As<ast::Array>()->count->As<ast::IntLiteralExpression>();
+    ASSERT_NE(size, nullptr);
+    EXPECT_EQ(size->value, 2);
 }
 
 TEST_F(CreateASTTypeForTest, ArrayNonImplicitStride) {
-  auto* arr = create([](ProgramBuilder& b) {
-    return b.create<sem::Array>(b.create<sem::F32>(), 2u, 4u, 4u, 64u, 32u);
-  });
-  ASSERT_TRUE(arr->Is<ast::Array>());
-  ASSERT_TRUE(arr->As<ast::Array>()->type->Is<ast::F32>());
-  ASSERT_EQ(arr->As<ast::Array>()->attributes.size(), 1u);
-  ASSERT_TRUE(arr->As<ast::Array>()->attributes[0]->Is<ast::StrideAttribute>());
-  ASSERT_EQ(
-      arr->As<ast::Array>()->attributes[0]->As<ast::StrideAttribute>()->stride,
-      64u);
+    auto* arr = create([](ProgramBuilder& b) {
+        return b.create<sem::Array>(b.create<sem::F32>(), 2u, 4u, 4u, 64u, 32u);
+    });
+    ASSERT_TRUE(arr->Is<ast::Array>());
+    ASSERT_TRUE(arr->As<ast::Array>()->type->Is<ast::F32>());
+    ASSERT_EQ(arr->As<ast::Array>()->attributes.size(), 1u);
+    ASSERT_TRUE(arr->As<ast::Array>()->attributes[0]->Is<ast::StrideAttribute>());
+    ASSERT_EQ(arr->As<ast::Array>()->attributes[0]->As<ast::StrideAttribute>()->stride, 64u);
 
-  auto* size = arr->As<ast::Array>()->count->As<ast::IntLiteralExpression>();
-  ASSERT_NE(size, nullptr);
-  EXPECT_EQ(size->ValueAsI32(), 2);
+    auto* size = arr->As<ast::Array>()->count->As<ast::IntLiteralExpression>();
+    ASSERT_NE(size, nullptr);
+    EXPECT_EQ(size->value, 2);
 }
 
 TEST_F(CreateASTTypeForTest, Struct) {
-  auto* str = create([](ProgramBuilder& b) {
-    auto* decl = b.Structure("S", {});
-    return b.create<sem::Struct>(decl, decl->name, sem::StructMemberList{},
-                                 4u /* align */, 4u /* size */,
-                                 4u /* size_no_padding */);
-  });
-  ASSERT_TRUE(str->Is<ast::TypeName>());
-  EXPECT_EQ(ast_type_builder.Symbols().NameFor(str->As<ast::TypeName>()->name),
-            "S");
+    auto* str = create([](ProgramBuilder& b) {
+        auto* decl = b.Structure("S", {});
+        return b.create<sem::Struct>(decl, decl->name, sem::StructMemberList{}, 4u /* align */,
+                                     4u /* size */, 4u /* size_no_padding */);
+    });
+    ASSERT_TRUE(str->Is<ast::TypeName>());
+    EXPECT_EQ(ast_type_builder.Symbols().NameFor(str->As<ast::TypeName>()->name), "S");
 }
 
 }  // namespace
diff --git a/src/tint/transform/unshadow.cc b/src/tint/transform/unshadow.cc
index 9c28675..dcf90da 100644
--- a/src/tint/transform/unshadow.cc
+++ b/src/tint/transform/unshadow.cc
@@ -30,60 +30,60 @@
 
 /// The PIMPL state for the Unshadow transform
 struct Unshadow::State {
-  /// The clone context
-  CloneContext& ctx;
+    /// The clone context
+    CloneContext& ctx;
 
-  /// Constructor
-  /// @param context the clone context
-  explicit State(CloneContext& context) : ctx(context) {}
+    /// Constructor
+    /// @param context the clone context
+    explicit State(CloneContext& context) : ctx(context) {}
 
-  /// Performs the transformation
-  void Run() {
-    auto& sem = ctx.src->Sem();
+    /// Performs the transformation
+    void Run() {
+        auto& sem = ctx.src->Sem();
 
-    // Maps a variable to its new name.
-    std::unordered_map<const sem::Variable*, Symbol> renamed_to;
+        // Maps a variable to its new name.
+        std::unordered_map<const sem::Variable*, Symbol> renamed_to;
 
-    auto rename = [&](const sem::Variable* var) -> const ast::Variable* {
-      auto* decl = var->Declaration();
-      auto name = ctx.src->Symbols().NameFor(decl->symbol);
-      auto symbol = ctx.dst->Symbols().New(name);
-      renamed_to.emplace(var, symbol);
+        auto rename = [&](const sem::Variable* var) -> const ast::Variable* {
+            auto* decl = var->Declaration();
+            auto name = ctx.src->Symbols().NameFor(decl->symbol);
+            auto symbol = ctx.dst->Symbols().New(name);
+            renamed_to.emplace(var, symbol);
 
-      auto source = ctx.Clone(decl->source);
-      auto* type = ctx.Clone(decl->type);
-      auto* constructor = ctx.Clone(decl->constructor);
-      auto attributes = ctx.Clone(decl->attributes);
-      return ctx.dst->create<ast::Variable>(
-          source, symbol, decl->declared_storage_class, decl->declared_access,
-          type, decl->is_const, decl->is_overridable, constructor, attributes);
-    };
+            auto source = ctx.Clone(decl->source);
+            auto* type = ctx.Clone(decl->type);
+            auto* constructor = ctx.Clone(decl->constructor);
+            auto attributes = ctx.Clone(decl->attributes);
+            return ctx.dst->create<ast::Variable>(source, symbol, decl->declared_storage_class,
+                                                  decl->declared_access, type, decl->is_const,
+                                                  decl->is_overridable, constructor, attributes);
+        };
 
-    ctx.ReplaceAll([&](const ast::Variable* var) -> const ast::Variable* {
-      if (auto* local = sem.Get<sem::LocalVariable>(var)) {
-        if (local->Shadows()) {
-          return rename(local);
-        }
-      }
-      if (auto* param = sem.Get<sem::Parameter>(var)) {
-        if (param->Shadows()) {
-          return rename(param);
-        }
-      }
-      return nullptr;
-    });
-    ctx.ReplaceAll([&](const ast::IdentifierExpression* ident)
-                       -> const tint::ast::IdentifierExpression* {
-      if (auto* user = sem.Get<sem::VariableUser>(ident)) {
-        auto it = renamed_to.find(user->Variable());
-        if (it != renamed_to.end()) {
-          return ctx.dst->Expr(it->second);
-        }
-      }
-      return nullptr;
-    });
-    ctx.Clone();
-  }
+        ctx.ReplaceAll([&](const ast::Variable* var) -> const ast::Variable* {
+            if (auto* local = sem.Get<sem::LocalVariable>(var)) {
+                if (local->Shadows()) {
+                    return rename(local);
+                }
+            }
+            if (auto* param = sem.Get<sem::Parameter>(var)) {
+                if (param->Shadows()) {
+                    return rename(param);
+                }
+            }
+            return nullptr;
+        });
+        ctx.ReplaceAll(
+            [&](const ast::IdentifierExpression* ident) -> const tint::ast::IdentifierExpression* {
+                if (auto* user = sem.Get<sem::VariableUser>(ident)) {
+                    auto it = renamed_to.find(user->Variable());
+                    if (it != renamed_to.end()) {
+                        return ctx.dst->Expr(it->second);
+                    }
+                }
+                return nullptr;
+            });
+        ctx.Clone();
+    }
 };
 
 Unshadow::Unshadow() = default;
@@ -91,7 +91,7 @@
 Unshadow::~Unshadow() = default;
 
 void Unshadow::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
-  State(ctx).Run();
+    State(ctx).Run();
 }
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/unshadow.h b/src/tint/transform/unshadow.h
index bfea677..ce5e975 100644
--- a/src/tint/transform/unshadow.h
+++ b/src/tint/transform/unshadow.h
@@ -22,25 +22,23 @@
 /// Unshadow is a Transform that renames any variables that shadow another
 /// variable.
 class Unshadow : public Castable<Unshadow, Transform> {
- public:
-  /// Constructor
-  Unshadow();
+  public:
+    /// Constructor
+    Unshadow();
 
-  /// Destructor
-  ~Unshadow() override;
+    /// Destructor
+    ~Unshadow() override;
 
- protected:
-  struct State;
+  protected:
+    struct State;
 
-  /// Runs the transform using the CloneContext built for transforming a
-  /// program. Run() is responsible for calling Clone() on the CloneContext.
-  /// @param ctx the CloneContext primed with the input program and
-  /// ProgramBuilder
-  /// @param inputs optional extra transform-specific input data
-  /// @param outputs optional extra transform-specific output data
-  void Run(CloneContext& ctx,
-           const DataMap& inputs,
-           DataMap& outputs) const override;
+    /// Runs the transform using the CloneContext built for transforming a
+    /// program. Run() is responsible for calling Clone() on the CloneContext.
+    /// @param ctx the CloneContext primed with the input program and
+    /// ProgramBuilder
+    /// @param inputs optional extra transform-specific input data
+    /// @param outputs optional extra transform-specific output data
+    void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const override;
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/unshadow_test.cc b/src/tint/transform/unshadow_test.cc
index ccb9fba..30e1db5 100644
--- a/src/tint/transform/unshadow_test.cc
+++ b/src/tint/transform/unshadow_test.cc
@@ -22,16 +22,16 @@
 using UnshadowTest = TransformTest;
 
 TEST_F(UnshadowTest, EmptyModule) {
-  auto* src = "";
-  auto* expect = "";
+    auto* src = "";
+    auto* expect = "";
 
-  auto got = Run<Unshadow>(src);
+    auto got = Run<Unshadow>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnshadowTest, Noop) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> a : i32;
 
 let b : i32 = 1;
@@ -46,15 +46,15 @@
 }
 )";
 
-  auto* expect = src;
+    auto* expect = src;
 
-  auto got = Run<Unshadow>(src);
+    auto got = Run<Unshadow>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnshadowTest, LocalShadowsAlias) {
-  auto* src = R"(
+    auto* src = R"(
 type a = i32;
 
 fn X() {
@@ -66,7 +66,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 type a = i32;
 
 fn X() {
@@ -78,13 +78,13 @@
 }
 )";
 
-  auto got = Run<Unshadow>(src);
+    auto got = Run<Unshadow>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnshadowTest, LocalShadowsAlias_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn X() {
   var a = false;
 }
@@ -96,7 +96,7 @@
 type a = i32;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn X() {
   var a_1 = false;
 }
@@ -108,13 +108,13 @@
 type a = i32;
 )";
 
-  auto got = Run<Unshadow>(src);
+    auto got = Run<Unshadow>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnshadowTest, LocalShadowsStruct) {
-  auto* src = R"(
+    auto* src = R"(
 struct a {
   m : i32,
 };
@@ -128,7 +128,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct a {
   m : i32,
 }
@@ -142,13 +142,13 @@
 }
 )";
 
-  auto got = Run<Unshadow>(src);
+    auto got = Run<Unshadow>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnshadowTest, LocalShadowsStruct_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn X() {
   var a = true;
 }
@@ -163,7 +163,7 @@
 
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn X() {
   var a_1 = true;
 }
@@ -177,13 +177,13 @@
 }
 )";
 
-  auto got = Run<Unshadow>(src);
+    auto got = Run<Unshadow>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnshadowTest, LocalShadowsFunction) {
-  auto* src = R"(
+    auto* src = R"(
 fn a() {
   var a = true;
   var b = false;
@@ -195,7 +195,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a() {
   var a_1 = true;
   var b_1 = false;
@@ -207,13 +207,13 @@
 }
 )";
 
-  auto got = Run<Unshadow>(src);
+    auto got = Run<Unshadow>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnshadowTest, LocalShadowsFunction_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn b() {
   let a = true;
   let b = false;
@@ -226,7 +226,7 @@
 
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn b() {
   let a_1 = true;
   let b_1 = false;
@@ -238,13 +238,13 @@
 }
 )";
 
-  auto got = Run<Unshadow>(src);
+    auto got = Run<Unshadow>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnshadowTest, LocalShadowsGlobalVar) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> a : i32;
 
 fn X() {
@@ -256,7 +256,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> a : i32;
 
 fn X() {
@@ -268,13 +268,13 @@
 }
 )";
 
-  auto got = Run<Unshadow>(src);
+    auto got = Run<Unshadow>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnshadowTest, LocalShadowsGlobalVar_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn X() {
   var a = (a == 123);
 }
@@ -286,7 +286,7 @@
 var<private> a : i32;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn X() {
   var a_1 = (a == 123);
 }
@@ -298,13 +298,13 @@
 var<private> a : i32;
 )";
 
-  auto got = Run<Unshadow>(src);
+    auto got = Run<Unshadow>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnshadowTest, LocalShadowsGlobalLet) {
-  auto* src = R"(
+    auto* src = R"(
 let a : i32 = 1;
 
 fn X() {
@@ -316,7 +316,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 let a : i32 = 1;
 
 fn X() {
@@ -328,13 +328,13 @@
 }
 )";
 
-  auto got = Run<Unshadow>(src);
+    auto got = Run<Unshadow>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnshadowTest, LocalShadowsGlobalLet_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn X() {
   var a = (a == 123);
 }
@@ -346,7 +346,7 @@
 let a : i32 = 1;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn X() {
   var a_1 = (a == 123);
 }
@@ -358,13 +358,13 @@
 let a : i32 = 1;
 )";
 
-  auto got = Run<Unshadow>(src);
+    auto got = Run<Unshadow>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnshadowTest, LocalShadowsLocalVar) {
-  auto* src = R"(
+    auto* src = R"(
 fn X() {
   var a : i32;
   {
@@ -376,7 +376,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn X() {
   var a : i32;
   {
@@ -388,13 +388,13 @@
 }
 )";
 
-  auto got = Run<Unshadow>(src);
+    auto got = Run<Unshadow>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnshadowTest, LocalShadowsLocalLet) {
-  auto* src = R"(
+    auto* src = R"(
 fn X() {
   let a = 1;
   {
@@ -406,7 +406,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn X() {
   let a = 1;
   {
@@ -418,13 +418,13 @@
 }
 )";
 
-  auto got = Run<Unshadow>(src);
+    auto got = Run<Unshadow>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnshadowTest, LocalShadowsParam) {
-  auto* src = R"(
+    auto* src = R"(
 fn F(a : i32) {
   {
     var a = (a == 123);
@@ -435,7 +435,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn F(a : i32) {
   {
     var a_1 = (a == 123);
@@ -446,13 +446,13 @@
 }
 )";
 
-  auto got = Run<Unshadow>(src);
+    auto got = Run<Unshadow>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnshadowTest, ParamShadowsFunction) {
-  auto* src = R"(
+    auto* src = R"(
 fn a(a : i32) {
   {
     var a = (a == 123);
@@ -463,7 +463,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn a(a_1 : i32) {
   {
     var a_2 = (a_1 == 123);
@@ -474,73 +474,73 @@
 }
 )";
 
-  auto got = Run<Unshadow>(src);
+    auto got = Run<Unshadow>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnshadowTest, ParamShadowsGlobalVar) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> a : i32;
 
 fn F(a : bool) {
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> a : i32;
 
 fn F(a_1 : bool) {
 }
 )";
 
-  auto got = Run<Unshadow>(src);
+    auto got = Run<Unshadow>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnshadowTest, ParamShadowsGlobalLet) {
-  auto* src = R"(
+    auto* src = R"(
 let a : i32 = 1;
 
 fn F(a : bool) {
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 let a : i32 = 1;
 
 fn F(a_1 : bool) {
 }
 )";
 
-  auto got = Run<Unshadow>(src);
+    auto got = Run<Unshadow>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnshadowTest, ParamShadowsGlobalLet_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn F(a : bool) {
 }
 
 let a : i32 = 1;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn F(a_1 : bool) {
 }
 
 let a : i32 = 1;
 )";
 
-  auto got = Run<Unshadow>(src);
+    auto got = Run<Unshadow>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnshadowTest, ParamShadowsAlias) {
-  auto* src = R"(
+    auto* src = R"(
 type a = i32;
 
 fn F(a : a) {
@@ -553,7 +553,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 type a = i32;
 
 fn F(a_1 : a) {
@@ -566,13 +566,13 @@
 }
 )";
 
-  auto got = Run<Unshadow>(src);
+    auto got = Run<Unshadow>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnshadowTest, ParamShadowsAlias_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn F(a : a) {
   {
     var a = (a == 123);
@@ -585,7 +585,7 @@
 type a = i32;
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn F(a_1 : a) {
   {
     var a_2 = (a_1 == 123);
@@ -598,9 +598,9 @@
 type a = i32;
 )";
 
-  auto got = Run<Unshadow>(src);
+    auto got = Run<Unshadow>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 }  // namespace
diff --git a/src/tint/transform/unwind_discard_functions.cc b/src/tint/transform/unwind_discard_functions.cc
index b15f3a0..e1ba74c 100644
--- a/src/tint/transform/unwind_discard_functions.cc
+++ b/src/tint/transform/unwind_discard_functions.cc
@@ -36,335 +36,299 @@
 namespace {
 
 class State {
- private:
-  CloneContext& ctx;
-  ProgramBuilder& b;
-  const sem::Info& sem;
-  Symbol module_discard_var_name;   // Use ModuleDiscardVarName() to read
-  Symbol module_discard_func_name;  // Use ModuleDiscardFuncName() to read
+  private:
+    CloneContext& ctx;
+    ProgramBuilder& b;
+    const sem::Info& sem;
+    Symbol module_discard_var_name;   // Use ModuleDiscardVarName() to read
+    Symbol module_discard_func_name;  // Use ModuleDiscardFuncName() to read
 
-  // If `block`'s parent is of type TO, returns pointer to it.
-  template <typename TO>
-  const TO* ParentAs(const ast::BlockStatement* block) {
-    if (auto* sem_block = sem.Get(block)) {
-      return As<TO>(sem_block->Parent());
-    }
-    return nullptr;
-  }
-
-  // Returns true if `sem_expr` contains a call expression that may
-  // (transitively) execute a discard statement.
-  bool MayDiscard(const sem::Expression* sem_expr) {
-    return sem_expr && sem_expr->Behaviors().Contains(sem::Behavior::kDiscard);
-  }
-
-  // Lazily creates and returns the name of the module bool variable for whether
-  // to discard: "tint_discard".
-  Symbol ModuleDiscardVarName() {
-    if (!module_discard_var_name.IsValid()) {
-      module_discard_var_name = b.Symbols().New("tint_discard");
-      ctx.dst->Global(module_discard_var_name, b.ty.bool_(), b.Expr(false),
-                      ast::StorageClass::kPrivate);
-    }
-    return module_discard_var_name;
-  }
-
-  // Lazily creates and returns the name of the function that contains a single
-  // discard statement: "tint_discard_func".
-  // We do this to avoid having multiple discard statements in a single program,
-  // which causes problems in certain backends (see crbug.com/1118).
-  Symbol ModuleDiscardFuncName() {
-    if (!module_discard_func_name.IsValid()) {
-      module_discard_func_name = b.Symbols().New("tint_discard_func");
-      b.Func(module_discard_func_name, {}, b.ty.void_(), {b.Discard()});
-    }
-    return module_discard_func_name;
-  }
-
-  // Creates "return <default return value>;" based on the return type of
-  // `stmt`'s owning function.
-  const ast::ReturnStatement* Return(const ast::Statement* stmt) {
-    const ast::Expression* ret_val = nullptr;
-    auto* ret_type = sem.Get(stmt)->Function()->Declaration()->return_type;
-    if (!ret_type->Is<ast::Void>()) {
-      ret_val = b.Construct(ctx.Clone(ret_type));
-    }
-    return b.Return(ret_val);
-  }
-
-  // Returns true if the function `stmt` is in is an entry point
-  bool IsInEntryPointFunc(const ast::Statement* stmt) {
-    return sem.Get(stmt)->Function()->Declaration()->IsEntryPoint();
-  }
-
-  // Creates "tint_discard_func();"
-  const ast::CallStatement* CallDiscardFunc() {
-    auto func_name = ModuleDiscardFuncName();
-    return b.CallStmt(b.Call(func_name));
-  }
-
-  // Creates and returns a new if-statement of the form:
-  //
-  //    if (tint_discard) {
-  //      return <default value>;
-  //    }
-  //
-  // or if `stmt` is in a entry point function:
-  //
-  //    if (tint_discard) {
-  //      tint_discard_func();
-  //      return <default value>;
-  //    }
-  //
-  const ast::IfStatement* IfDiscardReturn(const ast::Statement* stmt) {
-    ast::StatementList stmts;
-
-    // For entry point functions, also emit the discard statement
-    if (IsInEntryPointFunc(stmt)) {
-      stmts.emplace_back(CallDiscardFunc());
+    // Returns true if `sem_expr` contains a call expression that may
+    // (transitively) execute a discard statement.
+    bool MayDiscard(const sem::Expression* sem_expr) {
+        return sem_expr && sem_expr->Behaviors().Contains(sem::Behavior::kDiscard);
     }
 
-    stmts.emplace_back(Return(stmt));
-
-    auto var_name = ModuleDiscardVarName();
-    return b.If(var_name, b.Block(stmts));
-  }
-
-  // Hoists `sem_expr` to a let followed by an `IfDiscardReturn` before `stmt`.
-  // For example, if `stmt` is:
-  //
-  //    return f();
-  //
-  // This function will transform this to:
-  //
-  //    let t1 = f();
-  //    if (tint_discard) {
-  //      return;
-  //    }
-  //    return t1;
-  //
-  const ast::Statement* HoistAndInsertBefore(const ast::Statement* stmt,
-                                             const sem::Expression* sem_expr) {
-    auto* expr = sem_expr->Declaration();
-
-    auto ip = utils::GetInsertionPoint(ctx, stmt);
-    auto var_name = b.Sym();
-    auto* decl = b.Decl(b.Var(var_name, nullptr, ctx.Clone(expr)));
-    ctx.InsertBefore(ip.first->Declaration()->statements, ip.second, decl);
-
-    ctx.InsertBefore(ip.first->Declaration()->statements, ip.second,
-                     IfDiscardReturn(stmt));
-
-    auto* var_expr = b.Expr(var_name);
-
-    // Special handling for CallStatement as we can only replace its expression
-    // with a CallExpression.
-    if (stmt->Is<ast::CallStatement>()) {
-      // We could replace the call statement with no statement, but we can't do
-      // that with transforms (yet), so just return a phony assignment.
-      return b.Assign(b.Phony(), var_expr);
+    // Lazily creates and returns the name of the module bool variable for whether
+    // to discard: "tint_discard".
+    Symbol ModuleDiscardVarName() {
+        if (!module_discard_var_name.IsValid()) {
+            module_discard_var_name = b.Symbols().New("tint_discard");
+            ctx.dst->Global(module_discard_var_name, b.ty.bool_(), b.Expr(false),
+                            ast::StorageClass::kPrivate);
+        }
+        return module_discard_var_name;
     }
 
-    ctx.Replace(expr, var_expr);
-    return ctx.CloneWithoutTransform(stmt);
-  }
-
-  // Returns true if `stmt` is a for-loop initializer statement.
-  bool IsForLoopInitStatement(const ast::Statement* stmt) {
-    if (auto* sem_stmt = sem.Get(stmt)) {
-      if (auto* sem_fl = As<sem::ForLoopStatement>(sem_stmt->Parent())) {
-        return sem_fl->Declaration()->initializer == stmt;
-      }
-    }
-    return false;
-  }
-
-  // Inserts an `IfDiscardReturn` after `stmt` if possible (i.e. `stmt` is not
-  // in a for-loop init), otherwise falls back to HoistAndInsertBefore, hoisting
-  // `sem_expr` to a let followed by an `IfDiscardReturn` before `stmt`.
-  //
-  // For example, if `stmt` is:
-  //
-  //    let r = f();
-  //
-  // This function will transform this to:
-  //
-  //    let r = f();
-  //    if (tint_discard) {
-  //      return;
-  //    }
-  const ast::Statement* TryInsertAfter(const ast::Statement* stmt,
-                                       const sem::Expression* sem_expr) {
-    // If `stmt` is the init of a for-loop, hoist and insert before instead.
-    if (IsForLoopInitStatement(stmt)) {
-      return HoistAndInsertBefore(stmt, sem_expr);
+    // Lazily creates and returns the name of the function that contains a single
+    // discard statement: "tint_discard_func".
+    // We do this to avoid having multiple discard statements in a single program,
+    // which causes problems in certain backends (see crbug.com/1118).
+    Symbol ModuleDiscardFuncName() {
+        if (!module_discard_func_name.IsValid()) {
+            module_discard_func_name = b.Symbols().New("tint_discard_func");
+            b.Func(module_discard_func_name, {}, b.ty.void_(), {b.Discard()});
+        }
+        return module_discard_func_name;
     }
 
-    auto ip = utils::GetInsertionPoint(ctx, stmt);
-    ctx.InsertAfter(ip.first->Declaration()->statements, ip.second,
-                    IfDiscardReturn(stmt));
-    return nullptr;  // Don't replace current statement
-  }
-
-  // Replaces the input discard statement with either setting the module level
-  // discard bool ("tint_discard = true"), or calling the discard function
-  // ("tint_discard_func()"), followed by a default return statement.
-  //
-  // Replaces "discard;" with:
-  //
-  //    tint_discard = true;
-  //    return;
-  //
-  // Or if `stmt` is a entry point function, replaces with:
-  //
-  //    tint_discard_func();
-  //    return;
-  //
-  const ast::Statement* ReplaceDiscardStatement(
-      const ast::DiscardStatement* stmt) {
-    const ast::Statement* to_insert = nullptr;
-    if (IsInEntryPointFunc(stmt)) {
-      to_insert = CallDiscardFunc();
-    } else {
-      auto var_name = ModuleDiscardVarName();
-      to_insert = b.Assign(var_name, true);
+    // Creates "return <default return value>;" based on the return type of
+    // `stmt`'s owning function.
+    const ast::ReturnStatement* Return(const ast::Statement* stmt) {
+        const ast::Expression* ret_val = nullptr;
+        auto* ret_type = sem.Get(stmt)->Function()->Declaration()->return_type;
+        if (!ret_type->Is<ast::Void>()) {
+            ret_val = b.Construct(ctx.Clone(ret_type));
+        }
+        return b.Return(ret_val);
     }
 
-    auto ip = utils::GetInsertionPoint(ctx, stmt);
-    ctx.InsertBefore(ip.first->Declaration()->statements, ip.second, to_insert);
-    return Return(stmt);
-  }
+    // Returns true if the function `stmt` is in is an entry point
+    bool IsInEntryPointFunc(const ast::Statement* stmt) {
+        return sem.Get(stmt)->Function()->Declaration()->IsEntryPoint();
+    }
 
-  // Handle statement
-  const ast::Statement* Statement(const ast::Statement* stmt) {
-    return Switch(
-        stmt,
-        [&](const ast::DiscardStatement* s) -> const ast::Statement* {
-          return ReplaceDiscardStatement(s);
-        },
-        [&](const ast::AssignmentStatement* s) -> const ast::Statement* {
-          auto* sem_lhs = sem.Get(s->lhs);
-          auto* sem_rhs = sem.Get(s->rhs);
-          if (MayDiscard(sem_lhs)) {
-            if (MayDiscard(sem_rhs)) {
-              TINT_ICE(Transform, b.Diagnostics())
-                  << "Unexpected: both sides of assignment statement may "
-                     "discard. Make sure transform::PromoteSideEffectsToDecl "
-                     "was run first.";
+    // Creates "tint_discard_func();"
+    const ast::CallStatement* CallDiscardFunc() {
+        auto func_name = ModuleDiscardFuncName();
+        return b.CallStmt(b.Call(func_name));
+    }
+
+    // Creates and returns a new if-statement of the form:
+    //
+    //    if (tint_discard) {
+    //      return <default value>;
+    //    }
+    //
+    // or if `stmt` is in a entry point function:
+    //
+    //    if (tint_discard) {
+    //      tint_discard_func();
+    //      return <default value>;
+    //    }
+    //
+    const ast::IfStatement* IfDiscardReturn(const ast::Statement* stmt) {
+        ast::StatementList stmts;
+
+        // For entry point functions, also emit the discard statement
+        if (IsInEntryPointFunc(stmt)) {
+            stmts.emplace_back(CallDiscardFunc());
+        }
+
+        stmts.emplace_back(Return(stmt));
+
+        auto var_name = ModuleDiscardVarName();
+        return b.If(var_name, b.Block(stmts));
+    }
+
+    // Hoists `sem_expr` to a let followed by an `IfDiscardReturn` before `stmt`.
+    // For example, if `stmt` is:
+    //
+    //    return f();
+    //
+    // This function will transform this to:
+    //
+    //    let t1 = f();
+    //    if (tint_discard) {
+    //      return;
+    //    }
+    //    return t1;
+    //
+    const ast::Statement* HoistAndInsertBefore(const ast::Statement* stmt,
+                                               const sem::Expression* sem_expr) {
+        auto* expr = sem_expr->Declaration();
+
+        auto ip = utils::GetInsertionPoint(ctx, stmt);
+        auto var_name = b.Sym();
+        auto* decl = b.Decl(b.Var(var_name, nullptr, ctx.Clone(expr)));
+        ctx.InsertBefore(ip.first->Declaration()->statements, ip.second, decl);
+
+        ctx.InsertBefore(ip.first->Declaration()->statements, ip.second, IfDiscardReturn(stmt));
+
+        auto* var_expr = b.Expr(var_name);
+
+        // Special handling for CallStatement as we can only replace its expression
+        // with a CallExpression.
+        if (stmt->Is<ast::CallStatement>()) {
+            // We could replace the call statement with no statement, but we can't do
+            // that with transforms (yet), so just return a phony assignment.
+            return b.Assign(b.Phony(), var_expr);
+        }
+
+        ctx.Replace(expr, var_expr);
+        return ctx.CloneWithoutTransform(stmt);
+    }
+
+    // Returns true if `stmt` is a for-loop initializer statement.
+    bool IsForLoopInitStatement(const ast::Statement* stmt) {
+        if (auto* sem_stmt = sem.Get(stmt)) {
+            if (auto* sem_fl = As<sem::ForLoopStatement>(sem_stmt->Parent())) {
+                return sem_fl->Declaration()->initializer == stmt;
             }
-            return TryInsertAfter(s, sem_lhs);
-          } else if (MayDiscard(sem_rhs)) {
-            return TryInsertAfter(s, sem_rhs);
-          }
-          return nullptr;
-        },
-        [&](const ast::CallStatement* s) -> const ast::Statement* {
-          auto* sem_expr = sem.Get(s->expr);
-          if (!MayDiscard(sem_expr)) {
-            return nullptr;
-          }
-          return TryInsertAfter(s, sem_expr);
-        },
-        [&](const ast::ElseStatement* s) -> const ast::Statement* {
-          if (MayDiscard(sem.Get(s->condition))) {
-            TINT_ICE(Transform, b.Diagnostics())
-                << "Unexpected ElseIf condition that may discard. Make sure "
-                   "transform::PromoteSideEffectsToDecl was run first.";
-          }
-          return nullptr;
-        },
-        [&](const ast::ForLoopStatement* s) -> const ast::Statement* {
-          if (MayDiscard(sem.Get(s->condition))) {
-            TINT_ICE(Transform, b.Diagnostics())
-                << "Unexpected ForLoopStatement condition that may discard. "
-                   "Make sure transform::PromoteSideEffectsToDecl was run "
-                   "first.";
-          }
-          return nullptr;
-        },
-        [&](const ast::IfStatement* s) -> const ast::Statement* {
-          auto* sem_expr = sem.Get(s->condition);
-          if (!MayDiscard(sem_expr)) {
-            return nullptr;
-          }
-          return HoistAndInsertBefore(s, sem_expr);
-        },
-        [&](const ast::ReturnStatement* s) -> const ast::Statement* {
-          auto* sem_expr = sem.Get(s->value);
-          if (!MayDiscard(sem_expr)) {
-            return nullptr;
-          }
-          return HoistAndInsertBefore(s, sem_expr);
-        },
-        [&](const ast::SwitchStatement* s) -> const ast::Statement* {
-          auto* sem_expr = sem.Get(s->condition);
-          if (!MayDiscard(sem_expr)) {
-            return nullptr;
-          }
-          return HoistAndInsertBefore(s, sem_expr);
-        },
-        [&](const ast::VariableDeclStatement* s) -> const ast::Statement* {
-          auto* var = s->variable;
-          if (!var->constructor) {
-            return nullptr;
-          }
-          auto* sem_expr = sem.Get(var->constructor);
-          if (!MayDiscard(sem_expr)) {
-            return nullptr;
-          }
-          return TryInsertAfter(s, sem_expr);
-        });
-  }
+        }
+        return false;
+    }
 
- public:
-  /// Constructor
-  /// @param ctx_in the context
-  explicit State(CloneContext& ctx_in)
-      : ctx(ctx_in), b(*ctx_in.dst), sem(ctx_in.src->Sem()) {}
+    // Inserts an `IfDiscardReturn` after `stmt` if possible (i.e. `stmt` is not
+    // in a for-loop init), otherwise falls back to HoistAndInsertBefore, hoisting
+    // `sem_expr` to a let followed by an `IfDiscardReturn` before `stmt`.
+    //
+    // For example, if `stmt` is:
+    //
+    //    let r = f();
+    //
+    // This function will transform this to:
+    //
+    //    let r = f();
+    //    if (tint_discard) {
+    //      return;
+    //    }
+    const ast::Statement* TryInsertAfter(const ast::Statement* stmt,
+                                         const sem::Expression* sem_expr) {
+        // If `stmt` is the init of a for-loop, hoist and insert before instead.
+        if (IsForLoopInitStatement(stmt)) {
+            return HoistAndInsertBefore(stmt, sem_expr);
+        }
 
-  /// Runs the transform
-  void Run() {
-    ctx.ReplaceAll(
-        [&](const ast::BlockStatement* block) -> const ast::Statement* {
-          // If this block is for an else-if statement, process the else-if now
-          // before processing its block statements.
-          // NOTE: we can't replace else statements at this point - this would
-          // need to be done when replacing the parent if-statement. However, in
-          // this transform, we don't ever expect to need to do this as else-ifs
-          // are converted to else { if } by PromoteSideEffectsToDecl, so this
-          // is only for validation.
-          if (auto* sem_else = ParentAs<sem::ElseStatement>(block)) {
-            if (auto* new_stmt = Statement(sem_else->Declaration())) {
-              TINT_ASSERT(Transform, new_stmt == nullptr);
-              return nullptr;
-            }
-          }
+        auto ip = utils::GetInsertionPoint(ctx, stmt);
+        ctx.InsertAfter(ip.first->Declaration()->statements, ip.second, IfDiscardReturn(stmt));
+        return nullptr;  // Don't replace current statement
+    }
 
-          // Iterate block statements and replace them as needed.
-          for (auto* stmt : block->statements) {
-            if (auto* new_stmt = Statement(stmt)) {
-              ctx.Replace(stmt, new_stmt);
+    // Replaces the input discard statement with either setting the module level
+    // discard bool ("tint_discard = true"), or calling the discard function
+    // ("tint_discard_func()"), followed by a default return statement.
+    //
+    // Replaces "discard;" with:
+    //
+    //    tint_discard = true;
+    //    return;
+    //
+    // Or if `stmt` is a entry point function, replaces with:
+    //
+    //    tint_discard_func();
+    //    return;
+    //
+    const ast::Statement* ReplaceDiscardStatement(const ast::DiscardStatement* stmt) {
+        const ast::Statement* to_insert = nullptr;
+        if (IsInEntryPointFunc(stmt)) {
+            to_insert = CallDiscardFunc();
+        } else {
+            auto var_name = ModuleDiscardVarName();
+            to_insert = b.Assign(var_name, true);
+        }
+
+        auto ip = utils::GetInsertionPoint(ctx, stmt);
+        ctx.InsertBefore(ip.first->Declaration()->statements, ip.second, to_insert);
+        return Return(stmt);
+    }
+
+    // Handle statement
+    const ast::Statement* Statement(const ast::Statement* stmt) {
+        return Switch(
+            stmt,
+            [&](const ast::DiscardStatement* s) -> const ast::Statement* {
+                return ReplaceDiscardStatement(s);
+            },
+            [&](const ast::AssignmentStatement* s) -> const ast::Statement* {
+                auto* sem_lhs = sem.Get(s->lhs);
+                auto* sem_rhs = sem.Get(s->rhs);
+                if (MayDiscard(sem_lhs)) {
+                    if (MayDiscard(sem_rhs)) {
+                        TINT_ICE(Transform, b.Diagnostics())
+                            << "Unexpected: both sides of assignment statement may "
+                               "discard. Make sure transform::PromoteSideEffectsToDecl "
+                               "was run first.";
+                    }
+                    return TryInsertAfter(s, sem_lhs);
+                } else if (MayDiscard(sem_rhs)) {
+                    return TryInsertAfter(s, sem_rhs);
+                }
+                return nullptr;
+            },
+            [&](const ast::CallStatement* s) -> const ast::Statement* {
+                auto* sem_expr = sem.Get(s->expr);
+                if (!MayDiscard(sem_expr)) {
+                    return nullptr;
+                }
+                return TryInsertAfter(s, sem_expr);
+            },
+            [&](const ast::ForLoopStatement* s) -> const ast::Statement* {
+                if (MayDiscard(sem.Get(s->condition))) {
+                    TINT_ICE(Transform, b.Diagnostics())
+                        << "Unexpected ForLoopStatement condition that may discard. "
+                           "Make sure transform::PromoteSideEffectsToDecl was run "
+                           "first.";
+                }
+                return nullptr;
+            },
+            [&](const ast::IfStatement* s) -> const ast::Statement* {
+                auto* sem_expr = sem.Get(s->condition);
+                if (!MayDiscard(sem_expr)) {
+                    return nullptr;
+                }
+                return HoistAndInsertBefore(s, sem_expr);
+            },
+            [&](const ast::ReturnStatement* s) -> const ast::Statement* {
+                auto* sem_expr = sem.Get(s->value);
+                if (!MayDiscard(sem_expr)) {
+                    return nullptr;
+                }
+                return HoistAndInsertBefore(s, sem_expr);
+            },
+            [&](const ast::SwitchStatement* s) -> const ast::Statement* {
+                auto* sem_expr = sem.Get(s->condition);
+                if (!MayDiscard(sem_expr)) {
+                    return nullptr;
+                }
+                return HoistAndInsertBefore(s, sem_expr);
+            },
+            [&](const ast::VariableDeclStatement* s) -> const ast::Statement* {
+                auto* var = s->variable;
+                if (!var->constructor) {
+                    return nullptr;
+                }
+                auto* sem_expr = sem.Get(var->constructor);
+                if (!MayDiscard(sem_expr)) {
+                    return nullptr;
+                }
+                return TryInsertAfter(s, sem_expr);
+            });
+    }
+
+  public:
+    /// Constructor
+    /// @param ctx_in the context
+    explicit State(CloneContext& ctx_in) : ctx(ctx_in), b(*ctx_in.dst), sem(ctx_in.src->Sem()) {}
+
+    /// Runs the transform
+    void Run() {
+        ctx.ReplaceAll([&](const ast::BlockStatement* block) -> const ast::Statement* {
+            // Iterate block statements and replace them as needed.
+            for (auto* stmt : block->statements) {
+                if (auto* new_stmt = Statement(stmt)) {
+                    ctx.Replace(stmt, new_stmt);
+                }
+
+                // Handle for loops, as they are the only other AST node that
+                // contains statements outside of BlockStatements.
+                if (auto* fl = stmt->As<ast::ForLoopStatement>()) {
+                    if (auto* new_stmt = Statement(fl->initializer)) {
+                        ctx.Replace(fl->initializer, new_stmt);
+                    }
+                    if (auto* new_stmt = Statement(fl->continuing)) {
+                        // NOTE: Should never reach here as we cannot discard in a
+                        // continuing block.
+                        ctx.Replace(fl->continuing, new_stmt);
+                    }
+                }
             }
 
-            // Handle for loops, as they are the only other AST node that
-            // contains statements outside of BlockStatements.
-            if (auto* fl = stmt->As<ast::ForLoopStatement>()) {
-              if (auto* new_stmt = Statement(fl->initializer)) {
-                ctx.Replace(fl->initializer, new_stmt);
-              }
-              if (auto* new_stmt = Statement(fl->continuing)) {
-                // NOTE: Should never reach here as we cannot discard in a
-                // continuing block.
-                ctx.Replace(fl->continuing, new_stmt);
-              }
-            }
-          }
-
-          return nullptr;
+            return nullptr;
         });
 
-    ctx.Clone();
-  }
+        ctx.Clone();
+    }
 };
 
 }  // namespace
@@ -372,22 +336,19 @@
 UnwindDiscardFunctions::UnwindDiscardFunctions() = default;
 UnwindDiscardFunctions::~UnwindDiscardFunctions() = default;
 
-void UnwindDiscardFunctions::Run(CloneContext& ctx,
-                                 const DataMap&,
-                                 DataMap&) const {
-  State state(ctx);
-  state.Run();
+void UnwindDiscardFunctions::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
+    State state(ctx);
+    state.Run();
 }
 
-bool UnwindDiscardFunctions::ShouldRun(const Program* program,
-                                       const DataMap& /*data*/) const {
-  auto& sem = program->Sem();
-  for (auto* f : program->AST().Functions()) {
-    if (sem.Get(f)->Behaviors().Contains(sem::Behavior::kDiscard)) {
-      return true;
+bool UnwindDiscardFunctions::ShouldRun(const Program* program, const DataMap& /*data*/) const {
+    auto& sem = program->Sem();
+    for (auto* f : program->AST().Functions()) {
+        if (sem.Get(f)->Behaviors().Contains(sem::Behavior::kDiscard)) {
+            return true;
+        }
     }
-  }
-  return false;
+    return false;
 }
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/unwind_discard_functions.h b/src/tint/transform/unwind_discard_functions.h
index 42bbecb..3b1d838 100644
--- a/src/tint/transform/unwind_discard_functions.h
+++ b/src/tint/transform/unwind_discard_functions.h
@@ -36,31 +36,27 @@
 ///
 /// @note Depends on the following transforms to have been run first:
 /// * PromoteSideEffectsToDecl
-class UnwindDiscardFunctions
-    : public Castable<UnwindDiscardFunctions, Transform> {
- public:
-  /// Constructor
-  UnwindDiscardFunctions();
+class UnwindDiscardFunctions : public Castable<UnwindDiscardFunctions, Transform> {
+  public:
+    /// Constructor
+    UnwindDiscardFunctions();
 
-  /// Destructor
-  ~UnwindDiscardFunctions() override;
+    /// Destructor
+    ~UnwindDiscardFunctions() override;
 
- protected:
-  /// Runs the transform using the CloneContext built for transforming a
-  /// program. Run() is responsible for calling Clone() on the CloneContext.
-  /// @param ctx the CloneContext primed with the input program and
-  /// ProgramBuilder
-  /// @param inputs optional extra transform-specific input data
-  /// @param outputs optional extra transform-specific output data
-  void Run(CloneContext& ctx,
-           const DataMap& inputs,
-           DataMap& outputs) const override;
+  protected:
+    /// Runs the transform using the CloneContext built for transforming a
+    /// program. Run() is responsible for calling Clone() on the CloneContext.
+    /// @param ctx the CloneContext primed with the input program and
+    /// ProgramBuilder
+    /// @param inputs optional extra transform-specific input data
+    /// @param outputs optional extra transform-specific output data
+    void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const override;
 
-  /// @param program the program to inspect
-  /// @param data optional extra transform-specific input data
-  /// @returns true if this transform should be run for the given program
-  bool ShouldRun(const Program* program,
-                 const DataMap& data = {}) const override;
+    /// @param program the program to inspect
+    /// @param data optional extra transform-specific input data
+    /// @returns true if this transform should be run for the given program
+    bool ShouldRun(const Program* program, const DataMap& data = {}) const override;
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/unwind_discard_functions_test.cc b/src/tint/transform/unwind_discard_functions_test.cc
index 0b8c0fc..70b4218 100644
--- a/src/tint/transform/unwind_discard_functions_test.cc
+++ b/src/tint/transform/unwind_discard_functions_test.cc
@@ -22,31 +22,31 @@
 using UnwindDiscardFunctionsTest = TransformTest;
 
 TEST_F(UnwindDiscardFunctionsTest, EmptyModule) {
-  auto* src = "";
-  auto* expect = src;
+    auto* src = "";
+    auto* expect = src;
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnwindDiscardFunctionsTest, ShouldRun_NoDiscardFunc) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
 }
 )";
 
-  EXPECT_FALSE(ShouldRun<UnwindDiscardFunctions>(src));
+    EXPECT_FALSE(ShouldRun<UnwindDiscardFunctions>(src));
 }
 
 TEST_F(UnwindDiscardFunctionsTest, SingleDiscardFunc_NoCall) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   discard;
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> tint_discard : bool = false;
 
 fn f() {
@@ -55,14 +55,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnwindDiscardFunctionsTest, MultipleDiscardFuncs_NoCall) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   discard;
   let marker1 = 0;
@@ -73,7 +73,7 @@
   let marker1 = 0;
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> tint_discard : bool = false;
 
 fn f() {
@@ -89,14 +89,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnwindDiscardFunctionsTest, Call_VoidReturn) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   discard;
   let marker1 = 0;
@@ -109,7 +109,7 @@
   return vec4<f32>();
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> tint_discard : bool = false;
 
 fn f() {
@@ -134,14 +134,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnwindDiscardFunctionsTest, Call_NonVoidReturn) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   x : i32,
   y : i32,
@@ -164,7 +164,7 @@
   return vec4<f32>();
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   x : i32,
   y : i32,
@@ -199,14 +199,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnwindDiscardFunctionsTest, Call_Nested) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() -> i32 {
   let marker1 = 0;
   if (true) {
@@ -238,7 +238,7 @@
   return vec4<f32>();
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> tint_discard : bool = false;
 
 fn f() -> i32 {
@@ -288,14 +288,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnwindDiscardFunctionsTest, Call_Multiple) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   discard;
   let marker1 = 0;
@@ -323,7 +323,7 @@
   return vec4<f32>();
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> tint_discard : bool = false;
 
 fn f() {
@@ -373,14 +373,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnwindDiscardFunctionsTest, Call_DiscardFuncDeclaredBelow) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(fragment)
 fn main(@builtin(position) coord_in: vec4<f32>) -> @location(0) vec4<f32> {
   f();
@@ -393,7 +393,7 @@
   let marker1 = 0;
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 fn tint_discard_func() {
   discard;
 }
@@ -418,14 +418,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnwindDiscardFunctionsTest, If) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() -> i32 {
   if (true) {
     discard;
@@ -441,7 +441,7 @@
   return vec4<f32>();
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> tint_discard : bool = false;
 
 fn f() -> i32 {
@@ -470,14 +470,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnwindDiscardFunctionsTest, ElseIf) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() -> i32 {
   if (true) {
     discard;
@@ -497,7 +497,7 @@
   return vec4<f32>();
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> tint_discard : bool = false;
 
 fn f() -> i32 {
@@ -532,14 +532,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnwindDiscardFunctionsTest, ForLoop_Init_Assignment) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() -> i32 {
   if (true) {
     discard;
@@ -558,7 +558,7 @@
   return vec4<f32>();
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> tint_discard : bool = false;
 
 fn f() -> i32 {
@@ -590,14 +590,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnwindDiscardFunctionsTest, ForLoop_Init_Call) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() -> i32 {
   if (true) {
     discard;
@@ -615,7 +615,7 @@
   return vec4<f32>();
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> tint_discard : bool = false;
 
 fn f() -> i32 {
@@ -646,14 +646,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnwindDiscardFunctionsTest, ForLoop_Init_VariableDecl) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() -> i32 {
   if (true) {
     discard;
@@ -671,7 +671,7 @@
   return vec4<f32>();
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> tint_discard : bool = false;
 
 fn f() -> i32 {
@@ -702,14 +702,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnwindDiscardFunctionsTest, ForLoop_Cond) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() -> i32 {
   if (true) {
     discard;
@@ -727,7 +727,7 @@
   return vec4<f32>();
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> tint_discard : bool = false;
 
 fn f() -> i32 {
@@ -763,14 +763,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnwindDiscardFunctionsTest, ForLoop_Cont) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() -> i32 {
   if (true) {
     discard;
@@ -788,20 +788,20 @@
   return vec4<f32>();
 }
 )";
-  auto* expect =
-      R"(test:12:12 error: cannot call a function that may discard inside a continuing block
+    auto* expect =
+        R"(test:12:12 error: cannot call a function that may discard inside a continuing block
   for (; ; f()) {
            ^
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnwindDiscardFunctionsTest, Switch) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() -> i32 {
   if (true) {
     discard;
@@ -828,7 +828,7 @@
   return vec4<f32>();
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> tint_discard : bool = false;
 
 fn f() -> i32 {
@@ -868,14 +868,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnwindDiscardFunctionsTest, Return) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   x : i32,
   y : i32,
@@ -900,7 +900,7 @@
   return vec4<f32>();
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   x : i32,
   y : i32,
@@ -941,14 +941,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnwindDiscardFunctionsTest, VariableDecl) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() -> i32 {
   if (true) {
     discard;
@@ -963,7 +963,7 @@
   return vec4<f32>();
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> tint_discard : bool = false;
 
 fn f() -> i32 {
@@ -990,14 +990,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnwindDiscardFunctionsTest, Assignment_RightDiscard) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() -> i32 {
   if (true) {
     discard;
@@ -1013,7 +1013,7 @@
   return vec4<f32>();
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> tint_discard : bool = false;
 
 fn f() -> i32 {
@@ -1041,14 +1041,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnwindDiscardFunctionsTest, Assignment_LeftDiscard) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() -> i32 {
   if (true) {
     discard;
@@ -1064,7 +1064,7 @@
   return vec4<f32>();
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> tint_discard : bool = false;
 
 fn f() -> i32 {
@@ -1093,14 +1093,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnwindDiscardFunctionsTest, Assignment_BothDiscard) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() -> i32 {
   if (true) {
     discard;
@@ -1123,7 +1123,7 @@
   return vec4<f32>();
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> tint_discard : bool = false;
 
 fn f() -> i32 {
@@ -1165,14 +1165,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnwindDiscardFunctionsTest, Binary_Arith_MultipleDiscardFuncs) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() -> i32 {
   if (true) {
     discard;
@@ -1202,7 +1202,7 @@
   return vec4<f32>();
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> tint_discard : bool = false;
 
 fn f() -> i32 {
@@ -1257,14 +1257,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnwindDiscardFunctionsTest, Binary_Logical_MultipleDiscardFuncs) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() -> i32 {
   if (true) {
     discard;
@@ -1294,7 +1294,7 @@
   return vec4<f32>();
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> tint_discard : bool = false;
 
 fn f() -> i32 {
@@ -1357,14 +1357,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(UnwindDiscardFunctionsTest, EnsureNoSymbolCollision) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> tint_discard_func : i32;
 var<private> tint_discard : i32;
 
@@ -1380,7 +1380,7 @@
   return vec4<f32>();
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 var<private> tint_discard_func : i32;
 
 var<private> tint_discard : i32;
@@ -1409,10 +1409,10 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
+    DataMap data;
+    auto got = Run<PromoteSideEffectsToDecl, UnwindDiscardFunctions>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 }  // namespace
diff --git a/src/tint/transform/utils/get_insertion_point.cc b/src/tint/transform/utils/get_insertion_point.cc
index 0f00e0c..d10d134 100644
--- a/src/tint/transform/utils/get_insertion_point.cc
+++ b/src/tint/transform/utils/get_insertion_point.cc
@@ -19,40 +19,39 @@
 
 namespace tint::transform::utils {
 
-InsertionPoint GetInsertionPoint(CloneContext& ctx,
-                                 const ast::Statement* stmt) {
-  auto& sem = ctx.src->Sem();
-  auto& diag = ctx.dst->Diagnostics();
-  using RetType = std::pair<const sem::BlockStatement*, const ast::Statement*>;
+InsertionPoint GetInsertionPoint(CloneContext& ctx, const ast::Statement* stmt) {
+    auto& sem = ctx.src->Sem();
+    auto& diag = ctx.dst->Diagnostics();
+    using RetType = std::pair<const sem::BlockStatement*, const ast::Statement*>;
 
-  if (auto* sem_stmt = sem.Get(stmt)) {
-    auto* parent = sem_stmt->Parent();
-    return Switch(
-        parent,
-        [&](const sem::BlockStatement* block) -> RetType {
-          // Common case, can insert in the current block above/below the input
-          // statement.
-          return {block, stmt};
-        },
-        [&](const sem::ForLoopStatement* fl) -> RetType {
-          // `stmt` is either the for loop initializer or the continuing
-          // statement of a for-loop.
-          if (fl->Declaration()->initializer == stmt) {
-            // For loop init, can insert above the for loop itself.
-            return {fl->Block(), fl->Declaration()};
-          }
+    if (auto* sem_stmt = sem.Get(stmt)) {
+        auto* parent = sem_stmt->Parent();
+        return Switch(
+            parent,
+            [&](const sem::BlockStatement* block) -> RetType {
+                // Common case, can insert in the current block above/below the input
+                // statement.
+                return {block, stmt};
+            },
+            [&](const sem::ForLoopStatement* fl) -> RetType {
+                // `stmt` is either the for loop initializer or the continuing
+                // statement of a for-loop.
+                if (fl->Declaration()->initializer == stmt) {
+                    // For loop init, can insert above the for loop itself.
+                    return {fl->Block(), fl->Declaration()};
+                }
 
-          // Cannot insert before or after continuing statement of a for-loop
-          return {};
-        },
-        [&](Default) -> RetType {
-          TINT_ICE(Transform, diag) << "expected parent of statement to be "
-                                       "either a block or for loop";
-          return {};
-        });
-  }
+                // Cannot insert before or after continuing statement of a for-loop
+                return {};
+            },
+            [&](Default) -> RetType {
+                TINT_ICE(Transform, diag) << "expected parent of statement to be "
+                                             "either a block or for loop";
+                return {};
+            });
+    }
 
-  return {};
+    return {};
 }
 
 }  // namespace tint::transform::utils
diff --git a/src/tint/transform/utils/get_insertion_point.h b/src/tint/transform/utils/get_insertion_point.h
index 85abcea..14e867c 100644
--- a/src/tint/transform/utils/get_insertion_point.h
+++ b/src/tint/transform/utils/get_insertion_point.h
@@ -24,8 +24,7 @@
 
 /// InsertionPoint is a pair of the block (`first`) within which, and the
 /// statement (`second`) before or after which to insert.
-using InsertionPoint =
-    std::pair<const sem::BlockStatement*, const ast::Statement*>;
+using InsertionPoint = std::pair<const sem::BlockStatement*, const ast::Statement*>;
 
 /// For the input statement, returns the block and statement within that
 /// block to insert before/after. If `stmt` is a for-loop continue statement,
diff --git a/src/tint/transform/utils/get_insertion_point_test.cc b/src/tint/transform/utils/get_insertion_point_test.cc
index 48e358e..071cfea 100644
--- a/src/tint/transform/utils/get_insertion_point_test.cc
+++ b/src/tint/transform/utils/get_insertion_point_test.cc
@@ -20,74 +20,76 @@
 #include "src/tint/transform/test_helper.h"
 #include "src/tint/transform/utils/get_insertion_point.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::transform {
 namespace {
 
 using GetInsertionPointTest = ::testing::Test;
 
 TEST_F(GetInsertionPointTest, Block) {
-  // fn f() {
-  //     var a = 1;
-  // }
-  ProgramBuilder b;
-  auto* expr = b.Expr(1);
-  auto* var = b.Decl(b.Var("a", nullptr, expr));
-  auto* block = b.Block(var);
-  b.Func("f", {}, b.ty.void_(), {block});
+    // fn f() {
+    //     var a = 1i;
+    // }
+    ProgramBuilder b;
+    auto* expr = b.Expr(1_i);
+    auto* var = b.Decl(b.Var("a", nullptr, expr));
+    auto* block = b.Block(var);
+    b.Func("f", {}, b.ty.void_(), {block});
 
-  Program original(std::move(b));
-  ProgramBuilder cloned_b;
-  CloneContext ctx(&cloned_b, &original);
+    Program original(std::move(b));
+    ProgramBuilder cloned_b;
+    CloneContext ctx(&cloned_b, &original);
 
-  // Can insert in block containing the variable, above or below the input
-  // statement.
-  auto ip = utils::GetInsertionPoint(ctx, var);
-  ASSERT_EQ(ip.first->Declaration(), block);
-  ASSERT_EQ(ip.second, var);
+    // Can insert in block containing the variable, above or below the input
+    // statement.
+    auto ip = utils::GetInsertionPoint(ctx, var);
+    ASSERT_EQ(ip.first->Declaration(), block);
+    ASSERT_EQ(ip.second, var);
 }
 
 TEST_F(GetInsertionPointTest, ForLoopInit) {
-  // fn f() {
-  //     for(var a = 1; true; ) {
-  //     }
-  // }
-  ProgramBuilder b;
-  auto* expr = b.Expr(1);
-  auto* var = b.Decl(b.Var("a", nullptr, expr));
-  auto* fl = b.For(var, b.Expr(true), {}, b.Block());
-  auto* func_block = b.Block(fl);
-  b.Func("f", {}, b.ty.void_(), {func_block});
+    // fn f() {
+    //     for(var a = 1i; true; ) {
+    //     }
+    // }
+    ProgramBuilder b;
+    auto* expr = b.Expr(1_i);
+    auto* var = b.Decl(b.Var("a", nullptr, expr));
+    auto* fl = b.For(var, b.Expr(true), {}, b.Block());
+    auto* func_block = b.Block(fl);
+    b.Func("f", {}, b.ty.void_(), {func_block});
 
-  Program original(std::move(b));
-  ProgramBuilder cloned_b;
-  CloneContext ctx(&cloned_b, &original);
+    Program original(std::move(b));
+    ProgramBuilder cloned_b;
+    CloneContext ctx(&cloned_b, &original);
 
-  // Can insert in block containing for-loop above the for-loop itself.
-  auto ip = utils::GetInsertionPoint(ctx, var);
-  ASSERT_EQ(ip.first->Declaration(), func_block);
-  ASSERT_EQ(ip.second, fl);
+    // Can insert in block containing for-loop above the for-loop itself.
+    auto ip = utils::GetInsertionPoint(ctx, var);
+    ASSERT_EQ(ip.first->Declaration(), func_block);
+    ASSERT_EQ(ip.second, fl);
 }
 
 TEST_F(GetInsertionPointTest, ForLoopCont_Invalid) {
-  // fn f() {
-  //     for(; true; var a = 1) {
-  //     }
-  // }
-  ProgramBuilder b;
-  auto* expr = b.Expr(1);
-  auto* var = b.Decl(b.Var("a", nullptr, expr));
-  auto* s = b.For({}, b.Expr(true), var, b.Block());
-  b.Func("f", {}, b.ty.void_(), {s});
+    // fn f() {
+    //     for(; true; var a = 1i) {
+    //     }
+    // }
+    ProgramBuilder b;
+    auto* expr = b.Expr(1_i);
+    auto* var = b.Decl(b.Var("a", nullptr, expr));
+    auto* s = b.For({}, b.Expr(true), var, b.Block());
+    b.Func("f", {}, b.ty.void_(), {s});
 
-  Program original(std::move(b));
-  ProgramBuilder cloned_b;
-  CloneContext ctx(&cloned_b, &original);
+    Program original(std::move(b));
+    ProgramBuilder cloned_b;
+    CloneContext ctx(&cloned_b, &original);
 
-  // Can't insert before/after for loop continue statement (would ned to be
-  // converted to loop).
-  auto ip = utils::GetInsertionPoint(ctx, var);
-  ASSERT_EQ(ip.first, nullptr);
-  ASSERT_EQ(ip.second, nullptr);
+    // Can't insert before/after for loop continue statement (would ned to be
+    // converted to loop).
+    auto ip = utils::GetInsertionPoint(ctx, var);
+    ASSERT_EQ(ip.first, nullptr);
+    ASSERT_EQ(ip.second, nullptr);
 }
 
 }  // namespace
diff --git a/src/tint/transform/utils/hoist_to_decl_before.cc b/src/tint/transform/utils/hoist_to_decl_before.cc
index 05c56bb..450a2e8 100644
--- a/src/tint/transform/utils/hoist_to_decl_before.cc
+++ b/src/tint/transform/utils/hoist_to_decl_before.cc
@@ -20,7 +20,7 @@
 #include "src/tint/sem/block_statement.h"
 #include "src/tint/sem/for_loop_statement.h"
 #include "src/tint/sem/if_statement.h"
-#include "src/tint/sem/reference_type.h"
+#include "src/tint/sem/reference.h"
 #include "src/tint/sem/variable.h"
 #include "src/tint/utils/reverse.h"
 
@@ -28,305 +28,241 @@
 
 /// Private implementation of HoistToDeclBefore transform
 class HoistToDeclBefore::State {
-  CloneContext& ctx;
-  ProgramBuilder& b;
+    CloneContext& ctx;
+    ProgramBuilder& b;
 
-  /// Holds information about a for-loop that needs to be decomposed into a
-  /// loop, so that declaration statements can be inserted before the
-  /// condition expression or continuing statement.
-  struct LoopInfo {
-    ast::StatementList cond_decls;
-    ast::StatementList cont_decls;
-  };
-
-  /// Holds information about 'if's with 'else-if' statements that need to be
-  /// decomposed into 'if {else}' so that declaration statements can be
-  /// inserted before the condition expression.
-  struct IfInfo {
-    /// Info for each else-if that needs decomposing
-    struct ElseIfInfo {
-      /// Decls to insert before condition
-      ast::StatementList cond_decls;
+    /// Holds information about a for-loop that needs to be decomposed into a
+    /// loop, so that declaration statements can be inserted before the
+    /// condition expression or continuing statement.
+    struct LoopInfo {
+        ast::StatementList cond_decls;
+        ast::StatementList cont_decls;
     };
 
-    /// 'else if's that need to be decomposed to 'else { if }'
-    std::unordered_map<const sem::ElseStatement*, ElseIfInfo> else_ifs;
-  };
+    /// Info for each else-if that needs decomposing
+    struct ElseIfInfo {
+        /// Decls to insert before condition
+        ast::StatementList cond_decls;
+    };
 
-  /// For-loops that need to be decomposed to loops.
-  std::unordered_map<const sem::ForLoopStatement*, LoopInfo> loops;
+    /// For-loops that need to be decomposed to loops.
+    std::unordered_map<const sem::ForLoopStatement*, LoopInfo> loops;
 
-  /// If statements with 'else if's that need to be decomposed to 'else {if}'
-  std::unordered_map<const sem::IfStatement*, IfInfo> ifs;
+    /// 'else if' statements that need to be decomposed to 'else {if}'
+    std::unordered_map<const ast::IfStatement*, ElseIfInfo> else_ifs;
 
-  // Converts any for-loops marked for conversion to loops, inserting
-  // registered declaration statements before the condition or continuing
-  // statement.
-  void ForLoopsToLoops() {
-    if (loops.empty()) {
-      return;
-    }
+    // Converts any for-loops marked for conversion to loops, inserting
+    // registered declaration statements before the condition or continuing
+    // statement.
+    void ForLoopsToLoops() {
+        if (loops.empty()) {
+            return;
+        }
 
-    // At least one for-loop needs to be transformed into a loop.
-    ctx.ReplaceAll(
-        [&](const ast::ForLoopStatement* stmt) -> const ast::Statement* {
-          auto& sem = ctx.src->Sem();
+        // At least one for-loop needs to be transformed into a loop.
+        ctx.ReplaceAll([&](const ast::ForLoopStatement* stmt) -> const ast::Statement* {
+            auto& sem = ctx.src->Sem();
 
-          if (auto* fl = sem.Get(stmt)) {
-            if (auto it = loops.find(fl); it != loops.end()) {
-              auto& info = it->second;
-              auto* for_loop = fl->Declaration();
-              // For-loop needs to be decomposed to a loop.
-              // Build the loop body's statements.
-              // Start with any let declarations for the conditional
-              // expression.
-              auto body_stmts = info.cond_decls;
-              // If the for-loop has a condition, emit this next as:
-              //   if (!cond) { break; }
-              if (auto* cond = for_loop->condition) {
-                // !condition
-                auto* not_cond = b.create<ast::UnaryOpExpression>(
-                    ast::UnaryOp::kNot, ctx.Clone(cond));
-                // { break; }
-                auto* break_body = b.Block(b.create<ast::BreakStatement>());
-                // if (!condition) { break; }
-                body_stmts.emplace_back(b.If(not_cond, break_body));
-              }
-              // Next emit the for-loop body
-              body_stmts.emplace_back(ctx.Clone(for_loop->body));
+            if (auto* fl = sem.Get(stmt)) {
+                if (auto it = loops.find(fl); it != loops.end()) {
+                    auto& info = it->second;
+                    auto* for_loop = fl->Declaration();
+                    // For-loop needs to be decomposed to a loop.
+                    // Build the loop body's statements.
+                    // Start with any let declarations for the conditional
+                    // expression.
+                    auto body_stmts = info.cond_decls;
+                    // If the for-loop has a condition, emit this next as:
+                    //   if (!cond) { break; }
+                    if (auto* cond = for_loop->condition) {
+                        // !condition
+                        auto* not_cond =
+                            b.create<ast::UnaryOpExpression>(ast::UnaryOp::kNot, ctx.Clone(cond));
+                        // { break; }
+                        auto* break_body = b.Block(b.create<ast::BreakStatement>());
+                        // if (!condition) { break; }
+                        body_stmts.emplace_back(b.If(not_cond, break_body));
+                    }
+                    // Next emit the for-loop body
+                    body_stmts.emplace_back(ctx.Clone(for_loop->body));
 
-              // Finally create the continuing block if there was one.
-              const ast::BlockStatement* continuing = nullptr;
-              if (auto* cont = for_loop->continuing) {
-                // Continuing block starts with any let declarations used by
-                // the continuing.
-                auto cont_stmts = info.cont_decls;
-                cont_stmts.emplace_back(ctx.Clone(cont));
-                continuing = b.Block(cont_stmts);
-              }
+                    // Finally create the continuing block if there was one.
+                    const ast::BlockStatement* continuing = nullptr;
+                    if (auto* cont = for_loop->continuing) {
+                        // Continuing block starts with any let declarations used by
+                        // the continuing.
+                        auto cont_stmts = info.cont_decls;
+                        cont_stmts.emplace_back(ctx.Clone(cont));
+                        continuing = b.Block(cont_stmts);
+                    }
 
-              auto* body = b.Block(body_stmts);
-              auto* loop = b.Loop(body, continuing);
-              if (auto* init = for_loop->initializer) {
-                return b.Block(ctx.Clone(init), loop);
-              }
-              return loop;
+                    auto* body = b.Block(body_stmts);
+                    auto* loop = b.Loop(body, continuing);
+                    if (auto* init = for_loop->initializer) {
+                        return b.Block(ctx.Clone(init), loop);
+                    }
+                    return loop;
+                }
             }
-          }
-          return nullptr;
+            return nullptr;
         });
-  }
-
-  void ElseIfsToElseWithNestedIfs() {
-    if (ifs.empty()) {
-      return;
     }
 
-    ctx.ReplaceAll([&](const ast::IfStatement* if_stmt)  //
-                   -> const ast::IfStatement* {
-      auto& sem = ctx.src->Sem();
-      auto* sem_if = sem.Get(if_stmt);
-      if (!sem_if) {
-        return nullptr;
-      }
+    void ElseIfsToElseWithNestedIfs() {
+        // Decompose 'else-if' statements into 'else { if }' blocks.
+        ctx.ReplaceAll([&](const ast::IfStatement* else_if) -> const ast::Statement* {
+            if (!else_ifs.count(else_if)) {
+                return nullptr;
+            }
+            auto& else_if_info = else_ifs[else_if];
 
-      auto it = ifs.find(sem_if);
-      if (it == ifs.end()) {
-        return nullptr;
-      }
-      auto& if_info = it->second;
-
-      // This if statement has "else if"s that need to be converted to "else
-      // { if }"s
-
-      ast::ElseStatementList next_else_stmts;
-      next_else_stmts.reserve(if_stmt->else_statements.size());
-
-      for (auto* else_stmt : utils::Reverse(if_stmt->else_statements)) {
-        if (else_stmt->condition == nullptr) {
-          // The last 'else', keep as is
-          next_else_stmts.insert(next_else_stmts.begin(), ctx.Clone(else_stmt));
-
-        } else {
-          auto* sem_else_if = sem.Get(else_stmt);
-
-          auto it2 = if_info.else_ifs.find(sem_else_if);
-          if (it2 == if_info.else_ifs.end()) {
-            // 'else if' we don't need to modify (no decls to insert), so
-            // keep as is
-            next_else_stmts.insert(next_else_stmts.begin(),
-                                   ctx.Clone(else_stmt));
-
-          } else {
-            // 'else if' we need to replace with 'else <decls> { if }'
-            auto& else_if_info = it2->second;
-
-            // Build the else body's statements, starting with let decls for
-            // the conditional expression
+            // Build the else block's body statements, starting with let decls for
+            // the conditional expression.
             auto& body_stmts = else_if_info.cond_decls;
 
-            // Build nested if
-            auto* cond = ctx.Clone(else_stmt->condition);
-            auto* body = ctx.Clone(else_stmt->body);
-            body_stmts.emplace_back(b.If(cond, body, next_else_stmts));
+            // Move the 'else-if' into the new `else` block as a plain 'if'.
+            auto* cond = ctx.Clone(else_if->condition);
+            auto* body = ctx.Clone(else_if->body);
+            auto* new_if = b.If(cond, body, b.Else(ctx.Clone(else_if->else_statement)));
+            body_stmts.emplace_back(new_if);
 
-            // Build else
-            auto* else_with_nested_if = b.Else(b.Block(body_stmts));
+            // Replace the 'else-if' with the new 'else' block.
+            return b.Block(body_stmts);
+        });
+    }
 
-            // This will be used in parent if (either another nested if, or
-            // top-level if)
-            next_else_stmts = {else_with_nested_if};
-          }
+  public:
+    /// Constructor
+    /// @param ctx_in the clone context
+    explicit State(CloneContext& ctx_in) : ctx(ctx_in), b(*ctx_in.dst) {}
+
+    /// Hoists `expr` to a `let` or `var` with optional `decl_name`, inserting it
+    /// before `before_expr`.
+    /// @param before_expr expression to insert `expr` before
+    /// @param expr expression to hoist
+    /// @param as_const hoist to `let` if true, otherwise to `var`
+    /// @param decl_name optional name to use for the variable/constant name
+    /// @return true on success
+    bool Add(const sem::Expression* before_expr,
+             const ast::Expression* expr,
+             bool as_const,
+             const char* decl_name) {
+        auto name = b.Symbols().New(decl_name);
+
+        // Construct the let/var that holds the hoisted expr
+        auto* v = as_const ? b.Let(name, nullptr, ctx.Clone(expr))
+                           : b.Var(name, nullptr, ctx.Clone(expr));
+        auto* decl = b.Decl(v);
+
+        if (!InsertBefore(before_expr->Stmt(), decl)) {
+            return false;
         }
-      }
 
-      // Build a new top-level if with new else statements
-      if (next_else_stmts.empty()) {
+        // Replace the initializer expression with a reference to the let
+        ctx.Replace(expr, b.Expr(name));
+        return true;
+    }
+
+    /// Inserts `stmt` before `before_stmt`, possibly marking a for-loop to be
+    /// converted to a loop, or an else-if to an else { if }. If `decl` is
+    /// nullptr, for-loop and else-if conversions are marked, but no hoisting
+    /// takes place.
+    /// @param before_stmt statement to insert `stmt` before
+    /// @param stmt statement to insert
+    /// @return true on success
+    bool InsertBefore(const sem::Statement* before_stmt, const ast::Statement* stmt) {
+        auto* ip = before_stmt->Declaration();
+
+        auto* else_if = before_stmt->As<sem::IfStatement>();
+        if (else_if && else_if->Parent()->Is<sem::IfStatement>()) {
+            // Insertion point is an 'else if' condition.
+            // Need to convert 'else if' to 'else { if }'.
+            auto& else_if_info = else_ifs[else_if->Declaration()];
+
+            // Index the map to convert this else if, even if `stmt` is nullptr.
+            auto& decls = else_if_info.cond_decls;
+            if (stmt) {
+                decls.emplace_back(stmt);
+            }
+            return true;
+        }
+
+        if (auto* fl = before_stmt->As<sem::ForLoopStatement>()) {
+            // Insertion point is a for-loop condition.
+            // For-loop needs to be decomposed to a loop.
+
+            // Index the map to convert this for-loop, even if `stmt` is nullptr.
+            auto& decls = loops[fl].cond_decls;
+            if (stmt) {
+                decls.emplace_back(stmt);
+            }
+            return true;
+        }
+
+        auto* parent = before_stmt->Parent();  // The statement's parent
+        if (auto* block = parent->As<sem::BlockStatement>()) {
+            // Insert point sits in a block. Simple case.
+            // Insert the stmt before the parent statement.
+            if (stmt) {
+                ctx.InsertBefore(block->Declaration()->statements, ip, stmt);
+            }
+            return true;
+        }
+
+        if (auto* fl = parent->As<sem::ForLoopStatement>()) {
+            // Insertion point is a for-loop initializer or continuing statement.
+            // These require special care.
+            if (fl->Declaration()->initializer == ip) {
+                // Insertion point is a for-loop initializer.
+                // Insert the new statement above the for-loop.
+                if (stmt) {
+                    ctx.InsertBefore(fl->Block()->Declaration()->statements, fl->Declaration(),
+                                     stmt);
+                }
+                return true;
+            }
+
+            if (fl->Declaration()->continuing == ip) {
+                // Insertion point is a for-loop continuing statement.
+                // For-loop needs to be decomposed to a loop.
+
+                // Index the map to convert this for-loop, even if `stmt` is nullptr.
+                auto& decls = loops[fl].cont_decls;
+                if (stmt) {
+                    decls.emplace_back(stmt);
+                }
+                return true;
+            }
+
+            TINT_ICE(Transform, b.Diagnostics()) << "unhandled use of expression in for-loop";
+            return false;
+        }
+
         TINT_ICE(Transform, b.Diagnostics())
-            << "Expected else statements to insert into new if";
-      }
-      auto* cond = ctx.Clone(if_stmt->condition);
-      auto* body = ctx.Clone(if_stmt->body);
-      auto* new_if = b.If(cond, body, next_else_stmts);
-      return new_if;
-    });
-  }
-
- public:
-  /// Constructor
-  /// @param ctx_in the clone context
-  explicit State(CloneContext& ctx_in) : ctx(ctx_in), b(*ctx_in.dst) {}
-
-  /// Hoists `expr` to a `let` or `var` with optional `decl_name`, inserting it
-  /// before `before_expr`.
-  /// @param before_expr expression to insert `expr` before
-  /// @param expr expression to hoist
-  /// @param as_const hoist to `let` if true, otherwise to `var`
-  /// @param decl_name optional name to use for the variable/constant name
-  /// @return true on success
-  bool Add(const sem::Expression* before_expr,
-           const ast::Expression* expr,
-           bool as_const,
-           const char* decl_name) {
-    auto name = b.Symbols().New(decl_name);
-
-    // Construct the let/var that holds the hoisted expr
-    auto* v = as_const ? b.Const(name, nullptr, ctx.Clone(expr))
-                       : b.Var(name, nullptr, ctx.Clone(expr));
-    auto* decl = b.Decl(v);
-
-    if (!InsertBefore(before_expr->Stmt(), decl)) {
-      return false;
+            << "unhandled expression parent statement type: " << parent->TypeInfo().name;
+        return false;
     }
 
-    // Replace the initializer expression with a reference to the let
-    ctx.Replace(expr, b.Expr(name));
-    return true;
-  }
-
-  /// Inserts `stmt` before `before_stmt`, possibly marking a for-loop to be
-  /// converted to a loop, or an else-if to an else { if }. If `decl` is
-  /// nullptr, for-loop and else-if conversions are marked, but no hoisting
-  /// takes place.
-  /// @param before_stmt statement to insert `stmt` before
-  /// @param stmt statement to insert
-  /// @return true on success
-  bool InsertBefore(const sem::Statement* before_stmt,
-                    const ast::Statement* stmt) {
-    auto* ip = before_stmt->Declaration();
-
-    if (auto* else_if = before_stmt->As<sem::ElseStatement>()) {
-      // Insertion point is an 'else if' condition.
-      // Need to convert 'else if' to 'else { if }'.
-      auto& if_info = ifs[else_if->Parent()->As<sem::IfStatement>()];
-
-      // Index the map to convert this else if, even if `stmt` is nullptr.
-      auto& decls = if_info.else_ifs[else_if].cond_decls;
-      if (stmt) {
-        decls.emplace_back(stmt);
-      }
-      return true;
+    /// Use to signal that we plan on hoisting a decl before `before_expr`. This
+    /// will convert 'for-loop's to 'loop's and 'else-if's to 'else {if}'s if
+    /// needed.
+    /// @param before_expr expression we would hoist a decl before
+    /// @return true on success
+    bool Prepare(const sem::Expression* before_expr) {
+        return InsertBefore(before_expr->Stmt(), nullptr);
     }
 
-    if (auto* fl = before_stmt->As<sem::ForLoopStatement>()) {
-      // Insertion point is a for-loop condition.
-      // For-loop needs to be decomposed to a loop.
-
-      // Index the map to convert this for-loop, even if `stmt` is nullptr.
-      auto& decls = loops[fl].cond_decls;
-      if (stmt) {
-        decls.emplace_back(stmt);
-      }
-      return true;
-    }
-
-    auto* parent = before_stmt->Parent();  // The statement's parent
-    if (auto* block = parent->As<sem::BlockStatement>()) {
-      // Insert point sits in a block. Simple case.
-      // Insert the stmt before the parent statement.
-      if (stmt) {
-        ctx.InsertBefore(block->Declaration()->statements, ip, stmt);
-      }
-      return true;
-    }
-
-    if (auto* fl = parent->As<sem::ForLoopStatement>()) {
-      // Insertion point is a for-loop initializer or continuing statement.
-      // These require special care.
-      if (fl->Declaration()->initializer == ip) {
-        // Insertion point is a for-loop initializer.
-        // Insert the new statement above the for-loop.
-        if (stmt) {
-          ctx.InsertBefore(fl->Block()->Declaration()->statements,
-                           fl->Declaration(), stmt);
-        }
+    /// Applies any scheduled insertions from previous calls to Add() to
+    /// CloneContext. Call this once before ctx.Clone().
+    /// @return true on success
+    bool Apply() {
+        ForLoopsToLoops();
+        ElseIfsToElseWithNestedIfs();
         return true;
-      }
-
-      if (fl->Declaration()->continuing == ip) {
-        // Insertion point is a for-loop continuing statement.
-        // For-loop needs to be decomposed to a loop.
-
-        // Index the map to convert this for-loop, even if `stmt` is nullptr.
-        auto& decls = loops[fl].cont_decls;
-        if (stmt) {
-          decls.emplace_back(stmt);
-        }
-        return true;
-      }
-
-      TINT_ICE(Transform, b.Diagnostics())
-          << "unhandled use of expression in for-loop";
-      return false;
     }
-
-    TINT_ICE(Transform, b.Diagnostics())
-        << "unhandled expression parent statement type: "
-        << parent->TypeInfo().name;
-    return false;
-  }
-
-  /// Use to signal that we plan on hoisting a decl before `before_expr`. This
-  /// will convert 'for-loop's to 'loop's and 'else-if's to 'else {if}'s if
-  /// needed.
-  /// @param before_expr expression we would hoist a decl before
-  /// @return true on success
-  bool Prepare(const sem::Expression* before_expr) {
-    return InsertBefore(before_expr->Stmt(), nullptr);
-  }
-
-  /// Applies any scheduled insertions from previous calls to Add() to
-  /// CloneContext. Call this once before ctx.Clone().
-  /// @return true on success
-  bool Apply() {
-    ForLoopsToLoops();
-    ElseIfsToElseWithNestedIfs();
-    return true;
-  }
 };
 
-HoistToDeclBefore::HoistToDeclBefore(CloneContext& ctx)
-    : state_(std::make_unique<State>(ctx)) {}
+HoistToDeclBefore::HoistToDeclBefore(CloneContext& ctx) : state_(std::make_unique<State>(ctx)) {}
 
 HoistToDeclBefore::~HoistToDeclBefore() {}
 
@@ -334,20 +270,20 @@
                             const ast::Expression* expr,
                             bool as_const,
                             const char* decl_name) {
-  return state_->Add(before_expr, expr, as_const, decl_name);
+    return state_->Add(before_expr, expr, as_const, decl_name);
 }
 
 bool HoistToDeclBefore::InsertBefore(const sem::Statement* before_stmt,
                                      const ast::Statement* stmt) {
-  return state_->InsertBefore(before_stmt, stmt);
+    return state_->InsertBefore(before_stmt, stmt);
 }
 
 bool HoistToDeclBefore::Prepare(const sem::Expression* before_expr) {
-  return state_->Prepare(before_expr);
+    return state_->Prepare(before_expr);
 }
 
 bool HoistToDeclBefore::Apply() {
-  return state_->Apply();
+    return state_->Apply();
 }
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/utils/hoist_to_decl_before.h b/src/tint/transform/utils/hoist_to_decl_before.h
index 2d94f52..d0b96e0 100644
--- a/src/tint/transform/utils/hoist_to_decl_before.h
+++ b/src/tint/transform/utils/hoist_to_decl_before.h
@@ -26,49 +26,48 @@
 /// expressions, possibly converting 'for-loop's to 'loop's and 'else-if's to
 // 'else {if}'s.
 class HoistToDeclBefore {
- public:
-  /// Constructor
-  /// @param ctx the clone context
-  explicit HoistToDeclBefore(CloneContext& ctx);
+  public:
+    /// Constructor
+    /// @param ctx the clone context
+    explicit HoistToDeclBefore(CloneContext& ctx);
 
-  /// Destructor
-  ~HoistToDeclBefore();
+    /// Destructor
+    ~HoistToDeclBefore();
 
-  /// Hoists `expr` to a `let` or `var` with optional `decl_name`, inserting it
-  /// before `before_expr`.
-  /// @param before_expr expression to insert `expr` before
-  /// @param expr expression to hoist
-  /// @param as_const hoist to `let` if true, otherwise to `var`
-  /// @param decl_name optional name to use for the variable/constant name
-  /// @return true on success
-  bool Add(const sem::Expression* before_expr,
-           const ast::Expression* expr,
-           bool as_const,
-           const char* decl_name = "");
+    /// Hoists `expr` to a `let` or `var` with optional `decl_name`, inserting it
+    /// before `before_expr`.
+    /// @param before_expr expression to insert `expr` before
+    /// @param expr expression to hoist
+    /// @param as_const hoist to `let` if true, otherwise to `var`
+    /// @param decl_name optional name to use for the variable/constant name
+    /// @return true on success
+    bool Add(const sem::Expression* before_expr,
+             const ast::Expression* expr,
+             bool as_const,
+             const char* decl_name = "");
 
-  /// Inserts `stmt` before `before_stmt`, possibly converting 'for-loop's to
-  /// 'loop's if necessary.
-  /// @param before_stmt statement to insert `stmt` before
-  /// @param stmt statement to insert
-  /// @return true on success
-  bool InsertBefore(const sem::Statement* before_stmt,
-                    const ast::Statement* stmt);
+    /// Inserts `stmt` before `before_stmt`, possibly converting 'for-loop's to
+    /// 'loop's if necessary.
+    /// @param before_stmt statement to insert `stmt` before
+    /// @param stmt statement to insert
+    /// @return true on success
+    bool InsertBefore(const sem::Statement* before_stmt, const ast::Statement* stmt);
 
-  /// Use to signal that we plan on hoisting a decl before `before_expr`. This
-  /// will convert 'for-loop's to 'loop's and 'else-if's to 'else {if}'s if
-  /// needed.
-  /// @param before_expr expression we would hoist a decl before
-  /// @return true on success
-  bool Prepare(const sem::Expression* before_expr);
+    /// Use to signal that we plan on hoisting a decl before `before_expr`. This
+    /// will convert 'for-loop's to 'loop's and 'else-if's to 'else {if}'s if
+    /// needed.
+    /// @param before_expr expression we would hoist a decl before
+    /// @return true on success
+    bool Prepare(const sem::Expression* before_expr);
 
-  /// Applies any scheduled insertions from previous calls to Add() to
-  /// CloneContext. Call this once before ctx.Clone().
-  /// @return true on success
-  bool Apply();
+    /// Applies any scheduled insertions from previous calls to Add() to
+    /// CloneContext. Call this once before ctx.Clone().
+    /// @return true on success
+    bool Apply();
 
- private:
-  class State;
-  std::unique_ptr<State> state_;
+  private:
+    class State;
+    std::unique_ptr<State> state_;
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/utils/hoist_to_decl_before_test.cc b/src/tint/transform/utils/hoist_to_decl_before_test.cc
index 589eb9a..1e4cb8e 100644
--- a/src/tint/transform/utils/hoist_to_decl_before_test.cc
+++ b/src/tint/transform/utils/hoist_to_decl_before_test.cc
@@ -21,101 +21,102 @@
 #include "src/tint/transform/test_helper.h"
 #include "src/tint/transform/utils/hoist_to_decl_before.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::transform {
 namespace {
 
 using HoistToDeclBeforeTest = ::testing::Test;
 
 TEST_F(HoistToDeclBeforeTest, VarInit) {
-  // fn f() {
-  //     var a = 1;
-  // }
-  ProgramBuilder b;
-  auto* expr = b.Expr(1);
-  auto* var = b.Decl(b.Var("a", nullptr, expr));
-  b.Func("f", {}, b.ty.void_(), {var});
+    // fn f() {
+    //     var a = 1;
+    // }
+    ProgramBuilder b;
+    auto* expr = b.Expr(1_i);
+    auto* var = b.Decl(b.Var("a", nullptr, expr));
+    b.Func("f", {}, b.ty.void_(), {var});
 
-  Program original(std::move(b));
-  ProgramBuilder cloned_b;
-  CloneContext ctx(&cloned_b, &original);
+    Program original(std::move(b));
+    ProgramBuilder cloned_b;
+    CloneContext ctx(&cloned_b, &original);
 
-  HoistToDeclBefore hoistToDeclBefore(ctx);
-  auto* sem_expr = ctx.src->Sem().Get(expr);
-  hoistToDeclBefore.Add(sem_expr, expr, true);
-  hoistToDeclBefore.Apply();
+    HoistToDeclBefore hoistToDeclBefore(ctx);
+    auto* sem_expr = ctx.src->Sem().Get(expr);
+    hoistToDeclBefore.Add(sem_expr, expr, true);
+    hoistToDeclBefore.Apply();
 
-  ctx.Clone();
-  Program cloned(std::move(cloned_b));
+    ctx.Clone();
+    Program cloned(std::move(cloned_b));
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
-  let tint_symbol = 1;
+  let tint_symbol = 1i;
   var a = tint_symbol;
 }
 )";
 
-  EXPECT_EQ(expect, str(cloned));
+    EXPECT_EQ(expect, str(cloned));
 }
 
 TEST_F(HoistToDeclBeforeTest, ForLoopInit) {
-  // fn f() {
-  //     for(var a = 1; true; ) {
-  //     }
-  // }
-  ProgramBuilder b;
-  auto* expr = b.Expr(1);
-  auto* s =
-      b.For(b.Decl(b.Var("a", nullptr, expr)), b.Expr(true), {}, b.Block());
-  b.Func("f", {}, b.ty.void_(), {s});
+    // fn f() {
+    //     for(var a = 1i; true; ) {
+    //     }
+    // }
+    ProgramBuilder b;
+    auto* expr = b.Expr(1_i);
+    auto* s = b.For(b.Decl(b.Var("a", nullptr, expr)), b.Expr(true), {}, b.Block());
+    b.Func("f", {}, b.ty.void_(), {s});
 
-  Program original(std::move(b));
-  ProgramBuilder cloned_b;
-  CloneContext ctx(&cloned_b, &original);
+    Program original(std::move(b));
+    ProgramBuilder cloned_b;
+    CloneContext ctx(&cloned_b, &original);
 
-  HoistToDeclBefore hoistToDeclBefore(ctx);
-  auto* sem_expr = ctx.src->Sem().Get(expr);
-  hoistToDeclBefore.Add(sem_expr, expr, true);
-  hoistToDeclBefore.Apply();
+    HoistToDeclBefore hoistToDeclBefore(ctx);
+    auto* sem_expr = ctx.src->Sem().Get(expr);
+    hoistToDeclBefore.Add(sem_expr, expr, true);
+    hoistToDeclBefore.Apply();
 
-  ctx.Clone();
-  Program cloned(std::move(cloned_b));
+    ctx.Clone();
+    Program cloned(std::move(cloned_b));
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
-  let tint_symbol = 1;
+  let tint_symbol = 1i;
   for(var a = tint_symbol; true; ) {
   }
 }
 )";
 
-  EXPECT_EQ(expect, str(cloned));
+    EXPECT_EQ(expect, str(cloned));
 }
 
 TEST_F(HoistToDeclBeforeTest, ForLoopCond) {
-  // fn f() {
-  //     var a : bool;
-  //     for(; a; ) {
-  //     }
-  // }
-  ProgramBuilder b;
-  auto* var = b.Decl(b.Var("a", b.ty.bool_()));
-  auto* expr = b.Expr("a");
-  auto* s = b.For({}, expr, {}, b.Block());
-  b.Func("f", {}, b.ty.void_(), {var, s});
+    // fn f() {
+    //     var a : bool;
+    //     for(; a; ) {
+    //     }
+    // }
+    ProgramBuilder b;
+    auto* var = b.Decl(b.Var("a", b.ty.bool_()));
+    auto* expr = b.Expr("a");
+    auto* s = b.For({}, expr, {}, b.Block());
+    b.Func("f", {}, b.ty.void_(), {var, s});
 
-  Program original(std::move(b));
-  ProgramBuilder cloned_b;
-  CloneContext ctx(&cloned_b, &original);
+    Program original(std::move(b));
+    ProgramBuilder cloned_b;
+    CloneContext ctx(&cloned_b, &original);
 
-  HoistToDeclBefore hoistToDeclBefore(ctx);
-  auto* sem_expr = ctx.src->Sem().Get(expr);
-  hoistToDeclBefore.Add(sem_expr, expr, true);
-  hoistToDeclBefore.Apply();
+    HoistToDeclBefore hoistToDeclBefore(ctx);
+    auto* sem_expr = ctx.src->Sem().Get(expr);
+    hoistToDeclBefore.Add(sem_expr, expr, true);
+    hoistToDeclBefore.Apply();
 
-  ctx.Clone();
-  Program cloned(std::move(cloned_b));
+    ctx.Clone();
+    Program cloned(std::move(cloned_b));
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var a : bool;
   loop {
@@ -129,33 +130,32 @@
 }
 )";
 
-  EXPECT_EQ(expect, str(cloned));
+    EXPECT_EQ(expect, str(cloned));
 }
 
 TEST_F(HoistToDeclBeforeTest, ForLoopCont) {
-  // fn f() {
-  //     for(; true; var a = 1) {
-  //     }
-  // }
-  ProgramBuilder b;
-  auto* expr = b.Expr(1);
-  auto* s =
-      b.For({}, b.Expr(true), b.Decl(b.Var("a", nullptr, expr)), b.Block());
-  b.Func("f", {}, b.ty.void_(), {s});
+    // fn f() {
+    //     for(; true; var a = 1i) {
+    //     }
+    // }
+    ProgramBuilder b;
+    auto* expr = b.Expr(1_i);
+    auto* s = b.For({}, b.Expr(true), b.Decl(b.Var("a", nullptr, expr)), b.Block());
+    b.Func("f", {}, b.ty.void_(), {s});
 
-  Program original(std::move(b));
-  ProgramBuilder cloned_b;
-  CloneContext ctx(&cloned_b, &original);
+    Program original(std::move(b));
+    ProgramBuilder cloned_b;
+    CloneContext ctx(&cloned_b, &original);
 
-  HoistToDeclBefore hoistToDeclBefore(ctx);
-  auto* sem_expr = ctx.src->Sem().Get(expr);
-  hoistToDeclBefore.Add(sem_expr, expr, true);
-  hoistToDeclBefore.Apply();
+    HoistToDeclBefore hoistToDeclBefore(ctx);
+    auto* sem_expr = ctx.src->Sem().Get(expr);
+    hoistToDeclBefore.Add(sem_expr, expr, true);
+    hoistToDeclBefore.Apply();
 
-  ctx.Clone();
-  Program cloned(std::move(cloned_b));
+    ctx.Clone();
+    Program cloned(std::move(cloned_b));
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   loop {
     if (!(true)) {
@@ -165,45 +165,45 @@
     }
 
     continuing {
-      let tint_symbol = 1;
+      let tint_symbol = 1i;
       var a = tint_symbol;
     }
   }
 }
 )";
 
-  EXPECT_EQ(expect, str(cloned));
+    EXPECT_EQ(expect, str(cloned));
 }
 
 TEST_F(HoistToDeclBeforeTest, ElseIf) {
-  // fn f() {
-  //     var a : bool;
-  //     if (true) {
-  //     } else if (a) {
-  //     } else {
-  //     }
-  // }
-  ProgramBuilder b;
-  auto* var = b.Decl(b.Var("a", b.ty.bool_()));
-  auto* expr = b.Expr("a");
-  auto* s = b.If(b.Expr(true), b.Block(),  //
-                 b.Else(expr, b.Block()),  //
-                 b.Else(b.Block()));
-  b.Func("f", {}, b.ty.void_(), {var, s});
+    // fn f() {
+    //     var a : bool;
+    //     if (true) {
+    //     } else if (a) {
+    //     } else {
+    //     }
+    // }
+    ProgramBuilder b;
+    auto* var = b.Decl(b.Var("a", b.ty.bool_()));
+    auto* expr = b.Expr("a");
+    auto* s = b.If(b.Expr(true), b.Block(),      //
+                   b.Else(b.If(expr, b.Block(),  //
+                               b.Else(b.Block()))));
+    b.Func("f", {}, b.ty.void_(), {var, s});
 
-  Program original(std::move(b));
-  ProgramBuilder cloned_b;
-  CloneContext ctx(&cloned_b, &original);
+    Program original(std::move(b));
+    ProgramBuilder cloned_b;
+    CloneContext ctx(&cloned_b, &original);
 
-  HoistToDeclBefore hoistToDeclBefore(ctx);
-  auto* sem_expr = ctx.src->Sem().Get(expr);
-  hoistToDeclBefore.Add(sem_expr, expr, true);
-  hoistToDeclBefore.Apply();
+    HoistToDeclBefore hoistToDeclBefore(ctx);
+    auto* sem_expr = ctx.src->Sem().Get(expr);
+    hoistToDeclBefore.Add(sem_expr, expr, true);
+    hoistToDeclBefore.Apply();
 
-  ctx.Clone();
-  Program cloned(std::move(cloned_b));
+    ctx.Clone();
+    Program cloned(std::move(cloned_b));
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var a : bool;
   if (true) {
@@ -216,104 +216,103 @@
 }
 )";
 
-  EXPECT_EQ(expect, str(cloned));
+    EXPECT_EQ(expect, str(cloned));
 }
 
 TEST_F(HoistToDeclBeforeTest, Array1D) {
-  // fn f() {
-  //     var a : array<i32, 10>;
-  //     var b = a[0];
-  // }
-  ProgramBuilder b;
-  auto* var1 = b.Decl(b.Var("a", b.ty.array<ProgramBuilder::i32, 10>()));
-  auto* expr = b.IndexAccessor("a", 0);
-  auto* var2 = b.Decl(b.Var("b", nullptr, expr));
-  b.Func("f", {}, b.ty.void_(), {var1, var2});
+    // fn f() {
+    //     var a : array<i32, 10>;
+    //     var b = a[0];
+    // }
+    ProgramBuilder b;
+    auto* var1 = b.Decl(b.Var("a", b.ty.array<i32, 10>()));
+    auto* expr = b.IndexAccessor("a", 0_i);
+    auto* var2 = b.Decl(b.Var("b", nullptr, expr));
+    b.Func("f", {}, b.ty.void_(), {var1, var2});
 
-  Program original(std::move(b));
-  ProgramBuilder cloned_b;
-  CloneContext ctx(&cloned_b, &original);
+    Program original(std::move(b));
+    ProgramBuilder cloned_b;
+    CloneContext ctx(&cloned_b, &original);
 
-  HoistToDeclBefore hoistToDeclBefore(ctx);
-  auto* sem_expr = ctx.src->Sem().Get(expr);
-  hoistToDeclBefore.Add(sem_expr, expr, true);
-  hoistToDeclBefore.Apply();
+    HoistToDeclBefore hoistToDeclBefore(ctx);
+    auto* sem_expr = ctx.src->Sem().Get(expr);
+    hoistToDeclBefore.Add(sem_expr, expr, true);
+    hoistToDeclBefore.Apply();
 
-  ctx.Clone();
-  Program cloned(std::move(cloned_b));
+    ctx.Clone();
+    Program cloned(std::move(cloned_b));
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
-  var a : array<i32, 10>;
-  let tint_symbol = a[0];
+  var a : array<i32, 10u>;
+  let tint_symbol = a[0i];
   var b = tint_symbol;
 }
 )";
 
-  EXPECT_EQ(expect, str(cloned));
+    EXPECT_EQ(expect, str(cloned));
 }
 
 TEST_F(HoistToDeclBeforeTest, Array2D) {
-  // fn f() {
-  //     var a : array<array<i32, 10>, 10>;
-  //     var b = a[0][0];
-  // }
-  ProgramBuilder b;
+    // fn f() {
+    //     var a : array<array<i32, 10>, 10>;
+    //     var b = a[0][0];
+    // }
+    ProgramBuilder b;
 
-  auto* var1 =
-      b.Decl(b.Var("a", b.ty.array(b.ty.array<ProgramBuilder::i32, 10>(), 10)));
-  auto* expr = b.IndexAccessor(b.IndexAccessor("a", 0), 0);
-  auto* var2 = b.Decl(b.Var("b", nullptr, expr));
-  b.Func("f", {}, b.ty.void_(), {var1, var2});
+    auto* var1 = b.Decl(b.Var("a", b.ty.array(b.ty.array<i32, 10>(), 10_i)));
+    auto* expr = b.IndexAccessor(b.IndexAccessor("a", 0_i), 0_i);
+    auto* var2 = b.Decl(b.Var("b", nullptr, expr));
+    b.Func("f", {}, b.ty.void_(), {var1, var2});
 
-  Program original(std::move(b));
-  ProgramBuilder cloned_b;
-  CloneContext ctx(&cloned_b, &original);
+    Program original(std::move(b));
+    ProgramBuilder cloned_b;
+    CloneContext ctx(&cloned_b, &original);
 
-  HoistToDeclBefore hoistToDeclBefore(ctx);
-  auto* sem_expr = ctx.src->Sem().Get(expr);
-  hoistToDeclBefore.Add(sem_expr, expr, true);
-  hoistToDeclBefore.Apply();
+    HoistToDeclBefore hoistToDeclBefore(ctx);
+    auto* sem_expr = ctx.src->Sem().Get(expr);
+    hoistToDeclBefore.Add(sem_expr, expr, true);
+    hoistToDeclBefore.Apply();
 
-  ctx.Clone();
-  Program cloned(std::move(cloned_b));
+    ctx.Clone();
+    Program cloned(std::move(cloned_b));
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
-  var a : array<array<i32, 10>, 10>;
-  let tint_symbol = a[0][0];
+  var a : array<array<i32, 10u>, 10i>;
+  let tint_symbol = a[0i][0i];
   var b = tint_symbol;
 }
 )";
 
-  EXPECT_EQ(expect, str(cloned));
+    EXPECT_EQ(expect, str(cloned));
 }
 
 TEST_F(HoistToDeclBeforeTest, Prepare_ForLoopCond) {
-  // fn f() {
-  //     var a : bool;
-  //     for(; a; ) {
-  //     }
-  // }
-  ProgramBuilder b;
-  auto* var = b.Decl(b.Var("a", b.ty.bool_()));
-  auto* expr = b.Expr("a");
-  auto* s = b.For({}, expr, {}, b.Block());
-  b.Func("f", {}, b.ty.void_(), {var, s});
+    // fn f() {
+    //     var a : bool;
+    //     for(; a; ) {
+    //     }
+    // }
+    ProgramBuilder b;
+    auto* var = b.Decl(b.Var("a", b.ty.bool_()));
+    auto* expr = b.Expr("a");
+    auto* s = b.For({}, expr, {}, b.Block());
+    b.Func("f", {}, b.ty.void_(), {var, s});
 
-  Program original(std::move(b));
-  ProgramBuilder cloned_b;
-  CloneContext ctx(&cloned_b, &original);
+    Program original(std::move(b));
+    ProgramBuilder cloned_b;
+    CloneContext ctx(&cloned_b, &original);
 
-  HoistToDeclBefore hoistToDeclBefore(ctx);
-  auto* sem_expr = ctx.src->Sem().Get(expr);
-  hoistToDeclBefore.Prepare(sem_expr);
-  hoistToDeclBefore.Apply();
+    HoistToDeclBefore hoistToDeclBefore(ctx);
+    auto* sem_expr = ctx.src->Sem().Get(expr);
+    hoistToDeclBefore.Prepare(sem_expr);
+    hoistToDeclBefore.Apply();
 
-  ctx.Clone();
-  Program cloned(std::move(cloned_b));
+    ctx.Clone();
+    Program cloned(std::move(cloned_b));
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var a : bool;
   loop {
@@ -326,33 +325,32 @@
 }
 )";
 
-  EXPECT_EQ(expect, str(cloned));
+    EXPECT_EQ(expect, str(cloned));
 }
 
 TEST_F(HoistToDeclBeforeTest, Prepare_ForLoopCont) {
-  // fn f() {
-  //     for(; true; var a = 1) {
-  //     }
-  // }
-  ProgramBuilder b;
-  auto* expr = b.Expr(1);
-  auto* s =
-      b.For({}, b.Expr(true), b.Decl(b.Var("a", nullptr, expr)), b.Block());
-  b.Func("f", {}, b.ty.void_(), {s});
+    // fn f() {
+    //     for(; true; var a = 1i) {
+    //     }
+    // }
+    ProgramBuilder b;
+    auto* expr = b.Expr(1_i);
+    auto* s = b.For({}, b.Expr(true), b.Decl(b.Var("a", nullptr, expr)), b.Block());
+    b.Func("f", {}, b.ty.void_(), {s});
 
-  Program original(std::move(b));
-  ProgramBuilder cloned_b;
-  CloneContext ctx(&cloned_b, &original);
+    Program original(std::move(b));
+    ProgramBuilder cloned_b;
+    CloneContext ctx(&cloned_b, &original);
 
-  HoistToDeclBefore hoistToDeclBefore(ctx);
-  auto* sem_expr = ctx.src->Sem().Get(expr);
-  hoistToDeclBefore.Prepare(sem_expr);
-  hoistToDeclBefore.Apply();
+    HoistToDeclBefore hoistToDeclBefore(ctx);
+    auto* sem_expr = ctx.src->Sem().Get(expr);
+    hoistToDeclBefore.Prepare(sem_expr);
+    hoistToDeclBefore.Apply();
 
-  ctx.Clone();
-  Program cloned(std::move(cloned_b));
+    ctx.Clone();
+    Program cloned(std::move(cloned_b));
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   loop {
     if (!(true)) {
@@ -362,44 +360,44 @@
     }
 
     continuing {
-      var a = 1;
+      var a = 1i;
     }
   }
 }
 )";
 
-  EXPECT_EQ(expect, str(cloned));
+    EXPECT_EQ(expect, str(cloned));
 }
 
 TEST_F(HoistToDeclBeforeTest, Prepare_ElseIf) {
-  // fn f() {
-  //     var a : bool;
-  //     if (true) {
-  //     } else if (a) {
-  //     } else {
-  //     }
-  // }
-  ProgramBuilder b;
-  auto* var = b.Decl(b.Var("a", b.ty.bool_()));
-  auto* expr = b.Expr("a");
-  auto* s = b.If(b.Expr(true), b.Block(),  //
-                 b.Else(expr, b.Block()),  //
-                 b.Else(b.Block()));
-  b.Func("f", {}, b.ty.void_(), {var, s});
+    // fn f() {
+    //     var a : bool;
+    //     if (true) {
+    //     } else if (a) {
+    //     } else {
+    //     }
+    // }
+    ProgramBuilder b;
+    auto* var = b.Decl(b.Var("a", b.ty.bool_()));
+    auto* expr = b.Expr("a");
+    auto* s = b.If(b.Expr(true), b.Block(),      //
+                   b.Else(b.If(expr, b.Block(),  //
+                               b.Else(b.Block()))));
+    b.Func("f", {}, b.ty.void_(), {var, s});
 
-  Program original(std::move(b));
-  ProgramBuilder cloned_b;
-  CloneContext ctx(&cloned_b, &original);
+    Program original(std::move(b));
+    ProgramBuilder cloned_b;
+    CloneContext ctx(&cloned_b, &original);
 
-  HoistToDeclBefore hoistToDeclBefore(ctx);
-  auto* sem_expr = ctx.src->Sem().Get(expr);
-  hoistToDeclBefore.Prepare(sem_expr);
-  hoistToDeclBefore.Apply();
+    HoistToDeclBefore hoistToDeclBefore(ctx);
+    auto* sem_expr = ctx.src->Sem().Get(expr);
+    hoistToDeclBefore.Prepare(sem_expr);
+    hoistToDeclBefore.Apply();
 
-  ctx.Clone();
-  Program cloned(std::move(cloned_b));
+    ctx.Clone();
+    Program cloned(std::move(cloned_b));
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var a : bool;
   if (true) {
@@ -411,120 +409,120 @@
 }
 )";
 
-  EXPECT_EQ(expect, str(cloned));
+    EXPECT_EQ(expect, str(cloned));
 }
 
 TEST_F(HoistToDeclBeforeTest, InsertBefore_Block) {
-  // fn foo() {
-  // }
-  // fn f() {
-  //     var a = 1;
-  // }
-  ProgramBuilder b;
-  b.Func("foo", {}, b.ty.void_(), {});
-  auto* var = b.Decl(b.Var("a", nullptr, b.Expr(1)));
-  b.Func("f", {}, b.ty.void_(), {var});
+    // fn foo() {
+    // }
+    // fn f() {
+    //     var a = 1i;
+    // }
+    ProgramBuilder b;
+    b.Func("foo", {}, b.ty.void_(), {});
+    auto* var = b.Decl(b.Var("a", nullptr, b.Expr(1_i)));
+    b.Func("f", {}, b.ty.void_(), {var});
 
-  Program original(std::move(b));
-  ProgramBuilder cloned_b;
-  CloneContext ctx(&cloned_b, &original);
+    Program original(std::move(b));
+    ProgramBuilder cloned_b;
+    CloneContext ctx(&cloned_b, &original);
 
-  HoistToDeclBefore hoistToDeclBefore(ctx);
-  auto* before_stmt = ctx.src->Sem().Get(var);
-  auto* new_stmt = ctx.dst->CallStmt(ctx.dst->Call("foo"));
-  hoistToDeclBefore.InsertBefore(before_stmt, new_stmt);
-  hoistToDeclBefore.Apply();
+    HoistToDeclBefore hoistToDeclBefore(ctx);
+    auto* before_stmt = ctx.src->Sem().Get(var);
+    auto* new_stmt = ctx.dst->CallStmt(ctx.dst->Call("foo"));
+    hoistToDeclBefore.InsertBefore(before_stmt, new_stmt);
+    hoistToDeclBefore.Apply();
 
-  ctx.Clone();
-  Program cloned(std::move(cloned_b));
+    ctx.Clone();
+    Program cloned(std::move(cloned_b));
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn foo() {
 }
 
 fn f() {
   foo();
-  var a = 1;
+  var a = 1i;
 }
 )";
 
-  EXPECT_EQ(expect, str(cloned));
+    EXPECT_EQ(expect, str(cloned));
 }
 
 TEST_F(HoistToDeclBeforeTest, InsertBefore_ForLoopInit) {
-  // fn foo() {
-  // }
-  // fn f() {
-  //     for(var a = 1; true;) {
-  //     }
-  // }
-  ProgramBuilder b;
-  b.Func("foo", {}, b.ty.void_(), {});
-  auto* var = b.Decl(b.Var("a", nullptr, b.Expr(1)));
-  auto* s = b.For(var, b.Expr(true), {}, b.Block());
-  b.Func("f", {}, b.ty.void_(), {s});
+    // fn foo() {
+    // }
+    // fn f() {
+    //     for(var a = 1i; true;) {
+    //     }
+    // }
+    ProgramBuilder b;
+    b.Func("foo", {}, b.ty.void_(), {});
+    auto* var = b.Decl(b.Var("a", nullptr, b.Expr(1_i)));
+    auto* s = b.For(var, b.Expr(true), {}, b.Block());
+    b.Func("f", {}, b.ty.void_(), {s});
 
-  Program original(std::move(b));
-  ProgramBuilder cloned_b;
-  CloneContext ctx(&cloned_b, &original);
+    Program original(std::move(b));
+    ProgramBuilder cloned_b;
+    CloneContext ctx(&cloned_b, &original);
 
-  HoistToDeclBefore hoistToDeclBefore(ctx);
-  auto* before_stmt = ctx.src->Sem().Get(var);
-  auto* new_stmt = ctx.dst->CallStmt(ctx.dst->Call("foo"));
-  hoistToDeclBefore.InsertBefore(before_stmt, new_stmt);
-  hoistToDeclBefore.Apply();
+    HoistToDeclBefore hoistToDeclBefore(ctx);
+    auto* before_stmt = ctx.src->Sem().Get(var);
+    auto* new_stmt = ctx.dst->CallStmt(ctx.dst->Call("foo"));
+    hoistToDeclBefore.InsertBefore(before_stmt, new_stmt);
+    hoistToDeclBefore.Apply();
 
-  ctx.Clone();
-  Program cloned(std::move(cloned_b));
+    ctx.Clone();
+    Program cloned(std::move(cloned_b));
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn foo() {
 }
 
 fn f() {
   foo();
-  for(var a = 1; true; ) {
+  for(var a = 1i; true; ) {
   }
 }
 )";
 
-  EXPECT_EQ(expect, str(cloned));
+    EXPECT_EQ(expect, str(cloned));
 }
 
 TEST_F(HoistToDeclBeforeTest, InsertBefore_ForLoopCont) {
-  // fn foo() {
-  // }
-  // fn f() {
-  //     var a = 1;
-  //     for(; true; a+=1) {
-  //     }
-  // }
-  ProgramBuilder b;
-  b.Func("foo", {}, b.ty.void_(), {});
-  auto* var = b.Decl(b.Var("a", nullptr, b.Expr(1)));
-  auto* cont = b.CompoundAssign("a", b.Expr(1), ast::BinaryOp::kAdd);
-  auto* s = b.For({}, b.Expr(true), cont, b.Block());
-  b.Func("f", {}, b.ty.void_(), {var, s});
+    // fn foo() {
+    // }
+    // fn f() {
+    //     var a = 1i;
+    //     for(; true; a+=1i) {
+    //     }
+    // }
+    ProgramBuilder b;
+    b.Func("foo", {}, b.ty.void_(), {});
+    auto* var = b.Decl(b.Var("a", nullptr, b.Expr(1_i)));
+    auto* cont = b.CompoundAssign("a", b.Expr(1_i), ast::BinaryOp::kAdd);
+    auto* s = b.For({}, b.Expr(true), cont, b.Block());
+    b.Func("f", {}, b.ty.void_(), {var, s});
 
-  Program original(std::move(b));
-  ProgramBuilder cloned_b;
-  CloneContext ctx(&cloned_b, &original);
+    Program original(std::move(b));
+    ProgramBuilder cloned_b;
+    CloneContext ctx(&cloned_b, &original);
 
-  HoistToDeclBefore hoistToDeclBefore(ctx);
-  auto* before_stmt = ctx.src->Sem().Get(cont->As<ast::Statement>());
-  auto* new_stmt = ctx.dst->CallStmt(ctx.dst->Call("foo"));
-  hoistToDeclBefore.InsertBefore(before_stmt, new_stmt);
-  hoistToDeclBefore.Apply();
+    HoistToDeclBefore hoistToDeclBefore(ctx);
+    auto* before_stmt = ctx.src->Sem().Get(cont->As<ast::Statement>());
+    auto* new_stmt = ctx.dst->CallStmt(ctx.dst->Call("foo"));
+    hoistToDeclBefore.InsertBefore(before_stmt, new_stmt);
+    hoistToDeclBefore.Apply();
 
-  ctx.Clone();
-  Program cloned(std::move(cloned_b));
+    ctx.Clone();
+    Program cloned(std::move(cloned_b));
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn foo() {
 }
 
 fn f() {
-  var a = 1;
+  var a = 1i;
   loop {
     if (!(true)) {
       break;
@@ -534,48 +532,47 @@
 
     continuing {
       foo();
-      a += 1;
+      a += 1i;
     }
   }
 }
 )";
 
-  EXPECT_EQ(expect, str(cloned));
+    EXPECT_EQ(expect, str(cloned));
 }
 
 TEST_F(HoistToDeclBeforeTest, InsertBefore_ElseIf) {
-  // fn foo() {
-  // }
-  // fn f() {
-  //     var a : bool;
-  //     if (true) {
-  //     } else if (a) {
-  //     } else {
-  //     }
-  // }
-  ProgramBuilder b;
-  b.Func("foo", {}, b.ty.void_(), {});
-  auto* var = b.Decl(b.Var("a", b.ty.bool_()));
-  auto* elseif = b.Else(b.Expr("a"), b.Block());
-  auto* s = b.If(b.Expr(true), b.Block(),  //
-                 elseif,                   //
-                 b.Else(b.Block()));
-  b.Func("f", {}, b.ty.void_(), {var, s});
+    // fn foo() {
+    // }
+    // fn f() {
+    //     var a : bool;
+    //     if (true) {
+    //     } else if (a) {
+    //     } else {
+    //     }
+    // }
+    ProgramBuilder b;
+    b.Func("foo", {}, b.ty.void_(), {});
+    auto* var = b.Decl(b.Var("a", b.ty.bool_()));
+    auto* elseif = b.If(b.Expr("a"), b.Block(), b.Else(b.Block()));
+    auto* s = b.If(b.Expr(true), b.Block(),  //
+                   b.Else(elseif));
+    b.Func("f", {}, b.ty.void_(), {var, s});
 
-  Program original(std::move(b));
-  ProgramBuilder cloned_b;
-  CloneContext ctx(&cloned_b, &original);
+    Program original(std::move(b));
+    ProgramBuilder cloned_b;
+    CloneContext ctx(&cloned_b, &original);
 
-  HoistToDeclBefore hoistToDeclBefore(ctx);
-  auto* before_stmt = ctx.src->Sem().Get(elseif);
-  auto* new_stmt = ctx.dst->CallStmt(ctx.dst->Call("foo"));
-  hoistToDeclBefore.InsertBefore(before_stmt, new_stmt);
-  hoistToDeclBefore.Apply();
+    HoistToDeclBefore hoistToDeclBefore(ctx);
+    auto* before_stmt = ctx.src->Sem().Get(elseif);
+    auto* new_stmt = ctx.dst->CallStmt(ctx.dst->Call("foo"));
+    hoistToDeclBefore.InsertBefore(before_stmt, new_stmt);
+    hoistToDeclBefore.Apply();
 
-  ctx.Clone();
-  Program cloned(std::move(cloned_b));
+    ctx.Clone();
+    Program cloned(std::move(cloned_b));
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn foo() {
 }
 
@@ -591,7 +588,7 @@
 }
 )";
 
-  EXPECT_EQ(expect, str(cloned));
+    EXPECT_EQ(expect, str(cloned));
 }
 
 }  // namespace
diff --git a/src/tint/transform/var_for_dynamic_index.cc b/src/tint/transform/var_for_dynamic_index.cc
index ccd1215..aaebdc7 100644
--- a/src/tint/transform/var_for_dynamic_index.cc
+++ b/src/tint/transform/var_for_dynamic_index.cc
@@ -22,47 +22,43 @@
 
 VarForDynamicIndex::~VarForDynamicIndex() = default;
 
-void VarForDynamicIndex::Run(CloneContext& ctx,
-                             const DataMap&,
-                             DataMap&) const {
-  HoistToDeclBefore hoist_to_decl_before(ctx);
+void VarForDynamicIndex::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
+    HoistToDeclBefore hoist_to_decl_before(ctx);
 
-  // Extracts array and matrix values that are dynamically indexed to a
-  // temporary `var` local that is then indexed.
-  auto dynamic_index_to_var =
-      [&](const ast::IndexAccessorExpression* access_expr) {
+    // Extracts array and matrix values that are dynamically indexed to a
+    // temporary `var` local that is then indexed.
+    auto dynamic_index_to_var = [&](const ast::IndexAccessorExpression* access_expr) {
         auto* index_expr = access_expr->index;
         auto* object_expr = access_expr->object;
         auto& sem = ctx.src->Sem();
 
         if (sem.Get(index_expr)->ConstantValue()) {
-          // Index expression resolves to a compile time value.
-          // As this isn't a dynamic index, we can ignore this.
-          return true;
+            // Index expression resolves to a compile time value.
+            // As this isn't a dynamic index, we can ignore this.
+            return true;
         }
 
         auto* indexed = sem.Get(object_expr);
         if (!indexed->Type()->IsAnyOf<sem::Array, sem::Matrix>()) {
-          // We only care about array and matrices.
-          return true;
+            // We only care about array and matrices.
+            return true;
         }
 
         // TODO(bclayton): group multiple accesses in the same object.
         // e.g. arr[i] + arr[i+1] // Don't create two vars for this
-        return hoist_to_decl_before.Add(indexed, object_expr, false,
-                                        "var_for_index");
-      };
+        return hoist_to_decl_before.Add(indexed, object_expr, false, "var_for_index");
+    };
 
-  for (auto* node : ctx.src->ASTNodes().Objects()) {
-    if (auto* access_expr = node->As<ast::IndexAccessorExpression>()) {
-      if (!dynamic_index_to_var(access_expr)) {
-        return;
-      }
+    for (auto* node : ctx.src->ASTNodes().Objects()) {
+        if (auto* access_expr = node->As<ast::IndexAccessorExpression>()) {
+            if (!dynamic_index_to_var(access_expr)) {
+                return;
+            }
+        }
     }
-  }
 
-  hoist_to_decl_before.Apply();
-  ctx.Clone();
+    hoist_to_decl_before.Apply();
+    ctx.Clone();
 }
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/var_for_dynamic_index.h b/src/tint/transform/var_for_dynamic_index.h
index e7e2815..39ef2f2 100644
--- a/src/tint/transform/var_for_dynamic_index.h
+++ b/src/tint/transform/var_for_dynamic_index.h
@@ -24,23 +24,21 @@
 /// transform is used by the SPIR-V writer as there is no SPIR-V instruction
 /// that can dynamically index a non-pointer composite.
 class VarForDynamicIndex : public Transform {
- public:
-  /// Constructor
-  VarForDynamicIndex();
+  public:
+    /// Constructor
+    VarForDynamicIndex();
 
-  /// Destructor
-  ~VarForDynamicIndex() override;
+    /// Destructor
+    ~VarForDynamicIndex() override;
 
- protected:
-  /// Runs the transform using the CloneContext built for transforming a
-  /// program. Run() is responsible for calling Clone() on the CloneContext.
-  /// @param ctx the CloneContext primed with the input program and
-  /// ProgramBuilder
-  /// @param inputs optional extra transform-specific input data
-  /// @param outputs optional extra transform-specific output data
-  void Run(CloneContext& ctx,
-           const DataMap& inputs,
-           DataMap& outputs) const override;
+  protected:
+    /// Runs the transform using the CloneContext built for transforming a
+    /// program. Run() is responsible for calling Clone() on the CloneContext.
+    /// @param ctx the CloneContext primed with the input program and
+    /// ProgramBuilder
+    /// @param inputs optional extra transform-specific input data
+    /// @param outputs optional extra transform-specific output data
+    void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const override;
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/var_for_dynamic_index_test.cc b/src/tint/transform/var_for_dynamic_index_test.cc
index a222ad7..ca767c9 100644
--- a/src/tint/transform/var_for_dynamic_index_test.cc
+++ b/src/tint/transform/var_for_dynamic_index_test.cc
@@ -23,16 +23,16 @@
 using VarForDynamicIndexTest = TransformTest;
 
 TEST_F(VarForDynamicIndexTest, EmptyModule) {
-  auto* src = "";
-  auto* expect = "";
+    auto* src = "";
+    auto* expect = "";
 
-  auto got = Run<ForLoopToLoop, VarForDynamicIndex>(src);
+    auto got = Run<ForLoopToLoop, VarForDynamicIndex>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(VarForDynamicIndexTest, ArrayIndexDynamic) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var i : i32;
   let p = array<i32, 4>(1, 2, 3, 4);
@@ -40,7 +40,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var i : i32;
   let p = array<i32, 4>(1, 2, 3, 4);
@@ -49,14 +49,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<VarForDynamicIndex>(src, data);
+    DataMap data;
+    auto got = Run<VarForDynamicIndex>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(VarForDynamicIndexTest, MatrixIndexDynamic) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var i : i32;
   let p = mat2x2(1.0, 2.0, 3.0, 4.0);
@@ -64,7 +64,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var i : i32;
   let p = mat2x2(1.0, 2.0, 3.0, 4.0);
@@ -73,14 +73,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<VarForDynamicIndex>(src, data);
+    DataMap data;
+    auto got = Run<VarForDynamicIndex>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(VarForDynamicIndexTest, ArrayIndexDynamicChain) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var i : i32;
   var j : i32;
@@ -89,12 +89,12 @@
 }
 )";
 
-  // TODO(bclayton): Optimize this case:
-  // This output is not as efficient as it could be.
-  // We only actually need to hoist the inner-most array to a `var`
-  // (`var_for_index`), as later indexing operations will be working with
-  // references, not values.
-  auto* expect = R"(
+    // TODO(bclayton): Optimize this case:
+    // This output is not as efficient as it could be.
+    // We only actually need to hoist the inner-most array to a `var`
+    // (`var_for_index`), as later indexing operations will be working with
+    // references, not values.
+    auto* expect = R"(
 fn f() {
   var i : i32;
   var j : i32;
@@ -105,14 +105,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<VarForDynamicIndex>(src, data);
+    DataMap data;
+    auto got = Run<VarForDynamicIndex>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(VarForDynamicIndexTest, ArrayIndexInForLoopInit) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var i : i32;
   let p = array<array<i32, 2>, 2>(array<i32, 2>(1, 2), array<i32, 2>(3, 4));
@@ -122,7 +122,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var i : i32;
   let p = array<array<i32, 2>, 2>(array<i32, 2>(1, 2), array<i32, 2>(3, 4));
@@ -133,14 +133,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<VarForDynamicIndex>(src, data);
+    DataMap data;
+    auto got = Run<VarForDynamicIndex>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(VarForDynamicIndexTest, MatrixIndexInForLoopInit) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var i : i32;
   let p = mat2x2(1.0, 2.0, 3.0, 4.0);
@@ -150,7 +150,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var i : i32;
   let p = mat2x2(1.0, 2.0, 3.0, 4.0);
@@ -161,14 +161,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<VarForDynamicIndex>(src, data);
+    DataMap data;
+    auto got = Run<VarForDynamicIndex>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(VarForDynamicIndexTest, ArrayIndexInForLoopCond) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var i : i32;
   let p = array<i32, 2>(1, 2);
@@ -178,7 +178,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var i : i32;
   let p = array<i32, 2>(1, 2);
@@ -194,14 +194,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<VarForDynamicIndex>(src, data);
+    DataMap data;
+    auto got = Run<VarForDynamicIndex>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(VarForDynamicIndexTest, MatrixIndexInForLoopCond) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var i : i32;
   let p = mat2x2(1.0, 2.0, 3.0, 4.0);
@@ -211,7 +211,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var i : i32;
   let p = mat2x2(1.0, 2.0, 3.0, 4.0);
@@ -227,14 +227,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<VarForDynamicIndex>(src, data);
+    DataMap data;
+    auto got = Run<VarForDynamicIndex>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(VarForDynamicIndexTest, MatrixIndexInForLoopCondWithNestedIndex) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var i : i32;
   let p = mat2x2(1.0, 2.0, 3.0, 4.0);
@@ -247,7 +247,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var i : i32;
   let p = mat2x2(1.0, 2.0, 3.0, 4.0);
@@ -267,14 +267,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<VarForDynamicIndex>(src, data);
+    DataMap data;
+    auto got = Run<VarForDynamicIndex>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(VarForDynamicIndexTest, ArrayIndexInElseIf) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var i : i32;
   let p = array<i32, 2>(1, 2);
@@ -286,7 +286,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var i : i32;
   let p = array<i32, 2>(1, 2);
@@ -301,14 +301,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<VarForDynamicIndex>(src, data);
+    DataMap data;
+    auto got = Run<VarForDynamicIndex>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(VarForDynamicIndexTest, ArrayIndexInElseIfChain) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var i : i32;
   let p = array<i32, 2>(1, 2);
@@ -328,7 +328,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var i : i32;
   let p = array<i32, 2>(1, 2);
@@ -354,14 +354,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<VarForDynamicIndex>(src, data);
+    DataMap data;
+    auto got = Run<VarForDynamicIndex>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(VarForDynamicIndexTest, MatrixIndexInElseIf) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var i : i32;
   let p = mat2x2(1.0, 2.0, 3.0, 4.0);
@@ -373,7 +373,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var i : i32;
   let p = mat2x2(1.0, 2.0, 3.0, 4.0);
@@ -388,14 +388,14 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<VarForDynamicIndex>(src, data);
+    DataMap data;
+    auto got = Run<VarForDynamicIndex>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(VarForDynamicIndexTest, MatrixIndexInElseIfChain) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var i : i32;
   let p = mat2x2(1.0, 2.0, 3.0, 4.0);
@@ -415,7 +415,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 fn f() {
   var i : i32;
   let p = mat2x2(1.0, 2.0, 3.0, 4.0);
@@ -441,46 +441,46 @@
 }
 )";
 
-  DataMap data;
-  auto got = Run<VarForDynamicIndex>(src, data);
+    DataMap data;
+    auto got = Run<VarForDynamicIndex>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(VarForDynamicIndexTest, ArrayIndexLiteral) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let p = array<i32, 4>(1, 2, 3, 4);
   let x = p[1];
 }
 )";
 
-  auto* expect = src;
+    auto* expect = src;
 
-  DataMap data;
-  auto got = Run<VarForDynamicIndex>(src, data);
+    DataMap data;
+    auto got = Run<VarForDynamicIndex>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(VarForDynamicIndexTest, MatrixIndexLiteral) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let p = mat2x2(1.0, 2.0, 3.0, 4.0);
   let x = p[1];
 }
 )";
 
-  auto* expect = src;
+    auto* expect = src;
 
-  DataMap data;
-  auto got = Run<VarForDynamicIndex>(src, data);
+    DataMap data;
+    auto got = Run<VarForDynamicIndex>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(VarForDynamicIndexTest, ArrayIndexConstantLet) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let p = array<i32, 4>(1, 2, 3, 4);
   let c = 1;
@@ -488,16 +488,16 @@
 }
 )";
 
-  auto* expect = src;
+    auto* expect = src;
 
-  DataMap data;
-  auto got = Run<VarForDynamicIndex>(src, data);
+    DataMap data;
+    auto got = Run<VarForDynamicIndex>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(VarForDynamicIndexTest, MatrixIndexConstantLet) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let p = mat2x2(1.0, 2.0, 3.0, 4.0);
   let c = 1;
@@ -505,16 +505,16 @@
 }
 )";
 
-  auto* expect = src;
+    auto* expect = src;
 
-  DataMap data;
-  auto got = Run<VarForDynamicIndex>(src, data);
+    DataMap data;
+    auto got = Run<VarForDynamicIndex>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(VarForDynamicIndexTest, ArrayIndexLiteralChain) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let a = array<i32, 2>(1, 2);
   let b = array<i32, 2>(3, 4);
@@ -523,28 +523,28 @@
 }
 )";
 
-  auto* expect = src;
+    auto* expect = src;
 
-  DataMap data;
-  auto got = Run<VarForDynamicIndex>(src, data);
+    DataMap data;
+    auto got = Run<VarForDynamicIndex>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(VarForDynamicIndexTest, MatrixIndexLiteralChain) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   let p = mat2x2(1.0, 2.0, 3.0, 4.0);
   let x = p[0][1];
 }
 )";
 
-  auto* expect = src;
+    auto* expect = src;
 
-  DataMap data;
-  auto got = Run<VarForDynamicIndex>(src, data);
+    DataMap data;
+    auto got = Run<VarForDynamicIndex>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 }  // namespace
diff --git a/src/tint/transform/vectorize_scalar_matrix_constructors.cc b/src/tint/transform/vectorize_scalar_matrix_constructors.cc
index 8af0272..80e8b1e 100644
--- a/src/tint/transform/vectorize_scalar_matrix_constructors.cc
+++ b/src/tint/transform/vectorize_scalar_matrix_constructors.cc
@@ -25,71 +25,63 @@
 
 namespace tint::transform {
 
-VectorizeScalarMatrixConstructors::VectorizeScalarMatrixConstructors() =
-    default;
+VectorizeScalarMatrixConstructors::VectorizeScalarMatrixConstructors() = default;
 
-VectorizeScalarMatrixConstructors::~VectorizeScalarMatrixConstructors() =
-    default;
+VectorizeScalarMatrixConstructors::~VectorizeScalarMatrixConstructors() = default;
 
-bool VectorizeScalarMatrixConstructors::ShouldRun(const Program* program,
-                                                  const DataMap&) const {
-  for (auto* node : program->ASTNodes().Objects()) {
-    if (auto* call = program->Sem().Get<sem::Call>(node)) {
-      if (call->Target()->Is<sem::TypeConstructor>() &&
-          call->Type()->Is<sem::Matrix>()) {
-        auto& args = call->Arguments();
-        if (args.size() > 0 && args[0]->Type()->is_scalar()) {
-          return true;
+bool VectorizeScalarMatrixConstructors::ShouldRun(const Program* program, const DataMap&) const {
+    for (auto* node : program->ASTNodes().Objects()) {
+        if (auto* call = program->Sem().Get<sem::Call>(node)) {
+            if (call->Target()->Is<sem::TypeConstructor>() && call->Type()->Is<sem::Matrix>()) {
+                auto& args = call->Arguments();
+                if (args.size() > 0 && args[0]->Type()->is_scalar()) {
+                    return true;
+                }
+            }
         }
-      }
     }
-  }
-  return false;
+    return false;
 }
 
-void VectorizeScalarMatrixConstructors::Run(CloneContext& ctx,
-                                            const DataMap&,
-                                            DataMap&) const {
-  ctx.ReplaceAll(
-      [&](const ast::CallExpression* expr) -> const ast::CallExpression* {
+void VectorizeScalarMatrixConstructors::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
+    ctx.ReplaceAll([&](const ast::CallExpression* expr) -> const ast::CallExpression* {
         auto* call = ctx.src->Sem().Get(expr);
         auto* ty_ctor = call->Target()->As<sem::TypeConstructor>();
         if (!ty_ctor) {
-          return nullptr;
+            return nullptr;
         }
         // Check if this is a matrix constructor with scalar arguments.
         auto* mat_type = call->Type()->As<sem::Matrix>();
         if (!mat_type) {
-          return nullptr;
+            return nullptr;
         }
 
         auto& args = call->Arguments();
         if (args.size() == 0) {
-          return nullptr;
+            return nullptr;
         }
         if (!args[0]->Type()->is_scalar()) {
-          return nullptr;
+            return nullptr;
         }
 
         // Build a list of vector expressions for each column.
         ast::ExpressionList columns;
         for (uint32_t c = 0; c < mat_type->columns(); c++) {
-          // Build a list of scalar expressions for each value in the column.
-          ast::ExpressionList row_values;
-          for (uint32_t r = 0; r < mat_type->rows(); r++) {
-            row_values.push_back(
-                ctx.Clone(args[c * mat_type->rows() + r]->Declaration()));
-          }
+            // Build a list of scalar expressions for each value in the column.
+            ast::ExpressionList row_values;
+            for (uint32_t r = 0; r < mat_type->rows(); r++) {
+                row_values.push_back(ctx.Clone(args[c * mat_type->rows() + r]->Declaration()));
+            }
 
-          // Construct the column vector.
-          auto* col = ctx.dst->vec(CreateASTTypeFor(ctx, mat_type->type()),
-                                   mat_type->rows(), row_values);
-          columns.push_back(col);
+            // Construct the column vector.
+            auto* col =
+                ctx.dst->vec(CreateASTTypeFor(ctx, mat_type->type()), mat_type->rows(), row_values);
+            columns.push_back(col);
         }
         return ctx.dst->Construct(CreateASTTypeFor(ctx, mat_type), columns);
-      });
+    });
 
-  ctx.Clone();
+    ctx.Clone();
 }
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/vectorize_scalar_matrix_constructors.h b/src/tint/transform/vectorize_scalar_matrix_constructors.h
index f1abb4f..83c4ce1 100644
--- a/src/tint/transform/vectorize_scalar_matrix_constructors.h
+++ b/src/tint/transform/vectorize_scalar_matrix_constructors.h
@@ -22,29 +22,26 @@
 /// A transform that converts scalar matrix constructors to the vector form.
 class VectorizeScalarMatrixConstructors
     : public Castable<VectorizeScalarMatrixConstructors, Transform> {
- public:
-  /// Constructor
-  VectorizeScalarMatrixConstructors();
+  public:
+    /// Constructor
+    VectorizeScalarMatrixConstructors();
 
-  /// Destructor
-  ~VectorizeScalarMatrixConstructors() override;
+    /// Destructor
+    ~VectorizeScalarMatrixConstructors() override;
 
-  /// @param program the program to inspect
-  /// @param data optional extra transform-specific input data
-  /// @returns true if this transform should be run for the given program
-  bool ShouldRun(const Program* program,
-                 const DataMap& data = {}) const override;
+    /// @param program the program to inspect
+    /// @param data optional extra transform-specific input data
+    /// @returns true if this transform should be run for the given program
+    bool ShouldRun(const Program* program, const DataMap& data = {}) const override;
 
- protected:
-  /// Runs the transform using the CloneContext built for transforming a
-  /// program. Run() is responsible for calling Clone() on the CloneContext.
-  /// @param ctx the CloneContext primed with the input program and
-  /// ProgramBuilder
-  /// @param inputs optional extra transform-specific input data
-  /// @param outputs optional extra transform-specific output data
-  void Run(CloneContext& ctx,
-           const DataMap& inputs,
-           DataMap& outputs) const override;
+  protected:
+    /// Runs the transform using the CloneContext built for transforming a
+    /// program. Run() is responsible for calling Clone() on the CloneContext.
+    /// @param ctx the CloneContext primed with the input program and
+    /// ProgramBuilder
+    /// @param inputs optional extra transform-specific input data
+    /// @param outputs optional extra transform-specific output data
+    void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const override;
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/vectorize_scalar_matrix_constructors_test.cc b/src/tint/transform/vectorize_scalar_matrix_constructors_test.cc
index edd68e2..242151a 100644
--- a/src/tint/transform/vectorize_scalar_matrix_constructors_test.cc
+++ b/src/tint/transform/vectorize_scalar_matrix_constructors_test.cc
@@ -23,87 +23,84 @@
 namespace tint::transform {
 namespace {
 
-using VectorizeScalarMatrixConstructorsTest =
-    TransformTestWithParam<std::pair<uint32_t, uint32_t>>;
+using VectorizeScalarMatrixConstructorsTest = TransformTestWithParam<std::pair<uint32_t, uint32_t>>;
 
 TEST_F(VectorizeScalarMatrixConstructorsTest, ShouldRunEmptyModule) {
-  auto* src = R"()";
+    auto* src = R"()";
 
-  EXPECT_FALSE(ShouldRun<VectorizeScalarMatrixConstructors>(src));
+    EXPECT_FALSE(ShouldRun<VectorizeScalarMatrixConstructors>(src));
 }
 
 TEST_P(VectorizeScalarMatrixConstructorsTest, Basic) {
-  uint32_t cols = GetParam().first;
-  uint32_t rows = GetParam().second;
-  std::string mat_type =
-      "mat" + std::to_string(cols) + "x" + std::to_string(rows) + "<f32>";
-  std::string vec_type = "vec" + std::to_string(rows) + "<f32>";
-  std::string scalar_values;
-  std::string vector_values;
-  for (uint32_t c = 0; c < cols; c++) {
-    if (c > 0) {
-      vector_values += ", ";
-      scalar_values += ", ";
+    uint32_t cols = GetParam().first;
+    uint32_t rows = GetParam().second;
+    std::string mat_type = "mat" + std::to_string(cols) + "x" + std::to_string(rows) + "<f32>";
+    std::string vec_type = "vec" + std::to_string(rows) + "<f32>";
+    std::string scalar_values;
+    std::string vector_values;
+    for (uint32_t c = 0; c < cols; c++) {
+        if (c > 0) {
+            vector_values += ", ";
+            scalar_values += ", ";
+        }
+        vector_values += vec_type + "(";
+        for (uint32_t r = 0; r < rows; r++) {
+            if (r > 0) {
+                scalar_values += ", ";
+                vector_values += ", ";
+            }
+            auto value = std::to_string(c * rows + r) + ".0";
+            scalar_values += value;
+            vector_values += value;
+        }
+        vector_values += ")";
     }
-    vector_values += vec_type + "(";
-    for (uint32_t r = 0; r < rows; r++) {
-      if (r > 0) {
-        scalar_values += ", ";
-        vector_values += ", ";
-      }
-      auto value = std::to_string(c * rows + r) + ".0";
-      scalar_values += value;
-      vector_values += value;
-    }
-    vector_values += ")";
-  }
 
-  std::string tmpl = R"(
+    std::string tmpl = R"(
 @stage(fragment)
 fn main() {
   let m = ${matrix}(${values});
 }
 )";
-  tmpl = utils::ReplaceAll(tmpl, "${matrix}", mat_type);
-  auto src = utils::ReplaceAll(tmpl, "${values}", scalar_values);
-  auto expect = utils::ReplaceAll(tmpl, "${values}", vector_values);
+    tmpl = utils::ReplaceAll(tmpl, "${matrix}", mat_type);
+    auto src = utils::ReplaceAll(tmpl, "${values}", scalar_values);
+    auto expect = utils::ReplaceAll(tmpl, "${values}", vector_values);
 
-  EXPECT_TRUE(ShouldRun<VectorizeScalarMatrixConstructors>(src));
+    EXPECT_TRUE(ShouldRun<VectorizeScalarMatrixConstructors>(src));
 
-  auto got = Run<VectorizeScalarMatrixConstructors>(src);
+    auto got = Run<VectorizeScalarMatrixConstructors>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_P(VectorizeScalarMatrixConstructorsTest, NonScalarConstructors) {
-  uint32_t cols = GetParam().first;
-  uint32_t rows = GetParam().second;
-  std::string mat_type =
-      "mat" + std::to_string(cols) + "x" + std::to_string(rows) + "<f32>";
-  std::string vec_type = "vec" + std::to_string(rows) + "<f32>";
-  std::string columns;
-  for (uint32_t c = 0; c < cols; c++) {
-    if (c > 0) {
-      columns += ", ";
+    uint32_t cols = GetParam().first;
+    uint32_t rows = GetParam().second;
+    std::string mat_type = "mat" + std::to_string(cols) + "x" + std::to_string(rows) + "<f32>";
+    std::string vec_type = "vec" + std::to_string(rows) + "<f32>";
+    std::string columns;
+    for (uint32_t c = 0; c < cols; c++) {
+        if (c > 0) {
+            columns += ", ";
+        }
+        columns += vec_type + "()";
     }
-    columns += vec_type + "()";
-  }
 
-  std::string tmpl = R"(
+    std::string tmpl = R"(
 @stage(fragment)
 fn main() {
   let m = ${matrix}(${columns});
 }
 )";
-  tmpl = utils::ReplaceAll(tmpl, "${matrix}", mat_type);
-  auto src = utils::ReplaceAll(tmpl, "${columns}", columns);
-  auto expect = src;
+    tmpl = utils::ReplaceAll(tmpl, "${matrix}", mat_type);
+    auto src = utils::ReplaceAll(tmpl, "${columns}", columns);
+    auto expect = src;
 
-  EXPECT_FALSE(ShouldRun<VectorizeScalarMatrixConstructors>(src));
+    EXPECT_FALSE(ShouldRun<VectorizeScalarMatrixConstructors>(src));
 
-  auto got = Run<VectorizeScalarMatrixConstructors>(src);
+    auto got = Run<VectorizeScalarMatrixConstructors>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 INSTANTIATE_TEST_SUITE_P(VectorizeScalarMatrixConstructorsTest,
diff --git a/src/tint/transform/vertex_pulling.cc b/src/tint/transform/vertex_pulling.cc
index 4200767..6d315f5 100644
--- a/src/tint/transform/vertex_pulling.cc
+++ b/src/tint/transform/vertex_pulling.cc
@@ -28,6 +28,8 @@
 TINT_INSTANTIATE_TYPEINFO(tint::transform::VertexPulling);
 TINT_INSTANTIATE_TYPEINFO(tint::transform::VertexPulling::Config);
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::transform {
 
 namespace {
@@ -35,10 +37,10 @@
 /// The base type of a component.
 /// The format type is either this type or a vector of this type.
 enum class BaseType {
-  kInvalid,
-  kU32,
-  kI32,
-  kF32,
+    kInvalid,
+    kU32,
+    kI32,
+    kF32,
 };
 
 /// Writes the BaseType to the std::ostream.
@@ -46,17 +48,17 @@
 /// @param format the BaseType to write
 /// @returns out so calls can be chained
 std::ostream& operator<<(std::ostream& out, BaseType format) {
-  switch (format) {
-    case BaseType::kInvalid:
-      return out << "invalid";
-    case BaseType::kU32:
-      return out << "u32";
-    case BaseType::kI32:
-      return out << "i32";
-    case BaseType::kF32:
-      return out << "f32";
-  }
-  return out << "<unknown>";
+    switch (format) {
+        case BaseType::kInvalid:
+            return out << "invalid";
+        case BaseType::kU32:
+            return out << "u32";
+        case BaseType::kI32:
+            return out << "i32";
+        case BaseType::kF32:
+            return out << "f32";
+    }
+    return out << "<unknown>";
 }
 
 /// Writes the VertexFormat to the std::ostream.
@@ -64,837 +66,800 @@
 /// @param format the VertexFormat to write
 /// @returns out so calls can be chained
 std::ostream& operator<<(std::ostream& out, VertexFormat format) {
-  switch (format) {
-    case VertexFormat::kUint8x2:
-      return out << "uint8x2";
-    case VertexFormat::kUint8x4:
-      return out << "uint8x4";
-    case VertexFormat::kSint8x2:
-      return out << "sint8x2";
-    case VertexFormat::kSint8x4:
-      return out << "sint8x4";
-    case VertexFormat::kUnorm8x2:
-      return out << "unorm8x2";
-    case VertexFormat::kUnorm8x4:
-      return out << "unorm8x4";
-    case VertexFormat::kSnorm8x2:
-      return out << "snorm8x2";
-    case VertexFormat::kSnorm8x4:
-      return out << "snorm8x4";
-    case VertexFormat::kUint16x2:
-      return out << "uint16x2";
-    case VertexFormat::kUint16x4:
-      return out << "uint16x4";
-    case VertexFormat::kSint16x2:
-      return out << "sint16x2";
-    case VertexFormat::kSint16x4:
-      return out << "sint16x4";
-    case VertexFormat::kUnorm16x2:
-      return out << "unorm16x2";
-    case VertexFormat::kUnorm16x4:
-      return out << "unorm16x4";
-    case VertexFormat::kSnorm16x2:
-      return out << "snorm16x2";
-    case VertexFormat::kSnorm16x4:
-      return out << "snorm16x4";
-    case VertexFormat::kFloat16x2:
-      return out << "float16x2";
-    case VertexFormat::kFloat16x4:
-      return out << "float16x4";
-    case VertexFormat::kFloat32:
-      return out << "float32";
-    case VertexFormat::kFloat32x2:
-      return out << "float32x2";
-    case VertexFormat::kFloat32x3:
-      return out << "float32x3";
-    case VertexFormat::kFloat32x4:
-      return out << "float32x4";
-    case VertexFormat::kUint32:
-      return out << "uint32";
-    case VertexFormat::kUint32x2:
-      return out << "uint32x2";
-    case VertexFormat::kUint32x3:
-      return out << "uint32x3";
-    case VertexFormat::kUint32x4:
-      return out << "uint32x4";
-    case VertexFormat::kSint32:
-      return out << "sint32";
-    case VertexFormat::kSint32x2:
-      return out << "sint32x2";
-    case VertexFormat::kSint32x3:
-      return out << "sint32x3";
-    case VertexFormat::kSint32x4:
-      return out << "sint32x4";
-  }
-  return out << "<unknown>";
+    switch (format) {
+        case VertexFormat::kUint8x2:
+            return out << "uint8x2";
+        case VertexFormat::kUint8x4:
+            return out << "uint8x4";
+        case VertexFormat::kSint8x2:
+            return out << "sint8x2";
+        case VertexFormat::kSint8x4:
+            return out << "sint8x4";
+        case VertexFormat::kUnorm8x2:
+            return out << "unorm8x2";
+        case VertexFormat::kUnorm8x4:
+            return out << "unorm8x4";
+        case VertexFormat::kSnorm8x2:
+            return out << "snorm8x2";
+        case VertexFormat::kSnorm8x4:
+            return out << "snorm8x4";
+        case VertexFormat::kUint16x2:
+            return out << "uint16x2";
+        case VertexFormat::kUint16x4:
+            return out << "uint16x4";
+        case VertexFormat::kSint16x2:
+            return out << "sint16x2";
+        case VertexFormat::kSint16x4:
+            return out << "sint16x4";
+        case VertexFormat::kUnorm16x2:
+            return out << "unorm16x2";
+        case VertexFormat::kUnorm16x4:
+            return out << "unorm16x4";
+        case VertexFormat::kSnorm16x2:
+            return out << "snorm16x2";
+        case VertexFormat::kSnorm16x4:
+            return out << "snorm16x4";
+        case VertexFormat::kFloat16x2:
+            return out << "float16x2";
+        case VertexFormat::kFloat16x4:
+            return out << "float16x4";
+        case VertexFormat::kFloat32:
+            return out << "float32";
+        case VertexFormat::kFloat32x2:
+            return out << "float32x2";
+        case VertexFormat::kFloat32x3:
+            return out << "float32x3";
+        case VertexFormat::kFloat32x4:
+            return out << "float32x4";
+        case VertexFormat::kUint32:
+            return out << "uint32";
+        case VertexFormat::kUint32x2:
+            return out << "uint32x2";
+        case VertexFormat::kUint32x3:
+            return out << "uint32x3";
+        case VertexFormat::kUint32x4:
+            return out << "uint32x4";
+        case VertexFormat::kSint32:
+            return out << "sint32";
+        case VertexFormat::kSint32x2:
+            return out << "sint32x2";
+        case VertexFormat::kSint32x3:
+            return out << "sint32x3";
+        case VertexFormat::kSint32x4:
+            return out << "sint32x4";
+    }
+    return out << "<unknown>";
 }
 
 /// A vertex attribute data format.
 struct DataType {
-  BaseType base_type;
-  uint32_t width;  // 1 for scalar, 2+ for a vector
+    BaseType base_type;
+    uint32_t width;  // 1 for scalar, 2+ for a vector
 };
 
 DataType DataTypeOf(const sem::Type* ty) {
-  if (ty->Is<sem::I32>()) {
-    return {BaseType::kI32, 1};
-  }
-  if (ty->Is<sem::U32>()) {
-    return {BaseType::kU32, 1};
-  }
-  if (ty->Is<sem::F32>()) {
-    return {BaseType::kF32, 1};
-  }
-  if (auto* vec = ty->As<sem::Vector>()) {
-    return {DataTypeOf(vec->type()).base_type, vec->Width()};
-  }
-  return {BaseType::kInvalid, 0};
+    if (ty->Is<sem::I32>()) {
+        return {BaseType::kI32, 1};
+    }
+    if (ty->Is<sem::U32>()) {
+        return {BaseType::kU32, 1};
+    }
+    if (ty->Is<sem::F32>()) {
+        return {BaseType::kF32, 1};
+    }
+    if (auto* vec = ty->As<sem::Vector>()) {
+        return {DataTypeOf(vec->type()).base_type, vec->Width()};
+    }
+    return {BaseType::kInvalid, 0};
 }
 
 DataType DataTypeOf(VertexFormat format) {
-  switch (format) {
-    case VertexFormat::kUint32:
-      return {BaseType::kU32, 1};
-    case VertexFormat::kUint8x2:
-    case VertexFormat::kUint16x2:
-    case VertexFormat::kUint32x2:
-      return {BaseType::kU32, 2};
-    case VertexFormat::kUint32x3:
-      return {BaseType::kU32, 3};
-    case VertexFormat::kUint8x4:
-    case VertexFormat::kUint16x4:
-    case VertexFormat::kUint32x4:
-      return {BaseType::kU32, 4};
-    case VertexFormat::kSint32:
-      return {BaseType::kI32, 1};
-    case VertexFormat::kSint8x2:
-    case VertexFormat::kSint16x2:
-    case VertexFormat::kSint32x2:
-      return {BaseType::kI32, 2};
-    case VertexFormat::kSint32x3:
-      return {BaseType::kI32, 3};
-    case VertexFormat::kSint8x4:
-    case VertexFormat::kSint16x4:
-    case VertexFormat::kSint32x4:
-      return {BaseType::kI32, 4};
-    case VertexFormat::kFloat32:
-      return {BaseType::kF32, 1};
-    case VertexFormat::kUnorm8x2:
-    case VertexFormat::kSnorm8x2:
-    case VertexFormat::kUnorm16x2:
-    case VertexFormat::kSnorm16x2:
-    case VertexFormat::kFloat16x2:
-    case VertexFormat::kFloat32x2:
-      return {BaseType::kF32, 2};
-    case VertexFormat::kFloat32x3:
-      return {BaseType::kF32, 3};
-    case VertexFormat::kUnorm8x4:
-    case VertexFormat::kSnorm8x4:
-    case VertexFormat::kUnorm16x4:
-    case VertexFormat::kSnorm16x4:
-    case VertexFormat::kFloat16x4:
-    case VertexFormat::kFloat32x4:
-      return {BaseType::kF32, 4};
-  }
-  return {BaseType::kInvalid, 0};
+    switch (format) {
+        case VertexFormat::kUint32:
+            return {BaseType::kU32, 1};
+        case VertexFormat::kUint8x2:
+        case VertexFormat::kUint16x2:
+        case VertexFormat::kUint32x2:
+            return {BaseType::kU32, 2};
+        case VertexFormat::kUint32x3:
+            return {BaseType::kU32, 3};
+        case VertexFormat::kUint8x4:
+        case VertexFormat::kUint16x4:
+        case VertexFormat::kUint32x4:
+            return {BaseType::kU32, 4};
+        case VertexFormat::kSint32:
+            return {BaseType::kI32, 1};
+        case VertexFormat::kSint8x2:
+        case VertexFormat::kSint16x2:
+        case VertexFormat::kSint32x2:
+            return {BaseType::kI32, 2};
+        case VertexFormat::kSint32x3:
+            return {BaseType::kI32, 3};
+        case VertexFormat::kSint8x4:
+        case VertexFormat::kSint16x4:
+        case VertexFormat::kSint32x4:
+            return {BaseType::kI32, 4};
+        case VertexFormat::kFloat32:
+            return {BaseType::kF32, 1};
+        case VertexFormat::kUnorm8x2:
+        case VertexFormat::kSnorm8x2:
+        case VertexFormat::kUnorm16x2:
+        case VertexFormat::kSnorm16x2:
+        case VertexFormat::kFloat16x2:
+        case VertexFormat::kFloat32x2:
+            return {BaseType::kF32, 2};
+        case VertexFormat::kFloat32x3:
+            return {BaseType::kF32, 3};
+        case VertexFormat::kUnorm8x4:
+        case VertexFormat::kSnorm8x4:
+        case VertexFormat::kUnorm16x4:
+        case VertexFormat::kSnorm16x4:
+        case VertexFormat::kFloat16x4:
+        case VertexFormat::kFloat32x4:
+            return {BaseType::kF32, 4};
+    }
+    return {BaseType::kInvalid, 0};
 }
 
 struct State {
-  State(CloneContext& context, const VertexPulling::Config& c)
-      : ctx(context), cfg(c) {}
-  State(const State&) = default;
-  ~State() = default;
+    State(CloneContext& context, const VertexPulling::Config& c) : ctx(context), cfg(c) {}
+    State(const State&) = default;
+    ~State() = default;
 
-  /// LocationReplacement describes an ast::Variable replacement for a
-  /// location input.
-  struct LocationReplacement {
-    /// The variable to replace in the source Program
-    ast::Variable* from;
-    /// The replacement to use in the target ProgramBuilder
-    ast::Variable* to;
-  };
+    /// LocationReplacement describes an ast::Variable replacement for a
+    /// location input.
+    struct LocationReplacement {
+        /// The variable to replace in the source Program
+        ast::Variable* from;
+        /// The replacement to use in the target ProgramBuilder
+        ast::Variable* to;
+    };
 
-  struct LocationInfo {
-    std::function<const ast::Expression*()> expr;
-    const sem::Type* type;
-  };
+    struct LocationInfo {
+        std::function<const ast::Expression*()> expr;
+        const sem::Type* type;
+    };
 
-  CloneContext& ctx;
-  VertexPulling::Config const cfg;
-  std::unordered_map<uint32_t, LocationInfo> location_info;
-  std::function<const ast::Expression*()> vertex_index_expr = nullptr;
-  std::function<const ast::Expression*()> instance_index_expr = nullptr;
-  Symbol pulling_position_name;
-  Symbol struct_buffer_name;
-  std::unordered_map<uint32_t, Symbol> vertex_buffer_names;
-  ast::VariableList new_function_parameters;
+    CloneContext& ctx;
+    VertexPulling::Config const cfg;
+    std::unordered_map<uint32_t, LocationInfo> location_info;
+    std::function<const ast::Expression*()> vertex_index_expr = nullptr;
+    std::function<const ast::Expression*()> instance_index_expr = nullptr;
+    Symbol pulling_position_name;
+    Symbol struct_buffer_name;
+    std::unordered_map<uint32_t, Symbol> vertex_buffer_names;
+    ast::VariableList new_function_parameters;
 
-  /// Generate the vertex buffer binding name
-  /// @param index index to append to buffer name
-  Symbol GetVertexBufferName(uint32_t index) {
-    return utils::GetOrCreate(vertex_buffer_names, index, [&] {
-      static const char kVertexBufferNamePrefix[] =
-          "tint_pulling_vertex_buffer_";
-      return ctx.dst->Symbols().New(kVertexBufferNamePrefix +
-                                    std::to_string(index));
-    });
-  }
-
-  /// Lazily generates the structure buffer symbol
-  Symbol GetStructBufferName() {
-    if (!struct_buffer_name.IsValid()) {
-      static const char kStructBufferName[] = "tint_vertex_data";
-      struct_buffer_name = ctx.dst->Symbols().New(kStructBufferName);
-    }
-    return struct_buffer_name;
-  }
-
-  /// Adds storage buffer decorated variables for the vertex buffers
-  void AddVertexStorageBuffers() {
-    // Creating the struct type
-    static const char kStructName[] = "TintVertexData";
-    auto* struct_type = ctx.dst->Structure(
-        ctx.dst->Symbols().New(kStructName),
-        {
-            ctx.dst->Member(GetStructBufferName(),
-                            ctx.dst->ty.array<ProgramBuilder::u32>()),
+    /// Generate the vertex buffer binding name
+    /// @param index index to append to buffer name
+    Symbol GetVertexBufferName(uint32_t index) {
+        return utils::GetOrCreate(vertex_buffer_names, index, [&] {
+            static const char kVertexBufferNamePrefix[] = "tint_pulling_vertex_buffer_";
+            return ctx.dst->Symbols().New(kVertexBufferNamePrefix + std::to_string(index));
         });
-    for (uint32_t i = 0; i < cfg.vertex_state.size(); ++i) {
-      // The decorated variable with struct type
-      ctx.dst->Global(
-          GetVertexBufferName(i), ctx.dst->ty.Of(struct_type),
-          ast::StorageClass::kStorage, ast::Access::kRead,
-          ast::AttributeList{
-              ctx.dst->create<ast::BindingAttribute>(i),
-              ctx.dst->create<ast::GroupAttribute>(cfg.pulling_group),
-          });
     }
-  }
 
-  /// Creates and returns the assignment to the variables from the buffers
-  ast::BlockStatement* CreateVertexPullingPreamble() {
-    // Assign by looking at the vertex descriptor to find attributes with
-    // matching location.
-
-    ast::StatementList stmts;
-
-    for (uint32_t buffer_idx = 0; buffer_idx < cfg.vertex_state.size();
-         ++buffer_idx) {
-      const VertexBufferLayoutDescriptor& buffer_layout =
-          cfg.vertex_state[buffer_idx];
-
-      if ((buffer_layout.array_stride & 3) != 0) {
-        ctx.dst->Diagnostics().add_error(
-            diag::System::Transform,
-            "WebGPU requires that vertex stride must be a multiple of 4 bytes, "
-            "but VertexPulling array stride for buffer " +
-                std::to_string(buffer_idx) + " was " +
-                std::to_string(buffer_layout.array_stride) + " bytes");
-        return nullptr;
-      }
-
-      auto* index_expr = buffer_layout.step_mode == VertexStepMode::kVertex
-                             ? vertex_index_expr()
-                             : instance_index_expr();
-
-      // buffer_array_base is the base array offset for all the vertex
-      // attributes. These are units of uint (4 bytes).
-      auto buffer_array_base = ctx.dst->Symbols().New(
-          "buffer_array_base_" + std::to_string(buffer_idx));
-
-      auto* attribute_offset = index_expr;
-      if (buffer_layout.array_stride != 4) {
-        attribute_offset =
-            ctx.dst->Mul(index_expr, buffer_layout.array_stride / 4u);
-      }
-
-      // let pulling_offset_n = <attribute_offset>
-      stmts.emplace_back(ctx.dst->Decl(
-          ctx.dst->Const(buffer_array_base, nullptr, attribute_offset)));
-
-      for (const VertexAttributeDescriptor& attribute_desc :
-           buffer_layout.attributes) {
-        auto it = location_info.find(attribute_desc.shader_location);
-        if (it == location_info.end()) {
-          continue;
+    /// Lazily generates the structure buffer symbol
+    Symbol GetStructBufferName() {
+        if (!struct_buffer_name.IsValid()) {
+            static const char kStructBufferName[] = "tint_vertex_data";
+            struct_buffer_name = ctx.dst->Symbols().New(kStructBufferName);
         }
-        auto& var = it->second;
+        return struct_buffer_name;
+    }
 
-        // Data type of the target WGSL variable
-        auto var_dt = DataTypeOf(var.type);
-        // Data type of the vertex stream attribute
-        auto fmt_dt = DataTypeOf(attribute_desc.format);
+    /// Adds storage buffer decorated variables for the vertex buffers
+    void AddVertexStorageBuffers() {
+        // Creating the struct type
+        static const char kStructName[] = "TintVertexData";
+        auto* struct_type =
+            ctx.dst->Structure(ctx.dst->Symbols().New(kStructName),
+                               {
+                                   ctx.dst->Member(GetStructBufferName(), ctx.dst->ty.array<u32>()),
+                               });
+        for (uint32_t i = 0; i < cfg.vertex_state.size(); ++i) {
+            // The decorated variable with struct type
+            ctx.dst->Global(GetVertexBufferName(i), ctx.dst->ty.Of(struct_type),
+                            ast::StorageClass::kStorage, ast::Access::kRead,
+                            ast::AttributeList{
+                                ctx.dst->create<ast::BindingAttribute>(i),
+                                ctx.dst->create<ast::GroupAttribute>(cfg.pulling_group),
+                            });
+        }
+    }
 
-        // Base types must match between the vertex stream and the WGSL variable
-        if (var_dt.base_type != fmt_dt.base_type) {
-          std::stringstream err;
-          err << "VertexAttributeDescriptor for location "
-              << std::to_string(attribute_desc.shader_location)
-              << " has format " << attribute_desc.format
-              << " but shader expects "
-              << var.type->FriendlyName(ctx.src->Symbols());
-          ctx.dst->Diagnostics().add_error(diag::System::Transform, err.str());
-          return nullptr;
+    /// Creates and returns the assignment to the variables from the buffers
+    ast::BlockStatement* CreateVertexPullingPreamble() {
+        // Assign by looking at the vertex descriptor to find attributes with
+        // matching location.
+
+        ast::StatementList stmts;
+
+        for (uint32_t buffer_idx = 0; buffer_idx < cfg.vertex_state.size(); ++buffer_idx) {
+            const VertexBufferLayoutDescriptor& buffer_layout = cfg.vertex_state[buffer_idx];
+
+            if ((buffer_layout.array_stride & 3) != 0) {
+                ctx.dst->Diagnostics().add_error(
+                    diag::System::Transform,
+                    "WebGPU requires that vertex stride must be a multiple of 4 bytes, "
+                    "but VertexPulling array stride for buffer " +
+                        std::to_string(buffer_idx) + " was " +
+                        std::to_string(buffer_layout.array_stride) + " bytes");
+                return nullptr;
+            }
+
+            auto* index_expr = buffer_layout.step_mode == VertexStepMode::kVertex
+                                   ? vertex_index_expr()
+                                   : instance_index_expr();
+
+            // buffer_array_base is the base array offset for all the vertex
+            // attributes. These are units of uint (4 bytes).
+            auto buffer_array_base =
+                ctx.dst->Symbols().New("buffer_array_base_" + std::to_string(buffer_idx));
+
+            auto* attribute_offset = index_expr;
+            if (buffer_layout.array_stride != 4) {
+                attribute_offset = ctx.dst->Mul(index_expr, u32(buffer_layout.array_stride / 4u));
+            }
+
+            // let pulling_offset_n = <attribute_offset>
+            stmts.emplace_back(
+                ctx.dst->Decl(ctx.dst->Let(buffer_array_base, nullptr, attribute_offset)));
+
+            for (const VertexAttributeDescriptor& attribute_desc : buffer_layout.attributes) {
+                auto it = location_info.find(attribute_desc.shader_location);
+                if (it == location_info.end()) {
+                    continue;
+                }
+                auto& var = it->second;
+
+                // Data type of the target WGSL variable
+                auto var_dt = DataTypeOf(var.type);
+                // Data type of the vertex stream attribute
+                auto fmt_dt = DataTypeOf(attribute_desc.format);
+
+                // Base types must match between the vertex stream and the WGSL variable
+                if (var_dt.base_type != fmt_dt.base_type) {
+                    std::stringstream err;
+                    err << "VertexAttributeDescriptor for location "
+                        << std::to_string(attribute_desc.shader_location) << " has format "
+                        << attribute_desc.format << " but shader expects "
+                        << var.type->FriendlyName(ctx.src->Symbols());
+                    ctx.dst->Diagnostics().add_error(diag::System::Transform, err.str());
+                    return nullptr;
+                }
+
+                // Load the attribute value
+                auto* fetch = Fetch(buffer_array_base, attribute_desc.offset, buffer_idx,
+                                    attribute_desc.format);
+
+                // The attribute value may not be of the desired vector width. If it is
+                // not, we'll need to either reduce the width with a swizzle, or append
+                // 0's and / or a 1.
+                auto* value = fetch;
+                if (var_dt.width < fmt_dt.width) {
+                    // WGSL variable vector width is smaller than the loaded vector width
+                    switch (var_dt.width) {
+                        case 1:
+                            value = ctx.dst->MemberAccessor(fetch, "x");
+                            break;
+                        case 2:
+                            value = ctx.dst->MemberAccessor(fetch, "xy");
+                            break;
+                        case 3:
+                            value = ctx.dst->MemberAccessor(fetch, "xyz");
+                            break;
+                        default:
+                            TINT_UNREACHABLE(Transform, ctx.dst->Diagnostics()) << var_dt.width;
+                            return nullptr;
+                    }
+                } else if (var_dt.width > fmt_dt.width) {
+                    // WGSL variable vector width is wider than the loaded vector width
+                    const ast::Type* ty = nullptr;
+                    ast::ExpressionList values{fetch};
+                    switch (var_dt.base_type) {
+                        case BaseType::kI32:
+                            ty = ctx.dst->ty.i32();
+                            for (uint32_t i = fmt_dt.width; i < var_dt.width; i++) {
+                                values.emplace_back(ctx.dst->Expr(i32((i == 3) ? 1 : 0)));
+                            }
+                            break;
+                        case BaseType::kU32:
+                            ty = ctx.dst->ty.u32();
+                            for (uint32_t i = fmt_dt.width; i < var_dt.width; i++) {
+                                values.emplace_back(ctx.dst->Expr(u32((i == 3) ? 1u : 0u)));
+                            }
+                            break;
+                        case BaseType::kF32:
+                            ty = ctx.dst->ty.f32();
+                            for (uint32_t i = fmt_dt.width; i < var_dt.width; i++) {
+                                values.emplace_back(ctx.dst->Expr((i == 3) ? 1.f : 0.f));
+                            }
+                            break;
+                        default:
+                            TINT_UNREACHABLE(Transform, ctx.dst->Diagnostics()) << var_dt.base_type;
+                            return nullptr;
+                    }
+                    value = ctx.dst->Construct(ctx.dst->ty.vec(ty, var_dt.width), values);
+                }
+
+                // Assign the value to the WGSL variable
+                stmts.emplace_back(ctx.dst->Assign(var.expr(), value));
+            }
         }
 
-        // Load the attribute value
-        auto* fetch = Fetch(buffer_array_base, attribute_desc.offset,
-                            buffer_idx, attribute_desc.format);
-
-        // The attribute value may not be of the desired vector width. If it is
-        // not, we'll need to either reduce the width with a swizzle, or append
-        // 0's and / or a 1.
-        auto* value = fetch;
-        if (var_dt.width < fmt_dt.width) {
-          // WGSL variable vector width is smaller than the loaded vector width
-          switch (var_dt.width) {
-            case 1:
-              value = ctx.dst->MemberAccessor(fetch, "x");
-              break;
-            case 2:
-              value = ctx.dst->MemberAccessor(fetch, "xy");
-              break;
-            case 3:
-              value = ctx.dst->MemberAccessor(fetch, "xyz");
-              break;
-            default:
-              TINT_UNREACHABLE(Transform, ctx.dst->Diagnostics())
-                  << var_dt.width;
-              return nullptr;
-          }
-        } else if (var_dt.width > fmt_dt.width) {
-          // WGSL variable vector width is wider than the loaded vector width
-          const ast::Type* ty = nullptr;
-          ast::ExpressionList values{fetch};
-          switch (var_dt.base_type) {
-            case BaseType::kI32:
-              ty = ctx.dst->ty.i32();
-              for (uint32_t i = fmt_dt.width; i < var_dt.width; i++) {
-                values.emplace_back(ctx.dst->Expr((i == 3) ? 1 : 0));
-              }
-              break;
-            case BaseType::kU32:
-              ty = ctx.dst->ty.u32();
-              for (uint32_t i = fmt_dt.width; i < var_dt.width; i++) {
-                values.emplace_back(ctx.dst->Expr((i == 3) ? 1u : 0u));
-              }
-              break;
-            case BaseType::kF32:
-              ty = ctx.dst->ty.f32();
-              for (uint32_t i = fmt_dt.width; i < var_dt.width; i++) {
-                values.emplace_back(ctx.dst->Expr((i == 3) ? 1.f : 0.f));
-              }
-              break;
-            default:
-              TINT_UNREACHABLE(Transform, ctx.dst->Diagnostics())
-                  << var_dt.base_type;
-              return nullptr;
-          }
-          value = ctx.dst->Construct(ctx.dst->ty.vec(ty, var_dt.width), values);
+        if (stmts.empty()) {
+            return nullptr;
         }
 
-        // Assign the value to the WGSL variable
-        stmts.emplace_back(ctx.dst->Assign(var.expr(), value));
-      }
+        return ctx.dst->create<ast::BlockStatement>(stmts);
     }
 
-    if (stmts.empty()) {
-      return nullptr;
-    }
-
-    return ctx.dst->create<ast::BlockStatement>(stmts);
-  }
-
-  /// Generates an expression reading from a buffer a specific format.
-  /// @param array_base the symbol of the variable holding the base array offset
-  /// of the vertex array (each index is 4-bytes).
-  /// @param offset the byte offset of the data from `buffer_base`
-  /// @param buffer the index of the vertex buffer
-  /// @param format the format to read
-  const ast::Expression* Fetch(Symbol array_base,
-                               uint32_t offset,
-                               uint32_t buffer,
-                               VertexFormat format) {
-    using u32 = ProgramBuilder::u32;
-    using i32 = ProgramBuilder::i32;
-    using f32 = ProgramBuilder::f32;
-
-    // Returns a u32 loaded from buffer_base + offset.
-    auto load_u32 = [&] {
-      return LoadPrimitive(array_base, offset, buffer, VertexFormat::kUint32);
-    };
-
-    // Returns a i32 loaded from buffer_base + offset.
-    auto load_i32 = [&] { return ctx.dst->Bitcast<i32>(load_u32()); };
-
-    // Returns a u32 loaded from buffer_base + offset + 4.
-    auto load_next_u32 = [&] {
-      return LoadPrimitive(array_base, offset + 4, buffer,
-                           VertexFormat::kUint32);
-    };
-
-    // Returns a i32 loaded from buffer_base + offset + 4.
-    auto load_next_i32 = [&] { return ctx.dst->Bitcast<i32>(load_next_u32()); };
-
-    // Returns a u16 loaded from offset, packed in the high 16 bits of a u32.
-    // The low 16 bits are 0.
-    // `min_alignment` must be a power of two.
-    // `offset` must be `min_alignment` bytes aligned.
-    auto load_u16_h = [&] {
-      auto low_u32_offset = offset & ~3u;
-      auto* low_u32 = LoadPrimitive(array_base, low_u32_offset, buffer,
-                                    VertexFormat::kUint32);
-      switch (offset & 3) {
-        case 0:
-          return ctx.dst->Shl(low_u32, 16u);
-        case 1:
-          return ctx.dst->And(ctx.dst->Shl(low_u32, 8u), 0xffff0000u);
-        case 2:
-          return ctx.dst->And(low_u32, 0xffff0000u);
-        default: {  // 3:
-          auto* high_u32 = LoadPrimitive(array_base, low_u32_offset + 4, buffer,
-                                         VertexFormat::kUint32);
-          auto* shr = ctx.dst->Shr(low_u32, 8u);
-          auto* shl = ctx.dst->Shl(high_u32, 24u);
-          return ctx.dst->And(ctx.dst->Or(shl, shr), 0xffff0000u);
-        }
-      }
-    };
-
-    // Returns a u16 loaded from offset, packed in the low 16 bits of a u32.
-    // The high 16 bits are 0.
-    auto load_u16_l = [&] {
-      auto low_u32_offset = offset & ~3u;
-      auto* low_u32 = LoadPrimitive(array_base, low_u32_offset, buffer,
-                                    VertexFormat::kUint32);
-      switch (offset & 3) {
-        case 0:
-          return ctx.dst->And(low_u32, 0xffffu);
-        case 1:
-          return ctx.dst->And(ctx.dst->Shr(low_u32, 8u), 0xffffu);
-        case 2:
-          return ctx.dst->Shr(low_u32, 16u);
-        default: {  // 3:
-          auto* high_u32 = LoadPrimitive(array_base, low_u32_offset + 4, buffer,
-                                         VertexFormat::kUint32);
-          auto* shr = ctx.dst->Shr(low_u32, 24u);
-          auto* shl = ctx.dst->Shl(high_u32, 8u);
-          return ctx.dst->And(ctx.dst->Or(shl, shr), 0xffffu);
-        }
-      }
-    };
-
-    // Returns a i16 loaded from offset, packed in the high 16 bits of a u32.
-    // The low 16 bits are 0.
-    auto load_i16_h = [&] { return ctx.dst->Bitcast<i32>(load_u16_h()); };
-
-    // Assumptions are made that alignment must be at least as large as the size
-    // of a single component.
-    switch (format) {
-      // Basic primitives
-      case VertexFormat::kUint32:
-      case VertexFormat::kSint32:
-      case VertexFormat::kFloat32:
-        return LoadPrimitive(array_base, offset, buffer, format);
-
-        // Vectors of basic primitives
-      case VertexFormat::kUint32x2:
-        return LoadVec(array_base, offset, buffer, 4, ctx.dst->ty.u32(),
-                       VertexFormat::kUint32, 2);
-      case VertexFormat::kUint32x3:
-        return LoadVec(array_base, offset, buffer, 4, ctx.dst->ty.u32(),
-                       VertexFormat::kUint32, 3);
-      case VertexFormat::kUint32x4:
-        return LoadVec(array_base, offset, buffer, 4, ctx.dst->ty.u32(),
-                       VertexFormat::kUint32, 4);
-      case VertexFormat::kSint32x2:
-        return LoadVec(array_base, offset, buffer, 4, ctx.dst->ty.i32(),
-                       VertexFormat::kSint32, 2);
-      case VertexFormat::kSint32x3:
-        return LoadVec(array_base, offset, buffer, 4, ctx.dst->ty.i32(),
-                       VertexFormat::kSint32, 3);
-      case VertexFormat::kSint32x4:
-        return LoadVec(array_base, offset, buffer, 4, ctx.dst->ty.i32(),
-                       VertexFormat::kSint32, 4);
-      case VertexFormat::kFloat32x2:
-        return LoadVec(array_base, offset, buffer, 4, ctx.dst->ty.f32(),
-                       VertexFormat::kFloat32, 2);
-      case VertexFormat::kFloat32x3:
-        return LoadVec(array_base, offset, buffer, 4, ctx.dst->ty.f32(),
-                       VertexFormat::kFloat32, 3);
-      case VertexFormat::kFloat32x4:
-        return LoadVec(array_base, offset, buffer, 4, ctx.dst->ty.f32(),
-                       VertexFormat::kFloat32, 4);
-
-      case VertexFormat::kUint8x2: {
-        // yyxx0000, yyxx0000
-        auto* u16s = ctx.dst->vec2<u32>(load_u16_h());
-        // xx000000, yyxx0000
-        auto* shl = ctx.dst->Shl(u16s, ctx.dst->vec2<u32>(8u, 0u));
-        // 000000xx, 000000yy
-        return ctx.dst->Shr(shl, ctx.dst->vec2<u32>(24u));
-      }
-      case VertexFormat::kUint8x4: {
-        // wwzzyyxx, wwzzyyxx, wwzzyyxx, wwzzyyxx
-        auto* u32s = ctx.dst->vec4<u32>(load_u32());
-        // xx000000, yyxx0000, zzyyxx00, wwzzyyxx
-        auto* shl = ctx.dst->Shl(u32s, ctx.dst->vec4<u32>(24u, 16u, 8u, 0u));
-        // 000000xx, 000000yy, 000000zz, 000000ww
-        return ctx.dst->Shr(shl, ctx.dst->vec4<u32>(24u));
-      }
-      case VertexFormat::kUint16x2: {
-        // yyyyxxxx, yyyyxxxx
-        auto* u32s = ctx.dst->vec2<u32>(load_u32());
-        // xxxx0000, yyyyxxxx
-        auto* shl = ctx.dst->Shl(u32s, ctx.dst->vec2<u32>(16u, 0u));
-        // 0000xxxx, 0000yyyy
-        return ctx.dst->Shr(shl, ctx.dst->vec2<u32>(16u));
-      }
-      case VertexFormat::kUint16x4: {
-        // yyyyxxxx, wwwwzzzz
-        auto* u32s = ctx.dst->vec2<u32>(load_u32(), load_next_u32());
-        // yyyyxxxx, yyyyxxxx, wwwwzzzz, wwwwzzzz
-        auto* xxyy = ctx.dst->MemberAccessor(u32s, "xxyy");
-        // xxxx0000, yyyyxxxx, zzzz0000, wwwwzzzz
-        auto* shl = ctx.dst->Shl(xxyy, ctx.dst->vec4<u32>(16u, 0u, 16u, 0u));
-        // 0000xxxx, 0000yyyy, 0000zzzz, 0000wwww
-        return ctx.dst->Shr(shl, ctx.dst->vec4<u32>(16u));
-      }
-      case VertexFormat::kSint8x2: {
-        // yyxx0000, yyxx0000
-        auto* i16s = ctx.dst->vec2<i32>(load_i16_h());
-        // xx000000, yyxx0000
-        auto* shl = ctx.dst->Shl(i16s, ctx.dst->vec2<u32>(8u, 0u));
-        // ssssssxx, ssssssyy
-        return ctx.dst->Shr(shl, ctx.dst->vec2<u32>(24u));
-      }
-      case VertexFormat::kSint8x4: {
-        // wwzzyyxx, wwzzyyxx, wwzzyyxx, wwzzyyxx
-        auto* i32s = ctx.dst->vec4<i32>(load_i32());
-        // xx000000, yyxx0000, zzyyxx00, wwzzyyxx
-        auto* shl = ctx.dst->Shl(i32s, ctx.dst->vec4<u32>(24u, 16u, 8u, 0u));
-        // ssssssxx, ssssssyy, sssssszz, ssssssww
-        return ctx.dst->Shr(shl, ctx.dst->vec4<u32>(24u));
-      }
-      case VertexFormat::kSint16x2: {
-        // yyyyxxxx, yyyyxxxx
-        auto* i32s = ctx.dst->vec2<i32>(load_i32());
-        // xxxx0000, yyyyxxxx
-        auto* shl = ctx.dst->Shl(i32s, ctx.dst->vec2<u32>(16u, 0u));
-        // ssssxxxx, ssssyyyy
-        return ctx.dst->Shr(shl, ctx.dst->vec2<u32>(16u));
-      }
-      case VertexFormat::kSint16x4: {
-        // yyyyxxxx, wwwwzzzz
-        auto* i32s = ctx.dst->vec2<i32>(load_i32(), load_next_i32());
-        // yyyyxxxx, yyyyxxxx, wwwwzzzz, wwwwzzzz
-        auto* xxyy = ctx.dst->MemberAccessor(i32s, "xxyy");
-        // xxxx0000, yyyyxxxx, zzzz0000, wwwwzzzz
-        auto* shl = ctx.dst->Shl(xxyy, ctx.dst->vec4<u32>(16u, 0u, 16u, 0u));
-        // ssssxxxx, ssssyyyy, sssszzzz, sssswwww
-        return ctx.dst->Shr(shl, ctx.dst->vec4<u32>(16u));
-      }
-      case VertexFormat::kUnorm8x2:
-        return ctx.dst->MemberAccessor(
-            ctx.dst->Call("unpack4x8unorm", load_u16_l()), "xy");
-      case VertexFormat::kSnorm8x2:
-        return ctx.dst->MemberAccessor(
-            ctx.dst->Call("unpack4x8snorm", load_u16_l()), "xy");
-      case VertexFormat::kUnorm8x4:
-        return ctx.dst->Call("unpack4x8unorm", load_u32());
-      case VertexFormat::kSnorm8x4:
-        return ctx.dst->Call("unpack4x8snorm", load_u32());
-      case VertexFormat::kUnorm16x2:
-        return ctx.dst->Call("unpack2x16unorm", load_u32());
-      case VertexFormat::kSnorm16x2:
-        return ctx.dst->Call("unpack2x16snorm", load_u32());
-      case VertexFormat::kFloat16x2:
-        return ctx.dst->Call("unpack2x16float", load_u32());
-      case VertexFormat::kUnorm16x4:
-        return ctx.dst->vec4<f32>(
-            ctx.dst->Call("unpack2x16unorm", load_u32()),
-            ctx.dst->Call("unpack2x16unorm", load_next_u32()));
-      case VertexFormat::kSnorm16x4:
-        return ctx.dst->vec4<f32>(
-            ctx.dst->Call("unpack2x16snorm", load_u32()),
-            ctx.dst->Call("unpack2x16snorm", load_next_u32()));
-      case VertexFormat::kFloat16x4:
-        return ctx.dst->vec4<f32>(
-            ctx.dst->Call("unpack2x16float", load_u32()),
-            ctx.dst->Call("unpack2x16float", load_next_u32()));
-    }
-
-    TINT_UNREACHABLE(Transform, ctx.dst->Diagnostics())
-        << "format " << static_cast<int>(format);
-    return nullptr;
-  }
-
-  /// Generates an expression reading an aligned basic type (u32, i32, f32) from
-  /// a vertex buffer.
-  /// @param array_base the symbol of the variable holding the base array offset
-  /// of the vertex array (each index is 4-bytes).
-  /// @param offset the byte offset of the data from `buffer_base`
-  /// @param buffer the index of the vertex buffer
-  /// @param format VertexFormat::kUint32, VertexFormat::kSint32 or
-  /// VertexFormat::kFloat32
-  const ast::Expression* LoadPrimitive(Symbol array_base,
-                                       uint32_t offset,
-                                       uint32_t buffer,
-                                       VertexFormat format) {
-    const ast::Expression* u32 = nullptr;
-    if ((offset & 3) == 0) {
-      // Aligned load.
-
-      const ast ::Expression* index = nullptr;
-      if (offset > 0) {
-        index = ctx.dst->Add(array_base, offset / 4);
-      } else {
-        index = ctx.dst->Expr(array_base);
-      }
-      u32 = ctx.dst->IndexAccessor(
-          ctx.dst->MemberAccessor(GetVertexBufferName(buffer),
-                                  GetStructBufferName()),
-          index);
-
-    } else {
-      // Unaligned load
-      uint32_t offset_aligned = offset & ~3u;
-      auto* low = LoadPrimitive(array_base, offset_aligned, buffer,
-                                VertexFormat::kUint32);
-      auto* high = LoadPrimitive(array_base, offset_aligned + 4u, buffer,
-                                 VertexFormat::kUint32);
-
-      uint32_t shift = 8u * (offset & 3u);
-
-      auto* low_shr = ctx.dst->Shr(low, shift);
-      auto* high_shl = ctx.dst->Shl(high, 32u - shift);
-      u32 = ctx.dst->Or(low_shr, high_shl);
-    }
-
-    switch (format) {
-      case VertexFormat::kUint32:
-        return u32;
-      case VertexFormat::kSint32:
-        return ctx.dst->Bitcast(ctx.dst->ty.i32(), u32);
-      case VertexFormat::kFloat32:
-        return ctx.dst->Bitcast(ctx.dst->ty.f32(), u32);
-      default:
-        break;
-    }
-    TINT_UNREACHABLE(Transform, ctx.dst->Diagnostics())
-        << "invalid format for LoadPrimitive" << static_cast<int>(format);
-    return nullptr;
-  }
-
-  /// Generates an expression reading a vec2/3/4 from a vertex buffer.
-  /// @param array_base the symbol of the variable holding the base array offset
-  /// of the vertex array (each index is 4-bytes).
-  /// @param offset the byte offset of the data from `buffer_base`
-  /// @param buffer the index of the vertex buffer
-  /// @param element_stride stride between elements, in bytes
-  /// @param base_type underlying AST type
-  /// @param base_format underlying vertex format
-  /// @param count how many elements the vector has
-  const ast::Expression* LoadVec(Symbol array_base,
+    /// Generates an expression reading from a buffer a specific format.
+    /// @param array_base the symbol of the variable holding the base array offset
+    /// of the vertex array (each index is 4-bytes).
+    /// @param offset the byte offset of the data from `buffer_base`
+    /// @param buffer the index of the vertex buffer
+    /// @param format the format to read
+    const ast::Expression* Fetch(Symbol array_base,
                                  uint32_t offset,
                                  uint32_t buffer,
-                                 uint32_t element_stride,
-                                 const ast::Type* base_type,
-                                 VertexFormat base_format,
-                                 uint32_t count) {
-    ast::ExpressionList expr_list;
-    for (uint32_t i = 0; i < count; ++i) {
-      // Offset read position by element_stride for each component
-      uint32_t primitive_offset = offset + element_stride * i;
-      expr_list.push_back(
-          LoadPrimitive(array_base, primitive_offset, buffer, base_format));
-    }
-
-    return ctx.dst->Construct(ctx.dst->create<ast::Vector>(base_type, count),
-                              std::move(expr_list));
-  }
-
-  /// Process a non-struct entry point parameter.
-  /// Generate function-scope variables for location parameters, and record
-  /// vertex_index and instance_index builtins if present.
-  /// @param func the entry point function
-  /// @param param the parameter to process
-  void ProcessNonStructParameter(const ast::Function* func,
-                                 const ast::Variable* param) {
-    if (auto* location =
-            ast::GetAttribute<ast::LocationAttribute>(param->attributes)) {
-      // Create a function-scope variable to replace the parameter.
-      auto func_var_sym = ctx.Clone(param->symbol);
-      auto* func_var_type = ctx.Clone(param->type);
-      auto* func_var = ctx.dst->Var(func_var_sym, func_var_type);
-      ctx.InsertFront(func->body->statements, ctx.dst->Decl(func_var));
-      // Capture mapping from location to the new variable.
-      LocationInfo info;
-      info.expr = [this, func_var]() { return ctx.dst->Expr(func_var); };
-      info.type = ctx.src->Sem().Get(param)->Type();
-      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) {
-        vertex_index_expr = [this, param]() {
-          return ctx.dst->Expr(ctx.Clone(param->symbol));
+                                 VertexFormat format) {
+        // Returns a u32 loaded from buffer_base + offset.
+        auto load_u32 = [&] {
+            return LoadPrimitive(array_base, offset, buffer, VertexFormat::kUint32);
         };
-      } else if (builtin->builtin == ast::Builtin::kInstanceIndex) {
-        instance_index_expr = [this, param]() {
-          return ctx.dst->Expr(ctx.Clone(param->symbol));
+
+        // Returns a i32 loaded from buffer_base + offset.
+        auto load_i32 = [&] { return ctx.dst->Bitcast<i32>(load_u32()); };
+
+        // Returns a u32 loaded from buffer_base + offset + 4.
+        auto load_next_u32 = [&] {
+            return LoadPrimitive(array_base, offset + 4, buffer, VertexFormat::kUint32);
         };
-      }
-      new_function_parameters.push_back(ctx.Clone(param));
-    } else {
-      TINT_ICE(Transform, ctx.dst->Diagnostics())
-          << "Invalid entry point parameter";
-    }
-  }
 
-  /// Process a struct entry point parameter.
-  /// If the struct has members with location attributes, push the parameter to
-  /// a function-scope variable and create a new struct parameter without those
-  /// attributes. Record expressions for members that are vertex_index and
-  /// instance_index builtins.
-  /// @param func the entry point function
-  /// @param param the parameter to process
-  /// @param struct_ty the structure type
-  void ProcessStructParameter(const ast::Function* func,
-                              const ast::Variable* param,
-                              const ast::Struct* struct_ty) {
-    auto param_sym = ctx.Clone(param->symbol);
+        // Returns a i32 loaded from buffer_base + offset + 4.
+        auto load_next_i32 = [&] { return ctx.dst->Bitcast<i32>(load_next_u32()); };
 
-    // Process the struct members.
-    bool has_locations = false;
-    ast::StructMemberList members_to_clone;
-    for (auto* member : struct_ty->members) {
-      auto member_sym = ctx.Clone(member->symbol);
-      std::function<const ast::Expression*()> member_expr = [this, param_sym,
-                                                             member_sym]() {
-        return ctx.dst->MemberAccessor(param_sym, member_sym);
-      };
+        // Returns a u16 loaded from offset, packed in the high 16 bits of a u32.
+        // The low 16 bits are 0.
+        // `min_alignment` must be a power of two.
+        // `offset` must be `min_alignment` bytes aligned.
+        auto load_u16_h = [&] {
+            auto low_u32_offset = offset & ~3u;
+            auto* low_u32 =
+                LoadPrimitive(array_base, low_u32_offset, buffer, VertexFormat::kUint32);
+            switch (offset & 3) {
+                case 0:
+                    return ctx.dst->Shl(low_u32, 16_u);
+                case 1:
+                    return ctx.dst->And(ctx.dst->Shl(low_u32, 8_u), 0xffff0000_u);
+                case 2:
+                    return ctx.dst->And(low_u32, 0xffff0000_u);
+                default: {  // 3:
+                    auto* high_u32 = LoadPrimitive(array_base, low_u32_offset + 4, buffer,
+                                                   VertexFormat::kUint32);
+                    auto* shr = ctx.dst->Shr(low_u32, 8_u);
+                    auto* shl = ctx.dst->Shl(high_u32, 24_u);
+                    return ctx.dst->And(ctx.dst->Or(shl, shr), 0xffff0000_u);
+                }
+            }
+        };
 
-      if (auto* location =
-              ast::GetAttribute<ast::LocationAttribute>(member->attributes)) {
-        // Capture mapping from location to struct member.
-        LocationInfo info;
-        info.expr = member_expr;
-        info.type = ctx.src->Sem().Get(member)->Type();
-        location_info[location->value] = info;
-        has_locations = true;
-      } 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) {
-          vertex_index_expr = member_expr;
-        } else if (builtin->builtin == ast::Builtin::kInstanceIndex) {
-          instance_index_expr = member_expr;
+        // Returns a u16 loaded from offset, packed in the low 16 bits of a u32.
+        // The high 16 bits are 0.
+        auto load_u16_l = [&] {
+            auto low_u32_offset = offset & ~3u;
+            auto* low_u32 =
+                LoadPrimitive(array_base, low_u32_offset, buffer, VertexFormat::kUint32);
+            switch (offset & 3) {
+                case 0:
+                    return ctx.dst->And(low_u32, 0xffff_u);
+                case 1:
+                    return ctx.dst->And(ctx.dst->Shr(low_u32, 8_u), 0xffff_u);
+                case 2:
+                    return ctx.dst->Shr(low_u32, 16_u);
+                default: {  // 3:
+                    auto* high_u32 = LoadPrimitive(array_base, low_u32_offset + 4, buffer,
+                                                   VertexFormat::kUint32);
+                    auto* shr = ctx.dst->Shr(low_u32, 24_u);
+                    auto* shl = ctx.dst->Shl(high_u32, 8_u);
+                    return ctx.dst->And(ctx.dst->Or(shl, shr), 0xffff_u);
+                }
+            }
+        };
+
+        // Returns a i16 loaded from offset, packed in the high 16 bits of a u32.
+        // The low 16 bits are 0.
+        auto load_i16_h = [&] { return ctx.dst->Bitcast<i32>(load_u16_h()); };
+
+        // Assumptions are made that alignment must be at least as large as the size
+        // of a single component.
+        switch (format) {
+            // Basic primitives
+            case VertexFormat::kUint32:
+            case VertexFormat::kSint32:
+            case VertexFormat::kFloat32:
+                return LoadPrimitive(array_base, offset, buffer, format);
+
+                // Vectors of basic primitives
+            case VertexFormat::kUint32x2:
+                return LoadVec(array_base, offset, buffer, 4, ctx.dst->ty.u32(),
+                               VertexFormat::kUint32, 2);
+            case VertexFormat::kUint32x3:
+                return LoadVec(array_base, offset, buffer, 4, ctx.dst->ty.u32(),
+                               VertexFormat::kUint32, 3);
+            case VertexFormat::kUint32x4:
+                return LoadVec(array_base, offset, buffer, 4, ctx.dst->ty.u32(),
+                               VertexFormat::kUint32, 4);
+            case VertexFormat::kSint32x2:
+                return LoadVec(array_base, offset, buffer, 4, ctx.dst->ty.i32(),
+                               VertexFormat::kSint32, 2);
+            case VertexFormat::kSint32x3:
+                return LoadVec(array_base, offset, buffer, 4, ctx.dst->ty.i32(),
+                               VertexFormat::kSint32, 3);
+            case VertexFormat::kSint32x4:
+                return LoadVec(array_base, offset, buffer, 4, ctx.dst->ty.i32(),
+                               VertexFormat::kSint32, 4);
+            case VertexFormat::kFloat32x2:
+                return LoadVec(array_base, offset, buffer, 4, ctx.dst->ty.f32(),
+                               VertexFormat::kFloat32, 2);
+            case VertexFormat::kFloat32x3:
+                return LoadVec(array_base, offset, buffer, 4, ctx.dst->ty.f32(),
+                               VertexFormat::kFloat32, 3);
+            case VertexFormat::kFloat32x4:
+                return LoadVec(array_base, offset, buffer, 4, ctx.dst->ty.f32(),
+                               VertexFormat::kFloat32, 4);
+
+            case VertexFormat::kUint8x2: {
+                // yyxx0000, yyxx0000
+                auto* u16s = ctx.dst->vec2<u32>(load_u16_h());
+                // xx000000, yyxx0000
+                auto* shl = ctx.dst->Shl(u16s, ctx.dst->vec2<u32>(8_u, 0_u));
+                // 000000xx, 000000yy
+                return ctx.dst->Shr(shl, ctx.dst->vec2<u32>(24_u));
+            }
+            case VertexFormat::kUint8x4: {
+                // wwzzyyxx, wwzzyyxx, wwzzyyxx, wwzzyyxx
+                auto* u32s = ctx.dst->vec4<u32>(load_u32());
+                // xx000000, yyxx0000, zzyyxx00, wwzzyyxx
+                auto* shl = ctx.dst->Shl(u32s, ctx.dst->vec4<u32>(24_u, 16_u, 8_u, 0_u));
+                // 000000xx, 000000yy, 000000zz, 000000ww
+                return ctx.dst->Shr(shl, ctx.dst->vec4<u32>(24_u));
+            }
+            case VertexFormat::kUint16x2: {
+                // yyyyxxxx, yyyyxxxx
+                auto* u32s = ctx.dst->vec2<u32>(load_u32());
+                // xxxx0000, yyyyxxxx
+                auto* shl = ctx.dst->Shl(u32s, ctx.dst->vec2<u32>(16_u, 0_u));
+                // 0000xxxx, 0000yyyy
+                return ctx.dst->Shr(shl, ctx.dst->vec2<u32>(16_u));
+            }
+            case VertexFormat::kUint16x4: {
+                // yyyyxxxx, wwwwzzzz
+                auto* u32s = ctx.dst->vec2<u32>(load_u32(), load_next_u32());
+                // yyyyxxxx, yyyyxxxx, wwwwzzzz, wwwwzzzz
+                auto* xxyy = ctx.dst->MemberAccessor(u32s, "xxyy");
+                // xxxx0000, yyyyxxxx, zzzz0000, wwwwzzzz
+                auto* shl = ctx.dst->Shl(xxyy, ctx.dst->vec4<u32>(16_u, 0_u, 16_u, 0_u));
+                // 0000xxxx, 0000yyyy, 0000zzzz, 0000wwww
+                return ctx.dst->Shr(shl, ctx.dst->vec4<u32>(16_u));
+            }
+            case VertexFormat::kSint8x2: {
+                // yyxx0000, yyxx0000
+                auto* i16s = ctx.dst->vec2<i32>(load_i16_h());
+                // xx000000, yyxx0000
+                auto* shl = ctx.dst->Shl(i16s, ctx.dst->vec2<u32>(8_u, 0_u));
+                // ssssssxx, ssssssyy
+                return ctx.dst->Shr(shl, ctx.dst->vec2<u32>(24_u));
+            }
+            case VertexFormat::kSint8x4: {
+                // wwzzyyxx, wwzzyyxx, wwzzyyxx, wwzzyyxx
+                auto* i32s = ctx.dst->vec4<i32>(load_i32());
+                // xx000000, yyxx0000, zzyyxx00, wwzzyyxx
+                auto* shl = ctx.dst->Shl(i32s, ctx.dst->vec4<u32>(24_u, 16_u, 8_u, 0_u));
+                // ssssssxx, ssssssyy, sssssszz, ssssssww
+                return ctx.dst->Shr(shl, ctx.dst->vec4<u32>(24_u));
+            }
+            case VertexFormat::kSint16x2: {
+                // yyyyxxxx, yyyyxxxx
+                auto* i32s = ctx.dst->vec2<i32>(load_i32());
+                // xxxx0000, yyyyxxxx
+                auto* shl = ctx.dst->Shl(i32s, ctx.dst->vec2<u32>(16_u, 0_u));
+                // ssssxxxx, ssssyyyy
+                return ctx.dst->Shr(shl, ctx.dst->vec2<u32>(16_u));
+            }
+            case VertexFormat::kSint16x4: {
+                // yyyyxxxx, wwwwzzzz
+                auto* i32s = ctx.dst->vec2<i32>(load_i32(), load_next_i32());
+                // yyyyxxxx, yyyyxxxx, wwwwzzzz, wwwwzzzz
+                auto* xxyy = ctx.dst->MemberAccessor(i32s, "xxyy");
+                // xxxx0000, yyyyxxxx, zzzz0000, wwwwzzzz
+                auto* shl = ctx.dst->Shl(xxyy, ctx.dst->vec4<u32>(16_u, 0_u, 16_u, 0_u));
+                // ssssxxxx, ssssyyyy, sssszzzz, sssswwww
+                return ctx.dst->Shr(shl, ctx.dst->vec4<u32>(16_u));
+            }
+            case VertexFormat::kUnorm8x2:
+                return ctx.dst->MemberAccessor(ctx.dst->Call("unpack4x8unorm", load_u16_l()), "xy");
+            case VertexFormat::kSnorm8x2:
+                return ctx.dst->MemberAccessor(ctx.dst->Call("unpack4x8snorm", load_u16_l()), "xy");
+            case VertexFormat::kUnorm8x4:
+                return ctx.dst->Call("unpack4x8unorm", load_u32());
+            case VertexFormat::kSnorm8x4:
+                return ctx.dst->Call("unpack4x8snorm", load_u32());
+            case VertexFormat::kUnorm16x2:
+                return ctx.dst->Call("unpack2x16unorm", load_u32());
+            case VertexFormat::kSnorm16x2:
+                return ctx.dst->Call("unpack2x16snorm", load_u32());
+            case VertexFormat::kFloat16x2:
+                return ctx.dst->Call("unpack2x16float", load_u32());
+            case VertexFormat::kUnorm16x4:
+                return ctx.dst->vec4<f32>(ctx.dst->Call("unpack2x16unorm", load_u32()),
+                                          ctx.dst->Call("unpack2x16unorm", load_next_u32()));
+            case VertexFormat::kSnorm16x4:
+                return ctx.dst->vec4<f32>(ctx.dst->Call("unpack2x16snorm", load_u32()),
+                                          ctx.dst->Call("unpack2x16snorm", load_next_u32()));
+            case VertexFormat::kFloat16x4:
+                return ctx.dst->vec4<f32>(ctx.dst->Call("unpack2x16float", load_u32()),
+                                          ctx.dst->Call("unpack2x16float", load_next_u32()));
         }
-        members_to_clone.push_back(member);
-      } else {
-        TINT_ICE(Transform, ctx.dst->Diagnostics())
-            << "Invalid entry point parameter";
-      }
+
+        TINT_UNREACHABLE(Transform, ctx.dst->Diagnostics())
+            << "format " << static_cast<int>(format);
+        return nullptr;
     }
 
-    if (!has_locations) {
-      // Nothing to do.
-      new_function_parameters.push_back(ctx.Clone(param));
-      return;
-    }
+    /// Generates an expression reading an aligned basic type (u32, i32, f32) from
+    /// a vertex buffer.
+    /// @param array_base the symbol of the variable holding the base array offset
+    /// of the vertex array (each index is 4-bytes).
+    /// @param offset the byte offset of the data from `buffer_base`
+    /// @param buffer the index of the vertex buffer
+    /// @param format VertexFormat::kUint32, VertexFormat::kSint32 or
+    /// VertexFormat::kFloat32
+    const ast::Expression* LoadPrimitive(Symbol array_base,
+                                         uint32_t offset,
+                                         uint32_t buffer,
+                                         VertexFormat format) {
+        const ast::Expression* u = nullptr;
+        if ((offset & 3) == 0) {
+            // Aligned load.
 
-    // Create a function-scope variable to replace the parameter.
-    auto* func_var = ctx.dst->Var(param_sym, ctx.Clone(param->type));
-    ctx.InsertFront(func->body->statements, ctx.dst->Decl(func_var));
+            const ast ::Expression* index = nullptr;
+            if (offset > 0) {
+                index = ctx.dst->Add(array_base, u32(offset / 4));
+            } else {
+                index = ctx.dst->Expr(array_base);
+            }
+            u = ctx.dst->IndexAccessor(
+                ctx.dst->MemberAccessor(GetVertexBufferName(buffer), GetStructBufferName()), index);
 
-    if (!members_to_clone.empty()) {
-      // Create a new struct without the location attributes.
-      ast::StructMemberList new_members;
-      for (auto* member : members_to_clone) {
-        auto member_sym = ctx.Clone(member->symbol);
-        auto* member_type = ctx.Clone(member->type);
-        auto member_attrs = ctx.Clone(member->attributes);
-        new_members.push_back(
-            ctx.dst->Member(member_sym, member_type, std::move(member_attrs)));
-      }
-      auto* new_struct = ctx.dst->Structure(ctx.dst->Sym(), new_members);
+        } else {
+            // Unaligned load
+            uint32_t offset_aligned = offset & ~3u;
+            auto* low = LoadPrimitive(array_base, offset_aligned, buffer, VertexFormat::kUint32);
+            auto* high =
+                LoadPrimitive(array_base, offset_aligned + 4u, buffer, VertexFormat::kUint32);
 
-      // Create a new function parameter with this struct.
-      auto* new_param =
-          ctx.dst->Param(ctx.dst->Sym(), ctx.dst->ty.Of(new_struct));
-      new_function_parameters.push_back(new_param);
+            uint32_t shift = 8u * (offset & 3u);
 
-      // Copy values from the new parameter to the function-scope variable.
-      for (auto* member : members_to_clone) {
-        auto member_name = ctx.Clone(member->symbol);
-        ctx.InsertFront(
-            func->body->statements,
-            ctx.dst->Assign(ctx.dst->MemberAccessor(func_var, member_name),
-                            ctx.dst->MemberAccessor(new_param, member_name)));
-      }
-    }
-  }
-
-  /// Process an entry point function.
-  /// @param func the entry point function
-  void Process(const ast::Function* func) {
-    if (func->body->Empty()) {
-      return;
-    }
-
-    // Process entry point parameters.
-    for (auto* param : func->params) {
-      auto* sem = ctx.src->Sem().Get(param);
-      if (auto* str = sem->Type()->As<sem::Struct>()) {
-        ProcessStructParameter(func, param, str->Declaration());
-      } else {
-        ProcessNonStructParameter(func, param);
-      }
-    }
-
-    // Insert new parameters for vertex_index and instance_index if needed.
-    if (!vertex_index_expr) {
-      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)}));
-          vertex_index_expr = [this, name]() { return ctx.dst->Expr(name); };
-          break;
+            auto* low_shr = ctx.dst->Shr(low, u32(shift));
+            auto* high_shl = ctx.dst->Shl(high, u32(32u - shift));
+            u = ctx.dst->Or(low_shr, high_shl);
         }
-      }
-    }
-    if (!instance_index_expr) {
-      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)}));
-          instance_index_expr = [this, name]() { return ctx.dst->Expr(name); };
-          break;
+
+        switch (format) {
+            case VertexFormat::kUint32:
+                return u;
+            case VertexFormat::kSint32:
+                return ctx.dst->Bitcast(ctx.dst->ty.i32(), u);
+            case VertexFormat::kFloat32:
+                return ctx.dst->Bitcast(ctx.dst->ty.f32(), u);
+            default:
+                break;
         }
-      }
+        TINT_UNREACHABLE(Transform, ctx.dst->Diagnostics())
+            << "invalid format for LoadPrimitive" << static_cast<int>(format);
+        return nullptr;
     }
 
-    // Generate vertex pulling preamble.
-    if (auto* block = CreateVertexPullingPreamble()) {
-      ctx.InsertFront(func->body->statements, block);
+    /// Generates an expression reading a vec2/3/4 from a vertex buffer.
+    /// @param array_base the symbol of the variable holding the base array offset
+    /// of the vertex array (each index is 4-bytes).
+    /// @param offset the byte offset of the data from `buffer_base`
+    /// @param buffer the index of the vertex buffer
+    /// @param element_stride stride between elements, in bytes
+    /// @param base_type underlying AST type
+    /// @param base_format underlying vertex format
+    /// @param count how many elements the vector has
+    const ast::Expression* LoadVec(Symbol array_base,
+                                   uint32_t offset,
+                                   uint32_t buffer,
+                                   uint32_t element_stride,
+                                   const ast::Type* base_type,
+                                   VertexFormat base_format,
+                                   uint32_t count) {
+        ast::ExpressionList expr_list;
+        for (uint32_t i = 0; i < count; ++i) {
+            // Offset read position by element_stride for each component
+            uint32_t primitive_offset = offset + element_stride * i;
+            expr_list.push_back(LoadPrimitive(array_base, primitive_offset, buffer, base_format));
+        }
+
+        return ctx.dst->Construct(ctx.dst->create<ast::Vector>(base_type, count),
+                                  std::move(expr_list));
     }
 
-    // Rewrite the function header with the new parameters.
-    auto func_sym = ctx.Clone(func->symbol);
-    auto* ret_type = ctx.Clone(func->return_type);
-    auto* body = ctx.Clone(func->body);
-    auto attrs = ctx.Clone(func->attributes);
-    auto ret_attrs = ctx.Clone(func->return_type_attributes);
-    auto* new_func = ctx.dst->create<ast::Function>(
-        func->source, func_sym, new_function_parameters, ret_type, body,
-        std::move(attrs), std::move(ret_attrs));
-    ctx.Replace(func, new_func);
-  }
+    /// Process a non-struct entry point parameter.
+    /// Generate function-scope variables for location parameters, and record
+    /// vertex_index and instance_index builtins if present.
+    /// @param func the entry point function
+    /// @param param the parameter to process
+    void ProcessNonStructParameter(const ast::Function* func, const ast::Variable* param) {
+        if (auto* location = ast::GetAttribute<ast::LocationAttribute>(param->attributes)) {
+            // Create a function-scope variable to replace the parameter.
+            auto func_var_sym = ctx.Clone(param->symbol);
+            auto* func_var_type = ctx.Clone(param->type);
+            auto* func_var = ctx.dst->Var(func_var_sym, func_var_type);
+            ctx.InsertFront(func->body->statements, ctx.dst->Decl(func_var));
+            // Capture mapping from location to the new variable.
+            LocationInfo info;
+            info.expr = [this, func_var]() { return ctx.dst->Expr(func_var); };
+            info.type = ctx.src->Sem().Get(param)->Type();
+            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) {
+                vertex_index_expr = [this, param]() {
+                    return ctx.dst->Expr(ctx.Clone(param->symbol));
+                };
+            } else if (builtin->builtin == ast::Builtin::kInstanceIndex) {
+                instance_index_expr = [this, param]() {
+                    return ctx.dst->Expr(ctx.Clone(param->symbol));
+                };
+            }
+            new_function_parameters.push_back(ctx.Clone(param));
+        } else {
+            TINT_ICE(Transform, ctx.dst->Diagnostics()) << "Invalid entry point parameter";
+        }
+    }
+
+    /// Process a struct entry point parameter.
+    /// If the struct has members with location attributes, push the parameter to
+    /// a function-scope variable and create a new struct parameter without those
+    /// attributes. Record expressions for members that are vertex_index and
+    /// instance_index builtins.
+    /// @param func the entry point function
+    /// @param param the parameter to process
+    /// @param struct_ty the structure type
+    void ProcessStructParameter(const ast::Function* func,
+                                const ast::Variable* param,
+                                const ast::Struct* struct_ty) {
+        auto param_sym = ctx.Clone(param->symbol);
+
+        // Process the struct members.
+        bool has_locations = false;
+        ast::StructMemberList members_to_clone;
+        for (auto* member : struct_ty->members) {
+            auto member_sym = ctx.Clone(member->symbol);
+            std::function<const ast::Expression*()> member_expr = [this, param_sym, member_sym]() {
+                return ctx.dst->MemberAccessor(param_sym, member_sym);
+            };
+
+            if (auto* location = ast::GetAttribute<ast::LocationAttribute>(member->attributes)) {
+                // Capture mapping from location to struct member.
+                LocationInfo info;
+                info.expr = member_expr;
+                info.type = ctx.src->Sem().Get(member)->Type();
+                location_info[location->value] = info;
+                has_locations = true;
+            } 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) {
+                    vertex_index_expr = member_expr;
+                } else if (builtin->builtin == ast::Builtin::kInstanceIndex) {
+                    instance_index_expr = member_expr;
+                }
+                members_to_clone.push_back(member);
+            } else {
+                TINT_ICE(Transform, ctx.dst->Diagnostics()) << "Invalid entry point parameter";
+            }
+        }
+
+        if (!has_locations) {
+            // Nothing to do.
+            new_function_parameters.push_back(ctx.Clone(param));
+            return;
+        }
+
+        // Create a function-scope variable to replace the parameter.
+        auto* func_var = ctx.dst->Var(param_sym, ctx.Clone(param->type));
+        ctx.InsertFront(func->body->statements, ctx.dst->Decl(func_var));
+
+        if (!members_to_clone.empty()) {
+            // Create a new struct without the location attributes.
+            ast::StructMemberList new_members;
+            for (auto* member : members_to_clone) {
+                auto member_sym = ctx.Clone(member->symbol);
+                auto* member_type = ctx.Clone(member->type);
+                auto member_attrs = ctx.Clone(member->attributes);
+                new_members.push_back(
+                    ctx.dst->Member(member_sym, member_type, std::move(member_attrs)));
+            }
+            auto* new_struct = ctx.dst->Structure(ctx.dst->Sym(), new_members);
+
+            // Create a new function parameter with this struct.
+            auto* new_param = ctx.dst->Param(ctx.dst->Sym(), ctx.dst->ty.Of(new_struct));
+            new_function_parameters.push_back(new_param);
+
+            // Copy values from the new parameter to the function-scope variable.
+            for (auto* member : members_to_clone) {
+                auto member_name = ctx.Clone(member->symbol);
+                ctx.InsertFront(func->body->statements,
+                                ctx.dst->Assign(ctx.dst->MemberAccessor(func_var, member_name),
+                                                ctx.dst->MemberAccessor(new_param, member_name)));
+            }
+        }
+    }
+
+    /// Process an entry point function.
+    /// @param func the entry point function
+    void Process(const ast::Function* func) {
+        if (func->body->Empty()) {
+            return;
+        }
+
+        // Process entry point parameters.
+        for (auto* param : func->params) {
+            auto* sem = ctx.src->Sem().Get(param);
+            if (auto* str = sem->Type()->As<sem::Struct>()) {
+                ProcessStructParameter(func, param, str->Declaration());
+            } else {
+                ProcessNonStructParameter(func, param);
+            }
+        }
+
+        // Insert new parameters for vertex_index and instance_index if needed.
+        if (!vertex_index_expr) {
+            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)}));
+                    vertex_index_expr = [this, name]() { return ctx.dst->Expr(name); };
+                    break;
+                }
+            }
+        }
+        if (!instance_index_expr) {
+            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)}));
+                    instance_index_expr = [this, name]() { return ctx.dst->Expr(name); };
+                    break;
+                }
+            }
+        }
+
+        // Generate vertex pulling preamble.
+        if (auto* block = CreateVertexPullingPreamble()) {
+            ctx.InsertFront(func->body->statements, block);
+        }
+
+        // Rewrite the function header with the new parameters.
+        auto func_sym = ctx.Clone(func->symbol);
+        auto* ret_type = ctx.Clone(func->return_type);
+        auto* body = ctx.Clone(func->body);
+        auto attrs = ctx.Clone(func->attributes);
+        auto ret_attrs = ctx.Clone(func->return_type_attributes);
+        auto* new_func =
+            ctx.dst->create<ast::Function>(func->source, func_sym, new_function_parameters,
+                                           ret_type, body, std::move(attrs), std::move(ret_attrs));
+        ctx.Replace(func, new_func);
+    }
 };
 
 }  // namespace
@@ -902,42 +867,38 @@
 VertexPulling::VertexPulling() = default;
 VertexPulling::~VertexPulling() = default;
 
-void VertexPulling::Run(CloneContext& ctx,
-                        const DataMap& inputs,
-                        DataMap&) const {
-  auto cfg = cfg_;
-  if (auto* cfg_data = inputs.Get<Config>()) {
-    cfg = *cfg_data;
-  }
+void VertexPulling::Run(CloneContext& ctx, const DataMap& inputs, DataMap&) const {
+    auto cfg = cfg_;
+    if (auto* cfg_data = inputs.Get<Config>()) {
+        cfg = *cfg_data;
+    }
 
-  // Find entry point
-  auto* func = ctx.src->AST().Functions().Find(
-      ctx.src->Symbols().Get(cfg.entry_point_name),
-      ast::PipelineStage::kVertex);
-  if (func == nullptr) {
-    ctx.dst->Diagnostics().add_error(diag::System::Transform,
-                                     "Vertex stage entry point not found");
-    return;
-  }
+    // Find entry point
+    auto* func = ctx.src->AST().Functions().Find(ctx.src->Symbols().Get(cfg.entry_point_name),
+                                                 ast::PipelineStage::kVertex);
+    if (func == nullptr) {
+        ctx.dst->Diagnostics().add_error(diag::System::Transform,
+                                         "Vertex stage entry point not found");
+        return;
+    }
 
-  // TODO(idanr): Need to check shader locations in descriptor cover all
-  // attributes
+    // TODO(idanr): Need to check shader locations in descriptor cover all
+    // attributes
 
-  // TODO(idanr): Make sure we covered all error cases, to guarantee the
-  // following stages will pass
+    // TODO(idanr): Make sure we covered all error cases, to guarantee the
+    // following stages will pass
 
-  State state{ctx, cfg};
-  state.AddVertexStorageBuffers();
-  state.Process(func);
+    State state{ctx, cfg};
+    state.AddVertexStorageBuffers();
+    state.Process(func);
 
-  ctx.Clone();
+    ctx.Clone();
 }
 
 VertexPulling::Config::Config() = default;
 VertexPulling::Config::Config(const Config&) = default;
 VertexPulling::Config::~Config() = default;
-VertexPulling::Config& VertexPulling::Config::operator=(const Config&) =
-    default;
+VertexPulling::Config& VertexPulling::Config::operator=(const Config&) = default;
 
 VertexBufferLayoutDescriptor::VertexBufferLayoutDescriptor() = default;
 
diff --git a/src/tint/transform/vertex_pulling.h b/src/tint/transform/vertex_pulling.h
index ec0769b..7875600 100644
--- a/src/tint/transform/vertex_pulling.h
+++ b/src/tint/transform/vertex_pulling.h
@@ -26,38 +26,38 @@
 
 /// Describes the format of data in a vertex buffer
 enum class VertexFormat {
-  kUint8x2,    // uint8x2
-  kUint8x4,    // uint8x4
-  kSint8x2,    // sint8x2
-  kSint8x4,    // sint8x4
-  kUnorm8x2,   // unorm8x2
-  kUnorm8x4,   // unorm8x4
-  kSnorm8x2,   // snorm8x2
-  kSnorm8x4,   // snorm8x4
-  kUint16x2,   // uint16x2
-  kUint16x4,   // uint16x4
-  kSint16x2,   // sint16x2
-  kSint16x4,   // sint16x4
-  kUnorm16x2,  // unorm16x2
-  kUnorm16x4,  // unorm16x4
-  kSnorm16x2,  // snorm16x2
-  kSnorm16x4,  // snorm16x4
-  kFloat16x2,  // float16x2
-  kFloat16x4,  // float16x4
-  kFloat32,    // float32
-  kFloat32x2,  // float32x2
-  kFloat32x3,  // float32x3
-  kFloat32x4,  // float32x4
-  kUint32,     // uint32
-  kUint32x2,   // uint32x2
-  kUint32x3,   // uint32x3
-  kUint32x4,   // uint32x4
-  kSint32,     // sint32
-  kSint32x2,   // sint32x2
-  kSint32x3,   // sint32x3
-  kSint32x4,   // sint32x4
+    kUint8x2,    // uint8x2
+    kUint8x4,    // uint8x4
+    kSint8x2,    // sint8x2
+    kSint8x4,    // sint8x4
+    kUnorm8x2,   // unorm8x2
+    kUnorm8x4,   // unorm8x4
+    kSnorm8x2,   // snorm8x2
+    kSnorm8x4,   // snorm8x4
+    kUint16x2,   // uint16x2
+    kUint16x4,   // uint16x4
+    kSint16x2,   // sint16x2
+    kSint16x4,   // sint16x4
+    kUnorm16x2,  // unorm16x2
+    kUnorm16x4,  // unorm16x4
+    kSnorm16x2,  // snorm16x2
+    kSnorm16x4,  // snorm16x4
+    kFloat16x2,  // float16x2
+    kFloat16x4,  // float16x4
+    kFloat32,    // float32
+    kFloat32x2,  // float32x2
+    kFloat32x3,  // float32x3
+    kFloat32x4,  // float32x4
+    kUint32,     // uint32
+    kUint32x2,   // uint32x2
+    kUint32x3,   // uint32x3
+    kUint32x4,   // uint32x4
+    kSint32,     // sint32
+    kSint32x2,   // sint32x2
+    kSint32x3,   // sint32x3
+    kSint32x4,   // sint32x4
 
-  kLastEntry = kSint32x4,
+    kLastEntry = kSint32x4,
 };
 
 /// Describes if a vertex attributes increments with vertex index or instance
@@ -66,44 +66,42 @@
 
 /// Describes a vertex attribute within a buffer
 struct VertexAttributeDescriptor {
-  /// The format of the attribute
-  VertexFormat format;
-  /// The byte offset of the attribute in the buffer
-  uint32_t offset;
-  /// The shader location used for the attribute
-  uint32_t shader_location;
+    /// The format of the attribute
+    VertexFormat format;
+    /// The byte offset of the attribute in the buffer
+    uint32_t offset;
+    /// The shader location used for the attribute
+    uint32_t shader_location;
 };
 
 /// Describes a buffer containing multiple vertex attributes
 struct VertexBufferLayoutDescriptor {
-  /// Constructor
-  VertexBufferLayoutDescriptor();
-  /// Constructor
-  /// @param in_array_stride the array stride of the in buffer
-  /// @param in_step_mode the step mode of the in buffer
-  /// @param in_attributes the in attributes
-  VertexBufferLayoutDescriptor(
-      uint32_t in_array_stride,
-      VertexStepMode in_step_mode,
-      std::vector<VertexAttributeDescriptor> in_attributes);
-  /// Copy constructor
-  /// @param other the struct to copy
-  VertexBufferLayoutDescriptor(const VertexBufferLayoutDescriptor& other);
+    /// Constructor
+    VertexBufferLayoutDescriptor();
+    /// Constructor
+    /// @param in_array_stride the array stride of the in buffer
+    /// @param in_step_mode the step mode of the in buffer
+    /// @param in_attributes the in attributes
+    VertexBufferLayoutDescriptor(uint32_t in_array_stride,
+                                 VertexStepMode in_step_mode,
+                                 std::vector<VertexAttributeDescriptor> in_attributes);
+    /// Copy constructor
+    /// @param other the struct to copy
+    VertexBufferLayoutDescriptor(const VertexBufferLayoutDescriptor& other);
 
-  /// Assignment operator
-  /// @param other the struct to copy
-  /// @returns this struct
-  VertexBufferLayoutDescriptor& operator=(
-      const VertexBufferLayoutDescriptor& other);
+    /// Assignment operator
+    /// @param other the struct to copy
+    /// @returns this struct
+    VertexBufferLayoutDescriptor& operator=(const VertexBufferLayoutDescriptor& other);
 
-  ~VertexBufferLayoutDescriptor();
+    ~VertexBufferLayoutDescriptor();
 
-  /// The array stride used in the in buffer
-  uint32_t array_stride = 0u;
-  /// The input step mode used
-  VertexStepMode step_mode = VertexStepMode::kVertex;
-  /// The vertex attributes
-  std::vector<VertexAttributeDescriptor> attributes;
+    /// The array stride used in the in buffer
+    uint32_t array_stride = 0u;
+    /// The input step mode used
+    VertexStepMode step_mode = VertexStepMode::kVertex;
+    /// The vertex attributes
+    std::vector<VertexAttributeDescriptor> attributes;
 };
 
 /// Describes vertex state, which consists of many buffers containing vertex
@@ -131,52 +129,50 @@
 /// these smaller types into the base types such as `f32` and `u32` for the
 /// shader to use.
 class VertexPulling : public Castable<VertexPulling, Transform> {
- public:
-  /// Configuration options for the transform
-  struct Config : public Castable<Config, Data> {
-    /// Constructor
-    Config();
+  public:
+    /// Configuration options for the transform
+    struct Config : public Castable<Config, Data> {
+        /// Constructor
+        Config();
 
-    /// Copy constructor
-    Config(const Config&);
+        /// Copy constructor
+        Config(const Config&);
+
+        /// Destructor
+        ~Config() override;
+
+        /// Assignment operator
+        /// @returns this Config
+        Config& operator=(const Config&);
+
+        /// The entry point to add assignments into
+        std::string entry_point_name;
+
+        /// The vertex state descriptor, containing info about attributes
+        VertexStateDescriptor vertex_state;
+
+        /// The "group" we will put all our vertex buffers into (as storage buffers)
+        /// Default to 4 as it is past the limits of user-accessible groups
+        uint32_t pulling_group = 4u;
+    };
+
+    /// Constructor
+    VertexPulling();
 
     /// Destructor
-    ~Config() override;
+    ~VertexPulling() override;
 
-    /// Assignment operator
-    /// @returns this Config
-    Config& operator=(const Config&);
+  protected:
+    /// Runs the transform using the CloneContext built for transforming a
+    /// program. Run() is responsible for calling Clone() on the CloneContext.
+    /// @param ctx the CloneContext primed with the input program and
+    /// ProgramBuilder
+    /// @param inputs optional extra transform-specific input data
+    /// @param outputs optional extra transform-specific output data
+    void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const override;
 
-    /// The entry point to add assignments into
-    std::string entry_point_name;
-
-    /// The vertex state descriptor, containing info about attributes
-    VertexStateDescriptor vertex_state;
-
-    /// The "group" we will put all our vertex buffers into (as storage buffers)
-    /// Default to 4 as it is past the limits of user-accessible groups
-    uint32_t pulling_group = 4u;
-  };
-
-  /// Constructor
-  VertexPulling();
-
-  /// Destructor
-  ~VertexPulling() override;
-
- protected:
-  /// Runs the transform using the CloneContext built for transforming a
-  /// program. Run() is responsible for calling Clone() on the CloneContext.
-  /// @param ctx the CloneContext primed with the input program and
-  /// ProgramBuilder
-  /// @param inputs optional extra transform-specific input data
-  /// @param outputs optional extra transform-specific output data
-  void Run(CloneContext& ctx,
-           const DataMap& inputs,
-           DataMap& outputs) const override;
-
- private:
-  Config cfg_;
+  private:
+    Config cfg_;
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/vertex_pulling_test.cc b/src/tint/transform/vertex_pulling_test.cc
index 3c19aa6..80768a7 100644
--- a/src/tint/transform/vertex_pulling_test.cc
+++ b/src/tint/transform/vertex_pulling_test.cc
@@ -24,88 +24,87 @@
 using VertexPullingTest = TransformTest;
 
 TEST_F(VertexPullingTest, Error_NoEntryPoint) {
-  auto* src = "";
+    auto* src = "";
 
-  auto* expect = "error: Vertex stage entry point not found";
+    auto* expect = "error: Vertex stage entry point not found";
 
-  DataMap data;
-  data.Add<VertexPulling::Config>();
-  auto got = Run<VertexPulling>(src, data);
+    DataMap data;
+    data.Add<VertexPulling::Config>();
+    auto got = Run<VertexPulling>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(VertexPullingTest, Error_InvalidEntryPoint) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(vertex)
 fn main() -> @builtin(position) vec4<f32> {
   return vec4<f32>();
 }
 )";
 
-  auto* expect = "error: Vertex stage entry point not found";
+    auto* expect = "error: Vertex stage entry point not found";
 
-  VertexPulling::Config cfg;
-  cfg.entry_point_name = "_";
+    VertexPulling::Config cfg;
+    cfg.entry_point_name = "_";
 
-  DataMap data;
-  data.Add<VertexPulling::Config>(cfg);
-  auto got = Run<VertexPulling>(src, data);
+    DataMap data;
+    data.Add<VertexPulling::Config>(cfg);
+    auto got = Run<VertexPulling>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(VertexPullingTest, Error_EntryPointWrongStage) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(fragment)
 fn main() {}
 )";
 
-  auto* expect = "error: Vertex stage entry point not found";
+    auto* expect = "error: Vertex stage entry point not found";
 
-  VertexPulling::Config cfg;
-  cfg.entry_point_name = "main";
+    VertexPulling::Config cfg;
+    cfg.entry_point_name = "main";
 
-  DataMap data;
-  data.Add<VertexPulling::Config>(cfg);
-  auto got = Run<VertexPulling>(src, data);
+    DataMap data;
+    data.Add<VertexPulling::Config>(cfg);
+    auto got = Run<VertexPulling>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(VertexPullingTest, Error_BadStride) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(vertex)
 fn main(@location(0) var_a : f32) -> @builtin(position) vec4<f32> {
   return vec4<f32>(var_a, 0.0, 0.0, 1.0);
 }
 )";
 
-  auto* expect =
-      "error: WebGPU requires that vertex stride must be a multiple of 4 "
-      "bytes, but VertexPulling array stride for buffer 0 was 15 bytes";
+    auto* expect =
+        "error: WebGPU requires that vertex stride must be a multiple of 4 "
+        "bytes, but VertexPulling array stride for buffer 0 was 15 bytes";
 
-  VertexPulling::Config cfg;
-  cfg.vertex_state = {
-      {{15, VertexStepMode::kVertex, {{VertexFormat::kFloat32, 0, 0}}}}};
-  cfg.entry_point_name = "main";
+    VertexPulling::Config cfg;
+    cfg.vertex_state = {{{15, VertexStepMode::kVertex, {{VertexFormat::kFloat32, 0, 0}}}}};
+    cfg.entry_point_name = "main";
 
-  DataMap data;
-  data.Add<VertexPulling::Config>(cfg);
-  auto got = Run<VertexPulling>(src, data);
+    DataMap data;
+    data.Add<VertexPulling::Config>(cfg);
+    auto got = Run<VertexPulling>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(VertexPullingTest, BasicModule) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(vertex)
 fn main() -> @builtin(position) vec4<f32> {
   return vec4<f32>();
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct TintVertexData {
   tint_vertex_data : array<u32>,
 }
@@ -116,25 +115,25 @@
 }
 )";
 
-  VertexPulling::Config cfg;
-  cfg.entry_point_name = "main";
+    VertexPulling::Config cfg;
+    cfg.entry_point_name = "main";
 
-  DataMap data;
-  data.Add<VertexPulling::Config>(cfg);
-  auto got = Run<VertexPulling>(src, data);
+    DataMap data;
+    data.Add<VertexPulling::Config>(cfg);
+    auto got = Run<VertexPulling>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(VertexPullingTest, OneAttribute) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(vertex)
 fn main(@location(0) var_a : f32) -> @builtin(position) vec4<f32> {
   return vec4<f32>(var_a, 0.0, 0.0, 1.0);
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct TintVertexData {
   tint_vertex_data : array<u32>,
 }
@@ -152,27 +151,26 @@
 }
 )";
 
-  VertexPulling::Config cfg;
-  cfg.vertex_state = {
-      {{4, VertexStepMode::kVertex, {{VertexFormat::kFloat32, 0, 0}}}}};
-  cfg.entry_point_name = "main";
+    VertexPulling::Config cfg;
+    cfg.vertex_state = {{{4, VertexStepMode::kVertex, {{VertexFormat::kFloat32, 0, 0}}}}};
+    cfg.entry_point_name = "main";
 
-  DataMap data;
-  data.Add<VertexPulling::Config>(cfg);
-  auto got = Run<VertexPulling>(src, data);
+    DataMap data;
+    data.Add<VertexPulling::Config>(cfg);
+    auto got = Run<VertexPulling>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(VertexPullingTest, OneInstancedAttribute) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(vertex)
 fn main(@location(0) var_a : f32) -> @builtin(position) vec4<f32> {
   return vec4<f32>(var_a, 0.0, 0.0, 1.0);
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct TintVertexData {
   tint_vertex_data : array<u32>,
 }
@@ -190,27 +188,26 @@
 }
 )";
 
-  VertexPulling::Config cfg;
-  cfg.vertex_state = {
-      {{4, VertexStepMode::kInstance, {{VertexFormat::kFloat32, 0, 0}}}}};
-  cfg.entry_point_name = "main";
+    VertexPulling::Config cfg;
+    cfg.vertex_state = {{{4, VertexStepMode::kInstance, {{VertexFormat::kFloat32, 0, 0}}}}};
+    cfg.entry_point_name = "main";
 
-  DataMap data;
-  data.Add<VertexPulling::Config>(cfg);
-  auto got = Run<VertexPulling>(src, data);
+    DataMap data;
+    data.Add<VertexPulling::Config>(cfg);
+    auto got = Run<VertexPulling>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(VertexPullingTest, OneAttributeDifferentOutputSet) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(vertex)
 fn main(@location(0) var_a : f32) -> @builtin(position) vec4<f32> {
   return vec4<f32>(var_a, 0.0, 0.0, 1.0);
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct TintVertexData {
   tint_vertex_data : array<u32>,
 }
@@ -228,21 +225,20 @@
 }
 )";
 
-  VertexPulling::Config cfg;
-  cfg.vertex_state = {
-      {{4, VertexStepMode::kVertex, {{VertexFormat::kFloat32, 0, 0}}}}};
-  cfg.pulling_group = 5;
-  cfg.entry_point_name = "main";
+    VertexPulling::Config cfg;
+    cfg.vertex_state = {{{4, VertexStepMode::kVertex, {{VertexFormat::kFloat32, 0, 0}}}}};
+    cfg.pulling_group = 5;
+    cfg.entry_point_name = "main";
 
-  DataMap data;
-  data.Add<VertexPulling::Config>(cfg);
-  auto got = Run<VertexPulling>(src, data);
+    DataMap data;
+    data.Add<VertexPulling::Config>(cfg);
+    auto got = Run<VertexPulling>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(VertexPullingTest, OneAttribute_Struct) {
-  auto* src = R"(
+    auto* src = R"(
 struct Inputs {
   @location(0) var_a : f32,
 };
@@ -253,7 +249,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct TintVertexData {
   tint_vertex_data : array<u32>,
 }
@@ -276,21 +272,20 @@
 }
 )";
 
-  VertexPulling::Config cfg;
-  cfg.vertex_state = {
-      {{4, VertexStepMode::kVertex, {{VertexFormat::kFloat32, 0, 0}}}}};
-  cfg.entry_point_name = "main";
+    VertexPulling::Config cfg;
+    cfg.vertex_state = {{{4, VertexStepMode::kVertex, {{VertexFormat::kFloat32, 0, 0}}}}};
+    cfg.entry_point_name = "main";
 
-  DataMap data;
-  data.Add<VertexPulling::Config>(cfg);
-  auto got = Run<VertexPulling>(src, data);
+    DataMap data;
+    data.Add<VertexPulling::Config>(cfg);
+    auto got = Run<VertexPulling>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 // We expect the transform to use an existing builtin variables if it finds them
 TEST_F(VertexPullingTest, ExistingVertexIndexAndInstanceIndex) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(vertex)
 fn main(@location(0) var_a : f32,
         @location(1) var_b : f32,
@@ -301,7 +296,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct TintVertexData {
   tint_vertex_data : array<u32>,
 }
@@ -324,30 +319,30 @@
 }
 )";
 
-  VertexPulling::Config cfg;
-  cfg.vertex_state = {{
-      {
-          4,
-          VertexStepMode::kVertex,
-          {{VertexFormat::kFloat32, 0, 0}},
-      },
-      {
-          4,
-          VertexStepMode::kInstance,
-          {{VertexFormat::kFloat32, 0, 1}},
-      },
-  }};
-  cfg.entry_point_name = "main";
+    VertexPulling::Config cfg;
+    cfg.vertex_state = {{
+        {
+            4,
+            VertexStepMode::kVertex,
+            {{VertexFormat::kFloat32, 0, 0}},
+        },
+        {
+            4,
+            VertexStepMode::kInstance,
+            {{VertexFormat::kFloat32, 0, 1}},
+        },
+    }};
+    cfg.entry_point_name = "main";
 
-  DataMap data;
-  data.Add<VertexPulling::Config>(cfg);
-  auto got = Run<VertexPulling>(src, data);
+    DataMap data;
+    data.Add<VertexPulling::Config>(cfg);
+    auto got = Run<VertexPulling>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(VertexPullingTest, ExistingVertexIndexAndInstanceIndex_Struct) {
-  auto* src = R"(
+    auto* src = R"(
 struct Inputs {
   @location(0) var_a : f32,
   @location(1) var_b : f32,
@@ -361,7 +356,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct TintVertexData {
   tint_vertex_data : array<u32>,
 }
@@ -403,31 +398,30 @@
 }
 )";
 
-  VertexPulling::Config cfg;
-  cfg.vertex_state = {{
-      {
-          4,
-          VertexStepMode::kVertex,
-          {{VertexFormat::kFloat32, 0, 0}},
-      },
-      {
-          4,
-          VertexStepMode::kInstance,
-          {{VertexFormat::kFloat32, 0, 1}},
-      },
-  }};
-  cfg.entry_point_name = "main";
+    VertexPulling::Config cfg;
+    cfg.vertex_state = {{
+        {
+            4,
+            VertexStepMode::kVertex,
+            {{VertexFormat::kFloat32, 0, 0}},
+        },
+        {
+            4,
+            VertexStepMode::kInstance,
+            {{VertexFormat::kFloat32, 0, 1}},
+        },
+    }};
+    cfg.entry_point_name = "main";
 
-  DataMap data;
-  data.Add<VertexPulling::Config>(cfg);
-  auto got = Run<VertexPulling>(src, data);
+    DataMap data;
+    data.Add<VertexPulling::Config>(cfg);
+    auto got = Run<VertexPulling>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(VertexPullingTest,
-       ExistingVertexIndexAndInstanceIndex_Struct_OutOfOrder) {
-  auto* src = R"(
+TEST_F(VertexPullingTest, ExistingVertexIndexAndInstanceIndex_Struct_OutOfOrder) {
+    auto* src = R"(
 @stage(vertex)
 fn main(inputs : Inputs) -> @builtin(position) vec4<f32> {
   return vec4<f32>(inputs.var_a, inputs.var_b, 0.0, 1.0);
@@ -441,7 +435,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct TintVertexData {
   tint_vertex_data : array<u32>,
 }
@@ -483,30 +477,30 @@
 }
 )";
 
-  VertexPulling::Config cfg;
-  cfg.vertex_state = {{
-      {
-          4,
-          VertexStepMode::kVertex,
-          {{VertexFormat::kFloat32, 0, 0}},
-      },
-      {
-          4,
-          VertexStepMode::kInstance,
-          {{VertexFormat::kFloat32, 0, 1}},
-      },
-  }};
-  cfg.entry_point_name = "main";
+    VertexPulling::Config cfg;
+    cfg.vertex_state = {{
+        {
+            4,
+            VertexStepMode::kVertex,
+            {{VertexFormat::kFloat32, 0, 0}},
+        },
+        {
+            4,
+            VertexStepMode::kInstance,
+            {{VertexFormat::kFloat32, 0, 1}},
+        },
+    }};
+    cfg.entry_point_name = "main";
 
-  DataMap data;
-  data.Add<VertexPulling::Config>(cfg);
-  auto got = Run<VertexPulling>(src, data);
+    DataMap data;
+    data.Add<VertexPulling::Config>(cfg);
+    auto got = Run<VertexPulling>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(VertexPullingTest, ExistingVertexIndexAndInstanceIndex_SeparateStruct) {
-  auto* src = R"(
+    auto* src = R"(
 struct Inputs {
   @location(0) var_a : f32,
   @location(1) var_b : f32,
@@ -523,7 +517,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct TintVertexData {
   tint_vertex_data : array<u32>,
 }
@@ -559,31 +553,30 @@
 }
 )";
 
-  VertexPulling::Config cfg;
-  cfg.vertex_state = {{
-      {
-          4,
-          VertexStepMode::kVertex,
-          {{VertexFormat::kFloat32, 0, 0}},
-      },
-      {
-          4,
-          VertexStepMode::kInstance,
-          {{VertexFormat::kFloat32, 0, 1}},
-      },
-  }};
-  cfg.entry_point_name = "main";
+    VertexPulling::Config cfg;
+    cfg.vertex_state = {{
+        {
+            4,
+            VertexStepMode::kVertex,
+            {{VertexFormat::kFloat32, 0, 0}},
+        },
+        {
+            4,
+            VertexStepMode::kInstance,
+            {{VertexFormat::kFloat32, 0, 1}},
+        },
+    }};
+    cfg.entry_point_name = "main";
 
-  DataMap data;
-  data.Add<VertexPulling::Config>(cfg);
-  auto got = Run<VertexPulling>(src, data);
+    DataMap data;
+    data.Add<VertexPulling::Config>(cfg);
+    auto got = Run<VertexPulling>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(VertexPullingTest,
-       ExistingVertexIndexAndInstanceIndex_SeparateStruct_OutOfOrder) {
-  auto* src = R"(
+TEST_F(VertexPullingTest, ExistingVertexIndexAndInstanceIndex_SeparateStruct_OutOfOrder) {
+    auto* src = R"(
 @stage(vertex)
 fn main(inputs : Inputs, indices : Indices) -> @builtin(position) vec4<f32> {
   return vec4<f32>(inputs.var_a, inputs.var_b, 0.0, 1.0);
@@ -600,7 +593,7 @@
 };
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct TintVertexData {
   tint_vertex_data : array<u32>,
 }
@@ -636,30 +629,30 @@
 }
 )";
 
-  VertexPulling::Config cfg;
-  cfg.vertex_state = {{
-      {
-          4,
-          VertexStepMode::kVertex,
-          {{VertexFormat::kFloat32, 0, 0}},
-      },
-      {
-          4,
-          VertexStepMode::kInstance,
-          {{VertexFormat::kFloat32, 0, 1}},
-      },
-  }};
-  cfg.entry_point_name = "main";
+    VertexPulling::Config cfg;
+    cfg.vertex_state = {{
+        {
+            4,
+            VertexStepMode::kVertex,
+            {{VertexFormat::kFloat32, 0, 0}},
+        },
+        {
+            4,
+            VertexStepMode::kInstance,
+            {{VertexFormat::kFloat32, 0, 1}},
+        },
+    }};
+    cfg.entry_point_name = "main";
 
-  DataMap data;
-  data.Add<VertexPulling::Config>(cfg);
-  auto got = Run<VertexPulling>(src, data);
+    DataMap data;
+    data.Add<VertexPulling::Config>(cfg);
+    auto got = Run<VertexPulling>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(VertexPullingTest, TwoAttributesSameBuffer) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(vertex)
 fn main(@location(0) var_a : f32,
         @location(1) var_b : vec4<f32>) -> @builtin(position) vec4<f32> {
@@ -667,7 +660,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct TintVertexData {
   tint_vertex_data : array<u32>,
 }
@@ -687,22 +680,21 @@
 }
 )";
 
-  VertexPulling::Config cfg;
-  cfg.vertex_state = {
-      {{16,
-        VertexStepMode::kVertex,
-        {{VertexFormat::kFloat32, 0, 0}, {VertexFormat::kFloat32x4, 0, 1}}}}};
-  cfg.entry_point_name = "main";
+    VertexPulling::Config cfg;
+    cfg.vertex_state = {{{16,
+                          VertexStepMode::kVertex,
+                          {{VertexFormat::kFloat32, 0, 0}, {VertexFormat::kFloat32x4, 0, 1}}}}};
+    cfg.entry_point_name = "main";
 
-  DataMap data;
-  data.Add<VertexPulling::Config>(cfg);
-  auto got = Run<VertexPulling>(src, data);
+    DataMap data;
+    data.Add<VertexPulling::Config>(cfg);
+    auto got = Run<VertexPulling>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(VertexPullingTest, FloatVectorAttributes) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(vertex)
 fn main(@location(0) var_a : vec2<f32>,
         @location(1) var_b : vec3<f32>,
@@ -712,7 +704,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct TintVertexData {
   tint_vertex_data : array<u32>,
 }
@@ -740,23 +732,23 @@
 }
 )";
 
-  VertexPulling::Config cfg;
-  cfg.vertex_state = {{
-      {8, VertexStepMode::kVertex, {{VertexFormat::kFloat32x2, 0, 0}}},
-      {12, VertexStepMode::kVertex, {{VertexFormat::kFloat32x3, 0, 1}}},
-      {16, VertexStepMode::kVertex, {{VertexFormat::kFloat32x4, 0, 2}}},
-  }};
-  cfg.entry_point_name = "main";
+    VertexPulling::Config cfg;
+    cfg.vertex_state = {{
+        {8, VertexStepMode::kVertex, {{VertexFormat::kFloat32x2, 0, 0}}},
+        {12, VertexStepMode::kVertex, {{VertexFormat::kFloat32x3, 0, 1}}},
+        {16, VertexStepMode::kVertex, {{VertexFormat::kFloat32x4, 0, 2}}},
+    }};
+    cfg.entry_point_name = "main";
 
-  DataMap data;
-  data.Add<VertexPulling::Config>(cfg);
-  auto got = Run<VertexPulling>(src, data);
+    DataMap data;
+    data.Add<VertexPulling::Config>(cfg);
+    auto got = Run<VertexPulling>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(VertexPullingTest, AttemptSymbolCollision) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(vertex)
 fn main(@location(0) var_a : f32,
         @location(1) var_b : vec4<f32>) -> @builtin(position) vec4<f32> {
@@ -768,7 +760,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct TintVertexData {
   tint_vertex_data_1 : array<u32>,
 }
@@ -792,22 +784,21 @@
 }
 )";
 
-  VertexPulling::Config cfg;
-  cfg.vertex_state = {
-      {{16,
-        VertexStepMode::kVertex,
-        {{VertexFormat::kFloat32, 0, 0}, {VertexFormat::kFloat32x4, 0, 1}}}}};
-  cfg.entry_point_name = "main";
+    VertexPulling::Config cfg;
+    cfg.vertex_state = {{{16,
+                          VertexStepMode::kVertex,
+                          {{VertexFormat::kFloat32, 0, 0}, {VertexFormat::kFloat32x4, 0, 1}}}}};
+    cfg.entry_point_name = "main";
 
-  DataMap data;
-  data.Add<VertexPulling::Config>(cfg);
-  auto got = Run<VertexPulling>(src, std::move(data));
+    DataMap data;
+    data.Add<VertexPulling::Config>(cfg);
+    auto got = Run<VertexPulling>(src, std::move(data));
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(VertexPullingTest, FormatsAligned) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(vertex)
 fn main(
     @location(0) uint8x2 : vec2<u32>,
@@ -845,7 +836,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct TintVertexData {
   tint_vertex_data : array<u32>,
 }
@@ -921,52 +912,38 @@
 }
 )";
 
-  VertexPulling::Config cfg;
-  cfg.vertex_state = {{{256,
-                        VertexStepMode::kVertex,
-                        {
-                            {VertexFormat::kUint8x2, 64, 0},
-                            {VertexFormat::kUint8x4, 64, 1},
-                            {VertexFormat::kSint8x2, 64, 2},
-                            {VertexFormat::kSint8x4, 64, 3},
-                            {VertexFormat::kUnorm8x2, 64, 4},
-                            {VertexFormat::kUnorm8x4, 64, 5},
-                            {VertexFormat::kSnorm8x2, 64, 6},
-                            {VertexFormat::kSnorm8x4, 64, 7},
-                            {VertexFormat::kUint16x2, 64, 8},
-                            {VertexFormat::kUint16x4, 64, 9},
-                            {VertexFormat::kSint16x2, 64, 10},
-                            {VertexFormat::kSint16x4, 64, 11},
-                            {VertexFormat::kUnorm16x2, 64, 12},
-                            {VertexFormat::kUnorm16x4, 64, 13},
-                            {VertexFormat::kSnorm16x2, 64, 14},
-                            {VertexFormat::kSnorm16x4, 64, 15},
-                            {VertexFormat::kFloat16x2, 64, 16},
-                            {VertexFormat::kFloat16x4, 64, 17},
-                            {VertexFormat::kFloat32, 64, 18},
-                            {VertexFormat::kFloat32x2, 64, 19},
-                            {VertexFormat::kFloat32x3, 64, 20},
-                            {VertexFormat::kFloat32x4, 64, 21},
-                            {VertexFormat::kUint32, 64, 22},
-                            {VertexFormat::kUint32x2, 64, 23},
-                            {VertexFormat::kUint32x3, 64, 24},
-                            {VertexFormat::kUint32x4, 64, 25},
-                            {VertexFormat::kSint32, 64, 26},
-                            {VertexFormat::kSint32x2, 64, 27},
-                            {VertexFormat::kSint32x3, 64, 28},
-                            {VertexFormat::kSint32x4, 64, 29},
-                        }}}};
-  cfg.entry_point_name = "main";
+    VertexPulling::Config cfg;
+    cfg.vertex_state = {
+        {{256,
+          VertexStepMode::kVertex,
+          {
+              {VertexFormat::kUint8x2, 64, 0},    {VertexFormat::kUint8x4, 64, 1},
+              {VertexFormat::kSint8x2, 64, 2},    {VertexFormat::kSint8x4, 64, 3},
+              {VertexFormat::kUnorm8x2, 64, 4},   {VertexFormat::kUnorm8x4, 64, 5},
+              {VertexFormat::kSnorm8x2, 64, 6},   {VertexFormat::kSnorm8x4, 64, 7},
+              {VertexFormat::kUint16x2, 64, 8},   {VertexFormat::kUint16x4, 64, 9},
+              {VertexFormat::kSint16x2, 64, 10},  {VertexFormat::kSint16x4, 64, 11},
+              {VertexFormat::kUnorm16x2, 64, 12}, {VertexFormat::kUnorm16x4, 64, 13},
+              {VertexFormat::kSnorm16x2, 64, 14}, {VertexFormat::kSnorm16x4, 64, 15},
+              {VertexFormat::kFloat16x2, 64, 16}, {VertexFormat::kFloat16x4, 64, 17},
+              {VertexFormat::kFloat32, 64, 18},   {VertexFormat::kFloat32x2, 64, 19},
+              {VertexFormat::kFloat32x3, 64, 20}, {VertexFormat::kFloat32x4, 64, 21},
+              {VertexFormat::kUint32, 64, 22},    {VertexFormat::kUint32x2, 64, 23},
+              {VertexFormat::kUint32x3, 64, 24},  {VertexFormat::kUint32x4, 64, 25},
+              {VertexFormat::kSint32, 64, 26},    {VertexFormat::kSint32x2, 64, 27},
+              {VertexFormat::kSint32x3, 64, 28},  {VertexFormat::kSint32x4, 64, 29},
+          }}}};
+    cfg.entry_point_name = "main";
 
-  DataMap data;
-  data.Add<VertexPulling::Config>(cfg);
-  auto got = Run<VertexPulling>(src, data);
+    DataMap data;
+    data.Add<VertexPulling::Config>(cfg);
+    auto got = Run<VertexPulling>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(VertexPullingTest, FormatsStrideUnaligned) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(vertex)
 fn main(
     @location(0) uint8x2 : vec2<u32>,
@@ -1004,8 +981,8 @@
 }
 )";
 
-  auto* expect =
-      R"(
+    auto* expect =
+        R"(
 struct TintVertexData {
   tint_vertex_data : array<u32>,
 }
@@ -1081,52 +1058,38 @@
 }
 )";
 
-  VertexPulling::Config cfg;
-  cfg.vertex_state = {{{256,
-                        VertexStepMode::kVertex,
-                        {
-                            {VertexFormat::kUint8x2, 63, 0},
-                            {VertexFormat::kUint8x4, 63, 1},
-                            {VertexFormat::kSint8x2, 63, 2},
-                            {VertexFormat::kSint8x4, 63, 3},
-                            {VertexFormat::kUnorm8x2, 63, 4},
-                            {VertexFormat::kUnorm8x4, 63, 5},
-                            {VertexFormat::kSnorm8x2, 63, 6},
-                            {VertexFormat::kSnorm8x4, 63, 7},
-                            {VertexFormat::kUint16x2, 63, 8},
-                            {VertexFormat::kUint16x4, 63, 9},
-                            {VertexFormat::kSint16x2, 63, 10},
-                            {VertexFormat::kSint16x4, 63, 11},
-                            {VertexFormat::kUnorm16x2, 63, 12},
-                            {VertexFormat::kUnorm16x4, 63, 13},
-                            {VertexFormat::kSnorm16x2, 63, 14},
-                            {VertexFormat::kSnorm16x4, 63, 15},
-                            {VertexFormat::kFloat16x2, 63, 16},
-                            {VertexFormat::kFloat16x4, 63, 17},
-                            {VertexFormat::kFloat32, 63, 18},
-                            {VertexFormat::kFloat32x2, 63, 19},
-                            {VertexFormat::kFloat32x3, 63, 20},
-                            {VertexFormat::kFloat32x4, 63, 21},
-                            {VertexFormat::kUint32, 63, 22},
-                            {VertexFormat::kUint32x2, 63, 23},
-                            {VertexFormat::kUint32x3, 63, 24},
-                            {VertexFormat::kUint32x4, 63, 25},
-                            {VertexFormat::kSint32, 63, 26},
-                            {VertexFormat::kSint32x2, 63, 27},
-                            {VertexFormat::kSint32x3, 63, 28},
-                            {VertexFormat::kSint32x4, 63, 29},
-                        }}}};
-  cfg.entry_point_name = "main";
+    VertexPulling::Config cfg;
+    cfg.vertex_state = {
+        {{256,
+          VertexStepMode::kVertex,
+          {
+              {VertexFormat::kUint8x2, 63, 0},    {VertexFormat::kUint8x4, 63, 1},
+              {VertexFormat::kSint8x2, 63, 2},    {VertexFormat::kSint8x4, 63, 3},
+              {VertexFormat::kUnorm8x2, 63, 4},   {VertexFormat::kUnorm8x4, 63, 5},
+              {VertexFormat::kSnorm8x2, 63, 6},   {VertexFormat::kSnorm8x4, 63, 7},
+              {VertexFormat::kUint16x2, 63, 8},   {VertexFormat::kUint16x4, 63, 9},
+              {VertexFormat::kSint16x2, 63, 10},  {VertexFormat::kSint16x4, 63, 11},
+              {VertexFormat::kUnorm16x2, 63, 12}, {VertexFormat::kUnorm16x4, 63, 13},
+              {VertexFormat::kSnorm16x2, 63, 14}, {VertexFormat::kSnorm16x4, 63, 15},
+              {VertexFormat::kFloat16x2, 63, 16}, {VertexFormat::kFloat16x4, 63, 17},
+              {VertexFormat::kFloat32, 63, 18},   {VertexFormat::kFloat32x2, 63, 19},
+              {VertexFormat::kFloat32x3, 63, 20}, {VertexFormat::kFloat32x4, 63, 21},
+              {VertexFormat::kUint32, 63, 22},    {VertexFormat::kUint32x2, 63, 23},
+              {VertexFormat::kUint32x3, 63, 24},  {VertexFormat::kUint32x4, 63, 25},
+              {VertexFormat::kSint32, 63, 26},    {VertexFormat::kSint32x2, 63, 27},
+              {VertexFormat::kSint32x3, 63, 28},  {VertexFormat::kSint32x4, 63, 29},
+          }}}};
+    cfg.entry_point_name = "main";
 
-  DataMap data;
-  data.Add<VertexPulling::Config>(cfg);
-  auto got = Run<VertexPulling>(src, data);
+    DataMap data;
+    data.Add<VertexPulling::Config>(cfg);
+    auto got = Run<VertexPulling>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(VertexPullingTest, FormatsWithVectorsResized) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(vertex)
 fn main(
     @location(0) uint8x2 : vec3<u32>,
@@ -1164,7 +1127,7 @@
 }
 )";
 
-  auto* expect = R"(
+    auto* expect = R"(
 struct TintVertexData {
   tint_vertex_data : array<u32>,
 }
@@ -1215,7 +1178,7 @@
     snorm8x4 = unpack4x8snorm(tint_pulling_vertex_buffer_0.tint_vertex_data[(buffer_array_base_0 + 16u)]).x;
     uint16x2 = vec3<u32>(((vec2<u32>(tint_pulling_vertex_buffer_0.tint_vertex_data[(buffer_array_base_0 + 16u)]) << vec2<u32>(16u, 0u)) >> vec2<u32>(16u)), 0u);
     uint16x4 = (((vec2<u32>(tint_pulling_vertex_buffer_0.tint_vertex_data[(buffer_array_base_0 + 16u)], tint_pulling_vertex_buffer_0.tint_vertex_data[(buffer_array_base_0 + 17u)]).xxyy << vec4<u32>(16u, 0u, 16u, 0u)) >> vec4<u32>(16u))).xy;
-    sint16x2 = vec4<i32>(((vec2<i32>(bitcast<i32>(tint_pulling_vertex_buffer_0.tint_vertex_data[(buffer_array_base_0 + 16u)])) << vec2<u32>(16u, 0u)) >> vec2<u32>(16u)), 0, 1);
+    sint16x2 = vec4<i32>(((vec2<i32>(bitcast<i32>(tint_pulling_vertex_buffer_0.tint_vertex_data[(buffer_array_base_0 + 16u)])) << vec2<u32>(16u, 0u)) >> vec2<u32>(16u)), 0i, 1i);
     sint16x4 = (((vec2<i32>(bitcast<i32>(tint_pulling_vertex_buffer_0.tint_vertex_data[(buffer_array_base_0 + 16u)]), bitcast<i32>(tint_pulling_vertex_buffer_0.tint_vertex_data[(buffer_array_base_0 + 17u)])).xxyy << vec4<u32>(16u, 0u, 16u, 0u)) >> vec4<u32>(16u))).x;
     unorm16x2 = vec3<f32>(unpack2x16unorm(tint_pulling_vertex_buffer_0.tint_vertex_data[(buffer_array_base_0 + 16u)]), 0.0);
     unorm16x4 = vec4<f32>(unpack2x16unorm(tint_pulling_vertex_buffer_0.tint_vertex_data[(buffer_array_base_0 + 16u)]), unpack2x16unorm(tint_pulling_vertex_buffer_0.tint_vertex_data[(buffer_array_base_0 + 17u)])).x;
@@ -1231,8 +1194,8 @@
     uint32x2 = vec4<u32>(vec2<u32>(tint_pulling_vertex_buffer_0.tint_vertex_data[(buffer_array_base_0 + 16u)], tint_pulling_vertex_buffer_0.tint_vertex_data[(buffer_array_base_0 + 17u)]), 0u, 1u);
     uint32x3 = vec4<u32>(vec3<u32>(tint_pulling_vertex_buffer_0.tint_vertex_data[(buffer_array_base_0 + 16u)], tint_pulling_vertex_buffer_0.tint_vertex_data[(buffer_array_base_0 + 17u)], tint_pulling_vertex_buffer_0.tint_vertex_data[(buffer_array_base_0 + 18u)]), 1u);
     uint32x4 = vec4<u32>(tint_pulling_vertex_buffer_0.tint_vertex_data[(buffer_array_base_0 + 16u)], tint_pulling_vertex_buffer_0.tint_vertex_data[(buffer_array_base_0 + 17u)], tint_pulling_vertex_buffer_0.tint_vertex_data[(buffer_array_base_0 + 18u)], tint_pulling_vertex_buffer_0.tint_vertex_data[(buffer_array_base_0 + 19u)]).xy;
-    sint32 = vec4<i32>(bitcast<i32>(tint_pulling_vertex_buffer_0.tint_vertex_data[(buffer_array_base_0 + 16u)]), 0, 0, 1);
-    sint32x2 = vec3<i32>(vec2<i32>(bitcast<i32>(tint_pulling_vertex_buffer_0.tint_vertex_data[(buffer_array_base_0 + 16u)]), bitcast<i32>(tint_pulling_vertex_buffer_0.tint_vertex_data[(buffer_array_base_0 + 17u)])), 0);
+    sint32 = vec4<i32>(bitcast<i32>(tint_pulling_vertex_buffer_0.tint_vertex_data[(buffer_array_base_0 + 16u)]), 0i, 0i, 1i);
+    sint32x2 = vec3<i32>(vec2<i32>(bitcast<i32>(tint_pulling_vertex_buffer_0.tint_vertex_data[(buffer_array_base_0 + 16u)]), bitcast<i32>(tint_pulling_vertex_buffer_0.tint_vertex_data[(buffer_array_base_0 + 17u)])), 0i);
     sint32x3 = vec3<i32>(bitcast<i32>(tint_pulling_vertex_buffer_0.tint_vertex_data[(buffer_array_base_0 + 16u)]), bitcast<i32>(tint_pulling_vertex_buffer_0.tint_vertex_data[(buffer_array_base_0 + 17u)]), bitcast<i32>(tint_pulling_vertex_buffer_0.tint_vertex_data[(buffer_array_base_0 + 18u)])).x;
     sint32x4 = vec4<i32>(bitcast<i32>(tint_pulling_vertex_buffer_0.tint_vertex_data[(buffer_array_base_0 + 16u)]), bitcast<i32>(tint_pulling_vertex_buffer_0.tint_vertex_data[(buffer_array_base_0 + 17u)]), bitcast<i32>(tint_pulling_vertex_buffer_0.tint_vertex_data[(buffer_array_base_0 + 18u)]), bitcast<i32>(tint_pulling_vertex_buffer_0.tint_vertex_data[(buffer_array_base_0 + 19u)])).xy;
   }
@@ -1240,48 +1203,34 @@
 }
 )";
 
-  VertexPulling::Config cfg;
-  cfg.vertex_state = {{{256,
-                        VertexStepMode::kVertex,
-                        {
-                            {VertexFormat::kUint8x2, 64, 0},
-                            {VertexFormat::kUint8x4, 64, 1},
-                            {VertexFormat::kSint8x2, 64, 2},
-                            {VertexFormat::kSint8x4, 64, 3},
-                            {VertexFormat::kUnorm8x2, 64, 4},
-                            {VertexFormat::kUnorm8x4, 64, 5},
-                            {VertexFormat::kSnorm8x2, 64, 6},
-                            {VertexFormat::kSnorm8x4, 64, 7},
-                            {VertexFormat::kUint16x2, 64, 8},
-                            {VertexFormat::kUint16x4, 64, 9},
-                            {VertexFormat::kSint16x2, 64, 10},
-                            {VertexFormat::kSint16x4, 64, 11},
-                            {VertexFormat::kUnorm16x2, 64, 12},
-                            {VertexFormat::kUnorm16x4, 64, 13},
-                            {VertexFormat::kSnorm16x2, 64, 14},
-                            {VertexFormat::kSnorm16x4, 64, 15},
-                            {VertexFormat::kFloat16x2, 64, 16},
-                            {VertexFormat::kFloat16x4, 64, 17},
-                            {VertexFormat::kFloat32, 64, 18},
-                            {VertexFormat::kFloat32x2, 64, 19},
-                            {VertexFormat::kFloat32x3, 64, 20},
-                            {VertexFormat::kFloat32x4, 64, 21},
-                            {VertexFormat::kUint32, 64, 22},
-                            {VertexFormat::kUint32x2, 64, 23},
-                            {VertexFormat::kUint32x3, 64, 24},
-                            {VertexFormat::kUint32x4, 64, 25},
-                            {VertexFormat::kSint32, 64, 26},
-                            {VertexFormat::kSint32x2, 64, 27},
-                            {VertexFormat::kSint32x3, 64, 28},
-                            {VertexFormat::kSint32x4, 64, 29},
-                        }}}};
-  cfg.entry_point_name = "main";
+    VertexPulling::Config cfg;
+    cfg.vertex_state = {
+        {{256,
+          VertexStepMode::kVertex,
+          {
+              {VertexFormat::kUint8x2, 64, 0},    {VertexFormat::kUint8x4, 64, 1},
+              {VertexFormat::kSint8x2, 64, 2},    {VertexFormat::kSint8x4, 64, 3},
+              {VertexFormat::kUnorm8x2, 64, 4},   {VertexFormat::kUnorm8x4, 64, 5},
+              {VertexFormat::kSnorm8x2, 64, 6},   {VertexFormat::kSnorm8x4, 64, 7},
+              {VertexFormat::kUint16x2, 64, 8},   {VertexFormat::kUint16x4, 64, 9},
+              {VertexFormat::kSint16x2, 64, 10},  {VertexFormat::kSint16x4, 64, 11},
+              {VertexFormat::kUnorm16x2, 64, 12}, {VertexFormat::kUnorm16x4, 64, 13},
+              {VertexFormat::kSnorm16x2, 64, 14}, {VertexFormat::kSnorm16x4, 64, 15},
+              {VertexFormat::kFloat16x2, 64, 16}, {VertexFormat::kFloat16x4, 64, 17},
+              {VertexFormat::kFloat32, 64, 18},   {VertexFormat::kFloat32x2, 64, 19},
+              {VertexFormat::kFloat32x3, 64, 20}, {VertexFormat::kFloat32x4, 64, 21},
+              {VertexFormat::kUint32, 64, 22},    {VertexFormat::kUint32x2, 64, 23},
+              {VertexFormat::kUint32x3, 64, 24},  {VertexFormat::kUint32x4, 64, 25},
+              {VertexFormat::kSint32, 64, 26},    {VertexFormat::kSint32x2, 64, 27},
+              {VertexFormat::kSint32x3, 64, 28},  {VertexFormat::kSint32x4, 64, 29},
+          }}}};
+    cfg.entry_point_name = "main";
 
-  DataMap data;
-  data.Add<VertexPulling::Config>(cfg);
-  auto got = Run<VertexPulling>(src, data);
+    DataMap data;
+    data.Add<VertexPulling::Config>(cfg);
+    auto got = Run<VertexPulling>(src, data);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 }  // namespace
diff --git a/src/tint/transform/wrap_arrays_in_structs.cc b/src/tint/transform/wrap_arrays_in_structs.cc
index 7cf3fcb..b1dc5e8 100644
--- a/src/tint/transform/wrap_arrays_in_structs.cc
+++ b/src/tint/transform/wrap_arrays_in_structs.cc
@@ -29,141 +29,130 @@
 namespace tint::transform {
 
 WrapArraysInStructs::WrappedArrayInfo::WrappedArrayInfo() = default;
-WrapArraysInStructs::WrappedArrayInfo::WrappedArrayInfo(
-    const WrappedArrayInfo&) = default;
+WrapArraysInStructs::WrappedArrayInfo::WrappedArrayInfo(const WrappedArrayInfo&) = default;
 WrapArraysInStructs::WrappedArrayInfo::~WrappedArrayInfo() = default;
 
 WrapArraysInStructs::WrapArraysInStructs() = default;
 
 WrapArraysInStructs::~WrapArraysInStructs() = default;
 
-bool WrapArraysInStructs::ShouldRun(const Program* program,
-                                    const DataMap&) const {
-  for (auto* node : program->ASTNodes().Objects()) {
-    if (program->Sem().Get<sem::Array>(node->As<ast::Type>())) {
-      return true;
+bool WrapArraysInStructs::ShouldRun(const Program* program, const DataMap&) const {
+    for (auto* node : program->ASTNodes().Objects()) {
+        if (program->Sem().Get<sem::Array>(node->As<ast::Type>())) {
+            return true;
+        }
     }
-  }
-  return false;
+    return false;
 }
 
-void WrapArraysInStructs::Run(CloneContext& ctx,
-                              const DataMap&,
-                              DataMap&) const {
-  auto& sem = ctx.src->Sem();
+void WrapArraysInStructs::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
+    auto& sem = ctx.src->Sem();
 
-  std::unordered_map<const sem::Array*, WrappedArrayInfo> wrapped_arrays;
-  auto wrapper = [&](const sem::Array* array) {
-    return WrapArray(ctx, wrapped_arrays, array);
-  };
-  auto wrapper_typename = [&](const sem::Array* arr) -> ast::TypeName* {
-    auto info = wrapper(arr);
-    return info ? ctx.dst->create<ast::TypeName>(info.wrapper_name) : nullptr;
-  };
+    std::unordered_map<const sem::Array*, WrappedArrayInfo> wrapped_arrays;
+    auto wrapper = [&](const sem::Array* array) { return WrapArray(ctx, wrapped_arrays, array); };
+    auto wrapper_typename = [&](const sem::Array* arr) -> ast::TypeName* {
+        auto info = wrapper(arr);
+        return info ? ctx.dst->create<ast::TypeName>(info.wrapper_name) : nullptr;
+    };
 
-  // Replace all array types with their corresponding wrapper
-  ctx.ReplaceAll([&](const ast::Type* ast_type) -> const ast::Type* {
-    auto* type = ctx.src->TypeOf(ast_type);
-    if (auto* array = type->UnwrapRef()->As<sem::Array>()) {
-      return wrapper_typename(array);
-    }
-    return nullptr;
-  });
-
-  // Fix up index accessors so `a[1]` becomes `a.arr[1]`
-  ctx.ReplaceAll([&](const ast::IndexAccessorExpression* accessor)
-                     -> const ast::IndexAccessorExpression* {
-    if (auto* array = ::tint::As<sem::Array>(
-            sem.Get(accessor->object)->Type()->UnwrapRef())) {
-      if (wrapper(array)) {
-        // Array is wrapped in a structure. Emit a member accessor to get
-        // to the actual array.
-        auto* arr = ctx.Clone(accessor->object);
-        auto* idx = ctx.Clone(accessor->index);
-        auto* unwrapped = ctx.dst->MemberAccessor(arr, "arr");
-        return ctx.dst->IndexAccessor(accessor->source, unwrapped, idx);
-      }
-    }
-    return nullptr;
-  });
-
-  // Fix up array constructors so `A(1,2)` becomes `tint_array_wrapper(A(1,2))`
-  ctx.ReplaceAll(
-      [&](const ast::CallExpression* expr) -> const ast::Expression* {
-        if (auto* call = sem.Get(expr)) {
-          if (auto* ctor = call->Target()->As<sem::TypeConstructor>()) {
-            if (auto* array = ctor->ReturnType()->As<sem::Array>()) {
-              if (auto w = wrapper(array)) {
-                // Wrap the array type constructor with another constructor for
-                // the wrapper
-                auto* wrapped_array_ty = ctx.dst->ty.type_name(w.wrapper_name);
-                auto* array_ty = w.array_type(ctx);
-                auto args = utils::Transform(
-                    call->Arguments(), [&](const tint::sem::Expression* s) {
-                      return ctx.Clone(s->Declaration());
-                    });
-                auto* arr_ctor = ctx.dst->Construct(array_ty, args);
-                return ctx.dst->Construct(wrapped_array_ty, arr_ctor);
-              }
-            }
-          }
+    // Replace all array types with their corresponding wrapper
+    ctx.ReplaceAll([&](const ast::Type* ast_type) -> const ast::Type* {
+        auto* type = ctx.src->TypeOf(ast_type);
+        if (auto* array = type->UnwrapRef()->As<sem::Array>()) {
+            return wrapper_typename(array);
         }
         return nullptr;
-      });
+    });
 
-  ctx.Clone();
+    // Fix up index accessors so `a[1]` becomes `a.arr[1]`
+    ctx.ReplaceAll(
+        [&](const ast::IndexAccessorExpression* accessor) -> const ast::IndexAccessorExpression* {
+            if (auto* array =
+                    ::tint::As<sem::Array>(sem.Get(accessor->object)->Type()->UnwrapRef())) {
+                if (wrapper(array)) {
+                    // Array is wrapped in a structure. Emit a member accessor to get
+                    // to the actual array.
+                    auto* arr = ctx.Clone(accessor->object);
+                    auto* idx = ctx.Clone(accessor->index);
+                    auto* unwrapped = ctx.dst->MemberAccessor(arr, "arr");
+                    return ctx.dst->IndexAccessor(accessor->source, unwrapped, idx);
+                }
+            }
+            return nullptr;
+        });
+
+    // Fix up array constructors so `A(1,2)` becomes `tint_array_wrapper(A(1,2))`
+    ctx.ReplaceAll([&](const ast::CallExpression* expr) -> const ast::Expression* {
+        if (auto* call = sem.Get(expr)) {
+            if (auto* ctor = call->Target()->As<sem::TypeConstructor>()) {
+                if (auto* array = ctor->ReturnType()->As<sem::Array>()) {
+                    if (auto w = wrapper(array)) {
+                        // Wrap the array type constructor with another constructor for
+                        // the wrapper
+                        auto* wrapped_array_ty = ctx.dst->ty.type_name(w.wrapper_name);
+                        auto* array_ty = w.array_type(ctx);
+                        auto args = utils::Transform(call->Arguments(),
+                                                     [&](const tint::sem::Expression* s) {
+                                                         return ctx.Clone(s->Declaration());
+                                                     });
+                        auto* arr_ctor = ctx.dst->Construct(array_ty, args);
+                        return ctx.dst->Construct(wrapped_array_ty, arr_ctor);
+                    }
+                }
+            }
+        }
+        return nullptr;
+    });
+
+    ctx.Clone();
 }
 
 WrapArraysInStructs::WrappedArrayInfo WrapArraysInStructs::WrapArray(
     CloneContext& ctx,
     std::unordered_map<const sem::Array*, WrappedArrayInfo>& wrapped_arrays,
     const sem::Array* array) const {
-  if (array->IsRuntimeSized()) {
-    return {};  // We don't want to wrap runtime sized arrays
-  }
+    if (array->IsRuntimeSized()) {
+        return {};  // We don't want to wrap runtime sized arrays
+    }
 
-  return utils::GetOrCreate(wrapped_arrays, array, [&] {
-    WrappedArrayInfo info;
+    return utils::GetOrCreate(wrapped_arrays, array, [&] {
+        WrappedArrayInfo info;
 
-    // Generate a unique name for the array wrapper
-    info.wrapper_name = ctx.dst->Symbols().New("tint_array_wrapper");
+        // Generate a unique name for the array wrapper
+        info.wrapper_name = ctx.dst->Symbols().New("tint_array_wrapper");
 
-    // Examine the element type. Is it also an array?
-    std::function<const ast::Type*(CloneContext&)> el_type;
-    if (auto* el_array = array->ElemType()->As<sem::Array>()) {
-      // Array of array - call WrapArray() on the element type
-      if (auto el = WrapArray(ctx, wrapped_arrays, el_array)) {
-        el_type = [=](CloneContext& c) {
-          return c.dst->create<ast::TypeName>(el.wrapper_name);
+        // Examine the element type. Is it also an array?
+        std::function<const ast::Type*(CloneContext&)> el_type;
+        if (auto* el_array = array->ElemType()->As<sem::Array>()) {
+            // Array of array - call WrapArray() on the element type
+            if (auto el = WrapArray(ctx, wrapped_arrays, el_array)) {
+                el_type = [=](CloneContext& c) {
+                    return c.dst->create<ast::TypeName>(el.wrapper_name);
+                };
+            }
+        }
+
+        // If the element wasn't an array, just create the typical AST type for it
+        if (!el_type) {
+            el_type = [=](CloneContext& c) { return CreateASTTypeFor(c, array->ElemType()); };
+        }
+
+        // Construct the single structure field type
+        info.array_type = [=](CloneContext& c) {
+            ast::AttributeList attrs;
+            if (!array->IsStrideImplicit()) {
+                attrs.emplace_back(c.dst->create<ast::StrideAttribute>(array->Stride()));
+            }
+            return c.dst->ty.array(el_type(c), u32(array->Count()), std::move(attrs));
         };
-      }
-    }
 
-    // If the element wasn't an array, just create the typical AST type for it
-    if (!el_type) {
-      el_type = [=](CloneContext& c) {
-        return CreateASTTypeFor(c, array->ElemType());
-      };
-    }
-
-    // Construct the single structure field type
-    info.array_type = [=](CloneContext& c) {
-      ast::AttributeList attrs;
-      if (!array->IsStrideImplicit()) {
-        attrs.emplace_back(
-            c.dst->create<ast::StrideAttribute>(array->Stride()));
-      }
-      return c.dst->ty.array(el_type(c), array->Count(), std::move(attrs));
-    };
-
-    // Structure() will create and append the ast::Struct to the
-    // global declarations of `ctx.dst`. As we haven't finished building the
-    // current module-scope statement or function, this will be placed
-    // immediately before the usage.
-    ctx.dst->Structure(info.wrapper_name,
-                       {ctx.dst->Member("arr", info.array_type(ctx))});
-    return info;
-  });
+        // Structure() will create and append the ast::Struct to the
+        // global declarations of `ctx.dst`. As we haven't finished building the
+        // current module-scope statement or function, this will be placed
+        // immediately before the usage.
+        ctx.dst->Structure(info.wrapper_name, {ctx.dst->Member("arr", info.array_type(ctx))});
+        return info;
+    });
 }
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/wrap_arrays_in_structs.h b/src/tint/transform/wrap_arrays_in_structs.h
index a256ff8..4653c6b 100644
--- a/src/tint/transform/wrap_arrays_in_structs.h
+++ b/src/tint/transform/wrap_arrays_in_structs.h
@@ -34,56 +34,53 @@
 /// This transform helps with backends that cannot directly return arrays or use
 /// them as parameters.
 class WrapArraysInStructs : public Castable<WrapArraysInStructs, Transform> {
- public:
-  /// Constructor
-  WrapArraysInStructs();
+  public:
+    /// Constructor
+    WrapArraysInStructs();
 
-  /// Destructor
-  ~WrapArraysInStructs() override;
+    /// Destructor
+    ~WrapArraysInStructs() override;
 
-  /// @param program the program to inspect
-  /// @param data optional extra transform-specific input data
-  /// @returns true if this transform should be run for the given program
-  bool ShouldRun(const Program* program,
-                 const DataMap& data = {}) const override;
+    /// @param program the program to inspect
+    /// @param data optional extra transform-specific input data
+    /// @returns true if this transform should be run for the given program
+    bool ShouldRun(const Program* program, const DataMap& data = {}) const override;
 
- protected:
-  /// Runs the transform using the CloneContext built for transforming a
-  /// program. Run() is responsible for calling Clone() on the CloneContext.
-  /// @param ctx the CloneContext primed with the input program and
-  /// ProgramBuilder
-  /// @param inputs optional extra transform-specific input data
-  /// @param outputs optional extra transform-specific output data
-  void Run(CloneContext& ctx,
-           const DataMap& inputs,
-           DataMap& outputs) const override;
+  protected:
+    /// Runs the transform using the CloneContext built for transforming a
+    /// program. Run() is responsible for calling Clone() on the CloneContext.
+    /// @param ctx the CloneContext primed with the input program and
+    /// ProgramBuilder
+    /// @param inputs optional extra transform-specific input data
+    /// @param outputs optional extra transform-specific output data
+    void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const override;
 
- private:
-  struct WrappedArrayInfo {
-    WrappedArrayInfo();
-    WrappedArrayInfo(const WrappedArrayInfo&);
-    ~WrappedArrayInfo();
+  private:
+    struct WrappedArrayInfo {
+        WrappedArrayInfo();
+        WrappedArrayInfo(const WrappedArrayInfo&);
+        ~WrappedArrayInfo();
 
-    Symbol wrapper_name;
-    std::function<const ast::Type*(CloneContext&)> array_type;
+        Symbol wrapper_name;
+        std::function<const ast::Type*(CloneContext&)> array_type;
 
-    operator bool() { return wrapper_name.IsValid(); }
-  };
+        operator bool() { return wrapper_name.IsValid(); }
+    };
 
-  /// WrapArray wraps the fixed-size array type in a new structure (if it hasn't
-  /// already been wrapped). WrapArray will recursively wrap arrays-of-arrays.
-  /// The new structure will be added to module-scope type declarations of
-  /// `ctx.dst`.
-  /// @param ctx the CloneContext
-  /// @param wrapped_arrays a map of src array type to the wrapped structure
-  /// name
-  /// @param array the array type
-  /// @return the name of the structure that wraps the array, or an invalid
-  /// Symbol if this array should not be wrapped
-  WrappedArrayInfo WrapArray(
-      CloneContext& ctx,
-      std::unordered_map<const sem::Array*, WrappedArrayInfo>& wrapped_arrays,
-      const sem::Array* array) const;
+    /// WrapArray wraps the fixed-size array type in a new structure (if it hasn't
+    /// already been wrapped). WrapArray will recursively wrap arrays-of-arrays.
+    /// The new structure will be added to module-scope type declarations of
+    /// `ctx.dst`.
+    /// @param ctx the CloneContext
+    /// @param wrapped_arrays a map of src array type to the wrapped structure
+    /// name
+    /// @param array the array type
+    /// @return the name of the structure that wraps the array, or an invalid
+    /// Symbol if this array should not be wrapped
+    WrappedArrayInfo WrapArray(
+        CloneContext& ctx,
+        std::unordered_map<const sem::Array*, WrappedArrayInfo>& wrapped_arrays,
+        const sem::Array* array) const;
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/wrap_arrays_in_structs_test.cc b/src/tint/transform/wrap_arrays_in_structs_test.cc
index 7ba884c..7a7a6b3 100644
--- a/src/tint/transform/wrap_arrays_in_structs_test.cc
+++ b/src/tint/transform/wrap_arrays_in_structs_test.cc
@@ -25,33 +25,33 @@
 using WrapArraysInStructsTest = TransformTest;
 
 TEST_F(WrapArraysInStructsTest, ShouldRunEmptyModule) {
-  auto* src = R"()";
+    auto* src = R"()";
 
-  EXPECT_FALSE(ShouldRun<WrapArraysInStructs>(src));
+    EXPECT_FALSE(ShouldRun<WrapArraysInStructs>(src));
 }
 
 TEST_F(WrapArraysInStructsTest, ShouldRunHasArray) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> arr : array<i32, 4>;
 )";
 
-  EXPECT_TRUE(ShouldRun<WrapArraysInStructs>(src));
+    EXPECT_TRUE(ShouldRun<WrapArraysInStructs>(src));
 }
 
 TEST_F(WrapArraysInStructsTest, EmptyModule) {
-  auto* src = R"()";
-  auto* expect = src;
+    auto* src = R"()";
+    auto* expect = src;
 
-  auto got = Run<WrapArraysInStructs>(src);
+    auto got = Run<WrapArraysInStructs>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(WrapArraysInStructsTest, ArrayAsGlobal) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> arr : array<i32, 4>;
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_array_wrapper {
   arr : array<i32, 4u>,
 }
@@ -59,19 +59,19 @@
 var<private> arr : tint_array_wrapper;
 )";
 
-  auto got = Run<WrapArraysInStructs>(src);
+    auto got = Run<WrapArraysInStructs>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(WrapArraysInStructsTest, ArrayAsFunctionVar) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var arr : array<i32, 4>;
   let x = arr[3];
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_array_wrapper {
   arr : array<i32, 4u>,
 }
@@ -82,18 +82,18 @@
 }
 )";
 
-  auto got = Run<WrapArraysInStructs>(src);
+    auto got = Run<WrapArraysInStructs>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(WrapArraysInStructsTest, ArrayAsParam) {
-  auto* src = R"(
+    auto* src = R"(
 fn f(a : array<i32, 4>) -> i32 {
   return a[2];
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_array_wrapper {
   arr : array<i32, 4u>,
 }
@@ -103,18 +103,18 @@
 }
 )";
 
-  auto got = Run<WrapArraysInStructs>(src);
+    auto got = Run<WrapArraysInStructs>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(WrapArraysInStructsTest, ArrayAsReturn) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() -> array<i32, 4> {
   return array<i32, 4>(1, 2, 3, 4);
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_array_wrapper {
   arr : array<i32, 4u>,
 }
@@ -124,13 +124,13 @@
 }
 )";
 
-  auto got = Run<WrapArraysInStructs>(src);
+    auto got = Run<WrapArraysInStructs>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(WrapArraysInStructsTest, ArrayAlias) {
-  auto* src = R"(
+    auto* src = R"(
 type Inner = array<i32, 2>;
 type Array = array<Inner, 2>;
 
@@ -143,7 +143,7 @@
   let x = arr[3];
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_array_wrapper {
   arr : array<i32, 2u>,
 }
@@ -166,13 +166,13 @@
 }
 )";
 
-  auto got = Run<WrapArraysInStructs>(src);
+    auto got = Run<WrapArraysInStructs>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(WrapArraysInStructsTest, ArrayAlias_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn f() {
   var arr : Array;
   arr = Array();
@@ -185,7 +185,7 @@
 type Array = array<Inner, 2>;
 type Inner = array<i32, 2>;
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_array_wrapper_1 {
   arr : array<i32, 2u>,
 }
@@ -208,20 +208,20 @@
 type Inner = tint_array_wrapper_1;
 )";
 
-  auto got = Run<WrapArraysInStructs>(src);
+    auto got = Run<WrapArraysInStructs>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(WrapArraysInStructsTest, ArraysInStruct) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   a : array<i32, 4>,
   b : array<i32, 8>,
   c : array<i32, 4>,
 };
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_array_wrapper {
   arr : array<i32, 4u>,
 }
@@ -237,20 +237,20 @@
 }
 )";
 
-  auto got = Run<WrapArraysInStructs>(src);
+    auto got = Run<WrapArraysInStructs>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(WrapArraysInStructsTest, ArraysOfArraysInStruct) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   a : array<i32, 4>,
   b : array<array<i32, 4>, 4>,
   c : array<array<array<i32, 4>, 4>, 4>,
 };
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_array_wrapper {
   arr : array<i32, 4u>,
 }
@@ -270,13 +270,13 @@
 }
 )";
 
-  auto got = Run<WrapArraysInStructs>(src);
+    auto got = Run<WrapArraysInStructs>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(WrapArraysInStructsTest, AccessArraysOfArraysInStruct) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   a : array<i32, 4>,
   b : array<array<i32, 4>, 4>,
@@ -287,7 +287,7 @@
   return s.a[2] + s.b[1][2] + s.c[3][1][2];
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_array_wrapper {
   arr : array<i32, 4u>,
 }
@@ -311,13 +311,13 @@
 }
 )";
 
-  auto got = Run<WrapArraysInStructs>(src);
+    auto got = Run<WrapArraysInStructs>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(WrapArraysInStructsTest, DeclarationOrder) {
-  auto* src = R"(
+    auto* src = R"(
 type T0 = i32;
 
 type T1 = array<i32, 1>;
@@ -333,7 +333,7 @@
   var v : array<i32, 3>;
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 type T0 = i32;
 
 struct tint_array_wrapper {
@@ -362,13 +362,13 @@
 }
 )";
 
-  auto got = Run<WrapArraysInStructs>(src);
+    auto got = Run<WrapArraysInStructs>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(WrapArraysInStructsTest, DeclarationOrder_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 fn f2() {
   var v : array<i32, 3>;
 }
@@ -384,7 +384,7 @@
 
 type T0 = i32;
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 struct tint_array_wrapper {
   arr : array<i32, 3u>,
 }
@@ -413,9 +413,9 @@
 type T0 = i32;
 )";
 
-  auto got = Run<WrapArraysInStructs>(src);
+    auto got = Run<WrapArraysInStructs>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 }  // namespace
diff --git a/src/tint/transform/zero_init_workgroup_memory.cc b/src/tint/transform/zero_init_workgroup_memory.cc
index 8441e17..21a4565 100644
--- a/src/tint/transform/zero_init_workgroup_memory.cc
+++ b/src/tint/transform/zero_init_workgroup_memory.cc
@@ -22,7 +22,7 @@
 
 #include "src/tint/ast/workgroup_attribute.h"
 #include "src/tint/program_builder.h"
-#include "src/tint/sem/atomic_type.h"
+#include "src/tint/sem/atomic.h"
 #include "src/tint/sem/function.h"
 #include "src/tint/sem/variable.h"
 #include "src/tint/utils/map.h"
@@ -34,426 +34,410 @@
 
 /// PIMPL state for the ZeroInitWorkgroupMemory transform
 struct ZeroInitWorkgroupMemory::State {
-  /// The clone context
-  CloneContext& ctx;
+    /// The clone context
+    CloneContext& ctx;
 
-  /// An alias to *ctx.dst
-  ProgramBuilder& b = *ctx.dst;
+    /// An alias to *ctx.dst
+    ProgramBuilder& b = *ctx.dst;
 
-  /// The constant size of the workgroup. If 0, then #workgroup_size_expr should
-  /// be used instead.
-  uint32_t workgroup_size_const = 0;
-  /// The size of the workgroup as an expression generator. Use if
-  /// #workgroup_size_const is 0.
-  std::function<const ast::Expression*()> workgroup_size_expr;
+    /// The constant size of the workgroup. If 0, then #workgroup_size_expr should
+    /// be used instead.
+    uint32_t workgroup_size_const = 0;
+    /// The size of the workgroup as an expression generator. Use if
+    /// #workgroup_size_const is 0.
+    std::function<const ast::Expression*()> workgroup_size_expr;
 
-  /// ArrayIndex represents a function on the local invocation index, of
-  /// the form: `array_index = (local_invocation_index % modulo) / division`
-  struct ArrayIndex {
-    /// The RHS of the modulus part of the expression
-    uint32_t modulo = 1;
-    /// The RHS of the division part of the expression
-    uint32_t division = 1;
+    /// ArrayIndex represents a function on the local invocation index, of
+    /// the form: `array_index = (local_invocation_index % modulo) / division`
+    struct ArrayIndex {
+        /// The RHS of the modulus part of the expression
+        uint32_t modulo = 1;
+        /// The RHS of the division part of the expression
+        uint32_t division = 1;
 
-    /// Equality operator
-    /// @param i the ArrayIndex to compare to this ArrayIndex
-    /// @returns true if `i` and this ArrayIndex are equal
-    bool operator==(const ArrayIndex& i) const {
-      return modulo == i.modulo && division == i.division;
-    }
-
-    /// Hash function for the ArrayIndex type
-    struct Hasher {
-      /// @param i the ArrayIndex to calculate a hash for
-      /// @returns the hash value for the ArrayIndex `i`
-      size_t operator()(const ArrayIndex& i) const {
-        return utils::Hash(i.modulo, i.division);
-      }
-    };
-  };
-
-  /// A list of unique ArrayIndex
-  using ArrayIndices = utils::UniqueVector<ArrayIndex, ArrayIndex::Hasher>;
-
-  /// Expression holds information about an expression that is being built for a
-  /// statement will zero workgroup values.
-  struct Expression {
-    /// The AST expression node
-    const ast::Expression* expr = nullptr;
-    /// The number of iterations required to zero the value
-    uint32_t num_iterations = 0;
-    /// All array indices used by this expression
-    ArrayIndices array_indices;
-  };
-
-  /// Statement holds information about a statement that will zero workgroup
-  /// values.
-  struct Statement {
-    /// The AST statement node
-    const ast::Statement* stmt;
-    /// The number of iterations required to zero the value
-    uint32_t num_iterations;
-    /// All array indices used by this statement
-    ArrayIndices array_indices;
-  };
-
-  /// All statements that zero workgroup memory
-  std::vector<Statement> statements;
-
-  /// A map of ArrayIndex to the name reserved for the `let` declaration of that
-  /// index.
-  std::unordered_map<ArrayIndex, Symbol, ArrayIndex::Hasher> array_index_names;
-
-  /// Constructor
-  /// @param c the CloneContext used for the transform
-  explicit State(CloneContext& c) : ctx(c) {}
-
-  /// Run inserts the workgroup memory zero-initialization logic at the top of
-  /// the given function
-  /// @param fn a compute shader entry point function
-  void Run(const ast::Function* fn) {
-    auto& sem = ctx.src->Sem();
-
-    CalculateWorkgroupSize(
-        ast::GetAttribute<ast::WorkgroupAttribute>(fn->attributes));
-
-    // Generate a list of statements to zero initialize each of the
-    // workgroup storage variables used by `fn`. This will populate #statements.
-    auto* func = sem.Get(fn);
-    for (auto* var : func->TransitivelyReferencedGlobals()) {
-      if (var->StorageClass() == ast::StorageClass::kWorkgroup) {
-        BuildZeroingStatements(
-            var->Type()->UnwrapRef(), [&](uint32_t num_values) {
-              auto var_name = ctx.Clone(var->Declaration()->symbol);
-              return Expression{b.Expr(var_name), num_values, ArrayIndices{}};
-            });
-      }
-    }
-
-    if (statements.empty()) {
-      return;  // No workgroup variables to initialize.
-    }
-
-    // Scan the entry point for an existing local_invocation_index builtin
-    // parameter
-    std::function<const ast::Expression*()> local_index;
-    for (auto* param : fn->params) {
-      if (auto* builtin =
-              ast::GetAttribute<ast::BuiltinAttribute>(param->attributes)) {
-        if (builtin->builtin == ast::Builtin::kLocalInvocationIndex) {
-          local_index = [=] { return b.Expr(ctx.Clone(param->symbol)); };
-          break;
+        /// Equality operator
+        /// @param i the ArrayIndex to compare to this ArrayIndex
+        /// @returns true if `i` and this ArrayIndex are equal
+        bool operator==(const ArrayIndex& i) const {
+            return modulo == i.modulo && division == i.division;
         }
-      }
 
-      if (auto* str = sem.Get(param)->Type()->As<sem::Struct>()) {
-        for (auto* member : str->Members()) {
-          if (auto* builtin = ast::GetAttribute<ast::BuiltinAttribute>(
-                  member->Declaration()->attributes)) {
-            if (builtin->builtin == ast::Builtin::kLocalInvocationIndex) {
-              local_index = [=] {
-                auto* param_expr = b.Expr(ctx.Clone(param->symbol));
-                auto member_name = ctx.Clone(member->Declaration()->symbol);
-                return b.MemberAccessor(param_expr, member_name);
-              };
-              break;
+        /// Hash function for the ArrayIndex type
+        struct Hasher {
+            /// @param i the ArrayIndex to calculate a hash for
+            /// @returns the hash value for the ArrayIndex `i`
+            size_t operator()(const ArrayIndex& i) const {
+                return utils::Hash(i.modulo, i.division);
             }
-          }
-        }
-      }
-    }
-    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)});
-      ctx.InsertBack(fn->params, param);
-      local_index = [=] { return b.Expr(param->symbol); };
-    }
-
-    // Take the zeroing statements and bin them by the number of iterations
-    // required to zero the workgroup data. We then emit these in blocks,
-    // possibly wrapped in if-statements or for-loops.
-    std::unordered_map<uint32_t, std::vector<Statement>>
-        stmts_by_num_iterations;
-    std::vector<uint32_t> num_sorted_iterations;
-    for (auto& s : statements) {
-      auto& stmts = stmts_by_num_iterations[s.num_iterations];
-      if (stmts.empty()) {
-        num_sorted_iterations.emplace_back(s.num_iterations);
-      }
-      stmts.emplace_back(s);
-    }
-    std::sort(num_sorted_iterations.begin(), num_sorted_iterations.end());
-
-    // Loop over the statements, grouped by num_iterations.
-    for (auto num_iterations : num_sorted_iterations) {
-      auto& stmts = stmts_by_num_iterations[num_iterations];
-
-      // Gather all the array indices used by all the statements in the block.
-      ArrayIndices array_indices;
-      for (auto& s : stmts) {
-        for (auto& idx : s.array_indices) {
-          array_indices.add(idx);
-        }
-      }
-
-      // Determine the block type used to emit these statements.
-
-      if (workgroup_size_const == 0 || num_iterations > workgroup_size_const) {
-        // Either the workgroup size is dynamic, or smaller than num_iterations.
-        // In either case, we need to generate a for loop to ensure we
-        // initialize all the array elements.
-        //
-        //  for (var idx : u32 = local_index;
-        //           idx < num_iterations;
-        //           idx += workgroup_size) {
-        //    ...
-        //  }
-        auto idx = b.Symbols().New("idx");
-        auto* init = b.Decl(b.Var(idx, b.ty.u32(), local_index()));
-        auto* cond = b.create<ast::BinaryExpression>(
-            ast::BinaryOp::kLessThan, b.Expr(idx), b.Expr(num_iterations));
-        auto* cont = b.Assign(
-            idx, b.Add(idx, workgroup_size_const ? b.Expr(workgroup_size_const)
-                                                 : workgroup_size_expr()));
-
-        auto block = DeclareArrayIndices(num_iterations, array_indices,
-                                         [&] { return b.Expr(idx); });
-        for (auto& s : stmts) {
-          block.emplace_back(s.stmt);
-        }
-        auto* for_loop = b.For(init, cond, cont, b.Block(block));
-        ctx.InsertFront(fn->body->statements, for_loop);
-      } else if (num_iterations < workgroup_size_const) {
-        // Workgroup size is a known constant, but is greater than
-        // num_iterations. Emit an if statement:
-        //
-        //  if (local_index < num_iterations) {
-        //    ...
-        //  }
-        auto* cond = b.create<ast::BinaryExpression>(
-            ast::BinaryOp::kLessThan, local_index(), b.Expr(num_iterations));
-        auto block = DeclareArrayIndices(num_iterations, array_indices,
-                                         [&] { return b.Expr(local_index()); });
-        for (auto& s : stmts) {
-          block.emplace_back(s.stmt);
-        }
-        auto* if_stmt = b.If(cond, b.Block(block));
-        ctx.InsertFront(fn->body->statements, if_stmt);
-      } else {
-        // Workgroup size exactly equals num_iterations.
-        // No need for any conditionals. Just emit a basic block:
-        //
-        // {
-        //    ...
-        // }
-        auto block = DeclareArrayIndices(num_iterations, array_indices,
-                                         [&] { return b.Expr(local_index()); });
-        for (auto& s : stmts) {
-          block.emplace_back(s.stmt);
-        }
-        ctx.InsertFront(fn->body->statements, b.Block(block));
-      }
-    }
-
-    // Append a single workgroup barrier after the zero initialization.
-    ctx.InsertFront(fn->body->statements,
-                    b.CallStmt(b.Call("workgroupBarrier")));
-  }
-
-  /// BuildZeroingExpr is a function that builds a sub-expression used to zero
-  /// workgroup values. `num_values` is the number of elements that the
-  /// expression will be used to zero. Returns the expression.
-  using BuildZeroingExpr = std::function<Expression(uint32_t num_values)>;
-
-  /// BuildZeroingStatements() generates the statements required to zero
-  /// initialize the workgroup storage expression of type `ty`.
-  /// @param ty the expression type
-  /// @param get_expr a function that builds the AST nodes for the expression.
-  void BuildZeroingStatements(const sem::Type* ty,
-                              const BuildZeroingExpr& get_expr) {
-    if (CanTriviallyZero(ty)) {
-      auto var = get_expr(1u);
-      auto* zero_init = b.Construct(CreateASTTypeFor(ctx, ty));
-      statements.emplace_back(Statement{b.Assign(var.expr, zero_init),
-                                        var.num_iterations, var.array_indices});
-      return;
-    }
-
-    if (auto* atomic = ty->As<sem::Atomic>()) {
-      auto* zero_init = b.Construct(CreateASTTypeFor(ctx, atomic->Type()));
-      auto expr = get_expr(1u);
-      auto* store = b.Call("atomicStore", b.AddressOf(expr.expr), zero_init);
-      statements.emplace_back(Statement{b.CallStmt(store), expr.num_iterations,
-                                        expr.array_indices});
-      return;
-    }
-
-    if (auto* str = ty->As<sem::Struct>()) {
-      for (auto* member : str->Members()) {
-        auto name = ctx.Clone(member->Declaration()->symbol);
-        BuildZeroingStatements(member->Type(), [&](uint32_t num_values) {
-          auto s = get_expr(num_values);
-          return Expression{b.MemberAccessor(s.expr, name), s.num_iterations,
-                            s.array_indices};
-        });
-      }
-      return;
-    }
-
-    if (auto* arr = ty->As<sem::Array>()) {
-      BuildZeroingStatements(arr->ElemType(), [&](uint32_t num_values) {
-        // num_values is the number of values to zero for the element type.
-        // The number of iterations required to zero the array and its elements
-        // is:
-        //      `num_values * arr->Count()`
-        // The index for this array is:
-        //      `(idx % modulo) / division`
-        auto modulo = num_values * arr->Count();
-        auto division = num_values;
-        auto a = get_expr(modulo);
-        auto array_indices = a.array_indices;
-        array_indices.add(ArrayIndex{modulo, division});
-        auto index =
-            utils::GetOrCreate(array_index_names, ArrayIndex{modulo, division},
-                               [&] { return b.Symbols().New("i"); });
-        return Expression{b.IndexAccessor(a.expr, index), a.num_iterations,
-                          array_indices};
-      });
-      return;
-    }
-
-    TINT_UNREACHABLE(Transform, b.Diagnostics())
-        << "could not zero workgroup type: "
-        << ty->FriendlyName(ctx.src->Symbols());
-  }
-
-  /// DeclareArrayIndices returns a list of statements that contain the `let`
-  /// declarations for all of the ArrayIndices.
-  /// @param num_iterations the number of iterations for the block
-  /// @param array_indices the list of array indices to generate `let`
-  ///        declarations for
-  /// @param iteration a function that returns the index of the current
-  ///         iteration.
-  /// @returns the list of `let` statements that declare the array indices
-  ast::StatementList DeclareArrayIndices(
-      uint32_t num_iterations,
-      const ArrayIndices& array_indices,
-      const std::function<const ast::Expression*()>& iteration) {
-    ast::StatementList stmts;
-    std::map<Symbol, ArrayIndex> indices_by_name;
-    for (auto index : array_indices) {
-      auto name = array_index_names.at(index);
-      auto* mod =
-          (num_iterations > index.modulo)
-              ? b.create<ast::BinaryExpression>(
-                    ast::BinaryOp::kModulo, iteration(), b.Expr(index.modulo))
-              : iteration();
-      auto* div = (index.division != 1u) ? b.Div(mod, index.division) : mod;
-      auto* decl = b.Decl(b.Const(name, b.ty.u32(), div));
-      stmts.emplace_back(decl);
-    }
-    return stmts;
-  }
-
-  /// CalculateWorkgroupSize initializes the members #workgroup_size_const and
-  /// #workgroup_size_expr with the linear workgroup size.
-  /// @param attr the workgroup attribute applied to the entry point function
-  void CalculateWorkgroupSize(const ast::WorkgroupAttribute* attr) {
-    bool is_signed = false;
-    workgroup_size_const = 1u;
-    workgroup_size_expr = nullptr;
-    for (auto* expr : attr->Values()) {
-      if (!expr) {
-        continue;
-      }
-      auto* sem = ctx.src->Sem().Get(expr);
-      if (auto c = sem->ConstantValue()) {
-        if (c.ElementType()->Is<sem::I32>()) {
-          workgroup_size_const *= static_cast<uint32_t>(c.Elements()[0].i32);
-          continue;
-        } else if (c.ElementType()->Is<sem::U32>()) {
-          workgroup_size_const *= c.Elements()[0].u32;
-          continue;
-        }
-      }
-      // Constant value could not be found. Build expression instead.
-      workgroup_size_expr = [this, expr, size = workgroup_size_expr] {
-        auto* e = ctx.Clone(expr);
-        if (ctx.src->TypeOf(expr)->UnwrapRef()->Is<sem::I32>()) {
-          e = b.Construct<ProgramBuilder::u32>(e);
-        }
-        return size ? b.Mul(size(), e) : e;
-      };
-    }
-    if (workgroup_size_expr) {
-      if (workgroup_size_const != 1) {
-        // Fold workgroup_size_const in to workgroup_size_expr
-        workgroup_size_expr = [this, is_signed,
-                               const_size = workgroup_size_const,
-                               expr_size = workgroup_size_expr] {
-          return is_signed
-                     ? b.Mul(expr_size(), static_cast<int32_t>(const_size))
-                     : b.Mul(expr_size(), const_size);
         };
-      }
-      // Indicate that workgroup_size_expr should be used instead of the
-      // constant.
-      workgroup_size_const = 0;
-    }
-  }
+    };
 
-  /// @returns true if a variable with store type `ty` can be efficiently zeroed
-  /// by assignment of a type constructor without operands. If
-  /// CanTriviallyZero() returns false, then the type needs to be
-  /// initialized by decomposing the initialization into multiple
-  /// sub-initializations.
-  /// @param ty the type to inspect
-  bool CanTriviallyZero(const sem::Type* ty) {
-    if (ty->Is<sem::Atomic>()) {
-      return false;
-    }
-    if (auto* str = ty->As<sem::Struct>()) {
-      for (auto* member : str->Members()) {
-        if (!CanTriviallyZero(member->Type())) {
-          return false;
+    /// A list of unique ArrayIndex
+    using ArrayIndices = utils::UniqueVector<ArrayIndex, ArrayIndex::Hasher>;
+
+    /// Expression holds information about an expression that is being built for a
+    /// statement will zero workgroup values.
+    struct Expression {
+        /// The AST expression node
+        const ast::Expression* expr = nullptr;
+        /// The number of iterations required to zero the value
+        uint32_t num_iterations = 0;
+        /// All array indices used by this expression
+        ArrayIndices array_indices;
+    };
+
+    /// Statement holds information about a statement that will zero workgroup
+    /// values.
+    struct Statement {
+        /// The AST statement node
+        const ast::Statement* stmt;
+        /// The number of iterations required to zero the value
+        uint32_t num_iterations;
+        /// All array indices used by this statement
+        ArrayIndices array_indices;
+    };
+
+    /// All statements that zero workgroup memory
+    std::vector<Statement> statements;
+
+    /// A map of ArrayIndex to the name reserved for the `let` declaration of that
+    /// index.
+    std::unordered_map<ArrayIndex, Symbol, ArrayIndex::Hasher> array_index_names;
+
+    /// Constructor
+    /// @param c the CloneContext used for the transform
+    explicit State(CloneContext& c) : ctx(c) {}
+
+    /// Run inserts the workgroup memory zero-initialization logic at the top of
+    /// the given function
+    /// @param fn a compute shader entry point function
+    void Run(const ast::Function* fn) {
+        auto& sem = ctx.src->Sem();
+
+        CalculateWorkgroupSize(ast::GetAttribute<ast::WorkgroupAttribute>(fn->attributes));
+
+        // Generate a list of statements to zero initialize each of the
+        // workgroup storage variables used by `fn`. This will populate #statements.
+        auto* func = sem.Get(fn);
+        for (auto* var : func->TransitivelyReferencedGlobals()) {
+            if (var->StorageClass() == ast::StorageClass::kWorkgroup) {
+                BuildZeroingStatements(var->Type()->UnwrapRef(), [&](uint32_t num_values) {
+                    auto var_name = ctx.Clone(var->Declaration()->symbol);
+                    return Expression{b.Expr(var_name), num_values, ArrayIndices{}};
+                });
+            }
         }
-      }
+
+        if (statements.empty()) {
+            return;  // No workgroup variables to initialize.
+        }
+
+        // Scan the entry point for an existing local_invocation_index builtin
+        // parameter
+        std::function<const ast::Expression*()> local_index;
+        for (auto* param : fn->params) {
+            if (auto* builtin = ast::GetAttribute<ast::BuiltinAttribute>(param->attributes)) {
+                if (builtin->builtin == ast::Builtin::kLocalInvocationIndex) {
+                    local_index = [=] { return b.Expr(ctx.Clone(param->symbol)); };
+                    break;
+                }
+            }
+
+            if (auto* str = sem.Get(param)->Type()->As<sem::Struct>()) {
+                for (auto* member : str->Members()) {
+                    if (auto* builtin = ast::GetAttribute<ast::BuiltinAttribute>(
+                            member->Declaration()->attributes)) {
+                        if (builtin->builtin == ast::Builtin::kLocalInvocationIndex) {
+                            local_index = [=] {
+                                auto* param_expr = b.Expr(ctx.Clone(param->symbol));
+                                auto member_name = ctx.Clone(member->Declaration()->symbol);
+                                return b.MemberAccessor(param_expr, member_name);
+                            };
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+        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)});
+            ctx.InsertBack(fn->params, param);
+            local_index = [=] { return b.Expr(param->symbol); };
+        }
+
+        // Take the zeroing statements and bin them by the number of iterations
+        // required to zero the workgroup data. We then emit these in blocks,
+        // possibly wrapped in if-statements or for-loops.
+        std::unordered_map<uint32_t, std::vector<Statement>> stmts_by_num_iterations;
+        std::vector<uint32_t> num_sorted_iterations;
+        for (auto& s : statements) {
+            auto& stmts = stmts_by_num_iterations[s.num_iterations];
+            if (stmts.empty()) {
+                num_sorted_iterations.emplace_back(s.num_iterations);
+            }
+            stmts.emplace_back(s);
+        }
+        std::sort(num_sorted_iterations.begin(), num_sorted_iterations.end());
+
+        // Loop over the statements, grouped by num_iterations.
+        for (auto num_iterations : num_sorted_iterations) {
+            auto& stmts = stmts_by_num_iterations[num_iterations];
+
+            // Gather all the array indices used by all the statements in the block.
+            ArrayIndices array_indices;
+            for (auto& s : stmts) {
+                for (auto& idx : s.array_indices) {
+                    array_indices.add(idx);
+                }
+            }
+
+            // Determine the block type used to emit these statements.
+
+            if (workgroup_size_const == 0 || num_iterations > workgroup_size_const) {
+                // Either the workgroup size is dynamic, or smaller than num_iterations.
+                // In either case, we need to generate a for loop to ensure we
+                // initialize all the array elements.
+                //
+                //  for (var idx : u32 = local_index;
+                //           idx < num_iterations;
+                //           idx += workgroup_size) {
+                //    ...
+                //  }
+                auto idx = b.Symbols().New("idx");
+                auto* init = b.Decl(b.Var(idx, b.ty.u32(), local_index()));
+                auto* cond = b.create<ast::BinaryExpression>(ast::BinaryOp::kLessThan, b.Expr(idx),
+                                                             b.Expr(u32(num_iterations)));
+                auto* cont = b.Assign(
+                    idx, b.Add(idx, workgroup_size_const ? b.Expr(u32(workgroup_size_const))
+                                                         : workgroup_size_expr()));
+
+                auto block =
+                    DeclareArrayIndices(num_iterations, array_indices, [&] { return b.Expr(idx); });
+                for (auto& s : stmts) {
+                    block.emplace_back(s.stmt);
+                }
+                auto* for_loop = b.For(init, cond, cont, b.Block(block));
+                ctx.InsertFront(fn->body->statements, for_loop);
+            } else if (num_iterations < workgroup_size_const) {
+                // Workgroup size is a known constant, but is greater than
+                // num_iterations. Emit an if statement:
+                //
+                //  if (local_index < num_iterations) {
+                //    ...
+                //  }
+                auto* cond = b.create<ast::BinaryExpression>(
+                    ast::BinaryOp::kLessThan, local_index(), b.Expr(u32(num_iterations)));
+                auto block = DeclareArrayIndices(num_iterations, array_indices,
+                                                 [&] { return b.Expr(local_index()); });
+                for (auto& s : stmts) {
+                    block.emplace_back(s.stmt);
+                }
+                auto* if_stmt = b.If(cond, b.Block(block));
+                ctx.InsertFront(fn->body->statements, if_stmt);
+            } else {
+                // Workgroup size exactly equals num_iterations.
+                // No need for any conditionals. Just emit a basic block:
+                //
+                // {
+                //    ...
+                // }
+                auto block = DeclareArrayIndices(num_iterations, array_indices,
+                                                 [&] { return b.Expr(local_index()); });
+                for (auto& s : stmts) {
+                    block.emplace_back(s.stmt);
+                }
+                ctx.InsertFront(fn->body->statements, b.Block(block));
+            }
+        }
+
+        // Append a single workgroup barrier after the zero initialization.
+        ctx.InsertFront(fn->body->statements, b.CallStmt(b.Call("workgroupBarrier")));
     }
-    if (ty->Is<sem::Array>()) {
-      return false;
+
+    /// BuildZeroingExpr is a function that builds a sub-expression used to zero
+    /// workgroup values. `num_values` is the number of elements that the
+    /// expression will be used to zero. Returns the expression.
+    using BuildZeroingExpr = std::function<Expression(uint32_t num_values)>;
+
+    /// BuildZeroingStatements() generates the statements required to zero
+    /// initialize the workgroup storage expression of type `ty`.
+    /// @param ty the expression type
+    /// @param get_expr a function that builds the AST nodes for the expression.
+    void BuildZeroingStatements(const sem::Type* ty, const BuildZeroingExpr& get_expr) {
+        if (CanTriviallyZero(ty)) {
+            auto var = get_expr(1u);
+            auto* zero_init = b.Construct(CreateASTTypeFor(ctx, ty));
+            statements.emplace_back(
+                Statement{b.Assign(var.expr, zero_init), var.num_iterations, var.array_indices});
+            return;
+        }
+
+        if (auto* atomic = ty->As<sem::Atomic>()) {
+            auto* zero_init = b.Construct(CreateASTTypeFor(ctx, atomic->Type()));
+            auto expr = get_expr(1u);
+            auto* store = b.Call("atomicStore", b.AddressOf(expr.expr), zero_init);
+            statements.emplace_back(
+                Statement{b.CallStmt(store), expr.num_iterations, expr.array_indices});
+            return;
+        }
+
+        if (auto* str = ty->As<sem::Struct>()) {
+            for (auto* member : str->Members()) {
+                auto name = ctx.Clone(member->Declaration()->symbol);
+                BuildZeroingStatements(member->Type(), [&](uint32_t num_values) {
+                    auto s = get_expr(num_values);
+                    return Expression{b.MemberAccessor(s.expr, name), s.num_iterations,
+                                      s.array_indices};
+                });
+            }
+            return;
+        }
+
+        if (auto* arr = ty->As<sem::Array>()) {
+            BuildZeroingStatements(arr->ElemType(), [&](uint32_t num_values) {
+                // num_values is the number of values to zero for the element type.
+                // The number of iterations required to zero the array and its elements
+                // is:
+                //      `num_values * arr->Count()`
+                // The index for this array is:
+                //      `(idx % modulo) / division`
+                auto modulo = num_values * arr->Count();
+                auto division = num_values;
+                auto a = get_expr(modulo);
+                auto array_indices = a.array_indices;
+                array_indices.add(ArrayIndex{modulo, division});
+                auto index = utils::GetOrCreate(array_index_names, ArrayIndex{modulo, division},
+                                                [&] { return b.Symbols().New("i"); });
+                return Expression{b.IndexAccessor(a.expr, index), a.num_iterations, array_indices};
+            });
+            return;
+        }
+
+        TINT_UNREACHABLE(Transform, b.Diagnostics())
+            << "could not zero workgroup type: " << ty->FriendlyName(ctx.src->Symbols());
     }
-    // True for all other storable types
-    return true;
-  }
+
+    /// DeclareArrayIndices returns a list of statements that contain the `let`
+    /// declarations for all of the ArrayIndices.
+    /// @param num_iterations the number of iterations for the block
+    /// @param array_indices the list of array indices to generate `let`
+    ///        declarations for
+    /// @param iteration a function that returns the index of the current
+    ///         iteration.
+    /// @returns the list of `let` statements that declare the array indices
+    ast::StatementList DeclareArrayIndices(
+        uint32_t num_iterations,
+        const ArrayIndices& array_indices,
+        const std::function<const ast::Expression*()>& iteration) {
+        ast::StatementList stmts;
+        std::map<Symbol, ArrayIndex> indices_by_name;
+        for (auto index : array_indices) {
+            auto name = array_index_names.at(index);
+            auto* mod = (num_iterations > index.modulo)
+                            ? b.create<ast::BinaryExpression>(ast::BinaryOp::kModulo, iteration(),
+                                                              b.Expr(u32(index.modulo)))
+                            : iteration();
+            auto* div = (index.division != 1u) ? b.Div(mod, u32(index.division)) : mod;
+            auto* decl = b.Decl(b.Let(name, b.ty.u32(), div));
+            stmts.emplace_back(decl);
+        }
+        return stmts;
+    }
+
+    /// CalculateWorkgroupSize initializes the members #workgroup_size_const and
+    /// #workgroup_size_expr with the linear workgroup size.
+    /// @param attr the workgroup attribute applied to the entry point function
+    void CalculateWorkgroupSize(const ast::WorkgroupAttribute* attr) {
+        bool is_signed = false;
+        workgroup_size_const = 1u;
+        workgroup_size_expr = nullptr;
+        for (auto* expr : attr->Values()) {
+            if (!expr) {
+                continue;
+            }
+            auto* sem = ctx.src->Sem().Get(expr);
+            if (auto c = sem->ConstantValue()) {
+                if (c.ElementType()->Is<sem::I32>()) {
+                    workgroup_size_const *= static_cast<uint32_t>(c.Elements()[0].i32);
+                    continue;
+                } else if (c.ElementType()->Is<sem::U32>()) {
+                    workgroup_size_const *= c.Elements()[0].u32;
+                    continue;
+                }
+            }
+            // Constant value could not be found. Build expression instead.
+            workgroup_size_expr = [this, expr, size = workgroup_size_expr] {
+                auto* e = ctx.Clone(expr);
+                if (ctx.src->TypeOf(expr)->UnwrapRef()->Is<sem::I32>()) {
+                    e = b.Construct<u32>(e);
+                }
+                return size ? b.Mul(size(), e) : e;
+            };
+        }
+        if (workgroup_size_expr) {
+            if (workgroup_size_const != 1) {
+                // Fold workgroup_size_const in to workgroup_size_expr
+                workgroup_size_expr = [this, is_signed, const_size = workgroup_size_const,
+                                       expr_size = workgroup_size_expr] {
+                    return is_signed ? b.Mul(expr_size(), i32(const_size))
+                                     : b.Mul(expr_size(), u32(const_size));
+                };
+            }
+            // Indicate that workgroup_size_expr should be used instead of the
+            // constant.
+            workgroup_size_const = 0;
+        }
+    }
+
+    /// @returns true if a variable with store type `ty` can be efficiently zeroed
+    /// by assignment of a type constructor without operands. If
+    /// CanTriviallyZero() returns false, then the type needs to be
+    /// initialized by decomposing the initialization into multiple
+    /// sub-initializations.
+    /// @param ty the type to inspect
+    bool CanTriviallyZero(const sem::Type* ty) {
+        if (ty->Is<sem::Atomic>()) {
+            return false;
+        }
+        if (auto* str = ty->As<sem::Struct>()) {
+            for (auto* member : str->Members()) {
+                if (!CanTriviallyZero(member->Type())) {
+                    return false;
+                }
+            }
+        }
+        if (ty->Is<sem::Array>()) {
+            return false;
+        }
+        // True for all other storable types
+        return true;
+    }
 };
 
 ZeroInitWorkgroupMemory::ZeroInitWorkgroupMemory() = default;
 
 ZeroInitWorkgroupMemory::~ZeroInitWorkgroupMemory() = default;
 
-bool ZeroInitWorkgroupMemory::ShouldRun(const Program* program,
-                                        const DataMap&) const {
-  for (auto* decl : program->AST().GlobalDeclarations()) {
-    if (auto* var = decl->As<ast::Variable>()) {
-      if (var->declared_storage_class == ast::StorageClass::kWorkgroup) {
-        return true;
-      }
+bool ZeroInitWorkgroupMemory::ShouldRun(const Program* program, const DataMap&) const {
+    for (auto* decl : program->AST().GlobalDeclarations()) {
+        if (auto* var = decl->As<ast::Variable>()) {
+            if (var->declared_storage_class == ast::StorageClass::kWorkgroup) {
+                return true;
+            }
+        }
     }
-  }
-  return false;
+    return false;
 }
 
-void ZeroInitWorkgroupMemory::Run(CloneContext& ctx,
-                                  const DataMap&,
-                                  DataMap&) const {
-  for (auto* fn : ctx.src->AST().Functions()) {
-    if (fn->PipelineStage() == ast::PipelineStage::kCompute) {
-      State{ctx}.Run(fn);
+void ZeroInitWorkgroupMemory::Run(CloneContext& ctx, const DataMap&, DataMap&) const {
+    for (auto* fn : ctx.src->AST().Functions()) {
+        if (fn->PipelineStage() == ast::PipelineStage::kCompute) {
+            State{ctx}.Run(fn);
+        }
     }
-  }
-  ctx.Clone();
+    ctx.Clone();
 }
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/zero_init_workgroup_memory.h b/src/tint/transform/zero_init_workgroup_memory.h
index 33ae52c..c757725 100644
--- a/src/tint/transform/zero_init_workgroup_memory.h
+++ b/src/tint/transform/zero_init_workgroup_memory.h
@@ -22,34 +22,30 @@
 /// ZeroInitWorkgroupMemory is a transform that injects code at the top of entry
 /// points to zero-initialize workgroup memory used by that entry point (and all
 /// transitive functions called by that entry point)
-class ZeroInitWorkgroupMemory
-    : public Castable<ZeroInitWorkgroupMemory, Transform> {
- public:
-  /// Constructor
-  ZeroInitWorkgroupMemory();
+class ZeroInitWorkgroupMemory : public Castable<ZeroInitWorkgroupMemory, Transform> {
+  public:
+    /// Constructor
+    ZeroInitWorkgroupMemory();
 
-  /// Destructor
-  ~ZeroInitWorkgroupMemory() override;
+    /// Destructor
+    ~ZeroInitWorkgroupMemory() override;
 
-  /// @param program the program to inspect
-  /// @param data optional extra transform-specific input data
-  /// @returns true if this transform should be run for the given program
-  bool ShouldRun(const Program* program,
-                 const DataMap& data = {}) const override;
+    /// @param program the program to inspect
+    /// @param data optional extra transform-specific input data
+    /// @returns true if this transform should be run for the given program
+    bool ShouldRun(const Program* program, const DataMap& data = {}) const override;
 
- protected:
-  /// Runs the transform using the CloneContext built for transforming a
-  /// program. Run() is responsible for calling Clone() on the CloneContext.
-  /// @param ctx the CloneContext primed with the input program and
-  /// ProgramBuilder
-  /// @param inputs optional extra transform-specific input data
-  /// @param outputs optional extra transform-specific output data
-  void Run(CloneContext& ctx,
-           const DataMap& inputs,
-           DataMap& outputs) const override;
+  protected:
+    /// Runs the transform using the CloneContext built for transforming a
+    /// program. Run() is responsible for calling Clone() on the CloneContext.
+    /// @param ctx the CloneContext primed with the input program and
+    /// ProgramBuilder
+    /// @param inputs optional extra transform-specific input data
+    /// @param outputs optional extra transform-specific output data
+    void Run(CloneContext& ctx, const DataMap& inputs, DataMap& outputs) const override;
 
- private:
-  struct State;
+  private:
+    struct State;
 };
 
 }  // namespace tint::transform
diff --git a/src/tint/transform/zero_init_workgroup_memory_test.cc b/src/tint/transform/zero_init_workgroup_memory_test.cc
index 32c73db..c846d55 100644
--- a/src/tint/transform/zero_init_workgroup_memory_test.cc
+++ b/src/tint/transform/zero_init_workgroup_memory_test.cc
@@ -24,53 +24,53 @@
 using ZeroInitWorkgroupMemoryTest = TransformTest;
 
 TEST_F(ZeroInitWorkgroupMemoryTest, ShouldRunEmptyModule) {
-  auto* src = R"()";
+    auto* src = R"()";
 
-  EXPECT_FALSE(ShouldRun<ZeroInitWorkgroupMemory>(src));
+    EXPECT_FALSE(ShouldRun<ZeroInitWorkgroupMemory>(src));
 }
 
 TEST_F(ZeroInitWorkgroupMemoryTest, ShouldRunHasNoWorkgroupVars) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> v : i32;
 )";
 
-  EXPECT_FALSE(ShouldRun<ZeroInitWorkgroupMemory>(src));
+    EXPECT_FALSE(ShouldRun<ZeroInitWorkgroupMemory>(src));
 }
 
 TEST_F(ZeroInitWorkgroupMemoryTest, ShouldRunHasWorkgroupVars) {
-  auto* src = R"(
+    auto* src = R"(
 var<workgroup> a : i32;
 )";
 
-  EXPECT_TRUE(ShouldRun<ZeroInitWorkgroupMemory>(src));
+    EXPECT_TRUE(ShouldRun<ZeroInitWorkgroupMemory>(src));
 }
 
 TEST_F(ZeroInitWorkgroupMemoryTest, EmptyModule) {
-  auto* src = "";
-  auto* expect = src;
+    auto* src = "";
+    auto* expect = src;
 
-  auto got = Run<ZeroInitWorkgroupMemory>(src);
+    auto got = Run<ZeroInitWorkgroupMemory>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ZeroInitWorkgroupMemoryTest, NoWorkgroupVars) {
-  auto* src = R"(
+    auto* src = R"(
 var<private> v : i32;
 
 fn f() {
   v = 1;
 }
 )";
-  auto* expect = src;
+    auto* expect = src;
 
-  auto got = Run<ZeroInitWorkgroupMemory>(src);
+    auto got = Run<ZeroInitWorkgroupMemory>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ZeroInitWorkgroupMemoryTest, UnreferencedWorkgroupVars) {
-  auto* src = R"(
+    auto* src = R"(
 var<workgroup> a : i32;
 
 var<workgroup> b : i32;
@@ -85,15 +85,15 @@
 fn f() {
 }
 )";
-  auto* expect = src;
+    auto* expect = src;
 
-  auto got = Run<ZeroInitWorkgroupMemory>(src);
+    auto got = Run<ZeroInitWorkgroupMemory>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ZeroInitWorkgroupMemoryTest, UnreferencedWorkgroupVars_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn f() {
 }
@@ -108,15 +108,15 @@
 
 var<workgroup> c : i32;
 )";
-  auto* expect = src;
+    auto* expect = src;
 
-  auto got = Run<ZeroInitWorkgroupMemory>(src);
+    auto got = Run<ZeroInitWorkgroupMemory>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ZeroInitWorkgroupMemoryTest, SingleWorkgroupVar_ExistingLocalIndex) {
-  auto* src = R"(
+    auto* src = R"(
 var<workgroup> v : i32;
 
 @stage(compute) @workgroup_size(1)
@@ -124,7 +124,7 @@
   _ = v; // Initialization should be inserted above this statement
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 var<workgroup> v : i32;
 
 @stage(compute) @workgroup_size(1)
@@ -137,14 +137,13 @@
 }
 )";
 
-  auto got = Run<ZeroInitWorkgroupMemory>(src);
+    auto got = Run<ZeroInitWorkgroupMemory>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(ZeroInitWorkgroupMemoryTest,
-       SingleWorkgroupVar_ExistingLocalIndex_OutOfOrder) {
-  auto* src = R"(
+TEST_F(ZeroInitWorkgroupMemoryTest, SingleWorkgroupVar_ExistingLocalIndex_OutOfOrder) {
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn f(@builtin(local_invocation_index) local_idx : u32) {
   _ = v; // Initialization should be inserted above this statement
@@ -152,7 +151,7 @@
 
 var<workgroup> v : i32;
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 @stage(compute) @workgroup_size(1)
 fn f(@builtin(local_invocation_index) local_idx : u32) {
   {
@@ -165,14 +164,13 @@
 var<workgroup> v : i32;
 )";
 
-  auto got = Run<ZeroInitWorkgroupMemory>(src);
+    auto got = Run<ZeroInitWorkgroupMemory>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(ZeroInitWorkgroupMemoryTest,
-       SingleWorkgroupVar_ExistingLocalIndexInStruct) {
-  auto* src = R"(
+TEST_F(ZeroInitWorkgroupMemoryTest, SingleWorkgroupVar_ExistingLocalIndexInStruct) {
+    auto* src = R"(
 var<workgroup> v : i32;
 
 struct Params {
@@ -184,7 +182,7 @@
   _ = v; // Initialization should be inserted above this statement
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 var<workgroup> v : i32;
 
 struct Params {
@@ -202,14 +200,13 @@
 }
 )";
 
-  auto got = Run<ZeroInitWorkgroupMemory>(src);
+    auto got = Run<ZeroInitWorkgroupMemory>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(ZeroInitWorkgroupMemoryTest,
-       SingleWorkgroupVar_ExistingLocalIndexInStruct_OutOfOrder) {
-  auto* src = R"(
+TEST_F(ZeroInitWorkgroupMemoryTest, SingleWorkgroupVar_ExistingLocalIndexInStruct_OutOfOrder) {
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn f(params : Params) {
   _ = v; // Initialization should be inserted above this statement
@@ -221,7 +218,7 @@
 
 var<workgroup> v : i32;
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 @stage(compute) @workgroup_size(1)
 fn f(params : Params) {
   {
@@ -239,13 +236,13 @@
 var<workgroup> v : i32;
 )";
 
-  auto got = Run<ZeroInitWorkgroupMemory>(src);
+    auto got = Run<ZeroInitWorkgroupMemory>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ZeroInitWorkgroupMemoryTest, SingleWorkgroupVar_InjectedLocalIndex) {
-  auto* src = R"(
+    auto* src = R"(
 var<workgroup> v : i32;
 
 @stage(compute) @workgroup_size(1)
@@ -253,7 +250,7 @@
   _ = v; // Initialization should be inserted above this statement
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 var<workgroup> v : i32;
 
 @stage(compute) @workgroup_size(1)
@@ -266,14 +263,13 @@
 }
 )";
 
-  auto got = Run<ZeroInitWorkgroupMemory>(src);
+    auto got = Run<ZeroInitWorkgroupMemory>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(ZeroInitWorkgroupMemoryTest,
-       SingleWorkgroupVar_InjectedLocalIndex_OutOfOrder) {
-  auto* src = R"(
+TEST_F(ZeroInitWorkgroupMemoryTest, SingleWorkgroupVar_InjectedLocalIndex_OutOfOrder) {
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn f() {
   _ = v; // Initialization should be inserted above this statement
@@ -281,7 +277,7 @@
 
 var<workgroup> v : i32;
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 @stage(compute) @workgroup_size(1)
 fn f(@builtin(local_invocation_index) local_invocation_index : u32) {
   {
@@ -294,14 +290,13 @@
 var<workgroup> v : i32;
 )";
 
-  auto got = Run<ZeroInitWorkgroupMemory>(src);
+    auto got = Run<ZeroInitWorkgroupMemory>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(ZeroInitWorkgroupMemoryTest,
-       MultipleWorkgroupVar_ExistingLocalIndex_Size1) {
-  auto* src = R"(
+TEST_F(ZeroInitWorkgroupMemoryTest, MultipleWorkgroupVar_ExistingLocalIndex_Size1) {
+    auto* src = R"(
 struct S {
   x : i32,
   y : array<i32, 8>,
@@ -320,7 +315,7 @@
   _ = c;
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   x : i32,
   y : array<i32, 8>,
@@ -358,14 +353,13 @@
 }
 )";
 
-  auto got = Run<ZeroInitWorkgroupMemory>(src);
+    auto got = Run<ZeroInitWorkgroupMemory>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(ZeroInitWorkgroupMemoryTest,
-       MultipleWorkgroupVar_ExistingLocalIndex_Size1_OutOfOrder) {
-  auto* src = R"(
+TEST_F(ZeroInitWorkgroupMemoryTest, MultipleWorkgroupVar_ExistingLocalIndex_Size1_OutOfOrder) {
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn f(@builtin(local_invocation_index) local_idx : u32) {
   _ = a; // Initialization should be inserted above this statement
@@ -384,7 +378,7 @@
   y : array<i32, 8>,
 };
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 @stage(compute) @workgroup_size(1)
 fn f(@builtin(local_invocation_index) local_idx : u32) {
   {
@@ -422,14 +416,13 @@
 }
 )";
 
-  auto got = Run<ZeroInitWorkgroupMemory>(src);
+    auto got = Run<ZeroInitWorkgroupMemory>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(ZeroInitWorkgroupMemoryTest,
-       MultipleWorkgroupVar_ExistingLocalIndex_Size_2_3) {
-  auto* src = R"(
+TEST_F(ZeroInitWorkgroupMemoryTest, MultipleWorkgroupVar_ExistingLocalIndex_Size_2_3) {
+    auto* src = R"(
 struct S {
   x : i32,
   y : array<i32, 8>,
@@ -448,7 +441,7 @@
   _ = c;
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   x : i32,
   y : array<i32, 8>,
@@ -486,14 +479,13 @@
 }
 )";
 
-  auto got = Run<ZeroInitWorkgroupMemory>(src);
+    auto got = Run<ZeroInitWorkgroupMemory>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(ZeroInitWorkgroupMemoryTest,
-       MultipleWorkgroupVar_ExistingLocalIndex_Size_2_3_X) {
-  auto* src = R"(
+TEST_F(ZeroInitWorkgroupMemoryTest, MultipleWorkgroupVar_ExistingLocalIndex_Size_2_3_X) {
+    auto* src = R"(
 struct S {
   x : i32,
   y : array<i32, 8>,
@@ -514,8 +506,8 @@
   _ = c;
 }
 )";
-  auto* expect =
-      R"(
+    auto* expect =
+        R"(
 struct S {
   x : i32,
   y : array<i32, 8>,
@@ -555,14 +547,13 @@
 }
 )";
 
-  auto got = Run<ZeroInitWorkgroupMemory>(src);
+    auto got = Run<ZeroInitWorkgroupMemory>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(ZeroInitWorkgroupMemoryTest,
-       MultipleWorkgroupVar_ExistingLocalIndex_Size_5u_X_10u) {
-  auto* src = R"(
+TEST_F(ZeroInitWorkgroupMemoryTest, MultipleWorkgroupVar_ExistingLocalIndex_Size_5u_X_10u) {
+    auto* src = R"(
 struct S {
   x : array<array<i32, 8>, 10>,
   y : array<i32, 8>,
@@ -584,8 +575,8 @@
   _ = c;
 }
 )";
-  auto* expect =
-      R"(
+    auto* expect =
+        R"(
 struct S {
   x : array<array<i32, 8>, 10>,
   y : array<i32, 8>,
@@ -645,13 +636,13 @@
 }
 )";
 
-  auto got = Run<ZeroInitWorkgroupMemory>(src);
+    auto got = Run<ZeroInitWorkgroupMemory>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ZeroInitWorkgroupMemoryTest, MultipleWorkgroupVar_InjectedLocalIndex) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   x : i32,
   y : array<i32, 8>,
@@ -670,7 +661,7 @@
   _ = c;
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   x : i32,
   y : array<i32, 8>,
@@ -708,14 +699,13 @@
 }
 )";
 
-  auto got = Run<ZeroInitWorkgroupMemory>(src);
+    auto got = Run<ZeroInitWorkgroupMemory>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(ZeroInitWorkgroupMemoryTest,
-       MultipleWorkgroupVar_InjectedLocalIndex_OutOfOrder) {
-  auto* src = R"(
+TEST_F(ZeroInitWorkgroupMemoryTest, MultipleWorkgroupVar_InjectedLocalIndex_OutOfOrder) {
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn f(@builtin(local_invocation_id) local_invocation_id : vec3<u32>) {
   _ = a; // Initialization should be inserted above this statement
@@ -734,7 +724,7 @@
   y : array<i32, 8>,
 };
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 @stage(compute) @workgroup_size(1)
 fn f(@builtin(local_invocation_id) local_invocation_id : vec3<u32>, @builtin(local_invocation_index) local_invocation_index : u32) {
   {
@@ -772,13 +762,13 @@
 }
 )";
 
-  auto got = Run<ZeroInitWorkgroupMemory>(src);
+    auto got = Run<ZeroInitWorkgroupMemory>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ZeroInitWorkgroupMemoryTest, MultipleWorkgroupVar_MultipleEntryPoints) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   x : i32,
   y : array<i32, 8>,
@@ -807,7 +797,7 @@
   _ = a;
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   x : i32,
   y : array<i32, 8>,
@@ -871,14 +861,13 @@
 }
 )";
 
-  auto got = Run<ZeroInitWorkgroupMemory>(src);
+    auto got = Run<ZeroInitWorkgroupMemory>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(ZeroInitWorkgroupMemoryTest,
-       MultipleWorkgroupVar_MultipleEntryPoints_OutOfOrder) {
-  auto* src = R"(
+TEST_F(ZeroInitWorkgroupMemoryTest, MultipleWorkgroupVar_MultipleEntryPoints_OutOfOrder) {
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn f1() {
   _ = a; // Initialization should be inserted above this statement
@@ -907,7 +896,7 @@
   y : array<i32, 8>,
 };
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 @stage(compute) @workgroup_size(1)
 fn f1(@builtin(local_invocation_index) local_invocation_index : u32) {
   {
@@ -971,13 +960,13 @@
 }
 )";
 
-  auto got = Run<ZeroInitWorkgroupMemory>(src);
+    auto got = Run<ZeroInitWorkgroupMemory>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ZeroInitWorkgroupMemoryTest, TransitiveUsage) {
-  auto* src = R"(
+    auto* src = R"(
 var<workgroup> v : i32;
 
 fn use_v() {
@@ -993,7 +982,7 @@
   call_use_v(); // Initialization should be inserted above this statement
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 var<workgroup> v : i32;
 
 fn use_v() {
@@ -1014,13 +1003,13 @@
 }
 )";
 
-  auto got = Run<ZeroInitWorkgroupMemory>(src);
+    auto got = Run<ZeroInitWorkgroupMemory>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ZeroInitWorkgroupMemoryTest, TransitiveUsage_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn f(@builtin(local_invocation_index) local_idx : u32) {
   call_use_v(); // Initialization should be inserted above this statement
@@ -1036,7 +1025,7 @@
 
 var<workgroup> v : i32;
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 @stage(compute) @workgroup_size(1)
 fn f(@builtin(local_invocation_index) local_idx : u32) {
   {
@@ -1057,13 +1046,13 @@
 var<workgroup> v : i32;
 )";
 
-  auto got = Run<ZeroInitWorkgroupMemory>(src);
+    auto got = Run<ZeroInitWorkgroupMemory>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ZeroInitWorkgroupMemoryTest, WorkgroupAtomics) {
-  auto* src = R"(
+    auto* src = R"(
 var<workgroup> i : atomic<i32>;
 var<workgroup> u : atomic<u32>;
 
@@ -1073,7 +1062,7 @@
   atomicLoad(&(u));
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 var<workgroup> i : atomic<i32>;
 
 var<workgroup> u : atomic<u32>;
@@ -1090,13 +1079,13 @@
 }
 )";
 
-  auto got = Run<ZeroInitWorkgroupMemory>(src);
+    auto got = Run<ZeroInitWorkgroupMemory>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ZeroInitWorkgroupMemoryTest, WorkgroupAtomics_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn f() {
   atomicLoad(&(i)); // Initialization should be inserted above this statement
@@ -1106,7 +1095,7 @@
 var<workgroup> i : atomic<i32>;
 var<workgroup> u : atomic<u32>;
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 @stage(compute) @workgroup_size(1)
 fn f(@builtin(local_invocation_index) local_invocation_index : u32) {
   {
@@ -1123,13 +1112,13 @@
 var<workgroup> u : atomic<u32>;
 )";
 
-  auto got = Run<ZeroInitWorkgroupMemory>(src);
+    auto got = Run<ZeroInitWorkgroupMemory>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ZeroInitWorkgroupMemoryTest, WorkgroupStructOfAtomics) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   a : i32,
   i : atomic<i32>,
@@ -1145,7 +1134,7 @@
   _ = w.a; // Initialization should be inserted above this statement
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   a : i32,
   i : atomic<i32>,
@@ -1170,13 +1159,13 @@
 }
 )";
 
-  auto got = Run<ZeroInitWorkgroupMemory>(src);
+    auto got = Run<ZeroInitWorkgroupMemory>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ZeroInitWorkgroupMemoryTest, WorkgroupStructOfAtomics_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn f() {
   _ = w.a; // Initialization should be inserted above this statement
@@ -1192,7 +1181,7 @@
   c : u32,
 };
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 @stage(compute) @workgroup_size(1)
 fn f(@builtin(local_invocation_index) local_invocation_index : u32) {
   {
@@ -1217,13 +1206,13 @@
 }
 )";
 
-  auto got = Run<ZeroInitWorkgroupMemory>(src);
+    auto got = Run<ZeroInitWorkgroupMemory>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ZeroInitWorkgroupMemoryTest, WorkgroupArrayOfAtomics) {
-  auto* src = R"(
+    auto* src = R"(
 var<workgroup> w : array<atomic<u32>, 4>;
 
 @stage(compute) @workgroup_size(1)
@@ -1231,7 +1220,7 @@
   atomicLoad(&w[0]); // Initialization should be inserted above this statement
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 var<workgroup> w : array<atomic<u32>, 4>;
 
 @stage(compute) @workgroup_size(1)
@@ -1245,13 +1234,13 @@
 }
 )";
 
-  auto got = Run<ZeroInitWorkgroupMemory>(src);
+    auto got = Run<ZeroInitWorkgroupMemory>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ZeroInitWorkgroupMemoryTest, WorkgroupArrayOfAtomics_OutOfOrder) {
-  auto* src = R"(
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn f() {
   atomicLoad(&w[0]); // Initialization should be inserted above this statement
@@ -1259,7 +1248,7 @@
 
 var<workgroup> w : array<atomic<u32>, 4>;
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 @stage(compute) @workgroup_size(1)
 fn f(@builtin(local_invocation_index) local_invocation_index : u32) {
   for(var idx : u32 = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
@@ -1273,13 +1262,13 @@
 var<workgroup> w : array<atomic<u32>, 4>;
 )";
 
-  auto got = Run<ZeroInitWorkgroupMemory>(src);
+    auto got = Run<ZeroInitWorkgroupMemory>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 TEST_F(ZeroInitWorkgroupMemoryTest, WorkgroupArrayOfStructOfAtomics) {
-  auto* src = R"(
+    auto* src = R"(
 struct S {
   a : i32,
   i : atomic<i32>,
@@ -1295,7 +1284,7 @@
   _ = w[0].a; // Initialization should be inserted above this statement
 }
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 struct S {
   a : i32,
   i : atomic<i32>,
@@ -1321,14 +1310,13 @@
 }
 )";
 
-  auto got = Run<ZeroInitWorkgroupMemory>(src);
+    auto got = Run<ZeroInitWorkgroupMemory>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
-TEST_F(ZeroInitWorkgroupMemoryTest,
-       WorkgroupArrayOfStructOfAtomics_OutOfOrder) {
-  auto* src = R"(
+TEST_F(ZeroInitWorkgroupMemoryTest, WorkgroupArrayOfStructOfAtomics_OutOfOrder) {
+    auto* src = R"(
 @stage(compute) @workgroup_size(1)
 fn f() {
   _ = w[0].a; // Initialization should be inserted above this statement
@@ -1344,7 +1332,7 @@
   c : u32,
 };
 )";
-  auto* expect = R"(
+    auto* expect = R"(
 @stage(compute) @workgroup_size(1)
 fn f(@builtin(local_invocation_index) local_invocation_index : u32) {
   for(var idx : u32 = local_invocation_index; (idx < 4u); idx = (idx + 1u)) {
@@ -1370,9 +1358,9 @@
 }
 )";
 
-  auto got = Run<ZeroInitWorkgroupMemory>(src);
+    auto got = Run<ZeroInitWorkgroupMemory>(src);
 
-  EXPECT_EQ(expect, str(got));
+    EXPECT_EQ(expect, str(got));
 }
 
 }  // namespace
diff --git a/src/tint/utils/bitcast.h b/src/tint/utils/bitcast.h
new file mode 100644
index 0000000..4450336
--- /dev/null
+++ b/src/tint/utils/bitcast.h
@@ -0,0 +1,39 @@
+// 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_UTILS_BITCAST_H_
+#define SRC_TINT_UTILS_BITCAST_H_
+
+#include <cstring>
+
+namespace tint::utils {
+
+/// Bitcast performs a cast of `from` to the `TO` type using a memcpy.
+/// This unsafe cast avoids triggering Clang's Control Flow Integrity checks.
+/// See: crbug.com/dawn/1406
+/// See: https://clang.llvm.org/docs/ControlFlowIntegrity.html#bad-cast-checking
+/// @param from the value to cast
+/// @tparam TO the value to cast to
+/// @returns the cast value
+template <typename TO, typename FROM>
+inline TO Bitcast(FROM&& from) {
+    static_assert(sizeof(FROM) == sizeof(TO));
+    TO to;
+    memcpy(&to, &from, sizeof(TO));
+    return to;
+}
+
+}  // namespace tint::utils
+
+#endif  // SRC_TINT_UTILS_BITCAST_H_
diff --git a/src/tint/utils/bitcast_test.cc b/src/tint/utils/bitcast_test.cc
new file mode 100644
index 0000000..2364899
--- /dev/null
+++ b/src/tint/utils/bitcast_test.cc
@@ -0,0 +1,37 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/utils/bitcast.h"
+
+#include <stdint.h>
+
+#include "gtest/gtest.h"
+
+namespace tint::utils {
+namespace {
+
+TEST(Bitcast, Integer) {
+    uint32_t a = 123;
+    int32_t b = Bitcast<int32_t>(a);
+    EXPECT_EQ(a, static_cast<uint32_t>(b));
+}
+
+TEST(Bitcast, Pointer) {
+    uint32_t a = 123;
+    void* b = Bitcast<void*>(&a);
+    EXPECT_EQ(&a, static_cast<uint32_t*>(b));
+}
+
+}  // namespace
+}  // namespace tint::utils
diff --git a/src/tint/utils/block_allocator.h b/src/tint/utils/block_allocator.h
index 4823fae..f413940 100644
--- a/src/tint/utils/block_allocator.h
+++ b/src/tint/utils/block_allocator.h
@@ -16,8 +16,10 @@
 #define SRC_TINT_UTILS_BLOCK_ALLOCATOR_H_
 
 #include <array>
+#include <cstring>
 #include <utility>
 
+#include "src/tint/utils/bitcast.h"
 #include "src/tint/utils/math.h"
 
 namespace tint::utils {
@@ -28,265 +30,259 @@
 /// objects are automatically destructed and freed.
 ///
 /// Objects held by the BlockAllocator can be iterated over using a View.
-template <typename T,
-          size_t BLOCK_SIZE = 64 * 1024,
-          size_t BLOCK_ALIGNMENT = 16>
+template <typename T, size_t BLOCK_SIZE = 64 * 1024, size_t BLOCK_ALIGNMENT = 16>
 class BlockAllocator {
-  /// Pointers is a chunk of T* pointers, forming a linked list.
-  /// The list of Pointers are used to maintain the list of allocated objects.
-  /// Pointers are allocated out of the block memory.
-  struct Pointers {
-    static constexpr size_t kMax = 32;
-    std::array<T*, kMax> ptrs;
-    Pointers* next;
-  };
+    /// Pointers is a chunk of T* pointers, forming a linked list.
+    /// The list of Pointers are used to maintain the list of allocated objects.
+    /// Pointers are allocated out of the block memory.
+    struct Pointers {
+        static constexpr size_t kMax = 32;
+        std::array<T*, kMax> ptrs;
+        Pointers* next;
+    };
 
-  /// Block is linked list of memory blocks.
-  /// Blocks are allocated out of heap memory.
-  ///
-  /// Note: We're not using std::aligned_storage here as this warns / errors
-  /// on MSVC.
-  struct alignas(BLOCK_ALIGNMENT) Block {
-    uint8_t data[BLOCK_SIZE];
-    Block* next;
-  };
+    /// Block is linked list of memory blocks.
+    /// Blocks are allocated out of heap memory.
+    ///
+    /// Note: We're not using std::aligned_storage here as this warns / errors
+    /// on MSVC.
+    struct alignas(BLOCK_ALIGNMENT) Block {
+        uint8_t data[BLOCK_SIZE];
+        Block* next;
+    };
 
-  // Forward declaration
-  template <bool IS_CONST>
-  class TView;
+    // Forward declaration
+    template <bool IS_CONST>
+    class TView;
 
-  /// An iterator for the objects owned by the BlockAllocator.
-  template <bool IS_CONST>
-  class TIterator {
-    using PointerTy = std::conditional_t<IS_CONST, const T*, T*>;
+    /// An iterator for the objects owned by the BlockAllocator.
+    template <bool IS_CONST>
+    class TIterator {
+        using PointerTy = std::conditional_t<IS_CONST, const T*, T*>;
 
-   public:
-    /// Equality operator
-    /// @param other the iterator to compare this iterator to
-    /// @returns true if this iterator is equal to other
-    bool operator==(const TIterator& other) const {
-      return ptrs == other.ptrs && idx == other.idx;
-    }
-
-    /// Inequality operator
-    /// @param other the iterator to compare this iterator to
-    /// @returns true if this iterator is not equal to other
-    bool operator!=(const TIterator& other) const { return !(*this == other); }
-
-    /// Advances the iterator
-    /// @returns this iterator
-    TIterator& operator++() {
-      if (ptrs != nullptr) {
-        ++idx;
-        if (idx == Pointers::kMax) {
-          idx = 0;
-          ptrs = ptrs->next;
+      public:
+        /// Equality operator
+        /// @param other the iterator to compare this iterator to
+        /// @returns true if this iterator is equal to other
+        bool operator==(const TIterator& other) const {
+            return ptrs == other.ptrs && idx == other.idx;
         }
-      }
-      return *this;
+
+        /// Inequality operator
+        /// @param other the iterator to compare this iterator to
+        /// @returns true if this iterator is not equal to other
+        bool operator!=(const TIterator& other) const { return !(*this == other); }
+
+        /// Advances the iterator
+        /// @returns this iterator
+        TIterator& operator++() {
+            if (ptrs != nullptr) {
+                ++idx;
+                if (idx == Pointers::kMax) {
+                    idx = 0;
+                    ptrs = ptrs->next;
+                }
+            }
+            return *this;
+        }
+
+        /// @returns the pointer to the object at the current iterator position
+        PointerTy operator*() const { return ptrs ? ptrs->ptrs[idx] : nullptr; }
+
+      private:
+        friend TView<IS_CONST>;  // Keep internal iterator impl private.
+        explicit TIterator(const Pointers* p, size_t i) : ptrs(p), idx(i) {}
+
+        const Pointers* ptrs;
+        size_t idx;
+    };
+
+    /// View provides begin() and end() methods for looping over the objects
+    /// owned by the BlockAllocator.
+    template <bool IS_CONST>
+    class TView {
+      public:
+        /// @returns an iterator to the beginning of the view
+        TIterator<IS_CONST> begin() const {
+            return TIterator<IS_CONST>{allocator_->pointers_.root, 0};
+        }
+
+        /// @returns an iterator to the end of the view
+        TIterator<IS_CONST> end() const {
+            return allocator_->pointers_.current_index >= Pointers::kMax
+                       ? TIterator<IS_CONST>(nullptr, 0)
+                       : TIterator<IS_CONST>(allocator_->pointers_.current,
+                                             allocator_->pointers_.current_index);
+        }
+
+      private:
+        friend BlockAllocator;  // For BlockAllocator::operator View()
+        explicit TView(BlockAllocator const* allocator) : allocator_(allocator) {}
+        BlockAllocator const* const allocator_;
+    };
+
+  public:
+    /// An iterator type over the objects of the BlockAllocator
+    using Iterator = TIterator<false>;
+
+    /// An immutable iterator type over the objects of the BlockAllocator
+    using ConstIterator = TIterator<true>;
+
+    /// View provides begin() and end() methods for looping over the objects
+    /// owned by the BlockAllocator.
+    using View = TView<false>;
+
+    /// ConstView provides begin() and end() methods for looping over the objects
+    /// owned by the BlockAllocator.
+    using ConstView = TView<true>;
+
+    /// Constructor
+    BlockAllocator() = default;
+
+    /// Move constructor
+    /// @param rhs the BlockAllocator to move
+    BlockAllocator(BlockAllocator&& rhs) {
+        std::swap(block_, rhs.block_);
+        std::swap(pointers_, rhs.pointers_);
     }
 
-    /// @returns the pointer to the object at the current iterator position
-    PointerTy operator*() const { return ptrs ? ptrs->ptrs[idx] : nullptr; }
-
-   private:
-    friend TView<IS_CONST>;  // Keep internal iterator impl private.
-    explicit TIterator(const Pointers* p, size_t i) : ptrs(p), idx(i) {}
-
-    const Pointers* ptrs;
-    size_t idx;
-  };
-
-  /// View provides begin() and end() methods for looping over the objects
-  /// owned by the BlockAllocator.
-  template <bool IS_CONST>
-  class TView {
-   public:
-    /// @returns an iterator to the beginning of the view
-    TIterator<IS_CONST> begin() const {
-      return TIterator<IS_CONST>{allocator_->pointers_.root, 0};
+    /// Move assignment operator
+    /// @param rhs the BlockAllocator to move
+    /// @return this BlockAllocator
+    BlockAllocator& operator=(BlockAllocator&& rhs) {
+        if (this != &rhs) {
+            Reset();
+            std::swap(block_, rhs.block_);
+            std::swap(pointers_, rhs.pointers_);
+        }
+        return *this;
     }
 
-    /// @returns an iterator to the end of the view
-    TIterator<IS_CONST> end() const {
-      return allocator_->pointers_.current_index >= Pointers::kMax
-                 ? TIterator<IS_CONST>(nullptr, 0)
-                 : TIterator<IS_CONST>(allocator_->pointers_.current,
-                                       allocator_->pointers_.current_index);
+    /// Destructor
+    ~BlockAllocator() { Reset(); }
+
+    /// @return a View of all objects owned by this BlockAllocator
+    View Objects() { return View(this); }
+
+    /// @return a ConstView of all objects owned by this BlockAllocator
+    ConstView Objects() const { return ConstView(this); }
+
+    /// Creates a new `TYPE` owned by the BlockAllocator.
+    /// When the BlockAllocator is destructed the object will be destructed and
+    /// freed.
+    /// @param args the arguments to pass to the type constructor
+    /// @returns the pointer to the constructed object
+    template <typename TYPE = T, typename... ARGS>
+    TYPE* Create(ARGS&&... args) {
+        static_assert(std::is_same<T, TYPE>::value || std::is_base_of<T, TYPE>::value,
+                      "TYPE does not derive from T");
+        static_assert(std::is_same<T, TYPE>::value || std::has_virtual_destructor<T>::value,
+                      "TYPE requires a virtual destructor when calling Create() for a type "
+                      "that is not T");
+
+        auto* ptr = Allocate<TYPE>();
+        new (ptr) TYPE(std::forward<ARGS>(args)...);
+        AddObjectPointer(ptr);
+
+        return ptr;
     }
 
-   private:
-    friend BlockAllocator;  // For BlockAllocator::operator View()
-    explicit TView(BlockAllocator const* allocator) : allocator_(allocator) {}
-    BlockAllocator const* const allocator_;
-  };
-
- public:
-  /// An iterator type over the objects of the BlockAllocator
-  using Iterator = TIterator<false>;
-
-  /// An immutable iterator type over the objects of the BlockAllocator
-  using ConstIterator = TIterator<true>;
-
-  /// View provides begin() and end() methods for looping over the objects
-  /// owned by the BlockAllocator.
-  using View = TView<false>;
-
-  /// ConstView provides begin() and end() methods for looping over the objects
-  /// owned by the BlockAllocator.
-  using ConstView = TView<true>;
-
-  /// Constructor
-  BlockAllocator() = default;
-
-  /// Move constructor
-  /// @param rhs the BlockAllocator to move
-  BlockAllocator(BlockAllocator&& rhs) {
-    std::swap(block_, rhs.block_);
-    std::swap(pointers_, rhs.pointers_);
-  }
-
-  /// Move assignment operator
-  /// @param rhs the BlockAllocator to move
-  /// @return this BlockAllocator
-  BlockAllocator& operator=(BlockAllocator&& rhs) {
-    if (this != &rhs) {
-      Reset();
-      std::swap(block_, rhs.block_);
-      std::swap(pointers_, rhs.pointers_);
-    }
-    return *this;
-  }
-
-  /// Destructor
-  ~BlockAllocator() { Reset(); }
-
-  /// @return a View of all objects owned by this BlockAllocator
-  View Objects() { return View(this); }
-
-  /// @return a ConstView of all objects owned by this BlockAllocator
-  ConstView Objects() const { return ConstView(this); }
-
-  /// Creates a new `TYPE` owned by the BlockAllocator.
-  /// When the BlockAllocator is destructed the object will be destructed and
-  /// freed.
-  /// @param args the arguments to pass to the type constructor
-  /// @returns the pointer to the constructed object
-  template <typename TYPE = T, typename... ARGS>
-  TYPE* Create(ARGS&&... args) {
-    static_assert(
-        std::is_same<T, TYPE>::value || std::is_base_of<T, TYPE>::value,
-        "TYPE does not derive from T");
-    static_assert(
-        std::is_same<T, TYPE>::value || std::has_virtual_destructor<T>::value,
-        "TYPE requires a virtual destructor when calling Create() for a type "
-        "that is not T");
-
-    auto* ptr = Allocate<TYPE>();
-    new (ptr) TYPE(std::forward<ARGS>(args)...);
-    AddObjectPointer(ptr);
-
-    return ptr;
-  }
-
-  /// Frees all allocations from the allocator.
-  void Reset() {
-    for (auto ptr : Objects()) {
-      ptr->~T();
-    }
-    auto* block = block_.root;
-    while (block != nullptr) {
-      auto* next = block->next;
-      delete block;
-      block = next;
-    }
-    block_ = {};
-    pointers_ = {};
-  }
-
- private:
-  BlockAllocator(const BlockAllocator&) = delete;
-  BlockAllocator& operator=(const BlockAllocator&) = delete;
-
-  /// Allocates an instance of TYPE from the current block, or from a newly
-  /// allocated block if the current block is full.
-  template <typename TYPE>
-  TYPE* Allocate() {
-    static_assert(sizeof(TYPE) <= BLOCK_SIZE,
-                  "Cannot construct TYPE with size greater than BLOCK_SIZE");
-    static_assert(alignof(TYPE) <= BLOCK_ALIGNMENT,
-                  "alignof(TYPE) is greater than ALIGNMENT");
-
-    block_.current_offset =
-        utils::RoundUp(alignof(TYPE), block_.current_offset);
-    if (block_.current_offset + sizeof(TYPE) > BLOCK_SIZE) {
-      // Allocate a new block from the heap
-      auto* prev_block = block_.current;
-      block_.current = new Block;
-      if (!block_.current) {
-        return nullptr;  // out of memory
-      }
-      block_.current->next = nullptr;
-      block_.current_offset = 0;
-      if (prev_block) {
-        prev_block->next = block_.current;
-      } else {
-        block_.root = block_.current;
-      }
+    /// Frees all allocations from the allocator.
+    void Reset() {
+        for (auto ptr : Objects()) {
+            ptr->~T();
+        }
+        auto* block = block_.root;
+        while (block != nullptr) {
+            auto* next = block->next;
+            delete block;
+            block = next;
+        }
+        block_ = {};
+        pointers_ = {};
     }
 
-    auto* base = &block_.current->data[0];
-    auto* ptr = reinterpret_cast<TYPE*>(base + block_.current_offset);
-    block_.current_offset += sizeof(TYPE);
-    return ptr;
-  }
+  private:
+    BlockAllocator(const BlockAllocator&) = delete;
+    BlockAllocator& operator=(const BlockAllocator&) = delete;
 
-  /// Adds `ptr` to the linked list of objects owned by this BlockAllocator.
-  /// Once added, `ptr` will be tracked for destruction when the BlockAllocator
-  /// is destructed.
-  void AddObjectPointer(T* ptr) {
-    if (pointers_.current_index >= Pointers::kMax) {
-      auto* prev_pointers = pointers_.current;
-      pointers_.current = Allocate<Pointers>();
-      if (!pointers_.current) {
-        return;  // out of memory
-      }
-      pointers_.current->next = nullptr;
-      pointers_.current_index = 0;
+    /// Allocates an instance of TYPE from the current block, or from a newly
+    /// allocated block if the current block is full.
+    template <typename TYPE>
+    TYPE* Allocate() {
+        static_assert(sizeof(TYPE) <= BLOCK_SIZE,
+                      "Cannot construct TYPE with size greater than BLOCK_SIZE");
+        static_assert(alignof(TYPE) <= BLOCK_ALIGNMENT, "alignof(TYPE) is greater than ALIGNMENT");
 
-      if (prev_pointers) {
-        prev_pointers->next = pointers_.current;
-      } else {
-        pointers_.root = pointers_.current;
-      }
+        block_.current_offset = utils::RoundUp(alignof(TYPE), block_.current_offset);
+        if (block_.current_offset + sizeof(TYPE) > BLOCK_SIZE) {
+            // Allocate a new block from the heap
+            auto* prev_block = block_.current;
+            block_.current = new Block;
+            if (!block_.current) {
+                return nullptr;  // out of memory
+            }
+            block_.current->next = nullptr;
+            block_.current_offset = 0;
+            if (prev_block) {
+                prev_block->next = block_.current;
+            } else {
+                block_.root = block_.current;
+            }
+        }
+
+        auto* base = &block_.current->data[0];
+        auto* ptr = utils::Bitcast<TYPE*>(base + block_.current_offset);
+        block_.current_offset += sizeof(TYPE);
+        return ptr;
     }
 
-    pointers_.current->ptrs[pointers_.current_index++] = ptr;
-  }
+    /// Adds `ptr` to the linked list of objects owned by this BlockAllocator.
+    /// Once added, `ptr` will be tracked for destruction when the BlockAllocator
+    /// is destructed.
+    void AddObjectPointer(T* ptr) {
+        if (pointers_.current_index >= Pointers::kMax) {
+            auto* prev_pointers = pointers_.current;
+            pointers_.current = Allocate<Pointers>();
+            if (!pointers_.current) {
+                return;  // out of memory
+            }
+            pointers_.current->next = nullptr;
+            pointers_.current_index = 0;
 
-  struct {
-    /// The root block of the block linked list
-    Block* root = nullptr;
-    /// The current (end) block of the blocked linked list.
-    /// New allocations come from this block
-    Block* current = nullptr;
-    /// The byte offset in #current for the next allocation.
-    /// Initialized with BLOCK_SIZE so that the first allocation triggers a
-    /// block allocation.
-    size_t current_offset = BLOCK_SIZE;
-  } block_;
+            if (prev_pointers) {
+                prev_pointers->next = pointers_.current;
+            } else {
+                pointers_.root = pointers_.current;
+            }
+        }
 
-  struct {
-    /// The root Pointers structure of the pointers linked list
-    Pointers* root = nullptr;
-    /// The current (end) Pointers structure of the pointers linked list.
-    /// AddObjectPointer() adds to this structure.
-    Pointers* current = nullptr;
-    /// The array index in #current for the next append.
-    /// Initialized with Pointers::kMax so that the first append triggers a
-    /// allocation of the Pointers structure.
-    size_t current_index = Pointers::kMax;
-  } pointers_;
+        pointers_.current->ptrs[pointers_.current_index++] = ptr;
+    }
+
+    struct {
+        /// The root block of the block linked list
+        Block* root = nullptr;
+        /// The current (end) block of the blocked linked list.
+        /// New allocations come from this block
+        Block* current = nullptr;
+        /// The byte offset in #current for the next allocation.
+        /// Initialized with BLOCK_SIZE so that the first allocation triggers a
+        /// block allocation.
+        size_t current_offset = BLOCK_SIZE;
+    } block_;
+
+    struct {
+        /// The root Pointers structure of the pointers linked list
+        Pointers* root = nullptr;
+        /// The current (end) Pointers structure of the pointers linked list.
+        /// AddObjectPointer() adds to this structure.
+        Pointers* current = nullptr;
+        /// The array index in #current for the next append.
+        /// Initialized with Pointers::kMax so that the first append triggers a
+        /// allocation of the Pointers structure.
+        size_t current_index = Pointers::kMax;
+    } pointers_;
 };
 
 }  // namespace tint::utils
diff --git a/src/tint/utils/block_allocator_test.cc b/src/tint/utils/block_allocator_test.cc
index ace0e9f..600019c 100644
--- a/src/tint/utils/block_allocator_test.cc
+++ b/src/tint/utils/block_allocator_test.cc
@@ -20,127 +20,125 @@
 namespace {
 
 struct LifetimeCounter {
-  explicit LifetimeCounter(size_t* count) : count_(count) { (*count)++; }
-  ~LifetimeCounter() { (*count_)--; }
+    explicit LifetimeCounter(size_t* count) : count_(count) { (*count)++; }
+    ~LifetimeCounter() { (*count_)--; }
 
-  size_t* const count_;
+    size_t* const count_;
 };
 
 using BlockAllocatorTest = testing::Test;
 
 TEST_F(BlockAllocatorTest, Empty) {
-  using Allocator = BlockAllocator<int>;
+    using Allocator = BlockAllocator<int>;
 
-  Allocator allocator;
+    Allocator allocator;
 
-  for (int* i : allocator.Objects()) {
-    (void)i;
-    if ((true)) {  // Workaround for "error: loop will run at most once"
-      FAIL() << "BlockAllocator should be empty";
+    for (int* i : allocator.Objects()) {
+        (void)i;
+        if ((true)) {  // Workaround for "error: loop will run at most once"
+            FAIL() << "BlockAllocator should be empty";
+        }
     }
-  }
-  for (const int* i : static_cast<const Allocator&>(allocator).Objects()) {
-    (void)i;
-    if ((true)) {  // Workaround for "error: loop will run at most once"
-      FAIL() << "BlockAllocator should be empty";
+    for (const int* i : static_cast<const Allocator&>(allocator).Objects()) {
+        (void)i;
+        if ((true)) {  // Workaround for "error: loop will run at most once"
+            FAIL() << "BlockAllocator should be empty";
+        }
     }
-  }
 }
 
 TEST_F(BlockAllocatorTest, ObjectLifetime) {
-  using Allocator = BlockAllocator<LifetimeCounter>;
+    using Allocator = BlockAllocator<LifetimeCounter>;
 
-  size_t count = 0;
-  {
-    Allocator allocator;
+    size_t count = 0;
+    {
+        Allocator allocator;
+        EXPECT_EQ(count, 0u);
+        allocator.Create(&count);
+        EXPECT_EQ(count, 1u);
+        allocator.Create(&count);
+        EXPECT_EQ(count, 2u);
+        allocator.Create(&count);
+        EXPECT_EQ(count, 3u);
+    }
     EXPECT_EQ(count, 0u);
-    allocator.Create(&count);
-    EXPECT_EQ(count, 1u);
-    allocator.Create(&count);
-    EXPECT_EQ(count, 2u);
-    allocator.Create(&count);
-    EXPECT_EQ(count, 3u);
-  }
-  EXPECT_EQ(count, 0u);
 }
 
 TEST_F(BlockAllocatorTest, MoveConstruct) {
-  using Allocator = BlockAllocator<LifetimeCounter>;
+    using Allocator = BlockAllocator<LifetimeCounter>;
 
-  for (size_t n :
-       {0, 1, 10, 16, 20, 32, 50, 64, 100, 256, 300, 512, 500, 512}) {
-    size_t count = 0;
-    {
-      Allocator allocator_a;
-      for (size_t i = 0; i < n; i++) {
-        allocator_a.Create(&count);
-      }
-      EXPECT_EQ(count, n);
+    for (size_t n : {0, 1, 10, 16, 20, 32, 50, 64, 100, 256, 300, 512, 500, 512}) {
+        size_t count = 0;
+        {
+            Allocator allocator_a;
+            for (size_t i = 0; i < n; i++) {
+                allocator_a.Create(&count);
+            }
+            EXPECT_EQ(count, n);
 
-      Allocator allocator_b{std::move(allocator_a)};
-      EXPECT_EQ(count, n);
+            Allocator allocator_b{std::move(allocator_a)};
+            EXPECT_EQ(count, n);
+        }
+
+        EXPECT_EQ(count, 0u);
     }
-
-    EXPECT_EQ(count, 0u);
-  }
 }
 
 TEST_F(BlockAllocatorTest, MoveAssign) {
-  using Allocator = BlockAllocator<LifetimeCounter>;
+    using Allocator = BlockAllocator<LifetimeCounter>;
 
-  for (size_t n :
-       {0, 1, 10, 16, 20, 32, 50, 64, 100, 256, 300, 512, 500, 512}) {
-    size_t count_a = 0;
-    size_t count_b = 0;
+    for (size_t n : {0, 1, 10, 16, 20, 32, 50, 64, 100, 256, 300, 512, 500, 512}) {
+        size_t count_a = 0;
+        size_t count_b = 0;
 
-    {
-      Allocator allocator_a;
-      for (size_t i = 0; i < n; i++) {
-        allocator_a.Create(&count_a);
-      }
-      EXPECT_EQ(count_a, n);
+        {
+            Allocator allocator_a;
+            for (size_t i = 0; i < n; i++) {
+                allocator_a.Create(&count_a);
+            }
+            EXPECT_EQ(count_a, n);
 
-      Allocator allocator_b;
-      for (size_t i = 0; i < n; i++) {
-        allocator_b.Create(&count_b);
-      }
-      EXPECT_EQ(count_b, n);
+            Allocator allocator_b;
+            for (size_t i = 0; i < n; i++) {
+                allocator_b.Create(&count_b);
+            }
+            EXPECT_EQ(count_b, n);
 
-      allocator_b = std::move(allocator_a);
-      EXPECT_EQ(count_a, n);
-      EXPECT_EQ(count_b, 0u);
+            allocator_b = std::move(allocator_a);
+            EXPECT_EQ(count_a, n);
+            EXPECT_EQ(count_b, 0u);
+        }
+
+        EXPECT_EQ(count_a, 0u);
+        EXPECT_EQ(count_b, 0u);
     }
-
-    EXPECT_EQ(count_a, 0u);
-    EXPECT_EQ(count_b, 0u);
-  }
 }
 
 TEST_F(BlockAllocatorTest, ObjectOrder) {
-  using Allocator = BlockAllocator<int>;
+    using Allocator = BlockAllocator<int>;
 
-  Allocator allocator;
-  constexpr int N = 10000;
-  for (int i = 0; i < N; i++) {
-    allocator.Create(i);
-  }
+    Allocator allocator;
+    constexpr int N = 10000;
+    for (int i = 0; i < N; i++) {
+        allocator.Create(i);
+    }
 
-  {
-    int i = 0;
-    for (int* p : allocator.Objects()) {
-      EXPECT_EQ(*p, i);
-      i++;
+    {
+        int i = 0;
+        for (int* p : allocator.Objects()) {
+            EXPECT_EQ(*p, i);
+            i++;
+        }
+        EXPECT_EQ(i, N);
     }
-    EXPECT_EQ(i, N);
-  }
-  {
-    int i = 0;
-    for (const int* p : static_cast<const Allocator&>(allocator).Objects()) {
-      EXPECT_EQ(*p, i);
-      i++;
+    {
+        int i = 0;
+        for (const int* p : static_cast<const Allocator&>(allocator).Objects()) {
+            EXPECT_EQ(*p, i);
+            i++;
+        }
+        EXPECT_EQ(i, N);
     }
-    EXPECT_EQ(i, N);
-  }
 }
 
 }  // namespace
diff --git a/src/tint/utils/crc32.h b/src/tint/utils/crc32.h
index efe2f0e..5123612 100644
--- a/src/tint/utils/crc32.h
+++ b/src/tint/utils/crc32.h
@@ -24,57 +24,50 @@
 /// at compile time.
 /// @see https://en.wikipedia.org/wiki/Cyclic_redundancy_check#CRC-32_algorithm
 constexpr uint32_t CRC32(const char* s) {
-  constexpr uint32_t kLUT[] = {
-      0,          0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
-      0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
-      0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
-      0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
-      0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
-      0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
-      0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
-      0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
-      0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
-      0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
-      0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
-      0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
-      0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
-      0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
-      0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
-      0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
-      0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
-      0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
-      0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
-      0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
-      0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
-      0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
-      0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
-      0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
-      0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
-      0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
-      0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
-      0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
-      0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
-      0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
-      0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
-      0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
-      0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
-      0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
-      0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
-      0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
-      0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
-      0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
-      0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
-      0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
-      0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
-      0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
-      0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d};
+    constexpr uint32_t kLUT[] = {
+        0,          0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535,
+        0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd,
+        0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d,
+        0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
+        0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
+        0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+        0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac,
+        0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+        0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab,
+        0xb6662d3d, 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
+        0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb,
+        0x086d3d2d, 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+        0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea,
+        0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, 0x4db26158, 0x3ab551ce,
+        0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
+        0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+        0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409,
+        0xce61e49f, 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+        0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739,
+        0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+        0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344, 0x8708a3d2, 0x1e01f268,
+        0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0,
+        0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8,
+        0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+        0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
+        0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703,
+        0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7,
+        0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
+        0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae,
+        0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+        0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, 0x88085ae6,
+        0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+        0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d,
+        0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5,
+        0x47b2cf7f, 0x30b5ffe9, 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
+        0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+        0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d};
 
-  uint32_t crc = 0xffffffff;
-  for (auto* p = s; *p != '\0'; ++p) {
-    crc =
-        (crc >> 8) ^ kLUT[static_cast<uint8_t>(crc) ^ static_cast<uint8_t>(*p)];
-  }
-  return crc ^ 0xffffffff;
+    uint32_t crc = 0xffffffff;
+    for (auto* p = s; *p != '\0'; ++p) {
+        crc = (crc >> 8) ^ kLUT[static_cast<uint8_t>(crc) ^ static_cast<uint8_t>(*p)];
+    }
+    return crc ^ 0xffffffff;
 }
 
 }  // namespace tint::utils
diff --git a/src/tint/utils/crc32_test.cc b/src/tint/utils/crc32_test.cc
index 3e80e78..28dd16f 100644
--- a/src/tint/utils/crc32_test.cc
+++ b/src/tint/utils/crc32_test.cc
@@ -20,15 +20,15 @@
 namespace {
 
 TEST(CRC32Test, Compiletime) {
-  static_assert(CRC32("") == 0x00000000u);
-  static_assert(CRC32("hello world") == 0x0d4a1185u);
-  static_assert(CRC32("123456789") == 0xcbf43926u);
+    static_assert(CRC32("") == 0x00000000u);
+    static_assert(CRC32("hello world") == 0x0d4a1185u);
+    static_assert(CRC32("123456789") == 0xcbf43926u);
 }
 
 TEST(CRC32Test, Runtime) {
-  EXPECT_EQ(CRC32(""), 0x00000000u);
-  EXPECT_EQ(CRC32("hello world"), 0x0d4a1185u);
-  EXPECT_EQ(CRC32("123456789"), 0xcbf43926u);
+    EXPECT_EQ(CRC32(""), 0x00000000u);
+    EXPECT_EQ(CRC32("hello world"), 0x0d4a1185u);
+    EXPECT_EQ(CRC32("123456789"), 0xcbf43926u);
 }
 
 }  // namespace
diff --git a/src/tint/utils/debugger.cc b/src/tint/utils/debugger.cc
index aded5b6..3e05bdc 100644
--- a/src/tint/utils/debugger.cc
+++ b/src/tint/utils/debugger.cc
@@ -27,32 +27,31 @@
 #ifdef _MSC_VER
 #define TINT_DEBUGGER_BREAK_DEFINED
 void tint::debugger::Break() {
-  if (::IsDebuggerPresent()) {
-    ::DebugBreak();
-  }
+    if (::IsDebuggerPresent()) {
+        ::DebugBreak();
+    }
 }
 
 #elif defined(__linux__)
 
 #define TINT_DEBUGGER_BREAK_DEFINED
 void tint::debugger::Break() {
-  // A process is being traced (debugged) if "/proc/self/status" contains a
-  // line with "TracerPid: <non-zero-digit>...".
-  bool is_traced = false;
-  std::ifstream fin("/proc/self/status");
-  std::string line;
-  while (!is_traced && std::getline(fin, line)) {
-    const char kPrefix[] = "TracerPid:\t";
-    static constexpr int kPrefixLen = sizeof(kPrefix) - 1;
-    if (line.length() > kPrefixLen &&
-        line.compare(0, kPrefixLen, kPrefix) == 0) {
-      is_traced = line[kPrefixLen] != '0';
+    // A process is being traced (debugged) if "/proc/self/status" contains a
+    // line with "TracerPid: <non-zero-digit>...".
+    bool is_traced = false;
+    std::ifstream fin("/proc/self/status");
+    std::string line;
+    while (!is_traced && std::getline(fin, line)) {
+        const char kPrefix[] = "TracerPid:\t";
+        static constexpr int kPrefixLen = sizeof(kPrefix) - 1;
+        if (line.length() > kPrefixLen && line.compare(0, kPrefixLen, kPrefix) == 0) {
+            is_traced = line[kPrefixLen] != '0';
+        }
     }
-  }
 
-  if (is_traced) {
-    raise(SIGTRAP);
-  }
+    if (is_traced) {
+        raise(SIGTRAP);
+    }
 }
 #endif  // platform
 
diff --git a/src/tint/utils/defer.h b/src/tint/utils/defer.h
index ce586f9..f073fb9 100644
--- a/src/tint/utils/defer.h
+++ b/src/tint/utils/defer.h
@@ -24,38 +24,37 @@
 /// Defer executes a function or function like object when it is destructed.
 template <typename F>
 class Defer {
- public:
-  /// Constructor
-  /// @param f the function to call when the Defer is destructed
-  explicit Defer(F&& f) : f_(std::move(f)) {}
+  public:
+    /// Constructor
+    /// @param f the function to call when the Defer is destructed
+    explicit Defer(F&& f) : f_(std::move(f)) {}
 
-  /// Move constructor
-  Defer(Defer&&) = default;
+    /// Move constructor
+    Defer(Defer&&) = default;
 
-  /// Destructor
-  /// Calls the deferred function
-  ~Defer() { f_(); }
+    /// Destructor
+    /// Calls the deferred function
+    ~Defer() { f_(); }
 
- private:
-  Defer(const Defer&) = delete;
-  Defer& operator=(const Defer&) = delete;
+  private:
+    Defer(const Defer&) = delete;
+    Defer& operator=(const Defer&) = delete;
 
-  F f_;
+    F f_;
 };
 
 /// Constructor
 /// @param f the function to call when the Defer is destructed
 template <typename F>
 inline Defer<F> MakeDefer(F&& f) {
-  return Defer<F>(std::forward<F>(f));
+    return Defer<F>(std::forward<F>(f));
 }
 
 }  // namespace tint::utils
 
 /// TINT_DEFER(S) executes the statement(s) `S` when exiting the current lexical
 /// scope.
-#define TINT_DEFER(S)                          \
-  auto TINT_CONCAT(tint_defer_, __COUNTER__) = \
-      ::tint::utils::MakeDefer([&] { S; })
+#define TINT_DEFER(S) \
+    auto TINT_CONCAT(tint_defer_, __COUNTER__) = ::tint::utils::MakeDefer([&] { S; })
 
 #endif  // SRC_TINT_UTILS_DEFER_H_
diff --git a/src/tint/utils/defer_test.cc b/src/tint/utils/defer_test.cc
index 27fd9b5..8a0bddb 100644
--- a/src/tint/utils/defer_test.cc
+++ b/src/tint/utils/defer_test.cc
@@ -20,22 +20,22 @@
 namespace {
 
 TEST(DeferTest, Basic) {
-  bool deferCalled = false;
-  { TINT_DEFER(deferCalled = true); }
-  ASSERT_TRUE(deferCalled);
+    bool deferCalled = false;
+    { TINT_DEFER(deferCalled = true); }
+    ASSERT_TRUE(deferCalled);
 }
 
 TEST(DeferTest, DeferOrder) {
-  int counter = 0;
-  int a = 0, b = 0, c = 0;
-  {
-    TINT_DEFER(a = ++counter);
-    TINT_DEFER(b = ++counter);
-    TINT_DEFER(c = ++counter);
-  }
-  ASSERT_EQ(a, 3);
-  ASSERT_EQ(b, 2);
-  ASSERT_EQ(c, 1);
+    int counter = 0;
+    int a = 0, b = 0, c = 0;
+    {
+        TINT_DEFER(a = ++counter);
+        TINT_DEFER(b = ++counter);
+        TINT_DEFER(c = ++counter);
+    }
+    ASSERT_EQ(a, 3);
+    ASSERT_EQ(b, 2);
+    ASSERT_EQ(c, 1);
 }
 
 }  // namespace
diff --git a/src/tint/utils/enum_set.h b/src/tint/utils/enum_set.h
index c5af0f9..19d1a82 100644
--- a/src/tint/utils/enum_set.h
+++ b/src/tint/utils/enum_set.h
@@ -28,194 +28,192 @@
 /// enum values in the range [0 .. 63].
 template <typename ENUM>
 struct EnumSet {
- public:
-  /// Enum is the enum type this EnumSet wraps
-  using Enum = ENUM;
+  public:
+    /// Enum is the enum type this EnumSet wraps
+    using Enum = ENUM;
 
-  /// Constructor. Initializes the EnumSet with zero.
-  constexpr EnumSet() = default;
+    /// Constructor. Initializes the EnumSet with zero.
+    constexpr EnumSet() = default;
 
-  /// Copy constructor.
-  /// @param s the set to copy
-  constexpr EnumSet(const EnumSet& s) = default;
+    /// Copy constructor.
+    /// @param s the set to copy
+    constexpr EnumSet(const EnumSet& s) = default;
 
-  /// Constructor. Initializes the EnumSet with the given values.
-  /// @param values the enumerator values to construct the set with
-  template <typename... VALUES>
-  explicit constexpr EnumSet(VALUES... values) : set(Union(values...)) {}
+    /// Constructor. Initializes the EnumSet with the given values.
+    /// @param values the enumerator values to construct the set with
+    template <typename... VALUES>
+    explicit constexpr EnumSet(VALUES... values) : set(Union(values...)) {}
 
-  /// Copy assignment operator.
-  /// @param set the set to assign to this set
-  /// @return this set so calls can be chained
-  inline EnumSet& operator=(const EnumSet& set) = default;
+    /// Copy assignment operator.
+    /// @param set the set to assign to this set
+    /// @return this set so calls can be chained
+    inline EnumSet& operator=(const EnumSet& set) = default;
 
-  /// Copy assignment operator.
-  /// @param e the enum value
-  /// @return this set so calls can be chained
-  inline EnumSet& operator=(Enum e) { return *this = EnumSet{e}; }
+    /// Copy assignment operator.
+    /// @param e the enum value
+    /// @return this set so calls can be chained
+    inline EnumSet& operator=(Enum e) { return *this = EnumSet{e}; }
 
-  /// Adds all the given values to this set
-  /// @param values the values to add
-  /// @return this set so calls can be chained
-  template <typename... VALUES>
-  inline EnumSet& Add(VALUES... values) {
-    return Add(EnumSet(std::forward<VALUES>(values)...));
-  }
-
-  /// Removes all the given values from this set
-  /// @param values the values to remove
-  /// @return this set so calls can be chained
-  template <typename... VALUES>
-  inline EnumSet& Remove(VALUES... values) {
-    return Remove(EnumSet(std::forward<VALUES>(values)...));
-  }
-
-  /// Adds all of s to this set
-  /// @param s the enum value
-  /// @return this set so calls can be chained
-  inline EnumSet& Add(EnumSet s) { return (*this = *this + s); }
-
-  /// Removes all of s from this set
-  /// @param s the enum value
-  /// @return this set so calls can be chained
-  inline EnumSet& Remove(EnumSet s) { return (*this = *this - s); }
-
-  /// @param e the enum value
-  /// @returns a copy of this set with e added
-  inline EnumSet operator+(Enum e) const {
-    EnumSet out;
-    out.set = set | Bit(e);
-    return out;
-  }
-
-  /// @param e the enum value
-  /// @returns a copy of this set with e removed
-  inline EnumSet operator-(Enum e) const {
-    EnumSet out;
-    out.set = set & ~Bit(e);
-    return out;
-  }
-
-  /// @param s the other set
-  /// @returns the union of this set with s (this ∪ rhs)
-  inline EnumSet operator+(EnumSet s) const {
-    EnumSet out;
-    out.set = set | s.set;
-    return out;
-  }
-
-  /// @param s the other set
-  /// @returns the set of entries found in this but not in s (this \ s)
-  inline EnumSet operator-(EnumSet s) const {
-    EnumSet out;
-    out.set = set & ~s.set;
-    return out;
-  }
-
-  /// @param s the other set
-  /// @returns the intersection of this set with s (this ∩ rhs)
-  inline EnumSet operator&(EnumSet s) const {
-    EnumSet out;
-    out.set = set & s.set;
-    return out;
-  }
-
-  /// @param e the enum value
-  /// @return true if the set contains `e`
-  inline bool Contains(Enum e) const { return (set & Bit(e)) != 0; }
-
-  /// @return true if the set is empty
-  inline bool Empty() const { return set == 0; }
-
-  /// Equality operator
-  /// @param rhs the other EnumSet to compare this to
-  /// @return true if this EnumSet is equal to rhs
-  inline bool operator==(EnumSet rhs) const { return set == rhs.set; }
-
-  /// Inequality operator
-  /// @param rhs the other EnumSet to compare this to
-  /// @return true if this EnumSet is not equal to rhs
-  inline bool operator!=(EnumSet rhs) const { return set != rhs.set; }
-
-  /// Equality operator
-  /// @param rhs the enum to compare this to
-  /// @return true if this EnumSet only contains `rhs`
-  inline bool operator==(Enum rhs) const { return set == Bit(rhs); }
-
-  /// Inequality operator
-  /// @param rhs the enum to compare this to
-  /// @return false if this EnumSet only contains `rhs`
-  inline bool operator!=(Enum rhs) const { return set != Bit(rhs); }
-
-  /// @return the underlying value for the EnumSet
-  inline uint64_t Value() const { return set; }
-
-  /// Iterator provides read-only, unidirectional iterator over the enums of an
-  /// EnumSet.
-  class Iterator {
-    static constexpr int8_t kEnd = 63;
-
-    Iterator(uint64_t s, int8_t b) : set(s), pos(b) {}
-
-    /// Make the constructor accessible to the EnumSet.
-    friend struct EnumSet;
-
-   public:
-    /// @return the Enum value at this point in the iterator
-    Enum operator*() const { return static_cast<Enum>(pos); }
-
-    /// Increments the iterator
-    /// @returns this iterator
-    Iterator& operator++() {
-      while (pos < kEnd) {
-        pos++;
-        if (set & (static_cast<uint64_t>(1) << static_cast<uint64_t>(pos))) {
-          break;
-        }
-      }
-      return *this;
+    /// Adds all the given values to this set
+    /// @param values the values to add
+    /// @return this set so calls can be chained
+    template <typename... VALUES>
+    inline EnumSet& Add(VALUES... values) {
+        return Add(EnumSet(std::forward<VALUES>(values)...));
     }
 
+    /// Removes all the given values from this set
+    /// @param values the values to remove
+    /// @return this set so calls can be chained
+    template <typename... VALUES>
+    inline EnumSet& Remove(VALUES... values) {
+        return Remove(EnumSet(std::forward<VALUES>(values)...));
+    }
+
+    /// Adds all of s to this set
+    /// @param s the enum value
+    /// @return this set so calls can be chained
+    inline EnumSet& Add(EnumSet s) { return (*this = *this + s); }
+
+    /// Removes all of s from this set
+    /// @param s the enum value
+    /// @return this set so calls can be chained
+    inline EnumSet& Remove(EnumSet s) { return (*this = *this - s); }
+
+    /// @param e the enum value
+    /// @returns a copy of this set with e added
+    inline EnumSet operator+(Enum e) const {
+        EnumSet out;
+        out.set = set | Bit(e);
+        return out;
+    }
+
+    /// @param e the enum value
+    /// @returns a copy of this set with e removed
+    inline EnumSet operator-(Enum e) const {
+        EnumSet out;
+        out.set = set & ~Bit(e);
+        return out;
+    }
+
+    /// @param s the other set
+    /// @returns the union of this set with s (this ∪ rhs)
+    inline EnumSet operator+(EnumSet s) const {
+        EnumSet out;
+        out.set = set | s.set;
+        return out;
+    }
+
+    /// @param s the other set
+    /// @returns the set of entries found in this but not in s (this \ s)
+    inline EnumSet operator-(EnumSet s) const {
+        EnumSet out;
+        out.set = set & ~s.set;
+        return out;
+    }
+
+    /// @param s the other set
+    /// @returns the intersection of this set with s (this ∩ rhs)
+    inline EnumSet operator&(EnumSet s) const {
+        EnumSet out;
+        out.set = set & s.set;
+        return out;
+    }
+
+    /// @param e the enum value
+    /// @return true if the set contains `e`
+    inline bool Contains(Enum e) const { return (set & Bit(e)) != 0; }
+
+    /// @return true if the set is empty
+    inline bool Empty() const { return set == 0; }
+
     /// Equality operator
-    /// @param rhs the Iterator to compare this to
-    /// @return true if the two iterators are equal
-    bool operator==(const Iterator& rhs) const {
-      return set == rhs.set && pos == rhs.pos;
-    }
+    /// @param rhs the other EnumSet to compare this to
+    /// @return true if this EnumSet is equal to rhs
+    inline bool operator==(EnumSet rhs) const { return set == rhs.set; }
 
     /// Inequality operator
-    /// @param rhs the Iterator to compare this to
-    /// @return true if the two iterators are different
-    bool operator!=(const Iterator& rhs) const { return !(*this == rhs); }
+    /// @param rhs the other EnumSet to compare this to
+    /// @return true if this EnumSet is not equal to rhs
+    inline bool operator!=(EnumSet rhs) const { return set != rhs.set; }
 
-   private:
-    const uint64_t set;
-    int8_t pos;
-  };
+    /// Equality operator
+    /// @param rhs the enum to compare this to
+    /// @return true if this EnumSet only contains `rhs`
+    inline bool operator==(Enum rhs) const { return set == Bit(rhs); }
 
-  /// @returns an read-only iterator to the beginning of the set
-  Iterator begin() {
-    auto it = Iterator{set, -1};
-    ++it;  // Move to first set bit
-    return it;
-  }
+    /// Inequality operator
+    /// @param rhs the enum to compare this to
+    /// @return false if this EnumSet only contains `rhs`
+    inline bool operator!=(Enum rhs) const { return set != Bit(rhs); }
 
-  /// @returns an iterator to the beginning of the set
-  Iterator end() { return Iterator{set, Iterator::kEnd}; }
+    /// @return the underlying value for the EnumSet
+    inline uint64_t Value() const { return set; }
 
- private:
-  static constexpr uint64_t Bit(Enum value) {
-    return static_cast<uint64_t>(1) << static_cast<uint64_t>(value);
-  }
+    /// Iterator provides read-only, unidirectional iterator over the enums of an
+    /// EnumSet.
+    class Iterator {
+        static constexpr int8_t kEnd = 63;
 
-  static constexpr uint64_t Union() { return 0; }
+        Iterator(uint64_t s, int8_t b) : set(s), pos(b) {}
 
-  template <typename FIRST, typename... VALUES>
-  static constexpr uint64_t Union(FIRST first, VALUES... values) {
-    return Bit(first) | Union(values...);
-  }
+        /// Make the constructor accessible to the EnumSet.
+        friend struct EnumSet;
 
-  uint64_t set = 0;
+      public:
+        /// @return the Enum value at this point in the iterator
+        Enum operator*() const { return static_cast<Enum>(pos); }
+
+        /// Increments the iterator
+        /// @returns this iterator
+        Iterator& operator++() {
+            while (pos < kEnd) {
+                pos++;
+                if (set & (static_cast<uint64_t>(1) << static_cast<uint64_t>(pos))) {
+                    break;
+                }
+            }
+            return *this;
+        }
+
+        /// Equality operator
+        /// @param rhs the Iterator to compare this to
+        /// @return true if the two iterators are equal
+        bool operator==(const Iterator& rhs) const { return set == rhs.set && pos == rhs.pos; }
+
+        /// Inequality operator
+        /// @param rhs the Iterator to compare this to
+        /// @return true if the two iterators are different
+        bool operator!=(const Iterator& rhs) const { return !(*this == rhs); }
+
+      private:
+        const uint64_t set;
+        int8_t pos;
+    };
+
+    /// @returns an read-only iterator to the beginning of the set
+    Iterator begin() {
+        auto it = Iterator{set, -1};
+        ++it;  // Move to first set bit
+        return it;
+    }
+
+    /// @returns an iterator to the beginning of the set
+    Iterator end() { return Iterator{set, Iterator::kEnd}; }
+
+  private:
+    static constexpr uint64_t Bit(Enum value) {
+        return static_cast<uint64_t>(1) << static_cast<uint64_t>(value);
+    }
+
+    static constexpr uint64_t Union() { return 0; }
+
+    template <typename FIRST, typename... VALUES>
+    static constexpr uint64_t Union(FIRST first, VALUES... values) {
+        return Bit(first) | Union(values...);
+    }
+
+    uint64_t set = 0;
 };
 
 /// Writes the EnumSet to the std::ostream.
@@ -224,16 +222,16 @@
 /// @returns out so calls can be chained
 template <typename ENUM>
 inline std::ostream& operator<<(std::ostream& out, EnumSet<ENUM> set) {
-  out << "{";
-  bool first = true;
-  for (auto e : set) {
-    if (!first) {
-      out << ", ";
+    out << "{";
+    bool first = true;
+    for (auto e : set) {
+        if (!first) {
+            out << ", ";
+        }
+        first = false;
+        out << e;
     }
-    first = false;
-    out << e;
-  }
-  return out << "}";
+    return out << "}";
 }
 
 }  // namespace tint::utils
@@ -243,12 +241,12 @@
 /// Custom std::hash specialization for tint::utils::EnumSet<T>
 template <typename T>
 class hash<tint::utils::EnumSet<T>> {
- public:
-  /// @param e the EnumSet to create a hash for
-  /// @return the hash value
-  inline std::size_t operator()(const tint::utils::EnumSet<T>& e) const {
-    return std::hash<uint64_t>()(e.Value());
-  }
+  public:
+    /// @param e the EnumSet to create a hash for
+    /// @return the hash value
+    inline std::size_t operator()(const tint::utils::EnumSet<T>& e) const {
+        return std::hash<uint64_t>()(e.Value());
+    }
 };
 
 }  // namespace std
diff --git a/src/tint/utils/enum_set_test.cc b/src/tint/utils/enum_set_test.cc
index f0e4e67..e469650 100644
--- a/src/tint/utils/enum_set_test.cc
+++ b/src/tint/utils/enum_set_test.cc
@@ -27,215 +27,215 @@
 enum class E { A = 0, B = 3, C = 7 };
 
 std::ostream& operator<<(std::ostream& out, E e) {
-  switch (e) {
-    case E::A:
-      return out << "A";
-    case E::B:
-      return out << "B";
-    case E::C:
-      return out << "C";
-  }
-  return out << "E(" << static_cast<uint32_t>(e) << ")";
+    switch (e) {
+        case E::A:
+            return out << "A";
+        case E::B:
+            return out << "B";
+        case E::C:
+            return out << "C";
+    }
+    return out << "E(" << static_cast<uint32_t>(e) << ")";
 }
 
 TEST(EnumSetTest, ConstructEmpty) {
-  EnumSet<E> set;
-  EXPECT_FALSE(set.Contains(E::A));
-  EXPECT_FALSE(set.Contains(E::B));
-  EXPECT_FALSE(set.Contains(E::C));
-  EXPECT_TRUE(set.Empty());
+    EnumSet<E> set;
+    EXPECT_FALSE(set.Contains(E::A));
+    EXPECT_FALSE(set.Contains(E::B));
+    EXPECT_FALSE(set.Contains(E::C));
+    EXPECT_TRUE(set.Empty());
 }
 
 TEST(EnumSetTest, ConstructWithSingle) {
-  EnumSet<E> set(E::B);
-  EXPECT_FALSE(set.Contains(E::A));
-  EXPECT_TRUE(set.Contains(E::B));
-  EXPECT_FALSE(set.Contains(E::C));
-  EXPECT_FALSE(set.Empty());
+    EnumSet<E> set(E::B);
+    EXPECT_FALSE(set.Contains(E::A));
+    EXPECT_TRUE(set.Contains(E::B));
+    EXPECT_FALSE(set.Contains(E::C));
+    EXPECT_FALSE(set.Empty());
 }
 
 TEST(EnumSetTest, ConstructWithMultiple) {
-  EnumSet<E> set(E::A, E::C);
-  EXPECT_TRUE(set.Contains(E::A));
-  EXPECT_FALSE(set.Contains(E::B));
-  EXPECT_TRUE(set.Contains(E::C));
-  EXPECT_FALSE(set.Empty());
+    EnumSet<E> set(E::A, E::C);
+    EXPECT_TRUE(set.Contains(E::A));
+    EXPECT_FALSE(set.Contains(E::B));
+    EXPECT_TRUE(set.Contains(E::C));
+    EXPECT_FALSE(set.Empty());
 }
 
 TEST(EnumSetTest, AssignSet) {
-  EnumSet<E> set;
-  set = EnumSet<E>(E::A, E::C);
-  EXPECT_TRUE(set.Contains(E::A));
-  EXPECT_FALSE(set.Contains(E::B));
-  EXPECT_TRUE(set.Contains(E::C));
+    EnumSet<E> set;
+    set = EnumSet<E>(E::A, E::C);
+    EXPECT_TRUE(set.Contains(E::A));
+    EXPECT_FALSE(set.Contains(E::B));
+    EXPECT_TRUE(set.Contains(E::C));
 }
 
 TEST(EnumSetTest, AssignEnum) {
-  EnumSet<E> set(E::A);
-  set = E::B;
-  EXPECT_FALSE(set.Contains(E::A));
-  EXPECT_TRUE(set.Contains(E::B));
-  EXPECT_FALSE(set.Contains(E::C));
+    EnumSet<E> set(E::A);
+    set = E::B;
+    EXPECT_FALSE(set.Contains(E::A));
+    EXPECT_TRUE(set.Contains(E::B));
+    EXPECT_FALSE(set.Contains(E::C));
 }
 
 TEST(EnumSetTest, AddEnum) {
-  EnumSet<E> set;
-  set.Add(E::B);
-  EXPECT_FALSE(set.Contains(E::A));
-  EXPECT_TRUE(set.Contains(E::B));
-  EXPECT_FALSE(set.Contains(E::C));
+    EnumSet<E> set;
+    set.Add(E::B);
+    EXPECT_FALSE(set.Contains(E::A));
+    EXPECT_TRUE(set.Contains(E::B));
+    EXPECT_FALSE(set.Contains(E::C));
 }
 
 TEST(EnumSetTest, RemoveEnum) {
-  EnumSet<E> set(E::A, E::B);
-  set.Remove(E::B);
-  EXPECT_TRUE(set.Contains(E::A));
-  EXPECT_FALSE(set.Contains(E::B));
-  EXPECT_FALSE(set.Contains(E::C));
+    EnumSet<E> set(E::A, E::B);
+    set.Remove(E::B);
+    EXPECT_TRUE(set.Contains(E::A));
+    EXPECT_FALSE(set.Contains(E::B));
+    EXPECT_FALSE(set.Contains(E::C));
 }
 
 TEST(EnumSetTest, AddEnums) {
-  EnumSet<E> set;
-  set.Add(E::B, E::C);
-  EXPECT_FALSE(set.Contains(E::A));
-  EXPECT_TRUE(set.Contains(E::B));
-  EXPECT_TRUE(set.Contains(E::C));
+    EnumSet<E> set;
+    set.Add(E::B, E::C);
+    EXPECT_FALSE(set.Contains(E::A));
+    EXPECT_TRUE(set.Contains(E::B));
+    EXPECT_TRUE(set.Contains(E::C));
 }
 
 TEST(EnumSetTest, RemoveEnums) {
-  EnumSet<E> set(E::A, E::B);
-  set.Remove(E::C, E::B);
-  EXPECT_TRUE(set.Contains(E::A));
-  EXPECT_FALSE(set.Contains(E::B));
-  EXPECT_FALSE(set.Contains(E::C));
+    EnumSet<E> set(E::A, E::B);
+    set.Remove(E::C, E::B);
+    EXPECT_TRUE(set.Contains(E::A));
+    EXPECT_FALSE(set.Contains(E::B));
+    EXPECT_FALSE(set.Contains(E::C));
 }
 
 TEST(EnumSetTest, AddEnumSet) {
-  EnumSet<E> set;
-  set.Add(EnumSet<E>{E::B, E::C});
-  EXPECT_FALSE(set.Contains(E::A));
-  EXPECT_TRUE(set.Contains(E::B));
-  EXPECT_TRUE(set.Contains(E::C));
+    EnumSet<E> set;
+    set.Add(EnumSet<E>{E::B, E::C});
+    EXPECT_FALSE(set.Contains(E::A));
+    EXPECT_TRUE(set.Contains(E::B));
+    EXPECT_TRUE(set.Contains(E::C));
 }
 
 TEST(EnumSetTest, RemoveEnumSet) {
-  EnumSet<E> set(E::A, E::B);
-  set.Remove(EnumSet<E>{E::B, E::C});
-  EXPECT_TRUE(set.Contains(E::A));
-  EXPECT_FALSE(set.Contains(E::B));
-  EXPECT_FALSE(set.Contains(E::C));
+    EnumSet<E> set(E::A, E::B);
+    set.Remove(EnumSet<E>{E::B, E::C});
+    EXPECT_TRUE(set.Contains(E::A));
+    EXPECT_FALSE(set.Contains(E::B));
+    EXPECT_FALSE(set.Contains(E::C));
 }
 
 TEST(EnumSetTest, OperatorPlusEnum) {
-  EnumSet<E> set = EnumSet<E>{E::B} + E::C;
-  EXPECT_FALSE(set.Contains(E::A));
-  EXPECT_TRUE(set.Contains(E::B));
-  EXPECT_TRUE(set.Contains(E::C));
+    EnumSet<E> set = EnumSet<E>{E::B} + E::C;
+    EXPECT_FALSE(set.Contains(E::A));
+    EXPECT_TRUE(set.Contains(E::B));
+    EXPECT_TRUE(set.Contains(E::C));
 }
 
 TEST(EnumSetTest, OperatorMinusEnum) {
-  EnumSet<E> set = EnumSet<E>{E::A, E::B} - E::B;
-  EXPECT_TRUE(set.Contains(E::A));
-  EXPECT_FALSE(set.Contains(E::B));
-  EXPECT_FALSE(set.Contains(E::C));
+    EnumSet<E> set = EnumSet<E>{E::A, E::B} - E::B;
+    EXPECT_TRUE(set.Contains(E::A));
+    EXPECT_FALSE(set.Contains(E::B));
+    EXPECT_FALSE(set.Contains(E::C));
 }
 
 TEST(EnumSetTest, OperatorPlusSet) {
-  EnumSet<E> set = EnumSet<E>{E::B} + EnumSet<E>{E::B, E::C};
-  EXPECT_FALSE(set.Contains(E::A));
-  EXPECT_TRUE(set.Contains(E::B));
-  EXPECT_TRUE(set.Contains(E::C));
+    EnumSet<E> set = EnumSet<E>{E::B} + EnumSet<E>{E::B, E::C};
+    EXPECT_FALSE(set.Contains(E::A));
+    EXPECT_TRUE(set.Contains(E::B));
+    EXPECT_TRUE(set.Contains(E::C));
 }
 
 TEST(EnumSetTest, OperatorMinusSet) {
-  EnumSet<E> set = EnumSet<E>{E::A, E::B} - EnumSet<E>{E::B, E::C};
-  EXPECT_TRUE(set.Contains(E::A));
-  EXPECT_FALSE(set.Contains(E::B));
-  EXPECT_FALSE(set.Contains(E::C));
+    EnumSet<E> set = EnumSet<E>{E::A, E::B} - EnumSet<E>{E::B, E::C};
+    EXPECT_TRUE(set.Contains(E::A));
+    EXPECT_FALSE(set.Contains(E::B));
+    EXPECT_FALSE(set.Contains(E::C));
 }
 
 TEST(EnumSetTest, OperatorAnd) {
-  EnumSet<E> set = EnumSet<E>{E::A, E::B} & EnumSet<E>{E::B, E::C};
-  EXPECT_FALSE(set.Contains(E::A));
-  EXPECT_TRUE(set.Contains(E::B));
-  EXPECT_FALSE(set.Contains(E::C));
+    EnumSet<E> set = EnumSet<E>{E::A, E::B} & EnumSet<E>{E::B, E::C};
+    EXPECT_FALSE(set.Contains(E::A));
+    EXPECT_TRUE(set.Contains(E::B));
+    EXPECT_FALSE(set.Contains(E::C));
 }
 
 TEST(EnumSetTest, EqualitySet) {
-  EXPECT_TRUE(EnumSet<E>(E::A, E::B) == EnumSet<E>(E::A, E::B));
-  EXPECT_FALSE(EnumSet<E>(E::A, E::B) == EnumSet<E>(E::A, E::C));
+    EXPECT_TRUE(EnumSet<E>(E::A, E::B) == EnumSet<E>(E::A, E::B));
+    EXPECT_FALSE(EnumSet<E>(E::A, E::B) == EnumSet<E>(E::A, E::C));
 }
 
 TEST(EnumSetTest, InequalitySet) {
-  EXPECT_FALSE(EnumSet<E>(E::A, E::B) != EnumSet<E>(E::A, E::B));
-  EXPECT_TRUE(EnumSet<E>(E::A, E::B) != EnumSet<E>(E::A, E::C));
+    EXPECT_FALSE(EnumSet<E>(E::A, E::B) != EnumSet<E>(E::A, E::B));
+    EXPECT_TRUE(EnumSet<E>(E::A, E::B) != EnumSet<E>(E::A, E::C));
 }
 
 TEST(EnumSetTest, EqualityEnum) {
-  EXPECT_TRUE(EnumSet<E>(E::A) == E::A);
-  EXPECT_FALSE(EnumSet<E>(E::B) == E::A);
-  EXPECT_FALSE(EnumSet<E>(E::B) == E::C);
-  EXPECT_FALSE(EnumSet<E>(E::A, E::B) == E::A);
-  EXPECT_FALSE(EnumSet<E>(E::A, E::B) == E::B);
-  EXPECT_FALSE(EnumSet<E>(E::A, E::B) == E::C);
+    EXPECT_TRUE(EnumSet<E>(E::A) == E::A);
+    EXPECT_FALSE(EnumSet<E>(E::B) == E::A);
+    EXPECT_FALSE(EnumSet<E>(E::B) == E::C);
+    EXPECT_FALSE(EnumSet<E>(E::A, E::B) == E::A);
+    EXPECT_FALSE(EnumSet<E>(E::A, E::B) == E::B);
+    EXPECT_FALSE(EnumSet<E>(E::A, E::B) == E::C);
 }
 
 TEST(EnumSetTest, InequalityEnum) {
-  EXPECT_FALSE(EnumSet<E>(E::A) != E::A);
-  EXPECT_TRUE(EnumSet<E>(E::B) != E::A);
-  EXPECT_TRUE(EnumSet<E>(E::B) != E::C);
-  EXPECT_TRUE(EnumSet<E>(E::A, E::B) != E::A);
-  EXPECT_TRUE(EnumSet<E>(E::A, E::B) != E::B);
-  EXPECT_TRUE(EnumSet<E>(E::A, E::B) != E::C);
+    EXPECT_FALSE(EnumSet<E>(E::A) != E::A);
+    EXPECT_TRUE(EnumSet<E>(E::B) != E::A);
+    EXPECT_TRUE(EnumSet<E>(E::B) != E::C);
+    EXPECT_TRUE(EnumSet<E>(E::A, E::B) != E::A);
+    EXPECT_TRUE(EnumSet<E>(E::A, E::B) != E::B);
+    EXPECT_TRUE(EnumSet<E>(E::A, E::B) != E::C);
 }
 
 TEST(EnumSetTest, Hash) {
-  auto hash = [&](EnumSet<E> s) { return std::hash<EnumSet<E>>()(s); };
-  EXPECT_EQ(hash(EnumSet<E>(E::A, E::B)), hash(EnumSet<E>(E::A, E::B)));
-  EXPECT_NE(hash(EnumSet<E>(E::A, E::B)), hash(EnumSet<E>(E::A, E::C)));
+    auto hash = [&](EnumSet<E> s) { return std::hash<EnumSet<E>>()(s); };
+    EXPECT_EQ(hash(EnumSet<E>(E::A, E::B)), hash(EnumSet<E>(E::A, E::B)));
+    EXPECT_NE(hash(EnumSet<E>(E::A, E::B)), hash(EnumSet<E>(E::A, E::C)));
 }
 
 TEST(EnumSetTest, Value) {
-  EXPECT_EQ(EnumSet<E>().Value(), 0u);
-  EXPECT_EQ(EnumSet<E>(E::A).Value(), 1u);
-  EXPECT_EQ(EnumSet<E>(E::B).Value(), 8u);
-  EXPECT_EQ(EnumSet<E>(E::C).Value(), 128u);
-  EXPECT_EQ(EnumSet<E>(E::A, E::C).Value(), 129u);
+    EXPECT_EQ(EnumSet<E>().Value(), 0u);
+    EXPECT_EQ(EnumSet<E>(E::A).Value(), 1u);
+    EXPECT_EQ(EnumSet<E>(E::B).Value(), 8u);
+    EXPECT_EQ(EnumSet<E>(E::C).Value(), 128u);
+    EXPECT_EQ(EnumSet<E>(E::A, E::C).Value(), 129u);
 }
 
 TEST(EnumSetTest, Iterator) {
-  auto set = EnumSet<E>(E::C, E::A);
+    auto set = EnumSet<E>(E::C, E::A);
 
-  auto it = set.begin();
-  EXPECT_EQ(*it, E::A);
-  EXPECT_NE(it, set.end());
-  ++it;
-  EXPECT_EQ(*it, E::C);
-  EXPECT_NE(it, set.end());
-  ++it;
-  EXPECT_EQ(it, set.end());
+    auto it = set.begin();
+    EXPECT_EQ(*it, E::A);
+    EXPECT_NE(it, set.end());
+    ++it;
+    EXPECT_EQ(*it, E::C);
+    EXPECT_NE(it, set.end());
+    ++it;
+    EXPECT_EQ(it, set.end());
 }
 
 TEST(EnumSetTest, IteratorEmpty) {
-  auto set = EnumSet<E>();
-  EXPECT_EQ(set.begin(), set.end());
+    auto set = EnumSet<E>();
+    EXPECT_EQ(set.begin(), set.end());
 }
 
 TEST(EnumSetTest, Loop) {
-  auto set = EnumSet<E>(E::C, E::A);
+    auto set = EnumSet<E>(E::C, E::A);
 
-  std::vector<E> seen;
-  for (auto e : set) {
-    seen.emplace_back(e);
-  }
+    std::vector<E> seen;
+    for (auto e : set) {
+        seen.emplace_back(e);
+    }
 
-  EXPECT_THAT(seen, ElementsAre(E::A, E::C));
+    EXPECT_THAT(seen, ElementsAre(E::A, E::C));
 }
 
 TEST(EnumSetTest, Ostream) {
-  std::stringstream ss;
-  ss << EnumSet<E>(E::A, E::C);
-  EXPECT_EQ(ss.str(), "{A, C}");
+    std::stringstream ss;
+    ss << EnumSet<E>(E::A, E::C);
+    EXPECT_EQ(ss.str(), "{A, C}");
 }
 
 }  // namespace
diff --git a/src/tint/utils/hash.h b/src/tint/utils/hash.h
index e043e81..1bc2edb 100644
--- a/src/tint/utils/hash.h
+++ b/src/tint/utils/hash.h
@@ -18,6 +18,7 @@
 #include <stdint.h>
 #include <cstdio>
 #include <functional>
+#include <utility>
 #include <vector>
 
 namespace tint::utils {
@@ -31,15 +32,15 @@
 /// Specialization of HashCombineOffset for size_t == 4.
 template <>
 struct HashCombineOffset<4> {
-  /// @returns the seed bias value for HashCombine()
-  static constexpr inline uint32_t value() { return 0x7f4a7c16; }
+    /// @returns the seed bias value for HashCombine()
+    static constexpr inline uint32_t value() { return 0x7f4a7c16; }
 };
 
 /// Specialization of HashCombineOffset for size_t == 8.
 template <>
 struct HashCombineOffset<8> {
-  /// @returns the seed bias value for HashCombine()
-  static constexpr inline uint64_t value() { return 0x9e3779b97f4a7c16; }
+    /// @returns the seed bias value for HashCombine()
+    static constexpr inline uint64_t value() { return 0x9e3779b97f4a7c16; }
 };
 
 }  // namespace detail
@@ -47,35 +48,76 @@
 /// HashCombine "hashes" together an existing hash and hashable values.
 template <typename T>
 void HashCombine(size_t* hash, const T& value) {
-  constexpr size_t offset = detail::HashCombineOffset<sizeof(size_t)>::value();
-  *hash ^= std::hash<T>()(value) + offset + (*hash << 6) + (*hash >> 2);
+    constexpr size_t offset = detail::HashCombineOffset<sizeof(size_t)>::value();
+    *hash ^= std::hash<T>()(value) + offset + (*hash << 6) + (*hash >> 2);
 }
 
 /// HashCombine "hashes" together an existing hash and hashable values.
 template <typename T>
 void HashCombine(size_t* hash, const std::vector<T>& vector) {
-  HashCombine(hash, vector.size());
-  for (auto& el : vector) {
-    HashCombine(hash, el);
-  }
+    HashCombine(hash, vector.size());
+    for (auto& el : vector) {
+        HashCombine(hash, el);
+    }
 }
 
 /// HashCombine "hashes" together an existing hash and hashable values.
 template <typename T, typename... ARGS>
 void HashCombine(size_t* hash, const T& value, const ARGS&... args) {
-  HashCombine(hash, value);
-  HashCombine(hash, args...);
+    HashCombine(hash, value);
+    HashCombine(hash, args...);
 }
 
 /// @returns a hash of the combined arguments. The returned hash is dependent on
 /// the order of the arguments.
 template <typename... ARGS>
 size_t Hash(const ARGS&... args) {
-  size_t hash = 102931;  // seed with an arbitrary prime
-  HashCombine(&hash, args...);
-  return hash;
+    size_t hash = 102931;  // seed with an arbitrary prime
+    HashCombine(&hash, args...);
+    return hash;
 }
 
+/// Wrapper for a hashable type enabling the wrapped value to be used as a key
+/// for an unordered_map or unordered_set.
+template <typename T>
+struct UnorderedKeyWrapper {
+    /// The wrapped value
+    const T value;
+    /// The hash of value
+    const size_t hash;
+
+    /// Constructor
+    /// @param v the value to wrap
+    explicit UnorderedKeyWrapper(const T& v) : value(v), hash(Hash(v)) {}
+
+    /// Move constructor
+    /// @param v the value to wrap
+    explicit UnorderedKeyWrapper(T&& v) : value(std::move(v)), hash(Hash(value)) {}
+
+    /// @returns true if this wrapper comes before other
+    /// @param other the RHS of the operator
+    bool operator<(const UnorderedKeyWrapper& other) const { return hash < other.hash; }
+
+    /// @returns true if this wrapped value is equal to the other wrapped value
+    /// @param other the RHS of the operator
+    bool operator==(const UnorderedKeyWrapper& other) const { return value == other.value; }
+};
+
 }  // namespace tint::utils
 
+namespace std {
+
+/// Custom std::hash specialization for tint::utils::UnorderedKeyWrapper
+template <typename T>
+class hash<tint::utils::UnorderedKeyWrapper<T>> {
+  public:
+    /// @param w the UnorderedKeyWrapper
+    /// @return the hash value
+    inline std::size_t operator()(const tint::utils::UnorderedKeyWrapper<T>& w) const {
+        return w.hash;
+    }
+};
+
+}  // namespace std
+
 #endif  // SRC_TINT_UTILS_HASH_H_
diff --git a/src/tint/utils/hash_test.cc b/src/tint/utils/hash_test.cc
index ec88a8c..068ac45 100644
--- a/src/tint/utils/hash_test.cc
+++ b/src/tint/utils/hash_test.cc
@@ -15,6 +15,7 @@
 #include "src/tint/utils/hash.h"
 
 #include <string>
+#include <unordered_map>
 
 #include "gtest/gtest.h"
 
@@ -22,25 +23,47 @@
 namespace {
 
 TEST(HashTests, Basic) {
-  EXPECT_EQ(Hash(123), Hash(123));
-  EXPECT_NE(Hash(123), Hash(321));
-  EXPECT_EQ(Hash(123, 456), Hash(123, 456));
-  EXPECT_NE(Hash(123, 456), Hash(456, 123));
-  EXPECT_NE(Hash(123, 456), Hash(123));
-  EXPECT_EQ(Hash(123, 456, false), Hash(123, 456, false));
-  EXPECT_NE(Hash(123, 456, false), Hash(123, 456));
-  EXPECT_EQ(Hash(std::string("hello")), Hash(std::string("hello")));
-  EXPECT_NE(Hash(std::string("hello")), Hash(std::string("world")));
+    EXPECT_EQ(Hash(123), Hash(123));
+    EXPECT_NE(Hash(123), Hash(321));
+    EXPECT_EQ(Hash(123, 456), Hash(123, 456));
+    EXPECT_NE(Hash(123, 456), Hash(456, 123));
+    EXPECT_NE(Hash(123, 456), Hash(123));
+    EXPECT_EQ(Hash(123, 456, false), Hash(123, 456, false));
+    EXPECT_NE(Hash(123, 456, false), Hash(123, 456));
+    EXPECT_EQ(Hash(std::string("hello")), Hash(std::string("hello")));
+    EXPECT_NE(Hash(std::string("hello")), Hash(std::string("world")));
 }
 
 TEST(HashTests, Vector) {
-  EXPECT_EQ(Hash(std::vector<int>({})), Hash(std::vector<int>({})));
-  EXPECT_EQ(Hash(std::vector<int>({1, 2, 3})),
-            Hash(std::vector<int>({1, 2, 3})));
-  EXPECT_NE(Hash(std::vector<int>({1, 2, 3})),
-            Hash(std::vector<int>({1, 2, 4})));
-  EXPECT_NE(Hash(std::vector<int>({1, 2, 3})),
-            Hash(std::vector<int>({1, 2, 3, 4})));
+    EXPECT_EQ(Hash(std::vector<int>({})), Hash(std::vector<int>({})));
+    EXPECT_EQ(Hash(std::vector<int>({1, 2, 3})), Hash(std::vector<int>({1, 2, 3})));
+    EXPECT_NE(Hash(std::vector<int>({1, 2, 3})), Hash(std::vector<int>({1, 2, 4})));
+    EXPECT_NE(Hash(std::vector<int>({1, 2, 3})), Hash(std::vector<int>({1, 2, 3, 4})));
+}
+
+TEST(HashTests, UnorderedKeyWrapper) {
+    using W = UnorderedKeyWrapper<std::vector<int>>;
+
+    std::unordered_map<W, int> m;
+
+    m.emplace(W{{1, 2}}, -1);
+    EXPECT_EQ(m.size(), 1u);
+    EXPECT_EQ(m[W({1, 2})], -1);
+
+    m.emplace(W{{3, 2}}, 1);
+    EXPECT_EQ(m.size(), 2u);
+    EXPECT_EQ(m[W({3, 2})], 1);
+    EXPECT_EQ(m[W({1, 2})], -1);
+
+    m.emplace(W{{100}}, 100);
+    EXPECT_EQ(m.size(), 3u);
+    EXPECT_EQ(m[W({100})], 100);
+    EXPECT_EQ(m[W({3, 2})], 1);
+    EXPECT_EQ(m[W({1, 2})], -1);
+
+    // Reversed vector element order
+    EXPECT_EQ(m[W({2, 3})], 0);
+    EXPECT_EQ(m[W({2, 1})], 0);
 }
 
 }  // namespace
diff --git a/src/tint/utils/io/command.h b/src/tint/utils/io/command.h
index 63ddab8..8aae691 100644
--- a/src/tint/utils/io/command.h
+++ b/src/tint/utils/io/command.h
@@ -24,57 +24,57 @@
 /// arguments and an optional stdin string, and then collecting and returning
 /// the process's stdout and stderr output as strings.
 class Command {
- public:
-  /// Output holds the output of the process
-  struct Output {
-    /// stdout from the process
-    std::string out;
-    /// stderr from the process
-    std::string err;
-    /// process error code
-    int error_code = 0;
-  };
+  public:
+    /// Output holds the output of the process
+    struct Output {
+        /// stdout from the process
+        std::string out;
+        /// stderr from the process
+        std::string err;
+        /// process error code
+        int error_code = 0;
+    };
 
-  /// Constructor
-  /// @param path path to the executable
-  explicit Command(const std::string& path);
+    /// Constructor
+    /// @param path path to the executable
+    explicit Command(const std::string& path);
 
-  /// Looks for an executable with the given name in the current working
-  /// directory, and if not found there, in each of the directories in the
-  /// `PATH` environment variable.
-  /// @param executable the executable name
-  /// @returns a Command which will return true for Found() if the executable
-  /// was found.
-  static Command LookPath(const std::string& executable);
+    /// Looks for an executable with the given name in the current working
+    /// directory, and if not found there, in each of the directories in the
+    /// `PATH` environment variable.
+    /// @param executable the executable name
+    /// @returns a Command which will return true for Found() if the executable
+    /// was found.
+    static Command LookPath(const std::string& executable);
 
-  /// @return true if the executable exists at the path provided to the
-  /// constructor
-  bool Found() const;
+    /// @return true if the executable exists at the path provided to the
+    /// constructor
+    bool Found() const;
 
-  /// @returns the path of the command
-  const std::string& Path() const { return path_; }
+    /// @returns the path of the command
+    const std::string& Path() const { return path_; }
 
-  /// Invokes the command with the given argument strings, blocking until the
-  /// process has returned.
-  /// @param args the string arguments to pass to the process
-  /// @returns the process output
-  template <typename... ARGS>
-  Output operator()(ARGS... args) const {
-    return Exec({std::forward<ARGS>(args)...});
-  }
+    /// Invokes the command with the given argument strings, blocking until the
+    /// process has returned.
+    /// @param args the string arguments to pass to the process
+    /// @returns the process output
+    template <typename... ARGS>
+    Output operator()(ARGS... args) const {
+        return Exec({std::forward<ARGS>(args)...});
+    }
 
-  /// Exec invokes the command with the given argument strings, blocking until
-  /// the process has returned.
-  /// @param args the string arguments to pass to the process
-  /// @returns the process output
-  Output Exec(std::initializer_list<std::string> args) const;
+    /// Exec invokes the command with the given argument strings, blocking until
+    /// the process has returned.
+    /// @param args the string arguments to pass to the process
+    /// @returns the process output
+    Output Exec(std::initializer_list<std::string> args) const;
 
-  /// @param input the input data to pipe to the process's stdin
-  void SetInput(const std::string& input) { input_ = input; }
+    /// @param input the input data to pipe to the process's stdin
+    void SetInput(const std::string& input) { input_ = input; }
 
- private:
-  std::string const path_;
-  std::string input_;
+  private:
+    std::string const path_;
+    std::string input_;
 };
 
 }  // namespace tint::utils
diff --git a/src/tint/utils/io/command_other.cc b/src/tint/utils/io/command_other.cc
index 5ae73da..cc1997b 100644
--- a/src/tint/utils/io/command_other.cc
+++ b/src/tint/utils/io/command_other.cc
@@ -19,17 +19,17 @@
 Command::Command(const std::string&) {}
 
 Command Command::LookPath(const std::string&) {
-  return Command("");
+    return Command("");
 }
 
 bool Command::Found() const {
-  return false;
+    return false;
 }
 
 Command::Output Command::Exec(std::initializer_list<std::string>) const {
-  Output out;
-  out.err = "Command not supported by this target";
-  return out;
+    Output out;
+    out.err = "Command not supported by this target";
+    return out;
 }
 
 }  // namespace tint::utils
diff --git a/src/tint/utils/io/command_posix.cc b/src/tint/utils/io/command_posix.cc
index 3696921..23ee511 100644
--- a/src/tint/utils/io/command_posix.cc
+++ b/src/tint/utils/io/command_posix.cc
@@ -27,102 +27,102 @@
 
 /// File is a simple wrapper around a POSIX file descriptor
 class File {
-  constexpr static const int kClosed = -1;
+    constexpr static const int kClosed = -1;
 
- public:
-  /// Constructor
-  File() : handle_(kClosed) {}
+  public:
+    /// Constructor
+    File() : handle_(kClosed) {}
 
-  /// Constructor
-  explicit File(int handle) : handle_(handle) {}
+    /// Constructor
+    explicit File(int handle) : handle_(handle) {}
 
-  /// Destructor
-  ~File() { Close(); }
+    /// Destructor
+    ~File() { Close(); }
 
-  /// Move assignment operator
-  File& operator=(File&& rhs) {
-    Close();
-    handle_ = rhs.handle_;
-    rhs.handle_ = kClosed;
-    return *this;
-  }
-
-  /// Closes the file (if it wasn't already closed)
-  void Close() {
-    if (handle_ != kClosed) {
-      close(handle_);
+    /// Move assignment operator
+    File& operator=(File&& rhs) {
+        Close();
+        handle_ = rhs.handle_;
+        rhs.handle_ = kClosed;
+        return *this;
     }
-    handle_ = kClosed;
-  }
 
-  /// @returns the file handle
-  operator int() { return handle_; }
+    /// Closes the file (if it wasn't already closed)
+    void Close() {
+        if (handle_ != kClosed) {
+            close(handle_);
+        }
+        handle_ = kClosed;
+    }
 
-  /// @returns true if the file is not closed
-  operator bool() { return handle_ != kClosed; }
+    /// @returns the file handle
+    operator int() { return handle_; }
 
- private:
-  File(const File&) = delete;
-  File& operator=(const File&) = delete;
+    /// @returns true if the file is not closed
+    operator bool() { return handle_ != kClosed; }
 
-  int handle_ = kClosed;
+  private:
+    File(const File&) = delete;
+    File& operator=(const File&) = delete;
+
+    int handle_ = kClosed;
 };
 
 /// Pipe is a simple wrapper around a POSIX pipe() function
 class Pipe {
- public:
-  /// Constructs the pipe
-  Pipe() {
-    int pipes[2] = {};
-    if (pipe(pipes) == 0) {
-      read = File(pipes[0]);
-      write = File(pipes[1]);
+  public:
+    /// Constructs the pipe
+    Pipe() {
+        int pipes[2] = {};
+        if (pipe(pipes) == 0) {
+            read = File(pipes[0]);
+            write = File(pipes[1]);
+        }
     }
-  }
 
-  /// Closes both the read and write files (if they're not already closed)
-  void Close() {
-    read.Close();
-    write.Close();
-  }
+    /// Closes both the read and write files (if they're not already closed)
+    void Close() {
+        read.Close();
+        write.Close();
+    }
 
-  /// @returns true if the pipe has an open read or write file
-  operator bool() { return read || write; }
+    /// @returns true if the pipe has an open read or write file
+    operator bool() { return read || write; }
 
-  /// The reader end of the pipe
-  File read;
+    /// The reader end of the pipe
+    File read;
 
-  /// The writer end of the pipe
-  File write;
+    /// The writer end of the pipe
+    File write;
 };
 
 bool ExecutableExists(const std::string& path) {
-  struct stat s {};
-  if (stat(path.c_str(), &s) != 0) {
-    return false;
-  }
-  return s.st_mode & S_IXUSR;
+    struct stat s {};
+    if (stat(path.c_str(), &s) != 0) {
+        return false;
+    }
+    return s.st_mode & S_IXUSR;
 }
 
 std::string FindExecutable(const std::string& name) {
-  if (ExecutableExists(name)) {
-    return name;
-  }
-  if (name.find("/") == std::string::npos) {
-    auto* path_env = getenv("PATH");
-    if (!path_env) {
-      return "";
+    if (ExecutableExists(name)) {
+        return name;
     }
-    std::istringstream path{path_env};
-    std::string dir;
-    while (getline(path, dir, ':')) {
-      auto test = dir + "/" + name;
-      if (ExecutableExists(test)) {
-        return test;
-      }
+    if (name.find("/") == std::string::npos) {
+        auto* path_env = getenv("PATH");
+        if (!path_env) {
+            return "";
+        }
+        std::istringstream path{path_env};
+        std::string dir;
+        while (getline(path, dir, ':')) {
+            auto test = dir + "/" + name;
+            if (ExecutableExists(test)) {
+                return test;
+            }
+        }
     }
-  }
-  return "";
+    return "";
 }
 
 }  // namespace
@@ -130,134 +130,133 @@
 Command::Command(const std::string& path) : path_(path) {}
 
 Command Command::LookPath(const std::string& executable) {
-  return Command(FindExecutable(executable));
+    return Command(FindExecutable(executable));
 }
 
 bool Command::Found() const {
-  return ExecutableExists(path_);
+    return ExecutableExists(path_);
 }
 
-Command::Output Command::Exec(
-    std::initializer_list<std::string> arguments) const {
-  if (!Found()) {
-    Output out;
-    out.err = "Executable not found";
-    return out;
-  }
+Command::Output Command::Exec(std::initializer_list<std::string> arguments) const {
+    if (!Found()) {
+        Output out;
+        out.err = "Executable not found";
+        return out;
+    }
 
-  // Pipes used for piping std[in,out,err] to / from the target process.
-  Pipe stdin_pipe;
-  Pipe stdout_pipe;
-  Pipe stderr_pipe;
+    // Pipes used for piping std[in,out,err] to / from the target process.
+    Pipe stdin_pipe;
+    Pipe stdout_pipe;
+    Pipe stderr_pipe;
 
-  if (!stdin_pipe || !stdout_pipe || !stderr_pipe) {
-    Output output;
-    output.err = "Command::Exec(): Failed to create pipes";
-    return output;
-  }
-
-  // execv() and friends replace the current process image with the target
-  // process image. To keep process that called this function going, we need to
-  // fork() this process into a child and parent process.
-  //
-  // The child process is responsible for hooking up the pipes to
-  // std[in,out,err]_pipes to STD[IN,OUT,ERR]_FILENO and then calling execv() to
-  // run the target command.
-  //
-  // The parent process is responsible for feeding any input to the stdin_pipe
-  // and collectting output from the std[out,err]_pipes.
-
-  int child_id = fork();
-  if (child_id < 0) {
-    Output output;
-    output.err = "Command::Exec(): fork() failed";
-    return output;
-  }
-
-  if (child_id > 0) {
-    // fork() - parent
-
-    // Close the stdout and stderr writer pipes.
-    // This is required for getting poll() POLLHUP events.
-    stdout_pipe.write.Close();
-    stderr_pipe.write.Close();
-
-    // Write the input to the child process
-    if (!input_.empty()) {
-      ssize_t n = write(stdin_pipe.write, input_.data(), input_.size());
-      if (n != static_cast<ssize_t>(input_.size())) {
+    if (!stdin_pipe || !stdout_pipe || !stderr_pipe) {
         Output output;
-        output.err = "Command::Exec(): write() for stdin failed";
+        output.err = "Command::Exec(): Failed to create pipes";
         return output;
-      }
     }
-    stdin_pipe.write.Close();
 
-    // Accumulate the stdout and stderr output from the child process
-    pollfd poll_fds[2];
-    poll_fds[0].fd = stdout_pipe.read;
-    poll_fds[0].events = POLLIN;
-    poll_fds[1].fd = stderr_pipe.read;
-    poll_fds[1].events = POLLIN;
+    // execv() and friends replace the current process image with the target
+    // process image. To keep process that called this function going, we need to
+    // fork() this process into a child and parent process.
+    //
+    // The child process is responsible for hooking up the pipes to
+    // std[in,out,err]_pipes to STD[IN,OUT,ERR]_FILENO and then calling execv() to
+    // run the target command.
+    //
+    // The parent process is responsible for feeding any input to the stdin_pipe
+    // and collectting output from the std[out,err]_pipes.
 
-    Output output;
-    bool stdout_open = true;
-    bool stderr_open = true;
-    while (stdout_open || stderr_open) {
-      if (poll(poll_fds, 2, -1) < 0) {
-        break;
-      }
-      char buf[256];
-      if (poll_fds[0].revents & POLLIN) {
-        auto n = read(stdout_pipe.read, buf, sizeof(buf));
-        if (n > 0) {
-          output.out += std::string(buf, buf + n);
+    int child_id = fork();
+    if (child_id < 0) {
+        Output output;
+        output.err = "Command::Exec(): fork() failed";
+        return output;
+    }
+
+    if (child_id > 0) {
+        // fork() - parent
+
+        // Close the stdout and stderr writer pipes.
+        // This is required for getting poll() POLLHUP events.
+        stdout_pipe.write.Close();
+        stderr_pipe.write.Close();
+
+        // Write the input to the child process
+        if (!input_.empty()) {
+            ssize_t n = write(stdin_pipe.write, input_.data(), input_.size());
+            if (n != static_cast<ssize_t>(input_.size())) {
+                Output output;
+                output.err = "Command::Exec(): write() for stdin failed";
+                return output;
+            }
         }
-      }
-      if (poll_fds[0].revents & POLLHUP) {
-        stdout_open = false;
-      }
-      if (poll_fds[1].revents & POLLIN) {
-        auto n = read(stderr_pipe.read, buf, sizeof(buf));
-        if (n > 0) {
-          output.err += std::string(buf, buf + n);
+        stdin_pipe.write.Close();
+
+        // Accumulate the stdout and stderr output from the child process
+        pollfd poll_fds[2];
+        poll_fds[0].fd = stdout_pipe.read;
+        poll_fds[0].events = POLLIN;
+        poll_fds[1].fd = stderr_pipe.read;
+        poll_fds[1].events = POLLIN;
+
+        Output output;
+        bool stdout_open = true;
+        bool stderr_open = true;
+        while (stdout_open || stderr_open) {
+            if (poll(poll_fds, 2, -1) < 0) {
+                break;
+            }
+            char buf[256];
+            if (poll_fds[0].revents & POLLIN) {
+                auto n = read(stdout_pipe.read, buf, sizeof(buf));
+                if (n > 0) {
+                    output.out += std::string(buf, buf + n);
+                }
+            }
+            if (poll_fds[0].revents & POLLHUP) {
+                stdout_open = false;
+            }
+            if (poll_fds[1].revents & POLLIN) {
+                auto n = read(stderr_pipe.read, buf, sizeof(buf));
+                if (n > 0) {
+                    output.err += std::string(buf, buf + n);
+                }
+            }
+            if (poll_fds[1].revents & POLLHUP) {
+                stderr_open = false;
+            }
         }
-      }
-      if (poll_fds[1].revents & POLLHUP) {
-        stderr_open = false;
-      }
+
+        // Get the resulting error code
+        waitpid(child_id, &output.error_code, 0);
+
+        return output;
+    } else {
+        // fork() - child
+
+        // Redirect the stdin, stdout, stderr pipes for the execv process
+        if ((dup2(stdin_pipe.read, STDIN_FILENO) == -1) ||
+            (dup2(stdout_pipe.write, STDOUT_FILENO) == -1) ||
+            (dup2(stderr_pipe.write, STDERR_FILENO) == -1)) {
+            fprintf(stderr, "Command::Exec(): Failed to redirect pipes");
+            exit(errno);
+        }
+
+        // Close the pipes, once redirected above, we're now done with them.
+        stdin_pipe.Close();
+        stdout_pipe.Close();
+        stderr_pipe.Close();
+
+        // Run target executable
+        std::vector<const char*> args;
+        args.emplace_back(path_.c_str());
+        for (auto& arg : arguments) {
+            args.emplace_back(arg.c_str());
+        }
+        args.emplace_back(nullptr);
+        auto res = execv(path_.c_str(), const_cast<char* const*>(args.data()));
+        exit(res);
     }
-
-    // Get the resulting error code
-    waitpid(child_id, &output.error_code, 0);
-
-    return output;
-  } else {
-    // fork() - child
-
-    // Redirect the stdin, stdout, stderr pipes for the execv process
-    if ((dup2(stdin_pipe.read, STDIN_FILENO) == -1) ||
-        (dup2(stdout_pipe.write, STDOUT_FILENO) == -1) ||
-        (dup2(stderr_pipe.write, STDERR_FILENO) == -1)) {
-      fprintf(stderr, "Command::Exec(): Failed to redirect pipes");
-      exit(errno);
-    }
-
-    // Close the pipes, once redirected above, we're now done with them.
-    stdin_pipe.Close();
-    stdout_pipe.Close();
-    stderr_pipe.Close();
-
-    // Run target executable
-    std::vector<const char*> args;
-    args.emplace_back(path_.c_str());
-    for (auto& arg : arguments) {
-      args.emplace_back(arg.c_str());
-    }
-    args.emplace_back(nullptr);
-    auto res = execv(path_.c_str(), const_cast<char* const*>(args.data()));
-    exit(res);
-  }
 }
 
 }  // namespace tint::utils
diff --git a/src/tint/utils/io/command_test.cc b/src/tint/utils/io/command_test.cc
index 1b8bb83..ed7e29a 100644
--- a/src/tint/utils/io/command_test.cc
+++ b/src/tint/utils/io/command_test.cc
@@ -22,66 +22,66 @@
 #ifdef _WIN32
 
 TEST(CommandTest, Echo) {
-  auto cmd = Command::LookPath("cmd");
-  if (!cmd.Found()) {
-    GTEST_SKIP() << "cmd not found on PATH";
-  }
+    auto cmd = Command::LookPath("cmd");
+    if (!cmd.Found()) {
+        GTEST_SKIP() << "cmd not found on PATH";
+    }
 
-  auto res = cmd("/C", "echo", "hello world");
-  EXPECT_EQ(res.error_code, 0);
-  EXPECT_EQ(res.out, "hello world\r\n");
-  EXPECT_EQ(res.err, "");
+    auto res = cmd("/C", "echo", "hello world");
+    EXPECT_EQ(res.error_code, 0);
+    EXPECT_EQ(res.out, "hello world\r\n");
+    EXPECT_EQ(res.err, "");
 }
 
 #else
 
 TEST(CommandTest, Echo) {
-  auto cmd = Command::LookPath("echo");
-  if (!cmd.Found()) {
-    GTEST_SKIP() << "echo not found on PATH";
-  }
+    auto cmd = Command::LookPath("echo");
+    if (!cmd.Found()) {
+        GTEST_SKIP() << "echo not found on PATH";
+    }
 
-  auto res = cmd("hello world");
-  EXPECT_EQ(res.error_code, 0);
-  EXPECT_EQ(res.out, "hello world\n");
-  EXPECT_EQ(res.err, "");
+    auto res = cmd("hello world");
+    EXPECT_EQ(res.error_code, 0);
+    EXPECT_EQ(res.out, "hello world\n");
+    EXPECT_EQ(res.err, "");
 }
 
 TEST(CommandTest, Cat) {
-  auto cmd = Command::LookPath("cat");
-  if (!cmd.Found()) {
-    GTEST_SKIP() << "cat not found on PATH";
-  }
+    auto cmd = Command::LookPath("cat");
+    if (!cmd.Found()) {
+        GTEST_SKIP() << "cat not found on PATH";
+    }
 
-  cmd.SetInput("hello world");
-  auto res = cmd();
-  EXPECT_EQ(res.error_code, 0);
-  EXPECT_EQ(res.out, "hello world");
-  EXPECT_EQ(res.err, "");
+    cmd.SetInput("hello world");
+    auto res = cmd();
+    EXPECT_EQ(res.error_code, 0);
+    EXPECT_EQ(res.out, "hello world");
+    EXPECT_EQ(res.err, "");
 }
 
 TEST(CommandTest, True) {
-  auto cmd = Command::LookPath("true");
-  if (!cmd.Found()) {
-    GTEST_SKIP() << "true not found on PATH";
-  }
+    auto cmd = Command::LookPath("true");
+    if (!cmd.Found()) {
+        GTEST_SKIP() << "true not found on PATH";
+    }
 
-  auto res = cmd();
-  EXPECT_EQ(res.error_code, 0);
-  EXPECT_EQ(res.out, "");
-  EXPECT_EQ(res.err, "");
+    auto res = cmd();
+    EXPECT_EQ(res.error_code, 0);
+    EXPECT_EQ(res.out, "");
+    EXPECT_EQ(res.err, "");
 }
 
 TEST(CommandTest, False) {
-  auto cmd = Command::LookPath("false");
-  if (!cmd.Found()) {
-    GTEST_SKIP() << "false not found on PATH";
-  }
+    auto cmd = Command::LookPath("false");
+    if (!cmd.Found()) {
+        GTEST_SKIP() << "false not found on PATH";
+    }
 
-  auto res = cmd();
-  EXPECT_NE(res.error_code, 0);
-  EXPECT_EQ(res.out, "");
-  EXPECT_EQ(res.err, "");
+    auto res = cmd();
+    EXPECT_NE(res.error_code, 0);
+    EXPECT_EQ(res.out, "");
+    EXPECT_EQ(res.err, "");
 }
 
 #endif
diff --git a/src/tint/utils/io/command_windows.cc b/src/tint/utils/io/command_windows.cc
index d59f849..f953a85 100644
--- a/src/tint/utils/io/command_windows.cc
+++ b/src/tint/utils/io/command_windows.cc
@@ -25,112 +25,110 @@
 
 /// Handle is a simple wrapper around the Win32 HANDLE
 class Handle {
- public:
-  /// Constructor
-  Handle() : handle_(nullptr) {}
+  public:
+    /// Constructor
+    Handle() : handle_(nullptr) {}
 
-  /// Constructor
-  explicit Handle(HANDLE handle) : handle_(handle) {}
+    /// Constructor
+    explicit Handle(HANDLE handle) : handle_(handle) {}
 
-  /// Destructor
-  ~Handle() { Close(); }
+    /// Destructor
+    ~Handle() { Close(); }
 
-  /// Move assignment operator
-  Handle& operator=(Handle&& rhs) {
-    Close();
-    handle_ = rhs.handle_;
-    rhs.handle_ = nullptr;
-    return *this;
-  }
-
-  /// Closes the handle (if it wasn't already closed)
-  void Close() {
-    if (handle_) {
-      CloseHandle(handle_);
+    /// Move assignment operator
+    Handle& operator=(Handle&& rhs) {
+        Close();
+        handle_ = rhs.handle_;
+        rhs.handle_ = nullptr;
+        return *this;
     }
-    handle_ = nullptr;
-  }
 
-  /// @returns the handle
-  operator HANDLE() { return handle_; }
+    /// Closes the handle (if it wasn't already closed)
+    void Close() {
+        if (handle_) {
+            CloseHandle(handle_);
+        }
+        handle_ = nullptr;
+    }
 
-  /// @returns true if the handle is not invalid
-  operator bool() { return handle_ != nullptr; }
+    /// @returns the handle
+    operator HANDLE() { return handle_; }
 
- private:
-  Handle(const Handle&) = delete;
-  Handle& operator=(const Handle&) = delete;
+    /// @returns true if the handle is not invalid
+    operator bool() { return handle_ != nullptr; }
 
-  HANDLE handle_ = nullptr;
+  private:
+    Handle(const Handle&) = delete;
+    Handle& operator=(const Handle&) = delete;
+
+    HANDLE handle_ = nullptr;
 };
 
 /// Pipe is a simple wrapper around a Win32 CreatePipe() function
 class Pipe {
- public:
-  /// Constructs the pipe
-  explicit Pipe(bool for_read) {
-    SECURITY_ATTRIBUTES sa;
-    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
-    sa.bInheritHandle = TRUE;
-    sa.lpSecurityDescriptor = nullptr;
+  public:
+    /// Constructs the pipe
+    explicit Pipe(bool for_read) {
+        SECURITY_ATTRIBUTES sa;
+        sa.nLength = sizeof(SECURITY_ATTRIBUTES);
+        sa.bInheritHandle = TRUE;
+        sa.lpSecurityDescriptor = nullptr;
 
-    HANDLE hread;
-    HANDLE hwrite;
-    if (CreatePipe(&hread, &hwrite, &sa, 0)) {
-      read = Handle(hread);
-      write = Handle(hwrite);
-      // Ensure the read handle to the pipe is not inherited
-      if (!SetHandleInformation(for_read ? read : write, HANDLE_FLAG_INHERIT,
-                                0)) {
-        read.Close();
-        write.Close();
-      }
+        HANDLE hread;
+        HANDLE hwrite;
+        if (CreatePipe(&hread, &hwrite, &sa, 0)) {
+            read = Handle(hread);
+            write = Handle(hwrite);
+            // Ensure the read handle to the pipe is not inherited
+            if (!SetHandleInformation(for_read ? read : write, HANDLE_FLAG_INHERIT, 0)) {
+                read.Close();
+                write.Close();
+            }
+        }
     }
-  }
 
-  /// @returns true if the pipe has an open read or write file
-  operator bool() { return read || write; }
+    /// @returns true if the pipe has an open read or write file
+    operator bool() { return read || write; }
 
-  /// The reader end of the pipe
-  Handle read;
+    /// The reader end of the pipe
+    Handle read;
 
-  /// The writer end of the pipe
-  Handle write;
+    /// The writer end of the pipe
+    Handle write;
 };
 
 bool ExecutableExists(const std::string& path) {
-  DWORD type = 0;
-  return GetBinaryTypeA(path.c_str(), &type);
+    DWORD type = 0;
+    return GetBinaryTypeA(path.c_str(), &type);
 }
 
 std::string FindExecutable(const std::string& name) {
-  if (ExecutableExists(name)) {
-    return name;
-  }
-  if (ExecutableExists(name + ".exe")) {
-    return name + ".exe";
-  }
-  if (name.find("/") == std::string::npos &&
-      name.find("\\") == std::string::npos) {
-    char* path_env = nullptr;
-    size_t path_env_len = 0;
-    if (_dupenv_s(&path_env, &path_env_len, "PATH")) {
-      return "";
+    if (ExecutableExists(name)) {
+        return name;
     }
-    std::istringstream path{path_env};
-    free(path_env);
-    std::string dir;
-    while (getline(path, dir, ';')) {
-      auto test = dir + "\\" + name;
-      if (ExecutableExists(test)) {
-        return test;
-      }
-      if (ExecutableExists(test + ".exe")) {
-        return test + ".exe";
-      }
+    if (ExecutableExists(name + ".exe")) {
+        return name + ".exe";
     }
-  }
-  return "";
+    if (name.find("/") == std::string::npos && name.find("\\") == std::string::npos) {
+        char* path_env = nullptr;
+        size_t path_env_len = 0;
+        if (_dupenv_s(&path_env, &path_env_len, "PATH")) {
+            return "";
+        }
+        std::istringstream path{path_env};
+        free(path_env);
+        std::string dir;
+        while (getline(path, dir, ';')) {
+            auto test = dir + "\\" + name;
+            if (ExecutableExists(test)) {
+                return test;
+            }
+            if (ExecutableExists(test + ".exe")) {
+                return test + ".exe";
+            }
+        }
+    }
+    return "";
 }
 
 }  // namespace
@@ -138,110 +136,106 @@
 Command::Command(const std::string& path) : path_(path) {}
 
 Command Command::LookPath(const std::string& executable) {
-  return Command(FindExecutable(executable));
+    return Command(FindExecutable(executable));
 }
 
 bool Command::Found() const {
-  return ExecutableExists(path_);
+    return ExecutableExists(path_);
 }
 
-Command::Output Command::Exec(
-    std::initializer_list<std::string> arguments) const {
-  Pipe stdout_pipe(true);
-  Pipe stderr_pipe(true);
-  Pipe stdin_pipe(false);
-  if (!stdin_pipe || !stdout_pipe || !stderr_pipe) {
+Command::Output Command::Exec(std::initializer_list<std::string> arguments) const {
+    Pipe stdout_pipe(true);
+    Pipe stderr_pipe(true);
+    Pipe stdin_pipe(false);
+    if (!stdin_pipe || !stdout_pipe || !stderr_pipe) {
+        Output output;
+        output.err = "Command::Exec(): Failed to create pipes";
+        return output;
+    }
+
+    if (!input_.empty()) {
+        if (!WriteFile(stdin_pipe.write, input_.data(), input_.size(), nullptr, nullptr)) {
+            Output output;
+            output.err = "Command::Exec() Failed to write stdin";
+            return output;
+        }
+    }
+    stdin_pipe.write.Close();
+
+    STARTUPINFOA si{};
+    si.cb = sizeof(si);
+    si.dwFlags |= STARTF_USESTDHANDLES;
+    si.hStdOutput = stdout_pipe.write;
+    si.hStdError = stderr_pipe.write;
+    si.hStdInput = stdin_pipe.read;
+
+    std::stringstream args;
+    args << path_;
+    for (auto& arg : arguments) {
+        args << " " << arg;
+    }
+
+    PROCESS_INFORMATION pi{};
+    if (!CreateProcessA(nullptr,                                // No module name (use command line)
+                        const_cast<LPSTR>(args.str().c_str()),  // Command line
+                        nullptr,                                // Process handle not inheritable
+                        nullptr,                                // Thread handle not inheritable
+                        TRUE,                                   // Handles are inherited
+                        0,                                      // No creation flags
+                        nullptr,                                // Use parent's environment block
+                        nullptr,                                // Use parent's starting directory
+                        &si,                                    // Pointer to STARTUPINFO structure
+                        &pi)) {  // Pointer to PROCESS_INFORMATION structure
+        Output out;
+        out.err = "Command::Exec() CreateProcess() failed";
+        return out;
+    }
+
+    stdin_pipe.read.Close();
+    stdout_pipe.write.Close();
+    stderr_pipe.write.Close();
+
+    struct StreamReadThreadArgs {
+        HANDLE stream;
+        std::string output;
+    };
+
+    auto stream_read_thread = [](LPVOID user) -> DWORD {
+        auto* thread_args = reinterpret_cast<StreamReadThreadArgs*>(user);
+        DWORD n = 0;
+        char buf[256];
+        while (ReadFile(thread_args->stream, buf, sizeof(buf), &n, NULL)) {
+            auto s = std::string(buf, buf + n);
+            thread_args->output += std::string(buf, buf + n);
+        }
+        return 0;
+    };
+
+    StreamReadThreadArgs stdout_read_args{stdout_pipe.read, {}};
+    auto* stdout_read_thread =
+        ::CreateThread(nullptr, 0, stream_read_thread, &stdout_read_args, 0, nullptr);
+
+    StreamReadThreadArgs stderr_read_args{stderr_pipe.read, {}};
+    auto* stderr_read_thread =
+        ::CreateThread(nullptr, 0, stream_read_thread, &stderr_read_args, 0, nullptr);
+
+    HANDLE handles[] = {pi.hProcess, stdout_read_thread, stderr_read_thread};
+    constexpr DWORD num_handles = sizeof(handles) / sizeof(handles[0]);
+
     Output output;
-    output.err = "Command::Exec(): Failed to create pipes";
+
+    auto res = WaitForMultipleObjects(num_handles, handles, /* wait_all = */ TRUE, INFINITE);
+    if (res >= WAIT_OBJECT_0 && res < WAIT_OBJECT_0 + num_handles) {
+        output.out = stdout_read_args.output;
+        output.err = stderr_read_args.output;
+        DWORD exit_code = 0;
+        GetExitCodeProcess(pi.hProcess, &exit_code);
+        output.error_code = static_cast<int>(exit_code);
+    } else {
+        output.err = "Command::Exec() WaitForMultipleObjects() returned " + std::to_string(res);
+    }
+
     return output;
-  }
-
-  if (!input_.empty()) {
-    if (!WriteFile(stdin_pipe.write, input_.data(), input_.size(), nullptr,
-                   nullptr)) {
-      Output output;
-      output.err = "Command::Exec() Failed to write stdin";
-      return output;
-    }
-  }
-  stdin_pipe.write.Close();
-
-  STARTUPINFOA si{};
-  si.cb = sizeof(si);
-  si.dwFlags |= STARTF_USESTDHANDLES;
-  si.hStdOutput = stdout_pipe.write;
-  si.hStdError = stderr_pipe.write;
-  si.hStdInput = stdin_pipe.read;
-
-  std::stringstream args;
-  args << path_;
-  for (auto& arg : arguments) {
-    args << " " << arg;
-  }
-
-  PROCESS_INFORMATION pi{};
-  if (!CreateProcessA(nullptr,  // No module name (use command line)
-                      const_cast<LPSTR>(args.str().c_str()),  // Command line
-                      nullptr,  // Process handle not inheritable
-                      nullptr,  // Thread handle not inheritable
-                      TRUE,     // Handles are inherited
-                      0,        // No creation flags
-                      nullptr,  // Use parent's environment block
-                      nullptr,  // Use parent's starting directory
-                      &si,      // Pointer to STARTUPINFO structure
-                      &pi)) {   // Pointer to PROCESS_INFORMATION structure
-    Output out;
-    out.err = "Command::Exec() CreateProcess() failed";
-    return out;
-  }
-
-  stdin_pipe.read.Close();
-  stdout_pipe.write.Close();
-  stderr_pipe.write.Close();
-
-  struct StreamReadThreadArgs {
-    HANDLE stream;
-    std::string output;
-  };
-
-  auto stream_read_thread = [](LPVOID user) -> DWORD {
-    auto* thread_args = reinterpret_cast<StreamReadThreadArgs*>(user);
-    DWORD n = 0;
-    char buf[256];
-    while (ReadFile(thread_args->stream, buf, sizeof(buf), &n, NULL)) {
-      auto s = std::string(buf, buf + n);
-      thread_args->output += std::string(buf, buf + n);
-    }
-    return 0;
-  };
-
-  StreamReadThreadArgs stdout_read_args{stdout_pipe.read, {}};
-  auto* stdout_read_thread = ::CreateThread(nullptr, 0, stream_read_thread,
-                                            &stdout_read_args, 0, nullptr);
-
-  StreamReadThreadArgs stderr_read_args{stderr_pipe.read, {}};
-  auto* stderr_read_thread = ::CreateThread(nullptr, 0, stream_read_thread,
-                                            &stderr_read_args, 0, nullptr);
-
-  HANDLE handles[] = {pi.hProcess, stdout_read_thread, stderr_read_thread};
-  constexpr DWORD num_handles = sizeof(handles) / sizeof(handles[0]);
-
-  Output output;
-
-  auto res = WaitForMultipleObjects(num_handles, handles, /* wait_all = */ TRUE,
-                                    INFINITE);
-  if (res >= WAIT_OBJECT_0 && res < WAIT_OBJECT_0 + num_handles) {
-    output.out = stdout_read_args.output;
-    output.err = stderr_read_args.output;
-    DWORD exit_code = 0;
-    GetExitCodeProcess(pi.hProcess, &exit_code);
-    output.error_code = static_cast<int>(exit_code);
-  } else {
-    output.err = "Command::Exec() WaitForMultipleObjects() returned " +
-                 std::to_string(res);
-  }
-
-  return output;
 }
 
 }  // namespace tint::utils
diff --git a/src/tint/utils/io/tmpfile.h b/src/tint/utils/io/tmpfile.h
index 6f81a89..24e7208 100644
--- a/src/tint/utils/io/tmpfile.h
+++ b/src/tint/utils/io/tmpfile.h
@@ -23,50 +23,50 @@
 /// TmpFile constructs a temporary file that can be written to, and is
 /// automatically deleted on destruction.
 class TmpFile {
- public:
-  /// Constructor.
-  /// Creates a new temporary file which can be written to.
-  /// The temporary file will be automatically deleted on destruction.
-  /// @param extension optional file extension to use with the file. The file
-  /// have no extension by default.
-  explicit TmpFile(std::string extension = "");
+  public:
+    /// Constructor.
+    /// Creates a new temporary file which can be written to.
+    /// The temporary file will be automatically deleted on destruction.
+    /// @param extension optional file extension to use with the file. The file
+    /// have no extension by default.
+    explicit TmpFile(std::string extension = "");
 
-  /// Destructor.
-  /// Deletes the temporary file.
-  ~TmpFile();
+    /// Destructor.
+    /// Deletes the temporary file.
+    ~TmpFile();
 
-  /// @return true if the temporary file was successfully created.
-  operator bool() { return !path_.empty(); }
+    /// @return true if the temporary file was successfully created.
+    operator bool() { return !path_.empty(); }
 
-  /// @return the path to the temporary file
-  std::string Path() const { return path_; }
+    /// @return the path to the temporary file
+    std::string Path() const { return path_; }
 
-  /// Opens the temporary file and appends |size| bytes from |data| to the end
-  /// of the temporary file. The temporary file is closed again before
-  /// returning, allowing other processes to open the file on operating systems
-  /// that require exclusive ownership of opened files.
-  /// @param data the data to write to the end of the file
-  /// @param size the number of bytes to write from data
-  /// @returns true on success, otherwise false
-  bool Append(const void* data, size_t size) const;
+    /// Opens the temporary file and appends |size| bytes from |data| to the end
+    /// of the temporary file. The temporary file is closed again before
+    /// returning, allowing other processes to open the file on operating systems
+    /// that require exclusive ownership of opened files.
+    /// @param data the data to write to the end of the file
+    /// @param size the number of bytes to write from data
+    /// @returns true on success, otherwise false
+    bool Append(const void* data, size_t size) const;
 
-  /// Appends the argument to the end of the file.
-  /// @param data the data to write to the end of the file
-  /// @return a reference to this TmpFile
-  template <typename T>
-  inline TmpFile& operator<<(T&& data) {
-    std::stringstream ss;
-    ss << data;
-    std::string str = ss.str();
-    Append(str.data(), str.size());
-    return *this;
-  }
+    /// Appends the argument to the end of the file.
+    /// @param data the data to write to the end of the file
+    /// @return a reference to this TmpFile
+    template <typename T>
+    inline TmpFile& operator<<(T&& data) {
+        std::stringstream ss;
+        ss << data;
+        std::string str = ss.str();
+        Append(str.data(), str.size());
+        return *this;
+    }
 
- private:
-  TmpFile(const TmpFile&) = delete;
-  TmpFile& operator=(const TmpFile&) = delete;
+  private:
+    TmpFile(const TmpFile&) = delete;
+    TmpFile& operator=(const TmpFile&) = delete;
 
-  std::string path_;
+    std::string path_;
 };
 
 }  // namespace tint::utils
diff --git a/src/tint/utils/io/tmpfile_other.cc b/src/tint/utils/io/tmpfile_other.cc
index 7ddbb58..14c8660 100644
--- a/src/tint/utils/io/tmpfile_other.cc
+++ b/src/tint/utils/io/tmpfile_other.cc
@@ -21,7 +21,7 @@
 TmpFile::~TmpFile() = default;
 
 bool TmpFile::Append(const void*, size_t) const {
-  return false;
+    return false;
 }
 
 }  // namespace tint::utils
diff --git a/src/tint/utils/io/tmpfile_posix.cc b/src/tint/utils/io/tmpfile_posix.cc
index 00c20fe..ba84afd 100644
--- a/src/tint/utils/io/tmpfile_posix.cc
+++ b/src/tint/utils/io/tmpfile_posix.cc
@@ -24,45 +24,43 @@
 namespace {
 
 std::string TmpFilePath(std::string ext) {
-  char const* dir = getenv("TMPDIR");
-  if (dir == nullptr) {
-    dir = "/tmp";
-  }
+    char const* dir = getenv("TMPDIR");
+    if (dir == nullptr) {
+        dir = "/tmp";
+    }
 
-  // mkstemps requires an `int` for the file extension name but STL represents
-  // size_t. Pre-C++20 there the behavior for unsigned-to-signed conversion
-  // (when the source value exceeds the representable range) is implementation
-  // defined. While such a large file extension is unlikely in practice, we
-  // enforce this here at runtime.
-  TINT_ASSERT(Utils, ext.length() <=
-                         static_cast<size_t>(std::numeric_limits<int>::max()));
-  std::string name = std::string(dir) + "/tint_XXXXXX" + ext;
-  int file = mkstemps(&name[0], static_cast<int>(ext.length()));
-  if (file != -1) {
-    close(file);
-    return name;
-  }
-  return "";
+    // mkstemps requires an `int` for the file extension name but STL represents
+    // size_t. Pre-C++20 there the behavior for unsigned-to-signed conversion
+    // (when the source value exceeds the representable range) is implementation
+    // defined. While such a large file extension is unlikely in practice, we
+    // enforce this here at runtime.
+    TINT_ASSERT(Utils, ext.length() <= static_cast<size_t>(std::numeric_limits<int>::max()));
+    std::string name = std::string(dir) + "/tint_XXXXXX" + ext;
+    int file = mkstemps(&name[0], static_cast<int>(ext.length()));
+    if (file != -1) {
+        close(file);
+        return name;
+    }
+    return "";
 }
 
 }  // namespace
 
-TmpFile::TmpFile(std::string extension)
-    : path_(TmpFilePath(std::move(extension))) {}
+TmpFile::TmpFile(std::string extension) : path_(TmpFilePath(std::move(extension))) {}
 
 TmpFile::~TmpFile() {
-  if (!path_.empty()) {
-    remove(path_.c_str());
-  }
+    if (!path_.empty()) {
+        remove(path_.c_str());
+    }
 }
 
 bool TmpFile::Append(const void* data, size_t size) const {
-  if (auto* file = fopen(path_.c_str(), "ab")) {
-    fwrite(data, size, 1, file);
-    fclose(file);
-    return true;
-  }
-  return false;
+    if (auto* file = fopen(path_.c_str(), "ab")) {
+        fwrite(data, size, 1, file);
+        fclose(file);
+        return true;
+    }
+    return false;
 }
 
 }  // namespace tint::utils
diff --git a/src/tint/utils/io/tmpfile_test.cc b/src/tint/utils/io/tmpfile_test.cc
index d312922..4fe103d 100644
--- a/src/tint/utils/io/tmpfile_test.cc
+++ b/src/tint/utils/io/tmpfile_test.cc
@@ -22,66 +22,66 @@
 namespace {
 
 TEST(TmpFileTest, WriteReadAppendDelete) {
-  std::string path;
-  {
-    TmpFile tmp;
-    if (!tmp) {
-      GTEST_SKIP() << "Unable to create a temporary file";
-    }
-
-    path = tmp.Path();
-
-    // Write a string to the temporary file
-    tmp << "hello world\n";
-
-    // Check the content of the file
+    std::string path;
     {
-      std::ifstream file(path);
-      ASSERT_TRUE(file);
-      std::string line;
-      EXPECT_TRUE(std::getline(file, line));
-      EXPECT_EQ(line, "hello world");
-      EXPECT_FALSE(std::getline(file, line));
+        TmpFile tmp;
+        if (!tmp) {
+            GTEST_SKIP() << "Unable to create a temporary file";
+        }
+
+        path = tmp.Path();
+
+        // Write a string to the temporary file
+        tmp << "hello world\n";
+
+        // Check the content of the file
+        {
+            std::ifstream file(path);
+            ASSERT_TRUE(file);
+            std::string line;
+            EXPECT_TRUE(std::getline(file, line));
+            EXPECT_EQ(line, "hello world");
+            EXPECT_FALSE(std::getline(file, line));
+        }
+
+        // Write some more content to the file
+        tmp << 42;
+
+        // Check the content of the file again
+        {
+            std::ifstream file(path);
+            ASSERT_TRUE(file);
+            std::string line;
+            EXPECT_TRUE(std::getline(file, line));
+            EXPECT_EQ(line, "hello world");
+            EXPECT_TRUE(std::getline(file, line));
+            EXPECT_EQ(line, "42");
+            EXPECT_FALSE(std::getline(file, line));
+        }
     }
 
-    // Write some more content to the file
-    tmp << 42;
-
-    // Check the content of the file again
-    {
-      std::ifstream file(path);
-      ASSERT_TRUE(file);
-      std::string line;
-      EXPECT_TRUE(std::getline(file, line));
-      EXPECT_EQ(line, "hello world");
-      EXPECT_TRUE(std::getline(file, line));
-      EXPECT_EQ(line, "42");
-      EXPECT_FALSE(std::getline(file, line));
-    }
-  }
-
-  // Check the file has been deleted when it fell out of scope
-  std::ifstream file(path);
-  ASSERT_FALSE(file);
+    // Check the file has been deleted when it fell out of scope
+    std::ifstream file(path);
+    ASSERT_FALSE(file);
 }
 
 TEST(TmpFileTest, FileExtension) {
-  const std::string kExt = ".foo";
-  std::string path;
-  {
-    TmpFile tmp(kExt);
-    if (!tmp) {
-      GTEST_SKIP() << "Unable create a temporary file";
+    const std::string kExt = ".foo";
+    std::string path;
+    {
+        TmpFile tmp(kExt);
+        if (!tmp) {
+            GTEST_SKIP() << "Unable create a temporary file";
+        }
+        path = tmp.Path();
     }
-    path = tmp.Path();
-  }
 
-  ASSERT_GT(path.length(), kExt.length());
-  EXPECT_EQ(kExt, path.substr(path.length() - kExt.length()));
+    ASSERT_GT(path.length(), kExt.length());
+    EXPECT_EQ(kExt, path.substr(path.length() - kExt.length()));
 
-  // Check the file has been deleted when it fell out of scope
-  std::ifstream file(path);
-  ASSERT_FALSE(file);
+    // Check the file has been deleted when it fell out of scope
+    std::ifstream file(path);
+    ASSERT_FALSE(file);
 }
 
 }  // namespace
diff --git a/src/tint/utils/io/tmpfile_windows.cc b/src/tint/utils/io/tmpfile_windows.cc
index 40dffc8..3c8e5f7 100644
--- a/src/tint/utils/io/tmpfile_windows.cc
+++ b/src/tint/utils/io/tmpfile_windows.cc
@@ -22,20 +22,20 @@
 namespace {
 
 std::string TmpFilePath(const std::string& ext) {
-  char name[L_tmpnam];
-  // As we're adding an extension, to ensure the file is really unique, try
-  // creating it, failing if it already exists.
-  while (tmpnam_s(name, L_tmpnam - 1) == 0) {
-    std::string name_with_ext = std::string(name) + ext;
-    FILE* f = nullptr;
-    // The "x" arg forces the function to fail if the file already exists.
-    fopen_s(&f, name_with_ext.c_str(), "wbx");
-    if (f) {
-      fclose(f);
-      return name_with_ext;
+    char name[L_tmpnam];
+    // As we're adding an extension, to ensure the file is really unique, try
+    // creating it, failing if it already exists.
+    while (tmpnam_s(name, L_tmpnam - 1) == 0) {
+        std::string name_with_ext = std::string(name) + ext;
+        FILE* f = nullptr;
+        // The "x" arg forces the function to fail if the file already exists.
+        fopen_s(&f, name_with_ext.c_str(), "wbx");
+        if (f) {
+            fclose(f);
+            return name_with_ext;
+        }
     }
-  }
-  return {};
+    return {};
 }
 
 }  // namespace
@@ -43,19 +43,19 @@
 TmpFile::TmpFile(std::string ext) : path_(TmpFilePath(ext)) {}
 
 TmpFile::~TmpFile() {
-  if (!path_.empty()) {
-    remove(path_.c_str());
-  }
+    if (!path_.empty()) {
+        remove(path_.c_str());
+    }
 }
 
 bool TmpFile::Append(const void* data, size_t size) const {
-  FILE* file = nullptr;
-  if (fopen_s(&file, path_.c_str(), "ab") != 0) {
-    return false;
-  }
-  fwrite(data, size, 1, file);
-  fclose(file);
-  return true;
+    FILE* file = nullptr;
+    if (fopen_s(&file, path_.c_str(), "ab") != 0) {
+        return false;
+    }
+    fwrite(data, size, 1, file);
+    fclose(file);
+    return true;
 }
 
 }  // namespace tint::utils
diff --git a/src/tint/utils/map.h b/src/tint/utils/map.h
index 12c93d4..0a13730 100644
--- a/src/tint/utils/map.h
+++ b/src/tint/utils/map.h
@@ -28,11 +28,9 @@
 /// @return the map item value, or `if_missing` if the map does not contain the
 /// given key
 template <typename K, typename V, typename H, typename C, typename KV = K>
-V Lookup(const std::unordered_map<K, V, H, C>& map,
-         const KV& key,
-         const V& if_missing = {}) {
-  auto it = map.find(key);
-  return it != map.end() ? it->second : if_missing;
+V Lookup(const std::unordered_map<K, V, H, C>& map, const KV& key, const V& if_missing = {}) {
+    auto it = map.find(key);
+    return it != map.end() ? it->second : if_missing;
 }
 
 /// GetOrCreate is a utility function for lazily adding to an unordered map.
@@ -43,16 +41,14 @@
 /// @param create a callable function-like object with the signature `V()`
 /// @return the value of the item with the given key, or the newly created item
 template <typename K, typename V, typename H, typename C, typename CREATE>
-V GetOrCreate(std::unordered_map<K, V, H, C>& map,
-              const K& key,
-              CREATE&& create) {
-  auto it = map.find(key);
-  if (it != map.end()) {
-    return it->second;
-  }
-  V value = create();
-  map.emplace(key, value);
-  return value;
+V GetOrCreate(std::unordered_map<K, V, H, C>& map, const K& key, CREATE&& create) {
+    auto it = map.find(key);
+    if (it != map.end()) {
+        return it->second;
+    }
+    V value = create();
+    map.emplace(key, value);
+    return value;
 }
 
 }  // namespace tint::utils
diff --git a/src/tint/utils/map_test.cc b/src/tint/utils/map_test.cc
index ae35aeb..f0d9392 100644
--- a/src/tint/utils/map_test.cc
+++ b/src/tint/utils/map_test.cc
@@ -22,34 +22,34 @@
 namespace {
 
 TEST(Lookup, Test) {
-  std::unordered_map<int, int> map;
-  map.emplace(10, 1);
-  EXPECT_EQ(Lookup(map, 10, 0), 1);    // exists, with if_missing
-  EXPECT_EQ(Lookup(map, 10), 1);       // exists, without if_missing
-  EXPECT_EQ(Lookup(map, 20, 50), 50);  // missing, with if_missing
-  EXPECT_EQ(Lookup(map, 20), 0);       // missing, without if_missing
+    std::unordered_map<int, int> map;
+    map.emplace(10, 1);
+    EXPECT_EQ(Lookup(map, 10, 0), 1);    // exists, with if_missing
+    EXPECT_EQ(Lookup(map, 10), 1);       // exists, without if_missing
+    EXPECT_EQ(Lookup(map, 20, 50), 50);  // missing, with if_missing
+    EXPECT_EQ(Lookup(map, 20), 0);       // missing, without if_missing
 }
 
 TEST(GetOrCreateTest, NewKey) {
-  std::unordered_map<int, int> map;
-  EXPECT_EQ(GetOrCreate(map, 1, [&] { return 2; }), 2);
-  EXPECT_EQ(map.size(), 1u);
-  EXPECT_EQ(map[1], 2);
+    std::unordered_map<int, int> map;
+    EXPECT_EQ(GetOrCreate(map, 1, [&] { return 2; }), 2);
+    EXPECT_EQ(map.size(), 1u);
+    EXPECT_EQ(map[1], 2);
 }
 
 TEST(GetOrCreateTest, ExistingKey) {
-  std::unordered_map<int, int> map;
-  map[1] = 2;
-  bool called = false;
-  EXPECT_EQ(GetOrCreate(map, 1,
-                        [&] {
-                          called = true;
-                          return -2;
-                        }),
-            2);
-  EXPECT_EQ(called, false);
-  EXPECT_EQ(map.size(), 1u);
-  EXPECT_EQ(map[1], 2);
+    std::unordered_map<int, int> map;
+    map[1] = 2;
+    bool called = false;
+    EXPECT_EQ(GetOrCreate(map, 1,
+                          [&] {
+                              called = true;
+                              return -2;
+                          }),
+              2);
+    EXPECT_EQ(called, false);
+    EXPECT_EQ(map.size(), 1u);
+    EXPECT_EQ(map[1], 2);
 }
 
 }  // namespace
diff --git a/src/tint/utils/math.h b/src/tint/utils/math.h
index c6d7d46..3d8874a 100644
--- a/src/tint/utils/math.h
+++ b/src/tint/utils/math.h
@@ -27,7 +27,7 @@
 /// @note `alignment` must be positive. An alignment of zero will cause a DBZ.
 template <typename T>
 inline T RoundUp(T alignment, T value) {
-  return ((value + alignment - 1) / alignment) * alignment;
+    return ((value + alignment - 1) / alignment) * alignment;
 }
 
 /// @param value the value to check whether it is a power-of-two
@@ -35,19 +35,19 @@
 /// @note `value` must be positive if `T` is signed
 template <typename T>
 inline bool IsPowerOfTwo(T value) {
-  return (value & (value - 1)) == 0;
+    return (value & (value - 1)) == 0;
 }
 
 /// @param value the input value
 /// @returns the largest power of two that `value` is a multiple of
 template <typename T>
 inline std::enable_if_t<std::is_unsigned<T>::value, T> MaxAlignOf(T value) {
-  T pot = 1;
-  while (value && ((value & 1u) == 0)) {
-    pot <<= 1;
-    value >>= 1;
-  }
-  return pot;
+    T pot = 1;
+    while (value && ((value & 1u) == 0)) {
+        pot <<= 1;
+        value >>= 1;
+    }
+    return pot;
 }
 
 }  // namespace tint::utils
diff --git a/src/tint/utils/math_test.cc b/src/tint/utils/math_test.cc
index d6be3f6..515c718 100644
--- a/src/tint/utils/math_test.cc
+++ b/src/tint/utils/math_test.cc
@@ -20,61 +20,61 @@
 namespace {
 
 TEST(MathTests, RoundUp) {
-  EXPECT_EQ(RoundUp(1, 0), 0);
-  EXPECT_EQ(RoundUp(1, 1), 1);
-  EXPECT_EQ(RoundUp(1, 2), 2);
+    EXPECT_EQ(RoundUp(1, 0), 0);
+    EXPECT_EQ(RoundUp(1, 1), 1);
+    EXPECT_EQ(RoundUp(1, 2), 2);
 
-  EXPECT_EQ(RoundUp(1, 1), 1);
-  EXPECT_EQ(RoundUp(2, 1), 2);
-  EXPECT_EQ(RoundUp(3, 1), 3);
-  EXPECT_EQ(RoundUp(4, 1), 4);
+    EXPECT_EQ(RoundUp(1, 1), 1);
+    EXPECT_EQ(RoundUp(2, 1), 2);
+    EXPECT_EQ(RoundUp(3, 1), 3);
+    EXPECT_EQ(RoundUp(4, 1), 4);
 
-  EXPECT_EQ(RoundUp(1, 2), 2);
-  EXPECT_EQ(RoundUp(2, 2), 2);
-  EXPECT_EQ(RoundUp(3, 2), 3);
-  EXPECT_EQ(RoundUp(4, 2), 4);
+    EXPECT_EQ(RoundUp(1, 2), 2);
+    EXPECT_EQ(RoundUp(2, 2), 2);
+    EXPECT_EQ(RoundUp(3, 2), 3);
+    EXPECT_EQ(RoundUp(4, 2), 4);
 
-  EXPECT_EQ(RoundUp(1, 3), 3);
-  EXPECT_EQ(RoundUp(2, 3), 4);
-  EXPECT_EQ(RoundUp(3, 3), 3);
-  EXPECT_EQ(RoundUp(4, 3), 4);
+    EXPECT_EQ(RoundUp(1, 3), 3);
+    EXPECT_EQ(RoundUp(2, 3), 4);
+    EXPECT_EQ(RoundUp(3, 3), 3);
+    EXPECT_EQ(RoundUp(4, 3), 4);
 
-  EXPECT_EQ(RoundUp(1, 4), 4);
-  EXPECT_EQ(RoundUp(2, 4), 4);
-  EXPECT_EQ(RoundUp(3, 4), 6);
-  EXPECT_EQ(RoundUp(4, 4), 4);
+    EXPECT_EQ(RoundUp(1, 4), 4);
+    EXPECT_EQ(RoundUp(2, 4), 4);
+    EXPECT_EQ(RoundUp(3, 4), 6);
+    EXPECT_EQ(RoundUp(4, 4), 4);
 }
 
 TEST(MathTests, IsPowerOfTwo) {
-  EXPECT_EQ(IsPowerOfTwo(1), true);
-  EXPECT_EQ(IsPowerOfTwo(2), true);
-  EXPECT_EQ(IsPowerOfTwo(3), false);
-  EXPECT_EQ(IsPowerOfTwo(4), true);
-  EXPECT_EQ(IsPowerOfTwo(5), false);
-  EXPECT_EQ(IsPowerOfTwo(6), false);
-  EXPECT_EQ(IsPowerOfTwo(7), false);
-  EXPECT_EQ(IsPowerOfTwo(8), true);
-  EXPECT_EQ(IsPowerOfTwo(9), false);
+    EXPECT_EQ(IsPowerOfTwo(1), true);
+    EXPECT_EQ(IsPowerOfTwo(2), true);
+    EXPECT_EQ(IsPowerOfTwo(3), false);
+    EXPECT_EQ(IsPowerOfTwo(4), true);
+    EXPECT_EQ(IsPowerOfTwo(5), false);
+    EXPECT_EQ(IsPowerOfTwo(6), false);
+    EXPECT_EQ(IsPowerOfTwo(7), false);
+    EXPECT_EQ(IsPowerOfTwo(8), true);
+    EXPECT_EQ(IsPowerOfTwo(9), false);
 }
 
 TEST(MathTests, MaxAlignOf) {
-  EXPECT_EQ(MaxAlignOf(0u), 1u);
-  EXPECT_EQ(MaxAlignOf(1u), 1u);
-  EXPECT_EQ(MaxAlignOf(2u), 2u);
-  EXPECT_EQ(MaxAlignOf(3u), 1u);
-  EXPECT_EQ(MaxAlignOf(4u), 4u);
-  EXPECT_EQ(MaxAlignOf(5u), 1u);
-  EXPECT_EQ(MaxAlignOf(6u), 2u);
-  EXPECT_EQ(MaxAlignOf(7u), 1u);
-  EXPECT_EQ(MaxAlignOf(8u), 8u);
-  EXPECT_EQ(MaxAlignOf(9u), 1u);
-  EXPECT_EQ(MaxAlignOf(10u), 2u);
-  EXPECT_EQ(MaxAlignOf(11u), 1u);
-  EXPECT_EQ(MaxAlignOf(12u), 4u);
-  EXPECT_EQ(MaxAlignOf(13u), 1u);
-  EXPECT_EQ(MaxAlignOf(14u), 2u);
-  EXPECT_EQ(MaxAlignOf(15u), 1u);
-  EXPECT_EQ(MaxAlignOf(16u), 16u);
+    EXPECT_EQ(MaxAlignOf(0u), 1u);
+    EXPECT_EQ(MaxAlignOf(1u), 1u);
+    EXPECT_EQ(MaxAlignOf(2u), 2u);
+    EXPECT_EQ(MaxAlignOf(3u), 1u);
+    EXPECT_EQ(MaxAlignOf(4u), 4u);
+    EXPECT_EQ(MaxAlignOf(5u), 1u);
+    EXPECT_EQ(MaxAlignOf(6u), 2u);
+    EXPECT_EQ(MaxAlignOf(7u), 1u);
+    EXPECT_EQ(MaxAlignOf(8u), 8u);
+    EXPECT_EQ(MaxAlignOf(9u), 1u);
+    EXPECT_EQ(MaxAlignOf(10u), 2u);
+    EXPECT_EQ(MaxAlignOf(11u), 1u);
+    EXPECT_EQ(MaxAlignOf(12u), 4u);
+    EXPECT_EQ(MaxAlignOf(13u), 1u);
+    EXPECT_EQ(MaxAlignOf(14u), 2u);
+    EXPECT_EQ(MaxAlignOf(15u), 1u);
+    EXPECT_EQ(MaxAlignOf(16u), 16u);
 }
 
 }  // namespace
diff --git a/src/tint/utils/reverse.h b/src/tint/utils/reverse.h
index fb4f237..f28eedd 100644
--- a/src/tint/utils/reverse.h
+++ b/src/tint/utils/reverse.h
@@ -26,18 +26,18 @@
 /// See https://en.cppreference.com/w/cpp/language/range-for
 template <typename T>
 struct ReverseIterable {
-  /// The wrapped iterable object.
-  T& iterable;
+    /// The wrapped iterable object.
+    T& iterable;
 };
 
 template <typename T>
 auto begin(ReverseIterable<T> r_it) {
-  return std::rbegin(r_it.iterable);
+    return std::rbegin(r_it.iterable);
 }
 
 template <typename T>
 auto end(ReverseIterable<T> r_it) {
-  return std::rend(r_it.iterable);
+    return std::rend(r_it.iterable);
 }
 }  // namespace detail
 
@@ -54,7 +54,7 @@
 /// ```
 template <typename T>
 detail::ReverseIterable<T> Reverse(T&& iterable) {
-  return {iterable};
+    return {iterable};
 }
 
 }  // namespace tint::utils
diff --git a/src/tint/utils/reverse_test.cc b/src/tint/utils/reverse_test.cc
index b23c799..9bef6de 100644
--- a/src/tint/utils/reverse_test.cc
+++ b/src/tint/utils/reverse_test.cc
@@ -22,12 +22,12 @@
 namespace {
 
 TEST(ReverseTest, Vector) {
-  std::vector<int> vec{1, 3, 5, 7, 9};
-  std::vector<int> rev;
-  for (auto v : Reverse(vec)) {
-    rev.emplace_back(v);
-  }
-  ASSERT_THAT(rev, testing::ElementsAre(9, 7, 5, 3, 1));
+    std::vector<int> vec{1, 3, 5, 7, 9};
+    std::vector<int> rev;
+    for (auto v : Reverse(vec)) {
+        rev.emplace_back(v);
+    }
+    ASSERT_THAT(rev, testing::ElementsAre(9, 7, 5, 3, 1));
 }
 
 }  // namespace
diff --git a/src/tint/utils/scoped_assignment.h b/src/tint/utils/scoped_assignment.h
index fdd787f..6149454 100644
--- a/src/tint/utils/scoped_assignment.h
+++ b/src/tint/utils/scoped_assignment.h
@@ -27,36 +27,36 @@
 /// original value is restored.
 template <typename T>
 class ScopedAssignment {
- public:
-  /// Constructor
-  /// @param var the variable to temporarily assign a new value to
-  /// @param val the value to assign to `ref` for the lifetime of this
-  /// ScopedAssignment.
-  ScopedAssignment(T& var, T val) : ref_(var) {
-    old_value_ = var;
-    var = val;
-  }
+  public:
+    /// Constructor
+    /// @param var the variable to temporarily assign a new value to
+    /// @param val the value to assign to `ref` for the lifetime of this
+    /// ScopedAssignment.
+    ScopedAssignment(T& var, T val) : ref_(var) {
+        old_value_ = var;
+        var = val;
+    }
 
-  /// Destructor
-  /// Restores the original value of the variable.
-  ~ScopedAssignment() { ref_ = old_value_; }
+    /// Destructor
+    /// Restores the original value of the variable.
+    ~ScopedAssignment() { ref_ = old_value_; }
 
- private:
-  ScopedAssignment(const ScopedAssignment&) = delete;
-  ScopedAssignment& operator=(const ScopedAssignment&) = delete;
+  private:
+    ScopedAssignment(const ScopedAssignment&) = delete;
+    ScopedAssignment& operator=(const ScopedAssignment&) = delete;
 
-  T& ref_;
-  T old_value_;
+    T& ref_;
+    T old_value_;
 };
 
 }  // namespace tint::utils
 
 /// TINT_SCOPED_ASSIGNMENT(var, val) assigns `val` to `var`, and automatically
 /// restores the original value of `var` when exiting the current lexical scope.
-#define TINT_SCOPED_ASSIGNMENT(var, val)                                  \
-  ::tint::utils::ScopedAssignment<std::remove_reference_t<decltype(var)>> \
-  TINT_CONCAT(tint_scoped_assignment_, __COUNTER__) {                     \
-    var, val                                                              \
-  }
+#define TINT_SCOPED_ASSIGNMENT(var, val)                                                 \
+    ::tint::utils::ScopedAssignment<std::remove_reference_t<decltype(var)>> TINT_CONCAT( \
+        tint_scoped_assignment_, __COUNTER__) {                                          \
+        var, val                                                                         \
+    }
 
 #endif  // SRC_TINT_UTILS_SCOPED_ASSIGNMENT_H_
diff --git a/src/tint/utils/scoped_assignment_test.cc b/src/tint/utils/scoped_assignment_test.cc
index 3055afe..3c0c548 100644
--- a/src/tint/utils/scoped_assignment_test.cc
+++ b/src/tint/utils/scoped_assignment_test.cc
@@ -20,25 +20,25 @@
 namespace {
 
 TEST(ScopedAssignmentTest, Scopes) {
-  int i = 0;
-  EXPECT_EQ(i, 0);
-  {
+    int i = 0;
     EXPECT_EQ(i, 0);
-    TINT_SCOPED_ASSIGNMENT(i, 1);
-    EXPECT_EQ(i, 1);
     {
-      EXPECT_EQ(i, 1);
-      TINT_SCOPED_ASSIGNMENT(i, 2);
-      EXPECT_EQ(i, 2);
+        EXPECT_EQ(i, 0);
+        TINT_SCOPED_ASSIGNMENT(i, 1);
+        EXPECT_EQ(i, 1);
+        {
+            EXPECT_EQ(i, 1);
+            TINT_SCOPED_ASSIGNMENT(i, 2);
+            EXPECT_EQ(i, 2);
+        }
+        {
+            EXPECT_EQ(i, 1);
+            TINT_SCOPED_ASSIGNMENT(i, 3);
+            EXPECT_EQ(i, 3);
+        }
+        EXPECT_EQ(i, 1);
     }
-    {
-      EXPECT_EQ(i, 1);
-      TINT_SCOPED_ASSIGNMENT(i, 3);
-      EXPECT_EQ(i, 3);
-    }
-    EXPECT_EQ(i, 1);
-  }
-  EXPECT_EQ(i, 0);
+    EXPECT_EQ(i, 0);
 }
 
 }  // namespace
diff --git a/src/tint/utils/string.h b/src/tint/utils/string.h
index 011e326..a11e44e 100644
--- a/src/tint/utils/string.h
+++ b/src/tint/utils/string.h
@@ -26,12 +26,12 @@
 inline std::string ReplaceAll(std::string str,
                               const std::string& substr,
                               const std::string& replacement) {
-  size_t pos = 0;
-  while ((pos = str.find(substr, pos)) != std::string::npos) {
-    str.replace(pos, substr.length(), replacement);
-    pos += replacement.length();
-  }
-  return str;
+    size_t pos = 0;
+    while ((pos = str.find(substr, pos)) != std::string::npos) {
+        str.replace(pos, substr.length(), replacement);
+        pos += replacement.length();
+    }
+    return str;
 }
 
 }  // namespace tint::utils
diff --git a/src/tint/utils/string_test.cc b/src/tint/utils/string_test.cc
index f394ed7..0d3e14f 100644
--- a/src/tint/utils/string_test.cc
+++ b/src/tint/utils/string_test.cc
@@ -20,16 +20,16 @@
 namespace {
 
 TEST(StringTest, ReplaceAll) {
-  ASSERT_EQ("xybbcc", ReplaceAll("aabbcc", "aa", "xy"));
-  ASSERT_EQ("aaxycc", ReplaceAll("aabbcc", "bb", "xy"));
-  ASSERT_EQ("aabbxy", ReplaceAll("aabbcc", "cc", "xy"));
-  ASSERT_EQ("xyxybbcc", ReplaceAll("aabbcc", "a", "xy"));
-  ASSERT_EQ("aaxyxycc", ReplaceAll("aabbcc", "b", "xy"));
-  ASSERT_EQ("aabbxyxy", ReplaceAll("aabbcc", "c", "xy"));
-  // Replacement string includes the searched-for string.
-  // This proves that the algorithm needs to advance 'pos'
-  // past the replacement.
-  ASSERT_EQ("aabxybbxybcc", ReplaceAll("aabbcc", "b", "bxyb"));
+    ASSERT_EQ("xybbcc", ReplaceAll("aabbcc", "aa", "xy"));
+    ASSERT_EQ("aaxycc", ReplaceAll("aabbcc", "bb", "xy"));
+    ASSERT_EQ("aabbxy", ReplaceAll("aabbcc", "cc", "xy"));
+    ASSERT_EQ("xyxybbcc", ReplaceAll("aabbcc", "a", "xy"));
+    ASSERT_EQ("aaxyxycc", ReplaceAll("aabbcc", "b", "xy"));
+    ASSERT_EQ("aabbxyxy", ReplaceAll("aabbcc", "c", "xy"));
+    // Replacement string includes the searched-for string.
+    // This proves that the algorithm needs to advance 'pos'
+    // past the replacement.
+    ASSERT_EQ("aabxybbxybcc", ReplaceAll("aabbcc", "b", "bxyb"));
 }
 
 }  // namespace
diff --git a/src/tint/utils/to_const_ptr_vec.h b/src/tint/utils/to_const_ptr_vec.h
index a46b3ba..02cc984 100644
--- a/src/tint/utils/to_const_ptr_vec.h
+++ b/src/tint/utils/to_const_ptr_vec.h
@@ -24,12 +24,12 @@
 /// @returns a vector of `const T*` with the content of `in`.
 template <typename T>
 std::vector<const T*> ToConstPtrVec(const std::vector<T*>& in) {
-  std::vector<const T*> out;
-  out.reserve(in.size());
-  for (auto* ptr : in) {
-    out.emplace_back(ptr);
-  }
-  return out;
+    std::vector<const T*> out;
+    out.reserve(in.size());
+    for (auto* ptr : in) {
+        out.emplace_back(ptr);
+    }
+    return out;
 }
 
 }  // namespace tint::utils
diff --git a/src/tint/utils/transform.h b/src/tint/utils/transform.h
index 29a9740..2cd9481 100644
--- a/src/tint/utils/transform.h
+++ b/src/tint/utils/transform.h
@@ -32,11 +32,11 @@
 template <typename IN, typename TRANSFORMER>
 auto Transform(const std::vector<IN>& in, TRANSFORMER&& transform)
     -> std::vector<decltype(transform(in[0]))> {
-  std::vector<decltype(transform(in[0]))> result(in.size());
-  for (size_t i = 0; i < result.size(); ++i) {
-    result[i] = transform(in[i]);
-  }
-  return result;
+    std::vector<decltype(transform(in[0]))> result(in.size());
+    for (size_t i = 0; i < result.size(); ++i) {
+        result[i] = transform(in[i]);
+    }
+    return result;
 }
 
 /// Transform performs an element-wise transformation of a vector.
@@ -48,11 +48,11 @@
 template <typename IN, typename TRANSFORMER>
 auto Transform(const std::vector<IN>& in, TRANSFORMER&& transform)
     -> std::vector<decltype(transform(in[0], 1u))> {
-  std::vector<decltype(transform(in[0], 1u))> result(in.size());
-  for (size_t i = 0; i < result.size(); ++i) {
-    result[i] = transform(in[i], i);
-  }
-  return result;
+    std::vector<decltype(transform(in[0], 1u))> result(in.size());
+    for (size_t i = 0; i < result.size(); ++i) {
+        result[i] = transform(in[i], i);
+    }
+    return result;
 }
 
 }  // namespace tint::utils
diff --git a/src/tint/utils/transform_test.cc b/src/tint/utils/transform_test.cc
index e668824..af8b832 100644
--- a/src/tint/utils/transform_test.cc
+++ b/src/tint/utils/transform_test.cc
@@ -19,73 +19,72 @@
 
 #include "gmock/gmock.h"
 
-#define CHECK_ELEMENT_TYPE(vector, expected)                                 \
-  static_assert(std::is_same<decltype(vector)::value_type, expected>::value, \
-                "unexpected result vector element type")
+#define CHECK_ELEMENT_TYPE(vector, expected)                                   \
+    static_assert(std::is_same<decltype(vector)::value_type, expected>::value, \
+                  "unexpected result vector element type")
 
 namespace tint::utils {
 namespace {
 
 TEST(TransformTest, Empty) {
-  const std::vector<int> empty{};
-  {
-    auto transformed = Transform(empty, [](int) -> int {
-      [] { FAIL() << "Transform should not be called for empty vector"; }();
-      return 0;
-    });
-    CHECK_ELEMENT_TYPE(transformed, int);
-    EXPECT_EQ(transformed.size(), 0u);
-  }
-  {
-    auto transformed = Transform(empty, [](int, size_t) -> int {
-      [] { FAIL() << "Transform should not be called for empty vector"; }();
-      return 0;
-    });
-    CHECK_ELEMENT_TYPE(transformed, int);
-    EXPECT_EQ(transformed.size(), 0u);
-  }
+    const std::vector<int> empty{};
+    {
+        auto transformed = Transform(empty, [](int) -> int {
+            [] { FAIL() << "Transform should not be called for empty vector"; }();
+            return 0;
+        });
+        CHECK_ELEMENT_TYPE(transformed, int);
+        EXPECT_EQ(transformed.size(), 0u);
+    }
+    {
+        auto transformed = Transform(empty, [](int, size_t) -> int {
+            [] { FAIL() << "Transform should not be called for empty vector"; }();
+            return 0;
+        });
+        CHECK_ELEMENT_TYPE(transformed, int);
+        EXPECT_EQ(transformed.size(), 0u);
+    }
 }
 
 TEST(TransformTest, Identity) {
-  const std::vector<int> input{1, 2, 3, 4};
-  {
-    auto transformed = Transform(input, [](int i) { return i; });
-    CHECK_ELEMENT_TYPE(transformed, int);
-    EXPECT_THAT(transformed, testing::ElementsAre(1, 2, 3, 4));
-  }
-  {
-    auto transformed = Transform(input, [](int i, size_t) { return i; });
-    CHECK_ELEMENT_TYPE(transformed, int);
-    EXPECT_THAT(transformed, testing::ElementsAre(1, 2, 3, 4));
-  }
+    const std::vector<int> input{1, 2, 3, 4};
+    {
+        auto transformed = Transform(input, [](int i) { return i; });
+        CHECK_ELEMENT_TYPE(transformed, int);
+        EXPECT_THAT(transformed, testing::ElementsAre(1, 2, 3, 4));
+    }
+    {
+        auto transformed = Transform(input, [](int i, size_t) { return i; });
+        CHECK_ELEMENT_TYPE(transformed, int);
+        EXPECT_THAT(transformed, testing::ElementsAre(1, 2, 3, 4));
+    }
 }
 
 TEST(TransformTest, Index) {
-  const std::vector<int> input{10, 20, 30, 40};
-  {
-    auto transformed = Transform(input, [](int, size_t idx) { return idx; });
-    CHECK_ELEMENT_TYPE(transformed, size_t);
-    EXPECT_THAT(transformed, testing::ElementsAre(0u, 1u, 2u, 3u));
-  }
+    const std::vector<int> input{10, 20, 30, 40};
+    {
+        auto transformed = Transform(input, [](int, size_t idx) { return idx; });
+        CHECK_ELEMENT_TYPE(transformed, size_t);
+        EXPECT_THAT(transformed, testing::ElementsAre(0u, 1u, 2u, 3u));
+    }
 }
 
 TEST(TransformTest, TransformSameType) {
-  const std::vector<int> input{1, 2, 3, 4};
-  {
-    auto transformed = Transform(input, [](int i) { return i * 10; });
-    CHECK_ELEMENT_TYPE(transformed, int);
-    EXPECT_THAT(transformed, testing::ElementsAre(10, 20, 30, 40));
-  }
+    const std::vector<int> input{1, 2, 3, 4};
+    {
+        auto transformed = Transform(input, [](int i) { return i * 10; });
+        CHECK_ELEMENT_TYPE(transformed, int);
+        EXPECT_THAT(transformed, testing::ElementsAre(10, 20, 30, 40));
+    }
 }
 
 TEST(TransformTest, TransformDifferentType) {
-  const std::vector<int> input{1, 2, 3, 4};
-  {
-    auto transformed =
-        Transform(input, [](int i) { return std::to_string(i); });
-    CHECK_ELEMENT_TYPE(transformed, std::string);
-    EXPECT_THAT(transformed, testing::ElementsAre("1", "2", "3", "4"));
-  }
+    const std::vector<int> input{1, 2, 3, 4};
+    {
+        auto transformed = Transform(input, [](int i) { return std::to_string(i); });
+        CHECK_ELEMENT_TYPE(transformed, std::string);
+        EXPECT_THAT(transformed, testing::ElementsAre("1", "2", "3", "4"));
+    }
 }
 
 }  // namespace
diff --git a/src/tint/utils/unique_allocator.h b/src/tint/utils/unique_allocator.h
index 69242fb..628bc79 100644
--- a/src/tint/utils/unique_allocator.h
+++ b/src/tint/utils/unique_allocator.h
@@ -25,58 +25,56 @@
 
 /// UniqueAllocator is used to allocate unique instances of the template type
 /// `T`.
-template <typename T,
-          typename HASH = std::hash<T>,
-          typename EQUAL = std::equal_to<T>>
+template <typename T, typename HASH = std::hash<T>, typename EQUAL = std::equal_to<T>>
 class UniqueAllocator {
- public:
-  /// @param args the arguments used to construct the object.
-  /// @return a pointer to an instance of `T` with the provided arguments.
-  ///         If an existing instance of `T` has been constructed, then the same
-  ///         pointer is returned.
-  template <typename TYPE = T, typename... ARGS>
-  TYPE* Get(ARGS&&... args) {
-    // Create a temporary T instance on the stack so that we can hash it, and
-    // use it for equality lookup for the std::unordered_set. If the item is not
-    // found in the set, then we create the persisted instance with the
-    // allocator.
-    TYPE key{args...};
-    auto hash = HASH{}(key);
-    auto it = items.find(Entry{hash, &key});
-    if (it != items.end()) {
-      return static_cast<TYPE*>(it->ptr);
+  public:
+    /// @param args the arguments used to construct the object.
+    /// @return a pointer to an instance of `T` with the provided arguments.
+    ///         If an existing instance of `T` has been constructed, then the same
+    ///         pointer is returned.
+    template <typename TYPE = T, typename... ARGS>
+    TYPE* Get(ARGS&&... args) {
+        // Create a temporary T instance on the stack so that we can hash it, and
+        // use it for equality lookup for the std::unordered_set. If the item is not
+        // found in the set, then we create the persisted instance with the
+        // allocator.
+        TYPE key{args...};
+        auto hash = HASH{}(key);
+        auto it = items.find(Entry{hash, &key});
+        if (it != items.end()) {
+            return static_cast<TYPE*>(it->ptr);
+        }
+        auto* ptr = allocator.template Create<TYPE>(std::forward<ARGS>(args)...);
+        items.emplace_hint(it, Entry{hash, ptr});
+        return ptr;
     }
-    auto* ptr = allocator.template Create<TYPE>(std::forward<ARGS>(args)...);
-    items.emplace_hint(it, Entry{hash, ptr});
-    return ptr;
-  }
 
- protected:
-  /// Entry is used as the entry to the unordered_set
-  struct Entry {
-    /// The pre-calculated hash of the entry
-    size_t hash;
-    /// Tge pointer to the unique object
-    T* ptr;
-  };
-  /// Comparator is the hashing and equality function used by the unordered_set
-  struct Comparator {
-    /// Hashing function
-    /// @param e the entry
-    /// @returns the hash of the entry
-    size_t operator()(Entry e) const { return e.hash; }
+  protected:
+    /// Entry is used as the entry to the unordered_set
+    struct Entry {
+        /// The pre-calculated hash of the entry
+        size_t hash;
+        /// Tge pointer to the unique object
+        T* ptr;
+    };
+    /// Comparator is the hashing and equality function used by the unordered_set
+    struct Comparator {
+        /// Hashing function
+        /// @param e the entry
+        /// @returns the hash of the entry
+        size_t operator()(Entry e) const { return e.hash; }
 
-    /// Equality function
-    /// @param a the first entry to compare
-    /// @param b the second entry to compare
-    /// @returns true if the two entries are equal
-    bool operator()(Entry a, Entry b) const { return EQUAL{}(*a.ptr, *b.ptr); }
-  };
+        /// Equality function
+        /// @param a the first entry to compare
+        /// @param b the second entry to compare
+        /// @returns true if the two entries are equal
+        bool operator()(Entry a, Entry b) const { return EQUAL{}(*a.ptr, *b.ptr); }
+    };
 
-  /// The block allocator used to allocate the unique objects
-  BlockAllocator<T> allocator;
-  /// The unordered_set of unique item entries
-  std::unordered_set<Entry, Comparator, Comparator> items;
+    /// The block allocator used to allocate the unique objects
+    BlockAllocator<T> allocator;
+    /// The unordered_set of unique item entries
+    std::unordered_set<Entry, Comparator, Comparator> items;
 };
 
 }  // namespace tint::utils
diff --git a/src/tint/utils/unique_allocator_test.cc b/src/tint/utils/unique_allocator_test.cc
index d8d62df..b618734 100644
--- a/src/tint/utils/unique_allocator_test.cc
+++ b/src/tint/utils/unique_allocator_test.cc
@@ -22,30 +22,30 @@
 namespace {
 
 TEST(UniqueAllocator, Int) {
-  UniqueAllocator<int> a;
-  EXPECT_NE(a.Get(0), a.Get(1));
-  EXPECT_NE(a.Get(1), a.Get(2));
-  EXPECT_EQ(a.Get(0), a.Get(0));
-  EXPECT_EQ(a.Get(1), a.Get(1));
-  EXPECT_EQ(a.Get(2), a.Get(2));
+    UniqueAllocator<int> a;
+    EXPECT_NE(a.Get(0), a.Get(1));
+    EXPECT_NE(a.Get(1), a.Get(2));
+    EXPECT_EQ(a.Get(0), a.Get(0));
+    EXPECT_EQ(a.Get(1), a.Get(1));
+    EXPECT_EQ(a.Get(2), a.Get(2));
 }
 
 TEST(UniqueAllocator, Float) {
-  UniqueAllocator<float> a;
-  EXPECT_NE(a.Get(0.1f), a.Get(1.1f));
-  EXPECT_NE(a.Get(1.1f), a.Get(2.1f));
-  EXPECT_EQ(a.Get(0.1f), a.Get(0.1f));
-  EXPECT_EQ(a.Get(1.1f), a.Get(1.1f));
-  EXPECT_EQ(a.Get(2.1f), a.Get(2.1f));
+    UniqueAllocator<float> a;
+    EXPECT_NE(a.Get(0.1f), a.Get(1.1f));
+    EXPECT_NE(a.Get(1.1f), a.Get(2.1f));
+    EXPECT_EQ(a.Get(0.1f), a.Get(0.1f));
+    EXPECT_EQ(a.Get(1.1f), a.Get(1.1f));
+    EXPECT_EQ(a.Get(2.1f), a.Get(2.1f));
 }
 
 TEST(UniqueAllocator, String) {
-  UniqueAllocator<std::string> a;
-  EXPECT_NE(a.Get("x"), a.Get("y"));
-  EXPECT_NE(a.Get("z"), a.Get("w"));
-  EXPECT_EQ(a.Get("x"), a.Get("x"));
-  EXPECT_EQ(a.Get("y"), a.Get("y"));
-  EXPECT_EQ(a.Get("z"), a.Get("z"));
+    UniqueAllocator<std::string> a;
+    EXPECT_NE(a.Get("x"), a.Get("y"));
+    EXPECT_NE(a.Get("z"), a.Get("w"));
+    EXPECT_EQ(a.Get("x"), a.Get("x"));
+    EXPECT_EQ(a.Get("y"), a.Get("y"));
+    EXPECT_EQ(a.Get("z"), a.Get("z"));
 }
 
 }  // namespace
diff --git a/src/tint/utils/unique_vector.h b/src/tint/utils/unique_vector.h
index 32d593e..96d9cbf 100644
--- a/src/tint/utils/unique_vector.h
+++ b/src/tint/utils/unique_vector.h
@@ -25,85 +25,83 @@
 
 /// UniqueVector is an ordered container that only contains unique items.
 /// Attempting to add a duplicate is a no-op.
-template <typename T,
-          typename HASH = std::hash<T>,
-          typename EQUAL = std::equal_to<T>>
+template <typename T, typename HASH = std::hash<T>, typename EQUAL = std::equal_to<T>>
 struct UniqueVector {
-  /// The iterator returned by begin() and end()
-  using ConstIterator = typename std::vector<T>::const_iterator;
-  /// The iterator returned by rbegin() and rend()
-  using ConstReverseIterator = typename std::vector<T>::const_reverse_iterator;
+    /// The iterator returned by begin() and end()
+    using ConstIterator = typename std::vector<T>::const_iterator;
+    /// The iterator returned by rbegin() and rend()
+    using ConstReverseIterator = typename std::vector<T>::const_reverse_iterator;
 
-  /// Constructor
-  UniqueVector() = default;
+    /// Constructor
+    UniqueVector() = default;
 
-  /// Constructor
-  /// @param v the vector to construct this UniqueVector with. Duplicate
-  /// elements will be removed.
-  explicit UniqueVector(std::vector<T>&& v) {
-    for (auto& el : v) {
-      add(el);
+    /// Constructor
+    /// @param v the vector to construct this UniqueVector with. Duplicate
+    /// elements will be removed.
+    explicit UniqueVector(std::vector<T>&& v) {
+        for (auto& el : v) {
+            add(el);
+        }
     }
-  }
 
-  /// add appends the item to the end of the vector, if the vector does not
-  /// already contain the given item.
-  /// @param item the item to append to the end of the vector
-  /// @returns true if the item was added, otherwise false.
-  bool add(const T& item) {
-    if (set.count(item) == 0) {
-      vector.emplace_back(item);
-      set.emplace(item);
-      return true;
+    /// add appends the item to the end of the vector, if the vector does not
+    /// already contain the given item.
+    /// @param item the item to append to the end of the vector
+    /// @returns true if the item was added, otherwise false.
+    bool add(const T& item) {
+        if (set.count(item) == 0) {
+            vector.emplace_back(item);
+            set.emplace(item);
+            return true;
+        }
+        return false;
     }
-    return false;
-  }
 
-  /// @returns true if the vector contains `item`
-  /// @param item the item
-  bool contains(const T& item) const { return set.count(item); }
+    /// @returns true if the vector contains `item`
+    /// @param item the item
+    bool contains(const T& item) const { return set.count(item); }
 
-  /// @param i the index of the element to retrieve
-  /// @returns the element at the index `i`
-  T& operator[](size_t i) { return vector[i]; }
+    /// @param i the index of the element to retrieve
+    /// @returns the element at the index `i`
+    T& operator[](size_t i) { return vector[i]; }
 
-  /// @param i the index of the element to retrieve
-  /// @returns the element at the index `i`
-  const T& operator[](size_t i) const { return vector[i]; }
+    /// @param i the index of the element to retrieve
+    /// @returns the element at the index `i`
+    const T& operator[](size_t i) const { return vector[i]; }
 
-  /// @returns true if the vector is empty
-  bool empty() const { return vector.empty(); }
+    /// @returns true if the vector is empty
+    bool empty() const { return vector.empty(); }
 
-  /// @returns the number of items in the vector
-  size_t size() const { return vector.size(); }
+    /// @returns the number of items in the vector
+    size_t size() const { return vector.size(); }
 
-  /// @returns an iterator to the beginning of the vector
-  ConstIterator begin() const { return vector.begin(); }
+    /// @returns an iterator to the beginning of the vector
+    ConstIterator begin() const { return vector.begin(); }
 
-  /// @returns an iterator to the end of the vector
-  ConstIterator end() const { return vector.end(); }
+    /// @returns an iterator to the end of the vector
+    ConstIterator end() const { return vector.end(); }
 
-  /// @returns an iterator to the beginning of the reversed vector
-  ConstReverseIterator rbegin() const { return vector.rbegin(); }
+    /// @returns an iterator to the beginning of the reversed vector
+    ConstReverseIterator rbegin() const { return vector.rbegin(); }
 
-  /// @returns an iterator to the end of the reversed vector
-  ConstReverseIterator rend() const { return vector.rend(); }
+    /// @returns an iterator to the end of the reversed vector
+    ConstReverseIterator rend() const { return vector.rend(); }
 
-  /// @returns a const reference to the internal vector
-  operator const std::vector<T>&() const { return vector; }
+    /// @returns a const reference to the internal vector
+    operator const std::vector<T>&() const { return vector; }
 
-  /// Removes the last element from the vector
-  /// @returns the popped element
-  T pop_back() {
-    auto el = std::move(vector.back());
-    set.erase(el);
-    vector.pop_back();
-    return el;
-  }
+    /// Removes the last element from the vector
+    /// @returns the popped element
+    T pop_back() {
+        auto el = std::move(vector.back());
+        set.erase(el);
+        vector.pop_back();
+        return el;
+    }
 
- private:
-  std::vector<T> vector;
-  std::unordered_set<T, HASH, EQUAL> set;
+  private:
+    std::vector<T> vector;
+    std::unordered_set<T, HASH, EQUAL> set;
 };
 
 }  // namespace tint::utils
diff --git a/src/tint/utils/unique_vector_test.cc b/src/tint/utils/unique_vector_test.cc
index c2c47a4..7d586e9 100644
--- a/src/tint/utils/unique_vector_test.cc
+++ b/src/tint/utils/unique_vector_test.cc
@@ -21,122 +21,122 @@
 namespace {
 
 TEST(UniqueVectorTest, Empty) {
-  UniqueVector<int> unique_vec;
-  EXPECT_EQ(unique_vec.size(), 0u);
-  EXPECT_EQ(unique_vec.empty(), true);
-  EXPECT_EQ(unique_vec.begin(), unique_vec.end());
+    UniqueVector<int> unique_vec;
+    EXPECT_EQ(unique_vec.size(), 0u);
+    EXPECT_EQ(unique_vec.empty(), true);
+    EXPECT_EQ(unique_vec.begin(), unique_vec.end());
 }
 
 TEST(UniqueVectorTest, MoveConstructor) {
-  UniqueVector<int> unique_vec(std::vector<int>{0, 3, 2, 1, 2});
-  EXPECT_EQ(unique_vec.size(), 4u);
-  EXPECT_EQ(unique_vec.empty(), false);
-  EXPECT_EQ(unique_vec[0], 0);
-  EXPECT_EQ(unique_vec[1], 3);
-  EXPECT_EQ(unique_vec[2], 2);
-  EXPECT_EQ(unique_vec[3], 1);
+    UniqueVector<int> unique_vec(std::vector<int>{0, 3, 2, 1, 2});
+    EXPECT_EQ(unique_vec.size(), 4u);
+    EXPECT_EQ(unique_vec.empty(), false);
+    EXPECT_EQ(unique_vec[0], 0);
+    EXPECT_EQ(unique_vec[1], 3);
+    EXPECT_EQ(unique_vec[2], 2);
+    EXPECT_EQ(unique_vec[3], 1);
 }
 
 TEST(UniqueVectorTest, AddUnique) {
-  UniqueVector<int> unique_vec;
-  unique_vec.add(0);
-  unique_vec.add(1);
-  unique_vec.add(2);
-  EXPECT_EQ(unique_vec.size(), 3u);
-  EXPECT_EQ(unique_vec.empty(), false);
-  int i = 0;
-  for (auto n : unique_vec) {
-    EXPECT_EQ(n, i);
-    i++;
-  }
-  for (auto n : Reverse(unique_vec)) {
-    i--;
-    EXPECT_EQ(n, i);
-  }
-  EXPECT_EQ(unique_vec[0], 0);
-  EXPECT_EQ(unique_vec[1], 1);
-  EXPECT_EQ(unique_vec[2], 2);
+    UniqueVector<int> unique_vec;
+    unique_vec.add(0);
+    unique_vec.add(1);
+    unique_vec.add(2);
+    EXPECT_EQ(unique_vec.size(), 3u);
+    EXPECT_EQ(unique_vec.empty(), false);
+    int i = 0;
+    for (auto n : unique_vec) {
+        EXPECT_EQ(n, i);
+        i++;
+    }
+    for (auto n : Reverse(unique_vec)) {
+        i--;
+        EXPECT_EQ(n, i);
+    }
+    EXPECT_EQ(unique_vec[0], 0);
+    EXPECT_EQ(unique_vec[1], 1);
+    EXPECT_EQ(unique_vec[2], 2);
 }
 
 TEST(UniqueVectorTest, AddDuplicates) {
-  UniqueVector<int> unique_vec;
-  unique_vec.add(0);
-  unique_vec.add(0);
-  unique_vec.add(0);
-  unique_vec.add(1);
-  unique_vec.add(1);
-  unique_vec.add(2);
-  EXPECT_EQ(unique_vec.size(), 3u);
-  EXPECT_EQ(unique_vec.empty(), false);
-  int i = 0;
-  for (auto n : unique_vec) {
-    EXPECT_EQ(n, i);
-    i++;
-  }
-  for (auto n : Reverse(unique_vec)) {
-    i--;
-    EXPECT_EQ(n, i);
-  }
-  EXPECT_EQ(unique_vec[0], 0);
-  EXPECT_EQ(unique_vec[1], 1);
-  EXPECT_EQ(unique_vec[2], 2);
+    UniqueVector<int> unique_vec;
+    unique_vec.add(0);
+    unique_vec.add(0);
+    unique_vec.add(0);
+    unique_vec.add(1);
+    unique_vec.add(1);
+    unique_vec.add(2);
+    EXPECT_EQ(unique_vec.size(), 3u);
+    EXPECT_EQ(unique_vec.empty(), false);
+    int i = 0;
+    for (auto n : unique_vec) {
+        EXPECT_EQ(n, i);
+        i++;
+    }
+    for (auto n : Reverse(unique_vec)) {
+        i--;
+        EXPECT_EQ(n, i);
+    }
+    EXPECT_EQ(unique_vec[0], 0);
+    EXPECT_EQ(unique_vec[1], 1);
+    EXPECT_EQ(unique_vec[2], 2);
 }
 
 TEST(UniqueVectorTest, AsVector) {
-  UniqueVector<int> unique_vec;
-  unique_vec.add(0);
-  unique_vec.add(0);
-  unique_vec.add(0);
-  unique_vec.add(1);
-  unique_vec.add(1);
-  unique_vec.add(2);
+    UniqueVector<int> unique_vec;
+    unique_vec.add(0);
+    unique_vec.add(0);
+    unique_vec.add(0);
+    unique_vec.add(1);
+    unique_vec.add(1);
+    unique_vec.add(2);
 
-  const std::vector<int>& vec = unique_vec;
-  EXPECT_EQ(vec.size(), 3u);
-  EXPECT_EQ(unique_vec.empty(), false);
-  int i = 0;
-  for (auto n : vec) {
-    EXPECT_EQ(n, i);
-    i++;
-  }
-  for (auto n : Reverse(unique_vec)) {
-    i--;
-    EXPECT_EQ(n, i);
-  }
+    const std::vector<int>& vec = unique_vec;
+    EXPECT_EQ(vec.size(), 3u);
+    EXPECT_EQ(unique_vec.empty(), false);
+    int i = 0;
+    for (auto n : vec) {
+        EXPECT_EQ(n, i);
+        i++;
+    }
+    for (auto n : Reverse(unique_vec)) {
+        i--;
+        EXPECT_EQ(n, i);
+    }
 }
 
 TEST(UniqueVectorTest, PopBack) {
-  UniqueVector<int> unique_vec;
-  unique_vec.add(0);
-  unique_vec.add(2);
-  unique_vec.add(1);
+    UniqueVector<int> unique_vec;
+    unique_vec.add(0);
+    unique_vec.add(2);
+    unique_vec.add(1);
 
-  EXPECT_EQ(unique_vec.pop_back(), 1);
-  EXPECT_EQ(unique_vec.size(), 2u);
-  EXPECT_EQ(unique_vec.empty(), false);
-  EXPECT_EQ(unique_vec[0], 0);
-  EXPECT_EQ(unique_vec[1], 2);
+    EXPECT_EQ(unique_vec.pop_back(), 1);
+    EXPECT_EQ(unique_vec.size(), 2u);
+    EXPECT_EQ(unique_vec.empty(), false);
+    EXPECT_EQ(unique_vec[0], 0);
+    EXPECT_EQ(unique_vec[1], 2);
 
-  EXPECT_EQ(unique_vec.pop_back(), 2);
-  EXPECT_EQ(unique_vec.size(), 1u);
-  EXPECT_EQ(unique_vec.empty(), false);
-  EXPECT_EQ(unique_vec[0], 0);
+    EXPECT_EQ(unique_vec.pop_back(), 2);
+    EXPECT_EQ(unique_vec.size(), 1u);
+    EXPECT_EQ(unique_vec.empty(), false);
+    EXPECT_EQ(unique_vec[0], 0);
 
-  unique_vec.add(1);
+    unique_vec.add(1);
 
-  EXPECT_EQ(unique_vec.size(), 2u);
-  EXPECT_EQ(unique_vec.empty(), false);
-  EXPECT_EQ(unique_vec[0], 0);
-  EXPECT_EQ(unique_vec[1], 1);
+    EXPECT_EQ(unique_vec.size(), 2u);
+    EXPECT_EQ(unique_vec.empty(), false);
+    EXPECT_EQ(unique_vec[0], 0);
+    EXPECT_EQ(unique_vec[1], 1);
 
-  EXPECT_EQ(unique_vec.pop_back(), 1);
-  EXPECT_EQ(unique_vec.size(), 1u);
-  EXPECT_EQ(unique_vec.empty(), false);
-  EXPECT_EQ(unique_vec[0], 0);
+    EXPECT_EQ(unique_vec.pop_back(), 1);
+    EXPECT_EQ(unique_vec.size(), 1u);
+    EXPECT_EQ(unique_vec.empty(), false);
+    EXPECT_EQ(unique_vec[0], 0);
 
-  EXPECT_EQ(unique_vec.pop_back(), 0);
-  EXPECT_EQ(unique_vec.size(), 0u);
-  EXPECT_EQ(unique_vec.empty(), true);
+    EXPECT_EQ(unique_vec.pop_back(), 0);
+    EXPECT_EQ(unique_vec.size(), 0u);
+    EXPECT_EQ(unique_vec.empty(), true);
 }
 
 }  // namespace
diff --git a/src/tint/val/hlsl.cc b/src/tint/val/hlsl.cc
index a817a5d..49c3850 100644
--- a/src/tint/val/hlsl.cc
+++ b/src/tint/val/hlsl.cc
@@ -30,146 +30,167 @@
 
 Result HlslUsingDXC(const std::string& dxc_path,
                     const std::string& source,
-                    const EntryPointList& entry_points) {
-  Result result;
+                    const EntryPointList& entry_points,
+                    const std::vector<std::string>& overrides) {
+    Result result;
 
-  auto dxc = utils::Command(dxc_path);
-  if (!dxc.Found()) {
-    result.output = "DXC not found at '" + std::string(dxc_path) + "'";
-    result.failed = true;
-    return result;
-  }
-
-  utils::TmpFile file;
-  file << source;
-
-  for (auto ep : entry_points) {
-    const char* profile = "";
-
-    switch (ep.second) {
-      case ast::PipelineStage::kNone:
-        result.output = "Invalid PipelineStage";
+    auto dxc = utils::Command(dxc_path);
+    if (!dxc.Found()) {
+        result.output = "DXC not found at '" + std::string(dxc_path) + "'";
         result.failed = true;
         return result;
-      case ast::PipelineStage::kVertex:
-        profile = "-T vs_6_0";
-        break;
-      case ast::PipelineStage::kFragment:
-        profile = "-T ps_6_0";
-        break;
-      case ast::PipelineStage::kCompute:
-        profile = "-T cs_6_0";
-        break;
     }
 
-    // Match Dawn's compile flags
-    // See dawn\src\dawn_native\d3d12\RenderPipelineD3D12.cpp
-    // and dawn_native\d3d12\ShaderModuleD3D12.cpp (GetDXCArguments)
-    const char* compileFlags =
-        "/Zpr "  // D3DCOMPILE_PACK_MATRIX_ROW_MAJOR
-        "/Gis";  // D3DCOMPILE_IEEE_STRICTNESS
+    utils::TmpFile file;
+    file << source;
 
-    auto res = dxc(profile, "-E " + ep.first, compileFlags, file.Path());
-    if (!res.out.empty()) {
-      if (!result.output.empty()) {
-        result.output += "\n";
-      }
-      result.output += res.out;
-    }
-    if (!res.err.empty()) {
-      if (!result.output.empty()) {
-        result.output += "\n";
-      }
-      result.output += res.err;
-    }
-    result.failed = (res.error_code != 0);
-  }
+    for (auto ep : entry_points) {
+        const char* profile = "";
 
-  if (entry_points.empty()) {
-    result.output = "No entrypoint found";
-    result.failed = true;
+        switch (ep.second) {
+            case ast::PipelineStage::kNone:
+                result.output = "Invalid PipelineStage";
+                result.failed = true;
+                return result;
+            case ast::PipelineStage::kVertex:
+                profile = "-T vs_6_0";
+                break;
+            case ast::PipelineStage::kFragment:
+                profile = "-T ps_6_0";
+                break;
+            case ast::PipelineStage::kCompute:
+                profile = "-T cs_6_0";
+                break;
+        }
+
+        // Match Dawn's compile flags
+        // See dawn\src\dawn_native\d3d12\RenderPipelineD3D12.cpp
+        // and dawn_native\d3d12\ShaderModuleD3D12.cpp (GetDXCArguments)
+        const char* compileFlags =
+            "/Zpr "  // D3DCOMPILE_PACK_MATRIX_ROW_MAJOR
+            "/Gis";  // D3DCOMPILE_IEEE_STRICTNESS
+
+        std::string defs;
+        defs.reserve(overrides.size() * 20);
+        for (auto& o : overrides) {
+            defs += "/D" + o + " ";
+        }
+
+        auto res = dxc(profile, "-E " + ep.first, compileFlags, file.Path(), defs);
+        if (!res.out.empty()) {
+            if (!result.output.empty()) {
+                result.output += "\n";
+            }
+            result.output += res.out;
+        }
+        if (!res.err.empty()) {
+            if (!result.output.empty()) {
+                result.output += "\n";
+            }
+            result.output += res.err;
+        }
+        result.failed = (res.error_code != 0);
+    }
+
+    if (entry_points.empty()) {
+        result.output = "No entrypoint found";
+        result.failed = true;
+        return result;
+    }
+
     return result;
-  }
-
-  return result;
 }
 
 #ifdef _WIN32
 Result HlslUsingFXC(const std::string& source,
-                    const EntryPointList& entry_points) {
-  Result result;
+                    const EntryPointList& entry_points,
+                    const std::vector<std::string>& overrides) {
+    Result result;
 
-  // This library leaks if an error happens in this function, but it is ok
-  // because it is loaded at most once, and the executables using HlslUsingFXC
-  // are short-lived.
-  HMODULE fxcLib = LoadLibraryA("d3dcompiler_47.dll");
-  if (fxcLib == nullptr) {
-    result.output = "Couldn't load FXC";
-    result.failed = true;
-    return result;
-  }
-
-  pD3DCompile d3dCompile = reinterpret_cast<pD3DCompile>(
-      reinterpret_cast<void*>(GetProcAddress(fxcLib, "D3DCompile")));
-  if (d3dCompile == nullptr) {
-    result.output = "Couldn't load D3DCompile from FXC";
-    result.failed = true;
-    return result;
-  }
-
-  for (auto ep : entry_points) {
-    const char* profile = "";
-    switch (ep.second) {
-      case ast::PipelineStage::kNone:
-        result.output = "Invalid PipelineStage";
+    // This library leaks if an error happens in this function, but it is ok
+    // because it is loaded at most once, and the executables using HlslUsingFXC
+    // are short-lived.
+    HMODULE fxcLib = LoadLibraryA("d3dcompiler_47.dll");
+    if (fxcLib == nullptr) {
+        result.output = "Couldn't load FXC";
         result.failed = true;
         return result;
-      case ast::PipelineStage::kVertex:
-        profile = "vs_5_1";
-        break;
-      case ast::PipelineStage::kFragment:
-        profile = "ps_5_1";
-        break;
-      case ast::PipelineStage::kCompute:
-        profile = "cs_5_1";
-        break;
     }
 
-    // Match Dawn's compile flags
-    // See dawn\src\dawn_native\d3d12\RenderPipelineD3D12.cpp
-    UINT compileFlags = D3DCOMPILE_OPTIMIZATION_LEVEL0 |
-                        D3DCOMPILE_PACK_MATRIX_ROW_MAJOR |
-                        D3DCOMPILE_IEEE_STRICTNESS;
-
-    ComPtr<ID3DBlob> compiledShader;
-    ComPtr<ID3DBlob> errors;
-    HRESULT cr = d3dCompile(source.c_str(),    // pSrcData
-                            source.length(),   // SrcDataSize
-                            nullptr,           // pSourceName
-                            nullptr,           // pDefines
-                            nullptr,           // pInclude
-                            ep.first.c_str(),  // pEntrypoint
-                            profile,           // pTarget
-                            compileFlags,      // Flags1
-                            0,                 // Flags2
-                            &compiledShader,   // ppCode
-                            &errors);          // ppErrorMsgs
-    if (FAILED(cr)) {
-      result.output = static_cast<char*>(errors->GetBufferPointer());
-      result.failed = true;
-      return result;
+    pD3DCompile d3dCompile = reinterpret_cast<pD3DCompile>(
+        reinterpret_cast<void*>(GetProcAddress(fxcLib, "D3DCompile")));
+    if (d3dCompile == nullptr) {
+        result.output = "Couldn't load D3DCompile from FXC";
+        result.failed = true;
+        return result;
     }
-  }
 
-  FreeLibrary(fxcLib);
+    for (auto ep : entry_points) {
+        const char* profile = "";
+        switch (ep.second) {
+            case ast::PipelineStage::kNone:
+                result.output = "Invalid PipelineStage";
+                result.failed = true;
+                return result;
+            case ast::PipelineStage::kVertex:
+                profile = "vs_5_1";
+                break;
+            case ast::PipelineStage::kFragment:
+                profile = "ps_5_1";
+                break;
+            case ast::PipelineStage::kCompute:
+                profile = "cs_5_1";
+                break;
+        }
 
-  if (entry_points.empty()) {
-    result.output = "No entrypoint found";
-    result.failed = true;
+        // Match Dawn's compile flags
+        // See dawn\src\dawn_native\d3d12\RenderPipelineD3D12.cpp
+        UINT compileFlags = D3DCOMPILE_OPTIMIZATION_LEVEL0 | D3DCOMPILE_PACK_MATRIX_ROW_MAJOR |
+                            D3DCOMPILE_IEEE_STRICTNESS;
+
+        auto overrides_copy = overrides;  // Copy so that we can replace '=' with '\0'
+        std::vector<D3D_SHADER_MACRO> macros;
+        macros.reserve(overrides_copy.size() * 2);
+        for (auto& o : overrides_copy) {
+            if (auto sep = o.find_first_of('='); sep != std::string::npos) {
+                // Replace '=' with '\0' so we can point directly into the allocated string buffer
+                o[sep] = '\0';
+                macros.push_back(D3D_SHADER_MACRO{&o[0], &o[sep + 1]});
+            } else {
+                macros.emplace_back(D3D_SHADER_MACRO{o.c_str(), NULL});
+            }
+        }
+        macros.emplace_back(D3D_SHADER_MACRO{NULL, NULL});
+
+        ComPtr<ID3DBlob> compiledShader;
+        ComPtr<ID3DBlob> errors;
+        HRESULT cr = d3dCompile(source.c_str(),    // pSrcData
+                                source.length(),   // SrcDataSize
+                                nullptr,           // pSourceName
+                                macros.data(),     // pDefines
+                                nullptr,           // pInclude
+                                ep.first.c_str(),  // pEntrypoint
+                                profile,           // pTarget
+                                compileFlags,      // Flags1
+                                0,                 // Flags2
+                                &compiledShader,   // ppCode
+                                &errors);          // ppErrorMsgs
+        if (FAILED(cr)) {
+            result.output = static_cast<char*>(errors->GetBufferPointer());
+            result.failed = true;
+            return result;
+        }
+    }
+
+    FreeLibrary(fxcLib);
+
+    if (entry_points.empty()) {
+        result.output = "No entrypoint found";
+        result.failed = true;
+        return result;
+    }
+
     return result;
-  }
-
-  return result;
 }
 #endif  // _WIN32
 
diff --git a/src/tint/val/msl.cc b/src/tint/val/msl.cc
index 68e3c29..13bae1d 100644
--- a/src/tint/val/msl.cc
+++ b/src/tint/val/msl.cc
@@ -22,46 +22,46 @@
 namespace tint::val {
 
 Result Msl(const std::string& xcrun_path, const std::string& source) {
-  Result result;
+    Result result;
 
-  auto xcrun = utils::Command(xcrun_path);
-  if (!xcrun.Found()) {
-    result.output = "xcrun not found at '" + std::string(xcrun_path) + "'";
-    result.failed = true;
-    return result;
-  }
+    auto xcrun = utils::Command(xcrun_path);
+    if (!xcrun.Found()) {
+        result.output = "xcrun not found at '" + std::string(xcrun_path) + "'";
+        result.failed = true;
+        return result;
+    }
 
-  utils::TmpFile file(".metal");
-  file << source;
+    utils::TmpFile file(".metal");
+    file << source;
 
 #ifdef _WIN32
-  // On Windows, we should actually be running metal.exe from the Metal
-  // Developer Tools for Windows
-  auto res = xcrun("-x", "metal",        //
-                   "-o", "NUL",          //
-                   "-std=osx-metal1.2",  //
-                   "-c", file.Path());
+    // On Windows, we should actually be running metal.exe from the Metal
+    // Developer Tools for Windows
+    auto res = xcrun("-x", "metal",        //
+                     "-o", "NUL",          //
+                     "-std=osx-metal1.2",  //
+                     "-c", file.Path());
 #else
-  auto res = xcrun("-sdk", "macosx", "metal",  //
-                   "-o", "/dev/null",          //
-                   "-std=osx-metal1.2",        //
-                   "-c", file.Path());
+    auto res = xcrun("-sdk", "macosx", "metal",  //
+                     "-o", "/dev/null",          //
+                     "-std=osx-metal1.2",        //
+                     "-c", file.Path());
 #endif
-  if (!res.out.empty()) {
-    if (!result.output.empty()) {
-      result.output += "\n";
+    if (!res.out.empty()) {
+        if (!result.output.empty()) {
+            result.output += "\n";
+        }
+        result.output += res.out;
     }
-    result.output += res.out;
-  }
-  if (!res.err.empty()) {
-    if (!result.output.empty()) {
-      result.output += "\n";
+    if (!res.err.empty()) {
+        if (!result.output.empty()) {
+            result.output += "\n";
+        }
+        result.output += res.err;
     }
-    result.output += res.err;
-  }
-  result.failed = (res.error_code != 0);
+    result.failed = (res.error_code != 0);
 
-  return result;
+    return result;
 }
 
 }  // namespace tint::val
diff --git a/src/tint/val/msl_metal.mm b/src/tint/val/msl_metal.mm
index ad0271f..4e60959 100644
--- a/src/tint/val/msl_metal.mm
+++ b/src/tint/val/msl_metal.mm
@@ -25,33 +25,32 @@
 namespace tint::val {
 
 Result MslUsingMetalAPI(const std::string& src) {
-  tint::val::Result result;
+    tint::val::Result result;
 
-  NSError* error = nil;
+    NSError* error = nil;
 
-  id<MTLDevice> device = MTLCreateSystemDefaultDevice();
-  if (!device) {
-    result.output = "MTLCreateSystemDefaultDevice returned null";
-    result.failed = true;
+    id<MTLDevice> device = MTLCreateSystemDefaultDevice();
+    if (!device) {
+        result.output = "MTLCreateSystemDefaultDevice returned null";
+        result.failed = true;
+        return result;
+    }
+
+    NSString* source = [NSString stringWithCString:src.c_str() encoding:NSUTF8StringEncoding];
+
+    MTLCompileOptions* compileOptions = [MTLCompileOptions new];
+    compileOptions.languageVersion = MTLLanguageVersion1_2;
+
+    id<MTLLibrary> library = [device newLibraryWithSource:source
+                                                  options:compileOptions
+                                                    error:&error];
+    if (!library) {
+        NSString* output = [error localizedDescription];
+        result.output = [output UTF8String];
+        result.failed = true;
+    }
+
     return result;
-  }
-
-  NSString* source = [NSString stringWithCString:src.c_str()
-                                        encoding:NSUTF8StringEncoding];
-
-  MTLCompileOptions* compileOptions = [MTLCompileOptions new];
-  compileOptions.languageVersion = MTLLanguageVersion1_2;
-
-  id<MTLLibrary> library = [device newLibraryWithSource:source
-                                                options:compileOptions
-                                                  error:&error];
-  if (!library) {
-    NSString* output = [error localizedDescription];
-    result.output = [output UTF8String];
-    result.failed = true;
-  }
-
-  return result;
 }
 
 }  // namespace tint::val
diff --git a/src/tint/val/val.h b/src/tint/val/val.h
index a936181..c869efb 100644
--- a/src/tint/val/val.h
+++ b/src/tint/val/val.h
@@ -32,10 +32,10 @@
 
 /// The return structure of Validate()
 struct Result {
-  /// True if validation passed
-  bool failed = false;
-  /// Output of DXC.
-  std::string output;
+    /// True if validation passed
+    bool failed = false;
+    /// Output of DXC.
+    std::string output;
 };
 
 /// Hlsl attempts to compile the shader with DXC, verifying that the shader
@@ -43,19 +43,23 @@
 /// @param dxc_path path to DXC
 /// @param source the generated HLSL source
 /// @param entry_points the list of entry points to validate
+/// @param overrides optional list of pipeline overrides
 /// @return the result of the compile
 Result HlslUsingDXC(const std::string& dxc_path,
                     const std::string& source,
-                    const EntryPointList& entry_points);
+                    const EntryPointList& entry_points,
+                    const std::vector<std::string>& overrides);
 
 #ifdef _WIN32
 /// Hlsl attempts to compile the shader with FXC, verifying that the shader
 /// compiles successfully.
 /// @param source the generated HLSL source
 /// @param entry_points the list of entry points to validate
+/// @param overrides optional list of pipeline overrides
 /// @return the result of the compile
 Result HlslUsingFXC(const std::string& source,
-                    const EntryPointList& entry_points);
+                    const EntryPointList& entry_points,
+                    const std::vector<std::string>& overrides);
 #endif  // _WIN32
 
 /// Msl attempts to compile the shader with the Metal Shader Compiler,
diff --git a/src/tint/writer/append_vector.cc b/src/tint/writer/append_vector.cc
index 5c02917..d3d11c1 100644
--- a/src/tint/writer/append_vector.cc
+++ b/src/tint/writer/append_vector.cc
@@ -23,46 +23,46 @@
 #include "src/tint/sem/type_conversion.h"
 #include "src/tint/utils/transform.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer {
 namespace {
 
 struct VectorConstructorInfo {
-  const sem::Call* call = nullptr;
-  const sem::TypeConstructor* ctor = nullptr;
-  operator bool() const { return call != nullptr; }
+    const sem::Call* call = nullptr;
+    const sem::TypeConstructor* ctor = nullptr;
+    operator bool() const { return call != nullptr; }
 };
 VectorConstructorInfo AsVectorConstructor(const sem::Expression* expr) {
-  if (auto* call = expr->As<sem::Call>()) {
-    if (auto* ctor = call->Target()->As<sem::TypeConstructor>()) {
-      if (ctor->ReturnType()->Is<sem::Vector>()) {
-        return {call, ctor};
-      }
+    if (auto* call = expr->As<sem::Call>()) {
+        if (auto* ctor = call->Target()->As<sem::TypeConstructor>()) {
+            if (ctor->ReturnType()->Is<sem::Vector>()) {
+                return {call, ctor};
+            }
+        }
     }
-  }
-  return {};
+    return {};
 }
 
-const sem::Expression* Zero(ProgramBuilder& b,
-                            const sem::Type* ty,
-                            const sem::Statement* stmt) {
-  const ast::Expression* expr = nullptr;
-  if (ty->Is<sem::I32>()) {
-    expr = b.Expr(0);
-  } else if (ty->Is<sem::U32>()) {
-    expr = b.Expr(0u);
-  } else if (ty->Is<sem::F32>()) {
-    expr = b.Expr(0.0f);
-  } else if (ty->Is<sem::Bool>()) {
-    expr = b.Expr(false);
-  } else {
-    TINT_UNREACHABLE(Writer, b.Diagnostics())
-        << "unsupported vector element type: " << ty->TypeInfo().name;
-    return nullptr;
-  }
-  auto* sem = b.create<sem::Expression>(expr, ty, stmt, sem::Constant{},
-                                        /* has_side_effects */ false);
-  b.Sem().Add(expr, sem);
-  return sem;
+const sem::Expression* Zero(ProgramBuilder& b, const sem::Type* ty, const sem::Statement* stmt) {
+    const ast::Expression* expr = nullptr;
+    if (ty->Is<sem::I32>()) {
+        expr = b.Expr(0_i);
+    } else if (ty->Is<sem::U32>()) {
+        expr = b.Expr(0_u);
+    } else if (ty->Is<sem::F32>()) {
+        expr = b.Expr(0.0f);
+    } else if (ty->Is<sem::Bool>()) {
+        expr = b.Expr(false);
+    } else {
+        TINT_UNREACHABLE(Writer, b.Diagnostics())
+            << "unsupported vector element type: " << ty->TypeInfo().name;
+        return nullptr;
+    }
+    auto* sem = b.create<sem::Expression>(expr, ty, stmt, sem::Constant{},
+                                          /* has_side_effects */ false);
+    b.Sem().Add(expr, sem);
+    return sem;
 }
 
 }  // namespace
@@ -70,104 +70,98 @@
 const sem::Call* AppendVector(ProgramBuilder* b,
                               const ast::Expression* vector_ast,
                               const ast::Expression* scalar_ast) {
-  uint32_t packed_size;
-  const sem::Type* packed_el_sem_ty;
-  auto* vector_sem = b->Sem().Get(vector_ast);
-  auto* scalar_sem = b->Sem().Get(scalar_ast);
-  auto* vector_ty = vector_sem->Type()->UnwrapRef();
-  if (auto* vec = vector_ty->As<sem::Vector>()) {
-    packed_size = vec->Width() + 1;
-    packed_el_sem_ty = vec->type();
-  } else {
-    packed_size = 2;
-    packed_el_sem_ty = vector_ty;
-  }
-
-  const ast::Type* packed_el_ast_ty = nullptr;
-  if (packed_el_sem_ty->Is<sem::I32>()) {
-    packed_el_ast_ty = b->create<ast::I32>();
-  } else if (packed_el_sem_ty->Is<sem::U32>()) {
-    packed_el_ast_ty = b->create<ast::U32>();
-  } else if (packed_el_sem_ty->Is<sem::F32>()) {
-    packed_el_ast_ty = b->create<ast::F32>();
-  } else if (packed_el_sem_ty->Is<sem::Bool>()) {
-    packed_el_ast_ty = b->create<ast::Bool>();
-  } else {
-    TINT_UNREACHABLE(Writer, b->Diagnostics())
-        << "unsupported vector element type: "
-        << packed_el_sem_ty->TypeInfo().name;
-  }
-
-  auto* statement = vector_sem->Stmt();
-
-  auto* packed_ast_ty = b->create<ast::Vector>(packed_el_ast_ty, packed_size);
-  auto* packed_sem_ty = b->create<sem::Vector>(packed_el_sem_ty, packed_size);
-
-  // If the coordinates are already passed in a vector constructor, with only
-  // scalar components supplied, extract the elements into the new vector
-  // instead of nesting a vector-in-vector.
-  // If the coordinates are a zero-constructor of the vector, then expand that
-  // to scalar zeros.
-  // The other cases for a nested vector constructor are when it is used
-  // to convert a vector of a different type, e.g. vec2<i32>(vec2<u32>()).
-  // In that case, preserve the original argument, or you'll get a type error.
-
-  std::vector<const sem::Expression*> packed;
-  if (auto vc = AsVectorConstructor(vector_sem)) {
-    const auto num_supplied = vc.call->Arguments().size();
-    if (num_supplied == 0) {
-      // Zero-value vector constructor. Populate with zeros
-      for (uint32_t i = 0; i < packed_size - 1; i++) {
-        auto* zero = Zero(*b, packed_el_sem_ty, statement);
-        packed.emplace_back(zero);
-      }
-    } else if (num_supplied + 1 == packed_size) {
-      // All vector components were supplied as scalars.  Pass them through.
-      packed = vc.call->Arguments();
+    uint32_t packed_size;
+    const sem::Type* packed_el_sem_ty;
+    auto* vector_sem = b->Sem().Get(vector_ast);
+    auto* scalar_sem = b->Sem().Get(scalar_ast);
+    auto* vector_ty = vector_sem->Type()->UnwrapRef();
+    if (auto* vec = vector_ty->As<sem::Vector>()) {
+        packed_size = vec->Width() + 1;
+        packed_el_sem_ty = vec->type();
+    } else {
+        packed_size = 2;
+        packed_el_sem_ty = vector_ty;
     }
-  }
-  if (packed.empty()) {
-    // The special cases didn't occur. Use the vector argument as-is.
-    packed.emplace_back(vector_sem);
-  }
 
-  if (packed_el_sem_ty != scalar_sem->Type()->UnwrapRef()) {
-    // Cast scalar to the vector element type
-    auto* scalar_cast_ast = b->Construct(packed_el_ast_ty, scalar_ast);
-    auto* scalar_cast_target = b->create<sem::TypeConversion>(
-        packed_el_sem_ty,
-        b->create<sem::Parameter>(nullptr, 0, scalar_sem->Type()->UnwrapRef(),
-                                  ast::StorageClass::kNone,
-                                  ast::Access::kUndefined));
-    auto* scalar_cast_sem = b->create<sem::Call>(
-        scalar_cast_ast, scalar_cast_target,
-        std::vector<const sem::Expression*>{scalar_sem}, statement,
-        sem::Constant{}, /* has_side_effects */ false);
-    b->Sem().Add(scalar_cast_ast, scalar_cast_sem);
-    packed.emplace_back(scalar_cast_sem);
-  } else {
-    packed.emplace_back(scalar_sem);
-  }
+    const ast::Type* packed_el_ast_ty = nullptr;
+    if (packed_el_sem_ty->Is<sem::I32>()) {
+        packed_el_ast_ty = b->create<ast::I32>();
+    } else if (packed_el_sem_ty->Is<sem::U32>()) {
+        packed_el_ast_ty = b->create<ast::U32>();
+    } else if (packed_el_sem_ty->Is<sem::F32>()) {
+        packed_el_ast_ty = b->create<ast::F32>();
+    } else if (packed_el_sem_ty->Is<sem::Bool>()) {
+        packed_el_ast_ty = b->create<ast::Bool>();
+    } else {
+        TINT_UNREACHABLE(Writer, b->Diagnostics())
+            << "unsupported vector element type: " << packed_el_sem_ty->TypeInfo().name;
+    }
 
-  auto* constructor_ast = b->Construct(
-      packed_ast_ty, utils::Transform(packed, [&](const sem::Expression* expr) {
-        return expr->Declaration();
-      }));
-  auto* constructor_target = b->create<sem::TypeConstructor>(
-      packed_sem_ty, utils::Transform(packed,
-                                      [&](const tint::sem::Expression* arg,
-                                          size_t i) -> const sem::Parameter* {
-                                        return b->create<sem::Parameter>(
-                                            nullptr, static_cast<uint32_t>(i),
-                                            arg->Type()->UnwrapRef(),
-                                            ast::StorageClass::kNone,
-                                            ast::Access::kUndefined);
-                                      }));
-  auto* constructor_sem = b->create<sem::Call>(
-      constructor_ast, constructor_target, packed, statement, sem::Constant{},
-      /* has_side_effects */ false);
-  b->Sem().Add(constructor_ast, constructor_sem);
-  return constructor_sem;
+    auto* statement = vector_sem->Stmt();
+
+    auto* packed_ast_ty = b->create<ast::Vector>(packed_el_ast_ty, packed_size);
+    auto* packed_sem_ty = b->create<sem::Vector>(packed_el_sem_ty, packed_size);
+
+    // If the coordinates are already passed in a vector constructor, with only
+    // scalar components supplied, extract the elements into the new vector
+    // instead of nesting a vector-in-vector.
+    // If the coordinates are a zero-constructor of the vector, then expand that
+    // to scalar zeros.
+    // The other cases for a nested vector constructor are when it is used
+    // to convert a vector of a different type, e.g. vec2<i32>(vec2<u32>()).
+    // In that case, preserve the original argument, or you'll get a type error.
+
+    std::vector<const sem::Expression*> packed;
+    if (auto vc = AsVectorConstructor(vector_sem)) {
+        const auto num_supplied = vc.call->Arguments().size();
+        if (num_supplied == 0) {
+            // Zero-value vector constructor. Populate with zeros
+            for (uint32_t i = 0; i < packed_size - 1; i++) {
+                auto* zero = Zero(*b, packed_el_sem_ty, statement);
+                packed.emplace_back(zero);
+            }
+        } else if (num_supplied + 1 == packed_size) {
+            // All vector components were supplied as scalars.  Pass them through.
+            packed = vc.call->Arguments();
+        }
+    }
+    if (packed.empty()) {
+        // The special cases didn't occur. Use the vector argument as-is.
+        packed.emplace_back(vector_sem);
+    }
+
+    if (packed_el_sem_ty != scalar_sem->Type()->UnwrapRef()) {
+        // Cast scalar to the vector element type
+        auto* scalar_cast_ast = b->Construct(packed_el_ast_ty, scalar_ast);
+        auto* scalar_cast_target = b->create<sem::TypeConversion>(
+            packed_el_sem_ty,
+            b->create<sem::Parameter>(nullptr, 0, scalar_sem->Type()->UnwrapRef(),
+                                      ast::StorageClass::kNone, ast::Access::kUndefined));
+        auto* scalar_cast_sem = b->create<sem::Call>(
+            scalar_cast_ast, scalar_cast_target, std::vector<const sem::Expression*>{scalar_sem},
+            statement, sem::Constant{}, /* has_side_effects */ false);
+        b->Sem().Add(scalar_cast_ast, scalar_cast_sem);
+        packed.emplace_back(scalar_cast_sem);
+    } else {
+        packed.emplace_back(scalar_sem);
+    }
+
+    auto* constructor_ast = b->Construct(
+        packed_ast_ty,
+        utils::Transform(packed, [&](const sem::Expression* expr) { return expr->Declaration(); }));
+    auto* constructor_target = b->create<sem::TypeConstructor>(
+        packed_sem_ty,
+        utils::Transform(
+            packed, [&](const tint::sem::Expression* arg, size_t i) -> const sem::Parameter* {
+                return b->create<sem::Parameter>(nullptr, static_cast<uint32_t>(i),
+                                                 arg->Type()->UnwrapRef(), ast::StorageClass::kNone,
+                                                 ast::Access::kUndefined);
+            }));
+    auto* constructor_sem = b->create<sem::Call>(constructor_ast, constructor_target, packed,
+                                                 statement, sem::Constant{},
+                                                 /* has_side_effects */ false);
+    b->Sem().Add(constructor_ast, constructor_sem);
+    return constructor_sem;
 }
 
 }  // namespace tint::writer
diff --git a/src/tint/writer/append_vector_test.cc b/src/tint/writer/append_vector_test.cc
index e5b4292..5a9551e 100644
--- a/src/tint/writer/append_vector_test.cc
+++ b/src/tint/writer/append_vector_test.cc
@@ -19,6 +19,8 @@
 
 #include "gtest/gtest.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer {
 namespace {
 
@@ -26,460 +28,459 @@
 
 // AppendVector(vec2<i32>(1, 2), 3) -> vec3<i32>(1, 2, 3)
 TEST_F(AppendVectorTest, Vec2i32_i32) {
-  auto* scalar_1 = Expr(1);
-  auto* scalar_2 = Expr(2);
-  auto* scalar_3 = Expr(3);
-  auto* vec_12 = vec2<i32>(scalar_1, scalar_2);
-  WrapInFunction(vec_12, scalar_3);
+    auto* scalar_1 = Expr(1_i);
+    auto* scalar_2 = Expr(2_i);
+    auto* scalar_3 = Expr(3_i);
+    auto* vec_12 = vec2<i32>(scalar_1, scalar_2);
+    WrapInFunction(vec_12, scalar_3);
 
-  resolver::Resolver resolver(this);
-  ASSERT_TRUE(resolver.Resolve()) << resolver.error();
+    resolver::Resolver resolver(this);
+    ASSERT_TRUE(resolver.Resolve()) << resolver.error();
 
-  auto* append = AppendVector(this, vec_12, scalar_3);
+    auto* append = AppendVector(this, vec_12, scalar_3);
 
-  auto* vec_123 = As<ast::CallExpression>(append->Declaration());
-  ASSERT_NE(vec_123, nullptr);
-  ASSERT_EQ(vec_123->args.size(), 3u);
-  EXPECT_EQ(vec_123->args[0], scalar_1);
-  EXPECT_EQ(vec_123->args[1], scalar_2);
-  EXPECT_EQ(vec_123->args[2], scalar_3);
+    auto* vec_123 = As<ast::CallExpression>(append->Declaration());
+    ASSERT_NE(vec_123, nullptr);
+    ASSERT_EQ(vec_123->args.size(), 3u);
+    EXPECT_EQ(vec_123->args[0], scalar_1);
+    EXPECT_EQ(vec_123->args[1], scalar_2);
+    EXPECT_EQ(vec_123->args[2], scalar_3);
 
-  auto* call = Sem().Get(vec_123);
-  ASSERT_NE(call, nullptr);
-  ASSERT_EQ(call->Arguments().size(), 3u);
-  EXPECT_EQ(call->Arguments()[0], Sem().Get(scalar_1));
-  EXPECT_EQ(call->Arguments()[1], Sem().Get(scalar_2));
-  EXPECT_EQ(call->Arguments()[2], Sem().Get(scalar_3));
+    auto* call = Sem().Get(vec_123);
+    ASSERT_NE(call, nullptr);
+    ASSERT_EQ(call->Arguments().size(), 3u);
+    EXPECT_EQ(call->Arguments()[0], Sem().Get(scalar_1));
+    EXPECT_EQ(call->Arguments()[1], Sem().Get(scalar_2));
+    EXPECT_EQ(call->Arguments()[2], Sem().Get(scalar_3));
 
-  auto* ctor = call->Target()->As<sem::TypeConstructor>();
-  ASSERT_NE(ctor, nullptr);
-  ASSERT_TRUE(ctor->ReturnType()->Is<sem::Vector>());
-  EXPECT_EQ(ctor->ReturnType()->As<sem::Vector>()->Width(), 3u);
-  EXPECT_TRUE(ctor->ReturnType()->As<sem::Vector>()->type()->Is<sem::I32>());
-  EXPECT_EQ(ctor->ReturnType(), call->Type());
+    auto* ctor = call->Target()->As<sem::TypeConstructor>();
+    ASSERT_NE(ctor, nullptr);
+    ASSERT_TRUE(ctor->ReturnType()->Is<sem::Vector>());
+    EXPECT_EQ(ctor->ReturnType()->As<sem::Vector>()->Width(), 3u);
+    EXPECT_TRUE(ctor->ReturnType()->As<sem::Vector>()->type()->Is<sem::I32>());
+    EXPECT_EQ(ctor->ReturnType(), call->Type());
 
-  ASSERT_EQ(ctor->Parameters().size(), 3u);
-  EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::I32>());
-  EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::I32>());
-  EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::I32>());
+    ASSERT_EQ(ctor->Parameters().size(), 3u);
+    EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::I32>());
+    EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::I32>());
+    EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::I32>());
 }
 
 // AppendVector(vec2<i32>(1, 2), 3u) -> vec3<i32>(1, 2, i32(3u))
 TEST_F(AppendVectorTest, Vec2i32_u32) {
-  auto* scalar_1 = Expr(1);
-  auto* scalar_2 = Expr(2);
-  auto* scalar_3 = Expr(3u);
-  auto* vec_12 = vec2<i32>(scalar_1, scalar_2);
-  WrapInFunction(vec_12, scalar_3);
+    auto* scalar_1 = Expr(1_i);
+    auto* scalar_2 = Expr(2_i);
+    auto* scalar_3 = Expr(3_u);
+    auto* vec_12 = vec2<i32>(scalar_1, scalar_2);
+    WrapInFunction(vec_12, scalar_3);
 
-  resolver::Resolver resolver(this);
-  ASSERT_TRUE(resolver.Resolve()) << resolver.error();
+    resolver::Resolver resolver(this);
+    ASSERT_TRUE(resolver.Resolve()) << resolver.error();
 
-  auto* append = AppendVector(this, vec_12, scalar_3);
+    auto* append = AppendVector(this, vec_12, scalar_3);
 
-  auto* vec_123 = As<ast::CallExpression>(append->Declaration());
-  ASSERT_NE(vec_123, nullptr);
-  ASSERT_EQ(vec_123->args.size(), 3u);
-  EXPECT_EQ(vec_123->args[0], scalar_1);
-  EXPECT_EQ(vec_123->args[1], scalar_2);
-  auto* u32_to_i32 = vec_123->args[2]->As<ast::CallExpression>();
-  ASSERT_NE(u32_to_i32, nullptr);
-  EXPECT_TRUE(u32_to_i32->target.type->Is<ast::I32>());
-  ASSERT_EQ(u32_to_i32->args.size(), 1u);
-  EXPECT_EQ(u32_to_i32->args[0], scalar_3);
+    auto* vec_123 = As<ast::CallExpression>(append->Declaration());
+    ASSERT_NE(vec_123, nullptr);
+    ASSERT_EQ(vec_123->args.size(), 3u);
+    EXPECT_EQ(vec_123->args[0], scalar_1);
+    EXPECT_EQ(vec_123->args[1], scalar_2);
+    auto* u32_to_i32 = vec_123->args[2]->As<ast::CallExpression>();
+    ASSERT_NE(u32_to_i32, nullptr);
+    EXPECT_TRUE(u32_to_i32->target.type->Is<ast::I32>());
+    ASSERT_EQ(u32_to_i32->args.size(), 1u);
+    EXPECT_EQ(u32_to_i32->args[0], scalar_3);
 
-  auto* call = Sem().Get(vec_123);
-  ASSERT_NE(call, nullptr);
-  ASSERT_EQ(call->Arguments().size(), 3u);
-  EXPECT_EQ(call->Arguments()[0], Sem().Get(scalar_1));
-  EXPECT_EQ(call->Arguments()[1], Sem().Get(scalar_2));
-  EXPECT_EQ(call->Arguments()[2], Sem().Get(u32_to_i32));
+    auto* call = Sem().Get(vec_123);
+    ASSERT_NE(call, nullptr);
+    ASSERT_EQ(call->Arguments().size(), 3u);
+    EXPECT_EQ(call->Arguments()[0], Sem().Get(scalar_1));
+    EXPECT_EQ(call->Arguments()[1], Sem().Get(scalar_2));
+    EXPECT_EQ(call->Arguments()[2], Sem().Get(u32_to_i32));
 
-  auto* ctor = call->Target()->As<sem::TypeConstructor>();
-  ASSERT_NE(ctor, nullptr);
-  ASSERT_TRUE(ctor->ReturnType()->Is<sem::Vector>());
-  EXPECT_EQ(ctor->ReturnType()->As<sem::Vector>()->Width(), 3u);
-  EXPECT_TRUE(ctor->ReturnType()->As<sem::Vector>()->type()->Is<sem::I32>());
-  EXPECT_EQ(ctor->ReturnType(), call->Type());
+    auto* ctor = call->Target()->As<sem::TypeConstructor>();
+    ASSERT_NE(ctor, nullptr);
+    ASSERT_TRUE(ctor->ReturnType()->Is<sem::Vector>());
+    EXPECT_EQ(ctor->ReturnType()->As<sem::Vector>()->Width(), 3u);
+    EXPECT_TRUE(ctor->ReturnType()->As<sem::Vector>()->type()->Is<sem::I32>());
+    EXPECT_EQ(ctor->ReturnType(), call->Type());
 
-  ASSERT_EQ(ctor->Parameters().size(), 3u);
-  EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::I32>());
-  EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::I32>());
-  EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::I32>());
+    ASSERT_EQ(ctor->Parameters().size(), 3u);
+    EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::I32>());
+    EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::I32>());
+    EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::I32>());
 }
 
 // AppendVector(vec2<i32>(vec2<u32>(1u, 2u)), 3u) ->
 //    vec3<i32>(vec2<i32>(vec2<u32>(1u, 2u)), i32(3u))
 TEST_F(AppendVectorTest, Vec2i32FromVec2u32_u32) {
-  auto* scalar_1 = Expr(1u);
-  auto* scalar_2 = Expr(2u);
-  auto* scalar_3 = Expr(3u);
-  auto* uvec_12 = vec2<u32>(scalar_1, scalar_2);
-  auto* vec_12 = vec2<i32>(uvec_12);
-  WrapInFunction(vec_12, scalar_3);
+    auto* scalar_1 = Expr(1_u);
+    auto* scalar_2 = Expr(2_u);
+    auto* scalar_3 = Expr(3_u);
+    auto* uvec_12 = vec2<u32>(scalar_1, scalar_2);
+    auto* vec_12 = vec2<i32>(uvec_12);
+    WrapInFunction(vec_12, scalar_3);
 
-  resolver::Resolver resolver(this);
-  ASSERT_TRUE(resolver.Resolve()) << resolver.error();
+    resolver::Resolver resolver(this);
+    ASSERT_TRUE(resolver.Resolve()) << resolver.error();
 
-  auto* append = AppendVector(this, vec_12, scalar_3);
+    auto* append = AppendVector(this, vec_12, scalar_3);
 
-  auto* vec_123 = As<ast::CallExpression>(append->Declaration());
-  ASSERT_NE(vec_123, nullptr);
-  ASSERT_EQ(vec_123->args.size(), 2u);
-  auto* v2u32_to_v2i32 = vec_123->args[0]->As<ast::CallExpression>();
-  ASSERT_NE(v2u32_to_v2i32, nullptr);
-  ASSERT_TRUE(v2u32_to_v2i32->target.type->Is<ast::Vector>());
-  EXPECT_EQ(v2u32_to_v2i32->target.type->As<ast::Vector>()->width, 2u);
-  EXPECT_TRUE(
-      v2u32_to_v2i32->target.type->As<ast::Vector>()->type->Is<ast::I32>());
-  EXPECT_EQ(v2u32_to_v2i32->args.size(), 1u);
-  EXPECT_EQ(v2u32_to_v2i32->args[0], uvec_12);
+    auto* vec_123 = As<ast::CallExpression>(append->Declaration());
+    ASSERT_NE(vec_123, nullptr);
+    ASSERT_EQ(vec_123->args.size(), 2u);
+    auto* v2u32_to_v2i32 = vec_123->args[0]->As<ast::CallExpression>();
+    ASSERT_NE(v2u32_to_v2i32, nullptr);
+    ASSERT_TRUE(v2u32_to_v2i32->target.type->Is<ast::Vector>());
+    EXPECT_EQ(v2u32_to_v2i32->target.type->As<ast::Vector>()->width, 2u);
+    EXPECT_TRUE(v2u32_to_v2i32->target.type->As<ast::Vector>()->type->Is<ast::I32>());
+    EXPECT_EQ(v2u32_to_v2i32->args.size(), 1u);
+    EXPECT_EQ(v2u32_to_v2i32->args[0], uvec_12);
 
-  auto* u32_to_i32 = vec_123->args[1]->As<ast::CallExpression>();
-  ASSERT_NE(u32_to_i32, nullptr);
-  EXPECT_TRUE(u32_to_i32->target.type->Is<ast::I32>());
-  ASSERT_EQ(u32_to_i32->args.size(), 1u);
-  EXPECT_EQ(u32_to_i32->args[0], scalar_3);
+    auto* u32_to_i32 = vec_123->args[1]->As<ast::CallExpression>();
+    ASSERT_NE(u32_to_i32, nullptr);
+    EXPECT_TRUE(u32_to_i32->target.type->Is<ast::I32>());
+    ASSERT_EQ(u32_to_i32->args.size(), 1u);
+    EXPECT_EQ(u32_to_i32->args[0], scalar_3);
 
-  auto* call = Sem().Get(vec_123);
-  ASSERT_NE(call, nullptr);
-  ASSERT_EQ(call->Arguments().size(), 2u);
-  EXPECT_EQ(call->Arguments()[0], Sem().Get(vec_12));
-  EXPECT_EQ(call->Arguments()[1], Sem().Get(u32_to_i32));
+    auto* call = Sem().Get(vec_123);
+    ASSERT_NE(call, nullptr);
+    ASSERT_EQ(call->Arguments().size(), 2u);
+    EXPECT_EQ(call->Arguments()[0], Sem().Get(vec_12));
+    EXPECT_EQ(call->Arguments()[1], Sem().Get(u32_to_i32));
 
-  auto* ctor = call->Target()->As<sem::TypeConstructor>();
-  ASSERT_NE(ctor, nullptr);
-  ASSERT_TRUE(ctor->ReturnType()->Is<sem::Vector>());
-  EXPECT_EQ(ctor->ReturnType()->As<sem::Vector>()->Width(), 3u);
-  EXPECT_TRUE(ctor->ReturnType()->As<sem::Vector>()->type()->Is<sem::I32>());
-  EXPECT_EQ(ctor->ReturnType(), call->Type());
+    auto* ctor = call->Target()->As<sem::TypeConstructor>();
+    ASSERT_NE(ctor, nullptr);
+    ASSERT_TRUE(ctor->ReturnType()->Is<sem::Vector>());
+    EXPECT_EQ(ctor->ReturnType()->As<sem::Vector>()->Width(), 3u);
+    EXPECT_TRUE(ctor->ReturnType()->As<sem::Vector>()->type()->Is<sem::I32>());
+    EXPECT_EQ(ctor->ReturnType(), call->Type());
 
-  ASSERT_EQ(ctor->Parameters().size(), 2u);
-  EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Vector>());
-  EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::I32>());
+    ASSERT_EQ(ctor->Parameters().size(), 2u);
+    EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Vector>());
+    EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::I32>());
 }
 
 // AppendVector(vec2<i32>(1, 2), 3.0f) -> vec3<i32>(1, 2, i32(3.0f))
 TEST_F(AppendVectorTest, Vec2i32_f32) {
-  auto* scalar_1 = Expr(1);
-  auto* scalar_2 = Expr(2);
-  auto* scalar_3 = Expr(3.0f);
-  auto* vec_12 = vec2<i32>(scalar_1, scalar_2);
-  WrapInFunction(vec_12, scalar_3);
+    auto* scalar_1 = Expr(1_i);
+    auto* scalar_2 = Expr(2_i);
+    auto* scalar_3 = Expr(3.0f);
+    auto* vec_12 = vec2<i32>(scalar_1, scalar_2);
+    WrapInFunction(vec_12, scalar_3);
 
-  resolver::Resolver resolver(this);
-  ASSERT_TRUE(resolver.Resolve()) << resolver.error();
+    resolver::Resolver resolver(this);
+    ASSERT_TRUE(resolver.Resolve()) << resolver.error();
 
-  auto* append = AppendVector(this, vec_12, scalar_3);
+    auto* append = AppendVector(this, vec_12, scalar_3);
 
-  auto* vec_123 = As<ast::CallExpression>(append->Declaration());
-  ASSERT_NE(vec_123, nullptr);
-  ASSERT_EQ(vec_123->args.size(), 3u);
-  EXPECT_EQ(vec_123->args[0], scalar_1);
-  EXPECT_EQ(vec_123->args[1], scalar_2);
-  auto* f32_to_i32 = vec_123->args[2]->As<ast::CallExpression>();
-  ASSERT_NE(f32_to_i32, nullptr);
-  EXPECT_TRUE(f32_to_i32->target.type->Is<ast::I32>());
-  ASSERT_EQ(f32_to_i32->args.size(), 1u);
-  EXPECT_EQ(f32_to_i32->args[0], scalar_3);
+    auto* vec_123 = As<ast::CallExpression>(append->Declaration());
+    ASSERT_NE(vec_123, nullptr);
+    ASSERT_EQ(vec_123->args.size(), 3u);
+    EXPECT_EQ(vec_123->args[0], scalar_1);
+    EXPECT_EQ(vec_123->args[1], scalar_2);
+    auto* f32_to_i32 = vec_123->args[2]->As<ast::CallExpression>();
+    ASSERT_NE(f32_to_i32, nullptr);
+    EXPECT_TRUE(f32_to_i32->target.type->Is<ast::I32>());
+    ASSERT_EQ(f32_to_i32->args.size(), 1u);
+    EXPECT_EQ(f32_to_i32->args[0], scalar_3);
 
-  auto* call = Sem().Get(vec_123);
-  ASSERT_NE(call, nullptr);
-  ASSERT_EQ(call->Arguments().size(), 3u);
-  EXPECT_EQ(call->Arguments()[0], Sem().Get(scalar_1));
-  EXPECT_EQ(call->Arguments()[1], Sem().Get(scalar_2));
-  EXPECT_EQ(call->Arguments()[2], Sem().Get(f32_to_i32));
+    auto* call = Sem().Get(vec_123);
+    ASSERT_NE(call, nullptr);
+    ASSERT_EQ(call->Arguments().size(), 3u);
+    EXPECT_EQ(call->Arguments()[0], Sem().Get(scalar_1));
+    EXPECT_EQ(call->Arguments()[1], Sem().Get(scalar_2));
+    EXPECT_EQ(call->Arguments()[2], Sem().Get(f32_to_i32));
 
-  auto* ctor = call->Target()->As<sem::TypeConstructor>();
-  ASSERT_NE(ctor, nullptr);
-  ASSERT_TRUE(ctor->ReturnType()->Is<sem::Vector>());
-  EXPECT_EQ(ctor->ReturnType()->As<sem::Vector>()->Width(), 3u);
-  EXPECT_TRUE(ctor->ReturnType()->As<sem::Vector>()->type()->Is<sem::I32>());
-  EXPECT_EQ(ctor->ReturnType(), call->Type());
+    auto* ctor = call->Target()->As<sem::TypeConstructor>();
+    ASSERT_NE(ctor, nullptr);
+    ASSERT_TRUE(ctor->ReturnType()->Is<sem::Vector>());
+    EXPECT_EQ(ctor->ReturnType()->As<sem::Vector>()->Width(), 3u);
+    EXPECT_TRUE(ctor->ReturnType()->As<sem::Vector>()->type()->Is<sem::I32>());
+    EXPECT_EQ(ctor->ReturnType(), call->Type());
 
-  ASSERT_EQ(ctor->Parameters().size(), 3u);
-  EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::I32>());
-  EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::I32>());
-  EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::I32>());
+    ASSERT_EQ(ctor->Parameters().size(), 3u);
+    EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::I32>());
+    EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::I32>());
+    EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::I32>());
 }
 
 // AppendVector(vec3<i32>(1, 2, 3), 4) -> vec4<i32>(1, 2, 3, 4)
 TEST_F(AppendVectorTest, Vec3i32_i32) {
-  auto* scalar_1 = Expr(1);
-  auto* scalar_2 = Expr(2);
-  auto* scalar_3 = Expr(3);
-  auto* scalar_4 = Expr(4);
-  auto* vec_123 = vec3<i32>(scalar_1, scalar_2, scalar_3);
-  WrapInFunction(vec_123, scalar_4);
+    auto* scalar_1 = Expr(1_i);
+    auto* scalar_2 = Expr(2_i);
+    auto* scalar_3 = Expr(3_i);
+    auto* scalar_4 = Expr(4_i);
+    auto* vec_123 = vec3<i32>(scalar_1, scalar_2, scalar_3);
+    WrapInFunction(vec_123, scalar_4);
 
-  resolver::Resolver resolver(this);
-  ASSERT_TRUE(resolver.Resolve()) << resolver.error();
+    resolver::Resolver resolver(this);
+    ASSERT_TRUE(resolver.Resolve()) << resolver.error();
 
-  auto* append = AppendVector(this, vec_123, scalar_4);
+    auto* append = AppendVector(this, vec_123, scalar_4);
 
-  auto* vec_1234 = As<ast::CallExpression>(append->Declaration());
-  ASSERT_NE(vec_1234, nullptr);
-  ASSERT_EQ(vec_1234->args.size(), 4u);
-  EXPECT_EQ(vec_1234->args[0], scalar_1);
-  EXPECT_EQ(vec_1234->args[1], scalar_2);
-  EXPECT_EQ(vec_1234->args[2], scalar_3);
-  EXPECT_EQ(vec_1234->args[3], scalar_4);
+    auto* vec_1234 = As<ast::CallExpression>(append->Declaration());
+    ASSERT_NE(vec_1234, nullptr);
+    ASSERT_EQ(vec_1234->args.size(), 4u);
+    EXPECT_EQ(vec_1234->args[0], scalar_1);
+    EXPECT_EQ(vec_1234->args[1], scalar_2);
+    EXPECT_EQ(vec_1234->args[2], scalar_3);
+    EXPECT_EQ(vec_1234->args[3], scalar_4);
 
-  auto* call = Sem().Get(vec_1234);
-  ASSERT_NE(call, nullptr);
-  ASSERT_EQ(call->Arguments().size(), 4u);
-  EXPECT_EQ(call->Arguments()[0], Sem().Get(scalar_1));
-  EXPECT_EQ(call->Arguments()[1], Sem().Get(scalar_2));
-  EXPECT_EQ(call->Arguments()[2], Sem().Get(scalar_3));
-  EXPECT_EQ(call->Arguments()[3], Sem().Get(scalar_4));
+    auto* call = Sem().Get(vec_1234);
+    ASSERT_NE(call, nullptr);
+    ASSERT_EQ(call->Arguments().size(), 4u);
+    EXPECT_EQ(call->Arguments()[0], Sem().Get(scalar_1));
+    EXPECT_EQ(call->Arguments()[1], Sem().Get(scalar_2));
+    EXPECT_EQ(call->Arguments()[2], Sem().Get(scalar_3));
+    EXPECT_EQ(call->Arguments()[3], Sem().Get(scalar_4));
 
-  auto* ctor = call->Target()->As<sem::TypeConstructor>();
-  ASSERT_NE(ctor, nullptr);
-  ASSERT_TRUE(ctor->ReturnType()->Is<sem::Vector>());
-  EXPECT_EQ(ctor->ReturnType()->As<sem::Vector>()->Width(), 4u);
-  EXPECT_TRUE(ctor->ReturnType()->As<sem::Vector>()->type()->Is<sem::I32>());
-  EXPECT_EQ(ctor->ReturnType(), call->Type());
+    auto* ctor = call->Target()->As<sem::TypeConstructor>();
+    ASSERT_NE(ctor, nullptr);
+    ASSERT_TRUE(ctor->ReturnType()->Is<sem::Vector>());
+    EXPECT_EQ(ctor->ReturnType()->As<sem::Vector>()->Width(), 4u);
+    EXPECT_TRUE(ctor->ReturnType()->As<sem::Vector>()->type()->Is<sem::I32>());
+    EXPECT_EQ(ctor->ReturnType(), call->Type());
 
-  ASSERT_EQ(ctor->Parameters().size(), 4u);
-  EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::I32>());
-  EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::I32>());
-  EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::I32>());
-  EXPECT_TRUE(ctor->Parameters()[3]->Type()->Is<sem::I32>());
+    ASSERT_EQ(ctor->Parameters().size(), 4u);
+    EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::I32>());
+    EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::I32>());
+    EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::I32>());
+    EXPECT_TRUE(ctor->Parameters()[3]->Type()->Is<sem::I32>());
 }
 
 // AppendVector(vec_12, 3) -> vec3<i32>(vec_12, 3)
 TEST_F(AppendVectorTest, Vec2i32Var_i32) {
-  Global("vec_12", ty.vec2<i32>(), ast::StorageClass::kPrivate);
-  auto* vec_12 = Expr("vec_12");
-  auto* scalar_3 = Expr(3);
-  WrapInFunction(vec_12, scalar_3);
+    Global("vec_12", ty.vec2<i32>(), ast::StorageClass::kPrivate);
+    auto* vec_12 = Expr("vec_12");
+    auto* scalar_3 = Expr(3_i);
+    WrapInFunction(vec_12, scalar_3);
 
-  resolver::Resolver resolver(this);
-  ASSERT_TRUE(resolver.Resolve()) << resolver.error();
+    resolver::Resolver resolver(this);
+    ASSERT_TRUE(resolver.Resolve()) << resolver.error();
 
-  auto* append = AppendVector(this, vec_12, scalar_3);
+    auto* append = AppendVector(this, vec_12, scalar_3);
 
-  auto* vec_123 = As<ast::CallExpression>(append->Declaration());
-  ASSERT_NE(vec_123, nullptr);
-  ASSERT_EQ(vec_123->args.size(), 2u);
-  EXPECT_EQ(vec_123->args[0], vec_12);
-  EXPECT_EQ(vec_123->args[1], scalar_3);
+    auto* vec_123 = As<ast::CallExpression>(append->Declaration());
+    ASSERT_NE(vec_123, nullptr);
+    ASSERT_EQ(vec_123->args.size(), 2u);
+    EXPECT_EQ(vec_123->args[0], vec_12);
+    EXPECT_EQ(vec_123->args[1], scalar_3);
 
-  auto* call = Sem().Get(vec_123);
-  ASSERT_NE(call, nullptr);
-  ASSERT_EQ(call->Arguments().size(), 2u);
-  EXPECT_EQ(call->Arguments()[0], Sem().Get(vec_12));
-  EXPECT_EQ(call->Arguments()[1], Sem().Get(scalar_3));
+    auto* call = Sem().Get(vec_123);
+    ASSERT_NE(call, nullptr);
+    ASSERT_EQ(call->Arguments().size(), 2u);
+    EXPECT_EQ(call->Arguments()[0], Sem().Get(vec_12));
+    EXPECT_EQ(call->Arguments()[1], Sem().Get(scalar_3));
 
-  auto* ctor = call->Target()->As<sem::TypeConstructor>();
-  ASSERT_NE(ctor, nullptr);
-  ASSERT_TRUE(ctor->ReturnType()->Is<sem::Vector>());
-  EXPECT_EQ(ctor->ReturnType()->As<sem::Vector>()->Width(), 3u);
-  EXPECT_TRUE(ctor->ReturnType()->As<sem::Vector>()->type()->Is<sem::I32>());
-  EXPECT_EQ(ctor->ReturnType(), call->Type());
+    auto* ctor = call->Target()->As<sem::TypeConstructor>();
+    ASSERT_NE(ctor, nullptr);
+    ASSERT_TRUE(ctor->ReturnType()->Is<sem::Vector>());
+    EXPECT_EQ(ctor->ReturnType()->As<sem::Vector>()->Width(), 3u);
+    EXPECT_TRUE(ctor->ReturnType()->As<sem::Vector>()->type()->Is<sem::I32>());
+    EXPECT_EQ(ctor->ReturnType(), call->Type());
 
-  ASSERT_EQ(ctor->Parameters().size(), 2u);
-  EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Vector>());
-  EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::I32>());
+    ASSERT_EQ(ctor->Parameters().size(), 2u);
+    EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Vector>());
+    EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::I32>());
 }
 
 // AppendVector(1, 2, scalar_3) -> vec3<i32>(1, 2, scalar_3)
 TEST_F(AppendVectorTest, Vec2i32_i32Var) {
-  Global("scalar_3", ty.i32(), ast::StorageClass::kPrivate);
-  auto* scalar_1 = Expr(1);
-  auto* scalar_2 = Expr(2);
-  auto* scalar_3 = Expr("scalar_3");
-  auto* vec_12 = vec2<i32>(scalar_1, scalar_2);
-  WrapInFunction(vec_12, scalar_3);
+    Global("scalar_3", ty.i32(), ast::StorageClass::kPrivate);
+    auto* scalar_1 = Expr(1_i);
+    auto* scalar_2 = Expr(2_i);
+    auto* scalar_3 = Expr("scalar_3");
+    auto* vec_12 = vec2<i32>(scalar_1, scalar_2);
+    WrapInFunction(vec_12, scalar_3);
 
-  resolver::Resolver resolver(this);
-  ASSERT_TRUE(resolver.Resolve()) << resolver.error();
+    resolver::Resolver resolver(this);
+    ASSERT_TRUE(resolver.Resolve()) << resolver.error();
 
-  auto* append = AppendVector(this, vec_12, scalar_3);
+    auto* append = AppendVector(this, vec_12, scalar_3);
 
-  auto* vec_123 = As<ast::CallExpression>(append->Declaration());
-  ASSERT_NE(vec_123, nullptr);
-  ASSERT_EQ(vec_123->args.size(), 3u);
-  EXPECT_EQ(vec_123->args[0], scalar_1);
-  EXPECT_EQ(vec_123->args[1], scalar_2);
-  EXPECT_EQ(vec_123->args[2], scalar_3);
+    auto* vec_123 = As<ast::CallExpression>(append->Declaration());
+    ASSERT_NE(vec_123, nullptr);
+    ASSERT_EQ(vec_123->args.size(), 3u);
+    EXPECT_EQ(vec_123->args[0], scalar_1);
+    EXPECT_EQ(vec_123->args[1], scalar_2);
+    EXPECT_EQ(vec_123->args[2], scalar_3);
 
-  auto* call = Sem().Get(vec_123);
-  ASSERT_NE(call, nullptr);
-  ASSERT_EQ(call->Arguments().size(), 3u);
-  EXPECT_EQ(call->Arguments()[0], Sem().Get(scalar_1));
-  EXPECT_EQ(call->Arguments()[1], Sem().Get(scalar_2));
-  EXPECT_EQ(call->Arguments()[2], Sem().Get(scalar_3));
+    auto* call = Sem().Get(vec_123);
+    ASSERT_NE(call, nullptr);
+    ASSERT_EQ(call->Arguments().size(), 3u);
+    EXPECT_EQ(call->Arguments()[0], Sem().Get(scalar_1));
+    EXPECT_EQ(call->Arguments()[1], Sem().Get(scalar_2));
+    EXPECT_EQ(call->Arguments()[2], Sem().Get(scalar_3));
 
-  auto* ctor = call->Target()->As<sem::TypeConstructor>();
-  ASSERT_NE(ctor, nullptr);
-  ASSERT_TRUE(ctor->ReturnType()->Is<sem::Vector>());
-  EXPECT_EQ(ctor->ReturnType()->As<sem::Vector>()->Width(), 3u);
-  EXPECT_TRUE(ctor->ReturnType()->As<sem::Vector>()->type()->Is<sem::I32>());
-  EXPECT_EQ(ctor->ReturnType(), call->Type());
+    auto* ctor = call->Target()->As<sem::TypeConstructor>();
+    ASSERT_NE(ctor, nullptr);
+    ASSERT_TRUE(ctor->ReturnType()->Is<sem::Vector>());
+    EXPECT_EQ(ctor->ReturnType()->As<sem::Vector>()->Width(), 3u);
+    EXPECT_TRUE(ctor->ReturnType()->As<sem::Vector>()->type()->Is<sem::I32>());
+    EXPECT_EQ(ctor->ReturnType(), call->Type());
 
-  ASSERT_EQ(ctor->Parameters().size(), 3u);
-  EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::I32>());
-  EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::I32>());
-  EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::I32>());
+    ASSERT_EQ(ctor->Parameters().size(), 3u);
+    EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::I32>());
+    EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::I32>());
+    EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::I32>());
 }
 
 // AppendVector(vec_12, scalar_3) -> vec3<i32>(vec_12, scalar_3)
 TEST_F(AppendVectorTest, Vec2i32Var_i32Var) {
-  Global("vec_12", ty.vec2<i32>(), ast::StorageClass::kPrivate);
-  Global("scalar_3", ty.i32(), ast::StorageClass::kPrivate);
-  auto* vec_12 = Expr("vec_12");
-  auto* scalar_3 = Expr("scalar_3");
-  WrapInFunction(vec_12, scalar_3);
+    Global("vec_12", ty.vec2<i32>(), ast::StorageClass::kPrivate);
+    Global("scalar_3", ty.i32(), ast::StorageClass::kPrivate);
+    auto* vec_12 = Expr("vec_12");
+    auto* scalar_3 = Expr("scalar_3");
+    WrapInFunction(vec_12, scalar_3);
 
-  resolver::Resolver resolver(this);
-  ASSERT_TRUE(resolver.Resolve()) << resolver.error();
+    resolver::Resolver resolver(this);
+    ASSERT_TRUE(resolver.Resolve()) << resolver.error();
 
-  auto* append = AppendVector(this, vec_12, scalar_3);
+    auto* append = AppendVector(this, vec_12, scalar_3);
 
-  auto* vec_123 = As<ast::CallExpression>(append->Declaration());
-  ASSERT_NE(vec_123, nullptr);
-  ASSERT_EQ(vec_123->args.size(), 2u);
-  EXPECT_EQ(vec_123->args[0], vec_12);
-  EXPECT_EQ(vec_123->args[1], scalar_3);
+    auto* vec_123 = As<ast::CallExpression>(append->Declaration());
+    ASSERT_NE(vec_123, nullptr);
+    ASSERT_EQ(vec_123->args.size(), 2u);
+    EXPECT_EQ(vec_123->args[0], vec_12);
+    EXPECT_EQ(vec_123->args[1], scalar_3);
 
-  auto* call = Sem().Get(vec_123);
-  ASSERT_NE(call, nullptr);
-  ASSERT_EQ(call->Arguments().size(), 2u);
-  EXPECT_EQ(call->Arguments()[0], Sem().Get(vec_12));
-  EXPECT_EQ(call->Arguments()[1], Sem().Get(scalar_3));
+    auto* call = Sem().Get(vec_123);
+    ASSERT_NE(call, nullptr);
+    ASSERT_EQ(call->Arguments().size(), 2u);
+    EXPECT_EQ(call->Arguments()[0], Sem().Get(vec_12));
+    EXPECT_EQ(call->Arguments()[1], Sem().Get(scalar_3));
 
-  auto* ctor = call->Target()->As<sem::TypeConstructor>();
-  ASSERT_NE(ctor, nullptr);
-  ASSERT_TRUE(ctor->ReturnType()->Is<sem::Vector>());
-  EXPECT_EQ(ctor->ReturnType()->As<sem::Vector>()->Width(), 3u);
-  EXPECT_TRUE(ctor->ReturnType()->As<sem::Vector>()->type()->Is<sem::I32>());
-  EXPECT_EQ(ctor->ReturnType(), call->Type());
+    auto* ctor = call->Target()->As<sem::TypeConstructor>();
+    ASSERT_NE(ctor, nullptr);
+    ASSERT_TRUE(ctor->ReturnType()->Is<sem::Vector>());
+    EXPECT_EQ(ctor->ReturnType()->As<sem::Vector>()->Width(), 3u);
+    EXPECT_TRUE(ctor->ReturnType()->As<sem::Vector>()->type()->Is<sem::I32>());
+    EXPECT_EQ(ctor->ReturnType(), call->Type());
 
-  ASSERT_EQ(ctor->Parameters().size(), 2u);
-  EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Vector>());
-  EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::I32>());
+    ASSERT_EQ(ctor->Parameters().size(), 2u);
+    EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Vector>());
+    EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::I32>());
 }
 
 // AppendVector(vec_12, scalar_3) -> vec3<i32>(vec_12, i32(scalar_3))
 TEST_F(AppendVectorTest, Vec2i32Var_f32Var) {
-  Global("vec_12", ty.vec2<i32>(), ast::StorageClass::kPrivate);
-  Global("scalar_3", ty.f32(), ast::StorageClass::kPrivate);
-  auto* vec_12 = Expr("vec_12");
-  auto* scalar_3 = Expr("scalar_3");
-  WrapInFunction(vec_12, scalar_3);
+    Global("vec_12", ty.vec2<i32>(), ast::StorageClass::kPrivate);
+    Global("scalar_3", ty.f32(), ast::StorageClass::kPrivate);
+    auto* vec_12 = Expr("vec_12");
+    auto* scalar_3 = Expr("scalar_3");
+    WrapInFunction(vec_12, scalar_3);
 
-  resolver::Resolver resolver(this);
-  ASSERT_TRUE(resolver.Resolve()) << resolver.error();
+    resolver::Resolver resolver(this);
+    ASSERT_TRUE(resolver.Resolve()) << resolver.error();
 
-  auto* append = AppendVector(this, vec_12, scalar_3);
+    auto* append = AppendVector(this, vec_12, scalar_3);
 
-  auto* vec_123 = As<ast::CallExpression>(append->Declaration());
-  ASSERT_NE(vec_123, nullptr);
-  ASSERT_EQ(vec_123->args.size(), 2u);
-  EXPECT_EQ(vec_123->args[0], vec_12);
-  auto* f32_to_i32 = vec_123->args[1]->As<ast::CallExpression>();
-  ASSERT_NE(f32_to_i32, nullptr);
-  EXPECT_TRUE(f32_to_i32->target.type->Is<ast::I32>());
-  ASSERT_EQ(f32_to_i32->args.size(), 1u);
-  EXPECT_EQ(f32_to_i32->args[0], scalar_3);
+    auto* vec_123 = As<ast::CallExpression>(append->Declaration());
+    ASSERT_NE(vec_123, nullptr);
+    ASSERT_EQ(vec_123->args.size(), 2u);
+    EXPECT_EQ(vec_123->args[0], vec_12);
+    auto* f32_to_i32 = vec_123->args[1]->As<ast::CallExpression>();
+    ASSERT_NE(f32_to_i32, nullptr);
+    EXPECT_TRUE(f32_to_i32->target.type->Is<ast::I32>());
+    ASSERT_EQ(f32_to_i32->args.size(), 1u);
+    EXPECT_EQ(f32_to_i32->args[0], scalar_3);
 
-  auto* call = Sem().Get(vec_123);
-  ASSERT_NE(call, nullptr);
-  ASSERT_EQ(call->Arguments().size(), 2u);
-  EXPECT_EQ(call->Arguments()[0], Sem().Get(vec_12));
-  EXPECT_EQ(call->Arguments()[1], Sem().Get(f32_to_i32));
+    auto* call = Sem().Get(vec_123);
+    ASSERT_NE(call, nullptr);
+    ASSERT_EQ(call->Arguments().size(), 2u);
+    EXPECT_EQ(call->Arguments()[0], Sem().Get(vec_12));
+    EXPECT_EQ(call->Arguments()[1], Sem().Get(f32_to_i32));
 
-  auto* ctor = call->Target()->As<sem::TypeConstructor>();
-  ASSERT_NE(ctor, nullptr);
-  ASSERT_TRUE(ctor->ReturnType()->Is<sem::Vector>());
-  EXPECT_EQ(ctor->ReturnType()->As<sem::Vector>()->Width(), 3u);
-  EXPECT_TRUE(ctor->ReturnType()->As<sem::Vector>()->type()->Is<sem::I32>());
-  EXPECT_EQ(ctor->ReturnType(), call->Type());
+    auto* ctor = call->Target()->As<sem::TypeConstructor>();
+    ASSERT_NE(ctor, nullptr);
+    ASSERT_TRUE(ctor->ReturnType()->Is<sem::Vector>());
+    EXPECT_EQ(ctor->ReturnType()->As<sem::Vector>()->Width(), 3u);
+    EXPECT_TRUE(ctor->ReturnType()->As<sem::Vector>()->type()->Is<sem::I32>());
+    EXPECT_EQ(ctor->ReturnType(), call->Type());
 
-  ASSERT_EQ(ctor->Parameters().size(), 2u);
-  EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Vector>());
-  EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::I32>());
+    ASSERT_EQ(ctor->Parameters().size(), 2u);
+    EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Vector>());
+    EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::I32>());
 }
 
 // AppendVector(vec_12, scalar_3) -> vec3<bool>(vec_12, scalar_3)
 TEST_F(AppendVectorTest, Vec2boolVar_boolVar) {
-  Global("vec_12", ty.vec2<bool>(), ast::StorageClass::kPrivate);
-  Global("scalar_3", ty.bool_(), ast::StorageClass::kPrivate);
-  auto* vec_12 = Expr("vec_12");
-  auto* scalar_3 = Expr("scalar_3");
-  WrapInFunction(vec_12, scalar_3);
+    Global("vec_12", ty.vec2<bool>(), ast::StorageClass::kPrivate);
+    Global("scalar_3", ty.bool_(), ast::StorageClass::kPrivate);
+    auto* vec_12 = Expr("vec_12");
+    auto* scalar_3 = Expr("scalar_3");
+    WrapInFunction(vec_12, scalar_3);
 
-  resolver::Resolver resolver(this);
-  ASSERT_TRUE(resolver.Resolve()) << resolver.error();
+    resolver::Resolver resolver(this);
+    ASSERT_TRUE(resolver.Resolve()) << resolver.error();
 
-  auto* append = AppendVector(this, vec_12, scalar_3);
+    auto* append = AppendVector(this, vec_12, scalar_3);
 
-  auto* vec_123 = As<ast::CallExpression>(append->Declaration());
-  ASSERT_NE(vec_123, nullptr);
-  ASSERT_EQ(vec_123->args.size(), 2u);
-  EXPECT_EQ(vec_123->args[0], vec_12);
-  EXPECT_EQ(vec_123->args[1], scalar_3);
+    auto* vec_123 = As<ast::CallExpression>(append->Declaration());
+    ASSERT_NE(vec_123, nullptr);
+    ASSERT_EQ(vec_123->args.size(), 2u);
+    EXPECT_EQ(vec_123->args[0], vec_12);
+    EXPECT_EQ(vec_123->args[1], scalar_3);
 
-  auto* call = Sem().Get(vec_123);
-  ASSERT_NE(call, nullptr);
-  ASSERT_EQ(call->Arguments().size(), 2u);
-  EXPECT_EQ(call->Arguments()[0], Sem().Get(vec_12));
-  EXPECT_EQ(call->Arguments()[1], Sem().Get(scalar_3));
+    auto* call = Sem().Get(vec_123);
+    ASSERT_NE(call, nullptr);
+    ASSERT_EQ(call->Arguments().size(), 2u);
+    EXPECT_EQ(call->Arguments()[0], Sem().Get(vec_12));
+    EXPECT_EQ(call->Arguments()[1], Sem().Get(scalar_3));
 
-  auto* ctor = call->Target()->As<sem::TypeConstructor>();
-  ASSERT_NE(ctor, nullptr);
-  ASSERT_TRUE(ctor->ReturnType()->Is<sem::Vector>());
-  EXPECT_EQ(ctor->ReturnType()->As<sem::Vector>()->Width(), 3u);
-  EXPECT_TRUE(ctor->ReturnType()->As<sem::Vector>()->type()->Is<sem::Bool>());
-  EXPECT_EQ(ctor->ReturnType(), call->Type());
+    auto* ctor = call->Target()->As<sem::TypeConstructor>();
+    ASSERT_NE(ctor, nullptr);
+    ASSERT_TRUE(ctor->ReturnType()->Is<sem::Vector>());
+    EXPECT_EQ(ctor->ReturnType()->As<sem::Vector>()->Width(), 3u);
+    EXPECT_TRUE(ctor->ReturnType()->As<sem::Vector>()->type()->Is<sem::Bool>());
+    EXPECT_EQ(ctor->ReturnType(), call->Type());
 
-  ASSERT_EQ(ctor->Parameters().size(), 2u);
-  EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Vector>());
-  EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::Bool>());
+    ASSERT_EQ(ctor->Parameters().size(), 2u);
+    EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::Vector>());
+    EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::Bool>());
 }
 
 // AppendVector(vec3<i32>(), 4) -> vec3<bool>(0, 0, 0, 4)
 TEST_F(AppendVectorTest, ZeroVec3i32_i32) {
-  auto* scalar = Expr(4);
-  auto* vec000 = vec3<i32>();
-  WrapInFunction(vec000, scalar);
+    auto* scalar = Expr(4_i);
+    auto* vec000 = vec3<i32>();
+    WrapInFunction(vec000, scalar);
 
-  resolver::Resolver resolver(this);
-  ASSERT_TRUE(resolver.Resolve()) << resolver.error();
+    resolver::Resolver resolver(this);
+    ASSERT_TRUE(resolver.Resolve()) << resolver.error();
 
-  auto* append = AppendVector(this, vec000, scalar);
+    auto* append = AppendVector(this, vec000, scalar);
 
-  auto* vec_0004 = As<ast::CallExpression>(append->Declaration());
-  ASSERT_NE(vec_0004, nullptr);
-  ASSERT_EQ(vec_0004->args.size(), 4u);
-  for (size_t i = 0; i < 3; i++) {
-    auto* literal = As<ast::SintLiteralExpression>(vec_0004->args[i]);
-    ASSERT_NE(literal, nullptr);
-    EXPECT_EQ(literal->value, 0);
-  }
-  EXPECT_EQ(vec_0004->args[3], scalar);
+    auto* vec_0004 = As<ast::CallExpression>(append->Declaration());
+    ASSERT_NE(vec_0004, nullptr);
+    ASSERT_EQ(vec_0004->args.size(), 4u);
+    for (size_t i = 0; i < 3; i++) {
+        auto* literal = As<ast::IntLiteralExpression>(vec_0004->args[i]);
+        ASSERT_NE(literal, nullptr);
+        EXPECT_EQ(literal->value, 0);
+    }
+    EXPECT_EQ(vec_0004->args[3], scalar);
 
-  auto* call = Sem().Get(vec_0004);
-  ASSERT_NE(call, nullptr);
-  ASSERT_EQ(call->Arguments().size(), 4u);
-  EXPECT_EQ(call->Arguments()[0], Sem().Get(vec_0004->args[0]));
-  EXPECT_EQ(call->Arguments()[1], Sem().Get(vec_0004->args[1]));
-  EXPECT_EQ(call->Arguments()[2], Sem().Get(vec_0004->args[2]));
-  EXPECT_EQ(call->Arguments()[3], Sem().Get(scalar));
+    auto* call = Sem().Get(vec_0004);
+    ASSERT_NE(call, nullptr);
+    ASSERT_EQ(call->Arguments().size(), 4u);
+    EXPECT_EQ(call->Arguments()[0], Sem().Get(vec_0004->args[0]));
+    EXPECT_EQ(call->Arguments()[1], Sem().Get(vec_0004->args[1]));
+    EXPECT_EQ(call->Arguments()[2], Sem().Get(vec_0004->args[2]));
+    EXPECT_EQ(call->Arguments()[3], Sem().Get(scalar));
 
-  auto* ctor = call->Target()->As<sem::TypeConstructor>();
-  ASSERT_NE(ctor, nullptr);
-  ASSERT_TRUE(ctor->ReturnType()->Is<sem::Vector>());
-  EXPECT_EQ(ctor->ReturnType()->As<sem::Vector>()->Width(), 4u);
-  EXPECT_TRUE(ctor->ReturnType()->As<sem::Vector>()->type()->Is<sem::I32>());
-  EXPECT_EQ(ctor->ReturnType(), call->Type());
+    auto* ctor = call->Target()->As<sem::TypeConstructor>();
+    ASSERT_NE(ctor, nullptr);
+    ASSERT_TRUE(ctor->ReturnType()->Is<sem::Vector>());
+    EXPECT_EQ(ctor->ReturnType()->As<sem::Vector>()->Width(), 4u);
+    EXPECT_TRUE(ctor->ReturnType()->As<sem::Vector>()->type()->Is<sem::I32>());
+    EXPECT_EQ(ctor->ReturnType(), call->Type());
 
-  ASSERT_EQ(ctor->Parameters().size(), 4u);
-  EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::I32>());
-  EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::I32>());
-  EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::I32>());
-  EXPECT_TRUE(ctor->Parameters()[3]->Type()->Is<sem::I32>());
+    ASSERT_EQ(ctor->Parameters().size(), 4u);
+    EXPECT_TRUE(ctor->Parameters()[0]->Type()->Is<sem::I32>());
+    EXPECT_TRUE(ctor->Parameters()[1]->Type()->Is<sem::I32>());
+    EXPECT_TRUE(ctor->Parameters()[2]->Type()->Is<sem::I32>());
+    EXPECT_TRUE(ctor->Parameters()[3]->Type()->Is<sem::I32>());
 }
 
 }  // namespace
diff --git a/src/tint/writer/array_length_from_uniform_options.cc b/src/tint/writer/array_length_from_uniform_options.cc
index 2fdd436..7fd6e63 100644
--- a/src/tint/writer/array_length_from_uniform_options.cc
+++ b/src/tint/writer/array_length_from_uniform_options.cc
@@ -18,11 +18,11 @@
 
 ArrayLengthFromUniformOptions::ArrayLengthFromUniformOptions() = default;
 ArrayLengthFromUniformOptions::~ArrayLengthFromUniformOptions() = default;
-ArrayLengthFromUniformOptions::ArrayLengthFromUniformOptions(
-    const ArrayLengthFromUniformOptions&) = default;
+ArrayLengthFromUniformOptions::ArrayLengthFromUniformOptions(const ArrayLengthFromUniformOptions&) =
+    default;
 ArrayLengthFromUniformOptions& ArrayLengthFromUniformOptions::operator=(
     const ArrayLengthFromUniformOptions&) = default;
-ArrayLengthFromUniformOptions::ArrayLengthFromUniformOptions(
-    ArrayLengthFromUniformOptions&&) = default;
+ArrayLengthFromUniformOptions::ArrayLengthFromUniformOptions(ArrayLengthFromUniformOptions&&) =
+    default;
 
 }  // namespace tint::writer
diff --git a/src/tint/writer/array_length_from_uniform_options.h b/src/tint/writer/array_length_from_uniform_options.h
index e672dde..cfa2fbd 100644
--- a/src/tint/writer/array_length_from_uniform_options.h
+++ b/src/tint/writer/array_length_from_uniform_options.h
@@ -24,28 +24,27 @@
 /// Options used to specify a mapping of binding points to indices into a UBO
 /// from which to load buffer sizes.
 struct ArrayLengthFromUniformOptions {
-  /// Constructor
-  ArrayLengthFromUniformOptions();
-  /// Destructor
-  ~ArrayLengthFromUniformOptions();
-  /// Copy constructor
-  ArrayLengthFromUniformOptions(const ArrayLengthFromUniformOptions&);
-  /// Copy assignment
-  /// @returns this ArrayLengthFromUniformOptions
-  ArrayLengthFromUniformOptions& operator=(
-      const ArrayLengthFromUniformOptions&);
-  /// Move constructor
-  ArrayLengthFromUniformOptions(ArrayLengthFromUniformOptions&&);
+    /// Constructor
+    ArrayLengthFromUniformOptions();
+    /// Destructor
+    ~ArrayLengthFromUniformOptions();
+    /// Copy constructor
+    ArrayLengthFromUniformOptions(const ArrayLengthFromUniformOptions&);
+    /// Copy assignment
+    /// @returns this ArrayLengthFromUniformOptions
+    ArrayLengthFromUniformOptions& operator=(const ArrayLengthFromUniformOptions&);
+    /// Move constructor
+    ArrayLengthFromUniformOptions(ArrayLengthFromUniformOptions&&);
 
-  /// The binding point to use to generate a uniform buffer from which to read
-  /// buffer sizes.
-  sem::BindingPoint ubo_binding;
-  /// The mapping from storage buffer binding points to the index into the
-  /// uniform buffer where the length of the buffer is stored.
-  std::unordered_map<sem::BindingPoint, uint32_t> bindpoint_to_size_index;
+    /// The binding point to use to generate a uniform buffer from which to read
+    /// buffer sizes.
+    sem::BindingPoint ubo_binding;
+    /// The mapping from storage buffer binding points to the index into the
+    /// uniform buffer where the length of the buffer is stored.
+    std::unordered_map<sem::BindingPoint, uint32_t> bindpoint_to_size_index;
 
-  // NOTE: Update src/tint/fuzzers/data_builder.h when adding or changing any
-  // struct members.
+    // NOTE: Update src/tint/fuzzers/data_builder.h when adding or changing any
+    // struct members.
 };
 
 }  // namespace tint::writer
diff --git a/src/tint/writer/flatten_bindings.cc b/src/tint/writer/flatten_bindings.cc
new file mode 100644
index 0000000..1efc02a
--- /dev/null
+++ b/src/tint/writer/flatten_bindings.cc
@@ -0,0 +1,78 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/writer/flatten_bindings.h"
+
+#include <utility>
+
+#include "src/tint/inspector/inspector.h"
+#include "src/tint/transform/binding_remapper.h"
+#include "src/tint/transform/manager.h"
+
+namespace tint::writer {
+std::optional<Program> FlattenBindings(const Program* program) {
+    // TODO(crbug.com/tint/1101): Make this more robust for multiple entry points.
+    using BindingPoint = tint::transform::BindingPoint;
+    tint::transform::BindingRemapper::BindingPoints binding_points;
+    uint32_t next_buffer_idx = 0;
+    uint32_t next_sampler_idx = 0;
+    uint32_t next_texture_idx = 0;
+
+    tint::inspector::Inspector inspector(program);
+    auto entry_points = inspector.GetEntryPoints();
+    for (auto& entry_point : entry_points) {
+        auto bindings = inspector.GetResourceBindings(entry_point.name);
+        for (auto& binding : bindings) {
+            BindingPoint src = {binding.bind_group, binding.binding};
+            if (binding_points.count(src)) {
+                continue;
+            }
+            switch (binding.resource_type) {
+                case tint::inspector::ResourceBinding::ResourceType::kUniformBuffer:
+                case tint::inspector::ResourceBinding::ResourceType::kStorageBuffer:
+                case tint::inspector::ResourceBinding::ResourceType::kReadOnlyStorageBuffer:
+                    binding_points.emplace(src, BindingPoint{0, next_buffer_idx++});
+                    break;
+                case tint::inspector::ResourceBinding::ResourceType::kSampler:
+                case tint::inspector::ResourceBinding::ResourceType::kComparisonSampler:
+                    binding_points.emplace(src, BindingPoint{0, next_sampler_idx++});
+                    break;
+                case tint::inspector::ResourceBinding::ResourceType::kSampledTexture:
+                case tint::inspector::ResourceBinding::ResourceType::kMultisampledTexture:
+                case tint::inspector::ResourceBinding::ResourceType::kWriteOnlyStorageTexture:
+                case tint::inspector::ResourceBinding::ResourceType::kDepthTexture:
+                case tint::inspector::ResourceBinding::ResourceType::kDepthMultisampledTexture:
+                case tint::inspector::ResourceBinding::ResourceType::kExternalTexture:
+                    binding_points.emplace(src, BindingPoint{0, next_texture_idx++});
+                    break;
+            }
+        }
+    }
+
+    // Run the binding remapper transform.
+    tint::transform::Output transform_output;
+    if (!binding_points.empty()) {
+        tint::transform::Manager manager;
+        tint::transform::DataMap inputs;
+        inputs.Add<tint::transform::BindingRemapper::Remappings>(
+            std::move(binding_points), tint::transform::BindingRemapper::AccessControls{},
+            /* mayCollide */ true);
+        manager.Add<tint::transform::BindingRemapper>();
+        transform_output = manager.Run(program, inputs);
+        return std::move(transform_output.program);
+    }
+
+    return {};
+}
+}  // namespace tint::writer
diff --git a/src/tint/writer/flatten_bindings.h b/src/tint/writer/flatten_bindings.h
new file mode 100644
index 0000000..0250571
--- /dev/null
+++ b/src/tint/writer/flatten_bindings.h
@@ -0,0 +1,31 @@
+// 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_WRITER_FLATTEN_BINDINGS_H_
+#define SRC_TINT_WRITER_FLATTEN_BINDINGS_H_
+
+#include <optional>
+#include "src/tint/program.h"
+
+namespace tint::writer {
+
+/// If needed, remaps resource numbers of `program` to a flat namespace: all in
+/// group 0 within unique binding numbers.
+/// @param program A valid program
+/// @return A new program with bindings remapped if needed
+std::optional<Program> FlattenBindings(const Program* program);
+
+}  // namespace tint::writer
+
+#endif  // SRC_TINT_WRITER_FLATTEN_BINDINGS_H_
diff --git a/src/tint/writer/flatten_bindings_test.cc b/src/tint/writer/flatten_bindings_test.cc
new file mode 100644
index 0000000..1c516c9
--- /dev/null
+++ b/src/tint/writer/flatten_bindings_test.cc
@@ -0,0 +1,142 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/writer/flatten_bindings.h"
+
+#include <utility>
+
+#include "gtest/gtest.h"
+#include "src/tint/program_builder.h"
+#include "src/tint/resolver/resolver.h"
+#include "src/tint/sem/variable.h"
+
+namespace tint::writer {
+namespace {
+
+class FlattenBindingsTest : public ::testing::Test {};
+
+TEST_F(FlattenBindingsTest, NoBindings) {
+    ProgramBuilder b;
+    b.WrapInFunction();
+
+    resolver::Resolver resolver(&b);
+
+    Program program(std::move(b));
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+
+    auto flattened = tint::writer::FlattenBindings(&program);
+    EXPECT_FALSE(flattened);
+}
+
+TEST_F(FlattenBindingsTest, AlreadyFlat) {
+    ProgramBuilder b;
+    b.Global("a", b.ty.i32(), ast::StorageClass::kUniform, b.GroupAndBinding(0, 0));
+    b.Global("b", b.ty.i32(), ast::StorageClass::kUniform, b.GroupAndBinding(0, 1));
+    b.Global("c", b.ty.i32(), ast::StorageClass::kUniform, b.GroupAndBinding(0, 2));
+    b.WrapInFunction();
+
+    resolver::Resolver resolver(&b);
+
+    Program program(std::move(b));
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+
+    auto flattened = tint::writer::FlattenBindings(&program);
+    EXPECT_FALSE(flattened);
+}
+
+TEST_F(FlattenBindingsTest, NotFlat_SingleNamespace) {
+    ProgramBuilder b;
+    b.Global("a", b.ty.i32(), ast::StorageClass::kUniform, b.GroupAndBinding(0, 0));
+    b.Global("b", b.ty.i32(), ast::StorageClass::kUniform, b.GroupAndBinding(1, 1));
+    b.Global("c", b.ty.i32(), ast::StorageClass::kUniform, b.GroupAndBinding(2, 2));
+    b.WrapInFunction(b.Expr("a"), b.Expr("b"), b.Expr("c"));
+
+    resolver::Resolver resolver(&b);
+
+    Program program(std::move(b));
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+
+    auto flattened = tint::writer::FlattenBindings(&program);
+    EXPECT_TRUE(flattened);
+
+    auto& vars = flattened->AST().GlobalVariables();
+    EXPECT_EQ(vars[0]->BindingPoint().group->value, 0u);
+    EXPECT_EQ(vars[0]->BindingPoint().binding->value, 0u);
+    EXPECT_EQ(vars[1]->BindingPoint().group->value, 0u);
+    EXPECT_EQ(vars[1]->BindingPoint().binding->value, 1u);
+    EXPECT_EQ(vars[2]->BindingPoint().group->value, 0u);
+    EXPECT_EQ(vars[2]->BindingPoint().binding->value, 2u);
+}
+
+TEST_F(FlattenBindingsTest, NotFlat_MultipleNamespaces) {
+    ProgramBuilder b;
+
+    const size_t num_buffers = 3;
+    b.Global("buffer1", b.ty.i32(), ast::StorageClass::kUniform, b.GroupAndBinding(0, 0));
+    b.Global("buffer2", b.ty.i32(), ast::StorageClass::kStorage, b.GroupAndBinding(1, 1));
+    b.Global("buffer3", b.ty.i32(), ast::StorageClass::kStorage, ast::Access::kRead,
+             b.GroupAndBinding(2, 2));
+
+    const size_t num_samplers = 2;
+    b.Global("sampler1", b.ty.sampler(ast::SamplerKind::kSampler), b.GroupAndBinding(3, 3));
+    b.Global("sampler2", b.ty.sampler(ast::SamplerKind::kComparisonSampler),
+             b.GroupAndBinding(4, 4));
+
+    const size_t num_textures = 6;
+    b.Global("texture1", b.ty.sampled_texture(ast::TextureDimension::k2d, b.ty.f32()),
+             b.GroupAndBinding(5, 5));
+    b.Global("texture2", b.ty.multisampled_texture(ast::TextureDimension::k2d, b.ty.f32()),
+             b.GroupAndBinding(6, 6));
+    b.Global("texture3",
+             b.ty.storage_texture(ast::TextureDimension::k2d, ast::TexelFormat::kR32Float,
+                                  ast::Access::kWrite),
+             b.GroupAndBinding(7, 7));
+    b.Global("texture4", b.ty.depth_texture(ast::TextureDimension::k2d), b.GroupAndBinding(8, 8));
+    b.Global("texture5", b.ty.depth_multisampled_texture(ast::TextureDimension::k2d),
+             b.GroupAndBinding(9, 9));
+    b.Global("texture6", b.ty.external_texture(), b.GroupAndBinding(10, 10));
+
+    b.WrapInFunction(b.Assign(b.Phony(), "buffer1"), b.Assign(b.Phony(), "buffer2"),
+                     b.Assign(b.Phony(), "buffer3"), b.Assign(b.Phony(), "sampler1"),
+                     b.Assign(b.Phony(), "sampler2"), b.Assign(b.Phony(), "texture1"),
+                     b.Assign(b.Phony(), "texture2"), b.Assign(b.Phony(), "texture3"),
+                     b.Assign(b.Phony(), "texture4"), b.Assign(b.Phony(), "texture5"),
+                     b.Assign(b.Phony(), "texture6"));
+
+    resolver::Resolver resolver(&b);
+
+    Program program(std::move(b));
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+
+    auto flattened = tint::writer::FlattenBindings(&program);
+    EXPECT_TRUE(flattened);
+
+    auto& vars = flattened->AST().GlobalVariables();
+
+    for (size_t i = 0; i < num_buffers; ++i) {
+        EXPECT_EQ(vars[i]->BindingPoint().group->value, 0u);
+        EXPECT_EQ(vars[i]->BindingPoint().binding->value, i);
+    }
+    for (size_t i = 0; i < num_samplers; ++i) {
+        EXPECT_EQ(vars[i + num_buffers]->BindingPoint().group->value, 0u);
+        EXPECT_EQ(vars[i + num_buffers]->BindingPoint().binding->value, i);
+    }
+    for (size_t i = 0; i < num_textures; ++i) {
+        EXPECT_EQ(vars[i + num_buffers + num_samplers]->BindingPoint().group->value, 0u);
+        EXPECT_EQ(vars[i + num_buffers + num_samplers]->BindingPoint().binding->value, i);
+    }
+}
+
+}  // namespace
+}  // namespace tint::writer
diff --git a/src/tint/writer/float_to_string.cc b/src/tint/writer/float_to_string.cc
index 64885fe..e0c3260 100644
--- a/src/tint/writer/float_to_string.cc
+++ b/src/tint/writer/float_to_string.cc
@@ -26,131 +26,130 @@
 namespace tint::writer {
 
 std::string FloatToString(float f) {
-  // Try printing the float in fixed point, with a smallish limit on the
-  // precision
-  std::stringstream fixed;
-  fixed.flags(fixed.flags() | std::ios_base::showpoint | std::ios_base::fixed);
-  fixed.precision(9);
-  fixed << f;
+    // Try printing the float in fixed point, with a smallish limit on the
+    // precision
+    std::stringstream fixed;
+    fixed.flags(fixed.flags() | std::ios_base::showpoint | std::ios_base::fixed);
+    fixed.precision(9);
+    fixed << f;
 
-  // If this string can be parsed without loss of information, use it
-  auto float_equal_no_warning = std::equal_to<float>();
-  if (float_equal_no_warning(std::stof(fixed.str()), f)) {
-    auto str = fixed.str();
-    while (str.length() >= 2 && str[str.size() - 1] == '0' &&
-           str[str.size() - 2] != '.') {
-      str.pop_back();
+    // If this string can be parsed without loss of information, use it
+    auto float_equal_no_warning = std::equal_to<float>();
+    if (float_equal_no_warning(std::stof(fixed.str()), f)) {
+        auto str = fixed.str();
+        while (str.length() >= 2 && str[str.size() - 1] == '0' && str[str.size() - 2] != '.') {
+            str.pop_back();
+        }
+
+        return str;
     }
 
-    return str;
-  }
-
-  // Resort to scientific, with the minimum precision needed to preserve the
-  // whole float
-  std::stringstream sci;
-  sci.precision(std::numeric_limits<float>::max_digits10);
-  sci << f;
-  return sci.str();
+    // Resort to scientific, with the minimum precision needed to preserve the
+    // whole float
+    std::stringstream sci;
+    sci.precision(std::numeric_limits<float>::max_digits10);
+    sci << f;
+    return sci.str();
 }
 
 std::string FloatToBitPreservingString(float f) {
-  // For the NaN case, avoid handling the number as a floating point value.
-  // Some machines will modify the top bit in the mantissa of a NaN.
+    // For the NaN case, avoid handling the number as a floating point value.
+    // Some machines will modify the top bit in the mantissa of a NaN.
 
-  std::stringstream ss;
+    std::stringstream ss;
 
-  uint32_t float_bits = 0u;
-  std::memcpy(&float_bits, &f, sizeof(float_bits));
+    uint32_t float_bits = 0u;
+    std::memcpy(&float_bits, &f, sizeof(float_bits));
 
-  // Handle the sign.
-  const uint32_t kSignMask = 1u << 31;
-  if (float_bits & kSignMask) {
-    // If `f` is -0.0 print -0.0.
-    ss << '-';
-    // Strip sign bit.
-    float_bits = float_bits & (~kSignMask);
-  }
-
-  switch (std::fpclassify(f)) {
-    case FP_ZERO:
-    case FP_NORMAL:
-      std::memcpy(&f, &float_bits, sizeof(float_bits));
-      ss << FloatToString(f);
-      break;
-
-    default: {
-      // Infinity, NaN, and Subnormal
-      // TODO(dneto): It's unclear how Infinity and NaN should be handled.
-      // See https://github.com/gpuweb/gpuweb/issues/1769
-
-      // std::hexfloat prints 'nan' and 'inf' instead of an
-      // explicit representation like we want. Split it out
-      // manually.
-      const int kExponentBias = 127;
-      const int kExponentMask = 0x7f800000;
-      const int kMantissaMask = 0x007fffff;
-      const int kMantissaBits = 23;
-
-      int mantissaNibbles = (kMantissaBits + 3) / 4;
-
-      const int biased_exponent =
-          static_cast<int>((float_bits & kExponentMask) >> kMantissaBits);
-      int exponent = biased_exponent - kExponentBias;
-      uint32_t mantissa = float_bits & kMantissaMask;
-
-      ss << "0x";
-
-      if (exponent == 128) {
-        if (mantissa == 0) {
-          //  Infinity case.
-          ss << "1p+128";
-        } else {
-          //  NaN case.
-          //  Emit the mantissa bits as if they are left-justified after the
-          //  binary point.  This is what SPIRV-Tools hex float emitter does,
-          //  and it's a justifiable choice independent of the bit width
-          //  of the mantissa.
-          mantissa <<= (4 - (kMantissaBits % 4));
-          // Remove trailing zeroes, for tidyness.
-          while (0 == (0xf & mantissa)) {
-            mantissa >>= 4;
-            mantissaNibbles--;
-          }
-          ss << "1." << std::hex << std::setfill('0')
-             << std::setw(mantissaNibbles) << mantissa << "p+128";
-        }
-      } else {
-        // Subnormal, and not zero.
-        TINT_ASSERT(Writer, mantissa != 0);
-        const int kTopBit = (1 << kMantissaBits);
-
-        // Shift left until we get 1.x
-        while (0 == (kTopBit & mantissa)) {
-          mantissa <<= 1;
-          exponent--;
-        }
-        // Emit the leading 1, and remove it from the mantissa.
-        ss << "1";
-        mantissa = mantissa ^ kTopBit;
-        mantissa <<= 1;
-        exponent++;
-
-        // Emit the fractional part.
-        if (mantissa) {
-          // Remove trailing zeroes, for tidyness
-          while (0 == (0xf & mantissa)) {
-            mantissa >>= 4;
-            mantissaNibbles--;
-          }
-          ss << "." << std::hex << std::setfill('0')
-             << std::setw(mantissaNibbles) << mantissa;
-        }
-        // Emit the exponent
-        ss << "p" << std::showpos << std::dec << exponent;
-      }
+    // Handle the sign.
+    const uint32_t kSignMask = 1u << 31;
+    if (float_bits & kSignMask) {
+        // If `f` is -0.0 print -0.0.
+        ss << '-';
+        // Strip sign bit.
+        float_bits = float_bits & (~kSignMask);
     }
-  }
-  return ss.str();
+
+    switch (std::fpclassify(f)) {
+        case FP_ZERO:
+        case FP_NORMAL:
+            std::memcpy(&f, &float_bits, sizeof(float_bits));
+            ss << FloatToString(f);
+            break;
+
+        default: {
+            // Infinity, NaN, and Subnormal
+            // TODO(dneto): It's unclear how Infinity and NaN should be handled.
+            // See https://github.com/gpuweb/gpuweb/issues/1769
+
+            // std::hexfloat prints 'nan' and 'inf' instead of an
+            // explicit representation like we want. Split it out
+            // manually.
+            const int kExponentBias = 127;
+            const int kExponentMask = 0x7f800000;
+            const int kMantissaMask = 0x007fffff;
+            const int kMantissaBits = 23;
+
+            int mantissaNibbles = (kMantissaBits + 3) / 4;
+
+            const int biased_exponent =
+                static_cast<int>((float_bits & kExponentMask) >> kMantissaBits);
+            int exponent = biased_exponent - kExponentBias;
+            uint32_t mantissa = float_bits & kMantissaMask;
+
+            ss << "0x";
+
+            if (exponent == 128) {
+                if (mantissa == 0) {
+                    //  Infinity case.
+                    ss << "1p+128";
+                } else {
+                    //  NaN case.
+                    //  Emit the mantissa bits as if they are left-justified after the
+                    //  binary point.  This is what SPIRV-Tools hex float emitter does,
+                    //  and it's a justifiable choice independent of the bit width
+                    //  of the mantissa.
+                    mantissa <<= (4 - (kMantissaBits % 4));
+                    // Remove trailing zeroes, for tidyness.
+                    while (0 == (0xf & mantissa)) {
+                        mantissa >>= 4;
+                        mantissaNibbles--;
+                    }
+                    ss << "1." << std::hex << std::setfill('0') << std::setw(mantissaNibbles)
+                       << mantissa << "p+128";
+                }
+            } else {
+                // Subnormal, and not zero.
+                TINT_ASSERT(Writer, mantissa != 0);
+                const int kTopBit = (1 << kMantissaBits);
+
+                // Shift left until we get 1.x
+                while (0 == (kTopBit & mantissa)) {
+                    mantissa <<= 1;
+                    exponent--;
+                }
+                // Emit the leading 1, and remove it from the mantissa.
+                ss << "1";
+                mantissa = mantissa ^ kTopBit;
+                mantissa <<= 1;
+                exponent++;
+
+                // Emit the fractional part.
+                if (mantissa) {
+                    // Remove trailing zeroes, for tidyness
+                    while (0 == (0xf & mantissa)) {
+                        mantissa >>= 4;
+                        mantissaNibbles--;
+                    }
+                    ss << "." << std::hex << std::setfill('0') << std::setw(mantissaNibbles)
+                       << mantissa;
+                }
+                // Emit the exponent
+                ss << "p" << std::showpos << std::dec << exponent;
+            }
+        }
+    }
+    return ss.str();
 }
 
 }  // namespace tint::writer
diff --git a/src/tint/writer/float_to_string_test.cc b/src/tint/writer/float_to_string_test.cc
index 50caa59..2596be7 100644
--- a/src/tint/writer/float_to_string_test.cc
+++ b/src/tint/writer/float_to_string_test.cc
@@ -28,70 +28,69 @@
 // - 'exponent_bits' is placed in the exponent space.
 //   So, the exponent bias must already be included.
 float MakeFloat(int sign, int biased_exponent, int mantissa) {
-  const uint32_t sign_bit = sign ? 0x80000000u : 0u;
-  // The binary32 exponent is 8 bits, just below the sign.
-  const uint32_t exponent_bits = (biased_exponent & 0xffu) << 23;
-  // The mantissa is the bottom 23 bits.
-  const uint32_t mantissa_bits = (mantissa & 0x7fffffu);
+    const uint32_t sign_bit = sign ? 0x80000000u : 0u;
+    // The binary32 exponent is 8 bits, just below the sign.
+    const uint32_t exponent_bits = (biased_exponent & 0xffu) << 23;
+    // The mantissa is the bottom 23 bits.
+    const uint32_t mantissa_bits = (mantissa & 0x7fffffu);
 
-  uint32_t bits = sign_bit | exponent_bits | mantissa_bits;
-  float result = 0.0f;
-  static_assert(sizeof(result) == sizeof(bits),
-                "expected float and uint32_t to be the same size");
-  std::memcpy(&result, &bits, sizeof(bits));
-  return result;
+    uint32_t bits = sign_bit | exponent_bits | mantissa_bits;
+    float result = 0.0f;
+    static_assert(sizeof(result) == sizeof(bits),
+                  "expected float and uint32_t to be the same size");
+    std::memcpy(&result, &bits, sizeof(bits));
+    return result;
 }
 
 TEST(FloatToStringTest, Zero) {
-  EXPECT_EQ(FloatToString(0.0f), "0.0");
+    EXPECT_EQ(FloatToString(0.0f), "0.0");
 }
 
 TEST(FloatToStringTest, One) {
-  EXPECT_EQ(FloatToString(1.0f), "1.0");
+    EXPECT_EQ(FloatToString(1.0f), "1.0");
 }
 
 TEST(FloatToStringTest, MinusOne) {
-  EXPECT_EQ(FloatToString(-1.0f), "-1.0");
+    EXPECT_EQ(FloatToString(-1.0f), "-1.0");
 }
 
 TEST(FloatToStringTest, Billion) {
-  EXPECT_EQ(FloatToString(1e9f), "1000000000.0");
+    EXPECT_EQ(FloatToString(1e9f), "1000000000.0");
 }
 
 TEST(FloatToStringTest, Small) {
-  EXPECT_NE(FloatToString(std::numeric_limits<float>::epsilon()), "0.0");
+    EXPECT_NE(FloatToString(std::numeric_limits<float>::epsilon()), "0.0");
 }
 
 TEST(FloatToStringTest, Highest) {
-  const auto highest = std::numeric_limits<float>::max();
-  const auto expected_highest = 340282346638528859811704183484516925440.0f;
-  if (highest < expected_highest || highest > expected_highest) {
-    GTEST_SKIP() << "std::numeric_limits<float>::max() is not as expected for "
-                    "this target";
-  }
-  EXPECT_EQ(FloatToString(std::numeric_limits<float>::max()),
-            "340282346638528859811704183484516925440.0");
+    const auto highest = std::numeric_limits<float>::max();
+    const auto expected_highest = 340282346638528859811704183484516925440.0f;
+    if (highest < expected_highest || highest > expected_highest) {
+        GTEST_SKIP() << "std::numeric_limits<float>::max() is not as expected for "
+                        "this target";
+    }
+    EXPECT_EQ(FloatToString(std::numeric_limits<float>::max()),
+              "340282346638528859811704183484516925440.0");
 }
 
 TEST(FloatToStringTest, Lowest) {
-  // Some compilers complain if you test floating point numbers for equality.
-  // So say it via two inequalities.
-  const auto lowest = std::numeric_limits<float>::lowest();
-  const auto expected_lowest = -340282346638528859811704183484516925440.0f;
-  if (lowest < expected_lowest || lowest > expected_lowest) {
-    GTEST_SKIP()
-        << "std::numeric_limits<float>::lowest() is not as expected for "
-           "this target";
-  }
-  EXPECT_EQ(FloatToString(std::numeric_limits<float>::lowest()),
-            "-340282346638528859811704183484516925440.0");
+    // Some compilers complain if you test floating point numbers for equality.
+    // So say it via two inequalities.
+    const auto lowest = std::numeric_limits<float>::lowest();
+    const auto expected_lowest = -340282346638528859811704183484516925440.0f;
+    if (lowest < expected_lowest || lowest > expected_lowest) {
+        GTEST_SKIP() << "std::numeric_limits<float>::lowest() is not as expected for "
+                        "this target";
+    }
+    EXPECT_EQ(FloatToString(std::numeric_limits<float>::lowest()),
+              "-340282346638528859811704183484516925440.0");
 }
 
 TEST(FloatToStringTest, Precision) {
-  EXPECT_EQ(FloatToString(1e-8f), "0.00000001");
-  EXPECT_EQ(FloatToString(1e-9f), "0.000000001");
-  EXPECT_EQ(FloatToString(1e-10f), "1.00000001e-10");
-  EXPECT_EQ(FloatToString(1e-20f), "9.99999968e-21");
+    EXPECT_EQ(FloatToString(1e-8f), "0.00000001");
+    EXPECT_EQ(FloatToString(1e-9f), "0.000000001");
+    EXPECT_EQ(FloatToString(1e-10f), "1.00000001e-10");
+    EXPECT_EQ(FloatToString(1e-20f), "9.99999968e-21");
 }
 
 // FloatToBitPreservingString
@@ -99,99 +98,92 @@
 // First replicate the tests for FloatToString
 
 TEST(FloatToBitPreservingStringTest, Zero) {
-  EXPECT_EQ(FloatToBitPreservingString(0.0f), "0.0");
+    EXPECT_EQ(FloatToBitPreservingString(0.0f), "0.0");
 }
 
 TEST(FloatToBitPreservingStringTest, One) {
-  EXPECT_EQ(FloatToBitPreservingString(1.0f), "1.0");
+    EXPECT_EQ(FloatToBitPreservingString(1.0f), "1.0");
 }
 
 TEST(FloatToBitPreservingStringTest, MinusOne) {
-  EXPECT_EQ(FloatToBitPreservingString(-1.0f), "-1.0");
+    EXPECT_EQ(FloatToBitPreservingString(-1.0f), "-1.0");
 }
 
 TEST(FloatToBitPreservingStringTest, Billion) {
-  EXPECT_EQ(FloatToBitPreservingString(1e9f), "1000000000.0");
+    EXPECT_EQ(FloatToBitPreservingString(1e9f), "1000000000.0");
 }
 
 TEST(FloatToBitPreservingStringTest, Small) {
-  EXPECT_NE(FloatToBitPreservingString(std::numeric_limits<float>::epsilon()),
-            "0.0");
+    EXPECT_NE(FloatToBitPreservingString(std::numeric_limits<float>::epsilon()), "0.0");
 }
 
 TEST(FloatToBitPreservingStringTest, Highest) {
-  const auto highest = std::numeric_limits<float>::max();
-  const auto expected_highest = 340282346638528859811704183484516925440.0f;
-  if (highest < expected_highest || highest > expected_highest) {
-    GTEST_SKIP() << "std::numeric_limits<float>::max() is not as expected for "
-                    "this target";
-  }
-  EXPECT_EQ(FloatToBitPreservingString(std::numeric_limits<float>::max()),
-            "340282346638528859811704183484516925440.0");
+    const auto highest = std::numeric_limits<float>::max();
+    const auto expected_highest = 340282346638528859811704183484516925440.0f;
+    if (highest < expected_highest || highest > expected_highest) {
+        GTEST_SKIP() << "std::numeric_limits<float>::max() is not as expected for "
+                        "this target";
+    }
+    EXPECT_EQ(FloatToBitPreservingString(std::numeric_limits<float>::max()),
+              "340282346638528859811704183484516925440.0");
 }
 
 TEST(FloatToBitPreservingStringTest, Lowest) {
-  // Some compilers complain if you test floating point numbers for equality.
-  // So say it via two inequalities.
-  const auto lowest = std::numeric_limits<float>::lowest();
-  const auto expected_lowest = -340282346638528859811704183484516925440.0f;
-  if (lowest < expected_lowest || lowest > expected_lowest) {
-    GTEST_SKIP()
-        << "std::numeric_limits<float>::lowest() is not as expected for "
-           "this target";
-  }
-  EXPECT_EQ(FloatToBitPreservingString(std::numeric_limits<float>::lowest()),
-            "-340282346638528859811704183484516925440.0");
+    // Some compilers complain if you test floating point numbers for equality.
+    // So say it via two inequalities.
+    const auto lowest = std::numeric_limits<float>::lowest();
+    const auto expected_lowest = -340282346638528859811704183484516925440.0f;
+    if (lowest < expected_lowest || lowest > expected_lowest) {
+        GTEST_SKIP() << "std::numeric_limits<float>::lowest() is not as expected for "
+                        "this target";
+    }
+    EXPECT_EQ(FloatToBitPreservingString(std::numeric_limits<float>::lowest()),
+              "-340282346638528859811704183484516925440.0");
 }
 
 // Special cases for bit-preserving output.
 
 TEST(FloatToBitPreservingStringTest, NegativeZero) {
-  EXPECT_EQ(FloatToBitPreservingString(std::copysign(0.0f, -5.0f)), "-0.0");
+    EXPECT_EQ(FloatToBitPreservingString(std::copysign(0.0f, -5.0f)), "-0.0");
 }
 
 TEST(FloatToBitPreservingStringTest, ZeroAsBits) {
-  EXPECT_EQ(FloatToBitPreservingString(MakeFloat(0, 0, 0)), "0.0");
-  EXPECT_EQ(FloatToBitPreservingString(MakeFloat(1, 0, 0)), "-0.0");
+    EXPECT_EQ(FloatToBitPreservingString(MakeFloat(0, 0, 0)), "0.0");
+    EXPECT_EQ(FloatToBitPreservingString(MakeFloat(1, 0, 0)), "-0.0");
 }
 
 TEST(FloatToBitPreservingStringTest, OneBits) {
-  EXPECT_EQ(FloatToBitPreservingString(MakeFloat(0, 127, 0)), "1.0");
-  EXPECT_EQ(FloatToBitPreservingString(MakeFloat(1, 127, 0)), "-1.0");
+    EXPECT_EQ(FloatToBitPreservingString(MakeFloat(0, 127, 0)), "1.0");
+    EXPECT_EQ(FloatToBitPreservingString(MakeFloat(1, 127, 0)), "-1.0");
 }
 
 TEST(FloatToBitPreservingStringTest, SmallestDenormal) {
-  EXPECT_EQ(FloatToBitPreservingString(MakeFloat(0, 0, 1)), "0x1p-149");
-  EXPECT_EQ(FloatToBitPreservingString(MakeFloat(1, 0, 1)), "-0x1p-149");
+    EXPECT_EQ(FloatToBitPreservingString(MakeFloat(0, 0, 1)), "0x1p-149");
+    EXPECT_EQ(FloatToBitPreservingString(MakeFloat(1, 0, 1)), "-0x1p-149");
 }
 
 TEST(FloatToBitPreservingStringTest, BiggerDenormal) {
-  EXPECT_EQ(FloatToBitPreservingString(MakeFloat(0, 0, 2)), "0x1p-148");
-  EXPECT_EQ(FloatToBitPreservingString(MakeFloat(1, 0, 2)), "-0x1p-148");
+    EXPECT_EQ(FloatToBitPreservingString(MakeFloat(0, 0, 2)), "0x1p-148");
+    EXPECT_EQ(FloatToBitPreservingString(MakeFloat(1, 0, 2)), "-0x1p-148");
 }
 
 TEST(FloatToBitPreservingStringTest, LargestDenormal) {
-  EXPECT_EQ(FloatToBitPreservingString(MakeFloat(0, 0, 0x7fffff)),
-            "0x1.fffffcp-127");
+    EXPECT_EQ(FloatToBitPreservingString(MakeFloat(0, 0, 0x7fffff)), "0x1.fffffcp-127");
 }
 
 TEST(FloatToBitPreservingStringTest, Subnormal_cafebe) {
-  EXPECT_EQ(FloatToBitPreservingString(MakeFloat(0, 0, 0xcafebe)),
-            "0x1.2bfaf8p-127");
-  EXPECT_EQ(FloatToBitPreservingString(MakeFloat(1, 0, 0xcafebe)),
-            "-0x1.2bfaf8p-127");
+    EXPECT_EQ(FloatToBitPreservingString(MakeFloat(0, 0, 0xcafebe)), "0x1.2bfaf8p-127");
+    EXPECT_EQ(FloatToBitPreservingString(MakeFloat(1, 0, 0xcafebe)), "-0x1.2bfaf8p-127");
 }
 
 TEST(FloatToBitPreservingStringTest, Subnormal_aaaaa) {
-  EXPECT_EQ(FloatToBitPreservingString(MakeFloat(0, 0, 0xaaaaa)),
-            "0x1.55554p-130");
-  EXPECT_EQ(FloatToBitPreservingString(MakeFloat(1, 0, 0xaaaaa)),
-            "-0x1.55554p-130");
+    EXPECT_EQ(FloatToBitPreservingString(MakeFloat(0, 0, 0xaaaaa)), "0x1.55554p-130");
+    EXPECT_EQ(FloatToBitPreservingString(MakeFloat(1, 0, 0xaaaaa)), "-0x1.55554p-130");
 }
 
 TEST(FloatToBitPreservingStringTest, Infinity) {
-  EXPECT_EQ(FloatToBitPreservingString(MakeFloat(0, 255, 0)), "0x1p+128");
-  EXPECT_EQ(FloatToBitPreservingString(MakeFloat(1, 255, 0)), "-0x1p+128");
+    EXPECT_EQ(FloatToBitPreservingString(MakeFloat(0, 255, 0)), "0x1p+128");
+    EXPECT_EQ(FloatToBitPreservingString(MakeFloat(1, 255, 0)), "-0x1p+128");
 }
 
 // TODO(dneto): It's unclear how Infinity and NaN should be handled.
@@ -200,24 +192,18 @@
 // Disable NaN tests for now.
 
 TEST(FloatToBitPreservingStringTest, DISABLED_NaN_MsbOnly) {
-  EXPECT_EQ(FloatToBitPreservingString(MakeFloat(0, 255, 0x400000)),
-            "0x1.8p+128");
-  EXPECT_EQ(FloatToBitPreservingString(MakeFloat(1, 255, 0x400000)),
-            "-0x1.8p+128");
+    EXPECT_EQ(FloatToBitPreservingString(MakeFloat(0, 255, 0x400000)), "0x1.8p+128");
+    EXPECT_EQ(FloatToBitPreservingString(MakeFloat(1, 255, 0x400000)), "-0x1.8p+128");
 }
 
 TEST(FloatToBitPreservingStringTest, DISABLED_NaN_LsbOnly) {
-  EXPECT_EQ(FloatToBitPreservingString(MakeFloat(0, 255, 0x1)),
-            "0x1.000002p+128");
-  EXPECT_EQ(FloatToBitPreservingString(MakeFloat(1, 255, 0x1)),
-            "-0x1.000002p+128");
+    EXPECT_EQ(FloatToBitPreservingString(MakeFloat(0, 255, 0x1)), "0x1.000002p+128");
+    EXPECT_EQ(FloatToBitPreservingString(MakeFloat(1, 255, 0x1)), "-0x1.000002p+128");
 }
 
 TEST(FloatToBitPreservingStringTest, DISABLED_NaN_NonMsb) {
-  EXPECT_EQ(FloatToBitPreservingString(MakeFloat(0, 255, 0x20101f)),
-            "0x1.40203ep+128");
-  EXPECT_EQ(FloatToBitPreservingString(MakeFloat(1, 255, 0x20101f)),
-            "-0x1.40203ep+128");
+    EXPECT_EQ(FloatToBitPreservingString(MakeFloat(0, 255, 0x20101f)), "0x1.40203ep+128");
+    EXPECT_EQ(FloatToBitPreservingString(MakeFloat(1, 255, 0x20101f)), "-0x1.40203ep+128");
 }
 
 }  // namespace
diff --git a/src/tint/writer/generate_external_texture_bindings.cc b/src/tint/writer/generate_external_texture_bindings.cc
index 44bd262..16c33e3 100644
--- a/src/tint/writer/generate_external_texture_bindings.cc
+++ b/src/tint/writer/generate_external_texture_bindings.cc
@@ -21,39 +21,39 @@
 #include "src/tint/ast/external_texture.h"
 #include "src/tint/ast/module.h"
 #include "src/tint/program.h"
-#include "src/tint/sem/external_texture_type.h"
+#include "src/tint/sem/external_texture.h"
 #include "src/tint/sem/variable.h"
 
 namespace tint::writer {
 
-transform::MultiplanarExternalTexture::BindingsMap
-GenerateExternalTextureBindings(const Program* program) {
-  // TODO(tint:1491): Use Inspector once we can get binding info for all
-  // variables, not just those referenced by entry points.
+transform::MultiplanarExternalTexture::BindingsMap GenerateExternalTextureBindings(
+    const Program* program) {
+    // TODO(tint:1491): Use Inspector once we can get binding info for all
+    // variables, not just those referenced by entry points.
 
-  // Collect next valid binding number per group
-  std::unordered_map<uint32_t, uint32_t> group_to_next_binding_number;
-  std::vector<sem::BindingPoint> ext_tex_bps;
-  for (auto* var : program->AST().GlobalVariables()) {
-    if (auto* sem_var = program->Sem().Get(var)->As<sem::GlobalVariable>()) {
-      auto bp = sem_var->BindingPoint();
-      auto& n = group_to_next_binding_number[bp.group];
-      n = std::max(n, bp.binding + 1);
+    // Collect next valid binding number per group
+    std::unordered_map<uint32_t, uint32_t> group_to_next_binding_number;
+    std::vector<sem::BindingPoint> ext_tex_bps;
+    for (auto* var : program->AST().GlobalVariables()) {
+        if (auto* sem_var = program->Sem().Get(var)->As<sem::GlobalVariable>()) {
+            auto bp = sem_var->BindingPoint();
+            auto& n = group_to_next_binding_number[bp.group];
+            n = std::max(n, bp.binding + 1);
 
-      if (sem_var->Type()->UnwrapRef()->Is<sem::ExternalTexture>()) {
-        ext_tex_bps.emplace_back(bp);
-      }
+            if (sem_var->Type()->UnwrapRef()->Is<sem::ExternalTexture>()) {
+                ext_tex_bps.emplace_back(bp);
+            }
+        }
     }
-  }
 
-  transform::MultiplanarExternalTexture::BindingsMap new_bindings_map;
-  for (auto bp : ext_tex_bps) {
-    uint32_t g = bp.group;
-    uint32_t& next_num = group_to_next_binding_number[g];
-    auto new_bps = transform::BindingPoints{{g, next_num++}, {g, next_num++}};
-    new_bindings_map[bp] = new_bps;
-  }
-  return new_bindings_map;
+    transform::MultiplanarExternalTexture::BindingsMap new_bindings_map;
+    for (auto bp : ext_tex_bps) {
+        uint32_t g = bp.group;
+        uint32_t& next_num = group_to_next_binding_number[g];
+        auto new_bps = transform::BindingPoints{{g, next_num++}, {g, next_num++}};
+        new_bindings_map[bp] = new_bps;
+    }
+    return new_bindings_map;
 }
 
 }  // namespace tint::writer
diff --git a/src/tint/writer/generate_external_texture_bindings.h b/src/tint/writer/generate_external_texture_bindings.h
index 6f321d5..8d0aad9 100644
--- a/src/tint/writer/generate_external_texture_bindings.h
+++ b/src/tint/writer/generate_external_texture_bindings.h
@@ -19,8 +19,8 @@
 
 namespace tint::writer {
 
-transform::MultiplanarExternalTexture::BindingsMap
-GenerateExternalTextureBindings(const Program* program);
+transform::MultiplanarExternalTexture::BindingsMap GenerateExternalTextureBindings(
+    const Program* program);
 
 }  // namespace tint::writer
 
diff --git a/src/tint/writer/generate_external_texture_bindings_test.cc b/src/tint/writer/generate_external_texture_bindings_test.cc
index 3163007..d0918c3 100644
--- a/src/tint/writer/generate_external_texture_bindings_test.cc
+++ b/src/tint/writer/generate_external_texture_bindings_test.cc
@@ -26,105 +26,105 @@
 class GenerateExternalTextureBindingsTest : public ::testing::Test {};
 
 TEST_F(GenerateExternalTextureBindingsTest, None) {
-  ProgramBuilder b;
-  b.WrapInFunction();
+    ProgramBuilder b;
+    b.WrapInFunction();
 
-  tint::Program program(std::move(b));
-  ASSERT_TRUE(program.IsValid());
-  auto bindings = GenerateExternalTextureBindings(&program);
-  ASSERT_TRUE(bindings.empty());
+    tint::Program program(std::move(b));
+    ASSERT_TRUE(program.IsValid());
+    auto bindings = GenerateExternalTextureBindings(&program);
+    ASSERT_TRUE(bindings.empty());
 }
 
 TEST_F(GenerateExternalTextureBindingsTest, One) {
-  ProgramBuilder b;
-  b.Global("v0", b.ty.external_texture(), b.GroupAndBinding(0, 0));
-  b.WrapInFunction();
+    ProgramBuilder b;
+    b.Global("v0", b.ty.external_texture(), b.GroupAndBinding(0, 0));
+    b.WrapInFunction();
 
-  tint::Program program(std::move(b));
-  ASSERT_TRUE(program.IsValid());
-  auto bindings = GenerateExternalTextureBindings(&program);
-  ASSERT_EQ(bindings.size(), 1u);
+    tint::Program program(std::move(b));
+    ASSERT_TRUE(program.IsValid());
+    auto bindings = GenerateExternalTextureBindings(&program);
+    ASSERT_EQ(bindings.size(), 1u);
 
-  auto to = bindings[transform::BindingPoint{0, 0}];
-  ASSERT_EQ(to.plane_1.group, 0u);
-  ASSERT_EQ(to.params.group, 0u);
-  ASSERT_EQ(to.plane_1.binding, 1u);
-  ASSERT_EQ(to.params.binding, 2u);
+    auto to = bindings[transform::BindingPoint{0, 0}];
+    ASSERT_EQ(to.plane_1.group, 0u);
+    ASSERT_EQ(to.params.group, 0u);
+    ASSERT_EQ(to.plane_1.binding, 1u);
+    ASSERT_EQ(to.params.binding, 2u);
 }
 
 TEST_F(GenerateExternalTextureBindingsTest, Two_SameGroup) {
-  ProgramBuilder b;
-  b.Global("v0", b.ty.external_texture(), b.GroupAndBinding(0, 0));
-  b.Global("v1", b.ty.external_texture(), b.GroupAndBinding(0, 1));
-  b.WrapInFunction();
+    ProgramBuilder b;
+    b.Global("v0", b.ty.external_texture(), b.GroupAndBinding(0, 0));
+    b.Global("v1", b.ty.external_texture(), b.GroupAndBinding(0, 1));
+    b.WrapInFunction();
 
-  tint::Program program(std::move(b));
-  ASSERT_TRUE(program.IsValid());
-  auto bindings = GenerateExternalTextureBindings(&program);
-  ASSERT_EQ(bindings.size(), 2u);
+    tint::Program program(std::move(b));
+    ASSERT_TRUE(program.IsValid());
+    auto bindings = GenerateExternalTextureBindings(&program);
+    ASSERT_EQ(bindings.size(), 2u);
 
-  auto to0 = bindings[transform::BindingPoint{0, 0}];
-  ASSERT_EQ(to0.plane_1.group, 0u);
-  ASSERT_EQ(to0.params.group, 0u);
-  ASSERT_EQ(to0.plane_1.binding, 2u);
-  ASSERT_EQ(to0.params.binding, 3u);
+    auto to0 = bindings[transform::BindingPoint{0, 0}];
+    ASSERT_EQ(to0.plane_1.group, 0u);
+    ASSERT_EQ(to0.params.group, 0u);
+    ASSERT_EQ(to0.plane_1.binding, 2u);
+    ASSERT_EQ(to0.params.binding, 3u);
 
-  auto to1 = bindings[transform::BindingPoint{0, 1}];
-  ASSERT_EQ(to1.plane_1.group, 0u);
-  ASSERT_EQ(to1.params.group, 0u);
-  ASSERT_EQ(to1.plane_1.binding, 4u);
-  ASSERT_EQ(to1.params.binding, 5u);
+    auto to1 = bindings[transform::BindingPoint{0, 1}];
+    ASSERT_EQ(to1.plane_1.group, 0u);
+    ASSERT_EQ(to1.params.group, 0u);
+    ASSERT_EQ(to1.plane_1.binding, 4u);
+    ASSERT_EQ(to1.params.binding, 5u);
 }
 
 TEST_F(GenerateExternalTextureBindingsTest, Two_DifferentGroup) {
-  ProgramBuilder b;
-  b.Global("v0", b.ty.external_texture(), b.GroupAndBinding(0, 0));
-  b.Global("v1", b.ty.external_texture(), b.GroupAndBinding(1, 0));
-  b.WrapInFunction();
+    ProgramBuilder b;
+    b.Global("v0", b.ty.external_texture(), b.GroupAndBinding(0, 0));
+    b.Global("v1", b.ty.external_texture(), b.GroupAndBinding(1, 0));
+    b.WrapInFunction();
 
-  tint::Program program(std::move(b));
-  ASSERT_TRUE(program.IsValid());
-  auto bindings = GenerateExternalTextureBindings(&program);
-  ASSERT_EQ(bindings.size(), 2u);
+    tint::Program program(std::move(b));
+    ASSERT_TRUE(program.IsValid());
+    auto bindings = GenerateExternalTextureBindings(&program);
+    ASSERT_EQ(bindings.size(), 2u);
 
-  auto to0 = bindings[transform::BindingPoint{0, 0}];
-  ASSERT_EQ(to0.plane_1.group, 0u);
-  ASSERT_EQ(to0.params.group, 0u);
-  ASSERT_EQ(to0.plane_1.binding, 1u);
-  ASSERT_EQ(to0.params.binding, 2u);
+    auto to0 = bindings[transform::BindingPoint{0, 0}];
+    ASSERT_EQ(to0.plane_1.group, 0u);
+    ASSERT_EQ(to0.params.group, 0u);
+    ASSERT_EQ(to0.plane_1.binding, 1u);
+    ASSERT_EQ(to0.params.binding, 2u);
 
-  auto to1 = bindings[transform::BindingPoint{1, 0}];
-  ASSERT_EQ(to1.plane_1.group, 1u);
-  ASSERT_EQ(to1.params.group, 1u);
-  ASSERT_EQ(to1.plane_1.binding, 1u);
-  ASSERT_EQ(to1.params.binding, 2u);
+    auto to1 = bindings[transform::BindingPoint{1, 0}];
+    ASSERT_EQ(to1.plane_1.group, 1u);
+    ASSERT_EQ(to1.params.group, 1u);
+    ASSERT_EQ(to1.plane_1.binding, 1u);
+    ASSERT_EQ(to1.params.binding, 2u);
 }
 
 TEST_F(GenerateExternalTextureBindingsTest, Two_WithOtherBindingsInSameGroup) {
-  ProgramBuilder b;
-  b.Global("v0", b.ty.i32(), b.GroupAndBinding(0, 0), kUniform);
-  b.Global("v1", b.ty.external_texture(), b.GroupAndBinding(0, 1));
-  b.Global("v2", b.ty.i32(), b.GroupAndBinding(0, 2), kUniform);
-  b.Global("v3", b.ty.external_texture(), b.GroupAndBinding(0, 3));
-  b.Global("v4", b.ty.i32(), b.GroupAndBinding(0, 4), kUniform);
-  b.WrapInFunction();
+    ProgramBuilder b;
+    b.Global("v0", b.ty.i32(), b.GroupAndBinding(0, 0), kUniform);
+    b.Global("v1", b.ty.external_texture(), b.GroupAndBinding(0, 1));
+    b.Global("v2", b.ty.i32(), b.GroupAndBinding(0, 2), kUniform);
+    b.Global("v3", b.ty.external_texture(), b.GroupAndBinding(0, 3));
+    b.Global("v4", b.ty.i32(), b.GroupAndBinding(0, 4), kUniform);
+    b.WrapInFunction();
 
-  tint::Program program(std::move(b));
-  ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
-  auto bindings = GenerateExternalTextureBindings(&program);
-  ASSERT_EQ(bindings.size(), 2u);
+    tint::Program program(std::move(b));
+    ASSERT_TRUE(program.IsValid()) << program.Diagnostics().str();
+    auto bindings = GenerateExternalTextureBindings(&program);
+    ASSERT_EQ(bindings.size(), 2u);
 
-  auto to0 = bindings[transform::BindingPoint{0, 1}];
-  ASSERT_EQ(to0.plane_1.group, 0u);
-  ASSERT_EQ(to0.params.group, 0u);
-  ASSERT_EQ(to0.plane_1.binding, 5u);
-  ASSERT_EQ(to0.params.binding, 6u);
+    auto to0 = bindings[transform::BindingPoint{0, 1}];
+    ASSERT_EQ(to0.plane_1.group, 0u);
+    ASSERT_EQ(to0.params.group, 0u);
+    ASSERT_EQ(to0.plane_1.binding, 5u);
+    ASSERT_EQ(to0.params.binding, 6u);
 
-  auto to1 = bindings[transform::BindingPoint{0, 3}];
-  ASSERT_EQ(to1.plane_1.group, 0u);
-  ASSERT_EQ(to1.params.group, 0u);
-  ASSERT_EQ(to1.plane_1.binding, 7u);
-  ASSERT_EQ(to1.params.binding, 8u);
+    auto to1 = bindings[transform::BindingPoint{0, 3}];
+    ASSERT_EQ(to1.plane_1.group, 0u);
+    ASSERT_EQ(to1.params.group, 0u);
+    ASSERT_EQ(to1.plane_1.binding, 7u);
+    ASSERT_EQ(to1.params.binding, 8u);
 }
 
 }  // namespace
diff --git a/src/tint/writer/glsl/generator.cc b/src/tint/writer/glsl/generator.cc
index 83ae8c4..4b6da68 100644
--- a/src/tint/writer/glsl/generator.cc
+++ b/src/tint/writer/glsl/generator.cc
@@ -28,35 +28,32 @@
 Result::~Result() = default;
 Result::Result(const Result&) = default;
 
-Result Generate(const Program* program,
-                const Options& options,
-                const std::string& entry_point) {
-  Result result;
+Result Generate(const Program* program, const Options& options, const std::string& entry_point) {
+    Result result;
 
-  // Sanitize the program.
-  auto sanitized_result = Sanitize(program, options, entry_point);
-  if (!sanitized_result.program.IsValid()) {
-    result.success = false;
-    result.error = sanitized_result.program.Diagnostics().str();
-    return result;
-  }
-
-  // Generate the GLSL code.
-  auto impl = std::make_unique<GeneratorImpl>(&sanitized_result.program,
-                                              options.version);
-  result.success = impl->Generate();
-  result.error = impl->error();
-  result.glsl = impl->result();
-
-  // Collect the list of entry points in the sanitized program.
-  for (auto* func : sanitized_result.program.AST().Functions()) {
-    if (func->IsEntryPoint()) {
-      auto name = sanitized_result.program.Symbols().NameFor(func->symbol);
-      result.entry_points.push_back({name, func->PipelineStage()});
+    // Sanitize the program.
+    auto sanitized_result = Sanitize(program, options, entry_point);
+    if (!sanitized_result.program.IsValid()) {
+        result.success = false;
+        result.error = sanitized_result.program.Diagnostics().str();
+        return result;
     }
-  }
 
-  return result;
+    // Generate the GLSL code.
+    auto impl = std::make_unique<GeneratorImpl>(&sanitized_result.program, options.version);
+    result.success = impl->Generate();
+    result.error = impl->error();
+    result.glsl = impl->result();
+
+    // Collect the list of entry points in the sanitized program.
+    for (auto* func : sanitized_result.program.AST().Functions()) {
+        if (func->IsEntryPoint()) {
+            auto name = sanitized_result.program.Symbols().NameFor(func->symbol);
+            result.entry_points.push_back({name, func->PipelineStage()});
+        }
+    }
+
+    return result;
 }
 
 }  // namespace tint::writer::glsl
diff --git a/src/tint/writer/glsl/generator.h b/src/tint/writer/glsl/generator.h
index 11206cf..77a7f4b 100644
--- a/src/tint/writer/glsl/generator.h
+++ b/src/tint/writer/glsl/generator.h
@@ -42,66 +42,66 @@
 
 /// Configuration options used for generating GLSL.
 struct Options {
-  /// Constructor
-  Options();
+    /// Constructor
+    Options();
 
-  /// Destructor
-  ~Options();
+    /// Destructor
+    ~Options();
 
-  /// Copy constructor
-  Options(const Options&);
+    /// Copy constructor
+    Options(const Options&);
 
-  /// A map of SamplerTexturePair to combined sampler names for the
-  /// CombineSamplers transform
-  BindingMap binding_map;
+    /// A map of SamplerTexturePair to combined sampler names for the
+    /// CombineSamplers transform
+    BindingMap binding_map;
 
-  /// The binding point to use for placeholder samplers.
-  sem::BindingPoint placeholder_binding_point;
+    /// The binding point to use for placeholder samplers.
+    sem::BindingPoint placeholder_binding_point;
 
-  /// A map of old binding point to new binding point for the BindingRemapper
-  /// transform
-  std::unordered_map<sem::BindingPoint, sem::BindingPoint> binding_points;
+    /// A map of old binding point to new binding point for the BindingRemapper
+    /// transform
+    std::unordered_map<sem::BindingPoint, sem::BindingPoint> binding_points;
 
-  /// A map of old binding point to new access control for the BindingRemapper
-  /// transform
-  std::unordered_map<sem::BindingPoint, ast::Access> access_controls;
+    /// A map of old binding point to new access control for the BindingRemapper
+    /// transform
+    std::unordered_map<sem::BindingPoint, ast::Access> access_controls;
 
-  /// If true, then validation will be disabled for binding point collisions
-  /// generated by the BindingRemapper transform
-  bool allow_collisions = false;
+    /// If true, then validation will be disabled for binding point collisions
+    /// generated by the BindingRemapper transform
+    bool allow_collisions = false;
 
-  /// Set to `true` to disable workgroup memory zero initialization
-  bool disable_workgroup_init = false;
+    /// Set to `true` to disable workgroup memory zero initialization
+    bool disable_workgroup_init = false;
 
-  /// Set to 'true' to generates binding mappings for external textures
-  bool generate_external_texture_bindings = false;
+    /// Set to 'true' to generates binding mappings for external textures
+    bool generate_external_texture_bindings = false;
 
-  /// The GLSL version to emit
-  Version version;
+    /// The GLSL version to emit
+    Version version;
 };
 
 /// The result produced when generating GLSL.
 struct Result {
-  /// Constructor
-  Result();
+    /// Constructor
+    Result();
 
-  /// Destructor
-  ~Result();
+    /// Destructor
+    ~Result();
 
-  /// Copy constructor
-  Result(const Result&);
+    /// Copy constructor
+    Result(const Result&);
 
-  /// True if generation was successful.
-  bool success = false;
+    /// True if generation was successful.
+    bool success = false;
 
-  /// The errors generated during code generation, if any.
-  std::string error;
+    /// The errors generated during code generation, if any.
+    std::string error;
 
-  /// The generated GLSL.
-  std::string glsl = "";
+    /// The generated GLSL.
+    std::string glsl = "";
 
-  /// The list of entry points in the generated GLSL.
-  std::vector<std::pair<std::string, ast::PipelineStage>> entry_points;
+    /// The list of entry points in the generated GLSL.
+    std::vector<std::pair<std::string, ast::PipelineStage>> entry_points;
 };
 
 /// Generate GLSL for a program, according to a set of configuration options.
@@ -111,9 +111,7 @@
 /// @param options the configuration options to use when generating GLSL
 /// @param entry_point the entry point to generate GLSL for
 /// @returns the resulting GLSL and supplementary information
-Result Generate(const Program* program,
-                const Options& options,
-                const std::string& entry_point);
+Result Generate(const Program* program, const Options& options, const std::string& entry_point);
 
 }  // namespace tint::writer::glsl
 
diff --git a/src/tint/writer/glsl/generator_bench.cc b/src/tint/writer/glsl/generator_bench.cc
index ad87073..dddb303 100644
--- a/src/tint/writer/glsl/generator_bench.cc
+++ b/src/tint/writer/glsl/generator_bench.cc
@@ -21,27 +21,27 @@
 namespace {
 
 void GenerateGLSL(benchmark::State& state, std::string input_name) {
-  auto res = bench::LoadProgram(input_name);
-  if (auto err = std::get_if<bench::Error>(&res)) {
-    state.SkipWithError(err->msg.c_str());
-    return;
-  }
-  auto& program = std::get<bench::ProgramAndFile>(res).program;
-  std::vector<std::string> entry_points;
-  for (auto& fn : program.AST().Functions()) {
-    if (fn->IsEntryPoint()) {
-      entry_points.emplace_back(program.Symbols().NameFor(fn->symbol));
+    auto res = bench::LoadProgram(input_name);
+    if (auto err = std::get_if<bench::Error>(&res)) {
+        state.SkipWithError(err->msg.c_str());
+        return;
     }
-  }
+    auto& program = std::get<bench::ProgramAndFile>(res).program;
+    std::vector<std::string> entry_points;
+    for (auto& fn : program.AST().Functions()) {
+        if (fn->IsEntryPoint()) {
+            entry_points.emplace_back(program.Symbols().NameFor(fn->symbol));
+        }
+    }
 
-  for (auto _ : state) {
-    for (auto& ep : entry_points) {
-      auto res = Generate(&program, {}, ep);
-      if (!res.error.empty()) {
-        state.SkipWithError(res.error.c_str());
-      }
+    for (auto _ : state) {
+        for (auto& ep : entry_points) {
+            auto res = Generate(&program, {}, ep);
+            if (!res.error.empty()) {
+                state.SkipWithError(res.error.c_str());
+            }
+        }
     }
-  }
 }
 
 TINT_BENCHMARK_WGSL_PROGRAMS(GenerateGLSL);
diff --git a/src/tint/writer/glsl/generator_impl.cc b/src/tint/writer/glsl/generator_impl.cc
index ef7467d..29451e7 100644
--- a/src/tint/writer/glsl/generator_impl.cc
+++ b/src/tint/writer/glsl/generator_impl.cc
@@ -29,18 +29,18 @@
 #include "src/tint/ast/variable_decl_statement.h"
 #include "src/tint/debug.h"
 #include "src/tint/sem/array.h"
-#include "src/tint/sem/atomic_type.h"
+#include "src/tint/sem/atomic.h"
 #include "src/tint/sem/block_statement.h"
 #include "src/tint/sem/call.h"
-#include "src/tint/sem/depth_multisampled_texture_type.h"
-#include "src/tint/sem/depth_texture_type.h"
+#include "src/tint/sem/depth_multisampled_texture.h"
+#include "src/tint/sem/depth_texture.h"
 #include "src/tint/sem/function.h"
 #include "src/tint/sem/member_accessor_expression.h"
 #include "src/tint/sem/module.h"
-#include "src/tint/sem/multisampled_texture_type.h"
-#include "src/tint/sem/sampled_texture_type.h"
+#include "src/tint/sem/multisampled_texture.h"
+#include "src/tint/sem/sampled_texture.h"
 #include "src/tint/sem/statement.h"
-#include "src/tint/sem/storage_texture_type.h"
+#include "src/tint/sem/storage_texture.h"
 #include "src/tint/sem/struct.h"
 #include "src/tint/sem/type_constructor.h"
 #include "src/tint/sem/type_conversion.h"
@@ -75,22 +75,20 @@
 namespace {
 
 bool IsRelational(tint::ast::BinaryOp op) {
-  return op == tint::ast::BinaryOp::kEqual ||
-         op == tint::ast::BinaryOp::kNotEqual ||
-         op == tint::ast::BinaryOp::kLessThan ||
-         op == tint::ast::BinaryOp::kGreaterThan ||
-         op == tint::ast::BinaryOp::kLessThanEqual ||
-         op == tint::ast::BinaryOp::kGreaterThanEqual;
+    return op == tint::ast::BinaryOp::kEqual || op == tint::ast::BinaryOp::kNotEqual ||
+           op == tint::ast::BinaryOp::kLessThan || op == tint::ast::BinaryOp::kGreaterThan ||
+           op == tint::ast::BinaryOp::kLessThanEqual ||
+           op == tint::ast::BinaryOp::kGreaterThanEqual;
 }
 
 bool RequiresOESSampleVariables(tint::ast::Builtin builtin) {
-  switch (builtin) {
-    case tint::ast::Builtin::kSampleIndex:
-    case tint::ast::Builtin::kSampleMask:
-      return true;
-    default:
-      return false;
-  }
+    switch (builtin) {
+        case tint::ast::Builtin::kSampleIndex:
+        case tint::ast::Builtin::kSampleMask:
+            return true;
+        default:
+            return false;
+    }
 }
 
 }  // namespace
@@ -102,47 +100,47 @@
 const char kSpecConstantPrefix[] = "WGSL_SPEC_CONSTANT_";
 
 bool last_is_break_or_fallthrough(const ast::BlockStatement* stmts) {
-  return IsAnyOf<ast::BreakStatement, ast::FallthroughStatement>(stmts->Last());
+    return IsAnyOf<ast::BreakStatement, ast::FallthroughStatement>(stmts->Last());
 }
 
 const char* convert_texel_format_to_glsl(const ast::TexelFormat format) {
-  switch (format) {
-    case ast::TexelFormat::kR32Uint:
-      return "r32ui";
-    case ast::TexelFormat::kR32Sint:
-      return "r32i";
-    case ast::TexelFormat::kR32Float:
-      return "r32f";
-    case ast::TexelFormat::kRgba8Unorm:
-      return "rgba8";
-    case ast::TexelFormat::kRgba8Snorm:
-      return "rgba8_snorm";
-    case ast::TexelFormat::kRgba8Uint:
-      return "rgba8ui";
-    case ast::TexelFormat::kRgba8Sint:
-      return "rgba8i";
-    case ast::TexelFormat::kRg32Uint:
-      return "rg32ui";
-    case ast::TexelFormat::kRg32Sint:
-      return "rg32i";
-    case ast::TexelFormat::kRg32Float:
-      return "rg32f";
-    case ast::TexelFormat::kRgba16Uint:
-      return "rgba16ui";
-    case ast::TexelFormat::kRgba16Sint:
-      return "rgba16i";
-    case ast::TexelFormat::kRgba16Float:
-      return "rgba16f";
-    case ast::TexelFormat::kRgba32Uint:
-      return "rgba32ui";
-    case ast::TexelFormat::kRgba32Sint:
-      return "rgba32i";
-    case ast::TexelFormat::kRgba32Float:
-      return "rgba32f";
-    case ast::TexelFormat::kNone:
-      return "unknown";
-  }
-  return "unknown";
+    switch (format) {
+        case ast::TexelFormat::kR32Uint:
+            return "r32ui";
+        case ast::TexelFormat::kR32Sint:
+            return "r32i";
+        case ast::TexelFormat::kR32Float:
+            return "r32f";
+        case ast::TexelFormat::kRgba8Unorm:
+            return "rgba8";
+        case ast::TexelFormat::kRgba8Snorm:
+            return "rgba8_snorm";
+        case ast::TexelFormat::kRgba8Uint:
+            return "rgba8ui";
+        case ast::TexelFormat::kRgba8Sint:
+            return "rgba8i";
+        case ast::TexelFormat::kRg32Uint:
+            return "rg32ui";
+        case ast::TexelFormat::kRg32Sint:
+            return "rg32i";
+        case ast::TexelFormat::kRg32Float:
+            return "rg32f";
+        case ast::TexelFormat::kRgba16Uint:
+            return "rgba16ui";
+        case ast::TexelFormat::kRgba16Sint:
+            return "rgba16i";
+        case ast::TexelFormat::kRgba16Float:
+            return "rgba16f";
+        case ast::TexelFormat::kRgba32Uint:
+            return "rgba32ui";
+        case ast::TexelFormat::kRgba32Sint:
+            return "rgba32i";
+        case ast::TexelFormat::kRgba32Float:
+            return "rgba32f";
+        case ast::TexelFormat::kNone:
+            return "unknown";
+    }
+    return "unknown";
 }
 
 }  // namespace
@@ -154,77 +152,73 @@
 SanitizedResult Sanitize(const Program* in,
                          const Options& options,
                          const std::string& entry_point) {
-  transform::Manager manager;
-  transform::DataMap data;
+    transform::Manager manager;
+    transform::DataMap data;
 
-  {  // Builtin polyfills
-    transform::BuiltinPolyfill::Builtins polyfills;
-    polyfills.count_leading_zeros = true;
-    polyfills.count_trailing_zeros = true;
-    polyfills.extract_bits =
-        transform::BuiltinPolyfill::Level::kClampParameters;
-    polyfills.first_leading_bit = true;
-    polyfills.first_trailing_bit = true;
-    polyfills.insert_bits = transform::BuiltinPolyfill::Level::kClampParameters;
-    data.Add<transform::BuiltinPolyfill::Config>(polyfills);
-    manager.Add<transform::BuiltinPolyfill>();
-  }
+    {  // Builtin polyfills
+        transform::BuiltinPolyfill::Builtins polyfills;
+        polyfills.count_leading_zeros = true;
+        polyfills.count_trailing_zeros = true;
+        polyfills.extract_bits = transform::BuiltinPolyfill::Level::kClampParameters;
+        polyfills.first_leading_bit = true;
+        polyfills.first_trailing_bit = true;
+        polyfills.insert_bits = transform::BuiltinPolyfill::Level::kClampParameters;
+        data.Add<transform::BuiltinPolyfill::Config>(polyfills);
+        manager.Add<transform::BuiltinPolyfill>();
+    }
 
-  if (!entry_point.empty()) {
-    manager.Add<transform::SingleEntryPoint>();
-    data.Add<transform::SingleEntryPoint::Config>(entry_point);
-  }
-  manager.Add<transform::Renamer>();
-  data.Add<transform::Renamer::Config>(
-      transform::Renamer::Target::kGlslKeywords,
-      /* preserve_unicode */ false);
-  manager.Add<transform::Unshadow>();
+    if (!entry_point.empty()) {
+        manager.Add<transform::SingleEntryPoint>();
+        data.Add<transform::SingleEntryPoint::Config>(entry_point);
+    }
+    manager.Add<transform::Renamer>();
+    data.Add<transform::Renamer::Config>(transform::Renamer::Target::kGlslKeywords,
+                                         /* preserve_unicode */ false);
+    manager.Add<transform::Unshadow>();
 
-  // Attempt to convert `loop`s into for-loops. This is to try and massage the
-  // output into something that will not cause FXC to choke or misbehave.
-  manager.Add<transform::FoldTrivialSingleUseLets>();
-  manager.Add<transform::LoopToForLoop>();
+    // Attempt to convert `loop`s into for-loops. This is to try and massage the
+    // output into something that will not cause FXC to choke or misbehave.
+    manager.Add<transform::FoldTrivialSingleUseLets>();
+    manager.Add<transform::LoopToForLoop>();
 
-  if (!options.disable_workgroup_init) {
-    // ZeroInitWorkgroupMemory must come before CanonicalizeEntryPointIO as
-    // ZeroInitWorkgroupMemory may inject new builtin parameters.
-    manager.Add<transform::ZeroInitWorkgroupMemory>();
-  }
-  manager.Add<transform::CanonicalizeEntryPointIO>();
-  manager.Add<transform::ExpandCompoundAssignment>();
-  manager.Add<transform::PromoteSideEffectsToDecl>();
-  manager.Add<transform::UnwindDiscardFunctions>();
-  manager.Add<transform::SimplifyPointers>();
+    if (!options.disable_workgroup_init) {
+        // ZeroInitWorkgroupMemory must come before CanonicalizeEntryPointIO as
+        // ZeroInitWorkgroupMemory may inject new builtin parameters.
+        manager.Add<transform::ZeroInitWorkgroupMemory>();
+    }
+    manager.Add<transform::CanonicalizeEntryPointIO>();
+    manager.Add<transform::ExpandCompoundAssignment>();
+    manager.Add<transform::PromoteSideEffectsToDecl>();
+    manager.Add<transform::UnwindDiscardFunctions>();
+    manager.Add<transform::SimplifyPointers>();
 
-  manager.Add<transform::RemovePhonies>();
+    manager.Add<transform::RemovePhonies>();
 
-  if (options.generate_external_texture_bindings) {
-    auto new_bindings_map = writer::GenerateExternalTextureBindings(in);
-    data.Add<transform::MultiplanarExternalTexture::NewBindingPoints>(
-        new_bindings_map);
-  }
-  manager.Add<transform::MultiplanarExternalTexture>();
+    if (options.generate_external_texture_bindings) {
+        auto new_bindings_map = writer::GenerateExternalTextureBindings(in);
+        data.Add<transform::MultiplanarExternalTexture::NewBindingPoints>(new_bindings_map);
+    }
+    manager.Add<transform::MultiplanarExternalTexture>();
 
-  data.Add<transform::CombineSamplers::BindingInfo>(
-      options.binding_map, options.placeholder_binding_point);
-  manager.Add<transform::CombineSamplers>();
+    data.Add<transform::CombineSamplers::BindingInfo>(options.binding_map,
+                                                      options.placeholder_binding_point);
+    manager.Add<transform::CombineSamplers>();
 
-  data.Add<transform::BindingRemapper::Remappings>(options.binding_points,
-                                                   options.access_controls,
-                                                   options.allow_collisions);
-  manager.Add<transform::BindingRemapper>();
+    data.Add<transform::BindingRemapper::Remappings>(
+        options.binding_points, options.access_controls, options.allow_collisions);
+    manager.Add<transform::BindingRemapper>();
 
-  manager.Add<transform::PromoteInitializersToConstVar>();
-  manager.Add<transform::AddEmptyEntryPoint>();
-  manager.Add<transform::AddSpirvBlockAttribute>();
-  data.Add<transform::CanonicalizeEntryPointIO::Config>(
-      transform::CanonicalizeEntryPointIO::ShaderStyle::kGlsl);
+    manager.Add<transform::PromoteInitializersToConstVar>();
+    manager.Add<transform::AddEmptyEntryPoint>();
+    manager.Add<transform::AddSpirvBlockAttribute>();
+    data.Add<transform::CanonicalizeEntryPointIO::Config>(
+        transform::CanonicalizeEntryPointIO::ShaderStyle::kGlsl);
 
-  auto out = manager.Run(in, data);
+    auto out = manager.Run(in, data);
 
-  SanitizedResult result;
-  result.program = std::move(out.program);
-  return result;
+    SanitizedResult result;
+    result.program = std::move(out.program);
+    return result;
 }
 
 GeneratorImpl::GeneratorImpl(const Program* program, const Version& version)
@@ -233,2339 +227,2283 @@
 GeneratorImpl::~GeneratorImpl() = default;
 
 bool GeneratorImpl::Generate() {
-  {
-    auto out = line();
-    out << "#version " << version_.major_version << version_.minor_version
-        << "0";
-    if (version_.IsES()) {
-      out << " es";
-    }
-  }
-
-  auto helpers_insertion_point = current_buffer_->lines.size();
-
-  line();
-
-  auto* mod = builder_.Sem().Module();
-  for (auto* decl : mod->DependencyOrderedDeclarations()) {
-    if (decl->Is<ast::Alias>()) {
-      continue;  // Ignore aliases.
+    {
+        auto out = line();
+        out << "#version " << version_.major_version << version_.minor_version << "0";
+        if (version_.IsES()) {
+            out << " es";
+        }
     }
 
-    if (auto* global = decl->As<ast::Variable>()) {
-      if (!EmitGlobalVariable(global)) {
+    auto helpers_insertion_point = current_buffer_->lines.size();
+
+    line();
+
+    auto* mod = builder_.Sem().Module();
+    for (auto* decl : mod->DependencyOrderedDeclarations()) {
+        if (decl->Is<ast::Alias>()) {
+            continue;  // Ignore aliases.
+        }
+
+        if (auto* global = decl->As<ast::Variable>()) {
+            if (!EmitGlobalVariable(global)) {
+                return false;
+            }
+        } else if (auto* str = decl->As<ast::Struct>()) {
+            // Skip emission if the struct contains a runtime-sized array, since its
+            // only use will be as the store-type of a buffer and we emit those
+            // elsewhere.
+            // TODO(crbug.com/tint/1339): We could also avoid emitting any other
+            // struct that is only used as a buffer store type.
+            const sem::Struct* sem_str = builder_.Sem().Get(str);
+            const auto& members = sem_str->Members();
+            TINT_ASSERT(Writer, members.size() > 0);
+            auto* last_member = members[members.size() - 1];
+            auto* arr = last_member->Type()->As<sem::Array>();
+            if (!arr || !arr->IsRuntimeSized()) {
+                if (!EmitStructType(current_buffer_, sem_str)) {
+                    return false;
+                }
+            }
+        } else if (auto* func = decl->As<ast::Function>()) {
+            if (func->IsEntryPoint()) {
+                if (!EmitEntryPointFunction(func)) {
+                    return false;
+                }
+            } else {
+                if (!EmitFunction(func)) {
+                    return false;
+                }
+            }
+        } else if (auto* ext = decl->As<ast::Enable>()) {
+            // Record the required extension for generating extension directive later
+            if (!RecordExtension(ext)) {
+                return false;
+            }
+        } else {
+            TINT_ICE(Writer, diagnostics_)
+                << "unhandled module-scope declaration: " << decl->TypeInfo().name;
+            return false;
+        }
+    }
+
+    TextBuffer extensions;
+
+    if (version_.IsES() && requires_oes_sample_variables_) {
+        extensions.Append("#extension GL_OES_sample_variables : require");
+    }
+
+    auto indent = current_buffer_->current_indent;
+
+    if (!extensions.lines.empty()) {
+        current_buffer_->Insert(extensions, helpers_insertion_point, indent);
+        helpers_insertion_point += extensions.lines.size();
+    }
+
+    if (version_.IsES() && requires_default_precision_qualifier_) {
+        current_buffer_->Insert("precision mediump float;", helpers_insertion_point++, indent);
+    }
+
+    if (!helpers_.lines.empty()) {
+        current_buffer_->Insert("", helpers_insertion_point++, indent);
+        current_buffer_->Insert(helpers_, helpers_insertion_point, indent);
+        helpers_insertion_point += helpers_.lines.size();
+    }
+
+    return true;
+}
+
+bool GeneratorImpl::RecordExtension(const ast::Enable*) {
+    /*
+    Deal with extension node here, recording it within the generator for
+    later emition.
+    For example:
+    ```
+      if (ext->kind == ast::Enable::ExtensionKind::kF16) {
+      require_fp16_ = true;
+      }
+    ```
+    */
+
+    return true;
+}
+
+bool GeneratorImpl::EmitIndexAccessor(std::ostream& out, const ast::IndexAccessorExpression* expr) {
+    if (!EmitExpression(out, expr->object)) {
         return false;
-      }
-    } else if (auto* str = decl->As<ast::Struct>()) {
-      // Skip emission if the struct contains a runtime-sized array, since its
-      // only use will be as the store-type of a buffer and we emit those
-      // elsewhere.
-      // TODO(crbug.com/tint/1339): We could also avoid emitting any other
-      // struct that is only used as a buffer store type.
-      const sem::Struct* sem_str = builder_.Sem().Get(str);
-      const auto& members = sem_str->Members();
-      TINT_ASSERT(Writer, members.size() > 0);
-      auto* last_member = members[members.size() - 1];
-      auto* arr = last_member->Type()->As<sem::Array>();
-      if (!arr || !arr->IsRuntimeSized()) {
-        if (!EmitStructType(current_buffer_, sem_str)) {
-          return false;
-        }
-      }
-    } else if (auto* func = decl->As<ast::Function>()) {
-      if (func->IsEntryPoint()) {
-        if (!EmitEntryPointFunction(func)) {
-          return false;
-        }
-      } else {
-        if (!EmitFunction(func)) {
-          return false;
-        }
-      }
+    }
+    out << "[";
+
+    if (!EmitExpression(out, expr->index)) {
+        return false;
+    }
+    out << "]";
+
+    return true;
+}
+
+bool GeneratorImpl::EmitBitcast(std::ostream& out, const ast::BitcastExpression* expr) {
+    auto* src_type = TypeOf(expr->expr)->UnwrapRef();
+    auto* dst_type = TypeOf(expr)->UnwrapRef();
+
+    if (!dst_type->is_integer_scalar_or_vector() && !dst_type->is_float_scalar_or_vector()) {
+        diagnostics_.add_error(
+            diag::System::Writer,
+            "Unable to do bitcast to type " + dst_type->FriendlyName(builder_.Symbols()));
+        return false;
+    }
+
+    if (src_type == dst_type) {
+        return EmitExpression(out, expr->expr);
+    }
+
+    if (src_type->is_float_scalar_or_vector() && dst_type->is_signed_scalar_or_vector()) {
+        out << "floatBitsToInt";
+    } else if (src_type->is_float_scalar_or_vector() && dst_type->is_unsigned_scalar_or_vector()) {
+        out << "floatBitsToUint";
+    } else if (src_type->is_signed_scalar_or_vector() && dst_type->is_float_scalar_or_vector()) {
+        out << "intBitsToFloat";
+    } else if (src_type->is_unsigned_scalar_or_vector() && dst_type->is_float_scalar_or_vector()) {
+        out << "uintBitsToFloat";
     } else {
-      TINT_ICE(Writer, diagnostics_)
-          << "unhandled module-scope declaration: " << decl->TypeInfo().name;
-      return false;
+        if (!EmitType(out, dst_type, ast::StorageClass::kNone, ast::Access::kReadWrite, "")) {
+            return false;
+        }
     }
-  }
-
-  TextBuffer extensions;
-
-  if (version_.IsES() && requires_oes_sample_variables_) {
-    extensions.Append("#extension GL_OES_sample_variables : require");
-  }
-
-  auto indent = current_buffer_->current_indent;
-
-  if (!extensions.lines.empty()) {
-    current_buffer_->Insert(extensions, helpers_insertion_point, indent);
-    helpers_insertion_point += extensions.lines.size();
-  }
-
-  if (version_.IsES() && requires_default_precision_qualifier_) {
-    current_buffer_->Insert("precision mediump float;",
-                            helpers_insertion_point++, indent);
-  }
-
-  if (!helpers_.lines.empty()) {
-    current_buffer_->Insert("", helpers_insertion_point++, indent);
-    current_buffer_->Insert(helpers_, helpers_insertion_point, indent);
-    helpers_insertion_point += helpers_.lines.size();
-  }
-
-  return true;
-}
-
-bool GeneratorImpl::EmitIndexAccessor(
-    std::ostream& out,
-    const ast::IndexAccessorExpression* expr) {
-  if (!EmitExpression(out, expr->object)) {
-    return false;
-  }
-  out << "[";
-
-  if (!EmitExpression(out, expr->index)) {
-    return false;
-  }
-  out << "]";
-
-  return true;
-}
-
-bool GeneratorImpl::EmitBitcast(std::ostream& out,
-                                const ast::BitcastExpression* expr) {
-  auto* src_type = TypeOf(expr->expr)->UnwrapRef();
-  auto* dst_type = TypeOf(expr)->UnwrapRef();
-
-  if (!dst_type->is_integer_scalar_or_vector() &&
-      !dst_type->is_float_scalar_or_vector()) {
-    diagnostics_.add_error(diag::System::Writer,
-                           "Unable to do bitcast to type " +
-                               dst_type->FriendlyName(builder_.Symbols()));
-    return false;
-  }
-
-  if (src_type == dst_type) {
-    return EmitExpression(out, expr->expr);
-  }
-
-  if (src_type->is_float_scalar_or_vector() &&
-      dst_type->is_signed_scalar_or_vector()) {
-    out << "floatBitsToInt";
-  } else if (src_type->is_float_scalar_or_vector() &&
-             dst_type->is_unsigned_scalar_or_vector()) {
-    out << "floatBitsToUint";
-  } else if (src_type->is_signed_scalar_or_vector() &&
-             dst_type->is_float_scalar_or_vector()) {
-    out << "intBitsToFloat";
-  } else if (src_type->is_unsigned_scalar_or_vector() &&
-             dst_type->is_float_scalar_or_vector()) {
-    out << "uintBitsToFloat";
-  } else {
-    if (!EmitType(out, dst_type, ast::StorageClass::kNone,
-                  ast::Access::kReadWrite, "")) {
-      return false;
+    out << "(";
+    if (!EmitExpression(out, expr->expr)) {
+        return false;
     }
-  }
-  out << "(";
-  if (!EmitExpression(out, expr->expr)) {
-    return false;
-  }
-  out << ")";
-  return true;
+    out << ")";
+    return true;
 }
 
 bool GeneratorImpl::EmitAssign(const ast::AssignmentStatement* stmt) {
-  auto out = line();
-  if (!EmitExpression(out, stmt->lhs)) {
-    return false;
-  }
-  out << " = ";
-  if (!EmitExpression(out, stmt->rhs)) {
-    return false;
-  }
-  out << ";";
-  return true;
+    auto out = line();
+    if (!EmitExpression(out, stmt->lhs)) {
+        return false;
+    }
+    out << " = ";
+    if (!EmitExpression(out, stmt->rhs)) {
+        return false;
+    }
+    out << ";";
+    return true;
 }
 
-bool GeneratorImpl::EmitVectorRelational(std::ostream& out,
-                                         const ast::BinaryExpression* expr) {
-  switch (expr->op) {
-    case ast::BinaryOp::kEqual:
-      out << "equal";
-      break;
-    case ast::BinaryOp::kNotEqual:
-      out << "notEqual";
-      break;
-    case ast::BinaryOp::kLessThan:
-      out << "lessThan";
-      break;
-    case ast::BinaryOp::kGreaterThan:
-      out << "greaterThan";
-      break;
-    case ast::BinaryOp::kLessThanEqual:
-      out << "lessThanEqual";
-      break;
-    case ast::BinaryOp::kGreaterThanEqual:
-      out << "greaterThanEqual";
-      break;
-    default:
-      break;
-  }
-  out << "(";
-  if (!EmitExpression(out, expr->lhs)) {
-    return false;
-  }
-  out << ", ";
-  if (!EmitExpression(out, expr->rhs)) {
-    return false;
-  }
-  out << ")";
-  return true;
-}
-
-bool GeneratorImpl::EmitBitwiseBoolOp(std::ostream& out,
-                                      const ast::BinaryExpression* expr) {
-  auto* bool_type = TypeOf(expr->lhs)->UnwrapRef();
-  auto* uint_type = BoolTypeToUint(bool_type);
-
-  // Cast result to bool scalar or vector type.
-  if (!EmitType(out, bool_type, ast::StorageClass::kNone,
-                ast::Access::kReadWrite, "")) {
-    return false;
-  }
-  ScopedParen outerCastParen(out);
-  // Cast LHS to uint scalar or vector type.
-  if (!EmitType(out, uint_type, ast::StorageClass::kNone,
-                ast::Access::kReadWrite, "")) {
-    return false;
-  }
-  {
-    ScopedParen innerCastParen(out);
-    // Emit LHS.
+bool GeneratorImpl::EmitVectorRelational(std::ostream& out, const ast::BinaryExpression* expr) {
+    switch (expr->op) {
+        case ast::BinaryOp::kEqual:
+            out << "equal";
+            break;
+        case ast::BinaryOp::kNotEqual:
+            out << "notEqual";
+            break;
+        case ast::BinaryOp::kLessThan:
+            out << "lessThan";
+            break;
+        case ast::BinaryOp::kGreaterThan:
+            out << "greaterThan";
+            break;
+        case ast::BinaryOp::kLessThanEqual:
+            out << "lessThanEqual";
+            break;
+        case ast::BinaryOp::kGreaterThanEqual:
+            out << "greaterThanEqual";
+            break;
+        default:
+            break;
+    }
+    out << "(";
     if (!EmitExpression(out, expr->lhs)) {
-      return false;
-    }
-  }
-  // Emit operator.
-  if (expr->op == ast::BinaryOp::kAnd) {
-    out << " & ";
-  } else if (expr->op == ast::BinaryOp::kOr) {
-    out << " | ";
-  } else {
-    TINT_ICE(Writer, diagnostics_)
-        << "unexpected binary op: " << FriendlyName(expr->op);
-    return false;
-  }
-  // Cast RHS to uint scalar or vector type.
-  if (!EmitType(out, uint_type, ast::StorageClass::kNone,
-                ast::Access::kReadWrite, "")) {
-    return false;
-  }
-  {
-    ScopedParen innerCastParen(out);
-    // Emit RHS.
-    if (!EmitExpression(out, expr->rhs)) {
-      return false;
-    }
-  }
-  return true;
-}
-
-bool GeneratorImpl::EmitFloatModulo(std::ostream& out,
-                                    const ast::BinaryExpression* expr) {
-  std::string fn;
-  auto* ret_ty = TypeOf(expr)->UnwrapRef();
-  fn = utils::GetOrCreate(float_modulo_funcs_, ret_ty, [&]() -> std::string {
-    TextBuffer b;
-    TINT_DEFER(helpers_.Append(b));
-
-    auto fn_name = UniqueIdentifier("tint_float_modulo");
-    std::vector<std::string> parameter_names;
-    {
-      auto decl = line(&b);
-      if (!EmitTypeAndName(decl, ret_ty, ast::StorageClass::kNone,
-                           ast::Access::kUndefined, fn_name)) {
-        return "";
-      }
-      {
-        ScopedParen sp(decl);
-        const auto* ty = TypeOf(expr->lhs)->UnwrapRef();
-        if (!EmitTypeAndName(decl, ty, ast::StorageClass::kNone,
-                             ast::Access::kUndefined, "lhs")) {
-          return "";
-        }
-        decl << ", ";
-        ty = TypeOf(expr->rhs)->UnwrapRef();
-        if (!EmitTypeAndName(decl, ty, ast::StorageClass::kNone,
-                             ast::Access::kUndefined, "rhs")) {
-          return "";
-        }
-      }
-      decl << " {";
-    }
-    {
-      ScopedIndent si(&b);
-      line(&b) << "return (lhs - rhs * trunc(lhs / rhs));";
-    }
-    line(&b) << "}";
-    line(&b);
-    return fn_name;
-  });
-
-  if (fn.empty()) {
-    return false;
-  }
-
-  // Call the helper
-  out << fn;
-  {
-    ScopedParen sp(out);
-    if (!EmitExpression(out, expr->lhs)) {
-      return false;
+        return false;
     }
     out << ", ";
     if (!EmitExpression(out, expr->rhs)) {
-      return false;
+        return false;
     }
-  }
-  return true;
+    out << ")";
+    return true;
 }
 
-bool GeneratorImpl::EmitBinary(std::ostream& out,
-                               const ast::BinaryExpression* expr) {
-  if (IsRelational(expr->op) && !TypeOf(expr->lhs)->UnwrapRef()->is_scalar()) {
-    return EmitVectorRelational(out, expr);
-  }
-  if (expr->op == ast::BinaryOp::kLogicalAnd ||
-      expr->op == ast::BinaryOp::kLogicalOr) {
-    auto name = UniqueIdentifier(kTempNamePrefix);
+bool GeneratorImpl::EmitBitwiseBoolOp(std::ostream& out, const ast::BinaryExpression* expr) {
+    auto* bool_type = TypeOf(expr->lhs)->UnwrapRef();
+    auto* uint_type = BoolTypeToUint(bool_type);
 
-    {
-      auto pre = line();
-      pre << "bool " << name << " = ";
-      if (!EmitExpression(pre, expr->lhs)) {
+    // Cast result to bool scalar or vector type.
+    if (!EmitType(out, bool_type, ast::StorageClass::kNone, ast::Access::kReadWrite, "")) {
         return false;
-      }
-      pre << ";";
     }
-
-    if (expr->op == ast::BinaryOp::kLogicalOr) {
-      line() << "if (!" << name << ") {";
+    ScopedParen outerCastParen(out);
+    // Cast LHS to uint scalar or vector type.
+    if (!EmitType(out, uint_type, ast::StorageClass::kNone, ast::Access::kReadWrite, "")) {
+        return false;
+    }
+    {
+        ScopedParen innerCastParen(out);
+        // Emit LHS.
+        if (!EmitExpression(out, expr->lhs)) {
+            return false;
+        }
+    }
+    // Emit operator.
+    if (expr->op == ast::BinaryOp::kAnd) {
+        out << " & ";
+    } else if (expr->op == ast::BinaryOp::kOr) {
+        out << " | ";
     } else {
-      line() << "if (" << name << ") {";
-    }
-
-    {
-      ScopedIndent si(this);
-      auto pre = line();
-      pre << name << " = ";
-      if (!EmitExpression(pre, expr->rhs)) {
+        TINT_ICE(Writer, diagnostics_) << "unexpected binary op: " << FriendlyName(expr->op);
         return false;
-      }
-      pre << ";";
     }
-
-    line() << "}";
-
-    out << "(" << name << ")";
+    // Cast RHS to uint scalar or vector type.
+    if (!EmitType(out, uint_type, ast::StorageClass::kNone, ast::Access::kReadWrite, "")) {
+        return false;
+    }
+    {
+        ScopedParen innerCastParen(out);
+        // Emit RHS.
+        if (!EmitExpression(out, expr->rhs)) {
+            return false;
+        }
+    }
     return true;
-  }
-  if ((expr->op == ast::BinaryOp::kAnd || expr->op == ast::BinaryOp::kOr) &&
-      TypeOf(expr->lhs)->UnwrapRef()->is_bool_scalar_or_vector()) {
-    return EmitBitwiseBoolOp(out, expr);
-  }
+}
 
-  if (expr->op == ast::BinaryOp::kModulo &&
-      (TypeOf(expr->lhs)->UnwrapRef()->is_float_scalar_or_vector() ||
-       TypeOf(expr->rhs)->UnwrapRef()->is_float_scalar_or_vector())) {
-    return EmitFloatModulo(out, expr);
-  }
+bool GeneratorImpl::EmitFloatModulo(std::ostream& out, const ast::BinaryExpression* expr) {
+    std::string fn;
+    auto* ret_ty = TypeOf(expr)->UnwrapRef();
+    fn = utils::GetOrCreate(float_modulo_funcs_, ret_ty, [&]() -> std::string {
+        TextBuffer b;
+        TINT_DEFER(helpers_.Append(b));
 
-  out << "(";
-  if (!EmitExpression(out, expr->lhs)) {
-    return false;
-  }
-  out << " ";
+        auto fn_name = UniqueIdentifier("tint_float_modulo");
+        std::vector<std::string> parameter_names;
+        {
+            auto decl = line(&b);
+            if (!EmitTypeAndName(decl, ret_ty, ast::StorageClass::kNone, ast::Access::kUndefined,
+                                 fn_name)) {
+                return "";
+            }
+            {
+                ScopedParen sp(decl);
+                const auto* ty = TypeOf(expr->lhs)->UnwrapRef();
+                if (!EmitTypeAndName(decl, ty, ast::StorageClass::kNone, ast::Access::kUndefined,
+                                     "lhs")) {
+                    return "";
+                }
+                decl << ", ";
+                ty = TypeOf(expr->rhs)->UnwrapRef();
+                if (!EmitTypeAndName(decl, ty, ast::StorageClass::kNone, ast::Access::kUndefined,
+                                     "rhs")) {
+                    return "";
+                }
+            }
+            decl << " {";
+        }
+        {
+            ScopedIndent si(&b);
+            line(&b) << "return (lhs - rhs * trunc(lhs / rhs));";
+        }
+        line(&b) << "}";
+        line(&b);
+        return fn_name;
+    });
 
-  switch (expr->op) {
-    case ast::BinaryOp::kAnd:
-      out << "&";
-      break;
-    case ast::BinaryOp::kOr:
-      out << "|";
-      break;
-    case ast::BinaryOp::kXor:
-      out << "^";
-      break;
-    case ast::BinaryOp::kLogicalAnd:
-    case ast::BinaryOp::kLogicalOr: {
-      // These are both handled above.
-      TINT_UNREACHABLE(Writer, diagnostics_);
-      return false;
+    if (fn.empty()) {
+        return false;
     }
-    case ast::BinaryOp::kEqual:
-      out << "==";
-      break;
-    case ast::BinaryOp::kNotEqual:
-      out << "!=";
-      break;
-    case ast::BinaryOp::kLessThan:
-      out << "<";
-      break;
-    case ast::BinaryOp::kGreaterThan:
-      out << ">";
-      break;
-    case ast::BinaryOp::kLessThanEqual:
-      out << "<=";
-      break;
-    case ast::BinaryOp::kGreaterThanEqual:
-      out << ">=";
-      break;
-    case ast::BinaryOp::kShiftLeft:
-      out << "<<";
-      break;
-    case ast::BinaryOp::kShiftRight:
-      // TODO(dsinclair): MSL is based on C++14, and >> in C++14 has
-      // implementation-defined behaviour for negative LHS.  We may have to
-      // generate extra code to implement WGSL-specified behaviour for negative
-      // LHS.
-      out << R"(>>)";
-      break;
 
-    case ast::BinaryOp::kAdd:
-      out << "+";
-      break;
-    case ast::BinaryOp::kSubtract:
-      out << "-";
-      break;
-    case ast::BinaryOp::kMultiply:
-      out << "*";
-      break;
-    case ast::BinaryOp::kDivide:
-      out << "/";
-      break;
-    case ast::BinaryOp::kModulo:
-      out << "%";
-      break;
-    case ast::BinaryOp::kNone:
-      diagnostics_.add_error(diag::System::Writer,
-                             "missing binary operation type");
-      return false;
-  }
-  out << " ";
+    // Call the helper
+    out << fn;
+    {
+        ScopedParen sp(out);
+        if (!EmitExpression(out, expr->lhs)) {
+            return false;
+        }
+        out << ", ";
+        if (!EmitExpression(out, expr->rhs)) {
+            return false;
+        }
+    }
+    return true;
+}
 
-  if (!EmitExpression(out, expr->rhs)) {
-    return false;
-  }
+bool GeneratorImpl::EmitBinary(std::ostream& out, const ast::BinaryExpression* expr) {
+    if (IsRelational(expr->op) && !TypeOf(expr->lhs)->UnwrapRef()->is_scalar()) {
+        return EmitVectorRelational(out, expr);
+    }
+    if (expr->op == ast::BinaryOp::kLogicalAnd || expr->op == ast::BinaryOp::kLogicalOr) {
+        auto name = UniqueIdentifier(kTempNamePrefix);
 
-  out << ")";
-  return true;
+        {
+            auto pre = line();
+            pre << "bool " << name << " = ";
+            if (!EmitExpression(pre, expr->lhs)) {
+                return false;
+            }
+            pre << ";";
+        }
+
+        if (expr->op == ast::BinaryOp::kLogicalOr) {
+            line() << "if (!" << name << ") {";
+        } else {
+            line() << "if (" << name << ") {";
+        }
+
+        {
+            ScopedIndent si(this);
+            auto pre = line();
+            pre << name << " = ";
+            if (!EmitExpression(pre, expr->rhs)) {
+                return false;
+            }
+            pre << ";";
+        }
+
+        line() << "}";
+
+        out << "(" << name << ")";
+        return true;
+    }
+    if ((expr->op == ast::BinaryOp::kAnd || expr->op == ast::BinaryOp::kOr) &&
+        TypeOf(expr->lhs)->UnwrapRef()->is_bool_scalar_or_vector()) {
+        return EmitBitwiseBoolOp(out, expr);
+    }
+
+    if (expr->op == ast::BinaryOp::kModulo &&
+        (TypeOf(expr->lhs)->UnwrapRef()->is_float_scalar_or_vector() ||
+         TypeOf(expr->rhs)->UnwrapRef()->is_float_scalar_or_vector())) {
+        return EmitFloatModulo(out, expr);
+    }
+
+    out << "(";
+    if (!EmitExpression(out, expr->lhs)) {
+        return false;
+    }
+    out << " ";
+
+    switch (expr->op) {
+        case ast::BinaryOp::kAnd:
+            out << "&";
+            break;
+        case ast::BinaryOp::kOr:
+            out << "|";
+            break;
+        case ast::BinaryOp::kXor:
+            out << "^";
+            break;
+        case ast::BinaryOp::kLogicalAnd:
+        case ast::BinaryOp::kLogicalOr: {
+            // These are both handled above.
+            TINT_UNREACHABLE(Writer, diagnostics_);
+            return false;
+        }
+        case ast::BinaryOp::kEqual:
+            out << "==";
+            break;
+        case ast::BinaryOp::kNotEqual:
+            out << "!=";
+            break;
+        case ast::BinaryOp::kLessThan:
+            out << "<";
+            break;
+        case ast::BinaryOp::kGreaterThan:
+            out << ">";
+            break;
+        case ast::BinaryOp::kLessThanEqual:
+            out << "<=";
+            break;
+        case ast::BinaryOp::kGreaterThanEqual:
+            out << ">=";
+            break;
+        case ast::BinaryOp::kShiftLeft:
+            out << "<<";
+            break;
+        case ast::BinaryOp::kShiftRight:
+            // TODO(dsinclair): MSL is based on C++14, and >> in C++14 has
+            // implementation-defined behaviour for negative LHS.  We may have to
+            // generate extra code to implement WGSL-specified behaviour for negative
+            // LHS.
+            out << R"(>>)";
+            break;
+
+        case ast::BinaryOp::kAdd:
+            out << "+";
+            break;
+        case ast::BinaryOp::kSubtract:
+            out << "-";
+            break;
+        case ast::BinaryOp::kMultiply:
+            out << "*";
+            break;
+        case ast::BinaryOp::kDivide:
+            out << "/";
+            break;
+        case ast::BinaryOp::kModulo:
+            out << "%";
+            break;
+        case ast::BinaryOp::kNone:
+            diagnostics_.add_error(diag::System::Writer, "missing binary operation type");
+            return false;
+    }
+    out << " ";
+
+    if (!EmitExpression(out, expr->rhs)) {
+        return false;
+    }
+
+    out << ")";
+    return true;
 }
 
 bool GeneratorImpl::EmitStatements(const ast::StatementList& stmts) {
-  for (auto* s : stmts) {
-    if (!EmitStatement(s)) {
-      return false;
+    for (auto* s : stmts) {
+        if (!EmitStatement(s)) {
+            return false;
+        }
     }
-  }
-  return true;
+    return true;
 }
 
 bool GeneratorImpl::EmitStatementsWithIndent(const ast::StatementList& stmts) {
-  ScopedIndent si(this);
-  return EmitStatements(stmts);
+    ScopedIndent si(this);
+    return EmitStatements(stmts);
 }
 
 bool GeneratorImpl::EmitBlock(const ast::BlockStatement* stmt) {
-  line() << "{";
-  if (!EmitStatementsWithIndent(stmt->statements)) {
-    return false;
-  }
-  line() << "}";
-  return true;
+    line() << "{";
+    if (!EmitStatementsWithIndent(stmt->statements)) {
+        return false;
+    }
+    line() << "}";
+    return true;
 }
 
 bool GeneratorImpl::EmitBreak(const ast::BreakStatement*) {
-  line() << "break;";
-  return true;
+    line() << "break;";
+    return true;
 }
 
-bool GeneratorImpl::EmitCall(std::ostream& out,
-                             const ast::CallExpression* expr) {
-  auto* call = builder_.Sem().Get(expr);
-  auto* target = call->Target();
+bool GeneratorImpl::EmitCall(std::ostream& out, const ast::CallExpression* expr) {
+    auto* call = builder_.Sem().Get(expr);
+    auto* target = call->Target();
 
-  if (target->Is<sem::Function>()) {
-    return EmitFunctionCall(out, call);
-  }
-  if (auto* builtin = target->As<sem::Builtin>()) {
-    return EmitBuiltinCall(out, call, builtin);
-  }
-  if (auto* cast = target->As<sem::TypeConversion>()) {
-    return EmitTypeConversion(out, call, cast);
-  }
-  if (auto* ctor = target->As<sem::TypeConstructor>()) {
-    return EmitTypeConstructor(out, call, ctor);
-  }
-  TINT_ICE(Writer, diagnostics_)
-      << "unhandled call target: " << target->TypeInfo().name;
-  return false;
+    if (target->Is<sem::Function>()) {
+        return EmitFunctionCall(out, call);
+    }
+    if (auto* builtin = target->As<sem::Builtin>()) {
+        return EmitBuiltinCall(out, call, builtin);
+    }
+    if (auto* cast = target->As<sem::TypeConversion>()) {
+        return EmitTypeConversion(out, call, cast);
+    }
+    if (auto* ctor = target->As<sem::TypeConstructor>()) {
+        return EmitTypeConstructor(out, call, ctor);
+    }
+    TINT_ICE(Writer, diagnostics_) << "unhandled call target: " << target->TypeInfo().name;
+    return false;
 }
 
 bool GeneratorImpl::EmitFunctionCall(std::ostream& out, const sem::Call* call) {
-  const auto& args = call->Arguments();
-  auto* decl = call->Declaration();
-  auto* ident = decl->target.name;
+    const auto& args = call->Arguments();
+    auto* decl = call->Declaration();
+    auto* ident = decl->target.name;
 
-  auto name = builder_.Symbols().NameFor(ident->symbol);
-  auto caller_sym = ident->symbol;
+    auto name = builder_.Symbols().NameFor(ident->symbol);
+    auto caller_sym = ident->symbol;
 
-  out << name << "(";
+    out << name << "(";
 
-  bool first = true;
-  for (auto* arg : args) {
-    if (!first) {
-      out << ", ";
+    bool first = true;
+    for (auto* arg : args) {
+        if (!first) {
+            out << ", ";
+        }
+        first = false;
+
+        if (!EmitExpression(out, arg->Declaration())) {
+            return false;
+        }
     }
-    first = false;
 
-    if (!EmitExpression(out, arg->Declaration())) {
-      return false;
-    }
-  }
-
-  out << ")";
-  return true;
+    out << ")";
+    return true;
 }
 
 bool GeneratorImpl::EmitBuiltinCall(std::ostream& out,
                                     const sem::Call* call,
                                     const sem::Builtin* builtin) {
-  auto* expr = call->Declaration();
-  if (builtin->IsTexture()) {
-    return EmitTextureCall(out, call, builtin);
-  }
-  if (builtin->Type() == sem::BuiltinType::kCountOneBits) {
-    return EmitCountOneBitsCall(out, expr);
-  }
-  if (builtin->Type() == sem::BuiltinType::kSelect) {
-    return EmitSelectCall(out, expr);
-  }
-  if (builtin->Type() == sem::BuiltinType::kDot) {
-    return EmitDotCall(out, expr, builtin);
-  }
-  if (builtin->Type() == sem::BuiltinType::kModf) {
-    return EmitModfCall(out, expr, builtin);
-  }
-  if (builtin->Type() == sem::BuiltinType::kFrexp) {
-    return EmitFrexpCall(out, expr, builtin);
-  }
-  if (builtin->Type() == sem::BuiltinType::kDegrees) {
-    return EmitDegreesCall(out, expr, builtin);
-  }
-  if (builtin->Type() == sem::BuiltinType::kRadians) {
-    return EmitRadiansCall(out, expr, builtin);
-  }
-  if (builtin->Type() == sem::BuiltinType::kArrayLength) {
-    return EmitArrayLength(out, expr);
-  }
-  if (builtin->Type() == sem::BuiltinType::kExtractBits) {
-    return EmitExtractBits(out, expr);
-  }
-  if (builtin->Type() == sem::BuiltinType::kInsertBits) {
-    return EmitInsertBits(out, expr);
-  }
-  if (builtin->Type() == sem::BuiltinType::kFma && version_.IsES()) {
-    return EmitEmulatedFMA(out, expr);
-  }
-  if (builtin->Type() == sem::BuiltinType::kAbs &&
-      TypeOf(expr->args[0])->UnwrapRef()->is_unsigned_scalar_or_vector()) {
-    // GLSL does not support abs() on unsigned arguments. However, it's a no-op.
-    return EmitExpression(out, expr->args[0]);
-  }
-  if ((builtin->Type() == sem::BuiltinType::kAny ||
-       builtin->Type() == sem::BuiltinType::kAll) &&
-      TypeOf(expr->args[0])->UnwrapRef()->is_scalar()) {
-    // GLSL does not support any() or all() on scalar arguments. It's a no-op.
-    return EmitExpression(out, expr->args[0]);
-  }
-  if (builtin->IsBarrier()) {
-    return EmitBarrierCall(out, builtin);
-  }
-  if (builtin->IsAtomic()) {
-    return EmitWorkgroupAtomicCall(out, expr, builtin);
-  }
-  auto name = generate_builtin_name(builtin);
-  if (name.empty()) {
-    return false;
-  }
-
-  out << name << "(";
-
-  bool first = true;
-  for (auto* arg : call->Arguments()) {
-    if (!first) {
-      out << ", ";
+    auto* expr = call->Declaration();
+    if (builtin->IsTexture()) {
+        return EmitTextureCall(out, call, builtin);
     }
-    first = false;
-
-    if (!EmitExpression(out, arg->Declaration())) {
-      return false;
+    if (builtin->Type() == sem::BuiltinType::kCountOneBits) {
+        return EmitCountOneBitsCall(out, expr);
     }
-  }
+    if (builtin->Type() == sem::BuiltinType::kSelect) {
+        return EmitSelectCall(out, expr);
+    }
+    if (builtin->Type() == sem::BuiltinType::kDot) {
+        return EmitDotCall(out, expr, builtin);
+    }
+    if (builtin->Type() == sem::BuiltinType::kModf) {
+        return EmitModfCall(out, expr, builtin);
+    }
+    if (builtin->Type() == sem::BuiltinType::kFrexp) {
+        return EmitFrexpCall(out, expr, builtin);
+    }
+    if (builtin->Type() == sem::BuiltinType::kDegrees) {
+        return EmitDegreesCall(out, expr, builtin);
+    }
+    if (builtin->Type() == sem::BuiltinType::kRadians) {
+        return EmitRadiansCall(out, expr, builtin);
+    }
+    if (builtin->Type() == sem::BuiltinType::kArrayLength) {
+        return EmitArrayLength(out, expr);
+    }
+    if (builtin->Type() == sem::BuiltinType::kExtractBits) {
+        return EmitExtractBits(out, expr);
+    }
+    if (builtin->Type() == sem::BuiltinType::kInsertBits) {
+        return EmitInsertBits(out, expr);
+    }
+    if (builtin->Type() == sem::BuiltinType::kFma && version_.IsES()) {
+        return EmitEmulatedFMA(out, expr);
+    }
+    if (builtin->Type() == sem::BuiltinType::kAbs &&
+        TypeOf(expr->args[0])->UnwrapRef()->is_unsigned_scalar_or_vector()) {
+        // GLSL does not support abs() on unsigned arguments. However, it's a no-op.
+        return EmitExpression(out, expr->args[0]);
+    }
+    if ((builtin->Type() == sem::BuiltinType::kAny || builtin->Type() == sem::BuiltinType::kAll) &&
+        TypeOf(expr->args[0])->UnwrapRef()->is_scalar()) {
+        // GLSL does not support any() or all() on scalar arguments. It's a no-op.
+        return EmitExpression(out, expr->args[0]);
+    }
+    if (builtin->IsBarrier()) {
+        return EmitBarrierCall(out, builtin);
+    }
+    if (builtin->IsAtomic()) {
+        return EmitWorkgroupAtomicCall(out, expr, builtin);
+    }
+    auto name = generate_builtin_name(builtin);
+    if (name.empty()) {
+        return false;
+    }
 
-  out << ")";
-  return true;
+    out << name << "(";
+
+    bool first = true;
+    for (auto* arg : call->Arguments()) {
+        if (!first) {
+            out << ", ";
+        }
+        first = false;
+
+        if (!EmitExpression(out, arg->Declaration())) {
+            return false;
+        }
+    }
+
+    out << ")";
+    return true;
 }
 
 bool GeneratorImpl::EmitTypeConversion(std::ostream& out,
                                        const sem::Call* call,
                                        const sem::TypeConversion* conv) {
-  if (!EmitType(out, conv->Target(), ast::StorageClass::kNone,
-                ast::Access::kReadWrite, "")) {
-    return false;
-  }
-  out << "(";
+    if (!EmitType(out, conv->Target(), ast::StorageClass::kNone, ast::Access::kReadWrite, "")) {
+        return false;
+    }
+    out << "(";
 
-  if (!EmitExpression(out, call->Arguments()[0]->Declaration())) {
-    return false;
-  }
+    if (!EmitExpression(out, call->Arguments()[0]->Declaration())) {
+        return false;
+    }
 
-  out << ")";
-  return true;
+    out << ")";
+    return true;
 }
 
 bool GeneratorImpl::EmitTypeConstructor(std::ostream& out,
                                         const sem::Call* call,
                                         const sem::TypeConstructor* ctor) {
-  auto* type = ctor->ReturnType();
+    auto* type = ctor->ReturnType();
 
-  // If the type constructor is empty then we need to construct with the zero
-  // value for all components.
-  if (call->Arguments().empty()) {
-    return EmitZeroValue(out, type);
-  }
-
-  auto it = structure_builders_.find(As<sem::Struct>(type));
-  if (it != structure_builders_.end()) {
-    out << it->second << "(";
-  } else {
-    if (!EmitType(out, type, ast::StorageClass::kNone, ast::Access::kReadWrite,
-                  "")) {
-      return false;
+    // If the type constructor is empty then we need to construct with the zero
+    // value for all components.
+    if (call->Arguments().empty()) {
+        return EmitZeroValue(out, type);
     }
-    out << "(";
-  }
 
-  bool first = true;
-  for (auto* arg : call->Arguments()) {
-    if (!first) {
-      out << ", ";
+    auto it = structure_builders_.find(As<sem::Struct>(type));
+    if (it != structure_builders_.end()) {
+        out << it->second << "(";
+    } else {
+        if (!EmitType(out, type, ast::StorageClass::kNone, ast::Access::kReadWrite, "")) {
+            return false;
+        }
+        out << "(";
     }
-    first = false;
 
-    if (!EmitExpression(out, arg->Declaration())) {
-      return false;
+    bool first = true;
+    for (auto* arg : call->Arguments()) {
+        if (!first) {
+            out << ", ";
+        }
+        first = false;
+
+        if (!EmitExpression(out, arg->Declaration())) {
+            return false;
+        }
     }
-  }
 
-  out << ")";
-  return true;
+    out << ")";
+    return true;
 }
 
 bool GeneratorImpl::EmitWorkgroupAtomicCall(std::ostream& out,
                                             const ast::CallExpression* expr,
                                             const sem::Builtin* builtin) {
-  auto call = [&](const char* name) {
-    out << name;
-    {
-      ScopedParen sp(out);
-      for (size_t i = 0; i < expr->args.size(); i++) {
-        auto* arg = expr->args[i];
-        if (i > 0) {
-          out << ", ";
+    auto call = [&](const char* name) {
+        out << name;
+        {
+            ScopedParen sp(out);
+            for (size_t i = 0; i < expr->args.size(); i++) {
+                auto* arg = expr->args[i];
+                if (i > 0) {
+                    out << ", ";
+                }
+                if (!EmitExpression(out, arg)) {
+                    return false;
+                }
+            }
         }
-        if (!EmitExpression(out, arg)) {
-          return false;
-        }
-      }
-    }
-    return true;
-  };
+        return true;
+    };
 
-  switch (builtin->Type()) {
-    case sem::BuiltinType::kAtomicLoad: {
-      // GLSL does not have an atomicLoad, so we emulate it with
-      // atomicOr using 0 as the OR value
-      out << "atomicOr";
-      {
-        ScopedParen sp(out);
-        if (!EmitExpression(out, expr->args[0])) {
-          return false;
-        }
-        out << ", 0";
-        if (builtin->ReturnType()->Is<sem::U32>()) {
-          out << "u";
-        }
-      }
-      return true;
-    }
-    case sem::BuiltinType::kAtomicCompareExchangeWeak: {
-      return CallBuiltinHelper(
-          out, expr, builtin,
-          [&](TextBuffer* b, const std::vector<std::string>& params) {
+    switch (builtin->Type()) {
+        case sem::BuiltinType::kAtomicLoad: {
+            // GLSL does not have an atomicLoad, so we emulate it with
+            // atomicOr using 0 as the OR value
+            out << "atomicOr";
             {
-              auto pre = line(b);
-              if (!EmitTypeAndName(pre, builtin->ReturnType(),
-                                   ast::StorageClass::kNone,
-                                   ast::Access::kUndefined, "result")) {
-                return false;
-              }
-              pre << ";";
+                ScopedParen sp(out);
+                if (!EmitExpression(out, expr->args[0])) {
+                    return false;
+                }
+                out << ", 0";
+                if (builtin->ReturnType()->Is<sem::U32>()) {
+                    out << "u";
+                }
             }
-            {
-              auto pre = line(b);
-              pre << "result.x = atomicCompSwap";
-              {
-                ScopedParen sp(pre);
-                pre << params[0];
-                pre << ", " << params[1];
-                pre << ", " << params[2];
-              }
-              pre << ";";
-            }
-            {
-              auto pre = line(b);
-              pre << "result.y = result.x == " << params[2] << " ? ";
-              if (TypeOf(expr->args[2])->Is<sem::U32>()) {
-                pre << "1u : 0u;";
-              } else {
-                pre << "1 : 0;";
-              }
-            }
-            line(b) << "return result;";
             return true;
-          });
+        }
+        case sem::BuiltinType::kAtomicCompareExchangeWeak: {
+            return CallBuiltinHelper(
+                out, expr, builtin, [&](TextBuffer* b, const std::vector<std::string>& params) {
+                    {
+                        auto pre = line(b);
+                        if (!EmitTypeAndName(pre, builtin->ReturnType(), ast::StorageClass::kNone,
+                                             ast::Access::kUndefined, "result")) {
+                            return false;
+                        }
+                        pre << ";";
+                    }
+                    {
+                        auto pre = line(b);
+                        pre << "result.x = atomicCompSwap";
+                        {
+                            ScopedParen sp(pre);
+                            pre << params[0];
+                            pre << ", " << params[1];
+                            pre << ", " << params[2];
+                        }
+                        pre << ";";
+                    }
+                    {
+                        auto pre = line(b);
+                        pre << "result.y = result.x == " << params[2] << " ? ";
+                        if (TypeOf(expr->args[2])->Is<sem::U32>()) {
+                            pre << "1u : 0u;";
+                        } else {
+                            pre << "1 : 0;";
+                        }
+                    }
+                    line(b) << "return result;";
+                    return true;
+                });
+        }
+
+        case sem::BuiltinType::kAtomicAdd:
+        case sem::BuiltinType::kAtomicSub:
+            return call("atomicAdd");
+
+        case sem::BuiltinType::kAtomicMax:
+            return call("atomicMax");
+
+        case sem::BuiltinType::kAtomicMin:
+            return call("atomicMin");
+
+        case sem::BuiltinType::kAtomicAnd:
+            return call("atomicAnd");
+
+        case sem::BuiltinType::kAtomicOr:
+            return call("atomicOr");
+
+        case sem::BuiltinType::kAtomicXor:
+            return call("atomicXor");
+
+        case sem::BuiltinType::kAtomicExchange:
+        case sem::BuiltinType::kAtomicStore:
+            // GLSL does not have an atomicStore, so we emulate it with
+            // atomicExchange.
+            return call("atomicExchange");
+
+        default:
+            break;
     }
 
-    case sem::BuiltinType::kAtomicAdd:
-    case sem::BuiltinType::kAtomicSub:
-      return call("atomicAdd");
-
-    case sem::BuiltinType::kAtomicMax:
-      return call("atomicMax");
-
-    case sem::BuiltinType::kAtomicMin:
-      return call("atomicMin");
-
-    case sem::BuiltinType::kAtomicAnd:
-      return call("atomicAnd");
-
-    case sem::BuiltinType::kAtomicOr:
-      return call("atomicOr");
-
-    case sem::BuiltinType::kAtomicXor:
-      return call("atomicXor");
-
-    case sem::BuiltinType::kAtomicExchange:
-    case sem::BuiltinType::kAtomicStore:
-      // GLSL does not have an atomicStore, so we emulate it with
-      // atomicExchange.
-      return call("atomicExchange");
-
-    default:
-      break;
-  }
-
-  TINT_UNREACHABLE(Writer, diagnostics_)
-      << "unsupported atomic builtin: " << builtin->Type();
-  return false;
+    TINT_UNREACHABLE(Writer, diagnostics_) << "unsupported atomic builtin: " << builtin->Type();
+    return false;
 }
 
-bool GeneratorImpl::EmitArrayLength(std::ostream& out,
-                                    const ast::CallExpression* expr) {
-  out << "uint(";
-  if (!EmitExpression(out, expr->args[0])) {
-    return false;
-  }
-  out << ".length())";
-  return true;
-}
-
-bool GeneratorImpl::EmitExtractBits(std::ostream& out,
-                                    const ast::CallExpression* expr) {
-  out << "bitfieldExtract(";
-  if (!EmitExpression(out, expr->args[0])) {
-    return false;
-  }
-  out << ", int(";
-  if (!EmitExpression(out, expr->args[1])) {
-    return false;
-  }
-  out << "), int(";
-  if (!EmitExpression(out, expr->args[2])) {
-    return false;
-  }
-  out << "))";
-  return true;
-}
-
-bool GeneratorImpl::EmitInsertBits(std::ostream& out,
-                                   const ast::CallExpression* expr) {
-  out << "bitfieldInsert(";
-  if (!EmitExpression(out, expr->args[0])) {
-    return false;
-  }
-  out << ", ";
-  if (!EmitExpression(out, expr->args[1])) {
-    return false;
-  }
-  out << ", int(";
-  if (!EmitExpression(out, expr->args[2])) {
-    return false;
-  }
-  out << "), int(";
-  if (!EmitExpression(out, expr->args[3])) {
-    return false;
-  }
-  out << "))";
-  return true;
-}
-
-bool GeneratorImpl::EmitEmulatedFMA(std::ostream& out,
-                                    const ast::CallExpression* expr) {
-  out << "((";
-  if (!EmitExpression(out, expr->args[0])) {
-    return false;
-  }
-  out << ") * (";
-  if (!EmitExpression(out, expr->args[1])) {
-    return false;
-  }
-  out << ") + (";
-  if (!EmitExpression(out, expr->args[2])) {
-    return false;
-  }
-  out << "))";
-  return true;
-}
-
-bool GeneratorImpl::EmitCountOneBitsCall(std::ostream& out,
-                                         const ast::CallExpression* expr) {
-  // GLSL's bitCount returns an integer type, so cast it to the appropriate
-  // unsigned type.
-  if (!EmitType(out, TypeOf(expr)->UnwrapRef(), ast::StorageClass::kNone,
-                ast::Access::kReadWrite, "")) {
-    return false;
-  }
-  out << "(bitCount(";
-
-  if (!EmitExpression(out, expr->args[0])) {
-    return false;
-  }
-  out << "))";
-  return true;
-}
-
-bool GeneratorImpl::EmitSelectCall(std::ostream& out,
-                                   const ast::CallExpression* expr) {
-  auto* expr_false = expr->args[0];
-  auto* expr_true = expr->args[1];
-  auto* expr_cond = expr->args[2];
-  // GLSL does not support ternary expressions with a bool vector conditional,
-  // but it does support mix() with same.
-  if (TypeOf(expr_cond)->UnwrapRef()->is_bool_vector()) {
-    out << "mix(";
-    if (!EmitExpression(out, expr_false)) {
-      return false;
+bool GeneratorImpl::EmitArrayLength(std::ostream& out, const ast::CallExpression* expr) {
+    out << "uint(";
+    if (!EmitExpression(out, expr->args[0])) {
+        return false;
     }
-    out << ", ";
-    if (!EmitExpression(out, expr_true)) {
-      return false;
-    }
-    out << ", ";
-    if (!EmitExpression(out, expr_cond)) {
-      return false;
-    }
-    out << ")";
+    out << ".length())";
     return true;
-  }
-  ScopedParen paren(out);
-  if (!EmitExpression(out, expr_cond)) {
-    return false;
-  }
+}
 
-  out << " ? ";
+bool GeneratorImpl::EmitExtractBits(std::ostream& out, const ast::CallExpression* expr) {
+    out << "bitfieldExtract(";
+    if (!EmitExpression(out, expr->args[0])) {
+        return false;
+    }
+    out << ", int(";
+    if (!EmitExpression(out, expr->args[1])) {
+        return false;
+    }
+    out << "), int(";
+    if (!EmitExpression(out, expr->args[2])) {
+        return false;
+    }
+    out << "))";
+    return true;
+}
 
-  if (!EmitExpression(out, expr_true)) {
-    return false;
-  }
+bool GeneratorImpl::EmitInsertBits(std::ostream& out, const ast::CallExpression* expr) {
+    out << "bitfieldInsert(";
+    if (!EmitExpression(out, expr->args[0])) {
+        return false;
+    }
+    out << ", ";
+    if (!EmitExpression(out, expr->args[1])) {
+        return false;
+    }
+    out << ", int(";
+    if (!EmitExpression(out, expr->args[2])) {
+        return false;
+    }
+    out << "), int(";
+    if (!EmitExpression(out, expr->args[3])) {
+        return false;
+    }
+    out << "))";
+    return true;
+}
 
-  out << " : ";
+bool GeneratorImpl::EmitEmulatedFMA(std::ostream& out, const ast::CallExpression* expr) {
+    out << "((";
+    if (!EmitExpression(out, expr->args[0])) {
+        return false;
+    }
+    out << ") * (";
+    if (!EmitExpression(out, expr->args[1])) {
+        return false;
+    }
+    out << ") + (";
+    if (!EmitExpression(out, expr->args[2])) {
+        return false;
+    }
+    out << "))";
+    return true;
+}
 
-  if (!EmitExpression(out, expr_false)) {
-    return false;
-  }
+bool GeneratorImpl::EmitCountOneBitsCall(std::ostream& out, const ast::CallExpression* expr) {
+    // GLSL's bitCount returns an integer type, so cast it to the appropriate
+    // unsigned type.
+    if (!EmitType(out, TypeOf(expr)->UnwrapRef(), ast::StorageClass::kNone, ast::Access::kReadWrite,
+                  "")) {
+        return false;
+    }
+    out << "(bitCount(";
 
-  return true;
+    if (!EmitExpression(out, expr->args[0])) {
+        return false;
+    }
+    out << "))";
+    return true;
+}
+
+bool GeneratorImpl::EmitSelectCall(std::ostream& out, const ast::CallExpression* expr) {
+    auto* expr_false = expr->args[0];
+    auto* expr_true = expr->args[1];
+    auto* expr_cond = expr->args[2];
+    // GLSL does not support ternary expressions with a bool vector conditional,
+    // but it does support mix() with same.
+    if (TypeOf(expr_cond)->UnwrapRef()->is_bool_vector()) {
+        out << "mix(";
+        if (!EmitExpression(out, expr_false)) {
+            return false;
+        }
+        out << ", ";
+        if (!EmitExpression(out, expr_true)) {
+            return false;
+        }
+        out << ", ";
+        if (!EmitExpression(out, expr_cond)) {
+            return false;
+        }
+        out << ")";
+        return true;
+    }
+    ScopedParen paren(out);
+    if (!EmitExpression(out, expr_cond)) {
+        return false;
+    }
+
+    out << " ? ";
+
+    if (!EmitExpression(out, expr_true)) {
+        return false;
+    }
+
+    out << " : ";
+
+    if (!EmitExpression(out, expr_false)) {
+        return false;
+    }
+
+    return true;
 }
 
 bool GeneratorImpl::EmitDotCall(std::ostream& out,
                                 const ast::CallExpression* expr,
                                 const sem::Builtin* builtin) {
-  auto* vec_ty = builtin->Parameters()[0]->Type()->As<sem::Vector>();
-  std::string fn = "dot";
-  if (vec_ty->type()->is_integer_scalar()) {
-    // GLSL does not have a builtin for dot() with integer vector types.
-    // Generate the helper function if it hasn't been created already
-    fn = utils::GetOrCreate(int_dot_funcs_, vec_ty, [&]() -> std::string {
-      TextBuffer b;
-      TINT_DEFER(helpers_.Append(b));
+    auto* vec_ty = builtin->Parameters()[0]->Type()->As<sem::Vector>();
+    std::string fn = "dot";
+    if (vec_ty->type()->is_integer_scalar()) {
+        // GLSL does not have a builtin for dot() with integer vector types.
+        // Generate the helper function if it hasn't been created already
+        fn = utils::GetOrCreate(int_dot_funcs_, vec_ty, [&]() -> std::string {
+            TextBuffer b;
+            TINT_DEFER(helpers_.Append(b));
 
-      auto fn_name = UniqueIdentifier("tint_int_dot");
+            auto fn_name = UniqueIdentifier("tint_int_dot");
 
-      std::string v;
-      {
-        std::stringstream s;
-        if (!EmitType(s, vec_ty->type(), ast::StorageClass::kNone,
-                      ast::Access::kRead, "")) {
-          return "";
+            std::string v;
+            {
+                std::stringstream s;
+                if (!EmitType(s, vec_ty->type(), ast::StorageClass::kNone, ast::Access::kRead,
+                              "")) {
+                    return "";
+                }
+                v = s.str();
+            }
+            {  // (u)int tint_int_dot([i|u]vecN a, [i|u]vecN b) {
+                auto l = line(&b);
+                if (!EmitType(l, vec_ty->type(), ast::StorageClass::kNone, ast::Access::kRead,
+                              "")) {
+                    return "";
+                }
+                l << " " << fn_name << "(";
+                if (!EmitType(l, vec_ty, ast::StorageClass::kNone, ast::Access::kRead, "")) {
+                    return "";
+                }
+                l << " a, ";
+                if (!EmitType(l, vec_ty, ast::StorageClass::kNone, ast::Access::kRead, "")) {
+                    return "";
+                }
+                l << " b) {";
+            }
+            {
+                auto l = line(&b);
+                l << "  return ";
+                for (uint32_t i = 0; i < vec_ty->Width(); i++) {
+                    if (i > 0) {
+                        l << " + ";
+                    }
+                    l << "a[" << i << "]*b[" << i << "]";
+                }
+                l << ";";
+            }
+            line(&b) << "}";
+            return fn_name;
+        });
+        if (fn.empty()) {
+            return false;
         }
-        v = s.str();
-      }
-      {  // (u)int tint_int_dot([i|u]vecN a, [i|u]vecN b) {
-        auto l = line(&b);
-        if (!EmitType(l, vec_ty->type(), ast::StorageClass::kNone,
-                      ast::Access::kRead, "")) {
-          return "";
-        }
-        l << " " << fn_name << "(";
-        if (!EmitType(l, vec_ty, ast::StorageClass::kNone, ast::Access::kRead,
-                      "")) {
-          return "";
-        }
-        l << " a, ";
-        if (!EmitType(l, vec_ty, ast::StorageClass::kNone, ast::Access::kRead,
-                      "")) {
-          return "";
-        }
-        l << " b) {";
-      }
-      {
-        auto l = line(&b);
-        l << "  return ";
-        for (uint32_t i = 0; i < vec_ty->Width(); i++) {
-          if (i > 0) {
-            l << " + ";
-          }
-          l << "a[" << i << "]*b[" << i << "]";
-        }
-        l << ";";
-      }
-      line(&b) << "}";
-      return fn_name;
-    });
-    if (fn.empty()) {
-      return false;
     }
-  }
 
-  out << fn << "(";
-  if (!EmitExpression(out, expr->args[0])) {
-    return false;
-  }
-  out << ", ";
-  if (!EmitExpression(out, expr->args[1])) {
-    return false;
-  }
-  out << ")";
-  return true;
+    out << fn << "(";
+    if (!EmitExpression(out, expr->args[0])) {
+        return false;
+    }
+    out << ", ";
+    if (!EmitExpression(out, expr->args[1])) {
+        return false;
+    }
+    out << ")";
+    return true;
 }
 
 bool GeneratorImpl::EmitModfCall(std::ostream& out,
                                  const ast::CallExpression* expr,
                                  const sem::Builtin* builtin) {
-  if (expr->args.size() == 1) {
-    return CallBuiltinHelper(
-        out, expr, builtin,
-        [&](TextBuffer* b, const std::vector<std::string>& params) {
-          // Emit the builtin return type unique to this overload. This does not
-          // exist in the AST, so it will not be generated in Generate().
-          if (!EmitStructType(&helpers_,
-                              builtin->ReturnType()->As<sem::Struct>())) {
-            return false;
-          }
+    if (expr->args.size() == 1) {
+        return CallBuiltinHelper(
+            out, expr, builtin, [&](TextBuffer* b, const std::vector<std::string>& params) {
+                // Emit the builtin return type unique to this overload. This does not
+                // exist in the AST, so it will not be generated in Generate().
+                if (!EmitStructType(&helpers_, builtin->ReturnType()->As<sem::Struct>())) {
+                    return false;
+                }
 
-          {
-            auto l = line(b);
-            if (!EmitType(l, builtin->ReturnType(), ast::StorageClass::kNone,
-                          ast::Access::kUndefined, "")) {
-              return false;
-            }
-            l << " result;";
-          }
-          line(b) << "result.fract = modf(" << params[0] << ", result.whole);";
-          line(b) << "return result;";
-          return true;
-        });
-  }
+                {
+                    auto l = line(b);
+                    if (!EmitType(l, builtin->ReturnType(), ast::StorageClass::kNone,
+                                  ast::Access::kUndefined, "")) {
+                        return false;
+                    }
+                    l << " result;";
+                }
+                line(b) << "result.fract = modf(" << params[0] << ", result.whole);";
+                line(b) << "return result;";
+                return true;
+            });
+    }
 
-  // DEPRECATED
-  out << "modf";
-  ScopedParen sp(out);
-  if (!EmitExpression(out, expr->args[0])) {
-    return false;
-  }
-  out << ", ";
-  if (!EmitExpression(out, expr->args[1])) {
-    return false;
-  }
-  return true;
+    // DEPRECATED
+    out << "modf";
+    ScopedParen sp(out);
+    if (!EmitExpression(out, expr->args[0])) {
+        return false;
+    }
+    out << ", ";
+    if (!EmitExpression(out, expr->args[1])) {
+        return false;
+    }
+    return true;
 }
 
 bool GeneratorImpl::EmitFrexpCall(std::ostream& out,
                                   const ast::CallExpression* expr,
                                   const sem::Builtin* builtin) {
-  if (expr->args.size() == 1) {
+    if (expr->args.size() == 1) {
+        return CallBuiltinHelper(
+            out, expr, builtin, [&](TextBuffer* b, const std::vector<std::string>& params) {
+                // Emit the builtin return type unique to this overload. This does not
+                // exist in the AST, so it will not be generated in Generate().
+                if (!EmitStructType(&helpers_, builtin->ReturnType()->As<sem::Struct>())) {
+                    return false;
+                }
+
+                {
+                    auto l = line(b);
+                    if (!EmitType(l, builtin->ReturnType(), ast::StorageClass::kNone,
+                                  ast::Access::kUndefined, "")) {
+                        return false;
+                    }
+                    l << " result;";
+                }
+                line(b) << "result.sig = frexp(" << params[0] << ", result.exp);";
+                line(b) << "return result;";
+                return true;
+            });
+    }
+    // DEPRECATED
+    // Exponent is an integer in WGSL, but HLSL wants a float.
+    // We need to make the call with a temporary float, and then cast.
     return CallBuiltinHelper(
-        out, expr, builtin,
-        [&](TextBuffer* b, const std::vector<std::string>& params) {
-          // Emit the builtin return type unique to this overload. This does not
-          // exist in the AST, so it will not be generated in Generate().
-          if (!EmitStructType(&helpers_,
-                              builtin->ReturnType()->As<sem::Struct>())) {
-            return false;
-          }
+        out, expr, builtin, [&](TextBuffer* b, const std::vector<std::string>& params) {
+            auto* significand_ty = builtin->Parameters()[0]->Type();
+            auto significand = params[0];
+            auto* exponent_ty = builtin->Parameters()[1]->Type();
+            auto exponent = params[1];
 
-          {
-            auto l = line(b);
-            if (!EmitType(l, builtin->ReturnType(), ast::StorageClass::kNone,
-                          ast::Access::kUndefined, "")) {
-              return false;
+            std::string width;
+            if (auto* vec = significand_ty->As<sem::Vector>()) {
+                width = std::to_string(vec->Width());
             }
-            l << " result;";
-          }
-          line(b) << "result.sig = frexp(" << params[0] << ", result.exp);";
-          line(b) << "return result;";
-          return true;
+
+            // Exponent is an integer, which HLSL does not have an overload for.
+            // We need to cast from a float.
+            line(b) << "float" << width << " float_exp;";
+            line(b) << "float" << width << " significand = frexp(" << significand
+                    << ", float_exp);";
+            {
+                auto l = line(b);
+                l << exponent << " = ";
+                if (!EmitType(l, exponent_ty->UnwrapPtr(), ast::StorageClass::kNone,
+                              ast::Access::kUndefined, "")) {
+                    return false;
+                }
+                l << "(float_exp);";
+            }
+            line(b) << "return significand;";
+            return true;
         });
-  }
-  // DEPRECATED
-  // Exponent is an integer in WGSL, but HLSL wants a float.
-  // We need to make the call with a temporary float, and then cast.
-  return CallBuiltinHelper(
-      out, expr, builtin,
-      [&](TextBuffer* b, const std::vector<std::string>& params) {
-        auto* significand_ty = builtin->Parameters()[0]->Type();
-        auto significand = params[0];
-        auto* exponent_ty = builtin->Parameters()[1]->Type();
-        auto exponent = params[1];
-
-        std::string width;
-        if (auto* vec = significand_ty->As<sem::Vector>()) {
-          width = std::to_string(vec->Width());
-        }
-
-        // Exponent is an integer, which HLSL does not have an overload for.
-        // We need to cast from a float.
-        line(b) << "float" << width << " float_exp;";
-        line(b) << "float" << width << " significand = frexp(" << significand
-                << ", float_exp);";
-        {
-          auto l = line(b);
-          l << exponent << " = ";
-          if (!EmitType(l, exponent_ty->UnwrapPtr(), ast::StorageClass::kNone,
-                        ast::Access::kUndefined, "")) {
-            return false;
-          }
-          l << "(float_exp);";
-        }
-        line(b) << "return significand;";
-        return true;
-      });
 }
 
 bool GeneratorImpl::EmitDegreesCall(std::ostream& out,
                                     const ast::CallExpression* expr,
                                     const sem::Builtin* builtin) {
-  return CallBuiltinHelper(
-      out, expr, builtin,
-      [&](TextBuffer* b, const std::vector<std::string>& params) {
-        line(b) << "return " << params[0] << " * " << std::setprecision(20)
-                << sem::kRadToDeg << ";";
-        return true;
-      });
+    return CallBuiltinHelper(out, expr, builtin,
+                             [&](TextBuffer* b, const std::vector<std::string>& params) {
+                                 line(b) << "return " << params[0] << " * " << std::setprecision(20)
+                                         << sem::kRadToDeg << ";";
+                                 return true;
+                             });
 }
 
 bool GeneratorImpl::EmitRadiansCall(std::ostream& out,
                                     const ast::CallExpression* expr,
                                     const sem::Builtin* builtin) {
-  return CallBuiltinHelper(
-      out, expr, builtin,
-      [&](TextBuffer* b, const std::vector<std::string>& params) {
-        line(b) << "return " << params[0] << " * " << std::setprecision(20)
-                << sem::kDegToRad << ";";
-        return true;
-      });
+    return CallBuiltinHelper(out, expr, builtin,
+                             [&](TextBuffer* b, const std::vector<std::string>& params) {
+                                 line(b) << "return " << params[0] << " * " << std::setprecision(20)
+                                         << sem::kDegToRad << ";";
+                                 return true;
+                             });
 }
 
-bool GeneratorImpl::EmitBarrierCall(std::ostream& out,
-                                    const sem::Builtin* builtin) {
-  // TODO(crbug.com/tint/661): Combine sequential barriers to a single
-  // instruction.
-  if (builtin->Type() == sem::BuiltinType::kWorkgroupBarrier) {
-    out << "barrier()";
-  } else if (builtin->Type() == sem::BuiltinType::kStorageBarrier) {
-    out << "{ barrier(); memoryBarrierBuffer(); }";
-  } else {
-    TINT_UNREACHABLE(Writer, diagnostics_)
-        << "unexpected barrier builtin type " << sem::str(builtin->Type());
-    return false;
-  }
-  return true;
+bool GeneratorImpl::EmitBarrierCall(std::ostream& out, const sem::Builtin* builtin) {
+    // TODO(crbug.com/tint/661): Combine sequential barriers to a single
+    // instruction.
+    if (builtin->Type() == sem::BuiltinType::kWorkgroupBarrier) {
+        out << "barrier()";
+    } else if (builtin->Type() == sem::BuiltinType::kStorageBarrier) {
+        out << "{ barrier(); memoryBarrierBuffer(); }";
+    } else {
+        TINT_UNREACHABLE(Writer, diagnostics_)
+            << "unexpected barrier builtin type " << sem::str(builtin->Type());
+        return false;
+    }
+    return true;
 }
 
-const ast::Expression* GeneratorImpl::CreateF32Zero(
-    const sem::Statement* stmt) {
-  auto* zero = builder_.Expr(0.0f);
-  auto* f32 = builder_.create<sem::F32>();
-  auto* sem_zero = builder_.create<sem::Expression>(
-      zero, f32, stmt, sem::Constant{}, /* has_side_effects */ false);
-  builder_.Sem().Add(zero, sem_zero);
-  return zero;
+const ast::Expression* GeneratorImpl::CreateF32Zero(const sem::Statement* stmt) {
+    auto* zero = builder_.Expr(0.0f);
+    auto* f32 = builder_.create<sem::F32>();
+    auto* sem_zero = builder_.create<sem::Expression>(zero, f32, stmt, sem::Constant{},
+                                                      /* has_side_effects */ false);
+    builder_.Sem().Add(zero, sem_zero);
+    return zero;
 }
 
 bool GeneratorImpl::EmitTextureCall(std::ostream& out,
                                     const sem::Call* call,
                                     const sem::Builtin* builtin) {
-  using Usage = sem::ParameterUsage;
+    using Usage = sem::ParameterUsage;
 
-  auto& signature = builtin->Signature();
-  auto* expr = call->Declaration();
-  auto arguments = expr->args;
+    auto& signature = builtin->Signature();
+    auto* expr = call->Declaration();
+    auto arguments = expr->args;
 
-  // Returns the argument with the given usage
-  auto arg = [&](Usage usage) {
-    int idx = signature.IndexOf(usage);
-    return (idx >= 0) ? arguments[idx] : nullptr;
-  };
+    // Returns the argument with the given usage
+    auto arg = [&](Usage usage) {
+        int idx = signature.IndexOf(usage);
+        return (idx >= 0) ? arguments[idx] : nullptr;
+    };
 
-  auto* texture = arg(Usage::kTexture);
-  if (!texture) {
-    TINT_ICE(Writer, diagnostics_) << "missing texture argument";
-    return false;
-  }
-
-  auto* texture_type = TypeOf(texture)->UnwrapRef()->As<sem::Texture>();
-
-  switch (builtin->Type()) {
-    case sem::BuiltinType::kTextureDimensions: {
-      if (texture_type->Is<sem::StorageTexture>()) {
-        out << "imageSize(";
-      } else {
-        out << "textureSize(";
-      }
-      if (!EmitExpression(out, texture)) {
+    auto* texture = arg(Usage::kTexture);
+    if (!texture) {
+        TINT_ICE(Writer, diagnostics_) << "missing texture argument";
         return false;
-      }
+    }
 
-      // The LOD parameter is mandatory on textureSize() for non-multisampled
-      // textures.
-      if (!texture_type->Is<sem::StorageTexture>() &&
-          !texture_type->Is<sem::MultisampledTexture>() &&
-          !texture_type->Is<sem::DepthMultisampledTexture>()) {
-        out << ", ";
-        if (auto* level_arg = arg(Usage::kLevel)) {
-          if (!EmitExpression(out, level_arg)) {
+    auto* texture_type = TypeOf(texture)->UnwrapRef()->As<sem::Texture>();
+
+    switch (builtin->Type()) {
+        case sem::BuiltinType::kTextureDimensions: {
+            if (texture_type->Is<sem::StorageTexture>()) {
+                out << "imageSize(";
+            } else {
+                out << "textureSize(";
+            }
+            if (!EmitExpression(out, texture)) {
+                return false;
+            }
+
+            // The LOD parameter is mandatory on textureSize() for non-multisampled
+            // textures.
+            if (!texture_type->Is<sem::StorageTexture>() &&
+                !texture_type->Is<sem::MultisampledTexture>() &&
+                !texture_type->Is<sem::DepthMultisampledTexture>()) {
+                out << ", ";
+                if (auto* level_arg = arg(Usage::kLevel)) {
+                    if (!EmitExpression(out, level_arg)) {
+                        return false;
+                    }
+                } else {
+                    out << "0";
+                }
+            }
+            out << ")";
+            // textureSize() on array samplers returns the array size in the
+            // final component, so strip it out.
+            if (texture_type->dim() == ast::TextureDimension::k2dArray ||
+                texture_type->dim() == ast::TextureDimension::kCubeArray) {
+                out << ".xy";
+            }
+            return true;
+        }
+        case sem::BuiltinType::kTextureNumLayers: {
+            if (texture_type->Is<sem::StorageTexture>()) {
+                out << "imageSize(";
+            } else {
+                out << "textureSize(";
+            }
+            // textureSize() on sampler2dArray returns the array size in the
+            // final component, so return it
+            if (!EmitExpression(out, texture)) {
+                return false;
+            }
+            // The LOD parameter is mandatory on textureSize() for non-multisampled
+            // textures.
+            if (!texture_type->Is<sem::StorageTexture>() &&
+                !texture_type->Is<sem::MultisampledTexture>() &&
+                !texture_type->Is<sem::DepthMultisampledTexture>()) {
+                out << ", ";
+                if (auto* level_arg = arg(Usage::kLevel)) {
+                    if (!EmitExpression(out, level_arg)) {
+                        return false;
+                    }
+                } else {
+                    out << "0";
+                }
+            }
+            out << ").z";
+            return true;
+        }
+        case sem::BuiltinType::kTextureNumLevels: {
+            out << "textureQueryLevels(";
+            if (!EmitExpression(out, texture)) {
+                return false;
+            }
+            out << ")";
+            return true;
+        }
+        case sem::BuiltinType::kTextureNumSamples: {
+            out << "textureSamples(";
+            if (!EmitExpression(out, texture)) {
+                return false;
+            }
+            out << ")";
+            return true;
+        }
+        default:
+            break;
+    }
+
+    uint32_t glsl_ret_width = 4u;
+    bool append_depth_ref_to_coords = true;
+    bool is_depth = texture_type->Is<sem::DepthTexture>();
+
+    switch (builtin->Type()) {
+        case sem::BuiltinType::kTextureSample:
+        case sem::BuiltinType::kTextureSampleBias:
+            out << "texture";
+            if (is_depth) {
+                glsl_ret_width = 1u;
+            }
+            break;
+        case sem::BuiltinType::kTextureSampleLevel:
+            out << "textureLod";
+            if (is_depth) {
+                glsl_ret_width = 1u;
+            }
+            break;
+        case sem::BuiltinType::kTextureGather:
+        case sem::BuiltinType::kTextureGatherCompare:
+            out << "textureGather";
+            append_depth_ref_to_coords = false;
+            break;
+        case sem::BuiltinType::kTextureSampleGrad:
+            out << "textureGrad";
+            break;
+        case sem::BuiltinType::kTextureSampleCompare:
+        case sem::BuiltinType::kTextureSampleCompareLevel:
+            out << "texture";
+            glsl_ret_width = 1;
+            break;
+        case sem::BuiltinType::kTextureLoad:
+            out << "texelFetch";
+            break;
+        case sem::BuiltinType::kTextureStore:
+            out << "imageStore";
+            break;
+        default:
+            diagnostics_.add_error(diag::System::Writer,
+                                   "Internal compiler error: Unhandled texture builtin '" +
+                                       std::string(builtin->str()) + "'");
             return false;
-          }
-        } else {
-          out << "0";
+    }
+
+    if (builtin->Signature().IndexOf(sem::ParameterUsage::kOffset) >= 0) {
+        out << "Offset";
+    }
+
+    out << "(";
+
+    if (!EmitExpression(out, texture))
+        return false;
+
+    out << ", ";
+
+    auto* param_coords = arg(Usage::kCoords);
+    if (!param_coords) {
+        TINT_ICE(Writer, diagnostics_) << "missing coords argument";
+        return false;
+    }
+
+    if (auto* array_index = arg(Usage::kArrayIndex)) {
+        // Array index needs to be appended to the coordinates.
+        param_coords = AppendVector(&builder_, param_coords, array_index)->Declaration();
+    }
+
+    // GLSL requires Dref to be appended to the coordinates, *unless* it's
+    // samplerCubeArrayShadow, in which case it will be handled as a separate
+    // parameter.
+    if (texture_type->dim() == ast::TextureDimension::kCubeArray) {
+        append_depth_ref_to_coords = false;
+    }
+
+    if (is_depth && append_depth_ref_to_coords) {
+        auto* depth_ref = arg(Usage::kDepthRef);
+        if (!depth_ref) {
+            // Sampling a depth texture in GLSL always requires a depth reference, so
+            // append zero here.
+            depth_ref = CreateF32Zero(builder_.Sem().Get(param_coords)->Stmt());
         }
-      }
-      out << ")";
-      // textureSize() on array samplers returns the array size in the
-      // final component, so strip it out.
-      if (texture_type->dim() == ast::TextureDimension::k2dArray ||
-          texture_type->dim() == ast::TextureDimension::kCubeArray) {
-        out << ".xy";
-      }
-      return true;
+        param_coords = AppendVector(&builder_, param_coords, depth_ref)->Declaration();
     }
-    case sem::BuiltinType::kTextureNumLayers: {
-      if (texture_type->Is<sem::StorageTexture>()) {
-        out << "imageSize(";
-      } else {
-        out << "textureSize(";
-      }
-      // textureSize() on sampler2dArray returns the array size in the
-      // final component, so return it
-      if (!EmitExpression(out, texture)) {
+
+    if (!EmitExpression(out, param_coords)) {
         return false;
-      }
-      // The LOD parameter is mandatory on textureSize() for non-multisampled
-      // textures.
-      if (!texture_type->Is<sem::StorageTexture>() &&
-          !texture_type->Is<sem::MultisampledTexture>() &&
-          !texture_type->Is<sem::DepthMultisampledTexture>()) {
-        out << ", ";
-        if (auto* level_arg = arg(Usage::kLevel)) {
-          if (!EmitExpression(out, level_arg)) {
-            return false;
-          }
-        } else {
-          out << "0";
+    }
+
+    for (auto usage :
+         {Usage::kLevel, Usage::kDdx, Usage::kDdy, Usage::kSampleIndex, Usage::kValue}) {
+        if (auto* e = arg(usage)) {
+            out << ", ";
+            if (usage == Usage::kLevel && is_depth) {
+                // WGSL's textureSampleLevel() "level" param is i32 for depth textures,
+                // whereas GLSL's textureLod() "lod" param is always float, so cast it.
+                out << "float(";
+                if (!EmitExpression(out, e)) {
+                    return false;
+                }
+                out << ")";
+            } else if (!EmitExpression(out, e)) {
+                return false;
+            }
         }
-      }
-      out << ").z";
-      return true;
     }
-    case sem::BuiltinType::kTextureNumLevels: {
-      out << "textureQueryLevels(";
-      if (!EmitExpression(out, texture)) {
-        return false;
-      }
-      out << ")";
-      return true;
+
+    // GLSL's textureGather always requires a refZ parameter.
+    if (is_depth && builtin->Type() == sem::BuiltinType::kTextureGather) {
+        out << ", 0.0";
     }
-    case sem::BuiltinType::kTextureNumSamples: {
-      out << "textureSamples(";
-      if (!EmitExpression(out, texture)) {
-        return false;
-      }
-      out << ")";
-      return true;
-    }
-    default:
-      break;
-  }
 
-  uint32_t glsl_ret_width = 4u;
-  bool append_depth_ref_to_coords = true;
-  bool is_depth = texture_type->Is<sem::DepthTexture>();
-
-  switch (builtin->Type()) {
-    case sem::BuiltinType::kTextureSample:
-    case sem::BuiltinType::kTextureSampleBias:
-      out << "texture";
-      if (is_depth) {
-        glsl_ret_width = 1u;
-      }
-      break;
-    case sem::BuiltinType::kTextureSampleLevel:
-      out << "textureLod";
-      if (is_depth) {
-        glsl_ret_width = 1u;
-      }
-      break;
-    case sem::BuiltinType::kTextureGather:
-    case sem::BuiltinType::kTextureGatherCompare:
-      out << "textureGather";
-      append_depth_ref_to_coords = false;
-      break;
-    case sem::BuiltinType::kTextureSampleGrad:
-      out << "textureGrad";
-      break;
-    case sem::BuiltinType::kTextureSampleCompare:
-    case sem::BuiltinType::kTextureSampleCompareLevel:
-      out << "texture";
-      glsl_ret_width = 1;
-      break;
-    case sem::BuiltinType::kTextureLoad:
-      out << "texelFetch";
-      break;
-    case sem::BuiltinType::kTextureStore:
-      out << "imageStore";
-      break;
-    default:
-      diagnostics_.add_error(
-          diag::System::Writer,
-          "Internal compiler error: Unhandled texture builtin '" +
-              std::string(builtin->str()) + "'");
-      return false;
-  }
-
-  if (builtin->Signature().IndexOf(sem::ParameterUsage::kOffset) >= 0) {
-    out << "Offset";
-  }
-
-  out << "(";
-
-  if (!EmitExpression(out, texture))
-    return false;
-
-  out << ", ";
-
-  auto* param_coords = arg(Usage::kCoords);
-  if (!param_coords) {
-    TINT_ICE(Writer, diagnostics_) << "missing coords argument";
-    return false;
-  }
-
-  if (auto* array_index = arg(Usage::kArrayIndex)) {
-    // Array index needs to be appended to the coordinates.
-    param_coords =
-        AppendVector(&builder_, param_coords, array_index)->Declaration();
-  }
-
-  // GLSL requires Dref to be appended to the coordinates, *unless* it's
-  // samplerCubeArrayShadow, in which case it will be handled as a separate
-  // parameter.
-  if (texture_type->dim() == ast::TextureDimension::kCubeArray) {
-    append_depth_ref_to_coords = false;
-  }
-
-  if (is_depth && append_depth_ref_to_coords) {
-    auto* depth_ref = arg(Usage::kDepthRef);
-    if (!depth_ref) {
-      // Sampling a depth texture in GLSL always requires a depth reference, so
-      // append zero here.
-      depth_ref = CreateF32Zero(builder_.Sem().Get(param_coords)->Stmt());
-    }
-    param_coords =
-        AppendVector(&builder_, param_coords, depth_ref)->Declaration();
-  }
-
-  if (!EmitExpression(out, param_coords)) {
-    return false;
-  }
-
-  for (auto usage : {Usage::kLevel, Usage::kDdx, Usage::kDdy,
-                     Usage::kSampleIndex, Usage::kValue}) {
-    if (auto* e = arg(usage)) {
-      out << ", ";
-      if (usage == Usage::kLevel && is_depth) {
-        // WGSL's textureSampleLevel() "level" param is i32 for depth textures,
-        // whereas GLSL's textureLod() "lod" param is always float, so cast it.
-        out << "float(";
-        if (!EmitExpression(out, e)) {
-          return false;
+    // [1] samplerCubeArrayShadow requires a separate depthRef parameter
+    if (is_depth && !append_depth_ref_to_coords) {
+        if (auto* e = arg(Usage::kDepthRef)) {
+            out << ", ";
+            if (!EmitExpression(out, e)) {
+                return false;
+            }
+        } else if (builtin->Type() == sem::BuiltinType::kTextureSample) {
+            out << ", 0.0f";
         }
-        out << ")";
-      } else if (!EmitExpression(out, e)) {
-        return false;
-      }
     }
-  }
 
-  // GLSL's textureGather always requires a refZ parameter.
-  if (is_depth && builtin->Type() == sem::BuiltinType::kTextureGather) {
-    out << ", 0.0";
-  }
-
-  // [1] samplerCubeArrayShadow requires a separate depthRef parameter
-  if (is_depth && !append_depth_ref_to_coords) {
-    if (auto* e = arg(Usage::kDepthRef)) {
-      out << ", ";
-      if (!EmitExpression(out, e)) {
-        return false;
-      }
-    } else if (builtin->Type() == sem::BuiltinType::kTextureSample) {
-      out << ", 0.0f";
+    for (auto usage : {Usage::kOffset, Usage::kComponent, Usage::kBias}) {
+        if (auto* e = arg(usage)) {
+            out << ", ";
+            if (!EmitExpression(out, e)) {
+                return false;
+            }
+        }
     }
-  }
 
-  for (auto usage : {Usage::kOffset, Usage::kComponent, Usage::kBias}) {
-    if (auto* e = arg(usage)) {
-      out << ", ";
-      if (!EmitExpression(out, e)) {
-        return false;
-      }
+    out << ")";
+
+    if (builtin->ReturnType()->Is<sem::Void>()) {
+        return true;
     }
-  }
+    // If the builtin return type does not match the number of elements of the
+    // GLSL builtin, we need to swizzle the expression to generate the correct
+    // number of components.
+    uint32_t wgsl_ret_width = 1;
+    if (auto* vec = builtin->ReturnType()->As<sem::Vector>()) {
+        wgsl_ret_width = vec->Width();
+    }
+    if (wgsl_ret_width < glsl_ret_width) {
+        out << ".";
+        for (uint32_t i = 0; i < wgsl_ret_width; i++) {
+            out << "xyz"[i];
+        }
+    }
+    if (wgsl_ret_width > glsl_ret_width) {
+        TINT_ICE(Writer, diagnostics_)
+            << "WGSL return width (" << wgsl_ret_width << ") is wider than GLSL return width ("
+            << glsl_ret_width << ") for " << builtin->Type();
+        return false;
+    }
 
-  out << ")";
-
-  if (builtin->ReturnType()->Is<sem::Void>()) {
     return true;
-  }
-  // If the builtin return type does not match the number of elements of the
-  // GLSL builtin, we need to swizzle the expression to generate the correct
-  // number of components.
-  uint32_t wgsl_ret_width = 1;
-  if (auto* vec = builtin->ReturnType()->As<sem::Vector>()) {
-    wgsl_ret_width = vec->Width();
-  }
-  if (wgsl_ret_width < glsl_ret_width) {
-    out << ".";
-    for (uint32_t i = 0; i < wgsl_ret_width; i++) {
-      out << "xyz"[i];
-    }
-  }
-  if (wgsl_ret_width > glsl_ret_width) {
-    TINT_ICE(Writer, diagnostics_)
-        << "WGSL return width (" << wgsl_ret_width
-        << ") is wider than GLSL return width (" << glsl_ret_width << ") for "
-        << builtin->Type();
-    return false;
-  }
-
-  return true;
 }
 
 std::string GeneratorImpl::generate_builtin_name(const sem::Builtin* builtin) {
-  switch (builtin->Type()) {
-    case sem::BuiltinType::kAbs:
-    case sem::BuiltinType::kAcos:
-    case sem::BuiltinType::kAll:
-    case sem::BuiltinType::kAny:
-    case sem::BuiltinType::kAsin:
-    case sem::BuiltinType::kAtan:
-    case sem::BuiltinType::kCeil:
-    case sem::BuiltinType::kClamp:
-    case sem::BuiltinType::kCos:
-    case sem::BuiltinType::kCosh:
-    case sem::BuiltinType::kCross:
-    case sem::BuiltinType::kDeterminant:
-    case sem::BuiltinType::kDistance:
-    case sem::BuiltinType::kDot:
-    case sem::BuiltinType::kExp:
-    case sem::BuiltinType::kExp2:
-    case sem::BuiltinType::kFloor:
-    case sem::BuiltinType::kFrexp:
-    case sem::BuiltinType::kLdexp:
-    case sem::BuiltinType::kLength:
-    case sem::BuiltinType::kLog:
-    case sem::BuiltinType::kLog2:
-    case sem::BuiltinType::kMax:
-    case sem::BuiltinType::kMin:
-    case sem::BuiltinType::kModf:
-    case sem::BuiltinType::kNormalize:
-    case sem::BuiltinType::kPow:
-    case sem::BuiltinType::kReflect:
-    case sem::BuiltinType::kRefract:
-    case sem::BuiltinType::kRound:
-    case sem::BuiltinType::kSign:
-    case sem::BuiltinType::kSin:
-    case sem::BuiltinType::kSinh:
-    case sem::BuiltinType::kSqrt:
-    case sem::BuiltinType::kStep:
-    case sem::BuiltinType::kTan:
-    case sem::BuiltinType::kTanh:
-    case sem::BuiltinType::kTranspose:
-    case sem::BuiltinType::kTrunc:
-      return builtin->str();
-    case sem::BuiltinType::kAtan2:
-      return "atan";
-    case sem::BuiltinType::kCountOneBits:
-      return "bitCount";
-    case sem::BuiltinType::kDpdx:
-      return "dFdx";
-    case sem::BuiltinType::kDpdxCoarse:
-      if (version_.IsES()) {
-        return "dFdx";
-      }
-      return "dFdxCoarse";
-    case sem::BuiltinType::kDpdxFine:
-      if (version_.IsES()) {
-        return "dFdx";
-      }
-      return "dFdxFine";
-    case sem::BuiltinType::kDpdy:
-      return "dFdy";
-    case sem::BuiltinType::kDpdyCoarse:
-      if (version_.IsES()) {
-        return "dFdy";
-      }
-      return "dFdyCoarse";
-    case sem::BuiltinType::kDpdyFine:
-      if (version_.IsES()) {
-        return "dFdy";
-      }
-      return "dFdyFine";
-    case sem::BuiltinType::kFaceForward:
-      return "faceforward";
-    case sem::BuiltinType::kFract:
-      return "fract";
-    case sem::BuiltinType::kFma:
-      return "fma";
-    case sem::BuiltinType::kFwidth:
-    case sem::BuiltinType::kFwidthCoarse:
-    case sem::BuiltinType::kFwidthFine:
-      return "fwidth";
-    case sem::BuiltinType::kInverseSqrt:
-      return "inversesqrt";
-    case sem::BuiltinType::kMix:
-      return "mix";
-    case sem::BuiltinType::kPack2x16float:
-      return "packHalf2x16";
-    case sem::BuiltinType::kPack2x16snorm:
-      return "packSnorm2x16";
-    case sem::BuiltinType::kPack2x16unorm:
-      return "packUnorm2x16";
-    case sem::BuiltinType::kPack4x8snorm:
-      return "packSnorm4x8";
-    case sem::BuiltinType::kPack4x8unorm:
-      return "packUnorm4x8";
-    case sem::BuiltinType::kReverseBits:
-      return "bitfieldReverse";
-    case sem::BuiltinType::kSmoothstep:
-    case sem::BuiltinType::kSmoothStep:
-      return "smoothstep";
-    case sem::BuiltinType::kUnpack2x16float:
-      return "unpackHalf2x16";
-    case sem::BuiltinType::kUnpack2x16snorm:
-      return "unpackSnorm2x16";
-    case sem::BuiltinType::kUnpack2x16unorm:
-      return "unpackUnorm2x16";
-    case sem::BuiltinType::kUnpack4x8snorm:
-      return "unpackSnorm4x8";
-    case sem::BuiltinType::kUnpack4x8unorm:
-      return "unpackUnorm4x8";
-    default:
-      diagnostics_.add_error(
-          diag::System::Writer,
-          "Unknown builtin method: " + std::string(builtin->str()));
-  }
+    switch (builtin->Type()) {
+        case sem::BuiltinType::kAbs:
+        case sem::BuiltinType::kAcos:
+        case sem::BuiltinType::kAll:
+        case sem::BuiltinType::kAny:
+        case sem::BuiltinType::kAsin:
+        case sem::BuiltinType::kAtan:
+        case sem::BuiltinType::kCeil:
+        case sem::BuiltinType::kClamp:
+        case sem::BuiltinType::kCos:
+        case sem::BuiltinType::kCosh:
+        case sem::BuiltinType::kCross:
+        case sem::BuiltinType::kDeterminant:
+        case sem::BuiltinType::kDistance:
+        case sem::BuiltinType::kDot:
+        case sem::BuiltinType::kExp:
+        case sem::BuiltinType::kExp2:
+        case sem::BuiltinType::kFloor:
+        case sem::BuiltinType::kFrexp:
+        case sem::BuiltinType::kLdexp:
+        case sem::BuiltinType::kLength:
+        case sem::BuiltinType::kLog:
+        case sem::BuiltinType::kLog2:
+        case sem::BuiltinType::kMax:
+        case sem::BuiltinType::kMin:
+        case sem::BuiltinType::kModf:
+        case sem::BuiltinType::kNormalize:
+        case sem::BuiltinType::kPow:
+        case sem::BuiltinType::kReflect:
+        case sem::BuiltinType::kRefract:
+        case sem::BuiltinType::kRound:
+        case sem::BuiltinType::kSign:
+        case sem::BuiltinType::kSin:
+        case sem::BuiltinType::kSinh:
+        case sem::BuiltinType::kSqrt:
+        case sem::BuiltinType::kStep:
+        case sem::BuiltinType::kTan:
+        case sem::BuiltinType::kTanh:
+        case sem::BuiltinType::kTranspose:
+        case sem::BuiltinType::kTrunc:
+            return builtin->str();
+        case sem::BuiltinType::kAtan2:
+            return "atan";
+        case sem::BuiltinType::kCountOneBits:
+            return "bitCount";
+        case sem::BuiltinType::kDpdx:
+            return "dFdx";
+        case sem::BuiltinType::kDpdxCoarse:
+            if (version_.IsES()) {
+                return "dFdx";
+            }
+            return "dFdxCoarse";
+        case sem::BuiltinType::kDpdxFine:
+            if (version_.IsES()) {
+                return "dFdx";
+            }
+            return "dFdxFine";
+        case sem::BuiltinType::kDpdy:
+            return "dFdy";
+        case sem::BuiltinType::kDpdyCoarse:
+            if (version_.IsES()) {
+                return "dFdy";
+            }
+            return "dFdyCoarse";
+        case sem::BuiltinType::kDpdyFine:
+            if (version_.IsES()) {
+                return "dFdy";
+            }
+            return "dFdyFine";
+        case sem::BuiltinType::kFaceForward:
+            return "faceforward";
+        case sem::BuiltinType::kFract:
+            return "fract";
+        case sem::BuiltinType::kFma:
+            return "fma";
+        case sem::BuiltinType::kFwidth:
+        case sem::BuiltinType::kFwidthCoarse:
+        case sem::BuiltinType::kFwidthFine:
+            return "fwidth";
+        case sem::BuiltinType::kInverseSqrt:
+            return "inversesqrt";
+        case sem::BuiltinType::kMix:
+            return "mix";
+        case sem::BuiltinType::kPack2x16float:
+            return "packHalf2x16";
+        case sem::BuiltinType::kPack2x16snorm:
+            return "packSnorm2x16";
+        case sem::BuiltinType::kPack2x16unorm:
+            return "packUnorm2x16";
+        case sem::BuiltinType::kPack4x8snorm:
+            return "packSnorm4x8";
+        case sem::BuiltinType::kPack4x8unorm:
+            return "packUnorm4x8";
+        case sem::BuiltinType::kReverseBits:
+            return "bitfieldReverse";
+        case sem::BuiltinType::kSmoothstep:
+        case sem::BuiltinType::kSmoothStep:
+            return "smoothstep";
+        case sem::BuiltinType::kUnpack2x16float:
+            return "unpackHalf2x16";
+        case sem::BuiltinType::kUnpack2x16snorm:
+            return "unpackSnorm2x16";
+        case sem::BuiltinType::kUnpack2x16unorm:
+            return "unpackUnorm2x16";
+        case sem::BuiltinType::kUnpack4x8snorm:
+            return "unpackSnorm4x8";
+        case sem::BuiltinType::kUnpack4x8unorm:
+            return "unpackUnorm4x8";
+        default:
+            diagnostics_.add_error(diag::System::Writer,
+                                   "Unknown builtin method: " + std::string(builtin->str()));
+    }
 
-  return "";
+    return "";
 }
 
 bool GeneratorImpl::EmitCase(const ast::CaseStatement* stmt) {
-  if (stmt->IsDefault()) {
-    line() << "default: {";
-  } else {
-    for (auto* selector : stmt->selectors) {
-      auto out = line();
-      out << "case ";
-      if (!EmitLiteral(out, selector)) {
-        return false;
-      }
-      out << ":";
-      if (selector == stmt->selectors.back()) {
-        out << " {";
-      }
+    if (stmt->IsDefault()) {
+        line() << "default: {";
+    } else {
+        for (auto* selector : stmt->selectors) {
+            auto out = line();
+            out << "case ";
+            if (!EmitLiteral(out, selector)) {
+                return false;
+            }
+            out << ":";
+            if (selector == stmt->selectors.back()) {
+                out << " {";
+            }
+        }
     }
-  }
 
-  {
-    ScopedIndent si(this);
-    if (!EmitStatements(stmt->body->statements)) {
-      return false;
+    {
+        ScopedIndent si(this);
+        if (!EmitStatements(stmt->body->statements)) {
+            return false;
+        }
+        if (!last_is_break_or_fallthrough(stmt->body)) {
+            line() << "break;";
+        }
     }
-    if (!last_is_break_or_fallthrough(stmt->body)) {
-      line() << "break;";
-    }
-  }
 
-  line() << "}";
+    line() << "}";
 
-  return true;
+    return true;
 }
 
 bool GeneratorImpl::EmitContinue(const ast::ContinueStatement*) {
-  if (!emit_continuing_()) {
-    return false;
-  }
-  line() << "continue;";
-  return true;
+    if (!emit_continuing_()) {
+        return false;
+    }
+    line() << "continue;";
+    return true;
 }
 
 bool GeneratorImpl::EmitDiscard(const ast::DiscardStatement*) {
-  // TODO(dsinclair): Verify this is correct when the discard semantics are
-  // defined for WGSL (https://github.com/gpuweb/gpuweb/issues/361)
-  line() << "discard;";
-  return true;
+    // TODO(dsinclair): Verify this is correct when the discard semantics are
+    // defined for WGSL (https://github.com/gpuweb/gpuweb/issues/361)
+    line() << "discard;";
+    return true;
 }
 
-bool GeneratorImpl::EmitExpression(std::ostream& out,
-                                   const ast::Expression* expr) {
-  if (auto* a = expr->As<ast::IndexAccessorExpression>()) {
-    return EmitIndexAccessor(out, a);
-  }
-  if (auto* b = expr->As<ast::BinaryExpression>()) {
-    return EmitBinary(out, b);
-  }
-  if (auto* b = expr->As<ast::BitcastExpression>()) {
-    return EmitBitcast(out, b);
-  }
-  if (auto* c = expr->As<ast::CallExpression>()) {
-    return EmitCall(out, c);
-  }
-  if (auto* i = expr->As<ast::IdentifierExpression>()) {
-    return EmitIdentifier(out, i);
-  }
-  if (auto* l = expr->As<ast::LiteralExpression>()) {
-    return EmitLiteral(out, l);
-  }
-  if (auto* m = expr->As<ast::MemberAccessorExpression>()) {
-    return EmitMemberAccessor(out, m);
-  }
-  if (auto* u = expr->As<ast::UnaryOpExpression>()) {
-    return EmitUnaryOp(out, u);
-  }
+bool GeneratorImpl::EmitExpression(std::ostream& out, const ast::Expression* expr) {
+    if (auto* a = expr->As<ast::IndexAccessorExpression>()) {
+        return EmitIndexAccessor(out, a);
+    }
+    if (auto* b = expr->As<ast::BinaryExpression>()) {
+        return EmitBinary(out, b);
+    }
+    if (auto* b = expr->As<ast::BitcastExpression>()) {
+        return EmitBitcast(out, b);
+    }
+    if (auto* c = expr->As<ast::CallExpression>()) {
+        return EmitCall(out, c);
+    }
+    if (auto* i = expr->As<ast::IdentifierExpression>()) {
+        return EmitIdentifier(out, i);
+    }
+    if (auto* l = expr->As<ast::LiteralExpression>()) {
+        return EmitLiteral(out, l);
+    }
+    if (auto* m = expr->As<ast::MemberAccessorExpression>()) {
+        return EmitMemberAccessor(out, m);
+    }
+    if (auto* u = expr->As<ast::UnaryOpExpression>()) {
+        return EmitUnaryOp(out, u);
+    }
 
-  diagnostics_.add_error(
-      diag::System::Writer,
-      "unknown expression type: " + std::string(expr->TypeInfo().name));
-  return false;
+    diagnostics_.add_error(diag::System::Writer,
+                           "unknown expression type: " + std::string(expr->TypeInfo().name));
+    return false;
 }
 
-bool GeneratorImpl::EmitIdentifier(std::ostream& out,
-                                   const ast::IdentifierExpression* expr) {
-  out << builder_.Symbols().NameFor(expr->symbol);
-  return true;
+bool GeneratorImpl::EmitIdentifier(std::ostream& out, const ast::IdentifierExpression* expr) {
+    out << builder_.Symbols().NameFor(expr->symbol);
+    return true;
 }
 
 bool GeneratorImpl::EmitIf(const ast::IfStatement* stmt) {
-  {
-    auto out = line();
-    out << "if (";
-    if (!EmitExpression(out, stmt->condition)) {
-      return false;
-    }
-    out << ") {";
-  }
-
-  if (!EmitStatementsWithIndent(stmt->body->statements)) {
-    return false;
-  }
-
-  for (auto* e : stmt->else_statements) {
-    if (e->condition) {
-      line() << "} else {";
-      increment_indent();
-
-      {
+    {
         auto out = line();
         out << "if (";
-        if (!EmitExpression(out, e->condition)) {
-          return false;
+        if (!EmitExpression(out, stmt->condition)) {
+            return false;
         }
         out << ") {";
-      }
-    } else {
-      line() << "} else {";
     }
 
-    if (!EmitStatementsWithIndent(e->body->statements)) {
-      return false;
+    if (!EmitStatementsWithIndent(stmt->body->statements)) {
+        return false;
     }
-  }
 
-  line() << "}";
-
-  for (auto* e : stmt->else_statements) {
-    if (e->condition) {
-      decrement_indent();
-      line() << "}";
+    if (stmt->else_statement) {
+        line() << "} else {";
+        if (auto* block = stmt->else_statement->As<ast::BlockStatement>()) {
+            if (!EmitStatementsWithIndent(block->statements)) {
+                return false;
+            }
+        } else {
+            if (!EmitStatementsWithIndent({stmt->else_statement})) {
+                return false;
+            }
+        }
     }
-  }
-  return true;
+    line() << "}";
+
+    return true;
 }
 
 bool GeneratorImpl::EmitFunction(const ast::Function* func) {
-  auto* sem = builder_.Sem().Get(func);
+    auto* sem = builder_.Sem().Get(func);
 
-  if (ast::HasAttribute<ast::InternalAttribute>(func->attributes)) {
-    // An internal function. Do not emit.
-    return true;
-  }
-
-  {
-    auto out = line();
-    auto name = builder_.Symbols().NameFor(func->symbol);
-    if (!EmitType(out, sem->ReturnType(), ast::StorageClass::kNone,
-                  ast::Access::kReadWrite, "")) {
-      return false;
+    if (ast::HasAttribute<ast::InternalAttribute>(func->attributes)) {
+        // An internal function. Do not emit.
+        return true;
     }
 
-    out << " " << name << "(";
+    {
+        auto out = line();
+        auto name = builder_.Symbols().NameFor(func->symbol);
+        if (!EmitType(out, sem->ReturnType(), ast::StorageClass::kNone, ast::Access::kReadWrite,
+                      "")) {
+            return false;
+        }
 
-    bool first = true;
+        out << " " << name << "(";
 
-    for (auto* v : sem->Parameters()) {
-      if (!first) {
-        out << ", ";
-      }
-      first = false;
+        bool first = true;
 
-      auto const* type = v->Type();
+        for (auto* v : sem->Parameters()) {
+            if (!first) {
+                out << ", ";
+            }
+            first = false;
 
-      if (auto* ptr = type->As<sem::Pointer>()) {
-        // Transform pointer parameters in to `inout` parameters.
-        // The WGSL spec is highly restrictive in what can be passed in pointer
-        // parameters, which allows for this transformation. See:
-        // https://gpuweb.github.io/gpuweb/wgsl/#function-restriction
-        out << "inout ";
-        type = ptr->StoreType();
-      }
+            auto const* type = v->Type();
 
-      // Note: WGSL only allows for StorageClass::kNone on parameters, however
-      // the sanitizer transforms generates load / store functions for storage
-      // or uniform buffers. These functions have a buffer parameter with
-      // StorageClass::kStorage or StorageClass::kUniform. This is required to
-      // correctly translate the parameter to a [RW]ByteAddressBuffer for
-      // storage buffers and a uint4[N] for uniform buffers.
-      if (!EmitTypeAndName(
-              out, type, v->StorageClass(), v->Access(),
-              builder_.Symbols().NameFor(v->Declaration()->symbol))) {
+            if (auto* ptr = type->As<sem::Pointer>()) {
+                // Transform pointer parameters in to `inout` parameters.
+                // The WGSL spec is highly restrictive in what can be passed in pointer
+                // parameters, which allows for this transformation. See:
+                // https://gpuweb.github.io/gpuweb/wgsl/#function-restriction
+                out << "inout ";
+                type = ptr->StoreType();
+            }
+
+            // Note: WGSL only allows for StorageClass::kNone on parameters, however
+            // the sanitizer transforms generates load / store functions for storage
+            // or uniform buffers. These functions have a buffer parameter with
+            // StorageClass::kStorage or StorageClass::kUniform. This is required to
+            // correctly translate the parameter to a [RW]ByteAddressBuffer for
+            // storage buffers and a uint4[N] for uniform buffers.
+            if (!EmitTypeAndName(out, type, v->StorageClass(), v->Access(),
+                                 builder_.Symbols().NameFor(v->Declaration()->symbol))) {
+                return false;
+            }
+        }
+        out << ") {";
+    }
+
+    if (!EmitStatementsWithIndent(func->body->statements)) {
         return false;
-      }
     }
-    out << ") {";
-  }
 
-  if (!EmitStatementsWithIndent(func->body->statements)) {
-    return false;
-  }
+    line() << "}";
+    line();
 
-  line() << "}";
-  line();
-
-  return true;
+    return true;
 }
 
 bool GeneratorImpl::EmitGlobalVariable(const ast::Variable* global) {
-  if (global->is_const) {
-    return EmitProgramConstVariable(global);
-  }
+    if (global->is_const) {
+        return EmitProgramConstVariable(global);
+    }
 
-  auto* sem = builder_.Sem().Get(global);
-  switch (sem->StorageClass()) {
-    case ast::StorageClass::kUniform:
-      return EmitUniformVariable(sem);
-    case ast::StorageClass::kStorage:
-      return EmitStorageVariable(sem);
-    case ast::StorageClass::kUniformConstant:
-      return EmitHandleVariable(sem);
-    case ast::StorageClass::kPrivate:
-      return EmitPrivateVariable(sem);
-    case ast::StorageClass::kWorkgroup:
-      return EmitWorkgroupVariable(sem);
-    case ast::StorageClass::kInput:
-    case ast::StorageClass::kOutput:
-      return EmitIOVariable(sem);
-    default:
-      break;
-  }
+    auto* sem = builder_.Sem().Get(global);
+    switch (sem->StorageClass()) {
+        case ast::StorageClass::kUniform:
+            return EmitUniformVariable(sem);
+        case ast::StorageClass::kStorage:
+            return EmitStorageVariable(sem);
+        case ast::StorageClass::kHandle:
+            return EmitHandleVariable(sem);
+        case ast::StorageClass::kPrivate:
+            return EmitPrivateVariable(sem);
+        case ast::StorageClass::kWorkgroup:
+            return EmitWorkgroupVariable(sem);
+        case ast::StorageClass::kInput:
+        case ast::StorageClass::kOutput:
+            return EmitIOVariable(sem);
+        default:
+            break;
+    }
 
-  TINT_ICE(Writer, diagnostics_)
-      << "unhandled storage class " << sem->StorageClass();
-  return false;
+    TINT_ICE(Writer, diagnostics_) << "unhandled storage class " << sem->StorageClass();
+    return false;
 }
 
 bool GeneratorImpl::EmitUniformVariable(const sem::Variable* var) {
-  auto* decl = var->Declaration();
-  auto* type = var->Type()->UnwrapRef();
-  auto* str = type->As<sem::Struct>();
-  if (!str) {
-    TINT_ICE(Writer, builder_.Diagnostics())
-        << "storage variable must be of struct type";
-    return false;
-  }
-  ast::VariableBindingPoint bp = decl->BindingPoint();
-  {
-    auto out = line();
-    out << "layout(binding = " << bp.binding->value;
-    if (version_.IsDesktop()) {
-      out << ", std140";
+    auto* decl = var->Declaration();
+    auto* type = var->Type()->UnwrapRef();
+    auto* str = type->As<sem::Struct>();
+    if (!str) {
+        TINT_ICE(Writer, builder_.Diagnostics()) << "storage variable must be of struct type";
+        return false;
     }
-    out << ") uniform " << UniqueIdentifier(StructName(str)) << " {";
-  }
-  EmitStructMembers(current_buffer_, str, /* emit_offsets */ true);
-  auto name = builder_.Symbols().NameFor(decl->symbol);
-  line() << "} " << name << ";";
-  line();
+    ast::VariableBindingPoint bp = decl->BindingPoint();
+    {
+        auto out = line();
+        out << "layout(binding = " << bp.binding->value;
+        if (version_.IsDesktop()) {
+            out << ", std140";
+        }
+        out << ") uniform " << UniqueIdentifier(StructName(str)) << " {";
+    }
+    EmitStructMembers(current_buffer_, str, /* emit_offsets */ true);
+    auto name = builder_.Symbols().NameFor(decl->symbol);
+    line() << "} " << name << ";";
+    line();
 
-  return true;
+    return true;
 }
 
 bool GeneratorImpl::EmitStorageVariable(const sem::Variable* var) {
-  auto* decl = var->Declaration();
-  auto* type = var->Type()->UnwrapRef();
-  auto* str = type->As<sem::Struct>();
-  if (!str) {
-    TINT_ICE(Writer, builder_.Diagnostics())
-        << "storage variable must be of struct type";
-    return false;
-  }
-  ast::VariableBindingPoint bp = decl->BindingPoint();
-  line() << "layout(binding = " << bp.binding->value << ", std430) buffer "
-         << UniqueIdentifier(StructName(str)) << " {";
-  EmitStructMembers(current_buffer_, str, /* emit_offsets */ true);
-  auto name = builder_.Symbols().NameFor(decl->symbol);
-  line() << "} " << name << ";";
-  return true;
+    auto* decl = var->Declaration();
+    auto* type = var->Type()->UnwrapRef();
+    auto* str = type->As<sem::Struct>();
+    if (!str) {
+        TINT_ICE(Writer, builder_.Diagnostics()) << "storage variable must be of struct type";
+        return false;
+    }
+    ast::VariableBindingPoint bp = decl->BindingPoint();
+    line() << "layout(binding = " << bp.binding->value << ", std430) buffer "
+           << UniqueIdentifier(StructName(str)) << " {";
+    EmitStructMembers(current_buffer_, str, /* emit_offsets */ true);
+    auto name = builder_.Symbols().NameFor(decl->symbol);
+    line() << "} " << name << ";";
+    return true;
 }
 
 bool GeneratorImpl::EmitHandleVariable(const sem::Variable* var) {
-  auto* decl = var->Declaration();
-  auto out = line();
+    auto* decl = var->Declaration();
+    auto out = line();
 
-  auto name = builder_.Symbols().NameFor(decl->symbol);
-  auto* type = var->Type()->UnwrapRef();
-  if (type->Is<sem::Sampler>()) {
-    // GLSL ignores Sampler variables.
+    auto name = builder_.Symbols().NameFor(decl->symbol);
+    auto* type = var->Type()->UnwrapRef();
+    if (type->Is<sem::Sampler>()) {
+        // GLSL ignores Sampler variables.
+        return true;
+    }
+    if (auto* storage = type->As<sem::StorageTexture>()) {
+        out << "layout(" << convert_texel_format_to_glsl(storage->texel_format()) << ") ";
+    }
+    if (!EmitTypeAndName(out, type, var->StorageClass(), var->Access(), name)) {
+        return false;
+    }
+
+    out << ";";
     return true;
-  }
-  if (auto* storage = type->As<sem::StorageTexture>()) {
-    out << "layout(" << convert_texel_format_to_glsl(storage->texel_format())
-        << ") ";
-  }
-  if (!EmitTypeAndName(out, type, var->StorageClass(), var->Access(), name)) {
-    return false;
-  }
-
-  out << ";";
-  return true;
 }
 
 bool GeneratorImpl::EmitPrivateVariable(const sem::Variable* var) {
-  auto* decl = var->Declaration();
-  auto out = line();
+    auto* decl = var->Declaration();
+    auto out = line();
 
-  auto name = builder_.Symbols().NameFor(decl->symbol);
-  auto* type = var->Type()->UnwrapRef();
-  if (!EmitTypeAndName(out, type, var->StorageClass(), var->Access(), name)) {
-    return false;
-  }
-
-  out << " = ";
-  if (auto* constructor = decl->constructor) {
-    if (!EmitExpression(out, constructor)) {
-      return false;
+    auto name = builder_.Symbols().NameFor(decl->symbol);
+    auto* type = var->Type()->UnwrapRef();
+    if (!EmitTypeAndName(out, type, var->StorageClass(), var->Access(), name)) {
+        return false;
     }
-  } else {
-    if (!EmitZeroValue(out, var->Type()->UnwrapRef())) {
-      return false;
-    }
-  }
 
-  out << ";";
-  return true;
+    out << " = ";
+    if (auto* constructor = decl->constructor) {
+        if (!EmitExpression(out, constructor)) {
+            return false;
+        }
+    } else {
+        if (!EmitZeroValue(out, var->Type()->UnwrapRef())) {
+            return false;
+        }
+    }
+
+    out << ";";
+    return true;
 }
 
 bool GeneratorImpl::EmitWorkgroupVariable(const sem::Variable* var) {
-  auto* decl = var->Declaration();
-  auto out = line();
+    auto* decl = var->Declaration();
+    auto out = line();
 
-  out << "shared ";
+    out << "shared ";
 
-  auto name = builder_.Symbols().NameFor(decl->symbol);
-  auto* type = var->Type()->UnwrapRef();
-  if (!EmitTypeAndName(out, type, var->StorageClass(), var->Access(), name)) {
-    return false;
-  }
-
-  if (auto* constructor = decl->constructor) {
-    out << " = ";
-    if (!EmitExpression(out, constructor)) {
-      return false;
+    auto name = builder_.Symbols().NameFor(decl->symbol);
+    auto* type = var->Type()->UnwrapRef();
+    if (!EmitTypeAndName(out, type, var->StorageClass(), var->Access(), name)) {
+        return false;
     }
-  }
 
-  out << ";";
-  return true;
+    if (auto* constructor = decl->constructor) {
+        out << " = ";
+        if (!EmitExpression(out, constructor)) {
+            return false;
+        }
+    }
+
+    out << ";";
+    return true;
 }
 
 bool GeneratorImpl::EmitIOVariable(const sem::Variable* var) {
-  auto* decl = var->Declaration();
+    auto* decl = var->Declaration();
 
-  if (auto* b = ast::GetAttribute<ast::BuiltinAttribute>(decl->attributes)) {
-    // Use of gl_SampleID requires the GL_OES_sample_variables extension
-    if (RequiresOESSampleVariables(b->builtin)) {
-      requires_oes_sample_variables_ = true;
+    if (auto* b = ast::GetAttribute<ast::BuiltinAttribute>(decl->attributes)) {
+        // Use of gl_SampleID requires the GL_OES_sample_variables extension
+        if (RequiresOESSampleVariables(b->builtin)) {
+            requires_oes_sample_variables_ = true;
+        }
+        // Do not emit builtin (gl_) variables.
+        return true;
     }
-    // Do not emit builtin (gl_) variables.
+
+    auto out = line();
+    EmitAttributes(out, decl->attributes);
+    EmitInterpolationQualifiers(out, decl->attributes);
+
+    auto name = builder_.Symbols().NameFor(decl->symbol);
+    auto* type = var->Type()->UnwrapRef();
+    if (!EmitTypeAndName(out, type, var->StorageClass(), var->Access(), name)) {
+        return false;
+    }
+
+    if (auto* constructor = decl->constructor) {
+        out << " = ";
+        if (!EmitExpression(out, constructor)) {
+            return false;
+        }
+    }
+
+    out << ";";
     return true;
-  }
-
-  auto out = line();
-  EmitAttributes(out, decl->attributes);
-  EmitInterpolationQualifiers(out, decl->attributes);
-
-  auto name = builder_.Symbols().NameFor(decl->symbol);
-  auto* type = var->Type()->UnwrapRef();
-  if (!EmitTypeAndName(out, type, var->StorageClass(), var->Access(), name)) {
-    return false;
-  }
-
-  if (auto* constructor = decl->constructor) {
-    out << " = ";
-    if (!EmitExpression(out, constructor)) {
-      return false;
-    }
-  }
-
-  out << ";";
-  return true;
 }
 
-void GeneratorImpl::EmitInterpolationQualifiers(
-    std::ostream& out,
-    const ast::AttributeList& attributes) {
-  for (auto* attr : attributes) {
-    if (auto* interpolate = attr->As<ast::InterpolateAttribute>()) {
-      switch (interpolate->type) {
-        case ast::InterpolationType::kPerspective:
-        case ast::InterpolationType::kLinear:
-          break;
-        case ast::InterpolationType::kFlat:
-          out << "flat ";
-          break;
-      }
-      switch (interpolate->sampling) {
-        case ast::InterpolationSampling::kCentroid:
-          out << "centroid ";
-          break;
-        case ast::InterpolationSampling::kSample:
-        case ast::InterpolationSampling::kCenter:
-        case ast::InterpolationSampling::kNone:
-          break;
-      }
+void GeneratorImpl::EmitInterpolationQualifiers(std::ostream& out,
+                                                const ast::AttributeList& attributes) {
+    for (auto* attr : attributes) {
+        if (auto* interpolate = attr->As<ast::InterpolateAttribute>()) {
+            switch (interpolate->type) {
+                case ast::InterpolationType::kPerspective:
+                case ast::InterpolationType::kLinear:
+                    break;
+                case ast::InterpolationType::kFlat:
+                    out << "flat ";
+                    break;
+            }
+            switch (interpolate->sampling) {
+                case ast::InterpolationSampling::kCentroid:
+                    out << "centroid ";
+                    break;
+                case ast::InterpolationSampling::kSample:
+                case ast::InterpolationSampling::kCenter:
+                case ast::InterpolationSampling::kNone:
+                    break;
+            }
+        }
     }
-  }
 }
 
-bool GeneratorImpl::EmitAttributes(std::ostream& out,
-                                   const ast::AttributeList& attributes) {
-  if (attributes.empty()) {
-    return true;
-  }
-  bool first = true;
-  for (auto* attr : attributes) {
-    if (auto* location = attr->As<ast::LocationAttribute>()) {
-      out << (first ? "layout(" : ", ");
-      out << "location = " << std::to_string(location->value);
-      first = false;
+bool GeneratorImpl::EmitAttributes(std::ostream& out, const ast::AttributeList& attributes) {
+    if (attributes.empty()) {
+        return true;
     }
-  }
-  if (!first) {
-    out << ") ";
-  }
-  return true;
+    bool first = true;
+    for (auto* attr : attributes) {
+        if (auto* location = attr->As<ast::LocationAttribute>()) {
+            out << (first ? "layout(" : ", ");
+            out << "location = " << std::to_string(location->value);
+            first = false;
+        }
+    }
+    if (!first) {
+        out << ") ";
+    }
+    return true;
 }
 
 bool GeneratorImpl::EmitEntryPointFunction(const ast::Function* func) {
-  auto* func_sem = builder_.Sem().Get(func);
+    auto* func_sem = builder_.Sem().Get(func);
 
-  if (func->PipelineStage() == ast::PipelineStage::kFragment) {
-    requires_default_precision_qualifier_ = true;
-  }
+    if (func->PipelineStage() == ast::PipelineStage::kFragment) {
+        requires_default_precision_qualifier_ = true;
+    }
 
-  if (func->PipelineStage() == ast::PipelineStage::kCompute) {
-    auto out = line();
-    // Emit the layout(local_size) attributes.
-    auto wgsize = func_sem->WorkgroupSize();
-    out << "layout(";
-    for (int i = 0; i < 3; i++) {
-      if (i > 0) {
-        out << ", ";
-      }
-      out << "local_size_" << (i == 0 ? "x" : i == 1 ? "y" : "z") << " = ";
+    if (func->PipelineStage() == ast::PipelineStage::kCompute) {
+        auto out = line();
+        // Emit the layout(local_size) attributes.
+        auto wgsize = func_sem->WorkgroupSize();
+        out << "layout(";
+        for (int i = 0; i < 3; i++) {
+            if (i > 0) {
+                out << ", ";
+            }
+            out << "local_size_" << (i == 0 ? "x" : i == 1 ? "y" : "z") << " = ";
 
-      if (wgsize[i].overridable_const) {
-        auto* global = builder_.Sem().Get<sem::GlobalVariable>(
-            wgsize[i].overridable_const);
-        if (!global->IsOverridable()) {
-          TINT_ICE(Writer, builder_.Diagnostics())
-              << "expected a pipeline-overridable constant";
+            if (wgsize[i].overridable_const) {
+                auto* global = builder_.Sem().Get<sem::GlobalVariable>(wgsize[i].overridable_const);
+                if (!global->IsOverridable()) {
+                    TINT_ICE(Writer, builder_.Diagnostics())
+                        << "expected a pipeline-overridable constant";
+                }
+                out << kSpecConstantPrefix << global->ConstantId();
+            } else {
+                out << std::to_string(wgsize[i].value);
+            }
         }
-        out << kSpecConstantPrefix << global->ConstantId();
-      } else {
-        out << std::to_string(wgsize[i].value);
-      }
-    }
-    out << ") in;";
-  }
-
-  // Emit original entry point signature
-  {
-    auto out = line();
-    out << func->return_type->FriendlyName(builder_.Symbols()) << " "
-        << builder_.Symbols().NameFor(func->symbol) << "(";
-
-    bool first = true;
-
-    // Emit entry point parameters.
-    for (auto* var : func->params) {
-      auto* sem = builder_.Sem().Get(var);
-      auto* type = sem->Type();
-      if (!type->Is<sem::Struct>()) {
-        // ICE likely indicates that the CanonicalizeEntryPointIO transform was
-        // not run, or a builtin parameter was added after it was run.
-        TINT_ICE(Writer, diagnostics_)
-            << "Unsupported non-struct entry point parameter";
-      }
-
-      if (!first) {
-        out << ", ";
-      }
-      first = false;
-
-      if (!EmitTypeAndName(out, type, sem->StorageClass(), sem->Access(),
-                           builder_.Symbols().NameFor(var->symbol))) {
-        return false;
-      }
+        out << ") in;";
     }
 
-    out << ") {";
-  }
+    // Emit original entry point signature
+    {
+        auto out = line();
+        out << func->return_type->FriendlyName(builder_.Symbols()) << " "
+            << builder_.Symbols().NameFor(func->symbol) << "(";
 
-  // Emit original entry point function body
-  {
-    ScopedIndent si(this);
+        bool first = true;
 
-    if (!EmitStatements(func->body->statements)) {
-      return false;
+        // Emit entry point parameters.
+        for (auto* var : func->params) {
+            auto* sem = builder_.Sem().Get(var);
+            auto* type = sem->Type();
+            if (!type->Is<sem::Struct>()) {
+                // ICE likely indicates that the CanonicalizeEntryPointIO transform was
+                // not run, or a builtin parameter was added after it was run.
+                TINT_ICE(Writer, diagnostics_) << "Unsupported non-struct entry point parameter";
+            }
+
+            if (!first) {
+                out << ", ";
+            }
+            first = false;
+
+            if (!EmitTypeAndName(out, type, sem->StorageClass(), sem->Access(),
+                                 builder_.Symbols().NameFor(var->symbol))) {
+                return false;
+            }
+        }
+
+        out << ") {";
     }
 
-    if (!Is<ast::ReturnStatement>(func->body->Last())) {
-      ast::ReturnStatement ret(ProgramID(), Source{});
-      if (!EmitStatement(&ret)) {
-        return false;
-      }
+    // Emit original entry point function body
+    {
+        ScopedIndent si(this);
+        if (func->PipelineStage() == ast::PipelineStage::kVertex) {
+            line() << "gl_PointSize = 1.0;";
+        }
+
+        if (!EmitStatements(func->body->statements)) {
+            return false;
+        }
+
+        if (!Is<ast::ReturnStatement>(func->body->Last())) {
+            ast::ReturnStatement ret(ProgramID(), Source{});
+            if (!EmitStatement(&ret)) {
+                return false;
+            }
+        }
     }
-  }
 
-  line() << "}";
+    line() << "}";
 
-  return true;
+    return true;
 }
 
-bool GeneratorImpl::EmitLiteral(std::ostream& out,
-                                const ast::LiteralExpression* lit) {
-  if (auto* l = lit->As<ast::BoolLiteralExpression>()) {
-    out << (l->value ? "true" : "false");
-  } else if (auto* fl = lit->As<ast::FloatLiteralExpression>()) {
-    if (std::isinf(fl->value)) {
-      out << (fl->value >= 0 ? "uintBitsToFloat(0x7f800000u)"
-                             : "uintBitsToFloat(0xff800000u)");
-    } else if (std::isnan(fl->value)) {
-      out << "uintBitsToFloat(0x7fc00000u)";
-    } else {
-      out << FloatToString(fl->value) << "f";
-    }
-  } else if (auto* sl = lit->As<ast::SintLiteralExpression>()) {
-    out << sl->value;
-  } else if (auto* ul = lit->As<ast::UintLiteralExpression>()) {
-    out << ul->value << "u";
-  } else {
-    diagnostics_.add_error(diag::System::Writer, "unknown literal type");
-    return false;
-  }
-  return true;
+bool GeneratorImpl::EmitLiteral(std::ostream& out, const ast::LiteralExpression* lit) {
+    return Switch(
+        lit,
+        [&](const ast::BoolLiteralExpression* l) {
+            out << (l->value ? "true" : "false");
+            return true;
+        },
+        [&](const ast::FloatLiteralExpression* l) {
+            if (std::isinf(l->value)) {
+                out << (l->value >= 0 ? "uintBitsToFloat(0x7f800000u)"
+                                      : "uintBitsToFloat(0xff800000u)");
+            } else if (std::isnan(l->value)) {
+                out << "uintBitsToFloat(0x7fc00000u)";
+            } else {
+                out << FloatToString(l->value) << "f";
+            }
+            return true;
+        },
+        [&](const ast::IntLiteralExpression* l) {
+            out << l->value;
+            if (l->suffix == ast::IntLiteralExpression::Suffix::kU) {
+                out << "u";
+            }
+            return true;
+        },
+        [&](Default) {
+            diagnostics_.add_error(diag::System::Writer, "unknown literal type");
+            return false;
+        });
 }
 
 bool GeneratorImpl::EmitZeroValue(std::ostream& out, const sem::Type* type) {
-  if (type->Is<sem::Bool>()) {
-    out << "false";
-  } else if (type->Is<sem::F32>()) {
-    out << "0.0f";
-  } else if (type->Is<sem::I32>()) {
-    out << "0";
-  } else if (type->Is<sem::U32>()) {
-    out << "0u";
-  } else if (auto* vec = type->As<sem::Vector>()) {
-    if (!EmitType(out, type, ast::StorageClass::kNone, ast::Access::kReadWrite,
-                  "")) {
-      return false;
-    }
-    ScopedParen sp(out);
-    for (uint32_t i = 0; i < vec->Width(); i++) {
-      if (i != 0) {
-        out << ", ";
-      }
-      if (!EmitZeroValue(out, vec->type())) {
+    if (type->Is<sem::Bool>()) {
+        out << "false";
+    } else if (type->Is<sem::F32>()) {
+        out << "0.0f";
+    } else if (type->Is<sem::I32>()) {
+        out << "0";
+    } else if (type->Is<sem::U32>()) {
+        out << "0u";
+    } else if (auto* vec = type->As<sem::Vector>()) {
+        if (!EmitType(out, type, ast::StorageClass::kNone, ast::Access::kReadWrite, "")) {
+            return false;
+        }
+        ScopedParen sp(out);
+        for (uint32_t i = 0; i < vec->Width(); i++) {
+            if (i != 0) {
+                out << ", ";
+            }
+            if (!EmitZeroValue(out, vec->type())) {
+                return false;
+            }
+        }
+    } else if (auto* mat = type->As<sem::Matrix>()) {
+        if (!EmitType(out, type, ast::StorageClass::kNone, ast::Access::kReadWrite, "")) {
+            return false;
+        }
+        ScopedParen sp(out);
+        for (uint32_t i = 0; i < (mat->rows() * mat->columns()); i++) {
+            if (i != 0) {
+                out << ", ";
+            }
+            if (!EmitZeroValue(out, mat->type())) {
+                return false;
+            }
+        }
+    } else if (auto* str = type->As<sem::Struct>()) {
+        if (!EmitType(out, type, ast::StorageClass::kNone, ast::Access::kUndefined, "")) {
+            return false;
+        }
+        bool first = true;
+        out << "(";
+        for (auto* member : str->Members()) {
+            if (!first) {
+                out << ", ";
+            } else {
+                first = false;
+            }
+            EmitZeroValue(out, member->Type());
+        }
+        out << ")";
+    } else if (auto* array = type->As<sem::Array>()) {
+        if (!EmitType(out, type, ast::StorageClass::kNone, ast::Access::kUndefined, "")) {
+            return false;
+        }
+        out << "(";
+        for (uint32_t i = 0; i < array->Count(); i++) {
+            if (i != 0) {
+                out << ", ";
+            }
+            EmitZeroValue(out, array->ElemType());
+        }
+        out << ")";
+    } else {
+        diagnostics_.add_error(diag::System::Writer, "Invalid type for zero emission: " +
+                                                         type->FriendlyName(builder_.Symbols()));
         return false;
-      }
     }
-  } else if (auto* mat = type->As<sem::Matrix>()) {
-    if (!EmitType(out, type, ast::StorageClass::kNone, ast::Access::kReadWrite,
-                  "")) {
-      return false;
-    }
-    ScopedParen sp(out);
-    for (uint32_t i = 0; i < (mat->rows() * mat->columns()); i++) {
-      if (i != 0) {
-        out << ", ";
-      }
-      if (!EmitZeroValue(out, mat->type())) {
-        return false;
-      }
-    }
-  } else if (auto* str = type->As<sem::Struct>()) {
-    if (!EmitType(out, type, ast::StorageClass::kNone, ast::Access::kUndefined,
-                  "")) {
-      return false;
-    }
-    bool first = true;
-    out << "(";
-    for (auto* member : str->Members()) {
-      if (!first) {
-        out << ", ";
-      } else {
-        first = false;
-      }
-      EmitZeroValue(out, member->Type());
-    }
-    out << ")";
-  } else if (auto* array = type->As<sem::Array>()) {
-    if (!EmitType(out, type, ast::StorageClass::kNone, ast::Access::kUndefined,
-                  "")) {
-      return false;
-    }
-    out << "(";
-    for (uint32_t i = 0; i < array->Count(); i++) {
-      if (i != 0) {
-        out << ", ";
-      }
-      EmitZeroValue(out, array->ElemType());
-    }
-    out << ")";
-  } else {
-    diagnostics_.add_error(diag::System::Writer,
-                           "Invalid type for zero emission: " +
-                               type->FriendlyName(builder_.Symbols()));
-    return false;
-  }
-  return true;
+    return true;
 }
 
 bool GeneratorImpl::EmitLoop(const ast::LoopStatement* stmt) {
-  auto emit_continuing = [this, stmt]() {
-    if (stmt->continuing && !stmt->continuing->Empty()) {
-      if (!EmitBlock(stmt->continuing)) {
-        return false;
-      }
-    }
-    return true;
-  };
-
-  TINT_SCOPED_ASSIGNMENT(emit_continuing_, emit_continuing);
-  line() << "while (true) {";
-  {
-    ScopedIndent si(this);
-    if (!EmitStatements(stmt->body->statements)) {
-      return false;
-    }
-    if (!emit_continuing_()) {
-      return false;
-    }
-  }
-  line() << "}";
-
-  return true;
-}
-
-bool GeneratorImpl::EmitForLoop(const ast::ForLoopStatement* stmt) {
-  // Nest a for loop with a new block. In HLSL the initializer scope is not
-  // nested by the for-loop, so we may get variable redefinitions.
-  line() << "{";
-  increment_indent();
-  TINT_DEFER({
-    decrement_indent();
-    line() << "}";
-  });
-
-  TextBuffer init_buf;
-  if (auto* init = stmt->initializer) {
-    TINT_SCOPED_ASSIGNMENT(current_buffer_, &init_buf);
-    if (!EmitStatement(init)) {
-      return false;
-    }
-  }
-
-  TextBuffer cond_pre;
-  std::stringstream cond_buf;
-  if (auto* cond = stmt->condition) {
-    TINT_SCOPED_ASSIGNMENT(current_buffer_, &cond_pre);
-    if (!EmitExpression(cond_buf, cond)) {
-      return false;
-    }
-  }
-
-  TextBuffer cont_buf;
-  if (auto* cont = stmt->continuing) {
-    TINT_SCOPED_ASSIGNMENT(current_buffer_, &cont_buf);
-    if (!EmitStatement(cont)) {
-      return false;
-    }
-  }
-
-  // If the for-loop has a multi-statement conditional and / or continuing, then
-  // we cannot emit this as a regular for-loop in HLSL. Instead we need to
-  // generate a `while(true)` loop.
-  bool emit_as_loop = cond_pre.lines.size() > 0 || cont_buf.lines.size() > 1;
-
-  // If the for-loop has multi-statement initializer, or is going to be emitted
-  // as a `while(true)` loop, then declare the initializer statement(s) before
-  // the loop.
-  if (init_buf.lines.size() > 1 || (stmt->initializer && emit_as_loop)) {
-    current_buffer_->Append(init_buf);
-    init_buf.lines.clear();  // Don't emit the initializer again in the 'for'
-  }
-
-  if (emit_as_loop) {
-    auto emit_continuing = [&]() {
-      current_buffer_->Append(cont_buf);
-      return true;
+    auto emit_continuing = [this, stmt]() {
+        if (stmt->continuing && !stmt->continuing->Empty()) {
+            if (!EmitBlock(stmt->continuing)) {
+                return false;
+            }
+        }
+        return true;
     };
 
     TINT_SCOPED_ASSIGNMENT(emit_continuing_, emit_continuing);
     line() << "while (true) {";
-    increment_indent();
-    TINT_DEFER({
-      decrement_indent();
-      line() << "}";
-    });
-
-    if (stmt->condition) {
-      current_buffer_->Append(cond_pre);
-      line() << "if (!(" << cond_buf.str() << ")) { break; }";
-    }
-
-    if (!EmitStatements(stmt->body->statements)) {
-      return false;
-    }
-
-    if (!emit_continuing_()) {
-      return false;
-    }
-  } else {
-    // For-loop can be generated.
     {
-      auto out = line();
-      out << "for";
-      {
-        ScopedParen sp(out);
-
-        if (!init_buf.lines.empty()) {
-          out << init_buf.lines[0].content << " ";
-        } else {
-          out << "; ";
+        ScopedIndent si(this);
+        if (!EmitStatements(stmt->body->statements)) {
+            return false;
         }
-
-        out << cond_buf.str() << "; ";
-
-        if (!cont_buf.lines.empty()) {
-          out << TrimSuffix(cont_buf.lines[0].content, ";");
+        if (!emit_continuing_()) {
+            return false;
         }
-      }
-      out << " {";
-    }
-    {
-      auto emit_continuing = [] { return true; };
-      TINT_SCOPED_ASSIGNMENT(emit_continuing_, emit_continuing);
-      if (!EmitStatementsWithIndent(stmt->body->statements)) {
-        return false;
-      }
     }
     line() << "}";
-  }
 
-  return true;
+    return true;
 }
 
-bool GeneratorImpl::EmitMemberAccessor(
-    std::ostream& out,
-    const ast::MemberAccessorExpression* expr) {
-  if (!EmitExpression(out, expr->structure)) {
-    return false;
-  }
-  out << ".";
+bool GeneratorImpl::EmitForLoop(const ast::ForLoopStatement* stmt) {
+    // Nest a for loop with a new block. In HLSL the initializer scope is not
+    // nested by the for-loop, so we may get variable redefinitions.
+    line() << "{";
+    increment_indent();
+    TINT_DEFER({
+        decrement_indent();
+        line() << "}";
+    });
 
-  // Swizzles output the name directly
-  if (builder_.Sem().Get(expr)->Is<sem::Swizzle>()) {
-    out << builder_.Symbols().NameFor(expr->member->symbol);
-  } else if (!EmitExpression(out, expr->member)) {
-    return false;
-  }
+    TextBuffer init_buf;
+    if (auto* init = stmt->initializer) {
+        TINT_SCOPED_ASSIGNMENT(current_buffer_, &init_buf);
+        if (!EmitStatement(init)) {
+            return false;
+        }
+    }
 
-  return true;
+    TextBuffer cond_pre;
+    std::stringstream cond_buf;
+    if (auto* cond = stmt->condition) {
+        TINT_SCOPED_ASSIGNMENT(current_buffer_, &cond_pre);
+        if (!EmitExpression(cond_buf, cond)) {
+            return false;
+        }
+    }
+
+    TextBuffer cont_buf;
+    if (auto* cont = stmt->continuing) {
+        TINT_SCOPED_ASSIGNMENT(current_buffer_, &cont_buf);
+        if (!EmitStatement(cont)) {
+            return false;
+        }
+    }
+
+    // If the for-loop has a multi-statement conditional and / or continuing, then
+    // we cannot emit this as a regular for-loop in HLSL. Instead we need to
+    // generate a `while(true)` loop.
+    bool emit_as_loop = cond_pre.lines.size() > 0 || cont_buf.lines.size() > 1;
+
+    // If the for-loop has multi-statement initializer, or is going to be emitted
+    // as a `while(true)` loop, then declare the initializer statement(s) before
+    // the loop.
+    if (init_buf.lines.size() > 1 || (stmt->initializer && emit_as_loop)) {
+        current_buffer_->Append(init_buf);
+        init_buf.lines.clear();  // Don't emit the initializer again in the 'for'
+    }
+
+    if (emit_as_loop) {
+        auto emit_continuing = [&]() {
+            current_buffer_->Append(cont_buf);
+            return true;
+        };
+
+        TINT_SCOPED_ASSIGNMENT(emit_continuing_, emit_continuing);
+        line() << "while (true) {";
+        increment_indent();
+        TINT_DEFER({
+            decrement_indent();
+            line() << "}";
+        });
+
+        if (stmt->condition) {
+            current_buffer_->Append(cond_pre);
+            line() << "if (!(" << cond_buf.str() << ")) { break; }";
+        }
+
+        if (!EmitStatements(stmt->body->statements)) {
+            return false;
+        }
+
+        if (!emit_continuing_()) {
+            return false;
+        }
+    } else {
+        // For-loop can be generated.
+        {
+            auto out = line();
+            out << "for";
+            {
+                ScopedParen sp(out);
+
+                if (!init_buf.lines.empty()) {
+                    out << init_buf.lines[0].content << " ";
+                } else {
+                    out << "; ";
+                }
+
+                out << cond_buf.str() << "; ";
+
+                if (!cont_buf.lines.empty()) {
+                    out << TrimSuffix(cont_buf.lines[0].content, ";");
+                }
+            }
+            out << " {";
+        }
+        {
+            auto emit_continuing = [] { return true; };
+            TINT_SCOPED_ASSIGNMENT(emit_continuing_, emit_continuing);
+            if (!EmitStatementsWithIndent(stmt->body->statements)) {
+                return false;
+            }
+        }
+        line() << "}";
+    }
+
+    return true;
+}
+
+bool GeneratorImpl::EmitMemberAccessor(std::ostream& out,
+                                       const ast::MemberAccessorExpression* expr) {
+    if (!EmitExpression(out, expr->structure)) {
+        return false;
+    }
+    out << ".";
+
+    // Swizzles output the name directly
+    if (builder_.Sem().Get(expr)->Is<sem::Swizzle>()) {
+        out << builder_.Symbols().NameFor(expr->member->symbol);
+    } else if (!EmitExpression(out, expr->member)) {
+        return false;
+    }
+
+    return true;
 }
 
 bool GeneratorImpl::EmitReturn(const ast::ReturnStatement* stmt) {
-  if (stmt->value) {
-    auto out = line();
-    out << "return ";
-    if (!EmitExpression(out, stmt->value)) {
-      return false;
+    if (stmt->value) {
+        auto out = line();
+        out << "return ";
+        if (!EmitExpression(out, stmt->value)) {
+            return false;
+        }
+        out << ";";
+    } else {
+        line() << "return;";
     }
-    out << ";";
-  } else {
-    line() << "return;";
-  }
-  return true;
+    return true;
 }
 
 bool GeneratorImpl::EmitStatement(const ast::Statement* stmt) {
-  if (auto* a = stmt->As<ast::AssignmentStatement>()) {
-    return EmitAssign(a);
-  }
-  if (auto* b = stmt->As<ast::BlockStatement>()) {
-    return EmitBlock(b);
-  }
-  if (auto* b = stmt->As<ast::BreakStatement>()) {
-    return EmitBreak(b);
-  }
-  if (auto* c = stmt->As<ast::CallStatement>()) {
-    auto out = line();
-    if (!EmitCall(out, c->expr)) {
-      return false;
+    if (auto* a = stmt->As<ast::AssignmentStatement>()) {
+        return EmitAssign(a);
     }
-    out << ";";
-    return true;
-  }
-  if (auto* c = stmt->As<ast::ContinueStatement>()) {
-    return EmitContinue(c);
-  }
-  if (auto* d = stmt->As<ast::DiscardStatement>()) {
-    return EmitDiscard(d);
-  }
-  if (stmt->As<ast::FallthroughStatement>()) {
-    line() << "/* fallthrough */";
-    return true;
-  }
-  if (auto* i = stmt->As<ast::IfStatement>()) {
-    return EmitIf(i);
-  }
-  if (auto* l = stmt->As<ast::LoopStatement>()) {
-    return EmitLoop(l);
-  }
-  if (auto* l = stmt->As<ast::ForLoopStatement>()) {
-    return EmitForLoop(l);
-  }
-  if (auto* r = stmt->As<ast::ReturnStatement>()) {
-    return EmitReturn(r);
-  }
-  if (auto* s = stmt->As<ast::SwitchStatement>()) {
-    return EmitSwitch(s);
-  }
-  if (auto* v = stmt->As<ast::VariableDeclStatement>()) {
-    return EmitVariable(v->variable);
-  }
+    if (auto* b = stmt->As<ast::BlockStatement>()) {
+        return EmitBlock(b);
+    }
+    if (auto* b = stmt->As<ast::BreakStatement>()) {
+        return EmitBreak(b);
+    }
+    if (auto* c = stmt->As<ast::CallStatement>()) {
+        auto out = line();
+        if (!EmitCall(out, c->expr)) {
+            return false;
+        }
+        out << ";";
+        return true;
+    }
+    if (auto* c = stmt->As<ast::ContinueStatement>()) {
+        return EmitContinue(c);
+    }
+    if (auto* d = stmt->As<ast::DiscardStatement>()) {
+        return EmitDiscard(d);
+    }
+    if (stmt->As<ast::FallthroughStatement>()) {
+        line() << "/* fallthrough */";
+        return true;
+    }
+    if (auto* i = stmt->As<ast::IfStatement>()) {
+        return EmitIf(i);
+    }
+    if (auto* l = stmt->As<ast::LoopStatement>()) {
+        return EmitLoop(l);
+    }
+    if (auto* l = stmt->As<ast::ForLoopStatement>()) {
+        return EmitForLoop(l);
+    }
+    if (auto* r = stmt->As<ast::ReturnStatement>()) {
+        return EmitReturn(r);
+    }
+    if (auto* s = stmt->As<ast::SwitchStatement>()) {
+        return EmitSwitch(s);
+    }
+    if (auto* v = stmt->As<ast::VariableDeclStatement>()) {
+        return EmitVariable(v->variable);
+    }
 
-  diagnostics_.add_error(
-      diag::System::Writer,
-      "unknown statement type: " + std::string(stmt->TypeInfo().name));
-  return false;
+    diagnostics_.add_error(diag::System::Writer,
+                           "unknown statement type: " + std::string(stmt->TypeInfo().name));
+    return false;
 }
 
 bool GeneratorImpl::EmitSwitch(const ast::SwitchStatement* stmt) {
-  {  // switch(expr) {
-    auto out = line();
-    out << "switch(";
-    if (!EmitExpression(out, stmt->condition)) {
-      return false;
+    {  // switch(expr) {
+        auto out = line();
+        out << "switch(";
+        if (!EmitExpression(out, stmt->condition)) {
+            return false;
+        }
+        out << ") {";
     }
-    out << ") {";
-  }
 
-  {
-    ScopedIndent si(this);
-    for (auto* s : stmt->body) {
-      if (!EmitCase(s)) {
-        return false;
-      }
+    {
+        ScopedIndent si(this);
+        for (auto* s : stmt->body) {
+            if (!EmitCase(s)) {
+                return false;
+            }
+        }
     }
-  }
 
-  line() << "}";
+    line() << "}";
 
-  return true;
+    return true;
 }
 
 bool GeneratorImpl::EmitType(std::ostream& out,
@@ -2574,161 +2512,161 @@
                              ast::Access access,
                              const std::string& name,
                              bool* name_printed /* = nullptr */) {
-  if (name_printed) {
-    *name_printed = false;
-  }
-  switch (storage_class) {
-    case ast::StorageClass::kInput: {
-      out << "in ";
-      break;
+    if (name_printed) {
+        *name_printed = false;
     }
-    case ast::StorageClass::kOutput: {
-      out << "out ";
-      break;
-    }
-    case ast::StorageClass::kUniform:
-    case ast::StorageClass::kUniformConstant: {
-      out << "uniform ";
-      break;
-    }
-    default:
-      break;
-  }
-
-  if (auto* ary = type->As<sem::Array>()) {
-    const sem::Type* base_type = ary;
-    std::vector<uint32_t> sizes;
-    while (auto* arr = base_type->As<sem::Array>()) {
-      sizes.push_back(arr->Count());
-      base_type = arr->ElemType();
-    }
-    if (!EmitType(out, base_type, storage_class, access, "")) {
-      return false;
-    }
-    if (!name.empty()) {
-      out << " " << name;
-      if (name_printed) {
-        *name_printed = true;
-      }
-    }
-    for (uint32_t size : sizes) {
-      if (size > 0) {
-        out << "[" << size << "]";
-      } else {
-        out << "[]";
-      }
-    }
-  } else if (type->Is<sem::Bool>()) {
-    out << "bool";
-  } else if (type->Is<sem::F32>()) {
-    out << "float";
-  } else if (type->Is<sem::I32>()) {
-    out << "int";
-  } else if (auto* mat = type->As<sem::Matrix>()) {
-    TINT_ASSERT(Writer, mat->type()->Is<sem::F32>());
-    out << "mat" << mat->columns();
-    if (mat->rows() != mat->columns()) {
-      out << "x" << mat->rows();
-    }
-  } else if (type->Is<sem::Pointer>()) {
-    TINT_ICE(Writer, diagnostics_)
-        << "Attempting to emit pointer type. These should have been removed "
-           "with the InlinePointerLets transform";
-    return false;
-  } else if (type->Is<sem::Sampler>()) {
-    return false;
-  } else if (auto* str = type->As<sem::Struct>()) {
-    out << StructName(str);
-  } else if (auto* tex = type->As<sem::Texture>()) {
-    if (tex->Is<sem::ExternalTexture>()) {
-      TINT_ICE(Writer, diagnostics_)
-          << "Multiplanar external texture transform was not run.";
-      return false;
+    switch (storage_class) {
+        case ast::StorageClass::kInput: {
+            out << "in ";
+            break;
+        }
+        case ast::StorageClass::kOutput: {
+            out << "out ";
+            break;
+        }
+        case ast::StorageClass::kUniform:
+        case ast::StorageClass::kHandle: {
+            out << "uniform ";
+            break;
+        }
+        default:
+            break;
     }
 
-    auto* storage = tex->As<sem::StorageTexture>();
-    auto* ms = tex->As<sem::MultisampledTexture>();
-    auto* depth_ms = tex->As<sem::DepthMultisampledTexture>();
-    auto* sampled = tex->As<sem::SampledTexture>();
+    if (auto* ary = type->As<sem::Array>()) {
+        const sem::Type* base_type = ary;
+        std::vector<uint32_t> sizes;
+        while (auto* arr = base_type->As<sem::Array>()) {
+            sizes.push_back(arr->Count());
+            base_type = arr->ElemType();
+        }
+        if (!EmitType(out, base_type, storage_class, access, "")) {
+            return false;
+        }
+        if (!name.empty()) {
+            out << " " << name;
+            if (name_printed) {
+                *name_printed = true;
+            }
+        }
+        for (uint32_t size : sizes) {
+            if (size > 0) {
+                out << "[" << size << "]";
+            } else {
+                out << "[]";
+            }
+        }
+    } else if (type->Is<sem::Bool>()) {
+        out << "bool";
+    } else if (type->Is<sem::F32>()) {
+        out << "float";
+    } else if (type->Is<sem::I32>()) {
+        out << "int";
+    } else if (auto* mat = type->As<sem::Matrix>()) {
+        TINT_ASSERT(Writer, mat->type()->Is<sem::F32>());
+        out << "mat" << mat->columns();
+        if (mat->rows() != mat->columns()) {
+            out << "x" << mat->rows();
+        }
+    } else if (type->Is<sem::Pointer>()) {
+        TINT_ICE(Writer, diagnostics_)
+            << "Attempting to emit pointer type. These should have been removed "
+               "with the InlinePointerLets transform";
+        return false;
+    } else if (type->Is<sem::Sampler>()) {
+        return false;
+    } else if (auto* str = type->As<sem::Struct>()) {
+        out << StructName(str);
+    } else if (auto* tex = type->As<sem::Texture>()) {
+        if (tex->Is<sem::ExternalTexture>()) {
+            TINT_ICE(Writer, diagnostics_) << "Multiplanar external texture transform was not run.";
+            return false;
+        }
 
-    out << "highp ";
+        auto* storage = tex->As<sem::StorageTexture>();
+        auto* ms = tex->As<sem::MultisampledTexture>();
+        auto* depth_ms = tex->As<sem::DepthMultisampledTexture>();
+        auto* sampled = tex->As<sem::SampledTexture>();
 
-    if (storage && storage->access() != ast::Access::kRead) {
-      out << "writeonly ";
-    }
-    auto* subtype = sampled
-                        ? sampled->type()
-                        : storage ? storage->type() : ms ? ms->type() : nullptr;
-    if (!subtype || subtype->Is<sem::F32>()) {
-    } else if (subtype->Is<sem::I32>()) {
-      out << "i";
-    } else if (subtype->Is<sem::U32>()) {
-      out << "u";
+        out << "highp ";
+
+        if (storage && storage->access() != ast::Access::kRead) {
+            out << "writeonly ";
+        }
+        auto* subtype = sampled   ? sampled->type()
+                        : storage ? storage->type()
+                        : ms      ? ms->type()
+                                  : nullptr;
+        if (!subtype || subtype->Is<sem::F32>()) {
+        } else if (subtype->Is<sem::I32>()) {
+            out << "i";
+        } else if (subtype->Is<sem::U32>()) {
+            out << "u";
+        } else {
+            TINT_ICE(Writer, diagnostics_) << "Unsupported texture type";
+            return false;
+        }
+
+        out << (storage ? "image" : "sampler");
+
+        switch (tex->dim()) {
+            case ast::TextureDimension::k1d:
+                out << "1D";
+                break;
+            case ast::TextureDimension::k2d:
+                out << ((ms || depth_ms) ? "2DMS" : "2D");
+                break;
+            case ast::TextureDimension::k2dArray:
+                out << ((ms || depth_ms) ? "2DMSArray" : "2DArray");
+                break;
+            case ast::TextureDimension::k3d:
+                out << "3D";
+                break;
+            case ast::TextureDimension::kCube:
+                out << "Cube";
+                break;
+            case ast::TextureDimension::kCubeArray:
+                out << "CubeArray";
+                break;
+            default:
+                TINT_UNREACHABLE(Writer, diagnostics_)
+                    << "unexpected TextureDimension " << tex->dim();
+                return false;
+        }
+        if (tex->Is<sem::DepthTexture>()) {
+            out << "Shadow";
+        }
+    } else if (type->Is<sem::U32>()) {
+        out << "uint";
+    } else if (auto* vec = type->As<sem::Vector>()) {
+        auto width = vec->Width();
+        if (vec->type()->Is<sem::F32>() && width >= 1 && width <= 4) {
+            out << "vec" << width;
+        } else if (vec->type()->Is<sem::I32>() && width >= 1 && width <= 4) {
+            out << "ivec" << width;
+        } else if (vec->type()->Is<sem::U32>() && width >= 1 && width <= 4) {
+            out << "uvec" << width;
+        } else if (vec->type()->Is<sem::Bool>() && width >= 1 && width <= 4) {
+            out << "bvec" << width;
+        } else {
+            out << "vector<";
+            if (!EmitType(out, vec->type(), storage_class, access, "")) {
+                return false;
+            }
+            out << ", " << width << ">";
+        }
+    } else if (auto* atomic = type->As<sem::Atomic>()) {
+        if (!EmitType(out, atomic->Type(), storage_class, access, name)) {
+            return false;
+        }
+    } else if (type->Is<sem::Void>()) {
+        out << "void";
     } else {
-      TINT_ICE(Writer, diagnostics_) << "Unsupported texture type";
-      return false;
-    }
-
-    out << (storage ? "image" : "sampler");
-
-    switch (tex->dim()) {
-      case ast::TextureDimension::k1d:
-        out << "1D";
-        break;
-      case ast::TextureDimension::k2d:
-        out << ((ms || depth_ms) ? "2DMS" : "2D");
-        break;
-      case ast::TextureDimension::k2dArray:
-        out << ((ms || depth_ms) ? "2DMSArray" : "2DArray");
-        break;
-      case ast::TextureDimension::k3d:
-        out << "3D";
-        break;
-      case ast::TextureDimension::kCube:
-        out << "Cube";
-        break;
-      case ast::TextureDimension::kCubeArray:
-        out << "CubeArray";
-        break;
-      default:
-        TINT_UNREACHABLE(Writer, diagnostics_)
-            << "unexpected TextureDimension " << tex->dim();
+        diagnostics_.add_error(diag::System::Writer, "unknown type in EmitType");
         return false;
     }
-    if (tex->Is<sem::DepthTexture>()) {
-      out << "Shadow";
-    }
-  } else if (type->Is<sem::U32>()) {
-    out << "uint";
-  } else if (auto* vec = type->As<sem::Vector>()) {
-    auto width = vec->Width();
-    if (vec->type()->Is<sem::F32>() && width >= 1 && width <= 4) {
-      out << "vec" << width;
-    } else if (vec->type()->Is<sem::I32>() && width >= 1 && width <= 4) {
-      out << "ivec" << width;
-    } else if (vec->type()->Is<sem::U32>() && width >= 1 && width <= 4) {
-      out << "uvec" << width;
-    } else if (vec->type()->Is<sem::Bool>() && width >= 1 && width <= 4) {
-      out << "bvec" << width;
-    } else {
-      out << "vector<";
-      if (!EmitType(out, vec->type(), storage_class, access, "")) {
-        return false;
-      }
-      out << ", " << width << ">";
-    }
-  } else if (auto* atomic = type->As<sem::Atomic>()) {
-    if (!EmitType(out, atomic->Type(), storage_class, access, name)) {
-      return false;
-    }
-  } else if (type->Is<sem::Void>()) {
-    out << "void";
-  } else {
-    diagnostics_.add_error(diag::System::Writer, "unknown type in EmitType");
-    return false;
-  }
 
-  return true;
+    return true;
 }
 
 bool GeneratorImpl::EmitTypeAndName(std::ostream& out,
@@ -2736,171 +2674,165 @@
                                     ast::StorageClass storage_class,
                                     ast::Access access,
                                     const std::string& name) {
-  bool printed_name = false;
-  if (!EmitType(out, type, storage_class, access, name, &printed_name)) {
-    return false;
-  }
-  if (!name.empty() && !printed_name) {
-    out << " " << name;
-  }
-  return true;
+    bool printed_name = false;
+    if (!EmitType(out, type, storage_class, access, name, &printed_name)) {
+        return false;
+    }
+    if (!name.empty() && !printed_name) {
+        out << " " << name;
+    }
+    return true;
 }
 
 bool GeneratorImpl::EmitStructType(TextBuffer* b, const sem::Struct* str) {
-  auto storage_class_uses = str->StorageClassUsage();
-  line(b) << "struct " << StructName(str) << " {";
-  EmitStructMembers(b, str, false);
-  line(b) << "};";
-  line(b);
+    auto storage_class_uses = str->StorageClassUsage();
+    line(b) << "struct " << StructName(str) << " {";
+    EmitStructMembers(b, str, false);
+    line(b) << "};";
+    line(b);
 
-  return true;
+    return true;
 }
 
-bool GeneratorImpl::EmitStructMembers(TextBuffer* b,
-                                      const sem::Struct* str,
-                                      bool emit_offsets) {
-  ScopedIndent si(b);
-  for (auto* mem : str->Members()) {
-    auto name = builder_.Symbols().NameFor(mem->Name());
+bool GeneratorImpl::EmitStructMembers(TextBuffer* b, const sem::Struct* str, bool emit_offsets) {
+    ScopedIndent si(b);
+    for (auto* mem : str->Members()) {
+        auto name = builder_.Symbols().NameFor(mem->Name());
 
-    auto* ty = mem->Type();
+        auto* ty = mem->Type();
 
-    auto out = line(b);
+        auto out = line(b);
 
-    // Note: offsets are unsupported on GLSL ES.
-    if (emit_offsets && version_.IsDesktop() && mem->Offset() != 0) {
-      out << "layout(offset=" << mem->Offset() << ") ";
+        // Note: offsets are unsupported on GLSL ES.
+        if (emit_offsets && version_.IsDesktop() && mem->Offset() != 0) {
+            out << "layout(offset=" << mem->Offset() << ") ";
+        }
+        if (!EmitTypeAndName(out, ty, ast::StorageClass::kNone, ast::Access::kReadWrite, name)) {
+            return false;
+        }
+        out << ";";
     }
-    if (!EmitTypeAndName(out, ty, ast::StorageClass::kNone,
-                         ast::Access::kReadWrite, name)) {
-      return false;
-    }
-    out << ";";
-  }
-  return true;
+    return true;
 }
 
-bool GeneratorImpl::EmitUnaryOp(std::ostream& out,
-                                const ast::UnaryOpExpression* expr) {
-  switch (expr->op) {
-    case ast::UnaryOp::kIndirection:
-    case ast::UnaryOp::kAddressOf:
-      return EmitExpression(out, expr->expr);
-    case ast::UnaryOp::kComplement:
-      out << "~";
-      break;
-    case ast::UnaryOp::kNot:
-      if (TypeOf(expr)->UnwrapRef()->is_scalar()) {
-        out << "!";
-      } else {
-        out << "not";
-      }
-      break;
-    case ast::UnaryOp::kNegation:
-      out << "-";
-      break;
-  }
-  out << "(";
+bool GeneratorImpl::EmitUnaryOp(std::ostream& out, const ast::UnaryOpExpression* expr) {
+    switch (expr->op) {
+        case ast::UnaryOp::kIndirection:
+        case ast::UnaryOp::kAddressOf:
+            return EmitExpression(out, expr->expr);
+        case ast::UnaryOp::kComplement:
+            out << "~";
+            break;
+        case ast::UnaryOp::kNot:
+            if (TypeOf(expr)->UnwrapRef()->is_scalar()) {
+                out << "!";
+            } else {
+                out << "not";
+            }
+            break;
+        case ast::UnaryOp::kNegation:
+            out << "-";
+            break;
+    }
+    out << "(";
 
-  if (!EmitExpression(out, expr->expr)) {
-    return false;
-  }
+    if (!EmitExpression(out, expr->expr)) {
+        return false;
+    }
 
-  out << ")";
+    out << ")";
 
-  return true;
+    return true;
 }
 
 bool GeneratorImpl::EmitVariable(const ast::Variable* var) {
-  auto* sem = builder_.Sem().Get(var);
-  auto* type = sem->Type()->UnwrapRef();
+    auto* sem = builder_.Sem().Get(var);
+    auto* type = sem->Type()->UnwrapRef();
 
-  // TODO(dsinclair): Handle variable attributes
-  if (!var->attributes.empty()) {
-    diagnostics_.add_error(diag::System::Writer,
-                           "Variable attributes are not handled yet");
-    return false;
-  }
-
-  auto out = line();
-  // TODO(senorblanco): handle const
-  if (!EmitTypeAndName(out, type, sem->StorageClass(), sem->Access(),
-                       builder_.Symbols().NameFor(var->symbol))) {
-    return false;
-  }
-
-  out << " = ";
-
-  if (var->constructor) {
-    if (!EmitExpression(out, var->constructor)) {
-      return false;
+    // TODO(dsinclair): Handle variable attributes
+    if (!var->attributes.empty()) {
+        diagnostics_.add_error(diag::System::Writer, "Variable attributes are not handled yet");
+        return false;
     }
-  } else {
-    if (!EmitZeroValue(out, type)) {
-      return false;
-    }
-  }
-  out << ";";
 
-  return true;
+    auto out = line();
+    // TODO(senorblanco): handle const
+    if (!EmitTypeAndName(out, type, sem->StorageClass(), sem->Access(),
+                         builder_.Symbols().NameFor(var->symbol))) {
+        return false;
+    }
+
+    out << " = ";
+
+    if (var->constructor) {
+        if (!EmitExpression(out, var->constructor)) {
+            return false;
+        }
+    } else {
+        if (!EmitZeroValue(out, type)) {
+            return false;
+        }
+    }
+    out << ";";
+
+    return true;
 }
 
 bool GeneratorImpl::EmitProgramConstVariable(const ast::Variable* var) {
-  for (auto* d : var->attributes) {
-    if (!d->Is<ast::IdAttribute>()) {
-      diagnostics_.add_error(diag::System::Writer,
-                             "Decorated const values not valid");
-      return false;
+    for (auto* d : var->attributes) {
+        if (!d->Is<ast::IdAttribute>()) {
+            diagnostics_.add_error(diag::System::Writer, "Decorated const values not valid");
+            return false;
+        }
     }
-  }
-  if (!var->is_const) {
-    diagnostics_.add_error(diag::System::Writer, "Expected a const value");
-    return false;
-  }
-
-  auto* sem = builder_.Sem().Get(var);
-  auto* type = sem->Type();
-
-  auto* global = sem->As<sem::GlobalVariable>();
-  if (global && global->IsOverridable()) {
-    auto const_id = global->ConstantId();
-
-    line() << "#ifndef " << kSpecConstantPrefix << const_id;
-
-    if (var->constructor != nullptr) {
-      auto out = line();
-      out << "#define " << kSpecConstantPrefix << const_id << " ";
-      if (!EmitExpression(out, var->constructor)) {
+    if (!var->is_const) {
+        diagnostics_.add_error(diag::System::Writer, "Expected a const value");
         return false;
-      }
+    }
+
+    auto* sem = builder_.Sem().Get(var);
+    auto* type = sem->Type();
+
+    auto* global = sem->As<sem::GlobalVariable>();
+    if (global && global->IsOverridable()) {
+        auto const_id = global->ConstantId();
+
+        line() << "#ifndef " << kSpecConstantPrefix << const_id;
+
+        if (var->constructor != nullptr) {
+            auto out = line();
+            out << "#define " << kSpecConstantPrefix << const_id << " ";
+            if (!EmitExpression(out, var->constructor)) {
+                return false;
+            }
+        } else {
+            line() << "#error spec constant required for constant id " << const_id;
+        }
+        line() << "#endif";
+        {
+            auto out = line();
+            out << "const ";
+            if (!EmitTypeAndName(out, type, sem->StorageClass(), sem->Access(),
+                                 builder_.Symbols().NameFor(var->symbol))) {
+                return false;
+            }
+            out << " = " << kSpecConstantPrefix << const_id << ";";
+        }
     } else {
-      line() << "#error spec constant required for constant id " << const_id;
+        auto out = line();
+        out << "const ";
+        if (!EmitTypeAndName(out, type, sem->StorageClass(), sem->Access(),
+                             builder_.Symbols().NameFor(var->symbol))) {
+            return false;
+        }
+        out << " = ";
+        if (!EmitExpression(out, var->constructor)) {
+            return false;
+        }
+        out << ";";
     }
-    line() << "#endif";
-    {
-      auto out = line();
-      out << "const ";
-      if (!EmitTypeAndName(out, type, sem->StorageClass(), sem->Access(),
-                           builder_.Symbols().NameFor(var->symbol))) {
-        return false;
-      }
-      out << " = " << kSpecConstantPrefix << const_id << ";";
-    }
-  } else {
-    auto out = line();
-    out << "const ";
-    if (!EmitTypeAndName(out, type, sem->StorageClass(), sem->Access(),
-                         builder_.Symbols().NameFor(var->symbol))) {
-      return false;
-    }
-    out << " = ";
-    if (!EmitExpression(out, var->constructor)) {
-      return false;
-    }
-    out << ";";
-  }
 
-  return true;
+    return true;
 }
 
 template <typename F>
@@ -2908,84 +2840,82 @@
                                       const ast::CallExpression* call,
                                       const sem::Builtin* builtin,
                                       F&& build) {
-  // Generate the helper function if it hasn't been created already
-  auto fn = utils::GetOrCreate(builtins_, builtin, [&]() -> std::string {
-    TextBuffer b;
-    TINT_DEFER(helpers_.Append(b));
+    // Generate the helper function if it hasn't been created already
+    auto fn = utils::GetOrCreate(builtins_, builtin, [&]() -> std::string {
+        TextBuffer b;
+        TINT_DEFER(helpers_.Append(b));
 
-    auto fn_name =
-        UniqueIdentifier(std::string("tint_") + sem::str(builtin->Type()));
-    std::vector<std::string> parameter_names;
-    {
-      auto decl = line(&b);
-      if (!EmitTypeAndName(decl, builtin->ReturnType(),
-                           ast::StorageClass::kNone, ast::Access::kUndefined,
-                           fn_name)) {
-        return "";
-      }
-      {
-        ScopedParen sp(decl);
-        for (auto* param : builtin->Parameters()) {
-          if (!parameter_names.empty()) {
-            decl << ", ";
-          }
-          auto param_name = "param_" + std::to_string(parameter_names.size());
-          const auto* ty = param->Type();
-          if (auto* ptr = ty->As<sem::Pointer>()) {
-            decl << "inout ";
-            ty = ptr->StoreType();
-          }
-          if (!EmitTypeAndName(decl, ty, ast::StorageClass::kNone,
-                               ast::Access::kUndefined, param_name)) {
-            return "";
-          }
-          parameter_names.emplace_back(std::move(param_name));
+        auto fn_name = UniqueIdentifier(std::string("tint_") + sem::str(builtin->Type()));
+        std::vector<std::string> parameter_names;
+        {
+            auto decl = line(&b);
+            if (!EmitTypeAndName(decl, builtin->ReturnType(), ast::StorageClass::kNone,
+                                 ast::Access::kUndefined, fn_name)) {
+                return "";
+            }
+            {
+                ScopedParen sp(decl);
+                for (auto* param : builtin->Parameters()) {
+                    if (!parameter_names.empty()) {
+                        decl << ", ";
+                    }
+                    auto param_name = "param_" + std::to_string(parameter_names.size());
+                    const auto* ty = param->Type();
+                    if (auto* ptr = ty->As<sem::Pointer>()) {
+                        decl << "inout ";
+                        ty = ptr->StoreType();
+                    }
+                    if (!EmitTypeAndName(decl, ty, ast::StorageClass::kNone,
+                                         ast::Access::kUndefined, param_name)) {
+                        return "";
+                    }
+                    parameter_names.emplace_back(std::move(param_name));
+                }
+            }
+            decl << " {";
         }
-      }
-      decl << " {";
-    }
-    {
-      ScopedIndent si(&b);
-      if (!build(&b, parameter_names)) {
-        return "";
-      }
-    }
-    line(&b) << "}";
-    line(&b);
-    return fn_name;
-  });
+        {
+            ScopedIndent si(&b);
+            if (!build(&b, parameter_names)) {
+                return "";
+            }
+        }
+        line(&b) << "}";
+        line(&b);
+        return fn_name;
+    });
 
-  if (fn.empty()) {
-    return false;
-  }
-
-  // Call the helper
-  out << fn;
-  {
-    ScopedParen sp(out);
-    bool first = true;
-    for (auto* arg : call->args) {
-      if (!first) {
-        out << ", ";
-      }
-      first = false;
-      if (!EmitExpression(out, arg)) {
+    if (fn.empty()) {
         return false;
-      }
     }
-  }
-  return true;
+
+    // Call the helper
+    out << fn;
+    {
+        ScopedParen sp(out);
+        bool first = true;
+        for (auto* arg : call->args) {
+            if (!first) {
+                out << ", ";
+            }
+            first = false;
+            if (!EmitExpression(out, arg)) {
+                return false;
+            }
+        }
+    }
+    return true;
 }
 
 sem::Type* GeneratorImpl::BoolTypeToUint(const sem::Type* type) {
-  auto* u32 = builder_.create<sem::U32>();
-  if (type->Is<sem::Bool>()) {
-    return u32;
-  } else if (auto* vec = type->As<sem::Vector>()) {
-    return builder_.create<sem::Vector>(u32, vec->Width());
-  } else {
-    return nullptr;
-  }
+    auto* u32 = builder_.create<sem::U32>();
+    if (type->Is<sem::Bool>()) {
+        return u32;
+    } else if (auto* vec = type->As<sem::Vector>()) {
+        return builder_.create<sem::Vector>(u32, vec->Width());
+    } else {
+        return nullptr;
+    }
 }
 
 }  // namespace tint::writer::glsl
diff --git a/src/tint/writer/glsl/generator_impl.h b/src/tint/writer/glsl/generator_impl.h
index 9104182..72def34 100644
--- a/src/tint/writer/glsl/generator_impl.h
+++ b/src/tint/writer/glsl/generator_impl.h
@@ -51,15 +51,15 @@
 
 /// The result of sanitizing a program for generation.
 struct SanitizedResult {
-  /// Constructor
-  SanitizedResult();
-  /// Destructor
-  ~SanitizedResult();
-  /// Move constructor
-  SanitizedResult(SanitizedResult&&);
+    /// Constructor
+    SanitizedResult();
+    /// Destructor
+    ~SanitizedResult();
+    /// Move constructor
+    SanitizedResult(SanitizedResult&&);
 
-  /// The sanitized program.
-  Program program;
+    /// The sanitized program.
+    Program program;
 };
 
 /// Sanitize a program in preparation for generating GLSL.
@@ -73,451 +73,441 @@
 
 /// Implementation class for GLSL generator
 class GeneratorImpl : public TextGenerator {
- public:
-  /// Constructor
-  /// @param program the program to generate
-  /// @param version the GLSL version to use
-  GeneratorImpl(const Program* program, const Version& version);
-  ~GeneratorImpl();
+  public:
+    /// Constructor
+    /// @param program the program to generate
+    /// @param version the GLSL version to use
+    GeneratorImpl(const Program* program, const Version& version);
+    ~GeneratorImpl();
 
-  /// @returns true on successful generation; false otherwise
-  bool Generate();
+    /// @returns true on successful generation; false otherwise
+    bool Generate();
 
-  /// Handles an index accessor expression
-  /// @param out the output of the expression stream
-  /// @param expr the expression to emit
-  /// @returns true if the index accessor was emitted
-  bool EmitIndexAccessor(std::ostream& out,
-                         const ast::IndexAccessorExpression* expr);
-  /// Handles an assignment statement
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was emitted successfully
-  bool EmitAssign(const ast::AssignmentStatement* stmt);
-  /// Handles emission of bitwise operators (&|) on bool scalars and vectors
-  /// @param out the output of the expression stream
-  /// @param expr the binary expression
-  /// @returns true if the expression was emitted, false otherwise
-  bool EmitBitwiseBoolOp(std::ostream& out, const ast::BinaryExpression* expr);
-  /// Handles generating a binary expression
-  /// @param out the output of the expression stream
-  /// @param expr the binary expression
-  /// @returns true if the expression was emitted, false otherwise
-  bool EmitFloatModulo(std::ostream& out, const ast::BinaryExpression* expr);
-  /// Handles generating the modulo operator on float vector operands
-  /// @param out the output of the expression stream
-  /// @param expr the binary expression
-  /// @returns true if the expression was emitted, false otherwise
-  bool EmitBinary(std::ostream& out, const ast::BinaryExpression* expr);
-  /// Handles generating a bitcast expression
-  /// @param out the output of the expression stream
-  /// @param expr the expression
-  /// @returns true if the binary expression was emitted
-  bool EmitVectorRelational(std::ostream& out,
-                            const ast::BinaryExpression* expr);
-  /// Handles generating a vector relational expression
-  /// @param out the output of the expression stream
-  /// @param expr the expression
-  /// @returns true if the vector relational expression was emitted
-  bool EmitBitcast(std::ostream& out, const ast::BitcastExpression* expr);
-  /// Emits a list of statements
-  /// @param stmts the statement list
-  /// @returns true if the statements were emitted successfully
-  bool EmitStatements(const ast::StatementList& stmts);
-  /// Emits a list of statements with an indentation
-  /// @param stmts the statement list
-  /// @returns true if the statements were emitted successfully
-  bool EmitStatementsWithIndent(const ast::StatementList& stmts);
-  /// Handles a block statement
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was emitted successfully
-  bool EmitBlock(const ast::BlockStatement* stmt);
-  /// Handles a break statement
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was emitted successfully
-  bool EmitBreak(const ast::BreakStatement* stmt);
-  /// Handles generating a call expression
-  /// @param out the output of the expression stream
-  /// @param expr the call expression
-  /// @returns true if the call expression is emitted
-  bool EmitCall(std::ostream& out, const ast::CallExpression* expr);
-  /// Handles generating a function call expression
-  /// @param out the output of the expression stream
-  /// @param call the call expression
-  /// @returns true if the expression is emitted
-  bool EmitFunctionCall(std::ostream& out, const sem::Call* call);
-  /// Handles generating a builtin call expression
-  /// @param out the output of the expression stream
-  /// @param call the call expression
-  /// @param builtin the builtin being called
-  /// @returns true if the expression is emitted
-  bool EmitBuiltinCall(std::ostream& out,
-                       const sem::Call* call,
-                       const sem::Builtin* builtin);
-  /// Handles generating a type conversion expression
-  /// @param out the output of the expression stream
-  /// @param call the call expression
-  /// @param conv the type conversion
-  /// @returns true if the expression is emitted
-  bool EmitTypeConversion(std::ostream& out,
-                          const sem::Call* call,
-                          const sem::TypeConversion* conv);
-  /// Handles generating a type constructor expression
-  /// @param out the output of the expression stream
-  /// @param call the call expression
-  /// @param ctor the type constructor
-  /// @returns true if the expression is emitted
-  bool EmitTypeConstructor(std::ostream& out,
-                           const sem::Call* call,
-                           const sem::TypeConstructor* ctor);
-  /// Handles generating a barrier builtin call
-  /// @param out the output of the expression stream
-  /// @param builtin the semantic information for the barrier builtin
-  /// @returns true if the call expression is emitted
-  bool EmitBarrierCall(std::ostream& out, const sem::Builtin* builtin);
-  /// Handles generating an atomic intrinsic call for a storage buffer variable
-  /// @param out the output of the expression stream
-  /// @param expr the call expression
-  /// @param intrinsic the atomic intrinsic
-  /// @returns true if the call expression is emitted
-  bool EmitStorageAtomicCall(
-      std::ostream& out,
-      const ast::CallExpression* expr,
-      const transform::DecomposeMemoryAccess::Intrinsic* intrinsic);
-  /// Handles generating an atomic builtin call for a workgroup variable
-  /// @param out the output of the expression stream
-  /// @param expr the call expression
-  /// @param builtin the semantic information for the atomic builtin
-  /// @returns true if the call expression is emitted
-  bool EmitWorkgroupAtomicCall(std::ostream& out,
+    /// Record an extension directive within the generator
+    /// @param ext the extension to record
+    /// @returns true if the extension directive was recorded successfully
+    bool RecordExtension(const ast::Enable* ext);
+    /// Handles an index accessor expression
+    /// @param out the output of the expression stream
+    /// @param expr the expression to emit
+    /// @returns true if the index accessor was emitted
+    bool EmitIndexAccessor(std::ostream& out, const ast::IndexAccessorExpression* expr);
+    /// Handles an assignment statement
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was emitted successfully
+    bool EmitAssign(const ast::AssignmentStatement* stmt);
+    /// Handles emission of bitwise operators (&|) on bool scalars and vectors
+    /// @param out the output of the expression stream
+    /// @param expr the binary expression
+    /// @returns true if the expression was emitted, false otherwise
+    bool EmitBitwiseBoolOp(std::ostream& out, const ast::BinaryExpression* expr);
+    /// Handles generating a binary expression
+    /// @param out the output of the expression stream
+    /// @param expr the binary expression
+    /// @returns true if the expression was emitted, false otherwise
+    bool EmitFloatModulo(std::ostream& out, const ast::BinaryExpression* expr);
+    /// Handles generating the modulo operator on float vector operands
+    /// @param out the output of the expression stream
+    /// @param expr the binary expression
+    /// @returns true if the expression was emitted, false otherwise
+    bool EmitBinary(std::ostream& out, const ast::BinaryExpression* expr);
+    /// Handles generating a bitcast expression
+    /// @param out the output of the expression stream
+    /// @param expr the expression
+    /// @returns true if the binary expression was emitted
+    bool EmitVectorRelational(std::ostream& out, const ast::BinaryExpression* expr);
+    /// Handles generating a vector relational expression
+    /// @param out the output of the expression stream
+    /// @param expr the expression
+    /// @returns true if the vector relational expression was emitted
+    bool EmitBitcast(std::ostream& out, const ast::BitcastExpression* expr);
+    /// Emits a list of statements
+    /// @param stmts the statement list
+    /// @returns true if the statements were emitted successfully
+    bool EmitStatements(const ast::StatementList& stmts);
+    /// Emits a list of statements with an indentation
+    /// @param stmts the statement list
+    /// @returns true if the statements were emitted successfully
+    bool EmitStatementsWithIndent(const ast::StatementList& stmts);
+    /// Handles a block statement
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was emitted successfully
+    bool EmitBlock(const ast::BlockStatement* stmt);
+    /// Handles a break statement
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was emitted successfully
+    bool EmitBreak(const ast::BreakStatement* stmt);
+    /// Handles generating a call expression
+    /// @param out the output of the expression stream
+    /// @param expr the call expression
+    /// @returns true if the call expression is emitted
+    bool EmitCall(std::ostream& out, const ast::CallExpression* expr);
+    /// Handles generating a function call expression
+    /// @param out the output of the expression stream
+    /// @param call the call expression
+    /// @returns true if the expression is emitted
+    bool EmitFunctionCall(std::ostream& out, const sem::Call* call);
+    /// Handles generating a builtin call expression
+    /// @param out the output of the expression stream
+    /// @param call the call expression
+    /// @param builtin the builtin being called
+    /// @returns true if the expression is emitted
+    bool EmitBuiltinCall(std::ostream& out, const sem::Call* call, const sem::Builtin* builtin);
+    /// Handles generating a type conversion expression
+    /// @param out the output of the expression stream
+    /// @param call the call expression
+    /// @param conv the type conversion
+    /// @returns true if the expression is emitted
+    bool EmitTypeConversion(std::ostream& out,
+                            const sem::Call* call,
+                            const sem::TypeConversion* conv);
+    /// Handles generating a type constructor expression
+    /// @param out the output of the expression stream
+    /// @param call the call expression
+    /// @param ctor the type constructor
+    /// @returns true if the expression is emitted
+    bool EmitTypeConstructor(std::ostream& out,
+                             const sem::Call* call,
+                             const sem::TypeConstructor* ctor);
+    /// Handles generating a barrier builtin call
+    /// @param out the output of the expression stream
+    /// @param builtin the semantic information for the barrier builtin
+    /// @returns true if the call expression is emitted
+    bool EmitBarrierCall(std::ostream& out, const sem::Builtin* builtin);
+    /// Handles generating an atomic intrinsic call for a storage buffer variable
+    /// @param out the output of the expression stream
+    /// @param expr the call expression
+    /// @param intrinsic the atomic intrinsic
+    /// @returns true if the call expression is emitted
+    bool EmitStorageAtomicCall(std::ostream& out,
                                const ast::CallExpression* expr,
-                               const sem::Builtin* builtin);
-  /// Handles generating an array.length() call
-  /// @param out the output of the expression stream
-  /// @param expr the call expression
-  /// @returns true if the array length expression is emitted
-  bool EmitArrayLength(std::ostream& out, const ast::CallExpression* expr);
-  /// Handles generating a call to `bitfieldExtract`
-  /// @param out the output of the expression stream
-  /// @param expr the call expression
-  /// @returns true if the expression is emitted
-  bool EmitExtractBits(std::ostream& out, const ast::CallExpression* expr);
-  /// Handles generating a call to `bitfieldInsert`
-  /// @param out the output of the expression stream
-  /// @param expr the call expression
-  /// @returns true if the expression is emitted
-  bool EmitInsertBits(std::ostream& out, const ast::CallExpression* expr);
-  /// Emulates 'fma' on GLSL ES, where it is unsupported.
-  /// @param out the output of the expression stream
-  /// @param expr the fma() expression
-  /// @returns true if the expression is emitted
-  bool EmitEmulatedFMA(std::ostream& out, const ast::CallExpression* expr);
-  /// Create a float literal zero AST node, and associated semantic nodes.
-  /// @param stmt the statement which will own the semantic expression node
-  /// @returns an AST expression representing 0.0f
-  const ast::Expression* CreateF32Zero(const sem::Statement* stmt);
+                               const transform::DecomposeMemoryAccess::Intrinsic* intrinsic);
+    /// Handles generating an atomic builtin call for a workgroup variable
+    /// @param out the output of the expression stream
+    /// @param expr the call expression
+    /// @param builtin the semantic information for the atomic builtin
+    /// @returns true if the call expression is emitted
+    bool EmitWorkgroupAtomicCall(std::ostream& out,
+                                 const ast::CallExpression* expr,
+                                 const sem::Builtin* builtin);
+    /// Handles generating an array.length() call
+    /// @param out the output of the expression stream
+    /// @param expr the call expression
+    /// @returns true if the array length expression is emitted
+    bool EmitArrayLength(std::ostream& out, const ast::CallExpression* expr);
+    /// Handles generating a call to `bitfieldExtract`
+    /// @param out the output of the expression stream
+    /// @param expr the call expression
+    /// @returns true if the expression is emitted
+    bool EmitExtractBits(std::ostream& out, const ast::CallExpression* expr);
+    /// Handles generating a call to `bitfieldInsert`
+    /// @param out the output of the expression stream
+    /// @param expr the call expression
+    /// @returns true if the expression is emitted
+    bool EmitInsertBits(std::ostream& out, const ast::CallExpression* expr);
+    /// Emulates 'fma' on GLSL ES, where it is unsupported.
+    /// @param out the output of the expression stream
+    /// @param expr the fma() expression
+    /// @returns true if the expression is emitted
+    bool EmitEmulatedFMA(std::ostream& out, const ast::CallExpression* expr);
+    /// Create a float literal zero AST node, and associated semantic nodes.
+    /// @param stmt the statement which will own the semantic expression node
+    /// @returns an AST expression representing 0.0f
+    const ast::Expression* CreateF32Zero(const sem::Statement* stmt);
 
-  /// Handles generating a call to a texture function (`textureSample`,
-  /// `textureSampleGrad`, etc)
-  /// @param out the output of the expression stream
-  /// @param call the call expression
-  /// @param builtin the semantic information for the texture builtin
-  /// @returns true if the call expression is emitted
-  bool EmitTextureCall(std::ostream& out,
-                       const sem::Call* call,
-                       const sem::Builtin* builtin);
-  /// Handles generating a call to the `select()` builtin
-  /// @param out the output of the expression stream
-  /// @param expr the call expression
-  /// @returns true if the call expression is emitted
-  bool EmitCountOneBitsCall(std::ostream& out, const ast::CallExpression* expr);
-  /// Handles generating a call to the `countOneBits()` builtin
-  /// @param out the output of the expression stream
-  /// @param expr the call expression
-  /// @returns true if the call expression is emitted
-  bool EmitSelectCall(std::ostream& out, const ast::CallExpression* expr);
-  /// Handles generating a call to the `dot()` builtin
-  /// @param out the output of the expression stream
-  /// @param expr the call expression
-  /// @param builtin the semantic information for the builtin
-  /// @returns true if the call expression is emitted
-  bool EmitDotCall(std::ostream& out,
-                   const ast::CallExpression* expr,
-                   const sem::Builtin* builtin);
-  /// Handles generating a call to the `modf()` builtin
-  /// @param out the output of the expression stream
-  /// @param expr the call expression
-  /// @param builtin the semantic information for the builtin
-  /// @returns true if the call expression is emitted
-  bool EmitModfCall(std::ostream& out,
-                    const ast::CallExpression* expr,
-                    const sem::Builtin* builtin);
-  /// Handles generating a call to the `frexp()` builtin
-  /// @param out the output of the expression stream
-  /// @param expr the call expression
-  /// @param builtin the semantic information for the builtin
-  /// @returns true if the call expression is emitted
-  bool EmitFrexpCall(std::ostream& out,
+    /// Handles generating a call to a texture function (`textureSample`,
+    /// `textureSampleGrad`, etc)
+    /// @param out the output of the expression stream
+    /// @param call the call expression
+    /// @param builtin the semantic information for the texture builtin
+    /// @returns true if the call expression is emitted
+    bool EmitTextureCall(std::ostream& out, const sem::Call* call, const sem::Builtin* builtin);
+    /// Handles generating a call to the `select()` builtin
+    /// @param out the output of the expression stream
+    /// @param expr the call expression
+    /// @returns true if the call expression is emitted
+    bool EmitCountOneBitsCall(std::ostream& out, const ast::CallExpression* expr);
+    /// Handles generating a call to the `countOneBits()` builtin
+    /// @param out the output of the expression stream
+    /// @param expr the call expression
+    /// @returns true if the call expression is emitted
+    bool EmitSelectCall(std::ostream& out, const ast::CallExpression* expr);
+    /// Handles generating a call to the `dot()` builtin
+    /// @param out the output of the expression stream
+    /// @param expr the call expression
+    /// @param builtin the semantic information for the builtin
+    /// @returns true if the call expression is emitted
+    bool EmitDotCall(std::ostream& out,
                      const ast::CallExpression* expr,
                      const sem::Builtin* builtin);
-  /// Handles generating a call to the `degrees()` builtin
-  /// @param out the output of the expression stream
-  /// @param expr the call expression
-  /// @param builtin the semantic information for the builtin
-  /// @returns true if the call expression is emitted
-  bool EmitDegreesCall(std::ostream& out,
+    /// Handles generating a call to the `modf()` builtin
+    /// @param out the output of the expression stream
+    /// @param expr the call expression
+    /// @param builtin the semantic information for the builtin
+    /// @returns true if the call expression is emitted
+    bool EmitModfCall(std::ostream& out,
+                      const ast::CallExpression* expr,
+                      const sem::Builtin* builtin);
+    /// Handles generating a call to the `frexp()` builtin
+    /// @param out the output of the expression stream
+    /// @param expr the call expression
+    /// @param builtin the semantic information for the builtin
+    /// @returns true if the call expression is emitted
+    bool EmitFrexpCall(std::ostream& out,
                        const ast::CallExpression* expr,
                        const sem::Builtin* builtin);
-  /// Handles generating a call to the `radians()` builtin
-  /// @param out the output of the expression stream
-  /// @param expr the call expression
-  /// @param builtin the semantic information for the builtin
-  /// @returns true if the call expression is emitted
-  bool EmitRadiansCall(std::ostream& out,
-                       const ast::CallExpression* expr,
-                       const sem::Builtin* builtin);
-  /// Handles a case statement
-  /// @param stmt the statement
-  /// @returns true if the statement was emitted successfully
-  bool EmitCase(const ast::CaseStatement* stmt);
-  /// Handles generating a discard statement
-  /// @param stmt the discard statement
-  /// @returns true if the statement was successfully emitted
-  bool EmitDiscard(const ast::DiscardStatement* stmt);
-  /// Handles a continue statement
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was emitted successfully
-  bool EmitContinue(const ast::ContinueStatement* stmt);
-  /// Handles generate an Expression
-  /// @param out the output of the expression stream
-  /// @param expr the expression
-  /// @returns true if the expression was emitted
-  bool EmitExpression(std::ostream& out, const ast::Expression* expr);
-  /// Handles generating a function
-  /// @param func the function to generate
-  /// @returns true if the function was emitted
-  bool EmitFunction(const ast::Function* func);
+    /// Handles generating a call to the `degrees()` builtin
+    /// @param out the output of the expression stream
+    /// @param expr the call expression
+    /// @param builtin the semantic information for the builtin
+    /// @returns true if the call expression is emitted
+    bool EmitDegreesCall(std::ostream& out,
+                         const ast::CallExpression* expr,
+                         const sem::Builtin* builtin);
+    /// Handles generating a call to the `radians()` builtin
+    /// @param out the output of the expression stream
+    /// @param expr the call expression
+    /// @param builtin the semantic information for the builtin
+    /// @returns true if the call expression is emitted
+    bool EmitRadiansCall(std::ostream& out,
+                         const ast::CallExpression* expr,
+                         const sem::Builtin* builtin);
+    /// Handles a case statement
+    /// @param stmt the statement
+    /// @returns true if the statement was emitted successfully
+    bool EmitCase(const ast::CaseStatement* stmt);
+    /// Handles generating a discard statement
+    /// @param stmt the discard statement
+    /// @returns true if the statement was successfully emitted
+    bool EmitDiscard(const ast::DiscardStatement* stmt);
+    /// Handles a continue statement
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was emitted successfully
+    bool EmitContinue(const ast::ContinueStatement* stmt);
+    /// Handles generate an Expression
+    /// @param out the output of the expression stream
+    /// @param expr the expression
+    /// @returns true if the expression was emitted
+    bool EmitExpression(std::ostream& out, const ast::Expression* expr);
+    /// Handles generating a function
+    /// @param func the function to generate
+    /// @returns true if the function was emitted
+    bool EmitFunction(const ast::Function* func);
 
-  /// Handles emitting a global variable
-  /// @param global the global variable
-  /// @returns true on success
-  bool EmitGlobalVariable(const ast::Variable* global);
+    /// Handles emitting a global variable
+    /// @param global the global variable
+    /// @returns true on success
+    bool EmitGlobalVariable(const ast::Variable* global);
 
-  /// Handles emitting a global variable with the uniform storage class
-  /// @param var the global variable
-  /// @returns true on success
-  bool EmitUniformVariable(const sem::Variable* var);
+    /// Handles emitting a global variable with the uniform storage class
+    /// @param var the global variable
+    /// @returns true on success
+    bool EmitUniformVariable(const sem::Variable* var);
 
-  /// Handles emitting a global variable with the storage storage class
-  /// @param var the global variable
-  /// @returns true on success
-  bool EmitStorageVariable(const sem::Variable* var);
+    /// Handles emitting a global variable with the storage storage class
+    /// @param var the global variable
+    /// @returns true on success
+    bool EmitStorageVariable(const sem::Variable* var);
 
-  /// Handles emitting a global variable with the handle storage class
-  /// @param var the global variable
-  /// @returns true on success
-  bool EmitHandleVariable(const sem::Variable* var);
+    /// Handles emitting a global variable with the handle storage class
+    /// @param var the global variable
+    /// @returns true on success
+    bool EmitHandleVariable(const sem::Variable* var);
 
-  /// Handles emitting a global variable with the private storage class
-  /// @param var the global variable
-  /// @returns true on success
-  bool EmitPrivateVariable(const sem::Variable* var);
+    /// Handles emitting a global variable with the private storage class
+    /// @param var the global variable
+    /// @returns true on success
+    bool EmitPrivateVariable(const sem::Variable* var);
 
-  /// Handles emitting a global variable with the workgroup storage class
-  /// @param var the global variable
-  /// @returns true on success
-  bool EmitWorkgroupVariable(const sem::Variable* var);
+    /// Handles emitting a global variable with the workgroup storage class
+    /// @param var the global variable
+    /// @returns true on success
+    bool EmitWorkgroupVariable(const sem::Variable* var);
 
-  /// Handles emitting a global variable with the input or output storage class
-  /// @param var the global variable
-  /// @returns true on success
-  bool EmitIOVariable(const sem::Variable* var);
+    /// Handles emitting a global variable with the input or output storage class
+    /// @param var the global variable
+    /// @returns true on success
+    bool EmitIOVariable(const sem::Variable* var);
 
-  /// Handles emitting interpolation qualifiers
-  /// @param out the output of the expression stream
-  /// @param attrs the attributes
-  void EmitInterpolationQualifiers(std::ostream& out,
-                                   const ast::AttributeList& attrs);
-  /// Handles emitting attributes
-  /// @param out the output of the expression stream
-  /// @param attrs the attributes
-  /// @returns true if the attributes were emitted
-  bool EmitAttributes(std::ostream& out, const ast::AttributeList& attrs);
-  /// Handles emitting the entry point function
-  /// @param func the entry point
-  /// @returns true if the entry point function was emitted
-  bool EmitEntryPointFunction(const ast::Function* func);
-  /// Handles an if statement
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was successfully emitted
-  bool EmitIf(const ast::IfStatement* stmt);
-  /// Handles a literal
-  /// @param out the output stream
-  /// @param lit the literal to emit
-  /// @returns true if the literal was successfully emitted
-  bool EmitLiteral(std::ostream& out, const ast::LiteralExpression* lit);
-  /// Handles a loop statement
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was emitted
-  bool EmitLoop(const ast::LoopStatement* stmt);
-  /// Handles a for loop statement
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was emitted
-  bool EmitForLoop(const ast::ForLoopStatement* stmt);
-  /// Handles generating an identifier expression
-  /// @param out the output of the expression stream
-  /// @param expr the identifier expression
-  /// @returns true if the identifier was emitted
-  bool EmitIdentifier(std::ostream& out, const ast::IdentifierExpression* expr);
-  /// Handles a member accessor expression
-  /// @param out the output of the expression stream
-  /// @param expr the member accessor expression
-  /// @returns true if the member accessor was emitted
-  bool EmitMemberAccessor(std::ostream& out,
-                          const ast::MemberAccessorExpression* expr);
-  /// Handles return statements
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was successfully emitted
-  bool EmitReturn(const ast::ReturnStatement* stmt);
-  /// Handles statement
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was emitted
-  bool EmitStatement(const ast::Statement* stmt);
-  /// Handles generating a switch statement
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was emitted
-  bool EmitSwitch(const ast::SwitchStatement* stmt);
-  /// Handles generating type
-  /// @param out the output stream
-  /// @param type the type to generate
-  /// @param storage_class the storage class of the variable
-  /// @param access the access control type of the variable
-  /// @param name the name of the variable, used for array emission.
-  /// @param name_printed (optional) if not nullptr and an array was printed
-  /// then the boolean is set to true.
-  /// @returns true if the type is emitted
-  bool EmitType(std::ostream& out,
-                const sem::Type* type,
-                ast::StorageClass storage_class,
-                ast::Access access,
-                const std::string& name,
-                bool* name_printed = nullptr);
-  /// Handles generating type and name
-  /// @param out the output stream
-  /// @param type the type to generate
-  /// @param storage_class the storage class of the variable
-  /// @param access the access control type of the variable
-  /// @param name the name to emit
-  /// @returns true if the type is emitted
-  bool EmitTypeAndName(std::ostream& out,
-                       const sem::Type* type,
-                       ast::StorageClass storage_class,
-                       ast::Access access,
-                       const std::string& name);
-  /// Handles generating a structure declaration
-  /// @param buffer the text buffer that the type declaration will be written to
-  /// @param ty the struct to generate
-  /// @returns true if the struct is emitted
-  bool EmitStructType(TextBuffer* buffer, const sem::Struct* ty);
-  /// Handles generating the members of a structure
-  /// @param buffer the text buffer that the struct members will be written to
-  /// @param ty the struct to generate
-  /// @param emit_offsets whether offsets should be emitted as offset=
-  /// @returns true if the struct members are emitted
-  bool EmitStructMembers(TextBuffer* buffer,
-                         const sem::Struct* ty,
-                         bool emit_offsets);
-  /// Handles a unary op expression
-  /// @param out the output of the expression stream
-  /// @param expr the expression to emit
-  /// @returns true if the expression was emitted
-  bool EmitUnaryOp(std::ostream& out, const ast::UnaryOpExpression* expr);
-  /// Emits the zero value for the given type
-  /// @param out the output stream
-  /// @param type the type to emit the value for
-  /// @returns true if the zero value was successfully emitted.
-  bool EmitZeroValue(std::ostream& out, const sem::Type* type);
-  /// Handles generating a variable
-  /// @param var the variable to generate
-  /// @returns true if the variable was emitted
-  bool EmitVariable(const ast::Variable* var);
-  /// Handles generating a program scope constant variable
-  /// @param var the variable to emit
-  /// @returns true if the variable was emitted
-  bool EmitProgramConstVariable(const ast::Variable* var);
-  /// Handles generating a builtin method name
-  /// @param builtin the semantic info for the builtin
-  /// @returns the name or "" if not valid
-  std::string generate_builtin_name(const sem::Builtin* builtin);
-  /// Converts a builtin to a gl_ string
-  /// @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);
-  /// 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);
+    /// Handles emitting interpolation qualifiers
+    /// @param out the output of the expression stream
+    /// @param attrs the attributes
+    void EmitInterpolationQualifiers(std::ostream& out, const ast::AttributeList& attrs);
+    /// Handles emitting attributes
+    /// @param out the output of the expression stream
+    /// @param attrs the attributes
+    /// @returns true if the attributes were emitted
+    bool EmitAttributes(std::ostream& out, const ast::AttributeList& attrs);
+    /// Handles emitting the entry point function
+    /// @param func the entry point
+    /// @returns true if the entry point function was emitted
+    bool EmitEntryPointFunction(const ast::Function* func);
+    /// Handles an if statement
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was successfully emitted
+    bool EmitIf(const ast::IfStatement* stmt);
+    /// Handles a literal
+    /// @param out the output stream
+    /// @param lit the literal to emit
+    /// @returns true if the literal was successfully emitted
+    bool EmitLiteral(std::ostream& out, const ast::LiteralExpression* lit);
+    /// Handles a loop statement
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was emitted
+    bool EmitLoop(const ast::LoopStatement* stmt);
+    /// Handles a for loop statement
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was emitted
+    bool EmitForLoop(const ast::ForLoopStatement* stmt);
+    /// Handles generating an identifier expression
+    /// @param out the output of the expression stream
+    /// @param expr the identifier expression
+    /// @returns true if the identifier was emitted
+    bool EmitIdentifier(std::ostream& out, const ast::IdentifierExpression* expr);
+    /// Handles a member accessor expression
+    /// @param out the output of the expression stream
+    /// @param expr the member accessor expression
+    /// @returns true if the member accessor was emitted
+    bool EmitMemberAccessor(std::ostream& out, const ast::MemberAccessorExpression* expr);
+    /// Handles return statements
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was successfully emitted
+    bool EmitReturn(const ast::ReturnStatement* stmt);
+    /// Handles statement
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was emitted
+    bool EmitStatement(const ast::Statement* stmt);
+    /// Handles generating a switch statement
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was emitted
+    bool EmitSwitch(const ast::SwitchStatement* stmt);
+    /// Handles generating type
+    /// @param out the output stream
+    /// @param type the type to generate
+    /// @param storage_class the storage class of the variable
+    /// @param access the access control type of the variable
+    /// @param name the name of the variable, used for array emission.
+    /// @param name_printed (optional) if not nullptr and an array was printed
+    /// then the boolean is set to true.
+    /// @returns true if the type is emitted
+    bool EmitType(std::ostream& out,
+                  const sem::Type* type,
+                  ast::StorageClass storage_class,
+                  ast::Access access,
+                  const std::string& name,
+                  bool* name_printed = nullptr);
+    /// Handles generating type and name
+    /// @param out the output stream
+    /// @param type the type to generate
+    /// @param storage_class the storage class of the variable
+    /// @param access the access control type of the variable
+    /// @param name the name to emit
+    /// @returns true if the type is emitted
+    bool EmitTypeAndName(std::ostream& out,
+                         const sem::Type* type,
+                         ast::StorageClass storage_class,
+                         ast::Access access,
+                         const std::string& name);
+    /// Handles generating a structure declaration
+    /// @param buffer the text buffer that the type declaration will be written to
+    /// @param ty the struct to generate
+    /// @returns true if the struct is emitted
+    bool EmitStructType(TextBuffer* buffer, const sem::Struct* ty);
+    /// Handles generating the members of a structure
+    /// @param buffer the text buffer that the struct members will be written to
+    /// @param ty the struct to generate
+    /// @param emit_offsets whether offsets should be emitted as offset=
+    /// @returns true if the struct members are emitted
+    bool EmitStructMembers(TextBuffer* buffer, const sem::Struct* ty, bool emit_offsets);
+    /// Handles a unary op expression
+    /// @param out the output of the expression stream
+    /// @param expr the expression to emit
+    /// @returns true if the expression was emitted
+    bool EmitUnaryOp(std::ostream& out, const ast::UnaryOpExpression* expr);
+    /// Emits the zero value for the given type
+    /// @param out the output stream
+    /// @param type the type to emit the value for
+    /// @returns true if the zero value was successfully emitted.
+    bool EmitZeroValue(std::ostream& out, const sem::Type* type);
+    /// Handles generating a variable
+    /// @param var the variable to generate
+    /// @returns true if the variable was emitted
+    bool EmitVariable(const ast::Variable* var);
+    /// Handles generating a program scope constant variable
+    /// @param var the variable to emit
+    /// @returns true if the variable was emitted
+    bool EmitProgramConstVariable(const ast::Variable* var);
+    /// Handles generating a builtin method name
+    /// @param builtin the semantic info for the builtin
+    /// @returns the name or "" if not valid
+    std::string generate_builtin_name(const sem::Builtin* builtin);
+    /// Converts a builtin to a gl_ string
+    /// @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);
+    /// 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);
 
- private:
-  enum class VarType { kIn, kOut };
+  private:
+    enum class VarType { kIn, kOut };
 
-  struct EntryPointData {
-    std::string struct_name;
-    std::string var_name;
-  };
-
-  struct DMAIntrinsic {
-    transform::DecomposeMemoryAccess::Intrinsic::Op op;
-    transform::DecomposeMemoryAccess::Intrinsic::DataType type;
-    bool operator==(const DMAIntrinsic& rhs) const {
-      return op == rhs.op && type == rhs.type;
-    }
-    /// Hasher is a std::hash function for DMAIntrinsic
-    struct Hasher {
-      /// @param i the DMAIntrinsic to hash
-      /// @returns the hash of `i`
-      inline std::size_t operator()(const DMAIntrinsic& i) const {
-        return utils::Hash(i.op, i.type);
-      }
+    struct EntryPointData {
+        std::string struct_name;
+        std::string var_name;
     };
-  };
 
-  /// CallBuiltinHelper will call the builtin helper function, creating it
-  /// if it hasn't been built already. If the builtin needs to be built then
-  /// CallBuiltinHelper will generate the function signature and will call
-  /// `build` to emit the body of the function.
-  /// @param out the output of the expression stream
-  /// @param call the call expression
-  /// @param builtin the semantic information for the builtin
-  /// @param build a function with the signature:
-  ///        `bool(TextBuffer* buffer, const std::vector<std::string>& params)`
-  ///        Where:
-  ///          `buffer` is the body of the generated function
-  ///          `params` is the name of all the generated function parameters
-  /// @returns true if the call expression is emitted
-  template <typename F>
-  bool CallBuiltinHelper(std::ostream& out,
-                         const ast::CallExpression* call,
-                         const sem::Builtin* builtin,
-                         F&& build);
+    struct DMAIntrinsic {
+        transform::DecomposeMemoryAccess::Intrinsic::Op op;
+        transform::DecomposeMemoryAccess::Intrinsic::DataType type;
+        bool operator==(const DMAIntrinsic& rhs) const { return op == rhs.op && type == rhs.type; }
+        /// Hasher is a std::hash function for DMAIntrinsic
+        struct Hasher {
+            /// @param i the DMAIntrinsic to hash
+            /// @returns the hash of `i`
+            inline std::size_t operator()(const DMAIntrinsic& i) const {
+                return utils::Hash(i.op, i.type);
+            }
+        };
+    };
 
-  /// Create a uint type corresponding to the given bool or bool vector type.
-  /// @param type the bool or bool vector type to convert
-  /// @returns the corresponding uint type
-  sem::Type* BoolTypeToUint(const sem::Type* type);
+    /// CallBuiltinHelper will call the builtin helper function, creating it
+    /// if it hasn't been built already. If the builtin needs to be built then
+    /// CallBuiltinHelper will generate the function signature and will call
+    /// `build` to emit the body of the function.
+    /// @param out the output of the expression stream
+    /// @param call the call expression
+    /// @param builtin the semantic information for the builtin
+    /// @param build a function with the signature:
+    ///        `bool(TextBuffer* buffer, const std::vector<std::string>& params)`
+    ///        Where:
+    ///          `buffer` is the body of the generated function
+    ///          `params` is the name of all the generated function parameters
+    /// @returns true if the call expression is emitted
+    template <typename F>
+    bool CallBuiltinHelper(std::ostream& out,
+                           const ast::CallExpression* call,
+                           const sem::Builtin* builtin,
+                           F&& build);
 
-  TextBuffer helpers_;  // Helper functions emitted at the top of the output
-  std::function<bool()> emit_continuing_;
-  std::unordered_map<DMAIntrinsic, std::string, DMAIntrinsic::Hasher>
-      dma_intrinsics_;
-  std::unordered_map<const sem::Builtin*, std::string> builtins_;
-  std::unordered_map<const sem::Struct*, std::string> structure_builders_;
-  std::unordered_map<const sem::Vector*, std::string> dynamic_vector_write_;
-  std::unordered_map<const sem::Vector*, std::string> int_dot_funcs_;
-  std::unordered_map<const sem::Type*, std::string> float_modulo_funcs_;
-  bool requires_oes_sample_variables_ = false;
-  bool requires_default_precision_qualifier_ = false;
-  Version version_;
+    /// Create a uint type corresponding to the given bool or bool vector type.
+    /// @param type the bool or bool vector type to convert
+    /// @returns the corresponding uint type
+    sem::Type* BoolTypeToUint(const sem::Type* type);
+
+    TextBuffer helpers_;  // Helper functions emitted at the top of the output
+    std::function<bool()> emit_continuing_;
+    std::unordered_map<DMAIntrinsic, std::string, DMAIntrinsic::Hasher> dma_intrinsics_;
+    std::unordered_map<const sem::Builtin*, std::string> builtins_;
+    std::unordered_map<const sem::Struct*, std::string> structure_builders_;
+    std::unordered_map<const sem::Vector*, std::string> dynamic_vector_write_;
+    std::unordered_map<const sem::Vector*, std::string> int_dot_funcs_;
+    std::unordered_map<const sem::Type*, std::string> float_modulo_funcs_;
+    bool requires_oes_sample_variables_ = false;
+    bool requires_default_precision_qualifier_ = false;
+    Version version_;
 };
 
 }  // namespace tint::writer::glsl
diff --git a/src/tint/writer/glsl/generator_impl_array_accessor_test.cc b/src/tint/writer/glsl/generator_impl_array_accessor_test.cc
index 7858f9b..d28e560 100644
--- a/src/tint/writer/glsl/generator_impl_array_accessor_test.cc
+++ b/src/tint/writer/glsl/generator_impl_array_accessor_test.cc
@@ -14,21 +14,23 @@
 
 #include "src/tint/writer/glsl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::glsl {
 namespace {
 
 using GlslGeneratorImplTest_Expression = TestHelper;
 
 TEST_F(GlslGeneratorImplTest_Expression, IndexAccessor) {
-  Global("ary", ty.array<i32, 10>(), ast::StorageClass::kPrivate);
-  auto* expr = IndexAccessor("ary", 5);
-  WrapInFunction(expr);
+    Global("ary", ty.array<i32, 10>(), ast::StorageClass::kPrivate);
+    auto* expr = IndexAccessor("ary", 5_i);
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), "ary[5]");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), "ary[5]");
 }
 
 }  // namespace
diff --git a/src/tint/writer/glsl/generator_impl_assign_test.cc b/src/tint/writer/glsl/generator_impl_assign_test.cc
index c0da89e..fbd9f62 100644
--- a/src/tint/writer/glsl/generator_impl_assign_test.cc
+++ b/src/tint/writer/glsl/generator_impl_assign_test.cc
@@ -20,17 +20,17 @@
 using GlslGeneratorImplTest_Assign = TestHelper;
 
 TEST_F(GlslGeneratorImplTest_Assign, Emit_Assign) {
-  Global("lhs", ty.i32(), ast::StorageClass::kPrivate);
-  Global("rhs", ty.i32(), ast::StorageClass::kPrivate);
-  auto* assign = Assign("lhs", "rhs");
-  WrapInFunction(assign);
+    Global("lhs", ty.i32(), ast::StorageClass::kPrivate);
+    Global("rhs", ty.i32(), ast::StorageClass::kPrivate);
+    auto* assign = Assign("lhs", "rhs");
+    WrapInFunction(assign);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(assign)) << gen.error();
-  EXPECT_EQ(gen.result(), "  lhs = rhs;\n");
+    ASSERT_TRUE(gen.EmitStatement(assign)) << gen.error();
+    EXPECT_EQ(gen.result(), "  lhs = rhs;\n");
 }
 
 }  // namespace
diff --git a/src/tint/writer/glsl/generator_impl_binary_test.cc b/src/tint/writer/glsl/generator_impl_binary_test.cc
index 744eef4..970a2b3 100644
--- a/src/tint/writer/glsl/generator_impl_binary_test.cc
+++ b/src/tint/writer/glsl/generator_impl_binary_test.cc
@@ -16,243 +16,233 @@
 #include "src/tint/ast/variable_decl_statement.h"
 #include "src/tint/writer/glsl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::glsl {
 namespace {
 
 using GlslGeneratorImplTest_Binary = TestHelper;
 
 struct BinaryData {
-  const char* result;
-  ast::BinaryOp op;
+    const char* result;
+    ast::BinaryOp op;
 };
 inline std::ostream& operator<<(std::ostream& out, BinaryData data) {
-  out << data.op;
-  return out;
+    out << data.op;
+    return out;
 }
 
 using GlslBinaryTest = TestParamHelper<BinaryData>;
 TEST_P(GlslBinaryTest, Emit_f32) {
-  auto params = GetParam();
+    auto params = GetParam();
 
-  // Skip ops that are illegal for this type
-  if (params.op == ast::BinaryOp::kAnd || params.op == ast::BinaryOp::kOr ||
-      params.op == ast::BinaryOp::kXor ||
-      params.op == ast::BinaryOp::kShiftLeft ||
-      params.op == ast::BinaryOp::kShiftRight ||
-      params.op == ast::BinaryOp::kModulo) {
-    return;
-  }
+    // Skip ops that are illegal for this type
+    if (params.op == ast::BinaryOp::kAnd || params.op == ast::BinaryOp::kOr ||
+        params.op == ast::BinaryOp::kXor || params.op == ast::BinaryOp::kShiftLeft ||
+        params.op == ast::BinaryOp::kShiftRight || params.op == ast::BinaryOp::kModulo) {
+        return;
+    }
 
-  Global("left", ty.f32(), ast::StorageClass::kPrivate);
-  Global("right", ty.f32(), ast::StorageClass::kPrivate);
+    Global("left", ty.f32(), ast::StorageClass::kPrivate);
+    Global("right", ty.f32(), ast::StorageClass::kPrivate);
 
-  auto* left = Expr("left");
-  auto* right = Expr("right");
+    auto* left = Expr("left");
+    auto* right = Expr("right");
 
-  auto* expr = create<ast::BinaryExpression>(params.op, left, right);
+    auto* expr = create<ast::BinaryExpression>(params.op, left, right);
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), params.result);
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), params.result);
 }
 TEST_P(GlslBinaryTest, Emit_u32) {
-  auto params = GetParam();
+    auto params = GetParam();
 
-  Global("left", ty.u32(), ast::StorageClass::kPrivate);
-  Global("right", ty.u32(), ast::StorageClass::kPrivate);
+    Global("left", ty.u32(), ast::StorageClass::kPrivate);
+    Global("right", ty.u32(), ast::StorageClass::kPrivate);
 
-  auto* left = Expr("left");
-  auto* right = Expr("right");
+    auto* left = Expr("left");
+    auto* right = Expr("right");
 
-  auto* expr = create<ast::BinaryExpression>(params.op, left, right);
+    auto* expr = create<ast::BinaryExpression>(params.op, left, right);
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), params.result);
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), params.result);
 }
 TEST_P(GlslBinaryTest, Emit_i32) {
-  auto params = GetParam();
+    auto params = GetParam();
 
-  // Skip ops that are illegal for this type
-  if (params.op == ast::BinaryOp::kShiftLeft ||
-      params.op == ast::BinaryOp::kShiftRight) {
-    return;
-  }
+    // Skip ops that are illegal for this type
+    if (params.op == ast::BinaryOp::kShiftLeft || params.op == ast::BinaryOp::kShiftRight) {
+        return;
+    }
 
-  Global("left", ty.i32(), ast::StorageClass::kPrivate);
-  Global("right", ty.i32(), ast::StorageClass::kPrivate);
+    Global("left", ty.i32(), ast::StorageClass::kPrivate);
+    Global("right", ty.i32(), ast::StorageClass::kPrivate);
 
-  auto* left = Expr("left");
-  auto* right = Expr("right");
+    auto* left = Expr("left");
+    auto* right = Expr("right");
 
-  auto* expr = create<ast::BinaryExpression>(params.op, left, right);
+    auto* expr = create<ast::BinaryExpression>(params.op, left, right);
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), params.result);
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), params.result);
 }
 INSTANTIATE_TEST_SUITE_P(
     GlslGeneratorImplTest,
     GlslBinaryTest,
-    testing::Values(
-        BinaryData{"(left & right)", ast::BinaryOp::kAnd},
-        BinaryData{"(left | right)", ast::BinaryOp::kOr},
-        BinaryData{"(left ^ right)", ast::BinaryOp::kXor},
-        BinaryData{"(left == right)", ast::BinaryOp::kEqual},
-        BinaryData{"(left != right)", ast::BinaryOp::kNotEqual},
-        BinaryData{"(left < right)", ast::BinaryOp::kLessThan},
-        BinaryData{"(left > right)", ast::BinaryOp::kGreaterThan},
-        BinaryData{"(left <= right)", ast::BinaryOp::kLessThanEqual},
-        BinaryData{"(left >= right)", ast::BinaryOp::kGreaterThanEqual},
-        BinaryData{"(left << right)", ast::BinaryOp::kShiftLeft},
-        BinaryData{"(left >> right)", ast::BinaryOp::kShiftRight},
-        BinaryData{"(left + right)", ast::BinaryOp::kAdd},
-        BinaryData{"(left - right)", ast::BinaryOp::kSubtract},
-        BinaryData{"(left * right)", ast::BinaryOp::kMultiply},
-        BinaryData{"(left / right)", ast::BinaryOp::kDivide},
-        BinaryData{"(left % right)", ast::BinaryOp::kModulo}));
+    testing::Values(BinaryData{"(left & right)", ast::BinaryOp::kAnd},
+                    BinaryData{"(left | right)", ast::BinaryOp::kOr},
+                    BinaryData{"(left ^ right)", ast::BinaryOp::kXor},
+                    BinaryData{"(left == right)", ast::BinaryOp::kEqual},
+                    BinaryData{"(left != right)", ast::BinaryOp::kNotEqual},
+                    BinaryData{"(left < right)", ast::BinaryOp::kLessThan},
+                    BinaryData{"(left > right)", ast::BinaryOp::kGreaterThan},
+                    BinaryData{"(left <= right)", ast::BinaryOp::kLessThanEqual},
+                    BinaryData{"(left >= right)", ast::BinaryOp::kGreaterThanEqual},
+                    BinaryData{"(left << right)", ast::BinaryOp::kShiftLeft},
+                    BinaryData{"(left >> right)", ast::BinaryOp::kShiftRight},
+                    BinaryData{"(left + right)", ast::BinaryOp::kAdd},
+                    BinaryData{"(left - right)", ast::BinaryOp::kSubtract},
+                    BinaryData{"(left * right)", ast::BinaryOp::kMultiply},
+                    BinaryData{"(left / right)", ast::BinaryOp::kDivide},
+                    BinaryData{"(left % right)", ast::BinaryOp::kModulo}));
 
 TEST_F(GlslGeneratorImplTest_Binary, Multiply_VectorScalar) {
-  auto* lhs = vec3<f32>(1.f, 1.f, 1.f);
-  auto* rhs = Expr(1.f);
+    auto* lhs = vec3<f32>(1.f, 1.f, 1.f);
+    auto* rhs = Expr(1.f);
 
-  auto* expr =
-      create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
+    auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(),
-            "(vec3(1.0f, 1.0f, 1.0f) * "
-            "1.0f)");
+    std::stringstream out;
+    EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(),
+              "(vec3(1.0f, 1.0f, 1.0f) * "
+              "1.0f)");
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, Multiply_ScalarVector) {
-  auto* lhs = Expr(1.f);
-  auto* rhs = vec3<f32>(1.f, 1.f, 1.f);
+    auto* lhs = Expr(1.f);
+    auto* rhs = vec3<f32>(1.f, 1.f, 1.f);
 
-  auto* expr =
-      create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
+    auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(),
-            "(1.0f * vec3(1.0f, 1.0f, "
-            "1.0f))");
+    std::stringstream out;
+    EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(),
+              "(1.0f * vec3(1.0f, 1.0f, "
+              "1.0f))");
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, Multiply_MatrixScalar) {
-  Global("mat", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
-  auto* lhs = Expr("mat");
-  auto* rhs = Expr(1.f);
+    Global("mat", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
+    auto* lhs = Expr("mat");
+    auto* rhs = Expr(1.f);
 
-  auto* expr =
-      create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
-  WrapInFunction(expr);
+    auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), "(mat * 1.0f)");
+    std::stringstream out;
+    EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), "(mat * 1.0f)");
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, Multiply_ScalarMatrix) {
-  Global("mat", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
-  auto* lhs = Expr(1.f);
-  auto* rhs = Expr("mat");
+    Global("mat", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
+    auto* lhs = Expr(1.f);
+    auto* rhs = Expr("mat");
 
-  auto* expr =
-      create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
-  WrapInFunction(expr);
+    auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), "(1.0f * mat)");
+    std::stringstream out;
+    EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), "(1.0f * mat)");
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, Multiply_MatrixVector) {
-  Global("mat", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
-  auto* lhs = Expr("mat");
-  auto* rhs = vec3<f32>(1.f, 1.f, 1.f);
+    Global("mat", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
+    auto* lhs = Expr("mat");
+    auto* rhs = vec3<f32>(1.f, 1.f, 1.f);
 
-  auto* expr =
-      create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
-  WrapInFunction(expr);
+    auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), "(mat * vec3(1.0f, 1.0f, 1.0f))");
+    std::stringstream out;
+    EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), "(mat * vec3(1.0f, 1.0f, 1.0f))");
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, Multiply_VectorMatrix) {
-  Global("mat", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
-  auto* lhs = vec3<f32>(1.f, 1.f, 1.f);
-  auto* rhs = Expr("mat");
+    Global("mat", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
+    auto* lhs = vec3<f32>(1.f, 1.f, 1.f);
+    auto* rhs = Expr("mat");
 
-  auto* expr =
-      create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
-  WrapInFunction(expr);
+    auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), "(vec3(1.0f, 1.0f, 1.0f) * mat)");
+    std::stringstream out;
+    EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), "(vec3(1.0f, 1.0f, 1.0f) * mat)");
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, Multiply_MatrixMatrix) {
-  Global("lhs", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
-  Global("rhs", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
+    Global("lhs", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
+    Global("rhs", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
 
-  auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply,
-                                             Expr("lhs"), Expr("rhs"));
-  WrapInFunction(expr);
+    auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, Expr("lhs"), Expr("rhs"));
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), "(lhs * rhs)");
+    std::stringstream out;
+    EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), "(lhs * rhs)");
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, Logical_And) {
-  Global("a", ty.bool_(), ast::StorageClass::kPrivate);
-  Global("b", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("a", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("b", ty.bool_(), ast::StorageClass::kPrivate);
 
-  auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd,
-                                             Expr("a"), Expr("b"));
-  WrapInFunction(expr);
+    auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr("a"), Expr("b"));
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), "(tint_tmp)");
-  EXPECT_EQ(gen.result(), R"(bool tint_tmp = a;
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), "(tint_tmp)");
+    EXPECT_EQ(gen.result(), R"(bool tint_tmp = a;
 if (tint_tmp) {
   tint_tmp = b;
 }
@@ -260,56 +250,52 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, ModF32) {
-  Global("a", ty.f32(), ast::StorageClass::kPrivate);
-  Global("b", ty.f32(), ast::StorageClass::kPrivate);
+    Global("a", ty.f32(), ast::StorageClass::kPrivate);
+    Global("b", ty.f32(), ast::StorageClass::kPrivate);
 
-  auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kModulo, Expr("a"),
-                                             Expr("b"));
-  WrapInFunction(expr);
+    auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kModulo, Expr("a"), Expr("b"));
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), "tint_float_modulo(a, b)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), "tint_float_modulo(a, b)");
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, ModVec3F32) {
-  Global("a", ty.vec3<f32>(), ast::StorageClass::kPrivate);
-  Global("b", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+    Global("a", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+    Global("b", ty.vec3<f32>(), ast::StorageClass::kPrivate);
 
-  auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kModulo, Expr("a"),
-                                             Expr("b"));
-  WrapInFunction(expr);
+    auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kModulo, Expr("a"), Expr("b"));
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), "tint_float_modulo(a, b)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), "tint_float_modulo(a, b)");
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, Logical_Multi) {
-  // (a && b) || (c || d)
-  Global("a", ty.bool_(), ast::StorageClass::kPrivate);
-  Global("b", ty.bool_(), ast::StorageClass::kPrivate);
-  Global("c", ty.bool_(), ast::StorageClass::kPrivate);
-  Global("d", ty.bool_(), ast::StorageClass::kPrivate);
+    // (a && b) || (c || d)
+    Global("a", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("b", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("c", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("d", ty.bool_(), ast::StorageClass::kPrivate);
 
-  auto* expr = create<ast::BinaryExpression>(
-      ast::BinaryOp::kLogicalOr,
-      create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr("a"),
-                                    Expr("b")),
-      create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("c"),
-                                    Expr("d")));
-  WrapInFunction(expr);
+    auto* expr = create<ast::BinaryExpression>(
+        ast::BinaryOp::kLogicalOr,
+        create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr("a"), Expr("b")),
+        create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("c"), Expr("d")));
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), "(tint_tmp)");
-  EXPECT_EQ(gen.result(), R"(bool tint_tmp_1 = a;
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), "(tint_tmp)");
+    EXPECT_EQ(gen.result(), R"(bool tint_tmp_1 = a;
 if (tint_tmp_1) {
   tint_tmp_1 = b;
 }
@@ -325,19 +311,18 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, Logical_Or) {
-  Global("a", ty.bool_(), ast::StorageClass::kPrivate);
-  Global("b", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("a", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("b", ty.bool_(), ast::StorageClass::kPrivate);
 
-  auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr,
-                                             Expr("a"), Expr("b"));
-  WrapInFunction(expr);
+    auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("a"), Expr("b"));
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), "(tint_tmp)");
-  EXPECT_EQ(gen.result(), R"(bool tint_tmp = a;
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), "(tint_tmp)");
+    EXPECT_EQ(gen.result(), R"(bool tint_tmp = a;
 if (!tint_tmp) {
   tint_tmp = b;
 }
@@ -345,31 +330,29 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, If_WithLogical) {
-  // if (a && b) {
-  //   return 1;
-  // } else if (b || c) {
-  //   return 2;
-  // } else {
-  //   return 3;
-  // }
+    // if (a && b) {
+    //   return 1i;
+    // } else if (b || c) {
+    //   return 2i;
+    // } else {
+    //   return 3i;
+    // }
 
-  Global("a", ty.bool_(), ast::StorageClass::kPrivate);
-  Global("b", ty.bool_(), ast::StorageClass::kPrivate);
-  Global("c", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("a", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("b", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("c", ty.bool_(), ast::StorageClass::kPrivate);
 
-  auto* expr = If(create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd,
-                                                Expr("a"), Expr("b")),
-                  Block(Return(1)),
-                  Else(create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr,
-                                                     Expr("b"), Expr("c")),
-                       Block(Return(2))),
-                  Else(Block(Return(3))));
-  Func("func", {}, ty.i32(), {WrapInStatement(expr)});
+    auto* expr =
+        If(create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr("a"), Expr("b")),
+           Block(Return(1_i)),
+           Else(If(create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("b"), Expr("c")),
+                   Block(Return(2_i)), Else(Block(Return(3_i))))));
+    Func("func", {}, ty.i32(), {WrapInStatement(expr)});
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitStatement(expr)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(bool tint_tmp = a;
+    ASSERT_TRUE(gen.EmitStatement(expr)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(bool tint_tmp = a;
 if (tint_tmp) {
   tint_tmp = b;
 }
@@ -390,23 +373,22 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, Return_WithLogical) {
-  // return (a && b) || c;
+    // return (a && b) || c;
 
-  Global("a", ty.bool_(), ast::StorageClass::kPrivate);
-  Global("b", ty.bool_(), ast::StorageClass::kPrivate);
-  Global("c", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("a", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("b", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("c", ty.bool_(), ast::StorageClass::kPrivate);
 
-  auto* expr = Return(create<ast::BinaryExpression>(
-      ast::BinaryOp::kLogicalOr,
-      create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr("a"),
-                                    Expr("b")),
-      Expr("c")));
-  Func("func", {}, ty.bool_(), {WrapInStatement(expr)});
+    auto* expr = Return(create<ast::BinaryExpression>(
+        ast::BinaryOp::kLogicalOr,
+        create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr("a"), Expr("b")),
+        Expr("c")));
+    Func("func", {}, ty.bool_(), {WrapInStatement(expr)});
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitStatement(expr)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(bool tint_tmp_1 = a;
+    ASSERT_TRUE(gen.EmitStatement(expr)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(bool tint_tmp_1 = a;
 if (tint_tmp_1) {
   tint_tmp_1 = b;
 }
@@ -419,25 +401,25 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, Assign_WithLogical) {
-  // a = (b || c) && d;
+    // a = (b || c) && d;
 
-  Global("a", ty.bool_(), ast::StorageClass::kPrivate);
-  Global("b", ty.bool_(), ast::StorageClass::kPrivate);
-  Global("c", ty.bool_(), ast::StorageClass::kPrivate);
-  Global("d", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("a", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("b", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("c", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("d", ty.bool_(), ast::StorageClass::kPrivate);
 
-  auto* expr = Assign(
-      Expr("a"), create<ast::BinaryExpression>(
-                     ast::BinaryOp::kLogicalAnd,
-                     create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr,
-                                                   Expr("b"), Expr("c")),
-                     Expr("d")));
-  WrapInFunction(expr);
+    auto* expr =
+        Assign(Expr("a"),
+               create<ast::BinaryExpression>(
+                   ast::BinaryOp::kLogicalAnd,
+                   create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("b"), Expr("c")),
+                   Expr("d")));
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitStatement(expr)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(bool tint_tmp_1 = b;
+    ASSERT_TRUE(gen.EmitStatement(expr)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(bool tint_tmp_1 = b;
 if (!tint_tmp_1) {
   tint_tmp_1 = c;
 }
@@ -450,26 +432,26 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, Decl_WithLogical) {
-  // var a : bool = (b && c) || d;
+    // var a : bool = (b && c) || d;
 
-  Global("b", ty.bool_(), ast::StorageClass::kPrivate);
-  Global("c", ty.bool_(), ast::StorageClass::kPrivate);
-  Global("d", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("b", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("c", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("d", ty.bool_(), ast::StorageClass::kPrivate);
 
-  auto* var = Var("a", ty.bool_(), ast::StorageClass::kNone,
-                  create<ast::BinaryExpression>(
-                      ast::BinaryOp::kLogicalOr,
-                      create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd,
-                                                    Expr("b"), Expr("c")),
-                      Expr("d")));
+    auto* var =
+        Var("a", ty.bool_(), ast::StorageClass::kNone,
+            create<ast::BinaryExpression>(
+                ast::BinaryOp::kLogicalOr,
+                create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr("b"), Expr("c")),
+                Expr("d")));
 
-  auto* decl = Decl(var);
-  WrapInFunction(decl);
+    auto* decl = Decl(var);
+    WrapInFunction(decl);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitStatement(decl)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(bool tint_tmp_1 = b;
+    ASSERT_TRUE(gen.EmitStatement(decl)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(bool tint_tmp_1 = b;
 if (tint_tmp_1) {
   tint_tmp_1 = c;
 }
@@ -482,39 +464,37 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Binary, Call_WithLogical) {
-  // foo(a && b, c || d, (a || c) && (b || d))
+    // foo(a && b, c || d, (a || c) && (b || d))
 
-  Func("foo",
-       {
-           Param(Sym(), ty.bool_()),
-           Param(Sym(), ty.bool_()),
-           Param(Sym(), ty.bool_()),
-       },
-       ty.void_(), ast::StatementList{}, ast::AttributeList{});
-  Global("a", ty.bool_(), ast::StorageClass::kPrivate);
-  Global("b", ty.bool_(), ast::StorageClass::kPrivate);
-  Global("c", ty.bool_(), ast::StorageClass::kPrivate);
-  Global("d", ty.bool_(), ast::StorageClass::kPrivate);
+    Func("foo",
+         {
+             Param(Sym(), ty.bool_()),
+             Param(Sym(), ty.bool_()),
+             Param(Sym(), ty.bool_()),
+         },
+         ty.void_(), ast::StatementList{}, ast::AttributeList{});
+    Global("a", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("b", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("c", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("d", ty.bool_(), ast::StorageClass::kPrivate);
 
-  ast::ExpressionList params;
-  params.push_back(create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd,
-                                                 Expr("a"), Expr("b")));
-  params.push_back(create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr,
-                                                 Expr("c"), Expr("d")));
-  params.push_back(create<ast::BinaryExpression>(
-      ast::BinaryOp::kLogicalAnd,
-      create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("a"),
-                                    Expr("c")),
-      create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("b"),
-                                    Expr("d"))));
+    ast::ExpressionList params;
+    params.push_back(
+        create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr("a"), Expr("b")));
+    params.push_back(
+        create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("c"), Expr("d")));
+    params.push_back(create<ast::BinaryExpression>(
+        ast::BinaryOp::kLogicalAnd,
+        create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("a"), Expr("c")),
+        create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("b"), Expr("d"))));
 
-  auto* expr = CallStmt(Call("foo", params));
-  WrapInFunction(expr);
+    auto* expr = CallStmt(Call("foo", params));
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitStatement(expr)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(bool tint_tmp = a;
+    ASSERT_TRUE(gen.EmitStatement(expr)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(bool tint_tmp = a;
 if (tint_tmp) {
   tint_tmp = b;
 }
diff --git a/src/tint/writer/glsl/generator_impl_bitcast_test.cc b/src/tint/writer/glsl/generator_impl_bitcast_test.cc
index c0fcfb4..a56c5dd 100644
--- a/src/tint/writer/glsl/generator_impl_bitcast_test.cc
+++ b/src/tint/writer/glsl/generator_impl_bitcast_test.cc
@@ -14,42 +14,44 @@
 
 #include "src/tint/writer/glsl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::glsl {
 namespace {
 
 using GlslGeneratorImplTest_Bitcast = TestHelper;
 
 TEST_F(GlslGeneratorImplTest_Bitcast, EmitExpression_Bitcast_Float) {
-  auto* bitcast = create<ast::BitcastExpression>(ty.f32(), Expr(1));
-  WrapInFunction(bitcast);
+    auto* bitcast = create<ast::BitcastExpression>(ty.f32(), Expr(1_i));
+    WrapInFunction(bitcast);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, bitcast)) << gen.error();
-  EXPECT_EQ(out.str(), "intBitsToFloat(1)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, bitcast)) << gen.error();
+    EXPECT_EQ(out.str(), "intBitsToFloat(1)");
 }
 
 TEST_F(GlslGeneratorImplTest_Bitcast, EmitExpression_Bitcast_Int) {
-  auto* bitcast = create<ast::BitcastExpression>(ty.i32(), Expr(1u));
-  WrapInFunction(bitcast);
+    auto* bitcast = create<ast::BitcastExpression>(ty.i32(), Expr(1_u));
+    WrapInFunction(bitcast);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, bitcast)) << gen.error();
-  EXPECT_EQ(out.str(), "int(1u)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, bitcast)) << gen.error();
+    EXPECT_EQ(out.str(), "int(1u)");
 }
 
 TEST_F(GlslGeneratorImplTest_Bitcast, EmitExpression_Bitcast_Uint) {
-  auto* bitcast = create<ast::BitcastExpression>(ty.u32(), Expr(1));
-  WrapInFunction(bitcast);
+    auto* bitcast = create<ast::BitcastExpression>(ty.u32(), Expr(1_i));
+    WrapInFunction(bitcast);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, bitcast)) << gen.error();
-  EXPECT_EQ(out.str(), "uint(1)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, bitcast)) << gen.error();
+    EXPECT_EQ(out.str(), "uint(1)");
 }
 
 }  // namespace
diff --git a/src/tint/writer/glsl/generator_impl_block_test.cc b/src/tint/writer/glsl/generator_impl_block_test.cc
index cdfc925..014c1c7 100644
--- a/src/tint/writer/glsl/generator_impl_block_test.cc
+++ b/src/tint/writer/glsl/generator_impl_block_test.cc
@@ -20,15 +20,15 @@
 using GlslGeneratorImplTest_Block = TestHelper;
 
 TEST_F(GlslGeneratorImplTest_Block, Emit_Block) {
-  auto* b = Block(create<ast::DiscardStatement>());
-  WrapInFunction(b);
+    auto* b = Block(create<ast::DiscardStatement>());
+    WrapInFunction(b);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(b)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  {
+    ASSERT_TRUE(gen.EmitStatement(b)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  {
     discard;
   }
 )");
diff --git a/src/tint/writer/glsl/generator_impl_break_test.cc b/src/tint/writer/glsl/generator_impl_break_test.cc
index 7e716a2..fa0e514 100644
--- a/src/tint/writer/glsl/generator_impl_break_test.cc
+++ b/src/tint/writer/glsl/generator_impl_break_test.cc
@@ -20,15 +20,15 @@
 using GlslGeneratorImplTest_Break = TestHelper;
 
 TEST_F(GlslGeneratorImplTest_Break, Emit_Break) {
-  auto* b = create<ast::BreakStatement>();
-  WrapInFunction(Loop(Block(b)));
+    auto* b = create<ast::BreakStatement>();
+    WrapInFunction(Loop(Block(b)));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(b)) << gen.error();
-  EXPECT_EQ(gen.result(), "  break;\n");
+    ASSERT_TRUE(gen.EmitStatement(b)) << gen.error();
+    EXPECT_EQ(gen.result(), "  break;\n");
 }
 
 }  // namespace
diff --git a/src/tint/writer/glsl/generator_impl_builtin_test.cc b/src/tint/writer/glsl/generator_impl_builtin_test.cc
index 3b31326..311abd9 100644
--- a/src/tint/writer/glsl/generator_impl_builtin_test.cc
+++ b/src/tint/writer/glsl/generator_impl_builtin_test.cc
@@ -18,276 +18,275 @@
 #include "src/tint/sem/call.h"
 #include "src/tint/writer/glsl/test_helper.h"
 
+using ::testing::HasSubstr;
+
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::glsl {
 namespace {
 
 using BuiltinType = sem::BuiltinType;
 
-using ::testing::HasSubstr;
-
 using GlslGeneratorImplTest_Builtin = TestHelper;
 
 enum class ParamType {
-  kF32,
-  kU32,
-  kBool,
+    kF32,
+    kU32,
+    kBool,
 };
 
 struct BuiltinData {
-  BuiltinType builtin;
-  ParamType type;
-  const char* glsl_name;
+    BuiltinType builtin;
+    ParamType type;
+    const char* glsl_name;
 };
 inline std::ostream& operator<<(std::ostream& out, BuiltinData data) {
-  out << data.glsl_name;
-  switch (data.type) {
-    case ParamType::kF32:
-      out << "f32";
-      break;
-    case ParamType::kU32:
-      out << "u32";
-      break;
-    case ParamType::kBool:
-      out << "bool";
-      break;
-  }
-  out << ">";
-  return out;
+    out << data.glsl_name;
+    switch (data.type) {
+        case ParamType::kF32:
+            out << "f32";
+            break;
+        case ParamType::kU32:
+            out << "u32";
+            break;
+        case ParamType::kBool:
+            out << "bool";
+            break;
+    }
+    out << ">";
+    return out;
 }
 
 const ast::CallExpression* GenerateCall(BuiltinType builtin,
                                         ParamType type,
                                         ProgramBuilder* builder) {
-  std::string name;
-  std::ostringstream str(name);
-  str << builtin;
-  switch (builtin) {
-    case BuiltinType::kAcos:
-    case BuiltinType::kAsin:
-    case BuiltinType::kAtan:
-    case BuiltinType::kCeil:
-    case BuiltinType::kCos:
-    case BuiltinType::kCosh:
-    case BuiltinType::kDpdx:
-    case BuiltinType::kDpdxCoarse:
-    case BuiltinType::kDpdxFine:
-    case BuiltinType::kDpdy:
-    case BuiltinType::kDpdyCoarse:
-    case BuiltinType::kDpdyFine:
-    case BuiltinType::kExp:
-    case BuiltinType::kExp2:
-    case BuiltinType::kFloor:
-    case BuiltinType::kFract:
-    case BuiltinType::kFwidth:
-    case BuiltinType::kFwidthCoarse:
-    case BuiltinType::kFwidthFine:
-    case BuiltinType::kInverseSqrt:
-    case BuiltinType::kLength:
-    case BuiltinType::kLog:
-    case BuiltinType::kLog2:
-    case BuiltinType::kNormalize:
-    case BuiltinType::kRound:
-    case BuiltinType::kSin:
-    case BuiltinType::kSinh:
-    case BuiltinType::kSqrt:
-    case BuiltinType::kTan:
-    case BuiltinType::kTanh:
-    case BuiltinType::kTrunc:
-    case BuiltinType::kSign:
-      return builder->Call(str.str(), "f2");
-    case BuiltinType::kLdexp:
-      return builder->Call(str.str(), "f2", "i2");
-    case BuiltinType::kAtan2:
-    case BuiltinType::kDot:
-    case BuiltinType::kDistance:
-    case BuiltinType::kPow:
-    case BuiltinType::kReflect:
-    case BuiltinType::kStep:
-      return builder->Call(str.str(), "f2", "f2");
-    case BuiltinType::kCross:
-      return builder->Call(str.str(), "f3", "f3");
-    case BuiltinType::kFma:
-    case BuiltinType::kMix:
-    case BuiltinType::kFaceForward:
-    case BuiltinType::kSmoothstep:
-    case BuiltinType::kSmoothStep:
-      return builder->Call(str.str(), "f2", "f2", "f2");
-    case BuiltinType::kAll:
-    case BuiltinType::kAny:
-      return builder->Call(str.str(), "b2");
-    case BuiltinType::kAbs:
-      if (type == ParamType::kF32) {
-        return builder->Call(str.str(), "f2");
-      } else {
-        return builder->Call(str.str(), "u2");
-      }
-    case BuiltinType::kCountOneBits:
-    case BuiltinType::kReverseBits:
-      return builder->Call(str.str(), "u2");
-    case BuiltinType::kMax:
-    case BuiltinType::kMin:
-      if (type == ParamType::kF32) {
-        return builder->Call(str.str(), "f2", "f2");
-      } else {
-        return builder->Call(str.str(), "u2", "u2");
-      }
-    case BuiltinType::kClamp:
-      if (type == ParamType::kF32) {
-        return builder->Call(str.str(), "f2", "f2", "f2");
-      } else {
-        return builder->Call(str.str(), "u2", "u2", "u2");
-      }
-    case BuiltinType::kSelect:
-      return builder->Call(str.str(), "f2", "f2", "b2");
-    case BuiltinType::kDeterminant:
-      return builder->Call(str.str(), "m2x2");
-    case BuiltinType::kTranspose:
-      return builder->Call(str.str(), "m3x2");
-    default:
-      break;
-  }
-  return nullptr;
+    std::string name;
+    std::ostringstream str(name);
+    str << builtin;
+    switch (builtin) {
+        case BuiltinType::kAcos:
+        case BuiltinType::kAsin:
+        case BuiltinType::kAtan:
+        case BuiltinType::kCeil:
+        case BuiltinType::kCos:
+        case BuiltinType::kCosh:
+        case BuiltinType::kDpdx:
+        case BuiltinType::kDpdxCoarse:
+        case BuiltinType::kDpdxFine:
+        case BuiltinType::kDpdy:
+        case BuiltinType::kDpdyCoarse:
+        case BuiltinType::kDpdyFine:
+        case BuiltinType::kExp:
+        case BuiltinType::kExp2:
+        case BuiltinType::kFloor:
+        case BuiltinType::kFract:
+        case BuiltinType::kFwidth:
+        case BuiltinType::kFwidthCoarse:
+        case BuiltinType::kFwidthFine:
+        case BuiltinType::kInverseSqrt:
+        case BuiltinType::kLength:
+        case BuiltinType::kLog:
+        case BuiltinType::kLog2:
+        case BuiltinType::kNormalize:
+        case BuiltinType::kRound:
+        case BuiltinType::kSin:
+        case BuiltinType::kSinh:
+        case BuiltinType::kSqrt:
+        case BuiltinType::kTan:
+        case BuiltinType::kTanh:
+        case BuiltinType::kTrunc:
+        case BuiltinType::kSign:
+            return builder->Call(str.str(), "f2");
+        case BuiltinType::kLdexp:
+            return builder->Call(str.str(), "f2", "i2");
+        case BuiltinType::kAtan2:
+        case BuiltinType::kDot:
+        case BuiltinType::kDistance:
+        case BuiltinType::kPow:
+        case BuiltinType::kReflect:
+        case BuiltinType::kStep:
+            return builder->Call(str.str(), "f2", "f2");
+        case BuiltinType::kCross:
+            return builder->Call(str.str(), "f3", "f3");
+        case BuiltinType::kFma:
+        case BuiltinType::kMix:
+        case BuiltinType::kFaceForward:
+        case BuiltinType::kSmoothstep:
+        case BuiltinType::kSmoothStep:
+            return builder->Call(str.str(), "f2", "f2", "f2");
+        case BuiltinType::kAll:
+        case BuiltinType::kAny:
+            return builder->Call(str.str(), "b2");
+        case BuiltinType::kAbs:
+            if (type == ParamType::kF32) {
+                return builder->Call(str.str(), "f2");
+            } else {
+                return builder->Call(str.str(), "u2");
+            }
+        case BuiltinType::kCountOneBits:
+        case BuiltinType::kReverseBits:
+            return builder->Call(str.str(), "u2");
+        case BuiltinType::kMax:
+        case BuiltinType::kMin:
+            if (type == ParamType::kF32) {
+                return builder->Call(str.str(), "f2", "f2");
+            } else {
+                return builder->Call(str.str(), "u2", "u2");
+            }
+        case BuiltinType::kClamp:
+            if (type == ParamType::kF32) {
+                return builder->Call(str.str(), "f2", "f2", "f2");
+            } else {
+                return builder->Call(str.str(), "u2", "u2", "u2");
+            }
+        case BuiltinType::kSelect:
+            return builder->Call(str.str(), "f2", "f2", "b2");
+        case BuiltinType::kDeterminant:
+            return builder->Call(str.str(), "m2x2");
+        case BuiltinType::kTranspose:
+            return builder->Call(str.str(), "m3x2");
+        default:
+            break;
+    }
+    return nullptr;
 }
 using GlslBuiltinTest = TestParamHelper<BuiltinData>;
 TEST_P(GlslBuiltinTest, Emit) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  Global("f2", ty.vec2<f32>(), ast::StorageClass::kPrivate);
-  Global("f3", ty.vec3<f32>(), ast::StorageClass::kPrivate);
-  Global("u2", ty.vec2<u32>(), ast::StorageClass::kPrivate);
-  Global("i2", ty.vec2<i32>(), ast::StorageClass::kPrivate);
-  Global("b2", ty.vec2<bool>(), ast::StorageClass::kPrivate);
-  Global("m2x2", ty.mat2x2<f32>(), ast::StorageClass::kPrivate);
-  Global("m3x2", ty.mat3x2<f32>(), ast::StorageClass::kPrivate);
+    Global("f2", ty.vec2<f32>(), ast::StorageClass::kPrivate);
+    Global("f3", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+    Global("u2", ty.vec2<u32>(), ast::StorageClass::kPrivate);
+    Global("i2", ty.vec2<i32>(), ast::StorageClass::kPrivate);
+    Global("b2", ty.vec2<bool>(), ast::StorageClass::kPrivate);
+    Global("m2x2", ty.mat2x2<f32>(), ast::StorageClass::kPrivate);
+    Global("m3x2", ty.mat3x2<f32>(), ast::StorageClass::kPrivate);
 
-  auto* call = GenerateCall(param.builtin, param.type, this);
-  ASSERT_NE(nullptr, call) << "Unhandled builtin";
-  Func("func", {}, ty.void_(), {CallStmt(call)},
-       {create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
+    auto* call = GenerateCall(param.builtin, param.type, this);
+    ASSERT_NE(nullptr, call) << "Unhandled builtin";
+    Func("func", {}, ty.void_(), {CallStmt(call)},
+         {create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  auto* sem = program->Sem().Get(call);
-  ASSERT_NE(sem, nullptr);
-  auto* target = sem->Target();
-  ASSERT_NE(target, nullptr);
-  auto* builtin = target->As<sem::Builtin>();
-  ASSERT_NE(builtin, nullptr);
+    auto* sem = program->Sem().Get(call);
+    ASSERT_NE(sem, nullptr);
+    auto* target = sem->Target();
+    ASSERT_NE(target, nullptr);
+    auto* builtin = target->As<sem::Builtin>();
+    ASSERT_NE(builtin, nullptr);
 
-  EXPECT_EQ(gen.generate_builtin_name(builtin), param.glsl_name);
+    EXPECT_EQ(gen.generate_builtin_name(builtin), param.glsl_name);
 }
 INSTANTIATE_TEST_SUITE_P(
     GlslGeneratorImplTest_Builtin,
     GlslBuiltinTest,
-    testing::Values(
-        BuiltinData{BuiltinType::kAbs, ParamType::kF32, "abs"},
-        BuiltinData{BuiltinType::kAbs, ParamType::kU32, "abs"},
-        BuiltinData{BuiltinType::kAcos, ParamType::kF32, "acos"},
-        BuiltinData{BuiltinType::kAll, ParamType::kBool, "all"},
-        BuiltinData{BuiltinType::kAny, ParamType::kBool, "any"},
-        BuiltinData{BuiltinType::kAsin, ParamType::kF32, "asin"},
-        BuiltinData{BuiltinType::kAtan, ParamType::kF32, "atan"},
-        BuiltinData{BuiltinType::kAtan2, ParamType::kF32, "atan"},
-        BuiltinData{BuiltinType::kCeil, ParamType::kF32, "ceil"},
-        BuiltinData{BuiltinType::kClamp, ParamType::kF32, "clamp"},
-        BuiltinData{BuiltinType::kClamp, ParamType::kU32, "clamp"},
-        BuiltinData{BuiltinType::kCos, ParamType::kF32, "cos"},
-        BuiltinData{BuiltinType::kCosh, ParamType::kF32, "cosh"},
-        BuiltinData{BuiltinType::kCountOneBits, ParamType::kU32, "bitCount"},
-        BuiltinData{BuiltinType::kCross, ParamType::kF32, "cross"},
-        BuiltinData{BuiltinType::kDeterminant, ParamType::kF32, "determinant"},
-        BuiltinData{BuiltinType::kDistance, ParamType::kF32, "distance"},
-        BuiltinData{BuiltinType::kDot, ParamType::kF32, "dot"},
-        BuiltinData{BuiltinType::kDpdx, ParamType::kF32, "dFdx"},
-        BuiltinData{BuiltinType::kDpdxCoarse, ParamType::kF32, "dFdx"},
-        BuiltinData{BuiltinType::kDpdxFine, ParamType::kF32, "dFdx"},
-        BuiltinData{BuiltinType::kDpdy, ParamType::kF32, "dFdy"},
-        BuiltinData{BuiltinType::kDpdyCoarse, ParamType::kF32, "dFdy"},
-        BuiltinData{BuiltinType::kDpdyFine, ParamType::kF32, "dFdy"},
-        BuiltinData{BuiltinType::kExp, ParamType::kF32, "exp"},
-        BuiltinData{BuiltinType::kExp2, ParamType::kF32, "exp2"},
-        BuiltinData{BuiltinType::kFaceForward, ParamType::kF32, "faceforward"},
-        BuiltinData{BuiltinType::kFloor, ParamType::kF32, "floor"},
-        BuiltinData{BuiltinType::kFma, ParamType::kF32, "fma"},
-        BuiltinData{BuiltinType::kFract, ParamType::kF32, "fract"},
-        BuiltinData{BuiltinType::kFwidth, ParamType::kF32, "fwidth"},
-        BuiltinData{BuiltinType::kFwidthCoarse, ParamType::kF32, "fwidth"},
-        BuiltinData{BuiltinType::kFwidthFine, ParamType::kF32, "fwidth"},
-        BuiltinData{BuiltinType::kInverseSqrt, ParamType::kF32, "inversesqrt"},
-        BuiltinData{BuiltinType::kLdexp, ParamType::kF32, "ldexp"},
-        BuiltinData{BuiltinType::kLength, ParamType::kF32, "length"},
-        BuiltinData{BuiltinType::kLog, ParamType::kF32, "log"},
-        BuiltinData{BuiltinType::kLog2, ParamType::kF32, "log2"},
-        BuiltinData{BuiltinType::kMax, ParamType::kF32, "max"},
-        BuiltinData{BuiltinType::kMax, ParamType::kU32, "max"},
-        BuiltinData{BuiltinType::kMin, ParamType::kF32, "min"},
-        BuiltinData{BuiltinType::kMin, ParamType::kU32, "min"},
-        BuiltinData{BuiltinType::kMix, ParamType::kF32, "mix"},
-        BuiltinData{BuiltinType::kNormalize, ParamType::kF32, "normalize"},
-        BuiltinData{BuiltinType::kPow, ParamType::kF32, "pow"},
-        BuiltinData{BuiltinType::kReflect, ParamType::kF32, "reflect"},
-        BuiltinData{BuiltinType::kReverseBits, ParamType::kU32,
-                    "bitfieldReverse"},
-        BuiltinData{BuiltinType::kRound, ParamType::kU32, "round"},
-        BuiltinData{BuiltinType::kSign, ParamType::kF32, "sign"},
-        BuiltinData{BuiltinType::kSin, ParamType::kF32, "sin"},
-        BuiltinData{BuiltinType::kSinh, ParamType::kF32, "sinh"},
-        BuiltinData{BuiltinType::kSmoothstep, ParamType::kF32, "smoothstep"},
-        BuiltinData{BuiltinType::kSmoothStep, ParamType::kF32, "smoothstep"},
-        BuiltinData{BuiltinType::kSqrt, ParamType::kF32, "sqrt"},
-        BuiltinData{BuiltinType::kStep, ParamType::kF32, "step"},
-        BuiltinData{BuiltinType::kTan, ParamType::kF32, "tan"},
-        BuiltinData{BuiltinType::kTanh, ParamType::kF32, "tanh"},
-        BuiltinData{BuiltinType::kTranspose, ParamType::kF32, "transpose"},
-        BuiltinData{BuiltinType::kTrunc, ParamType::kF32, "trunc"}));
+    testing::Values(BuiltinData{BuiltinType::kAbs, ParamType::kF32, "abs"},
+                    BuiltinData{BuiltinType::kAbs, ParamType::kU32, "abs"},
+                    BuiltinData{BuiltinType::kAcos, ParamType::kF32, "acos"},
+                    BuiltinData{BuiltinType::kAll, ParamType::kBool, "all"},
+                    BuiltinData{BuiltinType::kAny, ParamType::kBool, "any"},
+                    BuiltinData{BuiltinType::kAsin, ParamType::kF32, "asin"},
+                    BuiltinData{BuiltinType::kAtan, ParamType::kF32, "atan"},
+                    BuiltinData{BuiltinType::kAtan2, ParamType::kF32, "atan"},
+                    BuiltinData{BuiltinType::kCeil, ParamType::kF32, "ceil"},
+                    BuiltinData{BuiltinType::kClamp, ParamType::kF32, "clamp"},
+                    BuiltinData{BuiltinType::kClamp, ParamType::kU32, "clamp"},
+                    BuiltinData{BuiltinType::kCos, ParamType::kF32, "cos"},
+                    BuiltinData{BuiltinType::kCosh, ParamType::kF32, "cosh"},
+                    BuiltinData{BuiltinType::kCountOneBits, ParamType::kU32, "bitCount"},
+                    BuiltinData{BuiltinType::kCross, ParamType::kF32, "cross"},
+                    BuiltinData{BuiltinType::kDeterminant, ParamType::kF32, "determinant"},
+                    BuiltinData{BuiltinType::kDistance, ParamType::kF32, "distance"},
+                    BuiltinData{BuiltinType::kDot, ParamType::kF32, "dot"},
+                    BuiltinData{BuiltinType::kDpdx, ParamType::kF32, "dFdx"},
+                    BuiltinData{BuiltinType::kDpdxCoarse, ParamType::kF32, "dFdx"},
+                    BuiltinData{BuiltinType::kDpdxFine, ParamType::kF32, "dFdx"},
+                    BuiltinData{BuiltinType::kDpdy, ParamType::kF32, "dFdy"},
+                    BuiltinData{BuiltinType::kDpdyCoarse, ParamType::kF32, "dFdy"},
+                    BuiltinData{BuiltinType::kDpdyFine, ParamType::kF32, "dFdy"},
+                    BuiltinData{BuiltinType::kExp, ParamType::kF32, "exp"},
+                    BuiltinData{BuiltinType::kExp2, ParamType::kF32, "exp2"},
+                    BuiltinData{BuiltinType::kFaceForward, ParamType::kF32, "faceforward"},
+                    BuiltinData{BuiltinType::kFloor, ParamType::kF32, "floor"},
+                    BuiltinData{BuiltinType::kFma, ParamType::kF32, "fma"},
+                    BuiltinData{BuiltinType::kFract, ParamType::kF32, "fract"},
+                    BuiltinData{BuiltinType::kFwidth, ParamType::kF32, "fwidth"},
+                    BuiltinData{BuiltinType::kFwidthCoarse, ParamType::kF32, "fwidth"},
+                    BuiltinData{BuiltinType::kFwidthFine, ParamType::kF32, "fwidth"},
+                    BuiltinData{BuiltinType::kInverseSqrt, ParamType::kF32, "inversesqrt"},
+                    BuiltinData{BuiltinType::kLdexp, ParamType::kF32, "ldexp"},
+                    BuiltinData{BuiltinType::kLength, ParamType::kF32, "length"},
+                    BuiltinData{BuiltinType::kLog, ParamType::kF32, "log"},
+                    BuiltinData{BuiltinType::kLog2, ParamType::kF32, "log2"},
+                    BuiltinData{BuiltinType::kMax, ParamType::kF32, "max"},
+                    BuiltinData{BuiltinType::kMax, ParamType::kU32, "max"},
+                    BuiltinData{BuiltinType::kMin, ParamType::kF32, "min"},
+                    BuiltinData{BuiltinType::kMin, ParamType::kU32, "min"},
+                    BuiltinData{BuiltinType::kMix, ParamType::kF32, "mix"},
+                    BuiltinData{BuiltinType::kNormalize, ParamType::kF32, "normalize"},
+                    BuiltinData{BuiltinType::kPow, ParamType::kF32, "pow"},
+                    BuiltinData{BuiltinType::kReflect, ParamType::kF32, "reflect"},
+                    BuiltinData{BuiltinType::kReverseBits, ParamType::kU32, "bitfieldReverse"},
+                    BuiltinData{BuiltinType::kRound, ParamType::kU32, "round"},
+                    BuiltinData{BuiltinType::kSign, ParamType::kF32, "sign"},
+                    BuiltinData{BuiltinType::kSin, ParamType::kF32, "sin"},
+                    BuiltinData{BuiltinType::kSinh, ParamType::kF32, "sinh"},
+                    BuiltinData{BuiltinType::kSmoothstep, ParamType::kF32, "smoothstep"},
+                    BuiltinData{BuiltinType::kSmoothStep, ParamType::kF32, "smoothstep"},
+                    BuiltinData{BuiltinType::kSqrt, ParamType::kF32, "sqrt"},
+                    BuiltinData{BuiltinType::kStep, ParamType::kF32, "step"},
+                    BuiltinData{BuiltinType::kTan, ParamType::kF32, "tan"},
+                    BuiltinData{BuiltinType::kTanh, ParamType::kF32, "tanh"},
+                    BuiltinData{BuiltinType::kTranspose, ParamType::kF32, "transpose"},
+                    BuiltinData{BuiltinType::kTrunc, ParamType::kF32, "trunc"}));
 
 TEST_F(GlslGeneratorImplTest_Builtin, Builtin_Call) {
-  auto* call = Call("dot", "param1", "param2");
+    auto* call = Call("dot", "param1", "param2");
 
-  Global("param1", ty.vec3<f32>(), ast::StorageClass::kPrivate);
-  Global("param2", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+    Global("param1", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+    Global("param2", ty.vec3<f32>(), ast::StorageClass::kPrivate);
 
-  WrapInFunction(CallStmt(call));
+    WrapInFunction(CallStmt(call));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
-  EXPECT_EQ(out.str(), "dot(param1, param2)");
+    gen.increment_indent();
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
+    EXPECT_EQ(out.str(), "dot(param1, param2)");
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, Select_Scalar) {
-  auto* call = Call("select", 1.0f, 2.0f, true);
-  WrapInFunction(CallStmt(call));
-  GeneratorImpl& gen = Build();
+    auto* call = Call("select", 1.0f, 2.0f, true);
+    WrapInFunction(CallStmt(call));
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
-  EXPECT_EQ(out.str(), "(true ? 2.0f : 1.0f)");
+    gen.increment_indent();
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
+    EXPECT_EQ(out.str(), "(true ? 2.0f : 1.0f)");
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, Select_Vector) {
-  auto* call =
-      Call("select", vec2<i32>(1, 2), vec2<i32>(3, 4), vec2<bool>(true, false));
-  WrapInFunction(CallStmt(call));
-  GeneratorImpl& gen = Build();
+    auto* call = Call("select", vec2<i32>(1_i, 2_i), vec2<i32>(3_i, 4_i), vec2<bool>(true, false));
+    WrapInFunction(CallStmt(call));
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
-  EXPECT_EQ(out.str(), "mix(ivec2(1, 2), ivec2(3, 4), bvec2(true, false))");
+    gen.increment_indent();
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
+    EXPECT_EQ(out.str(), "mix(ivec2(1, 2), ivec2(3, 4), bvec2(true, false))");
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, Modf_Scalar) {
-  auto* call = Call("modf", 1.0f);
-  WrapInFunction(CallStmt(call));
+    auto* call = Call("modf", 1.0f);
+    WrapInFunction(CallStmt(call));
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 
 struct modf_result {
   float fract;
@@ -314,13 +313,13 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, Modf_Vector) {
-  auto* call = Call("modf", vec3<f32>());
-  WrapInFunction(CallStmt(call));
+    auto* call = Call("modf", vec3<f32>());
+    WrapInFunction(CallStmt(call));
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 
 struct modf_result_vec3 {
   vec3 fract;
@@ -347,13 +346,13 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, Frexp_Scalar_i32) {
-  auto* call = Call("frexp", 1.0f);
-  WrapInFunction(CallStmt(call));
+    auto* call = Call("frexp", 1.0f);
+    WrapInFunction(CallStmt(call));
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr(R"(
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr(R"(
   float sig;
   int exp;
 };
@@ -374,13 +373,13 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, Frexp_Vector_i32) {
-  auto* call = Call("frexp", vec3<f32>());
-  WrapInFunction(CallStmt(call));
+    auto* call = Call("frexp", vec3<f32>());
+    WrapInFunction(CallStmt(call));
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr(R"(
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr(R"(
 
 struct frexp_result_vec3 {
   vec3 sig;
@@ -406,14 +405,14 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, Degrees_Scalar) {
-  auto* val = Var("val", ty.f32());
-  auto* call = Call("degrees", val);
-  WrapInFunction(val, call);
+    auto* val = Var("val", ty.f32());
+    auto* call = Call("degrees", val);
+    WrapInFunction(val, call);
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 
 float tint_degrees(float param_0) {
   return param_0 * 57.295779513082322865;
@@ -434,14 +433,14 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, Degrees_Vector) {
-  auto* val = Var("val", ty.vec3<f32>());
-  auto* call = Call("degrees", val);
-  WrapInFunction(val, call);
+    auto* val = Var("val", ty.vec3<f32>());
+    auto* call = Call("degrees", val);
+    WrapInFunction(val, call);
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 
 vec3 tint_degrees(vec3 param_0) {
   return param_0 * 57.295779513082322865;
@@ -462,14 +461,14 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, Radians_Scalar) {
-  auto* val = Var("val", ty.f32());
-  auto* call = Call("radians", val);
-  WrapInFunction(val, call);
+    auto* val = Var("val", ty.f32());
+    auto* call = Call("radians", val);
+    WrapInFunction(val, call);
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 
 float tint_radians(float param_0) {
   return param_0 * 0.017453292519943295474;
@@ -490,14 +489,14 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, Radians_Vector) {
-  auto* val = Var("val", ty.vec3<f32>());
-  auto* call = Call("radians", val);
-  WrapInFunction(val, call);
+    auto* val = Var("val", ty.vec3<f32>());
+    auto* call = Call("radians", val);
+    WrapInFunction(val, call);
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 
 vec3 tint_radians(vec3 param_0) {
   return param_0 * 0.017453292519943295474;
@@ -518,16 +517,16 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, ExtractBits) {
-  auto* v = Var("v", ty.vec3<u32>());
-  auto* offset = Var("offset", ty.u32());
-  auto* count = Var("count", ty.u32());
-  auto* call = Call("extractBits", v, offset, count);
-  WrapInFunction(v, offset, count, call);
+    auto* v = Var("v", ty.vec3<u32>());
+    auto* offset = Var("offset", ty.u32());
+    auto* count = Var("count", ty.u32());
+    auto* call = Call("extractBits", v, offset, count);
+    WrapInFunction(v, offset, count, call);
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 
 uvec3 tint_extract_bits(uvec3 v, uint offset, uint count) {
   uint s = min(offset, 32u);
@@ -551,17 +550,17 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, InsertBits) {
-  auto* v = Var("v", ty.vec3<u32>());
-  auto* n = Var("n", ty.vec3<u32>());
-  auto* offset = Var("offset", ty.u32());
-  auto* count = Var("count", ty.u32());
-  auto* call = Call("insertBits", v, n, offset, count);
-  WrapInFunction(v, n, offset, count, call);
+    auto* v = Var("v", ty.vec3<u32>());
+    auto* n = Var("n", ty.vec3<u32>());
+    auto* offset = Var("offset", ty.u32());
+    auto* count = Var("count", ty.u32());
+    auto* call = Call("insertBits", v, n, offset, count);
+    WrapInFunction(v, n, offset, count, call);
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 
 uvec3 tint_insert_bits(uvec3 v, uvec3 n, uint offset, uint count) {
   uint s = min(offset, 32u);
@@ -586,13 +585,13 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, Pack4x8Snorm) {
-  auto* call = Call("pack4x8snorm", "p1");
-  Global("p1", ty.vec4<f32>(), ast::StorageClass::kPrivate);
-  WrapInFunction(CallStmt(call));
-  GeneratorImpl& gen = Build();
+    auto* call = Call("pack4x8snorm", "p1");
+    Global("p1", ty.vec4<f32>(), ast::StorageClass::kPrivate);
+    WrapInFunction(CallStmt(call));
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 
 vec4 p1 = vec4(0.0f, 0.0f, 0.0f, 0.0f);
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
@@ -604,13 +603,13 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, Pack4x8Unorm) {
-  auto* call = Call("pack4x8unorm", "p1");
-  Global("p1", ty.vec4<f32>(), ast::StorageClass::kPrivate);
-  WrapInFunction(CallStmt(call));
-  GeneratorImpl& gen = Build();
+    auto* call = Call("pack4x8unorm", "p1");
+    Global("p1", ty.vec4<f32>(), ast::StorageClass::kPrivate);
+    WrapInFunction(CallStmt(call));
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 
 vec4 p1 = vec4(0.0f, 0.0f, 0.0f, 0.0f);
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
@@ -622,13 +621,13 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, Pack2x16Snorm) {
-  auto* call = Call("pack2x16snorm", "p1");
-  Global("p1", ty.vec2<f32>(), ast::StorageClass::kPrivate);
-  WrapInFunction(CallStmt(call));
-  GeneratorImpl& gen = Build();
+    auto* call = Call("pack2x16snorm", "p1");
+    Global("p1", ty.vec2<f32>(), ast::StorageClass::kPrivate);
+    WrapInFunction(CallStmt(call));
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 
 vec2 p1 = vec2(0.0f, 0.0f);
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
@@ -640,13 +639,13 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, Pack2x16Unorm) {
-  auto* call = Call("pack2x16unorm", "p1");
-  Global("p1", ty.vec2<f32>(), ast::StorageClass::kPrivate);
-  WrapInFunction(CallStmt(call));
-  GeneratorImpl& gen = Build();
+    auto* call = Call("pack2x16unorm", "p1");
+    Global("p1", ty.vec2<f32>(), ast::StorageClass::kPrivate);
+    WrapInFunction(CallStmt(call));
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 
 vec2 p1 = vec2(0.0f, 0.0f);
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
@@ -658,13 +657,13 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, Pack2x16Float) {
-  auto* call = Call("pack2x16float", "p1");
-  Global("p1", ty.vec2<f32>(), ast::StorageClass::kPrivate);
-  WrapInFunction(CallStmt(call));
-  GeneratorImpl& gen = Build();
+    auto* call = Call("pack2x16float", "p1");
+    Global("p1", ty.vec2<f32>(), ast::StorageClass::kPrivate);
+    WrapInFunction(CallStmt(call));
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 
 vec2 p1 = vec2(0.0f, 0.0f);
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
@@ -676,13 +675,13 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, Unpack4x8Snorm) {
-  auto* call = Call("unpack4x8snorm", "p1");
-  Global("p1", ty.u32(), ast::StorageClass::kPrivate);
-  WrapInFunction(CallStmt(call));
-  GeneratorImpl& gen = Build();
+    auto* call = Call("unpack4x8snorm", "p1");
+    Global("p1", ty.u32(), ast::StorageClass::kPrivate);
+    WrapInFunction(CallStmt(call));
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 
 uint p1 = 0u;
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
@@ -694,13 +693,13 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, Unpack4x8Unorm) {
-  auto* call = Call("unpack4x8unorm", "p1");
-  Global("p1", ty.u32(), ast::StorageClass::kPrivate);
-  WrapInFunction(CallStmt(call));
-  GeneratorImpl& gen = Build();
+    auto* call = Call("unpack4x8unorm", "p1");
+    Global("p1", ty.u32(), ast::StorageClass::kPrivate);
+    WrapInFunction(CallStmt(call));
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 
 uint p1 = 0u;
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
@@ -712,13 +711,13 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, Unpack2x16Snorm) {
-  auto* call = Call("unpack2x16snorm", "p1");
-  Global("p1", ty.u32(), ast::StorageClass::kPrivate);
-  WrapInFunction(CallStmt(call));
-  GeneratorImpl& gen = Build();
+    auto* call = Call("unpack2x16snorm", "p1");
+    Global("p1", ty.u32(), ast::StorageClass::kPrivate);
+    WrapInFunction(CallStmt(call));
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 
 uint p1 = 0u;
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
@@ -730,13 +729,13 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, Unpack2x16Unorm) {
-  auto* call = Call("unpack2x16unorm", "p1");
-  Global("p1", ty.u32(), ast::StorageClass::kPrivate);
-  WrapInFunction(CallStmt(call));
-  GeneratorImpl& gen = Build();
+    auto* call = Call("unpack2x16unorm", "p1");
+    Global("p1", ty.u32(), ast::StorageClass::kPrivate);
+    WrapInFunction(CallStmt(call));
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 
 uint p1 = 0u;
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
@@ -748,13 +747,13 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, Unpack2x16Float) {
-  auto* call = Call("unpack2x16float", "p1");
-  Global("p1", ty.u32(), ast::StorageClass::kPrivate);
-  WrapInFunction(CallStmt(call));
-  GeneratorImpl& gen = Build();
+    auto* call = Call("unpack2x16float", "p1");
+    Global("p1", ty.u32(), ast::StorageClass::kPrivate);
+    WrapInFunction(CallStmt(call));
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 
 uint p1 = 0u;
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
@@ -766,16 +765,16 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, StorageBarrier) {
-  Func("main", {}, ty.void_(), {CallStmt(Call("storageBarrier"))},
-       {
-           Stage(ast::PipelineStage::kCompute),
-           WorkgroupSize(1),
-       });
+    Func("main", {}, ty.void_(), {CallStmt(Call("storageBarrier"))},
+         {
+             Stage(ast::PipelineStage::kCompute),
+             WorkgroupSize(1_i),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void main() {
@@ -786,16 +785,16 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, WorkgroupBarrier) {
-  Func("main", {}, ty.void_(), {CallStmt(Call("workgroupBarrier"))},
-       {
-           Stage(ast::PipelineStage::kCompute),
-           WorkgroupSize(1),
-       });
+    Func("main", {}, ty.void_(), {CallStmt(Call("workgroupBarrier"))},
+         {
+             Stage(ast::PipelineStage::kCompute),
+             WorkgroupSize(1_i),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void main() {
@@ -806,13 +805,13 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, DotI32) {
-  Global("v", ty.vec3<i32>(), ast::StorageClass::kPrivate);
-  WrapInFunction(CallStmt(Call("dot", "v", "v")));
+    Global("v", ty.vec3<i32>(), ast::StorageClass::kPrivate);
+    WrapInFunction(CallStmt(Call("dot", "v", "v")));
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 
 int tint_int_dot(ivec3 a, ivec3 b) {
   return a[0]*b[0] + a[1]*b[1] + a[2]*b[2];
@@ -832,30 +831,30 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, FMA) {
-  auto* call = Call("fma", "a", "b", "c");
+    auto* call = Call("fma", "a", "b", "c");
 
-  Global("a", ty.vec3<f32>(), ast::StorageClass::kPrivate);
-  Global("b", ty.vec3<f32>(), ast::StorageClass::kPrivate);
-  Global("c", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+    Global("a", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+    Global("b", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+    Global("c", ty.vec3<f32>(), ast::StorageClass::kPrivate);
 
-  WrapInFunction(CallStmt(call));
+    WrapInFunction(CallStmt(call));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
-  EXPECT_EQ(out.str(), "((a) * (b) + (c))");
+    gen.increment_indent();
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
+    EXPECT_EQ(out.str(), "((a) * (b) + (c))");
 }
 
 TEST_F(GlslGeneratorImplTest_Builtin, DotU32) {
-  Global("v", ty.vec3<u32>(), ast::StorageClass::kPrivate);
-  WrapInFunction(CallStmt(Call("dot", "v", "v")));
+    Global("v", ty.vec3<u32>(), ast::StorageClass::kPrivate);
+    WrapInFunction(CallStmt(Call("dot", "v", "v")));
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 
 uint tint_int_dot(uvec3 a, uvec3 b) {
   return a[0]*b[0] + a[1]*b[1] + a[2]*b[2];
diff --git a/src/tint/writer/glsl/generator_impl_builtin_texture_test.cc b/src/tint/writer/glsl/generator_impl_builtin_texture_test.cc
index a94eb67..cb111ee 100644
--- a/src/tint/writer/glsl/generator_impl_builtin_texture_test.cc
+++ b/src/tint/writer/glsl/generator_impl_builtin_texture_test.cc
@@ -24,277 +24,275 @@
 using ::testing::HasSubstr;
 
 struct ExpectedResult {
-  ExpectedResult(const char* o) : out(o) {}  // NOLINT
+    ExpectedResult(const char* o) : out(o) {}  // NOLINT
 
-  std::string pre;
-  std::string out;
+    std::string pre;
+    std::string out;
 };
 
-ExpectedResult expected_texture_overload(
-    ast::builtin::test::ValidTextureOverload overload) {
-  using ValidTextureOverload = ast::builtin::test::ValidTextureOverload;
-  switch (overload) {
-    case ValidTextureOverload::kDimensions1d:
-    case ValidTextureOverload::kDimensions2d:
-    case ValidTextureOverload::kDimensionsDepth2d:
-    case ValidTextureOverload::kDimensionsDepthMultisampled2d:
-    case ValidTextureOverload::kDimensionsMultisampled2d:
-    case ValidTextureOverload::kDimensions2dArray:
-    case ValidTextureOverload::kDimensionsDepth2dArray:
-    case ValidTextureOverload::kDimensions3d:
-    case ValidTextureOverload::kDimensionsCube:
-    case ValidTextureOverload::kDimensionsDepthCube:
-    case ValidTextureOverload::kDimensionsCubeArray:
-    case ValidTextureOverload::kDimensionsDepthCubeArray:
-    case ValidTextureOverload::kDimensions2dLevel:
-    case ValidTextureOverload::kDimensionsDepth2dLevel:
-    case ValidTextureOverload::kDimensions2dArrayLevel:
-    case ValidTextureOverload::kDimensionsDepth2dArrayLevel:
-    case ValidTextureOverload::kDimensions3dLevel:
-    case ValidTextureOverload::kDimensionsCubeLevel:
-    case ValidTextureOverload::kDimensionsDepthCubeLevel:
-    case ValidTextureOverload::kDimensionsCubeArrayLevel:
-    case ValidTextureOverload::kDimensionsDepthCubeArrayLevel:
-      return {"textureSize"};
-    case ValidTextureOverload::kDimensionsStorageWO1d:
-    case ValidTextureOverload::kDimensionsStorageWO2d:
-    case ValidTextureOverload::kDimensionsStorageWO2dArray:
-    case ValidTextureOverload::kDimensionsStorageWO3d:
-      return {"imageSize"};
-    case ValidTextureOverload::kGather2dF32:
-      return R"(textureGather(tint_symbol_sampler, vec2(1.0f, 2.0f), 0))";
-    case ValidTextureOverload::kGather2dOffsetF32:
-      return R"(textureGatherOffset(tint_symbol_sampler, vec2(1.0f, 2.0f), ivec2(3, 4), 0))";
-    case ValidTextureOverload::kGather2dArrayF32:
-      return R"(textureGather(tint_symbol_sampler, vec3(1.0f, 2.0f, float(3)), 0))";
-    case ValidTextureOverload::kGather2dArrayOffsetF32:
-      return R"(textureGatherOffset(tint_symbol_sampler, vec3(1.0f, 2.0f, float(3)), ivec2(4, 5), 0))";
-    case ValidTextureOverload::kGatherCubeF32:
-      return R"(textureGather(tint_symbol_sampler, vec3(1.0f, 2.0f, 3.0f), 0))";
-    case ValidTextureOverload::kGatherCubeArrayF32:
-      return R"(textureGather(tint_symbol_sampler, vec4(1.0f, 2.0f, 3.0f, float(4)), 0))";
-    case ValidTextureOverload::kGatherDepth2dF32:
-      return R"(textureGather(tint_symbol_sampler, vec2(1.0f, 2.0f), 0.0))";
-    case ValidTextureOverload::kGatherDepth2dOffsetF32:
-      return R"(textureGatherOffset(tint_symbol_sampler, vec2(1.0f, 2.0f), 0.0, ivec2(3, 4))";
-    case ValidTextureOverload::kGatherDepth2dArrayF32:
-      return R"(textureGather(tint_symbol_sampler, vec3(1.0f, 2.0f, float(3)), 0.0))";
-    case ValidTextureOverload::kGatherDepth2dArrayOffsetF32:
-      return R"(textureGatherOffset(tint_symbol_sampler, vec3(1.0f, 2.0f, float(3)), 0.0, ivec2(4, 5)))";
-    case ValidTextureOverload::kGatherDepthCubeF32:
-      return R"(textureGather(tint_symbol_sampler, vec3(1.0f, 2.0f, 3.0f), 0.0))";
-    case ValidTextureOverload::kGatherDepthCubeArrayF32:
-      return R"(textureGather(tint_symbol_sampler, vec4(1.0f, 2.0f, 3.0f, float(4)), 0.0))";
-    case ValidTextureOverload::kGatherCompareDepth2dF32:
-      return R"(textureGather(tint_symbol_sampler, vec2(1.0f, 2.0f), 3.0f))";
-    case ValidTextureOverload::kGatherCompareDepth2dOffsetF32:
-      return R"(textureGatherOffset(tint_symbol_sampler, vec2(1.0f, 2.0f), 3.0f, ivec2(4, 5)))";
-    case ValidTextureOverload::kGatherCompareDepth2dArrayF32:
-      return R"(textureGather(tint_symbol_sampler, vec3(1.0f, 2.0f, float(3)), 4.0f))";
-    case ValidTextureOverload::kGatherCompareDepth2dArrayOffsetF32:
-      return R"(textureGatherOffset(tint_symbol_sampler, vec3(1.0f, 2.0f, float(3)), 4.0f, ivec2(5, 6)))";
-    case ValidTextureOverload::kGatherCompareDepthCubeF32:
-      return R"(textureGather(tint_symbol_sampler, vec3(1.0f, 2.0f, 3.0f), 4.0f))";
-    case ValidTextureOverload::kGatherCompareDepthCubeArrayF32:
-      return R"(textureGather(tint_symbol_sampler, vec4(1.0f, 2.0f, 3.0f, float(4)), 5.0f))";
-    case ValidTextureOverload::kNumLayers2dArray:
-    case ValidTextureOverload::kNumLayersDepth2dArray:
-    case ValidTextureOverload::kNumLayersCubeArray:
-    case ValidTextureOverload::kNumLayersDepthCubeArray:
-      return {"textureSize"};
-    case ValidTextureOverload::kNumLayersStorageWO2dArray:
-      return {"imageSize"};
-    case ValidTextureOverload::kNumLevels2d:
-    case ValidTextureOverload::kNumLevelsCube:
-    case ValidTextureOverload::kNumLevelsDepth2d:
-    case ValidTextureOverload::kNumLevelsDepthCube:
-    case ValidTextureOverload::kNumLevels2dArray:
-    case ValidTextureOverload::kNumLevels3d:
-    case ValidTextureOverload::kNumLevelsCubeArray:
-    case ValidTextureOverload::kNumLevelsDepth2dArray:
-    case ValidTextureOverload::kNumLevelsDepthCubeArray:
-      return {"textureQueryLevels"};
-    case ValidTextureOverload::kNumSamplesDepthMultisampled2d:
-    case ValidTextureOverload::kNumSamplesMultisampled2d:
-      return {"textureSamples"};
-    case ValidTextureOverload::kSample1dF32:
-      return R"(texture(tint_symbol_sampler, 1.0f);)";
-    case ValidTextureOverload::kSample2dF32:
-      return R"(texture(tint_symbol_sampler, vec2(1.0f, 2.0f));)";
-    case ValidTextureOverload::kSample2dOffsetF32:
-      return R"(textureOffset(tint_symbol_sampler, vec2(1.0f, 2.0f), ivec2(3, 4));)";
-    case ValidTextureOverload::kSample2dArrayF32:
-      return R"(texture(tint_symbol_sampler, vec3(1.0f, 2.0f, float(3)));)";
-    case ValidTextureOverload::kSample2dArrayOffsetF32:
-      return R"(textureOffset(tint_symbol_sampler, vec3(1.0f, 2.0f, float(3)), ivec2(4, 5));)";
-    case ValidTextureOverload::kSample3dF32:
-      return R"(texture(tint_symbol_sampler, vec3(1.0f, 2.0f, 3.0f));)";
-    case ValidTextureOverload::kSample3dOffsetF32:
-      return R"(textureOffset(tint_symbol_sampler, vec3(1.0f, 2.0f, 3.0f), ivec3(4, 5, 6));)";
-    case ValidTextureOverload::kSampleCubeF32:
-      return R"(texture(tint_symbol_sampler, vec3(1.0f, 2.0f, 3.0f));)";
-    case ValidTextureOverload::kSampleCubeArrayF32:
-      return R"(texture(tint_symbol_sampler, vec4(1.0f, 2.0f, 3.0f, float(4)));)";
-    case ValidTextureOverload::kSampleDepth2dF32:
-      return R"(texture(tint_symbol_sampler, vec3(1.0f, 2.0f, 0.0f));)";
-    case ValidTextureOverload::kSampleDepth2dOffsetF32:
-      return R"(textureOffset(tint_symbol_sampler, vec3(1.0f, 2.0f, 0.0f), ivec2(3, 4));)";
-    case ValidTextureOverload::kSampleDepth2dArrayF32:
-      return R"(texture(tint_symbol_sampler, vec4(1.0f, 2.0f, float(3), 0.0f));)";
-    case ValidTextureOverload::kSampleDepth2dArrayOffsetF32:
-      return R"(textureOffset(tint_symbol_sampler, vec4(1.0f, 2.0f, float(3), 0.0f), ivec2(4, 5));)";
-    case ValidTextureOverload::kSampleDepthCubeF32:
-      return R"(texture(tint_symbol_sampler, vec4(1.0f, 2.0f, 3.0f, 0.0f));)";
-    case ValidTextureOverload::kSampleDepthCubeArrayF32:
-      return R"(texture(tint_symbol_sampler, vec4(1.0f, 2.0f, 3.0f, float(4)), 0.0f);)";
-    case ValidTextureOverload::kSampleBias2dF32:
-      return R"(texture(tint_symbol_sampler, vec2(1.0f, 2.0f), 3.0f);)";
-    case ValidTextureOverload::kSampleBias2dOffsetF32:
-      return R"(textureOffset(tint_symbol_sampler, vec2(1.0f, 2.0f), ivec2(4, 5), 3.0f);)";
-    case ValidTextureOverload::kSampleBias2dArrayF32:
-      return R"(texture(tint_symbol_sampler, vec3(1.0f, 2.0f, float(4)), 3.0f);)";
-    case ValidTextureOverload::kSampleBias2dArrayOffsetF32:
-      return R"(textureOffset(tint_symbol_sampler, vec3(1.0f, 2.0f, float(3)), ivec2(5, 6), 4.0f);)";
-    case ValidTextureOverload::kSampleBias3dF32:
-      return R"(texture(tint_symbol_sampler, vec3(1.0f, 2.0f, 3.0f), 4.0f);)";
-    case ValidTextureOverload::kSampleBias3dOffsetF32:
-      return R"(textureOffset(tint_symbol_sampler, vec3(1.0f, 2.0f, 3.0f), ivec3(5, 6, 7), 4.0f);)";
-    case ValidTextureOverload::kSampleBiasCubeF32:
-      return R"(texture(tint_symbol_sampler, vec3(1.0f, 2.0f, 3.0f), 4.0f);)";
-    case ValidTextureOverload::kSampleBiasCubeArrayF32:
-      return R"(texture(tint_symbol_sampler, vec4(1.0f, 2.0f, 3.0f, float(3)), 4.0f);)";
-    case ValidTextureOverload::kSampleLevel2dF32:
-      return R"(textureLod(tint_symbol_sampler, vec2(1.0f, 2.0f), 3.0f);)";
-    case ValidTextureOverload::kSampleLevel2dOffsetF32:
-      return R"(textureLodOffset(tint_symbol_sampler, vec2(1.0f, 2.0f), 3.0f, ivec2(4, 5));)";
-    case ValidTextureOverload::kSampleLevel2dArrayF32:
-      return R"(textureLod(tint_symbol_sampler, vec3(1.0f, 2.0f, float(3)), 4.0f);)";
-    case ValidTextureOverload::kSampleLevel2dArrayOffsetF32:
-      return R"(textureLodOffset(tint_symbol_sampler, vec3(1.0f, 2.0f, float(3)), 4.0f, ivec2(5, 6));)";
-    case ValidTextureOverload::kSampleLevel3dF32:
-      return R"(textureLod(tint_symbol_sampler, vec3(1.0f, 2.0f, 3.0f), 4.0f);)";
-    case ValidTextureOverload::kSampleLevel3dOffsetF32:
-      return R"(textureLodOffset(tint_symbol_sampler, vec3(1.0f, 2.0f, 3.0f), 4.0f, ivec3(5, 6, 7));)";
-    case ValidTextureOverload::kSampleLevelCubeF32:
-      return R"(textureLod(tint_symbol_sampler, vec3(1.0f, 2.0f, 3.0f), 4.0f);)";
-    case ValidTextureOverload::kSampleLevelCubeArrayF32:
-      return R"(textureLod(tint_symbol_sampler, vec4(1.0f, 2.0f, 3.0f, float(4)), 5.0f);)";
-    case ValidTextureOverload::kSampleLevelDepth2dF32:
-      return R"(textureLod(tint_symbol_sampler, vec3(1.0f, 2.0f, 0.0f), float(3));)";
-    case ValidTextureOverload::kSampleLevelDepth2dOffsetF32:
-      return R"(textureLodOffset(tint_symbol_sampler, vec3(1.0f, 2.0f, 0.0f), float(3), ivec2(4, 5));)";
-    case ValidTextureOverload::kSampleLevelDepth2dArrayF32:
-      return R"(textureLod(tint_symbol_sampler, vec4(1.0f, 2.0f, float(3), 0.0f), float(4));)";
-    case ValidTextureOverload::kSampleLevelDepth2dArrayOffsetF32:
-      return R"(textureLodOffset(tint_symbol_sampler, vec4(1.0f, 2.0f, float(3), 0.0f), float(4), ivec2(5, 6));)";
-    case ValidTextureOverload::kSampleLevelDepthCubeF32:
-      return R"(textureLod(tint_symbol_sampler, vec4(1.0f, 2.0f, 3.0f, 0.0f), float(4)))";
-    case ValidTextureOverload::kSampleLevelDepthCubeArrayF32:
-      return R"(textureLod(tint_symbol_sampler, vec4(1.0f, 2.0f, 3.0f, float(4)), float(5));)";
-    case ValidTextureOverload::kSampleGrad2dF32:
-      return R"(textureGrad(tint_symbol_sampler, vec2(1.0f, 2.0f), vec2(3.0f, 4.0f), vec2(5.0f, 6.0f));)";
-    case ValidTextureOverload::kSampleGrad2dOffsetF32:
-      return R"(textureGradOffset(tint_symbol_sampler, vec2(1.0f, 2.0f), vec2(3.0f, 4.0f), vec2(5.0f, 6.0f), ivec2(7, 7));)";
-    case ValidTextureOverload::kSampleGrad2dArrayF32:
-      return R"(textureGrad(tint_symbol_sampler, vec3(1.0f, 2.0f, float(3)), vec2(4.0f, 5.0f), vec2(6.0f, 7.0f));)";
-    case ValidTextureOverload::kSampleGrad2dArrayOffsetF32:
-      return R"(textureGradOffset(tint_symbol_sampler, vec3(1.0f, 2.0f, float(3)), vec2(4.0f, 5.0f), vec2(6.0f, 7.0f), ivec2(6, 7));)";
-    case ValidTextureOverload::kSampleGrad3dF32:
-      return R"(textureGrad(tint_symbol_sampler, vec3(1.0f, 2.0f, 3.0f), vec3(4.0f, 5.0f, 6.0f), vec3(7.0f, 8.0f, 9.0f));)";
-    case ValidTextureOverload::kSampleGrad3dOffsetF32:
-      return R"(textureGradOffset(tint_symbol_sampler, vec3(1.0f, 2.0f, 3.0f), vec3(4.0f, 5.0f, 6.0f), vec3(7.0f, 8.0f, 9.0f), ivec3(0, 1, 2));)";
-    case ValidTextureOverload::kSampleGradCubeF32:
-      return R"(textureGrad(tint_symbol_sampler, vec3(1.0f, 2.0f, 3.0f), vec3(4.0f, 5.0f, 6.0f), vec3(7.0f, 8.0f, 9.0f));)";
-    case ValidTextureOverload::kSampleGradCubeArrayF32:
-      return R"(textureGrad(tint_symbol_sampler, vec4(1.0f, 2.0f, 3.0f, float(4)), vec3(5.0f, 6.0f, 7.0f), vec3(8.0f, 9.0f, 10.0f));)";
-    case ValidTextureOverload::kSampleCompareDepth2dF32:
-      return R"(texture(tint_symbol_sampler, vec3(1.0f, 2.0f, 3.0f));)";
-    case ValidTextureOverload::kSampleCompareDepth2dOffsetF32:
-      return R"(textureOffset(tint_symbol_sampler, vec3(1.0f, 2.0f, 3.0f), ivec2(4, 5));)";
-    case ValidTextureOverload::kSampleCompareDepth2dArrayF32:
-      return R"(texture(tint_symbol_sampler, vec4(1.0f, 2.0f, float(4), 3.0f));)";
-    case ValidTextureOverload::kSampleCompareDepth2dArrayOffsetF32:
-      return R"(textureOffset(tint_symbol_sampler, vec4(1.0f, 2.0f, float(4), 3.0f), ivec2(5, 6));)";
-    case ValidTextureOverload::kSampleCompareDepthCubeF32:
-      return R"(texture(tint_symbol_sampler, vec4(1.0f, 2.0f, 3.0f, 4.0f));)";
-    case ValidTextureOverload::kSampleCompareDepthCubeArrayF32:
-      return R"(texture(tint_symbol_sampler, vec4(1.0f, 2.0f, 3.0f, float(4)), 5.0f);)";
-    case ValidTextureOverload::kSampleCompareLevelDepth2dF32:
-      return R"(yyytexture(tint_symbol_sampler, vec2(1.0f, 2.0f), 3.0f);)";
-    case ValidTextureOverload::kSampleCompareLevelDepth2dOffsetF32:
-      return R"(yyytextureOffset(tint_symbol_sampler, vec2(1.0f, 2.0f), 3.0f, ivec2(4, 5));)";
-    case ValidTextureOverload::kSampleCompareLevelDepth2dArrayF32:
-      return R"(texture(tint_symbol_sampler, vec4(1.0f, 2.0f, float(4)), 3.0f);)";
-    case ValidTextureOverload::kSampleCompareLevelDepth2dArrayOffsetF32:
-      return R"(textureOffset(tint_symbol_sampler, vec3(1.0f, 2.0f, float(4)), 3.0f, ivec2(5, 6));)";
-    case ValidTextureOverload::kSampleCompareLevelDepthCubeF32:
-      return R"(texture(tint_symbol_sampler, vec3(1.0f, 2.0f, 3.0f), 4.0f);)";
-    case ValidTextureOverload::kSampleCompareLevelDepthCubeArrayF32:
-      return R"(texture(tint_symbol_sampler, vec4(1.0f, 2.0f, 3.0f, float(4)), 5.0f);)";
-    case ValidTextureOverload::kLoad1dLevelF32:
-    case ValidTextureOverload::kLoad1dLevelU32:
-    case ValidTextureOverload::kLoad1dLevelI32:
-      return R"(texelFetch(tint_symbol_2, 1, 3);)";
-    case ValidTextureOverload::kLoad2dLevelF32:
-    case ValidTextureOverload::kLoad2dLevelU32:
-    case ValidTextureOverload::kLoad2dLevelI32:
-      return R"(texelFetch(tint_symbol_2, ivec2(1, 2), 3);)";
-    case ValidTextureOverload::kLoad2dArrayLevelF32:
-    case ValidTextureOverload::kLoad2dArrayLevelU32:
-    case ValidTextureOverload::kLoad2dArrayLevelI32:
-    case ValidTextureOverload::kLoad3dLevelF32:
-    case ValidTextureOverload::kLoad3dLevelU32:
-    case ValidTextureOverload::kLoad3dLevelI32:
-      return R"(texelFetch(tint_symbol_2, ivec3(1, 2, 3), 4);)";
-    case ValidTextureOverload::kLoadDepthMultisampled2dF32:
-    case ValidTextureOverload::kLoadMultisampled2dF32:
-    case ValidTextureOverload::kLoadMultisampled2dU32:
-    case ValidTextureOverload::kLoadMultisampled2dI32:
-      return R"(texelFetch(tint_symbol_2, ivec2(1, 2), 3);)";
-    case ValidTextureOverload::kLoadDepth2dLevelF32:
-      return R"(texelFetch(tint_symbol_2, ivec2(1, 2), 3);)";
-    case ValidTextureOverload::kLoadDepth2dArrayLevelF32:
-      return R"(texelFetch(tint_symbol_2, ivec3(1, 2, 3), 4);)";
-    case ValidTextureOverload::kStoreWO1dRgba32float:
-      return R"(imageStore(tint_symbol, 1, vec4(2.0f, 3.0f, 4.0f, 5.0f));)";
-    case ValidTextureOverload::kStoreWO2dRgba32float:
-      return R"(imageStore(tint_symbol, ivec2(1, 2), vec4(3.0f, 4.0f, 5.0f, 6.0f));)";
-    case ValidTextureOverload::kStoreWO2dArrayRgba32float:
-      return R"(imageStore(tint_symbol, ivec3(1, 2, 3), vec4(4.0f, 5.0f, 6.0f, 7.0f));)";
-    case ValidTextureOverload::kStoreWO3dRgba32float:
-      return R"(imageStore(tint_symbol, ivec3(1, 2, 3), vec4(4.0f, 5.0f, 6.0f, 7.0f));)";
-  }
-  return "<unmatched texture overload>";
+ExpectedResult expected_texture_overload(ast::builtin::test::ValidTextureOverload overload) {
+    using ValidTextureOverload = ast::builtin::test::ValidTextureOverload;
+    switch (overload) {
+        case ValidTextureOverload::kDimensions1d:
+        case ValidTextureOverload::kDimensions2d:
+        case ValidTextureOverload::kDimensionsDepth2d:
+        case ValidTextureOverload::kDimensionsDepthMultisampled2d:
+        case ValidTextureOverload::kDimensionsMultisampled2d:
+        case ValidTextureOverload::kDimensions2dArray:
+        case ValidTextureOverload::kDimensionsDepth2dArray:
+        case ValidTextureOverload::kDimensions3d:
+        case ValidTextureOverload::kDimensionsCube:
+        case ValidTextureOverload::kDimensionsDepthCube:
+        case ValidTextureOverload::kDimensionsCubeArray:
+        case ValidTextureOverload::kDimensionsDepthCubeArray:
+        case ValidTextureOverload::kDimensions2dLevel:
+        case ValidTextureOverload::kDimensionsDepth2dLevel:
+        case ValidTextureOverload::kDimensions2dArrayLevel:
+        case ValidTextureOverload::kDimensionsDepth2dArrayLevel:
+        case ValidTextureOverload::kDimensions3dLevel:
+        case ValidTextureOverload::kDimensionsCubeLevel:
+        case ValidTextureOverload::kDimensionsDepthCubeLevel:
+        case ValidTextureOverload::kDimensionsCubeArrayLevel:
+        case ValidTextureOverload::kDimensionsDepthCubeArrayLevel:
+            return {"textureSize"};
+        case ValidTextureOverload::kDimensionsStorageWO1d:
+        case ValidTextureOverload::kDimensionsStorageWO2d:
+        case ValidTextureOverload::kDimensionsStorageWO2dArray:
+        case ValidTextureOverload::kDimensionsStorageWO3d:
+            return {"imageSize"};
+        case ValidTextureOverload::kGather2dF32:
+            return R"(textureGather(tint_symbol_sampler, vec2(1.0f, 2.0f), 0))";
+        case ValidTextureOverload::kGather2dOffsetF32:
+            return R"(textureGatherOffset(tint_symbol_sampler, vec2(1.0f, 2.0f), ivec2(3, 4), 0))";
+        case ValidTextureOverload::kGather2dArrayF32:
+            return R"(textureGather(tint_symbol_sampler, vec3(1.0f, 2.0f, float(3)), 0))";
+        case ValidTextureOverload::kGather2dArrayOffsetF32:
+            return R"(textureGatherOffset(tint_symbol_sampler, vec3(1.0f, 2.0f, float(3)), ivec2(4, 5), 0))";
+        case ValidTextureOverload::kGatherCubeF32:
+            return R"(textureGather(tint_symbol_sampler, vec3(1.0f, 2.0f, 3.0f), 0))";
+        case ValidTextureOverload::kGatherCubeArrayF32:
+            return R"(textureGather(tint_symbol_sampler, vec4(1.0f, 2.0f, 3.0f, float(4)), 0))";
+        case ValidTextureOverload::kGatherDepth2dF32:
+            return R"(textureGather(tint_symbol_sampler, vec2(1.0f, 2.0f), 0.0))";
+        case ValidTextureOverload::kGatherDepth2dOffsetF32:
+            return R"(textureGatherOffset(tint_symbol_sampler, vec2(1.0f, 2.0f), 0.0, ivec2(3, 4))";
+        case ValidTextureOverload::kGatherDepth2dArrayF32:
+            return R"(textureGather(tint_symbol_sampler, vec3(1.0f, 2.0f, float(3)), 0.0))";
+        case ValidTextureOverload::kGatherDepth2dArrayOffsetF32:
+            return R"(textureGatherOffset(tint_symbol_sampler, vec3(1.0f, 2.0f, float(3)), 0.0, ivec2(4, 5)))";
+        case ValidTextureOverload::kGatherDepthCubeF32:
+            return R"(textureGather(tint_symbol_sampler, vec3(1.0f, 2.0f, 3.0f), 0.0))";
+        case ValidTextureOverload::kGatherDepthCubeArrayF32:
+            return R"(textureGather(tint_symbol_sampler, vec4(1.0f, 2.0f, 3.0f, float(4)), 0.0))";
+        case ValidTextureOverload::kGatherCompareDepth2dF32:
+            return R"(textureGather(tint_symbol_sampler, vec2(1.0f, 2.0f), 3.0f))";
+        case ValidTextureOverload::kGatherCompareDepth2dOffsetF32:
+            return R"(textureGatherOffset(tint_symbol_sampler, vec2(1.0f, 2.0f), 3.0f, ivec2(4, 5)))";
+        case ValidTextureOverload::kGatherCompareDepth2dArrayF32:
+            return R"(textureGather(tint_symbol_sampler, vec3(1.0f, 2.0f, float(3)), 4.0f))";
+        case ValidTextureOverload::kGatherCompareDepth2dArrayOffsetF32:
+            return R"(textureGatherOffset(tint_symbol_sampler, vec3(1.0f, 2.0f, float(3)), 4.0f, ivec2(5, 6)))";
+        case ValidTextureOverload::kGatherCompareDepthCubeF32:
+            return R"(textureGather(tint_symbol_sampler, vec3(1.0f, 2.0f, 3.0f), 4.0f))";
+        case ValidTextureOverload::kGatherCompareDepthCubeArrayF32:
+            return R"(textureGather(tint_symbol_sampler, vec4(1.0f, 2.0f, 3.0f, float(4)), 5.0f))";
+        case ValidTextureOverload::kNumLayers2dArray:
+        case ValidTextureOverload::kNumLayersDepth2dArray:
+        case ValidTextureOverload::kNumLayersCubeArray:
+        case ValidTextureOverload::kNumLayersDepthCubeArray:
+            return {"textureSize"};
+        case ValidTextureOverload::kNumLayersStorageWO2dArray:
+            return {"imageSize"};
+        case ValidTextureOverload::kNumLevels2d:
+        case ValidTextureOverload::kNumLevelsCube:
+        case ValidTextureOverload::kNumLevelsDepth2d:
+        case ValidTextureOverload::kNumLevelsDepthCube:
+        case ValidTextureOverload::kNumLevels2dArray:
+        case ValidTextureOverload::kNumLevels3d:
+        case ValidTextureOverload::kNumLevelsCubeArray:
+        case ValidTextureOverload::kNumLevelsDepth2dArray:
+        case ValidTextureOverload::kNumLevelsDepthCubeArray:
+            return {"textureQueryLevels"};
+        case ValidTextureOverload::kNumSamplesDepthMultisampled2d:
+        case ValidTextureOverload::kNumSamplesMultisampled2d:
+            return {"textureSamples"};
+        case ValidTextureOverload::kSample1dF32:
+            return R"(texture(tint_symbol_sampler, 1.0f);)";
+        case ValidTextureOverload::kSample2dF32:
+            return R"(texture(tint_symbol_sampler, vec2(1.0f, 2.0f));)";
+        case ValidTextureOverload::kSample2dOffsetF32:
+            return R"(textureOffset(tint_symbol_sampler, vec2(1.0f, 2.0f), ivec2(3, 4));)";
+        case ValidTextureOverload::kSample2dArrayF32:
+            return R"(texture(tint_symbol_sampler, vec3(1.0f, 2.0f, float(3)));)";
+        case ValidTextureOverload::kSample2dArrayOffsetF32:
+            return R"(textureOffset(tint_symbol_sampler, vec3(1.0f, 2.0f, float(3)), ivec2(4, 5));)";
+        case ValidTextureOverload::kSample3dF32:
+            return R"(texture(tint_symbol_sampler, vec3(1.0f, 2.0f, 3.0f));)";
+        case ValidTextureOverload::kSample3dOffsetF32:
+            return R"(textureOffset(tint_symbol_sampler, vec3(1.0f, 2.0f, 3.0f), ivec3(4, 5, 6));)";
+        case ValidTextureOverload::kSampleCubeF32:
+            return R"(texture(tint_symbol_sampler, vec3(1.0f, 2.0f, 3.0f));)";
+        case ValidTextureOverload::kSampleCubeArrayF32:
+            return R"(texture(tint_symbol_sampler, vec4(1.0f, 2.0f, 3.0f, float(4)));)";
+        case ValidTextureOverload::kSampleDepth2dF32:
+            return R"(texture(tint_symbol_sampler, vec3(1.0f, 2.0f, 0.0f));)";
+        case ValidTextureOverload::kSampleDepth2dOffsetF32:
+            return R"(textureOffset(tint_symbol_sampler, vec3(1.0f, 2.0f, 0.0f), ivec2(3, 4));)";
+        case ValidTextureOverload::kSampleDepth2dArrayF32:
+            return R"(texture(tint_symbol_sampler, vec4(1.0f, 2.0f, float(3), 0.0f));)";
+        case ValidTextureOverload::kSampleDepth2dArrayOffsetF32:
+            return R"(textureOffset(tint_symbol_sampler, vec4(1.0f, 2.0f, float(3), 0.0f), ivec2(4, 5));)";
+        case ValidTextureOverload::kSampleDepthCubeF32:
+            return R"(texture(tint_symbol_sampler, vec4(1.0f, 2.0f, 3.0f, 0.0f));)";
+        case ValidTextureOverload::kSampleDepthCubeArrayF32:
+            return R"(texture(tint_symbol_sampler, vec4(1.0f, 2.0f, 3.0f, float(4)), 0.0f);)";
+        case ValidTextureOverload::kSampleBias2dF32:
+            return R"(texture(tint_symbol_sampler, vec2(1.0f, 2.0f), 3.0f);)";
+        case ValidTextureOverload::kSampleBias2dOffsetF32:
+            return R"(textureOffset(tint_symbol_sampler, vec2(1.0f, 2.0f), ivec2(4, 5), 3.0f);)";
+        case ValidTextureOverload::kSampleBias2dArrayF32:
+            return R"(texture(tint_symbol_sampler, vec3(1.0f, 2.0f, float(4)), 3.0f);)";
+        case ValidTextureOverload::kSampleBias2dArrayOffsetF32:
+            return R"(textureOffset(tint_symbol_sampler, vec3(1.0f, 2.0f, float(3)), ivec2(5, 6), 4.0f);)";
+        case ValidTextureOverload::kSampleBias3dF32:
+            return R"(texture(tint_symbol_sampler, vec3(1.0f, 2.0f, 3.0f), 4.0f);)";
+        case ValidTextureOverload::kSampleBias3dOffsetF32:
+            return R"(textureOffset(tint_symbol_sampler, vec3(1.0f, 2.0f, 3.0f), ivec3(5, 6, 7), 4.0f);)";
+        case ValidTextureOverload::kSampleBiasCubeF32:
+            return R"(texture(tint_symbol_sampler, vec3(1.0f, 2.0f, 3.0f), 4.0f);)";
+        case ValidTextureOverload::kSampleBiasCubeArrayF32:
+            return R"(texture(tint_symbol_sampler, vec4(1.0f, 2.0f, 3.0f, float(3)), 4.0f);)";
+        case ValidTextureOverload::kSampleLevel2dF32:
+            return R"(textureLod(tint_symbol_sampler, vec2(1.0f, 2.0f), 3.0f);)";
+        case ValidTextureOverload::kSampleLevel2dOffsetF32:
+            return R"(textureLodOffset(tint_symbol_sampler, vec2(1.0f, 2.0f), 3.0f, ivec2(4, 5));)";
+        case ValidTextureOverload::kSampleLevel2dArrayF32:
+            return R"(textureLod(tint_symbol_sampler, vec3(1.0f, 2.0f, float(3)), 4.0f);)";
+        case ValidTextureOverload::kSampleLevel2dArrayOffsetF32:
+            return R"(textureLodOffset(tint_symbol_sampler, vec3(1.0f, 2.0f, float(3)), 4.0f, ivec2(5, 6));)";
+        case ValidTextureOverload::kSampleLevel3dF32:
+            return R"(textureLod(tint_symbol_sampler, vec3(1.0f, 2.0f, 3.0f), 4.0f);)";
+        case ValidTextureOverload::kSampleLevel3dOffsetF32:
+            return R"(textureLodOffset(tint_symbol_sampler, vec3(1.0f, 2.0f, 3.0f), 4.0f, ivec3(5, 6, 7));)";
+        case ValidTextureOverload::kSampleLevelCubeF32:
+            return R"(textureLod(tint_symbol_sampler, vec3(1.0f, 2.0f, 3.0f), 4.0f);)";
+        case ValidTextureOverload::kSampleLevelCubeArrayF32:
+            return R"(textureLod(tint_symbol_sampler, vec4(1.0f, 2.0f, 3.0f, float(4)), 5.0f);)";
+        case ValidTextureOverload::kSampleLevelDepth2dF32:
+            return R"(textureLod(tint_symbol_sampler, vec3(1.0f, 2.0f, 0.0f), float(3));)";
+        case ValidTextureOverload::kSampleLevelDepth2dOffsetF32:
+            return R"(textureLodOffset(tint_symbol_sampler, vec3(1.0f, 2.0f, 0.0f), float(3), ivec2(4, 5));)";
+        case ValidTextureOverload::kSampleLevelDepth2dArrayF32:
+            return R"(textureLod(tint_symbol_sampler, vec4(1.0f, 2.0f, float(3), 0.0f), float(4));)";
+        case ValidTextureOverload::kSampleLevelDepth2dArrayOffsetF32:
+            return R"(textureLodOffset(tint_symbol_sampler, vec4(1.0f, 2.0f, float(3), 0.0f), float(4), ivec2(5, 6));)";
+        case ValidTextureOverload::kSampleLevelDepthCubeF32:
+            return R"(textureLod(tint_symbol_sampler, vec4(1.0f, 2.0f, 3.0f, 0.0f), float(4)))";
+        case ValidTextureOverload::kSampleLevelDepthCubeArrayF32:
+            return R"(textureLod(tint_symbol_sampler, vec4(1.0f, 2.0f, 3.0f, float(4)), float(5));)";
+        case ValidTextureOverload::kSampleGrad2dF32:
+            return R"(textureGrad(tint_symbol_sampler, vec2(1.0f, 2.0f), vec2(3.0f, 4.0f), vec2(5.0f, 6.0f));)";
+        case ValidTextureOverload::kSampleGrad2dOffsetF32:
+            return R"(textureGradOffset(tint_symbol_sampler, vec2(1.0f, 2.0f), vec2(3.0f, 4.0f), vec2(5.0f, 6.0f), ivec2(7, 7));)";
+        case ValidTextureOverload::kSampleGrad2dArrayF32:
+            return R"(textureGrad(tint_symbol_sampler, vec3(1.0f, 2.0f, float(3)), vec2(4.0f, 5.0f), vec2(6.0f, 7.0f));)";
+        case ValidTextureOverload::kSampleGrad2dArrayOffsetF32:
+            return R"(textureGradOffset(tint_symbol_sampler, vec3(1.0f, 2.0f, float(3)), vec2(4.0f, 5.0f), vec2(6.0f, 7.0f), ivec2(6, 7));)";
+        case ValidTextureOverload::kSampleGrad3dF32:
+            return R"(textureGrad(tint_symbol_sampler, vec3(1.0f, 2.0f, 3.0f), vec3(4.0f, 5.0f, 6.0f), vec3(7.0f, 8.0f, 9.0f));)";
+        case ValidTextureOverload::kSampleGrad3dOffsetF32:
+            return R"(textureGradOffset(tint_symbol_sampler, vec3(1.0f, 2.0f, 3.0f), vec3(4.0f, 5.0f, 6.0f), vec3(7.0f, 8.0f, 9.0f), ivec3(0, 1, 2));)";
+        case ValidTextureOverload::kSampleGradCubeF32:
+            return R"(textureGrad(tint_symbol_sampler, vec3(1.0f, 2.0f, 3.0f), vec3(4.0f, 5.0f, 6.0f), vec3(7.0f, 8.0f, 9.0f));)";
+        case ValidTextureOverload::kSampleGradCubeArrayF32:
+            return R"(textureGrad(tint_symbol_sampler, vec4(1.0f, 2.0f, 3.0f, float(4)), vec3(5.0f, 6.0f, 7.0f), vec3(8.0f, 9.0f, 10.0f));)";
+        case ValidTextureOverload::kSampleCompareDepth2dF32:
+            return R"(texture(tint_symbol_sampler, vec3(1.0f, 2.0f, 3.0f));)";
+        case ValidTextureOverload::kSampleCompareDepth2dOffsetF32:
+            return R"(textureOffset(tint_symbol_sampler, vec3(1.0f, 2.0f, 3.0f), ivec2(4, 5));)";
+        case ValidTextureOverload::kSampleCompareDepth2dArrayF32:
+            return R"(texture(tint_symbol_sampler, vec4(1.0f, 2.0f, float(4), 3.0f));)";
+        case ValidTextureOverload::kSampleCompareDepth2dArrayOffsetF32:
+            return R"(textureOffset(tint_symbol_sampler, vec4(1.0f, 2.0f, float(4), 3.0f), ivec2(5, 6));)";
+        case ValidTextureOverload::kSampleCompareDepthCubeF32:
+            return R"(texture(tint_symbol_sampler, vec4(1.0f, 2.0f, 3.0f, 4.0f));)";
+        case ValidTextureOverload::kSampleCompareDepthCubeArrayF32:
+            return R"(texture(tint_symbol_sampler, vec4(1.0f, 2.0f, 3.0f, float(4)), 5.0f);)";
+        case ValidTextureOverload::kSampleCompareLevelDepth2dF32:
+            return R"(yyytexture(tint_symbol_sampler, vec2(1.0f, 2.0f), 3.0f);)";
+        case ValidTextureOverload::kSampleCompareLevelDepth2dOffsetF32:
+            return R"(yyytextureOffset(tint_symbol_sampler, vec2(1.0f, 2.0f), 3.0f, ivec2(4, 5));)";
+        case ValidTextureOverload::kSampleCompareLevelDepth2dArrayF32:
+            return R"(texture(tint_symbol_sampler, vec4(1.0f, 2.0f, float(4)), 3.0f);)";
+        case ValidTextureOverload::kSampleCompareLevelDepth2dArrayOffsetF32:
+            return R"(textureOffset(tint_symbol_sampler, vec3(1.0f, 2.0f, float(4)), 3.0f, ivec2(5, 6));)";
+        case ValidTextureOverload::kSampleCompareLevelDepthCubeF32:
+            return R"(texture(tint_symbol_sampler, vec3(1.0f, 2.0f, 3.0f), 4.0f);)";
+        case ValidTextureOverload::kSampleCompareLevelDepthCubeArrayF32:
+            return R"(texture(tint_symbol_sampler, vec4(1.0f, 2.0f, 3.0f, float(4)), 5.0f);)";
+        case ValidTextureOverload::kLoad1dLevelF32:
+        case ValidTextureOverload::kLoad1dLevelU32:
+        case ValidTextureOverload::kLoad1dLevelI32:
+            return R"(texelFetch(tint_symbol_2, 1, 3);)";
+        case ValidTextureOverload::kLoad2dLevelF32:
+        case ValidTextureOverload::kLoad2dLevelU32:
+        case ValidTextureOverload::kLoad2dLevelI32:
+            return R"(texelFetch(tint_symbol_2, ivec2(1, 2), 3);)";
+        case ValidTextureOverload::kLoad2dArrayLevelF32:
+        case ValidTextureOverload::kLoad2dArrayLevelU32:
+        case ValidTextureOverload::kLoad2dArrayLevelI32:
+        case ValidTextureOverload::kLoad3dLevelF32:
+        case ValidTextureOverload::kLoad3dLevelU32:
+        case ValidTextureOverload::kLoad3dLevelI32:
+            return R"(texelFetch(tint_symbol_2, ivec3(1, 2, 3), 4);)";
+        case ValidTextureOverload::kLoadDepthMultisampled2dF32:
+        case ValidTextureOverload::kLoadMultisampled2dF32:
+        case ValidTextureOverload::kLoadMultisampled2dU32:
+        case ValidTextureOverload::kLoadMultisampled2dI32:
+            return R"(texelFetch(tint_symbol_2, ivec2(1, 2), 3);)";
+        case ValidTextureOverload::kLoadDepth2dLevelF32:
+            return R"(texelFetch(tint_symbol_2, ivec2(1, 2), 3);)";
+        case ValidTextureOverload::kLoadDepth2dArrayLevelF32:
+            return R"(texelFetch(tint_symbol_2, ivec3(1, 2, 3), 4);)";
+        case ValidTextureOverload::kStoreWO1dRgba32float:
+            return R"(imageStore(tint_symbol, 1, vec4(2.0f, 3.0f, 4.0f, 5.0f));)";
+        case ValidTextureOverload::kStoreWO2dRgba32float:
+            return R"(imageStore(tint_symbol, ivec2(1, 2), vec4(3.0f, 4.0f, 5.0f, 6.0f));)";
+        case ValidTextureOverload::kStoreWO2dArrayRgba32float:
+            return R"(imageStore(tint_symbol, ivec3(1, 2, 3), vec4(4.0f, 5.0f, 6.0f, 7.0f));)";
+        case ValidTextureOverload::kStoreWO3dRgba32float:
+            return R"(imageStore(tint_symbol, ivec3(1, 2, 3), vec4(4.0f, 5.0f, 6.0f, 7.0f));)";
+    }
+    return "<unmatched texture overload>";
 }  // NOLINT - Ignore the length of this function
 
 class GlslGeneratorBuiltinTextureTest
     : public TestParamHelper<ast::builtin::test::TextureOverloadCase> {};
 
 TEST_P(GlslGeneratorBuiltinTextureTest, Call) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  param.BuildTextureVariable(this);
-  param.BuildSamplerVariable(this);
+    param.BuildTextureVariable(this);
+    param.BuildSamplerVariable(this);
 
-  auto* call = Call(param.function, param.args(this));
-  auto* stmt = CallStmt(call);
+    auto* call = Call(param.function, param.args(this));
+    auto* stmt = CallStmt(call);
 
-  Func("main", {}, ty.void_(), {stmt}, {Stage(ast::PipelineStage::kFragment)});
+    Func("main", {}, ty.void_(), {stmt}, {Stage(ast::PipelineStage::kFragment)});
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
+    ASSERT_TRUE(gen.Generate()) << gen.error();
 
-  auto expected = expected_texture_overload(param.overload);
+    auto expected = expected_texture_overload(param.overload);
 
-  EXPECT_THAT(gen.result(), HasSubstr(expected.pre));
-  EXPECT_THAT(gen.result(), HasSubstr(expected.out));
+    EXPECT_THAT(gen.result(), HasSubstr(expected.pre));
+    EXPECT_THAT(gen.result(), HasSubstr(expected.out));
 }
 
-INSTANTIATE_TEST_SUITE_P(
-    GlslGeneratorBuiltinTextureTest,
-    GlslGeneratorBuiltinTextureTest,
-    testing::ValuesIn(ast::builtin::test::TextureOverloadCase::ValidCases()));
+INSTANTIATE_TEST_SUITE_P(GlslGeneratorBuiltinTextureTest,
+                         GlslGeneratorBuiltinTextureTest,
+                         testing::ValuesIn(ast::builtin::test::TextureOverloadCase::ValidCases()));
 
 }  // namespace
 }  // namespace tint::writer::glsl
diff --git a/src/tint/writer/glsl/generator_impl_call_test.cc b/src/tint/writer/glsl/generator_impl_call_test.cc
index fc74bb9..9b6a1c3 100644
--- a/src/tint/writer/glsl/generator_impl_call_test.cc
+++ b/src/tint/writer/glsl/generator_impl_call_test.cc
@@ -21,56 +21,56 @@
 using GlslGeneratorImplTest_Call = TestHelper;
 
 TEST_F(GlslGeneratorImplTest_Call, EmitExpression_Call_WithoutParams) {
-  Func("my_func", {}, ty.f32(), {Return(1.23f)});
+    Func("my_func", {}, ty.f32(), {Return(1.23f)});
 
-  auto* call = Call("my_func");
-  WrapInFunction(call);
+    auto* call = Call("my_func");
+    WrapInFunction(call);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
-  EXPECT_EQ(out.str(), "my_func()");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
+    EXPECT_EQ(out.str(), "my_func()");
 }
 
 TEST_F(GlslGeneratorImplTest_Call, EmitExpression_Call_WithParams) {
-  Func("my_func",
-       {
-           Param(Sym(), ty.f32()),
-           Param(Sym(), ty.f32()),
-       },
-       ty.f32(), {Return(1.23f)});
-  Global("param1", ty.f32(), ast::StorageClass::kPrivate);
-  Global("param2", ty.f32(), ast::StorageClass::kPrivate);
+    Func("my_func",
+         {
+             Param(Sym(), ty.f32()),
+             Param(Sym(), ty.f32()),
+         },
+         ty.f32(), {Return(1.23f)});
+    Global("param1", ty.f32(), ast::StorageClass::kPrivate);
+    Global("param2", ty.f32(), ast::StorageClass::kPrivate);
 
-  auto* call = Call("my_func", "param1", "param2");
-  WrapInFunction(call);
+    auto* call = Call("my_func", "param1", "param2");
+    WrapInFunction(call);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
-  EXPECT_EQ(out.str(), "my_func(param1, param2)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
+    EXPECT_EQ(out.str(), "my_func(param1, param2)");
 }
 
 TEST_F(GlslGeneratorImplTest_Call, EmitStatement_Call) {
-  Func("my_func",
-       {
-           Param(Sym(), ty.f32()),
-           Param(Sym(), ty.f32()),
-       },
-       ty.void_(), ast::StatementList{}, ast::AttributeList{});
-  Global("param1", ty.f32(), ast::StorageClass::kPrivate);
-  Global("param2", ty.f32(), ast::StorageClass::kPrivate);
+    Func("my_func",
+         {
+             Param(Sym(), ty.f32()),
+             Param(Sym(), ty.f32()),
+         },
+         ty.void_(), ast::StatementList{}, ast::AttributeList{});
+    Global("param1", ty.f32(), ast::StorageClass::kPrivate);
+    Global("param2", ty.f32(), ast::StorageClass::kPrivate);
 
-  auto* call = CallStmt(Call("my_func", "param1", "param2"));
-  WrapInFunction(call);
+    auto* call = CallStmt(Call("my_func", "param1", "param2"));
+    WrapInFunction(call);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
-  ASSERT_TRUE(gen.EmitStatement(call)) << gen.error();
-  EXPECT_EQ(gen.result(), "  my_func(param1, param2);\n");
+    gen.increment_indent();
+    ASSERT_TRUE(gen.EmitStatement(call)) << gen.error();
+    EXPECT_EQ(gen.result(), "  my_func(param1, param2);\n");
 }
 
 }  // namespace
diff --git a/src/tint/writer/glsl/generator_impl_case_test.cc b/src/tint/writer/glsl/generator_impl_case_test.cc
index ecf3937..02d1665 100644
--- a/src/tint/writer/glsl/generator_impl_case_test.cc
+++ b/src/tint/writer/glsl/generator_impl_case_test.cc
@@ -15,70 +15,70 @@
 #include "src/tint/ast/fallthrough_statement.h"
 #include "src/tint/writer/glsl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::glsl {
 namespace {
 
 using GlslGeneratorImplTest_Case = TestHelper;
 
 TEST_F(GlslGeneratorImplTest_Case, Emit_Case) {
-  auto* s = Switch(1, Case(Expr(5), Block(create<ast::BreakStatement>())),
-                   DefaultCase());
-  WrapInFunction(s);
+    auto* s = Switch(1_i, Case(Expr(5_i), Block(create<ast::BreakStatement>())), DefaultCase());
+    WrapInFunction(s);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitCase(s->body[0])) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  case 5: {
+    ASSERT_TRUE(gen.EmitCase(s->body[0])) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  case 5: {
     break;
   }
 )");
 }
 
 TEST_F(GlslGeneratorImplTest_Case, Emit_Case_BreaksByDefault) {
-  auto* s = Switch(1, Case(Expr(5), Block()), DefaultCase());
-  WrapInFunction(s);
+    auto* s = Switch(1_i, Case(Expr(5_i), Block()), DefaultCase());
+    WrapInFunction(s);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitCase(s->body[0])) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  case 5: {
+    ASSERT_TRUE(gen.EmitCase(s->body[0])) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  case 5: {
     break;
   }
 )");
 }
 
 TEST_F(GlslGeneratorImplTest_Case, Emit_Case_WithFallthrough) {
-  auto* s = Switch(1, Case(Expr(5), Block(create<ast::FallthroughStatement>())),
-                   DefaultCase());
-  WrapInFunction(s);
+    auto* s =
+        Switch(1_i, Case(Expr(5_i), Block(create<ast::FallthroughStatement>())), DefaultCase());
+    WrapInFunction(s);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitCase(s->body[0])) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  case 5: {
+    ASSERT_TRUE(gen.EmitCase(s->body[0])) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  case 5: {
     /* fallthrough */
   }
 )");
 }
 
 TEST_F(GlslGeneratorImplTest_Case, Emit_Case_MultipleSelectors) {
-  auto* s =
-      Switch(1, Case({Expr(5), Expr(6)}, Block(create<ast::BreakStatement>())),
-             DefaultCase());
-  WrapInFunction(s);
+    auto* s = Switch(1_i, Case({Expr(5_i), Expr(6_i)}, Block(create<ast::BreakStatement>())),
+                     DefaultCase());
+    WrapInFunction(s);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitCase(s->body[0])) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  case 5:
+    ASSERT_TRUE(gen.EmitCase(s->body[0])) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  case 5:
   case 6: {
     break;
   }
@@ -86,15 +86,15 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Case, Emit_Case_Default) {
-  auto* s = Switch(1, DefaultCase(Block(create<ast::BreakStatement>())));
-  WrapInFunction(s);
+    auto* s = Switch(1_i, DefaultCase(Block(create<ast::BreakStatement>())));
+    WrapInFunction(s);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitCase(s->body[0])) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  default: {
+    ASSERT_TRUE(gen.EmitCase(s->body[0])) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  default: {
     break;
   }
 )");
diff --git a/src/tint/writer/glsl/generator_impl_cast_test.cc b/src/tint/writer/glsl/generator_impl_cast_test.cc
index 8228af6..3666782 100644
--- a/src/tint/writer/glsl/generator_impl_cast_test.cc
+++ b/src/tint/writer/glsl/generator_impl_cast_test.cc
@@ -14,31 +14,33 @@
 
 #include "src/tint/writer/glsl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::glsl {
 namespace {
 
 using GlslGeneratorImplTest_Cast = TestHelper;
 
 TEST_F(GlslGeneratorImplTest_Cast, EmitExpression_Cast_Scalar) {
-  auto* cast = Construct<f32>(1);
-  WrapInFunction(cast);
+    auto* cast = Construct<f32>(1_i);
+    WrapInFunction(cast);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, cast)) << gen.error();
-  EXPECT_EQ(out.str(), "float(1)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, cast)) << gen.error();
+    EXPECT_EQ(out.str(), "float(1)");
 }
 
 TEST_F(GlslGeneratorImplTest_Cast, EmitExpression_Cast_Vector) {
-  auto* cast = vec3<f32>(vec3<i32>(1, 2, 3));
-  WrapInFunction(cast);
+    auto* cast = vec3<f32>(vec3<i32>(1_i, 2_i, 3_i));
+    WrapInFunction(cast);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, cast)) << gen.error();
-  EXPECT_EQ(out.str(), "vec3(ivec3(1, 2, 3))");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, cast)) << gen.error();
+    EXPECT_EQ(out.str(), "vec3(ivec3(1, 2, 3))");
 }
 
 }  // namespace
diff --git a/src/tint/writer/glsl/generator_impl_constructor_test.cc b/src/tint/writer/glsl/generator_impl_constructor_test.cc
index 51f2943..c247bab 100644
--- a/src/tint/writer/glsl/generator_impl_constructor_test.cc
+++ b/src/tint/writer/glsl/generator_impl_constructor_test.cc
@@ -15,6 +15,8 @@
 #include "gmock/gmock.h"
 #include "src/tint/writer/glsl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::glsl {
 namespace {
 
@@ -23,213 +25,202 @@
 using GlslGeneratorImplTest_Constructor = TestHelper;
 
 TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Bool) {
-  WrapInFunction(Expr(false));
+    WrapInFunction(Expr(false));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("false"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("false"));
 }
 
 TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Int) {
-  WrapInFunction(Expr(-12345));
+    WrapInFunction(Expr(i32(-12345)));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("-12345"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("-12345"));
 }
 
 TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_UInt) {
-  WrapInFunction(Expr(56779u));
+    WrapInFunction(Expr(56779_u));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("56779u"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("56779u"));
 }
 
 TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Float) {
-  // Use a number close to 1<<30 but whose decimal representation ends in 0.
-  WrapInFunction(Expr(static_cast<float>((1 << 30) - 4)));
+    // Use a number close to 1<<30 but whose decimal representation ends in 0.
+    WrapInFunction(Expr(f32((1 << 30) - 4)));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("1073741824.0f"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("1073741824.0f"));
 }
 
 TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Float) {
-  WrapInFunction(Construct<f32>(-1.2e-5f));
+    WrapInFunction(Construct<f32>(-1.2e-5f));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("float(-0.000012f)"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("float(-0.000012f)"));
 }
 
 TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Bool) {
-  WrapInFunction(Construct<bool>(true));
+    WrapInFunction(Construct<bool>(true));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("bool(true)"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("bool(true)"));
 }
 
 TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Int) {
-  WrapInFunction(Construct<i32>(-12345));
+    WrapInFunction(Construct<i32>(i32(-12345)));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("int(-12345)"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("int(-12345)"));
 }
 
 TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Uint) {
-  WrapInFunction(Construct<u32>(12345u));
+    WrapInFunction(Construct<u32>(12345_u));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("uint(12345u)"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("uint(12345u)"));
 }
 
 TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec) {
-  WrapInFunction(vec3<f32>(1.f, 2.f, 3.f));
+    WrapInFunction(vec3<f32>(1.f, 2.f, 3.f));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("vec3(1.0f, 2.0f, 3.0f)"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("vec3(1.0f, 2.0f, 3.0f)"));
 }
 
 TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_Empty) {
-  WrapInFunction(vec3<f32>());
+    WrapInFunction(vec3<f32>());
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("vec3(0.0f, 0.0f, 0.0f)"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("vec3(0.0f, 0.0f, 0.0f)"));
 }
 
-TEST_F(GlslGeneratorImplTest_Constructor,
-       EmitConstructor_Type_Vec_SingleScalar_Float) {
-  WrapInFunction(vec3<f32>(2.0f));
+TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_SingleScalar_Float) {
+    WrapInFunction(vec3<f32>(2.0f));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("vec3(2.0f)"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("vec3(2.0f)"));
 }
 
-TEST_F(GlslGeneratorImplTest_Constructor,
-       EmitConstructor_Type_Vec_SingleScalar_Bool) {
-  WrapInFunction(vec3<bool>(true));
+TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_SingleScalar_Bool) {
+    WrapInFunction(vec3<bool>(true));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("bvec3(true)"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("bvec3(true)"));
 }
 
-TEST_F(GlslGeneratorImplTest_Constructor,
-       EmitConstructor_Type_Vec_SingleScalar_Int) {
-  WrapInFunction(vec3<i32>(2));
+TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_SingleScalar_Int) {
+    WrapInFunction(vec3<i32>(2_i));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("ivec3(2)"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("ivec3(2)"));
 }
 
-TEST_F(GlslGeneratorImplTest_Constructor,
-       EmitConstructor_Type_Vec_SingleScalar_UInt) {
-  WrapInFunction(vec3<u32>(2u));
+TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_SingleScalar_UInt) {
+    WrapInFunction(vec3<u32>(2_u));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("uvec3(2u)"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("uvec3(2u)"));
 }
 
 TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Mat) {
-  WrapInFunction(
-      mat2x3<f32>(vec3<f32>(1.f, 2.f, 3.f), vec3<f32>(3.f, 4.f, 5.f)));
+    WrapInFunction(mat2x3<f32>(vec3<f32>(1.f, 2.f, 3.f), vec3<f32>(3.f, 4.f, 5.f)));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
+    ASSERT_TRUE(gen.Generate()) << gen.error();
 
-  EXPECT_THAT(
-      gen.result(),
-      HasSubstr("mat2x3(vec3(1.0f, 2.0f, 3.0f), vec3(3.0f, 4.0f, 5.0f))"));
+    EXPECT_THAT(gen.result(), HasSubstr("mat2x3(vec3(1.0f, 2.0f, 3.0f), vec3(3.0f, 4.0f, 5.0f))"));
 }
 
 TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Mat_Empty) {
-  WrapInFunction(mat2x3<f32>());
+    WrapInFunction(mat2x3<f32>());
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
+    ASSERT_TRUE(gen.Generate()) << gen.error();
 
-  EXPECT_THAT(gen.result(),
-              HasSubstr("mat2x3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)"));
+    EXPECT_THAT(gen.result(), HasSubstr("mat2x3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)"));
 }
 
 TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Array) {
-  WrapInFunction(Construct(ty.array(ty.vec3<f32>(), 3),
-                           vec3<f32>(1.f, 2.f, 3.f), vec3<f32>(4.f, 5.f, 6.f),
-                           vec3<f32>(7.f, 8.f, 9.f)));
+    WrapInFunction(Construct(ty.array(ty.vec3<f32>(), 3_u), vec3<f32>(1.f, 2.f, 3.f),
+                             vec3<f32>(4.f, 5.f, 6.f), vec3<f32>(7.f, 8.f, 9.f)));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("vec3[3](vec3(1.0f, 2.0f, 3.0f), "
-                                      "vec3(4.0f, 5.0f, 6.0f), "
-                                      "vec3(7.0f, 8.0f, 9.0f))"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("vec3[3](vec3(1.0f, 2.0f, 3.0f), "
+                                        "vec3(4.0f, 5.0f, 6.0f), "
+                                        "vec3(7.0f, 8.0f, 9.0f))"));
 }
 
 TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Array_Empty) {
-  WrapInFunction(Construct(ty.array(ty.vec3<f32>(), 3)));
+    WrapInFunction(Construct(ty.array(ty.vec3<f32>(), 3_u)));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(
-      gen.result(),
-      HasSubstr("vec3[3](vec3(0.0f, 0.0f, 0.0f), vec3(0.0f, 0.0f, 0.0f),"
-                " vec3(0.0f, 0.0f, 0.0f))"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("vec3[3](vec3(0.0f, 0.0f, 0.0f), vec3(0.0f, 0.0f, 0.0f),"
+                                        " vec3(0.0f, 0.0f, 0.0f))"));
 }
 
 TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Struct) {
-  auto* str = Structure("S", {
-                                 Member("a", ty.i32()),
-                                 Member("b", ty.f32()),
-                                 Member("c", ty.vec3<i32>()),
-                             });
+    auto* str = Structure("S", {
+                                   Member("a", ty.i32()),
+                                   Member("b", ty.f32()),
+                                   Member("c", ty.vec3<i32>()),
+                               });
 
-  WrapInFunction(Construct(ty.Of(str), 1, 2.0f, vec3<i32>(3, 4, 5)));
+    WrapInFunction(Construct(ty.Of(str), 1_i, 2.0f, vec3<i32>(3_i, 4_i, 5_i)));
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("S(1, 2.0f, ivec3(3, 4, 5))"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("S(1, 2.0f, ivec3(3, 4, 5))"));
 }
 
 TEST_F(GlslGeneratorImplTest_Constructor, EmitConstructor_Type_Struct_Empty) {
-  auto* str = Structure("S", {
-                                 Member("a", ty.i32()),
-                                 Member("b", ty.f32()),
-                                 Member("c", ty.vec3<i32>()),
-                             });
+    auto* str = Structure("S", {
+                                   Member("a", ty.i32()),
+                                   Member("b", ty.f32()),
+                                   Member("c", ty.vec3<i32>()),
+                               });
 
-  WrapInFunction(Construct(ty.Of(str)));
+    WrapInFunction(Construct(ty.Of(str)));
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("S(0"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("S(0"));
 }
 
 }  // namespace
diff --git a/src/tint/writer/glsl/generator_impl_continue_test.cc b/src/tint/writer/glsl/generator_impl_continue_test.cc
index 961aec5..331ce79 100644
--- a/src/tint/writer/glsl/generator_impl_continue_test.cc
+++ b/src/tint/writer/glsl/generator_impl_continue_test.cc
@@ -20,16 +20,15 @@
 using GlslGeneratorImplTest_Continue = TestHelper;
 
 TEST_F(GlslGeneratorImplTest_Continue, Emit_Continue) {
-  auto* loop = Loop(Block(If(false, Block(Break())),  //
-                          Continue()));
-  WrapInFunction(loop);
+    auto* loop = Loop(Block(If(false, Block(Break())), Continue()));
+    WrapInFunction(loop);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(loop)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  while (true) {
+    ASSERT_TRUE(gen.EmitStatement(loop)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  while (true) {
     if (false) {
       break;
     }
diff --git a/src/tint/writer/glsl/generator_impl_discard_test.cc b/src/tint/writer/glsl/generator_impl_discard_test.cc
index 7f3f183..87c85cb 100644
--- a/src/tint/writer/glsl/generator_impl_discard_test.cc
+++ b/src/tint/writer/glsl/generator_impl_discard_test.cc
@@ -20,15 +20,15 @@
 using GlslGeneratorImplTest_Discard = TestHelper;
 
 TEST_F(GlslGeneratorImplTest_Discard, Emit_Discard) {
-  auto* stmt = create<ast::DiscardStatement>();
-  WrapInFunction(stmt);
+    auto* stmt = create<ast::DiscardStatement>();
+    WrapInFunction(stmt);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
-  EXPECT_EQ(gen.result(), "  discard;\n");
+    ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
+    EXPECT_EQ(gen.result(), "  discard;\n");
 }
 
 }  // namespace
diff --git a/src/tint/writer/glsl/generator_impl_function_test.cc b/src/tint/writer/glsl/generator_impl_function_test.cc
index c9aa3b9..8b91cef 100644
--- a/src/tint/writer/glsl/generator_impl_function_test.cc
+++ b/src/tint/writer/glsl/generator_impl_function_test.cc
@@ -20,23 +20,25 @@
 
 using ::testing::HasSubstr;
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::glsl {
 namespace {
 
 using GlslGeneratorImplTest_Function = TestHelper;
 
 TEST_F(GlslGeneratorImplTest_Function, Emit_Function) {
-  Func("my_func", ast::VariableList{}, ty.void_(),
-       {
-           Return(),
-       });
+    Func("my_func", ast::VariableList{}, ty.void_(),
+         {
+             Return(),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  #version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  #version 310 es
 
   void my_func() {
     return;
@@ -46,34 +48,33 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Function, Emit_Function_Name_Collision) {
-  Func("centroid", ast::VariableList{}, ty.void_(),
-       {
-           Return(),
-       });
+    Func("centroid", ast::VariableList{}, ty.void_(),
+         {
+             Return(),
+         });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr(R"(  void tint_symbol() {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr(R"(  void tint_symbol() {
     return;
   })"));
 }
 
 TEST_F(GlslGeneratorImplTest_Function, Emit_Function_WithParams) {
-  Func("my_func", ast::VariableList{Param("a", ty.f32()), Param("b", ty.i32())},
-       ty.void_(),
-       {
-           Return(),
-       });
+    Func("my_func", ast::VariableList{Param("a", ty.f32()), Param("b", ty.i32())}, ty.void_(),
+         {
+             Return(),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  #version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  #version 310 es
 
   void my_func(float a, int b) {
     return;
@@ -82,17 +83,16 @@
 )");
 }
 
-TEST_F(GlslGeneratorImplTest_Function,
-       Emit_Attribute_EntryPoint_NoReturn_Void) {
-  Func("func", ast::VariableList{}, ty.void_(), {/* no explicit return */},
-       {
-           Stage(ast::PipelineStage::kFragment),
-       });
+TEST_F(GlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_NoReturn_Void) {
+    Func("func", ast::VariableList{}, ty.void_(), {/* no explicit return */},
+         {
+             Stage(ast::PipelineStage::kFragment),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 precision mediump float;
 
 void func() {
@@ -102,34 +102,33 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Function, PtrParameter) {
-  // fn f(foo : ptr<function, f32>) -> f32 {
-  //   return *foo;
-  // }
-  Func("f", {Param("foo", ty.pointer<f32>(ast::StorageClass::kFunction))},
-       ty.f32(), {Return(Deref("foo"))});
+    // fn f(foo : ptr<function, f32>) -> f32 {
+    //   return *foo;
+    // }
+    Func("f", {Param("foo", ty.pointer<f32>(ast::StorageClass::kFunction))}, ty.f32(),
+         {Return(Deref("foo"))});
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr(R"(float f(inout float foo) {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr(R"(float f(inout float foo) {
   return foo;
 }
 )"));
 }
 
-TEST_F(GlslGeneratorImplTest_Function,
-       Emit_Attribute_EntryPoint_WithInOutVars) {
-  // fn frag_main(@location(0) foo : f32) -> @location(1) f32 {
-  //   return foo;
-  // }
-  auto* foo_in = Param("foo", ty.f32(), {Location(0)});
-  Func("frag_main", ast::VariableList{foo_in}, ty.f32(), {Return("foo")},
-       {Stage(ast::PipelineStage::kFragment)}, {Location(1)});
+TEST_F(GlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_WithInOutVars) {
+    // fn frag_main(@location(0) foo : f32) -> @location(1) f32 {
+    //   return foo;
+    // }
+    auto* foo_in = Param("foo", ty.f32(), {Location(0)});
+    Func("frag_main", ast::VariableList{foo_in}, ty.f32(), {Return("foo")},
+         {Stage(ast::PipelineStage::kFragment)}, {Location(1)});
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 precision mediump float;
 
 layout(location = 0) in float foo_1;
@@ -146,22 +145,18 @@
 )");
 }
 
-TEST_F(GlslGeneratorImplTest_Function,
-       Emit_Attribute_EntryPoint_WithInOut_Builtins) {
-  // 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)});
-  Func("frag_main", ast::VariableList{coord_in}, ty.f32(),
-       {Return(MemberAccessor("coord", "x"))},
-       {Stage(ast::PipelineStage::kFragment)},
-       {Builtin(ast::Builtin::kFragDepth)});
+TEST_F(GlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_WithInOut_Builtins) {
+    // 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)});
+    Func("frag_main", ast::VariableList{coord_in}, ty.f32(), {Return(MemberAccessor("coord", "x"))},
+         {Stage(ast::PipelineStage::kFragment)}, {Builtin(ast::Builtin::kFragDepth)});
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 precision mediump float;
 
 float frag_main(vec4 coord) {
@@ -176,46 +171,44 @@
 )");
 }
 
-TEST_F(GlslGeneratorImplTest_Function,
-       Emit_Attribute_EntryPoint_SharedStruct_DifferentStages) {
-  // struct Interface {
-  //   @builtin(position) pos : vec4<f32>;
-  //   @location(1) col1 : f32;
-  //   @location(2) col2 : f32;
-  // };
-  // fn vert_main() -> Interface {
-  //   return Interface(vec4<f32>(), 0.4, 0.6);
-  // }
-  // fn frag_main(inputs : Interface) {
-  //   const r = inputs.col1;
-  //   const g = inputs.col2;
-  //   const p = inputs.pos;
-  // }
-  auto* interface_struct = Structure(
-      "Interface",
-      {
-          Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)}),
-          Member("col1", ty.f32(), {Location(1)}),
-          Member("col2", ty.f32(), {Location(2)}),
-      });
+TEST_F(GlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_SharedStruct_DifferentStages) {
+    // struct Interface {
+    //   @builtin(position) pos : vec4<f32>;
+    //   @location(1) col1 : f32;
+    //   @location(2) col2 : f32;
+    // };
+    // fn vert_main() -> Interface {
+    //   return Interface(vec4<f32>(), 0.4, 0.6);
+    // }
+    // fn frag_main(inputs : Interface) {
+    //   const r = inputs.col1;
+    //   const g = inputs.col2;
+    //   const p = inputs.pos;
+    // }
+    auto* interface_struct = Structure(
+        "Interface", {
+                         Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)}),
+                         Member("col1", ty.f32(), {Location(1)}),
+                         Member("col2", ty.f32(), {Location(2)}),
+                     });
 
-  Func("vert_main", {}, ty.Of(interface_struct),
-       {Return(Construct(ty.Of(interface_struct), Construct(ty.vec4<f32>()),
-                         Expr(0.5f), Expr(0.25f)))},
-       {Stage(ast::PipelineStage::kVertex)});
+    Func("vert_main", {}, ty.Of(interface_struct),
+         {Return(Construct(ty.Of(interface_struct), Construct(ty.vec4<f32>()), Expr(0.5f),
+                           Expr(0.25f)))},
+         {Stage(ast::PipelineStage::kVertex)});
 
-  Func("frag_main", {Param("inputs", ty.Of(interface_struct))}, ty.void_(),
-       {
-           Decl(Const("r", ty.f32(), MemberAccessor("inputs", "col1"))),
-           Decl(Const("g", ty.f32(), MemberAccessor("inputs", "col2"))),
-           Decl(Const("p", ty.vec4<f32>(), MemberAccessor("inputs", "pos"))),
-       },
-       {Stage(ast::PipelineStage::kFragment)});
+    Func("frag_main", {Param("inputs", ty.Of(interface_struct))}, ty.void_(),
+         {
+             Decl(Let("r", ty.f32(), MemberAccessor("inputs", "col1"))),
+             Decl(Let("g", ty.f32(), MemberAccessor("inputs", "col2"))),
+             Decl(Let("p", ty.vec4<f32>(), MemberAccessor("inputs", "pos"))),
+         },
+         {Stage(ast::PipelineStage::kFragment)});
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 precision mediump float;
 
 layout(location = 1) out float col1_1;
@@ -234,6 +227,7 @@
 }
 
 void main() {
+  gl_PointSize = 1.0;
   Interface inner_result = vert_main();
   gl_Position = inner_result.pos;
   col1_1 = inner_result.col1;
@@ -326,38 +320,37 @@
 #endif
 
 TEST_F(GlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_With_Uniform) {
-  auto* ubo_ty = Structure("UBO", {Member("coord", ty.vec4<f32>())});
-  auto* ubo = Global("ubo", ty.Of(ubo_ty), ast::StorageClass::kUniform,
-                     ast::AttributeList{
-                         create<ast::BindingAttribute>(0),
-                         create<ast::GroupAttribute>(1),
-                     });
+    auto* ubo_ty = Structure("UBO", {Member("coord", ty.vec4<f32>())});
+    auto* ubo = Global("ubo", ty.Of(ubo_ty), ast::StorageClass::kUniform,
+                       ast::AttributeList{
+                           create<ast::BindingAttribute>(0),
+                           create<ast::GroupAttribute>(1),
+                       });
 
-  Func("sub_func",
-       {
-           Param("param", ty.f32()),
-       },
-       ty.f32(),
-       {
-           Return(MemberAccessor(MemberAccessor(ubo, "coord"), "x")),
-       });
+    Func("sub_func",
+         {
+             Param("param", ty.f32()),
+         },
+         ty.f32(),
+         {
+             Return(MemberAccessor(MemberAccessor(ubo, "coord"), "x")),
+         });
 
-  auto* var =
-      Var("v", ty.f32(), ast::StorageClass::kNone, Call("sub_func", 1.0f));
+    auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, Call("sub_func", 1.0f));
 
-  Func("frag_main", {}, ty.void_(),
-       {
-           Decl(var),
-           Return(),
-       },
-       {
-           Stage(ast::PipelineStage::kFragment),
-       });
+    Func("frag_main", {}, ty.void_(),
+         {
+             Decl(var),
+             Return(),
+         },
+         {
+             Stage(ast::PipelineStage::kFragment),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 precision mediump float;
 
 struct UBO {
@@ -379,32 +372,31 @@
 )");
 }
 
-TEST_F(GlslGeneratorImplTest_Function,
-       Emit_Attribute_EntryPoint_With_UniformStruct) {
-  auto* s = Structure("Uniforms", {Member("coord", ty.vec4<f32>())});
+TEST_F(GlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_With_UniformStruct) {
+    auto* s = Structure("Uniforms", {Member("coord", ty.vec4<f32>())});
 
-  Global("uniforms", ty.Of(s), ast::StorageClass::kUniform,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(1),
+    Global("uniforms", ty.Of(s), ast::StorageClass::kUniform,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(1),
+           });
+
+    auto* var = Var("v", ty.f32(), ast::StorageClass::kNone,
+                    MemberAccessor(MemberAccessor("uniforms", "coord"), "x"));
+
+    Func("frag_main", ast::VariableList{}, ty.void_(),
+         {
+             Decl(var),
+             Return(),
+         },
+         {
+             Stage(ast::PipelineStage::kFragment),
          });
 
-  auto* var = Var("v", ty.f32(), ast::StorageClass::kNone,
-                  MemberAccessor(MemberAccessor("uniforms", "coord"), "x"));
+    GeneratorImpl& gen = Build();
 
-  Func("frag_main", ast::VariableList{}, ty.void_(),
-       {
-           Decl(var),
-           Return(),
-       },
-       {
-           Stage(ast::PipelineStage::kFragment),
-       });
-
-  GeneratorImpl& gen = Build();
-
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 precision mediump float;
 
 struct Uniforms {
@@ -422,36 +414,33 @@
 )");
 }
 
-TEST_F(GlslGeneratorImplTest_Function,
-       Emit_Attribute_EntryPoint_With_RW_StorageBuffer_Read) {
-  auto* s = Structure("Data", {
-                                  Member("a", ty.i32()),
-                                  Member("b", ty.f32()),
-                              });
+TEST_F(GlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_With_RW_StorageBuffer_Read) {
+    auto* s = Structure("Data", {
+                                    Member("a", ty.i32()),
+                                    Member("b", ty.f32()),
+                                });
 
-  Global("coord", ty.Of(s), ast::StorageClass::kStorage,
-         ast::Access::kReadWrite,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(1),
+    Global("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(1),
+           });
+
+    auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, MemberAccessor("coord", "b"));
+
+    Func("frag_main", ast::VariableList{}, ty.void_(),
+         {
+             Decl(var),
+             Return(),
+         },
+         {
+             Stage(ast::PipelineStage::kFragment),
          });
 
-  auto* var = Var("v", ty.f32(), ast::StorageClass::kNone,
-                  MemberAccessor("coord", "b"));
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  Func("frag_main", ast::VariableList{}, ty.void_(),
-       {
-           Decl(var),
-           Return(),
-       },
-       {
-           Stage(ast::PipelineStage::kFragment),
-       });
-
-  GeneratorImpl& gen = SanitizeAndBuild();
-
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 precision mediump float;
 
 struct Data {
@@ -475,36 +464,34 @@
 )");
 }
 
-TEST_F(GlslGeneratorImplTest_Function,
-       Emit_Attribute_EntryPoint_With_RO_StorageBuffer_Read) {
-  auto* s = Structure("Data", {
-                                  Member("a", ty.i32()),
-                                  Member("b", ty.f32()),
-                              });
+TEST_F(GlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_With_RO_StorageBuffer_Read) {
+    auto* s = Structure("Data", {
+                                    Member("a", ty.i32()),
+                                    Member("b", ty.f32()),
+                                });
 
-  Global("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(1),
+    Global("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(1),
+           });
+
+    auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, MemberAccessor("coord", "b"));
+
+    Func("frag_main", ast::VariableList{}, ty.void_(),
+         {
+             Decl(var),
+             Return(),
+         },
+         {
+             Stage(ast::PipelineStage::kFragment),
          });
 
-  auto* var = Var("v", ty.f32(), ast::StorageClass::kNone,
-                  MemberAccessor("coord", "b"));
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  Func("frag_main", ast::VariableList{}, ty.void_(),
-       {
-           Decl(var),
-           Return(),
-       },
-       {
-           Stage(ast::PipelineStage::kFragment),
-       });
-
-  GeneratorImpl& gen = SanitizeAndBuild();
-
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(),
-            R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(),
+              R"(#version 310 es
 precision mediump float;
 
 struct Data {
@@ -528,32 +515,31 @@
 )");
 }
 
-TEST_F(GlslGeneratorImplTest_Function,
-       Emit_Attribute_EntryPoint_With_WO_StorageBuffer_Store) {
-  auto* s = Structure("Data", {
-                                  Member("a", ty.i32()),
-                                  Member("b", ty.f32()),
-                              });
+TEST_F(GlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_With_WO_StorageBuffer_Store) {
+    auto* s = Structure("Data", {
+                                    Member("a", ty.i32()),
+                                    Member("b", ty.f32()),
+                                });
 
-  Global("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kWrite,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(1),
+    Global("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kWrite,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(1),
+           });
+
+    Func("frag_main", ast::VariableList{}, ty.void_(),
+         {
+             Assign(MemberAccessor("coord", "b"), Expr(2.0f)),
+             Return(),
+         },
+         {
+             Stage(ast::PipelineStage::kFragment),
          });
 
-  Func("frag_main", ast::VariableList{}, ty.void_(),
-       {
-           Assign(MemberAccessor("coord", "b"), Expr(2.0f)),
-           Return(),
-       },
-       {
-           Stage(ast::PipelineStage::kFragment),
-       });
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  GeneratorImpl& gen = SanitizeAndBuild();
-
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 precision mediump float;
 
 struct Data {
@@ -577,33 +563,31 @@
 )");
 }
 
-TEST_F(GlslGeneratorImplTest_Function,
-       Emit_Attribute_EntryPoint_With_StorageBuffer_Store) {
-  auto* s = Structure("Data", {
-                                  Member("a", ty.i32()),
-                                  Member("b", ty.f32()),
-                              });
+TEST_F(GlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_With_StorageBuffer_Store) {
+    auto* s = Structure("Data", {
+                                    Member("a", ty.i32()),
+                                    Member("b", ty.f32()),
+                                });
 
-  Global("coord", ty.Of(s), ast::StorageClass::kStorage,
-         ast::Access::kReadWrite,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(1),
+    Global("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(1),
+           });
+
+    Func("frag_main", ast::VariableList{}, ty.void_(),
+         {
+             Assign(MemberAccessor("coord", "b"), Expr(2.0f)),
+             Return(),
+         },
+         {
+             Stage(ast::PipelineStage::kFragment),
          });
 
-  Func("frag_main", ast::VariableList{}, ty.void_(),
-       {
-           Assign(MemberAccessor("coord", "b"), Expr(2.0f)),
-           Return(),
-       },
-       {
-           Stage(ast::PipelineStage::kFragment),
-       });
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  GeneratorImpl& gen = SanitizeAndBuild();
-
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 precision mediump float;
 
 struct Data {
@@ -627,36 +611,34 @@
 )");
 }
 
-TEST_F(GlslGeneratorImplTest_Function,
-       Emit_Attribute_Called_By_EntryPoint_With_Uniform) {
-  auto* s = Structure("S", {Member("x", ty.f32())});
-  Global("coord", ty.Of(s), ast::StorageClass::kUniform,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(1),
+TEST_F(GlslGeneratorImplTest_Function, Emit_Attribute_Called_By_EntryPoint_With_Uniform) {
+    auto* s = Structure("S", {Member("x", ty.f32())});
+    Global("coord", ty.Of(s), ast::StorageClass::kUniform,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(1),
+           });
+
+    Func("sub_func", ast::VariableList{Param("param", ty.f32())}, ty.f32(),
+         {
+             Return(MemberAccessor("coord", "x")),
          });
 
-  Func("sub_func", ast::VariableList{Param("param", ty.f32())}, ty.f32(),
-       {
-           Return(MemberAccessor("coord", "x")),
-       });
+    auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, Call("sub_func", 1.0f));
 
-  auto* var =
-      Var("v", ty.f32(), ast::StorageClass::kNone, Call("sub_func", 1.0f));
+    Func("frag_main", ast::VariableList{}, ty.void_(),
+         {
+             Decl(var),
+             Return(),
+         },
+         {
+             Stage(ast::PipelineStage::kFragment),
+         });
 
-  Func("frag_main", ast::VariableList{}, ty.void_(),
-       {
-           Decl(var),
-           Return(),
-       },
-       {
-           Stage(ast::PipelineStage::kFragment),
-       });
+    GeneratorImpl& gen = Build();
 
-  GeneratorImpl& gen = Build();
-
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 precision mediump float;
 
 struct S {
@@ -678,38 +660,35 @@
 )");
 }
 
-TEST_F(GlslGeneratorImplTest_Function,
-       Emit_Attribute_Called_By_EntryPoint_With_StorageBuffer) {
-  auto* s = Structure("S", {Member("x", ty.f32())});
-  Global("coord", ty.Of(s), ast::StorageClass::kStorage,
-         ast::Access::kReadWrite,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(1),
+TEST_F(GlslGeneratorImplTest_Function, Emit_Attribute_Called_By_EntryPoint_With_StorageBuffer) {
+    auto* s = Structure("S", {Member("x", ty.f32())});
+    Global("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(1),
+           });
+
+    Func("sub_func", ast::VariableList{Param("param", ty.f32())}, ty.f32(),
+         {
+             Return(MemberAccessor("coord", "x")),
          });
 
-  Func("sub_func", ast::VariableList{Param("param", ty.f32())}, ty.f32(),
-       {
-           Return(MemberAccessor("coord", "x")),
-       });
+    auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, Call("sub_func", 1.0f));
 
-  auto* var =
-      Var("v", ty.f32(), ast::StorageClass::kNone, Call("sub_func", 1.0f));
+    Func("frag_main", ast::VariableList{}, ty.void_(),
+         {
+             Decl(var),
+             Return(),
+         },
+         {
+             Stage(ast::PipelineStage::kFragment),
+         });
 
-  Func("frag_main", ast::VariableList{}, ty.void_(),
-       {
-           Decl(var),
-           Return(),
-       },
-       {
-           Stage(ast::PipelineStage::kFragment),
-       });
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  GeneratorImpl& gen = SanitizeAndBuild();
-
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(),
-            R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(),
+              R"(#version 310 es
 precision mediump float;
 
 struct S {
@@ -735,17 +714,16 @@
 )");
 }
 
-TEST_F(GlslGeneratorImplTest_Function,
-       Emit_Attribute_EntryPoint_WithNameCollision) {
-  Func("centroid", ast::VariableList{}, ty.void_(), {},
-       {
-           Stage(ast::PipelineStage::kFragment),
-       });
+TEST_F(GlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_WithNameCollision) {
+    Func("centroid", ast::VariableList{}, ty.void_(), {},
+         {
+             Stage(ast::PipelineStage::kFragment),
+         });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 precision mediump float;
 
 void tint_symbol() {
@@ -759,16 +737,16 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_Compute) {
-  Func("main", ast::VariableList{}, ty.void_(),
-       {
-           Return(),
-       },
-       {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
+    Func("main", ast::VariableList{}, ty.void_(),
+         {
+             Return(),
+         },
+         {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 
 layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
 void main() {
@@ -777,18 +755,17 @@
 )");
 }
 
-TEST_F(GlslGeneratorImplTest_Function,
-       Emit_Attribute_EntryPoint_Compute_WithWorkgroup_Literal) {
-  Func("main", ast::VariableList{}, ty.void_(), {},
-       {
-           Stage(ast::PipelineStage::kCompute),
-           WorkgroupSize(2, 4, 6),
-       });
+TEST_F(GlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_Compute_WithWorkgroup_Literal) {
+    Func("main", ast::VariableList{}, ty.void_(), {},
+         {
+             Stage(ast::PipelineStage::kCompute),
+             WorkgroupSize(2_i, 4_i, 6_i),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 
 layout(local_size_x = 2, local_size_y = 4, local_size_z = 6) in;
 void main() {
@@ -797,21 +774,20 @@
 )");
 }
 
-TEST_F(GlslGeneratorImplTest_Function,
-       Emit_Attribute_EntryPoint_Compute_WithWorkgroup_Const) {
-  GlobalConst("width", ty.i32(), Construct(ty.i32(), 2));
-  GlobalConst("height", ty.i32(), Construct(ty.i32(), 3));
-  GlobalConst("depth", ty.i32(), Construct(ty.i32(), 4));
-  Func("main", ast::VariableList{}, ty.void_(), {},
-       {
-           Stage(ast::PipelineStage::kCompute),
-           WorkgroupSize("width", "height", "depth"),
-       });
+TEST_F(GlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_Compute_WithWorkgroup_Const) {
+    GlobalConst("width", ty.i32(), Construct(ty.i32(), 2_i));
+    GlobalConst("height", ty.i32(), Construct(ty.i32(), 3_i));
+    GlobalConst("depth", ty.i32(), Construct(ty.i32(), 4_i));
+    Func("main", ast::VariableList{}, ty.void_(), {},
+         {
+             Stage(ast::PipelineStage::kCompute),
+             WorkgroupSize("width", "height", "depth"),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 
 const int width = int(2);
 const int height = int(3);
@@ -825,19 +801,19 @@
 
 TEST_F(GlslGeneratorImplTest_Function,
        Emit_Attribute_EntryPoint_Compute_WithWorkgroup_OverridableConst) {
-  Override("width", ty.i32(), Construct(ty.i32(), 2), {Id(7u)});
-  Override("height", ty.i32(), Construct(ty.i32(), 3), {Id(8u)});
-  Override("depth", ty.i32(), Construct(ty.i32(), 4), {Id(9u)});
-  Func("main", ast::VariableList{}, ty.void_(), {},
-       {
-           Stage(ast::PipelineStage::kCompute),
-           WorkgroupSize("width", "height", "depth"),
-       });
+    Override("width", ty.i32(), Construct(ty.i32(), 2_i), {Id(7u)});
+    Override("height", ty.i32(), Construct(ty.i32(), 3_i), {Id(8u)});
+    Override("depth", ty.i32(), Construct(ty.i32(), 4_i), {Id(9u)});
+    Func("main", ast::VariableList{}, ty.void_(), {},
+         {
+             Stage(ast::PipelineStage::kCompute),
+             WorkgroupSize("width", "height", "depth"),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 
 #ifndef WGSL_SPEC_CONSTANT_7
 #define WGSL_SPEC_CONSTANT_7 int(2)
@@ -859,15 +835,15 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Function, Emit_Function_WithArrayParams) {
-  Func("my_func", ast::VariableList{Param("a", ty.array<f32, 5>())}, ty.void_(),
-       {
-           Return(),
-       });
+    Func("my_func", ast::VariableList{Param("a", ty.array<f32, 5>())}, ty.void_(),
+         {
+             Return(),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 
 void my_func(float a[5]) {
   return;
@@ -877,15 +853,15 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Function, Emit_Function_WithArrayReturn) {
-  Func("my_func", {}, ty.array<f32, 5>(),
-       {
-           Return(Construct(ty.array<f32, 5>())),
-       });
+    Func("my_func", {}, ty.array<f32, 5>(),
+         {
+             Return(Construct(ty.array<f32, 5>())),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 
 float[5] my_func() {
   return float[5](0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
@@ -895,61 +871,58 @@
 }
 
 // https://crbug.com/tint/297
-TEST_F(GlslGeneratorImplTest_Function,
-       Emit_Multiple_EntryPoint_With_Same_ModuleVar) {
-  // struct Data {
-  //   d : f32;
-  // };
-  // @binding(0) @group(0) var<storage> data : Data;
-  //
-  // @stage(compute) @workgroup_size(1)
-  // fn a() {
-  //   var v = data.d;
-  //   return;
-  // }
-  //
-  // @stage(compute) @workgroup_size(1)
-  // fn b() {
-  //   var v = data.d;
-  //   return;
-  // }
+TEST_F(GlslGeneratorImplTest_Function, Emit_Multiple_EntryPoint_With_Same_ModuleVar) {
+    // struct Data {
+    //   d : f32;
+    // };
+    // @binding(0) @group(0) var<storage> data : Data;
+    //
+    // @stage(compute) @workgroup_size(1)
+    // fn a() {
+    //   var v = data.d;
+    //   return;
+    // }
+    //
+    // @stage(compute) @workgroup_size(1)
+    // fn b() {
+    //   var v = data.d;
+    //   return;
+    // }
 
-  auto* s = Structure("Data", {Member("d", ty.f32())});
+    auto* s = Structure("Data", {Member("d", ty.f32())});
 
-  Global("data", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    Global("data", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  {
-    auto* var = Var("v", ty.f32(), ast::StorageClass::kNone,
-                    MemberAccessor("data", "d"));
+    {
+        auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, MemberAccessor("data", "d"));
 
-    Func("a", ast::VariableList{}, ty.void_(),
-         {
-             Decl(var),
-             Return(),
-         },
-         {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
-  }
+        Func("a", ast::VariableList{}, ty.void_(),
+             {
+                 Decl(var),
+                 Return(),
+             },
+             {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+    }
 
-  {
-    auto* var = Var("v", ty.f32(), ast::StorageClass::kNone,
-                    MemberAccessor("data", "d"));
+    {
+        auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, MemberAccessor("data", "d"));
 
-    Func("b", ast::VariableList{}, ty.void_(),
-         {
-             Decl(var),
-             Return(),
-         },
-         {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
-  }
+        Func("b", ast::VariableList{}, ty.void_(),
+             {
+                 Decl(var),
+                 Return(),
+             },
+             {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+    }
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 
 struct Data {
   float d;
diff --git a/src/tint/writer/glsl/generator_impl_identifier_test.cc b/src/tint/writer/glsl/generator_impl_identifier_test.cc
index 18369cb..396c261 100644
--- a/src/tint/writer/glsl/generator_impl_identifier_test.cc
+++ b/src/tint/writer/glsl/generator_impl_identifier_test.cc
@@ -20,16 +20,16 @@
 using GlslGeneratorImplTest_Identifier = TestHelper;
 
 TEST_F(GlslGeneratorImplTest_Identifier, EmitIdentifierExpression) {
-  Global("foo", ty.i32(), ast::StorageClass::kPrivate);
+    Global("foo", ty.i32(), ast::StorageClass::kPrivate);
 
-  auto* i = Expr("foo");
-  WrapInFunction(i);
+    auto* i = Expr("foo");
+    WrapInFunction(i);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, i)) << gen.error();
-  EXPECT_EQ(out.str(), "foo");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, i)) << gen.error();
+    EXPECT_EQ(out.str(), "foo");
 }
 
 }  // namespace
diff --git a/src/tint/writer/glsl/generator_impl_if_test.cc b/src/tint/writer/glsl/generator_impl_if_test.cc
index 6975943..4b0b7bb 100644
--- a/src/tint/writer/glsl/generator_impl_if_test.cc
+++ b/src/tint/writer/glsl/generator_impl_if_test.cc
@@ -20,43 +20,41 @@
 using GlslGeneratorImplTest_If = TestHelper;
 
 TEST_F(GlslGeneratorImplTest_If, Emit_If) {
-  Global("cond", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("cond", ty.bool_(), ast::StorageClass::kPrivate);
 
-  auto* cond = Expr("cond");
-  auto* body = Block(Return());
-  auto* i = If(cond, body);
-  WrapInFunction(i);
+    auto* cond = Expr("cond");
+    auto* body = Block(Return());
+    auto* i = If(cond, body);
+    WrapInFunction(i);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
-  ASSERT_TRUE(gen.EmitStatement(i)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  if (cond) {
+    gen.increment_indent();
+    ASSERT_TRUE(gen.EmitStatement(i)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  if (cond) {
     return;
   }
 )");
 }
 
 TEST_F(GlslGeneratorImplTest_If, Emit_IfWithElseIf) {
-  Global("cond", ty.bool_(), ast::StorageClass::kPrivate);
-  Global("else_cond", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("cond", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("else_cond", ty.bool_(), ast::StorageClass::kPrivate);
 
-  auto* else_cond = Expr("else_cond");
-  auto* else_body = Block(Return());
+    auto* else_cond = Expr("else_cond");
+    auto* else_body = Block(Return());
 
-  auto* cond = Expr("cond");
-  auto* body = Block(Return());
-  auto* i = If(
-      cond, body,
-      ast::ElseStatementList{create<ast::ElseStatement>(else_cond, else_body)});
-  WrapInFunction(i);
+    auto* cond = Expr("cond");
+    auto* body = Block(Return());
+    auto* i = If(cond, body, Else(If(else_cond, else_body)));
+    WrapInFunction(i);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(i)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  if (cond) {
+    ASSERT_TRUE(gen.EmitStatement(i)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  if (cond) {
     return;
   } else {
     if (else_cond) {
@@ -67,23 +65,21 @@
 }
 
 TEST_F(GlslGeneratorImplTest_If, Emit_IfWithElse) {
-  Global("cond", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("cond", ty.bool_(), ast::StorageClass::kPrivate);
 
-  auto* else_body = Block(Return());
+    auto* else_body = Block(Return());
 
-  auto* cond = Expr("cond");
-  auto* body = Block(Return());
-  auto* i = If(
-      cond, body,
-      ast::ElseStatementList{create<ast::ElseStatement>(nullptr, else_body)});
-  WrapInFunction(i);
+    auto* cond = Expr("cond");
+    auto* body = Block(Return());
+    auto* i = If(cond, body, Else(else_body));
+    WrapInFunction(i);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(i)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  if (cond) {
+    ASSERT_TRUE(gen.EmitStatement(i)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  if (cond) {
     return;
   } else {
     return;
@@ -92,30 +88,26 @@
 }
 
 TEST_F(GlslGeneratorImplTest_If, Emit_IfWithMultiple) {
-  Global("cond", ty.bool_(), ast::StorageClass::kPrivate);
-  Global("else_cond", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("cond", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("else_cond", ty.bool_(), ast::StorageClass::kPrivate);
 
-  auto* else_cond = Expr("else_cond");
+    auto* else_cond = Expr("else_cond");
 
-  auto* else_body = Block(Return());
+    auto* else_body = Block(Return());
 
-  auto* else_body_2 = Block(Return());
+    auto* else_body_2 = Block(Return());
 
-  auto* cond = Expr("cond");
-  auto* body = Block(Return());
-  auto* i = If(cond, body,
-               ast::ElseStatementList{
-                   create<ast::ElseStatement>(else_cond, else_body),
-                   create<ast::ElseStatement>(nullptr, else_body_2),
-               });
-  WrapInFunction(i);
+    auto* cond = Expr("cond");
+    auto* body = Block(Return());
+    auto* i = If(cond, body, Else(If(else_cond, else_body, Else(else_body_2))));
+    WrapInFunction(i);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(i)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  if (cond) {
+    ASSERT_TRUE(gen.EmitStatement(i)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  if (cond) {
     return;
   } else {
     if (else_cond) {
diff --git a/src/tint/writer/glsl/generator_impl_import_test.cc b/src/tint/writer/glsl/generator_impl_import_test.cc
index c0d081e..a4a6440 100644
--- a/src/tint/writer/glsl/generator_impl_import_test.cc
+++ b/src/tint/writer/glsl/generator_impl_import_test.cc
@@ -14,33 +14,35 @@
 
 #include "src/tint/writer/glsl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::glsl {
 namespace {
 
 using GlslGeneratorImplTest_Import = TestHelper;
 
 struct GlslImportData {
-  const char* name;
-  const char* glsl_name;
+    const char* name;
+    const char* glsl_name;
 };
 inline std::ostream& operator<<(std::ostream& out, GlslImportData data) {
-  out << data.name;
-  return out;
+    out << data.name;
+    return out;
 }
 
 using GlslImportData_SingleParamTest = TestParamHelper<GlslImportData>;
 TEST_P(GlslImportData_SingleParamTest, FloatScalar) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* ident = Expr(param.name);
-  auto* expr = Call(ident, 1.f);
-  WrapInFunction(expr);
+    auto* ident = Expr(param.name);
+    auto* expr = Call(ident, 1.f);
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), std::string(param.glsl_name) + "(1.0f)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), std::string(param.glsl_name) + "(1.0f)");
 }
 INSTANTIATE_TEST_SUITE_P(GlslGeneratorImplTest_Import,
                          GlslImportData_SingleParamTest,
@@ -55,8 +57,7 @@
                                          GlslImportData{"exp2", "exp2"},
                                          GlslImportData{"floor", "floor"},
                                          GlslImportData{"fract", "fract"},
-                                         GlslImportData{"inverseSqrt",
-                                                        "inversesqrt"},
+                                         GlslImportData{"inverseSqrt", "inversesqrt"},
                                          GlslImportData{"length", "length"},
                                          GlslImportData{"log", "log"},
                                          GlslImportData{"log2", "log2"},
@@ -71,16 +72,16 @@
 
 using GlslImportData_SingleIntParamTest = TestParamHelper<GlslImportData>;
 TEST_P(GlslImportData_SingleIntParamTest, IntScalar) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* expr = Call(param.name, Expr(1));
-  WrapInFunction(expr);
+    auto* expr = Call(param.name, Expr(1_i));
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), std::string(param.glsl_name) + "(1)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), std::string(param.glsl_name) + "(1)");
 }
 INSTANTIATE_TEST_SUITE_P(GlslGeneratorImplTest_Import,
                          GlslImportData_SingleIntParamTest,
@@ -88,59 +89,57 @@
 
 using GlslImportData_SingleVectorParamTest = TestParamHelper<GlslImportData>;
 TEST_P(GlslImportData_SingleVectorParamTest, FloatVector) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* ident = Expr(param.name);
-  auto* expr = Call(ident, vec3<f32>(1.f, 2.f, 3.f));
-  WrapInFunction(expr);
+    auto* ident = Expr(param.name);
+    auto* expr = Call(ident, vec3<f32>(1.f, 2.f, 3.f));
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(),
-            std::string(param.glsl_name) + "(vec3(1.0f, 2.0f, 3.0f))");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), std::string(param.glsl_name) + "(vec3(1.0f, 2.0f, 3.0f))");
 }
-INSTANTIATE_TEST_SUITE_P(
-    GlslGeneratorImplTest_Import,
-    GlslImportData_SingleVectorParamTest,
-    testing::Values(GlslImportData{"abs", "abs"},
-                    GlslImportData{"acos", "acos"},
-                    GlslImportData{"asin", "asin"},
-                    GlslImportData{"atan", "atan"},
-                    GlslImportData{"cos", "cos"},
-                    GlslImportData{"cosh", "cosh"},
-                    GlslImportData{"ceil", "ceil"},
-                    GlslImportData{"exp", "exp"},
-                    GlslImportData{"exp2", "exp2"},
-                    GlslImportData{"floor", "floor"},
-                    GlslImportData{"fract", "fract"},
-                    GlslImportData{"inverseSqrt", "inversesqrt"},
-                    GlslImportData{"length", "length"},
-                    GlslImportData{"log", "log"},
-                    GlslImportData{"log2", "log2"},
-                    GlslImportData{"normalize", "normalize"},
-                    GlslImportData{"round", "round"},
-                    GlslImportData{"sign", "sign"},
-                    GlslImportData{"sin", "sin"},
-                    GlslImportData{"sinh", "sinh"},
-                    GlslImportData{"sqrt", "sqrt"},
-                    GlslImportData{"tan", "tan"},
-                    GlslImportData{"tanh", "tanh"},
-                    GlslImportData{"trunc", "trunc"}));
+INSTANTIATE_TEST_SUITE_P(GlslGeneratorImplTest_Import,
+                         GlslImportData_SingleVectorParamTest,
+                         testing::Values(GlslImportData{"abs", "abs"},
+                                         GlslImportData{"acos", "acos"},
+                                         GlslImportData{"asin", "asin"},
+                                         GlslImportData{"atan", "atan"},
+                                         GlslImportData{"cos", "cos"},
+                                         GlslImportData{"cosh", "cosh"},
+                                         GlslImportData{"ceil", "ceil"},
+                                         GlslImportData{"exp", "exp"},
+                                         GlslImportData{"exp2", "exp2"},
+                                         GlslImportData{"floor", "floor"},
+                                         GlslImportData{"fract", "fract"},
+                                         GlslImportData{"inverseSqrt", "inversesqrt"},
+                                         GlslImportData{"length", "length"},
+                                         GlslImportData{"log", "log"},
+                                         GlslImportData{"log2", "log2"},
+                                         GlslImportData{"normalize", "normalize"},
+                                         GlslImportData{"round", "round"},
+                                         GlslImportData{"sign", "sign"},
+                                         GlslImportData{"sin", "sin"},
+                                         GlslImportData{"sinh", "sinh"},
+                                         GlslImportData{"sqrt", "sqrt"},
+                                         GlslImportData{"tan", "tan"},
+                                         GlslImportData{"tanh", "tanh"},
+                                         GlslImportData{"trunc", "trunc"}));
 
 using GlslImportData_DualParam_ScalarTest = TestParamHelper<GlslImportData>;
 TEST_P(GlslImportData_DualParam_ScalarTest, Float) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* expr = Call(param.name, 1.f, 2.f);
-  WrapInFunction(expr);
+    auto* expr = Call(param.name, 1.f, 2.f);
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), std::string(param.glsl_name) + "(1.0f, 2.0f)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), std::string(param.glsl_name) + "(1.0f, 2.0f)");
 }
 INSTANTIATE_TEST_SUITE_P(GlslGeneratorImplTest_Import,
                          GlslImportData_DualParam_ScalarTest,
@@ -153,18 +152,17 @@
 
 using GlslImportData_DualParam_VectorTest = TestParamHelper<GlslImportData>;
 TEST_P(GlslImportData_DualParam_VectorTest, Float) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* expr =
-      Call(param.name, vec3<f32>(1.f, 2.f, 3.f), vec3<f32>(4.f, 5.f, 6.f));
-  WrapInFunction(expr);
+    auto* expr = Call(param.name, vec3<f32>(1.f, 2.f, 3.f), vec3<f32>(4.f, 5.f, 6.f));
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), std::string(param.glsl_name) +
-                           "(vec3(1.0f, 2.0f, 3.0f), vec3(4.0f, 5.0f, 6.0f))");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(),
+              std::string(param.glsl_name) + "(vec3(1.0f, 2.0f, 3.0f), vec3(4.0f, 5.0f, 6.0f))");
 }
 INSTANTIATE_TEST_SUITE_P(GlslGeneratorImplTest_Import,
                          GlslImportData_DualParam_VectorTest,
@@ -179,16 +177,16 @@
 
 using GlslImportData_DualParam_Int_Test = TestParamHelper<GlslImportData>;
 TEST_P(GlslImportData_DualParam_Int_Test, IntScalar) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* expr = Call(param.name, 1, 2);
-  WrapInFunction(expr);
+    auto* expr = Call(param.name, 1_i, 2_i);
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), std::string(param.glsl_name) + "(1, 2)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), std::string(param.glsl_name) + "(1, 2)");
 }
 INSTANTIATE_TEST_SUITE_P(GlslGeneratorImplTest_Import,
                          GlslImportData_DualParam_Int_Test,
@@ -197,80 +195,77 @@
 
 using GlslImportData_TripleParam_ScalarTest = TestParamHelper<GlslImportData>;
 TEST_P(GlslImportData_TripleParam_ScalarTest, Float) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* expr = Call(param.name, 1.f, 2.f, 3.f);
-  WrapInFunction(expr);
+    auto* expr = Call(param.name, 1.f, 2.f, 3.f);
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), std::string(param.glsl_name) + "(1.0f, 2.0f, 3.0f)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), std::string(param.glsl_name) + "(1.0f, 2.0f, 3.0f)");
 }
 INSTANTIATE_TEST_SUITE_P(GlslGeneratorImplTest_Import,
                          GlslImportData_TripleParam_ScalarTest,
                          testing::Values(GlslImportData{"mix", "mix"},
                                          GlslImportData{"clamp", "clamp"},
-                                         GlslImportData{"smoothstep",
-                                                        "smoothstep"}));
+                                         GlslImportData{"smoothstep", "smoothstep"}));
 
 using GlslImportData_TripleParam_VectorTest = TestParamHelper<GlslImportData>;
 TEST_P(GlslImportData_TripleParam_VectorTest, Float) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* expr = Call(param.name, vec3<f32>(1.f, 2.f, 3.f),
-                    vec3<f32>(4.f, 5.f, 6.f), vec3<f32>(7.f, 8.f, 9.f));
-  WrapInFunction(expr);
+    auto* expr = Call(param.name, vec3<f32>(1.f, 2.f, 3.f), vec3<f32>(4.f, 5.f, 6.f),
+                      vec3<f32>(7.f, 8.f, 9.f));
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
-  EXPECT_EQ(
-      out.str(),
-      std::string(param.glsl_name) +
-          R"((vec3(1.0f, 2.0f, 3.0f), vec3(4.0f, 5.0f, 6.0f), vec3(7.0f, 8.0f, 9.0f)))");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(),
+              std::string(param.glsl_name) +
+                  R"((vec3(1.0f, 2.0f, 3.0f), vec3(4.0f, 5.0f, 6.0f), vec3(7.0f, 8.0f, 9.0f)))");
 }
-INSTANTIATE_TEST_SUITE_P(
-    GlslGeneratorImplTest_Import,
-    GlslImportData_TripleParam_VectorTest,
-    testing::Values(GlslImportData{"faceForward", "faceforward"},
-                    GlslImportData{"clamp", "clamp"},
-                    GlslImportData{"smoothstep", "smoothstep"}));
+INSTANTIATE_TEST_SUITE_P(GlslGeneratorImplTest_Import,
+                         GlslImportData_TripleParam_VectorTest,
+                         testing::Values(GlslImportData{"faceForward", "faceforward"},
+                                         GlslImportData{"clamp", "clamp"},
+                                         GlslImportData{"smoothstep", "smoothstep"}));
 
 TEST_F(GlslGeneratorImplTest_Import, DISABLED_GlslImportData_FMix) {
-  FAIL();
+    FAIL();
 }
 
 using GlslImportData_TripleParam_Int_Test = TestParamHelper<GlslImportData>;
 TEST_P(GlslImportData_TripleParam_Int_Test, IntScalar) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* expr = Call(param.name, 1, 2, 3);
-  WrapInFunction(expr);
+    auto* expr = Call(param.name, 1_i, 2_i, 3_i);
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), std::string(param.glsl_name) + "(1, 2, 3)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), std::string(param.glsl_name) + "(1, 2, 3)");
 }
 INSTANTIATE_TEST_SUITE_P(GlslGeneratorImplTest_Import,
                          GlslImportData_TripleParam_Int_Test,
                          testing::Values(GlslImportData{"clamp", "clamp"}));
 
 TEST_F(GlslGeneratorImplTest_Import, GlslImportData_Determinant) {
-  Global("var", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
+    Global("var", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
 
-  auto* expr = Call("determinant", "var");
-  WrapInFunction(expr);
+    auto* expr = Call("determinant", "var");
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), std::string("determinant(var)"));
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), std::string("determinant(var)"));
 }
 
 }  // namespace
diff --git a/src/tint/writer/glsl/generator_impl_loop_test.cc b/src/tint/writer/glsl/generator_impl_loop_test.cc
index a8fa039..de29622 100644
--- a/src/tint/writer/glsl/generator_impl_loop_test.cc
+++ b/src/tint/writer/glsl/generator_impl_loop_test.cc
@@ -15,44 +15,46 @@
 #include "src/tint/ast/variable_decl_statement.h"
 #include "src/tint/writer/glsl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::glsl {
 namespace {
 
 using GlslGeneratorImplTest_Loop = TestHelper;
 
 TEST_F(GlslGeneratorImplTest_Loop, Emit_Loop) {
-  auto* body = Block(create<ast::DiscardStatement>());
-  auto* continuing = Block();
-  auto* l = Loop(body, continuing);
+    auto* body = Block(create<ast::DiscardStatement>());
+    auto* continuing = Block();
+    auto* l = Loop(body, continuing);
 
-  WrapInFunction(l);
+    WrapInFunction(l);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(l)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  while (true) {
+    ASSERT_TRUE(gen.EmitStatement(l)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  while (true) {
     discard;
   }
 )");
 }
 
 TEST_F(GlslGeneratorImplTest_Loop, Emit_LoopWithContinuing) {
-  Func("a_statement", {}, ty.void_(), {});
+    Func("a_statement", {}, ty.void_(), {});
 
-  auto* body = Block(create<ast::DiscardStatement>());
-  auto* continuing = Block(CallStmt(Call("a_statement")));
-  auto* l = Loop(body, continuing);
+    auto* body = Block(create<ast::DiscardStatement>());
+    auto* continuing = Block(CallStmt(Call("a_statement")));
+    auto* l = Loop(body, continuing);
 
-  WrapInFunction(l);
+    WrapInFunction(l);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(l)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  while (true) {
+    ASSERT_TRUE(gen.EmitStatement(l)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  while (true) {
     discard;
     {
       a_statement();
@@ -62,31 +64,31 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Loop, Emit_LoopNestedWithContinuing) {
-  Func("a_statement", {}, ty.void_(), {});
+    Func("a_statement", {}, ty.void_(), {});
 
-  Global("lhs", ty.f32(), ast::StorageClass::kPrivate);
-  Global("rhs", ty.f32(), ast::StorageClass::kPrivate);
+    Global("lhs", ty.f32(), ast::StorageClass::kPrivate);
+    Global("rhs", ty.f32(), ast::StorageClass::kPrivate);
 
-  auto* body = Block(create<ast::DiscardStatement>());
-  auto* continuing = Block(CallStmt(Call("a_statement")));
-  auto* inner = Loop(body, continuing);
+    auto* body = Block(create<ast::DiscardStatement>());
+    auto* continuing = Block(CallStmt(Call("a_statement")));
+    auto* inner = Loop(body, continuing);
 
-  body = Block(inner);
+    body = Block(inner);
 
-  auto* lhs = Expr("lhs");
-  auto* rhs = Expr("rhs");
+    auto* lhs = Expr("lhs");
+    auto* rhs = Expr("rhs");
 
-  continuing = Block(Assign(lhs, rhs));
+    continuing = Block(Assign(lhs, rhs));
 
-  auto* outer = Loop(body, continuing);
-  WrapInFunction(outer);
+    auto* outer = Loop(body, continuing);
+    WrapInFunction(outer);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(outer)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  while (true) {
+    ASSERT_TRUE(gen.EmitStatement(outer)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  while (true) {
     while (true) {
       discard;
       {
@@ -101,30 +103,30 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Loop, Emit_LoopWithVarUsedInContinuing) {
-  // loop {
-  //   var lhs : f32 = 2.4;
-  //   var other : f32;
-  //   break;
-  //   continuing {
-  //     lhs = rhs
-  //   }
-  // }
+    // loop {
+    //   var lhs : f32 = 2.4;
+    //   var other : f32;
+    //   break;
+    //   continuing {
+    //     lhs = rhs
+    //   }
+    // }
 
-  Global("rhs", ty.f32(), ast::StorageClass::kPrivate);
+    Global("rhs", ty.f32(), ast::StorageClass::kPrivate);
 
-  auto* body = Block(Decl(Var("lhs", ty.f32(), Expr(2.4f))),  //
-                     Decl(Var("other", ty.f32())),            //
-                     Break());
-  auto* continuing = Block(Assign("lhs", "rhs"));
-  auto* outer = Loop(body, continuing);
-  WrapInFunction(outer);
+    auto* body = Block(Decl(Var("lhs", ty.f32(), Expr(2.4f))),  //
+                       Decl(Var("other", ty.f32())),            //
+                       Break());
+    auto* continuing = Block(Assign("lhs", "rhs"));
+    auto* outer = Loop(body, continuing);
+    WrapInFunction(outer);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(outer)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  while (true) {
+    ASSERT_TRUE(gen.EmitStatement(outer)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  while (true) {
     float lhs = 2.400000095f;
     float other = 0.0f;
     break;
@@ -136,20 +138,20 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Loop, Emit_ForLoop) {
-  // for(; ; ) {
-  //   return;
-  // }
+    // for(; ; ) {
+    //   return;
+    // }
 
-  auto* f = For(nullptr, nullptr, nullptr,  //
-                Block(Return()));
-  WrapInFunction(f);
+    auto* f = For(nullptr, nullptr, nullptr,  //
+                  Block(Return()));
+    WrapInFunction(f);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  {
+    ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  {
     for(; ; ) {
       return;
     }
@@ -158,20 +160,20 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Loop, Emit_ForLoopWithSimpleInit) {
-  // for(var i : i32; ; ) {
-  //   return;
-  // }
+    // for(var i : i32; ; ) {
+    //   return;
+    // }
 
-  auto* f = For(Decl(Var("i", ty.i32())), nullptr, nullptr,  //
-                Block(Return()));
-  WrapInFunction(f);
+    auto* f = For(Decl(Var("i", ty.i32())), nullptr, nullptr,  //
+                  Block(Return()));
+    WrapInFunction(f);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  {
+    ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  {
     for(int i = 0; ; ) {
       return;
     }
@@ -180,22 +182,21 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Loop, Emit_ForLoopWithMultiStmtInit) {
-  // for(var b = true && false; ; ) {
-  //   return;
-  // }
+    // for(var b = true && false; ; ) {
+    //   return;
+    // }
 
-  auto* multi_stmt = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd,
-                                                   Expr(true), Expr(false));
-  auto* f = For(Decl(Var("b", nullptr, multi_stmt)), nullptr, nullptr,
-                Block(Return()));
-  WrapInFunction(f);
+    auto* multi_stmt =
+        create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr(true), Expr(false));
+    auto* f = For(Decl(Var("b", nullptr, multi_stmt)), nullptr, nullptr, Block(Return()));
+    WrapInFunction(f);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  {
+    ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  {
     bool tint_tmp = true;
     if (tint_tmp) {
       tint_tmp = false;
@@ -209,21 +210,21 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Loop, Emit_ForLoopWithSimpleCond) {
-  // for(; true; ) {
-  //   return;
-  // }
+    // for(; true; ) {
+    //   return;
+    // }
 
-  Func("a_statement", {}, ty.void_(), {});
+    Func("a_statement", {}, ty.void_(), {});
 
-  auto* f = For(nullptr, true, nullptr, Block(CallStmt(Call("a_statement"))));
-  WrapInFunction(f);
+    auto* f = For(nullptr, true, nullptr, Block(CallStmt(Call("a_statement"))));
+    WrapInFunction(f);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  {
+    ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  {
     for(; true; ) {
       a_statement();
     }
@@ -232,24 +233,23 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Loop, Emit_ForLoopWithMultiStmtCond) {
-  // for(; true && false; ) {
-  //   return;
-  // }
+    // for(; true && false; ) {
+    //   return;
+    // }
 
-  Func("a_statement", {}, ty.void_(), {});
+    Func("a_statement", {}, ty.void_(), {});
 
-  auto* multi_stmt = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd,
-                                                   Expr(true), Expr(false));
-  auto* f =
-      For(nullptr, multi_stmt, nullptr, Block(CallStmt(Call("a_statement"))));
-  WrapInFunction(f);
+    auto* multi_stmt =
+        create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr(true), Expr(false));
+    auto* f = For(nullptr, multi_stmt, nullptr, Block(CallStmt(Call("a_statement"))));
+    WrapInFunction(f);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  {
+    ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  {
     while (true) {
       bool tint_tmp = true;
       if (tint_tmp) {
@@ -263,21 +263,21 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Loop, Emit_ForLoopWithSimpleCont) {
-  // for(; ; i = i + 1) {
-  //   return;
-  // }
+    // for(; ; i = i + 1i) {
+    //   return;
+    // }
 
-  auto* v = Decl(Var("i", ty.i32()));
-  auto* f = For(nullptr, nullptr, Assign("i", Add("i", 1)),  //
-                Block(Return()));
-  WrapInFunction(v, f);
+    auto* v = Decl(Var("i", ty.i32()));
+    auto* f = For(nullptr, nullptr, Assign("i", Add("i", 1_i)),  //
+                  Block(Return()));
+    WrapInFunction(v, f);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  {
+    ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  {
     for(; ; i = (i + 1)) {
       return;
     }
@@ -286,23 +286,23 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Loop, Emit_ForLoopWithMultiStmtCont) {
-  // for(; ; i = true && false) {
-  //   return;
-  // }
+    // for(; ; i = true && false) {
+    //   return;
+    // }
 
-  auto* multi_stmt = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd,
-                                                   Expr(true), Expr(false));
-  auto* v = Decl(Var("i", ty.bool_()));
-  auto* f = For(nullptr, nullptr, Assign("i", multi_stmt),  //
-                Block(Return()));
-  WrapInFunction(v, f);
+    auto* multi_stmt =
+        create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr(true), Expr(false));
+    auto* v = Decl(Var("i", ty.bool_()));
+    auto* f = For(nullptr, nullptr, Assign("i", multi_stmt),  //
+                  Block(Return()));
+    WrapInFunction(v, f);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  {
+    ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  {
     while (true) {
       return;
       bool tint_tmp = true;
@@ -316,20 +316,19 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Loop, Emit_ForLoopWithSimpleInitCondCont) {
-  // for(var i : i32; true; i = i + 1) {
-  //   return;
-  // }
+    // for(var i : i32; true; i = ii + 1) {
+    //   return;
+    // }
 
-  auto* f = For(Decl(Var("i", ty.i32())), true, Assign("i", Add("i", 1)),
-                Block(Return()));
-  WrapInFunction(f);
+    auto* f = For(Decl(Var("i", ty.i32())), true, Assign("i", Add("i", 1_i)), Block(Return()));
+    WrapInFunction(f);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  {
+    ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  {
     for(int i = 0; true; i = (i + 1)) {
       return;
     }
@@ -338,28 +337,28 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Loop, Emit_ForLoopWithMultiStmtInitCondCont) {
-  // for(var i = true && false; true && false; i = true && false) {
-  //   return;
-  // }
+    // for(var i = true && false; true && false; i = true && false) {
+    //   return;
+    // }
 
-  auto* multi_stmt_a = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd,
-                                                     Expr(true), Expr(false));
-  auto* multi_stmt_b = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd,
-                                                     Expr(true), Expr(false));
-  auto* multi_stmt_c = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd,
-                                                     Expr(true), Expr(false));
+    auto* multi_stmt_a =
+        create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr(true), Expr(false));
+    auto* multi_stmt_b =
+        create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr(true), Expr(false));
+    auto* multi_stmt_c =
+        create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr(true), Expr(false));
 
-  auto* f = For(Decl(Var("i", nullptr, multi_stmt_a)), multi_stmt_b,
-                Assign("i", multi_stmt_c),  //
-                Block(Return()));
-  WrapInFunction(f);
+    auto* f =
+        For(Decl(Var("i", nullptr, multi_stmt_a)), multi_stmt_b, Assign("i", multi_stmt_c),  //
+            Block(Return()));
+    WrapInFunction(f);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  {
+    ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  {
     bool tint_tmp = true;
     if (tint_tmp) {
       tint_tmp = false;
diff --git a/src/tint/writer/glsl/generator_impl_member_accessor_test.cc b/src/tint/writer/glsl/generator_impl_member_accessor_test.cc
index f467798..2fdc833 100644
--- a/src/tint/writer/glsl/generator_impl_member_accessor_test.cc
+++ b/src/tint/writer/glsl/generator_impl_member_accessor_test.cc
@@ -16,119 +16,114 @@
 #include "src/tint/ast/stage_attribute.h"
 #include "src/tint/writer/glsl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::glsl {
 namespace {
 
 using ::testing::HasSubstr;
 
-using create_type_func_ptr =
-    const ast::Type* (*)(const ProgramBuilder::TypesBuilder& ty);
+using create_type_func_ptr = const ast::Type* (*)(const ProgramBuilder::TypesBuilder& ty);
 
 inline const ast::Type* ty_i32(const ProgramBuilder::TypesBuilder& ty) {
-  return ty.i32();
+    return ty.i32();
 }
 inline const ast::Type* ty_u32(const ProgramBuilder::TypesBuilder& ty) {
-  return ty.u32();
+    return ty.u32();
 }
 inline const ast::Type* ty_f32(const ProgramBuilder::TypesBuilder& ty) {
-  return ty.f32();
+    return ty.f32();
 }
 template <typename T>
 inline const ast::Type* ty_vec2(const ProgramBuilder::TypesBuilder& ty) {
-  return ty.vec2<T>();
+    return ty.vec2<T>();
 }
 template <typename T>
 inline const ast::Type* ty_vec3(const ProgramBuilder::TypesBuilder& ty) {
-  return ty.vec3<T>();
+    return ty.vec3<T>();
 }
 template <typename T>
 inline const ast::Type* ty_vec4(const ProgramBuilder::TypesBuilder& ty) {
-  return ty.vec4<T>();
+    return ty.vec4<T>();
 }
 template <typename T>
 inline const ast::Type* ty_mat2x2(const ProgramBuilder::TypesBuilder& ty) {
-  return ty.mat2x2<T>();
+    return ty.mat2x2<T>();
 }
 template <typename T>
 inline const ast::Type* ty_mat2x3(const ProgramBuilder::TypesBuilder& ty) {
-  return ty.mat2x3<T>();
+    return ty.mat2x3<T>();
 }
 template <typename T>
 inline const ast::Type* ty_mat2x4(const ProgramBuilder::TypesBuilder& ty) {
-  return ty.mat2x4<T>();
+    return ty.mat2x4<T>();
 }
 template <typename T>
 inline const ast::Type* ty_mat3x2(const ProgramBuilder::TypesBuilder& ty) {
-  return ty.mat3x2<T>();
+    return ty.mat3x2<T>();
 }
 template <typename T>
 inline const ast::Type* ty_mat3x3(const ProgramBuilder::TypesBuilder& ty) {
-  return ty.mat3x3<T>();
+    return ty.mat3x3<T>();
 }
 template <typename T>
 inline const ast::Type* ty_mat3x4(const ProgramBuilder::TypesBuilder& ty) {
-  return ty.mat3x4<T>();
+    return ty.mat3x4<T>();
 }
 template <typename T>
 inline const ast::Type* ty_mat4x2(const ProgramBuilder::TypesBuilder& ty) {
-  return ty.mat4x2<T>();
+    return ty.mat4x2<T>();
 }
 template <typename T>
 inline const ast::Type* ty_mat4x3(const ProgramBuilder::TypesBuilder& ty) {
-  return ty.mat4x3<T>();
+    return ty.mat4x3<T>();
 }
 template <typename T>
 inline const ast::Type* ty_mat4x4(const ProgramBuilder::TypesBuilder& ty) {
-  return ty.mat4x4<T>();
+    return ty.mat4x4<T>();
 }
 
-using i32 = ProgramBuilder::i32;
-using u32 = ProgramBuilder::u32;
-using f32 = ProgramBuilder::f32;
-
 template <typename BASE>
 class GlslGeneratorImplTest_MemberAccessorBase : public BASE {
- public:
-  void SetupStorageBuffer(ast::StructMemberList members) {
-    ProgramBuilder& b = *this;
+  public:
+    void SetupStorageBuffer(ast::StructMemberList members) {
+        ProgramBuilder& b = *this;
 
-    auto* s = b.Structure("Data", members);
+        auto* s = b.Structure("Data", members);
 
-    b.Global("data", b.ty.Of(s), ast::StorageClass::kStorage,
-             ast::Access::kReadWrite,
-             ast::AttributeList{
-                 b.create<ast::BindingAttribute>(0),
-                 b.create<ast::GroupAttribute>(1),
-             });
-  }
+        b.Global("data", b.ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+                 ast::AttributeList{
+                     b.create<ast::BindingAttribute>(0),
+                     b.create<ast::GroupAttribute>(1),
+                 });
+    }
 
-  void SetupFunction(ast::StatementList statements) {
-    ProgramBuilder& b = *this;
-    b.Func("main", ast::VariableList{}, b.ty.void_(), statements,
-           ast::AttributeList{
-               b.Stage(ast::PipelineStage::kFragment),
-           });
-  }
+    void SetupFunction(ast::StatementList statements) {
+        ProgramBuilder& b = *this;
+        b.Func("main", ast::VariableList{}, b.ty.void_(), statements,
+               ast::AttributeList{
+                   b.Stage(ast::PipelineStage::kFragment),
+               });
+    }
 };
 
-using GlslGeneratorImplTest_MemberAccessor =
-    GlslGeneratorImplTest_MemberAccessorBase<TestHelper>;
+using GlslGeneratorImplTest_MemberAccessor = GlslGeneratorImplTest_MemberAccessorBase<TestHelper>;
 
 template <typename T>
 using GlslGeneratorImplTest_MemberAccessorWithParam =
     GlslGeneratorImplTest_MemberAccessorBase<TestParamHelper<T>>;
 
 TEST_F(GlslGeneratorImplTest_MemberAccessor, EmitExpression_MemberAccessor) {
-  auto* s = Structure("Data", {Member("mem", ty.f32())});
-  Global("str", ty.Of(s), ast::StorageClass::kPrivate);
+    auto* s = Structure("Data", {Member("mem", ty.f32())});
+    Global("str", ty.Of(s), ast::StorageClass::kPrivate);
 
-  auto* expr = MemberAccessor("str", "mem");
-  WrapInFunction(Var("expr", ty.f32(), ast::StorageClass::kNone, expr));
+    auto* expr = MemberAccessor("str", "mem");
+    WrapInFunction(Var("expr", ty.f32(), ast::StorageClass::kNone, expr));
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 
 struct Data {
   float mem;
@@ -148,42 +143,41 @@
 }
 
 struct TypeCase {
-  create_type_func_ptr member_type;
-  std::string expected;
+    create_type_func_ptr member_type;
+    std::string expected;
 };
 inline std::ostream& operator<<(std::ostream& out, TypeCase c) {
-  ProgramBuilder b;
-  auto* ty = c.member_type(b.ty);
-  out << ty->FriendlyName(b.Symbols());
-  return out;
+    ProgramBuilder b;
+    auto* ty = c.member_type(b.ty);
+    out << ty->FriendlyName(b.Symbols());
+    return out;
 }
 
 using GlslGeneratorImplTest_MemberAccessor_StorageBufferLoad =
     GlslGeneratorImplTest_MemberAccessorWithParam<TypeCase>;
 TEST_P(GlslGeneratorImplTest_MemberAccessor_StorageBufferLoad, Test) {
-  // struct Data {
-  //   a : i32;
-  //   b : <type>;
-  // };
-  // var<storage> data : Data;
-  // data.b;
+    // struct Data {
+    //   a : i32;
+    //   b : <type>;
+    // };
+    // var<storage> data : Data;
+    // data.b;
 
-  auto p = GetParam();
+    auto p = GetParam();
 
-  SetupStorageBuffer({
-      Member("a", ty.i32()),
-      Member("b", p.member_type(ty)),
-  });
+    SetupStorageBuffer({
+        Member("a", ty.i32()),
+        Member("b", p.member_type(ty)),
+    });
 
-  SetupFunction({
-      Decl(Var("x", nullptr, ast::StorageClass::kNone,
-               MemberAccessor("data", "b"))),
-  });
+    SetupFunction({
+        Decl(Var("x", nullptr, ast::StorageClass::kNone, MemberAccessor("data", "b"))),
+    });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr(p.expected));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr(p.expected));
 }
 
 INSTANTIATE_TEST_SUITE_P(GlslGeneratorImplTest_MemberAccessor,
@@ -213,80 +207,78 @@
 using GlslGeneratorImplTest_MemberAccessor_StorageBufferStore =
     GlslGeneratorImplTest_MemberAccessorWithParam<TypeCase>;
 TEST_P(GlslGeneratorImplTest_MemberAccessor_StorageBufferStore, Test) {
-  // struct Data {
-  //   a : i32;
-  //   b : <type>;
-  // };
-  // var<storage> data : Data;
-  // data.b = <type>();
+    // struct Data {
+    //   a : i32;
+    //   b : <type>;
+    // };
+    // var<storage> data : Data;
+    // data.b = <type>();
 
-  auto p = GetParam();
+    auto p = GetParam();
 
-  SetupStorageBuffer({
-      Member("a", ty.i32()),
-      Member("b", p.member_type(ty)),
-  });
+    SetupStorageBuffer({
+        Member("a", ty.i32()),
+        Member("b", p.member_type(ty)),
+    });
 
-  SetupFunction({
-      Decl(Var("value", p.member_type(ty), ast::StorageClass::kNone,
-               Construct(p.member_type(ty)))),
-      Assign(MemberAccessor("data", "b"), Expr("value")),
-  });
+    SetupFunction({
+        Decl(Var("value", p.member_type(ty), ast::StorageClass::kNone,
+                 Construct(p.member_type(ty)))),
+        Assign(MemberAccessor("data", "b"), Expr("value")),
+    });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr(p.expected));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr(p.expected));
 }
 
-INSTANTIATE_TEST_SUITE_P(
-    GlslGeneratorImplTest_MemberAccessor,
-    GlslGeneratorImplTest_MemberAccessor_StorageBufferStore,
-    testing::Values(TypeCase{ty_u32, "data.b = value"},
-                    TypeCase{ty_f32, "data.b = value"},
-                    TypeCase{ty_i32, "data.b = value"},
-                    TypeCase{ty_vec2<u32>, "data.b = value"},
-                    TypeCase{ty_vec2<f32>, "data.b = value"},
-                    TypeCase{ty_vec2<i32>, "data.b = value"},
-                    TypeCase{ty_vec3<u32>, "data.b = value"},
-                    TypeCase{ty_vec3<f32>, "data.b = value"},
-                    TypeCase{ty_vec3<i32>, "data.b = value"},
-                    TypeCase{ty_vec4<u32>, "data.b = value"},
-                    TypeCase{ty_vec4<f32>, "data.b = value"},
-                    TypeCase{ty_vec4<i32>, "data.b = value"},
-                    TypeCase{ty_mat2x2<f32>, "data.b = value"},
-                    TypeCase{ty_mat2x3<f32>, "data.b = value"},
-                    TypeCase{ty_mat2x4<f32>, "data.b = value"},
-                    TypeCase{ty_mat3x2<f32>, "data.b = value"},
-                    TypeCase{ty_mat3x3<f32>, "data.b = value"},
-                    TypeCase{ty_mat3x4<f32>, "data.b = value"},
-                    TypeCase{ty_mat4x2<f32>, "data.b = value"},
-                    TypeCase{ty_mat4x3<f32>, "data.b = value"},
-                    TypeCase{ty_mat4x4<f32>, "data.b = value"}));
+INSTANTIATE_TEST_SUITE_P(GlslGeneratorImplTest_MemberAccessor,
+                         GlslGeneratorImplTest_MemberAccessor_StorageBufferStore,
+                         testing::Values(TypeCase{ty_u32, "data.b = value"},
+                                         TypeCase{ty_f32, "data.b = value"},
+                                         TypeCase{ty_i32, "data.b = value"},
+                                         TypeCase{ty_vec2<u32>, "data.b = value"},
+                                         TypeCase{ty_vec2<f32>, "data.b = value"},
+                                         TypeCase{ty_vec2<i32>, "data.b = value"},
+                                         TypeCase{ty_vec3<u32>, "data.b = value"},
+                                         TypeCase{ty_vec3<f32>, "data.b = value"},
+                                         TypeCase{ty_vec3<i32>, "data.b = value"},
+                                         TypeCase{ty_vec4<u32>, "data.b = value"},
+                                         TypeCase{ty_vec4<f32>, "data.b = value"},
+                                         TypeCase{ty_vec4<i32>, "data.b = value"},
+                                         TypeCase{ty_mat2x2<f32>, "data.b = value"},
+                                         TypeCase{ty_mat2x3<f32>, "data.b = value"},
+                                         TypeCase{ty_mat2x4<f32>, "data.b = value"},
+                                         TypeCase{ty_mat3x2<f32>, "data.b = value"},
+                                         TypeCase{ty_mat3x3<f32>, "data.b = value"},
+                                         TypeCase{ty_mat3x4<f32>, "data.b = value"},
+                                         TypeCase{ty_mat4x2<f32>, "data.b = value"},
+                                         TypeCase{ty_mat4x3<f32>, "data.b = value"},
+                                         TypeCase{ty_mat4x4<f32>, "data.b = value"}));
 
 TEST_F(GlslGeneratorImplTest_MemberAccessor, StorageBuffer_Store_Matrix_Empty) {
-  // struct Data {
-  //   z : f32;
-  //   a : mat2x3<f32>;
-  // };
-  // var<storage> data : Data;
-  // data.a = mat2x3<f32>();
+    // struct Data {
+    //   z : f32;
+    //   a : mat2x3<f32>;
+    // };
+    // var<storage> data : Data;
+    // data.a = mat2x3<f32>();
 
-  SetupStorageBuffer({
-      Member("a", ty.i32()),
-      Member("b", ty.mat2x3<f32>()),
-  });
+    SetupStorageBuffer({
+        Member("a", ty.i32()),
+        Member("b", ty.mat2x3<f32>()),
+    });
 
-  SetupFunction({
-      Assign(MemberAccessor("data", "b"),
-             Construct(ty.mat2x3<f32>(), ast::ExpressionList{})),
-  });
+    SetupFunction({
+        Assign(MemberAccessor("data", "b"), Construct(ty.mat2x3<f32>(), ast::ExpressionList{})),
+    });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  auto* expected =
-      R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    auto* expected =
+        R"(#version 310 es
 precision mediump float;
 
 struct Data {
@@ -307,34 +299,32 @@
   return;
 }
 )";
-  EXPECT_EQ(gen.result(), expected);
+    EXPECT_EQ(gen.result(), expected);
 }
 
-TEST_F(GlslGeneratorImplTest_MemberAccessor,
-       StorageBuffer_Load_Matrix_Single_Element) {
-  // struct Data {
-  //   z : f32;
-  //   a : mat4x3<f32>;
-  // };
-  // var<storage> data : Data;
-  // data.a[2][1];
+TEST_F(GlslGeneratorImplTest_MemberAccessor, StorageBuffer_Load_Matrix_Single_Element) {
+    // struct Data {
+    //   z : f32;
+    //   a : mat4x3<f32>;
+    // };
+    // var<storage> data : Data;
+    // data.a[2i][1i];
 
-  SetupStorageBuffer({
-      Member("z", ty.f32()),
-      Member("a", ty.mat4x3<f32>()),
-  });
+    SetupStorageBuffer({
+        Member("z", ty.f32()),
+        Member("a", ty.mat4x3<f32>()),
+    });
 
-  SetupFunction({
-      Decl(
-          Var("x", nullptr, ast::StorageClass::kNone,
-              IndexAccessor(IndexAccessor(MemberAccessor("data", "a"), 2), 1))),
-  });
+    SetupFunction({
+        Decl(Var("x", nullptr, ast::StorageClass::kNone,
+                 IndexAccessor(IndexAccessor(MemberAccessor("data", "a"), 2_i), 1_i))),
+    });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  auto* expected =
-      R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    auto* expected =
+        R"(#version 310 es
 precision mediump float;
 
 struct Data {
@@ -355,32 +345,32 @@
   return;
 }
 )";
-  EXPECT_EQ(gen.result(), expected);
+    EXPECT_EQ(gen.result(), expected);
 }
 
 TEST_F(GlslGeneratorImplTest_MemberAccessor,
        EmitExpression_IndexAccessor_StorageBuffer_Load_Int_FromArray) {
-  // struct Data {
-  //   a : array<i32, 5>;
-  // };
-  // var<storage> data : Data;
-  // data.a[2];
+    // struct Data {
+    //   a : array<i32, 5>;
+    // };
+    // var<storage> data : Data;
+    // data.a[2];
 
-  SetupStorageBuffer({
-      Member("z", ty.f32()),
-      Member("a", ty.array<i32, 5>(4)),
-  });
+    SetupStorageBuffer({
+        Member("z", ty.f32()),
+        Member("a", ty.array<i32, 5>(4)),
+    });
 
-  SetupFunction({
-      Decl(Var("x", nullptr, ast::StorageClass::kNone,
-               IndexAccessor(MemberAccessor("data", "a"), 2))),
-  });
+    SetupFunction({
+        Decl(Var("x", nullptr, ast::StorageClass::kNone,
+                 IndexAccessor(MemberAccessor("data", "a"), 2_i))),
+    });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  auto* expected =
-      R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    auto* expected =
+        R"(#version 310 es
 precision mediump float;
 
 struct Data {
@@ -401,33 +391,32 @@
   return;
 }
 )";
-  EXPECT_EQ(gen.result(), expected);
+    EXPECT_EQ(gen.result(), expected);
 }
 
 TEST_F(GlslGeneratorImplTest_MemberAccessor,
        EmitExpression_IndexAccessor_StorageBuffer_Load_Int_FromArray_ExprIdx) {
-  // struct Data {
-  //   a : array<i32, 5>;
-  // };
-  // var<storage> data : Data;
-  // data.a[(2 + 4) - 3];
+    // struct Data {
+    //   a : array<i32, 5u>;
+    // };
+    // var<storage> data : Data;
+    // data.a[(2i + 4i) - 3i];
 
-  SetupStorageBuffer({
-      Member("z", ty.f32()),
-      Member("a", ty.array<i32, 5>(4)),
-  });
+    SetupStorageBuffer({
+        Member("z", ty.f32()),
+        Member("a", ty.array<i32, 5>(4)),
+    });
 
-  SetupFunction({
-      Decl(Var("x", nullptr, ast::StorageClass::kNone,
-               IndexAccessor(MemberAccessor("data", "a"),
-                             Sub(Add(2, Expr(4)), Expr(3))))),
-  });
+    SetupFunction({
+        Decl(Var("x", nullptr, ast::StorageClass::kNone,
+                 IndexAccessor(MemberAccessor("data", "a"), Sub(Add(2_i, 4_i), 3_i)))),
+    });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  auto* expected =
-      R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    auto* expected =
+        R"(#version 310 es
 precision mediump float;
 
 struct Data {
@@ -448,30 +437,30 @@
   return;
 }
 )";
-  EXPECT_EQ(gen.result(), expected);
+    EXPECT_EQ(gen.result(), expected);
 }
 
 TEST_F(GlslGeneratorImplTest_MemberAccessor, StorageBuffer_Store_ToArray) {
-  // struct Data {
-  //   a : array<i32, 5>;
-  // };
-  // var<storage> data : Data;
-  // data.a[2] = 2;
+    // struct Data {
+    //   a : array<i32, 5u>;
+    // };
+    // var<storage> data : Data;
+    // data.a[2i] = 2i;
 
-  SetupStorageBuffer({
-      Member("z", ty.f32()),
-      Member("a", ty.array<i32, 5>(4)),
-  });
+    SetupStorageBuffer({
+        Member("z", ty.f32()),
+        Member("a", ty.array<i32, 5>(4)),
+    });
 
-  SetupFunction({
-      Assign(IndexAccessor(MemberAccessor("data", "a"), 2), 2),
-  });
+    SetupFunction({
+        Assign(IndexAccessor(MemberAccessor("data", "a"), 2_i), 2_i),
+    });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  auto* expected =
-      R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    auto* expected =
+        R"(#version 310 es
 precision mediump float;
 
 struct Data {
@@ -492,41 +481,40 @@
   return;
 }
 )";
-  EXPECT_EQ(gen.result(), expected);
+    EXPECT_EQ(gen.result(), expected);
 }
 
 TEST_F(GlslGeneratorImplTest_MemberAccessor, StorageBuffer_Load_MultiLevel) {
-  // struct Inner {
-  //   a : vec3<i32>;
-  //   b : vec3<f32>;
-  // };
-  // struct Data {
-  //   var c : array<Inner, 4>;
-  // };
-  //
-  // var<storage> data : Pre;
-  // data.c[2].b
+    // struct Inner {
+    //   a : vec3<i32>;
+    //   b : vec3<f32>;
+    // };
+    // struct Data {
+    //   var c : array<Inner, 4u>;
+    // };
+    //
+    // var<storage> data : Pre;
+    // data.c[2i].b
 
-  auto* inner = Structure("Inner", {
-                                       Member("a", ty.vec3<f32>()),
-                                       Member("b", ty.vec3<f32>()),
-                                   });
+    auto* inner = Structure("Inner", {
+                                         Member("a", ty.vec3<f32>()),
+                                         Member("b", ty.vec3<f32>()),
+                                     });
 
-  SetupStorageBuffer({
-      Member("c", ty.array(ty.Of(inner), 4, 32)),
-  });
+    SetupStorageBuffer({
+        Member("c", ty.array(ty.Of(inner), 4_u, 32)),
+    });
 
-  SetupFunction({
-      Decl(Var(
-          "x", nullptr, ast::StorageClass::kNone,
-          MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2), "b"))),
-  });
+    SetupFunction({
+        Decl(Var("x", nullptr, ast::StorageClass::kNone,
+                 MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2_i), "b"))),
+    });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  auto* expected =
-      R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    auto* expected =
+        R"(#version 310 es
 precision mediump float;
 
 struct Inner {
@@ -550,44 +538,41 @@
   return;
 }
 )";
-  EXPECT_EQ(gen.result(), expected);
+    EXPECT_EQ(gen.result(), expected);
 }
 
-TEST_F(GlslGeneratorImplTest_MemberAccessor,
-       StorageBuffer_Load_MultiLevel_Swizzle) {
-  // struct Inner {
-  //   a : vec3<i32>;
-  //   b : vec3<f32>;
-  // };
-  // struct Data {
-  //   var c : array<Inner, 4>;
-  // };
-  //
-  // var<storage> data : Pre;
-  // data.c[2].b.xy
+TEST_F(GlslGeneratorImplTest_MemberAccessor, StorageBuffer_Load_MultiLevel_Swizzle) {
+    // struct Inner {
+    //   a : vec3<i32>;
+    //   b : vec3<f32>;
+    // };
+    // struct Data {
+    //   var c : array<Inner, 4u>;
+    // };
+    //
+    // var<storage> data : Pre;
+    // data.c[2i].b.xy
 
-  auto* inner = Structure("Inner", {
-                                       Member("a", ty.vec3<f32>()),
-                                       Member("b", ty.vec3<f32>()),
-                                   });
+    auto* inner = Structure("Inner", {
+                                         Member("a", ty.vec3<f32>()),
+                                         Member("b", ty.vec3<f32>()),
+                                     });
 
-  SetupStorageBuffer({
-      Member("c", ty.array(ty.Of(inner), 4, 32)),
-  });
+    SetupStorageBuffer({
+        Member("c", ty.array(ty.Of(inner), 4_u, 32)),
+    });
 
-  SetupFunction({
-      Decl(Var("x", nullptr, ast::StorageClass::kNone,
-               MemberAccessor(
-                   MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2),
-                                  "b"),
-                   "xy"))),
-  });
+    SetupFunction({
+        Decl(Var("x", nullptr, ast::StorageClass::kNone,
+                 MemberAccessor(
+                     MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2_i), "b"), "xy"))),
+    });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  auto* expected =
-      R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    auto* expected =
+        R"(#version 310 es
 precision mediump float;
 
 struct Inner {
@@ -611,44 +596,42 @@
   return;
 }
 )";
-  EXPECT_EQ(gen.result(), expected);
+    EXPECT_EQ(gen.result(), expected);
 }
 
 TEST_F(GlslGeneratorImplTest_MemberAccessor,
        StorageBuffer_Load_MultiLevel_Swizzle_SingleLetter) {  // NOLINT
-  // struct Inner {
-  //   a : vec3<i32>;
-  //   b : vec3<f32>;
-  // };
-  // struct Data {
-  //   var c : array<Inner, 4>;
-  // };
-  //
-  // var<storage> data : Pre;
-  // data.c[2].b.g
+    // struct Inner {
+    //   a : vec3<i32>;
+    //   b : vec3<f32>;
+    // };
+    // struct Data {
+    //   var c : array<Inner, 4u>;
+    // };
+    //
+    // var<storage> data : Pre;
+    // data.c[2i].b.g
 
-  auto* inner = Structure("Inner", {
-                                       Member("a", ty.vec3<f32>()),
-                                       Member("b", ty.vec3<f32>()),
-                                   });
+    auto* inner = Structure("Inner", {
+                                         Member("a", ty.vec3<f32>()),
+                                         Member("b", ty.vec3<f32>()),
+                                     });
 
-  SetupStorageBuffer({
-      Member("c", ty.array(ty.Of(inner), 4, 32)),
-  });
+    SetupStorageBuffer({
+        Member("c", ty.array(ty.Of(inner), 4_u, 32)),
+    });
 
-  SetupFunction({
-      Decl(Var("x", nullptr, ast::StorageClass::kNone,
-               MemberAccessor(
-                   MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2),
-                                  "b"),
-                   "g"))),
-  });
+    SetupFunction({
+        Decl(Var("x", nullptr, ast::StorageClass::kNone,
+                 MemberAccessor(
+                     MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2_i), "b"), "g"))),
+    });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  auto* expected =
-      R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    auto* expected =
+        R"(#version 310 es
 precision mediump float;
 
 struct Inner {
@@ -672,44 +655,41 @@
   return;
 }
 )";
-  EXPECT_EQ(gen.result(), expected);
+    EXPECT_EQ(gen.result(), expected);
 }
 
-TEST_F(GlslGeneratorImplTest_MemberAccessor,
-       StorageBuffer_Load_MultiLevel_Index) {
-  // struct Inner {
-  //   a : vec3<i32>;
-  //   b : vec3<f32>;
-  // };
-  // struct Data {
-  //   var c : array<Inner, 4>;
-  // };
-  //
-  // var<storage> data : Pre;
-  // data.c[2].b[1]
+TEST_F(GlslGeneratorImplTest_MemberAccessor, StorageBuffer_Load_MultiLevel_Index) {
+    // struct Inner {
+    //   a : vec3<i32>;
+    //   b : vec3<f32>;
+    // };
+    // struct Data {
+    //   var c : array<Inner, 4u>;
+    // };
+    //
+    // var<storage> data : Pre;
+    // data.c[2i].b[1i]
 
-  auto* inner = Structure("Inner", {
-                                       Member("a", ty.vec3<f32>()),
-                                       Member("b", ty.vec3<f32>()),
-                                   });
+    auto* inner = Structure("Inner", {
+                                         Member("a", ty.vec3<f32>()),
+                                         Member("b", ty.vec3<f32>()),
+                                     });
 
-  SetupStorageBuffer({
-      Member("c", ty.array(ty.Of(inner), 4, 32)),
-  });
+    SetupStorageBuffer({
+        Member("c", ty.array(ty.Of(inner), 4_u, 32)),
+    });
 
-  SetupFunction({
-      Decl(Var(
-          "x", nullptr, ast::StorageClass::kNone,
-          IndexAccessor(MemberAccessor(
-                            IndexAccessor(MemberAccessor("data", "c"), 2), "b"),
-                        1))),
-  });
+    SetupFunction({
+        Decl(Var("x", nullptr, ast::StorageClass::kNone,
+                 IndexAccessor(MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2_i), "b"),
+                               1_i))),
+    });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  auto* expected =
-      R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    auto* expected =
+        R"(#version 310 es
 precision mediump float;
 
 struct Inner {
@@ -733,40 +713,40 @@
   return;
 }
 )";
-  EXPECT_EQ(gen.result(), expected);
+    EXPECT_EQ(gen.result(), expected);
 }
 
 TEST_F(GlslGeneratorImplTest_MemberAccessor, StorageBuffer_Store_MultiLevel) {
-  // struct Inner {
-  //   a : vec3<i32>;
-  //   b : vec3<f32>;
-  // };
-  // struct Data {
-  //   var c : array<Inner, 4>;
-  // };
-  //
-  // var<storage> data : Pre;
-  // data.c[2].b = vec3<f32>(1.f, 2.f, 3.f);
+    // struct Inner {
+    //   a : vec3<i32>;
+    //   b : vec3<f32>;
+    // };
+    // struct Data {
+    //   var c : array<Inner, 4u>;
+    // };
+    //
+    // var<storage> data : Pre;
+    // data.c[2i].b = vec3<f32>(1.f, 2.f, 3.f);
 
-  auto* inner = Structure("Inner", {
-                                       Member("a", ty.vec3<f32>()),
-                                       Member("b", ty.vec3<f32>()),
-                                   });
+    auto* inner = Structure("Inner", {
+                                         Member("a", ty.vec3<f32>()),
+                                         Member("b", ty.vec3<f32>()),
+                                     });
 
-  SetupStorageBuffer({
-      Member("c", ty.array(ty.Of(inner), 4, 32)),
-  });
+    SetupStorageBuffer({
+        Member("c", ty.array(ty.Of(inner), 4_u, 32)),
+    });
 
-  SetupFunction({
-      Assign(MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2), "b"),
-             vec3<f32>(1.f, 2.f, 3.f)),
-  });
+    SetupFunction({
+        Assign(MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2_i), "b"),
+               vec3<f32>(1.f, 2.f, 3.f)),
+    });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  auto* expected =
-      R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    auto* expected =
+        R"(#version 310 es
 precision mediump float;
 
 struct Inner {
@@ -790,44 +770,41 @@
   return;
 }
 )";
-  EXPECT_EQ(gen.result(), expected);
+    EXPECT_EQ(gen.result(), expected);
 }
 
-TEST_F(GlslGeneratorImplTest_MemberAccessor,
-       StorageBuffer_Store_Swizzle_SingleLetter) {
-  // struct Inner {
-  //   a : vec3<i32>;
-  //   b : vec3<f32>;
-  // };
-  // struct Data {
-  //   var c : array<Inner, 4>;
-  // };
-  //
-  // var<storage> data : Pre;
-  // data.c[2].b.y = 1.f;
+TEST_F(GlslGeneratorImplTest_MemberAccessor, StorageBuffer_Store_Swizzle_SingleLetter) {
+    // struct Inner {
+    //   a : vec3<i32>;
+    //   b : vec3<f32>;
+    // };
+    // struct Data {
+    //   var c : array<Inner, 4u>;
+    // };
+    //
+    // var<storage> data : Pre;
+    // data.c[2i].b.y = 1.f;
 
-  auto* inner = Structure("Inner", {
-                                       Member("a", ty.vec3<i32>()),
-                                       Member("b", ty.vec3<f32>()),
-                                   });
+    auto* inner = Structure("Inner", {
+                                         Member("a", ty.vec3<i32>()),
+                                         Member("b", ty.vec3<f32>()),
+                                     });
 
-  SetupStorageBuffer({
-      Member("c", ty.array(ty.Of(inner), 4, 32)),
-  });
+    SetupStorageBuffer({
+        Member("c", ty.array(ty.Of(inner), 4_u, 32)),
+    });
 
-  SetupFunction({
-      Assign(MemberAccessor(
-                 MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2),
-                                "b"),
-                 "y"),
-             Expr(1.f)),
-  });
+    SetupFunction({
+        Assign(MemberAccessor(MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2_i), "b"),
+                              "y"),
+               Expr(1.f)),
+    });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  auto* expected =
-      R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    auto* expected =
+        R"(#version 310 es
 precision mediump float;
 
 struct Inner {
@@ -851,29 +828,29 @@
   return;
 }
 )";
-  EXPECT_EQ(gen.result(), expected);
+    EXPECT_EQ(gen.result(), expected);
 }
 
 TEST_F(GlslGeneratorImplTest_MemberAccessor, Swizzle_xyz) {
-  auto* var = Var("my_vec", ty.vec4<f32>(), ast::StorageClass::kNone,
-                  vec4<f32>(1.f, 2.f, 3.f, 4.f));
-  auto* expr = MemberAccessor("my_vec", "xyz");
-  WrapInFunction(var, expr);
+    auto* var =
+        Var("my_vec", ty.vec4<f32>(), ast::StorageClass::kNone, vec4<f32>(1.f, 2.f, 3.f, 4.f));
+    auto* expr = MemberAccessor("my_vec", "xyz");
+    WrapInFunction(var, expr);
 
-  GeneratorImpl& gen = SanitizeAndBuild();
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("my_vec.xyz"));
+    GeneratorImpl& gen = SanitizeAndBuild();
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("my_vec.xyz"));
 }
 
 TEST_F(GlslGeneratorImplTest_MemberAccessor, Swizzle_gbr) {
-  auto* var = Var("my_vec", ty.vec4<f32>(), ast::StorageClass::kNone,
-                  vec4<f32>(1.f, 2.f, 3.f, 4.f));
-  auto* expr = MemberAccessor("my_vec", "gbr");
-  WrapInFunction(var, expr);
+    auto* var =
+        Var("my_vec", ty.vec4<f32>(), ast::StorageClass::kNone, vec4<f32>(1.f, 2.f, 3.f, 4.f));
+    auto* expr = MemberAccessor("my_vec", "gbr");
+    WrapInFunction(var, expr);
 
-  GeneratorImpl& gen = SanitizeAndBuild();
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("my_vec.gbr"));
+    GeneratorImpl& gen = SanitizeAndBuild();
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("my_vec.gbr"));
 }
 
 }  // namespace
diff --git a/src/tint/writer/glsl/generator_impl_module_constant_test.cc b/src/tint/writer/glsl/generator_impl_module_constant_test.cc
index bf9c74c..35e1dd2 100644
--- a/src/tint/writer/glsl/generator_impl_module_constant_test.cc
+++ b/src/tint/writer/glsl/generator_impl_module_constant_test.cc
@@ -21,25 +21,25 @@
 using GlslGeneratorImplTest_ModuleConstant = TestHelper;
 
 TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_ModuleConstant) {
-  auto* var = Const("pos", ty.array<f32, 3>(), array<f32, 3>(1.f, 2.f, 3.f));
-  WrapInFunction(Decl(var));
+    auto* var = Let("pos", ty.array<f32, 3>(), array<f32, 3>(1.f, 2.f, 3.f));
+    WrapInFunction(Decl(var));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitProgramConstVariable(var)) << gen.error();
-  EXPECT_EQ(gen.result(), "const float pos[3] = float[3](1.0f, 2.0f, 3.0f);\n");
+    ASSERT_TRUE(gen.EmitProgramConstVariable(var)) << gen.error();
+    EXPECT_EQ(gen.result(), "const float pos[3] = float[3](1.0f, 2.0f, 3.0f);\n");
 }
 
 TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_SpecConstant) {
-  auto* var = Override("pos", ty.f32(), Expr(3.0f),
-                       ast::AttributeList{
-                           Id(23),
-                       });
+    auto* var = Override("pos", ty.f32(), Expr(3.0f),
+                         ast::AttributeList{
+                             Id(23),
+                         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitProgramConstVariable(var)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#ifndef WGSL_SPEC_CONSTANT_23
+    ASSERT_TRUE(gen.EmitProgramConstVariable(var)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#ifndef WGSL_SPEC_CONSTANT_23
 #define WGSL_SPEC_CONSTANT_23 3.0f
 #endif
 const float pos = WGSL_SPEC_CONSTANT_23;
@@ -47,15 +47,15 @@
 }
 
 TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_SpecConstant_NoConstructor) {
-  auto* var = Override("pos", ty.f32(), nullptr,
-                       ast::AttributeList{
-                           Id(23),
-                       });
+    auto* var = Override("pos", ty.f32(), nullptr,
+                         ast::AttributeList{
+                             Id(23),
+                         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitProgramConstVariable(var)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#ifndef WGSL_SPEC_CONSTANT_23
+    ASSERT_TRUE(gen.EmitProgramConstVariable(var)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#ifndef WGSL_SPEC_CONSTANT_23
 #error spec constant required for constant id 23
 #endif
 const float pos = WGSL_SPEC_CONSTANT_23;
@@ -63,17 +63,17 @@
 }
 
 TEST_F(GlslGeneratorImplTest_ModuleConstant, Emit_SpecConstant_NoId) {
-  auto* a = Override("a", ty.f32(), Expr(3.0f),
-                     ast::AttributeList{
-                         Id(0),
-                     });
-  auto* b = Override("b", ty.f32(), Expr(2.0f));
+    auto* a = Override("a", ty.f32(), Expr(3.0f),
+                       ast::AttributeList{
+                           Id(0),
+                       });
+    auto* b = Override("b", ty.f32(), Expr(2.0f));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitProgramConstVariable(a)) << gen.error();
-  ASSERT_TRUE(gen.EmitProgramConstVariable(b)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#ifndef WGSL_SPEC_CONSTANT_0
+    ASSERT_TRUE(gen.EmitProgramConstVariable(a)) << gen.error();
+    ASSERT_TRUE(gen.EmitProgramConstVariable(b)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#ifndef WGSL_SPEC_CONSTANT_0
 #define WGSL_SPEC_CONSTANT_0 3.0f
 #endif
 const float a = WGSL_SPEC_CONSTANT_0;
diff --git a/src/tint/writer/glsl/generator_impl_return_test.cc b/src/tint/writer/glsl/generator_impl_return_test.cc
index 760188a..59df385 100644
--- a/src/tint/writer/glsl/generator_impl_return_test.cc
+++ b/src/tint/writer/glsl/generator_impl_return_test.cc
@@ -14,33 +14,35 @@
 
 #include "src/tint/writer/glsl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::glsl {
 namespace {
 
 using GlslGeneratorImplTest_Return = TestHelper;
 
 TEST_F(GlslGeneratorImplTest_Return, Emit_Return) {
-  auto* r = Return();
-  WrapInFunction(r);
+    auto* r = Return();
+    WrapInFunction(r);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(r)) << gen.error();
-  EXPECT_EQ(gen.result(), "  return;\n");
+    ASSERT_TRUE(gen.EmitStatement(r)) << gen.error();
+    EXPECT_EQ(gen.result(), "  return;\n");
 }
 
 TEST_F(GlslGeneratorImplTest_Return, Emit_ReturnWithValue) {
-  auto* r = Return(123);
-  Func("f", {}, ty.i32(), {r});
+    auto* r = Return(123_i);
+    Func("f", {}, ty.i32(), {r});
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(r)) << gen.error();
-  EXPECT_EQ(gen.result(), "  return 123;\n");
+    ASSERT_TRUE(gen.EmitStatement(r)) << gen.error();
+    EXPECT_EQ(gen.result(), "  return 123;\n");
 }
 
 }  // namespace
diff --git a/src/tint/writer/glsl/generator_impl_sanitizer_test.cc b/src/tint/writer/glsl/generator_impl_sanitizer_test.cc
index 812806f..874bfd0 100644
--- a/src/tint/writer/glsl/generator_impl_sanitizer_test.cc
+++ b/src/tint/writer/glsl/generator_impl_sanitizer_test.cc
@@ -17,34 +17,36 @@
 #include "src/tint/ast/variable_decl_statement.h"
 #include "src/tint/writer/glsl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::glsl {
 namespace {
 
 using GlslSanitizerTest = TestHelper;
 
 TEST_F(GlslSanitizerTest, Call_ArrayLength) {
-  auto* s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))});
-  Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+    auto* s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))});
+    Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(1),
+               create<ast::GroupAttribute>(2),
+           });
+
+    Func("a_func", ast::VariableList{}, ty.void_(),
+         ast::StatementList{
+             Decl(Var("len", ty.u32(), ast::StorageClass::kNone,
+                      Call("arrayLength", AddressOf(MemberAccessor("b", "a"))))),
+         },
          ast::AttributeList{
-             create<ast::BindingAttribute>(1),
-             create<ast::GroupAttribute>(2),
+             Stage(ast::PipelineStage::kFragment),
          });
 
-  Func("a_func", ast::VariableList{}, ty.void_(),
-       ast::StatementList{
-           Decl(Var("len", ty.u32(), ast::StorageClass::kNone,
-                    Call("arrayLength", AddressOf(MemberAccessor("b", "a"))))),
-       },
-       ast::AttributeList{
-           Stage(ast::PipelineStage::kFragment),
-       });
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    ASSERT_TRUE(gen.Generate()) << gen.error();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-
-  auto got = gen.result();
-  auto* expect = R"(#version 310 es
+    auto got = gen.result();
+    auto* expect = R"(#version 310 es
 precision mediump float;
 
 layout(binding = 1, std430) buffer my_struct_1 {
@@ -59,35 +61,35 @@
   return;
 }
 )";
-  EXPECT_EQ(expect, got);
+    EXPECT_EQ(expect, got);
 }
 
 TEST_F(GlslSanitizerTest, Call_ArrayLength_OtherMembersInStruct) {
-  auto* s = Structure("my_struct", {
-                                       Member(0, "z", ty.f32()),
-                                       Member(4, "a", ty.array<f32>(4)),
-                                   });
-  Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+    auto* s = Structure("my_struct", {
+                                         Member(0, "z", ty.f32()),
+                                         Member(4, "a", ty.array<f32>(4)),
+                                     });
+    Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(1),
+               create<ast::GroupAttribute>(2),
+           });
+
+    Func("a_func", ast::VariableList{}, ty.void_(),
+         ast::StatementList{
+             Decl(Var("len", ty.u32(), ast::StorageClass::kNone,
+                      Call("arrayLength", AddressOf(MemberAccessor("b", "a"))))),
+         },
          ast::AttributeList{
-             create<ast::BindingAttribute>(1),
-             create<ast::GroupAttribute>(2),
+             Stage(ast::PipelineStage::kFragment),
          });
 
-  Func("a_func", ast::VariableList{}, ty.void_(),
-       ast::StatementList{
-           Decl(Var("len", ty.u32(), ast::StorageClass::kNone,
-                    Call("arrayLength", AddressOf(MemberAccessor("b", "a"))))),
-       },
-       ast::AttributeList{
-           Stage(ast::PipelineStage::kFragment),
-       });
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    ASSERT_TRUE(gen.Generate()) << gen.error();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-
-  auto got = gen.result();
-  auto* expect = R"(#version 310 es
+    auto got = gen.result();
+    auto* expect = R"(#version 310 es
 precision mediump float;
 
 layout(binding = 1, std430) buffer my_struct_1 {
@@ -104,37 +106,36 @@
 }
 )";
 
-  EXPECT_EQ(expect, got);
+    EXPECT_EQ(expect, got);
 }
 
 TEST_F(GlslSanitizerTest, Call_ArrayLength_ViaLets) {
-  auto* s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))});
-  Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+    auto* s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))});
+    Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(1),
+               create<ast::GroupAttribute>(2),
+           });
+
+    auto* p = Let("p", nullptr, AddressOf("b"));
+    auto* p2 = Let("p2", nullptr, AddressOf(MemberAccessor(Deref(p), "a")));
+
+    Func("a_func", ast::VariableList{}, ty.void_(),
+         ast::StatementList{
+             Decl(p),
+             Decl(p2),
+             Decl(Var("len", ty.u32(), ast::StorageClass::kNone, Call("arrayLength", p2))),
+         },
          ast::AttributeList{
-             create<ast::BindingAttribute>(1),
-             create<ast::GroupAttribute>(2),
+             Stage(ast::PipelineStage::kFragment),
          });
 
-  auto* p = Const("p", nullptr, AddressOf("b"));
-  auto* p2 = Const("p2", nullptr, AddressOf(MemberAccessor(Deref(p), "a")));
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  Func("a_func", ast::VariableList{}, ty.void_(),
-       ast::StatementList{
-           Decl(p),
-           Decl(p2),
-           Decl(Var("len", ty.u32(), ast::StorageClass::kNone,
-                    Call("arrayLength", p2))),
-       },
-       ast::AttributeList{
-           Stage(ast::PipelineStage::kFragment),
-       });
+    ASSERT_TRUE(gen.Generate()) << gen.error();
 
-  GeneratorImpl& gen = SanitizeAndBuild();
-
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-
-  auto got = gen.result();
-  auto* expect = R"(#version 310 es
+    auto got = gen.result();
+    auto* expect = R"(#version 310 es
 precision mediump float;
 
 layout(binding = 1, std430) buffer my_struct_1 {
@@ -150,28 +151,28 @@
 }
 )";
 
-  EXPECT_EQ(expect, got);
+    EXPECT_EQ(expect, got);
 }
 
 TEST_F(GlslSanitizerTest, PromoteArrayInitializerToConstVar) {
-  auto* array_init = array<i32, 4>(1, 2, 3, 4);
-  auto* array_index = IndexAccessor(array_init, 3);
-  auto* pos = Var("pos", ty.i32(), ast::StorageClass::kNone, array_index);
+    auto* array_init = array<i32, 4>(1_i, 2_i, 3_i, 4_i);
+    auto* array_index = IndexAccessor(array_init, 3_i);
+    auto* pos = Var("pos", ty.i32(), ast::StorageClass::kNone, array_index);
 
-  Func("main", ast::VariableList{}, ty.void_(),
-       {
-           Decl(pos),
-       },
-       {
-           Stage(ast::PipelineStage::kFragment),
-       });
+    Func("main", ast::VariableList{}, ty.void_(),
+         {
+             Decl(pos),
+         },
+         {
+             Stage(ast::PipelineStage::kFragment),
+         });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
+    ASSERT_TRUE(gen.Generate()) << gen.error();
 
-  auto got = gen.result();
-  auto* expect = R"(#version 310 es
+    auto got = gen.result();
+    auto* expect = R"(#version 310 es
 precision mediump float;
 
 void tint_symbol() {
@@ -184,34 +185,33 @@
   return;
 }
 )";
-  EXPECT_EQ(expect, got);
+    EXPECT_EQ(expect, got);
 }
 
 TEST_F(GlslSanitizerTest, PromoteStructInitializerToConstVar) {
-  auto* str = Structure("S", {
-                                 Member("a", ty.i32()),
-                                 Member("b", ty.vec3<f32>()),
-                                 Member("c", ty.i32()),
-                             });
-  auto* struct_init = Construct(ty.Of(str), 1, vec3<f32>(2.f, 3.f, 4.f), 4);
-  auto* struct_access = MemberAccessor(struct_init, "b");
-  auto* pos =
-      Var("pos", ty.vec3<f32>(), ast::StorageClass::kNone, struct_access);
+    auto* str = Structure("S", {
+                                   Member("a", ty.i32()),
+                                   Member("b", ty.vec3<f32>()),
+                                   Member("c", ty.i32()),
+                               });
+    auto* struct_init = Construct(ty.Of(str), 1_i, vec3<f32>(2.f, 3.f, 4.f), 4_i);
+    auto* struct_access = MemberAccessor(struct_init, "b");
+    auto* pos = Var("pos", ty.vec3<f32>(), ast::StorageClass::kNone, struct_access);
 
-  Func("main", ast::VariableList{}, ty.void_(),
-       {
-           Decl(pos),
-       },
-       {
-           Stage(ast::PipelineStage::kFragment),
-       });
+    Func("main", ast::VariableList{}, ty.void_(),
+         {
+             Decl(pos),
+         },
+         {
+             Stage(ast::PipelineStage::kFragment),
+         });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
+    ASSERT_TRUE(gen.Generate()) << gen.error();
 
-  auto got = gen.result();
-  auto* expect = R"(#version 310 es
+    auto got = gen.result();
+    auto* expect = R"(#version 310 es
 precision mediump float;
 
 struct S {
@@ -230,34 +230,33 @@
   return;
 }
 )";
-  EXPECT_EQ(expect, got);
+    EXPECT_EQ(expect, got);
 }
 
 TEST_F(GlslSanitizerTest, InlinePtrLetsBasic) {
-  // var v : i32;
-  // let p : ptr<function, i32> = &v;
-  // let x : i32 = *p;
-  auto* v = Var("v", ty.i32());
-  auto* p =
-      Const("p", ty.pointer<i32>(ast::StorageClass::kFunction), AddressOf(v));
-  auto* x = Var("x", ty.i32(), ast::StorageClass::kNone, Deref(p));
+    // var v : i32;
+    // let p : ptr<function, i32> = &v;
+    // let x : i32 = *p;
+    auto* v = Var("v", ty.i32());
+    auto* p = Let("p", ty.pointer<i32>(ast::StorageClass::kFunction), AddressOf(v));
+    auto* x = Var("x", ty.i32(), ast::StorageClass::kNone, Deref(p));
 
-  Func("main", ast::VariableList{}, ty.void_(),
-       {
-           Decl(v),
-           Decl(p),
-           Decl(x),
-       },
-       {
-           Stage(ast::PipelineStage::kFragment),
-       });
+    Func("main", ast::VariableList{}, ty.void_(),
+         {
+             Decl(v),
+             Decl(p),
+             Decl(x),
+         },
+         {
+             Stage(ast::PipelineStage::kFragment),
+         });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
+    ASSERT_TRUE(gen.Generate()) << gen.error();
 
-  auto got = gen.result();
-  auto* expect = R"(#version 310 es
+    auto got = gen.result();
+    auto* expect = R"(#version 310 es
 precision mediump float;
 
 void tint_symbol() {
@@ -270,46 +269,42 @@
   return;
 }
 )";
-  EXPECT_EQ(expect, got);
+    EXPECT_EQ(expect, got);
 }
 
 TEST_F(GlslSanitizerTest, InlinePtrLetsComplexChain) {
-  // var a : array<mat4x4<f32>, 4>;
-  // let ap : ptr<function, array<mat4x4<f32>, 4>> = &a;
-  // let mp : ptr<function, mat4x4<f32>> = &(*ap)[3];
-  // let vp : ptr<function, vec4<f32>> = &(*mp)[2];
-  // let v : vec4<f32> = *vp;
-  auto* a = Var("a", ty.array(ty.mat4x4<f32>(), 4));
-  auto* ap = Const(
-      "ap",
-      ty.pointer(ty.array(ty.mat4x4<f32>(), 4), ast::StorageClass::kFunction),
-      AddressOf(a));
-  auto* mp =
-      Const("mp", ty.pointer(ty.mat4x4<f32>(), ast::StorageClass::kFunction),
-            AddressOf(IndexAccessor(Deref(ap), 3)));
-  auto* vp =
-      Const("vp", ty.pointer(ty.vec4<f32>(), ast::StorageClass::kFunction),
-            AddressOf(IndexAccessor(Deref(mp), 2)));
-  auto* v = Var("v", ty.vec4<f32>(), ast::StorageClass::kNone, Deref(vp));
+    // var a : array<mat4x4<f32>, 4u>;
+    // let ap : ptr<function, array<mat4x4<f32>, 4u>> = &a;
+    // let mp : ptr<function, mat4x4<f32>> = &(*ap)[3i];
+    // let vp : ptr<function, vec4<f32>> = &(*mp)[2i];
+    // let v : vec4<f32> = *vp;
+    auto* a = Var("a", ty.array(ty.mat4x4<f32>(), 4_u));
+    auto* ap = Let("ap", ty.pointer(ty.array(ty.mat4x4<f32>(), 4_u), ast::StorageClass::kFunction),
+                   AddressOf(a));
+    auto* mp = Let("mp", ty.pointer(ty.mat4x4<f32>(), ast::StorageClass::kFunction),
+                   AddressOf(IndexAccessor(Deref(ap), 3_i)));
+    auto* vp = Let("vp", ty.pointer(ty.vec4<f32>(), ast::StorageClass::kFunction),
+                   AddressOf(IndexAccessor(Deref(mp), 2_i)));
+    auto* v = Var("v", ty.vec4<f32>(), ast::StorageClass::kNone, Deref(vp));
 
-  Func("main", ast::VariableList{}, ty.void_(),
-       {
-           Decl(a),
-           Decl(ap),
-           Decl(mp),
-           Decl(vp),
-           Decl(v),
-       },
-       {
-           Stage(ast::PipelineStage::kFragment),
-       });
+    Func("main", ast::VariableList{}, ty.void_(),
+         {
+             Decl(a),
+             Decl(ap),
+             Decl(mp),
+             Decl(vp),
+             Decl(v),
+         },
+         {
+             Stage(ast::PipelineStage::kFragment),
+         });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
+    ASSERT_TRUE(gen.Generate()) << gen.error();
 
-  auto got = gen.result();
-  auto* expect = R"(#version 310 es
+    auto got = gen.result();
+    auto* expect = R"(#version 310 es
 precision mediump float;
 
 void tint_symbol() {
@@ -322,7 +317,7 @@
   return;
 }
 )";
-  EXPECT_EQ(expect, got);
+    EXPECT_EQ(expect, got);
 }
 
 }  // namespace
diff --git a/src/tint/writer/glsl/generator_impl_storage_buffer_test.cc b/src/tint/writer/glsl/generator_impl_storage_buffer_test.cc
index 00bca6c..a12fbbc 100644
--- a/src/tint/writer/glsl/generator_impl_storage_buffer_test.cc
+++ b/src/tint/writer/glsl/generator_impl_storage_buffer_test.cc
@@ -23,35 +23,34 @@
 using GlslGeneratorImplTest_StorageBuffer = TestHelper;
 
 void TestAlign(ProgramBuilder* ctx) {
-  // struct Nephews {
-  //   @align(256) huey  : f32;
-  //   @align(256) dewey : f32;
-  //   @align(256) louie : f32;
-  // };
-  // @group(0) @binding(0) var<storage, read_write> nephews : Nephews;
-  auto* nephews = ctx->Structure(
-      "Nephews",
-      {
-          ctx->Member("huey", ctx->ty.f32(), {ctx->MemberAlign(256)}),
-          ctx->Member("dewey", ctx->ty.f32(), {ctx->MemberAlign(256)}),
-          ctx->Member("louie", ctx->ty.f32(), {ctx->MemberAlign(256)}),
-      });
-  ctx->Global("nephews", ctx->ty.Of(nephews), ast::StorageClass::kStorage,
-              ast::AttributeList{
-                  ctx->create<ast::BindingAttribute>(0),
-                  ctx->create<ast::GroupAttribute>(0),
-              });
+    // struct Nephews {
+    //   @align(256) huey  : f32;
+    //   @align(256) dewey : f32;
+    //   @align(256) louie : f32;
+    // };
+    // @group(0) @binding(0) var<storage, read_write> nephews : Nephews;
+    auto* nephews =
+        ctx->Structure("Nephews", {
+                                      ctx->Member("huey", ctx->ty.f32(), {ctx->MemberAlign(256)}),
+                                      ctx->Member("dewey", ctx->ty.f32(), {ctx->MemberAlign(256)}),
+                                      ctx->Member("louie", ctx->ty.f32(), {ctx->MemberAlign(256)}),
+                                  });
+    ctx->Global("nephews", ctx->ty.Of(nephews), ast::StorageClass::kStorage,
+                ast::AttributeList{
+                    ctx->create<ast::BindingAttribute>(0),
+                    ctx->create<ast::GroupAttribute>(0),
+                });
 }
 
 TEST_F(GlslGeneratorImplTest_StorageBuffer, Align) {
-  TestAlign(this);
+    TestAlign(this);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  // TODO(crbug.com/tint/1421) offsets do not currently work on GLSL ES.
-  // They will likely require manual padding.
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    // TODO(crbug.com/tint/1421) offsets do not currently work on GLSL ES.
+    // They will likely require manual padding.
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 
 struct Nephews {
   float huey;
@@ -68,12 +67,12 @@
 }
 
 TEST_F(GlslGeneratorImplTest_StorageBuffer, Align_Desktop) {
-  TestAlign(this);
+    TestAlign(this);
 
-  GeneratorImpl& gen = Build(Version(Version::Standard::kDesktop, 4, 4));
+    GeneratorImpl& gen = Build(Version(Version::Standard::kDesktop, 4, 4));
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 440
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 440
 
 struct Nephews {
   float huey;
diff --git a/src/tint/writer/glsl/generator_impl_switch_test.cc b/src/tint/writer/glsl/generator_impl_switch_test.cc
index e49c08c..1cc42fb 100644
--- a/src/tint/writer/glsl/generator_impl_switch_test.cc
+++ b/src/tint/writer/glsl/generator_impl_switch_test.cc
@@ -14,38 +14,40 @@
 
 #include "src/tint/writer/glsl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::glsl {
 namespace {
 
 using GlslGeneratorImplTest_Switch = TestHelper;
 
 TEST_F(GlslGeneratorImplTest_Switch, Emit_Switch) {
-  Global("cond", ty.i32(), ast::StorageClass::kPrivate);
+    Global("cond", ty.i32(), ast::StorageClass::kPrivate);
 
-  auto* def_body = Block(create<ast::BreakStatement>());
-  auto* def = create<ast::CaseStatement>(ast::CaseSelectorList{}, def_body);
+    auto* def_body = Block(create<ast::BreakStatement>());
+    auto* def = create<ast::CaseStatement>(ast::CaseSelectorList{}, def_body);
 
-  ast::CaseSelectorList case_val;
-  case_val.push_back(Expr(5));
+    ast::CaseSelectorList case_val;
+    case_val.push_back(Expr(5_i));
 
-  auto* case_body = Block(create<ast::BreakStatement>());
+    auto* case_body = Block(create<ast::BreakStatement>());
 
-  auto* case_stmt = create<ast::CaseStatement>(case_val, case_body);
+    auto* case_stmt = create<ast::CaseStatement>(case_val, case_body);
 
-  ast::CaseStatementList body;
-  body.push_back(case_stmt);
-  body.push_back(def);
+    ast::CaseStatementList body;
+    body.push_back(case_stmt);
+    body.push_back(def);
 
-  auto* cond = Expr("cond");
-  auto* s = create<ast::SwitchStatement>(cond, body);
-  WrapInFunction(s);
+    auto* cond = Expr("cond");
+    auto* s = create<ast::SwitchStatement>(cond, body);
+    WrapInFunction(s);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(s)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  switch(cond) {
+    ASSERT_TRUE(gen.EmitStatement(s)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  switch(cond) {
     case 5: {
       break;
     }
diff --git a/src/tint/writer/glsl/generator_impl_test.cc b/src/tint/writer/glsl/generator_impl_test.cc
index cecfa92..ad11413 100644
--- a/src/tint/writer/glsl/generator_impl_test.cc
+++ b/src/tint/writer/glsl/generator_impl_test.cc
@@ -20,13 +20,12 @@
 using GlslGeneratorImplTest = TestHelper;
 
 TEST_F(GlslGeneratorImplTest, Generate) {
-  Func("my_func", ast::VariableList{}, ty.void_(), ast::StatementList{},
-       ast::AttributeList{});
+    Func("my_func", ast::VariableList{}, ty.void_(), ast::StatementList{}, ast::AttributeList{});
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 
 void my_func() {
 }
@@ -35,13 +34,12 @@
 }
 
 TEST_F(GlslGeneratorImplTest, GenerateDesktop) {
-  Func("my_func", ast::VariableList{}, ty.void_(), ast::StatementList{},
-       ast::AttributeList{});
+    Func("my_func", ast::VariableList{}, ty.void_(), ast::StatementList{}, ast::AttributeList{});
 
-  GeneratorImpl& gen = Build(Version(Version::Standard::kDesktop, 4, 4));
+    GeneratorImpl& gen = Build(Version(Version::Standard::kDesktop, 4, 4));
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 440
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 440
 
 void my_func() {
 }
@@ -50,18 +48,16 @@
 }
 
 TEST_F(GlslGeneratorImplTest, GenerateSampleIndexES) {
-  Global(
-      "gl_SampleID", ty.i32(),
-      ast::AttributeList{Builtin(ast::Builtin::kSampleIndex),
-                         Disable(ast::DisabledValidation::kIgnoreStorageClass)},
-      ast::StorageClass::kInput);
-  Func("my_func", {}, ty.i32(),
-       ast::StatementList{Return(Expr("gl_SampleID"))});
+    Global("gl_SampleID", ty.i32(),
+           ast::AttributeList{Builtin(ast::Builtin::kSampleIndex),
+                              Disable(ast::DisabledValidation::kIgnoreStorageClass)},
+           ast::StorageClass::kInput);
+    Func("my_func", {}, ty.i32(), ast::StatementList{Return(Expr("gl_SampleID"))});
 
-  GeneratorImpl& gen = Build(Version(Version::Standard::kES, 3, 1));
+    GeneratorImpl& gen = Build(Version(Version::Standard::kES, 3, 1));
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 #extension GL_OES_sample_variables : require
 
 int my_func() {
@@ -72,18 +68,16 @@
 }
 
 TEST_F(GlslGeneratorImplTest, GenerateSampleIndexDesktop) {
-  Global(
-      "gl_SampleID", ty.i32(),
-      ast::AttributeList{Builtin(ast::Builtin::kSampleIndex),
-                         Disable(ast::DisabledValidation::kIgnoreStorageClass)},
-      ast::StorageClass::kInput);
-  Func("my_func", {}, ty.i32(),
-       ast::StatementList{Return(Expr("gl_SampleID"))});
+    Global("gl_SampleID", ty.i32(),
+           ast::AttributeList{Builtin(ast::Builtin::kSampleIndex),
+                              Disable(ast::DisabledValidation::kIgnoreStorageClass)},
+           ast::StorageClass::kInput);
+    Func("my_func", {}, ty.i32(), ast::StatementList{Return(Expr("gl_SampleID"))});
 
-  GeneratorImpl& gen = Build(Version(Version::Standard::kDesktop, 4, 4));
+    GeneratorImpl& gen = Build(Version(Version::Standard::kDesktop, 4, 4));
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 440
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 440
 
 int my_func() {
   return gl_SampleID;
diff --git a/src/tint/writer/glsl/generator_impl_type_test.cc b/src/tint/writer/glsl/generator_impl_type_test.cc
index c6dbf53..b7daee2 100644
--- a/src/tint/writer/glsl/generator_impl_type_test.cc
+++ b/src/tint/writer/glsl/generator_impl_type_test.cc
@@ -15,135 +15,133 @@
 #include "gmock/gmock.h"
 #include "src/tint/ast/call_statement.h"
 #include "src/tint/ast/stage_attribute.h"
-#include "src/tint/sem/depth_texture_type.h"
-#include "src/tint/sem/multisampled_texture_type.h"
-#include "src/tint/sem/sampled_texture_type.h"
-#include "src/tint/sem/sampler_type.h"
-#include "src/tint/sem/storage_texture_type.h"
+#include "src/tint/sem/depth_texture.h"
+#include "src/tint/sem/multisampled_texture.h"
+#include "src/tint/sem/sampled_texture.h"
+#include "src/tint/sem/sampler.h"
+#include "src/tint/sem/storage_texture.h"
 #include "src/tint/writer/glsl/test_helper.h"
 
+using ::testing::HasSubstr;
+
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::glsl {
 namespace {
 
-using ::testing::HasSubstr;
-
 using GlslGeneratorImplTest_Type = TestHelper;
 
 TEST_F(GlslGeneratorImplTest_Type, EmitType_Array) {
-  auto* arr = ty.array<bool, 4>();
-  Global("G", arr, ast::StorageClass::kPrivate);
+    auto* arr = ty.array<bool, 4>();
+    Global("G", arr, ast::StorageClass::kPrivate);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, program->TypeOf(arr), ast::StorageClass::kNone,
-                           ast::Access::kReadWrite, "ary"))
-      << gen.error();
-  EXPECT_EQ(out.str(), "bool ary[4]");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, program->TypeOf(arr), ast::StorageClass::kNone,
+                             ast::Access::kReadWrite, "ary"))
+        << gen.error();
+    EXPECT_EQ(out.str(), "bool ary[4]");
 }
 
 TEST_F(GlslGeneratorImplTest_Type, EmitType_ArrayOfArray) {
-  auto* arr = ty.array(ty.array<bool, 4>(), 5);
-  Global("G", arr, ast::StorageClass::kPrivate);
+    auto* arr = ty.array(ty.array<bool, 4>(), 5_u);
+    Global("G", arr, ast::StorageClass::kPrivate);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, program->TypeOf(arr), ast::StorageClass::kNone,
-                           ast::Access::kReadWrite, "ary"))
-      << gen.error();
-  EXPECT_EQ(out.str(), "bool ary[5][4]");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, program->TypeOf(arr), ast::StorageClass::kNone,
+                             ast::Access::kReadWrite, "ary"))
+        << gen.error();
+    EXPECT_EQ(out.str(), "bool ary[5][4]");
 }
 
 TEST_F(GlslGeneratorImplTest_Type, EmitType_ArrayOfArrayOfArray) {
-  auto* arr = ty.array(ty.array(ty.array<bool, 4>(), 5), 6);
-  Global("G", arr, ast::StorageClass::kPrivate);
+    auto* arr = ty.array(ty.array(ty.array<bool, 4>(), 5_u), 6_u);
+    Global("G", arr, ast::StorageClass::kPrivate);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, program->TypeOf(arr), ast::StorageClass::kNone,
-                           ast::Access::kReadWrite, "ary"))
-      << gen.error();
-  EXPECT_EQ(out.str(), "bool ary[6][5][4]");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, program->TypeOf(arr), ast::StorageClass::kNone,
+                             ast::Access::kReadWrite, "ary"))
+        << gen.error();
+    EXPECT_EQ(out.str(), "bool ary[6][5][4]");
 }
 
 TEST_F(GlslGeneratorImplTest_Type, EmitType_Array_WithoutName) {
-  auto* arr = ty.array<bool, 4>();
-  Global("G", arr, ast::StorageClass::kPrivate);
+    auto* arr = ty.array<bool, 4>();
+    Global("G", arr, ast::StorageClass::kPrivate);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, program->TypeOf(arr), ast::StorageClass::kNone,
-                           ast::Access::kReadWrite, ""))
-      << gen.error();
-  EXPECT_EQ(out.str(), "bool[4]");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, program->TypeOf(arr), ast::StorageClass::kNone,
+                             ast::Access::kReadWrite, ""))
+        << gen.error();
+    EXPECT_EQ(out.str(), "bool[4]");
 }
 
 TEST_F(GlslGeneratorImplTest_Type, EmitType_Bool) {
-  auto* bool_ = create<sem::Bool>();
+    auto* bool_ = create<sem::Bool>();
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, bool_, ast::StorageClass::kNone,
-                           ast::Access::kReadWrite, ""))
-      << gen.error();
-  EXPECT_EQ(out.str(), "bool");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, bool_, ast::StorageClass::kNone, ast::Access::kReadWrite, ""))
+        << gen.error();
+    EXPECT_EQ(out.str(), "bool");
 }
 
 TEST_F(GlslGeneratorImplTest_Type, EmitType_F32) {
-  auto* f32 = create<sem::F32>();
+    auto* f32 = create<sem::F32>();
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, f32, ast::StorageClass::kNone,
-                           ast::Access::kReadWrite, ""))
-      << gen.error();
-  EXPECT_EQ(out.str(), "float");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, f32, ast::StorageClass::kNone, ast::Access::kReadWrite, ""))
+        << gen.error();
+    EXPECT_EQ(out.str(), "float");
 }
 
 TEST_F(GlslGeneratorImplTest_Type, EmitType_I32) {
-  auto* i32 = create<sem::I32>();
+    auto* i32 = create<sem::I32>();
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, i32, ast::StorageClass::kNone,
-                           ast::Access::kReadWrite, ""))
-      << gen.error();
-  EXPECT_EQ(out.str(), "int");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, i32, ast::StorageClass::kNone, ast::Access::kReadWrite, ""))
+        << gen.error();
+    EXPECT_EQ(out.str(), "int");
 }
 
 TEST_F(GlslGeneratorImplTest_Type, EmitType_Matrix) {
-  auto* f32 = create<sem::F32>();
-  auto* vec3 = create<sem::Vector>(f32, 3u);
-  auto* mat2x3 = create<sem::Matrix>(vec3, 2u);
+    auto* f32 = create<sem::F32>();
+    auto* vec3 = create<sem::Vector>(f32, 3u);
+    auto* mat2x3 = create<sem::Matrix>(vec3, 2u);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, mat2x3, ast::StorageClass::kNone,
-                           ast::Access::kReadWrite, ""))
-      << gen.error();
-  EXPECT_EQ(out.str(), "mat2x3");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, mat2x3, ast::StorageClass::kNone, ast::Access::kReadWrite, ""))
+        << gen.error();
+    EXPECT_EQ(out.str(), "mat2x3");
 }
 
 TEST_F(GlslGeneratorImplTest_Type, EmitType_StructDecl) {
-  auto* s = Structure("S", {
-                               Member("a", ty.i32()),
-                               Member("b", ty.f32()),
-                           });
-  Global("g", ty.Of(s), ast::StorageClass::kPrivate);
+    auto* s = Structure("S", {
+                                 Member("a", ty.i32()),
+                                 Member("b", ty.f32()),
+                             });
+    Global("g", ty.Of(s), ast::StorageClass::kPrivate);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  TextGenerator::TextBuffer buf;
-  auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
-  ASSERT_TRUE(gen.EmitStructType(&buf, sem_s)) << gen.error();
-  EXPECT_EQ(buf.String(), R"(struct S {
+    TextGenerator::TextBuffer buf;
+    auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
+    ASSERT_TRUE(gen.EmitStructType(&buf, sem_s)) << gen.error();
+    EXPECT_EQ(buf.String(), R"(struct S {
   int a;
   float b;
 };
@@ -152,33 +150,32 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Type, EmitType_Struct) {
-  auto* s = Structure("S", {
-                               Member("a", ty.i32()),
-                               Member("b", ty.f32()),
-                           });
-  Global("g", ty.Of(s), ast::StorageClass::kPrivate);
+    auto* s = Structure("S", {
+                                 Member("a", ty.i32()),
+                                 Member("b", ty.f32()),
+                             });
+    Global("g", ty.Of(s), ast::StorageClass::kPrivate);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, sem_s, ast::StorageClass::kNone,
-                           ast::Access::kReadWrite, ""))
-      << gen.error();
-  EXPECT_EQ(out.str(), "S");
+    auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, sem_s, ast::StorageClass::kNone, ast::Access::kReadWrite, ""))
+        << gen.error();
+    EXPECT_EQ(out.str(), "S");
 }
 
 TEST_F(GlslGeneratorImplTest_Type, EmitType_Struct_NameCollision) {
-  auto* s = Structure("S", {
-                               Member("double", ty.i32()),
-                               Member("float", ty.f32()),
-                           });
-  Global("g", ty.Of(s), ast::StorageClass::kPrivate);
+    auto* s = Structure("S", {
+                                 Member("double", ty.i32()),
+                                 Member("float", ty.f32()),
+                             });
+    Global("g", ty.Of(s), ast::StorageClass::kPrivate);
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr(R"(struct S {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr(R"(struct S {
   int tint_symbol;
   float tint_symbol_1;
 };
@@ -186,18 +183,18 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Type, EmitType_Struct_WithOffsetAttributes) {
-  auto* s = Structure("S", {
-                               Member("a", ty.i32(), {MemberOffset(0)}),
-                               Member("b", ty.f32(), {MemberOffset(8)}),
-                           });
-  Global("g", ty.Of(s), ast::StorageClass::kPrivate);
+    auto* s = Structure("S", {
+                                 Member("a", ty.i32(), {MemberOffset(0)}),
+                                 Member("b", ty.f32(), {MemberOffset(8)}),
+                             });
+    Global("g", ty.Of(s), ast::StorageClass::kPrivate);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  TextGenerator::TextBuffer buf;
-  auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
-  ASSERT_TRUE(gen.EmitStructType(&buf, sem_s)) << gen.error();
-  EXPECT_EQ(buf.String(), R"(struct S {
+    TextGenerator::TextBuffer buf;
+    auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
+    ASSERT_TRUE(gen.EmitStructType(&buf, sem_s)) << gen.error();
+    EXPECT_EQ(buf.String(), R"(struct S {
   int a;
   float b;
 };
@@ -206,165 +203,156 @@
 }
 
 TEST_F(GlslGeneratorImplTest_Type, EmitType_U32) {
-  auto* u32 = create<sem::U32>();
+    auto* u32 = create<sem::U32>();
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, u32, ast::StorageClass::kNone,
-                           ast::Access::kReadWrite, ""))
-      << gen.error();
-  EXPECT_EQ(out.str(), "uint");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, u32, ast::StorageClass::kNone, ast::Access::kReadWrite, ""))
+        << gen.error();
+    EXPECT_EQ(out.str(), "uint");
 }
 
 TEST_F(GlslGeneratorImplTest_Type, EmitType_Vector) {
-  auto* f32 = create<sem::F32>();
-  auto* vec3 = create<sem::Vector>(f32, 3u);
+    auto* f32 = create<sem::F32>();
+    auto* vec3 = create<sem::Vector>(f32, 3u);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, vec3, ast::StorageClass::kNone,
-                           ast::Access::kReadWrite, ""))
-      << gen.error();
-  EXPECT_EQ(out.str(), "vec3");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, vec3, ast::StorageClass::kNone, ast::Access::kReadWrite, ""))
+        << gen.error();
+    EXPECT_EQ(out.str(), "vec3");
 }
 
 TEST_F(GlslGeneratorImplTest_Type, EmitType_Void) {
-  auto* void_ = create<sem::Void>();
+    auto* void_ = create<sem::Void>();
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, void_, ast::StorageClass::kNone,
-                           ast::Access::kReadWrite, ""))
-      << gen.error();
-  EXPECT_EQ(out.str(), "void");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, void_, ast::StorageClass::kNone, ast::Access::kReadWrite, ""))
+        << gen.error();
+    EXPECT_EQ(out.str(), "void");
 }
 
 TEST_F(GlslGeneratorImplTest_Type, EmitSampler) {
-  auto* sampler = create<sem::Sampler>(ast::SamplerKind::kSampler);
+    auto* sampler = create<sem::Sampler>(ast::SamplerKind::kSampler);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_FALSE(gen.EmitType(out, sampler, ast::StorageClass::kNone,
-                            ast::Access::kReadWrite, ""))
-      << gen.error();
+    std::stringstream out;
+    ASSERT_FALSE(gen.EmitType(out, sampler, ast::StorageClass::kNone, ast::Access::kReadWrite, ""))
+        << gen.error();
 }
 
 TEST_F(GlslGeneratorImplTest_Type, EmitSamplerComparison) {
-  auto* sampler = create<sem::Sampler>(ast::SamplerKind::kComparisonSampler);
+    auto* sampler = create<sem::Sampler>(ast::SamplerKind::kComparisonSampler);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_FALSE(gen.EmitType(out, sampler, ast::StorageClass::kNone,
-                            ast::Access::kReadWrite, ""))
-      << gen.error();
+    std::stringstream out;
+    ASSERT_FALSE(gen.EmitType(out, sampler, ast::StorageClass::kNone, ast::Access::kReadWrite, ""))
+        << gen.error();
 }
 
 struct GlslDepthTextureData {
-  ast::TextureDimension dim;
-  std::string result;
+    ast::TextureDimension dim;
+    std::string result;
 };
 inline std::ostream& operator<<(std::ostream& out, GlslDepthTextureData data) {
-  out << data.dim;
-  return out;
+    out << data.dim;
+    return out;
 }
 using GlslDepthTexturesTest = TestParamHelper<GlslDepthTextureData>;
 TEST_P(GlslDepthTexturesTest, Emit) {
-  auto params = GetParam();
+    auto params = GetParam();
 
-  auto* t = ty.depth_texture(params.dim);
+    auto* t = ty.depth_texture(params.dim);
 
-  Global("tex", t,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(1),
-             create<ast::GroupAttribute>(2),
-         });
+    Global("tex", t,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(1),
+               create<ast::GroupAttribute>(2),
+           });
 
-  Func("main", {}, ty.void_(), {CallStmt(Call("textureDimensions", "tex"))},
-       {Stage(ast::PipelineStage::kFragment)});
+    Func("main", {}, ty.void_(), {CallStmt(Call("textureDimensions", "tex"))},
+         {Stage(ast::PipelineStage::kFragment)});
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr(params.result));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr(params.result));
 }
 INSTANTIATE_TEST_SUITE_P(
     GlslGeneratorImplTest_Type,
     GlslDepthTexturesTest,
-    testing::Values(GlslDepthTextureData{ast::TextureDimension::k2d,
-                                         "sampler2DShadow tex;"},
-                    GlslDepthTextureData{ast::TextureDimension::k2dArray,
-                                         "sampler2DArrayShadow tex;"},
-                    GlslDepthTextureData{ast::TextureDimension::kCube,
-                                         "samplerCubeShadow tex;"},
-                    GlslDepthTextureData{ast::TextureDimension::kCubeArray,
-                                         "samplerCubeArrayShadow tex;"}));
+    testing::Values(
+        GlslDepthTextureData{ast::TextureDimension::k2d, "sampler2DShadow tex;"},
+        GlslDepthTextureData{ast::TextureDimension::k2dArray, "sampler2DArrayShadow tex;"},
+        GlslDepthTextureData{ast::TextureDimension::kCube, "samplerCubeShadow tex;"},
+        GlslDepthTextureData{ast::TextureDimension::kCubeArray, "samplerCubeArrayShadow tex;"}));
 
 using GlslDepthMultisampledTexturesTest = TestHelper;
 TEST_F(GlslDepthMultisampledTexturesTest, Emit) {
-  auto* t = ty.depth_multisampled_texture(ast::TextureDimension::k2d);
+    auto* t = ty.depth_multisampled_texture(ast::TextureDimension::k2d);
 
-  Global("tex", t,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(1),
-             create<ast::GroupAttribute>(2),
-         });
+    Global("tex", t,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(1),
+               create<ast::GroupAttribute>(2),
+           });
 
-  Func("main", {}, ty.void_(), {CallStmt(Call("textureDimensions", "tex"))},
-       {Stage(ast::PipelineStage::kFragment)});
+    Func("main", {}, ty.void_(), {CallStmt(Call("textureDimensions", "tex"))},
+         {Stage(ast::PipelineStage::kFragment)});
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("sampler2DMS tex;"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("sampler2DMS tex;"));
 }
 
 enum class TextureDataType { F32, U32, I32 };
 struct GlslSampledTextureData {
-  ast::TextureDimension dim;
-  TextureDataType datatype;
-  std::string result;
+    ast::TextureDimension dim;
+    TextureDataType datatype;
+    std::string result;
 };
-inline std::ostream& operator<<(std::ostream& out,
-                                GlslSampledTextureData data) {
-  out << data.dim;
-  return out;
+inline std::ostream& operator<<(std::ostream& out, GlslSampledTextureData data) {
+    out << data.dim;
+    return out;
 }
 using GlslSampledTexturesTest = TestParamHelper<GlslSampledTextureData>;
 TEST_P(GlslSampledTexturesTest, Emit) {
-  auto params = GetParam();
+    auto params = GetParam();
 
-  const ast::Type* datatype = nullptr;
-  switch (params.datatype) {
-    case TextureDataType::F32:
-      datatype = ty.f32();
-      break;
-    case TextureDataType::U32:
-      datatype = ty.u32();
-      break;
-    case TextureDataType::I32:
-      datatype = ty.i32();
-      break;
-  }
-  auto* t = ty.sampled_texture(params.dim, datatype);
+    const ast::Type* datatype = nullptr;
+    switch (params.datatype) {
+        case TextureDataType::F32:
+            datatype = ty.f32();
+            break;
+        case TextureDataType::U32:
+            datatype = ty.u32();
+            break;
+        case TextureDataType::I32:
+            datatype = ty.i32();
+            break;
+    }
+    auto* t = ty.sampled_texture(params.dim, datatype);
 
-  Global("tex", t,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(1),
-             create<ast::GroupAttribute>(2),
-         });
+    Global("tex", t,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(1),
+               create<ast::GroupAttribute>(2),
+           });
 
-  Func("main", {}, ty.void_(), {CallStmt(Call("textureDimensions", "tex"))},
-       {Stage(ast::PipelineStage::kFragment)});
+    Func("main", {}, ty.void_(), {CallStmt(Call("textureDimensions", "tex"))},
+         {Stage(ast::PipelineStage::kFragment)});
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr(params.result));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr(params.result));
 }
 INSTANTIATE_TEST_SUITE_P(GlslGeneratorImplTest_Type,
                          GlslSampledTexturesTest,
@@ -461,78 +449,74 @@
                              }));
 
 TEST_F(GlslGeneratorImplTest_Type, EmitMultisampledTexture) {
-  auto* f32 = create<sem::F32>();
-  auto* s = create<sem::MultisampledTexture>(ast::TextureDimension::k2d, f32);
+    auto* f32 = create<sem::F32>();
+    auto* s = create<sem::MultisampledTexture>(ast::TextureDimension::k2d, f32);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, s, ast::StorageClass::kNone,
-                           ast::Access::kReadWrite, ""))
-      << gen.error();
-  EXPECT_EQ(out.str(), "highp sampler2DMS");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, s, ast::StorageClass::kNone, ast::Access::kReadWrite, ""))
+        << gen.error();
+    EXPECT_EQ(out.str(), "highp sampler2DMS");
 }
 
 struct GlslStorageTextureData {
-  ast::TextureDimension dim;
-  ast::TexelFormat imgfmt;
-  std::string result;
+    ast::TextureDimension dim;
+    ast::TexelFormat imgfmt;
+    std::string result;
 };
-inline std::ostream& operator<<(std::ostream& out,
-                                GlslStorageTextureData data) {
-  return out << data.dim;
+inline std::ostream& operator<<(std::ostream& out, GlslStorageTextureData data) {
+    return out << data.dim;
 }
 using GlslStorageTexturesTest = TestParamHelper<GlslStorageTextureData>;
 TEST_P(GlslStorageTexturesTest, Emit) {
-  auto params = GetParam();
+    auto params = GetParam();
 
-  auto* t = ty.storage_texture(params.dim, params.imgfmt, ast::Access::kWrite);
+    auto* t = ty.storage_texture(params.dim, params.imgfmt, ast::Access::kWrite);
 
-  Global("tex", t,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(1),
-             create<ast::GroupAttribute>(2),
-         });
+    Global("tex", t,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(1),
+               create<ast::GroupAttribute>(2),
+           });
 
-  Func("main", {}, ty.void_(), {CallStmt(Call("textureDimensions", "tex"))},
-       {Stage(ast::PipelineStage::kFragment)});
+    Func("main", {}, ty.void_(), {CallStmt(Call("textureDimensions", "tex"))},
+         {Stage(ast::PipelineStage::kFragment)});
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr(params.result));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr(params.result));
 }
 INSTANTIATE_TEST_SUITE_P(
     GlslGeneratorImplTest_Type,
     GlslStorageTexturesTest,
-    testing::Values(
-        GlslStorageTextureData{ast::TextureDimension::k1d,
-                               ast::TexelFormat::kRgba8Unorm, "image1D tex;"},
-        GlslStorageTextureData{ast::TextureDimension::k2d,
-                               ast::TexelFormat::kRgba16Float, "image2D tex;"},
-        GlslStorageTextureData{ast::TextureDimension::k2dArray,
-                               ast::TexelFormat::kR32Float,
-                               "image2DArray tex;"},
-        GlslStorageTextureData{ast::TextureDimension::k3d,
-                               ast::TexelFormat::kRg32Float, "image3D tex;"},
-        GlslStorageTextureData{ast::TextureDimension::k1d,
-                               ast::TexelFormat::kRgba32Float, "image1D tex;"},
-        GlslStorageTextureData{ast::TextureDimension::k2d,
-                               ast::TexelFormat::kRgba16Uint, "image2D tex;"},
-        GlslStorageTextureData{ast::TextureDimension::k2dArray,
-                               ast::TexelFormat::kR32Uint, "image2DArray tex;"},
-        GlslStorageTextureData{ast::TextureDimension::k3d,
-                               ast::TexelFormat::kRg32Uint, "image3D tex;"},
-        GlslStorageTextureData{ast::TextureDimension::k1d,
-                               ast::TexelFormat::kRgba32Uint, "image1D tex;"},
-        GlslStorageTextureData{ast::TextureDimension::k2d,
-                               ast::TexelFormat::kRgba16Sint, "image2D tex;"},
-        GlslStorageTextureData{ast::TextureDimension::k2dArray,
-                               ast::TexelFormat::kR32Sint, "image2DArray tex;"},
-        GlslStorageTextureData{ast::TextureDimension::k3d,
-                               ast::TexelFormat::kRg32Sint, "image3D tex;"},
-        GlslStorageTextureData{ast::TextureDimension::k1d,
-                               ast::TexelFormat::kRgba32Sint, "image1D tex;"}));
+    testing::Values(GlslStorageTextureData{ast::TextureDimension::k1d,
+                                           ast::TexelFormat::kRgba8Unorm, "image1D tex;"},
+                    GlslStorageTextureData{ast::TextureDimension::k2d,
+                                           ast::TexelFormat::kRgba16Float, "image2D tex;"},
+                    GlslStorageTextureData{ast::TextureDimension::k2dArray,
+                                           ast::TexelFormat::kR32Float, "image2DArray tex;"},
+                    GlslStorageTextureData{ast::TextureDimension::k3d, ast::TexelFormat::kRg32Float,
+                                           "image3D tex;"},
+                    GlslStorageTextureData{ast::TextureDimension::k1d,
+                                           ast::TexelFormat::kRgba32Float, "image1D tex;"},
+                    GlslStorageTextureData{ast::TextureDimension::k2d,
+                                           ast::TexelFormat::kRgba16Uint, "image2D tex;"},
+                    GlslStorageTextureData{ast::TextureDimension::k2dArray,
+                                           ast::TexelFormat::kR32Uint, "image2DArray tex;"},
+                    GlslStorageTextureData{ast::TextureDimension::k3d, ast::TexelFormat::kRg32Uint,
+                                           "image3D tex;"},
+                    GlslStorageTextureData{ast::TextureDimension::k1d,
+                                           ast::TexelFormat::kRgba32Uint, "image1D tex;"},
+                    GlslStorageTextureData{ast::TextureDimension::k2d,
+                                           ast::TexelFormat::kRgba16Sint, "image2D tex;"},
+                    GlslStorageTextureData{ast::TextureDimension::k2dArray,
+                                           ast::TexelFormat::kR32Sint, "image2DArray tex;"},
+                    GlslStorageTextureData{ast::TextureDimension::k3d, ast::TexelFormat::kRg32Sint,
+                                           "image3D tex;"},
+                    GlslStorageTextureData{ast::TextureDimension::k1d,
+                                           ast::TexelFormat::kRgba32Sint, "image1D tex;"}));
 
 }  // namespace
 }  // namespace tint::writer::glsl
diff --git a/src/tint/writer/glsl/generator_impl_unary_op_test.cc b/src/tint/writer/glsl/generator_impl_unary_op_test.cc
index 2743ad1..0e318fc 100644
--- a/src/tint/writer/glsl/generator_impl_unary_op_test.cc
+++ b/src/tint/writer/glsl/generator_impl_unary_op_test.cc
@@ -20,70 +20,65 @@
 using GlslUnaryOpTest = TestHelper;
 
 TEST_F(GlslUnaryOpTest, AddressOf) {
-  Global("expr", ty.f32(), ast::StorageClass::kPrivate);
-  auto* op =
-      create<ast::UnaryOpExpression>(ast::UnaryOp::kAddressOf, Expr("expr"));
-  WrapInFunction(op);
+    Global("expr", ty.f32(), ast::StorageClass::kPrivate);
+    auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kAddressOf, Expr("expr"));
+    WrapInFunction(op);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
-  EXPECT_EQ(out.str(), "expr");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
+    EXPECT_EQ(out.str(), "expr");
 }
 
 TEST_F(GlslUnaryOpTest, Complement) {
-  Global("expr", ty.u32(), ast::StorageClass::kPrivate);
-  auto* op =
-      create<ast::UnaryOpExpression>(ast::UnaryOp::kComplement, Expr("expr"));
-  WrapInFunction(op);
+    Global("expr", ty.u32(), ast::StorageClass::kPrivate);
+    auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kComplement, Expr("expr"));
+    WrapInFunction(op);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
-  EXPECT_EQ(out.str(), "~(expr)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
+    EXPECT_EQ(out.str(), "~(expr)");
 }
 
 TEST_F(GlslUnaryOpTest, Indirection) {
-  Global("G", ty.f32(), ast::StorageClass::kPrivate);
-  auto* p = Const(
-      "expr", nullptr,
-      create<ast::UnaryOpExpression>(ast::UnaryOp::kAddressOf, Expr("G")));
-  auto* op =
-      create<ast::UnaryOpExpression>(ast::UnaryOp::kIndirection, Expr("expr"));
-  WrapInFunction(p, op);
+    Global("G", ty.f32(), ast::StorageClass::kPrivate);
+    auto* p =
+        Let("expr", nullptr, create<ast::UnaryOpExpression>(ast::UnaryOp::kAddressOf, Expr("G")));
+    auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kIndirection, Expr("expr"));
+    WrapInFunction(p, op);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
-  EXPECT_EQ(out.str(), "expr");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
+    EXPECT_EQ(out.str(), "expr");
 }
 
 TEST_F(GlslUnaryOpTest, Not) {
-  Global("expr", ty.bool_(), ast::StorageClass::kPrivate);
-  auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kNot, Expr("expr"));
-  WrapInFunction(op);
+    Global("expr", ty.bool_(), ast::StorageClass::kPrivate);
+    auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kNot, Expr("expr"));
+    WrapInFunction(op);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
-  EXPECT_EQ(out.str(), "!(expr)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
+    EXPECT_EQ(out.str(), "!(expr)");
 }
 
 TEST_F(GlslUnaryOpTest, Negation) {
-  Global("expr", ty.i32(), ast::StorageClass::kPrivate);
-  auto* op =
-      create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation, Expr("expr"));
-  WrapInFunction(op);
+    Global("expr", ty.i32(), ast::StorageClass::kPrivate);
+    auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation, Expr("expr"));
+    WrapInFunction(op);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
-  EXPECT_EQ(out.str(), "-(expr)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
+    EXPECT_EQ(out.str(), "-(expr)");
 }
 }  // namespace
 }  // namespace tint::writer::glsl
diff --git a/src/tint/writer/glsl/generator_impl_uniform_buffer_test.cc b/src/tint/writer/glsl/generator_impl_uniform_buffer_test.cc
index b7a5f88..8709b3d 100644
--- a/src/tint/writer/glsl/generator_impl_uniform_buffer_test.cc
+++ b/src/tint/writer/glsl/generator_impl_uniform_buffer_test.cc
@@ -23,14 +23,13 @@
 using GlslGeneratorImplTest_UniformBuffer = TestHelper;
 
 TEST_F(GlslGeneratorImplTest_UniformBuffer, Simple) {
-  auto* simple = Structure("Simple", {Member("member", ty.f32())});
-  Global("simple", ty.Of(simple), ast::StorageClass::kUniform,
-         GroupAndBinding(0, 0));
+    auto* simple = Structure("Simple", {Member("member", ty.f32())});
+    Global("simple", ty.Of(simple), ast::StorageClass::kUniform, GroupAndBinding(0, 0));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 310 es
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 310 es
 
 struct Simple {
   float member;
@@ -44,14 +43,13 @@
 }
 
 TEST_F(GlslGeneratorImplTest_UniformBuffer, Simple_Desktop) {
-  auto* simple = Structure("Simple", {Member("member", ty.f32())});
-  Global("simple", ty.Of(simple), ast::StorageClass::kUniform,
-         GroupAndBinding(0, 0));
+    auto* simple = Structure("Simple", {Member("member", ty.f32())});
+    Global("simple", ty.Of(simple), ast::StorageClass::kUniform, GroupAndBinding(0, 0));
 
-  GeneratorImpl& gen = Build(Version(Version::Standard::kDesktop, 4, 4));
+    GeneratorImpl& gen = Build(Version(Version::Standard::kDesktop, 4, 4));
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#version 440
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#version 440
 
 struct Simple {
   float member;
diff --git a/src/tint/writer/glsl/generator_impl_variable_decl_statement_test.cc b/src/tint/writer/glsl/generator_impl_variable_decl_statement_test.cc
index 29d5a41..d293dba 100644
--- a/src/tint/writer/glsl/generator_impl_variable_decl_statement_test.cc
+++ b/src/tint/writer/glsl/generator_impl_variable_decl_statement_test.cc
@@ -24,100 +24,95 @@
 using GlslGeneratorImplTest_VariableDecl = TestHelper;
 
 TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement) {
-  auto* var = Var("a", ty.f32());
-  auto* stmt = Decl(var);
-  WrapInFunction(stmt);
+    auto* var = Var("a", ty.f32());
+    auto* stmt = Decl(var);
+    WrapInFunction(stmt);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
-  EXPECT_EQ(gen.result(), "  float a = 0.0f;\n");
+    ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
+    EXPECT_EQ(gen.result(), "  float a = 0.0f;\n");
 }
 
 TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const) {
-  auto* var = Const("a", ty.f32(), Construct(ty.f32()));
-  auto* stmt = Decl(var);
-  WrapInFunction(stmt);
+    auto* var = Let("a", ty.f32(), Construct(ty.f32()));
+    auto* stmt = Decl(var);
+    WrapInFunction(stmt);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
-  EXPECT_EQ(gen.result(), "  float a = 0.0f;\n");
+    ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
+    EXPECT_EQ(gen.result(), "  float a = 0.0f;\n");
 }
 
 TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Array) {
-  auto* var = Var("a", ty.array<f32, 5>());
+    auto* var = Var("a", ty.array<f32, 5>());
 
-  WrapInFunction(var, Expr("a"));
+    WrapInFunction(var, Expr("a"));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(
-      gen.result(),
-      HasSubstr("  float a[5] = float[5](0.0f, 0.0f, 0.0f, 0.0f, 0.0f);\n"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(),
+                HasSubstr("  float a[5] = float[5](0.0f, 0.0f, 0.0f, 0.0f, 0.0f);\n"));
 }
 
 TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Private) {
-  Global("a", ty.f32(), ast::StorageClass::kPrivate);
+    Global("a", ty.f32(), ast::StorageClass::kPrivate);
 
-  WrapInFunction(Expr("a"));
+    WrapInFunction(Expr("a"));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("  float a = 0.0f;\n"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("  float a = 0.0f;\n"));
 }
 
-TEST_F(GlslGeneratorImplTest_VariableDecl,
-       Emit_VariableDeclStatement_Initializer_Private) {
-  Global("initializer", ty.f32(), ast::StorageClass::kPrivate);
-  Global("a", ty.f32(), ast::StorageClass::kPrivate, Expr("initializer"));
+TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Initializer_Private) {
+    Global("initializer", ty.f32(), ast::StorageClass::kPrivate);
+    Global("a", ty.f32(), ast::StorageClass::kPrivate, Expr("initializer"));
 
-  WrapInFunction(Expr("a"));
+    WrapInFunction(Expr("a"));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr(R"(float a = initializer;
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr(R"(float a = initializer;
 )"));
 }
 
-TEST_F(GlslGeneratorImplTest_VariableDecl,
-       Emit_VariableDeclStatement_Initializer_ZeroVec) {
-  auto* var = Var("a", ty.vec3<f32>(), ast::StorageClass::kNone, vec3<f32>());
+TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Initializer_ZeroVec) {
+    auto* var = Var("a", ty.vec3<f32>(), ast::StorageClass::kNone, vec3<f32>());
 
-  auto* stmt = Decl(var);
-  WrapInFunction(stmt);
+    auto* stmt = Decl(var);
+    WrapInFunction(stmt);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(vec3 a = vec3(0.0f, 0.0f, 0.0f);
+    ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(vec3 a = vec3(0.0f, 0.0f, 0.0f);
 )");
 }
 
-TEST_F(GlslGeneratorImplTest_VariableDecl,
-       Emit_VariableDeclStatement_Initializer_ZeroMat) {
-  auto* var =
-      Var("a", ty.mat2x3<f32>(), ast::StorageClass::kNone, mat2x3<f32>());
+TEST_F(GlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Initializer_ZeroMat) {
+    auto* var = Var("a", ty.mat2x3<f32>(), ast::StorageClass::kNone, mat2x3<f32>());
 
-  auto* stmt = Decl(var);
-  WrapInFunction(stmt);
+    auto* stmt = Decl(var);
+    WrapInFunction(stmt);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
-  EXPECT_EQ(gen.result(),
-            R"(mat2x3 a = mat2x3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+    ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
+    EXPECT_EQ(gen.result(),
+              R"(mat2x3 a = mat2x3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
 )");
 }
 
diff --git a/src/tint/writer/glsl/generator_impl_workgroup_var_test.cc b/src/tint/writer/glsl/generator_impl_workgroup_var_test.cc
index 9c5a51b..a61cb17 100644
--- a/src/tint/writer/glsl/generator_impl_workgroup_var_test.cc
+++ b/src/tint/writer/glsl/generator_impl_workgroup_var_test.cc
@@ -17,40 +17,43 @@
 #include "src/tint/ast/stage_attribute.h"
 #include "src/tint/writer/glsl/test_helper.h"
 
+using ::testing::HasSubstr;
+
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::glsl {
 namespace {
-using ::testing::HasSubstr;
 
 using GlslGeneratorImplTest_WorkgroupVar = TestHelper;
 
 TEST_F(GlslGeneratorImplTest_WorkgroupVar, Basic) {
-  Global("wg", ty.f32(), ast::StorageClass::kWorkgroup);
+    Global("wg", ty.f32(), ast::StorageClass::kWorkgroup);
 
-  Func("main", {}, ty.void_(), {Assign("wg", 1.2f)},
-       {
-           Stage(ast::PipelineStage::kCompute),
-           WorkgroupSize(1),
-       });
-  GeneratorImpl& gen = Build();
+    Func("main", {}, ty.void_(), {Assign("wg", 1.2f)},
+         {
+             Stage(ast::PipelineStage::kCompute),
+             WorkgroupSize(1_i),
+         });
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("shared float wg;\n"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("shared float wg;\n"));
 }
 
 TEST_F(GlslGeneratorImplTest_WorkgroupVar, Aliased) {
-  auto* alias = Alias("F32", ty.f32());
+    auto* alias = Alias("F32", ty.f32());
 
-  Global("wg", ty.Of(alias), ast::StorageClass::kWorkgroup);
+    Global("wg", ty.Of(alias), ast::StorageClass::kWorkgroup);
 
-  Func("main", {}, ty.void_(), {Assign("wg", 1.2f)},
-       {
-           Stage(ast::PipelineStage::kCompute),
-           WorkgroupSize(1),
-       });
-  GeneratorImpl& gen = Build();
+    Func("main", {}, ty.void_(), {Assign("wg", 1.2f)},
+         {
+             Stage(ast::PipelineStage::kCompute),
+             WorkgroupSize(1_i),
+         });
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("shared float wg;\n"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("shared float wg;\n"));
 }
 
 }  // namespace
diff --git a/src/tint/writer/glsl/test_helper.h b/src/tint/writer/glsl/test_helper.h
index 7266d0a..2f806ce 100644
--- a/src/tint/writer/glsl/test_helper.h
+++ b/src/tint/writer/glsl/test_helper.h
@@ -28,72 +28,66 @@
 /// Helper class for testing
 template <typename BODY>
 class TestHelperBase : public BODY, public ProgramBuilder {
- public:
-  TestHelperBase() = default;
-  ~TestHelperBase() override = default;
+  public:
+    TestHelperBase() = default;
+    ~TestHelperBase() override = default;
 
-  /// Builds the program and returns a GeneratorImpl from the program.
-  /// @note The generator is only built once. Multiple calls to Build() will
-  /// return the same GeneratorImpl without rebuilding.
-  /// @param version the GLSL version
-  /// @return the built generator
-  GeneratorImpl& Build(Version version = Version()) {
-    if (gen_) {
-      return *gen_;
+    /// Builds the program and returns a GeneratorImpl from the program.
+    /// @note The generator is only built once. Multiple calls to Build() will
+    /// return the same GeneratorImpl without rebuilding.
+    /// @param version the GLSL version
+    /// @return the built generator
+    GeneratorImpl& Build(Version version = Version()) {
+        if (gen_) {
+            return *gen_;
+        }
+        [&]() {
+            ASSERT_TRUE(IsValid()) << "Builder program is not valid\n"
+                                   << diag::Formatter().format(Diagnostics());
+        }();
+        program = std::make_unique<Program>(std::move(*this));
+        [&]() {
+            ASSERT_TRUE(program->IsValid()) << diag::Formatter().format(program->Diagnostics());
+        }();
+        gen_ = std::make_unique<GeneratorImpl>(program.get(), version);
+        return *gen_;
     }
-    [&]() {
-      ASSERT_TRUE(IsValid()) << "Builder program is not valid\n"
-                             << diag::Formatter().format(Diagnostics());
-    }();
-    program = std::make_unique<Program>(std::move(*this));
-    [&]() {
-      ASSERT_TRUE(program->IsValid())
-          << diag::Formatter().format(program->Diagnostics());
-    }();
-    gen_ = std::make_unique<GeneratorImpl>(program.get(), version);
-    return *gen_;
-  }
 
-  /// Builds the program, runs the program through the transform::Glsl sanitizer
-  /// and returns a GeneratorImpl from the sanitized program.
-  /// @note The generator is only built once. Multiple calls to Build() will
-  /// return the same GeneratorImpl without rebuilding.
-  /// @param version the GLSL version
-  /// @param options the GLSL backend options
-  /// @return the built generator
-  GeneratorImpl& SanitizeAndBuild(Version version = Version(),
-                                  const Options& options = {}) {
-    if (gen_) {
-      return *gen_;
+    /// Builds the program, runs the program through the transform::Glsl sanitizer
+    /// and returns a GeneratorImpl from the sanitized program.
+    /// @note The generator is only built once. Multiple calls to Build() will
+    /// return the same GeneratorImpl without rebuilding.
+    /// @param version the GLSL version
+    /// @param options the GLSL backend options
+    /// @return the built generator
+    GeneratorImpl& SanitizeAndBuild(Version version = Version(), const Options& options = {}) {
+        if (gen_) {
+            return *gen_;
+        }
+        diag::Formatter formatter;
+        [&]() {
+            ASSERT_TRUE(IsValid()) << "Builder program is not valid\n"
+                                   << formatter.format(Diagnostics());
+        }();
+        program = std::make_unique<Program>(std::move(*this));
+        [&]() { ASSERT_TRUE(program->IsValid()) << formatter.format(program->Diagnostics()); }();
+
+        auto sanitized_result = Sanitize(program.get(), options, /* entry_point */ "");
+        [&]() {
+            ASSERT_TRUE(sanitized_result.program.IsValid())
+                << formatter.format(sanitized_result.program.Diagnostics());
+        }();
+
+        *program = std::move(sanitized_result.program);
+        gen_ = std::make_unique<GeneratorImpl>(program.get(), version);
+        return *gen_;
     }
-    diag::Formatter formatter;
-    [&]() {
-      ASSERT_TRUE(IsValid()) << "Builder program is not valid\n"
-                             << formatter.format(Diagnostics());
-    }();
-    program = std::make_unique<Program>(std::move(*this));
-    [&]() {
-      ASSERT_TRUE(program->IsValid())
-          << formatter.format(program->Diagnostics());
-    }();
 
-    auto sanitized_result =
-        Sanitize(program.get(), options, /* entry_point */ "");
-    [&]() {
-      ASSERT_TRUE(sanitized_result.program.IsValid())
-          << formatter.format(sanitized_result.program.Diagnostics());
-    }();
+    /// The program built with a call to Build()
+    std::unique_ptr<Program> program;
 
-    *program = std::move(sanitized_result.program);
-    gen_ = std::make_unique<GeneratorImpl>(program.get(), version);
-    return *gen_;
-  }
-
-  /// The program built with a call to Build()
-  std::unique_ptr<Program> program;
-
- private:
-  std::unique_ptr<GeneratorImpl> gen_;
+  private:
+    std::unique_ptr<GeneratorImpl> gen_;
 };
 using TestHelper = TestHelperBase<testing::Test>;
 
diff --git a/src/tint/writer/glsl/version.h b/src/tint/writer/glsl/version.h
index 63888a4..ee33c16 100644
--- a/src/tint/writer/glsl/version.h
+++ b/src/tint/writer/glsl/version.h
@@ -21,36 +21,36 @@
 
 /// A structure representing the version of GLSL to be generated.
 struct Version {
-  /// Is this version desktop GLSL, or GLSL ES?
-  enum class Standard {
-    kDesktop,
-    kES,
-  };
+    /// Is this version desktop GLSL, or GLSL ES?
+    enum class Standard {
+        kDesktop,
+        kES,
+    };
 
-  /// Constructor
-  /// @param standard_ Desktop or ES
-  /// @param major_ the major version
-  /// @param minor_ the minor version
-  Version(Standard standard_, uint32_t major_, uint32_t minor_)
-      : standard(standard_), major_version(major_), minor_version(minor_) {}
+    /// Constructor
+    /// @param standard_ Desktop or ES
+    /// @param major_ the major version
+    /// @param minor_ the minor version
+    Version(Standard standard_, uint32_t major_, uint32_t minor_)
+        : standard(standard_), major_version(major_), minor_version(minor_) {}
 
-  /// Default constructor (see default values below)
-  Version() = default;
+    /// Default constructor (see default values below)
+    Version() = default;
 
-  /// @returns true if this version is GLSL ES
-  bool IsES() const { return standard == Standard::kES; }
+    /// @returns true if this version is GLSL ES
+    bool IsES() const { return standard == Standard::kES; }
 
-  /// @returns true if this version is Desktop GLSL
-  bool IsDesktop() const { return standard == Standard::kDesktop; }
+    /// @returns true if this version is Desktop GLSL
+    bool IsDesktop() const { return standard == Standard::kDesktop; }
 
-  /// Desktop or ES
-  Standard standard = Standard::kES;
+    /// Desktop or ES
+    Standard standard = Standard::kES;
 
-  /// Major GLSL version
-  uint32_t major_version = 3;
+    /// Major GLSL version
+    uint32_t major_version = 3;
 
-  /// Minor GLSL version
-  uint32_t minor_version = 1;
+    /// Minor GLSL version
+    uint32_t minor_version = 1;
 };
 
 }  // namespace tint::writer::glsl
diff --git a/src/tint/writer/hlsl/generator.cc b/src/tint/writer/hlsl/generator.cc
index 682d371..ff3ffbe 100644
--- a/src/tint/writer/hlsl/generator.cc
+++ b/src/tint/writer/hlsl/generator.cc
@@ -28,34 +28,34 @@
 Result::Result(const Result&) = default;
 
 Result Generate(const Program* program, const Options& options) {
-  Result result;
+    Result result;
 
-  // Sanitize the program.
-  auto sanitized_result = Sanitize(program, options);
-  if (!sanitized_result.program.IsValid()) {
-    result.success = false;
-    result.error = sanitized_result.program.Diagnostics().str();
-    return result;
-  }
-
-  // Generate the HLSL code.
-  auto impl = std::make_unique<GeneratorImpl>(&sanitized_result.program);
-  result.success = impl->Generate();
-  result.error = impl->error();
-  result.hlsl = impl->result();
-
-  // Collect the list of entry points in the sanitized program.
-  for (auto* func : sanitized_result.program.AST().Functions()) {
-    if (func->IsEntryPoint()) {
-      auto name = sanitized_result.program.Symbols().NameFor(func->symbol);
-      result.entry_points.push_back({name, func->PipelineStage()});
+    // Sanitize the program.
+    auto sanitized_result = Sanitize(program, options);
+    if (!sanitized_result.program.IsValid()) {
+        result.success = false;
+        result.error = sanitized_result.program.Diagnostics().str();
+        return result;
     }
-  }
 
-  result.used_array_length_from_uniform_indices =
-      std::move(sanitized_result.used_array_length_from_uniform_indices);
+    // Generate the HLSL code.
+    auto impl = std::make_unique<GeneratorImpl>(&sanitized_result.program);
+    result.success = impl->Generate();
+    result.error = impl->error();
+    result.hlsl = impl->result();
 
-  return result;
+    // Collect the list of entry points in the sanitized program.
+    for (auto* func : sanitized_result.program.AST().Functions()) {
+        if (func->IsEntryPoint()) {
+            auto name = sanitized_result.program.Symbols().NameFor(func->symbol);
+            result.entry_points.push_back({name, func->PipelineStage()});
+        }
+    }
+
+    result.used_array_length_from_uniform_indices =
+        std::move(sanitized_result.used_array_length_from_uniform_indices);
+
+    return result;
 }
 
 }  // namespace tint::writer::hlsl
diff --git a/src/tint/writer/hlsl/generator.h b/src/tint/writer/hlsl/generator.h
index beb2a88..f658c99 100644
--- a/src/tint/writer/hlsl/generator.h
+++ b/src/tint/writer/hlsl/generator.h
@@ -38,56 +38,56 @@
 
 /// Configuration options used for generating HLSL.
 struct Options {
-  /// Constructor
-  Options();
-  /// Destructor
-  ~Options();
-  /// Copy constructor
-  Options(const Options&);
-  /// Copy assignment
-  /// @returns this Options
-  Options& operator=(const Options&);
+    /// Constructor
+    Options();
+    /// Destructor
+    ~Options();
+    /// Copy constructor
+    Options(const Options&);
+    /// Copy assignment
+    /// @returns this Options
+    Options& operator=(const Options&);
 
-  /// The binding point to use for information passed via root constants.
-  sem::BindingPoint root_constant_binding_point;
-  /// Set to `true` to disable workgroup memory zero initialization
-  bool disable_workgroup_init = false;
-  /// Set to 'true' to generates binding mappings for external textures
-  bool generate_external_texture_bindings = false;
-  /// Options used to specify a mapping of binding points to indices into a UBO
-  /// from which to load buffer sizes.
-  ArrayLengthFromUniformOptions array_length_from_uniform = {};
+    /// The binding point to use for information passed via root constants.
+    sem::BindingPoint root_constant_binding_point;
+    /// Set to `true` to disable workgroup memory zero initialization
+    bool disable_workgroup_init = false;
+    /// Set to 'true' to generates binding mappings for external textures
+    bool generate_external_texture_bindings = false;
+    /// Options used to specify a mapping of binding points to indices into a UBO
+    /// from which to load buffer sizes.
+    ArrayLengthFromUniformOptions array_length_from_uniform = {};
 
-  // NOTE: Update src/tint/fuzzers/data_builder.h when adding or changing any
-  // struct members.
+    // NOTE: Update src/tint/fuzzers/data_builder.h when adding or changing any
+    // struct members.
 };
 
 /// The result produced when generating HLSL.
 struct Result {
-  /// Constructor
-  Result();
+    /// Constructor
+    Result();
 
-  /// Destructor
-  ~Result();
+    /// Destructor
+    ~Result();
 
-  /// Copy constructor
-  Result(const Result&);
+    /// Copy constructor
+    Result(const Result&);
 
-  /// True if generation was successful.
-  bool success = false;
+    /// True if generation was successful.
+    bool success = false;
 
-  /// The errors generated during code generation, if any.
-  std::string error;
+    /// The errors generated during code generation, if any.
+    std::string error;
 
-  /// The generated HLSL.
-  std::string hlsl = "";
+    /// The generated HLSL.
+    std::string hlsl = "";
 
-  /// The list of entry points in the generated HLSL.
-  std::vector<std::pair<std::string, ast::PipelineStage>> entry_points;
+    /// The list of entry points in the generated HLSL.
+    std::vector<std::pair<std::string, ast::PipelineStage>> entry_points;
 
-  /// Indices into the array_length_from_uniform binding that are statically
-  /// used.
-  std::unordered_set<uint32_t> used_array_length_from_uniform_indices;
+    /// Indices into the array_length_from_uniform binding that are statically
+    /// used.
+    std::unordered_set<uint32_t> used_array_length_from_uniform_indices;
 };
 
 /// Generate HLSL for a program, according to a set of configuration options.
diff --git a/src/tint/writer/hlsl/generator_bench.cc b/src/tint/writer/hlsl/generator_bench.cc
index 27b605b..4567e2d 100644
--- a/src/tint/writer/hlsl/generator_bench.cc
+++ b/src/tint/writer/hlsl/generator_bench.cc
@@ -20,18 +20,18 @@
 namespace {
 
 void GenerateHLSL(benchmark::State& state, std::string input_name) {
-  auto res = bench::LoadProgram(input_name);
-  if (auto err = std::get_if<bench::Error>(&res)) {
-    state.SkipWithError(err->msg.c_str());
-    return;
-  }
-  auto& program = std::get<bench::ProgramAndFile>(res).program;
-  for (auto _ : state) {
-    auto res = Generate(&program, {});
-    if (!res.error.empty()) {
-      state.SkipWithError(res.error.c_str());
+    auto res = bench::LoadProgram(input_name);
+    if (auto err = std::get_if<bench::Error>(&res)) {
+        state.SkipWithError(err->msg.c_str());
+        return;
     }
-  }
+    auto& program = std::get<bench::ProgramAndFile>(res).program;
+    for (auto _ : state) {
+        auto res = Generate(&program, {});
+        if (!res.error.empty()) {
+            state.SkipWithError(res.error.c_str());
+        }
+    }
 }
 
 TINT_BENCHMARK_WGSL_PROGRAMS(GenerateHLSL);
diff --git a/src/tint/writer/hlsl/generator_impl.cc b/src/tint/writer/hlsl/generator_impl.cc
index 008f184..a64630b 100644
--- a/src/tint/writer/hlsl/generator_impl.cc
+++ b/src/tint/writer/hlsl/generator_impl.cc
@@ -30,18 +30,18 @@
 #include "src/tint/ast/variable_decl_statement.h"
 #include "src/tint/debug.h"
 #include "src/tint/sem/array.h"
-#include "src/tint/sem/atomic_type.h"
+#include "src/tint/sem/atomic.h"
 #include "src/tint/sem/block_statement.h"
 #include "src/tint/sem/call.h"
-#include "src/tint/sem/depth_multisampled_texture_type.h"
-#include "src/tint/sem/depth_texture_type.h"
+#include "src/tint/sem/depth_multisampled_texture.h"
+#include "src/tint/sem/depth_texture.h"
 #include "src/tint/sem/function.h"
 #include "src/tint/sem/member_accessor_expression.h"
 #include "src/tint/sem/module.h"
-#include "src/tint/sem/multisampled_texture_type.h"
-#include "src/tint/sem/sampled_texture_type.h"
+#include "src/tint/sem/multisampled_texture.h"
+#include "src/tint/sem/sampled_texture.h"
 #include "src/tint/sem/statement.h"
-#include "src/tint/sem/storage_texture_type.h"
+#include "src/tint/sem/storage_texture.h"
 #include "src/tint/sem/struct.h"
 #include "src/tint/sem/type_constructor.h"
 #include "src/tint/sem/type_conversion.h"
@@ -73,6 +73,8 @@
 #include "src/tint/writer/float_to_string.h"
 #include "src/tint/writer/generate_external_texture_bindings.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::hlsl {
 namespace {
 
@@ -80,52 +82,51 @@
 const char kSpecConstantPrefix[] = "WGSL_SPEC_CONSTANT_";
 
 const char* image_format_to_rwtexture_type(ast::TexelFormat image_format) {
-  switch (image_format) {
-    case ast::TexelFormat::kRgba8Unorm:
-    case ast::TexelFormat::kRgba8Snorm:
-    case ast::TexelFormat::kRgba16Float:
-    case ast::TexelFormat::kR32Float:
-    case ast::TexelFormat::kRg32Float:
-    case ast::TexelFormat::kRgba32Float:
-      return "float4";
-    case ast::TexelFormat::kRgba8Uint:
-    case ast::TexelFormat::kRgba16Uint:
-    case ast::TexelFormat::kR32Uint:
-    case ast::TexelFormat::kRg32Uint:
-    case ast::TexelFormat::kRgba32Uint:
-      return "uint4";
-    case ast::TexelFormat::kRgba8Sint:
-    case ast::TexelFormat::kRgba16Sint:
-    case ast::TexelFormat::kR32Sint:
-    case ast::TexelFormat::kRg32Sint:
-    case ast::TexelFormat::kRgba32Sint:
-      return "int4";
-    default:
-      return nullptr;
-  }
+    switch (image_format) {
+        case ast::TexelFormat::kRgba8Unorm:
+        case ast::TexelFormat::kRgba8Snorm:
+        case ast::TexelFormat::kRgba16Float:
+        case ast::TexelFormat::kR32Float:
+        case ast::TexelFormat::kRg32Float:
+        case ast::TexelFormat::kRgba32Float:
+            return "float4";
+        case ast::TexelFormat::kRgba8Uint:
+        case ast::TexelFormat::kRgba16Uint:
+        case ast::TexelFormat::kR32Uint:
+        case ast::TexelFormat::kRg32Uint:
+        case ast::TexelFormat::kRgba32Uint:
+            return "uint4";
+        case ast::TexelFormat::kRgba8Sint:
+        case ast::TexelFormat::kRgba16Sint:
+        case ast::TexelFormat::kR32Sint:
+        case ast::TexelFormat::kRg32Sint:
+        case ast::TexelFormat::kRgba32Sint:
+            return "int4";
+        default:
+            return nullptr;
+    }
 }
 
 // Helper for writing " : register(RX, spaceY)", where R is the register, X is
 // the binding point binding value, and Y is the binding point group value.
 struct RegisterAndSpace {
-  RegisterAndSpace(char r, ast::VariableBindingPoint bp)
-      : reg(r), binding_point(bp) {}
+    RegisterAndSpace(char r, ast::VariableBindingPoint bp) : reg(r), binding_point(bp) {}
 
-  const char reg;
-  ast::VariableBindingPoint const binding_point;
+    const char reg;
+    ast::VariableBindingPoint const binding_point;
 };
 
 std::ostream& operator<<(std::ostream& s, const RegisterAndSpace& rs) {
-  s << " : register(" << rs.reg << rs.binding_point.binding->value << ", space"
-    << rs.binding_point.group->value << ")";
-  return s;
+    s << " : register(" << rs.reg << rs.binding_point.binding->value << ", space"
+      << rs.binding_point.group->value << ")";
+    return s;
 }
 
 const char* LoopAttribute() {
-  // Force loops not to be unrolled to work around FXC compilation issues when
-  // it attempts and fails to unroll loops when it contains gradient operations.
-  // https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-while
-  return "[loop] ";
+    // Force loops not to be unrolled to work around FXC compilation issues when
+    // it attempts and fails to unroll loops when it contains gradient operations.
+    // https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-while
+    return "[loop] ";
 }
 
 }  // namespace
@@ -135,105 +136,101 @@
 SanitizedResult::SanitizedResult(SanitizedResult&&) = default;
 
 SanitizedResult Sanitize(const Program* in, const Options& options) {
-  transform::Manager manager;
-  transform::DataMap data;
+    transform::Manager manager;
+    transform::DataMap data;
 
-  {  // Builtin polyfills
-    transform::BuiltinPolyfill::Builtins polyfills;
-    // TODO(crbug.com/tint/1449): Some of these can map to HLSL's `firstbitlow`
-    // and `firstbithigh`.
-    polyfills.count_leading_zeros = true;
-    polyfills.count_trailing_zeros = true;
-    polyfills.extract_bits = transform::BuiltinPolyfill::Level::kFull;
-    polyfills.first_leading_bit = true;
-    polyfills.first_trailing_bit = true;
-    polyfills.insert_bits = transform::BuiltinPolyfill::Level::kFull;
-    data.Add<transform::BuiltinPolyfill::Config>(polyfills);
-    manager.Add<transform::BuiltinPolyfill>();
-  }
+    {  // Builtin polyfills
+        transform::BuiltinPolyfill::Builtins polyfills;
+        // TODO(crbug.com/tint/1449): Some of these can map to HLSL's `firstbitlow`
+        // and `firstbithigh`.
+        polyfills.count_leading_zeros = true;
+        polyfills.count_trailing_zeros = true;
+        polyfills.extract_bits = transform::BuiltinPolyfill::Level::kFull;
+        polyfills.first_leading_bit = true;
+        polyfills.first_trailing_bit = true;
+        polyfills.insert_bits = transform::BuiltinPolyfill::Level::kFull;
+        data.Add<transform::BuiltinPolyfill::Config>(polyfills);
+        manager.Add<transform::BuiltinPolyfill>();
+    }
 
-  // Build the config for the internal ArrayLengthFromUniform transform.
-  auto& array_length_from_uniform = options.array_length_from_uniform;
-  transform::ArrayLengthFromUniform::Config array_length_from_uniform_cfg(
-      array_length_from_uniform.ubo_binding);
-  array_length_from_uniform_cfg.bindpoint_to_size_index =
-      array_length_from_uniform.bindpoint_to_size_index;
+    // Build the config for the internal ArrayLengthFromUniform transform.
+    auto& array_length_from_uniform = options.array_length_from_uniform;
+    transform::ArrayLengthFromUniform::Config array_length_from_uniform_cfg(
+        array_length_from_uniform.ubo_binding);
+    array_length_from_uniform_cfg.bindpoint_to_size_index =
+        array_length_from_uniform.bindpoint_to_size_index;
 
-  if (options.generate_external_texture_bindings) {
-    auto new_bindings_map = GenerateExternalTextureBindings(in);
-    data.Add<transform::MultiplanarExternalTexture::NewBindingPoints>(
-        new_bindings_map);
-  }
-  manager.Add<transform::MultiplanarExternalTexture>();
+    if (options.generate_external_texture_bindings) {
+        auto new_bindings_map = GenerateExternalTextureBindings(in);
+        data.Add<transform::MultiplanarExternalTexture::NewBindingPoints>(new_bindings_map);
+    }
+    manager.Add<transform::MultiplanarExternalTexture>();
 
-  manager.Add<transform::Unshadow>();
+    manager.Add<transform::Unshadow>();
 
-  // LocalizeStructArrayAssignment must come after:
-  // * SimplifyPointers, because it assumes assignment to arrays in structs are
-  // done directly, not indirectly.
-  // TODO(crbug.com/tint/1340): See if we can get rid of the duplicate
-  // SimplifyPointers transform. Can't do it right now because
-  // LocalizeStructArrayAssignment introduces pointers.
-  manager.Add<transform::SimplifyPointers>();
-  manager.Add<transform::LocalizeStructArrayAssignment>();
+    // LocalizeStructArrayAssignment must come after:
+    // * SimplifyPointers, because it assumes assignment to arrays in structs are
+    // done directly, not indirectly.
+    // TODO(crbug.com/tint/1340): See if we can get rid of the duplicate
+    // SimplifyPointers transform. Can't do it right now because
+    // LocalizeStructArrayAssignment introduces pointers.
+    manager.Add<transform::SimplifyPointers>();
+    manager.Add<transform::LocalizeStructArrayAssignment>();
 
-  // Attempt to convert `loop`s into for-loops. This is to try and massage the
-  // output into something that will not cause FXC to choke or misbehave.
-  manager.Add<transform::FoldTrivialSingleUseLets>();
-  manager.Add<transform::LoopToForLoop>();
+    // Attempt to convert `loop`s into for-loops. This is to try and massage the
+    // output into something that will not cause FXC to choke or misbehave.
+    manager.Add<transform::FoldTrivialSingleUseLets>();
+    manager.Add<transform::LoopToForLoop>();
 
-  if (!options.disable_workgroup_init) {
-    // ZeroInitWorkgroupMemory must come before CanonicalizeEntryPointIO as
-    // ZeroInitWorkgroupMemory may inject new builtin parameters.
-    manager.Add<transform::ZeroInitWorkgroupMemory>();
-  }
-  manager.Add<transform::CanonicalizeEntryPointIO>();
-  // NumWorkgroupsFromUniform must come after CanonicalizeEntryPointIO, as it
-  // assumes that num_workgroups builtins only appear as struct members and are
-  // only accessed directly via member accessors.
-  manager.Add<transform::NumWorkgroupsFromUniform>();
-  manager.Add<transform::ExpandCompoundAssignment>();
-  manager.Add<transform::PromoteSideEffectsToDecl>();
-  manager.Add<transform::UnwindDiscardFunctions>();
-  manager.Add<transform::SimplifyPointers>();
-  manager.Add<transform::RemovePhonies>();
-  // ArrayLengthFromUniform must come after InlinePointerLets and Simplify, as
-  // it assumes that the form of the array length argument is &var.array.
-  manager.Add<transform::ArrayLengthFromUniform>();
-  data.Add<transform::ArrayLengthFromUniform::Config>(
-      std::move(array_length_from_uniform_cfg));
-  // DecomposeMemoryAccess must come after:
-  // * InlinePointerLets, as we cannot take the address of calls to
-  //   DecomposeMemoryAccess::Intrinsic.
-  // * Simplify, as we need to fold away the address-of and dereferences of
-  // `*(&(intrinsic_load()))` expressions.
-  // * RemovePhonies, as phonies can be assigned a pointer to a
-  //   non-constructible buffer, or dynamic array, which DMA cannot cope with.
-  manager.Add<transform::DecomposeMemoryAccess>();
-  // CalculateArrayLength must come after DecomposeMemoryAccess, as
-  // DecomposeMemoryAccess special-cases the arrayLength() intrinsic, which
-  // will be transformed by CalculateArrayLength
-  manager.Add<transform::CalculateArrayLength>();
-  manager.Add<transform::PromoteInitializersToConstVar>();
+    if (!options.disable_workgroup_init) {
+        // ZeroInitWorkgroupMemory must come before CanonicalizeEntryPointIO as
+        // ZeroInitWorkgroupMemory may inject new builtin parameters.
+        manager.Add<transform::ZeroInitWorkgroupMemory>();
+    }
+    manager.Add<transform::CanonicalizeEntryPointIO>();
+    // NumWorkgroupsFromUniform must come after CanonicalizeEntryPointIO, as it
+    // assumes that num_workgroups builtins only appear as struct members and are
+    // only accessed directly via member accessors.
+    manager.Add<transform::NumWorkgroupsFromUniform>();
+    manager.Add<transform::ExpandCompoundAssignment>();
+    manager.Add<transform::PromoteSideEffectsToDecl>();
+    manager.Add<transform::UnwindDiscardFunctions>();
+    manager.Add<transform::SimplifyPointers>();
+    manager.Add<transform::RemovePhonies>();
+    // ArrayLengthFromUniform must come after InlinePointerLets and Simplify, as
+    // it assumes that the form of the array length argument is &var.array.
+    manager.Add<transform::ArrayLengthFromUniform>();
+    data.Add<transform::ArrayLengthFromUniform::Config>(std::move(array_length_from_uniform_cfg));
+    // DecomposeMemoryAccess must come after:
+    // * InlinePointerLets, as we cannot take the address of calls to
+    //   DecomposeMemoryAccess::Intrinsic.
+    // * Simplify, as we need to fold away the address-of and dereferences of
+    // `*(&(intrinsic_load()))` expressions.
+    // * RemovePhonies, as phonies can be assigned a pointer to a
+    //   non-constructible buffer, or dynamic array, which DMA cannot cope with.
+    manager.Add<transform::DecomposeMemoryAccess>();
+    // CalculateArrayLength must come after DecomposeMemoryAccess, as
+    // DecomposeMemoryAccess special-cases the arrayLength() intrinsic, which
+    // will be transformed by CalculateArrayLength
+    manager.Add<transform::CalculateArrayLength>();
+    manager.Add<transform::PromoteInitializersToConstVar>();
 
-  manager.Add<transform::RemoveContinueInSwitch>();
+    manager.Add<transform::RemoveContinueInSwitch>();
 
-  manager.Add<transform::AddEmptyEntryPoint>();
+    manager.Add<transform::AddEmptyEntryPoint>();
 
-  data.Add<transform::CanonicalizeEntryPointIO::Config>(
-      transform::CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
-  data.Add<transform::NumWorkgroupsFromUniform::Config>(
-      options.root_constant_binding_point);
+    data.Add<transform::CanonicalizeEntryPointIO::Config>(
+        transform::CanonicalizeEntryPointIO::ShaderStyle::kHlsl);
+    data.Add<transform::NumWorkgroupsFromUniform::Config>(options.root_constant_binding_point);
 
-  auto out = manager.Run(in, data);
+    auto out = manager.Run(in, data);
 
-  SanitizedResult result;
-  result.program = std::move(out.program);
-  if (auto* res = out.data.Get<transform::ArrayLengthFromUniform::Result>()) {
-    result.used_array_length_from_uniform_indices =
-        std::move(res->used_size_indices);
-  }
-  return result;
+    SanitizedResult result;
+    result.program = std::move(out.program);
+    if (auto* res = out.data.Get<transform::ArrayLengthFromUniform::Result>()) {
+        result.used_array_length_from_uniform_indices = std::move(res->used_size_indices);
+    }
+    return result;
 }
 
 GeneratorImpl::GeneratorImpl(const Program* program) : TextGenerator(program) {}
@@ -241,3278 +238,3182 @@
 GeneratorImpl::~GeneratorImpl() = default;
 
 bool GeneratorImpl::Generate() {
-  const TypeInfo* last_kind = nullptr;
-  size_t last_padding_line = 0;
+    const TypeInfo* last_kind = nullptr;
+    size_t last_padding_line = 0;
 
-  auto* mod = builder_.Sem().Module();
-  for (auto* decl : mod->DependencyOrderedDeclarations()) {
-    if (decl->Is<ast::Alias>()) {
-      continue;  // Ignore aliases.
-    }
-
-    // Emit a new line between declarations if the type of declaration has
-    // changed, or we're about to emit a function
-    auto* kind = &decl->TypeInfo();
-    if (current_buffer_->lines.size() != last_padding_line) {
-      if (last_kind && (last_kind != kind || decl->Is<ast::Function>())) {
-        line();
-        last_padding_line = current_buffer_->lines.size();
-      }
-    }
-    last_kind = kind;
-
-    bool ok = Switch(
-        decl,
-        [&](const ast::Variable* global) {  //
-          return EmitGlobalVariable(global);
-        },
-        [&](const ast::Struct* str) {
-          auto* ty = builder_.Sem().Get(str);
-          auto storage_class_uses = ty->StorageClassUsage();
-          if (storage_class_uses.size() !=
-              (storage_class_uses.count(ast::StorageClass::kStorage) +
-               storage_class_uses.count(ast::StorageClass::kUniform))) {
-            // The structure is used as something other than a storage buffer or
-            // uniform buffer, so it needs to be emitted.
-            // Storage buffer are read and written to via a ByteAddressBuffer
-            // instead of true structure.
-            // Structures used as uniform buffer are read from an array of
-            // vectors instead of true structure.
-            return EmitStructType(current_buffer_, ty);
-          }
-          return true;
-        },
-        [&](const ast::Function* func) {
-          if (func->IsEntryPoint()) {
-            return EmitEntryPointFunction(func);
-          }
-          return EmitFunction(func);
-        },
-        [&](Default) {
-          TINT_ICE(Writer, diagnostics_)
-              << "unhandled module-scope declaration: "
-              << decl->TypeInfo().name;
-          return false;
-        });
-
-    if (!ok) {
-      return false;
-    }
-  }
-
-  if (!helpers_.lines.empty()) {
-    current_buffer_->Insert(helpers_, 0, 0);
-  }
-
-  return true;
-}
-
-bool GeneratorImpl::EmitDynamicVectorAssignment(
-    const ast::AssignmentStatement* stmt,
-    const sem::Vector* vec) {
-  auto name =
-      utils::GetOrCreate(dynamic_vector_write_, vec, [&]() -> std::string {
-        std::string fn;
-        {
-          std::ostringstream ss;
-          if (!EmitType(ss, vec, tint::ast::StorageClass::kInvalid,
-                        ast::Access::kUndefined, "")) {
-            return "";
-          }
-          fn = UniqueIdentifier("set_" + ss.str());
+    auto* mod = builder_.Sem().Module();
+    for (auto* decl : mod->DependencyOrderedDeclarations()) {
+        if (decl->Is<ast::Alias>()) {
+            continue;  // Ignore aliases.
         }
-        {
-          auto out = line(&helpers_);
-          out << "void " << fn << "(inout ";
-          if (!EmitTypeAndName(out, vec, ast::StorageClass::kInvalid,
-                               ast::Access::kUndefined, "vec")) {
-            return "";
-          }
-          out << ", int idx, ";
-          if (!EmitTypeAndName(out, vec->type(), ast::StorageClass::kInvalid,
-                               ast::Access::kUndefined, "val")) {
-            return "";
-          }
-          out << ") {";
-        }
-        {
-          ScopedIndent si(&helpers_);
-          auto out = line(&helpers_);
-          switch (vec->Width()) {
-            case 2:
-              out << "vec = (idx.xx == int2(0, 1)) ? val.xx : vec;";
-              break;
-            case 3:
-              out << "vec = (idx.xxx == int3(0, 1, 2)) ? val.xxx : vec;";
-              break;
-            case 4:
-              out << "vec = (idx.xxxx == int4(0, 1, 2, 3)) ? val.xxxx : vec;";
-              break;
-            default:
-              TINT_UNREACHABLE(Writer, builder_.Diagnostics())
-                  << "invalid vector size " << vec->Width();
-              break;
-          }
-        }
-        line(&helpers_) << "}";
-        line(&helpers_);
-        return fn;
-      });
 
-  if (name.empty()) {
-    return false;
-  }
-
-  auto* ast_access_expr = stmt->lhs->As<ast::IndexAccessorExpression>();
-
-  auto out = line();
-  out << name << "(";
-  if (!EmitExpression(out, ast_access_expr->object)) {
-    return false;
-  }
-  out << ", ";
-  if (!EmitExpression(out, ast_access_expr->index)) {
-    return false;
-  }
-  out << ", ";
-  if (!EmitExpression(out, stmt->rhs)) {
-    return false;
-  }
-  out << ");";
-
-  return true;
-}
-
-bool GeneratorImpl::EmitDynamicMatrixVectorAssignment(
-    const ast::AssignmentStatement* stmt,
-    const sem::Matrix* mat) {
-  auto name = utils::GetOrCreate(
-      dynamic_matrix_vector_write_, mat, [&]() -> std::string {
-        std::string fn;
-        {
-          std::ostringstream ss;
-          if (!EmitType(ss, mat, tint::ast::StorageClass::kInvalid,
-                        ast::Access::kUndefined, "")) {
-            return "";
-          }
-          fn = UniqueIdentifier("set_vector_" + ss.str());
-        }
-        {
-          auto out = line(&helpers_);
-          out << "void " << fn << "(inout ";
-          if (!EmitTypeAndName(out, mat, ast::StorageClass::kInvalid,
-                               ast::Access::kUndefined, "mat")) {
-            return "";
-          }
-          out << ", int col, ";
-          if (!EmitTypeAndName(out, mat->ColumnType(),
-                               ast::StorageClass::kInvalid,
-                               ast::Access::kUndefined, "val")) {
-            return "";
-          }
-          out << ") {";
-        }
-        {
-          ScopedIndent si(&helpers_);
-          line(&helpers_) << "switch (col) {";
-          {
-            ScopedIndent si2(&helpers_);
-            for (uint32_t i = 0; i < mat->columns(); ++i) {
-              line(&helpers_)
-                  << "case " << i << ": mat[" << i << "] = val; break;";
+        // Emit a new line between declarations if the type of declaration has
+        // changed, or we're about to emit a function
+        auto* kind = &decl->TypeInfo();
+        if (current_buffer_->lines.size() != last_padding_line) {
+            if (last_kind && (last_kind != kind || decl->Is<ast::Function>())) {
+                line();
+                last_padding_line = current_buffer_->lines.size();
             }
-          }
-          line(&helpers_) << "}";
         }
-        line(&helpers_) << "}";
-        line(&helpers_);
-        return fn;
-      });
+        last_kind = kind;
 
-  if (name.empty()) {
-    return false;
-  }
-
-  auto* ast_access_expr = stmt->lhs->As<ast::IndexAccessorExpression>();
-
-  auto out = line();
-  out << name << "(";
-  if (!EmitExpression(out, ast_access_expr->object)) {
-    return false;
-  }
-  out << ", ";
-  if (!EmitExpression(out, ast_access_expr->index)) {
-    return false;
-  }
-  out << ", ";
-  if (!EmitExpression(out, stmt->rhs)) {
-    return false;
-  }
-  out << ");";
-
-  return true;
-}
-
-bool GeneratorImpl::EmitDynamicMatrixScalarAssignment(
-    const ast::AssignmentStatement* stmt,
-    const sem::Matrix* mat) {
-  auto* lhs_col_access = stmt->lhs->As<ast::IndexAccessorExpression>();
-  auto* lhs_row_access =
-      lhs_col_access->object->As<ast::IndexAccessorExpression>();
-
-  auto name = utils::GetOrCreate(
-      dynamic_matrix_scalar_write_, mat, [&]() -> std::string {
-        std::string fn;
-        {
-          std::ostringstream ss;
-          if (!EmitType(ss, mat, tint::ast::StorageClass::kInvalid,
-                        ast::Access::kUndefined, "")) {
-            return "";
-          }
-          fn = UniqueIdentifier("set_scalar_" + ss.str());
-        }
-        {
-          auto out = line(&helpers_);
-          out << "void " << fn << "(inout ";
-          if (!EmitTypeAndName(out, mat, ast::StorageClass::kInvalid,
-                               ast::Access::kUndefined, "mat")) {
-            return "";
-          }
-          out << ", int col, int row, ";
-          if (!EmitTypeAndName(out, mat->type(), ast::StorageClass::kInvalid,
-                               ast::Access::kUndefined, "val")) {
-            return "";
-          }
-          out << ") {";
-        }
-        {
-          ScopedIndent si(&helpers_);
-          line(&helpers_) << "switch (col) {";
-          {
-            ScopedIndent si2(&helpers_);
-            auto* vec =
-                TypeOf(lhs_row_access->object)->UnwrapRef()->As<sem::Vector>();
-            for (uint32_t i = 0; i < mat->columns(); ++i) {
-              line(&helpers_) << "case " << i << ":";
-              {
-                auto vec_name = "mat[" + std::to_string(i) + "]";
-                ScopedIndent si3(&helpers_);
-                {
-                  auto out = line(&helpers_);
-                  switch (mat->rows()) {
-                    case 2:
-                      out << vec_name
-                          << " = (row.xx == int2(0, 1)) ? val.xx : " << vec_name
-                          << ";";
-                      break;
-                    case 3:
-                      out << vec_name
-                          << " = (row.xxx == int3(0, 1, 2)) ? val.xxx : "
-                          << vec_name << ";";
-                      break;
-                    case 4:
-                      out << vec_name
-                          << " = (row.xxxx == int4(0, 1, 2, 3)) ? val.xxxx : "
-                          << vec_name << ";";
-                      break;
-                    default:
-                      TINT_UNREACHABLE(Writer, builder_.Diagnostics())
-                          << "invalid vector size " << vec->Width();
-                      break;
-                  }
+        bool ok = Switch(
+            decl,
+            [&](const ast::Variable* global) {  //
+                return EmitGlobalVariable(global);
+            },
+            [&](const ast::Struct* str) {
+                auto* ty = builder_.Sem().Get(str);
+                auto storage_class_uses = ty->StorageClassUsage();
+                if (storage_class_uses.size() !=
+                    (storage_class_uses.count(ast::StorageClass::kStorage) +
+                     storage_class_uses.count(ast::StorageClass::kUniform))) {
+                    // The structure is used as something other than a storage buffer or
+                    // uniform buffer, so it needs to be emitted.
+                    // Storage buffer are read and written to via a ByteAddressBuffer
+                    // instead of true structure.
+                    // Structures used as uniform buffer are read from an array of
+                    // vectors instead of true structure.
+                    return EmitStructType(current_buffer_, ty);
                 }
-                line(&helpers_) << "break;";
-              }
+                return true;
+            },
+            [&](const ast::Function* func) {
+                if (func->IsEntryPoint()) {
+                    return EmitEntryPointFunction(func);
+                }
+                return EmitFunction(func);
+            },
+            [&](const ast::Enable*) {
+                // Currently we don't have to do anything for using a extension in
+                // HLSL
+                return true;
+            },
+            [&](Default) {
+                TINT_ICE(Writer, diagnostics_)
+                    << "unhandled module-scope declaration: " << decl->TypeInfo().name;
+                return false;
+            });
+
+        if (!ok) {
+            return false;
+        }
+    }
+
+    if (!helpers_.lines.empty()) {
+        current_buffer_->Insert(helpers_, 0, 0);
+    }
+
+    return true;
+}
+
+bool GeneratorImpl::EmitDynamicVectorAssignment(const ast::AssignmentStatement* stmt,
+                                                const sem::Vector* vec) {
+    auto name = utils::GetOrCreate(dynamic_vector_write_, vec, [&]() -> std::string {
+        std::string fn;
+        {
+            std::ostringstream ss;
+            if (!EmitType(ss, vec, tint::ast::StorageClass::kInvalid, ast::Access::kUndefined,
+                          "")) {
+                return "";
             }
-          }
-          line(&helpers_) << "}";
+            fn = UniqueIdentifier("set_" + ss.str());
+        }
+        {
+            auto out = line(&helpers_);
+            out << "void " << fn << "(inout ";
+            if (!EmitTypeAndName(out, vec, ast::StorageClass::kInvalid, ast::Access::kUndefined,
+                                 "vec")) {
+                return "";
+            }
+            out << ", int idx, ";
+            if (!EmitTypeAndName(out, vec->type(), ast::StorageClass::kInvalid,
+                                 ast::Access::kUndefined, "val")) {
+                return "";
+            }
+            out << ") {";
+        }
+        {
+            ScopedIndent si(&helpers_);
+            auto out = line(&helpers_);
+            switch (vec->Width()) {
+                case 2:
+                    out << "vec = (idx.xx == int2(0, 1)) ? val.xx : vec;";
+                    break;
+                case 3:
+                    out << "vec = (idx.xxx == int3(0, 1, 2)) ? val.xxx : vec;";
+                    break;
+                case 4:
+                    out << "vec = (idx.xxxx == int4(0, 1, 2, 3)) ? val.xxxx : vec;";
+                    break;
+                default:
+                    TINT_UNREACHABLE(Writer, builder_.Diagnostics())
+                        << "invalid vector size " << vec->Width();
+                    break;
+            }
         }
         line(&helpers_) << "}";
         line(&helpers_);
         return fn;
-      });
+    });
 
-  if (name.empty()) {
-    return false;
-  }
-
-  auto out = line();
-  out << name << "(";
-  if (!EmitExpression(out, lhs_row_access->object)) {
-    return false;
-  }
-  out << ", ";
-  if (!EmitExpression(out, lhs_col_access->index)) {
-    return false;
-  }
-  out << ", ";
-  if (!EmitExpression(out, lhs_row_access->index)) {
-    return false;
-  }
-  out << ", ";
-  if (!EmitExpression(out, stmt->rhs)) {
-    return false;
-  }
-  out << ");";
-
-  return true;
-}
-
-bool GeneratorImpl::EmitIndexAccessor(
-    std::ostream& out,
-    const ast::IndexAccessorExpression* expr) {
-  if (!EmitExpression(out, expr->object)) {
-    return false;
-  }
-  out << "[";
-
-  if (!EmitExpression(out, expr->index)) {
-    return false;
-  }
-  out << "]";
-
-  return true;
-}
-
-bool GeneratorImpl::EmitBitcast(std::ostream& out,
-                                const ast::BitcastExpression* expr) {
-  auto* type = TypeOf(expr);
-  if (auto* vec = type->UnwrapRef()->As<sem::Vector>()) {
-    type = vec->type();
-  }
-
-  if (!type->is_integer_scalar() && !type->is_float_scalar()) {
-    diagnostics_.add_error(diag::System::Writer,
-                           "Unable to do bitcast to type " +
-                               type->FriendlyName(builder_.Symbols()));
-    return false;
-  }
-
-  out << "as";
-  if (!EmitType(out, type, ast::StorageClass::kNone, ast::Access::kReadWrite,
-                "")) {
-    return false;
-  }
-  out << "(";
-  if (!EmitExpression(out, expr->expr)) {
-    return false;
-  }
-  out << ")";
-  return true;
-}
-
-bool GeneratorImpl::EmitAssign(const ast::AssignmentStatement* stmt) {
-  if (auto* lhs_access = stmt->lhs->As<ast::IndexAccessorExpression>()) {
-    // BUG(crbug.com/tint/1333): work around assignment of scalar to matrices
-    // with at least one dynamic index
-    if (auto* lhs_sub_access =
-            lhs_access->object->As<ast::IndexAccessorExpression>()) {
-      if (auto* mat =
-              TypeOf(lhs_sub_access->object)->UnwrapRef()->As<sem::Matrix>()) {
-        auto* rhs_col_idx_sem = builder_.Sem().Get(lhs_access->index);
-        auto* rhs_row_idx_sem = builder_.Sem().Get(lhs_sub_access->index);
-        if (!rhs_col_idx_sem->ConstantValue().IsValid() ||
-            !rhs_row_idx_sem->ConstantValue().IsValid()) {
-          return EmitDynamicMatrixScalarAssignment(stmt, mat);
-        }
-      }
-    }
-    // BUG(crbug.com/tint/1333): work around assignment of vector to matrices
-    // with dynamic indices
-    const auto* lhs_access_type = TypeOf(lhs_access->object)->UnwrapRef();
-    if (auto* mat = lhs_access_type->As<sem::Matrix>()) {
-      auto* lhs_index_sem = builder_.Sem().Get(lhs_access->index);
-      if (!lhs_index_sem->ConstantValue().IsValid()) {
-        return EmitDynamicMatrixVectorAssignment(stmt, mat);
-      }
-    }
-    // BUG(crbug.com/tint/534): work around assignment to vectors with dynamic
-    // indices
-    if (auto* vec = lhs_access_type->As<sem::Vector>()) {
-      auto* rhs_sem = builder_.Sem().Get(lhs_access->index);
-      if (!rhs_sem->ConstantValue().IsValid()) {
-        return EmitDynamicVectorAssignment(stmt, vec);
-      }
-    }
-  }
-
-  auto out = line();
-  if (!EmitExpression(out, stmt->lhs)) {
-    return false;
-  }
-  out << " = ";
-  if (!EmitExpression(out, stmt->rhs)) {
-    return false;
-  }
-  out << ";";
-  return true;
-}
-
-bool GeneratorImpl::EmitExpressionOrOneIfZero(std::ostream& out,
-                                              const ast::Expression* expr) {
-  // For constants, replace literal 0 with 1.
-  sem::Constant::Scalars elems;
-  if (const auto& val = builder_.Sem().Get(expr)->ConstantValue()) {
-    if (!val.AnyZero()) {
-      return EmitExpression(out, expr);
-    }
-
-    if (val.Type()->IsAnyOf<sem::I32, sem::U32>()) {
-      return EmitValue(out, val.Type(), 1);
-    }
-
-    if (auto* vec = val.Type()->As<sem::Vector>()) {
-      auto* elem_ty = vec->type();
-
-      if (!EmitType(out, val.Type(), ast::StorageClass::kNone,
-                    ast::Access::kUndefined, "")) {
+    if (name.empty()) {
         return false;
-      }
-
-      out << "(";
-      for (size_t i = 0; i < val.Elements().size(); ++i) {
-        if (i != 0) {
-          out << ", ";
-        }
-        if (!val.WithScalarAt(i, [&](auto&& s) -> bool {
-              // Use std::equal_to to work around -Wfloat-equal warnings
-              auto equals_to =
-                  std::equal_to<std::remove_reference_t<decltype(s)>>{};
-
-              bool is_zero = equals_to(s, 0);
-              return EmitValue(out, elem_ty, is_zero ? 1 : static_cast<int>(s));
-            })) {
-          return false;
-        }
-      }
-      out << ")";
-      return true;
     }
 
-    TINT_ICE(Writer, diagnostics_)
-        << "EmitExpressionOrOneIfZero expects integer scalar or vector";
-    return false;
-  }
+    auto* ast_access_expr = stmt->lhs->As<ast::IndexAccessorExpression>();
 
-  auto* ty = TypeOf(expr)->UnwrapRef();
+    auto out = line();
+    out << name << "(";
+    if (!EmitExpression(out, ast_access_expr->object)) {
+        return false;
+    }
+    out << ", ";
+    if (!EmitExpression(out, ast_access_expr->index)) {
+        return false;
+    }
+    out << ", ";
+    if (!EmitExpression(out, stmt->rhs)) {
+        return false;
+    }
+    out << ");";
 
-  // For non-constants, we need to emit runtime code to check if the value is 0,
-  // and return 1 in that case.
-  std::string zero;
-  {
-    std::ostringstream ss;
-    EmitValue(ss, ty, 0);
-    zero = ss.str();
-  }
-  std::string one;
-  {
-    std::ostringstream ss;
-    EmitValue(ss, ty, 1);
-    one = ss.str();
-  }
+    return true;
+}
 
-  // For identifiers, no need for a function call as it's fine to evaluate
-  // `expr` more than once.
-  if (expr->Is<ast::IdentifierExpression>()) {
+bool GeneratorImpl::EmitDynamicMatrixVectorAssignment(const ast::AssignmentStatement* stmt,
+                                                      const sem::Matrix* mat) {
+    auto name = utils::GetOrCreate(dynamic_matrix_vector_write_, mat, [&]() -> std::string {
+        std::string fn;
+        {
+            std::ostringstream ss;
+            if (!EmitType(ss, mat, tint::ast::StorageClass::kInvalid, ast::Access::kUndefined,
+                          "")) {
+                return "";
+            }
+            fn = UniqueIdentifier("set_vector_" + ss.str());
+        }
+        {
+            auto out = line(&helpers_);
+            out << "void " << fn << "(inout ";
+            if (!EmitTypeAndName(out, mat, ast::StorageClass::kInvalid, ast::Access::kUndefined,
+                                 "mat")) {
+                return "";
+            }
+            out << ", int col, ";
+            if (!EmitTypeAndName(out, mat->ColumnType(), ast::StorageClass::kInvalid,
+                                 ast::Access::kUndefined, "val")) {
+                return "";
+            }
+            out << ") {";
+        }
+        {
+            ScopedIndent si(&helpers_);
+            line(&helpers_) << "switch (col) {";
+            {
+                ScopedIndent si2(&helpers_);
+                for (uint32_t i = 0; i < mat->columns(); ++i) {
+                    line(&helpers_) << "case " << i << ": mat[" << i << "] = val; break;";
+                }
+            }
+            line(&helpers_) << "}";
+        }
+        line(&helpers_) << "}";
+        line(&helpers_);
+        return fn;
+    });
+
+    if (name.empty()) {
+        return false;
+    }
+
+    auto* ast_access_expr = stmt->lhs->As<ast::IndexAccessorExpression>();
+
+    auto out = line();
+    out << name << "(";
+    if (!EmitExpression(out, ast_access_expr->object)) {
+        return false;
+    }
+    out << ", ";
+    if (!EmitExpression(out, ast_access_expr->index)) {
+        return false;
+    }
+    out << ", ";
+    if (!EmitExpression(out, stmt->rhs)) {
+        return false;
+    }
+    out << ");";
+
+    return true;
+}
+
+bool GeneratorImpl::EmitDynamicMatrixScalarAssignment(const ast::AssignmentStatement* stmt,
+                                                      const sem::Matrix* mat) {
+    auto* lhs_col_access = stmt->lhs->As<ast::IndexAccessorExpression>();
+    auto* lhs_row_access = lhs_col_access->object->As<ast::IndexAccessorExpression>();
+
+    auto name = utils::GetOrCreate(dynamic_matrix_scalar_write_, mat, [&]() -> std::string {
+        std::string fn;
+        {
+            std::ostringstream ss;
+            if (!EmitType(ss, mat, tint::ast::StorageClass::kInvalid, ast::Access::kUndefined,
+                          "")) {
+                return "";
+            }
+            fn = UniqueIdentifier("set_scalar_" + ss.str());
+        }
+        {
+            auto out = line(&helpers_);
+            out << "void " << fn << "(inout ";
+            if (!EmitTypeAndName(out, mat, ast::StorageClass::kInvalid, ast::Access::kUndefined,
+                                 "mat")) {
+                return "";
+            }
+            out << ", int col, int row, ";
+            if (!EmitTypeAndName(out, mat->type(), ast::StorageClass::kInvalid,
+                                 ast::Access::kUndefined, "val")) {
+                return "";
+            }
+            out << ") {";
+        }
+        {
+            ScopedIndent si(&helpers_);
+            line(&helpers_) << "switch (col) {";
+            {
+                ScopedIndent si2(&helpers_);
+                auto* vec = TypeOf(lhs_row_access->object)->UnwrapRef()->As<sem::Vector>();
+                for (uint32_t i = 0; i < mat->columns(); ++i) {
+                    line(&helpers_) << "case " << i << ":";
+                    {
+                        auto vec_name = "mat[" + std::to_string(i) + "]";
+                        ScopedIndent si3(&helpers_);
+                        {
+                            auto out = line(&helpers_);
+                            switch (mat->rows()) {
+                                case 2:
+                                    out << vec_name
+                                        << " = (row.xx == int2(0, 1)) ? val.xx : " << vec_name
+                                        << ";";
+                                    break;
+                                case 3:
+                                    out << vec_name
+                                        << " = (row.xxx == int3(0, 1, 2)) ? val.xxx : " << vec_name
+                                        << ";";
+                                    break;
+                                case 4:
+                                    out << vec_name
+                                        << " = (row.xxxx == int4(0, 1, 2, 3)) ? val.xxxx : "
+                                        << vec_name << ";";
+                                    break;
+                                default:
+                                    TINT_UNREACHABLE(Writer, builder_.Diagnostics())
+                                        << "invalid vector size " << vec->Width();
+                                    break;
+                            }
+                        }
+                        line(&helpers_) << "break;";
+                    }
+                }
+            }
+            line(&helpers_) << "}";
+        }
+        line(&helpers_) << "}";
+        line(&helpers_);
+        return fn;
+    });
+
+    if (name.empty()) {
+        return false;
+    }
+
+    auto out = line();
+    out << name << "(";
+    if (!EmitExpression(out, lhs_row_access->object)) {
+        return false;
+    }
+    out << ", ";
+    if (!EmitExpression(out, lhs_col_access->index)) {
+        return false;
+    }
+    out << ", ";
+    if (!EmitExpression(out, lhs_row_access->index)) {
+        return false;
+    }
+    out << ", ";
+    if (!EmitExpression(out, stmt->rhs)) {
+        return false;
+    }
+    out << ");";
+
+    return true;
+}
+
+bool GeneratorImpl::EmitIndexAccessor(std::ostream& out, const ast::IndexAccessorExpression* expr) {
+    if (!EmitExpression(out, expr->object)) {
+        return false;
+    }
+    out << "[";
+
+    if (!EmitExpression(out, expr->index)) {
+        return false;
+    }
+    out << "]";
+
+    return true;
+}
+
+bool GeneratorImpl::EmitBitcast(std::ostream& out, const ast::BitcastExpression* expr) {
+    auto* type = TypeOf(expr);
+    if (auto* vec = type->UnwrapRef()->As<sem::Vector>()) {
+        type = vec->type();
+    }
+
+    if (!type->is_integer_scalar() && !type->is_float_scalar()) {
+        diagnostics_.add_error(diag::System::Writer, "Unable to do bitcast to type " +
+                                                         type->FriendlyName(builder_.Symbols()));
+        return false;
+    }
+
+    out << "as";
+    if (!EmitType(out, type, ast::StorageClass::kNone, ast::Access::kReadWrite, "")) {
+        return false;
+    }
     out << "(";
-    if (!EmitExpression(out, expr)) {
-      return false;
-    }
-    out << " == " << zero << " ? " << one << " : ";
-    if (!EmitExpression(out, expr)) {
-      return false;
+    if (!EmitExpression(out, expr->expr)) {
+        return false;
     }
     out << ")";
     return true;
-  }
+}
 
-  // For non-identifier expressions, call a function to make sure `expr` is only
-  // evaluated once.
-  auto name =
-      utils::GetOrCreate(value_or_one_if_zero_, ty, [&]() -> std::string {
+bool GeneratorImpl::EmitAssign(const ast::AssignmentStatement* stmt) {
+    if (auto* lhs_access = stmt->lhs->As<ast::IndexAccessorExpression>()) {
+        // BUG(crbug.com/tint/1333): work around assignment of scalar to matrices
+        // with at least one dynamic index
+        if (auto* lhs_sub_access = lhs_access->object->As<ast::IndexAccessorExpression>()) {
+            if (auto* mat = TypeOf(lhs_sub_access->object)->UnwrapRef()->As<sem::Matrix>()) {
+                auto* rhs_col_idx_sem = builder_.Sem().Get(lhs_access->index);
+                auto* rhs_row_idx_sem = builder_.Sem().Get(lhs_sub_access->index);
+                if (!rhs_col_idx_sem->ConstantValue().IsValid() ||
+                    !rhs_row_idx_sem->ConstantValue().IsValid()) {
+                    return EmitDynamicMatrixScalarAssignment(stmt, mat);
+                }
+            }
+        }
+        // BUG(crbug.com/tint/1333): work around assignment of vector to matrices
+        // with dynamic indices
+        const auto* lhs_access_type = TypeOf(lhs_access->object)->UnwrapRef();
+        if (auto* mat = lhs_access_type->As<sem::Matrix>()) {
+            auto* lhs_index_sem = builder_.Sem().Get(lhs_access->index);
+            if (!lhs_index_sem->ConstantValue().IsValid()) {
+                return EmitDynamicMatrixVectorAssignment(stmt, mat);
+            }
+        }
+        // BUG(crbug.com/tint/534): work around assignment to vectors with dynamic
+        // indices
+        if (auto* vec = lhs_access_type->As<sem::Vector>()) {
+            auto* rhs_sem = builder_.Sem().Get(lhs_access->index);
+            if (!rhs_sem->ConstantValue().IsValid()) {
+                return EmitDynamicVectorAssignment(stmt, vec);
+            }
+        }
+    }
+
+    auto out = line();
+    if (!EmitExpression(out, stmt->lhs)) {
+        return false;
+    }
+    out << " = ";
+    if (!EmitExpression(out, stmt->rhs)) {
+        return false;
+    }
+    out << ";";
+    return true;
+}
+
+bool GeneratorImpl::EmitExpressionOrOneIfZero(std::ostream& out, const ast::Expression* expr) {
+    // For constants, replace literal 0 with 1.
+    sem::Constant::Scalars elems;
+    if (const auto& val = builder_.Sem().Get(expr)->ConstantValue()) {
+        if (!val.AnyZero()) {
+            return EmitExpression(out, expr);
+        }
+
+        if (val.Type()->IsAnyOf<sem::I32, sem::U32>()) {
+            return EmitValue(out, val.Type(), 1);
+        }
+
+        if (auto* vec = val.Type()->As<sem::Vector>()) {
+            auto* elem_ty = vec->type();
+
+            if (!EmitType(out, val.Type(), ast::StorageClass::kNone, ast::Access::kUndefined, "")) {
+                return false;
+            }
+
+            out << "(";
+            for (size_t i = 0; i < val.Elements().size(); ++i) {
+                if (i != 0) {
+                    out << ", ";
+                }
+                if (!val.WithScalarAt(i, [&](auto&& s) -> bool {
+                        // Use std::equal_to to work around -Wfloat-equal warnings
+                        using T = std::remove_reference_t<decltype(s)>;
+                        auto equal_to = std::equal_to<T>{};
+                        bool is_zero = equal_to(s, T(0));
+                        return EmitValue(out, elem_ty, is_zero ? 1 : static_cast<int>(s));
+                    })) {
+                    return false;
+                }
+            }
+            out << ")";
+            return true;
+        }
+
+        TINT_ICE(Writer, diagnostics_)
+            << "EmitExpressionOrOneIfZero expects integer scalar or vector";
+        return false;
+    }
+
+    auto* ty = TypeOf(expr)->UnwrapRef();
+
+    // For non-constants, we need to emit runtime code to check if the value is 0,
+    // and return 1 in that case.
+    std::string zero;
+    {
+        std::ostringstream ss;
+        EmitValue(ss, ty, 0);
+        zero = ss.str();
+    }
+    std::string one;
+    {
+        std::ostringstream ss;
+        EmitValue(ss, ty, 1);
+        one = ss.str();
+    }
+
+    // For identifiers, no need for a function call as it's fine to evaluate
+    // `expr` more than once.
+    if (expr->Is<ast::IdentifierExpression>()) {
+        out << "(";
+        if (!EmitExpression(out, expr)) {
+            return false;
+        }
+        out << " == " << zero << " ? " << one << " : ";
+        if (!EmitExpression(out, expr)) {
+            return false;
+        }
+        out << ")";
+        return true;
+    }
+
+    // For non-identifier expressions, call a function to make sure `expr` is only
+    // evaluated once.
+    auto name = utils::GetOrCreate(value_or_one_if_zero_, ty, [&]() -> std::string {
         // Example:
         // int4 tint_value_or_one_if_zero_int4(int4 value) {
         //   return value == 0 ? 0 : value;
         // }
         std::string ty_name;
         {
-          std::ostringstream ss;
-          if (!EmitType(ss, ty, tint::ast::StorageClass::kInvalid,
-                        ast::Access::kUndefined, "")) {
-            return "";
-          }
-          ty_name = ss.str();
+            std::ostringstream ss;
+            if (!EmitType(ss, ty, tint::ast::StorageClass::kInvalid, ast::Access::kUndefined, "")) {
+                return "";
+            }
+            ty_name = ss.str();
         }
 
         std::string fn = UniqueIdentifier("value_or_one_if_zero_" + ty_name);
-        line(&helpers_) << ty_name << " " << fn << "(" << ty_name
-                        << " value) {";
+        line(&helpers_) << ty_name << " " << fn << "(" << ty_name << " value) {";
         {
-          ScopedIndent si(&helpers_);
-          line(&helpers_) << "return value == " << zero << " ? " << one
-                          << " : value;";
+            ScopedIndent si(&helpers_);
+            line(&helpers_) << "return value == " << zero << " ? " << one << " : value;";
         }
         line(&helpers_) << "}";
         line(&helpers_);
         return fn;
-      });
+    });
 
-  if (name.empty()) {
-    return false;
-  }
-
-  out << name << "(";
-  if (!EmitExpression(out, expr)) {
-    return false;
-  }
-  out << ")";
-  return true;
-}
-
-bool GeneratorImpl::EmitBinary(std::ostream& out,
-                               const ast::BinaryExpression* expr) {
-  if (expr->op == ast::BinaryOp::kLogicalAnd ||
-      expr->op == ast::BinaryOp::kLogicalOr) {
-    auto name = UniqueIdentifier(kTempNamePrefix);
-
-    {
-      auto pre = line();
-      pre << "bool " << name << " = ";
-      if (!EmitExpression(pre, expr->lhs)) {
+    if (name.empty()) {
         return false;
-      }
-      pre << ";";
     }
 
-    if (expr->op == ast::BinaryOp::kLogicalOr) {
-      line() << "if (!" << name << ") {";
-    } else {
-      line() << "if (" << name << ") {";
-    }
-
-    {
-      ScopedIndent si(this);
-      auto pre = line();
-      pre << name << " = ";
-      if (!EmitExpression(pre, expr->rhs)) {
+    out << name << "(";
+    if (!EmitExpression(out, expr)) {
         return false;
-      }
-      pre << ";";
-    }
-
-    line() << "}";
-
-    out << "(" << name << ")";
-    return true;
-  }
-
-  auto* lhs_type = TypeOf(expr->lhs)->UnwrapRef();
-  auto* rhs_type = TypeOf(expr->rhs)->UnwrapRef();
-  // Multiplying by a matrix requires the use of `mul` in order to get the
-  // type of multiply we desire.
-  if (expr->op == ast::BinaryOp::kMultiply &&
-      ((lhs_type->Is<sem::Vector>() && rhs_type->Is<sem::Matrix>()) ||
-       (lhs_type->Is<sem::Matrix>() && rhs_type->Is<sem::Vector>()) ||
-       (lhs_type->Is<sem::Matrix>() && rhs_type->Is<sem::Matrix>()))) {
-    // Matrices are transposed, so swap LHS and RHS.
-    out << "mul(";
-    if (!EmitExpression(out, expr->rhs)) {
-      return false;
-    }
-    out << ", ";
-    if (!EmitExpression(out, expr->lhs)) {
-      return false;
     }
     out << ")";
+    return true;
+}
+
+bool GeneratorImpl::EmitBinary(std::ostream& out, const ast::BinaryExpression* expr) {
+    if (expr->op == ast::BinaryOp::kLogicalAnd || expr->op == ast::BinaryOp::kLogicalOr) {
+        auto name = UniqueIdentifier(kTempNamePrefix);
+
+        {
+            auto pre = line();
+            pre << "bool " << name << " = ";
+            if (!EmitExpression(pre, expr->lhs)) {
+                return false;
+            }
+            pre << ";";
+        }
+
+        if (expr->op == ast::BinaryOp::kLogicalOr) {
+            line() << "if (!" << name << ") {";
+        } else {
+            line() << "if (" << name << ") {";
+        }
+
+        {
+            ScopedIndent si(this);
+            auto pre = line();
+            pre << name << " = ";
+            if (!EmitExpression(pre, expr->rhs)) {
+                return false;
+            }
+            pre << ";";
+        }
+
+        line() << "}";
+
+        out << "(" << name << ")";
+        return true;
+    }
+
+    auto* lhs_type = TypeOf(expr->lhs)->UnwrapRef();
+    auto* rhs_type = TypeOf(expr->rhs)->UnwrapRef();
+    // Multiplying by a matrix requires the use of `mul` in order to get the
+    // type of multiply we desire.
+    if (expr->op == ast::BinaryOp::kMultiply &&
+        ((lhs_type->Is<sem::Vector>() && rhs_type->Is<sem::Matrix>()) ||
+         (lhs_type->Is<sem::Matrix>() && rhs_type->Is<sem::Vector>()) ||
+         (lhs_type->Is<sem::Matrix>() && rhs_type->Is<sem::Matrix>()))) {
+        // Matrices are transposed, so swap LHS and RHS.
+        out << "mul(";
+        if (!EmitExpression(out, expr->rhs)) {
+            return false;
+        }
+        out << ", ";
+        if (!EmitExpression(out, expr->lhs)) {
+            return false;
+        }
+        out << ")";
+
+        return true;
+    }
+
+    out << "(";
+    TINT_DEFER(out << ")");
+
+    if (!EmitExpression(out, expr->lhs)) {
+        return false;
+    }
+    out << " ";
+
+    switch (expr->op) {
+        case ast::BinaryOp::kAnd:
+            out << "&";
+            break;
+        case ast::BinaryOp::kOr:
+            out << "|";
+            break;
+        case ast::BinaryOp::kXor:
+            out << "^";
+            break;
+        case ast::BinaryOp::kLogicalAnd:
+        case ast::BinaryOp::kLogicalOr: {
+            // These are both handled above.
+            TINT_UNREACHABLE(Writer, diagnostics_);
+            return false;
+        }
+        case ast::BinaryOp::kEqual:
+            out << "==";
+            break;
+        case ast::BinaryOp::kNotEqual:
+            out << "!=";
+            break;
+        case ast::BinaryOp::kLessThan:
+            out << "<";
+            break;
+        case ast::BinaryOp::kGreaterThan:
+            out << ">";
+            break;
+        case ast::BinaryOp::kLessThanEqual:
+            out << "<=";
+            break;
+        case ast::BinaryOp::kGreaterThanEqual:
+            out << ">=";
+            break;
+        case ast::BinaryOp::kShiftLeft:
+            out << "<<";
+            break;
+        case ast::BinaryOp::kShiftRight:
+            // TODO(dsinclair): MSL is based on C++14, and >> in C++14 has
+            // implementation-defined behaviour for negative LHS.  We may have to
+            // generate extra code to implement WGSL-specified behaviour for negative
+            // LHS.
+            out << R"(>>)";
+            break;
+
+        case ast::BinaryOp::kAdd:
+            out << "+";
+            break;
+        case ast::BinaryOp::kSubtract:
+            out << "-";
+            break;
+        case ast::BinaryOp::kMultiply:
+            out << "*";
+            break;
+        case ast::BinaryOp::kDivide:
+            out << "/";
+            // BUG(crbug.com/tint/1083): Integer divide/modulo by zero is a FXC
+            // compile error, and undefined behavior in WGSL.
+            if (TypeOf(expr->rhs)->UnwrapRef()->is_integer_scalar_or_vector()) {
+                out << " ";
+                return EmitExpressionOrOneIfZero(out, expr->rhs);
+            }
+            break;
+        case ast::BinaryOp::kModulo:
+            out << "%";
+            // BUG(crbug.com/tint/1083): Integer divide/modulo by zero is a FXC
+            // compile error, and undefined behavior in WGSL.
+            if (TypeOf(expr->rhs)->UnwrapRef()->is_integer_scalar_or_vector()) {
+                out << " ";
+                return EmitExpressionOrOneIfZero(out, expr->rhs);
+            }
+            break;
+        case ast::BinaryOp::kNone:
+            diagnostics_.add_error(diag::System::Writer, "missing binary operation type");
+            return false;
+    }
+    out << " ";
+
+    if (!EmitExpression(out, expr->rhs)) {
+        return false;
+    }
 
     return true;
-  }
-
-  out << "(";
-  TINT_DEFER(out << ")");
-
-  if (!EmitExpression(out, expr->lhs)) {
-    return false;
-  }
-  out << " ";
-
-  switch (expr->op) {
-    case ast::BinaryOp::kAnd:
-      out << "&";
-      break;
-    case ast::BinaryOp::kOr:
-      out << "|";
-      break;
-    case ast::BinaryOp::kXor:
-      out << "^";
-      break;
-    case ast::BinaryOp::kLogicalAnd:
-    case ast::BinaryOp::kLogicalOr: {
-      // These are both handled above.
-      TINT_UNREACHABLE(Writer, diagnostics_);
-      return false;
-    }
-    case ast::BinaryOp::kEqual:
-      out << "==";
-      break;
-    case ast::BinaryOp::kNotEqual:
-      out << "!=";
-      break;
-    case ast::BinaryOp::kLessThan:
-      out << "<";
-      break;
-    case ast::BinaryOp::kGreaterThan:
-      out << ">";
-      break;
-    case ast::BinaryOp::kLessThanEqual:
-      out << "<=";
-      break;
-    case ast::BinaryOp::kGreaterThanEqual:
-      out << ">=";
-      break;
-    case ast::BinaryOp::kShiftLeft:
-      out << "<<";
-      break;
-    case ast::BinaryOp::kShiftRight:
-      // TODO(dsinclair): MSL is based on C++14, and >> in C++14 has
-      // implementation-defined behaviour for negative LHS.  We may have to
-      // generate extra code to implement WGSL-specified behaviour for negative
-      // LHS.
-      out << R"(>>)";
-      break;
-
-    case ast::BinaryOp::kAdd:
-      out << "+";
-      break;
-    case ast::BinaryOp::kSubtract:
-      out << "-";
-      break;
-    case ast::BinaryOp::kMultiply:
-      out << "*";
-      break;
-    case ast::BinaryOp::kDivide:
-      out << "/";
-      // BUG(crbug.com/tint/1083): Integer divide/modulo by zero is a FXC
-      // compile error, and undefined behavior in WGSL.
-      if (TypeOf(expr->rhs)->UnwrapRef()->is_integer_scalar_or_vector()) {
-        out << " ";
-        return EmitExpressionOrOneIfZero(out, expr->rhs);
-      }
-      break;
-    case ast::BinaryOp::kModulo:
-      out << "%";
-      // BUG(crbug.com/tint/1083): Integer divide/modulo by zero is a FXC
-      // compile error, and undefined behavior in WGSL.
-      if (TypeOf(expr->rhs)->UnwrapRef()->is_integer_scalar_or_vector()) {
-        out << " ";
-        return EmitExpressionOrOneIfZero(out, expr->rhs);
-      }
-      break;
-    case ast::BinaryOp::kNone:
-      diagnostics_.add_error(diag::System::Writer,
-                             "missing binary operation type");
-      return false;
-  }
-  out << " ";
-
-  if (!EmitExpression(out, expr->rhs)) {
-    return false;
-  }
-
-  return true;
 }
 
 bool GeneratorImpl::EmitStatements(const ast::StatementList& stmts) {
-  for (auto* s : stmts) {
-    if (!EmitStatement(s)) {
-      return false;
+    for (auto* s : stmts) {
+        if (!EmitStatement(s)) {
+            return false;
+        }
     }
-  }
-  return true;
+    return true;
 }
 
 bool GeneratorImpl::EmitStatementsWithIndent(const ast::StatementList& stmts) {
-  ScopedIndent si(this);
-  return EmitStatements(stmts);
+    ScopedIndent si(this);
+    return EmitStatements(stmts);
 }
 
 bool GeneratorImpl::EmitBlock(const ast::BlockStatement* stmt) {
-  line() << "{";
-  if (!EmitStatementsWithIndent(stmt->statements)) {
-    return false;
-  }
-  line() << "}";
-  return true;
+    line() << "{";
+    if (!EmitStatementsWithIndent(stmt->statements)) {
+        return false;
+    }
+    line() << "}";
+    return true;
 }
 
 bool GeneratorImpl::EmitBreak(const ast::BreakStatement*) {
-  line() << "break;";
-  return true;
+    line() << "break;";
+    return true;
 }
 
-bool GeneratorImpl::EmitCall(std::ostream& out,
-                             const ast::CallExpression* expr) {
-  auto* call = builder_.Sem().Get(expr);
-  auto* target = call->Target();
-  return Switch(
-      target,
-      [&](const sem::Function* func) {
-        return EmitFunctionCall(out, call, func);
-      },
-      [&](const sem::Builtin* builtin) {
-        return EmitBuiltinCall(out, call, builtin);
-      },
-      [&](const sem::TypeConversion* conv) {
-        return EmitTypeConversion(out, call, conv);
-      },
-      [&](const sem::TypeConstructor* ctor) {
-        return EmitTypeConstructor(out, call, ctor);
-      },
-      [&](Default) {
-        TINT_ICE(Writer, diagnostics_)
-            << "unhandled call target: " << target->TypeInfo().name;
-        return false;
-      });
+bool GeneratorImpl::EmitCall(std::ostream& out, const ast::CallExpression* expr) {
+    auto* call = builder_.Sem().Get(expr);
+    auto* target = call->Target();
+    return Switch(
+        target, [&](const sem::Function* func) { return EmitFunctionCall(out, call, func); },
+        [&](const sem::Builtin* builtin) { return EmitBuiltinCall(out, call, builtin); },
+        [&](const sem::TypeConversion* conv) { return EmitTypeConversion(out, call, conv); },
+        [&](const sem::TypeConstructor* ctor) { return EmitTypeConstructor(out, call, ctor); },
+        [&](Default) {
+            TINT_ICE(Writer, diagnostics_) << "unhandled call target: " << target->TypeInfo().name;
+            return false;
+        });
 }
 
 bool GeneratorImpl::EmitFunctionCall(std::ostream& out,
                                      const sem::Call* call,
                                      const sem::Function* func) {
-  auto* expr = call->Declaration();
+    auto* expr = call->Declaration();
 
-  if (ast::HasAttribute<transform::CalculateArrayLength::BufferSizeIntrinsic>(
-          func->Declaration()->attributes)) {
-    // Special function generated by the CalculateArrayLength transform for
-    // calling X.GetDimensions(Y)
-    if (!EmitExpression(out, call->Arguments()[0]->Declaration())) {
-      return false;
+    if (ast::HasAttribute<transform::CalculateArrayLength::BufferSizeIntrinsic>(
+            func->Declaration()->attributes)) {
+        // Special function generated by the CalculateArrayLength transform for
+        // calling X.GetDimensions(Y)
+        if (!EmitExpression(out, call->Arguments()[0]->Declaration())) {
+            return false;
+        }
+        out << ".GetDimensions(";
+        if (!EmitExpression(out, call->Arguments()[1]->Declaration())) {
+            return false;
+        }
+        out << ")";
+        return true;
     }
-    out << ".GetDimensions(";
-    if (!EmitExpression(out, call->Arguments()[1]->Declaration())) {
-      return false;
+
+    if (auto* intrinsic = ast::GetAttribute<transform::DecomposeMemoryAccess::Intrinsic>(
+            func->Declaration()->attributes)) {
+        switch (intrinsic->storage_class) {
+            case ast::StorageClass::kUniform:
+                return EmitUniformBufferAccess(out, expr, intrinsic);
+            case ast::StorageClass::kStorage:
+                return EmitStorageBufferAccess(out, expr, intrinsic);
+            default:
+                TINT_UNREACHABLE(Writer, diagnostics_)
+                    << "unsupported DecomposeMemoryAccess::Intrinsic storage class:"
+                    << intrinsic->storage_class;
+                return false;
+        }
     }
+
+    out << builder_.Symbols().NameFor(func->Declaration()->symbol) << "(";
+
+    bool first = true;
+    for (auto* arg : call->Arguments()) {
+        if (!first) {
+            out << ", ";
+        }
+        first = false;
+
+        if (!EmitExpression(out, arg->Declaration())) {
+            return false;
+        }
+    }
+
     out << ")";
     return true;
-  }
-
-  if (auto* intrinsic =
-          ast::GetAttribute<transform::DecomposeMemoryAccess::Intrinsic>(
-              func->Declaration()->attributes)) {
-    switch (intrinsic->storage_class) {
-      case ast::StorageClass::kUniform:
-        return EmitUniformBufferAccess(out, expr, intrinsic);
-      case ast::StorageClass::kStorage:
-        return EmitStorageBufferAccess(out, expr, intrinsic);
-      default:
-        TINT_UNREACHABLE(Writer, diagnostics_)
-            << "unsupported DecomposeMemoryAccess::Intrinsic storage class:"
-            << intrinsic->storage_class;
-        return false;
-    }
-  }
-
-  out << builder_.Symbols().NameFor(func->Declaration()->symbol) << "(";
-
-  bool first = true;
-  for (auto* arg : call->Arguments()) {
-    if (!first) {
-      out << ", ";
-    }
-    first = false;
-
-    if (!EmitExpression(out, arg->Declaration())) {
-      return false;
-    }
-  }
-
-  out << ")";
-  return true;
 }
 
 bool GeneratorImpl::EmitBuiltinCall(std::ostream& out,
                                     const sem::Call* call,
                                     const sem::Builtin* builtin) {
-  auto* expr = call->Declaration();
-  if (builtin->IsTexture()) {
-    return EmitTextureCall(out, call, builtin);
-  }
-  if (builtin->Type() == sem::BuiltinType::kSelect) {
-    return EmitSelectCall(out, expr);
-  }
-  if (builtin->Type() == sem::BuiltinType::kModf) {
-    return EmitModfCall(out, expr, builtin);
-  }
-  if (builtin->Type() == sem::BuiltinType::kFrexp) {
-    return EmitFrexpCall(out, expr, builtin);
-  }
-  if (builtin->Type() == sem::BuiltinType::kDegrees) {
-    return EmitDegreesCall(out, expr, builtin);
-  }
-  if (builtin->Type() == sem::BuiltinType::kRadians) {
-    return EmitRadiansCall(out, expr, builtin);
-  }
-  if (builtin->IsDataPacking()) {
-    return EmitDataPackingCall(out, expr, builtin);
-  }
-  if (builtin->IsDataUnpacking()) {
-    return EmitDataUnpackingCall(out, expr, builtin);
-  }
-  if (builtin->IsBarrier()) {
-    return EmitBarrierCall(out, builtin);
-  }
-  if (builtin->IsAtomic()) {
-    return EmitWorkgroupAtomicCall(out, expr, builtin);
-  }
-  auto name = generate_builtin_name(builtin);
-  if (name.empty()) {
-    return false;
-  }
-
-  out << name << "(";
-
-  bool first = true;
-  for (auto* arg : call->Arguments()) {
-    if (!first) {
-      out << ", ";
+    auto* expr = call->Declaration();
+    if (builtin->IsTexture()) {
+        return EmitTextureCall(out, call, builtin);
     }
-    first = false;
-
-    if (!EmitExpression(out, arg->Declaration())) {
-      return false;
+    if (builtin->Type() == sem::BuiltinType::kSelect) {
+        return EmitSelectCall(out, expr);
     }
-  }
+    if (builtin->Type() == sem::BuiltinType::kModf) {
+        return EmitModfCall(out, expr, builtin);
+    }
+    if (builtin->Type() == sem::BuiltinType::kFrexp) {
+        return EmitFrexpCall(out, expr, builtin);
+    }
+    if (builtin->Type() == sem::BuiltinType::kDegrees) {
+        return EmitDegreesCall(out, expr, builtin);
+    }
+    if (builtin->Type() == sem::BuiltinType::kRadians) {
+        return EmitRadiansCall(out, expr, builtin);
+    }
+    if (builtin->IsDataPacking()) {
+        return EmitDataPackingCall(out, expr, builtin);
+    }
+    if (builtin->IsDataUnpacking()) {
+        return EmitDataUnpackingCall(out, expr, builtin);
+    }
+    if (builtin->IsBarrier()) {
+        return EmitBarrierCall(out, builtin);
+    }
+    if (builtin->IsAtomic()) {
+        return EmitWorkgroupAtomicCall(out, expr, builtin);
+    }
+    auto name = generate_builtin_name(builtin);
+    if (name.empty()) {
+        return false;
+    }
 
-  out << ")";
-  return true;
+    out << name << "(";
+
+    bool first = true;
+    for (auto* arg : call->Arguments()) {
+        if (!first) {
+            out << ", ";
+        }
+        first = false;
+
+        if (!EmitExpression(out, arg->Declaration())) {
+            return false;
+        }
+    }
+
+    out << ")";
+    return true;
 }
 
 bool GeneratorImpl::EmitTypeConversion(std::ostream& out,
                                        const sem::Call* call,
                                        const sem::TypeConversion* conv) {
-  if (!EmitType(out, conv->Target(), ast::StorageClass::kNone,
-                ast::Access::kReadWrite, "")) {
-    return false;
-  }
-  out << "(";
+    if (!EmitType(out, conv->Target(), ast::StorageClass::kNone, ast::Access::kReadWrite, "")) {
+        return false;
+    }
+    out << "(";
 
-  if (!EmitExpression(out, call->Arguments()[0]->Declaration())) {
-    return false;
-  }
+    if (!EmitExpression(out, call->Arguments()[0]->Declaration())) {
+        return false;
+    }
 
-  out << ")";
-  return true;
+    out << ")";
+    return true;
 }
 
 bool GeneratorImpl::EmitTypeConstructor(std::ostream& out,
                                         const sem::Call* call,
                                         const sem::TypeConstructor* ctor) {
-  auto* type = call->Type();
+    auto* type = call->Type();
 
-  // If the type constructor is empty then we need to construct with the zero
-  // value for all components.
-  if (call->Arguments().empty()) {
-    return EmitZeroValue(out, type);
-  }
-
-  bool brackets = type->IsAnyOf<sem::Array, sem::Struct>();
-
-  // For single-value vector initializers, swizzle the scalar to the right
-  // vector dimension using .x
-  const bool is_single_value_vector_init =
-      type->is_scalar_vector() && call->Arguments().size() == 1 &&
-      ctor->Parameters()[0]->Type()->is_scalar();
-
-  auto it = structure_builders_.find(As<sem::Struct>(type));
-  if (it != structure_builders_.end()) {
-    out << it->second << "(";
-    brackets = false;
-  } else if (brackets) {
-    out << "{";
-  } else {
-    if (!EmitType(out, type, ast::StorageClass::kNone, ast::Access::kReadWrite,
-                  "")) {
-      return false;
+    // If the type constructor is empty then we need to construct with the zero
+    // value for all components.
+    if (call->Arguments().empty()) {
+        return EmitZeroValue(out, type);
     }
-    out << "(";
-  }
 
-  if (is_single_value_vector_init) {
-    out << "(";
-  }
+    bool brackets = type->IsAnyOf<sem::Array, sem::Struct>();
 
-  bool first = true;
-  for (auto* e : call->Arguments()) {
-    if (!first) {
-      out << ", ";
+    // For single-value vector initializers, swizzle the scalar to the right
+    // vector dimension using .x
+    const bool is_single_value_vector_init = type->is_scalar_vector() &&
+                                             call->Arguments().size() == 1 &&
+                                             ctor->Parameters()[0]->Type()->is_scalar();
+
+    auto it = structure_builders_.find(As<sem::Struct>(type));
+    if (it != structure_builders_.end()) {
+        out << it->second << "(";
+        brackets = false;
+    } else if (brackets) {
+        out << "{";
+    } else {
+        if (!EmitType(out, type, ast::StorageClass::kNone, ast::Access::kReadWrite, "")) {
+            return false;
+        }
+        out << "(";
     }
-    first = false;
 
-    if (!EmitExpression(out, e->Declaration())) {
-      return false;
+    if (is_single_value_vector_init) {
+        out << "(";
     }
-  }
 
-  if (is_single_value_vector_init) {
-    out << ")." << std::string(type->As<sem::Vector>()->Width(), 'x');
-  }
+    bool first = true;
+    for (auto* e : call->Arguments()) {
+        if (!first) {
+            out << ", ";
+        }
+        first = false;
 
-  out << (brackets ? "}" : ")");
-  return true;
+        if (!EmitExpression(out, e->Declaration())) {
+            return false;
+        }
+    }
+
+    if (is_single_value_vector_init) {
+        out << ")." << std::string(type->As<sem::Vector>()->Width(), 'x');
+    }
+
+    out << (brackets ? "}" : ")");
+    return true;
 }
 
 bool GeneratorImpl::EmitUniformBufferAccess(
     std::ostream& out,
     const ast::CallExpression* expr,
     const transform::DecomposeMemoryAccess::Intrinsic* intrinsic) {
-  const auto& args = expr->args;
-  auto* offset_arg = builder_.Sem().Get(args[1]);
+    const auto& args = expr->args;
+    auto* offset_arg = builder_.Sem().Get(args[1]);
 
-  uint32_t scalar_offset_value = 0;
-  std::string scalar_offset_expr;
+    uint32_t scalar_offset_value = 0;
+    std::string scalar_offset_expr;
 
-  // If true, use scalar_offset_value, otherwise use scalar_offset_expr
-  bool scalar_offset_constant = false;
+    // If true, use scalar_offset_value, otherwise use scalar_offset_expr
+    bool scalar_offset_constant = false;
 
-  if (auto val = offset_arg->ConstantValue()) {
-    TINT_ASSERT(Writer, val.Type()->Is<sem::U32>());
-    scalar_offset_value = val.Elements()[0].u32;
-    scalar_offset_value /= 4;  // bytes -> scalar index
-    scalar_offset_constant = true;
-  }
-
-  if (!scalar_offset_constant) {
-    // UBO offset not compile-time known.
-    // Calculate the scalar offset into a temporary.
-    scalar_offset_expr = UniqueIdentifier("scalar_offset");
-    auto pre = line();
-    pre << "const uint " << scalar_offset_expr << " = (";
-    if (!EmitExpression(pre, args[1])) {  // offset
-      return false;
+    if (auto val = offset_arg->ConstantValue()) {
+        TINT_ASSERT(Writer, val.Type()->Is<sem::U32>());
+        scalar_offset_value = val.Elements()[0].u32;
+        scalar_offset_value /= 4;  // bytes -> scalar index
+        scalar_offset_constant = true;
     }
-    pre << ") / 4;";
-  }
 
-  using Op = transform::DecomposeMemoryAccess::Intrinsic::Op;
-  using DataType = transform::DecomposeMemoryAccess::Intrinsic::DataType;
-  switch (intrinsic->op) {
-    case Op::kLoad: {
-      auto cast = [&](const char* to, auto&& load) {
-        out << to << "(";
-        auto result = load();
-        out << ")";
-        return result;
-      };
-      auto load_scalar = [&]() {
-        if (!EmitExpression(out, args[0])) {  // buffer
-          return false;
-        }
-        if (scalar_offset_constant) {
-          char swizzle[] = {'x', 'y', 'z', 'w'};
-          out << "[" << (scalar_offset_value / 4) << "]."
-              << swizzle[scalar_offset_value & 3];
-        } else {
-          out << "[" << scalar_offset_expr << " / 4][" << scalar_offset_expr
-              << " % 4]";
-        }
-        return true;
-      };
-      // Has a minimum alignment of 8 bytes, so is either .xy or .zw
-      auto load_vec2 = [&] {
-        if (scalar_offset_constant) {
-          if (!EmitExpression(out, args[0])) {  // buffer
+    if (!scalar_offset_constant) {
+        // UBO offset not compile-time known.
+        // Calculate the scalar offset into a temporary.
+        scalar_offset_expr = UniqueIdentifier("scalar_offset");
+        auto pre = line();
+        pre << "const uint " << scalar_offset_expr << " = (";
+        if (!EmitExpression(pre, args[1])) {  // offset
             return false;
-          }
-          out << "[" << (scalar_offset_value / 4) << "]";
-          out << ((scalar_offset_value & 2) == 0 ? ".xy" : ".zw");
-        } else {
-          std::string ubo_load = UniqueIdentifier("ubo_load");
-          {
-            auto pre = line();
-            pre << "uint4 " << ubo_load << " = ";
-            if (!EmitExpression(pre, args[0])) {  // buffer
-              return false;
-            }
-            pre << "[" << scalar_offset_expr << " / 4];";
-          }
-          out << "((" << scalar_offset_expr << " & 2) ? " << ubo_load
-              << ".zw : " << ubo_load << ".xy)";
         }
-        return true;
-      };
-      // vec4 has a minimum alignment of 16 bytes, easiest case
-      auto load_vec4 = [&] {
-        if (!EmitExpression(out, args[0])) {  // buffer
-          return false;
-        }
-        if (scalar_offset_constant) {
-          out << "[" << (scalar_offset_value / 4) << "]";
-        } else {
-          out << "[" << scalar_offset_expr << " / 4]";
-        }
-        return true;
-      };
-      // vec3 has a minimum alignment of 16 bytes, so is just a .xyz swizzle
-      auto load_vec3 = [&] {
-        if (!load_vec4()) {
-          return false;
-        }
-        out << ".xyz";
-        return true;
-      };
-      switch (intrinsic->type) {
-        case DataType::kU32:
-          return load_scalar();
-        case DataType::kF32:
-          return cast("asfloat", load_scalar);
-        case DataType::kI32:
-          return cast("asint", load_scalar);
-        case DataType::kVec2U32:
-          return load_vec2();
-        case DataType::kVec2F32:
-          return cast("asfloat", load_vec2);
-        case DataType::kVec2I32:
-          return cast("asint", load_vec2);
-        case DataType::kVec3U32:
-          return load_vec3();
-        case DataType::kVec3F32:
-          return cast("asfloat", load_vec3);
-        case DataType::kVec3I32:
-          return cast("asint", load_vec3);
-        case DataType::kVec4U32:
-          return load_vec4();
-        case DataType::kVec4F32:
-          return cast("asfloat", load_vec4);
-        case DataType::kVec4I32:
-          return cast("asint", load_vec4);
-      }
-      TINT_UNREACHABLE(Writer, diagnostics_)
-          << "unsupported DecomposeMemoryAccess::Intrinsic::DataType: "
-          << static_cast<int>(intrinsic->type);
-      return false;
+        pre << ") / 4;";
     }
-    default:
-      break;
-  }
-  TINT_UNREACHABLE(Writer, diagnostics_)
-      << "unsupported DecomposeMemoryAccess::Intrinsic::Op: "
-      << static_cast<int>(intrinsic->op);
-  return false;
+
+    using Op = transform::DecomposeMemoryAccess::Intrinsic::Op;
+    using DataType = transform::DecomposeMemoryAccess::Intrinsic::DataType;
+    switch (intrinsic->op) {
+        case Op::kLoad: {
+            auto cast = [&](const char* to, auto&& load) {
+                out << to << "(";
+                auto result = load();
+                out << ")";
+                return result;
+            };
+            auto load_scalar = [&]() {
+                if (!EmitExpression(out, args[0])) {  // buffer
+                    return false;
+                }
+                if (scalar_offset_constant) {
+                    char swizzle[] = {'x', 'y', 'z', 'w'};
+                    out << "[" << (scalar_offset_value / 4) << "]."
+                        << swizzle[scalar_offset_value & 3];
+                } else {
+                    out << "[" << scalar_offset_expr << " / 4][" << scalar_offset_expr << " % 4]";
+                }
+                return true;
+            };
+            // Has a minimum alignment of 8 bytes, so is either .xy or .zw
+            auto load_vec2 = [&] {
+                if (scalar_offset_constant) {
+                    if (!EmitExpression(out, args[0])) {  // buffer
+                        return false;
+                    }
+                    out << "[" << (scalar_offset_value / 4) << "]";
+                    out << ((scalar_offset_value & 2) == 0 ? ".xy" : ".zw");
+                } else {
+                    std::string ubo_load = UniqueIdentifier("ubo_load");
+                    {
+                        auto pre = line();
+                        pre << "uint4 " << ubo_load << " = ";
+                        if (!EmitExpression(pre, args[0])) {  // buffer
+                            return false;
+                        }
+                        pre << "[" << scalar_offset_expr << " / 4];";
+                    }
+                    out << "((" << scalar_offset_expr << " & 2) ? " << ubo_load
+                        << ".zw : " << ubo_load << ".xy)";
+                }
+                return true;
+            };
+            // vec4 has a minimum alignment of 16 bytes, easiest case
+            auto load_vec4 = [&] {
+                if (!EmitExpression(out, args[0])) {  // buffer
+                    return false;
+                }
+                if (scalar_offset_constant) {
+                    out << "[" << (scalar_offset_value / 4) << "]";
+                } else {
+                    out << "[" << scalar_offset_expr << " / 4]";
+                }
+                return true;
+            };
+            // vec3 has a minimum alignment of 16 bytes, so is just a .xyz swizzle
+            auto load_vec3 = [&] {
+                if (!load_vec4()) {
+                    return false;
+                }
+                out << ".xyz";
+                return true;
+            };
+            switch (intrinsic->type) {
+                case DataType::kU32:
+                    return load_scalar();
+                case DataType::kF32:
+                    return cast("asfloat", load_scalar);
+                case DataType::kI32:
+                    return cast("asint", load_scalar);
+                case DataType::kVec2U32:
+                    return load_vec2();
+                case DataType::kVec2F32:
+                    return cast("asfloat", load_vec2);
+                case DataType::kVec2I32:
+                    return cast("asint", load_vec2);
+                case DataType::kVec3U32:
+                    return load_vec3();
+                case DataType::kVec3F32:
+                    return cast("asfloat", load_vec3);
+                case DataType::kVec3I32:
+                    return cast("asint", load_vec3);
+                case DataType::kVec4U32:
+                    return load_vec4();
+                case DataType::kVec4F32:
+                    return cast("asfloat", load_vec4);
+                case DataType::kVec4I32:
+                    return cast("asint", load_vec4);
+            }
+            TINT_UNREACHABLE(Writer, diagnostics_)
+                << "unsupported DecomposeMemoryAccess::Intrinsic::DataType: "
+                << static_cast<int>(intrinsic->type);
+            return false;
+        }
+        default:
+            break;
+    }
+    TINT_UNREACHABLE(Writer, diagnostics_)
+        << "unsupported DecomposeMemoryAccess::Intrinsic::Op: " << static_cast<int>(intrinsic->op);
+    return false;
 }
 
 bool GeneratorImpl::EmitStorageBufferAccess(
     std::ostream& out,
     const ast::CallExpression* expr,
     const transform::DecomposeMemoryAccess::Intrinsic* intrinsic) {
-  const auto& args = expr->args;
+    const auto& args = expr->args;
 
-  using Op = transform::DecomposeMemoryAccess::Intrinsic::Op;
-  using DataType = transform::DecomposeMemoryAccess::Intrinsic::DataType;
-  switch (intrinsic->op) {
-    case Op::kLoad: {
-      auto load = [&](const char* cast, int n) {
-        if (cast) {
-          out << cast << "(";
+    using Op = transform::DecomposeMemoryAccess::Intrinsic::Op;
+    using DataType = transform::DecomposeMemoryAccess::Intrinsic::DataType;
+    switch (intrinsic->op) {
+        case Op::kLoad: {
+            auto load = [&](const char* cast, int n) {
+                if (cast) {
+                    out << cast << "(";
+                }
+                if (!EmitExpression(out, args[0])) {  // buffer
+                    return false;
+                }
+                out << ".Load";
+                if (n > 1) {
+                    out << n;
+                }
+                ScopedParen sp(out);
+                if (!EmitExpression(out, args[1])) {  // offset
+                    return false;
+                }
+                if (cast) {
+                    out << ")";
+                }
+                return true;
+            };
+            switch (intrinsic->type) {
+                case DataType::kU32:
+                    return load(nullptr, 1);
+                case DataType::kF32:
+                    return load("asfloat", 1);
+                case DataType::kI32:
+                    return load("asint", 1);
+                case DataType::kVec2U32:
+                    return load(nullptr, 2);
+                case DataType::kVec2F32:
+                    return load("asfloat", 2);
+                case DataType::kVec2I32:
+                    return load("asint", 2);
+                case DataType::kVec3U32:
+                    return load(nullptr, 3);
+                case DataType::kVec3F32:
+                    return load("asfloat", 3);
+                case DataType::kVec3I32:
+                    return load("asint", 3);
+                case DataType::kVec4U32:
+                    return load(nullptr, 4);
+                case DataType::kVec4F32:
+                    return load("asfloat", 4);
+                case DataType::kVec4I32:
+                    return load("asint", 4);
+            }
+            TINT_UNREACHABLE(Writer, diagnostics_)
+                << "unsupported DecomposeMemoryAccess::Intrinsic::DataType: "
+                << static_cast<int>(intrinsic->type);
+            return false;
         }
-        if (!EmitExpression(out, args[0])) {  // buffer
-          return false;
+
+        case Op::kStore: {
+            auto store = [&](int n) {
+                if (!EmitExpression(out, args[0])) {  // buffer
+                    return false;
+                }
+                out << ".Store";
+                if (n > 1) {
+                    out << n;
+                }
+                ScopedParen sp1(out);
+                if (!EmitExpression(out, args[1])) {  // offset
+                    return false;
+                }
+                out << ", asuint";
+                ScopedParen sp2(out);
+                if (!EmitExpression(out, args[2])) {  // value
+                    return false;
+                }
+                return true;
+            };
+            switch (intrinsic->type) {
+                case DataType::kU32:
+                    return store(1);
+                case DataType::kF32:
+                    return store(1);
+                case DataType::kI32:
+                    return store(1);
+                case DataType::kVec2U32:
+                    return store(2);
+                case DataType::kVec2F32:
+                    return store(2);
+                case DataType::kVec2I32:
+                    return store(2);
+                case DataType::kVec3U32:
+                    return store(3);
+                case DataType::kVec3F32:
+                    return store(3);
+                case DataType::kVec3I32:
+                    return store(3);
+                case DataType::kVec4U32:
+                    return store(4);
+                case DataType::kVec4F32:
+                    return store(4);
+                case DataType::kVec4I32:
+                    return store(4);
+            }
+            TINT_UNREACHABLE(Writer, diagnostics_)
+                << "unsupported DecomposeMemoryAccess::Intrinsic::DataType: "
+                << static_cast<int>(intrinsic->type);
+            return false;
         }
-        out << ".Load";
-        if (n > 1) {
-          out << n;
-        }
-        ScopedParen sp(out);
-        if (!EmitExpression(out, args[1])) {  // offset
-          return false;
-        }
-        if (cast) {
-          out << ")";
-        }
-        return true;
-      };
-      switch (intrinsic->type) {
-        case DataType::kU32:
-          return load(nullptr, 1);
-        case DataType::kF32:
-          return load("asfloat", 1);
-        case DataType::kI32:
-          return load("asint", 1);
-        case DataType::kVec2U32:
-          return load(nullptr, 2);
-        case DataType::kVec2F32:
-          return load("asfloat", 2);
-        case DataType::kVec2I32:
-          return load("asint", 2);
-        case DataType::kVec3U32:
-          return load(nullptr, 3);
-        case DataType::kVec3F32:
-          return load("asfloat", 3);
-        case DataType::kVec3I32:
-          return load("asint", 3);
-        case DataType::kVec4U32:
-          return load(nullptr, 4);
-        case DataType::kVec4F32:
-          return load("asfloat", 4);
-        case DataType::kVec4I32:
-          return load("asint", 4);
-      }
-      TINT_UNREACHABLE(Writer, diagnostics_)
-          << "unsupported DecomposeMemoryAccess::Intrinsic::DataType: "
-          << static_cast<int>(intrinsic->type);
-      return false;
+
+        case Op::kAtomicLoad:
+        case Op::kAtomicStore:
+        case Op::kAtomicAdd:
+        case Op::kAtomicSub:
+        case Op::kAtomicMax:
+        case Op::kAtomicMin:
+        case Op::kAtomicAnd:
+        case Op::kAtomicOr:
+        case Op::kAtomicXor:
+        case Op::kAtomicExchange:
+        case Op::kAtomicCompareExchangeWeak:
+            return EmitStorageAtomicCall(out, expr, intrinsic);
     }
 
-    case Op::kStore: {
-      auto store = [&](int n) {
-        if (!EmitExpression(out, args[0])) {  // buffer
-          return false;
-        }
-        out << ".Store";
-        if (n > 1) {
-          out << n;
-        }
-        ScopedParen sp1(out);
-        if (!EmitExpression(out, args[1])) {  // offset
-          return false;
-        }
-        out << ", asuint";
-        ScopedParen sp2(out);
-        if (!EmitExpression(out, args[2])) {  // value
-          return false;
-        }
-        return true;
-      };
-      switch (intrinsic->type) {
-        case DataType::kU32:
-          return store(1);
-        case DataType::kF32:
-          return store(1);
-        case DataType::kI32:
-          return store(1);
-        case DataType::kVec2U32:
-          return store(2);
-        case DataType::kVec2F32:
-          return store(2);
-        case DataType::kVec2I32:
-          return store(2);
-        case DataType::kVec3U32:
-          return store(3);
-        case DataType::kVec3F32:
-          return store(3);
-        case DataType::kVec3I32:
-          return store(3);
-        case DataType::kVec4U32:
-          return store(4);
-        case DataType::kVec4F32:
-          return store(4);
-        case DataType::kVec4I32:
-          return store(4);
-      }
-      TINT_UNREACHABLE(Writer, diagnostics_)
-          << "unsupported DecomposeMemoryAccess::Intrinsic::DataType: "
-          << static_cast<int>(intrinsic->type);
-      return false;
-    }
-
-    case Op::kAtomicLoad:
-    case Op::kAtomicStore:
-    case Op::kAtomicAdd:
-    case Op::kAtomicSub:
-    case Op::kAtomicMax:
-    case Op::kAtomicMin:
-    case Op::kAtomicAnd:
-    case Op::kAtomicOr:
-    case Op::kAtomicXor:
-    case Op::kAtomicExchange:
-    case Op::kAtomicCompareExchangeWeak:
-      return EmitStorageAtomicCall(out, expr, intrinsic);
-  }
-
-  TINT_UNREACHABLE(Writer, diagnostics_)
-      << "unsupported DecomposeMemoryAccess::Intrinsic::Op: "
-      << static_cast<int>(intrinsic->op);
-  return false;
+    TINT_UNREACHABLE(Writer, diagnostics_)
+        << "unsupported DecomposeMemoryAccess::Intrinsic::Op: " << static_cast<int>(intrinsic->op);
+    return false;
 }
 
 bool GeneratorImpl::EmitStorageAtomicCall(
     std::ostream& out,
     const ast::CallExpression* expr,
     const transform::DecomposeMemoryAccess::Intrinsic* intrinsic) {
-  using Op = transform::DecomposeMemoryAccess::Intrinsic::Op;
+    using Op = transform::DecomposeMemoryAccess::Intrinsic::Op;
 
-  auto* result_ty = TypeOf(expr);
+    auto* result_ty = TypeOf(expr);
 
-  auto& buf = helpers_;
+    auto& buf = helpers_;
 
-  // generate_helper() generates a helper function that translates the
-  // DecomposeMemoryAccess::Intrinsic call into the corresponding HLSL
-  // atomic intrinsic function.
-  auto generate_helper = [&]() -> std::string {
-    auto rmw = [&](const char* wgsl, const char* hlsl) -> std::string {
-      auto name = UniqueIdentifier(wgsl);
-      {
-        auto fn = line(&buf);
-        if (!EmitTypeAndName(fn, result_ty, ast::StorageClass::kNone,
-                             ast::Access::kUndefined, name)) {
-          return "";
+    // generate_helper() generates a helper function that translates the
+    // DecomposeMemoryAccess::Intrinsic call into the corresponding HLSL
+    // atomic intrinsic function.
+    auto generate_helper = [&]() -> std::string {
+        auto rmw = [&](const char* wgsl, const char* hlsl) -> std::string {
+            auto name = UniqueIdentifier(wgsl);
+            {
+                auto fn = line(&buf);
+                if (!EmitTypeAndName(fn, result_ty, ast::StorageClass::kNone,
+                                     ast::Access::kUndefined, name)) {
+                    return "";
+                }
+                fn << "(RWByteAddressBuffer buffer, uint offset, ";
+                if (!EmitTypeAndName(fn, result_ty, ast::StorageClass::kNone,
+                                     ast::Access::kUndefined, "value")) {
+                    return "";
+                }
+                fn << ") {";
+            }
+
+            buf.IncrementIndent();
+            TINT_DEFER({
+                buf.DecrementIndent();
+                line(&buf) << "}";
+                line(&buf);
+            });
+
+            {
+                auto l = line(&buf);
+                if (!EmitTypeAndName(l, result_ty, ast::StorageClass::kNone,
+                                     ast::Access::kUndefined, "original_value")) {
+                    return "";
+                }
+                l << " = 0;";
+            }
+            {
+                auto l = line(&buf);
+                l << "buffer." << hlsl << "(offset, ";
+                if (intrinsic->op == Op::kAtomicSub) {
+                    l << "-";
+                }
+                l << "value, original_value);";
+            }
+            line(&buf) << "return original_value;";
+            return name;
+        };
+
+        switch (intrinsic->op) {
+            case Op::kAtomicAdd:
+                return rmw("atomicAdd", "InterlockedAdd");
+
+            case Op::kAtomicSub:
+                // Use add with the operand negated.
+                return rmw("atomicSub", "InterlockedAdd");
+
+            case Op::kAtomicMax:
+                return rmw("atomicMax", "InterlockedMax");
+
+            case Op::kAtomicMin:
+                return rmw("atomicMin", "InterlockedMin");
+
+            case Op::kAtomicAnd:
+                return rmw("atomicAnd", "InterlockedAnd");
+
+            case Op::kAtomicOr:
+                return rmw("atomicOr", "InterlockedOr");
+
+            case Op::kAtomicXor:
+                return rmw("atomicXor", "InterlockedXor");
+
+            case Op::kAtomicExchange:
+                return rmw("atomicExchange", "InterlockedExchange");
+
+            case Op::kAtomicLoad: {
+                // HLSL does not have an InterlockedLoad, so we emulate it with
+                // InterlockedOr using 0 as the OR value
+                auto name = UniqueIdentifier("atomicLoad");
+                {
+                    auto fn = line(&buf);
+                    if (!EmitTypeAndName(fn, result_ty, ast::StorageClass::kNone,
+                                         ast::Access::kUndefined, name)) {
+                        return "";
+                    }
+                    fn << "(RWByteAddressBuffer buffer, uint offset) {";
+                }
+
+                buf.IncrementIndent();
+                TINT_DEFER({
+                    buf.DecrementIndent();
+                    line(&buf) << "}";
+                    line(&buf);
+                });
+
+                {
+                    auto l = line(&buf);
+                    if (!EmitTypeAndName(l, result_ty, ast::StorageClass::kNone,
+                                         ast::Access::kUndefined, "value")) {
+                        return "";
+                    }
+                    l << " = 0;";
+                }
+
+                line(&buf) << "buffer.InterlockedOr(offset, 0, value);";
+                line(&buf) << "return value;";
+                return name;
+            }
+            case Op::kAtomicStore: {
+                // HLSL does not have an InterlockedStore, so we emulate it with
+                // InterlockedExchange and discard the returned value
+                auto* value_ty = TypeOf(expr->args[2])->UnwrapRef();
+                auto name = UniqueIdentifier("atomicStore");
+                {
+                    auto fn = line(&buf);
+                    fn << "void " << name << "(RWByteAddressBuffer buffer, uint offset, ";
+                    if (!EmitTypeAndName(fn, value_ty, ast::StorageClass::kNone,
+                                         ast::Access::kUndefined, "value")) {
+                        return "";
+                    }
+                    fn << ") {";
+                }
+
+                buf.IncrementIndent();
+                TINT_DEFER({
+                    buf.DecrementIndent();
+                    line(&buf) << "}";
+                    line(&buf);
+                });
+
+                {
+                    auto l = line(&buf);
+                    if (!EmitTypeAndName(l, value_ty, ast::StorageClass::kNone,
+                                         ast::Access::kUndefined, "ignored")) {
+                        return "";
+                    }
+                    l << ";";
+                }
+                line(&buf) << "buffer.InterlockedExchange(offset, value, ignored);";
+                return name;
+            }
+            case Op::kAtomicCompareExchangeWeak: {
+                auto* value_ty = TypeOf(expr->args[2])->UnwrapRef();
+
+                auto name = UniqueIdentifier("atomicCompareExchangeWeak");
+                {
+                    auto fn = line(&buf);
+                    if (!EmitTypeAndName(fn, result_ty, ast::StorageClass::kNone,
+                                         ast::Access::kUndefined, name)) {
+                        return "";
+                    }
+                    fn << "(RWByteAddressBuffer buffer, uint offset, ";
+                    if (!EmitTypeAndName(fn, value_ty, ast::StorageClass::kNone,
+                                         ast::Access::kUndefined, "compare")) {
+                        return "";
+                    }
+                    fn << ", ";
+                    if (!EmitTypeAndName(fn, value_ty, ast::StorageClass::kNone,
+                                         ast::Access::kUndefined, "value")) {
+                        return "";
+                    }
+                    fn << ") {";
+                }
+
+                buf.IncrementIndent();
+                TINT_DEFER({
+                    buf.DecrementIndent();
+                    line(&buf) << "}";
+                    line(&buf);
+                });
+
+                {  // T result = {0, 0};
+                    auto l = line(&buf);
+                    if (!EmitTypeAndName(l, result_ty, ast::StorageClass::kNone,
+                                         ast::Access::kUndefined, "result")) {
+                        return "";
+                    }
+                    l << " = {0, 0};";
+                }
+                line(&buf) << "buffer.InterlockedCompareExchange(offset, compare, "
+                              "value, result.x);";
+                line(&buf) << "result.y = result.x == compare;";
+                line(&buf) << "return result;";
+                return name;
+            }
+            default:
+                break;
         }
-        fn << "(RWByteAddressBuffer buffer, uint offset, ";
-        if (!EmitTypeAndName(fn, result_ty, ast::StorageClass::kNone,
-                             ast::Access::kUndefined, "value")) {
-          return "";
-        }
-        fn << ") {";
-      }
-
-      buf.IncrementIndent();
-      TINT_DEFER({
-        buf.DecrementIndent();
-        line(&buf) << "}";
-        line(&buf);
-      });
-
-      {
-        auto l = line(&buf);
-        if (!EmitTypeAndName(l, result_ty, ast::StorageClass::kNone,
-                             ast::Access::kUndefined, "original_value")) {
-          return "";
-        }
-        l << " = 0;";
-      }
-      {
-        auto l = line(&buf);
-        l << "buffer." << hlsl << "(offset, ";
-        if (intrinsic->op == Op::kAtomicSub) {
-          l << "-";
-        }
-        l << "value, original_value);";
-      }
-      line(&buf) << "return original_value;";
-      return name;
+        TINT_UNREACHABLE(Writer, diagnostics_)
+            << "unsupported atomic DecomposeMemoryAccess::Intrinsic::Op: "
+            << static_cast<int>(intrinsic->op);
+        return "";
     };
 
-    switch (intrinsic->op) {
-      case Op::kAtomicAdd:
-        return rmw("atomicAdd", "InterlockedAdd");
-
-      case Op::kAtomicSub:
-        // Use add with the operand negated.
-        return rmw("atomicSub", "InterlockedAdd");
-
-      case Op::kAtomicMax:
-        return rmw("atomicMax", "InterlockedMax");
-
-      case Op::kAtomicMin:
-        return rmw("atomicMin", "InterlockedMin");
-
-      case Op::kAtomicAnd:
-        return rmw("atomicAnd", "InterlockedAnd");
-
-      case Op::kAtomicOr:
-        return rmw("atomicOr", "InterlockedOr");
-
-      case Op::kAtomicXor:
-        return rmw("atomicXor", "InterlockedXor");
-
-      case Op::kAtomicExchange:
-        return rmw("atomicExchange", "InterlockedExchange");
-
-      case Op::kAtomicLoad: {
-        // HLSL does not have an InterlockedLoad, so we emulate it with
-        // InterlockedOr using 0 as the OR value
-        auto name = UniqueIdentifier("atomicLoad");
-        {
-          auto fn = line(&buf);
-          if (!EmitTypeAndName(fn, result_ty, ast::StorageClass::kNone,
-                               ast::Access::kUndefined, name)) {
-            return "";
-          }
-          fn << "(RWByteAddressBuffer buffer, uint offset) {";
-        }
-
-        buf.IncrementIndent();
-        TINT_DEFER({
-          buf.DecrementIndent();
-          line(&buf) << "}";
-          line(&buf);
-        });
-
-        {
-          auto l = line(&buf);
-          if (!EmitTypeAndName(l, result_ty, ast::StorageClass::kNone,
-                               ast::Access::kUndefined, "value")) {
-            return "";
-          }
-          l << " = 0;";
-        }
-
-        line(&buf) << "buffer.InterlockedOr(offset, 0, value);";
-        line(&buf) << "return value;";
-        return name;
-      }
-      case Op::kAtomicStore: {
-        // HLSL does not have an InterlockedStore, so we emulate it with
-        // InterlockedExchange and discard the returned value
-        auto* value_ty = TypeOf(expr->args[2])->UnwrapRef();
-        auto name = UniqueIdentifier("atomicStore");
-        {
-          auto fn = line(&buf);
-          fn << "void " << name << "(RWByteAddressBuffer buffer, uint offset, ";
-          if (!EmitTypeAndName(fn, value_ty, ast::StorageClass::kNone,
-                               ast::Access::kUndefined, "value")) {
-            return "";
-          }
-          fn << ") {";
-        }
-
-        buf.IncrementIndent();
-        TINT_DEFER({
-          buf.DecrementIndent();
-          line(&buf) << "}";
-          line(&buf);
-        });
-
-        {
-          auto l = line(&buf);
-          if (!EmitTypeAndName(l, value_ty, ast::StorageClass::kNone,
-                               ast::Access::kUndefined, "ignored")) {
-            return "";
-          }
-          l << ";";
-        }
-        line(&buf) << "buffer.InterlockedExchange(offset, value, ignored);";
-        return name;
-      }
-      case Op::kAtomicCompareExchangeWeak: {
-        auto* value_ty = TypeOf(expr->args[2])->UnwrapRef();
-
-        auto name = UniqueIdentifier("atomicCompareExchangeWeak");
-        {
-          auto fn = line(&buf);
-          if (!EmitTypeAndName(fn, result_ty, ast::StorageClass::kNone,
-                               ast::Access::kUndefined, name)) {
-            return "";
-          }
-          fn << "(RWByteAddressBuffer buffer, uint offset, ";
-          if (!EmitTypeAndName(fn, value_ty, ast::StorageClass::kNone,
-                               ast::Access::kUndefined, "compare")) {
-            return "";
-          }
-          fn << ", ";
-          if (!EmitTypeAndName(fn, value_ty, ast::StorageClass::kNone,
-                               ast::Access::kUndefined, "value")) {
-            return "";
-          }
-          fn << ") {";
-        }
-
-        buf.IncrementIndent();
-        TINT_DEFER({
-          buf.DecrementIndent();
-          line(&buf) << "}";
-          line(&buf);
-        });
-
-        {  // T result = {0, 0};
-          auto l = line(&buf);
-          if (!EmitTypeAndName(l, result_ty, ast::StorageClass::kNone,
-                               ast::Access::kUndefined, "result")) {
-            return "";
-          }
-          l << " = {0, 0};";
-        }
-        line(&buf) << "buffer.InterlockedCompareExchange(offset, compare, "
-                      "value, result.x);";
-        line(&buf) << "result.y = result.x == compare;";
-        line(&buf) << "return result;";
-        return name;
-      }
-      default:
-        break;
-    }
-    TINT_UNREACHABLE(Writer, diagnostics_)
-        << "unsupported atomic DecomposeMemoryAccess::Intrinsic::Op: "
-        << static_cast<int>(intrinsic->op);
-    return "";
-  };
-
-  auto func = utils::GetOrCreate(dma_intrinsics_,
-                                 DMAIntrinsic{intrinsic->op, intrinsic->type},
-                                 generate_helper);
-  if (func.empty()) {
-    return false;
-  }
-
-  out << func;
-  {
-    ScopedParen sp(out);
-    bool first = true;
-    for (auto* arg : expr->args) {
-      if (!first) {
-        out << ", ";
-      }
-      first = false;
-      if (!EmitExpression(out, arg)) {
+    auto func = utils::GetOrCreate(dma_intrinsics_, DMAIntrinsic{intrinsic->op, intrinsic->type},
+                                   generate_helper);
+    if (func.empty()) {
         return false;
-      }
     }
-  }
 
-  return true;
+    out << func;
+    {
+        ScopedParen sp(out);
+        bool first = true;
+        for (auto* arg : expr->args) {
+            if (!first) {
+                out << ", ";
+            }
+            first = false;
+            if (!EmitExpression(out, arg)) {
+                return false;
+            }
+        }
+    }
+
+    return true;
 }
 
 bool GeneratorImpl::EmitWorkgroupAtomicCall(std::ostream& out,
                                             const ast::CallExpression* expr,
                                             const sem::Builtin* builtin) {
-  std::string result = UniqueIdentifier("atomic_result");
+    std::string result = UniqueIdentifier("atomic_result");
 
-  if (!builtin->ReturnType()->Is<sem::Void>()) {
-    auto pre = line();
-    if (!EmitTypeAndName(pre, builtin->ReturnType(), ast::StorageClass::kNone,
-                         ast::Access::kUndefined, result)) {
-      return false;
-    }
-    pre << " = ";
-    if (!EmitZeroValue(pre, builtin->ReturnType())) {
-      return false;
-    }
-    pre << ";";
-  }
-
-  auto call = [&](const char* name) {
-    auto pre = line();
-    pre << name;
-
-    {
-      ScopedParen sp(pre);
-      for (size_t i = 0; i < expr->args.size(); i++) {
-        auto* arg = expr->args[i];
-        if (i > 0) {
-          pre << ", ";
-        }
-        if (i == 1 && builtin->Type() == sem::BuiltinType::kAtomicSub) {
-          // Sub uses InterlockedAdd with the operand negated.
-          pre << "-";
-        }
-        if (!EmitExpression(pre, arg)) {
-          return false;
-        }
-      }
-
-      pre << ", " << result;
-    }
-
-    pre << ";";
-
-    out << result;
-    return true;
-  };
-
-  switch (builtin->Type()) {
-    case sem::BuiltinType::kAtomicLoad: {
-      // HLSL does not have an InterlockedLoad, so we emulate it with
-      // InterlockedOr using 0 as the OR value
-      auto pre = line();
-      pre << "InterlockedOr";
-      {
-        ScopedParen sp(pre);
-        if (!EmitExpression(pre, expr->args[0])) {
-          return false;
-        }
-        pre << ", 0, " << result;
-      }
-      pre << ";";
-
-      out << result;
-      return true;
-    }
-    case sem::BuiltinType::kAtomicStore: {
-      // HLSL does not have an InterlockedStore, so we emulate it with
-      // InterlockedExchange and discard the returned value
-      {  // T result = 0;
+    if (!builtin->ReturnType()->Is<sem::Void>()) {
         auto pre = line();
-        auto* value_ty = builtin->Parameters()[1]->Type()->UnwrapRef();
-        if (!EmitTypeAndName(pre, value_ty, ast::StorageClass::kNone,
+        if (!EmitTypeAndName(pre, builtin->ReturnType(), ast::StorageClass::kNone,
                              ast::Access::kUndefined, result)) {
-          return false;
+            return false;
         }
         pre << " = ";
-        if (!EmitZeroValue(pre, value_ty)) {
-          return false;
+        if (!EmitZeroValue(pre, builtin->ReturnType())) {
+            return false;
         }
         pre << ";";
-      }
-
-      out << "InterlockedExchange";
-      {
-        ScopedParen sp(out);
-        if (!EmitExpression(out, expr->args[0])) {
-          return false;
-        }
-        out << ", ";
-        if (!EmitExpression(out, expr->args[1])) {
-          return false;
-        }
-        out << ", " << result;
-      }
-      return true;
     }
-    case sem::BuiltinType::kAtomicCompareExchangeWeak: {
-      auto* dest = expr->args[0];
-      auto* compare_value = expr->args[1];
-      auto* value = expr->args[2];
 
-      std::string compare = UniqueIdentifier("atomic_compare_value");
-
-      {  // T compare_value = <compare_value>;
+    auto call = [&](const char* name) {
         auto pre = line();
-        if (!EmitTypeAndName(pre, TypeOf(compare_value),
-                             ast::StorageClass::kNone, ast::Access::kUndefined,
-                             compare)) {
-          return false;
-        }
-        pre << " = ";
-        if (!EmitExpression(pre, compare_value)) {
-          return false;
-        }
-        pre << ";";
-      }
+        pre << name;
 
-      {  // InterlockedCompareExchange(dst, compare, value, result.x);
-        auto pre = line();
-        pre << "InterlockedCompareExchange";
         {
-          ScopedParen sp(pre);
-          if (!EmitExpression(pre, dest)) {
-            return false;
-          }
-          pre << ", " << compare << ", ";
-          if (!EmitExpression(pre, value)) {
-            return false;
-          }
-          pre << ", " << result << ".x";
+            ScopedParen sp(pre);
+            for (size_t i = 0; i < expr->args.size(); i++) {
+                auto* arg = expr->args[i];
+                if (i > 0) {
+                    pre << ", ";
+                }
+                if (i == 1 && builtin->Type() == sem::BuiltinType::kAtomicSub) {
+                    // Sub uses InterlockedAdd with the operand negated.
+                    pre << "-";
+                }
+                if (!EmitExpression(pre, arg)) {
+                    return false;
+                }
+            }
+
+            pre << ", " << result;
         }
+
         pre << ";";
-      }
 
-      {  // result.y = result.x == compare;
-        line() << result << ".y = " << result << ".x == " << compare << ";";
-      }
+        out << result;
+        return true;
+    };
 
-      out << result;
-      return true;
+    switch (builtin->Type()) {
+        case sem::BuiltinType::kAtomicLoad: {
+            // HLSL does not have an InterlockedLoad, so we emulate it with
+            // InterlockedOr using 0 as the OR value
+            auto pre = line();
+            pre << "InterlockedOr";
+            {
+                ScopedParen sp(pre);
+                if (!EmitExpression(pre, expr->args[0])) {
+                    return false;
+                }
+                pre << ", 0, " << result;
+            }
+            pre << ";";
+
+            out << result;
+            return true;
+        }
+        case sem::BuiltinType::kAtomicStore: {
+            // HLSL does not have an InterlockedStore, so we emulate it with
+            // InterlockedExchange and discard the returned value
+            {  // T result = 0;
+                auto pre = line();
+                auto* value_ty = builtin->Parameters()[1]->Type()->UnwrapRef();
+                if (!EmitTypeAndName(pre, value_ty, ast::StorageClass::kNone,
+                                     ast::Access::kUndefined, result)) {
+                    return false;
+                }
+                pre << " = ";
+                if (!EmitZeroValue(pre, value_ty)) {
+                    return false;
+                }
+                pre << ";";
+            }
+
+            out << "InterlockedExchange";
+            {
+                ScopedParen sp(out);
+                if (!EmitExpression(out, expr->args[0])) {
+                    return false;
+                }
+                out << ", ";
+                if (!EmitExpression(out, expr->args[1])) {
+                    return false;
+                }
+                out << ", " << result;
+            }
+            return true;
+        }
+        case sem::BuiltinType::kAtomicCompareExchangeWeak: {
+            auto* dest = expr->args[0];
+            auto* compare_value = expr->args[1];
+            auto* value = expr->args[2];
+
+            std::string compare = UniqueIdentifier("atomic_compare_value");
+
+            {  // T compare_value = <compare_value>;
+                auto pre = line();
+                if (!EmitTypeAndName(pre, TypeOf(compare_value), ast::StorageClass::kNone,
+                                     ast::Access::kUndefined, compare)) {
+                    return false;
+                }
+                pre << " = ";
+                if (!EmitExpression(pre, compare_value)) {
+                    return false;
+                }
+                pre << ";";
+            }
+
+            {  // InterlockedCompareExchange(dst, compare, value, result.x);
+                auto pre = line();
+                pre << "InterlockedCompareExchange";
+                {
+                    ScopedParen sp(pre);
+                    if (!EmitExpression(pre, dest)) {
+                        return false;
+                    }
+                    pre << ", " << compare << ", ";
+                    if (!EmitExpression(pre, value)) {
+                        return false;
+                    }
+                    pre << ", " << result << ".x";
+                }
+                pre << ";";
+            }
+
+            {  // result.y = result.x == compare;
+                line() << result << ".y = " << result << ".x == " << compare << ";";
+            }
+
+            out << result;
+            return true;
+        }
+
+        case sem::BuiltinType::kAtomicAdd:
+        case sem::BuiltinType::kAtomicSub:
+            return call("InterlockedAdd");
+
+        case sem::BuiltinType::kAtomicMax:
+            return call("InterlockedMax");
+
+        case sem::BuiltinType::kAtomicMin:
+            return call("InterlockedMin");
+
+        case sem::BuiltinType::kAtomicAnd:
+            return call("InterlockedAnd");
+
+        case sem::BuiltinType::kAtomicOr:
+            return call("InterlockedOr");
+
+        case sem::BuiltinType::kAtomicXor:
+            return call("InterlockedXor");
+
+        case sem::BuiltinType::kAtomicExchange:
+            return call("InterlockedExchange");
+
+        default:
+            break;
     }
 
-    case sem::BuiltinType::kAtomicAdd:
-    case sem::BuiltinType::kAtomicSub:
-      return call("InterlockedAdd");
-
-    case sem::BuiltinType::kAtomicMax:
-      return call("InterlockedMax");
-
-    case sem::BuiltinType::kAtomicMin:
-      return call("InterlockedMin");
-
-    case sem::BuiltinType::kAtomicAnd:
-      return call("InterlockedAnd");
-
-    case sem::BuiltinType::kAtomicOr:
-      return call("InterlockedOr");
-
-    case sem::BuiltinType::kAtomicXor:
-      return call("InterlockedXor");
-
-    case sem::BuiltinType::kAtomicExchange:
-      return call("InterlockedExchange");
-
-    default:
-      break;
-  }
-
-  TINT_UNREACHABLE(Writer, diagnostics_)
-      << "unsupported atomic builtin: " << builtin->Type();
-  return false;
+    TINT_UNREACHABLE(Writer, diagnostics_) << "unsupported atomic builtin: " << builtin->Type();
+    return false;
 }
 
-bool GeneratorImpl::EmitSelectCall(std::ostream& out,
-                                   const ast::CallExpression* expr) {
-  auto* expr_false = expr->args[0];
-  auto* expr_true = expr->args[1];
-  auto* expr_cond = expr->args[2];
-  ScopedParen paren(out);
-  if (!EmitExpression(out, expr_cond)) {
-    return false;
-  }
+bool GeneratorImpl::EmitSelectCall(std::ostream& out, const ast::CallExpression* expr) {
+    auto* expr_false = expr->args[0];
+    auto* expr_true = expr->args[1];
+    auto* expr_cond = expr->args[2];
+    ScopedParen paren(out);
+    if (!EmitExpression(out, expr_cond)) {
+        return false;
+    }
 
-  out << " ? ";
+    out << " ? ";
 
-  if (!EmitExpression(out, expr_true)) {
-    return false;
-  }
+    if (!EmitExpression(out, expr_true)) {
+        return false;
+    }
 
-  out << " : ";
+    out << " : ";
 
-  if (!EmitExpression(out, expr_false)) {
-    return false;
-  }
+    if (!EmitExpression(out, expr_false)) {
+        return false;
+    }
 
-  return true;
+    return true;
 }
 
 bool GeneratorImpl::EmitModfCall(std::ostream& out,
                                  const ast::CallExpression* expr,
                                  const sem::Builtin* builtin) {
-  return CallBuiltinHelper(
-      out, expr, builtin,
-      [&](TextBuffer* b, const std::vector<std::string>& params) {
-        auto* ty = builtin->Parameters()[0]->Type();
-        auto in = params[0];
+    return CallBuiltinHelper(
+        out, expr, builtin, [&](TextBuffer* b, const std::vector<std::string>& params) {
+            auto* ty = builtin->Parameters()[0]->Type();
+            auto in = params[0];
 
-        std::string width;
-        if (auto* vec = ty->As<sem::Vector>()) {
-          width = std::to_string(vec->Width());
-        }
+            std::string width;
+            if (auto* vec = ty->As<sem::Vector>()) {
+                width = std::to_string(vec->Width());
+            }
 
-        // Emit the builtin return type unique to this overload. This does not
-        // exist in the AST, so it will not be generated in Generate().
-        if (!EmitStructType(&helpers_,
-                            builtin->ReturnType()->As<sem::Struct>())) {
-          return false;
-        }
+            // Emit the builtin return type unique to this overload. This does not
+            // exist in the AST, so it will not be generated in Generate().
+            if (!EmitStructType(&helpers_, builtin->ReturnType()->As<sem::Struct>())) {
+                return false;
+            }
 
-        line(b) << "float" << width << " whole;";
-        line(b) << "float" << width << " fract = modf(" << in << ", whole);";
-        {
-          auto l = line(b);
-          if (!EmitType(l, builtin->ReturnType(), ast::StorageClass::kNone,
-                        ast::Access::kUndefined, "")) {
-            return false;
-          }
-          l << " result = {fract, whole};";
-        }
-        line(b) << "return result;";
-        return true;
-      });
+            line(b) << "float" << width << " whole;";
+            line(b) << "float" << width << " fract = modf(" << in << ", whole);";
+            {
+                auto l = line(b);
+                if (!EmitType(l, builtin->ReturnType(), ast::StorageClass::kNone,
+                              ast::Access::kUndefined, "")) {
+                    return false;
+                }
+                l << " result = {fract, whole};";
+            }
+            line(b) << "return result;";
+            return true;
+        });
 }
 
 bool GeneratorImpl::EmitFrexpCall(std::ostream& out,
                                   const ast::CallExpression* expr,
                                   const sem::Builtin* builtin) {
-  return CallBuiltinHelper(
-      out, expr, builtin,
-      [&](TextBuffer* b, const std::vector<std::string>& params) {
-        auto* ty = builtin->Parameters()[0]->Type();
-        auto in = params[0];
+    return CallBuiltinHelper(
+        out, expr, builtin, [&](TextBuffer* b, const std::vector<std::string>& params) {
+            auto* ty = builtin->Parameters()[0]->Type();
+            auto in = params[0];
 
-        std::string width;
-        if (auto* vec = ty->As<sem::Vector>()) {
-          width = std::to_string(vec->Width());
-        }
+            std::string width;
+            if (auto* vec = ty->As<sem::Vector>()) {
+                width = std::to_string(vec->Width());
+            }
 
-        // Emit the builtin return type unique to this overload. This does not
-        // exist in the AST, so it will not be generated in Generate().
-        if (!EmitStructType(&helpers_,
-                            builtin->ReturnType()->As<sem::Struct>())) {
-          return false;
-        }
+            // Emit the builtin return type unique to this overload. This does not
+            // exist in the AST, so it will not be generated in Generate().
+            if (!EmitStructType(&helpers_, builtin->ReturnType()->As<sem::Struct>())) {
+                return false;
+            }
 
-        line(b) << "float" << width << " exp;";
-        line(b) << "float" << width << " sig = frexp(" << in << ", exp);";
-        {
-          auto l = line(b);
-          if (!EmitType(l, builtin->ReturnType(), ast::StorageClass::kNone,
-                        ast::Access::kUndefined, "")) {
-            return false;
-          }
-          l << " result = {sig, int" << width << "(exp)};";
-        }
-        line(b) << "return result;";
-        return true;
-      });
+            line(b) << "float" << width << " exp;";
+            line(b) << "float" << width << " sig = frexp(" << in << ", exp);";
+            {
+                auto l = line(b);
+                if (!EmitType(l, builtin->ReturnType(), ast::StorageClass::kNone,
+                              ast::Access::kUndefined, "")) {
+                    return false;
+                }
+                l << " result = {sig, int" << width << "(exp)};";
+            }
+            line(b) << "return result;";
+            return true;
+        });
 }
 
 bool GeneratorImpl::EmitDegreesCall(std::ostream& out,
                                     const ast::CallExpression* expr,
                                     const sem::Builtin* builtin) {
-  return CallBuiltinHelper(
-      out, expr, builtin,
-      [&](TextBuffer* b, const std::vector<std::string>& params) {
-        line(b) << "return " << params[0] << " * " << std::setprecision(20)
-                << sem::kRadToDeg << ";";
-        return true;
-      });
+    return CallBuiltinHelper(out, expr, builtin,
+                             [&](TextBuffer* b, const std::vector<std::string>& params) {
+                                 line(b) << "return " << params[0] << " * " << std::setprecision(20)
+                                         << sem::kRadToDeg << ";";
+                                 return true;
+                             });
 }
 
 bool GeneratorImpl::EmitRadiansCall(std::ostream& out,
                                     const ast::CallExpression* expr,
                                     const sem::Builtin* builtin) {
-  return CallBuiltinHelper(
-      out, expr, builtin,
-      [&](TextBuffer* b, const std::vector<std::string>& params) {
-        line(b) << "return " << params[0] << " * " << std::setprecision(20)
-                << sem::kDegToRad << ";";
-        return true;
-      });
+    return CallBuiltinHelper(out, expr, builtin,
+                             [&](TextBuffer* b, const std::vector<std::string>& params) {
+                                 line(b) << "return " << params[0] << " * " << std::setprecision(20)
+                                         << sem::kDegToRad << ";";
+                                 return true;
+                             });
 }
 
 bool GeneratorImpl::EmitDataPackingCall(std::ostream& out,
                                         const ast::CallExpression* expr,
                                         const sem::Builtin* builtin) {
-  return CallBuiltinHelper(
-      out, expr, builtin,
-      [&](TextBuffer* b, const std::vector<std::string>& params) {
-        uint32_t dims = 2;
-        bool is_signed = false;
-        uint32_t scale = 65535;
-        if (builtin->Type() == sem::BuiltinType::kPack4x8snorm ||
-            builtin->Type() == sem::BuiltinType::kPack4x8unorm) {
-          dims = 4;
-          scale = 255;
-        }
-        if (builtin->Type() == sem::BuiltinType::kPack4x8snorm ||
-            builtin->Type() == sem::BuiltinType::kPack2x16snorm) {
-          is_signed = true;
-          scale = (scale - 1) / 2;
-        }
-        switch (builtin->Type()) {
-          case sem::BuiltinType::kPack4x8snorm:
-          case sem::BuiltinType::kPack4x8unorm:
-          case sem::BuiltinType::kPack2x16snorm:
-          case sem::BuiltinType::kPack2x16unorm: {
-            {
-              auto l = line(b);
-              l << (is_signed ? "" : "u") << "int" << dims
-                << " i = " << (is_signed ? "" : "u") << "int" << dims
-                << "(round(clamp(" << params[0] << ", "
-                << (is_signed ? "-1.0" : "0.0") << ", 1.0) * " << scale
-                << ".0))";
-              if (is_signed) {
-                l << " & " << (dims == 4 ? "0xff" : "0xffff");
-              }
-              l << ";";
+    return CallBuiltinHelper(
+        out, expr, builtin, [&](TextBuffer* b, const std::vector<std::string>& params) {
+            uint32_t dims = 2;
+            bool is_signed = false;
+            uint32_t scale = 65535;
+            if (builtin->Type() == sem::BuiltinType::kPack4x8snorm ||
+                builtin->Type() == sem::BuiltinType::kPack4x8unorm) {
+                dims = 4;
+                scale = 255;
             }
-            {
-              auto l = line(b);
-              l << "return ";
-              if (is_signed) {
-                l << "asuint";
-              }
-              l << "(i.x | i.y << " << (32 / dims);
-              if (dims == 4) {
-                l << " | i.z << 16 | i.w << 24";
-              }
-              l << ");";
+            if (builtin->Type() == sem::BuiltinType::kPack4x8snorm ||
+                builtin->Type() == sem::BuiltinType::kPack2x16snorm) {
+                is_signed = true;
+                scale = (scale - 1) / 2;
             }
-            break;
-          }
-          case sem::BuiltinType::kPack2x16float: {
-            line(b) << "uint2 i = f32tof16(" << params[0] << ");";
-            line(b) << "return i.x | (i.y << 16);";
-            break;
-          }
-          default:
-            diagnostics_.add_error(
-                diag::System::Writer,
-                "Internal error: unhandled data packing builtin");
-            return false;
-        }
+            switch (builtin->Type()) {
+                case sem::BuiltinType::kPack4x8snorm:
+                case sem::BuiltinType::kPack4x8unorm:
+                case sem::BuiltinType::kPack2x16snorm:
+                case sem::BuiltinType::kPack2x16unorm: {
+                    {
+                        auto l = line(b);
+                        l << (is_signed ? "" : "u") << "int" << dims
+                          << " i = " << (is_signed ? "" : "u") << "int" << dims << "(round(clamp("
+                          << params[0] << ", " << (is_signed ? "-1.0" : "0.0") << ", 1.0) * "
+                          << scale << ".0))";
+                        if (is_signed) {
+                            l << " & " << (dims == 4 ? "0xff" : "0xffff");
+                        }
+                        l << ";";
+                    }
+                    {
+                        auto l = line(b);
+                        l << "return ";
+                        if (is_signed) {
+                            l << "asuint";
+                        }
+                        l << "(i.x | i.y << " << (32 / dims);
+                        if (dims == 4) {
+                            l << " | i.z << 16 | i.w << 24";
+                        }
+                        l << ");";
+                    }
+                    break;
+                }
+                case sem::BuiltinType::kPack2x16float: {
+                    line(b) << "uint2 i = f32tof16(" << params[0] << ");";
+                    line(b) << "return i.x | (i.y << 16);";
+                    break;
+                }
+                default:
+                    diagnostics_.add_error(diag::System::Writer,
+                                           "Internal error: unhandled data packing builtin");
+                    return false;
+            }
 
-        return true;
-      });
+            return true;
+        });
 }
 
 bool GeneratorImpl::EmitDataUnpackingCall(std::ostream& out,
                                           const ast::CallExpression* expr,
                                           const sem::Builtin* builtin) {
-  return CallBuiltinHelper(
-      out, expr, builtin,
-      [&](TextBuffer* b, const std::vector<std::string>& params) {
-        uint32_t dims = 2;
-        bool is_signed = false;
-        uint32_t scale = 65535;
-        if (builtin->Type() == sem::BuiltinType::kUnpack4x8snorm ||
-            builtin->Type() == sem::BuiltinType::kUnpack4x8unorm) {
-          dims = 4;
-          scale = 255;
-        }
-        if (builtin->Type() == sem::BuiltinType::kUnpack4x8snorm ||
-            builtin->Type() == sem::BuiltinType::kUnpack2x16snorm) {
-          is_signed = true;
-          scale = (scale - 1) / 2;
-        }
-        switch (builtin->Type()) {
-          case sem::BuiltinType::kUnpack4x8snorm:
-          case sem::BuiltinType::kUnpack2x16snorm: {
-            line(b) << "int j = int(" << params[0] << ");";
-            {  // Perform sign extension on the converted values.
-              auto l = line(b);
-              l << "int" << dims << " i = int" << dims << "(";
-              if (dims == 2) {
-                l << "j << 16, j) >> 16";
-              } else {
-                l << "j << 24, j << 16, j << 8, j) >> 24";
-              }
-              l << ";";
+    return CallBuiltinHelper(
+        out, expr, builtin, [&](TextBuffer* b, const std::vector<std::string>& params) {
+            uint32_t dims = 2;
+            bool is_signed = false;
+            uint32_t scale = 65535;
+            if (builtin->Type() == sem::BuiltinType::kUnpack4x8snorm ||
+                builtin->Type() == sem::BuiltinType::kUnpack4x8unorm) {
+                dims = 4;
+                scale = 255;
             }
-            line(b) << "return clamp(float" << dims << "(i) / " << scale
-                    << ".0, " << (is_signed ? "-1.0" : "0.0") << ", 1.0);";
-            break;
-          }
-          case sem::BuiltinType::kUnpack4x8unorm:
-          case sem::BuiltinType::kUnpack2x16unorm: {
-            line(b) << "uint j = " << params[0] << ";";
-            {
-              auto l = line(b);
-              l << "uint" << dims << " i = uint" << dims << "(";
-              l << "j & " << (dims == 2 ? "0xffff" : "0xff") << ", ";
-              if (dims == 4) {
-                l << "(j >> " << (32 / dims)
-                  << ") & 0xff, (j >> 16) & 0xff, j >> 24";
-              } else {
-                l << "j >> " << (32 / dims);
-              }
-              l << ");";
+            if (builtin->Type() == sem::BuiltinType::kUnpack4x8snorm ||
+                builtin->Type() == sem::BuiltinType::kUnpack2x16snorm) {
+                is_signed = true;
+                scale = (scale - 1) / 2;
             }
-            line(b) << "return float" << dims << "(i) / " << scale << ".0;";
-            break;
-          }
-          case sem::BuiltinType::kUnpack2x16float:
-            line(b) << "uint i = " << params[0] << ";";
-            line(b) << "return f16tof32(uint2(i & 0xffff, i >> 16));";
-            break;
-          default:
-            diagnostics_.add_error(
-                diag::System::Writer,
-                "Internal error: unhandled data packing builtin");
-            return false;
-        }
+            switch (builtin->Type()) {
+                case sem::BuiltinType::kUnpack4x8snorm:
+                case sem::BuiltinType::kUnpack2x16snorm: {
+                    line(b) << "int j = int(" << params[0] << ");";
+                    {  // Perform sign extension on the converted values.
+                        auto l = line(b);
+                        l << "int" << dims << " i = int" << dims << "(";
+                        if (dims == 2) {
+                            l << "j << 16, j) >> 16";
+                        } else {
+                            l << "j << 24, j << 16, j << 8, j) >> 24";
+                        }
+                        l << ";";
+                    }
+                    line(b) << "return clamp(float" << dims << "(i) / " << scale << ".0, "
+                            << (is_signed ? "-1.0" : "0.0") << ", 1.0);";
+                    break;
+                }
+                case sem::BuiltinType::kUnpack4x8unorm:
+                case sem::BuiltinType::kUnpack2x16unorm: {
+                    line(b) << "uint j = " << params[0] << ";";
+                    {
+                        auto l = line(b);
+                        l << "uint" << dims << " i = uint" << dims << "(";
+                        l << "j & " << (dims == 2 ? "0xffff" : "0xff") << ", ";
+                        if (dims == 4) {
+                            l << "(j >> " << (32 / dims) << ") & 0xff, (j >> 16) & 0xff, j >> 24";
+                        } else {
+                            l << "j >> " << (32 / dims);
+                        }
+                        l << ");";
+                    }
+                    line(b) << "return float" << dims << "(i) / " << scale << ".0;";
+                    break;
+                }
+                case sem::BuiltinType::kUnpack2x16float:
+                    line(b) << "uint i = " << params[0] << ";";
+                    line(b) << "return f16tof32(uint2(i & 0xffff, i >> 16));";
+                    break;
+                default:
+                    diagnostics_.add_error(diag::System::Writer,
+                                           "Internal error: unhandled data packing builtin");
+                    return false;
+            }
 
-        return true;
-      });
+            return true;
+        });
 }
 
-bool GeneratorImpl::EmitBarrierCall(std::ostream& out,
-                                    const sem::Builtin* builtin) {
-  // TODO(crbug.com/tint/661): Combine sequential barriers to a single
-  // instruction.
-  if (builtin->Type() == sem::BuiltinType::kWorkgroupBarrier) {
-    out << "GroupMemoryBarrierWithGroupSync()";
-  } else if (builtin->Type() == sem::BuiltinType::kStorageBarrier) {
-    out << "DeviceMemoryBarrierWithGroupSync()";
-  } else {
-    TINT_UNREACHABLE(Writer, diagnostics_)
-        << "unexpected barrier builtin type " << sem::str(builtin->Type());
-    return false;
-  }
-  return true;
+bool GeneratorImpl::EmitBarrierCall(std::ostream& out, const sem::Builtin* builtin) {
+    // TODO(crbug.com/tint/661): Combine sequential barriers to a single
+    // instruction.
+    if (builtin->Type() == sem::BuiltinType::kWorkgroupBarrier) {
+        out << "GroupMemoryBarrierWithGroupSync()";
+    } else if (builtin->Type() == sem::BuiltinType::kStorageBarrier) {
+        out << "DeviceMemoryBarrierWithGroupSync()";
+    } else {
+        TINT_UNREACHABLE(Writer, diagnostics_)
+            << "unexpected barrier builtin type " << sem::str(builtin->Type());
+        return false;
+    }
+    return true;
 }
 
 bool GeneratorImpl::EmitTextureCall(std::ostream& out,
                                     const sem::Call* call,
                                     const sem::Builtin* builtin) {
-  using Usage = sem::ParameterUsage;
+    using Usage = sem::ParameterUsage;
 
-  auto& signature = builtin->Signature();
-  auto* expr = call->Declaration();
-  auto arguments = expr->args;
+    auto& signature = builtin->Signature();
+    auto* expr = call->Declaration();
+    auto arguments = expr->args;
 
-  // Returns the argument with the given usage
-  auto arg = [&](Usage usage) {
-    int idx = signature.IndexOf(usage);
-    return (idx >= 0) ? arguments[idx] : nullptr;
-  };
+    // Returns the argument with the given usage
+    auto arg = [&](Usage usage) {
+        int idx = signature.IndexOf(usage);
+        return (idx >= 0) ? arguments[idx] : nullptr;
+    };
 
-  auto* texture = arg(Usage::kTexture);
-  if (!texture) {
-    TINT_ICE(Writer, diagnostics_) << "missing texture argument";
-    return false;
-  }
+    auto* texture = arg(Usage::kTexture);
+    if (!texture) {
+        TINT_ICE(Writer, diagnostics_) << "missing texture argument";
+        return false;
+    }
 
-  auto* texture_type = TypeOf(texture)->UnwrapRef()->As<sem::Texture>();
+    auto* texture_type = TypeOf(texture)->UnwrapRef()->As<sem::Texture>();
 
-  switch (builtin->Type()) {
-    case sem::BuiltinType::kTextureDimensions:
-    case sem::BuiltinType::kTextureNumLayers:
-    case sem::BuiltinType::kTextureNumLevels:
-    case sem::BuiltinType::kTextureNumSamples: {
-      // All of these builtins use the GetDimensions() method on the texture
-      bool is_ms = texture_type->IsAnyOf<sem::MultisampledTexture,
-                                         sem::DepthMultisampledTexture>();
-      int num_dimensions = 0;
-      std::string swizzle;
-
-      switch (builtin->Type()) {
+    switch (builtin->Type()) {
         case sem::BuiltinType::kTextureDimensions:
-          switch (texture_type->dim()) {
-            case ast::TextureDimension::kNone:
-              TINT_ICE(Writer, diagnostics_) << "texture dimension is kNone";
-              return false;
-            case ast::TextureDimension::k1d:
-              num_dimensions = 1;
-              break;
-            case ast::TextureDimension::k2d:
-              num_dimensions = is_ms ? 3 : 2;
-              swizzle = is_ms ? ".xy" : "";
-              break;
-            case ast::TextureDimension::k2dArray:
-              num_dimensions = is_ms ? 4 : 3;
-              swizzle = ".xy";
-              break;
-            case ast::TextureDimension::k3d:
-              num_dimensions = 3;
-              break;
-            case ast::TextureDimension::kCube:
-              num_dimensions = 2;
-              break;
-            case ast::TextureDimension::kCubeArray:
-              num_dimensions = 3;
-              swizzle = ".xy";
-              break;
-          }
-          break;
         case sem::BuiltinType::kTextureNumLayers:
-          switch (texture_type->dim()) {
-            default:
-              TINT_ICE(Writer, diagnostics_)
-                  << "texture dimension is not arrayed";
-              return false;
-            case ast::TextureDimension::k2dArray:
-              num_dimensions = is_ms ? 4 : 3;
-              swizzle = ".z";
-              break;
-            case ast::TextureDimension::kCubeArray:
-              num_dimensions = 3;
-              swizzle = ".z";
-              break;
-          }
-          break;
         case sem::BuiltinType::kTextureNumLevels:
-          switch (texture_type->dim()) {
-            default:
-              TINT_ICE(Writer, diagnostics_)
-                  << "texture dimension does not support mips";
-              return false;
-            case ast::TextureDimension::k1d:
-              num_dimensions = 2;
-              swizzle = ".y";
-              break;
-            case ast::TextureDimension::k2d:
-            case ast::TextureDimension::kCube:
-              num_dimensions = 3;
-              swizzle = ".z";
-              break;
-            case ast::TextureDimension::k2dArray:
-            case ast::TextureDimension::k3d:
-            case ast::TextureDimension::kCubeArray:
-              num_dimensions = 4;
-              swizzle = ".w";
-              break;
-          }
-          break;
-        case sem::BuiltinType::kTextureNumSamples:
-          switch (texture_type->dim()) {
-            default:
-              TINT_ICE(Writer, diagnostics_)
-                  << "texture dimension does not support multisampling";
-              return false;
-            case ast::TextureDimension::k2d:
-              num_dimensions = 3;
-              swizzle = ".z";
-              break;
-            case ast::TextureDimension::k2dArray:
-              num_dimensions = 4;
-              swizzle = ".w";
-              break;
-          }
-          break;
-        default:
-          TINT_ICE(Writer, diagnostics_) << "unexpected builtin";
-          return false;
-      }
+        case sem::BuiltinType::kTextureNumSamples: {
+            // All of these builtins use the GetDimensions() method on the texture
+            bool is_ms =
+                texture_type->IsAnyOf<sem::MultisampledTexture, sem::DepthMultisampledTexture>();
+            int num_dimensions = 0;
+            std::string swizzle;
 
-      auto* level_arg = arg(Usage::kLevel);
-
-      if (level_arg) {
-        // `NumberOfLevels` is a non-optional argument if `MipLevel` was passed.
-        // Increment the number of dimensions for the temporary vector to
-        // accommodate this.
-        num_dimensions++;
-
-        // If the swizzle was empty, the expression will evaluate to the whole
-        // vector. As we've grown the vector by one element, we now need to
-        // swizzle to keep the result expression equivalent.
-        if (swizzle.empty()) {
-          static constexpr const char* swizzles[] = {"", ".x", ".xy", ".xyz"};
-          swizzle = swizzles[num_dimensions - 1];
-        }
-      }
-
-      if (num_dimensions > 4) {
-        TINT_ICE(Writer, diagnostics_)
-            << "Texture query builtin temporary vector has " << num_dimensions
-            << " dimensions";
-        return false;
-      }
-
-      // Declare a variable to hold the queried texture info
-      auto dims = UniqueIdentifier(kTempNamePrefix);
-      if (num_dimensions == 1) {
-        line() << "int " << dims << ";";
-      } else {
-        line() << "int" << num_dimensions << " " << dims << ";";
-      }
-
-      {  // texture.GetDimensions(...)
-        auto pre = line();
-        if (!EmitExpression(pre, texture)) {
-          return false;
-        }
-        pre << ".GetDimensions(";
-
-        if (level_arg) {
-          if (!EmitExpression(pre, level_arg)) {
-            return false;
-          }
-          pre << ", ";
-        } else if (builtin->Type() == sem::BuiltinType::kTextureNumLevels) {
-          pre << "0, ";
-        }
-
-        if (num_dimensions == 1) {
-          pre << dims;
-        } else {
-          static constexpr char xyzw[] = {'x', 'y', 'z', 'w'};
-          if (num_dimensions < 0 || num_dimensions > 4) {
-            TINT_ICE(Writer, diagnostics_)
-                << "vector dimensions are " << num_dimensions;
-            return false;
-          }
-          for (int i = 0; i < num_dimensions; i++) {
-            if (i > 0) {
-              pre << ", ";
+            switch (builtin->Type()) {
+                case sem::BuiltinType::kTextureDimensions:
+                    switch (texture_type->dim()) {
+                        case ast::TextureDimension::kNone:
+                            TINT_ICE(Writer, diagnostics_) << "texture dimension is kNone";
+                            return false;
+                        case ast::TextureDimension::k1d:
+                            num_dimensions = 1;
+                            break;
+                        case ast::TextureDimension::k2d:
+                            num_dimensions = is_ms ? 3 : 2;
+                            swizzle = is_ms ? ".xy" : "";
+                            break;
+                        case ast::TextureDimension::k2dArray:
+                            num_dimensions = is_ms ? 4 : 3;
+                            swizzle = ".xy";
+                            break;
+                        case ast::TextureDimension::k3d:
+                            num_dimensions = 3;
+                            break;
+                        case ast::TextureDimension::kCube:
+                            num_dimensions = 2;
+                            break;
+                        case ast::TextureDimension::kCubeArray:
+                            num_dimensions = 3;
+                            swizzle = ".xy";
+                            break;
+                    }
+                    break;
+                case sem::BuiltinType::kTextureNumLayers:
+                    switch (texture_type->dim()) {
+                        default:
+                            TINT_ICE(Writer, diagnostics_) << "texture dimension is not arrayed";
+                            return false;
+                        case ast::TextureDimension::k2dArray:
+                            num_dimensions = is_ms ? 4 : 3;
+                            swizzle = ".z";
+                            break;
+                        case ast::TextureDimension::kCubeArray:
+                            num_dimensions = 3;
+                            swizzle = ".z";
+                            break;
+                    }
+                    break;
+                case sem::BuiltinType::kTextureNumLevels:
+                    switch (texture_type->dim()) {
+                        default:
+                            TINT_ICE(Writer, diagnostics_)
+                                << "texture dimension does not support mips";
+                            return false;
+                        case ast::TextureDimension::k1d:
+                            num_dimensions = 2;
+                            swizzle = ".y";
+                            break;
+                        case ast::TextureDimension::k2d:
+                        case ast::TextureDimension::kCube:
+                            num_dimensions = 3;
+                            swizzle = ".z";
+                            break;
+                        case ast::TextureDimension::k2dArray:
+                        case ast::TextureDimension::k3d:
+                        case ast::TextureDimension::kCubeArray:
+                            num_dimensions = 4;
+                            swizzle = ".w";
+                            break;
+                    }
+                    break;
+                case sem::BuiltinType::kTextureNumSamples:
+                    switch (texture_type->dim()) {
+                        default:
+                            TINT_ICE(Writer, diagnostics_)
+                                << "texture dimension does not support multisampling";
+                            return false;
+                        case ast::TextureDimension::k2d:
+                            num_dimensions = 3;
+                            swizzle = ".z";
+                            break;
+                        case ast::TextureDimension::k2dArray:
+                            num_dimensions = 4;
+                            swizzle = ".w";
+                            break;
+                    }
+                    break;
+                default:
+                    TINT_ICE(Writer, diagnostics_) << "unexpected builtin";
+                    return false;
             }
-            pre << dims << "." << xyzw[i];
-          }
+
+            auto* level_arg = arg(Usage::kLevel);
+
+            if (level_arg) {
+                // `NumberOfLevels` is a non-optional argument if `MipLevel` was passed.
+                // Increment the number of dimensions for the temporary vector to
+                // accommodate this.
+                num_dimensions++;
+
+                // If the swizzle was empty, the expression will evaluate to the whole
+                // vector. As we've grown the vector by one element, we now need to
+                // swizzle to keep the result expression equivalent.
+                if (swizzle.empty()) {
+                    static constexpr const char* swizzles[] = {"", ".x", ".xy", ".xyz"};
+                    swizzle = swizzles[num_dimensions - 1];
+                }
+            }
+
+            if (num_dimensions > 4) {
+                TINT_ICE(Writer, diagnostics_) << "Texture query builtin temporary vector has "
+                                               << num_dimensions << " dimensions";
+                return false;
+            }
+
+            // Declare a variable to hold the queried texture info
+            auto dims = UniqueIdentifier(kTempNamePrefix);
+            if (num_dimensions == 1) {
+                line() << "int " << dims << ";";
+            } else {
+                line() << "int" << num_dimensions << " " << dims << ";";
+            }
+
+            {  // texture.GetDimensions(...)
+                auto pre = line();
+                if (!EmitExpression(pre, texture)) {
+                    return false;
+                }
+                pre << ".GetDimensions(";
+
+                if (level_arg) {
+                    if (!EmitExpression(pre, level_arg)) {
+                        return false;
+                    }
+                    pre << ", ";
+                } else if (builtin->Type() == sem::BuiltinType::kTextureNumLevels) {
+                    pre << "0, ";
+                }
+
+                if (num_dimensions == 1) {
+                    pre << dims;
+                } else {
+                    static constexpr char xyzw[] = {'x', 'y', 'z', 'w'};
+                    if (num_dimensions < 0 || num_dimensions > 4) {
+                        TINT_ICE(Writer, diagnostics_)
+                            << "vector dimensions are " << num_dimensions;
+                        return false;
+                    }
+                    for (int i = 0; i < num_dimensions; i++) {
+                        if (i > 0) {
+                            pre << ", ";
+                        }
+                        pre << dims << "." << xyzw[i];
+                    }
+                }
+
+                pre << ");";
+            }
+
+            // The out parameters of the GetDimensions() call is now in temporary
+            // `dims` variable. This may be packed with other data, so the final
+            // expression may require a swizzle.
+            out << dims << swizzle;
+            return true;
         }
-
-        pre << ");";
-      }
-
-      // The out parameters of the GetDimensions() call is now in temporary
-      // `dims` variable. This may be packed with other data, so the final
-      // expression may require a swizzle.
-      out << dims << swizzle;
-      return true;
+        default:
+            break;
     }
-    default:
-      break;
-  }
 
-  if (!EmitExpression(out, texture))
-    return false;
-
-  // If pack_level_in_coords is true, then the mip level will be appended as the
-  // last value of the coordinates argument. If the WGSL builtin overload does
-  // not have a level parameter and pack_level_in_coords is true, then a zero
-  // mip level will be inserted.
-  bool pack_level_in_coords = false;
-
-  uint32_t hlsl_ret_width = 4u;
-
-  switch (builtin->Type()) {
-    case sem::BuiltinType::kTextureSample:
-      out << ".Sample(";
-      break;
-    case sem::BuiltinType::kTextureSampleBias:
-      out << ".SampleBias(";
-      break;
-    case sem::BuiltinType::kTextureSampleLevel:
-      out << ".SampleLevel(";
-      break;
-    case sem::BuiltinType::kTextureSampleGrad:
-      out << ".SampleGrad(";
-      break;
-    case sem::BuiltinType::kTextureSampleCompare:
-      out << ".SampleCmp(";
-      hlsl_ret_width = 1;
-      break;
-    case sem::BuiltinType::kTextureSampleCompareLevel:
-      out << ".SampleCmpLevelZero(";
-      hlsl_ret_width = 1;
-      break;
-    case sem::BuiltinType::kTextureLoad:
-      out << ".Load(";
-      // Multisampled textures do not support mip-levels.
-      if (!texture_type->Is<sem::MultisampledTexture>()) {
-        pack_level_in_coords = true;
-      }
-      break;
-    case sem::BuiltinType::kTextureGather:
-      out << ".Gather";
-      if (builtin->Parameters()[0]->Usage() ==
-          sem::ParameterUsage::kComponent) {
-        switch (call->Arguments()[0]->ConstantValue().Elements()[0].i32) {
-          case 0:
-            out << "Red";
-            break;
-          case 1:
-            out << "Green";
-            break;
-          case 2:
-            out << "Blue";
-            break;
-          case 3:
-            out << "Alpha";
-            break;
-        }
-      }
-      out << "(";
-      break;
-    case sem::BuiltinType::kTextureGatherCompare:
-      out << ".GatherCmp(";
-      break;
-    case sem::BuiltinType::kTextureStore:
-      out << "[";
-      break;
-    default:
-      diagnostics_.add_error(
-          diag::System::Writer,
-          "Internal compiler error: Unhandled texture builtin '" +
-              std::string(builtin->str()) + "'");
-      return false;
-  }
-
-  if (auto* sampler = arg(Usage::kSampler)) {
-    if (!EmitExpression(out, sampler))
-      return false;
-    out << ", ";
-  }
-
-  auto* param_coords = arg(Usage::kCoords);
-  if (!param_coords) {
-    TINT_ICE(Writer, diagnostics_) << "missing coords argument";
-    return false;
-  }
-
-  auto emit_vector_appended_with_i32_zero = [&](const ast::Expression* vector) {
-    auto* i32 = builder_.create<sem::I32>();
-    auto* zero = builder_.Expr(0);
-    auto* stmt = builder_.Sem().Get(vector)->Stmt();
-    builder_.Sem().Add(
-        zero, builder_.create<sem::Expression>(zero, i32, stmt, sem::Constant{},
-                                               /* has_side_effects */ false));
-    auto* packed = AppendVector(&builder_, vector, zero);
-    return EmitExpression(out, packed->Declaration());
-  };
-
-  auto emit_vector_appended_with_level = [&](const ast::Expression* vector) {
-    if (auto* level = arg(Usage::kLevel)) {
-      auto* packed = AppendVector(&builder_, vector, level);
-      return EmitExpression(out, packed->Declaration());
-    }
-    return emit_vector_appended_with_i32_zero(vector);
-  };
-
-  if (auto* array_index = arg(Usage::kArrayIndex)) {
-    // Array index needs to be appended to the coordinates.
-    auto* packed = AppendVector(&builder_, param_coords, array_index);
-    if (pack_level_in_coords) {
-      // Then mip level needs to be appended to the coordinates.
-      if (!emit_vector_appended_with_level(packed->Declaration())) {
+    if (!EmitExpression(out, texture))
         return false;
-      }
+
+    // If pack_level_in_coords is true, then the mip level will be appended as the
+    // last value of the coordinates argument. If the WGSL builtin overload does
+    // not have a level parameter and pack_level_in_coords is true, then a zero
+    // mip level will be inserted.
+    bool pack_level_in_coords = false;
+
+    uint32_t hlsl_ret_width = 4u;
+
+    switch (builtin->Type()) {
+        case sem::BuiltinType::kTextureSample:
+            out << ".Sample(";
+            break;
+        case sem::BuiltinType::kTextureSampleBias:
+            out << ".SampleBias(";
+            break;
+        case sem::BuiltinType::kTextureSampleLevel:
+            out << ".SampleLevel(";
+            break;
+        case sem::BuiltinType::kTextureSampleGrad:
+            out << ".SampleGrad(";
+            break;
+        case sem::BuiltinType::kTextureSampleCompare:
+            out << ".SampleCmp(";
+            hlsl_ret_width = 1;
+            break;
+        case sem::BuiltinType::kTextureSampleCompareLevel:
+            out << ".SampleCmpLevelZero(";
+            hlsl_ret_width = 1;
+            break;
+        case sem::BuiltinType::kTextureLoad:
+            out << ".Load(";
+            // Multisampled textures do not support mip-levels.
+            if (!texture_type->Is<sem::MultisampledTexture>()) {
+                pack_level_in_coords = true;
+            }
+            break;
+        case sem::BuiltinType::kTextureGather:
+            out << ".Gather";
+            if (builtin->Parameters()[0]->Usage() == sem::ParameterUsage::kComponent) {
+                switch (call->Arguments()[0]->ConstantValue().Elements()[0].i32) {
+                    case 0:
+                        out << "Red";
+                        break;
+                    case 1:
+                        out << "Green";
+                        break;
+                    case 2:
+                        out << "Blue";
+                        break;
+                    case 3:
+                        out << "Alpha";
+                        break;
+                }
+            }
+            out << "(";
+            break;
+        case sem::BuiltinType::kTextureGatherCompare:
+            out << ".GatherCmp(";
+            break;
+        case sem::BuiltinType::kTextureStore:
+            out << "[";
+            break;
+        default:
+            diagnostics_.add_error(diag::System::Writer,
+                                   "Internal compiler error: Unhandled texture builtin '" +
+                                       std::string(builtin->str()) + "'");
+            return false;
+    }
+
+    if (auto* sampler = arg(Usage::kSampler)) {
+        if (!EmitExpression(out, sampler))
+            return false;
+        out << ", ";
+    }
+
+    auto* param_coords = arg(Usage::kCoords);
+    if (!param_coords) {
+        TINT_ICE(Writer, diagnostics_) << "missing coords argument";
+        return false;
+    }
+
+    auto emit_vector_appended_with_i32_zero = [&](const ast::Expression* vector) {
+        auto* i32 = builder_.create<sem::I32>();
+        auto* zero = builder_.Expr(0_i);
+        auto* stmt = builder_.Sem().Get(vector)->Stmt();
+        builder_.Sem().Add(zero, builder_.create<sem::Expression>(zero, i32, stmt, sem::Constant{},
+                                                                  /* has_side_effects */ false));
+        auto* packed = AppendVector(&builder_, vector, zero);
+        return EmitExpression(out, packed->Declaration());
+    };
+
+    auto emit_vector_appended_with_level = [&](const ast::Expression* vector) {
+        if (auto* level = arg(Usage::kLevel)) {
+            auto* packed = AppendVector(&builder_, vector, level);
+            return EmitExpression(out, packed->Declaration());
+        }
+        return emit_vector_appended_with_i32_zero(vector);
+    };
+
+    if (auto* array_index = arg(Usage::kArrayIndex)) {
+        // Array index needs to be appended to the coordinates.
+        auto* packed = AppendVector(&builder_, param_coords, array_index);
+        if (pack_level_in_coords) {
+            // Then mip level needs to be appended to the coordinates.
+            if (!emit_vector_appended_with_level(packed->Declaration())) {
+                return false;
+            }
+        } else {
+            if (!EmitExpression(out, packed->Declaration())) {
+                return false;
+            }
+        }
+    } else if (pack_level_in_coords) {
+        // Mip level needs to be appended to the coordinates.
+        if (!emit_vector_appended_with_level(param_coords)) {
+            return false;
+        }
     } else {
-      if (!EmitExpression(out, packed->Declaration())) {
-        return false;
-      }
+        if (!EmitExpression(out, param_coords)) {
+            return false;
+        }
     }
-  } else if (pack_level_in_coords) {
-    // Mip level needs to be appended to the coordinates.
-    if (!emit_vector_appended_with_level(param_coords)) {
-      return false;
-    }
-  } else {
-    if (!EmitExpression(out, param_coords)) {
-      return false;
-    }
-  }
 
-  for (auto usage : {Usage::kDepthRef, Usage::kBias, Usage::kLevel, Usage::kDdx,
-                     Usage::kDdy, Usage::kSampleIndex, Usage::kOffset}) {
-    if (usage == Usage::kLevel && pack_level_in_coords) {
-      continue;  // mip level already packed in coordinates.
+    for (auto usage : {Usage::kDepthRef, Usage::kBias, Usage::kLevel, Usage::kDdx, Usage::kDdy,
+                       Usage::kSampleIndex, Usage::kOffset}) {
+        if (usage == Usage::kLevel && pack_level_in_coords) {
+            continue;  // mip level already packed in coordinates.
+        }
+        if (auto* e = arg(usage)) {
+            out << ", ";
+            if (!EmitExpression(out, e)) {
+                return false;
+            }
+        }
     }
-    if (auto* e = arg(usage)) {
-      out << ", ";
-      if (!EmitExpression(out, e)) {
-        return false;
-      }
-    }
-  }
 
-  if (builtin->Type() == sem::BuiltinType::kTextureStore) {
-    out << "] = ";
-    if (!EmitExpression(out, arg(Usage::kValue))) {
-      return false;
-    }
-  } else {
-    out << ")";
+    if (builtin->Type() == sem::BuiltinType::kTextureStore) {
+        out << "] = ";
+        if (!EmitExpression(out, arg(Usage::kValue))) {
+            return false;
+        }
+    } else {
+        out << ")";
 
-    // If the builtin return type does not match the number of elements of the
-    // HLSL builtin, we need to swizzle the expression to generate the correct
-    // number of components.
-    uint32_t wgsl_ret_width = 1;
-    if (auto* vec = builtin->ReturnType()->As<sem::Vector>()) {
-      wgsl_ret_width = vec->Width();
+        // If the builtin return type does not match the number of elements of the
+        // HLSL builtin, we need to swizzle the expression to generate the correct
+        // number of components.
+        uint32_t wgsl_ret_width = 1;
+        if (auto* vec = builtin->ReturnType()->As<sem::Vector>()) {
+            wgsl_ret_width = vec->Width();
+        }
+        if (wgsl_ret_width < hlsl_ret_width) {
+            out << ".";
+            for (uint32_t i = 0; i < wgsl_ret_width; i++) {
+                out << "xyz"[i];
+            }
+        }
+        if (wgsl_ret_width > hlsl_ret_width) {
+            TINT_ICE(Writer, diagnostics_)
+                << "WGSL return width (" << wgsl_ret_width << ") is wider than HLSL return width ("
+                << hlsl_ret_width << ") for " << builtin->Type();
+            return false;
+        }
     }
-    if (wgsl_ret_width < hlsl_ret_width) {
-      out << ".";
-      for (uint32_t i = 0; i < wgsl_ret_width; i++) {
-        out << "xyz"[i];
-      }
-    }
-    if (wgsl_ret_width > hlsl_ret_width) {
-      TINT_ICE(Writer, diagnostics_)
-          << "WGSL return width (" << wgsl_ret_width
-          << ") is wider than HLSL return width (" << hlsl_ret_width << ") for "
-          << builtin->Type();
-      return false;
-    }
-  }
 
-  return true;
+    return true;
 }
 
 std::string GeneratorImpl::generate_builtin_name(const sem::Builtin* builtin) {
-  switch (builtin->Type()) {
-    case sem::BuiltinType::kAbs:
-    case sem::BuiltinType::kAcos:
-    case sem::BuiltinType::kAll:
-    case sem::BuiltinType::kAny:
-    case sem::BuiltinType::kAsin:
-    case sem::BuiltinType::kAtan:
-    case sem::BuiltinType::kAtan2:
-    case sem::BuiltinType::kCeil:
-    case sem::BuiltinType::kClamp:
-    case sem::BuiltinType::kCos:
-    case sem::BuiltinType::kCosh:
-    case sem::BuiltinType::kCross:
-    case sem::BuiltinType::kDeterminant:
-    case sem::BuiltinType::kDistance:
-    case sem::BuiltinType::kDot:
-    case sem::BuiltinType::kExp:
-    case sem::BuiltinType::kExp2:
-    case sem::BuiltinType::kFloor:
-    case sem::BuiltinType::kFrexp:
-    case sem::BuiltinType::kLdexp:
-    case sem::BuiltinType::kLength:
-    case sem::BuiltinType::kLog:
-    case sem::BuiltinType::kLog2:
-    case sem::BuiltinType::kMax:
-    case sem::BuiltinType::kMin:
-    case sem::BuiltinType::kModf:
-    case sem::BuiltinType::kNormalize:
-    case sem::BuiltinType::kPow:
-    case sem::BuiltinType::kReflect:
-    case sem::BuiltinType::kRefract:
-    case sem::BuiltinType::kRound:
-    case sem::BuiltinType::kSign:
-    case sem::BuiltinType::kSin:
-    case sem::BuiltinType::kSinh:
-    case sem::BuiltinType::kSqrt:
-    case sem::BuiltinType::kStep:
-    case sem::BuiltinType::kTan:
-    case sem::BuiltinType::kTanh:
-    case sem::BuiltinType::kTranspose:
-    case sem::BuiltinType::kTrunc:
-      return builtin->str();
-    case sem::BuiltinType::kCountOneBits:
-      return "countbits";
-    case sem::BuiltinType::kDpdx:
-      return "ddx";
-    case sem::BuiltinType::kDpdxCoarse:
-      return "ddx_coarse";
-    case sem::BuiltinType::kDpdxFine:
-      return "ddx_fine";
-    case sem::BuiltinType::kDpdy:
-      return "ddy";
-    case sem::BuiltinType::kDpdyCoarse:
-      return "ddy_coarse";
-    case sem::BuiltinType::kDpdyFine:
-      return "ddy_fine";
-    case sem::BuiltinType::kFaceForward:
-      return "faceforward";
-    case sem::BuiltinType::kFract:
-      return "frac";
-    case sem::BuiltinType::kFma:
-      return "mad";
-    case sem::BuiltinType::kFwidth:
-    case sem::BuiltinType::kFwidthCoarse:
-    case sem::BuiltinType::kFwidthFine:
-      return "fwidth";
-    case sem::BuiltinType::kInverseSqrt:
-      return "rsqrt";
-    case sem::BuiltinType::kMix:
-      return "lerp";
-    case sem::BuiltinType::kReverseBits:
-      return "reversebits";
-    case sem::BuiltinType::kSmoothstep:
-    case sem::BuiltinType::kSmoothStep:
-      return "smoothstep";
-    default:
-      diagnostics_.add_error(
-          diag::System::Writer,
-          "Unknown builtin method: " + std::string(builtin->str()));
-  }
+    switch (builtin->Type()) {
+        case sem::BuiltinType::kAbs:
+        case sem::BuiltinType::kAcos:
+        case sem::BuiltinType::kAll:
+        case sem::BuiltinType::kAny:
+        case sem::BuiltinType::kAsin:
+        case sem::BuiltinType::kAtan:
+        case sem::BuiltinType::kAtan2:
+        case sem::BuiltinType::kCeil:
+        case sem::BuiltinType::kClamp:
+        case sem::BuiltinType::kCos:
+        case sem::BuiltinType::kCosh:
+        case sem::BuiltinType::kCross:
+        case sem::BuiltinType::kDeterminant:
+        case sem::BuiltinType::kDistance:
+        case sem::BuiltinType::kDot:
+        case sem::BuiltinType::kExp:
+        case sem::BuiltinType::kExp2:
+        case sem::BuiltinType::kFloor:
+        case sem::BuiltinType::kFrexp:
+        case sem::BuiltinType::kLdexp:
+        case sem::BuiltinType::kLength:
+        case sem::BuiltinType::kLog:
+        case sem::BuiltinType::kLog2:
+        case sem::BuiltinType::kMax:
+        case sem::BuiltinType::kMin:
+        case sem::BuiltinType::kModf:
+        case sem::BuiltinType::kNormalize:
+        case sem::BuiltinType::kPow:
+        case sem::BuiltinType::kReflect:
+        case sem::BuiltinType::kRefract:
+        case sem::BuiltinType::kRound:
+        case sem::BuiltinType::kSign:
+        case sem::BuiltinType::kSin:
+        case sem::BuiltinType::kSinh:
+        case sem::BuiltinType::kSqrt:
+        case sem::BuiltinType::kStep:
+        case sem::BuiltinType::kTan:
+        case sem::BuiltinType::kTanh:
+        case sem::BuiltinType::kTranspose:
+        case sem::BuiltinType::kTrunc:
+            return builtin->str();
+        case sem::BuiltinType::kCountOneBits:
+            return "countbits";
+        case sem::BuiltinType::kDpdx:
+            return "ddx";
+        case sem::BuiltinType::kDpdxCoarse:
+            return "ddx_coarse";
+        case sem::BuiltinType::kDpdxFine:
+            return "ddx_fine";
+        case sem::BuiltinType::kDpdy:
+            return "ddy";
+        case sem::BuiltinType::kDpdyCoarse:
+            return "ddy_coarse";
+        case sem::BuiltinType::kDpdyFine:
+            return "ddy_fine";
+        case sem::BuiltinType::kFaceForward:
+            return "faceforward";
+        case sem::BuiltinType::kFract:
+            return "frac";
+        case sem::BuiltinType::kFma:
+            return "mad";
+        case sem::BuiltinType::kFwidth:
+        case sem::BuiltinType::kFwidthCoarse:
+        case sem::BuiltinType::kFwidthFine:
+            return "fwidth";
+        case sem::BuiltinType::kInverseSqrt:
+            return "rsqrt";
+        case sem::BuiltinType::kMix:
+            return "lerp";
+        case sem::BuiltinType::kReverseBits:
+            return "reversebits";
+        case sem::BuiltinType::kSmoothstep:
+        case sem::BuiltinType::kSmoothStep:
+            return "smoothstep";
+        default:
+            diagnostics_.add_error(diag::System::Writer,
+                                   "Unknown builtin method: " + std::string(builtin->str()));
+    }
 
-  return "";
+    return "";
 }
 
 bool GeneratorImpl::EmitCase(const ast::SwitchStatement* s, size_t case_idx) {
-  auto* stmt = s->body[case_idx];
-  if (stmt->IsDefault()) {
-    line() << "default: {";
-  } else {
-    for (auto* selector : stmt->selectors) {
-      auto out = line();
-      out << "case ";
-      if (!EmitLiteral(out, selector)) {
+    auto* stmt = s->body[case_idx];
+    if (stmt->IsDefault()) {
+        line() << "default: {";
+    } else {
+        for (auto* selector : stmt->selectors) {
+            auto out = line();
+            out << "case ";
+            if (!EmitLiteral(out, selector)) {
+                return false;
+            }
+            out << ":";
+            if (selector == stmt->selectors.back()) {
+                out << " {";
+            }
+        }
+    }
+
+    increment_indent();
+    TINT_DEFER({
+        decrement_indent();
+        line() << "}";
+    });
+
+    // Emit the case statement
+    if (!EmitStatements(stmt->body->statements)) {
         return false;
-      }
-      out << ":";
-      if (selector == stmt->selectors.back()) {
-        out << " {";
-      }
     }
-  }
 
-  increment_indent();
-  TINT_DEFER({
-    decrement_indent();
-    line() << "}";
-  });
-
-  // Emit the case statement
-  if (!EmitStatements(stmt->body->statements)) {
-    return false;
-  }
-
-  // Inline all fallthrough case statements. FXC cannot handle fallthroughs.
-  while (tint::Is<ast::FallthroughStatement>(stmt->body->Last())) {
-    case_idx++;
-    stmt = s->body[case_idx];
-    // Generate each fallthrough case statement in a new block. This is done to
-    // prevent symbol collision of variables declared in these cases statements.
-    if (!EmitBlock(stmt->body)) {
-      return false;
+    // Inline all fallthrough case statements. FXC cannot handle fallthroughs.
+    while (tint::Is<ast::FallthroughStatement>(stmt->body->Last())) {
+        case_idx++;
+        stmt = s->body[case_idx];
+        // Generate each fallthrough case statement in a new block. This is done to
+        // prevent symbol collision of variables declared in these cases statements.
+        if (!EmitBlock(stmt->body)) {
+            return false;
+        }
     }
-  }
 
-  if (!tint::IsAnyOf<ast::BreakStatement, ast::FallthroughStatement>(
-          stmt->body->Last())) {
-    line() << "break;";
-  }
+    if (!tint::IsAnyOf<ast::BreakStatement, ast::FallthroughStatement>(stmt->body->Last())) {
+        line() << "break;";
+    }
 
-  return true;
+    return true;
 }
 
 bool GeneratorImpl::EmitContinue(const ast::ContinueStatement*) {
-  if (!emit_continuing_()) {
-    return false;
-  }
-  line() << "continue;";
-  return true;
+    if (!emit_continuing_()) {
+        return false;
+    }
+    line() << "continue;";
+    return true;
 }
 
 bool GeneratorImpl::EmitDiscard(const ast::DiscardStatement*) {
-  // TODO(dsinclair): Verify this is correct when the discard semantics are
-  // defined for WGSL (https://github.com/gpuweb/gpuweb/issues/361)
-  line() << "discard;";
-  return true;
+    // TODO(dsinclair): Verify this is correct when the discard semantics are
+    // defined for WGSL (https://github.com/gpuweb/gpuweb/issues/361)
+    line() << "discard;";
+    return true;
 }
 
-bool GeneratorImpl::EmitExpression(std::ostream& out,
-                                   const ast::Expression* expr) {
-  return Switch(
-      expr,
-      [&](const ast::IndexAccessorExpression* a) {  //
-        return EmitIndexAccessor(out, a);
-      },
-      [&](const ast::BinaryExpression* b) {  //
-        return EmitBinary(out, b);
-      },
-      [&](const ast::BitcastExpression* b) {  //
-        return EmitBitcast(out, b);
-      },
-      [&](const ast::CallExpression* c) {  //
-        return EmitCall(out, c);
-      },
-      [&](const ast::IdentifierExpression* i) {  //
-        return EmitIdentifier(out, i);
-      },
-      [&](const ast::LiteralExpression* l) {  //
-        return EmitLiteral(out, l);
-      },
-      [&](const ast::MemberAccessorExpression* m) {  //
-        return EmitMemberAccessor(out, m);
-      },
-      [&](const ast::UnaryOpExpression* u) {  //
-        return EmitUnaryOp(out, u);
-      },
-      [&](Default) {  //
-        diagnostics_.add_error(
-            diag::System::Writer,
-            "unknown expression type: " + std::string(expr->TypeInfo().name));
-        return false;
-      });
+bool GeneratorImpl::EmitExpression(std::ostream& out, const ast::Expression* expr) {
+    return Switch(
+        expr,
+        [&](const ast::IndexAccessorExpression* a) {  //
+            return EmitIndexAccessor(out, a);
+        },
+        [&](const ast::BinaryExpression* b) {  //
+            return EmitBinary(out, b);
+        },
+        [&](const ast::BitcastExpression* b) {  //
+            return EmitBitcast(out, b);
+        },
+        [&](const ast::CallExpression* c) {  //
+            return EmitCall(out, c);
+        },
+        [&](const ast::IdentifierExpression* i) {  //
+            return EmitIdentifier(out, i);
+        },
+        [&](const ast::LiteralExpression* l) {  //
+            return EmitLiteral(out, l);
+        },
+        [&](const ast::MemberAccessorExpression* m) {  //
+            return EmitMemberAccessor(out, m);
+        },
+        [&](const ast::UnaryOpExpression* u) {  //
+            return EmitUnaryOp(out, u);
+        },
+        [&](Default) {  //
+            diagnostics_.add_error(diag::System::Writer, "unknown expression type: " +
+                                                             std::string(expr->TypeInfo().name));
+            return false;
+        });
 }
 
-bool GeneratorImpl::EmitIdentifier(std::ostream& out,
-                                   const ast::IdentifierExpression* expr) {
-  out << builder_.Symbols().NameFor(expr->symbol);
-  return true;
+bool GeneratorImpl::EmitIdentifier(std::ostream& out, const ast::IdentifierExpression* expr) {
+    out << builder_.Symbols().NameFor(expr->symbol);
+    return true;
 }
 
 bool GeneratorImpl::EmitIf(const ast::IfStatement* stmt) {
-  {
-    auto out = line();
-    out << "if (";
-    if (!EmitExpression(out, stmt->condition)) {
-      return false;
-    }
-    out << ") {";
-  }
-
-  if (!EmitStatementsWithIndent(stmt->body->statements)) {
-    return false;
-  }
-
-  for (auto* e : stmt->else_statements) {
-    if (e->condition) {
-      line() << "} else {";
-      increment_indent();
-
-      {
+    {
         auto out = line();
         out << "if (";
-        if (!EmitExpression(out, e->condition)) {
-          return false;
+        if (!EmitExpression(out, stmt->condition)) {
+            return false;
         }
         out << ") {";
-      }
-    } else {
-      line() << "} else {";
     }
 
-    if (!EmitStatementsWithIndent(e->body->statements)) {
-      return false;
+    if (!EmitStatementsWithIndent(stmt->body->statements)) {
+        return false;
     }
-  }
 
-  line() << "}";
-
-  for (auto* e : stmt->else_statements) {
-    if (e->condition) {
-      decrement_indent();
-      line() << "}";
+    if (stmt->else_statement) {
+        line() << "} else {";
+        if (auto* block = stmt->else_statement->As<ast::BlockStatement>()) {
+            if (!EmitStatementsWithIndent(block->statements)) {
+                return false;
+            }
+        } else {
+            if (!EmitStatementsWithIndent({stmt->else_statement})) {
+                return false;
+            }
+        }
     }
-  }
-  return true;
+    line() << "}";
+
+    return true;
 }
 
 bool GeneratorImpl::EmitFunction(const ast::Function* func) {
-  auto* sem = builder_.Sem().Get(func);
+    auto* sem = builder_.Sem().Get(func);
 
-  if (ast::HasAttribute<ast::InternalAttribute>(func->attributes)) {
-    // An internal function. Do not emit.
-    return true;
-  }
+    if (ast::HasAttribute<ast::InternalAttribute>(func->attributes)) {
+        // An internal function. Do not emit.
+        return true;
+    }
 
-  {
-    auto out = line();
-    auto name = builder_.Symbols().NameFor(func->symbol);
-    // If the function returns an array, then we need to declare a typedef for
-    // this.
-    if (sem->ReturnType()->Is<sem::Array>()) {
-      auto typedef_name = UniqueIdentifier(name + "_ret");
-      auto pre = line();
-      pre << "typedef ";
-      if (!EmitTypeAndName(pre, sem->ReturnType(), ast::StorageClass::kNone,
-                           ast::Access::kReadWrite, typedef_name)) {
-        return false;
-      }
-      pre << ";";
-      out << typedef_name;
+    {
+        auto out = line();
+        auto name = builder_.Symbols().NameFor(func->symbol);
+        // If the function returns an array, then we need to declare a typedef for
+        // this.
+        if (sem->ReturnType()->Is<sem::Array>()) {
+            auto typedef_name = UniqueIdentifier(name + "_ret");
+            auto pre = line();
+            pre << "typedef ";
+            if (!EmitTypeAndName(pre, sem->ReturnType(), ast::StorageClass::kNone,
+                                 ast::Access::kReadWrite, typedef_name)) {
+                return false;
+            }
+            pre << ";";
+            out << typedef_name;
+        } else {
+            if (!EmitType(out, sem->ReturnType(), ast::StorageClass::kNone, ast::Access::kReadWrite,
+                          "")) {
+                return false;
+            }
+        }
+
+        out << " " << name << "(";
+
+        bool first = true;
+
+        for (auto* v : sem->Parameters()) {
+            if (!first) {
+                out << ", ";
+            }
+            first = false;
+
+            auto const* type = v->Type();
+
+            if (auto* ptr = type->As<sem::Pointer>()) {
+                // Transform pointer parameters in to `inout` parameters.
+                // The WGSL spec is highly restrictive in what can be passed in pointer
+                // parameters, which allows for this transformation. See:
+                // https://gpuweb.github.io/gpuweb/wgsl/#function-restriction
+                out << "inout ";
+                type = ptr->StoreType();
+            }
+
+            // Note: WGSL only allows for StorageClass::kNone on parameters, however
+            // the sanitizer transforms generates load / store functions for storage
+            // or uniform buffers. These functions have a buffer parameter with
+            // StorageClass::kStorage or StorageClass::kUniform. This is required to
+            // correctly translate the parameter to a [RW]ByteAddressBuffer for
+            // storage buffers and a uint4[N] for uniform buffers.
+            if (!EmitTypeAndName(out, type, v->StorageClass(), v->Access(),
+                                 builder_.Symbols().NameFor(v->Declaration()->symbol))) {
+                return false;
+            }
+        }
+        out << ") {";
+    }
+
+    if (sem->HasDiscard() && !sem->ReturnType()->Is<sem::Void>()) {
+        // BUG(crbug.com/tint/1081): work around non-void functions with discard
+        // failing compilation sometimes
+        if (!EmitFunctionBodyWithDiscard(func)) {
+            return false;
+        }
     } else {
-      if (!EmitType(out, sem->ReturnType(), ast::StorageClass::kNone,
-                    ast::Access::kReadWrite, "")) {
-        return false;
-      }
+        if (!EmitStatementsWithIndent(func->body->statements)) {
+            return false;
+        }
     }
 
-    out << " " << name << "(";
+    line() << "}";
 
-    bool first = true;
-
-    for (auto* v : sem->Parameters()) {
-      if (!first) {
-        out << ", ";
-      }
-      first = false;
-
-      auto const* type = v->Type();
-
-      if (auto* ptr = type->As<sem::Pointer>()) {
-        // Transform pointer parameters in to `inout` parameters.
-        // The WGSL spec is highly restrictive in what can be passed in pointer
-        // parameters, which allows for this transformation. See:
-        // https://gpuweb.github.io/gpuweb/wgsl/#function-restriction
-        out << "inout ";
-        type = ptr->StoreType();
-      }
-
-      // Note: WGSL only allows for StorageClass::kNone on parameters, however
-      // the sanitizer transforms generates load / store functions for storage
-      // or uniform buffers. These functions have a buffer parameter with
-      // StorageClass::kStorage or StorageClass::kUniform. This is required to
-      // correctly translate the parameter to a [RW]ByteAddressBuffer for
-      // storage buffers and a uint4[N] for uniform buffers.
-      if (!EmitTypeAndName(
-              out, type, v->StorageClass(), v->Access(),
-              builder_.Symbols().NameFor(v->Declaration()->symbol))) {
-        return false;
-      }
-    }
-    out << ") {";
-  }
-
-  if (sem->HasDiscard() && !sem->ReturnType()->Is<sem::Void>()) {
-    // BUG(crbug.com/tint/1081): work around non-void functions with discard
-    // failing compilation sometimes
-    if (!EmitFunctionBodyWithDiscard(func)) {
-      return false;
-    }
-  } else {
-    if (!EmitStatementsWithIndent(func->body->statements)) {
-      return false;
-    }
-  }
-
-  line() << "}";
-
-  return true;
+    return true;
 }
 
 bool GeneratorImpl::EmitFunctionBodyWithDiscard(const ast::Function* func) {
-  // FXC sometimes fails to compile functions that discard with 'Not all control
-  // paths return a value'. We work around this by wrapping the function body
-  // within an "if (true) { <body> } return <default return type obj>;" so that
-  // there is always an (unused) return statement.
+    // FXC sometimes fails to compile functions that discard with 'Not all control
+    // paths return a value'. We work around this by wrapping the function body
+    // within an "if (true) { <body> } return <default return type obj>;" so that
+    // there is always an (unused) return statement.
 
-  auto* sem = builder_.Sem().Get(func);
-  TINT_ASSERT(Writer, sem->HasDiscard() && !sem->ReturnType()->Is<sem::Void>());
+    auto* sem = builder_.Sem().Get(func);
+    TINT_ASSERT(Writer, sem->HasDiscard() && !sem->ReturnType()->Is<sem::Void>());
 
-  ScopedIndent si(this);
-  line() << "if (true) {";
+    ScopedIndent si(this);
+    line() << "if (true) {";
 
-  if (!EmitStatementsWithIndent(func->body->statements)) {
-    return false;
-  }
-
-  line() << "}";
-
-  // Return an unused result that matches the type of the return value
-  auto name = builder_.Symbols().NameFor(builder_.Symbols().New("unused"));
-  {
-    auto out = line();
-    if (!EmitTypeAndName(out, sem->ReturnType(), ast::StorageClass::kNone,
-                         ast::Access::kReadWrite, name)) {
-      return false;
+    if (!EmitStatementsWithIndent(func->body->statements)) {
+        return false;
     }
-    out << ";";
-  }
-  line() << "return " << name << ";";
 
-  return true;
+    line() << "}";
+
+    // Return an unused result that matches the type of the return value
+    auto name = builder_.Symbols().NameFor(builder_.Symbols().New("unused"));
+    {
+        auto out = line();
+        if (!EmitTypeAndName(out, sem->ReturnType(), ast::StorageClass::kNone,
+                             ast::Access::kReadWrite, name)) {
+            return false;
+        }
+        out << ";";
+    }
+    line() << "return " << name << ";";
+
+    return true;
 }
 
 bool GeneratorImpl::EmitGlobalVariable(const ast::Variable* global) {
-  if (global->is_const) {
-    return EmitProgramConstVariable(global);
-  }
+    if (global->is_const) {
+        return EmitProgramConstVariable(global);
+    }
 
-  auto* sem = builder_.Sem().Get(global);
-  switch (sem->StorageClass()) {
-    case ast::StorageClass::kUniform:
-      return EmitUniformVariable(sem);
-    case ast::StorageClass::kStorage:
-      return EmitStorageVariable(sem);
-    case ast::StorageClass::kUniformConstant:
-      return EmitHandleVariable(sem);
-    case ast::StorageClass::kPrivate:
-      return EmitPrivateVariable(sem);
-    case ast::StorageClass::kWorkgroup:
-      return EmitWorkgroupVariable(sem);
-    default:
-      break;
-  }
+    auto* sem = builder_.Sem().Get(global);
+    switch (sem->StorageClass()) {
+        case ast::StorageClass::kUniform:
+            return EmitUniformVariable(sem);
+        case ast::StorageClass::kStorage:
+            return EmitStorageVariable(sem);
+        case ast::StorageClass::kHandle:
+            return EmitHandleVariable(sem);
+        case ast::StorageClass::kPrivate:
+            return EmitPrivateVariable(sem);
+        case ast::StorageClass::kWorkgroup:
+            return EmitWorkgroupVariable(sem);
+        default:
+            break;
+    }
 
-  TINT_ICE(Writer, diagnostics_)
-      << "unhandled storage class " << sem->StorageClass();
-  return false;
+    TINT_ICE(Writer, diagnostics_) << "unhandled storage class " << sem->StorageClass();
+    return false;
 }
 
 bool GeneratorImpl::EmitUniformVariable(const sem::Variable* var) {
-  auto* decl = var->Declaration();
-  auto binding_point = decl->BindingPoint();
-  auto* type = var->Type()->UnwrapRef();
-  auto name = builder_.Symbols().NameFor(decl->symbol);
-  line() << "cbuffer cbuffer_" << name << RegisterAndSpace('b', binding_point)
-         << " {";
+    auto* decl = var->Declaration();
+    auto binding_point = decl->BindingPoint();
+    auto* type = var->Type()->UnwrapRef();
+    auto name = builder_.Symbols().NameFor(decl->symbol);
+    line() << "cbuffer cbuffer_" << name << RegisterAndSpace('b', binding_point) << " {";
 
-  {
-    ScopedIndent si(this);
-    auto out = line();
-    if (!EmitTypeAndName(out, type, ast::StorageClass::kUniform, var->Access(),
-                         name)) {
-      return false;
+    {
+        ScopedIndent si(this);
+        auto out = line();
+        if (!EmitTypeAndName(out, type, ast::StorageClass::kUniform, var->Access(), name)) {
+            return false;
+        }
+        out << ";";
     }
-    out << ";";
-  }
 
-  line() << "};";
+    line() << "};";
 
-  return true;
+    return true;
 }
 
 bool GeneratorImpl::EmitStorageVariable(const sem::Variable* var) {
-  auto* decl = var->Declaration();
-  auto* type = var->Type()->UnwrapRef();
-  auto out = line();
-  if (!EmitTypeAndName(out, type, ast::StorageClass::kStorage, var->Access(),
-                       builder_.Symbols().NameFor(decl->symbol))) {
-    return false;
-  }
+    auto* decl = var->Declaration();
+    auto* type = var->Type()->UnwrapRef();
+    auto out = line();
+    if (!EmitTypeAndName(out, type, ast::StorageClass::kStorage, var->Access(),
+                         builder_.Symbols().NameFor(decl->symbol))) {
+        return false;
+    }
 
-  out << RegisterAndSpace(var->Access() == ast::Access::kRead ? 't' : 'u',
-                          decl->BindingPoint())
-      << ";";
+    out << RegisterAndSpace(var->Access() == ast::Access::kRead ? 't' : 'u', decl->BindingPoint())
+        << ";";
 
-  return true;
+    return true;
 }
 
 bool GeneratorImpl::EmitHandleVariable(const sem::Variable* var) {
-  auto* decl = var->Declaration();
-  auto* unwrapped_type = var->Type()->UnwrapRef();
-  auto out = line();
+    auto* decl = var->Declaration();
+    auto* unwrapped_type = var->Type()->UnwrapRef();
+    auto out = line();
 
-  auto name = builder_.Symbols().NameFor(decl->symbol);
-  auto* type = var->Type()->UnwrapRef();
-  if (!EmitTypeAndName(out, type, var->StorageClass(), var->Access(), name)) {
-    return false;
-  }
-
-  const char* register_space = nullptr;
-
-  if (unwrapped_type->Is<sem::Texture>()) {
-    register_space = "t";
-    if (unwrapped_type->Is<sem::StorageTexture>()) {
-      register_space = "u";
+    auto name = builder_.Symbols().NameFor(decl->symbol);
+    auto* type = var->Type()->UnwrapRef();
+    if (!EmitTypeAndName(out, type, var->StorageClass(), var->Access(), name)) {
+        return false;
     }
-  } else if (unwrapped_type->Is<sem::Sampler>()) {
-    register_space = "s";
-  }
 
-  if (register_space) {
-    auto bp = decl->BindingPoint();
-    out << " : register(" << register_space << bp.binding->value << ", space"
-        << bp.group->value << ")";
-  }
+    const char* register_space = nullptr;
 
-  out << ";";
-  return true;
+    if (unwrapped_type->Is<sem::Texture>()) {
+        register_space = "t";
+        if (unwrapped_type->Is<sem::StorageTexture>()) {
+            register_space = "u";
+        }
+    } else if (unwrapped_type->Is<sem::Sampler>()) {
+        register_space = "s";
+    }
+
+    if (register_space) {
+        auto bp = decl->BindingPoint();
+        out << " : register(" << register_space << bp.binding->value << ", space" << bp.group->value
+            << ")";
+    }
+
+    out << ";";
+    return true;
 }
 
 bool GeneratorImpl::EmitPrivateVariable(const sem::Variable* var) {
-  auto* decl = var->Declaration();
-  auto out = line();
+    auto* decl = var->Declaration();
+    auto out = line();
 
-  out << "static ";
+    out << "static ";
 
-  auto name = builder_.Symbols().NameFor(decl->symbol);
-  auto* type = var->Type()->UnwrapRef();
-  if (!EmitTypeAndName(out, type, var->StorageClass(), var->Access(), name)) {
-    return false;
-  }
-
-  out << " = ";
-  if (auto* constructor = decl->constructor) {
-    if (!EmitExpression(out, constructor)) {
-      return false;
+    auto name = builder_.Symbols().NameFor(decl->symbol);
+    auto* type = var->Type()->UnwrapRef();
+    if (!EmitTypeAndName(out, type, var->StorageClass(), var->Access(), name)) {
+        return false;
     }
-  } else {
-    if (!EmitZeroValue(out, var->Type()->UnwrapRef())) {
-      return false;
-    }
-  }
 
-  out << ";";
-  return true;
+    out << " = ";
+    if (auto* constructor = decl->constructor) {
+        if (!EmitExpression(out, constructor)) {
+            return false;
+        }
+    } else {
+        if (!EmitZeroValue(out, var->Type()->UnwrapRef())) {
+            return false;
+        }
+    }
+
+    out << ";";
+    return true;
 }
 
 bool GeneratorImpl::EmitWorkgroupVariable(const sem::Variable* var) {
-  auto* decl = var->Declaration();
-  auto out = line();
+    auto* decl = var->Declaration();
+    auto out = line();
 
-  out << "groupshared ";
+    out << "groupshared ";
 
-  auto name = builder_.Symbols().NameFor(decl->symbol);
-  auto* type = var->Type()->UnwrapRef();
-  if (!EmitTypeAndName(out, type, var->StorageClass(), var->Access(), name)) {
-    return false;
-  }
-
-  if (auto* constructor = decl->constructor) {
-    out << " = ";
-    if (!EmitExpression(out, constructor)) {
-      return false;
+    auto name = builder_.Symbols().NameFor(decl->symbol);
+    auto* type = var->Type()->UnwrapRef();
+    if (!EmitTypeAndName(out, type, var->StorageClass(), var->Access(), name)) {
+        return false;
     }
-  }
 
-  out << ";";
-  return true;
+    if (auto* constructor = decl->constructor) {
+        out << " = ";
+        if (!EmitExpression(out, constructor)) {
+            return false;
+        }
+    }
+
+    out << ";";
+    return true;
 }
 
 std::string GeneratorImpl::builtin_to_attribute(ast::Builtin builtin) const {
-  switch (builtin) {
-    case ast::Builtin::kPosition:
-      return "SV_Position";
-    case ast::Builtin::kVertexIndex:
-      return "SV_VertexID";
-    case ast::Builtin::kInstanceIndex:
-      return "SV_InstanceID";
-    case ast::Builtin::kFrontFacing:
-      return "SV_IsFrontFace";
-    case ast::Builtin::kFragDepth:
-      return "SV_Depth";
-    case ast::Builtin::kLocalInvocationId:
-      return "SV_GroupThreadID";
-    case ast::Builtin::kLocalInvocationIndex:
-      return "SV_GroupIndex";
-    case ast::Builtin::kGlobalInvocationId:
-      return "SV_DispatchThreadID";
-    case ast::Builtin::kWorkgroupId:
-      return "SV_GroupID";
-    case ast::Builtin::kSampleIndex:
-      return "SV_SampleIndex";
-    case ast::Builtin::kSampleMask:
-      return "SV_Coverage";
-    default:
-      break;
-  }
-  return "";
+    switch (builtin) {
+        case ast::Builtin::kPosition:
+            return "SV_Position";
+        case ast::Builtin::kVertexIndex:
+            return "SV_VertexID";
+        case ast::Builtin::kInstanceIndex:
+            return "SV_InstanceID";
+        case ast::Builtin::kFrontFacing:
+            return "SV_IsFrontFace";
+        case ast::Builtin::kFragDepth:
+            return "SV_Depth";
+        case ast::Builtin::kLocalInvocationId:
+            return "SV_GroupThreadID";
+        case ast::Builtin::kLocalInvocationIndex:
+            return "SV_GroupIndex";
+        case ast::Builtin::kGlobalInvocationId:
+            return "SV_DispatchThreadID";
+        case ast::Builtin::kWorkgroupId:
+            return "SV_GroupID";
+        case ast::Builtin::kSampleIndex:
+            return "SV_SampleIndex";
+        case ast::Builtin::kSampleMask:
+            return "SV_Coverage";
+        default:
+            break;
+    }
+    return "";
 }
 
-std::string GeneratorImpl::interpolation_to_modifiers(
-    ast::InterpolationType type,
-    ast::InterpolationSampling sampling) const {
-  std::string modifiers;
-  switch (type) {
-    case ast::InterpolationType::kPerspective:
-      modifiers += "linear ";
-      break;
-    case ast::InterpolationType::kLinear:
-      modifiers += "noperspective ";
-      break;
-    case ast::InterpolationType::kFlat:
-      modifiers += "nointerpolation ";
-      break;
-  }
-  switch (sampling) {
-    case ast::InterpolationSampling::kCentroid:
-      modifiers += "centroid ";
-      break;
-    case ast::InterpolationSampling::kSample:
-      modifiers += "sample ";
-      break;
-    case ast::InterpolationSampling::kCenter:
-    case ast::InterpolationSampling::kNone:
-      break;
-  }
-  return modifiers;
+std::string GeneratorImpl::interpolation_to_modifiers(ast::InterpolationType type,
+                                                      ast::InterpolationSampling sampling) const {
+    std::string modifiers;
+    switch (type) {
+        case ast::InterpolationType::kPerspective:
+            modifiers += "linear ";
+            break;
+        case ast::InterpolationType::kLinear:
+            modifiers += "noperspective ";
+            break;
+        case ast::InterpolationType::kFlat:
+            modifiers += "nointerpolation ";
+            break;
+    }
+    switch (sampling) {
+        case ast::InterpolationSampling::kCentroid:
+            modifiers += "centroid ";
+            break;
+        case ast::InterpolationSampling::kSample:
+            modifiers += "sample ";
+            break;
+        case ast::InterpolationSampling::kCenter:
+        case ast::InterpolationSampling::kNone:
+            break;
+    }
+    return modifiers;
 }
 
 bool GeneratorImpl::EmitEntryPointFunction(const ast::Function* func) {
-  auto* func_sem = builder_.Sem().Get(func);
+    auto* func_sem = builder_.Sem().Get(func);
 
-  {
-    auto out = line();
-    if (func->PipelineStage() == ast::PipelineStage::kCompute) {
-      // Emit the workgroup_size attribute.
-      auto wgsize = func_sem->WorkgroupSize();
-      out << "[numthreads(";
-      for (int i = 0; i < 3; i++) {
-        if (i > 0) {
-          out << ", ";
+    {
+        auto out = line();
+        if (func->PipelineStage() == ast::PipelineStage::kCompute) {
+            // Emit the workgroup_size attribute.
+            auto wgsize = func_sem->WorkgroupSize();
+            out << "[numthreads(";
+            for (int i = 0; i < 3; i++) {
+                if (i > 0) {
+                    out << ", ";
+                }
+
+                if (wgsize[i].overridable_const) {
+                    auto* global =
+                        builder_.Sem().Get<sem::GlobalVariable>(wgsize[i].overridable_const);
+                    if (!global->IsOverridable()) {
+                        TINT_ICE(Writer, builder_.Diagnostics())
+                            << "expected a pipeline-overridable constant";
+                    }
+                    out << kSpecConstantPrefix << global->ConstantId();
+                } else {
+                    out << std::to_string(wgsize[i].value);
+                }
+            }
+            out << ")]" << std::endl;
         }
 
-        if (wgsize[i].overridable_const) {
-          auto* global = builder_.Sem().Get<sem::GlobalVariable>(
-              wgsize[i].overridable_const);
-          if (!global->IsOverridable()) {
-            TINT_ICE(Writer, builder_.Diagnostics())
-                << "expected a pipeline-overridable constant";
-          }
-          out << kSpecConstantPrefix << global->ConstantId();
-        } else {
-          out << std::to_string(wgsize[i].value);
+        out << func->return_type->FriendlyName(builder_.Symbols());
+
+        out << " " << builder_.Symbols().NameFor(func->symbol) << "(";
+
+        bool first = true;
+
+        // Emit entry point parameters.
+        for (auto* var : func->params) {
+            auto* sem = builder_.Sem().Get(var);
+            auto* type = sem->Type();
+            if (!type->Is<sem::Struct>()) {
+                // ICE likely indicates that the CanonicalizeEntryPointIO transform was
+                // not run, or a builtin parameter was added after it was run.
+                TINT_ICE(Writer, diagnostics_) << "Unsupported non-struct entry point parameter";
+            }
+
+            if (!first) {
+                out << ", ";
+            }
+            first = false;
+
+            if (!EmitTypeAndName(out, type, sem->StorageClass(), sem->Access(),
+                                 builder_.Symbols().NameFor(var->symbol))) {
+                return false;
+            }
         }
-      }
-      out << ")]" << std::endl;
+
+        out << ") {";
     }
 
-    out << func->return_type->FriendlyName(builder_.Symbols());
+    {
+        ScopedIndent si(this);
 
-    out << " " << builder_.Symbols().NameFor(func->symbol) << "(";
+        if (!EmitStatements(func->body->statements)) {
+            return false;
+        }
 
-    bool first = true;
-
-    // Emit entry point parameters.
-    for (auto* var : func->params) {
-      auto* sem = builder_.Sem().Get(var);
-      auto* type = sem->Type();
-      if (!type->Is<sem::Struct>()) {
-        // ICE likely indicates that the CanonicalizeEntryPointIO transform was
-        // not run, or a builtin parameter was added after it was run.
-        TINT_ICE(Writer, diagnostics_)
-            << "Unsupported non-struct entry point parameter";
-      }
-
-      if (!first) {
-        out << ", ";
-      }
-      first = false;
-
-      if (!EmitTypeAndName(out, type, sem->StorageClass(), sem->Access(),
-                           builder_.Symbols().NameFor(var->symbol))) {
-        return false;
-      }
+        if (!Is<ast::ReturnStatement>(func->body->Last())) {
+            ast::ReturnStatement ret(ProgramID(), Source{});
+            if (!EmitStatement(&ret)) {
+                return false;
+            }
+        }
     }
 
-    out << ") {";
-  }
+    line() << "}";
 
-  {
-    ScopedIndent si(this);
-
-    if (!EmitStatements(func->body->statements)) {
-      return false;
-    }
-
-    if (!Is<ast::ReturnStatement>(func->body->Last())) {
-      ast::ReturnStatement ret(ProgramID(), Source{});
-      if (!EmitStatement(&ret)) {
-        return false;
-      }
-    }
-  }
-
-  line() << "}";
-
-  return true;
+    return true;
 }
 
-bool GeneratorImpl::EmitLiteral(std::ostream& out,
-                                const ast::LiteralExpression* lit) {
-  return Switch(
-      lit,
-      [&](const ast::BoolLiteralExpression* l) {
-        out << (l->value ? "true" : "false");
-        return true;
-      },
-      [&](const ast::FloatLiteralExpression* fl) {
-        if (std::isinf(fl->value)) {
-          out << (fl->value >= 0 ? "asfloat(0x7f800000u)"
-                                 : "asfloat(0xff800000u)");
-        } else if (std::isnan(fl->value)) {
-          out << "asfloat(0x7fc00000u)";
-        } else {
-          out << FloatToString(fl->value) << "f";
-        }
-        return true;
-      },
-      [&](const ast::SintLiteralExpression* sl) {
-        out << sl->value;
-        return true;
-      },
-      [&](const ast::UintLiteralExpression* ul) {
-        out << ul->value << "u";
-        return true;
-      },
-      [&](Default) {
-        diagnostics_.add_error(diag::System::Writer, "unknown literal type");
-        return false;
-      });
+bool GeneratorImpl::EmitLiteral(std::ostream& out, const ast::LiteralExpression* lit) {
+    return Switch(
+        lit,
+        [&](const ast::BoolLiteralExpression* l) {
+            out << (l->value ? "true" : "false");
+            return true;
+        },
+        [&](const ast::FloatLiteralExpression* fl) {
+            if (std::isinf(fl->value)) {
+                out << (fl->value >= 0 ? "asfloat(0x7f800000u)" : "asfloat(0xff800000u)");
+            } else if (std::isnan(fl->value)) {
+                out << "asfloat(0x7fc00000u)";
+            } else {
+                out << FloatToString(fl->value) << "f";
+            }
+            return true;
+        },
+        [&](const ast::IntLiteralExpression* i) {
+            out << i->value;
+            switch (i->suffix) {
+                case ast::IntLiteralExpression::Suffix::kNone:
+                case ast::IntLiteralExpression::Suffix::kI:
+                    return true;
+                case ast::IntLiteralExpression::Suffix::kU:
+                    out << "u";
+                    return true;
+            }
+            diagnostics_.add_error(diag::System::Writer, "unknown integer literal suffix type");
+            return false;
+        },
+        [&](Default) {
+            diagnostics_.add_error(diag::System::Writer, "unknown literal type");
+            return false;
+        });
 }
 
-bool GeneratorImpl::EmitValue(std::ostream& out,
-                              const sem::Type* type,
-                              int value) {
-  return Switch(
-      type,
-      [&](const sem::Bool*) {
-        out << (value == 0 ? "false" : "true");
-        return true;
-      },
-      [&](const sem::F32*) {
-        out << value << ".0f";
-        return true;
-      },
-      [&](const sem::I32*) {
-        out << value;
-        return true;
-      },
-      [&](const sem::U32*) {
-        out << value << "u";
-        return true;
-      },
-      [&](const sem::Vector* vec) {
-        if (!EmitType(out, type, ast::StorageClass::kNone,
-                      ast::Access::kReadWrite, "")) {
-          return false;
-        }
-        ScopedParen sp(out);
-        for (uint32_t i = 0; i < vec->Width(); i++) {
-          if (i != 0) {
-            out << ", ";
-          }
-          if (!EmitValue(out, vec->type(), value)) {
+bool GeneratorImpl::EmitValue(std::ostream& out, const sem::Type* type, int value) {
+    return Switch(
+        type,
+        [&](const sem::Bool*) {
+            out << (value == 0 ? "false" : "true");
+            return true;
+        },
+        [&](const sem::F32*) {
+            out << value << ".0f";
+            return true;
+        },
+        [&](const sem::I32*) {
+            out << value;
+            return true;
+        },
+        [&](const sem::U32*) {
+            out << value << "u";
+            return true;
+        },
+        [&](const sem::Vector* vec) {
+            if (!EmitType(out, type, ast::StorageClass::kNone, ast::Access::kReadWrite, "")) {
+                return false;
+            }
+            ScopedParen sp(out);
+            for (uint32_t i = 0; i < vec->Width(); i++) {
+                if (i != 0) {
+                    out << ", ";
+                }
+                if (!EmitValue(out, vec->type(), value)) {
+                    return false;
+                }
+            }
+            return true;
+        },
+        [&](const sem::Matrix* mat) {
+            if (!EmitType(out, type, ast::StorageClass::kNone, ast::Access::kReadWrite, "")) {
+                return false;
+            }
+            ScopedParen sp(out);
+            for (uint32_t i = 0; i < (mat->rows() * mat->columns()); i++) {
+                if (i != 0) {
+                    out << ", ";
+                }
+                if (!EmitValue(out, mat->type(), value)) {
+                    return false;
+                }
+            }
+            return true;
+        },
+        [&](const sem::Struct*) {
+            out << "(";
+            TINT_DEFER(out << ")" << value);
+            return EmitType(out, type, ast::StorageClass::kNone, ast::Access::kUndefined, "");
+        },
+        [&](const sem::Array*) {
+            out << "(";
+            TINT_DEFER(out << ")" << value);
+            return EmitType(out, type, ast::StorageClass::kNone, ast::Access::kUndefined, "");
+        },
+        [&](Default) {
+            diagnostics_.add_error(
+                diag::System::Writer,
+                "Invalid type for value emission: " + type->FriendlyName(builder_.Symbols()));
             return false;
-          }
-        }
-        return true;
-      },
-      [&](const sem::Matrix* mat) {
-        if (!EmitType(out, type, ast::StorageClass::kNone,
-                      ast::Access::kReadWrite, "")) {
-          return false;
-        }
-        ScopedParen sp(out);
-        for (uint32_t i = 0; i < (mat->rows() * mat->columns()); i++) {
-          if (i != 0) {
-            out << ", ";
-          }
-          if (!EmitValue(out, mat->type(), value)) {
-            return false;
-          }
-        }
-        return true;
-      },
-      [&](const sem::Struct*) {
-        out << "(";
-        TINT_DEFER(out << ")" << value);
-        return EmitType(out, type, ast::StorageClass::kNone,
-                        ast::Access::kUndefined, "");
-      },
-      [&](const sem::Array*) {
-        out << "(";
-        TINT_DEFER(out << ")" << value);
-        return EmitType(out, type, ast::StorageClass::kNone,
-                        ast::Access::kUndefined, "");
-      },
-      [&](Default) {
-        diagnostics_.add_error(diag::System::Writer,
-                               "Invalid type for value emission: " +
-                                   type->FriendlyName(builder_.Symbols()));
-        return false;
-      });
+        });
 }
 
 bool GeneratorImpl::EmitZeroValue(std::ostream& out, const sem::Type* type) {
-  return EmitValue(out, type, 0);
+    return EmitValue(out, type, 0);
 }
 
 bool GeneratorImpl::EmitLoop(const ast::LoopStatement* stmt) {
-  auto emit_continuing = [this, stmt]() {
-    if (stmt->continuing && !stmt->continuing->Empty()) {
-      if (!EmitBlock(stmt->continuing)) {
-        return false;
-      }
-    }
-    return true;
-  };
-
-  TINT_SCOPED_ASSIGNMENT(emit_continuing_, emit_continuing);
-  line() << LoopAttribute() << "while (true) {";
-  {
-    ScopedIndent si(this);
-    if (!EmitStatements(stmt->body->statements)) {
-      return false;
-    }
-    if (!emit_continuing_()) {
-      return false;
-    }
-  }
-  line() << "}";
-
-  return true;
-}
-
-bool GeneratorImpl::EmitForLoop(const ast::ForLoopStatement* stmt) {
-  // Nest a for loop with a new block. In HLSL the initializer scope is not
-  // nested by the for-loop, so we may get variable redefinitions.
-  line() << "{";
-  increment_indent();
-  TINT_DEFER({
-    decrement_indent();
-    line() << "}";
-  });
-
-  TextBuffer init_buf;
-  if (auto* init = stmt->initializer) {
-    TINT_SCOPED_ASSIGNMENT(current_buffer_, &init_buf);
-    if (!EmitStatement(init)) {
-      return false;
-    }
-  }
-
-  TextBuffer cond_pre;
-  std::stringstream cond_buf;
-  if (auto* cond = stmt->condition) {
-    TINT_SCOPED_ASSIGNMENT(current_buffer_, &cond_pre);
-    if (!EmitExpression(cond_buf, cond)) {
-      return false;
-    }
-  }
-
-  TextBuffer cont_buf;
-  if (auto* cont = stmt->continuing) {
-    TINT_SCOPED_ASSIGNMENT(current_buffer_, &cont_buf);
-    if (!EmitStatement(cont)) {
-      return false;
-    }
-  }
-
-  // If the for-loop has a multi-statement conditional and / or continuing, then
-  // we cannot emit this as a regular for-loop in HLSL. Instead we need to
-  // generate a `while(true)` loop.
-  bool emit_as_loop = cond_pre.lines.size() > 0 || cont_buf.lines.size() > 1;
-
-  // If the for-loop has multi-statement initializer, or is going to be emitted
-  // as a `while(true)` loop, then declare the initializer statement(s) before
-  // the loop.
-  if (init_buf.lines.size() > 1 || (stmt->initializer && emit_as_loop)) {
-    current_buffer_->Append(init_buf);
-    init_buf.lines.clear();  // Don't emit the initializer again in the 'for'
-  }
-
-  if (emit_as_loop) {
-    auto emit_continuing = [&]() {
-      current_buffer_->Append(cont_buf);
-      return true;
+    auto emit_continuing = [this, stmt]() {
+        if (stmt->continuing && !stmt->continuing->Empty()) {
+            if (!EmitBlock(stmt->continuing)) {
+                return false;
+            }
+        }
+        return true;
     };
 
     TINT_SCOPED_ASSIGNMENT(emit_continuing_, emit_continuing);
     line() << LoopAttribute() << "while (true) {";
-    increment_indent();
-    TINT_DEFER({
-      decrement_indent();
-      line() << "}";
-    });
-
-    if (stmt->condition) {
-      current_buffer_->Append(cond_pre);
-      line() << "if (!(" << cond_buf.str() << ")) { break; }";
-    }
-
-    if (!EmitStatements(stmt->body->statements)) {
-      return false;
-    }
-
-    if (!emit_continuing_()) {
-      return false;
-    }
-  } else {
-    // For-loop can be generated.
     {
-      auto out = line();
-      out << LoopAttribute() << "for";
-      {
-        ScopedParen sp(out);
-
-        if (!init_buf.lines.empty()) {
-          out << init_buf.lines[0].content << " ";
-        } else {
-          out << "; ";
+        ScopedIndent si(this);
+        if (!EmitStatements(stmt->body->statements)) {
+            return false;
         }
-
-        out << cond_buf.str() << "; ";
-
-        if (!cont_buf.lines.empty()) {
-          out << TrimSuffix(cont_buf.lines[0].content, ";");
+        if (!emit_continuing_()) {
+            return false;
         }
-      }
-      out << " {";
-    }
-    {
-      auto emit_continuing = [] { return true; };
-      TINT_SCOPED_ASSIGNMENT(emit_continuing_, emit_continuing);
-      if (!EmitStatementsWithIndent(stmt->body->statements)) {
-        return false;
-      }
     }
     line() << "}";
-  }
 
-  return true;
+    return true;
 }
 
-bool GeneratorImpl::EmitMemberAccessor(
-    std::ostream& out,
-    const ast::MemberAccessorExpression* expr) {
-  if (!EmitExpression(out, expr->structure)) {
-    return false;
-  }
-  out << ".";
+bool GeneratorImpl::EmitForLoop(const ast::ForLoopStatement* stmt) {
+    // Nest a for loop with a new block. In HLSL the initializer scope is not
+    // nested by the for-loop, so we may get variable redefinitions.
+    line() << "{";
+    increment_indent();
+    TINT_DEFER({
+        decrement_indent();
+        line() << "}";
+    });
 
-  // Swizzles output the name directly
-  if (builder_.Sem().Get(expr)->Is<sem::Swizzle>()) {
-    out << builder_.Symbols().NameFor(expr->member->symbol);
-  } else if (!EmitExpression(out, expr->member)) {
-    return false;
-  }
+    TextBuffer init_buf;
+    if (auto* init = stmt->initializer) {
+        TINT_SCOPED_ASSIGNMENT(current_buffer_, &init_buf);
+        if (!EmitStatement(init)) {
+            return false;
+        }
+    }
 
-  return true;
+    TextBuffer cond_pre;
+    std::stringstream cond_buf;
+    if (auto* cond = stmt->condition) {
+        TINT_SCOPED_ASSIGNMENT(current_buffer_, &cond_pre);
+        if (!EmitExpression(cond_buf, cond)) {
+            return false;
+        }
+    }
+
+    TextBuffer cont_buf;
+    if (auto* cont = stmt->continuing) {
+        TINT_SCOPED_ASSIGNMENT(current_buffer_, &cont_buf);
+        if (!EmitStatement(cont)) {
+            return false;
+        }
+    }
+
+    // If the for-loop has a multi-statement conditional and / or continuing, then
+    // we cannot emit this as a regular for-loop in HLSL. Instead we need to
+    // generate a `while(true)` loop.
+    bool emit_as_loop = cond_pre.lines.size() > 0 || cont_buf.lines.size() > 1;
+
+    // If the for-loop has multi-statement initializer, or is going to be emitted
+    // as a `while(true)` loop, then declare the initializer statement(s) before
+    // the loop.
+    if (init_buf.lines.size() > 1 || (stmt->initializer && emit_as_loop)) {
+        current_buffer_->Append(init_buf);
+        init_buf.lines.clear();  // Don't emit the initializer again in the 'for'
+    }
+
+    if (emit_as_loop) {
+        auto emit_continuing = [&]() {
+            current_buffer_->Append(cont_buf);
+            return true;
+        };
+
+        TINT_SCOPED_ASSIGNMENT(emit_continuing_, emit_continuing);
+        line() << LoopAttribute() << "while (true) {";
+        increment_indent();
+        TINT_DEFER({
+            decrement_indent();
+            line() << "}";
+        });
+
+        if (stmt->condition) {
+            current_buffer_->Append(cond_pre);
+            line() << "if (!(" << cond_buf.str() << ")) { break; }";
+        }
+
+        if (!EmitStatements(stmt->body->statements)) {
+            return false;
+        }
+
+        if (!emit_continuing_()) {
+            return false;
+        }
+    } else {
+        // For-loop can be generated.
+        {
+            auto out = line();
+            out << LoopAttribute() << "for";
+            {
+                ScopedParen sp(out);
+
+                if (!init_buf.lines.empty()) {
+                    out << init_buf.lines[0].content << " ";
+                } else {
+                    out << "; ";
+                }
+
+                out << cond_buf.str() << "; ";
+
+                if (!cont_buf.lines.empty()) {
+                    out << TrimSuffix(cont_buf.lines[0].content, ";");
+                }
+            }
+            out << " {";
+        }
+        {
+            auto emit_continuing = [] { return true; };
+            TINT_SCOPED_ASSIGNMENT(emit_continuing_, emit_continuing);
+            if (!EmitStatementsWithIndent(stmt->body->statements)) {
+                return false;
+            }
+        }
+        line() << "}";
+    }
+
+    return true;
+}
+
+bool GeneratorImpl::EmitMemberAccessor(std::ostream& out,
+                                       const ast::MemberAccessorExpression* expr) {
+    if (!EmitExpression(out, expr->structure)) {
+        return false;
+    }
+    out << ".";
+
+    // Swizzles output the name directly
+    if (builder_.Sem().Get(expr)->Is<sem::Swizzle>()) {
+        out << builder_.Symbols().NameFor(expr->member->symbol);
+    } else if (!EmitExpression(out, expr->member)) {
+        return false;
+    }
+
+    return true;
 }
 
 bool GeneratorImpl::EmitReturn(const ast::ReturnStatement* stmt) {
-  if (stmt->value) {
-    auto out = line();
-    out << "return ";
-    if (!EmitExpression(out, stmt->value)) {
-      return false;
+    if (stmt->value) {
+        auto out = line();
+        out << "return ";
+        if (!EmitExpression(out, stmt->value)) {
+            return false;
+        }
+        out << ";";
+    } else {
+        line() << "return;";
     }
-    out << ";";
-  } else {
-    line() << "return;";
-  }
-  return true;
+    return true;
 }
 
 bool GeneratorImpl::EmitStatement(const ast::Statement* stmt) {
-  return Switch(
-      stmt,
-      [&](const ast::AssignmentStatement* a) {  //
-        return EmitAssign(a);
-      },
-      [&](const ast::BlockStatement* b) {  //
-        return EmitBlock(b);
-      },
-      [&](const ast::BreakStatement* b) {  //
-        return EmitBreak(b);
-      },
-      [&](const ast::CallStatement* c) {  //
-        auto out = line();
-        if (!EmitCall(out, c->expr)) {
-          return false;
-        }
-        out << ";";
-        return true;
-      },
-      [&](const ast::ContinueStatement* c) {  //
-        return EmitContinue(c);
-      },
-      [&](const ast::DiscardStatement* d) {  //
-        return EmitDiscard(d);
-      },
-      [&](const ast::FallthroughStatement*) {  //
-        line() << "/* fallthrough */";
-        return true;
-      },
-      [&](const ast::IfStatement* i) {  //
-        return EmitIf(i);
-      },
-      [&](const ast::LoopStatement* l) {  //
-        return EmitLoop(l);
-      },
-      [&](const ast::ForLoopStatement* l) {  //
-        return EmitForLoop(l);
-      },
-      [&](const ast::ReturnStatement* r) {  //
-        return EmitReturn(r);
-      },
-      [&](const ast::SwitchStatement* s) {  //
-        return EmitSwitch(s);
-      },
-      [&](const ast::VariableDeclStatement* v) {  //
-        return EmitVariable(v->variable);
-      },
-      [&](Default) {  //
-        diagnostics_.add_error(
-            diag::System::Writer,
-            "unknown statement type: " + std::string(stmt->TypeInfo().name));
-        return false;
-      });
+    return Switch(
+        stmt,
+        [&](const ast::AssignmentStatement* a) {  //
+            return EmitAssign(a);
+        },
+        [&](const ast::BlockStatement* b) {  //
+            return EmitBlock(b);
+        },
+        [&](const ast::BreakStatement* b) {  //
+            return EmitBreak(b);
+        },
+        [&](const ast::CallStatement* c) {  //
+            auto out = line();
+            if (!EmitCall(out, c->expr)) {
+                return false;
+            }
+            out << ";";
+            return true;
+        },
+        [&](const ast::ContinueStatement* c) {  //
+            return EmitContinue(c);
+        },
+        [&](const ast::DiscardStatement* d) {  //
+            return EmitDiscard(d);
+        },
+        [&](const ast::FallthroughStatement*) {  //
+            line() << "/* fallthrough */";
+            return true;
+        },
+        [&](const ast::IfStatement* i) {  //
+            return EmitIf(i);
+        },
+        [&](const ast::LoopStatement* l) {  //
+            return EmitLoop(l);
+        },
+        [&](const ast::ForLoopStatement* l) {  //
+            return EmitForLoop(l);
+        },
+        [&](const ast::ReturnStatement* r) {  //
+            return EmitReturn(r);
+        },
+        [&](const ast::SwitchStatement* s) {  //
+            return EmitSwitch(s);
+        },
+        [&](const ast::VariableDeclStatement* v) {  //
+            return EmitVariable(v->variable);
+        },
+        [&](Default) {  //
+            diagnostics_.add_error(diag::System::Writer,
+                                   "unknown statement type: " + std::string(stmt->TypeInfo().name));
+            return false;
+        });
 }
 
 bool GeneratorImpl::EmitDefaultOnlySwitch(const ast::SwitchStatement* stmt) {
-  TINT_ASSERT(Writer, stmt->body.size() == 1 && stmt->body[0]->IsDefault());
+    TINT_ASSERT(Writer, stmt->body.size() == 1 && stmt->body[0]->IsDefault());
 
-  // FXC fails to compile a switch with just a default case, ignoring the
-  // default case body. We work around this here by emitting the default case
-  // without the switch.
+    // FXC fails to compile a switch with just a default case, ignoring the
+    // default case body. We work around this here by emitting the default case
+    // without the switch.
 
-  // Emit the switch condition as-is in case it has side-effects (e.g.
-  // function call). Note that's it's fine not to assign the result of the
-  // expression.
-  {
-    auto out = line();
-    if (!EmitExpression(out, stmt->condition)) {
-      return false;
+    // Emit the switch condition as-is in case it has side-effects (e.g.
+    // function call). Note that's it's fine not to assign the result of the
+    // expression.
+    {
+        auto out = line();
+        if (!EmitExpression(out, stmt->condition)) {
+            return false;
+        }
+        out << ";";
     }
-    out << ";";
-  }
 
-  // Emit "do { <default case body> } while(false);". We use a 'do' loop so
-  // that break statements work as expected, and make it 'while (false)' in
-  // case there isn't a break statement.
-  line() << "do {";
-  {
-    ScopedIndent si(this);
-    if (!EmitStatements(stmt->body[0]->body->statements)) {
-      return false;
+    // Emit "do { <default case body> } while(false);". We use a 'do' loop so
+    // that break statements work as expected, and make it 'while (false)' in
+    // case there isn't a break statement.
+    line() << "do {";
+    {
+        ScopedIndent si(this);
+        if (!EmitStatements(stmt->body[0]->body->statements)) {
+            return false;
+        }
     }
-  }
-  line() << "} while (false);";
-  return true;
+    line() << "} while (false);";
+    return true;
 }
 
 bool GeneratorImpl::EmitSwitch(const ast::SwitchStatement* stmt) {
-  // BUG(crbug.com/tint/1188): work around default-only switches
-  if (stmt->body.size() == 1 && stmt->body[0]->IsDefault()) {
-    return EmitDefaultOnlySwitch(stmt);
-  }
-
-  {  // switch(expr) {
-    auto out = line();
-    out << "switch(";
-    if (!EmitExpression(out, stmt->condition)) {
-      return false;
+    // BUG(crbug.com/tint/1188): work around default-only switches
+    if (stmt->body.size() == 1 && stmt->body[0]->IsDefault()) {
+        return EmitDefaultOnlySwitch(stmt);
     }
-    out << ") {";
-  }
 
-  {
-    ScopedIndent si(this);
-    for (size_t i = 0; i < stmt->body.size(); i++) {
-      if (!EmitCase(stmt, i)) {
-        return false;
-      }
+    {  // switch(expr) {
+        auto out = line();
+        out << "switch(";
+        if (!EmitExpression(out, stmt->condition)) {
+            return false;
+        }
+        out << ") {";
     }
-  }
 
-  line() << "}";
+    {
+        ScopedIndent si(this);
+        for (size_t i = 0; i < stmt->body.size(); i++) {
+            if (!EmitCase(stmt, i)) {
+                return false;
+            }
+        }
+    }
 
-  return true;
+    line() << "}";
+
+    return true;
 }
 
 bool GeneratorImpl::EmitType(std::ostream& out,
@@ -3521,209 +3422,205 @@
                              ast::Access access,
                              const std::string& name,
                              bool* name_printed /* = nullptr */) {
-  if (name_printed) {
-    *name_printed = false;
-  }
-  switch (storage_class) {
-    case ast::StorageClass::kStorage:
-      if (access != ast::Access::kRead) {
-        out << "RW";
-      }
-      out << "ByteAddressBuffer";
-      return true;
-    case ast::StorageClass::kUniform: {
-      auto array_length = (type->Size() + 15) / 16;
-      out << "uint4 " << name << "[" << array_length << "]";
-      if (name_printed) {
-        *name_printed = true;
-      }
-      return true;
+    if (name_printed) {
+        *name_printed = false;
     }
-    default:
-      break;
-  }
+    switch (storage_class) {
+        case ast::StorageClass::kStorage:
+            if (access != ast::Access::kRead) {
+                out << "RW";
+            }
+            out << "ByteAddressBuffer";
+            return true;
+        case ast::StorageClass::kUniform: {
+            auto array_length = (type->Size() + 15) / 16;
+            out << "uint4 " << name << "[" << array_length << "]";
+            if (name_printed) {
+                *name_printed = true;
+            }
+            return true;
+        }
+        default:
+            break;
+    }
 
-  return Switch(
-      type,
-      [&](const sem::Array* ary) {
-        const sem::Type* base_type = ary;
-        std::vector<uint32_t> sizes;
-        while (auto* arr = base_type->As<sem::Array>()) {
-          if (arr->IsRuntimeSized()) {
+    return Switch(
+        type,
+        [&](const sem::Array* ary) {
+            const sem::Type* base_type = ary;
+            std::vector<uint32_t> sizes;
+            while (auto* arr = base_type->As<sem::Array>()) {
+                if (arr->IsRuntimeSized()) {
+                    TINT_ICE(Writer, diagnostics_)
+                        << "Runtime arrays may only exist in storage buffers, which "
+                           "should "
+                           "have been transformed into a ByteAddressBuffer";
+                    return false;
+                }
+                sizes.push_back(arr->Count());
+                base_type = arr->ElemType();
+            }
+            if (!EmitType(out, base_type, storage_class, access, "")) {
+                return false;
+            }
+            if (!name.empty()) {
+                out << " " << name;
+                if (name_printed) {
+                    *name_printed = true;
+                }
+            }
+            for (uint32_t size : sizes) {
+                out << "[" << size << "]";
+            }
+            return true;
+        },
+        [&](const sem::Bool*) {
+            out << "bool";
+            return true;
+        },
+        [&](const sem::F32*) {
+            out << "float";
+            return true;
+        },
+        [&](const sem::I32*) {
+            out << "int";
+            return true;
+        },
+        [&](const sem::Matrix* mat) {
+            if (!EmitType(out, mat->type(), storage_class, access, "")) {
+                return false;
+            }
+            // Note: HLSL's matrices are declared as <type>NxM, where N is the
+            // number of rows and M is the number of columns. Despite HLSL's
+            // matrices being column-major by default, the index operator and
+            // constructors actually operate on row-vectors, where as WGSL operates
+            // on column vectors. To simplify everything we use the transpose of the
+            // matrices. See:
+            // https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-per-component-math#matrix-ordering
+            out << mat->columns() << "x" << mat->rows();
+            return true;
+        },
+        [&](const sem::Pointer*) {
             TINT_ICE(Writer, diagnostics_)
-                << "Runtime arrays may only exist in storage buffers, which "
-                   "should "
-                   "have been transformed into a ByteAddressBuffer";
+                << "Attempting to emit pointer type. These should have been "
+                   "removed with the InlinePointerLets transform";
             return false;
-          }
-          sizes.push_back(arr->Count());
-          base_type = arr->ElemType();
-        }
-        if (!EmitType(out, base_type, storage_class, access, "")) {
-          return false;
-        }
-        if (!name.empty()) {
-          out << " " << name;
-          if (name_printed) {
-            *name_printed = true;
-          }
-        }
-        for (uint32_t size : sizes) {
-          out << "[" << size << "]";
-        }
-        return true;
-      },
-      [&](const sem::Bool*) {
-        out << "bool";
-        return true;
-      },
-      [&](const sem::F32*) {
-        out << "float";
-        return true;
-      },
-      [&](const sem::I32*) {
-        out << "int";
-        return true;
-      },
-      [&](const sem::Matrix* mat) {
-        if (!EmitType(out, mat->type(), storage_class, access, "")) {
-          return false;
-        }
-        // Note: HLSL's matrices are declared as <type>NxM, where N is the
-        // number of rows and M is the number of columns. Despite HLSL's
-        // matrices being column-major by default, the index operator and
-        // constructors actually operate on row-vectors, where as WGSL operates
-        // on column vectors. To simplify everything we use the transpose of the
-        // matrices. See:
-        // https://docs.microsoft.com/en-us/windows/win32/direct3dhlsl/dx-graphics-hlsl-per-component-math#matrix-ordering
-        out << mat->columns() << "x" << mat->rows();
-        return true;
-      },
-      [&](const sem::Pointer*) {
-        TINT_ICE(Writer, diagnostics_)
-            << "Attempting to emit pointer type. These should have been "
-               "removed with the InlinePointerLets transform";
-        return false;
-      },
-      [&](const sem::Sampler* sampler) {
-        out << "Sampler";
-        if (sampler->IsComparison()) {
-          out << "Comparison";
-        }
-        out << "State";
-        return true;
-      },
-      [&](const sem::Struct* str) {
-        out << StructName(str);
-        return true;
-      },
-      [&](const sem::Texture* tex) {
-        if (tex->Is<sem::ExternalTexture>()) {
-          TINT_ICE(Writer, diagnostics_)
-              << "Multiplanar external texture transform was not run.";
-          return false;
-        }
+        },
+        [&](const sem::Sampler* sampler) {
+            out << "Sampler";
+            if (sampler->IsComparison()) {
+                out << "Comparison";
+            }
+            out << "State";
+            return true;
+        },
+        [&](const sem::Struct* str) {
+            out << StructName(str);
+            return true;
+        },
+        [&](const sem::Texture* tex) {
+            if (tex->Is<sem::ExternalTexture>()) {
+                TINT_ICE(Writer, diagnostics_)
+                    << "Multiplanar external texture transform was not run.";
+                return false;
+            }
 
-        auto* storage = tex->As<sem::StorageTexture>();
-        auto* ms = tex->As<sem::MultisampledTexture>();
-        auto* depth_ms = tex->As<sem::DepthMultisampledTexture>();
-        auto* sampled = tex->As<sem::SampledTexture>();
+            auto* storage = tex->As<sem::StorageTexture>();
+            auto* ms = tex->As<sem::MultisampledTexture>();
+            auto* depth_ms = tex->As<sem::DepthMultisampledTexture>();
+            auto* sampled = tex->As<sem::SampledTexture>();
 
-        if (storage && storage->access() != ast::Access::kRead) {
-          out << "RW";
-        }
-        out << "Texture";
+            if (storage && storage->access() != ast::Access::kRead) {
+                out << "RW";
+            }
+            out << "Texture";
 
-        switch (tex->dim()) {
-          case ast::TextureDimension::k1d:
-            out << "1D";
-            break;
-          case ast::TextureDimension::k2d:
-            out << ((ms || depth_ms) ? "2DMS" : "2D");
-            break;
-          case ast::TextureDimension::k2dArray:
-            out << ((ms || depth_ms) ? "2DMSArray" : "2DArray");
-            break;
-          case ast::TextureDimension::k3d:
-            out << "3D";
-            break;
-          case ast::TextureDimension::kCube:
-            out << "Cube";
-            break;
-          case ast::TextureDimension::kCubeArray:
-            out << "CubeArray";
-            break;
-          default:
-            TINT_UNREACHABLE(Writer, diagnostics_)
-                << "unexpected TextureDimension " << tex->dim();
-            return false;
-        }
+            switch (tex->dim()) {
+                case ast::TextureDimension::k1d:
+                    out << "1D";
+                    break;
+                case ast::TextureDimension::k2d:
+                    out << ((ms || depth_ms) ? "2DMS" : "2D");
+                    break;
+                case ast::TextureDimension::k2dArray:
+                    out << ((ms || depth_ms) ? "2DMSArray" : "2DArray");
+                    break;
+                case ast::TextureDimension::k3d:
+                    out << "3D";
+                    break;
+                case ast::TextureDimension::kCube:
+                    out << "Cube";
+                    break;
+                case ast::TextureDimension::kCubeArray:
+                    out << "CubeArray";
+                    break;
+                default:
+                    TINT_UNREACHABLE(Writer, diagnostics_)
+                        << "unexpected TextureDimension " << tex->dim();
+                    return false;
+            }
 
-        if (storage) {
-          auto* component =
-              image_format_to_rwtexture_type(storage->texel_format());
-          if (component == nullptr) {
-            TINT_ICE(Writer, diagnostics_)
-                << "Unsupported StorageTexture TexelFormat: "
-                << static_cast<int>(storage->texel_format());
+            if (storage) {
+                auto* component = image_format_to_rwtexture_type(storage->texel_format());
+                if (component == nullptr) {
+                    TINT_ICE(Writer, diagnostics_) << "Unsupported StorageTexture TexelFormat: "
+                                                   << static_cast<int>(storage->texel_format());
+                    return false;
+                }
+                out << "<" << component << ">";
+            } else if (depth_ms) {
+                out << "<float4>";
+            } else if (sampled || ms) {
+                auto* subtype = sampled ? sampled->type() : ms->type();
+                out << "<";
+                if (subtype->Is<sem::F32>()) {
+                    out << "float4";
+                } else if (subtype->Is<sem::I32>()) {
+                    out << "int4";
+                } else if (subtype->Is<sem::U32>()) {
+                    out << "uint4";
+                } else {
+                    TINT_ICE(Writer, diagnostics_) << "Unsupported multisampled texture type";
+                    return false;
+                }
+                out << ">";
+            }
+            return true;
+        },
+        [&](const sem::U32*) {
+            out << "uint";
+            return true;
+        },
+        [&](const sem::Vector* vec) {
+            auto width = vec->Width();
+            if (vec->type()->Is<sem::F32>() && width >= 1 && width <= 4) {
+                out << "float" << width;
+            } else if (vec->type()->Is<sem::I32>() && width >= 1 && width <= 4) {
+                out << "int" << width;
+            } else if (vec->type()->Is<sem::U32>() && width >= 1 && width <= 4) {
+                out << "uint" << width;
+            } else if (vec->type()->Is<sem::Bool>() && width >= 1 && width <= 4) {
+                out << "bool" << width;
+            } else {
+                out << "vector<";
+                if (!EmitType(out, vec->type(), storage_class, access, "")) {
+                    return false;
+                }
+                out << ", " << width << ">";
+            }
+            return true;
+        },
+        [&](const sem::Atomic* atomic) {
+            return EmitType(out, atomic->Type(), storage_class, access, name);
+        },
+        [&](const sem::Void*) {
+            out << "void";
+            return true;
+        },
+        [&](Default) {
+            diagnostics_.add_error(diag::System::Writer, "unknown type in EmitType");
             return false;
-          }
-          out << "<" << component << ">";
-        } else if (depth_ms) {
-          out << "<float4>";
-        } else if (sampled || ms) {
-          auto* subtype = sampled ? sampled->type() : ms->type();
-          out << "<";
-          if (subtype->Is<sem::F32>()) {
-            out << "float4";
-          } else if (subtype->Is<sem::I32>()) {
-            out << "int4";
-          } else if (subtype->Is<sem::U32>()) {
-            out << "uint4";
-          } else {
-            TINT_ICE(Writer, diagnostics_)
-                << "Unsupported multisampled texture type";
-            return false;
-          }
-          out << ">";
-        }
-        return true;
-      },
-      [&](const sem::U32*) {
-        out << "uint";
-        return true;
-      },
-      [&](const sem::Vector* vec) {
-        auto width = vec->Width();
-        if (vec->type()->Is<sem::F32>() && width >= 1 && width <= 4) {
-          out << "float" << width;
-        } else if (vec->type()->Is<sem::I32>() && width >= 1 && width <= 4) {
-          out << "int" << width;
-        } else if (vec->type()->Is<sem::U32>() && width >= 1 && width <= 4) {
-          out << "uint" << width;
-        } else if (vec->type()->Is<sem::Bool>() && width >= 1 && width <= 4) {
-          out << "bool" << width;
-        } else {
-          out << "vector<";
-          if (!EmitType(out, vec->type(), storage_class, access, "")) {
-            return false;
-          }
-          out << ", " << width << ">";
-        }
-        return true;
-      },
-      [&](const sem::Atomic* atomic) {
-        return EmitType(out, atomic->Type(), storage_class, access, name);
-      },
-      [&](const sem::Void*) {
-        out << "void";
-        return true;
-      },
-      [&](Default) {
-        diagnostics_.add_error(diag::System::Writer,
-                               "unknown type in EmitType");
-        return false;
-      });
+        });
 }
 
 bool GeneratorImpl::EmitTypeAndName(std::ostream& out,
@@ -3731,221 +3628,213 @@
                                     ast::StorageClass storage_class,
                                     ast::Access access,
                                     const std::string& name) {
-  bool name_printed = false;
-  if (!EmitType(out, type, storage_class, access, name, &name_printed)) {
-    return false;
-  }
-  if (!name.empty() && !name_printed) {
-    out << " " << name;
-  }
-  return true;
+    bool name_printed = false;
+    if (!EmitType(out, type, storage_class, access, name, &name_printed)) {
+        return false;
+    }
+    if (!name.empty() && !name_printed) {
+        out << " " << name;
+    }
+    return true;
 }
 
 bool GeneratorImpl::EmitStructType(TextBuffer* b, const sem::Struct* str) {
-  line(b) << "struct " << StructName(str) << " {";
-  {
-    ScopedIndent si(b);
-    for (auto* mem : str->Members()) {
-      auto mem_name = builder_.Symbols().NameFor(mem->Name());
+    line(b) << "struct " << StructName(str) << " {";
+    {
+        ScopedIndent si(b);
+        for (auto* mem : str->Members()) {
+            auto mem_name = builder_.Symbols().NameFor(mem->Name());
 
-      auto* ty = mem->Type();
+            auto* ty = mem->Type();
 
-      auto out = line(b);
+            auto out = line(b);
 
-      std::string pre, post;
+            std::string pre, post;
 
-      if (auto* decl = mem->Declaration()) {
-        for (auto* attr : decl->attributes) {
-          if (auto* location = attr->As<ast::LocationAttribute>()) {
-            auto& pipeline_stage_uses = str->PipelineStageUses();
-            if (pipeline_stage_uses.size() != 1) {
-              TINT_ICE(Writer, diagnostics_)
-                  << "invalid entry point IO struct uses";
+            if (auto* decl = mem->Declaration()) {
+                for (auto* attr : decl->attributes) {
+                    if (auto* location = attr->As<ast::LocationAttribute>()) {
+                        auto& pipeline_stage_uses = str->PipelineStageUses();
+                        if (pipeline_stage_uses.size() != 1) {
+                            TINT_ICE(Writer, diagnostics_) << "invalid entry point IO struct uses";
+                        }
+
+                        if (pipeline_stage_uses.count(sem::PipelineStageUsage::kVertexInput)) {
+                            post += " : TEXCOORD" + std::to_string(location->value);
+                        } else if (pipeline_stage_uses.count(
+                                       sem::PipelineStageUsage::kVertexOutput)) {
+                            post += " : TEXCOORD" + std::to_string(location->value);
+                        } else if (pipeline_stage_uses.count(
+                                       sem::PipelineStageUsage::kFragmentInput)) {
+                            post += " : TEXCOORD" + std::to_string(location->value);
+                        } else if (pipeline_stage_uses.count(
+                                       sem::PipelineStageUsage::kFragmentOutput)) {
+                            post += " : SV_Target" + std::to_string(location->value);
+                        } else {
+                            TINT_ICE(Writer, diagnostics_) << "invalid use of location attribute";
+                        }
+                    } else if (auto* builtin = attr->As<ast::BuiltinAttribute>()) {
+                        auto name = builtin_to_attribute(builtin->builtin);
+                        if (name.empty()) {
+                            diagnostics_.add_error(diag::System::Writer, "unsupported builtin");
+                            return false;
+                        }
+                        post += " : " + name;
+                    } else if (auto* interpolate = attr->As<ast::InterpolateAttribute>()) {
+                        auto mod =
+                            interpolation_to_modifiers(interpolate->type, interpolate->sampling);
+                        if (mod.empty()) {
+                            diagnostics_.add_error(diag::System::Writer,
+                                                   "unsupported interpolation");
+                            return false;
+                        }
+                        pre += mod;
+
+                    } else if (attr->Is<ast::InvariantAttribute>()) {
+                        // Note: `precise` is not exactly the same as `invariant`, but is
+                        // stricter and therefore provides the necessary guarantees.
+                        // See discussion here: https://github.com/gpuweb/gpuweb/issues/893
+                        pre += "precise ";
+                    } else if (!attr->IsAnyOf<ast::StructMemberAlignAttribute,
+                                              ast::StructMemberOffsetAttribute,
+                                              ast::StructMemberSizeAttribute>()) {
+                        TINT_ICE(Writer, diagnostics_)
+                            << "unhandled struct member attribute: " << attr->Name();
+                        return false;
+                    }
+                }
             }
 
-            if (pipeline_stage_uses.count(
-                    sem::PipelineStageUsage::kVertexInput)) {
-              post += " : TEXCOORD" + std::to_string(location->value);
-            } else if (pipeline_stage_uses.count(
-                           sem::PipelineStageUsage::kVertexOutput)) {
-              post += " : TEXCOORD" + std::to_string(location->value);
-            } else if (pipeline_stage_uses.count(
-                           sem::PipelineStageUsage::kFragmentInput)) {
-              post += " : TEXCOORD" + std::to_string(location->value);
-            } else if (pipeline_stage_uses.count(
-                           sem::PipelineStageUsage::kFragmentOutput)) {
-              post += " : SV_Target" + std::to_string(location->value);
-            } else {
-              TINT_ICE(Writer, diagnostics_)
-                  << "invalid use of location attribute";
+            out << pre;
+            if (!EmitTypeAndName(out, ty, ast::StorageClass::kNone, ast::Access::kReadWrite,
+                                 mem_name)) {
+                return false;
             }
-          } else if (auto* builtin = attr->As<ast::BuiltinAttribute>()) {
-            auto name = builtin_to_attribute(builtin->builtin);
-            if (name.empty()) {
-              diagnostics_.add_error(diag::System::Writer,
-                                     "unsupported builtin");
-              return false;
-            }
-            post += " : " + name;
-          } else if (auto* interpolate =
-                         attr->As<ast::InterpolateAttribute>()) {
-            auto mod = interpolation_to_modifiers(interpolate->type,
-                                                  interpolate->sampling);
-            if (mod.empty()) {
-              diagnostics_.add_error(diag::System::Writer,
-                                     "unsupported interpolation");
-              return false;
-            }
-            pre += mod;
-
-          } else if (attr->Is<ast::InvariantAttribute>()) {
-            // Note: `precise` is not exactly the same as `invariant`, but is
-            // stricter and therefore provides the necessary guarantees.
-            // See discussion here: https://github.com/gpuweb/gpuweb/issues/893
-            pre += "precise ";
-          } else if (!attr->IsAnyOf<ast::StructMemberAlignAttribute,
-                                    ast::StructMemberOffsetAttribute,
-                                    ast::StructMemberSizeAttribute>()) {
-            TINT_ICE(Writer, diagnostics_)
-                << "unhandled struct member attribute: " << attr->Name();
-            return false;
-          }
+            out << post << ";";
         }
-      }
-
-      out << pre;
-      if (!EmitTypeAndName(out, ty, ast::StorageClass::kNone,
-                           ast::Access::kReadWrite, mem_name)) {
-        return false;
-      }
-      out << post << ";";
     }
-  }
 
-  line(b) << "};";
+    line(b) << "};";
 
-  return true;
+    return true;
 }
 
-bool GeneratorImpl::EmitUnaryOp(std::ostream& out,
-                                const ast::UnaryOpExpression* expr) {
-  switch (expr->op) {
-    case ast::UnaryOp::kIndirection:
-    case ast::UnaryOp::kAddressOf:
-      return EmitExpression(out, expr->expr);
-    case ast::UnaryOp::kComplement:
-      out << "~";
-      break;
-    case ast::UnaryOp::kNot:
-      out << "!";
-      break;
-    case ast::UnaryOp::kNegation:
-      out << "-";
-      break;
-  }
-  out << "(";
+bool GeneratorImpl::EmitUnaryOp(std::ostream& out, const ast::UnaryOpExpression* expr) {
+    switch (expr->op) {
+        case ast::UnaryOp::kIndirection:
+        case ast::UnaryOp::kAddressOf:
+            return EmitExpression(out, expr->expr);
+        case ast::UnaryOp::kComplement:
+            out << "~";
+            break;
+        case ast::UnaryOp::kNot:
+            out << "!";
+            break;
+        case ast::UnaryOp::kNegation:
+            out << "-";
+            break;
+    }
+    out << "(";
 
-  if (!EmitExpression(out, expr->expr)) {
-    return false;
-  }
+    if (!EmitExpression(out, expr->expr)) {
+        return false;
+    }
 
-  out << ")";
+    out << ")";
 
-  return true;
+    return true;
 }
 
 bool GeneratorImpl::EmitVariable(const ast::Variable* var) {
-  auto* sem = builder_.Sem().Get(var);
-  auto* type = sem->Type()->UnwrapRef();
+    auto* sem = builder_.Sem().Get(var);
+    auto* type = sem->Type()->UnwrapRef();
 
-  // TODO(dsinclair): Handle variable attributes
-  if (!var->attributes.empty()) {
-    diagnostics_.add_error(diag::System::Writer,
-                           "Variable attributes are not handled yet");
-    return false;
-  }
-
-  auto out = line();
-  if (var->is_const) {
-    out << "const ";
-  }
-  if (!EmitTypeAndName(out, type, sem->StorageClass(), sem->Access(),
-                       builder_.Symbols().NameFor(var->symbol))) {
-    return false;
-  }
-
-  out << " = ";
-
-  if (var->constructor) {
-    if (!EmitExpression(out, var->constructor)) {
-      return false;
+    // TODO(dsinclair): Handle variable attributes
+    if (!var->attributes.empty()) {
+        diagnostics_.add_error(diag::System::Writer, "Variable attributes are not handled yet");
+        return false;
     }
-  } else {
-    if (!EmitZeroValue(out, type)) {
-      return false;
-    }
-  }
-  out << ";";
 
-  return true;
+    auto out = line();
+    if (var->is_const) {
+        out << "const ";
+    }
+    if (!EmitTypeAndName(out, type, sem->StorageClass(), sem->Access(),
+                         builder_.Symbols().NameFor(var->symbol))) {
+        return false;
+    }
+
+    out << " = ";
+
+    if (var->constructor) {
+        if (!EmitExpression(out, var->constructor)) {
+            return false;
+        }
+    } else {
+        if (!EmitZeroValue(out, type)) {
+            return false;
+        }
+    }
+    out << ";";
+
+    return true;
 }
 
 bool GeneratorImpl::EmitProgramConstVariable(const ast::Variable* var) {
-  for (auto* d : var->attributes) {
-    if (!d->Is<ast::IdAttribute>()) {
-      diagnostics_.add_error(diag::System::Writer,
-                             "Decorated const values not valid");
-      return false;
+    for (auto* d : var->attributes) {
+        if (!d->Is<ast::IdAttribute>()) {
+            diagnostics_.add_error(diag::System::Writer, "Decorated const values not valid");
+            return false;
+        }
     }
-  }
-  if (!var->is_const) {
-    diagnostics_.add_error(diag::System::Writer, "Expected a const value");
-    return false;
-  }
-
-  auto* sem = builder_.Sem().Get(var);
-  auto* type = sem->Type();
-
-  auto* global = sem->As<sem::GlobalVariable>();
-  if (global && global->IsOverridable()) {
-    auto const_id = global->ConstantId();
-
-    line() << "#ifndef " << kSpecConstantPrefix << const_id;
-
-    if (var->constructor != nullptr) {
-      auto out = line();
-      out << "#define " << kSpecConstantPrefix << const_id << " ";
-      if (!EmitExpression(out, var->constructor)) {
+    if (!var->is_const) {
+        diagnostics_.add_error(diag::System::Writer, "Expected a const value");
         return false;
-      }
+    }
+
+    auto* sem = builder_.Sem().Get(var);
+    auto* type = sem->Type();
+
+    auto* global = sem->As<sem::GlobalVariable>();
+    if (global && global->IsOverridable()) {
+        auto const_id = global->ConstantId();
+
+        line() << "#ifndef " << kSpecConstantPrefix << const_id;
+
+        if (var->constructor != nullptr) {
+            auto out = line();
+            out << "#define " << kSpecConstantPrefix << const_id << " ";
+            if (!EmitExpression(out, var->constructor)) {
+                return false;
+            }
+        } else {
+            line() << "#error spec constant required for constant id " << const_id;
+        }
+        line() << "#endif";
+        {
+            auto out = line();
+            out << "static const ";
+            if (!EmitTypeAndName(out, type, sem->StorageClass(), sem->Access(),
+                                 builder_.Symbols().NameFor(var->symbol))) {
+                return false;
+            }
+            out << " = " << kSpecConstantPrefix << const_id << ";";
+        }
     } else {
-      line() << "#error spec constant required for constant id " << const_id;
+        auto out = line();
+        out << "static const ";
+        if (!EmitTypeAndName(out, type, sem->StorageClass(), sem->Access(),
+                             builder_.Symbols().NameFor(var->symbol))) {
+            return false;
+        }
+        out << " = ";
+        if (!EmitExpression(out, var->constructor)) {
+            return false;
+        }
+        out << ";";
     }
-    line() << "#endif";
-    {
-      auto out = line();
-      out << "static const ";
-      if (!EmitTypeAndName(out, type, sem->StorageClass(), sem->Access(),
-                           builder_.Symbols().NameFor(var->symbol))) {
-        return false;
-      }
-      out << " = " << kSpecConstantPrefix << const_id << ";";
-    }
-  } else {
-    auto out = line();
-    out << "static const ";
-    if (!EmitTypeAndName(out, type, sem->StorageClass(), sem->Access(),
-                         builder_.Symbols().NameFor(var->symbol))) {
-      return false;
-    }
-    out << " = ";
-    if (!EmitExpression(out, var->constructor)) {
-      return false;
-    }
-    out << ";";
-  }
 
-  return true;
+    return true;
 }
 
 template <typename F>
@@ -3953,73 +3842,71 @@
                                       const ast::CallExpression* call,
                                       const sem::Builtin* builtin,
                                       F&& build) {
-  // Generate the helper function if it hasn't been created already
-  auto fn = utils::GetOrCreate(builtins_, builtin, [&]() -> std::string {
-    TextBuffer b;
-    TINT_DEFER(helpers_.Append(b));
+    // Generate the helper function if it hasn't been created already
+    auto fn = utils::GetOrCreate(builtins_, builtin, [&]() -> std::string {
+        TextBuffer b;
+        TINT_DEFER(helpers_.Append(b));
 
-    auto fn_name =
-        UniqueIdentifier(std::string("tint_") + sem::str(builtin->Type()));
-    std::vector<std::string> parameter_names;
-    {
-      auto decl = line(&b);
-      if (!EmitTypeAndName(decl, builtin->ReturnType(),
-                           ast::StorageClass::kNone, ast::Access::kUndefined,
-                           fn_name)) {
-        return "";
-      }
-      {
-        ScopedParen sp(decl);
-        for (auto* param : builtin->Parameters()) {
-          if (!parameter_names.empty()) {
-            decl << ", ";
-          }
-          auto param_name = "param_" + std::to_string(parameter_names.size());
-          const auto* ty = param->Type();
-          if (auto* ptr = ty->As<sem::Pointer>()) {
-            decl << "inout ";
-            ty = ptr->StoreType();
-          }
-          if (!EmitTypeAndName(decl, ty, ast::StorageClass::kNone,
-                               ast::Access::kUndefined, param_name)) {
-            return "";
-          }
-          parameter_names.emplace_back(std::move(param_name));
+        auto fn_name = UniqueIdentifier(std::string("tint_") + sem::str(builtin->Type()));
+        std::vector<std::string> parameter_names;
+        {
+            auto decl = line(&b);
+            if (!EmitTypeAndName(decl, builtin->ReturnType(), ast::StorageClass::kNone,
+                                 ast::Access::kUndefined, fn_name)) {
+                return "";
+            }
+            {
+                ScopedParen sp(decl);
+                for (auto* param : builtin->Parameters()) {
+                    if (!parameter_names.empty()) {
+                        decl << ", ";
+                    }
+                    auto param_name = "param_" + std::to_string(parameter_names.size());
+                    const auto* ty = param->Type();
+                    if (auto* ptr = ty->As<sem::Pointer>()) {
+                        decl << "inout ";
+                        ty = ptr->StoreType();
+                    }
+                    if (!EmitTypeAndName(decl, ty, ast::StorageClass::kNone,
+                                         ast::Access::kUndefined, param_name)) {
+                        return "";
+                    }
+                    parameter_names.emplace_back(std::move(param_name));
+                }
+            }
+            decl << " {";
         }
-      }
-      decl << " {";
-    }
-    {
-      ScopedIndent si(&b);
-      if (!build(&b, parameter_names)) {
-        return "";
-      }
-    }
-    line(&b) << "}";
-    line(&b);
-    return fn_name;
-  });
+        {
+            ScopedIndent si(&b);
+            if (!build(&b, parameter_names)) {
+                return "";
+            }
+        }
+        line(&b) << "}";
+        line(&b);
+        return fn_name;
+    });
 
-  if (fn.empty()) {
-    return false;
-  }
-
-  // Call the helper
-  out << fn;
-  {
-    ScopedParen sp(out);
-    bool first = true;
-    for (auto* arg : call->args) {
-      if (!first) {
-        out << ", ";
-      }
-      first = false;
-      if (!EmitExpression(out, arg)) {
+    if (fn.empty()) {
         return false;
-      }
     }
-  }
-  return true;
+
+    // Call the helper
+    out << fn;
+    {
+        ScopedParen sp(out);
+        bool first = true;
+        for (auto* arg : call->args) {
+            if (!first) {
+                out << ", ";
+            }
+            first = false;
+            if (!EmitExpression(out, arg)) {
+                return false;
+            }
+        }
+    }
+    return true;
 }
 
 }  // namespace tint::writer::hlsl
diff --git a/src/tint/writer/hlsl/generator_impl.h b/src/tint/writer/hlsl/generator_impl.h
index 4fcf151..e329638 100644
--- a/src/tint/writer/hlsl/generator_impl.h
+++ b/src/tint/writer/hlsl/generator_impl.h
@@ -52,18 +52,18 @@
 
 /// The result of sanitizing a program for generation.
 struct SanitizedResult {
-  /// Constructor
-  SanitizedResult();
-  /// Destructor
-  ~SanitizedResult();
-  /// Move constructor
-  SanitizedResult(SanitizedResult&&);
+    /// Constructor
+    SanitizedResult();
+    /// Destructor
+    ~SanitizedResult();
+    /// Move constructor
+    SanitizedResult(SanitizedResult&&);
 
-  /// The sanitized program.
-  Program program;
-  /// Indices into the array_length_from_uniform binding that are statically
-  /// used.
-  std::unordered_set<uint32_t> used_array_length_from_uniform_indices;
+    /// The sanitized program.
+    Program program;
+    /// Indices into the array_length_from_uniform binding that are statically
+    /// used.
+    std::unordered_set<uint32_t> used_array_length_from_uniform_indices;
 };
 
 /// Sanitize a program in preparation for generating HLSL.
@@ -74,461 +74,442 @@
 
 /// Implementation class for HLSL generator
 class GeneratorImpl : public TextGenerator {
- public:
-  /// Constructor
-  /// @param program the program to generate
-  explicit GeneratorImpl(const Program* program);
-  ~GeneratorImpl();
+  public:
+    /// Constructor
+    /// @param program the program to generate
+    explicit GeneratorImpl(const Program* program);
+    ~GeneratorImpl();
 
-  /// @returns true on successful generation; false otherwise
-  bool Generate();
+    /// @returns true on successful generation; false otherwise
+    bool Generate();
 
-  /// Handles an index accessor expression
-  /// @param out the output of the expression stream
-  /// @param expr the expression to emit
-  /// @returns true if the index accessor was emitted
-  bool EmitIndexAccessor(std::ostream& out,
-                         const ast::IndexAccessorExpression* expr);
-  /// Handles an assignment statement
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was emitted successfully
-  bool EmitAssign(const ast::AssignmentStatement* stmt);
-  /// Emits code such that if `expr` is zero, it emits one, else `expr`
-  /// @param out the output of the expression stream
-  /// @param expr the expression
-  /// @returns true if the expression was emitted, false otherwise
-  bool EmitExpressionOrOneIfZero(std::ostream& out,
-                                 const ast::Expression* expr);
-  /// Handles generating a binary expression
-  /// @param out the output of the expression stream
-  /// @param expr the binary expression
-  /// @returns true if the expression was emitted, false otherwise
-  bool EmitBinary(std::ostream& out, const ast::BinaryExpression* expr);
-  /// Handles generating a bitcast expression
-  /// @param out the output of the expression stream
-  /// @param expr the as expression
-  /// @returns true if the bitcast was emitted
-  bool EmitBitcast(std::ostream& out, const ast::BitcastExpression* expr);
-  /// Emits a list of statements
-  /// @param stmts the statement list
-  /// @returns true if the statements were emitted successfully
-  bool EmitStatements(const ast::StatementList& stmts);
-  /// Emits a list of statements with an indentation
-  /// @param stmts the statement list
-  /// @returns true if the statements were emitted successfully
-  bool EmitStatementsWithIndent(const ast::StatementList& stmts);
-  /// Handles a block statement
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was emitted successfully
-  bool EmitBlock(const ast::BlockStatement* stmt);
-  /// Handles a break statement
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was emitted successfully
-  bool EmitBreak(const ast::BreakStatement* stmt);
-  /// Handles generating a call expression
-  /// @param out the output of the expression stream
-  /// @param expr the call expression
-  /// @returns true if the call expression is emitted
-  bool EmitCall(std::ostream& out, const ast::CallExpression* expr);
-  /// Handles generating a function call expression
-  /// @param out the output of the expression stream
-  /// @param call the call expression
-  /// @param function the function being called
-  /// @returns true if the expression is emitted
-  bool EmitFunctionCall(std::ostream& out,
-                        const sem::Call* call,
-                        const sem::Function* function);
-  /// Handles generating a builtin call expression
-  /// @param out the output of the expression stream
-  /// @param call the call expression
-  /// @param builtin the builtin being called
-  /// @returns true if the expression is emitted
-  bool EmitBuiltinCall(std::ostream& out,
-                       const sem::Call* call,
-                       const sem::Builtin* builtin);
-  /// Handles generating a type conversion expression
-  /// @param out the output of the expression stream
-  /// @param call the call expression
-  /// @param conv the type conversion
-  /// @returns true if the expression is emitted
-  bool EmitTypeConversion(std::ostream& out,
-                          const sem::Call* call,
-                          const sem::TypeConversion* conv);
-  /// Handles generating a type constructor expression
-  /// @param out the output of the expression stream
-  /// @param call the call expression
-  /// @param ctor the type constructor
-  /// @returns true if the expression is emitted
-  bool EmitTypeConstructor(std::ostream& out,
-                           const sem::Call* call,
-                           const sem::TypeConstructor* ctor);
-  /// Handles generating a call expression to a
-  /// transform::DecomposeMemoryAccess::Intrinsic for a uniform buffer
-  /// @param out the output of the expression stream
-  /// @param expr the call expression
-  /// @param intrinsic the transform::DecomposeMemoryAccess::Intrinsic
-  /// @returns true if the call expression is emitted
-  bool EmitUniformBufferAccess(
-      std::ostream& out,
-      const ast::CallExpression* expr,
-      const transform::DecomposeMemoryAccess::Intrinsic* intrinsic);
-  /// Handles generating a call expression to a
-  /// transform::DecomposeMemoryAccess::Intrinsic for a storage buffer
-  /// @param out the output of the expression stream
-  /// @param expr the call expression
-  /// @param intrinsic the transform::DecomposeMemoryAccess::Intrinsic
-  /// @returns true if the call expression is emitted
-  bool EmitStorageBufferAccess(
-      std::ostream& out,
-      const ast::CallExpression* expr,
-      const transform::DecomposeMemoryAccess::Intrinsic* intrinsic);
-  /// Handles generating a barrier intrinsic call
-  /// @param out the output of the expression stream
-  /// @param builtin the semantic information for the barrier builtin
-  /// @returns true if the call expression is emitted
-  bool EmitBarrierCall(std::ostream& out, const sem::Builtin* builtin);
-  /// Handles generating an atomic intrinsic call for a storage buffer variable
-  /// @param out the output of the expression stream
-  /// @param expr the call expression
-  /// @param intrinsic the atomic intrinsic
-  /// @returns true if the call expression is emitted
-  bool EmitStorageAtomicCall(
-      std::ostream& out,
-      const ast::CallExpression* expr,
-      const transform::DecomposeMemoryAccess::Intrinsic* intrinsic);
-  /// Handles generating an atomic intrinsic call for a workgroup variable
-  /// @param out the output of the expression stream
-  /// @param expr the call expression
-  /// @param builtin the semantic information for the atomic builtin
-  /// @returns true if the call expression is emitted
-  bool EmitWorkgroupAtomicCall(std::ostream& out,
+    /// Handles an index accessor expression
+    /// @param out the output of the expression stream
+    /// @param expr the expression to emit
+    /// @returns true if the index accessor was emitted
+    bool EmitIndexAccessor(std::ostream& out, const ast::IndexAccessorExpression* expr);
+    /// Handles an assignment statement
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was emitted successfully
+    bool EmitAssign(const ast::AssignmentStatement* stmt);
+    /// Emits code such that if `expr` is zero, it emits one, else `expr`
+    /// @param out the output of the expression stream
+    /// @param expr the expression
+    /// @returns true if the expression was emitted, false otherwise
+    bool EmitExpressionOrOneIfZero(std::ostream& out, const ast::Expression* expr);
+    /// Handles generating a binary expression
+    /// @param out the output of the expression stream
+    /// @param expr the binary expression
+    /// @returns true if the expression was emitted, false otherwise
+    bool EmitBinary(std::ostream& out, const ast::BinaryExpression* expr);
+    /// Handles generating a bitcast expression
+    /// @param out the output of the expression stream
+    /// @param expr the as expression
+    /// @returns true if the bitcast was emitted
+    bool EmitBitcast(std::ostream& out, const ast::BitcastExpression* expr);
+    /// Emits a list of statements
+    /// @param stmts the statement list
+    /// @returns true if the statements were emitted successfully
+    bool EmitStatements(const ast::StatementList& stmts);
+    /// Emits a list of statements with an indentation
+    /// @param stmts the statement list
+    /// @returns true if the statements were emitted successfully
+    bool EmitStatementsWithIndent(const ast::StatementList& stmts);
+    /// Handles a block statement
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was emitted successfully
+    bool EmitBlock(const ast::BlockStatement* stmt);
+    /// Handles a break statement
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was emitted successfully
+    bool EmitBreak(const ast::BreakStatement* stmt);
+    /// Handles generating a call expression
+    /// @param out the output of the expression stream
+    /// @param expr the call expression
+    /// @returns true if the call expression is emitted
+    bool EmitCall(std::ostream& out, const ast::CallExpression* expr);
+    /// Handles generating a function call expression
+    /// @param out the output of the expression stream
+    /// @param call the call expression
+    /// @param function the function being called
+    /// @returns true if the expression is emitted
+    bool EmitFunctionCall(std::ostream& out, const sem::Call* call, const sem::Function* function);
+    /// Handles generating a builtin call expression
+    /// @param out the output of the expression stream
+    /// @param call the call expression
+    /// @param builtin the builtin being called
+    /// @returns true if the expression is emitted
+    bool EmitBuiltinCall(std::ostream& out, const sem::Call* call, const sem::Builtin* builtin);
+    /// Handles generating a type conversion expression
+    /// @param out the output of the expression stream
+    /// @param call the call expression
+    /// @param conv the type conversion
+    /// @returns true if the expression is emitted
+    bool EmitTypeConversion(std::ostream& out,
+                            const sem::Call* call,
+                            const sem::TypeConversion* conv);
+    /// Handles generating a type constructor expression
+    /// @param out the output of the expression stream
+    /// @param call the call expression
+    /// @param ctor the type constructor
+    /// @returns true if the expression is emitted
+    bool EmitTypeConstructor(std::ostream& out,
+                             const sem::Call* call,
+                             const sem::TypeConstructor* ctor);
+    /// Handles generating a call expression to a
+    /// transform::DecomposeMemoryAccess::Intrinsic for a uniform buffer
+    /// @param out the output of the expression stream
+    /// @param expr the call expression
+    /// @param intrinsic the transform::DecomposeMemoryAccess::Intrinsic
+    /// @returns true if the call expression is emitted
+    bool EmitUniformBufferAccess(std::ostream& out,
+                                 const ast::CallExpression* expr,
+                                 const transform::DecomposeMemoryAccess::Intrinsic* intrinsic);
+    /// Handles generating a call expression to a
+    /// transform::DecomposeMemoryAccess::Intrinsic for a storage buffer
+    /// @param out the output of the expression stream
+    /// @param expr the call expression
+    /// @param intrinsic the transform::DecomposeMemoryAccess::Intrinsic
+    /// @returns true if the call expression is emitted
+    bool EmitStorageBufferAccess(std::ostream& out,
+                                 const ast::CallExpression* expr,
+                                 const transform::DecomposeMemoryAccess::Intrinsic* intrinsic);
+    /// Handles generating a barrier intrinsic call
+    /// @param out the output of the expression stream
+    /// @param builtin the semantic information for the barrier builtin
+    /// @returns true if the call expression is emitted
+    bool EmitBarrierCall(std::ostream& out, const sem::Builtin* builtin);
+    /// Handles generating an atomic intrinsic call for a storage buffer variable
+    /// @param out the output of the expression stream
+    /// @param expr the call expression
+    /// @param intrinsic the atomic intrinsic
+    /// @returns true if the call expression is emitted
+    bool EmitStorageAtomicCall(std::ostream& out,
                                const ast::CallExpression* expr,
-                               const sem::Builtin* builtin);
-  /// Handles generating a call to a texture function (`textureSample`,
-  /// `textureSampleGrad`, etc)
-  /// @param out the output of the expression stream
-  /// @param call the call expression
-  /// @param builtin the semantic information for the texture builtin
-  /// @returns true if the call expression is emitted
-  bool EmitTextureCall(std::ostream& out,
-                       const sem::Call* call,
-                       const sem::Builtin* builtin);
-  /// Handles generating a call to the `select()` builtin
-  /// @param out the output of the expression stream
-  /// @param expr the call expression
-  /// @returns true if the call expression is emitted
-  bool EmitSelectCall(std::ostream& out, const ast::CallExpression* expr);
-  /// Handles generating a call to the `modf()` builtin
-  /// @param out the output of the expression stream
-  /// @param expr the call expression
-  /// @param builtin the semantic information for the builtin
-  /// @returns true if the call expression is emitted
-  bool EmitModfCall(std::ostream& out,
-                    const ast::CallExpression* expr,
-                    const sem::Builtin* builtin);
-  /// Handles generating a call to the `frexp()` builtin
-  /// @param out the output of the expression stream
-  /// @param expr the call expression
-  /// @param builtin the semantic information for the builtin
-  /// @returns true if the call expression is emitted
-  bool EmitFrexpCall(std::ostream& out,
-                     const ast::CallExpression* expr,
-                     const sem::Builtin* builtin);
-  /// Handles generating a call to the `degrees()` builtin
-  /// @param out the output of the expression stream
-  /// @param expr the call expression
-  /// @param builtin the semantic information for the builtin
-  /// @returns true if the call expression is emitted
-  bool EmitDegreesCall(std::ostream& out,
+                               const transform::DecomposeMemoryAccess::Intrinsic* intrinsic);
+    /// Handles generating an atomic intrinsic call for a workgroup variable
+    /// @param out the output of the expression stream
+    /// @param expr the call expression
+    /// @param builtin the semantic information for the atomic builtin
+    /// @returns true if the call expression is emitted
+    bool EmitWorkgroupAtomicCall(std::ostream& out,
+                                 const ast::CallExpression* expr,
+                                 const sem::Builtin* builtin);
+    /// Handles generating a call to a texture function (`textureSample`,
+    /// `textureSampleGrad`, etc)
+    /// @param out the output of the expression stream
+    /// @param call the call expression
+    /// @param builtin the semantic information for the texture builtin
+    /// @returns true if the call expression is emitted
+    bool EmitTextureCall(std::ostream& out, const sem::Call* call, const sem::Builtin* builtin);
+    /// Handles generating a call to the `select()` builtin
+    /// @param out the output of the expression stream
+    /// @param expr the call expression
+    /// @returns true if the call expression is emitted
+    bool EmitSelectCall(std::ostream& out, const ast::CallExpression* expr);
+    /// Handles generating a call to the `modf()` builtin
+    /// @param out the output of the expression stream
+    /// @param expr the call expression
+    /// @param builtin the semantic information for the builtin
+    /// @returns true if the call expression is emitted
+    bool EmitModfCall(std::ostream& out,
+                      const ast::CallExpression* expr,
+                      const sem::Builtin* builtin);
+    /// Handles generating a call to the `frexp()` builtin
+    /// @param out the output of the expression stream
+    /// @param expr the call expression
+    /// @param builtin the semantic information for the builtin
+    /// @returns true if the call expression is emitted
+    bool EmitFrexpCall(std::ostream& out,
                        const ast::CallExpression* expr,
                        const sem::Builtin* builtin);
-  /// Handles generating a call to the `radians()` builtin
-  /// @param out the output of the expression stream
-  /// @param expr the call expression
-  /// @param builtin the semantic information for the builtin
-  /// @returns true if the call expression is emitted
-  bool EmitRadiansCall(std::ostream& out,
-                       const ast::CallExpression* expr,
-                       const sem::Builtin* builtin);
-  /// Handles generating a call to data packing builtin
-  /// @param out the output of the expression stream
-  /// @param expr the call expression
-  /// @param builtin the semantic information for the texture builtin
-  /// @returns true if the call expression is emitted
-  bool EmitDataPackingCall(std::ostream& out,
-                           const ast::CallExpression* expr,
-                           const sem::Builtin* builtin);
-  /// Handles generating a call to data unpacking builtin
-  /// @param out the output of the expression stream
-  /// @param expr the call expression
-  /// @param builtin the semantic information for the texture builtin
-  /// @returns true if the call expression is emitted
-  bool EmitDataUnpackingCall(std::ostream& out,
+    /// Handles generating a call to the `degrees()` builtin
+    /// @param out the output of the expression stream
+    /// @param expr the call expression
+    /// @param builtin the semantic information for the builtin
+    /// @returns true if the call expression is emitted
+    bool EmitDegreesCall(std::ostream& out,
+                         const ast::CallExpression* expr,
+                         const sem::Builtin* builtin);
+    /// Handles generating a call to the `radians()` builtin
+    /// @param out the output of the expression stream
+    /// @param expr the call expression
+    /// @param builtin the semantic information for the builtin
+    /// @returns true if the call expression is emitted
+    bool EmitRadiansCall(std::ostream& out,
+                         const ast::CallExpression* expr,
+                         const sem::Builtin* builtin);
+    /// Handles generating a call to data packing builtin
+    /// @param out the output of the expression stream
+    /// @param expr the call expression
+    /// @param builtin the semantic information for the texture builtin
+    /// @returns true if the call expression is emitted
+    bool EmitDataPackingCall(std::ostream& out,
                              const ast::CallExpression* expr,
                              const sem::Builtin* builtin);
-  /// Handles a case statement
-  /// @param s the switch statement
-  /// @param case_idx the index of the switch case in the switch statement
-  /// @returns true if the statement was emitted successfully
-  bool EmitCase(const ast::SwitchStatement* s, size_t case_idx);
-  /// Handles generating a discard statement
-  /// @param stmt the discard statement
-  /// @returns true if the statement was successfully emitted
-  bool EmitDiscard(const ast::DiscardStatement* stmt);
-  /// Handles a continue statement
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was emitted successfully
-  bool EmitContinue(const ast::ContinueStatement* stmt);
-  /// Handles generate an Expression
-  /// @param out the output of the expression stream
-  /// @param expr the expression
-  /// @returns true if the expression was emitted
-  bool EmitExpression(std::ostream& out, const ast::Expression* expr);
-  /// Handles generating a function
-  /// @param func the function to generate
-  /// @returns true if the function was emitted
-  bool EmitFunction(const ast::Function* func);
-  /// Handles emitting the function body if it discards to work around a FXC
-  /// compilation bug.
-  /// @param func the function with the body to emit
-  /// @returns true if the function was emitted
-  bool EmitFunctionBodyWithDiscard(const ast::Function* func);
-  /// Handles emitting a global variable
-  /// @param global the global variable
-  /// @returns true on success
-  bool EmitGlobalVariable(const ast::Variable* global);
+    /// Handles generating a call to data unpacking builtin
+    /// @param out the output of the expression stream
+    /// @param expr the call expression
+    /// @param builtin the semantic information for the texture builtin
+    /// @returns true if the call expression is emitted
+    bool EmitDataUnpackingCall(std::ostream& out,
+                               const ast::CallExpression* expr,
+                               const sem::Builtin* builtin);
+    /// Handles a case statement
+    /// @param s the switch statement
+    /// @param case_idx the index of the switch case in the switch statement
+    /// @returns true if the statement was emitted successfully
+    bool EmitCase(const ast::SwitchStatement* s, size_t case_idx);
+    /// Handles generating a discard statement
+    /// @param stmt the discard statement
+    /// @returns true if the statement was successfully emitted
+    bool EmitDiscard(const ast::DiscardStatement* stmt);
+    /// Handles a continue statement
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was emitted successfully
+    bool EmitContinue(const ast::ContinueStatement* stmt);
+    /// Handles generate an Expression
+    /// @param out the output of the expression stream
+    /// @param expr the expression
+    /// @returns true if the expression was emitted
+    bool EmitExpression(std::ostream& out, const ast::Expression* expr);
+    /// Handles generating a function
+    /// @param func the function to generate
+    /// @returns true if the function was emitted
+    bool EmitFunction(const ast::Function* func);
+    /// Handles emitting the function body if it discards to work around a FXC
+    /// compilation bug.
+    /// @param func the function with the body to emit
+    /// @returns true if the function was emitted
+    bool EmitFunctionBodyWithDiscard(const ast::Function* func);
+    /// Handles emitting a global variable
+    /// @param global the global variable
+    /// @returns true on success
+    bool EmitGlobalVariable(const ast::Variable* global);
 
-  /// Handles emitting a global variable with the uniform storage class
-  /// @param var the global variable
-  /// @returns true on success
-  bool EmitUniformVariable(const sem::Variable* var);
+    /// Handles emitting a global variable with the uniform storage class
+    /// @param var the global variable
+    /// @returns true on success
+    bool EmitUniformVariable(const sem::Variable* var);
 
-  /// Handles emitting a global variable with the storage storage class
-  /// @param var the global variable
-  /// @returns true on success
-  bool EmitStorageVariable(const sem::Variable* var);
+    /// Handles emitting a global variable with the storage storage class
+    /// @param var the global variable
+    /// @returns true on success
+    bool EmitStorageVariable(const sem::Variable* var);
 
-  /// Handles emitting a global variable with the handle storage class
-  /// @param var the global variable
-  /// @returns true on success
-  bool EmitHandleVariable(const sem::Variable* var);
+    /// Handles emitting a global variable with the handle storage class
+    /// @param var the global variable
+    /// @returns true on success
+    bool EmitHandleVariable(const sem::Variable* var);
 
-  /// Handles emitting a global variable with the private storage class
-  /// @param var the global variable
-  /// @returns true on success
-  bool EmitPrivateVariable(const sem::Variable* var);
+    /// Handles emitting a global variable with the private storage class
+    /// @param var the global variable
+    /// @returns true on success
+    bool EmitPrivateVariable(const sem::Variable* var);
 
-  /// Handles emitting a global variable with the workgroup storage class
-  /// @param var the global variable
-  /// @returns true on success
-  bool EmitWorkgroupVariable(const sem::Variable* var);
+    /// Handles emitting a global variable with the workgroup storage class
+    /// @param var the global variable
+    /// @returns true on success
+    bool EmitWorkgroupVariable(const sem::Variable* var);
 
-  /// Handles emitting the entry point function
-  /// @param func the entry point
-  /// @returns true if the entry point function was emitted
-  bool EmitEntryPointFunction(const ast::Function* func);
-  /// Handles an if statement
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was successfully emitted
-  bool EmitIf(const ast::IfStatement* stmt);
-  /// Handles a literal
-  /// @param out the output stream
-  /// @param lit the literal to emit
-  /// @returns true if the literal was successfully emitted
-  bool EmitLiteral(std::ostream& out, const ast::LiteralExpression* lit);
-  /// Handles a loop statement
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was emitted
-  bool EmitLoop(const ast::LoopStatement* stmt);
-  /// Handles a for loop statement
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was emitted
-  bool EmitForLoop(const ast::ForLoopStatement* stmt);
-  /// Handles generating an identifier expression
-  /// @param out the output of the expression stream
-  /// @param expr the identifier expression
-  /// @returns true if the identifeir was emitted
-  bool EmitIdentifier(std::ostream& out, const ast::IdentifierExpression* expr);
-  /// Handles a member accessor expression
-  /// @param out the output of the expression stream
-  /// @param expr the member accessor expression
-  /// @returns true if the member accessor was emitted
-  bool EmitMemberAccessor(std::ostream& out,
-                          const ast::MemberAccessorExpression* expr);
-  /// Handles return statements
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was successfully emitted
-  bool EmitReturn(const ast::ReturnStatement* stmt);
-  /// Handles statement
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was emitted
-  bool EmitStatement(const ast::Statement* stmt);
-  /// Handles generating a switch statement
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was emitted
-  bool EmitSwitch(const ast::SwitchStatement* stmt);
-  // Handles generating a switch statement with only a default case
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was emitted
-  bool EmitDefaultOnlySwitch(const ast::SwitchStatement* stmt);
-  /// Handles generating type
-  /// @param out the output stream
-  /// @param type the type to generate
-  /// @param storage_class the storage class of the variable
-  /// @param access the access control type of the variable
-  /// @param name the name of the variable, used for array emission.
-  /// @param name_printed (optional) if not nullptr and an array was printed
-  /// then the boolean is set to true.
-  /// @returns true if the type is emitted
-  bool EmitType(std::ostream& out,
-                const sem::Type* type,
-                ast::StorageClass storage_class,
-                ast::Access access,
-                const std::string& name,
-                bool* name_printed = nullptr);
-  /// Handles generating type and name
-  /// @param out the output stream
-  /// @param type the type to generate
-  /// @param storage_class the storage class of the variable
-  /// @param access the access control type of the variable
-  /// @param name the name to emit
-  /// @returns true if the type is emitted
-  bool EmitTypeAndName(std::ostream& out,
-                       const sem::Type* type,
-                       ast::StorageClass storage_class,
-                       ast::Access access,
-                       const std::string& name);
-  /// Handles generating a structure declaration
-  /// @param buffer the text buffer that the type declaration will be written to
-  /// @param ty the struct to generate
-  /// @returns true if the struct is emitted
-  bool EmitStructType(TextBuffer* buffer, const sem::Struct* ty);
-  /// Handles a unary op expression
-  /// @param out the output of the expression stream
-  /// @param expr the expression to emit
-  /// @returns true if the expression was emitted
-  bool EmitUnaryOp(std::ostream& out, const ast::UnaryOpExpression* expr);
-  /// Emits `value` for the given type
-  /// @param out the output stream
-  /// @param type the type to emit the value for
-  /// @param value the value to emit
-  /// @returns true if the value was successfully emitted.
-  bool EmitValue(std::ostream& out, const sem::Type* type, int value);
-  /// Emits the zero value for the given type
-  /// @param out the output stream
-  /// @param type the type to emit the value for
-  /// @returns true if the zero value was successfully emitted.
-  bool EmitZeroValue(std::ostream& out, const sem::Type* type);
-  /// Handles generating a variable
-  /// @param var the variable to generate
-  /// @returns true if the variable was emitted
-  bool EmitVariable(const ast::Variable* var);
-  /// Handles generating a program scope constant variable
-  /// @param var the variable to emit
-  /// @returns true if the variable was emitted
-  bool EmitProgramConstVariable(const ast::Variable* var);
-  /// Emits call to a helper vector assignment function for the input assignment
-  /// statement and vector type. This is used to work around FXC issues where
-  /// assignments to vectors with dynamic indices cause compilation failures.
-  /// @param stmt assignment statement that corresponds to a vector assignment
-  /// via an accessor expression
-  /// @param vec the vector type being assigned to
-  /// @returns true on success
-  bool EmitDynamicVectorAssignment(const ast::AssignmentStatement* stmt,
-                                   const sem::Vector* vec);
-  /// Emits call to a helper matrix assignment function for the input assignment
-  /// statement and matrix type. This is used to work around FXC issues where
-  /// assignment of a vector to a matrix with a dynamic index causes compilation
-  /// failures.
-  /// @param stmt assignment statement that corresponds to a matrix assignment
-  /// via an accessor expression
-  /// @param mat the matrix type being assigned to
-  /// @returns true on success
-  bool EmitDynamicMatrixVectorAssignment(const ast::AssignmentStatement* stmt,
-                                         const sem::Matrix* mat);
-  /// Emits call to a helper matrix assignment function for the input assignment
-  /// statement and matrix type. This is used to work around FXC issues where
-  /// assignment of a scalar to a matrix with at least one dynamic index causes
-  /// compilation failures.
-  /// @param stmt assignment statement that corresponds to a matrix assignment
-  /// via an accessor expression
-  /// @param mat the matrix type being assigned to
-  /// @returns true on success
-  bool EmitDynamicMatrixScalarAssignment(const ast::AssignmentStatement* stmt,
-                                         const sem::Matrix* mat);
+    /// Handles emitting the entry point function
+    /// @param func the entry point
+    /// @returns true if the entry point function was emitted
+    bool EmitEntryPointFunction(const ast::Function* func);
+    /// Handles an if statement
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was successfully emitted
+    bool EmitIf(const ast::IfStatement* stmt);
+    /// Handles a literal
+    /// @param out the output stream
+    /// @param lit the literal to emit
+    /// @returns true if the literal was successfully emitted
+    bool EmitLiteral(std::ostream& out, const ast::LiteralExpression* lit);
+    /// Handles a loop statement
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was emitted
+    bool EmitLoop(const ast::LoopStatement* stmt);
+    /// Handles a for loop statement
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was emitted
+    bool EmitForLoop(const ast::ForLoopStatement* stmt);
+    /// Handles generating an identifier expression
+    /// @param out the output of the expression stream
+    /// @param expr the identifier expression
+    /// @returns true if the identifeir was emitted
+    bool EmitIdentifier(std::ostream& out, const ast::IdentifierExpression* expr);
+    /// Handles a member accessor expression
+    /// @param out the output of the expression stream
+    /// @param expr the member accessor expression
+    /// @returns true if the member accessor was emitted
+    bool EmitMemberAccessor(std::ostream& out, const ast::MemberAccessorExpression* expr);
+    /// Handles return statements
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was successfully emitted
+    bool EmitReturn(const ast::ReturnStatement* stmt);
+    /// Handles statement
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was emitted
+    bool EmitStatement(const ast::Statement* stmt);
+    /// Handles generating a switch statement
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was emitted
+    bool EmitSwitch(const ast::SwitchStatement* stmt);
+    // Handles generating a switch statement with only a default case
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was emitted
+    bool EmitDefaultOnlySwitch(const ast::SwitchStatement* stmt);
+    /// Handles generating type
+    /// @param out the output stream
+    /// @param type the type to generate
+    /// @param storage_class the storage class of the variable
+    /// @param access the access control type of the variable
+    /// @param name the name of the variable, used for array emission.
+    /// @param name_printed (optional) if not nullptr and an array was printed
+    /// then the boolean is set to true.
+    /// @returns true if the type is emitted
+    bool EmitType(std::ostream& out,
+                  const sem::Type* type,
+                  ast::StorageClass storage_class,
+                  ast::Access access,
+                  const std::string& name,
+                  bool* name_printed = nullptr);
+    /// Handles generating type and name
+    /// @param out the output stream
+    /// @param type the type to generate
+    /// @param storage_class the storage class of the variable
+    /// @param access the access control type of the variable
+    /// @param name the name to emit
+    /// @returns true if the type is emitted
+    bool EmitTypeAndName(std::ostream& out,
+                         const sem::Type* type,
+                         ast::StorageClass storage_class,
+                         ast::Access access,
+                         const std::string& name);
+    /// Handles generating a structure declaration
+    /// @param buffer the text buffer that the type declaration will be written to
+    /// @param ty the struct to generate
+    /// @returns true if the struct is emitted
+    bool EmitStructType(TextBuffer* buffer, const sem::Struct* ty);
+    /// Handles a unary op expression
+    /// @param out the output of the expression stream
+    /// @param expr the expression to emit
+    /// @returns true if the expression was emitted
+    bool EmitUnaryOp(std::ostream& out, const ast::UnaryOpExpression* expr);
+    /// Emits `value` for the given type
+    /// @param out the output stream
+    /// @param type the type to emit the value for
+    /// @param value the value to emit
+    /// @returns true if the value was successfully emitted.
+    bool EmitValue(std::ostream& out, const sem::Type* type, int value);
+    /// Emits the zero value for the given type
+    /// @param out the output stream
+    /// @param type the type to emit the value for
+    /// @returns true if the zero value was successfully emitted.
+    bool EmitZeroValue(std::ostream& out, const sem::Type* type);
+    /// Handles generating a variable
+    /// @param var the variable to generate
+    /// @returns true if the variable was emitted
+    bool EmitVariable(const ast::Variable* var);
+    /// Handles generating a program scope constant variable
+    /// @param var the variable to emit
+    /// @returns true if the variable was emitted
+    bool EmitProgramConstVariable(const ast::Variable* var);
+    /// Emits call to a helper vector assignment function for the input assignment
+    /// statement and vector type. This is used to work around FXC issues where
+    /// assignments to vectors with dynamic indices cause compilation failures.
+    /// @param stmt assignment statement that corresponds to a vector assignment
+    /// via an accessor expression
+    /// @param vec the vector type being assigned to
+    /// @returns true on success
+    bool EmitDynamicVectorAssignment(const ast::AssignmentStatement* stmt, const sem::Vector* vec);
+    /// Emits call to a helper matrix assignment function for the input assignment
+    /// statement and matrix type. This is used to work around FXC issues where
+    /// assignment of a vector to a matrix with a dynamic index causes compilation
+    /// failures.
+    /// @param stmt assignment statement that corresponds to a matrix assignment
+    /// via an accessor expression
+    /// @param mat the matrix type being assigned to
+    /// @returns true on success
+    bool EmitDynamicMatrixVectorAssignment(const ast::AssignmentStatement* stmt,
+                                           const sem::Matrix* mat);
+    /// Emits call to a helper matrix assignment function for the input assignment
+    /// statement and matrix type. This is used to work around FXC issues where
+    /// assignment of a scalar to a matrix with at least one dynamic index causes
+    /// compilation failures.
+    /// @param stmt assignment statement that corresponds to a matrix assignment
+    /// via an accessor expression
+    /// @param mat the matrix type being assigned to
+    /// @returns true on success
+    bool EmitDynamicMatrixScalarAssignment(const ast::AssignmentStatement* stmt,
+                                           const sem::Matrix* mat);
 
-  /// Handles generating a builtin method name
-  /// @param builtin the semantic info for the builtin
-  /// @returns the name or "" if not valid
-  std::string generate_builtin_name(const sem::Builtin* builtin);
-  /// 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;
+    /// Handles generating a builtin method name
+    /// @param builtin the semantic info for the builtin
+    /// @returns the name or "" if not valid
+    std::string generate_builtin_name(const sem::Builtin* builtin);
+    /// 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;
 
-  /// Converts interpolation attributes to a HLSL modifiers
-  /// @param type the interpolation type
-  /// @param sampling the interpolation sampling
-  /// @returns the string name of the attribute or blank on error
-  std::string interpolation_to_modifiers(
-      ast::InterpolationType type,
-      ast::InterpolationSampling sampling) const;
+    /// Converts interpolation attributes to a HLSL modifiers
+    /// @param type the interpolation type
+    /// @param sampling the interpolation sampling
+    /// @returns the string name of the attribute or blank on error
+    std::string interpolation_to_modifiers(ast::InterpolationType type,
+                                           ast::InterpolationSampling sampling) const;
 
- private:
-  enum class VarType { kIn, kOut };
+  private:
+    enum class VarType { kIn, kOut };
 
-  struct EntryPointData {
-    std::string struct_name;
-    std::string var_name;
-  };
-
-  struct DMAIntrinsic {
-    transform::DecomposeMemoryAccess::Intrinsic::Op op;
-    transform::DecomposeMemoryAccess::Intrinsic::DataType type;
-    bool operator==(const DMAIntrinsic& rhs) const {
-      return op == rhs.op && type == rhs.type;
-    }
-    /// Hasher is a std::hash function for DMAIntrinsic
-    struct Hasher {
-      /// @param i the DMAIntrinsic to hash
-      /// @returns the hash of `i`
-      inline std::size_t operator()(const DMAIntrinsic& i) const {
-        return utils::Hash(i.op, i.type);
-      }
+    struct EntryPointData {
+        std::string struct_name;
+        std::string var_name;
     };
-  };
 
-  /// CallBuiltinHelper will call the builtin helper function, creating it
-  /// if it hasn't been built already. If the builtin needs to be built then
-  /// CallBuiltinHelper will generate the function signature and will call
-  /// `build` to emit the body of the function.
-  /// @param out the output of the expression stream
-  /// @param call the call expression
-  /// @param builtin the semantic information for the builtin
-  /// @param build a function with the signature:
-  ///        `bool(TextBuffer* buffer, const std::vector<std::string>& params)`
-  ///        Where:
-  ///          `buffer` is the body of the generated function
-  ///          `params` is the name of all the generated function parameters
-  /// @returns true if the call expression is emitted
-  template <typename F>
-  bool CallBuiltinHelper(std::ostream& out,
-                         const ast::CallExpression* call,
-                         const sem::Builtin* builtin,
-                         F&& build);
+    struct DMAIntrinsic {
+        transform::DecomposeMemoryAccess::Intrinsic::Op op;
+        transform::DecomposeMemoryAccess::Intrinsic::DataType type;
+        bool operator==(const DMAIntrinsic& rhs) const { return op == rhs.op && type == rhs.type; }
+        /// Hasher is a std::hash function for DMAIntrinsic
+        struct Hasher {
+            /// @param i the DMAIntrinsic to hash
+            /// @returns the hash of `i`
+            inline std::size_t operator()(const DMAIntrinsic& i) const {
+                return utils::Hash(i.op, i.type);
+            }
+        };
+    };
 
-  TextBuffer helpers_;  // Helper functions emitted at the top of the output
-  std::function<bool()> emit_continuing_;
-  std::unordered_map<DMAIntrinsic, std::string, DMAIntrinsic::Hasher>
-      dma_intrinsics_;
-  std::unordered_map<const sem::Builtin*, std::string> builtins_;
-  std::unordered_map<const sem::Struct*, std::string> structure_builders_;
-  std::unordered_map<const sem::Vector*, std::string> dynamic_vector_write_;
-  std::unordered_map<const sem::Matrix*, std::string>
-      dynamic_matrix_vector_write_;
-  std::unordered_map<const sem::Matrix*, std::string>
-      dynamic_matrix_scalar_write_;
-  std::unordered_map<const sem::Type*, std::string> value_or_one_if_zero_;
+    /// CallBuiltinHelper will call the builtin helper function, creating it
+    /// if it hasn't been built already. If the builtin needs to be built then
+    /// CallBuiltinHelper will generate the function signature and will call
+    /// `build` to emit the body of the function.
+    /// @param out the output of the expression stream
+    /// @param call the call expression
+    /// @param builtin the semantic information for the builtin
+    /// @param build a function with the signature:
+    ///        `bool(TextBuffer* buffer, const std::vector<std::string>& params)`
+    ///        Where:
+    ///          `buffer` is the body of the generated function
+    ///          `params` is the name of all the generated function parameters
+    /// @returns true if the call expression is emitted
+    template <typename F>
+    bool CallBuiltinHelper(std::ostream& out,
+                           const ast::CallExpression* call,
+                           const sem::Builtin* builtin,
+                           F&& build);
+
+    TextBuffer helpers_;  // Helper functions emitted at the top of the output
+    std::function<bool()> emit_continuing_;
+    std::unordered_map<DMAIntrinsic, std::string, DMAIntrinsic::Hasher> dma_intrinsics_;
+    std::unordered_map<const sem::Builtin*, std::string> builtins_;
+    std::unordered_map<const sem::Struct*, std::string> structure_builders_;
+    std::unordered_map<const sem::Vector*, std::string> dynamic_vector_write_;
+    std::unordered_map<const sem::Matrix*, std::string> dynamic_matrix_vector_write_;
+    std::unordered_map<const sem::Matrix*, std::string> dynamic_matrix_scalar_write_;
+    std::unordered_map<const sem::Type*, std::string> value_or_one_if_zero_;
 };
 
 }  // namespace tint::writer::hlsl
diff --git a/src/tint/writer/hlsl/generator_impl_array_accessor_test.cc b/src/tint/writer/hlsl/generator_impl_array_accessor_test.cc
index bcf3ad1..bbdeb10 100644
--- a/src/tint/writer/hlsl/generator_impl_array_accessor_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_array_accessor_test.cc
@@ -14,21 +14,23 @@
 
 #include "src/tint/writer/hlsl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::hlsl {
 namespace {
 
 using HlslGeneratorImplTest_Expression = TestHelper;
 
 TEST_F(HlslGeneratorImplTest_Expression, IndexAccessor) {
-  Global("ary", ty.array<i32, 10>(), ast::StorageClass::kPrivate);
-  auto* expr = IndexAccessor("ary", 5);
-  WrapInFunction(expr);
+    Global("ary", ty.array<i32, 10>(), ast::StorageClass::kPrivate);
+    auto* expr = IndexAccessor("ary", 5_i);
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), "ary[5]");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), "ary[5]");
 }
 
 }  // namespace
diff --git a/src/tint/writer/hlsl/generator_impl_assign_test.cc b/src/tint/writer/hlsl/generator_impl_assign_test.cc
index 6305dc0..5e5f031 100644
--- a/src/tint/writer/hlsl/generator_impl_assign_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_assign_test.cc
@@ -14,24 +14,26 @@
 
 #include "src/tint/writer/hlsl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::hlsl {
 namespace {
 
 using HlslGeneratorImplTest_Assign = TestHelper;
 
 TEST_F(HlslGeneratorImplTest_Assign, Emit_Assign) {
-  Func("fn", {}, ty.void_(),
-       {
-           Decl(Var("lhs", ty.i32())),
-           Decl(Var("rhs", ty.i32())),
-           Assign("lhs", "rhs"),
-       });
+    Func("fn", {}, ty.void_(),
+         {
+             Decl(Var("lhs", ty.i32())),
+             Decl(Var("rhs", ty.i32())),
+             Assign("lhs", "rhs"),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate());
-  EXPECT_EQ(gen.result(),
-            R"(void fn() {
+    ASSERT_TRUE(gen.Generate());
+    EXPECT_EQ(gen.result(),
+              R"(void fn() {
   int lhs = 0;
   int rhs = 0;
   lhs = rhs;
@@ -40,19 +42,19 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Assign, Emit_Vector_Assign_ConstantIndex) {
-  Func("fn", {}, ty.void_(),
-       {
-           Decl(Var("lhs", ty.vec3<f32>())),
-           Decl(Var("rhs", ty.f32())),
-           Decl(Const("index", ty.u32(), Expr(0u))),
-           Assign(IndexAccessor("lhs", "index"), "rhs"),
-       });
+    Func("fn", {}, ty.void_(),
+         {
+             Decl(Var("lhs", ty.vec3<f32>())),
+             Decl(Var("rhs", ty.f32())),
+             Decl(Let("index", ty.u32(), Expr(0_u))),
+             Assign(IndexAccessor("lhs", "index"), "rhs"),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate());
-  EXPECT_EQ(gen.result(),
-            R"(void fn() {
+    ASSERT_TRUE(gen.Generate());
+    EXPECT_EQ(gen.result(),
+              R"(void fn() {
   float3 lhs = float3(0.0f, 0.0f, 0.0f);
   float rhs = 0.0f;
   const uint index = 0u;
@@ -62,19 +64,19 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Assign, Emit_Vector_Assign_DynamicIndex) {
-  Func("fn", {}, ty.void_(),
-       {
-           Decl(Var("lhs", ty.vec3<f32>())),
-           Decl(Var("rhs", ty.f32())),
-           Decl(Var("index", ty.u32())),
-           Assign(IndexAccessor("lhs", "index"), "rhs"),
-       });
+    Func("fn", {}, ty.void_(),
+         {
+             Decl(Var("lhs", ty.vec3<f32>())),
+             Decl(Var("rhs", ty.f32())),
+             Decl(Var("index", ty.u32())),
+             Assign(IndexAccessor("lhs", "index"), "rhs"),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate());
-  EXPECT_EQ(gen.result(),
-            R"(void set_float3(inout float3 vec, int idx, float val) {
+    ASSERT_TRUE(gen.Generate());
+    EXPECT_EQ(gen.result(),
+              R"(void set_float3(inout float3 vec, int idx, float val) {
   vec = (idx.xxx == int3(0, 1, 2)) ? val.xxx : vec;
 }
 
@@ -88,19 +90,19 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Assign, Emit_Matrix_Assign_Vector_ConstantIndex) {
-  Func("fn", {}, ty.void_(),
-       {
-           Decl(Var("lhs", ty.mat4x2<f32>())),
-           Decl(Var("rhs", ty.vec2<f32>())),
-           Decl(Const("index", ty.u32(), Expr(0u))),
-           Assign(IndexAccessor("lhs", "index"), "rhs"),
-       });
+    Func("fn", {}, ty.void_(),
+         {
+             Decl(Var("lhs", ty.mat4x2<f32>())),
+             Decl(Var("rhs", ty.vec2<f32>())),
+             Decl(Let("index", ty.u32(), Expr(0_u))),
+             Assign(IndexAccessor("lhs", "index"), "rhs"),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate());
-  EXPECT_EQ(gen.result(),
-            R"(void fn() {
+    ASSERT_TRUE(gen.Generate());
+    EXPECT_EQ(gen.result(),
+              R"(void fn() {
   float4x2 lhs = float4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
   float2 rhs = float2(0.0f, 0.0f);
   const uint index = 0u;
@@ -110,20 +112,19 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Assign, Emit_Matrix_Assign_Vector_DynamicIndex) {
-  Func("fn", {}, ty.void_(),
-       {
-           Decl(Var("lhs", ty.mat4x2<f32>())),
-           Decl(Var("rhs", ty.vec2<f32>())),
-           Decl(Var("index", ty.u32())),
-           Assign(IndexAccessor("lhs", "index"), "rhs"),
-       });
+    Func("fn", {}, ty.void_(),
+         {
+             Decl(Var("lhs", ty.mat4x2<f32>())),
+             Decl(Var("rhs", ty.vec2<f32>())),
+             Decl(Var("index", ty.u32())),
+             Assign(IndexAccessor("lhs", "index"), "rhs"),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate());
-  EXPECT_EQ(
-      gen.result(),
-      R"(void set_vector_float4x2(inout float4x2 mat, int col, float2 val) {
+    ASSERT_TRUE(gen.Generate());
+    EXPECT_EQ(gen.result(),
+              R"(void set_vector_float4x2(inout float4x2 mat, int col, float2 val) {
   switch (col) {
     case 0: mat[0] = val; break;
     case 1: mat[1] = val; break;
@@ -142,19 +143,19 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Assign, Emit_Matrix_Assign_Scalar_ConstantIndex) {
-  Func("fn", {}, ty.void_(),
-       {
-           Decl(Var("lhs", ty.mat4x2<f32>())),
-           Decl(Var("rhs", ty.f32())),
-           Decl(Const("index", ty.u32(), Expr(0u))),
-           Assign(IndexAccessor(IndexAccessor("lhs", "index"), "index"), "rhs"),
-       });
+    Func("fn", {}, ty.void_(),
+         {
+             Decl(Var("lhs", ty.mat4x2<f32>())),
+             Decl(Var("rhs", ty.f32())),
+             Decl(Let("index", ty.u32(), Expr(0_u))),
+             Assign(IndexAccessor(IndexAccessor("lhs", "index"), "index"), "rhs"),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate());
-  EXPECT_EQ(gen.result(),
-            R"(void fn() {
+    ASSERT_TRUE(gen.Generate());
+    EXPECT_EQ(gen.result(),
+              R"(void fn() {
   float4x2 lhs = float4x2(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
   float rhs = 0.0f;
   const uint index = 0u;
@@ -164,20 +165,19 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Assign, Emit_Matrix_Assign_Scalar_DynamicIndex) {
-  Func("fn", {}, ty.void_(),
-       {
-           Decl(Var("lhs", ty.mat4x2<f32>())),
-           Decl(Var("rhs", ty.f32())),
-           Decl(Var("index", ty.u32())),
-           Assign(IndexAccessor(IndexAccessor("lhs", "index"), "index"), "rhs"),
-       });
+    Func("fn", {}, ty.void_(),
+         {
+             Decl(Var("lhs", ty.mat4x2<f32>())),
+             Decl(Var("rhs", ty.f32())),
+             Decl(Var("index", ty.u32())),
+             Assign(IndexAccessor(IndexAccessor("lhs", "index"), "index"), "rhs"),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate());
-  EXPECT_EQ(
-      gen.result(),
-      R"(void set_scalar_float4x2(inout float4x2 mat, int col, int row, float val) {
+    ASSERT_TRUE(gen.Generate());
+    EXPECT_EQ(gen.result(),
+              R"(void set_scalar_float4x2(inout float4x2 mat, int col, int row, float val) {
   switch (col) {
     case 0:
       mat[0] = (row.xx == int2(0, 1)) ? val.xx : mat[0];
diff --git a/src/tint/writer/hlsl/generator_impl_binary_test.cc b/src/tint/writer/hlsl/generator_impl_binary_test.cc
index f720db7..4d62885 100644
--- a/src/tint/writer/hlsl/generator_impl_binary_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_binary_test.cc
@@ -16,261 +16,251 @@
 #include "src/tint/ast/variable_decl_statement.h"
 #include "src/tint/writer/hlsl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::hlsl {
 namespace {
 
 using HlslGeneratorImplTest_Binary = TestHelper;
 
 struct BinaryData {
-  const char* result;
-  ast::BinaryOp op;
+    const char* result;
+    ast::BinaryOp op;
 
-  enum Types { All = 0b11, Integer = 0b10, Float = 0b01 };
-  Types valid_for = Types::All;
+    enum Types { All = 0b11, Integer = 0b10, Float = 0b01 };
+    Types valid_for = Types::All;
 };
 inline std::ostream& operator<<(std::ostream& out, BinaryData data) {
-  out << data.op;
-  return out;
+    out << data.op;
+    return out;
 }
 
 using HlslBinaryTest = TestParamHelper<BinaryData>;
 TEST_P(HlslBinaryTest, Emit_f32) {
-  auto params = GetParam();
+    auto params = GetParam();
 
-  if ((params.valid_for & BinaryData::Types::Float) == 0) {
-    return;
-  }
+    if ((params.valid_for & BinaryData::Types::Float) == 0) {
+        return;
+    }
 
-  // Skip ops that are illegal for this type
-  if (params.op == ast::BinaryOp::kAnd || params.op == ast::BinaryOp::kOr ||
-      params.op == ast::BinaryOp::kXor ||
-      params.op == ast::BinaryOp::kShiftLeft ||
-      params.op == ast::BinaryOp::kShiftRight) {
-    return;
-  }
+    // Skip ops that are illegal for this type
+    if (params.op == ast::BinaryOp::kAnd || params.op == ast::BinaryOp::kOr ||
+        params.op == ast::BinaryOp::kXor || params.op == ast::BinaryOp::kShiftLeft ||
+        params.op == ast::BinaryOp::kShiftRight) {
+        return;
+    }
 
-  Global("left", ty.f32(), ast::StorageClass::kPrivate);
-  Global("right", ty.f32(), ast::StorageClass::kPrivate);
+    Global("left", ty.f32(), ast::StorageClass::kPrivate);
+    Global("right", ty.f32(), ast::StorageClass::kPrivate);
 
-  auto* left = Expr("left");
-  auto* right = Expr("right");
+    auto* left = Expr("left");
+    auto* right = Expr("right");
 
-  auto* expr = create<ast::BinaryExpression>(params.op, left, right);
+    auto* expr = create<ast::BinaryExpression>(params.op, left, right);
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), params.result);
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), params.result);
 }
 TEST_P(HlslBinaryTest, Emit_u32) {
-  auto params = GetParam();
+    auto params = GetParam();
 
-  if ((params.valid_for & BinaryData::Types::Integer) == 0) {
-    return;
-  }
+    if ((params.valid_for & BinaryData::Types::Integer) == 0) {
+        return;
+    }
 
-  Global("left", ty.u32(), ast::StorageClass::kPrivate);
-  Global("right", ty.u32(), ast::StorageClass::kPrivate);
+    Global("left", ty.u32(), ast::StorageClass::kPrivate);
+    Global("right", ty.u32(), ast::StorageClass::kPrivate);
 
-  auto* left = Expr("left");
-  auto* right = Expr("right");
+    auto* left = Expr("left");
+    auto* right = Expr("right");
 
-  auto* expr = create<ast::BinaryExpression>(params.op, left, right);
+    auto* expr = create<ast::BinaryExpression>(params.op, left, right);
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), params.result);
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), params.result);
 }
 TEST_P(HlslBinaryTest, Emit_i32) {
-  auto params = GetParam();
+    auto params = GetParam();
 
-  if ((params.valid_for & BinaryData::Types::Integer) == 0) {
-    return;
-  }
+    if ((params.valid_for & BinaryData::Types::Integer) == 0) {
+        return;
+    }
 
-  // Skip ops that are illegal for this type
-  if (params.op == ast::BinaryOp::kShiftLeft ||
-      params.op == ast::BinaryOp::kShiftRight) {
-    return;
-  }
+    // Skip ops that are illegal for this type
+    if (params.op == ast::BinaryOp::kShiftLeft || params.op == ast::BinaryOp::kShiftRight) {
+        return;
+    }
 
-  Global("left", ty.i32(), ast::StorageClass::kPrivate);
-  Global("right", ty.i32(), ast::StorageClass::kPrivate);
+    Global("left", ty.i32(), ast::StorageClass::kPrivate);
+    Global("right", ty.i32(), ast::StorageClass::kPrivate);
 
-  auto* left = Expr("left");
-  auto* right = Expr("right");
+    auto* left = Expr("left");
+    auto* right = Expr("right");
 
-  auto* expr = create<ast::BinaryExpression>(params.op, left, right);
+    auto* expr = create<ast::BinaryExpression>(params.op, left, right);
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), params.result);
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), params.result);
 }
 INSTANTIATE_TEST_SUITE_P(
     HlslGeneratorImplTest,
     HlslBinaryTest,
-    testing::Values(
-        BinaryData{"(left & right)", ast::BinaryOp::kAnd},
-        BinaryData{"(left | right)", ast::BinaryOp::kOr},
-        BinaryData{"(left ^ right)", ast::BinaryOp::kXor},
-        BinaryData{"(left == right)", ast::BinaryOp::kEqual},
-        BinaryData{"(left != right)", ast::BinaryOp::kNotEqual},
-        BinaryData{"(left < right)", ast::BinaryOp::kLessThan},
-        BinaryData{"(left > right)", ast::BinaryOp::kGreaterThan},
-        BinaryData{"(left <= right)", ast::BinaryOp::kLessThanEqual},
-        BinaryData{"(left >= right)", ast::BinaryOp::kGreaterThanEqual},
-        BinaryData{"(left << right)", ast::BinaryOp::kShiftLeft},
-        BinaryData{"(left >> right)", ast::BinaryOp::kShiftRight},
-        BinaryData{"(left + right)", ast::BinaryOp::kAdd},
-        BinaryData{"(left - right)", ast::BinaryOp::kSubtract},
-        BinaryData{"(left * right)", ast::BinaryOp::kMultiply},
-        // NOTE: Integer divide covered by DivOrModBy* tests below
-        BinaryData{"(left / right)", ast::BinaryOp::kDivide,
-                   BinaryData::Types::Float},
-        // NOTE: Integer modulo covered by DivOrModBy* tests below
-        BinaryData{"(left % right)", ast::BinaryOp::kModulo,
-                   BinaryData::Types::Float}));
+    testing::Values(BinaryData{"(left & right)", ast::BinaryOp::kAnd},
+                    BinaryData{"(left | right)", ast::BinaryOp::kOr},
+                    BinaryData{"(left ^ right)", ast::BinaryOp::kXor},
+                    BinaryData{"(left == right)", ast::BinaryOp::kEqual},
+                    BinaryData{"(left != right)", ast::BinaryOp::kNotEqual},
+                    BinaryData{"(left < right)", ast::BinaryOp::kLessThan},
+                    BinaryData{"(left > right)", ast::BinaryOp::kGreaterThan},
+                    BinaryData{"(left <= right)", ast::BinaryOp::kLessThanEqual},
+                    BinaryData{"(left >= right)", ast::BinaryOp::kGreaterThanEqual},
+                    BinaryData{"(left << right)", ast::BinaryOp::kShiftLeft},
+                    BinaryData{"(left >> right)", ast::BinaryOp::kShiftRight},
+                    BinaryData{"(left + right)", ast::BinaryOp::kAdd},
+                    BinaryData{"(left - right)", ast::BinaryOp::kSubtract},
+                    BinaryData{"(left * right)", ast::BinaryOp::kMultiply},
+                    // NOTE: Integer divide covered by DivOrModBy* tests below
+                    BinaryData{"(left / right)", ast::BinaryOp::kDivide, BinaryData::Types::Float},
+                    // NOTE: Integer modulo covered by DivOrModBy* tests below
+                    BinaryData{"(left % right)", ast::BinaryOp::kModulo,
+                               BinaryData::Types::Float}));
 
 TEST_F(HlslGeneratorImplTest_Binary, Multiply_VectorScalar) {
-  auto* lhs = vec3<f32>(1.f, 1.f, 1.f);
-  auto* rhs = Expr(1.f);
+    auto* lhs = vec3<f32>(1.f, 1.f, 1.f);
+    auto* rhs = Expr(1.f);
 
-  auto* expr =
-      create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
+    auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(),
-            "(float3(1.0f, 1.0f, 1.0f) * "
-            "1.0f)");
+    std::stringstream out;
+    EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(),
+              "(float3(1.0f, 1.0f, 1.0f) * "
+              "1.0f)");
 }
 
 TEST_F(HlslGeneratorImplTest_Binary, Multiply_ScalarVector) {
-  auto* lhs = Expr(1.f);
-  auto* rhs = vec3<f32>(1.f, 1.f, 1.f);
+    auto* lhs = Expr(1.f);
+    auto* rhs = vec3<f32>(1.f, 1.f, 1.f);
 
-  auto* expr =
-      create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
+    auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(),
-            "(1.0f * float3(1.0f, 1.0f, "
-            "1.0f))");
+    std::stringstream out;
+    EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(),
+              "(1.0f * float3(1.0f, 1.0f, "
+              "1.0f))");
 }
 
 TEST_F(HlslGeneratorImplTest_Binary, Multiply_MatrixScalar) {
-  Global("mat", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
-  auto* lhs = Expr("mat");
-  auto* rhs = Expr(1.f);
+    Global("mat", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
+    auto* lhs = Expr("mat");
+    auto* rhs = Expr(1.f);
 
-  auto* expr =
-      create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
-  WrapInFunction(expr);
+    auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), "(mat * 1.0f)");
+    std::stringstream out;
+    EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), "(mat * 1.0f)");
 }
 
 TEST_F(HlslGeneratorImplTest_Binary, Multiply_ScalarMatrix) {
-  Global("mat", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
-  auto* lhs = Expr(1.f);
-  auto* rhs = Expr("mat");
+    Global("mat", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
+    auto* lhs = Expr(1.f);
+    auto* rhs = Expr("mat");
 
-  auto* expr =
-      create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
-  WrapInFunction(expr);
+    auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), "(1.0f * mat)");
+    std::stringstream out;
+    EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), "(1.0f * mat)");
 }
 
 TEST_F(HlslGeneratorImplTest_Binary, Multiply_MatrixVector) {
-  Global("mat", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
-  auto* lhs = Expr("mat");
-  auto* rhs = vec3<f32>(1.f, 1.f, 1.f);
+    Global("mat", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
+    auto* lhs = Expr("mat");
+    auto* rhs = vec3<f32>(1.f, 1.f, 1.f);
 
-  auto* expr =
-      create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
-  WrapInFunction(expr);
+    auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), "mul(float3(1.0f, 1.0f, 1.0f), mat)");
+    std::stringstream out;
+    EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), "mul(float3(1.0f, 1.0f, 1.0f), mat)");
 }
 
 TEST_F(HlslGeneratorImplTest_Binary, Multiply_VectorMatrix) {
-  Global("mat", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
-  auto* lhs = vec3<f32>(1.f, 1.f, 1.f);
-  auto* rhs = Expr("mat");
+    Global("mat", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
+    auto* lhs = vec3<f32>(1.f, 1.f, 1.f);
+    auto* rhs = Expr("mat");
 
-  auto* expr =
-      create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
-  WrapInFunction(expr);
+    auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), "mul(mat, float3(1.0f, 1.0f, 1.0f))");
+    std::stringstream out;
+    EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), "mul(mat, float3(1.0f, 1.0f, 1.0f))");
 }
 
 TEST_F(HlslGeneratorImplTest_Binary, Multiply_MatrixMatrix) {
-  Global("lhs", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
-  Global("rhs", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
+    Global("lhs", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
+    Global("rhs", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
 
-  auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply,
-                                             Expr("lhs"), Expr("rhs"));
-  WrapInFunction(expr);
+    auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, Expr("lhs"), Expr("rhs"));
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), "mul(rhs, lhs)");
+    std::stringstream out;
+    EXPECT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), "mul(rhs, lhs)");
 }
 
 TEST_F(HlslGeneratorImplTest_Binary, Logical_And) {
-  Global("a", ty.bool_(), ast::StorageClass::kPrivate);
-  Global("b", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("a", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("b", ty.bool_(), ast::StorageClass::kPrivate);
 
-  auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd,
-                                             Expr("a"), Expr("b"));
-  WrapInFunction(expr);
+    auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr("a"), Expr("b"));
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), "(tint_tmp)");
-  EXPECT_EQ(gen.result(), R"(bool tint_tmp = a;
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), "(tint_tmp)");
+    EXPECT_EQ(gen.result(), R"(bool tint_tmp = a;
 if (tint_tmp) {
   tint_tmp = b;
 }
@@ -278,26 +268,24 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Binary, Logical_Multi) {
-  // (a && b) || (c || d)
-  Global("a", ty.bool_(), ast::StorageClass::kPrivate);
-  Global("b", ty.bool_(), ast::StorageClass::kPrivate);
-  Global("c", ty.bool_(), ast::StorageClass::kPrivate);
-  Global("d", ty.bool_(), ast::StorageClass::kPrivate);
+    // (a && b) || (c || d)
+    Global("a", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("b", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("c", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("d", ty.bool_(), ast::StorageClass::kPrivate);
 
-  auto* expr = create<ast::BinaryExpression>(
-      ast::BinaryOp::kLogicalOr,
-      create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr("a"),
-                                    Expr("b")),
-      create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("c"),
-                                    Expr("d")));
-  WrapInFunction(expr);
+    auto* expr = create<ast::BinaryExpression>(
+        ast::BinaryOp::kLogicalOr,
+        create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr("a"), Expr("b")),
+        create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("c"), Expr("d")));
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), "(tint_tmp)");
-  EXPECT_EQ(gen.result(), R"(bool tint_tmp_1 = a;
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), "(tint_tmp)");
+    EXPECT_EQ(gen.result(), R"(bool tint_tmp_1 = a;
 if (tint_tmp_1) {
   tint_tmp_1 = b;
 }
@@ -313,19 +301,18 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Binary, Logical_Or) {
-  Global("a", ty.bool_(), ast::StorageClass::kPrivate);
-  Global("b", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("a", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("b", ty.bool_(), ast::StorageClass::kPrivate);
 
-  auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr,
-                                             Expr("a"), Expr("b"));
-  WrapInFunction(expr);
+    auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("a"), Expr("b"));
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), "(tint_tmp)");
-  EXPECT_EQ(gen.result(), R"(bool tint_tmp = a;
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), "(tint_tmp)");
+    EXPECT_EQ(gen.result(), R"(bool tint_tmp = a;
 if (!tint_tmp) {
   tint_tmp = b;
 }
@@ -333,31 +320,29 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Binary, If_WithLogical) {
-  // if (a && b) {
-  //   return 1;
-  // } else if (b || c) {
-  //   return 2;
-  // } else {
-  //   return 3;
-  // }
+    // if (a && b) {
+    //   return 1i;
+    // } else if (b || c) {
+    //   return 2i;
+    // } else {
+    //   return 3i;
+    // }
 
-  Global("a", ty.bool_(), ast::StorageClass::kPrivate);
-  Global("b", ty.bool_(), ast::StorageClass::kPrivate);
-  Global("c", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("a", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("b", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("c", ty.bool_(), ast::StorageClass::kPrivate);
 
-  auto* expr = If(create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd,
-                                                Expr("a"), Expr("b")),
-                  Block(Return(1)),
-                  Else(create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr,
-                                                     Expr("b"), Expr("c")),
-                       Block(Return(2))),
-                  Else(Block(Return(3))));
-  Func("func", {}, ty.i32(), {WrapInStatement(expr)});
+    auto* expr =
+        If(create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr("a"), Expr("b")),
+           Block(Return(1_i)),
+           Else(If(create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("b"), Expr("c")),
+                   Block(Return(2_i)), Else(Block(Return(3_i))))));
+    Func("func", {}, ty.i32(), {WrapInStatement(expr)});
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitStatement(expr)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(bool tint_tmp = a;
+    ASSERT_TRUE(gen.EmitStatement(expr)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(bool tint_tmp = a;
 if (tint_tmp) {
   tint_tmp = b;
 }
@@ -378,23 +363,22 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Binary, Return_WithLogical) {
-  // return (a && b) || c;
+    // return (a && b) || c;
 
-  Global("a", ty.bool_(), ast::StorageClass::kPrivate);
-  Global("b", ty.bool_(), ast::StorageClass::kPrivate);
-  Global("c", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("a", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("b", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("c", ty.bool_(), ast::StorageClass::kPrivate);
 
-  auto* expr = Return(create<ast::BinaryExpression>(
-      ast::BinaryOp::kLogicalOr,
-      create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr("a"),
-                                    Expr("b")),
-      Expr("c")));
-  Func("func", {}, ty.bool_(), {WrapInStatement(expr)});
+    auto* expr = Return(create<ast::BinaryExpression>(
+        ast::BinaryOp::kLogicalOr,
+        create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr("a"), Expr("b")),
+        Expr("c")));
+    Func("func", {}, ty.bool_(), {WrapInStatement(expr)});
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitStatement(expr)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(bool tint_tmp_1 = a;
+    ASSERT_TRUE(gen.EmitStatement(expr)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(bool tint_tmp_1 = a;
 if (tint_tmp_1) {
   tint_tmp_1 = b;
 }
@@ -407,25 +391,25 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Binary, Assign_WithLogical) {
-  // a = (b || c) && d;
+    // a = (b || c) && d;
 
-  Global("a", ty.bool_(), ast::StorageClass::kPrivate);
-  Global("b", ty.bool_(), ast::StorageClass::kPrivate);
-  Global("c", ty.bool_(), ast::StorageClass::kPrivate);
-  Global("d", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("a", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("b", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("c", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("d", ty.bool_(), ast::StorageClass::kPrivate);
 
-  auto* expr = Assign(
-      Expr("a"), create<ast::BinaryExpression>(
-                     ast::BinaryOp::kLogicalAnd,
-                     create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr,
-                                                   Expr("b"), Expr("c")),
-                     Expr("d")));
-  WrapInFunction(expr);
+    auto* expr =
+        Assign(Expr("a"),
+               create<ast::BinaryExpression>(
+                   ast::BinaryOp::kLogicalAnd,
+                   create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("b"), Expr("c")),
+                   Expr("d")));
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitStatement(expr)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(bool tint_tmp_1 = b;
+    ASSERT_TRUE(gen.EmitStatement(expr)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(bool tint_tmp_1 = b;
 if (!tint_tmp_1) {
   tint_tmp_1 = c;
 }
@@ -438,26 +422,26 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Binary, Decl_WithLogical) {
-  // var a : bool = (b && c) || d;
+    // var a : bool = (b && c) || d;
 
-  Global("b", ty.bool_(), ast::StorageClass::kPrivate);
-  Global("c", ty.bool_(), ast::StorageClass::kPrivate);
-  Global("d", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("b", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("c", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("d", ty.bool_(), ast::StorageClass::kPrivate);
 
-  auto* var = Var("a", ty.bool_(), ast::StorageClass::kNone,
-                  create<ast::BinaryExpression>(
-                      ast::BinaryOp::kLogicalOr,
-                      create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd,
-                                                    Expr("b"), Expr("c")),
-                      Expr("d")));
+    auto* var =
+        Var("a", ty.bool_(), ast::StorageClass::kNone,
+            create<ast::BinaryExpression>(
+                ast::BinaryOp::kLogicalOr,
+                create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr("b"), Expr("c")),
+                Expr("d")));
 
-  auto* decl = Decl(var);
-  WrapInFunction(decl);
+    auto* decl = Decl(var);
+    WrapInFunction(decl);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitStatement(decl)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(bool tint_tmp_1 = b;
+    ASSERT_TRUE(gen.EmitStatement(decl)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(bool tint_tmp_1 = b;
 if (tint_tmp_1) {
   tint_tmp_1 = c;
 }
@@ -470,39 +454,37 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Binary, Call_WithLogical) {
-  // foo(a && b, c || d, (a || c) && (b || d))
+    // foo(a && b, c || d, (a || c) && (b || d))
 
-  Func("foo",
-       {
-           Param(Sym(), ty.bool_()),
-           Param(Sym(), ty.bool_()),
-           Param(Sym(), ty.bool_()),
-       },
-       ty.void_(), ast::StatementList{}, ast::AttributeList{});
-  Global("a", ty.bool_(), ast::StorageClass::kPrivate);
-  Global("b", ty.bool_(), ast::StorageClass::kPrivate);
-  Global("c", ty.bool_(), ast::StorageClass::kPrivate);
-  Global("d", ty.bool_(), ast::StorageClass::kPrivate);
+    Func("foo",
+         {
+             Param(Sym(), ty.bool_()),
+             Param(Sym(), ty.bool_()),
+             Param(Sym(), ty.bool_()),
+         },
+         ty.void_(), ast::StatementList{}, ast::AttributeList{});
+    Global("a", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("b", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("c", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("d", ty.bool_(), ast::StorageClass::kPrivate);
 
-  ast::ExpressionList params;
-  params.push_back(create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd,
-                                                 Expr("a"), Expr("b")));
-  params.push_back(create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr,
-                                                 Expr("c"), Expr("d")));
-  params.push_back(create<ast::BinaryExpression>(
-      ast::BinaryOp::kLogicalAnd,
-      create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("a"),
-                                    Expr("c")),
-      create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("b"),
-                                    Expr("d"))));
+    ast::ExpressionList params;
+    params.push_back(
+        create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr("a"), Expr("b")));
+    params.push_back(
+        create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("c"), Expr("d")));
+    params.push_back(create<ast::BinaryExpression>(
+        ast::BinaryOp::kLogicalAnd,
+        create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("a"), Expr("c")),
+        create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("b"), Expr("d"))));
 
-  auto* expr = CallStmt(Call("foo", params));
-  WrapInFunction(expr);
+    auto* expr = CallStmt(Call("foo", params));
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitStatement(expr)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(bool tint_tmp = a;
+    ASSERT_TRUE(gen.EmitStatement(expr)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(bool tint_tmp = a;
 if (tint_tmp) {
   tint_tmp = b;
 }
@@ -529,188 +511,184 @@
 namespace HlslGeneratorDivMod {
 
 struct Params {
-  enum class Type { Div, Mod };
-  Type type;
+    enum class Type { Div, Mod };
+    Type type;
 };
 
 struct HlslGeneratorDivModTest : TestParamHelper<Params> {
-  std::string Token() {
-    return GetParam().type == Params::Type::Div ? "/" : "%";
-  }
+    std::string Token() { return GetParam().type == Params::Type::Div ? "/" : "%"; }
 
-  template <typename... Args>
-  auto Op(Args... args) {
-    return GetParam().type == Params::Type::Div
-               ? Div(std::forward<Args>(args)...)
-               : Mod(std::forward<Args>(args)...);
-  }
+    template <typename... Args>
+    auto Op(Args... args) {
+        return GetParam().type == Params::Type::Div ? Div(std::forward<Args>(args)...)
+                                                    : Mod(std::forward<Args>(args)...);
+    }
 };
 
 INSTANTIATE_TEST_SUITE_P(HlslGeneratorImplTest,
                          HlslGeneratorDivModTest,
-                         testing::Values(Params{Params::Type::Div},
-                                         Params{Params::Type::Mod}));
+                         testing::Values(Params{Params::Type::Div}, Params{Params::Type::Mod}));
 
 TEST_P(HlslGeneratorDivModTest, DivOrModByLiteralZero_i32) {
-  Func("fn", {}, ty.void_(),
-       {
-           Decl(Var("a", ty.i32())),
-           Decl(Const("r", nullptr, Op("a", 0))),
-       });
+    Func("fn", {}, ty.void_(),
+         {
+             Decl(Var("a", ty.i32())),
+             Decl(Let("r", nullptr, Op("a", 0_i))),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate());
-  EXPECT_EQ(gen.result(), R"(void fn() {
+    ASSERT_TRUE(gen.Generate());
+    EXPECT_EQ(gen.result(), R"(void fn() {
   int a = 0;
   const int r = (a )" + Token() +
-                              R"( 1);
+                                R"( 1);
 }
 )");
 }
 
 TEST_P(HlslGeneratorDivModTest, DivOrModByLiteralZero_u32) {
-  Func("fn", {}, ty.void_(),
-       {
-           Decl(Var("a", ty.u32())),
-           Decl(Const("r", nullptr, Op("a", 0u))),
-       });
+    Func("fn", {}, ty.void_(),
+         {
+             Decl(Var("a", ty.u32())),
+             Decl(Let("r", nullptr, Op("a", 0_u))),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate());
-  EXPECT_EQ(gen.result(), R"(void fn() {
+    ASSERT_TRUE(gen.Generate());
+    EXPECT_EQ(gen.result(), R"(void fn() {
   uint a = 0u;
   const uint r = (a )" + Token() +
-                              R"( 1u);
+                                R"( 1u);
 }
 )");
 }  // namespace HlslGeneratorDivMod
 
 TEST_P(HlslGeneratorDivModTest, DivOrModByLiteralZero_vec_by_vec_i32) {
-  Func("fn", {}, ty.void_(),
-       {
-           Decl(Var("a", nullptr, vec4<i32>(100, 100, 100, 100))),
-           Decl(Const("r", nullptr, Op("a", vec4<i32>(50, 0, 25, 0)))),
-       });
+    Func("fn", {}, ty.void_(),
+         {
+             Decl(Var("a", nullptr, vec4<i32>(100_i, 100_i, 100_i, 100_i))),
+             Decl(Let("r", nullptr, Op("a", vec4<i32>(50_i, 0_i, 25_i, 0_i)))),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate());
-  EXPECT_EQ(gen.result(), R"(void fn() {
+    ASSERT_TRUE(gen.Generate());
+    EXPECT_EQ(gen.result(), R"(void fn() {
   int4 a = int4(100, 100, 100, 100);
   const int4 r = (a )" + Token() +
-                              R"( int4(50, 1, 25, 1));
+                                R"( int4(50, 1, 25, 1));
 }
 )");
 }  // namespace
 
 TEST_P(HlslGeneratorDivModTest, DivOrModByLiteralZero_vec_by_scalar_i32) {
-  Func("fn", {}, ty.void_(),
-       {
-           Decl(Var("a", nullptr, vec4<i32>(100, 100, 100, 100))),
-           Decl(Const("r", nullptr, Op("a", 0))),
-       });
+    Func("fn", {}, ty.void_(),
+         {
+             Decl(Var("a", nullptr, vec4<i32>(100_i, 100_i, 100_i, 100_i))),
+             Decl(Let("r", nullptr, Op("a", 0_i))),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate());
-  EXPECT_EQ(gen.result(), R"(void fn() {
+    ASSERT_TRUE(gen.Generate());
+    EXPECT_EQ(gen.result(), R"(void fn() {
   int4 a = int4(100, 100, 100, 100);
   const int4 r = (a )" + Token() +
-                              R"( 1);
+                                R"( 1);
 }
 )");
 }  // namespace hlsl
 
 TEST_P(HlslGeneratorDivModTest, DivOrModByIdentifier_i32) {
-  Func("fn", {Param("b", ty.i32())}, ty.void_(),
-       {
-           Decl(Var("a", ty.i32())),
-           Decl(Const("r", nullptr, Op("a", "b"))),
-       });
+    Func("fn", {Param("b", ty.i32())}, ty.void_(),
+         {
+             Decl(Var("a", ty.i32())),
+             Decl(Let("r", nullptr, Op("a", "b"))),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate());
-  EXPECT_EQ(gen.result(), R"(void fn(int b) {
+    ASSERT_TRUE(gen.Generate());
+    EXPECT_EQ(gen.result(), R"(void fn(int b) {
   int a = 0;
   const int r = (a )" + Token() +
-                              R"( (b == 0 ? 1 : b));
+                                R"( (b == 0 ? 1 : b));
 }
 )");
 }  // namespace writer
 
 TEST_P(HlslGeneratorDivModTest, DivOrModByIdentifier_u32) {
-  Func("fn", {Param("b", ty.u32())}, ty.void_(),
-       {
-           Decl(Var("a", ty.u32())),
-           Decl(Const("r", nullptr, Op("a", "b"))),
-       });
+    Func("fn", {Param("b", ty.u32())}, ty.void_(),
+         {
+             Decl(Var("a", ty.u32())),
+             Decl(Let("r", nullptr, Op("a", "b"))),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate());
-  EXPECT_EQ(gen.result(), R"(void fn(uint b) {
+    ASSERT_TRUE(gen.Generate());
+    EXPECT_EQ(gen.result(), R"(void fn(uint b) {
   uint a = 0u;
   const uint r = (a )" + Token() +
-                              R"( (b == 0u ? 1u : b));
+                                R"( (b == 0u ? 1u : b));
 }
 )");
 }  // namespace tint
 
 TEST_P(HlslGeneratorDivModTest, DivOrModByIdentifier_vec_by_vec_i32) {
-  Func("fn", {Param("b", ty.vec3<i32>())}, ty.void_(),
-       {
-           Decl(Var("a", ty.vec3<i32>())),
-           Decl(Const("r", nullptr, Op("a", "b"))),
-       });
+    Func("fn", {Param("b", ty.vec3<i32>())}, ty.void_(),
+         {
+             Decl(Var("a", ty.vec3<i32>())),
+             Decl(Let("r", nullptr, Op("a", "b"))),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate());
-  EXPECT_EQ(gen.result(), R"(void fn(int3 b) {
+    ASSERT_TRUE(gen.Generate());
+    EXPECT_EQ(gen.result(), R"(void fn(int3 b) {
   int3 a = int3(0, 0, 0);
   const int3 r = (a )" + Token() +
-                              R"( (b == int3(0, 0, 0) ? int3(1, 1, 1) : b));
+                                R"( (b == int3(0, 0, 0) ? int3(1, 1, 1) : b));
 }
 )");
 }
 
 TEST_P(HlslGeneratorDivModTest, DivOrModByIdentifier_vec_by_scalar_i32) {
-  Func("fn", {Param("b", ty.i32())}, ty.void_(),
-       {
-           Decl(Var("a", ty.vec3<i32>())),
-           Decl(Const("r", nullptr, Op("a", "b"))),
-       });
+    Func("fn", {Param("b", ty.i32())}, ty.void_(),
+         {
+             Decl(Var("a", ty.vec3<i32>())),
+             Decl(Let("r", nullptr, Op("a", "b"))),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate());
-  EXPECT_EQ(gen.result(), R"(void fn(int b) {
+    ASSERT_TRUE(gen.Generate());
+    EXPECT_EQ(gen.result(), R"(void fn(int b) {
   int3 a = int3(0, 0, 0);
   const int3 r = (a )" + Token() +
-                              R"( (b == 0 ? 1 : b));
+                                R"( (b == 0 ? 1 : b));
 }
 )");
 }
 
 TEST_P(HlslGeneratorDivModTest, DivOrModByExpression_i32) {
-  Func("zero", {}, ty.i32(),
-       {
-           Return(Expr(0)),
-       });
+    Func("zero", {}, ty.i32(),
+         {
+             Return(Expr(0_i)),
+         });
 
-  Func("fn", {}, ty.void_(),
-       {
-           Decl(Var("a", ty.i32())),
-           Decl(Const("r", nullptr, Op("a", Call("zero")))),
-       });
+    Func("fn", {}, ty.void_(),
+         {
+             Decl(Var("a", ty.i32())),
+             Decl(Let("r", nullptr, Op("a", Call("zero")))),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate());
-  EXPECT_EQ(gen.result(), R"(int value_or_one_if_zero_int(int value) {
+    ASSERT_TRUE(gen.Generate());
+    EXPECT_EQ(gen.result(), R"(int value_or_one_if_zero_int(int value) {
   return value == 0 ? 1 : value;
 }
 
@@ -721,27 +699,27 @@
 void fn() {
   int a = 0;
   const int r = (a )" + Token() +
-                              R"( value_or_one_if_zero_int(zero()));
+                                R"( value_or_one_if_zero_int(zero()));
 }
 )");
 }
 
 TEST_P(HlslGeneratorDivModTest, DivOrModByExpression_u32) {
-  Func("zero", {}, ty.u32(),
-       {
-           Return(Expr(0u)),
-       });
+    Func("zero", {}, ty.u32(),
+         {
+             Return(Expr(0_u)),
+         });
 
-  Func("fn", {}, ty.void_(),
-       {
-           Decl(Var("a", ty.u32())),
-           Decl(Const("r", nullptr, Op("a", Call("zero")))),
-       });
+    Func("fn", {}, ty.void_(),
+         {
+             Decl(Var("a", ty.u32())),
+             Decl(Let("r", nullptr, Op("a", Call("zero")))),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate());
-  EXPECT_EQ(gen.result(), R"(uint value_or_one_if_zero_uint(uint value) {
+    ASSERT_TRUE(gen.Generate());
+    EXPECT_EQ(gen.result(), R"(uint value_or_one_if_zero_uint(uint value) {
   return value == 0u ? 1u : value;
 }
 
@@ -752,27 +730,27 @@
 void fn() {
   uint a = 0u;
   const uint r = (a )" + Token() +
-                              R"( value_or_one_if_zero_uint(zero()));
+                                R"( value_or_one_if_zero_uint(zero()));
 }
 )");
 }
 
 TEST_P(HlslGeneratorDivModTest, DivOrModByExpression_vec_by_vec_i32) {
-  Func("zero", {}, ty.vec3<i32>(),
-       {
-           Return(vec3<i32>(0, 0, 0)),
-       });
+    Func("zero", {}, ty.vec3<i32>(),
+         {
+             Return(vec3<i32>(0_i, 0_i, 0_i)),
+         });
 
-  Func("fn", {}, ty.void_(),
-       {
-           Decl(Var("a", ty.vec3<i32>())),
-           Decl(Const("r", nullptr, Op("a", Call("zero")))),
-       });
+    Func("fn", {}, ty.void_(),
+         {
+             Decl(Var("a", ty.vec3<i32>())),
+             Decl(Let("r", nullptr, Op("a", Call("zero")))),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate());
-  EXPECT_EQ(gen.result(), R"(int3 value_or_one_if_zero_int3(int3 value) {
+    ASSERT_TRUE(gen.Generate());
+    EXPECT_EQ(gen.result(), R"(int3 value_or_one_if_zero_int3(int3 value) {
   return value == int3(0, 0, 0) ? int3(1, 1, 1) : value;
 }
 
@@ -783,27 +761,27 @@
 void fn() {
   int3 a = int3(0, 0, 0);
   const int3 r = (a )" + Token() +
-                              R"( value_or_one_if_zero_int3(zero()));
+                                R"( value_or_one_if_zero_int3(zero()));
 }
 )");
 }
 
 TEST_P(HlslGeneratorDivModTest, DivOrModByExpression_vec_by_scalar_i32) {
-  Func("zero", {}, ty.i32(),
-       {
-           Return(0),
-       });
+    Func("zero", {}, ty.i32(),
+         {
+             Return(0_i),
+         });
 
-  Func("fn", {}, ty.void_(),
-       {
-           Decl(Var("a", ty.vec3<i32>())),
-           Decl(Const("r", nullptr, Op("a", Call("zero")))),
-       });
+    Func("fn", {}, ty.void_(),
+         {
+             Decl(Var("a", ty.vec3<i32>())),
+             Decl(Let("r", nullptr, Op("a", Call("zero")))),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate());
-  EXPECT_EQ(gen.result(), R"(int value_or_one_if_zero_int(int value) {
+    ASSERT_TRUE(gen.Generate());
+    EXPECT_EQ(gen.result(), R"(int value_or_one_if_zero_int(int value) {
   return value == 0 ? 1 : value;
 }
 
@@ -814,7 +792,7 @@
 void fn() {
   int3 a = int3(0, 0, 0);
   const int3 r = (a )" + Token() +
-                              R"( value_or_one_if_zero_int(zero()));
+                                R"( value_or_one_if_zero_int(zero()));
 }
 )");
 }
diff --git a/src/tint/writer/hlsl/generator_impl_bitcast_test.cc b/src/tint/writer/hlsl/generator_impl_bitcast_test.cc
index 19c7ed7..8305d64 100644
--- a/src/tint/writer/hlsl/generator_impl_bitcast_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_bitcast_test.cc
@@ -14,42 +14,44 @@
 
 #include "src/tint/writer/hlsl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::hlsl {
 namespace {
 
 using HlslGeneratorImplTest_Bitcast = TestHelper;
 
 TEST_F(HlslGeneratorImplTest_Bitcast, EmitExpression_Bitcast_Float) {
-  auto* bitcast = create<ast::BitcastExpression>(ty.f32(), Expr(1));
-  WrapInFunction(bitcast);
+    auto* bitcast = create<ast::BitcastExpression>(ty.f32(), Expr(1_i));
+    WrapInFunction(bitcast);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, bitcast)) << gen.error();
-  EXPECT_EQ(out.str(), "asfloat(1)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, bitcast)) << gen.error();
+    EXPECT_EQ(out.str(), "asfloat(1)");
 }
 
 TEST_F(HlslGeneratorImplTest_Bitcast, EmitExpression_Bitcast_Int) {
-  auto* bitcast = create<ast::BitcastExpression>(ty.i32(), Expr(1u));
-  WrapInFunction(bitcast);
+    auto* bitcast = create<ast::BitcastExpression>(ty.i32(), Expr(1_u));
+    WrapInFunction(bitcast);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, bitcast)) << gen.error();
-  EXPECT_EQ(out.str(), "asint(1u)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, bitcast)) << gen.error();
+    EXPECT_EQ(out.str(), "asint(1u)");
 }
 
 TEST_F(HlslGeneratorImplTest_Bitcast, EmitExpression_Bitcast_Uint) {
-  auto* bitcast = create<ast::BitcastExpression>(ty.u32(), Expr(1));
-  WrapInFunction(bitcast);
+    auto* bitcast = create<ast::BitcastExpression>(ty.u32(), Expr(1_i));
+    WrapInFunction(bitcast);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, bitcast)) << gen.error();
-  EXPECT_EQ(out.str(), "asuint(1)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, bitcast)) << gen.error();
+    EXPECT_EQ(out.str(), "asuint(1)");
 }
 
 }  // namespace
diff --git a/src/tint/writer/hlsl/generator_impl_block_test.cc b/src/tint/writer/hlsl/generator_impl_block_test.cc
index 2f6cd13..9a6cada 100644
--- a/src/tint/writer/hlsl/generator_impl_block_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_block_test.cc
@@ -20,15 +20,15 @@
 using HlslGeneratorImplTest_Block = TestHelper;
 
 TEST_F(HlslGeneratorImplTest_Block, Emit_Block) {
-  auto* b = Block(create<ast::DiscardStatement>());
-  WrapInFunction(b);
+    auto* b = Block(create<ast::DiscardStatement>());
+    WrapInFunction(b);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(b)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  {
+    ASSERT_TRUE(gen.EmitStatement(b)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  {
     discard;
   }
 )");
diff --git a/src/tint/writer/hlsl/generator_impl_break_test.cc b/src/tint/writer/hlsl/generator_impl_break_test.cc
index 4a2c038..4e4ecf1 100644
--- a/src/tint/writer/hlsl/generator_impl_break_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_break_test.cc
@@ -20,15 +20,15 @@
 using HlslGeneratorImplTest_Break = TestHelper;
 
 TEST_F(HlslGeneratorImplTest_Break, Emit_Break) {
-  auto* b = create<ast::BreakStatement>();
-  WrapInFunction(Loop(Block(b)));
+    auto* b = create<ast::BreakStatement>();
+    WrapInFunction(Loop(Block(b)));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(b)) << gen.error();
-  EXPECT_EQ(gen.result(), "  break;\n");
+    ASSERT_TRUE(gen.EmitStatement(b)) << gen.error();
+    EXPECT_EQ(gen.result(), "  break;\n");
 }
 
 }  // namespace
diff --git a/src/tint/writer/hlsl/generator_impl_builtin_test.cc b/src/tint/writer/hlsl/generator_impl_builtin_test.cc
index 95d59af..ada17f1 100644
--- a/src/tint/writer/hlsl/generator_impl_builtin_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_builtin_test.cc
@@ -18,275 +18,274 @@
 #include "src/tint/sem/call.h"
 #include "src/tint/writer/hlsl/test_helper.h"
 
+using ::testing::HasSubstr;
+
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::hlsl {
 namespace {
 
 using BuiltinType = sem::BuiltinType;
-
-using ::testing::HasSubstr;
-
 using HlslGeneratorImplTest_Builtin = TestHelper;
 
 enum class ParamType {
-  kF32,
-  kU32,
-  kBool,
+    kF32,
+    kU32,
+    kBool,
 };
 
 struct BuiltinData {
-  BuiltinType builtin;
-  ParamType type;
-  const char* hlsl_name;
+    BuiltinType builtin;
+    ParamType type;
+    const char* hlsl_name;
 };
 inline std::ostream& operator<<(std::ostream& out, BuiltinData data) {
-  out << data.hlsl_name;
-  switch (data.type) {
-    case ParamType::kF32:
-      out << "f32";
-      break;
-    case ParamType::kU32:
-      out << "u32";
-      break;
-    case ParamType::kBool:
-      out << "bool";
-      break;
-  }
-  out << ">";
-  return out;
+    out << data.hlsl_name;
+    switch (data.type) {
+        case ParamType::kF32:
+            out << "f32";
+            break;
+        case ParamType::kU32:
+            out << "u32";
+            break;
+        case ParamType::kBool:
+            out << "bool";
+            break;
+    }
+    out << ">";
+    return out;
 }
 
 const ast::CallExpression* GenerateCall(BuiltinType builtin,
                                         ParamType type,
                                         ProgramBuilder* builder) {
-  std::string name;
-  std::ostringstream str(name);
-  str << builtin;
-  switch (builtin) {
-    case BuiltinType::kAcos:
-    case BuiltinType::kAsin:
-    case BuiltinType::kAtan:
-    case BuiltinType::kCeil:
-    case BuiltinType::kCos:
-    case BuiltinType::kCosh:
-    case BuiltinType::kDpdx:
-    case BuiltinType::kDpdxCoarse:
-    case BuiltinType::kDpdxFine:
-    case BuiltinType::kDpdy:
-    case BuiltinType::kDpdyCoarse:
-    case BuiltinType::kDpdyFine:
-    case BuiltinType::kExp:
-    case BuiltinType::kExp2:
-    case BuiltinType::kFloor:
-    case BuiltinType::kFract:
-    case BuiltinType::kFwidth:
-    case BuiltinType::kFwidthCoarse:
-    case BuiltinType::kFwidthFine:
-    case BuiltinType::kInverseSqrt:
-    case BuiltinType::kLength:
-    case BuiltinType::kLog:
-    case BuiltinType::kLog2:
-    case BuiltinType::kNormalize:
-    case BuiltinType::kRound:
-    case BuiltinType::kSin:
-    case BuiltinType::kSinh:
-    case BuiltinType::kSqrt:
-    case BuiltinType::kTan:
-    case BuiltinType::kTanh:
-    case BuiltinType::kTrunc:
-    case BuiltinType::kSign:
-      return builder->Call(str.str(), "f2");
-    case BuiltinType::kLdexp:
-      return builder->Call(str.str(), "f2", "i2");
-    case BuiltinType::kAtan2:
-    case BuiltinType::kDot:
-    case BuiltinType::kDistance:
-    case BuiltinType::kPow:
-    case BuiltinType::kReflect:
-    case BuiltinType::kStep:
-      return builder->Call(str.str(), "f2", "f2");
-    case BuiltinType::kCross:
-      return builder->Call(str.str(), "f3", "f3");
-    case BuiltinType::kFma:
-    case BuiltinType::kMix:
-    case BuiltinType::kFaceForward:
-    case BuiltinType::kSmoothstep:
-    case BuiltinType::kSmoothStep:
-      return builder->Call(str.str(), "f2", "f2", "f2");
-    case BuiltinType::kAll:
-    case BuiltinType::kAny:
-      return builder->Call(str.str(), "b2");
-    case BuiltinType::kAbs:
-      if (type == ParamType::kF32) {
-        return builder->Call(str.str(), "f2");
-      } else {
-        return builder->Call(str.str(), "u2");
-      }
-    case BuiltinType::kCountOneBits:
-    case BuiltinType::kReverseBits:
-      return builder->Call(str.str(), "u2");
-    case BuiltinType::kMax:
-    case BuiltinType::kMin:
-      if (type == ParamType::kF32) {
-        return builder->Call(str.str(), "f2", "f2");
-      } else {
-        return builder->Call(str.str(), "u2", "u2");
-      }
-    case BuiltinType::kClamp:
-      if (type == ParamType::kF32) {
-        return builder->Call(str.str(), "f2", "f2", "f2");
-      } else {
-        return builder->Call(str.str(), "u2", "u2", "u2");
-      }
-    case BuiltinType::kSelect:
-      return builder->Call(str.str(), "f2", "f2", "b2");
-    case BuiltinType::kDeterminant:
-      return builder->Call(str.str(), "m2x2");
-    case BuiltinType::kTranspose:
-      return builder->Call(str.str(), "m3x2");
-    default:
-      break;
-  }
-  return nullptr;
+    std::string name;
+    std::ostringstream str(name);
+    str << builtin;
+    switch (builtin) {
+        case BuiltinType::kAcos:
+        case BuiltinType::kAsin:
+        case BuiltinType::kAtan:
+        case BuiltinType::kCeil:
+        case BuiltinType::kCos:
+        case BuiltinType::kCosh:
+        case BuiltinType::kDpdx:
+        case BuiltinType::kDpdxCoarse:
+        case BuiltinType::kDpdxFine:
+        case BuiltinType::kDpdy:
+        case BuiltinType::kDpdyCoarse:
+        case BuiltinType::kDpdyFine:
+        case BuiltinType::kExp:
+        case BuiltinType::kExp2:
+        case BuiltinType::kFloor:
+        case BuiltinType::kFract:
+        case BuiltinType::kFwidth:
+        case BuiltinType::kFwidthCoarse:
+        case BuiltinType::kFwidthFine:
+        case BuiltinType::kInverseSqrt:
+        case BuiltinType::kLength:
+        case BuiltinType::kLog:
+        case BuiltinType::kLog2:
+        case BuiltinType::kNormalize:
+        case BuiltinType::kRound:
+        case BuiltinType::kSin:
+        case BuiltinType::kSinh:
+        case BuiltinType::kSqrt:
+        case BuiltinType::kTan:
+        case BuiltinType::kTanh:
+        case BuiltinType::kTrunc:
+        case BuiltinType::kSign:
+            return builder->Call(str.str(), "f2");
+        case BuiltinType::kLdexp:
+            return builder->Call(str.str(), "f2", "i2");
+        case BuiltinType::kAtan2:
+        case BuiltinType::kDot:
+        case BuiltinType::kDistance:
+        case BuiltinType::kPow:
+        case BuiltinType::kReflect:
+        case BuiltinType::kStep:
+            return builder->Call(str.str(), "f2", "f2");
+        case BuiltinType::kCross:
+            return builder->Call(str.str(), "f3", "f3");
+        case BuiltinType::kFma:
+        case BuiltinType::kMix:
+        case BuiltinType::kFaceForward:
+        case BuiltinType::kSmoothstep:
+        case BuiltinType::kSmoothStep:
+            return builder->Call(str.str(), "f2", "f2", "f2");
+        case BuiltinType::kAll:
+        case BuiltinType::kAny:
+            return builder->Call(str.str(), "b2");
+        case BuiltinType::kAbs:
+            if (type == ParamType::kF32) {
+                return builder->Call(str.str(), "f2");
+            } else {
+                return builder->Call(str.str(), "u2");
+            }
+        case BuiltinType::kCountOneBits:
+        case BuiltinType::kReverseBits:
+            return builder->Call(str.str(), "u2");
+        case BuiltinType::kMax:
+        case BuiltinType::kMin:
+            if (type == ParamType::kF32) {
+                return builder->Call(str.str(), "f2", "f2");
+            } else {
+                return builder->Call(str.str(), "u2", "u2");
+            }
+        case BuiltinType::kClamp:
+            if (type == ParamType::kF32) {
+                return builder->Call(str.str(), "f2", "f2", "f2");
+            } else {
+                return builder->Call(str.str(), "u2", "u2", "u2");
+            }
+        case BuiltinType::kSelect:
+            return builder->Call(str.str(), "f2", "f2", "b2");
+        case BuiltinType::kDeterminant:
+            return builder->Call(str.str(), "m2x2");
+        case BuiltinType::kTranspose:
+            return builder->Call(str.str(), "m3x2");
+        default:
+            break;
+    }
+    return nullptr;
 }
 using HlslBuiltinTest = TestParamHelper<BuiltinData>;
 TEST_P(HlslBuiltinTest, Emit) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  Global("f2", ty.vec2<f32>(), ast::StorageClass::kPrivate);
-  Global("f3", ty.vec3<f32>(), ast::StorageClass::kPrivate);
-  Global("u2", ty.vec2<u32>(), ast::StorageClass::kPrivate);
-  Global("i2", ty.vec2<i32>(), ast::StorageClass::kPrivate);
-  Global("b2", ty.vec2<bool>(), ast::StorageClass::kPrivate);
-  Global("m2x2", ty.mat2x2<f32>(), ast::StorageClass::kPrivate);
-  Global("m3x2", ty.mat3x2<f32>(), ast::StorageClass::kPrivate);
+    Global("f2", ty.vec2<f32>(), ast::StorageClass::kPrivate);
+    Global("f3", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+    Global("u2", ty.vec2<u32>(), ast::StorageClass::kPrivate);
+    Global("i2", ty.vec2<i32>(), ast::StorageClass::kPrivate);
+    Global("b2", ty.vec2<bool>(), ast::StorageClass::kPrivate);
+    Global("m2x2", ty.mat2x2<f32>(), ast::StorageClass::kPrivate);
+    Global("m3x2", ty.mat3x2<f32>(), ast::StorageClass::kPrivate);
 
-  auto* call = GenerateCall(param.builtin, param.type, this);
-  ASSERT_NE(nullptr, call) << "Unhandled builtin";
-  Func("func", {}, ty.void_(), {CallStmt(call)},
-       {create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
+    auto* call = GenerateCall(param.builtin, param.type, this);
+    ASSERT_NE(nullptr, call) << "Unhandled builtin";
+    Func("func", {}, ty.void_(), {CallStmt(call)},
+         {create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  auto* sem = program->Sem().Get(call);
-  ASSERT_NE(sem, nullptr);
-  auto* target = sem->Target();
-  ASSERT_NE(target, nullptr);
-  auto* builtin = target->As<sem::Builtin>();
-  ASSERT_NE(builtin, nullptr);
+    auto* sem = program->Sem().Get(call);
+    ASSERT_NE(sem, nullptr);
+    auto* target = sem->Target();
+    ASSERT_NE(target, nullptr);
+    auto* builtin = target->As<sem::Builtin>();
+    ASSERT_NE(builtin, nullptr);
 
-  EXPECT_EQ(gen.generate_builtin_name(builtin), param.hlsl_name);
+    EXPECT_EQ(gen.generate_builtin_name(builtin), param.hlsl_name);
 }
 INSTANTIATE_TEST_SUITE_P(
     HlslGeneratorImplTest_Builtin,
     HlslBuiltinTest,
-    testing::Values(
-        BuiltinData{BuiltinType::kAbs, ParamType::kF32, "abs"},
-        BuiltinData{BuiltinType::kAbs, ParamType::kU32, "abs"},
-        BuiltinData{BuiltinType::kAcos, ParamType::kF32, "acos"},
-        BuiltinData{BuiltinType::kAll, ParamType::kBool, "all"},
-        BuiltinData{BuiltinType::kAny, ParamType::kBool, "any"},
-        BuiltinData{BuiltinType::kAsin, ParamType::kF32, "asin"},
-        BuiltinData{BuiltinType::kAtan, ParamType::kF32, "atan"},
-        BuiltinData{BuiltinType::kAtan2, ParamType::kF32, "atan2"},
-        BuiltinData{BuiltinType::kCeil, ParamType::kF32, "ceil"},
-        BuiltinData{BuiltinType::kClamp, ParamType::kF32, "clamp"},
-        BuiltinData{BuiltinType::kClamp, ParamType::kU32, "clamp"},
-        BuiltinData{BuiltinType::kCos, ParamType::kF32, "cos"},
-        BuiltinData{BuiltinType::kCosh, ParamType::kF32, "cosh"},
-        BuiltinData{BuiltinType::kCountOneBits, ParamType::kU32, "countbits"},
-        BuiltinData{BuiltinType::kCross, ParamType::kF32, "cross"},
-        BuiltinData{BuiltinType::kDeterminant, ParamType::kF32, "determinant"},
-        BuiltinData{BuiltinType::kDistance, ParamType::kF32, "distance"},
-        BuiltinData{BuiltinType::kDot, ParamType::kF32, "dot"},
-        BuiltinData{BuiltinType::kDpdx, ParamType::kF32, "ddx"},
-        BuiltinData{BuiltinType::kDpdxCoarse, ParamType::kF32, "ddx_coarse"},
-        BuiltinData{BuiltinType::kDpdxFine, ParamType::kF32, "ddx_fine"},
-        BuiltinData{BuiltinType::kDpdy, ParamType::kF32, "ddy"},
-        BuiltinData{BuiltinType::kDpdyCoarse, ParamType::kF32, "ddy_coarse"},
-        BuiltinData{BuiltinType::kDpdyFine, ParamType::kF32, "ddy_fine"},
-        BuiltinData{BuiltinType::kExp, ParamType::kF32, "exp"},
-        BuiltinData{BuiltinType::kExp2, ParamType::kF32, "exp2"},
-        BuiltinData{BuiltinType::kFaceForward, ParamType::kF32, "faceforward"},
-        BuiltinData{BuiltinType::kFloor, ParamType::kF32, "floor"},
-        BuiltinData{BuiltinType::kFma, ParamType::kF32, "mad"},
-        BuiltinData{BuiltinType::kFract, ParamType::kF32, "frac"},
-        BuiltinData{BuiltinType::kFwidth, ParamType::kF32, "fwidth"},
-        BuiltinData{BuiltinType::kFwidthCoarse, ParamType::kF32, "fwidth"},
-        BuiltinData{BuiltinType::kFwidthFine, ParamType::kF32, "fwidth"},
-        BuiltinData{BuiltinType::kInverseSqrt, ParamType::kF32, "rsqrt"},
-        BuiltinData{BuiltinType::kLdexp, ParamType::kF32, "ldexp"},
-        BuiltinData{BuiltinType::kLength, ParamType::kF32, "length"},
-        BuiltinData{BuiltinType::kLog, ParamType::kF32, "log"},
-        BuiltinData{BuiltinType::kLog2, ParamType::kF32, "log2"},
-        BuiltinData{BuiltinType::kMax, ParamType::kF32, "max"},
-        BuiltinData{BuiltinType::kMax, ParamType::kU32, "max"},
-        BuiltinData{BuiltinType::kMin, ParamType::kF32, "min"},
-        BuiltinData{BuiltinType::kMin, ParamType::kU32, "min"},
-        BuiltinData{BuiltinType::kMix, ParamType::kF32, "lerp"},
-        BuiltinData{BuiltinType::kNormalize, ParamType::kF32, "normalize"},
-        BuiltinData{BuiltinType::kPow, ParamType::kF32, "pow"},
-        BuiltinData{BuiltinType::kReflect, ParamType::kF32, "reflect"},
-        BuiltinData{BuiltinType::kReverseBits, ParamType::kU32, "reversebits"},
-        BuiltinData{BuiltinType::kRound, ParamType::kU32, "round"},
-        BuiltinData{BuiltinType::kSign, ParamType::kF32, "sign"},
-        BuiltinData{BuiltinType::kSin, ParamType::kF32, "sin"},
-        BuiltinData{BuiltinType::kSinh, ParamType::kF32, "sinh"},
-        BuiltinData{BuiltinType::kSmoothstep, ParamType::kF32, "smoothstep"},
-        BuiltinData{BuiltinType::kSmoothStep, ParamType::kF32, "smoothstep"},
-        BuiltinData{BuiltinType::kSqrt, ParamType::kF32, "sqrt"},
-        BuiltinData{BuiltinType::kStep, ParamType::kF32, "step"},
-        BuiltinData{BuiltinType::kTan, ParamType::kF32, "tan"},
-        BuiltinData{BuiltinType::kTanh, ParamType::kF32, "tanh"},
-        BuiltinData{BuiltinType::kTranspose, ParamType::kF32, "transpose"},
-        BuiltinData{BuiltinType::kTrunc, ParamType::kF32, "trunc"}));
+    testing::Values(BuiltinData{BuiltinType::kAbs, ParamType::kF32, "abs"},
+                    BuiltinData{BuiltinType::kAbs, ParamType::kU32, "abs"},
+                    BuiltinData{BuiltinType::kAcos, ParamType::kF32, "acos"},
+                    BuiltinData{BuiltinType::kAll, ParamType::kBool, "all"},
+                    BuiltinData{BuiltinType::kAny, ParamType::kBool, "any"},
+                    BuiltinData{BuiltinType::kAsin, ParamType::kF32, "asin"},
+                    BuiltinData{BuiltinType::kAtan, ParamType::kF32, "atan"},
+                    BuiltinData{BuiltinType::kAtan2, ParamType::kF32, "atan2"},
+                    BuiltinData{BuiltinType::kCeil, ParamType::kF32, "ceil"},
+                    BuiltinData{BuiltinType::kClamp, ParamType::kF32, "clamp"},
+                    BuiltinData{BuiltinType::kClamp, ParamType::kU32, "clamp"},
+                    BuiltinData{BuiltinType::kCos, ParamType::kF32, "cos"},
+                    BuiltinData{BuiltinType::kCosh, ParamType::kF32, "cosh"},
+                    BuiltinData{BuiltinType::kCountOneBits, ParamType::kU32, "countbits"},
+                    BuiltinData{BuiltinType::kCross, ParamType::kF32, "cross"},
+                    BuiltinData{BuiltinType::kDeterminant, ParamType::kF32, "determinant"},
+                    BuiltinData{BuiltinType::kDistance, ParamType::kF32, "distance"},
+                    BuiltinData{BuiltinType::kDot, ParamType::kF32, "dot"},
+                    BuiltinData{BuiltinType::kDpdx, ParamType::kF32, "ddx"},
+                    BuiltinData{BuiltinType::kDpdxCoarse, ParamType::kF32, "ddx_coarse"},
+                    BuiltinData{BuiltinType::kDpdxFine, ParamType::kF32, "ddx_fine"},
+                    BuiltinData{BuiltinType::kDpdy, ParamType::kF32, "ddy"},
+                    BuiltinData{BuiltinType::kDpdyCoarse, ParamType::kF32, "ddy_coarse"},
+                    BuiltinData{BuiltinType::kDpdyFine, ParamType::kF32, "ddy_fine"},
+                    BuiltinData{BuiltinType::kExp, ParamType::kF32, "exp"},
+                    BuiltinData{BuiltinType::kExp2, ParamType::kF32, "exp2"},
+                    BuiltinData{BuiltinType::kFaceForward, ParamType::kF32, "faceforward"},
+                    BuiltinData{BuiltinType::kFloor, ParamType::kF32, "floor"},
+                    BuiltinData{BuiltinType::kFma, ParamType::kF32, "mad"},
+                    BuiltinData{BuiltinType::kFract, ParamType::kF32, "frac"},
+                    BuiltinData{BuiltinType::kFwidth, ParamType::kF32, "fwidth"},
+                    BuiltinData{BuiltinType::kFwidthCoarse, ParamType::kF32, "fwidth"},
+                    BuiltinData{BuiltinType::kFwidthFine, ParamType::kF32, "fwidth"},
+                    BuiltinData{BuiltinType::kInverseSqrt, ParamType::kF32, "rsqrt"},
+                    BuiltinData{BuiltinType::kLdexp, ParamType::kF32, "ldexp"},
+                    BuiltinData{BuiltinType::kLength, ParamType::kF32, "length"},
+                    BuiltinData{BuiltinType::kLog, ParamType::kF32, "log"},
+                    BuiltinData{BuiltinType::kLog2, ParamType::kF32, "log2"},
+                    BuiltinData{BuiltinType::kMax, ParamType::kF32, "max"},
+                    BuiltinData{BuiltinType::kMax, ParamType::kU32, "max"},
+                    BuiltinData{BuiltinType::kMin, ParamType::kF32, "min"},
+                    BuiltinData{BuiltinType::kMin, ParamType::kU32, "min"},
+                    BuiltinData{BuiltinType::kMix, ParamType::kF32, "lerp"},
+                    BuiltinData{BuiltinType::kNormalize, ParamType::kF32, "normalize"},
+                    BuiltinData{BuiltinType::kPow, ParamType::kF32, "pow"},
+                    BuiltinData{BuiltinType::kReflect, ParamType::kF32, "reflect"},
+                    BuiltinData{BuiltinType::kReverseBits, ParamType::kU32, "reversebits"},
+                    BuiltinData{BuiltinType::kRound, ParamType::kU32, "round"},
+                    BuiltinData{BuiltinType::kSign, ParamType::kF32, "sign"},
+                    BuiltinData{BuiltinType::kSin, ParamType::kF32, "sin"},
+                    BuiltinData{BuiltinType::kSinh, ParamType::kF32, "sinh"},
+                    BuiltinData{BuiltinType::kSmoothstep, ParamType::kF32, "smoothstep"},
+                    BuiltinData{BuiltinType::kSmoothStep, ParamType::kF32, "smoothstep"},
+                    BuiltinData{BuiltinType::kSqrt, ParamType::kF32, "sqrt"},
+                    BuiltinData{BuiltinType::kStep, ParamType::kF32, "step"},
+                    BuiltinData{BuiltinType::kTan, ParamType::kF32, "tan"},
+                    BuiltinData{BuiltinType::kTanh, ParamType::kF32, "tanh"},
+                    BuiltinData{BuiltinType::kTranspose, ParamType::kF32, "transpose"},
+                    BuiltinData{BuiltinType::kTrunc, ParamType::kF32, "trunc"}));
 
 TEST_F(HlslGeneratorImplTest_Builtin, Builtin_Call) {
-  auto* call = Call("dot", "param1", "param2");
+    auto* call = Call("dot", "param1", "param2");
 
-  Global("param1", ty.vec3<f32>(), ast::StorageClass::kPrivate);
-  Global("param2", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+    Global("param1", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+    Global("param2", ty.vec3<f32>(), ast::StorageClass::kPrivate);
 
-  WrapInFunction(CallStmt(call));
+    WrapInFunction(CallStmt(call));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
-  EXPECT_EQ(out.str(), "dot(param1, param2)");
+    gen.increment_indent();
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
+    EXPECT_EQ(out.str(), "dot(param1, param2)");
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Select_Scalar) {
-  auto* call = Call("select", 1.0f, 2.0f, true);
-  WrapInFunction(CallStmt(call));
-  GeneratorImpl& gen = Build();
+    auto* call = Call("select", 1.0f, 2.0f, true);
+    WrapInFunction(CallStmt(call));
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
-  EXPECT_EQ(out.str(), "(true ? 2.0f : 1.0f)");
+    gen.increment_indent();
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
+    EXPECT_EQ(out.str(), "(true ? 2.0f : 1.0f)");
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Select_Vector) {
-  auto* call =
-      Call("select", vec2<i32>(1, 2), vec2<i32>(3, 4), vec2<bool>(true, false));
-  WrapInFunction(CallStmt(call));
-  GeneratorImpl& gen = Build();
+    auto* call = Call("select", vec2<i32>(1_i, 2_i), vec2<i32>(3_i, 4_i), vec2<bool>(true, false));
+    WrapInFunction(CallStmt(call));
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
-  EXPECT_EQ(out.str(), "(bool2(true, false) ? int2(3, 4) : int2(1, 2))");
+    gen.increment_indent();
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
+    EXPECT_EQ(out.str(), "(bool2(true, false) ? int2(3, 4) : int2(1, 2))");
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Modf_Scalar) {
-  auto* call = Call("modf", 1.0f);
-  WrapInFunction(CallStmt(call));
+    auto* call = Call("modf", 1.0f);
+    WrapInFunction(CallStmt(call));
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(struct modf_result {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(struct modf_result {
   float fract;
   float whole;
 };
@@ -306,13 +305,13 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Modf_Vector) {
-  auto* call = Call("modf", vec3<f32>());
-  WrapInFunction(CallStmt(call));
+    auto* call = Call("modf", vec3<f32>());
+    WrapInFunction(CallStmt(call));
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(struct modf_result_vec3 {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(struct modf_result_vec3 {
   float3 fract;
   float3 whole;
 };
@@ -332,13 +331,13 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Frexp_Scalar_i32) {
-  auto* call = Call("frexp", 1.0f);
-  WrapInFunction(CallStmt(call));
+    auto* call = Call("frexp", 1.0f);
+    WrapInFunction(CallStmt(call));
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(struct frexp_result {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(struct frexp_result {
   float sig;
   int exp;
 };
@@ -358,13 +357,13 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Frexp_Vector_i32) {
-  auto* call = Call("frexp", vec3<f32>());
-  WrapInFunction(CallStmt(call));
+    auto* call = Call("frexp", vec3<f32>());
+    WrapInFunction(CallStmt(call));
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(struct frexp_result_vec3 {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(struct frexp_result_vec3 {
   float3 sig;
   int3 exp;
 };
@@ -384,14 +383,14 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Degrees_Scalar) {
-  auto* val = Var("val", ty.f32());
-  auto* call = Call("degrees", val);
-  WrapInFunction(val, call);
+    auto* val = Var("val", ty.f32());
+    auto* call = Call("degrees", val);
+    WrapInFunction(val, call);
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(float tint_degrees(float param_0) {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(float tint_degrees(float param_0) {
   return param_0 * 57.295779513082322865;
 }
 
@@ -405,14 +404,14 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Degrees_Vector) {
-  auto* val = Var("val", ty.vec3<f32>());
-  auto* call = Call("degrees", val);
-  WrapInFunction(val, call);
+    auto* val = Var("val", ty.vec3<f32>());
+    auto* call = Call("degrees", val);
+    WrapInFunction(val, call);
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(float3 tint_degrees(float3 param_0) {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(float3 tint_degrees(float3 param_0) {
   return param_0 * 57.295779513082322865;
 }
 
@@ -426,14 +425,14 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Radians_Scalar) {
-  auto* val = Var("val", ty.f32());
-  auto* call = Call("radians", val);
-  WrapInFunction(val, call);
+    auto* val = Var("val", ty.f32());
+    auto* call = Call("radians", val);
+    WrapInFunction(val, call);
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(float tint_radians(float param_0) {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(float tint_radians(float param_0) {
   return param_0 * 0.017453292519943295474;
 }
 
@@ -447,14 +446,14 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Radians_Vector) {
-  auto* val = Var("val", ty.vec3<f32>());
-  auto* call = Call("radians", val);
-  WrapInFunction(val, call);
+    auto* val = Var("val", ty.vec3<f32>());
+    auto* call = Call("radians", val);
+    WrapInFunction(val, call);
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(float3 tint_radians(float3 param_0) {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(float3 tint_radians(float3 param_0) {
   return param_0 * 0.017453292519943295474;
 }
 
@@ -468,13 +467,13 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Pack4x8Snorm) {
-  auto* call = Call("pack4x8snorm", "p1");
-  Global("p1", ty.vec4<f32>(), ast::StorageClass::kPrivate);
-  WrapInFunction(CallStmt(call));
-  GeneratorImpl& gen = Build();
+    auto* call = Call("pack4x8snorm", "p1");
+    Global("p1", ty.vec4<f32>(), ast::StorageClass::kPrivate);
+    WrapInFunction(CallStmt(call));
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(uint tint_pack4x8snorm(float4 param_0) {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(uint tint_pack4x8snorm(float4 param_0) {
   int4 i = int4(round(clamp(param_0, -1.0, 1.0) * 127.0)) & 0xff;
   return asuint(i.x | i.y << 8 | i.z << 16 | i.w << 24);
 }
@@ -490,13 +489,13 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Pack4x8Unorm) {
-  auto* call = Call("pack4x8unorm", "p1");
-  Global("p1", ty.vec4<f32>(), ast::StorageClass::kPrivate);
-  WrapInFunction(CallStmt(call));
-  GeneratorImpl& gen = Build();
+    auto* call = Call("pack4x8unorm", "p1");
+    Global("p1", ty.vec4<f32>(), ast::StorageClass::kPrivate);
+    WrapInFunction(CallStmt(call));
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(uint tint_pack4x8unorm(float4 param_0) {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(uint tint_pack4x8unorm(float4 param_0) {
   uint4 i = uint4(round(clamp(param_0, 0.0, 1.0) * 255.0));
   return (i.x | i.y << 8 | i.z << 16 | i.w << 24);
 }
@@ -512,13 +511,13 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Pack2x16Snorm) {
-  auto* call = Call("pack2x16snorm", "p1");
-  Global("p1", ty.vec2<f32>(), ast::StorageClass::kPrivate);
-  WrapInFunction(CallStmt(call));
-  GeneratorImpl& gen = Build();
+    auto* call = Call("pack2x16snorm", "p1");
+    Global("p1", ty.vec2<f32>(), ast::StorageClass::kPrivate);
+    WrapInFunction(CallStmt(call));
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(uint tint_pack2x16snorm(float2 param_0) {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(uint tint_pack2x16snorm(float2 param_0) {
   int2 i = int2(round(clamp(param_0, -1.0, 1.0) * 32767.0)) & 0xffff;
   return asuint(i.x | i.y << 16);
 }
@@ -534,13 +533,13 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Pack2x16Unorm) {
-  auto* call = Call("pack2x16unorm", "p1");
-  Global("p1", ty.vec2<f32>(), ast::StorageClass::kPrivate);
-  WrapInFunction(CallStmt(call));
-  GeneratorImpl& gen = Build();
+    auto* call = Call("pack2x16unorm", "p1");
+    Global("p1", ty.vec2<f32>(), ast::StorageClass::kPrivate);
+    WrapInFunction(CallStmt(call));
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(uint tint_pack2x16unorm(float2 param_0) {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(uint tint_pack2x16unorm(float2 param_0) {
   uint2 i = uint2(round(clamp(param_0, 0.0, 1.0) * 65535.0));
   return (i.x | i.y << 16);
 }
@@ -556,13 +555,13 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Pack2x16Float) {
-  auto* call = Call("pack2x16float", "p1");
-  Global("p1", ty.vec2<f32>(), ast::StorageClass::kPrivate);
-  WrapInFunction(CallStmt(call));
-  GeneratorImpl& gen = Build();
+    auto* call = Call("pack2x16float", "p1");
+    Global("p1", ty.vec2<f32>(), ast::StorageClass::kPrivate);
+    WrapInFunction(CallStmt(call));
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(uint tint_pack2x16float(float2 param_0) {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(uint tint_pack2x16float(float2 param_0) {
   uint2 i = f32tof16(param_0);
   return i.x | (i.y << 16);
 }
@@ -578,13 +577,13 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Unpack4x8Snorm) {
-  auto* call = Call("unpack4x8snorm", "p1");
-  Global("p1", ty.u32(), ast::StorageClass::kPrivate);
-  WrapInFunction(CallStmt(call));
-  GeneratorImpl& gen = Build();
+    auto* call = Call("unpack4x8snorm", "p1");
+    Global("p1", ty.u32(), ast::StorageClass::kPrivate);
+    WrapInFunction(CallStmt(call));
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(float4 tint_unpack4x8snorm(uint param_0) {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(float4 tint_unpack4x8snorm(uint param_0) {
   int j = int(param_0);
   int4 i = int4(j << 24, j << 16, j << 8, j) >> 24;
   return clamp(float4(i) / 127.0, -1.0, 1.0);
@@ -601,13 +600,13 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Unpack4x8Unorm) {
-  auto* call = Call("unpack4x8unorm", "p1");
-  Global("p1", ty.u32(), ast::StorageClass::kPrivate);
-  WrapInFunction(CallStmt(call));
-  GeneratorImpl& gen = Build();
+    auto* call = Call("unpack4x8unorm", "p1");
+    Global("p1", ty.u32(), ast::StorageClass::kPrivate);
+    WrapInFunction(CallStmt(call));
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(float4 tint_unpack4x8unorm(uint param_0) {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(float4 tint_unpack4x8unorm(uint param_0) {
   uint j = param_0;
   uint4 i = uint4(j & 0xff, (j >> 8) & 0xff, (j >> 16) & 0xff, j >> 24);
   return float4(i) / 255.0;
@@ -624,13 +623,13 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Unpack2x16Snorm) {
-  auto* call = Call("unpack2x16snorm", "p1");
-  Global("p1", ty.u32(), ast::StorageClass::kPrivate);
-  WrapInFunction(CallStmt(call));
-  GeneratorImpl& gen = Build();
+    auto* call = Call("unpack2x16snorm", "p1");
+    Global("p1", ty.u32(), ast::StorageClass::kPrivate);
+    WrapInFunction(CallStmt(call));
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(float2 tint_unpack2x16snorm(uint param_0) {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(float2 tint_unpack2x16snorm(uint param_0) {
   int j = int(param_0);
   int2 i = int2(j << 16, j) >> 16;
   return clamp(float2(i) / 32767.0, -1.0, 1.0);
@@ -647,13 +646,13 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Unpack2x16Unorm) {
-  auto* call = Call("unpack2x16unorm", "p1");
-  Global("p1", ty.u32(), ast::StorageClass::kPrivate);
-  WrapInFunction(CallStmt(call));
-  GeneratorImpl& gen = Build();
+    auto* call = Call("unpack2x16unorm", "p1");
+    Global("p1", ty.u32(), ast::StorageClass::kPrivate);
+    WrapInFunction(CallStmt(call));
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(float2 tint_unpack2x16unorm(uint param_0) {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(float2 tint_unpack2x16unorm(uint param_0) {
   uint j = param_0;
   uint2 i = uint2(j & 0xffff, j >> 16);
   return float2(i) / 65535.0;
@@ -670,13 +669,13 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, Unpack2x16Float) {
-  auto* call = Call("unpack2x16float", "p1");
-  Global("p1", ty.u32(), ast::StorageClass::kPrivate);
-  WrapInFunction(CallStmt(call));
-  GeneratorImpl& gen = Build();
+    auto* call = Call("unpack2x16float", "p1");
+    Global("p1", ty.u32(), ast::StorageClass::kPrivate);
+    WrapInFunction(CallStmt(call));
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(float2 tint_unpack2x16float(uint param_0) {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(float2 tint_unpack2x16float(uint param_0) {
   uint i = param_0;
   return f16tof32(uint2(i & 0xffff, i >> 16));
 }
@@ -692,16 +691,16 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, StorageBarrier) {
-  Func("main", {}, ty.void_(), {CallStmt(Call("storageBarrier"))},
-       {
-           Stage(ast::PipelineStage::kCompute),
-           WorkgroupSize(1),
-       });
+    Func("main", {}, ty.void_(), {CallStmt(Call("storageBarrier"))},
+         {
+             Stage(ast::PipelineStage::kCompute),
+             WorkgroupSize(1_i),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"([numthreads(1, 1, 1)]
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"([numthreads(1, 1, 1)]
 void main() {
   DeviceMemoryBarrierWithGroupSync();
   return;
@@ -710,16 +709,16 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Builtin, WorkgroupBarrier) {
-  Func("main", {}, ty.void_(), {CallStmt(Call("workgroupBarrier"))},
-       {
-           Stage(ast::PipelineStage::kCompute),
-           WorkgroupSize(1),
-       });
+    Func("main", {}, ty.void_(), {CallStmt(Call("workgroupBarrier"))},
+         {
+             Stage(ast::PipelineStage::kCompute),
+             WorkgroupSize(1_i),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"([numthreads(1, 1, 1)]
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"([numthreads(1, 1, 1)]
 void main() {
   GroupMemoryBarrierWithGroupSync();
   return;
diff --git a/src/tint/writer/hlsl/generator_impl_builtin_texture_test.cc b/src/tint/writer/hlsl/generator_impl_builtin_texture_test.cc
index f11dd90..60bd303 100644
--- a/src/tint/writer/hlsl/generator_impl_builtin_texture_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_builtin_texture_test.cc
@@ -24,369 +24,367 @@
 using ::testing::HasSubstr;
 
 struct ExpectedResult {
-  ExpectedResult(const char* o) : out(o) {}  // NOLINT
-  ExpectedResult(const char* p, const char* o) : pre(p), out(o) {}
+    ExpectedResult(const char* o) : out(o) {}  // NOLINT
+    ExpectedResult(const char* p, const char* o) : pre(p), out(o) {}
 
-  std::string pre;
-  std::string out;
+    std::string pre;
+    std::string out;
 };
 
-ExpectedResult expected_texture_overload(
-    ast::builtin::test::ValidTextureOverload overload) {
-  using ValidTextureOverload = ast::builtin::test::ValidTextureOverload;
-  switch (overload) {
-    case ValidTextureOverload::kDimensions1d:
-    case ValidTextureOverload::kDimensionsStorageWO1d:
-      return {
-          R"(int tint_tmp;
+ExpectedResult expected_texture_overload(ast::builtin::test::ValidTextureOverload overload) {
+    using ValidTextureOverload = ast::builtin::test::ValidTextureOverload;
+    switch (overload) {
+        case ValidTextureOverload::kDimensions1d:
+        case ValidTextureOverload::kDimensionsStorageWO1d:
+            return {
+                R"(int tint_tmp;
   tint_symbol.GetDimensions(tint_tmp);
 )",
-          "tint_tmp;",
-      };
-    case ValidTextureOverload::kDimensions2d:
-    case ValidTextureOverload::kDimensionsDepth2d:
-    case ValidTextureOverload::kDimensionsStorageWO2d:
-      return {
-          R"(int2 tint_tmp;
+                "tint_tmp;",
+            };
+        case ValidTextureOverload::kDimensions2d:
+        case ValidTextureOverload::kDimensionsDepth2d:
+        case ValidTextureOverload::kDimensionsStorageWO2d:
+            return {
+                R"(int2 tint_tmp;
   tint_symbol.GetDimensions(tint_tmp.x, tint_tmp.y);
 )",
-          "tint_tmp;",
-      };
-    case ValidTextureOverload::kDimensionsDepthMultisampled2d:
-    case ValidTextureOverload::kDimensionsMultisampled2d:
-      return {
-          R"(int3 tint_tmp;
+                "tint_tmp;",
+            };
+        case ValidTextureOverload::kDimensionsDepthMultisampled2d:
+        case ValidTextureOverload::kDimensionsMultisampled2d:
+            return {
+                R"(int3 tint_tmp;
   tint_symbol.GetDimensions(tint_tmp.x, tint_tmp.y, tint_tmp.z);
 )",
-          "tint_tmp.xy;",
-      };
+                "tint_tmp.xy;",
+            };
 
-    case ValidTextureOverload::kDimensions2dArray:
-    case ValidTextureOverload::kDimensionsDepth2dArray:
-    case ValidTextureOverload::kDimensionsStorageWO2dArray:
-      return {
-          R"(int3 tint_tmp;
+        case ValidTextureOverload::kDimensions2dArray:
+        case ValidTextureOverload::kDimensionsDepth2dArray:
+        case ValidTextureOverload::kDimensionsStorageWO2dArray:
+            return {
+                R"(int3 tint_tmp;
   tint_symbol.GetDimensions(tint_tmp.x, tint_tmp.y, tint_tmp.z);
 )",
-          "tint_tmp.xy;",
-      };
-    case ValidTextureOverload::kDimensions3d:
-    case ValidTextureOverload::kDimensionsStorageWO3d:
-      return {
-          R"(int3 tint_tmp;
+                "tint_tmp.xy;",
+            };
+        case ValidTextureOverload::kDimensions3d:
+        case ValidTextureOverload::kDimensionsStorageWO3d:
+            return {
+                R"(int3 tint_tmp;
   tint_symbol.GetDimensions(tint_tmp.x, tint_tmp.y, tint_tmp.z);
 )",
-          "tint_tmp;",
-      };
-    case ValidTextureOverload::kDimensionsCube:
-    case ValidTextureOverload::kDimensionsDepthCube:
-      return {
-          R"(int2 tint_tmp;
+                "tint_tmp;",
+            };
+        case ValidTextureOverload::kDimensionsCube:
+        case ValidTextureOverload::kDimensionsDepthCube:
+            return {
+                R"(int2 tint_tmp;
   tint_symbol.GetDimensions(tint_tmp.x, tint_tmp.y);
 )",
-          "tint_tmp;",
-      };
-    case ValidTextureOverload::kDimensionsCubeArray:
-    case ValidTextureOverload::kDimensionsDepthCubeArray:
-      return {
-          R"(int3 tint_tmp;
+                "tint_tmp;",
+            };
+        case ValidTextureOverload::kDimensionsCubeArray:
+        case ValidTextureOverload::kDimensionsDepthCubeArray:
+            return {
+                R"(int3 tint_tmp;
   tint_symbol.GetDimensions(tint_tmp.x, tint_tmp.y, tint_tmp.z);
 )",
-          "tint_tmp.xy;",
-      };
-    case ValidTextureOverload::kDimensions2dLevel:
-    case ValidTextureOverload::kDimensionsDepth2dLevel:
-      return {
-          R"(int3 tint_tmp;
+                "tint_tmp.xy;",
+            };
+        case ValidTextureOverload::kDimensions2dLevel:
+        case ValidTextureOverload::kDimensionsDepth2dLevel:
+            return {
+                R"(int3 tint_tmp;
   tint_symbol.GetDimensions(1, tint_tmp.x, tint_tmp.y, tint_tmp.z);
 )",
-          "tint_tmp.xy;",
-      };
-    case ValidTextureOverload::kDimensions2dArrayLevel:
-    case ValidTextureOverload::kDimensionsDepth2dArrayLevel:
-      return {
-          R"(int4 tint_tmp;
+                "tint_tmp.xy;",
+            };
+        case ValidTextureOverload::kDimensions2dArrayLevel:
+        case ValidTextureOverload::kDimensionsDepth2dArrayLevel:
+            return {
+                R"(int4 tint_tmp;
   tint_symbol.GetDimensions(1, tint_tmp.x, tint_tmp.y, tint_tmp.z, tint_tmp.w);
 )",
-          "tint_tmp.xy;",
-      };
-    case ValidTextureOverload::kDimensions3dLevel:
-      return {
-          R"(int4 tint_tmp;
+                "tint_tmp.xy;",
+            };
+        case ValidTextureOverload::kDimensions3dLevel:
+            return {
+                R"(int4 tint_tmp;
   tint_symbol.GetDimensions(1, tint_tmp.x, tint_tmp.y, tint_tmp.z, tint_tmp.w);
 )",
-          "tint_tmp.xyz;",
-      };
-    case ValidTextureOverload::kDimensionsCubeLevel:
-    case ValidTextureOverload::kDimensionsDepthCubeLevel:
-      return {
-          R"(int3 tint_tmp;
+                "tint_tmp.xyz;",
+            };
+        case ValidTextureOverload::kDimensionsCubeLevel:
+        case ValidTextureOverload::kDimensionsDepthCubeLevel:
+            return {
+                R"(int3 tint_tmp;
   tint_symbol.GetDimensions(1, tint_tmp.x, tint_tmp.y, tint_tmp.z);
 )",
-          "tint_tmp.xy;",
-      };
-    case ValidTextureOverload::kDimensionsCubeArrayLevel:
-    case ValidTextureOverload::kDimensionsDepthCubeArrayLevel:
-      return {
-          R"(int4 tint_tmp;
+                "tint_tmp.xy;",
+            };
+        case ValidTextureOverload::kDimensionsCubeArrayLevel:
+        case ValidTextureOverload::kDimensionsDepthCubeArrayLevel:
+            return {
+                R"(int4 tint_tmp;
   tint_symbol.GetDimensions(1, tint_tmp.x, tint_tmp.y, tint_tmp.z, tint_tmp.w);
 )",
-          "tint_tmp.xy;",
-      };
-    case ValidTextureOverload::kGather2dF32:
-      return R"(tint_symbol.GatherRed(tint_symbol_1, float2(1.0f, 2.0f)))";
-    case ValidTextureOverload::kGather2dOffsetF32:
-      return R"(tint_symbol.GatherRed(tint_symbol_1, float2(1.0f, 2.0f), int2(3, 4)))";
-    case ValidTextureOverload::kGather2dArrayF32:
-      return R"(tint_symbol.GatherRed(tint_symbol_1, float3(1.0f, 2.0f, float(3))))";
-    case ValidTextureOverload::kGather2dArrayOffsetF32:
-      return R"(tint_symbol.GatherRed(tint_symbol_1, float3(1.0f, 2.0f, float(3)), int2(4, 5)))";
-    case ValidTextureOverload::kGatherCubeF32:
-      return R"(tint_symbol.GatherRed(tint_symbol_1, float3(1.0f, 2.0f, 3.0f)))";
-    case ValidTextureOverload::kGatherCubeArrayF32:
-      return R"(tint_symbol.GatherRed(tint_symbol_1, float4(1.0f, 2.0f, 3.0f, float(4))))";
-    case ValidTextureOverload::kGatherDepth2dF32:
-      return R"(tint_symbol.Gather(tint_symbol_1, float2(1.0f, 2.0f)))";
-    case ValidTextureOverload::kGatherDepth2dOffsetF32:
-      return R"(tint_symbol.Gather(tint_symbol_1, float2(1.0f, 2.0f), int2(3, 4)))";
-    case ValidTextureOverload::kGatherDepth2dArrayF32:
-      return R"(tint_symbol.Gather(tint_symbol_1, float3(1.0f, 2.0f, float(3))))";
-    case ValidTextureOverload::kGatherDepth2dArrayOffsetF32:
-      return R"(tint_symbol.Gather(tint_symbol_1, float3(1.0f, 2.0f, float(3)), int2(4, 5)))";
-    case ValidTextureOverload::kGatherDepthCubeF32:
-      return R"(tint_symbol.Gather(tint_symbol_1, float3(1.0f, 2.0f, 3.0f)))";
-    case ValidTextureOverload::kGatherDepthCubeArrayF32:
-      return R"(tint_symbol.Gather(tint_symbol_1, float4(1.0f, 2.0f, 3.0f, float(4))))";
-    case ValidTextureOverload::kGatherCompareDepth2dF32:
-      return R"(tint_symbol.GatherCmp(tint_symbol_1, float2(1.0f, 2.0f), 3.0f))";
-    case ValidTextureOverload::kGatherCompareDepth2dOffsetF32:
-      return R"(tint_symbol.GatherCmp(tint_symbol_1, float2(1.0f, 2.0f), 3.0f, int2(4, 5)))";
-    case ValidTextureOverload::kGatherCompareDepth2dArrayF32:
-      return R"(tint_symbol.GatherCmp(tint_symbol_1, float3(1.0f, 2.0f, float(3)), 4.0f))";
-    case ValidTextureOverload::kGatherCompareDepth2dArrayOffsetF32:
-      return R"(tint_symbol.GatherCmp(tint_symbol_1, float3(1.0f, 2.0f, float(3)), 4.0f, int2(5, 6)))";
-    case ValidTextureOverload::kGatherCompareDepthCubeF32:
-      return R"(tint_symbol.GatherCmp(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), 4.0f))";
-    case ValidTextureOverload::kGatherCompareDepthCubeArrayF32:
-      return R"(tint_symbol.GatherCmp(tint_symbol_1, float4(1.0f, 2.0f, 3.0f, float(4)), 5.0f))";
-    case ValidTextureOverload::kNumLayers2dArray:
-    case ValidTextureOverload::kNumLayersDepth2dArray:
-    case ValidTextureOverload::kNumLayersCubeArray:
-    case ValidTextureOverload::kNumLayersDepthCubeArray:
-    case ValidTextureOverload::kNumLayersStorageWO2dArray:
-      return {
-          R"(int3 tint_tmp;
+                "tint_tmp.xy;",
+            };
+        case ValidTextureOverload::kGather2dF32:
+            return R"(tint_symbol.GatherRed(tint_symbol_1, float2(1.0f, 2.0f)))";
+        case ValidTextureOverload::kGather2dOffsetF32:
+            return R"(tint_symbol.GatherRed(tint_symbol_1, float2(1.0f, 2.0f), int2(3, 4)))";
+        case ValidTextureOverload::kGather2dArrayF32:
+            return R"(tint_symbol.GatherRed(tint_symbol_1, float3(1.0f, 2.0f, float(3))))";
+        case ValidTextureOverload::kGather2dArrayOffsetF32:
+            return R"(tint_symbol.GatherRed(tint_symbol_1, float3(1.0f, 2.0f, float(3)), int2(4, 5)))";
+        case ValidTextureOverload::kGatherCubeF32:
+            return R"(tint_symbol.GatherRed(tint_symbol_1, float3(1.0f, 2.0f, 3.0f)))";
+        case ValidTextureOverload::kGatherCubeArrayF32:
+            return R"(tint_symbol.GatherRed(tint_symbol_1, float4(1.0f, 2.0f, 3.0f, float(4))))";
+        case ValidTextureOverload::kGatherDepth2dF32:
+            return R"(tint_symbol.Gather(tint_symbol_1, float2(1.0f, 2.0f)))";
+        case ValidTextureOverload::kGatherDepth2dOffsetF32:
+            return R"(tint_symbol.Gather(tint_symbol_1, float2(1.0f, 2.0f), int2(3, 4)))";
+        case ValidTextureOverload::kGatherDepth2dArrayF32:
+            return R"(tint_symbol.Gather(tint_symbol_1, float3(1.0f, 2.0f, float(3))))";
+        case ValidTextureOverload::kGatherDepth2dArrayOffsetF32:
+            return R"(tint_symbol.Gather(tint_symbol_1, float3(1.0f, 2.0f, float(3)), int2(4, 5)))";
+        case ValidTextureOverload::kGatherDepthCubeF32:
+            return R"(tint_symbol.Gather(tint_symbol_1, float3(1.0f, 2.0f, 3.0f)))";
+        case ValidTextureOverload::kGatherDepthCubeArrayF32:
+            return R"(tint_symbol.Gather(tint_symbol_1, float4(1.0f, 2.0f, 3.0f, float(4))))";
+        case ValidTextureOverload::kGatherCompareDepth2dF32:
+            return R"(tint_symbol.GatherCmp(tint_symbol_1, float2(1.0f, 2.0f), 3.0f))";
+        case ValidTextureOverload::kGatherCompareDepth2dOffsetF32:
+            return R"(tint_symbol.GatherCmp(tint_symbol_1, float2(1.0f, 2.0f), 3.0f, int2(4, 5)))";
+        case ValidTextureOverload::kGatherCompareDepth2dArrayF32:
+            return R"(tint_symbol.GatherCmp(tint_symbol_1, float3(1.0f, 2.0f, float(3)), 4.0f))";
+        case ValidTextureOverload::kGatherCompareDepth2dArrayOffsetF32:
+            return R"(tint_symbol.GatherCmp(tint_symbol_1, float3(1.0f, 2.0f, float(3)), 4.0f, int2(5, 6)))";
+        case ValidTextureOverload::kGatherCompareDepthCubeF32:
+            return R"(tint_symbol.GatherCmp(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), 4.0f))";
+        case ValidTextureOverload::kGatherCompareDepthCubeArrayF32:
+            return R"(tint_symbol.GatherCmp(tint_symbol_1, float4(1.0f, 2.0f, 3.0f, float(4)), 5.0f))";
+        case ValidTextureOverload::kNumLayers2dArray:
+        case ValidTextureOverload::kNumLayersDepth2dArray:
+        case ValidTextureOverload::kNumLayersCubeArray:
+        case ValidTextureOverload::kNumLayersDepthCubeArray:
+        case ValidTextureOverload::kNumLayersStorageWO2dArray:
+            return {
+                R"(int3 tint_tmp;
   tint_symbol.GetDimensions(tint_tmp.x, tint_tmp.y, tint_tmp.z);
 )",
-          "tint_tmp.z;",
-      };
-    case ValidTextureOverload::kNumLevels2d:
-    case ValidTextureOverload::kNumLevelsCube:
-    case ValidTextureOverload::kNumLevelsDepth2d:
-    case ValidTextureOverload::kNumLevelsDepthCube:
-      return {
-          R"(int3 tint_tmp;
+                "tint_tmp.z;",
+            };
+        case ValidTextureOverload::kNumLevels2d:
+        case ValidTextureOverload::kNumLevelsCube:
+        case ValidTextureOverload::kNumLevelsDepth2d:
+        case ValidTextureOverload::kNumLevelsDepthCube:
+            return {
+                R"(int3 tint_tmp;
   tint_symbol.GetDimensions(0, tint_tmp.x, tint_tmp.y, tint_tmp.z);
 )",
-          "tint_tmp.z;",
-      };
-    case ValidTextureOverload::kNumLevels2dArray:
-    case ValidTextureOverload::kNumLevels3d:
-    case ValidTextureOverload::kNumLevelsCubeArray:
-    case ValidTextureOverload::kNumLevelsDepth2dArray:
-    case ValidTextureOverload::kNumLevelsDepthCubeArray:
-      return {
-          R"(int4 tint_tmp;
+                "tint_tmp.z;",
+            };
+        case ValidTextureOverload::kNumLevels2dArray:
+        case ValidTextureOverload::kNumLevels3d:
+        case ValidTextureOverload::kNumLevelsCubeArray:
+        case ValidTextureOverload::kNumLevelsDepth2dArray:
+        case ValidTextureOverload::kNumLevelsDepthCubeArray:
+            return {
+                R"(int4 tint_tmp;
   tint_symbol.GetDimensions(0, tint_tmp.x, tint_tmp.y, tint_tmp.z, tint_tmp.w);
 )",
-          "tint_tmp.w;",
-      };
-    case ValidTextureOverload::kNumSamplesDepthMultisampled2d:
-    case ValidTextureOverload::kNumSamplesMultisampled2d:
-      return {
-          R"(int3 tint_tmp;
+                "tint_tmp.w;",
+            };
+        case ValidTextureOverload::kNumSamplesDepthMultisampled2d:
+        case ValidTextureOverload::kNumSamplesMultisampled2d:
+            return {
+                R"(int3 tint_tmp;
   tint_symbol.GetDimensions(tint_tmp.x, tint_tmp.y, tint_tmp.z);
 )",
-          "tint_tmp.z;",
-      };
-    case ValidTextureOverload::kSample1dF32:
-      return R"(tint_symbol.Sample(tint_symbol_1, 1.0f);)";
-    case ValidTextureOverload::kSample2dF32:
-      return R"(tint_symbol.Sample(tint_symbol_1, float2(1.0f, 2.0f));)";
-    case ValidTextureOverload::kSample2dOffsetF32:
-      return R"(tint_symbol.Sample(tint_symbol_1, float2(1.0f, 2.0f), int2(3, 4));)";
-    case ValidTextureOverload::kSample2dArrayF32:
-      return R"(tint_symbol.Sample(tint_symbol_1, float3(1.0f, 2.0f, float(3)));)";
-    case ValidTextureOverload::kSample2dArrayOffsetF32:
-      return R"(tint_symbol.Sample(tint_symbol_1, float3(1.0f, 2.0f, float(3)), int2(4, 5));)";
-    case ValidTextureOverload::kSample3dF32:
-      return R"(tint_symbol.Sample(tint_symbol_1, float3(1.0f, 2.0f, 3.0f));)";
-    case ValidTextureOverload::kSample3dOffsetF32:
-      return R"(tint_symbol.Sample(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), int3(4, 5, 6));)";
-    case ValidTextureOverload::kSampleCubeF32:
-      return R"(tint_symbol.Sample(tint_symbol_1, float3(1.0f, 2.0f, 3.0f));)";
-    case ValidTextureOverload::kSampleCubeArrayF32:
-      return R"(tint_symbol.Sample(tint_symbol_1, float4(1.0f, 2.0f, 3.0f, float(4)));)";
-    case ValidTextureOverload::kSampleDepth2dF32:
-      return R"(tint_symbol.Sample(tint_symbol_1, float2(1.0f, 2.0f)).x;)";
-    case ValidTextureOverload::kSampleDepth2dOffsetF32:
-      return R"(tint_symbol.Sample(tint_symbol_1, float2(1.0f, 2.0f), int2(3, 4)).x;)";
-    case ValidTextureOverload::kSampleDepth2dArrayF32:
-      return R"(tint_symbol.Sample(tint_symbol_1, float3(1.0f, 2.0f, float(3))).x;)";
-    case ValidTextureOverload::kSampleDepth2dArrayOffsetF32:
-      return R"(tint_symbol.Sample(tint_symbol_1, float3(1.0f, 2.0f, float(3)), int2(4, 5)).x;)";
-    case ValidTextureOverload::kSampleDepthCubeF32:
-      return R"(tint_symbol.Sample(tint_symbol_1, float3(1.0f, 2.0f, 3.0f)).x;)";
-    case ValidTextureOverload::kSampleDepthCubeArrayF32:
-      return R"(tint_symbol.Sample(tint_symbol_1, float4(1.0f, 2.0f, 3.0f, float(4))).x;)";
-    case ValidTextureOverload::kSampleBias2dF32:
-      return R"(tint_symbol.SampleBias(tint_symbol_1, float2(1.0f, 2.0f), 3.0f);)";
-    case ValidTextureOverload::kSampleBias2dOffsetF32:
-      return R"(tint_symbol.SampleBias(tint_symbol_1, float2(1.0f, 2.0f), 3.0f, int2(4, 5));)";
-    case ValidTextureOverload::kSampleBias2dArrayF32:
-      return R"(tint_symbol.SampleBias(tint_symbol_1, float3(1.0f, 2.0f, float(4)), 3.0f);)";
-    case ValidTextureOverload::kSampleBias2dArrayOffsetF32:
-      return R"(tint_symbol.SampleBias(tint_symbol_1, float3(1.0f, 2.0f, float(3)), 4.0f, int2(5, 6));)";
-    case ValidTextureOverload::kSampleBias3dF32:
-      return R"(tint_symbol.SampleBias(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), 4.0f);)";
-    case ValidTextureOverload::kSampleBias3dOffsetF32:
-      return R"(tint_symbol.SampleBias(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), 4.0f, int3(5, 6, 7));)";
-    case ValidTextureOverload::kSampleBiasCubeF32:
-      return R"(tint_symbol.SampleBias(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), 4.0f);)";
-    case ValidTextureOverload::kSampleBiasCubeArrayF32:
-      return R"(tint_symbol.SampleBias(tint_symbol_1, float4(1.0f, 2.0f, 3.0f, float(3)), 4.0f);)";
-    case ValidTextureOverload::kSampleLevel2dF32:
-      return R"(tint_symbol.SampleLevel(tint_symbol_1, float2(1.0f, 2.0f), 3.0f);)";
-    case ValidTextureOverload::kSampleLevel2dOffsetF32:
-      return R"(tint_symbol.SampleLevel(tint_symbol_1, float2(1.0f, 2.0f), 3.0f, int2(4, 5));)";
-    case ValidTextureOverload::kSampleLevel2dArrayF32:
-      return R"(tint_symbol.SampleLevel(tint_symbol_1, float3(1.0f, 2.0f, float(3)), 4.0f);)";
-    case ValidTextureOverload::kSampleLevel2dArrayOffsetF32:
-      return R"(tint_symbol.SampleLevel(tint_symbol_1, float3(1.0f, 2.0f, float(3)), 4.0f, int2(5, 6));)";
-    case ValidTextureOverload::kSampleLevel3dF32:
-      return R"(tint_symbol.SampleLevel(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), 4.0f);)";
-    case ValidTextureOverload::kSampleLevel3dOffsetF32:
-      return R"(tint_symbol.SampleLevel(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), 4.0f, int3(5, 6, 7));)";
-    case ValidTextureOverload::kSampleLevelCubeF32:
-      return R"(tint_symbol.SampleLevel(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), 4.0f);)";
-    case ValidTextureOverload::kSampleLevelCubeArrayF32:
-      return R"(tint_symbol.SampleLevel(tint_symbol_1, float4(1.0f, 2.0f, 3.0f, float(4)), 5.0f);)";
-    case ValidTextureOverload::kSampleLevelDepth2dF32:
-      return R"(tint_symbol.SampleLevel(tint_symbol_1, float2(1.0f, 2.0f), 3).x;)";
-    case ValidTextureOverload::kSampleLevelDepth2dOffsetF32:
-      return R"(tint_symbol.SampleLevel(tint_symbol_1, float2(1.0f, 2.0f), 3, int2(4, 5)).x;)";
-    case ValidTextureOverload::kSampleLevelDepth2dArrayF32:
-      return R"(tint_symbol.SampleLevel(tint_symbol_1, float3(1.0f, 2.0f, float(3)), 4).x;)";
-    case ValidTextureOverload::kSampleLevelDepth2dArrayOffsetF32:
-      return R"(tint_symbol.SampleLevel(tint_symbol_1, float3(1.0f, 2.0f, float(3)), 4, int2(5, 6)).x;)";
-    case ValidTextureOverload::kSampleLevelDepthCubeF32:
-      return R"(tint_symbol.SampleLevel(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), 4).x;)";
-    case ValidTextureOverload::kSampleLevelDepthCubeArrayF32:
-      return R"(tint_symbol.SampleLevel(tint_symbol_1, float4(1.0f, 2.0f, 3.0f, float(4)), 5).x;)";
-    case ValidTextureOverload::kSampleGrad2dF32:
-      return R"(tint_symbol.SampleGrad(tint_symbol_1, float2(1.0f, 2.0f), float2(3.0f, 4.0f), float2(5.0f, 6.0f));)";
-    case ValidTextureOverload::kSampleGrad2dOffsetF32:
-      return R"(tint_symbol.SampleGrad(tint_symbol_1, float2(1.0f, 2.0f), float2(3.0f, 4.0f), float2(5.0f, 6.0f), int2(7, 7));)";
-    case ValidTextureOverload::kSampleGrad2dArrayF32:
-      return R"(tint_symbol.SampleGrad(tint_symbol_1, float3(1.0f, 2.0f, float(3)), float2(4.0f, 5.0f), float2(6.0f, 7.0f));)";
-    case ValidTextureOverload::kSampleGrad2dArrayOffsetF32:
-      return R"(tint_symbol.SampleGrad(tint_symbol_1, float3(1.0f, 2.0f, float(3)), float2(4.0f, 5.0f), float2(6.0f, 7.0f), int2(6, 7));)";
-    case ValidTextureOverload::kSampleGrad3dF32:
-      return R"(tint_symbol.SampleGrad(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f));)";
-    case ValidTextureOverload::kSampleGrad3dOffsetF32:
-      return R"(tint_symbol.SampleGrad(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f), int3(0, 1, 2));)";
-    case ValidTextureOverload::kSampleGradCubeF32:
-      return R"(tint_symbol.SampleGrad(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f));)";
-    case ValidTextureOverload::kSampleGradCubeArrayF32:
-      return R"(tint_symbol.SampleGrad(tint_symbol_1, float4(1.0f, 2.0f, 3.0f, float(4)), float3(5.0f, 6.0f, 7.0f), float3(8.0f, 9.0f, 10.0f));)";
-    case ValidTextureOverload::kSampleCompareDepth2dF32:
-      return R"(tint_symbol.SampleCmp(tint_symbol_1, float2(1.0f, 2.0f), 3.0f);)";
-    case ValidTextureOverload::kSampleCompareDepth2dOffsetF32:
-      return R"(tint_symbol.SampleCmp(tint_symbol_1, float2(1.0f, 2.0f), 3.0f, int2(4, 5));)";
-    case ValidTextureOverload::kSampleCompareDepth2dArrayF32:
-      return R"(tint_symbol.SampleCmp(tint_symbol_1, float3(1.0f, 2.0f, float(4)), 3.0f);)";
-    case ValidTextureOverload::kSampleCompareDepth2dArrayOffsetF32:
-      return R"(tint_symbol.SampleCmp(tint_symbol_1, float3(1.0f, 2.0f, float(4)), 3.0f, int2(5, 6));)";
-    case ValidTextureOverload::kSampleCompareDepthCubeF32:
-      return R"(tint_symbol.SampleCmp(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), 4.0f);)";
-    case ValidTextureOverload::kSampleCompareDepthCubeArrayF32:
-      return R"(tint_symbol.SampleCmp(tint_symbol_1, float4(1.0f, 2.0f, 3.0f, float(4)), 5.0f);)";
-    case ValidTextureOverload::kSampleCompareLevelDepth2dF32:
-      return R"(tint_symbol.SampleCmpLevelZero(tint_symbol_1, float2(1.0f, 2.0f), 3.0f);)";
-    case ValidTextureOverload::kSampleCompareLevelDepth2dOffsetF32:
-      return R"(tint_symbol.SampleCmpLevelZero(tint_symbol_1, float2(1.0f, 2.0f), 3.0f, int2(4, 5));)";
-    case ValidTextureOverload::kSampleCompareLevelDepth2dArrayF32:
-      return R"(tint_symbol.SampleCmpLevelZero(tint_symbol_1, float3(1.0f, 2.0f, float(4)), 3.0f);)";
-    case ValidTextureOverload::kSampleCompareLevelDepth2dArrayOffsetF32:
-      return R"(tint_symbol.SampleCmpLevelZero(tint_symbol_1, float3(1.0f, 2.0f, float(4)), 3.0f, int2(5, 6));)";
-    case ValidTextureOverload::kSampleCompareLevelDepthCubeF32:
-      return R"(tint_symbol.SampleCmpLevelZero(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), 4.0f);)";
-    case ValidTextureOverload::kSampleCompareLevelDepthCubeArrayF32:
-      return R"(tint_symbol.SampleCmpLevelZero(tint_symbol_1, float4(1.0f, 2.0f, 3.0f, float(4)), 5.0f);)";
-    case ValidTextureOverload::kLoad1dLevelF32:
-    case ValidTextureOverload::kLoad1dLevelU32:
-    case ValidTextureOverload::kLoad1dLevelI32:
-      return R"(tint_symbol.Load(int2(1, 3));)";
-    case ValidTextureOverload::kLoad2dLevelF32:
-    case ValidTextureOverload::kLoad2dLevelU32:
-    case ValidTextureOverload::kLoad2dLevelI32:
-      return R"(tint_symbol.Load(int3(1, 2, 3));)";
-    case ValidTextureOverload::kLoad2dArrayLevelF32:
-    case ValidTextureOverload::kLoad2dArrayLevelU32:
-    case ValidTextureOverload::kLoad2dArrayLevelI32:
-    case ValidTextureOverload::kLoad3dLevelF32:
-    case ValidTextureOverload::kLoad3dLevelU32:
-    case ValidTextureOverload::kLoad3dLevelI32:
-      return R"(tint_symbol.Load(int4(1, 2, 3, 4));)";
-    case ValidTextureOverload::kLoadDepthMultisampled2dF32:
-    case ValidTextureOverload::kLoadMultisampled2dF32:
-    case ValidTextureOverload::kLoadMultisampled2dU32:
-    case ValidTextureOverload::kLoadMultisampled2dI32:
-      return R"(tint_symbol.Load(int2(1, 2), 3);)";
-    case ValidTextureOverload::kLoadDepth2dLevelF32:
-      return R"(tint_symbol.Load(int3(1, 2, 3)).x;)";
-    case ValidTextureOverload::kLoadDepth2dArrayLevelF32:
-      return R"(tint_symbol.Load(int4(1, 2, 3, 4)).x;)";
-    case ValidTextureOverload::kStoreWO1dRgba32float:
-      return R"(tint_symbol[1] = float4(2.0f, 3.0f, 4.0f, 5.0f);)";
-    case ValidTextureOverload::kStoreWO2dRgba32float:
-      return R"(tint_symbol[int2(1, 2)] = float4(3.0f, 4.0f, 5.0f, 6.0f);)";
-    case ValidTextureOverload::kStoreWO2dArrayRgba32float:
-      return R"(tint_symbol[int3(1, 2, 3)] = float4(4.0f, 5.0f, 6.0f, 7.0f);)";
-    case ValidTextureOverload::kStoreWO3dRgba32float:
-      return R"(tint_symbol[int3(1, 2, 3)] = float4(4.0f, 5.0f, 6.0f, 7.0f);)";
-  }
-  return "<unmatched texture overload>";
+                "tint_tmp.z;",
+            };
+        case ValidTextureOverload::kSample1dF32:
+            return R"(tint_symbol.Sample(tint_symbol_1, 1.0f);)";
+        case ValidTextureOverload::kSample2dF32:
+            return R"(tint_symbol.Sample(tint_symbol_1, float2(1.0f, 2.0f));)";
+        case ValidTextureOverload::kSample2dOffsetF32:
+            return R"(tint_symbol.Sample(tint_symbol_1, float2(1.0f, 2.0f), int2(3, 4));)";
+        case ValidTextureOverload::kSample2dArrayF32:
+            return R"(tint_symbol.Sample(tint_symbol_1, float3(1.0f, 2.0f, float(3)));)";
+        case ValidTextureOverload::kSample2dArrayOffsetF32:
+            return R"(tint_symbol.Sample(tint_symbol_1, float3(1.0f, 2.0f, float(3)), int2(4, 5));)";
+        case ValidTextureOverload::kSample3dF32:
+            return R"(tint_symbol.Sample(tint_symbol_1, float3(1.0f, 2.0f, 3.0f));)";
+        case ValidTextureOverload::kSample3dOffsetF32:
+            return R"(tint_symbol.Sample(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), int3(4, 5, 6));)";
+        case ValidTextureOverload::kSampleCubeF32:
+            return R"(tint_symbol.Sample(tint_symbol_1, float3(1.0f, 2.0f, 3.0f));)";
+        case ValidTextureOverload::kSampleCubeArrayF32:
+            return R"(tint_symbol.Sample(tint_symbol_1, float4(1.0f, 2.0f, 3.0f, float(4)));)";
+        case ValidTextureOverload::kSampleDepth2dF32:
+            return R"(tint_symbol.Sample(tint_symbol_1, float2(1.0f, 2.0f)).x;)";
+        case ValidTextureOverload::kSampleDepth2dOffsetF32:
+            return R"(tint_symbol.Sample(tint_symbol_1, float2(1.0f, 2.0f), int2(3, 4)).x;)";
+        case ValidTextureOverload::kSampleDepth2dArrayF32:
+            return R"(tint_symbol.Sample(tint_symbol_1, float3(1.0f, 2.0f, float(3))).x;)";
+        case ValidTextureOverload::kSampleDepth2dArrayOffsetF32:
+            return R"(tint_symbol.Sample(tint_symbol_1, float3(1.0f, 2.0f, float(3)), int2(4, 5)).x;)";
+        case ValidTextureOverload::kSampleDepthCubeF32:
+            return R"(tint_symbol.Sample(tint_symbol_1, float3(1.0f, 2.0f, 3.0f)).x;)";
+        case ValidTextureOverload::kSampleDepthCubeArrayF32:
+            return R"(tint_symbol.Sample(tint_symbol_1, float4(1.0f, 2.0f, 3.0f, float(4))).x;)";
+        case ValidTextureOverload::kSampleBias2dF32:
+            return R"(tint_symbol.SampleBias(tint_symbol_1, float2(1.0f, 2.0f), 3.0f);)";
+        case ValidTextureOverload::kSampleBias2dOffsetF32:
+            return R"(tint_symbol.SampleBias(tint_symbol_1, float2(1.0f, 2.0f), 3.0f, int2(4, 5));)";
+        case ValidTextureOverload::kSampleBias2dArrayF32:
+            return R"(tint_symbol.SampleBias(tint_symbol_1, float3(1.0f, 2.0f, float(4)), 3.0f);)";
+        case ValidTextureOverload::kSampleBias2dArrayOffsetF32:
+            return R"(tint_symbol.SampleBias(tint_symbol_1, float3(1.0f, 2.0f, float(3)), 4.0f, int2(5, 6));)";
+        case ValidTextureOverload::kSampleBias3dF32:
+            return R"(tint_symbol.SampleBias(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), 4.0f);)";
+        case ValidTextureOverload::kSampleBias3dOffsetF32:
+            return R"(tint_symbol.SampleBias(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), 4.0f, int3(5, 6, 7));)";
+        case ValidTextureOverload::kSampleBiasCubeF32:
+            return R"(tint_symbol.SampleBias(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), 4.0f);)";
+        case ValidTextureOverload::kSampleBiasCubeArrayF32:
+            return R"(tint_symbol.SampleBias(tint_symbol_1, float4(1.0f, 2.0f, 3.0f, float(3)), 4.0f);)";
+        case ValidTextureOverload::kSampleLevel2dF32:
+            return R"(tint_symbol.SampleLevel(tint_symbol_1, float2(1.0f, 2.0f), 3.0f);)";
+        case ValidTextureOverload::kSampleLevel2dOffsetF32:
+            return R"(tint_symbol.SampleLevel(tint_symbol_1, float2(1.0f, 2.0f), 3.0f, int2(4, 5));)";
+        case ValidTextureOverload::kSampleLevel2dArrayF32:
+            return R"(tint_symbol.SampleLevel(tint_symbol_1, float3(1.0f, 2.0f, float(3)), 4.0f);)";
+        case ValidTextureOverload::kSampleLevel2dArrayOffsetF32:
+            return R"(tint_symbol.SampleLevel(tint_symbol_1, float3(1.0f, 2.0f, float(3)), 4.0f, int2(5, 6));)";
+        case ValidTextureOverload::kSampleLevel3dF32:
+            return R"(tint_symbol.SampleLevel(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), 4.0f);)";
+        case ValidTextureOverload::kSampleLevel3dOffsetF32:
+            return R"(tint_symbol.SampleLevel(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), 4.0f, int3(5, 6, 7));)";
+        case ValidTextureOverload::kSampleLevelCubeF32:
+            return R"(tint_symbol.SampleLevel(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), 4.0f);)";
+        case ValidTextureOverload::kSampleLevelCubeArrayF32:
+            return R"(tint_symbol.SampleLevel(tint_symbol_1, float4(1.0f, 2.0f, 3.0f, float(4)), 5.0f);)";
+        case ValidTextureOverload::kSampleLevelDepth2dF32:
+            return R"(tint_symbol.SampleLevel(tint_symbol_1, float2(1.0f, 2.0f), 3).x;)";
+        case ValidTextureOverload::kSampleLevelDepth2dOffsetF32:
+            return R"(tint_symbol.SampleLevel(tint_symbol_1, float2(1.0f, 2.0f), 3, int2(4, 5)).x;)";
+        case ValidTextureOverload::kSampleLevelDepth2dArrayF32:
+            return R"(tint_symbol.SampleLevel(tint_symbol_1, float3(1.0f, 2.0f, float(3)), 4).x;)";
+        case ValidTextureOverload::kSampleLevelDepth2dArrayOffsetF32:
+            return R"(tint_symbol.SampleLevel(tint_symbol_1, float3(1.0f, 2.0f, float(3)), 4, int2(5, 6)).x;)";
+        case ValidTextureOverload::kSampleLevelDepthCubeF32:
+            return R"(tint_symbol.SampleLevel(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), 4).x;)";
+        case ValidTextureOverload::kSampleLevelDepthCubeArrayF32:
+            return R"(tint_symbol.SampleLevel(tint_symbol_1, float4(1.0f, 2.0f, 3.0f, float(4)), 5).x;)";
+        case ValidTextureOverload::kSampleGrad2dF32:
+            return R"(tint_symbol.SampleGrad(tint_symbol_1, float2(1.0f, 2.0f), float2(3.0f, 4.0f), float2(5.0f, 6.0f));)";
+        case ValidTextureOverload::kSampleGrad2dOffsetF32:
+            return R"(tint_symbol.SampleGrad(tint_symbol_1, float2(1.0f, 2.0f), float2(3.0f, 4.0f), float2(5.0f, 6.0f), int2(7, 7));)";
+        case ValidTextureOverload::kSampleGrad2dArrayF32:
+            return R"(tint_symbol.SampleGrad(tint_symbol_1, float3(1.0f, 2.0f, float(3)), float2(4.0f, 5.0f), float2(6.0f, 7.0f));)";
+        case ValidTextureOverload::kSampleGrad2dArrayOffsetF32:
+            return R"(tint_symbol.SampleGrad(tint_symbol_1, float3(1.0f, 2.0f, float(3)), float2(4.0f, 5.0f), float2(6.0f, 7.0f), int2(6, 7));)";
+        case ValidTextureOverload::kSampleGrad3dF32:
+            return R"(tint_symbol.SampleGrad(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f));)";
+        case ValidTextureOverload::kSampleGrad3dOffsetF32:
+            return R"(tint_symbol.SampleGrad(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f), int3(0, 1, 2));)";
+        case ValidTextureOverload::kSampleGradCubeF32:
+            return R"(tint_symbol.SampleGrad(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f));)";
+        case ValidTextureOverload::kSampleGradCubeArrayF32:
+            return R"(tint_symbol.SampleGrad(tint_symbol_1, float4(1.0f, 2.0f, 3.0f, float(4)), float3(5.0f, 6.0f, 7.0f), float3(8.0f, 9.0f, 10.0f));)";
+        case ValidTextureOverload::kSampleCompareDepth2dF32:
+            return R"(tint_symbol.SampleCmp(tint_symbol_1, float2(1.0f, 2.0f), 3.0f);)";
+        case ValidTextureOverload::kSampleCompareDepth2dOffsetF32:
+            return R"(tint_symbol.SampleCmp(tint_symbol_1, float2(1.0f, 2.0f), 3.0f, int2(4, 5));)";
+        case ValidTextureOverload::kSampleCompareDepth2dArrayF32:
+            return R"(tint_symbol.SampleCmp(tint_symbol_1, float3(1.0f, 2.0f, float(4)), 3.0f);)";
+        case ValidTextureOverload::kSampleCompareDepth2dArrayOffsetF32:
+            return R"(tint_symbol.SampleCmp(tint_symbol_1, float3(1.0f, 2.0f, float(4)), 3.0f, int2(5, 6));)";
+        case ValidTextureOverload::kSampleCompareDepthCubeF32:
+            return R"(tint_symbol.SampleCmp(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), 4.0f);)";
+        case ValidTextureOverload::kSampleCompareDepthCubeArrayF32:
+            return R"(tint_symbol.SampleCmp(tint_symbol_1, float4(1.0f, 2.0f, 3.0f, float(4)), 5.0f);)";
+        case ValidTextureOverload::kSampleCompareLevelDepth2dF32:
+            return R"(tint_symbol.SampleCmpLevelZero(tint_symbol_1, float2(1.0f, 2.0f), 3.0f);)";
+        case ValidTextureOverload::kSampleCompareLevelDepth2dOffsetF32:
+            return R"(tint_symbol.SampleCmpLevelZero(tint_symbol_1, float2(1.0f, 2.0f), 3.0f, int2(4, 5));)";
+        case ValidTextureOverload::kSampleCompareLevelDepth2dArrayF32:
+            return R"(tint_symbol.SampleCmpLevelZero(tint_symbol_1, float3(1.0f, 2.0f, float(4)), 3.0f);)";
+        case ValidTextureOverload::kSampleCompareLevelDepth2dArrayOffsetF32:
+            return R"(tint_symbol.SampleCmpLevelZero(tint_symbol_1, float3(1.0f, 2.0f, float(4)), 3.0f, int2(5, 6));)";
+        case ValidTextureOverload::kSampleCompareLevelDepthCubeF32:
+            return R"(tint_symbol.SampleCmpLevelZero(tint_symbol_1, float3(1.0f, 2.0f, 3.0f), 4.0f);)";
+        case ValidTextureOverload::kSampleCompareLevelDepthCubeArrayF32:
+            return R"(tint_symbol.SampleCmpLevelZero(tint_symbol_1, float4(1.0f, 2.0f, 3.0f, float(4)), 5.0f);)";
+        case ValidTextureOverload::kLoad1dLevelF32:
+        case ValidTextureOverload::kLoad1dLevelU32:
+        case ValidTextureOverload::kLoad1dLevelI32:
+            return R"(tint_symbol.Load(int2(1, 3));)";
+        case ValidTextureOverload::kLoad2dLevelF32:
+        case ValidTextureOverload::kLoad2dLevelU32:
+        case ValidTextureOverload::kLoad2dLevelI32:
+            return R"(tint_symbol.Load(int3(1, 2, 3));)";
+        case ValidTextureOverload::kLoad2dArrayLevelF32:
+        case ValidTextureOverload::kLoad2dArrayLevelU32:
+        case ValidTextureOverload::kLoad2dArrayLevelI32:
+        case ValidTextureOverload::kLoad3dLevelF32:
+        case ValidTextureOverload::kLoad3dLevelU32:
+        case ValidTextureOverload::kLoad3dLevelI32:
+            return R"(tint_symbol.Load(int4(1, 2, 3, 4));)";
+        case ValidTextureOverload::kLoadDepthMultisampled2dF32:
+        case ValidTextureOverload::kLoadMultisampled2dF32:
+        case ValidTextureOverload::kLoadMultisampled2dU32:
+        case ValidTextureOverload::kLoadMultisampled2dI32:
+            return R"(tint_symbol.Load(int2(1, 2), 3);)";
+        case ValidTextureOverload::kLoadDepth2dLevelF32:
+            return R"(tint_symbol.Load(int3(1, 2, 3)).x;)";
+        case ValidTextureOverload::kLoadDepth2dArrayLevelF32:
+            return R"(tint_symbol.Load(int4(1, 2, 3, 4)).x;)";
+        case ValidTextureOverload::kStoreWO1dRgba32float:
+            return R"(tint_symbol[1] = float4(2.0f, 3.0f, 4.0f, 5.0f);)";
+        case ValidTextureOverload::kStoreWO2dRgba32float:
+            return R"(tint_symbol[int2(1, 2)] = float4(3.0f, 4.0f, 5.0f, 6.0f);)";
+        case ValidTextureOverload::kStoreWO2dArrayRgba32float:
+            return R"(tint_symbol[int3(1, 2, 3)] = float4(4.0f, 5.0f, 6.0f, 7.0f);)";
+        case ValidTextureOverload::kStoreWO3dRgba32float:
+            return R"(tint_symbol[int3(1, 2, 3)] = float4(4.0f, 5.0f, 6.0f, 7.0f);)";
+    }
+    return "<unmatched texture overload>";
 }  // NOLINT - Ignore the length of this function
 
 class HlslGeneratorBuiltinTextureTest
     : public TestParamHelper<ast::builtin::test::TextureOverloadCase> {};
 
 TEST_P(HlslGeneratorBuiltinTextureTest, Call) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  param.BuildTextureVariable(this);
-  param.BuildSamplerVariable(this);
+    param.BuildTextureVariable(this);
+    param.BuildSamplerVariable(this);
 
-  auto* call = Call(param.function, param.args(this));
-  auto* stmt = CallStmt(call);
+    auto* call = Call(param.function, param.args(this));
+    auto* stmt = CallStmt(call);
 
-  Func("main", {}, ty.void_(), {stmt}, {Stage(ast::PipelineStage::kFragment)});
+    Func("main", {}, ty.void_(), {stmt}, {Stage(ast::PipelineStage::kFragment)});
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
+    ASSERT_TRUE(gen.Generate()) << gen.error();
 
-  auto expected = expected_texture_overload(param.overload);
+    auto expected = expected_texture_overload(param.overload);
 
-  EXPECT_THAT(gen.result(), HasSubstr(expected.pre));
-  EXPECT_THAT(gen.result(), HasSubstr(expected.out));
+    EXPECT_THAT(gen.result(), HasSubstr(expected.pre));
+    EXPECT_THAT(gen.result(), HasSubstr(expected.out));
 }
 
-INSTANTIATE_TEST_SUITE_P(
-    HlslGeneratorBuiltinTextureTest,
-    HlslGeneratorBuiltinTextureTest,
-    testing::ValuesIn(ast::builtin::test::TextureOverloadCase::ValidCases()));
+INSTANTIATE_TEST_SUITE_P(HlslGeneratorBuiltinTextureTest,
+                         HlslGeneratorBuiltinTextureTest,
+                         testing::ValuesIn(ast::builtin::test::TextureOverloadCase::ValidCases()));
 
 }  // namespace
 }  // namespace tint::writer::hlsl
diff --git a/src/tint/writer/hlsl/generator_impl_call_test.cc b/src/tint/writer/hlsl/generator_impl_call_test.cc
index 8a3289e..e905e88 100644
--- a/src/tint/writer/hlsl/generator_impl_call_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_call_test.cc
@@ -21,56 +21,56 @@
 using HlslGeneratorImplTest_Call = TestHelper;
 
 TEST_F(HlslGeneratorImplTest_Call, EmitExpression_Call_WithoutParams) {
-  Func("my_func", {}, ty.f32(), {Return(1.23f)});
+    Func("my_func", {}, ty.f32(), {Return(1.23f)});
 
-  auto* call = Call("my_func");
-  WrapInFunction(call);
+    auto* call = Call("my_func");
+    WrapInFunction(call);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
-  EXPECT_EQ(out.str(), "my_func()");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
+    EXPECT_EQ(out.str(), "my_func()");
 }
 
 TEST_F(HlslGeneratorImplTest_Call, EmitExpression_Call_WithParams) {
-  Func("my_func",
-       {
-           Param(Sym(), ty.f32()),
-           Param(Sym(), ty.f32()),
-       },
-       ty.f32(), {Return(1.23f)});
-  Global("param1", ty.f32(), ast::StorageClass::kPrivate);
-  Global("param2", ty.f32(), ast::StorageClass::kPrivate);
+    Func("my_func",
+         {
+             Param(Sym(), ty.f32()),
+             Param(Sym(), ty.f32()),
+         },
+         ty.f32(), {Return(1.23f)});
+    Global("param1", ty.f32(), ast::StorageClass::kPrivate);
+    Global("param2", ty.f32(), ast::StorageClass::kPrivate);
 
-  auto* call = Call("my_func", "param1", "param2");
-  WrapInFunction(call);
+    auto* call = Call("my_func", "param1", "param2");
+    WrapInFunction(call);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
-  EXPECT_EQ(out.str(), "my_func(param1, param2)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
+    EXPECT_EQ(out.str(), "my_func(param1, param2)");
 }
 
 TEST_F(HlslGeneratorImplTest_Call, EmitStatement_Call) {
-  Func("my_func",
-       {
-           Param(Sym(), ty.f32()),
-           Param(Sym(), ty.f32()),
-       },
-       ty.void_(), ast::StatementList{}, ast::AttributeList{});
-  Global("param1", ty.f32(), ast::StorageClass::kPrivate);
-  Global("param2", ty.f32(), ast::StorageClass::kPrivate);
+    Func("my_func",
+         {
+             Param(Sym(), ty.f32()),
+             Param(Sym(), ty.f32()),
+         },
+         ty.void_(), ast::StatementList{}, ast::AttributeList{});
+    Global("param1", ty.f32(), ast::StorageClass::kPrivate);
+    Global("param2", ty.f32(), ast::StorageClass::kPrivate);
 
-  auto* call = CallStmt(Call("my_func", "param1", "param2"));
-  WrapInFunction(call);
+    auto* call = CallStmt(Call("my_func", "param1", "param2"));
+    WrapInFunction(call);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
-  ASSERT_TRUE(gen.EmitStatement(call)) << gen.error();
-  EXPECT_EQ(gen.result(), "  my_func(param1, param2);\n");
+    gen.increment_indent();
+    ASSERT_TRUE(gen.EmitStatement(call)) << gen.error();
+    EXPECT_EQ(gen.result(), "  my_func(param1, param2);\n");
 }
 
 }  // namespace
diff --git a/src/tint/writer/hlsl/generator_impl_case_test.cc b/src/tint/writer/hlsl/generator_impl_case_test.cc
index 004ba41..ee3acfc 100644
--- a/src/tint/writer/hlsl/generator_impl_case_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_case_test.cc
@@ -15,56 +15,56 @@
 #include "src/tint/ast/fallthrough_statement.h"
 #include "src/tint/writer/hlsl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::hlsl {
 namespace {
 
 using HlslGeneratorImplTest_Case = TestHelper;
 
 TEST_F(HlslGeneratorImplTest_Case, Emit_Case) {
-  auto* s = Switch(1, Case(Expr(5), Block(create<ast::BreakStatement>())),
-                   DefaultCase());
-  WrapInFunction(s);
+    auto* s = Switch(1_i, Case(Expr(5_i), Block(create<ast::BreakStatement>())), DefaultCase());
+    WrapInFunction(s);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitCase(s, 0)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  case 5: {
+    ASSERT_TRUE(gen.EmitCase(s, 0)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  case 5: {
     break;
   }
 )");
 }
 
 TEST_F(HlslGeneratorImplTest_Case, Emit_Case_BreaksByDefault) {
-  auto* s = Switch(1, Case(Expr(5), Block()), DefaultCase());
-  WrapInFunction(s);
+    auto* s = Switch(1_i, Case(Expr(5_i), Block()), DefaultCase());
+    WrapInFunction(s);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitCase(s, 0)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  case 5: {
+    ASSERT_TRUE(gen.EmitCase(s, 0)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  case 5: {
     break;
   }
 )");
 }
 
 TEST_F(HlslGeneratorImplTest_Case, Emit_Case_WithFallthrough) {
-  auto* s =
-      Switch(1,                                                          //
-             Case(Expr(4), Block(create<ast::FallthroughStatement>())),  //
-             Case(Expr(5), Block(create<ast::ReturnStatement>())),       //
-             DefaultCase());
-  WrapInFunction(s);
+    auto* s = Switch(1_i,                                                          //
+                     Case(Expr(4_i), Block(create<ast::FallthroughStatement>())),  //
+                     Case(Expr(5_i), Block(create<ast::ReturnStatement>())),       //
+                     DefaultCase());
+    WrapInFunction(s);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitCase(s, 0)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  case 4: {
+    ASSERT_TRUE(gen.EmitCase(s, 0)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  case 4: {
     /* fallthrough */
     {
       return;
@@ -75,17 +75,16 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Case, Emit_Case_MultipleSelectors) {
-  auto* s =
-      Switch(1, Case({Expr(5), Expr(6)}, Block(create<ast::BreakStatement>())),
-             DefaultCase());
-  WrapInFunction(s);
+    auto* s = Switch(1_i, Case({Expr(5_i), Expr(6_i)}, Block(create<ast::BreakStatement>())),
+                     DefaultCase());
+    WrapInFunction(s);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitCase(s, 0)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  case 5:
+    ASSERT_TRUE(gen.EmitCase(s, 0)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  case 5:
   case 6: {
     break;
   }
@@ -93,15 +92,15 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Case, Emit_Case_Default) {
-  auto* s = Switch(1, DefaultCase(Block(create<ast::BreakStatement>())));
-  WrapInFunction(s);
+    auto* s = Switch(1_i, DefaultCase(Block(create<ast::BreakStatement>())));
+    WrapInFunction(s);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitCase(s, 0)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  default: {
+    ASSERT_TRUE(gen.EmitCase(s, 0_i)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  default: {
     break;
   }
 )");
diff --git a/src/tint/writer/hlsl/generator_impl_cast_test.cc b/src/tint/writer/hlsl/generator_impl_cast_test.cc
index 283c859..458f07d 100644
--- a/src/tint/writer/hlsl/generator_impl_cast_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_cast_test.cc
@@ -14,31 +14,33 @@
 
 #include "src/tint/writer/hlsl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::hlsl {
 namespace {
 
 using HlslGeneratorImplTest_Cast = TestHelper;
 
 TEST_F(HlslGeneratorImplTest_Cast, EmitExpression_Cast_Scalar) {
-  auto* cast = Construct<f32>(1);
-  WrapInFunction(cast);
+    auto* cast = Construct<f32>(1_i);
+    WrapInFunction(cast);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, cast)) << gen.error();
-  EXPECT_EQ(out.str(), "float(1)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, cast)) << gen.error();
+    EXPECT_EQ(out.str(), "float(1)");
 }
 
 TEST_F(HlslGeneratorImplTest_Cast, EmitExpression_Cast_Vector) {
-  auto* cast = vec3<f32>(vec3<i32>(1, 2, 3));
-  WrapInFunction(cast);
+    auto* cast = vec3<f32>(vec3<i32>(1_i, 2_i, 3_i));
+    WrapInFunction(cast);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, cast)) << gen.error();
-  EXPECT_EQ(out.str(), "float3(int3(1, 2, 3))");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, cast)) << gen.error();
+    EXPECT_EQ(out.str(), "float3(int3(1, 2, 3))");
 }
 
 }  // namespace
diff --git a/src/tint/writer/hlsl/generator_impl_constructor_test.cc b/src/tint/writer/hlsl/generator_impl_constructor_test.cc
index 8801edd..5916b0a 100644
--- a/src/tint/writer/hlsl/generator_impl_constructor_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_constructor_test.cc
@@ -15,6 +15,8 @@
 #include "gmock/gmock.h"
 #include "src/tint/writer/hlsl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::hlsl {
 namespace {
 
@@ -23,237 +25,225 @@
 using HlslGeneratorImplTest_Constructor = TestHelper;
 
 TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Bool) {
-  WrapInFunction(Expr(false));
+    WrapInFunction(Expr(false));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("false"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("false"));
 }
 
 TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Int) {
-  WrapInFunction(Expr(-12345));
+    WrapInFunction(Expr(i32(-12345)));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("-12345"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("-12345"));
 }
 
 TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_UInt) {
-  WrapInFunction(Expr(56779u));
+    WrapInFunction(Expr(56779_u));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("56779u"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("56779u"));
 }
 
 TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Float) {
-  // Use a number close to 1<<30 but whose decimal representation ends in 0.
-  WrapInFunction(Expr(static_cast<float>((1 << 30) - 4)));
+    // Use a number close to 1<<30 but whose decimal representation ends in 0.
+    WrapInFunction(Expr(f32((1 << 30) - 4)));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("1073741824.0f"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("1073741824.0f"));
 }
 
 TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Float) {
-  WrapInFunction(Construct<f32>(-1.2e-5f));
+    WrapInFunction(Construct<f32>(-1.2e-5f));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("float(-0.000012f)"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("float(-0.000012f)"));
 }
 
 TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Bool) {
-  WrapInFunction(Construct<bool>(true));
+    WrapInFunction(Construct<bool>(true));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("bool(true)"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("bool(true)"));
 }
 
 TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Int) {
-  WrapInFunction(Construct<i32>(-12345));
+    WrapInFunction(Construct<i32>(i32(-12345)));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("int(-12345)"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("int(-12345)"));
 }
 
 TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Uint) {
-  WrapInFunction(Construct<u32>(12345u));
+    WrapInFunction(Construct<u32>(12345_u));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("uint(12345u)"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("uint(12345u)"));
 }
 
 TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec) {
-  WrapInFunction(vec3<f32>(1.f, 2.f, 3.f));
+    WrapInFunction(vec3<f32>(1.f, 2.f, 3.f));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("float3(1.0f, 2.0f, 3.0f)"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("float3(1.0f, 2.0f, 3.0f)"));
 }
 
 TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_Empty) {
-  WrapInFunction(vec3<f32>());
+    WrapInFunction(vec3<f32>());
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("float3(0.0f, 0.0f, 0.0f)"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("float3(0.0f, 0.0f, 0.0f)"));
 }
 
-TEST_F(HlslGeneratorImplTest_Constructor,
-       EmitConstructor_Type_Vec_SingleScalar_Float_Literal) {
-  WrapInFunction(vec3<f32>(2.0f));
+TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_SingleScalar_Float_Literal) {
+    WrapInFunction(vec3<f32>(2.0f));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("float3((2.0f).xxx)"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("float3((2.0f).xxx)"));
 }
 
-TEST_F(HlslGeneratorImplTest_Constructor,
-       EmitConstructor_Type_Vec_SingleScalar_Float_Var) {
-  auto* var = Var("v", nullptr, Expr(2.0f));
-  auto* cast = vec3<f32>(var);
-  WrapInFunction(var, cast);
+TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_SingleScalar_Float_Var) {
+    auto* var = Var("v", nullptr, Expr(2.0f));
+    auto* cast = vec3<f32>(var);
+    WrapInFunction(var, cast);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr(R"(float v = 2.0f;
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr(R"(float v = 2.0f;
   const float3 tint_symbol = float3((v).xxx);)"));
 }
 
-TEST_F(HlslGeneratorImplTest_Constructor,
-       EmitConstructor_Type_Vec_SingleScalar_Bool_Literal) {
-  WrapInFunction(vec3<bool>(true));
+TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_SingleScalar_Bool_Literal) {
+    WrapInFunction(vec3<bool>(true));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("bool3((true).xxx)"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("bool3((true).xxx)"));
 }
 
-TEST_F(HlslGeneratorImplTest_Constructor,
-       EmitConstructor_Type_Vec_SingleScalar_Bool_Var) {
-  auto* var = Var("v", nullptr, Expr(true));
-  auto* cast = vec3<bool>(var);
-  WrapInFunction(var, cast);
+TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_SingleScalar_Bool_Var) {
+    auto* var = Var("v", nullptr, Expr(true));
+    auto* cast = vec3<bool>(var);
+    WrapInFunction(var, cast);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr(R"(bool v = true;
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr(R"(bool v = true;
   const bool3 tint_symbol = bool3((v).xxx);)"));
 }
 
-TEST_F(HlslGeneratorImplTest_Constructor,
-       EmitConstructor_Type_Vec_SingleScalar_Int) {
-  WrapInFunction(vec3<i32>(2));
+TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_SingleScalar_Int) {
+    WrapInFunction(vec3<i32>(2_i));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("int3((2).xxx)"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("int3((2).xxx)"));
 }
 
-TEST_F(HlslGeneratorImplTest_Constructor,
-       EmitConstructor_Type_Vec_SingleScalar_UInt) {
-  WrapInFunction(vec3<u32>(2u));
+TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Vec_SingleScalar_UInt) {
+    WrapInFunction(vec3<u32>(2_u));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("uint3((2u).xxx)"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("uint3((2u).xxx)"));
 }
 
 TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Mat) {
-  WrapInFunction(
-      mat2x3<f32>(vec3<f32>(1.f, 2.f, 3.f), vec3<f32>(3.f, 4.f, 5.f)));
+    WrapInFunction(mat2x3<f32>(vec3<f32>(1.f, 2.f, 3.f), vec3<f32>(3.f, 4.f, 5.f)));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
+    ASSERT_TRUE(gen.Generate()) << gen.error();
 
-  EXPECT_THAT(
-      gen.result(),
-      HasSubstr(
-          "float2x3(float3(1.0f, 2.0f, 3.0f), float3(3.0f, 4.0f, 5.0f))"));
+    EXPECT_THAT(gen.result(),
+                HasSubstr("float2x3(float3(1.0f, 2.0f, 3.0f), float3(3.0f, 4.0f, 5.0f))"));
 }
 
 TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Mat_Empty) {
-  WrapInFunction(mat2x3<f32>());
+    WrapInFunction(mat2x3<f32>());
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
+    ASSERT_TRUE(gen.Generate()) << gen.error();
 
-  EXPECT_THAT(gen.result(),
-              HasSubstr("float2x3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)"));
+    EXPECT_THAT(gen.result(), HasSubstr("float2x3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f)"));
 }
 
 TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Array) {
-  WrapInFunction(Construct(ty.array(ty.vec3<f32>(), 3),
-                           vec3<f32>(1.f, 2.f, 3.f), vec3<f32>(4.f, 5.f, 6.f),
-                           vec3<f32>(7.f, 8.f, 9.f)));
+    WrapInFunction(Construct(ty.array(ty.vec3<f32>(), 3_u), vec3<f32>(1.f, 2.f, 3.f),
+                             vec3<f32>(4.f, 5.f, 6.f), vec3<f32>(7.f, 8.f, 9.f)));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(),
-              HasSubstr("{float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f),"
-                        " float3(7.0f, 8.0f, 9.0f)}"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("{float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f),"
+                                        " float3(7.0f, 8.0f, 9.0f)}"));
 }
 
 TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Array_Empty) {
-  WrapInFunction(Construct(ty.array(ty.vec3<f32>(), 3)));
+    WrapInFunction(Construct(ty.array(ty.vec3<f32>(), 3_u)));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("(float3[3])0"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("(float3[3])0"));
 }
 
 TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Struct) {
-  auto* str = Structure("S", {
-                                 Member("a", ty.i32()),
-                                 Member("b", ty.f32()),
-                                 Member("c", ty.vec3<i32>()),
-                             });
+    auto* str = Structure("S", {
+                                   Member("a", ty.i32()),
+                                   Member("b", ty.f32()),
+                                   Member("c", ty.vec3<i32>()),
+                               });
 
-  WrapInFunction(Construct(ty.Of(str), 1, 2.0f, vec3<i32>(3, 4, 5)));
+    WrapInFunction(Construct(ty.Of(str), 1_i, 2.0f, vec3<i32>(3_i, 4_i, 5_i)));
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("{1, 2.0f, int3(3, 4, 5)}"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("{1, 2.0f, int3(3, 4, 5)}"));
 }
 
 TEST_F(HlslGeneratorImplTest_Constructor, EmitConstructor_Type_Struct_Empty) {
-  auto* str = Structure("S", {
-                                 Member("a", ty.i32()),
-                                 Member("b", ty.f32()),
-                                 Member("c", ty.vec3<i32>()),
-                             });
+    auto* str = Structure("S", {
+                                   Member("a", ty.i32()),
+                                   Member("b", ty.f32()),
+                                   Member("c", ty.vec3<i32>()),
+                               });
 
-  WrapInFunction(Construct(ty.Of(str)));
+    WrapInFunction(Construct(ty.Of(str)));
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("(S)0"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("(S)0"));
 }
 
 }  // namespace
diff --git a/src/tint/writer/hlsl/generator_impl_continue_test.cc b/src/tint/writer/hlsl/generator_impl_continue_test.cc
index 5a9e07d..c7192f6 100644
--- a/src/tint/writer/hlsl/generator_impl_continue_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_continue_test.cc
@@ -20,16 +20,16 @@
 using HlslGeneratorImplTest_Continue = TestHelper;
 
 TEST_F(HlslGeneratorImplTest_Continue, Emit_Continue) {
-  auto* loop = Loop(Block(If(false, Block(Break())),  //
-                          Continue()));
-  WrapInFunction(loop);
+    auto* loop = Loop(Block(If(false, Block(Break())),  //
+                            Continue()));
+    WrapInFunction(loop);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(loop)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  [loop] while (true) {
+    ASSERT_TRUE(gen.EmitStatement(loop)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  [loop] while (true) {
     if (false) {
       break;
     }
diff --git a/src/tint/writer/hlsl/generator_impl_discard_test.cc b/src/tint/writer/hlsl/generator_impl_discard_test.cc
index e8e52a9..4bc4bf9 100644
--- a/src/tint/writer/hlsl/generator_impl_discard_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_discard_test.cc
@@ -20,15 +20,15 @@
 using HlslGeneratorImplTest_Discard = TestHelper;
 
 TEST_F(HlslGeneratorImplTest_Discard, Emit_Discard) {
-  auto* stmt = create<ast::DiscardStatement>();
-  WrapInFunction(stmt);
+    auto* stmt = create<ast::DiscardStatement>();
+    WrapInFunction(stmt);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
-  EXPECT_EQ(gen.result(), "  discard;\n");
+    ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
+    EXPECT_EQ(gen.result(), "  discard;\n");
 }
 
 }  // namespace
diff --git a/src/tint/writer/hlsl/generator_impl_function_test.cc b/src/tint/writer/hlsl/generator_impl_function_test.cc
index 15e9e86..0525fa6 100644
--- a/src/tint/writer/hlsl/generator_impl_function_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_function_test.cc
@@ -20,107 +20,106 @@
 
 using ::testing::HasSubstr;
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::hlsl {
 namespace {
 
 using HlslGeneratorImplTest_Function = TestHelper;
 
 TEST_F(HlslGeneratorImplTest_Function, Emit_Function) {
-  Func("my_func", ast::VariableList{}, ty.void_(),
-       {
-           Return(),
-       });
+    Func("my_func", ast::VariableList{}, ty.void_(),
+         {
+             Return(),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  void my_func() {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  void my_func() {
     return;
   }
 )");
 }
 
 TEST_F(HlslGeneratorImplTest_Function, Emit_Function_Name_Collision) {
-  Func("GeometryShader", ast::VariableList{}, ty.void_(),
-       {
-           Return(),
-       });
+    Func("GeometryShader", ast::VariableList{}, ty.void_(),
+         {
+             Return(),
+         });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr(R"(  void tint_symbol() {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr(R"(  void tint_symbol() {
     return;
   })"));
 }
 
 TEST_F(HlslGeneratorImplTest_Function, Emit_Function_WithParams) {
-  Func("my_func", ast::VariableList{Param("a", ty.f32()), Param("b", ty.i32())},
-       ty.void_(),
-       {
-           Return(),
-       });
+    Func("my_func", ast::VariableList{Param("a", ty.f32()), Param("b", ty.i32())}, ty.void_(),
+         {
+             Return(),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  void my_func(float a, int b) {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  void my_func(float a, int b) {
     return;
   }
 )");
 }
 
-TEST_F(HlslGeneratorImplTest_Function,
-       Emit_Attribute_EntryPoint_NoReturn_Void) {
-  Func("main", ast::VariableList{}, ty.void_(), {/* no explicit return */},
-       {
-           Stage(ast::PipelineStage::kFragment),
-       });
+TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_NoReturn_Void) {
+    Func("main", ast::VariableList{}, ty.void_(), {/* no explicit return */},
+         {
+             Stage(ast::PipelineStage::kFragment),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(void main() {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(void main() {
   return;
 }
 )");
 }
 
 TEST_F(HlslGeneratorImplTest_Function, PtrParameter) {
-  // fn f(foo : ptr<function, f32>) -> f32 {
-  //   return *foo;
-  // }
-  Func("f", {Param("foo", ty.pointer<f32>(ast::StorageClass::kFunction))},
-       ty.f32(), {Return(Deref("foo"))});
+    // fn f(foo : ptr<function, f32>) -> f32 {
+    //   return *foo;
+    // }
+    Func("f", {Param("foo", ty.pointer<f32>(ast::StorageClass::kFunction))}, ty.f32(),
+         {Return(Deref("foo"))});
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr(R"(float f(inout float foo) {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr(R"(float f(inout float foo) {
   return foo;
 }
 )"));
 }
 
-TEST_F(HlslGeneratorImplTest_Function,
-       Emit_Attribute_EntryPoint_WithInOutVars) {
-  // fn frag_main(@location(0) foo : f32) -> @location(1) f32 {
-  //   return foo;
-  // }
-  auto* foo_in = Param("foo", ty.f32(), {Location(0)});
-  Func("frag_main", ast::VariableList{foo_in}, ty.f32(), {Return("foo")},
-       {Stage(ast::PipelineStage::kFragment)}, {Location(1)});
+TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_WithInOutVars) {
+    // fn frag_main(@location(0) foo : f32) -> @location(1) f32 {
+    //   return foo;
+    // }
+    auto* foo_in = Param("foo", ty.f32(), {Location(0)});
+    Func("frag_main", ast::VariableList{foo_in}, ty.f32(), {Return("foo")},
+         {Stage(ast::PipelineStage::kFragment)}, {Location(1)});
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(struct tint_symbol_1 {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(struct tint_symbol_1 {
   float foo : TEXCOORD0;
 };
 struct tint_symbol_2 {
@@ -140,22 +139,18 @@
 )");
 }
 
-TEST_F(HlslGeneratorImplTest_Function,
-       Emit_Attribute_EntryPoint_WithInOut_Builtins) {
-  // 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)});
-  Func("frag_main", ast::VariableList{coord_in}, ty.f32(),
-       {Return(MemberAccessor("coord", "x"))},
-       {Stage(ast::PipelineStage::kFragment)},
-       {Builtin(ast::Builtin::kFragDepth)});
+TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_WithInOut_Builtins) {
+    // 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)});
+    Func("frag_main", ast::VariableList{coord_in}, ty.f32(), {Return(MemberAccessor("coord", "x"))},
+         {Stage(ast::PipelineStage::kFragment)}, {Builtin(ast::Builtin::kFragDepth)});
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(struct tint_symbol_1 {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(struct tint_symbol_1 {
   float4 coord : SV_Position;
 };
 struct tint_symbol_2 {
@@ -175,46 +170,44 @@
 )");
 }
 
-TEST_F(HlslGeneratorImplTest_Function,
-       Emit_Attribute_EntryPoint_SharedStruct_DifferentStages) {
-  // struct Interface {
-  //   @builtin(position) pos : vec4<f32>;
-  //   @location(1) col1 : f32;
-  //   @location(2) col2 : f32;
-  // };
-  // fn vert_main() -> Interface {
-  //   return Interface(vec4<f32>(), 0.4, 0.6);
-  // }
-  // fn frag_main(inputs : Interface) {
-  //   const r = inputs.col1;
-  //   const g = inputs.col2;
-  //   const p = inputs.pos;
-  // }
-  auto* interface_struct = Structure(
-      "Interface",
-      {
-          Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)}),
-          Member("col1", ty.f32(), {Location(1)}),
-          Member("col2", ty.f32(), {Location(2)}),
-      });
+TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_SharedStruct_DifferentStages) {
+    // struct Interface {
+    //   @builtin(position) pos : vec4<f32>;
+    //   @location(1) col1 : f32;
+    //   @location(2) col2 : f32;
+    // };
+    // fn vert_main() -> Interface {
+    //   return Interface(vec4<f32>(), 0.4, 0.6);
+    // }
+    // fn frag_main(inputs : Interface) {
+    //   const r = inputs.col1;
+    //   const g = inputs.col2;
+    //   const p = inputs.pos;
+    // }
+    auto* interface_struct = Structure(
+        "Interface", {
+                         Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)}),
+                         Member("col1", ty.f32(), {Location(1)}),
+                         Member("col2", ty.f32(), {Location(2)}),
+                     });
 
-  Func("vert_main", {}, ty.Of(interface_struct),
-       {Return(Construct(ty.Of(interface_struct), Construct(ty.vec4<f32>()),
-                         Expr(0.5f), Expr(0.25f)))},
-       {Stage(ast::PipelineStage::kVertex)});
+    Func("vert_main", {}, ty.Of(interface_struct),
+         {Return(Construct(ty.Of(interface_struct), Construct(ty.vec4<f32>()), Expr(0.5f),
+                           Expr(0.25f)))},
+         {Stage(ast::PipelineStage::kVertex)});
 
-  Func("frag_main", {Param("inputs", ty.Of(interface_struct))}, ty.void_(),
-       {
-           Decl(Const("r", ty.f32(), MemberAccessor("inputs", "col1"))),
-           Decl(Const("g", ty.f32(), MemberAccessor("inputs", "col2"))),
-           Decl(Const("p", ty.vec4<f32>(), MemberAccessor("inputs", "pos"))),
-       },
-       {Stage(ast::PipelineStage::kFragment)});
+    Func("frag_main", {Param("inputs", ty.Of(interface_struct))}, ty.void_(),
+         {
+             Decl(Let("r", ty.f32(), MemberAccessor("inputs", "col1"))),
+             Decl(Let("g", ty.f32(), MemberAccessor("inputs", "col2"))),
+             Decl(Let("p", ty.vec4<f32>(), MemberAccessor("inputs", "pos"))),
+         },
+         {Stage(ast::PipelineStage::kFragment)});
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(struct Interface {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(struct Interface {
   float4 pos;
   float col1;
   float col2;
@@ -259,40 +252,37 @@
 )");
 }
 
-TEST_F(HlslGeneratorImplTest_Function,
-       Emit_Attribute_EntryPoint_SharedStruct_HelperFunction) {
-  // struct VertexOutput {
-  //   @builtin(position) pos : vec4<f32>;
-  // };
-  // fn foo(x : f32) -> VertexOutput {
-  //   return VertexOutput(vec4<f32>(x, x, x, 1.0));
-  // }
-  // fn vert_main1() -> VertexOutput {
-  //   return foo(0.5);
-  // }
-  // fn vert_main2() -> VertexOutput {
-  //   return foo(0.25);
-  // }
-  auto* vertex_output_struct = Structure(
-      "VertexOutput",
-      {Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)})});
+TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_SharedStruct_HelperFunction) {
+    // struct VertexOutput {
+    //   @builtin(position) pos : vec4<f32>;
+    // };
+    // fn foo(x : f32) -> VertexOutput {
+    //   return VertexOutput(vec4<f32>(x, x, x, 1.0));
+    // }
+    // fn vert_main1() -> VertexOutput {
+    //   return foo(0.5);
+    // }
+    // fn vert_main2() -> VertexOutput {
+    //   return foo(0.25);
+    // }
+    auto* vertex_output_struct = Structure(
+        "VertexOutput", {Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)})});
 
-  Func("foo", {Param("x", ty.f32())}, ty.Of(vertex_output_struct),
-       {Return(Construct(ty.Of(vertex_output_struct),
-                         Construct(ty.vec4<f32>(), "x", "x", "x", Expr(1.f))))},
-       {});
+    Func("foo", {Param("x", ty.f32())}, ty.Of(vertex_output_struct),
+         {Return(Construct(ty.Of(vertex_output_struct),
+                           Construct(ty.vec4<f32>(), "x", "x", "x", Expr(1.f))))},
+         {});
 
-  Func("vert_main1", {}, ty.Of(vertex_output_struct),
-       {Return(Call("foo", Expr(0.5f)))}, {Stage(ast::PipelineStage::kVertex)});
+    Func("vert_main1", {}, ty.Of(vertex_output_struct), {Return(Call("foo", Expr(0.5f)))},
+         {Stage(ast::PipelineStage::kVertex)});
 
-  Func("vert_main2", {}, ty.Of(vertex_output_struct),
-       {Return(Call("foo", Expr(0.25f)))},
-       {Stage(ast::PipelineStage::kVertex)});
+    Func("vert_main2", {}, ty.Of(vertex_output_struct), {Return(Call("foo", Expr(0.25f)))},
+         {Stage(ast::PipelineStage::kVertex)});
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(struct VertexOutput {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(struct VertexOutput {
   float4 pos;
 };
 
@@ -334,38 +324,37 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_With_Uniform) {
-  auto* ubo_ty = Structure("UBO", {Member("coord", ty.vec4<f32>())});
-  auto* ubo = Global("ubo", ty.Of(ubo_ty), ast::StorageClass::kUniform,
-                     ast::AttributeList{
-                         create<ast::BindingAttribute>(0),
-                         create<ast::GroupAttribute>(1),
-                     });
+    auto* ubo_ty = Structure("UBO", {Member("coord", ty.vec4<f32>())});
+    auto* ubo = Global("ubo", ty.Of(ubo_ty), ast::StorageClass::kUniform,
+                       ast::AttributeList{
+                           create<ast::BindingAttribute>(0),
+                           create<ast::GroupAttribute>(1),
+                       });
 
-  Func("sub_func",
-       {
-           Param("param", ty.f32()),
-       },
-       ty.f32(),
-       {
-           Return(MemberAccessor(MemberAccessor(ubo, "coord"), "x")),
-       });
+    Func("sub_func",
+         {
+             Param("param", ty.f32()),
+         },
+         ty.f32(),
+         {
+             Return(MemberAccessor(MemberAccessor(ubo, "coord"), "x")),
+         });
 
-  auto* var =
-      Var("v", ty.f32(), ast::StorageClass::kNone, Call("sub_func", 1.0f));
+    auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, Call("sub_func", 1.0f));
 
-  Func("frag_main", {}, ty.void_(),
-       {
-           Decl(var),
-           Return(),
-       },
-       {
-           Stage(ast::PipelineStage::kFragment),
-       });
+    Func("frag_main", {}, ty.void_(),
+         {
+             Decl(var),
+             Return(),
+         },
+         {
+             Stage(ast::PipelineStage::kFragment),
+         });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(cbuffer cbuffer_ubo : register(b0, space1) {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(cbuffer cbuffer_ubo : register(b0, space1) {
   uint4 ubo[1];
 };
 
@@ -380,32 +369,31 @@
 )");
 }
 
-TEST_F(HlslGeneratorImplTest_Function,
-       Emit_Attribute_EntryPoint_With_UniformStruct) {
-  auto* s = Structure("Uniforms", {Member("coord", ty.vec4<f32>())});
+TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_With_UniformStruct) {
+    auto* s = Structure("Uniforms", {Member("coord", ty.vec4<f32>())});
 
-  Global("uniforms", ty.Of(s), ast::StorageClass::kUniform,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(1),
+    Global("uniforms", ty.Of(s), ast::StorageClass::kUniform,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(1),
+           });
+
+    auto* var = Var("v", ty.f32(), ast::StorageClass::kNone,
+                    MemberAccessor(MemberAccessor("uniforms", "coord"), "x"));
+
+    Func("frag_main", ast::VariableList{}, ty.void_(),
+         {
+             Decl(var),
+             Return(),
+         },
+         {
+             Stage(ast::PipelineStage::kFragment),
          });
 
-  auto* var = Var("v", ty.f32(), ast::StorageClass::kNone,
-                  MemberAccessor(MemberAccessor("uniforms", "coord"), "x"));
+    GeneratorImpl& gen = Build();
 
-  Func("frag_main", ast::VariableList{}, ty.void_(),
-       {
-           Decl(var),
-           Return(),
-       },
-       {
-           Stage(ast::PipelineStage::kFragment),
-       });
-
-  GeneratorImpl& gen = Build();
-
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(cbuffer cbuffer_uniforms : register(b0, space1) {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(cbuffer cbuffer_uniforms : register(b0, space1) {
   uint4 uniforms[1];
 };
 
@@ -416,37 +404,34 @@
 )");
 }
 
-TEST_F(HlslGeneratorImplTest_Function,
-       Emit_Attribute_EntryPoint_With_RW_StorageBuffer_Read) {
-  auto* s = Structure("Data", {
-                                  Member("a", ty.i32()),
-                                  Member("b", ty.f32()),
-                              });
+TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_With_RW_StorageBuffer_Read) {
+    auto* s = Structure("Data", {
+                                    Member("a", ty.i32()),
+                                    Member("b", ty.f32()),
+                                });
 
-  Global("coord", ty.Of(s), ast::StorageClass::kStorage,
-         ast::Access::kReadWrite,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(1),
+    Global("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(1),
+           });
+
+    auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, MemberAccessor("coord", "b"));
+
+    Func("frag_main", ast::VariableList{}, ty.void_(),
+         {
+             Decl(var),
+             Return(),
+         },
+         {
+             Stage(ast::PipelineStage::kFragment),
          });
 
-  auto* var = Var("v", ty.f32(), ast::StorageClass::kNone,
-                  MemberAccessor("coord", "b"));
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  Func("frag_main", ast::VariableList{}, ty.void_(),
-       {
-           Decl(var),
-           Return(),
-       },
-       {
-           Stage(ast::PipelineStage::kFragment),
-       });
-
-  GeneratorImpl& gen = SanitizeAndBuild();
-
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(),
-            R"(RWByteAddressBuffer coord : register(u0, space1);
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(),
+              R"(RWByteAddressBuffer coord : register(u0, space1);
 
 void frag_main() {
   float v = asfloat(coord.Load(4u));
@@ -455,36 +440,34 @@
 )");
 }
 
-TEST_F(HlslGeneratorImplTest_Function,
-       Emit_Attribute_EntryPoint_With_RO_StorageBuffer_Read) {
-  auto* s = Structure("Data", {
-                                  Member("a", ty.i32()),
-                                  Member("b", ty.f32()),
-                              });
+TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_With_RO_StorageBuffer_Read) {
+    auto* s = Structure("Data", {
+                                    Member("a", ty.i32()),
+                                    Member("b", ty.f32()),
+                                });
 
-  Global("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(1),
+    Global("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(1),
+           });
+
+    auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, MemberAccessor("coord", "b"));
+
+    Func("frag_main", ast::VariableList{}, ty.void_(),
+         {
+             Decl(var),
+             Return(),
+         },
+         {
+             Stage(ast::PipelineStage::kFragment),
          });
 
-  auto* var = Var("v", ty.f32(), ast::StorageClass::kNone,
-                  MemberAccessor("coord", "b"));
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  Func("frag_main", ast::VariableList{}, ty.void_(),
-       {
-           Decl(var),
-           Return(),
-       },
-       {
-           Stage(ast::PipelineStage::kFragment),
-       });
-
-  GeneratorImpl& gen = SanitizeAndBuild();
-
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(),
-            R"(ByteAddressBuffer coord : register(t0, space1);
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(),
+              R"(ByteAddressBuffer coord : register(t0, space1);
 
 void frag_main() {
   float v = asfloat(coord.Load(4u));
@@ -493,33 +476,32 @@
 )");
 }
 
-TEST_F(HlslGeneratorImplTest_Function,
-       Emit_Attribute_EntryPoint_With_WO_StorageBuffer_Store) {
-  auto* s = Structure("Data", {
-                                  Member("a", ty.i32()),
-                                  Member("b", ty.f32()),
-                              });
+TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_With_WO_StorageBuffer_Store) {
+    auto* s = Structure("Data", {
+                                    Member("a", ty.i32()),
+                                    Member("b", ty.f32()),
+                                });
 
-  Global("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kWrite,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(1),
+    Global("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kWrite,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(1),
+           });
+
+    Func("frag_main", ast::VariableList{}, ty.void_(),
+         {
+             Assign(MemberAccessor("coord", "b"), Expr(2.0f)),
+             Return(),
+         },
+         {
+             Stage(ast::PipelineStage::kFragment),
          });
 
-  Func("frag_main", ast::VariableList{}, ty.void_(),
-       {
-           Assign(MemberAccessor("coord", "b"), Expr(2.0f)),
-           Return(),
-       },
-       {
-           Stage(ast::PipelineStage::kFragment),
-       });
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  GeneratorImpl& gen = SanitizeAndBuild();
-
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(),
-            R"(RWByteAddressBuffer coord : register(u0, space1);
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(),
+              R"(RWByteAddressBuffer coord : register(u0, space1);
 
 void frag_main() {
   coord.Store(4u, asuint(2.0f));
@@ -528,34 +510,32 @@
 )");
 }
 
-TEST_F(HlslGeneratorImplTest_Function,
-       Emit_Attribute_EntryPoint_With_StorageBuffer_Store) {
-  auto* s = Structure("Data", {
-                                  Member("a", ty.i32()),
-                                  Member("b", ty.f32()),
-                              });
+TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_With_StorageBuffer_Store) {
+    auto* s = Structure("Data", {
+                                    Member("a", ty.i32()),
+                                    Member("b", ty.f32()),
+                                });
 
-  Global("coord", ty.Of(s), ast::StorageClass::kStorage,
-         ast::Access::kReadWrite,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(1),
+    Global("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(1),
+           });
+
+    Func("frag_main", ast::VariableList{}, ty.void_(),
+         {
+             Assign(MemberAccessor("coord", "b"), Expr(2.0f)),
+             Return(),
+         },
+         {
+             Stage(ast::PipelineStage::kFragment),
          });
 
-  Func("frag_main", ast::VariableList{}, ty.void_(),
-       {
-           Assign(MemberAccessor("coord", "b"), Expr(2.0f)),
-           Return(),
-       },
-       {
-           Stage(ast::PipelineStage::kFragment),
-       });
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  GeneratorImpl& gen = SanitizeAndBuild();
-
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(),
-            R"(RWByteAddressBuffer coord : register(u0, space1);
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(),
+              R"(RWByteAddressBuffer coord : register(u0, space1);
 
 void frag_main() {
   coord.Store(4u, asuint(2.0f));
@@ -564,36 +544,34 @@
 )");
 }
 
-TEST_F(HlslGeneratorImplTest_Function,
-       Emit_Attribute_Called_By_EntryPoint_With_Uniform) {
-  auto* s = Structure("S", {Member("x", ty.f32())});
-  Global("coord", ty.Of(s), ast::StorageClass::kUniform,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(1),
+TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_Called_By_EntryPoint_With_Uniform) {
+    auto* s = Structure("S", {Member("x", ty.f32())});
+    Global("coord", ty.Of(s), ast::StorageClass::kUniform,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(1),
+           });
+
+    Func("sub_func", ast::VariableList{Param("param", ty.f32())}, ty.f32(),
+         {
+             Return(MemberAccessor("coord", "x")),
          });
 
-  Func("sub_func", ast::VariableList{Param("param", ty.f32())}, ty.f32(),
-       {
-           Return(MemberAccessor("coord", "x")),
-       });
+    auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, Call("sub_func", 1.0f));
 
-  auto* var =
-      Var("v", ty.f32(), ast::StorageClass::kNone, Call("sub_func", 1.0f));
+    Func("frag_main", ast::VariableList{}, ty.void_(),
+         {
+             Decl(var),
+             Return(),
+         },
+         {
+             Stage(ast::PipelineStage::kFragment),
+         });
 
-  Func("frag_main", ast::VariableList{}, ty.void_(),
-       {
-           Decl(var),
-           Return(),
-       },
-       {
-           Stage(ast::PipelineStage::kFragment),
-       });
+    GeneratorImpl& gen = Build();
 
-  GeneratorImpl& gen = Build();
-
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(cbuffer cbuffer_coord : register(b0, space1) {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(cbuffer cbuffer_coord : register(b0, space1) {
   uint4 coord[1];
 };
 
@@ -608,38 +586,35 @@
 )");
 }
 
-TEST_F(HlslGeneratorImplTest_Function,
-       Emit_Attribute_Called_By_EntryPoint_With_StorageBuffer) {
-  auto* s = Structure("S", {Member("x", ty.f32())});
-  Global("coord", ty.Of(s), ast::StorageClass::kStorage,
-         ast::Access::kReadWrite,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(1),
+TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_Called_By_EntryPoint_With_StorageBuffer) {
+    auto* s = Structure("S", {Member("x", ty.f32())});
+    Global("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(1),
+           });
+
+    Func("sub_func", ast::VariableList{Param("param", ty.f32())}, ty.f32(),
+         {
+             Return(MemberAccessor("coord", "x")),
          });
 
-  Func("sub_func", ast::VariableList{Param("param", ty.f32())}, ty.f32(),
-       {
-           Return(MemberAccessor("coord", "x")),
-       });
+    auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, Call("sub_func", 1.0f));
 
-  auto* var =
-      Var("v", ty.f32(), ast::StorageClass::kNone, Call("sub_func", 1.0f));
+    Func("frag_main", ast::VariableList{}, ty.void_(),
+         {
+             Decl(var),
+             Return(),
+         },
+         {
+             Stage(ast::PipelineStage::kFragment),
+         });
 
-  Func("frag_main", ast::VariableList{}, ty.void_(),
-       {
-           Decl(var),
-           Return(),
-       },
-       {
-           Stage(ast::PipelineStage::kFragment),
-       });
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  GeneratorImpl& gen = SanitizeAndBuild();
-
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(),
-            R"(RWByteAddressBuffer coord : register(u0, space1);
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(),
+              R"(RWByteAddressBuffer coord : register(u0, space1);
 
 float sub_func(float param) {
   return asfloat(coord.Load(0u));
@@ -652,72 +627,69 @@
 )");
 }
 
-TEST_F(HlslGeneratorImplTest_Function,
-       Emit_Attribute_EntryPoint_WithNameCollision) {
-  Func("GeometryShader", ast::VariableList{}, ty.void_(), {},
-       {
-           Stage(ast::PipelineStage::kFragment),
-       });
+TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_WithNameCollision) {
+    Func("GeometryShader", ast::VariableList{}, ty.void_(), {},
+         {
+             Stage(ast::PipelineStage::kFragment),
+         });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(void tint_symbol() {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(void tint_symbol() {
   return;
 }
 )");
 }
 
 TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_Compute) {
-  Func("main", ast::VariableList{}, ty.void_(),
-       {
-           Return(),
-       },
-       {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
+    Func("main", ast::VariableList{}, ty.void_(),
+         {
+             Return(),
+         },
+         {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"([numthreads(1, 1, 1)]
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"([numthreads(1, 1, 1)]
 void main() {
   return;
 }
 )");
 }
 
-TEST_F(HlslGeneratorImplTest_Function,
-       Emit_Attribute_EntryPoint_Compute_WithWorkgroup_Literal) {
-  Func("main", ast::VariableList{}, ty.void_(), {},
-       {
-           Stage(ast::PipelineStage::kCompute),
-           WorkgroupSize(2, 4, 6),
-       });
+TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_Compute_WithWorkgroup_Literal) {
+    Func("main", ast::VariableList{}, ty.void_(), {},
+         {
+             Stage(ast::PipelineStage::kCompute),
+             WorkgroupSize(2_i, 4_i, 6_i),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"([numthreads(2, 4, 6)]
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"([numthreads(2, 4, 6)]
 void main() {
   return;
 }
 )");
 }
 
-TEST_F(HlslGeneratorImplTest_Function,
-       Emit_Attribute_EntryPoint_Compute_WithWorkgroup_Const) {
-  GlobalConst("width", ty.i32(), Construct(ty.i32(), 2));
-  GlobalConst("height", ty.i32(), Construct(ty.i32(), 3));
-  GlobalConst("depth", ty.i32(), Construct(ty.i32(), 4));
-  Func("main", ast::VariableList{}, ty.void_(), {},
-       {
-           Stage(ast::PipelineStage::kCompute),
-           WorkgroupSize("width", "height", "depth"),
-       });
+TEST_F(HlslGeneratorImplTest_Function, Emit_Attribute_EntryPoint_Compute_WithWorkgroup_Const) {
+    GlobalConst("width", ty.i32(), Construct(ty.i32(), 2_i));
+    GlobalConst("height", ty.i32(), Construct(ty.i32(), 3_i));
+    GlobalConst("depth", ty.i32(), Construct(ty.i32(), 4_i));
+    Func("main", ast::VariableList{}, ty.void_(), {},
+         {
+             Stage(ast::PipelineStage::kCompute),
+             WorkgroupSize("width", "height", "depth"),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(static const int width = int(2);
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(static const int width = int(2);
 static const int height = int(3);
 static const int depth = int(4);
 
@@ -730,19 +702,19 @@
 
 TEST_F(HlslGeneratorImplTest_Function,
        Emit_Attribute_EntryPoint_Compute_WithWorkgroup_OverridableConst) {
-  Override("width", ty.i32(), Construct(ty.i32(), 2), {Id(7u)});
-  Override("height", ty.i32(), Construct(ty.i32(), 3), {Id(8u)});
-  Override("depth", ty.i32(), Construct(ty.i32(), 4), {Id(9u)});
-  Func("main", ast::VariableList{}, ty.void_(), {},
-       {
-           Stage(ast::PipelineStage::kCompute),
-           WorkgroupSize("width", "height", "depth"),
-       });
+    Override("width", ty.i32(), Construct(ty.i32(), 2_i), {Id(7u)});
+    Override("height", ty.i32(), Construct(ty.i32(), 3_i), {Id(8u)});
+    Override("depth", ty.i32(), Construct(ty.i32(), 4_i), {Id(9u)});
+    Func("main", ast::VariableList{}, ty.void_(), {},
+         {
+             Stage(ast::PipelineStage::kCompute),
+             WorkgroupSize("width", "height", "depth"),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#ifndef WGSL_SPEC_CONSTANT_7
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#ifndef WGSL_SPEC_CONSTANT_7
 #define WGSL_SPEC_CONSTANT_7 int(2)
 #endif
 static const int width = WGSL_SPEC_CONSTANT_7;
@@ -763,30 +735,30 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Function, Emit_Function_WithArrayParams) {
-  Func("my_func", ast::VariableList{Param("a", ty.array<f32, 5>())}, ty.void_(),
-       {
-           Return(),
-       });
+    Func("my_func", ast::VariableList{Param("a", ty.array<f32, 5>())}, ty.void_(),
+         {
+             Return(),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(void my_func(float a[5]) {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(void my_func(float a[5]) {
   return;
 }
 )");
 }
 
 TEST_F(HlslGeneratorImplTest_Function, Emit_Function_WithArrayReturn) {
-  Func("my_func", {}, ty.array<f32, 5>(),
-       {
-           Return(Construct(ty.array<f32, 5>())),
-       });
+    Func("my_func", {}, ty.array<f32, 5>(),
+         {
+             Return(Construct(ty.array<f32, 5>())),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(typedef float my_func_ret[5];
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(typedef float my_func_ret[5];
 my_func_ret my_func() {
   return (float[5])0;
 }
@@ -794,17 +766,17 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Function, Emit_Function_WithDiscardAndVoidReturn) {
-  Func("my_func", {Param("a", ty.i32())}, ty.void_(),
-       {
-           If(Equal("a", 0),  //
-              Block(create<ast::DiscardStatement>())),
-           Return(),
-       });
+    Func("my_func", {Param("a", ty.i32())}, ty.void_(),
+         {
+             If(Equal("a", 0_i),  //
+                Block(create<ast::DiscardStatement>())),
+             Return(),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(void my_func(int a) {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(void my_func(int a) {
   if ((a == 0)) {
     discard;
   }
@@ -813,19 +785,18 @@
 )");
 }
 
-TEST_F(HlslGeneratorImplTest_Function,
-       Emit_Function_WithDiscardAndNonVoidReturn) {
-  Func("my_func", {Param("a", ty.i32())}, ty.i32(),
-       {
-           If(Equal("a", 0),  //
-              Block(create<ast::DiscardStatement>())),
-           Return(42),
-       });
+TEST_F(HlslGeneratorImplTest_Function, Emit_Function_WithDiscardAndNonVoidReturn) {
+    Func("my_func", {Param("a", ty.i32())}, ty.i32(),
+         {
+             If(Equal("a", 0_i),  //
+                Block(create<ast::DiscardStatement>())),
+             Return(42_i),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(int my_func(int a) {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(int my_func(int a) {
   if (true) {
     if ((a == 0)) {
       discard;
@@ -839,61 +810,58 @@
 }
 
 // https://crbug.com/tint/297
-TEST_F(HlslGeneratorImplTest_Function,
-       Emit_Multiple_EntryPoint_With_Same_ModuleVar) {
-  // struct Data {
-  //   d : f32;
-  // };
-  // @binding(0) @group(0) var<storage> data : Data;
-  //
-  // @stage(compute) @workgroup_size(1)
-  // fn a() {
-  //   var v = data.d;
-  //   return;
-  // }
-  //
-  // @stage(compute) @workgroup_size(1)
-  // fn b() {
-  //   var v = data.d;
-  //   return;
-  // }
+TEST_F(HlslGeneratorImplTest_Function, Emit_Multiple_EntryPoint_With_Same_ModuleVar) {
+    // struct Data {
+    //   d : f32;
+    // };
+    // @binding(0) @group(0) var<storage> data : Data;
+    //
+    // @stage(compute) @workgroup_size(1)
+    // fn a() {
+    //   var v = data.d;
+    //   return;
+    // }
+    //
+    // @stage(compute) @workgroup_size(1)
+    // fn b() {
+    //   var v = data.d;
+    //   return;
+    // }
 
-  auto* s = Structure("Data", {Member("d", ty.f32())});
+    auto* s = Structure("Data", {Member("d", ty.f32())});
 
-  Global("data", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    Global("data", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  {
-    auto* var = Var("v", ty.f32(), ast::StorageClass::kNone,
-                    MemberAccessor("data", "d"));
+    {
+        auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, MemberAccessor("data", "d"));
 
-    Func("a", ast::VariableList{}, ty.void_(),
-         {
-             Decl(var),
-             Return(),
-         },
-         {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
-  }
+        Func("a", ast::VariableList{}, ty.void_(),
+             {
+                 Decl(var),
+                 Return(),
+             },
+             {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+    }
 
-  {
-    auto* var = Var("v", ty.f32(), ast::StorageClass::kNone,
-                    MemberAccessor("data", "d"));
+    {
+        auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, MemberAccessor("data", "d"));
 
-    Func("b", ast::VariableList{}, ty.void_(),
-         {
-             Decl(var),
-             Return(),
-         },
-         {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
-  }
+        Func("b", ast::VariableList{}, ty.void_(),
+             {
+                 Decl(var),
+                 Return(),
+             },
+             {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+    }
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(RWByteAddressBuffer data : register(u0, space0);
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(RWByteAddressBuffer data : register(u0, space0);
 
 [numthreads(1, 1, 1)]
 void a() {
diff --git a/src/tint/writer/hlsl/generator_impl_identifier_test.cc b/src/tint/writer/hlsl/generator_impl_identifier_test.cc
index d054bd8..d982e1e 100644
--- a/src/tint/writer/hlsl/generator_impl_identifier_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_identifier_test.cc
@@ -20,16 +20,16 @@
 using HlslGeneratorImplTest_Identifier = TestHelper;
 
 TEST_F(HlslGeneratorImplTest_Identifier, EmitIdentifierExpression) {
-  Global("foo", ty.i32(), ast::StorageClass::kPrivate);
+    Global("foo", ty.i32(), ast::StorageClass::kPrivate);
 
-  auto* i = Expr("foo");
-  WrapInFunction(i);
+    auto* i = Expr("foo");
+    WrapInFunction(i);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, i)) << gen.error();
-  EXPECT_EQ(out.str(), "foo");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, i)) << gen.error();
+    EXPECT_EQ(out.str(), "foo");
 }
 
 }  // namespace
diff --git a/src/tint/writer/hlsl/generator_impl_if_test.cc b/src/tint/writer/hlsl/generator_impl_if_test.cc
index f2e092c..1668d71 100644
--- a/src/tint/writer/hlsl/generator_impl_if_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_if_test.cc
@@ -20,43 +20,41 @@
 using HlslGeneratorImplTest_If = TestHelper;
 
 TEST_F(HlslGeneratorImplTest_If, Emit_If) {
-  Global("cond", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("cond", ty.bool_(), ast::StorageClass::kPrivate);
 
-  auto* cond = Expr("cond");
-  auto* body = Block(Return());
-  auto* i = If(cond, body);
-  WrapInFunction(i);
+    auto* cond = Expr("cond");
+    auto* body = Block(Return());
+    auto* i = If(cond, body);
+    WrapInFunction(i);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
-  ASSERT_TRUE(gen.EmitStatement(i)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  if (cond) {
+    gen.increment_indent();
+    ASSERT_TRUE(gen.EmitStatement(i)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  if (cond) {
     return;
   }
 )");
 }
 
 TEST_F(HlslGeneratorImplTest_If, Emit_IfWithElseIf) {
-  Global("cond", ty.bool_(), ast::StorageClass::kPrivate);
-  Global("else_cond", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("cond", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("else_cond", ty.bool_(), ast::StorageClass::kPrivate);
 
-  auto* else_cond = Expr("else_cond");
-  auto* else_body = Block(Return());
+    auto* else_cond = Expr("else_cond");
+    auto* else_body = Block(Return());
 
-  auto* cond = Expr("cond");
-  auto* body = Block(Return());
-  auto* i = If(
-      cond, body,
-      ast::ElseStatementList{create<ast::ElseStatement>(else_cond, else_body)});
-  WrapInFunction(i);
+    auto* cond = Expr("cond");
+    auto* body = Block(Return());
+    auto* i = If(cond, body, Else(If(else_cond, else_body)));
+    WrapInFunction(i);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(i)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  if (cond) {
+    ASSERT_TRUE(gen.EmitStatement(i)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  if (cond) {
     return;
   } else {
     if (else_cond) {
@@ -67,23 +65,21 @@
 }
 
 TEST_F(HlslGeneratorImplTest_If, Emit_IfWithElse) {
-  Global("cond", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("cond", ty.bool_(), ast::StorageClass::kPrivate);
 
-  auto* else_body = Block(Return());
+    auto* else_body = Block(Return());
 
-  auto* cond = Expr("cond");
-  auto* body = Block(Return());
-  auto* i = If(
-      cond, body,
-      ast::ElseStatementList{create<ast::ElseStatement>(nullptr, else_body)});
-  WrapInFunction(i);
+    auto* cond = Expr("cond");
+    auto* body = Block(Return());
+    auto* i = If(cond, body, Else(else_body));
+    WrapInFunction(i);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(i)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  if (cond) {
+    ASSERT_TRUE(gen.EmitStatement(i)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  if (cond) {
     return;
   } else {
     return;
@@ -92,30 +88,26 @@
 }
 
 TEST_F(HlslGeneratorImplTest_If, Emit_IfWithMultiple) {
-  Global("cond", ty.bool_(), ast::StorageClass::kPrivate);
-  Global("else_cond", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("cond", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("else_cond", ty.bool_(), ast::StorageClass::kPrivate);
 
-  auto* else_cond = Expr("else_cond");
+    auto* else_cond = Expr("else_cond");
 
-  auto* else_body = Block(Return());
+    auto* else_body = Block(Return());
 
-  auto* else_body_2 = Block(Return());
+    auto* else_body_2 = Block(Return());
 
-  auto* cond = Expr("cond");
-  auto* body = Block(Return());
-  auto* i = If(cond, body,
-               ast::ElseStatementList{
-                   create<ast::ElseStatement>(else_cond, else_body),
-                   create<ast::ElseStatement>(nullptr, else_body_2),
-               });
-  WrapInFunction(i);
+    auto* cond = Expr("cond");
+    auto* body = Block(Return());
+    auto* i = If(cond, body, Else(If(else_cond, else_body, Else(else_body_2))));
+    WrapInFunction(i);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(i)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  if (cond) {
+    ASSERT_TRUE(gen.EmitStatement(i)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  if (cond) {
     return;
   } else {
     if (else_cond) {
diff --git a/src/tint/writer/hlsl/generator_impl_import_test.cc b/src/tint/writer/hlsl/generator_impl_import_test.cc
index d1886ca..73e3161 100644
--- a/src/tint/writer/hlsl/generator_impl_import_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_import_test.cc
@@ -14,33 +14,35 @@
 
 #include "src/tint/writer/hlsl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::hlsl {
 namespace {
 
 using HlslGeneratorImplTest_Import = TestHelper;
 
 struct HlslImportData {
-  const char* name;
-  const char* hlsl_name;
+    const char* name;
+    const char* hlsl_name;
 };
 inline std::ostream& operator<<(std::ostream& out, HlslImportData data) {
-  out << data.name;
-  return out;
+    out << data.name;
+    return out;
 }
 
 using HlslImportData_SingleParamTest = TestParamHelper<HlslImportData>;
 TEST_P(HlslImportData_SingleParamTest, FloatScalar) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* ident = Expr(param.name);
-  auto* expr = Call(ident, 1.f);
-  WrapInFunction(expr);
+    auto* ident = Expr(param.name);
+    auto* expr = Call(ident, 1.f);
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), std::string(param.hlsl_name) + "(1.0f)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), std::string(param.hlsl_name) + "(1.0f)");
 }
 INSTANTIATE_TEST_SUITE_P(HlslGeneratorImplTest_Import,
                          HlslImportData_SingleParamTest,
@@ -70,16 +72,16 @@
 
 using HlslImportData_SingleIntParamTest = TestParamHelper<HlslImportData>;
 TEST_P(HlslImportData_SingleIntParamTest, IntScalar) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* expr = Call(param.name, Expr(1));
-  WrapInFunction(expr);
+    auto* expr = Call(param.name, Expr(1_i));
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), std::string(param.hlsl_name) + "(1)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), std::string(param.hlsl_name) + "(1)");
 }
 INSTANTIATE_TEST_SUITE_P(HlslGeneratorImplTest_Import,
                          HlslImportData_SingleIntParamTest,
@@ -87,18 +89,17 @@
 
 using HlslImportData_SingleVectorParamTest = TestParamHelper<HlslImportData>;
 TEST_P(HlslImportData_SingleVectorParamTest, FloatVector) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* ident = Expr(param.name);
-  auto* expr = Call(ident, vec3<f32>(1.f, 2.f, 3.f));
-  WrapInFunction(expr);
+    auto* ident = Expr(param.name);
+    auto* expr = Call(ident, vec3<f32>(1.f, 2.f, 3.f));
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(),
-            std::string(param.hlsl_name) + "(float3(1.0f, 2.0f, 3.0f))");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), std::string(param.hlsl_name) + "(float3(1.0f, 2.0f, 3.0f))");
 }
 INSTANTIATE_TEST_SUITE_P(HlslGeneratorImplTest_Import,
                          HlslImportData_SingleVectorParamTest,
@@ -117,8 +118,7 @@
                                          HlslImportData{"length", "length"},
                                          HlslImportData{"log", "log"},
                                          HlslImportData{"log2", "log2"},
-                                         HlslImportData{"normalize",
-                                                        "normalize"},
+                                         HlslImportData{"normalize", "normalize"},
                                          HlslImportData{"round", "round"},
                                          HlslImportData{"sign", "sign"},
                                          HlslImportData{"sin", "sin"},
@@ -130,16 +130,16 @@
 
 using HlslImportData_DualParam_ScalarTest = TestParamHelper<HlslImportData>;
 TEST_P(HlslImportData_DualParam_ScalarTest, Float) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* expr = Call(param.name, 1.f, 2.f);
-  WrapInFunction(expr);
+    auto* expr = Call(param.name, 1.f, 2.f);
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), std::string(param.hlsl_name) + "(1.0f, 2.0f)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), std::string(param.hlsl_name) + "(1.0f, 2.0f)");
 }
 INSTANTIATE_TEST_SUITE_P(HlslGeneratorImplTest_Import,
                          HlslImportData_DualParam_ScalarTest,
@@ -152,19 +152,17 @@
 
 using HlslImportData_DualParam_VectorTest = TestParamHelper<HlslImportData>;
 TEST_P(HlslImportData_DualParam_VectorTest, Float) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* expr =
-      Call(param.name, vec3<f32>(1.f, 2.f, 3.f), vec3<f32>(4.f, 5.f, 6.f));
-  WrapInFunction(expr);
+    auto* expr = Call(param.name, vec3<f32>(1.f, 2.f, 3.f), vec3<f32>(4.f, 5.f, 6.f));
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(),
-            std::string(param.hlsl_name) +
-                "(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f))");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), std::string(param.hlsl_name) +
+                             "(float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f))");
 }
 INSTANTIATE_TEST_SUITE_P(HlslGeneratorImplTest_Import,
                          HlslImportData_DualParam_VectorTest,
@@ -179,16 +177,16 @@
 
 using HlslImportData_DualParam_Int_Test = TestParamHelper<HlslImportData>;
 TEST_P(HlslImportData_DualParam_Int_Test, IntScalar) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* expr = Call(param.name, 1, 2);
-  WrapInFunction(expr);
+    auto* expr = Call(param.name, 1_i, 2_i);
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), std::string(param.hlsl_name) + "(1, 2)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), std::string(param.hlsl_name) + "(1, 2)");
 }
 INSTANTIATE_TEST_SUITE_P(HlslGeneratorImplTest_Import,
                          HlslImportData_DualParam_Int_Test,
@@ -197,82 +195,80 @@
 
 using HlslImportData_TripleParam_ScalarTest = TestParamHelper<HlslImportData>;
 TEST_P(HlslImportData_TripleParam_ScalarTest, Float) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* expr = Call(param.name, 1.f, 2.f, 3.f);
-  WrapInFunction(expr);
+    auto* expr = Call(param.name, 1.f, 2.f, 3.f);
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), std::string(param.hlsl_name) + "(1.0f, 2.0f, 3.0f)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), std::string(param.hlsl_name) + "(1.0f, 2.0f, 3.0f)");
 }
 INSTANTIATE_TEST_SUITE_P(HlslGeneratorImplTest_Import,
                          HlslImportData_TripleParam_ScalarTest,
                          testing::Values(HlslImportData{"fma", "mad"},
                                          HlslImportData{"mix", "lerp"},
                                          HlslImportData{"clamp", "clamp"},
-                                         HlslImportData{"smoothstep",
-                                                        "smoothstep"}));
+                                         HlslImportData{"smoothstep", "smoothstep"}));
 
 using HlslImportData_TripleParam_VectorTest = TestParamHelper<HlslImportData>;
 TEST_P(HlslImportData_TripleParam_VectorTest, Float) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* expr = Call(param.name, vec3<f32>(1.f, 2.f, 3.f),
-                    vec3<f32>(4.f, 5.f, 6.f), vec3<f32>(7.f, 8.f, 9.f));
-  WrapInFunction(expr);
+    auto* expr = Call(param.name, vec3<f32>(1.f, 2.f, 3.f), vec3<f32>(4.f, 5.f, 6.f),
+                      vec3<f32>(7.f, 8.f, 9.f));
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
-  EXPECT_EQ(
-      out.str(),
-      std::string(param.hlsl_name) +
-          R"((float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f)))");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
+    EXPECT_EQ(
+        out.str(),
+        std::string(param.hlsl_name) +
+            R"((float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f)))");
 }
-INSTANTIATE_TEST_SUITE_P(
-    HlslGeneratorImplTest_Import,
-    HlslImportData_TripleParam_VectorTest,
-    testing::Values(HlslImportData{"faceForward", "faceforward"},
-                    HlslImportData{"fma", "mad"},
-                    HlslImportData{"clamp", "clamp"},
-                    HlslImportData{"smoothstep", "smoothstep"}));
+INSTANTIATE_TEST_SUITE_P(HlslGeneratorImplTest_Import,
+                         HlslImportData_TripleParam_VectorTest,
+                         testing::Values(HlslImportData{"faceForward", "faceforward"},
+                                         HlslImportData{"fma", "mad"},
+                                         HlslImportData{"clamp", "clamp"},
+                                         HlslImportData{"smoothstep", "smoothstep"}));
 
 TEST_F(HlslGeneratorImplTest_Import, DISABLED_HlslImportData_FMix) {
-  FAIL();
+    FAIL();
 }
 
 using HlslImportData_TripleParam_Int_Test = TestParamHelper<HlslImportData>;
 TEST_P(HlslImportData_TripleParam_Int_Test, IntScalar) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* expr = Call(param.name, 1, 2, 3);
-  WrapInFunction(expr);
+    auto* expr = Call(param.name, 1_i, 2_i, 3_i);
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), std::string(param.hlsl_name) + "(1, 2, 3)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), std::string(param.hlsl_name) + "(1, 2, 3)");
 }
 INSTANTIATE_TEST_SUITE_P(HlslGeneratorImplTest_Import,
                          HlslImportData_TripleParam_Int_Test,
                          testing::Values(HlslImportData{"clamp", "clamp"}));
 
 TEST_F(HlslGeneratorImplTest_Import, HlslImportData_Determinant) {
-  Global("var", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
+    Global("var", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
 
-  auto* expr = Call("determinant", "var");
-  WrapInFunction(expr);
+    auto* expr = Call("determinant", "var");
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), std::string("determinant(var)"));
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), std::string("determinant(var)"));
 }
 
 }  // namespace
diff --git a/src/tint/writer/hlsl/generator_impl_loop_test.cc b/src/tint/writer/hlsl/generator_impl_loop_test.cc
index 6932d3b..0bd1f75 100644
--- a/src/tint/writer/hlsl/generator_impl_loop_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_loop_test.cc
@@ -15,44 +15,46 @@
 #include "src/tint/ast/variable_decl_statement.h"
 #include "src/tint/writer/hlsl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::hlsl {
 namespace {
 
 using HlslGeneratorImplTest_Loop = TestHelper;
 
 TEST_F(HlslGeneratorImplTest_Loop, Emit_Loop) {
-  auto* body = Block(create<ast::DiscardStatement>());
-  auto* continuing = Block();
-  auto* l = Loop(body, continuing);
+    auto* body = Block(create<ast::DiscardStatement>());
+    auto* continuing = Block();
+    auto* l = Loop(body, continuing);
 
-  WrapInFunction(l);
+    WrapInFunction(l);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(l)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  [loop] while (true) {
+    ASSERT_TRUE(gen.EmitStatement(l)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  [loop] while (true) {
     discard;
   }
 )");
 }
 
 TEST_F(HlslGeneratorImplTest_Loop, Emit_LoopWithContinuing) {
-  Func("a_statement", {}, ty.void_(), {});
+    Func("a_statement", {}, ty.void_(), {});
 
-  auto* body = Block(create<ast::DiscardStatement>());
-  auto* continuing = Block(CallStmt(Call("a_statement")));
-  auto* l = Loop(body, continuing);
+    auto* body = Block(create<ast::DiscardStatement>());
+    auto* continuing = Block(CallStmt(Call("a_statement")));
+    auto* l = Loop(body, continuing);
 
-  WrapInFunction(l);
+    WrapInFunction(l);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(l)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  [loop] while (true) {
+    ASSERT_TRUE(gen.EmitStatement(l)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  [loop] while (true) {
     discard;
     {
       a_statement();
@@ -62,31 +64,31 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Loop, Emit_LoopNestedWithContinuing) {
-  Func("a_statement", {}, ty.void_(), {});
+    Func("a_statement", {}, ty.void_(), {});
 
-  Global("lhs", ty.f32(), ast::StorageClass::kPrivate);
-  Global("rhs", ty.f32(), ast::StorageClass::kPrivate);
+    Global("lhs", ty.f32(), ast::StorageClass::kPrivate);
+    Global("rhs", ty.f32(), ast::StorageClass::kPrivate);
 
-  auto* body = Block(create<ast::DiscardStatement>());
-  auto* continuing = Block(CallStmt(Call("a_statement")));
-  auto* inner = Loop(body, continuing);
+    auto* body = Block(create<ast::DiscardStatement>());
+    auto* continuing = Block(CallStmt(Call("a_statement")));
+    auto* inner = Loop(body, continuing);
 
-  body = Block(inner);
+    body = Block(inner);
 
-  auto* lhs = Expr("lhs");
-  auto* rhs = Expr("rhs");
+    auto* lhs = Expr("lhs");
+    auto* rhs = Expr("rhs");
 
-  continuing = Block(Assign(lhs, rhs));
+    continuing = Block(Assign(lhs, rhs));
 
-  auto* outer = Loop(body, continuing);
-  WrapInFunction(outer);
+    auto* outer = Loop(body, continuing);
+    WrapInFunction(outer);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(outer)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  [loop] while (true) {
+    ASSERT_TRUE(gen.EmitStatement(outer)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  [loop] while (true) {
     [loop] while (true) {
       discard;
       {
@@ -101,31 +103,31 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Loop, Emit_LoopWithVarUsedInContinuing) {
-  // loop {
-  //   var lhs : f32 = 2.4;
-  //   var other : f32;
-  //   break;
-  //   continuing {
-  //     lhs = rhs
-  //   }
-  // }
+    // loop {
+    //   var lhs : f32 = 2.4;
+    //   var other : f32;
+    //   break;
+    //   continuing {
+    //     lhs = rhs
+    //   }
+    // }
 
-  Global("rhs", ty.f32(), ast::StorageClass::kPrivate);
+    Global("rhs", ty.f32(), ast::StorageClass::kPrivate);
 
-  auto* body = Block(Decl(Var("lhs", ty.f32(), Expr(2.4f))),  //
-                     Decl(Var("other", ty.f32())),            //
-                     Break());
+    auto* body = Block(Decl(Var("lhs", ty.f32(), Expr(2.4f))),  //
+                       Decl(Var("other", ty.f32())),            //
+                       Break());
 
-  auto* continuing = Block(Assign("lhs", "rhs"));
-  auto* outer = Loop(body, continuing);
-  WrapInFunction(outer);
+    auto* continuing = Block(Assign("lhs", "rhs"));
+    auto* outer = Loop(body, continuing);
+    WrapInFunction(outer);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(outer)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  [loop] while (true) {
+    ASSERT_TRUE(gen.EmitStatement(outer)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  [loop] while (true) {
     float lhs = 2.400000095f;
     float other = 0.0f;
     break;
@@ -137,19 +139,19 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Loop, Emit_ForLoop) {
-  // for(; ; ) {
-  //   return;
-  // }
+    // for(; ; ) {
+    //   return;
+    // }
 
-  auto* f = For(nullptr, nullptr, nullptr, Block(Return()));
-  WrapInFunction(f);
+    auto* f = For(nullptr, nullptr, nullptr, Block(Return()));
+    WrapInFunction(f);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  {
+    ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  {
     [loop] for(; ; ) {
       return;
     }
@@ -158,19 +160,19 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Loop, Emit_ForLoopWithSimpleInit) {
-  // for(var i : i32; ; ) {
-  //   return;
-  // }
+    // for(var i : i32; ; ) {
+    //   return;
+    // }
 
-  auto* f = For(Decl(Var("i", ty.i32())), nullptr, nullptr, Block(Return()));
-  WrapInFunction(f);
+    auto* f = For(Decl(Var("i", ty.i32())), nullptr, nullptr, Block(Return()));
+    WrapInFunction(f);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  {
+    ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  {
     [loop] for(int i = 0; ; ) {
       return;
     }
@@ -179,22 +181,21 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Loop, Emit_ForLoopWithMultiStmtInit) {
-  // for(var b = true && false; ; ) {
-  //   return;
-  // }
+    // for(var b = true && false; ; ) {
+    //   return;
+    // }
 
-  auto* multi_stmt = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd,
-                                                   Expr(true), Expr(false));
-  auto* f = For(Decl(Var("b", nullptr, multi_stmt)), nullptr, nullptr,
-                Block(Return()));
-  WrapInFunction(f);
+    auto* multi_stmt =
+        create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr(true), Expr(false));
+    auto* f = For(Decl(Var("b", nullptr, multi_stmt)), nullptr, nullptr, Block(Return()));
+    WrapInFunction(f);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  {
+    ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  {
     bool tint_tmp = true;
     if (tint_tmp) {
       tint_tmp = false;
@@ -208,19 +209,19 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Loop, Emit_ForLoopWithSimpleCond) {
-  // for(; true; ) {
-  //   return;
-  // }
+    // for(; true; ) {
+    //   return;
+    // }
 
-  auto* f = For(nullptr, true, nullptr, Block(Return()));
-  WrapInFunction(f);
+    auto* f = For(nullptr, true, nullptr, Block(Return()));
+    WrapInFunction(f);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  {
+    ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  {
     [loop] for(; true; ) {
       return;
     }
@@ -229,21 +230,21 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Loop, Emit_ForLoopWithMultiStmtCond) {
-  // for(; true && false; ) {
-  //   return;
-  // }
+    // for(; true && false; ) {
+    //   return;
+    // }
 
-  auto* multi_stmt = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd,
-                                                   Expr(true), Expr(false));
-  auto* f = For(nullptr, multi_stmt, nullptr, Block(Return()));
-  WrapInFunction(f);
+    auto* multi_stmt =
+        create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr(true), Expr(false));
+    auto* f = For(nullptr, multi_stmt, nullptr, Block(Return()));
+    WrapInFunction(f);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  {
+    ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  {
     [loop] while (true) {
       bool tint_tmp = true;
       if (tint_tmp) {
@@ -257,20 +258,20 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Loop, Emit_ForLoopWithSimpleCont) {
-  // for(; ; i = i + 1) {
-  //   return;
-  // }
+    // for(; ; i = i + 1i) {
+    //   return;
+    // }
 
-  auto* v = Decl(Var("i", ty.i32()));
-  auto* f = For(nullptr, nullptr, Assign("i", Add("i", 1)), Block(Return()));
-  WrapInFunction(v, f);
+    auto* v = Decl(Var("i", ty.i32()));
+    auto* f = For(nullptr, nullptr, Assign("i", Add("i", 1_i)), Block(Return()));
+    WrapInFunction(v, f);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  {
+    ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  {
     [loop] for(; ; i = (i + 1)) {
       return;
     }
@@ -279,22 +280,22 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Loop, Emit_ForLoopWithMultiStmtCont) {
-  // for(; ; i = true && false) {
-  //   return;
-  // }
+    // for(; ; i = true && false) {
+    //   return;
+    // }
 
-  auto* multi_stmt = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd,
-                                                   Expr(true), Expr(false));
-  auto* v = Decl(Var("i", ty.bool_()));
-  auto* f = For(nullptr, nullptr, Assign("i", multi_stmt), Block(Return()));
-  WrapInFunction(v, f);
+    auto* multi_stmt =
+        create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr(true), Expr(false));
+    auto* v = Decl(Var("i", ty.bool_()));
+    auto* f = For(nullptr, nullptr, Assign("i", multi_stmt), Block(Return()));
+    WrapInFunction(v, f);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  {
+    ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  {
     [loop] while (true) {
       return;
       bool tint_tmp = true;
@@ -308,20 +309,19 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Loop, Emit_ForLoopWithSimpleInitCondCont) {
-  // for(var i : i32; true; i = i + 1) {
-  //   return;
-  // }
+    // for(var i : i32; true; i = i + 1i) {
+    //   return;
+    // }
 
-  auto* f = For(Decl(Var("i", ty.i32())), true, Assign("i", Add("i", 1)),
-                Block(Return()));
-  WrapInFunction(f);
+    auto* f = For(Decl(Var("i", ty.i32())), true, Assign("i", Add("i", 1_i)), Block(Return()));
+    WrapInFunction(f);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  {
+    ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  {
     [loop] for(int i = 0; true; i = (i + 1)) {
       return;
     }
@@ -330,27 +330,27 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Loop, Emit_ForLoopWithMultiStmtInitCondCont) {
-  // for(var i = true && false; true && false; i = true && false) {
-  //   return;
-  // }
+    // for(var i = true && false; true && false; i = true && false) {
+    //   return;
+    // }
 
-  auto* multi_stmt_a = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd,
-                                                     Expr(true), Expr(false));
-  auto* multi_stmt_b = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd,
-                                                     Expr(true), Expr(false));
-  auto* multi_stmt_c = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd,
-                                                     Expr(true), Expr(false));
+    auto* multi_stmt_a =
+        create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr(true), Expr(false));
+    auto* multi_stmt_b =
+        create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr(true), Expr(false));
+    auto* multi_stmt_c =
+        create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr(true), Expr(false));
 
-  auto* f = For(Decl(Var("i", nullptr, multi_stmt_a)), multi_stmt_b,
-                Assign("i", multi_stmt_c), Block(Return()));
-  WrapInFunction(f);
+    auto* f = For(Decl(Var("i", nullptr, multi_stmt_a)), multi_stmt_b, Assign("i", multi_stmt_c),
+                  Block(Return()));
+    WrapInFunction(f);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  {
+    ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  {
     bool tint_tmp = true;
     if (tint_tmp) {
       tint_tmp = false;
diff --git a/src/tint/writer/hlsl/generator_impl_member_accessor_test.cc b/src/tint/writer/hlsl/generator_impl_member_accessor_test.cc
index 8244767..ad1e973 100644
--- a/src/tint/writer/hlsl/generator_impl_member_accessor_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_member_accessor_test.cc
@@ -16,119 +16,114 @@
 #include "src/tint/ast/stage_attribute.h"
 #include "src/tint/writer/hlsl/test_helper.h"
 
+using ::testing::HasSubstr;
+
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::hlsl {
 namespace {
 
-using ::testing::HasSubstr;
-
-using create_type_func_ptr =
-    const ast::Type* (*)(const ProgramBuilder::TypesBuilder& ty);
+using create_type_func_ptr = const ast::Type* (*)(const ProgramBuilder::TypesBuilder& ty);
 
 inline const ast::Type* ty_i32(const ProgramBuilder::TypesBuilder& ty) {
-  return ty.i32();
+    return ty.i32();
 }
 inline const ast::Type* ty_u32(const ProgramBuilder::TypesBuilder& ty) {
-  return ty.u32();
+    return ty.u32();
 }
 inline const ast::Type* ty_f32(const ProgramBuilder::TypesBuilder& ty) {
-  return ty.f32();
+    return ty.f32();
 }
 template <typename T>
 inline const ast::Type* ty_vec2(const ProgramBuilder::TypesBuilder& ty) {
-  return ty.vec2<T>();
+    return ty.vec2<T>();
 }
 template <typename T>
 inline const ast::Type* ty_vec3(const ProgramBuilder::TypesBuilder& ty) {
-  return ty.vec3<T>();
+    return ty.vec3<T>();
 }
 template <typename T>
 inline const ast::Type* ty_vec4(const ProgramBuilder::TypesBuilder& ty) {
-  return ty.vec4<T>();
+    return ty.vec4<T>();
 }
 template <typename T>
 inline const ast::Type* ty_mat2x2(const ProgramBuilder::TypesBuilder& ty) {
-  return ty.mat2x2<T>();
+    return ty.mat2x2<T>();
 }
 template <typename T>
 inline const ast::Type* ty_mat2x3(const ProgramBuilder::TypesBuilder& ty) {
-  return ty.mat2x3<T>();
+    return ty.mat2x3<T>();
 }
 template <typename T>
 inline const ast::Type* ty_mat2x4(const ProgramBuilder::TypesBuilder& ty) {
-  return ty.mat2x4<T>();
+    return ty.mat2x4<T>();
 }
 template <typename T>
 inline const ast::Type* ty_mat3x2(const ProgramBuilder::TypesBuilder& ty) {
-  return ty.mat3x2<T>();
+    return ty.mat3x2<T>();
 }
 template <typename T>
 inline const ast::Type* ty_mat3x3(const ProgramBuilder::TypesBuilder& ty) {
-  return ty.mat3x3<T>();
+    return ty.mat3x3<T>();
 }
 template <typename T>
 inline const ast::Type* ty_mat3x4(const ProgramBuilder::TypesBuilder& ty) {
-  return ty.mat3x4<T>();
+    return ty.mat3x4<T>();
 }
 template <typename T>
 inline const ast::Type* ty_mat4x2(const ProgramBuilder::TypesBuilder& ty) {
-  return ty.mat4x2<T>();
+    return ty.mat4x2<T>();
 }
 template <typename T>
 inline const ast::Type* ty_mat4x3(const ProgramBuilder::TypesBuilder& ty) {
-  return ty.mat4x3<T>();
+    return ty.mat4x3<T>();
 }
 template <typename T>
 inline const ast::Type* ty_mat4x4(const ProgramBuilder::TypesBuilder& ty) {
-  return ty.mat4x4<T>();
+    return ty.mat4x4<T>();
 }
 
-using i32 = ProgramBuilder::i32;
-using u32 = ProgramBuilder::u32;
-using f32 = ProgramBuilder::f32;
-
 template <typename BASE>
 class HlslGeneratorImplTest_MemberAccessorBase : public BASE {
- public:
-  void SetupStorageBuffer(ast::StructMemberList members) {
-    ProgramBuilder& b = *this;
+  public:
+    void SetupStorageBuffer(ast::StructMemberList members) {
+        ProgramBuilder& b = *this;
 
-    auto* s = b.Structure("Data", members);
+        auto* s = b.Structure("Data", members);
 
-    b.Global("data", b.ty.Of(s), ast::StorageClass::kStorage,
-             ast::Access::kReadWrite,
-             ast::AttributeList{
-                 b.create<ast::BindingAttribute>(0),
-                 b.create<ast::GroupAttribute>(1),
-             });
-  }
+        b.Global("data", b.ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+                 ast::AttributeList{
+                     b.create<ast::BindingAttribute>(0),
+                     b.create<ast::GroupAttribute>(1),
+                 });
+    }
 
-  void SetupFunction(ast::StatementList statements) {
-    ProgramBuilder& b = *this;
-    b.Func("main", ast::VariableList{}, b.ty.void_(), statements,
-           ast::AttributeList{
-               b.Stage(ast::PipelineStage::kFragment),
-           });
-  }
+    void SetupFunction(ast::StatementList statements) {
+        ProgramBuilder& b = *this;
+        b.Func("main", ast::VariableList{}, b.ty.void_(), statements,
+               ast::AttributeList{
+                   b.Stage(ast::PipelineStage::kFragment),
+               });
+    }
 };
 
-using HlslGeneratorImplTest_MemberAccessor =
-    HlslGeneratorImplTest_MemberAccessorBase<TestHelper>;
+using HlslGeneratorImplTest_MemberAccessor = HlslGeneratorImplTest_MemberAccessorBase<TestHelper>;
 
 template <typename T>
 using HlslGeneratorImplTest_MemberAccessorWithParam =
     HlslGeneratorImplTest_MemberAccessorBase<TestParamHelper<T>>;
 
 TEST_F(HlslGeneratorImplTest_MemberAccessor, EmitExpression_MemberAccessor) {
-  auto* s = Structure("Data", {Member("mem", ty.f32())});
-  Global("str", ty.Of(s), ast::StorageClass::kPrivate);
+    auto* s = Structure("Data", {Member("mem", ty.f32())});
+    Global("str", ty.Of(s), ast::StorageClass::kPrivate);
 
-  auto* expr = MemberAccessor("str", "mem");
-  WrapInFunction(Var("expr", ty.f32(), ast::StorageClass::kNone, expr));
+    auto* expr = MemberAccessor("str", "mem");
+    WrapInFunction(Var("expr", ty.f32(), ast::StorageClass::kNone, expr));
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(struct Data {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(struct Data {
   float mem;
 };
 
@@ -143,42 +138,41 @@
 }
 
 struct TypeCase {
-  create_type_func_ptr member_type;
-  std::string expected;
+    create_type_func_ptr member_type;
+    std::string expected;
 };
 inline std::ostream& operator<<(std::ostream& out, TypeCase c) {
-  ProgramBuilder b;
-  auto* ty = c.member_type(b.ty);
-  out << ty->FriendlyName(b.Symbols());
-  return out;
+    ProgramBuilder b;
+    auto* ty = c.member_type(b.ty);
+    out << ty->FriendlyName(b.Symbols());
+    return out;
 }
 
 using HlslGeneratorImplTest_MemberAccessor_StorageBufferLoad =
     HlslGeneratorImplTest_MemberAccessorWithParam<TypeCase>;
 TEST_P(HlslGeneratorImplTest_MemberAccessor_StorageBufferLoad, Test) {
-  // struct Data {
-  //   a : i32;
-  //   b : <type>;
-  // };
-  // var<storage> data : Data;
-  // data.b;
+    // struct Data {
+    //   a : i32;
+    //   b : <type>;
+    // };
+    // var<storage> data : Data;
+    // data.b;
 
-  auto p = GetParam();
+    auto p = GetParam();
 
-  SetupStorageBuffer({
-      Member("a", ty.i32()),
-      Member("b", p.member_type(ty)),
-  });
+    SetupStorageBuffer({
+        Member("a", ty.i32()),
+        Member("b", p.member_type(ty)),
+    });
 
-  SetupFunction({
-      Decl(Var("x", nullptr, ast::StorageClass::kNone,
-               MemberAccessor("data", "b"))),
-  });
+    SetupFunction({
+        Decl(Var("x", nullptr, ast::StorageClass::kNone, MemberAccessor("data", "b"))),
+    });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr(p.expected));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr(p.expected));
 }
 
 INSTANTIATE_TEST_SUITE_P(
@@ -228,87 +222,86 @@
 using HlslGeneratorImplTest_MemberAccessor_StorageBufferStore =
     HlslGeneratorImplTest_MemberAccessorWithParam<TypeCase>;
 TEST_P(HlslGeneratorImplTest_MemberAccessor_StorageBufferStore, Test) {
-  // struct Data {
-  //   a : i32;
-  //   b : <type>;
-  // };
-  // var<storage> data : Data;
-  // data.b = <type>();
+    // struct Data {
+    //   a : i32;
+    //   b : <type>;
+    // };
+    // var<storage> data : Data;
+    // data.b = <type>();
 
-  auto p = GetParam();
+    auto p = GetParam();
 
-  SetupStorageBuffer({
-      Member("a", ty.i32()),
-      Member("b", p.member_type(ty)),
-  });
+    SetupStorageBuffer({
+        Member("a", ty.i32()),
+        Member("b", p.member_type(ty)),
+    });
 
-  SetupFunction({
-      Decl(Var("value", p.member_type(ty), ast::StorageClass::kNone,
-               Construct(p.member_type(ty)))),
-      Assign(MemberAccessor("data", "b"), Expr("value")),
-  });
+    SetupFunction({
+        Decl(Var("value", p.member_type(ty), ast::StorageClass::kNone,
+                 Construct(p.member_type(ty)))),
+        Assign(MemberAccessor("data", "b"), Expr("value")),
+    });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr(p.expected));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr(p.expected));
 }
 
-INSTANTIATE_TEST_SUITE_P(
-    HlslGeneratorImplTest_MemberAccessor,
-    HlslGeneratorImplTest_MemberAccessor_StorageBufferStore,
-    testing::Values(TypeCase{ty_u32, "data.Store(4u, asuint(value))"},
-                    TypeCase{ty_f32, "data.Store(4u, asuint(value))"},
-                    TypeCase{ty_i32, "data.Store(4u, asuint(value))"},
-                    TypeCase{ty_vec2<u32>, "data.Store2(8u, asuint(value))"},
-                    TypeCase{ty_vec2<f32>, "data.Store2(8u, asuint(value))"},
-                    TypeCase{ty_vec2<i32>, "data.Store2(8u, asuint(value))"},
-                    TypeCase{ty_vec3<u32>, "data.Store3(16u, asuint(value))"},
-                    TypeCase{ty_vec3<f32>, "data.Store3(16u, asuint(value))"},
-                    TypeCase{ty_vec3<i32>, "data.Store3(16u, asuint(value))"},
-                    TypeCase{ty_vec4<u32>, "data.Store4(16u, asuint(value))"},
-                    TypeCase{ty_vec4<f32>, "data.Store4(16u, asuint(value))"},
-                    TypeCase{ty_vec4<i32>, "data.Store4(16u, asuint(value))"},
-                    TypeCase{ty_mat2x2<f32>, R"({
+INSTANTIATE_TEST_SUITE_P(HlslGeneratorImplTest_MemberAccessor,
+                         HlslGeneratorImplTest_MemberAccessor_StorageBufferStore,
+                         testing::Values(TypeCase{ty_u32, "data.Store(4u, asuint(value))"},
+                                         TypeCase{ty_f32, "data.Store(4u, asuint(value))"},
+                                         TypeCase{ty_i32, "data.Store(4u, asuint(value))"},
+                                         TypeCase{ty_vec2<u32>, "data.Store2(8u, asuint(value))"},
+                                         TypeCase{ty_vec2<f32>, "data.Store2(8u, asuint(value))"},
+                                         TypeCase{ty_vec2<i32>, "data.Store2(8u, asuint(value))"},
+                                         TypeCase{ty_vec3<u32>, "data.Store3(16u, asuint(value))"},
+                                         TypeCase{ty_vec3<f32>, "data.Store3(16u, asuint(value))"},
+                                         TypeCase{ty_vec3<i32>, "data.Store3(16u, asuint(value))"},
+                                         TypeCase{ty_vec4<u32>, "data.Store4(16u, asuint(value))"},
+                                         TypeCase{ty_vec4<f32>, "data.Store4(16u, asuint(value))"},
+                                         TypeCase{ty_vec4<i32>, "data.Store4(16u, asuint(value))"},
+                                         TypeCase{ty_mat2x2<f32>, R"({
   buffer.Store2((offset + 0u), asuint(value[0u]));
   buffer.Store2((offset + 8u), asuint(value[1u]));
 })"},
-                    TypeCase{ty_mat2x3<f32>, R"({
+                                         TypeCase{ty_mat2x3<f32>, R"({
   buffer.Store3((offset + 0u), asuint(value[0u]));
   buffer.Store3((offset + 16u), asuint(value[1u]));
 })"},
-                    TypeCase{ty_mat2x4<f32>, R"({
+                                         TypeCase{ty_mat2x4<f32>, R"({
   buffer.Store4((offset + 0u), asuint(value[0u]));
   buffer.Store4((offset + 16u), asuint(value[1u]));
 })"},
-                    TypeCase{ty_mat3x2<f32>, R"({
+                                         TypeCase{ty_mat3x2<f32>, R"({
   buffer.Store2((offset + 0u), asuint(value[0u]));
   buffer.Store2((offset + 8u), asuint(value[1u]));
   buffer.Store2((offset + 16u), asuint(value[2u]));
 })"},
-                    TypeCase{ty_mat3x3<f32>, R"({
+                                         TypeCase{ty_mat3x3<f32>, R"({
   buffer.Store3((offset + 0u), asuint(value[0u]));
   buffer.Store3((offset + 16u), asuint(value[1u]));
   buffer.Store3((offset + 32u), asuint(value[2u]));
 })"},
-                    TypeCase{ty_mat3x4<f32>, R"({
+                                         TypeCase{ty_mat3x4<f32>, R"({
   buffer.Store4((offset + 0u), asuint(value[0u]));
   buffer.Store4((offset + 16u), asuint(value[1u]));
   buffer.Store4((offset + 32u), asuint(value[2u]));
 })"},
-                    TypeCase{ty_mat4x2<f32>, R"({
+                                         TypeCase{ty_mat4x2<f32>, R"({
   buffer.Store2((offset + 0u), asuint(value[0u]));
   buffer.Store2((offset + 8u), asuint(value[1u]));
   buffer.Store2((offset + 16u), asuint(value[2u]));
   buffer.Store2((offset + 24u), asuint(value[3u]));
 })"},
-                    TypeCase{ty_mat4x3<f32>, R"({
+                                         TypeCase{ty_mat4x3<f32>, R"({
   buffer.Store3((offset + 0u), asuint(value[0u]));
   buffer.Store3((offset + 16u), asuint(value[1u]));
   buffer.Store3((offset + 32u), asuint(value[2u]));
   buffer.Store3((offset + 48u), asuint(value[3u]));
 })"},
-                    TypeCase{ty_mat4x4<f32>, R"({
+                                         TypeCase{ty_mat4x4<f32>, R"({
   buffer.Store4((offset + 0u), asuint(value[0u]));
   buffer.Store4((offset + 16u), asuint(value[1u]));
   buffer.Store4((offset + 32u), asuint(value[2u]));
@@ -316,28 +309,27 @@
 })"}));
 
 TEST_F(HlslGeneratorImplTest_MemberAccessor, StorageBuffer_Store_Matrix_Empty) {
-  // struct Data {
-  //   z : f32;
-  //   a : mat2x3<f32>;
-  // };
-  // var<storage> data : Data;
-  // data.a = mat2x3<f32>();
+    // struct Data {
+    //   z : f32;
+    //   a : mat2x3<f32>;
+    // };
+    // var<storage> data : Data;
+    // data.a = mat2x3<f32>();
 
-  SetupStorageBuffer({
-      Member("a", ty.i32()),
-      Member("b", ty.mat2x3<f32>()),
-  });
+    SetupStorageBuffer({
+        Member("a", ty.i32()),
+        Member("b", ty.mat2x3<f32>()),
+    });
 
-  SetupFunction({
-      Assign(MemberAccessor("data", "b"),
-             Construct(ty.mat2x3<f32>(), ast::ExpressionList{})),
-  });
+    SetupFunction({
+        Assign(MemberAccessor("data", "b"), Construct(ty.mat2x3<f32>(), ast::ExpressionList{})),
+    });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  auto* expected =
-      R"(RWByteAddressBuffer data : register(u0, space1);
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    auto* expected =
+        R"(RWByteAddressBuffer data : register(u0, space1);
 
 void tint_symbol(RWByteAddressBuffer buffer, uint offset, float2x3 value) {
   buffer.Store3((offset + 0u), asuint(value[0u]));
@@ -349,415 +341,400 @@
   return;
 }
 )";
-  EXPECT_EQ(gen.result(), expected);
+    EXPECT_EQ(gen.result(), expected);
 }
 
-TEST_F(HlslGeneratorImplTest_MemberAccessor,
-       StorageBuffer_Load_Matrix_Single_Element) {
-  // struct Data {
-  //   z : f32;
-  //   a : mat4x3<f32>;
-  // };
-  // var<storage> data : Data;
-  // data.a[2][1];
+TEST_F(HlslGeneratorImplTest_MemberAccessor, StorageBuffer_Load_Matrix_Single_Element) {
+    // struct Data {
+    //   z : f32;
+    //   a : mat4x3<f32>;
+    // };
+    // var<storage> data : Data;
+    // data.a[2i][1i];
 
-  SetupStorageBuffer({
-      Member("z", ty.f32()),
-      Member("a", ty.mat4x3<f32>()),
-  });
+    SetupStorageBuffer({
+        Member("z", ty.f32()),
+        Member("a", ty.mat4x3<f32>()),
+    });
 
-  SetupFunction({
-      Decl(
-          Var("x", nullptr, ast::StorageClass::kNone,
-              IndexAccessor(IndexAccessor(MemberAccessor("data", "a"), 2), 1))),
-  });
+    SetupFunction({
+        Decl(Var("x", nullptr, ast::StorageClass::kNone,
+                 IndexAccessor(IndexAccessor(MemberAccessor("data", "a"), 2_i), 1_i))),
+    });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  auto* expected =
-      R"(RWByteAddressBuffer data : register(u0, space1);
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    auto* expected =
+        R"(RWByteAddressBuffer data : register(u0, space1);
 
 void main() {
   float x = asfloat(data.Load(52u));
   return;
 }
 )";
-  EXPECT_EQ(gen.result(), expected);
+    EXPECT_EQ(gen.result(), expected);
 }
 
 TEST_F(HlslGeneratorImplTest_MemberAccessor,
        EmitExpression_IndexAccessor_StorageBuffer_Load_Int_FromArray) {
-  // struct Data {
-  //   a : array<i32, 5>;
-  // };
-  // var<storage> data : Data;
-  // data.a[2];
+    // struct Data {
+    //   a : array<i32, 5>;
+    // };
+    // var<storage> data : Data;
+    // data.a[2];
 
-  SetupStorageBuffer({
-      Member("z", ty.f32()),
-      Member("a", ty.array<i32, 5>(4)),
-  });
+    SetupStorageBuffer({
+        Member("z", ty.f32()),
+        Member("a", ty.array<i32, 5>(4)),
+    });
 
-  SetupFunction({
-      Decl(Var("x", nullptr, ast::StorageClass::kNone,
-               IndexAccessor(MemberAccessor("data", "a"), 2))),
-  });
+    SetupFunction({
+        Decl(Var("x", nullptr, ast::StorageClass::kNone,
+                 IndexAccessor(MemberAccessor("data", "a"), 2_i))),
+    });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  auto* expected =
-      R"(RWByteAddressBuffer data : register(u0, space1);
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    auto* expected =
+        R"(RWByteAddressBuffer data : register(u0, space1);
 
 void main() {
   int x = asint(data.Load(12u));
   return;
 }
 )";
-  EXPECT_EQ(gen.result(), expected);
+    EXPECT_EQ(gen.result(), expected);
 }
 
 TEST_F(HlslGeneratorImplTest_MemberAccessor,
        EmitExpression_IndexAccessor_StorageBuffer_Load_Int_FromArray_ExprIdx) {
-  // struct Data {
-  //   a : array<i32, 5>;
-  // };
-  // var<storage> data : Data;
-  // data.a[(2 + 4) - 3];
+    // struct Data {
+    //   a : array<i32, 5>;
+    // };
+    // var<storage> data : Data;
+    // data.a[(2i + 4i) - 3i];
 
-  SetupStorageBuffer({
-      Member("z", ty.f32()),
-      Member("a", ty.array<i32, 5>(4)),
-  });
+    SetupStorageBuffer({
+        Member("z", ty.f32()),
+        Member("a", ty.array<i32, 5>(4)),
+    });
 
-  SetupFunction({
-      Decl(Var("x", nullptr, ast::StorageClass::kNone,
-               IndexAccessor(MemberAccessor("data", "a"),
-                             Sub(Add(2, Expr(4)), Expr(3))))),
-  });
+    SetupFunction({
+        Decl(Var("x", nullptr, ast::StorageClass::kNone,
+                 IndexAccessor(MemberAccessor("data", "a"), Sub(Add(2_i, Expr(4_i)), Expr(3_i))))),
+    });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  auto* expected =
-      R"(RWByteAddressBuffer data : register(u0, space1);
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    auto* expected =
+        R"(RWByteAddressBuffer data : register(u0, space1);
 
 void main() {
   int x = asint(data.Load((4u + (4u * uint(((2 + 4) - 3))))));
   return;
 }
 )";
-  EXPECT_EQ(gen.result(), expected);
+    EXPECT_EQ(gen.result(), expected);
 }
 
 TEST_F(HlslGeneratorImplTest_MemberAccessor, StorageBuffer_Store_ToArray) {
-  // struct Data {
-  //   a : array<i32, 5>;
-  // };
-  // var<storage> data : Data;
-  // data.a[2] = 2;
+    // struct Data {
+    //   a : array<i32, 5>;
+    // };
+    // var<storage> data : Data;
+    // data.a[2] = 2;
 
-  SetupStorageBuffer({
-      Member("z", ty.f32()),
-      Member("a", ty.array<i32, 5>(4)),
-  });
+    SetupStorageBuffer({
+        Member("z", ty.f32()),
+        Member("a", ty.array<i32, 5>(4)),
+    });
 
-  SetupFunction({
-      Assign(IndexAccessor(MemberAccessor("data", "a"), 2), 2),
-  });
+    SetupFunction({
+        Assign(IndexAccessor(MemberAccessor("data", "a"), 2_i), 2_i),
+    });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  auto* expected =
-      R"(RWByteAddressBuffer data : register(u0, space1);
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    auto* expected =
+        R"(RWByteAddressBuffer data : register(u0, space1);
 
 void main() {
   data.Store(12u, asuint(2));
   return;
 }
 )";
-  EXPECT_EQ(gen.result(), expected);
+    EXPECT_EQ(gen.result(), expected);
 }
 
 TEST_F(HlslGeneratorImplTest_MemberAccessor, StorageBuffer_Load_MultiLevel) {
-  // struct Inner {
-  //   a : vec3<i32>;
-  //   b : vec3<f32>;
-  // };
-  // struct Data {
-  //   var c : array<Inner, 4>;
-  // };
-  //
-  // var<storage> data : Pre;
-  // data.c[2].b
+    // struct Inner {
+    //   a : vec3<i32>;
+    //   b : vec3<f32>;
+    // };
+    // struct Data {
+    //   var c : array<Inner, 4u>;
+    // };
+    //
+    // var<storage> data : Pre;
+    // data.c[2].b
 
-  auto* inner = Structure("Inner", {
-                                       Member("a", ty.vec3<f32>()),
-                                       Member("b", ty.vec3<f32>()),
-                                   });
+    auto* inner = Structure("Inner", {
+                                         Member("a", ty.vec3<f32>()),
+                                         Member("b", ty.vec3<f32>()),
+                                     });
 
-  SetupStorageBuffer({
-      Member("c", ty.array(ty.Of(inner), 4, 32)),
-  });
+    SetupStorageBuffer({
+        Member("c", ty.array(ty.Of(inner), 4_u, 32)),
+    });
 
-  SetupFunction({
-      Decl(Var(
-          "x", nullptr, ast::StorageClass::kNone,
-          MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2), "b"))),
-  });
+    SetupFunction({
+        Decl(Var("x", nullptr, ast::StorageClass::kNone,
+                 MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2_i), "b"))),
+    });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  auto* expected =
-      R"(RWByteAddressBuffer data : register(u0, space1);
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    auto* expected =
+        R"(RWByteAddressBuffer data : register(u0, space1);
 
 void main() {
   float3 x = asfloat(data.Load3(80u));
   return;
 }
 )";
-  EXPECT_EQ(gen.result(), expected);
+    EXPECT_EQ(gen.result(), expected);
 }
 
-TEST_F(HlslGeneratorImplTest_MemberAccessor,
-       StorageBuffer_Load_MultiLevel_Swizzle) {
-  // struct Inner {
-  //   a : vec3<i32>;
-  //   b : vec3<f32>;
-  // };
-  // struct Data {
-  //   var c : array<Inner, 4>;
-  // };
-  //
-  // var<storage> data : Pre;
-  // data.c[2].b.xy
+TEST_F(HlslGeneratorImplTest_MemberAccessor, StorageBuffer_Load_MultiLevel_Swizzle) {
+    // struct Inner {
+    //   a : vec3<i32>;
+    //   b : vec3<f32>;
+    // };
+    // struct Data {
+    //   var c : array<Inner, 4u>;
+    // };
+    //
+    // var<storage> data : Pre;
+    // data.c[2].b.xy
 
-  auto* inner = Structure("Inner", {
-                                       Member("a", ty.vec3<f32>()),
-                                       Member("b", ty.vec3<f32>()),
-                                   });
+    auto* inner = Structure("Inner", {
+                                         Member("a", ty.vec3<f32>()),
+                                         Member("b", ty.vec3<f32>()),
+                                     });
 
-  SetupStorageBuffer({
-      Member("c", ty.array(ty.Of(inner), 4, 32)),
-  });
+    SetupStorageBuffer({
+        Member("c", ty.array(ty.Of(inner), 4_u, 32)),
+    });
 
-  SetupFunction({
-      Decl(Var("x", nullptr, ast::StorageClass::kNone,
-               MemberAccessor(
-                   MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2),
-                                  "b"),
-                   "xy"))),
-  });
+    SetupFunction({
+        Decl(Var("x", nullptr, ast::StorageClass::kNone,
+                 MemberAccessor(
+                     MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2_i), "b"), "xy"))),
+    });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  auto* expected =
-      R"(RWByteAddressBuffer data : register(u0, space1);
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    auto* expected =
+        R"(RWByteAddressBuffer data : register(u0, space1);
 
 void main() {
   float2 x = asfloat(data.Load3(80u)).xy;
   return;
 }
 )";
-  EXPECT_EQ(gen.result(), expected);
+    EXPECT_EQ(gen.result(), expected);
 }
 
 TEST_F(HlslGeneratorImplTest_MemberAccessor,
        StorageBuffer_Load_MultiLevel_Swizzle_SingleLetter) {  // NOLINT
-  // struct Inner {
-  //   a : vec3<i32>;
-  //   b : vec3<f32>;
-  // };
-  // struct Data {
-  //   var c : array<Inner, 4>;
-  // };
-  //
-  // var<storage> data : Pre;
-  // data.c[2].b.g
+    // struct Inner {
+    //   a : vec3<i32>;
+    //   b : vec3<f32>;
+    // };
+    // struct Data {
+    //   var c : array<Inner, 4u>;
+    // };
+    //
+    // var<storage> data : Pre;
+    // data.c[2].b.g
 
-  auto* inner = Structure("Inner", {
-                                       Member("a", ty.vec3<f32>()),
-                                       Member("b", ty.vec3<f32>()),
-                                   });
+    auto* inner = Structure("Inner", {
+                                         Member("a", ty.vec3<f32>()),
+                                         Member("b", ty.vec3<f32>()),
+                                     });
 
-  SetupStorageBuffer({
-      Member("c", ty.array(ty.Of(inner), 4, 32)),
-  });
+    SetupStorageBuffer({
+        Member("c", ty.array(ty.Of(inner), 4_u, 32)),
+    });
 
-  SetupFunction({
-      Decl(Var("x", nullptr, ast::StorageClass::kNone,
-               MemberAccessor(
-                   MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2),
-                                  "b"),
-                   "g"))),
-  });
+    SetupFunction({
+        Decl(Var("x", nullptr, ast::StorageClass::kNone,
+                 MemberAccessor(
+                     MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2_i), "b"), "g"))),
+    });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  auto* expected =
-      R"(RWByteAddressBuffer data : register(u0, space1);
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    auto* expected =
+        R"(RWByteAddressBuffer data : register(u0, space1);
 
 void main() {
   float x = asfloat(data.Load(84u));
   return;
 }
 )";
-  EXPECT_EQ(gen.result(), expected);
+    EXPECT_EQ(gen.result(), expected);
 }
 
-TEST_F(HlslGeneratorImplTest_MemberAccessor,
-       StorageBuffer_Load_MultiLevel_Index) {
-  // struct Inner {
-  //   a : vec3<i32>;
-  //   b : vec3<f32>;
-  // };
-  // struct Data {
-  //   var c : array<Inner, 4>;
-  // };
-  //
-  // var<storage> data : Pre;
-  // data.c[2].b[1]
+TEST_F(HlslGeneratorImplTest_MemberAccessor, StorageBuffer_Load_MultiLevel_Index) {
+    // struct Inner {
+    //   a : vec3<i32>;
+    //   b : vec3<f32>;
+    // };
+    // struct Data {
+    //   var c : array<Inner, 4u>;
+    // };
+    //
+    // var<storage> data : Pre;
+    // data.c[2].b[1]
 
-  auto* inner = Structure("Inner", {
-                                       Member("a", ty.vec3<f32>()),
-                                       Member("b", ty.vec3<f32>()),
-                                   });
+    auto* inner = Structure("Inner", {
+                                         Member("a", ty.vec3<f32>()),
+                                         Member("b", ty.vec3<f32>()),
+                                     });
 
-  SetupStorageBuffer({
-      Member("c", ty.array(ty.Of(inner), 4, 32)),
-  });
+    SetupStorageBuffer({
+        Member("c", ty.array(ty.Of(inner), 4_u, 32)),
+    });
 
-  SetupFunction({
-      Decl(Var(
-          "x", nullptr, ast::StorageClass::kNone,
-          IndexAccessor(MemberAccessor(
-                            IndexAccessor(MemberAccessor("data", "c"), 2), "b"),
-                        1))),
-  });
+    SetupFunction({
+        Decl(Var("x", nullptr, ast::StorageClass::kNone,
+                 IndexAccessor(MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2_i), "b"),
+                               1_i))),
+    });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  auto* expected =
-      R"(RWByteAddressBuffer data : register(u0, space1);
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    auto* expected =
+        R"(RWByteAddressBuffer data : register(u0, space1);
 
 void main() {
   float x = asfloat(data.Load(84u));
   return;
 }
 )";
-  EXPECT_EQ(gen.result(), expected);
+    EXPECT_EQ(gen.result(), expected);
 }
 
 TEST_F(HlslGeneratorImplTest_MemberAccessor, StorageBuffer_Store_MultiLevel) {
-  // struct Inner {
-  //   a : vec3<i32>;
-  //   b : vec3<f32>;
-  // };
-  // struct Data {
-  //   var c : array<Inner, 4>;
-  // };
-  //
-  // var<storage> data : Pre;
-  // data.c[2].b = vec3<f32>(1.f, 2.f, 3.f);
+    // struct Inner {
+    //   a : vec3<i32>;
+    //   b : vec3<f32>;
+    // };
+    // struct Data {
+    //   var c : array<Inner, 4u>;
+    // };
+    //
+    // var<storage> data : Pre;
+    // data.c[2].b = vec3<f32>(1.f, 2.f, 3.f);
 
-  auto* inner = Structure("Inner", {
-                                       Member("a", ty.vec3<f32>()),
-                                       Member("b", ty.vec3<f32>()),
-                                   });
+    auto* inner = Structure("Inner", {
+                                         Member("a", ty.vec3<f32>()),
+                                         Member("b", ty.vec3<f32>()),
+                                     });
 
-  SetupStorageBuffer({
-      Member("c", ty.array(ty.Of(inner), 4, 32)),
-  });
+    SetupStorageBuffer({
+        Member("c", ty.array(ty.Of(inner), 4_u, 32)),
+    });
 
-  SetupFunction({
-      Assign(MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2), "b"),
-             vec3<f32>(1.f, 2.f, 3.f)),
-  });
+    SetupFunction({
+        Assign(MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2_i), "b"),
+               vec3<f32>(1.f, 2.f, 3.f)),
+    });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  auto* expected =
-      R"(RWByteAddressBuffer data : register(u0, space1);
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    auto* expected =
+        R"(RWByteAddressBuffer data : register(u0, space1);
 
 void main() {
   data.Store3(80u, asuint(float3(1.0f, 2.0f, 3.0f)));
   return;
 }
 )";
-  EXPECT_EQ(gen.result(), expected);
+    EXPECT_EQ(gen.result(), expected);
 }
 
-TEST_F(HlslGeneratorImplTest_MemberAccessor,
-       StorageBuffer_Store_Swizzle_SingleLetter) {
-  // struct Inner {
-  //   a : vec3<i32>;
-  //   b : vec3<f32>;
-  // };
-  // struct Data {
-  //   var c : array<Inner, 4>;
-  // };
-  //
-  // var<storage> data : Pre;
-  // data.c[2].b.y = 1.f;
+TEST_F(HlslGeneratorImplTest_MemberAccessor, StorageBuffer_Store_Swizzle_SingleLetter) {
+    // struct Inner {
+    //   a : vec3<i32>;
+    //   b : vec3<f32>;
+    // };
+    // struct Data {
+    //   var c : array<Inner, 4u>;
+    // };
+    //
+    // var<storage> data : Pre;
+    // data.c[2].b.y = 1.f;
 
-  auto* inner = Structure("Inner", {
-                                       Member("a", ty.vec3<i32>()),
-                                       Member("b", ty.vec3<f32>()),
-                                   });
+    auto* inner = Structure("Inner", {
+                                         Member("a", ty.vec3<i32>()),
+                                         Member("b", ty.vec3<f32>()),
+                                     });
 
-  SetupStorageBuffer({
-      Member("c", ty.array(ty.Of(inner), 4, 32)),
-  });
+    SetupStorageBuffer({
+        Member("c", ty.array(ty.Of(inner), 4_u, 32)),
+    });
 
-  SetupFunction({
-      Assign(MemberAccessor(
-                 MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2),
-                                "b"),
-                 "y"),
-             Expr(1.f)),
-  });
+    SetupFunction({
+        Assign(MemberAccessor(MemberAccessor(IndexAccessor(MemberAccessor("data", "c"), 2_i), "b"),
+                              "y"),
+               Expr(1.f)),
+    });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  auto* expected =
-      R"(RWByteAddressBuffer data : register(u0, space1);
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    auto* expected =
+        R"(RWByteAddressBuffer data : register(u0, space1);
 
 void main() {
   data.Store(84u, asuint(1.0f));
   return;
 }
 )";
-  EXPECT_EQ(gen.result(), expected);
+    EXPECT_EQ(gen.result(), expected);
 }
 
 TEST_F(HlslGeneratorImplTest_MemberAccessor, Swizzle_xyz) {
-  auto* var = Var("my_vec", ty.vec4<f32>(), ast::StorageClass::kNone,
-                  vec4<f32>(1.f, 2.f, 3.f, 4.f));
-  auto* expr = MemberAccessor("my_vec", "xyz");
-  WrapInFunction(var, expr);
+    auto* var =
+        Var("my_vec", ty.vec4<f32>(), ast::StorageClass::kNone, vec4<f32>(1.f, 2.f, 3.f, 4.f));
+    auto* expr = MemberAccessor("my_vec", "xyz");
+    WrapInFunction(var, expr);
 
-  GeneratorImpl& gen = SanitizeAndBuild();
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("my_vec.xyz"));
+    GeneratorImpl& gen = SanitizeAndBuild();
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("my_vec.xyz"));
 }
 
 TEST_F(HlslGeneratorImplTest_MemberAccessor, Swizzle_gbr) {
-  auto* var = Var("my_vec", ty.vec4<f32>(), ast::StorageClass::kNone,
-                  vec4<f32>(1.f, 2.f, 3.f, 4.f));
-  auto* expr = MemberAccessor("my_vec", "gbr");
-  WrapInFunction(var, expr);
+    auto* var =
+        Var("my_vec", ty.vec4<f32>(), ast::StorageClass::kNone, vec4<f32>(1.f, 2.f, 3.f, 4.f));
+    auto* expr = MemberAccessor("my_vec", "gbr");
+    WrapInFunction(var, expr);
 
-  GeneratorImpl& gen = SanitizeAndBuild();
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("my_vec.gbr"));
+    GeneratorImpl& gen = SanitizeAndBuild();
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("my_vec.gbr"));
 }
 
 }  // namespace
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 30b0b0c..14e8e93 100644
--- a/src/tint/writer/hlsl/generator_impl_module_constant_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_module_constant_test.cc
@@ -21,25 +21,25 @@
 using HlslGeneratorImplTest_ModuleConstant = TestHelper;
 
 TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_ModuleConstant) {
-  auto* var = Const("pos", ty.array<f32, 3>(), array<f32, 3>(1.f, 2.f, 3.f));
-  WrapInFunction(Decl(var));
+    auto* var = Let("pos", ty.array<f32, 3>(), array<f32, 3>(1.f, 2.f, 3.f));
+    WrapInFunction(Decl(var));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitProgramConstVariable(var)) << gen.error();
-  EXPECT_EQ(gen.result(), "static const float pos[3] = {1.0f, 2.0f, 3.0f};\n");
+    ASSERT_TRUE(gen.EmitProgramConstVariable(var)) << gen.error();
+    EXPECT_EQ(gen.result(), "static const float pos[3] = {1.0f, 2.0f, 3.0f};\n");
 }
 
 TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_SpecConstant) {
-  auto* var = Override("pos", ty.f32(), Expr(3.0f),
-                       ast::AttributeList{
-                           Id(23),
-                       });
+    auto* var = Override("pos", ty.f32(), Expr(3.0f),
+                         ast::AttributeList{
+                             Id(23),
+                         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitProgramConstVariable(var)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#ifndef WGSL_SPEC_CONSTANT_23
+    ASSERT_TRUE(gen.EmitProgramConstVariable(var)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#ifndef WGSL_SPEC_CONSTANT_23
 #define WGSL_SPEC_CONSTANT_23 3.0f
 #endif
 static const float pos = WGSL_SPEC_CONSTANT_23;
@@ -47,15 +47,15 @@
 }
 
 TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_SpecConstant_NoConstructor) {
-  auto* var = Override("pos", ty.f32(), nullptr,
-                       ast::AttributeList{
-                           Id(23),
-                       });
+    auto* var = Override("pos", ty.f32(), nullptr,
+                         ast::AttributeList{
+                             Id(23),
+                         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitProgramConstVariable(var)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#ifndef WGSL_SPEC_CONSTANT_23
+    ASSERT_TRUE(gen.EmitProgramConstVariable(var)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#ifndef WGSL_SPEC_CONSTANT_23
 #error spec constant required for constant id 23
 #endif
 static const float pos = WGSL_SPEC_CONSTANT_23;
@@ -63,17 +63,17 @@
 }
 
 TEST_F(HlslGeneratorImplTest_ModuleConstant, Emit_SpecConstant_NoId) {
-  auto* a = Override("a", ty.f32(), Expr(3.0f),
-                     ast::AttributeList{
-                         Id(0),
-                     });
-  auto* b = Override("b", ty.f32(), Expr(2.0f));
+    auto* a = Override("a", ty.f32(), Expr(3.0f),
+                       ast::AttributeList{
+                           Id(0),
+                       });
+    auto* b = Override("b", ty.f32(), Expr(2.0f));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitProgramConstVariable(a)) << gen.error();
-  ASSERT_TRUE(gen.EmitProgramConstVariable(b)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#ifndef WGSL_SPEC_CONSTANT_0
+    ASSERT_TRUE(gen.EmitProgramConstVariable(a)) << gen.error();
+    ASSERT_TRUE(gen.EmitProgramConstVariable(b)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#ifndef WGSL_SPEC_CONSTANT_0
 #define WGSL_SPEC_CONSTANT_0 3.0f
 #endif
 static const float a = WGSL_SPEC_CONSTANT_0;
diff --git a/src/tint/writer/hlsl/generator_impl_return_test.cc b/src/tint/writer/hlsl/generator_impl_return_test.cc
index 3f839fc..1813645 100644
--- a/src/tint/writer/hlsl/generator_impl_return_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_return_test.cc
@@ -14,33 +14,35 @@
 
 #include "src/tint/writer/hlsl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::hlsl {
 namespace {
 
 using HlslGeneratorImplTest_Return = TestHelper;
 
 TEST_F(HlslGeneratorImplTest_Return, Emit_Return) {
-  auto* r = Return();
-  WrapInFunction(r);
+    auto* r = Return();
+    WrapInFunction(r);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(r)) << gen.error();
-  EXPECT_EQ(gen.result(), "  return;\n");
+    ASSERT_TRUE(gen.EmitStatement(r)) << gen.error();
+    EXPECT_EQ(gen.result(), "  return;\n");
 }
 
 TEST_F(HlslGeneratorImplTest_Return, Emit_ReturnWithValue) {
-  auto* r = Return(123);
-  Func("f", {}, ty.i32(), {r});
+    auto* r = Return(123_i);
+    Func("f", {}, ty.i32(), {r});
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(r)) << gen.error();
-  EXPECT_EQ(gen.result(), "  return 123;\n");
+    ASSERT_TRUE(gen.EmitStatement(r)) << gen.error();
+    EXPECT_EQ(gen.result(), "  return 123;\n");
 }
 
 }  // namespace
diff --git a/src/tint/writer/hlsl/generator_impl_sanitizer_test.cc b/src/tint/writer/hlsl/generator_impl_sanitizer_test.cc
index cb31f4d..b68c950 100644
--- a/src/tint/writer/hlsl/generator_impl_sanitizer_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_sanitizer_test.cc
@@ -17,34 +17,36 @@
 #include "src/tint/ast/variable_decl_statement.h"
 #include "src/tint/writer/hlsl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::hlsl {
 namespace {
 
 using HlslSanitizerTest = TestHelper;
 
 TEST_F(HlslSanitizerTest, Call_ArrayLength) {
-  auto* s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))});
-  Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+    auto* s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))});
+    Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(1),
+               create<ast::GroupAttribute>(2),
+           });
+
+    Func("a_func", ast::VariableList{}, ty.void_(),
+         ast::StatementList{
+             Decl(Var("len", ty.u32(), ast::StorageClass::kNone,
+                      Call("arrayLength", AddressOf(MemberAccessor("b", "a"))))),
+         },
          ast::AttributeList{
-             create<ast::BindingAttribute>(1),
-             create<ast::GroupAttribute>(2),
+             Stage(ast::PipelineStage::kFragment),
          });
 
-  Func("a_func", ast::VariableList{}, ty.void_(),
-       ast::StatementList{
-           Decl(Var("len", ty.u32(), ast::StorageClass::kNone,
-                    Call("arrayLength", AddressOf(MemberAccessor("b", "a"))))),
-       },
-       ast::AttributeList{
-           Stage(ast::PipelineStage::kFragment),
-       });
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    ASSERT_TRUE(gen.Generate()) << gen.error();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-
-  auto got = gen.result();
-  auto* expect = R"(ByteAddressBuffer b : register(t1, space2);
+    auto got = gen.result();
+    auto* expect = R"(ByteAddressBuffer b : register(t1, space2);
 
 void a_func() {
   uint tint_symbol_1 = 0u;
@@ -54,35 +56,35 @@
   return;
 }
 )";
-  EXPECT_EQ(expect, got);
+    EXPECT_EQ(expect, got);
 }
 
 TEST_F(HlslSanitizerTest, Call_ArrayLength_OtherMembersInStruct) {
-  auto* s = Structure("my_struct", {
-                                       Member(0, "z", ty.f32()),
-                                       Member(4, "a", ty.array<f32>(4)),
-                                   });
-  Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+    auto* s = Structure("my_struct", {
+                                         Member(0, "z", ty.f32()),
+                                         Member(4, "a", ty.array<f32>(4)),
+                                     });
+    Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(1),
+               create<ast::GroupAttribute>(2),
+           });
+
+    Func("a_func", ast::VariableList{}, ty.void_(),
+         ast::StatementList{
+             Decl(Var("len", ty.u32(), ast::StorageClass::kNone,
+                      Call("arrayLength", AddressOf(MemberAccessor("b", "a"))))),
+         },
          ast::AttributeList{
-             create<ast::BindingAttribute>(1),
-             create<ast::GroupAttribute>(2),
+             Stage(ast::PipelineStage::kFragment),
          });
 
-  Func("a_func", ast::VariableList{}, ty.void_(),
-       ast::StatementList{
-           Decl(Var("len", ty.u32(), ast::StorageClass::kNone,
-                    Call("arrayLength", AddressOf(MemberAccessor("b", "a"))))),
-       },
-       ast::AttributeList{
-           Stage(ast::PipelineStage::kFragment),
-       });
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    ASSERT_TRUE(gen.Generate()) << gen.error();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-
-  auto got = gen.result();
-  auto* expect = R"(ByteAddressBuffer b : register(t1, space2);
+    auto got = gen.result();
+    auto* expect = R"(ByteAddressBuffer b : register(t1, space2);
 
 void a_func() {
   uint tint_symbol_1 = 0u;
@@ -93,37 +95,36 @@
 }
 )";
 
-  EXPECT_EQ(expect, got);
+    EXPECT_EQ(expect, got);
 }
 
 TEST_F(HlslSanitizerTest, Call_ArrayLength_ViaLets) {
-  auto* s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))});
-  Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+    auto* s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))});
+    Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(1),
+               create<ast::GroupAttribute>(2),
+           });
+
+    auto* p = Let("p", nullptr, AddressOf("b"));
+    auto* p2 = Let("p2", nullptr, AddressOf(MemberAccessor(Deref(p), "a")));
+
+    Func("a_func", ast::VariableList{}, ty.void_(),
+         ast::StatementList{
+             Decl(p),
+             Decl(p2),
+             Decl(Var("len", ty.u32(), ast::StorageClass::kNone, Call("arrayLength", p2))),
+         },
          ast::AttributeList{
-             create<ast::BindingAttribute>(1),
-             create<ast::GroupAttribute>(2),
+             Stage(ast::PipelineStage::kFragment),
          });
 
-  auto* p = Const("p", nullptr, AddressOf("b"));
-  auto* p2 = Const("p2", nullptr, AddressOf(MemberAccessor(Deref(p), "a")));
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  Func("a_func", ast::VariableList{}, ty.void_(),
-       ast::StatementList{
-           Decl(p),
-           Decl(p2),
-           Decl(Var("len", ty.u32(), ast::StorageClass::kNone,
-                    Call("arrayLength", p2))),
-       },
-       ast::AttributeList{
-           Stage(ast::PipelineStage::kFragment),
-       });
+    ASSERT_TRUE(gen.Generate()) << gen.error();
 
-  GeneratorImpl& gen = SanitizeAndBuild();
-
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-
-  auto got = gen.result();
-  auto* expect = R"(ByteAddressBuffer b : register(t1, space2);
+    auto got = gen.result();
+    auto* expect = R"(ByteAddressBuffer b : register(t1, space2);
 
 void a_func() {
   uint tint_symbol_1 = 0u;
@@ -134,43 +135,41 @@
 }
 )";
 
-  EXPECT_EQ(expect, got);
+    EXPECT_EQ(expect, got);
 }
 
 TEST_F(HlslSanitizerTest, Call_ArrayLength_ArrayLengthFromUniform) {
-  auto* s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))});
-  Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+    auto* s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))});
+    Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(1),
+               create<ast::GroupAttribute>(2),
+           });
+    Global("c", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(2),
+               create<ast::GroupAttribute>(2),
+           });
+
+    Func("a_func", ast::VariableList{}, ty.void_(),
+         ast::StatementList{
+             Decl(Var("len", ty.u32(), ast::StorageClass::kNone,
+                      Add(Call("arrayLength", AddressOf(MemberAccessor("b", "a"))),
+                          Call("arrayLength", AddressOf(MemberAccessor("c", "a")))))),
+         },
          ast::AttributeList{
-             create<ast::BindingAttribute>(1),
-             create<ast::GroupAttribute>(2),
-         });
-  Global("c", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(2),
-             create<ast::GroupAttribute>(2),
+             Stage(ast::PipelineStage::kFragment),
          });
 
-  Func("a_func", ast::VariableList{}, ty.void_(),
-       ast::StatementList{
-           Decl(Var(
-               "len", ty.u32(), ast::StorageClass::kNone,
-               Add(Call("arrayLength", AddressOf(MemberAccessor("b", "a"))),
-                   Call("arrayLength", AddressOf(MemberAccessor("c", "a")))))),
-       },
-       ast::AttributeList{
-           Stage(ast::PipelineStage::kFragment),
-       });
+    Options options;
+    options.array_length_from_uniform.ubo_binding = {3, 4};
+    options.array_length_from_uniform.bindpoint_to_size_index.emplace(sem::BindingPoint{2, 2}, 7u);
+    GeneratorImpl& gen = SanitizeAndBuild(options);
 
-  Options options;
-  options.array_length_from_uniform.ubo_binding = {3, 4};
-  options.array_length_from_uniform.bindpoint_to_size_index.emplace(
-      sem::BindingPoint{2, 2}, 7u);
-  GeneratorImpl& gen = SanitizeAndBuild(options);
+    ASSERT_TRUE(gen.Generate()) << gen.error();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-
-  auto got = gen.result();
-  auto* expect = R"(cbuffer cbuffer_tint_symbol_1 : register(b4, space3) {
+    auto got = gen.result();
+    auto* expect = R"(cbuffer cbuffer_tint_symbol_1 : register(b4, space3) {
   uint4 tint_symbol_1[2];
 };
 ByteAddressBuffer b : register(t1, space2);
@@ -184,61 +183,60 @@
   return;
 }
 )";
-  EXPECT_EQ(expect, got);
+    EXPECT_EQ(expect, got);
 }
 
 TEST_F(HlslSanitizerTest, PromoteArrayInitializerToConstVar) {
-  auto* array_init = array<i32, 4>(1, 2, 3, 4);
-  auto* array_index = IndexAccessor(array_init, 3);
-  auto* pos = Var("pos", ty.i32(), ast::StorageClass::kNone, array_index);
+    auto* array_init = array<i32, 4>(1_i, 2_i, 3_i, 4_i);
+    auto* array_index = IndexAccessor(array_init, 3_i);
+    auto* pos = Var("pos", ty.i32(), ast::StorageClass::kNone, array_index);
 
-  Func("main", ast::VariableList{}, ty.void_(),
-       {
-           Decl(pos),
-       },
-       {
-           Stage(ast::PipelineStage::kFragment),
-       });
+    Func("main", ast::VariableList{}, ty.void_(),
+         {
+             Decl(pos),
+         },
+         {
+             Stage(ast::PipelineStage::kFragment),
+         });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
+    ASSERT_TRUE(gen.Generate()) << gen.error();
 
-  auto got = gen.result();
-  auto* expect = R"(void main() {
+    auto got = gen.result();
+    auto* expect = R"(void main() {
   const int tint_symbol[4] = {1, 2, 3, 4};
   int pos = tint_symbol[3];
   return;
 }
 )";
-  EXPECT_EQ(expect, got);
+    EXPECT_EQ(expect, got);
 }
 
 TEST_F(HlslSanitizerTest, PromoteStructInitializerToConstVar) {
-  auto* str = Structure("S", {
-                                 Member("a", ty.i32()),
-                                 Member("b", ty.vec3<f32>()),
-                                 Member("c", ty.i32()),
-                             });
-  auto* struct_init = Construct(ty.Of(str), 1, vec3<f32>(2.f, 3.f, 4.f), 4);
-  auto* struct_access = MemberAccessor(struct_init, "b");
-  auto* pos =
-      Var("pos", ty.vec3<f32>(), ast::StorageClass::kNone, struct_access);
+    auto* str = Structure("S", {
+                                   Member("a", ty.i32()),
+                                   Member("b", ty.vec3<f32>()),
+                                   Member("c", ty.i32()),
+                               });
+    auto* struct_init = Construct(ty.Of(str), 1_i, vec3<f32>(2.f, 3.f, 4.f), 4_i);
+    auto* struct_access = MemberAccessor(struct_init, "b");
+    auto* pos = Var("pos", ty.vec3<f32>(), ast::StorageClass::kNone, struct_access);
 
-  Func("main", ast::VariableList{}, ty.void_(),
-       {
-           Decl(pos),
-       },
-       {
-           Stage(ast::PipelineStage::kFragment),
-       });
+    Func("main", ast::VariableList{}, ty.void_(),
+         {
+             Decl(pos),
+         },
+         {
+             Stage(ast::PipelineStage::kFragment),
+         });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
+    ASSERT_TRUE(gen.Generate()) << gen.error();
 
-  auto got = gen.result();
-  auto* expect = R"(struct S {
+    auto got = gen.result();
+    auto* expect = R"(struct S {
   int a;
   float3 b;
   int c;
@@ -250,85 +248,80 @@
   return;
 }
 )";
-  EXPECT_EQ(expect, got);
+    EXPECT_EQ(expect, got);
 }
 
 TEST_F(HlslSanitizerTest, InlinePtrLetsBasic) {
-  // var v : i32;
-  // let p : ptr<function, i32> = &v;
-  // let x : i32 = *p;
-  auto* v = Var("v", ty.i32());
-  auto* p =
-      Const("p", ty.pointer<i32>(ast::StorageClass::kFunction), AddressOf(v));
-  auto* x = Var("x", ty.i32(), ast::StorageClass::kNone, Deref(p));
+    // var v : i32;
+    // let p : ptr<function, i32> = &v;
+    // let x : i32 = *p;
+    auto* v = Var("v", ty.i32());
+    auto* p = Let("p", ty.pointer<i32>(ast::StorageClass::kFunction), AddressOf(v));
+    auto* x = Var("x", ty.i32(), ast::StorageClass::kNone, Deref(p));
 
-  Func("main", ast::VariableList{}, ty.void_(),
-       {
-           Decl(v),
-           Decl(p),
-           Decl(x),
-       },
-       {
-           Stage(ast::PipelineStage::kFragment),
-       });
+    Func("main", ast::VariableList{}, ty.void_(),
+         {
+             Decl(v),
+             Decl(p),
+             Decl(x),
+         },
+         {
+             Stage(ast::PipelineStage::kFragment),
+         });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
+    ASSERT_TRUE(gen.Generate()) << gen.error();
 
-  auto got = gen.result();
-  auto* expect = R"(void main() {
+    auto got = gen.result();
+    auto* expect = R"(void main() {
   int v = 0;
   int x = v;
   return;
 }
 )";
-  EXPECT_EQ(expect, got);
+    EXPECT_EQ(expect, got);
 }
 
 TEST_F(HlslSanitizerTest, InlinePtrLetsComplexChain) {
-  // var a : array<mat4x4<f32>, 4>;
-  // let ap : ptr<function, array<mat4x4<f32>, 4>> = &a;
-  // let mp : ptr<function, mat4x4<f32>> = &(*ap)[3];
-  // let vp : ptr<function, vec4<f32>> = &(*mp)[2];
-  // let v : vec4<f32> = *vp;
-  auto* a = Var("a", ty.array(ty.mat4x4<f32>(), 4));
-  auto* ap = Const(
-      "ap",
-      ty.pointer(ty.array(ty.mat4x4<f32>(), 4), ast::StorageClass::kFunction),
-      AddressOf(a));
-  auto* mp =
-      Const("mp", ty.pointer(ty.mat4x4<f32>(), ast::StorageClass::kFunction),
-            AddressOf(IndexAccessor(Deref(ap), 3)));
-  auto* vp =
-      Const("vp", ty.pointer(ty.vec4<f32>(), ast::StorageClass::kFunction),
-            AddressOf(IndexAccessor(Deref(mp), 2)));
-  auto* v = Var("v", ty.vec4<f32>(), ast::StorageClass::kNone, Deref(vp));
+    // var a : array<mat4x4<f32>, 4u>;
+    // let ap : ptr<function, array<mat4x4<f32>, 4u>> = &a;
+    // let mp : ptr<function, mat4x4<f32>> = &(*ap)[3i];
+    // let vp : ptr<function, vec4<f32>> = &(*mp)[2i];
+    // let v : vec4<f32> = *vp;
+    auto* a = Var("a", ty.array(ty.mat4x4<f32>(), 4_u));
+    auto* ap = Let("ap", ty.pointer(ty.array(ty.mat4x4<f32>(), 4_u), ast::StorageClass::kFunction),
+                   AddressOf(a));
+    auto* mp = Let("mp", ty.pointer(ty.mat4x4<f32>(), ast::StorageClass::kFunction),
+                   AddressOf(IndexAccessor(Deref(ap), 3_i)));
+    auto* vp = Let("vp", ty.pointer(ty.vec4<f32>(), ast::StorageClass::kFunction),
+                   AddressOf(IndexAccessor(Deref(mp), 2_i)));
+    auto* v = Var("v", ty.vec4<f32>(), ast::StorageClass::kNone, Deref(vp));
 
-  Func("main", ast::VariableList{}, ty.void_(),
-       {
-           Decl(a),
-           Decl(ap),
-           Decl(mp),
-           Decl(vp),
-           Decl(v),
-       },
-       {
-           Stage(ast::PipelineStage::kFragment),
-       });
+    Func("main", ast::VariableList{}, ty.void_(),
+         {
+             Decl(a),
+             Decl(ap),
+             Decl(mp),
+             Decl(vp),
+             Decl(v),
+         },
+         {
+             Stage(ast::PipelineStage::kFragment),
+         });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
+    ASSERT_TRUE(gen.Generate()) << gen.error();
 
-  auto got = gen.result();
-  auto* expect = R"(void main() {
+    auto got = gen.result();
+    auto* expect = R"(void main() {
   float4x4 a[4] = (float4x4[4])0;
   float4 v = a[3][2];
   return;
 }
 )";
-  EXPECT_EQ(expect, got);
+    EXPECT_EQ(expect, got);
 }
 
 }  // namespace
diff --git a/src/tint/writer/hlsl/generator_impl_switch_test.cc b/src/tint/writer/hlsl/generator_impl_switch_test.cc
index 792b64b..3ef1a7b 100644
--- a/src/tint/writer/hlsl/generator_impl_switch_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_switch_test.cc
@@ -14,25 +14,27 @@
 
 #include "src/tint/writer/hlsl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::hlsl {
 namespace {
 
 using HlslGeneratorImplTest_Switch = TestHelper;
 
 TEST_F(HlslGeneratorImplTest_Switch, Emit_Switch) {
-  Global("cond", ty.i32(), ast::StorageClass::kPrivate);
-  auto* s = Switch(                   //
-      Expr("cond"),                   //
-      Case(Expr(5), Block(Break())),  //
-      DefaultCase());
-  WrapInFunction(s);
+    Global("cond", ty.i32(), ast::StorageClass::kPrivate);
+    auto* s = Switch(                     //
+        Expr("cond"),                     //
+        Case(Expr(5_i), Block(Break())),  //
+        DefaultCase());
+    WrapInFunction(s);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(s)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  switch(cond) {
+    ASSERT_TRUE(gen.EmitStatement(s)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  switch(cond) {
     case 5: {
       break;
     }
@@ -44,19 +46,19 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Switch, Emit_Switch_OnlyDefaultCase) {
-  Global("cond", ty.i32(), ast::StorageClass::kPrivate);
-  Global("a", ty.i32(), ast::StorageClass::kPrivate);
-  auto* s = Switch(  //
-      Expr("cond"),  //
-      DefaultCase(Block(Assign(Expr("a"), Expr(42)))));
-  WrapInFunction(s);
+    Global("cond", ty.i32(), ast::StorageClass::kPrivate);
+    Global("a", ty.i32(), ast::StorageClass::kPrivate);
+    auto* s = Switch(  //
+        Expr("cond"),  //
+        DefaultCase(Block(Assign(Expr("a"), Expr(42_i)))));
+    WrapInFunction(s);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(s)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  cond;
+    ASSERT_TRUE(gen.EmitStatement(s)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  cond;
   do {
     a = 42;
   } while (false);
diff --git a/src/tint/writer/hlsl/generator_impl_test.cc b/src/tint/writer/hlsl/generator_impl_test.cc
index ea479e4..460b202 100644
--- a/src/tint/writer/hlsl/generator_impl_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_test.cc
@@ -20,49 +20,45 @@
 using HlslGeneratorImplTest = TestHelper;
 
 TEST_F(HlslGeneratorImplTest, Generate) {
-  Func("my_func", ast::VariableList{}, ty.void_(), ast::StatementList{},
-       ast::AttributeList{});
+    Func("my_func", ast::VariableList{}, ty.void_(), ast::StatementList{}, ast::AttributeList{});
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(void my_func() {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(void my_func() {
 }
 )");
 }
 
 struct HlslBuiltinData {
-  ast::Builtin builtin;
-  const char* attribute_name;
+    ast::Builtin builtin;
+    const char* attribute_name;
 };
 inline std::ostream& operator<<(std::ostream& out, HlslBuiltinData data) {
-  out << data.builtin;
-  return out;
+    out << data.builtin;
+    return out;
 }
 using HlslBuiltinConversionTest = TestParamHelper<HlslBuiltinData>;
 TEST_P(HlslBuiltinConversionTest, Emit) {
-  auto params = GetParam();
-  GeneratorImpl& gen = Build();
+    auto params = GetParam();
+    GeneratorImpl& gen = Build();
 
-  EXPECT_EQ(gen.builtin_to_attribute(params.builtin),
-            std::string(params.attribute_name));
+    EXPECT_EQ(gen.builtin_to_attribute(params.builtin), std::string(params.attribute_name));
 }
 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::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"}));
 
 }  // namespace
 }  // namespace tint::writer::hlsl
diff --git a/src/tint/writer/hlsl/generator_impl_type_test.cc b/src/tint/writer/hlsl/generator_impl_type_test.cc
index bea99ce..b99f06e 100644
--- a/src/tint/writer/hlsl/generator_impl_type_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_type_test.cc
@@ -15,135 +15,133 @@
 #include "gmock/gmock.h"
 #include "src/tint/ast/call_statement.h"
 #include "src/tint/ast/stage_attribute.h"
-#include "src/tint/sem/depth_texture_type.h"
-#include "src/tint/sem/multisampled_texture_type.h"
-#include "src/tint/sem/sampled_texture_type.h"
-#include "src/tint/sem/sampler_type.h"
-#include "src/tint/sem/storage_texture_type.h"
+#include "src/tint/sem/depth_texture.h"
+#include "src/tint/sem/multisampled_texture.h"
+#include "src/tint/sem/sampled_texture.h"
+#include "src/tint/sem/sampler.h"
+#include "src/tint/sem/storage_texture.h"
 #include "src/tint/writer/hlsl/test_helper.h"
 
+using ::testing::HasSubstr;
+
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::hlsl {
 namespace {
 
-using ::testing::HasSubstr;
-
 using HlslGeneratorImplTest_Type = TestHelper;
 
 TEST_F(HlslGeneratorImplTest_Type, EmitType_Array) {
-  auto* arr = ty.array<bool, 4>();
-  Global("G", arr, ast::StorageClass::kPrivate);
+    auto* arr = ty.array<bool, 4>();
+    Global("G", arr, ast::StorageClass::kPrivate);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, program->TypeOf(arr), ast::StorageClass::kNone,
-                           ast::Access::kReadWrite, "ary"))
-      << gen.error();
-  EXPECT_EQ(out.str(), "bool ary[4]");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, program->TypeOf(arr), ast::StorageClass::kNone,
+                             ast::Access::kReadWrite, "ary"))
+        << gen.error();
+    EXPECT_EQ(out.str(), "bool ary[4]");
 }
 
 TEST_F(HlslGeneratorImplTest_Type, EmitType_ArrayOfArray) {
-  auto* arr = ty.array(ty.array<bool, 4>(), 5);
-  Global("G", arr, ast::StorageClass::kPrivate);
+    auto* arr = ty.array(ty.array<bool, 4>(), 5_u);
+    Global("G", arr, ast::StorageClass::kPrivate);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, program->TypeOf(arr), ast::StorageClass::kNone,
-                           ast::Access::kReadWrite, "ary"))
-      << gen.error();
-  EXPECT_EQ(out.str(), "bool ary[5][4]");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, program->TypeOf(arr), ast::StorageClass::kNone,
+                             ast::Access::kReadWrite, "ary"))
+        << gen.error();
+    EXPECT_EQ(out.str(), "bool ary[5][4]");
 }
 
 TEST_F(HlslGeneratorImplTest_Type, EmitType_ArrayOfArrayOfArray) {
-  auto* arr = ty.array(ty.array(ty.array<bool, 4>(), 5), 6);
-  Global("G", arr, ast::StorageClass::kPrivate);
+    auto* arr = ty.array(ty.array(ty.array<bool, 4>(), 5_u), 6_u);
+    Global("G", arr, ast::StorageClass::kPrivate);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, program->TypeOf(arr), ast::StorageClass::kNone,
-                           ast::Access::kReadWrite, "ary"))
-      << gen.error();
-  EXPECT_EQ(out.str(), "bool ary[6][5][4]");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, program->TypeOf(arr), ast::StorageClass::kNone,
+                             ast::Access::kReadWrite, "ary"))
+        << gen.error();
+    EXPECT_EQ(out.str(), "bool ary[6][5][4]");
 }
 
 TEST_F(HlslGeneratorImplTest_Type, EmitType_Array_WithoutName) {
-  auto* arr = ty.array<bool, 4>();
-  Global("G", arr, ast::StorageClass::kPrivate);
+    auto* arr = ty.array<bool, 4>();
+    Global("G", arr, ast::StorageClass::kPrivate);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, program->TypeOf(arr), ast::StorageClass::kNone,
-                           ast::Access::kReadWrite, ""))
-      << gen.error();
-  EXPECT_EQ(out.str(), "bool[4]");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, program->TypeOf(arr), ast::StorageClass::kNone,
+                             ast::Access::kReadWrite, ""))
+        << gen.error();
+    EXPECT_EQ(out.str(), "bool[4]");
 }
 
 TEST_F(HlslGeneratorImplTest_Type, EmitType_Bool) {
-  auto* bool_ = create<sem::Bool>();
+    auto* bool_ = create<sem::Bool>();
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, bool_, ast::StorageClass::kNone,
-                           ast::Access::kReadWrite, ""))
-      << gen.error();
-  EXPECT_EQ(out.str(), "bool");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, bool_, ast::StorageClass::kNone, ast::Access::kReadWrite, ""))
+        << gen.error();
+    EXPECT_EQ(out.str(), "bool");
 }
 
 TEST_F(HlslGeneratorImplTest_Type, EmitType_F32) {
-  auto* f32 = create<sem::F32>();
+    auto* f32 = create<sem::F32>();
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, f32, ast::StorageClass::kNone,
-                           ast::Access::kReadWrite, ""))
-      << gen.error();
-  EXPECT_EQ(out.str(), "float");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, f32, ast::StorageClass::kNone, ast::Access::kReadWrite, ""))
+        << gen.error();
+    EXPECT_EQ(out.str(), "float");
 }
 
 TEST_F(HlslGeneratorImplTest_Type, EmitType_I32) {
-  auto* i32 = create<sem::I32>();
+    auto* i32 = create<sem::I32>();
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, i32, ast::StorageClass::kNone,
-                           ast::Access::kReadWrite, ""))
-      << gen.error();
-  EXPECT_EQ(out.str(), "int");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, i32, ast::StorageClass::kNone, ast::Access::kReadWrite, ""))
+        << gen.error();
+    EXPECT_EQ(out.str(), "int");
 }
 
 TEST_F(HlslGeneratorImplTest_Type, EmitType_Matrix) {
-  auto* f32 = create<sem::F32>();
-  auto* vec3 = create<sem::Vector>(f32, 3u);
-  auto* mat2x3 = create<sem::Matrix>(vec3, 2u);
+    auto* f32 = create<sem::F32>();
+    auto* vec3 = create<sem::Vector>(f32, 3u);
+    auto* mat2x3 = create<sem::Matrix>(vec3, 2u);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, mat2x3, ast::StorageClass::kNone,
-                           ast::Access::kReadWrite, ""))
-      << gen.error();
-  EXPECT_EQ(out.str(), "float2x3");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, mat2x3, ast::StorageClass::kNone, ast::Access::kReadWrite, ""))
+        << gen.error();
+    EXPECT_EQ(out.str(), "float2x3");
 }
 
 TEST_F(HlslGeneratorImplTest_Type, EmitType_StructDecl) {
-  auto* s = Structure("S", {
-                               Member("a", ty.i32()),
-                               Member("b", ty.f32()),
-                           });
-  Global("g", ty.Of(s), ast::StorageClass::kPrivate);
+    auto* s = Structure("S", {
+                                 Member("a", ty.i32()),
+                                 Member("b", ty.f32()),
+                             });
+    Global("g", ty.Of(s), ast::StorageClass::kPrivate);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  TextGenerator::TextBuffer buf;
-  auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
-  ASSERT_TRUE(gen.EmitStructType(&buf, sem_s)) << gen.error();
-  EXPECT_EQ(buf.String(), R"(struct S {
+    TextGenerator::TextBuffer buf;
+    auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
+    ASSERT_TRUE(gen.EmitStructType(&buf, sem_s)) << gen.error();
+    EXPECT_EQ(buf.String(), R"(struct S {
   int a;
   float b;
 };
@@ -151,50 +149,49 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Type, EmitType_StructDecl_OmittedIfStorageBuffer) {
-  auto* s = Structure("S", {
-                               Member("a", ty.i32()),
-                               Member("b", ty.f32()),
-                           });
-  Global("g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    auto* s = Structure("S", {
+                                 Member("a", ty.i32()),
+                                 Member("b", ty.f32()),
+                             });
+    Global("g", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), "RWByteAddressBuffer g : register(u0, space0);\n");
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), "RWByteAddressBuffer g : register(u0, space0);\n");
 }
 
 TEST_F(HlslGeneratorImplTest_Type, EmitType_Struct) {
-  auto* s = Structure("S", {
-                               Member("a", ty.i32()),
-                               Member("b", ty.f32()),
-                           });
-  Global("g", ty.Of(s), ast::StorageClass::kPrivate);
+    auto* s = Structure("S", {
+                                 Member("a", ty.i32()),
+                                 Member("b", ty.f32()),
+                             });
+    Global("g", ty.Of(s), ast::StorageClass::kPrivate);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, sem_s, ast::StorageClass::kNone,
-                           ast::Access::kReadWrite, ""))
-      << gen.error();
-  EXPECT_EQ(out.str(), "S");
+    auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, sem_s, ast::StorageClass::kNone, ast::Access::kReadWrite, ""))
+        << gen.error();
+    EXPECT_EQ(out.str(), "S");
 }
 
 TEST_F(HlslGeneratorImplTest_Type, EmitType_Struct_NameCollision) {
-  auto* s = Structure("S", {
-                               Member("double", ty.i32()),
-                               Member("float", ty.f32()),
-                           });
-  Global("g", ty.Of(s), ast::StorageClass::kPrivate);
+    auto* s = Structure("S", {
+                                 Member("double", ty.i32()),
+                                 Member("float", ty.f32()),
+                             });
+    Global("g", ty.Of(s), ast::StorageClass::kPrivate);
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr(R"(struct S {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr(R"(struct S {
   int tint_symbol;
   float tint_symbol_1;
 };
@@ -202,18 +199,18 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Type, EmitType_Struct_WithOffsetAttributes) {
-  auto* s = Structure("S", {
-                               Member("a", ty.i32(), {MemberOffset(0)}),
-                               Member("b", ty.f32(), {MemberOffset(8)}),
-                           });
-  Global("g", ty.Of(s), ast::StorageClass::kPrivate);
+    auto* s = Structure("S", {
+                                 Member("a", ty.i32(), {MemberOffset(0)}),
+                                 Member("b", ty.f32(), {MemberOffset(8)}),
+                             });
+    Global("g", ty.Of(s), ast::StorageClass::kPrivate);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  TextGenerator::TextBuffer buf;
-  auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
-  ASSERT_TRUE(gen.EmitStructType(&buf, sem_s)) << gen.error();
-  EXPECT_EQ(buf.String(), R"(struct S {
+    TextGenerator::TextBuffer buf;
+    auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
+    ASSERT_TRUE(gen.EmitStructType(&buf, sem_s)) << gen.error();
+    EXPECT_EQ(buf.String(), R"(struct S {
   int a;
   float b;
 };
@@ -221,347 +218,323 @@
 }
 
 TEST_F(HlslGeneratorImplTest_Type, EmitType_U32) {
-  auto* u32 = create<sem::U32>();
+    auto* u32 = create<sem::U32>();
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, u32, ast::StorageClass::kNone,
-                           ast::Access::kReadWrite, ""))
-      << gen.error();
-  EXPECT_EQ(out.str(), "uint");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, u32, ast::StorageClass::kNone, ast::Access::kReadWrite, ""))
+        << gen.error();
+    EXPECT_EQ(out.str(), "uint");
 }
 
 TEST_F(HlslGeneratorImplTest_Type, EmitType_Vector) {
-  auto* f32 = create<sem::F32>();
-  auto* vec3 = create<sem::Vector>(f32, 3u);
+    auto* f32 = create<sem::F32>();
+    auto* vec3 = create<sem::Vector>(f32, 3u);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, vec3, ast::StorageClass::kNone,
-                           ast::Access::kReadWrite, ""))
-      << gen.error();
-  EXPECT_EQ(out.str(), "float3");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, vec3, ast::StorageClass::kNone, ast::Access::kReadWrite, ""))
+        << gen.error();
+    EXPECT_EQ(out.str(), "float3");
 }
 
 TEST_F(HlslGeneratorImplTest_Type, EmitType_Void) {
-  auto* void_ = create<sem::Void>();
+    auto* void_ = create<sem::Void>();
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, void_, ast::StorageClass::kNone,
-                           ast::Access::kReadWrite, ""))
-      << gen.error();
-  EXPECT_EQ(out.str(), "void");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, void_, ast::StorageClass::kNone, ast::Access::kReadWrite, ""))
+        << gen.error();
+    EXPECT_EQ(out.str(), "void");
 }
 
 TEST_F(HlslGeneratorImplTest_Type, EmitSampler) {
-  auto* sampler = create<sem::Sampler>(ast::SamplerKind::kSampler);
+    auto* sampler = create<sem::Sampler>(ast::SamplerKind::kSampler);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, sampler, ast::StorageClass::kNone,
-                           ast::Access::kReadWrite, ""))
-      << gen.error();
-  EXPECT_EQ(out.str(), "SamplerState");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, sampler, ast::StorageClass::kNone, ast::Access::kReadWrite, ""))
+        << gen.error();
+    EXPECT_EQ(out.str(), "SamplerState");
 }
 
 TEST_F(HlslGeneratorImplTest_Type, EmitSamplerComparison) {
-  auto* sampler = create<sem::Sampler>(ast::SamplerKind::kComparisonSampler);
+    auto* sampler = create<sem::Sampler>(ast::SamplerKind::kComparisonSampler);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, sampler, ast::StorageClass::kNone,
-                           ast::Access::kReadWrite, ""))
-      << gen.error();
-  EXPECT_EQ(out.str(), "SamplerComparisonState");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, sampler, ast::StorageClass::kNone, ast::Access::kReadWrite, ""))
+        << gen.error();
+    EXPECT_EQ(out.str(), "SamplerComparisonState");
 }
 
 struct HlslDepthTextureData {
-  ast::TextureDimension dim;
-  std::string result;
+    ast::TextureDimension dim;
+    std::string result;
 };
 inline std::ostream& operator<<(std::ostream& out, HlslDepthTextureData data) {
-  out << data.dim;
-  return out;
+    out << data.dim;
+    return out;
 }
 using HlslDepthTexturesTest = TestParamHelper<HlslDepthTextureData>;
 TEST_P(HlslDepthTexturesTest, Emit) {
-  auto params = GetParam();
+    auto params = GetParam();
 
-  auto* t = ty.depth_texture(params.dim);
+    auto* t = ty.depth_texture(params.dim);
 
-  Global("tex", t,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(1),
-             create<ast::GroupAttribute>(2),
-         });
+    Global("tex", t,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(1),
+               create<ast::GroupAttribute>(2),
+           });
 
-  Func("main", {}, ty.void_(), {CallStmt(Call("textureDimensions", "tex"))},
-       {Stage(ast::PipelineStage::kFragment)});
+    Func("main", {}, ty.void_(), {CallStmt(Call("textureDimensions", "tex"))},
+         {Stage(ast::PipelineStage::kFragment)});
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr(params.result));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr(params.result));
 }
 INSTANTIATE_TEST_SUITE_P(
     HlslGeneratorImplTest_Type,
     HlslDepthTexturesTest,
-    testing::Values(
-        HlslDepthTextureData{ast::TextureDimension::k2d,
-                             "Texture2D tex : register(t1, space2);"},
-        HlslDepthTextureData{ast::TextureDimension::k2dArray,
-                             "Texture2DArray tex : register(t1, space2);"},
-        HlslDepthTextureData{ast::TextureDimension::kCube,
-                             "TextureCube tex : register(t1, space2);"},
-        HlslDepthTextureData{ast::TextureDimension::kCubeArray,
-                             "TextureCubeArray tex : register(t1, space2);"}));
+    testing::Values(HlslDepthTextureData{ast::TextureDimension::k2d,
+                                         "Texture2D tex : register(t1, space2);"},
+                    HlslDepthTextureData{ast::TextureDimension::k2dArray,
+                                         "Texture2DArray tex : register(t1, space2);"},
+                    HlslDepthTextureData{ast::TextureDimension::kCube,
+                                         "TextureCube tex : register(t1, space2);"},
+                    HlslDepthTextureData{ast::TextureDimension::kCubeArray,
+                                         "TextureCubeArray tex : register(t1, space2);"}));
 
 using HlslDepthMultisampledTexturesTest = TestHelper;
 TEST_F(HlslDepthMultisampledTexturesTest, Emit) {
-  auto* t = ty.depth_multisampled_texture(ast::TextureDimension::k2d);
+    auto* t = ty.depth_multisampled_texture(ast::TextureDimension::k2d);
 
-  Global("tex", t,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(1),
-             create<ast::GroupAttribute>(2),
-         });
+    Global("tex", t,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(1),
+               create<ast::GroupAttribute>(2),
+           });
 
-  Func("main", {}, ty.void_(), {CallStmt(Call("textureDimensions", "tex"))},
-       {Stage(ast::PipelineStage::kFragment)});
+    Func("main", {}, ty.void_(), {CallStmt(Call("textureDimensions", "tex"))},
+         {Stage(ast::PipelineStage::kFragment)});
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(),
-              HasSubstr("Texture2DMS<float4> tex : register(t1, space2);"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("Texture2DMS<float4> tex : register(t1, space2);"));
 }
 
 enum class TextureDataType { F32, U32, I32 };
 struct HlslSampledTextureData {
-  ast::TextureDimension dim;
-  TextureDataType datatype;
-  std::string result;
+    ast::TextureDimension dim;
+    TextureDataType datatype;
+    std::string result;
 };
-inline std::ostream& operator<<(std::ostream& out,
-                                HlslSampledTextureData data) {
-  out << data.dim;
-  return out;
+inline std::ostream& operator<<(std::ostream& out, HlslSampledTextureData data) {
+    out << data.dim;
+    return out;
 }
 using HlslSampledTexturesTest = TestParamHelper<HlslSampledTextureData>;
 TEST_P(HlslSampledTexturesTest, Emit) {
-  auto params = GetParam();
+    auto params = GetParam();
 
-  const ast::Type* datatype = nullptr;
-  switch (params.datatype) {
-    case TextureDataType::F32:
-      datatype = ty.f32();
-      break;
-    case TextureDataType::U32:
-      datatype = ty.u32();
-      break;
-    case TextureDataType::I32:
-      datatype = ty.i32();
-      break;
-  }
-  auto* t = ty.sampled_texture(params.dim, datatype);
+    const ast::Type* datatype = nullptr;
+    switch (params.datatype) {
+        case TextureDataType::F32:
+            datatype = ty.f32();
+            break;
+        case TextureDataType::U32:
+            datatype = ty.u32();
+            break;
+        case TextureDataType::I32:
+            datatype = ty.i32();
+            break;
+    }
+    auto* t = ty.sampled_texture(params.dim, datatype);
 
-  Global("tex", t,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(1),
-             create<ast::GroupAttribute>(2),
-         });
+    Global("tex", t,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(1),
+               create<ast::GroupAttribute>(2),
+           });
 
-  Func("main", {}, ty.void_(), {CallStmt(Call("textureDimensions", "tex"))},
-       {Stage(ast::PipelineStage::kFragment)});
+    Func("main", {}, ty.void_(), {CallStmt(Call("textureDimensions", "tex"))},
+         {Stage(ast::PipelineStage::kFragment)});
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr(params.result));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr(params.result));
 }
-INSTANTIATE_TEST_SUITE_P(
-    HlslGeneratorImplTest_Type,
-    HlslSampledTexturesTest,
-    testing::Values(
-        HlslSampledTextureData{
-            ast::TextureDimension::k1d,
-            TextureDataType::F32,
-            "Texture1D<float4> tex : register(t1, space2);",
-        },
-        HlslSampledTextureData{
-            ast::TextureDimension::k2d,
-            TextureDataType::F32,
-            "Texture2D<float4> tex : register(t1, space2);",
-        },
-        HlslSampledTextureData{
-            ast::TextureDimension::k2dArray,
-            TextureDataType::F32,
-            "Texture2DArray<float4> tex : register(t1, space2);",
-        },
-        HlslSampledTextureData{
-            ast::TextureDimension::k3d,
-            TextureDataType::F32,
-            "Texture3D<float4> tex : register(t1, space2);",
-        },
-        HlslSampledTextureData{
-            ast::TextureDimension::kCube,
-            TextureDataType::F32,
-            "TextureCube<float4> tex : register(t1, space2);",
-        },
-        HlslSampledTextureData{
-            ast::TextureDimension::kCubeArray,
-            TextureDataType::F32,
-            "TextureCubeArray<float4> tex : register(t1, space2);",
-        },
-        HlslSampledTextureData{
-            ast::TextureDimension::k1d,
-            TextureDataType::U32,
-            "Texture1D<uint4> tex : register(t1, space2);",
-        },
-        HlslSampledTextureData{
-            ast::TextureDimension::k2d,
-            TextureDataType::U32,
-            "Texture2D<uint4> tex : register(t1, space2);",
-        },
-        HlslSampledTextureData{
-            ast::TextureDimension::k2dArray,
-            TextureDataType::U32,
-            "Texture2DArray<uint4> tex : register(t1, space2);",
-        },
-        HlslSampledTextureData{
-            ast::TextureDimension::k3d,
-            TextureDataType::U32,
-            "Texture3D<uint4> tex : register(t1, space2);",
-        },
-        HlslSampledTextureData{
-            ast::TextureDimension::kCube,
-            TextureDataType::U32,
-            "TextureCube<uint4> tex : register(t1, space2);",
-        },
-        HlslSampledTextureData{
-            ast::TextureDimension::kCubeArray,
-            TextureDataType::U32,
-            "TextureCubeArray<uint4> tex : register(t1, space2);",
-        },
-        HlslSampledTextureData{
-            ast::TextureDimension::k1d,
-            TextureDataType::I32,
-            "Texture1D<int4> tex : register(t1, space2);",
-        },
-        HlslSampledTextureData{
-            ast::TextureDimension::k2d,
-            TextureDataType::I32,
-            "Texture2D<int4> tex : register(t1, space2);",
-        },
-        HlslSampledTextureData{
-            ast::TextureDimension::k2dArray,
-            TextureDataType::I32,
-            "Texture2DArray<int4> tex : register(t1, space2);",
-        },
-        HlslSampledTextureData{
-            ast::TextureDimension::k3d,
-            TextureDataType::I32,
-            "Texture3D<int4> tex : register(t1, space2);",
-        },
-        HlslSampledTextureData{
-            ast::TextureDimension::kCube,
-            TextureDataType::I32,
-            "TextureCube<int4> tex : register(t1, space2);",
-        },
-        HlslSampledTextureData{
-            ast::TextureDimension::kCubeArray,
-            TextureDataType::I32,
-            "TextureCubeArray<int4> tex : register(t1, space2);",
-        }));
+INSTANTIATE_TEST_SUITE_P(HlslGeneratorImplTest_Type,
+                         HlslSampledTexturesTest,
+                         testing::Values(
+                             HlslSampledTextureData{
+                                 ast::TextureDimension::k1d,
+                                 TextureDataType::F32,
+                                 "Texture1D<float4> tex : register(t1, space2);",
+                             },
+                             HlslSampledTextureData{
+                                 ast::TextureDimension::k2d,
+                                 TextureDataType::F32,
+                                 "Texture2D<float4> tex : register(t1, space2);",
+                             },
+                             HlslSampledTextureData{
+                                 ast::TextureDimension::k2dArray,
+                                 TextureDataType::F32,
+                                 "Texture2DArray<float4> tex : register(t1, space2);",
+                             },
+                             HlslSampledTextureData{
+                                 ast::TextureDimension::k3d,
+                                 TextureDataType::F32,
+                                 "Texture3D<float4> tex : register(t1, space2);",
+                             },
+                             HlslSampledTextureData{
+                                 ast::TextureDimension::kCube,
+                                 TextureDataType::F32,
+                                 "TextureCube<float4> tex : register(t1, space2);",
+                             },
+                             HlslSampledTextureData{
+                                 ast::TextureDimension::kCubeArray,
+                                 TextureDataType::F32,
+                                 "TextureCubeArray<float4> tex : register(t1, space2);",
+                             },
+                             HlslSampledTextureData{
+                                 ast::TextureDimension::k1d,
+                                 TextureDataType::U32,
+                                 "Texture1D<uint4> tex : register(t1, space2);",
+                             },
+                             HlslSampledTextureData{
+                                 ast::TextureDimension::k2d,
+                                 TextureDataType::U32,
+                                 "Texture2D<uint4> tex : register(t1, space2);",
+                             },
+                             HlslSampledTextureData{
+                                 ast::TextureDimension::k2dArray,
+                                 TextureDataType::U32,
+                                 "Texture2DArray<uint4> tex : register(t1, space2);",
+                             },
+                             HlslSampledTextureData{
+                                 ast::TextureDimension::k3d,
+                                 TextureDataType::U32,
+                                 "Texture3D<uint4> tex : register(t1, space2);",
+                             },
+                             HlslSampledTextureData{
+                                 ast::TextureDimension::kCube,
+                                 TextureDataType::U32,
+                                 "TextureCube<uint4> tex : register(t1, space2);",
+                             },
+                             HlslSampledTextureData{
+                                 ast::TextureDimension::kCubeArray,
+                                 TextureDataType::U32,
+                                 "TextureCubeArray<uint4> tex : register(t1, space2);",
+                             },
+                             HlslSampledTextureData{
+                                 ast::TextureDimension::k1d,
+                                 TextureDataType::I32,
+                                 "Texture1D<int4> tex : register(t1, space2);",
+                             },
+                             HlslSampledTextureData{
+                                 ast::TextureDimension::k2d,
+                                 TextureDataType::I32,
+                                 "Texture2D<int4> tex : register(t1, space2);",
+                             },
+                             HlslSampledTextureData{
+                                 ast::TextureDimension::k2dArray,
+                                 TextureDataType::I32,
+                                 "Texture2DArray<int4> tex : register(t1, space2);",
+                             },
+                             HlslSampledTextureData{
+                                 ast::TextureDimension::k3d,
+                                 TextureDataType::I32,
+                                 "Texture3D<int4> tex : register(t1, space2);",
+                             },
+                             HlslSampledTextureData{
+                                 ast::TextureDimension::kCube,
+                                 TextureDataType::I32,
+                                 "TextureCube<int4> tex : register(t1, space2);",
+                             },
+                             HlslSampledTextureData{
+                                 ast::TextureDimension::kCubeArray,
+                                 TextureDataType::I32,
+                                 "TextureCubeArray<int4> tex : register(t1, space2);",
+                             }));
 
 TEST_F(HlslGeneratorImplTest_Type, EmitMultisampledTexture) {
-  auto* f32 = create<sem::F32>();
-  auto* s = create<sem::MultisampledTexture>(ast::TextureDimension::k2d, f32);
+    auto* f32 = create<sem::F32>();
+    auto* s = create<sem::MultisampledTexture>(ast::TextureDimension::k2d, f32);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, s, ast::StorageClass::kNone,
-                           ast::Access::kReadWrite, ""))
-      << gen.error();
-  EXPECT_EQ(out.str(), "Texture2DMS<float4>");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, s, ast::StorageClass::kNone, ast::Access::kReadWrite, ""))
+        << gen.error();
+    EXPECT_EQ(out.str(), "Texture2DMS<float4>");
 }
 
 struct HlslStorageTextureData {
-  ast::TextureDimension dim;
-  ast::TexelFormat imgfmt;
-  std::string result;
+    ast::TextureDimension dim;
+    ast::TexelFormat imgfmt;
+    std::string result;
 };
-inline std::ostream& operator<<(std::ostream& out,
-                                HlslStorageTextureData data) {
-  out << data.dim;
-  return out;
+inline std::ostream& operator<<(std::ostream& out, HlslStorageTextureData data) {
+    out << data.dim;
+    return out;
 }
 using HlslStorageTexturesTest = TestParamHelper<HlslStorageTextureData>;
 TEST_P(HlslStorageTexturesTest, Emit) {
-  auto params = GetParam();
+    auto params = GetParam();
 
-  auto* t = ty.storage_texture(params.dim, params.imgfmt, ast::Access::kWrite);
+    auto* t = ty.storage_texture(params.dim, params.imgfmt, ast::Access::kWrite);
 
-  Global("tex", t, ast::AttributeList{GroupAndBinding(2, 1)});
+    Global("tex", t, ast::AttributeList{GroupAndBinding(2, 1)});
 
-  Func("main", {}, ty.void_(), {CallStmt(Call("textureDimensions", "tex"))},
-       {Stage(ast::PipelineStage::kFragment)});
+    Func("main", {}, ty.void_(), {CallStmt(Call("textureDimensions", "tex"))},
+         {Stage(ast::PipelineStage::kFragment)});
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr(params.result));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr(params.result));
 }
 INSTANTIATE_TEST_SUITE_P(
     HlslGeneratorImplTest_Type,
     HlslStorageTexturesTest,
     testing::Values(
-        HlslStorageTextureData{
-            ast::TextureDimension::k1d, ast::TexelFormat::kRgba8Unorm,
-            "RWTexture1D<float4> tex : register(u1, space2);"},
-        HlslStorageTextureData{
-            ast::TextureDimension::k2d, ast::TexelFormat::kRgba16Float,
-            "RWTexture2D<float4> tex : register(u1, space2);"},
-        HlslStorageTextureData{
-            ast::TextureDimension::k2dArray, ast::TexelFormat::kR32Float,
-            "RWTexture2DArray<float4> tex : register(u1, space2);"},
-        HlslStorageTextureData{
-            ast::TextureDimension::k3d, ast::TexelFormat::kRg32Float,
-            "RWTexture3D<float4> tex : register(u1, space2);"},
-        HlslStorageTextureData{
-            ast::TextureDimension::k1d, ast::TexelFormat::kRgba32Float,
-            "RWTexture1D<float4> tex : register(u1, space2);"},
-        HlslStorageTextureData{
-            ast::TextureDimension::k2d, ast::TexelFormat::kRgba16Uint,
-            "RWTexture2D<uint4> tex : register(u1, space2);"},
-        HlslStorageTextureData{
-            ast::TextureDimension::k2dArray, ast::TexelFormat::kR32Uint,
-            "RWTexture2DArray<uint4> tex : register(u1, space2);"},
-        HlslStorageTextureData{
-            ast::TextureDimension::k3d, ast::TexelFormat::kRg32Uint,
-            "RWTexture3D<uint4> tex : register(u1, space2);"},
-        HlslStorageTextureData{
-            ast::TextureDimension::k1d, ast::TexelFormat::kRgba32Uint,
-            "RWTexture1D<uint4> tex : register(u1, space2);"},
-        HlslStorageTextureData{ast::TextureDimension::k2d,
-                               ast::TexelFormat::kRgba16Sint,
+        HlslStorageTextureData{ast::TextureDimension::k1d, ast::TexelFormat::kRgba8Unorm,
+                               "RWTexture1D<float4> tex : register(u1, space2);"},
+        HlslStorageTextureData{ast::TextureDimension::k2d, ast::TexelFormat::kRgba16Float,
+                               "RWTexture2D<float4> tex : register(u1, space2);"},
+        HlslStorageTextureData{ast::TextureDimension::k2dArray, ast::TexelFormat::kR32Float,
+                               "RWTexture2DArray<float4> tex : register(u1, space2);"},
+        HlslStorageTextureData{ast::TextureDimension::k3d, ast::TexelFormat::kRg32Float,
+                               "RWTexture3D<float4> tex : register(u1, space2);"},
+        HlslStorageTextureData{ast::TextureDimension::k1d, ast::TexelFormat::kRgba32Float,
+                               "RWTexture1D<float4> tex : register(u1, space2);"},
+        HlslStorageTextureData{ast::TextureDimension::k2d, ast::TexelFormat::kRgba16Uint,
+                               "RWTexture2D<uint4> tex : register(u1, space2);"},
+        HlslStorageTextureData{ast::TextureDimension::k2dArray, ast::TexelFormat::kR32Uint,
+                               "RWTexture2DArray<uint4> tex : register(u1, space2);"},
+        HlslStorageTextureData{ast::TextureDimension::k3d, ast::TexelFormat::kRg32Uint,
+                               "RWTexture3D<uint4> tex : register(u1, space2);"},
+        HlslStorageTextureData{ast::TextureDimension::k1d, ast::TexelFormat::kRgba32Uint,
+                               "RWTexture1D<uint4> tex : register(u1, space2);"},
+        HlslStorageTextureData{ast::TextureDimension::k2d, ast::TexelFormat::kRgba16Sint,
                                "RWTexture2D<int4> tex : register(u1, space2);"},
-        HlslStorageTextureData{
-            ast::TextureDimension::k2dArray, ast::TexelFormat::kR32Sint,
-            "RWTexture2DArray<int4> tex : register(u1, space2);"},
-        HlslStorageTextureData{ast::TextureDimension::k3d,
-                               ast::TexelFormat::kRg32Sint,
+        HlslStorageTextureData{ast::TextureDimension::k2dArray, ast::TexelFormat::kR32Sint,
+                               "RWTexture2DArray<int4> tex : register(u1, space2);"},
+        HlslStorageTextureData{ast::TextureDimension::k3d, ast::TexelFormat::kRg32Sint,
                                "RWTexture3D<int4> tex : register(u1, space2);"},
-        HlslStorageTextureData{
-            ast::TextureDimension::k1d, ast::TexelFormat::kRgba32Sint,
-            "RWTexture1D<int4> tex : register(u1, space2);"}));
+        HlslStorageTextureData{ast::TextureDimension::k1d, ast::TexelFormat::kRgba32Sint,
+                               "RWTexture1D<int4> tex : register(u1, space2);"}));
 
 }  // namespace
 }  // namespace tint::writer::hlsl
diff --git a/src/tint/writer/hlsl/generator_impl_unary_op_test.cc b/src/tint/writer/hlsl/generator_impl_unary_op_test.cc
index 3217a01..c9abf1f 100644
--- a/src/tint/writer/hlsl/generator_impl_unary_op_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_unary_op_test.cc
@@ -20,70 +20,65 @@
 using HlslUnaryOpTest = TestHelper;
 
 TEST_F(HlslUnaryOpTest, AddressOf) {
-  Global("expr", ty.f32(), ast::StorageClass::kPrivate);
-  auto* op =
-      create<ast::UnaryOpExpression>(ast::UnaryOp::kAddressOf, Expr("expr"));
-  WrapInFunction(op);
+    Global("expr", ty.f32(), ast::StorageClass::kPrivate);
+    auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kAddressOf, Expr("expr"));
+    WrapInFunction(op);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
-  EXPECT_EQ(out.str(), "expr");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
+    EXPECT_EQ(out.str(), "expr");
 }
 
 TEST_F(HlslUnaryOpTest, Complement) {
-  Global("expr", ty.u32(), ast::StorageClass::kPrivate);
-  auto* op =
-      create<ast::UnaryOpExpression>(ast::UnaryOp::kComplement, Expr("expr"));
-  WrapInFunction(op);
+    Global("expr", ty.u32(), ast::StorageClass::kPrivate);
+    auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kComplement, Expr("expr"));
+    WrapInFunction(op);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
-  EXPECT_EQ(out.str(), "~(expr)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
+    EXPECT_EQ(out.str(), "~(expr)");
 }
 
 TEST_F(HlslUnaryOpTest, Indirection) {
-  Global("G", ty.f32(), ast::StorageClass::kPrivate);
-  auto* p = Const(
-      "expr", nullptr,
-      create<ast::UnaryOpExpression>(ast::UnaryOp::kAddressOf, Expr("G")));
-  auto* op =
-      create<ast::UnaryOpExpression>(ast::UnaryOp::kIndirection, Expr("expr"));
-  WrapInFunction(p, op);
+    Global("G", ty.f32(), ast::StorageClass::kPrivate);
+    auto* p =
+        Let("expr", nullptr, create<ast::UnaryOpExpression>(ast::UnaryOp::kAddressOf, Expr("G")));
+    auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kIndirection, Expr("expr"));
+    WrapInFunction(p, op);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
-  EXPECT_EQ(out.str(), "expr");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
+    EXPECT_EQ(out.str(), "expr");
 }
 
 TEST_F(HlslUnaryOpTest, Not) {
-  Global("expr", ty.bool_(), ast::StorageClass::kPrivate);
-  auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kNot, Expr("expr"));
-  WrapInFunction(op);
+    Global("expr", ty.bool_(), ast::StorageClass::kPrivate);
+    auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kNot, Expr("expr"));
+    WrapInFunction(op);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
-  EXPECT_EQ(out.str(), "!(expr)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
+    EXPECT_EQ(out.str(), "!(expr)");
 }
 
 TEST_F(HlslUnaryOpTest, Negation) {
-  Global("expr", ty.i32(), ast::StorageClass::kPrivate);
-  auto* op =
-      create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation, Expr("expr"));
-  WrapInFunction(op);
+    Global("expr", ty.i32(), ast::StorageClass::kPrivate);
+    auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation, Expr("expr"));
+    WrapInFunction(op);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
-  EXPECT_EQ(out.str(), "-(expr)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
+    EXPECT_EQ(out.str(), "-(expr)");
 }
 }  // namespace
 }  // namespace tint::writer::hlsl
diff --git a/src/tint/writer/hlsl/generator_impl_variable_decl_statement_test.cc b/src/tint/writer/hlsl/generator_impl_variable_decl_statement_test.cc
index 1188aed..580ad46 100644
--- a/src/tint/writer/hlsl/generator_impl_variable_decl_statement_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_variable_decl_statement_test.cc
@@ -24,98 +24,94 @@
 using HlslGeneratorImplTest_VariableDecl = TestHelper;
 
 TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement) {
-  auto* var = Var("a", ty.f32());
-  auto* stmt = Decl(var);
-  WrapInFunction(stmt);
+    auto* var = Var("a", ty.f32());
+    auto* stmt = Decl(var);
+    WrapInFunction(stmt);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
-  EXPECT_EQ(gen.result(), "  float a = 0.0f;\n");
+    ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
+    EXPECT_EQ(gen.result(), "  float a = 0.0f;\n");
 }
 
 TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Const) {
-  auto* var = Const("a", ty.f32(), Construct(ty.f32()));
-  auto* stmt = Decl(var);
-  WrapInFunction(stmt);
+    auto* var = Let("a", ty.f32(), Construct(ty.f32()));
+    auto* stmt = Decl(var);
+    WrapInFunction(stmt);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
-  EXPECT_EQ(gen.result(), "  const float a = 0.0f;\n");
+    ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
+    EXPECT_EQ(gen.result(), "  const float a = 0.0f;\n");
 }
 
 TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Array) {
-  auto* var = Var("a", ty.array<f32, 5>());
+    auto* var = Var("a", ty.array<f32, 5>());
 
-  WrapInFunction(var, Expr("a"));
+    WrapInFunction(var, Expr("a"));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("  float a[5] = (float[5])0;\n"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("  float a[5] = (float[5])0;\n"));
 }
 
 TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Private) {
-  Global("a", ty.f32(), ast::StorageClass::kPrivate);
+    Global("a", ty.f32(), ast::StorageClass::kPrivate);
 
-  WrapInFunction(Expr("a"));
+    WrapInFunction(Expr("a"));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("  static float a = 0.0f;\n"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("  static float a = 0.0f;\n"));
 }
 
-TEST_F(HlslGeneratorImplTest_VariableDecl,
-       Emit_VariableDeclStatement_Initializer_Private) {
-  Global("initializer", ty.f32(), ast::StorageClass::kPrivate);
-  Global("a", ty.f32(), ast::StorageClass::kPrivate, Expr("initializer"));
+TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Initializer_Private) {
+    Global("initializer", ty.f32(), ast::StorageClass::kPrivate);
+    Global("a", ty.f32(), ast::StorageClass::kPrivate, Expr("initializer"));
 
-  WrapInFunction(Expr("a"));
+    WrapInFunction(Expr("a"));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr(R"(float a = initializer;
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr(R"(float a = initializer;
 )"));
 }
 
-TEST_F(HlslGeneratorImplTest_VariableDecl,
-       Emit_VariableDeclStatement_Initializer_ZeroVec) {
-  auto* var = Var("a", ty.vec3<f32>(), ast::StorageClass::kNone, vec3<f32>());
+TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Initializer_ZeroVec) {
+    auto* var = Var("a", ty.vec3<f32>(), ast::StorageClass::kNone, vec3<f32>());
 
-  auto* stmt = Decl(var);
-  WrapInFunction(stmt);
+    auto* stmt = Decl(var);
+    WrapInFunction(stmt);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(float3 a = float3(0.0f, 0.0f, 0.0f);
+    ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(float3 a = float3(0.0f, 0.0f, 0.0f);
 )");
 }
 
-TEST_F(HlslGeneratorImplTest_VariableDecl,
-       Emit_VariableDeclStatement_Initializer_ZeroMat) {
-  auto* var =
-      Var("a", ty.mat2x3<f32>(), ast::StorageClass::kNone, mat2x3<f32>());
+TEST_F(HlslGeneratorImplTest_VariableDecl, Emit_VariableDeclStatement_Initializer_ZeroMat) {
+    auto* var = Var("a", ty.mat2x3<f32>(), ast::StorageClass::kNone, mat2x3<f32>());
 
-  auto* stmt = Decl(var);
-  WrapInFunction(stmt);
+    auto* stmt = Decl(var);
+    WrapInFunction(stmt);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
-  EXPECT_EQ(gen.result(),
-            R"(float2x3 a = float2x3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
+    ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
+    EXPECT_EQ(gen.result(),
+              R"(float2x3 a = float2x3(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
 )");
 }
 
diff --git a/src/tint/writer/hlsl/generator_impl_workgroup_var_test.cc b/src/tint/writer/hlsl/generator_impl_workgroup_var_test.cc
index 641b8f1..466c871 100644
--- a/src/tint/writer/hlsl/generator_impl_workgroup_var_test.cc
+++ b/src/tint/writer/hlsl/generator_impl_workgroup_var_test.cc
@@ -17,40 +17,43 @@
 #include "src/tint/ast/stage_attribute.h"
 #include "src/tint/writer/hlsl/test_helper.h"
 
+using ::testing::HasSubstr;
+
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::hlsl {
 namespace {
-using ::testing::HasSubstr;
 
 using HlslGeneratorImplTest_WorkgroupVar = TestHelper;
 
 TEST_F(HlslGeneratorImplTest_WorkgroupVar, Basic) {
-  Global("wg", ty.f32(), ast::StorageClass::kWorkgroup);
+    Global("wg", ty.f32(), ast::StorageClass::kWorkgroup);
 
-  Func("main", {}, ty.void_(), {Assign("wg", 1.2f)},
-       {
-           Stage(ast::PipelineStage::kCompute),
-           WorkgroupSize(1),
-       });
-  GeneratorImpl& gen = Build();
+    Func("main", {}, ty.void_(), {Assign("wg", 1.2f)},
+         {
+             Stage(ast::PipelineStage::kCompute),
+             WorkgroupSize(1_i),
+         });
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("groupshared float wg;\n"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("groupshared float wg;\n"));
 }
 
 TEST_F(HlslGeneratorImplTest_WorkgroupVar, Aliased) {
-  auto* alias = Alias("F32", ty.f32());
+    auto* alias = Alias("F32", ty.f32());
 
-  Global("wg", ty.Of(alias), ast::StorageClass::kWorkgroup);
+    Global("wg", ty.Of(alias), ast::StorageClass::kWorkgroup);
 
-  Func("main", {}, ty.void_(), {Assign("wg", 1.2f)},
-       {
-           Stage(ast::PipelineStage::kCompute),
-           WorkgroupSize(1),
-       });
-  GeneratorImpl& gen = Build();
+    Func("main", {}, ty.void_(), {Assign("wg", 1.2f)},
+         {
+             Stage(ast::PipelineStage::kCompute),
+             WorkgroupSize(1_i),
+         });
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("groupshared float wg;\n"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("groupshared float wg;\n"));
 }
 
 }  // namespace
diff --git a/src/tint/writer/hlsl/test_helper.h b/src/tint/writer/hlsl/test_helper.h
index 089ddb9..8fd6bae 100644
--- a/src/tint/writer/hlsl/test_helper.h
+++ b/src/tint/writer/hlsl/test_helper.h
@@ -30,80 +30,73 @@
 /// Helper class for testing
 template <typename BODY>
 class TestHelperBase : public BODY, public ProgramBuilder {
- public:
-  TestHelperBase() = default;
-  ~TestHelperBase() override = default;
+  public:
+    TestHelperBase() = default;
+    ~TestHelperBase() override = default;
 
-  /// Builds the program and returns a GeneratorImpl from the program.
-  /// @note The generator is only built once. Multiple calls to Build() will
-  /// return the same GeneratorImpl without rebuilding.
-  /// @return the built generator
-  GeneratorImpl& Build() {
-    if (gen_) {
-      return *gen_;
+    /// Builds the program and returns a GeneratorImpl from the program.
+    /// @note The generator is only built once. Multiple calls to Build() will
+    /// return the same GeneratorImpl without rebuilding.
+    /// @return the built generator
+    GeneratorImpl& Build() {
+        if (gen_) {
+            return *gen_;
+        }
+        [&]() {
+            ASSERT_TRUE(IsValid()) << "Builder program is not valid\n"
+                                   << diag::Formatter().format(Diagnostics());
+        }();
+        program = std::make_unique<Program>(std::move(*this));
+        [&]() {
+            ASSERT_TRUE(program->IsValid()) << diag::Formatter().format(program->Diagnostics());
+        }();
+        gen_ = std::make_unique<GeneratorImpl>(program.get());
+        return *gen_;
     }
-    [&]() {
-      ASSERT_TRUE(IsValid()) << "Builder program is not valid\n"
-                             << diag::Formatter().format(Diagnostics());
-    }();
-    program = std::make_unique<Program>(std::move(*this));
-    [&]() {
-      ASSERT_TRUE(program->IsValid())
-          << diag::Formatter().format(program->Diagnostics());
-    }();
-    gen_ = std::make_unique<GeneratorImpl>(program.get());
-    return *gen_;
-  }
 
-  /// Builds the program, runs the program through the HLSL sanitizer
-  /// and returns a GeneratorImpl from the sanitized program.
-  /// @param options The HLSL generator options.
-  /// @note The generator is only built once. Multiple calls to Build() will
-  /// return the same GeneratorImpl without rebuilding.
-  /// @return the built generator
-  GeneratorImpl& SanitizeAndBuild(const Options& options = {}) {
-    if (gen_) {
-      return *gen_;
+    /// Builds the program, runs the program through the HLSL sanitizer
+    /// and returns a GeneratorImpl from the sanitized program.
+    /// @param options The HLSL generator options.
+    /// @note The generator is only built once. Multiple calls to Build() will
+    /// return the same GeneratorImpl without rebuilding.
+    /// @return the built generator
+    GeneratorImpl& SanitizeAndBuild(const Options& options = {}) {
+        if (gen_) {
+            return *gen_;
+        }
+        diag::Formatter formatter;
+        [&]() {
+            ASSERT_TRUE(IsValid()) << "Builder program is not valid\n"
+                                   << formatter.format(Diagnostics());
+        }();
+        program = std::make_unique<Program>(std::move(*this));
+        [&]() { ASSERT_TRUE(program->IsValid()) << formatter.format(program->Diagnostics()); }();
+
+        auto sanitized_result = Sanitize(program.get(), options);
+        [&]() {
+            ASSERT_TRUE(sanitized_result.program.IsValid())
+                << formatter.format(sanitized_result.program.Diagnostics());
+        }();
+
+        transform::Manager transform_manager;
+        transform::DataMap transform_data;
+        transform_data.Add<transform::Renamer::Config>(transform::Renamer::Target::kHlslKeywords,
+                                                       /* preserve_unicode */ true);
+        transform_manager.Add<tint::transform::Renamer>();
+        auto result = transform_manager.Run(&sanitized_result.program, transform_data);
+        [&]() {
+            ASSERT_TRUE(result.program.IsValid()) << formatter.format(result.program.Diagnostics());
+        }();
+        *program = std::move(result.program);
+        gen_ = std::make_unique<GeneratorImpl>(program.get());
+        return *gen_;
     }
-    diag::Formatter formatter;
-    [&]() {
-      ASSERT_TRUE(IsValid()) << "Builder program is not valid\n"
-                             << formatter.format(Diagnostics());
-    }();
-    program = std::make_unique<Program>(std::move(*this));
-    [&]() {
-      ASSERT_TRUE(program->IsValid())
-          << formatter.format(program->Diagnostics());
-    }();
 
-    auto sanitized_result = Sanitize(program.get(), options);
-    [&]() {
-      ASSERT_TRUE(sanitized_result.program.IsValid())
-          << formatter.format(sanitized_result.program.Diagnostics());
-    }();
+    /// The program built with a call to Build()
+    std::unique_ptr<Program> program;
 
-    transform::Manager transform_manager;
-    transform::DataMap transform_data;
-    transform_data.Add<transform::Renamer::Config>(
-        transform::Renamer::Target::kHlslKeywords,
-        /* preserve_unicode */ true);
-    transform_manager.Add<tint::transform::Renamer>();
-    auto result =
-        transform_manager.Run(&sanitized_result.program, transform_data);
-    [&]() {
-      ASSERT_TRUE(result.program.IsValid())
-          << formatter.format(result.program.Diagnostics());
-    }();
-    *program = std::move(result.program);
-    gen_ = std::make_unique<GeneratorImpl>(program.get());
-    return *gen_;
-  }
-
-  /// The program built with a call to Build()
-  std::unique_ptr<Program> program;
-
- private:
-  std::unique_ptr<GeneratorImpl> gen_;
+  private:
+    std::unique_ptr<GeneratorImpl> gen_;
 };
 
 /// TestHelper the the base class for HLSL writer unit tests.
diff --git a/src/tint/writer/msl/generator.cc b/src/tint/writer/msl/generator.cc
index ee33006..6d09a86 100644
--- a/src/tint/writer/msl/generator.cc
+++ b/src/tint/writer/msl/generator.cc
@@ -30,29 +30,28 @@
 Result::Result(const Result&) = default;
 
 Result Generate(const Program* program, const Options& options) {
-  Result result;
+    Result result;
 
-  // Sanitize the program.
-  auto sanitized_result = Sanitize(program, options);
-  if (!sanitized_result.program.IsValid()) {
-    result.success = false;
-    result.error = sanitized_result.program.Diagnostics().str();
+    // Sanitize the program.
+    auto sanitized_result = Sanitize(program, options);
+    if (!sanitized_result.program.IsValid()) {
+        result.success = false;
+        result.error = sanitized_result.program.Diagnostics().str();
+        return result;
+    }
+    result.needs_storage_buffer_sizes = sanitized_result.needs_storage_buffer_sizes;
+    result.used_array_length_from_uniform_indices =
+        std::move(sanitized_result.used_array_length_from_uniform_indices);
+
+    // Generate the MSL code.
+    auto impl = std::make_unique<GeneratorImpl>(&sanitized_result.program);
+    result.success = impl->Generate();
+    result.error = impl->error();
+    result.msl = impl->result();
+    result.has_invariant_attribute = impl->HasInvariant();
+    result.workgroup_allocations = impl->DynamicWorkgroupAllocations();
+
     return result;
-  }
-  result.needs_storage_buffer_sizes =
-      sanitized_result.needs_storage_buffer_sizes;
-  result.used_array_length_from_uniform_indices =
-      std::move(sanitized_result.used_array_length_from_uniform_indices);
-
-  // Generate the MSL code.
-  auto impl = std::make_unique<GeneratorImpl>(&sanitized_result.program);
-  result.success = impl->Generate();
-  result.error = impl->error();
-  result.msl = impl->result();
-  result.has_invariant_attribute = impl->HasInvariant();
-  result.workgroup_allocations = impl->DynamicWorkgroupAllocations();
-
-  return result;
 }
 
 }  // namespace tint::writer::msl
diff --git a/src/tint/writer/msl/generator.h b/src/tint/writer/msl/generator.h
index 1415e6b..43b0cb7 100644
--- a/src/tint/writer/msl/generator.h
+++ b/src/tint/writer/msl/generator.h
@@ -36,76 +36,76 @@
 
 /// Configuration options used for generating MSL.
 struct Options {
-  /// Constructor
-  Options();
-  /// Destructor
-  ~Options();
-  /// Copy constructor
-  Options(const Options&);
-  /// Copy assignment
-  /// @returns this Options
-  Options& operator=(const Options&);
+    /// Constructor
+    Options();
+    /// Destructor
+    ~Options();
+    /// Copy constructor
+    Options(const Options&);
+    /// Copy assignment
+    /// @returns this Options
+    Options& operator=(const Options&);
 
-  /// The index to use when generating a UBO to receive storage buffer sizes.
-  /// Defaults to 30, which is the last valid buffer slot.
-  uint32_t buffer_size_ubo_index = 30;
+    /// The index to use when generating a UBO to receive storage buffer sizes.
+    /// Defaults to 30, which is the last valid buffer slot.
+    uint32_t buffer_size_ubo_index = 30;
 
-  /// The fixed sample mask to combine with fragment shader outputs.
-  /// Defaults to 0xFFFFFFFF.
-  uint32_t fixed_sample_mask = 0xFFFFFFFF;
+    /// The fixed sample mask to combine with fragment shader outputs.
+    /// Defaults to 0xFFFFFFFF.
+    uint32_t fixed_sample_mask = 0xFFFFFFFF;
 
-  /// Set to `true` to generate a [[point_size]] attribute which is set to 1.0
-  /// for all vertex shaders in the module.
-  bool emit_vertex_point_size = false;
+    /// Set to `true` to generate a [[point_size]] attribute which is set to 1.0
+    /// for all vertex shaders in the module.
+    bool emit_vertex_point_size = false;
 
-  /// Set to `true` to disable workgroup memory zero initialization
-  bool disable_workgroup_init = false;
+    /// Set to `true` to disable workgroup memory zero initialization
+    bool disable_workgroup_init = false;
 
-  /// Set to 'true' to generates binding mappings for external textures
-  bool generate_external_texture_bindings = false;
+    /// Set to 'true' to generates binding mappings for external textures
+    bool generate_external_texture_bindings = false;
 
-  /// Options used to specify a mapping of binding points to indices into a UBO
-  /// from which to load buffer sizes.
-  ArrayLengthFromUniformOptions array_length_from_uniform = {};
+    /// Options used to specify a mapping of binding points to indices into a UBO
+    /// from which to load buffer sizes.
+    ArrayLengthFromUniformOptions array_length_from_uniform = {};
 
-  // NOTE: Update src/tint/fuzzers/data_builder.h when adding or changing any
-  // struct members.
+    // NOTE: Update src/tint/fuzzers/data_builder.h when adding or changing any
+    // struct members.
 };
 
 /// The result produced when generating MSL.
 struct Result {
-  /// Constructor
-  Result();
+    /// Constructor
+    Result();
 
-  /// Destructor
-  ~Result();
+    /// Destructor
+    ~Result();
 
-  /// Copy constructor
-  Result(const Result&);
+    /// Copy constructor
+    Result(const Result&);
 
-  /// True if generation was successful.
-  bool success = false;
+    /// True if generation was successful.
+    bool success = false;
 
-  /// The errors generated during code generation, if any.
-  std::string error;
+    /// The errors generated during code generation, if any.
+    std::string error;
 
-  /// The generated MSL.
-  std::string msl = "";
+    /// The generated MSL.
+    std::string msl = "";
 
-  /// True if the shader needs a UBO of buffer sizes.
-  bool needs_storage_buffer_sizes = false;
+    /// True if the shader needs a UBO of buffer sizes.
+    bool needs_storage_buffer_sizes = false;
 
-  /// True if the generated shader uses the invariant attribute.
-  bool has_invariant_attribute = false;
+    /// True if the generated shader uses the invariant attribute.
+    bool has_invariant_attribute = false;
 
-  /// A map from entry point name to a list of dynamic workgroup allocations.
-  /// Each entry in the vector is the size of the workgroup allocation that
-  /// should be created for that index.
-  std::unordered_map<std::string, std::vector<uint32_t>> workgroup_allocations;
+    /// A map from entry point name to a list of dynamic workgroup allocations.
+    /// Each entry in the vector is the size of the workgroup allocation that
+    /// should be created for that index.
+    std::unordered_map<std::string, std::vector<uint32_t>> workgroup_allocations;
 
-  /// Indices into the array_length_from_uniform binding that are statically
-  /// used.
-  std::unordered_set<uint32_t> used_array_length_from_uniform_indices;
+    /// Indices into the array_length_from_uniform binding that are statically
+    /// used.
+    std::unordered_set<uint32_t> used_array_length_from_uniform_indices;
 };
 
 /// Generate MSL for a program, according to a set of configuration options. The
diff --git a/src/tint/writer/msl/generator_bench.cc b/src/tint/writer/msl/generator_bench.cc
index c9d4440..7feb1cf 100644
--- a/src/tint/writer/msl/generator_bench.cc
+++ b/src/tint/writer/msl/generator_bench.cc
@@ -20,18 +20,18 @@
 namespace {
 
 void GenerateMSL(benchmark::State& state, std::string input_name) {
-  auto res = bench::LoadProgram(input_name);
-  if (auto err = std::get_if<bench::Error>(&res)) {
-    state.SkipWithError(err->msg.c_str());
-    return;
-  }
-  auto& program = std::get<bench::ProgramAndFile>(res).program;
-  for (auto _ : state) {
-    auto res = Generate(&program, {});
-    if (!res.error.empty()) {
-      state.SkipWithError(res.error.c_str());
+    auto res = bench::LoadProgram(input_name);
+    if (auto err = std::get_if<bench::Error>(&res)) {
+        state.SkipWithError(err->msg.c_str());
+        return;
     }
-  }
+    auto& program = std::get<bench::ProgramAndFile>(res).program;
+    for (auto _ : state) {
+        auto res = Generate(&program, {});
+        if (!res.error.empty()) {
+            state.SkipWithError(res.error.c_str());
+        }
+    }
 }
 
 TINT_BENCHMARK_WGSL_PROGRAMS(GenerateMSL);
diff --git a/src/tint/writer/msl/generator_impl.cc b/src/tint/writer/msl/generator_impl.cc
index 349ed1d..8665cdb 100644
--- a/src/tint/writer/msl/generator_impl.cc
+++ b/src/tint/writer/msl/generator_impl.cc
@@ -30,34 +30,32 @@
 #include "src/tint/ast/id_attribute.h"
 #include "src/tint/ast/interpolate_attribute.h"
 #include "src/tint/ast/module.h"
-#include "src/tint/ast/sint_literal_expression.h"
-#include "src/tint/ast/uint_literal_expression.h"
 #include "src/tint/ast/variable_decl_statement.h"
 #include "src/tint/ast/void.h"
 #include "src/tint/sem/array.h"
-#include "src/tint/sem/atomic_type.h"
-#include "src/tint/sem/bool_type.h"
+#include "src/tint/sem/atomic.h"
+#include "src/tint/sem/bool.h"
 #include "src/tint/sem/call.h"
-#include "src/tint/sem/depth_multisampled_texture_type.h"
-#include "src/tint/sem/depth_texture_type.h"
-#include "src/tint/sem/f32_type.h"
+#include "src/tint/sem/depth_multisampled_texture.h"
+#include "src/tint/sem/depth_texture.h"
+#include "src/tint/sem/f32.h"
 #include "src/tint/sem/function.h"
-#include "src/tint/sem/i32_type.h"
-#include "src/tint/sem/matrix_type.h"
+#include "src/tint/sem/i32.h"
+#include "src/tint/sem/matrix.h"
 #include "src/tint/sem/member_accessor_expression.h"
 #include "src/tint/sem/module.h"
-#include "src/tint/sem/multisampled_texture_type.h"
-#include "src/tint/sem/pointer_type.h"
-#include "src/tint/sem/reference_type.h"
-#include "src/tint/sem/sampled_texture_type.h"
-#include "src/tint/sem/storage_texture_type.h"
+#include "src/tint/sem/multisampled_texture.h"
+#include "src/tint/sem/pointer.h"
+#include "src/tint/sem/reference.h"
+#include "src/tint/sem/sampled_texture.h"
+#include "src/tint/sem/storage_texture.h"
 #include "src/tint/sem/struct.h"
 #include "src/tint/sem/type_constructor.h"
 #include "src/tint/sem/type_conversion.h"
-#include "src/tint/sem/u32_type.h"
+#include "src/tint/sem/u32.h"
 #include "src/tint/sem/variable.h"
-#include "src/tint/sem/vector_type.h"
-#include "src/tint/sem/void_type.h"
+#include "src/tint/sem/vector.h"
+#include "src/tint/sem/void.h"
 #include "src/tint/transform/array_length_from_uniform.h"
 #include "src/tint/transform/builtin_polyfill.h"
 #include "src/tint/transform/canonicalize_entry_point_io.h"
@@ -83,34 +81,34 @@
 namespace {
 
 bool last_is_break_or_fallthrough(const ast::BlockStatement* stmts) {
-  return IsAnyOf<ast::BreakStatement, ast::FallthroughStatement>(stmts->Last());
+    return IsAnyOf<ast::BreakStatement, ast::FallthroughStatement>(stmts->Last());
 }
 
 class ScopedBitCast {
- public:
-  ScopedBitCast(GeneratorImpl* generator,
-                std::ostream& stream,
-                const sem::Type* curr_type,
-                const sem::Type* target_type)
-      : s(stream) {
-    auto* target_vec_type = target_type->As<sem::Vector>();
+  public:
+    ScopedBitCast(GeneratorImpl* generator,
+                  std::ostream& stream,
+                  const sem::Type* curr_type,
+                  const sem::Type* target_type)
+        : s(stream) {
+        auto* target_vec_type = target_type->As<sem::Vector>();
 
-    // If we need to promote from scalar to vector, bitcast the scalar to the
-    // vector element type.
-    if (curr_type->is_scalar() && target_vec_type) {
-      target_type = target_vec_type->type();
+        // If we need to promote from scalar to vector, bitcast the scalar to the
+        // vector element type.
+        if (curr_type->is_scalar() && target_vec_type) {
+            target_type = target_vec_type->type();
+        }
+
+        // Bit cast
+        s << "as_type<";
+        generator->EmitType(s, target_type, "");
+        s << ">(";
     }
 
-    // Bit cast
-    s << "as_type<";
-    generator->EmitType(s, target_type, "");
-    s << ">(";
-  }
+    ~ScopedBitCast() { s << ")"; }
 
-  ~ScopedBitCast() { s << ")"; }
-
- private:
-  std::ostream& s;
+  private:
+    std::ostream& s;
 };
 
 }  // namespace
@@ -120,94 +118,88 @@
 SanitizedResult::SanitizedResult(SanitizedResult&&) = default;
 
 SanitizedResult Sanitize(const Program* in, const Options& options) {
-  transform::Manager manager;
-  transform::DataMap data;
+    transform::Manager manager;
+    transform::DataMap data;
 
-  {  // Builtin polyfills
-    transform::BuiltinPolyfill::Builtins polyfills;
-    polyfills.extract_bits =
-        transform::BuiltinPolyfill::Level::kClampParameters;
-    polyfills.first_leading_bit = true;
-    polyfills.first_trailing_bit = true;
-    polyfills.insert_bits = transform::BuiltinPolyfill::Level::kClampParameters;
-    data.Add<transform::BuiltinPolyfill::Config>(polyfills);
-    manager.Add<transform::BuiltinPolyfill>();
-  }
-
-  // Build the config for the internal ArrayLengthFromUniform transform.
-  auto& array_length_from_uniform = options.array_length_from_uniform;
-  transform::ArrayLengthFromUniform::Config array_length_from_uniform_cfg(
-      array_length_from_uniform.ubo_binding);
-  if (!array_length_from_uniform.bindpoint_to_size_index.empty()) {
-    // If |array_length_from_uniform| bindings are provided, use that config.
-    array_length_from_uniform_cfg.bindpoint_to_size_index =
-        array_length_from_uniform.bindpoint_to_size_index;
-  } else {
-    // If the binding map is empty, use the deprecated |buffer_size_ubo_index|
-    // and automatically choose indices using the binding numbers.
-    array_length_from_uniform_cfg = transform::ArrayLengthFromUniform::Config(
-        sem::BindingPoint{0, options.buffer_size_ubo_index});
-    // Use the SSBO binding numbers as the indices for the buffer size lookups.
-    for (auto* var : in->AST().GlobalVariables()) {
-      auto* global = in->Sem().Get<sem::GlobalVariable>(var);
-      if (global && global->StorageClass() == ast::StorageClass::kStorage) {
-        array_length_from_uniform_cfg.bindpoint_to_size_index.emplace(
-            global->BindingPoint(), global->BindingPoint().binding);
-      }
+    {  // Builtin polyfills
+        transform::BuiltinPolyfill::Builtins polyfills;
+        polyfills.extract_bits = transform::BuiltinPolyfill::Level::kClampParameters;
+        polyfills.first_leading_bit = true;
+        polyfills.first_trailing_bit = true;
+        polyfills.insert_bits = transform::BuiltinPolyfill::Level::kClampParameters;
+        data.Add<transform::BuiltinPolyfill::Config>(polyfills);
+        manager.Add<transform::BuiltinPolyfill>();
     }
-  }
 
-  // Build the configs for the internal CanonicalizeEntryPointIO transform.
-  auto entry_point_io_cfg = transform::CanonicalizeEntryPointIO::Config(
-      transform::CanonicalizeEntryPointIO::ShaderStyle::kMsl,
-      options.fixed_sample_mask, options.emit_vertex_point_size);
+    // Build the config for the internal ArrayLengthFromUniform transform.
+    auto& array_length_from_uniform = options.array_length_from_uniform;
+    transform::ArrayLengthFromUniform::Config array_length_from_uniform_cfg(
+        array_length_from_uniform.ubo_binding);
+    if (!array_length_from_uniform.bindpoint_to_size_index.empty()) {
+        // If |array_length_from_uniform| bindings are provided, use that config.
+        array_length_from_uniform_cfg.bindpoint_to_size_index =
+            array_length_from_uniform.bindpoint_to_size_index;
+    } else {
+        // If the binding map is empty, use the deprecated |buffer_size_ubo_index|
+        // and automatically choose indices using the binding numbers.
+        array_length_from_uniform_cfg = transform::ArrayLengthFromUniform::Config(
+            sem::BindingPoint{0, options.buffer_size_ubo_index});
+        // Use the SSBO binding numbers as the indices for the buffer size lookups.
+        for (auto* var : in->AST().GlobalVariables()) {
+            auto* global = in->Sem().Get<sem::GlobalVariable>(var);
+            if (global && global->StorageClass() == ast::StorageClass::kStorage) {
+                array_length_from_uniform_cfg.bindpoint_to_size_index.emplace(
+                    global->BindingPoint(), global->BindingPoint().binding);
+            }
+        }
+    }
 
-  if (options.generate_external_texture_bindings) {
-    auto new_bindings_map = GenerateExternalTextureBindings(in);
-    data.Add<transform::MultiplanarExternalTexture::NewBindingPoints>(
-        new_bindings_map);
-  }
-  manager.Add<transform::MultiplanarExternalTexture>();
+    // Build the configs for the internal CanonicalizeEntryPointIO transform.
+    auto entry_point_io_cfg = transform::CanonicalizeEntryPointIO::Config(
+        transform::CanonicalizeEntryPointIO::ShaderStyle::kMsl, options.fixed_sample_mask,
+        options.emit_vertex_point_size);
 
-  manager.Add<transform::Unshadow>();
+    if (options.generate_external_texture_bindings) {
+        auto new_bindings_map = GenerateExternalTextureBindings(in);
+        data.Add<transform::MultiplanarExternalTexture::NewBindingPoints>(new_bindings_map);
+    }
+    manager.Add<transform::MultiplanarExternalTexture>();
 
-  if (!options.disable_workgroup_init) {
-    // ZeroInitWorkgroupMemory must come before CanonicalizeEntryPointIO as
-    // ZeroInitWorkgroupMemory may inject new builtin parameters.
-    manager.Add<transform::ZeroInitWorkgroupMemory>();
-  }
-  manager.Add<transform::CanonicalizeEntryPointIO>();
-  manager.Add<transform::ExpandCompoundAssignment>();
-  manager.Add<transform::PromoteSideEffectsToDecl>();
-  manager.Add<transform::UnwindDiscardFunctions>();
-  manager.Add<transform::PromoteInitializersToConstVar>();
+    manager.Add<transform::Unshadow>();
 
-  manager.Add<transform::VectorizeScalarMatrixConstructors>();
-  manager.Add<transform::WrapArraysInStructs>();
-  manager.Add<transform::RemovePhonies>();
-  manager.Add<transform::SimplifyPointers>();
-  // ArrayLengthFromUniform must come after SimplifyPointers, as
-  // it assumes that the form of the array length argument is &var.array.
-  manager.Add<transform::ArrayLengthFromUniform>();
-  manager.Add<transform::ModuleScopeVarToEntryPointParam>();
-  data.Add<transform::ArrayLengthFromUniform::Config>(
-      std::move(array_length_from_uniform_cfg));
-  data.Add<transform::CanonicalizeEntryPointIO::Config>(
-      std::move(entry_point_io_cfg));
-  auto out = manager.Run(in, data);
+    if (!options.disable_workgroup_init) {
+        // ZeroInitWorkgroupMemory must come before CanonicalizeEntryPointIO as
+        // ZeroInitWorkgroupMemory may inject new builtin parameters.
+        manager.Add<transform::ZeroInitWorkgroupMemory>();
+    }
+    manager.Add<transform::CanonicalizeEntryPointIO>();
+    manager.Add<transform::ExpandCompoundAssignment>();
+    manager.Add<transform::PromoteSideEffectsToDecl>();
+    manager.Add<transform::UnwindDiscardFunctions>();
+    manager.Add<transform::PromoteInitializersToConstVar>();
 
-  SanitizedResult result;
-  result.program = std::move(out.program);
-  if (!result.program.IsValid()) {
+    manager.Add<transform::VectorizeScalarMatrixConstructors>();
+    manager.Add<transform::WrapArraysInStructs>();
+    manager.Add<transform::RemovePhonies>();
+    manager.Add<transform::SimplifyPointers>();
+    // ArrayLengthFromUniform must come after SimplifyPointers, as
+    // it assumes that the form of the array length argument is &var.array.
+    manager.Add<transform::ArrayLengthFromUniform>();
+    manager.Add<transform::ModuleScopeVarToEntryPointParam>();
+    data.Add<transform::ArrayLengthFromUniform::Config>(std::move(array_length_from_uniform_cfg));
+    data.Add<transform::CanonicalizeEntryPointIO::Config>(std::move(entry_point_io_cfg));
+    auto out = manager.Run(in, data);
+
+    SanitizedResult result;
+    result.program = std::move(out.program);
+    if (!result.program.IsValid()) {
+        return result;
+    }
+    if (auto* res = out.data.Get<transform::ArrayLengthFromUniform::Result>()) {
+        result.used_array_length_from_uniform_indices = std::move(res->used_size_indices);
+    }
+    result.needs_storage_buffer_sizes = !result.used_array_length_from_uniform_indices.empty();
     return result;
-  }
-  if (auto* res = out.data.Get<transform::ArrayLengthFromUniform::Result>()) {
-    result.used_array_length_from_uniform_indices =
-        std::move(res->used_size_indices);
-  }
-  result.needs_storage_buffer_sizes =
-      !result.used_array_length_from_uniform_indices.empty();
-  return result;
 }
 
 GeneratorImpl::GeneratorImpl(const Program* program) : TextGenerator(program) {}
@@ -215,2319 +207,2251 @@
 GeneratorImpl::~GeneratorImpl() = default;
 
 bool GeneratorImpl::Generate() {
-  line() << "#include <metal_stdlib>";
-  line();
-  line() << "using namespace metal;";
+    line() << "#include <metal_stdlib>";
+    line();
+    line() << "using namespace metal;";
 
-  auto helpers_insertion_point = current_buffer_->lines.size();
+    auto helpers_insertion_point = current_buffer_->lines.size();
 
-  auto* mod = builder_.Sem().Module();
-  for (auto* decl : mod->DependencyOrderedDeclarations()) {
-    bool ok = Switch(
-        decl,  //
-        [&](const ast::Struct* str) {
-          TINT_DEFER(line());
-          return EmitTypeDecl(TypeOf(str));
-        },
-        [&](const ast::Alias*) {
-          return true;  // folded away by the writer
-        },
-        [&](const ast::Variable* var) {
-          if (var->is_const) {
-            TINT_DEFER(line());
-            return EmitProgramConstVariable(var);
-          }
-          // These are pushed into the entry point by sanitizer transforms.
-          TINT_ICE(Writer, diagnostics_)
-              << "module-scope variables should have been handled by the MSL "
-                 "sanitizer";
-          return false;
-        },
-        [&](const ast::Function* func) {
-          TINT_DEFER(line());
-          if (func->IsEntryPoint()) {
-            return EmitEntryPointFunction(func);
-          }
-          return EmitFunction(func);
-        },
-        [&](Default) {
-          // These are pushed into the entry point by sanitizer transforms.
-          TINT_ICE(Writer, diagnostics_)
-              << "unhandled type: " << decl->TypeInfo().name;
-          return false;
-        });
-    if (!ok) {
-      return false;
+    auto* mod = builder_.Sem().Module();
+    for (auto* decl : mod->DependencyOrderedDeclarations()) {
+        bool ok = Switch(
+            decl,  //
+            [&](const ast::Struct* str) {
+                TINT_DEFER(line());
+                return EmitTypeDecl(TypeOf(str));
+            },
+            [&](const ast::Alias*) {
+                return true;  // folded away by the writer
+            },
+            [&](const ast::Variable* var) {
+                if (var->is_const) {
+                    TINT_DEFER(line());
+                    return EmitProgramConstVariable(var);
+                }
+                // These are pushed into the entry point by sanitizer transforms.
+                TINT_ICE(Writer, diagnostics_)
+                    << "module-scope variables should have been handled by the MSL "
+                       "sanitizer";
+                return false;
+            },
+            [&](const ast::Function* func) {
+                TINT_DEFER(line());
+                if (func->IsEntryPoint()) {
+                    return EmitEntryPointFunction(func);
+                }
+                return EmitFunction(func);
+            },
+            [&](const ast::Enable*) {
+                // Do nothing for enabling extension in MSL
+                return true;
+            },
+            [&](Default) {
+                // These are pushed into the entry point by sanitizer transforms.
+                TINT_ICE(Writer, diagnostics_) << "unhandled type: " << decl->TypeInfo().name;
+                return false;
+            });
+        if (!ok) {
+            return false;
+        }
     }
-  }
 
-  if (!invariant_define_name_.empty()) {
-    // 'invariant' attribute requires MSL 2.1 or higher.
-    // WGSL can ignore the invariant attribute on pre MSL 2.1 devices.
-    // See: https://github.com/gpuweb/gpuweb/issues/893#issuecomment-745537465
-    line(&helpers_) << "#if __METAL_VERSION__ >= 210";
-    line(&helpers_) << "#define " << invariant_define_name_ << " @invariant";
-    line(&helpers_) << "#else";
-    line(&helpers_) << "#define " << invariant_define_name_;
-    line(&helpers_) << "#endif";
-    line(&helpers_);
-  }
+    if (!invariant_define_name_.empty()) {
+        // 'invariant' attribute requires MSL 2.1 or higher.
+        // WGSL can ignore the invariant attribute on pre MSL 2.1 devices.
+        // See: https://github.com/gpuweb/gpuweb/issues/893#issuecomment-745537465
+        line(&helpers_) << "#if __METAL_VERSION__ >= 210";
+        line(&helpers_) << "#define " << invariant_define_name_ << " @invariant";
+        line(&helpers_) << "#else";
+        line(&helpers_) << "#define " << invariant_define_name_;
+        line(&helpers_) << "#endif";
+        line(&helpers_);
+    }
 
-  if (!helpers_.lines.empty()) {
-    current_buffer_->Insert("", helpers_insertion_point++, 0);
-    current_buffer_->Insert(helpers_, helpers_insertion_point++, 0);
-  }
+    if (!helpers_.lines.empty()) {
+        current_buffer_->Insert("", helpers_insertion_point++, 0);
+        current_buffer_->Insert(helpers_, helpers_insertion_point++, 0);
+    }
 
-  return true;
+    return true;
 }
 
 bool GeneratorImpl::EmitTypeDecl(const sem::Type* ty) {
-  if (auto* str = ty->As<sem::Struct>()) {
-    if (!EmitStructType(current_buffer_, str)) {
-      return false;
+    if (auto* str = ty->As<sem::Struct>()) {
+        if (!EmitStructType(current_buffer_, str)) {
+            return false;
+        }
+    } else {
+        diagnostics_.add_error(diag::System::Writer,
+                               "unknown alias type: " + ty->FriendlyName(builder_.Symbols()));
+        return false;
     }
-  } else {
-    diagnostics_.add_error(
-        diag::System::Writer,
-        "unknown alias type: " + ty->FriendlyName(builder_.Symbols()));
-    return false;
-  }
 
-  return true;
+    return true;
 }
 
-bool GeneratorImpl::EmitIndexAccessor(
-    std::ostream& out,
-    const ast::IndexAccessorExpression* expr) {
-  bool paren_lhs =
-      !expr->object->IsAnyOf<ast::IndexAccessorExpression, ast::CallExpression,
-                             ast::IdentifierExpression,
-                             ast::MemberAccessorExpression>();
+bool GeneratorImpl::EmitIndexAccessor(std::ostream& out, const ast::IndexAccessorExpression* expr) {
+    bool paren_lhs =
+        !expr->object->IsAnyOf<ast::IndexAccessorExpression, ast::CallExpression,
+                               ast::IdentifierExpression, ast::MemberAccessorExpression>();
 
-  if (paren_lhs) {
-    out << "(";
-  }
-  if (!EmitExpression(out, expr->object)) {
-    return false;
-  }
-  if (paren_lhs) {
+    if (paren_lhs) {
+        out << "(";
+    }
+    if (!EmitExpression(out, expr->object)) {
+        return false;
+    }
+    if (paren_lhs) {
+        out << ")";
+    }
+
+    out << "[";
+
+    if (!EmitExpression(out, expr->index)) {
+        return false;
+    }
+    out << "]";
+
+    return true;
+}
+
+bool GeneratorImpl::EmitBitcast(std::ostream& out, const ast::BitcastExpression* expr) {
+    out << "as_type<";
+    if (!EmitType(out, TypeOf(expr)->UnwrapRef(), "")) {
+        return false;
+    }
+
+    out << ">(";
+    if (!EmitExpression(out, expr->expr)) {
+        return false;
+    }
+
     out << ")";
-  }
-
-  out << "[";
-
-  if (!EmitExpression(out, expr->index)) {
-    return false;
-  }
-  out << "]";
-
-  return true;
-}
-
-bool GeneratorImpl::EmitBitcast(std::ostream& out,
-                                const ast::BitcastExpression* expr) {
-  out << "as_type<";
-  if (!EmitType(out, TypeOf(expr)->UnwrapRef(), "")) {
-    return false;
-  }
-
-  out << ">(";
-  if (!EmitExpression(out, expr->expr)) {
-    return false;
-  }
-
-  out << ")";
-  return true;
+    return true;
 }
 
 bool GeneratorImpl::EmitAssign(const ast::AssignmentStatement* stmt) {
-  auto out = line();
+    auto out = line();
 
-  if (!EmitExpression(out, stmt->lhs)) {
-    return false;
-  }
+    if (!EmitExpression(out, stmt->lhs)) {
+        return false;
+    }
 
-  out << " = ";
+    out << " = ";
 
-  if (!EmitExpression(out, stmt->rhs)) {
-    return false;
-  }
+    if (!EmitExpression(out, stmt->rhs)) {
+        return false;
+    }
 
-  out << ";";
+    out << ";";
 
-  return true;
+    return true;
 }
 
-bool GeneratorImpl::EmitBinary(std::ostream& out,
-                               const ast::BinaryExpression* expr) {
-  auto emit_op = [&] {
-    out << " ";
+bool GeneratorImpl::EmitBinary(std::ostream& out, const ast::BinaryExpression* expr) {
+    auto emit_op = [&] {
+        out << " ";
 
-    switch (expr->op) {
-      case ast::BinaryOp::kAnd:
-        out << "&";
-        break;
-      case ast::BinaryOp::kOr:
-        out << "|";
-        break;
-      case ast::BinaryOp::kXor:
-        out << "^";
-        break;
-      case ast::BinaryOp::kLogicalAnd:
-        out << "&&";
-        break;
-      case ast::BinaryOp::kLogicalOr:
-        out << "||";
-        break;
-      case ast::BinaryOp::kEqual:
-        out << "==";
-        break;
-      case ast::BinaryOp::kNotEqual:
-        out << "!=";
-        break;
-      case ast::BinaryOp::kLessThan:
-        out << "<";
-        break;
-      case ast::BinaryOp::kGreaterThan:
-        out << ">";
-        break;
-      case ast::BinaryOp::kLessThanEqual:
-        out << "<=";
-        break;
-      case ast::BinaryOp::kGreaterThanEqual:
-        out << ">=";
-        break;
-      case ast::BinaryOp::kShiftLeft:
-        out << "<<";
-        break;
-      case ast::BinaryOp::kShiftRight:
-        // TODO(dsinclair): MSL is based on C++14, and >> in C++14 has
-        // implementation-defined behaviour for negative LHS.  We may have to
-        // generate extra code to implement WGSL-specified behaviour for
-        // negative LHS.
-        out << R"(>>)";
-        break;
+        switch (expr->op) {
+            case ast::BinaryOp::kAnd:
+                out << "&";
+                break;
+            case ast::BinaryOp::kOr:
+                out << "|";
+                break;
+            case ast::BinaryOp::kXor:
+                out << "^";
+                break;
+            case ast::BinaryOp::kLogicalAnd:
+                out << "&&";
+                break;
+            case ast::BinaryOp::kLogicalOr:
+                out << "||";
+                break;
+            case ast::BinaryOp::kEqual:
+                out << "==";
+                break;
+            case ast::BinaryOp::kNotEqual:
+                out << "!=";
+                break;
+            case ast::BinaryOp::kLessThan:
+                out << "<";
+                break;
+            case ast::BinaryOp::kGreaterThan:
+                out << ">";
+                break;
+            case ast::BinaryOp::kLessThanEqual:
+                out << "<=";
+                break;
+            case ast::BinaryOp::kGreaterThanEqual:
+                out << ">=";
+                break;
+            case ast::BinaryOp::kShiftLeft:
+                out << "<<";
+                break;
+            case ast::BinaryOp::kShiftRight:
+                // TODO(dsinclair): MSL is based on C++14, and >> in C++14 has
+                // implementation-defined behaviour for negative LHS.  We may have to
+                // generate extra code to implement WGSL-specified behaviour for
+                // negative LHS.
+                out << R"(>>)";
+                break;
 
-      case ast::BinaryOp::kAdd:
-        out << "+";
-        break;
-      case ast::BinaryOp::kSubtract:
-        out << "-";
-        break;
-      case ast::BinaryOp::kMultiply:
-        out << "*";
-        break;
-      case ast::BinaryOp::kDivide:
-        out << "/";
-        break;
-      case ast::BinaryOp::kModulo:
-        out << "%";
-        break;
-      case ast::BinaryOp::kNone:
-        diagnostics_.add_error(diag::System::Writer,
-                               "missing binary operation type");
-        return false;
+            case ast::BinaryOp::kAdd:
+                out << "+";
+                break;
+            case ast::BinaryOp::kSubtract:
+                out << "-";
+                break;
+            case ast::BinaryOp::kMultiply:
+                out << "*";
+                break;
+            case ast::BinaryOp::kDivide:
+                out << "/";
+                break;
+            case ast::BinaryOp::kModulo:
+                out << "%";
+                break;
+            case ast::BinaryOp::kNone:
+                diagnostics_.add_error(diag::System::Writer, "missing binary operation type");
+                return false;
+        }
+        out << " ";
+        return true;
+    };
+
+    auto signed_type_of = [&](const sem::Type* ty) -> const sem::Type* {
+        if (ty->is_integer_scalar()) {
+            return builder_.create<sem::I32>();
+        } else if (auto* v = ty->As<sem::Vector>()) {
+            return builder_.create<sem::Vector>(builder_.create<sem::I32>(), v->Width());
+        }
+        return {};
+    };
+
+    auto unsigned_type_of = [&](const sem::Type* ty) -> const sem::Type* {
+        if (ty->is_integer_scalar()) {
+            return builder_.create<sem::U32>();
+        } else if (auto* v = ty->As<sem::Vector>()) {
+            return builder_.create<sem::Vector>(builder_.create<sem::U32>(), v->Width());
+        }
+        return {};
+    };
+
+    auto* lhs_type = TypeOf(expr->lhs)->UnwrapRef();
+    auto* rhs_type = TypeOf(expr->rhs)->UnwrapRef();
+
+    // Handle fmod
+    if (expr->op == ast::BinaryOp::kModulo && lhs_type->is_float_scalar_or_vector()) {
+        out << "fmod";
+        ScopedParen sp(out);
+        if (!EmitExpression(out, expr->lhs)) {
+            return false;
+        }
+        out << ", ";
+        if (!EmitExpression(out, expr->rhs)) {
+            return false;
+        }
+        return true;
     }
-    out << " ";
-    return true;
-  };
 
-  auto signed_type_of = [&](const sem::Type* ty) -> const sem::Type* {
-    if (ty->is_integer_scalar()) {
-      return builder_.create<sem::I32>();
-    } else if (auto* v = ty->As<sem::Vector>()) {
-      return builder_.create<sem::Vector>(builder_.create<sem::I32>(),
-                                          v->Width());
+    // Handle +/-/* of signed values
+    if ((expr->IsAdd() || expr->IsSubtract() || expr->IsMultiply()) &&
+        lhs_type->is_signed_scalar_or_vector() && rhs_type->is_signed_scalar_or_vector()) {
+        // If lhs or rhs is a vector, use that type (support implicit scalar to
+        // vector promotion)
+        auto* target_type = lhs_type->Is<sem::Vector>()
+                                ? lhs_type
+                                : (rhs_type->Is<sem::Vector>() ? rhs_type : lhs_type);
+
+        // WGSL defines behaviour for signed overflow, MSL does not. For these
+        // cases, bitcast operands to unsigned, then cast result to signed.
+        ScopedBitCast outer_int_cast(this, out, target_type, signed_type_of(target_type));
+        ScopedParen sp(out);
+        {
+            ScopedBitCast lhs_uint_cast(this, out, lhs_type, unsigned_type_of(target_type));
+            if (!EmitExpression(out, expr->lhs)) {
+                return false;
+            }
+        }
+        if (!emit_op()) {
+            return false;
+        }
+        {
+            ScopedBitCast rhs_uint_cast(this, out, rhs_type, unsigned_type_of(target_type));
+            if (!EmitExpression(out, expr->rhs)) {
+                return false;
+            }
+        }
+        return true;
     }
-    return {};
-  };
 
-  auto unsigned_type_of = [&](const sem::Type* ty) -> const sem::Type* {
-    if (ty->is_integer_scalar()) {
-      return builder_.create<sem::U32>();
-    } else if (auto* v = ty->As<sem::Vector>()) {
-      return builder_.create<sem::Vector>(builder_.create<sem::U32>(),
-                                          v->Width());
+    // Handle left bit shifting a signed value
+    // TODO(crbug.com/tint/1077): This may not be necessary. The MSL spec
+    // seems to imply that left shifting a signed value is treated the same as
+    // left shifting an unsigned value, but we need to make sure.
+    if (expr->IsShiftLeft() && lhs_type->is_signed_scalar_or_vector()) {
+        // Shift left: discards top bits, so convert first operand to unsigned
+        // first, then convert result back to signed
+        ScopedBitCast outer_int_cast(this, out, lhs_type, signed_type_of(lhs_type));
+        ScopedParen sp(out);
+        {
+            ScopedBitCast lhs_uint_cast(this, out, lhs_type, unsigned_type_of(lhs_type));
+            if (!EmitExpression(out, expr->lhs)) {
+                return false;
+            }
+        }
+        if (!emit_op()) {
+            return false;
+        }
+        if (!EmitExpression(out, expr->rhs)) {
+            return false;
+        }
+        return true;
     }
-    return {};
-  };
 
-  auto* lhs_type = TypeOf(expr->lhs)->UnwrapRef();
-  auto* rhs_type = TypeOf(expr->rhs)->UnwrapRef();
-
-  // Handle fmod
-  if (expr->op == ast::BinaryOp::kModulo &&
-      lhs_type->is_float_scalar_or_vector()) {
-    out << "fmod";
+    // Emit as usual
     ScopedParen sp(out);
     if (!EmitExpression(out, expr->lhs)) {
-      return false;
-    }
-    out << ", ";
-    if (!EmitExpression(out, expr->rhs)) {
-      return false;
-    }
-    return true;
-  }
-
-  // Handle +/-/* of signed values
-  if ((expr->IsAdd() || expr->IsSubtract() || expr->IsMultiply()) &&
-      lhs_type->is_signed_scalar_or_vector() &&
-      rhs_type->is_signed_scalar_or_vector()) {
-    // If lhs or rhs is a vector, use that type (support implicit scalar to
-    // vector promotion)
-    auto* target_type =
-        lhs_type->Is<sem::Vector>()
-            ? lhs_type
-            : (rhs_type->Is<sem::Vector>() ? rhs_type : lhs_type);
-
-    // WGSL defines behaviour for signed overflow, MSL does not. For these
-    // cases, bitcast operands to unsigned, then cast result to signed.
-    ScopedBitCast outer_int_cast(this, out, target_type,
-                                 signed_type_of(target_type));
-    ScopedParen sp(out);
-    {
-      ScopedBitCast lhs_uint_cast(this, out, lhs_type,
-                                  unsigned_type_of(target_type));
-      if (!EmitExpression(out, expr->lhs)) {
         return false;
-      }
     }
     if (!emit_op()) {
-      return false;
-    }
-    {
-      ScopedBitCast rhs_uint_cast(this, out, rhs_type,
-                                  unsigned_type_of(target_type));
-      if (!EmitExpression(out, expr->rhs)) {
         return false;
-      }
-    }
-    return true;
-  }
-
-  // Handle left bit shifting a signed value
-  // TODO(crbug.com/tint/1077): This may not be necessary. The MSL spec
-  // seems to imply that left shifting a signed value is treated the same as
-  // left shifting an unsigned value, but we need to make sure.
-  if (expr->IsShiftLeft() && lhs_type->is_signed_scalar_or_vector()) {
-    // Shift left: discards top bits, so convert first operand to unsigned
-    // first, then convert result back to signed
-    ScopedBitCast outer_int_cast(this, out, lhs_type, signed_type_of(lhs_type));
-    ScopedParen sp(out);
-    {
-      ScopedBitCast lhs_uint_cast(this, out, lhs_type,
-                                  unsigned_type_of(lhs_type));
-      if (!EmitExpression(out, expr->lhs)) {
-        return false;
-      }
-    }
-    if (!emit_op()) {
-      return false;
     }
     if (!EmitExpression(out, expr->rhs)) {
-      return false;
+        return false;
     }
+
     return true;
-  }
-
-  // Emit as usual
-  ScopedParen sp(out);
-  if (!EmitExpression(out, expr->lhs)) {
-    return false;
-  }
-  if (!emit_op()) {
-    return false;
-  }
-  if (!EmitExpression(out, expr->rhs)) {
-    return false;
-  }
-
-  return true;
 }
 
 bool GeneratorImpl::EmitBreak(const ast::BreakStatement*) {
-  line() << "break;";
-  return true;
+    line() << "break;";
+    return true;
 }
 
-bool GeneratorImpl::EmitCall(std::ostream& out,
-                             const ast::CallExpression* expr) {
-  auto* call = program_->Sem().Get(expr);
-  auto* target = call->Target();
-  return Switch(
-      target,
-      [&](const sem::Function* func) {
-        return EmitFunctionCall(out, call, func);
-      },
-      [&](const sem::Builtin* builtin) {
-        return EmitBuiltinCall(out, call, builtin);
-      },
-      [&](const sem::TypeConversion* conv) {
-        return EmitTypeConversion(out, call, conv);
-      },
-      [&](const sem::TypeConstructor* ctor) {
-        return EmitTypeConstructor(out, call, ctor);
-      },
-      [&](Default) {
-        TINT_ICE(Writer, diagnostics_)
-            << "unhandled call target: " << target->TypeInfo().name;
-        return false;
-      });
+bool GeneratorImpl::EmitCall(std::ostream& out, const ast::CallExpression* expr) {
+    auto* call = program_->Sem().Get(expr);
+    auto* target = call->Target();
+    return Switch(
+        target, [&](const sem::Function* func) { return EmitFunctionCall(out, call, func); },
+        [&](const sem::Builtin* builtin) { return EmitBuiltinCall(out, call, builtin); },
+        [&](const sem::TypeConversion* conv) { return EmitTypeConversion(out, call, conv); },
+        [&](const sem::TypeConstructor* ctor) { return EmitTypeConstructor(out, call, ctor); },
+        [&](Default) {
+            TINT_ICE(Writer, diagnostics_) << "unhandled call target: " << target->TypeInfo().name;
+            return false;
+        });
 }
 
 bool GeneratorImpl::EmitFunctionCall(std::ostream& out,
                                      const sem::Call* call,
                                      const sem::Function*) {
-  auto* ident = call->Declaration()->target.name;
-  out << program_->Symbols().NameFor(ident->symbol) << "(";
+    auto* ident = call->Declaration()->target.name;
+    out << program_->Symbols().NameFor(ident->symbol) << "(";
 
-  bool first = true;
-  for (auto* arg : call->Arguments()) {
-    if (!first) {
-      out << ", ";
+    bool first = true;
+    for (auto* arg : call->Arguments()) {
+        if (!first) {
+            out << ", ";
+        }
+        first = false;
+
+        if (!EmitExpression(out, arg->Declaration())) {
+            return false;
+        }
     }
-    first = false;
 
-    if (!EmitExpression(out, arg->Declaration())) {
-      return false;
-    }
-  }
-
-  out << ")";
-  return true;
+    out << ")";
+    return true;
 }
 
 bool GeneratorImpl::EmitBuiltinCall(std::ostream& out,
                                     const sem::Call* call,
                                     const sem::Builtin* builtin) {
-  auto* expr = call->Declaration();
-  if (builtin->IsAtomic()) {
-    return EmitAtomicCall(out, expr, builtin);
-  }
-  if (builtin->IsTexture()) {
-    return EmitTextureCall(out, call, builtin);
-  }
+    auto* expr = call->Declaration();
+    if (builtin->IsAtomic()) {
+        return EmitAtomicCall(out, expr, builtin);
+    }
+    if (builtin->IsTexture()) {
+        return EmitTextureCall(out, call, builtin);
+    }
 
-  auto name = generate_builtin_name(builtin);
+    auto name = generate_builtin_name(builtin);
 
-  switch (builtin->Type()) {
-    case sem::BuiltinType::kDot:
-      return EmitDotCall(out, expr, builtin);
-    case sem::BuiltinType::kModf:
-      return EmitModfCall(out, expr, builtin);
-    case sem::BuiltinType::kFrexp:
-      return EmitFrexpCall(out, expr, builtin);
-    case sem::BuiltinType::kDegrees:
-      return EmitDegreesCall(out, expr, builtin);
-    case sem::BuiltinType::kRadians:
-      return EmitRadiansCall(out, expr, builtin);
+    switch (builtin->Type()) {
+        case sem::BuiltinType::kDot:
+            return EmitDotCall(out, expr, builtin);
+        case sem::BuiltinType::kModf:
+            return EmitModfCall(out, expr, builtin);
+        case sem::BuiltinType::kFrexp:
+            return EmitFrexpCall(out, expr, builtin);
+        case sem::BuiltinType::kDegrees:
+            return EmitDegreesCall(out, expr, builtin);
+        case sem::BuiltinType::kRadians:
+            return EmitRadiansCall(out, expr, builtin);
 
-    case sem::BuiltinType::kPack2x16float:
-    case sem::BuiltinType::kUnpack2x16float: {
-      if (builtin->Type() == sem::BuiltinType::kPack2x16float) {
-        out << "as_type<uint>(half2(";
-      } else {
-        out << "float2(as_type<half2>(";
-      }
-      if (!EmitExpression(out, expr->args[0])) {
+        case sem::BuiltinType::kPack2x16float:
+        case sem::BuiltinType::kUnpack2x16float: {
+            if (builtin->Type() == sem::BuiltinType::kPack2x16float) {
+                out << "as_type<uint>(half2(";
+            } else {
+                out << "float2(as_type<half2>(";
+            }
+            if (!EmitExpression(out, expr->args[0])) {
+                return false;
+            }
+            out << "))";
+            return true;
+        }
+        // TODO(crbug.com/tint/661): Combine sequential barriers to a single
+        // instruction.
+        case sem::BuiltinType::kStorageBarrier: {
+            out << "threadgroup_barrier(mem_flags::mem_device)";
+            return true;
+        }
+        case sem::BuiltinType::kWorkgroupBarrier: {
+            out << "threadgroup_barrier(mem_flags::mem_threadgroup)";
+            return true;
+        }
+
+        case sem::BuiltinType::kLength: {
+            auto* sem = builder_.Sem().Get(expr->args[0]);
+            if (sem->Type()->UnwrapRef()->is_scalar()) {
+                // Emulate scalar overload using fabs(x).
+                name = "fabs";
+            }
+            break;
+        }
+
+        case sem::BuiltinType::kDistance: {
+            auto* sem = builder_.Sem().Get(expr->args[0]);
+            if (sem->Type()->UnwrapRef()->is_scalar()) {
+                // Emulate scalar overload using fabs(x - y);
+                out << "fabs";
+                ScopedParen sp(out);
+                if (!EmitExpression(out, expr->args[0])) {
+                    return false;
+                }
+                out << " - ";
+                if (!EmitExpression(out, expr->args[1])) {
+                    return false;
+                }
+                return true;
+            }
+            break;
+        }
+
+        default:
+            break;
+    }
+
+    if (name.empty()) {
         return false;
-      }
-      out << "))";
-      return true;
-    }
-    // TODO(crbug.com/tint/661): Combine sequential barriers to a single
-    // instruction.
-    case sem::BuiltinType::kStorageBarrier: {
-      out << "threadgroup_barrier(mem_flags::mem_device)";
-      return true;
-    }
-    case sem::BuiltinType::kWorkgroupBarrier: {
-      out << "threadgroup_barrier(mem_flags::mem_threadgroup)";
-      return true;
     }
 
-    case sem::BuiltinType::kLength: {
-      auto* sem = builder_.Sem().Get(expr->args[0]);
-      if (sem->Type()->UnwrapRef()->is_scalar()) {
-        // Emulate scalar overload using fabs(x).
-        name = "fabs";
-      }
-      break;
-    }
+    out << name << "(";
 
-    case sem::BuiltinType::kDistance: {
-      auto* sem = builder_.Sem().Get(expr->args[0]);
-      if (sem->Type()->UnwrapRef()->is_scalar()) {
-        // Emulate scalar overload using fabs(x - y);
-        out << "fabs";
-        ScopedParen sp(out);
-        if (!EmitExpression(out, expr->args[0])) {
-          return false;
+    bool first = true;
+    for (auto* arg : expr->args) {
+        if (!first) {
+            out << ", ";
         }
-        out << " - ";
-        if (!EmitExpression(out, expr->args[1])) {
-          return false;
+        first = false;
+
+        if (!EmitExpression(out, arg)) {
+            return false;
         }
-        return true;
-      }
-      break;
     }
 
-    default:
-      break;
-  }
-
-  if (name.empty()) {
-    return false;
-  }
-
-  out << name << "(";
-
-  bool first = true;
-  for (auto* arg : expr->args) {
-    if (!first) {
-      out << ", ";
-    }
-    first = false;
-
-    if (!EmitExpression(out, arg)) {
-      return false;
-    }
-  }
-
-  out << ")";
-  return true;
+    out << ")";
+    return true;
 }
 
 bool GeneratorImpl::EmitTypeConversion(std::ostream& out,
                                        const sem::Call* call,
                                        const sem::TypeConversion* conv) {
-  if (!EmitType(out, conv->Target(), "")) {
-    return false;
-  }
-  out << "(";
+    if (!EmitType(out, conv->Target(), "")) {
+        return false;
+    }
+    out << "(";
 
-  if (!EmitExpression(out, call->Arguments()[0]->Declaration())) {
-    return false;
-  }
+    if (!EmitExpression(out, call->Arguments()[0]->Declaration())) {
+        return false;
+    }
 
-  out << ")";
-  return true;
+    out << ")";
+    return true;
 }
 
 bool GeneratorImpl::EmitTypeConstructor(std::ostream& out,
                                         const sem::Call* call,
                                         const sem::TypeConstructor* ctor) {
-  auto* type = ctor->ReturnType();
+    auto* type = ctor->ReturnType();
 
-  if (type->IsAnyOf<sem::Array, sem::Struct>()) {
-    out << "{";
-  } else {
-    if (!EmitType(out, type, "")) {
-      return false;
-    }
-    out << "(";
-  }
-
-  int i = 0;
-  for (auto* arg : call->Arguments()) {
-    if (i > 0) {
-      out << ", ";
+    if (type->IsAnyOf<sem::Array, sem::Struct>()) {
+        out << "{";
+    } else {
+        if (!EmitType(out, type, "")) {
+            return false;
+        }
+        out << "(";
     }
 
-    if (auto* struct_ty = type->As<sem::Struct>()) {
-      // Emit field designators for structures to account for padding members.
-      auto* member = struct_ty->Members()[i]->Declaration();
-      auto name = program_->Symbols().NameFor(member->symbol);
-      out << "." << name << "=";
+    int i = 0;
+    for (auto* arg : call->Arguments()) {
+        if (i > 0) {
+            out << ", ";
+        }
+
+        if (auto* struct_ty = type->As<sem::Struct>()) {
+            // Emit field designators for structures to account for padding members.
+            auto* member = struct_ty->Members()[i]->Declaration();
+            auto name = program_->Symbols().NameFor(member->symbol);
+            out << "." << name << "=";
+        }
+
+        if (!EmitExpression(out, arg->Declaration())) {
+            return false;
+        }
+
+        i++;
     }
 
-    if (!EmitExpression(out, arg->Declaration())) {
-      return false;
+    if (type->IsAnyOf<sem::Array, sem::Struct>()) {
+        out << "}";
+    } else {
+        out << ")";
     }
-
-    i++;
-  }
-
-  if (type->IsAnyOf<sem::Array, sem::Struct>()) {
-    out << "}";
-  } else {
-    out << ")";
-  }
-  return true;
+    return true;
 }
 
 bool GeneratorImpl::EmitAtomicCall(std::ostream& out,
                                    const ast::CallExpression* expr,
                                    const sem::Builtin* builtin) {
-  auto call = [&](const std::string& name, bool append_memory_order_relaxed) {
-    out << name;
-    {
-      ScopedParen sp(out);
-      for (size_t i = 0; i < expr->args.size(); i++) {
-        auto* arg = expr->args[i];
-        if (i > 0) {
-          out << ", ";
-        }
-        if (!EmitExpression(out, arg)) {
-          return false;
-        }
-      }
-      if (append_memory_order_relaxed) {
-        out << ", memory_order_relaxed";
-      }
-    }
-    return true;
-  };
-
-  switch (builtin->Type()) {
-    case sem::BuiltinType::kAtomicLoad:
-      return call("atomic_load_explicit", true);
-
-    case sem::BuiltinType::kAtomicStore:
-      return call("atomic_store_explicit", true);
-
-    case sem::BuiltinType::kAtomicAdd:
-      return call("atomic_fetch_add_explicit", true);
-
-    case sem::BuiltinType::kAtomicSub:
-      return call("atomic_fetch_sub_explicit", true);
-
-    case sem::BuiltinType::kAtomicMax:
-      return call("atomic_fetch_max_explicit", true);
-
-    case sem::BuiltinType::kAtomicMin:
-      return call("atomic_fetch_min_explicit", true);
-
-    case sem::BuiltinType::kAtomicAnd:
-      return call("atomic_fetch_and_explicit", true);
-
-    case sem::BuiltinType::kAtomicOr:
-      return call("atomic_fetch_or_explicit", true);
-
-    case sem::BuiltinType::kAtomicXor:
-      return call("atomic_fetch_xor_explicit", true);
-
-    case sem::BuiltinType::kAtomicExchange:
-      return call("atomic_exchange_explicit", true);
-
-    case sem::BuiltinType::kAtomicCompareExchangeWeak: {
-      auto* ptr_ty = TypeOf(expr->args[0])->UnwrapRef()->As<sem::Pointer>();
-      auto sc = ptr_ty->StorageClass();
-
-      auto func = utils::GetOrCreate(
-          atomicCompareExchangeWeak_, sc, [&]() -> std::string {
-            auto name = UniqueIdentifier("atomicCompareExchangeWeak");
-            auto& buf = helpers_;
-
-            line(&buf) << "template <typename A, typename T>";
-            {
-              auto f = line(&buf);
-              f << "vec<T, 2> " << name << "(";
-              if (!EmitStorageClass(f, sc)) {
-                return "";
-              }
-              f << " A* atomic, T compare, T value) {";
+    auto call = [&](const std::string& name, bool append_memory_order_relaxed) {
+        out << name;
+        {
+            ScopedParen sp(out);
+            for (size_t i = 0; i < expr->args.size(); i++) {
+                auto* arg = expr->args[i];
+                if (i > 0) {
+                    out << ", ";
+                }
+                if (!EmitExpression(out, arg)) {
+                    return false;
+                }
             }
+            if (append_memory_order_relaxed) {
+                out << ", memory_order_relaxed";
+            }
+        }
+        return true;
+    };
 
-            buf.IncrementIndent();
-            TINT_DEFER({
-              buf.DecrementIndent();
-              line(&buf) << "}";
-              line(&buf);
+    switch (builtin->Type()) {
+        case sem::BuiltinType::kAtomicLoad:
+            return call("atomic_load_explicit", true);
+
+        case sem::BuiltinType::kAtomicStore:
+            return call("atomic_store_explicit", true);
+
+        case sem::BuiltinType::kAtomicAdd:
+            return call("atomic_fetch_add_explicit", true);
+
+        case sem::BuiltinType::kAtomicSub:
+            return call("atomic_fetch_sub_explicit", true);
+
+        case sem::BuiltinType::kAtomicMax:
+            return call("atomic_fetch_max_explicit", true);
+
+        case sem::BuiltinType::kAtomicMin:
+            return call("atomic_fetch_min_explicit", true);
+
+        case sem::BuiltinType::kAtomicAnd:
+            return call("atomic_fetch_and_explicit", true);
+
+        case sem::BuiltinType::kAtomicOr:
+            return call("atomic_fetch_or_explicit", true);
+
+        case sem::BuiltinType::kAtomicXor:
+            return call("atomic_fetch_xor_explicit", true);
+
+        case sem::BuiltinType::kAtomicExchange:
+            return call("atomic_exchange_explicit", true);
+
+        case sem::BuiltinType::kAtomicCompareExchangeWeak: {
+            auto* ptr_ty = TypeOf(expr->args[0])->UnwrapRef()->As<sem::Pointer>();
+            auto sc = ptr_ty->StorageClass();
+
+            auto func = utils::GetOrCreate(atomicCompareExchangeWeak_, sc, [&]() -> std::string {
+                auto name = UniqueIdentifier("atomicCompareExchangeWeak");
+                auto& buf = helpers_;
+
+                line(&buf) << "template <typename A, typename T>";
+                {
+                    auto f = line(&buf);
+                    f << "vec<T, 2> " << name << "(";
+                    if (!EmitStorageClass(f, sc)) {
+                        return "";
+                    }
+                    f << " A* atomic, T compare, T value) {";
+                }
+
+                buf.IncrementIndent();
+                TINT_DEFER({
+                    buf.DecrementIndent();
+                    line(&buf) << "}";
+                    line(&buf);
+                });
+
+                line(&buf) << "T prev_value = compare;";
+                line(&buf) << "bool matched = "
+                              "atomic_compare_exchange_weak_explicit(atomic, "
+                              "&prev_value, value, memory_order_relaxed, "
+                              "memory_order_relaxed);";
+                line(&buf) << "return {prev_value, matched};";
+                return name;
             });
 
-            line(&buf) << "T prev_value = compare;";
-            line(&buf) << "bool matched = "
-                          "atomic_compare_exchange_weak_explicit(atomic, "
-                          "&prev_value, value, memory_order_relaxed, "
-                          "memory_order_relaxed);";
-            line(&buf) << "return {prev_value, matched};";
-            return name;
-          });
+            return call(func, false);
+        }
 
-      return call(func, false);
+        default:
+            break;
     }
 
-    default:
-      break;
-  }
-
-  TINT_UNREACHABLE(Writer, diagnostics_)
-      << "unsupported atomic builtin: " << builtin->Type();
-  return false;
+    TINT_UNREACHABLE(Writer, diagnostics_) << "unsupported atomic builtin: " << builtin->Type();
+    return false;
 }
 
 bool GeneratorImpl::EmitTextureCall(std::ostream& out,
                                     const sem::Call* call,
                                     const sem::Builtin* builtin) {
-  using Usage = sem::ParameterUsage;
+    using Usage = sem::ParameterUsage;
 
-  auto& signature = builtin->Signature();
-  auto* expr = call->Declaration();
-  auto& arguments = call->Arguments();
+    auto& signature = builtin->Signature();
+    auto* expr = call->Declaration();
+    auto& arguments = call->Arguments();
 
-  // Returns the argument with the given usage
-  auto arg = [&](Usage usage) {
-    int idx = signature.IndexOf(usage);
-    return (idx >= 0) ? arguments[idx] : nullptr;
-  };
+    // Returns the argument with the given usage
+    auto arg = [&](Usage usage) {
+        int idx = signature.IndexOf(usage);
+        return (idx >= 0) ? arguments[idx] : nullptr;
+    };
 
-  auto* texture = arg(Usage::kTexture)->Declaration();
-  if (!texture) {
-    TINT_ICE(Writer, diagnostics_) << "missing texture arg";
-    return false;
-  }
-
-  auto* texture_type = TypeOf(texture)->UnwrapRef()->As<sem::Texture>();
-
-  // Helper to emit the texture expression, wrapped in parentheses if the
-  // expression includes an operator with lower precedence than the member
-  // accessor used for the function calls.
-  auto texture_expr = [&]() {
-    bool paren_lhs =
-        !texture->IsAnyOf<ast::IndexAccessorExpression, ast::CallExpression,
-                          ast::IdentifierExpression,
-                          ast::MemberAccessorExpression>();
-    if (paren_lhs) {
-      out << "(";
+    auto* texture = arg(Usage::kTexture)->Declaration();
+    if (!texture) {
+        TINT_ICE(Writer, diagnostics_) << "missing texture arg";
+        return false;
     }
-    if (!EmitExpression(out, texture)) {
-      return false;
-    }
-    if (paren_lhs) {
-      out << ")";
-    }
-    return true;
-  };
 
-  // MSL requires that `lod` is a constant 0 for 1D textures.
-  bool level_is_constant_zero =
-      texture_type->dim() == ast::TextureDimension::k1d;
+    auto* texture_type = TypeOf(texture)->UnwrapRef()->As<sem::Texture>();
 
-  switch (builtin->Type()) {
-    case sem::BuiltinType::kTextureDimensions: {
-      std::vector<const char*> dims;
-      switch (texture_type->dim()) {
-        case ast::TextureDimension::kNone:
-          diagnostics_.add_error(diag::System::Writer,
-                                 "texture dimension is kNone");
-          return false;
-        case ast::TextureDimension::k1d:
-          dims = {"width"};
-          break;
-        case ast::TextureDimension::k2d:
-        case ast::TextureDimension::k2dArray:
-        case ast::TextureDimension::kCube:
-        case ast::TextureDimension::kCubeArray:
-          dims = {"width", "height"};
-          break;
-        case ast::TextureDimension::k3d:
-          dims = {"width", "height", "depth"};
-          break;
-      }
-
-      auto get_dim = [&](const char* name) {
-        if (!texture_expr()) {
-          return false;
+    // Helper to emit the texture expression, wrapped in parentheses if the
+    // expression includes an operator with lower precedence than the member
+    // accessor used for the function calls.
+    auto texture_expr = [&]() {
+        bool paren_lhs =
+            !texture->IsAnyOf<ast::IndexAccessorExpression, ast::CallExpression,
+                              ast::IdentifierExpression, ast::MemberAccessorExpression>();
+        if (paren_lhs) {
+            out << "(";
         }
-        out << ".get_" << name << "(";
-        if (level_is_constant_zero) {
-          out << "0";
-        } else {
-          if (auto* level = arg(Usage::kLevel)) {
-            if (!EmitExpression(out, level->Declaration())) {
-              return false;
-            }
-          }
+        if (!EmitExpression(out, texture)) {
+            return false;
         }
-        out << ")";
+        if (paren_lhs) {
+            out << ")";
+        }
         return true;
-      };
+    };
 
-      if (dims.size() == 1) {
-        out << "int(";
-        get_dim(dims[0]);
-        out << ")";
-      } else {
-        EmitType(out, TypeOf(expr)->UnwrapRef(), "");
-        out << "(";
-        for (size_t i = 0; i < dims.size(); i++) {
-          if (i > 0) {
-            out << ", ";
-          }
-          get_dim(dims[i]);
+    // MSL requires that `lod` is a constant 0 for 1D textures.
+    bool level_is_constant_zero = texture_type->dim() == ast::TextureDimension::k1d;
+
+    switch (builtin->Type()) {
+        case sem::BuiltinType::kTextureDimensions: {
+            std::vector<const char*> dims;
+            switch (texture_type->dim()) {
+                case ast::TextureDimension::kNone:
+                    diagnostics_.add_error(diag::System::Writer, "texture dimension is kNone");
+                    return false;
+                case ast::TextureDimension::k1d:
+                    dims = {"width"};
+                    break;
+                case ast::TextureDimension::k2d:
+                case ast::TextureDimension::k2dArray:
+                case ast::TextureDimension::kCube:
+                case ast::TextureDimension::kCubeArray:
+                    dims = {"width", "height"};
+                    break;
+                case ast::TextureDimension::k3d:
+                    dims = {"width", "height", "depth"};
+                    break;
+            }
+
+            auto get_dim = [&](const char* name) {
+                if (!texture_expr()) {
+                    return false;
+                }
+                out << ".get_" << name << "(";
+                if (level_is_constant_zero) {
+                    out << "0";
+                } else {
+                    if (auto* level = arg(Usage::kLevel)) {
+                        if (!EmitExpression(out, level->Declaration())) {
+                            return false;
+                        }
+                    }
+                }
+                out << ")";
+                return true;
+            };
+
+            if (dims.size() == 1) {
+                out << "int(";
+                get_dim(dims[0]);
+                out << ")";
+            } else {
+                EmitType(out, TypeOf(expr)->UnwrapRef(), "");
+                out << "(";
+                for (size_t i = 0; i < dims.size(); i++) {
+                    if (i > 0) {
+                        out << ", ";
+                    }
+                    get_dim(dims[i]);
+                }
+                out << ")";
+            }
+            return true;
         }
-        out << ")";
-      }
-      return true;
-    }
-    case sem::BuiltinType::kTextureNumLayers: {
-      out << "int(";
-      if (!texture_expr()) {
-        return false;
-      }
-      out << ".get_array_size())";
-      return true;
-    }
-    case sem::BuiltinType::kTextureNumLevels: {
-      out << "int(";
-      if (!texture_expr()) {
-        return false;
-      }
-      out << ".get_num_mip_levels())";
-      return true;
-    }
-    case sem::BuiltinType::kTextureNumSamples: {
-      out << "int(";
-      if (!texture_expr()) {
-        return false;
-      }
-      out << ".get_num_samples())";
-      return true;
-    }
-    default:
-      break;
-  }
-
-  if (!texture_expr()) {
-    return false;
-  }
-
-  bool lod_param_is_named = true;
-
-  switch (builtin->Type()) {
-    case sem::BuiltinType::kTextureSample:
-    case sem::BuiltinType::kTextureSampleBias:
-    case sem::BuiltinType::kTextureSampleLevel:
-    case sem::BuiltinType::kTextureSampleGrad:
-      out << ".sample(";
-      break;
-    case sem::BuiltinType::kTextureSampleCompare:
-    case sem::BuiltinType::kTextureSampleCompareLevel:
-      out << ".sample_compare(";
-      break;
-    case sem::BuiltinType::kTextureGather:
-      out << ".gather(";
-      break;
-    case sem::BuiltinType::kTextureGatherCompare:
-      out << ".gather_compare(";
-      break;
-    case sem::BuiltinType::kTextureLoad:
-      out << ".read(";
-      lod_param_is_named = false;
-      break;
-    case sem::BuiltinType::kTextureStore:
-      out << ".write(";
-      break;
-    default:
-      TINT_UNREACHABLE(Writer, diagnostics_)
-          << "Unhandled texture builtin '" << builtin->str() << "'";
-      return false;
-  }
-
-  bool first_arg = true;
-  auto maybe_write_comma = [&] {
-    if (!first_arg) {
-      out << ", ";
-    }
-    first_arg = false;
-  };
-
-  for (auto usage :
-       {Usage::kValue, Usage::kSampler, Usage::kCoords, Usage::kArrayIndex,
-        Usage::kDepthRef, Usage::kSampleIndex}) {
-    if (auto* e = arg(usage)) {
-      maybe_write_comma();
-
-      // Cast the coordinates to unsigned integers if necessary.
-      bool casted = false;
-      if (usage == Usage::kCoords &&
-          e->Type()->UnwrapRef()->is_integer_scalar_or_vector()) {
-        casted = true;
-        switch (texture_type->dim()) {
-          case ast::TextureDimension::k1d:
-            out << "uint(";
-            break;
-          case ast::TextureDimension::k2d:
-          case ast::TextureDimension::k2dArray:
-            out << "uint2(";
-            break;
-          case ast::TextureDimension::k3d:
-            out << "uint3(";
-            break;
-          default:
-            TINT_ICE(Writer, diagnostics_)
-                << "unhandled texture dimensionality";
-            break;
+        case sem::BuiltinType::kTextureNumLayers: {
+            out << "int(";
+            if (!texture_expr()) {
+                return false;
+            }
+            out << ".get_array_size())";
+            return true;
         }
-      }
-
-      if (!EmitExpression(out, e->Declaration()))
-        return false;
-
-      if (casted) {
-        out << ")";
-      }
-    }
-  }
-
-  if (auto* bias = arg(Usage::kBias)) {
-    maybe_write_comma();
-    out << "bias(";
-    if (!EmitExpression(out, bias->Declaration())) {
-      return false;
-    }
-    out << ")";
-  }
-  if (auto* level = arg(Usage::kLevel)) {
-    maybe_write_comma();
-    if (lod_param_is_named) {
-      out << "level(";
-    }
-    if (level_is_constant_zero) {
-      out << "0";
-    } else {
-      if (!EmitExpression(out, level->Declaration())) {
-        return false;
-      }
-    }
-    if (lod_param_is_named) {
-      out << ")";
-    }
-  }
-  if (builtin->Type() == sem::BuiltinType::kTextureSampleCompareLevel) {
-    maybe_write_comma();
-    out << "level(0)";
-  }
-  if (auto* ddx = arg(Usage::kDdx)) {
-    auto dim = texture_type->dim();
-    switch (dim) {
-      case ast::TextureDimension::k2d:
-      case ast::TextureDimension::k2dArray:
-        maybe_write_comma();
-        out << "gradient2d(";
-        break;
-      case ast::TextureDimension::k3d:
-        maybe_write_comma();
-        out << "gradient3d(";
-        break;
-      case ast::TextureDimension::kCube:
-      case ast::TextureDimension::kCubeArray:
-        maybe_write_comma();
-        out << "gradientcube(";
-        break;
-      default: {
-        std::stringstream err;
-        err << "MSL does not support gradients for " << dim << " textures";
-        diagnostics_.add_error(diag::System::Writer, err.str());
-        return false;
-      }
-    }
-    if (!EmitExpression(out, ddx->Declaration())) {
-      return false;
-    }
-    out << ", ";
-    if (!EmitExpression(out, arg(Usage::kDdy)->Declaration())) {
-      return false;
-    }
-    out << ")";
-  }
-
-  bool has_offset = false;
-  if (auto* offset = arg(Usage::kOffset)) {
-    has_offset = true;
-    maybe_write_comma();
-    if (!EmitExpression(out, offset->Declaration())) {
-      return false;
-    }
-  }
-
-  if (auto* component = arg(Usage::kComponent)) {
-    maybe_write_comma();
-    if (!has_offset) {
-      // offset argument may need to be provided if we have a component.
-      switch (texture_type->dim()) {
-        case ast::TextureDimension::k2d:
-        case ast::TextureDimension::k2dArray:
-          out << "int2(0), ";
-          break;
+        case sem::BuiltinType::kTextureNumLevels: {
+            out << "int(";
+            if (!texture_expr()) {
+                return false;
+            }
+            out << ".get_num_mip_levels())";
+            return true;
+        }
+        case sem::BuiltinType::kTextureNumSamples: {
+            out << "int(";
+            if (!texture_expr()) {
+                return false;
+            }
+            out << ".get_num_samples())";
+            return true;
+        }
         default:
-          break;  // Other texture dimensions don't have an offset
-      }
+            break;
     }
-    auto c = component->ConstantValue().Elements()[0].i32;
-    switch (c) {
-      case 0:
-        out << "component::x";
-        break;
-      case 1:
-        out << "component::y";
-        break;
-      case 2:
-        out << "component::z";
-        break;
-      case 3:
-        out << "component::w";
-        break;
-      default:
-        TINT_ICE(Writer, diagnostics_)
-            << "invalid textureGather component: " << c;
-        break;
+
+    if (!texture_expr()) {
+        return false;
     }
-  }
 
-  out << ")";
+    bool lod_param_is_named = true;
 
-  return true;
+    switch (builtin->Type()) {
+        case sem::BuiltinType::kTextureSample:
+        case sem::BuiltinType::kTextureSampleBias:
+        case sem::BuiltinType::kTextureSampleLevel:
+        case sem::BuiltinType::kTextureSampleGrad:
+            out << ".sample(";
+            break;
+        case sem::BuiltinType::kTextureSampleCompare:
+        case sem::BuiltinType::kTextureSampleCompareLevel:
+            out << ".sample_compare(";
+            break;
+        case sem::BuiltinType::kTextureGather:
+            out << ".gather(";
+            break;
+        case sem::BuiltinType::kTextureGatherCompare:
+            out << ".gather_compare(";
+            break;
+        case sem::BuiltinType::kTextureLoad:
+            out << ".read(";
+            lod_param_is_named = false;
+            break;
+        case sem::BuiltinType::kTextureStore:
+            out << ".write(";
+            break;
+        default:
+            TINT_UNREACHABLE(Writer, diagnostics_)
+                << "Unhandled texture builtin '" << builtin->str() << "'";
+            return false;
+    }
+
+    bool first_arg = true;
+    auto maybe_write_comma = [&] {
+        if (!first_arg) {
+            out << ", ";
+        }
+        first_arg = false;
+    };
+
+    for (auto usage : {Usage::kValue, Usage::kSampler, Usage::kCoords, Usage::kArrayIndex,
+                       Usage::kDepthRef, Usage::kSampleIndex}) {
+        if (auto* e = arg(usage)) {
+            maybe_write_comma();
+
+            // Cast the coordinates to unsigned integers if necessary.
+            bool casted = false;
+            if (usage == Usage::kCoords && e->Type()->UnwrapRef()->is_integer_scalar_or_vector()) {
+                casted = true;
+                switch (texture_type->dim()) {
+                    case ast::TextureDimension::k1d:
+                        out << "uint(";
+                        break;
+                    case ast::TextureDimension::k2d:
+                    case ast::TextureDimension::k2dArray:
+                        out << "uint2(";
+                        break;
+                    case ast::TextureDimension::k3d:
+                        out << "uint3(";
+                        break;
+                    default:
+                        TINT_ICE(Writer, diagnostics_) << "unhandled texture dimensionality";
+                        break;
+                }
+            }
+
+            if (!EmitExpression(out, e->Declaration()))
+                return false;
+
+            if (casted) {
+                out << ")";
+            }
+        }
+    }
+
+    if (auto* bias = arg(Usage::kBias)) {
+        maybe_write_comma();
+        out << "bias(";
+        if (!EmitExpression(out, bias->Declaration())) {
+            return false;
+        }
+        out << ")";
+    }
+    if (auto* level = arg(Usage::kLevel)) {
+        maybe_write_comma();
+        if (lod_param_is_named) {
+            out << "level(";
+        }
+        if (level_is_constant_zero) {
+            out << "0";
+        } else {
+            if (!EmitExpression(out, level->Declaration())) {
+                return false;
+            }
+        }
+        if (lod_param_is_named) {
+            out << ")";
+        }
+    }
+    if (builtin->Type() == sem::BuiltinType::kTextureSampleCompareLevel) {
+        maybe_write_comma();
+        out << "level(0)";
+    }
+    if (auto* ddx = arg(Usage::kDdx)) {
+        auto dim = texture_type->dim();
+        switch (dim) {
+            case ast::TextureDimension::k2d:
+            case ast::TextureDimension::k2dArray:
+                maybe_write_comma();
+                out << "gradient2d(";
+                break;
+            case ast::TextureDimension::k3d:
+                maybe_write_comma();
+                out << "gradient3d(";
+                break;
+            case ast::TextureDimension::kCube:
+            case ast::TextureDimension::kCubeArray:
+                maybe_write_comma();
+                out << "gradientcube(";
+                break;
+            default: {
+                std::stringstream err;
+                err << "MSL does not support gradients for " << dim << " textures";
+                diagnostics_.add_error(diag::System::Writer, err.str());
+                return false;
+            }
+        }
+        if (!EmitExpression(out, ddx->Declaration())) {
+            return false;
+        }
+        out << ", ";
+        if (!EmitExpression(out, arg(Usage::kDdy)->Declaration())) {
+            return false;
+        }
+        out << ")";
+    }
+
+    bool has_offset = false;
+    if (auto* offset = arg(Usage::kOffset)) {
+        has_offset = true;
+        maybe_write_comma();
+        if (!EmitExpression(out, offset->Declaration())) {
+            return false;
+        }
+    }
+
+    if (auto* component = arg(Usage::kComponent)) {
+        maybe_write_comma();
+        if (!has_offset) {
+            // offset argument may need to be provided if we have a component.
+            switch (texture_type->dim()) {
+                case ast::TextureDimension::k2d:
+                case ast::TextureDimension::k2dArray:
+                    out << "int2(0), ";
+                    break;
+                default:
+                    break;  // Other texture dimensions don't have an offset
+            }
+        }
+        auto c = component->ConstantValue().Elements()[0].i32;
+        switch (c) {
+            case 0:
+                out << "component::x";
+                break;
+            case 1:
+                out << "component::y";
+                break;
+            case 2:
+                out << "component::z";
+                break;
+            case 3:
+                out << "component::w";
+                break;
+            default:
+                TINT_ICE(Writer, diagnostics_) << "invalid textureGather component: " << c;
+                break;
+        }
+    }
+
+    out << ")";
+
+    return true;
 }
 
 bool GeneratorImpl::EmitDotCall(std::ostream& out,
                                 const ast::CallExpression* expr,
                                 const sem::Builtin* builtin) {
-  auto* vec_ty = builtin->Parameters()[0]->Type()->As<sem::Vector>();
-  std::string fn = "dot";
-  if (vec_ty->type()->is_integer_scalar()) {
-    // MSL does not have a builtin for dot() with integer vector types.
-    // Generate the helper function if it hasn't been created already
-    fn = utils::GetOrCreate(
-        int_dot_funcs_, vec_ty->Width(), [&]() -> std::string {
-          TextBuffer b;
-          TINT_DEFER(helpers_.Append(b));
+    auto* vec_ty = builtin->Parameters()[0]->Type()->As<sem::Vector>();
+    std::string fn = "dot";
+    if (vec_ty->type()->is_integer_scalar()) {
+        // MSL does not have a builtin for dot() with integer vector types.
+        // Generate the helper function if it hasn't been created already
+        fn = utils::GetOrCreate(int_dot_funcs_, vec_ty->Width(), [&]() -> std::string {
+            TextBuffer b;
+            TINT_DEFER(helpers_.Append(b));
 
-          auto fn_name =
-              UniqueIdentifier("tint_dot" + std::to_string(vec_ty->Width()));
-          auto v = "vec<T," + std::to_string(vec_ty->Width()) + ">";
+            auto fn_name = UniqueIdentifier("tint_dot" + std::to_string(vec_ty->Width()));
+            auto v = "vec<T," + std::to_string(vec_ty->Width()) + ">";
 
-          line(&b) << "template<typename T>";
-          line(&b) << "T " << fn_name << "(" << v << " a, " << v << " b) {";
-          {
-            auto l = line(&b);
-            l << "  return ";
-            for (uint32_t i = 0; i < vec_ty->Width(); i++) {
-              if (i > 0) {
-                l << " + ";
-              }
-              l << "a[" << i << "]*b[" << i << "]";
+            line(&b) << "template<typename T>";
+            line(&b) << "T " << fn_name << "(" << v << " a, " << v << " b) {";
+            {
+                auto l = line(&b);
+                l << "  return ";
+                for (uint32_t i = 0; i < vec_ty->Width(); i++) {
+                    if (i > 0) {
+                        l << " + ";
+                    }
+                    l << "a[" << i << "]*b[" << i << "]";
+                }
+                l << ";";
             }
-            l << ";";
-          }
-          line(&b) << "}";
-          return fn_name;
+            line(&b) << "}";
+            return fn_name;
         });
-  }
+    }
 
-  out << fn << "(";
-  if (!EmitExpression(out, expr->args[0])) {
-    return false;
-  }
-  out << ", ";
-  if (!EmitExpression(out, expr->args[1])) {
-    return false;
-  }
-  out << ")";
-  return true;
+    out << fn << "(";
+    if (!EmitExpression(out, expr->args[0])) {
+        return false;
+    }
+    out << ", ";
+    if (!EmitExpression(out, expr->args[1])) {
+        return false;
+    }
+    out << ")";
+    return true;
 }
 
 bool GeneratorImpl::EmitModfCall(std::ostream& out,
                                  const ast::CallExpression* expr,
                                  const sem::Builtin* builtin) {
-  return CallBuiltinHelper(
-      out, expr, builtin,
-      [&](TextBuffer* b, const std::vector<std::string>& params) {
-        auto* ty = builtin->Parameters()[0]->Type();
-        auto in = params[0];
+    return CallBuiltinHelper(
+        out, expr, builtin, [&](TextBuffer* b, const std::vector<std::string>& params) {
+            auto* ty = builtin->Parameters()[0]->Type();
+            auto in = params[0];
 
-        std::string width;
-        if (auto* vec = ty->As<sem::Vector>()) {
-          width = std::to_string(vec->Width());
-        }
+            std::string width;
+            if (auto* vec = ty->As<sem::Vector>()) {
+                width = std::to_string(vec->Width());
+            }
 
-        // Emit the builtin return type unique to this overload. This does not
-        // exist in the AST, so it will not be generated in Generate().
-        if (!EmitStructType(&helpers_,
-                            builtin->ReturnType()->As<sem::Struct>())) {
-          return false;
-        }
+            // Emit the builtin return type unique to this overload. This does not
+            // exist in the AST, so it will not be generated in Generate().
+            if (!EmitStructType(&helpers_, builtin->ReturnType()->As<sem::Struct>())) {
+                return false;
+            }
 
-        line(b) << "float" << width << " whole;";
-        line(b) << "float" << width << " fract = modf(" << in << ", whole);";
-        line(b) << "return {fract, whole};";
-        return true;
-      });
+            line(b) << "float" << width << " whole;";
+            line(b) << "float" << width << " fract = modf(" << in << ", whole);";
+            line(b) << "return {fract, whole};";
+            return true;
+        });
 }
 
 bool GeneratorImpl::EmitFrexpCall(std::ostream& out,
                                   const ast::CallExpression* expr,
                                   const sem::Builtin* builtin) {
-  return CallBuiltinHelper(
-      out, expr, builtin,
-      [&](TextBuffer* b, const std::vector<std::string>& params) {
-        auto* ty = builtin->Parameters()[0]->Type();
-        auto in = params[0];
+    return CallBuiltinHelper(
+        out, expr, builtin, [&](TextBuffer* b, const std::vector<std::string>& params) {
+            auto* ty = builtin->Parameters()[0]->Type();
+            auto in = params[0];
 
-        std::string width;
-        if (auto* vec = ty->As<sem::Vector>()) {
-          width = std::to_string(vec->Width());
-        }
+            std::string width;
+            if (auto* vec = ty->As<sem::Vector>()) {
+                width = std::to_string(vec->Width());
+            }
 
-        // Emit the builtin return type unique to this overload. This does not
-        // exist in the AST, so it will not be generated in Generate().
-        if (!EmitStructType(&helpers_,
-                            builtin->ReturnType()->As<sem::Struct>())) {
-          return false;
-        }
+            // Emit the builtin return type unique to this overload. This does not
+            // exist in the AST, so it will not be generated in Generate().
+            if (!EmitStructType(&helpers_, builtin->ReturnType()->As<sem::Struct>())) {
+                return false;
+            }
 
-        line(b) << "int" << width << " exp;";
-        line(b) << "float" << width << " sig = frexp(" << in << ", exp);";
-        line(b) << "return {sig, exp};";
-        return true;
-      });
+            line(b) << "int" << width << " exp;";
+            line(b) << "float" << width << " sig = frexp(" << in << ", exp);";
+            line(b) << "return {sig, exp};";
+            return true;
+        });
 }
 
 bool GeneratorImpl::EmitDegreesCall(std::ostream& out,
                                     const ast::CallExpression* expr,
                                     const sem::Builtin* builtin) {
-  return CallBuiltinHelper(
-      out, expr, builtin,
-      [&](TextBuffer* b, const std::vector<std::string>& params) {
-        line(b) << "return " << params[0] << " * " << std::setprecision(20)
-                << sem::kRadToDeg << ";";
-        return true;
-      });
+    return CallBuiltinHelper(out, expr, builtin,
+                             [&](TextBuffer* b, const std::vector<std::string>& params) {
+                                 line(b) << "return " << params[0] << " * " << std::setprecision(20)
+                                         << sem::kRadToDeg << ";";
+                                 return true;
+                             });
 }
 
 bool GeneratorImpl::EmitRadiansCall(std::ostream& out,
                                     const ast::CallExpression* expr,
                                     const sem::Builtin* builtin) {
-  return CallBuiltinHelper(
-      out, expr, builtin,
-      [&](TextBuffer* b, const std::vector<std::string>& params) {
-        line(b) << "return " << params[0] << " * " << std::setprecision(20)
-                << sem::kDegToRad << ";";
-        return true;
-      });
+    return CallBuiltinHelper(out, expr, builtin,
+                             [&](TextBuffer* b, const std::vector<std::string>& params) {
+                                 line(b) << "return " << params[0] << " * " << std::setprecision(20)
+                                         << sem::kDegToRad << ";";
+                                 return true;
+                             });
 }
 
 std::string GeneratorImpl::generate_builtin_name(const sem::Builtin* builtin) {
-  std::string out = "";
-  switch (builtin->Type()) {
-    case sem::BuiltinType::kAcos:
-    case sem::BuiltinType::kAll:
-    case sem::BuiltinType::kAny:
-    case sem::BuiltinType::kAsin:
-    case sem::BuiltinType::kAtan:
-    case sem::BuiltinType::kAtan2:
-    case sem::BuiltinType::kCeil:
-    case sem::BuiltinType::kCos:
-    case sem::BuiltinType::kCosh:
-    case sem::BuiltinType::kCross:
-    case sem::BuiltinType::kDeterminant:
-    case sem::BuiltinType::kDistance:
-    case sem::BuiltinType::kDot:
-    case sem::BuiltinType::kExp:
-    case sem::BuiltinType::kExp2:
-    case sem::BuiltinType::kFloor:
-    case sem::BuiltinType::kFma:
-    case sem::BuiltinType::kFract:
-    case sem::BuiltinType::kFrexp:
-    case sem::BuiltinType::kLength:
-    case sem::BuiltinType::kLdexp:
-    case sem::BuiltinType::kLog:
-    case sem::BuiltinType::kLog2:
-    case sem::BuiltinType::kMix:
-    case sem::BuiltinType::kModf:
-    case sem::BuiltinType::kNormalize:
-    case sem::BuiltinType::kPow:
-    case sem::BuiltinType::kReflect:
-    case sem::BuiltinType::kRefract:
-    case sem::BuiltinType::kSelect:
-    case sem::BuiltinType::kSin:
-    case sem::BuiltinType::kSinh:
-    case sem::BuiltinType::kSqrt:
-    case sem::BuiltinType::kStep:
-    case sem::BuiltinType::kTan:
-    case sem::BuiltinType::kTanh:
-    case sem::BuiltinType::kTranspose:
-    case sem::BuiltinType::kTrunc:
-    case sem::BuiltinType::kSign:
-    case sem::BuiltinType::kClamp:
-      out += builtin->str();
-      break;
-    case sem::BuiltinType::kAbs:
-      if (builtin->ReturnType()->is_float_scalar_or_vector()) {
-        out += "fabs";
-      } else {
-        out += "abs";
-      }
-      break;
-    case sem::BuiltinType::kCountLeadingZeros:
-      out += "clz";
-      break;
-    case sem::BuiltinType::kCountOneBits:
-      out += "popcount";
-      break;
-    case sem::BuiltinType::kCountTrailingZeros:
-      out += "ctz";
-      break;
-    case sem::BuiltinType::kDpdx:
-    case sem::BuiltinType::kDpdxCoarse:
-    case sem::BuiltinType::kDpdxFine:
-      out += "dfdx";
-      break;
-    case sem::BuiltinType::kDpdy:
-    case sem::BuiltinType::kDpdyCoarse:
-    case sem::BuiltinType::kDpdyFine:
-      out += "dfdy";
-      break;
-    case sem::BuiltinType::kExtractBits:
-      out += "extract_bits";
-      break;
-    case sem::BuiltinType::kInsertBits:
-      out += "insert_bits";
-      break;
-    case sem::BuiltinType::kFwidth:
-    case sem::BuiltinType::kFwidthCoarse:
-    case sem::BuiltinType::kFwidthFine:
-      out += "fwidth";
-      break;
-    case sem::BuiltinType::kMax:
-      if (builtin->ReturnType()->is_float_scalar_or_vector()) {
-        out += "fmax";
-      } else {
-        out += "max";
-      }
-      break;
-    case sem::BuiltinType::kMin:
-      if (builtin->ReturnType()->is_float_scalar_or_vector()) {
-        out += "fmin";
-      } else {
-        out += "min";
-      }
-      break;
-    case sem::BuiltinType::kFaceForward:
-      out += "faceforward";
-      break;
-    case sem::BuiltinType::kPack4x8snorm:
-      out += "pack_float_to_snorm4x8";
-      break;
-    case sem::BuiltinType::kPack4x8unorm:
-      out += "pack_float_to_unorm4x8";
-      break;
-    case sem::BuiltinType::kPack2x16snorm:
-      out += "pack_float_to_snorm2x16";
-      break;
-    case sem::BuiltinType::kPack2x16unorm:
-      out += "pack_float_to_unorm2x16";
-      break;
-    case sem::BuiltinType::kReverseBits:
-      out += "reverse_bits";
-      break;
-    case sem::BuiltinType::kRound:
-      out += "rint";
-      break;
-    case sem::BuiltinType::kSmoothstep:
-    case sem::BuiltinType::kSmoothStep:
-      out += "smoothstep";
-      break;
-    case sem::BuiltinType::kInverseSqrt:
-      out += "rsqrt";
-      break;
-    case sem::BuiltinType::kUnpack4x8snorm:
-      out += "unpack_snorm4x8_to_float";
-      break;
-    case sem::BuiltinType::kUnpack4x8unorm:
-      out += "unpack_unorm4x8_to_float";
-      break;
-    case sem::BuiltinType::kUnpack2x16snorm:
-      out += "unpack_snorm2x16_to_float";
-      break;
-    case sem::BuiltinType::kUnpack2x16unorm:
-      out += "unpack_unorm2x16_to_float";
-      break;
-    case sem::BuiltinType::kArrayLength:
-      diagnostics_.add_error(
-          diag::System::Writer,
-          "Unable to translate builtin: " + std::string(builtin->str()) +
-              "\nDid you forget to pass array_length_from_uniform generator "
-              "options?");
-      return "";
-    default:
-      diagnostics_.add_error(
-          diag::System::Writer,
-          "Unknown import method: " + std::string(builtin->str()));
-      return "";
-  }
-  return out;
+    std::string out = "";
+    switch (builtin->Type()) {
+        case sem::BuiltinType::kAcos:
+        case sem::BuiltinType::kAll:
+        case sem::BuiltinType::kAny:
+        case sem::BuiltinType::kAsin:
+        case sem::BuiltinType::kAtan:
+        case sem::BuiltinType::kAtan2:
+        case sem::BuiltinType::kCeil:
+        case sem::BuiltinType::kCos:
+        case sem::BuiltinType::kCosh:
+        case sem::BuiltinType::kCross:
+        case sem::BuiltinType::kDeterminant:
+        case sem::BuiltinType::kDistance:
+        case sem::BuiltinType::kDot:
+        case sem::BuiltinType::kExp:
+        case sem::BuiltinType::kExp2:
+        case sem::BuiltinType::kFloor:
+        case sem::BuiltinType::kFma:
+        case sem::BuiltinType::kFract:
+        case sem::BuiltinType::kFrexp:
+        case sem::BuiltinType::kLength:
+        case sem::BuiltinType::kLdexp:
+        case sem::BuiltinType::kLog:
+        case sem::BuiltinType::kLog2:
+        case sem::BuiltinType::kMix:
+        case sem::BuiltinType::kModf:
+        case sem::BuiltinType::kNormalize:
+        case sem::BuiltinType::kPow:
+        case sem::BuiltinType::kReflect:
+        case sem::BuiltinType::kRefract:
+        case sem::BuiltinType::kSelect:
+        case sem::BuiltinType::kSin:
+        case sem::BuiltinType::kSinh:
+        case sem::BuiltinType::kSqrt:
+        case sem::BuiltinType::kStep:
+        case sem::BuiltinType::kTan:
+        case sem::BuiltinType::kTanh:
+        case sem::BuiltinType::kTranspose:
+        case sem::BuiltinType::kTrunc:
+        case sem::BuiltinType::kSign:
+        case sem::BuiltinType::kClamp:
+            out += builtin->str();
+            break;
+        case sem::BuiltinType::kAbs:
+            if (builtin->ReturnType()->is_float_scalar_or_vector()) {
+                out += "fabs";
+            } else {
+                out += "abs";
+            }
+            break;
+        case sem::BuiltinType::kCountLeadingZeros:
+            out += "clz";
+            break;
+        case sem::BuiltinType::kCountOneBits:
+            out += "popcount";
+            break;
+        case sem::BuiltinType::kCountTrailingZeros:
+            out += "ctz";
+            break;
+        case sem::BuiltinType::kDpdx:
+        case sem::BuiltinType::kDpdxCoarse:
+        case sem::BuiltinType::kDpdxFine:
+            out += "dfdx";
+            break;
+        case sem::BuiltinType::kDpdy:
+        case sem::BuiltinType::kDpdyCoarse:
+        case sem::BuiltinType::kDpdyFine:
+            out += "dfdy";
+            break;
+        case sem::BuiltinType::kExtractBits:
+            out += "extract_bits";
+            break;
+        case sem::BuiltinType::kInsertBits:
+            out += "insert_bits";
+            break;
+        case sem::BuiltinType::kFwidth:
+        case sem::BuiltinType::kFwidthCoarse:
+        case sem::BuiltinType::kFwidthFine:
+            out += "fwidth";
+            break;
+        case sem::BuiltinType::kMax:
+            if (builtin->ReturnType()->is_float_scalar_or_vector()) {
+                out += "fmax";
+            } else {
+                out += "max";
+            }
+            break;
+        case sem::BuiltinType::kMin:
+            if (builtin->ReturnType()->is_float_scalar_or_vector()) {
+                out += "fmin";
+            } else {
+                out += "min";
+            }
+            break;
+        case sem::BuiltinType::kFaceForward:
+            out += "faceforward";
+            break;
+        case sem::BuiltinType::kPack4x8snorm:
+            out += "pack_float_to_snorm4x8";
+            break;
+        case sem::BuiltinType::kPack4x8unorm:
+            out += "pack_float_to_unorm4x8";
+            break;
+        case sem::BuiltinType::kPack2x16snorm:
+            out += "pack_float_to_snorm2x16";
+            break;
+        case sem::BuiltinType::kPack2x16unorm:
+            out += "pack_float_to_unorm2x16";
+            break;
+        case sem::BuiltinType::kReverseBits:
+            out += "reverse_bits";
+            break;
+        case sem::BuiltinType::kRound:
+            out += "rint";
+            break;
+        case sem::BuiltinType::kSmoothstep:
+        case sem::BuiltinType::kSmoothStep:
+            out += "smoothstep";
+            break;
+        case sem::BuiltinType::kInverseSqrt:
+            out += "rsqrt";
+            break;
+        case sem::BuiltinType::kUnpack4x8snorm:
+            out += "unpack_snorm4x8_to_float";
+            break;
+        case sem::BuiltinType::kUnpack4x8unorm:
+            out += "unpack_unorm4x8_to_float";
+            break;
+        case sem::BuiltinType::kUnpack2x16snorm:
+            out += "unpack_snorm2x16_to_float";
+            break;
+        case sem::BuiltinType::kUnpack2x16unorm:
+            out += "unpack_unorm2x16_to_float";
+            break;
+        case sem::BuiltinType::kArrayLength:
+            diagnostics_.add_error(
+                diag::System::Writer,
+                "Unable to translate builtin: " + std::string(builtin->str()) +
+                    "\nDid you forget to pass array_length_from_uniform generator "
+                    "options?");
+            return "";
+        default:
+            diagnostics_.add_error(diag::System::Writer,
+                                   "Unknown import method: " + std::string(builtin->str()));
+            return "";
+    }
+    return out;
 }
 
 bool GeneratorImpl::EmitCase(const ast::CaseStatement* stmt) {
-  if (stmt->IsDefault()) {
-    line() << "default: {";
-  } else {
-    for (auto* selector : stmt->selectors) {
-      auto out = line();
-      out << "case ";
-      if (!EmitLiteral(out, selector)) {
-        return false;
-      }
-      out << ":";
-      if (selector == stmt->selectors.back()) {
-        out << " {";
-      }
-    }
-  }
-
-  {
-    ScopedIndent si(this);
-
-    for (auto* s : stmt->body->statements) {
-      if (!EmitStatement(s)) {
-        return false;
-      }
+    if (stmt->IsDefault()) {
+        line() << "default: {";
+    } else {
+        for (auto* selector : stmt->selectors) {
+            auto out = line();
+            out << "case ";
+            if (!EmitLiteral(out, selector)) {
+                return false;
+            }
+            out << ":";
+            if (selector == stmt->selectors.back()) {
+                out << " {";
+            }
+        }
     }
 
-    if (!last_is_break_or_fallthrough(stmt->body)) {
-      line() << "break;";
+    {
+        ScopedIndent si(this);
+
+        for (auto* s : stmt->body->statements) {
+            if (!EmitStatement(s)) {
+                return false;
+            }
+        }
+
+        if (!last_is_break_or_fallthrough(stmt->body)) {
+            line() << "break;";
+        }
     }
-  }
 
-  line() << "}";
+    line() << "}";
 
-  return true;
+    return true;
 }
 
 bool GeneratorImpl::EmitContinue(const ast::ContinueStatement*) {
-  if (!emit_continuing_()) {
-    return false;
-  }
+    if (!emit_continuing_()) {
+        return false;
+    }
 
-  line() << "continue;";
-  return true;
+    line() << "continue;";
+    return true;
 }
 
 bool GeneratorImpl::EmitZeroValue(std::ostream& out, const sem::Type* type) {
-  return Switch(
-      type,
-      [&](const sem::Bool*) {
-        out << "false";
-        return true;
-      },
-      [&](const sem::F32*) {
-        out << "0.0f";
-        return true;
-      },
-      [&](const sem::I32*) {
-        out << "0";
-        return true;
-      },
-      [&](const sem::U32*) {
-        out << "0u";
-        return true;
-      },
-      [&](const sem::Vector* vec) {  //
-        return EmitZeroValue(out, vec->type());
-      },
-      [&](const sem::Matrix* mat) {
-        if (!EmitType(out, mat, "")) {
-          return false;
-        }
-        out << "(";
-        TINT_DEFER(out << ")");
-        return EmitZeroValue(out, mat->type());
-      },
-      [&](const sem::Array* arr) {
-        out << "{";
-        TINT_DEFER(out << "}");
-        return EmitZeroValue(out, arr->ElemType());
-      },
-      [&](const sem::Struct*) {
-        out << "{}";
-        return true;
-      },
-      [&](Default) {
-        diagnostics_.add_error(diag::System::Writer,
-                               "Invalid type for zero emission: " +
-                                   type->FriendlyName(builder_.Symbols()));
-        return false;
-      });
+    return Switch(
+        type,
+        [&](const sem::Bool*) {
+            out << "false";
+            return true;
+        },
+        [&](const sem::F32*) {
+            out << "0.0f";
+            return true;
+        },
+        [&](const sem::I32*) {
+            out << "0";
+            return true;
+        },
+        [&](const sem::U32*) {
+            out << "0u";
+            return true;
+        },
+        [&](const sem::Vector* vec) {  //
+            return EmitZeroValue(out, vec->type());
+        },
+        [&](const sem::Matrix* mat) {
+            if (!EmitType(out, mat, "")) {
+                return false;
+            }
+            out << "(";
+            TINT_DEFER(out << ")");
+            return EmitZeroValue(out, mat->type());
+        },
+        [&](const sem::Array* arr) {
+            out << "{";
+            TINT_DEFER(out << "}");
+            return EmitZeroValue(out, arr->ElemType());
+        },
+        [&](const sem::Struct*) {
+            out << "{}";
+            return true;
+        },
+        [&](Default) {
+            diagnostics_.add_error(
+                diag::System::Writer,
+                "Invalid type for zero emission: " + type->FriendlyName(builder_.Symbols()));
+            return false;
+        });
 }
 
-bool GeneratorImpl::EmitLiteral(std::ostream& out,
-                                const ast::LiteralExpression* lit) {
-  return Switch(
-      lit,
-      [&](const ast::BoolLiteralExpression* l) {
-        out << (l->value ? "true" : "false");
-        return true;
-      },
-      [&](const ast::FloatLiteralExpression* l) {
-        if (std::isinf(l->value)) {
-          out << (l->value >= 0 ? "INFINITY" : "-INFINITY");
-        } else if (std::isnan(l->value)) {
-          out << "NAN";
-        } else {
-          out << FloatToString(l->value) << "f";
-        }
-        return true;
-      },
-      [&](const ast::SintLiteralExpression* l) {
-        // MSL (and C++) parse `-2147483648` as a `long` because it parses
-        // unary minus and `2147483648` as separate tokens, and the latter
-        // doesn't fit into an (32-bit) `int`. WGSL, OTOH, parses this as an
-        // `i32`. To avoid issues with `long` to `int` casts, emit
-        // `(2147483647 - 1)` instead, which ensures the expression type is
-        // `int`.
-        const auto int_min = std::numeric_limits<int32_t>::min();
-        if (l->ValueAsI32() == int_min) {
-          out << "(" << int_min + 1 << " - 1)";
-        } else {
-          out << l->value;
-        }
-        return true;
-      },
-      [&](const ast::UintLiteralExpression* l) {
-        out << l->value << "u";
-        return true;
-      },
-      [&](Default) {
-        diagnostics_.add_error(diag::System::Writer, "unknown literal type");
-        return false;
-      });
+bool GeneratorImpl::EmitLiteral(std::ostream& out, const ast::LiteralExpression* lit) {
+    return Switch(
+        lit,
+        [&](const ast::BoolLiteralExpression* l) {
+            out << (l->value ? "true" : "false");
+            return true;
+        },
+        [&](const ast::FloatLiteralExpression* l) {
+            if (std::isinf(l->value)) {
+                out << (l->value >= 0 ? "INFINITY" : "-INFINITY");
+            } else if (std::isnan(l->value)) {
+                out << "NAN";
+            } else {
+                out << FloatToString(l->value) << "f";
+            }
+            return true;
+        },
+        [&](const ast::IntLiteralExpression* i) {
+            switch (i->suffix) {
+                case ast::IntLiteralExpression::Suffix::kNone:
+                case ast::IntLiteralExpression::Suffix::kI: {
+                    // MSL (and C++) parse `-2147483648` as a `long` because it parses
+                    // unary minus and `2147483648` as separate tokens, and the latter
+                    // doesn't fit into an (32-bit) `int`. WGSL, OTOH, parses this as an
+                    // `i32`. To avoid issues with `long` to `int` casts, emit
+                    // `(2147483647 - 1)` instead, which ensures the expression type is
+                    // `int`.
+                    const auto int_min = std::numeric_limits<int32_t>::min();
+                    if (i->value == int_min) {
+                        out << "(" << int_min + 1 << " - 1)";
+                    } else {
+                        out << i->value;
+                    }
+                    return true;
+                }
+                case ast::IntLiteralExpression::Suffix::kU: {
+                    out << i->value << "u";
+                    return true;
+                }
+            }
+            diagnostics_.add_error(diag::System::Writer, "unknown integer literal suffix type");
+            return false;
+        },
+        [&](Default) {
+            diagnostics_.add_error(diag::System::Writer, "unknown literal type");
+            return false;
+        });
 }
 
-bool GeneratorImpl::EmitExpression(std::ostream& out,
-                                   const ast::Expression* expr) {
-  return Switch(
-      expr,
-      [&](const ast::IndexAccessorExpression* a) {  //
-        return EmitIndexAccessor(out, a);
-      },
-      [&](const ast::BinaryExpression* b) {  //
-        return EmitBinary(out, b);
-      },
-      [&](const ast::BitcastExpression* b) {  //
-        return EmitBitcast(out, b);
-      },
-      [&](const ast::CallExpression* c) {  //
-        return EmitCall(out, c);
-      },
-      [&](const ast::IdentifierExpression* i) {  //
-        return EmitIdentifier(out, i);
-      },
-      [&](const ast::LiteralExpression* l) {  //
-        return EmitLiteral(out, l);
-      },
-      [&](const ast::MemberAccessorExpression* m) {  //
-        return EmitMemberAccessor(out, m);
-      },
-      [&](const ast::UnaryOpExpression* u) {  //
-        return EmitUnaryOp(out, u);
-      },
-      [&](Default) {  //
-        diagnostics_.add_error(
-            diag::System::Writer,
-            "unknown expression type: " + std::string(expr->TypeInfo().name));
-        return false;
-      });
+bool GeneratorImpl::EmitExpression(std::ostream& out, const ast::Expression* expr) {
+    return Switch(
+        expr,
+        [&](const ast::IndexAccessorExpression* a) {  //
+            return EmitIndexAccessor(out, a);
+        },
+        [&](const ast::BinaryExpression* b) {  //
+            return EmitBinary(out, b);
+        },
+        [&](const ast::BitcastExpression* b) {  //
+            return EmitBitcast(out, b);
+        },
+        [&](const ast::CallExpression* c) {  //
+            return EmitCall(out, c);
+        },
+        [&](const ast::IdentifierExpression* i) {  //
+            return EmitIdentifier(out, i);
+        },
+        [&](const ast::LiteralExpression* l) {  //
+            return EmitLiteral(out, l);
+        },
+        [&](const ast::MemberAccessorExpression* m) {  //
+            return EmitMemberAccessor(out, m);
+        },
+        [&](const ast::UnaryOpExpression* u) {  //
+            return EmitUnaryOp(out, u);
+        },
+        [&](Default) {  //
+            diagnostics_.add_error(diag::System::Writer, "unknown expression type: " +
+                                                             std::string(expr->TypeInfo().name));
+            return false;
+        });
 }
 
 void GeneratorImpl::EmitStage(std::ostream& out, ast::PipelineStage stage) {
-  switch (stage) {
-    case ast::PipelineStage::kFragment:
-      out << "fragment";
-      break;
-    case ast::PipelineStage::kVertex:
-      out << "vertex";
-      break;
-    case ast::PipelineStage::kCompute:
-      out << "kernel";
-      break;
-    case ast::PipelineStage::kNone:
-      break;
-  }
-  return;
+    switch (stage) {
+        case ast::PipelineStage::kFragment:
+            out << "fragment";
+            break;
+        case ast::PipelineStage::kVertex:
+            out << "vertex";
+            break;
+        case ast::PipelineStage::kCompute:
+            out << "kernel";
+            break;
+        case ast::PipelineStage::kNone:
+            break;
+    }
+    return;
 }
 
 bool GeneratorImpl::EmitFunction(const ast::Function* func) {
-  auto* func_sem = program_->Sem().Get(func);
+    auto* func_sem = program_->Sem().Get(func);
 
-  {
-    auto out = line();
-    if (!EmitType(out, func_sem->ReturnType(), "")) {
-      return false;
+    {
+        auto out = line();
+        if (!EmitType(out, func_sem->ReturnType(), "")) {
+            return false;
+        }
+        out << " " << program_->Symbols().NameFor(func->symbol) << "(";
+
+        bool first = true;
+        for (auto* v : func->params) {
+            if (!first) {
+                out << ", ";
+            }
+            first = false;
+
+            auto* type = program_->Sem().Get(v)->Type();
+
+            std::string param_name = "const " + program_->Symbols().NameFor(v->symbol);
+            if (!EmitType(out, type, param_name)) {
+                return false;
+            }
+            // Parameter name is output as part of the type for arrays and pointers.
+            if (!type->Is<sem::Array>() && !type->Is<sem::Pointer>()) {
+                out << " " << program_->Symbols().NameFor(v->symbol);
+            }
+        }
+
+        out << ") {";
     }
-    out << " " << program_->Symbols().NameFor(func->symbol) << "(";
 
-    bool first = true;
-    for (auto* v : func->params) {
-      if (!first) {
-        out << ", ";
-      }
-      first = false;
-
-      auto* type = program_->Sem().Get(v)->Type();
-
-      std::string param_name =
-          "const " + program_->Symbols().NameFor(v->symbol);
-      if (!EmitType(out, type, param_name)) {
+    if (!EmitStatementsWithIndent(func->body->statements)) {
         return false;
-      }
-      // Parameter name is output as part of the type for arrays and pointers.
-      if (!type->Is<sem::Array>() && !type->Is<sem::Pointer>()) {
-        out << " " << program_->Symbols().NameFor(v->symbol);
-      }
     }
 
-    out << ") {";
-  }
+    line() << "}";
 
-  if (!EmitStatementsWithIndent(func->body->statements)) {
-    return false;
-  }
-
-  line() << "}";
-
-  return true;
+    return true;
 }
 
 std::string GeneratorImpl::builtin_to_attribute(ast::Builtin builtin) const {
-  switch (builtin) {
-    case ast::Builtin::kPosition:
-      return "position";
-    case ast::Builtin::kVertexIndex:
-      return "vertex_id";
-    case ast::Builtin::kInstanceIndex:
-      return "instance_id";
-    case ast::Builtin::kFrontFacing:
-      return "front_facing";
-    case ast::Builtin::kFragDepth:
-      return "depth(any)";
-    case ast::Builtin::kLocalInvocationId:
-      return "thread_position_in_threadgroup";
-    case ast::Builtin::kLocalInvocationIndex:
-      return "thread_index_in_threadgroup";
-    case ast::Builtin::kGlobalInvocationId:
-      return "thread_position_in_grid";
-    case ast::Builtin::kWorkgroupId:
-      return "threadgroup_position_in_grid";
-    case ast::Builtin::kNumWorkgroups:
-      return "threadgroups_per_grid";
-    case ast::Builtin::kSampleIndex:
-      return "sample_id";
-    case ast::Builtin::kSampleMask:
-      return "sample_mask";
-    case ast::Builtin::kPointSize:
-      return "point_size";
-    default:
-      break;
-  }
-  return "";
+    switch (builtin) {
+        case ast::Builtin::kPosition:
+            return "position";
+        case ast::Builtin::kVertexIndex:
+            return "vertex_id";
+        case ast::Builtin::kInstanceIndex:
+            return "instance_id";
+        case ast::Builtin::kFrontFacing:
+            return "front_facing";
+        case ast::Builtin::kFragDepth:
+            return "depth(any)";
+        case ast::Builtin::kLocalInvocationId:
+            return "thread_position_in_threadgroup";
+        case ast::Builtin::kLocalInvocationIndex:
+            return "thread_index_in_threadgroup";
+        case ast::Builtin::kGlobalInvocationId:
+            return "thread_position_in_grid";
+        case ast::Builtin::kWorkgroupId:
+            return "threadgroup_position_in_grid";
+        case ast::Builtin::kNumWorkgroups:
+            return "threadgroups_per_grid";
+        case ast::Builtin::kSampleIndex:
+            return "sample_id";
+        case ast::Builtin::kSampleMask:
+            return "sample_mask";
+        case ast::Builtin::kPointSize:
+            return "point_size";
+        default:
+            break;
+    }
+    return "";
 }
 
-std::string GeneratorImpl::interpolation_to_attribute(
-    ast::InterpolationType type,
-    ast::InterpolationSampling sampling) const {
-  std::string attr;
-  switch (sampling) {
-    case ast::InterpolationSampling::kCenter:
-      attr = "center_";
-      break;
-    case ast::InterpolationSampling::kCentroid:
-      attr = "centroid_";
-      break;
-    case ast::InterpolationSampling::kSample:
-      attr = "sample_";
-      break;
-    case ast::InterpolationSampling::kNone:
-      break;
-  }
-  switch (type) {
-    case ast::InterpolationType::kPerspective:
-      attr += "perspective";
-      break;
-    case ast::InterpolationType::kLinear:
-      attr += "no_perspective";
-      break;
-    case ast::InterpolationType::kFlat:
-      attr += "flat";
-      break;
-  }
-  return attr;
+std::string GeneratorImpl::interpolation_to_attribute(ast::InterpolationType type,
+                                                      ast::InterpolationSampling sampling) const {
+    std::string attr;
+    switch (sampling) {
+        case ast::InterpolationSampling::kCenter:
+            attr = "center_";
+            break;
+        case ast::InterpolationSampling::kCentroid:
+            attr = "centroid_";
+            break;
+        case ast::InterpolationSampling::kSample:
+            attr = "sample_";
+            break;
+        case ast::InterpolationSampling::kNone:
+            break;
+    }
+    switch (type) {
+        case ast::InterpolationType::kPerspective:
+            attr += "perspective";
+            break;
+        case ast::InterpolationType::kLinear:
+            attr += "no_perspective";
+            break;
+        case ast::InterpolationType::kFlat:
+            attr += "flat";
+            break;
+    }
+    return attr;
 }
 
 bool GeneratorImpl::EmitEntryPointFunction(const ast::Function* func) {
-  auto func_name = program_->Symbols().NameFor(func->symbol);
+    auto func_name = program_->Symbols().NameFor(func->symbol);
 
-  // Returns the binding index of a variable, requiring that the group
-  // attribute have a value of zero.
-  const uint32_t kInvalidBindingIndex = std::numeric_limits<uint32_t>::max();
-  auto get_binding_index = [&](const ast::Variable* var) -> uint32_t {
-    auto bp = var->BindingPoint();
-    if (bp.group == nullptr || bp.binding == nullptr) {
-      TINT_ICE(Writer, diagnostics_)
-          << "missing binding attributes for entry point parameter";
-      return kInvalidBindingIndex;
-    }
-    if (bp.group->value != 0) {
-      TINT_ICE(Writer, diagnostics_)
-          << "encountered non-zero resource group index (use "
-             "BindingRemapper to fix)";
-      return kInvalidBindingIndex;
-    }
-    return bp.binding->value;
-  };
-
-  {
-    auto out = line();
-
-    EmitStage(out, func->PipelineStage());
-    out << " " << func->return_type->FriendlyName(program_->Symbols());
-    out << " " << func_name << "(";
-
-    // Emit entry point parameters.
-    bool first = true;
-    for (auto* var : func->params) {
-      if (!first) {
-        out << ", ";
-      }
-      first = false;
-
-      auto* type = program_->Sem().Get(var)->Type()->UnwrapRef();
-
-      auto param_name = program_->Symbols().NameFor(var->symbol);
-      if (!EmitType(out, type, param_name)) {
-        return false;
-      }
-      // Parameter name is output as part of the type for arrays and pointers.
-      if (!type->Is<sem::Array>() && !type->Is<sem::Pointer>()) {
-        out << " " << param_name;
-      }
-
-      if (type->Is<sem::Struct>()) {
-        out << " [[stage_in]]";
-      } else if (type->is_handle()) {
-        uint32_t binding = get_binding_index(var);
-        if (binding == kInvalidBindingIndex) {
-          return false;
+    // Returns the binding index of a variable, requiring that the group
+    // attribute have a value of zero.
+    const uint32_t kInvalidBindingIndex = std::numeric_limits<uint32_t>::max();
+    auto get_binding_index = [&](const ast::Variable* var) -> uint32_t {
+        auto bp = var->BindingPoint();
+        if (bp.group == nullptr || bp.binding == nullptr) {
+            TINT_ICE(Writer, diagnostics_)
+                << "missing binding attributes for entry point parameter";
+            return kInvalidBindingIndex;
         }
-        if (var->type->Is<ast::Sampler>()) {
-          out << " [[sampler(" << binding << ")]]";
-        } else if (var->type->Is<ast::Texture>()) {
-          out << " [[texture(" << binding << ")]]";
-        } else {
-          TINT_ICE(Writer, diagnostics_)
-              << "invalid handle type entry point parameter";
-          return false;
+        if (bp.group->value != 0) {
+            TINT_ICE(Writer, diagnostics_) << "encountered non-zero resource group index (use "
+                                              "BindingRemapper to fix)";
+            return kInvalidBindingIndex;
         }
-      } else if (auto* ptr = var->type->As<ast::Pointer>()) {
-        auto sc = ptr->storage_class;
-        if (sc == ast::StorageClass::kWorkgroup) {
-          auto& allocations = workgroup_allocations_[func_name];
-          out << " [[threadgroup(" << allocations.size() << ")]]";
-          allocations.push_back(program_->Sem().Get(ptr->type)->Size());
-        } else if (sc == ast::StorageClass::kStorage ||
-                   sc == ast::StorageClass::kUniform) {
-          uint32_t binding = get_binding_index(var);
-          if (binding == kInvalidBindingIndex) {
+        return bp.binding->value;
+    };
+
+    {
+        auto out = line();
+
+        EmitStage(out, func->PipelineStage());
+        out << " " << func->return_type->FriendlyName(program_->Symbols());
+        out << " " << func_name << "(";
+
+        // Emit entry point parameters.
+        bool first = true;
+        for (auto* var : func->params) {
+            if (!first) {
+                out << ", ";
+            }
+            first = false;
+
+            auto* type = program_->Sem().Get(var)->Type()->UnwrapRef();
+
+            auto param_name = program_->Symbols().NameFor(var->symbol);
+            if (!EmitType(out, type, param_name)) {
+                return false;
+            }
+            // Parameter name is output as part of the type for arrays and pointers.
+            if (!type->Is<sem::Array>() && !type->Is<sem::Pointer>()) {
+                out << " " << param_name;
+            }
+
+            if (type->Is<sem::Struct>()) {
+                out << " [[stage_in]]";
+            } else if (type->is_handle()) {
+                uint32_t binding = get_binding_index(var);
+                if (binding == kInvalidBindingIndex) {
+                    return false;
+                }
+                if (var->type->Is<ast::Sampler>()) {
+                    out << " [[sampler(" << binding << ")]]";
+                } else if (var->type->Is<ast::Texture>()) {
+                    out << " [[texture(" << binding << ")]]";
+                } else {
+                    TINT_ICE(Writer, diagnostics_) << "invalid handle type entry point parameter";
+                    return false;
+                }
+            } else if (auto* ptr = var->type->As<ast::Pointer>()) {
+                auto sc = ptr->storage_class;
+                if (sc == ast::StorageClass::kWorkgroup) {
+                    auto& allocations = workgroup_allocations_[func_name];
+                    out << " [[threadgroup(" << allocations.size() << ")]]";
+                    allocations.push_back(program_->Sem().Get(ptr->type)->Size());
+                } else if (sc == ast::StorageClass::kStorage || sc == ast::StorageClass::kUniform) {
+                    uint32_t binding = get_binding_index(var);
+                    if (binding == kInvalidBindingIndex) {
+                        return false;
+                    }
+                    out << " [[buffer(" << binding << ")]]";
+                } else {
+                    TINT_ICE(Writer, diagnostics_)
+                        << "invalid pointer storage class for entry point parameter";
+                    return false;
+                }
+            } else {
+                auto& attrs = var->attributes;
+                bool builtin_found = false;
+                for (auto* attr : attrs) {
+                    auto* builtin = attr->As<ast::BuiltinAttribute>();
+                    if (!builtin) {
+                        continue;
+                    }
+
+                    builtin_found = true;
+
+                    auto name = builtin_to_attribute(builtin->builtin);
+                    if (name.empty()) {
+                        diagnostics_.add_error(diag::System::Writer, "unknown builtin");
+                        return false;
+                    }
+                    out << " [[" << name << "]]";
+                }
+                if (!builtin_found) {
+                    TINT_ICE(Writer, diagnostics_) << "Unsupported entry point parameter";
+                }
+            }
+        }
+        out << ") {";
+    }
+
+    {
+        ScopedIndent si(this);
+
+        if (!EmitStatements(func->body->statements)) {
             return false;
-          }
-          out << " [[buffer(" << binding << ")]]";
-        } else {
-          TINT_ICE(Writer, diagnostics_)
-              << "invalid pointer storage class for entry point parameter";
-          return false;
         }
-      } else {
-        auto& attrs = var->attributes;
-        bool builtin_found = false;
-        for (auto* attr : attrs) {
-          auto* builtin = attr->As<ast::BuiltinAttribute>();
-          if (!builtin) {
-            continue;
-          }
 
-          builtin_found = true;
-
-          auto name = builtin_to_attribute(builtin->builtin);
-          if (name.empty()) {
-            diagnostics_.add_error(diag::System::Writer, "unknown builtin");
-            return false;
-          }
-          out << " [[" << name << "]]";
+        if (!Is<ast::ReturnStatement>(func->body->Last())) {
+            ast::ReturnStatement ret(ProgramID{}, Source{});
+            if (!EmitStatement(&ret)) {
+                return false;
+            }
         }
-        if (!builtin_found) {
-          TINT_ICE(Writer, diagnostics_) << "Unsupported entry point parameter";
-        }
-      }
-    }
-    out << ") {";
-  }
-
-  {
-    ScopedIndent si(this);
-
-    if (!EmitStatements(func->body->statements)) {
-      return false;
     }
 
-    if (!Is<ast::ReturnStatement>(func->body->Last())) {
-      ast::ReturnStatement ret(ProgramID{}, Source{});
-      if (!EmitStatement(&ret)) {
-        return false;
-      }
-    }
-  }
-
-  line() << "}";
-  return true;
+    line() << "}";
+    return true;
 }
 
-bool GeneratorImpl::EmitIdentifier(std::ostream& out,
-                                   const ast::IdentifierExpression* expr) {
-  out << program_->Symbols().NameFor(expr->symbol);
-  return true;
+bool GeneratorImpl::EmitIdentifier(std::ostream& out, const ast::IdentifierExpression* expr) {
+    out << program_->Symbols().NameFor(expr->symbol);
+    return true;
 }
 
 bool GeneratorImpl::EmitLoop(const ast::LoopStatement* stmt) {
-  auto emit_continuing = [this, stmt]() {
-    if (stmt->continuing && !stmt->continuing->Empty()) {
-      if (!EmitBlock(stmt->continuing)) {
-        return false;
-      }
-    }
-    return true;
-  };
-
-  TINT_SCOPED_ASSIGNMENT(emit_continuing_, emit_continuing);
-  line() << "while (true) {";
-  {
-    ScopedIndent si(this);
-    if (!EmitStatements(stmt->body->statements)) {
-      return false;
-    }
-    if (!emit_continuing_()) {
-      return false;
-    }
-  }
-  line() << "}";
-
-  return true;
-}
-
-bool GeneratorImpl::EmitForLoop(const ast::ForLoopStatement* stmt) {
-  TextBuffer init_buf;
-  if (auto* init = stmt->initializer) {
-    TINT_SCOPED_ASSIGNMENT(current_buffer_, &init_buf);
-    if (!EmitStatement(init)) {
-      return false;
-    }
-  }
-
-  TextBuffer cond_pre;
-  std::stringstream cond_buf;
-  if (auto* cond = stmt->condition) {
-    TINT_SCOPED_ASSIGNMENT(current_buffer_, &cond_pre);
-    if (!EmitExpression(cond_buf, cond)) {
-      return false;
-    }
-  }
-
-  TextBuffer cont_buf;
-  if (auto* cont = stmt->continuing) {
-    TINT_SCOPED_ASSIGNMENT(current_buffer_, &cont_buf);
-    if (!EmitStatement(cont)) {
-      return false;
-    }
-  }
-
-  // If the for-loop has a multi-statement conditional and / or continuing,
-  // then we cannot emit this as a regular for-loop in MSL. Instead we need to
-  // generate a `while(true)` loop.
-  bool emit_as_loop = cond_pre.lines.size() > 0 || cont_buf.lines.size() > 1;
-
-  // If the for-loop has multi-statement initializer, or is going to be
-  // emitted as a `while(true)` loop, then declare the initializer
-  // statement(s) before the loop in a new block.
-  bool nest_in_block =
-      init_buf.lines.size() > 1 || (stmt->initializer && emit_as_loop);
-  if (nest_in_block) {
-    line() << "{";
-    increment_indent();
-    current_buffer_->Append(init_buf);
-    init_buf.lines.clear();  // Don't emit the initializer again in the 'for'
-  }
-  TINT_DEFER({
-    if (nest_in_block) {
-      decrement_indent();
-      line() << "}";
-    }
-  });
-
-  if (emit_as_loop) {
-    auto emit_continuing = [&]() {
-      current_buffer_->Append(cont_buf);
-      return true;
+    auto emit_continuing = [this, stmt]() {
+        if (stmt->continuing && !stmt->continuing->Empty()) {
+            if (!EmitBlock(stmt->continuing)) {
+                return false;
+            }
+        }
+        return true;
     };
 
     TINT_SCOPED_ASSIGNMENT(emit_continuing_, emit_continuing);
     line() << "while (true) {";
-    increment_indent();
-    TINT_DEFER({
-      decrement_indent();
-      line() << "}";
-    });
-
-    if (stmt->condition) {
-      current_buffer_->Append(cond_pre);
-      line() << "if (!(" << cond_buf.str() << ")) { break; }";
-    }
-
-    if (!EmitStatements(stmt->body->statements)) {
-      return false;
-    }
-
-    if (!emit_continuing_()) {
-      return false;
-    }
-  } else {
-    // For-loop can be generated.
     {
-      auto out = line();
-      out << "for";
-      {
-        ScopedParen sp(out);
-
-        if (!init_buf.lines.empty()) {
-          out << init_buf.lines[0].content << " ";
-        } else {
-          out << "; ";
+        ScopedIndent si(this);
+        if (!EmitStatements(stmt->body->statements)) {
+            return false;
         }
-
-        out << cond_buf.str() << "; ";
-
-        if (!cont_buf.lines.empty()) {
-          out << TrimSuffix(cont_buf.lines[0].content, ";");
+        if (!emit_continuing_()) {
+            return false;
         }
-      }
-      out << " {";
-    }
-    {
-      auto emit_continuing = [] { return true; };
-      TINT_SCOPED_ASSIGNMENT(emit_continuing_, emit_continuing);
-      if (!EmitStatementsWithIndent(stmt->body->statements)) {
-        return false;
-      }
     }
     line() << "}";
-  }
 
-  return true;
+    return true;
+}
+
+bool GeneratorImpl::EmitForLoop(const ast::ForLoopStatement* stmt) {
+    TextBuffer init_buf;
+    if (auto* init = stmt->initializer) {
+        TINT_SCOPED_ASSIGNMENT(current_buffer_, &init_buf);
+        if (!EmitStatement(init)) {
+            return false;
+        }
+    }
+
+    TextBuffer cond_pre;
+    std::stringstream cond_buf;
+    if (auto* cond = stmt->condition) {
+        TINT_SCOPED_ASSIGNMENT(current_buffer_, &cond_pre);
+        if (!EmitExpression(cond_buf, cond)) {
+            return false;
+        }
+    }
+
+    TextBuffer cont_buf;
+    if (auto* cont = stmt->continuing) {
+        TINT_SCOPED_ASSIGNMENT(current_buffer_, &cont_buf);
+        if (!EmitStatement(cont)) {
+            return false;
+        }
+    }
+
+    // If the for-loop has a multi-statement conditional and / or continuing,
+    // then we cannot emit this as a regular for-loop in MSL. Instead we need to
+    // generate a `while(true)` loop.
+    bool emit_as_loop = cond_pre.lines.size() > 0 || cont_buf.lines.size() > 1;
+
+    // If the for-loop has multi-statement initializer, or is going to be
+    // emitted as a `while(true)` loop, then declare the initializer
+    // statement(s) before the loop in a new block.
+    bool nest_in_block = init_buf.lines.size() > 1 || (stmt->initializer && emit_as_loop);
+    if (nest_in_block) {
+        line() << "{";
+        increment_indent();
+        current_buffer_->Append(init_buf);
+        init_buf.lines.clear();  // Don't emit the initializer again in the 'for'
+    }
+    TINT_DEFER({
+        if (nest_in_block) {
+            decrement_indent();
+            line() << "}";
+        }
+    });
+
+    if (emit_as_loop) {
+        auto emit_continuing = [&]() {
+            current_buffer_->Append(cont_buf);
+            return true;
+        };
+
+        TINT_SCOPED_ASSIGNMENT(emit_continuing_, emit_continuing);
+        line() << "while (true) {";
+        increment_indent();
+        TINT_DEFER({
+            decrement_indent();
+            line() << "}";
+        });
+
+        if (stmt->condition) {
+            current_buffer_->Append(cond_pre);
+            line() << "if (!(" << cond_buf.str() << ")) { break; }";
+        }
+
+        if (!EmitStatements(stmt->body->statements)) {
+            return false;
+        }
+
+        if (!emit_continuing_()) {
+            return false;
+        }
+    } else {
+        // For-loop can be generated.
+        {
+            auto out = line();
+            out << "for";
+            {
+                ScopedParen sp(out);
+
+                if (!init_buf.lines.empty()) {
+                    out << init_buf.lines[0].content << " ";
+                } else {
+                    out << "; ";
+                }
+
+                out << cond_buf.str() << "; ";
+
+                if (!cont_buf.lines.empty()) {
+                    out << TrimSuffix(cont_buf.lines[0].content, ";");
+                }
+            }
+            out << " {";
+        }
+        {
+            auto emit_continuing = [] { return true; };
+            TINT_SCOPED_ASSIGNMENT(emit_continuing_, emit_continuing);
+            if (!EmitStatementsWithIndent(stmt->body->statements)) {
+                return false;
+            }
+        }
+        line() << "}";
+    }
+
+    return true;
 }
 
 bool GeneratorImpl::EmitDiscard(const ast::DiscardStatement*) {
-  // TODO(dsinclair): Verify this is correct when the discard semantics are
-  // defined for WGSL (https://github.com/gpuweb/gpuweb/issues/361)
-  line() << "discard_fragment();";
-  return true;
+    // TODO(dsinclair): Verify this is correct when the discard semantics are
+    // defined for WGSL (https://github.com/gpuweb/gpuweb/issues/361)
+    line() << "discard_fragment();";
+    return true;
 }
 
 bool GeneratorImpl::EmitIf(const ast::IfStatement* stmt) {
-  {
-    auto out = line();
-    out << "if (";
-    if (!EmitExpression(out, stmt->condition)) {
-      return false;
-    }
-    out << ") {";
-  }
-
-  if (!EmitStatementsWithIndent(stmt->body->statements)) {
-    return false;
-  }
-
-  for (auto* e : stmt->else_statements) {
-    if (e->condition) {
-      line() << "} else {";
-      increment_indent();
-
-      {
+    {
         auto out = line();
         out << "if (";
-        if (!EmitExpression(out, e->condition)) {
-          return false;
+        if (!EmitExpression(out, stmt->condition)) {
+            return false;
         }
         out << ") {";
-      }
-    } else {
-      line() << "} else {";
     }
 
-    if (!EmitStatementsWithIndent(e->body->statements)) {
-      return false;
+    if (!EmitStatementsWithIndent(stmt->body->statements)) {
+        return false;
     }
-  }
 
-  line() << "}";
-
-  for (auto* e : stmt->else_statements) {
-    if (e->condition) {
-      decrement_indent();
-      line() << "}";
+    if (stmt->else_statement) {
+        line() << "} else {";
+        if (auto* block = stmt->else_statement->As<ast::BlockStatement>()) {
+            if (!EmitStatementsWithIndent(block->statements)) {
+                return false;
+            }
+        } else {
+            if (!EmitStatementsWithIndent({stmt->else_statement})) {
+                return false;
+            }
+        }
     }
-  }
-  return true;
+    line() << "}";
+
+    return true;
 }
 
-bool GeneratorImpl::EmitMemberAccessor(
-    std::ostream& out,
-    const ast::MemberAccessorExpression* expr) {
-  auto write_lhs = [&] {
-    bool paren_lhs = !expr->structure->IsAnyOf<
-        ast::IndexAccessorExpression, ast::CallExpression,
-        ast::IdentifierExpression, ast::MemberAccessorExpression>();
-    if (paren_lhs) {
-      out << "(";
-    }
-    if (!EmitExpression(out, expr->structure)) {
-      return false;
-    }
-    if (paren_lhs) {
-      out << ")";
-    }
-    return true;
-  };
+bool GeneratorImpl::EmitMemberAccessor(std::ostream& out,
+                                       const ast::MemberAccessorExpression* expr) {
+    auto write_lhs = [&] {
+        bool paren_lhs =
+            !expr->structure->IsAnyOf<ast::IndexAccessorExpression, ast::CallExpression,
+                                      ast::IdentifierExpression, ast::MemberAccessorExpression>();
+        if (paren_lhs) {
+            out << "(";
+        }
+        if (!EmitExpression(out, expr->structure)) {
+            return false;
+        }
+        if (paren_lhs) {
+            out << ")";
+        }
+        return true;
+    };
 
-  auto& sem = program_->Sem();
+    auto& sem = program_->Sem();
 
-  if (auto* swizzle = sem.Get(expr)->As<sem::Swizzle>()) {
-    // Metal 1.x does not support swizzling of packed vector types.
-    // For single element swizzles, we can use the index operator.
-    // For multi-element swizzles, we need to cast to a regular vector type
-    // first. Note that we do not currently allow assignments to swizzles, so
-    // the casting which will convert the l-value to r-value is fine.
-    if (swizzle->Indices().size() == 1) {
-      if (!write_lhs()) {
-        return false;
-      }
-      out << "[" << swizzle->Indices()[0] << "]";
+    if (auto* swizzle = sem.Get(expr)->As<sem::Swizzle>()) {
+        // Metal 1.x does not support swizzling of packed vector types.
+        // For single element swizzles, we can use the index operator.
+        // For multi-element swizzles, we need to cast to a regular vector type
+        // first. Note that we do not currently allow assignments to swizzles, so
+        // the casting which will convert the l-value to r-value is fine.
+        if (swizzle->Indices().size() == 1) {
+            if (!write_lhs()) {
+                return false;
+            }
+            out << "[" << swizzle->Indices()[0] << "]";
+        } else {
+            if (!EmitType(out, sem.Get(expr->structure)->Type()->UnwrapRef(), "")) {
+                return false;
+            }
+            out << "(";
+            if (!write_lhs()) {
+                return false;
+            }
+            out << ")." << program_->Symbols().NameFor(expr->member->symbol);
+        }
     } else {
-      if (!EmitType(out, sem.Get(expr->structure)->Type()->UnwrapRef(), "")) {
-        return false;
-      }
-      out << "(";
-      if (!write_lhs()) {
-        return false;
-      }
-      out << ")." << program_->Symbols().NameFor(expr->member->symbol);
+        if (!write_lhs()) {
+            return false;
+        }
+        out << ".";
+        if (!EmitExpression(out, expr->member)) {
+            return false;
+        }
     }
-  } else {
-    if (!write_lhs()) {
-      return false;
-    }
-    out << ".";
-    if (!EmitExpression(out, expr->member)) {
-      return false;
-    }
-  }
 
-  return true;
+    return true;
 }
 
 bool GeneratorImpl::EmitReturn(const ast::ReturnStatement* stmt) {
-  auto out = line();
-  out << "return";
-  if (stmt->value) {
-    out << " ";
-    if (!EmitExpression(out, stmt->value)) {
-      return false;
+    auto out = line();
+    out << "return";
+    if (stmt->value) {
+        out << " ";
+        if (!EmitExpression(out, stmt->value)) {
+            return false;
+        }
     }
-  }
-  out << ";";
-  return true;
+    out << ";";
+    return true;
 }
 
 bool GeneratorImpl::EmitBlock(const ast::BlockStatement* stmt) {
-  line() << "{";
+    line() << "{";
 
-  if (!EmitStatementsWithIndent(stmt->statements)) {
-    return false;
-  }
+    if (!EmitStatementsWithIndent(stmt->statements)) {
+        return false;
+    }
 
-  line() << "}";
+    line() << "}";
 
-  return true;
+    return true;
 }
 
 bool GeneratorImpl::EmitStatement(const ast::Statement* stmt) {
-  return Switch(
-      stmt,
-      [&](const ast::AssignmentStatement* a) {  //
-        return EmitAssign(a);
-      },
-      [&](const ast::BlockStatement* b) {  //
-        return EmitBlock(b);
-      },
-      [&](const ast::BreakStatement* b) {  //
-        return EmitBreak(b);
-      },
-      [&](const ast::CallStatement* c) {  //
-        auto out = line();
-        if (!EmitCall(out, c->expr)) {  //
-          return false;
-        }
-        out << ";";
-        return true;
-      },
-      [&](const ast::ContinueStatement* c) {  //
-        return EmitContinue(c);
-      },
-      [&](const ast::DiscardStatement* d) {  //
-        return EmitDiscard(d);
-      },
-      [&](const ast::FallthroughStatement*) {  //
-        line() << "/* fallthrough */";
-        return true;
-      },
-      [&](const ast::IfStatement* i) {  //
-        return EmitIf(i);
-      },
-      [&](const ast::LoopStatement* l) {  //
-        return EmitLoop(l);
-      },
-      [&](const ast::ForLoopStatement* l) {  //
-        return EmitForLoop(l);
-      },
-      [&](const ast::ReturnStatement* r) {  //
-        return EmitReturn(r);
-      },
-      [&](const ast::SwitchStatement* s) {  //
-        return EmitSwitch(s);
-      },
-      [&](const ast::VariableDeclStatement* v) {  //
-        auto* var = program_->Sem().Get(v->variable);
-        return EmitVariable(var);
-      },
-      [&](Default) {
-        diagnostics_.add_error(
-            diag::System::Writer,
-            "unknown statement type: " + std::string(stmt->TypeInfo().name));
-        return false;
-      });
+    return Switch(
+        stmt,
+        [&](const ast::AssignmentStatement* a) {  //
+            return EmitAssign(a);
+        },
+        [&](const ast::BlockStatement* b) {  //
+            return EmitBlock(b);
+        },
+        [&](const ast::BreakStatement* b) {  //
+            return EmitBreak(b);
+        },
+        [&](const ast::CallStatement* c) {  //
+            auto out = line();
+            if (!EmitCall(out, c->expr)) {  //
+                return false;
+            }
+            out << ";";
+            return true;
+        },
+        [&](const ast::ContinueStatement* c) {  //
+            return EmitContinue(c);
+        },
+        [&](const ast::DiscardStatement* d) {  //
+            return EmitDiscard(d);
+        },
+        [&](const ast::FallthroughStatement*) {  //
+            line() << "/* fallthrough */";
+            return true;
+        },
+        [&](const ast::IfStatement* i) {  //
+            return EmitIf(i);
+        },
+        [&](const ast::LoopStatement* l) {  //
+            return EmitLoop(l);
+        },
+        [&](const ast::ForLoopStatement* l) {  //
+            return EmitForLoop(l);
+        },
+        [&](const ast::ReturnStatement* r) {  //
+            return EmitReturn(r);
+        },
+        [&](const ast::SwitchStatement* s) {  //
+            return EmitSwitch(s);
+        },
+        [&](const ast::VariableDeclStatement* v) {  //
+            auto* var = program_->Sem().Get(v->variable);
+            return EmitVariable(var);
+        },
+        [&](Default) {
+            diagnostics_.add_error(diag::System::Writer,
+                                   "unknown statement type: " + std::string(stmt->TypeInfo().name));
+            return false;
+        });
 }
 
 bool GeneratorImpl::EmitStatements(const ast::StatementList& stmts) {
-  for (auto* s : stmts) {
-    if (!EmitStatement(s)) {
-      return false;
+    for (auto* s : stmts) {
+        if (!EmitStatement(s)) {
+            return false;
+        }
     }
-  }
-  return true;
+    return true;
 }
 
 bool GeneratorImpl::EmitStatementsWithIndent(const ast::StatementList& stmts) {
-  ScopedIndent si(this);
-  return EmitStatements(stmts);
+    ScopedIndent si(this);
+    return EmitStatements(stmts);
 }
 
 bool GeneratorImpl::EmitSwitch(const ast::SwitchStatement* stmt) {
-  {
-    auto out = line();
-    out << "switch(";
-    if (!EmitExpression(out, stmt->condition)) {
-      return false;
+    {
+        auto out = line();
+        out << "switch(";
+        if (!EmitExpression(out, stmt->condition)) {
+            return false;
+        }
+        out << ") {";
     }
-    out << ") {";
-  }
 
-  {
-    ScopedIndent si(this);
-    for (auto* s : stmt->body) {
-      if (!EmitCase(s)) {
-        return false;
-      }
+    {
+        ScopedIndent si(this);
+        for (auto* s : stmt->body) {
+            if (!EmitCase(s)) {
+                return false;
+            }
+        }
     }
-  }
 
-  line() << "}";
+    line() << "}";
 
-  return true;
+    return true;
 }
 
 bool GeneratorImpl::EmitType(std::ostream& out,
                              const sem::Type* type,
                              const std::string& name,
                              bool* name_printed /* = nullptr */) {
-  if (name_printed) {
-    *name_printed = false;
-  }
+    if (name_printed) {
+        *name_printed = false;
+    }
 
-  return Switch(
-      type,
-      [&](const sem::Atomic* atomic) {
-        if (atomic->Type()->Is<sem::I32>()) {
-          out << "atomic_int";
-          return true;
-        }
-        if (atomic->Type()->Is<sem::U32>()) {
-          out << "atomic_uint";
-          return true;
-        }
-        TINT_ICE(Writer, diagnostics_)
-            << "unhandled atomic type "
-            << atomic->Type()->FriendlyName(builder_.Symbols());
-        return false;
-      },
-      [&](const sem::Array* ary) {
-        const sem::Type* base_type = ary;
-        std::vector<uint32_t> sizes;
-        while (auto* arr = base_type->As<sem::Array>()) {
-          if (arr->IsRuntimeSized()) {
-            sizes.push_back(1);
-          } else {
-            sizes.push_back(arr->Count());
-          }
-          base_type = arr->ElemType();
-        }
-        if (!EmitType(out, base_type, "")) {
-          return false;
-        }
-        if (!name.empty()) {
-          out << " " << name;
-          if (name_printed) {
-            *name_printed = true;
-          }
-        }
-        for (uint32_t size : sizes) {
-          out << "[" << size << "]";
-        }
-        return true;
-      },
-      [&](const sem::Bool*) {
-        out << "bool";
-        return true;
-      },
-      [&](const sem::F32*) {
-        out << "float";
-        return true;
-      },
-      [&](const sem::I32*) {
-        out << "int";
-        return true;
-      },
-      [&](const sem::Matrix* mat) {
-        if (!EmitType(out, mat->type(), "")) {
-          return false;
-        }
-        out << mat->columns() << "x" << mat->rows();
-        return true;
-      },
-      [&](const sem::Pointer* ptr) {
-        if (ptr->Access() == ast::Access::kRead) {
-          out << "const ";
-        }
-        if (!EmitStorageClass(out, ptr->StorageClass())) {
-          return false;
-        }
-        out << " ";
-        if (ptr->StoreType()->Is<sem::Array>()) {
-          std::string inner = "(*" + name + ")";
-          if (!EmitType(out, ptr->StoreType(), inner)) {
+    return Switch(
+        type,
+        [&](const sem::Atomic* atomic) {
+            if (atomic->Type()->Is<sem::I32>()) {
+                out << "atomic_int";
+                return true;
+            }
+            if (atomic->Type()->Is<sem::U32>()) {
+                out << "atomic_uint";
+                return true;
+            }
+            TINT_ICE(Writer, diagnostics_)
+                << "unhandled atomic type " << atomic->Type()->FriendlyName(builder_.Symbols());
             return false;
-          }
-          if (name_printed) {
-            *name_printed = true;
-          }
-        } else {
-          if (!EmitType(out, ptr->StoreType(), "")) {
+        },
+        [&](const sem::Array* ary) {
+            const sem::Type* base_type = ary;
+            std::vector<uint32_t> sizes;
+            while (auto* arr = base_type->As<sem::Array>()) {
+                if (arr->IsRuntimeSized()) {
+                    sizes.push_back(1);
+                } else {
+                    sizes.push_back(arr->Count());
+                }
+                base_type = arr->ElemType();
+            }
+            if (!EmitType(out, base_type, "")) {
+                return false;
+            }
+            if (!name.empty()) {
+                out << " " << name;
+                if (name_printed) {
+                    *name_printed = true;
+                }
+            }
+            for (uint32_t size : sizes) {
+                out << "[" << size << "]";
+            }
+            return true;
+        },
+        [&](const sem::Bool*) {
+            out << "bool";
+            return true;
+        },
+        [&](const sem::F32*) {
+            out << "float";
+            return true;
+        },
+        [&](const sem::I32*) {
+            out << "int";
+            return true;
+        },
+        [&](const sem::Matrix* mat) {
+            if (!EmitType(out, mat->type(), "")) {
+                return false;
+            }
+            out << mat->columns() << "x" << mat->rows();
+            return true;
+        },
+        [&](const sem::Pointer* ptr) {
+            if (ptr->Access() == ast::Access::kRead) {
+                out << "const ";
+            }
+            if (!EmitStorageClass(out, ptr->StorageClass())) {
+                return false;
+            }
+            out << " ";
+            if (ptr->StoreType()->Is<sem::Array>()) {
+                std::string inner = "(*" + name + ")";
+                if (!EmitType(out, ptr->StoreType(), inner)) {
+                    return false;
+                }
+                if (name_printed) {
+                    *name_printed = true;
+                }
+            } else {
+                if (!EmitType(out, ptr->StoreType(), "")) {
+                    return false;
+                }
+                out << "* " << name;
+                if (name_printed) {
+                    *name_printed = true;
+                }
+            }
+            return true;
+        },
+        [&](const sem::Sampler*) {
+            out << "sampler";
+            return true;
+        },
+        [&](const sem::Struct* str) {
+            // The struct type emits as just the name. The declaration would be
+            // emitted as part of emitting the declared types.
+            out << StructName(str);
+            return true;
+        },
+        [&](const sem::Texture* tex) {
+            if (tex->Is<sem::ExternalTexture>()) {
+                TINT_ICE(Writer, diagnostics_)
+                    << "Multiplanar external texture transform was not run.";
+                return false;
+            }
+
+            if (tex->IsAnyOf<sem::DepthTexture, sem::DepthMultisampledTexture>()) {
+                out << "depth";
+            } else {
+                out << "texture";
+            }
+
+            switch (tex->dim()) {
+                case ast::TextureDimension::k1d:
+                    out << "1d";
+                    break;
+                case ast::TextureDimension::k2d:
+                    out << "2d";
+                    break;
+                case ast::TextureDimension::k2dArray:
+                    out << "2d_array";
+                    break;
+                case ast::TextureDimension::k3d:
+                    out << "3d";
+                    break;
+                case ast::TextureDimension::kCube:
+                    out << "cube";
+                    break;
+                case ast::TextureDimension::kCubeArray:
+                    out << "cube_array";
+                    break;
+                default:
+                    diagnostics_.add_error(diag::System::Writer, "Invalid texture dimensions");
+                    return false;
+            }
+            if (tex->IsAnyOf<sem::MultisampledTexture, sem::DepthMultisampledTexture>()) {
+                out << "_ms";
+            }
+            out << "<";
+            TINT_DEFER(out << ">");
+
+            return Switch(
+                tex,
+                [&](const sem::DepthTexture*) {
+                    out << "float, access::sample";
+                    return true;
+                },
+                [&](const sem::DepthMultisampledTexture*) {
+                    out << "float, access::read";
+                    return true;
+                },
+                [&](const sem::StorageTexture* storage) {
+                    if (!EmitType(out, storage->type(), "")) {
+                        return false;
+                    }
+
+                    std::string access_str;
+                    if (storage->access() == ast::Access::kRead) {
+                        out << ", access::read";
+                    } else if (storage->access() == ast::Access::kWrite) {
+                        out << ", access::write";
+                    } else {
+                        diagnostics_.add_error(diag::System::Writer,
+                                               "Invalid access control for storage texture");
+                        return false;
+                    }
+                    return true;
+                },
+                [&](const sem::MultisampledTexture* ms) {
+                    if (!EmitType(out, ms->type(), "")) {
+                        return false;
+                    }
+                    out << ", access::read";
+                    return true;
+                },
+                [&](const sem::SampledTexture* sampled) {
+                    if (!EmitType(out, sampled->type(), "")) {
+                        return false;
+                    }
+                    out << ", access::sample";
+                    return true;
+                },
+                [&](Default) {
+                    diagnostics_.add_error(diag::System::Writer, "invalid texture type");
+                    return false;
+                });
+        },
+        [&](const sem::U32*) {
+            out << "uint";
+            return true;
+        },
+        [&](const sem::Vector* vec) {
+            if (!EmitType(out, vec->type(), "")) {
+                return false;
+            }
+            out << vec->Width();
+            return true;
+        },
+        [&](const sem::Void*) {
+            out << "void";
+            return true;
+        },
+        [&](Default) {
+            diagnostics_.add_error(
+                diag::System::Writer,
+                "unknown type in EmitType: " + type->FriendlyName(builder_.Symbols()));
             return false;
-          }
-          out << "* " << name;
-          if (name_printed) {
-            *name_printed = true;
-          }
-        }
-        return true;
-      },
-      [&](const sem::Sampler*) {
-        out << "sampler";
-        return true;
-      },
-      [&](const sem::Struct* str) {
-        // The struct type emits as just the name. The declaration would be
-        // emitted as part of emitting the declared types.
-        out << StructName(str);
-        return true;
-      },
-      [&](const sem::Texture* tex) {
-        if (tex->Is<sem::ExternalTexture>()) {
-          TINT_ICE(Writer, diagnostics_)
-              << "Multiplanar external texture transform was not run.";
-          return false;
-        }
-
-        if (tex->IsAnyOf<sem::DepthTexture, sem::DepthMultisampledTexture>()) {
-          out << "depth";
-        } else {
-          out << "texture";
-        }
-
-        switch (tex->dim()) {
-          case ast::TextureDimension::k1d:
-            out << "1d";
-            break;
-          case ast::TextureDimension::k2d:
-            out << "2d";
-            break;
-          case ast::TextureDimension::k2dArray:
-            out << "2d_array";
-            break;
-          case ast::TextureDimension::k3d:
-            out << "3d";
-            break;
-          case ast::TextureDimension::kCube:
-            out << "cube";
-            break;
-          case ast::TextureDimension::kCubeArray:
-            out << "cube_array";
-            break;
-          default:
-            diagnostics_.add_error(diag::System::Writer,
-                                   "Invalid texture dimensions");
-            return false;
-        }
-        if (tex->IsAnyOf<sem::MultisampledTexture,
-                         sem::DepthMultisampledTexture>()) {
-          out << "_ms";
-        }
-        out << "<";
-        TINT_DEFER(out << ">");
-
-        return Switch(
-            tex,
-            [&](const sem::DepthTexture*) {
-              out << "float, access::sample";
-              return true;
-            },
-            [&](const sem::DepthMultisampledTexture*) {
-              out << "float, access::read";
-              return true;
-            },
-            [&](const sem::StorageTexture* storage) {
-              if (!EmitType(out, storage->type(), "")) {
-                return false;
-              }
-
-              std::string access_str;
-              if (storage->access() == ast::Access::kRead) {
-                out << ", access::read";
-              } else if (storage->access() == ast::Access::kWrite) {
-                out << ", access::write";
-              } else {
-                diagnostics_.add_error(
-                    diag::System::Writer,
-                    "Invalid access control for storage texture");
-                return false;
-              }
-              return true;
-            },
-            [&](const sem::MultisampledTexture* ms) {
-              if (!EmitType(out, ms->type(), "")) {
-                return false;
-              }
-              out << ", access::read";
-              return true;
-            },
-            [&](const sem::SampledTexture* sampled) {
-              if (!EmitType(out, sampled->type(), "")) {
-                return false;
-              }
-              out << ", access::sample";
-              return true;
-            },
-            [&](Default) {
-              diagnostics_.add_error(diag::System::Writer,
-                                     "invalid texture type");
-              return false;
-            });
-      },
-      [&](const sem::U32*) {
-        out << "uint";
-        return true;
-      },
-      [&](const sem::Vector* vec) {
-        if (!EmitType(out, vec->type(), "")) {
-          return false;
-        }
-        out << vec->Width();
-        return true;
-      },
-      [&](const sem::Void*) {
-        out << "void";
-        return true;
-      },
-      [&](Default) {
-        diagnostics_.add_error(diag::System::Writer,
-                               "unknown type in EmitType: " +
-                                   type->FriendlyName(builder_.Symbols()));
-        return false;
-      });
+        });
 }
 
 bool GeneratorImpl::EmitTypeAndName(std::ostream& out,
                                     const sem::Type* type,
                                     const std::string& name) {
-  bool name_printed = false;
-  if (!EmitType(out, type, name, &name_printed)) {
-    return false;
-  }
-  if (!name_printed) {
-    out << " " << name;
-  }
-  return true;
+    bool name_printed = false;
+    if (!EmitType(out, type, name, &name_printed)) {
+        return false;
+    }
+    if (!name_printed) {
+        out << " " << name;
+    }
+    return true;
 }
 
 bool GeneratorImpl::EmitStorageClass(std::ostream& out, ast::StorageClass sc) {
-  switch (sc) {
-    case ast::StorageClass::kFunction:
-    case ast::StorageClass::kPrivate:
-    case ast::StorageClass::kUniformConstant:
-      out << "thread";
-      return true;
-    case ast::StorageClass::kWorkgroup:
-      out << "threadgroup";
-      return true;
-    case ast::StorageClass::kStorage:
-      out << "device";
-      return true;
-    case ast::StorageClass::kUniform:
-      out << "constant";
-      return true;
-    default:
-      break;
-  }
-  TINT_ICE(Writer, diagnostics_) << "unhandled storage class: " << sc;
-  return false;
+    switch (sc) {
+        case ast::StorageClass::kFunction:
+        case ast::StorageClass::kPrivate:
+        case ast::StorageClass::kHandle:
+            out << "thread";
+            return true;
+        case ast::StorageClass::kWorkgroup:
+            out << "threadgroup";
+            return true;
+        case ast::StorageClass::kStorage:
+            out << "device";
+            return true;
+        case ast::StorageClass::kUniform:
+            out << "constant";
+            return true;
+        default:
+            break;
+    }
+    TINT_ICE(Writer, diagnostics_) << "unhandled storage class: " << sc;
+    return false;
 }
 
 bool GeneratorImpl::EmitPackedType(std::ostream& out,
                                    const sem::Type* type,
                                    const std::string& name) {
-  auto* vec = type->As<sem::Vector>();
-  if (vec && vec->Width() == 3) {
-    out << "packed_";
-    if (!EmitType(out, vec, "")) {
-      return false;
-    }
+    auto* vec = type->As<sem::Vector>();
+    if (vec && vec->Width() == 3) {
+        out << "packed_";
+        if (!EmitType(out, vec, "")) {
+            return false;
+        }
 
-    if (vec->is_float_vector() && !matrix_packed_vector_overloads_) {
-      // Overload operators for matrix-vector arithmetic where the vector
-      // operand is packed, as these overloads to not exist in the metal
-      // namespace.
-      TextBuffer b;
-      TINT_DEFER(helpers_.Append(b));
-      line(&b) << R"(template<typename T, int N, int M>
+        if (vec->is_float_vector() && !matrix_packed_vector_overloads_) {
+            // Overload operators for matrix-vector arithmetic where the vector
+            // operand is packed, as these overloads to not exist in the metal
+            // namespace.
+            TextBuffer b;
+            TINT_DEFER(helpers_.Append(b));
+            line(&b) << R"(template<typename T, int N, int M>
 inline vec<T, M> operator*(matrix<T, N, M> lhs, packed_vec<T, N> rhs) {
   return lhs * vec<T, N>(rhs);
 }
@@ -2537,443 +2461,429 @@
   return vec<T, M>(lhs) * rhs;
 }
 )";
-      matrix_packed_vector_overloads_ = true;
+            matrix_packed_vector_overloads_ = true;
+        }
+
+        return true;
     }
 
-    return true;
-  }
-
-  return EmitType(out, type, name);
+    return EmitType(out, type, name);
 }
 
 bool GeneratorImpl::EmitStructType(TextBuffer* b, const sem::Struct* str) {
-  line(b) << "struct " << StructName(str) << " {";
+    line(b) << "struct " << StructName(str) << " {";
 
-  bool is_host_shareable = str->IsHostShareable();
+    bool is_host_shareable = str->IsHostShareable();
 
-  // Emits a `/* 0xnnnn */` byte offset comment for a struct member.
-  auto add_byte_offset_comment = [&](std::ostream& out, uint32_t offset) {
-    std::ios_base::fmtflags saved_flag_state(out.flags());
-    out << "/* 0x" << std::hex << std::setfill('0') << std::setw(4) << offset
-        << " */ ";
-    out.flags(saved_flag_state);
-  };
+    // Emits a `/* 0xnnnn */` byte offset comment for a struct member.
+    auto add_byte_offset_comment = [&](std::ostream& out, uint32_t offset) {
+        std::ios_base::fmtflags saved_flag_state(out.flags());
+        out << "/* 0x" << std::hex << std::setfill('0') << std::setw(4) << offset << " */ ";
+        out.flags(saved_flag_state);
+    };
 
-  auto add_padding = [&](uint32_t size, uint32_t msl_offset) {
-    std::string name;
-    do {
-      name = UniqueIdentifier("tint_pad");
-    } while (str->FindMember(program_->Symbols().Get(name)));
+    auto add_padding = [&](uint32_t size, uint32_t msl_offset) {
+        std::string name;
+        do {
+            name = UniqueIdentifier("tint_pad");
+        } while (str->FindMember(program_->Symbols().Get(name)));
 
-    auto out = line(b);
-    add_byte_offset_comment(out, msl_offset);
-    out << "int8_t " << name << "[" << size << "];";
-  };
+        auto out = line(b);
+        add_byte_offset_comment(out, msl_offset);
+        out << "int8_t " << name << "[" << size << "];";
+    };
 
-  b->IncrementIndent();
+    b->IncrementIndent();
 
-  uint32_t msl_offset = 0;
-  for (auto* mem : str->Members()) {
-    auto out = line(b);
-    auto mem_name = program_->Symbols().NameFor(mem->Name());
-    auto wgsl_offset = mem->Offset();
+    uint32_t msl_offset = 0;
+    for (auto* mem : str->Members()) {
+        auto out = line(b);
+        auto mem_name = program_->Symbols().NameFor(mem->Name());
+        auto wgsl_offset = mem->Offset();
 
-    if (is_host_shareable) {
-      if (wgsl_offset < msl_offset) {
-        // Unimplementable layout
-        TINT_ICE(Writer, diagnostics_)
-            << "Structure member WGSL offset (" << wgsl_offset
-            << ") is behind MSL offset (" << msl_offset << ")";
-        return false;
-      }
-
-      // Generate padding if required
-      if (auto padding = wgsl_offset - msl_offset) {
-        add_padding(padding, msl_offset);
-        msl_offset += padding;
-      }
-
-      add_byte_offset_comment(out, msl_offset);
-
-      if (!EmitPackedType(out, mem->Type(), mem_name)) {
-        return false;
-      }
-    } else {
-      if (!EmitType(out, mem->Type(), mem_name)) {
-        return false;
-      }
-    }
-
-    auto* ty = mem->Type();
-
-    // Array member name will be output with the type
-    if (!ty->Is<sem::Array>()) {
-      out << " " << mem_name;
-    }
-
-    // Emit attributes
-    if (auto* decl = mem->Declaration()) {
-      for (auto* attr : decl->attributes) {
-        bool ok = Switch(
-            attr,
-            [&](const ast::BuiltinAttribute* builtin) {
-              auto name = builtin_to_attribute(builtin->builtin);
-              if (name.empty()) {
-                diagnostics_.add_error(diag::System::Writer, "unknown builtin");
+        if (is_host_shareable) {
+            if (wgsl_offset < msl_offset) {
+                // Unimplementable layout
+                TINT_ICE(Writer, diagnostics_) << "Structure member WGSL offset (" << wgsl_offset
+                                               << ") is behind MSL offset (" << msl_offset << ")";
                 return false;
-              }
-              out << " [[" << name << "]]";
-              return true;
-            },
-            [&](const ast::LocationAttribute* loc) {
-              auto& pipeline_stage_uses = str->PipelineStageUses();
-              if (pipeline_stage_uses.size() != 1) {
-                TINT_ICE(Writer, diagnostics_)
-                    << "invalid entry point IO struct uses";
-                return false;
-              }
+            }
 
-              if (pipeline_stage_uses.count(
-                      sem::PipelineStageUsage::kVertexInput)) {
-                out << " [[attribute(" + std::to_string(loc->value) + ")]]";
-              } else if (pipeline_stage_uses.count(
-                             sem::PipelineStageUsage::kVertexOutput)) {
-                out << " [[user(locn" + std::to_string(loc->value) + ")]]";
-              } else if (pipeline_stage_uses.count(
-                             sem::PipelineStageUsage::kFragmentInput)) {
-                out << " [[user(locn" + std::to_string(loc->value) + ")]]";
-              } else if (pipeline_stage_uses.count(
-                             sem::PipelineStageUsage::kFragmentOutput)) {
-                out << " [[color(" + std::to_string(loc->value) + ")]]";
-              } else {
-                TINT_ICE(Writer, diagnostics_)
-                    << "invalid use of location decoration";
+            // Generate padding if required
+            if (auto padding = wgsl_offset - msl_offset) {
+                add_padding(padding, msl_offset);
+                msl_offset += padding;
+            }
+
+            add_byte_offset_comment(out, msl_offset);
+
+            if (!EmitPackedType(out, mem->Type(), mem_name)) {
                 return false;
-              }
-              return true;
-            },
-            [&](const ast::InterpolateAttribute* interpolate) {
-              auto name = interpolation_to_attribute(interpolate->type,
-                                                     interpolate->sampling);
-              if (name.empty()) {
-                diagnostics_.add_error(diag::System::Writer,
-                                       "unknown interpolation attribute");
+            }
+        } else {
+            if (!EmitType(out, mem->Type(), mem_name)) {
                 return false;
-              }
-              out << " [[" << name << "]]";
-              return true;
-            },
-            [&](const ast::InvariantAttribute*) {
-              if (invariant_define_name_.empty()) {
-                invariant_define_name_ = UniqueIdentifier("TINT_INVARIANT");
-              }
-              out << " " << invariant_define_name_;
-              return true;
-            },
-            [&](const ast::StructMemberOffsetAttribute*) { return true; },
-            [&](const ast::StructMemberAlignAttribute*) { return true; },
-            [&](const ast::StructMemberSizeAttribute*) { return true; },
-            [&](Default) {
-              TINT_ICE(Writer, diagnostics_)
-                  << "unhandled struct member attribute: " << attr->Name();
-              return false;
-            });
-        if (!ok) {
-          return false;
+            }
         }
-      }
+
+        auto* ty = mem->Type();
+
+        // Array member name will be output with the type
+        if (!ty->Is<sem::Array>()) {
+            out << " " << mem_name;
+        }
+
+        // Emit attributes
+        if (auto* decl = mem->Declaration()) {
+            for (auto* attr : decl->attributes) {
+                bool ok = Switch(
+                    attr,
+                    [&](const ast::BuiltinAttribute* builtin) {
+                        auto name = builtin_to_attribute(builtin->builtin);
+                        if (name.empty()) {
+                            diagnostics_.add_error(diag::System::Writer, "unknown builtin");
+                            return false;
+                        }
+                        out << " [[" << name << "]]";
+                        return true;
+                    },
+                    [&](const ast::LocationAttribute* loc) {
+                        auto& pipeline_stage_uses = str->PipelineStageUses();
+                        if (pipeline_stage_uses.size() != 1) {
+                            TINT_ICE(Writer, diagnostics_) << "invalid entry point IO struct uses";
+                            return false;
+                        }
+
+                        if (pipeline_stage_uses.count(sem::PipelineStageUsage::kVertexInput)) {
+                            out << " [[attribute(" + std::to_string(loc->value) + ")]]";
+                        } else if (pipeline_stage_uses.count(
+                                       sem::PipelineStageUsage::kVertexOutput)) {
+                            out << " [[user(locn" + std::to_string(loc->value) + ")]]";
+                        } else if (pipeline_stage_uses.count(
+                                       sem::PipelineStageUsage::kFragmentInput)) {
+                            out << " [[user(locn" + std::to_string(loc->value) + ")]]";
+                        } else if (pipeline_stage_uses.count(
+                                       sem::PipelineStageUsage::kFragmentOutput)) {
+                            out << " [[color(" + std::to_string(loc->value) + ")]]";
+                        } else {
+                            TINT_ICE(Writer, diagnostics_) << "invalid use of location decoration";
+                            return false;
+                        }
+                        return true;
+                    },
+                    [&](const ast::InterpolateAttribute* interpolate) {
+                        auto name =
+                            interpolation_to_attribute(interpolate->type, interpolate->sampling);
+                        if (name.empty()) {
+                            diagnostics_.add_error(diag::System::Writer,
+                                                   "unknown interpolation attribute");
+                            return false;
+                        }
+                        out << " [[" << name << "]]";
+                        return true;
+                    },
+                    [&](const ast::InvariantAttribute*) {
+                        if (invariant_define_name_.empty()) {
+                            invariant_define_name_ = UniqueIdentifier("TINT_INVARIANT");
+                        }
+                        out << " " << invariant_define_name_;
+                        return true;
+                    },
+                    [&](const ast::StructMemberOffsetAttribute*) { return true; },
+                    [&](const ast::StructMemberAlignAttribute*) { return true; },
+                    [&](const ast::StructMemberSizeAttribute*) { return true; },
+                    [&](Default) {
+                        TINT_ICE(Writer, diagnostics_)
+                            << "unhandled struct member attribute: " << attr->Name();
+                        return false;
+                    });
+                if (!ok) {
+                    return false;
+                }
+            }
+        }
+
+        out << ";";
+
+        if (is_host_shareable) {
+            // Calculate new MSL offset
+            auto size_align = MslPackedTypeSizeAndAlign(ty);
+            if (msl_offset % size_align.align) {
+                TINT_ICE(Writer, diagnostics_)
+                    << "Misaligned MSL structure member " << ty->FriendlyName(program_->Symbols())
+                    << " " << mem_name;
+                return false;
+            }
+            msl_offset += size_align.size;
+        }
     }
 
-    out << ";";
-
-    if (is_host_shareable) {
-      // Calculate new MSL offset
-      auto size_align = MslPackedTypeSizeAndAlign(ty);
-      if (msl_offset % size_align.align) {
-        TINT_ICE(Writer, diagnostics_)
-            << "Misaligned MSL structure member "
-            << ty->FriendlyName(program_->Symbols()) << " " << mem_name;
-        return false;
-      }
-      msl_offset += size_align.size;
+    if (is_host_shareable && str->Size() != msl_offset) {
+        add_padding(str->Size() - msl_offset, msl_offset);
     }
-  }
 
-  if (is_host_shareable && str->Size() != msl_offset) {
-    add_padding(str->Size() - msl_offset, msl_offset);
-  }
+    b->DecrementIndent();
 
-  b->DecrementIndent();
-
-  line(b) << "};";
-  return true;
+    line(b) << "};";
+    return true;
 }
 
-bool GeneratorImpl::EmitUnaryOp(std::ostream& out,
-                                const ast::UnaryOpExpression* expr) {
-  // Handle `-e` when `e` is signed, so that we ensure that if `e` is the
-  // largest negative value, it returns `e`.
-  auto* expr_type = TypeOf(expr->expr)->UnwrapRef();
-  if (expr->op == ast::UnaryOp::kNegation &&
-      expr_type->is_signed_scalar_or_vector()) {
-    auto fn =
-        utils::GetOrCreate(unary_minus_funcs_, expr_type, [&]() -> std::string {
-          // e.g.:
-          // int tint_unary_minus(const int v) {
-          //     return (v == -2147483648) ? v : -v;
-          // }
-          TextBuffer b;
-          TINT_DEFER(helpers_.Append(b));
+bool GeneratorImpl::EmitUnaryOp(std::ostream& out, const ast::UnaryOpExpression* expr) {
+    // Handle `-e` when `e` is signed, so that we ensure that if `e` is the
+    // largest negative value, it returns `e`.
+    auto* expr_type = TypeOf(expr->expr)->UnwrapRef();
+    if (expr->op == ast::UnaryOp::kNegation && expr_type->is_signed_scalar_or_vector()) {
+        auto fn = utils::GetOrCreate(unary_minus_funcs_, expr_type, [&]() -> std::string {
+            // e.g.:
+            // int tint_unary_minus(const int v) {
+            //     return (v == -2147483648) ? v : -v;
+            // }
+            TextBuffer b;
+            TINT_DEFER(helpers_.Append(b));
 
-          auto fn_name = UniqueIdentifier("tint_unary_minus");
-          {
-            auto decl = line(&b);
-            if (!EmitTypeAndName(decl, expr_type, fn_name)) {
-              return "";
+            auto fn_name = UniqueIdentifier("tint_unary_minus");
+            {
+                auto decl = line(&b);
+                if (!EmitTypeAndName(decl, expr_type, fn_name)) {
+                    return "";
+                }
+                decl << "(const ";
+                if (!EmitType(decl, expr_type, "")) {
+                    return "";
+                }
+                decl << " v) {";
             }
-            decl << "(const ";
-            if (!EmitType(decl, expr_type, "")) {
-              return "";
-            }
-            decl << " v) {";
-          }
 
-          {
-            ScopedIndent si(&b);
-            const auto largest_negative_value =
-                std::to_string(std::numeric_limits<int32_t>::min());
-            line(&b) << "return select(-v, v, v == " << largest_negative_value
-                     << ");";
-          }
-          line(&b) << "}";
-          line(&b);
-          return fn_name;
+            {
+                ScopedIndent si(&b);
+                const auto largest_negative_value =
+                    std::to_string(std::numeric_limits<int32_t>::min());
+                line(&b) << "return select(-v, v, v == " << largest_negative_value << ");";
+            }
+            line(&b) << "}";
+            line(&b);
+            return fn_name;
         });
 
-    out << fn << "(";
-    if (!EmitExpression(out, expr->expr)) {
-      return false;
+        out << fn << "(";
+        if (!EmitExpression(out, expr->expr)) {
+            return false;
+        }
+        out << ")";
+        return true;
     }
+
+    switch (expr->op) {
+        case ast::UnaryOp::kAddressOf:
+            out << "&";
+            break;
+        case ast::UnaryOp::kComplement:
+            out << "~";
+            break;
+        case ast::UnaryOp::kIndirection:
+            out << "*";
+            break;
+        case ast::UnaryOp::kNot:
+            out << "!";
+            break;
+        case ast::UnaryOp::kNegation:
+            out << "-";
+            break;
+    }
+    out << "(";
+
+    if (!EmitExpression(out, expr->expr)) {
+        return false;
+    }
+
     out << ")";
+
     return true;
-  }
-
-  switch (expr->op) {
-    case ast::UnaryOp::kAddressOf:
-      out << "&";
-      break;
-    case ast::UnaryOp::kComplement:
-      out << "~";
-      break;
-    case ast::UnaryOp::kIndirection:
-      out << "*";
-      break;
-    case ast::UnaryOp::kNot:
-      out << "!";
-      break;
-    case ast::UnaryOp::kNegation:
-      out << "-";
-      break;
-  }
-  out << "(";
-
-  if (!EmitExpression(out, expr->expr)) {
-    return false;
-  }
-
-  out << ")";
-
-  return true;
 }
 
 bool GeneratorImpl::EmitVariable(const sem::Variable* var) {
-  auto* decl = var->Declaration();
+    auto* decl = var->Declaration();
 
-  for (auto* attr : decl->attributes) {
-    if (!attr->Is<ast::InternalAttribute>()) {
-      TINT_ICE(Writer, diagnostics_) << "unexpected variable attribute";
-      return false;
+    for (auto* attr : decl->attributes) {
+        if (!attr->Is<ast::InternalAttribute>()) {
+            TINT_ICE(Writer, diagnostics_) << "unexpected variable attribute";
+            return false;
+        }
     }
-  }
 
-  auto out = line();
+    auto out = line();
 
-  switch (var->StorageClass()) {
-    case ast::StorageClass::kFunction:
-    case ast::StorageClass::kUniformConstant:
-    case ast::StorageClass::kNone:
-      break;
-    case ast::StorageClass::kPrivate:
-      out << "thread ";
-      break;
-    case ast::StorageClass::kWorkgroup:
-      out << "threadgroup ";
-      break;
-    default:
-      TINT_ICE(Writer, diagnostics_) << "unhandled variable storage class";
-      return false;
-  }
-
-  auto* type = var->Type()->UnwrapRef();
-
-  std::string name = program_->Symbols().NameFor(decl->symbol);
-  if (decl->is_const) {
-    name = "const " + name;
-  }
-  if (!EmitType(out, type, name)) {
-    return false;
-  }
-  // Variable name is output as part of the type for arrays and pointers.
-  if (!type->Is<sem::Array>() && !type->Is<sem::Pointer>()) {
-    out << " " << name;
-  }
-
-  if (decl->constructor != nullptr) {
-    out << " = ";
-    if (!EmitExpression(out, decl->constructor)) {
-      return false;
+    switch (var->StorageClass()) {
+        case ast::StorageClass::kFunction:
+        case ast::StorageClass::kHandle:
+        case ast::StorageClass::kNone:
+            break;
+        case ast::StorageClass::kPrivate:
+            out << "thread ";
+            break;
+        case ast::StorageClass::kWorkgroup:
+            out << "threadgroup ";
+            break;
+        default:
+            TINT_ICE(Writer, diagnostics_) << "unhandled variable storage class";
+            return false;
     }
-  } else if (var->StorageClass() == ast::StorageClass::kPrivate ||
-             var->StorageClass() == ast::StorageClass::kFunction ||
-             var->StorageClass() == ast::StorageClass::kNone) {
-    out << " = ";
-    if (!EmitZeroValue(out, type)) {
-      return false;
-    }
-  }
-  out << ";";
 
-  return true;
+    auto* type = var->Type()->UnwrapRef();
+
+    std::string name = program_->Symbols().NameFor(decl->symbol);
+    if (decl->is_const) {
+        name = "const " + name;
+    }
+    if (!EmitType(out, type, name)) {
+        return false;
+    }
+    // Variable name is output as part of the type for arrays and pointers.
+    if (!type->Is<sem::Array>() && !type->Is<sem::Pointer>()) {
+        out << " " << name;
+    }
+
+    if (decl->constructor != nullptr) {
+        out << " = ";
+        if (!EmitExpression(out, decl->constructor)) {
+            return false;
+        }
+    } else if (var->StorageClass() == ast::StorageClass::kPrivate ||
+               var->StorageClass() == ast::StorageClass::kFunction ||
+               var->StorageClass() == ast::StorageClass::kNone) {
+        out << " = ";
+        if (!EmitZeroValue(out, type)) {
+            return false;
+        }
+    }
+    out << ";";
+
+    return true;
 }
 
 bool GeneratorImpl::EmitProgramConstVariable(const ast::Variable* var) {
-  for (auto* d : var->attributes) {
-    if (!d->Is<ast::IdAttribute>()) {
-      diagnostics_.add_error(diag::System::Writer,
-                             "Decorated const values not valid");
-      return false;
+    for (auto* d : var->attributes) {
+        if (!d->Is<ast::IdAttribute>()) {
+            diagnostics_.add_error(diag::System::Writer, "Decorated const values not valid");
+            return false;
+        }
     }
-  }
-  if (!var->is_const) {
-    diagnostics_.add_error(diag::System::Writer, "Expected a const value");
-    return false;
-  }
-
-  auto out = line();
-  out << "constant ";
-  auto* type = program_->Sem().Get(var)->Type()->UnwrapRef();
-  if (!EmitType(out, type, program_->Symbols().NameFor(var->symbol))) {
-    return false;
-  }
-  if (!type->Is<sem::Array>()) {
-    out << " " << program_->Symbols().NameFor(var->symbol);
-  }
-
-  auto* global = program_->Sem().Get<sem::GlobalVariable>(var);
-  if (global && global->IsOverridable()) {
-    out << " [[function_constant(" << global->ConstantId() << ")]]";
-  } else if (var->constructor != nullptr) {
-    out << " = ";
-    if (!EmitExpression(out, var->constructor)) {
-      return false;
+    if (!var->is_const) {
+        diagnostics_.add_error(diag::System::Writer, "Expected a const value");
+        return false;
     }
-  }
-  out << ";";
 
-  return true;
+    auto out = line();
+    out << "constant ";
+    auto* type = program_->Sem().Get(var)->Type()->UnwrapRef();
+    if (!EmitType(out, type, program_->Symbols().NameFor(var->symbol))) {
+        return false;
+    }
+    if (!type->Is<sem::Array>()) {
+        out << " " << program_->Symbols().NameFor(var->symbol);
+    }
+
+    auto* global = program_->Sem().Get<sem::GlobalVariable>(var);
+    if (global && global->IsOverridable()) {
+        out << " [[function_constant(" << global->ConstantId() << ")]]";
+    } else if (var->constructor != nullptr) {
+        out << " = ";
+        if (!EmitExpression(out, var->constructor)) {
+            return false;
+        }
+    }
+    out << ";";
+
+    return true;
 }
 
-GeneratorImpl::SizeAndAlign GeneratorImpl::MslPackedTypeSizeAndAlign(
-    const sem::Type* ty) {
-  return Switch(
-      ty,
+GeneratorImpl::SizeAndAlign GeneratorImpl::MslPackedTypeSizeAndAlign(const sem::Type* ty) {
+    return Switch(
+        ty,
 
-      // https://developer.apple.com/metal/Metal-Shading-Language-Specification.pdf
-      // 2.1 Scalar Data Types
-      [&](const sem::U32*) {
-        return SizeAndAlign{4, 4};
-      },
-      [&](const sem::I32*) {
-        return SizeAndAlign{4, 4};
-      },
-      [&](const sem::F32*) {
-        return SizeAndAlign{4, 4};
-      },
-
-      [&](const sem::Vector* vec) {
-        auto num_els = vec->Width();
-        auto* el_ty = vec->type();
-        if (el_ty->IsAnyOf<sem::U32, sem::I32, sem::F32>()) {
-          // Use a packed_vec type for 3-element vectors only.
-          if (num_els == 3) {
-            // https://developer.apple.com/metal/Metal-Shading-Language-Specification.pdf
-            // 2.2.3 Packed Vector Types
-            return SizeAndAlign{num_els * 4, 4};
-          } else {
-            // https://developer.apple.com/metal/Metal-Shading-Language-Specification.pdf
-            // 2.2 Vector Data Types
-            return SizeAndAlign{num_els * 4, num_els * 4};
-          }
-        }
-        TINT_UNREACHABLE(Writer, diagnostics_)
-            << "Unhandled vector element type " << el_ty->TypeInfo().name;
-        return SizeAndAlign{};
-      },
-
-      [&](const sem::Matrix* mat) {
         // https://developer.apple.com/metal/Metal-Shading-Language-Specification.pdf
-        // 2.3 Matrix Data Types
-        auto cols = mat->columns();
-        auto rows = mat->rows();
-        auto* el_ty = mat->type();
-        if (el_ty->IsAnyOf<sem::U32, sem::I32, sem::F32>()) {
-          static constexpr SizeAndAlign table[] = {
-              /* float2x2 */ {16, 8},
-              /* float2x3 */ {32, 16},
-              /* float2x4 */ {32, 16},
-              /* float3x2 */ {24, 8},
-              /* float3x3 */ {48, 16},
-              /* float3x4 */ {48, 16},
-              /* float4x2 */ {32, 8},
-              /* float4x3 */ {64, 16},
-              /* float4x4 */ {64, 16},
-          };
-          if (cols >= 2 && cols <= 4 && rows >= 2 && rows <= 4) {
-            return table[(3 * (cols - 2)) + (rows - 2)];
-          }
-        }
+        // 2.1 Scalar Data Types
+        [&](const sem::U32*) {
+            return SizeAndAlign{4, 4};
+        },
+        [&](const sem::I32*) {
+            return SizeAndAlign{4, 4};
+        },
+        [&](const sem::F32*) {
+            return SizeAndAlign{4, 4};
+        },
 
-        TINT_UNREACHABLE(Writer, diagnostics_)
-            << "Unhandled matrix element type " << el_ty->TypeInfo().name;
-        return SizeAndAlign{};
-      },
+        [&](const sem::Vector* vec) {
+            auto num_els = vec->Width();
+            auto* el_ty = vec->type();
+            if (el_ty->IsAnyOf<sem::U32, sem::I32, sem::F32>()) {
+                // Use a packed_vec type for 3-element vectors only.
+                if (num_els == 3) {
+                    // https://developer.apple.com/metal/Metal-Shading-Language-Specification.pdf
+                    // 2.2.3 Packed Vector Types
+                    return SizeAndAlign{num_els * 4, 4};
+                } else {
+                    // https://developer.apple.com/metal/Metal-Shading-Language-Specification.pdf
+                    // 2.2 Vector Data Types
+                    return SizeAndAlign{num_els * 4, num_els * 4};
+                }
+            }
+            TINT_UNREACHABLE(Writer, diagnostics_)
+                << "Unhandled vector element type " << el_ty->TypeInfo().name;
+            return SizeAndAlign{};
+        },
 
-      [&](const sem::Array* arr) {
-        if (!arr->IsStrideImplicit()) {
-          TINT_ICE(Writer, diagnostics_) << "arrays with explicit strides not "
-                                            "exist past the SPIR-V reader";
-          return SizeAndAlign{};
-        }
-        auto num_els = std::max<uint32_t>(arr->Count(), 1);
-        return SizeAndAlign{arr->Stride() * num_els, arr->Align()};
-      },
+        [&](const sem::Matrix* mat) {
+            // https://developer.apple.com/metal/Metal-Shading-Language-Specification.pdf
+            // 2.3 Matrix Data Types
+            auto cols = mat->columns();
+            auto rows = mat->rows();
+            auto* el_ty = mat->type();
+            if (el_ty->IsAnyOf<sem::U32, sem::I32, sem::F32>()) {
+                static constexpr SizeAndAlign table[] = {
+                    /* float2x2 */ {16, 8},
+                    /* float2x3 */ {32, 16},
+                    /* float2x4 */ {32, 16},
+                    /* float3x2 */ {24, 8},
+                    /* float3x3 */ {48, 16},
+                    /* float3x4 */ {48, 16},
+                    /* float4x2 */ {32, 8},
+                    /* float4x3 */ {64, 16},
+                    /* float4x4 */ {64, 16},
+                };
+                if (cols >= 2 && cols <= 4 && rows >= 2 && rows <= 4) {
+                    return table[(3 * (cols - 2)) + (rows - 2)];
+                }
+            }
 
-      [&](const sem::Struct* str) {
-        // TODO(crbug.com/tint/650): There's an assumption here that MSL's
-        // default structure size and alignment matches WGSL's. We need to
-        // confirm this.
-        return SizeAndAlign{str->Size(), str->Align()};
-      },
+            TINT_UNREACHABLE(Writer, diagnostics_)
+                << "Unhandled matrix element type " << el_ty->TypeInfo().name;
+            return SizeAndAlign{};
+        },
 
-      [&](const sem::Atomic* atomic) {
-        return MslPackedTypeSizeAndAlign(atomic->Type());
-      },
+        [&](const sem::Array* arr) {
+            if (!arr->IsStrideImplicit()) {
+                TINT_ICE(Writer, diagnostics_) << "arrays with explicit strides not "
+                                                  "exist past the SPIR-V reader";
+                return SizeAndAlign{};
+            }
+            auto num_els = std::max<uint32_t>(arr->Count(), 1);
+            return SizeAndAlign{arr->Stride() * num_els, arr->Align()};
+        },
 
-      [&](Default) {
-        TINT_UNREACHABLE(Writer, diagnostics_)
-            << "Unhandled type " << ty->TypeInfo().name;
-        return SizeAndAlign{};
-      });
+        [&](const sem::Struct* str) {
+            // TODO(crbug.com/tint/650): There's an assumption here that MSL's
+            // default structure size and alignment matches WGSL's. We need to
+            // confirm this.
+            return SizeAndAlign{str->Size(), str->Align()};
+        },
+
+        [&](const sem::Atomic* atomic) { return MslPackedTypeSizeAndAlign(atomic->Type()); },
+
+        [&](Default) {
+            TINT_UNREACHABLE(Writer, diagnostics_) << "Unhandled type " << ty->TypeInfo().name;
+            return SizeAndAlign{};
+        });
 }
 
 template <typename F>
@@ -2981,65 +2891,64 @@
                                       const ast::CallExpression* call,
                                       const sem::Builtin* builtin,
                                       F&& build) {
-  // Generate the helper function if it hasn't been created already
-  auto fn = utils::GetOrCreate(builtins_, builtin, [&]() -> std::string {
-    TextBuffer b;
-    TINT_DEFER(helpers_.Append(b));
+    // Generate the helper function if it hasn't been created already
+    auto fn = utils::GetOrCreate(builtins_, builtin, [&]() -> std::string {
+        TextBuffer b;
+        TINT_DEFER(helpers_.Append(b));
 
-    auto fn_name =
-        UniqueIdentifier(std::string("tint_") + sem::str(builtin->Type()));
-    std::vector<std::string> parameter_names;
-    {
-      auto decl = line(&b);
-      if (!EmitTypeAndName(decl, builtin->ReturnType(), fn_name)) {
-        return "";
-      }
-      {
-        ScopedParen sp(decl);
-        for (auto* param : builtin->Parameters()) {
-          if (!parameter_names.empty()) {
-            decl << ", ";
-          }
-          auto param_name = "param_" + std::to_string(parameter_names.size());
-          if (!EmitTypeAndName(decl, param->Type(), param_name)) {
-            return "";
-          }
-          parameter_names.emplace_back(std::move(param_name));
+        auto fn_name = UniqueIdentifier(std::string("tint_") + sem::str(builtin->Type()));
+        std::vector<std::string> parameter_names;
+        {
+            auto decl = line(&b);
+            if (!EmitTypeAndName(decl, builtin->ReturnType(), fn_name)) {
+                return "";
+            }
+            {
+                ScopedParen sp(decl);
+                for (auto* param : builtin->Parameters()) {
+                    if (!parameter_names.empty()) {
+                        decl << ", ";
+                    }
+                    auto param_name = "param_" + std::to_string(parameter_names.size());
+                    if (!EmitTypeAndName(decl, param->Type(), param_name)) {
+                        return "";
+                    }
+                    parameter_names.emplace_back(std::move(param_name));
+                }
+            }
+            decl << " {";
         }
-      }
-      decl << " {";
-    }
-    {
-      ScopedIndent si(&b);
-      if (!build(&b, parameter_names)) {
-        return "";
-      }
-    }
-    line(&b) << "}";
-    line(&b);
-    return fn_name;
-  });
+        {
+            ScopedIndent si(&b);
+            if (!build(&b, parameter_names)) {
+                return "";
+            }
+        }
+        line(&b) << "}";
+        line(&b);
+        return fn_name;
+    });
 
-  if (fn.empty()) {
-    return false;
-  }
-
-  // Call the helper
-  out << fn;
-  {
-    ScopedParen sp(out);
-    bool first = true;
-    for (auto* arg : call->args) {
-      if (!first) {
-        out << ", ";
-      }
-      first = false;
-      if (!EmitExpression(out, arg)) {
+    if (fn.empty()) {
         return false;
-      }
     }
-  }
-  return true;
+
+    // Call the helper
+    out << fn;
+    {
+        ScopedParen sp(out);
+        bool first = true;
+        for (auto* arg : call->args) {
+            if (!first) {
+                out << ", ";
+            }
+            first = false;
+            if (!EmitExpression(out, arg)) {
+                return false;
+            }
+        }
+    }
+    return true;
 }
 
 }  // namespace tint::writer::msl
diff --git a/src/tint/writer/msl/generator_impl.h b/src/tint/writer/msl/generator_impl.h
index f3cee25..b7a2029 100644
--- a/src/tint/writer/msl/generator_impl.h
+++ b/src/tint/writer/msl/generator_impl.h
@@ -54,20 +54,20 @@
 
 /// The result of sanitizing a program for generation.
 struct SanitizedResult {
-  /// Constructor
-  SanitizedResult();
-  /// Destructor
-  ~SanitizedResult();
-  /// Move constructor
-  SanitizedResult(SanitizedResult&&);
+    /// Constructor
+    SanitizedResult();
+    /// Destructor
+    ~SanitizedResult();
+    /// Move constructor
+    SanitizedResult(SanitizedResult&&);
 
-  /// The sanitized program.
-  Program program;
-  /// True if the shader needs a UBO of buffer sizes.
-  bool needs_storage_buffer_sizes = false;
-  /// Indices into the array_length_from_uniform binding that are statically
-  /// used.
-  std::unordered_set<uint32_t> used_array_length_from_uniform_indices;
+    /// The sanitized program.
+    Program program;
+    /// True if the shader needs a UBO of buffer sizes.
+    bool needs_storage_buffer_sizes = false;
+    /// Indices into the array_length_from_uniform binding that are statically
+    /// used.
+    std::unordered_set<uint32_t> used_array_length_from_uniform_indices;
 };
 
 /// Sanitize a program in preparation for generating MSL.
@@ -78,359 +78,345 @@
 
 /// Implementation class for MSL generator
 class GeneratorImpl : public TextGenerator {
- public:
-  /// Constructor
-  /// @param program the program to generate
-  explicit GeneratorImpl(const Program* program);
-  ~GeneratorImpl();
+  public:
+    /// Constructor
+    /// @param program the program to generate
+    explicit GeneratorImpl(const Program* program);
+    ~GeneratorImpl();
 
-  /// @returns true on successful generation; false otherwise
-  bool Generate();
+    /// @returns true on successful generation; false otherwise
+    bool Generate();
 
-  /// @returns true if an invariant attribute was generated
-  bool HasInvariant() { return !invariant_define_name_.empty(); }
+    /// @returns true if an invariant attribute was generated
+    bool HasInvariant() { return !invariant_define_name_.empty(); }
 
-  /// @returns a map from entry point to list of required workgroup allocations
-  const std::unordered_map<std::string, std::vector<uint32_t>>&
-  DynamicWorkgroupAllocations() const {
-    return workgroup_allocations_;
-  }
+    /// @returns a map from entry point to list of required workgroup allocations
+    const std::unordered_map<std::string, std::vector<uint32_t>>& DynamicWorkgroupAllocations()
+        const {
+        return workgroup_allocations_;
+    }
 
-  /// Handles generating a declared type
-  /// @param ty the declared type to generate
-  /// @returns true if the declared type was emitted
-  bool EmitTypeDecl(const sem::Type* ty);
-  /// Handles an index accessor expression
-  /// @param out the output of the expression stream
-  /// @param expr the expression to emit
-  /// @returns true if the index accessor was emitted
-  bool EmitIndexAccessor(std::ostream& out,
-                         const ast::IndexAccessorExpression* expr);
-  /// Handles an assignment statement
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was emitted successfully
-  bool EmitAssign(const ast::AssignmentStatement* stmt);
-  /// Handles generating a binary expression
-  /// @param out the output of the expression stream
-  /// @param expr the binary expression
-  /// @returns true if the expression was emitted, false otherwise
-  bool EmitBinary(std::ostream& out, const ast::BinaryExpression* expr);
-  /// Handles generating a bitcast expression
-  /// @param out the output of the expression stream
-  /// @param expr the bitcast expression
-  /// @returns true if the bitcast was emitted
-  bool EmitBitcast(std::ostream& out, const ast::BitcastExpression* expr);
-  /// Handles a block statement
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was emitted successfully
-  bool EmitBlock(const ast::BlockStatement* stmt);
-  /// Handles a break statement
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was emitted successfully
-  bool EmitBreak(const ast::BreakStatement* stmt);
-  /// Handles generating a call expression
-  /// @param out the output of the expression stream
-  /// @param expr the call expression
-  /// @returns true if the call expression is emitted
-  bool EmitCall(std::ostream& out, const ast::CallExpression* expr);
-  /// Handles generating a builtin call expression
-  /// @param out the output of the expression stream
-  /// @param call the call expression
-  /// @param builtin the builtin being called
-  /// @returns true if the call expression is emitted
-  bool EmitBuiltinCall(std::ostream& out,
-                       const sem::Call* call,
-                       const sem::Builtin* builtin);
-  /// Handles generating a type conversion expression
-  /// @param out the output of the expression stream
-  /// @param call the call expression
-  /// @param conv the type conversion
-  /// @returns true if the expression is emitted
-  bool EmitTypeConversion(std::ostream& out,
-                          const sem::Call* call,
-                          const sem::TypeConversion* conv);
-  /// Handles generating a type constructor
-  /// @param out the output of the expression stream
-  /// @param call the call expression
-  /// @param ctor the type constructor
-  /// @returns true if the constructor is emitted
-  bool EmitTypeConstructor(std::ostream& out,
-                           const sem::Call* call,
-                           const sem::TypeConstructor* ctor);
-  /// Handles generating a function call
-  /// @param out the output of the expression stream
-  /// @param call the call expression
-  /// @param func the target function
-  /// @returns true if the call is emitted
-  bool EmitFunctionCall(std::ostream& out,
-                        const sem::Call* call,
-                        const sem::Function* func);
-  /// Handles generating a call to an atomic function (`atomicAdd`,
-  /// `atomicMax`, etc)
-  /// @param out the output of the expression stream
-  /// @param expr the call expression
-  /// @param builtin the semantic information for the atomic builtin
-  /// @returns true if the call expression is emitted
-  bool EmitAtomicCall(std::ostream& out,
-                      const ast::CallExpression* expr,
-                      const sem::Builtin* builtin);
-  /// Handles generating a call to a texture function (`textureSample`,
-  /// `textureSampleGrad`, etc)
-  /// @param out the output of the expression stream
-  /// @param call the call expression
-  /// @param builtin the semantic information for the texture builtin
-  /// @returns true if the call expression is emitted
-  bool EmitTextureCall(std::ostream& out,
-                       const sem::Call* call,
-                       const sem::Builtin* builtin);
-  /// Handles generating a call to the `dot()` builtin
-  /// @param out the output of the expression stream
-  /// @param expr the call expression
-  /// @param builtin the semantic information for the builtin
-  /// @returns true if the call expression is emitted
-  bool EmitDotCall(std::ostream& out,
-                   const ast::CallExpression* expr,
-                   const sem::Builtin* builtin);
-  /// Handles generating a call to the `modf()` builtin
-  /// @param out the output of the expression stream
-  /// @param expr the call expression
-  /// @param builtin the semantic information for the builtin
-  /// @returns true if the call expression is emitted
-  bool EmitModfCall(std::ostream& out,
-                    const ast::CallExpression* expr,
-                    const sem::Builtin* builtin);
-  /// Handles generating a call to the `frexp()` builtin
-  /// @param out the output of the expression stream
-  /// @param expr the call expression
-  /// @param builtin the semantic information for the builtin
-  /// @returns true if the call expression is emitted
-  bool EmitFrexpCall(std::ostream& out,
+    /// Handles generating a declared type
+    /// @param ty the declared type to generate
+    /// @returns true if the declared type was emitted
+    bool EmitTypeDecl(const sem::Type* ty);
+    /// Handles an index accessor expression
+    /// @param out the output of the expression stream
+    /// @param expr the expression to emit
+    /// @returns true if the index accessor was emitted
+    bool EmitIndexAccessor(std::ostream& out, const ast::IndexAccessorExpression* expr);
+    /// Handles an assignment statement
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was emitted successfully
+    bool EmitAssign(const ast::AssignmentStatement* stmt);
+    /// Handles generating a binary expression
+    /// @param out the output of the expression stream
+    /// @param expr the binary expression
+    /// @returns true if the expression was emitted, false otherwise
+    bool EmitBinary(std::ostream& out, const ast::BinaryExpression* expr);
+    /// Handles generating a bitcast expression
+    /// @param out the output of the expression stream
+    /// @param expr the bitcast expression
+    /// @returns true if the bitcast was emitted
+    bool EmitBitcast(std::ostream& out, const ast::BitcastExpression* expr);
+    /// Handles a block statement
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was emitted successfully
+    bool EmitBlock(const ast::BlockStatement* stmt);
+    /// Handles a break statement
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was emitted successfully
+    bool EmitBreak(const ast::BreakStatement* stmt);
+    /// Handles generating a call expression
+    /// @param out the output of the expression stream
+    /// @param expr the call expression
+    /// @returns true if the call expression is emitted
+    bool EmitCall(std::ostream& out, const ast::CallExpression* expr);
+    /// Handles generating a builtin call expression
+    /// @param out the output of the expression stream
+    /// @param call the call expression
+    /// @param builtin the builtin being called
+    /// @returns true if the call expression is emitted
+    bool EmitBuiltinCall(std::ostream& out, const sem::Call* call, const sem::Builtin* builtin);
+    /// Handles generating a type conversion expression
+    /// @param out the output of the expression stream
+    /// @param call the call expression
+    /// @param conv the type conversion
+    /// @returns true if the expression is emitted
+    bool EmitTypeConversion(std::ostream& out,
+                            const sem::Call* call,
+                            const sem::TypeConversion* conv);
+    /// Handles generating a type constructor
+    /// @param out the output of the expression stream
+    /// @param call the call expression
+    /// @param ctor the type constructor
+    /// @returns true if the constructor is emitted
+    bool EmitTypeConstructor(std::ostream& out,
+                             const sem::Call* call,
+                             const sem::TypeConstructor* ctor);
+    /// Handles generating a function call
+    /// @param out the output of the expression stream
+    /// @param call the call expression
+    /// @param func the target function
+    /// @returns true if the call is emitted
+    bool EmitFunctionCall(std::ostream& out, const sem::Call* call, const sem::Function* func);
+    /// Handles generating a call to an atomic function (`atomicAdd`,
+    /// `atomicMax`, etc)
+    /// @param out the output of the expression stream
+    /// @param expr the call expression
+    /// @param builtin the semantic information for the atomic builtin
+    /// @returns true if the call expression is emitted
+    bool EmitAtomicCall(std::ostream& out,
+                        const ast::CallExpression* expr,
+                        const sem::Builtin* builtin);
+    /// Handles generating a call to a texture function (`textureSample`,
+    /// `textureSampleGrad`, etc)
+    /// @param out the output of the expression stream
+    /// @param call the call expression
+    /// @param builtin the semantic information for the texture builtin
+    /// @returns true if the call expression is emitted
+    bool EmitTextureCall(std::ostream& out, const sem::Call* call, const sem::Builtin* builtin);
+    /// Handles generating a call to the `dot()` builtin
+    /// @param out the output of the expression stream
+    /// @param expr the call expression
+    /// @param builtin the semantic information for the builtin
+    /// @returns true if the call expression is emitted
+    bool EmitDotCall(std::ostream& out,
                      const ast::CallExpression* expr,
                      const sem::Builtin* builtin);
-  /// Handles generating a call to the `degrees()` builtin
-  /// @param out the output of the expression stream
-  /// @param expr the call expression
-  /// @param builtin the semantic information for the builtin
-  /// @returns true if the call expression is emitted
-  bool EmitDegreesCall(std::ostream& out,
+    /// Handles generating a call to the `modf()` builtin
+    /// @param out the output of the expression stream
+    /// @param expr the call expression
+    /// @param builtin the semantic information for the builtin
+    /// @returns true if the call expression is emitted
+    bool EmitModfCall(std::ostream& out,
+                      const ast::CallExpression* expr,
+                      const sem::Builtin* builtin);
+    /// Handles generating a call to the `frexp()` builtin
+    /// @param out the output of the expression stream
+    /// @param expr the call expression
+    /// @param builtin the semantic information for the builtin
+    /// @returns true if the call expression is emitted
+    bool EmitFrexpCall(std::ostream& out,
                        const ast::CallExpression* expr,
                        const sem::Builtin* builtin);
-  /// Handles generating a call to the `radians()` builtin
-  /// @param out the output of the expression stream
-  /// @param expr the call expression
-  /// @param builtin the semantic information for the builtin
-  /// @returns true if the call expression is emitted
-  bool EmitRadiansCall(std::ostream& out,
-                       const ast::CallExpression* expr,
-                       const sem::Builtin* builtin);
-  /// Handles a case statement
-  /// @param stmt the statement
-  /// @returns true if the statement was emitted successfully
-  bool EmitCase(const ast::CaseStatement* stmt);
-  /// Handles a continue statement
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was emitted successfully
-  bool EmitContinue(const ast::ContinueStatement* stmt);
-  /// Handles generating a discard statement
-  /// @param stmt the discard statement
-  /// @returns true if the statement was successfully emitted
-  bool EmitDiscard(const ast::DiscardStatement* stmt);
-  /// Handles emitting the entry point function
-  /// @param func the entry point function
-  /// @returns true if the entry point function was emitted
-  bool EmitEntryPointFunction(const ast::Function* func);
-  /// Handles generate an Expression
-  /// @param out the output of the expression stream
-  /// @param expr the expression
-  /// @returns true if the expression was emitted
-  bool EmitExpression(std::ostream& out, const ast::Expression* expr);
-  /// Handles generating a function
-  /// @param func the function to generate
-  /// @returns true if the function was emitted
-  bool EmitFunction(const ast::Function* func);
-  /// Handles generating an identifier expression
-  /// @param out the output of the expression stream
-  /// @param expr the identifier expression
-  /// @returns true if the identifier was emitted
-  bool EmitIdentifier(std::ostream& out, const ast::IdentifierExpression* expr);
-  /// Handles an if statement
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was successfully emitted
-  bool EmitIf(const ast::IfStatement* stmt);
-  /// Handles a literal
-  /// @param out the output of the expression stream
-  /// @param lit the literal to emit
-  /// @returns true if the literal was successfully emitted
-  bool EmitLiteral(std::ostream& out, const ast::LiteralExpression* lit);
-  /// Handles a loop statement
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was emitted
-  bool EmitLoop(const ast::LoopStatement* stmt);
-  /// Handles a for loop statement
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was emitted
-  bool EmitForLoop(const ast::ForLoopStatement* stmt);
-  /// Handles a member accessor expression
-  /// @param out the output of the expression stream
-  /// @param expr the member accessor expression
-  /// @returns true if the member accessor was emitted
-  bool EmitMemberAccessor(std::ostream& out,
-                          const ast::MemberAccessorExpression* expr);
-  /// Handles return statements
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was successfully emitted
-  bool EmitReturn(const ast::ReturnStatement* stmt);
-  /// Handles emitting a pipeline stage name
-  /// @param out the output of the expression stream
-  /// @param stage the stage to emit
-  void EmitStage(std::ostream& out, ast::PipelineStage stage);
-  /// Handles statement
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was emitted
-  bool EmitStatement(const ast::Statement* stmt);
-  /// Emits a list of statements
-  /// @param stmts the statement list
-  /// @returns true if the statements were emitted successfully
-  bool EmitStatements(const ast::StatementList& stmts);
-  /// Emits a list of statements with an indentation
-  /// @param stmts the statement list
-  /// @returns true if the statements were emitted successfully
-  bool EmitStatementsWithIndent(const ast::StatementList& stmts);
-  /// Handles generating a switch statement
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was emitted
-  bool EmitSwitch(const ast::SwitchStatement* stmt);
-  /// Handles generating a type
-  /// @param out the output of the type stream
-  /// @param type the type to generate
-  /// @param name the name of the variable, only used for array emission
-  /// @param name_printed (optional) if not nullptr and an array was printed
-  /// @returns true if the type is emitted
-  bool EmitType(std::ostream& out,
-                const sem::Type* type,
-                const std::string& name,
-                bool* name_printed = nullptr);
-  /// Handles generating type and name
-  /// @param out the output stream
-  /// @param type the type to generate
-  /// @param name the name to emit
-  /// @returns true if the type is emitted
-  bool EmitTypeAndName(std::ostream& out,
-                       const sem::Type* type,
-                       const std::string& name);
-  /// Handles generating a storage class
-  /// @param out the output of the type stream
-  /// @param sc the storage class to generate
-  /// @returns true if the storage class is emitted
-  bool EmitStorageClass(std::ostream& out, ast::StorageClass sc);
-  /// Handles generating an MSL-packed storage type.
-  /// If the type does not have a packed form, the standard non-packed form is
-  /// emitted.
-  /// @param out the output of the type stream
-  /// @param type the type to generate
-  /// @param name the name of the variable, only used for array emission
-  /// @returns true if the type is emitted
-  bool EmitPackedType(std::ostream& out,
-                      const sem::Type* type,
-                      const std::string& name);
-  /// Handles generating a struct declaration
-  /// @param buffer the text buffer that the type declaration will be written to
-  /// @param str the struct to generate
-  /// @returns true if the struct is emitted
-  bool EmitStructType(TextBuffer* buffer, const sem::Struct* str);
-  /// Handles a unary op expression
-  /// @param out the output of the expression stream
-  /// @param expr the expression to emit
-  /// @returns true if the expression was emitted
-  bool EmitUnaryOp(std::ostream& out, const ast::UnaryOpExpression* expr);
-  /// Handles generating a variable
-  /// @param var the variable to generate
-  /// @returns true if the variable was emitted
-  bool EmitVariable(const sem::Variable* var);
-  /// Handles generating a program scope constant variable
-  /// @param var the variable to emit
-  /// @returns true if the variable was emitted
-  bool EmitProgramConstVariable(const ast::Variable* var);
-  /// Emits the zero value for the given type
-  /// @param out the output of the expression stream
-  /// @param type the type to emit the value for
-  /// @returns true if the zero value was successfully emitted.
-  bool EmitZeroValue(std::ostream& out, const sem::Type* type);
+    /// Handles generating a call to the `degrees()` builtin
+    /// @param out the output of the expression stream
+    /// @param expr the call expression
+    /// @param builtin the semantic information for the builtin
+    /// @returns true if the call expression is emitted
+    bool EmitDegreesCall(std::ostream& out,
+                         const ast::CallExpression* expr,
+                         const sem::Builtin* builtin);
+    /// Handles generating a call to the `radians()` builtin
+    /// @param out the output of the expression stream
+    /// @param expr the call expression
+    /// @param builtin the semantic information for the builtin
+    /// @returns true if the call expression is emitted
+    bool EmitRadiansCall(std::ostream& out,
+                         const ast::CallExpression* expr,
+                         const sem::Builtin* builtin);
+    /// Handles a case statement
+    /// @param stmt the statement
+    /// @returns true if the statement was emitted successfully
+    bool EmitCase(const ast::CaseStatement* stmt);
+    /// Handles a continue statement
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was emitted successfully
+    bool EmitContinue(const ast::ContinueStatement* stmt);
+    /// Handles generating a discard statement
+    /// @param stmt the discard statement
+    /// @returns true if the statement was successfully emitted
+    bool EmitDiscard(const ast::DiscardStatement* stmt);
+    /// Handles emitting the entry point function
+    /// @param func the entry point function
+    /// @returns true if the entry point function was emitted
+    bool EmitEntryPointFunction(const ast::Function* func);
+    /// Handles generate an Expression
+    /// @param out the output of the expression stream
+    /// @param expr the expression
+    /// @returns true if the expression was emitted
+    bool EmitExpression(std::ostream& out, const ast::Expression* expr);
+    /// Handles generating a function
+    /// @param func the function to generate
+    /// @returns true if the function was emitted
+    bool EmitFunction(const ast::Function* func);
+    /// Handles generating an identifier expression
+    /// @param out the output of the expression stream
+    /// @param expr the identifier expression
+    /// @returns true if the identifier was emitted
+    bool EmitIdentifier(std::ostream& out, const ast::IdentifierExpression* expr);
+    /// Handles an if statement
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was successfully emitted
+    bool EmitIf(const ast::IfStatement* stmt);
+    /// Handles a literal
+    /// @param out the output of the expression stream
+    /// @param lit the literal to emit
+    /// @returns true if the literal was successfully emitted
+    bool EmitLiteral(std::ostream& out, const ast::LiteralExpression* lit);
+    /// Handles a loop statement
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was emitted
+    bool EmitLoop(const ast::LoopStatement* stmt);
+    /// Handles a for loop statement
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was emitted
+    bool EmitForLoop(const ast::ForLoopStatement* stmt);
+    /// Handles a member accessor expression
+    /// @param out the output of the expression stream
+    /// @param expr the member accessor expression
+    /// @returns true if the member accessor was emitted
+    bool EmitMemberAccessor(std::ostream& out, const ast::MemberAccessorExpression* expr);
+    /// Handles return statements
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was successfully emitted
+    bool EmitReturn(const ast::ReturnStatement* stmt);
+    /// Handles emitting a pipeline stage name
+    /// @param out the output of the expression stream
+    /// @param stage the stage to emit
+    void EmitStage(std::ostream& out, ast::PipelineStage stage);
+    /// Handles statement
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was emitted
+    bool EmitStatement(const ast::Statement* stmt);
+    /// Emits a list of statements
+    /// @param stmts the statement list
+    /// @returns true if the statements were emitted successfully
+    bool EmitStatements(const ast::StatementList& stmts);
+    /// Emits a list of statements with an indentation
+    /// @param stmts the statement list
+    /// @returns true if the statements were emitted successfully
+    bool EmitStatementsWithIndent(const ast::StatementList& stmts);
+    /// Handles generating a switch statement
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was emitted
+    bool EmitSwitch(const ast::SwitchStatement* stmt);
+    /// Handles generating a type
+    /// @param out the output of the type stream
+    /// @param type the type to generate
+    /// @param name the name of the variable, only used for array emission
+    /// @param name_printed (optional) if not nullptr and an array was printed
+    /// @returns true if the type is emitted
+    bool EmitType(std::ostream& out,
+                  const sem::Type* type,
+                  const std::string& name,
+                  bool* name_printed = nullptr);
+    /// Handles generating type and name
+    /// @param out the output stream
+    /// @param type the type to generate
+    /// @param name the name to emit
+    /// @returns true if the type is emitted
+    bool EmitTypeAndName(std::ostream& out, const sem::Type* type, const std::string& name);
+    /// Handles generating a storage class
+    /// @param out the output of the type stream
+    /// @param sc the storage class to generate
+    /// @returns true if the storage class is emitted
+    bool EmitStorageClass(std::ostream& out, ast::StorageClass sc);
+    /// Handles generating an MSL-packed storage type.
+    /// If the type does not have a packed form, the standard non-packed form is
+    /// emitted.
+    /// @param out the output of the type stream
+    /// @param type the type to generate
+    /// @param name the name of the variable, only used for array emission
+    /// @returns true if the type is emitted
+    bool EmitPackedType(std::ostream& out, const sem::Type* type, const std::string& name);
+    /// Handles generating a struct declaration
+    /// @param buffer the text buffer that the type declaration will be written to
+    /// @param str the struct to generate
+    /// @returns true if the struct is emitted
+    bool EmitStructType(TextBuffer* buffer, const sem::Struct* str);
+    /// Handles a unary op expression
+    /// @param out the output of the expression stream
+    /// @param expr the expression to emit
+    /// @returns true if the expression was emitted
+    bool EmitUnaryOp(std::ostream& out, const ast::UnaryOpExpression* expr);
+    /// Handles generating a variable
+    /// @param var the variable to generate
+    /// @returns true if the variable was emitted
+    bool EmitVariable(const sem::Variable* var);
+    /// Handles generating a program scope constant variable
+    /// @param var the variable to emit
+    /// @returns true if the variable was emitted
+    bool EmitProgramConstVariable(const ast::Variable* var);
+    /// Emits the zero value for the given type
+    /// @param out the output of the expression stream
+    /// @param type the type to emit the value for
+    /// @returns true if the zero value was successfully emitted.
+    bool EmitZeroValue(std::ostream& out, const sem::Type* type);
 
-  /// Handles generating a builtin name
-  /// @param builtin the semantic info for the builtin
-  /// @returns the name or "" if not valid
-  std::string generate_builtin_name(const sem::Builtin* builtin);
+    /// Handles generating a builtin name
+    /// @param builtin the semantic info for the builtin
+    /// @returns the name or "" if not valid
+    std::string generate_builtin_name(const sem::Builtin* builtin);
 
-  /// 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;
+    /// 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;
 
-  /// Converts interpolation attributes to an MSL attribute
-  /// @param type the interpolation type
-  /// @param sampling the interpolation sampling
-  /// @returns the string name of the attribute or blank on error
-  std::string interpolation_to_attribute(
-      ast::InterpolationType type,
-      ast::InterpolationSampling sampling) const;
+    /// Converts interpolation attributes to an MSL attribute
+    /// @param type the interpolation type
+    /// @param sampling the interpolation sampling
+    /// @returns the string name of the attribute or blank on error
+    std::string interpolation_to_attribute(ast::InterpolationType type,
+                                           ast::InterpolationSampling sampling) const;
 
- private:
-  // A pair of byte size and alignment `uint32_t`s.
-  struct SizeAndAlign {
-    uint32_t size;
-    uint32_t align;
-  };
+  private:
+    // A pair of byte size and alignment `uint32_t`s.
+    struct SizeAndAlign {
+        uint32_t size;
+        uint32_t align;
+    };
 
-  /// CallBuiltinHelper will call the builtin helper function, creating it
-  /// if it hasn't been built already. If the builtin needs to be built then
-  /// CallBuiltinHelper will generate the function signature and will call
-  /// `build` to emit the body of the function.
-  /// @param out the output of the expression stream
-  /// @param call the call expression
-  /// @param builtin the semantic information for the builtin
-  /// @param build a function with the signature:
-  ///        `bool(TextBuffer* buffer, const std::vector<std::string>& params)`
-  ///        Where:
-  ///          `buffer` is the body of the generated function
-  ///          `params` is the name of all the generated function parameters
-  /// @returns true if the call expression is emitted
-  template <typename F>
-  bool CallBuiltinHelper(std::ostream& out,
-                         const ast::CallExpression* call,
-                         const sem::Builtin* builtin,
-                         F&& build);
+    /// CallBuiltinHelper will call the builtin helper function, creating it
+    /// if it hasn't been built already. If the builtin needs to be built then
+    /// CallBuiltinHelper will generate the function signature and will call
+    /// `build` to emit the body of the function.
+    /// @param out the output of the expression stream
+    /// @param call the call expression
+    /// @param builtin the semantic information for the builtin
+    /// @param build a function with the signature:
+    ///        `bool(TextBuffer* buffer, const std::vector<std::string>& params)`
+    ///        Where:
+    ///          `buffer` is the body of the generated function
+    ///          `params` is the name of all the generated function parameters
+    /// @returns true if the call expression is emitted
+    template <typename F>
+    bool CallBuiltinHelper(std::ostream& out,
+                           const ast::CallExpression* call,
+                           const sem::Builtin* builtin,
+                           F&& build);
 
-  TextBuffer helpers_;  // Helper functions emitted at the top of the output
+    TextBuffer helpers_;  // Helper functions emitted at the top of the output
 
-  /// @returns the MSL packed type size and alignment in bytes for the given
-  /// type.
-  SizeAndAlign MslPackedTypeSizeAndAlign(const sem::Type* ty);
+    /// @returns the MSL packed type size and alignment in bytes for the given
+    /// type.
+    SizeAndAlign MslPackedTypeSizeAndAlign(const sem::Type* ty);
 
-  using StorageClassToString =
-      std::unordered_map<ast::StorageClass, std::string>;
+    using StorageClassToString = std::unordered_map<ast::StorageClass, std::string>;
 
-  std::function<bool()> emit_continuing_;
+    std::function<bool()> emit_continuing_;
 
-  /// Name of atomicCompareExchangeWeak() helper for the given pointer storage
-  /// class.
-  StorageClassToString atomicCompareExchangeWeak_;
+    /// Name of atomicCompareExchangeWeak() helper for the given pointer storage
+    /// class.
+    StorageClassToString atomicCompareExchangeWeak_;
 
-  /// Unique name of the 'TINT_INVARIANT' preprocessor define. Non-empty only if
-  /// an invariant attribute has been generated.
-  std::string invariant_define_name_;
+    /// Unique name of the 'TINT_INVARIANT' preprocessor define. Non-empty only if
+    /// an invariant attribute has been generated.
+    std::string invariant_define_name_;
 
-  /// True if matrix-packed_vector operator overloads have been generated.
-  bool matrix_packed_vector_overloads_ = false;
+    /// True if matrix-packed_vector operator overloads have been generated.
+    bool matrix_packed_vector_overloads_ = false;
 
-  /// A map from entry point name to a list of dynamic workgroup allocations.
-  /// Each entry in the vector is the size of the workgroup allocation that
-  /// should be created for that index.
-  std::unordered_map<std::string, std::vector<uint32_t>> workgroup_allocations_;
+    /// A map from entry point name to a list of dynamic workgroup allocations.
+    /// Each entry in the vector is the size of the workgroup allocation that
+    /// should be created for that index.
+    std::unordered_map<std::string, std::vector<uint32_t>> workgroup_allocations_;
 
-  std::unordered_map<const sem::Builtin*, std::string> builtins_;
-  std::unordered_map<const sem::Type*, std::string> unary_minus_funcs_;
-  std::unordered_map<uint32_t, std::string> int_dot_funcs_;
+    std::unordered_map<const sem::Builtin*, std::string> builtins_;
+    std::unordered_map<const sem::Type*, std::string> unary_minus_funcs_;
+    std::unordered_map<uint32_t, std::string> int_dot_funcs_;
 };
 
 }  // namespace tint::writer::msl
diff --git a/src/tint/writer/msl/generator_impl_array_accessor_test.cc b/src/tint/writer/msl/generator_impl_array_accessor_test.cc
index d87469e..7475b67 100644
--- a/src/tint/writer/msl/generator_impl_array_accessor_test.cc
+++ b/src/tint/writer/msl/generator_impl_array_accessor_test.cc
@@ -14,35 +14,37 @@
 
 #include "src/tint/writer/msl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::msl {
 namespace {
 
 using MslGeneratorImplTest = TestHelper;
 
 TEST_F(MslGeneratorImplTest, IndexAccessor) {
-  auto* ary = Var("ary", ty.array<i32, 10>());
-  auto* expr = IndexAccessor("ary", 5);
-  WrapInFunction(ary, expr);
+    auto* ary = Var("ary", ty.array<i32, 10>());
+    auto* expr = IndexAccessor("ary", 5_i);
+    WrapInFunction(ary, expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), "ary[5]");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), "ary[5]");
 }
 
 TEST_F(MslGeneratorImplTest, IndexAccessor_OfDref) {
-  Global("ary", ty.array<i32, 10>(), ast::StorageClass::kPrivate);
+    Global("ary", ty.array<i32, 10>(), ast::StorageClass::kPrivate);
 
-  auto* p = Const("p", nullptr, AddressOf("ary"));
-  auto* expr = IndexAccessor(Deref("p"), 5);
-  WrapInFunction(p, expr);
+    auto* p = Let("p", nullptr, AddressOf("ary"));
+    auto* expr = IndexAccessor(Deref("p"), 5_i);
+    WrapInFunction(p, expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), "(*(p))[5]");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), "(*(p))[5]");
 }
 
 }  // namespace
diff --git a/src/tint/writer/msl/generator_impl_assign_test.cc b/src/tint/writer/msl/generator_impl_assign_test.cc
index d87a614..6423aae 100644
--- a/src/tint/writer/msl/generator_impl_assign_test.cc
+++ b/src/tint/writer/msl/generator_impl_assign_test.cc
@@ -20,17 +20,17 @@
 using MslGeneratorImplTest = TestHelper;
 
 TEST_F(MslGeneratorImplTest, Emit_Assign) {
-  auto* lhs = Var("lhs", ty.i32());
-  auto* rhs = Var("rhs", ty.i32());
-  auto* assign = Assign(lhs, rhs);
-  WrapInFunction(lhs, rhs, assign);
+    auto* lhs = Var("lhs", ty.i32());
+    auto* rhs = Var("rhs", ty.i32());
+    auto* assign = Assign(lhs, rhs);
+    WrapInFunction(lhs, rhs, assign);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(assign)) << gen.error();
-  EXPECT_EQ(gen.result(), "  lhs = rhs;\n");
+    ASSERT_TRUE(gen.EmitStatement(assign)) << gen.error();
+    EXPECT_EQ(gen.result(), "  lhs = rhs;\n");
 }
 
 }  // namespace
diff --git a/src/tint/writer/msl/generator_impl_binary_test.cc b/src/tint/writer/msl/generator_impl_binary_test.cc
index 796f1de..5262b97 100644
--- a/src/tint/writer/msl/generator_impl_binary_test.cc
+++ b/src/tint/writer/msl/generator_impl_binary_test.cc
@@ -18,82 +18,79 @@
 namespace {
 
 struct BinaryData {
-  const char* result;
-  ast::BinaryOp op;
+    const char* result;
+    ast::BinaryOp op;
 };
 inline std::ostream& operator<<(std::ostream& out, BinaryData data) {
-  out << data.op;
-  return out;
+    out << data.op;
+    return out;
 }
 using MslBinaryTest = TestParamHelper<BinaryData>;
 TEST_P(MslBinaryTest, Emit) {
-  auto params = GetParam();
+    auto params = GetParam();
 
-  auto type = [&] {
-    return ((params.op == ast::BinaryOp::kLogicalAnd) ||
-            (params.op == ast::BinaryOp::kLogicalOr))
-               ? static_cast<const ast::Type*>(ty.bool_())
-               : static_cast<const ast::Type*>(ty.u32());
-  };
+    auto type = [&] {
+        return ((params.op == ast::BinaryOp::kLogicalAnd) ||
+                (params.op == ast::BinaryOp::kLogicalOr))
+                   ? static_cast<const ast::Type*>(ty.bool_())
+                   : static_cast<const ast::Type*>(ty.u32());
+    };
 
-  auto* left = Var("left", type());
-  auto* right = Var("right", type());
+    auto* left = Var("left", type());
+    auto* right = Var("right", type());
 
-  auto* expr =
-      create<ast::BinaryExpression>(params.op, Expr(left), Expr(right));
-  WrapInFunction(left, right, expr);
+    auto* expr = create<ast::BinaryExpression>(params.op, Expr(left), Expr(right));
+    WrapInFunction(left, right, expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), params.result);
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), params.result);
 }
 INSTANTIATE_TEST_SUITE_P(
     MslGeneratorImplTest,
     MslBinaryTest,
-    testing::Values(
-        BinaryData{"(left & right)", ast::BinaryOp::kAnd},
-        BinaryData{"(left | right)", ast::BinaryOp::kOr},
-        BinaryData{"(left ^ right)", ast::BinaryOp::kXor},
-        BinaryData{"(left && right)", ast::BinaryOp::kLogicalAnd},
-        BinaryData{"(left || right)", ast::BinaryOp::kLogicalOr},
-        BinaryData{"(left == right)", ast::BinaryOp::kEqual},
-        BinaryData{"(left != right)", ast::BinaryOp::kNotEqual},
-        BinaryData{"(left < right)", ast::BinaryOp::kLessThan},
-        BinaryData{"(left > right)", ast::BinaryOp::kGreaterThan},
-        BinaryData{"(left <= right)", ast::BinaryOp::kLessThanEqual},
-        BinaryData{"(left >= right)", ast::BinaryOp::kGreaterThanEqual},
-        BinaryData{"(left << right)", ast::BinaryOp::kShiftLeft},
-        BinaryData{"(left >> right)", ast::BinaryOp::kShiftRight},
-        BinaryData{"(left + right)", ast::BinaryOp::kAdd},
-        BinaryData{"(left - right)", ast::BinaryOp::kSubtract},
-        BinaryData{"(left * right)", ast::BinaryOp::kMultiply},
-        BinaryData{"(left / right)", ast::BinaryOp::kDivide},
-        BinaryData{"(left % right)", ast::BinaryOp::kModulo}));
+    testing::Values(BinaryData{"(left & right)", ast::BinaryOp::kAnd},
+                    BinaryData{"(left | right)", ast::BinaryOp::kOr},
+                    BinaryData{"(left ^ right)", ast::BinaryOp::kXor},
+                    BinaryData{"(left && right)", ast::BinaryOp::kLogicalAnd},
+                    BinaryData{"(left || right)", ast::BinaryOp::kLogicalOr},
+                    BinaryData{"(left == right)", ast::BinaryOp::kEqual},
+                    BinaryData{"(left != right)", ast::BinaryOp::kNotEqual},
+                    BinaryData{"(left < right)", ast::BinaryOp::kLessThan},
+                    BinaryData{"(left > right)", ast::BinaryOp::kGreaterThan},
+                    BinaryData{"(left <= right)", ast::BinaryOp::kLessThanEqual},
+                    BinaryData{"(left >= right)", ast::BinaryOp::kGreaterThanEqual},
+                    BinaryData{"(left << right)", ast::BinaryOp::kShiftLeft},
+                    BinaryData{"(left >> right)", ast::BinaryOp::kShiftRight},
+                    BinaryData{"(left + right)", ast::BinaryOp::kAdd},
+                    BinaryData{"(left - right)", ast::BinaryOp::kSubtract},
+                    BinaryData{"(left * right)", ast::BinaryOp::kMultiply},
+                    BinaryData{"(left / right)", ast::BinaryOp::kDivide},
+                    BinaryData{"(left % right)", ast::BinaryOp::kModulo}));
 
-using MslBinaryTest_SignedOverflowDefinedBehaviour =
-    TestParamHelper<BinaryData>;
+using MslBinaryTest_SignedOverflowDefinedBehaviour = TestParamHelper<BinaryData>;
 TEST_P(MslBinaryTest_SignedOverflowDefinedBehaviour, Emit) {
-  auto params = GetParam();
+    auto params = GetParam();
 
-  auto* a_type = ty.i32();
-  auto* b_type = (params.op == ast::BinaryOp::kShiftLeft ||
-                  params.op == ast::BinaryOp::kShiftRight)
-                     ? static_cast<const ast::Type*>(ty.u32())
-                     : ty.i32();
+    auto* a_type = ty.i32();
+    auto* b_type =
+        (params.op == ast::BinaryOp::kShiftLeft || params.op == ast::BinaryOp::kShiftRight)
+            ? static_cast<const ast::Type*>(ty.u32())
+            : ty.i32();
 
-  auto* a = Var("a", a_type);
-  auto* b = Var("b", b_type);
+    auto* a = Var("a", a_type);
+    auto* b = Var("b", b_type);
 
-  auto* expr = create<ast::BinaryExpression>(params.op, Expr(a), Expr(b));
-  WrapInFunction(a, b, expr);
+    auto* expr = create<ast::BinaryExpression>(params.op, Expr(a), Expr(b));
+    WrapInFunction(a, b, expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), params.result);
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), params.result);
 }
 using Op = ast::BinaryOp;
 constexpr BinaryData signed_overflow_defined_behaviour_cases[] = {
@@ -102,34 +99,32 @@
     {"as_type<int>((as_type<uint>(a) + as_type<uint>(b)))", Op::kAdd},
     {"as_type<int>((as_type<uint>(a) - as_type<uint>(b)))", Op::kSubtract},
     {"as_type<int>((as_type<uint>(a) * as_type<uint>(b)))", Op::kMultiply}};
-INSTANTIATE_TEST_SUITE_P(
-    MslGeneratorImplTest,
-    MslBinaryTest_SignedOverflowDefinedBehaviour,
-    testing::ValuesIn(signed_overflow_defined_behaviour_cases));
+INSTANTIATE_TEST_SUITE_P(MslGeneratorImplTest,
+                         MslBinaryTest_SignedOverflowDefinedBehaviour,
+                         testing::ValuesIn(signed_overflow_defined_behaviour_cases));
 
-using MslBinaryTest_SignedOverflowDefinedBehaviour_Chained =
-    TestParamHelper<BinaryData>;
+using MslBinaryTest_SignedOverflowDefinedBehaviour_Chained = TestParamHelper<BinaryData>;
 TEST_P(MslBinaryTest_SignedOverflowDefinedBehaviour_Chained, Emit) {
-  auto params = GetParam();
+    auto params = GetParam();
 
-  auto* a_type = ty.i32();
-  auto* b_type = (params.op == ast::BinaryOp::kShiftLeft ||
-                  params.op == ast::BinaryOp::kShiftRight)
-                     ? static_cast<const ast::Type*>(ty.u32())
-                     : ty.i32();
+    auto* a_type = ty.i32();
+    auto* b_type =
+        (params.op == ast::BinaryOp::kShiftLeft || params.op == ast::BinaryOp::kShiftRight)
+            ? static_cast<const ast::Type*>(ty.u32())
+            : ty.i32();
 
-  auto* a = Var("a", a_type);
-  auto* b = Var("b", b_type);
+    auto* a = Var("a", a_type);
+    auto* b = Var("b", b_type);
 
-  auto* expr1 = create<ast::BinaryExpression>(params.op, Expr(a), Expr(b));
-  auto* expr2 = create<ast::BinaryExpression>(params.op, expr1, Expr(b));
-  WrapInFunction(a, b, expr2);
+    auto* expr1 = create<ast::BinaryExpression>(params.op, Expr(a), Expr(b));
+    auto* expr2 = create<ast::BinaryExpression>(params.op, expr1, Expr(b));
+    WrapInFunction(a, b, expr2);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, expr2)) << gen.error();
-  EXPECT_EQ(out.str(), params.result);
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, expr2)) << gen.error();
+    EXPECT_EQ(out.str(), params.result);
 }
 using Op = ast::BinaryOp;
 constexpr BinaryData signed_overflow_defined_behaviour_chained_cases[] = {
@@ -146,37 +141,34 @@
     {"as_type<int>((as_type<uint>(as_type<int>((as_type<uint>(a) * "
      "as_type<uint>(b)))) * as_type<uint>(b)))",
      Op::kMultiply}};
-INSTANTIATE_TEST_SUITE_P(
-    MslGeneratorImplTest,
-    MslBinaryTest_SignedOverflowDefinedBehaviour_Chained,
-    testing::ValuesIn(signed_overflow_defined_behaviour_chained_cases));
+INSTANTIATE_TEST_SUITE_P(MslGeneratorImplTest,
+                         MslBinaryTest_SignedOverflowDefinedBehaviour_Chained,
+                         testing::ValuesIn(signed_overflow_defined_behaviour_chained_cases));
 
 TEST_F(MslBinaryTest, ModF32) {
-  auto* left = Var("left", ty.f32());
-  auto* right = Var("right", ty.f32());
-  auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kModulo, Expr(left),
-                                             Expr(right));
-  WrapInFunction(left, right, expr);
+    auto* left = Var("left", ty.f32());
+    auto* right = Var("right", ty.f32());
+    auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kModulo, Expr(left), Expr(right));
+    WrapInFunction(left, right, expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), "fmod(left, right)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), "fmod(left, right)");
 }
 
 TEST_F(MslBinaryTest, ModVec3F32) {
-  auto* left = Var("left", ty.vec3<f32>());
-  auto* right = Var("right", ty.vec3<f32>());
-  auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kModulo, Expr(left),
-                                             Expr(right));
-  WrapInFunction(left, right, expr);
+    auto* left = Var("left", ty.vec3<f32>());
+    auto* right = Var("right", ty.vec3<f32>());
+    auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kModulo, Expr(left), Expr(right));
+    WrapInFunction(left, right, expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), "fmod(left, right)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), "fmod(left, right)");
 }
 
 }  // namespace
diff --git a/src/tint/writer/msl/generator_impl_bitcast_test.cc b/src/tint/writer/msl/generator_impl_bitcast_test.cc
index fe51305..c398558 100644
--- a/src/tint/writer/msl/generator_impl_bitcast_test.cc
+++ b/src/tint/writer/msl/generator_impl_bitcast_test.cc
@@ -14,20 +14,22 @@
 
 #include "src/tint/writer/msl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::msl {
 namespace {
 
 using MslGeneratorImplTest = TestHelper;
 
 TEST_F(MslGeneratorImplTest, EmitExpression_Bitcast) {
-  auto* bitcast = create<ast::BitcastExpression>(ty.f32(), Expr(1));
-  WrapInFunction(bitcast);
+    auto* bitcast = create<ast::BitcastExpression>(ty.f32(), Expr(1_i));
+    WrapInFunction(bitcast);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, bitcast)) << gen.error();
-  EXPECT_EQ(out.str(), "as_type<float>(1)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, bitcast)) << gen.error();
+    EXPECT_EQ(out.str(), "as_type<float>(1)");
 }
 
 }  // namespace
diff --git a/src/tint/writer/msl/generator_impl_block_test.cc b/src/tint/writer/msl/generator_impl_block_test.cc
index ac6aa5a..9e73eac 100644
--- a/src/tint/writer/msl/generator_impl_block_test.cc
+++ b/src/tint/writer/msl/generator_impl_block_test.cc
@@ -20,30 +20,30 @@
 using MslGeneratorImplTest = TestHelper;
 
 TEST_F(MslGeneratorImplTest, Emit_Block) {
-  auto* b = Block(create<ast::DiscardStatement>());
-  WrapInFunction(b);
+    auto* b = Block(create<ast::DiscardStatement>());
+    WrapInFunction(b);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(b)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  {
+    ASSERT_TRUE(gen.EmitStatement(b)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  {
     discard_fragment();
   }
 )");
 }
 
 TEST_F(MslGeneratorImplTest, Emit_Block_WithoutNewline) {
-  auto* b = Block(create<ast::DiscardStatement>());
-  WrapInFunction(b);
+    auto* b = Block(create<ast::DiscardStatement>());
+    WrapInFunction(b);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitBlock(b)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  {
+    ASSERT_TRUE(gen.EmitBlock(b)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  {
     discard_fragment();
   }
 )");
diff --git a/src/tint/writer/msl/generator_impl_break_test.cc b/src/tint/writer/msl/generator_impl_break_test.cc
index 806188b..d9d1103 100644
--- a/src/tint/writer/msl/generator_impl_break_test.cc
+++ b/src/tint/writer/msl/generator_impl_break_test.cc
@@ -20,15 +20,15 @@
 using MslGeneratorImplTest = TestHelper;
 
 TEST_F(MslGeneratorImplTest, Emit_Break) {
-  auto* b = create<ast::BreakStatement>();
-  WrapInFunction(Loop(Block(b)));
+    auto* b = create<ast::BreakStatement>();
+    WrapInFunction(Loop(Block(b)));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(b)) << gen.error();
-  EXPECT_EQ(gen.result(), "  break;\n");
+    ASSERT_TRUE(gen.EmitStatement(b)) << gen.error();
+    EXPECT_EQ(gen.result(), "  break;\n");
 }
 
 }  // namespace
diff --git a/src/tint/writer/msl/generator_impl_builtin_test.cc b/src/tint/writer/msl/generator_impl_builtin_test.cc
index 09a98a7..752fc73 100644
--- a/src/tint/writer/msl/generator_impl_builtin_test.cc
+++ b/src/tint/writer/msl/generator_impl_builtin_test.cc
@@ -16,6 +16,8 @@
 #include "src/tint/sem/call.h"
 #include "src/tint/writer/msl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::msl {
 namespace {
 
@@ -24,177 +26,177 @@
 using MslGeneratorImplTest = TestHelper;
 
 enum class ParamType {
-  kF32,
-  kU32,
-  kBool,
+    kF32,
+    kU32,
+    kBool,
 };
 
 struct BuiltinData {
-  BuiltinType builtin;
-  ParamType type;
-  const char* msl_name;
+    BuiltinType builtin;
+    ParamType type;
+    const char* msl_name;
 };
 inline std::ostream& operator<<(std::ostream& out, BuiltinData data) {
-  out << data.msl_name << "<";
-  switch (data.type) {
-    case ParamType::kF32:
-      out << "f32";
-      break;
-    case ParamType::kU32:
-      out << "u32";
-      break;
-    case ParamType::kBool:
-      out << "bool";
-      break;
-  }
-  out << ">";
-  return out;
+    out << data.msl_name << "<";
+    switch (data.type) {
+        case ParamType::kF32:
+            out << "f32";
+            break;
+        case ParamType::kU32:
+            out << "u32";
+            break;
+        case ParamType::kBool:
+            out << "bool";
+            break;
+    }
+    out << ">";
+    return out;
 }
 
 const ast::CallExpression* GenerateCall(BuiltinType builtin,
                                         ParamType type,
                                         ProgramBuilder* builder) {
-  std::string name;
-  std::ostringstream str(name);
-  str << builtin;
-  switch (builtin) {
-    case BuiltinType::kAcos:
-    case BuiltinType::kAsin:
-    case BuiltinType::kAtan:
-    case BuiltinType::kCeil:
-    case BuiltinType::kCos:
-    case BuiltinType::kCosh:
-    case BuiltinType::kDpdx:
-    case BuiltinType::kDpdxCoarse:
-    case BuiltinType::kDpdxFine:
-    case BuiltinType::kDpdy:
-    case BuiltinType::kDpdyCoarse:
-    case BuiltinType::kDpdyFine:
-    case BuiltinType::kExp:
-    case BuiltinType::kExp2:
-    case BuiltinType::kFloor:
-    case BuiltinType::kFract:
-    case BuiltinType::kFwidth:
-    case BuiltinType::kFwidthCoarse:
-    case BuiltinType::kFwidthFine:
-    case BuiltinType::kInverseSqrt:
-    case BuiltinType::kLength:
-    case BuiltinType::kLog:
-    case BuiltinType::kLog2:
-    case BuiltinType::kNormalize:
-    case BuiltinType::kRound:
-    case BuiltinType::kSin:
-    case BuiltinType::kSinh:
-    case BuiltinType::kSqrt:
-    case BuiltinType::kTan:
-    case BuiltinType::kTanh:
-    case BuiltinType::kTrunc:
-    case BuiltinType::kSign:
-      return builder->Call(str.str(), "f2");
-    case BuiltinType::kLdexp:
-      return builder->Call(str.str(), "f2", "i2");
-    case BuiltinType::kAtan2:
-    case BuiltinType::kDot:
-    case BuiltinType::kDistance:
-    case BuiltinType::kPow:
-    case BuiltinType::kReflect:
-    case BuiltinType::kStep:
-      return builder->Call(str.str(), "f2", "f2");
-    case BuiltinType::kStorageBarrier:
-      return builder->Call(str.str());
-    case BuiltinType::kCross:
-      return builder->Call(str.str(), "f3", "f3");
-    case BuiltinType::kFma:
-    case BuiltinType::kMix:
-    case BuiltinType::kFaceForward:
-    case BuiltinType::kSmoothstep:
-    case BuiltinType::kSmoothStep:
-      return builder->Call(str.str(), "f2", "f2", "f2");
-    case BuiltinType::kAll:
-    case BuiltinType::kAny:
-      return builder->Call(str.str(), "b2");
-    case BuiltinType::kAbs:
-      if (type == ParamType::kF32) {
-        return builder->Call(str.str(), "f2");
-      } else {
-        return builder->Call(str.str(), "u2");
-      }
-    case BuiltinType::kCountLeadingZeros:
-    case BuiltinType::kCountOneBits:
-    case BuiltinType::kCountTrailingZeros:
-    case BuiltinType::kReverseBits:
-      return builder->Call(str.str(), "u2");
-    case BuiltinType::kExtractBits:
-      return builder->Call(str.str(), "u2", "u1", "u1");
-    case BuiltinType::kInsertBits:
-      return builder->Call(str.str(), "u2", "u2", "u1", "u1");
-    case BuiltinType::kMax:
-    case BuiltinType::kMin:
-      if (type == ParamType::kF32) {
-        return builder->Call(str.str(), "f2", "f2");
-      } else {
-        return builder->Call(str.str(), "u2", "u2");
-      }
-    case BuiltinType::kClamp:
-      if (type == ParamType::kF32) {
-        return builder->Call(str.str(), "f2", "f2", "f2");
-      } else {
-        return builder->Call(str.str(), "u2", "u2", "u2");
-      }
-    case BuiltinType::kSelect:
-      return builder->Call(str.str(), "f2", "f2", "b2");
-    case BuiltinType::kDeterminant:
-      return builder->Call(str.str(), "m2x2");
-    case BuiltinType::kPack2x16snorm:
-    case BuiltinType::kPack2x16unorm:
-      return builder->Call(str.str(), "f2");
-    case BuiltinType::kPack4x8snorm:
-    case BuiltinType::kPack4x8unorm:
-      return builder->Call(str.str(), "f4");
-    case BuiltinType::kUnpack4x8snorm:
-    case BuiltinType::kUnpack4x8unorm:
-    case BuiltinType::kUnpack2x16snorm:
-    case BuiltinType::kUnpack2x16unorm:
-      return builder->Call(str.str(), "u1");
-    case BuiltinType::kWorkgroupBarrier:
-      return builder->Call(str.str());
-    case BuiltinType::kTranspose:
-      return builder->Call(str.str(), "m3x2");
-    default:
-      break;
-  }
-  return nullptr;
+    std::string name;
+    std::ostringstream str(name);
+    str << builtin;
+    switch (builtin) {
+        case BuiltinType::kAcos:
+        case BuiltinType::kAsin:
+        case BuiltinType::kAtan:
+        case BuiltinType::kCeil:
+        case BuiltinType::kCos:
+        case BuiltinType::kCosh:
+        case BuiltinType::kDpdx:
+        case BuiltinType::kDpdxCoarse:
+        case BuiltinType::kDpdxFine:
+        case BuiltinType::kDpdy:
+        case BuiltinType::kDpdyCoarse:
+        case BuiltinType::kDpdyFine:
+        case BuiltinType::kExp:
+        case BuiltinType::kExp2:
+        case BuiltinType::kFloor:
+        case BuiltinType::kFract:
+        case BuiltinType::kFwidth:
+        case BuiltinType::kFwidthCoarse:
+        case BuiltinType::kFwidthFine:
+        case BuiltinType::kInverseSqrt:
+        case BuiltinType::kLength:
+        case BuiltinType::kLog:
+        case BuiltinType::kLog2:
+        case BuiltinType::kNormalize:
+        case BuiltinType::kRound:
+        case BuiltinType::kSin:
+        case BuiltinType::kSinh:
+        case BuiltinType::kSqrt:
+        case BuiltinType::kTan:
+        case BuiltinType::kTanh:
+        case BuiltinType::kTrunc:
+        case BuiltinType::kSign:
+            return builder->Call(str.str(), "f2");
+        case BuiltinType::kLdexp:
+            return builder->Call(str.str(), "f2", "i2");
+        case BuiltinType::kAtan2:
+        case BuiltinType::kDot:
+        case BuiltinType::kDistance:
+        case BuiltinType::kPow:
+        case BuiltinType::kReflect:
+        case BuiltinType::kStep:
+            return builder->Call(str.str(), "f2", "f2");
+        case BuiltinType::kStorageBarrier:
+            return builder->Call(str.str());
+        case BuiltinType::kCross:
+            return builder->Call(str.str(), "f3", "f3");
+        case BuiltinType::kFma:
+        case BuiltinType::kMix:
+        case BuiltinType::kFaceForward:
+        case BuiltinType::kSmoothstep:
+        case BuiltinType::kSmoothStep:
+            return builder->Call(str.str(), "f2", "f2", "f2");
+        case BuiltinType::kAll:
+        case BuiltinType::kAny:
+            return builder->Call(str.str(), "b2");
+        case BuiltinType::kAbs:
+            if (type == ParamType::kF32) {
+                return builder->Call(str.str(), "f2");
+            } else {
+                return builder->Call(str.str(), "u2");
+            }
+        case BuiltinType::kCountLeadingZeros:
+        case BuiltinType::kCountOneBits:
+        case BuiltinType::kCountTrailingZeros:
+        case BuiltinType::kReverseBits:
+            return builder->Call(str.str(), "u2");
+        case BuiltinType::kExtractBits:
+            return builder->Call(str.str(), "u2", "u1", "u1");
+        case BuiltinType::kInsertBits:
+            return builder->Call(str.str(), "u2", "u2", "u1", "u1");
+        case BuiltinType::kMax:
+        case BuiltinType::kMin:
+            if (type == ParamType::kF32) {
+                return builder->Call(str.str(), "f2", "f2");
+            } else {
+                return builder->Call(str.str(), "u2", "u2");
+            }
+        case BuiltinType::kClamp:
+            if (type == ParamType::kF32) {
+                return builder->Call(str.str(), "f2", "f2", "f2");
+            } else {
+                return builder->Call(str.str(), "u2", "u2", "u2");
+            }
+        case BuiltinType::kSelect:
+            return builder->Call(str.str(), "f2", "f2", "b2");
+        case BuiltinType::kDeterminant:
+            return builder->Call(str.str(), "m2x2");
+        case BuiltinType::kPack2x16snorm:
+        case BuiltinType::kPack2x16unorm:
+            return builder->Call(str.str(), "f2");
+        case BuiltinType::kPack4x8snorm:
+        case BuiltinType::kPack4x8unorm:
+            return builder->Call(str.str(), "f4");
+        case BuiltinType::kUnpack4x8snorm:
+        case BuiltinType::kUnpack4x8unorm:
+        case BuiltinType::kUnpack2x16snorm:
+        case BuiltinType::kUnpack2x16unorm:
+            return builder->Call(str.str(), "u1");
+        case BuiltinType::kWorkgroupBarrier:
+            return builder->Call(str.str());
+        case BuiltinType::kTranspose:
+            return builder->Call(str.str(), "m3x2");
+        default:
+            break;
+    }
+    return nullptr;
 }
 
 using MslBuiltinTest = TestParamHelper<BuiltinData>;
 TEST_P(MslBuiltinTest, Emit) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  Global("f2", ty.vec2<f32>(), ast::StorageClass::kPrivate);
-  Global("f3", ty.vec3<f32>(), ast::StorageClass::kPrivate);
-  Global("f4", ty.vec4<f32>(), ast::StorageClass::kPrivate);
-  Global("u1", ty.u32(), ast::StorageClass::kPrivate);
-  Global("u2", ty.vec2<u32>(), ast::StorageClass::kPrivate);
-  Global("i2", ty.vec2<i32>(), ast::StorageClass::kPrivate);
-  Global("b2", ty.vec2<bool>(), ast::StorageClass::kPrivate);
-  Global("m2x2", ty.mat2x2<f32>(), ast::StorageClass::kPrivate);
-  Global("m3x2", ty.mat3x2<f32>(), ast::StorageClass::kPrivate);
+    Global("f2", ty.vec2<f32>(), ast::StorageClass::kPrivate);
+    Global("f3", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+    Global("f4", ty.vec4<f32>(), ast::StorageClass::kPrivate);
+    Global("u1", ty.u32(), ast::StorageClass::kPrivate);
+    Global("u2", ty.vec2<u32>(), ast::StorageClass::kPrivate);
+    Global("i2", ty.vec2<i32>(), ast::StorageClass::kPrivate);
+    Global("b2", ty.vec2<bool>(), ast::StorageClass::kPrivate);
+    Global("m2x2", ty.mat2x2<f32>(), ast::StorageClass::kPrivate);
+    Global("m3x2", ty.mat3x2<f32>(), ast::StorageClass::kPrivate);
 
-  auto* call = GenerateCall(param.builtin, param.type, this);
-  ASSERT_NE(nullptr, call) << "Unhandled builtin";
-  Func("func", {}, ty.void_(), {Ignore(call)},
-       {create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
+    auto* call = GenerateCall(param.builtin, param.type, this);
+    ASSERT_NE(nullptr, call) << "Unhandled builtin";
+    Func("func", {}, ty.void_(), {Ignore(call)},
+         {create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  auto* sem = program->Sem().Get(call);
-  ASSERT_NE(sem, nullptr);
-  auto* target = sem->Target();
-  ASSERT_NE(target, nullptr);
-  auto* builtin = target->As<sem::Builtin>();
-  ASSERT_NE(builtin, nullptr);
+    auto* sem = program->Sem().Get(call);
+    ASSERT_NE(sem, nullptr);
+    auto* target = sem->Target();
+    ASSERT_NE(target, nullptr);
+    auto* builtin = target->As<sem::Builtin>();
+    ASSERT_NE(builtin, nullptr);
 
-  EXPECT_EQ(gen.generate_builtin_name(builtin), param.msl_name);
+    EXPECT_EQ(gen.generate_builtin_name(builtin), param.msl_name);
 }
 INSTANTIATE_TEST_SUITE_P(
     MslGeneratorImplTest,
@@ -247,14 +249,10 @@
         BuiltinData{BuiltinType::kMin, ParamType::kF32, "fmin"},
         BuiltinData{BuiltinType::kMin, ParamType::kU32, "min"},
         BuiltinData{BuiltinType::kNormalize, ParamType::kF32, "normalize"},
-        BuiltinData{BuiltinType::kPack4x8snorm, ParamType::kF32,
-                    "pack_float_to_snorm4x8"},
-        BuiltinData{BuiltinType::kPack4x8unorm, ParamType::kF32,
-                    "pack_float_to_unorm4x8"},
-        BuiltinData{BuiltinType::kPack2x16snorm, ParamType::kF32,
-                    "pack_float_to_snorm2x16"},
-        BuiltinData{BuiltinType::kPack2x16unorm, ParamType::kF32,
-                    "pack_float_to_unorm2x16"},
+        BuiltinData{BuiltinType::kPack4x8snorm, ParamType::kF32, "pack_float_to_snorm4x8"},
+        BuiltinData{BuiltinType::kPack4x8unorm, ParamType::kF32, "pack_float_to_unorm4x8"},
+        BuiltinData{BuiltinType::kPack2x16snorm, ParamType::kF32, "pack_float_to_snorm2x16"},
+        BuiltinData{BuiltinType::kPack2x16unorm, ParamType::kF32, "pack_float_to_unorm2x16"},
         BuiltinData{BuiltinType::kPow, ParamType::kF32, "pow"},
         BuiltinData{BuiltinType::kReflect, ParamType::kF32, "reflect"},
         BuiltinData{BuiltinType::kReverseBits, ParamType::kU32, "reverse_bits"},
@@ -271,60 +269,56 @@
         BuiltinData{BuiltinType::kTanh, ParamType::kF32, "tanh"},
         BuiltinData{BuiltinType::kTranspose, ParamType::kF32, "transpose"},
         BuiltinData{BuiltinType::kTrunc, ParamType::kF32, "trunc"},
-        BuiltinData{BuiltinType::kUnpack4x8snorm, ParamType::kU32,
-                    "unpack_snorm4x8_to_float"},
-        BuiltinData{BuiltinType::kUnpack4x8unorm, ParamType::kU32,
-                    "unpack_unorm4x8_to_float"},
-        BuiltinData{BuiltinType::kUnpack2x16snorm, ParamType::kU32,
-                    "unpack_snorm2x16_to_float"},
-        BuiltinData{BuiltinType::kUnpack2x16unorm, ParamType::kU32,
-                    "unpack_unorm2x16_to_float"}));
+        BuiltinData{BuiltinType::kUnpack4x8snorm, ParamType::kU32, "unpack_snorm4x8_to_float"},
+        BuiltinData{BuiltinType::kUnpack4x8unorm, ParamType::kU32, "unpack_unorm4x8_to_float"},
+        BuiltinData{BuiltinType::kUnpack2x16snorm, ParamType::kU32, "unpack_snorm2x16_to_float"},
+        BuiltinData{BuiltinType::kUnpack2x16unorm, ParamType::kU32, "unpack_unorm2x16_to_float"}));
 
 TEST_F(MslGeneratorImplTest, Builtin_Call) {
-  Global("param1", ty.vec2<f32>(), ast::StorageClass::kPrivate);
-  Global("param2", ty.vec2<f32>(), ast::StorageClass::kPrivate);
+    Global("param1", ty.vec2<f32>(), ast::StorageClass::kPrivate);
+    Global("param2", ty.vec2<f32>(), ast::StorageClass::kPrivate);
 
-  auto* call = Call("dot", "param1", "param2");
-  WrapInFunction(CallStmt(call));
+    auto* call = Call("dot", "param1", "param2");
+    WrapInFunction(CallStmt(call));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
-  EXPECT_EQ(out.str(), "dot(param1, param2)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
+    EXPECT_EQ(out.str(), "dot(param1, param2)");
 }
 
 TEST_F(MslGeneratorImplTest, StorageBarrier) {
-  auto* call = Call("storageBarrier");
-  WrapInFunction(CallStmt(call));
+    auto* call = Call("storageBarrier");
+    WrapInFunction(CallStmt(call));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
-  EXPECT_EQ(out.str(), "threadgroup_barrier(mem_flags::mem_device)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
+    EXPECT_EQ(out.str(), "threadgroup_barrier(mem_flags::mem_device)");
 }
 
 TEST_F(MslGeneratorImplTest, WorkgroupBarrier) {
-  auto* call = Call("workgroupBarrier");
-  WrapInFunction(CallStmt(call));
+    auto* call = Call("workgroupBarrier");
+    WrapInFunction(CallStmt(call));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
-  EXPECT_EQ(out.str(), "threadgroup_barrier(mem_flags::mem_threadgroup)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
+    EXPECT_EQ(out.str(), "threadgroup_barrier(mem_flags::mem_threadgroup)");
 }
 
 TEST_F(MslGeneratorImplTest, Degrees_Scalar) {
-  auto* val = Var("val", ty.f32());
-  auto* call = Call("degrees", val);
-  WrapInFunction(val, call);
+    auto* val = Var("val", ty.f32());
+    auto* call = Call("degrees", val);
+    WrapInFunction(val, call);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
 
 using namespace metal;
 
@@ -342,14 +336,14 @@
 }
 
 TEST_F(MslGeneratorImplTest, Degrees_Vector) {
-  auto* val = Var("val", ty.vec3<f32>());
-  auto* call = Call("degrees", val);
-  WrapInFunction(val, call);
+    auto* val = Var("val", ty.vec3<f32>());
+    auto* call = Call("degrees", val);
+    WrapInFunction(val, call);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
 
 using namespace metal;
 
@@ -367,14 +361,14 @@
 }
 
 TEST_F(MslGeneratorImplTest, Radians_Scalar) {
-  auto* val = Var("val", ty.f32());
-  auto* call = Call("radians", val);
-  WrapInFunction(val, call);
+    auto* val = Var("val", ty.f32());
+    auto* call = Call("radians", val);
+    WrapInFunction(val, call);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
 
 using namespace metal;
 
@@ -392,14 +386,14 @@
 }
 
 TEST_F(MslGeneratorImplTest, Radians_Vector) {
-  auto* val = Var("val", ty.vec3<f32>());
-  auto* call = Call("radians", val);
-  WrapInFunction(val, call);
+    auto* val = Var("val", ty.vec3<f32>());
+    auto* call = Call("radians", val);
+    WrapInFunction(val, call);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
 
 using namespace metal;
 
@@ -417,37 +411,37 @@
 }
 
 TEST_F(MslGeneratorImplTest, Pack2x16Float) {
-  auto* call = Call("pack2x16float", "p1");
-  Global("p1", ty.vec2<f32>(), ast::StorageClass::kPrivate);
-  WrapInFunction(CallStmt(call));
+    auto* call = Call("pack2x16float", "p1");
+    Global("p1", ty.vec2<f32>(), ast::StorageClass::kPrivate);
+    WrapInFunction(CallStmt(call));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
-  EXPECT_EQ(out.str(), "as_type<uint>(half2(p1))");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
+    EXPECT_EQ(out.str(), "as_type<uint>(half2(p1))");
 }
 
 TEST_F(MslGeneratorImplTest, Unpack2x16Float) {
-  auto* call = Call("unpack2x16float", "p1");
-  Global("p1", ty.u32(), ast::StorageClass::kPrivate);
-  WrapInFunction(CallStmt(call));
+    auto* call = Call("unpack2x16float", "p1");
+    Global("p1", ty.u32(), ast::StorageClass::kPrivate);
+    WrapInFunction(CallStmt(call));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
-  EXPECT_EQ(out.str(), "float2(as_type<half2>(p1))");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
+    EXPECT_EQ(out.str(), "float2(as_type<half2>(p1))");
 }
 
 TEST_F(MslGeneratorImplTest, DotI32) {
-  Global("v", ty.vec3<i32>(), ast::StorageClass::kPrivate);
-  WrapInFunction(CallStmt(Call("dot", "v", "v")));
+    Global("v", ty.vec3<i32>(), ast::StorageClass::kPrivate);
+    WrapInFunction(CallStmt(Call("dot", "v", "v")));
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
 
 using namespace metal;
 
@@ -465,19 +459,19 @@
 }
 
 TEST_F(MslGeneratorImplTest, Ignore) {
-  Func("f", {Param("a", ty.i32()), Param("b", ty.i32()), Param("c", ty.i32())},
-       ty.i32(), {Return(Mul(Add("a", "b"), "c"))});
+    Func("f", {Param("a", ty.i32()), Param("b", ty.i32()), Param("c", ty.i32())}, ty.i32(),
+         {Return(Mul(Add("a", "b"), "c"))});
 
-  Func("func", {}, ty.void_(), {CallStmt(Call("f", 1, 2, 3))},
-       {
-           Stage(ast::PipelineStage::kCompute),
-           WorkgroupSize(1),
-       });
+    Func("func", {}, ty.void_(), {CallStmt(Call("f", 1_i, 2_i, 3_i))},
+         {
+             Stage(ast::PipelineStage::kCompute),
+             WorkgroupSize(1_i),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
 
 using namespace metal;
 int f(int a, int b, int c) {
diff --git a/src/tint/writer/msl/generator_impl_builtin_texture_test.cc b/src/tint/writer/msl/generator_impl_builtin_texture_test.cc
index 4760526..a78a255 100644
--- a/src/tint/writer/msl/generator_impl_builtin_texture_test.cc
+++ b/src/tint/writer/msl/generator_impl_builtin_texture_test.cc
@@ -19,283 +19,281 @@
 namespace tint::writer::msl {
 namespace {
 
-std::string expected_texture_overload(
-    ast::builtin::test::ValidTextureOverload overload) {
-  using ValidTextureOverload = ast::builtin::test::ValidTextureOverload;
-  switch (overload) {
-    case ValidTextureOverload::kDimensions1d:
-    case ValidTextureOverload::kDimensionsStorageWO1d:
-      return R"(int(texture.get_width(0)))";
-    case ValidTextureOverload::kDimensions2d:
-    case ValidTextureOverload::kDimensions2dArray:
-    case ValidTextureOverload::kDimensionsCube:
-    case ValidTextureOverload::kDimensionsCubeArray:
-    case ValidTextureOverload::kDimensionsMultisampled2d:
-    case ValidTextureOverload::kDimensionsDepth2d:
-    case ValidTextureOverload::kDimensionsDepth2dArray:
-    case ValidTextureOverload::kDimensionsDepthCube:
-    case ValidTextureOverload::kDimensionsDepthCubeArray:
-    case ValidTextureOverload::kDimensionsDepthMultisampled2d:
-    case ValidTextureOverload::kDimensionsStorageWO2d:
-    case ValidTextureOverload::kDimensionsStorageWO2dArray:
-      return R"(int2(texture.get_width(), texture.get_height()))";
-    case ValidTextureOverload::kDimensions3d:
-    case ValidTextureOverload::kDimensionsStorageWO3d:
-      return R"(int3(texture.get_width(), texture.get_height(), texture.get_depth()))";
-    case ValidTextureOverload::kDimensions2dLevel:
-    case ValidTextureOverload::kDimensionsCubeLevel:
-    case ValidTextureOverload::kDimensionsCubeArrayLevel:
-    case ValidTextureOverload::kDimensions2dArrayLevel:
-    case ValidTextureOverload::kDimensionsDepth2dLevel:
-    case ValidTextureOverload::kDimensionsDepth2dArrayLevel:
-    case ValidTextureOverload::kDimensionsDepthCubeLevel:
-    case ValidTextureOverload::kDimensionsDepthCubeArrayLevel:
-      return R"(int2(texture.get_width(1), texture.get_height(1)))";
-    case ValidTextureOverload::kDimensions3dLevel:
-      return R"(int3(texture.get_width(1), texture.get_height(1), texture.get_depth(1)))";
-    case ValidTextureOverload::kGather2dF32:
-      return R"(texture.gather(sampler, float2(1.0f, 2.0f), int2(0), component::x))";
-    case ValidTextureOverload::kGather2dOffsetF32:
-      return R"(texture.gather(sampler, float2(1.0f, 2.0f), int2(3, 4), component::x))";
-    case ValidTextureOverload::kGather2dArrayF32:
-      return R"(texture.gather(sampler, float2(1.0f, 2.0f), 3, int2(0), component::x))";
-    case ValidTextureOverload::kGather2dArrayOffsetF32:
-      return R"(texture.gather(sampler, float2(1.0f, 2.0f), 3, int2(4, 5), component::x))";
-    case ValidTextureOverload::kGatherCubeF32:
-      return R"(texture.gather(sampler, float3(1.0f, 2.0f, 3.0f), component::x))";
-    case ValidTextureOverload::kGatherCubeArrayF32:
-      return R"(texture.gather(sampler, float3(1.0f, 2.0f, 3.0f), 4, component::x))";
-    case ValidTextureOverload::kGatherDepth2dF32:
-      return R"(texture.gather(sampler, float2(1.0f, 2.0f)))";
-    case ValidTextureOverload::kGatherDepth2dOffsetF32:
-      return R"(texture.gather(sampler, float2(1.0f, 2.0f), int2(3, 4)))";
-    case ValidTextureOverload::kGatherDepth2dArrayF32:
-      return R"(texture.gather(sampler, float2(1.0f, 2.0f), 3))";
-    case ValidTextureOverload::kGatherDepth2dArrayOffsetF32:
-      return R"(texture.gather(sampler, float2(1.0f, 2.0f), 3, int2(4, 5)))";
-    case ValidTextureOverload::kGatherDepthCubeF32:
-      return R"(texture.gather(sampler, float3(1.0f, 2.0f, 3.0f)))";
-    case ValidTextureOverload::kGatherDepthCubeArrayF32:
-      return R"(texture.gather(sampler, float3(1.0f, 2.0f, 3.0f), 4))";
-    case ValidTextureOverload::kGatherCompareDepth2dF32:
-      return R"(texture.gather_compare(sampler, float2(1.0f, 2.0f), 3.0f))";
-    case ValidTextureOverload::kGatherCompareDepth2dOffsetF32:
-      return R"(texture.gather_compare(sampler, float2(1.0f, 2.0f), 3.0f, int2(4, 5)))";
-    case ValidTextureOverload::kGatherCompareDepth2dArrayF32:
-      return R"(texture.gather_compare(sampler, float2(1.0f, 2.0f), 3, 4.0f))";
-    case ValidTextureOverload::kGatherCompareDepth2dArrayOffsetF32:
-      return R"(texture.gather_compare(sampler, float2(1.0f, 2.0f), 3, 4.0f, int2(5, 6)))";
-    case ValidTextureOverload::kGatherCompareDepthCubeF32:
-      return R"(texture.gather_compare(sampler, float3(1.0f, 2.0f, 3.0f), 4.0f))";
-    case ValidTextureOverload::kGatherCompareDepthCubeArrayF32:
-      return R"(texture.gather_compare(sampler, float3(1.0f, 2.0f, 3.0f), 4, 5.0f))";
-    case ValidTextureOverload::kNumLayers2dArray:
-    case ValidTextureOverload::kNumLayersCubeArray:
-    case ValidTextureOverload::kNumLayersDepth2dArray:
-    case ValidTextureOverload::kNumLayersDepthCubeArray:
-    case ValidTextureOverload::kNumLayersStorageWO2dArray:
-      return R"(int(texture.get_array_size()))";
-    case ValidTextureOverload::kNumLevels2d:
-    case ValidTextureOverload::kNumLevels2dArray:
-    case ValidTextureOverload::kNumLevels3d:
-    case ValidTextureOverload::kNumLevelsCube:
-    case ValidTextureOverload::kNumLevelsCubeArray:
-    case ValidTextureOverload::kNumLevelsDepth2d:
-    case ValidTextureOverload::kNumLevelsDepth2dArray:
-    case ValidTextureOverload::kNumLevelsDepthCube:
-    case ValidTextureOverload::kNumLevelsDepthCubeArray:
-      return R"(int(texture.get_num_mip_levels()))";
-    case ValidTextureOverload::kNumSamplesDepthMultisampled2d:
-    case ValidTextureOverload::kNumSamplesMultisampled2d:
-      return R"(int(texture.get_num_samples()))";
-    case ValidTextureOverload::kSample1dF32:
-      return R"(texture.sample(sampler, 1.0f))";
-    case ValidTextureOverload::kSample2dF32:
-      return R"(texture.sample(sampler, float2(1.0f, 2.0f)))";
-    case ValidTextureOverload::kSample2dOffsetF32:
-      return R"(texture.sample(sampler, float2(1.0f, 2.0f), int2(3, 4)))";
-    case ValidTextureOverload::kSample2dArrayF32:
-      return R"(texture.sample(sampler, float2(1.0f, 2.0f), 3))";
-    case ValidTextureOverload::kSample2dArrayOffsetF32:
-      return R"(texture.sample(sampler, float2(1.0f, 2.0f), 3, int2(4, 5)))";
-    case ValidTextureOverload::kSample3dF32:
-      return R"(texture.sample(sampler, float3(1.0f, 2.0f, 3.0f)))";
-    case ValidTextureOverload::kSample3dOffsetF32:
-      return R"(texture.sample(sampler, float3(1.0f, 2.0f, 3.0f), int3(4, 5, 6)))";
-    case ValidTextureOverload::kSampleCubeF32:
-      return R"(texture.sample(sampler, float3(1.0f, 2.0f, 3.0f)))";
-    case ValidTextureOverload::kSampleCubeArrayF32:
-      return R"(texture.sample(sampler, float3(1.0f, 2.0f, 3.0f), 4))";
-    case ValidTextureOverload::kSampleDepth2dF32:
-      return R"(texture.sample(sampler, float2(1.0f, 2.0f)))";
-    case ValidTextureOverload::kSampleDepth2dOffsetF32:
-      return R"(texture.sample(sampler, float2(1.0f, 2.0f), int2(3, 4)))";
-    case ValidTextureOverload::kSampleDepth2dArrayF32:
-      return R"(texture.sample(sampler, float2(1.0f, 2.0f), 3))";
-    case ValidTextureOverload::kSampleDepth2dArrayOffsetF32:
-      return R"(texture.sample(sampler, float2(1.0f, 2.0f), 3, int2(4, 5)))";
-    case ValidTextureOverload::kSampleDepthCubeF32:
-      return R"(texture.sample(sampler, float3(1.0f, 2.0f, 3.0f)))";
-    case ValidTextureOverload::kSampleDepthCubeArrayF32:
-      return R"(texture.sample(sampler, float3(1.0f, 2.0f, 3.0f), 4))";
-    case ValidTextureOverload::kSampleBias2dF32:
-      return R"(texture.sample(sampler, float2(1.0f, 2.0f), bias(3.0f)))";
-    case ValidTextureOverload::kSampleBias2dOffsetF32:
-      return R"(texture.sample(sampler, float2(1.0f, 2.0f), bias(3.0f), int2(4, 5)))";
-    case ValidTextureOverload::kSampleBias2dArrayF32:
-      return R"(texture.sample(sampler, float2(1.0f, 2.0f), 4, bias(3.0f)))";
-    case ValidTextureOverload::kSampleBias2dArrayOffsetF32:
-      return R"(texture.sample(sampler, float2(1.0f, 2.0f), 3, bias(4.0f), int2(5, 6)))";
-    case ValidTextureOverload::kSampleBias3dF32:
-      return R"(texture.sample(sampler, float3(1.0f, 2.0f, 3.0f), bias(4.0f)))";
-    case ValidTextureOverload::kSampleBias3dOffsetF32:
-      return R"(texture.sample(sampler, float3(1.0f, 2.0f, 3.0f), bias(4.0f), int3(5, 6, 7)))";
-    case ValidTextureOverload::kSampleBiasCubeF32:
-      return R"(texture.sample(sampler, float3(1.0f, 2.0f, 3.0f), bias(4.0f)))";
-    case ValidTextureOverload::kSampleBiasCubeArrayF32:
-      return R"(texture.sample(sampler, float3(1.0f, 2.0f, 3.0f), 3, bias(4.0f)))";
-    case ValidTextureOverload::kSampleLevel2dF32:
-      return R"(texture.sample(sampler, float2(1.0f, 2.0f), level(3.0f)))";
-    case ValidTextureOverload::kSampleLevel2dOffsetF32:
-      return R"(texture.sample(sampler, float2(1.0f, 2.0f), level(3.0f), int2(4, 5)))";
-    case ValidTextureOverload::kSampleLevel2dArrayF32:
-      return R"(texture.sample(sampler, float2(1.0f, 2.0f), 3, level(4.0f)))";
-    case ValidTextureOverload::kSampleLevel2dArrayOffsetF32:
-      return R"(texture.sample(sampler, float2(1.0f, 2.0f), 3, level(4.0f), int2(5, 6)))";
-    case ValidTextureOverload::kSampleLevel3dF32:
-      return R"(texture.sample(sampler, float3(1.0f, 2.0f, 3.0f), level(4.0f)))";
-    case ValidTextureOverload::kSampleLevel3dOffsetF32:
-      return R"(texture.sample(sampler, float3(1.0f, 2.0f, 3.0f), level(4.0f), int3(5, 6, 7)))";
-    case ValidTextureOverload::kSampleLevelCubeF32:
-      return R"(texture.sample(sampler, float3(1.0f, 2.0f, 3.0f), level(4.0f)))";
-    case ValidTextureOverload::kSampleLevelCubeArrayF32:
-      return R"(texture.sample(sampler, float3(1.0f, 2.0f, 3.0f), 4, level(5.0f)))";
-    case ValidTextureOverload::kSampleLevelDepth2dF32:
-      return R"(texture.sample(sampler, float2(1.0f, 2.0f), level(3)))";
-    case ValidTextureOverload::kSampleLevelDepth2dOffsetF32:
-      return R"(texture.sample(sampler, float2(1.0f, 2.0f), level(3), int2(4, 5)))";
-    case ValidTextureOverload::kSampleLevelDepth2dArrayF32:
-      return R"(texture.sample(sampler, float2(1.0f, 2.0f), 3, level(4)))";
-    case ValidTextureOverload::kSampleLevelDepth2dArrayOffsetF32:
-      return R"(texture.sample(sampler, float2(1.0f, 2.0f), 3, level(4), int2(5, 6)))";
-    case ValidTextureOverload::kSampleLevelDepthCubeF32:
-      return R"(texture.sample(sampler, float3(1.0f, 2.0f, 3.0f), level(4)))";
-    case ValidTextureOverload::kSampleLevelDepthCubeArrayF32:
-      return R"(texture.sample(sampler, float3(1.0f, 2.0f, 3.0f), 4, level(5)))";
-    case ValidTextureOverload::kSampleGrad2dF32:
-      return R"(texture.sample(sampler, float2(1.0f, 2.0f), gradient2d(float2(3.0f, 4.0f), float2(5.0f, 6.0f))))";
-    case ValidTextureOverload::kSampleGrad2dOffsetF32:
-      return R"(texture.sample(sampler, float2(1.0f, 2.0f), gradient2d(float2(3.0f, 4.0f), float2(5.0f, 6.0f)), int2(7, 7)))";
-    case ValidTextureOverload::kSampleGrad2dArrayF32:
-      return R"(texture.sample(sampler, float2(1.0f, 2.0f), 3, gradient2d(float2(4.0f, 5.0f), float2(6.0f, 7.0f))))";
-    case ValidTextureOverload::kSampleGrad2dArrayOffsetF32:
-      return R"(texture.sample(sampler, float2(1.0f, 2.0f), 3, gradient2d(float2(4.0f, 5.0f), float2(6.0f, 7.0f)), int2(6, 7)))";
-    case ValidTextureOverload::kSampleGrad3dF32:
-      return R"(texture.sample(sampler, float3(1.0f, 2.0f, 3.0f), gradient3d(float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f))))";
-    case ValidTextureOverload::kSampleGrad3dOffsetF32:
-      return R"(texture.sample(sampler, float3(1.0f, 2.0f, 3.0f), gradient3d(float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f)), int3(0, 1, 2)))";
-    case ValidTextureOverload::kSampleGradCubeF32:
-      return R"(texture.sample(sampler, float3(1.0f, 2.0f, 3.0f), gradientcube(float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f))))";
-    case ValidTextureOverload::kSampleGradCubeArrayF32:
-      return R"(texture.sample(sampler, float3(1.0f, 2.0f, 3.0f), 4, gradientcube(float3(5.0f, 6.0f, 7.0f), float3(8.0f, 9.0f, 10.0f))))";
-    case ValidTextureOverload::kSampleCompareDepth2dF32:
-      return R"(texture.sample_compare(sampler, float2(1.0f, 2.0f), 3.0f))";
-    case ValidTextureOverload::kSampleCompareDepth2dOffsetF32:
-      return R"(texture.sample_compare(sampler, float2(1.0f, 2.0f), 3.0f, int2(4, 5)))";
-    case ValidTextureOverload::kSampleCompareDepth2dArrayF32:
-      return R"(texture.sample_compare(sampler, float2(1.0f, 2.0f), 4, 3.0f))";
-    case ValidTextureOverload::kSampleCompareDepth2dArrayOffsetF32:
-      return R"(texture.sample_compare(sampler, float2(1.0f, 2.0f), 4, 3.0f, int2(5, 6)))";
-    case ValidTextureOverload::kSampleCompareDepthCubeF32:
-      return R"(texture.sample_compare(sampler, float3(1.0f, 2.0f, 3.0f), 4.0f))";
-    case ValidTextureOverload::kSampleCompareDepthCubeArrayF32:
-      return R"(texture.sample_compare(sampler, float3(1.0f, 2.0f, 3.0f), 4, 5.0f))";
-    case ValidTextureOverload::kSampleCompareLevelDepth2dF32:
-      return R"(texture.sample_compare(sampler, float2(1.0f, 2.0f), 3.0f))";
-    case ValidTextureOverload::kSampleCompareLevelDepth2dOffsetF32:
-      return R"(texture.sample_compare(sampler, float2(1.0f, 2.0f), 3.0f, int2(4, 5)))";
-    case ValidTextureOverload::kSampleCompareLevelDepth2dArrayF32:
-      return R"(texture.sample_compare(sampler, float2(1.0f, 2.0f), 4, 3.0f))";
-    case ValidTextureOverload::kSampleCompareLevelDepth2dArrayOffsetF32:
-      return R"(texture.sample_compare(sampler, float2(1.0f, 2.0f), 4, 3.0f, int2(5, 6)))";
-    case ValidTextureOverload::kSampleCompareLevelDepthCubeF32:
-      return R"(texture.sample_compare(sampler, float3(1.0f, 2.0f, 3.0f), 4.0f))";
-    case ValidTextureOverload::kSampleCompareLevelDepthCubeArrayF32:
-      return R"(texture.sample_compare(sampler, float3(1.0f, 2.0f, 3.0f), 4, 5.0f))";
-    case ValidTextureOverload::kLoad1dLevelF32:
-      return R"(texture.read(uint(1), 0))";
-    case ValidTextureOverload::kLoad1dLevelU32:
-      return R"(texture.read(uint(1), 0))";
-    case ValidTextureOverload::kLoad1dLevelI32:
-      return R"(texture.read(uint(1), 0))";
-    case ValidTextureOverload::kLoad2dLevelF32:
-      return R"(texture.read(uint2(int2(1, 2)), 3))";
-    case ValidTextureOverload::kLoad2dLevelU32:
-      return R"(texture.read(uint2(int2(1, 2)), 3))";
-    case ValidTextureOverload::kLoad2dLevelI32:
-      return R"(texture.read(uint2(int2(1, 2)), 3))";
-    case ValidTextureOverload::kLoad2dArrayLevelF32:
-      return R"(texture.read(uint2(int2(1, 2)), 3, 4))";
-    case ValidTextureOverload::kLoad2dArrayLevelU32:
-      return R"(texture.read(uint2(int2(1, 2)), 3, 4))";
-    case ValidTextureOverload::kLoad2dArrayLevelI32:
-      return R"(texture.read(uint2(int2(1, 2)), 3, 4))";
-    case ValidTextureOverload::kLoad3dLevelF32:
-      return R"(texture.read(uint3(int3(1, 2, 3)), 4))";
-    case ValidTextureOverload::kLoad3dLevelU32:
-      return R"(texture.read(uint3(int3(1, 2, 3)), 4))";
-    case ValidTextureOverload::kLoad3dLevelI32:
-      return R"(texture.read(uint3(int3(1, 2, 3)), 4))";
-    case ValidTextureOverload::kLoadMultisampled2dF32:
-      return R"(texture.read(uint2(int2(1, 2)), 3))";
-    case ValidTextureOverload::kLoadMultisampled2dU32:
-      return R"(texture.read(uint2(int2(1, 2)), 3))";
-    case ValidTextureOverload::kLoadMultisampled2dI32:
-      return R"(texture.read(uint2(int2(1, 2)), 3))";
-    case ValidTextureOverload::kLoadDepth2dLevelF32:
-    case ValidTextureOverload::kLoadDepthMultisampled2dF32:
-      return R"(texture.read(uint2(int2(1, 2)), 3))";
-    case ValidTextureOverload::kLoadDepth2dArrayLevelF32:
-      return R"(texture.read(uint2(int2(1, 2)), 3, 4))";
-    case ValidTextureOverload::kStoreWO1dRgba32float:
-      return R"(texture.write(float4(2.0f, 3.0f, 4.0f, 5.0f), uint(1)))";
-    case ValidTextureOverload::kStoreWO2dRgba32float:
-      return R"(texture.write(float4(3.0f, 4.0f, 5.0f, 6.0f), uint2(int2(1, 2))))";
-    case ValidTextureOverload::kStoreWO2dArrayRgba32float:
-      return R"(texture.write(float4(4.0f, 5.0f, 6.0f, 7.0f), uint2(int2(1, 2)), 3))";
-    case ValidTextureOverload::kStoreWO3dRgba32float:
-      return R"(texture.write(float4(4.0f, 5.0f, 6.0f, 7.0f), uint3(int3(1, 2, 3))))";
-  }
-  return "<unmatched texture overload>";
+std::string expected_texture_overload(ast::builtin::test::ValidTextureOverload overload) {
+    using ValidTextureOverload = ast::builtin::test::ValidTextureOverload;
+    switch (overload) {
+        case ValidTextureOverload::kDimensions1d:
+        case ValidTextureOverload::kDimensionsStorageWO1d:
+            return R"(int(texture.get_width(0)))";
+        case ValidTextureOverload::kDimensions2d:
+        case ValidTextureOverload::kDimensions2dArray:
+        case ValidTextureOverload::kDimensionsCube:
+        case ValidTextureOverload::kDimensionsCubeArray:
+        case ValidTextureOverload::kDimensionsMultisampled2d:
+        case ValidTextureOverload::kDimensionsDepth2d:
+        case ValidTextureOverload::kDimensionsDepth2dArray:
+        case ValidTextureOverload::kDimensionsDepthCube:
+        case ValidTextureOverload::kDimensionsDepthCubeArray:
+        case ValidTextureOverload::kDimensionsDepthMultisampled2d:
+        case ValidTextureOverload::kDimensionsStorageWO2d:
+        case ValidTextureOverload::kDimensionsStorageWO2dArray:
+            return R"(int2(texture.get_width(), texture.get_height()))";
+        case ValidTextureOverload::kDimensions3d:
+        case ValidTextureOverload::kDimensionsStorageWO3d:
+            return R"(int3(texture.get_width(), texture.get_height(), texture.get_depth()))";
+        case ValidTextureOverload::kDimensions2dLevel:
+        case ValidTextureOverload::kDimensionsCubeLevel:
+        case ValidTextureOverload::kDimensionsCubeArrayLevel:
+        case ValidTextureOverload::kDimensions2dArrayLevel:
+        case ValidTextureOverload::kDimensionsDepth2dLevel:
+        case ValidTextureOverload::kDimensionsDepth2dArrayLevel:
+        case ValidTextureOverload::kDimensionsDepthCubeLevel:
+        case ValidTextureOverload::kDimensionsDepthCubeArrayLevel:
+            return R"(int2(texture.get_width(1), texture.get_height(1)))";
+        case ValidTextureOverload::kDimensions3dLevel:
+            return R"(int3(texture.get_width(1), texture.get_height(1), texture.get_depth(1)))";
+        case ValidTextureOverload::kGather2dF32:
+            return R"(texture.gather(sampler, float2(1.0f, 2.0f), int2(0), component::x))";
+        case ValidTextureOverload::kGather2dOffsetF32:
+            return R"(texture.gather(sampler, float2(1.0f, 2.0f), int2(3, 4), component::x))";
+        case ValidTextureOverload::kGather2dArrayF32:
+            return R"(texture.gather(sampler, float2(1.0f, 2.0f), 3, int2(0), component::x))";
+        case ValidTextureOverload::kGather2dArrayOffsetF32:
+            return R"(texture.gather(sampler, float2(1.0f, 2.0f), 3, int2(4, 5), component::x))";
+        case ValidTextureOverload::kGatherCubeF32:
+            return R"(texture.gather(sampler, float3(1.0f, 2.0f, 3.0f), component::x))";
+        case ValidTextureOverload::kGatherCubeArrayF32:
+            return R"(texture.gather(sampler, float3(1.0f, 2.0f, 3.0f), 4, component::x))";
+        case ValidTextureOverload::kGatherDepth2dF32:
+            return R"(texture.gather(sampler, float2(1.0f, 2.0f)))";
+        case ValidTextureOverload::kGatherDepth2dOffsetF32:
+            return R"(texture.gather(sampler, float2(1.0f, 2.0f), int2(3, 4)))";
+        case ValidTextureOverload::kGatherDepth2dArrayF32:
+            return R"(texture.gather(sampler, float2(1.0f, 2.0f), 3))";
+        case ValidTextureOverload::kGatherDepth2dArrayOffsetF32:
+            return R"(texture.gather(sampler, float2(1.0f, 2.0f), 3, int2(4, 5)))";
+        case ValidTextureOverload::kGatherDepthCubeF32:
+            return R"(texture.gather(sampler, float3(1.0f, 2.0f, 3.0f)))";
+        case ValidTextureOverload::kGatherDepthCubeArrayF32:
+            return R"(texture.gather(sampler, float3(1.0f, 2.0f, 3.0f), 4))";
+        case ValidTextureOverload::kGatherCompareDepth2dF32:
+            return R"(texture.gather_compare(sampler, float2(1.0f, 2.0f), 3.0f))";
+        case ValidTextureOverload::kGatherCompareDepth2dOffsetF32:
+            return R"(texture.gather_compare(sampler, float2(1.0f, 2.0f), 3.0f, int2(4, 5)))";
+        case ValidTextureOverload::kGatherCompareDepth2dArrayF32:
+            return R"(texture.gather_compare(sampler, float2(1.0f, 2.0f), 3, 4.0f))";
+        case ValidTextureOverload::kGatherCompareDepth2dArrayOffsetF32:
+            return R"(texture.gather_compare(sampler, float2(1.0f, 2.0f), 3, 4.0f, int2(5, 6)))";
+        case ValidTextureOverload::kGatherCompareDepthCubeF32:
+            return R"(texture.gather_compare(sampler, float3(1.0f, 2.0f, 3.0f), 4.0f))";
+        case ValidTextureOverload::kGatherCompareDepthCubeArrayF32:
+            return R"(texture.gather_compare(sampler, float3(1.0f, 2.0f, 3.0f), 4, 5.0f))";
+        case ValidTextureOverload::kNumLayers2dArray:
+        case ValidTextureOverload::kNumLayersCubeArray:
+        case ValidTextureOverload::kNumLayersDepth2dArray:
+        case ValidTextureOverload::kNumLayersDepthCubeArray:
+        case ValidTextureOverload::kNumLayersStorageWO2dArray:
+            return R"(int(texture.get_array_size()))";
+        case ValidTextureOverload::kNumLevels2d:
+        case ValidTextureOverload::kNumLevels2dArray:
+        case ValidTextureOverload::kNumLevels3d:
+        case ValidTextureOverload::kNumLevelsCube:
+        case ValidTextureOverload::kNumLevelsCubeArray:
+        case ValidTextureOverload::kNumLevelsDepth2d:
+        case ValidTextureOverload::kNumLevelsDepth2dArray:
+        case ValidTextureOverload::kNumLevelsDepthCube:
+        case ValidTextureOverload::kNumLevelsDepthCubeArray:
+            return R"(int(texture.get_num_mip_levels()))";
+        case ValidTextureOverload::kNumSamplesDepthMultisampled2d:
+        case ValidTextureOverload::kNumSamplesMultisampled2d:
+            return R"(int(texture.get_num_samples()))";
+        case ValidTextureOverload::kSample1dF32:
+            return R"(texture.sample(sampler, 1.0f))";
+        case ValidTextureOverload::kSample2dF32:
+            return R"(texture.sample(sampler, float2(1.0f, 2.0f)))";
+        case ValidTextureOverload::kSample2dOffsetF32:
+            return R"(texture.sample(sampler, float2(1.0f, 2.0f), int2(3, 4)))";
+        case ValidTextureOverload::kSample2dArrayF32:
+            return R"(texture.sample(sampler, float2(1.0f, 2.0f), 3))";
+        case ValidTextureOverload::kSample2dArrayOffsetF32:
+            return R"(texture.sample(sampler, float2(1.0f, 2.0f), 3, int2(4, 5)))";
+        case ValidTextureOverload::kSample3dF32:
+            return R"(texture.sample(sampler, float3(1.0f, 2.0f, 3.0f)))";
+        case ValidTextureOverload::kSample3dOffsetF32:
+            return R"(texture.sample(sampler, float3(1.0f, 2.0f, 3.0f), int3(4, 5, 6)))";
+        case ValidTextureOverload::kSampleCubeF32:
+            return R"(texture.sample(sampler, float3(1.0f, 2.0f, 3.0f)))";
+        case ValidTextureOverload::kSampleCubeArrayF32:
+            return R"(texture.sample(sampler, float3(1.0f, 2.0f, 3.0f), 4))";
+        case ValidTextureOverload::kSampleDepth2dF32:
+            return R"(texture.sample(sampler, float2(1.0f, 2.0f)))";
+        case ValidTextureOverload::kSampleDepth2dOffsetF32:
+            return R"(texture.sample(sampler, float2(1.0f, 2.0f), int2(3, 4)))";
+        case ValidTextureOverload::kSampleDepth2dArrayF32:
+            return R"(texture.sample(sampler, float2(1.0f, 2.0f), 3))";
+        case ValidTextureOverload::kSampleDepth2dArrayOffsetF32:
+            return R"(texture.sample(sampler, float2(1.0f, 2.0f), 3, int2(4, 5)))";
+        case ValidTextureOverload::kSampleDepthCubeF32:
+            return R"(texture.sample(sampler, float3(1.0f, 2.0f, 3.0f)))";
+        case ValidTextureOverload::kSampleDepthCubeArrayF32:
+            return R"(texture.sample(sampler, float3(1.0f, 2.0f, 3.0f), 4))";
+        case ValidTextureOverload::kSampleBias2dF32:
+            return R"(texture.sample(sampler, float2(1.0f, 2.0f), bias(3.0f)))";
+        case ValidTextureOverload::kSampleBias2dOffsetF32:
+            return R"(texture.sample(sampler, float2(1.0f, 2.0f), bias(3.0f), int2(4, 5)))";
+        case ValidTextureOverload::kSampleBias2dArrayF32:
+            return R"(texture.sample(sampler, float2(1.0f, 2.0f), 4, bias(3.0f)))";
+        case ValidTextureOverload::kSampleBias2dArrayOffsetF32:
+            return R"(texture.sample(sampler, float2(1.0f, 2.0f), 3, bias(4.0f), int2(5, 6)))";
+        case ValidTextureOverload::kSampleBias3dF32:
+            return R"(texture.sample(sampler, float3(1.0f, 2.0f, 3.0f), bias(4.0f)))";
+        case ValidTextureOverload::kSampleBias3dOffsetF32:
+            return R"(texture.sample(sampler, float3(1.0f, 2.0f, 3.0f), bias(4.0f), int3(5, 6, 7)))";
+        case ValidTextureOverload::kSampleBiasCubeF32:
+            return R"(texture.sample(sampler, float3(1.0f, 2.0f, 3.0f), bias(4.0f)))";
+        case ValidTextureOverload::kSampleBiasCubeArrayF32:
+            return R"(texture.sample(sampler, float3(1.0f, 2.0f, 3.0f), 3, bias(4.0f)))";
+        case ValidTextureOverload::kSampleLevel2dF32:
+            return R"(texture.sample(sampler, float2(1.0f, 2.0f), level(3.0f)))";
+        case ValidTextureOverload::kSampleLevel2dOffsetF32:
+            return R"(texture.sample(sampler, float2(1.0f, 2.0f), level(3.0f), int2(4, 5)))";
+        case ValidTextureOverload::kSampleLevel2dArrayF32:
+            return R"(texture.sample(sampler, float2(1.0f, 2.0f), 3, level(4.0f)))";
+        case ValidTextureOverload::kSampleLevel2dArrayOffsetF32:
+            return R"(texture.sample(sampler, float2(1.0f, 2.0f), 3, level(4.0f), int2(5, 6)))";
+        case ValidTextureOverload::kSampleLevel3dF32:
+            return R"(texture.sample(sampler, float3(1.0f, 2.0f, 3.0f), level(4.0f)))";
+        case ValidTextureOverload::kSampleLevel3dOffsetF32:
+            return R"(texture.sample(sampler, float3(1.0f, 2.0f, 3.0f), level(4.0f), int3(5, 6, 7)))";
+        case ValidTextureOverload::kSampleLevelCubeF32:
+            return R"(texture.sample(sampler, float3(1.0f, 2.0f, 3.0f), level(4.0f)))";
+        case ValidTextureOverload::kSampleLevelCubeArrayF32:
+            return R"(texture.sample(sampler, float3(1.0f, 2.0f, 3.0f), 4, level(5.0f)))";
+        case ValidTextureOverload::kSampleLevelDepth2dF32:
+            return R"(texture.sample(sampler, float2(1.0f, 2.0f), level(3)))";
+        case ValidTextureOverload::kSampleLevelDepth2dOffsetF32:
+            return R"(texture.sample(sampler, float2(1.0f, 2.0f), level(3), int2(4, 5)))";
+        case ValidTextureOverload::kSampleLevelDepth2dArrayF32:
+            return R"(texture.sample(sampler, float2(1.0f, 2.0f), 3, level(4)))";
+        case ValidTextureOverload::kSampleLevelDepth2dArrayOffsetF32:
+            return R"(texture.sample(sampler, float2(1.0f, 2.0f), 3, level(4), int2(5, 6)))";
+        case ValidTextureOverload::kSampleLevelDepthCubeF32:
+            return R"(texture.sample(sampler, float3(1.0f, 2.0f, 3.0f), level(4)))";
+        case ValidTextureOverload::kSampleLevelDepthCubeArrayF32:
+            return R"(texture.sample(sampler, float3(1.0f, 2.0f, 3.0f), 4, level(5)))";
+        case ValidTextureOverload::kSampleGrad2dF32:
+            return R"(texture.sample(sampler, float2(1.0f, 2.0f), gradient2d(float2(3.0f, 4.0f), float2(5.0f, 6.0f))))";
+        case ValidTextureOverload::kSampleGrad2dOffsetF32:
+            return R"(texture.sample(sampler, float2(1.0f, 2.0f), gradient2d(float2(3.0f, 4.0f), float2(5.0f, 6.0f)), int2(7, 7)))";
+        case ValidTextureOverload::kSampleGrad2dArrayF32:
+            return R"(texture.sample(sampler, float2(1.0f, 2.0f), 3, gradient2d(float2(4.0f, 5.0f), float2(6.0f, 7.0f))))";
+        case ValidTextureOverload::kSampleGrad2dArrayOffsetF32:
+            return R"(texture.sample(sampler, float2(1.0f, 2.0f), 3, gradient2d(float2(4.0f, 5.0f), float2(6.0f, 7.0f)), int2(6, 7)))";
+        case ValidTextureOverload::kSampleGrad3dF32:
+            return R"(texture.sample(sampler, float3(1.0f, 2.0f, 3.0f), gradient3d(float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f))))";
+        case ValidTextureOverload::kSampleGrad3dOffsetF32:
+            return R"(texture.sample(sampler, float3(1.0f, 2.0f, 3.0f), gradient3d(float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f)), int3(0, 1, 2)))";
+        case ValidTextureOverload::kSampleGradCubeF32:
+            return R"(texture.sample(sampler, float3(1.0f, 2.0f, 3.0f), gradientcube(float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f))))";
+        case ValidTextureOverload::kSampleGradCubeArrayF32:
+            return R"(texture.sample(sampler, float3(1.0f, 2.0f, 3.0f), 4, gradientcube(float3(5.0f, 6.0f, 7.0f), float3(8.0f, 9.0f, 10.0f))))";
+        case ValidTextureOverload::kSampleCompareDepth2dF32:
+            return R"(texture.sample_compare(sampler, float2(1.0f, 2.0f), 3.0f))";
+        case ValidTextureOverload::kSampleCompareDepth2dOffsetF32:
+            return R"(texture.sample_compare(sampler, float2(1.0f, 2.0f), 3.0f, int2(4, 5)))";
+        case ValidTextureOverload::kSampleCompareDepth2dArrayF32:
+            return R"(texture.sample_compare(sampler, float2(1.0f, 2.0f), 4, 3.0f))";
+        case ValidTextureOverload::kSampleCompareDepth2dArrayOffsetF32:
+            return R"(texture.sample_compare(sampler, float2(1.0f, 2.0f), 4, 3.0f, int2(5, 6)))";
+        case ValidTextureOverload::kSampleCompareDepthCubeF32:
+            return R"(texture.sample_compare(sampler, float3(1.0f, 2.0f, 3.0f), 4.0f))";
+        case ValidTextureOverload::kSampleCompareDepthCubeArrayF32:
+            return R"(texture.sample_compare(sampler, float3(1.0f, 2.0f, 3.0f), 4, 5.0f))";
+        case ValidTextureOverload::kSampleCompareLevelDepth2dF32:
+            return R"(texture.sample_compare(sampler, float2(1.0f, 2.0f), 3.0f))";
+        case ValidTextureOverload::kSampleCompareLevelDepth2dOffsetF32:
+            return R"(texture.sample_compare(sampler, float2(1.0f, 2.0f), 3.0f, int2(4, 5)))";
+        case ValidTextureOverload::kSampleCompareLevelDepth2dArrayF32:
+            return R"(texture.sample_compare(sampler, float2(1.0f, 2.0f), 4, 3.0f))";
+        case ValidTextureOverload::kSampleCompareLevelDepth2dArrayOffsetF32:
+            return R"(texture.sample_compare(sampler, float2(1.0f, 2.0f), 4, 3.0f, int2(5, 6)))";
+        case ValidTextureOverload::kSampleCompareLevelDepthCubeF32:
+            return R"(texture.sample_compare(sampler, float3(1.0f, 2.0f, 3.0f), 4.0f))";
+        case ValidTextureOverload::kSampleCompareLevelDepthCubeArrayF32:
+            return R"(texture.sample_compare(sampler, float3(1.0f, 2.0f, 3.0f), 4, 5.0f))";
+        case ValidTextureOverload::kLoad1dLevelF32:
+            return R"(texture.read(uint(1), 0))";
+        case ValidTextureOverload::kLoad1dLevelU32:
+            return R"(texture.read(uint(1), 0))";
+        case ValidTextureOverload::kLoad1dLevelI32:
+            return R"(texture.read(uint(1), 0))";
+        case ValidTextureOverload::kLoad2dLevelF32:
+            return R"(texture.read(uint2(int2(1, 2)), 3))";
+        case ValidTextureOverload::kLoad2dLevelU32:
+            return R"(texture.read(uint2(int2(1, 2)), 3))";
+        case ValidTextureOverload::kLoad2dLevelI32:
+            return R"(texture.read(uint2(int2(1, 2)), 3))";
+        case ValidTextureOverload::kLoad2dArrayLevelF32:
+            return R"(texture.read(uint2(int2(1, 2)), 3, 4))";
+        case ValidTextureOverload::kLoad2dArrayLevelU32:
+            return R"(texture.read(uint2(int2(1, 2)), 3, 4))";
+        case ValidTextureOverload::kLoad2dArrayLevelI32:
+            return R"(texture.read(uint2(int2(1, 2)), 3, 4))";
+        case ValidTextureOverload::kLoad3dLevelF32:
+            return R"(texture.read(uint3(int3(1, 2, 3)), 4))";
+        case ValidTextureOverload::kLoad3dLevelU32:
+            return R"(texture.read(uint3(int3(1, 2, 3)), 4))";
+        case ValidTextureOverload::kLoad3dLevelI32:
+            return R"(texture.read(uint3(int3(1, 2, 3)), 4))";
+        case ValidTextureOverload::kLoadMultisampled2dF32:
+            return R"(texture.read(uint2(int2(1, 2)), 3))";
+        case ValidTextureOverload::kLoadMultisampled2dU32:
+            return R"(texture.read(uint2(int2(1, 2)), 3))";
+        case ValidTextureOverload::kLoadMultisampled2dI32:
+            return R"(texture.read(uint2(int2(1, 2)), 3))";
+        case ValidTextureOverload::kLoadDepth2dLevelF32:
+        case ValidTextureOverload::kLoadDepthMultisampled2dF32:
+            return R"(texture.read(uint2(int2(1, 2)), 3))";
+        case ValidTextureOverload::kLoadDepth2dArrayLevelF32:
+            return R"(texture.read(uint2(int2(1, 2)), 3, 4))";
+        case ValidTextureOverload::kStoreWO1dRgba32float:
+            return R"(texture.write(float4(2.0f, 3.0f, 4.0f, 5.0f), uint(1)))";
+        case ValidTextureOverload::kStoreWO2dRgba32float:
+            return R"(texture.write(float4(3.0f, 4.0f, 5.0f, 6.0f), uint2(int2(1, 2))))";
+        case ValidTextureOverload::kStoreWO2dArrayRgba32float:
+            return R"(texture.write(float4(4.0f, 5.0f, 6.0f, 7.0f), uint2(int2(1, 2)), 3))";
+        case ValidTextureOverload::kStoreWO3dRgba32float:
+            return R"(texture.write(float4(4.0f, 5.0f, 6.0f, 7.0f), uint3(int3(1, 2, 3))))";
+    }
+    return "<unmatched texture overload>";
 }  // NOLINT - Ignore the length of this function
 
 class MslGeneratorBuiltinTextureTest
     : public TestParamHelper<ast::builtin::test::TextureOverloadCase> {};
 
 TEST_P(MslGeneratorBuiltinTextureTest, Call) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  param.BuildTextureVariable(this);
-  param.BuildSamplerVariable(this);
+    param.BuildTextureVariable(this);
+    param.BuildSamplerVariable(this);
 
-  auto* call = Call(Expr(param.function), param.args(this));
-  auto* stmt = CallStmt(call);
+    auto* call = Call(Expr(param.function), param.args(this));
+    auto* stmt = CallStmt(call);
 
-  Func("main", {}, ty.void_(), {stmt}, {Stage(ast::PipelineStage::kFragment)});
+    Func("main", {}, ty.void_(), {stmt}, {Stage(ast::PipelineStage::kFragment)});
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
 
-  auto expected = expected_texture_overload(param.overload);
-  EXPECT_EQ(expected, out.str());
+    auto expected = expected_texture_overload(param.overload);
+    EXPECT_EQ(expected, out.str());
 }
 
-INSTANTIATE_TEST_SUITE_P(
-    MslGeneratorBuiltinTextureTest,
-    MslGeneratorBuiltinTextureTest,
-    testing::ValuesIn(ast::builtin::test::TextureOverloadCase::ValidCases()));
+INSTANTIATE_TEST_SUITE_P(MslGeneratorBuiltinTextureTest,
+                         MslGeneratorBuiltinTextureTest,
+                         testing::ValuesIn(ast::builtin::test::TextureOverloadCase::ValidCases()));
 
 }  // namespace
 }  // namespace tint::writer::msl
diff --git a/src/tint/writer/msl/generator_impl_call_test.cc b/src/tint/writer/msl/generator_impl_call_test.cc
index 1b6ce7a..9fc7b8f 100644
--- a/src/tint/writer/msl/generator_impl_call_test.cc
+++ b/src/tint/writer/msl/generator_impl_call_test.cc
@@ -21,57 +21,57 @@
 using MslGeneratorImplTest = TestHelper;
 
 TEST_F(MslGeneratorImplTest, EmitExpression_Call_WithoutParams) {
-  Func("my_func", {}, ty.f32(), {Return(1.23f)});
+    Func("my_func", {}, ty.f32(), {Return(1.23f)});
 
-  auto* call = Call("my_func");
-  WrapInFunction(call);
+    auto* call = Call("my_func");
+    WrapInFunction(call);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
-  EXPECT_EQ(out.str(), "my_func()");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
+    EXPECT_EQ(out.str(), "my_func()");
 }
 
 TEST_F(MslGeneratorImplTest, EmitExpression_Call_WithParams) {
-  Func("my_func",
-       {
-           Param(Sym(), ty.f32()),
-           Param(Sym(), ty.f32()),
-       },
-       ty.f32(), {Return(1.23f)});
-  Global("param1", ty.f32(), ast::StorageClass::kPrivate);
-  Global("param2", ty.f32(), ast::StorageClass::kPrivate);
+    Func("my_func",
+         {
+             Param(Sym(), ty.f32()),
+             Param(Sym(), ty.f32()),
+         },
+         ty.f32(), {Return(1.23f)});
+    Global("param1", ty.f32(), ast::StorageClass::kPrivate);
+    Global("param2", ty.f32(), ast::StorageClass::kPrivate);
 
-  auto* call = Call("my_func", "param1", "param2");
-  WrapInFunction(call);
+    auto* call = Call("my_func", "param1", "param2");
+    WrapInFunction(call);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
-  EXPECT_EQ(out.str(), "my_func(param1, param2)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
+    EXPECT_EQ(out.str(), "my_func(param1, param2)");
 }
 
 TEST_F(MslGeneratorImplTest, EmitStatement_Call) {
-  Func("my_func",
-       {
-           Param(Sym(), ty.f32()),
-           Param(Sym(), ty.f32()),
-       },
-       ty.void_(), ast::StatementList{}, ast::AttributeList{});
-  Global("param1", ty.f32(), ast::StorageClass::kPrivate);
-  Global("param2", ty.f32(), ast::StorageClass::kPrivate);
+    Func("my_func",
+         {
+             Param(Sym(), ty.f32()),
+             Param(Sym(), ty.f32()),
+         },
+         ty.void_(), ast::StatementList{}, ast::AttributeList{});
+    Global("param1", ty.f32(), ast::StorageClass::kPrivate);
+    Global("param2", ty.f32(), ast::StorageClass::kPrivate);
 
-  auto* call = Call("my_func", "param1", "param2");
-  auto* stmt = CallStmt(call);
-  WrapInFunction(stmt);
+    auto* call = Call("my_func", "param1", "param2");
+    auto* stmt = CallStmt(call);
+    WrapInFunction(stmt);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
-  ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
-  EXPECT_EQ(gen.result(), "  my_func(param1, param2);\n");
+    gen.increment_indent();
+    ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
+    EXPECT_EQ(gen.result(), "  my_func(param1, param2);\n");
 }
 
 }  // namespace
diff --git a/src/tint/writer/msl/generator_impl_case_test.cc b/src/tint/writer/msl/generator_impl_case_test.cc
index 8822ea9..8fc1bc9 100644
--- a/src/tint/writer/msl/generator_impl_case_test.cc
+++ b/src/tint/writer/msl/generator_impl_case_test.cc
@@ -15,70 +15,70 @@
 #include "src/tint/ast/fallthrough_statement.h"
 #include "src/tint/writer/msl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::msl {
 namespace {
 
 using MslGeneratorImplTest = TestHelper;
 
 TEST_F(MslGeneratorImplTest, Emit_Case) {
-  auto* s = Switch(1, Case(Expr(5), Block(create<ast::BreakStatement>())),
-                   DefaultCase());
-  WrapInFunction(s);
+    auto* s = Switch(1_i, Case(Expr(5_i), Block(create<ast::BreakStatement>())), DefaultCase());
+    WrapInFunction(s);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitCase(s->body[0])) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  case 5: {
+    ASSERT_TRUE(gen.EmitCase(s->body[0])) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  case 5: {
     break;
   }
 )");
 }
 
 TEST_F(MslGeneratorImplTest, Emit_Case_BreaksByDefault) {
-  auto* s = Switch(1, Case(Expr(5), Block()), DefaultCase());
-  WrapInFunction(s);
+    auto* s = Switch(1_i, Case(Expr(5_i), Block()), DefaultCase());
+    WrapInFunction(s);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitCase(s->body[0])) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  case 5: {
+    ASSERT_TRUE(gen.EmitCase(s->body[0])) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  case 5: {
     break;
   }
 )");
 }
 
 TEST_F(MslGeneratorImplTest, Emit_Case_WithFallthrough) {
-  auto* s = Switch(1, Case(Expr(5), Block(create<ast::FallthroughStatement>())),
-                   DefaultCase());
-  WrapInFunction(s);
+    auto* s =
+        Switch(1_i, Case(Expr(5_i), Block(create<ast::FallthroughStatement>())), DefaultCase());
+    WrapInFunction(s);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitCase(s->body[0])) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  case 5: {
+    ASSERT_TRUE(gen.EmitCase(s->body[0])) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  case 5: {
     /* fallthrough */
   }
 )");
 }
 
 TEST_F(MslGeneratorImplTest, Emit_Case_MultipleSelectors) {
-  auto* s =
-      Switch(1, Case({Expr(5), Expr(6)}, Block(create<ast::BreakStatement>())),
-             DefaultCase());
-  WrapInFunction(s);
+    auto* s = Switch(1_i, Case({Expr(5_i), Expr(6_i)}, Block(create<ast::BreakStatement>())),
+                     DefaultCase());
+    WrapInFunction(s);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitCase(s->body[0])) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  case 5:
+    ASSERT_TRUE(gen.EmitCase(s->body[0])) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  case 5:
   case 6: {
     break;
   }
@@ -86,15 +86,15 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_Case_Default) {
-  auto* s = Switch(1, DefaultCase(Block(create<ast::BreakStatement>())));
-  WrapInFunction(s);
+    auto* s = Switch(1_i, DefaultCase(Block(create<ast::BreakStatement>())));
+    WrapInFunction(s);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitCase(s->body[0])) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  default: {
+    ASSERT_TRUE(gen.EmitCase(s->body[0])) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  default: {
     break;
   }
 )");
diff --git a/src/tint/writer/msl/generator_impl_cast_test.cc b/src/tint/writer/msl/generator_impl_cast_test.cc
index 80497c2..0eca191 100644
--- a/src/tint/writer/msl/generator_impl_cast_test.cc
+++ b/src/tint/writer/msl/generator_impl_cast_test.cc
@@ -14,42 +14,44 @@
 
 #include "src/tint/writer/msl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::msl {
 namespace {
 
 using MslGeneratorImplTest = TestHelper;
 
 TEST_F(MslGeneratorImplTest, EmitExpression_Cast_Scalar) {
-  auto* cast = Construct<f32>(1);
-  WrapInFunction(cast);
+    auto* cast = Construct<f32>(1_i);
+    WrapInFunction(cast);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, cast)) << gen.error();
-  EXPECT_EQ(out.str(), "float(1)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, cast)) << gen.error();
+    EXPECT_EQ(out.str(), "float(1)");
 }
 
 TEST_F(MslGeneratorImplTest, EmitExpression_Cast_Vector) {
-  auto* cast = vec3<f32>(vec3<i32>(1, 2, 3));
-  WrapInFunction(cast);
+    auto* cast = vec3<f32>(vec3<i32>(1_i, 2_i, 3_i));
+    WrapInFunction(cast);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, cast)) << gen.error();
-  EXPECT_EQ(out.str(), "float3(int3(1, 2, 3))");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, cast)) << gen.error();
+    EXPECT_EQ(out.str(), "float3(int3(1, 2, 3))");
 }
 
 TEST_F(MslGeneratorImplTest, EmitExpression_Cast_IntMin) {
-  auto* cast = Construct<u32>(std::numeric_limits<int32_t>::min());
-  WrapInFunction(cast);
+    auto* cast = Construct<u32>(i32(std::numeric_limits<int32_t>::min()));
+    WrapInFunction(cast);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, cast)) << gen.error();
-  EXPECT_EQ(out.str(), "uint((-2147483647 - 1))");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, cast)) << gen.error();
+    EXPECT_EQ(out.str(), "uint((-2147483647 - 1))");
 }
 
 }  // namespace
diff --git a/src/tint/writer/msl/generator_impl_constructor_test.cc b/src/tint/writer/msl/generator_impl_constructor_test.cc
index cbe34e7..134a7ae 100644
--- a/src/tint/writer/msl/generator_impl_constructor_test.cc
+++ b/src/tint/writer/msl/generator_impl_constructor_test.cc
@@ -15,6 +15,8 @@
 #include "gmock/gmock.h"
 #include "src/tint/writer/msl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::msl {
 namespace {
 
@@ -23,163 +25,159 @@
 using MslGeneratorImplTest = TestHelper;
 
 TEST_F(MslGeneratorImplTest, EmitConstructor_Bool) {
-  WrapInFunction(Expr(false));
+    WrapInFunction(Expr(false));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("false"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("false"));
 }
 
 TEST_F(MslGeneratorImplTest, EmitConstructor_Int) {
-  WrapInFunction(Expr(-12345));
+    WrapInFunction(Expr(i32(-12345)));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("-12345"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("-12345"));
 }
 
 TEST_F(MslGeneratorImplTest, EmitConstructor_UInt) {
-  WrapInFunction(Expr(56779u));
+    WrapInFunction(Expr(56779_u));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("56779u"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("56779u"));
 }
 
 TEST_F(MslGeneratorImplTest, EmitConstructor_Float) {
-  // Use a number close to 1<<30 but whose decimal representation ends in 0.
-  WrapInFunction(Expr(static_cast<float>((1 << 30) - 4)));
+    // Use a number close to 1<<30 but whose decimal representation ends in 0.
+    WrapInFunction(Expr(static_cast<float>((1 << 30) - 4)));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("1073741824.0f"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("1073741824.0f"));
 }
 
 TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Float) {
-  WrapInFunction(Construct<f32>(-1.2e-5f));
+    WrapInFunction(Construct<f32>(-1.2e-5f));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("float(-0.000012f)"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("float(-0.000012f)"));
 }
 
 TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Bool) {
-  WrapInFunction(Construct<bool>(true));
+    WrapInFunction(Construct<bool>(true));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("bool(true)"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("bool(true)"));
 }
 
 TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Int) {
-  WrapInFunction(Construct<i32>(-12345));
+    WrapInFunction(Construct<i32>(i32(-12345)));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("int(-12345)"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("int(-12345)"));
 }
 
 TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Uint) {
-  WrapInFunction(Construct<u32>(12345u));
+    WrapInFunction(Construct<u32>(12345_u));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("uint(12345u)"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("uint(12345u)"));
 }
 
 TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Vec) {
-  WrapInFunction(vec3<f32>(1.f, 2.f, 3.f));
+    WrapInFunction(vec3<f32>(1.f, 2.f, 3.f));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("float3(1.0f, 2.0f, 3.0f)"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("float3(1.0f, 2.0f, 3.0f)"));
 }
 
 TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Vec_Empty) {
-  WrapInFunction(vec3<f32>());
+    WrapInFunction(vec3<f32>());
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("float3()"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("float3()"));
 }
 
 TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Mat) {
-  WrapInFunction(Construct(ty.mat2x3<f32>(), vec3<f32>(1.0f, 2.0f, 3.0f),
-                           vec3<f32>(3.0f, 4.0f, 5.0f)));
+    WrapInFunction(
+        Construct(ty.mat2x3<f32>(), vec3<f32>(1.0f, 2.0f, 3.0f), vec3<f32>(3.0f, 4.0f, 5.0f)));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
+    ASSERT_TRUE(gen.Generate()) << gen.error();
 
-  // A matrix of type T with n columns and m rows can also be constructed from
-  // n vectors of type T with m components.
-  EXPECT_THAT(
-      gen.result(),
-      HasSubstr(
-          "float2x3(float3(1.0f, 2.0f, 3.0f), float3(3.0f, 4.0f, 5.0f))"));
+    // A matrix of type T with n columns and m rows can also be constructed from
+    // n vectors of type T with m components.
+    EXPECT_THAT(gen.result(),
+                HasSubstr("float2x3(float3(1.0f, 2.0f, 3.0f), float3(3.0f, 4.0f, 5.0f))"));
 }
 
 TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Mat_Empty) {
-  WrapInFunction(mat4x4<f32>());
+    WrapInFunction(mat4x4<f32>());
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("float4x4()"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("float4x4()"));
 }
 
 TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Array) {
-  WrapInFunction(
-      Construct(ty.array(ty.vec3<f32>(), 3), vec3<f32>(1.0f, 2.0f, 3.0f),
-                vec3<f32>(4.0f, 5.0f, 6.0f), vec3<f32>(7.0f, 8.0f, 9.0f)));
+    WrapInFunction(Construct(ty.array(ty.vec3<f32>(), 3_u), vec3<f32>(1.0f, 2.0f, 3.0f),
+                             vec3<f32>(4.0f, 5.0f, 6.0f), vec3<f32>(7.0f, 8.0f, 9.0f)));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(),
-              HasSubstr("{float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), "
-                        "float3(7.0f, 8.0f, 9.0f)}"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("{float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), "
+                                        "float3(7.0f, 8.0f, 9.0f)}"));
 }
 
 TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Struct) {
-  auto* str = Structure("S", {
-                                 Member("a", ty.i32()),
-                                 Member("b", ty.f32()),
-                                 Member("c", ty.vec3<i32>()),
-                             });
+    auto* str = Structure("S", {
+                                   Member("a", ty.i32()),
+                                   Member("b", ty.f32()),
+                                   Member("c", ty.vec3<i32>()),
+                               });
 
-  WrapInFunction(Construct(ty.Of(str), 1, 2.0f, vec3<i32>(3, 4, 5)));
+    WrapInFunction(Construct(ty.Of(str), 1_i, 2.0f, vec3<i32>(3_i, 4_i, 5_i)));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("{.a=1, .b=2.0f, .c=int3(3, 4, 5)}"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("{.a=1, .b=2.0f, .c=int3(3, 4, 5)}"));
 }
 
 TEST_F(MslGeneratorImplTest, EmitConstructor_Type_Struct_Empty) {
-  auto* str = Structure("S", {
-                                 Member("a", ty.i32()),
-                                 Member("b", ty.f32()),
-                                 Member("c", ty.vec3<i32>()),
-                             });
+    auto* str = Structure("S", {
+                                   Member("a", ty.i32()),
+                                   Member("b", ty.f32()),
+                                   Member("c", ty.vec3<i32>()),
+                               });
 
-  WrapInFunction(Construct(ty.Of(str)));
+    WrapInFunction(Construct(ty.Of(str)));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("{}"));
-  EXPECT_THAT(gen.result(), testing::Not(HasSubstr("{{}}")));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("{}"));
+    EXPECT_THAT(gen.result(), testing::Not(HasSubstr("{{}}")));
 }
 
 }  // namespace
diff --git a/src/tint/writer/msl/generator_impl_continue_test.cc b/src/tint/writer/msl/generator_impl_continue_test.cc
index b6618db..649aae6 100644
--- a/src/tint/writer/msl/generator_impl_continue_test.cc
+++ b/src/tint/writer/msl/generator_impl_continue_test.cc
@@ -20,16 +20,16 @@
 using MslGeneratorImplTest = TestHelper;
 
 TEST_F(MslGeneratorImplTest, Emit_Continue) {
-  auto* loop = Loop(Block(If(false, Block(Break())),  //
-                          Continue()));
-  WrapInFunction(loop);
+    auto* loop = Loop(Block(If(false, Block(Break())),  //
+                            Continue()));
+    WrapInFunction(loop);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(loop)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  while (true) {
+    ASSERT_TRUE(gen.EmitStatement(loop)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  while (true) {
     if (false) {
       break;
     }
diff --git a/src/tint/writer/msl/generator_impl_discard_test.cc b/src/tint/writer/msl/generator_impl_discard_test.cc
index aeea97d..5f5c17f 100644
--- a/src/tint/writer/msl/generator_impl_discard_test.cc
+++ b/src/tint/writer/msl/generator_impl_discard_test.cc
@@ -20,15 +20,15 @@
 using MslGeneratorImplTest = TestHelper;
 
 TEST_F(MslGeneratorImplTest, Emit_Discard) {
-  auto* stmt = create<ast::DiscardStatement>();
-  WrapInFunction(stmt);
+    auto* stmt = create<ast::DiscardStatement>();
+    WrapInFunction(stmt);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
-  EXPECT_EQ(gen.result(), "  discard_fragment();\n");
+    ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
+    EXPECT_EQ(gen.result(), "  discard_fragment();\n");
 }
 
 }  // namespace
diff --git a/src/tint/writer/msl/generator_impl_function_test.cc b/src/tint/writer/msl/generator_impl_function_test.cc
index 41dcbf1..063fda8 100644
--- a/src/tint/writer/msl/generator_impl_function_test.cc
+++ b/src/tint/writer/msl/generator_impl_function_test.cc
@@ -16,24 +16,26 @@
 #include "src/tint/ast/variable_decl_statement.h"
 #include "src/tint/writer/msl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::msl {
 namespace {
 
 using MslGeneratorImplTest = TestHelper;
 
 TEST_F(MslGeneratorImplTest, Emit_Function) {
-  Func("my_func", ast::VariableList{}, ty.void_(),
-       ast::StatementList{
-           Return(),
-       },
-       {});
+    Func("my_func", ast::VariableList{}, ty.void_(),
+         ast::StatementList{
+             Return(),
+         },
+         {});
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  #include <metal_stdlib>
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  #include <metal_stdlib>
 
   using namespace metal;
   void my_func() {
@@ -44,22 +46,22 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_Function_WithParams) {
-  ast::VariableList params;
-  params.push_back(Param("a", ty.f32()));
-  params.push_back(Param("b", ty.i32()));
+    ast::VariableList params;
+    params.push_back(Param("a", ty.f32()));
+    params.push_back(Param("b", ty.i32()));
 
-  Func("my_func", params, ty.void_(),
-       ast::StatementList{
-           Return(),
-       },
-       {});
+    Func("my_func", params, ty.void_(),
+         ast::StatementList{
+             Return(),
+         },
+         {});
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  #include <metal_stdlib>
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  #include <metal_stdlib>
 
   using namespace metal;
   void my_func(float a, int b) {
@@ -70,14 +72,13 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_Attribute_EntryPoint_NoReturn_Void) {
-  Func("main", ast::VariableList{}, ty.void_(),
-       ast::StatementList{/* no explicit return */},
-       {Stage(ast::PipelineStage::kFragment)});
+    Func("main", ast::VariableList{}, ty.void_(), ast::StatementList{/* no explicit return */},
+         {Stage(ast::PipelineStage::kFragment)});
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
 
 using namespace metal;
 fragment void main() {
@@ -88,17 +89,17 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_Attribute_EntryPoint_WithInOutVars) {
-  // fn frag_main(@location(0) foo : f32) -> @location(1) f32 {
-  //   return foo;
-  // }
-  auto* foo_in = Param("foo", ty.f32(), {Location(0)});
-  Func("frag_main", ast::VariableList{foo_in}, ty.f32(), {Return("foo")},
-       {Stage(ast::PipelineStage::kFragment)}, {Location(1)});
+    // fn frag_main(@location(0) foo : f32) -> @location(1) f32 {
+    //   return foo;
+    // }
+    auto* foo_in = Param("foo", ty.f32(), {Location(0)});
+    Func("frag_main", ast::VariableList{foo_in}, ty.f32(), {Return("foo")},
+         {Stage(ast::PipelineStage::kFragment)}, {Location(1)});
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
 
 using namespace metal;
 struct tint_symbol_1 {
@@ -124,20 +125,17 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_Attribute_EntryPoint_WithInOut_Builtins) {
-  // 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)});
-  Func("frag_main", ast::VariableList{coord_in}, ty.f32(),
-       {Return(MemberAccessor("coord", "x"))},
-       {Stage(ast::PipelineStage::kFragment)},
-       {Builtin(ast::Builtin::kFragDepth)});
+    // 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)});
+    Func("frag_main", ast::VariableList{coord_in}, ty.f32(), {Return(MemberAccessor("coord", "x"))},
+         {Stage(ast::PipelineStage::kFragment)}, {Builtin(ast::Builtin::kFragDepth)});
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
 
 using namespace metal;
 struct tint_symbol {
@@ -158,46 +156,42 @@
 )");
 }
 
-TEST_F(MslGeneratorImplTest,
-       Emit_Attribute_EntryPoint_SharedStruct_DifferentStages) {
-  // struct Interface {
-  //   @location(1) col1 : f32;
-  //   @location(2) col2 : f32;
-  //   @builtin(position) pos : vec4<f32>;
-  // };
-  // fn vert_main() -> Interface {
-  //   return Interface(0.4, 0.6, vec4<f32>());
-  // }
-  // fn frag_main(colors : Interface) {
-  //   const r = colors.col1;
-  //   const g = colors.col2;
-  // }
-  auto* interface_struct = Structure(
-      "Interface",
-      {
-          Member("col1", ty.f32(), {Location(1)}),
-          Member("col2", ty.f32(), {Location(2)}),
-          Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)}),
-      });
+TEST_F(MslGeneratorImplTest, Emit_Attribute_EntryPoint_SharedStruct_DifferentStages) {
+    // struct Interface {
+    //   @location(1) col1 : f32;
+    //   @location(2) col2 : f32;
+    //   @builtin(position) pos : vec4<f32>;
+    // };
+    // fn vert_main() -> Interface {
+    //   return Interface(0.4, 0.6, vec4<f32>());
+    // }
+    // fn frag_main(colors : Interface) {
+    //   const r = colors.col1;
+    //   const g = colors.col2;
+    // }
+    auto* interface_struct = Structure(
+        "Interface", {
+                         Member("col1", ty.f32(), {Location(1)}),
+                         Member("col2", ty.f32(), {Location(2)}),
+                         Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)}),
+                     });
 
-  Func("vert_main", {}, ty.Of(interface_struct),
-       {Return(Construct(ty.Of(interface_struct), Expr(0.5f), Expr(0.25f),
-                         Construct(ty.vec4<f32>())))},
-       {Stage(ast::PipelineStage::kVertex)});
+    Func("vert_main", {}, ty.Of(interface_struct),
+         {Return(Construct(ty.Of(interface_struct), Expr(0.5f), Expr(0.25f),
+                           Construct(ty.vec4<f32>())))},
+         {Stage(ast::PipelineStage::kVertex)});
 
-  Func("frag_main", {Param("colors", ty.Of(interface_struct))}, ty.void_(),
-       {
-           WrapInStatement(
-               Const("r", ty.f32(), MemberAccessor("colors", "col1"))),
-           WrapInStatement(
-               Const("g", ty.f32(), MemberAccessor("colors", "col2"))),
-       },
-       {Stage(ast::PipelineStage::kFragment)});
+    Func("frag_main", {Param("colors", ty.Of(interface_struct))}, ty.void_(),
+         {
+             WrapInStatement(Let("r", ty.f32(), MemberAccessor("colors", "col1"))),
+             WrapInStatement(Let("g", ty.f32(), MemberAccessor("colors", "col2"))),
+         },
+         {Stage(ast::PipelineStage::kFragment)});
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
 
 using namespace metal;
 struct Interface {
@@ -245,41 +239,37 @@
 )");
 }
 
-TEST_F(MslGeneratorImplTest,
-       Emit_Attribute_EntryPoint_SharedStruct_HelperFunction) {
-  // struct VertexOutput {
-  //   @builtin(position) pos : vec4<f32>;
-  // };
-  // fn foo(x : f32) -> VertexOutput {
-  //   return VertexOutput(vec4<f32>(x, x, x, 1.0));
-  // }
-  // fn vert_main1() -> VertexOutput {
-  //   return foo(0.5);
-  // }
-  // fn vert_main2() -> VertexOutput {
-  //   return foo(0.25);
-  // }
-  auto* vertex_output_struct = Structure(
-      "VertexOutput",
-      {Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)})});
+TEST_F(MslGeneratorImplTest, Emit_Attribute_EntryPoint_SharedStruct_HelperFunction) {
+    // struct VertexOutput {
+    //   @builtin(position) pos : vec4<f32>;
+    // };
+    // fn foo(x : f32) -> VertexOutput {
+    //   return VertexOutput(vec4<f32>(x, x, x, 1.0));
+    // }
+    // fn vert_main1() -> VertexOutput {
+    //   return foo(0.5);
+    // }
+    // fn vert_main2() -> VertexOutput {
+    //   return foo(0.25);
+    // }
+    auto* vertex_output_struct = Structure(
+        "VertexOutput", {Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)})});
 
-  Func("foo", {Param("x", ty.f32())}, ty.Of(vertex_output_struct),
-       {Return(Construct(ty.Of(vertex_output_struct),
-                         Construct(ty.vec4<f32>(), "x", "x", "x", Expr(1.f))))},
-       {});
+    Func("foo", {Param("x", ty.f32())}, ty.Of(vertex_output_struct),
+         {Return(Construct(ty.Of(vertex_output_struct),
+                           Construct(ty.vec4<f32>(), "x", "x", "x", Expr(1.f))))},
+         {});
 
-  Func("vert_main1", {}, ty.Of(vertex_output_struct),
-       {Return(Expr(Call("foo", Expr(0.5f))))},
-       {Stage(ast::PipelineStage::kVertex)});
+    Func("vert_main1", {}, ty.Of(vertex_output_struct), {Return(Expr(Call("foo", Expr(0.5f))))},
+         {Stage(ast::PipelineStage::kVertex)});
 
-  Func("vert_main2", {}, ty.Of(vertex_output_struct),
-       {Return(Expr(Call("foo", Expr(0.25f))))},
-       {Stage(ast::PipelineStage::kVertex)});
+    Func("vert_main2", {}, ty.Of(vertex_output_struct), {Return(Expr(Call("foo", Expr(0.25f))))},
+         {Stage(ast::PipelineStage::kVertex)});
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
 
 using namespace metal;
 struct VertexOutput {
@@ -324,36 +314,33 @@
 )");
 }
 
-TEST_F(MslGeneratorImplTest,
-       Emit_FunctionAttribute_EntryPoint_With_RW_StorageBuffer) {
-  auto* s = Structure("Data", {
-                                  Member("a", ty.i32()),
-                                  Member("b", ty.f32()),
-                              });
+TEST_F(MslGeneratorImplTest, Emit_FunctionAttribute_EntryPoint_With_RW_StorageBuffer) {
+    auto* s = Structure("Data", {
+                                    Member("a", ty.i32()),
+                                    Member("b", ty.f32()),
+                                });
 
-  Global("coord", ty.Of(s), ast::StorageClass::kStorage,
-         ast::Access::kReadWrite,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
+    Global("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
+
+    auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, MemberAccessor("coord", "b"));
+
+    Func("frag_main", ast::VariableList{}, ty.void_(),
+         ast::StatementList{
+             Decl(var),
+             Return(),
+         },
+         {
+             Stage(ast::PipelineStage::kFragment),
          });
 
-  auto* var = Var("v", ty.f32(), ast::StorageClass::kNone,
-                  MemberAccessor("coord", "b"));
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  Func("frag_main", ast::VariableList{}, ty.void_(),
-       ast::StatementList{
-           Decl(var),
-           Return(),
-       },
-       {
-           Stage(ast::PipelineStage::kFragment),
-       });
-
-  GeneratorImpl& gen = SanitizeAndBuild();
-
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
 
 using namespace metal;
 struct Data {
@@ -369,35 +356,33 @@
 )");
 }
 
-TEST_F(MslGeneratorImplTest,
-       Emit_FunctionAttribute_EntryPoint_With_RO_StorageBuffer) {
-  auto* s = Structure("Data", {
-                                  Member("a", ty.i32()),
-                                  Member("b", ty.f32()),
-                              });
+TEST_F(MslGeneratorImplTest, Emit_FunctionAttribute_EntryPoint_With_RO_StorageBuffer) {
+    auto* s = Structure("Data", {
+                                    Member("a", ty.i32()),
+                                    Member("b", ty.f32()),
+                                });
 
-  Global("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
+    Global("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
+
+    auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, MemberAccessor("coord", "b"));
+
+    Func("frag_main", ast::VariableList{}, ty.void_(),
+         ast::StatementList{
+             Decl(var),
+             Return(),
+         },
+         {
+             Stage(ast::PipelineStage::kFragment),
          });
 
-  auto* var = Var("v", ty.f32(), ast::StorageClass::kNone,
-                  MemberAccessor("coord", "b"));
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  Func("frag_main", ast::VariableList{}, ty.void_(),
-       ast::StatementList{
-           Decl(var),
-           Return(),
-       },
-       {
-           Stage(ast::PipelineStage::kFragment),
-       });
-
-  GeneratorImpl& gen = SanitizeAndBuild();
-
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
 
 using namespace metal;
 struct Data {
@@ -414,38 +399,37 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_Attribute_Called_By_EntryPoint_With_Uniform) {
-  auto* ubo_ty = Structure("UBO", {Member("coord", ty.vec4<f32>())});
-  auto* ubo = Global("ubo", ty.Of(ubo_ty), ast::StorageClass::kUniform,
-                     ast::AttributeList{
-                         create<ast::BindingAttribute>(0),
-                         create<ast::GroupAttribute>(0),
-                     });
+    auto* ubo_ty = Structure("UBO", {Member("coord", ty.vec4<f32>())});
+    auto* ubo = Global("ubo", ty.Of(ubo_ty), ast::StorageClass::kUniform,
+                       ast::AttributeList{
+                           create<ast::BindingAttribute>(0),
+                           create<ast::GroupAttribute>(0),
+                       });
 
-  Func("sub_func",
-       {
-           Param("param", ty.f32()),
-       },
-       ty.f32(),
-       {
-           Return(MemberAccessor(MemberAccessor(ubo, "coord"), "x")),
-       });
+    Func("sub_func",
+         {
+             Param("param", ty.f32()),
+         },
+         ty.f32(),
+         {
+             Return(MemberAccessor(MemberAccessor(ubo, "coord"), "x")),
+         });
 
-  auto* var =
-      Var("v", ty.f32(), ast::StorageClass::kNone, Call("sub_func", 1.0f));
+    auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, Call("sub_func", 1.0f));
 
-  Func("frag_main", {}, ty.void_(),
-       {
-           Decl(var),
-           Return(),
-       },
-       {
-           Stage(ast::PipelineStage::kFragment),
-       });
+    Func("frag_main", {}, ty.void_(),
+         {
+             Decl(var),
+             Return(),
+         },
+         {
+             Stage(ast::PipelineStage::kFragment),
+         });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
 
 using namespace metal;
 struct UBO {
@@ -464,43 +448,40 @@
 )");
 }
 
-TEST_F(MslGeneratorImplTest,
-       Emit_FunctionAttribute_Called_By_EntryPoint_With_RW_StorageBuffer) {
-  auto* s = Structure("Data", {
-                                  Member("a", ty.i32()),
-                                  Member("b", ty.f32()),
-                              });
+TEST_F(MslGeneratorImplTest, Emit_FunctionAttribute_Called_By_EntryPoint_With_RW_StorageBuffer) {
+    auto* s = Structure("Data", {
+                                    Member("a", ty.i32()),
+                                    Member("b", ty.f32()),
+                                });
 
-  Global("coord", ty.Of(s), ast::StorageClass::kStorage,
-         ast::Access::kReadWrite,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
+    Global("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
+
+    ast::VariableList params;
+    params.push_back(Param("param", ty.f32()));
+
+    auto body = ast::StatementList{Return(MemberAccessor("coord", "b"))};
+
+    Func("sub_func", params, ty.f32(), body, {});
+
+    auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, Call("sub_func", 1.0f));
+
+    Func("frag_main", ast::VariableList{}, ty.void_(),
+         ast::StatementList{
+             Decl(var),
+             Return(),
+         },
+         {
+             Stage(ast::PipelineStage::kFragment),
          });
 
-  ast::VariableList params;
-  params.push_back(Param("param", ty.f32()));
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  auto body = ast::StatementList{Return(MemberAccessor("coord", "b"))};
-
-  Func("sub_func", params, ty.f32(), body, {});
-
-  auto* var =
-      Var("v", ty.f32(), ast::StorageClass::kNone, Call("sub_func", 1.0f));
-
-  Func("frag_main", ast::VariableList{}, ty.void_(),
-       ast::StatementList{
-           Decl(var),
-           Return(),
-       },
-       {
-           Stage(ast::PipelineStage::kFragment),
-       });
-
-  GeneratorImpl& gen = SanitizeAndBuild();
-
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
 
 using namespace metal;
 struct Data {
@@ -520,42 +501,40 @@
 )");
 }
 
-TEST_F(MslGeneratorImplTest,
-       Emit_FunctionAttribute_Called_By_EntryPoint_With_RO_StorageBuffer) {
-  auto* s = Structure("Data", {
-                                  Member("a", ty.i32()),
-                                  Member("b", ty.f32()),
-                              });
+TEST_F(MslGeneratorImplTest, Emit_FunctionAttribute_Called_By_EntryPoint_With_RO_StorageBuffer) {
+    auto* s = Structure("Data", {
+                                    Member("a", ty.i32()),
+                                    Member("b", ty.f32()),
+                                });
 
-  Global("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
+    Global("coord", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
+
+    ast::VariableList params;
+    params.push_back(Param("param", ty.f32()));
+
+    auto body = ast::StatementList{Return(MemberAccessor("coord", "b"))};
+
+    Func("sub_func", params, ty.f32(), body, {});
+
+    auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, Call("sub_func", 1.0f));
+
+    Func("frag_main", ast::VariableList{}, ty.void_(),
+         ast::StatementList{
+             Decl(var),
+             Return(),
+         },
+         {
+             Stage(ast::PipelineStage::kFragment),
          });
 
-  ast::VariableList params;
-  params.push_back(Param("param", ty.f32()));
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  auto body = ast::StatementList{Return(MemberAccessor("coord", "b"))};
-
-  Func("sub_func", params, ty.f32(), body, {});
-
-  auto* var =
-      Var("v", ty.f32(), ast::StorageClass::kNone, Call("sub_func", 1.0f));
-
-  Func("frag_main", ast::VariableList{}, ty.void_(),
-       ast::StatementList{
-           Decl(var),
-           Return(),
-       },
-       {
-           Stage(ast::PipelineStage::kFragment),
-       });
-
-  GeneratorImpl& gen = SanitizeAndBuild();
-
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
 
 using namespace metal;
 struct Data {
@@ -576,20 +555,20 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_Function_WithArrayParams) {
-  ast::VariableList params;
-  params.push_back(Param("a", ty.array<f32, 5>()));
+    ast::VariableList params;
+    params.push_back(Param("a", ty.array<f32, 5>()));
 
-  Func("my_func", params, ty.void_(),
-       {
-           Return(),
-       });
+    Func("my_func", params, ty.void_(),
+         {
+             Return(),
+         });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  #include <metal_stdlib>
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  #include <metal_stdlib>
 
   using namespace metal;
   struct tint_array_wrapper {
@@ -604,17 +583,17 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_Function_WithArrayReturn) {
-  Func("my_func", {}, ty.array<f32, 5>(),
-       {
-           Return(Construct(ty.array<f32, 5>())),
-       });
+    Func("my_func", {}, ty.array<f32, 5>(),
+         {
+             Return(Construct(ty.array<f32, 5>())),
+         });
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  #include <metal_stdlib>
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  #include <metal_stdlib>
 
   using namespace metal;
   struct tint_array_wrapper {
@@ -630,62 +609,58 @@
 }
 
 // https://crbug.com/tint/297
-TEST_F(MslGeneratorImplTest,
-       Emit_Function_Multiple_EntryPoint_With_Same_ModuleVar) {
-  // struct Data {
-  //   d : f32;
-  // };
-  // @binding(0) @group(0) var<storage> data : Data;
-  //
-  // @stage(compute) @workgroup_size(1)
-  // fn a() {
-  //   return;
-  // }
-  //
-  // @stage(compute) @workgroup_size(1)
-  // fn b() {
-  //   return;
-  // }
+TEST_F(MslGeneratorImplTest, Emit_Function_Multiple_EntryPoint_With_Same_ModuleVar) {
+    // struct Data {
+    //   d : f32;
+    // };
+    // @binding(0) @group(0) var<storage> data : Data;
+    //
+    // @stage(compute) @workgroup_size(1)
+    // fn a() {
+    //   return;
+    // }
+    //
+    // @stage(compute) @workgroup_size(1)
+    // fn b() {
+    //   return;
+    // }
 
-  auto* s = Structure("Data", {Member("d", ty.f32())});
+    auto* s = Structure("Data", {Member("d", ty.f32())});
 
-  Global("data", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    Global("data", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  {
-    auto* var = Var("v", ty.f32(), ast::StorageClass::kNone,
-                    MemberAccessor("data", "d"));
+    {
+        auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, MemberAccessor("data", "d"));
 
-    Func("a", ast::VariableList{}, ty.void_(),
-         ast::StatementList{
-             Decl(var),
-             Return(),
-         },
-         {
-             Stage(ast::PipelineStage::kCompute),
-             WorkgroupSize(1),
-         });
-  }
+        Func("a", ast::VariableList{}, ty.void_(),
+             ast::StatementList{
+                 Decl(var),
+                 Return(),
+             },
+             {
+                 Stage(ast::PipelineStage::kCompute),
+                 WorkgroupSize(1_i),
+             });
+    }
 
-  {
-    auto* var = Var("v", ty.f32(), ast::StorageClass::kNone,
-                    MemberAccessor("data", "d"));
+    {
+        auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, MemberAccessor("data", "d"));
 
-    Func("b", ast::VariableList{}, ty.void_(),
-         ast::StatementList{Decl(var), Return()},
-         {
-             Stage(ast::PipelineStage::kCompute),
-             WorkgroupSize(1),
-         });
-  }
+        Func("b", ast::VariableList{}, ty.void_(), ast::StatementList{Decl(var), Return()},
+             {
+                 Stage(ast::PipelineStage::kCompute),
+                 WorkgroupSize(1_i),
+             });
+    }
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
 
 using namespace metal;
 struct Data {
diff --git a/src/tint/writer/msl/generator_impl_identifier_test.cc b/src/tint/writer/msl/generator_impl_identifier_test.cc
index ea7a617..a625776 100644
--- a/src/tint/writer/msl/generator_impl_identifier_test.cc
+++ b/src/tint/writer/msl/generator_impl_identifier_test.cc
@@ -20,16 +20,16 @@
 using MslGeneratorImplTest = TestHelper;
 
 TEST_F(MslGeneratorImplTest, EmitIdentifierExpression) {
-  auto* foo = Var("foo", ty.i32());
+    auto* foo = Var("foo", ty.i32());
 
-  auto* i = Expr("foo");
-  WrapInFunction(foo, i);
+    auto* i = Expr("foo");
+    WrapInFunction(foo, i);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, i)) << gen.error();
-  EXPECT_EQ(out.str(), "foo");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, i)) << gen.error();
+    EXPECT_EQ(out.str(), "foo");
 }
 
 }  // namespace
diff --git a/src/tint/writer/msl/generator_impl_if_test.cc b/src/tint/writer/msl/generator_impl_if_test.cc
index ff0cabc..5138dce 100644
--- a/src/tint/writer/msl/generator_impl_if_test.cc
+++ b/src/tint/writer/msl/generator_impl_if_test.cc
@@ -20,33 +20,33 @@
 using MslGeneratorImplTest = TestHelper;
 
 TEST_F(MslGeneratorImplTest, Emit_If) {
-  auto* cond = Var("cond", ty.bool_());
-  auto* i = If(cond, Block(Return()));
-  WrapInFunction(cond, i);
+    auto* cond = Var("cond", ty.bool_());
+    auto* i = If(cond, Block(Return()));
+    WrapInFunction(cond, i);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(i)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  if (cond) {
+    ASSERT_TRUE(gen.EmitStatement(i)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  if (cond) {
     return;
   }
 )");
 }
 
 TEST_F(MslGeneratorImplTest, Emit_IfWithElseIf) {
-  auto* cond = Var("cond", ty.bool_());
-  auto* else_cond = Var("else_cond", ty.bool_());
-  auto* i = If(cond, Block(Return()), Else(else_cond, Block(Return())));
-  WrapInFunction(cond, else_cond, i);
+    auto* cond = Var("cond", ty.bool_());
+    auto* else_cond = Var("else_cond", ty.bool_());
+    auto* i = If(cond, Block(Return()), Else(If(else_cond, Block(Return()))));
+    WrapInFunction(cond, else_cond, i);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(i)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  if (cond) {
+    ASSERT_TRUE(gen.EmitStatement(i)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  if (cond) {
     return;
   } else {
     if (else_cond) {
@@ -57,16 +57,16 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_IfWithElse) {
-  auto* cond = Var("cond", ty.bool_());
-  auto* i = If(cond, Block(Return()), Else(nullptr, Block(Return())));
-  WrapInFunction(cond, i);
+    auto* cond = Var("cond", ty.bool_());
+    auto* i = If(cond, Block(Return()), Else(Block(Return())));
+    WrapInFunction(cond, i);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(i)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  if (cond) {
+    ASSERT_TRUE(gen.EmitStatement(i)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  if (cond) {
     return;
   } else {
     return;
@@ -75,18 +75,18 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_IfWithMultiple) {
-  auto* cond = Var("cond", ty.bool_());
-  auto* else_cond = Var("else_cond", ty.bool_());
-  auto* i = If(cond, Block(Return()), Else(else_cond, Block(Return())),
-               Else(nullptr, Block(Return())));
-  WrapInFunction(cond, else_cond, i);
+    auto* cond = Var("cond", ty.bool_());
+    auto* else_cond = Var("else_cond", ty.bool_());
+    auto* i =
+        If(cond, Block(Return()), Else(If(else_cond, Block(Return()), Else(Block(Return())))));
+    WrapInFunction(cond, else_cond, i);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(i)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  if (cond) {
+    ASSERT_TRUE(gen.EmitStatement(i)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  if (cond) {
     return;
   } else {
     if (else_cond) {
diff --git a/src/tint/writer/msl/generator_impl_import_test.cc b/src/tint/writer/msl/generator_impl_import_test.cc
index b7cfddb..fa5519a 100644
--- a/src/tint/writer/msl/generator_impl_import_test.cc
+++ b/src/tint/writer/msl/generator_impl_import_test.cc
@@ -15,37 +15,39 @@
 #include "src/tint/sem/call.h"
 #include "src/tint/writer/msl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::msl {
 namespace {
 
 using MslGeneratorImplTest = TestHelper;
 
 struct MslImportData {
-  const char* name;
-  const char* msl_name;
+    const char* name;
+    const char* msl_name;
 };
 inline std::ostream& operator<<(std::ostream& out, MslImportData data) {
-  out << data.name;
-  return out;
+    out << data.name;
+    return out;
 }
 using MslImportData_SingleParamTest = TestParamHelper<MslImportData>;
 TEST_P(MslImportData_SingleParamTest, FloatScalar) {
-  auto param = GetParam();
-  auto* call = Call(param.name, 1.f);
+    auto param = GetParam();
+    auto* call = Call(param.name, 1.f);
 
-  // The resolver will set the builtin data for the ident
-  WrapInFunction(call);
+    // The resolver will set the builtin data for the ident
+    WrapInFunction(call);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  auto* sem = program->Sem().Get(call);
-  ASSERT_NE(sem, nullptr);
-  auto* target = sem->Target();
-  ASSERT_NE(target, nullptr);
-  auto* builtin = target->As<sem::Builtin>();
-  ASSERT_NE(builtin, nullptr);
+    auto* sem = program->Sem().Get(call);
+    ASSERT_NE(sem, nullptr);
+    auto* target = sem->Target();
+    ASSERT_NE(target, nullptr);
+    auto* builtin = target->As<sem::Builtin>();
+    ASSERT_NE(builtin, nullptr);
 
-  ASSERT_EQ(gen.generate_builtin_name(builtin), param.msl_name);
+    ASSERT_EQ(gen.generate_builtin_name(builtin), param.msl_name);
 }
 INSTANTIATE_TEST_SUITE_P(MslGeneratorImplTest,
                          MslImportData_SingleParamTest,
@@ -74,39 +76,39 @@
                                          MslImportData{"trunc", "trunc"}));
 
 TEST_F(MslGeneratorImplTest, MslImportData_SingleParamTest_IntScalar) {
-  auto* expr = Call("abs", 1);
-  WrapInFunction(expr);
+    auto* expr = Call("abs", 1_i);
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), R"(abs(1))");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), R"(abs(1))");
 }
 
 TEST_F(MslGeneratorImplTest, MslImportData_SingleParamTest_ScalarLength) {
-  auto* expr = Call("length", 2.f);
-  WrapInFunction(expr);
+    auto* expr = Call("length", 2.f);
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), R"(fabs(2.0f))");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), R"(fabs(2.0f))");
 }
 
 using MslImportData_DualParam_ScalarTest = TestParamHelper<MslImportData>;
 TEST_P(MslImportData_DualParam_ScalarTest, Float) {
-  auto param = GetParam();
-  auto* expr = Call(param.name, 1.0f, 2.0f);
+    auto param = GetParam();
+    auto* expr = Call(param.name, 1.0f, 2.0f);
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), std::string(param.msl_name) + "(1.0f, 2.0f)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), std::string(param.msl_name) + "(1.0f, 2.0f)");
 }
 INSTANTIATE_TEST_SUITE_P(MslGeneratorImplTest,
                          MslImportData_DualParam_ScalarTest,
@@ -117,31 +119,29 @@
                                          MslImportData{"step", "step"}));
 
 TEST_F(MslGeneratorImplTest, MslImportData_DualParam_ScalarDistance) {
-  auto* expr = Call("distance", 2.f, 3.f);
-  WrapInFunction(expr);
+    auto* expr = Call("distance", 2.f, 3.f);
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), R"(fabs(2.0f - 3.0f))");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), R"(fabs(2.0f - 3.0f))");
 }
 
 using MslImportData_DualParam_VectorTest = TestParamHelper<MslImportData>;
 TEST_P(MslImportData_DualParam_VectorTest, Float) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* expr =
-      Call(param.name, vec3<f32>(1.f, 2.f, 3.f), vec3<f32>(4.f, 5.f, 6.f));
-  WrapInFunction(expr);
+    auto* expr = Call(param.name, vec3<f32>(1.f, 2.f, 3.f), vec3<f32>(4.f, 5.f, 6.f));
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(),
-            std::string(param.msl_name) +
-                R"((float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f)))");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), std::string(param.msl_name) +
+                             R"((float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f)))");
 }
 INSTANTIATE_TEST_SUITE_P(MslGeneratorImplTest,
                          MslImportData_DualParam_VectorTest,
@@ -156,80 +156,77 @@
 
 using MslImportData_DualParam_Int_Test = TestParamHelper<MslImportData>;
 TEST_P(MslImportData_DualParam_Int_Test, IntScalar) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* expr = Call(param.name, 1, 2);
-  WrapInFunction(expr);
+    auto* expr = Call(param.name, 1_i, 2_i);
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), std::string(param.msl_name) + "(1, 2)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), std::string(param.msl_name) + "(1, 2)");
 }
 INSTANTIATE_TEST_SUITE_P(MslGeneratorImplTest,
                          MslImportData_DualParam_Int_Test,
-                         testing::Values(MslImportData{"max", "max"},
-                                         MslImportData{"min", "min"}));
+                         testing::Values(MslImportData{"max", "max"}, MslImportData{"min", "min"}));
 
 using MslImportData_TripleParam_ScalarTest = TestParamHelper<MslImportData>;
 TEST_P(MslImportData_TripleParam_ScalarTest, Float) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* expr = Call(param.name, 1.f, 2.f, 3.f);
-  WrapInFunction(expr);
+    auto* expr = Call(param.name, 1.f, 2.f, 3.f);
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), std::string(param.msl_name) + "(1.0f, 2.0f, 3.0f)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), std::string(param.msl_name) + "(1.0f, 2.0f, 3.0f)");
 }
 INSTANTIATE_TEST_SUITE_P(MslGeneratorImplTest,
                          MslImportData_TripleParam_ScalarTest,
                          testing::Values(MslImportData{"fma", "fma"},
                                          MslImportData{"mix", "mix"},
                                          MslImportData{"clamp", "clamp"},
-                                         MslImportData{"smoothstep",
-                                                       "smoothstep"}));
+                                         MslImportData{"smoothstep", "smoothstep"}));
 
 using MslImportData_TripleParam_VectorTest = TestParamHelper<MslImportData>;
 TEST_P(MslImportData_TripleParam_VectorTest, Float) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* expr = Call(param.name, vec3<f32>(1.f, 2.f, 3.f),
-                    vec3<f32>(4.f, 5.f, 6.f), vec3<f32>(7.f, 8.f, 9.f));
-  WrapInFunction(expr);
+    auto* expr = Call(param.name, vec3<f32>(1.f, 2.f, 3.f), vec3<f32>(4.f, 5.f, 6.f),
+                      vec3<f32>(7.f, 8.f, 9.f));
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
-  EXPECT_EQ(
-      out.str(),
-      std::string(param.msl_name) +
-          R"((float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f)))");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
+    EXPECT_EQ(
+        out.str(),
+        std::string(param.msl_name) +
+            R"((float3(1.0f, 2.0f, 3.0f), float3(4.0f, 5.0f, 6.0f), float3(7.0f, 8.0f, 9.0f)))");
 }
-INSTANTIATE_TEST_SUITE_P(
-    MslGeneratorImplTest,
-    MslImportData_TripleParam_VectorTest,
-    testing::Values(MslImportData{"faceForward", "faceforward"},
-                    MslImportData{"fma", "fma"},
-                    MslImportData{"clamp", "clamp"},
-                    MslImportData{"smoothstep", "smoothstep"}));
+INSTANTIATE_TEST_SUITE_P(MslGeneratorImplTest,
+                         MslImportData_TripleParam_VectorTest,
+                         testing::Values(MslImportData{"faceForward", "faceforward"},
+                                         MslImportData{"fma", "fma"},
+                                         MslImportData{"clamp", "clamp"},
+                                         MslImportData{"smoothstep", "smoothstep"}));
 
 using MslImportData_TripleParam_Int_Test = TestParamHelper<MslImportData>;
 TEST_P(MslImportData_TripleParam_Int_Test, IntScalar) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* expr = Call(param.name, 1, 2, 3);
-  WrapInFunction(expr);
+    auto* expr = Call(param.name, 1_i, 2_i, 3_i);
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), std::string(param.msl_name) + "(1, 2, 3)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), std::string(param.msl_name) + "(1, 2, 3)");
 }
 INSTANTIATE_TEST_SUITE_P(MslGeneratorImplTest,
                          MslImportData_TripleParam_Int_Test,
@@ -237,17 +234,17 @@
                                          MslImportData{"clamp", "clamp"}));
 
 TEST_F(MslGeneratorImplTest, MslImportData_Determinant) {
-  Global("var", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
+    Global("var", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
 
-  auto* expr = Call("determinant", "var");
+    auto* expr = Call("determinant", "var");
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), std::string("determinant(var)"));
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitCall(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), std::string("determinant(var)"));
 }
 
 }  // namespace
diff --git a/src/tint/writer/msl/generator_impl_loop_test.cc b/src/tint/writer/msl/generator_impl_loop_test.cc
index e31b640..1df7486 100644
--- a/src/tint/writer/msl/generator_impl_loop_test.cc
+++ b/src/tint/writer/msl/generator_impl_loop_test.cc
@@ -15,42 +15,44 @@
 #include "src/tint/ast/variable_decl_statement.h"
 #include "src/tint/writer/msl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::msl {
 namespace {
 
 using MslGeneratorImplTest = TestHelper;
 
 TEST_F(MslGeneratorImplTest, Emit_Loop) {
-  auto* body = Block(create<ast::DiscardStatement>());
-  auto* continuing = Block();
-  auto* l = Loop(body, continuing);
-  WrapInFunction(l);
+    auto* body = Block(create<ast::DiscardStatement>());
+    auto* continuing = Block();
+    auto* l = Loop(body, continuing);
+    WrapInFunction(l);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(l)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  while (true) {
+    ASSERT_TRUE(gen.EmitStatement(l)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  while (true) {
     discard_fragment();
   }
 )");
 }
 
 TEST_F(MslGeneratorImplTest, Emit_LoopWithContinuing) {
-  Func("a_statement", {}, ty.void_(), {});
+    Func("a_statement", {}, ty.void_(), {});
 
-  auto* body = Block(create<ast::DiscardStatement>());
-  auto* continuing = Block(CallStmt(Call("a_statement")));
-  auto* l = Loop(body, continuing);
-  WrapInFunction(l);
+    auto* body = Block(create<ast::DiscardStatement>());
+    auto* continuing = Block(CallStmt(Call("a_statement")));
+    auto* l = Loop(body, continuing);
+    WrapInFunction(l);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(l)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  while (true) {
+    ASSERT_TRUE(gen.EmitStatement(l)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  while (true) {
     discard_fragment();
     {
       a_statement();
@@ -60,28 +62,28 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_LoopNestedWithContinuing) {
-  Func("a_statement", {}, ty.void_(), {});
+    Func("a_statement", {}, ty.void_(), {});
 
-  Global("lhs", ty.f32(), ast::StorageClass::kPrivate);
-  Global("rhs", ty.f32(), ast::StorageClass::kPrivate);
+    Global("lhs", ty.f32(), ast::StorageClass::kPrivate);
+    Global("rhs", ty.f32(), ast::StorageClass::kPrivate);
 
-  auto* body = Block(create<ast::DiscardStatement>());
-  auto* continuing = Block(CallStmt(Call("a_statement")));
-  auto* inner = Loop(body, continuing);
+    auto* body = Block(create<ast::DiscardStatement>());
+    auto* continuing = Block(CallStmt(Call("a_statement")));
+    auto* inner = Loop(body, continuing);
 
-  body = Block(inner);
+    body = Block(inner);
 
-  continuing = Block(Assign("lhs", "rhs"));
+    continuing = Block(Assign("lhs", "rhs"));
 
-  auto* outer = Loop(body, continuing);
-  WrapInFunction(outer);
+    auto* outer = Loop(body, continuing);
+    WrapInFunction(outer);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(outer)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  while (true) {
+    ASSERT_TRUE(gen.EmitStatement(outer)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  while (true) {
     while (true) {
       discard_fragment();
       {
@@ -96,31 +98,31 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_LoopWithVarUsedInContinuing) {
-  // loop {
-  //   var lhs : f32 = 2.4;
-  //   var other : f32;
-  //   continuing {
-  //     lhs = rhs
-  //   }
-  // }
-  //
+    // loop {
+    //   var lhs : f32 = 2.4;
+    //   var other : f32;
+    //   continuing {
+    //     lhs = rhs
+    //   }
+    // }
+    //
 
-  Global("rhs", ty.f32(), ast::StorageClass::kPrivate);
+    Global("rhs", ty.f32(), ast::StorageClass::kPrivate);
 
-  auto* body = Block(Decl(Var("lhs", ty.f32(), Expr(2.4f))),  //
-                     Decl(Var("other", ty.f32())),            //
-                     Break());
+    auto* body = Block(Decl(Var("lhs", ty.f32(), Expr(2.4f))),  //
+                       Decl(Var("other", ty.f32())),            //
+                       Break());
 
-  auto* continuing = Block(Assign("lhs", "rhs"));
-  auto* outer = Loop(body, continuing);
-  WrapInFunction(outer);
+    auto* continuing = Block(Assign("lhs", "rhs"));
+    auto* outer = Loop(body, continuing);
+    WrapInFunction(outer);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(outer)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  while (true) {
+    ASSERT_TRUE(gen.EmitStatement(outer)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  while (true) {
     float lhs = 2.400000095f;
     float other = 0.0f;
     break;
@@ -132,68 +134,68 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_ForLoop) {
-  // for(; ; ) {
-  //   return;
-  // }
+    // for(; ; ) {
+    //   return;
+    // }
 
-  auto* f = For(nullptr, nullptr, nullptr,  //
-                Block(Return()));
-  WrapInFunction(f);
+    auto* f = For(nullptr, nullptr, nullptr,  //
+                  Block(Return()));
+    WrapInFunction(f);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  for(; ; ) {
+    ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  for(; ; ) {
     return;
   }
 )");
 }
 
 TEST_F(MslGeneratorImplTest, Emit_ForLoopWithSimpleInit) {
-  // for(var i : i32; ; ) {
-  //   return;
-  // }
+    // for(var i : i32; ; ) {
+    //   return;
+    // }
 
-  auto* f = For(Decl(Var("i", ty.i32())), nullptr, nullptr,  //
-                Block(Return()));
-  WrapInFunction(f);
+    auto* f = For(Decl(Var("i", ty.i32())), nullptr, nullptr,  //
+                  Block(Return()));
+    WrapInFunction(f);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  for(int i = 0; ; ) {
+    ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  for(int i = 0; ; ) {
     return;
   }
 )");
 }
 
 TEST_F(MslGeneratorImplTest, Emit_ForLoopWithMultiStmtInit) {
-  // fn f(i : i32) {}
-  //
-  // var<workgroup> a : atomic<i32>;
-  // for({f(1); f(2);}; ; ) {
-  //   return;
-  // }
+    // fn f(i : i32) {}
+    //
+    // var<workgroup> a : atomic<i32>;
+    // for({f(1i); f(2i);}; ; ) {
+    //   return;
+    // }
 
-  Func("f", {Param("i", ty.i32())}, ty.void_(), {});
-  auto f = [&](auto&& expr) { return CallStmt(Call("f", expr)); };
+    Func("f", {Param("i", ty.i32())}, ty.void_(), {});
+    auto f = [&](auto&& expr) { return CallStmt(Call("f", expr)); };
 
-  Global("a", ty.atomic<i32>(), ast::StorageClass::kWorkgroup);
-  auto* multi_stmt = Block(f(1), f(2));
-  auto* loop = For(multi_stmt, nullptr, nullptr,  //
-                   Block(Return()));
-  WrapInFunction(loop);
+    Global("a", ty.atomic<i32>(), ast::StorageClass::kWorkgroup);
+    auto* multi_stmt = Block(f(1_i), f(2_i));
+    auto* loop = For(multi_stmt, nullptr, nullptr,  //
+                     Block(Return()));
+    WrapInFunction(loop);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(loop)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  {
+    ASSERT_TRUE(gen.EmitStatement(loop)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  {
     {
       f(1);
       f(2);
@@ -206,71 +208,70 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_ForLoopWithSimpleCond) {
-  // for(; true; ) {
-  //   return;
-  // }
+    // for(; true; ) {
+    //   return;
+    // }
 
-  auto* f = For(nullptr, true, nullptr,  //
-                Block(Return()));
-  WrapInFunction(f);
+    auto* f = For(nullptr, true, nullptr,  //
+                  Block(Return()));
+    WrapInFunction(f);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  for(; true; ) {
+    ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  for(; true; ) {
     return;
   }
 )");
 }
 
 TEST_F(MslGeneratorImplTest, Emit_ForLoopWithSimpleCont) {
-  // for(; ; i = i + 1) {
-  //   return;
-  // }
+    // for(; ; i = i + 1) {
+    //   return;
+    // }
 
-  auto* v = Decl(Var("i", ty.i32()));
-  auto* f = For(nullptr, nullptr, Assign("i", Add("i", 1)),  //
-                Block(Return()));
-  WrapInFunction(v, f);
+    auto* v = Decl(Var("i", ty.i32()));
+    auto* f = For(nullptr, nullptr, Assign("i", Add("i", 1_i)),  //
+                  Block(Return()));
+    WrapInFunction(v, f);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
-  EXPECT_EQ(
-      gen.result(),
-      R"(  for(; ; i = as_type<int>((as_type<uint>(i) + as_type<uint>(1)))) {
+    ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+    EXPECT_EQ(gen.result(),
+              R"(  for(; ; i = as_type<int>((as_type<uint>(i) + as_type<uint>(1)))) {
     return;
   }
 )");
 }
 
 TEST_F(MslGeneratorImplTest, Emit_ForLoopWithMultiStmtCont) {
-  // fn f(i : i32) {}
-  //
-  // var<workgroup> a : atomic<i32>;
-  // for(; ; { f(1); f(2); }) {
-  //   return;
-  // }
+    // fn f(i : i32) {}
+    //
+    // var<workgroup> a : atomic<i32>;
+    // for(; ; { f(1i); f(2i); }) {
+    //   return;
+    // }
 
-  Func("f", {Param("i", ty.i32())}, ty.void_(), {});
-  auto f = [&](auto&& expr) { return CallStmt(Call("f", expr)); };
+    Func("f", {Param("i", ty.i32())}, ty.void_(), {});
+    auto f = [&](auto&& expr) { return CallStmt(Call("f", expr)); };
 
-  Global("a", ty.atomic<i32>(), ast::StorageClass::kWorkgroup);
-  auto* multi_stmt = Block(f(1), f(2));
-  auto* loop = For(nullptr, nullptr, multi_stmt,  //
-                   Block(Return()));
-  WrapInFunction(loop);
+    Global("a", ty.atomic<i32>(), ast::StorageClass::kWorkgroup);
+    auto* multi_stmt = Block(f(1_i), f(2_i));
+    auto* loop = For(nullptr, nullptr, multi_stmt,  //
+                     Block(Return()));
+    WrapInFunction(loop);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(loop)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  while (true) {
+    ASSERT_TRUE(gen.EmitStatement(loop)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  while (true) {
     return;
     {
       f(1);
@@ -281,53 +282,52 @@
 }
 
 TEST_F(MslGeneratorImplTest, Emit_ForLoopWithSimpleInitCondCont) {
-  // for(var i : i32; true; i = i + 1) {
-  //   return;
-  // }
+    // for(var i : i32; true; i = i + 1) {
+    //   return;
+    // }
 
-  Func("a_statement", {}, ty.void_(), {});
+    Func("a_statement", {}, ty.void_(), {});
 
-  auto* f = For(Decl(Var("i", ty.i32())), true, Assign("i", Add("i", 1)),
-                Block(CallStmt(Call("a_statement"))));
-  WrapInFunction(f);
+    auto* f = For(Decl(Var("i", ty.i32())), true, Assign("i", Add("i", 1_i)),
+                  Block(CallStmt(Call("a_statement"))));
+    WrapInFunction(f);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
-  EXPECT_EQ(
-      gen.result(),
-      R"(  for(int i = 0; true; i = as_type<int>((as_type<uint>(i) + as_type<uint>(1)))) {
+    ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+    EXPECT_EQ(gen.result(),
+              R"(  for(int i = 0; true; i = as_type<int>((as_type<uint>(i) + as_type<uint>(1)))) {
     a_statement();
   }
 )");
 }
 
 TEST_F(MslGeneratorImplTest, Emit_ForLoopWithMultiStmtInitCondCont) {
-  // fn f(i : i32) {}
-  //
-  // var<workgroup> a : atomic<i32>;
-  // for({ f(1); f(2); }; true; { f(3); f(4); }) {
-  //   return;
-  // }
+    // fn f(i : i32) {}
+    //
+    // var<workgroup> a : atomic<i32>;
+    // for({ f(1i); f(2i); }; true; { f(3i); f(4i); }) {
+    //   return;
+    // }
 
-  Func("f", {Param("i", ty.i32())}, ty.void_(), {});
-  auto f = [&](auto&& expr) { return CallStmt(Call("f", expr)); };
+    Func("f", {Param("i", ty.i32())}, ty.void_(), {});
+    auto f = [&](auto&& expr) { return CallStmt(Call("f", expr)); };
 
-  Global("a", ty.atomic<i32>(), ast::StorageClass::kWorkgroup);
-  auto* multi_stmt_a = Block(f(1), f(2));
-  auto* multi_stmt_b = Block(f(3), f(4));
-  auto* loop = For(multi_stmt_a, Expr(true), multi_stmt_b,  //
-                   Block(Return()));
-  WrapInFunction(loop);
+    Global("a", ty.atomic<i32>(), ast::StorageClass::kWorkgroup);
+    auto* multi_stmt_a = Block(f(1_i), f(2_i));
+    auto* multi_stmt_b = Block(f(3_i), f(4_i));
+    auto* loop = For(multi_stmt_a, Expr(true), multi_stmt_b,  //
+                     Block(Return()));
+    WrapInFunction(loop);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(loop)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  {
+    ASSERT_TRUE(gen.EmitStatement(loop)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  {
     {
       f(1);
       f(2);
diff --git a/src/tint/writer/msl/generator_impl_member_accessor_test.cc b/src/tint/writer/msl/generator_impl_member_accessor_test.cc
index 21c637e..c9f3da0 100644
--- a/src/tint/writer/msl/generator_impl_member_accessor_test.cc
+++ b/src/tint/writer/msl/generator_impl_member_accessor_test.cc
@@ -20,40 +20,40 @@
 using MslGeneratorImplTest = TestHelper;
 
 TEST_F(MslGeneratorImplTest, EmitExpression_MemberAccessor) {
-  Global("str", ty.Of(Structure("my_str", {Member("mem", ty.f32())})),
-         ast::StorageClass::kPrivate);
-  auto* expr = MemberAccessor("str", "mem");
-  WrapInFunction(expr);
+    Global("str", ty.Of(Structure("my_str", {Member("mem", ty.f32())})),
+           ast::StorageClass::kPrivate);
+    auto* expr = MemberAccessor("str", "mem");
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), "str.mem");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), "str.mem");
 }
 
 TEST_F(MslGeneratorImplTest, EmitExpression_MemberAccessor_Swizzle_xyz) {
-  Global("my_vec", ty.vec4<f32>(), ast::StorageClass::kPrivate);
+    Global("my_vec", ty.vec4<f32>(), ast::StorageClass::kPrivate);
 
-  auto* expr = MemberAccessor("my_vec", "xyz");
-  WrapInFunction(expr);
+    auto* expr = MemberAccessor("my_vec", "xyz");
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), "float4(my_vec).xyz");
+    GeneratorImpl& gen = Build();
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), "float4(my_vec).xyz");
 }
 
 TEST_F(MslGeneratorImplTest, EmitExpression_MemberAccessor_Swizzle_gbr) {
-  Global("my_vec", ty.vec4<f32>(), ast::StorageClass::kPrivate);
+    Global("my_vec", ty.vec4<f32>(), ast::StorageClass::kPrivate);
 
-  auto* expr = MemberAccessor("my_vec", "gbr");
-  WrapInFunction(expr);
+    auto* expr = MemberAccessor("my_vec", "gbr");
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), "float4(my_vec).gbr");
+    GeneratorImpl& gen = Build();
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), "float4(my_vec).gbr");
 }
 
 }  // namespace
diff --git a/src/tint/writer/msl/generator_impl_module_constant_test.cc b/src/tint/writer/msl/generator_impl_module_constant_test.cc
index 8f419de..59cc2eb 100644
--- a/src/tint/writer/msl/generator_impl_module_constant_test.cc
+++ b/src/tint/writer/msl/generator_impl_module_constant_test.cc
@@ -21,39 +21,38 @@
 using MslGeneratorImplTest = TestHelper;
 
 TEST_F(MslGeneratorImplTest, Emit_ModuleConstant) {
-  auto* var =
-      GlobalConst("pos", ty.array<f32, 3>(), array<f32, 3>(1.f, 2.f, 3.f));
+    auto* var = GlobalConst("pos", ty.array<f32, 3>(), array<f32, 3>(1.f, 2.f, 3.f));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitProgramConstVariable(var)) << gen.error();
-  EXPECT_EQ(gen.result(), "constant float pos[3] = {1.0f, 2.0f, 3.0f};\n");
+    ASSERT_TRUE(gen.EmitProgramConstVariable(var)) << gen.error();
+    EXPECT_EQ(gen.result(), "constant float pos[3] = {1.0f, 2.0f, 3.0f};\n");
 }
 
 TEST_F(MslGeneratorImplTest, Emit_SpecConstant) {
-  auto* var = Override("pos", ty.f32(), Expr(3.f),
-                       ast::AttributeList{
-                           Id(23),
-                       });
+    auto* var = Override("pos", ty.f32(), Expr(3.f),
+                         ast::AttributeList{
+                             Id(23),
+                         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitProgramConstVariable(var)) << gen.error();
-  EXPECT_EQ(gen.result(), "constant float pos [[function_constant(23)]];\n");
+    ASSERT_TRUE(gen.EmitProgramConstVariable(var)) << gen.error();
+    EXPECT_EQ(gen.result(), "constant float pos [[function_constant(23)]];\n");
 }
 
 TEST_F(MslGeneratorImplTest, Emit_SpecConstant_NoId) {
-  auto* var_a = Override("a", ty.f32(), nullptr,
-                         ast::AttributeList{
-                             Id(0),
-                         });
-  auto* var_b = Override("b", ty.f32(), nullptr);
+    auto* var_a = Override("a", ty.f32(), nullptr,
+                           ast::AttributeList{
+                               Id(0),
+                           });
+    auto* var_b = Override("b", ty.f32(), nullptr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitProgramConstVariable(var_a)) << gen.error();
-  ASSERT_TRUE(gen.EmitProgramConstVariable(var_b)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(constant float a [[function_constant(0)]];
+    ASSERT_TRUE(gen.EmitProgramConstVariable(var_a)) << gen.error();
+    ASSERT_TRUE(gen.EmitProgramConstVariable(var_b)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(constant float a [[function_constant(0)]];
 constant float b [[function_constant(1)]];
 )");
 }
diff --git a/src/tint/writer/msl/generator_impl_return_test.cc b/src/tint/writer/msl/generator_impl_return_test.cc
index 7b846af..1443209 100644
--- a/src/tint/writer/msl/generator_impl_return_test.cc
+++ b/src/tint/writer/msl/generator_impl_return_test.cc
@@ -14,33 +14,35 @@
 
 #include "src/tint/writer/msl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::msl {
 namespace {
 
 using MslGeneratorImplTest = TestHelper;
 
 TEST_F(MslGeneratorImplTest, Emit_Return) {
-  auto* r = Return();
-  WrapInFunction(r);
+    auto* r = Return();
+    WrapInFunction(r);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(r)) << gen.error();
-  EXPECT_EQ(gen.result(), "  return;\n");
+    ASSERT_TRUE(gen.EmitStatement(r)) << gen.error();
+    EXPECT_EQ(gen.result(), "  return;\n");
 }
 
 TEST_F(MslGeneratorImplTest, Emit_ReturnWithValue) {
-  auto* r = Return(123);
-  Func("f", {}, ty.i32(), {r});
+    auto* r = Return(123_i);
+    Func("f", {}, ty.i32(), {r});
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(r)) << gen.error();
-  EXPECT_EQ(gen.result(), "  return 123;\n");
+    ASSERT_TRUE(gen.EmitStatement(r)) << gen.error();
+    EXPECT_EQ(gen.result(), "  return 123;\n");
 }
 
 }  // namespace
diff --git a/src/tint/writer/msl/generator_impl_sanitizer_test.cc b/src/tint/writer/msl/generator_impl_sanitizer_test.cc
index abab3d2..32ddb42 100644
--- a/src/tint/writer/msl/generator_impl_sanitizer_test.cc
+++ b/src/tint/writer/msl/generator_impl_sanitizer_test.cc
@@ -26,28 +26,28 @@
 using MslSanitizerTest = TestHelper;
 
 TEST_F(MslSanitizerTest, Call_ArrayLength) {
-  auto* s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))});
-  Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+    auto* s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))});
+    Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(1),
+               create<ast::GroupAttribute>(2),
+           });
+
+    Func("a_func", ast::VariableList{}, ty.void_(),
+         ast::StatementList{
+             Decl(Var("len", ty.u32(), ast::StorageClass::kNone,
+                      Call("arrayLength", AddressOf(MemberAccessor("b", "a"))))),
+         },
          ast::AttributeList{
-             create<ast::BindingAttribute>(1),
-             create<ast::GroupAttribute>(2),
+             Stage(ast::PipelineStage::kFragment),
          });
 
-  Func("a_func", ast::VariableList{}, ty.void_(),
-       ast::StatementList{
-           Decl(Var("len", ty.u32(), ast::StorageClass::kNone,
-                    Call("arrayLength", AddressOf(MemberAccessor("b", "a"))))),
-       },
-       ast::AttributeList{
-           Stage(ast::PipelineStage::kFragment),
-       });
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    ASSERT_TRUE(gen.Generate()) << gen.error();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-
-  auto got = gen.result();
-  auto* expect = R"(#include <metal_stdlib>
+    auto got = gen.result();
+    auto* expect = R"(#include <metal_stdlib>
 
 using namespace metal;
 struct tint_symbol {
@@ -64,35 +64,35 @@
 }
 
 )";
-  EXPECT_EQ(expect, got);
+    EXPECT_EQ(expect, got);
 }
 
 TEST_F(MslSanitizerTest, Call_ArrayLength_OtherMembersInStruct) {
-  auto* s = Structure("my_struct", {
-                                       Member(0, "z", ty.f32()),
-                                       Member(4, "a", ty.array<f32>(4)),
-                                   });
-  Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+    auto* s = Structure("my_struct", {
+                                         Member(0, "z", ty.f32()),
+                                         Member(4, "a", ty.array<f32>(4)),
+                                     });
+    Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(1),
+               create<ast::GroupAttribute>(2),
+           });
+
+    Func("a_func", ast::VariableList{}, ty.void_(),
+         ast::StatementList{
+             Decl(Var("len", ty.u32(), ast::StorageClass::kNone,
+                      Call("arrayLength", AddressOf(MemberAccessor("b", "a"))))),
+         },
          ast::AttributeList{
-             create<ast::BindingAttribute>(1),
-             create<ast::GroupAttribute>(2),
+             Stage(ast::PipelineStage::kFragment),
          });
 
-  Func("a_func", ast::VariableList{}, ty.void_(),
-       ast::StatementList{
-           Decl(Var("len", ty.u32(), ast::StorageClass::kNone,
-                    Call("arrayLength", AddressOf(MemberAccessor("b", "a"))))),
-       },
-       ast::AttributeList{
-           Stage(ast::PipelineStage::kFragment),
-       });
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    ASSERT_TRUE(gen.Generate()) << gen.error();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-
-  auto got = gen.result();
-  auto* expect = R"(#include <metal_stdlib>
+    auto got = gen.result();
+    auto* expect = R"(#include <metal_stdlib>
 
 using namespace metal;
 struct tint_symbol {
@@ -111,37 +111,36 @@
 
 )";
 
-  EXPECT_EQ(expect, got);
+    EXPECT_EQ(expect, got);
 }
 
 TEST_F(MslSanitizerTest, Call_ArrayLength_ViaLets) {
-  auto* s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))});
-  Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+    auto* s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))});
+    Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(1),
+               create<ast::GroupAttribute>(2),
+           });
+
+    auto* p = Let("p", nullptr, AddressOf("b"));
+    auto* p2 = Let("p2", nullptr, AddressOf(MemberAccessor(Deref(p), "a")));
+
+    Func("a_func", ast::VariableList{}, ty.void_(),
+         ast::StatementList{
+             Decl(p),
+             Decl(p2),
+             Decl(Var("len", ty.u32(), ast::StorageClass::kNone, Call("arrayLength", p2))),
+         },
          ast::AttributeList{
-             create<ast::BindingAttribute>(1),
-             create<ast::GroupAttribute>(2),
+             Stage(ast::PipelineStage::kFragment),
          });
 
-  auto* p = Const("p", nullptr, AddressOf("b"));
-  auto* p2 = Const("p2", nullptr, AddressOf(MemberAccessor(Deref(p), "a")));
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  Func("a_func", ast::VariableList{}, ty.void_(),
-       ast::StatementList{
-           Decl(p),
-           Decl(p2),
-           Decl(Var("len", ty.u32(), ast::StorageClass::kNone,
-                    Call("arrayLength", p2))),
-       },
-       ast::AttributeList{
-           Stage(ast::PipelineStage::kFragment),
-       });
+    ASSERT_TRUE(gen.Generate()) << gen.error();
 
-  GeneratorImpl& gen = SanitizeAndBuild();
-
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-
-  auto got = gen.result();
-  auto* expect = R"(#include <metal_stdlib>
+    auto got = gen.result();
+    auto* expect = R"(#include <metal_stdlib>
 
 using namespace metal;
 struct tint_symbol {
@@ -159,45 +158,42 @@
 
 )";
 
-  EXPECT_EQ(expect, got);
+    EXPECT_EQ(expect, got);
 }
 
 TEST_F(MslSanitizerTest, Call_ArrayLength_ArrayLengthFromUniform) {
-  auto* s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))});
-  Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+    auto* s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))});
+    Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(1),
+               create<ast::GroupAttribute>(0),
+           });
+    Global("c", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(2),
+               create<ast::GroupAttribute>(0),
+           });
+
+    Func("a_func", ast::VariableList{}, ty.void_(),
+         ast::StatementList{
+             Decl(Var("len", ty.u32(), ast::StorageClass::kNone,
+                      Add(Call("arrayLength", AddressOf(MemberAccessor("b", "a"))),
+                          Call("arrayLength", AddressOf(MemberAccessor("c", "a")))))),
+         },
          ast::AttributeList{
-             create<ast::BindingAttribute>(1),
-             create<ast::GroupAttribute>(0),
-         });
-  Global("c", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(2),
-             create<ast::GroupAttribute>(0),
+             Stage(ast::PipelineStage::kFragment),
          });
 
-  Func("a_func", ast::VariableList{}, ty.void_(),
-       ast::StatementList{
-           Decl(Var(
-               "len", ty.u32(), ast::StorageClass::kNone,
-               Add(Call("arrayLength", AddressOf(MemberAccessor("b", "a"))),
-                   Call("arrayLength", AddressOf(MemberAccessor("c", "a")))))),
-       },
-       ast::AttributeList{
-           Stage(ast::PipelineStage::kFragment),
-       });
+    Options options;
+    options.array_length_from_uniform.ubo_binding = {0, 29};
+    options.array_length_from_uniform.bindpoint_to_size_index.emplace(sem::BindingPoint{0, 1}, 7u);
+    options.array_length_from_uniform.bindpoint_to_size_index.emplace(sem::BindingPoint{0, 2}, 2u);
+    GeneratorImpl& gen = SanitizeAndBuild(options);
 
-  Options options;
-  options.array_length_from_uniform.ubo_binding = {0, 29};
-  options.array_length_from_uniform.bindpoint_to_size_index.emplace(
-      sem::BindingPoint{0, 1}, 7u);
-  options.array_length_from_uniform.bindpoint_to_size_index.emplace(
-      sem::BindingPoint{0, 2}, 2u);
-  GeneratorImpl& gen = SanitizeAndBuild(options);
+    ASSERT_TRUE(gen.Generate()) << gen.error();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-
-  auto got = gen.result();
-  auto* expect = R"(#include <metal_stdlib>
+    auto got = gen.result();
+    auto* expect = R"(#include <metal_stdlib>
 
 using namespace metal;
 struct tint_symbol {
@@ -214,43 +210,39 @@
 }
 
 )";
-  EXPECT_EQ(expect, got);
+    EXPECT_EQ(expect, got);
 }
 
-TEST_F(MslSanitizerTest,
-       Call_ArrayLength_ArrayLengthFromUniformMissingBinding) {
-  auto* s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))});
-  Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+TEST_F(MslSanitizerTest, Call_ArrayLength_ArrayLengthFromUniformMissingBinding) {
+    auto* s = Structure("my_struct", {Member(0, "a", ty.array<f32>(4))});
+    Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(1),
+               create<ast::GroupAttribute>(0),
+           });
+    Global("c", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(2),
+               create<ast::GroupAttribute>(0),
+           });
+
+    Func("a_func", ast::VariableList{}, ty.void_(),
+         ast::StatementList{
+             Decl(Var("len", ty.u32(), ast::StorageClass::kNone,
+                      Add(Call("arrayLength", AddressOf(MemberAccessor("b", "a"))),
+                          Call("arrayLength", AddressOf(MemberAccessor("c", "a")))))),
+         },
          ast::AttributeList{
-             create<ast::BindingAttribute>(1),
-             create<ast::GroupAttribute>(0),
-         });
-  Global("c", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(2),
-             create<ast::GroupAttribute>(0),
+             Stage(ast::PipelineStage::kFragment),
          });
 
-  Func("a_func", ast::VariableList{}, ty.void_(),
-       ast::StatementList{
-           Decl(Var(
-               "len", ty.u32(), ast::StorageClass::kNone,
-               Add(Call("arrayLength", AddressOf(MemberAccessor("b", "a"))),
-                   Call("arrayLength", AddressOf(MemberAccessor("c", "a")))))),
-       },
-       ast::AttributeList{
-           Stage(ast::PipelineStage::kFragment),
-       });
+    Options options;
+    options.array_length_from_uniform.ubo_binding = {0, 29};
+    options.array_length_from_uniform.bindpoint_to_size_index.emplace(sem::BindingPoint{0, 2}, 2u);
+    GeneratorImpl& gen = SanitizeAndBuild(options);
 
-  Options options;
-  options.array_length_from_uniform.ubo_binding = {0, 29};
-  options.array_length_from_uniform.bindpoint_to_size_index.emplace(
-      sem::BindingPoint{0, 2}, 2u);
-  GeneratorImpl& gen = SanitizeAndBuild(options);
-
-  ASSERT_FALSE(gen.Generate());
-  EXPECT_THAT(gen.error(),
-              HasSubstr("Unable to translate builtin: arrayLength"));
+    ASSERT_FALSE(gen.Generate());
+    EXPECT_THAT(gen.error(), HasSubstr("Unable to translate builtin: arrayLength"));
 }
 
 }  // namespace
diff --git a/src/tint/writer/msl/generator_impl_switch_test.cc b/src/tint/writer/msl/generator_impl_switch_test.cc
index eec4c24..ce8087b 100644
--- a/src/tint/writer/msl/generator_impl_switch_test.cc
+++ b/src/tint/writer/msl/generator_impl_switch_test.cc
@@ -14,36 +14,38 @@
 
 #include "src/tint/writer/msl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::msl {
 namespace {
 
 using MslGeneratorImplTest = TestHelper;
 
 TEST_F(MslGeneratorImplTest, Emit_Switch) {
-  auto* cond = Var("cond", ty.i32());
+    auto* cond = Var("cond", ty.i32());
 
-  auto* def_body = Block(create<ast::BreakStatement>());
-  auto* def = create<ast::CaseStatement>(ast::CaseSelectorList{}, def_body);
+    auto* def_body = Block(create<ast::BreakStatement>());
+    auto* def = create<ast::CaseStatement>(ast::CaseSelectorList{}, def_body);
 
-  ast::CaseSelectorList case_val;
-  case_val.push_back(Expr(5));
+    ast::CaseSelectorList case_val;
+    case_val.push_back(Expr(5_i));
 
-  auto* case_body = Block(create<ast::BreakStatement>());
+    auto* case_body = Block(create<ast::BreakStatement>());
 
-  auto* case_stmt = create<ast::CaseStatement>(case_val, case_body);
+    auto* case_stmt = create<ast::CaseStatement>(case_val, case_body);
 
-  ast::CaseStatementList body;
-  body.push_back(case_stmt);
-  body.push_back(def);
+    ast::CaseStatementList body;
+    body.push_back(case_stmt);
+    body.push_back(def);
 
-  auto* s = create<ast::SwitchStatement>(Expr(cond), body);
-  WrapInFunction(cond, s);
-  GeneratorImpl& gen = Build();
+    auto* s = create<ast::SwitchStatement>(Expr(cond), body);
+    WrapInFunction(cond, s);
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(s)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  switch(cond) {
+    ASSERT_TRUE(gen.EmitStatement(s)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  switch(cond) {
     case 5: {
       break;
     }
diff --git a/src/tint/writer/msl/generator_impl_test.cc b/src/tint/writer/msl/generator_impl_test.cc
index cad1eb1..b5af8e4 100644
--- a/src/tint/writer/msl/generator_impl_test.cc
+++ b/src/tint/writer/msl/generator_impl_test.cc
@@ -15,22 +15,24 @@
 #include "src/tint/ast/stage_attribute.h"
 #include "src/tint/writer/msl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::msl {
 namespace {
 
 using MslGeneratorImplTest = TestHelper;
 
 TEST_F(MslGeneratorImplTest, Generate) {
-  Func("my_func", ast::VariableList{}, ty.void_(), ast::StatementList{},
-       ast::AttributeList{
-           Stage(ast::PipelineStage::kCompute),
-           WorkgroupSize(1),
-       });
+    Func("my_func", ast::VariableList{}, ty.void_(), ast::StatementList{},
+         ast::AttributeList{
+             Stage(ast::PipelineStage::kCompute),
+             WorkgroupSize(1_i),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
 
 using namespace metal;
 kernel void my_func() {
@@ -41,56 +43,50 @@
 }
 
 struct MslBuiltinData {
-  ast::Builtin builtin;
-  const char* attribute_name;
+    ast::Builtin builtin;
+    const char* attribute_name;
 };
 inline std::ostream& operator<<(std::ostream& out, MslBuiltinData data) {
-  out << data.builtin;
-  return out;
+    out << data.builtin;
+    return out;
 }
 using MslBuiltinConversionTest = TestParamHelper<MslBuiltinData>;
 TEST_P(MslBuiltinConversionTest, Emit) {
-  auto params = GetParam();
+    auto params = GetParam();
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  EXPECT_EQ(gen.builtin_to_attribute(params.builtin),
-            std::string(params.attribute_name));
+    EXPECT_EQ(gen.builtin_to_attribute(params.builtin), std::string(params.attribute_name));
 }
 INSTANTIATE_TEST_SUITE_P(
     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"}));
+    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"}));
 
 TEST_F(MslGeneratorImplTest, HasInvariantAttribute_True) {
-  auto* out = Structure(
-      "Out", {Member("pos", ty.vec4<f32>(),
-                     {Builtin(ast::Builtin::kPosition), Invariant()})});
-  Func("vert_main", ast::VariableList{}, ty.Of(out),
-       {Return(Construct(ty.Of(out)))}, {Stage(ast::PipelineStage::kVertex)});
+    auto* out = Structure(
+        "Out", {Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition), Invariant()})});
+    Func("vert_main", ast::VariableList{}, ty.Of(out), {Return(Construct(ty.Of(out)))},
+         {Stage(ast::PipelineStage::kVertex)});
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_TRUE(gen.HasInvariant());
-  EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_TRUE(gen.HasInvariant());
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
 
 using namespace metal;
 
@@ -112,16 +108,16 @@
 }
 
 TEST_F(MslGeneratorImplTest, HasInvariantAttribute_False) {
-  auto* out = Structure("Out", {Member("pos", ty.vec4<f32>(),
-                                       {Builtin(ast::Builtin::kPosition)})});
-  Func("vert_main", ast::VariableList{}, ty.Of(out),
-       {Return(Construct(ty.Of(out)))}, {Stage(ast::PipelineStage::kVertex)});
+    auto* out =
+        Structure("Out", {Member("pos", ty.vec4<f32>(), {Builtin(ast::Builtin::kPosition)})});
+    Func("vert_main", ast::VariableList{}, ty.Of(out), {Return(Construct(ty.Of(out)))},
+         {Stage(ast::PipelineStage::kVertex)});
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_FALSE(gen.HasInvariant());
-  EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_FALSE(gen.HasInvariant());
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
 
 using namespace metal;
 struct Out {
@@ -136,15 +132,14 @@
 }
 
 TEST_F(MslGeneratorImplTest, WorkgroupMatrix) {
-  Global("m", ty.mat2x2<f32>(), ast::StorageClass::kWorkgroup);
-  Func("comp_main", ast::VariableList{}, ty.void_(),
-       {Decl(Const("x", nullptr, Expr("m")))},
-       {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
+    Global("m", ty.mat2x2<f32>(), ast::StorageClass::kWorkgroup);
+    Func("comp_main", ast::VariableList{}, ty.void_(), {Decl(Let("x", nullptr, Expr("m")))},
+         {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
 
 using namespace metal;
 struct tint_symbol_3 {
@@ -167,22 +162,21 @@
 
 )");
 
-  auto allocations = gen.DynamicWorkgroupAllocations();
-  ASSERT_TRUE(allocations.count("comp_main"));
-  ASSERT_EQ(allocations["comp_main"].size(), 1u);
-  EXPECT_EQ(allocations["comp_main"][0], 2u * 2u * sizeof(float));
+    auto allocations = gen.DynamicWorkgroupAllocations();
+    ASSERT_TRUE(allocations.count("comp_main"));
+    ASSERT_EQ(allocations["comp_main"].size(), 1u);
+    EXPECT_EQ(allocations["comp_main"][0], 2u * 2u * sizeof(float));
 }
 
 TEST_F(MslGeneratorImplTest, WorkgroupMatrixInArray) {
-  Global("m", ty.array(ty.mat2x2<f32>(), 4), ast::StorageClass::kWorkgroup);
-  Func("comp_main", ast::VariableList{}, ty.void_(),
-       {Decl(Const("x", nullptr, Expr("m")))},
-       {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
+    Global("m", ty.array(ty.mat2x2<f32>(), 4_i), ast::StorageClass::kWorkgroup);
+    Func("comp_main", ast::VariableList{}, ty.void_(), {Decl(Let("x", nullptr, Expr("m")))},
+         {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
 
 using namespace metal;
 struct tint_array_wrapper {
@@ -210,29 +204,28 @@
 
 )");
 
-  auto allocations = gen.DynamicWorkgroupAllocations();
-  ASSERT_TRUE(allocations.count("comp_main"));
-  ASSERT_EQ(allocations["comp_main"].size(), 1u);
-  EXPECT_EQ(allocations["comp_main"][0], 4u * 2u * 2u * sizeof(float));
+    auto allocations = gen.DynamicWorkgroupAllocations();
+    ASSERT_TRUE(allocations.count("comp_main"));
+    ASSERT_EQ(allocations["comp_main"].size(), 1u);
+    EXPECT_EQ(allocations["comp_main"][0], 4u * 2u * 2u * sizeof(float));
 }
 
 TEST_F(MslGeneratorImplTest, WorkgroupMatrixInStruct) {
-  Structure("S1", {
-                      Member("m1", ty.mat2x2<f32>()),
-                      Member("m2", ty.mat4x4<f32>()),
-                  });
-  Structure("S2", {
-                      Member("s", ty.type_name("S1")),
-                  });
-  Global("s", ty.type_name("S2"), ast::StorageClass::kWorkgroup);
-  Func("comp_main", ast::VariableList{}, ty.void_(),
-       {Decl(Const("x", nullptr, Expr("s")))},
-       {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
+    Structure("S1", {
+                        Member("m1", ty.mat2x2<f32>()),
+                        Member("m2", ty.mat4x4<f32>()),
+                    });
+    Structure("S2", {
+                        Member("s", ty.type_name("S1")),
+                    });
+    Global("s", ty.type_name("S2"), ast::StorageClass::kWorkgroup);
+    Func("comp_main", ast::VariableList{}, ty.void_(), {Decl(Let("x", nullptr, Expr("s")))},
+         {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
 
 using namespace metal;
 struct S1 {
@@ -265,51 +258,50 @@
 
 )");
 
-  auto allocations = gen.DynamicWorkgroupAllocations();
-  ASSERT_TRUE(allocations.count("comp_main"));
-  ASSERT_EQ(allocations["comp_main"].size(), 1u);
-  EXPECT_EQ(allocations["comp_main"][0],
-            (2 * 2 * sizeof(float)) + (4u * 4u * sizeof(float)));
+    auto allocations = gen.DynamicWorkgroupAllocations();
+    ASSERT_TRUE(allocations.count("comp_main"));
+    ASSERT_EQ(allocations["comp_main"].size(), 1u);
+    EXPECT_EQ(allocations["comp_main"][0], (2 * 2 * sizeof(float)) + (4u * 4u * sizeof(float)));
 }
 
 TEST_F(MslGeneratorImplTest, WorkgroupMatrix_Multiples) {
-  Global("m1", ty.mat2x2<f32>(), ast::StorageClass::kWorkgroup);
-  Global("m2", ty.mat2x3<f32>(), ast::StorageClass::kWorkgroup);
-  Global("m3", ty.mat2x4<f32>(), ast::StorageClass::kWorkgroup);
-  Global("m4", ty.mat3x2<f32>(), ast::StorageClass::kWorkgroup);
-  Global("m5", ty.mat3x3<f32>(), ast::StorageClass::kWorkgroup);
-  Global("m6", ty.mat3x4<f32>(), ast::StorageClass::kWorkgroup);
-  Global("m7", ty.mat4x2<f32>(), ast::StorageClass::kWorkgroup);
-  Global("m8", ty.mat4x3<f32>(), ast::StorageClass::kWorkgroup);
-  Global("m9", ty.mat4x4<f32>(), ast::StorageClass::kWorkgroup);
-  Func("main1", ast::VariableList{}, ty.void_(),
-       {
-           Decl(Const("a1", nullptr, Expr("m1"))),
-           Decl(Const("a2", nullptr, Expr("m2"))),
-           Decl(Const("a3", nullptr, Expr("m3"))),
-       },
-       {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
-  Func("main2", ast::VariableList{}, ty.void_(),
-       {
-           Decl(Const("a1", nullptr, Expr("m4"))),
-           Decl(Const("a2", nullptr, Expr("m5"))),
-           Decl(Const("a3", nullptr, Expr("m6"))),
-       },
-       {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
-  Func("main3", ast::VariableList{}, ty.void_(),
-       {
-           Decl(Const("a1", nullptr, Expr("m7"))),
-           Decl(Const("a2", nullptr, Expr("m8"))),
-           Decl(Const("a3", nullptr, Expr("m9"))),
-       },
-       {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
-  Func("main4_no_usages", ast::VariableList{}, ty.void_(), {},
-       {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1)});
+    Global("m1", ty.mat2x2<f32>(), ast::StorageClass::kWorkgroup);
+    Global("m2", ty.mat2x3<f32>(), ast::StorageClass::kWorkgroup);
+    Global("m3", ty.mat2x4<f32>(), ast::StorageClass::kWorkgroup);
+    Global("m4", ty.mat3x2<f32>(), ast::StorageClass::kWorkgroup);
+    Global("m5", ty.mat3x3<f32>(), ast::StorageClass::kWorkgroup);
+    Global("m6", ty.mat3x4<f32>(), ast::StorageClass::kWorkgroup);
+    Global("m7", ty.mat4x2<f32>(), ast::StorageClass::kWorkgroup);
+    Global("m8", ty.mat4x3<f32>(), ast::StorageClass::kWorkgroup);
+    Global("m9", ty.mat4x4<f32>(), ast::StorageClass::kWorkgroup);
+    Func("main1", ast::VariableList{}, ty.void_(),
+         {
+             Decl(Let("a1", nullptr, Expr("m1"))),
+             Decl(Let("a2", nullptr, Expr("m2"))),
+             Decl(Let("a3", nullptr, Expr("m3"))),
+         },
+         {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+    Func("main2", ast::VariableList{}, ty.void_(),
+         {
+             Decl(Let("a1", nullptr, Expr("m4"))),
+             Decl(Let("a2", nullptr, Expr("m5"))),
+             Decl(Let("a3", nullptr, Expr("m6"))),
+         },
+         {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+    Func("main3", ast::VariableList{}, ty.void_(),
+         {
+             Decl(Let("a1", nullptr, Expr("m7"))),
+             Decl(Let("a2", nullptr, Expr("m8"))),
+             Decl(Let("a3", nullptr, Expr("m9"))),
+         },
+         {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+    Func("main4_no_usages", ast::VariableList{}, ty.void_(), {},
+         {Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(#include <metal_stdlib>
 
 using namespace metal;
 struct tint_symbol_7 {
@@ -396,17 +388,17 @@
 
 )");
 
-  auto allocations = gen.DynamicWorkgroupAllocations();
-  ASSERT_TRUE(allocations.count("main1"));
-  ASSERT_TRUE(allocations.count("main2"));
-  ASSERT_TRUE(allocations.count("main3"));
-  EXPECT_EQ(allocations.count("main4_no_usages"), 0u);
-  ASSERT_EQ(allocations["main1"].size(), 1u);
-  EXPECT_EQ(allocations["main1"][0], 20u * sizeof(float));
-  ASSERT_EQ(allocations["main2"].size(), 1u);
-  EXPECT_EQ(allocations["main2"][0], 32u * sizeof(float));
-  ASSERT_EQ(allocations["main3"].size(), 1u);
-  EXPECT_EQ(allocations["main3"][0], 40u * sizeof(float));
+    auto allocations = gen.DynamicWorkgroupAllocations();
+    ASSERT_TRUE(allocations.count("main1"));
+    ASSERT_TRUE(allocations.count("main2"));
+    ASSERT_TRUE(allocations.count("main3"));
+    EXPECT_EQ(allocations.count("main4_no_usages"), 0u);
+    ASSERT_EQ(allocations["main1"].size(), 1u);
+    EXPECT_EQ(allocations["main1"][0], 20u * sizeof(float));
+    ASSERT_EQ(allocations["main2"].size(), 1u);
+    EXPECT_EQ(allocations["main2"][0], 32u * sizeof(float));
+    ASSERT_EQ(allocations["main3"].size(), 1u);
+    EXPECT_EQ(allocations["main3"][0], 40u * sizeof(float));
 }
 
 }  // namespace
diff --git a/src/tint/writer/msl/generator_impl_type_test.cc b/src/tint/writer/msl/generator_impl_type_test.cc
index 1efffbb..257468b 100644
--- a/src/tint/writer/msl/generator_impl_type_test.cc
+++ b/src/tint/writer/msl/generator_impl_type_test.cc
@@ -16,30 +16,32 @@
 
 #include "gmock/gmock.h"
 
-#include "src/tint/sem/depth_multisampled_texture_type.h"
-#include "src/tint/sem/depth_texture_type.h"
-#include "src/tint/sem/multisampled_texture_type.h"
-#include "src/tint/sem/sampled_texture_type.h"
-#include "src/tint/sem/sampler_type.h"
-#include "src/tint/sem/storage_texture_type.h"
+#include "src/tint/sem/depth_multisampled_texture.h"
+#include "src/tint/sem/depth_texture.h"
+#include "src/tint/sem/multisampled_texture.h"
+#include "src/tint/sem/sampled_texture.h"
+#include "src/tint/sem/sampler.h"
+#include "src/tint/sem/storage_texture.h"
 #include "src/tint/writer/msl/test_helper.h"
 
+using ::testing::HasSubstr;
+
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::msl {
 namespace {
 
-using ::testing::HasSubstr;
-
-#define CHECK_TYPE_SIZE_AND_ALIGN(TYPE, SIZE, ALIGN)    \
-  static_assert(sizeof(TYPE) == SIZE, "Bad type size"); \
-  static_assert(alignof(TYPE) == ALIGN, "Bad type alignment")
+#define CHECK_TYPE_SIZE_AND_ALIGN(TYPE, SIZE, ALIGN)      \
+    static_assert(sizeof(TYPE) == SIZE, "Bad type size"); \
+    static_assert(alignof(TYPE) == ALIGN, "Bad type alignment")
 
 // Declare C++ types that match the size and alignment of the types of the same
 // name in MSL.
 #define DECLARE_TYPE(NAME, SIZE, ALIGN) \
-  struct alignas(ALIGN) NAME {          \
-    uint8_t _[SIZE];                    \
-  };                                    \
-  CHECK_TYPE_SIZE_AND_ALIGN(NAME, SIZE, ALIGN)
+    struct alignas(ALIGN) NAME {        \
+        uint8_t _[SIZE];                \
+    };                                  \
+    CHECK_TYPE_SIZE_AND_ALIGN(NAME, SIZE, ALIGN)
 
 // Size and alignments taken from the MSL spec:
 // https://developer.apple.com/metal/Metal-Shading-Language-Specification.pdf
@@ -60,142 +62,141 @@
 using MslGeneratorImplTest = TestHelper;
 
 TEST_F(MslGeneratorImplTest, EmitType_Array) {
-  auto* arr = ty.array<bool, 4>();
-  Global("G", arr, ast::StorageClass::kPrivate);
+    auto* arr = ty.array<bool, 4>();
+    Global("G", arr, ast::StorageClass::kPrivate);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, program->TypeOf(arr), "ary")) << gen.error();
-  EXPECT_EQ(out.str(), "bool ary[4]");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, program->TypeOf(arr), "ary")) << gen.error();
+    EXPECT_EQ(out.str(), "bool ary[4]");
 }
 
 TEST_F(MslGeneratorImplTest, EmitType_ArrayOfArray) {
-  auto* a = ty.array<bool, 4>();
-  auto* b = ty.array(a, 5);
-  Global("G", b, ast::StorageClass::kPrivate);
+    auto* a = ty.array<bool, 4>();
+    auto* b = ty.array(a, 5_u);
+    Global("G", b, ast::StorageClass::kPrivate);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, program->TypeOf(b), "ary")) << gen.error();
-  EXPECT_EQ(out.str(), "bool ary[5][4]");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, program->TypeOf(b), "ary")) << gen.error();
+    EXPECT_EQ(out.str(), "bool ary[5][4]");
 }
 
 TEST_F(MslGeneratorImplTest, EmitType_ArrayOfArrayOfArray) {
-  auto* a = ty.array<bool, 4>();
-  auto* b = ty.array(a, 5);
-  auto* c = ty.array(b, 6);
-  Global("G", c, ast::StorageClass::kPrivate);
+    auto* a = ty.array<bool, 4>();
+    auto* b = ty.array(a, 5_u);
+    auto* c = ty.array(b, 6_u);
+    Global("G", c, ast::StorageClass::kPrivate);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, program->TypeOf(c), "ary")) << gen.error();
-  EXPECT_EQ(out.str(), "bool ary[6][5][4]");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, program->TypeOf(c), "ary")) << gen.error();
+    EXPECT_EQ(out.str(), "bool ary[6][5][4]");
 }
 
 TEST_F(MslGeneratorImplTest, EmitType_Array_WithoutName) {
-  auto* arr = ty.array<bool, 4>();
-  Global("G", arr, ast::StorageClass::kPrivate);
+    auto* arr = ty.array<bool, 4>();
+    Global("G", arr, ast::StorageClass::kPrivate);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, program->TypeOf(arr), "")) << gen.error();
-  EXPECT_EQ(out.str(), "bool[4]");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, program->TypeOf(arr), "")) << gen.error();
+    EXPECT_EQ(out.str(), "bool[4]");
 }
 
 TEST_F(MslGeneratorImplTest, EmitType_RuntimeArray) {
-  auto* arr = ty.array<bool, 1>();
-  Global("G", arr, ast::StorageClass::kPrivate);
+    auto* arr = ty.array<bool, 1>();
+    Global("G", arr, ast::StorageClass::kPrivate);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, program->TypeOf(arr), "ary")) << gen.error();
-  EXPECT_EQ(out.str(), "bool ary[1]");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, program->TypeOf(arr), "ary")) << gen.error();
+    EXPECT_EQ(out.str(), "bool ary[1]");
 }
 
 TEST_F(MslGeneratorImplTest, EmitType_Bool) {
-  auto* bool_ = create<sem::Bool>();
+    auto* bool_ = create<sem::Bool>();
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, bool_, "")) << gen.error();
-  EXPECT_EQ(out.str(), "bool");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, bool_, "")) << gen.error();
+    EXPECT_EQ(out.str(), "bool");
 }
 
 TEST_F(MslGeneratorImplTest, EmitType_F32) {
-  auto* f32 = create<sem::F32>();
+    auto* f32 = create<sem::F32>();
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, f32, "")) << gen.error();
-  EXPECT_EQ(out.str(), "float");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, f32, "")) << gen.error();
+    EXPECT_EQ(out.str(), "float");
 }
 
 TEST_F(MslGeneratorImplTest, EmitType_I32) {
-  auto* i32 = create<sem::I32>();
+    auto* i32 = create<sem::I32>();
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, i32, "")) << gen.error();
-  EXPECT_EQ(out.str(), "int");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, i32, "")) << gen.error();
+    EXPECT_EQ(out.str(), "int");
 }
 
 TEST_F(MslGeneratorImplTest, EmitType_Matrix) {
-  auto* f32 = create<sem::F32>();
-  auto* vec3 = create<sem::Vector>(f32, 3u);
-  auto* mat2x3 = create<sem::Matrix>(vec3, 2u);
+    auto* f32 = create<sem::F32>();
+    auto* vec3 = create<sem::Vector>(f32, 3u);
+    auto* mat2x3 = create<sem::Matrix>(vec3, 2u);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, mat2x3, "")) << gen.error();
-  EXPECT_EQ(out.str(), "float2x3");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, mat2x3, "")) << gen.error();
+    EXPECT_EQ(out.str(), "float2x3");
 }
 
 TEST_F(MslGeneratorImplTest, EmitType_Pointer) {
-  auto* f32 = create<sem::F32>();
-  auto* p = create<sem::Pointer>(f32, ast::StorageClass::kWorkgroup,
-                                 ast::Access::kReadWrite);
+    auto* f32 = create<sem::F32>();
+    auto* p = create<sem::Pointer>(f32, ast::StorageClass::kWorkgroup, ast::Access::kReadWrite);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, p, "")) << gen.error();
-  EXPECT_EQ(out.str(), "threadgroup float* ");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, p, "")) << gen.error();
+    EXPECT_EQ(out.str(), "threadgroup float* ");
 }
 
 TEST_F(MslGeneratorImplTest, EmitType_Struct) {
-  auto* s = Structure("S", {
-                               Member("a", ty.i32()),
-                               Member("b", ty.f32()),
-                           });
+    auto* s = Structure("S", {
+                                 Member("a", ty.i32()),
+                                 Member("b", ty.f32()),
+                             });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, program->TypeOf(s), "")) << gen.error();
-  EXPECT_EQ(out.str(), "S");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, program->TypeOf(s), "")) << gen.error();
+    EXPECT_EQ(out.str(), "S");
 }
 
 TEST_F(MslGeneratorImplTest, EmitType_StructDecl) {
-  auto* s = Structure("S", {
-                               Member("a", ty.i32()),
-                               Member("b", ty.f32()),
-                           });
+    auto* s = Structure("S", {
+                                 Member("a", ty.i32()),
+                                 Member("b", ty.f32()),
+                             });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  TextGenerator::TextBuffer buf;
-  auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
-  ASSERT_TRUE(gen.EmitStructType(&buf, sem_s)) << gen.error();
-  EXPECT_EQ(buf.String(), R"(struct S {
+    TextGenerator::TextBuffer buf;
+    auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
+    ASSERT_TRUE(gen.EmitStructType(&buf, sem_s)) << gen.error();
+    EXPECT_EQ(buf.String(), R"(struct S {
   int a;
   float b;
 };
@@ -203,393 +204,384 @@
 }
 
 TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_NonComposites) {
-  auto* s = Structure(
-      "S", {
-               Member("a", ty.i32(), {MemberSize(32)}),
-               Member("b", ty.f32(), {MemberAlign(128), MemberSize(128)}),
-               Member("c", ty.vec2<f32>()),
-               Member("d", ty.u32()),
-               Member("e", ty.vec3<f32>()),
-               Member("f", ty.u32()),
-               Member("g", ty.vec4<f32>()),
-               Member("h", ty.u32()),
-               Member("i", ty.mat2x2<f32>()),
-               Member("j", ty.u32()),
-               Member("k", ty.mat2x3<f32>()),
-               Member("l", ty.u32()),
-               Member("m", ty.mat2x4<f32>()),
-               Member("n", ty.u32()),
-               Member("o", ty.mat3x2<f32>()),
-               Member("p", ty.u32()),
-               Member("q", ty.mat3x3<f32>()),
-               Member("r", ty.u32()),
-               Member("s", ty.mat3x4<f32>()),
-               Member("t", ty.u32()),
-               Member("u", ty.mat4x2<f32>()),
-               Member("v", ty.u32()),
-               Member("w", ty.mat4x3<f32>()),
-               Member("x", ty.u32()),
-               Member("y", ty.mat4x4<f32>()),
-               Member("z", ty.f32()),
+    auto* s = Structure("S", {
+                                 Member("a", ty.i32(), {MemberSize(32)}),
+                                 Member("b", ty.f32(), {MemberAlign(128), MemberSize(128)}),
+                                 Member("c", ty.vec2<f32>()),
+                                 Member("d", ty.u32()),
+                                 Member("e", ty.vec3<f32>()),
+                                 Member("f", ty.u32()),
+                                 Member("g", ty.vec4<f32>()),
+                                 Member("h", ty.u32()),
+                                 Member("i", ty.mat2x2<f32>()),
+                                 Member("j", ty.u32()),
+                                 Member("k", ty.mat2x3<f32>()),
+                                 Member("l", ty.u32()),
+                                 Member("m", ty.mat2x4<f32>()),
+                                 Member("n", ty.u32()),
+                                 Member("o", ty.mat3x2<f32>()),
+                                 Member("p", ty.u32()),
+                                 Member("q", ty.mat3x3<f32>()),
+                                 Member("r", ty.u32()),
+                                 Member("s", ty.mat3x4<f32>()),
+                                 Member("t", ty.u32()),
+                                 Member("u", ty.mat4x2<f32>()),
+                                 Member("v", ty.u32()),
+                                 Member("w", ty.mat4x3<f32>()),
+                                 Member("x", ty.u32()),
+                                 Member("y", ty.mat4x4<f32>()),
+                                 Member("z", ty.f32()),
+                             });
+
+    Global("G", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
            });
 
-  Global("G", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    GeneratorImpl& gen = Build();
 
-  GeneratorImpl& gen = Build();
+    TextGenerator::TextBuffer buf;
+    auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
+    ASSERT_TRUE(gen.EmitStructType(&buf, sem_s)) << gen.error();
 
-  TextGenerator::TextBuffer buf;
-  auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
-  ASSERT_TRUE(gen.EmitStructType(&buf, sem_s)) << gen.error();
+    // ALL_FIELDS() calls the macro FIELD(ADDR, TYPE, NAME, SUFFIX)
+    // for each field of the structure s.
+#define ALL_FIELDS()                               \
+    FIELD(0x0000, int, a, /*NO SUFFIX*/)           \
+    FIELD(0x0004, int8_t, tint_pad, [124])         \
+    FIELD(0x0080, float, b, /*NO SUFFIX*/)         \
+    FIELD(0x0084, int8_t, tint_pad_1, [124])       \
+    FIELD(0x0100, float2, c, /*NO SUFFIX*/)        \
+    FIELD(0x0108, uint, d, /*NO SUFFIX*/)          \
+    FIELD(0x010c, int8_t, tint_pad_2, [4])         \
+    FIELD(0x0110, packed_float3, e, /*NO SUFFIX*/) \
+    FIELD(0x011c, uint, f, /*NO SUFFIX*/)          \
+    FIELD(0x0120, float4, g, /*NO SUFFIX*/)        \
+    FIELD(0x0130, uint, h, /*NO SUFFIX*/)          \
+    FIELD(0x0134, int8_t, tint_pad_3, [4])         \
+    FIELD(0x0138, float2x2, i, /*NO SUFFIX*/)      \
+    FIELD(0x0148, uint, j, /*NO SUFFIX*/)          \
+    FIELD(0x014c, int8_t, tint_pad_4, [4])         \
+    FIELD(0x0150, float2x3, k, /*NO SUFFIX*/)      \
+    FIELD(0x0170, uint, l, /*NO SUFFIX*/)          \
+    FIELD(0x0174, int8_t, tint_pad_5, [12])        \
+    FIELD(0x0180, float2x4, m, /*NO SUFFIX*/)      \
+    FIELD(0x01a0, uint, n, /*NO SUFFIX*/)          \
+    FIELD(0x01a4, int8_t, tint_pad_6, [4])         \
+    FIELD(0x01a8, float3x2, o, /*NO SUFFIX*/)      \
+    FIELD(0x01c0, uint, p, /*NO SUFFIX*/)          \
+    FIELD(0x01c4, int8_t, tint_pad_7, [12])        \
+    FIELD(0x01d0, float3x3, q, /*NO SUFFIX*/)      \
+    FIELD(0x0200, uint, r, /*NO SUFFIX*/)          \
+    FIELD(0x0204, int8_t, tint_pad_8, [12])        \
+    FIELD(0x0210, float3x4, s, /*NO SUFFIX*/)      \
+    FIELD(0x0240, uint, t, /*NO SUFFIX*/)          \
+    FIELD(0x0244, int8_t, tint_pad_9, [4])         \
+    FIELD(0x0248, float4x2, u, /*NO SUFFIX*/)      \
+    FIELD(0x0268, uint, v, /*NO SUFFIX*/)          \
+    FIELD(0x026c, int8_t, tint_pad_10, [4])        \
+    FIELD(0x0270, float4x3, w, /*NO SUFFIX*/)      \
+    FIELD(0x02b0, uint, x, /*NO SUFFIX*/)          \
+    FIELD(0x02b4, int8_t, tint_pad_11, [12])       \
+    FIELD(0x02c0, float4x4, y, /*NO SUFFIX*/)      \
+    FIELD(0x0300, float, z, /*NO SUFFIX*/)         \
+    FIELD(0x0304, int8_t, tint_pad_12, [124])
 
-  // ALL_FIELDS() calls the macro FIELD(ADDR, TYPE, NAME, SUFFIX)
-  // for each field of the structure s.
-#define ALL_FIELDS()                             \
-  FIELD(0x0000, int, a, /*NO SUFFIX*/)           \
-  FIELD(0x0004, int8_t, tint_pad, [124])         \
-  FIELD(0x0080, float, b, /*NO SUFFIX*/)         \
-  FIELD(0x0084, int8_t, tint_pad_1, [124])       \
-  FIELD(0x0100, float2, c, /*NO SUFFIX*/)        \
-  FIELD(0x0108, uint, d, /*NO SUFFIX*/)          \
-  FIELD(0x010c, int8_t, tint_pad_2, [4])         \
-  FIELD(0x0110, packed_float3, e, /*NO SUFFIX*/) \
-  FIELD(0x011c, uint, f, /*NO SUFFIX*/)          \
-  FIELD(0x0120, float4, g, /*NO SUFFIX*/)        \
-  FIELD(0x0130, uint, h, /*NO SUFFIX*/)          \
-  FIELD(0x0134, int8_t, tint_pad_3, [4])         \
-  FIELD(0x0138, float2x2, i, /*NO SUFFIX*/)      \
-  FIELD(0x0148, uint, j, /*NO SUFFIX*/)          \
-  FIELD(0x014c, int8_t, tint_pad_4, [4])         \
-  FIELD(0x0150, float2x3, k, /*NO SUFFIX*/)      \
-  FIELD(0x0170, uint, l, /*NO SUFFIX*/)          \
-  FIELD(0x0174, int8_t, tint_pad_5, [12])        \
-  FIELD(0x0180, float2x4, m, /*NO SUFFIX*/)      \
-  FIELD(0x01a0, uint, n, /*NO SUFFIX*/)          \
-  FIELD(0x01a4, int8_t, tint_pad_6, [4])         \
-  FIELD(0x01a8, float3x2, o, /*NO SUFFIX*/)      \
-  FIELD(0x01c0, uint, p, /*NO SUFFIX*/)          \
-  FIELD(0x01c4, int8_t, tint_pad_7, [12])        \
-  FIELD(0x01d0, float3x3, q, /*NO SUFFIX*/)      \
-  FIELD(0x0200, uint, r, /*NO SUFFIX*/)          \
-  FIELD(0x0204, int8_t, tint_pad_8, [12])        \
-  FIELD(0x0210, float3x4, s, /*NO SUFFIX*/)      \
-  FIELD(0x0240, uint, t, /*NO SUFFIX*/)          \
-  FIELD(0x0244, int8_t, tint_pad_9, [4])         \
-  FIELD(0x0248, float4x2, u, /*NO SUFFIX*/)      \
-  FIELD(0x0268, uint, v, /*NO SUFFIX*/)          \
-  FIELD(0x026c, int8_t, tint_pad_10, [4])        \
-  FIELD(0x0270, float4x3, w, /*NO SUFFIX*/)      \
-  FIELD(0x02b0, uint, x, /*NO SUFFIX*/)          \
-  FIELD(0x02b4, int8_t, tint_pad_11, [12])       \
-  FIELD(0x02c0, float4x4, y, /*NO SUFFIX*/)      \
-  FIELD(0x0300, float, z, /*NO SUFFIX*/)         \
-  FIELD(0x0304, int8_t, tint_pad_12, [124])
-
-  // Check that the generated string is as expected.
-#define FIELD(ADDR, TYPE, NAME, SUFFIX) \
-  "  /* " #ADDR " */ " #TYPE " " #NAME #SUFFIX ";\n"
-  auto* expect = "struct S {\n" ALL_FIELDS() "};\n";
+    // Check that the generated string is as expected.
+#define FIELD(ADDR, TYPE, NAME, SUFFIX) "  /* " #ADDR " */ " #TYPE " " #NAME #SUFFIX ";\n"
+    auto* expect = "struct S {\n" ALL_FIELDS() "};\n";
 #undef FIELD
-  EXPECT_EQ(buf.String(), expect);
+    EXPECT_EQ(buf.String(), expect);
 
-  // 1.4 Metal and C++14
-  // The Metal programming language is a C++14-based Specification with
-  // extensions and restrictions. Refer to the C++14 Specification (also known
-  // as the ISO/IEC JTC1/SC22/WG21 N4431 Language Specification) for a detailed
-  // description of the language grammar.
-  //
-  // Tint is written in C++14, so use the compiler to verify the generated
-  // layout is as expected for C++14 / MSL.
-  {
-    struct S {
+    // 1.4 Metal and C++14
+    // The Metal programming language is a C++14-based Specification with
+    // extensions and restrictions. Refer to the C++14 Specification (also known
+    // as the ISO/IEC JTC1/SC22/WG21 N4431 Language Specification) for a detailed
+    // description of the language grammar.
+    //
+    // Tint is written in C++14, so use the compiler to verify the generated
+    // layout is as expected for C++14 / MSL.
+    {
+        struct S {
 #define FIELD(ADDR, TYPE, NAME, SUFFIX) TYPE NAME SUFFIX;
-      ALL_FIELDS()
+            ALL_FIELDS()
 #undef FIELD
-    };
+        };
 
 #define FIELD(ADDR, TYPE, NAME, SUFFIX) \
-  EXPECT_EQ(ADDR, static_cast<int>(offsetof(S, NAME))) << "Field " << #NAME;
-    ALL_FIELDS()
+    EXPECT_EQ(ADDR, static_cast<int>(offsetof(S, NAME))) << "Field " << #NAME;
+        ALL_FIELDS()
 #undef FIELD
-  }
+    }
 #undef ALL_FIELDS
 }
 
 TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_Structures) {
-  // inner_x: size(1024), align(512)
-  auto* inner_x =
-      Structure("inner_x", {
-                               Member("a", ty.i32()),
-                               Member("b", ty.f32(), {MemberAlign(512)}),
-                           });
+    // inner_x: size(1024), align(512)
+    auto* inner_x = Structure("inner_x", {
+                                             Member("a", ty.i32()),
+                                             Member("b", ty.f32(), {MemberAlign(512)}),
+                                         });
 
-  // inner_y: size(516), align(4)
-  auto* inner_y =
-      Structure("inner_y", {
-                               Member("a", ty.i32(), {MemberSize(512)}),
-                               Member("b", ty.f32()),
-                           });
+    // inner_y: size(516), align(4)
+    auto* inner_y = Structure("inner_y", {
+                                             Member("a", ty.i32(), {MemberSize(512)}),
+                                             Member("b", ty.f32()),
+                                         });
 
-  auto* s = Structure("S", {
-                               Member("a", ty.i32()),
-                               Member("b", ty.Of(inner_x)),
-                               Member("c", ty.f32()),
-                               Member("d", ty.Of(inner_y)),
-                               Member("e", ty.f32()),
-                           });
+    auto* s = Structure("S", {
+                                 Member("a", ty.i32()),
+                                 Member("b", ty.Of(inner_x)),
+                                 Member("c", ty.f32()),
+                                 Member("d", ty.Of(inner_y)),
+                                 Member("e", ty.f32()),
+                             });
 
-  Global("G", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    Global("G", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  TextGenerator::TextBuffer buf;
-  auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
-  ASSERT_TRUE(gen.EmitStructType(&buf, sem_s)) << gen.error();
+    TextGenerator::TextBuffer buf;
+    auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
+    ASSERT_TRUE(gen.EmitStructType(&buf, sem_s)) << gen.error();
 
-  // ALL_FIELDS() calls the macro FIELD(ADDR, TYPE, NAME, SUFFIX)
-  // for each field of the structure s.
-#define ALL_FIELDS()                       \
-  FIELD(0x0000, int, a, /*NO SUFFIX*/)     \
-  FIELD(0x0004, int8_t, tint_pad, [508])   \
-  FIELD(0x0200, inner_x, b, /*NO SUFFIX*/) \
-  FIELD(0x0600, float, c, /*NO SUFFIX*/)   \
-  FIELD(0x0604, inner_y, d, /*NO SUFFIX*/) \
-  FIELD(0x0808, float, e, /*NO SUFFIX*/)   \
-  FIELD(0x080c, int8_t, tint_pad_1, [500])
+    // ALL_FIELDS() calls the macro FIELD(ADDR, TYPE, NAME, SUFFIX)
+    // for each field of the structure s.
+#define ALL_FIELDS()                         \
+    FIELD(0x0000, int, a, /*NO SUFFIX*/)     \
+    FIELD(0x0004, int8_t, tint_pad, [508])   \
+    FIELD(0x0200, inner_x, b, /*NO SUFFIX*/) \
+    FIELD(0x0600, float, c, /*NO SUFFIX*/)   \
+    FIELD(0x0604, inner_y, d, /*NO SUFFIX*/) \
+    FIELD(0x0808, float, e, /*NO SUFFIX*/)   \
+    FIELD(0x080c, int8_t, tint_pad_1, [500])
 
-  // Check that the generated string is as expected.
-#define FIELD(ADDR, TYPE, NAME, SUFFIX) \
-  "  /* " #ADDR " */ " #TYPE " " #NAME #SUFFIX ";\n"
-  auto* expect = "struct S {\n" ALL_FIELDS() "};\n";
+    // Check that the generated string is as expected.
+#define FIELD(ADDR, TYPE, NAME, SUFFIX) "  /* " #ADDR " */ " #TYPE " " #NAME #SUFFIX ";\n"
+    auto* expect = "struct S {\n" ALL_FIELDS() "};\n";
 #undef FIELD
-  EXPECT_EQ(buf.String(), expect);
+    EXPECT_EQ(buf.String(), expect);
 
-  // 1.4 Metal and C++14
-  // The Metal programming language is a C++14-based Specification with
-  // extensions and restrictions. Refer to the C++14 Specification (also known
-  // as the ISO/IEC JTC1/SC22/WG21 N4431 Language Specification) for a detailed
-  // description of the language grammar.
-  //
-  // Tint is written in C++14, so use the compiler to verify the generated
-  // layout is as expected for C++14 / MSL.
-  {
-    struct inner_x {
-      uint32_t a;
-      alignas(512) float b;
-    };
-    CHECK_TYPE_SIZE_AND_ALIGN(inner_x, 1024, 512);
+    // 1.4 Metal and C++14
+    // The Metal programming language is a C++14-based Specification with
+    // extensions and restrictions. Refer to the C++14 Specification (also known
+    // as the ISO/IEC JTC1/SC22/WG21 N4431 Language Specification) for a detailed
+    // description of the language grammar.
+    //
+    // Tint is written in C++14, so use the compiler to verify the generated
+    // layout is as expected for C++14 / MSL.
+    {
+        struct inner_x {
+            uint32_t a;
+            alignas(512) float b;
+        };
+        CHECK_TYPE_SIZE_AND_ALIGN(inner_x, 1024, 512);
 
-    struct inner_y {
-      uint32_t a[128];
-      float b;
-    };
-    CHECK_TYPE_SIZE_AND_ALIGN(inner_y, 516, 4);
+        struct inner_y {
+            uint32_t a[128];
+            float b;
+        };
+        CHECK_TYPE_SIZE_AND_ALIGN(inner_y, 516, 4);
 
-    struct S {
+        struct S {
 #define FIELD(ADDR, TYPE, NAME, SUFFIX) TYPE NAME SUFFIX;
-      ALL_FIELDS()
+            ALL_FIELDS()
 #undef FIELD
-    };
+        };
 
 #define FIELD(ADDR, TYPE, NAME, SUFFIX) \
-  EXPECT_EQ(ADDR, static_cast<int>(offsetof(S, NAME))) << "Field " << #NAME;
-    ALL_FIELDS()
+    EXPECT_EQ(ADDR, static_cast<int>(offsetof(S, NAME))) << "Field " << #NAME;
+        ALL_FIELDS()
 #undef FIELD
-  }
+    }
 
 #undef ALL_FIELDS
 }
 
 TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_ArrayDefaultStride) {
-  // inner: size(1024), align(512)
-  auto* inner =
-      Structure("inner", {
-                             Member("a", ty.i32()),
-                             Member("b", ty.f32(), {MemberAlign(512)}),
-                         });
-
-  // array_x: size(28), align(4)
-  auto* array_x = ty.array<f32, 7>();
-
-  // array_y: size(4096), align(512)
-  auto* array_y = ty.array(ty.Of(inner), 4);
-
-  // array_z: size(4), align(4)
-  auto* array_z = ty.array<f32>();
-
-  auto* s = Structure("S", {
-                               Member("a", ty.i32()),
-                               Member("b", array_x),
-                               Member("c", ty.f32()),
-                               Member("d", array_y),
-                               Member("e", ty.f32()),
-                               Member("f", array_z),
-                           });
-
-  Global("G", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
-
-  GeneratorImpl& gen = Build();
-
-  TextGenerator::TextBuffer buf;
-  auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
-  ASSERT_TRUE(gen.EmitStructType(&buf, sem_s)) << gen.error();
-
-  // ALL_FIELDS() calls the macro FIELD(ADDR, TYPE, NAME, SUFFIX)
-  // for each field of the structure s.
-#define ALL_FIELDS()                     \
-  FIELD(0x0000, int, a, /*NO SUFFIX*/)   \
-  FIELD(0x0004, float, b, [7])           \
-  FIELD(0x0020, float, c, /*NO SUFFIX*/) \
-  FIELD(0x0024, int8_t, tint_pad, [476]) \
-  FIELD(0x0200, inner, d, [4])           \
-  FIELD(0x1200, float, e, /*NO SUFFIX*/) \
-  FIELD(0x1204, float, f, [1])           \
-  FIELD(0x1208, int8_t, tint_pad_1, [504])
-
-  // Check that the generated string is as expected.
-#define FIELD(ADDR, TYPE, NAME, SUFFIX) \
-  "  /* " #ADDR " */ " #TYPE " " #NAME #SUFFIX ";\n"
-  auto* expect = "struct S {\n" ALL_FIELDS() "};\n";
-#undef FIELD
-  EXPECT_EQ(buf.String(), expect);
-
-  // 1.4 Metal and C++14
-  // The Metal programming language is a C++14-based Specification with
-  // extensions and restrictions. Refer to the C++14 Specification (also known
-  // as the ISO/IEC JTC1/SC22/WG21 N4431 Language Specification) for a detailed
-  // description of the language grammar.
-  //
-  // Tint is written in C++14, so use the compiler to verify the generated
-  // layout is as expected for C++14 / MSL.
-  {
-    struct inner {
-      uint32_t a;
-      alignas(512) float b;
-    };
-    CHECK_TYPE_SIZE_AND_ALIGN(inner, 1024, 512);
+    // inner: size(1024), align(512)
+    auto* inner = Structure("inner", {
+                                         Member("a", ty.i32()),
+                                         Member("b", ty.f32(), {MemberAlign(512)}),
+                                     });
 
     // array_x: size(28), align(4)
-    using array_x = std::array<float, 7>;
-    CHECK_TYPE_SIZE_AND_ALIGN(array_x, 28, 4);
+    auto* array_x = ty.array<f32, 7>();
 
     // array_y: size(4096), align(512)
-    using array_y = std::array<inner, 4>;
-    CHECK_TYPE_SIZE_AND_ALIGN(array_y, 4096, 512);
+    auto* array_y = ty.array(ty.Of(inner), 4_u);
 
     // array_z: size(4), align(4)
-    using array_z = std::array<float, 1>;
-    CHECK_TYPE_SIZE_AND_ALIGN(array_z, 4, 4);
+    auto* array_z = ty.array<f32>();
 
-    struct S {
-#define FIELD(ADDR, TYPE, NAME, SUFFIX) TYPE NAME SUFFIX;
-      ALL_FIELDS()
+    auto* s = Structure("S", {
+                                 Member("a", ty.i32()),
+                                 Member("b", array_x),
+                                 Member("c", ty.f32()),
+                                 Member("d", array_y),
+                                 Member("e", ty.f32()),
+                                 Member("f", array_z),
+                             });
+
+    Global("G", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
+
+    GeneratorImpl& gen = Build();
+
+    TextGenerator::TextBuffer buf;
+    auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
+    ASSERT_TRUE(gen.EmitStructType(&buf, sem_s)) << gen.error();
+
+    // ALL_FIELDS() calls the macro FIELD(ADDR, TYPE, NAME, SUFFIX)
+    // for each field of the structure s.
+#define ALL_FIELDS()                       \
+    FIELD(0x0000, int, a, /*NO SUFFIX*/)   \
+    FIELD(0x0004, float, b, [7])           \
+    FIELD(0x0020, float, c, /*NO SUFFIX*/) \
+    FIELD(0x0024, int8_t, tint_pad, [476]) \
+    FIELD(0x0200, inner, d, [4])           \
+    FIELD(0x1200, float, e, /*NO SUFFIX*/) \
+    FIELD(0x1204, float, f, [1])           \
+    FIELD(0x1208, int8_t, tint_pad_1, [504])
+
+    // Check that the generated string is as expected.
+#define FIELD(ADDR, TYPE, NAME, SUFFIX) "  /* " #ADDR " */ " #TYPE " " #NAME #SUFFIX ";\n"
+    auto* expect = "struct S {\n" ALL_FIELDS() "};\n";
 #undef FIELD
-    };
+    EXPECT_EQ(buf.String(), expect);
+
+    // 1.4 Metal and C++14
+    // The Metal programming language is a C++14-based Specification with
+    // extensions and restrictions. Refer to the C++14 Specification (also known
+    // as the ISO/IEC JTC1/SC22/WG21 N4431 Language Specification) for a detailed
+    // description of the language grammar.
+    //
+    // Tint is written in C++14, so use the compiler to verify the generated
+    // layout is as expected for C++14 / MSL.
+    {
+        struct inner {
+            uint32_t a;
+            alignas(512) float b;
+        };
+        CHECK_TYPE_SIZE_AND_ALIGN(inner, 1024, 512);
+
+        // array_x: size(28), align(4)
+        using array_x = std::array<float, 7>;
+        CHECK_TYPE_SIZE_AND_ALIGN(array_x, 28, 4);
+
+        // array_y: size(4096), align(512)
+        using array_y = std::array<inner, 4>;
+        CHECK_TYPE_SIZE_AND_ALIGN(array_y, 4096, 512);
+
+        // array_z: size(4), align(4)
+        using array_z = std::array<float, 1>;
+        CHECK_TYPE_SIZE_AND_ALIGN(array_z, 4, 4);
+
+        struct S {
+#define FIELD(ADDR, TYPE, NAME, SUFFIX) TYPE NAME SUFFIX;
+            ALL_FIELDS()
+#undef FIELD
+        };
 
 #define FIELD(ADDR, TYPE, NAME, SUFFIX) \
-  EXPECT_EQ(ADDR, static_cast<int>(offsetof(S, NAME))) << "Field " << #NAME;
-    ALL_FIELDS()
+    EXPECT_EQ(ADDR, static_cast<int>(offsetof(S, NAME))) << "Field " << #NAME;
+        ALL_FIELDS()
 #undef FIELD
-  }
+    }
 
 #undef ALL_FIELDS
 }
 
 TEST_F(MslGeneratorImplTest, EmitType_Struct_Layout_ArrayVec3DefaultStride) {
-  // array: size(64), align(16)
-  auto* array = ty.array(ty.vec3<f32>(), 4);
+    // array: size(64), align(16)
+    auto* array = ty.array(ty.vec3<f32>(), 4_u);
 
-  auto* s = Structure("S", {
-                               Member("a", ty.i32()),
-                               Member("b", array),
-                               Member("c", ty.i32()),
-                           });
+    auto* s = Structure("S", {
+                                 Member("a", ty.i32()),
+                                 Member("b", array),
+                                 Member("c", ty.i32()),
+                             });
 
-  Global("G", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    Global("G", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  TextGenerator::TextBuffer buf;
-  auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
-  ASSERT_TRUE(gen.EmitStructType(&buf, sem_s)) << gen.error();
+    TextGenerator::TextBuffer buf;
+    auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
+    ASSERT_TRUE(gen.EmitStructType(&buf, sem_s)) << gen.error();
 
-  // ALL_FIELDS() calls the macro FIELD(ADDR, TYPE, NAME, SUFFIX)
-  // for each field of the structure s.
-#define ALL_FIELDS()                    \
-  FIELD(0x0000, int, a, /*NO SUFFIX*/)  \
-  FIELD(0x0004, int8_t, tint_pad, [12]) \
-  FIELD(0x0010, float3, b, [4])         \
-  FIELD(0x0050, int, c, /*NO SUFFIX*/)  \
-  FIELD(0x0054, int8_t, tint_pad_1, [12])
+    // ALL_FIELDS() calls the macro FIELD(ADDR, TYPE, NAME, SUFFIX)
+    // for each field of the structure s.
+#define ALL_FIELDS()                      \
+    FIELD(0x0000, int, a, /*NO SUFFIX*/)  \
+    FIELD(0x0004, int8_t, tint_pad, [12]) \
+    FIELD(0x0010, float3, b, [4])         \
+    FIELD(0x0050, int, c, /*NO SUFFIX*/)  \
+    FIELD(0x0054, int8_t, tint_pad_1, [12])
 
-  // Check that the generated string is as expected.
-#define FIELD(ADDR, TYPE, NAME, SUFFIX) \
-  "  /* " #ADDR " */ " #TYPE " " #NAME #SUFFIX ";\n"
-  auto* expect = "struct S {\n" ALL_FIELDS() "};\n";
+    // Check that the generated string is as expected.
+#define FIELD(ADDR, TYPE, NAME, SUFFIX) "  /* " #ADDR " */ " #TYPE " " #NAME #SUFFIX ";\n"
+    auto* expect = "struct S {\n" ALL_FIELDS() "};\n";
 #undef FIELD
-  EXPECT_EQ(buf.String(), expect);
+    EXPECT_EQ(buf.String(), expect);
 }
 
 TEST_F(MslGeneratorImplTest, AttemptTintPadSymbolCollision) {
-  auto* s = Structure(
-      "S",
-      {
-          // uses symbols tint_pad_[0..9] and tint_pad_[20..35]
-          Member("tint_pad_2", ty.i32(), {MemberSize(32)}),
-          Member("tint_pad_20", ty.f32(), {MemberAlign(128), MemberSize(128)}),
-          Member("tint_pad_33", ty.vec2<f32>()),
-          Member("tint_pad_1", ty.u32()),
-          Member("tint_pad_3", ty.vec3<f32>()),
-          Member("tint_pad_7", ty.u32()),
-          Member("tint_pad_25", ty.vec4<f32>()),
-          Member("tint_pad_5", ty.u32()),
-          Member("tint_pad_27", ty.mat2x2<f32>()),
-          Member("tint_pad_24", ty.u32()),
-          Member("tint_pad_23", ty.mat2x3<f32>()),
-          Member("tint_pad", ty.u32()),
-          Member("tint_pad_8", ty.mat2x4<f32>()),
-          Member("tint_pad_26", ty.u32()),
-          Member("tint_pad_29", ty.mat3x2<f32>()),
-          Member("tint_pad_6", ty.u32()),
-          Member("tint_pad_22", ty.mat3x3<f32>()),
-          Member("tint_pad_32", ty.u32()),
-          Member("tint_pad_34", ty.mat3x4<f32>()),
-          Member("tint_pad_35", ty.u32()),
-          Member("tint_pad_30", ty.mat4x2<f32>()),
-          Member("tint_pad_9", ty.u32()),
-          Member("tint_pad_31", ty.mat4x3<f32>()),
-          Member("tint_pad_28", ty.u32()),
-          Member("tint_pad_4", ty.mat4x4<f32>()),
-          Member("tint_pad_21", ty.f32()),
-      });
+    auto* s =
+        Structure("S", {
+                           // uses symbols tint_pad_[0..9] and tint_pad_[20..35]
+                           Member("tint_pad_2", ty.i32(), {MemberSize(32)}),
+                           Member("tint_pad_20", ty.f32(), {MemberAlign(128), MemberSize(128)}),
+                           Member("tint_pad_33", ty.vec2<f32>()),
+                           Member("tint_pad_1", ty.u32()),
+                           Member("tint_pad_3", ty.vec3<f32>()),
+                           Member("tint_pad_7", ty.u32()),
+                           Member("tint_pad_25", ty.vec4<f32>()),
+                           Member("tint_pad_5", ty.u32()),
+                           Member("tint_pad_27", ty.mat2x2<f32>()),
+                           Member("tint_pad_24", ty.u32()),
+                           Member("tint_pad_23", ty.mat2x3<f32>()),
+                           Member("tint_pad", ty.u32()),
+                           Member("tint_pad_8", ty.mat2x4<f32>()),
+                           Member("tint_pad_26", ty.u32()),
+                           Member("tint_pad_29", ty.mat3x2<f32>()),
+                           Member("tint_pad_6", ty.u32()),
+                           Member("tint_pad_22", ty.mat3x3<f32>()),
+                           Member("tint_pad_32", ty.u32()),
+                           Member("tint_pad_34", ty.mat3x4<f32>()),
+                           Member("tint_pad_35", ty.u32()),
+                           Member("tint_pad_30", ty.mat4x2<f32>()),
+                           Member("tint_pad_9", ty.u32()),
+                           Member("tint_pad_31", ty.mat4x3<f32>()),
+                           Member("tint_pad_28", ty.u32()),
+                           Member("tint_pad_4", ty.mat4x4<f32>()),
+                           Member("tint_pad_21", ty.f32()),
+                       });
 
-  Global("G", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    Global("G", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  TextGenerator::TextBuffer buf;
-  auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
-  ASSERT_TRUE(gen.EmitStructType(&buf, sem_s)) << gen.error();
-  EXPECT_EQ(buf.String(), R"(struct S {
+    TextGenerator::TextBuffer buf;
+    auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
+    ASSERT_TRUE(gen.EmitStructType(&buf, sem_s)) << gen.error();
+    EXPECT_EQ(buf.String(), R"(struct S {
   /* 0x0000 */ int tint_pad_2;
   /* 0x0004 */ int8_t tint_pad_10[124];
   /* 0x0080 */ float tint_pad_20;
@@ -634,23 +626,23 @@
 }
 
 TEST_F(MslGeneratorImplTest, EmitType_Struct_WithAttribute) {
-  auto* s = Structure("S", {
-                               Member("a", ty.i32()),
-                               Member("b", ty.f32()),
-                           });
+    auto* s = Structure("S", {
+                                 Member("a", ty.i32()),
+                                 Member("b", ty.f32()),
+                             });
 
-  Global("G", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    Global("G", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  TextGenerator::TextBuffer buf;
-  auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
-  ASSERT_TRUE(gen.EmitStructType(&buf, sem_s)) << gen.error();
-  EXPECT_EQ(buf.String(), R"(struct S {
+    TextGenerator::TextBuffer buf;
+    auto* sem_s = program->TypeOf(s)->As<sem::Struct>();
+    ASSERT_TRUE(gen.EmitStructType(&buf, sem_s)) << gen.error();
+    EXPECT_EQ(buf.String(), R"(struct S {
   /* 0x0000 */ int a;
   /* 0x0004 */ float b;
 };
@@ -658,186 +650,175 @@
 }
 
 TEST_F(MslGeneratorImplTest, EmitType_U32) {
-  auto* u32 = create<sem::U32>();
+    auto* u32 = create<sem::U32>();
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, u32, "")) << gen.error();
-  EXPECT_EQ(out.str(), "uint");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, u32, "")) << gen.error();
+    EXPECT_EQ(out.str(), "uint");
 }
 
 TEST_F(MslGeneratorImplTest, EmitType_Vector) {
-  auto* f32 = create<sem::F32>();
-  auto* vec3 = create<sem::Vector>(f32, 3u);
+    auto* f32 = create<sem::F32>();
+    auto* vec3 = create<sem::Vector>(f32, 3u);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, vec3, "")) << gen.error();
-  EXPECT_EQ(out.str(), "float3");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, vec3, "")) << gen.error();
+    EXPECT_EQ(out.str(), "float3");
 }
 
 TEST_F(MslGeneratorImplTest, EmitType_Void) {
-  auto* void_ = create<sem::Void>();
+    auto* void_ = create<sem::Void>();
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, void_, "")) << gen.error();
-  EXPECT_EQ(out.str(), "void");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, void_, "")) << gen.error();
+    EXPECT_EQ(out.str(), "void");
 }
 
 TEST_F(MslGeneratorImplTest, EmitType_Sampler) {
-  auto* sampler = create<sem::Sampler>(ast::SamplerKind::kSampler);
+    auto* sampler = create<sem::Sampler>(ast::SamplerKind::kSampler);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, sampler, "")) << gen.error();
-  EXPECT_EQ(out.str(), "sampler");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, sampler, "")) << gen.error();
+    EXPECT_EQ(out.str(), "sampler");
 }
 
 TEST_F(MslGeneratorImplTest, EmitType_SamplerComparison) {
-  auto* sampler = create<sem::Sampler>(ast::SamplerKind::kComparisonSampler);
+    auto* sampler = create<sem::Sampler>(ast::SamplerKind::kComparisonSampler);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, sampler, "")) << gen.error();
-  EXPECT_EQ(out.str(), "sampler");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, sampler, "")) << gen.error();
+    EXPECT_EQ(out.str(), "sampler");
 }
 
 struct MslDepthTextureData {
-  ast::TextureDimension dim;
-  std::string result;
+    ast::TextureDimension dim;
+    std::string result;
 };
 inline std::ostream& operator<<(std::ostream& out, MslDepthTextureData data) {
-  out << data.dim;
-  return out;
+    out << data.dim;
+    return out;
 }
 using MslDepthTexturesTest = TestParamHelper<MslDepthTextureData>;
 TEST_P(MslDepthTexturesTest, Emit) {
-  auto params = GetParam();
+    auto params = GetParam();
 
-  sem::DepthTexture s(params.dim);
+    sem::DepthTexture s(params.dim);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, &s, "")) << gen.error();
-  EXPECT_EQ(out.str(), params.result);
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, &s, "")) << gen.error();
+    EXPECT_EQ(out.str(), params.result);
 }
 INSTANTIATE_TEST_SUITE_P(
     MslGeneratorImplTest,
     MslDepthTexturesTest,
-    testing::Values(MslDepthTextureData{ast::TextureDimension::k2d,
-                                        "depth2d<float, access::sample>"},
-                    MslDepthTextureData{ast::TextureDimension::k2dArray,
-                                        "depth2d_array<float, access::sample>"},
-                    MslDepthTextureData{ast::TextureDimension::kCube,
-                                        "depthcube<float, access::sample>"},
-                    MslDepthTextureData{
-                        ast::TextureDimension::kCubeArray,
-                        "depthcube_array<float, access::sample>"}));
+    testing::Values(
+        MslDepthTextureData{ast::TextureDimension::k2d, "depth2d<float, access::sample>"},
+        MslDepthTextureData{ast::TextureDimension::k2dArray,
+                            "depth2d_array<float, access::sample>"},
+        MslDepthTextureData{ast::TextureDimension::kCube, "depthcube<float, access::sample>"},
+        MslDepthTextureData{ast::TextureDimension::kCubeArray,
+                            "depthcube_array<float, access::sample>"}));
 
 using MslDepthMultisampledTexturesTest = TestHelper;
 TEST_F(MslDepthMultisampledTexturesTest, Emit) {
-  sem::DepthMultisampledTexture s(ast::TextureDimension::k2d);
+    sem::DepthMultisampledTexture s(ast::TextureDimension::k2d);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, &s, "")) << gen.error();
-  EXPECT_EQ(out.str(), "depth2d_ms<float, access::read>");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, &s, "")) << gen.error();
+    EXPECT_EQ(out.str(), "depth2d_ms<float, access::read>");
 }
 
 struct MslTextureData {
-  ast::TextureDimension dim;
-  std::string result;
+    ast::TextureDimension dim;
+    std::string result;
 };
 inline std::ostream& operator<<(std::ostream& out, MslTextureData data) {
-  out << data.dim;
-  return out;
+    out << data.dim;
+    return out;
 }
 using MslSampledtexturesTest = TestParamHelper<MslTextureData>;
 TEST_P(MslSampledtexturesTest, Emit) {
-  auto params = GetParam();
+    auto params = GetParam();
 
-  auto* f32 = create<sem::F32>();
-  auto* s = create<sem::SampledTexture>(params.dim, f32);
+    auto* f32 = create<sem::F32>();
+    auto* s = create<sem::SampledTexture>(params.dim, f32);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, s, "")) << gen.error();
-  EXPECT_EQ(out.str(), params.result);
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, s, "")) << gen.error();
+    EXPECT_EQ(out.str(), params.result);
 }
 INSTANTIATE_TEST_SUITE_P(
     MslGeneratorImplTest,
     MslSampledtexturesTest,
-    testing::Values(MslTextureData{ast::TextureDimension::k1d,
-                                   "texture1d<float, access::sample>"},
-                    MslTextureData{ast::TextureDimension::k2d,
-                                   "texture2d<float, access::sample>"},
-                    MslTextureData{ast::TextureDimension::k2dArray,
-                                   "texture2d_array<float, access::sample>"},
-                    MslTextureData{ast::TextureDimension::k3d,
-                                   "texture3d<float, access::sample>"},
-                    MslTextureData{ast::TextureDimension::kCube,
-                                   "texturecube<float, access::sample>"},
-                    MslTextureData{
-                        ast::TextureDimension::kCubeArray,
-                        "texturecube_array<float, access::sample>"}));
+    testing::Values(
+        MslTextureData{ast::TextureDimension::k1d, "texture1d<float, access::sample>"},
+        MslTextureData{ast::TextureDimension::k2d, "texture2d<float, access::sample>"},
+        MslTextureData{ast::TextureDimension::k2dArray, "texture2d_array<float, access::sample>"},
+        MslTextureData{ast::TextureDimension::k3d, "texture3d<float, access::sample>"},
+        MslTextureData{ast::TextureDimension::kCube, "texturecube<float, access::sample>"},
+        MslTextureData{ast::TextureDimension::kCubeArray,
+                       "texturecube_array<float, access::sample>"}));
 
 TEST_F(MslGeneratorImplTest, Emit_TypeMultisampledTexture) {
-  auto* u32 = create<sem::U32>();
-  auto* ms = create<sem::MultisampledTexture>(ast::TextureDimension::k2d, u32);
+    auto* u32 = create<sem::U32>();
+    auto* ms = create<sem::MultisampledTexture>(ast::TextureDimension::k2d, u32);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, ms, "")) << gen.error();
-  EXPECT_EQ(out.str(), "texture2d_ms<uint, access::read>");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, ms, "")) << gen.error();
+    EXPECT_EQ(out.str(), "texture2d_ms<uint, access::read>");
 }
 
 struct MslStorageTextureData {
-  ast::TextureDimension dim;
-  std::string result;
+    ast::TextureDimension dim;
+    std::string result;
 };
 inline std::ostream& operator<<(std::ostream& out, MslStorageTextureData data) {
-  return out << data.dim;
+    return out << data.dim;
 }
 using MslStorageTexturesTest = TestParamHelper<MslStorageTextureData>;
 TEST_P(MslStorageTexturesTest, Emit) {
-  auto params = GetParam();
+    auto params = GetParam();
 
-  auto* s = ty.storage_texture(params.dim, ast::TexelFormat::kR32Float,
-                               ast::Access::kWrite);
-  Global("test_var", s,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    auto* s = ty.storage_texture(params.dim, ast::TexelFormat::kR32Float, ast::Access::kWrite);
+    Global("test_var", s,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, program->TypeOf(s), "")) << gen.error();
-  EXPECT_EQ(out.str(), params.result);
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, program->TypeOf(s), "")) << gen.error();
+    EXPECT_EQ(out.str(), params.result);
 }
 INSTANTIATE_TEST_SUITE_P(
     MslGeneratorImplTest,
     MslStorageTexturesTest,
-    testing::Values(MslStorageTextureData{ast::TextureDimension::k1d,
-                                          "texture1d<float, access::write>"},
-                    MslStorageTextureData{ast::TextureDimension::k2d,
-                                          "texture2d<float, access::write>"},
-                    MslStorageTextureData{
-                        ast::TextureDimension::k2dArray,
-                        "texture2d_array<float, access::write>"},
-                    MslStorageTextureData{ast::TextureDimension::k3d,
-                                          "texture3d<float, access::write>"}));
+    testing::Values(
+        MslStorageTextureData{ast::TextureDimension::k1d, "texture1d<float, access::write>"},
+        MslStorageTextureData{ast::TextureDimension::k2d, "texture2d<float, access::write>"},
+        MslStorageTextureData{ast::TextureDimension::k2dArray,
+                              "texture2d_array<float, access::write>"},
+        MslStorageTextureData{ast::TextureDimension::k3d, "texture3d<float, access::write>"}));
 
 }  // namespace
 }  // namespace tint::writer::msl
diff --git a/src/tint/writer/msl/generator_impl_unary_op_test.cc b/src/tint/writer/msl/generator_impl_unary_op_test.cc
index c40183d..a1aecd9 100644
--- a/src/tint/writer/msl/generator_impl_unary_op_test.cc
+++ b/src/tint/writer/msl/generator_impl_unary_op_test.cc
@@ -20,82 +20,77 @@
 using MslUnaryOpTest = TestHelper;
 
 TEST_F(MslUnaryOpTest, AddressOf) {
-  Global("expr", ty.f32(), ast::StorageClass::kPrivate);
-  auto* op =
-      create<ast::UnaryOpExpression>(ast::UnaryOp::kAddressOf, Expr("expr"));
-  WrapInFunction(op);
+    Global("expr", ty.f32(), ast::StorageClass::kPrivate);
+    auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kAddressOf, Expr("expr"));
+    WrapInFunction(op);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
-  EXPECT_EQ(out.str(), "&(expr)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
+    EXPECT_EQ(out.str(), "&(expr)");
 }
 
 TEST_F(MslUnaryOpTest, Complement) {
-  Global("expr", ty.i32(), ast::StorageClass::kPrivate);
-  auto* op =
-      create<ast::UnaryOpExpression>(ast::UnaryOp::kComplement, Expr("expr"));
-  WrapInFunction(op);
+    Global("expr", ty.i32(), ast::StorageClass::kPrivate);
+    auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kComplement, Expr("expr"));
+    WrapInFunction(op);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
-  EXPECT_EQ(out.str(), "~(expr)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
+    EXPECT_EQ(out.str(), "~(expr)");
 }
 
 TEST_F(MslUnaryOpTest, Indirection) {
-  Global("G", ty.f32(), ast::StorageClass::kPrivate);
-  auto* p = Const(
-      "expr", nullptr,
-      create<ast::UnaryOpExpression>(ast::UnaryOp::kAddressOf, Expr("G")));
-  auto* op =
-      create<ast::UnaryOpExpression>(ast::UnaryOp::kIndirection, Expr("expr"));
-  WrapInFunction(p, op);
+    Global("G", ty.f32(), ast::StorageClass::kPrivate);
+    auto* p =
+        Let("expr", nullptr, create<ast::UnaryOpExpression>(ast::UnaryOp::kAddressOf, Expr("G")));
+    auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kIndirection, Expr("expr"));
+    WrapInFunction(p, op);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
-  EXPECT_EQ(out.str(), "*(expr)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
+    EXPECT_EQ(out.str(), "*(expr)");
 }
 
 TEST_F(MslUnaryOpTest, Not) {
-  Global("expr", ty.bool_(), ast::StorageClass::kPrivate);
-  auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kNot, Expr("expr"));
-  WrapInFunction(op);
+    Global("expr", ty.bool_(), ast::StorageClass::kPrivate);
+    auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kNot, Expr("expr"));
+    WrapInFunction(op);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
-  EXPECT_EQ(out.str(), "!(expr)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
+    EXPECT_EQ(out.str(), "!(expr)");
 }
 
 TEST_F(MslUnaryOpTest, Negation) {
-  Global("expr", ty.i32(), ast::StorageClass::kPrivate);
-  auto* op =
-      create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation, Expr("expr"));
-  WrapInFunction(op);
+    Global("expr", ty.i32(), ast::StorageClass::kPrivate);
+    auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation, Expr("expr"));
+    WrapInFunction(op);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
-  EXPECT_EQ(out.str(), "tint_unary_minus(expr)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
+    EXPECT_EQ(out.str(), "tint_unary_minus(expr)");
 }
 
 TEST_F(MslUnaryOpTest, NegationOfIntMin) {
-  auto* op = create<ast::UnaryOpExpression>(
-      ast::UnaryOp::kNegation, Expr(std::numeric_limits<int32_t>::min()));
-  WrapInFunction(op);
+    auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation,
+                                              Expr(i32(std::numeric_limits<int32_t>::min())));
+    WrapInFunction(op);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
-  EXPECT_EQ(out.str(), "tint_unary_minus((-2147483647 - 1))");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
+    EXPECT_EQ(out.str(), "tint_unary_minus((-2147483647 - 1))");
 }
 
 }  // namespace
diff --git a/src/tint/writer/msl/generator_impl_variable_decl_statement_test.cc b/src/tint/writer/msl/generator_impl_variable_decl_statement_test.cc
index ce26ab9..cd8190f 100644
--- a/src/tint/writer/msl/generator_impl_variable_decl_statement_test.cc
+++ b/src/tint/writer/msl/generator_impl_variable_decl_statement_test.cc
@@ -24,140 +24,139 @@
 using MslGeneratorImplTest = TestHelper;
 
 TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement) {
-  auto* var = Var("a", ty.f32(), ast::StorageClass::kNone);
-  auto* stmt = Decl(var);
-  WrapInFunction(stmt);
+    auto* var = Var("a", ty.f32(), ast::StorageClass::kNone);
+    auto* stmt = Decl(var);
+    WrapInFunction(stmt);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
-  EXPECT_EQ(gen.result(), "  float a = 0.0f;\n");
+    ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
+    EXPECT_EQ(gen.result(), "  float a = 0.0f;\n");
 }
 
 TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Const) {
-  auto* var = Const("a", ty.f32(), Construct(ty.f32()));
-  auto* stmt = Decl(var);
-  WrapInFunction(stmt);
+    auto* var = Let("a", ty.f32(), Construct(ty.f32()));
+    auto* stmt = Decl(var);
+    WrapInFunction(stmt);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
-  EXPECT_EQ(gen.result(), "  float const a = float();\n");
+    ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
+    EXPECT_EQ(gen.result(), "  float const a = float();\n");
 }
 
 TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Array) {
-  auto* var = Var("a", ty.array<f32, 5>(), ast::StorageClass::kNone);
-  auto* stmt = Decl(var);
-  WrapInFunction(stmt);
+    auto* var = Var("a", ty.array<f32, 5>(), ast::StorageClass::kNone);
+    auto* stmt = Decl(var);
+    WrapInFunction(stmt);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
-  EXPECT_EQ(gen.result(), "  float a[5] = {0.0f};\n");
+    ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
+    EXPECT_EQ(gen.result(), "  float a[5] = {0.0f};\n");
 }
 
 TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Struct) {
-  auto* s = Structure("S", {
-                               Member("a", ty.f32()),
-                               Member("b", ty.f32()),
-                           });
+    auto* s = Structure("S", {
+                                 Member("a", ty.f32()),
+                                 Member("b", ty.f32()),
+                             });
 
-  auto* var = Var("a", ty.Of(s), ast::StorageClass::kNone);
-  auto* stmt = Decl(var);
-  WrapInFunction(stmt);
+    auto* var = Var("a", ty.Of(s), ast::StorageClass::kNone);
+    auto* stmt = Decl(var);
+    WrapInFunction(stmt);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  S a = {};
+    ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  S a = {};
 )");
 }
 
 TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Vector) {
-  auto* var = Var("a", ty.vec2<f32>());
-  auto* stmt = Decl(var);
-  WrapInFunction(stmt);
+    auto* var = Var("a", ty.vec2<f32>());
+    auto* stmt = Decl(var);
+    WrapInFunction(stmt);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
-  EXPECT_EQ(gen.result(), "  float2 a = 0.0f;\n");
+    ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
+    EXPECT_EQ(gen.result(), "  float2 a = 0.0f;\n");
 }
 
 TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Matrix) {
-  auto* var = Var("a", ty.mat3x2<f32>());
+    auto* var = Var("a", ty.mat3x2<f32>());
 
-  auto* stmt = Decl(var);
-  WrapInFunction(stmt);
+    auto* stmt = Decl(var);
+    WrapInFunction(stmt);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
-  EXPECT_EQ(gen.result(), "  float3x2 a = float3x2(0.0f);\n");
+    ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
+    EXPECT_EQ(gen.result(), "  float3x2 a = float3x2(0.0f);\n");
 }
 
 TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Private) {
-  Global("a", ty.f32(), ast::StorageClass::kPrivate);
+    Global("a", ty.f32(), ast::StorageClass::kPrivate);
 
-  WrapInFunction(Expr("a"));
+    WrapInFunction(Expr("a"));
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("thread float tint_symbol_1 = 0.0f;\n"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("thread float tint_symbol_1 = 0.0f;\n"));
 }
 
 TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Initializer_Private) {
-  GlobalConst("initializer", ty.f32(), Expr(0.f));
-  Global("a", ty.f32(), ast::StorageClass::kPrivate, Expr("initializer"));
+    GlobalConst("initializer", ty.f32(), Expr(0.f));
+    Global("a", ty.f32(), ast::StorageClass::kPrivate, Expr("initializer"));
 
-  WrapInFunction(Expr("a"));
+    WrapInFunction(Expr("a"));
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(),
-              HasSubstr("thread float tint_symbol_1 = initializer;\n"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("thread float tint_symbol_1 = initializer;\n"));
 }
 
 TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Workgroup) {
-  Global("a", ty.f32(), ast::StorageClass::kWorkgroup);
+    Global("a", ty.f32(), ast::StorageClass::kWorkgroup);
 
-  WrapInFunction(Expr("a"));
+    WrapInFunction(Expr("a"));
 
-  GeneratorImpl& gen = SanitizeAndBuild();
+    GeneratorImpl& gen = SanitizeAndBuild();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("threadgroup float tint_symbol_2;\n"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("threadgroup float tint_symbol_2;\n"));
 }
 
 TEST_F(MslGeneratorImplTest, Emit_VariableDeclStatement_Initializer_ZeroVec) {
-  auto* zero_vec = vec3<f32>();
+    auto* zero_vec = vec3<f32>();
 
-  auto* var = Var("a", ty.vec3<f32>(), ast::StorageClass::kNone, zero_vec);
-  auto* stmt = Decl(var);
-  WrapInFunction(stmt);
+    auto* var = Var("a", ty.vec3<f32>(), ast::StorageClass::kNone, zero_vec);
+    auto* stmt = Decl(var);
+    WrapInFunction(stmt);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(float3 a = float3();
+    ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(float3 a = float3();
 )");
 }
 
diff --git a/src/tint/writer/msl/test_helper.h b/src/tint/writer/msl/test_helper.h
index 25fb046..f1b530d 100644
--- a/src/tint/writer/msl/test_helper.h
+++ b/src/tint/writer/msl/test_helper.h
@@ -29,66 +29,64 @@
 /// Helper class for testing
 template <typename BASE>
 class TestHelperBase : public BASE, public ProgramBuilder {
- public:
-  TestHelperBase() = default;
-  ~TestHelperBase() override = default;
+  public:
+    TestHelperBase() = default;
+    ~TestHelperBase() override = default;
 
-  /// Builds and returns a GeneratorImpl from the program.
-  /// @note The generator is only built once. Multiple calls to Build() will
-  /// return the same GeneratorImpl without rebuilding.
-  /// @return the built generator
-  GeneratorImpl& Build() {
-    if (gen_) {
-      return *gen_;
+    /// Builds and returns a GeneratorImpl from the program.
+    /// @note The generator is only built once. Multiple calls to Build() will
+    /// return the same GeneratorImpl without rebuilding.
+    /// @return the built generator
+    GeneratorImpl& Build() {
+        if (gen_) {
+            return *gen_;
+        }
+        [&]() {
+            ASSERT_TRUE(IsValid()) << "Builder program is not valid\n"
+                                   << diag::Formatter().format(Diagnostics());
+        }();
+        program = std::make_unique<Program>(std::move(*this));
+        [&]() {
+            ASSERT_TRUE(program->IsValid()) << diag::Formatter().format(program->Diagnostics());
+        }();
+        gen_ = std::make_unique<GeneratorImpl>(program.get());
+        return *gen_;
     }
-    [&]() {
-      ASSERT_TRUE(IsValid()) << "Builder program is not valid\n"
-                             << diag::Formatter().format(Diagnostics());
-    }();
-    program = std::make_unique<Program>(std::move(*this));
-    [&]() {
-      ASSERT_TRUE(program->IsValid())
-          << diag::Formatter().format(program->Diagnostics());
-    }();
-    gen_ = std::make_unique<GeneratorImpl>(program.get());
-    return *gen_;
-  }
 
-  /// Builds the program, runs the program through the transform::Msl sanitizer
-  /// and returns a GeneratorImpl from the sanitized program.
-  /// @param options The MSL generator options.
-  /// @note The generator is only built once. Multiple calls to Build() will
-  /// return the same GeneratorImpl without rebuilding.
-  /// @return the built generator
-  GeneratorImpl& SanitizeAndBuild(const Options& options = {}) {
-    if (gen_) {
-      return *gen_;
+    /// Builds the program, runs the program through the transform::Msl sanitizer
+    /// and returns a GeneratorImpl from the sanitized program.
+    /// @param options The MSL generator options.
+    /// @note The generator is only built once. Multiple calls to Build() will
+    /// return the same GeneratorImpl without rebuilding.
+    /// @return the built generator
+    GeneratorImpl& SanitizeAndBuild(const Options& options = {}) {
+        if (gen_) {
+            return *gen_;
+        }
+        [&]() {
+            ASSERT_TRUE(IsValid()) << "Builder program is not valid\n"
+                                   << diag::Formatter().format(Diagnostics());
+        }();
+        program = std::make_unique<Program>(std::move(*this));
+        [&]() {
+            ASSERT_TRUE(program->IsValid()) << diag::Formatter().format(program->Diagnostics());
+        }();
+
+        auto result = Sanitize(program.get(), options);
+        [&]() {
+            ASSERT_TRUE(result.program.IsValid())
+                << diag::Formatter().format(result.program.Diagnostics());
+        }();
+        *program = std::move(result.program);
+        gen_ = std::make_unique<GeneratorImpl>(program.get());
+        return *gen_;
     }
-    [&]() {
-      ASSERT_TRUE(IsValid()) << "Builder program is not valid\n"
-                             << diag::Formatter().format(Diagnostics());
-    }();
-    program = std::make_unique<Program>(std::move(*this));
-    [&]() {
-      ASSERT_TRUE(program->IsValid())
-          << diag::Formatter().format(program->Diagnostics());
-    }();
 
-    auto result = Sanitize(program.get(), options);
-    [&]() {
-      ASSERT_TRUE(result.program.IsValid())
-          << diag::Formatter().format(result.program.Diagnostics());
-    }();
-    *program = std::move(result.program);
-    gen_ = std::make_unique<GeneratorImpl>(program.get());
-    return *gen_;
-  }
+    /// The program built with a call to Build()
+    std::unique_ptr<Program> program;
 
-  /// The program built with a call to Build()
-  std::unique_ptr<Program> program;
-
- private:
-  std::unique_ptr<GeneratorImpl> gen_;
+  private:
+    std::unique_ptr<GeneratorImpl> gen_;
 };
 using TestHelper = TestHelperBase<testing::Test>;
 
diff --git a/src/tint/writer/spirv/binary_writer.cc b/src/tint/writer/spirv/binary_writer.cc
index aa32f38..69ac353 100644
--- a/src/tint/writer/spirv/binary_writer.cc
+++ b/src/tint/writer/spirv/binary_writer.cc
@@ -15,6 +15,7 @@
 #include "src/tint/writer/spirv/binary_writer.h"
 
 #include <cstring>
+#include <string>
 
 namespace tint::writer::spirv {
 namespace {
@@ -28,46 +29,47 @@
 BinaryWriter::~BinaryWriter() = default;
 
 void BinaryWriter::WriteBuilder(Builder* builder) {
-  out_.reserve(builder->total_size());
-  builder->iterate(
-      [this](const Instruction& inst) { this->process_instruction(inst); });
+    out_.reserve(builder->total_size());
+    builder->iterate([this](const Instruction& inst) { this->process_instruction(inst); });
 }
 
 void BinaryWriter::WriteInstruction(const Instruction& inst) {
-  process_instruction(inst);
+    process_instruction(inst);
 }
 
 void BinaryWriter::WriteHeader(uint32_t bound) {
-  out_.push_back(spv::MagicNumber);
-  out_.push_back(0x00010300);  // Version 1.3
-  out_.push_back(kGeneratorId);
-  out_.push_back(bound);
-  out_.push_back(0);
+    out_.push_back(spv::MagicNumber);
+    out_.push_back(0x00010300);  // Version 1.3
+    out_.push_back(kGeneratorId);
+    out_.push_back(bound);
+    out_.push_back(0);
 }
 
 void BinaryWriter::process_instruction(const Instruction& inst) {
-  out_.push_back(inst.word_length() << 16 |
-                 static_cast<uint32_t>(inst.opcode()));
-  for (const auto& op : inst.operands()) {
-    process_op(op);
-  }
+    out_.push_back(inst.word_length() << 16 | static_cast<uint32_t>(inst.opcode()));
+    for (const auto& op : inst.operands()) {
+        process_op(op);
+    }
 }
 
 void BinaryWriter::process_op(const Operand& op) {
-  if (op.IsFloat()) {
-    // Allocate space for the float
-    out_.push_back(0);
-    auto f = op.to_f();
-    uint8_t* ptr = reinterpret_cast<uint8_t*>(out_.data() + (out_.size() - 1));
-    memcpy(ptr, &f, 4);
-  } else if (op.IsInt()) {
-    out_.push_back(op.to_i());
-  } else {
-    auto idx = out_.size();
-    const auto& str = op.to_s();
-    out_.resize(out_.size() + op.length(), 0);
-    memcpy(out_.data() + idx, str.c_str(), str.size() + 1);
-  }
+    if (auto* i = std::get_if<uint32_t>(&op)) {
+        out_.push_back(*i);
+        return;
+    }
+    if (auto* f = std::get_if<float>(&op)) {
+        // Allocate space for the float
+        out_.push_back(0);
+        uint8_t* ptr = reinterpret_cast<uint8_t*>(out_.data() + (out_.size() - 1));
+        memcpy(ptr, f, 4);
+        return;
+    }
+    if (auto* str = std::get_if<std::string>(&op)) {
+        auto idx = out_.size();
+        out_.resize(out_.size() + OperandLength(op), 0);
+        memcpy(out_.data() + idx, str->c_str(), str->size() + 1);
+        return;
+    }
 }
 
 }  // namespace tint::writer::spirv
diff --git a/src/tint/writer/spirv/binary_writer.h b/src/tint/writer/spirv/binary_writer.h
index a071d7c..e1e7f68 100644
--- a/src/tint/writer/spirv/binary_writer.h
+++ b/src/tint/writer/spirv/binary_writer.h
@@ -23,36 +23,36 @@
 
 /// Writer to convert from builder to SPIR-V binary
 class BinaryWriter {
- public:
-  /// Constructor
-  BinaryWriter();
-  ~BinaryWriter();
+  public:
+    /// Constructor
+    BinaryWriter();
+    ~BinaryWriter();
 
-  /// Writes the SPIR-V header.
-  /// @param bound the bound to output
-  void WriteHeader(uint32_t bound);
+    /// Writes the SPIR-V header.
+    /// @param bound the bound to output
+    void WriteHeader(uint32_t bound);
 
-  /// Writes the given builder data into a binary. Note, this does not emit
-  /// the SPIR-V header. You **must** call WriteHeader() before WriteBuilder()
-  /// if you want the SPIR-V to be emitted.
-  /// @param builder the builder to assemble from
-  void WriteBuilder(Builder* builder);
+    /// Writes the given builder data into a binary. Note, this does not emit
+    /// the SPIR-V header. You **must** call WriteHeader() before WriteBuilder()
+    /// if you want the SPIR-V to be emitted.
+    /// @param builder the builder to assemble from
+    void WriteBuilder(Builder* builder);
 
-  /// Writes the given instruction into the binary.
-  /// @param inst the instruction to assemble
-  void WriteInstruction(const Instruction& inst);
+    /// Writes the given instruction into the binary.
+    /// @param inst the instruction to assemble
+    void WriteInstruction(const Instruction& inst);
 
-  /// @returns the assembled SPIR-V
-  const std::vector<uint32_t>& result() const { return out_; }
+    /// @returns the assembled SPIR-V
+    const std::vector<uint32_t>& result() const { return out_; }
 
-  /// @returns the assembled SPIR-V
-  std::vector<uint32_t>& result() { return out_; }
+    /// @returns the assembled SPIR-V
+    std::vector<uint32_t>& result() { return out_; }
 
- private:
-  void process_instruction(const Instruction& inst);
-  void process_op(const Operand& op);
+  private:
+    void process_instruction(const Instruction& inst);
+    void process_op(const Operand& op);
 
-  std::vector<uint32_t> out_;
+    std::vector<uint32_t> out_;
 };
 
 }  // namespace tint::writer::spirv
diff --git a/src/tint/writer/spirv/binary_writer_test.cc b/src/tint/writer/spirv/binary_writer_test.cc
index 5d6b8b8..11812cf 100644
--- a/src/tint/writer/spirv/binary_writer_test.cc
+++ b/src/tint/writer/spirv/binary_writer_test.cc
@@ -20,106 +20,106 @@
 using BinaryWriterTest = TestHelper;
 
 TEST_F(BinaryWriterTest, Preamble) {
-  BinaryWriter bw;
-  bw.WriteHeader(5);
+    BinaryWriter bw;
+    bw.WriteHeader(5);
 
-  auto res = bw.result();
-  ASSERT_EQ(res.size(), 5u);
-  EXPECT_EQ(res[0], spv::MagicNumber);
-  EXPECT_EQ(res[1], 0x00010300u);  // SPIR-V 1.3
-  EXPECT_EQ(res[2], 23u << 16);    // Generator ID
-  EXPECT_EQ(res[3], 5u);           // ID Bound
-  EXPECT_EQ(res[4], 0u);           // Reserved
+    auto res = bw.result();
+    ASSERT_EQ(res.size(), 5u);
+    EXPECT_EQ(res[0], spv::MagicNumber);
+    EXPECT_EQ(res[1], 0x00010300u);  // SPIR-V 1.3
+    EXPECT_EQ(res[2], 23u << 16);    // Generator ID
+    EXPECT_EQ(res[3], 5u);           // ID Bound
+    EXPECT_EQ(res[4], 0u);           // Reserved
 }
 
 TEST_F(BinaryWriterTest, Float) {
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_annot(spv::Op::OpKill, {Operand::Float(2.4f)});
-  BinaryWriter bw;
-  bw.WriteBuilder(&b);
+    b.push_annot(spv::Op::OpKill, {Operand(2.4f)});
+    BinaryWriter bw;
+    bw.WriteBuilder(&b);
 
-  auto res = bw.result();
-  ASSERT_EQ(res.size(), 2u);
-  float f;
-  memcpy(&f, res.data() + 1, 4);
-  EXPECT_EQ(f, 2.4f);
+    auto res = bw.result();
+    ASSERT_EQ(res.size(), 2u);
+    float f;
+    memcpy(&f, res.data() + 1, 4);
+    EXPECT_EQ(f, 2.4f);
 }
 
 TEST_F(BinaryWriterTest, Int) {
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_annot(spv::Op::OpKill, {Operand::Int(2)});
-  BinaryWriter bw;
-  bw.WriteBuilder(&b);
+    b.push_annot(spv::Op::OpKill, {Operand(2u)});
+    BinaryWriter bw;
+    bw.WriteBuilder(&b);
 
-  auto res = bw.result();
-  ASSERT_EQ(res.size(), 2u);
-  EXPECT_EQ(res[1], 2u);
+    auto res = bw.result();
+    ASSERT_EQ(res.size(), 2u);
+    EXPECT_EQ(res[1], 2u);
 }
 
 TEST_F(BinaryWriterTest, String) {
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_annot(spv::Op::OpKill, {Operand::String("my_string")});
-  BinaryWriter bw;
-  bw.WriteBuilder(&b);
+    b.push_annot(spv::Op::OpKill, {Operand("my_string")});
+    BinaryWriter bw;
+    bw.WriteBuilder(&b);
 
-  auto res = bw.result();
-  ASSERT_EQ(res.size(), 4u);
+    auto res = bw.result();
+    ASSERT_EQ(res.size(), 4u);
 
-  uint8_t* v = reinterpret_cast<uint8_t*>(res.data() + 1);
-  EXPECT_EQ(v[0], 'm');
-  EXPECT_EQ(v[1], 'y');
-  EXPECT_EQ(v[2], '_');
-  EXPECT_EQ(v[3], 's');
-  EXPECT_EQ(v[4], 't');
-  EXPECT_EQ(v[5], 'r');
-  EXPECT_EQ(v[6], 'i');
-  EXPECT_EQ(v[7], 'n');
-  EXPECT_EQ(v[8], 'g');
-  EXPECT_EQ(v[9], '\0');
-  EXPECT_EQ(v[10], '\0');
-  EXPECT_EQ(v[11], '\0');
+    uint8_t* v = reinterpret_cast<uint8_t*>(res.data() + 1);
+    EXPECT_EQ(v[0], 'm');
+    EXPECT_EQ(v[1], 'y');
+    EXPECT_EQ(v[2], '_');
+    EXPECT_EQ(v[3], 's');
+    EXPECT_EQ(v[4], 't');
+    EXPECT_EQ(v[5], 'r');
+    EXPECT_EQ(v[6], 'i');
+    EXPECT_EQ(v[7], 'n');
+    EXPECT_EQ(v[8], 'g');
+    EXPECT_EQ(v[9], '\0');
+    EXPECT_EQ(v[10], '\0');
+    EXPECT_EQ(v[11], '\0');
 }
 
 TEST_F(BinaryWriterTest, String_Multiple4Length) {
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_annot(spv::Op::OpKill, {Operand::String("mystring")});
-  BinaryWriter bw;
-  bw.WriteBuilder(&b);
+    b.push_annot(spv::Op::OpKill, {Operand("mystring")});
+    BinaryWriter bw;
+    bw.WriteBuilder(&b);
 
-  auto res = bw.result();
-  ASSERT_EQ(res.size(), 4u);
+    auto res = bw.result();
+    ASSERT_EQ(res.size(), 4u);
 
-  uint8_t* v = reinterpret_cast<uint8_t*>(res.data() + 1);
-  EXPECT_EQ(v[0], 'm');
-  EXPECT_EQ(v[1], 'y');
-  EXPECT_EQ(v[2], 's');
-  EXPECT_EQ(v[3], 't');
-  EXPECT_EQ(v[4], 'r');
-  EXPECT_EQ(v[5], 'i');
-  EXPECT_EQ(v[6], 'n');
-  EXPECT_EQ(v[7], 'g');
-  EXPECT_EQ(v[8], '\0');
-  EXPECT_EQ(v[9], '\0');
-  EXPECT_EQ(v[10], '\0');
-  EXPECT_EQ(v[11], '\0');
+    uint8_t* v = reinterpret_cast<uint8_t*>(res.data() + 1);
+    EXPECT_EQ(v[0], 'm');
+    EXPECT_EQ(v[1], 'y');
+    EXPECT_EQ(v[2], 's');
+    EXPECT_EQ(v[3], 't');
+    EXPECT_EQ(v[4], 'r');
+    EXPECT_EQ(v[5], 'i');
+    EXPECT_EQ(v[6], 'n');
+    EXPECT_EQ(v[7], 'g');
+    EXPECT_EQ(v[8], '\0');
+    EXPECT_EQ(v[9], '\0');
+    EXPECT_EQ(v[10], '\0');
+    EXPECT_EQ(v[11], '\0');
 }
 
 TEST_F(BinaryWriterTest, TestInstructionWriter) {
-  Instruction i1{spv::Op::OpKill, {Operand::Int(2)}};
-  Instruction i2{spv::Op::OpKill, {Operand::Int(4)}};
+    Instruction i1{spv::Op::OpKill, {Operand(2u)}};
+    Instruction i2{spv::Op::OpKill, {Operand(4u)}};
 
-  BinaryWriter bw;
-  bw.WriteInstruction(i1);
-  bw.WriteInstruction(i2);
+    BinaryWriter bw;
+    bw.WriteInstruction(i1);
+    bw.WriteInstruction(i2);
 
-  auto res = bw.result();
-  ASSERT_EQ(res.size(), 4u);
-  EXPECT_EQ(res[1], 2u);
-  EXPECT_EQ(res[3], 4u);
+    auto res = bw.result();
+    ASSERT_EQ(res.size(), 4u);
+    EXPECT_EQ(res[1], 2u);
+    EXPECT_EQ(res[3], 4u);
 }
 
 }  // namespace
diff --git a/src/tint/writer/spirv/builder.cc b/src/tint/writer/spirv/builder.cc
index c033344..72a0962 100644
--- a/src/tint/writer/spirv/builder.cc
+++ b/src/tint/writer/spirv/builder.cc
@@ -24,23 +24,23 @@
 #include "src/tint/ast/internal_attribute.h"
 #include "src/tint/ast/traverse_expressions.h"
 #include "src/tint/sem/array.h"
-#include "src/tint/sem/atomic_type.h"
+#include "src/tint/sem/atomic.h"
 #include "src/tint/sem/builtin.h"
 #include "src/tint/sem/call.h"
-#include "src/tint/sem/depth_multisampled_texture_type.h"
-#include "src/tint/sem/depth_texture_type.h"
+#include "src/tint/sem/depth_multisampled_texture.h"
+#include "src/tint/sem/depth_texture.h"
 #include "src/tint/sem/function.h"
 #include "src/tint/sem/member_accessor_expression.h"
 #include "src/tint/sem/module.h"
-#include "src/tint/sem/multisampled_texture_type.h"
-#include "src/tint/sem/reference_type.h"
-#include "src/tint/sem/sampled_texture_type.h"
+#include "src/tint/sem/multisampled_texture.h"
+#include "src/tint/sem/reference.h"
+#include "src/tint/sem/sampled_texture.h"
 #include "src/tint/sem/statement.h"
 #include "src/tint/sem/struct.h"
 #include "src/tint/sem/type_constructor.h"
 #include "src/tint/sem/type_conversion.h"
 #include "src/tint/sem/variable.h"
-#include "src/tint/sem/vector_type.h"
+#include "src/tint/sem/vector.h"
 #include "src/tint/transform/add_spirv_block_attribute.h"
 #include "src/tint/utils/defer.h"
 #include "src/tint/utils/map.h"
@@ -54,35 +54,35 @@
 const char kGLSLstd450[] = "GLSL.std.450";
 
 uint32_t size_of(const InstructionList& instructions) {
-  uint32_t size = 0;
-  for (const auto& inst : instructions)
-    size += inst.word_length();
+    uint32_t size = 0;
+    for (const auto& inst : instructions)
+        size += inst.word_length();
 
-  return size;
+    return size;
 }
 
 uint32_t pipeline_stage_to_execution_model(ast::PipelineStage stage) {
-  SpvExecutionModel model = SpvExecutionModelVertex;
+    SpvExecutionModel model = SpvExecutionModelVertex;
 
-  switch (stage) {
-    case ast::PipelineStage::kFragment:
-      model = SpvExecutionModelFragment;
-      break;
-    case ast::PipelineStage::kVertex:
-      model = SpvExecutionModelVertex;
-      break;
-    case ast::PipelineStage::kCompute:
-      model = SpvExecutionModelGLCompute;
-      break;
-    case ast::PipelineStage::kNone:
-      model = SpvExecutionModelMax;
-      break;
-  }
-  return model;
+    switch (stage) {
+        case ast::PipelineStage::kFragment:
+            model = SpvExecutionModelFragment;
+            break;
+        case ast::PipelineStage::kVertex:
+            model = SpvExecutionModelVertex;
+            break;
+        case ast::PipelineStage::kCompute:
+            model = SpvExecutionModelGLCompute;
+            break;
+        case ast::PipelineStage::kNone:
+            model = SpvExecutionModelMax;
+            break;
+    }
+    return model;
 }
 
 bool LastIsFallthrough(const ast::BlockStatement* stmts) {
-  return !stmts->Empty() && stmts->Last()->Is<ast::FallthroughStatement>();
+    return !stmts->Empty() && stmts->Last()->Is<ast::FallthroughStatement>();
 }
 
 /// Returns the matrix type that is `type` or that is wrapped by
@@ -90,151 +90,151 @@
 /// @param type the given type, which must not be null
 /// @returns the nested matrix type, or nullptr if none
 const sem::Matrix* GetNestedMatrixType(const sem::Type* type) {
-  while (auto* arr = type->As<sem::Array>()) {
-    type = arr->ElemType();
-  }
-  return type->As<sem::Matrix>();
+    while (auto* arr = type->As<sem::Array>()) {
+        type = arr->ElemType();
+    }
+    return type->As<sem::Matrix>();
 }
 
 uint32_t builtin_to_glsl_method(const sem::Builtin* builtin) {
-  switch (builtin->Type()) {
-    case BuiltinType::kAcos:
-      return GLSLstd450Acos;
-    case BuiltinType::kAsin:
-      return GLSLstd450Asin;
-    case BuiltinType::kAtan:
-      return GLSLstd450Atan;
-    case BuiltinType::kAtan2:
-      return GLSLstd450Atan2;
-    case BuiltinType::kCeil:
-      return GLSLstd450Ceil;
-    case BuiltinType::kClamp:
-      if (builtin->ReturnType()->is_float_scalar_or_vector()) {
-        return GLSLstd450NClamp;
-      } else if (builtin->ReturnType()->is_unsigned_scalar_or_vector()) {
-        return GLSLstd450UClamp;
-      } else {
-        return GLSLstd450SClamp;
-      }
-    case BuiltinType::kCos:
-      return GLSLstd450Cos;
-    case BuiltinType::kCosh:
-      return GLSLstd450Cosh;
-    case BuiltinType::kCross:
-      return GLSLstd450Cross;
-    case BuiltinType::kDegrees:
-      return GLSLstd450Degrees;
-    case BuiltinType::kDeterminant:
-      return GLSLstd450Determinant;
-    case BuiltinType::kDistance:
-      return GLSLstd450Distance;
-    case BuiltinType::kExp:
-      return GLSLstd450Exp;
-    case BuiltinType::kExp2:
-      return GLSLstd450Exp2;
-    case BuiltinType::kFaceForward:
-      return GLSLstd450FaceForward;
-    case BuiltinType::kFloor:
-      return GLSLstd450Floor;
-    case BuiltinType::kFma:
-      return GLSLstd450Fma;
-    case BuiltinType::kFract:
-      return GLSLstd450Fract;
-    case BuiltinType::kFrexp:
-      return GLSLstd450FrexpStruct;
-    case BuiltinType::kInverseSqrt:
-      return GLSLstd450InverseSqrt;
-    case BuiltinType::kLdexp:
-      return GLSLstd450Ldexp;
-    case BuiltinType::kLength:
-      return GLSLstd450Length;
-    case BuiltinType::kLog:
-      return GLSLstd450Log;
-    case BuiltinType::kLog2:
-      return GLSLstd450Log2;
-    case BuiltinType::kMax:
-      if (builtin->ReturnType()->is_float_scalar_or_vector()) {
-        return GLSLstd450NMax;
-      } else if (builtin->ReturnType()->is_unsigned_scalar_or_vector()) {
-        return GLSLstd450UMax;
-      } else {
-        return GLSLstd450SMax;
-      }
-    case BuiltinType::kMin:
-      if (builtin->ReturnType()->is_float_scalar_or_vector()) {
-        return GLSLstd450NMin;
-      } else if (builtin->ReturnType()->is_unsigned_scalar_or_vector()) {
-        return GLSLstd450UMin;
-      } else {
-        return GLSLstd450SMin;
-      }
-    case BuiltinType::kMix:
-      return GLSLstd450FMix;
-    case BuiltinType::kModf:
-      return GLSLstd450ModfStruct;
-    case BuiltinType::kNormalize:
-      return GLSLstd450Normalize;
-    case BuiltinType::kPack4x8snorm:
-      return GLSLstd450PackSnorm4x8;
-    case BuiltinType::kPack4x8unorm:
-      return GLSLstd450PackUnorm4x8;
-    case BuiltinType::kPack2x16snorm:
-      return GLSLstd450PackSnorm2x16;
-    case BuiltinType::kPack2x16unorm:
-      return GLSLstd450PackUnorm2x16;
-    case BuiltinType::kPack2x16float:
-      return GLSLstd450PackHalf2x16;
-    case BuiltinType::kPow:
-      return GLSLstd450Pow;
-    case BuiltinType::kRadians:
-      return GLSLstd450Radians;
-    case BuiltinType::kReflect:
-      return GLSLstd450Reflect;
-    case BuiltinType::kRefract:
-      return GLSLstd450Refract;
-    case BuiltinType::kRound:
-      return GLSLstd450RoundEven;
-    case BuiltinType::kSign:
-      return GLSLstd450FSign;
-    case BuiltinType::kSin:
-      return GLSLstd450Sin;
-    case BuiltinType::kSinh:
-      return GLSLstd450Sinh;
-    case BuiltinType::kSmoothstep:
-    case BuiltinType::kSmoothStep:
-      return GLSLstd450SmoothStep;
-    case BuiltinType::kSqrt:
-      return GLSLstd450Sqrt;
-    case BuiltinType::kStep:
-      return GLSLstd450Step;
-    case BuiltinType::kTan:
-      return GLSLstd450Tan;
-    case BuiltinType::kTanh:
-      return GLSLstd450Tanh;
-    case BuiltinType::kTrunc:
-      return GLSLstd450Trunc;
-    case BuiltinType::kUnpack4x8snorm:
-      return GLSLstd450UnpackSnorm4x8;
-    case BuiltinType::kUnpack4x8unorm:
-      return GLSLstd450UnpackUnorm4x8;
-    case BuiltinType::kUnpack2x16snorm:
-      return GLSLstd450UnpackSnorm2x16;
-    case BuiltinType::kUnpack2x16unorm:
-      return GLSLstd450UnpackUnorm2x16;
-    case BuiltinType::kUnpack2x16float:
-      return GLSLstd450UnpackHalf2x16;
-    default:
-      break;
-  }
-  return 0;
+    switch (builtin->Type()) {
+        case BuiltinType::kAcos:
+            return GLSLstd450Acos;
+        case BuiltinType::kAsin:
+            return GLSLstd450Asin;
+        case BuiltinType::kAtan:
+            return GLSLstd450Atan;
+        case BuiltinType::kAtan2:
+            return GLSLstd450Atan2;
+        case BuiltinType::kCeil:
+            return GLSLstd450Ceil;
+        case BuiltinType::kClamp:
+            if (builtin->ReturnType()->is_float_scalar_or_vector()) {
+                return GLSLstd450NClamp;
+            } else if (builtin->ReturnType()->is_unsigned_scalar_or_vector()) {
+                return GLSLstd450UClamp;
+            } else {
+                return GLSLstd450SClamp;
+            }
+        case BuiltinType::kCos:
+            return GLSLstd450Cos;
+        case BuiltinType::kCosh:
+            return GLSLstd450Cosh;
+        case BuiltinType::kCross:
+            return GLSLstd450Cross;
+        case BuiltinType::kDegrees:
+            return GLSLstd450Degrees;
+        case BuiltinType::kDeterminant:
+            return GLSLstd450Determinant;
+        case BuiltinType::kDistance:
+            return GLSLstd450Distance;
+        case BuiltinType::kExp:
+            return GLSLstd450Exp;
+        case BuiltinType::kExp2:
+            return GLSLstd450Exp2;
+        case BuiltinType::kFaceForward:
+            return GLSLstd450FaceForward;
+        case BuiltinType::kFloor:
+            return GLSLstd450Floor;
+        case BuiltinType::kFma:
+            return GLSLstd450Fma;
+        case BuiltinType::kFract:
+            return GLSLstd450Fract;
+        case BuiltinType::kFrexp:
+            return GLSLstd450FrexpStruct;
+        case BuiltinType::kInverseSqrt:
+            return GLSLstd450InverseSqrt;
+        case BuiltinType::kLdexp:
+            return GLSLstd450Ldexp;
+        case BuiltinType::kLength:
+            return GLSLstd450Length;
+        case BuiltinType::kLog:
+            return GLSLstd450Log;
+        case BuiltinType::kLog2:
+            return GLSLstd450Log2;
+        case BuiltinType::kMax:
+            if (builtin->ReturnType()->is_float_scalar_or_vector()) {
+                return GLSLstd450NMax;
+            } else if (builtin->ReturnType()->is_unsigned_scalar_or_vector()) {
+                return GLSLstd450UMax;
+            } else {
+                return GLSLstd450SMax;
+            }
+        case BuiltinType::kMin:
+            if (builtin->ReturnType()->is_float_scalar_or_vector()) {
+                return GLSLstd450NMin;
+            } else if (builtin->ReturnType()->is_unsigned_scalar_or_vector()) {
+                return GLSLstd450UMin;
+            } else {
+                return GLSLstd450SMin;
+            }
+        case BuiltinType::kMix:
+            return GLSLstd450FMix;
+        case BuiltinType::kModf:
+            return GLSLstd450ModfStruct;
+        case BuiltinType::kNormalize:
+            return GLSLstd450Normalize;
+        case BuiltinType::kPack4x8snorm:
+            return GLSLstd450PackSnorm4x8;
+        case BuiltinType::kPack4x8unorm:
+            return GLSLstd450PackUnorm4x8;
+        case BuiltinType::kPack2x16snorm:
+            return GLSLstd450PackSnorm2x16;
+        case BuiltinType::kPack2x16unorm:
+            return GLSLstd450PackUnorm2x16;
+        case BuiltinType::kPack2x16float:
+            return GLSLstd450PackHalf2x16;
+        case BuiltinType::kPow:
+            return GLSLstd450Pow;
+        case BuiltinType::kRadians:
+            return GLSLstd450Radians;
+        case BuiltinType::kReflect:
+            return GLSLstd450Reflect;
+        case BuiltinType::kRefract:
+            return GLSLstd450Refract;
+        case BuiltinType::kRound:
+            return GLSLstd450RoundEven;
+        case BuiltinType::kSign:
+            return GLSLstd450FSign;
+        case BuiltinType::kSin:
+            return GLSLstd450Sin;
+        case BuiltinType::kSinh:
+            return GLSLstd450Sinh;
+        case BuiltinType::kSmoothstep:
+        case BuiltinType::kSmoothStep:
+            return GLSLstd450SmoothStep;
+        case BuiltinType::kSqrt:
+            return GLSLstd450Sqrt;
+        case BuiltinType::kStep:
+            return GLSLstd450Step;
+        case BuiltinType::kTan:
+            return GLSLstd450Tan;
+        case BuiltinType::kTanh:
+            return GLSLstd450Tanh;
+        case BuiltinType::kTrunc:
+            return GLSLstd450Trunc;
+        case BuiltinType::kUnpack4x8snorm:
+            return GLSLstd450UnpackSnorm4x8;
+        case BuiltinType::kUnpack4x8unorm:
+            return GLSLstd450UnpackUnorm4x8;
+        case BuiltinType::kUnpack2x16snorm:
+            return GLSLstd450UnpackSnorm2x16;
+        case BuiltinType::kUnpack2x16unorm:
+            return GLSLstd450UnpackUnorm2x16;
+        case BuiltinType::kUnpack2x16float:
+            return GLSLstd450UnpackHalf2x16;
+        default:
+            break;
+    }
+    return 0;
 }
 
 /// @return the vector element type if ty is a vector, otherwise return ty.
 const sem::Type* ElementTypeOf(const sem::Type* ty) {
-  if (auto* v = ty->As<sem::Vector>()) {
-    return v->type();
-  }
-  return ty;
+    if (auto* v = ty->As<sem::Vector>()) {
+        return v->type();
+    }
+    return ty;
 }
 
 }  // namespace
@@ -245,2939 +245,2832 @@
 
 Builder::Builder(const Program* program, bool zero_initialize_workgroup_memory)
     : builder_(ProgramBuilder::Wrap(program)),
-      scope_stack_({}),
+      scope_stack_{Scope{}},
       zero_initialize_workgroup_memory_(zero_initialize_workgroup_memory) {}
 
 Builder::~Builder() = default;
 
 bool Builder::Build() {
-  push_capability(SpvCapabilityShader);
+    push_capability(SpvCapabilityShader);
 
-  push_memory_model(spv::Op::OpMemoryModel,
-                    {Operand::Int(SpvAddressingModelLogical),
-                     Operand::Int(SpvMemoryModelGLSL450)});
+    push_memory_model(spv::Op::OpMemoryModel,
+                      {U32Operand(SpvAddressingModelLogical), U32Operand(SpvMemoryModelGLSL450)});
 
-  for (auto* var : builder_.AST().GlobalVariables()) {
-    if (!GenerateGlobalVariable(var)) {
-      return false;
+    for (auto ext : builder_.AST().Extensions()) {
+        GenerateExtension(ext);
     }
-  }
 
-  auto* mod = builder_.Sem().Module();
-  for (auto* decl : mod->DependencyOrderedDeclarations()) {
-    if (auto* func = decl->As<ast::Function>()) {
-      if (!GenerateFunction(func)) {
-        return false;
-      }
+    for (auto* var : builder_.AST().GlobalVariables()) {
+        if (!GenerateGlobalVariable(var)) {
+            return false;
+        }
     }
-  }
 
-  return true;
+    auto* mod = builder_.Sem().Module();
+    for (auto* decl : mod->DependencyOrderedDeclarations()) {
+        if (auto* func = decl->As<ast::Function>()) {
+            if (!GenerateFunction(func)) {
+                return false;
+            }
+        }
+    }
+
+    return true;
+}
+
+void Builder::RegisterVariable(const sem::Variable* var, uint32_t id) {
+    var_to_id_.emplace(var, id);
+    id_to_var_.emplace(id, var);
+}
+
+uint32_t Builder::LookupVariableID(const sem::Variable* var) {
+    auto it = var_to_id_.find(var);
+    if (it == var_to_id_.end()) {
+        error_ = "unable to find ID for variable: " +
+                 builder_.Symbols().NameFor(var->Declaration()->symbol);
+        return 0;
+    }
+    return it->second;
+}
+
+void Builder::PushScope() {
+    // Push a new scope, by copying the top-most stack
+    scope_stack_.push_back(scope_stack_.back());
+}
+
+void Builder::PopScope() {
+    scope_stack_.pop_back();
 }
 
 Operand Builder::result_op() {
-  return Operand::Int(next_id());
+    return Operand(next_id());
 }
 
 uint32_t Builder::total_size() const {
-  // The 5 covers the magic, version, generator, id bound and reserved.
-  uint32_t size = 5;
+    // The 5 covers the magic, version, generator, id bound and reserved.
+    uint32_t size = 5;
 
-  size += size_of(capabilities_);
-  size += size_of(extensions_);
-  size += size_of(ext_imports_);
-  size += size_of(memory_model_);
-  size += size_of(entry_points_);
-  size += size_of(execution_modes_);
-  size += size_of(debug_);
-  size += size_of(annotations_);
-  size += size_of(types_);
-  for (const auto& func : functions_) {
-    size += func.word_length();
-  }
+    size += size_of(capabilities_);
+    size += size_of(extensions_);
+    size += size_of(ext_imports_);
+    size += size_of(memory_model_);
+    size += size_of(entry_points_);
+    size += size_of(execution_modes_);
+    size += size_of(debug_);
+    size += size_of(annotations_);
+    size += size_of(types_);
+    for (const auto& func : functions_) {
+        size += func.word_length();
+    }
 
-  return size;
+    return size;
 }
 
 void Builder::iterate(std::function<void(const Instruction&)> cb) const {
-  for (const auto& inst : capabilities_) {
-    cb(inst);
-  }
-  for (const auto& inst : extensions_) {
-    cb(inst);
-  }
-  for (const auto& inst : ext_imports_) {
-    cb(inst);
-  }
-  for (const auto& inst : memory_model_) {
-    cb(inst);
-  }
-  for (const auto& inst : entry_points_) {
-    cb(inst);
-  }
-  for (const auto& inst : execution_modes_) {
-    cb(inst);
-  }
-  for (const auto& inst : debug_) {
-    cb(inst);
-  }
-  for (const auto& inst : annotations_) {
-    cb(inst);
-  }
-  for (const auto& inst : types_) {
-    cb(inst);
-  }
-  for (const auto& func : functions_) {
-    func.iterate(cb);
-  }
+    for (const auto& inst : capabilities_) {
+        cb(inst);
+    }
+    for (const auto& inst : extensions_) {
+        cb(inst);
+    }
+    for (const auto& inst : ext_imports_) {
+        cb(inst);
+    }
+    for (const auto& inst : memory_model_) {
+        cb(inst);
+    }
+    for (const auto& inst : entry_points_) {
+        cb(inst);
+    }
+    for (const auto& inst : execution_modes_) {
+        cb(inst);
+    }
+    for (const auto& inst : debug_) {
+        cb(inst);
+    }
+    for (const auto& inst : annotations_) {
+        cb(inst);
+    }
+    for (const auto& inst : types_) {
+        cb(inst);
+    }
+    for (const auto& func : functions_) {
+        func.iterate(cb);
+    }
 }
 
 void Builder::push_capability(uint32_t cap) {
-  if (capability_set_.count(cap) == 0) {
-    capability_set_.insert(cap);
-    capabilities_.push_back(
-        Instruction{spv::Op::OpCapability, {Operand::Int(cap)}});
-  }
+    if (capability_set_.count(cap) == 0) {
+        capability_set_.insert(cap);
+        capabilities_.push_back(Instruction{spv::Op::OpCapability, {Operand(cap)}});
+    }
+}
+
+bool Builder::GenerateExtension(ast::Enable::ExtensionKind) {
+    /*
+    For each supported extension, push corresponding capability into the builder.
+    For example:
+      if (kind == ast::Extension::Kind::kF16) {
+        push_capability(SpvCapabilityFloat16);
+        push_capability(SpvCapabilityUniformAndStorageBuffer16BitAccess);
+        push_capability(SpvCapabilityStorageBuffer16BitAccess);
+        push_capability(SpvCapabilityStorageInputOutput16);
+      }
+    */
+
+    return true;
 }
 
 bool Builder::GenerateLabel(uint32_t id) {
-  if (!push_function_inst(spv::Op::OpLabel, {Operand::Int(id)})) {
-    return false;
-  }
-  current_label_id_ = id;
-  return true;
+    if (!push_function_inst(spv::Op::OpLabel, {Operand(id)})) {
+        return false;
+    }
+    current_label_id_ = id;
+    return true;
 }
 
 bool Builder::GenerateAssignStatement(const ast::AssignmentStatement* assign) {
-  if (assign->lhs->Is<ast::PhonyExpression>()) {
-    auto rhs_id = GenerateExpression(assign->rhs);
-    if (rhs_id == 0) {
-      return false;
+    if (assign->lhs->Is<ast::PhonyExpression>()) {
+        auto rhs_id = GenerateExpression(assign->rhs);
+        if (rhs_id == 0) {
+            return false;
+        }
+        return true;
+    } else {
+        auto lhs_id = GenerateExpression(assign->lhs);
+        if (lhs_id == 0) {
+            return false;
+        }
+        auto rhs_id = GenerateExpressionWithLoadIfNeeded(assign->rhs);
+        if (rhs_id == 0) {
+            return false;
+        }
+        return GenerateStore(lhs_id, rhs_id);
     }
-    return true;
-  } else {
-    auto lhs_id = GenerateExpression(assign->lhs);
-    if (lhs_id == 0) {
-      return false;
-    }
-    auto rhs_id = GenerateExpressionWithLoadIfNeeded(assign->rhs);
-    if (rhs_id == 0) {
-      return false;
-    }
-    return GenerateStore(lhs_id, rhs_id);
-  }
 }
 
 bool Builder::GenerateBreakStatement(const ast::BreakStatement*) {
-  if (merge_stack_.empty()) {
-    error_ = "Attempted to break without a merge block";
-    return false;
-  }
-  if (!push_function_inst(spv::Op::OpBranch,
-                          {Operand::Int(merge_stack_.back())})) {
-    return false;
-  }
-  return true;
+    if (merge_stack_.empty()) {
+        error_ = "Attempted to break without a merge block";
+        return false;
+    }
+    if (!push_function_inst(spv::Op::OpBranch, {Operand(merge_stack_.back())})) {
+        return false;
+    }
+    return true;
 }
 
 bool Builder::GenerateContinueStatement(const ast::ContinueStatement*) {
-  if (continue_stack_.empty()) {
-    error_ = "Attempted to continue without a continue block";
-    return false;
-  }
-  if (!push_function_inst(spv::Op::OpBranch,
-                          {Operand::Int(continue_stack_.back())})) {
-    return false;
-  }
-  return true;
+    if (continue_stack_.empty()) {
+        error_ = "Attempted to continue without a continue block";
+        return false;
+    }
+    if (!push_function_inst(spv::Op::OpBranch, {Operand(continue_stack_.back())})) {
+        return false;
+    }
+    return true;
 }
 
 // TODO(dsinclair): This is generating an OpKill but the semantics of kill
 // haven't been defined for WGSL yet. So, this may need to change.
 // https://github.com/gpuweb/gpuweb/issues/676
 bool Builder::GenerateDiscardStatement(const ast::DiscardStatement*) {
-  if (!push_function_inst(spv::Op::OpKill, {})) {
-    return false;
-  }
-  return true;
+    if (!push_function_inst(spv::Op::OpKill, {})) {
+        return false;
+    }
+    return true;
 }
 
 bool Builder::GenerateEntryPoint(const ast::Function* func, uint32_t id) {
-  auto stage = pipeline_stage_to_execution_model(func->PipelineStage());
-  if (stage == SpvExecutionModelMax) {
-    error_ = "Unknown pipeline stage provided";
-    return false;
-  }
-
-  OperandList operands = {
-      Operand::Int(stage), Operand::Int(id),
-      Operand::String(builder_.Symbols().NameFor(func->symbol))};
-
-  auto* func_sem = builder_.Sem().Get(func);
-  for (const auto* var : func_sem->TransitivelyReferencedGlobals()) {
-    // For SPIR-V 1.3 we only output Input/output variables. If we update to
-    // SPIR-V 1.4 or later this should be all variables.
-    if (var->StorageClass() != ast::StorageClass::kInput &&
-        var->StorageClass() != ast::StorageClass::kOutput) {
-      continue;
+    auto stage = pipeline_stage_to_execution_model(func->PipelineStage());
+    if (stage == SpvExecutionModelMax) {
+        error_ = "Unknown pipeline stage provided";
+        return false;
     }
 
-    uint32_t var_id = scope_stack_.Get(var->Declaration()->symbol);
-    if (var_id == 0) {
-      error_ = "unable to find ID for global variable: " +
-               builder_.Symbols().NameFor(var->Declaration()->symbol);
-      return false;
+    OperandList operands = {Operand(stage), Operand(id),
+                            Operand(builder_.Symbols().NameFor(func->symbol))};
+
+    auto* func_sem = builder_.Sem().Get(func);
+    for (const auto* var : func_sem->TransitivelyReferencedGlobals()) {
+        // For SPIR-V 1.3 we only output Input/output variables. If we update to
+        // SPIR-V 1.4 or later this should be all variables.
+        if (var->StorageClass() != ast::StorageClass::kInput &&
+            var->StorageClass() != ast::StorageClass::kOutput) {
+            continue;
+        }
+
+        uint32_t var_id = LookupVariableID(var);
+        if (var_id == 0) {
+            error_ = "unable to find ID for global variable: " +
+                     builder_.Symbols().NameFor(var->Declaration()->symbol);
+            return false;
+        }
+
+        operands.push_back(Operand(var_id));
     }
+    push_entry_point(spv::Op::OpEntryPoint, operands);
 
-    operands.push_back(Operand::Int(var_id));
-  }
-  push_entry_point(spv::Op::OpEntryPoint, operands);
-
-  return true;
+    return true;
 }
 
 bool Builder::GenerateExecutionModes(const ast::Function* func, uint32_t id) {
-  auto* func_sem = builder_.Sem().Get(func);
+    auto* func_sem = builder_.Sem().Get(func);
 
-  // WGSL fragment shader origin is upper left
-  if (func->PipelineStage() == ast::PipelineStage::kFragment) {
-    push_execution_mode(
-        spv::Op::OpExecutionMode,
-        {Operand::Int(id), Operand::Int(SpvExecutionModeOriginUpperLeft)});
-  } else if (func->PipelineStage() == ast::PipelineStage::kCompute) {
-    auto& wgsize = func_sem->WorkgroupSize();
+    // WGSL fragment shader origin is upper left
+    if (func->PipelineStage() == ast::PipelineStage::kFragment) {
+        push_execution_mode(spv::Op::OpExecutionMode,
+                            {Operand(id), U32Operand(SpvExecutionModeOriginUpperLeft)});
+    } else if (func->PipelineStage() == ast::PipelineStage::kCompute) {
+        auto& wgsize = func_sem->WorkgroupSize();
 
-    // Check if the workgroup_size uses pipeline-overridable constants.
-    if (wgsize[0].overridable_const || wgsize[1].overridable_const ||
-        wgsize[2].overridable_const) {
-      if (has_overridable_workgroup_size_) {
-        // Only one stage can have a pipeline-overridable workgroup size.
-        // TODO(crbug.com/tint/810): Use LocalSizeId to handle this scenario.
-        TINT_ICE(Writer, builder_.Diagnostics())
-            << "multiple stages using pipeline-overridable workgroup sizes";
-      }
-      has_overridable_workgroup_size_ = true;
+        // Check if the workgroup_size uses pipeline-overridable constants.
+        if (wgsize[0].overridable_const || wgsize[1].overridable_const ||
+            wgsize[2].overridable_const) {
+            if (has_overridable_workgroup_size_) {
+                // Only one stage can have a pipeline-overridable workgroup size.
+                // TODO(crbug.com/tint/810): Use LocalSizeId to handle this scenario.
+                TINT_ICE(Writer, builder_.Diagnostics())
+                    << "multiple stages using pipeline-overridable workgroup sizes";
+            }
+            has_overridable_workgroup_size_ = true;
 
-      auto* vec3_u32 =
-          builder_.create<sem::Vector>(builder_.create<sem::U32>(), 3u);
-      uint32_t vec3_u32_type_id = GenerateTypeIfNeeded(vec3_u32);
-      if (vec3_u32_type_id == 0) {
-        return 0;
-      }
+            auto* vec3_u32 = builder_.create<sem::Vector>(builder_.create<sem::U32>(), 3u);
+            uint32_t vec3_u32_type_id = GenerateTypeIfNeeded(vec3_u32);
+            if (vec3_u32_type_id == 0) {
+                return 0;
+            }
 
-      OperandList wgsize_ops;
-      auto wgsize_result = result_op();
-      wgsize_ops.push_back(Operand::Int(vec3_u32_type_id));
-      wgsize_ops.push_back(wgsize_result);
+            OperandList wgsize_ops;
+            auto wgsize_result = result_op();
+            wgsize_ops.push_back(Operand(vec3_u32_type_id));
+            wgsize_ops.push_back(wgsize_result);
 
-      // Generate OpConstant instructions for each dimension.
-      for (int i = 0; i < 3; i++) {
-        auto constant = ScalarConstant::U32(wgsize[i].value);
-        if (wgsize[i].overridable_const) {
-          // Make the constant specializable.
-          auto* sem_const = builder_.Sem().Get<sem::GlobalVariable>(
-              wgsize[i].overridable_const);
-          if (!sem_const->IsOverridable()) {
-            TINT_ICE(Writer, builder_.Diagnostics())
-                << "expected a pipeline-overridable constant";
-          }
-          constant.is_spec_op = true;
-          constant.constant_id = sem_const->ConstantId();
+            // Generate OpConstant instructions for each dimension.
+            for (int i = 0; i < 3; i++) {
+                auto constant = ScalarConstant::U32(wgsize[i].value);
+                if (wgsize[i].overridable_const) {
+                    // Make the constant specializable.
+                    auto* sem_const =
+                        builder_.Sem().Get<sem::GlobalVariable>(wgsize[i].overridable_const);
+                    if (!sem_const->IsOverridable()) {
+                        TINT_ICE(Writer, builder_.Diagnostics())
+                            << "expected a pipeline-overridable constant";
+                    }
+                    constant.is_spec_op = true;
+                    constant.constant_id = sem_const->ConstantId();
+                }
+
+                auto result = GenerateConstantIfNeeded(constant);
+                wgsize_ops.push_back(Operand(result));
+            }
+
+            // Generate the WorkgroupSize builtin.
+            push_type(spv::Op::OpSpecConstantComposite, wgsize_ops);
+            push_annot(spv::Op::OpDecorate, {wgsize_result, U32Operand(SpvDecorationBuiltIn),
+                                             U32Operand(SpvBuiltInWorkgroupSize)});
+        } else {
+            // Not overridable, so just use OpExecutionMode LocalSize.
+            uint32_t x = wgsize[0].value;
+            uint32_t y = wgsize[1].value;
+            uint32_t z = wgsize[2].value;
+            push_execution_mode(spv::Op::OpExecutionMode,
+                                {Operand(id), U32Operand(SpvExecutionModeLocalSize), Operand(x),
+                                 Operand(y), Operand(z)});
         }
-
-        auto result = GenerateConstantIfNeeded(constant);
-        wgsize_ops.push_back(Operand::Int(result));
-      }
-
-      // Generate the WorkgroupSize builtin.
-      push_type(spv::Op::OpSpecConstantComposite, wgsize_ops);
-      push_annot(spv::Op::OpDecorate,
-                 {wgsize_result, Operand::Int(SpvDecorationBuiltIn),
-                  Operand::Int(SpvBuiltInWorkgroupSize)});
-    } else {
-      // Not overridable, so just use OpExecutionMode LocalSize.
-      uint32_t x = wgsize[0].value;
-      uint32_t y = wgsize[1].value;
-      uint32_t z = wgsize[2].value;
-      push_execution_mode(
-          spv::Op::OpExecutionMode,
-          {Operand::Int(id), Operand::Int(SpvExecutionModeLocalSize),
-           Operand::Int(x), Operand::Int(y), Operand::Int(z)});
     }
-  }
 
-  for (auto builtin : func_sem->TransitivelyReferencedBuiltinVariables()) {
-    if (builtin.second->builtin == ast::Builtin::kFragDepth) {
-      push_execution_mode(
-          spv::Op::OpExecutionMode,
-          {Operand::Int(id), Operand::Int(SpvExecutionModeDepthReplacing)});
+    for (auto builtin : func_sem->TransitivelyReferencedBuiltinVariables()) {
+        if (builtin.second->builtin == ast::Builtin::kFragDepth) {
+            push_execution_mode(spv::Op::OpExecutionMode,
+                                {Operand(id), U32Operand(SpvExecutionModeDepthReplacing)});
+        }
     }
-  }
 
-  return true;
+    return true;
 }
 
 uint32_t Builder::GenerateExpression(const ast::Expression* expr) {
-  return Switch(
-      expr,
-      [&](const ast::IndexAccessorExpression* a) {
-        return GenerateAccessorExpression(a);
-      },
-      [&](const ast::BinaryExpression* b) {
-        return GenerateBinaryExpression(b);
-      },
-      [&](const ast::BitcastExpression* b) {
-        return GenerateBitcastExpression(b);
-      },
-      [&](const ast::CallExpression* c) { return GenerateCallExpression(c); },
-      [&](const ast::IdentifierExpression* i) {
-        return GenerateIdentifierExpression(i);
-      },
-      [&](const ast::LiteralExpression* l) {
-        return GenerateLiteralIfNeeded(nullptr, l);
-      },
-      [&](const ast::MemberAccessorExpression* m) {
-        return GenerateAccessorExpression(m);
-      },
-      [&](const ast::UnaryOpExpression* u) {
-        return GenerateUnaryOpExpression(u);
-      },
-      [&](Default) {
-        error_ =
-            "unknown expression type: " + std::string(expr->TypeInfo().name);
-        return 0;
-      });
+    return Switch(
+        expr, [&](const ast::IndexAccessorExpression* a) { return GenerateAccessorExpression(a); },
+        [&](const ast::BinaryExpression* b) { return GenerateBinaryExpression(b); },
+        [&](const ast::BitcastExpression* b) { return GenerateBitcastExpression(b); },
+        [&](const ast::CallExpression* c) { return GenerateCallExpression(c); },
+        [&](const ast::IdentifierExpression* i) { return GenerateIdentifierExpression(i); },
+        [&](const ast::LiteralExpression* l) { return GenerateLiteralIfNeeded(nullptr, l); },
+        [&](const ast::MemberAccessorExpression* m) { return GenerateAccessorExpression(m); },
+        [&](const ast::UnaryOpExpression* u) { return GenerateUnaryOpExpression(u); },
+        [&](Default) {
+            error_ = "unknown expression type: " + std::string(expr->TypeInfo().name);
+            return 0;
+        });
 }
 
 bool Builder::GenerateFunction(const ast::Function* func_ast) {
-  auto* func = builder_.Sem().Get(func_ast);
+    auto* func = builder_.Sem().Get(func_ast);
 
-  uint32_t func_type_id = GenerateFunctionTypeIfNeeded(func);
-  if (func_type_id == 0) {
-    return false;
-  }
-
-  auto func_op = result_op();
-  auto func_id = func_op.to_i();
-
-  push_debug(spv::Op::OpName,
-             {Operand::Int(func_id),
-              Operand::String(builder_.Symbols().NameFor(func_ast->symbol))});
-
-  auto ret_id = GenerateTypeIfNeeded(func->ReturnType());
-  if (ret_id == 0) {
-    return false;
-  }
-
-  scope_stack_.Push();
-  TINT_DEFER(scope_stack_.Pop());
-
-  auto definition_inst = Instruction{
-      spv::Op::OpFunction,
-      {Operand::Int(ret_id), func_op, Operand::Int(SpvFunctionControlMaskNone),
-       Operand::Int(func_type_id)}};
-
-  InstructionList params;
-  for (auto* param : func->Parameters()) {
-    auto param_op = result_op();
-    auto param_id = param_op.to_i();
-
-    auto param_type_id = GenerateTypeIfNeeded(param->Type());
-    if (param_type_id == 0) {
-      return false;
+    uint32_t func_type_id = GenerateFunctionTypeIfNeeded(func);
+    if (func_type_id == 0) {
+        return false;
     }
 
-    push_debug(spv::Op::OpName, {Operand::Int(param_id),
-                                 Operand::String(builder_.Symbols().NameFor(
-                                     param->Declaration()->symbol))});
-    params.push_back(Instruction{spv::Op::OpFunctionParameter,
-                                 {Operand::Int(param_type_id), param_op}});
+    auto func_op = result_op();
+    auto func_id = std::get<uint32_t>(func_op);
 
-    scope_stack_.Set(param->Declaration()->symbol, param_id);
-  }
+    push_debug(spv::Op::OpName,
+               {Operand(func_id), Operand(builder_.Symbols().NameFor(func_ast->symbol))});
 
-  push_function(Function{definition_inst, result_op(), std::move(params)});
-
-  for (auto* stmt : func_ast->body->statements) {
-    if (!GenerateStatement(stmt)) {
-      return false;
+    auto ret_id = GenerateTypeIfNeeded(func->ReturnType());
+    if (ret_id == 0) {
+        return false;
     }
-  }
 
-  if (InsideBasicBlock()) {
-    if (func->ReturnType()->Is<sem::Void>()) {
-      push_function_inst(spv::Op::OpReturn, {});
-    } else {
-      auto zero = GenerateConstantNullIfNeeded(func->ReturnType());
-      push_function_inst(spv::Op::OpReturnValue, {Operand::Int(zero)});
+    PushScope();
+    TINT_DEFER(PopScope());
+
+    auto definition_inst = Instruction{
+        spv::Op::OpFunction,
+        {Operand(ret_id), func_op, U32Operand(SpvFunctionControlMaskNone), Operand(func_type_id)}};
+
+    InstructionList params;
+    for (auto* param : func->Parameters()) {
+        auto param_op = result_op();
+        auto param_id = std::get<uint32_t>(param_op);
+
+        auto param_type_id = GenerateTypeIfNeeded(param->Type());
+        if (param_type_id == 0) {
+            return false;
+        }
+
+        push_debug(
+            spv::Op::OpName,
+            {Operand(param_id), Operand(builder_.Symbols().NameFor(param->Declaration()->symbol))});
+        params.push_back(
+            Instruction{spv::Op::OpFunctionParameter, {Operand(param_type_id), param_op}});
+
+        RegisterVariable(param, param_id);
     }
-  }
 
-  if (func_ast->IsEntryPoint()) {
-    if (!GenerateEntryPoint(func_ast, func_id)) {
-      return false;
+    push_function(Function{definition_inst, result_op(), std::move(params)});
+
+    for (auto* stmt : func_ast->body->statements) {
+        if (!GenerateStatement(stmt)) {
+            return false;
+        }
     }
-    if (!GenerateExecutionModes(func_ast, func_id)) {
-      return false;
+
+    if (InsideBasicBlock()) {
+        if (func->ReturnType()->Is<sem::Void>()) {
+            push_function_inst(spv::Op::OpReturn, {});
+        } else {
+            auto zero = GenerateConstantNullIfNeeded(func->ReturnType());
+            push_function_inst(spv::Op::OpReturnValue, {Operand(zero)});
+        }
     }
-  }
 
-  func_symbol_to_id_[func_ast->symbol] = func_id;
+    if (func_ast->IsEntryPoint()) {
+        if (!GenerateEntryPoint(func_ast, func_id)) {
+            return false;
+        }
+        if (!GenerateExecutionModes(func_ast, func_id)) {
+            return false;
+        }
+    }
 
-  return true;
+    func_symbol_to_id_[func_ast->symbol] = func_id;
+
+    return true;
 }
 
 uint32_t Builder::GenerateFunctionTypeIfNeeded(const sem::Function* func) {
-  return utils::GetOrCreate(
-      func_sig_to_id_, func->Signature(), [&]() -> uint32_t {
+    return utils::GetOrCreate(func_sig_to_id_, func->Signature(), [&]() -> uint32_t {
         auto func_op = result_op();
-        auto func_type_id = func_op.to_i();
+        auto func_type_id = std::get<uint32_t>(func_op);
 
         auto ret_id = GenerateTypeIfNeeded(func->ReturnType());
         if (ret_id == 0) {
-          return 0;
+            return 0;
         }
 
-        OperandList ops = {func_op, Operand::Int(ret_id)};
+        OperandList ops = {func_op, Operand(ret_id)};
         for (auto* param : func->Parameters()) {
-          auto param_type_id = GenerateTypeIfNeeded(param->Type());
-          if (param_type_id == 0) {
-            return 0;
-          }
-          ops.push_back(Operand::Int(param_type_id));
+            auto param_type_id = GenerateTypeIfNeeded(param->Type());
+            if (param_type_id == 0) {
+                return 0;
+            }
+            ops.push_back(Operand(param_type_id));
         }
 
         push_type(spv::Op::OpTypeFunction, std::move(ops));
         return func_type_id;
-      });
+    });
 }
 
 bool Builder::GenerateFunctionVariable(const ast::Variable* var) {
-  uint32_t init_id = 0;
-  if (var->constructor) {
-    init_id = GenerateExpressionWithLoadIfNeeded(var->constructor);
-    if (init_id == 0) {
-      return false;
+    uint32_t init_id = 0;
+    if (var->constructor) {
+        init_id = GenerateExpressionWithLoadIfNeeded(var->constructor);
+        if (init_id == 0) {
+            return false;
+        }
     }
-  }
 
-  if (var->is_const) {
-    if (!var->constructor) {
-      error_ = "missing constructor for constant";
-      return false;
+    auto* sem = builder_.Sem().Get(var);
+
+    if (var->is_const) {
+        if (!var->constructor) {
+            error_ = "missing constructor for constant";
+            return false;
+        }
+        RegisterVariable(sem, init_id);
+        return true;
     }
-    scope_stack_.Set(var->symbol, init_id);
-    spirv_id_to_variable_[init_id] = var;
+
+    auto result = result_op();
+    auto var_id = std::get<uint32_t>(result);
+    auto sc = ast::StorageClass::kFunction;
+    auto* type = sem->Type();
+    auto type_id = GenerateTypeIfNeeded(type);
+    if (type_id == 0) {
+        return false;
+    }
+
+    push_debug(spv::Op::OpName,
+               {Operand(var_id), Operand(builder_.Symbols().NameFor(var->symbol))});
+
+    // TODO(dsinclair) We could detect if the constructor is fully const and emit
+    // an initializer value for the variable instead of doing the OpLoad.
+    auto null_id = GenerateConstantNullIfNeeded(type->UnwrapRef());
+    if (null_id == 0) {
+        return 0;
+    }
+    push_function_var(
+        {Operand(type_id), result, U32Operand(ConvertStorageClass(sc)), Operand(null_id)});
+
+    if (var->constructor) {
+        if (!GenerateStore(var_id, init_id)) {
+            return false;
+        }
+    }
+
+    RegisterVariable(sem, var_id);
+
     return true;
-  }
-
-  auto result = result_op();
-  auto var_id = result.to_i();
-  auto sc = ast::StorageClass::kFunction;
-  auto* type = builder_.Sem().Get(var)->Type();
-  auto type_id = GenerateTypeIfNeeded(type);
-  if (type_id == 0) {
-    return false;
-  }
-
-  push_debug(spv::Op::OpName,
-             {Operand::Int(var_id),
-              Operand::String(builder_.Symbols().NameFor(var->symbol))});
-
-  // TODO(dsinclair) We could detect if the constructor is fully const and emit
-  // an initializer value for the variable instead of doing the OpLoad.
-  auto null_id = GenerateConstantNullIfNeeded(type->UnwrapRef());
-  if (null_id == 0) {
-    return 0;
-  }
-  push_function_var({Operand::Int(type_id), result,
-                     Operand::Int(ConvertStorageClass(sc)),
-                     Operand::Int(null_id)});
-
-  if (var->constructor) {
-    if (!GenerateStore(var_id, init_id)) {
-      return false;
-    }
-  }
-
-  scope_stack_.Set(var->symbol, var_id);
-  spirv_id_to_variable_[var_id] = var;
-
-  return true;
 }
 
 bool Builder::GenerateStore(uint32_t to, uint32_t from) {
-  return push_function_inst(spv::Op::OpStore,
-                            {Operand::Int(to), Operand::Int(from)});
+    return push_function_inst(spv::Op::OpStore, {Operand(to), Operand(from)});
 }
 
 bool Builder::GenerateGlobalVariable(const ast::Variable* var) {
-  auto* sem = builder_.Sem().Get(var);
-  auto* type = sem->Type()->UnwrapRef();
+    auto* sem = builder_.Sem().Get(var);
+    auto* type = sem->Type()->UnwrapRef();
 
-  uint32_t init_id = 0;
-  if (var->constructor) {
-    init_id = GenerateConstructorExpression(var, var->constructor);
-    if (init_id == 0) {
-      return false;
-    }
-  }
-
-  if (var->is_const) {
-    if (!var->constructor) {
-      // Constants must have an initializer unless they are overridable.
-      if (!var->is_overridable) {
-        error_ = "missing constructor for constant";
-        return false;
-      }
-
-      // SPIR-V requires specialization constants to have initializers.
-      if (type->Is<sem::F32>()) {
-        ast::FloatLiteralExpression l(ProgramID(), Source{}, 0.0f);
-        init_id = GenerateLiteralIfNeeded(var, &l);
-      } else if (type->Is<sem::U32>()) {
-        ast::UintLiteralExpression l(ProgramID(), Source{}, 0);
-        init_id = GenerateLiteralIfNeeded(var, &l);
-      } else if (type->Is<sem::I32>()) {
-        ast::SintLiteralExpression l(ProgramID(), Source{}, 0);
-        init_id = GenerateLiteralIfNeeded(var, &l);
-      } else if (type->Is<sem::Bool>()) {
-        ast::BoolLiteralExpression l(ProgramID(), Source{}, false);
-        init_id = GenerateLiteralIfNeeded(var, &l);
-      } else {
-        error_ = "invalid type for pipeline constant ID, must be scalar";
-        return false;
-      }
-      if (init_id == 0) {
-        return 0;
-      }
-    }
-    push_debug(spv::Op::OpName,
-               {Operand::Int(init_id),
-                Operand::String(builder_.Symbols().NameFor(var->symbol))});
-
-    scope_stack_.Set(var->symbol, init_id);
-    spirv_id_to_variable_[init_id] = var;
-    return true;
-  }
-
-  auto result = result_op();
-  auto var_id = result.to_i();
-
-  auto sc = sem->StorageClass() == ast::StorageClass::kNone
-                ? ast::StorageClass::kPrivate
-                : sem->StorageClass();
-
-  auto type_id = GenerateTypeIfNeeded(sem->Type());
-  if (type_id == 0) {
-    return false;
-  }
-
-  push_debug(spv::Op::OpName,
-             {Operand::Int(var_id),
-              Operand::String(builder_.Symbols().NameFor(var->symbol))});
-
-  OperandList ops = {Operand::Int(type_id), result,
-                     Operand::Int(ConvertStorageClass(sc))};
-
-  if (var->constructor) {
-    ops.push_back(Operand::Int(init_id));
-  } else {
-    auto* st = type->As<sem::StorageTexture>();
-    if (st || type->Is<sem::Struct>()) {
-      // type is a sem::Struct or a sem::StorageTexture
-      auto access = st ? st->access() : sem->Access();
-      switch (access) {
-        case ast::Access::kWrite:
-          push_annot(
-              spv::Op::OpDecorate,
-              {Operand::Int(var_id), Operand::Int(SpvDecorationNonReadable)});
-          break;
-        case ast::Access::kRead:
-          push_annot(
-              spv::Op::OpDecorate,
-              {Operand::Int(var_id), Operand::Int(SpvDecorationNonWritable)});
-          break;
-        case ast::Access::kUndefined:
-        case ast::Access::kReadWrite:
-          break;
-      }
-    }
-    if (!type->Is<sem::Sampler>()) {
-      // If we don't have a constructor and we're an Output or Private
-      // variable, then WGSL requires that we zero-initialize.
-      // If we're a Workgroup variable, and the
-      // VK_KHR_zero_initialize_workgroup_memory extension is enabled, we should
-      // also zero-initialize.
-      if (sem->StorageClass() == ast::StorageClass::kPrivate ||
-          sem->StorageClass() == ast::StorageClass::kOutput ||
-          (zero_initialize_workgroup_memory_ &&
-           sem->StorageClass() == ast::StorageClass::kWorkgroup)) {
-        init_id = GenerateConstantNullIfNeeded(type);
+    uint32_t init_id = 0;
+    if (var->constructor) {
+        init_id = GenerateConstructorExpression(var, var->constructor);
         if (init_id == 0) {
-          return 0;
+            return false;
         }
-        ops.push_back(Operand::Int(init_id));
-      }
     }
-  }
 
-  push_type(spv::Op::OpVariable, std::move(ops));
+    if (var->is_const) {
+        if (!var->constructor) {
+            // Constants must have an initializer unless they are overridable.
+            if (!var->is_overridable) {
+                error_ = "missing constructor for constant";
+                return false;
+            }
 
-  for (auto* attr : var->attributes) {
-    bool ok = Switch(
-        attr,
-        [&](const ast::BuiltinAttribute* builtin) {
-          push_annot(spv::Op::OpDecorate,
-                     {Operand::Int(var_id), Operand::Int(SpvDecorationBuiltIn),
-                      Operand::Int(ConvertBuiltin(builtin->builtin,
-                                                  sem->StorageClass()))});
-          return true;
-        },
-        [&](const ast::LocationAttribute* location) {
-          push_annot(spv::Op::OpDecorate,
-                     {Operand::Int(var_id), Operand::Int(SpvDecorationLocation),
-                      Operand::Int(location->value)});
-          return true;
-        },
-        [&](const ast::InterpolateAttribute* interpolate) {
-          AddInterpolationDecorations(var_id, interpolate->type,
-                                      interpolate->sampling);
-          return true;
-        },
-        [&](const ast::InvariantAttribute*) {
-          push_annot(
-              spv::Op::OpDecorate,
-              {Operand::Int(var_id), Operand::Int(SpvDecorationInvariant)});
-          return true;
-        },
-        [&](const ast::BindingAttribute* binding) {
-          push_annot(spv::Op::OpDecorate,
-                     {Operand::Int(var_id), Operand::Int(SpvDecorationBinding),
-                      Operand::Int(binding->value)});
-          return true;
-        },
-        [&](const ast::GroupAttribute* group) {
-          push_annot(
-              spv::Op::OpDecorate,
-              {Operand::Int(var_id), Operand::Int(SpvDecorationDescriptorSet),
-               Operand::Int(group->value)});
-          return true;
-        },
-        [&](const ast::IdAttribute*) {
-          return true;  // Spec constants are handled elsewhere
-        },
-        [&](const ast::InternalAttribute*) {
-          return true;  // ignored
-        },
-        [&](Default) {
-          error_ = "unknown attribute";
-          return false;
-        });
-    if (!ok) {
-      return false;
+            // SPIR-V requires specialization constants to have initializers.
+            init_id = Switch(
+                type,  //
+                [&](const sem::F32*) {
+                    ast::FloatLiteralExpression l(ProgramID{}, Source{}, 0.0f);
+                    return GenerateLiteralIfNeeded(var, &l);
+                },
+                [&](const sem::U32*) {
+                    ast::IntLiteralExpression l(ProgramID{}, Source{}, 0,
+                                                ast::IntLiteralExpression::Suffix::kU);
+                    return GenerateLiteralIfNeeded(var, &l);
+                },
+                [&](const sem::I32*) {
+                    ast::IntLiteralExpression l(ProgramID{}, Source{}, 0,
+                                                ast::IntLiteralExpression::Suffix::kI);
+                    return GenerateLiteralIfNeeded(var, &l);
+                },
+                [&](const sem::Bool*) {
+                    ast::BoolLiteralExpression l(ProgramID{}, Source{}, false);
+                    return GenerateLiteralIfNeeded(var, &l);
+                },
+                [&](Default) {
+                    error_ = "invalid type for pipeline constant ID, must be scalar";
+                    return 0;
+                });
+            if (init_id == 0) {
+                return 0;
+            }
+        }
+        push_debug(spv::Op::OpName,
+                   {Operand(init_id), Operand(builder_.Symbols().NameFor(var->symbol))});
+
+        RegisterVariable(sem, init_id);
+        return true;
     }
-  }
 
-  scope_stack_.Set(var->symbol, var_id);
-  spirv_id_to_variable_[var_id] = var;
-  return true;
+    auto result = result_op();
+    auto var_id = std::get<uint32_t>(result);
+
+    auto sc = sem->StorageClass() == ast::StorageClass::kNone ? ast::StorageClass::kPrivate
+                                                              : sem->StorageClass();
+
+    auto type_id = GenerateTypeIfNeeded(sem->Type());
+    if (type_id == 0) {
+        return false;
+    }
+
+    push_debug(spv::Op::OpName,
+               {Operand(var_id), Operand(builder_.Symbols().NameFor(var->symbol))});
+
+    OperandList ops = {Operand(type_id), result, U32Operand(ConvertStorageClass(sc))};
+
+    if (var->constructor) {
+        ops.push_back(Operand(init_id));
+    } else {
+        auto* st = type->As<sem::StorageTexture>();
+        if (st || type->Is<sem::Struct>()) {
+            // type is a sem::Struct or a sem::StorageTexture
+            auto access = st ? st->access() : sem->Access();
+            switch (access) {
+                case ast::Access::kWrite:
+                    push_annot(spv::Op::OpDecorate,
+                               {Operand(var_id), U32Operand(SpvDecorationNonReadable)});
+                    break;
+                case ast::Access::kRead:
+                    push_annot(spv::Op::OpDecorate,
+                               {Operand(var_id), U32Operand(SpvDecorationNonWritable)});
+                    break;
+                case ast::Access::kUndefined:
+                case ast::Access::kReadWrite:
+                    break;
+            }
+        }
+        if (!type->Is<sem::Sampler>()) {
+            // If we don't have a constructor and we're an Output or Private
+            // variable, then WGSL requires that we zero-initialize.
+            // If we're a Workgroup variable, and the
+            // VK_KHR_zero_initialize_workgroup_memory extension is enabled, we should
+            // also zero-initialize.
+            if (sem->StorageClass() == ast::StorageClass::kPrivate ||
+                sem->StorageClass() == ast::StorageClass::kOutput ||
+                (zero_initialize_workgroup_memory_ &&
+                 sem->StorageClass() == ast::StorageClass::kWorkgroup)) {
+                init_id = GenerateConstantNullIfNeeded(type);
+                if (init_id == 0) {
+                    return 0;
+                }
+                ops.push_back(Operand(init_id));
+            }
+        }
+    }
+
+    push_type(spv::Op::OpVariable, std::move(ops));
+
+    for (auto* attr : var->attributes) {
+        bool ok = Switch(
+            attr,
+            [&](const ast::BuiltinAttribute* builtin) {
+                push_annot(spv::Op::OpDecorate,
+                           {Operand(var_id), U32Operand(SpvDecorationBuiltIn),
+                            U32Operand(ConvertBuiltin(builtin->builtin, sem->StorageClass()))});
+                return true;
+            },
+            [&](const ast::LocationAttribute* location) {
+                push_annot(spv::Op::OpDecorate, {Operand(var_id), U32Operand(SpvDecorationLocation),
+                                                 Operand(location->value)});
+                return true;
+            },
+            [&](const ast::InterpolateAttribute* interpolate) {
+                AddInterpolationDecorations(var_id, interpolate->type, interpolate->sampling);
+                return true;
+            },
+            [&](const ast::InvariantAttribute*) {
+                push_annot(spv::Op::OpDecorate,
+                           {Operand(var_id), U32Operand(SpvDecorationInvariant)});
+                return true;
+            },
+            [&](const ast::BindingAttribute* binding) {
+                push_annot(spv::Op::OpDecorate, {Operand(var_id), U32Operand(SpvDecorationBinding),
+                                                 Operand(binding->value)});
+                return true;
+            },
+            [&](const ast::GroupAttribute* group) {
+                push_annot(spv::Op::OpDecorate,
+                           {Operand(var_id), U32Operand(SpvDecorationDescriptorSet),
+                            Operand(group->value)});
+                return true;
+            },
+            [&](const ast::IdAttribute*) {
+                return true;  // Spec constants are handled elsewhere
+            },
+            [&](const ast::InternalAttribute*) {
+                return true;  // ignored
+            },
+            [&](Default) {
+                error_ = "unknown attribute";
+                return false;
+            });
+        if (!ok) {
+            return false;
+        }
+    }
+
+    RegisterVariable(sem, var_id);
+    return true;
 }
 
-bool Builder::GenerateIndexAccessor(const ast::IndexAccessorExpression* expr,
-                                    AccessorInfo* info) {
-  auto idx_id = GenerateExpressionWithLoadIfNeeded(expr->index);
-  if (idx_id == 0) {
-    return 0;
-  }
+bool Builder::GenerateIndexAccessor(const ast::IndexAccessorExpression* expr, AccessorInfo* info) {
+    auto idx_id = GenerateExpressionWithLoadIfNeeded(expr->index);
+    if (idx_id == 0) {
+        return 0;
+    }
 
-  // If the source is a reference, we access chain into it.
-  // In the future, pointers may support access-chaining.
-  // See https://github.com/gpuweb/gpuweb/pull/1580
-  if (info->source_type->Is<sem::Reference>()) {
-    info->access_chain_indices.push_back(idx_id);
-    info->source_type = TypeOf(expr);
-    return true;
-  }
+    // If the source is a reference, we access chain into it.
+    // In the future, pointers may support access-chaining.
+    // See https://github.com/gpuweb/gpuweb/pull/1580
+    if (info->source_type->Is<sem::Reference>()) {
+        info->access_chain_indices.push_back(idx_id);
+        info->source_type = TypeOf(expr);
+        return true;
+    }
 
-  auto result_type_id = GenerateTypeIfNeeded(TypeOf(expr));
-  if (result_type_id == 0) {
+    auto result_type_id = GenerateTypeIfNeeded(TypeOf(expr));
+    if (result_type_id == 0) {
+        return false;
+    }
+
+    // We don't have a pointer, so we can just directly extract the value.
+    auto extract = result_op();
+    auto extract_id = std::get<uint32_t>(extract);
+
+    // If the index is compile-time constant, we use OpCompositeExtract.
+    auto* idx = builder_.Sem().Get(expr->index);
+    if (auto idx_constval = idx->ConstantValue()) {
+        if (!push_function_inst(spv::Op::OpCompositeExtract,
+                                {
+                                    Operand(result_type_id),
+                                    extract,
+                                    Operand(info->source_id),
+                                    Operand(idx_constval.ElementAs<uint32_t>(0)),
+                                })) {
+            return false;
+        }
+
+        info->source_id = extract_id;
+        info->source_type = TypeOf(expr);
+
+        return true;
+    }
+
+    // If the source is a vector, we use OpVectorExtractDynamic.
+    if (info->source_type->Is<sem::Vector>()) {
+        if (!push_function_inst(
+                spv::Op::OpVectorExtractDynamic,
+                {Operand(result_type_id), extract, Operand(info->source_id), Operand(idx_id)})) {
+            return false;
+        }
+
+        info->source_id = extract_id;
+        info->source_type = TypeOf(expr);
+
+        return true;
+    }
+
+    TINT_ICE(Writer, builder_.Diagnostics()) << "unsupported index accessor expression";
     return false;
-  }
-
-  // We don't have a pointer, so we can just directly extract the value.
-  auto extract = result_op();
-  auto extract_id = extract.to_i();
-
-  // If the index is compile-time constant, we use OpCompositeExtract.
-  auto* idx = builder_.Sem().Get(expr->index);
-  if (auto idx_constval = idx->ConstantValue()) {
-    if (!push_function_inst(
-            spv::Op::OpCompositeExtract,
-            {
-                Operand::Int(result_type_id),
-                extract,
-                Operand::Int(info->source_id),
-                Operand::Int(idx_constval.ElementAs<uint32_t>(0)),
-            })) {
-      return false;
-    }
-
-    info->source_id = extract_id;
-    info->source_type = TypeOf(expr);
-
-    return true;
-  }
-
-  // If the source is a vector, we use OpVectorExtractDynamic.
-  if (info->source_type->Is<sem::Vector>()) {
-    if (!push_function_inst(
-            spv::Op::OpVectorExtractDynamic,
-            {Operand::Int(result_type_id), extract,
-             Operand::Int(info->source_id), Operand::Int(idx_id)})) {
-      return false;
-    }
-
-    info->source_id = extract_id;
-    info->source_type = TypeOf(expr);
-
-    return true;
-  }
-
-  TINT_ICE(Writer, builder_.Diagnostics())
-      << "unsupported index accessor expression";
-  return false;
 }
 
 bool Builder::GenerateMemberAccessor(const ast::MemberAccessorExpression* expr,
                                      AccessorInfo* info) {
-  auto* expr_sem = builder_.Sem().Get(expr);
-  auto* expr_type = expr_sem->Type();
+    auto* expr_sem = builder_.Sem().Get(expr);
+    auto* expr_type = expr_sem->Type();
 
-  if (auto* access = expr_sem->As<sem::StructMemberAccess>()) {
-    uint32_t idx = access->Member()->Index();
+    if (auto* access = expr_sem->As<sem::StructMemberAccess>()) {
+        uint32_t idx = access->Member()->Index();
 
-    if (info->source_type->Is<sem::Reference>()) {
-      auto idx_id = GenerateConstantIfNeeded(ScalarConstant::U32(idx));
-      if (idx_id == 0) {
-        return 0;
-      }
-      info->access_chain_indices.push_back(idx_id);
-      info->source_type = expr_type;
-    } else {
-      auto result_type_id = GenerateTypeIfNeeded(expr_type);
-      if (result_type_id == 0) {
-        return false;
-      }
+        if (info->source_type->Is<sem::Reference>()) {
+            auto idx_id = GenerateConstantIfNeeded(ScalarConstant::U32(idx));
+            if (idx_id == 0) {
+                return 0;
+            }
+            info->access_chain_indices.push_back(idx_id);
+            info->source_type = expr_type;
+        } else {
+            auto result_type_id = GenerateTypeIfNeeded(expr_type);
+            if (result_type_id == 0) {
+                return false;
+            }
 
-      auto extract = result_op();
-      auto extract_id = extract.to_i();
-      if (!push_function_inst(
-              spv::Op::OpCompositeExtract,
-              {Operand::Int(result_type_id), extract,
-               Operand::Int(info->source_id), Operand::Int(idx)})) {
-        return false;
-      }
+            auto extract = result_op();
+            auto extract_id = std::get<uint32_t>(extract);
+            if (!push_function_inst(
+                    spv::Op::OpCompositeExtract,
+                    {Operand(result_type_id), extract, Operand(info->source_id), Operand(idx)})) {
+                return false;
+            }
 
-      info->source_id = extract_id;
-      info->source_type = expr_type;
+            info->source_id = extract_id;
+            info->source_type = expr_type;
+        }
+
+        return true;
     }
 
-    return true;
-  }
+    if (auto* swizzle = expr_sem->As<sem::Swizzle>()) {
+        // Single element swizzle is either an access chain or a composite extract
+        auto& indices = swizzle->Indices();
+        if (indices.size() == 1) {
+            if (info->source_type->Is<sem::Reference>()) {
+                auto idx_id = GenerateConstantIfNeeded(ScalarConstant::U32(indices[0]));
+                if (idx_id == 0) {
+                    return 0;
+                }
+                info->access_chain_indices.push_back(idx_id);
+            } else {
+                auto result_type_id = GenerateTypeIfNeeded(expr_type);
+                if (result_type_id == 0) {
+                    return 0;
+                }
 
-  if (auto* swizzle = expr_sem->As<sem::Swizzle>()) {
-    // Single element swizzle is either an access chain or a composite extract
-    auto& indices = swizzle->Indices();
-    if (indices.size() == 1) {
-      if (info->source_type->Is<sem::Reference>()) {
-        auto idx_id = GenerateConstantIfNeeded(ScalarConstant::U32(indices[0]));
-        if (idx_id == 0) {
-          return 0;
+                auto extract = result_op();
+                auto extract_id = std::get<uint32_t>(extract);
+                if (!push_function_inst(spv::Op::OpCompositeExtract,
+                                        {Operand(result_type_id), extract, Operand(info->source_id),
+                                         Operand(indices[0])})) {
+                    return false;
+                }
+
+                info->source_id = extract_id;
+                info->source_type = expr_type;
+            }
+            return true;
         }
-        info->access_chain_indices.push_back(idx_id);
-      } else {
+
+        // Store the type away as it may change if we run the access chain
+        auto* incoming_type = info->source_type;
+
+        // Multi-item extract is a VectorShuffle. We have to emit any existing
+        // access chain data, then load the access chain and shuffle that.
+        if (!info->access_chain_indices.empty()) {
+            auto result_type_id = GenerateTypeIfNeeded(info->source_type);
+            if (result_type_id == 0) {
+                return 0;
+            }
+            auto extract = result_op();
+            auto extract_id = std::get<uint32_t>(extract);
+
+            OperandList ops = {Operand(result_type_id), extract, Operand(info->source_id)};
+            for (auto id : info->access_chain_indices) {
+                ops.push_back(Operand(id));
+            }
+
+            if (!push_function_inst(spv::Op::OpAccessChain, ops)) {
+                return false;
+            }
+
+            info->source_id = GenerateLoadIfNeeded(expr_type, extract_id);
+            info->source_type = expr_type->UnwrapRef();
+            info->access_chain_indices.clear();
+        }
+
         auto result_type_id = GenerateTypeIfNeeded(expr_type);
         if (result_type_id == 0) {
-          return 0;
+            return false;
         }
 
-        auto extract = result_op();
-        auto extract_id = extract.to_i();
-        if (!push_function_inst(
-                spv::Op::OpCompositeExtract,
-                {Operand::Int(result_type_id), extract,
-                 Operand::Int(info->source_id), Operand::Int(indices[0])})) {
-          return false;
+        auto vec_id = GenerateLoadIfNeeded(incoming_type, info->source_id);
+
+        auto result = result_op();
+        auto result_id = std::get<uint32_t>(result);
+
+        OperandList ops = {Operand(result_type_id), result, Operand(vec_id), Operand(vec_id)};
+
+        for (auto idx : indices) {
+            ops.push_back(Operand(idx));
         }
 
-        info->source_id = extract_id;
+        if (!push_function_inst(spv::Op::OpVectorShuffle, ops)) {
+            return false;
+        }
+        info->source_id = result_id;
         info->source_type = expr_type;
-      }
-      return true;
+        return true;
     }
 
-    // Store the type away as it may change if we run the access chain
-    auto* incoming_type = info->source_type;
-
-    // Multi-item extract is a VectorShuffle. We have to emit any existing
-    // access chain data, then load the access chain and shuffle that.
-    if (!info->access_chain_indices.empty()) {
-      auto result_type_id = GenerateTypeIfNeeded(info->source_type);
-      if (result_type_id == 0) {
-        return 0;
-      }
-      auto extract = result_op();
-      auto extract_id = extract.to_i();
-
-      OperandList ops = {Operand::Int(result_type_id), extract,
-                         Operand::Int(info->source_id)};
-      for (auto id : info->access_chain_indices) {
-        ops.push_back(Operand::Int(id));
-      }
-
-      if (!push_function_inst(spv::Op::OpAccessChain, ops)) {
-        return false;
-      }
-
-      info->source_id = GenerateLoadIfNeeded(expr_type, extract_id);
-      info->source_type = expr_type->UnwrapRef();
-      info->access_chain_indices.clear();
-    }
-
-    auto result_type_id = GenerateTypeIfNeeded(expr_type);
-    if (result_type_id == 0) {
-      return false;
-    }
-
-    auto vec_id = GenerateLoadIfNeeded(incoming_type, info->source_id);
-
-    auto result = result_op();
-    auto result_id = result.to_i();
-
-    OperandList ops = {Operand::Int(result_type_id), result,
-                       Operand::Int(vec_id), Operand::Int(vec_id)};
-
-    for (auto idx : indices) {
-      ops.push_back(Operand::Int(idx));
-    }
-
-    if (!push_function_inst(spv::Op::OpVectorShuffle, ops)) {
-      return false;
-    }
-    info->source_id = result_id;
-    info->source_type = expr_type;
-    return true;
-  }
-
-  TINT_ICE(Writer, builder_.Diagnostics())
-      << "unhandled member index type: " << expr_sem->TypeInfo().name;
-  return false;
+    TINT_ICE(Writer, builder_.Diagnostics())
+        << "unhandled member index type: " << expr_sem->TypeInfo().name;
+    return false;
 }
 
 uint32_t Builder::GenerateAccessorExpression(const ast::Expression* expr) {
-  if (!expr->IsAnyOf<ast::IndexAccessorExpression,
-                     ast::MemberAccessorExpression>()) {
-    TINT_ICE(Writer, builder_.Diagnostics()) << "expression is not an accessor";
+    if (!expr->IsAnyOf<ast::IndexAccessorExpression, ast::MemberAccessorExpression>()) {
+        TINT_ICE(Writer, builder_.Diagnostics()) << "expression is not an accessor";
+        return 0;
+    }
+
+    // Gather a list of all the member and index accessors that are in this chain.
+    // The list is built in reverse order as that's the order we need to access
+    // the chain.
+    std::vector<const ast::Expression*> accessors;
+    const ast::Expression* source = expr;
+    while (true) {
+        if (auto* array = source->As<ast::IndexAccessorExpression>()) {
+            accessors.insert(accessors.begin(), source);
+            source = array->object;
+        } else if (auto* member = source->As<ast::MemberAccessorExpression>()) {
+            accessors.insert(accessors.begin(), source);
+            source = member->structure;
+        } else {
+            break;
+        }
+    }
+
+    AccessorInfo info;
+    info.source_id = GenerateExpression(source);
+    if (info.source_id == 0) {
+        return 0;
+    }
+    info.source_type = TypeOf(source);
+
+    // Note: Dynamic index on array and matrix values (lets) should have been
+    // promoted to storage with the VarForDynamicIndex transform.
+
+    for (auto* accessor : accessors) {
+        bool ok = Switch(
+            accessor,
+            [&](const ast::IndexAccessorExpression* array) {
+                return GenerateIndexAccessor(array, &info);
+            },
+            [&](const ast::MemberAccessorExpression* member) {
+                return GenerateMemberAccessor(member, &info);
+            },
+            [&](Default) {
+                error_ = "invalid accessor in list: " + std::string(accessor->TypeInfo().name);
+                return false;
+            });
+        if (!ok) {
+            return false;
+        }
+    }
+
+    if (!info.access_chain_indices.empty()) {
+        auto* type = TypeOf(expr);
+        auto result_type_id = GenerateTypeIfNeeded(type);
+        if (result_type_id == 0) {
+            return 0;
+        }
+
+        auto result = result_op();
+        auto result_id = std::get<uint32_t>(result);
+
+        OperandList ops = {Operand(result_type_id), result, Operand(info.source_id)};
+        for (auto id : info.access_chain_indices) {
+            ops.push_back(Operand(id));
+        }
+
+        if (!push_function_inst(spv::Op::OpAccessChain, ops)) {
+            return false;
+        }
+        info.source_id = result_id;
+    }
+
+    return info.source_id;
+}
+
+uint32_t Builder::GenerateIdentifierExpression(const ast::IdentifierExpression* expr) {
+    auto* sem = builder_.Sem().Get(expr);
+    if (auto* user = sem->As<sem::VariableUser>()) {
+        return LookupVariableID(user->Variable());
+    }
+    error_ = "identifier '" + builder_.Symbols().NameFor(expr->symbol) +
+             "' does not resolve to a variable";
     return 0;
-  }
+}
 
-  // Gather a list of all the member and index accessors that are in this chain.
-  // The list is built in reverse order as that's the order we need to access
-  // the chain.
-  std::vector<const ast::Expression*> accessors;
-  const ast::Expression* source = expr;
-  while (true) {
-    if (auto* array = source->As<ast::IndexAccessorExpression>()) {
-      accessors.insert(accessors.begin(), source);
-      source = array->object;
-    } else if (auto* member = source->As<ast::MemberAccessorExpression>()) {
-      accessors.insert(accessors.begin(), source);
-      source = member->structure;
-    } else {
-      break;
+uint32_t Builder::GenerateExpressionWithLoadIfNeeded(const sem::Expression* expr) {
+    // The semantic node directly knows both the AST node and the resolved type.
+    if (const auto id = GenerateExpression(expr->Declaration())) {
+        return GenerateLoadIfNeeded(expr->Type(), id);
     }
-  }
-
-  AccessorInfo info;
-  info.source_id = GenerateExpression(source);
-  if (info.source_id == 0) {
     return 0;
-  }
-  info.source_type = TypeOf(source);
-
-  // Note: Dynamic index on array and matrix values (lets) should have been
-  // promoted to storage with the VarForDynamicIndex transform.
-
-  for (auto* accessor : accessors) {
-    bool ok = Switch(
-        accessor,
-        [&](const ast::IndexAccessorExpression* array) {
-          return GenerateIndexAccessor(array, &info);
-        },
-        [&](const ast::MemberAccessorExpression* member) {
-          return GenerateMemberAccessor(member, &info);
-        },
-        [&](Default) {
-          error_ = "invalid accessor in list: " +
-                   std::string(accessor->TypeInfo().name);
-          return false;
-        });
-    if (!ok) {
-      return false;
-    }
-  }
-
-  if (!info.access_chain_indices.empty()) {
-    auto* type = TypeOf(expr);
-    auto result_type_id = GenerateTypeIfNeeded(type);
-    if (result_type_id == 0) {
-      return 0;
-    }
-
-    auto result = result_op();
-    auto result_id = result.to_i();
-
-    OperandList ops = {Operand::Int(result_type_id), result,
-                       Operand::Int(info.source_id)};
-    for (auto id : info.access_chain_indices) {
-      ops.push_back(Operand::Int(id));
-    }
-
-    if (!push_function_inst(spv::Op::OpAccessChain, ops)) {
-      return false;
-    }
-    info.source_id = result_id;
-  }
-
-  return info.source_id;
 }
 
-uint32_t Builder::GenerateIdentifierExpression(
-    const ast::IdentifierExpression* expr) {
-  uint32_t val = scope_stack_.Get(expr->symbol);
-  if (val == 0) {
-    error_ = "unable to find variable with identifier: " +
-             builder_.Symbols().NameFor(expr->symbol);
-  }
-  return val;
-}
-
-uint32_t Builder::GenerateExpressionWithLoadIfNeeded(
-    const sem::Expression* expr) {
-  // The semantic node directly knows both the AST node and the resolved type.
-  if (const auto id = GenerateExpression(expr->Declaration())) {
-    return GenerateLoadIfNeeded(expr->Type(), id);
-  }
-  return 0;
-}
-
-uint32_t Builder::GenerateExpressionWithLoadIfNeeded(
-    const ast::Expression* expr) {
-  if (const auto id = GenerateExpression(expr)) {
-    // Perform a lookup to get the resolved type.
-    return GenerateLoadIfNeeded(TypeOf(expr), id);
-  }
-  return 0;
+uint32_t Builder::GenerateExpressionWithLoadIfNeeded(const ast::Expression* expr) {
+    if (const auto id = GenerateExpression(expr)) {
+        // Perform a lookup to get the resolved type.
+        return GenerateLoadIfNeeded(TypeOf(expr), id);
+    }
+    return 0;
 }
 
 uint32_t Builder::GenerateLoadIfNeeded(const sem::Type* type, uint32_t id) {
-  if (auto* ref = type->As<sem::Reference>()) {
-    type = ref->StoreType();
-  } else {
-    return id;
-  }
+    if (auto* ref = type->As<sem::Reference>()) {
+        type = ref->StoreType();
+    } else {
+        return id;
+    }
 
-  auto type_id = GenerateTypeIfNeeded(type);
-  auto result = result_op();
-  auto result_id = result.to_i();
-  if (!push_function_inst(spv::Op::OpLoad,
-                          {Operand::Int(type_id), result, Operand::Int(id)})) {
-    return 0;
-  }
-  return result_id;
+    auto type_id = GenerateTypeIfNeeded(type);
+    auto result = result_op();
+    auto result_id = std::get<uint32_t>(result);
+    if (!push_function_inst(spv::Op::OpLoad, {Operand(type_id), result, Operand(id)})) {
+        return 0;
+    }
+    return result_id;
 }
 
-uint32_t Builder::GenerateUnaryOpExpression(
-    const ast::UnaryOpExpression* expr) {
-  auto result = result_op();
-  auto result_id = result.to_i();
+uint32_t Builder::GenerateUnaryOpExpression(const ast::UnaryOpExpression* expr) {
+    auto result = result_op();
+    auto result_id = std::get<uint32_t>(result);
 
-  spv::Op op = spv::Op::OpNop;
-  switch (expr->op) {
-    case ast::UnaryOp::kComplement:
-      op = spv::Op::OpNot;
-      break;
-    case ast::UnaryOp::kNegation:
-      if (TypeOf(expr)->is_float_scalar_or_vector()) {
-        op = spv::Op::OpFNegate;
-      } else {
-        op = spv::Op::OpSNegate;
-      }
-      break;
-    case ast::UnaryOp::kNot:
-      op = spv::Op::OpLogicalNot;
-      break;
-    case ast::UnaryOp::kAddressOf:
-    case ast::UnaryOp::kIndirection:
-      // Address-of converts a reference to a pointer, and dereference converts
-      // a pointer to a reference. These are the same thing in SPIR-V, so this
-      // is a no-op.
-      return GenerateExpression(expr->expr);
-  }
+    spv::Op op = spv::Op::OpNop;
+    switch (expr->op) {
+        case ast::UnaryOp::kComplement:
+            op = spv::Op::OpNot;
+            break;
+        case ast::UnaryOp::kNegation:
+            if (TypeOf(expr)->is_float_scalar_or_vector()) {
+                op = spv::Op::OpFNegate;
+            } else {
+                op = spv::Op::OpSNegate;
+            }
+            break;
+        case ast::UnaryOp::kNot:
+            op = spv::Op::OpLogicalNot;
+            break;
+        case ast::UnaryOp::kAddressOf:
+        case ast::UnaryOp::kIndirection:
+            // Address-of converts a reference to a pointer, and dereference converts
+            // a pointer to a reference. These are the same thing in SPIR-V, so this
+            // is a no-op.
+            return GenerateExpression(expr->expr);
+    }
 
-  auto val_id = GenerateExpressionWithLoadIfNeeded(expr->expr);
-  if (val_id == 0) {
-    return 0;
-  }
+    auto val_id = GenerateExpressionWithLoadIfNeeded(expr->expr);
+    if (val_id == 0) {
+        return 0;
+    }
 
-  auto type_id = GenerateTypeIfNeeded(TypeOf(expr));
-  if (type_id == 0) {
-    return 0;
-  }
+    auto type_id = GenerateTypeIfNeeded(TypeOf(expr));
+    if (type_id == 0) {
+        return 0;
+    }
 
-  if (!push_function_inst(
-          op, {Operand::Int(type_id), result, Operand::Int(val_id)})) {
-    return false;
-  }
+    if (!push_function_inst(op, {Operand(type_id), result, Operand(val_id)})) {
+        return false;
+    }
 
-  return result_id;
+    return result_id;
 }
 
 uint32_t Builder::GetGLSLstd450Import() {
-  auto where = import_name_to_id_.find(kGLSLstd450);
-  if (where != import_name_to_id_.end()) {
-    return where->second;
-  }
+    auto where = import_name_to_id_.find(kGLSLstd450);
+    if (where != import_name_to_id_.end()) {
+        return where->second;
+    }
 
-  // It doesn't exist yet. Generate it.
-  auto result = result_op();
-  auto id = result.to_i();
+    // It doesn't exist yet. Generate it.
+    auto result = result_op();
+    auto id = std::get<uint32_t>(result);
 
-  push_ext_import(spv::Op::OpExtInstImport,
-                  {result, Operand::String(kGLSLstd450)});
+    push_ext_import(spv::Op::OpExtInstImport, {result, Operand(kGLSLstd450)});
 
-  // Remember it for later.
-  import_name_to_id_[kGLSLstd450] = id;
-  return id;
+    // Remember it for later.
+    import_name_to_id_[kGLSLstd450] = id;
+    return id;
 }
 
 uint32_t Builder::GenerateConstructorExpression(const ast::Variable* var,
                                                 const ast::Expression* expr) {
-  if (auto* literal = expr->As<ast::LiteralExpression>()) {
-    return GenerateLiteralIfNeeded(var, literal);
-  }
-  if (auto* call = builder_.Sem().Get<sem::Call>(expr)) {
-    if (call->Target()->IsAnyOf<sem::TypeConstructor, sem::TypeConversion>()) {
-      return GenerateTypeConstructorOrConversion(call, var);
+    if (auto* literal = expr->As<ast::LiteralExpression>()) {
+        return GenerateLiteralIfNeeded(var, literal);
     }
-  }
-  error_ = "unknown constructor expression";
-  return 0;
+    if (auto* call = builder_.Sem().Get<sem::Call>(expr)) {
+        if (call->Target()->IsAnyOf<sem::TypeConstructor, sem::TypeConversion>()) {
+            return GenerateTypeConstructorOrConversion(call, var);
+        }
+    }
+    error_ = "unknown constructor expression";
+    return 0;
 }
 
 bool Builder::IsConstructorConst(const ast::Expression* expr) {
-  bool is_const = true;
-  ast::TraverseExpressions(expr, builder_.Diagnostics(),
-                           [&](const ast::Expression* e) {
-                             if (e->Is<ast::LiteralExpression>()) {
-                               return ast::TraverseAction::Descend;
-                             }
-                             if (auto* ce = e->As<ast::CallExpression>()) {
-                               auto* call = builder_.Sem().Get(ce);
-                               if (call->Target()->Is<sem::TypeConstructor>()) {
-                                 return ast::TraverseAction::Descend;
-                               }
-                             }
+    bool is_const = true;
+    ast::TraverseExpressions(expr, builder_.Diagnostics(), [&](const ast::Expression* e) {
+        if (e->Is<ast::LiteralExpression>()) {
+            return ast::TraverseAction::Descend;
+        }
+        if (auto* ce = e->As<ast::CallExpression>()) {
+            auto* call = builder_.Sem().Get(ce);
+            if (call->Target()->Is<sem::TypeConstructor>()) {
+                return ast::TraverseAction::Descend;
+            }
+        }
 
-                             is_const = false;
-                             return ast::TraverseAction::Stop;
-                           });
-  return is_const;
+        is_const = false;
+        return ast::TraverseAction::Stop;
+    });
+    return is_const;
 }
 
-uint32_t Builder::GenerateTypeConstructorOrConversion(
-    const sem::Call* call,
-    const ast::Variable* var) {
-  auto& args = call->Arguments();
-  auto* global_var = builder_.Sem().Get<sem::GlobalVariable>(var);
-  auto* result_type = call->Type();
+uint32_t Builder::GenerateTypeConstructorOrConversion(const sem::Call* call,
+                                                      const ast::Variable* var) {
+    auto& args = call->Arguments();
+    auto* global_var = builder_.Sem().Get<sem::GlobalVariable>(var);
+    auto* result_type = call->Type();
 
-  // Generate the zero initializer if there are no values provided.
-  if (args.empty()) {
-    if (global_var && global_var->IsOverridable()) {
-      auto constant_id = global_var->ConstantId();
-      if (result_type->Is<sem::I32>()) {
-        return GenerateConstantIfNeeded(
-            ScalarConstant::I32(0).AsSpecOp(constant_id));
-      }
-      if (result_type->Is<sem::U32>()) {
-        return GenerateConstantIfNeeded(
-            ScalarConstant::U32(0).AsSpecOp(constant_id));
-      }
-      if (result_type->Is<sem::F32>()) {
-        return GenerateConstantIfNeeded(
-            ScalarConstant::F32(0).AsSpecOp(constant_id));
-      }
-      if (result_type->Is<sem::Bool>()) {
-        return GenerateConstantIfNeeded(
-            ScalarConstant::Bool(false).AsSpecOp(constant_id));
-      }
-    }
-    return GenerateConstantNullIfNeeded(result_type->UnwrapRef());
-  }
-
-  std::ostringstream out;
-  out << "__const_" << result_type->FriendlyName(builder_.Symbols()) << "_";
-
-  result_type = result_type->UnwrapRef();
-  bool constructor_is_const = IsConstructorConst(call->Declaration());
-  if (has_error()) {
-    return 0;
-  }
-
-  bool can_cast_or_copy = result_type->is_scalar();
-
-  if (auto* res_vec = result_type->As<sem::Vector>()) {
-    if (res_vec->type()->is_scalar()) {
-      auto* value_type = args[0]->Type()->UnwrapRef();
-      if (auto* val_vec = value_type->As<sem::Vector>()) {
-        if (val_vec->type()->is_scalar()) {
-          can_cast_or_copy = res_vec->Width() == val_vec->Width();
+    // Generate the zero initializer if there are no values provided.
+    if (args.empty()) {
+        if (global_var && global_var->IsOverridable()) {
+            auto constant_id = global_var->ConstantId();
+            if (result_type->Is<sem::I32>()) {
+                return GenerateConstantIfNeeded(ScalarConstant::I32(0).AsSpecOp(constant_id));
+            }
+            if (result_type->Is<sem::U32>()) {
+                return GenerateConstantIfNeeded(ScalarConstant::U32(0).AsSpecOp(constant_id));
+            }
+            if (result_type->Is<sem::F32>()) {
+                return GenerateConstantIfNeeded(ScalarConstant::F32(0).AsSpecOp(constant_id));
+            }
+            if (result_type->Is<sem::Bool>()) {
+                return GenerateConstantIfNeeded(ScalarConstant::Bool(false).AsSpecOp(constant_id));
+            }
         }
-      }
-    }
-  }
-
-  if (can_cast_or_copy) {
-    return GenerateCastOrCopyOrPassthrough(result_type, args[0]->Declaration(),
-                                           global_var);
-  }
-
-  auto type_id = GenerateTypeIfNeeded(result_type);
-  if (type_id == 0) {
-    return 0;
-  }
-
-  bool result_is_constant_composite = constructor_is_const;
-  bool result_is_spec_composite = false;
-
-  if (auto* vec = result_type->As<sem::Vector>()) {
-    result_type = vec->type();
-  }
-
-  OperandList ops;
-  for (auto* e : args) {
-    uint32_t id = 0;
-    id = GenerateExpressionWithLoadIfNeeded(e);
-    if (id == 0) {
-      return 0;
+        return GenerateConstantNullIfNeeded(result_type->UnwrapRef());
     }
 
-    auto* value_type = e->Type()->UnwrapRef();
-    // If the result and value types are the same we can just use the object.
-    // If the result is not a vector then we should have validated that the
-    // value type is a correctly sized vector so we can just use it directly.
-    if (result_type == value_type || result_type->Is<sem::Matrix>() ||
-        result_type->Is<sem::Array>() || result_type->Is<sem::Struct>()) {
-      out << "_" << id;
-
-      ops.push_back(Operand::Int(id));
-      continue;
-    }
-
-    // Both scalars, but not the same type so we need to generate a conversion
-    // of the value.
-    if (value_type->is_scalar() && result_type->is_scalar()) {
-      id = GenerateCastOrCopyOrPassthrough(result_type, args[0]->Declaration(),
-                                           global_var);
-      out << "_" << id;
-      ops.push_back(Operand::Int(id));
-      continue;
-    }
-
-    // When handling vectors as the values there a few cases to take into
-    // consideration:
-    //  1. Module scoped vec3<f32>(vec2<f32>(1, 2), 3)  -> OpSpecConstantOp
-    //  2. Function scoped vec3<f32>(vec2<f32>(1, 2), 3) ->  OpCompositeExtract
-    //  3. Either array<vec3<f32>, 1>(vec3<f32>(1, 2, 3))  -> use the ID.
-    //       -> handled above
-    //
-    // For cases 1 and 2, if the type is different we also may need to insert
-    // a type cast.
-    if (auto* vec = value_type->As<sem::Vector>()) {
-      auto* vec_type = vec->type();
-
-      auto value_type_id = GenerateTypeIfNeeded(vec_type);
-      if (value_type_id == 0) {
+    result_type = result_type->UnwrapRef();
+    bool constructor_is_const = IsConstructorConst(call->Declaration());
+    if (has_error()) {
         return 0;
-      }
+    }
 
-      for (uint32_t i = 0; i < vec->Width(); ++i) {
-        auto extract = result_op();
-        auto extract_id = extract.to_i();
+    bool can_cast_or_copy = result_type->is_scalar();
 
-        if (!global_var) {
-          // A non-global initializer. Case 2.
-          if (!push_function_inst(spv::Op::OpCompositeExtract,
-                                  {Operand::Int(value_type_id), extract,
-                                   Operand::Int(id), Operand::Int(i)})) {
-            return false;
-          }
+    if (auto* res_vec = result_type->As<sem::Vector>()) {
+        if (res_vec->type()->is_scalar()) {
+            auto* value_type = args[0]->Type()->UnwrapRef();
+            if (auto* val_vec = value_type->As<sem::Vector>()) {
+                if (val_vec->type()->is_scalar()) {
+                    can_cast_or_copy = res_vec->Width() == val_vec->Width();
+                }
+            }
+        }
+    }
 
-          // We no longer have a constant composite, but have to do a
-          // composite construction as these calls are inside a function.
-          result_is_constant_composite = false;
-        } else {
-          // A global initializer, must use OpSpecConstantOp. Case 1.
-          auto idx_id = GenerateConstantIfNeeded(ScalarConstant::U32(i));
-          if (idx_id == 0) {
+    if (can_cast_or_copy) {
+        return GenerateCastOrCopyOrPassthrough(result_type, args[0]->Declaration(), global_var);
+    }
+
+    auto type_id = GenerateTypeIfNeeded(result_type);
+    if (type_id == 0) {
+        return 0;
+    }
+
+    bool result_is_constant_composite = constructor_is_const;
+    bool result_is_spec_composite = false;
+
+    if (auto* vec = result_type->As<sem::Vector>()) {
+        result_type = vec->type();
+    }
+
+    OperandList ops;
+    static constexpr size_t kOpsResultIdx = 1;
+    static constexpr size_t kOpsFirstValueIdx = 2;
+    ops.reserve(8);
+    ops.push_back(Operand(type_id));
+    ops.push_back(Operand(0u));  // Placeholder for the result ID
+
+    for (auto* e : args) {
+        uint32_t id = 0;
+        id = GenerateExpressionWithLoadIfNeeded(e);
+        if (id == 0) {
             return 0;
-          }
-          push_type(spv::Op::OpSpecConstantOp,
-                    {Operand::Int(value_type_id), extract,
-                     Operand::Int(SpvOpCompositeExtract), Operand::Int(id),
-                     Operand::Int(idx_id)});
-
-          result_is_spec_composite = true;
         }
 
-        out << "_" << extract_id;
-        ops.push_back(Operand::Int(extract_id));
-      }
-    } else {
-      error_ = "Unhandled type cast value type";
-      return 0;
+        auto* value_type = e->Type()->UnwrapRef();
+        // If the result and value types are the same we can just use the object.
+        // If the result is not a vector then we should have validated that the
+        // value type is a correctly sized vector so we can just use it directly.
+        if (result_type == value_type || result_type->Is<sem::Matrix>() ||
+            result_type->Is<sem::Array>() || result_type->Is<sem::Struct>()) {
+            ops.push_back(Operand(id));
+            continue;
+        }
+
+        // Both scalars, but not the same type so we need to generate a conversion
+        // of the value.
+        if (value_type->is_scalar() && result_type->is_scalar()) {
+            id = GenerateCastOrCopyOrPassthrough(result_type, args[0]->Declaration(), global_var);
+            ops.push_back(Operand(id));
+            continue;
+        }
+
+        // When handling vectors as the values there a few cases to take into
+        // consideration:
+        //  1. Module scoped vec3<f32>(vec2<f32>(1, 2), 3)  -> OpSpecConstantOp
+        //  2. Function scoped vec3<f32>(vec2<f32>(1, 2), 3) ->  OpCompositeExtract
+        //  3. Either array<vec3<f32>, 1>(vec3<f32>(1, 2, 3))  -> use the ID.
+        //       -> handled above
+        //
+        // For cases 1 and 2, if the type is different we also may need to insert
+        // a type cast.
+        if (auto* vec = value_type->As<sem::Vector>()) {
+            auto* vec_type = vec->type();
+
+            auto value_type_id = GenerateTypeIfNeeded(vec_type);
+            if (value_type_id == 0) {
+                return 0;
+            }
+
+            for (uint32_t i = 0; i < vec->Width(); ++i) {
+                auto extract = result_op();
+                auto extract_id = std::get<uint32_t>(extract);
+
+                if (!global_var) {
+                    // A non-global initializer. Case 2.
+                    if (!push_function_inst(
+                            spv::Op::OpCompositeExtract,
+                            {Operand(value_type_id), extract, Operand(id), Operand(i)})) {
+                        return false;
+                    }
+
+                    // We no longer have a constant composite, but have to do a
+                    // composite construction as these calls are inside a function.
+                    result_is_constant_composite = false;
+                } else {
+                    // A global initializer, must use OpSpecConstantOp. Case 1.
+                    auto idx_id = GenerateConstantIfNeeded(ScalarConstant::U32(i));
+                    if (idx_id == 0) {
+                        return 0;
+                    }
+                    push_type(spv::Op::OpSpecConstantOp,
+                              {Operand(value_type_id), extract, U32Operand(SpvOpCompositeExtract),
+                               Operand(id), Operand(idx_id)});
+
+                    result_is_spec_composite = true;
+                }
+
+                ops.push_back(Operand(extract_id));
+            }
+        } else {
+            error_ = "Unhandled type cast value type";
+            return 0;
+        }
     }
-  }
 
-  // For a single-value vector initializer, splat the initializer value.
-  auto* const init_result_type = call->Type()->UnwrapRef();
-  if (args.size() == 1 && init_result_type->is_scalar_vector() &&
-      args[0]->Type()->UnwrapRef()->is_scalar()) {
-    size_t vec_size = init_result_type->As<sem::Vector>()->Width();
-    for (size_t i = 0; i < (vec_size - 1); ++i) {
-      ops.push_back(ops[0]);
+    // For a single-value vector initializer, splat the initializer value.
+    auto* const init_result_type = call->Type()->UnwrapRef();
+    if (args.size() == 1 && init_result_type->is_scalar_vector() &&
+        args[0]->Type()->UnwrapRef()->is_scalar()) {
+        size_t vec_size = init_result_type->As<sem::Vector>()->Width();
+        for (size_t i = 0; i < (vec_size - 1); ++i) {
+            ops.push_back(ops[kOpsFirstValueIdx]);
+        }
     }
-  }
 
-  auto str = out.str();
-  auto val = type_constructor_to_id_.find(str);
-  if (val != type_constructor_to_id_.end()) {
-    return val->second;
-  }
+    auto& stack = (result_is_spec_composite || result_is_constant_composite)
+                      ? scope_stack_[0]       // Global scope
+                      : scope_stack_.back();  // Lexical scope
 
-  auto result = result_op();
-  ops.insert(ops.begin(), result);
-  ops.insert(ops.begin(), Operand::Int(type_id));
+    return utils::GetOrCreate(stack.type_ctor_to_id_, OperandListKey{ops}, [&]() -> uint32_t {
+        auto result = result_op();
+        ops[kOpsResultIdx] = result;
 
-  type_constructor_to_id_[str] = result.to_i();
+        if (result_is_spec_composite) {
+            push_type(spv::Op::OpSpecConstantComposite, ops);
+        } else if (result_is_constant_composite) {
+            push_type(spv::Op::OpConstantComposite, ops);
+        } else {
+            if (!push_function_inst(spv::Op::OpCompositeConstruct, ops)) {
+                return 0;
+            }
+        }
 
-  if (result_is_spec_composite) {
-    push_type(spv::Op::OpSpecConstantComposite, ops);
-  } else if (result_is_constant_composite) {
-    push_type(spv::Op::OpConstantComposite, ops);
-  } else {
-    if (!push_function_inst(spv::Op::OpCompositeConstruct, ops)) {
-      return 0;
-    }
-  }
-
-  return result.to_i();
+        return std::get<uint32_t>(result);
+    });
 }
 
-uint32_t Builder::GenerateCastOrCopyOrPassthrough(
-    const sem::Type* to_type,
-    const ast::Expression* from_expr,
-    bool is_global_init) {
-  // This should not happen as we rely on constant folding to obviate
-  // casts/conversions for module-scope variables
-  if (is_global_init) {
-    TINT_ICE(Writer, builder_.Diagnostics())
-        << "Module-level conversions are not supported. Conversions should "
-           "have already been constant-folded by the FoldConstants transform.";
-    return 0;
-  }
-
-  auto elem_type_of = [](const sem::Type* t) -> const sem::Type* {
-    if (t->is_scalar()) {
-      return t;
-    }
-    if (auto* v = t->As<sem::Vector>()) {
-      return v->type();
-    }
-    return nullptr;
-  };
-
-  auto result = result_op();
-  auto result_id = result.to_i();
-
-  auto result_type_id = GenerateTypeIfNeeded(to_type);
-  if (result_type_id == 0) {
-    return 0;
-  }
-
-  auto val_id = GenerateExpressionWithLoadIfNeeded(from_expr);
-  if (val_id == 0) {
-    return 0;
-  }
-
-  auto* from_type = TypeOf(from_expr)->UnwrapRef();
-
-  spv::Op op = spv::Op::OpNop;
-  if ((from_type->Is<sem::I32>() && to_type->Is<sem::F32>()) ||
-      (from_type->is_signed_integer_vector() && to_type->is_float_vector())) {
-    op = spv::Op::OpConvertSToF;
-  } else if ((from_type->Is<sem::U32>() && to_type->Is<sem::F32>()) ||
-             (from_type->is_unsigned_integer_vector() &&
-              to_type->is_float_vector())) {
-    op = spv::Op::OpConvertUToF;
-  } else if ((from_type->Is<sem::F32>() && to_type->Is<sem::I32>()) ||
-             (from_type->is_float_vector() &&
-              to_type->is_signed_integer_vector())) {
-    op = spv::Op::OpConvertFToS;
-  } else if ((from_type->Is<sem::F32>() && to_type->Is<sem::U32>()) ||
-             (from_type->is_float_vector() &&
-              to_type->is_unsigned_integer_vector())) {
-    op = spv::Op::OpConvertFToU;
-  } else if ((from_type->Is<sem::Bool>() && to_type->Is<sem::Bool>()) ||
-             (from_type->Is<sem::U32>() && to_type->Is<sem::U32>()) ||
-             (from_type->Is<sem::I32>() && to_type->Is<sem::I32>()) ||
-             (from_type->Is<sem::F32>() && to_type->Is<sem::F32>()) ||
-             (from_type->Is<sem::Vector>() && (from_type == to_type))) {
-    return val_id;
-  } else if ((from_type->Is<sem::I32>() && to_type->Is<sem::U32>()) ||
-             (from_type->Is<sem::U32>() && to_type->Is<sem::I32>()) ||
-             (from_type->is_signed_integer_vector() &&
-              to_type->is_unsigned_integer_vector()) ||
-             (from_type->is_unsigned_integer_vector() &&
-              to_type->is_integer_scalar_or_vector())) {
-    op = spv::Op::OpBitcast;
-  } else if ((from_type->is_numeric_scalar() && to_type->Is<sem::Bool>()) ||
-             (from_type->is_numeric_vector() && to_type->is_bool_vector())) {
-    // Convert scalar (vector) to bool (vector)
-
-    // Return the result of comparing from_expr with zero
-    uint32_t zero = GenerateConstantNullIfNeeded(from_type);
-    const auto* from_elem_type = elem_type_of(from_type);
-    op = from_elem_type->is_integer_scalar() ? spv::Op::OpINotEqual
-                                             : spv::Op::OpFUnordNotEqual;
-    if (!push_function_inst(
-            op, {Operand::Int(result_type_id), Operand::Int(result_id),
-                 Operand::Int(val_id), Operand::Int(zero)})) {
-      return 0;
+uint32_t Builder::GenerateCastOrCopyOrPassthrough(const sem::Type* to_type,
+                                                  const ast::Expression* from_expr,
+                                                  bool is_global_init) {
+    // This should not happen as we rely on constant folding to obviate
+    // casts/conversions for module-scope variables
+    if (is_global_init) {
+        TINT_ICE(Writer, builder_.Diagnostics())
+            << "Module-level conversions are not supported. Conversions should "
+               "have already been constant-folded by the FoldConstants transform.";
+        return 0;
     }
 
-    return result_id;
-  } else if (from_type->is_bool_scalar_or_vector() &&
-             to_type->is_numeric_scalar_or_vector()) {
-    // Convert bool scalar/vector to numeric scalar/vector.
-    // Use the bool to select between 1 (if true) and 0 (if false).
+    auto elem_type_of = [](const sem::Type* t) -> const sem::Type* {
+        if (t->is_scalar()) {
+            return t;
+        }
+        if (auto* v = t->As<sem::Vector>()) {
+            return v->type();
+        }
+        return nullptr;
+    };
 
-    const auto* to_elem_type = elem_type_of(to_type);
-    uint32_t one_id;
-    uint32_t zero_id;
-    if (to_elem_type->Is<sem::F32>()) {
-      ast::FloatLiteralExpression one(ProgramID(), Source{}, 1.0f);
-      ast::FloatLiteralExpression zero(ProgramID(), Source{}, 0.0f);
-      one_id = GenerateLiteralIfNeeded(nullptr, &one);
-      zero_id = GenerateLiteralIfNeeded(nullptr, &zero);
-    } else if (to_elem_type->Is<sem::U32>()) {
-      ast::UintLiteralExpression one(ProgramID(), Source{}, 1);
-      ast::UintLiteralExpression zero(ProgramID(), Source{}, 0);
-      one_id = GenerateLiteralIfNeeded(nullptr, &one);
-      zero_id = GenerateLiteralIfNeeded(nullptr, &zero);
-    } else if (to_elem_type->Is<sem::I32>()) {
-      ast::SintLiteralExpression one(ProgramID(), Source{}, 1);
-      ast::SintLiteralExpression zero(ProgramID(), Source{}, 0);
-      one_id = GenerateLiteralIfNeeded(nullptr, &one);
-      zero_id = GenerateLiteralIfNeeded(nullptr, &zero);
+    auto result = result_op();
+    auto result_id = std::get<uint32_t>(result);
+
+    auto result_type_id = GenerateTypeIfNeeded(to_type);
+    if (result_type_id == 0) {
+        return 0;
+    }
+
+    auto val_id = GenerateExpressionWithLoadIfNeeded(from_expr);
+    if (val_id == 0) {
+        return 0;
+    }
+
+    auto* from_type = TypeOf(from_expr)->UnwrapRef();
+
+    spv::Op op = spv::Op::OpNop;
+    if ((from_type->Is<sem::I32>() && to_type->Is<sem::F32>()) ||
+        (from_type->is_signed_integer_vector() && to_type->is_float_vector())) {
+        op = spv::Op::OpConvertSToF;
+    } else if ((from_type->Is<sem::U32>() && to_type->Is<sem::F32>()) ||
+               (from_type->is_unsigned_integer_vector() && to_type->is_float_vector())) {
+        op = spv::Op::OpConvertUToF;
+    } else if ((from_type->Is<sem::F32>() && to_type->Is<sem::I32>()) ||
+               (from_type->is_float_vector() && to_type->is_signed_integer_vector())) {
+        op = spv::Op::OpConvertFToS;
+    } else if ((from_type->Is<sem::F32>() && to_type->Is<sem::U32>()) ||
+               (from_type->is_float_vector() && to_type->is_unsigned_integer_vector())) {
+        op = spv::Op::OpConvertFToU;
+    } else if ((from_type->Is<sem::Bool>() && to_type->Is<sem::Bool>()) ||
+               (from_type->Is<sem::U32>() && to_type->Is<sem::U32>()) ||
+               (from_type->Is<sem::I32>() && to_type->Is<sem::I32>()) ||
+               (from_type->Is<sem::F32>() && to_type->Is<sem::F32>()) ||
+               (from_type->Is<sem::Vector>() && (from_type == to_type))) {
+        return val_id;
+    } else if ((from_type->Is<sem::I32>() && to_type->Is<sem::U32>()) ||
+               (from_type->Is<sem::U32>() && to_type->Is<sem::I32>()) ||
+               (from_type->is_signed_integer_vector() && to_type->is_unsigned_integer_vector()) ||
+               (from_type->is_unsigned_integer_vector() &&
+                to_type->is_integer_scalar_or_vector())) {
+        op = spv::Op::OpBitcast;
+    } else if ((from_type->is_numeric_scalar() && to_type->Is<sem::Bool>()) ||
+               (from_type->is_numeric_vector() && to_type->is_bool_vector())) {
+        // Convert scalar (vector) to bool (vector)
+
+        // Return the result of comparing from_expr with zero
+        uint32_t zero = GenerateConstantNullIfNeeded(from_type);
+        const auto* from_elem_type = elem_type_of(from_type);
+        op = from_elem_type->is_integer_scalar() ? spv::Op::OpINotEqual : spv::Op::OpFUnordNotEqual;
+        if (!push_function_inst(op, {Operand(result_type_id), Operand(result_id), Operand(val_id),
+                                     Operand(zero)})) {
+            return 0;
+        }
+
+        return result_id;
+    } else if (from_type->is_bool_scalar_or_vector() && to_type->is_numeric_scalar_or_vector()) {
+        // Convert bool scalar/vector to numeric scalar/vector.
+        // Use the bool to select between 1 (if true) and 0 (if false).
+
+        const auto* to_elem_type = elem_type_of(to_type);
+        uint32_t one_id;
+        uint32_t zero_id;
+        if (to_elem_type->Is<sem::F32>()) {
+            zero_id = GenerateConstantIfNeeded(ScalarConstant::F32(0));
+            one_id = GenerateConstantIfNeeded(ScalarConstant::F32(1));
+        } else if (to_elem_type->Is<sem::U32>()) {
+            zero_id = GenerateConstantIfNeeded(ScalarConstant::U32(0));
+            one_id = GenerateConstantIfNeeded(ScalarConstant::U32(1));
+        } else if (to_elem_type->Is<sem::I32>()) {
+            zero_id = GenerateConstantIfNeeded(ScalarConstant::I32(0));
+            one_id = GenerateConstantIfNeeded(ScalarConstant::I32(1));
+        } else {
+            error_ = "invalid destination type for bool conversion";
+            return false;
+        }
+        if (auto* to_vec = to_type->As<sem::Vector>()) {
+            // Splat the scalars into vectors.
+            zero_id = GenerateConstantVectorSplatIfNeeded(to_vec, zero_id);
+            one_id = GenerateConstantVectorSplatIfNeeded(to_vec, one_id);
+        }
+        if (!one_id || !zero_id) {
+            return false;
+        }
+
+        op = spv::Op::OpSelect;
+        if (!push_function_inst(op, {Operand(result_type_id), Operand(result_id), Operand(val_id),
+                                     Operand(one_id), Operand(zero_id)})) {
+            return 0;
+        }
+
+        return result_id;
     } else {
-      error_ = "invalid destination type for bool conversion";
-      return false;
-    }
-    if (auto* to_vec = to_type->As<sem::Vector>()) {
-      // Splat the scalars into vectors.
-      one_id = GenerateConstantVectorSplatIfNeeded(to_vec, one_id);
-      zero_id = GenerateConstantVectorSplatIfNeeded(to_vec, zero_id);
-    }
-    if (!one_id || !zero_id) {
-      return false;
+        TINT_ICE(Writer, builder_.Diagnostics()) << "Invalid from_type";
     }
 
-    op = spv::Op::OpSelect;
-    if (!push_function_inst(
-            op, {Operand::Int(result_type_id), Operand::Int(result_id),
-                 Operand::Int(val_id), Operand::Int(one_id),
-                 Operand::Int(zero_id)})) {
-      return 0;
+    if (op == spv::Op::OpNop) {
+        error_ = "unable to determine conversion type for cast, from: " +
+                 from_type->FriendlyName(builder_.Symbols()) +
+                 " to: " + to_type->FriendlyName(builder_.Symbols());
+        return 0;
+    }
+
+    if (!push_function_inst(op, {Operand(result_type_id), result, Operand(val_id)})) {
+        return 0;
     }
 
     return result_id;
-  } else {
-    TINT_ICE(Writer, builder_.Diagnostics()) << "Invalid from_type";
-  }
-
-  if (op == spv::Op::OpNop) {
-    error_ = "unable to determine conversion type for cast, from: " +
-             from_type->FriendlyName(builder_.Symbols()) +
-             " to: " + to_type->FriendlyName(builder_.Symbols());
-    return 0;
-  }
-
-  if (!push_function_inst(
-          op, {Operand::Int(result_type_id), result, Operand::Int(val_id)})) {
-    return 0;
-  }
-
-  return result_id;
 }
 
 uint32_t Builder::GenerateLiteralIfNeeded(const ast::Variable* var,
                                           const ast::LiteralExpression* lit) {
-  ScalarConstant constant;
+    ScalarConstant constant;
 
-  auto* global = builder_.Sem().Get<sem::GlobalVariable>(var);
-  if (global && global->IsOverridable()) {
-    constant.is_spec_op = true;
-    constant.constant_id = global->ConstantId();
-  }
+    auto* global = builder_.Sem().Get<sem::GlobalVariable>(var);
+    if (global && global->IsOverridable()) {
+        constant.is_spec_op = true;
+        constant.constant_id = global->ConstantId();
+    }
 
-  Switch(
-      lit,
-      [&](const ast::BoolLiteralExpression* l) {
-        constant.kind = ScalarConstant::Kind::kBool;
-        constant.value.b = l->value;
-      },
-      [&](const ast::SintLiteralExpression* sl) {
-        constant.kind = ScalarConstant::Kind::kI32;
-        constant.value.i32 = sl->value;
-      },
-      [&](const ast::UintLiteralExpression* ul) {
-        constant.kind = ScalarConstant::Kind::kU32;
-        constant.value.u32 = ul->value;
-      },
-      [&](const ast::FloatLiteralExpression* fl) {
-        constant.kind = ScalarConstant::Kind::kF32;
-        constant.value.f32 = fl->value;
-      },
-      [&](Default) { error_ = "unknown literal type"; });
+    Switch(
+        lit,
+        [&](const ast::BoolLiteralExpression* l) {
+            constant.kind = ScalarConstant::Kind::kBool;
+            constant.value.b = l->value;
+        },
+        [&](const ast::IntLiteralExpression* i) {
+            switch (i->suffix) {
+                case ast::IntLiteralExpression::Suffix::kNone:
+                case ast::IntLiteralExpression::Suffix::kI:
+                    constant.kind = ScalarConstant::Kind::kI32;
+                    constant.value.i32 = static_cast<int32_t>(i->value);
+                    return;
+                case ast::IntLiteralExpression::Suffix::kU:
+                    constant.kind = ScalarConstant::Kind::kU32;
+                    constant.value.u32 = static_cast<uint32_t>(i->value);
+                    return;
+            }
+        },
+        [&](const ast::FloatLiteralExpression* f) {
+            constant.kind = ScalarConstant::Kind::kF32;
+            constant.value.f32 = f->value;
+        },
+        [&](Default) { error_ = "unknown literal type"; });
 
-  if (!error_.empty()) {
-    return false;
-  }
+    if (!error_.empty()) {
+        return false;
+    }
 
-  return GenerateConstantIfNeeded(constant);
+    return GenerateConstantIfNeeded(constant);
 }
 
 uint32_t Builder::GenerateConstantIfNeeded(const ScalarConstant& constant) {
-  auto it = const_to_id_.find(constant);
-  if (it != const_to_id_.end()) {
-    return it->second;
-  }
+    auto it = const_to_id_.find(constant);
+    if (it != const_to_id_.end()) {
+        return it->second;
+    }
 
-  uint32_t type_id = 0;
+    uint32_t type_id = 0;
 
-  switch (constant.kind) {
-    case ScalarConstant::Kind::kU32: {
-      type_id = GenerateTypeIfNeeded(builder_.create<sem::U32>());
-      break;
+    switch (constant.kind) {
+        case ScalarConstant::Kind::kU32: {
+            type_id = GenerateTypeIfNeeded(builder_.create<sem::U32>());
+            break;
+        }
+        case ScalarConstant::Kind::kI32: {
+            type_id = GenerateTypeIfNeeded(builder_.create<sem::I32>());
+            break;
+        }
+        case ScalarConstant::Kind::kF32: {
+            type_id = GenerateTypeIfNeeded(builder_.create<sem::F32>());
+            break;
+        }
+        case ScalarConstant::Kind::kBool: {
+            type_id = GenerateTypeIfNeeded(builder_.create<sem::Bool>());
+            break;
+        }
     }
-    case ScalarConstant::Kind::kI32: {
-      type_id = GenerateTypeIfNeeded(builder_.create<sem::I32>());
-      break;
-    }
-    case ScalarConstant::Kind::kF32: {
-      type_id = GenerateTypeIfNeeded(builder_.create<sem::F32>());
-      break;
-    }
-    case ScalarConstant::Kind::kBool: {
-      type_id = GenerateTypeIfNeeded(builder_.create<sem::Bool>());
-      break;
-    }
-  }
 
-  if (type_id == 0) {
-    return 0;
-  }
-
-  auto result = result_op();
-  auto result_id = result.to_i();
-
-  if (constant.is_spec_op) {
-    push_annot(spv::Op::OpDecorate,
-               {Operand::Int(result_id), Operand::Int(SpvDecorationSpecId),
-                Operand::Int(constant.constant_id)});
-  }
-
-  switch (constant.kind) {
-    case ScalarConstant::Kind::kU32: {
-      push_type(
-          constant.is_spec_op ? spv::Op::OpSpecConstant : spv::Op::OpConstant,
-          {Operand::Int(type_id), result, Operand::Int(constant.value.u32)});
-      break;
+    if (type_id == 0) {
+        return 0;
     }
-    case ScalarConstant::Kind::kI32: {
-      push_type(
-          constant.is_spec_op ? spv::Op::OpSpecConstant : spv::Op::OpConstant,
-          {Operand::Int(type_id), result, Operand::Int(constant.value.i32)});
-      break;
-    }
-    case ScalarConstant::Kind::kF32: {
-      push_type(
-          constant.is_spec_op ? spv::Op::OpSpecConstant : spv::Op::OpConstant,
-          {Operand::Int(type_id), result, Operand::Float(constant.value.f32)});
-      break;
-    }
-    case ScalarConstant::Kind::kBool: {
-      if (constant.value.b) {
-        push_type(constant.is_spec_op ? spv::Op::OpSpecConstantTrue
-                                      : spv::Op::OpConstantTrue,
-                  {Operand::Int(type_id), result});
-      } else {
-        push_type(constant.is_spec_op ? spv::Op::OpSpecConstantFalse
-                                      : spv::Op::OpConstantFalse,
-                  {Operand::Int(type_id), result});
-      }
-      break;
-    }
-  }
 
-  const_to_id_[constant] = result_id;
-  return result_id;
+    auto result = result_op();
+    auto result_id = std::get<uint32_t>(result);
+
+    if (constant.is_spec_op) {
+        push_annot(spv::Op::OpDecorate, {Operand(result_id), U32Operand(SpvDecorationSpecId),
+                                         Operand(constant.constant_id)});
+    }
+
+    switch (constant.kind) {
+        case ScalarConstant::Kind::kU32: {
+            push_type(constant.is_spec_op ? spv::Op::OpSpecConstant : spv::Op::OpConstant,
+                      {Operand(type_id), result, Operand(constant.value.u32)});
+            break;
+        }
+        case ScalarConstant::Kind::kI32: {
+            push_type(constant.is_spec_op ? spv::Op::OpSpecConstant : spv::Op::OpConstant,
+                      {Operand(type_id), result, U32Operand(constant.value.i32)});
+            break;
+        }
+        case ScalarConstant::Kind::kF32: {
+            push_type(constant.is_spec_op ? spv::Op::OpSpecConstant : spv::Op::OpConstant,
+                      {Operand(type_id), result, Operand(constant.value.f32)});
+            break;
+        }
+        case ScalarConstant::Kind::kBool: {
+            if (constant.value.b) {
+                push_type(
+                    constant.is_spec_op ? spv::Op::OpSpecConstantTrue : spv::Op::OpConstantTrue,
+                    {Operand(type_id), result});
+            } else {
+                push_type(
+                    constant.is_spec_op ? spv::Op::OpSpecConstantFalse : spv::Op::OpConstantFalse,
+                    {Operand(type_id), result});
+            }
+            break;
+        }
+    }
+
+    const_to_id_[constant] = result_id;
+    return result_id;
 }
 
 uint32_t Builder::GenerateConstantNullIfNeeded(const sem::Type* type) {
-  auto type_id = GenerateTypeIfNeeded(type);
-  if (type_id == 0) {
-    return 0;
-  }
-
-  return utils::GetOrCreate(const_null_to_id_, type, [&] {
-    auto result = result_op();
-
-    push_type(spv::Op::OpConstantNull, {Operand::Int(type_id), result});
-
-    return result.to_i();
-  });
-}
-
-uint32_t Builder::GenerateConstantVectorSplatIfNeeded(const sem::Vector* type,
-                                                      uint32_t value_id) {
-  auto type_id = GenerateTypeIfNeeded(type);
-  if (type_id == 0 || value_id == 0) {
-    return 0;
-  }
-
-  uint64_t key = (static_cast<uint64_t>(type->Width()) << 32) + value_id;
-  return utils::GetOrCreate(const_splat_to_id_, key, [&] {
-    auto result = result_op();
-    auto result_id = result.to_i();
-
-    OperandList ops;
-    ops.push_back(Operand::Int(type_id));
-    ops.push_back(result);
-    for (uint32_t i = 0; i < type->Width(); i++) {
-      ops.push_back(Operand::Int(value_id));
+    auto type_id = GenerateTypeIfNeeded(type);
+    if (type_id == 0) {
+        return 0;
     }
-    push_type(spv::Op::OpConstantComposite, ops);
 
-    const_splat_to_id_[key] = result_id;
-    return result_id;
-  });
+    return utils::GetOrCreate(const_null_to_id_, type, [&] {
+        auto result = result_op();
+
+        push_type(spv::Op::OpConstantNull, {Operand(type_id), result});
+
+        return std::get<uint32_t>(result);
+    });
 }
 
-uint32_t Builder::GenerateShortCircuitBinaryExpression(
-    const ast::BinaryExpression* expr) {
-  auto lhs_id = GenerateExpressionWithLoadIfNeeded(expr->lhs);
-  if (lhs_id == 0) {
-    return false;
-  }
+uint32_t Builder::GenerateConstantVectorSplatIfNeeded(const sem::Vector* type, uint32_t value_id) {
+    auto type_id = GenerateTypeIfNeeded(type);
+    if (type_id == 0 || value_id == 0) {
+        return 0;
+    }
 
-  // Get the ID of the basic block where control flow will diverge. It's the
-  // last basic block generated for the left-hand-side of the operator.
-  auto original_label_id = current_label_id_;
+    uint64_t key = (static_cast<uint64_t>(type->Width()) << 32) + value_id;
+    return utils::GetOrCreate(const_splat_to_id_, key, [&] {
+        auto result = result_op();
+        auto result_id = std::get<uint32_t>(result);
 
-  auto type_id = GenerateTypeIfNeeded(TypeOf(expr));
-  if (type_id == 0) {
-    return 0;
-  }
+        OperandList ops;
+        ops.push_back(Operand(type_id));
+        ops.push_back(result);
+        for (uint32_t i = 0; i < type->Width(); i++) {
+            ops.push_back(Operand(value_id));
+        }
+        push_type(spv::Op::OpConstantComposite, ops);
 
-  auto merge_block = result_op();
-  auto merge_block_id = merge_block.to_i();
+        const_splat_to_id_[key] = result_id;
+        return result_id;
+    });
+}
 
-  auto block = result_op();
-  auto block_id = block.to_i();
+uint32_t Builder::GenerateShortCircuitBinaryExpression(const ast::BinaryExpression* expr) {
+    auto lhs_id = GenerateExpressionWithLoadIfNeeded(expr->lhs);
+    if (lhs_id == 0) {
+        return false;
+    }
 
-  auto true_block_id = block_id;
-  auto false_block_id = merge_block_id;
+    // Get the ID of the basic block where control flow will diverge. It's the
+    // last basic block generated for the left-hand-side of the operator.
+    auto original_label_id = current_label_id_;
 
-  // For a logical or we want to only check the RHS if the LHS is failed.
-  if (expr->IsLogicalOr()) {
-    std::swap(true_block_id, false_block_id);
-  }
+    auto type_id = GenerateTypeIfNeeded(TypeOf(expr));
+    if (type_id == 0) {
+        return 0;
+    }
 
-  if (!push_function_inst(spv::Op::OpSelectionMerge,
-                          {Operand::Int(merge_block_id),
-                           Operand::Int(SpvSelectionControlMaskNone)})) {
-    return 0;
-  }
-  if (!push_function_inst(spv::Op::OpBranchConditional,
-                          {Operand::Int(lhs_id), Operand::Int(true_block_id),
-                           Operand::Int(false_block_id)})) {
-    return 0;
-  }
+    auto merge_block = result_op();
+    auto merge_block_id = std::get<uint32_t>(merge_block);
 
-  // Output block to check the RHS
-  if (!GenerateLabel(block_id)) {
-    return 0;
-  }
-  auto rhs_id = GenerateExpressionWithLoadIfNeeded(expr->rhs);
-  if (rhs_id == 0) {
-    return 0;
-  }
+    auto block = result_op();
+    auto block_id = std::get<uint32_t>(block);
 
-  // Get the block ID of the last basic block generated for the right-hand-side
-  // expression. That block will be an immediate predecessor to the merge block.
-  auto rhs_block_id = current_label_id_;
-  if (!push_function_inst(spv::Op::OpBranch, {Operand::Int(merge_block_id)})) {
-    return 0;
-  }
+    auto true_block_id = block_id;
+    auto false_block_id = merge_block_id;
 
-  // Output the merge block
-  if (!GenerateLabel(merge_block_id)) {
-    return 0;
-  }
+    // For a logical or we want to only check the RHS if the LHS is failed.
+    if (expr->IsLogicalOr()) {
+        std::swap(true_block_id, false_block_id);
+    }
 
-  auto result = result_op();
-  auto result_id = result.to_i();
+    if (!push_function_inst(spv::Op::OpSelectionMerge,
+                            {Operand(merge_block_id), U32Operand(SpvSelectionControlMaskNone)})) {
+        return 0;
+    }
+    if (!push_function_inst(spv::Op::OpBranchConditional,
+                            {Operand(lhs_id), Operand(true_block_id), Operand(false_block_id)})) {
+        return 0;
+    }
 
-  if (!push_function_inst(spv::Op::OpPhi,
-                          {Operand::Int(type_id), result, Operand::Int(lhs_id),
-                           Operand::Int(original_label_id),
-                           Operand::Int(rhs_id), Operand::Int(rhs_block_id)})) {
-    return 0;
-  }
+    // Output block to check the RHS
+    if (!GenerateLabel(block_id)) {
+        return 0;
+    }
+    auto rhs_id = GenerateExpressionWithLoadIfNeeded(expr->rhs);
+    if (rhs_id == 0) {
+        return 0;
+    }
 
-  return result_id;
+    // Get the block ID of the last basic block generated for the right-hand-side
+    // expression. That block will be an immediate predecessor to the merge block.
+    auto rhs_block_id = current_label_id_;
+    if (!push_function_inst(spv::Op::OpBranch, {Operand(merge_block_id)})) {
+        return 0;
+    }
+
+    // Output the merge block
+    if (!GenerateLabel(merge_block_id)) {
+        return 0;
+    }
+
+    auto result = result_op();
+    auto result_id = std::get<uint32_t>(result);
+
+    if (!push_function_inst(spv::Op::OpPhi,
+                            {Operand(type_id), result, Operand(lhs_id), Operand(original_label_id),
+                             Operand(rhs_id), Operand(rhs_block_id)})) {
+        return 0;
+    }
+
+    return result_id;
 }
 
 uint32_t Builder::GenerateSplat(uint32_t scalar_id, const sem::Type* vec_type) {
-  // Create a new vector to splat scalar into
-  auto splat_vector = result_op();
-  auto* splat_vector_type = builder_.create<sem::Pointer>(
-      vec_type, ast::StorageClass::kFunction, ast::Access::kReadWrite);
-  push_function_var(
-      {Operand::Int(GenerateTypeIfNeeded(splat_vector_type)), splat_vector,
-       Operand::Int(ConvertStorageClass(ast::StorageClass::kFunction)),
-       Operand::Int(GenerateConstantNullIfNeeded(vec_type))});
+    // Create a new vector to splat scalar into
+    auto splat_vector = result_op();
+    auto* splat_vector_type = builder_.create<sem::Pointer>(vec_type, ast::StorageClass::kFunction,
+                                                            ast::Access::kReadWrite);
+    push_function_var({Operand(GenerateTypeIfNeeded(splat_vector_type)), splat_vector,
+                       U32Operand(ConvertStorageClass(ast::StorageClass::kFunction)),
+                       Operand(GenerateConstantNullIfNeeded(vec_type))});
 
-  // Splat scalar into vector
-  auto splat_result = result_op();
-  OperandList ops;
-  ops.push_back(Operand::Int(GenerateTypeIfNeeded(vec_type)));
-  ops.push_back(splat_result);
-  for (size_t i = 0; i < vec_type->As<sem::Vector>()->Width(); ++i) {
-    ops.push_back(Operand::Int(scalar_id));
-  }
-  if (!push_function_inst(spv::Op::OpCompositeConstruct, ops)) {
-    return 0;
-  }
+    // Splat scalar into vector
+    auto splat_result = result_op();
+    OperandList ops;
+    ops.push_back(Operand(GenerateTypeIfNeeded(vec_type)));
+    ops.push_back(splat_result);
+    for (size_t i = 0; i < vec_type->As<sem::Vector>()->Width(); ++i) {
+        ops.push_back(Operand(scalar_id));
+    }
+    if (!push_function_inst(spv::Op::OpCompositeConstruct, ops)) {
+        return 0;
+    }
 
-  return splat_result.to_i();
+    return std::get<uint32_t>(splat_result);
 }
 
 uint32_t Builder::GenerateMatrixAddOrSub(uint32_t lhs_id,
                                          uint32_t rhs_id,
                                          const sem::Matrix* type,
                                          spv::Op op) {
-  // Example addition of two matrices:
-  // %31 = OpLoad %mat3v4float %m34
-  // %32 = OpLoad %mat3v4float %m34
-  // %33 = OpCompositeExtract %v4float %31 0
-  // %34 = OpCompositeExtract %v4float %32 0
-  // %35 = OpFAdd %v4float %33 %34
-  // %36 = OpCompositeExtract %v4float %31 1
-  // %37 = OpCompositeExtract %v4float %32 1
-  // %38 = OpFAdd %v4float %36 %37
-  // %39 = OpCompositeExtract %v4float %31 2
-  // %40 = OpCompositeExtract %v4float %32 2
-  // %41 = OpFAdd %v4float %39 %40
-  // %42 = OpCompositeConstruct %mat3v4float %35 %38 %41
+    // Example addition of two matrices:
+    // %31 = OpLoad %mat3v4float %m34
+    // %32 = OpLoad %mat3v4float %m34
+    // %33 = OpCompositeExtract %v4float %31 0
+    // %34 = OpCompositeExtract %v4float %32 0
+    // %35 = OpFAdd %v4float %33 %34
+    // %36 = OpCompositeExtract %v4float %31 1
+    // %37 = OpCompositeExtract %v4float %32 1
+    // %38 = OpFAdd %v4float %36 %37
+    // %39 = OpCompositeExtract %v4float %31 2
+    // %40 = OpCompositeExtract %v4float %32 2
+    // %41 = OpFAdd %v4float %39 %40
+    // %42 = OpCompositeConstruct %mat3v4float %35 %38 %41
 
-  auto* column_type = builder_.create<sem::Vector>(type->type(), type->rows());
-  auto column_type_id = GenerateTypeIfNeeded(column_type);
+    auto* column_type = builder_.create<sem::Vector>(type->type(), type->rows());
+    auto column_type_id = GenerateTypeIfNeeded(column_type);
 
-  OperandList ops;
+    OperandList ops;
 
-  for (uint32_t i = 0; i < type->columns(); ++i) {
-    // Extract column `i` from lhs mat
-    auto lhs_column_id = result_op();
-    if (!push_function_inst(spv::Op::OpCompositeExtract,
-                            {Operand::Int(column_type_id), lhs_column_id,
-                             Operand::Int(lhs_id), Operand::Int(i)})) {
-      return 0;
+    for (uint32_t i = 0; i < type->columns(); ++i) {
+        // Extract column `i` from lhs mat
+        auto lhs_column_id = result_op();
+        if (!push_function_inst(
+                spv::Op::OpCompositeExtract,
+                {Operand(column_type_id), lhs_column_id, Operand(lhs_id), Operand(i)})) {
+            return 0;
+        }
+
+        // Extract column `i` from rhs mat
+        auto rhs_column_id = result_op();
+        if (!push_function_inst(
+                spv::Op::OpCompositeExtract,
+                {Operand(column_type_id), rhs_column_id, Operand(rhs_id), Operand(i)})) {
+            return 0;
+        }
+
+        // Add or subtract the two columns
+        auto result = result_op();
+        if (!push_function_inst(op,
+                                {Operand(column_type_id), result, lhs_column_id, rhs_column_id})) {
+            return 0;
+        }
+
+        ops.push_back(result);
     }
 
-    // Extract column `i` from rhs mat
-    auto rhs_column_id = result_op();
-    if (!push_function_inst(spv::Op::OpCompositeExtract,
-                            {Operand::Int(column_type_id), rhs_column_id,
-                             Operand::Int(rhs_id), Operand::Int(i)})) {
-      return 0;
+    // Create the result matrix from the added/subtracted column vectors
+    auto result_mat_id = result_op();
+    ops.insert(ops.begin(), result_mat_id);
+    ops.insert(ops.begin(), Operand(GenerateTypeIfNeeded(type)));
+    if (!push_function_inst(spv::Op::OpCompositeConstruct, ops)) {
+        return 0;
     }
 
-    // Add or subtract the two columns
-    auto result = result_op();
-    if (!push_function_inst(op, {Operand::Int(column_type_id), result,
-                                 lhs_column_id, rhs_column_id})) {
-      return 0;
-    }
-
-    ops.push_back(result);
-  }
-
-  // Create the result matrix from the added/subtracted column vectors
-  auto result_mat_id = result_op();
-  ops.insert(ops.begin(), result_mat_id);
-  ops.insert(ops.begin(), Operand::Int(GenerateTypeIfNeeded(type)));
-  if (!push_function_inst(spv::Op::OpCompositeConstruct, ops)) {
-    return 0;
-  }
-
-  return result_mat_id.to_i();
+    return std::get<uint32_t>(result_mat_id);
 }
 
 uint32_t Builder::GenerateBinaryExpression(const ast::BinaryExpression* expr) {
-  // There is special logic for short circuiting operators.
-  if (expr->IsLogicalAnd() || expr->IsLogicalOr()) {
-    return GenerateShortCircuitBinaryExpression(expr);
-  }
-
-  auto lhs_id = GenerateExpressionWithLoadIfNeeded(expr->lhs);
-  if (lhs_id == 0) {
-    return 0;
-  }
-
-  auto rhs_id = GenerateExpressionWithLoadIfNeeded(expr->rhs);
-  if (rhs_id == 0) {
-    return 0;
-  }
-
-  auto result = result_op();
-  auto result_id = result.to_i();
-
-  auto type_id = GenerateTypeIfNeeded(TypeOf(expr));
-  if (type_id == 0) {
-    return 0;
-  }
-
-  // Handle int and float and the vectors of those types. Other types
-  // should have been rejected by validation.
-  auto* lhs_type = TypeOf(expr->lhs)->UnwrapRef();
-  auto* rhs_type = TypeOf(expr->rhs)->UnwrapRef();
-
-  // Handle matrix-matrix addition and subtraction
-  if ((expr->IsAdd() || expr->IsSubtract()) && lhs_type->is_float_matrix() &&
-      rhs_type->is_float_matrix()) {
-    auto* lhs_mat = lhs_type->As<sem::Matrix>();
-    auto* rhs_mat = rhs_type->As<sem::Matrix>();
-
-    // This should already have been validated by resolver
-    if (lhs_mat->rows() != rhs_mat->rows() ||
-        lhs_mat->columns() != rhs_mat->columns()) {
-      error_ = "matrices must have same dimensionality for add or subtract";
-      return 0;
+    // There is special logic for short circuiting operators.
+    if (expr->IsLogicalAnd() || expr->IsLogicalOr()) {
+        return GenerateShortCircuitBinaryExpression(expr);
     }
 
-    return GenerateMatrixAddOrSub(
-        lhs_id, rhs_id, lhs_mat,
-        expr->IsAdd() ? spv::Op::OpFAdd : spv::Op::OpFSub);
-  }
-
-  // For vector-scalar arithmetic operations, splat scalar into a vector. We
-  // skip this for multiply as we can use OpVectorTimesScalar.
-  const bool is_float_scalar_vector_multiply =
-      expr->IsMultiply() &&
-      ((lhs_type->is_float_scalar() && rhs_type->is_float_vector()) ||
-       (lhs_type->is_float_vector() && rhs_type->is_float_scalar()));
-
-  if (expr->IsArithmetic() && !is_float_scalar_vector_multiply) {
-    if (lhs_type->Is<sem::Vector>() && rhs_type->is_numeric_scalar()) {
-      uint32_t splat_vector_id = GenerateSplat(rhs_id, lhs_type);
-      if (splat_vector_id == 0) {
+    auto lhs_id = GenerateExpressionWithLoadIfNeeded(expr->lhs);
+    if (lhs_id == 0) {
         return 0;
-      }
-      rhs_id = splat_vector_id;
-      rhs_type = lhs_type;
+    }
 
-    } else if (lhs_type->is_numeric_scalar() && rhs_type->Is<sem::Vector>()) {
-      uint32_t splat_vector_id = GenerateSplat(lhs_id, rhs_type);
-      if (splat_vector_id == 0) {
+    auto rhs_id = GenerateExpressionWithLoadIfNeeded(expr->rhs);
+    if (rhs_id == 0) {
         return 0;
-      }
-      lhs_id = splat_vector_id;
-      lhs_type = rhs_type;
     }
-  }
 
-  bool lhs_is_float_or_vec = lhs_type->is_float_scalar_or_vector();
-  bool lhs_is_bool_or_vec = lhs_type->is_bool_scalar_or_vector();
-  bool lhs_is_integer_or_vec = lhs_type->is_integer_scalar_or_vector();
-  bool lhs_is_unsigned = lhs_type->is_unsigned_scalar_or_vector();
+    auto result = result_op();
+    auto result_id = std::get<uint32_t>(result);
 
-  spv::Op op = spv::Op::OpNop;
-  if (expr->IsAnd()) {
-    if (lhs_is_integer_or_vec) {
-      op = spv::Op::OpBitwiseAnd;
-    } else if (lhs_is_bool_or_vec) {
-      op = spv::Op::OpLogicalAnd;
-    } else {
-      error_ = "invalid and expression";
-      return 0;
+    auto type_id = GenerateTypeIfNeeded(TypeOf(expr));
+    if (type_id == 0) {
+        return 0;
     }
-  } else if (expr->IsAdd()) {
-    op = lhs_is_float_or_vec ? spv::Op::OpFAdd : spv::Op::OpIAdd;
-  } else if (expr->IsDivide()) {
-    if (lhs_is_float_or_vec) {
-      op = spv::Op::OpFDiv;
-    } else if (lhs_is_unsigned) {
-      op = spv::Op::OpUDiv;
-    } else {
-      op = spv::Op::OpSDiv;
-    }
-  } else if (expr->IsEqual()) {
-    if (lhs_is_float_or_vec) {
-      op = spv::Op::OpFOrdEqual;
-    } else if (lhs_is_bool_or_vec) {
-      op = spv::Op::OpLogicalEqual;
-    } else if (lhs_is_integer_or_vec) {
-      op = spv::Op::OpIEqual;
-    } else {
-      error_ = "invalid equal expression";
-      return 0;
-    }
-  } else if (expr->IsGreaterThan()) {
-    if (lhs_is_float_or_vec) {
-      op = spv::Op::OpFOrdGreaterThan;
-    } else if (lhs_is_unsigned) {
-      op = spv::Op::OpUGreaterThan;
-    } else {
-      op = spv::Op::OpSGreaterThan;
-    }
-  } else if (expr->IsGreaterThanEqual()) {
-    if (lhs_is_float_or_vec) {
-      op = spv::Op::OpFOrdGreaterThanEqual;
-    } else if (lhs_is_unsigned) {
-      op = spv::Op::OpUGreaterThanEqual;
-    } else {
-      op = spv::Op::OpSGreaterThanEqual;
-    }
-  } else if (expr->IsLessThan()) {
-    if (lhs_is_float_or_vec) {
-      op = spv::Op::OpFOrdLessThan;
-    } else if (lhs_is_unsigned) {
-      op = spv::Op::OpULessThan;
-    } else {
-      op = spv::Op::OpSLessThan;
-    }
-  } else if (expr->IsLessThanEqual()) {
-    if (lhs_is_float_or_vec) {
-      op = spv::Op::OpFOrdLessThanEqual;
-    } else if (lhs_is_unsigned) {
-      op = spv::Op::OpULessThanEqual;
-    } else {
-      op = spv::Op::OpSLessThanEqual;
-    }
-  } else if (expr->IsModulo()) {
-    if (lhs_is_float_or_vec) {
-      op = spv::Op::OpFRem;
-    } else if (lhs_is_unsigned) {
-      op = spv::Op::OpUMod;
-    } else {
-      op = spv::Op::OpSMod;
-    }
-  } else if (expr->IsMultiply()) {
-    if (lhs_type->is_integer_scalar_or_vector()) {
-      // If the left hand side is an integer then this _has_ to be OpIMul as
-      // there there is no other integer multiplication.
-      op = spv::Op::OpIMul;
-    } else if (lhs_type->is_float_scalar() && rhs_type->is_float_scalar()) {
-      // Float scalars multiply with OpFMul
-      op = spv::Op::OpFMul;
-    } else if (lhs_type->is_float_vector() && rhs_type->is_float_vector()) {
-      // Float vectors must be validated to be the same size and then use OpFMul
-      op = spv::Op::OpFMul;
-    } else if (lhs_type->is_float_scalar() && rhs_type->is_float_vector()) {
-      // Scalar * Vector we need to flip lhs and rhs types
-      // because OpVectorTimesScalar expects <vector>, <scalar>
-      std::swap(lhs_id, rhs_id);
-      op = spv::Op::OpVectorTimesScalar;
-    } else if (lhs_type->is_float_vector() && rhs_type->is_float_scalar()) {
-      // float vector * scalar
-      op = spv::Op::OpVectorTimesScalar;
-    } else if (lhs_type->is_float_scalar() && rhs_type->is_float_matrix()) {
-      // Scalar * Matrix we need to flip lhs and rhs types because
-      // OpMatrixTimesScalar expects <matrix>, <scalar>
-      std::swap(lhs_id, rhs_id);
-      op = spv::Op::OpMatrixTimesScalar;
-    } else if (lhs_type->is_float_matrix() && rhs_type->is_float_scalar()) {
-      // float matrix * scalar
-      op = spv::Op::OpMatrixTimesScalar;
-    } else if (lhs_type->is_float_vector() && rhs_type->is_float_matrix()) {
-      // float vector * matrix
-      op = spv::Op::OpVectorTimesMatrix;
-    } else if (lhs_type->is_float_matrix() && rhs_type->is_float_vector()) {
-      // float matrix * vector
-      op = spv::Op::OpMatrixTimesVector;
-    } else if (lhs_type->is_float_matrix() && rhs_type->is_float_matrix()) {
-      // float matrix * matrix
-      op = spv::Op::OpMatrixTimesMatrix;
-    } else {
-      error_ = "invalid multiply expression";
-      return 0;
-    }
-  } else if (expr->IsNotEqual()) {
-    if (lhs_is_float_or_vec) {
-      op = spv::Op::OpFOrdNotEqual;
-    } else if (lhs_is_bool_or_vec) {
-      op = spv::Op::OpLogicalNotEqual;
-    } else if (lhs_is_integer_or_vec) {
-      op = spv::Op::OpINotEqual;
-    } else {
-      error_ = "invalid not-equal expression";
-      return 0;
-    }
-  } else if (expr->IsOr()) {
-    if (lhs_is_integer_or_vec) {
-      op = spv::Op::OpBitwiseOr;
-    } else if (lhs_is_bool_or_vec) {
-      op = spv::Op::OpLogicalOr;
-    } else {
-      error_ = "invalid and expression";
-      return 0;
-    }
-  } else if (expr->IsShiftLeft()) {
-    op = spv::Op::OpShiftLeftLogical;
-  } else if (expr->IsShiftRight() && lhs_type->is_signed_scalar_or_vector()) {
-    // A shift right with a signed LHS is an arithmetic shift.
-    op = spv::Op::OpShiftRightArithmetic;
-  } else if (expr->IsShiftRight()) {
-    op = spv::Op::OpShiftRightLogical;
-  } else if (expr->IsSubtract()) {
-    op = lhs_is_float_or_vec ? spv::Op::OpFSub : spv::Op::OpISub;
-  } else if (expr->IsXor()) {
-    op = spv::Op::OpBitwiseXor;
-  } else {
-    error_ = "unknown binary expression";
-    return 0;
-  }
 
-  if (!push_function_inst(op, {Operand::Int(type_id), result,
-                               Operand::Int(lhs_id), Operand::Int(rhs_id)})) {
-    return 0;
-  }
-  return result_id;
+    // Handle int and float and the vectors of those types. Other types
+    // should have been rejected by validation.
+    auto* lhs_type = TypeOf(expr->lhs)->UnwrapRef();
+    auto* rhs_type = TypeOf(expr->rhs)->UnwrapRef();
+
+    // Handle matrix-matrix addition and subtraction
+    if ((expr->IsAdd() || expr->IsSubtract()) && lhs_type->is_float_matrix() &&
+        rhs_type->is_float_matrix()) {
+        auto* lhs_mat = lhs_type->As<sem::Matrix>();
+        auto* rhs_mat = rhs_type->As<sem::Matrix>();
+
+        // This should already have been validated by resolver
+        if (lhs_mat->rows() != rhs_mat->rows() || lhs_mat->columns() != rhs_mat->columns()) {
+            error_ = "matrices must have same dimensionality for add or subtract";
+            return 0;
+        }
+
+        return GenerateMatrixAddOrSub(lhs_id, rhs_id, lhs_mat,
+                                      expr->IsAdd() ? spv::Op::OpFAdd : spv::Op::OpFSub);
+    }
+
+    // For vector-scalar arithmetic operations, splat scalar into a vector. We
+    // skip this for multiply as we can use OpVectorTimesScalar.
+    const bool is_float_scalar_vector_multiply =
+        expr->IsMultiply() && ((lhs_type->is_float_scalar() && rhs_type->is_float_vector()) ||
+                               (lhs_type->is_float_vector() && rhs_type->is_float_scalar()));
+
+    if (expr->IsArithmetic() && !is_float_scalar_vector_multiply) {
+        if (lhs_type->Is<sem::Vector>() && rhs_type->is_numeric_scalar()) {
+            uint32_t splat_vector_id = GenerateSplat(rhs_id, lhs_type);
+            if (splat_vector_id == 0) {
+                return 0;
+            }
+            rhs_id = splat_vector_id;
+            rhs_type = lhs_type;
+
+        } else if (lhs_type->is_numeric_scalar() && rhs_type->Is<sem::Vector>()) {
+            uint32_t splat_vector_id = GenerateSplat(lhs_id, rhs_type);
+            if (splat_vector_id == 0) {
+                return 0;
+            }
+            lhs_id = splat_vector_id;
+            lhs_type = rhs_type;
+        }
+    }
+
+    bool lhs_is_float_or_vec = lhs_type->is_float_scalar_or_vector();
+    bool lhs_is_bool_or_vec = lhs_type->is_bool_scalar_or_vector();
+    bool lhs_is_integer_or_vec = lhs_type->is_integer_scalar_or_vector();
+    bool lhs_is_unsigned = lhs_type->is_unsigned_scalar_or_vector();
+
+    spv::Op op = spv::Op::OpNop;
+    if (expr->IsAnd()) {
+        if (lhs_is_integer_or_vec) {
+            op = spv::Op::OpBitwiseAnd;
+        } else if (lhs_is_bool_or_vec) {
+            op = spv::Op::OpLogicalAnd;
+        } else {
+            error_ = "invalid and expression";
+            return 0;
+        }
+    } else if (expr->IsAdd()) {
+        op = lhs_is_float_or_vec ? spv::Op::OpFAdd : spv::Op::OpIAdd;
+    } else if (expr->IsDivide()) {
+        if (lhs_is_float_or_vec) {
+            op = spv::Op::OpFDiv;
+        } else if (lhs_is_unsigned) {
+            op = spv::Op::OpUDiv;
+        } else {
+            op = spv::Op::OpSDiv;
+        }
+    } else if (expr->IsEqual()) {
+        if (lhs_is_float_or_vec) {
+            op = spv::Op::OpFOrdEqual;
+        } else if (lhs_is_bool_or_vec) {
+            op = spv::Op::OpLogicalEqual;
+        } else if (lhs_is_integer_or_vec) {
+            op = spv::Op::OpIEqual;
+        } else {
+            error_ = "invalid equal expression";
+            return 0;
+        }
+    } else if (expr->IsGreaterThan()) {
+        if (lhs_is_float_or_vec) {
+            op = spv::Op::OpFOrdGreaterThan;
+        } else if (lhs_is_unsigned) {
+            op = spv::Op::OpUGreaterThan;
+        } else {
+            op = spv::Op::OpSGreaterThan;
+        }
+    } else if (expr->IsGreaterThanEqual()) {
+        if (lhs_is_float_or_vec) {
+            op = spv::Op::OpFOrdGreaterThanEqual;
+        } else if (lhs_is_unsigned) {
+            op = spv::Op::OpUGreaterThanEqual;
+        } else {
+            op = spv::Op::OpSGreaterThanEqual;
+        }
+    } else if (expr->IsLessThan()) {
+        if (lhs_is_float_or_vec) {
+            op = spv::Op::OpFOrdLessThan;
+        } else if (lhs_is_unsigned) {
+            op = spv::Op::OpULessThan;
+        } else {
+            op = spv::Op::OpSLessThan;
+        }
+    } else if (expr->IsLessThanEqual()) {
+        if (lhs_is_float_or_vec) {
+            op = spv::Op::OpFOrdLessThanEqual;
+        } else if (lhs_is_unsigned) {
+            op = spv::Op::OpULessThanEqual;
+        } else {
+            op = spv::Op::OpSLessThanEqual;
+        }
+    } else if (expr->IsModulo()) {
+        if (lhs_is_float_or_vec) {
+            op = spv::Op::OpFRem;
+        } else if (lhs_is_unsigned) {
+            op = spv::Op::OpUMod;
+        } else {
+            op = spv::Op::OpSMod;
+        }
+    } else if (expr->IsMultiply()) {
+        if (lhs_type->is_integer_scalar_or_vector()) {
+            // If the left hand side is an integer then this _has_ to be OpIMul as
+            // there there is no other integer multiplication.
+            op = spv::Op::OpIMul;
+        } else if (lhs_type->is_float_scalar() && rhs_type->is_float_scalar()) {
+            // Float scalars multiply with OpFMul
+            op = spv::Op::OpFMul;
+        } else if (lhs_type->is_float_vector() && rhs_type->is_float_vector()) {
+            // Float vectors must be validated to be the same size and then use OpFMul
+            op = spv::Op::OpFMul;
+        } else if (lhs_type->is_float_scalar() && rhs_type->is_float_vector()) {
+            // Scalar * Vector we need to flip lhs and rhs types
+            // because OpVectorTimesScalar expects <vector>, <scalar>
+            std::swap(lhs_id, rhs_id);
+            op = spv::Op::OpVectorTimesScalar;
+        } else if (lhs_type->is_float_vector() && rhs_type->is_float_scalar()) {
+            // float vector * scalar
+            op = spv::Op::OpVectorTimesScalar;
+        } else if (lhs_type->is_float_scalar() && rhs_type->is_float_matrix()) {
+            // Scalar * Matrix we need to flip lhs and rhs types because
+            // OpMatrixTimesScalar expects <matrix>, <scalar>
+            std::swap(lhs_id, rhs_id);
+            op = spv::Op::OpMatrixTimesScalar;
+        } else if (lhs_type->is_float_matrix() && rhs_type->is_float_scalar()) {
+            // float matrix * scalar
+            op = spv::Op::OpMatrixTimesScalar;
+        } else if (lhs_type->is_float_vector() && rhs_type->is_float_matrix()) {
+            // float vector * matrix
+            op = spv::Op::OpVectorTimesMatrix;
+        } else if (lhs_type->is_float_matrix() && rhs_type->is_float_vector()) {
+            // float matrix * vector
+            op = spv::Op::OpMatrixTimesVector;
+        } else if (lhs_type->is_float_matrix() && rhs_type->is_float_matrix()) {
+            // float matrix * matrix
+            op = spv::Op::OpMatrixTimesMatrix;
+        } else {
+            error_ = "invalid multiply expression";
+            return 0;
+        }
+    } else if (expr->IsNotEqual()) {
+        if (lhs_is_float_or_vec) {
+            op = spv::Op::OpFOrdNotEqual;
+        } else if (lhs_is_bool_or_vec) {
+            op = spv::Op::OpLogicalNotEqual;
+        } else if (lhs_is_integer_or_vec) {
+            op = spv::Op::OpINotEqual;
+        } else {
+            error_ = "invalid not-equal expression";
+            return 0;
+        }
+    } else if (expr->IsOr()) {
+        if (lhs_is_integer_or_vec) {
+            op = spv::Op::OpBitwiseOr;
+        } else if (lhs_is_bool_or_vec) {
+            op = spv::Op::OpLogicalOr;
+        } else {
+            error_ = "invalid and expression";
+            return 0;
+        }
+    } else if (expr->IsShiftLeft()) {
+        op = spv::Op::OpShiftLeftLogical;
+    } else if (expr->IsShiftRight() && lhs_type->is_signed_scalar_or_vector()) {
+        // A shift right with a signed LHS is an arithmetic shift.
+        op = spv::Op::OpShiftRightArithmetic;
+    } else if (expr->IsShiftRight()) {
+        op = spv::Op::OpShiftRightLogical;
+    } else if (expr->IsSubtract()) {
+        op = lhs_is_float_or_vec ? spv::Op::OpFSub : spv::Op::OpISub;
+    } else if (expr->IsXor()) {
+        op = spv::Op::OpBitwiseXor;
+    } else {
+        error_ = "unknown binary expression";
+        return 0;
+    }
+
+    if (!push_function_inst(op, {Operand(type_id), result, Operand(lhs_id), Operand(rhs_id)})) {
+        return 0;
+    }
+    return result_id;
 }
 
 bool Builder::GenerateBlockStatement(const ast::BlockStatement* stmt) {
-  scope_stack_.Push();
-  TINT_DEFER(scope_stack_.Pop());
-  return GenerateBlockStatementWithoutScoping(stmt);
+    PushScope();
+    TINT_DEFER(PopScope());
+    return GenerateBlockStatementWithoutScoping(stmt);
 }
 
-bool Builder::GenerateBlockStatementWithoutScoping(
-    const ast::BlockStatement* stmt) {
-  for (auto* block_stmt : stmt->statements) {
-    if (!GenerateStatement(block_stmt)) {
-      return false;
+bool Builder::GenerateBlockStatementWithoutScoping(const ast::BlockStatement* stmt) {
+    for (auto* block_stmt : stmt->statements) {
+        if (!GenerateStatement(block_stmt)) {
+            return false;
+        }
     }
-  }
-  return true;
+    return true;
 }
 
 uint32_t Builder::GenerateCallExpression(const ast::CallExpression* expr) {
-  auto* call = builder_.Sem().Get(expr);
-  auto* target = call->Target();
-  return Switch(
-      target,
-      [&](const sem::Function* func) {
-        return GenerateFunctionCall(call, func);
-      },
-      [&](const sem::Builtin* builtin) {
-        return GenerateBuiltinCall(call, builtin);
-      },
-      [&](const sem::TypeConversion*) {
-        return GenerateTypeConstructorOrConversion(call, nullptr);
-      },
-      [&](const sem::TypeConstructor*) {
-        return GenerateTypeConstructorOrConversion(call, nullptr);
-      },
-      [&](Default) {
-        TINT_ICE(Writer, builder_.Diagnostics())
-            << "unhandled call target: " << target->TypeInfo().name;
-        return 0;
-      });
-}
-
-uint32_t Builder::GenerateFunctionCall(const sem::Call* call,
-                                       const sem::Function*) {
-  auto* expr = call->Declaration();
-  auto* ident = expr->target.name;
-
-  auto type_id = GenerateTypeIfNeeded(call->Type());
-  if (type_id == 0) {
-    return 0;
-  }
-
-  auto result = result_op();
-  auto result_id = result.to_i();
-
-  OperandList ops = {Operand::Int(type_id), result};
-
-  auto func_id = func_symbol_to_id_[ident->symbol];
-  if (func_id == 0) {
-    error_ = "unable to find called function: " +
-             builder_.Symbols().NameFor(ident->symbol);
-    return 0;
-  }
-  ops.push_back(Operand::Int(func_id));
-
-  size_t arg_idx = 0;
-  for (auto* arg : expr->args) {
-    auto id = GenerateExpressionWithLoadIfNeeded(arg);
-    if (id == 0) {
-      return 0;
-    }
-    ops.push_back(Operand::Int(id));
-    arg_idx++;
-  }
-
-  if (!push_function_inst(spv::Op::OpFunctionCall, std::move(ops))) {
-    return 0;
-  }
-
-  return result_id;
-}
-
-uint32_t Builder::GenerateBuiltinCall(const sem::Call* call,
-                                      const sem::Builtin* builtin) {
-  auto result = result_op();
-  auto result_id = result.to_i();
-
-  auto result_type_id = GenerateTypeIfNeeded(builtin->ReturnType());
-  if (result_type_id == 0) {
-    return 0;
-  }
-
-  if (builtin->IsFineDerivative() || builtin->IsCoarseDerivative()) {
-    push_capability(SpvCapabilityDerivativeControl);
-  }
-
-  if (builtin->IsImageQuery()) {
-    push_capability(SpvCapabilityImageQuery);
-  }
-
-  if (builtin->IsTexture()) {
-    if (!GenerateTextureBuiltin(call, builtin, Operand::Int(result_type_id),
-                                result)) {
-      return 0;
-    }
-    return result_id;
-  }
-
-  if (builtin->IsBarrier()) {
-    if (!GenerateControlBarrierBuiltin(builtin)) {
-      return 0;
-    }
-    return result_id;
-  }
-
-  if (builtin->IsAtomic()) {
-    if (!GenerateAtomicBuiltin(call, builtin, Operand::Int(result_type_id),
-                               result)) {
-      return 0;
-    }
-    return result_id;
-  }
-
-  // Generates the SPIR-V ID for the expression for the indexed call argument,
-  // and loads it if necessary. Returns 0 on error.
-  auto get_arg_as_value_id = [&](size_t i,
-                                 bool generate_load = true) -> uint32_t {
-    auto* arg = call->Arguments()[i];
-    auto* param = builtin->Parameters()[i];
-    auto val_id = GenerateExpression(arg->Declaration());
-    if (val_id == 0) {
-      return 0;
-    }
-
-    if (generate_load && !param->Type()->Is<sem::Pointer>()) {
-      val_id = GenerateLoadIfNeeded(arg->Type(), val_id);
-    }
-    return val_id;
-  };
-
-  OperandList params = {Operand::Int(result_type_id), result};
-  spv::Op op = spv::Op::OpNop;
-
-  // Pushes the arguments for a GlslStd450 extended instruction, and sets op
-  // to OpExtInst.
-  auto glsl_std450 = [&](uint32_t inst_id) {
-    auto set_id = GetGLSLstd450Import();
-    params.push_back(Operand::Int(set_id));
-    params.push_back(Operand::Int(inst_id));
-    op = spv::Op::OpExtInst;
-  };
-
-  switch (builtin->Type()) {
-    case BuiltinType::kAny:
-      if (builtin->Parameters()[0]->Type()->Is<sem::Bool>()) {
-        // any(v: bool) just resolves to v.
-        return get_arg_as_value_id(0);
-      }
-      op = spv::Op::OpAny;
-      break;
-    case BuiltinType::kAll:
-      if (builtin->Parameters()[0]->Type()->Is<sem::Bool>()) {
-        // all(v: bool) just resolves to v.
-        return get_arg_as_value_id(0);
-      }
-      op = spv::Op::OpAll;
-      break;
-    case BuiltinType::kArrayLength: {
-      auto* address_of =
-          call->Arguments()[0]->Declaration()->As<ast::UnaryOpExpression>();
-      if (!address_of || address_of->op != ast::UnaryOp::kAddressOf) {
-        error_ = "arrayLength() expected pointer to member access, got " +
-                 std::string(address_of->TypeInfo().name);
-        return 0;
-      }
-      auto* array_expr = address_of->expr;
-
-      auto* accessor = array_expr->As<ast::MemberAccessorExpression>();
-      if (!accessor) {
-        error_ =
-            "arrayLength() expected pointer to member access, got pointer to " +
-            std::string(array_expr->TypeInfo().name);
-        return 0;
-      }
-
-      auto struct_id = GenerateExpression(accessor->structure);
-      if (struct_id == 0) {
-        return 0;
-      }
-      params.push_back(Operand::Int(struct_id));
-
-      auto* type = TypeOf(accessor->structure)->UnwrapRef();
-      if (!type->Is<sem::Struct>()) {
-        error_ = "invalid type (" + type->FriendlyName(builder_.Symbols()) +
-                 ") for runtime array length";
-        return 0;
-      }
-      // Runtime array must be the last member in the structure
-      params.push_back(Operand::Int(uint32_t(
-          type->As<sem::Struct>()->Declaration()->members.size() - 1)));
-
-      if (!push_function_inst(spv::Op::OpArrayLength, params)) {
-        return 0;
-      }
-      return result_id;
-    }
-    case BuiltinType::kCountOneBits:
-      op = spv::Op::OpBitCount;
-      break;
-    case BuiltinType::kDot: {
-      op = spv::Op::OpDot;
-      auto* vec_ty = builtin->Parameters()[0]->Type()->As<sem::Vector>();
-      if (vec_ty->type()->is_integer_scalar()) {
-        // TODO(crbug.com/tint/1267): OpDot requires floating-point types, but
-        // WGSL also supports integer types. SPV_KHR_integer_dot_product adds
-        // support for integer vectors. Use it if it is available.
-        auto el_ty = Operand::Int(GenerateTypeIfNeeded(vec_ty->type()));
-        auto vec_a = Operand::Int(get_arg_as_value_id(0));
-        auto vec_b = Operand::Int(get_arg_as_value_id(1));
-        if (vec_a.to_i() == 0 || vec_b.to_i() == 0) {
-          return 0;
-        }
-
-        auto sum = Operand::Int(0);
-        for (uint32_t i = 0; i < vec_ty->Width(); i++) {
-          auto a = result_op();
-          auto b = result_op();
-          auto mul = result_op();
-          if (!push_function_inst(spv::Op::OpCompositeExtract,
-                                  {el_ty, a, vec_a, Operand::Int(i)}) ||
-              !push_function_inst(spv::Op::OpCompositeExtract,
-                                  {el_ty, b, vec_b, Operand::Int(i)}) ||
-              !push_function_inst(spv::Op::OpIMul, {el_ty, mul, a, b})) {
+    auto* call = builder_.Sem().Get(expr);
+    auto* target = call->Target();
+    return Switch(
+        target, [&](const sem::Function* func) { return GenerateFunctionCall(call, func); },
+        [&](const sem::Builtin* builtin) { return GenerateBuiltinCall(call, builtin); },
+        [&](const sem::TypeConversion*) {
+            return GenerateTypeConstructorOrConversion(call, nullptr);
+        },
+        [&](const sem::TypeConstructor*) {
+            return GenerateTypeConstructorOrConversion(call, nullptr);
+        },
+        [&](Default) {
+            TINT_ICE(Writer, builder_.Diagnostics())
+                << "unhandled call target: " << target->TypeInfo().name;
             return 0;
-          }
-          if (i == 0) {
-            sum = mul;
-          } else {
-            auto prev_sum = sum;
-            auto is_last_el = i == (vec_ty->Width() - 1);
-            sum = is_last_el ? Operand::Int(result_id) : result_op();
-            if (!push_function_inst(spv::Op::OpIAdd,
-                                    {el_ty, sum, prev_sum, mul})) {
-              return 0;
-            }
-          }
+        });
+}
+
+uint32_t Builder::GenerateFunctionCall(const sem::Call* call, const sem::Function*) {
+    auto* expr = call->Declaration();
+    auto* ident = expr->target.name;
+
+    auto type_id = GenerateTypeIfNeeded(call->Type());
+    if (type_id == 0) {
+        return 0;
+    }
+
+    auto result = result_op();
+    auto result_id = std::get<uint32_t>(result);
+
+    OperandList ops = {Operand(type_id), result};
+
+    auto func_id = func_symbol_to_id_[ident->symbol];
+    if (func_id == 0) {
+        error_ = "unable to find called function: " + builder_.Symbols().NameFor(ident->symbol);
+        return 0;
+    }
+    ops.push_back(Operand(func_id));
+
+    for (auto* arg : expr->args) {
+        auto id = GenerateExpressionWithLoadIfNeeded(arg);
+        if (id == 0) {
+            return 0;
+        }
+        ops.push_back(Operand(id));
+    }
+
+    if (!push_function_inst(spv::Op::OpFunctionCall, std::move(ops))) {
+        return 0;
+    }
+
+    return result_id;
+}
+
+uint32_t Builder::GenerateBuiltinCall(const sem::Call* call, const sem::Builtin* builtin) {
+    auto result = result_op();
+    auto result_id = std::get<uint32_t>(result);
+
+    auto result_type_id = GenerateTypeIfNeeded(builtin->ReturnType());
+    if (result_type_id == 0) {
+        return 0;
+    }
+
+    if (builtin->IsFineDerivative() || builtin->IsCoarseDerivative()) {
+        push_capability(SpvCapabilityDerivativeControl);
+    }
+
+    if (builtin->IsImageQuery()) {
+        push_capability(SpvCapabilityImageQuery);
+    }
+
+    if (builtin->IsTexture()) {
+        if (!GenerateTextureBuiltin(call, builtin, Operand(result_type_id), result)) {
+            return 0;
         }
         return result_id;
-      }
-      break;
     }
-    case BuiltinType::kDpdx:
-      op = spv::Op::OpDPdx;
-      break;
-    case BuiltinType::kDpdxCoarse:
-      op = spv::Op::OpDPdxCoarse;
-      break;
-    case BuiltinType::kDpdxFine:
-      op = spv::Op::OpDPdxFine;
-      break;
-    case BuiltinType::kDpdy:
-      op = spv::Op::OpDPdy;
-      break;
-    case BuiltinType::kDpdyCoarse:
-      op = spv::Op::OpDPdyCoarse;
-      break;
-    case BuiltinType::kDpdyFine:
-      op = spv::Op::OpDPdyFine;
-      break;
-    case BuiltinType::kExtractBits:
-      op = builtin->Parameters()[0]->Type()->is_unsigned_scalar_or_vector()
-               ? spv::Op::OpBitFieldUExtract
-               : spv::Op::OpBitFieldSExtract;
-      break;
-    case BuiltinType::kFwidth:
-      op = spv::Op::OpFwidth;
-      break;
-    case BuiltinType::kFwidthCoarse:
-      op = spv::Op::OpFwidthCoarse;
-      break;
-    case BuiltinType::kFwidthFine:
-      op = spv::Op::OpFwidthFine;
-      break;
-    case BuiltinType::kInsertBits:
-      op = spv::Op::OpBitFieldInsert;
-      break;
-    case BuiltinType::kMix: {
-      auto std450 = Operand::Int(GetGLSLstd450Import());
 
-      auto a_id = get_arg_as_value_id(0);
-      auto b_id = get_arg_as_value_id(1);
-      auto f_id = get_arg_as_value_id(2);
-      if (!a_id || !b_id || !f_id) {
-        return 0;
-      }
-
-      // If the interpolant is scalar but the objects are vectors, we need to
-      // splat the interpolant into a vector of the same size.
-      auto* result_vector_type = builtin->ReturnType()->As<sem::Vector>();
-      if (result_vector_type && builtin->Parameters()[2]->Type()->is_scalar()) {
-        f_id = GenerateSplat(f_id, builtin->Parameters()[0]->Type());
-        if (f_id == 0) {
-          return 0;
+    if (builtin->IsBarrier()) {
+        if (!GenerateControlBarrierBuiltin(builtin)) {
+            return 0;
         }
-      }
-
-      if (!push_function_inst(spv::Op::OpExtInst,
-                              {Operand::Int(result_type_id), result, std450,
-                               Operand::Int(GLSLstd450FMix), Operand::Int(a_id),
-                               Operand::Int(b_id), Operand::Int(f_id)})) {
-        return 0;
-      }
-      return result_id;
+        return result_id;
     }
-    case BuiltinType::kReverseBits:
-      op = spv::Op::OpBitReverse;
-      break;
-    case BuiltinType::kSelect: {
-      // Note: Argument order is different in WGSL and SPIR-V
-      auto cond_id = get_arg_as_value_id(2);
-      auto true_id = get_arg_as_value_id(1);
-      auto false_id = get_arg_as_value_id(0);
-      if (!cond_id || !true_id || !false_id) {
-        return 0;
-      }
 
-      // If the condition is scalar but the objects are vectors, we need to
-      // splat the condition into a vector of the same size.
-      // TODO(jrprice): If we're targeting SPIR-V 1.4, we don't need to do this.
-      auto* result_vector_type = builtin->ReturnType()->As<sem::Vector>();
-      if (result_vector_type && builtin->Parameters()[2]->Type()->is_scalar()) {
-        auto* bool_vec_ty = builder_.create<sem::Vector>(
-            builder_.create<sem::Bool>(), result_vector_type->Width());
-        if (!GenerateTypeIfNeeded(bool_vec_ty)) {
-          return 0;
+    if (builtin->IsAtomic()) {
+        if (!GenerateAtomicBuiltin(call, builtin, Operand(result_type_id), result)) {
+            return 0;
         }
-        cond_id = GenerateSplat(cond_id, bool_vec_ty);
-        if (cond_id == 0) {
-          return 0;
+        return result_id;
+    }
+
+    // Generates the SPIR-V ID for the expression for the indexed call argument,
+    // and loads it if necessary. Returns 0 on error.
+    auto get_arg_as_value_id = [&](size_t i, bool generate_load = true) -> uint32_t {
+        auto* arg = call->Arguments()[i];
+        auto* param = builtin->Parameters()[i];
+        auto val_id = GenerateExpression(arg->Declaration());
+        if (val_id == 0) {
+            return 0;
         }
-      }
 
-      if (!push_function_inst(
-              spv::Op::OpSelect,
-              {Operand::Int(result_type_id), result, Operand::Int(cond_id),
-               Operand::Int(true_id), Operand::Int(false_id)})) {
+        if (generate_load && !param->Type()->Is<sem::Pointer>()) {
+            val_id = GenerateLoadIfNeeded(arg->Type(), val_id);
+        }
+        return val_id;
+    };
+
+    OperandList params = {Operand(result_type_id), result};
+    spv::Op op = spv::Op::OpNop;
+
+    // Pushes the arguments for a GlslStd450 extended instruction, and sets op
+    // to OpExtInst.
+    auto glsl_std450 = [&](uint32_t inst_id) {
+        auto set_id = GetGLSLstd450Import();
+        params.push_back(Operand(set_id));
+        params.push_back(Operand(inst_id));
+        op = spv::Op::OpExtInst;
+    };
+
+    switch (builtin->Type()) {
+        case BuiltinType::kAny:
+            if (builtin->Parameters()[0]->Type()->Is<sem::Bool>()) {
+                // any(v: bool) just resolves to v.
+                return get_arg_as_value_id(0);
+            }
+            op = spv::Op::OpAny;
+            break;
+        case BuiltinType::kAll:
+            if (builtin->Parameters()[0]->Type()->Is<sem::Bool>()) {
+                // all(v: bool) just resolves to v.
+                return get_arg_as_value_id(0);
+            }
+            op = spv::Op::OpAll;
+            break;
+        case BuiltinType::kArrayLength: {
+            auto* address_of = call->Arguments()[0]->Declaration()->As<ast::UnaryOpExpression>();
+            if (!address_of || address_of->op != ast::UnaryOp::kAddressOf) {
+                error_ = "arrayLength() expected pointer to member access, got " +
+                         std::string(address_of->TypeInfo().name);
+                return 0;
+            }
+            auto* array_expr = address_of->expr;
+
+            auto* accessor = array_expr->As<ast::MemberAccessorExpression>();
+            if (!accessor) {
+                error_ = "arrayLength() expected pointer to member access, got pointer to " +
+                         std::string(array_expr->TypeInfo().name);
+                return 0;
+            }
+
+            auto struct_id = GenerateExpression(accessor->structure);
+            if (struct_id == 0) {
+                return 0;
+            }
+            params.push_back(Operand(struct_id));
+
+            auto* type = TypeOf(accessor->structure)->UnwrapRef();
+            if (!type->Is<sem::Struct>()) {
+                error_ = "invalid type (" + type->FriendlyName(builder_.Symbols()) +
+                         ") for runtime array length";
+                return 0;
+            }
+            // Runtime array must be the last member in the structure
+            params.push_back(
+                Operand(uint32_t(type->As<sem::Struct>()->Declaration()->members.size() - 1)));
+
+            if (!push_function_inst(spv::Op::OpArrayLength, params)) {
+                return 0;
+            }
+            return result_id;
+        }
+        case BuiltinType::kCountOneBits:
+            op = spv::Op::OpBitCount;
+            break;
+        case BuiltinType::kDot: {
+            op = spv::Op::OpDot;
+            auto* vec_ty = builtin->Parameters()[0]->Type()->As<sem::Vector>();
+            if (vec_ty->type()->is_integer_scalar()) {
+                // TODO(crbug.com/tint/1267): OpDot requires floating-point types, but
+                // WGSL also supports integer types. SPV_KHR_integer_dot_product adds
+                // support for integer vectors. Use it if it is available.
+                auto el_ty = Operand(GenerateTypeIfNeeded(vec_ty->type()));
+                auto vec_a = Operand(get_arg_as_value_id(0));
+                auto vec_b = Operand(get_arg_as_value_id(1));
+                if (std::get<uint32_t>(vec_a) == 0 || std::get<uint32_t>(vec_b) == 0) {
+                    return 0;
+                }
+
+                auto sum = Operand(0u);
+                for (uint32_t i = 0; i < vec_ty->Width(); i++) {
+                    auto a = result_op();
+                    auto b = result_op();
+                    auto mul = result_op();
+                    if (!push_function_inst(spv::Op::OpCompositeExtract,
+                                            {el_ty, a, vec_a, Operand(i)}) ||
+                        !push_function_inst(spv::Op::OpCompositeExtract,
+                                            {el_ty, b, vec_b, Operand(i)}) ||
+                        !push_function_inst(spv::Op::OpIMul, {el_ty, mul, a, b})) {
+                        return 0;
+                    }
+                    if (i == 0) {
+                        sum = mul;
+                    } else {
+                        auto prev_sum = sum;
+                        auto is_last_el = i == (vec_ty->Width() - 1);
+                        sum = is_last_el ? Operand(result_id) : result_op();
+                        if (!push_function_inst(spv::Op::OpIAdd, {el_ty, sum, prev_sum, mul})) {
+                            return 0;
+                        }
+                    }
+                }
+                return result_id;
+            }
+            break;
+        }
+        case BuiltinType::kDpdx:
+            op = spv::Op::OpDPdx;
+            break;
+        case BuiltinType::kDpdxCoarse:
+            op = spv::Op::OpDPdxCoarse;
+            break;
+        case BuiltinType::kDpdxFine:
+            op = spv::Op::OpDPdxFine;
+            break;
+        case BuiltinType::kDpdy:
+            op = spv::Op::OpDPdy;
+            break;
+        case BuiltinType::kDpdyCoarse:
+            op = spv::Op::OpDPdyCoarse;
+            break;
+        case BuiltinType::kDpdyFine:
+            op = spv::Op::OpDPdyFine;
+            break;
+        case BuiltinType::kExtractBits:
+            op = builtin->Parameters()[0]->Type()->is_unsigned_scalar_or_vector()
+                     ? spv::Op::OpBitFieldUExtract
+                     : spv::Op::OpBitFieldSExtract;
+            break;
+        case BuiltinType::kFwidth:
+            op = spv::Op::OpFwidth;
+            break;
+        case BuiltinType::kFwidthCoarse:
+            op = spv::Op::OpFwidthCoarse;
+            break;
+        case BuiltinType::kFwidthFine:
+            op = spv::Op::OpFwidthFine;
+            break;
+        case BuiltinType::kInsertBits:
+            op = spv::Op::OpBitFieldInsert;
+            break;
+        case BuiltinType::kMix: {
+            auto std450 = Operand(GetGLSLstd450Import());
+
+            auto a_id = get_arg_as_value_id(0);
+            auto b_id = get_arg_as_value_id(1);
+            auto f_id = get_arg_as_value_id(2);
+            if (!a_id || !b_id || !f_id) {
+                return 0;
+            }
+
+            // If the interpolant is scalar but the objects are vectors, we need to
+            // splat the interpolant into a vector of the same size.
+            auto* result_vector_type = builtin->ReturnType()->As<sem::Vector>();
+            if (result_vector_type && builtin->Parameters()[2]->Type()->is_scalar()) {
+                f_id = GenerateSplat(f_id, builtin->Parameters()[0]->Type());
+                if (f_id == 0) {
+                    return 0;
+                }
+            }
+
+            if (!push_function_inst(spv::Op::OpExtInst, {Operand(result_type_id), result, std450,
+                                                         U32Operand(GLSLstd450FMix), Operand(a_id),
+                                                         Operand(b_id), Operand(f_id)})) {
+                return 0;
+            }
+            return result_id;
+        }
+        case BuiltinType::kReverseBits:
+            op = spv::Op::OpBitReverse;
+            break;
+        case BuiltinType::kSelect: {
+            // Note: Argument order is different in WGSL and SPIR-V
+            auto cond_id = get_arg_as_value_id(2);
+            auto true_id = get_arg_as_value_id(1);
+            auto false_id = get_arg_as_value_id(0);
+            if (!cond_id || !true_id || !false_id) {
+                return 0;
+            }
+
+            // If the condition is scalar but the objects are vectors, we need to
+            // splat the condition into a vector of the same size.
+            // TODO(jrprice): If we're targeting SPIR-V 1.4, we don't need to do this.
+            auto* result_vector_type = builtin->ReturnType()->As<sem::Vector>();
+            if (result_vector_type && builtin->Parameters()[2]->Type()->is_scalar()) {
+                auto* bool_vec_ty = builder_.create<sem::Vector>(builder_.create<sem::Bool>(),
+                                                                 result_vector_type->Width());
+                if (!GenerateTypeIfNeeded(bool_vec_ty)) {
+                    return 0;
+                }
+                cond_id = GenerateSplat(cond_id, bool_vec_ty);
+                if (cond_id == 0) {
+                    return 0;
+                }
+            }
+
+            if (!push_function_inst(spv::Op::OpSelect,
+                                    {Operand(result_type_id), result, Operand(cond_id),
+                                     Operand(true_id), Operand(false_id)})) {
+                return 0;
+            }
+            return result_id;
+        }
+        case BuiltinType::kTranspose:
+            op = spv::Op::OpTranspose;
+            break;
+        case BuiltinType::kAbs:
+            if (builtin->ReturnType()->is_unsigned_scalar_or_vector()) {
+                // abs() only operates on *signed* integers.
+                // This is a no-op for unsigned integers.
+                return get_arg_as_value_id(0);
+            }
+            if (builtin->ReturnType()->is_float_scalar_or_vector()) {
+                glsl_std450(GLSLstd450FAbs);
+            } else {
+                glsl_std450(GLSLstd450SAbs);
+            }
+            break;
+        default: {
+            auto inst_id = builtin_to_glsl_method(builtin);
+            if (inst_id == 0) {
+                error_ = "unknown method " + std::string(builtin->str());
+                return 0;
+            }
+            glsl_std450(inst_id);
+            break;
+        }
+    }
+
+    if (op == spv::Op::OpNop) {
+        error_ = "unable to determine operator for: " + std::string(builtin->str());
         return 0;
-      }
-      return result_id;
     }
-    case BuiltinType::kTranspose:
-      op = spv::Op::OpTranspose;
-      break;
-    case BuiltinType::kAbs:
-      if (builtin->ReturnType()->is_unsigned_scalar_or_vector()) {
-        // abs() only operates on *signed* integers.
-        // This is a no-op for unsigned integers.
-        return get_arg_as_value_id(0);
-      }
-      if (builtin->ReturnType()->is_float_scalar_or_vector()) {
-        glsl_std450(GLSLstd450FAbs);
-      } else {
-        glsl_std450(GLSLstd450SAbs);
-      }
-      break;
-    default: {
-      auto inst_id = builtin_to_glsl_method(builtin);
-      if (inst_id == 0) {
-        error_ = "unknown method " + std::string(builtin->str());
+
+    for (size_t i = 0; i < call->Arguments().size(); i++) {
+        if (auto val_id = get_arg_as_value_id(i)) {
+            params.emplace_back(Operand(val_id));
+        } else {
+            return 0;
+        }
+    }
+
+    if (!push_function_inst(op, params)) {
         return 0;
-      }
-      glsl_std450(inst_id);
-      break;
     }
-  }
 
-  if (op == spv::Op::OpNop) {
-    error_ = "unable to determine operator for: " + std::string(builtin->str());
-    return 0;
-  }
-
-  for (size_t i = 0; i < call->Arguments().size(); i++) {
-    if (auto val_id = get_arg_as_value_id(i)) {
-      params.emplace_back(Operand::Int(val_id));
-    } else {
-      return 0;
-    }
-  }
-
-  if (!push_function_inst(op, params)) {
-    return 0;
-  }
-
-  return result_id;
+    return result_id;
 }
 
 bool Builder::GenerateTextureBuiltin(const sem::Call* call,
                                      const sem::Builtin* builtin,
                                      Operand result_type,
                                      Operand result_id) {
-  using Usage = sem::ParameterUsage;
+    using Usage = sem::ParameterUsage;
 
-  auto& signature = builtin->Signature();
-  auto& arguments = call->Arguments();
+    auto& signature = builtin->Signature();
+    auto& arguments = call->Arguments();
 
-  // Generates the given expression, returning the operand ID
-  auto gen = [&](const sem::Expression* expr) {
-    const auto val_id = GenerateExpressionWithLoadIfNeeded(expr);
-    return Operand::Int(val_id);
-  };
+    // Generates the given expression, returning the operand ID
+    auto gen = [&](const sem::Expression* expr) {
+        const auto val_id = GenerateExpressionWithLoadIfNeeded(expr);
+        return Operand(val_id);
+    };
 
-  // Returns the argument with the given usage
-  auto arg = [&](Usage usage) {
-    int idx = signature.IndexOf(usage);
-    return (idx >= 0) ? arguments[idx] : nullptr;
-  };
+    // Returns the argument with the given usage
+    auto arg = [&](Usage usage) {
+        int idx = signature.IndexOf(usage);
+        return (idx >= 0) ? arguments[idx] : nullptr;
+    };
 
-  // Generates the argument with the given usage, returning the operand ID
-  auto gen_arg = [&](Usage usage) {
-    auto* argument = arg(usage);
-    if (!argument) {
-      TINT_ICE(Writer, builder_.Diagnostics())
-          << "missing argument " << static_cast<int>(usage);
-    }
-    return gen(argument);
-  };
+    // Generates the argument with the given usage, returning the operand ID
+    auto gen_arg = [&](Usage usage) {
+        auto* argument = arg(usage);
+        if (!argument) {
+            TINT_ICE(Writer, builder_.Diagnostics())
+                << "missing argument " << static_cast<int>(usage);
+        }
+        return gen(argument);
+    };
 
-  auto* texture = arg(Usage::kTexture);
-  if (!texture) {
-    TINT_ICE(Writer, builder_.Diagnostics()) << "missing texture argument";
-  }
-
-  auto* texture_type = texture->Type()->UnwrapRef()->As<sem::Texture>();
-
-  auto op = spv::Op::OpNop;
-
-  // Custom function to call after the texture-builtin op has been generated.
-  std::function<bool()> post_emission = [] { return true; };
-
-  // Populate the spirv_params with common parameters
-  OperandList spirv_params;
-  spirv_params.reserve(8);  // Enough to fit most parameter lists
-
-  // Extra image operands, appended to spirv_params.
-  struct ImageOperand {
-    SpvImageOperandsMask mask;
-    Operand operand;
-  };
-  std::vector<ImageOperand> image_operands;
-  image_operands.reserve(4);  // Enough to fit most parameter lists
-
-  // Appends `result_type` and `result_id` to `spirv_params`
-  auto append_result_type_and_id_to_spirv_params = [&]() {
-    spirv_params.emplace_back(std::move(result_type));
-    spirv_params.emplace_back(std::move(result_id));
-  };
-
-  // Appends a result type and id to `spirv_params`, possibly adding a
-  // post_emission step.
-  //
-  // If the texture is a depth texture, then this function wraps the result of
-  // the op with a OpCompositeExtract to evaluate to the first element of the
-  // returned vector. This is done as the WGSL texture reading functions for
-  // depths return a single float scalar instead of a vector.
-  //
-  // If the texture is not a depth texture, then this function simply delegates
-  // to calling append_result_type_and_id_to_spirv_params().
-  auto append_result_type_and_id_to_spirv_params_for_read = [&]() {
-    if (texture_type
-            ->IsAnyOf<sem::DepthTexture, sem::DepthMultisampledTexture>()) {
-      auto* f32 = builder_.create<sem::F32>();
-      auto* spirv_result_type = builder_.create<sem::Vector>(f32, 4u);
-      auto spirv_result = result_op();
-      post_emission = [=] {
-        return push_function_inst(
-            spv::Op::OpCompositeExtract,
-            {result_type, result_id, spirv_result, Operand::Int(0)});
-      };
-      auto spirv_result_type_id = GenerateTypeIfNeeded(spirv_result_type);
-      if (spirv_result_type_id == 0) {
-        return false;
-      }
-      spirv_params.emplace_back(Operand::Int(spirv_result_type_id));
-      spirv_params.emplace_back(spirv_result);
-      return true;
+    auto* texture = arg(Usage::kTexture);
+    if (!texture) {
+        TINT_ICE(Writer, builder_.Diagnostics()) << "missing texture argument";
     }
 
-    append_result_type_and_id_to_spirv_params();
-    return true;
-  };
+    auto* texture_type = texture->Type()->UnwrapRef()->As<sem::Texture>();
 
-  // Appends a result type and id to `spirv_params`, by first swizzling the
-  // result of the op with `swizzle`.
-  auto append_result_type_and_id_to_spirv_params_swizzled =
-      [&](uint32_t spirv_result_width, std::vector<uint32_t> swizzle) {
+    auto op = spv::Op::OpNop;
+
+    // Custom function to call after the texture-builtin op has been generated.
+    std::function<bool()> post_emission = [] { return true; };
+
+    // Populate the spirv_params with common parameters
+    OperandList spirv_params;
+    spirv_params.reserve(8);  // Enough to fit most parameter lists
+
+    // Extra image operands, appended to spirv_params.
+    struct ImageOperand {
+        SpvImageOperandsMask mask;
+        Operand operand;
+    };
+    std::vector<ImageOperand> image_operands;
+    image_operands.reserve(4);  // Enough to fit most parameter lists
+
+    // Appends `result_type` and `result_id` to `spirv_params`
+    auto append_result_type_and_id_to_spirv_params = [&]() {
+        spirv_params.emplace_back(std::move(result_type));
+        spirv_params.emplace_back(std::move(result_id));
+    };
+
+    // Appends a result type and id to `spirv_params`, possibly adding a
+    // post_emission step.
+    //
+    // If the texture is a depth texture, then this function wraps the result of
+    // the op with a OpCompositeExtract to evaluate to the first element of the
+    // returned vector. This is done as the WGSL texture reading functions for
+    // depths return a single float scalar instead of a vector.
+    //
+    // If the texture is not a depth texture, then this function simply delegates
+    // to calling append_result_type_and_id_to_spirv_params().
+    auto append_result_type_and_id_to_spirv_params_for_read = [&]() {
+        if (texture_type->IsAnyOf<sem::DepthTexture, sem::DepthMultisampledTexture>()) {
+            auto* f32 = builder_.create<sem::F32>();
+            auto* spirv_result_type = builder_.create<sem::Vector>(f32, 4u);
+            auto spirv_result = result_op();
+            post_emission = [=] {
+                return push_function_inst(spv::Op::OpCompositeExtract,
+                                          {result_type, result_id, spirv_result, Operand(0u)});
+            };
+            auto spirv_result_type_id = GenerateTypeIfNeeded(spirv_result_type);
+            if (spirv_result_type_id == 0) {
+                return false;
+            }
+            spirv_params.emplace_back(Operand(spirv_result_type_id));
+            spirv_params.emplace_back(spirv_result);
+            return true;
+        }
+
+        append_result_type_and_id_to_spirv_params();
+        return true;
+    };
+
+    // Appends a result type and id to `spirv_params`, by first swizzling the
+    // result of the op with `swizzle`.
+    auto append_result_type_and_id_to_spirv_params_swizzled = [&](uint32_t spirv_result_width,
+                                                                  std::vector<uint32_t> swizzle) {
         if (swizzle.empty()) {
-          append_result_type_and_id_to_spirv_params();
+            append_result_type_and_id_to_spirv_params();
         } else {
-          // Assign post_emission to swizzle the result of the call to
-          // OpImageQuerySize[Lod].
-          auto* element_type = ElementTypeOf(call->Type());
-          auto spirv_result = result_op();
-          auto* spirv_result_type =
-              builder_.create<sem::Vector>(element_type, spirv_result_width);
-          if (swizzle.size() > 1) {
-            post_emission = [=] {
-              OperandList operands{
-                  result_type,
-                  result_id,
-                  spirv_result,
-                  spirv_result,
-              };
-              for (auto idx : swizzle) {
-                operands.emplace_back(Operand::Int(idx));
-              }
-              return push_function_inst(spv::Op::OpVectorShuffle, operands);
-            };
-          } else {
-            post_emission = [=] {
-              return push_function_inst(spv::Op::OpCompositeExtract,
-                                        {result_type, result_id, spirv_result,
-                                         Operand::Int(swizzle[0])});
-            };
-          }
-          auto spirv_result_type_id = GenerateTypeIfNeeded(spirv_result_type);
-          if (spirv_result_type_id == 0) {
-            return false;
-          }
-          spirv_params.emplace_back(Operand::Int(spirv_result_type_id));
-          spirv_params.emplace_back(spirv_result);
+            // Assign post_emission to swizzle the result of the call to
+            // OpImageQuerySize[Lod].
+            auto* element_type = ElementTypeOf(call->Type());
+            auto spirv_result = result_op();
+            auto* spirv_result_type =
+                builder_.create<sem::Vector>(element_type, spirv_result_width);
+            if (swizzle.size() > 1) {
+                post_emission = [=] {
+                    OperandList operands{
+                        result_type,
+                        result_id,
+                        spirv_result,
+                        spirv_result,
+                    };
+                    for (auto idx : swizzle) {
+                        operands.emplace_back(Operand(idx));
+                    }
+                    return push_function_inst(spv::Op::OpVectorShuffle, operands);
+                };
+            } else {
+                post_emission = [=] {
+                    return push_function_inst(
+                        spv::Op::OpCompositeExtract,
+                        {result_type, result_id, spirv_result, Operand(swizzle[0])});
+                };
+            }
+            auto spirv_result_type_id = GenerateTypeIfNeeded(spirv_result_type);
+            if (spirv_result_type_id == 0) {
+                return false;
+            }
+            spirv_params.emplace_back(Operand(spirv_result_type_id));
+            spirv_params.emplace_back(spirv_result);
         }
         return true;
-      };
+    };
 
-  auto append_coords_to_spirv_params = [&]() -> bool {
-    if (auto* array_index = arg(Usage::kArrayIndex)) {
-      // Array index needs to be appended to the coordinates.
-      auto* packed = AppendVector(&builder_, arg(Usage::kCoords)->Declaration(),
-                                  array_index->Declaration());
-      auto param = GenerateExpression(packed->Declaration());
-      if (param == 0) {
-        return false;
-      }
-      spirv_params.emplace_back(Operand::Int(param));
-    } else {
-      spirv_params.emplace_back(gen_arg(Usage::kCoords));  // coordinates
-    }
-    return true;
-  };
+    auto append_coords_to_spirv_params = [&]() -> bool {
+        if (auto* array_index = arg(Usage::kArrayIndex)) {
+            // Array index needs to be appended to the coordinates.
+            auto* packed = AppendVector(&builder_, arg(Usage::kCoords)->Declaration(),
+                                        array_index->Declaration());
+            auto param = GenerateExpression(packed->Declaration());
+            if (param == 0) {
+                return false;
+            }
+            spirv_params.emplace_back(Operand(param));
+        } else {
+            spirv_params.emplace_back(gen_arg(Usage::kCoords));  // coordinates
+        }
+        return true;
+    };
 
-  auto append_image_and_coords_to_spirv_params = [&]() -> bool {
-    auto sampler_param = gen_arg(Usage::kSampler);
-    auto texture_param = gen_arg(Usage::kTexture);
-    auto sampled_image =
-        GenerateSampledImage(texture_type, texture_param, sampler_param);
+    auto append_image_and_coords_to_spirv_params = [&]() -> bool {
+        auto sampler_param = gen_arg(Usage::kSampler);
+        auto texture_param = gen_arg(Usage::kTexture);
+        auto sampled_image = GenerateSampledImage(texture_type, texture_param, sampler_param);
 
-    // Populate the spirv_params with the common parameters
-    spirv_params.emplace_back(Operand::Int(sampled_image));  // sampled image
-    return append_coords_to_spirv_params();
-  };
+        // Populate the spirv_params with the common parameters
+        spirv_params.emplace_back(Operand(sampled_image));  // sampled image
+        return append_coords_to_spirv_params();
+    };
 
-  switch (builtin->Type()) {
-    case BuiltinType::kTextureDimensions: {
-      // Number of returned elements from OpImageQuerySize[Lod] may not match
-      // those of textureDimensions().
-      // This might be due to an extra vector scalar describing the number of
-      // array elements or textureDimensions() returning a vec3 for cubes
-      // when only width / height is returned by OpImageQuerySize[Lod]
-      // (see https://github.com/gpuweb/gpuweb/issues/1345).
-      // Handle these mismatches by swizzling the returned vector.
-      std::vector<uint32_t> swizzle;
-      uint32_t spirv_dims = 0;
-      switch (texture_type->dim()) {
-        case ast::TextureDimension::kNone:
-          error_ = "texture dimension is kNone";
-          return false;
-        case ast::TextureDimension::k1d:
-        case ast::TextureDimension::k2d:
-        case ast::TextureDimension::k3d:
-        case ast::TextureDimension::kCube:
-          break;  // No swizzle needed
-        case ast::TextureDimension::kCubeArray:
-        case ast::TextureDimension::k2dArray:
-          swizzle = {0, 1};  // Strip array index
-          spirv_dims = 3;    // [width, height, array_count]
-          break;
-      }
+    switch (builtin->Type()) {
+        case BuiltinType::kTextureDimensions: {
+            // Number of returned elements from OpImageQuerySize[Lod] may not match
+            // those of textureDimensions().
+            // This might be due to an extra vector scalar describing the number of
+            // array elements or textureDimensions() returning a vec3 for cubes
+            // when only width / height is returned by OpImageQuerySize[Lod]
+            // (see https://github.com/gpuweb/gpuweb/issues/1345).
+            // Handle these mismatches by swizzling the returned vector.
+            std::vector<uint32_t> swizzle;
+            uint32_t spirv_dims = 0;
+            switch (texture_type->dim()) {
+                case ast::TextureDimension::kNone:
+                    error_ = "texture dimension is kNone";
+                    return false;
+                case ast::TextureDimension::k1d:
+                case ast::TextureDimension::k2d:
+                case ast::TextureDimension::k3d:
+                case ast::TextureDimension::kCube:
+                    break;  // No swizzle needed
+                case ast::TextureDimension::kCubeArray:
+                case ast::TextureDimension::k2dArray:
+                    swizzle = {0, 1};  // Strip array index
+                    spirv_dims = 3;    // [width, height, array_count]
+                    break;
+            }
 
-      if (!append_result_type_and_id_to_spirv_params_swizzled(spirv_dims,
-                                                              swizzle)) {
-        return false;
-      }
+            if (!append_result_type_and_id_to_spirv_params_swizzled(spirv_dims, swizzle)) {
+                return false;
+            }
 
-      spirv_params.emplace_back(gen_arg(Usage::kTexture));
-      if (texture_type->IsAnyOf<sem::MultisampledTexture,       //
-                                sem::DepthMultisampledTexture,  //
-                                sem::StorageTexture>()) {
-        op = spv::Op::OpImageQuerySize;
-      } else if (auto* level = arg(Usage::kLevel)) {
-        op = spv::Op::OpImageQuerySizeLod;
-        spirv_params.emplace_back(gen(level));
-      } else {
-        ast::SintLiteralExpression i32_0(ProgramID(), Source{}, 0);
-        op = spv::Op::OpImageQuerySizeLod;
-        spirv_params.emplace_back(
-            Operand::Int(GenerateLiteralIfNeeded(nullptr, &i32_0)));
-      }
-      break;
-    }
-    case BuiltinType::kTextureNumLayers: {
-      uint32_t spirv_dims = 0;
-      switch (texture_type->dim()) {
+            spirv_params.emplace_back(gen_arg(Usage::kTexture));
+            if (texture_type->IsAnyOf<sem::MultisampledTexture,       //
+                                      sem::DepthMultisampledTexture,  //
+                                      sem::StorageTexture>()) {
+                op = spv::Op::OpImageQuerySize;
+            } else if (auto* level = arg(Usage::kLevel)) {
+                op = spv::Op::OpImageQuerySizeLod;
+                spirv_params.emplace_back(gen(level));
+            } else {
+                op = spv::Op::OpImageQuerySizeLod;
+                spirv_params.emplace_back(
+                    Operand(GenerateConstantIfNeeded(ScalarConstant::I32(0))));
+            }
+            break;
+        }
+        case BuiltinType::kTextureNumLayers: {
+            uint32_t spirv_dims = 0;
+            switch (texture_type->dim()) {
+                default:
+                    error_ = "texture is not arrayed";
+                    return false;
+                case ast::TextureDimension::k2dArray:
+                case ast::TextureDimension::kCubeArray:
+                    spirv_dims = 3;
+                    break;
+            }
+
+            // OpImageQuerySize[Lod] packs the array count as the last element of the
+            // returned vector. Extract this.
+            if (!append_result_type_and_id_to_spirv_params_swizzled(spirv_dims, {spirv_dims - 1})) {
+                return false;
+            }
+
+            spirv_params.emplace_back(gen_arg(Usage::kTexture));
+
+            if (texture_type->Is<sem::MultisampledTexture>() ||
+                texture_type->Is<sem::StorageTexture>()) {
+                op = spv::Op::OpImageQuerySize;
+            } else {
+                op = spv::Op::OpImageQuerySizeLod;
+                spirv_params.emplace_back(
+                    Operand(GenerateConstantIfNeeded(ScalarConstant::I32(0))));
+            }
+            break;
+        }
+        case BuiltinType::kTextureNumLevels: {
+            op = spv::Op::OpImageQueryLevels;
+            append_result_type_and_id_to_spirv_params();
+            spirv_params.emplace_back(gen_arg(Usage::kTexture));
+            break;
+        }
+        case BuiltinType::kTextureNumSamples: {
+            op = spv::Op::OpImageQuerySamples;
+            append_result_type_and_id_to_spirv_params();
+            spirv_params.emplace_back(gen_arg(Usage::kTexture));
+            break;
+        }
+        case BuiltinType::kTextureLoad: {
+            op = texture_type->Is<sem::StorageTexture>() ? spv::Op::OpImageRead
+                                                         : spv::Op::OpImageFetch;
+            append_result_type_and_id_to_spirv_params_for_read();
+            spirv_params.emplace_back(gen_arg(Usage::kTexture));
+            if (!append_coords_to_spirv_params()) {
+                return false;
+            }
+
+            if (auto* level = arg(Usage::kLevel)) {
+                image_operands.emplace_back(ImageOperand{SpvImageOperandsLodMask, gen(level)});
+            }
+
+            if (auto* sample_index = arg(Usage::kSampleIndex)) {
+                image_operands.emplace_back(
+                    ImageOperand{SpvImageOperandsSampleMask, gen(sample_index)});
+            }
+
+            break;
+        }
+        case BuiltinType::kTextureStore: {
+            op = spv::Op::OpImageWrite;
+            spirv_params.emplace_back(gen_arg(Usage::kTexture));
+            if (!append_coords_to_spirv_params()) {
+                return false;
+            }
+            spirv_params.emplace_back(gen_arg(Usage::kValue));
+            break;
+        }
+        case BuiltinType::kTextureGather: {
+            op = spv::Op::OpImageGather;
+            append_result_type_and_id_to_spirv_params();
+            if (!append_image_and_coords_to_spirv_params()) {
+                return false;
+            }
+            if (signature.IndexOf(Usage::kComponent) < 0) {
+                spirv_params.emplace_back(
+                    Operand(GenerateConstantIfNeeded(ScalarConstant::I32(0))));
+            } else {
+                spirv_params.emplace_back(gen_arg(Usage::kComponent));
+            }
+            break;
+        }
+        case BuiltinType::kTextureGatherCompare: {
+            op = spv::Op::OpImageDrefGather;
+            append_result_type_and_id_to_spirv_params();
+            if (!append_image_and_coords_to_spirv_params()) {
+                return false;
+            }
+            spirv_params.emplace_back(gen_arg(Usage::kDepthRef));
+            break;
+        }
+        case BuiltinType::kTextureSample: {
+            op = spv::Op::OpImageSampleImplicitLod;
+            append_result_type_and_id_to_spirv_params_for_read();
+            if (!append_image_and_coords_to_spirv_params()) {
+                return false;
+            }
+            break;
+        }
+        case BuiltinType::kTextureSampleBias: {
+            op = spv::Op::OpImageSampleImplicitLod;
+            append_result_type_and_id_to_spirv_params_for_read();
+            if (!append_image_and_coords_to_spirv_params()) {
+                return false;
+            }
+            image_operands.emplace_back(
+                ImageOperand{SpvImageOperandsBiasMask, gen_arg(Usage::kBias)});
+            break;
+        }
+        case BuiltinType::kTextureSampleLevel: {
+            op = spv::Op::OpImageSampleExplicitLod;
+            append_result_type_and_id_to_spirv_params_for_read();
+            if (!append_image_and_coords_to_spirv_params()) {
+                return false;
+            }
+            auto level = Operand(0u);
+            if (arg(Usage::kLevel)->Type()->UnwrapRef()->Is<sem::I32>()) {
+                // Depth textures have i32 parameters for the level, but SPIR-V expects
+                // F32. Cast.
+                auto f32_type_id = GenerateTypeIfNeeded(builder_.create<sem::F32>());
+                if (f32_type_id == 0) {
+                    return 0;
+                }
+                level = result_op();
+                if (!push_function_inst(spv::Op::OpConvertSToF,
+                                        {Operand(f32_type_id), level, gen_arg(Usage::kLevel)})) {
+                    return 0;
+                }
+            } else {
+                level = gen_arg(Usage::kLevel);
+            }
+            image_operands.emplace_back(ImageOperand{SpvImageOperandsLodMask, level});
+            break;
+        }
+        case BuiltinType::kTextureSampleGrad: {
+            op = spv::Op::OpImageSampleExplicitLod;
+            append_result_type_and_id_to_spirv_params_for_read();
+            if (!append_image_and_coords_to_spirv_params()) {
+                return false;
+            }
+            image_operands.emplace_back(
+                ImageOperand{SpvImageOperandsGradMask, gen_arg(Usage::kDdx)});
+            image_operands.emplace_back(
+                ImageOperand{SpvImageOperandsGradMask, gen_arg(Usage::kDdy)});
+            break;
+        }
+        case BuiltinType::kTextureSampleCompare: {
+            op = spv::Op::OpImageSampleDrefImplicitLod;
+            append_result_type_and_id_to_spirv_params();
+            if (!append_image_and_coords_to_spirv_params()) {
+                return false;
+            }
+            spirv_params.emplace_back(gen_arg(Usage::kDepthRef));
+            break;
+        }
+        case BuiltinType::kTextureSampleCompareLevel: {
+            op = spv::Op::OpImageSampleDrefExplicitLod;
+            append_result_type_and_id_to_spirv_params();
+            if (!append_image_and_coords_to_spirv_params()) {
+                return false;
+            }
+            spirv_params.emplace_back(gen_arg(Usage::kDepthRef));
+
+            ast::FloatLiteralExpression float_0(ProgramID(), Source{}, 0.0);
+            image_operands.emplace_back(ImageOperand{
+                SpvImageOperandsLodMask, Operand(GenerateLiteralIfNeeded(nullptr, &float_0))});
+            break;
+        }
         default:
-          error_ = "texture is not arrayed";
-          return false;
-        case ast::TextureDimension::k2dArray:
-        case ast::TextureDimension::kCubeArray:
-          spirv_dims = 3;
-          break;
-      }
+            TINT_UNREACHABLE(Writer, builder_.Diagnostics());
+            return false;
+    }
 
-      // OpImageQuerySize[Lod] packs the array count as the last element of the
-      // returned vector. Extract this.
-      if (!append_result_type_and_id_to_spirv_params_swizzled(
-              spirv_dims, {spirv_dims - 1})) {
-        return false;
-      }
+    if (auto* offset = arg(Usage::kOffset)) {
+        image_operands.emplace_back(ImageOperand{SpvImageOperandsConstOffsetMask, gen(offset)});
+    }
 
-      spirv_params.emplace_back(gen_arg(Usage::kTexture));
-
-      if (texture_type->Is<sem::MultisampledTexture>() ||
-          texture_type->Is<sem::StorageTexture>()) {
-        op = spv::Op::OpImageQuerySize;
-      } else {
-        ast::SintLiteralExpression i32_0(ProgramID(), Source{}, 0);
-        op = spv::Op::OpImageQuerySizeLod;
-        spirv_params.emplace_back(
-            Operand::Int(GenerateLiteralIfNeeded(nullptr, &i32_0)));
-      }
-      break;
-    }
-    case BuiltinType::kTextureNumLevels: {
-      op = spv::Op::OpImageQueryLevels;
-      append_result_type_and_id_to_spirv_params();
-      spirv_params.emplace_back(gen_arg(Usage::kTexture));
-      break;
-    }
-    case BuiltinType::kTextureNumSamples: {
-      op = spv::Op::OpImageQuerySamples;
-      append_result_type_and_id_to_spirv_params();
-      spirv_params.emplace_back(gen_arg(Usage::kTexture));
-      break;
-    }
-    case BuiltinType::kTextureLoad: {
-      op = texture_type->Is<sem::StorageTexture>() ? spv::Op::OpImageRead
-                                                   : spv::Op::OpImageFetch;
-      append_result_type_and_id_to_spirv_params_for_read();
-      spirv_params.emplace_back(gen_arg(Usage::kTexture));
-      if (!append_coords_to_spirv_params()) {
-        return false;
-      }
-
-      if (auto* level = arg(Usage::kLevel)) {
-        image_operands.emplace_back(
-            ImageOperand{SpvImageOperandsLodMask, gen(level)});
-      }
-
-      if (auto* sample_index = arg(Usage::kSampleIndex)) {
-        image_operands.emplace_back(
-            ImageOperand{SpvImageOperandsSampleMask, gen(sample_index)});
-      }
-
-      break;
-    }
-    case BuiltinType::kTextureStore: {
-      op = spv::Op::OpImageWrite;
-      spirv_params.emplace_back(gen_arg(Usage::kTexture));
-      if (!append_coords_to_spirv_params()) {
-        return false;
-      }
-      spirv_params.emplace_back(gen_arg(Usage::kValue));
-      break;
-    }
-    case BuiltinType::kTextureGather: {
-      op = spv::Op::OpImageGather;
-      append_result_type_and_id_to_spirv_params();
-      if (!append_image_and_coords_to_spirv_params()) {
-        return false;
-      }
-      if (signature.IndexOf(Usage::kComponent) < 0) {
-        spirv_params.emplace_back(
-            Operand::Int(GenerateConstantIfNeeded(ScalarConstant::I32(0))));
-      } else {
-        spirv_params.emplace_back(gen_arg(Usage::kComponent));
-      }
-      break;
-    }
-    case BuiltinType::kTextureGatherCompare: {
-      op = spv::Op::OpImageDrefGather;
-      append_result_type_and_id_to_spirv_params();
-      if (!append_image_and_coords_to_spirv_params()) {
-        return false;
-      }
-      spirv_params.emplace_back(gen_arg(Usage::kDepthRef));
-      break;
-    }
-    case BuiltinType::kTextureSample: {
-      op = spv::Op::OpImageSampleImplicitLod;
-      append_result_type_and_id_to_spirv_params_for_read();
-      if (!append_image_and_coords_to_spirv_params()) {
-        return false;
-      }
-      break;
-    }
-    case BuiltinType::kTextureSampleBias: {
-      op = spv::Op::OpImageSampleImplicitLod;
-      append_result_type_and_id_to_spirv_params_for_read();
-      if (!append_image_and_coords_to_spirv_params()) {
-        return false;
-      }
-      image_operands.emplace_back(
-          ImageOperand{SpvImageOperandsBiasMask, gen_arg(Usage::kBias)});
-      break;
-    }
-    case BuiltinType::kTextureSampleLevel: {
-      op = spv::Op::OpImageSampleExplicitLod;
-      append_result_type_and_id_to_spirv_params_for_read();
-      if (!append_image_and_coords_to_spirv_params()) {
-        return false;
-      }
-      auto level = Operand::Int(0);
-      if (arg(Usage::kLevel)->Type()->UnwrapRef()->Is<sem::I32>()) {
-        // Depth textures have i32 parameters for the level, but SPIR-V expects
-        // F32. Cast.
-        auto f32_type_id = GenerateTypeIfNeeded(builder_.create<sem::F32>());
-        if (f32_type_id == 0) {
-          return 0;
+    if (!image_operands.empty()) {
+        std::sort(image_operands.begin(), image_operands.end(),
+                  [](auto& a, auto& b) { return a.mask < b.mask; });
+        uint32_t mask = 0;
+        for (auto& image_operand : image_operands) {
+            mask |= image_operand.mask;
         }
-        level = result_op();
-        if (!push_function_inst(
-                spv::Op::OpConvertSToF,
-                {Operand::Int(f32_type_id), level, gen_arg(Usage::kLevel)})) {
-          return 0;
+        spirv_params.emplace_back(Operand(mask));
+        for (auto& image_operand : image_operands) {
+            spirv_params.emplace_back(image_operand.operand);
         }
-      } else {
-        level = gen_arg(Usage::kLevel);
-      }
-      image_operands.emplace_back(ImageOperand{SpvImageOperandsLodMask, level});
-      break;
     }
-    case BuiltinType::kTextureSampleGrad: {
-      op = spv::Op::OpImageSampleExplicitLod;
-      append_result_type_and_id_to_spirv_params_for_read();
-      if (!append_image_and_coords_to_spirv_params()) {
+
+    if (op == spv::Op::OpNop) {
+        error_ = "unable to determine operator for: " + std::string(builtin->str());
         return false;
-      }
-      image_operands.emplace_back(
-          ImageOperand{SpvImageOperandsGradMask, gen_arg(Usage::kDdx)});
-      image_operands.emplace_back(
-          ImageOperand{SpvImageOperandsGradMask, gen_arg(Usage::kDdy)});
-      break;
     }
-    case BuiltinType::kTextureSampleCompare: {
-      op = spv::Op::OpImageSampleDrefImplicitLod;
-      append_result_type_and_id_to_spirv_params();
-      if (!append_image_and_coords_to_spirv_params()) {
+
+    if (!push_function_inst(op, spirv_params)) {
         return false;
-      }
-      spirv_params.emplace_back(gen_arg(Usage::kDepthRef));
-      break;
     }
-    case BuiltinType::kTextureSampleCompareLevel: {
-      op = spv::Op::OpImageSampleDrefExplicitLod;
-      append_result_type_and_id_to_spirv_params();
-      if (!append_image_and_coords_to_spirv_params()) {
-        return false;
-      }
-      spirv_params.emplace_back(gen_arg(Usage::kDepthRef));
 
-      ast::FloatLiteralExpression float_0(ProgramID(), Source{}, 0.0);
-      image_operands.emplace_back(ImageOperand{
-          SpvImageOperandsLodMask,
-          Operand::Int(GenerateLiteralIfNeeded(nullptr, &float_0))});
-      break;
-    }
-    default:
-      TINT_UNREACHABLE(Writer, builder_.Diagnostics());
-      return false;
-  }
-
-  if (auto* offset = arg(Usage::kOffset)) {
-    image_operands.emplace_back(
-        ImageOperand{SpvImageOperandsConstOffsetMask, gen(offset)});
-  }
-
-  if (!image_operands.empty()) {
-    std::sort(image_operands.begin(), image_operands.end(),
-              [](auto& a, auto& b) { return a.mask < b.mask; });
-    uint32_t mask = 0;
-    for (auto& image_operand : image_operands) {
-      mask |= image_operand.mask;
-    }
-    spirv_params.emplace_back(Operand::Int(mask));
-    for (auto& image_operand : image_operands) {
-      spirv_params.emplace_back(image_operand.operand);
-    }
-  }
-
-  if (op == spv::Op::OpNop) {
-    error_ = "unable to determine operator for: " + std::string(builtin->str());
-    return false;
-  }
-
-  if (!push_function_inst(op, spirv_params)) {
-    return false;
-  }
-
-  return post_emission();
+    return post_emission();
 }
 
 bool Builder::GenerateControlBarrierBuiltin(const sem::Builtin* builtin) {
-  auto const op = spv::Op::OpControlBarrier;
-  uint32_t execution = 0;
-  uint32_t memory = 0;
-  uint32_t semantics = 0;
+    auto const op = spv::Op::OpControlBarrier;
+    uint32_t execution = 0;
+    uint32_t memory = 0;
+    uint32_t semantics = 0;
 
-  // TODO(crbug.com/tint/661): Combine sequential barriers to a single
-  // instruction.
-  if (builtin->Type() == sem::BuiltinType::kWorkgroupBarrier) {
-    execution = static_cast<uint32_t>(spv::Scope::Workgroup);
-    memory = static_cast<uint32_t>(spv::Scope::Workgroup);
-    semantics =
-        static_cast<uint32_t>(spv::MemorySemanticsMask::AcquireRelease) |
-        static_cast<uint32_t>(spv::MemorySemanticsMask::WorkgroupMemory);
-  } else if (builtin->Type() == sem::BuiltinType::kStorageBarrier) {
-    execution = static_cast<uint32_t>(spv::Scope::Workgroup);
-    memory = static_cast<uint32_t>(spv::Scope::Workgroup);
-    semantics =
-        static_cast<uint32_t>(spv::MemorySemanticsMask::AcquireRelease) |
-        static_cast<uint32_t>(spv::MemorySemanticsMask::UniformMemory);
-  } else {
-    error_ = "unexpected barrier builtin type ";
-    error_ += sem::str(builtin->Type());
-    return false;
-  }
+    // TODO(crbug.com/tint/661): Combine sequential barriers to a single
+    // instruction.
+    if (builtin->Type() == sem::BuiltinType::kWorkgroupBarrier) {
+        execution = static_cast<uint32_t>(spv::Scope::Workgroup);
+        memory = static_cast<uint32_t>(spv::Scope::Workgroup);
+        semantics = static_cast<uint32_t>(spv::MemorySemanticsMask::AcquireRelease) |
+                    static_cast<uint32_t>(spv::MemorySemanticsMask::WorkgroupMemory);
+    } else if (builtin->Type() == sem::BuiltinType::kStorageBarrier) {
+        execution = static_cast<uint32_t>(spv::Scope::Workgroup);
+        memory = static_cast<uint32_t>(spv::Scope::Workgroup);
+        semantics = static_cast<uint32_t>(spv::MemorySemanticsMask::AcquireRelease) |
+                    static_cast<uint32_t>(spv::MemorySemanticsMask::UniformMemory);
+    } else {
+        error_ = "unexpected barrier builtin type ";
+        error_ += sem::str(builtin->Type());
+        return false;
+    }
 
-  auto execution_id = GenerateConstantIfNeeded(ScalarConstant::U32(execution));
-  auto memory_id = GenerateConstantIfNeeded(ScalarConstant::U32(memory));
-  auto semantics_id = GenerateConstantIfNeeded(ScalarConstant::U32(semantics));
-  if (execution_id == 0 || memory_id == 0 || semantics_id == 0) {
-    return false;
-  }
+    auto execution_id = GenerateConstantIfNeeded(ScalarConstant::U32(execution));
+    auto memory_id = GenerateConstantIfNeeded(ScalarConstant::U32(memory));
+    auto semantics_id = GenerateConstantIfNeeded(ScalarConstant::U32(semantics));
+    if (execution_id == 0 || memory_id == 0 || semantics_id == 0) {
+        return false;
+    }
 
-  return push_function_inst(op, {
-                                    Operand::Int(execution_id),
-                                    Operand::Int(memory_id),
-                                    Operand::Int(semantics_id),
-                                });
+    return push_function_inst(op, {
+                                      Operand(execution_id),
+                                      Operand(memory_id),
+                                      Operand(semantics_id),
+                                  });
 }
 
 bool Builder::GenerateAtomicBuiltin(const sem::Call* call,
                                     const sem::Builtin* builtin,
                                     Operand result_type,
                                     Operand result_id) {
-  auto is_value_signed = [&] {
-    return builtin->Parameters()[1]->Type()->Is<sem::I32>();
-  };
+    auto is_value_signed = [&] { return builtin->Parameters()[1]->Type()->Is<sem::I32>(); };
 
-  auto storage_class =
-      builtin->Parameters()[0]->Type()->As<sem::Pointer>()->StorageClass();
+    auto storage_class = builtin->Parameters()[0]->Type()->As<sem::Pointer>()->StorageClass();
 
-  uint32_t memory_id = 0;
-  switch (
-      builtin->Parameters()[0]->Type()->As<sem::Pointer>()->StorageClass()) {
-    case ast::StorageClass::kWorkgroup:
-      memory_id = GenerateConstantIfNeeded(
-          ScalarConstant::U32(static_cast<uint32_t>(spv::Scope::Workgroup)));
-      break;
-    case ast::StorageClass::kStorage:
-      memory_id = GenerateConstantIfNeeded(
-          ScalarConstant::U32(static_cast<uint32_t>(spv::Scope::Device)));
-      break;
-    default:
-      TINT_UNREACHABLE(Writer, builder_.Diagnostics())
-          << "unhandled atomic storage class " << storage_class;
-      return false;
-  }
-  if (memory_id == 0) {
-    return false;
-  }
-
-  uint32_t semantics_id = GenerateConstantIfNeeded(ScalarConstant::U32(
-      static_cast<uint32_t>(spv::MemorySemanticsMask::MaskNone)));
-  if (semantics_id == 0) {
-    return false;
-  }
-
-  uint32_t pointer_id = GenerateExpression(call->Arguments()[0]->Declaration());
-  if (pointer_id == 0) {
-    return false;
-  }
-
-  uint32_t value_id = 0;
-  if (call->Arguments().size() > 1) {
-    value_id = GenerateExpressionWithLoadIfNeeded(call->Arguments().back());
-    if (value_id == 0) {
-      return false;
+    uint32_t memory_id = 0;
+    switch (builtin->Parameters()[0]->Type()->As<sem::Pointer>()->StorageClass()) {
+        case ast::StorageClass::kWorkgroup:
+            memory_id = GenerateConstantIfNeeded(
+                ScalarConstant::U32(static_cast<uint32_t>(spv::Scope::Workgroup)));
+            break;
+        case ast::StorageClass::kStorage:
+            memory_id = GenerateConstantIfNeeded(
+                ScalarConstant::U32(static_cast<uint32_t>(spv::Scope::Device)));
+            break;
+        default:
+            TINT_UNREACHABLE(Writer, builder_.Diagnostics())
+                << "unhandled atomic storage class " << storage_class;
+            return false;
     }
-  }
+    if (memory_id == 0) {
+        return false;
+    }
 
-  Operand pointer = Operand::Int(pointer_id);
-  Operand value = Operand::Int(value_id);
-  Operand memory = Operand::Int(memory_id);
-  Operand semantics = Operand::Int(semantics_id);
+    uint32_t semantics_id = GenerateConstantIfNeeded(
+        ScalarConstant::U32(static_cast<uint32_t>(spv::MemorySemanticsMask::MaskNone)));
+    if (semantics_id == 0) {
+        return false;
+    }
 
-  switch (builtin->Type()) {
-    case sem::BuiltinType::kAtomicLoad:
-      return push_function_inst(spv::Op::OpAtomicLoad, {
-                                                           result_type,
-                                                           result_id,
-                                                           pointer,
-                                                           memory,
-                                                           semantics,
-                                                       });
-    case sem::BuiltinType::kAtomicStore:
-      return push_function_inst(spv::Op::OpAtomicStore, {
-                                                            pointer,
-                                                            memory,
-                                                            semantics,
-                                                            value,
-                                                        });
-    case sem::BuiltinType::kAtomicAdd:
-      return push_function_inst(spv::Op::OpAtomicIAdd, {
-                                                           result_type,
-                                                           result_id,
-                                                           pointer,
-                                                           memory,
-                                                           semantics,
-                                                           value,
-                                                       });
-    case sem::BuiltinType::kAtomicSub:
-      return push_function_inst(spv::Op::OpAtomicISub, {
-                                                           result_type,
-                                                           result_id,
-                                                           pointer,
-                                                           memory,
-                                                           semantics,
-                                                           value,
-                                                       });
-    case sem::BuiltinType::kAtomicMax:
-      return push_function_inst(
-          is_value_signed() ? spv::Op::OpAtomicSMax : spv::Op::OpAtomicUMax,
-          {
-              result_type,
-              result_id,
-              pointer,
-              memory,
-              semantics,
-              value,
-          });
-    case sem::BuiltinType::kAtomicMin:
-      return push_function_inst(
-          is_value_signed() ? spv::Op::OpAtomicSMin : spv::Op::OpAtomicUMin,
-          {
-              result_type,
-              result_id,
-              pointer,
-              memory,
-              semantics,
-              value,
-          });
-    case sem::BuiltinType::kAtomicAnd:
-      return push_function_inst(spv::Op::OpAtomicAnd, {
-                                                          result_type,
-                                                          result_id,
-                                                          pointer,
-                                                          memory,
-                                                          semantics,
-                                                          value,
-                                                      });
-    case sem::BuiltinType::kAtomicOr:
-      return push_function_inst(spv::Op::OpAtomicOr, {
-                                                         result_type,
-                                                         result_id,
-                                                         pointer,
-                                                         memory,
-                                                         semantics,
-                                                         value,
-                                                     });
-    case sem::BuiltinType::kAtomicXor:
-      return push_function_inst(spv::Op::OpAtomicXor, {
-                                                          result_type,
-                                                          result_id,
-                                                          pointer,
-                                                          memory,
-                                                          semantics,
-                                                          value,
-                                                      });
-    case sem::BuiltinType::kAtomicExchange:
-      return push_function_inst(spv::Op::OpAtomicExchange, {
+    uint32_t pointer_id = GenerateExpression(call->Arguments()[0]->Declaration());
+    if (pointer_id == 0) {
+        return false;
+    }
+
+    uint32_t value_id = 0;
+    if (call->Arguments().size() > 1) {
+        value_id = GenerateExpressionWithLoadIfNeeded(call->Arguments().back());
+        if (value_id == 0) {
+            return false;
+        }
+    }
+
+    Operand pointer = Operand(pointer_id);
+    Operand value = Operand(value_id);
+    Operand memory = Operand(memory_id);
+    Operand semantics = Operand(semantics_id);
+
+    switch (builtin->Type()) {
+        case sem::BuiltinType::kAtomicLoad:
+            return push_function_inst(spv::Op::OpAtomicLoad, {
+                                                                 result_type,
+                                                                 result_id,
+                                                                 pointer,
+                                                                 memory,
+                                                                 semantics,
+                                                             });
+        case sem::BuiltinType::kAtomicStore:
+            return push_function_inst(spv::Op::OpAtomicStore, {
+                                                                  pointer,
+                                                                  memory,
+                                                                  semantics,
+                                                                  value,
+                                                              });
+        case sem::BuiltinType::kAtomicAdd:
+            return push_function_inst(spv::Op::OpAtomicIAdd, {
+                                                                 result_type,
+                                                                 result_id,
+                                                                 pointer,
+                                                                 memory,
+                                                                 semantics,
+                                                                 value,
+                                                             });
+        case sem::BuiltinType::kAtomicSub:
+            return push_function_inst(spv::Op::OpAtomicISub, {
+                                                                 result_type,
+                                                                 result_id,
+                                                                 pointer,
+                                                                 memory,
+                                                                 semantics,
+                                                                 value,
+                                                             });
+        case sem::BuiltinType::kAtomicMax:
+            return push_function_inst(
+                is_value_signed() ? spv::Op::OpAtomicSMax : spv::Op::OpAtomicUMax, {
+                                                                                       result_type,
+                                                                                       result_id,
+                                                                                       pointer,
+                                                                                       memory,
+                                                                                       semantics,
+                                                                                       value,
+                                                                                   });
+        case sem::BuiltinType::kAtomicMin:
+            return push_function_inst(
+                is_value_signed() ? spv::Op::OpAtomicSMin : spv::Op::OpAtomicUMin, {
+                                                                                       result_type,
+                                                                                       result_id,
+                                                                                       pointer,
+                                                                                       memory,
+                                                                                       semantics,
+                                                                                       value,
+                                                                                   });
+        case sem::BuiltinType::kAtomicAnd:
+            return push_function_inst(spv::Op::OpAtomicAnd, {
+                                                                result_type,
+                                                                result_id,
+                                                                pointer,
+                                                                memory,
+                                                                semantics,
+                                                                value,
+                                                            });
+        case sem::BuiltinType::kAtomicOr:
+            return push_function_inst(spv::Op::OpAtomicOr, {
                                                                result_type,
                                                                result_id,
                                                                pointer,
@@ -3185,1148 +3078,1080 @@
                                                                semantics,
                                                                value,
                                                            });
-    case sem::BuiltinType::kAtomicCompareExchangeWeak: {
-      auto comparator = GenerateExpression(call->Arguments()[1]->Declaration());
-      if (comparator == 0) {
-        return false;
-      }
+        case sem::BuiltinType::kAtomicXor:
+            return push_function_inst(spv::Op::OpAtomicXor, {
+                                                                result_type,
+                                                                result_id,
+                                                                pointer,
+                                                                memory,
+                                                                semantics,
+                                                                value,
+                                                            });
+        case sem::BuiltinType::kAtomicExchange:
+            return push_function_inst(spv::Op::OpAtomicExchange, {
+                                                                     result_type,
+                                                                     result_id,
+                                                                     pointer,
+                                                                     memory,
+                                                                     semantics,
+                                                                     value,
+                                                                 });
+        case sem::BuiltinType::kAtomicCompareExchangeWeak: {
+            auto comparator = GenerateExpression(call->Arguments()[1]->Declaration());
+            if (comparator == 0) {
+                return false;
+            }
 
-      auto* value_sem_type = TypeOf(call->Arguments()[2]->Declaration());
+            auto* value_sem_type = TypeOf(call->Arguments()[2]->Declaration());
 
-      auto value_type = GenerateTypeIfNeeded(value_sem_type);
-      if (value_type == 0) {
-        return false;
-      }
+            auto value_type = GenerateTypeIfNeeded(value_sem_type);
+            if (value_type == 0) {
+                return false;
+            }
 
-      auto* bool_sem_ty = builder_.create<sem::Bool>();
-      auto bool_type = GenerateTypeIfNeeded(bool_sem_ty);
-      if (bool_type == 0) {
-        return false;
-      }
+            auto* bool_sem_ty = builder_.create<sem::Bool>();
+            auto bool_type = GenerateTypeIfNeeded(bool_sem_ty);
+            if (bool_type == 0) {
+                return false;
+            }
 
-      // original_value := OpAtomicCompareExchange(pointer, memory, semantics,
-      //                                           semantics, value, comparator)
-      auto original_value = result_op();
-      if (!push_function_inst(spv::Op::OpAtomicCompareExchange,
-                              {
-                                  Operand::Int(value_type),
-                                  original_value,
-                                  pointer,
-                                  memory,
-                                  semantics,
-                                  semantics,
-                                  value,
-                                  Operand::Int(comparator),
-                              })) {
-        return false;
-      }
+            // original_value := OpAtomicCompareExchange(pointer, memory, semantics,
+            //                                           semantics, value, comparator)
+            auto original_value = result_op();
+            if (!push_function_inst(spv::Op::OpAtomicCompareExchange, {
+                                                                          Operand(value_type),
+                                                                          original_value,
+                                                                          pointer,
+                                                                          memory,
+                                                                          semantics,
+                                                                          semantics,
+                                                                          value,
+                                                                          Operand(comparator),
+                                                                      })) {
+                return false;
+            }
 
-      // values_equal := original_value == value
-      auto values_equal = result_op();
-      if (!push_function_inst(spv::Op::OpIEqual, {
-                                                     Operand::Int(bool_type),
-                                                     values_equal,
-                                                     original_value,
-                                                     value,
-                                                 })) {
-        return false;
-      }
+            // values_equal := original_value == value
+            auto values_equal = result_op();
+            if (!push_function_inst(spv::Op::OpIEqual, {
+                                                           Operand(bool_type),
+                                                           values_equal,
+                                                           original_value,
+                                                           value,
+                                                       })) {
+                return false;
+            }
 
-      // zero := T(0)
-      // one := T(1)
-      uint32_t zero = 0;
-      uint32_t one = 0;
-      if (value_sem_type->Is<sem::I32>()) {
-        zero = GenerateConstantIfNeeded(ScalarConstant::I32(0u));
-        one = GenerateConstantIfNeeded(ScalarConstant::I32(1u));
-      } else if (value_sem_type->Is<sem::U32>()) {
-        zero = GenerateConstantIfNeeded(ScalarConstant::U32(0u));
-        one = GenerateConstantIfNeeded(ScalarConstant::U32(1u));
-      } else {
-        TINT_UNREACHABLE(Writer, builder_.Diagnostics())
-            << "unsupported atomic type " << value_sem_type->TypeInfo().name;
-      }
-      if (zero == 0 || one == 0) {
-        return false;
-      }
+            // zero := T(0)
+            // one := T(1)
+            uint32_t zero = 0;
+            uint32_t one = 0;
+            if (value_sem_type->Is<sem::I32>()) {
+                zero = GenerateConstantIfNeeded(ScalarConstant::I32(0u));
+                one = GenerateConstantIfNeeded(ScalarConstant::I32(1u));
+            } else if (value_sem_type->Is<sem::U32>()) {
+                zero = GenerateConstantIfNeeded(ScalarConstant::U32(0u));
+                one = GenerateConstantIfNeeded(ScalarConstant::U32(1u));
+            } else {
+                TINT_UNREACHABLE(Writer, builder_.Diagnostics())
+                    << "unsupported atomic type " << value_sem_type->TypeInfo().name;
+            }
+            if (zero == 0 || one == 0) {
+                return false;
+            }
 
-      // xchg_success := values_equal ? one : zero
-      auto xchg_success = result_op();
-      if (!push_function_inst(spv::Op::OpSelect, {
-                                                     Operand::Int(value_type),
-                                                     xchg_success,
-                                                     values_equal,
-                                                     Operand::Int(one),
-                                                     Operand::Int(zero),
-                                                 })) {
-        return false;
-      }
+            // xchg_success := values_equal ? one : zero
+            auto xchg_success = result_op();
+            if (!push_function_inst(spv::Op::OpSelect, {
+                                                           Operand(value_type),
+                                                           xchg_success,
+                                                           values_equal,
+                                                           Operand(one),
+                                                           Operand(zero),
+                                                       })) {
+                return false;
+            }
 
-      // result := vec2<T>(original_value, xchg_success)
-      return push_function_inst(spv::Op::OpCompositeConstruct,
-                                {
-                                    result_type,
-                                    result_id,
-                                    original_value,
-                                    xchg_success,
-                                });
+            // result := vec2<T>(original_value, xchg_success)
+            return push_function_inst(spv::Op::OpCompositeConstruct, {
+                                                                         result_type,
+                                                                         result_id,
+                                                                         original_value,
+                                                                         xchg_success,
+                                                                     });
+        }
+        default:
+            TINT_UNREACHABLE(Writer, builder_.Diagnostics())
+                << "unhandled atomic builtin " << builtin->Type();
+            return false;
     }
-    default:
-      TINT_UNREACHABLE(Writer, builder_.Diagnostics())
-          << "unhandled atomic builtin " << builtin->Type();
-      return false;
-  }
 }
 
 uint32_t Builder::GenerateSampledImage(const sem::Type* texture_type,
                                        Operand texture_operand,
                                        Operand sampler_operand) {
-  // DepthTexture is always declared as SampledTexture.
-  // The Vulkan spec says: The "Depth" operand of OpTypeImage is ignored.
-  // In SPIRV, 0 means not depth, 1 means depth, and 2 means unknown.
-  // Using anything other than 0 is problematic on various Vulkan drivers.
-  if (auto* depthTextureType = texture_type->As<sem::DepthTexture>()) {
-    texture_type = builder_.create<sem::SampledTexture>(
-        depthTextureType->dim(), builder_.create<sem::F32>());
-  }
+    // DepthTexture is always declared as SampledTexture.
+    // The Vulkan spec says: The "Depth" operand of OpTypeImage is ignored.
+    // In SPIRV, 0 means not depth, 1 means depth, and 2 means unknown.
+    // Using anything other than 0 is problematic on various Vulkan drivers.
+    if (auto* depthTextureType = texture_type->As<sem::DepthTexture>()) {
+        texture_type = builder_.create<sem::SampledTexture>(depthTextureType->dim(),
+                                                            builder_.create<sem::F32>());
+    }
 
-  uint32_t sampled_image_type_id = utils::GetOrCreate(
-      texture_type_to_sampled_image_type_id_, texture_type, [&] {
-        // We need to create the sampled image type and cache the result.
-        auto sampled_image_type = result_op();
-        auto texture_type_id = GenerateTypeIfNeeded(texture_type);
-        push_type(spv::Op::OpTypeSampledImage,
-                  {sampled_image_type, Operand::Int(texture_type_id)});
-        return sampled_image_type.to_i();
-      });
+    uint32_t sampled_image_type_id =
+        utils::GetOrCreate(texture_type_to_sampled_image_type_id_, texture_type, [&] {
+            // We need to create the sampled image type and cache the result.
+            auto sampled_image_type = result_op();
+            auto texture_type_id = GenerateTypeIfNeeded(texture_type);
+            push_type(spv::Op::OpTypeSampledImage, {sampled_image_type, Operand(texture_type_id)});
+            return std::get<uint32_t>(sampled_image_type);
+        });
 
-  auto sampled_image = result_op();
-  if (!push_function_inst(spv::Op::OpSampledImage,
-                          {Operand::Int(sampled_image_type_id), sampled_image,
-                           texture_operand, sampler_operand})) {
-    return 0;
-  }
+    auto sampled_image = result_op();
+    if (!push_function_inst(spv::Op::OpSampledImage, {Operand(sampled_image_type_id), sampled_image,
+                                                      texture_operand, sampler_operand})) {
+        return 0;
+    }
 
-  return sampled_image.to_i();
+    return std::get<uint32_t>(sampled_image);
 }
 
-uint32_t Builder::GenerateBitcastExpression(
-    const ast::BitcastExpression* expr) {
-  auto result = result_op();
-  auto result_id = result.to_i();
+uint32_t Builder::GenerateBitcastExpression(const ast::BitcastExpression* expr) {
+    auto result = result_op();
+    auto result_id = std::get<uint32_t>(result);
 
-  auto result_type_id = GenerateTypeIfNeeded(TypeOf(expr));
-  if (result_type_id == 0) {
-    return 0;
-  }
-
-  auto val_id = GenerateExpressionWithLoadIfNeeded(expr->expr);
-  if (val_id == 0) {
-    return 0;
-  }
-
-  // Bitcast does not allow same types, just emit a CopyObject
-  auto* to_type = TypeOf(expr)->UnwrapRef();
-  auto* from_type = TypeOf(expr->expr)->UnwrapRef();
-  if (to_type == from_type) {
-    if (!push_function_inst(
-            spv::Op::OpCopyObject,
-            {Operand::Int(result_type_id), result, Operand::Int(val_id)})) {
-      return 0;
+    auto result_type_id = GenerateTypeIfNeeded(TypeOf(expr));
+    if (result_type_id == 0) {
+        return 0;
     }
+
+    auto val_id = GenerateExpressionWithLoadIfNeeded(expr->expr);
+    if (val_id == 0) {
+        return 0;
+    }
+
+    // Bitcast does not allow same types, just emit a CopyObject
+    auto* to_type = TypeOf(expr)->UnwrapRef();
+    auto* from_type = TypeOf(expr->expr)->UnwrapRef();
+    if (to_type == from_type) {
+        if (!push_function_inst(spv::Op::OpCopyObject,
+                                {Operand(result_type_id), result, Operand(val_id)})) {
+            return 0;
+        }
+        return result_id;
+    }
+
+    if (!push_function_inst(spv::Op::OpBitcast,
+                            {Operand(result_type_id), result, Operand(val_id)})) {
+        return 0;
+    }
+
     return result_id;
-  }
-
-  if (!push_function_inst(spv::Op::OpBitcast, {Operand::Int(result_type_id),
-                                               result, Operand::Int(val_id)})) {
-    return 0;
-  }
-
-  return result_id;
 }
 
-bool Builder::GenerateConditionalBlock(
-    const ast::Expression* cond,
-    const ast::BlockStatement* true_body,
-    size_t cur_else_idx,
-    const ast::ElseStatementList& else_stmts) {
-  auto cond_id = GenerateExpressionWithLoadIfNeeded(cond);
-  if (cond_id == 0) {
-    return false;
-  }
-
-  auto merge_block = result_op();
-  auto merge_block_id = merge_block.to_i();
-
-  if (!push_function_inst(spv::Op::OpSelectionMerge,
-                          {Operand::Int(merge_block_id),
-                           Operand::Int(SpvSelectionControlMaskNone)})) {
-    return false;
-  }
-
-  auto true_block = result_op();
-  auto true_block_id = true_block.to_i();
-
-  // if there are no more else statements we branch on false to the merge
-  // block otherwise we branch to the false block
-  auto false_block_id =
-      cur_else_idx < else_stmts.size() ? next_id() : merge_block_id;
-
-  if (!push_function_inst(spv::Op::OpBranchConditional,
-                          {Operand::Int(cond_id), Operand::Int(true_block_id),
-                           Operand::Int(false_block_id)})) {
-    return false;
-  }
-
-  // Output true block
-  if (!GenerateLabel(true_block_id)) {
-    return false;
-  }
-  if (!GenerateBlockStatement(true_body)) {
-    return false;
-  }
-  // We only branch if the last element of the body didn't already branch.
-  if (InsideBasicBlock()) {
-    if (!push_function_inst(spv::Op::OpBranch,
-                            {Operand::Int(merge_block_id)})) {
-      return false;
-    }
-  }
-
-  // Start the false block if needed
-  if (false_block_id != merge_block_id) {
-    if (!GenerateLabel(false_block_id)) {
-      return false;
-    }
-
-    auto* else_stmt = else_stmts[cur_else_idx];
-    // Handle the else case by just outputting the statements.
-    if (!else_stmt->condition) {
-      if (!GenerateBlockStatement(else_stmt->body)) {
+bool Builder::GenerateConditionalBlock(const ast::Expression* cond,
+                                       const ast::BlockStatement* true_body,
+                                       const ast::Statement* else_stmt) {
+    auto cond_id = GenerateExpressionWithLoadIfNeeded(cond);
+    if (cond_id == 0) {
         return false;
-      }
-    } else {
-      if (!GenerateConditionalBlock(else_stmt->condition, else_stmt->body,
-                                    cur_else_idx + 1, else_stmts)) {
-        return false;
-      }
     }
+
+    auto merge_block = result_op();
+    auto merge_block_id = std::get<uint32_t>(merge_block);
+
+    if (!push_function_inst(spv::Op::OpSelectionMerge,
+                            {Operand(merge_block_id), U32Operand(SpvSelectionControlMaskNone)})) {
+        return false;
+    }
+
+    auto true_block = result_op();
+    auto true_block_id = std::get<uint32_t>(true_block);
+
+    // if there are no more else statements we branch on false to the merge
+    // block otherwise we branch to the false block
+    auto false_block_id = else_stmt ? next_id() : merge_block_id;
+
+    if (!push_function_inst(spv::Op::OpBranchConditional,
+                            {Operand(cond_id), Operand(true_block_id), Operand(false_block_id)})) {
+        return false;
+    }
+
+    // Output true block
+    if (!GenerateLabel(true_block_id)) {
+        return false;
+    }
+    if (!GenerateBlockStatement(true_body)) {
+        return false;
+    }
+    // We only branch if the last element of the body didn't already branch.
     if (InsideBasicBlock()) {
-      if (!push_function_inst(spv::Op::OpBranch,
-                              {Operand::Int(merge_block_id)})) {
-        return false;
-      }
+        if (!push_function_inst(spv::Op::OpBranch, {Operand(merge_block_id)})) {
+            return false;
+        }
     }
-  }
 
-  // Output the merge block
-  return GenerateLabel(merge_block_id);
+    // Start the false block if needed
+    if (false_block_id != merge_block_id) {
+        if (!GenerateLabel(false_block_id)) {
+            return false;
+        }
+
+        // Handle the else case by just outputting the statements.
+        if (auto* block = else_stmt->As<ast::BlockStatement>()) {
+            if (!GenerateBlockStatement(block)) {
+                return false;
+            }
+        } else {
+            auto* elseif = else_stmt->As<ast::IfStatement>();
+            if (!GenerateConditionalBlock(elseif->condition, elseif->body,
+                                          elseif->else_statement)) {
+                return false;
+            }
+        }
+        if (InsideBasicBlock()) {
+            if (!push_function_inst(spv::Op::OpBranch, {Operand(merge_block_id)})) {
+                return false;
+            }
+        }
+    }
+
+    // Output the merge block
+    return GenerateLabel(merge_block_id);
 }
 
 bool Builder::GenerateIfStatement(const ast::IfStatement* stmt) {
-  if (!continuing_stack_.empty() &&
-      stmt == continuing_stack_.back().last_statement->As<ast::IfStatement>()) {
-    const ContinuingInfo& ci = continuing_stack_.back();
-    // Match one of two patterns: the break-if and break-unless patterns.
-    //
-    // The break-if pattern:
-    //  continuing { ...
-    //    if (cond) { break; }
-    //  }
-    //
-    // The break-unless pattern:
-    //  continuing { ...
-    //    if (cond) {} else {break;}
-    //  }
-    auto is_just_a_break = [](const ast::BlockStatement* block) {
-      return block && (block->statements.size() == 1) &&
-             block->Last()->Is<ast::BreakStatement>();
-    };
-    if (is_just_a_break(stmt->body) && stmt->else_statements.empty()) {
-      // It's a break-if.
-      TINT_ASSERT(Writer, !backedge_stack_.empty());
-      const auto cond_id = GenerateExpressionWithLoadIfNeeded(stmt->condition);
-      if (!cond_id) {
-        return false;
-      }
-      backedge_stack_.back() =
-          Backedge(spv::Op::OpBranchConditional,
-                   {Operand::Int(cond_id), Operand::Int(ci.break_target_id),
-                    Operand::Int(ci.loop_header_id)});
-      return true;
-    } else if (stmt->body->Empty()) {
-      const auto& es = stmt->else_statements;
-      if (es.size() == 1 && !es.back()->condition &&
-          is_just_a_break(es.back()->body)) {
-        // It's a break-unless.
-        TINT_ASSERT(Writer, !backedge_stack_.empty());
-        const auto cond_id =
-            GenerateExpressionWithLoadIfNeeded(stmt->condition);
-        if (!cond_id) {
-          return false;
+    if (!continuing_stack_.empty() &&
+        stmt == continuing_stack_.back().last_statement->As<ast::IfStatement>()) {
+        const ContinuingInfo& ci = continuing_stack_.back();
+        // Match one of two patterns: the break-if and break-unless patterns.
+        //
+        // The break-if pattern:
+        //  continuing { ...
+        //    if (cond) { break; }
+        //  }
+        //
+        // The break-unless pattern:
+        //  continuing { ...
+        //    if (cond) {} else {break;}
+        //  }
+        auto is_just_a_break = [](const ast::BlockStatement* block) {
+            return block && (block->statements.size() == 1) &&
+                   block->Last()->Is<ast::BreakStatement>();
+        };
+        if (is_just_a_break(stmt->body) && stmt->else_statement == nullptr) {
+            // It's a break-if.
+            TINT_ASSERT(Writer, !backedge_stack_.empty());
+            const auto cond_id = GenerateExpressionWithLoadIfNeeded(stmt->condition);
+            if (!cond_id) {
+                return false;
+            }
+            backedge_stack_.back() = Backedge(
+                spv::Op::OpBranchConditional,
+                {Operand(cond_id), Operand(ci.break_target_id), Operand(ci.loop_header_id)});
+            return true;
+        } else if (stmt->body->Empty()) {
+            auto* es_block = As<ast::BlockStatement>(stmt->else_statement);
+            if (es_block && is_just_a_break(es_block)) {
+                // It's a break-unless.
+                TINT_ASSERT(Writer, !backedge_stack_.empty());
+                const auto cond_id = GenerateExpressionWithLoadIfNeeded(stmt->condition);
+                if (!cond_id) {
+                    return false;
+                }
+                backedge_stack_.back() = Backedge(
+                    spv::Op::OpBranchConditional,
+                    {Operand(cond_id), Operand(ci.loop_header_id), Operand(ci.break_target_id)});
+                return true;
+            }
         }
-        backedge_stack_.back() =
-            Backedge(spv::Op::OpBranchConditional,
-                     {Operand::Int(cond_id), Operand::Int(ci.loop_header_id),
-                      Operand::Int(ci.break_target_id)});
-        return true;
-      }
     }
-  }
 
-  if (!GenerateConditionalBlock(stmt->condition, stmt->body, 0,
-                                stmt->else_statements)) {
-    return false;
-  }
-  return true;
+    if (!GenerateConditionalBlock(stmt->condition, stmt->body, stmt->else_statement)) {
+        return false;
+    }
+    return true;
 }
 
 bool Builder::GenerateSwitchStatement(const ast::SwitchStatement* stmt) {
-  auto merge_block = result_op();
-  auto merge_block_id = merge_block.to_i();
+    auto merge_block = result_op();
+    auto merge_block_id = std::get<uint32_t>(merge_block);
 
-  merge_stack_.push_back(merge_block_id);
+    merge_stack_.push_back(merge_block_id);
 
-  auto cond_id = GenerateExpressionWithLoadIfNeeded(stmt->condition);
-  if (cond_id == 0) {
-    return false;
-  }
-
-  auto default_block = result_op();
-  auto default_block_id = default_block.to_i();
-
-  OperandList params = {Operand::Int(cond_id), Operand::Int(default_block_id)};
-
-  std::vector<uint32_t> case_ids;
-  for (const auto* item : stmt->body) {
-    if (item->IsDefault()) {
-      case_ids.push_back(default_block_id);
-      continue;
-    }
-
-    auto block = result_op();
-    auto block_id = block.to_i();
-
-    case_ids.push_back(block_id);
-    for (auto* selector : item->selectors) {
-      auto* int_literal = selector->As<ast::IntLiteralExpression>();
-      if (!int_literal) {
-        error_ = "expected integer literal for switch case label";
+    auto cond_id = GenerateExpressionWithLoadIfNeeded(stmt->condition);
+    if (cond_id == 0) {
         return false;
-      }
-
-      params.push_back(Operand::Int(int_literal->ValueAsU32()));
-      params.push_back(Operand::Int(block_id));
-    }
-  }
-
-  if (!push_function_inst(spv::Op::OpSelectionMerge,
-                          {Operand::Int(merge_block_id),
-                           Operand::Int(SpvSelectionControlMaskNone)})) {
-    return false;
-  }
-  if (!push_function_inst(spv::Op::OpSwitch, params)) {
-    return false;
-  }
-
-  bool generated_default = false;
-  auto& body = stmt->body;
-  // We output the case statements in order they were entered in the original
-  // source. Each fallthrough goes to the next case entry, so is a forward
-  // branch, otherwise the branch is to the merge block which comes after
-  // the switch statement.
-  for (uint32_t i = 0; i < body.size(); i++) {
-    auto* item = body[i];
-
-    if (item->IsDefault()) {
-      generated_default = true;
     }
 
-    if (!GenerateLabel(case_ids[i])) {
-      return false;
-    }
-    if (!GenerateBlockStatement(item->body)) {
-      return false;
+    auto default_block = result_op();
+    auto default_block_id = std::get<uint32_t>(default_block);
+
+    OperandList params = {Operand(cond_id), Operand(default_block_id)};
+
+    std::vector<uint32_t> case_ids;
+    for (const auto* item : stmt->body) {
+        if (item->IsDefault()) {
+            case_ids.push_back(default_block_id);
+            continue;
+        }
+
+        auto block = result_op();
+        auto block_id = std::get<uint32_t>(block);
+
+        case_ids.push_back(block_id);
+        for (auto* selector : item->selectors) {
+            auto* int_literal = selector->As<ast::IntLiteralExpression>();
+            if (!int_literal) {
+                error_ = "expected integer literal for switch case label";
+                return false;
+            }
+
+            params.push_back(Operand(static_cast<uint32_t>(int_literal->value)));
+            params.push_back(Operand(block_id));
+        }
     }
 
-    if (LastIsFallthrough(item->body)) {
-      if (i == (body.size() - 1)) {
-        // This case is caught by Resolver validation
-        TINT_UNREACHABLE(Writer, builder_.Diagnostics());
+    if (!push_function_inst(spv::Op::OpSelectionMerge,
+                            {Operand(merge_block_id), U32Operand(SpvSelectionControlMaskNone)})) {
         return false;
-      }
-      if (!push_function_inst(spv::Op::OpBranch,
-                              {Operand::Int(case_ids[i + 1])})) {
+    }
+    if (!push_function_inst(spv::Op::OpSwitch, params)) {
         return false;
-      }
-    } else if (InsideBasicBlock()) {
-      if (!push_function_inst(spv::Op::OpBranch,
-                              {Operand::Int(merge_block_id)})) {
-        return false;
-      }
     }
-  }
 
-  if (!generated_default) {
-    if (!GenerateLabel(default_block_id)) {
-      return false;
+    bool generated_default = false;
+    auto& body = stmt->body;
+    // We output the case statements in order they were entered in the original
+    // source. Each fallthrough goes to the next case entry, so is a forward
+    // branch, otherwise the branch is to the merge block which comes after
+    // the switch statement.
+    for (uint32_t i = 0; i < body.size(); i++) {
+        auto* item = body[i];
+
+        if (item->IsDefault()) {
+            generated_default = true;
+        }
+
+        if (!GenerateLabel(case_ids[i])) {
+            return false;
+        }
+        if (!GenerateBlockStatement(item->body)) {
+            return false;
+        }
+
+        if (LastIsFallthrough(item->body)) {
+            if (i == (body.size() - 1)) {
+                // This case is caught by Resolver validation
+                TINT_UNREACHABLE(Writer, builder_.Diagnostics());
+                return false;
+            }
+            if (!push_function_inst(spv::Op::OpBranch, {Operand(case_ids[i + 1])})) {
+                return false;
+            }
+        } else if (InsideBasicBlock()) {
+            if (!push_function_inst(spv::Op::OpBranch, {Operand(merge_block_id)})) {
+                return false;
+            }
+        }
     }
-    if (!push_function_inst(spv::Op::OpBranch,
-                            {Operand::Int(merge_block_id)})) {
-      return false;
+
+    if (!generated_default) {
+        if (!GenerateLabel(default_block_id)) {
+            return false;
+        }
+        if (!push_function_inst(spv::Op::OpBranch, {Operand(merge_block_id)})) {
+            return false;
+        }
     }
-  }
 
-  merge_stack_.pop_back();
+    merge_stack_.pop_back();
 
-  return GenerateLabel(merge_block_id);
+    return GenerateLabel(merge_block_id);
 }
 
 bool Builder::GenerateReturnStatement(const ast::ReturnStatement* stmt) {
-  if (stmt->value) {
-    auto val_id = GenerateExpressionWithLoadIfNeeded(stmt->value);
-    if (val_id == 0) {
-      return false;
+    if (stmt->value) {
+        auto val_id = GenerateExpressionWithLoadIfNeeded(stmt->value);
+        if (val_id == 0) {
+            return false;
+        }
+        if (!push_function_inst(spv::Op::OpReturnValue, {Operand(val_id)})) {
+            return false;
+        }
+    } else {
+        if (!push_function_inst(spv::Op::OpReturn, {})) {
+            return false;
+        }
     }
-    if (!push_function_inst(spv::Op::OpReturnValue, {Operand::Int(val_id)})) {
-      return false;
-    }
-  } else {
-    if (!push_function_inst(spv::Op::OpReturn, {})) {
-      return false;
-    }
-  }
 
-  return true;
+    return true;
 }
 
 bool Builder::GenerateLoopStatement(const ast::LoopStatement* stmt) {
-  auto loop_header = result_op();
-  auto loop_header_id = loop_header.to_i();
-  if (!push_function_inst(spv::Op::OpBranch, {Operand::Int(loop_header_id)})) {
-    return false;
-  }
-  if (!GenerateLabel(loop_header_id)) {
-    return false;
-  }
-
-  auto merge_block = result_op();
-  auto merge_block_id = merge_block.to_i();
-  auto continue_block = result_op();
-  auto continue_block_id = continue_block.to_i();
-
-  auto body_block = result_op();
-  auto body_block_id = body_block.to_i();
-
-  if (!push_function_inst(
-          spv::Op::OpLoopMerge,
-          {Operand::Int(merge_block_id), Operand::Int(continue_block_id),
-           Operand::Int(SpvLoopControlMaskNone)})) {
-    return false;
-  }
-
-  continue_stack_.push_back(continue_block_id);
-  merge_stack_.push_back(merge_block_id);
-
-  // Usually, the backedge is a simple branch.  This will be modified if the
-  // backedge block in the continuing construct has an exiting edge.
-  backedge_stack_.emplace_back(spv::Op::OpBranch,
-                               OperandList{Operand::Int(loop_header_id)});
-
-  if (!push_function_inst(spv::Op::OpBranch, {Operand::Int(body_block_id)})) {
-    return false;
-  }
-  if (!GenerateLabel(body_block_id)) {
-    return false;
-  }
-
-  // We need variables from the body to be visible in the continuing block, so
-  // manage scope outside of GenerateBlockStatement.
-  {
-    scope_stack_.Push();
-    TINT_DEFER(scope_stack_.Pop());
-
-    if (!GenerateBlockStatementWithoutScoping(stmt->body)) {
-      return false;
-    }
-
-    // We only branch if the last element of the body didn't already branch.
-    if (InsideBasicBlock()) {
-      if (!push_function_inst(spv::Op::OpBranch,
-                              {Operand::Int(continue_block_id)})) {
+    auto loop_header = result_op();
+    auto loop_header_id = std::get<uint32_t>(loop_header);
+    if (!push_function_inst(spv::Op::OpBranch, {Operand(loop_header_id)})) {
         return false;
-      }
     }
-
-    if (!GenerateLabel(continue_block_id)) {
-      return false;
-    }
-    if (stmt->continuing && !stmt->continuing->Empty()) {
-      continuing_stack_.emplace_back(stmt->continuing->Last(), loop_header_id,
-                                     merge_block_id);
-      if (!GenerateBlockStatementWithoutScoping(stmt->continuing)) {
+    if (!GenerateLabel(loop_header_id)) {
         return false;
-      }
-      continuing_stack_.pop_back();
     }
-  }
 
-  // Generate the backedge.
-  TINT_ASSERT(Writer, !backedge_stack_.empty());
-  const Backedge& backedge = backedge_stack_.back();
-  if (!push_function_inst(backedge.opcode, backedge.operands)) {
-    return false;
-  }
-  backedge_stack_.pop_back();
+    auto merge_block = result_op();
+    auto merge_block_id = std::get<uint32_t>(merge_block);
+    auto continue_block = result_op();
+    auto continue_block_id = std::get<uint32_t>(continue_block);
 
-  merge_stack_.pop_back();
-  continue_stack_.pop_back();
+    auto body_block = result_op();
+    auto body_block_id = std::get<uint32_t>(body_block);
 
-  return GenerateLabel(merge_block_id);
+    if (!push_function_inst(spv::Op::OpLoopMerge,
+                            {Operand(merge_block_id), Operand(continue_block_id),
+                             U32Operand(SpvLoopControlMaskNone)})) {
+        return false;
+    }
+
+    continue_stack_.push_back(continue_block_id);
+    merge_stack_.push_back(merge_block_id);
+
+    // Usually, the backedge is a simple branch.  This will be modified if the
+    // backedge block in the continuing construct has an exiting edge.
+    backedge_stack_.emplace_back(spv::Op::OpBranch, OperandList{Operand(loop_header_id)});
+
+    if (!push_function_inst(spv::Op::OpBranch, {Operand(body_block_id)})) {
+        return false;
+    }
+    if (!GenerateLabel(body_block_id)) {
+        return false;
+    }
+
+    // We need variables from the body to be visible in the continuing block, so
+    // manage scope outside of GenerateBlockStatement.
+    {
+        PushScope();
+        TINT_DEFER(PopScope());
+
+        if (!GenerateBlockStatementWithoutScoping(stmt->body)) {
+            return false;
+        }
+
+        // We only branch if the last element of the body didn't already branch.
+        if (InsideBasicBlock()) {
+            if (!push_function_inst(spv::Op::OpBranch, {Operand(continue_block_id)})) {
+                return false;
+            }
+        }
+
+        if (!GenerateLabel(continue_block_id)) {
+            return false;
+        }
+        if (stmt->continuing && !stmt->continuing->Empty()) {
+            continuing_stack_.emplace_back(stmt->continuing->Last(), loop_header_id,
+                                           merge_block_id);
+            if (!GenerateBlockStatementWithoutScoping(stmt->continuing)) {
+                return false;
+            }
+            continuing_stack_.pop_back();
+        }
+    }
+
+    // Generate the backedge.
+    TINT_ASSERT(Writer, !backedge_stack_.empty());
+    const Backedge& backedge = backedge_stack_.back();
+    if (!push_function_inst(backedge.opcode, backedge.operands)) {
+        return false;
+    }
+    backedge_stack_.pop_back();
+
+    merge_stack_.pop_back();
+    continue_stack_.pop_back();
+
+    return GenerateLabel(merge_block_id);
 }
 
 bool Builder::GenerateStatement(const ast::Statement* stmt) {
-  return Switch(
-      stmt,
-      [&](const ast::AssignmentStatement* a) {
-        return GenerateAssignStatement(a);
-      },
-      [&](const ast::BlockStatement* b) {  //
-        return GenerateBlockStatement(b);
-      },
-      [&](const ast::BreakStatement* b) {  //
-        return GenerateBreakStatement(b);
-      },
-      [&](const ast::CallStatement* c) {
-        return GenerateCallExpression(c->expr) != 0;
-      },
-      [&](const ast::ContinueStatement* c) {
-        return GenerateContinueStatement(c);
-      },
-      [&](const ast::DiscardStatement* d) {
-        return GenerateDiscardStatement(d);
-      },
-      [&](const ast::FallthroughStatement*) {
-        // Do nothing here, the fallthrough gets handled by the switch code.
-        return true;
-      },
-      [&](const ast::IfStatement* i) {  //
-        return GenerateIfStatement(i);
-      },
-      [&](const ast::LoopStatement* l) {  //
-        return GenerateLoopStatement(l);
-      },
-      [&](const ast::ReturnStatement* r) {  //
-        return GenerateReturnStatement(r);
-      },
-      [&](const ast::SwitchStatement* s) {  //
-        return GenerateSwitchStatement(s);
-      },
-      [&](const ast::VariableDeclStatement* v) {
-        return GenerateVariableDeclStatement(v);
-      },
-      [&](Default) {
-        error_ = "Unknown statement: " + std::string(stmt->TypeInfo().name);
-        return false;
-      });
+    return Switch(
+        stmt, [&](const ast::AssignmentStatement* a) { return GenerateAssignStatement(a); },
+        [&](const ast::BlockStatement* b) {  //
+            return GenerateBlockStatement(b);
+        },
+        [&](const ast::BreakStatement* b) {  //
+            return GenerateBreakStatement(b);
+        },
+        [&](const ast::CallStatement* c) { return GenerateCallExpression(c->expr) != 0; },
+        [&](const ast::ContinueStatement* c) { return GenerateContinueStatement(c); },
+        [&](const ast::DiscardStatement* d) { return GenerateDiscardStatement(d); },
+        [&](const ast::FallthroughStatement*) {
+            // Do nothing here, the fallthrough gets handled by the switch code.
+            return true;
+        },
+        [&](const ast::IfStatement* i) {  //
+            return GenerateIfStatement(i);
+        },
+        [&](const ast::LoopStatement* l) {  //
+            return GenerateLoopStatement(l);
+        },
+        [&](const ast::ReturnStatement* r) {  //
+            return GenerateReturnStatement(r);
+        },
+        [&](const ast::SwitchStatement* s) {  //
+            return GenerateSwitchStatement(s);
+        },
+        [&](const ast::VariableDeclStatement* v) { return GenerateVariableDeclStatement(v); },
+        [&](Default) {
+            error_ = "Unknown statement: " + std::string(stmt->TypeInfo().name);
+            return false;
+        });
 }
 
-bool Builder::GenerateVariableDeclStatement(
-    const ast::VariableDeclStatement* stmt) {
-  return GenerateFunctionVariable(stmt->variable);
+bool Builder::GenerateVariableDeclStatement(const ast::VariableDeclStatement* stmt) {
+    return GenerateFunctionVariable(stmt->variable);
 }
 
 uint32_t Builder::GenerateTypeIfNeeded(const sem::Type* type) {
-  if (type == nullptr) {
-    error_ = "attempting to generate type from null type";
-    return 0;
-  }
-
-  // Atomics are a type in WGSL, but aren't a distinct type in SPIR-V.
-  // Just emit the type inside the atomic.
-  if (auto* atomic = type->As<sem::Atomic>()) {
-    return GenerateTypeIfNeeded(atomic->Type());
-  }
-
-  // DepthTexture is always declared as SampledTexture.
-  // The Vulkan spec says: The "Depth" operand of OpTypeImage is ignored.
-  // In SPIRV, 0 means not depth, 1 means depth, and 2 means unknown.
-  // Using anything other than 0 is problematic on various Vulkan drivers.
-  if (auto* depthTextureType = type->As<sem::DepthTexture>()) {
-    type = builder_.create<sem::SampledTexture>(depthTextureType->dim(),
-                                                builder_.create<sem::F32>());
-  } else if (auto* multisampledDepthTextureType =
-                 type->As<sem::DepthMultisampledTexture>()) {
-    type = builder_.create<sem::MultisampledTexture>(
-        multisampledDepthTextureType->dim(), builder_.create<sem::F32>());
-  }
-
-  // Pointers and references with differing accesses should not result in a
-  // different SPIR-V types, so we explicitly ignore the access.
-  // Pointers and References both map to a SPIR-V pointer type.
-  // Transform a Reference to a Pointer to prevent these having duplicated
-  // definitions in the generated SPIR-V. Note that nested pointers and
-  // references are not legal in WGSL, so only considering the top-level type is
-  // fine.
-  if (auto* ptr = type->As<sem::Pointer>()) {
-    type = builder_.create<sem::Pointer>(ptr->StoreType(), ptr->StorageClass(),
-                                         ast::kReadWrite);
-  } else if (auto* ref = type->As<sem::Reference>()) {
-    type = builder_.create<sem::Pointer>(ref->StoreType(), ref->StorageClass(),
-                                         ast::kReadWrite);
-  }
-
-  return utils::GetOrCreate(type_to_id_, type, [&]() -> uint32_t {
-    auto result = result_op();
-    auto id = result.to_i();
-    bool ok = Switch(
-        type,
-        [&](const sem::Array* arr) {  //
-          return GenerateArrayType(arr, result);
-        },
-        [&](const sem::Bool*) {
-          push_type(spv::Op::OpTypeBool, {result});
-          return true;
-        },
-        [&](const sem::F32*) {
-          push_type(spv::Op::OpTypeFloat, {result, Operand::Int(32)});
-          return true;
-        },
-        [&](const sem::I32*) {
-          push_type(spv::Op::OpTypeInt,
-                    {result, Operand::Int(32), Operand::Int(1)});
-          return true;
-        },
-        [&](const sem::Matrix* mat) {  //
-          return GenerateMatrixType(mat, result);
-        },
-        [&](const sem::Pointer* ptr) {  //
-          return GeneratePointerType(ptr, result);
-        },
-        [&](const sem::Reference* ref) {  //
-          return GenerateReferenceType(ref, result);
-        },
-        [&](const sem::Struct* str) {  //
-          return GenerateStructType(str, result);
-        },
-        [&](const sem::U32*) {
-          push_type(spv::Op::OpTypeInt,
-                    {result, Operand::Int(32), Operand::Int(0)});
-          return true;
-        },
-        [&](const sem::Vector* vec) {  //
-          return GenerateVectorType(vec, result);
-        },
-        [&](const sem::Void*) {
-          push_type(spv::Op::OpTypeVoid, {result});
-          return true;
-        },
-        [&](const sem::StorageTexture* tex) {
-          if (!GenerateTextureType(tex, result)) {
-            return false;
-          }
-
-          // Register all three access types of StorageTexture names. In
-          // SPIR-V, we must output a single type, while the variable is
-          // annotated with the access type. Doing this ensures we de-dupe.
-          type_to_id_[builder_.create<sem::StorageTexture>(
-              tex->dim(), tex->texel_format(), ast::Access::kRead,
-              tex->type())] = id;
-          type_to_id_[builder_.create<sem::StorageTexture>(
-              tex->dim(), tex->texel_format(), ast::Access::kWrite,
-              tex->type())] = id;
-          type_to_id_[builder_.create<sem::StorageTexture>(
-              tex->dim(), tex->texel_format(), ast::Access::kReadWrite,
-              tex->type())] = id;
-          return true;
-        },
-        [&](const sem::Texture* tex) {
-          return GenerateTextureType(tex, result);
-        },
-        [&](const sem::Sampler* s) {
-          push_type(spv::Op::OpTypeSampler, {result});
-
-          // Register both of the sampler type names. In SPIR-V they're the same
-          // sampler type, so we need to match that when we do the dedup check.
-          if (s->kind() == ast::SamplerKind::kSampler) {
-            type_to_id_[builder_.create<sem::Sampler>(
-                ast::SamplerKind::kComparisonSampler)] = id;
-          } else {
-            type_to_id_[builder_.create<sem::Sampler>(
-                ast::SamplerKind::kSampler)] = id;
-          }
-          return true;
-        },
-        [&](Default) {
-          error_ = "unable to convert type: " +
-                   type->FriendlyName(builder_.Symbols());
-          return false;
-        });
-
-    if (!ok) {
-      return 0;
+    if (type == nullptr) {
+        error_ = "attempting to generate type from null type";
+        return 0;
     }
 
-    return id;
-  });
+    // Atomics are a type in WGSL, but aren't a distinct type in SPIR-V.
+    // Just emit the type inside the atomic.
+    if (auto* atomic = type->As<sem::Atomic>()) {
+        return GenerateTypeIfNeeded(atomic->Type());
+    }
+
+    // DepthTexture is always declared as SampledTexture.
+    // The Vulkan spec says: The "Depth" operand of OpTypeImage is ignored.
+    // In SPIRV, 0 means not depth, 1 means depth, and 2 means unknown.
+    // Using anything other than 0 is problematic on various Vulkan drivers.
+    if (auto* depthTextureType = type->As<sem::DepthTexture>()) {
+        type = builder_.create<sem::SampledTexture>(depthTextureType->dim(),
+                                                    builder_.create<sem::F32>());
+    } else if (auto* multisampledDepthTextureType = type->As<sem::DepthMultisampledTexture>()) {
+        type = builder_.create<sem::MultisampledTexture>(multisampledDepthTextureType->dim(),
+                                                         builder_.create<sem::F32>());
+    }
+
+    // Pointers and references with differing accesses should not result in a
+    // different SPIR-V types, so we explicitly ignore the access.
+    // Pointers and References both map to a SPIR-V pointer type.
+    // Transform a Reference to a Pointer to prevent these having duplicated
+    // definitions in the generated SPIR-V. Note that nested pointers and
+    // references are not legal in WGSL, so only considering the top-level type is
+    // fine.
+    if (auto* ptr = type->As<sem::Pointer>()) {
+        type =
+            builder_.create<sem::Pointer>(ptr->StoreType(), ptr->StorageClass(), ast::kReadWrite);
+    } else if (auto* ref = type->As<sem::Reference>()) {
+        type =
+            builder_.create<sem::Pointer>(ref->StoreType(), ref->StorageClass(), ast::kReadWrite);
+    }
+
+    return utils::GetOrCreate(type_to_id_, type, [&]() -> uint32_t {
+        auto result = result_op();
+        auto id = std::get<uint32_t>(result);
+        bool ok = Switch(
+            type,
+            [&](const sem::Array* arr) {  //
+                return GenerateArrayType(arr, result);
+            },
+            [&](const sem::Bool*) {
+                push_type(spv::Op::OpTypeBool, {result});
+                return true;
+            },
+            [&](const sem::F32*) {
+                push_type(spv::Op::OpTypeFloat, {result, Operand(32u)});
+                return true;
+            },
+            [&](const sem::I32*) {
+                push_type(spv::Op::OpTypeInt, {result, Operand(32u), Operand(1u)});
+                return true;
+            },
+            [&](const sem::Matrix* mat) {  //
+                return GenerateMatrixType(mat, result);
+            },
+            [&](const sem::Pointer* ptr) {  //
+                return GeneratePointerType(ptr, result);
+            },
+            [&](const sem::Reference* ref) {  //
+                return GenerateReferenceType(ref, result);
+            },
+            [&](const sem::Struct* str) {  //
+                return GenerateStructType(str, result);
+            },
+            [&](const sem::U32*) {
+                push_type(spv::Op::OpTypeInt, {result, Operand(32u), Operand(0u)});
+                return true;
+            },
+            [&](const sem::Vector* vec) {  //
+                return GenerateVectorType(vec, result);
+            },
+            [&](const sem::Void*) {
+                push_type(spv::Op::OpTypeVoid, {result});
+                return true;
+            },
+            [&](const sem::StorageTexture* tex) {
+                if (!GenerateTextureType(tex, result)) {
+                    return false;
+                }
+
+                // Register all three access types of StorageTexture names. In
+                // SPIR-V, we must output a single type, while the variable is
+                // annotated with the access type. Doing this ensures we de-dupe.
+                type_to_id_[builder_.create<sem::StorageTexture>(
+                    tex->dim(), tex->texel_format(), ast::Access::kRead, tex->type())] = id;
+                type_to_id_[builder_.create<sem::StorageTexture>(
+                    tex->dim(), tex->texel_format(), ast::Access::kWrite, tex->type())] = id;
+                type_to_id_[builder_.create<sem::StorageTexture>(
+                    tex->dim(), tex->texel_format(), ast::Access::kReadWrite, tex->type())] = id;
+                return true;
+            },
+            [&](const sem::Texture* tex) { return GenerateTextureType(tex, result); },
+            [&](const sem::Sampler* s) {
+                push_type(spv::Op::OpTypeSampler, {result});
+
+                // Register both of the sampler type names. In SPIR-V they're the same
+                // sampler type, so we need to match that when we do the dedup check.
+                if (s->kind() == ast::SamplerKind::kSampler) {
+                    type_to_id_[builder_.create<sem::Sampler>(
+                        ast::SamplerKind::kComparisonSampler)] = id;
+                } else {
+                    type_to_id_[builder_.create<sem::Sampler>(ast::SamplerKind::kSampler)] = id;
+                }
+                return true;
+            },
+            [&](Default) {
+                error_ = "unable to convert type: " + type->FriendlyName(builder_.Symbols());
+                return false;
+            });
+
+        if (!ok) {
+            return 0;
+        }
+
+        return id;
+    });
 }
 
-bool Builder::GenerateTextureType(const sem::Texture* texture,
-                                  const Operand& result) {
-  if (texture->Is<sem::ExternalTexture>()) {
-    TINT_ICE(Writer, builder_.Diagnostics())
-        << "Multiplanar external texture transform was not run.";
-    return false;
-  }
-
-  uint32_t array_literal = 0u;
-  const auto dim = texture->dim();
-  if (dim == ast::TextureDimension::k2dArray ||
-      dim == ast::TextureDimension::kCubeArray) {
-    array_literal = 1u;
-  }
-
-  uint32_t dim_literal = SpvDim2D;
-  if (dim == ast::TextureDimension::k1d) {
-    dim_literal = SpvDim1D;
-    if (texture->Is<sem::SampledTexture>()) {
-      push_capability(SpvCapabilitySampled1D);
-    } else if (texture->Is<sem::StorageTexture>()) {
-      push_capability(SpvCapabilityImage1D);
+bool Builder::GenerateTextureType(const sem::Texture* texture, const Operand& result) {
+    if (texture->Is<sem::ExternalTexture>()) {
+        TINT_ICE(Writer, builder_.Diagnostics())
+            << "Multiplanar external texture transform was not run.";
+        return false;
     }
-  }
-  if (dim == ast::TextureDimension::k3d) {
-    dim_literal = SpvDim3D;
-  }
-  if (dim == ast::TextureDimension::kCube ||
-      dim == ast::TextureDimension::kCubeArray) {
-    dim_literal = SpvDimCube;
-  }
 
-  uint32_t ms_literal = 0u;
-  if (texture->IsAnyOf<sem::MultisampledTexture,
-                       sem::DepthMultisampledTexture>()) {
-    ms_literal = 1u;
-  }
-
-  uint32_t depth_literal = 0u;
-  // The Vulkan spec says: The "Depth" operand of OpTypeImage is ignored.
-  // In SPIRV, 0 means not depth, 1 means depth, and 2 means unknown.
-  // Using anything other than 0 is problematic on various Vulkan drivers.
-
-  uint32_t sampled_literal = 2u;
-  if (texture->IsAnyOf<sem::MultisampledTexture, sem::SampledTexture,
-                       sem::DepthTexture, sem::DepthMultisampledTexture>()) {
-    sampled_literal = 1u;
-  }
-
-  if (dim == ast::TextureDimension::kCubeArray) {
-    if (texture->IsAnyOf<sem::SampledTexture, sem::DepthTexture>()) {
-      push_capability(SpvCapabilitySampledCubeArray);
+    uint32_t array_literal = 0u;
+    const auto dim = texture->dim();
+    if (dim == ast::TextureDimension::k2dArray || dim == ast::TextureDimension::kCubeArray) {
+        array_literal = 1u;
     }
-  }
 
-  uint32_t type_id = Switch(
-      texture,
-      [&](const sem::DepthTexture*) {
-        return GenerateTypeIfNeeded(builder_.create<sem::F32>());
-      },
-      [&](const sem::DepthMultisampledTexture*) {
-        return GenerateTypeIfNeeded(builder_.create<sem::F32>());
-      },
-      [&](const sem::SampledTexture* t) {
-        return GenerateTypeIfNeeded(t->type());
-      },
-      [&](const sem::MultisampledTexture* t) {
-        return GenerateTypeIfNeeded(t->type());
-      },
-      [&](const sem::StorageTexture* t) {
-        return GenerateTypeIfNeeded(t->type());
-      },
-      [&](Default) { return 0u; });
-  if (type_id == 0u) {
-    return false;
-  }
+    uint32_t dim_literal = SpvDim2D;
+    if (dim == ast::TextureDimension::k1d) {
+        dim_literal = SpvDim1D;
+        if (texture->Is<sem::SampledTexture>()) {
+            push_capability(SpvCapabilitySampled1D);
+        } else if (texture->Is<sem::StorageTexture>()) {
+            push_capability(SpvCapabilityImage1D);
+        }
+    }
+    if (dim == ast::TextureDimension::k3d) {
+        dim_literal = SpvDim3D;
+    }
+    if (dim == ast::TextureDimension::kCube || dim == ast::TextureDimension::kCubeArray) {
+        dim_literal = SpvDimCube;
+    }
 
-  uint32_t format_literal = SpvImageFormat_::SpvImageFormatUnknown;
-  if (auto* t = texture->As<sem::StorageTexture>()) {
-    format_literal = convert_texel_format_to_spv(t->texel_format());
-  }
+    uint32_t ms_literal = 0u;
+    if (texture->IsAnyOf<sem::MultisampledTexture, sem::DepthMultisampledTexture>()) {
+        ms_literal = 1u;
+    }
 
-  push_type(spv::Op::OpTypeImage,
-            {result, Operand::Int(type_id), Operand::Int(dim_literal),
-             Operand::Int(depth_literal), Operand::Int(array_literal),
-             Operand::Int(ms_literal), Operand::Int(sampled_literal),
-             Operand::Int(format_literal)});
+    uint32_t depth_literal = 0u;
+    // The Vulkan spec says: The "Depth" operand of OpTypeImage is ignored.
+    // In SPIRV, 0 means not depth, 1 means depth, and 2 means unknown.
+    // Using anything other than 0 is problematic on various Vulkan drivers.
 
-  return true;
+    uint32_t sampled_literal = 2u;
+    if (texture->IsAnyOf<sem::MultisampledTexture, sem::SampledTexture, sem::DepthTexture,
+                         sem::DepthMultisampledTexture>()) {
+        sampled_literal = 1u;
+    }
+
+    if (dim == ast::TextureDimension::kCubeArray) {
+        if (texture->IsAnyOf<sem::SampledTexture, sem::DepthTexture>()) {
+            push_capability(SpvCapabilitySampledCubeArray);
+        }
+    }
+
+    uint32_t type_id = Switch(
+        texture,
+        [&](const sem::DepthTexture*) { return GenerateTypeIfNeeded(builder_.create<sem::F32>()); },
+        [&](const sem::DepthMultisampledTexture*) {
+            return GenerateTypeIfNeeded(builder_.create<sem::F32>());
+        },
+        [&](const sem::SampledTexture* t) { return GenerateTypeIfNeeded(t->type()); },
+        [&](const sem::MultisampledTexture* t) { return GenerateTypeIfNeeded(t->type()); },
+        [&](const sem::StorageTexture* t) { return GenerateTypeIfNeeded(t->type()); },
+        [&](Default) { return 0u; });
+    if (type_id == 0u) {
+        return false;
+    }
+
+    uint32_t format_literal = SpvImageFormat_::SpvImageFormatUnknown;
+    if (auto* t = texture->As<sem::StorageTexture>()) {
+        format_literal = convert_texel_format_to_spv(t->texel_format());
+    }
+
+    push_type(spv::Op::OpTypeImage,
+              {result, Operand(type_id), Operand(dim_literal), Operand(depth_literal),
+               Operand(array_literal), Operand(ms_literal), Operand(sampled_literal),
+               Operand(format_literal)});
+
+    return true;
 }
 
 bool Builder::GenerateArrayType(const sem::Array* ary, const Operand& result) {
-  auto elem_type = GenerateTypeIfNeeded(ary->ElemType());
-  if (elem_type == 0) {
-    return false;
-  }
-
-  auto result_id = result.to_i();
-  if (ary->IsRuntimeSized()) {
-    push_type(spv::Op::OpTypeRuntimeArray, {result, Operand::Int(elem_type)});
-  } else {
-    auto len_id = GenerateConstantIfNeeded(ScalarConstant::U32(ary->Count()));
-    if (len_id == 0) {
-      return false;
+    auto elem_type = GenerateTypeIfNeeded(ary->ElemType());
+    if (elem_type == 0) {
+        return false;
     }
 
-    push_type(spv::Op::OpTypeArray,
-              {result, Operand::Int(elem_type), Operand::Int(len_id)});
-  }
+    auto result_id = std::get<uint32_t>(result);
+    if (ary->IsRuntimeSized()) {
+        push_type(spv::Op::OpTypeRuntimeArray, {result, Operand(elem_type)});
+    } else {
+        auto len_id = GenerateConstantIfNeeded(ScalarConstant::U32(ary->Count()));
+        if (len_id == 0) {
+            return false;
+        }
 
-  push_annot(spv::Op::OpDecorate,
-             {Operand::Int(result_id), Operand::Int(SpvDecorationArrayStride),
-              Operand::Int(ary->Stride())});
-  return true;
-}
+        push_type(spv::Op::OpTypeArray, {result, Operand(elem_type), Operand(len_id)});
+    }
 
-bool Builder::GenerateMatrixType(const sem::Matrix* mat,
-                                 const Operand& result) {
-  auto* col_type = builder_.create<sem::Vector>(mat->type(), mat->rows());
-  auto col_type_id = GenerateTypeIfNeeded(col_type);
-  if (has_error()) {
-    return false;
-  }
-
-  push_type(spv::Op::OpTypeMatrix,
-            {result, Operand::Int(col_type_id), Operand::Int(mat->columns())});
-  return true;
-}
-
-bool Builder::GeneratePointerType(const sem::Pointer* ptr,
-                                  const Operand& result) {
-  auto subtype_id = GenerateTypeIfNeeded(ptr->StoreType());
-  if (subtype_id == 0) {
-    return false;
-  }
-
-  auto stg_class = ConvertStorageClass(ptr->StorageClass());
-  if (stg_class == SpvStorageClassMax) {
-    error_ = "invalid storage class for pointer";
-    return false;
-  }
-
-  push_type(spv::Op::OpTypePointer,
-            {result, Operand::Int(stg_class), Operand::Int(subtype_id)});
-
-  return true;
-}
-
-bool Builder::GenerateReferenceType(const sem::Reference* ref,
-                                    const Operand& result) {
-  auto subtype_id = GenerateTypeIfNeeded(ref->StoreType());
-  if (subtype_id == 0) {
-    return false;
-  }
-
-  auto stg_class = ConvertStorageClass(ref->StorageClass());
-  if (stg_class == SpvStorageClassMax) {
-    error_ = "invalid storage class for reference";
-    return false;
-  }
-
-  push_type(spv::Op::OpTypePointer,
-            {result, Operand::Int(stg_class), Operand::Int(subtype_id)});
-
-  return true;
-}
-
-bool Builder::GenerateStructType(const sem::Struct* struct_type,
-                                 const Operand& result) {
-  auto struct_id = result.to_i();
-
-  if (struct_type->Name().IsValid()) {
-    push_debug(
-        spv::Op::OpName,
-        {Operand::Int(struct_id),
-         Operand::String(builder_.Symbols().NameFor(struct_type->Name()))});
-  }
-
-  OperandList ops;
-  ops.push_back(result);
-
-  auto* decl = struct_type->Declaration();
-  if (decl &&
-      ast::HasAttribute<transform::AddSpirvBlockAttribute::SpirvBlockAttribute>(
-          decl->attributes)) {
     push_annot(spv::Op::OpDecorate,
-               {Operand::Int(struct_id), Operand::Int(SpvDecorationBlock)});
-  }
+               {Operand(result_id), U32Operand(SpvDecorationArrayStride), Operand(ary->Stride())});
+    return true;
+}
 
-  for (uint32_t i = 0; i < struct_type->Members().size(); ++i) {
-    auto mem_id = GenerateStructMember(struct_id, i, struct_type->Members()[i]);
-    if (mem_id == 0) {
-      return false;
+bool Builder::GenerateMatrixType(const sem::Matrix* mat, const Operand& result) {
+    auto* col_type = builder_.create<sem::Vector>(mat->type(), mat->rows());
+    auto col_type_id = GenerateTypeIfNeeded(col_type);
+    if (has_error()) {
+        return false;
     }
 
-    ops.push_back(Operand::Int(mem_id));
-  }
+    push_type(spv::Op::OpTypeMatrix, {result, Operand(col_type_id), Operand(mat->columns())});
+    return true;
+}
 
-  push_type(spv::Op::OpTypeStruct, std::move(ops));
-  return true;
+bool Builder::GeneratePointerType(const sem::Pointer* ptr, const Operand& result) {
+    auto subtype_id = GenerateTypeIfNeeded(ptr->StoreType());
+    if (subtype_id == 0) {
+        return false;
+    }
+
+    auto stg_class = ConvertStorageClass(ptr->StorageClass());
+    if (stg_class == SpvStorageClassMax) {
+        error_ = "invalid storage class for pointer";
+        return false;
+    }
+
+    push_type(spv::Op::OpTypePointer, {result, U32Operand(stg_class), Operand(subtype_id)});
+
+    return true;
+}
+
+bool Builder::GenerateReferenceType(const sem::Reference* ref, const Operand& result) {
+    auto subtype_id = GenerateTypeIfNeeded(ref->StoreType());
+    if (subtype_id == 0) {
+        return false;
+    }
+
+    auto stg_class = ConvertStorageClass(ref->StorageClass());
+    if (stg_class == SpvStorageClassMax) {
+        error_ = "invalid storage class for reference";
+        return false;
+    }
+
+    push_type(spv::Op::OpTypePointer, {result, U32Operand(stg_class), Operand(subtype_id)});
+
+    return true;
+}
+
+bool Builder::GenerateStructType(const sem::Struct* struct_type, const Operand& result) {
+    auto struct_id = std::get<uint32_t>(result);
+
+    if (struct_type->Name().IsValid()) {
+        push_debug(spv::Op::OpName,
+                   {Operand(struct_id), Operand(builder_.Symbols().NameFor(struct_type->Name()))});
+    }
+
+    OperandList ops;
+    ops.push_back(result);
+
+    auto* decl = struct_type->Declaration();
+    if (decl && ast::HasAttribute<transform::AddSpirvBlockAttribute::SpirvBlockAttribute>(
+                    decl->attributes)) {
+        push_annot(spv::Op::OpDecorate, {Operand(struct_id), U32Operand(SpvDecorationBlock)});
+    }
+
+    for (uint32_t i = 0; i < struct_type->Members().size(); ++i) {
+        auto mem_id = GenerateStructMember(struct_id, i, struct_type->Members()[i]);
+        if (mem_id == 0) {
+            return false;
+        }
+
+        ops.push_back(Operand(mem_id));
+    }
+
+    push_type(spv::Op::OpTypeStruct, std::move(ops));
+    return true;
 }
 
 uint32_t Builder::GenerateStructMember(uint32_t struct_id,
                                        uint32_t idx,
                                        const sem::StructMember* member) {
-  push_debug(spv::Op::OpMemberName,
-             {Operand::Int(struct_id), Operand::Int(idx),
-              Operand::String(builder_.Symbols().NameFor(member->Name()))});
+    push_debug(spv::Op::OpMemberName, {Operand(struct_id), Operand(idx),
+                                       Operand(builder_.Symbols().NameFor(member->Name()))});
 
-  // Note: This will generate layout annotations for *all* structs, whether or
-  // not they are used in host-shareable variables. This is officially ok in
-  // SPIR-V 1.0 through 1.3. If / when we migrate to using SPIR-V 1.4 we'll have
-  // to only generate the layout info for structs used for certain storage
-  // classes.
+    // Note: This will generate layout annotations for *all* structs, whether or
+    // not they are used in host-shareable variables. This is officially ok in
+    // SPIR-V 1.0 through 1.3. If / when we migrate to using SPIR-V 1.4 we'll have
+    // to only generate the layout info for structs used for certain storage
+    // classes.
 
-  push_annot(
-      spv::Op::OpMemberDecorate,
-      {Operand::Int(struct_id), Operand::Int(idx),
-       Operand::Int(SpvDecorationOffset), Operand::Int(member->Offset())});
-
-  // Infer and emit matrix layout.
-  auto* matrix_type = GetNestedMatrixType(member->Type());
-  if (matrix_type) {
     push_annot(spv::Op::OpMemberDecorate,
-               {Operand::Int(struct_id), Operand::Int(idx),
-                Operand::Int(SpvDecorationColMajor)});
-    if (!matrix_type->type()->Is<sem::F32>()) {
-      error_ = "matrix scalar element type must be f32";
-      return 0;
+               {Operand(struct_id), Operand(idx), U32Operand(SpvDecorationOffset),
+                Operand(member->Offset())});
+
+    // Infer and emit matrix layout.
+    auto* matrix_type = GetNestedMatrixType(member->Type());
+    if (matrix_type) {
+        push_annot(spv::Op::OpMemberDecorate,
+                   {Operand(struct_id), Operand(idx), U32Operand(SpvDecorationColMajor)});
+        if (!matrix_type->type()->Is<sem::F32>()) {
+            error_ = "matrix scalar element type must be f32";
+            return 0;
+        }
+        const uint32_t scalar_elem_size = 4;
+        const uint32_t effective_row_count = (matrix_type->rows() == 2) ? 2 : 4;
+        push_annot(spv::Op::OpMemberDecorate,
+                   {Operand(struct_id), Operand(idx), U32Operand(SpvDecorationMatrixStride),
+                    Operand(effective_row_count * scalar_elem_size)});
     }
-    const auto scalar_elem_size = 4;
-    const auto effective_row_count = (matrix_type->rows() == 2) ? 2 : 4;
-    push_annot(spv::Op::OpMemberDecorate,
-               {Operand::Int(struct_id), Operand::Int(idx),
-                Operand::Int(SpvDecorationMatrixStride),
-                Operand::Int(effective_row_count * scalar_elem_size)});
-  }
 
-  return GenerateTypeIfNeeded(member->Type());
+    return GenerateTypeIfNeeded(member->Type());
 }
 
-bool Builder::GenerateVectorType(const sem::Vector* vec,
-                                 const Operand& result) {
-  auto type_id = GenerateTypeIfNeeded(vec->type());
-  if (has_error()) {
-    return false;
-  }
+bool Builder::GenerateVectorType(const sem::Vector* vec, const Operand& result) {
+    auto type_id = GenerateTypeIfNeeded(vec->type());
+    if (has_error()) {
+        return false;
+    }
 
-  push_type(spv::Op::OpTypeVector,
-            {result, Operand::Int(type_id), Operand::Int(vec->Width())});
-  return true;
+    push_type(spv::Op::OpTypeVector, {result, Operand(type_id), Operand(vec->Width())});
+    return true;
 }
 
 SpvStorageClass Builder::ConvertStorageClass(ast::StorageClass klass) const {
-  switch (klass) {
-    case ast::StorageClass::kInvalid:
-      return SpvStorageClassMax;
-    case ast::StorageClass::kInput:
-      return SpvStorageClassInput;
-    case ast::StorageClass::kOutput:
-      return SpvStorageClassOutput;
-    case ast::StorageClass::kUniform:
-      return SpvStorageClassUniform;
-    case ast::StorageClass::kWorkgroup:
-      return SpvStorageClassWorkgroup;
-    case ast::StorageClass::kUniformConstant:
-      return SpvStorageClassUniformConstant;
-    case ast::StorageClass::kStorage:
-      return SpvStorageClassStorageBuffer;
-    case ast::StorageClass::kPrivate:
-      return SpvStorageClassPrivate;
-    case ast::StorageClass::kFunction:
-      return SpvStorageClassFunction;
-    case ast::StorageClass::kNone:
-      break;
-  }
-  return SpvStorageClassMax;
+    switch (klass) {
+        case ast::StorageClass::kInvalid:
+            return SpvStorageClassMax;
+        case ast::StorageClass::kInput:
+            return SpvStorageClassInput;
+        case ast::StorageClass::kOutput:
+            return SpvStorageClassOutput;
+        case ast::StorageClass::kUniform:
+            return SpvStorageClassUniform;
+        case ast::StorageClass::kWorkgroup:
+            return SpvStorageClassWorkgroup;
+        case ast::StorageClass::kHandle:
+            return SpvStorageClassUniformConstant;
+        case ast::StorageClass::kStorage:
+            return SpvStorageClassStorageBuffer;
+        case ast::StorageClass::kPrivate:
+            return SpvStorageClassPrivate;
+        case ast::StorageClass::kFunction:
+            return SpvStorageClassFunction;
+        case ast::StorageClass::kNone:
+            break;
+    }
+    return SpvStorageClassMax;
 }
 
-SpvBuiltIn Builder::ConvertBuiltin(ast::Builtin builtin,
-                                   ast::StorageClass storage) {
-  switch (builtin) {
-    case ast::Builtin::kPosition:
-      if (storage == ast::StorageClass::kInput) {
-        return SpvBuiltInFragCoord;
-      } else if (storage == ast::StorageClass::kOutput) {
-        return SpvBuiltInPosition;
-      } else {
-        TINT_ICE(Writer, builder_.Diagnostics())
-            << "invalid storage class for builtin";
-        break;
-      }
-    case ast::Builtin::kVertexIndex:
-      return SpvBuiltInVertexIndex;
-    case ast::Builtin::kInstanceIndex:
-      return SpvBuiltInInstanceIndex;
-    case ast::Builtin::kFrontFacing:
-      return SpvBuiltInFrontFacing;
-    case ast::Builtin::kFragDepth:
-      return SpvBuiltInFragDepth;
-    case ast::Builtin::kLocalInvocationId:
-      return SpvBuiltInLocalInvocationId;
-    case ast::Builtin::kLocalInvocationIndex:
-      return SpvBuiltInLocalInvocationIndex;
-    case ast::Builtin::kGlobalInvocationId:
-      return SpvBuiltInGlobalInvocationId;
-    case ast::Builtin::kPointSize:
-      return SpvBuiltInPointSize;
-    case ast::Builtin::kWorkgroupId:
-      return SpvBuiltInWorkgroupId;
-    case ast::Builtin::kNumWorkgroups:
-      return SpvBuiltInNumWorkgroups;
-    case ast::Builtin::kSampleIndex:
-      push_capability(SpvCapabilitySampleRateShading);
-      return SpvBuiltInSampleId;
-    case ast::Builtin::kSampleMask:
-      return SpvBuiltInSampleMask;
-    case ast::Builtin::kNone:
-      break;
-  }
-  return SpvBuiltInMax;
+SpvBuiltIn Builder::ConvertBuiltin(ast::Builtin builtin, ast::StorageClass storage) {
+    switch (builtin) {
+        case ast::Builtin::kPosition:
+            if (storage == ast::StorageClass::kInput) {
+                return SpvBuiltInFragCoord;
+            } else if (storage == ast::StorageClass::kOutput) {
+                return SpvBuiltInPosition;
+            } else {
+                TINT_ICE(Writer, builder_.Diagnostics()) << "invalid storage class for builtin";
+                break;
+            }
+        case ast::Builtin::kVertexIndex:
+            return SpvBuiltInVertexIndex;
+        case ast::Builtin::kInstanceIndex:
+            return SpvBuiltInInstanceIndex;
+        case ast::Builtin::kFrontFacing:
+            return SpvBuiltInFrontFacing;
+        case ast::Builtin::kFragDepth:
+            return SpvBuiltInFragDepth;
+        case ast::Builtin::kLocalInvocationId:
+            return SpvBuiltInLocalInvocationId;
+        case ast::Builtin::kLocalInvocationIndex:
+            return SpvBuiltInLocalInvocationIndex;
+        case ast::Builtin::kGlobalInvocationId:
+            return SpvBuiltInGlobalInvocationId;
+        case ast::Builtin::kPointSize:
+            return SpvBuiltInPointSize;
+        case ast::Builtin::kWorkgroupId:
+            return SpvBuiltInWorkgroupId;
+        case ast::Builtin::kNumWorkgroups:
+            return SpvBuiltInNumWorkgroups;
+        case ast::Builtin::kSampleIndex:
+            push_capability(SpvCapabilitySampleRateShading);
+            return SpvBuiltInSampleId;
+        case ast::Builtin::kSampleMask:
+            return SpvBuiltInSampleMask;
+        case ast::Builtin::kNone:
+            break;
+    }
+    return SpvBuiltInMax;
 }
 
 void Builder::AddInterpolationDecorations(uint32_t id,
                                           ast::InterpolationType type,
                                           ast::InterpolationSampling sampling) {
-  switch (type) {
-    case ast::InterpolationType::kLinear:
-      push_annot(spv::Op::OpDecorate,
-                 {Operand::Int(id), Operand::Int(SpvDecorationNoPerspective)});
-      break;
-    case ast::InterpolationType::kFlat:
-      push_annot(spv::Op::OpDecorate,
-                 {Operand::Int(id), Operand::Int(SpvDecorationFlat)});
-      break;
-    case ast::InterpolationType::kPerspective:
-      break;
-  }
-  switch (sampling) {
-    case ast::InterpolationSampling::kCentroid:
-      push_annot(spv::Op::OpDecorate,
-                 {Operand::Int(id), Operand::Int(SpvDecorationCentroid)});
-      break;
-    case ast::InterpolationSampling::kSample:
-      push_capability(SpvCapabilitySampleRateShading);
-      push_annot(spv::Op::OpDecorate,
-                 {Operand::Int(id), Operand::Int(SpvDecorationSample)});
-      break;
-    case ast::InterpolationSampling::kCenter:
-    case ast::InterpolationSampling::kNone:
-      break;
-  }
+    switch (type) {
+        case ast::InterpolationType::kLinear:
+            push_annot(spv::Op::OpDecorate, {Operand(id), U32Operand(SpvDecorationNoPerspective)});
+            break;
+        case ast::InterpolationType::kFlat:
+            push_annot(spv::Op::OpDecorate, {Operand(id), U32Operand(SpvDecorationFlat)});
+            break;
+        case ast::InterpolationType::kPerspective:
+            break;
+    }
+    switch (sampling) {
+        case ast::InterpolationSampling::kCentroid:
+            push_annot(spv::Op::OpDecorate, {Operand(id), U32Operand(SpvDecorationCentroid)});
+            break;
+        case ast::InterpolationSampling::kSample:
+            push_capability(SpvCapabilitySampleRateShading);
+            push_annot(spv::Op::OpDecorate, {Operand(id), U32Operand(SpvDecorationSample)});
+            break;
+        case ast::InterpolationSampling::kCenter:
+        case ast::InterpolationSampling::kNone:
+            break;
+    }
 }
 
-SpvImageFormat Builder::convert_texel_format_to_spv(
-    const ast::TexelFormat format) {
-  switch (format) {
-    case ast::TexelFormat::kR32Uint:
-      return SpvImageFormatR32ui;
-    case ast::TexelFormat::kR32Sint:
-      return SpvImageFormatR32i;
-    case ast::TexelFormat::kR32Float:
-      return SpvImageFormatR32f;
-    case ast::TexelFormat::kRgba8Unorm:
-      return SpvImageFormatRgba8;
-    case ast::TexelFormat::kRgba8Snorm:
-      return SpvImageFormatRgba8Snorm;
-    case ast::TexelFormat::kRgba8Uint:
-      return SpvImageFormatRgba8ui;
-    case ast::TexelFormat::kRgba8Sint:
-      return SpvImageFormatRgba8i;
-    case ast::TexelFormat::kRg32Uint:
-      push_capability(SpvCapabilityStorageImageExtendedFormats);
-      return SpvImageFormatRg32ui;
-    case ast::TexelFormat::kRg32Sint:
-      push_capability(SpvCapabilityStorageImageExtendedFormats);
-      return SpvImageFormatRg32i;
-    case ast::TexelFormat::kRg32Float:
-      push_capability(SpvCapabilityStorageImageExtendedFormats);
-      return SpvImageFormatRg32f;
-    case ast::TexelFormat::kRgba16Uint:
-      return SpvImageFormatRgba16ui;
-    case ast::TexelFormat::kRgba16Sint:
-      return SpvImageFormatRgba16i;
-    case ast::TexelFormat::kRgba16Float:
-      return SpvImageFormatRgba16f;
-    case ast::TexelFormat::kRgba32Uint:
-      return SpvImageFormatRgba32ui;
-    case ast::TexelFormat::kRgba32Sint:
-      return SpvImageFormatRgba32i;
-    case ast::TexelFormat::kRgba32Float:
-      return SpvImageFormatRgba32f;
-    case ast::TexelFormat::kNone:
-      return SpvImageFormatUnknown;
-  }
-  return SpvImageFormatUnknown;
+SpvImageFormat Builder::convert_texel_format_to_spv(const ast::TexelFormat format) {
+    switch (format) {
+        case ast::TexelFormat::kR32Uint:
+            return SpvImageFormatR32ui;
+        case ast::TexelFormat::kR32Sint:
+            return SpvImageFormatR32i;
+        case ast::TexelFormat::kR32Float:
+            return SpvImageFormatR32f;
+        case ast::TexelFormat::kRgba8Unorm:
+            return SpvImageFormatRgba8;
+        case ast::TexelFormat::kRgba8Snorm:
+            return SpvImageFormatRgba8Snorm;
+        case ast::TexelFormat::kRgba8Uint:
+            return SpvImageFormatRgba8ui;
+        case ast::TexelFormat::kRgba8Sint:
+            return SpvImageFormatRgba8i;
+        case ast::TexelFormat::kRg32Uint:
+            push_capability(SpvCapabilityStorageImageExtendedFormats);
+            return SpvImageFormatRg32ui;
+        case ast::TexelFormat::kRg32Sint:
+            push_capability(SpvCapabilityStorageImageExtendedFormats);
+            return SpvImageFormatRg32i;
+        case ast::TexelFormat::kRg32Float:
+            push_capability(SpvCapabilityStorageImageExtendedFormats);
+            return SpvImageFormatRg32f;
+        case ast::TexelFormat::kRgba16Uint:
+            return SpvImageFormatRgba16ui;
+        case ast::TexelFormat::kRgba16Sint:
+            return SpvImageFormatRgba16i;
+        case ast::TexelFormat::kRgba16Float:
+            return SpvImageFormatRgba16f;
+        case ast::TexelFormat::kRgba32Uint:
+            return SpvImageFormatRgba32ui;
+        case ast::TexelFormat::kRgba32Sint:
+            return SpvImageFormatRgba32i;
+        case ast::TexelFormat::kRgba32Float:
+            return SpvImageFormatRgba32f;
+        case ast::TexelFormat::kNone:
+            return SpvImageFormatUnknown;
+    }
+    return SpvImageFormatUnknown;
 }
 
 bool Builder::push_function_inst(spv::Op op, const OperandList& operands) {
-  if (functions_.empty()) {
-    std::ostringstream ss;
-    ss << "Internal error: trying to add SPIR-V instruction " << int(op)
-       << " outside a function";
-    error_ = ss.str();
-    return false;
-  }
-  functions_.back().push_inst(op, operands);
-  return true;
+    if (functions_.empty()) {
+        std::ostringstream ss;
+        ss << "Internal error: trying to add SPIR-V instruction " << int(op)
+           << " outside a function";
+        error_ = ss.str();
+        return false;
+    }
+    functions_.back().push_inst(op, operands);
+    return true;
 }
 
 bool Builder::InsideBasicBlock() const {
-  if (functions_.empty()) {
-    return false;
-  }
-  const auto& instructions = functions_.back().instructions();
-  if (instructions.empty()) {
-    // The Function object does not explicitly represent its entry block
-    // label.  So return *true* because an empty list means the only
-    // thing in the function is that entry block label.
+    if (functions_.empty()) {
+        return false;
+    }
+    const auto& instructions = functions_.back().instructions();
+    if (instructions.empty()) {
+        // The Function object does not explicitly represent its entry block
+        // label.  So return *true* because an empty list means the only
+        // thing in the function is that entry block label.
+        return true;
+    }
+    const auto& inst = instructions.back();
+    switch (inst.opcode()) {
+        case spv::Op::OpBranch:
+        case spv::Op::OpBranchConditional:
+        case spv::Op::OpSwitch:
+        case spv::Op::OpReturn:
+        case spv::Op::OpReturnValue:
+        case spv::Op::OpUnreachable:
+        case spv::Op::OpKill:
+        case spv::Op::OpTerminateInvocation:
+            return false;
+        default:
+            break;
+    }
     return true;
-  }
-  const auto& inst = instructions.back();
-  switch (inst.opcode()) {
-    case spv::Op::OpBranch:
-    case spv::Op::OpBranchConditional:
-    case spv::Op::OpSwitch:
-    case spv::Op::OpReturn:
-    case spv::Op::OpReturnValue:
-    case spv::Op::OpUnreachable:
-    case spv::Op::OpKill:
-    case spv::Op::OpTerminateInvocation:
-      return false;
-    default:
-      break;
-  }
-  return true;
 }
 
-Builder::ContinuingInfo::ContinuingInfo(
-    const ast::Statement* the_last_statement,
-    uint32_t loop_id,
-    uint32_t break_id)
-    : last_statement(the_last_statement),
-      loop_header_id(loop_id),
-      break_target_id(break_id) {
-  TINT_ASSERT(Writer, last_statement != nullptr);
-  TINT_ASSERT(Writer, loop_header_id != 0u);
-  TINT_ASSERT(Writer, break_target_id != 0u);
+Builder::ContinuingInfo::ContinuingInfo(const ast::Statement* the_last_statement,
+                                        uint32_t loop_id,
+                                        uint32_t break_id)
+    : last_statement(the_last_statement), loop_header_id(loop_id), break_target_id(break_id) {
+    TINT_ASSERT(Writer, last_statement != nullptr);
+    TINT_ASSERT(Writer, loop_header_id != 0u);
+    TINT_ASSERT(Writer, break_target_id != 0u);
 }
 
 Builder::Backedge::Backedge(spv::Op the_opcode, OperandList the_operands)
     : opcode(the_opcode), operands(the_operands) {}
 
 Builder::Backedge::Backedge(const Builder::Backedge& other) = default;
-Builder::Backedge& Builder::Backedge::operator=(
-    const Builder::Backedge& other) = default;
+Builder::Backedge& Builder::Backedge::operator=(const Builder::Backedge& other) = default;
 Builder::Backedge::~Backedge() = default;
 
+Builder::Scope::Scope() = default;
+Builder::Scope::Scope(const Scope&) = default;
+Builder::Scope::~Scope() = default;
+
 }  // namespace tint::writer::spirv
diff --git a/src/tint/writer/spirv/builder.h b/src/tint/writer/spirv/builder.h
index 7ad9cf2..34cfd76 100644
--- a/src/tint/writer/spirv/builder.h
+++ b/src/tint/writer/spirv/builder.h
@@ -36,7 +36,7 @@
 #include "src/tint/program_builder.h"
 #include "src/tint/scope_stack.h"
 #include "src/tint/sem/builtin.h"
-#include "src/tint/sem/storage_texture_type.h"
+#include "src/tint/sem/storage_texture.h"
 #include "src/tint/writer/spirv/function.h"
 #include "src/tint/writer/spirv/scalar_constant.h"
 
@@ -52,592 +52,605 @@
 
 /// Builder class to create SPIR-V instructions from a module.
 class Builder {
- public:
-  /// Contains information for generating accessor chains
-  struct AccessorInfo {
-    AccessorInfo();
-    ~AccessorInfo();
+  public:
+    /// Contains information for generating accessor chains
+    struct AccessorInfo {
+        AccessorInfo();
+        ~AccessorInfo();
 
-    /// The ID of the current chain source. The chain source may change as we
-    /// evaluate the access chain. The chain source always points to the ID
-    /// which we will use to evaluate the current set of accessors. This maybe
-    /// the original variable, or maybe an intermediary if we had to evaulate
-    /// the access chain early (in the case of a swizzle of an access chain).
-    uint32_t source_id;
-    /// The type of the current chain source. This type matches the deduced
-    /// result_type of the current source defined above.
-    const sem::Type* source_type;
-    /// A list of access chain indices to emit. Note, we _only_ have access
-    /// chain indices if the source is reference.
-    std::vector<uint32_t> access_chain_indices;
-  };
+        /// The ID of the current chain source. The chain source may change as we
+        /// evaluate the access chain. The chain source always points to the ID
+        /// which we will use to evaluate the current set of accessors. This maybe
+        /// the original variable, or maybe an intermediary if we had to evaulate
+        /// the access chain early (in the case of a swizzle of an access chain).
+        uint32_t source_id;
+        /// The type of the current chain source. This type matches the deduced
+        /// result_type of the current source defined above.
+        const sem::Type* source_type;
+        /// A list of access chain indices to emit. Note, we _only_ have access
+        /// chain indices if the source is reference.
+        std::vector<uint32_t> access_chain_indices;
+    };
 
-  /// Constructor
-  /// @param program the program
-  /// @param zero_initialize_workgroup_memory `true` to initialize all the
-  /// variables in the Workgroup storage class with OpConstantNull
-  Builder(const Program* program,
-          bool zero_initialize_workgroup_memory = false);
-  ~Builder();
+    /// Constructor
+    /// @param program the program
+    /// @param zero_initialize_workgroup_memory `true` to initialize all the
+    /// variables in the Workgroup storage class with OpConstantNull
+    explicit Builder(const Program* program, bool zero_initialize_workgroup_memory = false);
+    ~Builder();
 
-  /// Generates the SPIR-V instructions for the given program
-  /// @returns true if the SPIR-V was successfully built
-  bool Build();
+    /// Generates the SPIR-V instructions for the given program
+    /// @returns true if the SPIR-V was successfully built
+    bool Build();
 
-  /// @returns the error string or blank if no error was reported.
-  const std::string& error() const { return error_; }
-  /// @returns true if the builder encountered an error
-  bool has_error() const { return !error_.empty(); }
+    /// @returns the error string or blank if no error was reported.
+    const std::string& error() const { return error_; }
+    /// @returns true if the builder encountered an error
+    bool has_error() const { return !error_.empty(); }
 
-  /// @returns the number of uint32_t's needed to make up the results
-  uint32_t total_size() const;
+    /// @returns the number of uint32_t's needed to make up the results
+    uint32_t total_size() const;
 
-  /// @returns the id bound for this program
-  uint32_t id_bound() const { return next_id_; }
+    /// @returns the id bound for this program
+    uint32_t id_bound() const { return next_id_; }
 
-  /// @returns the next id to be used
-  uint32_t next_id() {
-    auto id = next_id_;
-    next_id_ += 1;
-    return id;
-  }
-
-  /// Iterates over all the instructions in the correct order and calls the
-  /// given callback
-  /// @param cb the callback to execute
-  void iterate(std::function<void(const Instruction&)> cb) const;
-
-  /// Adds an instruction to the list of capabilities, if the capability
-  /// hasn't already been added.
-  /// @param cap the capability to set
-  void push_capability(uint32_t cap);
-  /// @returns the capabilities
-  const InstructionList& capabilities() const { return capabilities_; }
-  /// Adds an instruction to the extensions
-  /// @param op the op to set
-  /// @param operands the operands for the instruction
-  void push_extension(spv::Op op, const OperandList& operands) {
-    extensions_.push_back(Instruction{op, operands});
-  }
-  /// @returns the extensions
-  const InstructionList& extensions() const { return extensions_; }
-  /// Adds an instruction to the ext import
-  /// @param op the op to set
-  /// @param operands the operands for the instruction
-  void push_ext_import(spv::Op op, const OperandList& operands) {
-    ext_imports_.push_back(Instruction{op, operands});
-  }
-  /// @returns the ext imports
-  const InstructionList& ext_imports() const { return ext_imports_; }
-  /// Adds an instruction to the memory model
-  /// @param op the op to set
-  /// @param operands the operands for the instruction
-  void push_memory_model(spv::Op op, const OperandList& operands) {
-    memory_model_.push_back(Instruction{op, operands});
-  }
-  /// @returns the memory model
-  const InstructionList& memory_model() const { return memory_model_; }
-  /// Adds an instruction to the entry points
-  /// @param op the op to set
-  /// @param operands the operands for the instruction
-  void push_entry_point(spv::Op op, const OperandList& operands) {
-    entry_points_.push_back(Instruction{op, operands});
-  }
-  /// @returns the entry points
-  const InstructionList& entry_points() const { return entry_points_; }
-  /// Adds an instruction to the execution modes
-  /// @param op the op to set
-  /// @param operands the operands for the instruction
-  void push_execution_mode(spv::Op op, const OperandList& operands) {
-    execution_modes_.push_back(Instruction{op, operands});
-  }
-  /// @returns the execution modes
-  const InstructionList& execution_modes() const { return execution_modes_; }
-  /// Adds an instruction to the debug
-  /// @param op the op to set
-  /// @param operands the operands for the instruction
-  void push_debug(spv::Op op, const OperandList& operands) {
-    debug_.push_back(Instruction{op, operands});
-  }
-  /// @returns the debug instructions
-  const InstructionList& debug() const { return debug_; }
-  /// Adds an instruction to the types
-  /// @param op the op to set
-  /// @param operands the operands for the instruction
-  void push_type(spv::Op op, const OperandList& operands) {
-    types_.push_back(Instruction{op, operands});
-  }
-  /// @returns the type instructions
-  const InstructionList& types() const { return types_; }
-  /// Adds an instruction to the annotations
-  /// @param op the op to set
-  /// @param operands the operands for the instruction
-  void push_annot(spv::Op op, const OperandList& operands) {
-    annotations_.push_back(Instruction{op, operands});
-  }
-  /// @returns the annotations
-  const InstructionList& annots() const { return annotations_; }
-
-  /// Adds a function to the builder
-  /// @param func the function to add
-  void push_function(const Function& func) {
-    functions_.push_back(func);
-    current_label_id_ = func.label_id();
-  }
-  /// @returns the functions
-  const std::vector<Function>& functions() const { return functions_; }
-  /// Pushes an instruction to the current function. If we're outside
-  /// a function then issue an internal error and return false.
-  /// @param op the operation
-  /// @param operands the operands
-  /// @returns true if we succeeded
-  bool push_function_inst(spv::Op op, const OperandList& operands);
-  /// Pushes a variable to the current function
-  /// @param operands the variable operands
-  void push_function_var(const OperandList& operands) {
-    if (functions_.empty()) {
-      TINT_ICE(Writer, builder_.Diagnostics())
-          << "push_function_var() called without a function";
+    /// @returns the next id to be used
+    uint32_t next_id() {
+        auto id = next_id_;
+        next_id_ += 1;
+        return id;
     }
-    functions_.back().push_var(operands);
-  }
 
-  /// @returns true if the current instruction insertion point is
-  /// inside a basic block.
-  bool InsideBasicBlock() const;
+    /// Iterates over all the instructions in the correct order and calls the
+    /// given callback
+    /// @param cb the callback to execute
+    void iterate(std::function<void(const Instruction&)> cb) const;
 
-  /// Converts a storage class to a SPIR-V storage class.
-  /// @param klass the storage class to convert
-  /// @returns the SPIR-V storage class or SpvStorageClassMax on error.
-  SpvStorageClass ConvertStorageClass(ast::StorageClass klass) const;
-  /// Converts a builtin to a SPIR-V builtin and pushes a capability if needed.
-  /// @param builtin the builtin to convert
-  /// @param storage the 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);
+    /// Adds an instruction to the list of capabilities, if the capability
+    /// hasn't already been added.
+    /// @param cap the capability to set
+    void push_capability(uint32_t cap);
+    /// @returns the capabilities
+    const InstructionList& capabilities() const { return capabilities_; }
+    /// Adds an instruction to the extensions
+    /// @param op the op to set
+    /// @param operands the operands for the instruction
+    void push_extension(spv::Op op, const OperandList& operands) {
+        extensions_.push_back(Instruction{op, operands});
+    }
+    /// @returns the extensions
+    const InstructionList& extensions() const { return extensions_; }
+    /// Adds an instruction to the ext import
+    /// @param op the op to set
+    /// @param operands the operands for the instruction
+    void push_ext_import(spv::Op op, const OperandList& operands) {
+        ext_imports_.push_back(Instruction{op, operands});
+    }
+    /// @returns the ext imports
+    const InstructionList& ext_imports() const { return ext_imports_; }
+    /// Adds an instruction to the memory model
+    /// @param op the op to set
+    /// @param operands the operands for the instruction
+    void push_memory_model(spv::Op op, const OperandList& operands) {
+        memory_model_.push_back(Instruction{op, operands});
+    }
+    /// @returns the memory model
+    const InstructionList& memory_model() const { return memory_model_; }
+    /// Adds an instruction to the entry points
+    /// @param op the op to set
+    /// @param operands the operands for the instruction
+    void push_entry_point(spv::Op op, const OperandList& operands) {
+        entry_points_.push_back(Instruction{op, operands});
+    }
+    /// @returns the entry points
+    const InstructionList& entry_points() const { return entry_points_; }
+    /// Adds an instruction to the execution modes
+    /// @param op the op to set
+    /// @param operands the operands for the instruction
+    void push_execution_mode(spv::Op op, const OperandList& operands) {
+        execution_modes_.push_back(Instruction{op, operands});
+    }
+    /// @returns the execution modes
+    const InstructionList& execution_modes() const { return execution_modes_; }
+    /// Adds an instruction to the debug
+    /// @param op the op to set
+    /// @param operands the operands for the instruction
+    void push_debug(spv::Op op, const OperandList& operands) {
+        debug_.push_back(Instruction{op, operands});
+    }
+    /// @returns the debug instructions
+    const InstructionList& debug() const { return debug_; }
+    /// Adds an instruction to the types
+    /// @param op the op to set
+    /// @param operands the operands for the instruction
+    void push_type(spv::Op op, const OperandList& operands) {
+        types_.push_back(Instruction{op, operands});
+    }
+    /// @returns the type instructions
+    const InstructionList& types() const { return types_; }
+    /// Adds an instruction to the annotations
+    /// @param op the op to set
+    /// @param operands the operands for the instruction
+    void push_annot(spv::Op op, const OperandList& operands) {
+        annotations_.push_back(Instruction{op, operands});
+    }
+    /// @returns the annotations
+    const InstructionList& annots() const { return annotations_; }
 
-  /// Converts an interpolate attribute to SPIR-V decorations and pushes a
-  /// capability if needed.
-  /// @param id the id to decorate
-  /// @param type the interpolation type
-  /// @param sampling the interpolation sampling
-  void AddInterpolationDecorations(uint32_t id,
-                                   ast::InterpolationType type,
-                                   ast::InterpolationSampling sampling);
+    /// Adds a function to the builder
+    /// @param func the function to add
+    void push_function(const Function& func) {
+        functions_.push_back(func);
+        current_label_id_ = func.label_id();
+    }
+    /// @returns the functions
+    const std::vector<Function>& functions() const { return functions_; }
+    /// Pushes an instruction to the current function. If we're outside
+    /// a function then issue an internal error and return false.
+    /// @param op the operation
+    /// @param operands the operands
+    /// @returns true if we succeeded
+    bool push_function_inst(spv::Op op, const OperandList& operands);
+    /// Pushes a variable to the current function
+    /// @param operands the variable operands
+    void push_function_var(const OperandList& operands) {
+        if (functions_.empty()) {
+            TINT_ICE(Writer, builder_.Diagnostics())
+                << "push_function_var() called without a function";
+        }
+        functions_.back().push_var(operands);
+    }
 
-  /// Generates a label for the given id. Emits an error and returns false if
-  /// we're currently outside a function.
-  /// @param id the id to use for the label
-  /// @returns true on success.
-  bool GenerateLabel(uint32_t id);
-  /// Generates an assignment statement
-  /// @param assign the statement to generate
-  /// @returns true if the statement was successfully generated
-  bool GenerateAssignStatement(const ast::AssignmentStatement* assign);
-  /// Generates a block statement, wrapped in a push/pop scope
-  /// @param stmt the statement to generate
-  /// @returns true if the statement was successfully generated
-  bool GenerateBlockStatement(const ast::BlockStatement* stmt);
-  /// Generates a block statement
-  /// @param stmt the statement to generate
-  /// @returns true if the statement was successfully generated
-  bool GenerateBlockStatementWithoutScoping(const ast::BlockStatement* stmt);
-  /// Generates a break statement
-  /// @param stmt the statement to generate
-  /// @returns true if the statement was successfully generated
-  bool GenerateBreakStatement(const ast::BreakStatement* stmt);
-  /// Generates a continue statement
-  /// @param stmt the statement to generate
-  /// @returns true if the statement was successfully generated
-  bool GenerateContinueStatement(const ast::ContinueStatement* stmt);
-  /// Generates a discard statement
-  /// @param stmt the statement to generate
-  /// @returns true if the statement was successfully generated
-  bool GenerateDiscardStatement(const ast::DiscardStatement* stmt);
-  /// Generates an entry point instruction
-  /// @param func the function
-  /// @param id the id of the function
-  /// @returns true if the instruction was generated, false otherwise
-  bool GenerateEntryPoint(const ast::Function* func, uint32_t id);
-  /// Generates execution modes for an entry point
-  /// @param func the function
-  /// @param id the id of the function
-  /// @returns false on failure
-  bool GenerateExecutionModes(const ast::Function* func, uint32_t id);
-  /// Generates an expression
-  /// @param expr the expression to generate
-  /// @returns the resulting ID of the expression or 0 on error
-  uint32_t GenerateExpression(const ast::Expression* expr);
-  /// Generates the instructions for a function
-  /// @param func the function to generate
-  /// @returns true if the instructions were generated
-  bool GenerateFunction(const ast::Function* func);
-  /// Generates a function type if not already created
-  /// @param func the function to generate for
-  /// @returns the ID to use for the function type. Returns 0 on failure.
-  uint32_t GenerateFunctionTypeIfNeeded(const sem::Function* func);
-  /// Generates access control annotations if needed
-  /// @param type the type to generate for
-  /// @param struct_id the struct id
-  /// @param member_idx the member index
-  void GenerateMemberAccessIfNeeded(const sem::Type* type,
-                                    uint32_t struct_id,
-                                    uint32_t member_idx);
-  /// Generates a function variable
-  /// @param var the variable
-  /// @returns true if the variable was generated
-  bool GenerateFunctionVariable(const ast::Variable* var);
-  /// Generates a global variable
-  /// @param var the variable to generate
-  /// @returns true if the variable is emited.
-  bool GenerateGlobalVariable(const ast::Variable* var);
-  /// Generates an index accessor expression.
-  ///
-  /// For more information on accessors see the "Pointer evaluation" section of
-  /// the WGSL specification.
-  ///
-  /// @param expr the expresssion to generate
-  /// @returns the id of the expression or 0 on failure
-  uint32_t GenerateAccessorExpression(const ast::Expression* expr);
-  /// Generates an index accessor
-  /// @param expr the accessor to generate
-  /// @param info the current accessor information
-  /// @returns true if the accessor was generated successfully
-  bool GenerateIndexAccessor(const ast::IndexAccessorExpression* expr,
-                             AccessorInfo* info);
-  /// Generates a member accessor
-  /// @param expr the accessor to generate
-  /// @param info the current accessor information
-  /// @returns true if the accessor was generated successfully
-  bool GenerateMemberAccessor(const ast::MemberAccessorExpression* expr,
-                              AccessorInfo* info);
-  /// Generates an identifier expression
-  /// @param expr the expresssion to generate
-  /// @returns the id of the expression or 0 on failure
-  uint32_t GenerateIdentifierExpression(const ast::IdentifierExpression* expr);
-  /// Generates a unary op expression
-  /// @param expr the expression to generate
-  /// @returns the id of the expression or 0 on failure
-  uint32_t GenerateUnaryOpExpression(const ast::UnaryOpExpression* expr);
-  /// Generates an if statement
-  /// @param stmt the statement to generate
-  /// @returns true on success
-  bool GenerateIfStatement(const ast::IfStatement* stmt);
-  /// Generates an import instruction for the "GLSL.std.450" extended
-  /// instruction set, if one doesn't exist yet, and returns the import ID.
-  /// @returns the import ID, or 0 on error.
-  uint32_t GetGLSLstd450Import();
-  /// Generates a constructor expression
-  /// @param var the variable generated for, nullptr if no variable associated.
-  /// @param expr the expression to generate
-  /// @returns the ID of the expression or 0 on failure.
-  uint32_t GenerateConstructorExpression(const ast::Variable* var,
-                                         const ast::Expression* expr);
-  /// Generates a literal constant if needed
-  /// @param var the variable generated for, nullptr if no variable associated.
-  /// @param lit the literal to generate
-  /// @returns the ID on success or 0 on failure
-  uint32_t GenerateLiteralIfNeeded(const ast::Variable* var,
-                                   const ast::LiteralExpression* lit);
-  /// Generates a binary expression
-  /// @param expr the expression to generate
-  /// @returns the expression ID on success or 0 otherwise
-  uint32_t GenerateBinaryExpression(const ast::BinaryExpression* expr);
-  /// Generates a bitcast expression
-  /// @param expr the expression to generate
-  /// @returns the expression ID on success or 0 otherwise
-  uint32_t GenerateBitcastExpression(const ast::BitcastExpression* expr);
-  /// Generates a short circuting binary expression
-  /// @param expr the expression to generate
-  /// @returns teh expression ID on success or 0 otherwise
-  uint32_t GenerateShortCircuitBinaryExpression(
-      const ast::BinaryExpression* expr);
-  /// Generates a call expression
-  /// @param expr the expression to generate
-  /// @returns the expression ID on success or 0 otherwise
-  uint32_t GenerateCallExpression(const ast::CallExpression* expr);
-  /// Handles generating a function call expression
-  /// @param call the call expression
-  /// @param function the function being called
-  /// @returns the expression ID on success or 0 otherwise
-  uint32_t GenerateFunctionCall(const sem::Call* call,
-                                const sem::Function* function);
-  /// Handles generating a builtin call expression
-  /// @param call the call expression
-  /// @param builtin the builtin being called
-  /// @returns the expression ID on success or 0 otherwise
-  uint32_t GenerateBuiltinCall(const sem::Call* call,
-                               const sem::Builtin* builtin);
-  /// Handles generating a type constructor or type conversion expression
-  /// @param call the call expression
-  /// @param var the variable that is being initialized. May be null.
-  /// @returns the expression ID on success or 0 otherwise
-  uint32_t GenerateTypeConstructorOrConversion(const sem::Call* call,
-                                               const ast::Variable* var);
-  /// Generates a texture builtin call. Emits an error and returns false if
-  /// we're currently outside a function.
-  /// @param call the call expression
-  /// @param builtin the semantic information for the texture builtin
-  /// @param result_type result type operand of the texture instruction
-  /// @param result_id result identifier operand of the texture instruction
-  /// parameters
-  /// @returns true on success
-  bool GenerateTextureBuiltin(const sem::Call* call,
-                              const sem::Builtin* builtin,
-                              spirv::Operand result_type,
-                              spirv::Operand result_id);
-  /// Generates a control barrier statement.
-  /// @param builtin the semantic information for the barrier builtin call
-  /// @returns true on success
-  bool GenerateControlBarrierBuiltin(const sem::Builtin* builtin);
-  /// Generates an atomic builtin call.
-  /// @param call the call expression
-  /// @param builtin the semantic information for the atomic builtin call
-  /// @param result_type result type operand of the texture instruction
-  /// @param result_id result identifier operand of the texture instruction
-  /// @returns true on success
-  bool GenerateAtomicBuiltin(const sem::Call* call,
-                             const sem::Builtin* builtin,
-                             Operand result_type,
-                             Operand result_id);
-  /// Generates a sampled image
-  /// @param texture_type the texture type
-  /// @param texture_operand the texture operand
-  /// @param sampler_operand the sampler operand
-  /// @returns the expression ID
-  uint32_t GenerateSampledImage(const sem::Type* texture_type,
-                                Operand texture_operand,
-                                Operand sampler_operand);
-  /// Generates a cast or object copy for the expression result,
-  /// or return the ID generated the expression if it is already
-  /// of the right type.
-  /// @param to_type the type we're casting too
-  /// @param from_expr the expression to cast
-  /// @param is_global_init if this is a global initializer
-  /// @returns the expression ID on success or 0 otherwise
-  uint32_t GenerateCastOrCopyOrPassthrough(const sem::Type* to_type,
-                                           const ast::Expression* from_expr,
-                                           bool is_global_init);
-  /// Generates a loop statement
-  /// @param stmt the statement to generate
-  /// @returns true on successful generation
-  bool GenerateLoopStatement(const ast::LoopStatement* stmt);
-  /// Generates a return statement
-  /// @param stmt the statement to generate
-  /// @returns true on success, false otherwise
-  bool GenerateReturnStatement(const ast::ReturnStatement* stmt);
-  /// Generates a switch statement
-  /// @param stmt the statement to generate
-  /// @returns ture on success, false otherwise
-  bool GenerateSwitchStatement(const ast::SwitchStatement* stmt);
-  /// Generates a conditional section merge block
-  /// @param cond the condition
-  /// @param true_body the statements making up the true block
-  /// @param cur_else_idx the index of the current else statement to process
-  /// @param else_stmts the list of all else statements
-  /// @returns true on success, false on failure
-  bool GenerateConditionalBlock(const ast::Expression* cond,
-                                const ast::BlockStatement* true_body,
-                                size_t cur_else_idx,
-                                const ast::ElseStatementList& else_stmts);
-  /// Generates a statement
-  /// @param stmt the statement to generate
-  /// @returns true if the statement was generated
-  bool GenerateStatement(const ast::Statement* stmt);
-  /// Generates an expression. If the WGSL expression does not have reference
-  /// type, then return the SPIR-V ID for the expression. Otherwise implement
-  /// the WGSL Load Rule: generate an OpLoad and return the ID of the result.
-  /// Returns 0 if the expression could not be generated.
-  /// @param expr the semantic expression node to be generated
-  /// @returns the the ID of the expression, or loaded expression
-  uint32_t GenerateExpressionWithLoadIfNeeded(const sem::Expression* expr);
-  /// Generates an expression. If the WGSL expression does not have reference
-  /// type, then return the SPIR-V ID for the expression. Otherwise implement
-  /// the WGSL Load Rule: generate an OpLoad and return the ID of the result.
-  /// Returns 0 if the expression could not be generated.
-  /// @param expr the AST expression to be generated
-  /// @returns the the ID of the expression, or loaded expression
-  uint32_t GenerateExpressionWithLoadIfNeeded(const ast::Expression* expr);
-  /// Generates an OpLoad on the given ID if it has reference type in WGSL,
-  /// othewrise return the ID itself.
-  /// @param type the type of the expression
-  /// @param id the SPIR-V id of the experssion
-  /// @returns the ID of the loaded value or `id` if type is not a reference
-  uint32_t GenerateLoadIfNeeded(const sem::Type* type, uint32_t id);
-  /// Generates an OpStore. Emits an error and returns false if we're
-  /// currently outside a function.
-  /// @param to the ID to store too
-  /// @param from the ID to store from
-  /// @returns true on success
-  bool GenerateStore(uint32_t to, uint32_t from);
-  /// Generates a type if not already created
-  /// @param type the type to create
-  /// @returns the ID to use for the given type. Returns 0 on unknown type.
-  uint32_t GenerateTypeIfNeeded(const sem::Type* type);
-  /// Generates a texture type declaration
-  /// @param texture the texture to generate
-  /// @param result the result operand
-  /// @returns true if the texture was successfully generated
-  bool GenerateTextureType(const sem::Texture* texture, const Operand& result);
-  /// Generates an array type declaration
-  /// @param ary the array to generate
-  /// @param result the result operand
-  /// @returns true if the array was successfully generated
-  bool GenerateArrayType(const sem::Array* ary, const Operand& result);
-  /// Generates a matrix type declaration
-  /// @param mat the matrix to generate
-  /// @param result the result operand
-  /// @returns true if the matrix was successfully generated
-  bool GenerateMatrixType(const sem::Matrix* mat, const Operand& result);
-  /// Generates a pointer type declaration
-  /// @param ptr the pointer type to generate
-  /// @param result the result operand
-  /// @returns true if the pointer was successfully generated
-  bool GeneratePointerType(const sem::Pointer* ptr, const Operand& result);
-  /// Generates a reference type declaration
-  /// @param ref the reference type to generate
-  /// @param result the result operand
-  /// @returns true if the reference was successfully generated
-  bool GenerateReferenceType(const sem::Reference* ref, const Operand& result);
-  /// Generates a vector type declaration
-  /// @param struct_type the vector to generate
-  /// @param result the result operand
-  /// @returns true if the vector was successfully generated
-  bool GenerateStructType(const sem::Struct* struct_type,
-                          const Operand& result);
-  /// Generates a struct member
-  /// @param struct_id the id of the parent structure
-  /// @param idx the index of the member
-  /// @param member the member to generate
-  /// @returns the id of the struct member or 0 on error.
-  uint32_t GenerateStructMember(uint32_t struct_id,
-                                uint32_t idx,
-                                const sem::StructMember* member);
-  /// Generates a variable declaration statement
-  /// @param stmt the statement to generate
-  /// @returns true on successfull generation
-  bool GenerateVariableDeclStatement(const ast::VariableDeclStatement* stmt);
-  /// Generates a vector type declaration
-  /// @param vec the vector to generate
-  /// @param result the result operand
-  /// @returns true if the vector was successfully generated
-  bool GenerateVectorType(const sem::Vector* vec, const Operand& result);
+    /// @returns true if the current instruction insertion point is
+    /// inside a basic block.
+    bool InsideBasicBlock() const;
 
-  /// Generates instructions to splat `scalar_id` into a vector of type
-  /// `vec_type`
-  /// @param scalar_id scalar to splat
-  /// @param vec_type type of vector
-  /// @returns id of the new vector
-  uint32_t GenerateSplat(uint32_t scalar_id, const sem::Type* vec_type);
+    /// Converts a storage class to a SPIR-V storage class.
+    /// @param klass the storage class to convert
+    /// @returns the SPIR-V storage class or SpvStorageClassMax on error.
+    SpvStorageClass ConvertStorageClass(ast::StorageClass klass) const;
+    /// Converts a builtin to a SPIR-V builtin and pushes a capability if needed.
+    /// @param builtin the builtin to convert
+    /// @param storage the 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);
 
-  /// Generates instructions to add or subtract two matrices
-  /// @param lhs_id id of multiplicand
-  /// @param rhs_id id of multiplier
-  /// @param type type of both matrices and of result
-  /// @param op one of `spv::Op::OpFAdd` or `spv::Op::OpFSub`
-  /// @returns id of the result matrix
-  uint32_t GenerateMatrixAddOrSub(uint32_t lhs_id,
-                                  uint32_t rhs_id,
-                                  const sem::Matrix* type,
-                                  spv::Op op);
+    /// Converts an interpolate attribute to SPIR-V decorations and pushes a
+    /// capability if needed.
+    /// @param id the id to decorate
+    /// @param type the interpolation type
+    /// @param sampling the interpolation sampling
+    void AddInterpolationDecorations(uint32_t id,
+                                     ast::InterpolationType type,
+                                     ast::InterpolationSampling sampling);
 
-  /// Converts TexelFormat to SPIR-V and pushes an appropriate capability.
-  /// @param format AST image format type
-  /// @returns SPIR-V image format type
-  SpvImageFormat convert_texel_format_to_spv(const ast::TexelFormat format);
+    /// Generates a extension for the given extension kind. Emits an error and
+    /// returns false if the extension kind is not supported.
+    /// @param kind ExtensionKind of the extension to generate
+    /// @returns true on success.
+    bool GenerateExtension(ast::Enable::ExtensionKind kind);
+    /// Generates a label for the given id. Emits an error and returns false if
+    /// we're currently outside a function.
+    /// @param id the id to use for the label
+    /// @returns true on success.
+    bool GenerateLabel(uint32_t id);
+    /// Generates an assignment statement
+    /// @param assign the statement to generate
+    /// @returns true if the statement was successfully generated
+    bool GenerateAssignStatement(const ast::AssignmentStatement* assign);
+    /// Generates a block statement, wrapped in a push/pop scope
+    /// @param stmt the statement to generate
+    /// @returns true if the statement was successfully generated
+    bool GenerateBlockStatement(const ast::BlockStatement* stmt);
+    /// Generates a block statement
+    /// @param stmt the statement to generate
+    /// @returns true if the statement was successfully generated
+    bool GenerateBlockStatementWithoutScoping(const ast::BlockStatement* stmt);
+    /// Generates a break statement
+    /// @param stmt the statement to generate
+    /// @returns true if the statement was successfully generated
+    bool GenerateBreakStatement(const ast::BreakStatement* stmt);
+    /// Generates a continue statement
+    /// @param stmt the statement to generate
+    /// @returns true if the statement was successfully generated
+    bool GenerateContinueStatement(const ast::ContinueStatement* stmt);
+    /// Generates a discard statement
+    /// @param stmt the statement to generate
+    /// @returns true if the statement was successfully generated
+    bool GenerateDiscardStatement(const ast::DiscardStatement* stmt);
+    /// Generates an entry point instruction
+    /// @param func the function
+    /// @param id the id of the function
+    /// @returns true if the instruction was generated, false otherwise
+    bool GenerateEntryPoint(const ast::Function* func, uint32_t id);
+    /// Generates execution modes for an entry point
+    /// @param func the function
+    /// @param id the id of the function
+    /// @returns false on failure
+    bool GenerateExecutionModes(const ast::Function* func, uint32_t id);
+    /// Generates an expression
+    /// @param expr the expression to generate
+    /// @returns the resulting ID of the expression or 0 on error
+    uint32_t GenerateExpression(const ast::Expression* expr);
+    /// Generates the instructions for a function
+    /// @param func the function to generate
+    /// @returns true if the instructions were generated
+    bool GenerateFunction(const ast::Function* func);
+    /// Generates a function type if not already created
+    /// @param func the function to generate for
+    /// @returns the ID to use for the function type. Returns 0 on failure.
+    uint32_t GenerateFunctionTypeIfNeeded(const sem::Function* func);
+    /// Generates access control annotations if needed
+    /// @param type the type to generate for
+    /// @param struct_id the struct id
+    /// @param member_idx the member index
+    void GenerateMemberAccessIfNeeded(const sem::Type* type,
+                                      uint32_t struct_id,
+                                      uint32_t member_idx);
+    /// Generates a function variable
+    /// @param var the variable
+    /// @returns true if the variable was generated
+    bool GenerateFunctionVariable(const ast::Variable* var);
+    /// Generates a global variable
+    /// @param var the variable to generate
+    /// @returns true if the variable is emited.
+    bool GenerateGlobalVariable(const ast::Variable* var);
+    /// Generates an index accessor expression.
+    ///
+    /// For more information on accessors see the "Pointer evaluation" section of
+    /// the WGSL specification.
+    ///
+    /// @param expr the expresssion to generate
+    /// @returns the id of the expression or 0 on failure
+    uint32_t GenerateAccessorExpression(const ast::Expression* expr);
+    /// Generates an index accessor
+    /// @param expr the accessor to generate
+    /// @param info the current accessor information
+    /// @returns true if the accessor was generated successfully
+    bool GenerateIndexAccessor(const ast::IndexAccessorExpression* expr, AccessorInfo* info);
+    /// Generates a member accessor
+    /// @param expr the accessor to generate
+    /// @param info the current accessor information
+    /// @returns true if the accessor was generated successfully
+    bool GenerateMemberAccessor(const ast::MemberAccessorExpression* expr, AccessorInfo* info);
+    /// Generates an identifier expression
+    /// @param expr the expresssion to generate
+    /// @returns the id of the expression or 0 on failure
+    uint32_t GenerateIdentifierExpression(const ast::IdentifierExpression* expr);
+    /// Generates a unary op expression
+    /// @param expr the expression to generate
+    /// @returns the id of the expression or 0 on failure
+    uint32_t GenerateUnaryOpExpression(const ast::UnaryOpExpression* expr);
+    /// Generates an if statement
+    /// @param stmt the statement to generate
+    /// @returns true on success
+    bool GenerateIfStatement(const ast::IfStatement* stmt);
+    /// Generates an import instruction for the "GLSL.std.450" extended
+    /// instruction set, if one doesn't exist yet, and returns the import ID.
+    /// @returns the import ID, or 0 on error.
+    uint32_t GetGLSLstd450Import();
+    /// Generates a constructor expression
+    /// @param var the variable generated for, nullptr if no variable associated.
+    /// @param expr the expression to generate
+    /// @returns the ID of the expression or 0 on failure.
+    uint32_t GenerateConstructorExpression(const ast::Variable* var, const ast::Expression* expr);
+    /// Generates a literal constant if needed
+    /// @param var the variable generated for, nullptr if no variable associated.
+    /// @param lit the literal to generate
+    /// @returns the ID on success or 0 on failure
+    uint32_t GenerateLiteralIfNeeded(const ast::Variable* var, const ast::LiteralExpression* lit);
+    /// Generates a binary expression
+    /// @param expr the expression to generate
+    /// @returns the expression ID on success or 0 otherwise
+    uint32_t GenerateBinaryExpression(const ast::BinaryExpression* expr);
+    /// Generates a bitcast expression
+    /// @param expr the expression to generate
+    /// @returns the expression ID on success or 0 otherwise
+    uint32_t GenerateBitcastExpression(const ast::BitcastExpression* expr);
+    /// Generates a short circuting binary expression
+    /// @param expr the expression to generate
+    /// @returns teh expression ID on success or 0 otherwise
+    uint32_t GenerateShortCircuitBinaryExpression(const ast::BinaryExpression* expr);
+    /// Generates a call expression
+    /// @param expr the expression to generate
+    /// @returns the expression ID on success or 0 otherwise
+    uint32_t GenerateCallExpression(const ast::CallExpression* expr);
+    /// Handles generating a function call expression
+    /// @param call the call expression
+    /// @param function the function being called
+    /// @returns the expression ID on success or 0 otherwise
+    uint32_t GenerateFunctionCall(const sem::Call* call, const sem::Function* function);
+    /// Handles generating a builtin call expression
+    /// @param call the call expression
+    /// @param builtin the builtin being called
+    /// @returns the expression ID on success or 0 otherwise
+    uint32_t GenerateBuiltinCall(const sem::Call* call, const sem::Builtin* builtin);
+    /// Handles generating a type constructor or type conversion expression
+    /// @param call the call expression
+    /// @param var the variable that is being initialized. May be null.
+    /// @returns the expression ID on success or 0 otherwise
+    uint32_t GenerateTypeConstructorOrConversion(const sem::Call* call, const ast::Variable* var);
+    /// Generates a texture builtin call. Emits an error and returns false if
+    /// we're currently outside a function.
+    /// @param call the call expression
+    /// @param builtin the semantic information for the texture builtin
+    /// @param result_type result type operand of the texture instruction
+    /// @param result_id result identifier operand of the texture instruction
+    /// parameters
+    /// @returns true on success
+    bool GenerateTextureBuiltin(const sem::Call* call,
+                                const sem::Builtin* builtin,
+                                spirv::Operand result_type,
+                                spirv::Operand result_id);
+    /// Generates a control barrier statement.
+    /// @param builtin the semantic information for the barrier builtin call
+    /// @returns true on success
+    bool GenerateControlBarrierBuiltin(const sem::Builtin* builtin);
+    /// Generates an atomic builtin call.
+    /// @param call the call expression
+    /// @param builtin the semantic information for the atomic builtin call
+    /// @param result_type result type operand of the texture instruction
+    /// @param result_id result identifier operand of the texture instruction
+    /// @returns true on success
+    bool GenerateAtomicBuiltin(const sem::Call* call,
+                               const sem::Builtin* builtin,
+                               Operand result_type,
+                               Operand result_id);
+    /// Generates a sampled image
+    /// @param texture_type the texture type
+    /// @param texture_operand the texture operand
+    /// @param sampler_operand the sampler operand
+    /// @returns the expression ID
+    uint32_t GenerateSampledImage(const sem::Type* texture_type,
+                                  Operand texture_operand,
+                                  Operand sampler_operand);
+    /// Generates a cast or object copy for the expression result,
+    /// or return the ID generated the expression if it is already
+    /// of the right type.
+    /// @param to_type the type we're casting too
+    /// @param from_expr the expression to cast
+    /// @param is_global_init if this is a global initializer
+    /// @returns the expression ID on success or 0 otherwise
+    uint32_t GenerateCastOrCopyOrPassthrough(const sem::Type* to_type,
+                                             const ast::Expression* from_expr,
+                                             bool is_global_init);
+    /// Generates a loop statement
+    /// @param stmt the statement to generate
+    /// @returns true on successful generation
+    bool GenerateLoopStatement(const ast::LoopStatement* stmt);
+    /// Generates a return statement
+    /// @param stmt the statement to generate
+    /// @returns true on success, false otherwise
+    bool GenerateReturnStatement(const ast::ReturnStatement* stmt);
+    /// Generates a switch statement
+    /// @param stmt the statement to generate
+    /// @returns ture on success, false otherwise
+    bool GenerateSwitchStatement(const ast::SwitchStatement* stmt);
+    /// Generates a conditional section merge block
+    /// @param cond the condition
+    /// @param true_body the statements making up the true block
+    /// @param else_stmt the statement for the else block
+    /// @returns true on success, false on failure
+    bool GenerateConditionalBlock(const ast::Expression* cond,
+                                  const ast::BlockStatement* true_body,
+                                  const ast::Statement* else_stmt);
+    /// Generates a statement
+    /// @param stmt the statement to generate
+    /// @returns true if the statement was generated
+    bool GenerateStatement(const ast::Statement* stmt);
+    /// Generates an expression. If the WGSL expression does not have reference
+    /// type, then return the SPIR-V ID for the expression. Otherwise implement
+    /// the WGSL Load Rule: generate an OpLoad and return the ID of the result.
+    /// Returns 0 if the expression could not be generated.
+    /// @param expr the semantic expression node to be generated
+    /// @returns the the ID of the expression, or loaded expression
+    uint32_t GenerateExpressionWithLoadIfNeeded(const sem::Expression* expr);
+    /// Generates an expression. If the WGSL expression does not have reference
+    /// type, then return the SPIR-V ID for the expression. Otherwise implement
+    /// the WGSL Load Rule: generate an OpLoad and return the ID of the result.
+    /// Returns 0 if the expression could not be generated.
+    /// @param expr the AST expression to be generated
+    /// @returns the the ID of the expression, or loaded expression
+    uint32_t GenerateExpressionWithLoadIfNeeded(const ast::Expression* expr);
+    /// Generates an OpLoad on the given ID if it has reference type in WGSL,
+    /// othewrise return the ID itself.
+    /// @param type the type of the expression
+    /// @param id the SPIR-V id of the experssion
+    /// @returns the ID of the loaded value or `id` if type is not a reference
+    uint32_t GenerateLoadIfNeeded(const sem::Type* type, uint32_t id);
+    /// Generates an OpStore. Emits an error and returns false if we're
+    /// currently outside a function.
+    /// @param to the ID to store too
+    /// @param from the ID to store from
+    /// @returns true on success
+    bool GenerateStore(uint32_t to, uint32_t from);
+    /// Generates a type if not already created
+    /// @param type the type to create
+    /// @returns the ID to use for the given type. Returns 0 on unknown type.
+    uint32_t GenerateTypeIfNeeded(const sem::Type* type);
+    /// Generates a texture type declaration
+    /// @param texture the texture to generate
+    /// @param result the result operand
+    /// @returns true if the texture was successfully generated
+    bool GenerateTextureType(const sem::Texture* texture, const Operand& result);
+    /// Generates an array type declaration
+    /// @param ary the array to generate
+    /// @param result the result operand
+    /// @returns true if the array was successfully generated
+    bool GenerateArrayType(const sem::Array* ary, const Operand& result);
+    /// Generates a matrix type declaration
+    /// @param mat the matrix to generate
+    /// @param result the result operand
+    /// @returns true if the matrix was successfully generated
+    bool GenerateMatrixType(const sem::Matrix* mat, const Operand& result);
+    /// Generates a pointer type declaration
+    /// @param ptr the pointer type to generate
+    /// @param result the result operand
+    /// @returns true if the pointer was successfully generated
+    bool GeneratePointerType(const sem::Pointer* ptr, const Operand& result);
+    /// Generates a reference type declaration
+    /// @param ref the reference type to generate
+    /// @param result the result operand
+    /// @returns true if the reference was successfully generated
+    bool GenerateReferenceType(const sem::Reference* ref, const Operand& result);
+    /// Generates a vector type declaration
+    /// @param struct_type the vector to generate
+    /// @param result the result operand
+    /// @returns true if the vector was successfully generated
+    bool GenerateStructType(const sem::Struct* struct_type, const Operand& result);
+    /// Generates a struct member
+    /// @param struct_id the id of the parent structure
+    /// @param idx the index of the member
+    /// @param member the member to generate
+    /// @returns the id of the struct member or 0 on error.
+    uint32_t GenerateStructMember(uint32_t struct_id,
+                                  uint32_t idx,
+                                  const sem::StructMember* member);
+    /// Generates a variable declaration statement
+    /// @param stmt the statement to generate
+    /// @returns true on successfull generation
+    bool GenerateVariableDeclStatement(const ast::VariableDeclStatement* stmt);
+    /// Generates a vector type declaration
+    /// @param vec the vector to generate
+    /// @param result the result operand
+    /// @returns true if the vector was successfully generated
+    bool GenerateVectorType(const sem::Vector* vec, const Operand& result);
 
-  /// Determines if the given type constructor is created from constant values
-  /// @param expr the expression to check
-  /// @returns true if the constructor is constant
-  bool IsConstructorConst(const ast::Expression* expr);
+    /// Generates instructions to splat `scalar_id` into a vector of type
+    /// `vec_type`
+    /// @param scalar_id scalar to splat
+    /// @param vec_type type of vector
+    /// @returns id of the new vector
+    uint32_t GenerateSplat(uint32_t scalar_id, const sem::Type* vec_type);
 
- private:
-  /// @returns an Operand with a new result ID in it. Increments the next_id_
-  /// automatically.
-  Operand result_op();
+    /// Generates instructions to add or subtract two matrices
+    /// @param lhs_id id of multiplicand
+    /// @param rhs_id id of multiplier
+    /// @param type type of both matrices and of result
+    /// @param op one of `spv::Op::OpFAdd` or `spv::Op::OpFSub`
+    /// @returns id of the result matrix
+    uint32_t GenerateMatrixAddOrSub(uint32_t lhs_id,
+                                    uint32_t rhs_id,
+                                    const sem::Matrix* type,
+                                    spv::Op op);
 
-  /// @returns the resolved type of the ast::Expression `expr`
-  /// @param expr the expression
-  const sem::Type* TypeOf(const ast::Expression* expr) const {
-    return builder_.TypeOf(expr);
-  }
+    /// Converts TexelFormat to SPIR-V and pushes an appropriate capability.
+    /// @param format AST image format type
+    /// @returns SPIR-V image format type
+    SpvImageFormat convert_texel_format_to_spv(const ast::TexelFormat format);
 
-  /// Generates a scalar constant if needed
-  /// @param constant the constant to generate.
-  /// @returns the ID on success or 0 on failure
-  uint32_t GenerateConstantIfNeeded(const ScalarConstant& constant);
+    /// Determines if the given type constructor is created from constant values
+    /// @param expr the expression to check
+    /// @returns true if the constructor is constant
+    bool IsConstructorConst(const ast::Expression* expr);
 
-  /// Generates a constant-null of the given type, if needed
-  /// @param type the type of the constant null to generate.
-  /// @returns the ID on success or 0 on failure
-  uint32_t GenerateConstantNullIfNeeded(const sem::Type* type);
+  private:
+    /// @returns an Operand with a new result ID in it. Increments the next_id_
+    /// automatically.
+    Operand result_op();
 
-  /// Generates a vector constant splat if needed
-  /// @param type the type of the vector to generate
-  /// @param value_id the ID of the scalar value to splat
-  /// @returns the ID on success or 0 on failure
-  uint32_t GenerateConstantVectorSplatIfNeeded(const sem::Vector* type,
-                                               uint32_t value_id);
+    /// @returns the resolved type of the ast::Expression `expr`
+    /// @param expr the expression
+    const sem::Type* TypeOf(const ast::Expression* expr) const { return builder_.TypeOf(expr); }
 
-  ProgramBuilder builder_;
-  std::string error_;
-  uint32_t next_id_ = 1;
-  uint32_t current_label_id_ = 0;
-  InstructionList capabilities_;
-  InstructionList extensions_;
-  InstructionList ext_imports_;
-  InstructionList memory_model_;
-  InstructionList entry_points_;
-  InstructionList execution_modes_;
-  InstructionList debug_;
-  InstructionList types_;
-  InstructionList annotations_;
-  std::vector<Function> functions_;
+    /// Generates a scalar constant if needed
+    /// @param constant the constant to generate.
+    /// @returns the ID on success or 0 on failure
+    uint32_t GenerateConstantIfNeeded(const ScalarConstant& constant);
 
-  std::unordered_map<std::string, uint32_t> import_name_to_id_;
-  std::unordered_map<Symbol, uint32_t> func_symbol_to_id_;
-  std::unordered_map<sem::CallTargetSignature, uint32_t> func_sig_to_id_;
-  std::unordered_map<const sem::Type*, uint32_t> type_to_id_;
-  std::unordered_map<ScalarConstant, uint32_t> const_to_id_;
-  std::unordered_map<std::string, uint32_t> type_constructor_to_id_;
-  std::unordered_map<const sem::Type*, uint32_t> const_null_to_id_;
-  std::unordered_map<uint64_t, uint32_t> const_splat_to_id_;
-  std::unordered_map<const sem::Type*, uint32_t>
-      texture_type_to_sampled_image_type_id_;
-  ScopeStack<uint32_t> scope_stack_;
-  std::unordered_map<uint32_t, const ast::Variable*> spirv_id_to_variable_;
-  std::vector<uint32_t> merge_stack_;
-  std::vector<uint32_t> continue_stack_;
-  std::unordered_set<uint32_t> capability_set_;
-  bool has_overridable_workgroup_size_ = false;
-  bool zero_initialize_workgroup_memory_ = false;
+    /// Generates a constant-null of the given type, if needed
+    /// @param type the type of the constant null to generate.
+    /// @returns the ID on success or 0 on failure
+    uint32_t GenerateConstantNullIfNeeded(const sem::Type* type);
 
-  struct ContinuingInfo {
-    ContinuingInfo(const ast::Statement* last_statement,
-                   uint32_t loop_header_id,
-                   uint32_t break_target_id);
-    // The last statement in the continiung block.
-    const ast::Statement* const last_statement = nullptr;
-    // The ID of the loop header
-    const uint32_t loop_header_id = 0u;
-    // The ID of the merge block for the loop.
-    const uint32_t break_target_id = 0u;
-  };
-  // Stack of nodes, where each is the last statement in a surrounding
-  // continuing block.
-  std::vector<ContinuingInfo> continuing_stack_;
+    /// Generates a vector constant splat if needed
+    /// @param type the type of the vector to generate
+    /// @param value_id the ID of the scalar value to splat
+    /// @returns the ID on success or 0 on failure
+    uint32_t GenerateConstantVectorSplatIfNeeded(const sem::Vector* type, uint32_t value_id);
 
-  // The instruction to emit as the backedge of a loop.
-  struct Backedge {
-    Backedge(spv::Op, OperandList);
-    Backedge(const Backedge&);
-    Backedge& operator=(const Backedge&);
-    ~Backedge();
+    /// Registers the semantic variable to the given SPIR-V ID
+    /// @param var the semantic variable
+    /// @param id the generated SPIR-V identifier for the variable
+    void RegisterVariable(const sem::Variable* var, uint32_t id);
 
-    spv::Op opcode;
-    OperandList operands;
-  };
-  std::vector<Backedge> backedge_stack_;
+    /// Looks up the SPIR-V ID for the variable, which must have been registered
+    /// with a call to RegisterVariable()
+    /// @returns the SPIR-V ID, or 0 if the variable was not found
+    uint32_t LookupVariableID(const sem::Variable* var);
+
+    /// Pushes a new scope
+    void PushScope();
+
+    /// Pops the top-most scope
+    void PopScope();
+
+    ProgramBuilder builder_;
+    std::string error_;
+    uint32_t next_id_ = 1;
+    uint32_t current_label_id_ = 0;
+    InstructionList capabilities_;
+    InstructionList extensions_;
+    InstructionList ext_imports_;
+    InstructionList memory_model_;
+    InstructionList entry_points_;
+    InstructionList execution_modes_;
+    InstructionList debug_;
+    InstructionList types_;
+    InstructionList annotations_;
+    std::vector<Function> functions_;
+
+    // Scope holds per-block information
+    struct Scope {
+        Scope();
+        Scope(const Scope&);
+        ~Scope();
+        std::unordered_map<OperandListKey, uint32_t> type_ctor_to_id_;
+    };
+
+    std::unordered_map<const sem::Variable*, uint32_t> var_to_id_;
+    std::unordered_map<uint32_t, const sem::Variable*> id_to_var_;
+    std::unordered_map<std::string, uint32_t> import_name_to_id_;
+    std::unordered_map<Symbol, uint32_t> func_symbol_to_id_;
+    std::unordered_map<sem::CallTargetSignature, uint32_t> func_sig_to_id_;
+    std::unordered_map<const sem::Type*, uint32_t> type_to_id_;
+    std::unordered_map<ScalarConstant, uint32_t> const_to_id_;
+    std::unordered_map<const sem::Type*, uint32_t> const_null_to_id_;
+    std::unordered_map<uint64_t, uint32_t> const_splat_to_id_;
+    std::unordered_map<const sem::Type*, uint32_t> texture_type_to_sampled_image_type_id_;
+    std::vector<Scope> scope_stack_;
+    std::vector<uint32_t> merge_stack_;
+    std::vector<uint32_t> continue_stack_;
+    std::unordered_set<uint32_t> capability_set_;
+    bool has_overridable_workgroup_size_ = false;
+    bool zero_initialize_workgroup_memory_ = false;
+
+    struct ContinuingInfo {
+        ContinuingInfo(const ast::Statement* last_statement,
+                       uint32_t loop_header_id,
+                       uint32_t break_target_id);
+        // The last statement in the continiung block.
+        const ast::Statement* const last_statement = nullptr;
+        // The ID of the loop header
+        const uint32_t loop_header_id = 0u;
+        // The ID of the merge block for the loop.
+        const uint32_t break_target_id = 0u;
+    };
+    // Stack of nodes, where each is the last statement in a surrounding
+    // continuing block.
+    std::vector<ContinuingInfo> continuing_stack_;
+
+    // The instruction to emit as the backedge of a loop.
+    struct Backedge {
+        Backedge(spv::Op, OperandList);
+        Backedge(const Backedge&);
+        Backedge& operator=(const Backedge&);
+        ~Backedge();
+
+        spv::Op opcode;
+        OperandList operands;
+    };
+    std::vector<Backedge> backedge_stack_;
 };
 
 }  // namespace tint::writer::spirv
diff --git a/src/tint/writer/spirv/builder_accessor_expression_test.cc b/src/tint/writer/spirv/builder_accessor_expression_test.cc
index 285d259..67ee185 100644
--- a/src/tint/writer/spirv/builder_accessor_expression_test.cc
+++ b/src/tint/writer/spirv/builder_accessor_expression_test.cc
@@ -15,31 +15,33 @@
 #include "src/tint/writer/spirv/spv_dump.h"
 #include "src/tint/writer/spirv/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::spirv {
 namespace {
 
 using BuilderTest = TestHelper;
 
 TEST_F(BuilderTest, IndexAccessor_VectorRef_Literal) {
-  // var ary : vec3<f32>;
-  // ary[1]  -> ref<f32>
+    // var ary : vec3<f32>;
+    // ary[1]  -> ref<f32>
 
-  auto* var = Var("ary", ty.vec3<f32>());
+    auto* var = Var("ary", ty.vec3<f32>());
 
-  auto* ary = Expr("ary");
-  auto* idx_expr = Expr(1);
+    auto* ary = Expr("ary");
+    auto* idx_expr = Expr(1_i);
 
-  auto* expr = IndexAccessor(ary, idx_expr);
-  WrapInFunction(var, expr);
+    auto* expr = IndexAccessor(ary, idx_expr);
+    WrapInFunction(var, expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
 
-  EXPECT_EQ(b.GenerateAccessorExpression(expr), 9u);
+    EXPECT_EQ(b.GenerateAccessorExpression(expr), 9u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
 %3 = OpTypeVector %4 3
 %2 = OpTypePointer Function %3
 %5 = OpConstantNull %3
@@ -47,37 +49,37 @@
 %7 = OpConstant %6 1
 %8 = OpTypePointer Function %4
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-            R"(%1 = OpVariable %2 Function %5
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
+              R"(%1 = OpVariable %2 Function %5
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%9 = OpAccessChain %8 %1 %7
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%9 = OpAccessChain %8 %1 %7
 )");
 }
 
 TEST_F(BuilderTest, IndexAccessor_VectorRef_Dynamic) {
-  // var ary : vec3<f32>;
-  // var idx : i32;
-  // ary[idx]  -> ref<f32>
+    // var ary : vec3<f32>;
+    // var idx : i32;
+    // ary[idx]  -> ref<f32>
 
-  auto* var = Var("ary", ty.vec3<f32>());
-  auto* idx = Var("idx", ty.i32());
+    auto* var = Var("ary", ty.vec3<f32>());
+    auto* idx = Var("idx", ty.i32());
 
-  auto* ary = Expr("ary");
-  auto* idx_expr = Expr("idx");
+    auto* ary = Expr("ary");
+    auto* idx_expr = Expr("idx");
 
-  auto* expr = IndexAccessor(ary, idx_expr);
-  WrapInFunction(var, idx, expr);
+    auto* expr = IndexAccessor(ary, idx_expr);
+    WrapInFunction(var, idx, expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
-  ASSERT_TRUE(b.GenerateFunctionVariable(idx)) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+    ASSERT_TRUE(b.GenerateFunctionVariable(idx)) << b.error();
 
-  EXPECT_EQ(b.GenerateAccessorExpression(expr), 12u);
+    EXPECT_EQ(b.GenerateAccessorExpression(expr), 12u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
 %3 = OpTypeVector %4 3
 %2 = OpTypePointer Function %3
 %5 = OpConstantNull %3
@@ -86,35 +88,35 @@
 %9 = OpConstantNull %8
 %11 = OpTypePointer Function %4
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-            R"(%1 = OpVariable %2 Function %5
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
+              R"(%1 = OpVariable %2 Function %5
 %6 = OpVariable %7 Function %9
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%10 = OpLoad %8 %6
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%10 = OpLoad %8 %6
 %12 = OpAccessChain %11 %1 %10
 )");
 }
 
 TEST_F(BuilderTest, IndexAccessor_VectorRef_Dynamic2) {
-  // var ary : vec3<f32>;
-  // ary[1 + 2]  -> ref<f32>
+    // var ary : vec3<f32>;
+    // ary[1 + 2]  -> ref<f32>
 
-  auto* var = Var("ary", ty.vec3<f32>());
+    auto* var = Var("ary", ty.vec3<f32>());
 
-  auto* ary = Expr("ary");
+    auto* ary = Expr("ary");
 
-  auto* expr = IndexAccessor(ary, Add(1, 2));
-  WrapInFunction(var, expr);
+    auto* expr = IndexAccessor(ary, Add(1_i, 2_i));
+    WrapInFunction(var, expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
 
-  EXPECT_EQ(b.GenerateAccessorExpression(expr), 11u);
+    EXPECT_EQ(b.GenerateAccessorExpression(expr), 11u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
 %3 = OpTypeVector %4 3
 %2 = OpTypePointer Function %3
 %5 = OpConstantNull %3
@@ -123,34 +125,34 @@
 %8 = OpConstant %6 2
 %10 = OpTypePointer Function %4
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-            R"(%1 = OpVariable %2 Function %5
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
+              R"(%1 = OpVariable %2 Function %5
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%9 = OpIAdd %6 %7 %8
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%9 = OpIAdd %6 %7 %8
 %11 = OpAccessChain %10 %1 %9
 )");
 }
 
 TEST_F(BuilderTest, IndexAccessor_ArrayRef_MultiLevel) {
-  auto* ary4 = ty.array(ty.vec3<f32>(), 4);
+    auto* ary4 = ty.array(ty.vec3<f32>(), 4_u);
 
-  // var ary : array<vec3<f32>, 4>
-  // ary[3][2];
+    // var ary : array<vec3<f32>, 4u>
+    // ary[3i][2i];
 
-  auto* var = Var("ary", ary4);
+    auto* var = Var("ary", ary4);
 
-  auto* expr = IndexAccessor(IndexAccessor("ary", 3), 2);
-  WrapInFunction(var, expr);
+    auto* expr = IndexAccessor(IndexAccessor("ary", 3_i), 2_i);
+    WrapInFunction(var, expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
 
-  EXPECT_EQ(b.GenerateAccessorExpression(expr), 13u);
+    EXPECT_EQ(b.GenerateAccessorExpression(expr), 13u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeFloat 32
 %4 = OpTypeVector %5 3
 %6 = OpTypeInt 32 0
 %7 = OpConstant %6 4
@@ -162,32 +164,32 @@
 %11 = OpConstant %9 2
 %12 = OpTypePointer Function %5
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-            R"(%1 = OpVariable %2 Function %8
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
+              R"(%1 = OpVariable %2 Function %8
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%13 = OpAccessChain %12 %1 %10 %11
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%13 = OpAccessChain %12 %1 %10 %11
 )");
 }
 
 TEST_F(BuilderTest, IndexAccessor_ArrayRef_ArrayWithSwizzle) {
-  auto* ary4 = ty.array(ty.vec3<f32>(), 4);
+    auto* ary4 = ty.array(ty.vec3<f32>(), 4_u);
 
-  // var a : array<vec3<f32>, 4>;
-  // a[2].xy;
+    // var a : array<vec3<f32>, 4u>;
+    // a[2i].xy;
 
-  auto* var = Var("ary", ary4);
+    auto* var = Var("ary", ary4);
 
-  auto* expr = MemberAccessor(IndexAccessor("ary", 2), "xy");
-  WrapInFunction(var, expr);
+    auto* expr = MemberAccessor(IndexAccessor("ary", 2_i), "xy");
+    WrapInFunction(var, expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
-  EXPECT_EQ(b.GenerateAccessorExpression(expr), 15u);
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+    EXPECT_EQ(b.GenerateAccessorExpression(expr), 15u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeFloat 32
 %4 = OpTypeVector %5 3
 %6 = OpTypeInt 32 0
 %7 = OpConstant %6 4
@@ -199,42 +201,42 @@
 %11 = OpTypePointer Function %4
 %13 = OpTypeVector %5 2
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-            R"(%1 = OpVariable %2 Function %8
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
+              R"(%1 = OpVariable %2 Function %8
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%12 = OpAccessChain %11 %1 %10
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%12 = OpAccessChain %11 %1 %10
 %14 = OpLoad %4 %12
 %15 = OpVectorShuffle %13 %14 %14 0 1
 )");
 }
 
 TEST_F(BuilderTest, MemberAccessor) {
-  // my_struct {
-  //   a : f32
-  //   b : f32
-  // }
-  // var ident : my_struct
-  // ident.b
+    // my_struct {
+    //   a : f32
+    //   b : f32
+    // }
+    // var ident : my_struct
+    // ident.b
 
-  auto* s = Structure("my_struct", {
-                                       Member("a", ty.f32()),
-                                       Member("b", ty.f32()),
-                                   });
+    auto* s = Structure("my_struct", {
+                                         Member("a", ty.f32()),
+                                         Member("b", ty.f32()),
+                                     });
 
-  auto* var = Var("ident", ty.Of(s));
+    auto* var = Var("ident", ty.Of(s));
 
-  auto* expr = MemberAccessor("ident", "b");
-  WrapInFunction(var, expr);
+    auto* expr = MemberAccessor("ident", "b");
+    WrapInFunction(var, expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
 
-  EXPECT_EQ(b.GenerateAccessorExpression(expr), 9u);
+    EXPECT_EQ(b.GenerateAccessorExpression(expr), 9u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
 %3 = OpTypeStruct %4 %4
 %2 = OpTypePointer Function %3
 %5 = OpConstantNull %3
@@ -242,44 +244,44 @@
 %7 = OpConstant %6 1
 %8 = OpTypePointer Function %4
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-            R"(%1 = OpVariable %2 Function %5
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
+              R"(%1 = OpVariable %2 Function %5
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%9 = OpAccessChain %8 %1 %7
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%9 = OpAccessChain %8 %1 %7
 )");
 }
 
 TEST_F(BuilderTest, MemberAccessor_Nested) {
-  // inner_struct {
-  //   a : f32
-  //   b : f32
-  // }
-  // my_struct {
-  //   inner : inner_struct
-  // }
-  //
-  // var ident : my_struct
-  // ident.inner.a
-  auto* inner_struct = Structure("Inner", {
-                                              Member("a", ty.f32()),
-                                              Member("b", ty.f32()),
-                                          });
+    // inner_struct {
+    //   a : f32
+    //   b : f32
+    // }
+    // my_struct {
+    //   inner : inner_struct
+    // }
+    //
+    // var ident : my_struct
+    // ident.inner.a
+    auto* inner_struct = Structure("Inner", {
+                                                Member("a", ty.f32()),
+                                                Member("b", ty.f32()),
+                                            });
 
-  auto* s_type = Structure("my_struct", {Member("inner", ty.Of(inner_struct))});
+    auto* s_type = Structure("my_struct", {Member("inner", ty.Of(inner_struct))});
 
-  auto* var = Var("ident", ty.Of(s_type));
-  auto* expr = MemberAccessor(MemberAccessor("ident", "inner"), "b");
-  WrapInFunction(var, expr);
+    auto* var = Var("ident", ty.Of(s_type));
+    auto* expr = MemberAccessor(MemberAccessor("ident", "inner"), "b");
+    WrapInFunction(var, expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
 
-  EXPECT_EQ(b.GenerateAccessorExpression(expr), 11u);
+    EXPECT_EQ(b.GenerateAccessorExpression(expr), 11u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeFloat 32
 %4 = OpTypeStruct %5 %5
 %3 = OpTypeStruct %4
 %2 = OpTypePointer Function %3
@@ -289,125 +291,124 @@
 %9 = OpConstant %7 1
 %10 = OpTypePointer Function %5
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-            R"(%1 = OpVariable %2 Function %6
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
+              R"(%1 = OpVariable %2 Function %6
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%11 = OpAccessChain %10 %1 %8 %9
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%11 = OpAccessChain %10 %1 %8 %9
 )");
 }
 
 TEST_F(BuilderTest, MemberAccessor_NonPointer) {
-  // my_struct {
-  //   a : f32
-  //   b : f32
-  // }
-  // let ident : my_struct = my_struct();
-  // ident.b
+    // my_struct {
+    //   a : f32
+    //   b : f32
+    // }
+    // let ident : my_struct = my_struct();
+    // ident.b
 
-  auto* s = Structure("my_struct", {
-                                       Member("a", ty.f32()),
-                                       Member("b", ty.f32()),
-                                   });
+    auto* s = Structure("my_struct", {
+                                         Member("a", ty.f32()),
+                                         Member("b", ty.f32()),
+                                     });
 
-  auto* var = Const("ident", ty.Of(s), Construct(ty.Of(s), 0.f, 0.f));
+    auto* var = Let("ident", ty.Of(s), Construct(ty.Of(s), 0.f, 0.f));
 
-  auto* expr = MemberAccessor("ident", "b");
-  WrapInFunction(var, expr);
+    auto* expr = MemberAccessor("ident", "b");
+    WrapInFunction(var, expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
 
-  EXPECT_EQ(b.GenerateAccessorExpression(expr), 5u);
+    EXPECT_EQ(b.GenerateAccessorExpression(expr), 5u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeStruct %2 %2
 %3 = OpConstant %2 0
 %4 = OpConstantComposite %1 %3 %3
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%5 = OpCompositeExtract %2 %4 1
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%5 = OpCompositeExtract %2 %4 1
 )");
 }
 
 TEST_F(BuilderTest, MemberAccessor_Nested_NonPointer) {
-  // inner_struct {
-  //   a : f32
-  //   b : f32
-  // }
-  // my_struct {
-  //   inner : inner_struct
-  // }
-  //
-  // let ident : my_struct = my_struct();
-  // ident.inner.a
-  auto* inner_struct = Structure("Inner", {
-                                              Member("a", ty.f32()),
-                                              Member("b", ty.f32()),
-                                          });
+    // inner_struct {
+    //   a : f32
+    //   b : f32
+    // }
+    // my_struct {
+    //   inner : inner_struct
+    // }
+    //
+    // let ident : my_struct = my_struct();
+    // ident.inner.a
+    auto* inner_struct = Structure("Inner", {
+                                                Member("a", ty.f32()),
+                                                Member("b", ty.f32()),
+                                            });
 
-  auto* s_type = Structure("my_struct", {Member("inner", ty.Of(inner_struct))});
+    auto* s_type = Structure("my_struct", {Member("inner", ty.Of(inner_struct))});
 
-  auto* var =
-      Const("ident", ty.Of(s_type),
-            Construct(ty.Of(s_type), Construct(ty.Of(inner_struct), 0.f, 0.f)));
-  auto* expr = MemberAccessor(MemberAccessor("ident", "inner"), "b");
-  WrapInFunction(var, expr);
+    auto* var = Let("ident", ty.Of(s_type),
+                    Construct(ty.Of(s_type), Construct(ty.Of(inner_struct), 0.f, 0.f)));
+    auto* expr = MemberAccessor(MemberAccessor("ident", "inner"), "b");
+    WrapInFunction(var, expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
 
-  EXPECT_EQ(b.GenerateAccessorExpression(expr), 8u);
+    EXPECT_EQ(b.GenerateAccessorExpression(expr), 8u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
 %2 = OpTypeStruct %3 %3
 %1 = OpTypeStruct %2
 %4 = OpConstant %3 0
 %5 = OpConstantComposite %2 %4 %4
 %6 = OpConstantComposite %1 %5
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%7 = OpCompositeExtract %2 %6 0
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%7 = OpCompositeExtract %2 %6 0
 %8 = OpCompositeExtract %3 %7 1
 )");
 }
 
 TEST_F(BuilderTest, MemberAccessor_Nested_WithAlias) {
-  // struct Inner {
-  //   a : f32
-  //   b : f32
-  // };
-  // type Alias = Inner;
-  // my_struct {
-  //   inner : Inner
-  // }
-  //
-  // var ident : my_struct
-  // ident.inner.a
-  auto* inner_struct = Structure("Inner", {
-                                              Member("a", ty.f32()),
-                                              Member("b", ty.f32()),
-                                          });
+    // struct Inner {
+    //   a : f32
+    //   b : f32
+    // };
+    // type Alias = Inner;
+    // my_struct {
+    //   inner : Inner
+    // }
+    //
+    // var ident : my_struct
+    // ident.inner.a
+    auto* inner_struct = Structure("Inner", {
+                                                Member("a", ty.f32()),
+                                                Member("b", ty.f32()),
+                                            });
 
-  auto* alias = Alias("Alias", ty.Of(inner_struct));
-  auto* s_type = Structure("Outer", {Member("inner", ty.Of(alias))});
+    auto* alias = Alias("Alias", ty.Of(inner_struct));
+    auto* s_type = Structure("Outer", {Member("inner", ty.Of(alias))});
 
-  auto* var = Var("ident", ty.Of(s_type));
-  auto* expr = MemberAccessor(MemberAccessor("ident", "inner"), "a");
-  WrapInFunction(var, expr);
+    auto* var = Var("ident", ty.Of(s_type));
+    auto* expr = MemberAccessor(MemberAccessor("ident", "inner"), "a");
+    WrapInFunction(var, expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
 
-  EXPECT_EQ(b.GenerateAccessorExpression(expr), 10u);
+    EXPECT_EQ(b.GenerateAccessorExpression(expr), 10u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeFloat 32
 %4 = OpTypeStruct %5 %5
 %3 = OpTypeStruct %4
 %2 = OpTypePointer Function %3
@@ -416,44 +417,43 @@
 %8 = OpConstant %7 0
 %9 = OpTypePointer Function %5
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-            R"(%1 = OpVariable %2 Function %6
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
+              R"(%1 = OpVariable %2 Function %6
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%10 = OpAccessChain %9 %1 %8 %8
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%10 = OpAccessChain %9 %1 %8 %8
 )");
 }
 
 TEST_F(BuilderTest, MemberAccessor_Nested_Assignment_LHS) {
-  // inner_struct {
-  //   a : f32
-  // }
-  // my_struct {
-  //   inner : inner_struct
-  // }
-  //
-  // var ident : my_struct
-  // ident.inner.a = 2.0f;
-  auto* inner_struct = Structure("Inner", {
-                                              Member("a", ty.f32()),
-                                              Member("b", ty.f32()),
-                                          });
+    // inner_struct {
+    //   a : f32
+    // }
+    // my_struct {
+    //   inner : inner_struct
+    // }
+    //
+    // var ident : my_struct
+    // ident.inner.a = 2.0f;
+    auto* inner_struct = Structure("Inner", {
+                                                Member("a", ty.f32()),
+                                                Member("b", ty.f32()),
+                                            });
 
-  auto* s_type = Structure("my_struct", {Member("inner", ty.Of(inner_struct))});
+    auto* s_type = Structure("my_struct", {Member("inner", ty.Of(inner_struct))});
 
-  auto* var = Var("ident", ty.Of(s_type));
-  auto* expr =
-      Assign(MemberAccessor(MemberAccessor("ident", "inner"), "a"), Expr(2.0f));
-  WrapInFunction(var, expr);
+    auto* var = Var("ident", ty.Of(s_type));
+    auto* expr = Assign(MemberAccessor(MemberAccessor("ident", "inner"), "a"), Expr(2.0f));
+    WrapInFunction(var, expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
 
-  EXPECT_TRUE(b.GenerateAssignStatement(expr)) << b.error();
+    EXPECT_TRUE(b.GenerateAssignStatement(expr)) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeFloat 32
 %4 = OpTypeStruct %5 %5
 %3 = OpTypeStruct %4
 %2 = OpTypePointer Function %3
@@ -463,49 +463,49 @@
 %9 = OpTypePointer Function %5
 %11 = OpConstant %5 2
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-            R"(%1 = OpVariable %2 Function %6
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
+              R"(%1 = OpVariable %2 Function %6
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%10 = OpAccessChain %9 %1 %8 %8
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%10 = OpAccessChain %9 %1 %8 %8
 OpStore %10 %11
 )");
 }
 
 TEST_F(BuilderTest, MemberAccessor_Nested_Assignment_RHS) {
-  // inner_struct {
-  //   a : f32
-  // }
-  // my_struct {
-  //   inner : inner_struct
-  // }
-  //
-  // var ident : my_struct
-  // var store : f32 = ident.inner.a
+    // inner_struct {
+    //   a : f32
+    // }
+    // my_struct {
+    //   inner : inner_struct
+    // }
+    //
+    // var ident : my_struct
+    // var store : f32 = ident.inner.a
 
-  auto* inner_struct = Structure("Inner", {
-                                              Member("a", ty.f32()),
-                                              Member("b", ty.f32()),
-                                          });
+    auto* inner_struct = Structure("Inner", {
+                                                Member("a", ty.f32()),
+                                                Member("b", ty.f32()),
+                                            });
 
-  auto* s_type = Structure("my_struct", {Member("inner", ty.Of(inner_struct))});
+    auto* s_type = Structure("my_struct", {Member("inner", ty.Of(inner_struct))});
 
-  auto* var = Var("ident", ty.Of(s_type));
-  auto* store = Var("store", ty.f32());
+    auto* var = Var("ident", ty.Of(s_type));
+    auto* store = Var("store", ty.f32());
 
-  auto* rhs = MemberAccessor(MemberAccessor("ident", "inner"), "a");
-  auto* expr = Assign("store", rhs);
-  WrapInFunction(var, store, expr);
+    auto* rhs = MemberAccessor(MemberAccessor("ident", "inner"), "a");
+    auto* expr = Assign("store", rhs);
+    WrapInFunction(var, store, expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
-  ASSERT_TRUE(b.GenerateFunctionVariable(store)) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+    ASSERT_TRUE(b.GenerateFunctionVariable(store)) << b.error();
 
-  EXPECT_TRUE(b.GenerateAssignStatement(expr)) << b.error();
+    EXPECT_TRUE(b.GenerateAssignStatement(expr)) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeFloat 32
 %4 = OpTypeStruct %5 %5
 %3 = OpTypeStruct %4
 %2 = OpTypePointer Function %3
@@ -515,33 +515,33 @@
 %10 = OpTypeInt 32 0
 %11 = OpConstant %10 0
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-            R"(%1 = OpVariable %2 Function %6
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
+              R"(%1 = OpVariable %2 Function %6
 %7 = OpVariable %8 Function %9
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%12 = OpAccessChain %8 %1 %11 %11
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%12 = OpAccessChain %8 %1 %11 %11
 %13 = OpLoad %5 %12
 OpStore %7 %13
 )");
 }
 
 TEST_F(BuilderTest, MemberAccessor_Swizzle_Single) {
-  // ident.y
+    // ident.y
 
-  auto* var = Var("ident", ty.vec3<f32>());
+    auto* var = Var("ident", ty.vec3<f32>());
 
-  auto* expr = MemberAccessor("ident", "y");
-  WrapInFunction(var, expr);
+    auto* expr = MemberAccessor("ident", "y");
+    WrapInFunction(var, expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
 
-  EXPECT_EQ(b.GenerateAccessorExpression(expr), 9u);
+    EXPECT_EQ(b.GenerateAccessorExpression(expr), 9u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
 %3 = OpTypeVector %4 3
 %2 = OpTypePointer Function %3
 %5 = OpConstantNull %3
@@ -549,176 +549,174 @@
 %7 = OpConstant %6 1
 %8 = OpTypePointer Function %4
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-            R"(%1 = OpVariable %2 Function %5
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
+              R"(%1 = OpVariable %2 Function %5
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%9 = OpAccessChain %8 %1 %7
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%9 = OpAccessChain %8 %1 %7
 )");
 }
 
 TEST_F(BuilderTest, MemberAccessor_Swizzle_MultipleNames) {
-  // ident.yx
+    // ident.yx
 
-  auto* var = Var("ident", ty.vec3<f32>());
+    auto* var = Var("ident", ty.vec3<f32>());
 
-  auto* expr = MemberAccessor("ident", "yx");
-  WrapInFunction(var, expr);
+    auto* expr = MemberAccessor("ident", "yx");
+    WrapInFunction(var, expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
 
-  EXPECT_EQ(b.GenerateAccessorExpression(expr), 8u);
+    EXPECT_EQ(b.GenerateAccessorExpression(expr), 8u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
 %3 = OpTypeVector %4 3
 %2 = OpTypePointer Function %3
 %5 = OpConstantNull %3
 %6 = OpTypeVector %4 2
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-            R"(%1 = OpVariable %2 Function %5
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
+              R"(%1 = OpVariable %2 Function %5
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%7 = OpLoad %3 %1
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%7 = OpLoad %3 %1
 %8 = OpVectorShuffle %6 %7 %7 1 0
 )");
 }
 
 TEST_F(BuilderTest, MemberAccessor_Swizzle_of_Swizzle) {
-  // ident.yxz.xz
+    // ident.yxz.xz
 
-  auto* var = Var("ident", ty.vec3<f32>());
+    auto* var = Var("ident", ty.vec3<f32>());
 
-  auto* expr = MemberAccessor(MemberAccessor("ident", "yxz"), "xz");
-  WrapInFunction(var, expr);
+    auto* expr = MemberAccessor(MemberAccessor("ident", "yxz"), "xz");
+    WrapInFunction(var, expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
 
-  EXPECT_EQ(b.GenerateAccessorExpression(expr), 9u);
+    EXPECT_EQ(b.GenerateAccessorExpression(expr), 9u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
 %3 = OpTypeVector %4 3
 %2 = OpTypePointer Function %3
 %5 = OpConstantNull %3
 %8 = OpTypeVector %4 2
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-            R"(%1 = OpVariable %2 Function %5
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
+              R"(%1 = OpVariable %2 Function %5
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%6 = OpLoad %3 %1
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%6 = OpLoad %3 %1
 %7 = OpVectorShuffle %3 %6 %6 1 0 2
 %9 = OpVectorShuffle %8 %7 %7 0 2
 )");
 }
 
 TEST_F(BuilderTest, MemberAccessor_Member_of_Swizzle) {
-  // ident.yxz.x
+    // ident.yxz.x
 
-  auto* var = Var("ident", ty.vec3<f32>());
+    auto* var = Var("ident", ty.vec3<f32>());
 
-  auto* expr = MemberAccessor(MemberAccessor("ident", "yxz"), "x");
-  WrapInFunction(var, expr);
+    auto* expr = MemberAccessor(MemberAccessor("ident", "yxz"), "x");
+    WrapInFunction(var, expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
 
-  EXPECT_EQ(b.GenerateAccessorExpression(expr), 8u);
+    EXPECT_EQ(b.GenerateAccessorExpression(expr), 8u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
 %3 = OpTypeVector %4 3
 %2 = OpTypePointer Function %3
 %5 = OpConstantNull %3
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-            R"(%1 = OpVariable %2 Function %5
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
+              R"(%1 = OpVariable %2 Function %5
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%6 = OpLoad %3 %1
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%6 = OpLoad %3 %1
 %7 = OpVectorShuffle %3 %6 %6 1 0 2
 %8 = OpCompositeExtract %4 %7 0
 )");
 }
 
 TEST_F(BuilderTest, MemberAccessor_Array_of_Swizzle) {
-  // index.yxz[1]
+    // index.yxz[1i]
 
-  auto* var = Var("ident", ty.vec3<f32>());
+    auto* var = Var("ident", ty.vec3<f32>());
 
-  auto* expr = IndexAccessor(MemberAccessor("ident", "yxz"), 1);
-  WrapInFunction(var, expr);
+    auto* expr = IndexAccessor(MemberAccessor("ident", "yxz"), 1_i);
+    WrapInFunction(var, expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
 
-  EXPECT_EQ(b.GenerateAccessorExpression(expr), 10u);
+    EXPECT_EQ(b.GenerateAccessorExpression(expr), 10u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
 %3 = OpTypeVector %4 3
 %2 = OpTypePointer Function %3
 %5 = OpConstantNull %3
 %8 = OpTypeInt 32 1
 %9 = OpConstant %8 1
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-            R"(%1 = OpVariable %2 Function %5
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
+              R"(%1 = OpVariable %2 Function %5
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%6 = OpLoad %3 %1
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%6 = OpLoad %3 %1
 %7 = OpVectorShuffle %3 %6 %6 1 0 2
 %10 = OpCompositeExtract %4 %7 1
 )");
 }
 
 TEST_F(BuilderTest, IndexAccessor_Mixed_ArrayAndMember) {
-  // type C = struct {
-  //   baz : vec3<f32>
-  // }
-  // type B = struct {
-  //  bar : C;
-  // }
-  // type A = struct {
-  //   foo : array<B, 3>
-  // }
-  // var index : array<A, 2>
-  // index[0].foo[2].bar.baz.yx
+    // type C = struct {
+    //   baz : vec3<f32>
+    // }
+    // type B = struct {
+    //  bar : C;
+    // }
+    // type A = struct {
+    //   foo : array<B, 3>
+    // }
+    // var index : array<A, 2u>
+    // index[0i].foo[2i].bar.baz.yx
 
-  auto* c_type = Structure("C", {Member("baz", ty.vec3<f32>())});
+    auto* c_type = Structure("C", {Member("baz", ty.vec3<f32>())});
 
-  auto* b_type = Structure("B", {Member("bar", ty.Of(c_type))});
-  auto* b_ary_type = ty.array(ty.Of(b_type), 3);
-  auto* a_type = Structure("A", {Member("foo", b_ary_type)});
+    auto* b_type = Structure("B", {Member("bar", ty.Of(c_type))});
+    auto* b_ary_type = ty.array(ty.Of(b_type), 3_u);
+    auto* a_type = Structure("A", {Member("foo", b_ary_type)});
 
-  auto* a_ary_type = ty.array(ty.Of(a_type), 2);
-  auto* var = Var("index", a_ary_type);
-  auto* expr = MemberAccessor(
-      MemberAccessor(
-          MemberAccessor(
-              IndexAccessor(MemberAccessor(IndexAccessor("index", 0), "foo"),
-                            2),
-              "bar"),
-          "baz"),
-      "yx");
-  WrapInFunction(var, expr);
+    auto* a_ary_type = ty.array(ty.Of(a_type), 2_u);
+    auto* var = Var("index", a_ary_type);
+    auto* expr = MemberAccessor(
+        MemberAccessor(
+            MemberAccessor(IndexAccessor(MemberAccessor(IndexAccessor("index", 0_i), "foo"), 2_i),
+                           "bar"),
+            "baz"),
+        "yx");
+    WrapInFunction(var, expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
 
-  EXPECT_EQ(b.GenerateAccessorExpression(expr), 22u);
+    EXPECT_EQ(b.GenerateAccessorExpression(expr), 22u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%9 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%9 = OpTypeFloat 32
 %8 = OpTypeVector %9 3
 %7 = OpTypeStruct %8
 %6 = OpTypeStruct %7
@@ -737,36 +735,35 @@
 %18 = OpTypePointer Function %8
 %20 = OpTypeVector %9 2
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-            R"(%1 = OpVariable %2 Function %13
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
+              R"(%1 = OpVariable %2 Function %13
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%19 = OpAccessChain %18 %1 %15 %16 %17 %16 %16
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%19 = OpAccessChain %18 %1 %15 %16 %17 %16 %16
 %21 = OpLoad %8 %19
 %22 = OpVectorShuffle %20 %21 %21 1 0
 )");
 }
 
 TEST_F(BuilderTest, IndexAccessor_Of_Vec) {
-  // let pos : array<vec2<f32>, 3> = array<vec2<f32>, 3>(
-  //   vec2<f32>(0.0, 0.5),
-  //   vec2<f32>(-0.5, -0.5),
-  //   vec2<f32>(0.5, -0.5));
-  // pos[1]
+    // let pos : array<vec2<f32>, 3u> = array<vec2<f32>, 3u>(
+    //   vec2<f32>(0.0, 0.5),
+    //   vec2<f32>(-0.5, -0.5),
+    //   vec2<f32>(0.5, -0.5));
+    // pos[1u]
 
-  auto* var =
-      Const("pos", ty.array(ty.vec2<f32>(), 3),
-            Construct(ty.array(ty.vec2<f32>(), 3), vec2<f32>(0.0f, 0.5f),
-                      vec2<f32>(-0.5f, -0.5f), vec2<f32>(0.5f, -0.5f)));
+    auto* var = Let("pos", ty.array(ty.vec2<f32>(), 3_u),
+                    Construct(ty.array(ty.vec2<f32>(), 3_u), vec2<f32>(0.0f, 0.5f),
+                              vec2<f32>(-0.5f, -0.5f), vec2<f32>(0.5f, -0.5f)));
 
-  auto* expr = IndexAccessor("pos", 1u);
-  WrapInFunction(var, expr);
+    auto* expr = IndexAccessor("pos", 1_u);
+    WrapInFunction(var, expr);
 
-  spirv::Builder& b = SanitizeAndBuild();
+    spirv::Builder& b = SanitizeAndBuild();
 
-  ASSERT_TRUE(b.Build());
+    ASSERT_TRUE(b.Build());
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
 %1 = OpTypeFunction %2
 %7 = OpTypeFloat 32
 %6 = OpTypeVector %7 2
@@ -782,35 +779,34 @@
 %16 = OpConstantComposite %5 %12 %14 %15
 %17 = OpConstant %8 1
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"()");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%18 = OpCompositeExtract %6 %16 1
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"()");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%18 = OpCompositeExtract %6 %16 1
 OpReturn
 )");
 
-  Validate(b);
+    Validate(b);
 }
 
 TEST_F(BuilderTest, IndexAccessor_Of_Array_Of_f32) {
-  // let pos : array<array<f32, 2>, 3> = array<vec2<f32, 2>, 3>(
-  //   array<f32, 2>(0.0, 0.5),
-  //   array<f32, 2>(-0.5, -0.5),
-  //   array<f32, 2>(0.5, -0.5));
-  // pos[2][1]
+    // let pos : array<array<f32, 2>, 3u> = array<vec2<f32, 2>, 3u>(
+    //   array<f32, 2>(0.0, 0.5),
+    //   array<f32, 2>(-0.5, -0.5),
+    //   array<f32, 2>(0.5, -0.5));
+    // pos[2u][1u]
 
-  auto* var =
-      Const("pos", ty.array(ty.vec2<f32>(), 3),
-            Construct(ty.array(ty.vec2<f32>(), 3), vec2<f32>(0.0f, 0.5f),
-                      vec2<f32>(-0.5f, -0.5f), vec2<f32>(0.5f, -0.5f)));
+    auto* var = Let("pos", ty.array(ty.vec2<f32>(), 3_u),
+                    Construct(ty.array(ty.vec2<f32>(), 3_u), vec2<f32>(0.0f, 0.5f),
+                              vec2<f32>(-0.5f, -0.5f), vec2<f32>(0.5f, -0.5f)));
 
-  auto* expr = IndexAccessor(IndexAccessor("pos", 2u), 1u);
-  WrapInFunction(var, expr);
+    auto* expr = IndexAccessor(IndexAccessor("pos", 2_u), 1_u);
+    WrapInFunction(var, expr);
 
-  spirv::Builder& b = SanitizeAndBuild();
+    spirv::Builder& b = SanitizeAndBuild();
 
-  ASSERT_TRUE(b.Build());
+    ASSERT_TRUE(b.Build());
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
 %1 = OpTypeFunction %2
 %7 = OpTypeFloat 32
 %6 = OpTypeVector %7 2
@@ -827,32 +823,32 @@
 %17 = OpConstant %8 2
 %19 = OpConstant %8 1
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"()");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%18 = OpCompositeExtract %6 %16 2
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), R"()");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%18 = OpCompositeExtract %6 %16 2
 %20 = OpCompositeExtract %7 %18 1
 OpReturn
 )");
 
-  Validate(b);
+    Validate(b);
 }
 
 TEST_F(BuilderTest, IndexAccessor_Vec_Literal) {
-  // let pos : vec2<f32> = vec2<f32>(0.0, 0.5);
-  // pos[1]
+    // let pos : vec2<f32> = vec2<f32>(0.0, 0.5);
+    // pos[1]
 
-  auto* var = Const("pos", ty.vec2<f32>(), vec2<f32>(0.0f, 0.5f));
+    auto* var = Let("pos", ty.vec2<f32>(), vec2<f32>(0.0f, 0.5f));
 
-  auto* expr = IndexAccessor("pos", 1u);
-  WrapInFunction(var, expr);
+    auto* expr = IndexAccessor("pos", 1_u);
+    WrapInFunction(var, expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
-  EXPECT_EQ(b.GenerateAccessorExpression(expr), 8u) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+    EXPECT_EQ(b.GenerateAccessorExpression(expr), 8u) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 2
 %3 = OpConstant %2 0
 %4 = OpConstant %2 0.5
@@ -860,31 +856,31 @@
 %6 = OpTypeInt 32 0
 %7 = OpConstant %6 1
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), "");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%8 = OpCompositeExtract %2 %5 1
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), "");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%8 = OpCompositeExtract %2 %5 1
 )");
 }
 
 TEST_F(BuilderTest, IndexAccessor_Vec_Dynamic) {
-  // let pos : vec2<f32> = vec2<f32>(0.0, 0.5);
-  // idx : i32
-  // pos[idx]
+    // let pos : vec2<f32> = vec2<f32>(0.0, 0.5);
+    // idx : i32
+    // pos[idx]
 
-  auto* var = Const("pos", ty.vec2<f32>(), vec2<f32>(0.0f, 0.5f));
-  auto* idx = Var("idx", ty.i32());
-  auto* expr = IndexAccessor("pos", idx);
+    auto* var = Let("pos", ty.vec2<f32>(), vec2<f32>(0.0f, 0.5f));
+    auto* idx = Var("idx", ty.i32());
+    auto* expr = IndexAccessor("pos", idx);
 
-  WrapInFunction(var, idx, expr);
+    WrapInFunction(var, idx, expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
-  ASSERT_TRUE(b.GenerateFunctionVariable(idx)) << b.error();
-  EXPECT_EQ(b.GenerateAccessorExpression(expr), 11u) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+    ASSERT_TRUE(b.GenerateFunctionVariable(idx)) << b.error();
+    EXPECT_EQ(b.GenerateAccessorExpression(expr), 11u) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 2
 %3 = OpConstant %2 0
 %4 = OpConstant %2 0.5
@@ -893,29 +889,28 @@
 %7 = OpTypePointer Function %8
 %9 = OpConstantNull %8
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-            R"(%6 = OpVariable %7 Function %9
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
+              R"(%6 = OpVariable %7 Function %9
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%10 = OpLoad %8 %6
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%10 = OpLoad %8 %6
 %11 = OpVectorExtractDynamic %2 %5 %10
 )");
 }
 
 TEST_F(BuilderTest, IndexAccessor_Array_Literal) {
-  // let a : array<f32, 3>;
-  // a[2]
+    // let a : array<f32, 3u>;
+    // a[2i]
 
-  auto* var = Const("a", ty.array<f32, 3>(),
-                    Construct(ty.array<f32, 3>(), 0.0f, 0.5f, 1.0f));
-  auto* expr = IndexAccessor("a", 2);
-  WrapInFunction(var, expr);
+    auto* var = Let("a", ty.array<f32, 3>(), Construct(ty.array<f32, 3>(), 0.0f, 0.5f, 1.0f));
+    auto* expr = IndexAccessor("a", 2_i);
+    WrapInFunction(var, expr);
 
-  spirv::Builder& b = SanitizeAndBuild();
+    spirv::Builder& b = SanitizeAndBuild();
 
-  ASSERT_TRUE(b.Build());
+    ASSERT_TRUE(b.Build());
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
 %1 = OpTypeFunction %2
 %6 = OpTypeFloat 32
 %7 = OpTypeInt 32 0
@@ -928,33 +923,32 @@
 %13 = OpTypeInt 32 1
 %14 = OpConstant %13 2
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), "");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%15 = OpCompositeExtract %6 %12 2
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()), "");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%15 = OpCompositeExtract %6 %12 2
 OpReturn
 )");
 
-  Validate(b);
+    Validate(b);
 }
 
 TEST_F(BuilderTest, IndexAccessor_Array_Dynamic) {
-  // let a : array<f32, 3>;
-  // idx : i32
-  // a[idx]
+    // let a : array<f32, 3>;
+    // idx : i32
+    // a[idx]
 
-  auto* var = Const("a", ty.array<f32, 3>(),
-                    Construct(ty.array<f32, 3>(), 0.0f, 0.5f, 1.0f));
+    auto* var = Let("a", ty.array<f32, 3>(), Construct(ty.array<f32, 3>(), 0.0f, 0.5f, 1.0f));
 
-  auto* idx = Var("idx", ty.i32());
-  auto* expr = IndexAccessor("a", idx);
+    auto* idx = Var("idx", ty.i32());
+    auto* expr = IndexAccessor("a", idx);
 
-  WrapInFunction(var, idx, expr);
+    WrapInFunction(var, idx, expr);
 
-  spirv::Builder& b = SanitizeAndBuild();
+    spirv::Builder& b = SanitizeAndBuild();
 
-  ASSERT_TRUE(b.Build());
+    ASSERT_TRUE(b.Build());
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
 %1 = OpTypeFunction %2
 %6 = OpTypeFloat 32
 %7 = OpTypeInt 32 0
@@ -971,41 +965,40 @@
 %19 = OpConstantNull %5
 %21 = OpTypePointer Function %6
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-            R"(%13 = OpVariable %14 Function %16
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
+              R"(%13 = OpVariable %14 Function %16
 %17 = OpVariable %18 Function %19
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(OpStore %17 %12
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpStore %17 %12
 %20 = OpLoad %15 %13
 %22 = OpAccessChain %21 %17 %20
 %23 = OpLoad %6 %22
 OpReturn
 )");
 
-  Validate(b);
+    Validate(b);
 }
 
 TEST_F(BuilderTest, IndexAccessor_Matrix_Dynamic) {
-  // let a : mat2x2<f32>(vec2<f32>(1., 2.), vec2<f32>(3., 4.));
-  // idx : i32
-  // a[idx]
+    // let a : mat2x2<f32>(vec2<f32>(1., 2.), vec2<f32>(3., 4.));
+    // idx : i32
+    // a[idx]
 
-  auto* var =
-      Const("a", ty.mat2x2<f32>(),
-            Construct(ty.mat2x2<f32>(), Construct(ty.vec2<f32>(), 1.f, 2.f),
-                      Construct(ty.vec2<f32>(), 3.f, 4.f)));
+    auto* var = Let("a", ty.mat2x2<f32>(),
+                    Construct(ty.mat2x2<f32>(), Construct(ty.vec2<f32>(), 1.f, 2.f),
+                              Construct(ty.vec2<f32>(), 3.f, 4.f)));
 
-  auto* idx = Var("idx", ty.i32());
-  auto* expr = IndexAccessor("a", idx);
+    auto* idx = Var("idx", ty.i32());
+    auto* expr = IndexAccessor("a", idx);
 
-  WrapInFunction(var, idx, expr);
+    WrapInFunction(var, idx, expr);
 
-  spirv::Builder& b = SanitizeAndBuild();
+    spirv::Builder& b = SanitizeAndBuild();
 
-  ASSERT_TRUE(b.Build());
+    ASSERT_TRUE(b.Build());
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
 %1 = OpTypeFunction %2
 %7 = OpTypeFloat 32
 %6 = OpTypeVector %7 2
@@ -1024,19 +1017,19 @@
 %21 = OpConstantNull %5
 %23 = OpTypePointer Function %6
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-            R"(%15 = OpVariable %16 Function %18
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
+              R"(%15 = OpVariable %16 Function %18
 %19 = OpVariable %20 Function %21
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(OpStore %19 %14
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpStore %19 %14
 %22 = OpLoad %17 %15
 %24 = OpAccessChain %23 %19 %22
 %25 = OpLoad %6 %24
 OpReturn
 )");
 
-  Validate(b);
+    Validate(b);
 }
 
 }  // namespace
diff --git a/src/tint/writer/spirv/builder_assign_test.cc b/src/tint/writer/spirv/builder_assign_test.cc
index cd64741..1e02e27 100644
--- a/src/tint/writer/spirv/builder_assign_test.cc
+++ b/src/tint/writer/spirv/builder_assign_test.cc
@@ -15,106 +15,108 @@
 #include "src/tint/writer/spirv/spv_dump.h"
 #include "src/tint/writer/spirv/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::spirv {
 namespace {
 
 using BuilderTest = TestHelper;
 
 TEST_F(BuilderTest, Assign_Var) {
-  auto* v = Global("var", ty.f32(), ast::StorageClass::kPrivate);
+    auto* v = Global("var", ty.f32(), ast::StorageClass::kPrivate);
 
-  auto* assign = Assign("var", 1.f);
+    auto* assign = Assign("var", 1.f);
 
-  WrapInFunction(assign);
+    WrapInFunction(assign);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
-  ASSERT_FALSE(b.has_error()) << b.error();
+    b.push_function(Function{});
+    EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_TRUE(b.GenerateAssignStatement(assign)) << b.error();
-  EXPECT_FALSE(b.has_error());
+    EXPECT_TRUE(b.GenerateAssignStatement(assign)) << b.error();
+    EXPECT_FALSE(b.has_error());
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
 %2 = OpTypePointer Private %3
 %4 = OpConstantNull %3
 %1 = OpVariable %2 Private %4
 %5 = OpConstant %3 1
 )");
 
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(OpStore %1 %5
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpStore %1 %5
 )");
 }
 
 TEST_F(BuilderTest, Assign_Var_OutsideFunction_IsError) {
-  auto* v = Global("var", ty.f32(), ast::StorageClass::kPrivate);
+    auto* v = Global("var", ty.f32(), ast::StorageClass::kPrivate);
 
-  auto* assign = Assign("var", Expr(1.f));
+    auto* assign = Assign("var", Expr(1.f));
 
-  WrapInFunction(assign);
+    WrapInFunction(assign);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
-  ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_FALSE(b.GenerateAssignStatement(assign)) << b.error();
-  EXPECT_TRUE(b.has_error());
-  EXPECT_EQ(b.error(),
-            "Internal error: trying to add SPIR-V instruction 62 outside a "
-            "function");
+    EXPECT_FALSE(b.GenerateAssignStatement(assign)) << b.error();
+    EXPECT_TRUE(b.has_error());
+    EXPECT_EQ(b.error(),
+              "Internal error: trying to add SPIR-V instruction 62 outside a "
+              "function");
 }
 
 TEST_F(BuilderTest, Assign_Var_ZeroConstructor) {
-  auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+    auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
 
-  auto* val = vec3<f32>();
-  auto* assign = Assign("var", val);
+    auto* val = vec3<f32>();
+    auto* assign = Assign("var", val);
 
-  WrapInFunction(assign);
+    WrapInFunction(assign);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
-  ASSERT_FALSE(b.has_error()) << b.error();
+    b.push_function(Function{});
+    EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_TRUE(b.GenerateAssignStatement(assign)) << b.error();
-  EXPECT_FALSE(b.has_error());
+    EXPECT_TRUE(b.GenerateAssignStatement(assign)) << b.error();
+    EXPECT_FALSE(b.has_error());
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
 %3 = OpTypeVector %4 3
 %2 = OpTypePointer Private %3
 %5 = OpConstantNull %3
 %1 = OpVariable %2 Private %5
 )");
 
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(OpStore %1 %5
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpStore %1 %5
 )");
 }
 
 TEST_F(BuilderTest, Assign_Var_Complex_ConstructorWithExtract) {
-  auto* init = vec3<f32>(vec2<f32>(1.f, 2.f), 3.f);
+    auto* init = vec3<f32>(vec2<f32>(1.f, 2.f), 3.f);
 
-  auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+    auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
 
-  auto* assign = Assign("var", init);
+    auto* assign = Assign("var", init);
 
-  WrapInFunction(assign);
+    WrapInFunction(assign);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
-  ASSERT_FALSE(b.has_error()) << b.error();
+    b.push_function(Function{});
+    EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_TRUE(b.GenerateAssignStatement(assign)) << b.error();
-  EXPECT_FALSE(b.has_error());
+    EXPECT_TRUE(b.GenerateAssignStatement(assign)) << b.error();
+    EXPECT_FALSE(b.has_error());
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
 %3 = OpTypeVector %4 3
 %2 = OpTypePointer Private %3
 %5 = OpConstantNull %3
@@ -125,8 +127,8 @@
 %9 = OpConstantComposite %6 %7 %8
 %12 = OpConstant %4 3
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%10 = OpCompositeExtract %4 %9 0
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%10 = OpCompositeExtract %4 %9 0
 %11 = OpCompositeExtract %4 %9 1
 %13 = OpCompositeConstruct %3 %10 %11 %12
 OpStore %1 %13
@@ -134,24 +136,24 @@
 }
 
 TEST_F(BuilderTest, Assign_Var_Complex_Constructor) {
-  auto* init = vec3<f32>(1.f, 2.f, 3.f);
+    auto* init = vec3<f32>(1.f, 2.f, 3.f);
 
-  auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+    auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
 
-  auto* assign = Assign("var", init);
+    auto* assign = Assign("var", init);
 
-  WrapInFunction(assign);
+    WrapInFunction(assign);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
-  ASSERT_FALSE(b.has_error()) << b.error();
+    b.push_function(Function{});
+    EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_TRUE(b.GenerateAssignStatement(assign)) << b.error();
-  EXPECT_FALSE(b.has_error());
+    EXPECT_TRUE(b.GenerateAssignStatement(assign)) << b.error();
+    EXPECT_FALSE(b.has_error());
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
 %3 = OpTypeVector %4 3
 %2 = OpTypePointer Private %3
 %5 = OpConstantNull %3
@@ -161,40 +163,40 @@
 %8 = OpConstant %4 3
 %9 = OpConstantComposite %3 %6 %7 %8
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(OpStore %1 %9
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpStore %1 %9
 )");
 }
 
 TEST_F(BuilderTest, Assign_StructMember) {
-  // my_struct {
-  //   a : f32
-  //   b : f32
-  // }
-  // var ident : my_struct
-  // ident.b = 4.0;
+    // my_struct {
+    //   a : f32
+    //   b : f32
+    // }
+    // var ident : my_struct
+    // ident.b = 4.0;
 
-  auto* s = Structure("my_struct", {
-                                       Member("a", ty.f32()),
-                                       Member("b", ty.f32()),
-                                   });
+    auto* s = Structure("my_struct", {
+                                         Member("a", ty.f32()),
+                                         Member("b", ty.f32()),
+                                     });
 
-  auto* v = Var("ident", ty.Of(s));
+    auto* v = Var("ident", ty.Of(s));
 
-  auto* assign = Assign(MemberAccessor("ident", "b"), Expr(4.f));
+    auto* assign = Assign(MemberAccessor("ident", "b"), Expr(4.f));
 
-  WrapInFunction(v, assign);
+    WrapInFunction(v, assign);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
-  ASSERT_FALSE(b.has_error()) << b.error();
+    b.push_function(Function{});
+    EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_TRUE(b.GenerateAssignStatement(assign)) << b.error();
-  EXPECT_FALSE(b.has_error());
+    EXPECT_TRUE(b.GenerateAssignStatement(assign)) << b.error();
+    EXPECT_FALSE(b.has_error());
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
 %3 = OpTypeStruct %4 %4
 %2 = OpTypePointer Function %3
 %1 = OpVariable %2 Function
@@ -204,30 +206,30 @@
 %9 = OpConstant %4 4
 )");
 
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%8 = OpAccessChain %7 %1 %6
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%8 = OpAccessChain %7 %1 %6
 OpStore %8 %9
 )");
 }
 
 TEST_F(BuilderTest, Assign_Vector) {
-  auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+    auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
 
-  auto* val = vec3<f32>(1.f, 1.f, 3.f);
-  auto* assign = Assign("var", val);
+    auto* val = vec3<f32>(1.f, 1.f, 3.f);
+    auto* assign = Assign("var", val);
 
-  WrapInFunction(assign);
+    WrapInFunction(assign);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
-  ASSERT_FALSE(b.has_error()) << b.error();
+    b.push_function(Function{});
+    EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_TRUE(b.GenerateAssignStatement(assign)) << b.error();
-  EXPECT_FALSE(b.has_error());
+    EXPECT_TRUE(b.GenerateAssignStatement(assign)) << b.error();
+    EXPECT_FALSE(b.has_error());
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
 %3 = OpTypeVector %4 3
 %2 = OpTypePointer Private %3
 %5 = OpConstantNull %3
@@ -237,30 +239,30 @@
 %8 = OpConstantComposite %3 %6 %6 %7
 )");
 
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(OpStore %1 %8
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpStore %1 %8
 )");
 }
 
 TEST_F(BuilderTest, Assign_Vector_MemberByName) {
-  // var.y = 1
+    // var.y = 1
 
-  auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+    auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
 
-  auto* assign = Assign(MemberAccessor("var", "y"), Expr(1.f));
+    auto* assign = Assign(MemberAccessor("var", "y"), Expr(1.f));
 
-  WrapInFunction(assign);
+    WrapInFunction(assign);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
-  ASSERT_FALSE(b.has_error()) << b.error();
+    b.push_function(Function{});
+    EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_TRUE(b.GenerateAssignStatement(assign)) << b.error();
-  EXPECT_FALSE(b.has_error());
+    EXPECT_TRUE(b.GenerateAssignStatement(assign)) << b.error();
+    EXPECT_FALSE(b.has_error());
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
 %3 = OpTypeVector %4 3
 %2 = OpTypePointer Private %3
 %5 = OpConstantNull %3
@@ -271,31 +273,31 @@
 %10 = OpConstant %4 1
 )");
 
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%9 = OpAccessChain %8 %1 %7
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%9 = OpAccessChain %8 %1 %7
 OpStore %9 %10
 )");
 }
 
 TEST_F(BuilderTest, Assign_Vector_MemberByIndex) {
-  // var[1] = 1
+    // var[1] = 1
 
-  auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+    auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kPrivate);
 
-  auto* assign = Assign(IndexAccessor("var", 1), Expr(1.f));
+    auto* assign = Assign(IndexAccessor("var", 1_i), Expr(1.f));
 
-  WrapInFunction(assign);
+    WrapInFunction(assign);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
-  ASSERT_FALSE(b.has_error()) << b.error();
+    b.push_function(Function{});
+    EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_TRUE(b.GenerateAssignStatement(assign)) << b.error();
-  EXPECT_FALSE(b.has_error());
+    EXPECT_TRUE(b.GenerateAssignStatement(assign)) << b.error();
+    EXPECT_FALSE(b.has_error());
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
 %3 = OpTypeVector %4 3
 %2 = OpTypePointer Private %3
 %5 = OpConstantNull %3
@@ -306,8 +308,8 @@
 %10 = OpConstant %4 1
 )");
 
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%9 = OpAccessChain %8 %1 %7
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%9 = OpAccessChain %8 %1 %7
 OpStore %9 %10
 )");
 }
diff --git a/src/tint/writer/spirv/builder_binary_expression_test.cc b/src/tint/writer/spirv/builder_binary_expression_test.cc
index e2768a8..17ca134 100644
--- a/src/tint/writer/spirv/builder_binary_expression_test.cc
+++ b/src/tint/writer/spirv/builder_binary_expression_test.cc
@@ -15,167 +15,167 @@
 #include "src/tint/writer/spirv/spv_dump.h"
 #include "src/tint/writer/spirv/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::spirv {
 namespace {
 
 using BuilderTest = TestHelper;
 
 struct BinaryData {
-  ast::BinaryOp op;
-  std::string name;
+    ast::BinaryOp op;
+    std::string name;
 };
 inline std::ostream& operator<<(std::ostream& out, BinaryData data) {
-  out << data.op;
-  return out;
+    out << data.op;
+    return out;
 }
 
 using BinaryArithSignedIntegerTest = TestParamHelper<BinaryData>;
 TEST_P(BinaryArithSignedIntegerTest, Scalar) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* lhs = Expr(3);
-  auto* rhs = Expr(4);
+    auto* lhs = Expr(3_i);
+    auto* rhs = Expr(4_i);
 
-  auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
+    auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_EQ(b.GenerateBinaryExpression(expr), 4u) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 1
+    EXPECT_EQ(b.GenerateBinaryExpression(expr), 4u) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 1
 %2 = OpConstant %1 3
 %3 = OpConstant %1 4
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            "%4 = " + param.name + " %1 %2 %3\n");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              "%4 = " + param.name + " %1 %2 %3\n");
 }
 
 TEST_P(BinaryArithSignedIntegerTest, Vector) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  // Skip ops that are illegal for this type
-  if (param.op == ast::BinaryOp::kAnd || param.op == ast::BinaryOp::kOr ||
-      param.op == ast::BinaryOp::kXor) {
-    return;
-  }
+    // Skip ops that are illegal for this type
+    if (param.op == ast::BinaryOp::kAnd || param.op == ast::BinaryOp::kOr ||
+        param.op == ast::BinaryOp::kXor) {
+        return;
+    }
 
-  auto* lhs = vec3<i32>(1, 1, 1);
-  auto* rhs = vec3<i32>(1, 1, 1);
+    auto* lhs = vec3<i32>(1_i, 1_i, 1_i);
+    auto* rhs = vec3<i32>(1_i, 1_i, 1_i);
 
-  auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
+    auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_EQ(b.GenerateBinaryExpression(expr), 5u) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
+    EXPECT_EQ(b.GenerateBinaryExpression(expr), 5u) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
 %1 = OpTypeVector %2 3
 %3 = OpConstant %2 1
 %4 = OpConstantComposite %1 %3 %3 %3
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            "%5 = " + param.name + " %1 %4 %4\n");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              "%5 = " + param.name + " %1 %4 %4\n");
 }
 TEST_P(BinaryArithSignedIntegerTest, Scalar_Loads) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* var = Var("param", ty.i32());
-  auto* expr =
-      create<ast::BinaryExpression>(param.op, Expr("param"), Expr("param"));
+    auto* var = Var("param", ty.i32());
+    auto* expr = create<ast::BinaryExpression>(param.op, Expr("param"), Expr("param"));
 
-  WrapInFunction(var, expr);
+    WrapInFunction(var, expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
-  EXPECT_EQ(b.GenerateBinaryExpression(expr), 7u) << b.error();
-  ASSERT_FALSE(b.has_error()) << b.error();
+    b.push_function(Function{});
+    EXPECT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+    EXPECT_EQ(b.GenerateBinaryExpression(expr), 7u) << b.error();
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeInt 32 1
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeInt 32 1
 %2 = OpTypePointer Function %3
 %4 = OpConstantNull %3
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-            R"(%1 = OpVariable %2 Function %4
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
+              R"(%1 = OpVariable %2 Function %4
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%5 = OpLoad %3 %1
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%5 = OpLoad %3 %1
 %6 = OpLoad %3 %1
 %7 = )" + param.name +
-                R"( %3 %5 %6
+                  R"( %3 %5 %6
 )");
 }
-INSTANTIATE_TEST_SUITE_P(
-    BuilderTest,
-    BinaryArithSignedIntegerTest,
-    // NOTE: No left and right shift as they require u32 for rhs operand
-    testing::Values(BinaryData{ast::BinaryOp::kAdd, "OpIAdd"},
-                    BinaryData{ast::BinaryOp::kAnd, "OpBitwiseAnd"},
-                    BinaryData{ast::BinaryOp::kDivide, "OpSDiv"},
-                    BinaryData{ast::BinaryOp::kModulo, "OpSMod"},
-                    BinaryData{ast::BinaryOp::kMultiply, "OpIMul"},
-                    BinaryData{ast::BinaryOp::kOr, "OpBitwiseOr"},
-                    BinaryData{ast::BinaryOp::kSubtract, "OpISub"},
-                    BinaryData{ast::BinaryOp::kXor, "OpBitwiseXor"}));
+INSTANTIATE_TEST_SUITE_P(BuilderTest,
+                         BinaryArithSignedIntegerTest,
+                         // NOTE: No left and right shift as they require u32 for rhs operand
+                         testing::Values(BinaryData{ast::BinaryOp::kAdd, "OpIAdd"},
+                                         BinaryData{ast::BinaryOp::kAnd, "OpBitwiseAnd"},
+                                         BinaryData{ast::BinaryOp::kDivide, "OpSDiv"},
+                                         BinaryData{ast::BinaryOp::kModulo, "OpSMod"},
+                                         BinaryData{ast::BinaryOp::kMultiply, "OpIMul"},
+                                         BinaryData{ast::BinaryOp::kOr, "OpBitwiseOr"},
+                                         BinaryData{ast::BinaryOp::kSubtract, "OpISub"},
+                                         BinaryData{ast::BinaryOp::kXor, "OpBitwiseXor"}));
 
 using BinaryArithUnsignedIntegerTest = TestParamHelper<BinaryData>;
 TEST_P(BinaryArithUnsignedIntegerTest, Scalar) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* lhs = Expr(3u);
-  auto* rhs = Expr(4u);
+    auto* lhs = Expr(3_u);
+    auto* rhs = Expr(4_u);
 
-  auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
+    auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_EQ(b.GenerateBinaryExpression(expr), 4u) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 0
+    EXPECT_EQ(b.GenerateBinaryExpression(expr), 4u) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 0
 %2 = OpConstant %1 3
 %3 = OpConstant %1 4
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            "%4 = " + param.name + " %1 %2 %3\n");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              "%4 = " + param.name + " %1 %2 %3\n");
 }
 TEST_P(BinaryArithUnsignedIntegerTest, Vector) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  // Skip ops that are illegal for this type
-  if (param.op == ast::BinaryOp::kAnd || param.op == ast::BinaryOp::kOr ||
-      param.op == ast::BinaryOp::kXor) {
-    return;
-  }
+    // Skip ops that are illegal for this type
+    if (param.op == ast::BinaryOp::kAnd || param.op == ast::BinaryOp::kOr ||
+        param.op == ast::BinaryOp::kXor) {
+        return;
+    }
 
-  auto* lhs = vec3<u32>(1u, 1u, 1u);
-  auto* rhs = vec3<u32>(1u, 1u, 1u);
+    auto* lhs = vec3<u32>(1_u, 1_u, 1_u);
+    auto* rhs = vec3<u32>(1_u, 1_u, 1_u);
 
-  auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
+    auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_EQ(b.GenerateBinaryExpression(expr), 5u) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 0
+    EXPECT_EQ(b.GenerateBinaryExpression(expr), 5u) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 0
 %1 = OpTypeVector %2 3
 %3 = OpConstant %2 1
 %4 = OpConstantComposite %1 %3 %3 %3
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            "%5 = " + param.name + " %1 %4 %4\n");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              "%5 = " + param.name + " %1 %4 %4\n");
 }
 INSTANTIATE_TEST_SUITE_P(
     BuilderTest,
@@ -187,428 +187,417 @@
                     BinaryData{ast::BinaryOp::kMultiply, "OpIMul"},
                     BinaryData{ast::BinaryOp::kOr, "OpBitwiseOr"},
                     BinaryData{ast::BinaryOp::kShiftLeft, "OpShiftLeftLogical"},
-                    BinaryData{ast::BinaryOp::kShiftRight,
-                               "OpShiftRightLogical"},
+                    BinaryData{ast::BinaryOp::kShiftRight, "OpShiftRightLogical"},
                     BinaryData{ast::BinaryOp::kSubtract, "OpISub"},
                     BinaryData{ast::BinaryOp::kXor, "OpBitwiseXor"}));
 
 using BinaryArithFloatTest = TestParamHelper<BinaryData>;
 TEST_P(BinaryArithFloatTest, Scalar) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* lhs = Expr(3.2f);
-  auto* rhs = Expr(4.5f);
+    auto* lhs = Expr(3.2f);
+    auto* rhs = Expr(4.5f);
 
-  auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
+    auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_EQ(b.GenerateBinaryExpression(expr), 4u) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32
+    EXPECT_EQ(b.GenerateBinaryExpression(expr), 4u) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32
 %2 = OpConstant %1 3.20000005
 %3 = OpConstant %1 4.5
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            "%4 = " + param.name + " %1 %2 %3\n");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              "%4 = " + param.name + " %1 %2 %3\n");
 }
 
 TEST_P(BinaryArithFloatTest, Vector) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* lhs = vec3<f32>(1.f, 1.f, 1.f);
-  auto* rhs = vec3<f32>(1.f, 1.f, 1.f);
+    auto* lhs = vec3<f32>(1.f, 1.f, 1.f);
+    auto* rhs = vec3<f32>(1.f, 1.f, 1.f);
 
-  auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
+    auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_EQ(b.GenerateBinaryExpression(expr), 5u) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(b.GenerateBinaryExpression(expr), 5u) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 3
 %3 = OpConstant %2 1
 %4 = OpConstantComposite %1 %3 %3 %3
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            "%5 = " + param.name + " %1 %4 %4\n");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              "%5 = " + param.name + " %1 %4 %4\n");
 }
-INSTANTIATE_TEST_SUITE_P(
-    BuilderTest,
-    BinaryArithFloatTest,
-    testing::Values(BinaryData{ast::BinaryOp::kAdd, "OpFAdd"},
-                    BinaryData{ast::BinaryOp::kDivide, "OpFDiv"},
-                    BinaryData{ast::BinaryOp::kModulo, "OpFRem"},
-                    BinaryData{ast::BinaryOp::kMultiply, "OpFMul"},
-                    BinaryData{ast::BinaryOp::kSubtract, "OpFSub"}));
+INSTANTIATE_TEST_SUITE_P(BuilderTest,
+                         BinaryArithFloatTest,
+                         testing::Values(BinaryData{ast::BinaryOp::kAdd, "OpFAdd"},
+                                         BinaryData{ast::BinaryOp::kDivide, "OpFDiv"},
+                                         BinaryData{ast::BinaryOp::kModulo, "OpFRem"},
+                                         BinaryData{ast::BinaryOp::kMultiply, "OpFMul"},
+                                         BinaryData{ast::BinaryOp::kSubtract, "OpFSub"}));
 
 using BinaryOperatorBoolTest = TestParamHelper<BinaryData>;
 TEST_P(BinaryOperatorBoolTest, Scalar) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* lhs = Expr(true);
-  auto* rhs = Expr(false);
+    auto* lhs = Expr(true);
+    auto* rhs = Expr(false);
 
-  auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
+    auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_EQ(b.GenerateBinaryExpression(expr), 4u) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeBool
+    EXPECT_EQ(b.GenerateBinaryExpression(expr), 4u) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeBool
 %2 = OpConstantTrue %1
 %3 = OpConstantFalse %1
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            "%4 = " + param.name + " %1 %2 %3\n");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              "%4 = " + param.name + " %1 %2 %3\n");
 }
 
 TEST_P(BinaryOperatorBoolTest, Vector) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* lhs = vec3<bool>(false, true, false);
-  auto* rhs = vec3<bool>(true, false, true);
+    auto* lhs = vec3<bool>(false, true, false);
+    auto* rhs = vec3<bool>(true, false, true);
 
-  auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
+    auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_EQ(b.GenerateBinaryExpression(expr), 7u) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeBool
+    EXPECT_EQ(b.GenerateBinaryExpression(expr), 7u) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeBool
 %1 = OpTypeVector %2 3
 %3 = OpConstantFalse %2
 %4 = OpConstantTrue %2
 %5 = OpConstantComposite %1 %3 %4 %3
 %6 = OpConstantComposite %1 %4 %3 %4
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            "%7 = " + param.name + " %1 %5 %6\n");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              "%7 = " + param.name + " %1 %5 %6\n");
 }
-INSTANTIATE_TEST_SUITE_P(
-    BuilderTest,
-    BinaryOperatorBoolTest,
-    testing::Values(BinaryData{ast::BinaryOp::kEqual, "OpLogicalEqual"},
-                    BinaryData{ast::BinaryOp::kNotEqual, "OpLogicalNotEqual"},
-                    BinaryData{ast::BinaryOp::kAnd, "OpLogicalAnd"},
-                    BinaryData{ast::BinaryOp::kOr, "OpLogicalOr"}));
+INSTANTIATE_TEST_SUITE_P(BuilderTest,
+                         BinaryOperatorBoolTest,
+                         testing::Values(BinaryData{ast::BinaryOp::kEqual, "OpLogicalEqual"},
+                                         BinaryData{ast::BinaryOp::kNotEqual, "OpLogicalNotEqual"},
+                                         BinaryData{ast::BinaryOp::kAnd, "OpLogicalAnd"},
+                                         BinaryData{ast::BinaryOp::kOr, "OpLogicalOr"}));
 
 using BinaryCompareUnsignedIntegerTest = TestParamHelper<BinaryData>;
 TEST_P(BinaryCompareUnsignedIntegerTest, Scalar) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* lhs = Expr(3u);
-  auto* rhs = Expr(4u);
+    auto* lhs = Expr(3_u);
+    auto* rhs = Expr(4_u);
 
-  auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
+    auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_EQ(b.GenerateBinaryExpression(expr), 4u) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 0
+    EXPECT_EQ(b.GenerateBinaryExpression(expr), 4u) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 0
 %2 = OpConstant %1 3
 %3 = OpConstant %1 4
 %5 = OpTypeBool
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            "%4 = " + param.name + " %5 %2 %3\n");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              "%4 = " + param.name + " %5 %2 %3\n");
 }
 
 TEST_P(BinaryCompareUnsignedIntegerTest, Vector) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* lhs = vec3<u32>(1u, 1u, 1u);
-  auto* rhs = vec3<u32>(1u, 1u, 1u);
+    auto* lhs = vec3<u32>(1_u, 1_u, 1_u);
+    auto* rhs = vec3<u32>(1_u, 1_u, 1_u);
 
-  auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
+    auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_EQ(b.GenerateBinaryExpression(expr), 5u) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 0
+    EXPECT_EQ(b.GenerateBinaryExpression(expr), 5u) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 0
 %1 = OpTypeVector %2 3
 %3 = OpConstant %2 1
 %4 = OpConstantComposite %1 %3 %3 %3
 %7 = OpTypeBool
 %6 = OpTypeVector %7 3
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            "%5 = " + param.name + " %6 %4 %4\n");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              "%5 = " + param.name + " %6 %4 %4\n");
 }
 INSTANTIATE_TEST_SUITE_P(
     BuilderTest,
     BinaryCompareUnsignedIntegerTest,
-    testing::Values(
-        BinaryData{ast::BinaryOp::kEqual, "OpIEqual"},
-        BinaryData{ast::BinaryOp::kGreaterThan, "OpUGreaterThan"},
-        BinaryData{ast::BinaryOp::kGreaterThanEqual, "OpUGreaterThanEqual"},
-        BinaryData{ast::BinaryOp::kLessThan, "OpULessThan"},
-        BinaryData{ast::BinaryOp::kLessThanEqual, "OpULessThanEqual"},
-        BinaryData{ast::BinaryOp::kNotEqual, "OpINotEqual"}));
+    testing::Values(BinaryData{ast::BinaryOp::kEqual, "OpIEqual"},
+                    BinaryData{ast::BinaryOp::kGreaterThan, "OpUGreaterThan"},
+                    BinaryData{ast::BinaryOp::kGreaterThanEqual, "OpUGreaterThanEqual"},
+                    BinaryData{ast::BinaryOp::kLessThan, "OpULessThan"},
+                    BinaryData{ast::BinaryOp::kLessThanEqual, "OpULessThanEqual"},
+                    BinaryData{ast::BinaryOp::kNotEqual, "OpINotEqual"}));
 
 using BinaryCompareSignedIntegerTest = TestParamHelper<BinaryData>;
 TEST_P(BinaryCompareSignedIntegerTest, Scalar) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* lhs = Expr(3);
-  auto* rhs = Expr(4);
+    auto* lhs = Expr(3_i);
+    auto* rhs = Expr(4_i);
 
-  auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
+    auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_EQ(b.GenerateBinaryExpression(expr), 4u) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 1
+    EXPECT_EQ(b.GenerateBinaryExpression(expr), 4u) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 1
 %2 = OpConstant %1 3
 %3 = OpConstant %1 4
 %5 = OpTypeBool
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            "%4 = " + param.name + " %5 %2 %3\n");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              "%4 = " + param.name + " %5 %2 %3\n");
 }
 
 TEST_P(BinaryCompareSignedIntegerTest, Vector) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* lhs = vec3<i32>(1, 1, 1);
-  auto* rhs = vec3<i32>(1, 1, 1);
+    auto* lhs = vec3<i32>(1_i, 1_i, 1_i);
+    auto* rhs = vec3<i32>(1_i, 1_i, 1_i);
 
-  auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
+    auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_EQ(b.GenerateBinaryExpression(expr), 5u) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
+    EXPECT_EQ(b.GenerateBinaryExpression(expr), 5u) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
 %1 = OpTypeVector %2 3
 %3 = OpConstant %2 1
 %4 = OpConstantComposite %1 %3 %3 %3
 %7 = OpTypeBool
 %6 = OpTypeVector %7 3
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            "%5 = " + param.name + " %6 %4 %4\n");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              "%5 = " + param.name + " %6 %4 %4\n");
 }
 INSTANTIATE_TEST_SUITE_P(
     BuilderTest,
     BinaryCompareSignedIntegerTest,
-    testing::Values(
-        BinaryData{ast::BinaryOp::kEqual, "OpIEqual"},
-        BinaryData{ast::BinaryOp::kGreaterThan, "OpSGreaterThan"},
-        BinaryData{ast::BinaryOp::kGreaterThanEqual, "OpSGreaterThanEqual"},
-        BinaryData{ast::BinaryOp::kLessThan, "OpSLessThan"},
-        BinaryData{ast::BinaryOp::kLessThanEqual, "OpSLessThanEqual"},
-        BinaryData{ast::BinaryOp::kNotEqual, "OpINotEqual"}));
+    testing::Values(BinaryData{ast::BinaryOp::kEqual, "OpIEqual"},
+                    BinaryData{ast::BinaryOp::kGreaterThan, "OpSGreaterThan"},
+                    BinaryData{ast::BinaryOp::kGreaterThanEqual, "OpSGreaterThanEqual"},
+                    BinaryData{ast::BinaryOp::kLessThan, "OpSLessThan"},
+                    BinaryData{ast::BinaryOp::kLessThanEqual, "OpSLessThanEqual"},
+                    BinaryData{ast::BinaryOp::kNotEqual, "OpINotEqual"}));
 
 using BinaryCompareFloatTest = TestParamHelper<BinaryData>;
 TEST_P(BinaryCompareFloatTest, Scalar) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* lhs = Expr(3.2f);
-  auto* rhs = Expr(4.5f);
+    auto* lhs = Expr(3.2f);
+    auto* rhs = Expr(4.5f);
 
-  auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
+    auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_EQ(b.GenerateBinaryExpression(expr), 4u) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32
+    EXPECT_EQ(b.GenerateBinaryExpression(expr), 4u) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32
 %2 = OpConstant %1 3.20000005
 %3 = OpConstant %1 4.5
 %5 = OpTypeBool
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            "%4 = " + param.name + " %5 %2 %3\n");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              "%4 = " + param.name + " %5 %2 %3\n");
 }
 
 TEST_P(BinaryCompareFloatTest, Vector) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* lhs = vec3<f32>(1.f, 1.f, 1.f);
-  auto* rhs = vec3<f32>(1.f, 1.f, 1.f);
+    auto* lhs = vec3<f32>(1.f, 1.f, 1.f);
+    auto* rhs = vec3<f32>(1.f, 1.f, 1.f);
 
-  auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
+    auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_EQ(b.GenerateBinaryExpression(expr), 5u) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(b.GenerateBinaryExpression(expr), 5u) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 3
 %3 = OpConstant %2 1
 %4 = OpConstantComposite %1 %3 %3 %3
 %7 = OpTypeBool
 %6 = OpTypeVector %7 3
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            "%5 = " + param.name + " %6 %4 %4\n");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              "%5 = " + param.name + " %6 %4 %4\n");
 }
 INSTANTIATE_TEST_SUITE_P(
     BuilderTest,
     BinaryCompareFloatTest,
-    testing::Values(
-        BinaryData{ast::BinaryOp::kEqual, "OpFOrdEqual"},
-        BinaryData{ast::BinaryOp::kGreaterThan, "OpFOrdGreaterThan"},
-        BinaryData{ast::BinaryOp::kGreaterThanEqual, "OpFOrdGreaterThanEqual"},
-        BinaryData{ast::BinaryOp::kLessThan, "OpFOrdLessThan"},
-        BinaryData{ast::BinaryOp::kLessThanEqual, "OpFOrdLessThanEqual"},
-        BinaryData{ast::BinaryOp::kNotEqual, "OpFOrdNotEqual"}));
+    testing::Values(BinaryData{ast::BinaryOp::kEqual, "OpFOrdEqual"},
+                    BinaryData{ast::BinaryOp::kGreaterThan, "OpFOrdGreaterThan"},
+                    BinaryData{ast::BinaryOp::kGreaterThanEqual, "OpFOrdGreaterThanEqual"},
+                    BinaryData{ast::BinaryOp::kLessThan, "OpFOrdLessThan"},
+                    BinaryData{ast::BinaryOp::kLessThanEqual, "OpFOrdLessThanEqual"},
+                    BinaryData{ast::BinaryOp::kNotEqual, "OpFOrdNotEqual"}));
 
 TEST_F(BuilderTest, Binary_Multiply_VectorScalar) {
-  auto* lhs = vec3<f32>(1.f, 1.f, 1.f);
-  auto* rhs = Expr(1.f);
+    auto* lhs = vec3<f32>(1.f, 1.f, 1.f);
+    auto* rhs = Expr(1.f);
 
-  auto* expr =
-      create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
+    auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_EQ(b.GenerateBinaryExpression(expr), 5u) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()),
-            R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(b.GenerateBinaryExpression(expr), 5u) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()),
+              R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 3
 %3 = OpConstant %2 1
 %4 = OpConstantComposite %1 %3 %3 %3
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            "%5 = OpVectorTimesScalar %1 %4 %3\n");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              "%5 = OpVectorTimesScalar %1 %4 %3\n");
 }
 
 TEST_F(BuilderTest, Binary_Multiply_ScalarVector) {
-  auto* lhs = Expr(1.f);
-  auto* rhs = vec3<f32>(1.f, 1.f, 1.f);
+    auto* lhs = Expr(1.f);
+    auto* rhs = vec3<f32>(1.f, 1.f, 1.f);
 
-  auto* expr =
-      create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
+    auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, rhs);
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_EQ(b.GenerateBinaryExpression(expr), 5u) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()),
-            R"(%1 = OpTypeFloat 32
+    EXPECT_EQ(b.GenerateBinaryExpression(expr), 5u) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()),
+              R"(%1 = OpTypeFloat 32
 %2 = OpConstant %1 1
 %3 = OpTypeVector %1 3
 %4 = OpConstantComposite %3 %2 %2 %2
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            "%5 = OpVectorTimesScalar %3 %4 %2\n");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              "%5 = OpVectorTimesScalar %3 %4 %2\n");
 }
 
 TEST_F(BuilderTest, Binary_Multiply_MatrixScalar) {
-  auto* var = Var("mat", ty.mat3x3<f32>());
+    auto* var = Var("mat", ty.mat3x3<f32>());
 
-  auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply,
-                                             Expr("mat"), Expr(1.f));
+    auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, Expr("mat"), Expr(1.f));
 
-  WrapInFunction(var, expr);
+    WrapInFunction(var, expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
 
-  EXPECT_EQ(b.GenerateBinaryExpression(expr), 8u) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()),
-            R"(%5 = OpTypeFloat 32
+    EXPECT_EQ(b.GenerateBinaryExpression(expr), 8u) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()),
+              R"(%5 = OpTypeFloat 32
 %4 = OpTypeVector %5 3
 %3 = OpTypeMatrix %4 3
 %2 = OpTypePointer Function %3
 %1 = OpVariable %2 Function
 %7 = OpConstant %5 1
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%6 = OpLoad %3 %1
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%6 = OpLoad %3 %1
 %8 = OpMatrixTimesScalar %3 %6 %7
 )");
 }
 
 TEST_F(BuilderTest, Binary_Multiply_ScalarMatrix) {
-  auto* var = Var("mat", ty.mat3x3<f32>());
+    auto* var = Var("mat", ty.mat3x3<f32>());
 
-  auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply,
-                                             Expr(1.f), Expr("mat"));
+    auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, Expr(1.f), Expr("mat"));
 
-  WrapInFunction(var, expr);
+    WrapInFunction(var, expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
 
-  EXPECT_EQ(b.GenerateBinaryExpression(expr), 8u) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()),
-            R"(%5 = OpTypeFloat 32
+    EXPECT_EQ(b.GenerateBinaryExpression(expr), 8u) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()),
+              R"(%5 = OpTypeFloat 32
 %4 = OpTypeVector %5 3
 %3 = OpTypeMatrix %4 3
 %2 = OpTypePointer Function %3
 %1 = OpVariable %2 Function
 %6 = OpConstant %5 1
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%7 = OpLoad %3 %1
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%7 = OpLoad %3 %1
 %8 = OpMatrixTimesScalar %3 %7 %6
 )");
 }
 
 TEST_F(BuilderTest, Binary_Multiply_MatrixVector) {
-  auto* var = Var("mat", ty.mat3x3<f32>());
-  auto* rhs = vec3<f32>(1.f, 1.f, 1.f);
+    auto* var = Var("mat", ty.mat3x3<f32>());
+    auto* rhs = vec3<f32>(1.f, 1.f, 1.f);
 
-  auto* expr =
-      create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, Expr("mat"), rhs);
+    auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, Expr("mat"), rhs);
 
-  WrapInFunction(var, expr);
+    WrapInFunction(var, expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
 
-  EXPECT_EQ(b.GenerateBinaryExpression(expr), 9u) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()),
-            R"(%5 = OpTypeFloat 32
+    EXPECT_EQ(b.GenerateBinaryExpression(expr), 9u) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()),
+              R"(%5 = OpTypeFloat 32
 %4 = OpTypeVector %5 3
 %3 = OpTypeMatrix %4 3
 %2 = OpTypePointer Function %3
@@ -616,29 +605,28 @@
 %7 = OpConstant %5 1
 %8 = OpConstantComposite %4 %7 %7 %7
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%6 = OpLoad %3 %1
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%6 = OpLoad %3 %1
 %9 = OpMatrixTimesVector %4 %6 %8
 )");
 }
 
 TEST_F(BuilderTest, Binary_Multiply_VectorMatrix) {
-  auto* var = Var("mat", ty.mat3x3<f32>());
-  auto* lhs = vec3<f32>(1.f, 1.f, 1.f);
+    auto* var = Var("mat", ty.mat3x3<f32>());
+    auto* lhs = vec3<f32>(1.f, 1.f, 1.f);
 
-  auto* expr =
-      create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, Expr("mat"));
+    auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, lhs, Expr("mat"));
 
-  WrapInFunction(var, expr);
+    WrapInFunction(var, expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
 
-  EXPECT_EQ(b.GenerateBinaryExpression(expr), 9u) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()),
-            R"(%5 = OpTypeFloat 32
+    EXPECT_EQ(b.GenerateBinaryExpression(expr), 9u) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()),
+              R"(%5 = OpTypeFloat 32
 %4 = OpTypeVector %5 3
 %3 = OpTypeMatrix %4 3
 %2 = OpTypePointer Function %3
@@ -646,68 +634,64 @@
 %6 = OpConstant %5 1
 %7 = OpConstantComposite %4 %6 %6 %6
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%8 = OpLoad %3 %1
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%8 = OpLoad %3 %1
 %9 = OpVectorTimesMatrix %4 %7 %8
 )");
 }
 
 TEST_F(BuilderTest, Binary_Multiply_MatrixMatrix) {
-  auto* var = Var("mat", ty.mat3x3<f32>());
+    auto* var = Var("mat", ty.mat3x3<f32>());
 
-  auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply,
-                                             Expr("mat"), Expr("mat"));
+    auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kMultiply, Expr("mat"), Expr("mat"));
 
-  WrapInFunction(var, expr);
+    WrapInFunction(var, expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
 
-  EXPECT_EQ(b.GenerateBinaryExpression(expr), 8u) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()),
-            R"(%5 = OpTypeFloat 32
+    EXPECT_EQ(b.GenerateBinaryExpression(expr), 8u) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()),
+              R"(%5 = OpTypeFloat 32
 %4 = OpTypeVector %5 3
 %3 = OpTypeMatrix %4 3
 %2 = OpTypePointer Function %3
 %1 = OpVariable %2 Function
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%6 = OpLoad %3 %1
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%6 = OpLoad %3 %1
 %7 = OpLoad %3 %1
 %8 = OpMatrixTimesMatrix %3 %6 %7
 )");
 }
 
 TEST_F(BuilderTest, Binary_LogicalAnd) {
-  auto* lhs =
-      create<ast::BinaryExpression>(ast::BinaryOp::kEqual, Expr(1), Expr(2));
+    auto* lhs = create<ast::BinaryExpression>(ast::BinaryOp::kEqual, Expr(1_i), Expr(2_i));
 
-  auto* rhs =
-      create<ast::BinaryExpression>(ast::BinaryOp::kEqual, Expr(3), Expr(4));
+    auto* rhs = create<ast::BinaryExpression>(ast::BinaryOp::kEqual, Expr(3_i), Expr(4_i));
 
-  auto* expr =
-      create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, lhs, rhs);
+    auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, lhs, rhs);
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  b.GenerateLabel(b.next_id());
+    b.push_function(Function{});
+    b.GenerateLabel(b.next_id());
 
-  EXPECT_EQ(b.GenerateBinaryExpression(expr), 12u) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()),
-            R"(%2 = OpTypeInt 32 1
+    EXPECT_EQ(b.GenerateBinaryExpression(expr), 12u) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()),
+              R"(%2 = OpTypeInt 32 1
 %3 = OpConstant %2 1
 %4 = OpConstant %2 2
 %6 = OpTypeBool
 %9 = OpConstant %2 3
 %10 = OpConstant %2 4
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%1 = OpLabel
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%1 = OpLabel
 %5 = OpIEqual %6 %3 %4
 OpSelectionMerge %7 None
 OpBranchConditional %5 %8 %7
@@ -720,34 +704,31 @@
 }
 
 TEST_F(BuilderTest, Binary_LogicalAnd_WithLoads) {
-  auto* a_var =
-      Global("a", ty.bool_(), ast::StorageClass::kPrivate, Expr(true));
-  auto* b_var =
-      Global("b", ty.bool_(), ast::StorageClass::kPrivate, Expr(false));
+    auto* a_var = Global("a", ty.bool_(), ast::StorageClass::kPrivate, Expr(true));
+    auto* b_var = Global("b", ty.bool_(), ast::StorageClass::kPrivate, Expr(false));
 
-  auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd,
-                                             Expr("a"), Expr("b"));
+    auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr("a"), Expr("b"));
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  b.GenerateLabel(b.next_id());
+    b.push_function(Function{});
+    b.GenerateLabel(b.next_id());
 
-  ASSERT_TRUE(b.GenerateGlobalVariable(a_var)) << b.error();
-  ASSERT_TRUE(b.GenerateGlobalVariable(b_var)) << b.error();
+    ASSERT_TRUE(b.GenerateGlobalVariable(a_var)) << b.error();
+    ASSERT_TRUE(b.GenerateGlobalVariable(b_var)) << b.error();
 
-  EXPECT_EQ(b.GenerateBinaryExpression(expr), 12u) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeBool
+    EXPECT_EQ(b.GenerateBinaryExpression(expr), 12u) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeBool
 %3 = OpConstantTrue %2
 %5 = OpTypePointer Private %2
 %4 = OpVariable %5 Private %3
 %6 = OpConstantFalse %2
 %7 = OpVariable %5 Private %6
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%1 = OpLabel
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%1 = OpLabel
 %8 = OpLoad %2 %4
 OpSelectionMerge %9 None
 OpBranchConditional %8 %10 %9
@@ -760,30 +741,30 @@
 }
 
 TEST_F(BuilderTest, Binary_logicalOr_Nested_LogicalAnd) {
-  // Test an expression like
-  //    a || (b && c)
-  // From: crbug.com/tint/355
+    // Test an expression like
+    //    a || (b && c)
+    // From: crbug.com/tint/355
 
-  auto* logical_and_expr = create<ast::BinaryExpression>(
-      ast::BinaryOp::kLogicalAnd, Expr(true), Expr(false));
+    auto* logical_and_expr =
+        create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr(true), Expr(false));
 
-  auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr,
-                                             Expr(true), logical_and_expr);
+    auto* expr =
+        create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr(true), logical_and_expr);
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  b.GenerateLabel(b.next_id());
+    b.push_function(Function{});
+    b.GenerateLabel(b.next_id());
 
-  EXPECT_EQ(b.GenerateBinaryExpression(expr), 10u) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeBool
+    EXPECT_EQ(b.GenerateBinaryExpression(expr), 10u) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeBool
 %3 = OpConstantTrue %2
 %8 = OpConstantFalse %2
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%1 = OpLabel
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%1 = OpLabel
 OpSelectionMerge %4 None
 OpBranchConditional %3 %4 %5
 %5 = OpLabel
@@ -800,30 +781,30 @@
 }
 
 TEST_F(BuilderTest, Binary_logicalAnd_Nested_LogicalOr) {
-  // Test an expression like
-  //    a && (b || c)
-  // From: crbug.com/tint/355
+    // Test an expression like
+    //    a && (b || c)
+    // From: crbug.com/tint/355
 
-  auto* logical_or_expr = create<ast::BinaryExpression>(
-      ast::BinaryOp::kLogicalOr, Expr(true), Expr(false));
+    auto* logical_or_expr =
+        create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr(true), Expr(false));
 
-  auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd,
-                                             Expr(true), logical_or_expr);
+    auto* expr =
+        create<ast::BinaryExpression>(ast::BinaryOp::kLogicalAnd, Expr(true), logical_or_expr);
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  b.GenerateLabel(b.next_id());
+    b.push_function(Function{});
+    b.GenerateLabel(b.next_id());
 
-  EXPECT_EQ(b.GenerateBinaryExpression(expr), 10u) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeBool
+    EXPECT_EQ(b.GenerateBinaryExpression(expr), 10u) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeBool
 %3 = OpConstantTrue %2
 %8 = OpConstantFalse %2
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%1 = OpLabel
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%1 = OpLabel
 OpSelectionMerge %4 None
 OpBranchConditional %3 %5 %4
 %5 = OpLabel
@@ -840,33 +821,30 @@
 }
 
 TEST_F(BuilderTest, Binary_LogicalOr) {
-  auto* lhs =
-      create<ast::BinaryExpression>(ast::BinaryOp::kEqual, Expr(1), Expr(2));
+    auto* lhs = create<ast::BinaryExpression>(ast::BinaryOp::kEqual, Expr(1_i), Expr(2_i));
 
-  auto* rhs =
-      create<ast::BinaryExpression>(ast::BinaryOp::kEqual, Expr(3), Expr(4));
+    auto* rhs = create<ast::BinaryExpression>(ast::BinaryOp::kEqual, Expr(3_i), Expr(4_i));
 
-  auto* expr =
-      create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, lhs, rhs);
+    auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, lhs, rhs);
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  b.GenerateLabel(b.next_id());
+    b.push_function(Function{});
+    b.GenerateLabel(b.next_id());
 
-  EXPECT_EQ(b.GenerateBinaryExpression(expr), 12u) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()),
-            R"(%2 = OpTypeInt 32 1
+    EXPECT_EQ(b.GenerateBinaryExpression(expr), 12u) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()),
+              R"(%2 = OpTypeInt 32 1
 %3 = OpConstant %2 1
 %4 = OpConstant %2 2
 %6 = OpTypeBool
 %9 = OpConstant %2 3
 %10 = OpConstant %2 4
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%1 = OpLabel
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%1 = OpLabel
 %5 = OpIEqual %6 %3 %4
 OpSelectionMerge %7 None
 OpBranchConditional %5 %7 %8
@@ -879,34 +857,31 @@
 }
 
 TEST_F(BuilderTest, Binary_LogicalOr_WithLoads) {
-  auto* a_var =
-      Global("a", ty.bool_(), ast::StorageClass::kPrivate, Expr(true));
-  auto* b_var =
-      Global("b", ty.bool_(), ast::StorageClass::kPrivate, Expr(false));
+    auto* a_var = Global("a", ty.bool_(), ast::StorageClass::kPrivate, Expr(true));
+    auto* b_var = Global("b", ty.bool_(), ast::StorageClass::kPrivate, Expr(false));
 
-  auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr,
-                                             Expr("a"), Expr("b"));
+    auto* expr = create<ast::BinaryExpression>(ast::BinaryOp::kLogicalOr, Expr("a"), Expr("b"));
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  b.GenerateLabel(b.next_id());
+    b.push_function(Function{});
+    b.GenerateLabel(b.next_id());
 
-  ASSERT_TRUE(b.GenerateGlobalVariable(a_var)) << b.error();
-  ASSERT_TRUE(b.GenerateGlobalVariable(b_var)) << b.error();
+    ASSERT_TRUE(b.GenerateGlobalVariable(a_var)) << b.error();
+    ASSERT_TRUE(b.GenerateGlobalVariable(b_var)) << b.error();
 
-  EXPECT_EQ(b.GenerateBinaryExpression(expr), 12u) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeBool
+    EXPECT_EQ(b.GenerateBinaryExpression(expr), 12u) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeBool
 %3 = OpConstantTrue %2
 %5 = OpTypePointer Private %2
 %4 = OpVariable %5 Private %3
 %6 = OpConstantFalse %2
 %7 = OpVariable %5 Private %6
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%1 = OpLabel
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%1 = OpLabel
 %8 = OpLoad %2 %4
 OpSelectionMerge %9 None
 OpBranchConditional %8 %9 %10
@@ -921,64 +896,62 @@
 namespace BinaryArithVectorScalar {
 
 enum class Type { f32, i32, u32 };
-static const ast::Expression* MakeVectorExpr(ProgramBuilder* builder,
-                                             Type type) {
-  switch (type) {
-    case Type::f32:
-      return builder->vec3<ProgramBuilder::f32>(1.f, 1.f, 1.f);
-    case Type::i32:
-      return builder->vec3<ProgramBuilder::i32>(1, 1, 1);
-    case Type::u32:
-      return builder->vec3<ProgramBuilder::u32>(1u, 1u, 1u);
-  }
-  return nullptr;
+static const ast::Expression* MakeVectorExpr(ProgramBuilder* builder, Type type) {
+    switch (type) {
+        case Type::f32:
+            return builder->vec3<f32>(1.f, 1.f, 1.f);
+        case Type::i32:
+            return builder->vec3<i32>(1_i, 1_i, 1_i);
+        case Type::u32:
+            return builder->vec3<u32>(1_u, 1_u, 1_u);
+    }
+    return nullptr;
 }
-static const ast::Expression* MakeScalarExpr(ProgramBuilder* builder,
-                                             Type type) {
-  switch (type) {
-    case Type::f32:
-      return builder->Expr(1.f);
-    case Type::i32:
-      return builder->Expr(1);
-    case Type::u32:
-      return builder->Expr(1u);
-  }
-  return nullptr;
+static const ast::Expression* MakeScalarExpr(ProgramBuilder* builder, Type type) {
+    switch (type) {
+        case Type::f32:
+            return builder->Expr(1.f);
+        case Type::i32:
+            return builder->Expr(1_i);
+        case Type::u32:
+            return builder->Expr(1_u);
+    }
+    return nullptr;
 }
 static std::string OpTypeDecl(Type type) {
-  switch (type) {
-    case Type::f32:
-      return "OpTypeFloat 32";
-    case Type::i32:
-      return "OpTypeInt 32 1";
-    case Type::u32:
-      return "OpTypeInt 32 0";
-  }
-  return {};
+    switch (type) {
+        case Type::f32:
+            return "OpTypeFloat 32";
+        case Type::i32:
+            return "OpTypeInt 32 1";
+        case Type::u32:
+            return "OpTypeInt 32 0";
+    }
+    return {};
 }
 
 struct Param {
-  Type type;
-  ast::BinaryOp op;
-  std::string name;
+    Type type;
+    ast::BinaryOp op;
+    std::string name;
 };
 
 using BinaryArithVectorScalarTest = TestParamHelper<Param>;
 TEST_P(BinaryArithVectorScalarTest, VectorScalar) {
-  auto& param = GetParam();
+    auto& param = GetParam();
 
-  const ast::Expression* lhs = MakeVectorExpr(this, param.type);
-  const ast::Expression* rhs = MakeScalarExpr(this, param.type);
-  std::string op_type_decl = OpTypeDecl(param.type);
+    const ast::Expression* lhs = MakeVectorExpr(this, param.type);
+    const ast::Expression* rhs = MakeScalarExpr(this, param.type);
+    std::string op_type_decl = OpTypeDecl(param.type);
 
-  auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
+    auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
-  ASSERT_TRUE(b.Build()) << b.error();
+    spirv::Builder& b = Build();
+    ASSERT_TRUE(b.Build()) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(OpCapability Shader
+    EXPECT_EQ(DumpBuilder(b), R"(OpCapability Shader
 OpMemoryModel Logical GLSL450
 OpEntryPoint GLCompute %3 "test_function"
 OpExecutionMode %3 LocalSize 1 1 1
@@ -1000,23 +973,23 @@
 OpFunctionEnd
 )");
 
-  Validate(b);
+    Validate(b);
 }
 TEST_P(BinaryArithVectorScalarTest, ScalarVector) {
-  auto& param = GetParam();
+    auto& param = GetParam();
 
-  const ast::Expression* lhs = MakeScalarExpr(this, param.type);
-  const ast::Expression* rhs = MakeVectorExpr(this, param.type);
-  std::string op_type_decl = OpTypeDecl(param.type);
+    const ast::Expression* lhs = MakeScalarExpr(this, param.type);
+    const ast::Expression* rhs = MakeVectorExpr(this, param.type);
+    std::string op_type_decl = OpTypeDecl(param.type);
 
-  auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
+    auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
-  ASSERT_TRUE(b.Build()) << b.error();
+    spirv::Builder& b = Build();
+    ASSERT_TRUE(b.Build()) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(OpCapability Shader
+    EXPECT_EQ(DumpBuilder(b), R"(OpCapability Shader
 OpMemoryModel Logical GLSL450
 OpEntryPoint GLCompute %3 "test_function"
 OpExecutionMode %3 LocalSize 1 1 1
@@ -1038,48 +1011,47 @@
 OpFunctionEnd
 )");
 
-  Validate(b);
+    Validate(b);
 }
-INSTANTIATE_TEST_SUITE_P(
-    BuilderTest,
-    BinaryArithVectorScalarTest,
-    testing::Values(Param{Type::f32, ast::BinaryOp::kAdd, "OpFAdd"},
-                    Param{Type::f32, ast::BinaryOp::kDivide, "OpFDiv"},
-                    // NOTE: Modulo not allowed on mixed float scalar-vector
-                    // Param{Type::f32, ast::BinaryOp::kModulo, "OpFMod"},
-                    // NOTE: We test f32 multiplies separately as we emit
-                    // OpVectorTimesScalar for this case
-                    // Param{Type::i32, ast::BinaryOp::kMultiply, "OpIMul"},
-                    Param{Type::f32, ast::BinaryOp::kSubtract, "OpFSub"},
+INSTANTIATE_TEST_SUITE_P(BuilderTest,
+                         BinaryArithVectorScalarTest,
+                         testing::Values(Param{Type::f32, ast::BinaryOp::kAdd, "OpFAdd"},
+                                         Param{Type::f32, ast::BinaryOp::kDivide, "OpFDiv"},
+                                         // NOTE: Modulo not allowed on mixed float scalar-vector
+                                         // Param{Type::f32, ast::BinaryOp::kModulo, "OpFMod"},
+                                         // NOTE: We test f32 multiplies separately as we emit
+                                         // OpVectorTimesScalar for this case
+                                         // Param{Type::i32, ast::BinaryOp::kMultiply, "OpIMul"},
+                                         Param{Type::f32, ast::BinaryOp::kSubtract, "OpFSub"},
 
-                    Param{Type::i32, ast::BinaryOp::kAdd, "OpIAdd"},
-                    Param{Type::i32, ast::BinaryOp::kDivide, "OpSDiv"},
-                    Param{Type::i32, ast::BinaryOp::kModulo, "OpSMod"},
-                    Param{Type::i32, ast::BinaryOp::kMultiply, "OpIMul"},
-                    Param{Type::i32, ast::BinaryOp::kSubtract, "OpISub"},
+                                         Param{Type::i32, ast::BinaryOp::kAdd, "OpIAdd"},
+                                         Param{Type::i32, ast::BinaryOp::kDivide, "OpSDiv"},
+                                         Param{Type::i32, ast::BinaryOp::kModulo, "OpSMod"},
+                                         Param{Type::i32, ast::BinaryOp::kMultiply, "OpIMul"},
+                                         Param{Type::i32, ast::BinaryOp::kSubtract, "OpISub"},
 
-                    Param{Type::u32, ast::BinaryOp::kAdd, "OpIAdd"},
-                    Param{Type::u32, ast::BinaryOp::kDivide, "OpUDiv"},
-                    Param{Type::u32, ast::BinaryOp::kModulo, "OpUMod"},
-                    Param{Type::u32, ast::BinaryOp::kMultiply, "OpIMul"},
-                    Param{Type::u32, ast::BinaryOp::kSubtract, "OpISub"}));
+                                         Param{Type::u32, ast::BinaryOp::kAdd, "OpIAdd"},
+                                         Param{Type::u32, ast::BinaryOp::kDivide, "OpUDiv"},
+                                         Param{Type::u32, ast::BinaryOp::kModulo, "OpUMod"},
+                                         Param{Type::u32, ast::BinaryOp::kMultiply, "OpIMul"},
+                                         Param{Type::u32, ast::BinaryOp::kSubtract, "OpISub"}));
 
 using BinaryArithVectorScalarMultiplyTest = TestParamHelper<Param>;
 TEST_P(BinaryArithVectorScalarMultiplyTest, VectorScalar) {
-  auto& param = GetParam();
+    auto& param = GetParam();
 
-  const ast::Expression* lhs = MakeVectorExpr(this, param.type);
-  const ast::Expression* rhs = MakeScalarExpr(this, param.type);
-  std::string op_type_decl = OpTypeDecl(param.type);
+    const ast::Expression* lhs = MakeVectorExpr(this, param.type);
+    const ast::Expression* rhs = MakeScalarExpr(this, param.type);
+    std::string op_type_decl = OpTypeDecl(param.type);
 
-  auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
+    auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
-  ASSERT_TRUE(b.Build()) << b.error();
+    spirv::Builder& b = Build();
+    ASSERT_TRUE(b.Build()) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(OpCapability Shader
+    EXPECT_EQ(DumpBuilder(b), R"(OpCapability Shader
 OpMemoryModel Logical GLSL450
 OpEntryPoint GLCompute %3 "test_function"
 OpExecutionMode %3 LocalSize 1 1 1
@@ -1097,23 +1069,23 @@
 OpFunctionEnd
 )");
 
-  Validate(b);
+    Validate(b);
 }
 TEST_P(BinaryArithVectorScalarMultiplyTest, ScalarVector) {
-  auto& param = GetParam();
+    auto& param = GetParam();
 
-  const ast::Expression* lhs = MakeScalarExpr(this, param.type);
-  const ast::Expression* rhs = MakeVectorExpr(this, param.type);
-  std::string op_type_decl = OpTypeDecl(param.type);
+    const ast::Expression* lhs = MakeScalarExpr(this, param.type);
+    const ast::Expression* rhs = MakeVectorExpr(this, param.type);
+    std::string op_type_decl = OpTypeDecl(param.type);
 
-  auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
+    auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
-  ASSERT_TRUE(b.Build()) << b.error();
+    spirv::Builder& b = Build();
+    ASSERT_TRUE(b.Build()) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(OpCapability Shader
+    EXPECT_EQ(DumpBuilder(b), R"(OpCapability Shader
 OpMemoryModel Logical GLSL450
 OpEntryPoint GLCompute %3 "test_function"
 OpExecutionMode %3 LocalSize 1 1 1
@@ -1131,37 +1103,36 @@
 OpFunctionEnd
 )");
 
-  Validate(b);
+    Validate(b);
 }
 INSTANTIATE_TEST_SUITE_P(BuilderTest,
                          BinaryArithVectorScalarMultiplyTest,
-                         testing::Values(Param{
-                             Type::f32, ast::BinaryOp::kMultiply, "OpFMul"}));
+                         testing::Values(Param{Type::f32, ast::BinaryOp::kMultiply, "OpFMul"}));
 
 }  // namespace BinaryArithVectorScalar
 
 namespace BinaryArithMatrixMatrix {
 
 struct Param {
-  ast::BinaryOp op;
-  std::string name;
+    ast::BinaryOp op;
+    std::string name;
 };
 
 using BinaryArithMatrixMatrix = TestParamHelper<Param>;
 TEST_P(BinaryArithMatrixMatrix, AddOrSubtract) {
-  auto& param = GetParam();
+    auto& param = GetParam();
 
-  const ast::Expression* lhs = mat3x4<f32>();
-  const ast::Expression* rhs = mat3x4<f32>();
+    const ast::Expression* lhs = mat3x4<f32>();
+    const ast::Expression* rhs = mat3x4<f32>();
 
-  auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
+    auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
-  ASSERT_TRUE(b.Build()) << b.error();
+    spirv::Builder& b = Build();
+    ASSERT_TRUE(b.Build()) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(OpCapability Shader
+    EXPECT_EQ(DumpBuilder(b), R"(OpCapability Shader
 OpMemoryModel Logical GLSL450
 OpEntryPoint GLCompute %3 "test_function"
 OpExecutionMode %3 LocalSize 1 1 1
@@ -1188,7 +1159,7 @@
 OpFunctionEnd
 )");
 
-  Validate(b);
+    Validate(b);
 }
 INSTANTIATE_TEST_SUITE_P(  //
     BuilderTest,
@@ -1198,19 +1169,19 @@
 
 using BinaryArithMatrixMatrixMultiply = TestParamHelper<Param>;
 TEST_P(BinaryArithMatrixMatrixMultiply, Multiply) {
-  auto& param = GetParam();
+    auto& param = GetParam();
 
-  const ast::Expression* lhs = mat3x4<f32>();
-  const ast::Expression* rhs = mat4x3<f32>();
+    const ast::Expression* lhs = mat3x4<f32>();
+    const ast::Expression* rhs = mat4x3<f32>();
 
-  auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
+    auto* expr = create<ast::BinaryExpression>(param.op, lhs, rhs);
 
-  WrapInFunction(expr);
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
-  ASSERT_TRUE(b.Build()) << b.error();
+    spirv::Builder& b = Build();
+    ASSERT_TRUE(b.Build()) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(OpCapability Shader
+    EXPECT_EQ(DumpBuilder(b), R"(OpCapability Shader
 OpMemoryModel Logical GLSL450
 OpEntryPoint GLCompute %3 "test_function"
 OpExecutionMode %3 LocalSize 1 1 1
@@ -1232,7 +1203,7 @@
 OpFunctionEnd
 )");
 
-  Validate(b);
+    Validate(b);
 }
 INSTANTIATE_TEST_SUITE_P(  //
     BuilderTest,
diff --git a/src/tint/writer/spirv/builder_bitcast_expression_test.cc b/src/tint/writer/spirv/builder_bitcast_expression_test.cc
index 655ed33..073d000 100644
--- a/src/tint/writer/spirv/builder_bitcast_expression_test.cc
+++ b/src/tint/writer/spirv/builder_bitcast_expression_test.cc
@@ -21,39 +21,39 @@
 using BuilderTest = TestHelper;
 
 TEST_F(BuilderTest, Bitcast) {
-  auto* bitcast = create<ast::BitcastExpression>(ty.u32(), Expr(2.4f));
+    auto* bitcast = create<ast::BitcastExpression>(ty.u32(), Expr(2.4f));
 
-  WrapInFunction(bitcast);
+    WrapInFunction(bitcast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateBitcastExpression(bitcast), 1u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateBitcastExpression(bitcast), 1u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 0
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 0
 %3 = OpTypeFloat 32
 %4 = OpConstant %3 2.4000001
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%1 = OpBitcast %2 %4
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%1 = OpBitcast %2 %4
 )");
 }
 
 TEST_F(BuilderTest, Bitcast_DuplicateType) {
-  auto* bitcast = create<ast::BitcastExpression>(ty.f32(), Expr(2.4f));
+    auto* bitcast = create<ast::BitcastExpression>(ty.f32(), Expr(2.4f));
 
-  WrapInFunction(bitcast);
+    WrapInFunction(bitcast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateBitcastExpression(bitcast), 1u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateBitcastExpression(bitcast), 1u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %3 = OpConstant %2 2.4000001
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%1 = OpCopyObject %2 %3
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%1 = OpCopyObject %2 %3
 )");
 }
 
diff --git a/src/tint/writer/spirv/builder_block_test.cc b/src/tint/writer/spirv/builder_block_test.cc
index 462161b..ea70b6c 100644
--- a/src/tint/writer/spirv/builder_block_test.cc
+++ b/src/tint/writer/spirv/builder_block_test.cc
@@ -21,24 +21,23 @@
 using BuilderTest = TestHelper;
 
 TEST_F(BuilderTest, Block) {
-  // Note, this test uses shadow variables which aren't allowed in WGSL but
-  // serves to prove the block code is pushing new scopes as needed.
-  auto* inner = Block(Decl(Var("var", ty.f32(), ast::StorageClass::kNone)),
-                      Assign("var", 2.f));
-  auto* outer = Block(Decl(Var("var", ty.f32(), ast::StorageClass::kNone)),
-                      Assign("var", 1.f), inner, Assign("var", 3.f));
+    // Note, this test uses shadow variables which aren't allowed in WGSL but
+    // serves to prove the block code is pushing new scopes as needed.
+    auto* inner = Block(Decl(Var("var", ty.f32(), ast::StorageClass::kNone)), Assign("var", 2.f));
+    auto* outer = Block(Decl(Var("var", ty.f32(), ast::StorageClass::kNone)), Assign("var", 1.f),
+                        inner, Assign("var", 3.f));
 
-  WrapInFunction(outer);
+    WrapInFunction(outer);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_FALSE(b.has_error()) << b.error();
+    b.push_function(Function{});
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_TRUE(b.GenerateStatement(outer)) << b.error();
-  EXPECT_FALSE(b.has_error());
+    EXPECT_TRUE(b.GenerateStatement(outer)) << b.error();
+    EXPECT_FALSE(b.has_error());
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
 %2 = OpTypePointer Function %3
 %4 = OpConstantNull %3
 %5 = OpConstant %3 1
@@ -46,13 +45,13 @@
 %8 = OpConstant %3 3
 )");
 
-  EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-            R"(%1 = OpVariable %2 Function %4
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
+              R"(%1 = OpVariable %2 Function %4
 %6 = OpVariable %2 Function %4
 )");
 
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(OpStore %1 %5
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpStore %1 %5
 OpStore %6 %7
 OpStore %1 %8
 )");
diff --git a/src/tint/writer/spirv/builder_builtin_test.cc b/src/tint/writer/spirv/builder_builtin_test.cc
index 321cc0e..901abad 100644
--- a/src/tint/writer/spirv/builder_builtin_test.cc
+++ b/src/tint/writer/spirv/builder_builtin_test.cc
@@ -14,11 +14,13 @@
 
 #include "src/tint/ast/call_statement.h"
 #include "src/tint/ast/stage_attribute.h"
-#include "src/tint/sem/depth_texture_type.h"
+#include "src/tint/sem/depth_texture.h"
 #include "src/tint/utils/string.h"
 #include "src/tint/writer/spirv/spv_dump.h"
 #include "src/tint/writer/spirv/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::spirv {
 namespace {
 
@@ -28,30 +30,30 @@
 using BuiltinBuilderTestWithParam = TestParamHelper<T>;
 
 struct BuiltinData {
-  std::string name;
-  std::string op;
+    std::string name;
+    std::string op;
 };
 inline std::ostream& operator<<(std::ostream& out, BuiltinData data) {
-  out << data.name;
-  return out;
+    out << data.name;
+    return out;
 }
 
 using BuiltinBoolTest = BuiltinBuilderTestWithParam<BuiltinData>;
 TEST_P(BuiltinBoolTest, Call_Bool_Scalar) {
-  auto param = GetParam();
-  auto* var = Global("v", ty.bool_(), ast::StorageClass::kPrivate);
-  auto* expr = Call(param.name, "v");
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Assign(Phony(), expr),
-                    });
+    auto param = GetParam();
+    auto* var = Global("v", ty.bool_(), ast::StorageClass::kPrivate);
+    auto* expr = Call(param.name, "v");
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Assign(Phony(), expr),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeBool
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeBool
 %2 = OpTypePointer Private %3
 %4 = OpConstantNull %3
 %1 = OpVariable %2 Private %4
@@ -59,26 +61,25 @@
 %5 = OpTypeFunction %6
 )");
 
-  // both any and all are 'passthrough' for scalar booleans
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            "%10 = OpLoad %3 %1\nOpReturn\n");
+    // both any and all are 'passthrough' for scalar booleans
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), "%10 = OpLoad %3 %1\nOpReturn\n");
 }
 
 TEST_P(BuiltinBoolTest, Call_Bool_Vector) {
-  auto param = GetParam();
-  auto* var = Global("v", ty.vec3<bool>(), ast::StorageClass::kPrivate);
-  auto* expr = Call(param.name, "v");
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Assign(Phony(), expr),
-                    });
+    auto param = GetParam();
+    auto* var = Global("v", ty.vec3<bool>(), ast::StorageClass::kPrivate);
+    auto* expr = Call(param.name, "v");
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Assign(Phony(), expr),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeBool
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeBool
 %3 = OpTypeVector %4 3
 %2 = OpTypePointer Private %3
 %5 = OpConstantNull %3
@@ -87,34 +88,33 @@
 %6 = OpTypeFunction %7
 )");
 
-  auto expected = utils::ReplaceAll(R"(%11 = OpLoad %3 %1
+    auto expected = utils::ReplaceAll(R"(%11 = OpLoad %3 %1
 %10 = ${op} %4 %11
 OpReturn
 )",
-                                    "${op}", param.op);
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), expected);
+                                      "${op}", param.op);
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), expected);
 }
 INSTANTIATE_TEST_SUITE_P(BuiltinBuilderTest,
                          BuiltinBoolTest,
-                         testing::Values(BuiltinData{"any", "OpAny"},
-                                         BuiltinData{"all", "OpAll"}));
+                         testing::Values(BuiltinData{"any", "OpAny"}, BuiltinData{"all", "OpAll"}));
 
 using BuiltinIntTest = BuiltinBuilderTestWithParam<BuiltinData>;
 TEST_P(BuiltinIntTest, Call_SInt_Scalar) {
-  auto param = GetParam();
-  auto* var = Global("v", ty.i32(), ast::StorageClass::kPrivate);
-  auto* expr = Call(param.name, "v");
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Assign(Phony(), expr),
-                    });
+    auto param = GetParam();
+    auto* var = Global("v", ty.i32(), ast::StorageClass::kPrivate);
+    auto* expr = Call(param.name, "v");
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Assign(Phony(), expr),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeInt 32 1
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeInt 32 1
 %2 = OpTypePointer Private %3
 %4 = OpConstantNull %3
 %1 = OpVariable %2 Private %4
@@ -122,29 +122,29 @@
 %5 = OpTypeFunction %6
 )");
 
-  auto expected = utils::ReplaceAll(R"(%10 = OpLoad %3 %1
+    auto expected = utils::ReplaceAll(R"(%10 = OpLoad %3 %1
 %9 = ${op} %3 %10
 OpReturn
 )",
-                                    "${op}", param.op);
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), expected);
+                                      "${op}", param.op);
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), expected);
 }
 
 TEST_P(BuiltinIntTest, Call_SInt_Vector) {
-  auto param = GetParam();
-  auto* var = Global("v", ty.vec3<i32>(), ast::StorageClass::kPrivate);
-  auto* expr = Call(param.name, "v");
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Assign(Phony(), expr),
-                    });
+    auto param = GetParam();
+    auto* var = Global("v", ty.vec3<i32>(), ast::StorageClass::kPrivate);
+    auto* expr = Call(param.name, "v");
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Assign(Phony(), expr),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 1
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 1
 %3 = OpTypeVector %4 3
 %2 = OpTypePointer Private %3
 %5 = OpConstantNull %3
@@ -153,29 +153,29 @@
 %6 = OpTypeFunction %7
 )");
 
-  auto expected = utils::ReplaceAll(R"(%11 = OpLoad %3 %1
+    auto expected = utils::ReplaceAll(R"(%11 = OpLoad %3 %1
 %10 = ${op} %3 %11
 OpReturn
 )",
-                                    "${op}", param.op);
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), expected);
+                                      "${op}", param.op);
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), expected);
 }
 
 TEST_P(BuiltinIntTest, Call_UInt_Scalar) {
-  auto param = GetParam();
-  auto* var = Global("v", ty.u32(), ast::StorageClass::kPrivate);
-  auto* expr = Call(param.name, "v");
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Assign(Phony(), expr),
-                    });
+    auto param = GetParam();
+    auto* var = Global("v", ty.u32(), ast::StorageClass::kPrivate);
+    auto* expr = Call(param.name, "v");
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Assign(Phony(), expr),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeInt 32 0
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeInt 32 0
 %2 = OpTypePointer Private %3
 %4 = OpConstantNull %3
 %1 = OpVariable %2 Private %4
@@ -183,29 +183,29 @@
 %5 = OpTypeFunction %6
 )");
 
-  auto expected = utils::ReplaceAll(R"(%10 = OpLoad %3 %1
+    auto expected = utils::ReplaceAll(R"(%10 = OpLoad %3 %1
 %9 = ${op} %3 %10
 OpReturn
 )",
-                                    "${op}", param.op);
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), expected);
+                                      "${op}", param.op);
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), expected);
 }
 
 TEST_P(BuiltinIntTest, Call_UInt_Vector) {
-  auto param = GetParam();
-  auto* var = Global("v", ty.vec3<u32>(), ast::StorageClass::kPrivate);
-  auto* expr = Call(param.name, "v");
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Assign(Phony(), expr),
-                    });
+    auto param = GetParam();
+    auto* var = Global("v", ty.vec3<u32>(), ast::StorageClass::kPrivate);
+    auto* expr = Call(param.name, "v");
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Assign(Phony(), expr),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 0
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 0
 %3 = OpTypeVector %4 3
 %2 = OpTypePointer Private %3
 %5 = OpConstantNull %3
@@ -214,33 +214,32 @@
 %6 = OpTypeFunction %7
 )");
 
-  auto expected = utils::ReplaceAll(R"(%11 = OpLoad %3 %1
+    auto expected = utils::ReplaceAll(R"(%11 = OpLoad %3 %1
 %10 = ${op} %3 %11
 OpReturn
 )",
-                                    "${op}", param.op);
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), expected);
+                                      "${op}", param.op);
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), expected);
 }
-INSTANTIATE_TEST_SUITE_P(
-    BuiltinBuilderTest,
-    BuiltinIntTest,
-    testing::Values(BuiltinData{"countOneBits", "OpBitCount"},
-                    BuiltinData{"reverseBits", "OpBitReverse"}));
+INSTANTIATE_TEST_SUITE_P(BuiltinBuilderTest,
+                         BuiltinIntTest,
+                         testing::Values(BuiltinData{"countOneBits", "OpBitCount"},
+                                         BuiltinData{"reverseBits", "OpBitReverse"}));
 
 TEST_F(BuiltinBuilderTest, Call_Dot_F32) {
-  auto* var = Global("v", ty.vec3<f32>(), ast::StorageClass::kPrivate);
-  auto* expr = Call("dot", "v", "v");
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Assign(Phony(), expr),
-                    });
+    auto* var = Global("v", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+    auto* expr = Call("dot", "v", "v");
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Assign(Phony(), expr),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
 %3 = OpTypeVector %4 3
 %2 = OpTypePointer Private %3
 %5 = OpConstantNull %3
@@ -248,8 +247,8 @@
 %7 = OpTypeVoid
 %6 = OpTypeFunction %7
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%11 = OpLoad %3 %1
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%11 = OpLoad %3 %1
 %12 = OpLoad %3 %1
 %10 = OpDot %4 %11 %12
 OpReturn
@@ -257,19 +256,19 @@
 }
 
 TEST_F(BuiltinBuilderTest, Call_Dot_U32) {
-  auto* var = Global("v", ty.vec3<u32>(), ast::StorageClass::kPrivate);
-  auto* expr = Call("dot", "v", "v");
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Assign(Phony(), expr),
-                    });
+    auto* var = Global("v", ty.vec3<u32>(), ast::StorageClass::kPrivate);
+    auto* expr = Call("dot", "v", "v");
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Assign(Phony(), expr),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 0
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 0
 %3 = OpTypeVector %4 3
 %2 = OpTypePointer Private %3
 %5 = OpConstantNull %3
@@ -277,8 +276,8 @@
 %7 = OpTypeVoid
 %6 = OpTypeFunction %7
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%11 = OpLoad %3 %1
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%11 = OpLoad %3 %1
 %12 = OpLoad %3 %1
 %13 = OpCompositeExtract %4 %11 0
 %14 = OpCompositeExtract %4 %12 0
@@ -296,19 +295,19 @@
 }
 
 TEST_F(BuiltinBuilderTest, Call_Dot_I32) {
-  auto* var = Global("v", ty.vec3<i32>(), ast::StorageClass::kPrivate);
-  auto* expr = Call("dot", "v", "v");
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Assign(Phony(), expr),
-                    });
+    auto* var = Global("v", ty.vec3<i32>(), ast::StorageClass::kPrivate);
+    auto* expr = Call("dot", "v", "v");
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Assign(Phony(), expr),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 1
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 1
 %3 = OpTypeVector %4 3
 %2 = OpTypePointer Private %3
 %5 = OpConstantNull %3
@@ -316,8 +315,8 @@
 %7 = OpTypeVoid
 %6 = OpTypeFunction %7
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%11 = OpLoad %3 %1
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%11 = OpLoad %3 %1
 %12 = OpLoad %3 %1
 %13 = OpCompositeExtract %4 %11 0
 %14 = OpCompositeExtract %4 %12 0
@@ -336,18 +335,18 @@
 
 using BuiltinDeriveTest = BuiltinBuilderTestWithParam<BuiltinData>;
 TEST_P(BuiltinDeriveTest, Call_Derivative_Scalar) {
-  auto param = GetParam();
-  auto* var = Global("v", ty.f32(), ast::StorageClass::kPrivate);
-  auto* expr = Call(param.name, "v");
-  auto* func = Func("func", {}, ty.void_(), {CallStmt(expr)},
-                    {Stage(ast::PipelineStage::kFragment)});
+    auto param = GetParam();
+    auto* var = Global("v", ty.f32(), ast::StorageClass::kPrivate);
+    auto* expr = Call(param.name, "v");
+    auto* func =
+        Func("func", {}, ty.void_(), {CallStmt(expr)}, {Stage(ast::PipelineStage::kFragment)});
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
 %2 = OpTypePointer Private %3
 %4 = OpConstantNull %3
 %1 = OpVariable %2 Private %4
@@ -355,33 +354,33 @@
 %5 = OpTypeFunction %6
 )");
 
-  auto expected = utils::ReplaceAll(R"(%10 = OpLoad %3 %1
+    auto expected = utils::ReplaceAll(R"(%10 = OpLoad %3 %1
 %9 = ${op} %3 %10
 OpReturn
 )",
-                                    "${op}", param.op);
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), expected);
+                                      "${op}", param.op);
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), expected);
 }
 
 TEST_P(BuiltinDeriveTest, Call_Derivative_Vector) {
-  auto param = GetParam();
-  auto* var = Global("v", ty.vec3<f32>(), ast::StorageClass::kPrivate);
-  auto* expr = Call(param.name, "v");
-  auto* func = Func("func", {}, ty.void_(), {CallStmt(expr)},
-                    {Stage(ast::PipelineStage::kFragment)});
+    auto param = GetParam();
+    auto* var = Global("v", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+    auto* expr = Call(param.name, "v");
+    auto* func =
+        Func("func", {}, ty.void_(), {CallStmt(expr)}, {Stage(ast::PipelineStage::kFragment)});
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  if (param.name != "dpdx" && param.name != "dpdy" && param.name != "fwidth") {
-    EXPECT_EQ(DumpInstructions(b.capabilities()),
-              R"(OpCapability DerivativeControl
+    if (param.name != "dpdx" && param.name != "dpdy" && param.name != "fwidth") {
+        EXPECT_EQ(DumpInstructions(b.capabilities()),
+                  R"(OpCapability DerivativeControl
 )");
-  }
+    }
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
 %3 = OpTypeVector %4 3
 %2 = OpTypePointer Private %3
 %5 = OpConstantNull %3
@@ -390,44 +389,42 @@
 %6 = OpTypeFunction %7
 )");
 
-  auto expected = utils::ReplaceAll(R"(%11 = OpLoad %3 %1
+    auto expected = utils::ReplaceAll(R"(%11 = OpLoad %3 %1
 %10 = ${op} %3 %11
 OpReturn
 )",
-                                    "${op}", param.op);
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), expected);
+                                      "${op}", param.op);
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), expected);
 }
-INSTANTIATE_TEST_SUITE_P(
-    BuiltinBuilderTest,
-    BuiltinDeriveTest,
-    testing::Values(BuiltinData{"dpdx", "OpDPdx"},
-                    BuiltinData{"dpdxFine", "OpDPdxFine"},
-                    BuiltinData{"dpdxCoarse", "OpDPdxCoarse"},
-                    BuiltinData{"dpdy", "OpDPdy"},
-                    BuiltinData{"dpdyFine", "OpDPdyFine"},
-                    BuiltinData{"dpdyCoarse", "OpDPdyCoarse"},
-                    BuiltinData{"fwidth", "OpFwidth"},
-                    BuiltinData{"fwidthFine", "OpFwidthFine"},
-                    BuiltinData{"fwidthCoarse", "OpFwidthCoarse"}));
+INSTANTIATE_TEST_SUITE_P(BuiltinBuilderTest,
+                         BuiltinDeriveTest,
+                         testing::Values(BuiltinData{"dpdx", "OpDPdx"},
+                                         BuiltinData{"dpdxFine", "OpDPdxFine"},
+                                         BuiltinData{"dpdxCoarse", "OpDPdxCoarse"},
+                                         BuiltinData{"dpdy", "OpDPdy"},
+                                         BuiltinData{"dpdyFine", "OpDPdyFine"},
+                                         BuiltinData{"dpdyCoarse", "OpDPdyCoarse"},
+                                         BuiltinData{"fwidth", "OpFwidth"},
+                                         BuiltinData{"fwidthFine", "OpFwidthFine"},
+                                         BuiltinData{"fwidthCoarse", "OpFwidthCoarse"}));
 
 TEST_F(BuiltinBuilderTest, Call_Select) {
-  auto* v3 = Global("v3", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+    auto* v3 = Global("v3", ty.vec3<f32>(), ast::StorageClass::kPrivate);
 
-  auto* bool_v3 =
-      Global("bool_v3", ty.vec3<bool>(), ast::StorageClass::kPrivate);
-  auto* expr = Call("select", "v3", "v3", "bool_v3");
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Assign(Phony(), expr),
-                    });
+    auto* bool_v3 = Global("bool_v3", ty.vec3<bool>(), ast::StorageClass::kPrivate);
+    auto* expr = Call("select", "v3", "v3", "bool_v3");
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Assign(Phony(), expr),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateGlobalVariable(v3)) << b.error();
-  ASSERT_TRUE(b.GenerateGlobalVariable(bool_v3)) << b.error();
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateGlobalVariable(v3)) << b.error();
+    ASSERT_TRUE(b.GenerateGlobalVariable(bool_v3)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
 %3 = OpTypeVector %4 3
 %2 = OpTypePointer Private %3
 %5 = OpConstantNull %3
@@ -440,8 +437,8 @@
 %12 = OpTypeVoid
 %11 = OpTypeFunction %12
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%16 = OpLoad %8 %6
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%16 = OpLoad %8 %6
 %17 = OpLoad %3 %1
 %18 = OpLoad %3 %1
 %15 = OpSelect %3 %16 %17 %18
@@ -451,40 +448,38 @@
 
 // This tests that we do not push OpTypeSampledImage and float_0 type twice.
 TEST_F(BuiltinBuilderTest, Call_TextureSampleCompare_Twice) {
-  auto* s = ty.sampler(ast::SamplerKind::kComparisonSampler);
-  auto* t = ty.depth_texture(ast::TextureDimension::k2d);
+    auto* s = ty.sampler(ast::SamplerKind::kComparisonSampler);
+    auto* t = ty.depth_texture(ast::TextureDimension::k2d);
 
-  auto* tex = Global("texture", t,
-                     ast::AttributeList{
-                         create<ast::BindingAttribute>(0),
-                         create<ast::GroupAttribute>(0),
-                     });
+    auto* tex = Global("texture", t,
+                       ast::AttributeList{
+                           create<ast::BindingAttribute>(0),
+                           create<ast::GroupAttribute>(0),
+                       });
 
-  auto* sampler = Global("sampler", s,
-                         ast::AttributeList{
-                             create<ast::BindingAttribute>(1),
-                             create<ast::GroupAttribute>(0),
-                         });
+    auto* sampler = Global("sampler", s,
+                           ast::AttributeList{
+                               create<ast::BindingAttribute>(1),
+                               create<ast::GroupAttribute>(0),
+                           });
 
-  auto* expr1 = Call("textureSampleCompare", "texture", "sampler",
-                     vec2<f32>(1.0f, 2.0f), 2.0f);
-  auto* expr2 = Call("textureSampleCompare", "texture", "sampler",
-                     vec2<f32>(1.0f, 2.0f), 2.0f);
+    auto* expr1 = Call("textureSampleCompare", "texture", "sampler", vec2<f32>(1.0f, 2.0f), 2.0f);
+    auto* expr2 = Call("textureSampleCompare", "texture", "sampler", vec2<f32>(1.0f, 2.0f), 2.0f);
 
-  Func("f1", {}, ty.void_(), {CallStmt(expr1)}, {});
-  Func("f2", {}, ty.void_(), {CallStmt(expr2)}, {});
+    Func("f1", {}, ty.void_(), {CallStmt(expr1)}, {});
+    Func("f2", {}, ty.void_(), {CallStmt(expr2)}, {});
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  ASSERT_TRUE(b.GenerateGlobalVariable(tex)) << b.error();
-  ASSERT_TRUE(b.GenerateGlobalVariable(sampler)) << b.error();
+    ASSERT_TRUE(b.GenerateGlobalVariable(tex)) << b.error();
+    ASSERT_TRUE(b.GenerateGlobalVariable(sampler)) << b.error();
 
-  EXPECT_EQ(b.GenerateExpression(expr1), 8u) << b.error();
-  EXPECT_EQ(b.GenerateExpression(expr2), 17u) << b.error();
+    EXPECT_EQ(b.GenerateExpression(expr1), 8u) << b.error();
+    EXPECT_EQ(b.GenerateExpression(expr2), 17u) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
 %1 = OpVariable %2 UniformConstant
@@ -498,8 +493,8 @@
 %16 = OpConstantComposite %13 %14 %15
 )");
 
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%9 = OpLoad %7 %5
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%9 = OpLoad %7 %5
 %10 = OpLoad %3 %1
 %12 = OpSampledImage %11 %10 %9
 %8 = OpImageSampleDrefImplicitLod %4 %12 %16 %15
@@ -511,19 +506,19 @@
 }
 
 TEST_F(BuiltinBuilderTest, Call_GLSLMethod_WithLoad) {
-  auto* var = Global("ident", ty.f32(), ast::StorageClass::kPrivate);
-  auto* expr = Call("round", "ident");
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Assign(Phony(), expr),
-                    });
+    auto* var = Global("ident", ty.f32(), ast::StorageClass::kPrivate);
+    auto* expr = Call("round", "ident");
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Assign(Phony(), expr),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(%10 = OpExtInstImport "GLSL.std.450"
+    EXPECT_EQ(DumpBuilder(b), R"(%10 = OpExtInstImport "GLSL.std.450"
 OpName %1 "ident"
 OpName %7 "a_func"
 %3 = OpTypeFloat 32
@@ -541,21 +536,20 @@
 )");
 }
 
-using Builtin_Builtin_SingleParam_Float_Test =
-    BuiltinBuilderTestWithParam<BuiltinData>;
+using Builtin_Builtin_SingleParam_Float_Test = BuiltinBuilderTestWithParam<BuiltinData>;
 TEST_P(Builtin_Builtin_SingleParam_Float_Test, Call_Scalar) {
-  auto param = GetParam();
-  auto* expr = Call(param.name, 1.0f);
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Assign(Phony(), expr),
-                    });
+    auto param = GetParam();
+    auto* expr = Call(param.name, 1.0f);
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Assign(Phony(), expr),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450"
+    EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450"
 OpName %3 "a_func"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
@@ -564,25 +558,25 @@
 %3 = OpFunction %2 None %1
 %4 = OpLabel
 %5 = OpExtInst %6 %7 )" + param.op +
-                                R"( %8
+                                  R"( %8
 OpReturn
 OpFunctionEnd
 )");
 }
 
 TEST_P(Builtin_Builtin_SingleParam_Float_Test, Call_Vector) {
-  auto param = GetParam();
-  auto* expr = Call(param.name, vec2<f32>(1.0f, 1.0f));
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Assign(Phony(), expr),
-                    });
+    auto param = GetParam();
+    auto* expr = Call(param.name, vec2<f32>(1.0f, 1.0f));
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Assign(Phony(), expr),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450"
+    EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450"
 OpName %3 "a_func"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
@@ -593,7 +587,7 @@
 %3 = OpFunction %2 None %1
 %4 = OpLabel
 %5 = OpExtInst %6 %8 )" + param.op +
-                                R"( %10
+                                  R"( %10
 OpReturn
 OpFunctionEnd
 )");
@@ -612,8 +606,7 @@
                                          BuiltinData{"exp2", "Exp2"},
                                          BuiltinData{"floor", "Floor"},
                                          BuiltinData{"fract", "Fract"},
-                                         BuiltinData{"inverseSqrt",
-                                                     "InverseSqrt"},
+                                         BuiltinData{"inverseSqrt", "InverseSqrt"},
                                          BuiltinData{"log", "Log"},
                                          BuiltinData{"log2", "Log2"},
                                          BuiltinData{"radians", "Radians"},
@@ -627,17 +620,17 @@
                                          BuiltinData{"trunc", "Trunc"}));
 
 TEST_F(BuiltinBuilderTest, Call_Length_Scalar) {
-  auto* expr = Call("length", 1.0f);
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Assign(Phony(), expr),
-                    });
+    auto* expr = Call("length", 1.0f);
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Assign(Phony(), expr),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450"
+    EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450"
 OpName %3 "a_func"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
@@ -652,17 +645,17 @@
 }
 
 TEST_F(BuiltinBuilderTest, Call_Length_Vector) {
-  auto* expr = Call("length", vec2<f32>(1.0f, 1.0f));
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Assign(Phony(), expr),
-                    });
+    auto* expr = Call("length", vec2<f32>(1.0f, 1.0f));
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Assign(Phony(), expr),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450"
+    EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450"
 OpName %3 "a_func"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
@@ -679,17 +672,17 @@
 }
 
 TEST_F(BuiltinBuilderTest, Call_Normalize) {
-  auto* expr = Call("normalize", vec2<f32>(1.0f, 1.0f));
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Assign(Phony(), expr),
-                    });
+    auto* expr = Call("normalize", vec2<f32>(1.0f, 1.0f));
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Assign(Phony(), expr),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450"
+    EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450"
 OpName %3 "a_func"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
@@ -705,21 +698,20 @@
 )");
 }
 
-using Builtin_Builtin_DualParam_Float_Test =
-    BuiltinBuilderTestWithParam<BuiltinData>;
+using Builtin_Builtin_DualParam_Float_Test = BuiltinBuilderTestWithParam<BuiltinData>;
 TEST_P(Builtin_Builtin_DualParam_Float_Test, Call_Scalar) {
-  auto param = GetParam();
-  auto* expr = Call(param.name, 1.0f, 1.0f);
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Assign(Phony(), expr),
-                    });
+    auto param = GetParam();
+    auto* expr = Call(param.name, 1.0f, 1.0f);
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Assign(Phony(), expr),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450"
+    EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450"
 OpName %3 "a_func"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
@@ -728,25 +720,25 @@
 %3 = OpFunction %2 None %1
 %4 = OpLabel
 %5 = OpExtInst %6 %7 )" + param.op +
-                                R"( %8 %8
+                                  R"( %8 %8
 OpReturn
 OpFunctionEnd
 )");
 }
 
 TEST_P(Builtin_Builtin_DualParam_Float_Test, Call_Vector) {
-  auto param = GetParam();
-  auto* expr = Call(param.name, vec2<f32>(1.0f, 1.0f), vec2<f32>(1.0f, 1.0f));
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Assign(Phony(), expr),
-                    });
+    auto param = GetParam();
+    auto* expr = Call(param.name, vec2<f32>(1.0f, 1.0f), vec2<f32>(1.0f, 1.0f));
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Assign(Phony(), expr),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450"
+    EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450"
 OpName %3 "a_func"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
@@ -757,7 +749,7 @@
 %3 = OpFunction %2 None %1
 %4 = OpLabel
 %5 = OpExtInst %6 %8 )" + param.op +
-                                R"( %10 %10
+                                  R"( %10 %10
 OpReturn
 OpFunctionEnd
 )");
@@ -771,17 +763,17 @@
                                          BuiltinData{"step", "Step"}));
 
 TEST_F(BuiltinBuilderTest, Call_Reflect_Vector) {
-  auto* expr = Call("reflect", vec2<f32>(1.0f, 1.0f), vec2<f32>(1.0f, 1.0f));
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Assign(Phony(), expr),
-                    });
+    auto* expr = Call("reflect", vec2<f32>(1.0f, 1.0f), vec2<f32>(1.0f, 1.0f));
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Assign(Phony(), expr),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450"
+    EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450"
 OpName %3 "a_func"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
@@ -798,17 +790,17 @@
 }
 
 TEST_F(BuiltinBuilderTest, Call_Distance_Scalar) {
-  auto* expr = Call("distance", 1.0f, 1.0f);
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Assign(Phony(), expr),
-                    });
+    auto* expr = Call("distance", 1.0f, 1.0f);
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Assign(Phony(), expr),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450"
+    EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450"
 OpName %3 "a_func"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
@@ -823,17 +815,17 @@
 }
 
 TEST_F(BuiltinBuilderTest, Call_Distance_Vector) {
-  auto* expr = Call("distance", vec2<f32>(1.0f, 1.0f), vec2<f32>(1.0f, 1.0f));
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Assign(Phony(), expr),
-                    });
+    auto* expr = Call("distance", vec2<f32>(1.0f, 1.0f), vec2<f32>(1.0f, 1.0f));
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Assign(Phony(), expr),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450"
+    EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450"
 OpName %3 "a_func"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
@@ -850,18 +842,17 @@
 }
 
 TEST_F(BuiltinBuilderTest, Call_Cross) {
-  auto* expr =
-      Call("cross", vec3<f32>(1.0f, 1.0f, 1.0f), vec3<f32>(1.0f, 1.0f, 1.0f));
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Assign(Phony(), expr),
-                    });
+    auto* expr = Call("cross", vec3<f32>(1.0f, 1.0f, 1.0f), vec3<f32>(1.0f, 1.0f, 1.0f));
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Assign(Phony(), expr),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450"
+    EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450"
 OpName %3 "a_func"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
@@ -877,21 +868,20 @@
 )");
 }
 
-using Builtin_Builtin_ThreeParam_Float_Test =
-    BuiltinBuilderTestWithParam<BuiltinData>;
+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.0f, 1.0f, 1.0f);
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Assign(Phony(), expr),
-                    });
+    auto param = GetParam();
+    auto* expr = Call(param.name, 1.0f, 1.0f, 1.0f);
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Assign(Phony(), expr),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450"
+    EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450"
 OpName %3 "a_func"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
@@ -900,26 +890,26 @@
 %3 = OpFunction %2 None %1
 %4 = OpLabel
 %5 = OpExtInst %6 %7 )" + param.op +
-                                R"( %8 %8 %8
+                                  R"( %8 %8 %8
 OpReturn
 OpFunctionEnd
 )");
 }
 
 TEST_P(Builtin_Builtin_ThreeParam_Float_Test, Call_Vector) {
-  auto param = GetParam();
-  auto* expr = Call(param.name, vec2<f32>(1.0f, 1.0f), vec2<f32>(1.0f, 1.0f),
-                    vec2<f32>(1.0f, 1.0f));
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Assign(Phony(), expr),
-                    });
+    auto param = GetParam();
+    auto* expr =
+        Call(param.name, vec2<f32>(1.0f, 1.0f), vec2<f32>(1.0f, 1.0f), vec2<f32>(1.0f, 1.0f));
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Assign(Phony(), expr),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450"
+    EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450"
 OpName %3 "a_func"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
@@ -930,7 +920,7 @@
 %3 = OpFunction %2 None %1
 %4 = OpLabel
 %5 = OpExtInst %6 %8 )" + param.op +
-                                R"( %10 %10 %10
+                                  R"( %10 %10 %10
 OpReturn
 OpFunctionEnd
 )");
@@ -941,22 +931,21 @@
                                          BuiltinData{"fma", "Fma"},
                                          BuiltinData{"mix", "FMix"},
 
-                                         BuiltinData{"smoothstep",
-                                                     "SmoothStep"}));
+                                         BuiltinData{"smoothstep", "SmoothStep"}));
 
 TEST_F(BuiltinBuilderTest, Call_FaceForward_Vector) {
-  auto* expr = Call("faceForward", vec2<f32>(1.0f, 1.0f), vec2<f32>(1.0f, 1.0f),
-                    vec2<f32>(1.0f, 1.0f));
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Assign(Phony(), expr),
-                    });
+    auto* expr =
+        Call("faceForward", vec2<f32>(1.0f, 1.0f), vec2<f32>(1.0f, 1.0f), vec2<f32>(1.0f, 1.0f));
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Assign(Phony(), expr),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450"
+    EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450"
 OpName %3 "a_func"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
@@ -972,21 +961,20 @@
 )");
 }
 
-using Builtin_Builtin_SingleParam_Sint_Test =
-    BuiltinBuilderTestWithParam<BuiltinData>;
+using Builtin_Builtin_SingleParam_Sint_Test = BuiltinBuilderTestWithParam<BuiltinData>;
 TEST_P(Builtin_Builtin_SingleParam_Sint_Test, Call_Scalar) {
-  auto param = GetParam();
-  auto* expr = Call(param.name, 1);
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Assign(Phony(), expr),
-                    });
+    auto param = GetParam();
+    auto* expr = Call(param.name, 1_i);
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Assign(Phony(), expr),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450"
+    EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450"
 OpName %3 "a_func"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
@@ -995,25 +983,25 @@
 %3 = OpFunction %2 None %1
 %4 = OpLabel
 %5 = OpExtInst %6 %7 )" + param.op +
-                                R"( %8
+                                  R"( %8
 OpReturn
 OpFunctionEnd
 )");
 }
 
 TEST_P(Builtin_Builtin_SingleParam_Sint_Test, Call_Vector) {
-  auto param = GetParam();
-  auto* expr = Call(param.name, vec2<i32>(1, 1));
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Assign(Phony(), expr),
-                    });
+    auto param = GetParam();
+    auto* expr = Call(param.name, vec2<i32>(1_i, 1_i));
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Assign(Phony(), expr),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450"
+    EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450"
 OpName %3 "a_func"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
@@ -1024,7 +1012,7 @@
 %3 = OpFunction %2 None %1
 %4 = OpLabel
 %5 = OpExtInst %6 %8 )" + param.op +
-                                R"( %10
+                                  R"( %10
 OpReturn
 OpFunctionEnd
 )");
@@ -1036,17 +1024,17 @@
 // Calling abs() on an unsigned integer scalar / vector is a no-op.
 using Builtin_Builtin_Abs_Uint_Test = BuiltinBuilderTest;
 TEST_F(Builtin_Builtin_Abs_Uint_Test, Call_Scalar) {
-  auto* expr = Call("abs", 1u);
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Assign(Phony(), expr),
-                    });
+    auto* expr = Call("abs", 1_u);
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Assign(Phony(), expr),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(OpName %3 "a_func"
+    EXPECT_EQ(DumpBuilder(b), R"(OpName %3 "a_func"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
 %6 = OpTypeInt 32 0
@@ -1059,17 +1047,17 @@
 }
 
 TEST_F(Builtin_Builtin_Abs_Uint_Test, Call_Vector) {
-  auto* expr = Call("abs", vec2<u32>(1u, 1u));
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Assign(Phony(), expr),
-                    });
+    auto* expr = Call("abs", vec2<u32>(1_u, 1_u));
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Assign(Phony(), expr),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(OpName %3 "a_func"
+    EXPECT_EQ(DumpBuilder(b), R"(OpName %3 "a_func"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
 %7 = OpTypeInt 32 0
@@ -1083,21 +1071,20 @@
 )");
 }
 
-using Builtin_Builtin_DualParam_SInt_Test =
-    BuiltinBuilderTestWithParam<BuiltinData>;
+using Builtin_Builtin_DualParam_SInt_Test = BuiltinBuilderTestWithParam<BuiltinData>;
 TEST_P(Builtin_Builtin_DualParam_SInt_Test, Call_Scalar) {
-  auto param = GetParam();
-  auto* expr = Call(param.name, 1, 1);
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Assign(Phony(), expr),
-                    });
+    auto param = GetParam();
+    auto* expr = Call(param.name, 1_i, 1_i);
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Assign(Phony(), expr),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450"
+    EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450"
 OpName %3 "a_func"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
@@ -1106,25 +1093,25 @@
 %3 = OpFunction %2 None %1
 %4 = OpLabel
 %5 = OpExtInst %6 %7 )" + param.op +
-                                R"( %8 %8
+                                  R"( %8 %8
 OpReturn
 OpFunctionEnd
 )");
 }
 
 TEST_P(Builtin_Builtin_DualParam_SInt_Test, Call_Vector) {
-  auto param = GetParam();
-  auto* expr = Call(param.name, vec2<i32>(1, 1), vec2<i32>(1, 1));
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Assign(Phony(), expr),
-                    });
+    auto param = GetParam();
+    auto* expr = Call(param.name, vec2<i32>(1_i, 1_i), vec2<i32>(1_i, 1_i));
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Assign(Phony(), expr),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450"
+    EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450"
 OpName %3 "a_func"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
@@ -1135,31 +1122,29 @@
 %3 = OpFunction %2 None %1
 %4 = OpLabel
 %5 = OpExtInst %6 %8 )" + param.op +
-                                R"( %10 %10
+                                  R"( %10 %10
 OpReturn
 OpFunctionEnd
 )");
 }
 INSTANTIATE_TEST_SUITE_P(BuiltinBuilderTest,
                          Builtin_Builtin_DualParam_SInt_Test,
-                         testing::Values(BuiltinData{"max", "SMax"},
-                                         BuiltinData{"min", "SMin"}));
+                         testing::Values(BuiltinData{"max", "SMax"}, BuiltinData{"min", "SMin"}));
 
-using Builtin_Builtin_DualParam_UInt_Test =
-    BuiltinBuilderTestWithParam<BuiltinData>;
+using Builtin_Builtin_DualParam_UInt_Test = BuiltinBuilderTestWithParam<BuiltinData>;
 TEST_P(Builtin_Builtin_DualParam_UInt_Test, Call_Scalar) {
-  auto param = GetParam();
-  auto* expr = Call(param.name, 1u, 1u);
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Assign(Phony(), expr),
-                    });
+    auto param = GetParam();
+    auto* expr = Call(param.name, 1_u, 1_u);
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Assign(Phony(), expr),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450"
+    EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450"
 OpName %3 "a_func"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
@@ -1168,25 +1153,25 @@
 %3 = OpFunction %2 None %1
 %4 = OpLabel
 %5 = OpExtInst %6 %7 )" + param.op +
-                                R"( %8 %8
+                                  R"( %8 %8
 OpReturn
 OpFunctionEnd
 )");
 }
 
 TEST_P(Builtin_Builtin_DualParam_UInt_Test, Call_Vector) {
-  auto param = GetParam();
-  auto* expr = Call(param.name, vec2<u32>(1u, 1u), vec2<u32>(1u, 1u));
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Assign(Phony(), expr),
-                    });
+    auto param = GetParam();
+    auto* expr = Call(param.name, vec2<u32>(1_u, 1_u), vec2<u32>(1_u, 1_u));
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Assign(Phony(), expr),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450"
+    EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450"
 OpName %3 "a_func"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
@@ -1197,31 +1182,29 @@
 %3 = OpFunction %2 None %1
 %4 = OpLabel
 %5 = OpExtInst %6 %8 )" + param.op +
-                                R"( %10 %10
+                                  R"( %10 %10
 OpReturn
 OpFunctionEnd
 )");
 }
 INSTANTIATE_TEST_SUITE_P(BuiltinBuilderTest,
                          Builtin_Builtin_DualParam_UInt_Test,
-                         testing::Values(BuiltinData{"max", "UMax"},
-                                         BuiltinData{"min", "UMin"}));
+                         testing::Values(BuiltinData{"max", "UMax"}, BuiltinData{"min", "UMin"}));
 
-using Builtin_Builtin_ThreeParam_Sint_Test =
-    BuiltinBuilderTestWithParam<BuiltinData>;
+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, 1, 1);
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Assign(Phony(), expr),
-                    });
+    auto param = GetParam();
+    auto* expr = Call(param.name, 1_i, 1_i, 1_i);
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Assign(Phony(), expr),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450"
+    EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450"
 OpName %3 "a_func"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
@@ -1230,26 +1213,25 @@
 %3 = OpFunction %2 None %1
 %4 = OpLabel
 %5 = OpExtInst %6 %7 )" + param.op +
-                                R"( %8 %8 %8
+                                  R"( %8 %8 %8
 OpReturn
 OpFunctionEnd
 )");
 }
 
 TEST_P(Builtin_Builtin_ThreeParam_Sint_Test, Call_Vector) {
-  auto param = GetParam();
-  auto* expr =
-      Call(param.name, vec2<i32>(1, 1), vec2<i32>(1, 1), vec2<i32>(1, 1));
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Assign(Phony(), expr),
-                    });
+    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* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Assign(Phony(), expr),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450"
+    EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450"
 OpName %3 "a_func"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
@@ -1260,7 +1242,7 @@
 %3 = OpFunction %2 None %1
 %4 = OpLabel
 %5 = OpExtInst %6 %8 )" + param.op +
-                                R"( %10 %10 %10
+                                  R"( %10 %10 %10
 OpReturn
 OpFunctionEnd
 )");
@@ -1269,21 +1251,20 @@
                          Builtin_Builtin_ThreeParam_Sint_Test,
                          testing::Values(BuiltinData{"clamp", "SClamp"}));
 
-using Builtin_Builtin_ThreeParam_Uint_Test =
-    BuiltinBuilderTestWithParam<BuiltinData>;
+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, 1u, 1u, 1u);
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Assign(Phony(), expr),
-                    });
+    auto param = GetParam();
+    auto* expr = Call(param.name, 1_u, 1_u, 1_u);
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Assign(Phony(), expr),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450"
+    EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450"
 OpName %3 "a_func"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
@@ -1292,26 +1273,25 @@
 %3 = OpFunction %2 None %1
 %4 = OpLabel
 %5 = OpExtInst %6 %7 )" + param.op +
-                                R"( %8 %8 %8
+                                  R"( %8 %8 %8
 OpReturn
 OpFunctionEnd
 )");
 }
 
 TEST_P(Builtin_Builtin_ThreeParam_Uint_Test, Call_Vector) {
-  auto param = GetParam();
-  auto* expr =
-      Call(param.name, vec2<u32>(1u, 1u), vec2<u32>(1u, 1u), vec2<u32>(1u, 1u));
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Assign(Phony(), expr),
-                    });
+    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* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Assign(Phony(), expr),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450"
+    EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450"
 OpName %3 "a_func"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
@@ -1322,7 +1302,7 @@
 %3 = OpFunction %2 None %1
 %4 = OpLabel
 %5 = OpExtInst %6 %8 )" + param.op +
-                                R"( %10 %10 %10
+                                  R"( %10 %10 %10
 OpReturn
 OpFunctionEnd
 )");
@@ -1332,15 +1312,14 @@
                          testing::Values(BuiltinData{"clamp", "UClamp"}));
 
 TEST_F(BuiltinBuilderTest, Call_Modf) {
-  auto* expr = Call("modf", vec2<f32>(1.0f, 2.0f));
-  Func("a_func", {}, ty.void_(), {CallStmt(expr)},
-       {Stage(ast::PipelineStage::kFragment)});
+    auto* expr = Call("modf", vec2<f32>(1.0f, 2.0f));
+    Func("a_func", {}, ty.void_(), {CallStmt(expr)}, {Stage(ast::PipelineStage::kFragment)});
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.Build()) << b.error();
-  auto got = DumpBuilder(b);
-  auto* expect = R"(OpCapability Shader
+    ASSERT_TRUE(b.Build()) << b.error();
+    auto got = DumpBuilder(b);
+    auto* expect = R"(OpCapability Shader
 %9 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel Logical GLSL450
 OpEntryPoint Fragment %3 "a_func"
@@ -1365,21 +1344,20 @@
 OpReturn
 OpFunctionEnd
 )";
-  EXPECT_EQ(expect, got);
+    EXPECT_EQ(expect, got);
 
-  Validate(b);
+    Validate(b);
 }
 
 TEST_F(BuiltinBuilderTest, Call_Frexp) {
-  auto* expr = Call("frexp", vec2<f32>(1.0f, 2.0f));
-  Func("a_func", {}, ty.void_(), {CallStmt(expr)},
-       {Stage(ast::PipelineStage::kFragment)});
+    auto* expr = Call("frexp", vec2<f32>(1.0f, 2.0f));
+    Func("a_func", {}, ty.void_(), {CallStmt(expr)}, {Stage(ast::PipelineStage::kFragment)});
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.Build()) << b.error();
-  auto got = DumpBuilder(b);
-  auto* expect = R"(OpCapability Shader
+    ASSERT_TRUE(b.Build()) << b.error();
+    auto got = DumpBuilder(b);
+    auto* expect = R"(OpCapability Shader
 %11 = OpExtInstImport "GLSL.std.450"
 OpMemoryModel Logical GLSL450
 OpEntryPoint Fragment %3 "a_func"
@@ -1406,25 +1384,25 @@
 OpReturn
 OpFunctionEnd
 )";
-  EXPECT_EQ(expect, got);
+    EXPECT_EQ(expect, got);
 
-  Validate(b);
+    Validate(b);
 }
 
 TEST_F(BuiltinBuilderTest, Call_Determinant) {
-  auto* var = Global("var", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
-  auto* expr = Call("determinant", "var");
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Assign(Phony(), expr),
-                    });
+    auto* var = Global("var", ty.mat3x3<f32>(), ast::StorageClass::kPrivate);
+    auto* expr = Call("determinant", "var");
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Assign(Phony(), expr),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(%12 = OpExtInstImport "GLSL.std.450"
+    EXPECT_EQ(DumpBuilder(b), R"(%12 = OpExtInstImport "GLSL.std.450"
 OpName %1 "var"
 OpName %9 "a_func"
 %5 = OpTypeFloat 32
@@ -1445,19 +1423,19 @@
 }
 
 TEST_F(BuiltinBuilderTest, Call_Transpose) {
-  auto* var = Global("var", ty.mat2x3<f32>(), ast::StorageClass::kPrivate);
-  auto* expr = Call("transpose", "var");
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Assign(Phony(), expr),
-                    });
+    auto* var = Global("var", ty.mat2x3<f32>(), ast::StorageClass::kPrivate);
+    auto* expr = Call("transpose", "var");
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Assign(Phony(), expr),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(OpName %1 "var"
+    EXPECT_EQ(DumpBuilder(b), R"(OpName %1 "var"
 OpName %9 "a_func"
 %5 = OpTypeFloat 32
 %4 = OpTypeVector %5 3
@@ -1479,29 +1457,29 @@
 }
 
 TEST_F(BuiltinBuilderTest, Call_ArrayLength) {
-  auto* s = Structure("my_struct", {Member("a", ty.array<f32>(4))});
-  Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+    auto* s = Structure("my_struct", {Member("a", ty.array<f32>(4))});
+    Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(1),
+               create<ast::GroupAttribute>(2),
+           });
+    auto* expr = Call("arrayLength", AddressOf(MemberAccessor("b", "a")));
+
+    Func("a_func", {}, ty.void_(),
+         ast::StatementList{
+             CallStmt(expr),
+         },
          ast::AttributeList{
-             create<ast::BindingAttribute>(1),
-             create<ast::GroupAttribute>(2),
+             Stage(ast::PipelineStage::kFragment),
          });
-  auto* expr = Call("arrayLength", AddressOf(MemberAccessor("b", "a")));
 
-  Func("a_func", {}, ty.void_(),
-       ast::StatementList{
-           CallStmt(expr),
-       },
-       ast::AttributeList{
-           Stage(ast::PipelineStage::kFragment),
-       });
+    spirv::Builder& b = SanitizeAndBuild();
 
-  spirv::Builder& b = SanitizeAndBuild();
+    ASSERT_TRUE(b.Build()) << b.error();
 
-  ASSERT_TRUE(b.Build()) << b.error();
+    ASSERT_EQ(b.functions().size(), 1_u);
 
-  ASSERT_EQ(b.functions().size(), 1u);
-
-  auto* expected_types = R"(%5 = OpTypeFloat 32
+    auto* expected_types = R"(%5 = OpTypeFloat 32
 %4 = OpTypeRuntimeArray %5
 %3 = OpTypeStruct %4
 %2 = OpTypePointer StorageBuffer %3
@@ -1510,45 +1488,45 @@
 %6 = OpTypeFunction %7
 %11 = OpTypeInt 32 0
 )";
-  auto got_types = DumpInstructions(b.types());
-  EXPECT_EQ(expected_types, got_types);
+    auto got_types = DumpInstructions(b.types());
+    EXPECT_EQ(expected_types, got_types);
 
-  auto* expected_instructions = R"(%10 = OpArrayLength %11 %1 0
+    auto* expected_instructions = R"(%10 = OpArrayLength %11 %1 0
 OpReturn
 )";
-  auto got_instructions = DumpInstructions(b.functions()[0].instructions());
-  EXPECT_EQ(expected_instructions, got_instructions);
+    auto got_instructions = DumpInstructions(b.functions()[0].instructions());
+    EXPECT_EQ(expected_instructions, got_instructions);
 
-  Validate(b);
+    Validate(b);
 }
 
 TEST_F(BuiltinBuilderTest, Call_ArrayLength_OtherMembersInStruct) {
-  auto* s = Structure("my_struct", {
-                                       Member("z", ty.f32()),
-                                       Member(4, "a", ty.array<f32>(4)),
-                                   });
-  Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+    auto* s = Structure("my_struct", {
+                                         Member("z", ty.f32()),
+                                         Member(4, "a", ty.array<f32>(4)),
+                                     });
+    Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(1),
+               create<ast::GroupAttribute>(2),
+           });
+    auto* expr = Call("arrayLength", AddressOf(MemberAccessor("b", "a")));
+
+    Func("a_func", {}, ty.void_(),
+         ast::StatementList{
+             CallStmt(expr),
+         },
          ast::AttributeList{
-             create<ast::BindingAttribute>(1),
-             create<ast::GroupAttribute>(2),
+             Stage(ast::PipelineStage::kFragment),
          });
-  auto* expr = Call("arrayLength", AddressOf(MemberAccessor("b", "a")));
 
-  Func("a_func", {}, ty.void_(),
-       ast::StatementList{
-           CallStmt(expr),
-       },
-       ast::AttributeList{
-           Stage(ast::PipelineStage::kFragment),
-       });
+    spirv::Builder& b = SanitizeAndBuild();
 
-  spirv::Builder& b = SanitizeAndBuild();
+    ASSERT_TRUE(b.Build()) << b.error();
 
-  ASSERT_TRUE(b.Build()) << b.error();
+    ASSERT_EQ(b.functions().size(), 1_u);
 
-  ASSERT_EQ(b.functions().size(), 1u);
-
-  auto* expected_types = R"(%4 = OpTypeFloat 32
+    auto* expected_types = R"(%4 = OpTypeFloat 32
 %5 = OpTypeRuntimeArray %4
 %3 = OpTypeStruct %4 %5
 %2 = OpTypePointer StorageBuffer %3
@@ -1557,47 +1535,47 @@
 %6 = OpTypeFunction %7
 %11 = OpTypeInt 32 0
 )";
-  auto got_types = DumpInstructions(b.types());
-  EXPECT_EQ(expected_types, got_types);
+    auto got_types = DumpInstructions(b.types());
+    EXPECT_EQ(expected_types, got_types);
 
-  auto* expected_instructions = R"(%10 = OpArrayLength %11 %1 1
+    auto* expected_instructions = R"(%10 = OpArrayLength %11 %1 1
 OpReturn
 )";
-  auto got_instructions = DumpInstructions(b.functions()[0].instructions());
-  EXPECT_EQ(expected_instructions, got_instructions);
+    auto got_instructions = DumpInstructions(b.functions()[0].instructions());
+    EXPECT_EQ(expected_instructions, got_instructions);
 
-  Validate(b);
+    Validate(b);
 }
 
 TEST_F(BuiltinBuilderTest, Call_ArrayLength_ViaLets) {
-  auto* s = Structure("my_struct", {Member("a", ty.array<f32>(4))});
-  Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+    auto* s = Structure("my_struct", {Member("a", ty.array<f32>(4))});
+    Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(1),
+               create<ast::GroupAttribute>(2),
+           });
+
+    auto* p = Let("p", nullptr, AddressOf("b"));
+    auto* p2 = Let("p2", nullptr, AddressOf(MemberAccessor(Deref(p), "a")));
+    auto* expr = Call("arrayLength", p2);
+
+    Func("a_func", {}, ty.void_(),
+         ast::StatementList{
+             Decl(p),
+             Decl(p2),
+             CallStmt(expr),
+         },
          ast::AttributeList{
-             create<ast::BindingAttribute>(1),
-             create<ast::GroupAttribute>(2),
+             Stage(ast::PipelineStage::kFragment),
          });
 
-  auto* p = Const("p", nullptr, AddressOf("b"));
-  auto* p2 = Const("p2", nullptr, AddressOf(MemberAccessor(Deref(p), "a")));
-  auto* expr = Call("arrayLength", p2);
+    spirv::Builder& b = SanitizeAndBuild();
 
-  Func("a_func", {}, ty.void_(),
-       ast::StatementList{
-           Decl(p),
-           Decl(p2),
-           CallStmt(expr),
-       },
-       ast::AttributeList{
-           Stage(ast::PipelineStage::kFragment),
-       });
+    ASSERT_TRUE(b.Build()) << b.error();
 
-  spirv::Builder& b = SanitizeAndBuild();
+    ASSERT_EQ(b.functions().size(), 1_u);
 
-  ASSERT_TRUE(b.Build()) << b.error();
-
-  ASSERT_EQ(b.functions().size(), 1u);
-
-  auto* expected_types = R"(%5 = OpTypeFloat 32
+    auto* expected_types = R"(%5 = OpTypeFloat 32
 %4 = OpTypeRuntimeArray %5
 %3 = OpTypeStruct %4
 %2 = OpTypePointer StorageBuffer %3
@@ -1606,60 +1584,60 @@
 %6 = OpTypeFunction %7
 %11 = OpTypeInt 32 0
 )";
-  auto got_types = DumpInstructions(b.types());
-  EXPECT_EQ(expected_types, got_types);
+    auto got_types = DumpInstructions(b.types());
+    EXPECT_EQ(expected_types, got_types);
 
-  auto* expected_instructions = R"(%10 = OpArrayLength %11 %1 0
+    auto* expected_instructions = R"(%10 = OpArrayLength %11 %1 0
 OpReturn
 )";
-  auto got_instructions = DumpInstructions(b.functions()[0].instructions());
-  EXPECT_EQ(expected_instructions, got_instructions);
+    auto got_instructions = DumpInstructions(b.functions()[0].instructions());
+    EXPECT_EQ(expected_instructions, got_instructions);
 
-  Validate(b);
+    Validate(b);
 }
 
 TEST_F(BuiltinBuilderTest, Call_ArrayLength_ViaLets_WithPtrNoise) {
-  // struct my_struct {
-  //   a : array<f32>;
-  // };
-  // @binding(1) @group(2) var<storage, read> b : my_struct;
-  //
-  // fn a_func() {
-  //   let p = &*&b;
-  //   let p2 = &*p;
-  //   let p3 = &((*p).a);
-  //   arrayLength(&*p3);
-  // }
-  auto* s = Structure("my_struct", {Member("a", ty.array<f32>(4))});
-  Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+    // struct my_struct {
+    //   a : array<f32>;
+    // };
+    // @binding(1) @group(2) var<storage, read> b : my_struct;
+    //
+    // fn a_func() {
+    //   let p = &*&b;
+    //   let p2 = &*p;
+    //   let p3 = &((*p).a);
+    //   arrayLength(&*p3);
+    // }
+    auto* s = Structure("my_struct", {Member("a", ty.array<f32>(4))});
+    Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(1),
+               create<ast::GroupAttribute>(2),
+           });
+
+    auto* p = Let("p", nullptr, AddressOf(Deref(AddressOf("b"))));
+    auto* p2 = Let("p2", nullptr, AddressOf(Deref(p)));
+    auto* p3 = Let("p3", nullptr, AddressOf(MemberAccessor(Deref(p2), "a")));
+    auto* expr = Call("arrayLength", AddressOf(Deref(p3)));
+
+    Func("a_func", {}, ty.void_(),
+         ast::StatementList{
+             Decl(p),
+             Decl(p2),
+             Decl(p3),
+             CallStmt(expr),
+         },
          ast::AttributeList{
-             create<ast::BindingAttribute>(1),
-             create<ast::GroupAttribute>(2),
+             Stage(ast::PipelineStage::kFragment),
          });
 
-  auto* p = Const("p", nullptr, AddressOf(Deref(AddressOf("b"))));
-  auto* p2 = Const("p2", nullptr, AddressOf(Deref(p)));
-  auto* p3 = Const("p3", nullptr, AddressOf(MemberAccessor(Deref(p2), "a")));
-  auto* expr = Call("arrayLength", AddressOf(Deref(p3)));
+    spirv::Builder& b = SanitizeAndBuild();
 
-  Func("a_func", {}, ty.void_(),
-       ast::StatementList{
-           Decl(p),
-           Decl(p2),
-           Decl(p3),
-           CallStmt(expr),
-       },
-       ast::AttributeList{
-           Stage(ast::PipelineStage::kFragment),
-       });
+    ASSERT_TRUE(b.Build()) << b.error();
 
-  spirv::Builder& b = SanitizeAndBuild();
+    ASSERT_EQ(b.functions().size(), 1_u);
 
-  ASSERT_TRUE(b.Build()) << b.error();
-
-  ASSERT_EQ(b.functions().size(), 1u);
-
-  auto* expected_types = R"(%5 = OpTypeFloat 32
+    auto* expected_types = R"(%5 = OpTypeFloat 32
 %4 = OpTypeRuntimeArray %5
 %3 = OpTypeStruct %4
 %2 = OpTypePointer StorageBuffer %3
@@ -1668,56 +1646,54 @@
 %6 = OpTypeFunction %7
 %11 = OpTypeInt 32 0
 )";
-  auto got_types = DumpInstructions(b.types());
-  EXPECT_EQ(expected_types, got_types);
+    auto got_types = DumpInstructions(b.types());
+    EXPECT_EQ(expected_types, got_types);
 
-  auto* expected_instructions = R"(%10 = OpArrayLength %11 %1 0
+    auto* expected_instructions = R"(%10 = OpArrayLength %11 %1 0
 OpReturn
 )";
-  auto got_instructions = DumpInstructions(b.functions()[0].instructions());
-  EXPECT_EQ(expected_instructions, got_instructions);
+    auto got_instructions = DumpInstructions(b.functions()[0].instructions());
+    EXPECT_EQ(expected_instructions, got_instructions);
 
-  Validate(b);
+    Validate(b);
 }
 
 TEST_F(BuiltinBuilderTest, Call_AtomicLoad) {
-  // struct S {
-  //   u : atomic<u32>;
-  //   i : atomic<i32>;
-  // }
-  //
-  // @binding(1) @group(2) var<storage, read_write> b : S;
-  //
-  // fn a_func() {
-  //   let u : u32 = atomicLoad(&b.u);
-  //   let i : i32 = atomicLoad(&b.i);
-  // }
-  auto* s = Structure("S", {
-                               Member("u", ty.atomic<u32>()),
-                               Member("i", ty.atomic<i32>()),
-                           });
-  Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(1),
-             create<ast::GroupAttribute>(2),
-         });
+    // struct S {
+    //   u : atomic<u32>;
+    //   i : atomic<i32>;
+    // }
+    //
+    // @binding(1) @group(2) var<storage, read_write> b : S;
+    //
+    // fn a_func() {
+    //   let u : u32 = atomicLoad(&b.u);
+    //   let i : i32 = atomicLoad(&b.i);
+    // }
+    auto* s = Structure("S", {
+                                 Member("u", ty.atomic<u32>()),
+                                 Member("i", ty.atomic<i32>()),
+                             });
+    Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(1),
+               create<ast::GroupAttribute>(2),
+           });
 
-  Func("a_func", {}, ty.void_(),
-       ast::StatementList{
-           Decl(Const("u", ty.u32(),
-                      Call("atomicLoad", AddressOf(MemberAccessor("b", "u"))))),
-           Decl(Const("i", ty.i32(),
-                      Call("atomicLoad", AddressOf(MemberAccessor("b", "i"))))),
-       },
-       ast::AttributeList{Stage(ast::PipelineStage::kFragment)});
+    Func("a_func", {}, ty.void_(),
+         ast::StatementList{
+             Decl(Let("u", ty.u32(), Call("atomicLoad", AddressOf(MemberAccessor("b", "u"))))),
+             Decl(Let("i", ty.i32(), Call("atomicLoad", AddressOf(MemberAccessor("b", "i"))))),
+         },
+         ast::AttributeList{Stage(ast::PipelineStage::kFragment)});
 
-  spirv::Builder& b = SanitizeAndBuild();
+    spirv::Builder& b = SanitizeAndBuild();
 
-  ASSERT_TRUE(b.Build()) << b.error();
+    ASSERT_TRUE(b.Build()) << b.error();
 
-  ASSERT_EQ(b.functions().size(), 1u);
+    ASSERT_EQ(b.functions().size(), 1_u);
 
-  auto* expected_types = R"(%4 = OpTypeInt 32 0
+    auto* expected_types = R"(%4 = OpTypeInt 32 0
 %5 = OpTypeInt 32 1
 %3 = OpTypeStruct %4 %5
 %2 = OpTypePointer StorageBuffer %3
@@ -1729,63 +1705,61 @@
 %14 = OpTypePointer StorageBuffer %4
 %18 = OpTypePointer StorageBuffer %5
 )";
-  auto got_types = DumpInstructions(b.types());
-  EXPECT_EQ(expected_types, got_types);
+    auto got_types = DumpInstructions(b.types());
+    EXPECT_EQ(expected_types, got_types);
 
-  auto* expected_instructions = R"(%15 = OpAccessChain %14 %1 %12
+    auto* expected_instructions = R"(%15 = OpAccessChain %14 %1 %12
 %10 = OpAtomicLoad %4 %15 %11 %12
 %19 = OpAccessChain %18 %1 %11
 %16 = OpAtomicLoad %5 %19 %11 %12
 OpReturn
 )";
-  auto got_instructions = DumpInstructions(b.functions()[0].instructions());
-  EXPECT_EQ(expected_instructions, got_instructions);
+    auto got_instructions = DumpInstructions(b.functions()[0].instructions());
+    EXPECT_EQ(expected_instructions, got_instructions);
 
-  Validate(b);
+    Validate(b);
 }
 
 TEST_F(BuiltinBuilderTest, Call_AtomicStore) {
-  // struct S {
-  //   u : atomic<u32>;
-  //   i : atomic<i32>;
-  // }
-  //
-  // @binding(1) @group(2) var<storage, read_write> b : S;
-  //
-  // fn a_func() {
-  //   var u = 1u;
-  //   var i = 2;
-  //   atomicStore(&b.u, u);
-  //   atomicStore(&b.i, i);
-  // }
-  auto* s = Structure("S", {
-                               Member("u", ty.atomic<u32>()),
-                               Member("i", ty.atomic<i32>()),
-                           });
-  Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(1),
-             create<ast::GroupAttribute>(2),
-         });
+    // struct S {
+    //   u : atomic<u32>;
+    //   i : atomic<i32>;
+    // }
+    //
+    // @binding(1) @group(2) var<storage, read_write> b : S;
+    //
+    // fn a_func() {
+    //   var u = 1_u;
+    //   var i = 2;
+    //   atomicStore(&b.u, u);
+    //   atomicStore(&b.i, i);
+    // }
+    auto* s = Structure("S", {
+                                 Member("u", ty.atomic<u32>()),
+                                 Member("i", ty.atomic<i32>()),
+                             });
+    Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(1),
+               create<ast::GroupAttribute>(2),
+           });
 
-  Func("a_func", {}, ty.void_(),
-       ast::StatementList{
-           Decl(Var("u", nullptr, Expr(1u))),
-           Decl(Var("i", nullptr, Expr(2))),
-           CallStmt(
-               Call("atomicStore", AddressOf(MemberAccessor("b", "u")), "u")),
-           CallStmt(
-               Call("atomicStore", AddressOf(MemberAccessor("b", "i")), "i")),
-       },
-       ast::AttributeList{Stage(ast::PipelineStage::kFragment)});
+    Func("a_func", {}, ty.void_(),
+         ast::StatementList{
+             Decl(Var("u", nullptr, Expr(1_u))),
+             Decl(Var("i", nullptr, Expr(2_i))),
+             CallStmt(Call("atomicStore", AddressOf(MemberAccessor("b", "u")), "u")),
+             CallStmt(Call("atomicStore", AddressOf(MemberAccessor("b", "i")), "i")),
+         },
+         ast::AttributeList{Stage(ast::PipelineStage::kFragment)});
 
-  spirv::Builder& b = SanitizeAndBuild();
+    spirv::Builder& b = SanitizeAndBuild();
 
-  ASSERT_TRUE(b.Build()) << b.error();
+    ASSERT_TRUE(b.Build()) << b.error();
 
-  ASSERT_EQ(b.functions().size(), 1u);
+    ASSERT_EQ(b.functions().size(), 1_u);
 
-  auto* expected_types = R"(%4 = OpTypeInt 32 0
+    auto* expected_types = R"(%4 = OpTypeInt 32 0
 %5 = OpTypeInt 32 1
 %3 = OpTypeStruct %4 %5
 %2 = OpTypePointer StorageBuffer %3
@@ -1802,10 +1776,10 @@
 %21 = OpTypePointer StorageBuffer %4
 %26 = OpTypePointer StorageBuffer %5
 )";
-  auto got_types = DumpInstructions(b.types());
-  EXPECT_EQ(expected_types, got_types);
+    auto got_types = DumpInstructions(b.types());
+    EXPECT_EQ(expected_types, got_types);
 
-  auto* expected_instructions = R"(OpStore %11 %10
+    auto* expected_instructions = R"(OpStore %11 %10
 OpStore %15 %14
 %22 = OpAccessChain %21 %1 %19
 %23 = OpLoad %4 %11
@@ -1815,49 +1789,48 @@
 OpAtomicStore %27 %10 %19 %28
 OpReturn
 )";
-  auto got_instructions = DumpInstructions(b.functions()[0].instructions());
-  EXPECT_EQ(expected_instructions, got_instructions);
+    auto got_instructions = DumpInstructions(b.functions()[0].instructions());
+    EXPECT_EQ(expected_instructions, got_instructions);
 
-  Validate(b);
+    Validate(b);
 }
 
 using Builtin_Builtin_AtomicRMW_i32 = BuiltinBuilderTestWithParam<BuiltinData>;
 TEST_P(Builtin_Builtin_AtomicRMW_i32, Test) {
-  // struct S {
-  //   v : atomic<i32>;
-  // }
-  //
-  // @binding(1) @group(2) var<storage, read_write> b : S;
-  //
-  // fn a_func() {
-  //   var v = 10;
-  //   let x : i32 = atomicOP(&b.v, v);
-  // }
-  auto* s = Structure("S", {
-                               Member("v", ty.atomic<i32>()),
-                           });
-  Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(1),
-             create<ast::GroupAttribute>(2),
-         });
+    // struct S {
+    //   v : atomic<i32>;
+    // }
+    //
+    // @binding(1) @group(2) var<storage, read_write> b : S;
+    //
+    // fn a_func() {
+    //   var v = 10;
+    //   let x : i32 = atomicOP(&b.v, v);
+    // }
+    auto* s = Structure("S", {
+                                 Member("v", ty.atomic<i32>()),
+                             });
+    Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(1),
+               create<ast::GroupAttribute>(2),
+           });
 
-  Func("a_func", {}, ty.void_(),
-       ast::StatementList{
-           Decl(Var("v", nullptr, Expr(10))),
-           Decl(Const("x", ty.i32(),
-                      Call(GetParam().name, AddressOf(MemberAccessor("b", "v")),
-                           "v"))),
-       },
-       ast::AttributeList{Stage(ast::PipelineStage::kFragment)});
+    Func("a_func", {}, ty.void_(),
+         ast::StatementList{
+             Decl(Var("v", nullptr, Expr(10_i))),
+             Decl(Let("x", ty.i32(),
+                      Call(GetParam().name, AddressOf(MemberAccessor("b", "v")), "v"))),
+         },
+         ast::AttributeList{Stage(ast::PipelineStage::kFragment)});
 
-  spirv::Builder& b = SanitizeAndBuild();
+    spirv::Builder& b = SanitizeAndBuild();
 
-  ASSERT_TRUE(b.Build()) << b.error();
+    ASSERT_TRUE(b.Build()) << b.error();
 
-  ASSERT_EQ(b.functions().size(), 1u);
+    ASSERT_EQ(b.functions().size(), 1_u);
 
-  std::string expected_types = R"(%4 = OpTypeInt 32 1
+    std::string expected_types = R"(%4 = OpTypeInt 32 1
 %3 = OpTypeStruct %4
 %2 = OpTypePointer StorageBuffer %3
 %1 = OpVariable %2 StorageBuffer
@@ -1871,68 +1844,66 @@
 %16 = OpConstant %14 0
 %18 = OpTypePointer StorageBuffer %4
 )";
-  auto got_types = DumpInstructions(b.types());
-  EXPECT_EQ(expected_types, got_types);
+    auto got_types = DumpInstructions(b.types());
+    EXPECT_EQ(expected_types, got_types);
 
-  std::string expected_instructions = R"(OpStore %10 %9
+    std::string expected_instructions = R"(OpStore %10 %9
 %19 = OpAccessChain %18 %1 %16
 %20 = OpLoad %4 %10
 )";
-  expected_instructions += "%13 = " + GetParam().op + " %4 %19 %15 %16 %20\n";
-  expected_instructions += "OpReturn\n";
+    expected_instructions += "%13 = " + GetParam().op + " %4 %19 %15 %16 %20\n";
+    expected_instructions += "OpReturn\n";
 
-  auto got_instructions = DumpInstructions(b.functions()[0].instructions());
-  EXPECT_EQ(expected_instructions, got_instructions);
+    auto got_instructions = DumpInstructions(b.functions()[0].instructions());
+    EXPECT_EQ(expected_instructions, got_instructions);
 
-  Validate(b);
+    Validate(b);
 }
-INSTANTIATE_TEST_SUITE_P(
-    BuiltinBuilderTest,
-    Builtin_Builtin_AtomicRMW_i32,
-    testing::Values(BuiltinData{"atomicAdd", "OpAtomicIAdd"},
-                    BuiltinData{"atomicMax", "OpAtomicSMax"},
-                    BuiltinData{"atomicMin", "OpAtomicSMin"},
-                    BuiltinData{"atomicAnd", "OpAtomicAnd"},
-                    BuiltinData{"atomicOr", "OpAtomicOr"},
-                    BuiltinData{"atomicXor", "OpAtomicXor"}));
+INSTANTIATE_TEST_SUITE_P(BuiltinBuilderTest,
+                         Builtin_Builtin_AtomicRMW_i32,
+                         testing::Values(BuiltinData{"atomicAdd", "OpAtomicIAdd"},
+                                         BuiltinData{"atomicMax", "OpAtomicSMax"},
+                                         BuiltinData{"atomicMin", "OpAtomicSMin"},
+                                         BuiltinData{"atomicAnd", "OpAtomicAnd"},
+                                         BuiltinData{"atomicOr", "OpAtomicOr"},
+                                         BuiltinData{"atomicXor", "OpAtomicXor"}));
 
 using Builtin_Builtin_AtomicRMW_u32 = BuiltinBuilderTestWithParam<BuiltinData>;
 TEST_P(Builtin_Builtin_AtomicRMW_u32, Test) {
-  // struct S {
-  //   v : atomic<u32>;
-  // }
-  //
-  // @binding(1) @group(2) var<storage, read_write> b : S;
-  //
-  // fn a_func() {
-  //   var v = 10u;
-  //   let x : u32 = atomicOP(&b.v, v);
-  // }
-  auto* s = Structure("S", {
-                               Member("v", ty.atomic<u32>()),
-                           });
-  Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(1),
-             create<ast::GroupAttribute>(2),
-         });
+    // struct S {
+    //   v : atomic<u32>;
+    // }
+    //
+    // @binding(1) @group(2) var<storage, read_write> b : S;
+    //
+    // fn a_func() {
+    //   var v = 10u;
+    //   let x : u32 = atomicOP(&b.v, v);
+    // }
+    auto* s = Structure("S", {
+                                 Member("v", ty.atomic<u32>()),
+                             });
+    Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(1),
+               create<ast::GroupAttribute>(2),
+           });
 
-  Func("a_func", {}, ty.void_(),
-       ast::StatementList{
-           Decl(Var("v", nullptr, Expr(10u))),
-           Decl(Const("x", ty.u32(),
-                      Call(GetParam().name, AddressOf(MemberAccessor("b", "v")),
-                           "v"))),
-       },
-       ast::AttributeList{Stage(ast::PipelineStage::kFragment)});
+    Func("a_func", {}, ty.void_(),
+         ast::StatementList{
+             Decl(Var("v", nullptr, Expr(10_u))),
+             Decl(Let("x", ty.u32(),
+                      Call(GetParam().name, AddressOf(MemberAccessor("b", "v")), "v"))),
+         },
+         ast::AttributeList{Stage(ast::PipelineStage::kFragment)});
 
-  spirv::Builder& b = SanitizeAndBuild();
+    spirv::Builder& b = SanitizeAndBuild();
 
-  ASSERT_TRUE(b.Build()) << b.error();
+    ASSERT_TRUE(b.Build()) << b.error();
 
-  ASSERT_EQ(b.functions().size(), 1u);
+    ASSERT_EQ(b.functions().size(), 1_u);
 
-  std::string expected_types = R"(%4 = OpTypeInt 32 0
+    std::string expected_types = R"(%4 = OpTypeInt 32 0
 %3 = OpTypeStruct %4
 %2 = OpTypePointer StorageBuffer %3
 %1 = OpVariable %2 StorageBuffer
@@ -1945,75 +1916,72 @@
 %15 = OpConstant %4 0
 %17 = OpTypePointer StorageBuffer %4
 )";
-  auto got_types = DumpInstructions(b.types());
-  EXPECT_EQ(expected_types, got_types);
+    auto got_types = DumpInstructions(b.types());
+    EXPECT_EQ(expected_types, got_types);
 
-  std::string expected_instructions = R"(OpStore %10 %9
+    std::string expected_instructions = R"(OpStore %10 %9
 %18 = OpAccessChain %17 %1 %15
 %19 = OpLoad %4 %10
 )";
-  expected_instructions += "%13 = " + GetParam().op + " %4 %18 %14 %15 %19\n";
-  expected_instructions += "OpReturn\n";
+    expected_instructions += "%13 = " + GetParam().op + " %4 %18 %14 %15 %19\n";
+    expected_instructions += "OpReturn\n";
 
-  auto got_instructions = DumpInstructions(b.functions()[0].instructions());
-  EXPECT_EQ(expected_instructions, got_instructions);
+    auto got_instructions = DumpInstructions(b.functions()[0].instructions());
+    EXPECT_EQ(expected_instructions, got_instructions);
 
-  Validate(b);
+    Validate(b);
 }
-INSTANTIATE_TEST_SUITE_P(
-    BuiltinBuilderTest,
-    Builtin_Builtin_AtomicRMW_u32,
-    testing::Values(BuiltinData{"atomicAdd", "OpAtomicIAdd"},
-                    BuiltinData{"atomicMax", "OpAtomicUMax"},
-                    BuiltinData{"atomicMin", "OpAtomicUMin"},
-                    BuiltinData{"atomicAnd", "OpAtomicAnd"},
-                    BuiltinData{"atomicOr", "OpAtomicOr"},
-                    BuiltinData{"atomicXor", "OpAtomicXor"}));
+INSTANTIATE_TEST_SUITE_P(BuiltinBuilderTest,
+                         Builtin_Builtin_AtomicRMW_u32,
+                         testing::Values(BuiltinData{"atomicAdd", "OpAtomicIAdd"},
+                                         BuiltinData{"atomicMax", "OpAtomicUMax"},
+                                         BuiltinData{"atomicMin", "OpAtomicUMin"},
+                                         BuiltinData{"atomicAnd", "OpAtomicAnd"},
+                                         BuiltinData{"atomicOr", "OpAtomicOr"},
+                                         BuiltinData{"atomicXor", "OpAtomicXor"}));
 
 TEST_F(BuiltinBuilderTest, Call_AtomicExchange) {
-  // struct S {
-  //   u : atomic<u32>;
-  //   i : atomic<i32>;
-  // }
-  //
-  // @binding(1) @group(2) var<storage, read_write> b : S;
-  //
-  // fn a_func() {
-  //   var u = 10u;
-  //   var i = 10;
-  //   let r : u32 = atomicExchange(&b.u, u);
-  //   let s : i32 = atomicExchange(&b.i, i);
-  // }
-  auto* s = Structure("S", {
-                               Member("u", ty.atomic<u32>()),
-                               Member("i", ty.atomic<i32>()),
-                           });
-  Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(1),
-             create<ast::GroupAttribute>(2),
-         });
+    // struct S {
+    //   u : atomic<u32>;
+    //   i : atomic<i32>;
+    // }
+    //
+    // @binding(1) @group(2) var<storage, read_write> b : S;
+    //
+    // fn a_func() {
+    //   var u = 10u;
+    //   var i = 10i;
+    //   let r : u32 = atomicExchange(&b.u, u);
+    //   let s : i32 = atomicExchange(&b.i, i);
+    // }
+    auto* s = Structure("S", {
+                                 Member("u", ty.atomic<u32>()),
+                                 Member("i", ty.atomic<i32>()),
+                             });
+    Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(1),
+               create<ast::GroupAttribute>(2),
+           });
 
-  Func("a_func", {}, ty.void_(),
-       ast::StatementList{
-           Decl(Var("u", nullptr, Expr(10u))),
-           Decl(Var("i", nullptr, Expr(10))),
-           Decl(Const("r", ty.u32(),
-                      Call("atomicExchange",
-                           AddressOf(MemberAccessor("b", "u")), "u"))),
-           Decl(Const("s", ty.i32(),
-                      Call("atomicExchange",
-                           AddressOf(MemberAccessor("b", "i")), "i"))),
-       },
-       ast::AttributeList{Stage(ast::PipelineStage::kFragment)});
+    Func("a_func", {}, ty.void_(),
+         ast::StatementList{
+             Decl(Var("u", nullptr, Expr(10_u))),
+             Decl(Var("i", nullptr, Expr(10_i))),
+             Decl(Let("r", ty.u32(),
+                      Call("atomicExchange", AddressOf(MemberAccessor("b", "u")), "u"))),
+             Decl(Let("s", ty.i32(),
+                      Call("atomicExchange", AddressOf(MemberAccessor("b", "i")), "i"))),
+         },
+         ast::AttributeList{Stage(ast::PipelineStage::kFragment)});
 
-  spirv::Builder& b = SanitizeAndBuild();
+    spirv::Builder& b = SanitizeAndBuild();
 
-  ASSERT_TRUE(b.Build()) << b.error();
+    ASSERT_TRUE(b.Build()) << b.error();
 
-  ASSERT_EQ(b.functions().size(), 1u);
+    ASSERT_EQ(b.functions().size(), 1_u);
 
-  auto* expected_types = R"(%4 = OpTypeInt 32 0
+    auto* expected_types = R"(%4 = OpTypeInt 32 0
 %5 = OpTypeInt 32 1
 %3 = OpTypeStruct %4 %5
 %2 = OpTypePointer StorageBuffer %3
@@ -2031,10 +1999,10 @@
 %22 = OpTypePointer StorageBuffer %4
 %27 = OpTypePointer StorageBuffer %5
 )";
-  auto got_types = DumpInstructions(b.types());
-  EXPECT_EQ(expected_types, got_types);
+    auto got_types = DumpInstructions(b.types());
+    EXPECT_EQ(expected_types, got_types);
 
-  auto* expected_instructions = R"(OpStore %11 %10
+    auto* expected_instructions = R"(OpStore %11 %10
 OpStore %15 %14
 %23 = OpAccessChain %22 %1 %20
 %24 = OpLoad %4 %11
@@ -2044,52 +2012,52 @@
 %25 = OpAtomicExchange %5 %28 %19 %20 %29
 OpReturn
 )";
-  auto got_instructions = DumpInstructions(b.functions()[0].instructions());
-  EXPECT_EQ(expected_instructions, got_instructions);
+    auto got_instructions = DumpInstructions(b.functions()[0].instructions());
+    EXPECT_EQ(expected_instructions, got_instructions);
 
-  Validate(b);
+    Validate(b);
 }
 
 TEST_F(BuiltinBuilderTest, Call_AtomicCompareExchangeWeak) {
-  // struct S {
-  //   u : atomic<u32>;
-  //   i : atomic<i32>;
-  // }
-  //
-  // @binding(1) @group(2) var<storage, read_write> b : S;
-  //
-  // fn a_func() {
-  //   let u : vec2<u32> = atomicCompareExchangeWeak(&b.u, 10u);
-  //   let i : vec2<i32> = atomicCompareExchangeWeak(&b.i, 10);
-  // }
-  auto* s = Structure("S", {
-                               Member("u", ty.atomic<u32>()),
-                               Member("i", ty.atomic<i32>()),
-                           });
-  Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(1),
-             create<ast::GroupAttribute>(2),
-         });
+    // struct S {
+    //   u : atomic<u32>;
+    //   i : atomic<i32>;
+    // }
+    //
+    // @binding(1) @group(2) var<storage, read_write> b : S;
+    //
+    // fn a_func() {
+    //   let u : vec2<u32> = atomicCompareExchangeWeak(&b.u, 10u);
+    //   let i : vec2<i32> = atomicCompareExchangeWeak(&b.i, 10);
+    // }
+    auto* s = Structure("S", {
+                                 Member("u", ty.atomic<u32>()),
+                                 Member("i", ty.atomic<i32>()),
+                             });
+    Global("b", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(1),
+               create<ast::GroupAttribute>(2),
+           });
 
-  Func("a_func", {}, ty.void_(),
-       ast::StatementList{
-           Decl(Const("u", ty.vec2<u32>(),
-                      Call("atomicCompareExchangeWeak",
-                           AddressOf(MemberAccessor("b", "u")), 10u, 20u))),
-           Decl(Const("i", ty.vec2<i32>(),
-                      Call("atomicCompareExchangeWeak",
-                           AddressOf(MemberAccessor("b", "i")), 10, 20))),
-       },
-       ast::AttributeList{Stage(ast::PipelineStage::kFragment)});
+    Func("a_func", {}, ty.void_(),
+         ast::StatementList{
+             Decl(Let("u", ty.vec2<u32>(),
+                      Call("atomicCompareExchangeWeak", AddressOf(MemberAccessor("b", "u")), 10_u,
+                           20_u))),
+             Decl(Let("i", ty.vec2<i32>(),
+                      Call("atomicCompareExchangeWeak", AddressOf(MemberAccessor("b", "i")), 10_i,
+                           20_i))),
+         },
+         ast::AttributeList{Stage(ast::PipelineStage::kFragment)});
 
-  spirv::Builder& b = SanitizeAndBuild();
+    spirv::Builder& b = SanitizeAndBuild();
 
-  ASSERT_TRUE(b.Build()) << b.error();
+    ASSERT_TRUE(b.Build()) << b.error();
 
-  ASSERT_EQ(b.functions().size(), 1u);
+    ASSERT_EQ(b.functions().size(), 1_u);
 
-  auto* expected_types = R"(%4 = OpTypeInt 32 0
+    auto* expected_types = R"(%4 = OpTypeInt 32 0
 %5 = OpTypeInt 32 1
 %3 = OpTypeStruct %4 %5
 %2 = OpTypePointer StorageBuffer %3
@@ -2110,10 +2078,10 @@
 %32 = OpConstant %5 0
 %33 = OpConstant %5 1
 )";
-  auto got_types = DumpInstructions(b.types());
-  EXPECT_EQ(expected_types, got_types);
+    auto got_types = DumpInstructions(b.types());
+    EXPECT_EQ(expected_types, got_types);
 
-  auto* expected_instructions = R"(%16 = OpAccessChain %15 %1 %13
+    auto* expected_instructions = R"(%16 = OpAccessChain %15 %1 %13
 %20 = OpAtomicCompareExchange %4 %16 %12 %13 %13 %17 %18
 %21 = OpIEqual %19 %20 %17
 %22 = OpSelect %4 %21 %12 %13
@@ -2125,28 +2093,27 @@
 %23 = OpCompositeConstruct %24 %30 %34
 OpReturn
 )";
-  auto got_instructions = DumpInstructions(b.functions()[0].instructions());
-  EXPECT_EQ(expected_instructions, got_instructions);
+    auto got_instructions = DumpInstructions(b.functions()[0].instructions());
+    EXPECT_EQ(expected_instructions, got_instructions);
 
-  Validate(b);
+    Validate(b);
 }
 
-using Builtin_Builtin_DataPacking_Test =
-    BuiltinBuilderTestWithParam<BuiltinData>;
+using Builtin_Builtin_DataPacking_Test = BuiltinBuilderTestWithParam<BuiltinData>;
 TEST_P(Builtin_Builtin_DataPacking_Test, Binary) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  bool pack4 = param.name == "pack4x8snorm" || param.name == "pack4x8unorm";
-  auto* call = pack4 ? Call(param.name, vec4<float>(1.0f, 1.0f, 1.0f, 1.0f))
-                     : Call(param.name, vec2<float>(1.0f, 1.0f));
-  auto* func = Func("a_func", {}, ty.void_(), {CallStmt(call)});
+    bool pack4 = param.name == "pack4x8snorm" || param.name == "pack4x8unorm";
+    auto* call = pack4 ? Call(param.name, vec4<float>(1.0f, 1.0f, 1.0f, 1.0f))
+                       : Call(param.name, vec2<float>(1.0f, 1.0f));
+    auto* func = Func("a_func", {}, ty.void_(), {CallStmt(call)});
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  if (pack4) {
-    EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450"
+    if (pack4) {
+        EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450"
 OpName %3 "a_func"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
@@ -2158,12 +2125,12 @@
 %3 = OpFunction %2 None %1
 %4 = OpLabel
 %5 = OpExtInst %6 %7 )" + param.op +
-                                  R"( %11
+                                      R"( %11
 OpReturn
 OpFunctionEnd
 )");
-  } else {
-    EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450"
+    } else {
+        EXPECT_EQ(DumpBuilder(b), R"(%7 = OpExtInstImport "GLSL.std.450"
 OpName %3 "a_func"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
@@ -2175,36 +2142,34 @@
 %3 = OpFunction %2 None %1
 %4 = OpLabel
 %5 = OpExtInst %6 %7 )" + param.op +
-                                  R"( %11
+                                      R"( %11
 OpReturn
 OpFunctionEnd
 )");
-  }
+    }
 }
 
-INSTANTIATE_TEST_SUITE_P(
-    BuiltinBuilderTest,
-    Builtin_Builtin_DataPacking_Test,
-    testing::Values(BuiltinData{"pack4x8snorm", "PackSnorm4x8"},
-                    BuiltinData{"pack4x8unorm", "PackUnorm4x8"},
-                    BuiltinData{"pack2x16snorm", "PackSnorm2x16"},
-                    BuiltinData{"pack2x16unorm", "PackUnorm2x16"},
-                    BuiltinData{"pack2x16float", "PackHalf2x16"}));
+INSTANTIATE_TEST_SUITE_P(BuiltinBuilderTest,
+                         Builtin_Builtin_DataPacking_Test,
+                         testing::Values(BuiltinData{"pack4x8snorm", "PackSnorm4x8"},
+                                         BuiltinData{"pack4x8unorm", "PackUnorm4x8"},
+                                         BuiltinData{"pack2x16snorm", "PackSnorm2x16"},
+                                         BuiltinData{"pack2x16unorm", "PackUnorm2x16"},
+                                         BuiltinData{"pack2x16float", "PackHalf2x16"}));
 
-using Builtin_Builtin_DataUnpacking_Test =
-    BuiltinBuilderTestWithParam<BuiltinData>;
+using Builtin_Builtin_DataUnpacking_Test = BuiltinBuilderTestWithParam<BuiltinData>;
 TEST_P(Builtin_Builtin_DataUnpacking_Test, Binary) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  bool pack4 = param.name == "unpack4x8snorm" || param.name == "unpack4x8unorm";
-  auto* func = Func("a_func", {}, ty.void_(), {CallStmt(Call(param.name, 1u))});
+    bool pack4 = param.name == "unpack4x8snorm" || param.name == "unpack4x8unorm";
+    auto* func = Func("a_func", {}, ty.void_(), {CallStmt(Call(param.name, 1_u))});
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  if (pack4) {
-    EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450"
+    if (pack4) {
+        EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450"
 OpName %3 "a_func"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
@@ -2215,12 +2180,12 @@
 %3 = OpFunction %2 None %1
 %4 = OpLabel
 %5 = OpExtInst %6 %8 )" + param.op +
-                                  R"( %10
+                                      R"( %10
 OpReturn
 OpFunctionEnd
 )");
-  } else {
-    EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450"
+    } else {
+        EXPECT_EQ(DumpBuilder(b), R"(%8 = OpExtInstImport "GLSL.std.450"
 OpName %3 "a_func"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
@@ -2231,102 +2196,101 @@
 %3 = OpFunction %2 None %1
 %4 = OpLabel
 %5 = OpExtInst %6 %8 )" + param.op +
-                                  R"( %10
+                                      R"( %10
 OpReturn
 OpFunctionEnd
 )");
-  }
+    }
 }
 
-INSTANTIATE_TEST_SUITE_P(
-    BuiltinBuilderTest,
-    Builtin_Builtin_DataUnpacking_Test,
-    testing::Values(BuiltinData{"unpack4x8snorm", "UnpackSnorm4x8"},
-                    BuiltinData{"unpack4x8unorm", "UnpackUnorm4x8"},
-                    BuiltinData{"unpack2x16snorm", "UnpackSnorm2x16"},
-                    BuiltinData{"unpack2x16unorm", "UnpackUnorm2x16"},
-                    BuiltinData{"unpack2x16float", "UnpackHalf2x16"}));
+INSTANTIATE_TEST_SUITE_P(BuiltinBuilderTest,
+                         Builtin_Builtin_DataUnpacking_Test,
+                         testing::Values(BuiltinData{"unpack4x8snorm", "UnpackSnorm4x8"},
+                                         BuiltinData{"unpack4x8unorm", "UnpackUnorm4x8"},
+                                         BuiltinData{"unpack2x16snorm", "UnpackSnorm2x16"},
+                                         BuiltinData{"unpack2x16unorm", "UnpackUnorm2x16"},
+                                         BuiltinData{"unpack2x16float", "UnpackHalf2x16"}));
 
 TEST_F(BuiltinBuilderTest, Call_WorkgroupBarrier) {
-  Func("f", {}, ty.void_(),
-       ast::StatementList{
-           CallStmt(Call("workgroupBarrier")),
-       },
-       ast::AttributeList{
-           Stage(ast::PipelineStage::kCompute),
-           WorkgroupSize(1),
-       });
+    Func("f", {}, ty.void_(),
+         ast::StatementList{
+             CallStmt(Call("workgroupBarrier")),
+         },
+         ast::AttributeList{
+             Stage(ast::PipelineStage::kCompute),
+             WorkgroupSize(1_i),
+         });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.Build()) << b.error();
+    ASSERT_TRUE(b.Build()) << b.error();
 
-  ASSERT_EQ(b.functions().size(), 1u);
+    ASSERT_EQ(b.functions().size(), 1_u);
 
-  auto* expected_types = R"(%2 = OpTypeVoid
+    auto* expected_types = R"(%2 = OpTypeVoid
 %1 = OpTypeFunction %2
 %6 = OpTypeInt 32 0
 %7 = OpConstant %6 2
 %8 = OpConstant %6 264
 )";
-  auto got_types = DumpInstructions(b.types());
-  EXPECT_EQ(expected_types, got_types);
+    auto got_types = DumpInstructions(b.types());
+    EXPECT_EQ(expected_types, got_types);
 
-  auto* expected_instructions = R"(OpControlBarrier %7 %7 %8
+    auto* expected_instructions = R"(OpControlBarrier %7 %7 %8
 OpReturn
 )";
-  auto got_instructions = DumpInstructions(b.functions()[0].instructions());
-  EXPECT_EQ(expected_instructions, got_instructions);
+    auto got_instructions = DumpInstructions(b.functions()[0].instructions());
+    EXPECT_EQ(expected_instructions, got_instructions);
 
-  Validate(b);
+    Validate(b);
 }
 
 TEST_F(BuiltinBuilderTest, Call_StorageBarrier) {
-  Func("f", {}, ty.void_(),
-       ast::StatementList{
-           CallStmt(Call("storageBarrier")),
-       },
-       ast::AttributeList{
-           Stage(ast::PipelineStage::kCompute),
-           WorkgroupSize(1),
-       });
+    Func("f", {}, ty.void_(),
+         ast::StatementList{
+             CallStmt(Call("storageBarrier")),
+         },
+         ast::AttributeList{
+             Stage(ast::PipelineStage::kCompute),
+             WorkgroupSize(1_i),
+         });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.Build()) << b.error();
+    ASSERT_TRUE(b.Build()) << b.error();
 
-  ASSERT_EQ(b.functions().size(), 1u);
+    ASSERT_EQ(b.functions().size(), 1_u);
 
-  auto* expected_types = R"(%2 = OpTypeVoid
+    auto* expected_types = R"(%2 = OpTypeVoid
 %1 = OpTypeFunction %2
 %6 = OpTypeInt 32 0
 %7 = OpConstant %6 2
 %8 = OpConstant %6 72
 )";
-  auto got_types = DumpInstructions(b.types());
-  EXPECT_EQ(expected_types, got_types);
+    auto got_types = DumpInstructions(b.types());
+    EXPECT_EQ(expected_types, got_types);
 
-  auto* expected_instructions = R"(OpControlBarrier %7 %7 %8
+    auto* expected_instructions = R"(OpControlBarrier %7 %7 %8
 OpReturn
 )";
-  auto got_instructions = DumpInstructions(b.functions()[0].instructions());
-  EXPECT_EQ(expected_instructions, got_instructions);
+    auto got_instructions = DumpInstructions(b.functions()[0].instructions());
+    EXPECT_EQ(expected_instructions, got_instructions);
 
-  Validate(b);
+    Validate(b);
 }
 
 TEST_F(BuiltinBuilderTest, Call_ExtractBits_i32) {
-  auto* v = Var("v", ty.i32());
-  auto* offset = Var("offset", ty.u32());
-  auto* count = Var("count", ty.u32());
-  auto* call = Call("extractBits", v, offset, count);
-  auto* func = WrapInFunction(v, offset, count, call);
+    auto* v = Var("v", ty.i32());
+    auto* offset = Var("offset", ty.u32());
+    auto* count = Var("count", ty.u32());
+    auto* call = Call("extractBits", v, offset, count);
+    auto* func = WrapInFunction(v, offset, count, call);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(OpEntryPoint GLCompute %3 "test_function"
+    EXPECT_EQ(DumpBuilder(b), R"(OpEntryPoint GLCompute %3 "test_function"
 OpExecutionMode %3 LocalSize 1 1 1
 OpName %3 "test_function"
 OpName %5 "v"
@@ -2355,17 +2319,17 @@
 }
 
 TEST_F(BuiltinBuilderTest, Call_ExtractBits_u32) {
-  auto* v = Var("v", ty.u32());
-  auto* offset = Var("offset", ty.u32());
-  auto* count = Var("count", ty.u32());
-  auto* call = Call("extractBits", v, offset, count);
-  auto* func = WrapInFunction(v, offset, count, call);
+    auto* v = Var("v", ty.u32());
+    auto* offset = Var("offset", ty.u32());
+    auto* count = Var("count", ty.u32());
+    auto* call = Call("extractBits", v, offset, count);
+    auto* func = WrapInFunction(v, offset, count, call);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(OpEntryPoint GLCompute %3 "test_function"
+    EXPECT_EQ(DumpBuilder(b), R"(OpEntryPoint GLCompute %3 "test_function"
 OpExecutionMode %3 LocalSize 1 1 1
 OpName %3 "test_function"
 OpName %5 "v"
@@ -2391,17 +2355,17 @@
 }
 
 TEST_F(BuiltinBuilderTest, Call_ExtractBits_vec3_i32) {
-  auto* v = Var("v", ty.vec3<i32>());
-  auto* offset = Var("offset", ty.u32());
-  auto* count = Var("count", ty.u32());
-  auto* call = Call("extractBits", v, offset, count);
-  auto* func = WrapInFunction(v, offset, count, call);
+    auto* v = Var("v", ty.vec3<i32>());
+    auto* offset = Var("offset", ty.u32());
+    auto* count = Var("count", ty.u32());
+    auto* call = Call("extractBits", v, offset, count);
+    auto* func = WrapInFunction(v, offset, count, call);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(OpEntryPoint GLCompute %3 "test_function"
+    EXPECT_EQ(DumpBuilder(b), R"(OpEntryPoint GLCompute %3 "test_function"
 OpExecutionMode %3 LocalSize 1 1 1
 OpName %3 "test_function"
 OpName %5 "v"
@@ -2431,17 +2395,17 @@
 }
 
 TEST_F(BuiltinBuilderTest, Call_ExtractBits_vec3_u32) {
-  auto* v = Var("v", ty.vec3<u32>());
-  auto* offset = Var("offset", ty.u32());
-  auto* count = Var("count", ty.u32());
-  auto* call = Call("extractBits", v, offset, count);
-  auto* func = WrapInFunction(v, offset, count, call);
+    auto* v = Var("v", ty.vec3<u32>());
+    auto* offset = Var("offset", ty.u32());
+    auto* count = Var("count", ty.u32());
+    auto* call = Call("extractBits", v, offset, count);
+    auto* func = WrapInFunction(v, offset, count, call);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(OpEntryPoint GLCompute %3 "test_function"
+    EXPECT_EQ(DumpBuilder(b), R"(OpEntryPoint GLCompute %3 "test_function"
 OpExecutionMode %3 LocalSize 1 1 1
 OpName %3 "test_function"
 OpName %5 "v"
@@ -2470,18 +2434,18 @@
 }
 
 TEST_F(BuiltinBuilderTest, Call_InsertBits_i32) {
-  auto* v = Var("v", ty.i32());
-  auto* n = Var("n", ty.i32());
-  auto* offset = Var("offset", ty.u32());
-  auto* count = Var("count", ty.u32());
-  auto* call = Call("insertBits", v, n, offset, count);
-  auto* func = WrapInFunction(v, n, offset, count, call);
+    auto* v = Var("v", ty.i32());
+    auto* n = Var("n", ty.i32());
+    auto* offset = Var("offset", ty.u32());
+    auto* count = Var("count", ty.u32());
+    auto* call = Call("insertBits", v, n, offset, count);
+    auto* func = WrapInFunction(v, n, offset, count, call);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(OpEntryPoint GLCompute %3 "test_function"
+    EXPECT_EQ(DumpBuilder(b), R"(OpEntryPoint GLCompute %3 "test_function"
 OpExecutionMode %3 LocalSize 1 1 1
 OpName %3 "test_function"
 OpName %5 "v"
@@ -2513,18 +2477,18 @@
 }
 
 TEST_F(BuiltinBuilderTest, Call_InsertBits_u32) {
-  auto* v = Var("v", ty.u32());
-  auto* n = Var("n", ty.u32());
-  auto* offset = Var("offset", ty.u32());
-  auto* count = Var("count", ty.u32());
-  auto* call = Call("insertBits", v, n, offset, count);
-  auto* func = WrapInFunction(v, n, offset, count, call);
+    auto* v = Var("v", ty.u32());
+    auto* n = Var("n", ty.u32());
+    auto* offset = Var("offset", ty.u32());
+    auto* count = Var("count", ty.u32());
+    auto* call = Call("insertBits", v, n, offset, count);
+    auto* func = WrapInFunction(v, n, offset, count, call);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(OpEntryPoint GLCompute %3 "test_function"
+    EXPECT_EQ(DumpBuilder(b), R"(OpEntryPoint GLCompute %3 "test_function"
 OpExecutionMode %3 LocalSize 1 1 1
 OpName %3 "test_function"
 OpName %5 "v"
@@ -2553,18 +2517,18 @@
 }
 
 TEST_F(BuiltinBuilderTest, Call_InsertBits_vec3_i32) {
-  auto* v = Var("v", ty.vec3<i32>());
-  auto* n = Var("n", ty.vec3<i32>());
-  auto* offset = Var("offset", ty.u32());
-  auto* count = Var("count", ty.u32());
-  auto* call = Call("insertBits", v, n, offset, count);
-  auto* func = WrapInFunction(v, n, offset, count, call);
+    auto* v = Var("v", ty.vec3<i32>());
+    auto* n = Var("n", ty.vec3<i32>());
+    auto* offset = Var("offset", ty.u32());
+    auto* count = Var("count", ty.u32());
+    auto* call = Call("insertBits", v, n, offset, count);
+    auto* func = WrapInFunction(v, n, offset, count, call);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(OpEntryPoint GLCompute %3 "test_function"
+    EXPECT_EQ(DumpBuilder(b), R"(OpEntryPoint GLCompute %3 "test_function"
 OpExecutionMode %3 LocalSize 1 1 1
 OpName %3 "test_function"
 OpName %5 "v"
@@ -2597,18 +2561,18 @@
 }
 
 TEST_F(BuiltinBuilderTest, Call_InsertBits_vec3_u32) {
-  auto* v = Var("v", ty.vec3<u32>());
-  auto* n = Var("n", ty.vec3<u32>());
-  auto* offset = Var("offset", ty.u32());
-  auto* count = Var("count", ty.u32());
-  auto* call = Call("insertBits", v, n, offset, count);
-  auto* func = WrapInFunction(v, n, offset, count, call);
+    auto* v = Var("v", ty.vec3<u32>());
+    auto* n = Var("n", ty.vec3<u32>());
+    auto* offset = Var("offset", ty.u32());
+    auto* count = Var("count", ty.u32());
+    auto* call = Call("insertBits", v, n, offset, count);
+    auto* func = WrapInFunction(v, n, offset, count, call);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(OpEntryPoint GLCompute %3 "test_function"
+    EXPECT_EQ(DumpBuilder(b), R"(OpEntryPoint GLCompute %3 "test_function"
 OpExecutionMode %3 LocalSize 1 1 1
 OpName %3 "test_function"
 OpName %5 "v"
diff --git a/src/tint/writer/spirv/builder_builtin_texture_test.cc b/src/tint/writer/spirv/builder_builtin_texture_test.cc
index 9a2269d..e76e478 100644
--- a/src/tint/writer/spirv/builder_builtin_texture_test.cc
+++ b/src/tint/writer/spirv/builder_builtin_texture_test.cc
@@ -23,18 +23,18 @@
 namespace {
 
 struct expected_texture_overload_spirv {
-  std::string types;
-  std::string instructions;
-  std::string capabilities;
+    std::string types;
+    std::string instructions;
+    std::string capabilities;
 };
 
 expected_texture_overload_spirv expected_texture_overload(
     ast::builtin::test::ValidTextureOverload overload) {
-  using ValidTextureOverload = ast::builtin::test::ValidTextureOverload;
-  switch (overload) {
-    case ValidTextureOverload::kDimensions1d:
-      return {
-          R"(
+    using ValidTextureOverload = ast::builtin::test::ValidTextureOverload;
+    switch (overload) {
+        case ValidTextureOverload::kDimensions1d:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 1D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -45,17 +45,17 @@
 %9 = OpTypeInt 32 1
 %11 = OpConstant %9 0
 )",
-          R"(
+                R"(
 %10 = OpLoad %3 %1
 %8 = OpImageQuerySizeLod %9 %10 %11
 )",
-          R"(
+                R"(
 OpCapability Sampled1D
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kDimensions2d:
-      return {
-          R"(
+        case ValidTextureOverload::kDimensions2d:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -67,16 +67,16 @@
 %9 = OpTypeVector %10 2
 %12 = OpConstant %10 0
 )",
-          R"(
+                R"(
 %11 = OpLoad %3 %1
 %8 = OpImageQuerySizeLod %9 %11 %12
 )",
-          R"(
+                R"(
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kDimensions2dLevel:
-      return {
-          R"(
+        case ValidTextureOverload::kDimensions2dLevel:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -88,16 +88,16 @@
 %9 = OpTypeVector %10 2
 %12 = OpConstant %10 1
 )",
-          R"(
+                R"(
 %11 = OpLoad %3 %1
 %8 = OpImageQuerySizeLod %9 %11 %12
 )",
-          R"(
+                R"(
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kDimensions2dArray:
-      return {
-          R"(
+        case ValidTextureOverload::kDimensions2dArray:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -110,17 +110,17 @@
 %12 = OpTypeVector %10 3
 %14 = OpConstant %10 0
 )",
-          R"(
+                R"(
 %13 = OpLoad %3 %1
 %11 = OpImageQuerySizeLod %12 %13 %14
 %8 = OpVectorShuffle %9 %11 %11 0 1
 )",
-          R"(
+                R"(
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kDimensions2dArrayLevel:
-      return {
-          R"(
+        case ValidTextureOverload::kDimensions2dArrayLevel:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -133,17 +133,17 @@
 %12 = OpTypeVector %10 3
 %14 = OpConstant %10 1
 )",
-          R"(
+                R"(
 %13 = OpLoad %3 %1
 %11 = OpImageQuerySizeLod %12 %13 %14
 %8 = OpVectorShuffle %9 %11 %11 0 1
 )",
-          R"(
+                R"(
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kDimensions3d:
-      return {
-          R"(
+        case ValidTextureOverload::kDimensions3d:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 3D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -155,16 +155,16 @@
 %9 = OpTypeVector %10 3
 %12 = OpConstant %10 0
 )",
-          R"(
+                R"(
 %11 = OpLoad %3 %1
 %8 = OpImageQuerySizeLod %9 %11 %12
 )",
-          R"(
+                R"(
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kDimensions3dLevel:
-      return {
-          R"(
+        case ValidTextureOverload::kDimensions3dLevel:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 3D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -176,16 +176,16 @@
 %9 = OpTypeVector %10 3
 %12 = OpConstant %10 1
 )",
-          R"(
+                R"(
 %11 = OpLoad %3 %1
 %8 = OpImageQuerySizeLod %9 %11 %12
 )",
-          R"(
+                R"(
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kDimensionsCube:
-      return {
-          R"(
+        case ValidTextureOverload::kDimensionsCube:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 Cube 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -197,16 +197,16 @@
 %9 = OpTypeVector %10 2
 %12 = OpConstant %10 0
 )",
-          R"(
+                R"(
 %11 = OpLoad %3 %1
 %8 = OpImageQuerySizeLod %9 %11 %12
 )",
-          R"(
+                R"(
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kDimensionsCubeLevel:
-      return {
-          R"(
+        case ValidTextureOverload::kDimensionsCubeLevel:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 Cube 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -218,16 +218,16 @@
 %9 = OpTypeVector %10 2
 %12 = OpConstant %10 1
 )",
-          R"(
+                R"(
 %11 = OpLoad %3 %1
 %8 = OpImageQuerySizeLod %9 %11 %12
 )",
-          R"(
+                R"(
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kDimensionsCubeArray:
-      return {
-          R"(
+        case ValidTextureOverload::kDimensionsCubeArray:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 Cube 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -240,18 +240,18 @@
 %12 = OpTypeVector %10 3
 %14 = OpConstant %10 0
 )",
-          R"(
+                R"(
 %13 = OpLoad %3 %1
 %11 = OpImageQuerySizeLod %12 %13 %14
 %8 = OpVectorShuffle %9 %11 %11 0 1
 )",
-          R"(
+                R"(
 OpCapability SampledCubeArray
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kDimensionsCubeArrayLevel:
-      return {
-          R"(
+        case ValidTextureOverload::kDimensionsCubeArrayLevel:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 Cube 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -264,18 +264,18 @@
 %12 = OpTypeVector %10 3
 %14 = OpConstant %10 1
 )",
-          R"(
+                R"(
 %13 = OpLoad %3 %1
 %11 = OpImageQuerySizeLod %12 %13 %14
 %8 = OpVectorShuffle %9 %11 %11 0 1
 )",
-          R"(
+                R"(
 OpCapability SampledCubeArray
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kDimensionsMultisampled2d:
-      return {
-          R"(
+        case ValidTextureOverload::kDimensionsMultisampled2d:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 1 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -286,16 +286,16 @@
 %10 = OpTypeInt 32 1
 %9 = OpTypeVector %10 2
 )",
-          R"(
+                R"(
 %11 = OpLoad %3 %1
 %8 = OpImageQuerySize %9 %11
 )",
-          R"(
+                R"(
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kDimensionsDepth2d:
-      return {
-          R"(
+        case ValidTextureOverload::kDimensionsDepth2d:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -307,16 +307,16 @@
 %9 = OpTypeVector %10 2
 %12 = OpConstant %10 0
 )",
-          R"(
+                R"(
 %11 = OpLoad %3 %1
 %8 = OpImageQuerySizeLod %9 %11 %12
 )",
-          R"(
+                R"(
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kDimensionsDepth2dLevel:
-      return {
-          R"(
+        case ValidTextureOverload::kDimensionsDepth2dLevel:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -328,16 +328,16 @@
 %9 = OpTypeVector %10 2
 %12 = OpConstant %10 1
 )",
-          R"(
+                R"(
 %11 = OpLoad %3 %1
 %8 = OpImageQuerySizeLod %9 %11 %12
 )",
-          R"(
+                R"(
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kDimensionsDepth2dArray:
-      return {
-          R"(
+        case ValidTextureOverload::kDimensionsDepth2dArray:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -350,17 +350,17 @@
 %12 = OpTypeVector %10 3
 %14 = OpConstant %10 0
 )",
-          R"(
+                R"(
 %13 = OpLoad %3 %1
 %11 = OpImageQuerySizeLod %12 %13 %14
 %8 = OpVectorShuffle %9 %11 %11 0 1
 )",
-          R"(
+                R"(
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kDimensionsDepth2dArrayLevel:
-      return {
-          R"(
+        case ValidTextureOverload::kDimensionsDepth2dArrayLevel:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -373,17 +373,17 @@
 %12 = OpTypeVector %10 3
 %14 = OpConstant %10 1
 )",
-          R"(
+                R"(
 %13 = OpLoad %3 %1
 %11 = OpImageQuerySizeLod %12 %13 %14
 %8 = OpVectorShuffle %9 %11 %11 0 1
 )",
-          R"(
+                R"(
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kDimensionsDepthCube:
-      return {
-          R"(
+        case ValidTextureOverload::kDimensionsDepthCube:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 Cube 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -395,16 +395,16 @@
 %9 = OpTypeVector %10 2
 %12 = OpConstant %10 0
 )",
-          R"(
+                R"(
 %11 = OpLoad %3 %1
 %8 = OpImageQuerySizeLod %9 %11 %12
 )",
-          R"(
+                R"(
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kDimensionsDepthCubeLevel:
-      return {
-          R"(
+        case ValidTextureOverload::kDimensionsDepthCubeLevel:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 Cube 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -416,16 +416,16 @@
 %9 = OpTypeVector %10 2
 %12 = OpConstant %10 1
 )",
-          R"(
+                R"(
 %11 = OpLoad %3 %1
 %8 = OpImageQuerySizeLod %9 %11 %12
 )",
-          R"(
+                R"(
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kDimensionsDepthCubeArray:
-      return {
-          R"(
+        case ValidTextureOverload::kDimensionsDepthCubeArray:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 Cube 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -438,18 +438,18 @@
 %12 = OpTypeVector %10 3
 %14 = OpConstant %10 0
 )",
-          R"(
+                R"(
 %13 = OpLoad %3 %1
 %11 = OpImageQuerySizeLod %12 %13 %14
 %8 = OpVectorShuffle %9 %11 %11 0 1
 )",
-          R"(
+                R"(
 OpCapability SampledCubeArray
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kDimensionsDepthCubeArrayLevel:
-      return {
-          R"(
+        case ValidTextureOverload::kDimensionsDepthCubeArrayLevel:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 Cube 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -462,18 +462,18 @@
 %12 = OpTypeVector %10 3
 %14 = OpConstant %10 1
 )",
-          R"(
+                R"(
 %13 = OpLoad %3 %1
 %11 = OpImageQuerySizeLod %12 %13 %14
 %8 = OpVectorShuffle %9 %11 %11 0 1
 )",
-          R"(
+                R"(
 OpCapability SampledCubeArray
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kDimensionsDepthMultisampled2d:
-      return {
-          R"(
+        case ValidTextureOverload::kDimensionsDepthMultisampled2d:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 1 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -484,16 +484,16 @@
 %10 = OpTypeInt 32 1
 %9 = OpTypeVector %10 2
 )",
-          R"(
+                R"(
 %11 = OpLoad %3 %1
 %8 = OpImageQuerySize %9 %11
 )",
-          R"(
+                R"(
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kDimensionsStorageWO1d:
-      return {
-          R"(
+        case ValidTextureOverload::kDimensionsStorageWO1d:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 1D 0 0 0 2 Rgba32f
 %2 = OpTypePointer UniformConstant %3
@@ -503,17 +503,17 @@
 %5 = OpVariable %6 UniformConstant
 %9 = OpTypeInt 32 1
 )",
-          R"(
+                R"(
 %10 = OpLoad %3 %1
 %8 = OpImageQuerySize %9 %10
 )",
-          R"(
+                R"(
 OpCapability Image1D
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kDimensionsStorageWO2d:
-      return {
-          R"(
+        case ValidTextureOverload::kDimensionsStorageWO2d:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 2 Rgba32f
 %2 = OpTypePointer UniformConstant %3
@@ -524,16 +524,16 @@
 %10 = OpTypeInt 32 1
 %9 = OpTypeVector %10 2
 )",
-          R"(
+                R"(
 %11 = OpLoad %3 %1
 %8 = OpImageQuerySize %9 %11
 )",
-          R"(
+                R"(
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kDimensionsStorageWO2dArray:
-      return {
-          R"(
+        case ValidTextureOverload::kDimensionsStorageWO2dArray:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 0 2 Rgba32f
 %2 = OpTypePointer UniformConstant %3
@@ -545,17 +545,17 @@
 %9 = OpTypeVector %10 2
 %12 = OpTypeVector %10 3
 )",
-          R"(
+                R"(
 %13 = OpLoad %3 %1
 %11 = OpImageQuerySize %12 %13
 %8 = OpVectorShuffle %9 %11 %11 0 1
 )",
-          R"(
+                R"(
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kDimensionsStorageWO3d:
-      return {
-          R"(
+        case ValidTextureOverload::kDimensionsStorageWO3d:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 3D 0 0 0 2 Rgba32f
 %2 = OpTypePointer UniformConstant %3
@@ -566,15 +566,15 @@
 %10 = OpTypeInt 32 1
 %9 = OpTypeVector %10 3
 )",
-          R"(
+                R"(
 %11 = OpLoad %3 %1
 %8 = OpImageQuerySize %9 %11
 )",
-          R"(
+                R"(
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kGather2dF32:
-      return {R"(
+        case ValidTextureOverload::kGather2dF32:
+            return {R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -591,16 +591,16 @@
 %18 = OpTypeInt 32 1
 %19 = OpConstant %18 0
 )",
-              R"(
+                    R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageGather %9 %13 %17 %19
 )",
-              R"(
+                    R"(
 )"};
-    case ValidTextureOverload::kGather2dOffsetF32:
-      return {R"(
+        case ValidTextureOverload::kGather2dOffsetF32:
+            return {R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -621,16 +621,16 @@
 %22 = OpConstant %18 4
 %23 = OpConstantComposite %20 %21 %22
 )",
-              R"(
+                    R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageGather %9 %13 %17 %19 ConstOffset %23
 )",
-              R"(
+                    R"(
 )"};
-    case ValidTextureOverload::kGather2dArrayF32:
-      return {R"(
+        case ValidTextureOverload::kGather2dArrayF32:
+            return {R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -647,7 +647,7 @@
 %19 = OpConstant %18 3
 %21 = OpConstant %18 0
 )",
-              R"(
+                    R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
@@ -655,10 +655,10 @@
 %20 = OpCompositeConstruct %14 %15 %16 %17
 %8 = OpImageGather %9 %13 %20 %21
 )",
-              R"(
+                    R"(
 )"};
-    case ValidTextureOverload::kGather2dArrayOffsetF32:
-      return {R"(
+        case ValidTextureOverload::kGather2dArrayOffsetF32:
+            return {R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -679,7 +679,7 @@
 %24 = OpConstant %18 5
 %25 = OpConstantComposite %22 %23 %24
 )",
-              R"(
+                    R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
@@ -687,10 +687,10 @@
 %20 = OpCompositeConstruct %14 %15 %16 %17
 %8 = OpImageGather %9 %13 %20 %21 ConstOffset %25
 )",
-              R"(
+                    R"(
 )"};
-    case ValidTextureOverload::kGatherCubeF32:
-      return {R"(
+        case ValidTextureOverload::kGatherCubeF32:
+            return {R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 Cube 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -708,16 +708,16 @@
 %19 = OpTypeInt 32 1
 %20 = OpConstant %19 0
 )",
-              R"(
+                    R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageGather %9 %13 %18 %20
 )",
-              R"(
+                    R"(
 )"};
-    case ValidTextureOverload::kGatherCubeArrayF32:
-      return {R"(
+        case ValidTextureOverload::kGatherCubeArrayF32:
+            return {R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 Cube 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -734,7 +734,7 @@
 %19 = OpConstant %18 4
 %21 = OpConstant %18 0
 )",
-              R"(
+                    R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
@@ -742,11 +742,11 @@
 %20 = OpCompositeConstruct %9 %14 %15 %16 %17
 %8 = OpImageGather %9 %13 %20 %21
 )",
-              R"(
+                    R"(
 OpCapability SampledCubeArray
 )"};
-    case ValidTextureOverload::kGatherDepth2dF32:
-      return {R"(
+        case ValidTextureOverload::kGatherDepth2dF32:
+            return {R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -763,16 +763,16 @@
 %18 = OpTypeInt 32 1
 %19 = OpConstant %18 0
 )",
-              R"(
+                    R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageGather %9 %13 %17 %19
 )",
-              R"(
+                    R"(
 )"};
-    case ValidTextureOverload::kGatherDepth2dOffsetF32:
-      return {R"(
+        case ValidTextureOverload::kGatherDepth2dOffsetF32:
+            return {R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -793,16 +793,16 @@
 %22 = OpConstant %18 4
 %23 = OpConstantComposite %20 %21 %22
 )",
-              R"(
+                    R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageGather %9 %13 %17 %19 ConstOffset %23
 )",
-              R"(
+                    R"(
 )"};
-    case ValidTextureOverload::kGatherDepth2dArrayF32:
-      return {R"(
+        case ValidTextureOverload::kGatherDepth2dArrayF32:
+            return {R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -819,7 +819,7 @@
 %19 = OpConstant %18 3
 %21 = OpConstant %18 0
 )",
-              R"(
+                    R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
@@ -827,10 +827,10 @@
 %20 = OpCompositeConstruct %14 %15 %16 %17
 %8 = OpImageGather %9 %13 %20 %21
 )",
-              R"(
+                    R"(
 )"};
-    case ValidTextureOverload::kGatherDepth2dArrayOffsetF32:
-      return {R"(
+        case ValidTextureOverload::kGatherDepth2dArrayOffsetF32:
+            return {R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -851,7 +851,7 @@
 %24 = OpConstant %18 5
 %25 = OpConstantComposite %22 %23 %24
 )",
-              R"(
+                    R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
@@ -859,10 +859,10 @@
 %20 = OpCompositeConstruct %14 %15 %16 %17
 %8 = OpImageGather %9 %13 %20 %21 ConstOffset %25
 )",
-              R"(
+                    R"(
 )"};
-    case ValidTextureOverload::kGatherDepthCubeF32:
-      return {R"(
+        case ValidTextureOverload::kGatherDepthCubeF32:
+            return {R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 Cube 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -880,16 +880,16 @@
 %19 = OpTypeInt 32 1
 %20 = OpConstant %19 0
 )",
-              R"(
+                    R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageGather %9 %13 %18 %20
 )",
-              R"(
+                    R"(
 )"};
-    case ValidTextureOverload::kGatherDepthCubeArrayF32:
-      return {R"(
+        case ValidTextureOverload::kGatherDepthCubeArrayF32:
+            return {R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 Cube 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -906,7 +906,7 @@
 %19 = OpConstant %18 4
 %21 = OpConstant %18 0
 )",
-              R"(
+                    R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
@@ -914,11 +914,11 @@
 %20 = OpCompositeConstruct %9 %14 %15 %16 %17
 %8 = OpImageGather %9 %13 %20 %21
 )",
-              R"(
+                    R"(
 OpCapability SampledCubeArray
 )"};
-    case ValidTextureOverload::kGatherCompareDepth2dF32:
-      return {R"(
+        case ValidTextureOverload::kGatherCompareDepth2dF32:
+            return {R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -934,16 +934,16 @@
 %17 = OpConstantComposite %14 %15 %16
 %18 = OpConstant %4 3
 )",
-              R"(
+                    R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageDrefGather %9 %13 %17 %18
 )",
-              R"(
+                    R"(
 )"};
-    case ValidTextureOverload::kGatherCompareDepth2dOffsetF32:
-      return {R"(
+        case ValidTextureOverload::kGatherCompareDepth2dOffsetF32:
+            return {R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -964,16 +964,16 @@
 %22 = OpConstant %20 5
 %23 = OpConstantComposite %19 %21 %22
 )",
-              R"(
+                    R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageDrefGather %9 %13 %17 %18 ConstOffset %23
 )",
-              R"(
+                    R"(
 )"};
-    case ValidTextureOverload::kGatherCompareDepth2dArrayF32:
-      return {R"(
+        case ValidTextureOverload::kGatherCompareDepth2dArrayF32:
+            return {R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -990,7 +990,7 @@
 %19 = OpConstant %18 3
 %21 = OpConstant %4 4
 )",
-              R"(
+                    R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
@@ -998,10 +998,10 @@
 %20 = OpCompositeConstruct %14 %15 %16 %17
 %8 = OpImageDrefGather %9 %13 %20 %21
 )",
-              R"(
+                    R"(
 )"};
-    case ValidTextureOverload::kGatherCompareDepth2dArrayOffsetF32:
-      return {R"(
+        case ValidTextureOverload::kGatherCompareDepth2dArrayOffsetF32:
+            return {R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -1022,7 +1022,7 @@
 %24 = OpConstant %18 6
 %25 = OpConstantComposite %22 %23 %24
 )",
-              R"(
+                    R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
@@ -1030,10 +1030,10 @@
 %20 = OpCompositeConstruct %14 %15 %16 %17
 %8 = OpImageDrefGather %9 %13 %20 %21 ConstOffset %25
 )",
-              R"(
+                    R"(
 )"};
-    case ValidTextureOverload::kGatherCompareDepthCubeF32:
-      return {R"(
+        case ValidTextureOverload::kGatherCompareDepthCubeF32:
+            return {R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 Cube 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -1050,16 +1050,16 @@
 %18 = OpConstantComposite %14 %15 %16 %17
 %19 = OpConstant %4 4
 )",
-              R"(
+                    R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageDrefGather %9 %13 %18 %19
 )",
-              R"(
+                    R"(
 )"};
-    case ValidTextureOverload::kGatherCompareDepthCubeArrayF32:
-      return {R"(
+        case ValidTextureOverload::kGatherCompareDepthCubeArrayF32:
+            return {R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 Cube 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -1076,7 +1076,7 @@
 %19 = OpConstant %18 4
 %21 = OpConstant %4 5
 )",
-              R"(
+                    R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
@@ -1084,11 +1084,11 @@
 %20 = OpCompositeConstruct %9 %14 %15 %16 %17
 %8 = OpImageDrefGather %9 %13 %20 %21
 )",
-              R"(
+                    R"(
 OpCapability SampledCubeArray
 )"};
-    case ValidTextureOverload::kNumLayers2dArray:
-      return {R"(
+        case ValidTextureOverload::kNumLayers2dArray:
+            return {R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -1100,16 +1100,16 @@
 %11 = OpTypeVector %9 3
 %13 = OpConstant %9 0
 )",
-              R"(
+                    R"(
 %12 = OpLoad %3 %1
 %10 = OpImageQuerySizeLod %11 %12 %13
 %8 = OpCompositeExtract %9 %10 2
 )",
-              R"(
+                    R"(
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kNumLayersCubeArray:
-      return {R"(
+        case ValidTextureOverload::kNumLayersCubeArray:
+            return {R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 Cube 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -1121,17 +1121,17 @@
 %11 = OpTypeVector %9 3
 %13 = OpConstant %9 0
 )",
-              R"(
+                    R"(
 %12 = OpLoad %3 %1
 %10 = OpImageQuerySizeLod %11 %12 %13
 %8 = OpCompositeExtract %9 %10 2
 )",
-              R"(
+                    R"(
 OpCapability SampledCubeArray
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kNumLayersDepth2dArray:
-      return {R"(
+        case ValidTextureOverload::kNumLayersDepth2dArray:
+            return {R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -1143,16 +1143,16 @@
 %11 = OpTypeVector %9 3
 %13 = OpConstant %9 0
 )",
-              R"(
+                    R"(
 %12 = OpLoad %3 %1
 %10 = OpImageQuerySizeLod %11 %12 %13
 %8 = OpCompositeExtract %9 %10 2
 )",
-              R"(
+                    R"(
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kNumLayersDepthCubeArray:
-      return {R"(
+        case ValidTextureOverload::kNumLayersDepthCubeArray:
+            return {R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 Cube 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -1164,17 +1164,17 @@
 %11 = OpTypeVector %9 3
 %13 = OpConstant %9 0
 )",
-              R"(
+                    R"(
 %12 = OpLoad %3 %1
 %10 = OpImageQuerySizeLod %11 %12 %13
 %8 = OpCompositeExtract %9 %10 2
 )",
-              R"(
+                    R"(
 OpCapability SampledCubeArray
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kNumLayersStorageWO2dArray:
-      return {R"(
+        case ValidTextureOverload::kNumLayersStorageWO2dArray:
+            return {R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 0 2 Rgba32f
 %2 = OpTypePointer UniformConstant %3
@@ -1185,16 +1185,16 @@
 %9 = OpTypeInt 32 1
 %11 = OpTypeVector %9 3
 )",
-              R"(
+                    R"(
 %12 = OpLoad %3 %1
 %10 = OpImageQuerySize %11 %12
 %8 = OpCompositeExtract %9 %10 2
 )",
-              R"(
+                    R"(
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kNumLevels2d:
-      return {R"(
+        case ValidTextureOverload::kNumLevels2d:
+            return {R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -1204,15 +1204,15 @@
 %5 = OpVariable %6 UniformConstant
 %9 = OpTypeInt 32 1
 )",
-              R"(
+                    R"(
 %10 = OpLoad %3 %1
 %8 = OpImageQueryLevels %9 %10
 )",
-              R"(
+                    R"(
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kNumLevels2dArray:
-      return {R"(
+        case ValidTextureOverload::kNumLevels2dArray:
+            return {R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -1222,15 +1222,15 @@
 %5 = OpVariable %6 UniformConstant
 %9 = OpTypeInt 32 1
 )",
-              R"(
+                    R"(
 %10 = OpLoad %3 %1
 %8 = OpImageQueryLevels %9 %10
 )",
-              R"(
+                    R"(
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kNumLevels3d:
-      return {R"(
+        case ValidTextureOverload::kNumLevels3d:
+            return {R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 3D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -1240,15 +1240,15 @@
 %5 = OpVariable %6 UniformConstant
 %9 = OpTypeInt 32 1
 )",
-              R"(
+                    R"(
 %10 = OpLoad %3 %1
 %8 = OpImageQueryLevels %9 %10
 )",
-              R"(
+                    R"(
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kNumLevelsCube:
-      return {R"(
+        case ValidTextureOverload::kNumLevelsCube:
+            return {R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 Cube 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -1258,15 +1258,15 @@
 %5 = OpVariable %6 UniformConstant
 %9 = OpTypeInt 32 1
 )",
-              R"(
+                    R"(
 %10 = OpLoad %3 %1
 %8 = OpImageQueryLevels %9 %10
 )",
-              R"(
+                    R"(
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kNumLevelsCubeArray:
-      return {R"(
+        case ValidTextureOverload::kNumLevelsCubeArray:
+            return {R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 Cube 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -1276,16 +1276,16 @@
 %5 = OpVariable %6 UniformConstant
 %9 = OpTypeInt 32 1
 )",
-              R"(
+                    R"(
 %10 = OpLoad %3 %1
 %8 = OpImageQueryLevels %9 %10
 )",
-              R"(
+                    R"(
 OpCapability SampledCubeArray
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kNumLevelsDepth2d:
-      return {R"(
+        case ValidTextureOverload::kNumLevelsDepth2d:
+            return {R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -1295,15 +1295,15 @@
 %5 = OpVariable %6 UniformConstant
 %9 = OpTypeInt 32 1
 )",
-              R"(
+                    R"(
 %10 = OpLoad %3 %1
 %8 = OpImageQueryLevels %9 %10
 )",
-              R"(
+                    R"(
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kNumLevelsDepth2dArray:
-      return {R"(
+        case ValidTextureOverload::kNumLevelsDepth2dArray:
+            return {R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -1313,15 +1313,15 @@
 %5 = OpVariable %6 UniformConstant
 %9 = OpTypeInt 32 1
 )",
-              R"(
+                    R"(
 %10 = OpLoad %3 %1
 %8 = OpImageQueryLevels %9 %10
 )",
-              R"(
+                    R"(
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kNumLevelsDepthCube:
-      return {R"(
+        case ValidTextureOverload::kNumLevelsDepthCube:
+            return {R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 Cube 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -1331,15 +1331,15 @@
 %5 = OpVariable %6 UniformConstant
 %9 = OpTypeInt 32 1
 )",
-              R"(
+                    R"(
 %10 = OpLoad %3 %1
 %8 = OpImageQueryLevels %9 %10
 )",
-              R"(
+                    R"(
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kNumLevelsDepthCubeArray:
-      return {R"(
+        case ValidTextureOverload::kNumLevelsDepthCubeArray:
+            return {R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 Cube 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -1349,16 +1349,16 @@
 %5 = OpVariable %6 UniformConstant
 %9 = OpTypeInt 32 1
 )",
-              R"(
+                    R"(
 %10 = OpLoad %3 %1
 %8 = OpImageQueryLevels %9 %10
 )",
-              R"(
+                    R"(
 OpCapability SampledCubeArray
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kNumSamplesMultisampled2d:
-      return {R"(
+        case ValidTextureOverload::kNumSamplesMultisampled2d:
+            return {R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 1 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -1368,15 +1368,15 @@
 %5 = OpVariable %6 UniformConstant
 %9 = OpTypeInt 32 1
 )",
-              R"(
+                    R"(
 %10 = OpLoad %3 %1
 %8 = OpImageQuerySamples %9 %10
 )",
-              R"(
+                    R"(
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kNumSamplesDepthMultisampled2d:
-      return {R"(
+        case ValidTextureOverload::kNumSamplesDepthMultisampled2d:
+            return {R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 1 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -1386,16 +1386,16 @@
 %5 = OpVariable %6 UniformConstant
 %9 = OpTypeInt 32 1
 )",
-              R"(
+                    R"(
 %10 = OpLoad %3 %1
 %8 = OpImageQuerySamples %9 %10
 )",
-              R"(
+                    R"(
 OpCapability ImageQuery
 )"};
-    case ValidTextureOverload::kSample1dF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSample1dF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 1D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -1407,18 +1407,18 @@
 %12 = OpTypeSampledImage %3
 %14 = OpConstant %4 1
 )",
-          R"(
+                R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleImplicitLod %9 %13 %14
 )",
-          R"(
+                R"(
 OpCapability Sampled1D
 )"};
-    case ValidTextureOverload::kSample2dF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSample2dF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -1433,17 +1433,17 @@
 %16 = OpConstant %4 2
 %17 = OpConstantComposite %14 %15 %16
 )",
-          R"(
+                R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleImplicitLod %9 %13 %17
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSample2dOffsetF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSample2dOffsetF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -1463,17 +1463,17 @@
 %21 = OpConstant %19 4
 %22 = OpConstantComposite %18 %20 %21
 )",
-          R"(
+                R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleImplicitLod %9 %13 %17 ConstOffset %22
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSample2dArrayF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSample2dArrayF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -1489,7 +1489,7 @@
 %18 = OpTypeInt 32 1
 %19 = OpConstant %18 3
 )",
-          R"(
+                R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
@@ -1497,11 +1497,11 @@
 %20 = OpCompositeConstruct %14 %15 %16 %17
 %8 = OpImageSampleImplicitLod %9 %13 %20
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSample2dArrayOffsetF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSample2dArrayOffsetF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -1521,7 +1521,7 @@
 %23 = OpConstant %18 5
 %24 = OpConstantComposite %21 %22 %23
 )",
-          R"(
+                R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
@@ -1529,11 +1529,11 @@
 %20 = OpCompositeConstruct %14 %15 %16 %17
 %8 = OpImageSampleImplicitLod %9 %13 %20 ConstOffset %24
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSample3dF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSample3dF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 3D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -1549,17 +1549,17 @@
 %17 = OpConstant %4 3
 %18 = OpConstantComposite %14 %15 %16 %17
 )",
-          R"(
+                R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleImplicitLod %9 %13 %18
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSample3dOffsetF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSample3dOffsetF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 3D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -1581,17 +1581,17 @@
 %23 = OpConstant %20 6
 %24 = OpConstantComposite %19 %21 %22 %23
 )",
-          R"(
+                R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleImplicitLod %9 %13 %18 ConstOffset %24
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleCubeF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleCubeF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 Cube 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -1607,17 +1607,17 @@
 %17 = OpConstant %4 3
 %18 = OpConstantComposite %14 %15 %16 %17
 )",
-          R"(
+                R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleImplicitLod %9 %13 %18
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleCubeArrayF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleCubeArrayF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 Cube 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -1633,7 +1633,7 @@
 %18 = OpTypeInt 32 1
 %19 = OpConstant %18 4
 )",
-          R"(
+                R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
@@ -1641,12 +1641,12 @@
 %20 = OpCompositeConstruct %9 %14 %15 %16 %17
 %8 = OpImageSampleImplicitLod %9 %13 %20
 )",
-          R"(
+                R"(
 OpCapability SampledCubeArray
 )"};
-    case ValidTextureOverload::kSampleDepth2dF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleDepth2dF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -1661,18 +1661,18 @@
 %17 = OpConstant %4 2
 %18 = OpConstantComposite %15 %16 %17
 )",
-          R"(
+                R"(
 %11 = OpLoad %7 %5
 %12 = OpLoad %3 %1
 %14 = OpSampledImage %13 %12 %11
 %9 = OpImageSampleImplicitLod %10 %14 %18
 %8 = OpCompositeExtract %4 %9 0
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleDepth2dOffsetF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleDepth2dOffsetF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -1692,18 +1692,18 @@
 %22 = OpConstant %20 4
 %23 = OpConstantComposite %19 %21 %22
 )",
-          R"(
+                R"(
 %11 = OpLoad %7 %5
 %12 = OpLoad %3 %1
 %14 = OpSampledImage %13 %12 %11
 %9 = OpImageSampleImplicitLod %10 %14 %18 ConstOffset %23
 %8 = OpCompositeExtract %4 %9 0
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleDepth2dArrayF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleDepth2dArrayF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -1719,7 +1719,7 @@
 %19 = OpTypeInt 32 1
 %20 = OpConstant %19 3
 )",
-          R"(
+                R"(
 %11 = OpLoad %7 %5
 %12 = OpLoad %3 %1
 %14 = OpSampledImage %13 %12 %11
@@ -1728,11 +1728,11 @@
 %9 = OpImageSampleImplicitLod %10 %14 %21
 %8 = OpCompositeExtract %4 %9 0
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleDepth2dArrayOffsetF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleDepth2dArrayOffsetF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -1752,7 +1752,7 @@
 %24 = OpConstant %19 5
 %25 = OpConstantComposite %22 %23 %24
 )",
-          R"(
+                R"(
 %11 = OpLoad %7 %5
 %12 = OpLoad %3 %1
 %14 = OpSampledImage %13 %12 %11
@@ -1761,11 +1761,11 @@
 %9 = OpImageSampleImplicitLod %10 %14 %21 ConstOffset %25
 %8 = OpCompositeExtract %4 %9 0
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleDepthCubeF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleDepthCubeF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 Cube 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -1781,18 +1781,18 @@
 %18 = OpConstant %4 3
 %19 = OpConstantComposite %15 %16 %17 %18
 )",
-          R"(
+                R"(
 %11 = OpLoad %7 %5
 %12 = OpLoad %3 %1
 %14 = OpSampledImage %13 %12 %11
 %9 = OpImageSampleImplicitLod %10 %14 %19
 %8 = OpCompositeExtract %4 %9 0
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleDepthCubeArrayF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleDepthCubeArrayF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 Cube 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -1808,7 +1808,7 @@
 %19 = OpTypeInt 32 1
 %20 = OpConstant %19 4
 )",
-          R"(
+                R"(
 %11 = OpLoad %7 %5
 %12 = OpLoad %3 %1
 %14 = OpSampledImage %13 %12 %11
@@ -1817,12 +1817,12 @@
 %9 = OpImageSampleImplicitLod %10 %14 %21
 %8 = OpCompositeExtract %4 %9 0
 )",
-          R"(
+                R"(
 OpCapability SampledCubeArray
 )"};
-    case ValidTextureOverload::kSampleBias2dF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleBias2dF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -1838,17 +1838,17 @@
 %17 = OpConstantComposite %14 %15 %16
 %18 = OpConstant %4 3
 )",
-          R"(
+                R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleImplicitLod %9 %13 %17 Bias %18
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleBias2dOffsetF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleBias2dOffsetF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -1869,17 +1869,17 @@
 %22 = OpConstant %20 5
 %23 = OpConstantComposite %19 %21 %22
 )",
-          R"(
+                R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleImplicitLod %9 %13 %17 Bias|ConstOffset %18 %23
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleBias2dArrayF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleBias2dArrayF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -1896,7 +1896,7 @@
 %19 = OpConstant %18 4
 %21 = OpConstant %4 3
 )",
-          R"(
+                R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
@@ -1904,11 +1904,11 @@
 %20 = OpCompositeConstruct %14 %15 %16 %17
 %8 = OpImageSampleImplicitLod %9 %13 %20 Bias %21
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleBias2dArrayOffsetF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleBias2dArrayOffsetF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -1929,7 +1929,7 @@
 %24 = OpConstant %18 6
 %25 = OpConstantComposite %22 %23 %24
 )",
-          R"(
+                R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
@@ -1937,11 +1937,11 @@
 %20 = OpCompositeConstruct %14 %15 %16 %17
 %8 = OpImageSampleImplicitLod %9 %13 %20 Bias|ConstOffset %21 %25
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleBias3dF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleBias3dF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 3D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -1958,17 +1958,17 @@
 %18 = OpConstantComposite %14 %15 %16 %17
 %19 = OpConstant %4 4
 )",
-          R"(
+                R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleImplicitLod %9 %13 %18 Bias %19
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleBias3dOffsetF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleBias3dOffsetF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 3D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -1991,17 +1991,17 @@
 %24 = OpConstant %21 7
 %25 = OpConstantComposite %20 %22 %23 %24
 )",
-          R"(
+                R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleImplicitLod %9 %13 %18 Bias|ConstOffset %19 %25
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleBiasCubeF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleBiasCubeF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 Cube 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -2018,17 +2018,17 @@
 %18 = OpConstantComposite %14 %15 %16 %17
 %19 = OpConstant %4 4
 )",
-          R"(
+                R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleImplicitLod %9 %13 %18 Bias %19
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleBiasCubeArrayF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleBiasCubeArrayF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 Cube 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -2045,7 +2045,7 @@
 %19 = OpConstant %18 3
 %21 = OpConstant %4 4
 )",
-          R"(
+                R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
@@ -2053,12 +2053,12 @@
 %20 = OpCompositeConstruct %9 %14 %15 %16 %17
 %8 = OpImageSampleImplicitLod %9 %13 %20 Bias %21
 )",
-          R"(
+                R"(
 OpCapability SampledCubeArray
 )"};
-    case ValidTextureOverload::kSampleLevel2dF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleLevel2dF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -2074,17 +2074,17 @@
 %17 = OpConstantComposite %14 %15 %16
 %18 = OpConstant %4 3
 )",
-          R"(
+                R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleExplicitLod %9 %13 %17 Lod %18
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleLevel2dOffsetF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleLevel2dOffsetF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -2105,17 +2105,17 @@
 %22 = OpConstant %20 5
 %23 = OpConstantComposite %19 %21 %22
 )",
-          R"(
+                R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleExplicitLod %9 %13 %17 Lod|ConstOffset %18 %23
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleLevel2dArrayF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleLevel2dArrayF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -2132,7 +2132,7 @@
 %19 = OpConstant %18 3
 %21 = OpConstant %4 4
 )",
-          R"(
+                R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
@@ -2140,11 +2140,11 @@
 %20 = OpCompositeConstruct %14 %15 %16 %17
 %8 = OpImageSampleExplicitLod %9 %13 %20 Lod %21
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleLevel2dArrayOffsetF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleLevel2dArrayOffsetF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -2165,7 +2165,7 @@
 %24 = OpConstant %18 6
 %25 = OpConstantComposite %22 %23 %24
 )",
-          R"(
+                R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
@@ -2173,11 +2173,11 @@
 %20 = OpCompositeConstruct %14 %15 %16 %17
 %8 = OpImageSampleExplicitLod %9 %13 %20 Lod|ConstOffset %21 %25
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleLevel3dF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleLevel3dF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 3D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -2194,17 +2194,17 @@
 %18 = OpConstantComposite %14 %15 %16 %17
 %19 = OpConstant %4 4
 )",
-          R"(
+                R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleExplicitLod %9 %13 %18 Lod %19
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleLevel3dOffsetF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleLevel3dOffsetF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 3D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -2227,17 +2227,17 @@
 %24 = OpConstant %21 7
 %25 = OpConstantComposite %20 %22 %23 %24
 )",
-          R"(
+                R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleExplicitLod %9 %13 %18 Lod|ConstOffset %19 %25
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleLevelCubeF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleLevelCubeF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 Cube 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -2254,17 +2254,17 @@
 %18 = OpConstantComposite %14 %15 %16 %17
 %19 = OpConstant %4 4
 )",
-          R"(
+                R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleExplicitLod %9 %13 %18 Lod %19
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleLevelCubeArrayF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleLevelCubeArrayF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 Cube 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -2281,7 +2281,7 @@
 %19 = OpConstant %18 4
 %21 = OpConstant %4 5
 )",
-          R"(
+                R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
@@ -2289,12 +2289,12 @@
 %20 = OpCompositeConstruct %9 %14 %15 %16 %17
 %8 = OpImageSampleExplicitLod %9 %13 %20 Lod %21
 )",
-          R"(
+                R"(
 OpCapability SampledCubeArray
 )"};
-    case ValidTextureOverload::kSampleLevelDepth2dF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleLevelDepth2dF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -2311,7 +2311,7 @@
 %20 = OpTypeInt 32 1
 %21 = OpConstant %20 3
 )",
-          R"(
+                R"(
 %11 = OpLoad %7 %5
 %12 = OpLoad %3 %1
 %14 = OpSampledImage %13 %12 %11
@@ -2319,11 +2319,11 @@
 %9 = OpImageSampleExplicitLod %10 %14 %18 Lod %19
 %8 = OpCompositeExtract %4 %9 0
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleLevelDepth2dOffsetF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleLevelDepth2dOffsetF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -2344,7 +2344,7 @@
 %24 = OpConstant %20 5
 %25 = OpConstantComposite %22 %23 %24
 )",
-          R"(
+                R"(
 %11 = OpLoad %7 %5
 %12 = OpLoad %3 %1
 %14 = OpSampledImage %13 %12 %11
@@ -2352,11 +2352,11 @@
 %9 = OpImageSampleExplicitLod %10 %14 %18 Lod|ConstOffset %19 %25
 %8 = OpCompositeExtract %4 %9 0
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleLevelDepth2dArrayF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleLevelDepth2dArrayF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -2373,7 +2373,7 @@
 %20 = OpConstant %19 3
 %23 = OpConstant %19 4
 )",
-          R"(
+                R"(
 %11 = OpLoad %7 %5
 %12 = OpLoad %3 %1
 %14 = OpSampledImage %13 %12 %11
@@ -2383,11 +2383,11 @@
 %9 = OpImageSampleExplicitLod %10 %14 %21 Lod %22
 %8 = OpCompositeExtract %4 %9 0
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleLevelDepth2dArrayOffsetF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleLevelDepth2dArrayOffsetF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -2408,7 +2408,7 @@
 %26 = OpConstant %19 6
 %27 = OpConstantComposite %24 %25 %26
 )",
-          R"(
+                R"(
 %11 = OpLoad %7 %5
 %12 = OpLoad %3 %1
 %14 = OpSampledImage %13 %12 %11
@@ -2418,11 +2418,11 @@
 %9 = OpImageSampleExplicitLod %10 %14 %21 Lod|ConstOffset %22 %27
 %8 = OpCompositeExtract %4 %9 0
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleLevelDepthCubeF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleLevelDepthCubeF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 Cube 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -2440,7 +2440,7 @@
 %21 = OpTypeInt 32 1
 %22 = OpConstant %21 4
 )",
-          R"(
+                R"(
 %11 = OpLoad %7 %5
 %12 = OpLoad %3 %1
 %14 = OpSampledImage %13 %12 %11
@@ -2448,11 +2448,11 @@
 %9 = OpImageSampleExplicitLod %10 %14 %19 Lod %20
 %8 = OpCompositeExtract %4 %9 0
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleLevelDepthCubeArrayF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleLevelDepthCubeArrayF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 Cube 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -2469,7 +2469,7 @@
 %20 = OpConstant %19 4
 %23 = OpConstant %19 5
 )",
-          R"(
+                R"(
 %11 = OpLoad %7 %5
 %12 = OpLoad %3 %1
 %14 = OpSampledImage %13 %12 %11
@@ -2479,12 +2479,12 @@
 %9 = OpImageSampleExplicitLod %10 %14 %21 Lod %22
 %8 = OpCompositeExtract %4 %9 0
 )",
-          R"(
+                R"(
 OpCapability SampledCubeArray
 )"};
-    case ValidTextureOverload::kSampleGrad2dF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleGrad2dF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -2505,17 +2505,17 @@
 %22 = OpConstant %4 6
 %23 = OpConstantComposite %14 %21 %22
 )",
-          R"(
+                R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleExplicitLod %9 %13 %17 Grad %20 %23
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleGrad2dOffsetF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleGrad2dOffsetF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -2540,17 +2540,17 @@
 %26 = OpConstant %25 7
 %27 = OpConstantComposite %24 %26 %26
 )",
-          R"(
+                R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleExplicitLod %9 %13 %17 Grad|ConstOffset %20 %23 %27
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleGrad2dArrayF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleGrad2dArrayF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -2573,7 +2573,7 @@
 %26 = OpConstant %4 7
 %27 = OpConstantComposite %21 %25 %26
 )",
-          R"(
+                R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
@@ -2581,11 +2581,11 @@
 %20 = OpCompositeConstruct %14 %15 %16 %17
 %8 = OpImageSampleExplicitLod %9 %13 %20 Grad %24 %27
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleGrad2dArrayOffsetF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleGrad2dArrayOffsetF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -2612,7 +2612,7 @@
 %30 = OpConstant %18 7
 %31 = OpConstantComposite %28 %29 %30
 )",
-          R"(
+                R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
@@ -2620,11 +2620,11 @@
 %20 = OpCompositeConstruct %14 %15 %16 %17
 %8 = OpImageSampleExplicitLod %9 %13 %20 Grad|ConstOffset %24 %27 %31
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleGrad3dF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleGrad3dF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 3D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -2648,17 +2648,17 @@
 %25 = OpConstant %4 9
 %26 = OpConstantComposite %14 %23 %24 %25
 )",
-          R"(
+                R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleExplicitLod %9 %13 %18 Grad %22 %26
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleGrad3dOffsetF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleGrad3dOffsetF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 3D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -2688,17 +2688,17 @@
 %31 = OpConstant %28 2
 %32 = OpConstantComposite %27 %29 %30 %31
 )",
-          R"(
+                R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleExplicitLod %9 %13 %18 Grad|ConstOffset %22 %26 %32
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleGradCubeF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleGradCubeF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 Cube 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -2722,17 +2722,17 @@
 %25 = OpConstant %4 9
 %26 = OpConstantComposite %14 %23 %24 %25
 )",
-          R"(
+                R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
 %8 = OpImageSampleExplicitLod %9 %13 %18 Grad %22 %26
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleGradCubeArrayF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleGradCubeArrayF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 Cube 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -2757,7 +2757,7 @@
 %28 = OpConstant %4 10
 %29 = OpConstantComposite %21 %26 %27 %28
 )",
-          R"(
+                R"(
 %10 = OpLoad %7 %5
 %11 = OpLoad %3 %1
 %13 = OpSampledImage %12 %11 %10
@@ -2765,12 +2765,12 @@
 %20 = OpCompositeConstruct %9 %14 %15 %16 %17
 %8 = OpImageSampleExplicitLod %9 %13 %20 Grad %25 %29
 )",
-          R"(
+                R"(
 OpCapability SampledCubeArray
 )"};
-    case ValidTextureOverload::kSampleCompareDepth2dF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleCompareDepth2dF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -2785,17 +2785,17 @@
 %16 = OpConstantComposite %13 %14 %15
 %17 = OpConstant %4 3
 )",
-          R"(
+                R"(
 %9 = OpLoad %7 %5
 %10 = OpLoad %3 %1
 %12 = OpSampledImage %11 %10 %9
 %8 = OpImageSampleDrefImplicitLod %4 %12 %16 %17
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleCompareDepth2dOffsetF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleCompareDepth2dOffsetF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -2815,17 +2815,17 @@
 %21 = OpConstant %19 5
 %22 = OpConstantComposite %18 %20 %21
 )",
-          R"(
+                R"(
 %9 = OpLoad %7 %5
 %10 = OpLoad %3 %1
 %12 = OpSampledImage %11 %10 %9
 %8 = OpImageSampleDrefImplicitLod %4 %12 %16 %17 ConstOffset %22
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleCompareDepth2dArrayF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleCompareDepth2dArrayF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -2841,7 +2841,7 @@
 %18 = OpConstant %17 4
 %20 = OpConstant %4 3
 )",
-          R"(
+                R"(
 %9 = OpLoad %7 %5
 %10 = OpLoad %3 %1
 %12 = OpSampledImage %11 %10 %9
@@ -2849,11 +2849,11 @@
 %19 = OpCompositeConstruct %13 %14 %15 %16
 %8 = OpImageSampleDrefImplicitLod %4 %12 %19 %20
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleCompareDepth2dArrayOffsetF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleCompareDepth2dArrayOffsetF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -2873,7 +2873,7 @@
 %23 = OpConstant %17 6
 %24 = OpConstantComposite %21 %22 %23
 )",
-          R"(
+                R"(
 %9 = OpLoad %7 %5
 %10 = OpLoad %3 %1
 %12 = OpSampledImage %11 %10 %9
@@ -2881,11 +2881,11 @@
 %19 = OpCompositeConstruct %13 %14 %15 %16
 %8 = OpImageSampleDrefImplicitLod %4 %12 %19 %20 ConstOffset %24
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleCompareDepthCubeF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleCompareDepthCubeF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 Cube 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -2901,17 +2901,17 @@
 %17 = OpConstantComposite %13 %14 %15 %16
 %18 = OpConstant %4 4
 )",
-          R"(
+                R"(
 %9 = OpLoad %7 %5
 %10 = OpLoad %3 %1
 %12 = OpSampledImage %11 %10 %9
 %8 = OpImageSampleDrefImplicitLod %4 %12 %17 %18
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleCompareDepthCubeArrayF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleCompareDepthCubeArrayF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 Cube 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -2928,7 +2928,7 @@
 %19 = OpConstant %18 4
 %21 = OpConstant %4 5
 )",
-          R"(
+                R"(
 %9 = OpLoad %7 %5
 %10 = OpLoad %3 %1
 %12 = OpSampledImage %11 %10 %9
@@ -2936,12 +2936,12 @@
 %20 = OpCompositeConstruct %13 %14 %15 %16 %17
 %8 = OpImageSampleDrefImplicitLod %4 %12 %20 %21
 )",
-          R"(
+                R"(
 OpCapability SampledCubeArray
 )"};
-    case ValidTextureOverload::kSampleCompareLevelDepth2dF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleCompareLevelDepth2dF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -2957,17 +2957,17 @@
 %17 = OpConstant %4 3
 %18 = OpConstant %4 0
 )",
-          R"(
+                R"(
 %9 = OpLoad %7 %5
 %10 = OpLoad %3 %1
 %12 = OpSampledImage %11 %10 %9
 %8 = OpImageSampleDrefExplicitLod %4 %12 %16 %17 Lod %18
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleCompareLevelDepth2dOffsetF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleCompareLevelDepth2dOffsetF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -2988,17 +2988,17 @@
 %22 = OpConstant %20 5
 %23 = OpConstantComposite %19 %21 %22
 )",
-          R"(
+                R"(
 %9 = OpLoad %7 %5
 %10 = OpLoad %3 %1
 %12 = OpSampledImage %11 %10 %9
 %8 = OpImageSampleDrefExplicitLod %4 %12 %16 %17 Lod|ConstOffset %18 %23
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleCompareLevelDepth2dArrayF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleCompareLevelDepth2dArrayF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -3015,7 +3015,7 @@
 %20 = OpConstant %4 3
 %21 = OpConstant %4 0
 )",
-          R"(
+                R"(
 %9 = OpLoad %7 %5
 %10 = OpLoad %3 %1
 %12 = OpSampledImage %11 %10 %9
@@ -3023,11 +3023,11 @@
 %19 = OpCompositeConstruct %13 %14 %15 %16
 %8 = OpImageSampleDrefExplicitLod %4 %12 %19 %20 Lod %21
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleCompareLevelDepth2dArrayOffsetF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleCompareLevelDepth2dArrayOffsetF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -3048,7 +3048,7 @@
 %24 = OpConstant %17 6
 %25 = OpConstantComposite %22 %23 %24
 )",
-          R"(
+                R"(
 %9 = OpLoad %7 %5
 %10 = OpLoad %3 %1
 %12 = OpSampledImage %11 %10 %9
@@ -3056,11 +3056,11 @@
 %19 = OpCompositeConstruct %13 %14 %15 %16
 %8 = OpImageSampleDrefExplicitLod %4 %12 %19 %20 Lod|ConstOffset %21 %25
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleCompareLevelDepthCubeF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleCompareLevelDepthCubeF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 Cube 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -3077,17 +3077,17 @@
 %18 = OpConstant %4 4
 %19 = OpConstant %4 0
 )",
-          R"(
+                R"(
 %9 = OpLoad %7 %5
 %10 = OpLoad %3 %1
 %12 = OpSampledImage %11 %10 %9
 %8 = OpImageSampleDrefExplicitLod %4 %12 %17 %18 Lod %19
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kSampleCompareLevelDepthCubeArrayF32:
-      return {
-          R"(
+        case ValidTextureOverload::kSampleCompareLevelDepthCubeArrayF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 Cube 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -3105,7 +3105,7 @@
 %21 = OpConstant %4 5
 %22 = OpConstant %4 0
 )",
-          R"(
+                R"(
 %9 = OpLoad %7 %5
 %10 = OpLoad %3 %1
 %12 = OpSampledImage %11 %10 %9
@@ -3113,12 +3113,12 @@
 %20 = OpCompositeConstruct %13 %14 %15 %16 %17
 %8 = OpImageSampleDrefExplicitLod %4 %12 %20 %21 Lod %22
 )",
-          R"(
+                R"(
 OpCapability SampledCubeArray
 )"};
-    case ValidTextureOverload::kLoad1dLevelF32:
-      return {
-          R"(
+        case ValidTextureOverload::kLoad1dLevelF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 1D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -3131,16 +3131,16 @@
 %12 = OpConstant %11 1
 %13 = OpConstant %11 3
 )",
-          R"(
+                R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %12 Lod %13
 )",
-          R"(
+                R"(
 OpCapability Sampled1D
 )"};
-    case ValidTextureOverload::kLoad1dLevelU32:
-      return {
-          R"(
+        case ValidTextureOverload::kLoad1dLevelU32:
+            return {
+                R"(
 %4 = OpTypeInt 32 0
 %3 = OpTypeImage %4 1D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -3153,16 +3153,16 @@
 %12 = OpConstant %11 1
 %13 = OpConstant %11 3
 )",
-          R"(
+                R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %12 Lod %13
 )",
-          R"(
+                R"(
 OpCapability Sampled1D
 )"};
-    case ValidTextureOverload::kLoad1dLevelI32:
-      return {
-          R"(
+        case ValidTextureOverload::kLoad1dLevelI32:
+            return {
+                R"(
 %4 = OpTypeInt 32 1
 %3 = OpTypeImage %4 1D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -3174,16 +3174,16 @@
 %11 = OpConstant %4 1
 %12 = OpConstant %4 3
 )",
-          R"(
+                R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %11 Lod %12
 )",
-          R"(
+                R"(
 OpCapability Sampled1D
 )"};
-    case ValidTextureOverload::kLoad2dLevelF32:
-      return {
-          R"(
+        case ValidTextureOverload::kLoad2dLevelF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -3199,15 +3199,15 @@
 %15 = OpConstantComposite %11 %13 %14
 %16 = OpConstant %12 3
 )",
-          R"(
+                R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %15 Lod %16
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kLoad2dLevelU32:
-      return {
-          R"(
+        case ValidTextureOverload::kLoad2dLevelU32:
+            return {
+                R"(
 %4 = OpTypeInt 32 0
 %3 = OpTypeImage %4 2D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -3223,15 +3223,15 @@
 %15 = OpConstantComposite %11 %13 %14
 %16 = OpConstant %12 3
 )",
-          R"(
+                R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %15 Lod %16
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kLoad2dLevelI32:
-      return {
-          R"(
+        case ValidTextureOverload::kLoad2dLevelI32:
+            return {
+                R"(
 %4 = OpTypeInt 32 1
 %3 = OpTypeImage %4 2D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -3246,15 +3246,15 @@
 %14 = OpConstantComposite %11 %12 %13
 %15 = OpConstant %4 3
 )",
-          R"(
+                R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %14 Lod %15
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kLoad2dArrayLevelF32:
-      return {
-          R"(
+        case ValidTextureOverload::kLoad2dArrayLevelF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -3271,15 +3271,15 @@
 %16 = OpConstantComposite %11 %13 %14 %15
 %17 = OpConstant %12 4
 )",
-          R"(
+                R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %16 Lod %17
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kLoad2dArrayLevelU32:
-      return {
-          R"(
+        case ValidTextureOverload::kLoad2dArrayLevelU32:
+            return {
+                R"(
 %4 = OpTypeInt 32 0
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -3296,15 +3296,15 @@
 %16 = OpConstantComposite %11 %13 %14 %15
 %17 = OpConstant %12 4
 )",
-          R"(
+                R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %16 Lod %17
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kLoad2dArrayLevelI32:
-      return {
-          R"(
+        case ValidTextureOverload::kLoad2dArrayLevelI32:
+            return {
+                R"(
 %4 = OpTypeInt 32 1
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -3320,15 +3320,15 @@
 %15 = OpConstantComposite %11 %12 %13 %14
 %16 = OpConstant %4 4
 )",
-          R"(
+                R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %15 Lod %16
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kLoad3dLevelF32:
-      return {
-          R"(
+        case ValidTextureOverload::kLoad3dLevelF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 3D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -3345,15 +3345,15 @@
 %16 = OpConstantComposite %11 %13 %14 %15
 %17 = OpConstant %12 4
 )",
-          R"(
+                R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %16 Lod %17
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kLoad3dLevelU32:
-      return {
-          R"(
+        case ValidTextureOverload::kLoad3dLevelU32:
+            return {
+                R"(
 %4 = OpTypeInt 32 0
 %3 = OpTypeImage %4 3D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -3370,15 +3370,15 @@
 %16 = OpConstantComposite %11 %13 %14 %15
 %17 = OpConstant %12 4
 )",
-          R"(
+                R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %16 Lod %17
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kLoad3dLevelI32:
-      return {
-          R"(
+        case ValidTextureOverload::kLoad3dLevelI32:
+            return {
+                R"(
 %4 = OpTypeInt 32 1
 %3 = OpTypeImage %4 3D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -3394,15 +3394,15 @@
 %15 = OpConstantComposite %11 %12 %13 %14
 %16 = OpConstant %4 4
 )",
-          R"(
+                R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %15 Lod %16
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kLoadMultisampled2dF32:
-      return {
-          R"(
+        case ValidTextureOverload::kLoadMultisampled2dF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 1 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -3418,15 +3418,15 @@
 %15 = OpConstantComposite %11 %13 %14
 %16 = OpConstant %12 3
 )",
-          R"(
+                R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %15 Sample %16
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kLoadMultisampled2dU32:
-      return {
-          R"(
+        case ValidTextureOverload::kLoadMultisampled2dU32:
+            return {
+                R"(
 %4 = OpTypeInt 32 0
 %3 = OpTypeImage %4 2D 0 0 1 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -3442,15 +3442,15 @@
 %15 = OpConstantComposite %11 %13 %14
 %16 = OpConstant %12 3
 )",
-          R"(
+                R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %15 Sample %16
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kLoadMultisampled2dI32:
-      return {
-          R"(
+        case ValidTextureOverload::kLoadMultisampled2dI32:
+            return {
+                R"(
 %4 = OpTypeInt 32 1
 %3 = OpTypeImage %4 2D 0 0 1 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -3465,15 +3465,15 @@
 %14 = OpConstantComposite %11 %12 %13
 %15 = OpConstant %4 3
 )",
-          R"(
+                R"(
 %10 = OpLoad %3 %1
 %8 = OpImageFetch %9 %10 %14 Sample %15
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kLoadDepth2dLevelF32:
-      return {
-          R"(
+        case ValidTextureOverload::kLoadDepth2dLevelF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -3489,16 +3489,16 @@
 %16 = OpConstantComposite %12 %14 %15
 %17 = OpConstant %13 3
 )",
-          R"(
+                R"(
 %11 = OpLoad %3 %1
 %9 = OpImageFetch %10 %11 %16 Lod %17
 %8 = OpCompositeExtract %4 %9 0
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kLoadDepth2dArrayLevelF32:
-      return {
-          R"(
+        case ValidTextureOverload::kLoadDepth2dArrayLevelF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -3515,16 +3515,16 @@
 %17 = OpConstantComposite %12 %14 %15 %16
 %18 = OpConstant %13 4
 )",
-          R"(
+                R"(
 %11 = OpLoad %3 %1
 %9 = OpImageFetch %10 %11 %17 Lod %18
 %8 = OpCompositeExtract %4 %9 0
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kLoadDepthMultisampled2dF32:
-      return {
-          R"(
+        case ValidTextureOverload::kLoadDepthMultisampled2dF32:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 0 1 Unknown
 %2 = OpTypePointer UniformConstant %3
@@ -3541,16 +3541,16 @@
 %17 = OpConstantComposite %12 %14 %15 %16
 %18 = OpConstant %13 4
 )",
-          R"(
+                R"(
 %11 = OpLoad %3 %1
 %9 = OpImageFetch %10 %11 %17 Sample %18
 %8 = OpCompositeExtract %4 %9 0
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kStoreWO1dRgba32float:
-      return {
-          R"(
+        case ValidTextureOverload::kStoreWO1dRgba32float:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 1D 0 0 0 2 Rgba32f
 %2 = OpTypePointer UniformConstant %3
@@ -3568,16 +3568,16 @@
 %17 = OpConstant %4 5
 %18 = OpConstantComposite %13 %14 %15 %16 %17
 )",
-          R"(
+                R"(
 %10 = OpLoad %3 %1
 OpImageWrite %10 %12 %18
 )",
-          R"(
+                R"(
 OpCapability Image1D
 )"};
-    case ValidTextureOverload::kStoreWO2dRgba32float:
-      return {
-          R"(
+        case ValidTextureOverload::kStoreWO2dRgba32float:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 0 0 2 Rgba32f
 %2 = OpTypePointer UniformConstant %3
@@ -3598,15 +3598,15 @@
 %20 = OpConstant %4 6
 %21 = OpConstantComposite %16 %17 %18 %19 %20
 )",
-          R"(
+                R"(
 %10 = OpLoad %3 %1
 OpImageWrite %10 %15 %21
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kStoreWO2dArrayRgba32float:
-      return {
-          R"(
+        case ValidTextureOverload::kStoreWO2dArrayRgba32float:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 2D 0 1 0 2 Rgba32f
 %2 = OpTypePointer UniformConstant %3
@@ -3628,15 +3628,15 @@
 %21 = OpConstant %4 7
 %22 = OpConstantComposite %17 %18 %19 %20 %21
 )",
-          R"(
+                R"(
 %10 = OpLoad %3 %1
 OpImageWrite %10 %16 %22
 )",
-          R"(
+                R"(
 )"};
-    case ValidTextureOverload::kStoreWO3dRgba32float:
-      return {
-          R"(
+        case ValidTextureOverload::kStoreWO3dRgba32float:
+            return {
+                R"(
 %4 = OpTypeFloat 32
 %3 = OpTypeImage %4 3D 0 0 0 2 Rgba32f
 %2 = OpTypePointer UniformConstant %3
@@ -3658,93 +3658,89 @@
 %21 = OpConstant %4 7
 %22 = OpConstantComposite %17 %18 %19 %20 %21
 )",
-          R"(
+                R"(
 %10 = OpLoad %3 %1
 OpImageWrite %10 %16 %22
 )",
-          R"(
+                R"(
 )"};
-  }
+    }
 
-  return {"<unmatched texture overload>", "<unmatched texture overload>",
-          "<unmatched texture overload>"};
+    return {"<unmatched texture overload>", "<unmatched texture overload>",
+            "<unmatched texture overload>"};
 }  // NOLINT - Ignore the length of this function
 
-using BuiltinTextureTest =
-    TestParamHelper<ast::builtin::test::TextureOverloadCase>;
+using BuiltinTextureTest = TestParamHelper<ast::builtin::test::TextureOverloadCase>;
 
-INSTANTIATE_TEST_SUITE_P(
-    BuiltinTextureTest,
-    BuiltinTextureTest,
-    testing::ValuesIn(ast::builtin::test::TextureOverloadCase::ValidCases()));
+INSTANTIATE_TEST_SUITE_P(BuiltinTextureTest,
+                         BuiltinTextureTest,
+                         testing::ValuesIn(ast::builtin::test::TextureOverloadCase::ValidCases()));
 
 TEST_P(BuiltinTextureTest, Call) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* texture = param.BuildTextureVariable(this);
-  auto* sampler = param.BuildSamplerVariable(this);
+    auto* texture = param.BuildTextureVariable(this);
+    auto* sampler = param.BuildSamplerVariable(this);
 
-  auto* call = Call(param.function, param.args(this));
-  auto* stmt = CallStmt(call);
-  Func("func", {}, ty.void_(), {stmt}, {Stage(ast::PipelineStage::kFragment)});
+    auto* call = Call(param.function, param.args(this));
+    auto* stmt = CallStmt(call);
+    Func("func", {}, ty.void_(), {stmt}, {Stage(ast::PipelineStage::kFragment)});
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateGlobalVariable(texture)) << b.error();
-  ASSERT_TRUE(b.GenerateGlobalVariable(sampler)) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateGlobalVariable(texture)) << b.error();
+    ASSERT_TRUE(b.GenerateGlobalVariable(sampler)) << b.error();
 
-  EXPECT_EQ(b.GenerateExpression(call), 8u) << b.error();
+    EXPECT_EQ(b.GenerateExpression(call), 8u) << b.error();
 
-  auto expected = expected_texture_overload(param.overload);
-  EXPECT_EQ(expected.types, "\n" + DumpInstructions(b.types()));
-  EXPECT_EQ(expected.instructions,
-            "\n" + DumpInstructions(b.functions()[0].instructions()));
-  EXPECT_EQ(expected.capabilities, "\n" + DumpInstructions(b.capabilities()));
+    auto expected = expected_texture_overload(param.overload);
+    EXPECT_EQ(expected.types, "\n" + DumpInstructions(b.types()));
+    EXPECT_EQ(expected.instructions, "\n" + DumpInstructions(b.functions()[0].instructions()));
+    EXPECT_EQ(expected.capabilities, "\n" + DumpInstructions(b.capabilities()));
 }
 
 // Check the SPIRV generated passes validation
 TEST_P(BuiltinTextureTest, ValidateSPIRV) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  param.BuildTextureVariable(this);
-  param.BuildSamplerVariable(this);
+    param.BuildTextureVariable(this);
+    param.BuildSamplerVariable(this);
 
-  auto* call = Call(param.function, param.args(this));
+    auto* call = Call(param.function, param.args(this));
 
-  auto* stmt = CallStmt(call);
-  Func("main", {}, ty.void_(), {stmt}, {Stage(ast::PipelineStage::kFragment)});
+    auto* stmt = CallStmt(call);
+    Func("main", {}, ty.void_(), {stmt}, {Stage(ast::PipelineStage::kFragment)});
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.Build()) << b.error();
+    ASSERT_TRUE(b.Build()) << b.error();
 
-  Validate(b);
+    Validate(b);
 }
 
 TEST_P(BuiltinTextureTest, OutsideFunction_IsError) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  // The point of this test is to try to generate the texture
-  // builtin call outside a function.
+    // The point of this test is to try to generate the texture
+    // builtin call outside a function.
 
-  auto* texture = param.BuildTextureVariable(this);
-  auto* sampler = param.BuildSamplerVariable(this);
+    auto* texture = param.BuildTextureVariable(this);
+    auto* sampler = param.BuildSamplerVariable(this);
 
-  auto* call = Call(param.function, param.args(this));
-  auto* stmt = CallStmt(call);
-  Func("func", {}, ty.void_(), {stmt},
-       {create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
+    auto* call = Call(param.function, param.args(this));
+    auto* stmt = CallStmt(call);
+    Func("func", {}, ty.void_(), {stmt},
+         {create<ast::StageAttribute>(ast::PipelineStage::kFragment)});
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateGlobalVariable(texture)) << b.error();
-  ASSERT_TRUE(b.GenerateGlobalVariable(sampler)) << b.error();
-  EXPECT_EQ(b.GenerateExpression(call), 0u);
-  EXPECT_THAT(b.error(),
-              ::testing::StartsWith(
-                  "Internal error: trying to add SPIR-V instruction "));
-  EXPECT_THAT(b.error(), ::testing::EndsWith(" outside a function"));
+    ASSERT_TRUE(b.GenerateGlobalVariable(texture)) << b.error();
+    ASSERT_TRUE(b.GenerateGlobalVariable(sampler)) << b.error();
+    EXPECT_EQ(b.GenerateExpression(call), 0u);
+    EXPECT_THAT(b.error(),
+                ::testing::StartsWith("Internal error: trying to add SPIR-V instruction "));
+    EXPECT_THAT(b.error(), ::testing::EndsWith(" outside a function"));
 }
 
 }  // namespace
diff --git a/src/tint/writer/spirv/builder_call_test.cc b/src/tint/writer/spirv/builder_call_test.cc
index 77b169f..782b008 100644
--- a/src/tint/writer/spirv/builder_call_test.cc
+++ b/src/tint/writer/spirv/builder_call_test.cc
@@ -23,20 +23,19 @@
 using BuilderTest = TestHelper;
 
 TEST_F(BuilderTest, Expression_Call) {
-  ast::VariableList func_params;
-  func_params.push_back(Param("a", ty.f32()));
-  func_params.push_back(Param("b", ty.f32()));
+    ast::VariableList func_params;
+    func_params.push_back(Param("a", ty.f32()));
+    func_params.push_back(Param("b", ty.f32()));
 
-  auto* a_func = Func("a_func", func_params, ty.f32(), {Return(Add("a", "b"))});
-  auto* func =
-      Func("main", {}, ty.void_(), {Assign(Phony(), Call("a_func", 1.f, 1.f))});
+    auto* a_func = Func("a_func", func_params, ty.f32(), {Return(Add("a", "b"))});
+    auto* func = Func("main", {}, ty.void_(), {Assign(Phony(), Call("a_func", 1.f, 1.f))});
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(a_func)) << b.error();
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(a_func)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(OpName %3 "a_func"
+    EXPECT_EQ(DumpBuilder(b), R"(OpName %3 "a_func"
 OpName %4 "a"
 OpName %5 "b"
 OpName %10 "main"
@@ -61,21 +60,20 @@
 }
 
 TEST_F(BuilderTest, Statement_Call) {
-  ast::VariableList func_params;
-  func_params.push_back(Param("a", ty.f32()));
-  func_params.push_back(Param("b", ty.f32()));
+    ast::VariableList func_params;
+    func_params.push_back(Param("a", ty.f32()));
+    func_params.push_back(Param("b", ty.f32()));
 
-  auto* a_func = Func("a_func", func_params, ty.f32(), {Return(Add("a", "b"))});
+    auto* a_func = Func("a_func", func_params, ty.f32(), {Return(Add("a", "b"))});
 
-  auto* func =
-      Func("main", {}, ty.void_(), {CallStmt(Call("a_func", 1.f, 1.f))});
+    auto* func = Func("main", {}, ty.void_(), {CallStmt(Call("a_func", 1.f, 1.f))});
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(a_func)) << b.error();
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(a_func)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(OpName %3 "a_func"
+    EXPECT_EQ(DumpBuilder(b), R"(OpName %3 "a_func"
 OpName %4 "a"
 OpName %5 "b"
 OpName %10 "main"
diff --git a/src/tint/writer/spirv/builder_constructor_expression_test.cc b/src/tint/writer/spirv/builder_constructor_expression_test.cc
index 495f1c4..41409af 100644
--- a/src/tint/writer/spirv/builder_constructor_expression_test.cc
+++ b/src/tint/writer/spirv/builder_constructor_expression_test.cc
@@ -15,48 +15,50 @@
 #include "src/tint/writer/spirv/spv_dump.h"
 #include "src/tint/writer/spirv/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::spirv {
 namespace {
 
 using SpvBuilderConstructorTest = TestHelper;
 
 TEST_F(SpvBuilderConstructorTest, Const) {
-  auto* c = Expr(42.2f);
-  auto* g = Global("g", ty.f32(), c, ast::StorageClass::kPrivate);
+    auto* c = Expr(42.2f);
+    auto* g = Global("g", ty.f32(), c, ast::StorageClass::kPrivate);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_EQ(b.GenerateConstructorExpression(g, c), 2u);
-  ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(b.GenerateConstructorExpression(g, c), 2u);
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32
 %2 = OpConstant %1 42.2000008
 )");
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_WithCasts_OutsideFunction_IsError) {
-  auto* t = Construct<f32>(Construct<u32>(1));
-  WrapInFunction(t);
+    auto* t = Construct<f32>(Construct<u32>(1_i));
+    WrapInFunction(t);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_EQ(b.GenerateExpression(t), 0u);
-  EXPECT_TRUE(b.has_error()) << b.error();
-  EXPECT_EQ(b.error(),
-            "Internal error: trying to add SPIR-V instruction 124 outside a "
-            "function");
+    EXPECT_EQ(b.GenerateExpression(t), 0u);
+    EXPECT_TRUE(b.has_error()) << b.error();
+    EXPECT_EQ(b.error(),
+              "Internal error: trying to add SPIR-V instruction 124 outside a "
+              "function");
 }
 
 TEST_F(SpvBuilderConstructorTest, Type) {
-  auto* t = vec3<f32>(1.0f, 1.0f, 3.0f);
-  WrapInFunction(t);
+    auto* t = vec3<f32>(1.0f, 1.0f, 3.0f);
+    WrapInFunction(t);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_EQ(b.GenerateConstructorExpression(nullptr, t), 5u);
-  ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(b.GenerateConstructorExpression(nullptr, t), 5u);
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 3
 %3 = OpConstant %2 1
 %4 = OpConstant %2 3
@@ -65,257 +67,257 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_WithCasts) {
-  auto* t = vec2<f32>(Construct<f32>(1), Construct<f32>(1));
-  WrapInFunction(t);
+    auto* t = vec2<f32>(Construct<f32>(1_i), Construct<f32>(1_i));
+    WrapInFunction(t);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_EQ(b.GenerateExpression(t), 7u);
-  ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(b.GenerateExpression(t), 7u);
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 2
 %4 = OpTypeInt 32 1
 %5 = OpConstant %4 1
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%3 = OpConvertSToF %2 %5
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%3 = OpConvertSToF %2 %5
 %6 = OpConvertSToF %2 %5
 %7 = OpCompositeConstruct %1 %3 %6
 )");
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_WithAlias) {
-  // type Int = i32
-  // cast<Int>(2.3f)
+    // type Int = i32
+    // cast<Int>(2.3f)
 
-  auto* alias = Alias("Int", ty.i32());
-  auto* cast = Construct(ty.Of(alias), 2.3f);
-  WrapInFunction(cast);
+    auto* alias = Alias("Int", ty.i32());
+    auto* cast = Construct(ty.Of(alias), 2.3f);
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(cast), 1u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(cast), 1u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
 %3 = OpTypeFloat 32
 %4 = OpConstant %3 2.29999995
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%1 = OpConvertFToS %2 %4
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%1 = OpConvertFToS %2 %4
 )");
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_IdentifierExpression_Param) {
-  auto* var = Var("ident", ty.f32());
+    auto* var = Var("ident", ty.f32());
 
-  auto* t = vec2<f32>(1.0f, "ident");
-  WrapInFunction(var, t);
+    auto* t = vec2<f32>(1.0f, "ident");
+    WrapInFunction(var, t);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
 
-  EXPECT_EQ(b.GenerateExpression(t), 8u);
-  ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(b.GenerateExpression(t), 8u);
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
 %2 = OpTypePointer Function %3
 %4 = OpConstantNull %3
 %5 = OpTypeVector %3 2
 %6 = OpConstant %3 1
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-            R"(%1 = OpVariable %2 Function %4
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
+              R"(%1 = OpVariable %2 Function %4
 )");
 
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%7 = OpLoad %3 %1
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%7 = OpLoad %3 %1
 %8 = OpCompositeConstruct %5 %6 %7
 )");
 }
 
 TEST_F(SpvBuilderConstructorTest, Vector_Bitcast_Params) {
-  auto* t = vec2<u32>(Construct<u32>(1), Construct<u32>(1));
-  WrapInFunction(t);
+    auto* t = vec2<u32>(Construct<u32>(1_i), Construct<u32>(1_i));
+    WrapInFunction(t);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_EQ(b.GenerateExpression(t), 7u);
-  ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(b.GenerateExpression(t), 7u);
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 0
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 0
 %1 = OpTypeVector %2 2
 %4 = OpTypeInt 32 1
 %5 = OpConstant %4 1
 )");
 
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%3 = OpBitcast %2 %5
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%3 = OpBitcast %2 %5
 %6 = OpBitcast %2 %5
 %7 = OpCompositeConstruct %1 %3 %6
 )");
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Bool_With_Bool) {
-  auto* cast = Construct<bool>(true);
-  WrapInFunction(cast);
+    auto* cast = Construct<bool>(true);
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_EQ(b.GenerateExpression(cast), 3u);
-  ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(b.GenerateExpression(cast), 3u);
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeBool
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeBool
 %3 = OpConstantTrue %2
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_I32_With_I32) {
-  auto* cast = Construct<i32>(2);
-  WrapInFunction(cast);
+    auto* cast = Construct<i32>(2_i);
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(cast), 3u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(cast), 3u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
 %3 = OpConstant %2 2
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_U32_With_U32) {
-  auto* cast = Construct<u32>(2u);
-  WrapInFunction(cast);
+    auto* cast = Construct<u32>(2_u);
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(cast), 3u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(cast), 3u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 0
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 0
 %3 = OpConstant %2 2
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_F32_With_F32) {
-  auto* cast = Construct<f32>(2.0f);
-  WrapInFunction(cast);
+    auto* cast = Construct<f32>(2.0f);
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(cast), 3u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(cast), 3u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %3 = OpConstant %2 2
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_Bool_Literal) {
-  auto* cast = vec2<bool>(true);
-  WrapInFunction(cast);
+    auto* cast = vec2<bool>(true);
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(cast), 4u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(cast), 4u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeBool
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeBool
 %1 = OpTypeVector %2 2
 %3 = OpConstantTrue %2
 %4 = OpConstantComposite %1 %3 %3
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_Bool_Var) {
-  auto* var = Var("v", nullptr, Expr(true));
-  auto* cast = vec2<bool>(var);
-  WrapInFunction(var, cast);
+    auto* var = Var("v", nullptr, Expr(true));
+    auto* cast = vec2<bool>(var);
+    WrapInFunction(var, cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
-  ASSERT_EQ(b.GenerateExpression(cast), 8u) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+    ASSERT_EQ(b.GenerateExpression(cast), 8u) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeBool
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeBool
 %2 = OpConstantTrue %1
 %4 = OpTypePointer Function %1
 %5 = OpConstantNull %1
 %6 = OpTypeVector %1 2
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(OpStore %3 %2
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpStore %3 %2
 %7 = OpLoad %1 %3
 %8 = OpCompositeConstruct %6 %7 %7
 )");
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_F32_Literal) {
-  auto* cast = vec2<f32>(2.0f);
-  WrapInFunction(cast);
+    auto* cast = vec2<f32>(2.0f);
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(cast), 4u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(cast), 4u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 2
 %3 = OpConstant %2 2
 %4 = OpConstantComposite %1 %3 %3
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_F32_Var) {
-  auto* var = Var("v", nullptr, Expr(2.0f));
-  auto* cast = vec2<f32>(var);
-  WrapInFunction(var, cast);
+    auto* var = Var("v", nullptr, Expr(2.0f));
+    auto* cast = vec2<f32>(var);
+    WrapInFunction(var, cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
-  ASSERT_EQ(b.GenerateExpression(cast), 8u) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+    ASSERT_EQ(b.GenerateExpression(cast), 8u) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32
 %2 = OpConstant %1 2
 %4 = OpTypePointer Function %1
 %5 = OpConstantNull %1
 %6 = OpTypeVector %1 2
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %3 %2
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpStore %3 %2
 %7 = OpLoad %1 %3
 %8 = OpCompositeConstruct %6 %7 %7
 )");
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_F32_F32) {
-  auto* cast = vec2<f32>(2.0f, 2.0f);
-  WrapInFunction(cast);
+    auto* cast = vec2<f32>(2.0f, 2.0f);
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(cast), 4u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(cast), 4u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 2
 %3 = OpConstant %2 2
 %4 = OpConstantComposite %1 %3 %3
@@ -323,33 +325,33 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec2_With_Vec2) {
-  auto* value = vec2<f32>(2.0f, 2.0f);
-  auto* cast = vec2<f32>(value);
-  WrapInFunction(cast);
+    auto* value = vec2<f32>(2.0f, 2.0f);
+    auto* cast = vec2<f32>(value);
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(cast), 5u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(cast), 5u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
 %2 = OpTypeVector %3 2
 %4 = OpConstant %3 2
 %5 = OpConstantComposite %2 %4 %4
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F32) {
-  auto* cast = vec3<f32>(2.0f);
-  WrapInFunction(cast);
+    auto* cast = vec3<f32>(2.0f);
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(cast), 4u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(cast), 4u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 3
 %3 = OpConstant %2 2
 %4 = OpConstantComposite %1 %3 %3 %3
@@ -357,15 +359,15 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Bool) {
-  auto* cast = vec3<bool>(true);
-  WrapInFunction(cast);
+    auto* cast = vec3<bool>(true);
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(cast), 4u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(cast), 4u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeBool
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeBool
 %1 = OpTypeVector %2 3
 %3 = OpConstantTrue %2
 %4 = OpConstantComposite %1 %3 %3 %3
@@ -373,15 +375,15 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F32_F32_F32) {
-  auto* cast = vec3<f32>(2.0f, 2.0f, 2.0f);
-  WrapInFunction(cast);
+    auto* cast = vec3<f32>(2.0f, 2.0f, 2.0f);
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(cast), 4u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(cast), 4u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 3
 %3 = OpConstant %2 2
 %4 = OpConstantComposite %1 %3 %3 %3
@@ -389,77 +391,77 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_F32_Vec2) {
-  auto* cast = vec3<f32>(2.0f, vec2<f32>(2.0f, 2.0f));
-  WrapInFunction(cast);
+    auto* cast = vec3<f32>(2.0f, vec2<f32>(2.0f, 2.0f));
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(cast), 8u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(cast), 8u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 3
 %3 = OpConstant %2 2
 %4 = OpTypeVector %2 2
 %5 = OpConstantComposite %4 %3 %3
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%6 = OpCompositeExtract %2 %5 0
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%6 = OpCompositeExtract %2 %5 0
 %7 = OpCompositeExtract %2 %5 1
 %8 = OpCompositeConstruct %1 %3 %6 %7
 )");
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Vec2_F32) {
-  auto* cast = vec3<f32>(vec2<f32>(2.0f, 2.0f), 2.0f);
-  WrapInFunction(cast);
+    auto* cast = vec3<f32>(vec2<f32>(2.0f, 2.0f), 2.0f);
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(cast), 8u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(cast), 8u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 3
 %3 = OpTypeVector %2 2
 %4 = OpConstant %2 2
 %5 = OpConstantComposite %3 %4 %4
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%6 = OpCompositeExtract %2 %5 0
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%6 = OpCompositeExtract %2 %5 0
 %7 = OpCompositeExtract %2 %5 1
 %8 = OpCompositeConstruct %1 %6 %7 %4
 )");
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec3_With_Vec3) {
-  auto* value = vec3<f32>(2.0f, 2.0f, 2.0f);
-  auto* cast = vec3<f32>(value);
-  WrapInFunction(cast);
+    auto* value = vec3<f32>(2.0f, 2.0f, 2.0f);
+    auto* cast = vec3<f32>(value);
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(cast), 5u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(cast), 5u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
 %2 = OpTypeVector %3 3
 %4 = OpConstant %3 2
 %5 = OpConstantComposite %2 %4 %4 %4
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Bool) {
-  auto* cast = vec4<bool>(true);
-  WrapInFunction(cast);
+    auto* cast = vec4<bool>(true);
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(cast), 4u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(cast), 4u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeBool
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeBool
 %1 = OpTypeVector %2 4
 %3 = OpConstantTrue %2
 %4 = OpConstantComposite %1 %3 %3 %3 %3
@@ -467,15 +469,15 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32) {
-  auto* cast = vec4<f32>(2.0f);
-  WrapInFunction(cast);
+    auto* cast = vec4<f32>(2.0f);
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(cast), 4u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(cast), 4u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 4
 %3 = OpConstant %2 2
 %4 = OpConstantComposite %1 %3 %3 %3 %3
@@ -483,15 +485,15 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_F32_F32_F32) {
-  auto* cast = vec4<f32>(2.0f, 2.0f, 2.0f, 2.0f);
-  WrapInFunction(cast);
+    auto* cast = vec4<f32>(2.0f, 2.0f, 2.0f, 2.0f);
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(cast), 4u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(cast), 4u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 4
 %3 = OpConstant %2 2
 %4 = OpConstantComposite %1 %3 %3 %3 %3
@@ -499,88 +501,88 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_F32_Vec2) {
-  auto* cast = vec4<f32>(2.0f, 2.0f, vec2<f32>(2.0f, 2.0f));
-  WrapInFunction(cast);
+    auto* cast = vec4<f32>(2.0f, 2.0f, vec2<f32>(2.0f, 2.0f));
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(cast), 8u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(cast), 8u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 4
 %3 = OpConstant %2 2
 %4 = OpTypeVector %2 2
 %5 = OpConstantComposite %4 %3 %3
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%6 = OpCompositeExtract %2 %5 0
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%6 = OpCompositeExtract %2 %5 0
 %7 = OpCompositeExtract %2 %5 1
 %8 = OpCompositeConstruct %1 %3 %3 %6 %7
 )");
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_Vec2_F32) {
-  auto* cast = vec4<f32>(2.0f, vec2<f32>(2.0f, 2.0f), 2.0f);
-  WrapInFunction(cast);
+    auto* cast = vec4<f32>(2.0f, vec2<f32>(2.0f, 2.0f), 2.0f);
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(cast), 8u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(cast), 8u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 4
 %3 = OpConstant %2 2
 %4 = OpTypeVector %2 2
 %5 = OpConstantComposite %4 %3 %3
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%6 = OpCompositeExtract %2 %5 0
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%6 = OpCompositeExtract %2 %5 0
 %7 = OpCompositeExtract %2 %5 1
 %8 = OpCompositeConstruct %1 %3 %6 %7 %3
 )");
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec2_F32_F32) {
-  auto* cast = vec4<f32>(vec2<f32>(2.0f, 2.0f), 2.0f, 2.0f);
-  WrapInFunction(cast);
+    auto* cast = vec4<f32>(vec2<f32>(2.0f, 2.0f), 2.0f, 2.0f);
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(cast), 8u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(cast), 8u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 4
 %3 = OpTypeVector %2 2
 %4 = OpConstant %2 2
 %5 = OpConstantComposite %3 %4 %4
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%6 = OpCompositeExtract %2 %5 0
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%6 = OpCompositeExtract %2 %5 0
 %7 = OpCompositeExtract %2 %5 1
 %8 = OpCompositeConstruct %1 %6 %7 %4 %4
 )");
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec2_Vec2) {
-  auto* cast = vec4<f32>(vec2<f32>(2.0f, 2.0f), vec2<f32>(2.0f, 2.0f));
-  WrapInFunction(cast);
+    auto* cast = vec4<f32>(vec2<f32>(2.0f, 2.0f), vec2<f32>(2.0f, 2.0f));
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(cast), 10u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(cast), 10u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 4
 %3 = OpTypeVector %2 2
 %4 = OpConstant %2 2
 %5 = OpConstantComposite %3 %4 %4
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%6 = OpCompositeExtract %2 %5 0
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%6 = OpCompositeExtract %2 %5 0
 %7 = OpCompositeExtract %2 %5 1
 %8 = OpCompositeExtract %2 %5 0
 %9 = OpCompositeExtract %2 %5 1
@@ -589,22 +591,22 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_F32_Vec3) {
-  auto* cast = vec4<f32>(2.0f, vec3<f32>(2.0f, 2.0f, 2.0f));
-  WrapInFunction(cast);
+    auto* cast = vec4<f32>(2.0f, vec3<f32>(2.0f, 2.0f, 2.0f));
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(cast), 9u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(cast), 9u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 4
 %3 = OpConstant %2 2
 %4 = OpTypeVector %2 3
 %5 = OpConstantComposite %4 %3 %3 %3
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%6 = OpCompositeExtract %2 %5 0
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%6 = OpCompositeExtract %2 %5 0
 %7 = OpCompositeExtract %2 %5 1
 %8 = OpCompositeExtract %2 %5 2
 %9 = OpCompositeConstruct %1 %3 %6 %7 %8
@@ -612,22 +614,22 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec3_F32) {
-  auto* cast = vec4<f32>(vec3<f32>(2.0f, 2.0f, 2.0f), 2.0f);
-  WrapInFunction(cast);
+    auto* cast = vec4<f32>(vec3<f32>(2.0f, 2.0f, 2.0f), 2.0f);
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(cast), 9u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(cast), 9u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 4
 %3 = OpTypeVector %2 3
 %4 = OpConstant %2 2
 %5 = OpConstantComposite %3 %4 %4 %4
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%6 = OpCompositeExtract %2 %5 0
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%6 = OpCompositeExtract %2 %5 0
 %7 = OpCompositeExtract %2 %5 1
 %8 = OpCompositeExtract %2 %5 2
 %9 = OpCompositeConstruct %1 %6 %7 %8 %4
@@ -635,63 +637,63 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Vec4_With_Vec4) {
-  auto* value = vec4<f32>(2.0f, 2.0f, 2.0f, 2.0f);
-  auto* cast = vec4<f32>(value);
-  WrapInFunction(cast);
+    auto* value = vec4<f32>(2.0f, 2.0f, 2.0f, 2.0f);
+    auto* cast = vec4<f32>(value);
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(cast), 5u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(cast), 5u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
 %2 = OpTypeVector %3 4
 %4 = OpConstant %3 2
 %5 = OpConstantComposite %2 %4 %4 %4 %4
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"()");
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_F32_With_F32) {
-  auto* ctor = Construct<f32>(2.0f);
-  GlobalConst("g", ty.f32(), ctor);
+    auto* ctor = Construct<f32>(2.0f);
+    GlobalConst("g", ty.f32(), ctor);
 
-  spirv::Builder& b = SanitizeAndBuild();
-  ASSERT_TRUE(b.Build());
+    spirv::Builder& b = SanitizeAndBuild();
+    ASSERT_TRUE(b.Build());
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32
 %2 = OpConstant %1 2
 %4 = OpTypeVoid
 %3 = OpTypeFunction %4
 )");
-  Validate(b);
+    Validate(b);
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_U32_With_F32) {
-  auto* ctor = Construct<u32>(1.5f);
-  GlobalConst("g", ty.u32(), ctor);
+    auto* ctor = Construct<u32>(1.5f);
+    GlobalConst("g", ty.u32(), ctor);
 
-  spirv::Builder& b = SanitizeAndBuild();
-  ASSERT_TRUE(b.Build());
+    spirv::Builder& b = SanitizeAndBuild();
+    ASSERT_TRUE(b.Build());
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 0
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 0
 %2 = OpConstant %1 1
 %4 = OpTypeVoid
 %3 = OpTypeFunction %4
 )");
-  Validate(b);
+    Validate(b);
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec2_With_F32) {
-  auto* cast = vec2<f32>(2.0f);
-  auto* g = Global("g", ty.vec2<f32>(), cast, ast::StorageClass::kPrivate);
+    auto* cast = vec2<f32>(2.0f);
+    auto* g = Global("g", ty.vec2<f32>(), cast, ast::StorageClass::kPrivate);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 2
 %3 = OpConstant %2 2
 %4 = OpConstantComposite %1 %3 %3
@@ -699,13 +701,13 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec2_With_Vec2) {
-  auto* cast = vec2<f32>(vec2<f32>(2.0f, 2.0f));
-  GlobalConst("a", ty.vec2<f32>(), cast);
+    auto* cast = vec2<f32>(vec2<f32>(2.0f, 2.0f));
+    GlobalConst("a", ty.vec2<f32>(), cast);
 
-  spirv::Builder& b = SanitizeAndBuild();
-  ASSERT_TRUE(b.Build());
+    spirv::Builder& b = SanitizeAndBuild();
+    ASSERT_TRUE(b.Build());
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 2
 %3 = OpConstant %2 2
 %4 = OpConstantComposite %1 %3 %3
@@ -713,17 +715,17 @@
 %5 = OpTypeFunction %6
 )");
 
-  Validate(b);
+    Validate(b);
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec3_With_Vec3) {
-  auto* cast = vec3<f32>(vec3<f32>(2.0f, 2.0f, 2.0f));
-  GlobalConst("a", ty.vec3<f32>(), cast);
+    auto* cast = vec3<f32>(vec3<f32>(2.0f, 2.0f, 2.0f));
+    GlobalConst("a", ty.vec3<f32>(), cast);
 
-  spirv::Builder& b = SanitizeAndBuild();
-  ASSERT_TRUE(b.Build());
+    spirv::Builder& b = SanitizeAndBuild();
+    ASSERT_TRUE(b.Build());
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 3
 %3 = OpConstant %2 2
 %4 = OpConstantComposite %1 %3 %3 %3
@@ -731,17 +733,17 @@
 %5 = OpTypeFunction %6
 )");
 
-  Validate(b);
+    Validate(b);
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec4_With_Vec4) {
-  auto* cast = vec4<f32>(vec4<f32>(2.0f, 2.0f, 2.0f, 2.0f));
-  GlobalConst("a", ty.vec4<f32>(), cast);
+    auto* cast = vec4<f32>(vec4<f32>(2.0f, 2.0f, 2.0f, 2.0f));
+    GlobalConst("a", ty.vec4<f32>(), cast);
 
-  spirv::Builder& b = SanitizeAndBuild();
-  ASSERT_TRUE(b.Build());
+    spirv::Builder& b = SanitizeAndBuild();
+    ASSERT_TRUE(b.Build());
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 4
 %3 = OpConstant %2 2
 %4 = OpConstantComposite %1 %3 %3 %3 %3
@@ -749,19 +751,19 @@
 %5 = OpTypeFunction %6
 )");
 
-  Validate(b);
+    Validate(b);
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec3_With_F32) {
-  auto* cast = vec3<f32>(2.0f);
-  auto* g = Global("g", ty.vec3<f32>(), cast, ast::StorageClass::kPrivate);
+    auto* cast = vec3<f32>(2.0f);
+    auto* g = Global("g", ty.vec3<f32>(), cast, ast::StorageClass::kPrivate);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 3
 %3 = OpConstant %2 2
 %4 = OpConstantComposite %1 %3 %3 %3
@@ -769,15 +771,15 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec3_With_F32_Vec2) {
-  auto* cast = vec3<f32>(2.0f, vec2<f32>(2.0f, 2.0f));
-  auto* g = Global("g", ty.vec3<f32>(), cast, ast::StorageClass::kPrivate);
+    auto* cast = vec3<f32>(2.0f, vec2<f32>(2.0f, 2.0f));
+    auto* g = Global("g", ty.vec3<f32>(), cast, ast::StorageClass::kPrivate);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 11u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 11u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 3
 %3 = OpConstant %2 2
 %4 = OpTypeVector %2 2
@@ -792,15 +794,15 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec3_With_Vec2_F32) {
-  auto* cast = vec3<f32>(vec2<f32>(2.0f, 2.0f), 2.0f);
-  auto* g = Global("g", ty.vec3<f32>(), cast, ast::StorageClass::kPrivate);
+    auto* cast = vec3<f32>(vec2<f32>(2.0f, 2.0f), 2.0f);
+    auto* g = Global("g", ty.vec3<f32>(), cast, ast::StorageClass::kPrivate);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 11u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 11u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 3
 %3 = OpTypeVector %2 2
 %4 = OpConstant %2 2
@@ -815,15 +817,15 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec4_With_F32) {
-  auto* cast = vec4<f32>(2.0f);
-  auto* g = Global("g", ty.vec4<f32>(), cast, ast::StorageClass::kPrivate);
+    auto* cast = vec4<f32>(2.0f);
+    auto* g = Global("g", ty.vec4<f32>(), cast, ast::StorageClass::kPrivate);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 4u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 4
 %3 = OpConstant %2 2
 %4 = OpConstantComposite %1 %3 %3 %3 %3
@@ -831,15 +833,15 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec4_With_F32_F32_Vec2) {
-  auto* cast = vec4<f32>(2.0f, 2.0f, vec2<f32>(2.0f, 2.0f));
-  auto* g = Global("g", ty.vec4<f32>(), cast, ast::StorageClass::kPrivate);
+    auto* cast = vec4<f32>(2.0f, 2.0f, vec2<f32>(2.0f, 2.0f));
+    auto* g = Global("g", ty.vec4<f32>(), cast, ast::StorageClass::kPrivate);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 11u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 11u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 4
 %3 = OpConstant %2 2
 %4 = OpTypeVector %2 2
@@ -854,15 +856,15 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec4_With_F32_Vec2_F32) {
-  auto* cast = vec4<f32>(2.0f, vec2<f32>(2.0f, 2.0f), 2.0f);
-  auto* g = Global("g", ty.vec4<f32>(), cast, ast::StorageClass::kPrivate);
+    auto* cast = vec4<f32>(2.0f, vec2<f32>(2.0f, 2.0f), 2.0f);
+    auto* g = Global("g", ty.vec4<f32>(), cast, ast::StorageClass::kPrivate);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 11u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 11u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 4
 %3 = OpConstant %2 2
 %4 = OpTypeVector %2 2
@@ -877,15 +879,15 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec4_With_Vec2_F32_F32) {
-  auto* cast = vec4<f32>(vec2<f32>(2.0f, 2.0f), 2.0f, 2.0f);
-  auto* g = Global("g", ty.vec4<f32>(), cast, ast::StorageClass::kPrivate);
+    auto* cast = vec4<f32>(vec2<f32>(2.0f, 2.0f), 2.0f, 2.0f);
+    auto* g = Global("g", ty.vec4<f32>(), cast, ast::StorageClass::kPrivate);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 11u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 11u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 4
 %3 = OpTypeVector %2 2
 %4 = OpConstant %2 2
@@ -900,15 +902,15 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec4_With_Vec2_Vec2) {
-  auto* cast = vec4<f32>(vec2<f32>(2.0f, 2.0f), vec2<f32>(2.0f, 2.0f));
-  auto* g = Global("g", ty.vec4<f32>(), cast, ast::StorageClass::kPrivate);
+    auto* cast = vec4<f32>(vec2<f32>(2.0f, 2.0f), vec2<f32>(2.0f, 2.0f));
+    auto* g = Global("g", ty.vec4<f32>(), cast, ast::StorageClass::kPrivate);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 13u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 13u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 4
 %3 = OpTypeVector %2 2
 %4 = OpConstant %2 2
@@ -925,15 +927,15 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec4_With_F32_Vec3) {
-  auto* cast = vec4<f32>(2.0f, vec3<f32>(2.0f, 2.0f, 2.0f));
-  auto* g = Global("g", ty.vec4<f32>(), cast, ast::StorageClass::kPrivate);
+    auto* cast = vec4<f32>(2.0f, vec3<f32>(2.0f, 2.0f, 2.0f));
+    auto* g = Global("g", ty.vec4<f32>(), cast, ast::StorageClass::kPrivate);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 13u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 13u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 4
 %3 = OpConstant %2 2
 %4 = OpTypeVector %2 3
@@ -950,15 +952,15 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_ModuleScope_Vec4_With_Vec3_F32) {
-  auto* cast = vec4<f32>(vec3<f32>(2.0f, 2.0f, 2.0f), 2.0f);
-  auto* g = Global("g", ty.vec4<f32>(), cast, ast::StorageClass::kPrivate);
+    auto* cast = vec4<f32>(vec3<f32>(2.0f, 2.0f, 2.0f), 2.0f);
+    auto* g = Global("g", ty.vec4<f32>(), cast, ast::StorageClass::kPrivate);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 13u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateConstructorExpression(g, cast), 13u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 4
 %3 = OpTypeVector %2 3
 %4 = OpConstant %2 2
@@ -975,15 +977,15 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Mat2x2_With_Vec2_Vec2) {
-  auto* cast = mat2x2<f32>(vec2<f32>(2.0f, 2.0f), vec2<f32>(2.0f, 2.0f));
-  WrapInFunction(cast);
+    auto* cast = mat2x2<f32>(vec2<f32>(2.0f, 2.0f), vec2<f32>(2.0f, 2.0f));
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(cast), 6u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(cast), 6u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
 %2 = OpTypeVector %3 2
 %1 = OpTypeMatrix %2 2
 %4 = OpConstant %3 2
@@ -993,16 +995,15 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Mat3x2_With_Vec2_Vec2_Vec2) {
-  auto* cast = mat3x2<f32>(vec2<f32>(2.0f, 2.0f), vec2<f32>(2.0f, 2.0f),
-                           vec2<f32>(2.0f, 2.0f));
-  WrapInFunction(cast);
+    auto* cast = mat3x2<f32>(vec2<f32>(2.0f, 2.0f), vec2<f32>(2.0f, 2.0f), vec2<f32>(2.0f, 2.0f));
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(cast), 6u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(cast), 6u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
 %2 = OpTypeVector %3 2
 %1 = OpTypeMatrix %2 3
 %4 = OpConstant %3 2
@@ -1012,16 +1013,16 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Mat4x2_With_Vec2_Vec2_Vec2_Vec2) {
-  auto* cast = mat4x2<f32>(vec2<f32>(2.0f, 2.0f), vec2<f32>(2.0f, 2.0f),
-                           vec2<f32>(2.0f, 2.0f), vec2<f32>(2.0f, 2.0f));
-  WrapInFunction(cast);
+    auto* cast = mat4x2<f32>(vec2<f32>(2.0f, 2.0f), vec2<f32>(2.0f, 2.0f), vec2<f32>(2.0f, 2.0f),
+                             vec2<f32>(2.0f, 2.0f));
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(cast), 6u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(cast), 6u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
 %2 = OpTypeVector %3 2
 %1 = OpTypeMatrix %2 4
 %4 = OpConstant %3 2
@@ -1031,16 +1032,15 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Mat2x3_With_Vec3_Vec3) {
-  auto* cast =
-      mat2x3<f32>(vec3<f32>(2.0f, 2.0f, 2.0f), vec3<f32>(2.0f, 2.0f, 2.0f));
-  WrapInFunction(cast);
+    auto* cast = mat2x3<f32>(vec3<f32>(2.0f, 2.0f, 2.0f), vec3<f32>(2.0f, 2.0f, 2.0f));
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(cast), 6u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(cast), 6u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
 %2 = OpTypeVector %3 3
 %1 = OpTypeMatrix %2 2
 %4 = OpConstant %3 2
@@ -1050,17 +1050,16 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Mat3x3_With_Vec3_Vec3_Vec3) {
-  auto* cast =
-      mat3x3<f32>(vec3<f32>(2.0f, 2.0f, 2.0f), vec3<f32>(2.0f, 2.0f, 2.0f),
-                  vec3<f32>(2.0f, 2.0f, 2.0f));
-  WrapInFunction(cast);
+    auto* cast = mat3x3<f32>(vec3<f32>(2.0f, 2.0f, 2.0f), vec3<f32>(2.0f, 2.0f, 2.0f),
+                             vec3<f32>(2.0f, 2.0f, 2.0f));
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(cast), 6u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(cast), 6u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
 %2 = OpTypeVector %3 3
 %1 = OpTypeMatrix %2 3
 %4 = OpConstant %3 2
@@ -1070,17 +1069,16 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Mat4x3_With_Vec3_Vec3_Vec3_Vec3) {
-  auto* cast =
-      mat4x3<f32>(vec3<f32>(2.0f, 2.0f, 2.0f), vec3<f32>(2.0f, 2.0f, 2.0f),
-                  vec3<f32>(2.0f, 2.0f, 2.0f), vec3<f32>(2.0f, 2.0f, 2.0f));
-  WrapInFunction(cast);
+    auto* cast = mat4x3<f32>(vec3<f32>(2.0f, 2.0f, 2.0f), vec3<f32>(2.0f, 2.0f, 2.0f),
+                             vec3<f32>(2.0f, 2.0f, 2.0f), vec3<f32>(2.0f, 2.0f, 2.0f));
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(cast), 6u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(cast), 6u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
 %2 = OpTypeVector %3 3
 %1 = OpTypeMatrix %2 4
 %4 = OpConstant %3 2
@@ -1090,16 +1088,15 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Mat2x4_With_Vec4_Vec4) {
-  auto* cast = mat2x4<f32>(vec4<f32>(2.0f, 2.0f, 2.0f, 2.0f),
-                           vec4<f32>(2.0f, 2.0f, 2.0f, 2.0f));
-  WrapInFunction(cast);
+    auto* cast = mat2x4<f32>(vec4<f32>(2.0f, 2.0f, 2.0f, 2.0f), vec4<f32>(2.0f, 2.0f, 2.0f, 2.0f));
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(cast), 6u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(cast), 6u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
 %2 = OpTypeVector %3 4
 %1 = OpTypeMatrix %2 2
 %4 = OpConstant %3 2
@@ -1109,17 +1106,16 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Mat3x4_With_Vec4_Vec4_Vec4) {
-  auto* cast = mat3x4<f32>(vec4<f32>(2.0f, 2.0f, 2.0f, 2.0f),
-                           vec4<f32>(2.0f, 2.0f, 2.0f, 2.0f),
-                           vec4<f32>(2.0f, 2.0f, 2.0f, 2.0f));
-  WrapInFunction(cast);
+    auto* cast = mat3x4<f32>(vec4<f32>(2.0f, 2.0f, 2.0f, 2.0f), vec4<f32>(2.0f, 2.0f, 2.0f, 2.0f),
+                             vec4<f32>(2.0f, 2.0f, 2.0f, 2.0f));
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(cast), 6u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(cast), 6u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
 %2 = OpTypeVector %3 4
 %1 = OpTypeMatrix %2 3
 %4 = OpConstant %3 2
@@ -1129,17 +1125,16 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Mat4x4_With_Vec4_Vec4_Vec4_Vec4) {
-  auto* cast = mat4x4<f32>(
-      vec4<f32>(2.0f, 2.0f, 2.0f, 2.0f), vec4<f32>(2.0f, 2.0f, 2.0f, 2.0f),
-      vec4<f32>(2.0f, 2.0f, 2.0f, 2.0f), vec4<f32>(2.0f, 2.0f, 2.0f, 2.0f));
-  WrapInFunction(cast);
+    auto* cast = mat4x4<f32>(vec4<f32>(2.0f, 2.0f, 2.0f, 2.0f), vec4<f32>(2.0f, 2.0f, 2.0f, 2.0f),
+                             vec4<f32>(2.0f, 2.0f, 2.0f, 2.0f), vec4<f32>(2.0f, 2.0f, 2.0f, 2.0f));
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(cast), 6u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(cast), 6u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
 %2 = OpTypeVector %3 4
 %1 = OpTypeMatrix %2 4
 %4 = OpConstant %3 2
@@ -1149,15 +1144,15 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Array_5_F32) {
-  auto* cast = array<f32, 5>(2.0f, 2.0f, 2.0f, 2.0f, 2.0f);
-  WrapInFunction(cast);
+    auto* cast = array<f32, 5>(2.0f, 2.0f, 2.0f, 2.0f, 2.0f);
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(cast), 6u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(cast), 6u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %3 = OpTypeInt 32 0
 %4 = OpConstant %3 5
 %1 = OpTypeArray %2 %4
@@ -1167,15 +1162,15 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Array_2_Vec3) {
-  auto* first = vec3<f32>(1.f, 2.f, 3.f);
-  auto* second = vec3<f32>(1.f, 2.f, 3.f);
-  auto* t = Construct(ty.array(ty.vec3<f32>(), 2), first, second);
-  WrapInFunction(t);
-  spirv::Builder& b = Build();
+    auto* first = vec3<f32>(1.f, 2.f, 3.f);
+    auto* second = vec3<f32>(1.f, 2.f, 3.f);
+    auto* t = Construct(ty.array(ty.vec3<f32>(), 2_u), first, second);
+    WrapInFunction(t);
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(t), 10u);
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(t), 10u);
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
 %2 = OpTypeVector %3 3
 %4 = OpTypeInt 32 0
 %5 = OpConstant %4 2
@@ -1189,21 +1184,21 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, CommonInitializer_TwoVectors) {
-  auto* v1 = vec3<f32>(2.0f, 2.0f, 2.0f);
-  auto* v2 = vec3<f32>(2.0f, 2.0f, 2.0f);
-  ast::StatementList stmts = {
-      WrapInStatement(v1),
-      WrapInStatement(v2),
-  };
-  WrapInFunction(stmts);
+    auto* v1 = vec3<f32>(2.0f, 2.0f, 2.0f);
+    auto* v2 = vec3<f32>(2.0f, 2.0f, 2.0f);
+    ast::StatementList stmts = {
+        WrapInStatement(v1),
+        WrapInStatement(v2),
+    };
+    WrapInFunction(stmts);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(v1), 4u);
-  EXPECT_EQ(b.GenerateExpression(v2), 4u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(v1), 4u);
+    EXPECT_EQ(b.GenerateExpression(v2), 4u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 3
 %3 = OpConstant %2 2
 %4 = OpConstantComposite %1 %3 %3 %3
@@ -1211,21 +1206,21 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, CommonInitializer_TwoArrays) {
-  auto* a1 = array<f32, 3>(2.0f, 2.0f, 2.0f);
-  auto* a2 = array<f32, 3>(2.0f, 2.0f, 2.0f);
-  ast::StatementList stmts = {
-      WrapInStatement(a1),
-      WrapInStatement(a2),
-  };
-  WrapInFunction(stmts);
+    auto* a1 = array<f32, 3>(2.0f, 2.0f, 2.0f);
+    auto* a2 = array<f32, 3>(2.0f, 2.0f, 2.0f);
+    ast::StatementList stmts = {
+        WrapInStatement(a1),
+        WrapInStatement(a2),
+    };
+    WrapInFunction(stmts);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(a1), 6u);
-  EXPECT_EQ(b.GenerateExpression(a2), 6u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(a1), 6u);
+    EXPECT_EQ(b.GenerateExpression(a2), 6u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %3 = OpTypeInt 32 0
 %4 = OpConstant %3 3
 %1 = OpTypeArray %2 %4
@@ -1235,23 +1230,23 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, CommonInitializer_Array_VecArray) {
-  // Test that initializers of different types with the same values produce
-  // different OpConstantComposite instructions.
-  // crbug.com/tint/777
-  auto* a1 = array<f32, 2>(1.0f, 2.0f);
-  auto* a2 = vec2<f32>(1.0f, 2.0f);
-  ast::StatementList stmts = {
-      WrapInStatement(a1),
-      WrapInStatement(a2),
-  };
-  WrapInFunction(stmts);
-  spirv::Builder& b = Build();
+    // Test that initializers of different types with the same values produce
+    // different OpConstantComposite instructions.
+    // crbug.com/tint/777
+    auto* a1 = array<f32, 2>(1.0f, 2.0f);
+    auto* a2 = vec2<f32>(1.0f, 2.0f);
+    ast::StatementList stmts = {
+        WrapInStatement(a1),
+        WrapInStatement(a2),
+    };
+    WrapInFunction(stmts);
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(a1), 7u);
-  EXPECT_EQ(b.GenerateExpression(a2), 9u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(a1), 7u);
+    EXPECT_EQ(b.GenerateExpression(a2), 9u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %3 = OpTypeInt 32 0
 %4 = OpConstant %3 2
 %1 = OpTypeArray %2 %4
@@ -1264,22 +1259,22 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Struct) {
-  auto* s = Structure("my_struct", {
-                                       Member("a", ty.f32()),
-                                       Member("b", ty.vec3<f32>()),
-                                   });
+    auto* s = Structure("my_struct", {
+                                         Member("a", ty.f32()),
+                                         Member("b", ty.vec3<f32>()),
+                                     });
 
-  auto* t = Construct(ty.Of(s), 2.0f, vec3<f32>(2.0f, 2.0f, 2.0f));
-  WrapInFunction(t);
+    auto* t = Construct(ty.Of(s), 2.0f, vec3<f32>(2.0f, 2.0f, 2.0f));
+    WrapInFunction(t);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_EQ(b.GenerateExpression(t), 6u);
-  ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(b.GenerateExpression(t), 6u);
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %3 = OpTypeVector %2 3
 %1 = OpTypeStruct %2 %3
 %4 = OpConstant %2 2
@@ -1289,104 +1284,104 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_F32) {
-  auto* t = Construct<f32>();
+    auto* t = Construct<f32>();
 
-  WrapInFunction(t);
+    WrapInFunction(t);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_EQ(b.GenerateExpression(t), 2u);
-  ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(b.GenerateExpression(t), 2u);
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32
 %2 = OpConstantNull %1
 )");
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_I32) {
-  auto* t = Construct<i32>();
+    auto* t = Construct<i32>();
 
-  WrapInFunction(t);
+    WrapInFunction(t);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_EQ(b.GenerateExpression(t), 2u);
-  ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(b.GenerateExpression(t), 2u);
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 1
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 1
 %2 = OpConstantNull %1
 )");
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_U32) {
-  auto* t = Construct<u32>();
+    auto* t = Construct<u32>();
 
-  WrapInFunction(t);
+    WrapInFunction(t);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_EQ(b.GenerateExpression(t), 2u);
-  ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(b.GenerateExpression(t), 2u);
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 0
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 0
 %2 = OpConstantNull %1
 )");
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_Bool) {
-  auto* t = Construct<bool>();
+    auto* t = Construct<bool>();
 
-  WrapInFunction(t);
+    WrapInFunction(t);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_EQ(b.GenerateExpression(t), 2u);
-  ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(b.GenerateExpression(t), 2u);
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeBool
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeBool
 %2 = OpConstantNull %1
 )");
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_Vector) {
-  auto* t = vec2<i32>();
+    auto* t = vec2<i32>();
 
-  WrapInFunction(t);
+    WrapInFunction(t);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_EQ(b.GenerateExpression(t), 3u);
-  ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(b.GenerateExpression(t), 3u);
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
 %1 = OpTypeVector %2 2
 %3 = OpConstantNull %1
 )");
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_Matrix) {
-  auto* t = mat4x2<f32>();
+    auto* t = mat4x2<f32>();
 
-  WrapInFunction(t);
+    WrapInFunction(t);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_EQ(b.GenerateExpression(t), 4u);
-  ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(b.GenerateExpression(t), 4u);
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
 %2 = OpTypeVector %3 2
 %1 = OpTypeMatrix %2 4
 %4 = OpConstantNull %1
@@ -1394,18 +1389,18 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_Array) {
-  auto* t = array<i32, 2>();
+    auto* t = array<i32, 2>();
 
-  WrapInFunction(t);
+    WrapInFunction(t);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_EQ(b.GenerateExpression(t), 5u);
-  ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(b.GenerateExpression(t), 5u);
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
 %3 = OpTypeInt 32 0
 %4 = OpConstant %3 2
 %1 = OpTypeArray %2 %4
@@ -1414,144 +1409,144 @@
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_ZeroInit_Struct) {
-  auto* s = Structure("my_struct", {Member("a", ty.f32())});
-  auto* t = Construct(ty.Of(s));
-  WrapInFunction(t);
+    auto* s = Structure("my_struct", {Member("a", ty.f32())});
+    auto* t = Construct(ty.Of(s));
+    WrapInFunction(t);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_EQ(b.GenerateExpression(t), 3u);
-  ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(b.GenerateExpression(t), 3u);
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeStruct %2
 %3 = OpConstantNull %1
 )");
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Convert_U32_To_I32) {
-  auto* cast = Construct<i32>(2u);
-  WrapInFunction(cast);
+    auto* cast = Construct<i32>(2_u);
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(cast), 1u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(cast), 1u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
 %3 = OpTypeInt 32 0
 %4 = OpConstant %3 2
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%1 = OpBitcast %2 %4
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%1 = OpBitcast %2 %4
 )");
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Convert_I32_To_U32) {
-  auto* cast = Construct<u32>(2);
-  WrapInFunction(cast);
+    auto* cast = Construct<u32>(2_i);
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(cast), 1u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(cast), 1u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 0
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 0
 %3 = OpTypeInt 32 1
 %4 = OpConstant %3 2
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%1 = OpBitcast %2 %4
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%1 = OpBitcast %2 %4
 )");
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Convert_F32_To_I32) {
-  auto* cast = Construct<i32>(2.4f);
-  WrapInFunction(cast);
+    auto* cast = Construct<i32>(2.4f);
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(cast), 1u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(cast), 1u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
 %3 = OpTypeFloat 32
 %4 = OpConstant %3 2.4000001
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%1 = OpConvertFToS %2 %4
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%1 = OpConvertFToS %2 %4
 )");
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Convert_F32_To_U32) {
-  auto* cast = Construct<u32>(2.4f);
-  WrapInFunction(cast);
+    auto* cast = Construct<u32>(2.4f);
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(cast), 1u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(cast), 1u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 0
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 0
 %3 = OpTypeFloat 32
 %4 = OpConstant %3 2.4000001
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%1 = OpConvertFToU %2 %4
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%1 = OpConvertFToU %2 %4
 )");
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Convert_I32_To_F32) {
-  auto* cast = Construct<f32>(2);
-  WrapInFunction(cast);
+    auto* cast = Construct<f32>(2_i);
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(cast), 1u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(cast), 1u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %3 = OpTypeInt 32 1
 %4 = OpConstant %3 2
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%1 = OpConvertSToF %2 %4
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%1 = OpConvertSToF %2 %4
 )");
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Convert_U32_To_F32) {
-  auto* cast = Construct<f32>(2u);
-  WrapInFunction(cast);
+    auto* cast = Construct<f32>(2_u);
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateExpression(cast), 1u);
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateExpression(cast), 1u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %3 = OpTypeInt 32 0
 %4 = OpConstant %3 2
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%1 = OpConvertUToF %2 %4
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%1 = OpConvertUToF %2 %4
 )");
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_U32_to_I32) {
-  auto* var = Global("i", ty.vec3<u32>(), ast::StorageClass::kPrivate);
+    auto* var = Global("i", ty.vec3<u32>(), ast::StorageClass::kPrivate);
 
-  auto* cast = vec3<i32>("i");
-  WrapInFunction(cast);
+    auto* cast = vec3<i32>("i");
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
-  EXPECT_EQ(b.GenerateExpression(cast), 6u) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+    EXPECT_EQ(b.GenerateExpression(cast), 6u) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 0
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 0
 %3 = OpTypeVector %4 3
 %2 = OpTypePointer Private %3
 %5 = OpConstantNull %3
@@ -1559,25 +1554,25 @@
 %8 = OpTypeInt 32 1
 %7 = OpTypeVector %8 3
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%9 = OpLoad %3 %1
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%9 = OpLoad %3 %1
 %6 = OpBitcast %7 %9
 )");
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_F32_to_I32) {
-  auto* var = Global("i", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+    auto* var = Global("i", ty.vec3<f32>(), ast::StorageClass::kPrivate);
 
-  auto* cast = vec3<i32>("i");
-  WrapInFunction(cast);
+    auto* cast = vec3<i32>("i");
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
-  EXPECT_EQ(b.GenerateExpression(cast), 6u) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+    EXPECT_EQ(b.GenerateExpression(cast), 6u) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
 %3 = OpTypeVector %4 3
 %2 = OpTypePointer Private %3
 %5 = OpConstantNull %3
@@ -1585,25 +1580,25 @@
 %8 = OpTypeInt 32 1
 %7 = OpTypeVector %8 3
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%9 = OpLoad %3 %1
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%9 = OpLoad %3 %1
 %6 = OpConvertFToS %7 %9
 )");
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_I32_to_U32) {
-  auto* var = Global("i", ty.vec3<i32>(), ast::StorageClass::kPrivate);
+    auto* var = Global("i", ty.vec3<i32>(), ast::StorageClass::kPrivate);
 
-  auto* cast = vec3<u32>("i");
-  WrapInFunction(cast);
+    auto* cast = vec3<u32>("i");
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
-  EXPECT_EQ(b.GenerateExpression(cast), 6u) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+    EXPECT_EQ(b.GenerateExpression(cast), 6u) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 1
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 1
 %3 = OpTypeVector %4 3
 %2 = OpTypePointer Private %3
 %5 = OpConstantNull %3
@@ -1611,25 +1606,25 @@
 %8 = OpTypeInt 32 0
 %7 = OpTypeVector %8 3
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%9 = OpLoad %3 %1
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%9 = OpLoad %3 %1
 %6 = OpBitcast %7 %9
 )");
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_F32_to_U32) {
-  auto* var = Global("i", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+    auto* var = Global("i", ty.vec3<f32>(), ast::StorageClass::kPrivate);
 
-  auto* cast = vec3<u32>("i");
-  WrapInFunction(cast);
+    auto* cast = vec3<u32>("i");
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
-  EXPECT_EQ(b.GenerateExpression(cast), 6u) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+    EXPECT_EQ(b.GenerateExpression(cast), 6u) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
 %3 = OpTypeVector %4 3
 %2 = OpTypePointer Private %3
 %5 = OpConstantNull %3
@@ -1637,25 +1632,25 @@
 %8 = OpTypeInt 32 0
 %7 = OpTypeVector %8 3
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%9 = OpLoad %3 %1
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%9 = OpLoad %3 %1
 %6 = OpConvertFToU %7 %9
 )");
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_I32_to_F32) {
-  auto* var = Global("i", ty.vec3<i32>(), ast::StorageClass::kPrivate);
+    auto* var = Global("i", ty.vec3<i32>(), ast::StorageClass::kPrivate);
 
-  auto* cast = vec3<f32>("i");
-  WrapInFunction(cast);
+    auto* cast = vec3<f32>("i");
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
-  EXPECT_EQ(b.GenerateExpression(cast), 6u) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+    EXPECT_EQ(b.GenerateExpression(cast), 6u) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 1
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 1
 %3 = OpTypeVector %4 3
 %2 = OpTypePointer Private %3
 %5 = OpConstantNull %3
@@ -1663,25 +1658,25 @@
 %8 = OpTypeFloat 32
 %7 = OpTypeVector %8 3
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%9 = OpLoad %3 %1
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%9 = OpLoad %3 %1
 %6 = OpConvertSToF %7 %9
 )");
 }
 
 TEST_F(SpvBuilderConstructorTest, Type_Convert_Vectors_U32_to_F32) {
-  auto* var = Global("i", ty.vec3<u32>(), ast::StorageClass::kPrivate);
+    auto* var = Global("i", ty.vec3<u32>(), ast::StorageClass::kPrivate);
 
-  auto* cast = vec3<f32>("i");
-  WrapInFunction(cast);
+    auto* cast = vec3<f32>("i");
+    WrapInFunction(cast);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
-  EXPECT_EQ(b.GenerateExpression(cast), 6u) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+    EXPECT_EQ(b.GenerateExpression(cast), 6u) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 0
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 0
 %3 = OpTypeVector %4 3
 %2 = OpTypePointer Private %3
 %5 = OpConstantNull %3
@@ -1689,166 +1684,250 @@
 %8 = OpTypeFloat 32
 %7 = OpTypeVector %8 3
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%9 = OpLoad %3 %1
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%9 = OpLoad %3 %1
 %6 = OpConvertUToF %7 %9
 )");
 }
 
-TEST_F(SpvBuilderConstructorTest,
-       IsConstructorConst_GlobalVectorWithAllConstConstructors) {
-  // vec3<f32>(1.0, 2.0, 3.0)  -> true
-  auto* t = vec3<f32>(1.f, 2.f, 3.f);
-  WrapInFunction(t);
+TEST_F(SpvBuilderConstructorTest, IsConstructorConst_GlobalVectorWithAllConstConstructors) {
+    // vec3<f32>(1.0, 2.0, 3.0)  -> true
+    auto* t = vec3<f32>(1.f, 2.f, 3.f);
+    WrapInFunction(t);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_TRUE(b.IsConstructorConst(t));
-  EXPECT_FALSE(b.has_error());
+    EXPECT_TRUE(b.IsConstructorConst(t));
+    EXPECT_FALSE(b.has_error());
 }
 
-TEST_F(SpvBuilderConstructorTest,
-       IsConstructorConst_GlobalArrayWithAllConstConstructors) {
-  // array<vec3<f32>, 2>(vec3<f32>(1.0, 2.0, 3.0), vec3<f32>(1.0, 2.0, 3.0))
-  //   -> true
-  auto* t = Construct(ty.array(ty.vec3<f32>(), 2), vec3<f32>(1.f, 2.f, 3.f),
-                      vec3<f32>(1.f, 2.f, 3.f));
-  WrapInFunction(t);
+TEST_F(SpvBuilderConstructorTest, IsConstructorConst_GlobalArrayWithAllConstConstructors) {
+    // array<vec3<f32>, 2u>(vec3<f32>(1.0, 2.0, 3.0), vec3<f32>(1.0, 2.0, 3.0))
+    //   -> true
+    auto* t = Construct(ty.array(ty.vec3<f32>(), 2_u), vec3<f32>(1.f, 2.f, 3.f),
+                        vec3<f32>(1.f, 2.f, 3.f));
+    WrapInFunction(t);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_TRUE(b.IsConstructorConst(t));
-  EXPECT_FALSE(b.has_error());
+    EXPECT_TRUE(b.IsConstructorConst(t));
+    EXPECT_FALSE(b.has_error());
 }
 
-TEST_F(SpvBuilderConstructorTest,
-       IsConstructorConst_GlobalVectorWithMatchingTypeConstructors) {
-  // vec2<f32>(f32(1.0), f32(2.0))  -> false
+TEST_F(SpvBuilderConstructorTest, IsConstructorConst_GlobalVectorWithMatchingTypeConstructors) {
+    // vec2<f32>(f32(1.0), f32(2.0))  -> false
 
-  auto* t = vec2<f32>(Construct<f32>(1.f), Construct<f32>(2.f));
-  WrapInFunction(t);
+    auto* t = vec2<f32>(Construct<f32>(1.f), Construct<f32>(2.f));
+    WrapInFunction(t);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_TRUE(b.IsConstructorConst(t));
-  EXPECT_FALSE(b.has_error());
+    EXPECT_TRUE(b.IsConstructorConst(t));
+    EXPECT_FALSE(b.has_error());
 }
 
-TEST_F(SpvBuilderConstructorTest,
-       IsConstructorConst_GlobalWithTypeConversionConstructor) {
-  // vec2<f32>(f32(1), f32(2)) -> false
+TEST_F(SpvBuilderConstructorTest, IsConstructorConst_GlobalWithTypeConversionConstructor) {
+    // vec2<f32>(f32(1), f32(2)) -> false
 
-  auto* t = vec2<f32>(Construct<f32>(1), Construct<f32>(2));
-  WrapInFunction(t);
+    auto* t = vec2<f32>(Construct<f32>(1_i), Construct<f32>(2_i));
+    WrapInFunction(t);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_FALSE(b.IsConstructorConst(t));
-  EXPECT_FALSE(b.has_error());
+    EXPECT_FALSE(b.IsConstructorConst(t));
+    EXPECT_FALSE(b.has_error());
 }
 
-TEST_F(SpvBuilderConstructorTest,
-       IsConstructorConst_VectorWithAllConstConstructors) {
-  // vec3<f32>(1.0, 2.0, 3.0)  -> true
+TEST_F(SpvBuilderConstructorTest, IsConstructorConst_VectorWithAllConstConstructors) {
+    // vec3<f32>(1.0, 2.0, 3.0)  -> true
 
-  auto* t = vec3<f32>(1.f, 2.f, 3.f);
-  WrapInFunction(t);
+    auto* t = vec3<f32>(1.f, 2.f, 3.f);
+    WrapInFunction(t);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_TRUE(b.IsConstructorConst(t));
-  EXPECT_FALSE(b.has_error());
+    EXPECT_TRUE(b.IsConstructorConst(t));
+    EXPECT_FALSE(b.has_error());
 }
 
 TEST_F(SpvBuilderConstructorTest, IsConstructorConst_Vector_WithIdent) {
-  // vec3<f32>(a, b, c)  -> false
+    // vec3<f32>(a, b, c)  -> false
 
-  Global("a", ty.f32(), ast::StorageClass::kPrivate);
-  Global("b", ty.f32(), ast::StorageClass::kPrivate);
-  Global("c", ty.f32(), ast::StorageClass::kPrivate);
+    Global("a", ty.f32(), ast::StorageClass::kPrivate);
+    Global("b", ty.f32(), ast::StorageClass::kPrivate);
+    Global("c", ty.f32(), ast::StorageClass::kPrivate);
 
-  auto* t = vec3<f32>("a", "b", "c");
-  WrapInFunction(t);
+    auto* t = vec3<f32>("a", "b", "c");
+    WrapInFunction(t);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_FALSE(b.IsConstructorConst(t));
-  EXPECT_FALSE(b.has_error());
+    EXPECT_FALSE(b.IsConstructorConst(t));
+    EXPECT_FALSE(b.has_error());
 }
 
-TEST_F(SpvBuilderConstructorTest,
-       IsConstructorConst_ArrayWithAllConstConstructors) {
-  // array<vec3<f32>, 2>(vec3<f32>(1.0, 2.0, 3.0), vec3<f32>(1.0, 2.0, 3.0))
-  //   -> true
+TEST_F(SpvBuilderConstructorTest, IsConstructorConst_ArrayWithAllConstConstructors) {
+    // array<vec3<f32>, 2u>(vec3<f32>(1.0, 2.0, 3.0), vec3<f32>(1.0, 2.0, 3.0))
+    //   -> true
 
-  auto* first = vec3<f32>(1.f, 2.f, 3.f);
-  auto* second = vec3<f32>(1.f, 2.f, 3.f);
+    auto* first = vec3<f32>(1.f, 2.f, 3.f);
+    auto* second = vec3<f32>(1.f, 2.f, 3.f);
 
-  auto* t = Construct(ty.array(ty.vec3<f32>(), 2), first, second);
-  WrapInFunction(t);
+    auto* t = Construct(ty.array(ty.vec3<f32>(), 2_u), first, second);
+    WrapInFunction(t);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_TRUE(b.IsConstructorConst(t));
-  EXPECT_FALSE(b.has_error());
+    EXPECT_TRUE(b.IsConstructorConst(t));
+    EXPECT_FALSE(b.has_error());
 }
 
-TEST_F(SpvBuilderConstructorTest,
-       IsConstructorConst_VectorWithTypeConversionConstConstructors) {
-  // vec2<f32>(f32(1), f32(2))  -> false
+TEST_F(SpvBuilderConstructorTest, IsConstructorConst_VectorWithTypeConversionConstConstructors) {
+    // vec2<f32>(f32(1), f32(2))  -> false
 
-  auto* t = vec2<f32>(Construct<f32>(1), Construct<f32>(2));
-  WrapInFunction(t);
+    auto* t = vec2<f32>(Construct<f32>(1_i), Construct<f32>(2_i));
+    WrapInFunction(t);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_FALSE(b.IsConstructorConst(t));
-  EXPECT_FALSE(b.has_error());
+    EXPECT_FALSE(b.IsConstructorConst(t));
+    EXPECT_FALSE(b.has_error());
 }
 
 TEST_F(SpvBuilderConstructorTest, IsConstructorConst_BitCastScalars) {
-  auto* t = vec2<u32>(Construct<u32>(1), Construct<u32>(1));
-  WrapInFunction(t);
+    auto* t = vec2<u32>(Construct<u32>(1_i), Construct<u32>(1_i));
+    WrapInFunction(t);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_FALSE(b.IsConstructorConst(t));
-  EXPECT_FALSE(b.has_error());
+    EXPECT_FALSE(b.IsConstructorConst(t));
+    EXPECT_FALSE(b.has_error());
 }
 
 TEST_F(SpvBuilderConstructorTest, IsConstructorConst_Struct) {
-  auto* s = Structure("my_struct", {
-                                       Member("a", ty.f32()),
-                                       Member("b", ty.vec3<f32>()),
-                                   });
+    auto* s = Structure("my_struct", {
+                                         Member("a", ty.f32()),
+                                         Member("b", ty.vec3<f32>()),
+                                     });
 
-  auto* t = Construct(ty.Of(s), 2.f, vec3<f32>(2.f, 2.f, 2.f));
-  WrapInFunction(t);
+    auto* t = Construct(ty.Of(s), 2.f, vec3<f32>(2.f, 2.f, 2.f));
+    WrapInFunction(t);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_TRUE(b.IsConstructorConst(t));
-  EXPECT_FALSE(b.has_error());
+    EXPECT_TRUE(b.IsConstructorConst(t));
+    EXPECT_FALSE(b.has_error());
 }
 
-TEST_F(SpvBuilderConstructorTest,
-       IsConstructorConst_Struct_WithIdentSubExpression) {
-  auto* s = Structure("my_struct", {
-                                       Member("a", ty.f32()),
-                                       Member("b", ty.vec3<f32>()),
-                                   });
+TEST_F(SpvBuilderConstructorTest, IsConstructorConst_Struct_WithIdentSubExpression) {
+    auto* s = Structure("my_struct", {
+                                         Member("a", ty.f32()),
+                                         Member("b", ty.vec3<f32>()),
+                                     });
 
-  Global("a", ty.f32(), ast::StorageClass::kPrivate);
-  Global("b", ty.vec3<f32>(), ast::StorageClass::kPrivate);
+    Global("a", ty.f32(), ast::StorageClass::kPrivate);
+    Global("b", ty.vec3<f32>(), ast::StorageClass::kPrivate);
 
-  auto* t = Construct(ty.Of(s), "a", "b");
-  WrapInFunction(t);
+    auto* t = Construct(ty.Of(s), "a", "b");
+    WrapInFunction(t);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_FALSE(b.IsConstructorConst(t));
-  EXPECT_FALSE(b.has_error());
+    EXPECT_FALSE(b.IsConstructorConst(t));
+    EXPECT_FALSE(b.has_error());
 }
 
+TEST_F(SpvBuilderConstructorTest, ConstantCompositeScoping) {
+    // if (true) {
+    //    let x = vec3<f32>(1.0, 2.0, 3.0);
+    // }
+    // let y = vec3<f32>(1.0, 2.0, 3.0); // Reuses the ID 'x'
+
+    WrapInFunction(If(true, Block(Decl(Let("x", nullptr, vec3<f32>(1.f, 2.f, 3.f))))),
+                   Decl(Let("y", nullptr, vec3<f32>(1.f, 2.f, 3.f))));
+
+    spirv::Builder& b = SanitizeAndBuild();
+    ASSERT_TRUE(b.Build());
+
+    EXPECT_EQ(DumpBuilder(b), R"(OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %3 "test_function"
+OpExecutionMode %3 LocalSize 1 1 1
+OpName %3 "test_function"
+%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%5 = OpTypeBool
+%6 = OpConstantTrue %5
+%10 = OpTypeFloat 32
+%9 = OpTypeVector %10 3
+%11 = OpConstant %10 1
+%12 = OpConstant %10 2
+%13 = OpConstant %10 3
+%14 = OpConstantComposite %9 %11 %12 %13
+%3 = OpFunction %2 None %1
+%4 = OpLabel
+OpSelectionMerge %7 None
+OpBranchConditional %6 %8 %7
+%8 = OpLabel
+OpBranch %7
+%7 = OpLabel
+OpReturn
+OpFunctionEnd
+)");
+    Validate(b);
+}
+
+// TODO(crbug.com/tint/1155) Implement when overrides are fully implemented.
+// TEST_F(SpvBuilderConstructorTest, SpecConstantCompositeScoping)
+
+TEST_F(SpvBuilderConstructorTest, CompositeConstructScoping) {
+    // var one = 1.0;
+    // if (true) {
+    //    let x = vec3<f32>(one, 2.0, 3.0);
+    // }
+    // let y = vec3<f32>(one, 2.0, 3.0); // Mustn't reuse the ID 'x'
+
+    WrapInFunction(Decl(Var("one", nullptr, Expr(1.f))),
+                   If(true, Block(Decl(Let("x", nullptr, vec3<f32>("one", 2.f, 3.f))))),
+                   Decl(Let("y", nullptr, vec3<f32>("one", 2.f, 3.f))));
+
+    spirv::Builder& b = SanitizeAndBuild();
+    ASSERT_TRUE(b.Build());
+
+    EXPECT_EQ(DumpBuilder(b), R"(OpCapability Shader
+OpMemoryModel Logical GLSL450
+OpEntryPoint GLCompute %3 "test_function"
+OpExecutionMode %3 LocalSize 1 1 1
+OpName %3 "test_function"
+OpName %7 "one"
+%2 = OpTypeVoid
+%1 = OpTypeFunction %2
+%5 = OpTypeFloat 32
+%6 = OpConstant %5 1
+%8 = OpTypePointer Function %5
+%9 = OpConstantNull %5
+%10 = OpTypeBool
+%11 = OpConstantTrue %10
+%14 = OpTypeVector %5 3
+%16 = OpConstant %5 2
+%17 = OpConstant %5 3
+%3 = OpFunction %2 None %1
+%4 = OpLabel
+%7 = OpVariable %8 Function %9
+OpStore %7 %6
+OpSelectionMerge %12 None
+OpBranchConditional %11 %13 %12
+%13 = OpLabel
+%15 = OpLoad %5 %7
+%18 = OpCompositeConstruct %14 %15 %16 %17
+OpBranch %12
+%12 = OpLabel
+%19 = OpLoad %5 %7
+%20 = OpCompositeConstruct %14 %19 %16 %17
+OpReturn
+OpFunctionEnd
+)");
+    Validate(b);
+}
 }  // namespace
 }  // namespace tint::writer::spirv
diff --git a/src/tint/writer/spirv/builder_discard_test.cc b/src/tint/writer/spirv/builder_discard_test.cc
index baa566f..8c49abe 100644
--- a/src/tint/writer/spirv/builder_discard_test.cc
+++ b/src/tint/writer/spirv/builder_discard_test.cc
@@ -21,14 +21,14 @@
 using BuilderTest = TestHelper;
 
 TEST_F(BuilderTest, Discard) {
-  auto* expr = create<ast::DiscardStatement>();
-  WrapInFunction(expr);
+    auto* expr = create<ast::DiscardStatement>();
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_TRUE(b.GenerateStatement(expr)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpKill
+    b.push_function(Function{});
+    EXPECT_TRUE(b.GenerateStatement(expr)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpKill
 )");
 }
 
diff --git a/src/tint/writer/spirv/builder_entry_point_test.cc b/src/tint/writer/spirv/builder_entry_point_test.cc
index 23c5e67..a38bb8e 100644
--- a/src/tint/writer/spirv/builder_entry_point_test.cc
+++ b/src/tint/writer/spirv/builder_entry_point_test.cc
@@ -23,41 +23,42 @@
 #include "src/tint/ast/storage_class.h"
 #include "src/tint/ast/variable.h"
 #include "src/tint/program.h"
-#include "src/tint/sem/f32_type.h"
-#include "src/tint/sem/vector_type.h"
+#include "src/tint/sem/f32.h"
+#include "src/tint/sem/vector.h"
 #include "src/tint/writer/spirv/builder.h"
 #include "src/tint/writer/spirv/spv_dump.h"
 #include "src/tint/writer/spirv/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::spirv {
 namespace {
 
 using BuilderTest = TestHelper;
 
 TEST_F(BuilderTest, EntryPoint_Parameters) {
-  // @stage(fragment)
-  // fn frag_main(@builtin(position) coord : vec4<f32>,
-  //              @location(1) loc1 : f32) {
-  //   var col : f32 = (coord.x * loc1);
-  // }
-  auto* coord =
-      Param("coord", ty.vec4<f32>(), {Builtin(ast::Builtin::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);
-  Func("frag_main", ast::VariableList{coord, loc1}, ty.void_(),
-       ast::StatementList{WrapInStatement(col)},
-       ast::AttributeList{
-           Stage(ast::PipelineStage::kFragment),
-       });
+    // @stage(fragment)
+    // fn frag_main(@builtin(position) coord : vec4<f32>,
+    //              @location(1) loc1 : f32) {
+    //   var col : f32 = (coord.x * loc1);
+    // }
+    auto* coord = Param("coord", ty.vec4<f32>(), {Builtin(ast::Builtin::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);
+    Func("frag_main", ast::VariableList{coord, loc1}, ty.void_(),
+         ast::StatementList{WrapInStatement(col)},
+         ast::AttributeList{
+             Stage(ast::PipelineStage::kFragment),
+         });
 
-  spirv::Builder& b = SanitizeAndBuild();
+    spirv::Builder& b = SanitizeAndBuild();
 
-  ASSERT_TRUE(b.Build());
+    ASSERT_TRUE(b.Build());
 
-  // Test that "coord" and "loc1" get hoisted out to global variables with the
-  // Input storage class, retaining their decorations.
-  EXPECT_EQ(DumpBuilder(b), R"(OpCapability Shader
+    // Test that "coord" and "loc1" get hoisted out to global variables with the
+    // Input storage class, retaining their decorations.
+    EXPECT_EQ(DumpBuilder(b), R"(OpCapability Shader
 OpMemoryModel Logical GLSL450
 OpEntryPoint Fragment %19 "frag_main" %1 %5
 OpExecutionMode %19 OriginUpperLeft
@@ -100,38 +101,38 @@
 OpFunctionEnd
 )");
 
-  Validate(b);
+    Validate(b);
 }
 
 TEST_F(BuilderTest, EntryPoint_ReturnValue) {
-  // @stage(fragment)
-  // fn frag_main(@location(0) @interpolate(flat) loc_in : u32)
-  //     -> @location(0) f32 {
-  //   if (loc_in > 10) {
-  //     return 0.5;
-  //   }
-  //   return 1.0;
-  // }
-  auto* loc_in = Param("loc_in", ty.u32(), {Location(0), Flat()});
-  auto* cond = create<ast::BinaryExpression>(ast::BinaryOp::kGreaterThan,
-                                             Expr("loc_in"), Expr(10u));
-  Func("frag_main", ast::VariableList{loc_in}, ty.f32(),
-       ast::StatementList{
-           If(cond, Block(Return(0.5f))),
-           Return(1.0f),
-       },
-       ast::AttributeList{
-           Stage(ast::PipelineStage::kFragment),
-       },
-       ast::AttributeList{Location(0)});
+    // @stage(fragment)
+    // fn frag_main(@location(0) @interpolate(flat) loc_in : u32)
+    //     -> @location(0) f32 {
+    //   if (loc_in > 10) {
+    //     return 0.5;
+    //   }
+    //   return 1.0;
+    // }
+    auto* loc_in = Param("loc_in", ty.u32(), {Location(0), Flat()});
+    auto* cond =
+        create<ast::BinaryExpression>(ast::BinaryOp::kGreaterThan, Expr("loc_in"), Expr(10_u));
+    Func("frag_main", ast::VariableList{loc_in}, ty.f32(),
+         ast::StatementList{
+             If(cond, Block(Return(0.5f))),
+             Return(1.0f),
+         },
+         ast::AttributeList{
+             Stage(ast::PipelineStage::kFragment),
+         },
+         ast::AttributeList{Location(0)});
 
-  spirv::Builder& b = SanitizeAndBuild();
+    spirv::Builder& b = SanitizeAndBuild();
 
-  ASSERT_TRUE(b.Build());
+    ASSERT_TRUE(b.Build());
 
-  // Test that the return value gets hoisted out to a global variable with the
-  // Output storage class, and the return statements are replaced with stores.
-  EXPECT_EQ(DumpBuilder(b), R"(OpCapability Shader
+    // Test that the return value gets hoisted out to a global variable with the
+    // Output storage class, and the return statements are replaced with stores.
+    EXPECT_EQ(DumpBuilder(b), R"(OpCapability Shader
 OpMemoryModel Logical GLSL450
 OpEntryPoint Fragment %21 "frag_main" %1 %4
 OpExecutionMode %21 OriginUpperLeft
@@ -177,49 +178,46 @@
 OpFunctionEnd
 )");
 
-  Validate(b);
+    Validate(b);
 }
 
 TEST_F(BuilderTest, EntryPoint_SharedStruct) {
-  // struct Interface {
-  //   @location(1) value : f32;
-  //   @builtin(position) pos : vec4<f32>;
-  // };
-  //
-  // @stage(vertex)
-  // fn vert_main() -> Interface {
-  //   return Interface(42.0, vec4<f32>());
-  // }
-  //
-  // @stage(fragment)
-  // fn frag_main(inputs : Interface) -> @builtin(frag_depth) f32 {
-  //   return inputs.value;
-  // }
+    // struct Interface {
+    //   @location(1) value : f32;
+    //   @builtin(position) pos : vec4<f32>;
+    // };
+    //
+    // @stage(vertex)
+    // fn vert_main() -> Interface {
+    //   return Interface(42.0, vec4<f32>());
+    // }
+    //
+    // @stage(fragment)
+    // fn frag_main(inputs : Interface) -> @builtin(frag_depth) f32 {
+    //   return inputs.value;
+    // }
 
-  auto* interface = Structure(
-      "Interface",
-      {
-          Member("value", ty.f32(), ast::AttributeList{Location(1u)}),
-          Member("pos", ty.vec4<f32>(),
-                 ast::AttributeList{Builtin(ast::Builtin::kPosition)}),
-      });
+    auto* interface = Structure(
+        "Interface",
+        {
+            Member("value", ty.f32(), ast::AttributeList{Location(1u)}),
+            Member("pos", ty.vec4<f32>(), ast::AttributeList{Builtin(ast::Builtin::kPosition)}),
+        });
 
-  auto* vert_retval =
-      Construct(ty.Of(interface), 42.f, Construct(ty.vec4<f32>()));
-  Func("vert_main", ast::VariableList{}, ty.Of(interface),
-       {Return(vert_retval)}, {Stage(ast::PipelineStage::kVertex)});
+    auto* vert_retval = Construct(ty.Of(interface), 42.f, Construct(ty.vec4<f32>()));
+    Func("vert_main", ast::VariableList{}, ty.Of(interface), {Return(vert_retval)},
+         {Stage(ast::PipelineStage::kVertex)});
 
-  auto* frag_inputs = Param("inputs", ty.Of(interface));
-  Func("frag_main", ast::VariableList{frag_inputs}, ty.f32(),
-       {Return(MemberAccessor(Expr("inputs"), "value"))},
-       {Stage(ast::PipelineStage::kFragment)},
-       {Builtin(ast::Builtin::kFragDepth)});
+    auto* frag_inputs = Param("inputs", ty.Of(interface));
+    Func("frag_main", ast::VariableList{frag_inputs}, ty.f32(),
+         {Return(MemberAccessor(Expr("inputs"), "value"))}, {Stage(ast::PipelineStage::kFragment)},
+         {Builtin(ast::Builtin::kFragDepth)});
 
-  spirv::Builder& b = SanitizeAndBuild();
+    spirv::Builder& b = SanitizeAndBuild();
 
-  ASSERT_TRUE(b.Build()) << b.error();
+    ASSERT_TRUE(b.Build()) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(OpCapability Shader
+    EXPECT_EQ(DumpBuilder(b), R"(OpCapability Shader
 OpMemoryModel Logical GLSL450
 OpEntryPoint Vertex %23 "vert_main" %1 %5 %9
 OpEntryPoint Fragment %34 "frag_main" %10 %12 %14
@@ -300,23 +298,22 @@
 OpFunctionEnd
 )");
 
-  Validate(b);
+    Validate(b);
 }
 
 TEST_F(BuilderTest, SampleIndex_SampleRateShadingCapability) {
-  Func("main",
-       {Param("sample_index", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)})},
-       ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
+    Func("main", {Param("sample_index", ty.u32(), {Builtin(ast::Builtin::kSampleIndex)})},
+         ty.void_(), {}, {Stage(ast::PipelineStage::kFragment)});
 
-  spirv::Builder& b = SanitizeAndBuild();
+    spirv::Builder& b = SanitizeAndBuild();
 
-  ASSERT_TRUE(b.Build()) << b.error();
+    ASSERT_TRUE(b.Build()) << b.error();
 
-  // Make sure we generate the SampleRateShading capability.
-  EXPECT_EQ(DumpInstructions(b.capabilities()),
-            "OpCapability Shader\n"
-            "OpCapability SampleRateShading\n");
-  EXPECT_EQ(DumpInstructions(b.annots()), "OpDecorate %1 BuiltIn SampleId\n");
+    // Make sure we generate the SampleRateShading capability.
+    EXPECT_EQ(DumpInstructions(b.capabilities()),
+              "OpCapability Shader\n"
+              "OpCapability SampleRateShading\n");
+    EXPECT_EQ(DumpInstructions(b.annots()), "OpDecorate %1 BuiltIn SampleId\n");
 }
 
 }  // namespace
diff --git a/src/tint/writer/spirv/builder_format_conversion_test.cc b/src/tint/writer/spirv/builder_format_conversion_test.cc
index 396b5ac..dbb4f44 100644
--- a/src/tint/writer/spirv/builder_format_conversion_test.cc
+++ b/src/tint/writer/spirv/builder_format_conversion_test.cc
@@ -19,73 +19,72 @@
 namespace {
 
 struct TestData {
-  ast::TexelFormat ast_format;
-  SpvImageFormat_ spv_format;
-  bool extended_format = false;
+    ast::TexelFormat ast_format;
+    SpvImageFormat_ spv_format;
+    bool extended_format = false;
 };
 inline std::ostream& operator<<(std::ostream& out, TestData data) {
-  out << data.ast_format;
-  return out;
+    out << data.ast_format;
+    return out;
 }
 using ImageFormatConversionTest = TestParamHelper<TestData>;
 
 TEST_P(ImageFormatConversionTest, ImageFormatConversion) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_EQ(b.convert_texel_format_to_spv(param.ast_format), param.spv_format);
+    EXPECT_EQ(b.convert_texel_format_to_spv(param.ast_format), param.spv_format);
 
-  if (param.extended_format) {
-    EXPECT_EQ(DumpInstructions(b.capabilities()),
-              R"(OpCapability StorageImageExtendedFormats
+    if (param.extended_format) {
+        EXPECT_EQ(DumpInstructions(b.capabilities()),
+                  R"(OpCapability StorageImageExtendedFormats
 )");
-  } else {
-    EXPECT_EQ(DumpInstructions(b.capabilities()), "");
-  }
+    } else {
+        EXPECT_EQ(DumpInstructions(b.capabilities()), "");
+    }
 }
 
-INSTANTIATE_TEST_SUITE_P(
-    BuilderTest,
-    ImageFormatConversionTest,
-    testing::Values(
-        /* WGSL unsupported formats
-  TestData{ast::TexelFormat::kR8Unorm, SpvImageFormatR8, true},
-  TestData{ast::TexelFormat::kR8Snorm, SpvImageFormatR8Snorm, true},
-  TestData{ast::TexelFormat::kR8Uint, SpvImageFormatR8ui, true},
-  TestData{ast::TexelFormat::kR8Sint, SpvImageFormatR8i, true},
-  TestData{ast::TexelFormat::kR16Uint, SpvImageFormatR16ui, true},
-  TestData{ast::TexelFormat::kR16Sint, SpvImageFormatR16i, true},
-  TestData{ast::TexelFormat::kR16Float, SpvImageFormatR16f, true},
-  TestData{ast::TexelFormat::kRg8Unorm, SpvImageFormatRg8, true},
-  TestData{ast::TexelFormat::kRg8Snorm, SpvImageFormatRg8Snorm, true},
-  TestData{ast::TexelFormat::kRg8Uint, SpvImageFormatRg8ui, true},
-  TestData{ast::TexelFormat::kRg8Sint, SpvImageFormatRg8i, true},
-  TestData{ast::TexelFormat::kRg16Uint, SpvImageFormatRg16ui, true},
-  TestData{ast::TexelFormat::kRg16Sint, SpvImageFormatRg16i, true},
-  TestData{ast::TexelFormat::kRg16Float, SpvImageFormatRg16f, true},
-  TestData{ast::TexelFormat::kRgba8UnormSrgb, SpvImageFormatUnknown},
-  TestData{ast::TexelFormat::kBgra8Unorm, SpvImageFormatUnknown},
-  TestData{ast::TexelFormat::kBgra8UnormSrgb, SpvImageFormatUnknown},
-  TestData{ast::TexelFormat::kRgb10A2Unorm, SpvImageFormatRgb10A2, true},
-  TestData{ast::TexelFormat::kRg11B10Float, SpvImageFormatR11fG11fB10f, true},
-*/
-        TestData{ast::TexelFormat::kR32Uint, SpvImageFormatR32ui},
-        TestData{ast::TexelFormat::kR32Sint, SpvImageFormatR32i},
-        TestData{ast::TexelFormat::kR32Float, SpvImageFormatR32f},
-        TestData{ast::TexelFormat::kRgba8Unorm, SpvImageFormatRgba8},
-        TestData{ast::TexelFormat::kRgba8Snorm, SpvImageFormatRgba8Snorm},
-        TestData{ast::TexelFormat::kRgba8Uint, SpvImageFormatRgba8ui},
-        TestData{ast::TexelFormat::kRgba8Sint, SpvImageFormatRgba8i},
-        TestData{ast::TexelFormat::kRg32Uint, SpvImageFormatRg32ui, true},
-        TestData{ast::TexelFormat::kRg32Sint, SpvImageFormatRg32i, true},
-        TestData{ast::TexelFormat::kRg32Float, SpvImageFormatRg32f, true},
-        TestData{ast::TexelFormat::kRgba16Uint, SpvImageFormatRgba16ui},
-        TestData{ast::TexelFormat::kRgba16Sint, SpvImageFormatRgba16i},
-        TestData{ast::TexelFormat::kRgba16Float, SpvImageFormatRgba16f},
-        TestData{ast::TexelFormat::kRgba32Uint, SpvImageFormatRgba32ui},
-        TestData{ast::TexelFormat::kRgba32Sint, SpvImageFormatRgba32i},
-        TestData{ast::TexelFormat::kRgba32Float, SpvImageFormatRgba32f}));
+INSTANTIATE_TEST_SUITE_P(BuilderTest,
+                         ImageFormatConversionTest,
+                         testing::Values(
+                             /* WGSL unsupported formats
+                       TestData{ast::TexelFormat::kR8Unorm, SpvImageFormatR8, true},
+                       TestData{ast::TexelFormat::kR8Snorm, SpvImageFormatR8Snorm, true},
+                       TestData{ast::TexelFormat::kR8Uint, SpvImageFormatR8ui, true},
+                       TestData{ast::TexelFormat::kR8Sint, SpvImageFormatR8i, true},
+                       TestData{ast::TexelFormat::kR16Uint, SpvImageFormatR16ui, true},
+                       TestData{ast::TexelFormat::kR16Sint, SpvImageFormatR16i, true},
+                       TestData{ast::TexelFormat::kR16Float, SpvImageFormatR16f, true},
+                       TestData{ast::TexelFormat::kRg8Unorm, SpvImageFormatRg8, true},
+                       TestData{ast::TexelFormat::kRg8Snorm, SpvImageFormatRg8Snorm, true},
+                       TestData{ast::TexelFormat::kRg8Uint, SpvImageFormatRg8ui, true},
+                       TestData{ast::TexelFormat::kRg8Sint, SpvImageFormatRg8i, true},
+                       TestData{ast::TexelFormat::kRg16Uint, SpvImageFormatRg16ui, true},
+                       TestData{ast::TexelFormat::kRg16Sint, SpvImageFormatRg16i, true},
+                       TestData{ast::TexelFormat::kRg16Float, SpvImageFormatRg16f, true},
+                       TestData{ast::TexelFormat::kRgba8UnormSrgb, SpvImageFormatUnknown},
+                       TestData{ast::TexelFormat::kBgra8Unorm, SpvImageFormatUnknown},
+                       TestData{ast::TexelFormat::kBgra8UnormSrgb, SpvImageFormatUnknown},
+                       TestData{ast::TexelFormat::kRgb10A2Unorm, SpvImageFormatRgb10A2, true},
+                       TestData{ast::TexelFormat::kRg11B10Float, SpvImageFormatR11fG11fB10f, true},
+                     */
+                             TestData{ast::TexelFormat::kR32Uint, SpvImageFormatR32ui},
+                             TestData{ast::TexelFormat::kR32Sint, SpvImageFormatR32i},
+                             TestData{ast::TexelFormat::kR32Float, SpvImageFormatR32f},
+                             TestData{ast::TexelFormat::kRgba8Unorm, SpvImageFormatRgba8},
+                             TestData{ast::TexelFormat::kRgba8Snorm, SpvImageFormatRgba8Snorm},
+                             TestData{ast::TexelFormat::kRgba8Uint, SpvImageFormatRgba8ui},
+                             TestData{ast::TexelFormat::kRgba8Sint, SpvImageFormatRgba8i},
+                             TestData{ast::TexelFormat::kRg32Uint, SpvImageFormatRg32ui, true},
+                             TestData{ast::TexelFormat::kRg32Sint, SpvImageFormatRg32i, true},
+                             TestData{ast::TexelFormat::kRg32Float, SpvImageFormatRg32f, true},
+                             TestData{ast::TexelFormat::kRgba16Uint, SpvImageFormatRgba16ui},
+                             TestData{ast::TexelFormat::kRgba16Sint, SpvImageFormatRgba16i},
+                             TestData{ast::TexelFormat::kRgba16Float, SpvImageFormatRgba16f},
+                             TestData{ast::TexelFormat::kRgba32Uint, SpvImageFormatRgba32ui},
+                             TestData{ast::TexelFormat::kRgba32Sint, SpvImageFormatRgba32i},
+                             TestData{ast::TexelFormat::kRgba32Float, SpvImageFormatRgba32f}));
 
 }  // namespace
 }  // namespace tint::writer::spirv
diff --git a/src/tint/writer/spirv/builder_function_attribute_test.cc b/src/tint/writer/spirv/builder_function_attribute_test.cc
index 8a9e82a..f4fdf6e 100644
--- a/src/tint/writer/spirv/builder_function_attribute_test.cc
+++ b/src/tint/writer/spirv/builder_function_attribute_test.cc
@@ -17,165 +17,162 @@
 #include "src/tint/writer/spirv/spv_dump.h"
 #include "src/tint/writer/spirv/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::spirv {
 namespace {
 
 using BuilderTest = TestHelper;
 
 TEST_F(BuilderTest, Attribute_Stage) {
-  auto* func = Func("main", {}, ty.void_(), ast::StatementList{},
-                    ast::AttributeList{
-                        Stage(ast::PipelineStage::kFragment),
-                    });
+    auto* func = Func("main", {}, ty.void_(), ast::StatementList{},
+                      ast::AttributeList{
+                          Stage(ast::PipelineStage::kFragment),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.entry_points()),
-            R"(OpEntryPoint Fragment %3 "main"
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.entry_points()),
+              R"(OpEntryPoint Fragment %3 "main"
 )");
 }
 
 struct FunctionStageData {
-  ast::PipelineStage stage;
-  SpvExecutionModel model;
+    ast::PipelineStage stage;
+    SpvExecutionModel model;
 };
 inline std::ostream& operator<<(std::ostream& out, FunctionStageData data) {
-  out << data.stage;
-  return out;
+    out << data.stage;
+    return out;
 }
 using Attribute_StageTest = TestParamHelper<FunctionStageData>;
 TEST_P(Attribute_StageTest, Emit) {
-  auto params = GetParam();
+    auto params = GetParam();
 
-  const ast::Variable* var = nullptr;
-  const ast::Type* ret_type = nullptr;
-  ast::AttributeList ret_type_attrs;
-  ast::StatementList body;
-  if (params.stage == ast::PipelineStage::kVertex) {
-    ret_type = ty.vec4<f32>();
-    ret_type_attrs.push_back(Builtin(ast::Builtin::kPosition));
-    body.push_back(Return(Construct(ty.vec4<f32>())));
-  } else {
-    ret_type = ty.void_();
-  }
+    const ast::Variable* var = nullptr;
+    const ast::Type* ret_type = nullptr;
+    ast::AttributeList ret_type_attrs;
+    ast::StatementList body;
+    if (params.stage == ast::PipelineStage::kVertex) {
+        ret_type = ty.vec4<f32>();
+        ret_type_attrs.push_back(Builtin(ast::Builtin::kPosition));
+        body.push_back(Return(Construct(ty.vec4<f32>())));
+    } else {
+        ret_type = ty.void_();
+    }
 
-  auto deco_list = ast::AttributeList{Stage(params.stage)};
-  if (params.stage == ast::PipelineStage::kCompute) {
-    deco_list.push_back(WorkgroupSize(1));
-  }
+    auto deco_list = ast::AttributeList{Stage(params.stage)};
+    if (params.stage == ast::PipelineStage::kCompute) {
+        deco_list.push_back(WorkgroupSize(1_i));
+    }
 
-  auto* func = Func("main", {}, ret_type, body, deco_list, ret_type_attrs);
+    auto* func = Func("main", {}, ret_type, body, deco_list, ret_type_attrs);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  if (var) {
-    ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
-  }
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    if (var) {
+        ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+    }
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  auto preamble = b.entry_points();
-  ASSERT_GE(preamble.size(), 1u);
-  EXPECT_EQ(preamble[0].opcode(), spv::Op::OpEntryPoint);
+    auto preamble = b.entry_points();
+    ASSERT_GE(preamble.size(), 1u);
+    EXPECT_EQ(preamble[0].opcode(), spv::Op::OpEntryPoint);
 
-  ASSERT_GE(preamble[0].operands().size(), 3u);
-  EXPECT_EQ(preamble[0].operands()[0].to_i(),
-            static_cast<uint32_t>(params.model));
+    ASSERT_GE(preamble[0].operands().size(), 3u);
+    EXPECT_EQ(std::get<uint32_t>(preamble[0].operands()[0]), static_cast<uint32_t>(params.model));
 }
 INSTANTIATE_TEST_SUITE_P(
     BuilderTest,
     Attribute_StageTest,
-    testing::Values(FunctionStageData{ast::PipelineStage::kVertex,
-                                      SpvExecutionModelVertex},
-                    FunctionStageData{ast::PipelineStage::kFragment,
-                                      SpvExecutionModelFragment},
-                    FunctionStageData{ast::PipelineStage::kCompute,
-                                      SpvExecutionModelGLCompute}));
+    testing::Values(FunctionStageData{ast::PipelineStage::kVertex, SpvExecutionModelVertex},
+                    FunctionStageData{ast::PipelineStage::kFragment, SpvExecutionModelFragment},
+                    FunctionStageData{ast::PipelineStage::kCompute, SpvExecutionModelGLCompute}));
 
 TEST_F(BuilderTest, Decoration_ExecutionMode_Fragment_OriginUpperLeft) {
-  auto* func = Func("main", {}, ty.void_(), ast::StatementList{},
-                    ast::AttributeList{
-                        Stage(ast::PipelineStage::kFragment),
-                    });
+    auto* func = Func("main", {}, ty.void_(), ast::StatementList{},
+                      ast::AttributeList{
+                          Stage(ast::PipelineStage::kFragment),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateExecutionModes(func, 3)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.execution_modes()),
-            R"(OpExecutionMode %3 OriginUpperLeft
+    ASSERT_TRUE(b.GenerateExecutionModes(func, 3)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.execution_modes()),
+              R"(OpExecutionMode %3 OriginUpperLeft
 )");
 }
 
 TEST_F(BuilderTest, Decoration_ExecutionMode_WorkgroupSize_Default) {
-  auto* func = Func("main", {}, ty.void_(), ast::StatementList{},
-                    ast::AttributeList{Stage(ast::PipelineStage::kCompute),
-                                       WorkgroupSize(1)});
+    auto* func = Func("main", {}, ty.void_(), ast::StatementList{},
+                      ast::AttributeList{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateExecutionModes(func, 3)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.execution_modes()),
-            R"(OpExecutionMode %3 LocalSize 1 1 1
+    ASSERT_TRUE(b.GenerateExecutionModes(func, 3)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.execution_modes()),
+              R"(OpExecutionMode %3 LocalSize 1 1 1
 )");
 }
 
 TEST_F(BuilderTest, Decoration_ExecutionMode_WorkgroupSize_Literals) {
-  auto* func = Func("main", {}, ty.void_(), ast::StatementList{},
-                    ast::AttributeList{
-                        WorkgroupSize(2, 4, 6),
-                        Stage(ast::PipelineStage::kCompute),
-                    });
+    auto* func = Func("main", {}, ty.void_(), ast::StatementList{},
+                      ast::AttributeList{
+                          WorkgroupSize(2_i, 4_i, 6_i),
+                          Stage(ast::PipelineStage::kCompute),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateExecutionModes(func, 3)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.execution_modes()),
-            R"(OpExecutionMode %3 LocalSize 2 4 6
+    ASSERT_TRUE(b.GenerateExecutionModes(func, 3)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.execution_modes()),
+              R"(OpExecutionMode %3 LocalSize 2 4 6
 )");
 }
 
 TEST_F(BuilderTest, Decoration_ExecutionMode_WorkgroupSize_Const) {
-  GlobalConst("width", ty.i32(), Construct(ty.i32(), 2));
-  GlobalConst("height", ty.i32(), Construct(ty.i32(), 3));
-  GlobalConst("depth", ty.i32(), Construct(ty.i32(), 4));
-  auto* func = Func("main", {}, ty.void_(), ast::StatementList{},
-                    ast::AttributeList{
-                        WorkgroupSize("width", "height", "depth"),
-                        Stage(ast::PipelineStage::kCompute),
-                    });
+    GlobalConst("width", ty.i32(), Construct(ty.i32(), 2_i));
+    GlobalConst("height", ty.i32(), Construct(ty.i32(), 3_i));
+    GlobalConst("depth", ty.i32(), Construct(ty.i32(), 4_i));
+    auto* func = Func("main", {}, ty.void_(), ast::StatementList{},
+                      ast::AttributeList{
+                          WorkgroupSize("width", "height", "depth"),
+                          Stage(ast::PipelineStage::kCompute),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateExecutionModes(func, 3)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.execution_modes()),
-            R"(OpExecutionMode %3 LocalSize 2 3 4
+    ASSERT_TRUE(b.GenerateExecutionModes(func, 3)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.execution_modes()),
+              R"(OpExecutionMode %3 LocalSize 2 3 4
 )");
 }
 
 TEST_F(BuilderTest, Decoration_ExecutionMode_WorkgroupSize_OverridableConst) {
-  Override("width", ty.i32(), Construct(ty.i32(), 2), {Id(7u)});
-  Override("height", ty.i32(), Construct(ty.i32(), 3), {Id(8u)});
-  Override("depth", ty.i32(), Construct(ty.i32(), 4), {Id(9u)});
-  auto* func = Func("main", {}, ty.void_(), ast::StatementList{},
-                    ast::AttributeList{
-                        WorkgroupSize("width", "height", "depth"),
-                        Stage(ast::PipelineStage::kCompute),
-                    });
+    Override("width", ty.i32(), Construct(ty.i32(), 2_i), {Id(7u)});
+    Override("height", ty.i32(), Construct(ty.i32(), 3_i), {Id(8u)});
+    Override("depth", ty.i32(), Construct(ty.i32(), 4_i), {Id(9u)});
+    auto* func = Func("main", {}, ty.void_(), ast::StatementList{},
+                      ast::AttributeList{
+                          WorkgroupSize("width", "height", "depth"),
+                          Stage(ast::PipelineStage::kCompute),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateExecutionModes(func, 3)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.execution_modes()), "");
-  EXPECT_EQ(DumpInstructions(b.types()),
-            R"(%2 = OpTypeInt 32 0
+    ASSERT_TRUE(b.GenerateExecutionModes(func, 3)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.execution_modes()), "");
+    EXPECT_EQ(DumpInstructions(b.types()),
+              R"(%2 = OpTypeInt 32 0
 %1 = OpTypeVector %2 3
 %4 = OpSpecConstant %2 2
 %5 = OpSpecConstant %2 3
 %6 = OpSpecConstant %2 4
 %3 = OpSpecConstantComposite %1 %4 %5 %6
 )");
-  EXPECT_EQ(DumpInstructions(b.annots()),
-            R"(OpDecorate %4 SpecId 7
+    EXPECT_EQ(DumpInstructions(b.annots()),
+              R"(OpDecorate %4 SpecId 7
 OpDecorate %5 SpecId 8
 OpDecorate %6 SpecId 9
 OpDecorate %3 BuiltIn WorkgroupSize
@@ -183,49 +180,49 @@
 }
 
 TEST_F(BuilderTest, Decoration_ExecutionMode_WorkgroupSize_LiteralAndConst) {
-  Override("height", ty.i32(), Construct(ty.i32(), 2), {Id(7u)});
-  GlobalConst("depth", ty.i32(), Construct(ty.i32(), 3));
-  auto* func = Func("main", {}, ty.void_(), ast::StatementList{},
-                    ast::AttributeList{
-                        WorkgroupSize(4, "height", "depth"),
-                        Stage(ast::PipelineStage::kCompute),
-                    });
+    Override("height", ty.i32(), Construct(ty.i32(), 2_i), {Id(7u)});
+    GlobalConst("depth", ty.i32(), Construct(ty.i32(), 3_i));
+    auto* func = Func("main", {}, ty.void_(), ast::StatementList{},
+                      ast::AttributeList{
+                          WorkgroupSize(4_i, "height", "depth"),
+                          Stage(ast::PipelineStage::kCompute),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateExecutionModes(func, 3)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.execution_modes()), "");
-  EXPECT_EQ(DumpInstructions(b.types()),
-            R"(%2 = OpTypeInt 32 0
+    ASSERT_TRUE(b.GenerateExecutionModes(func, 3)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.execution_modes()), "");
+    EXPECT_EQ(DumpInstructions(b.types()),
+              R"(%2 = OpTypeInt 32 0
 %1 = OpTypeVector %2 3
 %4 = OpConstant %2 4
 %5 = OpSpecConstant %2 2
 %6 = OpConstant %2 3
 %3 = OpSpecConstantComposite %1 %4 %5 %6
 )");
-  EXPECT_EQ(DumpInstructions(b.annots()),
-            R"(OpDecorate %5 SpecId 7
+    EXPECT_EQ(DumpInstructions(b.annots()),
+              R"(OpDecorate %5 SpecId 7
 OpDecorate %3 BuiltIn WorkgroupSize
 )");
 }
 
 TEST_F(BuilderTest, Decoration_ExecutionMode_MultipleFragment) {
-  auto* func1 = Func("main1", {}, ty.void_(), ast::StatementList{},
-                     ast::AttributeList{
-                         Stage(ast::PipelineStage::kFragment),
-                     });
+    auto* func1 = Func("main1", {}, ty.void_(), ast::StatementList{},
+                       ast::AttributeList{
+                           Stage(ast::PipelineStage::kFragment),
+                       });
 
-  auto* func2 = Func("main2", {}, ty.void_(), ast::StatementList{},
-                     ast::AttributeList{
-                         Stage(ast::PipelineStage::kFragment),
-                     });
+    auto* func2 = Func("main2", {}, ty.void_(), ast::StatementList{},
+                       ast::AttributeList{
+                           Stage(ast::PipelineStage::kFragment),
+                       });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(func1)) << b.error();
-  ASSERT_TRUE(b.GenerateFunction(func2)) << b.error();
-  EXPECT_EQ(DumpBuilder(b),
-            R"(OpEntryPoint Fragment %3 "main1"
+    ASSERT_TRUE(b.GenerateFunction(func1)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func2)) << b.error();
+    EXPECT_EQ(DumpBuilder(b),
+              R"(OpEntryPoint Fragment %3 "main1"
 OpEntryPoint Fragment %5 "main2"
 OpExecutionMode %3 OriginUpperLeft
 OpExecutionMode %5 OriginUpperLeft
@@ -245,21 +242,21 @@
 }
 
 TEST_F(BuilderTest, Decoration_ExecutionMode_FragDepth) {
-  Func("main", ast::VariableList{}, ty.f32(),
-       ast::StatementList{
-           Return(Expr(1.f)),
-       },
-       ast::AttributeList{Stage(ast::PipelineStage::kFragment)},
-       ast::AttributeList{
-           Builtin(ast::Builtin::kFragDepth),
-       });
+    Func("main", ast::VariableList{}, ty.f32(),
+         ast::StatementList{
+             Return(Expr(1.f)),
+         },
+         ast::AttributeList{Stage(ast::PipelineStage::kFragment)},
+         ast::AttributeList{
+             Builtin(ast::Builtin::kFragDepth),
+         });
 
-  spirv::Builder& b = SanitizeAndBuild();
+    spirv::Builder& b = SanitizeAndBuild();
 
-  ASSERT_TRUE(b.Build());
+    ASSERT_TRUE(b.Build());
 
-  EXPECT_EQ(DumpInstructions(b.execution_modes()),
-            R"(OpExecutionMode %11 OriginUpperLeft
+    EXPECT_EQ(DumpInstructions(b.execution_modes()),
+              R"(OpExecutionMode %11 OriginUpperLeft
 OpExecutionMode %11 DepthReplacing
 )");
 }
diff --git a/src/tint/writer/spirv/builder_function_test.cc b/src/tint/writer/spirv/builder_function_test.cc
index 23dd0c8..fdb6a34 100644
--- a/src/tint/writer/spirv/builder_function_test.cc
+++ b/src/tint/writer/spirv/builder_function_test.cc
@@ -16,19 +16,21 @@
 #include "src/tint/writer/spirv/spv_dump.h"
 #include "src/tint/writer/spirv/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::spirv {
 namespace {
 
 using BuilderTest = TestHelper;
 
 TEST_F(BuilderTest, Function_Empty) {
-  Func("a_func", {}, ty.void_(), ast::StatementList{}, ast::AttributeList{});
+    Func("a_func", {}, ty.void_(), ast::StatementList{}, ast::AttributeList{});
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  auto* func = program->AST().Functions()[0];
-  ASSERT_TRUE(b.GenerateFunction(func));
-  EXPECT_EQ(DumpBuilder(b), R"(OpName %3 "a_func"
+    auto* func = program->AST().Functions()[0];
+    ASSERT_TRUE(b.GenerateFunction(func));
+    EXPECT_EQ(DumpBuilder(b), R"(OpName %3 "a_func"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
 %3 = OpFunction %2 None %1
@@ -39,17 +41,17 @@
 }
 
 TEST_F(BuilderTest, Function_Terminator_Return) {
-  Func("a_func", {}, ty.void_(),
-       ast::StatementList{
-           Return(),
-       },
-       ast::AttributeList{});
+    Func("a_func", {}, ty.void_(),
+         ast::StatementList{
+             Return(),
+         },
+         ast::AttributeList{});
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  auto* func = program->AST().Functions()[0];
-  ASSERT_TRUE(b.GenerateFunction(func));
-  EXPECT_EQ(DumpBuilder(b), R"(OpName %3 "a_func"
+    auto* func = program->AST().Functions()[0];
+    ASSERT_TRUE(b.GenerateFunction(func));
+    EXPECT_EQ(DumpBuilder(b), R"(OpName %3 "a_func"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
 %3 = OpFunction %2 None %1
@@ -60,19 +62,18 @@
 }
 
 TEST_F(BuilderTest, Function_Terminator_ReturnValue) {
-  Global("a", ty.f32(), ast::StorageClass::kPrivate);
+    Global("a", ty.f32(), ast::StorageClass::kPrivate);
 
-  Func("a_func", {}, ty.f32(), ast::StatementList{Return("a")},
-       ast::AttributeList{});
+    Func("a_func", {}, ty.f32(), ast::StatementList{Return("a")}, ast::AttributeList{});
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  auto* var_a = program->AST().GlobalVariables()[0];
-  auto* func = program->AST().Functions()[0];
+    auto* var_a = program->AST().GlobalVariables()[0];
+    auto* func = program->AST().Functions()[0];
 
-  ASSERT_TRUE(b.GenerateGlobalVariable(var_a)) << b.error();
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
-  EXPECT_EQ(DumpBuilder(b), R"(OpName %1 "a"
+    ASSERT_TRUE(b.GenerateGlobalVariable(var_a)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    EXPECT_EQ(DumpBuilder(b), R"(OpName %1 "a"
 OpName %6 "a_func"
 %3 = OpTypeFloat 32
 %2 = OpTypePointer Private %3
@@ -88,17 +89,17 @@
 }
 
 TEST_F(BuilderTest, Function_Terminator_Discard) {
-  Func("a_func", {}, ty.void_(),
-       ast::StatementList{
-           create<ast::DiscardStatement>(),
-       },
-       ast::AttributeList{});
+    Func("a_func", {}, ty.void_(),
+         ast::StatementList{
+             create<ast::DiscardStatement>(),
+         },
+         ast::AttributeList{});
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  auto* func = program->AST().Functions()[0];
-  ASSERT_TRUE(b.GenerateFunction(func));
-  EXPECT_EQ(DumpBuilder(b), R"(OpName %3 "a_func"
+    auto* func = program->AST().Functions()[0];
+    ASSERT_TRUE(b.GenerateFunction(func));
+    EXPECT_EQ(DumpBuilder(b), R"(OpName %3 "a_func"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
 %3 = OpFunction %2 None %1
@@ -109,16 +110,15 @@
 }
 
 TEST_F(BuilderTest, Function_WithParams) {
-  ast::VariableList params = {Param("a", ty.f32()), Param("b", ty.i32())};
+    ast::VariableList params = {Param("a", ty.f32()), Param("b", ty.i32())};
 
-  Func("a_func", params, ty.f32(), ast::StatementList{Return("a")},
-       ast::AttributeList{});
+    Func("a_func", params, ty.f32(), ast::StatementList{Return("a")}, ast::AttributeList{});
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  auto* func = program->AST().Functions()[0];
-  ASSERT_TRUE(b.GenerateFunction(func));
-  EXPECT_EQ(DumpBuilder(b), R"(OpName %4 "a_func"
+    auto* func = program->AST().Functions()[0];
+    ASSERT_TRUE(b.GenerateFunction(func));
+    EXPECT_EQ(DumpBuilder(b), R"(OpName %4 "a_func"
 OpName %5 "a"
 OpName %6 "b"
 %2 = OpTypeFloat 32
@@ -134,17 +134,17 @@
 }
 
 TEST_F(BuilderTest, Function_WithBody) {
-  Func("a_func", {}, ty.void_(),
-       ast::StatementList{
-           Return(),
-       },
-       ast::AttributeList{});
+    Func("a_func", {}, ty.void_(),
+         ast::StatementList{
+             Return(),
+         },
+         ast::AttributeList{});
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  auto* func = program->AST().Functions()[0];
-  ASSERT_TRUE(b.GenerateFunction(func));
-  EXPECT_EQ(DumpBuilder(b), R"(OpName %3 "a_func"
+    auto* func = program->AST().Functions()[0];
+    ASSERT_TRUE(b.GenerateFunction(func));
+    EXPECT_EQ(DumpBuilder(b), R"(OpName %3 "a_func"
 %2 = OpTypeVoid
 %1 = OpTypeFunction %2
 %3 = OpFunction %2 None %1
@@ -155,87 +155,81 @@
 }
 
 TEST_F(BuilderTest, FunctionType) {
-  Func("a_func", {}, ty.void_(), ast::StatementList{}, ast::AttributeList{});
+    Func("a_func", {}, ty.void_(), ast::StatementList{}, ast::AttributeList{});
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  auto* func = program->AST().Functions()[0];
-  ASSERT_TRUE(b.GenerateFunction(func));
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+    auto* func = program->AST().Functions()[0];
+    ASSERT_TRUE(b.GenerateFunction(func));
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
 %1 = OpTypeFunction %2
 )");
 }
 
 TEST_F(BuilderTest, FunctionType_DeDuplicate) {
-  auto* func1 = Func("a_func", {}, ty.void_(), ast::StatementList{},
-                     ast::AttributeList{});
-  auto* func2 = Func("b_func", {}, ty.void_(), ast::StatementList{},
-                     ast::AttributeList{});
+    auto* func1 = Func("a_func", {}, ty.void_(), ast::StatementList{}, ast::AttributeList{});
+    auto* func2 = Func("b_func", {}, ty.void_(), ast::StatementList{}, ast::AttributeList{});
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateFunction(func1));
-  ASSERT_TRUE(b.GenerateFunction(func2));
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+    ASSERT_TRUE(b.GenerateFunction(func1));
+    ASSERT_TRUE(b.GenerateFunction(func2));
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
 %1 = OpTypeFunction %2
 )");
 }
 
 // https://crbug.com/tint/297
 TEST_F(BuilderTest, Emit_Multiple_EntryPoint_With_Same_ModuleVar) {
-  // struct Data {
-  //   d : f32;
-  // };
-  // @binding(0) @group(0) var<storage> data : Data;
-  //
-  // @stage(compute) @workgroup_size(1)
-  // fn a() {
-  //   return;
-  // }
-  //
-  // @stage(compute) @workgroup_size(1)
-  // fn b() {
-  //   return;
-  // }
+    // struct Data {
+    //   d : f32;
+    // };
+    // @binding(0) @group(0) var<storage> data : Data;
+    //
+    // @stage(compute) @workgroup_size(1)
+    // fn a() {
+    //   return;
+    // }
+    //
+    // @stage(compute) @workgroup_size(1)
+    // fn b() {
+    //   return;
+    // }
 
-  auto* s = Structure("Data", {Member("d", ty.f32())});
+    auto* s = Structure("Data", {Member("d", ty.f32())});
 
-  Global("data", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    Global("data", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  {
-    auto* var = Var("v", ty.f32(), ast::StorageClass::kNone,
-                    MemberAccessor("data", "d"));
+    {
+        auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, MemberAccessor("data", "d"));
 
-    Func("a", ast::VariableList{}, ty.void_(),
-         ast::StatementList{
-             Decl(var),
-             Return(),
-         },
-         ast::AttributeList{Stage(ast::PipelineStage::kCompute),
-                            WorkgroupSize(1)});
-  }
+        Func("a", ast::VariableList{}, ty.void_(),
+             ast::StatementList{
+                 Decl(var),
+                 Return(),
+             },
+             ast::AttributeList{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+    }
 
-  {
-    auto* var = Var("v", ty.f32(), ast::StorageClass::kNone,
-                    MemberAccessor("data", "d"));
+    {
+        auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, MemberAccessor("data", "d"));
 
-    Func("b", ast::VariableList{}, ty.void_(),
-         ast::StatementList{
-             Decl(var),
-             Return(),
-         },
-         ast::AttributeList{Stage(ast::PipelineStage::kCompute),
-                            WorkgroupSize(1)});
-  }
+        Func("b", ast::VariableList{}, ty.void_(),
+             ast::StatementList{
+                 Decl(var),
+                 Return(),
+             },
+             ast::AttributeList{Stage(ast::PipelineStage::kCompute), WorkgroupSize(1_i)});
+    }
 
-  spirv::Builder& b = SanitizeAndBuild();
+    spirv::Builder& b = SanitizeAndBuild();
 
-  ASSERT_TRUE(b.Build());
-  EXPECT_EQ(DumpBuilder(b), R"(OpCapability Shader
+    ASSERT_TRUE(b.Build());
+    EXPECT_EQ(DumpBuilder(b), R"(OpCapability Shader
 OpMemoryModel Logical GLSL450
 OpEntryPoint GLCompute %7 "a"
 OpEntryPoint GLCompute %17 "b"
diff --git a/src/tint/writer/spirv/builder_function_variable_test.cc b/src/tint/writer/spirv/builder_function_variable_test.cc
index 6264b27..a3989a0 100644
--- a/src/tint/writer/spirv/builder_function_variable_test.cc
+++ b/src/tint/writer/spirv/builder_function_variable_test.cc
@@ -21,40 +21,40 @@
 using BuilderTest = TestHelper;
 
 TEST_F(BuilderTest, FunctionVar_NoStorageClass) {
-  auto* v = Var("var", ty.f32(), ast::StorageClass::kFunction);
-  WrapInFunction(v);
+    auto* v = Var("var", ty.f32(), ast::StorageClass::kFunction);
+    WrapInFunction(v);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_TRUE(b.GenerateFunctionVariable(v)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "var"
+    b.push_function(Function{});
+    EXPECT_TRUE(b.GenerateFunctionVariable(v)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "var"
 )");
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
 %2 = OpTypePointer Function %3
 %4 = OpConstantNull %3
 )");
 
-  const auto& func = b.functions()[0];
-  EXPECT_EQ(DumpInstructions(func.variables()),
-            R"(%1 = OpVariable %2 Function %4
+    const auto& func = b.functions()[0];
+    EXPECT_EQ(DumpInstructions(func.variables()),
+              R"(%1 = OpVariable %2 Function %4
 )");
 }
 
 TEST_F(BuilderTest, FunctionVar_WithConstantConstructor) {
-  auto* init = vec3<f32>(1.f, 1.f, 3.f);
-  auto* v = Var("var", ty.vec3<f32>(), ast::StorageClass::kFunction, init);
-  WrapInFunction(v);
+    auto* init = vec3<f32>(1.f, 1.f, 3.f);
+    auto* v = Var("var", ty.vec3<f32>(), ast::StorageClass::kFunction, init);
+    WrapInFunction(v);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_TRUE(b.GenerateFunctionVariable(v)) << b.error();
-  ASSERT_FALSE(b.has_error()) << b.error();
+    b.push_function(Function{});
+    EXPECT_TRUE(b.GenerateFunctionVariable(v)) << b.error();
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %6 "var"
+    EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %6 "var"
 )");
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 3
 %3 = OpConstant %2 1
 %4 = OpConstant %2 3
@@ -62,128 +62,128 @@
 %7 = OpTypePointer Function %1
 %8 = OpConstantNull %1
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-            R"(%6 = OpVariable %7 Function %8
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
+              R"(%6 = OpVariable %7 Function %8
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(OpStore %6 %5
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpStore %6 %5
 )");
 }
 
 TEST_F(BuilderTest, FunctionVar_WithNonConstantConstructor) {
-  auto* init = vec2<f32>(1.f, Add(3.f, 3.f));
+    auto* init = vec2<f32>(1.f, Add(3.f, 3.f));
 
-  auto* v = Var("var", ty.vec2<f32>(), ast::StorageClass::kNone, init);
-  WrapInFunction(v);
+    auto* v = Var("var", ty.vec2<f32>(), ast::StorageClass::kNone, init);
+    WrapInFunction(v);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_TRUE(b.GenerateFunctionVariable(v)) << b.error();
-  ASSERT_FALSE(b.has_error()) << b.error();
+    b.push_function(Function{});
+    EXPECT_TRUE(b.GenerateFunctionVariable(v)) << b.error();
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %7 "var"
+    EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %7 "var"
 )");
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 2
 %3 = OpConstant %2 1
 %4 = OpConstant %2 3
 %8 = OpTypePointer Function %1
 %9 = OpConstantNull %1
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-            R"(%7 = OpVariable %8 Function %9
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
+              R"(%7 = OpVariable %8 Function %9
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%5 = OpFAdd %2 %4 %4
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%5 = OpFAdd %2 %4 %4
 %6 = OpCompositeConstruct %1 %3 %5
 OpStore %7 %6
 )");
 }
 
 TEST_F(BuilderTest, FunctionVar_WithNonConstantConstructorLoadedFromVar) {
-  // var v : f32 = 1.0;
-  // var v2 : f32 = v; // Should generate the load and store automatically.
+    // var v : f32 = 1.0;
+    // var v2 : f32 = v; // Should generate the load and store automatically.
 
-  auto* v = Var("v", ty.f32(), ast::StorageClass::kNone, Expr(1.f));
+    auto* v = Var("v", ty.f32(), ast::StorageClass::kNone, Expr(1.f));
 
-  auto* v2 = Var("v2", ty.f32(), ast::StorageClass::kNone, Expr("v"));
-  WrapInFunction(v, v2);
+    auto* v2 = Var("v2", ty.f32(), ast::StorageClass::kNone, Expr("v"));
+    WrapInFunction(v, v2);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_TRUE(b.GenerateFunctionVariable(v)) << b.error();
-  EXPECT_TRUE(b.GenerateFunctionVariable(v2)) << b.error();
-  ASSERT_FALSE(b.has_error()) << b.error();
+    b.push_function(Function{});
+    EXPECT_TRUE(b.GenerateFunctionVariable(v)) << b.error();
+    EXPECT_TRUE(b.GenerateFunctionVariable(v2)) << b.error();
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %3 "v"
+    EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %3 "v"
 OpName %7 "v2"
 )");
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32
 %2 = OpConstant %1 1
 %4 = OpTypePointer Function %1
 %5 = OpConstantNull %1
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-            R"(%3 = OpVariable %4 Function %5
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
+              R"(%3 = OpVariable %4 Function %5
 %7 = OpVariable %4 Function %5
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(OpStore %3 %2
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpStore %3 %2
 %6 = OpLoad %1 %3
 OpStore %7 %6
 )");
 }
 
 TEST_F(BuilderTest, FunctionVar_ConstWithVarInitializer) {
-  // var v : f32 = 1.0;
-  // let v2 : f32 = v; // Should generate the load
+    // var v : f32 = 1.0;
+    // let v2 : f32 = v; // Should generate the load
 
-  auto* v = Var("v", ty.f32(), ast::StorageClass::kNone, Expr(1.f));
+    auto* v = Var("v", ty.f32(), ast::StorageClass::kNone, Expr(1.f));
 
-  auto* v2 = Var("v2", ty.f32(), ast::StorageClass::kNone, Expr("v"));
-  WrapInFunction(v, v2);
+    auto* v2 = Var("v2", ty.f32(), ast::StorageClass::kNone, Expr("v"));
+    WrapInFunction(v, v2);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_TRUE(b.GenerateFunctionVariable(v)) << b.error();
-  EXPECT_TRUE(b.GenerateFunctionVariable(v2)) << b.error();
-  ASSERT_FALSE(b.has_error()) << b.error();
+    b.push_function(Function{});
+    EXPECT_TRUE(b.GenerateFunctionVariable(v)) << b.error();
+    EXPECT_TRUE(b.GenerateFunctionVariable(v2)) << b.error();
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %3 "v"
+    EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %3 "v"
 OpName %7 "v2"
 )");
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32
 %2 = OpConstant %1 1
 %4 = OpTypePointer Function %1
 %5 = OpConstantNull %1
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-            R"(%3 = OpVariable %4 Function %5
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
+              R"(%3 = OpVariable %4 Function %5
 %7 = OpVariable %4 Function %5
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(OpStore %3 %2
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpStore %3 %2
 %6 = OpLoad %1 %3
 OpStore %7 %6
 )");
 }
 
 TEST_F(BuilderTest, FunctionVar_Const) {
-  auto* init = vec3<f32>(1.f, 1.f, 3.f);
+    auto* init = vec3<f32>(1.f, 1.f, 3.f);
 
-  auto* v = Const("var", ty.vec3<f32>(), init);
+    auto* v = Let("var", ty.vec3<f32>(), init);
 
-  WrapInFunction(v);
+    WrapInFunction(v);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_TRUE(b.GenerateFunctionVariable(v)) << b.error();
-  ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_TRUE(b.GenerateFunctionVariable(v)) << b.error();
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 3
 %3 = OpConstant %2 1
 %4 = OpConstant %2 3
diff --git a/src/tint/writer/spirv/builder_global_variable_test.cc b/src/tint/writer/spirv/builder_global_variable_test.cc
index 16ae30b..727c573 100644
--- a/src/tint/writer/spirv/builder_global_variable_test.cc
+++ b/src/tint/writer/spirv/builder_global_variable_test.cc
@@ -23,14 +23,14 @@
 using BuilderTest = TestHelper;
 
 TEST_F(BuilderTest, GlobalVar_WithStorageClass) {
-  auto* v = Global("var", ty.f32(), ast::StorageClass::kPrivate);
+    auto* v = Global("var", ty.f32(), ast::StorageClass::kPrivate);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "var"
+    EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "var"
 )");
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
 %2 = OpTypePointer Private %3
 %4 = OpConstantNull %3
 %1 = OpVariable %2 Private %4
@@ -38,18 +38,18 @@
 }
 
 TEST_F(BuilderTest, GlobalVar_WithConstructor) {
-  auto* init = vec3<f32>(1.f, 1.f, 3.f);
+    auto* init = vec3<f32>(1.f, 1.f, 3.f);
 
-  auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kPrivate, init);
+    auto* v = Global("var", ty.vec3<f32>(), ast::StorageClass::kPrivate, init);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
-  ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %6 "var"
+    EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %6 "var"
 )");
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 3
 %3 = OpConstant %2 1
 %4 = OpConstant %2 3
@@ -60,18 +60,18 @@
 }
 
 TEST_F(BuilderTest, GlobalVar_Const) {
-  auto* init = vec3<f32>(1.f, 1.f, 3.f);
+    auto* init = vec3<f32>(1.f, 1.f, 3.f);
 
-  auto* v = GlobalConst("var", ty.vec3<f32>(), init);
+    auto* v = GlobalConst("var", ty.vec3<f32>(), init);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
-  ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %5 "var"
+    EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %5 "var"
 )");
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 3
 %3 = OpConstant %2 1
 %4 = OpConstant %2 3
@@ -80,16 +80,16 @@
 }
 
 TEST_F(BuilderTest, GlobalVar_Complex_Constructor) {
-  auto* init = vec3<f32>(ast::ExpressionList{Expr(1.f), Expr(2.f), Expr(3.f)});
+    auto* init = vec3<f32>(ast::ExpressionList{Expr(1.f), Expr(2.f), Expr(3.f)});
 
-  auto* v = GlobalConst("var", ty.vec3<f32>(), init);
+    auto* v = GlobalConst("var", ty.vec3<f32>(), init);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
-  ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 3
 %3 = OpConstant %2 1
 %4 = OpConstant %2 2
@@ -99,16 +99,16 @@
 }
 
 TEST_F(BuilderTest, GlobalVar_Complex_ConstructorWithExtract) {
-  auto* init = vec3<f32>(vec2<f32>(1.f, 2.f), 3.f);
+    auto* init = vec3<f32>(vec2<f32>(1.f, 2.f), 3.f);
 
-  auto* v = GlobalConst("var", ty.vec3<f32>(), init);
+    auto* v = GlobalConst("var", ty.vec3<f32>(), init);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
-  ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 3
 %3 = OpTypeVector %2 2
 %4 = OpConstant %2 1
@@ -125,221 +125,218 @@
 }
 
 TEST_F(BuilderTest, GlobalVar_WithBindingAndGroup) {
-  auto* v = Global("var", ty.sampler(ast::SamplerKind::kSampler),
-                   ast::StorageClass::kNone, nullptr,
-                   ast::AttributeList{
-                       create<ast::BindingAttribute>(2),
-                       create<ast::GroupAttribute>(3),
-                   });
+    auto* v =
+        Global("var", ty.sampler(ast::SamplerKind::kSampler), ast::StorageClass::kNone, nullptr,
+               ast::AttributeList{
+                   create<ast::BindingAttribute>(2),
+                   create<ast::GroupAttribute>(3),
+               });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "var"
+    EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "var"
 )");
-  EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %1 Binding 2
+    EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %1 Binding 2
 OpDecorate %1 DescriptorSet 3
 )");
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeSampler
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeSampler
 %2 = OpTypePointer UniformConstant %3
 %1 = OpVariable %2 UniformConstant
 )");
 }
 
 TEST_F(BuilderTest, GlobalVar_Override_Bool) {
-  auto* v = Override("var", ty.bool_(), Expr(true),
-                     ast::AttributeList{
-                         Id(1200),
-                     });
+    auto* v = Override("var", ty.bool_(), Expr(true),
+                       ast::AttributeList{
+                           Id(1200),
+                       });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %2 "var"
+    EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %2 "var"
 )");
-  EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %2 SpecId 1200
+    EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %2 SpecId 1200
 )");
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeBool
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeBool
 %2 = OpSpecConstantTrue %1
 )");
 }
 
 TEST_F(BuilderTest, GlobalVar_Override_Bool_ZeroValue) {
-  auto* v = Override("var", ty.bool_(), Construct<bool>(),
-                     ast::AttributeList{
-                         Id(1200),
-                     });
+    auto* v = Override("var", ty.bool_(), Construct<bool>(),
+                       ast::AttributeList{
+                           Id(1200),
+                       });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %2 "var"
+    EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %2 "var"
 )");
-  EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %2 SpecId 1200
+    EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %2 SpecId 1200
 )");
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeBool
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeBool
 %2 = OpSpecConstantFalse %1
 )");
 }
 
 TEST_F(BuilderTest, GlobalVar_Override_Bool_NoConstructor) {
-  auto* v = Override("var", ty.bool_(), nullptr,
-                     ast::AttributeList{
-                         Id(1200),
-                     });
+    auto* v = Override("var", ty.bool_(), nullptr,
+                       ast::AttributeList{
+                           Id(1200),
+                       });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %2 "var"
+    EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %2 "var"
 )");
-  EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %2 SpecId 1200
+    EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %2 SpecId 1200
 )");
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeBool
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeBool
 %2 = OpSpecConstantFalse %1
 )");
 }
 
 TEST_F(BuilderTest, GlobalVar_Override_Scalar) {
-  auto* v = Override("var", ty.f32(), Expr(2.f),
-                     ast::AttributeList{
-                         Id(0),
-                     });
+    auto* v = Override("var", ty.f32(), Expr(2.f),
+                       ast::AttributeList{
+                           Id(0),
+                       });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %2 "var"
+    EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %2 "var"
 )");
-  EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %2 SpecId 0
+    EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %2 SpecId 0
 )");
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32
 %2 = OpSpecConstant %1 2
 )");
 }
 
 TEST_F(BuilderTest, GlobalVar_Override_Scalar_ZeroValue) {
-  auto* v = Override("var", ty.f32(), Construct<f32>(),
-                     ast::AttributeList{
-                         Id(0),
-                     });
+    auto* v = Override("var", ty.f32(), Construct<f32>(),
+                       ast::AttributeList{
+                           Id(0),
+                       });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %2 "var"
+    EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %2 "var"
 )");
-  EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %2 SpecId 0
+    EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %2 SpecId 0
 )");
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32
 %2 = OpSpecConstant %1 0
 )");
 }
 
 TEST_F(BuilderTest, GlobalVar_Override_Scalar_F32_NoConstructor) {
-  auto* v = Override("var", ty.f32(), nullptr,
-                     ast::AttributeList{
-                         Id(0),
-                     });
+    auto* v = Override("var", ty.f32(), nullptr,
+                       ast::AttributeList{
+                           Id(0),
+                       });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %2 "var"
+    EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %2 "var"
 )");
-  EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %2 SpecId 0
+    EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %2 SpecId 0
 )");
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32
 %2 = OpSpecConstant %1 0
 )");
 }
 
 TEST_F(BuilderTest, GlobalVar_Override_Scalar_I32_NoConstructor) {
-  auto* v = Override("var", ty.i32(), nullptr,
-                     ast::AttributeList{
-                         Id(0),
-                     });
+    auto* v = Override("var", ty.i32(), nullptr,
+                       ast::AttributeList{
+                           Id(0),
+                       });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %2 "var"
+    EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %2 "var"
 )");
-  EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %2 SpecId 0
+    EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %2 SpecId 0
 )");
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 1
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 1
 %2 = OpSpecConstant %1 0
 )");
 }
 
 TEST_F(BuilderTest, GlobalVar_Override_Scalar_U32_NoConstructor) {
-  auto* v = Override("var", ty.u32(), nullptr,
-                     ast::AttributeList{
-                         Id(0),
-                     });
+    auto* v = Override("var", ty.u32(), nullptr,
+                       ast::AttributeList{
+                           Id(0),
+                       });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %2 "var"
+    EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %2 "var"
 )");
-  EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %2 SpecId 0
+    EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %2 SpecId 0
 )");
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 0
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 0
 %2 = OpSpecConstant %1 0
 )");
 }
 
 TEST_F(BuilderTest, GlobalVar_Override_NoId) {
-  auto* var_a = Override("a", ty.bool_(), Expr(true),
-                         ast::AttributeList{
-                             Id(0),
-                         });
-  auto* var_b = Override("b", ty.bool_(), Expr(false));
+    auto* var_a = Override("a", ty.bool_(), Expr(true),
+                           ast::AttributeList{
+                               Id(0),
+                           });
+    auto* var_b = Override("b", ty.bool_(), Expr(false));
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_TRUE(b.GenerateGlobalVariable(var_a)) << b.error();
-  EXPECT_TRUE(b.GenerateGlobalVariable(var_b)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %2 "a"
+    EXPECT_TRUE(b.GenerateGlobalVariable(var_a)) << b.error();
+    EXPECT_TRUE(b.GenerateGlobalVariable(var_b)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %2 "a"
 OpName %3 "b"
 )");
-  EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %2 SpecId 0
+    EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %2 SpecId 0
 OpDecorate %3 SpecId 1
 )");
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeBool
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeBool
 %2 = OpSpecConstantTrue %1
 %3 = OpSpecConstantFalse %1
 )");
 }
 
 struct BuiltinData {
-  ast::Builtin builtin;
-  ast::StorageClass storage;
-  SpvBuiltIn result;
+    ast::Builtin builtin;
+    ast::StorageClass storage;
+    SpvBuiltIn result;
 };
 inline std::ostream& operator<<(std::ostream& out, BuiltinData data) {
-  out << data.builtin;
-  return out;
+    out << data.builtin;
+    return out;
 }
 using BuiltinDataTest = TestParamHelper<BuiltinData>;
 TEST_P(BuiltinDataTest, Convert) {
-  auto params = GetParam();
+    auto params = GetParam();
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_EQ(b.ConvertBuiltin(params.builtin, params.storage), params.result);
+    EXPECT_EQ(b.ConvertBuiltin(params.builtin, params.storage), params.result);
 }
 INSTANTIATE_TEST_SUITE_P(
     BuilderTest_Type,
     BuiltinDataTest,
     testing::Values(
-        BuiltinData{ast::Builtin::kNone, ast::StorageClass::kNone,
-                    SpvBuiltInMax},
-        BuiltinData{ast::Builtin::kPosition, ast::StorageClass::kInput,
-                    SpvBuiltInFragCoord},
-        BuiltinData{ast::Builtin::kPosition, ast::StorageClass::kOutput,
-                    SpvBuiltInPosition},
+        BuiltinData{ast::Builtin::kNone, ast::StorageClass::kNone, SpvBuiltInMax},
+        BuiltinData{ast::Builtin::kPosition, ast::StorageClass::kInput, SpvBuiltInFragCoord},
+        BuiltinData{ast::Builtin::kPosition, ast::StorageClass::kOutput, SpvBuiltInPosition},
         BuiltinData{
             ast::Builtin::kVertexIndex,
             ast::StorageClass::kInput,
@@ -347,62 +344,56 @@
         },
         BuiltinData{ast::Builtin::kInstanceIndex, ast::StorageClass::kInput,
                     SpvBuiltInInstanceIndex},
-        BuiltinData{ast::Builtin::kFrontFacing, ast::StorageClass::kInput,
-                    SpvBuiltInFrontFacing},
-        BuiltinData{ast::Builtin::kFragDepth, ast::StorageClass::kOutput,
-                    SpvBuiltInFragDepth},
+        BuiltinData{ast::Builtin::kFrontFacing, ast::StorageClass::kInput, SpvBuiltInFrontFacing},
+        BuiltinData{ast::Builtin::kFragDepth, ast::StorageClass::kOutput, SpvBuiltInFragDepth},
         BuiltinData{ast::Builtin::kLocalInvocationId, ast::StorageClass::kInput,
                     SpvBuiltInLocalInvocationId},
-        BuiltinData{ast::Builtin::kLocalInvocationIndex,
-                    ast::StorageClass::kInput, SpvBuiltInLocalInvocationIndex},
-        BuiltinData{ast::Builtin::kGlobalInvocationId,
-                    ast::StorageClass::kInput, SpvBuiltInGlobalInvocationId},
-        BuiltinData{ast::Builtin::kWorkgroupId, ast::StorageClass::kInput,
-                    SpvBuiltInWorkgroupId},
+        BuiltinData{ast::Builtin::kLocalInvocationIndex, ast::StorageClass::kInput,
+                    SpvBuiltInLocalInvocationIndex},
+        BuiltinData{ast::Builtin::kGlobalInvocationId, ast::StorageClass::kInput,
+                    SpvBuiltInGlobalInvocationId},
+        BuiltinData{ast::Builtin::kWorkgroupId, ast::StorageClass::kInput, SpvBuiltInWorkgroupId},
         BuiltinData{ast::Builtin::kNumWorkgroups, ast::StorageClass::kInput,
                     SpvBuiltInNumWorkgroups},
-        BuiltinData{ast::Builtin::kSampleIndex, ast::StorageClass::kInput,
-                    SpvBuiltInSampleId},
-        BuiltinData{ast::Builtin::kSampleMask, ast::StorageClass::kInput,
-                    SpvBuiltInSampleMask},
-        BuiltinData{ast::Builtin::kSampleMask, ast::StorageClass::kOutput,
-                    SpvBuiltInSampleMask}));
+        BuiltinData{ast::Builtin::kSampleIndex, ast::StorageClass::kInput, SpvBuiltInSampleId},
+        BuiltinData{ast::Builtin::kSampleMask, ast::StorageClass::kInput, SpvBuiltInSampleMask},
+        BuiltinData{ast::Builtin::kSampleMask, ast::StorageClass::kOutput, SpvBuiltInSampleMask}));
 
 TEST_F(BuilderTest, GlobalVar_DeclReadOnly) {
-  // struct A {
-  //   a : i32;
-  // };
-  // var b<storage, read> : A
+    // struct A {
+    //   a : i32;
+    // };
+    // var b<storage, read> : A
 
-  auto* A = Structure("A", {
-                               Member("a", ty.i32()),
-                               Member("b", ty.i32()),
-                           });
+    auto* A = Structure("A", {
+                                 Member("a", ty.i32()),
+                                 Member("b", ty.i32()),
+                             });
 
-  Global("b", ty.Of(A), ast::StorageClass::kStorage, ast::Access::kRead,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    Global("b", ty.Of(A), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  spirv::Builder& b = SanitizeAndBuild();
+    spirv::Builder& b = SanitizeAndBuild();
 
-  ASSERT_TRUE(b.Build());
+    ASSERT_TRUE(b.Build());
 
-  EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %3 Block
+    EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %3 Block
 OpMemberDecorate %3 0 Offset 0
 OpMemberDecorate %3 1 Offset 4
 OpDecorate %1 NonWritable
 OpDecorate %1 Binding 0
 OpDecorate %1 DescriptorSet 0
 )");
-  EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %3 "A"
+    EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %3 "A"
 OpMemberName %3 0 "a"
 OpMemberName %3 1 "b"
 OpName %1 "b"
 OpName %7 "unused_entry_point"
 )");
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 1
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 1
 %3 = OpTypeStruct %4 %4
 %2 = OpTypePointer StorageBuffer %3
 %1 = OpVariable %2 StorageBuffer
@@ -412,36 +403,36 @@
 }
 
 TEST_F(BuilderTest, GlobalVar_TypeAliasDeclReadOnly) {
-  // struct A {
-  //   a : i32;
-  // };
-  // type B = A;
-  // var b<storage, read> : B
+    // struct A {
+    //   a : i32;
+    // };
+    // type B = A;
+    // var b<storage, read> : B
 
-  auto* A = Structure("A", {Member("a", ty.i32())});
-  auto* B = Alias("B", ty.Of(A));
-  Global("b", ty.Of(B), ast::StorageClass::kStorage, ast::Access::kRead,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    auto* A = Structure("A", {Member("a", ty.i32())});
+    auto* B = Alias("B", ty.Of(A));
+    Global("b", ty.Of(B), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  spirv::Builder& b = SanitizeAndBuild();
+    spirv::Builder& b = SanitizeAndBuild();
 
-  ASSERT_TRUE(b.Build());
+    ASSERT_TRUE(b.Build());
 
-  EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %3 Block
+    EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %3 Block
 OpMemberDecorate %3 0 Offset 0
 OpDecorate %1 NonWritable
 OpDecorate %1 Binding 0
 OpDecorate %1 DescriptorSet 0
 )");
-  EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %3 "A"
+    EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %3 "A"
 OpMemberName %3 0 "a"
 OpName %1 "b"
 OpName %7 "unused_entry_point"
 )");
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 1
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 1
 %3 = OpTypeStruct %4
 %2 = OpTypePointer StorageBuffer %3
 %1 = OpVariable %2 StorageBuffer
@@ -451,36 +442,36 @@
 }
 
 TEST_F(BuilderTest, GlobalVar_TypeAliasAssignReadOnly) {
-  // struct A {
-  //   a : i32;
-  // };
-  // type B = A;
-  // var<storage, read> b : B
+    // struct A {
+    //   a : i32;
+    // };
+    // type B = A;
+    // var<storage, read> b : B
 
-  auto* A = Structure("A", {Member("a", ty.i32())});
-  auto* B = Alias("B", ty.Of(A));
-  Global("b", ty.Of(B), ast::StorageClass::kStorage, ast::Access::kRead,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    auto* A = Structure("A", {Member("a", ty.i32())});
+    auto* B = Alias("B", ty.Of(A));
+    Global("b", ty.Of(B), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  spirv::Builder& b = SanitizeAndBuild();
+    spirv::Builder& b = SanitizeAndBuild();
 
-  ASSERT_TRUE(b.Build());
+    ASSERT_TRUE(b.Build());
 
-  EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %3 Block
+    EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %3 Block
 OpMemberDecorate %3 0 Offset 0
 OpDecorate %1 NonWritable
 OpDecorate %1 Binding 0
 OpDecorate %1 DescriptorSet 0
 )");
-  EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %3 "A"
+    EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %3 "A"
 OpMemberName %3 0 "a"
 OpName %1 "b"
 OpName %7 "unused_entry_point"
 )");
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 1
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 1
 %3 = OpTypeStruct %4
 %2 = OpTypePointer StorageBuffer %3
 %1 = OpVariable %2 StorageBuffer
@@ -490,30 +481,30 @@
 }
 
 TEST_F(BuilderTest, GlobalVar_TwoVarDeclReadOnly) {
-  // struct A {
-  //   a : i32;
-  // };
-  // var<storage, read> b : A
-  // var<storage, read_write> c : A
+    // struct A {
+    //   a : i32;
+    // };
+    // var<storage, read> b : A
+    // var<storage, read_write> c : A
 
-  auto* A = Structure("A", {Member("a", ty.i32())});
-  Global("b", ty.Of(A), ast::StorageClass::kStorage, ast::Access::kRead,
-         ast::AttributeList{
-             create<ast::GroupAttribute>(0),
-             create<ast::BindingAttribute>(0),
-         });
-  Global("c", ty.Of(A), ast::StorageClass::kStorage, ast::Access::kReadWrite,
-         ast::AttributeList{
-             create<ast::GroupAttribute>(1),
-             create<ast::BindingAttribute>(0),
-         });
+    auto* A = Structure("A", {Member("a", ty.i32())});
+    Global("b", ty.Of(A), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::GroupAttribute>(0),
+               create<ast::BindingAttribute>(0),
+           });
+    Global("c", ty.Of(A), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+           ast::AttributeList{
+               create<ast::GroupAttribute>(1),
+               create<ast::BindingAttribute>(0),
+           });
 
-  spirv::Builder& b = SanitizeAndBuild();
+    spirv::Builder& b = SanitizeAndBuild();
 
-  ASSERT_TRUE(b.Build());
+    ASSERT_TRUE(b.Build());
 
-  EXPECT_EQ(DumpInstructions(b.annots()),
-            R"(OpDecorate %3 Block
+    EXPECT_EQ(DumpInstructions(b.annots()),
+              R"(OpDecorate %3 Block
 OpMemberDecorate %3 0 Offset 0
 OpDecorate %1 NonWritable
 OpDecorate %1 DescriptorSet 0
@@ -521,13 +512,13 @@
 OpDecorate %5 DescriptorSet 1
 OpDecorate %5 Binding 0
 )");
-  EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %3 "A"
+    EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %3 "A"
 OpMemberName %3 0 "a"
 OpName %1 "b"
 OpName %5 "c"
 OpName %8 "unused_entry_point"
 )");
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 1
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 1
 %3 = OpTypeStruct %4
 %2 = OpTypePointer StorageBuffer %3
 %1 = OpVariable %2 StorageBuffer
@@ -538,27 +529,26 @@
 }
 
 TEST_F(BuilderTest, GlobalVar_TextureStorageWriteOnly) {
-  // var<uniform_constant> a : texture_storage_2d<r32uint, write>;
+    // var<uniform_constant> a : texture_storage_2d<r32uint, write>;
 
-  auto* type =
-      ty.storage_texture(ast::TextureDimension::k2d, ast::TexelFormat::kR32Uint,
-                         ast::Access::kWrite);
+    auto* type = ty.storage_texture(ast::TextureDimension::k2d, ast::TexelFormat::kR32Uint,
+                                    ast::Access::kWrite);
 
-  auto* var_a = Global("a", type,
-                       ast::AttributeList{
-                           create<ast::BindingAttribute>(0),
-                           create<ast::GroupAttribute>(0),
-                       });
+    auto* var_a = Global("a", type,
+                         ast::AttributeList{
+                             create<ast::BindingAttribute>(0),
+                             create<ast::GroupAttribute>(0),
+                         });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_TRUE(b.GenerateGlobalVariable(var_a)) << b.error();
+    EXPECT_TRUE(b.GenerateGlobalVariable(var_a)) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %1 NonReadable
+    EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %1 NonReadable
 OpDecorate %1 Binding 0
 OpDecorate %1 DescriptorSet 0
 )");
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 0
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 0
 %3 = OpTypeImage %4 2D 0 0 0 2 R32ui
 %2 = OpTypePointer UniformConstant %3
 %1 = OpVariable %2 UniformConstant
@@ -570,42 +560,40 @@
 // Test disabled as storage textures currently only support 'write' access. In
 // the future we'll likely support read_write.
 TEST_F(BuilderTest, DISABLED_GlobalVar_TextureStorageWithDifferentAccess) {
-  // var<uniform_constant> a : texture_storage_2d<r32uint, read_write>;
-  // var<uniform_constant> b : texture_storage_2d<r32uint, write>;
+    // var<uniform_constant> a : texture_storage_2d<r32uint, read_write>;
+    // var<uniform_constant> b : texture_storage_2d<r32uint, write>;
 
-  auto* type_a =
-      ty.storage_texture(ast::TextureDimension::k2d, ast::TexelFormat::kR32Uint,
-                         ast::Access::kReadWrite);
-  auto* var_a = Global("a", type_a, ast::StorageClass::kNone,
-                       ast::AttributeList{
-                           create<ast::BindingAttribute>(0),
-                           create<ast::GroupAttribute>(0),
-                       });
+    auto* type_a = ty.storage_texture(ast::TextureDimension::k2d, ast::TexelFormat::kR32Uint,
+                                      ast::Access::kReadWrite);
+    auto* var_a = Global("a", type_a, ast::StorageClass::kNone,
+                         ast::AttributeList{
+                             create<ast::BindingAttribute>(0),
+                             create<ast::GroupAttribute>(0),
+                         });
 
-  auto* type_b =
-      ty.storage_texture(ast::TextureDimension::k2d, ast::TexelFormat::kR32Uint,
-                         ast::Access::kWrite);
-  auto* var_b = Global("b", type_b, ast::StorageClass::kNone,
-                       ast::AttributeList{
-                           create<ast::BindingAttribute>(1),
-                           create<ast::GroupAttribute>(0),
-                       });
+    auto* type_b = ty.storage_texture(ast::TextureDimension::k2d, ast::TexelFormat::kR32Uint,
+                                      ast::Access::kWrite);
+    auto* var_b = Global("b", type_b, ast::StorageClass::kNone,
+                         ast::AttributeList{
+                             create<ast::BindingAttribute>(1),
+                             create<ast::GroupAttribute>(0),
+                         });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_TRUE(b.GenerateGlobalVariable(var_a)) << b.error();
-  EXPECT_TRUE(b.GenerateGlobalVariable(var_b)) << b.error();
+    EXPECT_TRUE(b.GenerateGlobalVariable(var_a)) << b.error();
+    EXPECT_TRUE(b.GenerateGlobalVariable(var_b)) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %1 NonWritable
+    EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %1 NonWritable
 OpDecorate %1 Binding 0
 OpDecorate %1 DescriptorSet 0
 OpDecorate %5 NonReadable
 OpDecorate %5 Binding 1
 OpDecorate %5 DescriptorSet 0
 )");
-  // There must only be one OpTypeImage declaration with the same
-  // arguments
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 0
+    // There must only be one OpTypeImage declaration with the same
+    // arguments
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeInt 32 0
 %3 = OpTypeImage %4 2D 0 0 0 2 R32ui
 %2 = OpTypePointer UniformConstant %3
 %1 = OpVariable %2 UniformConstant
@@ -615,31 +603,30 @@
 }
 
 TEST_F(BuilderTest, GlobalVar_WorkgroupWithZeroInit) {
-  auto* type_scalar = ty.i32();
-  auto* var_scalar = Global("a", type_scalar, ast::StorageClass::kWorkgroup);
+    auto* type_scalar = ty.i32();
+    auto* var_scalar = Global("a", type_scalar, ast::StorageClass::kWorkgroup);
 
-  auto* type_array = ty.array<f32, 16>();
-  auto* var_array = Global("b", type_array, ast::StorageClass::kWorkgroup);
+    auto* type_array = ty.array<f32, 16>();
+    auto* var_array = Global("b", type_array, ast::StorageClass::kWorkgroup);
 
-  auto* type_struct = Structure("C", {
-                                         Member("a", ty.i32()),
-                                         Member("b", ty.i32()),
-                                     });
-  auto* var_struct =
-      Global("c", ty.Of(type_struct), ast::StorageClass::kWorkgroup);
+    auto* type_struct = Structure("C", {
+                                           Member("a", ty.i32()),
+                                           Member("b", ty.i32()),
+                                       });
+    auto* var_struct = Global("c", ty.Of(type_struct), ast::StorageClass::kWorkgroup);
 
-  program = std::make_unique<Program>(std::move(*this));
+    program = std::make_unique<Program>(std::move(*this));
 
-  constexpr bool kZeroInitializeWorkgroupMemory = true;
-  std::unique_ptr<spirv::Builder> b = std::make_unique<spirv::Builder>(
-      program.get(), kZeroInitializeWorkgroupMemory);
+    constexpr bool kZeroInitializeWorkgroupMemory = true;
+    std::unique_ptr<spirv::Builder> b =
+        std::make_unique<spirv::Builder>(program.get(), kZeroInitializeWorkgroupMemory);
 
-  EXPECT_TRUE(b->GenerateGlobalVariable(var_scalar)) << b->error();
-  EXPECT_TRUE(b->GenerateGlobalVariable(var_array)) << b->error();
-  EXPECT_TRUE(b->GenerateGlobalVariable(var_struct)) << b->error();
-  ASSERT_FALSE(b->has_error()) << b->error();
+    EXPECT_TRUE(b->GenerateGlobalVariable(var_scalar)) << b->error();
+    EXPECT_TRUE(b->GenerateGlobalVariable(var_array)) << b->error();
+    EXPECT_TRUE(b->GenerateGlobalVariable(var_struct)) << b->error();
+    ASSERT_FALSE(b->has_error()) << b->error();
 
-  EXPECT_EQ(DumpInstructions(b->types()), R"(%3 = OpTypeInt 32 1
+    EXPECT_EQ(DumpInstructions(b->types()), R"(%3 = OpTypeInt 32 1
 %2 = OpTypePointer Workgroup %3
 %4 = OpConstantNull %3
 %1 = OpVariable %2 Workgroup %4
diff --git a/src/tint/writer/spirv/builder_ident_expression_test.cc b/src/tint/writer/spirv/builder_ident_expression_test.cc
index 48d35a3..540b5c1 100644
--- a/src/tint/writer/spirv/builder_ident_expression_test.cc
+++ b/src/tint/writer/spirv/builder_ident_expression_test.cc
@@ -15,145 +15,145 @@
 #include "src/tint/writer/spirv/spv_dump.h"
 #include "src/tint/writer/spirv/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::spirv {
 namespace {
 
 using BuilderTest = TestHelper;
 
 TEST_F(BuilderTest, IdentifierExpression_GlobalConst) {
-  auto* init = vec3<f32>(1.f, 1.f, 3.f);
+    auto* init = vec3<f32>(1.f, 1.f, 3.f);
 
-  auto* v = GlobalConst("var", ty.vec3<f32>(), init);
+    auto* v = GlobalConst("var", ty.vec3<f32>(), init);
 
-  auto* expr = Expr("var");
-  WrapInFunction(expr);
+    auto* expr = Expr("var");
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
-  ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 3
 %3 = OpConstant %2 1
 %4 = OpConstant %2 3
 %5 = OpConstantComposite %1 %3 %3 %4
 )");
 
-  EXPECT_EQ(b.GenerateIdentifierExpression(expr), 5u);
+    EXPECT_EQ(b.GenerateIdentifierExpression(expr), 5u);
 }
 
 TEST_F(BuilderTest, IdentifierExpression_GlobalVar) {
-  auto* v = Global("var", ty.f32(), ast::StorageClass::kPrivate);
+    auto* v = Global("var", ty.f32(), ast::StorageClass::kPrivate);
 
-  auto* expr = Expr("var");
-  WrapInFunction(expr);
+    auto* expr = Expr("var");
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "var"
+    b.push_function(Function{});
+    EXPECT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "var"
 )");
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
 %2 = OpTypePointer Private %3
 %4 = OpConstantNull %3
 %1 = OpVariable %2 Private %4
 )");
 
-  EXPECT_EQ(b.GenerateIdentifierExpression(expr), 1u);
+    EXPECT_EQ(b.GenerateIdentifierExpression(expr), 1u);
 }
 
 TEST_F(BuilderTest, IdentifierExpression_FunctionConst) {
-  auto* init = vec3<f32>(1.f, 1.f, 3.f);
+    auto* init = vec3<f32>(1.f, 1.f, 3.f);
 
-  auto* v = Const("var", ty.vec3<f32>(), init);
+    auto* v = Let("var", ty.vec3<f32>(), init);
 
-  auto* expr = Expr("var");
-  WrapInFunction(v, expr);
+    auto* expr = Expr("var");
+    WrapInFunction(v, expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_TRUE(b.GenerateFunctionVariable(v)) << b.error();
-  ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_TRUE(b.GenerateFunctionVariable(v)) << b.error();
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 3
 %3 = OpConstant %2 1
 %4 = OpConstant %2 3
 %5 = OpConstantComposite %1 %3 %3 %4
 )");
 
-  EXPECT_EQ(b.GenerateIdentifierExpression(expr), 5u);
+    EXPECT_EQ(b.GenerateIdentifierExpression(expr), 5u);
 }
 
 TEST_F(BuilderTest, IdentifierExpression_FunctionVar) {
-  auto* v = Var("var", ty.f32(), ast::StorageClass::kFunction);
-  auto* expr = Expr("var");
-  WrapInFunction(v, expr);
+    auto* v = Var("var", ty.f32(), ast::StorageClass::kFunction);
+    auto* expr = Expr("var");
+    WrapInFunction(v, expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_TRUE(b.GenerateFunctionVariable(v)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "var"
+    b.push_function(Function{});
+    EXPECT_TRUE(b.GenerateFunctionVariable(v)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "var"
 )");
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
 %2 = OpTypePointer Function %3
 %4 = OpConstantNull %3
 )");
 
-  const auto& func = b.functions()[0];
-  EXPECT_EQ(DumpInstructions(func.variables()),
-            R"(%1 = OpVariable %2 Function %4
+    const auto& func = b.functions()[0];
+    EXPECT_EQ(DumpInstructions(func.variables()),
+              R"(%1 = OpVariable %2 Function %4
 )");
 
-  EXPECT_EQ(b.GenerateIdentifierExpression(expr), 1u);
+    EXPECT_EQ(b.GenerateIdentifierExpression(expr), 1u);
 }
 
 TEST_F(BuilderTest, IdentifierExpression_Load) {
-  auto* var = Global("var", ty.i32(), ast::StorageClass::kPrivate);
+    auto* var = Global("var", ty.i32(), ast::StorageClass::kPrivate);
 
-  auto* expr = Add("var", "var");
-  WrapInFunction(expr);
+    auto* expr = Add("var", "var");
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
 
-  EXPECT_EQ(b.GenerateBinaryExpression(expr->As<ast::BinaryExpression>()), 7u)
-      << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeInt 32 1
+    EXPECT_EQ(b.GenerateBinaryExpression(expr->As<ast::BinaryExpression>()), 7u) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeInt 32 1
 %2 = OpTypePointer Private %3
 %4 = OpConstantNull %3
 %1 = OpVariable %2 Private %4
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%5 = OpLoad %3 %1
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%5 = OpLoad %3 %1
 %6 = OpLoad %3 %1
 %7 = OpIAdd %3 %5 %6
 )");
 }
 
 TEST_F(BuilderTest, IdentifierExpression_NoLoadConst) {
-  auto* var = GlobalConst("var", ty.i32(), Expr(2));
+    auto* var = GlobalConst("var", ty.i32(), Expr(2_i));
 
-  auto* expr = Add("var", "var");
-  WrapInFunction(expr);
+    auto* expr = Add("var", "var");
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
 
-  EXPECT_EQ(b.GenerateBinaryExpression(expr->As<ast::BinaryExpression>()), 3u)
-      << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 1
+    EXPECT_EQ(b.GenerateBinaryExpression(expr->As<ast::BinaryExpression>()), 3u) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 1
 %2 = OpConstant %1 2
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%3 = OpIAdd %1 %2 %2
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%3 = OpIAdd %1 %2 %2
 )");
 }
 
diff --git a/src/tint/writer/spirv/builder_if_test.cc b/src/tint/writer/spirv/builder_if_test.cc
index 661bbd8..a32f409 100644
--- a/src/tint/writer/spirv/builder_if_test.cc
+++ b/src/tint/writer/spirv/builder_if_test.cc
@@ -15,27 +15,29 @@
 #include "src/tint/writer/spirv/spv_dump.h"
 #include "src/tint/writer/spirv/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::spirv {
 namespace {
 
 using BuilderTest = TestHelper;
 
 TEST_F(BuilderTest, If_Empty) {
-  // if (true) {
-  // }
-  auto* expr = If(true, Block());
-  WrapInFunction(expr);
+    // if (true) {
+    // }
+    auto* expr = If(true, Block());
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_TRUE(b.GenerateIfStatement(expr)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeBool
+    EXPECT_TRUE(b.GenerateIfStatement(expr)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeBool
 %2 = OpConstantTrue %1
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(OpSelectionMerge %3 None
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpSelectionMerge %3 None
 OpBranchConditional %2 %4 %3
 %4 = OpLabel
 OpBranch %3
@@ -44,40 +46,40 @@
 }
 
 TEST_F(BuilderTest, If_Empty_OutsideFunction_IsError) {
-  // Outside a function.
-  // if (true) {
-  // }
+    // Outside a function.
+    // if (true) {
+    // }
 
-  auto* block = Block();
-  auto* expr = If(true, block);
-  WrapInFunction(expr);
+    auto* block = Block();
+    auto* expr = If(true, block);
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_FALSE(b.GenerateIfStatement(expr)) << b.error();
-  EXPECT_TRUE(b.has_error());
-  EXPECT_EQ(b.error(),
-            "Internal error: trying to add SPIR-V instruction 247 outside a "
-            "function");
+    EXPECT_FALSE(b.GenerateIfStatement(expr)) << b.error();
+    EXPECT_TRUE(b.has_error());
+    EXPECT_EQ(b.error(),
+              "Internal error: trying to add SPIR-V instruction 247 outside a "
+              "function");
 }
 
 TEST_F(BuilderTest, If_WithStatements) {
-  // if (true) {
-  //   v = 2;
-  // }
+    // if (true) {
+    //   v = 2;
+    // }
 
-  auto* var = Global("v", ty.i32(), ast::StorageClass::kPrivate);
-  auto* body = Block(Assign("v", 2));
-  auto* expr = If(true, body);
-  WrapInFunction(expr);
+    auto* var = Global("v", ty.i32(), ast::StorageClass::kPrivate);
+    auto* body = Block(Assign("v", 2_i));
+    auto* expr = If(true, body);
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
 
-  EXPECT_TRUE(b.GenerateIfStatement(expr)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeInt 32 1
+    EXPECT_TRUE(b.GenerateIfStatement(expr)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeInt 32 1
 %2 = OpTypePointer Private %3
 %4 = OpConstantNull %3
 %1 = OpVariable %2 Private %4
@@ -85,8 +87,8 @@
 %6 = OpConstantTrue %5
 %9 = OpConstant %3 2
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(OpSelectionMerge %7 None
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpSelectionMerge %7 None
 OpBranchConditional %6 %8 %7
 %8 = OpLabel
 OpStore %1 %9
@@ -96,26 +98,26 @@
 }
 
 TEST_F(BuilderTest, If_WithElse) {
-  // if (true) {
-  //   v = 2;
-  // } else {
-  //   v = 3;
-  // }
+    // if (true) {
+    //   v = 2i;
+    // } else {
+    //   v = 3i;
+    // }
 
-  auto* var = Global("v", ty.i32(), ast::StorageClass::kPrivate);
-  auto* body = Block(Assign("v", 2));
-  auto* else_body = Block(Assign("v", 3));
+    auto* var = Global("v", ty.i32(), ast::StorageClass::kPrivate);
+    auto* body = Block(Assign("v", 2_i));
+    auto* else_body = Block(Assign("v", 3_i));
 
-  auto* expr = If(true, body, Else(else_body));
-  WrapInFunction(expr);
+    auto* expr = If(true, body, Else(else_body));
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
 
-  EXPECT_TRUE(b.GenerateIfStatement(expr)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeInt 32 1
+    EXPECT_TRUE(b.GenerateIfStatement(expr)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeInt 32 1
 %2 = OpTypePointer Private %3
 %4 = OpConstantNull %3
 %1 = OpVariable %2 Private %4
@@ -124,8 +126,8 @@
 %10 = OpConstant %3 2
 %11 = OpConstant %3 3
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(OpSelectionMerge %7 None
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpSelectionMerge %7 None
 OpBranchConditional %6 %8 %9
 %8 = OpLabel
 OpStore %1 %10
@@ -138,26 +140,26 @@
 }
 
 TEST_F(BuilderTest, If_WithElseIf) {
-  // if (true) {
-  //   v = 2;
-  // } else if (true) {
-  //   v = 3;
-  // }
+    // if (true) {
+    //   v = 2i;
+    // } else if (true) {
+    //   v = 3i;
+    // }
 
-  auto* var = Global("v", ty.i32(), ast::StorageClass::kPrivate);
-  auto* body = Block(Assign("v", 2));
-  auto* else_body = Block(Assign("v", 3));
+    auto* var = Global("v", ty.i32(), ast::StorageClass::kPrivate);
+    auto* body = Block(Assign("v", 2_i));
+    auto* else_body = Block(Assign("v", 3_i));
 
-  auto* expr = If(true, body, Else(true, else_body));
-  WrapInFunction(expr);
+    auto* expr = If(true, body, Else(If(true, else_body)));
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
 
-  EXPECT_TRUE(b.GenerateIfStatement(expr)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeInt 32 1
+    EXPECT_TRUE(b.GenerateIfStatement(expr)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeInt 32 1
 %2 = OpTypePointer Private %3
 %4 = OpConstantNull %3
 %1 = OpVariable %2 Private %4
@@ -166,8 +168,8 @@
 %10 = OpConstant %3 2
 %13 = OpConstant %3 3
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(OpSelectionMerge %7 None
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpSelectionMerge %7 None
 OpBranchConditional %6 %8 %9
 %8 = OpLabel
 OpStore %1 %10
@@ -185,35 +187,35 @@
 }
 
 TEST_F(BuilderTest, If_WithMultiple) {
-  // if (true) {
-  //   v = 2;
-  // } else if (true) {
-  //   v = 3;
-  // } else if (false) {
-  //   v = 4;
-  // } else {
-  //   v = 5;
-  // }
+    // if (true) {
+    //   v = 2i;
+    // } else if (true) {
+    //   v = 3i;
+    // } else if (false) {
+    //   v = 4i;
+    // } else {
+    //   v = 5i;
+    // }
 
-  auto* var = Global("v", ty.i32(), ast::StorageClass::kPrivate);
-  auto* body = Block(Assign("v", 2));
-  auto* elseif_1_body = Block(Assign("v", 3));
-  auto* elseif_2_body = Block(Assign("v", 4));
-  auto* else_body = Block(Assign("v", 5));
+    auto* var = Global("v", ty.i32(), ast::StorageClass::kPrivate);
+    auto* body = Block(Assign("v", 2_i));
+    auto* elseif_1_body = Block(Assign("v", 3_i));
+    auto* elseif_2_body = Block(Assign("v", 4_i));
+    auto* else_body = Block(Assign("v", 5_i));
 
-  auto* expr = If(true, body,                  //
-                  Else(true, elseif_1_body),   //
-                  Else(false, elseif_2_body),  //
-                  Else(else_body));
-  WrapInFunction(expr);
+    auto* expr = If(true, body,                            //
+                    Else(If(true, elseif_1_body,           //
+                            Else(If(false, elseif_2_body,  //
+                                    Else(else_body))))));
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
 
-  EXPECT_TRUE(b.GenerateIfStatement(expr)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeInt 32 1
+    EXPECT_TRUE(b.GenerateIfStatement(expr)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeInt 32 1
 %2 = OpTypePointer Private %3
 %4 = OpConstantNull %3
 %1 = OpVariable %2 Private %4
@@ -225,8 +227,8 @@
 %19 = OpConstant %3 4
 %20 = OpConstant %3 5
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(OpSelectionMerge %7 None
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpSelectionMerge %7 None
 OpBranchConditional %6 %8 %9
 %8 = OpLabel
 OpStore %1 %10
@@ -255,31 +257,31 @@
 }
 
 TEST_F(BuilderTest, If_WithBreak) {
-  // loop {
-  //   if (true) {
-  //     break;
-  //   }
-  // }
+    // loop {
+    //   if (true) {
+    //     break;
+    //   }
+    // }
 
-  auto* if_body = Block(Break());
+    auto* if_body = Block(Break());
 
-  auto* if_stmt = If(true, if_body);
+    auto* if_stmt = If(true, if_body);
 
-  auto* loop_body = Block(if_stmt);
+    auto* loop_body = Block(if_stmt);
 
-  auto* expr = Loop(loop_body, Block());
-  WrapInFunction(expr);
+    auto* expr = Loop(loop_body, Block());
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_TRUE(b.GenerateLoopStatement(expr)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeBool
+    EXPECT_TRUE(b.GenerateLoopStatement(expr)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeBool
 %6 = OpConstantTrue %5
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(OpBranch %1
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpBranch %1
 %1 = OpLabel
 OpLoopMerge %2 %3 None
 OpBranch %4
@@ -297,31 +299,31 @@
 }
 
 TEST_F(BuilderTest, If_WithElseBreak) {
-  // loop {
-  //   if (true) {
-  //   } else {
-  //     break;
-  //   }
-  // }
-  auto* else_body = Block(Break());
+    // loop {
+    //   if (true) {
+    //   } else {
+    //     break;
+    //   }
+    // }
+    auto* else_body = Block(Break());
 
-  auto* if_stmt = If(true, Block(), Else(else_body));
+    auto* if_stmt = If(true, Block(), Else(else_body));
 
-  auto* loop_body = Block(if_stmt);
+    auto* loop_body = Block(if_stmt);
 
-  auto* expr = Loop(loop_body, Block());
-  WrapInFunction(expr);
+    auto* expr = Loop(loop_body, Block());
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_TRUE(b.GenerateLoopStatement(expr)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeBool
+    EXPECT_TRUE(b.GenerateLoopStatement(expr)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeBool
 %6 = OpConstantTrue %5
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(OpBranch %1
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpBranch %1
 %1 = OpLabel
 OpLoopMerge %2 %3 None
 OpBranch %4
@@ -341,29 +343,29 @@
 }
 
 TEST_F(BuilderTest, If_WithContinueAndBreak) {
-  // loop {
-  //   if (true) {
-  //     continue;
-  //   } else {
-  //     break;
-  //   }
-  // }
+    // loop {
+    //   if (true) {
+    //     continue;
+    //   } else {
+    //     break;
+    //   }
+    // }
 
-  auto* if_stmt = If(true, Block(Continue()), Else(Block(Break())));
+    auto* if_stmt = If(true, Block(Continue()), Else(Block(Break())));
 
-  auto* expr = Loop(Block(if_stmt), Block());
-  WrapInFunction(expr);
+    auto* expr = Loop(Block(if_stmt), Block());
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_TRUE(b.GenerateLoopStatement(expr)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeBool
+    EXPECT_TRUE(b.GenerateLoopStatement(expr)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeBool
 %6 = OpConstantTrue %5
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(OpBranch %1
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpBranch %1
 %1 = OpLabel
 OpLoopMerge %2 %3 None
 OpBranch %4
@@ -383,32 +385,32 @@
 }
 
 TEST_F(BuilderTest, If_WithElseContinue) {
-  // loop {
-  //   if (true) {
-  //   } else {
-  //     continue;
-  //   }
-  //   break;
-  // }
-  auto* else_body = Block(create<ast::ContinueStatement>());
+    // loop {
+    //   if (true) {
+    //   } else {
+    //     continue;
+    //   }
+    //   break;
+    // }
+    auto* else_body = Block(create<ast::ContinueStatement>());
 
-  auto* if_stmt = If(true, Block(), Else(else_body));
+    auto* if_stmt = If(true, Block(), Else(else_body));
 
-  auto* loop_body = Block(if_stmt, Break());
+    auto* loop_body = Block(if_stmt, Break());
 
-  auto* expr = Loop(loop_body, Block());
-  WrapInFunction(expr);
+    auto* expr = Loop(loop_body, Block());
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_TRUE(b.GenerateLoopStatement(expr)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeBool
+    EXPECT_TRUE(b.GenerateLoopStatement(expr)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeBool
 %6 = OpConstantTrue %5
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(OpBranch %1
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpBranch %1
 %1 = OpLabel
 OpLoopMerge %2 %3 None
 OpBranch %4
@@ -428,22 +430,22 @@
 }
 
 TEST_F(BuilderTest, If_WithReturn) {
-  // if (true) {
-  //   return;
-  // }
+    // if (true) {
+    //   return;
+    // }
 
-  auto* fn = Func("f", {}, ty.void_(), {If(true, Block(Return()))});
+    auto* fn = Func("f", {}, ty.void_(), {If(true, Block(Return()))});
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_TRUE(b.GenerateFunction(fn)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+    EXPECT_TRUE(b.GenerateFunction(fn)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
 %1 = OpTypeFunction %2
 %5 = OpTypeBool
 %6 = OpConstantTrue %5
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(OpSelectionMerge %7 None
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpSelectionMerge %7 None
 OpBranchConditional %6 %8 %7
 %8 = OpLabel
 OpReturn
@@ -453,27 +455,27 @@
 }
 
 TEST_F(BuilderTest, If_WithReturnValue) {
-  // if (true) {
-  //   return false;
-  // }
-  // return true;
+    // if (true) {
+    //   return false;
+    // }
+    // return true;
 
-  auto* fn = Func("f", {}, ty.bool_(),
-                  {
-                      If(true, Block(Return(false))),
-                      Return(true),
-                  });
+    auto* fn = Func("f", {}, ty.bool_(),
+                    {
+                        If(true, Block(Return(false))),
+                        Return(true),
+                    });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_TRUE(b.GenerateFunction(fn)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeBool
+    EXPECT_TRUE(b.GenerateFunction(fn)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeBool
 %1 = OpTypeFunction %2
 %5 = OpConstantTrue %2
 %8 = OpConstantFalse %2
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(OpSelectionMerge %6 None
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpSelectionMerge %6 None
 OpBranchConditional %5 %7 %6
 %7 = OpLabel
 OpReturnValue %8
@@ -483,29 +485,29 @@
 }
 
 TEST_F(BuilderTest, IfElse_BothReturn) {
-  // if (true) {
-  //   return true;
-  // } else {
-  //   return true;
-  // }
+    // if (true) {
+    //   return true;
+    // } else {
+    //   return true;
+    // }
 
-  auto* fn = Func("f", {}, ty.bool_(),
-                  {
-                      If(true,                 //
-                         Block(Return(true)),  //
-                         Else(Block(Return(true)))),
-                  });
+    auto* fn = Func("f", {}, ty.bool_(),
+                    {
+                        If(true,                 //
+                           Block(Return(true)),  //
+                           Else(Block(Return(true)))),
+                    });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_TRUE(b.GenerateFunction(fn)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeBool
+    EXPECT_TRUE(b.GenerateFunction(fn)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeBool
 %1 = OpTypeFunction %2
 %5 = OpConstantTrue %2
 %9 = OpConstantNull %2
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(OpSelectionMerge %6 None
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpSelectionMerge %6 None
 OpBranchConditional %5 %7 %8
 %7 = OpLabel
 OpReturnValue %5
@@ -517,33 +519,33 @@
 }
 
 TEST_F(BuilderTest, If_WithNestedBlockReturnValue) {
-  // if (true) {
-  //  {
-  //    {
-  //      {
-  //        return false;
-  //      }
-  //    }
-  //  }
-  // }
-  // return true;
+    // if (true) {
+    //  {
+    //    {
+    //      {
+    //        return false;
+    //      }
+    //    }
+    //  }
+    // }
+    // return true;
 
-  auto* fn = Func("f", {}, ty.bool_(),
-                  {
-                      If(true, Block(Block(Block(Block(Return(false)))))),
-                      Return(true),
-                  });
+    auto* fn = Func("f", {}, ty.bool_(),
+                    {
+                        If(true, Block(Block(Block(Block(Return(false)))))),
+                        Return(true),
+                    });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_TRUE(b.GenerateFunction(fn)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeBool
+    EXPECT_TRUE(b.GenerateFunction(fn)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeBool
 %1 = OpTypeFunction %2
 %5 = OpConstantTrue %2
 %8 = OpConstantFalse %2
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(OpSelectionMerge %6 None
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpSelectionMerge %6 None
 OpBranchConditional %5 %7 %6
 %7 = OpLabel
 OpReturnValue %8
@@ -553,26 +555,26 @@
 }
 
 TEST_F(BuilderTest, If_WithLoad_Bug327) {
-  // var a : bool;
-  // if (a) {
-  // }
+    // var a : bool;
+    // if (a) {
+    // }
 
-  auto* var = Global("a", ty.bool_(), ast::StorageClass::kPrivate);
-  auto* fn = Func("f", {}, ty.void_(), {If("a", Block())});
+    auto* var = Global("a", ty.bool_(), ast::StorageClass::kPrivate);
+    auto* fn = Func("f", {}, ty.void_(), {If("a", Block())});
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
-  EXPECT_TRUE(b.GenerateFunction(fn)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeBool
+    ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+    EXPECT_TRUE(b.GenerateFunction(fn)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeBool
 %2 = OpTypePointer Private %3
 %4 = OpConstantNull %3
 %1 = OpVariable %2 Private %4
 %6 = OpTypeVoid
 %5 = OpTypeFunction %6
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%9 = OpLoad %3 %1
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%9 = OpLoad %3 %1
 OpSelectionMerge %10 None
 OpBranchConditional %9 %11 %10
 %11 = OpLabel
@@ -583,26 +585,26 @@
 }
 
 TEST_F(BuilderTest, If_ElseIf_WithReturn) {
-  // crbug.com/tint/1315
-  // if (false) {
-  // } else if (true) {
-  //   return;
-  // }
+    // crbug.com/tint/1315
+    // if (false) {
+    // } else if (true) {
+    //   return;
+    // }
 
-  auto* if_stmt = If(false, Block(), Else(true, Block(Return())));
-  auto* fn = Func("f", {}, ty.void_(), {if_stmt});
+    auto* if_stmt = If(false, Block(), Else(If(true, Block(Return()))));
+    auto* fn = Func("f", {}, ty.void_(), {if_stmt});
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_TRUE(b.GenerateFunction(fn)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+    EXPECT_TRUE(b.GenerateFunction(fn)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
 %1 = OpTypeFunction %2
 %5 = OpTypeBool
 %6 = OpConstantFalse %5
 %10 = OpConstantTrue %5
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(OpSelectionMerge %7 None
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpSelectionMerge %7 None
 OpBranchConditional %6 %8 %9
 %8 = OpLabel
 OpBranch %7
@@ -619,28 +621,28 @@
 }
 
 TEST_F(BuilderTest, Loop_If_ElseIf_WithBreak) {
-  // crbug.com/tint/1315
-  // loop {
-  //   if (false) {
-  //   } else if (true) {
-  //     break;
-  //   }
-  // }
+    // crbug.com/tint/1315
+    // loop {
+    //   if (false) {
+    //   } else if (true) {
+    //     break;
+    //   }
+    // }
 
-  auto* if_stmt = If(false, Block(), Else(true, Block(Break())));
-  auto* fn = Func("f", {}, ty.void_(), {Loop(Block(if_stmt))});
+    auto* if_stmt = If(false, Block(), Else(If(true, Block(Break()))));
+    auto* fn = Func("f", {}, ty.void_(), {Loop(Block(if_stmt))});
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_TRUE(b.GenerateFunction(fn)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
+    EXPECT_TRUE(b.GenerateFunction(fn)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
 %1 = OpTypeFunction %2
 %9 = OpTypeBool
 %10 = OpConstantFalse %9
 %14 = OpConstantTrue %9
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(OpBranch %5
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpBranch %5
 %5 = OpLabel
 OpLoopMerge %6 %7 None
 OpBranch %8
diff --git a/src/tint/writer/spirv/builder_literal_test.cc b/src/tint/writer/spirv/builder_literal_test.cc
index 49378ef..d8a0311 100644
--- a/src/tint/writer/spirv/builder_literal_test.cc
+++ b/src/tint/writer/spirv/builder_literal_test.cc
@@ -15,148 +15,150 @@
 #include "src/tint/writer/spirv/spv_dump.h"
 #include "src/tint/writer/spirv/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::spirv {
 
 using BuilderTest = TestHelper;
 
 TEST_F(BuilderTest, Literal_Bool_True) {
-  auto* b_true = create<ast::BoolLiteralExpression>(true);
-  WrapInFunction(b_true);
+    auto* b_true = create<ast::BoolLiteralExpression>(true);
+    WrapInFunction(b_true);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  auto id = b.GenerateLiteralIfNeeded(nullptr, b_true);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(2u, id);
+    auto id = b.GenerateLiteralIfNeeded(nullptr, b_true);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(2u, id);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeBool
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeBool
 %2 = OpConstantTrue %1
 )");
 }
 
 TEST_F(BuilderTest, Literal_Bool_False) {
-  auto* b_false = create<ast::BoolLiteralExpression>(false);
-  WrapInFunction(b_false);
+    auto* b_false = create<ast::BoolLiteralExpression>(false);
+    WrapInFunction(b_false);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  auto id = b.GenerateLiteralIfNeeded(nullptr, b_false);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(2u, id);
+    auto id = b.GenerateLiteralIfNeeded(nullptr, b_false);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(2u, id);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeBool
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeBool
 %2 = OpConstantFalse %1
 )");
 }
 
 TEST_F(BuilderTest, Literal_Bool_Dedup) {
-  auto* b_true = create<ast::BoolLiteralExpression>(true);
-  auto* b_false = create<ast::BoolLiteralExpression>(false);
-  WrapInFunction(b_true, b_false);
+    auto* b_true = create<ast::BoolLiteralExpression>(true);
+    auto* b_false = create<ast::BoolLiteralExpression>(false);
+    WrapInFunction(b_true, b_false);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_NE(b.GenerateLiteralIfNeeded(nullptr, b_true), 0u);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  ASSERT_NE(b.GenerateLiteralIfNeeded(nullptr, b_false), 0u);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  ASSERT_NE(b.GenerateLiteralIfNeeded(nullptr, b_true), 0u);
-  ASSERT_FALSE(b.has_error()) << b.error();
+    ASSERT_NE(b.GenerateLiteralIfNeeded(nullptr, b_true), 0u);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    ASSERT_NE(b.GenerateLiteralIfNeeded(nullptr, b_false), 0u);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    ASSERT_NE(b.GenerateLiteralIfNeeded(nullptr, b_true), 0u);
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeBool
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeBool
 %2 = OpConstantTrue %1
 %3 = OpConstantFalse %1
 )");
 }
 
 TEST_F(BuilderTest, Literal_I32) {
-  auto* i = create<ast::SintLiteralExpression>(-23);
-  WrapInFunction(i);
-  spirv::Builder& b = Build();
+    auto* i = Expr(i32(-23));
+    WrapInFunction(i);
+    spirv::Builder& b = Build();
 
-  auto id = b.GenerateLiteralIfNeeded(nullptr, i);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(2u, id);
+    auto id = b.GenerateLiteralIfNeeded(nullptr, i);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(2u, id);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 1
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 1
 %2 = OpConstant %1 -23
 )");
 }
 
 TEST_F(BuilderTest, Literal_I32_Dedup) {
-  auto* i1 = create<ast::SintLiteralExpression>(-23);
-  auto* i2 = create<ast::SintLiteralExpression>(-23);
-  WrapInFunction(i1, i2);
+    auto* i1 = Expr(i32(-23));
+    auto* i2 = Expr(i32(-23));
+    WrapInFunction(i1, i2);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_NE(b.GenerateLiteralIfNeeded(nullptr, i1), 0u);
-  ASSERT_NE(b.GenerateLiteralIfNeeded(nullptr, i2), 0u);
-  ASSERT_FALSE(b.has_error()) << b.error();
+    ASSERT_NE(b.GenerateLiteralIfNeeded(nullptr, i1), 0u);
+    ASSERT_NE(b.GenerateLiteralIfNeeded(nullptr, i2), 0u);
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 1
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 1
 %2 = OpConstant %1 -23
 )");
 }
 
 TEST_F(BuilderTest, Literal_U32) {
-  auto* i = create<ast::UintLiteralExpression>(23);
-  WrapInFunction(i);
+    auto* i = Expr(23_u);
+    WrapInFunction(i);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  auto id = b.GenerateLiteralIfNeeded(nullptr, i);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(2u, id);
+    auto id = b.GenerateLiteralIfNeeded(nullptr, i);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(2u, id);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 0
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 0
 %2 = OpConstant %1 23
 )");
 }
 
 TEST_F(BuilderTest, Literal_U32_Dedup) {
-  auto* i1 = create<ast::UintLiteralExpression>(23);
-  auto* i2 = create<ast::UintLiteralExpression>(23);
-  WrapInFunction(i1, i2);
+    auto* i1 = Expr(23_u);
+    auto* i2 = Expr(23_u);
+    WrapInFunction(i1, i2);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_NE(b.GenerateLiteralIfNeeded(nullptr, i1), 0u);
-  ASSERT_NE(b.GenerateLiteralIfNeeded(nullptr, i2), 0u);
-  ASSERT_FALSE(b.has_error()) << b.error();
+    ASSERT_NE(b.GenerateLiteralIfNeeded(nullptr, i1), 0u);
+    ASSERT_NE(b.GenerateLiteralIfNeeded(nullptr, i2), 0u);
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 0
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeInt 32 0
 %2 = OpConstant %1 23
 )");
 }
 
 TEST_F(BuilderTest, Literal_F32) {
-  auto* i = create<ast::FloatLiteralExpression>(23.245f);
-  WrapInFunction(i);
+    auto* i = create<ast::FloatLiteralExpression>(23.245f);
+    WrapInFunction(i);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  auto id = b.GenerateLiteralIfNeeded(nullptr, i);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(2u, id);
+    auto id = b.GenerateLiteralIfNeeded(nullptr, i);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(2u, id);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32
 %2 = OpConstant %1 23.2450008
 )");
 }
 
 TEST_F(BuilderTest, Literal_F32_Dedup) {
-  auto* i1 = create<ast::FloatLiteralExpression>(23.245f);
-  auto* i2 = create<ast::FloatLiteralExpression>(23.245f);
-  WrapInFunction(i1, i2);
+    auto* i1 = create<ast::FloatLiteralExpression>(23.245f);
+    auto* i2 = create<ast::FloatLiteralExpression>(23.245f);
+    WrapInFunction(i1, i2);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_NE(b.GenerateLiteralIfNeeded(nullptr, i1), 0u);
-  ASSERT_NE(b.GenerateLiteralIfNeeded(nullptr, i2), 0u);
-  ASSERT_FALSE(b.has_error()) << b.error();
+    ASSERT_NE(b.GenerateLiteralIfNeeded(nullptr, i1), 0u);
+    ASSERT_NE(b.GenerateLiteralIfNeeded(nullptr, i2), 0u);
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%1 = OpTypeFloat 32
 %2 = OpConstant %1 23.2450008
 )");
 }
diff --git a/src/tint/writer/spirv/builder_loop_test.cc b/src/tint/writer/spirv/builder_loop_test.cc
index 555c167..b4c2baa 100644
--- a/src/tint/writer/spirv/builder_loop_test.cc
+++ b/src/tint/writer/spirv/builder_loop_test.cc
@@ -15,26 +15,28 @@
 #include "src/tint/writer/spirv/spv_dump.h"
 #include "src/tint/writer/spirv/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::spirv {
 namespace {
 
 using BuilderTest = TestHelper;
 
 TEST_F(BuilderTest, Loop_Empty) {
-  // loop {
-  //   break;
-  // }
+    // loop {
+    //   break;
+    // }
 
-  auto* loop = Loop(Block(Break()), Block());
-  WrapInFunction(loop);
+    auto* loop = Loop(Block(Break()), Block());
+    WrapInFunction(loop);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_TRUE(b.GenerateLoopStatement(loop)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(OpBranch %1
+    EXPECT_TRUE(b.GenerateLoopStatement(loop)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpBranch %1
 %1 = OpLabel
 OpLoopMerge %2 %3 None
 OpBranch %4
@@ -47,32 +49,32 @@
 }
 
 TEST_F(BuilderTest, Loop_WithoutContinuing) {
-  // loop {
-  //   v = 2;
-  //   break;
-  // }
+    // loop {
+    //   v = 2i;
+    //   break;
+    // }
 
-  auto* var = Global("v", ty.i32(), ast::StorageClass::kPrivate);
-  auto* body = Block(Assign("v", 2),  //
-                     Break());
+    auto* var = Global("v", ty.i32(), ast::StorageClass::kPrivate);
+    auto* body = Block(Assign("v", 2_i),  //
+                       Break());
 
-  auto* loop = Loop(body, Block());
-  WrapInFunction(loop);
+    auto* loop = Loop(body, Block());
+    WrapInFunction(loop);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
 
-  EXPECT_TRUE(b.GenerateLoopStatement(loop)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeInt 32 1
+    EXPECT_TRUE(b.GenerateLoopStatement(loop)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeInt 32 1
 %2 = OpTypePointer Private %3
 %4 = OpConstantNull %3
 %1 = OpVariable %2 Private %4
 %9 = OpConstant %3 2
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(OpBranch %5
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpBranch %5
 %5 = OpLabel
 OpLoopMerge %6 %7 None
 OpBranch %8
@@ -86,37 +88,37 @@
 }
 
 TEST_F(BuilderTest, Loop_WithContinuing) {
-  // loop {
-  //   a = 2;
-  //   break;
-  //   continuing {
-  //     a = 3;
-  //   }
-  // }
+    // loop {
+    //   a = 2i;
+    //   break;
+    //   continuing {
+    //     a = 3i;
+    //   }
+    // }
 
-  auto* var = Global("v", ty.i32(), ast::StorageClass::kPrivate);
-  auto* body = Block(Assign("v", 2),  //
-                     Break());
-  auto* continuing = Block(Assign("v", 3));
+    auto* var = Global("v", ty.i32(), ast::StorageClass::kPrivate);
+    auto* body = Block(Assign("v", 2_i),  //
+                       Break());
+    auto* continuing = Block(Assign("v", 3_i));
 
-  auto* loop = Loop(body, continuing);
-  WrapInFunction(loop);
+    auto* loop = Loop(body, continuing);
+    WrapInFunction(loop);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
+    b.push_function(Function{});
+    ASSERT_TRUE(b.GenerateGlobalVariable(var)) << b.error();
 
-  EXPECT_TRUE(b.GenerateLoopStatement(loop)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeInt 32 1
+    EXPECT_TRUE(b.GenerateLoopStatement(loop)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeInt 32 1
 %2 = OpTypePointer Private %3
 %4 = OpConstantNull %3
 %1 = OpVariable %2 Private %4
 %9 = OpConstant %3 2
 %10 = OpConstant %3 3
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(OpBranch %5
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpBranch %5
 %5 = OpLabel
 OpLoopMerge %6 %7 None
 OpBranch %8
@@ -131,33 +133,33 @@
 }
 
 TEST_F(BuilderTest, Loop_WithBodyVariableAccessInContinuing) {
-  // loop {
-  //   var a : i32;
-  //   break;
-  //   continuing {
-  //     a = 3;
-  //   }
-  // }
+    // loop {
+    //   var a : i32;
+    //   break;
+    //   continuing {
+    //     a = 3i;
+    //   }
+    // }
 
-  auto* body = Block(Decl(Var("a", ty.i32())),  //
-                     Break());
-  auto* continuing = Block(Assign("a", 3));
+    auto* body = Block(Decl(Var("a", ty.i32())),  //
+                       Break());
+    auto* continuing = Block(Assign("a", 3_i));
 
-  auto* loop = Loop(body, continuing);
-  WrapInFunction(loop);
+    auto* loop = Loop(body, continuing);
+    WrapInFunction(loop);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_TRUE(b.GenerateLoopStatement(loop)) << b.error();
+    b.push_function(Function{});
+    EXPECT_TRUE(b.GenerateLoopStatement(loop)) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%7 = OpTypeInt 32 1
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%7 = OpTypeInt 32 1
 %6 = OpTypePointer Function %7
 %8 = OpConstantNull %7
 %9 = OpConstant %7 3
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(OpBranch %1
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpBranch %1
 %1 = OpLabel
 OpLoopMerge %2 %3 None
 OpBranch %4
@@ -171,22 +173,22 @@
 }
 
 TEST_F(BuilderTest, Loop_WithContinue) {
-  // loop {
-  //   if (false) { break; }
-  //   continue;
-  // }
-  auto* body = Block(If(false, Block(Break())),  //
-                     Continue());
-  auto* loop = Loop(body, Block());
-  WrapInFunction(loop);
+    // loop {
+    //   if (false) { break; }
+    //   continue;
+    // }
+    auto* body = Block(If(false, Block(Break())),  //
+                       Continue());
+    auto* loop = Loop(body, Block());
+    WrapInFunction(loop);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_TRUE(b.GenerateLoopStatement(loop)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(OpBranch %1
+    EXPECT_TRUE(b.GenerateLoopStatement(loop)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpBranch %1
 %1 = OpLabel
 OpLoopMerge %2 %3 None
 OpBranch %4
@@ -204,20 +206,20 @@
 }
 
 TEST_F(BuilderTest, Loop_WithBreak) {
-  // loop {
-  //   break;
-  // }
-  auto* body = Block(create<ast::BreakStatement>());
-  auto* loop = Loop(body, Block());
-  WrapInFunction(loop);
+    // loop {
+    //   break;
+    // }
+    auto* body = Block(create<ast::BreakStatement>());
+    auto* loop = Loop(body, Block());
+    WrapInFunction(loop);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_TRUE(b.GenerateLoopStatement(loop)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(OpBranch %1
+    EXPECT_TRUE(b.GenerateLoopStatement(loop)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpBranch %1
 %1 = OpLabel
 OpLoopMerge %2 %3 None
 OpBranch %4
@@ -230,28 +232,27 @@
 }
 
 TEST_F(BuilderTest, Loop_WithContinuing_BreakIf) {
-  // loop {
-  //   continuing {
-  //     if (true) { break; }
-  //   }
-  // }
+    // loop {
+    //   continuing {
+    //     if (true) { break; }
+    //   }
+    // }
 
-  auto* if_stmt = create<ast::IfStatement>(Expr(true), Block(Break()),
-                                           ast::ElseStatementList{});
-  auto* continuing = Block(if_stmt);
-  auto* loop = Loop(Block(), continuing);
-  WrapInFunction(loop);
+    auto* if_stmt = If(Expr(true), Block(Break()));
+    auto* continuing = Block(if_stmt);
+    auto* loop = Loop(Block(), continuing);
+    WrapInFunction(loop);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_TRUE(b.GenerateLoopStatement(loop)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeBool
+    EXPECT_TRUE(b.GenerateLoopStatement(loop)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeBool
 %6 = OpConstantTrue %5
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(OpBranch %1
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpBranch %1
 %1 = OpLabel
 OpLoopMerge %2 %3 None
 OpBranch %4
@@ -264,28 +265,26 @@
 }
 
 TEST_F(BuilderTest, Loop_WithContinuing_BreakUnless) {
-  // loop {
-  //   continuing {
-  //     if (true) {} else { break; }
-  //   }
-  // }
-  auto* if_stmt = create<ast::IfStatement>(
-      Expr(true), Block(),
-      ast::ElseStatementList{Else(nullptr, Block(Break()))});
-  auto* continuing = Block(if_stmt);
-  auto* loop = Loop(Block(), continuing);
-  WrapInFunction(loop);
+    // loop {
+    //   continuing {
+    //     if (true) {} else { break; }
+    //   }
+    // }
+    auto* if_stmt = If(Expr(true), Block(), Else(Block(Break())));
+    auto* continuing = Block(if_stmt);
+    auto* loop = Loop(Block(), continuing);
+    WrapInFunction(loop);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_TRUE(b.GenerateLoopStatement(loop)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeBool
+    EXPECT_TRUE(b.GenerateLoopStatement(loop)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeBool
 %6 = OpConstantTrue %5
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(OpBranch %1
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpBranch %1
 %1 = OpLabel
 OpLoopMerge %2 %3 None
 OpBranch %4
@@ -298,31 +297,31 @@
 }
 
 TEST_F(BuilderTest, Loop_WithContinuing_BreakIf_ConditionIsVar) {
-  // loop {
-  //   continuing {
-  //     var cond = true;
-  //     if (cond) { break; }
-  //   }
-  // }
+    // loop {
+    //   continuing {
+    //     var cond = true;
+    //     if (cond) { break; }
+    //   }
+    // }
 
-  auto* cond_var = Decl(Var("cond", nullptr, Expr(true)));
-  auto* if_stmt = If(Expr("cond"), Block(Break()), ast::ElseStatementList{});
-  auto* continuing = Block(cond_var, if_stmt);
-  auto* loop = Loop(Block(), continuing);
-  WrapInFunction(loop);
+    auto* cond_var = Decl(Var("cond", nullptr, Expr(true)));
+    auto* if_stmt = If(Expr("cond"), Block(Break()));
+    auto* continuing = Block(cond_var, if_stmt);
+    auto* loop = Loop(Block(), continuing);
+    WrapInFunction(loop);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_TRUE(b.GenerateLoopStatement(loop)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeBool
+    EXPECT_TRUE(b.GenerateLoopStatement(loop)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeBool
 %6 = OpConstantTrue %5
 %8 = OpTypePointer Function %5
 %9 = OpConstantNull %5
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(OpBranch %1
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpBranch %1
 %1 = OpLabel
 OpLoopMerge %2 %3 None
 OpBranch %4
@@ -337,31 +336,30 @@
 }
 
 TEST_F(BuilderTest, Loop_WithContinuing_BreakUnless_ConditionIsVar) {
-  // loop {
-  //   continuing {
-  //     var cond = true;
-  //     if (cond) {} else { break; }
-  //   }
-  // }
-  auto* cond_var = Decl(Var("cond", nullptr, Expr(true)));
-  auto* if_stmt = If(Expr("cond"), Block(),
-                     ast::ElseStatementList{Else(nullptr, Block(Break()))});
-  auto* continuing = Block(cond_var, if_stmt);
-  auto* loop = Loop(Block(), continuing);
-  WrapInFunction(loop);
+    // loop {
+    //   continuing {
+    //     var cond = true;
+    //     if (cond) {} else { break; }
+    //   }
+    // }
+    auto* cond_var = Decl(Var("cond", nullptr, Expr(true)));
+    auto* if_stmt = If(Expr("cond"), Block(), Else(Block(Break())));
+    auto* continuing = Block(cond_var, if_stmt);
+    auto* loop = Loop(Block(), continuing);
+    WrapInFunction(loop);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_TRUE(b.GenerateLoopStatement(loop)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeBool
+    EXPECT_TRUE(b.GenerateLoopStatement(loop)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeBool
 %6 = OpConstantTrue %5
 %8 = OpTypePointer Function %5
 %9 = OpConstantNull %5
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(OpBranch %1
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpBranch %1
 %1 = OpLabel
 OpLoopMerge %2 %3 None
 OpBranch %4
@@ -376,40 +374,38 @@
 }
 
 TEST_F(BuilderTest, Loop_WithContinuing_BreakIf_Nested) {
-  // Make sure the right backedge and break target are used.
-  // loop {
-  //   continuing {
-  //     loop {
-  //       continuing {
-  //         if (true) { break; }
-  //       }
-  //     }
-  //     if (true) { break; }
-  //   }
-  // }
+    // Make sure the right backedge and break target are used.
+    // loop {
+    //   continuing {
+    //     loop {
+    //       continuing {
+    //         if (true) { break; }
+    //       }
+    //     }
+    //     if (true) { break; }
+    //   }
+    // }
 
-  auto* inner_if_stmt = create<ast::IfStatement>(Expr(true), Block(Break()),
-                                                 ast::ElseStatementList{});
-  auto* inner_continuing = Block(inner_if_stmt);
-  auto* inner_loop = Loop(Block(), inner_continuing);
+    auto* inner_if_stmt = If(Expr(true), Block(Break()));
+    auto* inner_continuing = Block(inner_if_stmt);
+    auto* inner_loop = Loop(Block(), inner_continuing);
 
-  auto* outer_if_stmt = create<ast::IfStatement>(Expr(true), Block(Break()),
-                                                 ast::ElseStatementList{});
-  auto* outer_continuing = Block(inner_loop, outer_if_stmt);
-  auto* outer_loop = Loop(Block(), outer_continuing);
+    auto* outer_if_stmt = If(Expr(true), Block(Break()));
+    auto* outer_continuing = Block(inner_loop, outer_if_stmt);
+    auto* outer_loop = Loop(Block(), outer_continuing);
 
-  WrapInFunction(outer_loop);
+    WrapInFunction(outer_loop);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_TRUE(b.GenerateLoopStatement(outer_loop)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%9 = OpTypeBool
+    EXPECT_TRUE(b.GenerateLoopStatement(outer_loop)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%9 = OpTypeBool
 %10 = OpConstantTrue %9
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(OpBranch %1
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpBranch %1
 %1 = OpLabel
 OpLoopMerge %2 %3 None
 OpBranch %4
@@ -431,42 +427,38 @@
 }
 
 TEST_F(BuilderTest, Loop_WithContinuing_BreakUnless_Nested) {
-  // Make sure the right backedge and break target are used.
-  // loop {
-  //   continuing {
-  //     loop {
-  //       continuing {
-  //         if (true) {} else { break; }
-  //       }
-  //     }
-  //     if (true) {} else { break; }
-  //   }
-  // }
+    // Make sure the right backedge and break target are used.
+    // loop {
+    //   continuing {
+    //     loop {
+    //       continuing {
+    //         if (true) {} else { break; }
+    //       }
+    //     }
+    //     if (true) {} else { break; }
+    //   }
+    // }
 
-  auto* inner_if_stmt = create<ast::IfStatement>(
-      Expr(true), Block(),
-      ast::ElseStatementList{Else(nullptr, Block(Break()))});
-  auto* inner_continuing = Block(inner_if_stmt);
-  auto* inner_loop = Loop(Block(), inner_continuing);
+    auto* inner_if_stmt = If(Expr(true), Block(), Else(Block(Break())));
+    auto* inner_continuing = Block(inner_if_stmt);
+    auto* inner_loop = Loop(Block(), inner_continuing);
 
-  auto* outer_if_stmt = create<ast::IfStatement>(
-      Expr(true), Block(),
-      ast::ElseStatementList{Else(nullptr, Block(Break()))});
-  auto* outer_continuing = Block(inner_loop, outer_if_stmt);
-  auto* outer_loop = Loop(Block(), outer_continuing);
+    auto* outer_if_stmt = If(Expr(true), Block(), Else(Block(Break())));
+    auto* outer_continuing = Block(inner_loop, outer_if_stmt);
+    auto* outer_loop = Loop(Block(), outer_continuing);
 
-  WrapInFunction(outer_loop);
+    WrapInFunction(outer_loop);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_TRUE(b.GenerateLoopStatement(outer_loop)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%9 = OpTypeBool
+    EXPECT_TRUE(b.GenerateLoopStatement(outer_loop)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%9 = OpTypeBool
 %10 = OpConstantTrue %9
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(OpBranch %1
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpBranch %1
 %1 = OpLabel
 OpLoopMerge %2 %3 None
 OpBranch %4
diff --git a/src/tint/writer/spirv/builder_return_test.cc b/src/tint/writer/spirv/builder_return_test.cc
index 3b0eb4a..635db28 100644
--- a/src/tint/writer/spirv/builder_return_test.cc
+++ b/src/tint/writer/spirv/builder_return_test.cc
@@ -21,64 +21,64 @@
 using BuilderTest = TestHelper;
 
 TEST_F(BuilderTest, Return) {
-  auto* ret = Return();
-  WrapInFunction(ret);
+    auto* ret = Return();
+    WrapInFunction(ret);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_TRUE(b.GenerateReturnStatement(ret));
-  ASSERT_FALSE(b.has_error()) << b.error();
+    b.push_function(Function{});
+    EXPECT_TRUE(b.GenerateReturnStatement(ret));
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpReturn
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()), R"(OpReturn
 )");
 }
 
 TEST_F(BuilderTest, Return_WithValue) {
-  auto* val = vec3<f32>(1.f, 1.f, 3.f);
+    auto* val = vec3<f32>(1.f, 1.f, 3.f);
 
-  auto* ret = Return(val);
-  Func("test", {}, ty.vec3<f32>(), {ret}, {});
+    auto* ret = Return(val);
+    Func("test", {}, ty.vec3<f32>(), {ret}, {});
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_TRUE(b.GenerateReturnStatement(ret));
-  ASSERT_FALSE(b.has_error()) << b.error();
+    b.push_function(Function{});
+    EXPECT_TRUE(b.GenerateReturnStatement(ret));
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 3
 %3 = OpConstant %2 1
 %4 = OpConstant %2 3
 %5 = OpConstantComposite %1 %3 %3 %4
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(OpReturnValue %5
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpReturnValue %5
 )");
 }
 
 TEST_F(BuilderTest, Return_WithValue_GeneratesLoad) {
-  auto* var = Var("param", ty.f32());
+    auto* var = Var("param", ty.f32());
 
-  auto* ret = Return(var);
-  Func("test", {}, ty.f32(), {Decl(var), ret}, {});
+    auto* ret = Return(var);
+    Func("test", {}, ty.f32(), {Decl(var), ret}, {});
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
-  EXPECT_TRUE(b.GenerateReturnStatement(ret)) << b.error();
-  ASSERT_FALSE(b.has_error()) << b.error();
+    b.push_function(Function{});
+    EXPECT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+    EXPECT_TRUE(b.GenerateReturnStatement(ret)) << b.error();
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
 %2 = OpTypePointer Function %3
 %4 = OpConstantNull %3
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-            R"(%1 = OpVariable %2 Function %4
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
+              R"(%1 = OpVariable %2 Function %4
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%5 = OpLoad %3 %1
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%5 = OpLoad %3 %1
 OpReturnValue %5
 )");
 }
diff --git a/src/tint/writer/spirv/builder_switch_test.cc b/src/tint/writer/spirv/builder_switch_test.cc
index 8fd7921..7ddd1bd 100644
--- a/src/tint/writer/spirv/builder_switch_test.cc
+++ b/src/tint/writer/spirv/builder_switch_test.cc
@@ -16,29 +16,31 @@
 #include "src/tint/writer/spirv/spv_dump.h"
 #include "src/tint/writer/spirv/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::spirv {
 namespace {
 
 using BuilderTest = TestHelper;
 
 TEST_F(BuilderTest, Switch_Empty) {
-  // switch (1) {
-  //   default: {}
-  // }
+    // switch (1i) {
+    //   default: {}
+    // }
 
-  auto* expr = Switch(1, DefaultCase());
-  WrapInFunction(expr);
+    auto* expr = Switch(1_i, DefaultCase());
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
+    b.push_function(Function{});
 
-  EXPECT_TRUE(b.GenerateSwitchStatement(expr)) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
+    EXPECT_TRUE(b.GenerateSwitchStatement(expr)) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
 %3 = OpConstant %2 1
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(OpSelectionMerge %1 None
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(OpSelectionMerge %1 None
 OpSwitch %3 %4
 %4 = OpLabel
 OpBranch %1
@@ -47,32 +49,32 @@
 }
 
 TEST_F(BuilderTest, Switch_WithCase) {
-  // switch(a) {
-  //   case 1:
-  //     v = 1;
-  //   case 2:
-  //     v = 2;
-  //   default: {}
-  // }
+    // switch(a) {
+    //   case 1i:
+    //     v = 1i;
+    //   case 2i:
+    //     v = 2i;
+    //   default: {}
+    // }
 
-  auto* v = Global("v", ty.i32(), ast::StorageClass::kPrivate);
-  auto* a = Global("a", ty.i32(), ast::StorageClass::kPrivate);
+    auto* v = Global("v", ty.i32(), ast::StorageClass::kPrivate);
+    auto* a = Global("a", ty.i32(), ast::StorageClass::kPrivate);
 
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Switch("a",                                   //
-                               Case(Expr(1), Block(Assign("v", 1))),  //
-                               Case(Expr(2), Block(Assign("v", 2))),  //
-                               DefaultCase()),
-                    });
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Switch("a",                                       //
+                                 Case(Expr(1_i), Block(Assign("v", 1_i))),  //
+                                 Case(Expr(2_i), Block(Assign("v", 2_i))),  //
+                                 DefaultCase()),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
-  ASSERT_TRUE(b.GenerateGlobalVariable(a)) << b.error();
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
+    ASSERT_TRUE(b.GenerateGlobalVariable(a)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(OpName %1 "v"
+    EXPECT_EQ(DumpBuilder(b), R"(OpName %1 "v"
 OpName %5 "a"
 OpName %8 "a_func"
 %3 = OpTypeInt 32 1
@@ -104,32 +106,32 @@
 }
 
 TEST_F(BuilderTest, Switch_WithCase_Unsigned) {
-  // switch(a) {
-  //   case 1u:
-  //     v = 1;
-  //   case 2u:
-  //     v = 2;
-  //   default: {}
-  // }
+    // switch(a) {
+    //   case 1u:
+    //     v = 1i;
+    //   case 2u:
+    //     v = 2i;
+    //   default: {}
+    // }
 
-  auto* v = Global("v", ty.i32(), ast::StorageClass::kPrivate);
-  auto* a = Global("a", ty.u32(), ast::StorageClass::kPrivate);
+    auto* v = Global("v", ty.i32(), ast::StorageClass::kPrivate);
+    auto* a = Global("a", ty.u32(), ast::StorageClass::kPrivate);
 
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Switch("a",                                    //
-                               Case(Expr(1u), Block(Assign("v", 1))),  //
-                               Case(Expr(2u), Block(Assign("v", 2))),  //
-                               DefaultCase()),
-                    });
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Switch("a",                                       //
+                                 Case(Expr(1_u), Block(Assign("v", 1_i))),  //
+                                 Case(Expr(2_u), Block(Assign("v", 2_i))),  //
+                                 DefaultCase()),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
-  ASSERT_TRUE(b.GenerateGlobalVariable(a)) << b.error();
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
+    ASSERT_TRUE(b.GenerateGlobalVariable(a)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(OpName %1 "v"
+    EXPECT_EQ(DumpBuilder(b), R"(OpName %1 "v"
 OpName %5 "a"
 OpName %11 "a_func"
 %3 = OpTypeInt 32 1
@@ -164,27 +166,27 @@
 }
 
 TEST_F(BuilderTest, Switch_WithDefault) {
-  // switch(true) {
-  //   default: {}
-  //     v = 1;
-  //  }
+    // switch(true) {
+    //   default: {}
+    //     v = 1i;
+    //  }
 
-  auto* v = Global("v", ty.i32(), ast::StorageClass::kPrivate);
-  auto* a = Global("a", ty.i32(), ast::StorageClass::kPrivate);
+    auto* v = Global("v", ty.i32(), ast::StorageClass::kPrivate);
+    auto* a = Global("a", ty.i32(), ast::StorageClass::kPrivate);
 
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Switch("a",                                  //
-                               DefaultCase(Block(Assign("v", 1)))),  //
-                    });
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Switch("a",                                    //
+                                 DefaultCase(Block(Assign("v", 1_i)))),  //
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
-  ASSERT_TRUE(b.GenerateGlobalVariable(a)) << b.error();
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
+    ASSERT_TRUE(b.GenerateGlobalVariable(a)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(OpName %1 "v"
+    EXPECT_EQ(DumpBuilder(b), R"(OpName %1 "v"
 OpName %5 "a"
 OpName %8 "a_func"
 %3 = OpTypeInt 32 1
@@ -210,35 +212,35 @@
 }
 
 TEST_F(BuilderTest, Switch_WithCaseAndDefault) {
-  // switch(a) {
-  //   case 1:
-  //      v = 1;
-  //   case 2, 3:
-  //      v = 2;
-  //   default: {}
-  //      v = 3;
-  //  }
+    // switch(a) {
+    //   case 1i:
+    //      v = 1i;
+    //   case 2i, 3i:
+    //      v = 2i;
+    //   default: {}
+    //      v = 3i;
+    //  }
 
-  auto* v = Global("v", ty.i32(), ast::StorageClass::kPrivate);
-  auto* a = Global("a", ty.i32(), ast::StorageClass::kPrivate);
+    auto* v = Global("v", ty.i32(), ast::StorageClass::kPrivate);
+    auto* a = Global("a", ty.i32(), ast::StorageClass::kPrivate);
 
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Switch(Expr("a"),                    //
-                               Case(Expr(1),                 //
-                                    Block(Assign("v", 1))),  //
-                               Case({Expr(2), Expr(3)},      //
-                                    Block(Assign("v", 2))),  //
-                               DefaultCase(Block(Assign("v", 3)))),
-                    });
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Switch(Expr("a"),                      //
+                                 Case(Expr(1_i),                 //
+                                      Block(Assign("v", 1_i))),  //
+                                 Case({Expr(2_i), Expr(3_i)},    //
+                                      Block(Assign("v", 2_i))),  //
+                                 DefaultCase(Block(Assign("v", 3_i)))),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
-  ASSERT_TRUE(b.GenerateGlobalVariable(a)) << b.error();
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
+    ASSERT_TRUE(b.GenerateGlobalVariable(a)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(OpName %1 "v"
+    EXPECT_EQ(DumpBuilder(b), R"(OpName %1 "v"
 OpName %5 "a"
 OpName %8 "a_func"
 %3 = OpTypeInt 32 1
@@ -272,36 +274,36 @@
 }
 
 TEST_F(BuilderTest, Switch_CaseWithFallthrough) {
-  // switch(a) {
-  //   case 1:
-  //      v = 1;
-  //      fallthrough;
-  //   case 2:
-  //      v = 2;
-  //   default: {}
-  //      v = 3;
-  //  }
+    // switch(a) {
+    //   case 1i:
+    //      v = 1i;
+    //      fallthrough;
+    //   case 2i:
+    //      v = 2i;
+    //   default: {}
+    //      v = 3i;
+    //  }
 
-  auto* v = Global("v", ty.i32(), ast::StorageClass::kPrivate);
-  auto* a = Global("a", ty.i32(), ast::StorageClass::kPrivate);
+    auto* v = Global("v", ty.i32(), ast::StorageClass::kPrivate);
+    auto* a = Global("a", ty.i32(), ast::StorageClass::kPrivate);
 
-  auto* func = Func("a_func", {}, ty.void_(),
-                    {
-                        Switch(Expr("a"),                                   //
-                               Case(Expr(1),                                //
-                                    Block(Assign("v", 1), Fallthrough())),  //
-                               Case(Expr(2),                                //
-                                    Block(Assign("v", 2))),                 //
-                               DefaultCase(Block(Assign("v", 3)))),
-                    });
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Switch(Expr("a"),                                     //
+                                 Case(Expr(1_i),                                //
+                                      Block(Assign("v", 1_i), Fallthrough())),  //
+                                 Case(Expr(2_i),                                //
+                                      Block(Assign("v", 2_i))),                 //
+                                 DefaultCase(Block(Assign("v", 3_i)))),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
-  ASSERT_TRUE(b.GenerateGlobalVariable(a)) << b.error();
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
+    ASSERT_TRUE(b.GenerateGlobalVariable(a)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(OpName %1 "v"
+    EXPECT_EQ(DumpBuilder(b), R"(OpName %1 "v"
 OpName %5 "a"
 OpName %8 "a_func"
 %3 = OpTypeInt 32 1
@@ -335,36 +337,35 @@
 }
 
 TEST_F(BuilderTest, Switch_WithNestedBreak) {
-  // switch (a) {
-  //   case 1:
-  //     if (true) {
-  //       break;
-  //     }
-  //     v = 1;
-  //   default: {}
-  // }
+    // switch (a) {
+    //   case 1:
+    //     if (true) {
+    //       break;
+    //     }
+    //     v = 1i;
+    //   default: {}
+    // }
 
-  auto* v = Global("v", ty.i32(), ast::StorageClass::kPrivate);
-  auto* a = Global("a", ty.i32(), ast::StorageClass::kPrivate);
+    auto* v = Global("v", ty.i32(), ast::StorageClass::kPrivate);
+    auto* a = Global("a", ty.i32(), ast::StorageClass::kPrivate);
 
-  auto* func = Func(
-      "a_func", {}, ty.void_(),
-      {
-          Switch("a",           //
-                 Case(Expr(1),  //
-                      Block(    //
-                          If(Expr(true), Block(create<ast::BreakStatement>())),
-                          Assign("v", 1))),
-                 DefaultCase()),
-      });
+    auto* func = Func("a_func", {}, ty.void_(),
+                      {
+                          Switch("a",             //
+                                 Case(Expr(1_i),  //
+                                      Block(      //
+                                          If(Expr(true), Block(create<ast::BreakStatement>())),
+                                          Assign("v", 1_i))),
+                                 DefaultCase()),
+                      });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  ASSERT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
-  ASSERT_TRUE(b.GenerateGlobalVariable(a)) << b.error();
-  ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
+    ASSERT_TRUE(b.GenerateGlobalVariable(v)) << b.error();
+    ASSERT_TRUE(b.GenerateGlobalVariable(a)) << b.error();
+    ASSERT_TRUE(b.GenerateFunction(func)) << b.error();
 
-  EXPECT_EQ(DumpBuilder(b), R"(OpName %1 "v"
+    EXPECT_EQ(DumpBuilder(b), R"(OpName %1 "v"
 OpName %5 "a"
 OpName %8 "a_func"
 %3 = OpTypeInt 32 1
@@ -399,30 +400,30 @@
 }
 
 TEST_F(BuilderTest, Switch_AllReturn) {
-  // switch (1) {
-  //   case 1: {
-  //     return 1;
-  //   }
-  //   case 2: {
-  //     fallthrough;
-  //   }
-  //   default: {
-  //     return 3;
-  //   }
-  // }
+    // switch (1i) {
+    //   case 1i: {
+    //     return 1i;
+    //   }
+    //   case 2i: {
+    //     fallthrough;
+    //   }
+    //   default: {
+    //     return 3i;
+    //   }
+    // }
 
-  auto* fn = Func("f", {}, ty.i32(),
-                  {
-                      Switch(1,                                    //
-                             Case(Expr(1), Block(Return(1))),      //
-                             Case(Expr(2), Block(Fallthrough())),  //
-                             DefaultCase(Block(Return(3)))),
-                  });
+    auto* fn = Func("f", {}, ty.i32(),
+                    {
+                        Switch(1_i,                                    //
+                               Case(Expr(1_i), Block(Return(1_i))),    //
+                               Case(Expr(2_i), Block(Fallthrough())),  //
+                               DefaultCase(Block(Return(3_i)))),
+                    });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_TRUE(b.GenerateFunction(fn)) << b.error();
-  EXPECT_EQ(DumpBuilder(b), R"(OpName %3 "f"
+    EXPECT_TRUE(b.GenerateFunction(fn)) << b.error();
+    EXPECT_EQ(DumpBuilder(b), R"(OpName %3 "f"
 %2 = OpTypeInt 32 1
 %1 = OpTypeFunction %2
 %6 = OpConstant %2 1
diff --git a/src/tint/writer/spirv/builder_test.cc b/src/tint/writer/spirv/builder_test.cc
index 59938ad..f2475c0 100644
--- a/src/tint/writer/spirv/builder_test.cc
+++ b/src/tint/writer/spirv/builder_test.cc
@@ -21,23 +21,23 @@
 using BuilderTest = TestHelper;
 
 TEST_F(BuilderTest, TracksIdBounds) {
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  for (size_t i = 0; i < 5; i++) {
-    EXPECT_EQ(b.next_id(), i + 1);
-  }
+    for (size_t i = 0; i < 5; i++) {
+        EXPECT_EQ(b.next_id(), i + 1);
+    }
 
-  EXPECT_EQ(6u, b.id_bound());
+    EXPECT_EQ(6u, b.id_bound());
 }
 
 TEST_F(BuilderTest, Capabilities_Dedup) {
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_capability(SpvCapabilityShader);
-  b.push_capability(SpvCapabilityShader);
-  b.push_capability(SpvCapabilityShader);
+    b.push_capability(SpvCapabilityShader);
+    b.push_capability(SpvCapabilityShader);
+    b.push_capability(SpvCapabilityShader);
 
-  EXPECT_EQ(DumpInstructions(b.capabilities()), "OpCapability Shader\n");
+    EXPECT_EQ(DumpInstructions(b.capabilities()), "OpCapability Shader\n");
 }
 
 }  // namespace
diff --git a/src/tint/writer/spirv/builder_type_test.cc b/src/tint/writer/spirv/builder_type_test.cc
index 44e778b..8dc048e 100644
--- a/src/tint/writer/spirv/builder_type_test.cc
+++ b/src/tint/writer/spirv/builder_type_test.cc
@@ -12,68 +12,70 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/sem/depth_texture_type.h"
-#include "src/tint/sem/multisampled_texture_type.h"
-#include "src/tint/sem/sampled_texture_type.h"
+#include "src/tint/sem/depth_texture.h"
+#include "src/tint/sem/multisampled_texture.h"
+#include "src/tint/sem/sampled_texture.h"
 #include "src/tint/writer/spirv/spv_dump.h"
 #include "src/tint/writer/spirv/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::spirv {
 namespace {
 
 using BuilderTest_Type = TestHelper;
 
 TEST_F(BuilderTest_Type, GenerateRuntimeArray) {
-  auto* ary = ty.array(ty.i32());
-  auto* str = Structure("S", {Member("x", ary)});
-  Global("a", ty.Of(str), ast::StorageClass::kStorage, ast::Access::kRead,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    auto* ary = ty.array(ty.i32());
+    auto* str = Structure("S", {Member("x", ary)});
+    Global("a", ty.Of(str), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  auto id = b.GenerateTypeIfNeeded(program->TypeOf(ary));
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(1u, id);
+    auto id = b.GenerateTypeIfNeeded(program->TypeOf(ary));
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(1u, id);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
 %1 = OpTypeRuntimeArray %2
 )");
 }
 
 TEST_F(BuilderTest_Type, ReturnsGeneratedRuntimeArray) {
-  auto* ary = ty.array(ty.i32());
-  auto* str = Structure("S", {Member("x", ary)});
-  Global("a", ty.Of(str), ast::StorageClass::kStorage, ast::Access::kRead,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    auto* ary = ty.array(ty.i32());
+    auto* str = Structure("S", {Member("x", ary)});
+    Global("a", ty.Of(str), ast::StorageClass::kStorage, ast::Access::kRead,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_EQ(b.GenerateTypeIfNeeded(program->TypeOf(ary)), 1u);
-  EXPECT_EQ(b.GenerateTypeIfNeeded(program->TypeOf(ary)), 1u);
-  ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(b.GenerateTypeIfNeeded(program->TypeOf(ary)), 1u);
+    EXPECT_EQ(b.GenerateTypeIfNeeded(program->TypeOf(ary)), 1u);
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
 %1 = OpTypeRuntimeArray %2
 )");
 }
 
 TEST_F(BuilderTest_Type, GenerateArray) {
-  auto* ary = ty.array(ty.i32(), 4);
-  Global("a", ary, ast::StorageClass::kPrivate);
+    auto* ary = ty.array(ty.i32(), 4_u);
+    Global("a", ary, ast::StorageClass::kPrivate);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  auto id = b.GenerateTypeIfNeeded(program->TypeOf(ary));
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(1u, id);
+    auto id = b.GenerateTypeIfNeeded(program->TypeOf(ary));
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(1u, id);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
 %3 = OpTypeInt 32 0
 %4 = OpConstant %3 4
 %1 = OpTypeArray %2 %4
@@ -81,19 +83,19 @@
 }
 
 TEST_F(BuilderTest_Type, GenerateArray_WithStride) {
-  auto* ary = ty.array(ty.i32(), 4, 16u);
-  Global("a", ary, ast::StorageClass::kPrivate);
+    auto* ary = ty.array(ty.i32(), 4_u, 16u);
+    Global("a", ary, ast::StorageClass::kPrivate);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  auto id = b.GenerateTypeIfNeeded(program->TypeOf(ary));
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(1u, id);
+    auto id = b.GenerateTypeIfNeeded(program->TypeOf(ary));
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(1u, id);
 
-  EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %1 ArrayStride 16
+    EXPECT_EQ(DumpInstructions(b.annots()), R"(OpDecorate %1 ArrayStride 16
 )");
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
 %3 = OpTypeInt 32 0
 %4 = OpConstant %3 4
 %1 = OpTypeArray %2 %4
@@ -101,16 +103,16 @@
 }
 
 TEST_F(BuilderTest_Type, ReturnsGeneratedArray) {
-  auto* ary = ty.array(ty.i32(), 4);
-  Global("a", ary, ast::StorageClass::kPrivate);
+    auto* ary = ty.array(ty.i32(), 4_u);
+    Global("a", ary, ast::StorageClass::kPrivate);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_EQ(b.GenerateTypeIfNeeded(program->TypeOf(ary)), 1u);
-  EXPECT_EQ(b.GenerateTypeIfNeeded(program->TypeOf(ary)), 1u);
-  ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(b.GenerateTypeIfNeeded(program->TypeOf(ary)), 1u);
+    EXPECT_EQ(b.GenerateTypeIfNeeded(program->TypeOf(ary)), 1u);
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
 %3 = OpTypeInt 32 0
 %4 = OpConstant %3 4
 %1 = OpTypeArray %2 %4
@@ -118,204 +120,202 @@
 }
 
 TEST_F(BuilderTest_Type, GenerateBool) {
-  auto* bool_ = create<sem::Bool>();
+    auto* bool_ = create<sem::Bool>();
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  auto id = b.GenerateTypeIfNeeded(bool_);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(id, 1u);
+    auto id = b.GenerateTypeIfNeeded(bool_);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(id, 1u);
 
-  ASSERT_EQ(b.types().size(), 1u);
-  EXPECT_EQ(DumpInstruction(b.types()[0]), R"(%1 = OpTypeBool
+    ASSERT_EQ(b.types().size(), 1u);
+    EXPECT_EQ(DumpInstruction(b.types()[0]), R"(%1 = OpTypeBool
 )");
 }
 
 TEST_F(BuilderTest_Type, ReturnsGeneratedBool) {
-  auto* bool_ = create<sem::Bool>();
-  auto* i32 = create<sem::I32>();
+    auto* bool_ = create<sem::Bool>();
+    auto* i32 = create<sem::I32>();
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_EQ(b.GenerateTypeIfNeeded(bool_), 1u);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(b.GenerateTypeIfNeeded(i32), 2u);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(b.GenerateTypeIfNeeded(bool_), 1u);
-  ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(b.GenerateTypeIfNeeded(bool_), 1u);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(b.GenerateTypeIfNeeded(i32), 2u);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(b.GenerateTypeIfNeeded(bool_), 1u);
+    ASSERT_FALSE(b.has_error()) << b.error();
 }
 
 TEST_F(BuilderTest_Type, GenerateF32) {
-  auto* f32 = create<sem::F32>();
+    auto* f32 = create<sem::F32>();
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  auto id = b.GenerateTypeIfNeeded(f32);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(id, 1u);
+    auto id = b.GenerateTypeIfNeeded(f32);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(id, 1u);
 
-  ASSERT_EQ(b.types().size(), 1u);
-  EXPECT_EQ(DumpInstruction(b.types()[0]), R"(%1 = OpTypeFloat 32
+    ASSERT_EQ(b.types().size(), 1u);
+    EXPECT_EQ(DumpInstruction(b.types()[0]), R"(%1 = OpTypeFloat 32
 )");
 }
 
 TEST_F(BuilderTest_Type, ReturnsGeneratedF32) {
-  auto* f32 = create<sem::F32>();
-  auto* i32 = create<sem::I32>();
+    auto* f32 = create<sem::F32>();
+    auto* i32 = create<sem::I32>();
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_EQ(b.GenerateTypeIfNeeded(f32), 1u);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(b.GenerateTypeIfNeeded(i32), 2u);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(b.GenerateTypeIfNeeded(f32), 1u);
-  ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(b.GenerateTypeIfNeeded(f32), 1u);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(b.GenerateTypeIfNeeded(i32), 2u);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(b.GenerateTypeIfNeeded(f32), 1u);
+    ASSERT_FALSE(b.has_error()) << b.error();
 }
 
 TEST_F(BuilderTest_Type, GenerateI32) {
-  auto* i32 = create<sem::I32>();
+    auto* i32 = create<sem::I32>();
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  auto id = b.GenerateTypeIfNeeded(i32);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(id, 1u);
+    auto id = b.GenerateTypeIfNeeded(i32);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(id, 1u);
 
-  ASSERT_EQ(b.types().size(), 1u);
-  EXPECT_EQ(DumpInstruction(b.types()[0]), R"(%1 = OpTypeInt 32 1
+    ASSERT_EQ(b.types().size(), 1u);
+    EXPECT_EQ(DumpInstruction(b.types()[0]), R"(%1 = OpTypeInt 32 1
 )");
 }
 
 TEST_F(BuilderTest_Type, ReturnsGeneratedI32) {
-  auto* f32 = create<sem::F32>();
-  auto* i32 = create<sem::I32>();
+    auto* f32 = create<sem::F32>();
+    auto* i32 = create<sem::I32>();
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_EQ(b.GenerateTypeIfNeeded(i32), 1u);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(b.GenerateTypeIfNeeded(f32), 2u);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(b.GenerateTypeIfNeeded(i32), 1u);
-  ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(b.GenerateTypeIfNeeded(i32), 1u);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(b.GenerateTypeIfNeeded(f32), 2u);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(b.GenerateTypeIfNeeded(i32), 1u);
+    ASSERT_FALSE(b.has_error()) << b.error();
 }
 
 TEST_F(BuilderTest_Type, GenerateMatrix) {
-  auto* f32 = create<sem::F32>();
-  auto* vec3 = create<sem::Vector>(f32, 3u);
-  auto* mat2x3 = create<sem::Matrix>(vec3, 2u);
+    auto* f32 = create<sem::F32>();
+    auto* vec3 = create<sem::Vector>(f32, 3u);
+    auto* mat2x3 = create<sem::Matrix>(vec3, 2u);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  auto id = b.GenerateTypeIfNeeded(mat2x3);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(id, 1u);
+    auto id = b.GenerateTypeIfNeeded(mat2x3);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(id, 1u);
 
-  EXPECT_EQ(b.types().size(), 3u);
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
+    EXPECT_EQ(b.types().size(), 3u);
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%3 = OpTypeFloat 32
 %2 = OpTypeVector %3 3
 %1 = OpTypeMatrix %2 2
 )");
 }
 
 TEST_F(BuilderTest_Type, ReturnsGeneratedMatrix) {
-  auto* i32 = create<sem::I32>();
-  auto* col = create<sem::Vector>(i32, 4u);
-  auto* mat = create<sem::Matrix>(col, 3u);
+    auto* i32 = create<sem::I32>();
+    auto* col = create<sem::Vector>(i32, 4u);
+    auto* mat = create<sem::Matrix>(col, 3u);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_EQ(b.GenerateTypeIfNeeded(mat), 1u);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(b.GenerateTypeIfNeeded(i32), 3u);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(b.GenerateTypeIfNeeded(mat), 1u);
-  ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(b.GenerateTypeIfNeeded(mat), 1u);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(b.GenerateTypeIfNeeded(i32), 3u);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(b.GenerateTypeIfNeeded(mat), 1u);
+    ASSERT_FALSE(b.has_error()) << b.error();
 }
 
 TEST_F(BuilderTest_Type, GeneratePtr) {
-  auto* i32 = create<sem::I32>();
-  auto* ptr = create<sem::Pointer>(i32, ast::StorageClass::kOutput,
-                                   ast::Access::kReadWrite);
+    auto* i32 = create<sem::I32>();
+    auto* ptr = create<sem::Pointer>(i32, ast::StorageClass::kOutput, ast::Access::kReadWrite);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  auto id = b.GenerateTypeIfNeeded(ptr);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(1u, id);
+    auto id = b.GenerateTypeIfNeeded(ptr);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(1u, id);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
 %1 = OpTypePointer Output %2
 )");
 }
 
 TEST_F(BuilderTest_Type, ReturnsGeneratedPtr) {
-  auto* i32 = create<sem::I32>();
-  auto* ptr = create<sem::Pointer>(i32, ast::StorageClass::kOutput,
-                                   ast::Access::kReadWrite);
+    auto* i32 = create<sem::I32>();
+    auto* ptr = create<sem::Pointer>(i32, ast::StorageClass::kOutput, ast::Access::kReadWrite);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_EQ(b.GenerateTypeIfNeeded(ptr), 1u);
-  EXPECT_EQ(b.GenerateTypeIfNeeded(ptr), 1u);
+    EXPECT_EQ(b.GenerateTypeIfNeeded(ptr), 1u);
+    EXPECT_EQ(b.GenerateTypeIfNeeded(ptr), 1u);
 }
 
 TEST_F(BuilderTest_Type, GenerateStruct) {
-  auto* s = Structure("my_struct", {Member("a", ty.f32())});
+    auto* s = Structure("my_struct", {Member("a", ty.f32())});
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  auto id = b.GenerateTypeIfNeeded(program->TypeOf(s));
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(id, 1u);
+    auto id = b.GenerateTypeIfNeeded(program->TypeOf(s));
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(id, 1u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeStruct %2
 )");
-  EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "my_struct"
+    EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "my_struct"
 OpMemberName %1 0 "a"
 )");
 }
 
 TEST_F(BuilderTest_Type, GenerateStruct_DecoratedMembers) {
-  auto* s = Structure("S", {
-                               Member("a", ty.f32()),
-                               Member("b", ty.f32(), {MemberAlign(8)}),
-                           });
+    auto* s = Structure("S", {
+                                 Member("a", ty.f32()),
+                                 Member("b", ty.f32(), {MemberAlign(8)}),
+                             });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  auto id = b.GenerateTypeIfNeeded(program->TypeOf(s));
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(id, 1u);
+    auto id = b.GenerateTypeIfNeeded(program->TypeOf(s));
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(id, 1u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeStruct %2 %2
 )");
-  EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "S"
+    EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "S"
 OpMemberName %1 0 "a"
 OpMemberName %1 1 "b"
 )");
-  EXPECT_EQ(DumpInstructions(b.annots()), R"(OpMemberDecorate %1 0 Offset 0
+    EXPECT_EQ(DumpInstructions(b.annots()), R"(OpMemberDecorate %1 0 Offset 0
 OpMemberDecorate %1 1 Offset 8
 )");
 }
 
 TEST_F(BuilderTest_Type, GenerateStruct_NonLayout_Matrix) {
-  auto* s = Structure("S", {
-                               Member("a", ty.mat2x2<f32>()),
-                               Member("b", ty.mat2x3<f32>()),
-                               Member("c", ty.mat4x4<f32>()),
-                           });
+    auto* s = Structure("S", {
+                                 Member("a", ty.mat2x2<f32>()),
+                                 Member("b", ty.mat2x3<f32>()),
+                                 Member("c", ty.mat4x4<f32>()),
+                             });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  auto id = b.GenerateTypeIfNeeded(program->TypeOf(s));
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(id, 1u);
+    auto id = b.GenerateTypeIfNeeded(program->TypeOf(s));
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(id, 1u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
 %3 = OpTypeVector %4 2
 %2 = OpTypeMatrix %3 2
 %6 = OpTypeVector %4 3
@@ -324,12 +324,12 @@
 %7 = OpTypeMatrix %8 4
 %1 = OpTypeStruct %2 %5 %7
 )");
-  EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "S"
+    EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "S"
 OpMemberName %1 0 "a"
 OpMemberName %1 1 "b"
 OpMemberName %1 2 "c"
 )");
-  EXPECT_EQ(DumpInstructions(b.annots()), R"(OpMemberDecorate %1 0 Offset 0
+    EXPECT_EQ(DumpInstructions(b.annots()), R"(OpMemberDecorate %1 0 Offset 0
 OpMemberDecorate %1 0 ColMajor
 OpMemberDecorate %1 0 MatrixStride 8
 OpMemberDecorate %1 1 Offset 16
@@ -342,20 +342,20 @@
 }
 
 TEST_F(BuilderTest_Type, GenerateStruct_DecoratedMembers_LayoutMatrix) {
-  // We have to infer layout for matrix when it also has an offset.
-  auto* s = Structure("S", {
-                               Member("a", ty.mat2x2<f32>()),
-                               Member("b", ty.mat2x3<f32>()),
-                               Member("c", ty.mat4x4<f32>()),
-                           });
+    // We have to infer layout for matrix when it also has an offset.
+    auto* s = Structure("S", {
+                                 Member("a", ty.mat2x2<f32>()),
+                                 Member("b", ty.mat2x3<f32>()),
+                                 Member("c", ty.mat4x4<f32>()),
+                             });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  auto id = b.GenerateTypeIfNeeded(program->TypeOf(s));
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(id, 1u);
+    auto id = b.GenerateTypeIfNeeded(program->TypeOf(s));
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(id, 1u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
 %3 = OpTypeVector %4 2
 %2 = OpTypeMatrix %3 2
 %6 = OpTypeVector %4 3
@@ -364,12 +364,12 @@
 %7 = OpTypeMatrix %8 4
 %1 = OpTypeStruct %2 %5 %7
 )");
-  EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "S"
+    EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "S"
 OpMemberName %1 0 "a"
 OpMemberName %1 1 "b"
 OpMemberName %1 2 "c"
 )");
-  EXPECT_EQ(DumpInstructions(b.annots()), R"(OpMemberDecorate %1 0 Offset 0
+    EXPECT_EQ(DumpInstructions(b.annots()), R"(OpMemberDecorate %1 0 Offset 0
 OpMemberDecorate %1 0 ColMajor
 OpMemberDecorate %1 0 MatrixStride 8
 OpMemberDecorate %1 1 Offset 16
@@ -382,26 +382,26 @@
 }
 
 TEST_F(BuilderTest_Type, GenerateStruct_DecoratedMembers_LayoutArraysOfMatrix) {
-  // We have to infer layout for matrix when it also has an offset.
-  // The decoration goes on the struct member, even if the matrix is buried
-  // in levels of arrays.
-  auto* arr_mat2x2 = ty.array(ty.mat2x2<f32>(), 1);      // Singly nested array
-  auto* arr_arr_mat2x3 = ty.array(ty.mat2x3<f32>(), 1);  // Doubly nested array
-  auto* rtarr_mat4x4 = ty.array(ty.mat4x4<f32>());       // Runtime array
+    // We have to infer layout for matrix when it also has an offset.
+    // The decoration goes on the struct member, even if the matrix is buried
+    // in levels of arrays.
+    auto* arr_mat2x2 = ty.array(ty.mat2x2<f32>(), 1_u);      // Singly nested array
+    auto* arr_arr_mat2x3 = ty.array(ty.mat2x3<f32>(), 1_u);  // Doubly nested array
+    auto* rtarr_mat4x4 = ty.array(ty.mat4x4<f32>());         // Runtime array
 
-  auto* s = Structure("S", {
-                               Member("a", arr_mat2x2),
-                               Member("b", arr_arr_mat2x3),
-                               Member("c", rtarr_mat4x4),
-                           });
+    auto* s = Structure("S", {
+                                 Member("a", arr_mat2x2),
+                                 Member("b", arr_arr_mat2x3),
+                                 Member("c", rtarr_mat4x4),
+                             });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  auto id = b.GenerateTypeIfNeeded(program->TypeOf(s));
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(id, 1u);
+    auto id = b.GenerateTypeIfNeeded(program->TypeOf(s));
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(id, 1u);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%5 = OpTypeFloat 32
 %4 = OpTypeVector %5 2
 %3 = OpTypeMatrix %4 2
 %6 = OpTypeInt 32 0
@@ -415,12 +415,12 @@
 %11 = OpTypeRuntimeArray %12
 %1 = OpTypeStruct %2 %8 %11
 )");
-  EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "S"
+    EXPECT_EQ(DumpInstructions(b.debug()), R"(OpName %1 "S"
 OpMemberName %1 0 "a"
 OpMemberName %1 1 "b"
 OpMemberName %1 2 "c"
 )");
-  EXPECT_EQ(DumpInstructions(b.annots()), R"(OpMemberDecorate %1 0 Offset 0
+    EXPECT_EQ(DumpInstructions(b.annots()), R"(OpMemberDecorate %1 0 Offset 0
 OpMemberDecorate %1 0 ColMajor
 OpMemberDecorate %1 0 MatrixStride 8
 OpDecorate %2 ArrayStride 16
@@ -436,526 +436,512 @@
 }
 
 TEST_F(BuilderTest_Type, GenerateU32) {
-  auto* u32 = create<sem::U32>();
+    auto* u32 = create<sem::U32>();
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  auto id = b.GenerateTypeIfNeeded(u32);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(id, 1u);
+    auto id = b.GenerateTypeIfNeeded(u32);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(id, 1u);
 
-  ASSERT_EQ(b.types().size(), 1u);
-  EXPECT_EQ(DumpInstruction(b.types()[0]), R"(%1 = OpTypeInt 32 0
+    ASSERT_EQ(b.types().size(), 1u);
+    EXPECT_EQ(DumpInstruction(b.types()[0]), R"(%1 = OpTypeInt 32 0
 )");
 }
 
 TEST_F(BuilderTest_Type, ReturnsGeneratedU32) {
-  auto* u32 = create<sem::U32>();
-  auto* f32 = create<sem::F32>();
+    auto* u32 = create<sem::U32>();
+    auto* f32 = create<sem::F32>();
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_EQ(b.GenerateTypeIfNeeded(u32), 1u);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(b.GenerateTypeIfNeeded(f32), 2u);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(b.GenerateTypeIfNeeded(u32), 1u);
-  ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(b.GenerateTypeIfNeeded(u32), 1u);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(b.GenerateTypeIfNeeded(f32), 2u);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(b.GenerateTypeIfNeeded(u32), 1u);
+    ASSERT_FALSE(b.has_error()) << b.error();
 }
 
 TEST_F(BuilderTest_Type, GenerateVector) {
-  auto* vec = create<sem::Vector>(create<sem::F32>(), 3u);
+    auto* vec = create<sem::Vector>(create<sem::F32>(), 3u);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  auto id = b.GenerateTypeIfNeeded(vec);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(id, 1u);
+    auto id = b.GenerateTypeIfNeeded(vec);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(id, 1u);
 
-  EXPECT_EQ(b.types().size(), 2u);
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(b.types().size(), 2u);
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeVector %2 3
 )");
 }
 
 TEST_F(BuilderTest_Type, ReturnsGeneratedVector) {
-  auto* i32 = create<sem::I32>();
-  auto* vec = create<sem::Vector>(i32, 3u);
+    auto* i32 = create<sem::I32>();
+    auto* vec = create<sem::Vector>(i32, 3u);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_EQ(b.GenerateTypeIfNeeded(vec), 1u);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(b.GenerateTypeIfNeeded(i32), 2u);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(b.GenerateTypeIfNeeded(vec), 1u);
-  ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(b.GenerateTypeIfNeeded(vec), 1u);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(b.GenerateTypeIfNeeded(i32), 2u);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(b.GenerateTypeIfNeeded(vec), 1u);
+    ASSERT_FALSE(b.has_error()) << b.error();
 }
 
 TEST_F(BuilderTest_Type, GenerateVoid) {
-  auto* void_ = create<sem::Void>();
+    auto* void_ = create<sem::Void>();
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  auto id = b.GenerateTypeIfNeeded(void_);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(id, 1u);
+    auto id = b.GenerateTypeIfNeeded(void_);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(id, 1u);
 
-  ASSERT_EQ(b.types().size(), 1u);
-  EXPECT_EQ(DumpInstruction(b.types()[0]), R"(%1 = OpTypeVoid
+    ASSERT_EQ(b.types().size(), 1u);
+    EXPECT_EQ(DumpInstruction(b.types()[0]), R"(%1 = OpTypeVoid
 )");
 }
 
 TEST_F(BuilderTest_Type, ReturnsGeneratedVoid) {
-  auto* void_ = create<sem::Void>();
-  auto* i32 = create<sem::I32>();
+    auto* void_ = create<sem::Void>();
+    auto* i32 = create<sem::I32>();
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_EQ(b.GenerateTypeIfNeeded(void_), 1u);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(b.GenerateTypeIfNeeded(i32), 2u);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(b.GenerateTypeIfNeeded(void_), 1u);
-  ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(b.GenerateTypeIfNeeded(void_), 1u);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(b.GenerateTypeIfNeeded(i32), 2u);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(b.GenerateTypeIfNeeded(void_), 1u);
+    ASSERT_FALSE(b.has_error()) << b.error();
 }
 
 struct PtrData {
-  ast::StorageClass ast_class;
-  SpvStorageClass result;
+    ast::StorageClass ast_class;
+    SpvStorageClass result;
 };
 inline std::ostream& operator<<(std::ostream& out, PtrData data) {
-  out << data.ast_class;
-  return out;
+    out << data.ast_class;
+    return out;
 }
 using PtrDataTest = TestParamHelper<PtrData>;
 TEST_P(PtrDataTest, ConvertStorageClass) {
-  auto params = GetParam();
+    auto params = GetParam();
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_EQ(b.ConvertStorageClass(params.ast_class), params.result);
+    EXPECT_EQ(b.ConvertStorageClass(params.ast_class), params.result);
 }
 INSTANTIATE_TEST_SUITE_P(
     BuilderTest_Type,
     PtrDataTest,
-    testing::Values(
-        PtrData{ast::StorageClass::kNone, SpvStorageClassMax},
-        PtrData{ast::StorageClass::kInput, SpvStorageClassInput},
-        PtrData{ast::StorageClass::kOutput, SpvStorageClassOutput},
-        PtrData{ast::StorageClass::kUniform, SpvStorageClassUniform},
-        PtrData{ast::StorageClass::kWorkgroup, SpvStorageClassWorkgroup},
-        PtrData{ast::StorageClass::kUniformConstant,
-                SpvStorageClassUniformConstant},
-        PtrData{ast::StorageClass::kStorage, SpvStorageClassStorageBuffer},
-        PtrData{ast::StorageClass::kPrivate, SpvStorageClassPrivate},
-        PtrData{ast::StorageClass::kFunction, SpvStorageClassFunction}));
+    testing::Values(PtrData{ast::StorageClass::kNone, SpvStorageClassMax},
+                    PtrData{ast::StorageClass::kInput, SpvStorageClassInput},
+                    PtrData{ast::StorageClass::kOutput, SpvStorageClassOutput},
+                    PtrData{ast::StorageClass::kUniform, SpvStorageClassUniform},
+                    PtrData{ast::StorageClass::kWorkgroup, SpvStorageClassWorkgroup},
+                    PtrData{ast::StorageClass::kHandle, SpvStorageClassUniformConstant},
+                    PtrData{ast::StorageClass::kStorage, SpvStorageClassStorageBuffer},
+                    PtrData{ast::StorageClass::kPrivate, SpvStorageClassPrivate},
+                    PtrData{ast::StorageClass::kFunction, SpvStorageClassFunction}));
 
 TEST_F(BuilderTest_Type, DepthTexture_Generate_2d) {
-  auto* two_d = create<sem::DepthTexture>(ast::TextureDimension::k2d);
+    auto* two_d = create<sem::DepthTexture>(ast::TextureDimension::k2d);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  auto id_two_d = b.GenerateTypeIfNeeded(two_d);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(1u, id_two_d);
+    auto id_two_d = b.GenerateTypeIfNeeded(two_d);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(1u, id_two_d);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeImage %2 2D 0 0 0 1 Unknown
 )");
 }
 
 TEST_F(BuilderTest_Type, DepthTexture_Generate_2dArray) {
-  auto* two_d_array =
-      create<sem::DepthTexture>(ast::TextureDimension::k2dArray);
+    auto* two_d_array = create<sem::DepthTexture>(ast::TextureDimension::k2dArray);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  auto id_two_d_array = b.GenerateTypeIfNeeded(two_d_array);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(1u, id_two_d_array);
+    auto id_two_d_array = b.GenerateTypeIfNeeded(two_d_array);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(1u, id_two_d_array);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeImage %2 2D 0 1 0 1 Unknown
 )");
 }
 
 TEST_F(BuilderTest_Type, DepthTexture_Generate_Cube) {
-  auto* cube = create<sem::DepthTexture>(ast::TextureDimension::kCube);
+    auto* cube = create<sem::DepthTexture>(ast::TextureDimension::kCube);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  auto id_cube = b.GenerateTypeIfNeeded(cube);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(1u, id_cube);
+    auto id_cube = b.GenerateTypeIfNeeded(cube);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(1u, id_cube);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeImage %2 Cube 0 0 0 1 Unknown
 )");
-  EXPECT_EQ(DumpInstructions(b.capabilities()), "");
+    EXPECT_EQ(DumpInstructions(b.capabilities()), "");
 }
 
 TEST_F(BuilderTest_Type, DepthTexture_Generate_CubeArray) {
-  auto* cube_array =
-      create<sem::DepthTexture>(ast::TextureDimension::kCubeArray);
+    auto* cube_array = create<sem::DepthTexture>(ast::TextureDimension::kCubeArray);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  auto id_cube_array = b.GenerateTypeIfNeeded(cube_array);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(1u, id_cube_array);
+    auto id_cube_array = b.GenerateTypeIfNeeded(cube_array);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(1u, id_cube_array);
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeImage %2 Cube 0 1 0 1 Unknown
 )");
-  EXPECT_EQ(DumpInstructions(b.capabilities()),
-            R"(OpCapability SampledCubeArray
+    EXPECT_EQ(DumpInstructions(b.capabilities()),
+              R"(OpCapability SampledCubeArray
 )");
 }
 
 TEST_F(BuilderTest_Type, MultisampledTexture_Generate_2d_i32) {
-  auto* i32 = create<sem::I32>();
-  auto* ms = create<sem::MultisampledTexture>(ast::TextureDimension::k2d, i32);
+    auto* i32 = create<sem::I32>();
+    auto* ms = create<sem::MultisampledTexture>(ast::TextureDimension::k2d, i32);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_EQ(1u, b.GenerateTypeIfNeeded(ms));
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
+    EXPECT_EQ(1u, b.GenerateTypeIfNeeded(ms));
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
 %1 = OpTypeImage %2 2D 0 0 1 1 Unknown
 )");
 }
 
 TEST_F(BuilderTest_Type, MultisampledTexture_Generate_2d_u32) {
-  auto* u32 = create<sem::U32>();
-  auto* ms = create<sem::MultisampledTexture>(ast::TextureDimension::k2d, u32);
+    auto* u32 = create<sem::U32>();
+    auto* ms = create<sem::MultisampledTexture>(ast::TextureDimension::k2d, u32);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_EQ(b.GenerateTypeIfNeeded(ms), 1u);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()),
-            R"(%2 = OpTypeInt 32 0
+    EXPECT_EQ(b.GenerateTypeIfNeeded(ms), 1u);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()),
+              R"(%2 = OpTypeInt 32 0
 %1 = OpTypeImage %2 2D 0 0 1 1 Unknown
 )");
 }
 
 TEST_F(BuilderTest_Type, MultisampledTexture_Generate_2d_f32) {
-  auto* f32 = create<sem::F32>();
-  auto* ms = create<sem::MultisampledTexture>(ast::TextureDimension::k2d, f32);
+    auto* f32 = create<sem::F32>();
+    auto* ms = create<sem::MultisampledTexture>(ast::TextureDimension::k2d, f32);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_EQ(b.GenerateTypeIfNeeded(ms), 1u);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()),
-            R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(b.GenerateTypeIfNeeded(ms), 1u);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()),
+              R"(%2 = OpTypeFloat 32
 %1 = OpTypeImage %2 2D 0 0 1 1 Unknown
 )");
 }
 
 TEST_F(BuilderTest_Type, SampledTexture_Generate_1d_i32) {
-  auto* s = create<sem::SampledTexture>(ast::TextureDimension::k1d,
-                                        create<sem::I32>());
+    auto* s = create<sem::SampledTexture>(ast::TextureDimension::k1d, create<sem::I32>());
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_EQ(b.GenerateTypeIfNeeded(s), 1u);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()),
-            R"(%2 = OpTypeInt 32 1
+    EXPECT_EQ(b.GenerateTypeIfNeeded(s), 1u);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()),
+              R"(%2 = OpTypeInt 32 1
 %1 = OpTypeImage %2 1D 0 0 0 1 Unknown
 )");
 
-  EXPECT_EQ(DumpInstructions(b.capabilities()),
-            R"(OpCapability Sampled1D
+    EXPECT_EQ(DumpInstructions(b.capabilities()),
+              R"(OpCapability Sampled1D
 )");
 }
 
 TEST_F(BuilderTest_Type, SampledTexture_Generate_1d_u32) {
-  auto* u32 = create<sem::U32>();
-  auto* s = create<sem::SampledTexture>(ast::TextureDimension::k1d, u32);
+    auto* u32 = create<sem::U32>();
+    auto* s = create<sem::SampledTexture>(ast::TextureDimension::k1d, u32);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_EQ(b.GenerateTypeIfNeeded(s), 1u);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()),
-            R"(%2 = OpTypeInt 32 0
+    EXPECT_EQ(b.GenerateTypeIfNeeded(s), 1u);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()),
+              R"(%2 = OpTypeInt 32 0
 %1 = OpTypeImage %2 1D 0 0 0 1 Unknown
 )");
 
-  EXPECT_EQ(DumpInstructions(b.capabilities()),
-            R"(OpCapability Sampled1D
+    EXPECT_EQ(DumpInstructions(b.capabilities()),
+              R"(OpCapability Sampled1D
 )");
 }
 
 TEST_F(BuilderTest_Type, SampledTexture_Generate_1d_f32) {
-  auto* f32 = create<sem::F32>();
-  auto* s = create<sem::SampledTexture>(ast::TextureDimension::k1d, f32);
+    auto* f32 = create<sem::F32>();
+    auto* s = create<sem::SampledTexture>(ast::TextureDimension::k1d, f32);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_EQ(b.GenerateTypeIfNeeded(s), 1u);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()),
-            R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(b.GenerateTypeIfNeeded(s), 1u);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()),
+              R"(%2 = OpTypeFloat 32
 %1 = OpTypeImage %2 1D 0 0 0 1 Unknown
 )");
 
-  EXPECT_EQ(DumpInstructions(b.capabilities()),
-            R"(OpCapability Sampled1D
+    EXPECT_EQ(DumpInstructions(b.capabilities()),
+              R"(OpCapability Sampled1D
 )");
 }
 
 TEST_F(BuilderTest_Type, SampledTexture_Generate_2d) {
-  auto* f32 = create<sem::F32>();
-  auto* s = create<sem::SampledTexture>(ast::TextureDimension::k2d, f32);
+    auto* f32 = create<sem::F32>();
+    auto* s = create<sem::SampledTexture>(ast::TextureDimension::k2d, f32);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_EQ(b.GenerateTypeIfNeeded(s), 1u);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()),
-            R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(b.GenerateTypeIfNeeded(s), 1u);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()),
+              R"(%2 = OpTypeFloat 32
 %1 = OpTypeImage %2 2D 0 0 0 1 Unknown
 )");
 }
 
 TEST_F(BuilderTest_Type, SampledTexture_Generate_2d_array) {
-  auto* f32 = create<sem::F32>();
-  auto* s = create<sem::SampledTexture>(ast::TextureDimension::k2dArray, f32);
+    auto* f32 = create<sem::F32>();
+    auto* s = create<sem::SampledTexture>(ast::TextureDimension::k2dArray, f32);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_EQ(b.GenerateTypeIfNeeded(s), 1u);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()),
-            R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(b.GenerateTypeIfNeeded(s), 1u);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()),
+              R"(%2 = OpTypeFloat 32
 %1 = OpTypeImage %2 2D 0 1 0 1 Unknown
 )");
 }
 
 TEST_F(BuilderTest_Type, SampledTexture_Generate_3d) {
-  auto* f32 = create<sem::F32>();
-  auto* s = create<sem::SampledTexture>(ast::TextureDimension::k3d, f32);
+    auto* f32 = create<sem::F32>();
+    auto* s = create<sem::SampledTexture>(ast::TextureDimension::k3d, f32);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_EQ(b.GenerateTypeIfNeeded(s), 1u);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()),
-            R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(b.GenerateTypeIfNeeded(s), 1u);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()),
+              R"(%2 = OpTypeFloat 32
 %1 = OpTypeImage %2 3D 0 0 0 1 Unknown
 )");
 }
 
 TEST_F(BuilderTest_Type, SampledTexture_Generate_Cube) {
-  auto* f32 = create<sem::F32>();
-  auto* s = create<sem::SampledTexture>(ast::TextureDimension::kCube, f32);
+    auto* f32 = create<sem::F32>();
+    auto* s = create<sem::SampledTexture>(ast::TextureDimension::kCube, f32);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_EQ(b.GenerateTypeIfNeeded(s), 1u);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()),
-            R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(b.GenerateTypeIfNeeded(s), 1u);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()),
+              R"(%2 = OpTypeFloat 32
 %1 = OpTypeImage %2 Cube 0 0 0 1 Unknown
 )");
-  EXPECT_EQ(DumpInstructions(b.capabilities()), "");
+    EXPECT_EQ(DumpInstructions(b.capabilities()), "");
 }
 
 TEST_F(BuilderTest_Type, SampledTexture_Generate_CubeArray) {
-  auto* f32 = create<sem::F32>();
-  auto* s = create<sem::SampledTexture>(ast::TextureDimension::kCubeArray, f32);
+    auto* f32 = create<sem::F32>();
+    auto* s = create<sem::SampledTexture>(ast::TextureDimension::kCubeArray, f32);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_EQ(b.GenerateTypeIfNeeded(s), 1u);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()),
-            R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(b.GenerateTypeIfNeeded(s), 1u);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()),
+              R"(%2 = OpTypeFloat 32
 %1 = OpTypeImage %2 Cube 0 1 0 1 Unknown
 )");
-  EXPECT_EQ(DumpInstructions(b.capabilities()),
-            R"(OpCapability SampledCubeArray
+    EXPECT_EQ(DumpInstructions(b.capabilities()),
+              R"(OpCapability SampledCubeArray
 )");
 }
 
 TEST_F(BuilderTest_Type, StorageTexture_Generate_1d) {
-  auto* s =
-      ty.storage_texture(ast::TextureDimension::k1d,
-                         ast::TexelFormat::kR32Float, ast::Access::kWrite);
+    auto* s = ty.storage_texture(ast::TextureDimension::k1d, ast::TexelFormat::kR32Float,
+                                 ast::Access::kWrite);
 
-  Global("test_var", s,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    Global("test_var", s,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_EQ(b.GenerateTypeIfNeeded(program->TypeOf(s)), 1u);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(b.GenerateTypeIfNeeded(program->TypeOf(s)), 1u);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeImage %2 1D 0 0 0 2 R32f
 )");
 }
 
 TEST_F(BuilderTest_Type, StorageTexture_Generate_2d) {
-  auto* s =
-      ty.storage_texture(ast::TextureDimension::k2d,
-                         ast::TexelFormat::kR32Float, ast::Access::kWrite);
+    auto* s = ty.storage_texture(ast::TextureDimension::k2d, ast::TexelFormat::kR32Float,
+                                 ast::Access::kWrite);
 
-  Global("test_var", s,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    Global("test_var", s,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_EQ(b.GenerateTypeIfNeeded(program->TypeOf(s)), 1u);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(b.GenerateTypeIfNeeded(program->TypeOf(s)), 1u);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeImage %2 2D 0 0 0 2 R32f
 )");
 }
 
 TEST_F(BuilderTest_Type, StorageTexture_Generate_2dArray) {
-  auto* s =
-      ty.storage_texture(ast::TextureDimension::k2dArray,
-                         ast::TexelFormat::kR32Float, ast::Access::kWrite);
+    auto* s = ty.storage_texture(ast::TextureDimension::k2dArray, ast::TexelFormat::kR32Float,
+                                 ast::Access::kWrite);
 
-  Global("test_var", s,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    Global("test_var", s,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_EQ(b.GenerateTypeIfNeeded(program->TypeOf(s)), 1u);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(b.GenerateTypeIfNeeded(program->TypeOf(s)), 1u);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeImage %2 2D 0 1 0 2 R32f
 )");
 }
 
 TEST_F(BuilderTest_Type, StorageTexture_Generate_3d) {
-  auto* s =
-      ty.storage_texture(ast::TextureDimension::k3d,
-                         ast::TexelFormat::kR32Float, ast::Access::kWrite);
+    auto* s = ty.storage_texture(ast::TextureDimension::k3d, ast::TexelFormat::kR32Float,
+                                 ast::Access::kWrite);
 
-  Global("test_var", s,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    Global("test_var", s,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_EQ(b.GenerateTypeIfNeeded(program->TypeOf(s)), 1u);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(b.GenerateTypeIfNeeded(program->TypeOf(s)), 1u);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeImage %2 3D 0 0 0 2 R32f
 )");
 }
 
-TEST_F(BuilderTest_Type,
-       StorageTexture_Generate_SampledTypeFloat_Format_r32float) {
-  auto* s =
-      ty.storage_texture(ast::TextureDimension::k2d,
-                         ast::TexelFormat::kR32Float, ast::Access::kWrite);
+TEST_F(BuilderTest_Type, StorageTexture_Generate_SampledTypeFloat_Format_r32float) {
+    auto* s = ty.storage_texture(ast::TextureDimension::k2d, ast::TexelFormat::kR32Float,
+                                 ast::Access::kWrite);
 
-  Global("test_var", s,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    Global("test_var", s,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_EQ(b.GenerateTypeIfNeeded(program->TypeOf(s)), 1u);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    EXPECT_EQ(b.GenerateTypeIfNeeded(program->TypeOf(s)), 1u);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %1 = OpTypeImage %2 2D 0 0 0 2 R32f
 )");
 }
 
-TEST_F(BuilderTest_Type,
-       StorageTexture_Generate_SampledTypeSint_Format_r32sint) {
-  auto* s = ty.storage_texture(ast::TextureDimension::k2d,
-                               ast::TexelFormat::kR32Sint, ast::Access::kWrite);
+TEST_F(BuilderTest_Type, StorageTexture_Generate_SampledTypeSint_Format_r32sint) {
+    auto* s = ty.storage_texture(ast::TextureDimension::k2d, ast::TexelFormat::kR32Sint,
+                                 ast::Access::kWrite);
 
-  Global("test_var", s,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    Global("test_var", s,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_EQ(b.GenerateTypeIfNeeded(program->TypeOf(s)), 1u);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
+    EXPECT_EQ(b.GenerateTypeIfNeeded(program->TypeOf(s)), 1u);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
 %1 = OpTypeImage %2 2D 0 0 0 2 R32i
 )");
 }
 
-TEST_F(BuilderTest_Type,
-       StorageTexture_Generate_SampledTypeUint_Format_r32uint) {
-  auto* s = ty.storage_texture(ast::TextureDimension::k2d,
-                               ast::TexelFormat::kR32Uint, ast::Access::kWrite);
+TEST_F(BuilderTest_Type, StorageTexture_Generate_SampledTypeUint_Format_r32uint) {
+    auto* s = ty.storage_texture(ast::TextureDimension::k2d, ast::TexelFormat::kR32Uint,
+                                 ast::Access::kWrite);
 
-  Global("test_var", s,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    Global("test_var", s,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_EQ(b.GenerateTypeIfNeeded(program->TypeOf(s)), 1u);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 0
+    EXPECT_EQ(b.GenerateTypeIfNeeded(program->TypeOf(s)), 1u);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 0
 %1 = OpTypeImage %2 2D 0 0 0 2 R32ui
 )");
 }
 
 TEST_F(BuilderTest_Type, Sampler) {
-  auto* sampler = create<sem::Sampler>(ast::SamplerKind::kSampler);
+    auto* sampler = create<sem::Sampler>(ast::SamplerKind::kSampler);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_EQ(b.GenerateTypeIfNeeded(sampler), 1u);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), "%1 = OpTypeSampler\n");
+    EXPECT_EQ(b.GenerateTypeIfNeeded(sampler), 1u);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), "%1 = OpTypeSampler\n");
 }
 
 TEST_F(BuilderTest_Type, ComparisonSampler) {
-  auto* sampler = create<sem::Sampler>(ast::SamplerKind::kComparisonSampler);
+    auto* sampler = create<sem::Sampler>(ast::SamplerKind::kComparisonSampler);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_EQ(b.GenerateTypeIfNeeded(sampler), 1u);
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), "%1 = OpTypeSampler\n");
+    EXPECT_EQ(b.GenerateTypeIfNeeded(sampler), 1u);
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), "%1 = OpTypeSampler\n");
 }
 
 TEST_F(BuilderTest_Type, Dedup_Sampler_And_ComparisonSampler) {
-  auto* comp_sampler =
-      create<sem::Sampler>(ast::SamplerKind::kComparisonSampler);
-  auto* sampler = create<sem::Sampler>(ast::SamplerKind::kSampler);
+    auto* comp_sampler = create<sem::Sampler>(ast::SamplerKind::kComparisonSampler);
+    auto* sampler = create<sem::Sampler>(ast::SamplerKind::kSampler);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  EXPECT_EQ(b.GenerateTypeIfNeeded(comp_sampler), 1u);
+    EXPECT_EQ(b.GenerateTypeIfNeeded(comp_sampler), 1u);
 
-  EXPECT_EQ(b.GenerateTypeIfNeeded(sampler), 1u);
+    EXPECT_EQ(b.GenerateTypeIfNeeded(sampler), 1u);
 
-  ASSERT_FALSE(b.has_error()) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), "%1 = OpTypeSampler\n");
+    ASSERT_FALSE(b.has_error()) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), "%1 = OpTypeSampler\n");
 }
 
 }  // namespace
diff --git a/src/tint/writer/spirv/builder_unary_op_expression_test.cc b/src/tint/writer/spirv/builder_unary_op_expression_test.cc
index ae08c94..c34ae32 100644
--- a/src/tint/writer/spirv/builder_unary_op_expression_test.cc
+++ b/src/tint/writer/spirv/builder_unary_op_expression_test.cc
@@ -15,101 +15,100 @@
 #include "src/tint/writer/spirv/spv_dump.h"
 #include "src/tint/writer/spirv/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::spirv {
 namespace {
 
 using BuilderTest = TestHelper;
 
 TEST_F(BuilderTest, UnaryOp_Negation_Integer) {
-  auto* expr = create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation, Expr(1));
-  WrapInFunction(expr);
+    auto* expr = create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation, Expr(1_i));
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateUnaryOpExpression(expr), 1u) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateUnaryOpExpression(expr), 1u) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
 %3 = OpConstant %2 1
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%1 = OpSNegate %2 %3
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%1 = OpSNegate %2 %3
 )");
 }
 
 TEST_F(BuilderTest, UnaryOp_Negation_Float) {
-  auto* expr =
-      create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation, Expr(1.f));
-  WrapInFunction(expr);
+    auto* expr = create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation, Expr(1.f));
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateUnaryOpExpression(expr), 1u) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateUnaryOpExpression(expr), 1u) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
 %3 = OpConstant %2 1
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%1 = OpFNegate %2 %3
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%1 = OpFNegate %2 %3
 )");
 }
 
 TEST_F(BuilderTest, UnaryOp_Complement) {
-  auto* expr =
-      create<ast::UnaryOpExpression>(ast::UnaryOp::kComplement, Expr(1));
-  WrapInFunction(expr);
+    auto* expr = create<ast::UnaryOpExpression>(ast::UnaryOp::kComplement, Expr(1_i));
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateUnaryOpExpression(expr), 1u) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateUnaryOpExpression(expr), 1u) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeInt 32 1
 %3 = OpConstant %2 1
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%1 = OpNot %2 %3
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%1 = OpNot %2 %3
 )");
 }
 
 TEST_F(BuilderTest, UnaryOp_Not) {
-  auto* expr = create<ast::UnaryOpExpression>(ast::UnaryOp::kNot, Expr(false));
-  WrapInFunction(expr);
+    auto* expr = create<ast::UnaryOpExpression>(ast::UnaryOp::kNot, Expr(false));
+    WrapInFunction(expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_EQ(b.GenerateUnaryOpExpression(expr), 1u) << b.error();
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeBool
+    b.push_function(Function{});
+    EXPECT_EQ(b.GenerateUnaryOpExpression(expr), 1u) << b.error();
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeBool
 %3 = OpConstantFalse %2
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%1 = OpLogicalNot %2 %3
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%1 = OpLogicalNot %2 %3
 )");
 }
 
 TEST_F(BuilderTest, UnaryOp_LoadRequired) {
-  auto* var = Var("param", ty.vec3<f32>());
+    auto* var = Var("param", ty.vec3<f32>());
 
-  auto* expr =
-      create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation, Expr("param"));
-  WrapInFunction(var, expr);
+    auto* expr = create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation, Expr("param"));
+    WrapInFunction(var, expr);
 
-  spirv::Builder& b = Build();
+    spirv::Builder& b = Build();
 
-  b.push_function(Function{});
-  EXPECT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
-  EXPECT_EQ(b.GenerateUnaryOpExpression(expr), 6u) << b.error();
-  ASSERT_FALSE(b.has_error()) << b.error();
+    b.push_function(Function{});
+    EXPECT_TRUE(b.GenerateFunctionVariable(var)) << b.error();
+    EXPECT_EQ(b.GenerateUnaryOpExpression(expr), 6u) << b.error();
+    ASSERT_FALSE(b.has_error()) << b.error();
 
-  EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
+    EXPECT_EQ(DumpInstructions(b.types()), R"(%4 = OpTypeFloat 32
 %3 = OpTypeVector %4 3
 %2 = OpTypePointer Function %3
 %5 = OpConstantNull %3
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
-            R"(%1 = OpVariable %2 Function %5
+    EXPECT_EQ(DumpInstructions(b.functions()[0].variables()),
+              R"(%1 = OpVariable %2 Function %5
 )");
-  EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
-            R"(%7 = OpLoad %3 %1
+    EXPECT_EQ(DumpInstructions(b.functions()[0].instructions()),
+              R"(%7 = OpLoad %3 %1
 %6 = OpFNegate %3 %7
 )");
 }
diff --git a/src/tint/writer/spirv/function.cc b/src/tint/writer/spirv/function.cc
index c7dc855..871ef3f 100644
--- a/src/tint/writer/spirv/function.cc
+++ b/src/tint/writer/spirv/function.cc
@@ -16,9 +16,7 @@
 
 namespace tint::writer::spirv {
 
-Function::Function()
-    : declaration_(Instruction{spv::Op::OpNop, {}}),
-      label_op_(Operand::Int(0)) {}
+Function::Function() : declaration_(Instruction{spv::Op::OpNop, {}}), label_op_(Operand(0u)) {}
 
 Function::Function(const Instruction& declaration,
                    const Operand& label_op,
@@ -30,22 +28,22 @@
 Function::~Function() = default;
 
 void Function::iterate(std::function<void(const Instruction&)> cb) const {
-  cb(declaration_);
+    cb(declaration_);
 
-  for (const auto& param : params_) {
-    cb(param);
-  }
+    for (const auto& param : params_) {
+        cb(param);
+    }
 
-  cb(Instruction{spv::Op::OpLabel, {label_op_}});
+    cb(Instruction{spv::Op::OpLabel, {label_op_}});
 
-  for (const auto& var : vars_) {
-    cb(var);
-  }
-  for (const auto& inst : instructions_) {
-    cb(inst);
-  }
+    for (const auto& var : vars_) {
+        cb(var);
+    }
+    for (const auto& inst : instructions_) {
+        cb(inst);
+    }
 
-  cb(Instruction{spv::Op::OpFunctionEnd, {}});
+    cb(Instruction{spv::Op::OpFunctionEnd, {}});
 }
 
 }  // namespace tint::writer::spirv
diff --git a/src/tint/writer/spirv/function.h b/src/tint/writer/spirv/function.h
index de6f8a4..05012f2 100644
--- a/src/tint/writer/spirv/function.h
+++ b/src/tint/writer/spirv/function.h
@@ -23,73 +23,73 @@
 
 /// A SPIR-V function
 class Function {
- public:
-  /// Constructor for testing purposes
-  /// This creates a bad declaration, so won't generate correct SPIR-V
-  Function();
+  public:
+    /// Constructor for testing purposes
+    /// This creates a bad declaration, so won't generate correct SPIR-V
+    Function();
 
-  /// Constructor
-  /// @param declaration the function declaration
-  /// @param label_op the operand for function's entry block label
-  /// @param params the function parameters
-  Function(const Instruction& declaration,
-           const Operand& label_op,
-           const InstructionList& params);
-  /// Copy constructor
-  /// @param other the function to copy
-  Function(const Function& other);
-  ~Function();
+    /// Constructor
+    /// @param declaration the function declaration
+    /// @param label_op the operand for function's entry block label
+    /// @param params the function parameters
+    Function(const Instruction& declaration,
+             const Operand& label_op,
+             const InstructionList& params);
+    /// Copy constructor
+    /// @param other the function to copy
+    Function(const Function& other);
+    ~Function();
 
-  /// Iterates over the function call the cb on each instruction
-  /// @param cb the callback to call
-  void iterate(std::function<void(const Instruction&)> cb) const;
+    /// Iterates over the function call the cb on each instruction
+    /// @param cb the callback to call
+    void iterate(std::function<void(const Instruction&)> cb) const;
 
-  /// @returns the declaration
-  const Instruction& declaration() const { return declaration_; }
+    /// @returns the declaration
+    const Instruction& declaration() const { return declaration_; }
 
-  /// @returns the label ID for the function entry block
-  uint32_t label_id() const { return label_op_.to_i(); }
+    /// @returns the label ID for the function entry block
+    uint32_t label_id() const { return std::get<uint32_t>(label_op_); }
 
-  /// Adds an instruction to the instruction list
-  /// @param op the op to set
-  /// @param operands the operands for the instruction
-  void push_inst(spv::Op op, const OperandList& operands) {
-    instructions_.push_back(Instruction{op, operands});
-  }
-  /// @returns the instruction list
-  const InstructionList& instructions() const { return instructions_; }
-
-  /// Adds a variable to the variable list
-  /// @param operands the operands for the variable
-  void push_var(const OperandList& operands) {
-    vars_.push_back(Instruction{spv::Op::OpVariable, operands});
-  }
-  /// @returns the variable list
-  const InstructionList& variables() const { return vars_; }
-
-  /// @returns the word length of the function
-  uint32_t word_length() const {
-    // 1 for the Label and 1 for the FunctionEnd
-    uint32_t size = 2 + declaration_.word_length();
-
-    for (const auto& param : params_) {
-      size += param.word_length();
+    /// Adds an instruction to the instruction list
+    /// @param op the op to set
+    /// @param operands the operands for the instruction
+    void push_inst(spv::Op op, const OperandList& operands) {
+        instructions_.push_back(Instruction{op, operands});
     }
-    for (const auto& var : vars_) {
-      size += var.word_length();
-    }
-    for (const auto& inst : instructions_) {
-      size += inst.word_length();
-    }
-    return size;
-  }
+    /// @returns the instruction list
+    const InstructionList& instructions() const { return instructions_; }
 
- private:
-  Instruction declaration_;
-  Operand label_op_;
-  InstructionList params_;
-  InstructionList vars_;
-  InstructionList instructions_;
+    /// Adds a variable to the variable list
+    /// @param operands the operands for the variable
+    void push_var(const OperandList& operands) {
+        vars_.push_back(Instruction{spv::Op::OpVariable, operands});
+    }
+    /// @returns the variable list
+    const InstructionList& variables() const { return vars_; }
+
+    /// @returns the word length of the function
+    uint32_t word_length() const {
+        // 1 for the Label and 1 for the FunctionEnd
+        uint32_t size = 2 + declaration_.word_length();
+
+        for (const auto& param : params_) {
+            size += param.word_length();
+        }
+        for (const auto& var : vars_) {
+            size += var.word_length();
+        }
+        for (const auto& inst : instructions_) {
+            size += inst.word_length();
+        }
+        return size;
+    }
+
+  private:
+    Instruction declaration_;
+    Operand label_op_;
+    InstructionList params_;
+    InstructionList vars_;
+    InstructionList instructions_;
 };
 
 }  // namespace tint::writer::spirv
diff --git a/src/tint/writer/spirv/generator.cc b/src/tint/writer/spirv/generator.cc
index 04f6e15..fa67827 100644
--- a/src/tint/writer/spirv/generator.cc
+++ b/src/tint/writer/spirv/generator.cc
@@ -25,28 +25,27 @@
 Result::Result(const Result&) = default;
 
 Result Generate(const Program* program, const Options& options) {
-  Result result;
+    Result result;
 
-  // Sanitize the program.
-  auto sanitized_result = Sanitize(program, options);
-  if (!sanitized_result.program.IsValid()) {
-    result.success = false;
-    result.error = sanitized_result.program.Diagnostics().str();
+    // Sanitize the program.
+    auto sanitized_result = Sanitize(program, options);
+    if (!sanitized_result.program.IsValid()) {
+        result.success = false;
+        result.error = sanitized_result.program.Diagnostics().str();
+        return result;
+    }
+
+    // Generate the SPIR-V code.
+    bool zero_initialize_workgroup_memory =
+        !options.disable_workgroup_init && options.use_zero_initialize_workgroup_memory_extension;
+
+    auto impl = std::make_unique<GeneratorImpl>(&sanitized_result.program,
+                                                zero_initialize_workgroup_memory);
+    result.success = impl->Generate();
+    result.error = impl->error();
+    result.spirv = std::move(impl->result());
+
     return result;
-  }
-
-  // Generate the SPIR-V code.
-  bool zero_initialize_workgroup_memory =
-      !options.disable_workgroup_init &&
-      options.use_zero_initialize_workgroup_memory_extension;
-
-  auto impl = std::make_unique<GeneratorImpl>(&sanitized_result.program,
-                                              zero_initialize_workgroup_memory);
-  result.success = impl->Generate();
-  result.error = impl->error();
-  result.spirv = std::move(impl->result());
-
-  return result;
 }
 
 }  // namespace tint::writer::spirv
diff --git a/src/tint/writer/spirv/generator.h b/src/tint/writer/spirv/generator.h
index 81428b4..ce871ff 100644
--- a/src/tint/writer/spirv/generator.h
+++ b/src/tint/writer/spirv/generator.h
@@ -34,40 +34,40 @@
 
 /// Configuration options used for generating SPIR-V.
 struct Options {
-  /// Set to `true` to generate a PointSize builtin and have it set to 1.0
-  /// from all vertex shaders in the module.
-  bool emit_vertex_point_size = true;
+    /// Set to `true` to generate a PointSize builtin and have it set to 1.0
+    /// from all vertex shaders in the module.
+    bool emit_vertex_point_size = true;
 
-  /// Set to `true` to disable workgroup memory zero initialization
-  bool disable_workgroup_init = false;
+    /// Set to `true` to disable workgroup memory zero initialization
+    bool disable_workgroup_init = false;
 
-  /// Set to 'true' to generates binding mappings for external textures
-  bool generate_external_texture_bindings = false;
+    /// Set to 'true' to generates binding mappings for external textures
+    bool generate_external_texture_bindings = false;
 
-  /// Set to `true` to initialize workgroup memory with OpConstantNull when
-  /// VK_KHR_zero_initialize_workgroup_memory is enabled.
-  bool use_zero_initialize_workgroup_memory_extension = false;
+    /// Set to `true` to initialize workgroup memory with OpConstantNull when
+    /// VK_KHR_zero_initialize_workgroup_memory is enabled.
+    bool use_zero_initialize_workgroup_memory_extension = false;
 };
 
 /// The result produced when generating SPIR-V.
 struct Result {
-  /// Constructor
-  Result();
+    /// Constructor
+    Result();
 
-  /// Destructor
-  ~Result();
+    /// Destructor
+    ~Result();
 
-  /// Copy constructor
-  Result(const Result&);
+    /// Copy constructor
+    Result(const Result&);
 
-  /// True if generation was successful.
-  bool success = false;
+    /// True if generation was successful.
+    bool success = false;
 
-  /// The errors generated during code generation, if any.
-  std::string error;
+    /// The errors generated during code generation, if any.
+    std::string error;
 
-  /// The generated SPIR-V.
-  std::vector<uint32_t> spirv;
+    /// The generated SPIR-V.
+    std::vector<uint32_t> spirv;
 };
 
 /// Generate SPIR-V for a program, according to a set of configuration options.
diff --git a/src/tint/writer/spirv/generator_bench.cc b/src/tint/writer/spirv/generator_bench.cc
index 6589740..4aac8bc 100644
--- a/src/tint/writer/spirv/generator_bench.cc
+++ b/src/tint/writer/spirv/generator_bench.cc
@@ -20,18 +20,18 @@
 namespace {
 
 void GenerateSPIRV(benchmark::State& state, std::string input_name) {
-  auto res = bench::LoadProgram(input_name);
-  if (auto err = std::get_if<bench::Error>(&res)) {
-    state.SkipWithError(err->msg.c_str());
-    return;
-  }
-  auto& program = std::get<bench::ProgramAndFile>(res).program;
-  for (auto _ : state) {
-    auto res = Generate(&program, {});
-    if (!res.error.empty()) {
-      state.SkipWithError(res.error.c_str());
+    auto res = bench::LoadProgram(input_name);
+    if (auto err = std::get_if<bench::Error>(&res)) {
+        state.SkipWithError(err->msg.c_str());
+        return;
     }
-  }
+    auto& program = std::get<bench::ProgramAndFile>(res).program;
+    for (auto _ : state) {
+        auto res = Generate(&program, {});
+        if (!res.error.empty()) {
+            state.SkipWithError(res.error.c_str());
+        }
+    }
 }
 
 TINT_BENCHMARK_WGSL_PROGRAMS(GenerateSPIRV);
diff --git a/src/tint/writer/spirv/generator_impl.cc b/src/tint/writer/spirv/generator_impl.cc
index 3318808..e466a24 100644
--- a/src/tint/writer/spirv/generator_impl.cc
+++ b/src/tint/writer/spirv/generator_impl.cc
@@ -38,83 +38,79 @@
 namespace tint::writer::spirv {
 
 SanitizedResult Sanitize(const Program* in, const Options& options) {
-  transform::Manager manager;
-  transform::DataMap data;
+    transform::Manager manager;
+    transform::DataMap data;
 
-  {  // Builtin polyfills
-    transform::BuiltinPolyfill::Builtins polyfills;
-    polyfills.count_leading_zeros = true;
-    polyfills.count_trailing_zeros = true;
-    polyfills.extract_bits =
-        transform::BuiltinPolyfill::Level::kClampParameters;
-    polyfills.first_leading_bit = true;
-    polyfills.first_trailing_bit = true;
-    polyfills.insert_bits = transform::BuiltinPolyfill::Level::kClampParameters;
-    data.Add<transform::BuiltinPolyfill::Config>(polyfills);
-    manager.Add<transform::BuiltinPolyfill>();
-  }
+    {  // Builtin polyfills
+        transform::BuiltinPolyfill::Builtins polyfills;
+        polyfills.count_leading_zeros = true;
+        polyfills.count_trailing_zeros = true;
+        polyfills.extract_bits = transform::BuiltinPolyfill::Level::kClampParameters;
+        polyfills.first_leading_bit = true;
+        polyfills.first_trailing_bit = true;
+        polyfills.insert_bits = transform::BuiltinPolyfill::Level::kClampParameters;
+        data.Add<transform::BuiltinPolyfill::Config>(polyfills);
+        manager.Add<transform::BuiltinPolyfill>();
+    }
 
-  if (options.generate_external_texture_bindings) {
-    auto new_bindings_map = GenerateExternalTextureBindings(in);
-    data.Add<transform::MultiplanarExternalTexture::NewBindingPoints>(
-        new_bindings_map);
-  }
-  manager.Add<transform::MultiplanarExternalTexture>();
+    if (options.generate_external_texture_bindings) {
+        auto new_bindings_map = GenerateExternalTextureBindings(in);
+        data.Add<transform::MultiplanarExternalTexture::NewBindingPoints>(new_bindings_map);
+    }
+    manager.Add<transform::MultiplanarExternalTexture>();
 
-  manager.Add<transform::Unshadow>();
-  bool disable_workgroup_init_in_sanitizer =
-      options.disable_workgroup_init ||
-      options.use_zero_initialize_workgroup_memory_extension;
-  if (!disable_workgroup_init_in_sanitizer) {
-    manager.Add<transform::ZeroInitWorkgroupMemory>();
-  }
-  manager.Add<transform::RemoveUnreachableStatements>();
-  manager.Add<transform::ExpandCompoundAssignment>();
-  manager.Add<transform::PromoteSideEffectsToDecl>();
-  manager.Add<transform::UnwindDiscardFunctions>();
-  manager.Add<transform::SimplifyPointers>();  // Required for arrayLength()
-  manager.Add<transform::FoldConstants>();
-  manager.Add<transform::VectorizeScalarMatrixConstructors>();
-  manager.Add<transform::ForLoopToLoop>();  // Must come after
-                                            // ZeroInitWorkgroupMemory
-  manager.Add<transform::CanonicalizeEntryPointIO>();
-  manager.Add<transform::AddEmptyEntryPoint>();
-  manager.Add<transform::AddSpirvBlockAttribute>();
-  manager.Add<transform::VarForDynamicIndex>();
+    manager.Add<transform::Unshadow>();
+    bool disable_workgroup_init_in_sanitizer =
+        options.disable_workgroup_init || options.use_zero_initialize_workgroup_memory_extension;
+    if (!disable_workgroup_init_in_sanitizer) {
+        manager.Add<transform::ZeroInitWorkgroupMemory>();
+    }
+    manager.Add<transform::RemoveUnreachableStatements>();
+    manager.Add<transform::ExpandCompoundAssignment>();
+    manager.Add<transform::PromoteSideEffectsToDecl>();
+    manager.Add<transform::UnwindDiscardFunctions>();
+    manager.Add<transform::SimplifyPointers>();  // Required for arrayLength()
+    manager.Add<transform::FoldConstants>();
+    manager.Add<transform::VectorizeScalarMatrixConstructors>();
+    manager.Add<transform::ForLoopToLoop>();  // Must come after
+                                              // ZeroInitWorkgroupMemory
+    manager.Add<transform::CanonicalizeEntryPointIO>();
+    manager.Add<transform::AddEmptyEntryPoint>();
+    manager.Add<transform::AddSpirvBlockAttribute>();
+    manager.Add<transform::VarForDynamicIndex>();
 
-  data.Add<transform::CanonicalizeEntryPointIO::Config>(
-      transform::CanonicalizeEntryPointIO::Config(
-          transform::CanonicalizeEntryPointIO::ShaderStyle::kSpirv, 0xFFFFFFFF,
-          options.emit_vertex_point_size));
+    data.Add<transform::CanonicalizeEntryPointIO::Config>(
+        transform::CanonicalizeEntryPointIO::Config(
+            transform::CanonicalizeEntryPointIO::ShaderStyle::kSpirv, 0xFFFFFFFF,
+            options.emit_vertex_point_size));
 
-  SanitizedResult result;
-  result.program = std::move(manager.Run(in, data).program);
-  return result;
+    SanitizedResult result;
+    result.program = std::move(manager.Run(in, data).program);
+    return result;
 }
 
-GeneratorImpl::GeneratorImpl(const Program* program,
-                             bool zero_initialize_workgroup_memory)
+GeneratorImpl::GeneratorImpl(const Program* program, bool zero_initialize_workgroup_memory)
     : builder_(program, zero_initialize_workgroup_memory) {}
 
 bool GeneratorImpl::Generate() {
-  if (builder_.Build()) {
-    writer_.WriteHeader(builder_.id_bound());
-    writer_.WriteBuilder(&builder_);
-    return true;
-  }
-  return false;
+    if (builder_.Build()) {
+        writer_.WriteHeader(builder_.id_bound());
+        writer_.WriteBuilder(&builder_);
+        return true;
+    }
+    return false;
 }
 
 const std::vector<uint32_t>& GeneratorImpl::result() const {
-  return writer_.result();
+    return writer_.result();
 }
 
 std::vector<uint32_t>& GeneratorImpl::result() {
-  return writer_.result();
+    return writer_.result();
 }
 
 std::string GeneratorImpl::error() const {
-  return builder_.error();
+    return builder_.error();
 }
 
 }  // namespace tint::writer::spirv
diff --git a/src/tint/writer/spirv/generator_impl.h b/src/tint/writer/spirv/generator_impl.h
index 2e02af1..106e2f8 100644
--- a/src/tint/writer/spirv/generator_impl.h
+++ b/src/tint/writer/spirv/generator_impl.h
@@ -27,8 +27,8 @@
 
 /// The result of sanitizing a program for generation.
 struct SanitizedResult {
-  /// The sanitized program.
-  Program program;
+    /// The sanitized program.
+    Program program;
 };
 
 /// Sanitize a program in preparation for generating SPIR-V.
@@ -38,28 +38,28 @@
 
 /// Implementation class for SPIR-V generator
 class GeneratorImpl {
- public:
-  /// Constructor
-  /// @param program the program to generate
-  /// @param zero_initialize_workgroup_memory `true` to initialize all the
-  /// variables in the Workgroup storage class with OpConstantNull
-  GeneratorImpl(const Program* program, bool zero_initialize_workgroup_memory);
+  public:
+    /// Constructor
+    /// @param program the program to generate
+    /// @param zero_initialize_workgroup_memory `true` to initialize all the
+    /// variables in the Workgroup storage class with OpConstantNull
+    GeneratorImpl(const Program* program, bool zero_initialize_workgroup_memory);
 
-  /// @returns true on successful generation; false otherwise
-  bool Generate();
+    /// @returns true on successful generation; false otherwise
+    bool Generate();
 
-  /// @returns the result data
-  const std::vector<uint32_t>& result() const;
+    /// @returns the result data
+    const std::vector<uint32_t>& result() const;
 
-  /// @returns the result data
-  std::vector<uint32_t>& result();
+    /// @returns the result data
+    std::vector<uint32_t>& result();
 
-  /// @returns the error
-  std::string error() const;
+    /// @returns the error
+    std::string error() const;
 
- private:
-  Builder builder_;
-  BinaryWriter writer_;
+  private:
+    Builder builder_;
+    BinaryWriter writer_;
 };
 
 }  // namespace tint::writer::spirv
diff --git a/src/tint/writer/spirv/instruction.cc b/src/tint/writer/spirv/instruction.cc
index 4be648b..8b883c1 100644
--- a/src/tint/writer/spirv/instruction.cc
+++ b/src/tint/writer/spirv/instruction.cc
@@ -26,11 +26,11 @@
 Instruction::~Instruction() = default;
 
 uint32_t Instruction::word_length() const {
-  uint32_t size = 1;  // Initial 1 for the op and size
-  for (const auto& op : operands_) {
-    size += op.length();
-  }
-  return size;
+    uint32_t size = 1;  // Initial 1 for the op and size
+    for (const auto& op : operands_) {
+        size += OperandLength(op);
+    }
+    return size;
 }
 
 }  // namespace tint::writer::spirv
diff --git a/src/tint/writer/spirv/instruction.h b/src/tint/writer/spirv/instruction.h
index 7fd126c..2beae59 100644
--- a/src/tint/writer/spirv/instruction.h
+++ b/src/tint/writer/spirv/instruction.h
@@ -24,27 +24,27 @@
 
 /// A single SPIR-V instruction
 class Instruction {
- public:
-  /// Constructor
-  /// @param op the op to generate
-  /// @param operands the operand values for the instruction
-  Instruction(spv::Op op, OperandList operands);
-  /// Copy Constructor
-  Instruction(const Instruction&);
-  ~Instruction();
+  public:
+    /// Constructor
+    /// @param op the op to generate
+    /// @param operands the operand values for the instruction
+    Instruction(spv::Op op, OperandList operands);
+    /// Copy Constructor
+    Instruction(const Instruction&);
+    ~Instruction();
 
-  /// @returns the instructions op
-  spv::Op opcode() const { return op_; }
+    /// @returns the instructions op
+    spv::Op opcode() const { return op_; }
 
-  /// @returns the instructions operands
-  const OperandList& operands() const { return operands_; }
+    /// @returns the instructions operands
+    const OperandList& operands() const { return operands_; }
 
-  /// @returns the number of uint32_t's needed to hold the instruction
-  uint32_t word_length() const;
+    /// @returns the number of uint32_t's needed to hold the instruction
+    uint32_t word_length() const;
 
- private:
-  spv::Op op_ = spv::Op::OpNop;
-  OperandList operands_;
+  private:
+    spv::Op op_ = spv::Op::OpNop;
+    OperandList operands_;
 };
 
 /// A list of instructions
diff --git a/src/tint/writer/spirv/instruction_test.cc b/src/tint/writer/spirv/instruction_test.cc
index 2c919f0..65460c8 100644
--- a/src/tint/writer/spirv/instruction_test.cc
+++ b/src/tint/writer/spirv/instruction_test.cc
@@ -14,6 +14,8 @@
 
 #include "src/tint/writer/spirv/instruction.h"
 
+#include <string>
+
 #include "gtest/gtest.h"
 
 namespace tint::writer::spirv {
@@ -22,26 +24,24 @@
 using InstructionTest = testing::Test;
 
 TEST_F(InstructionTest, Create) {
-  Instruction i(spv::Op::OpEntryPoint, {Operand::Float(1.2f), Operand::Int(1),
-                                        Operand::String("my_str")});
-  EXPECT_EQ(i.opcode(), spv::Op::OpEntryPoint);
-  ASSERT_EQ(i.operands().size(), 3u);
+    Instruction i(spv::Op::OpEntryPoint, {Operand(1.2f), Operand(1u), Operand("my_str")});
+    EXPECT_EQ(i.opcode(), spv::Op::OpEntryPoint);
+    ASSERT_EQ(i.operands().size(), 3u);
 
-  const auto& ops = i.operands();
-  EXPECT_TRUE(ops[0].IsFloat());
-  EXPECT_FLOAT_EQ(ops[0].to_f(), 1.2f);
+    const auto& ops = i.operands();
+    ASSERT_TRUE(std::holds_alternative<float>(ops[0]));
+    EXPECT_FLOAT_EQ(std::get<float>(ops[0]), 1.2f);
 
-  EXPECT_TRUE(ops[1].IsInt());
-  EXPECT_EQ(ops[1].to_i(), 1u);
+    ASSERT_TRUE(std::holds_alternative<uint32_t>(ops[1]));
+    EXPECT_EQ(std::get<uint32_t>(ops[1]), 1u);
 
-  EXPECT_TRUE(ops[2].IsString());
-  EXPECT_EQ(ops[2].to_s(), "my_str");
+    ASSERT_TRUE(std::holds_alternative<std::string>(ops[2]));
+    EXPECT_EQ(std::get<std::string>(ops[2]), "my_str");
 }
 
 TEST_F(InstructionTest, Length) {
-  Instruction i(spv::Op::OpEntryPoint, {Operand::Float(1.2f), Operand::Int(1),
-                                        Operand::String("my_str")});
-  EXPECT_EQ(i.word_length(), 5u);
+    Instruction i(spv::Op::OpEntryPoint, {Operand(1.2f), Operand(1u), Operand("my_str")});
+    EXPECT_EQ(i.word_length(), 5u);
 }
 
 }  // namespace
diff --git a/src/tint/writer/spirv/operand.cc b/src/tint/writer/spirv/operand.cc
index 7d27249..501307f 100644
--- a/src/tint/writer/spirv/operand.cc
+++ b/src/tint/writer/spirv/operand.cc
@@ -16,46 +16,14 @@
 
 namespace tint::writer::spirv {
 
-// static
-Operand Operand::Float(float val) {
-  Operand o(Kind::kFloat);
-  o.set_float(val);
-  return o;
-}
-
-// static
-Operand Operand::Int(uint32_t val) {
-  Operand o(Kind::kInt);
-  o.set_int(val);
-  return o;
-}
-
-// static
-Operand Operand::String(const std::string& val) {
-  Operand o(Kind::kString);
-  o.set_string(val);
-  return o;
-}
-
-Operand::Operand(Kind kind) : kind_(kind) {}
-
-Operand::~Operand() = default;
-
-uint32_t Operand::length() const {
-  uint32_t val = 0;
-  switch (kind_) {
-    case Kind::kFloat:
-    case Kind::kInt:
-      val = 1;
-      break;
-    case Kind::kString:
-      // SPIR-V always nul-terminates strings. The length is rounded up to a
-      // multiple of 4 bytes with 0 bytes padding the end. Accounting for the
-      // nul terminator is why '+ 4u' is used here instead of '+ 3u'.
-      val = static_cast<uint32_t>((str_val_.length() + 4u) >> 2);
-      break;
-  }
-  return val;
+uint32_t OperandLength(const Operand& o) {
+    if (auto* str = std::get_if<std::string>(&o)) {
+        // SPIR-V always nul-terminates strings. The length is rounded up to a
+        // multiple of 4 bytes with 0 bytes padding the end. Accounting for the
+        // nul terminator is why '+ 4u' is used here instead of '+ 3u'.
+        return static_cast<uint32_t>((str->length() + 4u) >> 2);
+    }
+    return 1;
 }
 
 }  // namespace tint::writer::spirv
diff --git a/src/tint/writer/spirv/operand.h b/src/tint/writer/spirv/operand.h
index 46a5deb..3174d0c 100644
--- a/src/tint/writer/spirv/operand.h
+++ b/src/tint/writer/spirv/operand.h
@@ -15,81 +15,47 @@
 #ifndef SRC_TINT_WRITER_SPIRV_OPERAND_H_
 #define SRC_TINT_WRITER_SPIRV_OPERAND_H_
 
+#include <cstring>
 #include <string>
+// TODO(https://crbug.com/dawn/1379) Update cpplint and remove NOLINT
+#include <variant>  // NOLINT(build/include_order)
 #include <vector>
 
+#include "src/tint/utils/hash.h"
+
 namespace tint::writer::spirv {
 
 /// A single SPIR-V instruction operand
-class Operand {
- public:
-  /// The kind of the operand
-  // Note, the `kInt` will cover most cases as things like IDs in SPIR-V are
-  // just ints for the purpose of converting to binary.
-  enum class Kind { kInt = 0, kFloat, kString };
+using Operand = std::variant<uint32_t, float, std::string>;
 
-  /// Creates a float operand
-  /// @param val the float value
-  /// @returns the operand
-  static Operand Float(float val);
-  /// Creates an int operand
-  /// @param val the int value
-  /// @returns the operand
-  static Operand Int(uint32_t val);
-  /// Creates a string operand
-  /// @param val the string value
-  /// @returns the operand
-  static Operand String(const std::string& val);
+// Helper for returning an uint32_t Operand with the provided integer value.
+template <typename T>
+inline Operand U32Operand(T val) {
+    return Operand{static_cast<uint32_t>(val)};
+}
 
-  /// Constructor
-  /// @param kind the type of operand
-  explicit Operand(Kind kind);
-  /// Copy Constructor
-  Operand(const Operand&) = default;
-  ~Operand();
-
-  /// Copy assignment
-  /// @param b the operand to copy
-  /// @returns a copy of this operand
-  Operand& operator=(const Operand& b) = default;
-
-  /// Sets the float value
-  /// @param val the value to set
-  void set_float(float val) { float_val_ = val; }
-  /// Sets the int value
-  /// @param val the value to set
-  void set_int(uint32_t val) { int_val_ = val; }
-  /// Sets the string value
-  /// @param val the value to set
-  void set_string(const std::string& val) { str_val_ = val; }
-
-  /// @returns true if this is a float operand
-  bool IsFloat() const { return kind_ == Kind::kFloat; }
-  /// @returns true if this is an integer operand
-  bool IsInt() const { return kind_ == Kind::kInt; }
-  /// @returns true if this is a string operand
-  bool IsString() const { return kind_ == Kind::kString; }
-
-  /// @returns the number of uint32_t's needed for this operand
-  uint32_t length() const;
-
-  /// @returns the float value
-  float to_f() const { return float_val_; }
-  /// @returns the int value
-  uint32_t to_i() const { return int_val_; }
-  /// @returns the string value
-  const std::string& to_s() const { return str_val_; }
-
- private:
-  Kind kind_ = Kind::kInt;
-  float float_val_ = 0.0;
-  uint32_t int_val_ = 0;
-  std::string str_val_;
-};
+/// @returns the number of uint32_t's needed for this operand
+uint32_t OperandLength(const Operand& o);
 
 /// A list of operands
 using OperandList = std::vector<Operand>;
 
+using OperandListKey = utils::UnorderedKeyWrapper<OperandList>;
+
 }  // namespace tint::writer::spirv
 
+namespace std {
+
+/// Custom std::hash specialization for tint::writer::spirv::Operand
+template <>
+class hash<tint::writer::spirv::Operand> {
+  public:
+    /// @param o the Operand
+    /// @return the hash value
+    inline std::size_t operator()(const tint::writer::spirv::Operand& o) const {
+        return std::visit([](auto v) { return tint::utils::Hash(v); }, o);
+    }
+};
+
+}  // namespace std
 #endif  // SRC_TINT_WRITER_SPIRV_OPERAND_H_
diff --git a/src/tint/writer/spirv/operand_test.cc b/src/tint/writer/spirv/operand_test.cc
index 9a688e9..ed28406 100644
--- a/src/tint/writer/spirv/operand_test.cc
+++ b/src/tint/writer/spirv/operand_test.cc
@@ -22,41 +22,41 @@
 using OperandTest = testing::Test;
 
 TEST_F(OperandTest, CreateFloat) {
-  auto o = Operand::Float(1.2f);
-  EXPECT_TRUE(o.IsFloat());
-  EXPECT_FLOAT_EQ(o.to_f(), 1.2f);
+    auto o = Operand(1.2f);
+    ASSERT_TRUE(std::holds_alternative<float>(o));
+    EXPECT_FLOAT_EQ(std::get<float>(o), 1.2f);
 }
 
 TEST_F(OperandTest, CreateInt) {
-  auto o = Operand::Int(1);
-  EXPECT_TRUE(o.IsInt());
-  EXPECT_EQ(o.to_i(), 1u);
+    auto o = Operand(1u);
+    ASSERT_TRUE(std::holds_alternative<uint32_t>(o));
+    EXPECT_EQ(std::get<uint32_t>(o), 1u);
 }
 
 TEST_F(OperandTest, CreateString) {
-  auto o = Operand::String("my string");
-  EXPECT_TRUE(o.IsString());
-  EXPECT_EQ(o.to_s(), "my string");
+    auto o = Operand("my string");
+    ASSERT_TRUE(std::holds_alternative<std::string>(o));
+    EXPECT_EQ(std::get<std::string>(o), "my string");
 }
 
 TEST_F(OperandTest, Length_Float) {
-  auto o = Operand::Float(1.2f);
-  EXPECT_EQ(o.length(), 1u);
+    auto o = Operand(1.2f);
+    EXPECT_EQ(OperandLength(o), 1u);
 }
 
 TEST_F(OperandTest, Length_Int) {
-  auto o = Operand::Int(1);
-  EXPECT_EQ(o.length(), 1u);
+    auto o = U32Operand(1);
+    EXPECT_EQ(OperandLength(o), 1u);
 }
 
 TEST_F(OperandTest, Length_String) {
-  auto o = Operand::String("my string");
-  EXPECT_EQ(o.length(), 3u);
+    auto o = Operand("my string");
+    EXPECT_EQ(OperandLength(o), 3u);
 }
 
 TEST_F(OperandTest, Length_String_Empty) {
-  auto o = Operand::String("");
-  EXPECT_EQ(o.length(), 1u);
+    auto o = Operand("");
+    EXPECT_EQ(OperandLength(o), 1u);
 }
 
 }  // namespace
diff --git a/src/tint/writer/spirv/scalar_constant.h b/src/tint/writer/spirv/scalar_constant.h
index abb1a0d..14bcefb 100644
--- a/src/tint/writer/spirv/scalar_constant.h
+++ b/src/tint/writer/spirv/scalar_constant.h
@@ -31,97 +31,95 @@
 
 /// ScalarConstant represents a scalar constant value
 struct ScalarConstant {
-  /// The constant value
-  union Value {
-    /// The value as a bool
-    bool b;
-    /// The value as a uint32_t
-    uint32_t u32;
-    /// The value as a int32_t
-    int32_t i32;
-    /// The value as a float
-    float f32;
+    /// The constant value
+    union Value {
+        /// The value as a bool
+        bool b;
+        /// The value as a uint32_t
+        uint32_t u32;
+        /// The value as a int32_t
+        int32_t i32;
+        /// The value as a float
+        float f32;
 
-    /// The value that is wide enough to encompass all other types (including
-    /// future 64-bit data types).
-    uint64_t u64;
-  };
+        /// The value that is wide enough to encompass all other types (including
+        /// future 64-bit data types).
+        uint64_t u64;
+    };
 
-  /// The kind of constant
-  enum class Kind { kBool, kU32, kI32, kF32 };
+    /// The kind of constant
+    enum class Kind { kBool, kU32, kI32, kF32 };
 
-  /// Constructor
-  inline ScalarConstant() { value.u64 = 0; }
+    /// Constructor
+    inline ScalarConstant() { value.u64 = 0; }
 
-  /// @param value the value of the constant
-  /// @returns a new ScalarConstant with the provided value and kind Kind::kU32
-  static inline ScalarConstant U32(uint32_t value) {
-    ScalarConstant c;
-    c.value.u32 = value;
-    c.kind = Kind::kU32;
-    return c;
-  }
+    /// @param value the value of the constant
+    /// @returns a new ScalarConstant with the provided value and kind Kind::kU32
+    static inline ScalarConstant U32(uint32_t value) {
+        ScalarConstant c;
+        c.value.u32 = value;
+        c.kind = Kind::kU32;
+        return c;
+    }
 
-  /// @param value the value of the constant
-  /// @returns a new ScalarConstant with the provided value and kind Kind::kI32
-  static inline ScalarConstant I32(int32_t value) {
-    ScalarConstant c;
-    c.value.i32 = value;
-    c.kind = Kind::kI32;
-    return c;
-  }
+    /// @param value the value of the constant
+    /// @returns a new ScalarConstant with the provided value and kind Kind::kI32
+    static inline ScalarConstant I32(int32_t value) {
+        ScalarConstant c;
+        c.value.i32 = value;
+        c.kind = Kind::kI32;
+        return c;
+    }
 
-  /// @param value the value of the constant
-  /// @returns a new ScalarConstant with the provided value and kind Kind::kI32
-  static inline ScalarConstant F32(float value) {
-    ScalarConstant c;
-    c.value.f32 = value;
-    c.kind = Kind::kF32;
-    return c;
-  }
+    /// @param value the value of the constant
+    /// @returns a new ScalarConstant with the provided value and kind Kind::kI32
+    static inline ScalarConstant F32(float value) {
+        ScalarConstant c;
+        c.value.f32 = value;
+        c.kind = Kind::kF32;
+        return c;
+    }
 
-  /// @param value the value of the constant
-  /// @returns a new ScalarConstant with the provided value and kind Kind::kBool
-  static inline ScalarConstant Bool(bool value) {
-    ScalarConstant c;
-    c.value.b = value;
-    c.kind = Kind::kBool;
-    return c;
-  }
+    /// @param value the value of the constant
+    /// @returns a new ScalarConstant with the provided value and kind Kind::kBool
+    static inline ScalarConstant Bool(bool value) {
+        ScalarConstant c;
+        c.value.b = value;
+        c.kind = Kind::kBool;
+        return c;
+    }
 
-  /// Equality operator
-  /// @param rhs the ScalarConstant to compare against
-  /// @returns true if this ScalarConstant is equal to `rhs`
-  inline bool operator==(const ScalarConstant& rhs) const {
-    return value.u64 == rhs.value.u64 && kind == rhs.kind &&
-           is_spec_op == rhs.is_spec_op && constant_id == rhs.constant_id;
-  }
+    /// Equality operator
+    /// @param rhs the ScalarConstant to compare against
+    /// @returns true if this ScalarConstant is equal to `rhs`
+    inline bool operator==(const ScalarConstant& rhs) const {
+        return value.u64 == rhs.value.u64 && kind == rhs.kind && is_spec_op == rhs.is_spec_op &&
+               constant_id == rhs.constant_id;
+    }
 
-  /// Inequality operator
-  /// @param rhs the ScalarConstant to compare against
-  /// @returns true if this ScalarConstant is not equal to `rhs`
-  inline bool operator!=(const ScalarConstant& rhs) const {
-    return !(*this == rhs);
-  }
+    /// Inequality operator
+    /// @param rhs the ScalarConstant to compare against
+    /// @returns true if this ScalarConstant is not equal to `rhs`
+    inline bool operator!=(const ScalarConstant& rhs) const { return !(*this == rhs); }
 
-  /// @returns this ScalarConstant as a specialization op with the given
-  /// specialization constant identifier
-  /// @param id the constant identifier
-  ScalarConstant AsSpecOp(uint32_t id) const {
-    auto ret = *this;
-    ret.is_spec_op = true;
-    ret.constant_id = id;
-    return ret;
-  }
+    /// @returns this ScalarConstant as a specialization op with the given
+    /// specialization constant identifier
+    /// @param id the constant identifier
+    ScalarConstant AsSpecOp(uint32_t id) const {
+        auto ret = *this;
+        ret.is_spec_op = true;
+        ret.constant_id = id;
+        return ret;
+    }
 
-  /// The constant value
-  Value value;
-  /// The constant value kind
-  Kind kind = Kind::kBool;
-  /// True if the constant is a specialization op
-  bool is_spec_op = false;
-  /// The identifier if a specialization op
-  uint32_t constant_id = 0;
+    /// The constant value
+    Value value;
+    /// The constant value kind
+    Kind kind = Kind::kBool;
+    /// True if the constant is a specialization op
+    bool is_spec_op = false;
+    /// The identifier if a specialization op
+    uint32_t constant_id = 0;
 };
 
 }  // namespace tint::writer::spirv
@@ -132,15 +130,14 @@
 /// keys for std::unordered_map and std::unordered_set.
 template <>
 class hash<tint::writer::spirv::ScalarConstant> {
- public:
-  /// @param c the ScalarConstant
-  /// @return the Symbol internal value
-  inline std::size_t operator()(
-      const tint::writer::spirv::ScalarConstant& c) const {
-    uint32_t value = 0;
-    std::memcpy(&value, &c.value, sizeof(value));
-    return tint::utils::Hash(value, c.kind);
-  }
+  public:
+    /// @param c the ScalarConstant
+    /// @return the Symbol internal value
+    inline std::size_t operator()(const tint::writer::spirv::ScalarConstant& c) const {
+        uint32_t value = 0;
+        std::memcpy(&value, &c.value, sizeof(value));
+        return tint::utils::Hash(value, c.kind);
+    }
 };
 
 }  // namespace std
diff --git a/src/tint/writer/spirv/scalar_constant_test.cc b/src/tint/writer/spirv/scalar_constant_test.cc
index 253f05b..196e600 100644
--- a/src/tint/writer/spirv/scalar_constant_test.cc
+++ b/src/tint/writer/spirv/scalar_constant_test.cc
@@ -21,35 +21,35 @@
 using SpirvScalarConstantTest = TestHelper;
 
 TEST_F(SpirvScalarConstantTest, Equality) {
-  ScalarConstant a{};
-  ScalarConstant b{};
-  EXPECT_EQ(a, b);
+    ScalarConstant a{};
+    ScalarConstant b{};
+    EXPECT_EQ(a, b);
 
-  a.kind = ScalarConstant::Kind::kU32;
-  EXPECT_NE(a, b);
-  b.kind = ScalarConstant::Kind::kU32;
-  EXPECT_EQ(a, b);
+    a.kind = ScalarConstant::Kind::kU32;
+    EXPECT_NE(a, b);
+    b.kind = ScalarConstant::Kind::kU32;
+    EXPECT_EQ(a, b);
 
-  a.value.b = true;
-  EXPECT_NE(a, b);
-  b.value.b = true;
-  EXPECT_EQ(a, b);
+    a.value.b = true;
+    EXPECT_NE(a, b);
+    b.value.b = true;
+    EXPECT_EQ(a, b);
 
-  a.is_spec_op = true;
-  EXPECT_NE(a, b);
-  b.is_spec_op = true;
-  EXPECT_EQ(a, b);
+    a.is_spec_op = true;
+    EXPECT_NE(a, b);
+    b.is_spec_op = true;
+    EXPECT_EQ(a, b);
 
-  a.constant_id = 3;
-  EXPECT_NE(a, b);
-  b.constant_id = 3;
-  EXPECT_EQ(a, b);
+    a.constant_id = 3;
+    EXPECT_NE(a, b);
+    b.constant_id = 3;
+    EXPECT_EQ(a, b);
 }
 
 TEST_F(SpirvScalarConstantTest, U32) {
-  auto c = ScalarConstant::U32(123);
-  EXPECT_EQ(c.value.u32, 123u);
-  EXPECT_EQ(c.kind, ScalarConstant::Kind::kU32);
+    auto c = ScalarConstant::U32(123);
+    EXPECT_EQ(c.value.u32, 123u);
+    EXPECT_EQ(c.kind, ScalarConstant::Kind::kU32);
 }
 
 }  // namespace
diff --git a/src/tint/writer/spirv/spv_dump.cc b/src/tint/writer/spirv/spv_dump.cc
index 21dc1a5..0f95efe 100644
--- a/src/tint/writer/spirv/spv_dump.cc
+++ b/src/tint/writer/spirv/spv_dump.cc
@@ -21,65 +21,64 @@
 namespace {
 
 std::string Disassemble(const std::vector<uint32_t>& data) {
-  std::string spv_errors;
-  spv_target_env target_env = SPV_ENV_UNIVERSAL_1_0;
+    std::string spv_errors;
+    spv_target_env target_env = SPV_ENV_UNIVERSAL_1_0;
 
-  auto msg_consumer = [&spv_errors](spv_message_level_t level, const char*,
-                                    const spv_position_t& position,
-                                    const char* message) {
-    switch (level) {
-      case SPV_MSG_FATAL:
-      case SPV_MSG_INTERNAL_ERROR:
-      case SPV_MSG_ERROR:
-        spv_errors += "error: line " + std::to_string(position.index) + ": " +
-                      message + "\n";
-        break;
-      case SPV_MSG_WARNING:
-        spv_errors += "warning: line " + std::to_string(position.index) + ": " +
-                      message + "\n";
-        break;
-      case SPV_MSG_INFO:
-        spv_errors += "info: line " + std::to_string(position.index) + ": " +
-                      message + "\n";
-        break;
-      case SPV_MSG_DEBUG:
-        break;
+    auto msg_consumer = [&spv_errors](spv_message_level_t level, const char*,
+                                      const spv_position_t& position, const char* message) {
+        switch (level) {
+            case SPV_MSG_FATAL:
+            case SPV_MSG_INTERNAL_ERROR:
+            case SPV_MSG_ERROR:
+                spv_errors +=
+                    "error: line " + std::to_string(position.index) + ": " + message + "\n";
+                break;
+            case SPV_MSG_WARNING:
+                spv_errors +=
+                    "warning: line " + std::to_string(position.index) + ": " + message + "\n";
+                break;
+            case SPV_MSG_INFO:
+                spv_errors +=
+                    "info: line " + std::to_string(position.index) + ": " + message + "\n";
+                break;
+            case SPV_MSG_DEBUG:
+                break;
+        }
+    };
+
+    spvtools::SpirvTools tools(target_env);
+    tools.SetMessageConsumer(msg_consumer);
+
+    std::string result;
+    if (!tools.Disassemble(data, &result, SPV_BINARY_TO_TEXT_OPTION_NO_HEADER)) {
+        return "*** Invalid SPIR-V ***\n" + spv_errors;
     }
-  };
-
-  spvtools::SpirvTools tools(target_env);
-  tools.SetMessageConsumer(msg_consumer);
-
-  std::string result;
-  if (!tools.Disassemble(data, &result, SPV_BINARY_TO_TEXT_OPTION_NO_HEADER)) {
-    return "*** Invalid SPIR-V ***\n" + spv_errors;
-  }
-  return result;
+    return result;
 }
 
 }  // namespace
 
 std::string DumpBuilder(Builder& builder) {
-  BinaryWriter writer;
-  writer.WriteHeader(builder.id_bound());
-  writer.WriteBuilder(&builder);
-  return Disassemble(writer.result());
+    BinaryWriter writer;
+    writer.WriteHeader(builder.id_bound());
+    writer.WriteBuilder(&builder);
+    return Disassemble(writer.result());
 }
 
 std::string DumpInstruction(const Instruction& inst) {
-  BinaryWriter writer;
-  writer.WriteHeader(kDefaultMaxIdBound);
-  writer.WriteInstruction(inst);
-  return Disassemble(writer.result());
+    BinaryWriter writer;
+    writer.WriteHeader(kDefaultMaxIdBound);
+    writer.WriteInstruction(inst);
+    return Disassemble(writer.result());
 }
 
 std::string DumpInstructions(const InstructionList& insts) {
-  BinaryWriter writer;
-  writer.WriteHeader(kDefaultMaxIdBound);
-  for (const auto& inst : insts) {
-    writer.WriteInstruction(inst);
-  }
-  return Disassemble(writer.result());
+    BinaryWriter writer;
+    writer.WriteHeader(kDefaultMaxIdBound);
+    for (const auto& inst : insts) {
+        writer.WriteInstruction(inst);
+    }
+    return Disassemble(writer.result());
 }
 
 }  // namespace tint::writer::spirv
diff --git a/src/tint/writer/spirv/test_helper.h b/src/tint/writer/spirv/test_helper.h
index c8052b2..2e58760 100644
--- a/src/tint/writer/spirv/test_helper.h
+++ b/src/tint/writer/spirv/test_helper.h
@@ -29,103 +29,100 @@
 /// Helper class for testing
 template <typename BASE>
 class TestHelperBase : public ProgramBuilder, public BASE {
- public:
-  TestHelperBase() = default;
-  ~TestHelperBase() override = default;
+  public:
+    TestHelperBase() = default;
+    ~TestHelperBase() override = default;
 
-  /// Builds and returns a spirv::Builder from the program.
-  /// @note The spirv::Builder is only built once. Multiple calls to Build()
-  /// will return the same spirv::Builder without rebuilding.
-  /// @return the built spirv::Builder
-  spirv::Builder& Build() {
-    if (spirv_builder) {
-      return *spirv_builder;
+    /// Builds and returns a spirv::Builder from the program.
+    /// @note The spirv::Builder is only built once. Multiple calls to Build()
+    /// will return the same spirv::Builder without rebuilding.
+    /// @return the built spirv::Builder
+    spirv::Builder& Build() {
+        if (spirv_builder) {
+            return *spirv_builder;
+        }
+        [&]() {
+            ASSERT_TRUE(IsValid()) << "Builder program is not valid\n"
+                                   << diag::Formatter().format(Diagnostics());
+        }();
+        program = std::make_unique<Program>(std::move(*this));
+        [&]() {
+            ASSERT_TRUE(program->IsValid()) << diag::Formatter().format(program->Diagnostics());
+        }();
+        spirv_builder = std::make_unique<spirv::Builder>(program.get());
+        return *spirv_builder;
     }
-    [&]() {
-      ASSERT_TRUE(IsValid()) << "Builder program is not valid\n"
-                             << diag::Formatter().format(Diagnostics());
-    }();
-    program = std::make_unique<Program>(std::move(*this));
-    [&]() {
-      ASSERT_TRUE(program->IsValid())
-          << diag::Formatter().format(program->Diagnostics());
-    }();
-    spirv_builder = std::make_unique<spirv::Builder>(program.get());
-    return *spirv_builder;
-  }
 
-  /// Builds the program, runs the program through the transform::Spirv
-  /// sanitizer and returns a spirv::Builder from the sanitized program.
-  /// @param options The SPIR-V generator options.
-  /// @note The spirv::Builder is only built once. Multiple calls to Build()
-  /// will return the same spirv::Builder without rebuilding.
-  /// @return the built spirv::Builder
-  spirv::Builder& SanitizeAndBuild(const Options& options = {}) {
-    if (spirv_builder) {
-      return *spirv_builder;
+    /// Builds the program, runs the program through the transform::Spirv
+    /// sanitizer and returns a spirv::Builder from the sanitized program.
+    /// @param options The SPIR-V generator options.
+    /// @note The spirv::Builder is only built once. Multiple calls to Build()
+    /// will return the same spirv::Builder without rebuilding.
+    /// @return the built spirv::Builder
+    spirv::Builder& SanitizeAndBuild(const Options& options = {}) {
+        if (spirv_builder) {
+            return *spirv_builder;
+        }
+        [&]() {
+            ASSERT_TRUE(IsValid()) << "Builder program is not valid\n"
+                                   << diag::Formatter().format(Diagnostics());
+        }();
+        program = std::make_unique<Program>(std::move(*this));
+        [&]() {
+            ASSERT_TRUE(program->IsValid()) << diag::Formatter().format(program->Diagnostics());
+        }();
+        auto result = Sanitize(program.get(), options);
+        [&]() {
+            ASSERT_TRUE(result.program.IsValid())
+                << diag::Formatter().format(result.program.Diagnostics());
+        }();
+        *program = std::move(result.program);
+        spirv_builder = std::make_unique<spirv::Builder>(program.get());
+        return *spirv_builder;
     }
-    [&]() {
-      ASSERT_TRUE(IsValid()) << "Builder program is not valid\n"
-                             << diag::Formatter().format(Diagnostics());
-    }();
-    program = std::make_unique<Program>(std::move(*this));
-    [&]() {
-      ASSERT_TRUE(program->IsValid())
-          << diag::Formatter().format(program->Diagnostics());
-    }();
-    auto result = Sanitize(program.get(), options);
-    [&]() {
-      ASSERT_TRUE(result.program.IsValid())
-          << diag::Formatter().format(result.program.Diagnostics());
-    }();
-    *program = std::move(result.program);
-    spirv_builder = std::make_unique<spirv::Builder>(program.get());
-    return *spirv_builder;
-  }
 
-  /// Validate passes the generated SPIR-V of the builder `b` to the SPIR-V
-  /// Tools Validator. If the validator finds problems the test will fail.
-  /// @param b the spirv::Builder containing the built SPIR-V module
-  void Validate(spirv::Builder& b) {
-    BinaryWriter writer;
-    writer.WriteHeader(b.id_bound());
-    writer.WriteBuilder(&b);
-    auto binary = writer.result();
+    /// Validate passes the generated SPIR-V of the builder `b` to the SPIR-V
+    /// Tools Validator. If the validator finds problems the test will fail.
+    /// @param b the spirv::Builder containing the built SPIR-V module
+    void Validate(spirv::Builder& b) {
+        BinaryWriter writer;
+        writer.WriteHeader(b.id_bound());
+        writer.WriteBuilder(&b);
+        auto binary = writer.result();
 
-    std::string spv_errors;
-    auto msg_consumer = [&spv_errors](spv_message_level_t level, const char*,
-                                      const spv_position_t& position,
-                                      const char* message) {
-      switch (level) {
-        case SPV_MSG_FATAL:
-        case SPV_MSG_INTERNAL_ERROR:
-        case SPV_MSG_ERROR:
-          spv_errors += "error: line " + std::to_string(position.index) + ": " +
-                        message + "\n";
-          break;
-        case SPV_MSG_WARNING:
-          spv_errors += "warning: line " + std::to_string(position.index) +
-                        ": " + message + "\n";
-          break;
-        case SPV_MSG_INFO:
-          spv_errors += "info: line " + std::to_string(position.index) + ": " +
-                        message + "\n";
-          break;
-        case SPV_MSG_DEBUG:
-          break;
-      }
-    };
+        std::string spv_errors;
+        auto msg_consumer = [&spv_errors](spv_message_level_t level, const char*,
+                                          const spv_position_t& position, const char* message) {
+            switch (level) {
+                case SPV_MSG_FATAL:
+                case SPV_MSG_INTERNAL_ERROR:
+                case SPV_MSG_ERROR:
+                    spv_errors +=
+                        "error: line " + std::to_string(position.index) + ": " + message + "\n";
+                    break;
+                case SPV_MSG_WARNING:
+                    spv_errors +=
+                        "warning: line " + std::to_string(position.index) + ": " + message + "\n";
+                    break;
+                case SPV_MSG_INFO:
+                    spv_errors +=
+                        "info: line " + std::to_string(position.index) + ": " + message + "\n";
+                    break;
+                case SPV_MSG_DEBUG:
+                    break;
+            }
+        };
 
-    spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_2);
-    tools.SetMessageConsumer(msg_consumer);
-    ASSERT_TRUE(tools.Validate(binary)) << spv_errors;
-  }
+        spvtools::SpirvTools tools(SPV_ENV_VULKAN_1_2);
+        tools.SetMessageConsumer(msg_consumer);
+        ASSERT_TRUE(tools.Validate(binary)) << spv_errors;
+    }
 
-  /// The program built with a call to Build()
-  std::unique_ptr<Program> program;
+    /// The program built with a call to Build()
+    std::unique_ptr<Program> program;
 
- private:
-  std::unique_ptr<spirv::Builder> spirv_builder;
+  private:
+    std::unique_ptr<spirv::Builder> spirv_builder;
 };
 using TestHelper = TestHelperBase<testing::Test>;
 
diff --git a/src/tint/writer/text.h b/src/tint/writer/text.h
index 71af064..2bbf1c2 100644
--- a/src/tint/writer/text.h
+++ b/src/tint/writer/text.h
@@ -23,11 +23,11 @@
 
 /// Class to generate text source
 class Text : public Writer {
- public:
-  ~Text() override;
+  public:
+    ~Text() override;
 
-  /// @returns the result data
-  virtual std::string result() const = 0;
+    /// @returns the result data
+    virtual std::string result() const = 0;
 };
 
 }  // namespace tint::writer
diff --git a/src/tint/writer/text_generator.cc b/src/tint/writer/text_generator.cc
index 8623fd5..5e4e93f 100644
--- a/src/tint/writer/text_generator.cc
+++ b/src/tint/writer/text_generator.cc
@@ -27,127 +27,118 @@
 TextGenerator::~TextGenerator() = default;
 
 std::string TextGenerator::UniqueIdentifier(const std::string& prefix) {
-  return builder_.Symbols().NameFor(builder_.Symbols().New(prefix));
+    return builder_.Symbols().NameFor(builder_.Symbols().New(prefix));
 }
 
 std::string TextGenerator::StructName(const sem::Struct* s) {
-  auto name = builder_.Symbols().NameFor(s->Name());
-  if (name.size() > 1 && name[0] == '_' && name[1] == '_') {
-    name = utils::GetOrCreate(builtin_struct_names_, s,
-                              [&] { return UniqueIdentifier(name.substr(2)); });
-  }
-  return name;
+    auto name = builder_.Symbols().NameFor(s->Name());
+    if (name.size() > 1 && name[0] == '_' && name[1] == '_') {
+        name = utils::GetOrCreate(builtin_struct_names_, s,
+                                  [&] { return UniqueIdentifier(name.substr(2)); });
+    }
+    return name;
 }
 
-std::string TextGenerator::TrimSuffix(std::string str,
-                                      const std::string& suffix) {
-  if (str.size() >= suffix.size()) {
-    if (str.substr(str.size() - suffix.size(), suffix.size()) == suffix) {
-      return str.substr(0, str.size() - suffix.size());
+std::string TextGenerator::TrimSuffix(std::string str, const std::string& suffix) {
+    if (str.size() >= suffix.size()) {
+        if (str.substr(str.size() - suffix.size(), suffix.size()) == suffix) {
+            return str.substr(0, str.size() - suffix.size());
+        }
     }
-  }
-  return str;
+    return str;
 }
 
 TextGenerator::LineWriter::LineWriter(TextBuffer* buf) : buffer(buf) {}
 
 TextGenerator::LineWriter::LineWriter(LineWriter&& other) {
-  buffer = other.buffer;
-  other.buffer = nullptr;
+    buffer = other.buffer;
+    other.buffer = nullptr;
 }
 
 TextGenerator::LineWriter::~LineWriter() {
-  if (buffer) {
-    buffer->Append(os.str());
-  }
+    if (buffer) {
+        buffer->Append(os.str());
+    }
 }
 
 TextGenerator::TextBuffer::TextBuffer() = default;
 TextGenerator::TextBuffer::~TextBuffer() = default;
 
 void TextGenerator::TextBuffer::IncrementIndent() {
-  current_indent += 2;
+    current_indent += 2;
 }
 
 void TextGenerator::TextBuffer::DecrementIndent() {
-  current_indent = std::max(2u, current_indent) - 2u;
+    current_indent = std::max(2u, current_indent) - 2u;
 }
 
 void TextGenerator::TextBuffer::Append(const std::string& line) {
-  lines.emplace_back(Line{current_indent, line});
+    lines.emplace_back(Line{current_indent, line});
 }
 
-void TextGenerator::TextBuffer::Insert(const std::string& line,
-                                       size_t before,
-                                       uint32_t indent) {
-  if (before >= lines.size()) {
-    diag::List d;
-    TINT_ICE(Writer, d)
-        << "TextBuffer::Insert() called with before >= lines.size()\n"
-        << "  before:" << before << "\n"
-        << "  lines.size(): " << lines.size();
-    return;
-  }
-  lines.insert(lines.begin() + before, Line{indent, line});
+void TextGenerator::TextBuffer::Insert(const std::string& line, size_t before, uint32_t indent) {
+    if (before >= lines.size()) {
+        diag::List d;
+        TINT_ICE(Writer, d) << "TextBuffer::Insert() called with before >= lines.size()\n"
+                            << "  before:" << before << "\n"
+                            << "  lines.size(): " << lines.size();
+        return;
+    }
+    lines.insert(lines.begin() + before, Line{indent, line});
 }
 
 void TextGenerator::TextBuffer::Append(const TextBuffer& tb) {
-  for (auto& line : tb.lines) {
-    // TODO(bclayton): inefficent, consider optimizing
-    lines.emplace_back(Line{current_indent + line.indent, line.content});
-  }
+    for (auto& line : tb.lines) {
+        // TODO(bclayton): inefficent, consider optimizing
+        lines.emplace_back(Line{current_indent + line.indent, line.content});
+    }
 }
 
-void TextGenerator::TextBuffer::Insert(const TextBuffer& tb,
-                                       size_t before,
-                                       uint32_t indent) {
-  if (before >= lines.size()) {
-    diag::List d;
-    TINT_ICE(Writer, d)
-        << "TextBuffer::Insert() called with before >= lines.size()\n"
-        << "  before:" << before << "\n"
-        << "  lines.size(): " << lines.size();
-    return;
-  }
-  size_t idx = 0;
-  for (auto& line : tb.lines) {
-    // TODO(bclayton): inefficent, consider optimizing
-    lines.insert(lines.begin() + before + idx,
-                 Line{indent + line.indent, line.content});
-    idx++;
-  }
+void TextGenerator::TextBuffer::Insert(const TextBuffer& tb, size_t before, uint32_t indent) {
+    if (before >= lines.size()) {
+        diag::List d;
+        TINT_ICE(Writer, d) << "TextBuffer::Insert() called with before >= lines.size()\n"
+                            << "  before:" << before << "\n"
+                            << "  lines.size(): " << lines.size();
+        return;
+    }
+    size_t idx = 0;
+    for (auto& line : tb.lines) {
+        // TODO(bclayton): inefficent, consider optimizing
+        lines.insert(lines.begin() + before + idx, Line{indent + line.indent, line.content});
+        idx++;
+    }
 }
 
 std::string TextGenerator::TextBuffer::String(uint32_t indent /* = 0 */) const {
-  std::stringstream ss;
-  for (auto& line : lines) {
-    if (!line.content.empty()) {
-      for (uint32_t i = 0; i < indent + line.indent; i++) {
-        ss << " ";
-      }
-      ss << line.content;
+    std::stringstream ss;
+    for (auto& line : lines) {
+        if (!line.content.empty()) {
+            for (uint32_t i = 0; i < indent + line.indent; i++) {
+                ss << " ";
+            }
+            ss << line.content;
+        }
+        ss << std::endl;
     }
-    ss << std::endl;
-  }
-  return ss.str();
+    return ss.str();
 }
 
 TextGenerator::ScopedParen::ScopedParen(std::ostream& stream) : s(stream) {
-  s << "(";
+    s << "(";
 }
 TextGenerator::ScopedParen::~ScopedParen() {
-  s << ")";
+    s << ")";
 }
 
 TextGenerator::ScopedIndent::ScopedIndent(TextGenerator* generator)
     : ScopedIndent(generator->current_buffer_) {}
 
-TextGenerator::ScopedIndent::ScopedIndent(TextBuffer* buffer)
-    : buffer_(buffer) {
-  buffer_->IncrementIndent();
+TextGenerator::ScopedIndent::ScopedIndent(TextBuffer* buffer) : buffer_(buffer) {
+    buffer_->IncrementIndent();
 }
 TextGenerator::ScopedIndent::~ScopedIndent() {
-  buffer_->DecrementIndent();
+    buffer_->DecrementIndent();
 }
 
 }  // namespace tint::writer
diff --git a/src/tint/writer/text_generator.h b/src/tint/writer/text_generator.h
index 67501ab..2f4b578 100644
--- a/src/tint/writer/text_generator.h
+++ b/src/tint/writer/text_generator.h
@@ -28,211 +28,207 @@
 
 /// Helper methods for generators which are creating text output
 class TextGenerator {
- public:
-  /// Line holds a single line of text
-  struct Line {
-    /// The indentation of the line in blankspace
-    uint32_t indent = 0;
-    /// The content of the line, without a trailing newline character
-    std::string content;
-  };
+  public:
+    /// Line holds a single line of text
+    struct Line {
+        /// The indentation of the line in blankspace
+        uint32_t indent = 0;
+        /// The content of the line, without a trailing newline character
+        std::string content;
+    };
 
-  /// TextBuffer holds a list of lines of text.
-  struct TextBuffer {
-    // Constructor
-    TextBuffer();
+    /// TextBuffer holds a list of lines of text.
+    struct TextBuffer {
+        // Constructor
+        TextBuffer();
 
-    // Destructor
-    ~TextBuffer();
+        // Destructor
+        ~TextBuffer();
 
-    /// IncrementIndent increases the indentation of lines that will be written
-    /// to the TextBuffer
-    void IncrementIndent();
+        /// IncrementIndent increases the indentation of lines that will be written
+        /// to the TextBuffer
+        void IncrementIndent();
 
-    /// DecrementIndent decreases the indentation of lines that will be written
-    /// to the TextBuffer
-    void DecrementIndent();
+        /// DecrementIndent decreases the indentation of lines that will be written
+        /// to the TextBuffer
+        void DecrementIndent();
 
-    /// Appends the line to the end of the TextBuffer
-    /// @param line the line to append to the TextBuffer
-    void Append(const std::string& line);
+        /// Appends the line to the end of the TextBuffer
+        /// @param line the line to append to the TextBuffer
+        void Append(const std::string& line);
 
-    /// Inserts the line to the TextBuffer before the line with index `before`
-    /// @param line the line to append to the TextBuffer
-    /// @param before the zero-based index of the line to insert the text before
-    /// @param indent the indentation to apply to the inserted lines
-    void Insert(const std::string& line, size_t before, uint32_t indent);
+        /// Inserts the line to the TextBuffer before the line with index `before`
+        /// @param line the line to append to the TextBuffer
+        /// @param before the zero-based index of the line to insert the text before
+        /// @param indent the indentation to apply to the inserted lines
+        void Insert(const std::string& line, size_t before, uint32_t indent);
 
-    /// Appends the lines of `tb` to the end of this TextBuffer
-    /// @param tb the TextBuffer to append to the end of this TextBuffer
-    void Append(const TextBuffer& tb);
+        /// Appends the lines of `tb` to the end of this TextBuffer
+        /// @param tb the TextBuffer to append to the end of this TextBuffer
+        void Append(const TextBuffer& tb);
 
-    /// Inserts the lines of `tb` to the TextBuffer before the line with index
-    /// `before`
-    /// @param tb the TextBuffer to insert into this TextBuffer
-    /// @param before the zero-based index of the line to insert the text before
-    /// @param indent the indentation to apply to the inserted lines
-    void Insert(const TextBuffer& tb, size_t before, uint32_t indent);
+        /// Inserts the lines of `tb` to the TextBuffer before the line with index
+        /// `before`
+        /// @param tb the TextBuffer to insert into this TextBuffer
+        /// @param before the zero-based index of the line to insert the text before
+        /// @param indent the indentation to apply to the inserted lines
+        void Insert(const TextBuffer& tb, size_t before, uint32_t indent);
 
-    /// @returns the buffer's content as a single string
-    /// @param indent additional indentation to apply to each line
-    std::string String(uint32_t indent = 0) const;
+        /// @returns the buffer's content as a single string
+        /// @param indent additional indentation to apply to each line
+        std::string String(uint32_t indent = 0) const;
 
-    /// The current indentation of the TextBuffer. Lines appended to the
-    /// TextBuffer will use this indentation.
-    uint32_t current_indent = 0;
+        /// The current indentation of the TextBuffer. Lines appended to the
+        /// TextBuffer will use this indentation.
+        uint32_t current_indent = 0;
 
-    /// The lines
-    std::vector<Line> lines;
-  };
+        /// The lines
+        std::vector<Line> lines;
+    };
 
-  /// Constructor
-  /// @param program the program used by the generator
-  explicit TextGenerator(const Program* program);
-  ~TextGenerator();
-
-  /// Increment the emitter indent level
-  void increment_indent() { current_buffer_->IncrementIndent(); }
-  /// Decrement the emitter indent level
-  void decrement_indent() { current_buffer_->DecrementIndent(); }
-
-  /// @returns the result data
-  std::string result() const { return main_buffer_.String(); }
-
-  /// @returns the list of diagnostics raised by the generator.
-  const diag::List& Diagnostics() const { return diagnostics_; }
-
-  /// @returns the error
-  std::string error() const { return diagnostics_.str(); }
-
-  /// @return a new, unique identifier with the given prefix.
-  /// @param prefix optional prefix to apply to the generated identifier. If
-  /// empty "tint_symbol" will be used.
-  std::string UniqueIdentifier(const std::string& prefix = "");
-
-  /// @param s the semantic structure
-  /// @returns the name of the structure, taking special care of builtin
-  /// structures that start with double underscores. If the structure is a
-  /// builtin, then the returned name will be a unique name without the leading
-  /// underscores.
-  std::string StructName(const sem::Struct* s);
-
-  /// @param str the string
-  /// @param suffix the suffix to remove
-  /// @return returns str without the provided trailing suffix string. If str
-  /// doesn't end with suffix, str is returned unchanged.
-  std::string TrimSuffix(std::string str, const std::string& suffix);
-
- protected:
-  /// LineWriter is a helper that acts as a string buffer, who's content is
-  /// emitted to the TextBuffer as a single line on destruction.
-  struct LineWriter {
-   public:
     /// Constructor
-    /// @param buffer the TextBuffer that the LineWriter will append its
-    /// content to on destruction, at the end of the buffer.
-    explicit LineWriter(TextBuffer* buffer);
+    /// @param program the program used by the generator
+    explicit TextGenerator(const Program* program);
+    ~TextGenerator();
 
-    /// Move constructor
-    /// @param rhs the LineWriter to move
-    LineWriter(LineWriter&& rhs);
-    /// Destructor
-    ~LineWriter();
+    /// Increment the emitter indent level
+    void increment_indent() { current_buffer_->IncrementIndent(); }
+    /// Decrement the emitter indent level
+    void decrement_indent() { current_buffer_->DecrementIndent(); }
 
-    /// @returns the ostringstream
-    operator std::ostream&() { return os; }
+    /// @returns the result data
+    std::string result() const { return main_buffer_.String(); }
 
-    /// @param rhs the value to write to the line
-    /// @returns the ostream so calls can be chained
-    template <typename T>
-    std::ostream& operator<<(T&& rhs) {
-      return os << std::forward<T>(rhs);
+    /// @returns the list of diagnostics raised by the generator.
+    const diag::List& Diagnostics() const { return diagnostics_; }
+
+    /// @returns the error
+    std::string error() const { return diagnostics_.str(); }
+
+    /// @return a new, unique identifier with the given prefix.
+    /// @param prefix optional prefix to apply to the generated identifier. If
+    /// empty "tint_symbol" will be used.
+    std::string UniqueIdentifier(const std::string& prefix = "");
+
+    /// @param s the semantic structure
+    /// @returns the name of the structure, taking special care of builtin
+    /// structures that start with double underscores. If the structure is a
+    /// builtin, then the returned name will be a unique name without the leading
+    /// underscores.
+    std::string StructName(const sem::Struct* s);
+
+    /// @param str the string
+    /// @param suffix the suffix to remove
+    /// @return returns str without the provided trailing suffix string. If str
+    /// doesn't end with suffix, str is returned unchanged.
+    std::string TrimSuffix(std::string str, const std::string& suffix);
+
+  protected:
+    /// LineWriter is a helper that acts as a string buffer, who's content is
+    /// emitted to the TextBuffer as a single line on destruction.
+    struct LineWriter {
+      public:
+        /// Constructor
+        /// @param buffer the TextBuffer that the LineWriter will append its
+        /// content to on destruction, at the end of the buffer.
+        explicit LineWriter(TextBuffer* buffer);
+
+        /// Move constructor
+        /// @param rhs the LineWriter to move
+        LineWriter(LineWriter&& rhs);
+        /// Destructor
+        ~LineWriter();
+
+        /// @returns the ostringstream
+        operator std::ostream&() { return os; }
+
+        /// @param rhs the value to write to the line
+        /// @returns the ostream so calls can be chained
+        template <typename T>
+        std::ostream& operator<<(T&& rhs) {
+            return os << std::forward<T>(rhs);
+        }
+
+      private:
+        LineWriter(const LineWriter&) = delete;
+        LineWriter& operator=(const LineWriter&) = delete;
+
+        std::ostringstream os;
+        TextBuffer* buffer;
+    };
+
+    /// Helper for writing a '(' on construction and a ')' destruction.
+    struct ScopedParen {
+        /// Constructor
+        /// @param stream the std::ostream that will be written to
+        explicit ScopedParen(std::ostream& stream);
+        /// Destructor
+        ~ScopedParen();
+
+      private:
+        ScopedParen(ScopedParen&& rhs) = delete;
+        ScopedParen(const ScopedParen&) = delete;
+        ScopedParen& operator=(const ScopedParen&) = delete;
+        std::ostream& s;
+    };
+
+    /// Helper for incrementing indentation on construction and decrementing
+    /// indentation on destruction.
+    struct ScopedIndent {
+        /// Constructor
+        /// @param buffer the TextBuffer that the ScopedIndent will indent
+        explicit ScopedIndent(TextBuffer* buffer);
+        /// Constructor
+        /// @param generator ScopedIndent will indent the generator's
+        /// `current_buffer_`
+        explicit ScopedIndent(TextGenerator* generator);
+        /// Destructor
+        ~ScopedIndent();
+
+      private:
+        ScopedIndent(ScopedIndent&& rhs) = delete;
+        ScopedIndent(const ScopedIndent&) = delete;
+        ScopedIndent& operator=(const ScopedIndent&) = delete;
+        TextBuffer* buffer_;
+    };
+
+    /// @returns the resolved type of the ast::Expression `expr`
+    /// @param expr the expression
+    const sem::Type* TypeOf(const ast::Expression* expr) const { return builder_.TypeOf(expr); }
+
+    /// @returns the resolved type of the ast::Type `type`
+    /// @param type the type
+    const sem::Type* TypeOf(const ast::Type* type) const { return builder_.TypeOf(type); }
+
+    /// @returns the resolved type of the ast::TypeDecl `type_decl`
+    /// @param type_decl the type
+    const sem::Type* TypeOf(const ast::TypeDecl* type_decl) const {
+        return builder_.TypeOf(type_decl);
     }
 
-   private:
-    LineWriter(const LineWriter&) = delete;
-    LineWriter& operator=(const LineWriter&) = delete;
+    /// @returns a new LineWriter, used for buffering and writing a line to
+    /// the end of #current_buffer_.
+    LineWriter line() { return LineWriter(current_buffer_); }
 
-    std::ostringstream os;
-    TextBuffer* buffer;
-  };
+    /// @param buffer the TextBuffer to write the line to
+    /// @returns a new LineWriter, used for buffering and writing a line to
+    /// the end of `buffer`.
+    static LineWriter line(TextBuffer* buffer) { return LineWriter(buffer); }
 
-  /// Helper for writing a '(' on construction and a ')' destruction.
-  struct ScopedParen {
-    /// Constructor
-    /// @param stream the std::ostream that will be written to
-    explicit ScopedParen(std::ostream& stream);
-    /// Destructor
-    ~ScopedParen();
+    /// The program
+    Program const* const program_;
+    /// A ProgramBuilder that thinly wraps program_
+    ProgramBuilder builder_;
+    /// Diagnostics generated by the generator
+    diag::List diagnostics_;
+    /// The buffer the TextGenerator is currently appending lines to
+    TextBuffer* current_buffer_ = &main_buffer_;
 
-   private:
-    ScopedParen(ScopedParen&& rhs) = delete;
-    ScopedParen(const ScopedParen&) = delete;
-    ScopedParen& operator=(const ScopedParen&) = delete;
-    std::ostream& s;
-  };
-
-  /// Helper for incrementing indentation on construction and decrementing
-  /// indentation on destruction.
-  struct ScopedIndent {
-    /// Constructor
-    /// @param buffer the TextBuffer that the ScopedIndent will indent
-    explicit ScopedIndent(TextBuffer* buffer);
-    /// Constructor
-    /// @param generator ScopedIndent will indent the generator's
-    /// `current_buffer_`
-    explicit ScopedIndent(TextGenerator* generator);
-    /// Destructor
-    ~ScopedIndent();
-
-   private:
-    ScopedIndent(ScopedIndent&& rhs) = delete;
-    ScopedIndent(const ScopedIndent&) = delete;
-    ScopedIndent& operator=(const ScopedIndent&) = delete;
-    TextBuffer* buffer_;
-  };
-
-  /// @returns the resolved type of the ast::Expression `expr`
-  /// @param expr the expression
-  const sem::Type* TypeOf(const ast::Expression* expr) const {
-    return builder_.TypeOf(expr);
-  }
-
-  /// @returns the resolved type of the ast::Type `type`
-  /// @param type the type
-  const sem::Type* TypeOf(const ast::Type* type) const {
-    return builder_.TypeOf(type);
-  }
-
-  /// @returns the resolved type of the ast::TypeDecl `type_decl`
-  /// @param type_decl the type
-  const sem::Type* TypeOf(const ast::TypeDecl* type_decl) const {
-    return builder_.TypeOf(type_decl);
-  }
-
-  /// @returns a new LineWriter, used for buffering and writing a line to
-  /// the end of #current_buffer_.
-  LineWriter line() { return LineWriter(current_buffer_); }
-
-  /// @param buffer the TextBuffer to write the line to
-  /// @returns a new LineWriter, used for buffering and writing a line to
-  /// the end of `buffer`.
-  static LineWriter line(TextBuffer* buffer) { return LineWriter(buffer); }
-
-  /// The program
-  Program const* const program_;
-  /// A ProgramBuilder that thinly wraps program_
-  ProgramBuilder builder_;
-  /// Diagnostics generated by the generator
-  diag::List diagnostics_;
-  /// The buffer the TextGenerator is currently appending lines to
-  TextBuffer* current_buffer_ = &main_buffer_;
-
- private:
-  /// The primary text buffer that the generator will emit
-  TextBuffer main_buffer_;
-  /// Map of builtin structure to unique generated name
-  std::unordered_map<const sem::Struct*, std::string> builtin_struct_names_;
+  private:
+    /// The primary text buffer that the generator will emit
+    TextBuffer main_buffer_;
+    /// Map of builtin structure to unique generated name
+    std::unordered_map<const sem::Struct*, std::string> builtin_struct_names_;
 };
 
 }  // namespace tint::writer
diff --git a/src/tint/writer/text_generator_test.cc b/src/tint/writer/text_generator_test.cc
index fdd74d6..1bfa41f 100644
--- a/src/tint/writer/text_generator_test.cc
+++ b/src/tint/writer/text_generator_test.cc
@@ -20,26 +20,26 @@
 namespace {
 
 TEST(TextGeneratorTest, UniqueIdentifier) {
-  Program program(ProgramBuilder{});
+    Program program(ProgramBuilder{});
 
-  TextGenerator gen(&program);
+    TextGenerator gen(&program);
 
-  ASSERT_EQ(gen.UniqueIdentifier("ident"), "ident");
-  ASSERT_EQ(gen.UniqueIdentifier("ident"), "ident_1");
+    ASSERT_EQ(gen.UniqueIdentifier("ident"), "ident");
+    ASSERT_EQ(gen.UniqueIdentifier("ident"), "ident_1");
 }
 
 TEST(TextGeneratorTest, UniqueIdentifier_ConflictWithExisting) {
-  ProgramBuilder builder;
-  builder.Symbols().Register("ident_1");
-  builder.Symbols().Register("ident_2");
-  Program program(std::move(builder));
+    ProgramBuilder builder;
+    builder.Symbols().Register("ident_1");
+    builder.Symbols().Register("ident_2");
+    Program program(std::move(builder));
 
-  TextGenerator gen(&program);
+    TextGenerator gen(&program);
 
-  ASSERT_EQ(gen.UniqueIdentifier("ident"), "ident");
-  ASSERT_EQ(gen.UniqueIdentifier("ident"), "ident_3");
-  ASSERT_EQ(gen.UniqueIdentifier("ident"), "ident_4");
-  ASSERT_EQ(gen.UniqueIdentifier("ident"), "ident_5");
+    ASSERT_EQ(gen.UniqueIdentifier("ident"), "ident");
+    ASSERT_EQ(gen.UniqueIdentifier("ident"), "ident_3");
+    ASSERT_EQ(gen.UniqueIdentifier("ident"), "ident_4");
+    ASSERT_EQ(gen.UniqueIdentifier("ident"), "ident_5");
 }
 
 }  // namespace
diff --git a/src/tint/writer/wgsl/generator.cc b/src/tint/writer/wgsl/generator.cc
index 4d00725..623f3a6 100644
--- a/src/tint/writer/wgsl/generator.cc
+++ b/src/tint/writer/wgsl/generator.cc
@@ -22,15 +22,15 @@
 Result::Result(const Result&) = default;
 
 Result Generate(const Program* program, const Options&) {
-  Result result;
+    Result result;
 
-  // Generate the WGSL code.
-  auto impl = std::make_unique<GeneratorImpl>(program);
-  result.success = impl->Generate();
-  result.error = impl->error();
-  result.wgsl = impl->result();
+    // Generate the WGSL code.
+    auto impl = std::make_unique<GeneratorImpl>(program);
+    result.success = impl->Generate();
+    result.error = impl->error();
+    result.wgsl = impl->result();
 
-  return result;
+    return result;
 }
 
 }  // namespace tint::writer::wgsl
diff --git a/src/tint/writer/wgsl/generator.h b/src/tint/writer/wgsl/generator.h
index 62fe2e1..5f249c7 100644
--- a/src/tint/writer/wgsl/generator.h
+++ b/src/tint/writer/wgsl/generator.h
@@ -34,23 +34,23 @@
 
 /// The result produced when generating WGSL.
 struct Result {
-  /// Constructor
-  Result();
+    /// Constructor
+    Result();
 
-  /// Destructor
-  ~Result();
+    /// Destructor
+    ~Result();
 
-  /// Copy constructor
-  Result(const Result&);
+    /// Copy constructor
+    Result(const Result&);
 
-  /// True if generation was successful.
-  bool success = false;
+    /// True if generation was successful.
+    bool success = false;
 
-  /// The errors generated during code generation, if any.
-  std::string error;
+    /// The errors generated during code generation, if any.
+    std::string error;
 
-  /// The generated WGSL.
-  std::string wgsl = "";
+    /// The generated WGSL.
+    std::string wgsl = "";
 };
 
 /// Generate WGSL for a program, according to a set of configuration options.
diff --git a/src/tint/writer/wgsl/generator_bench.cc b/src/tint/writer/wgsl/generator_bench.cc
index cb8cb68..a9efacc 100644
--- a/src/tint/writer/wgsl/generator_bench.cc
+++ b/src/tint/writer/wgsl/generator_bench.cc
@@ -20,18 +20,18 @@
 namespace {
 
 void GenerateWGSL(benchmark::State& state, std::string input_name) {
-  auto res = bench::LoadProgram(input_name);
-  if (auto err = std::get_if<bench::Error>(&res)) {
-    state.SkipWithError(err->msg.c_str());
-    return;
-  }
-  auto& program = std::get<bench::ProgramAndFile>(res).program;
-  for (auto _ : state) {
-    auto res = Generate(&program, {});
-    if (!res.error.empty()) {
-      state.SkipWithError(res.error.c_str());
+    auto res = bench::LoadProgram(input_name);
+    if (auto err = std::get_if<bench::Error>(&res)) {
+        state.SkipWithError(err->msg.c_str());
+        return;
     }
-  }
+    auto& program = std::get<bench::ProgramAndFile>(res).program;
+    for (auto _ : state) {
+        auto res = Generate(&program, {});
+        if (!res.error.empty()) {
+            state.SkipWithError(res.error.c_str());
+        }
+    }
 }
 
 TINT_BENCHMARK_WGSL_PROGRAMS(GenerateWGSL);
diff --git a/src/tint/writer/wgsl/generator_impl.cc b/src/tint/writer/wgsl/generator_impl.cc
index d3174c1..588a6e9 100644
--- a/src/tint/writer/wgsl/generator_impl.cc
+++ b/src/tint/writer/wgsl/generator_impl.cc
@@ -37,7 +37,6 @@
 #include "src/tint/ast/multisampled_texture.h"
 #include "src/tint/ast/pointer.h"
 #include "src/tint/ast/sampled_texture.h"
-#include "src/tint/ast/sint_literal_expression.h"
 #include "src/tint/ast/stage_attribute.h"
 #include "src/tint/ast/storage_texture.h"
 #include "src/tint/ast/stride_attribute.h"
@@ -46,7 +45,6 @@
 #include "src/tint/ast/struct_member_size_attribute.h"
 #include "src/tint/ast/type_name.h"
 #include "src/tint/ast/u32.h"
-#include "src/tint/ast/uint_literal_expression.h"
 #include "src/tint/ast/variable_decl_statement.h"
 #include "src/tint/ast/vector.h"
 #include "src/tint/ast/void.h"
@@ -63,1164 +61,1159 @@
 GeneratorImpl::~GeneratorImpl() = default;
 
 bool GeneratorImpl::Generate() {
-  // Generate global declarations in the order they appear in the module.
-  for (auto* decl : program_->AST().GlobalDeclarations()) {
-    if (!Switch(
-            decl,  //
-            [&](const ast::TypeDecl* td) { return EmitTypeDecl(td); },
-            [&](const ast::Function* func) { return EmitFunction(func); },
-            [&](const ast::Variable* var) { return EmitVariable(line(), var); },
-            [&](Default) {
-              TINT_UNREACHABLE(Writer, diagnostics_);
-              return false;
-            })) {
-      return false;
+    // Generate enable directives before any other global declarations.
+    for (auto ext : program_->AST().Extensions()) {
+        if (!EmitEnableDirective(ext)) {
+            return false;
+        }
     }
-    if (decl != program_->AST().GlobalDeclarations().back()) {
-      line();
+    if (!program_->AST().Extensions().empty()) {
+        line();
     }
-  }
+    // Generate global declarations in the order they appear in the module.
+    for (auto* decl : program_->AST().GlobalDeclarations()) {
+        if (decl->Is<ast::Enable>()) {
+            continue;
+        }
+        if (!Switch(
+                decl,  //
+                [&](const ast::TypeDecl* td) { return EmitTypeDecl(td); },
+                [&](const ast::Function* func) { return EmitFunction(func); },
+                [&](const ast::Variable* var) { return EmitVariable(line(), var); },
+                [&](Default) {
+                    TINT_UNREACHABLE(Writer, diagnostics_);
+                    return false;
+                })) {
+            return false;
+        }
+        if (decl != program_->AST().GlobalDeclarations().back()) {
+            line();
+        }
+    }
 
-  return true;
+    return true;
+}
+
+bool GeneratorImpl::EmitEnableDirective(const ast::Enable::ExtensionKind ext) {
+    auto out = line();
+    auto extension = ast::Enable::KindToName(ext);
+    if (extension == "") {
+        return false;
+    }
+    out << "enable " << extension << ";";
+    return true;
 }
 
 bool GeneratorImpl::EmitTypeDecl(const ast::TypeDecl* ty) {
-  return Switch(
-      ty,
-      [&](const ast::Alias* alias) {  //
-        auto out = line();
-        out << "type " << program_->Symbols().NameFor(alias->name) << " = ";
-        if (!EmitType(out, alias->type)) {
-          return false;
+    return Switch(
+        ty,
+        [&](const ast::Alias* alias) {  //
+            auto out = line();
+            out << "type " << program_->Symbols().NameFor(alias->name) << " = ";
+            if (!EmitType(out, alias->type)) {
+                return false;
+            }
+            out << ";";
+            return true;
+        },
+        [&](const ast::Struct* str) {  //
+            return EmitStructType(str);
+        },
+        [&](Default) {  //
+            diagnostics_.add_error(diag::System::Writer,
+                                   "unknown declared type: " + std::string(ty->TypeInfo().name));
+            return false;
+        });
+}
+
+bool GeneratorImpl::EmitExpression(std::ostream& out, const ast::Expression* expr) {
+    return Switch(
+        expr,
+        [&](const ast::IndexAccessorExpression* a) {  //
+            return EmitIndexAccessor(out, a);
+        },
+        [&](const ast::BinaryExpression* b) {  //
+            return EmitBinary(out, b);
+        },
+        [&](const ast::BitcastExpression* b) {  //
+            return EmitBitcast(out, b);
+        },
+        [&](const ast::CallExpression* c) {  //
+            return EmitCall(out, c);
+        },
+        [&](const ast::IdentifierExpression* i) {  //
+            return EmitIdentifier(out, i);
+        },
+        [&](const ast::LiteralExpression* l) {  //
+            return EmitLiteral(out, l);
+        },
+        [&](const ast::MemberAccessorExpression* m) {  //
+            return EmitMemberAccessor(out, m);
+        },
+        [&](const ast::PhonyExpression*) {  //
+            out << "_";
+            return true;
+        },
+        [&](const ast::UnaryOpExpression* u) {  //
+            return EmitUnaryOp(out, u);
+        },
+        [&](Default) {
+            diagnostics_.add_error(diag::System::Writer, "unknown expression type");
+            return false;
+        });
+}
+
+bool GeneratorImpl::EmitIndexAccessor(std::ostream& out, const ast::IndexAccessorExpression* expr) {
+    bool paren_lhs =
+        !expr->object->IsAnyOf<ast::IndexAccessorExpression, ast::CallExpression,
+                               ast::IdentifierExpression, ast::MemberAccessorExpression>();
+    if (paren_lhs) {
+        out << "(";
+    }
+    if (!EmitExpression(out, expr->object)) {
+        return false;
+    }
+    if (paren_lhs) {
+        out << ")";
+    }
+    out << "[";
+
+    if (!EmitExpression(out, expr->index)) {
+        return false;
+    }
+    out << "]";
+
+    return true;
+}
+
+bool GeneratorImpl::EmitMemberAccessor(std::ostream& out,
+                                       const ast::MemberAccessorExpression* expr) {
+    bool paren_lhs =
+        !expr->structure->IsAnyOf<ast::IndexAccessorExpression, ast::CallExpression,
+                                  ast::IdentifierExpression, ast::MemberAccessorExpression>();
+    if (paren_lhs) {
+        out << "(";
+    }
+    if (!EmitExpression(out, expr->structure)) {
+        return false;
+    }
+    if (paren_lhs) {
+        out << ")";
+    }
+
+    out << ".";
+
+    return EmitExpression(out, expr->member);
+}
+
+bool GeneratorImpl::EmitBitcast(std::ostream& out, const ast::BitcastExpression* expr) {
+    out << "bitcast<";
+    if (!EmitType(out, expr->type)) {
+        return false;
+    }
+
+    out << ">(";
+    if (!EmitExpression(out, expr->expr)) {
+        return false;
+    }
+
+    out << ")";
+    return true;
+}
+
+bool GeneratorImpl::EmitCall(std::ostream& out, const ast::CallExpression* expr) {
+    if (expr->target.name) {
+        if (!EmitExpression(out, expr->target.name)) {
+            return false;
         }
-        out << ";";
-        return true;
-      },
-      [&](const ast::Struct* str) {  //
-        return EmitStructType(str);
-      },
-      [&](Default) {  //
-        diagnostics_.add_error(
-            diag::System::Writer,
-            "unknown declared type: " + std::string(ty->TypeInfo().name));
+    } else if (expr->target.type) {
+        if (!EmitType(out, expr->target.type)) {
+            return false;
+        }
+    } else {
+        TINT_ICE(Writer, diagnostics_) << "CallExpression target had neither a name or type";
         return false;
-      });
-}
-
-bool GeneratorImpl::EmitExpression(std::ostream& out,
-                                   const ast::Expression* expr) {
-  return Switch(
-      expr,
-      [&](const ast::IndexAccessorExpression* a) {  //
-        return EmitIndexAccessor(out, a);
-      },
-      [&](const ast::BinaryExpression* b) {  //
-        return EmitBinary(out, b);
-      },
-      [&](const ast::BitcastExpression* b) {  //
-        return EmitBitcast(out, b);
-      },
-      [&](const ast::CallExpression* c) {  //
-        return EmitCall(out, c);
-      },
-      [&](const ast::IdentifierExpression* i) {  //
-        return EmitIdentifier(out, i);
-      },
-      [&](const ast::LiteralExpression* l) {  //
-        return EmitLiteral(out, l);
-      },
-      [&](const ast::MemberAccessorExpression* m) {  //
-        return EmitMemberAccessor(out, m);
-      },
-      [&](const ast::PhonyExpression*) {  //
-        out << "_";
-        return true;
-      },
-      [&](const ast::UnaryOpExpression* u) {  //
-        return EmitUnaryOp(out, u);
-      },
-      [&](Default) {
-        diagnostics_.add_error(diag::System::Writer, "unknown expression type");
-        return false;
-      });
-}
-
-bool GeneratorImpl::EmitIndexAccessor(
-    std::ostream& out,
-    const ast::IndexAccessorExpression* expr) {
-  bool paren_lhs =
-      !expr->object->IsAnyOf<ast::IndexAccessorExpression, ast::CallExpression,
-                             ast::IdentifierExpression,
-                             ast::MemberAccessorExpression>();
-  if (paren_lhs) {
+    }
     out << "(";
-  }
-  if (!EmitExpression(out, expr->object)) {
-    return false;
-  }
-  if (paren_lhs) {
+
+    bool first = true;
+    const auto& args = expr->args;
+    for (auto* arg : args) {
+        if (!first) {
+            out << ", ";
+        }
+        first = false;
+
+        if (!EmitExpression(out, arg)) {
+            return false;
+        }
+    }
+
     out << ")";
-  }
-  out << "[";
 
-  if (!EmitExpression(out, expr->index)) {
-    return false;
-  }
-  out << "]";
-
-  return true;
+    return true;
 }
 
-bool GeneratorImpl::EmitMemberAccessor(
-    std::ostream& out,
-    const ast::MemberAccessorExpression* expr) {
-  bool paren_lhs =
-      !expr->structure->IsAnyOf<ast::IndexAccessorExpression,
-                                ast::CallExpression, ast::IdentifierExpression,
-                                ast::MemberAccessorExpression>();
-  if (paren_lhs) {
-    out << "(";
-  }
-  if (!EmitExpression(out, expr->structure)) {
-    return false;
-  }
-  if (paren_lhs) {
-    out << ")";
-  }
-
-  out << ".";
-
-  return EmitExpression(out, expr->member);
+bool GeneratorImpl::EmitLiteral(std::ostream& out, const ast::LiteralExpression* lit) {
+    return Switch(
+        lit,
+        [&](const ast::BoolLiteralExpression* l) {  //
+            out << (l->value ? "true" : "false");
+            return true;
+        },
+        [&](const ast::FloatLiteralExpression* l) {  //
+            out << FloatToBitPreservingString(l->value);
+            return true;
+        },
+        [&](const ast::IntLiteralExpression* l) {  //
+            out << l->value << l->suffix;
+            return true;
+        },
+        [&](Default) {  //
+            diagnostics_.add_error(diag::System::Writer, "unknown literal type");
+            return false;
+        });
 }
 
-bool GeneratorImpl::EmitBitcast(std::ostream& out,
-                                const ast::BitcastExpression* expr) {
-  out << "bitcast<";
-  if (!EmitType(out, expr->type)) {
-    return false;
-  }
-
-  out << ">(";
-  if (!EmitExpression(out, expr->expr)) {
-    return false;
-  }
-
-  out << ")";
-  return true;
-}
-
-bool GeneratorImpl::EmitCall(std::ostream& out,
-                             const ast::CallExpression* expr) {
-  if (expr->target.name) {
-    if (!EmitExpression(out, expr->target.name)) {
-      return false;
-    }
-  } else if (expr->target.type) {
-    if (!EmitType(out, expr->target.type)) {
-      return false;
-    }
-  } else {
-    TINT_ICE(Writer, diagnostics_)
-        << "CallExpression target had neither a name or type";
-    return false;
-  }
-  out << "(";
-
-  bool first = true;
-  const auto& args = expr->args;
-  for (auto* arg : args) {
-    if (!first) {
-      out << ", ";
-    }
-    first = false;
-
-    if (!EmitExpression(out, arg)) {
-      return false;
-    }
-  }
-
-  out << ")";
-
-  return true;
-}
-
-bool GeneratorImpl::EmitLiteral(std::ostream& out,
-                                const ast::LiteralExpression* lit) {
-  return Switch(
-      lit,
-      [&](const ast::BoolLiteralExpression* bl) {  //
-        out << (bl->value ? "true" : "false");
-        return true;
-      },
-      [&](const ast::FloatLiteralExpression* fl) {  //
-        out << FloatToBitPreservingString(fl->value);
-        return true;
-      },
-      [&](const ast::SintLiteralExpression* sl) {  //
-        out << sl->value;
-        return true;
-      },
-      [&](const ast::UintLiteralExpression* ul) {  //
-        out << ul->value << "u";
-        return true;
-      },
-      [&](Default) {  //
-        diagnostics_.add_error(diag::System::Writer, "unknown literal type");
-        return false;
-      });
-}
-
-bool GeneratorImpl::EmitIdentifier(std::ostream& out,
-                                   const ast::IdentifierExpression* expr) {
-  out << program_->Symbols().NameFor(expr->symbol);
-  return true;
+bool GeneratorImpl::EmitIdentifier(std::ostream& out, const ast::IdentifierExpression* expr) {
+    out << program_->Symbols().NameFor(expr->symbol);
+    return true;
 }
 
 bool GeneratorImpl::EmitFunction(const ast::Function* func) {
-  if (func->attributes.size()) {
-    if (!EmitAttributes(line(), func->attributes)) {
-      return false;
+    if (func->attributes.size()) {
+        if (!EmitAttributes(line(), func->attributes)) {
+            return false;
+        }
     }
-  }
-  {
-    auto out = line();
-    out << "fn " << program_->Symbols().NameFor(func->symbol) << "(";
+    {
+        auto out = line();
+        out << "fn " << program_->Symbols().NameFor(func->symbol) << "(";
 
-    bool first = true;
-    for (auto* v : func->params) {
-      if (!first) {
-        out << ", ";
-      }
-      first = false;
+        bool first = true;
+        for (auto* v : func->params) {
+            if (!first) {
+                out << ", ";
+            }
+            first = false;
 
-      if (!v->attributes.empty()) {
-        if (!EmitAttributes(out, v->attributes)) {
-          return false;
+            if (!v->attributes.empty()) {
+                if (!EmitAttributes(out, v->attributes)) {
+                    return false;
+                }
+                out << " ";
+            }
+
+            out << program_->Symbols().NameFor(v->symbol) << " : ";
+
+            if (!EmitType(out, v->type)) {
+                return false;
+            }
+        }
+
+        out << ")";
+
+        if (!func->return_type->Is<ast::Void>() || !func->return_type_attributes.empty()) {
+            out << " -> ";
+
+            if (!func->return_type_attributes.empty()) {
+                if (!EmitAttributes(out, func->return_type_attributes)) {
+                    return false;
+                }
+                out << " ";
+            }
+
+            if (!EmitType(out, func->return_type)) {
+                return false;
+            }
+        }
+
+        if (func->body) {
+            out << " {";
+        }
+    }
+
+    if (func->body) {
+        if (!EmitStatementsWithIndent(func->body->statements)) {
+            return false;
+        }
+        line() << "}";
+    }
+
+    return true;
+}
+
+bool GeneratorImpl::EmitImageFormat(std::ostream& out, const ast::TexelFormat fmt) {
+    switch (fmt) {
+        case ast::TexelFormat::kNone:
+            diagnostics_.add_error(diag::System::Writer, "unknown image format");
+            return false;
+        default:
+            out << fmt;
+    }
+    return true;
+}
+
+bool GeneratorImpl::EmitAccess(std::ostream& out, const ast::Access access) {
+    switch (access) {
+        case ast::Access::kRead:
+            out << "read";
+            return true;
+        case ast::Access::kWrite:
+            out << "write";
+            return true;
+        case ast::Access::kReadWrite:
+            out << "read_write";
+            return true;
+        default:
+            break;
+    }
+    diagnostics_.add_error(diag::System::Writer, "unknown access");
+    return false;
+}
+
+bool GeneratorImpl::EmitType(std::ostream& out, const ast::Type* ty) {
+    return Switch(
+        ty,
+        [&](const ast::Array* ary) {
+            for (auto* attr : ary->attributes) {
+                if (auto* stride = attr->As<ast::StrideAttribute>()) {
+                    out << "@stride(" << stride->stride << ") ";
+                }
+            }
+
+            out << "array<";
+            if (!EmitType(out, ary->type)) {
+                return false;
+            }
+
+            if (!ary->IsRuntimeArray()) {
+                out << ", ";
+                if (!EmitExpression(out, ary->count)) {
+                    return false;
+                }
+            }
+
+            out << ">";
+            return true;
+        },
+        [&](const ast::Bool*) {
+            out << "bool";
+            return true;
+        },
+        [&](const ast::F32*) {
+            out << "f32";
+            return true;
+        },
+        [&](const ast::I32*) {
+            out << "i32";
+            return true;
+        },
+        [&](const ast::Matrix* mat) {
+            out << "mat" << mat->columns << "x" << mat->rows;
+            if (auto* el_ty = mat->type) {
+                out << "<";
+                if (!EmitType(out, el_ty)) {
+                    return false;
+                }
+                out << ">";
+            }
+            return true;
+        },
+        [&](const ast::Pointer* ptr) {
+            out << "ptr<" << ptr->storage_class << ", ";
+            if (!EmitType(out, ptr->type)) {
+                return false;
+            }
+            if (ptr->access != ast::Access::kUndefined) {
+                out << ", ";
+                if (!EmitAccess(out, ptr->access)) {
+                    return false;
+                }
+            }
+            out << ">";
+            return true;
+        },
+        [&](const ast::Atomic* atomic) {
+            out << "atomic<";
+            if (!EmitType(out, atomic->type)) {
+                return false;
+            }
+            out << ">";
+            return true;
+        },
+        [&](const ast::Sampler* sampler) {
+            out << "sampler";
+
+            if (sampler->IsComparison()) {
+                out << "_comparison";
+            }
+            return true;
+        },
+        [&](const ast::ExternalTexture*) {
+            out << "texture_external";
+            return true;
+        },
+        [&](const ast::Texture* texture) {
+            out << "texture_";
+            bool ok = Switch(
+                texture,
+                [&](const ast::DepthTexture*) {  //
+                    out << "depth_";
+                    return true;
+                },
+                [&](const ast::DepthMultisampledTexture*) {  //
+                    out << "depth_multisampled_";
+                    return true;
+                },
+                [&](const ast::SampledTexture*) {  //
+                    /* nothing to emit */
+                    return true;
+                },
+                [&](const ast::MultisampledTexture*) {  //
+                    out << "multisampled_";
+                    return true;
+                },
+                [&](const ast::StorageTexture*) {  //
+                    out << "storage_";
+                    return true;
+                },
+                [&](Default) {  //
+                    diagnostics_.add_error(diag::System::Writer, "unknown texture type");
+                    return false;
+                });
+            if (!ok) {
+                return false;
+            }
+
+            switch (texture->dim) {
+                case ast::TextureDimension::k1d:
+                    out << "1d";
+                    break;
+                case ast::TextureDimension::k2d:
+                    out << "2d";
+                    break;
+                case ast::TextureDimension::k2dArray:
+                    out << "2d_array";
+                    break;
+                case ast::TextureDimension::k3d:
+                    out << "3d";
+                    break;
+                case ast::TextureDimension::kCube:
+                    out << "cube";
+                    break;
+                case ast::TextureDimension::kCubeArray:
+                    out << "cube_array";
+                    break;
+                default:
+                    diagnostics_.add_error(diag::System::Writer, "unknown texture dimension");
+                    return false;
+            }
+
+            return Switch(
+                texture,
+                [&](const ast::SampledTexture* sampled) {  //
+                    out << "<";
+                    if (!EmitType(out, sampled->type)) {
+                        return false;
+                    }
+                    out << ">";
+                    return true;
+                },
+                [&](const ast::MultisampledTexture* ms) {  //
+                    out << "<";
+                    if (!EmitType(out, ms->type)) {
+                        return false;
+                    }
+                    out << ">";
+                    return true;
+                },
+                [&](const ast::StorageTexture* storage) {  //
+                    out << "<";
+                    if (!EmitImageFormat(out, storage->format)) {
+                        return false;
+                    }
+                    out << ", ";
+                    if (!EmitAccess(out, storage->access)) {
+                        return false;
+                    }
+                    out << ">";
+                    return true;
+                },
+                [&](Default) {  //
+                    return true;
+                });
+        },
+        [&](const ast::U32*) {
+            out << "u32";
+            return true;
+        },
+        [&](const ast::Vector* vec) {
+            out << "vec" << vec->width;
+            if (auto* el_ty = vec->type) {
+                out << "<";
+                if (!EmitType(out, el_ty)) {
+                    return false;
+                }
+                out << ">";
+            }
+            return true;
+        },
+        [&](const ast::Void*) {
+            out << "void";
+            return true;
+        },
+        [&](const ast::TypeName* tn) {
+            out << program_->Symbols().NameFor(tn->name);
+            return true;
+        },
+        [&](Default) {
+            diagnostics_.add_error(diag::System::Writer,
+                                   "unknown type in EmitType: " + std::string(ty->TypeInfo().name));
+            return false;
+        });
+}
+
+bool GeneratorImpl::EmitStructType(const ast::Struct* str) {
+    if (str->attributes.size()) {
+        if (!EmitAttributes(line(), str->attributes)) {
+            return false;
+        }
+    }
+    line() << "struct " << program_->Symbols().NameFor(str->name) << " {";
+
+    auto add_padding = [&](uint32_t size) {
+        line() << "@size(" << size << ")";
+
+        // Note: u32 is the smallest primitive we currently support. When WGSL
+        // supports smaller types, this will need to be updated.
+        line() << UniqueIdentifier("padding") << " : u32,";
+    };
+
+    increment_indent();
+    uint32_t offset = 0;
+    for (auto* mem : str->members) {
+        // TODO(crbug.com/tint/798) move the @offset attribute handling to the
+        // transform::Wgsl sanitizer.
+        if (auto* mem_sem = program_->Sem().Get(mem)) {
+            offset = utils::RoundUp(mem_sem->Align(), offset);
+            if (uint32_t padding = mem_sem->Offset() - offset) {
+                add_padding(padding);
+                offset += padding;
+            }
+            offset += mem_sem->Size();
+        }
+
+        // Offset attributes no longer exist in the WGSL spec, but are emitted
+        // by the SPIR-V reader and are consumed by the Resolver(). These should not
+        // be emitted, but instead struct padding fields should be emitted.
+        ast::AttributeList attributes_sanitized;
+        attributes_sanitized.reserve(mem->attributes.size());
+        for (auto* attr : mem->attributes) {
+            if (!attr->Is<ast::StructMemberOffsetAttribute>()) {
+                attributes_sanitized.emplace_back(attr);
+            }
+        }
+
+        if (!attributes_sanitized.empty()) {
+            if (!EmitAttributes(line(), attributes_sanitized)) {
+                return false;
+            }
+        }
+
+        auto out = line();
+        out << program_->Symbols().NameFor(mem->symbol) << " : ";
+        if (!EmitType(out, mem->type)) {
+            return false;
+        }
+        out << ",";
+    }
+    decrement_indent();
+
+    line() << "}";
+    return true;
+}
+
+bool GeneratorImpl::EmitVariable(std::ostream& out, const ast::Variable* var) {
+    if (!var->attributes.empty()) {
+        if (!EmitAttributes(out, var->attributes)) {
+            return false;
         }
         out << " ";
-      }
+    }
 
-      out << program_->Symbols().NameFor(v->symbol) << " : ";
+    if (var->is_overridable) {
+        out << "override";
+    } else if (var->is_const) {
+        out << "let";
+    } else {
+        out << "var";
+        auto sc = var->declared_storage_class;
+        auto ac = var->declared_access;
+        if (sc != ast::StorageClass::kNone || ac != ast::Access::kUndefined) {
+            out << "<" << sc;
+            if (ac != ast::Access::kUndefined) {
+                out << ", ";
+                if (!EmitAccess(out, ac)) {
+                    return false;
+                }
+            }
+            out << ">";
+        }
+    }
 
-      if (!EmitType(out, v->type)) {
+    out << " " << program_->Symbols().NameFor(var->symbol);
+
+    if (auto* ty = var->type) {
+        out << " : ";
+        if (!EmitType(out, ty)) {
+            return false;
+        }
+    }
+
+    if (var->constructor != nullptr) {
+        out << " = ";
+        if (!EmitExpression(out, var->constructor)) {
+            return false;
+        }
+    }
+    out << ";";
+
+    return true;
+}
+
+bool GeneratorImpl::EmitAttributes(std::ostream& out, const ast::AttributeList& attrs) {
+    bool first = true;
+    for (auto* attr : attrs) {
+        if (!first) {
+            out << " ";
+        }
+        first = false;
+        out << "@";
+        bool ok = Switch(
+            attr,
+            [&](const ast::WorkgroupAttribute* workgroup) {
+                auto values = workgroup->Values();
+                out << "workgroup_size(";
+                for (int i = 0; i < 3; i++) {
+                    if (values[i]) {
+                        if (i > 0) {
+                            out << ", ";
+                        }
+                        if (!EmitExpression(out, values[i])) {
+                            return false;
+                        }
+                    }
+                }
+                out << ")";
+                return true;
+            },
+            [&](const ast::StageAttribute* stage) {
+                out << "stage(" << stage->stage << ")";
+                return true;
+            },
+            [&](const ast::BindingAttribute* binding) {
+                out << "binding(" << binding->value << ")";
+                return true;
+            },
+            [&](const ast::GroupAttribute* group) {
+                out << "group(" << group->value << ")";
+                return true;
+            },
+            [&](const ast::LocationAttribute* location) {
+                out << "location(" << location->value << ")";
+                return true;
+            },
+            [&](const ast::BuiltinAttribute* builtin) {
+                out << "builtin(" << builtin->builtin << ")";
+                return true;
+            },
+            [&](const ast::InterpolateAttribute* interpolate) {
+                out << "interpolate(" << interpolate->type;
+                if (interpolate->sampling != ast::InterpolationSampling::kNone) {
+                    out << ", " << interpolate->sampling;
+                }
+                out << ")";
+                return true;
+            },
+            [&](const ast::InvariantAttribute*) {
+                out << "invariant";
+                return true;
+            },
+            [&](const ast::IdAttribute* override_deco) {
+                out << "id(" << override_deco->value << ")";
+                return true;
+            },
+            [&](const ast::StructMemberSizeAttribute* size) {
+                out << "size(" << size->size << ")";
+                return true;
+            },
+            [&](const ast::StructMemberAlignAttribute* align) {
+                out << "align(" << align->align << ")";
+                return true;
+            },
+            [&](const ast::StrideAttribute* stride) {
+                out << "stride(" << stride->stride << ")";
+                return true;
+            },
+            [&](const ast::InternalAttribute* internal) {
+                out << "internal(" << internal->InternalName() << ")";
+                return true;
+            },
+            [&](Default) {
+                TINT_ICE(Writer, diagnostics_)
+                    << "Unsupported attribute '" << attr->TypeInfo().name << "'";
+                return false;
+            });
+
+        if (!ok) {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+bool GeneratorImpl::EmitBinary(std::ostream& out, const ast::BinaryExpression* expr) {
+    out << "(";
+
+    if (!EmitExpression(out, expr->lhs)) {
         return false;
-      }
+    }
+    out << " ";
+    if (!EmitBinaryOp(out, expr->op)) {
+        return false;
+    }
+    out << " ";
+
+    if (!EmitExpression(out, expr->rhs)) {
+        return false;
+    }
+
+    out << ")";
+    return true;
+}
+
+bool GeneratorImpl::EmitBinaryOp(std::ostream& out, const ast::BinaryOp op) {
+    switch (op) {
+        case ast::BinaryOp::kAnd:
+            out << "&";
+            break;
+        case ast::BinaryOp::kOr:
+            out << "|";
+            break;
+        case ast::BinaryOp::kXor:
+            out << "^";
+            break;
+        case ast::BinaryOp::kLogicalAnd:
+            out << "&&";
+            break;
+        case ast::BinaryOp::kLogicalOr:
+            out << "||";
+            break;
+        case ast::BinaryOp::kEqual:
+            out << "==";
+            break;
+        case ast::BinaryOp::kNotEqual:
+            out << "!=";
+            break;
+        case ast::BinaryOp::kLessThan:
+            out << "<";
+            break;
+        case ast::BinaryOp::kGreaterThan:
+            out << ">";
+            break;
+        case ast::BinaryOp::kLessThanEqual:
+            out << "<=";
+            break;
+        case ast::BinaryOp::kGreaterThanEqual:
+            out << ">=";
+            break;
+        case ast::BinaryOp::kShiftLeft:
+            out << "<<";
+            break;
+        case ast::BinaryOp::kShiftRight:
+            out << ">>";
+            break;
+        case ast::BinaryOp::kAdd:
+            out << "+";
+            break;
+        case ast::BinaryOp::kSubtract:
+            out << "-";
+            break;
+        case ast::BinaryOp::kMultiply:
+            out << "*";
+            break;
+        case ast::BinaryOp::kDivide:
+            out << "/";
+            break;
+        case ast::BinaryOp::kModulo:
+            out << "%";
+            break;
+        case ast::BinaryOp::kNone:
+            diagnostics_.add_error(diag::System::Writer, "missing binary operation type");
+            return false;
+    }
+    return true;
+}
+
+bool GeneratorImpl::EmitUnaryOp(std::ostream& out, const ast::UnaryOpExpression* expr) {
+    switch (expr->op) {
+        case ast::UnaryOp::kAddressOf:
+            out << "&";
+            break;
+        case ast::UnaryOp::kComplement:
+            out << "~";
+            break;
+        case ast::UnaryOp::kIndirection:
+            out << "*";
+            break;
+        case ast::UnaryOp::kNot:
+            out << "!";
+            break;
+        case ast::UnaryOp::kNegation:
+            out << "-";
+            break;
+    }
+    out << "(";
+
+    if (!EmitExpression(out, expr->expr)) {
+        return false;
     }
 
     out << ")";
 
-    if (!func->return_type->Is<ast::Void>() ||
-        !func->return_type_attributes.empty()) {
-      out << " -> ";
-
-      if (!func->return_type_attributes.empty()) {
-        if (!EmitAttributes(out, func->return_type_attributes)) {
-          return false;
-        }
-        out << " ";
-      }
-
-      if (!EmitType(out, func->return_type)) {
-        return false;
-      }
-    }
-
-    if (func->body) {
-      out << " {";
-    }
-  }
-
-  if (func->body) {
-    if (!EmitStatementsWithIndent(func->body->statements)) {
-      return false;
-    }
-    line() << "}";
-  }
-
-  return true;
-}
-
-bool GeneratorImpl::EmitImageFormat(std::ostream& out,
-                                    const ast::TexelFormat fmt) {
-  switch (fmt) {
-    case ast::TexelFormat::kNone:
-      diagnostics_.add_error(diag::System::Writer, "unknown image format");
-      return false;
-    default:
-      out << fmt;
-  }
-  return true;
-}
-
-bool GeneratorImpl::EmitAccess(std::ostream& out, const ast::Access access) {
-  switch (access) {
-    case ast::Access::kRead:
-      out << "read";
-      return true;
-    case ast::Access::kWrite:
-      out << "write";
-      return true;
-    case ast::Access::kReadWrite:
-      out << "read_write";
-      return true;
-    default:
-      break;
-  }
-  diagnostics_.add_error(diag::System::Writer, "unknown access");
-  return false;
-}
-
-bool GeneratorImpl::EmitType(std::ostream& out, const ast::Type* ty) {
-  return Switch(
-      ty,
-      [&](const ast::Array* ary) {
-        for (auto* attr : ary->attributes) {
-          if (auto* stride = attr->As<ast::StrideAttribute>()) {
-            out << "@stride(" << stride->stride << ") ";
-          }
-        }
-
-        out << "array<";
-        if (!EmitType(out, ary->type)) {
-          return false;
-        }
-
-        if (!ary->IsRuntimeArray()) {
-          out << ", ";
-          if (!EmitExpression(out, ary->count)) {
-            return false;
-          }
-        }
-
-        out << ">";
-        return true;
-      },
-      [&](const ast::Bool*) {
-        out << "bool";
-        return true;
-      },
-      [&](const ast::F32*) {
-        out << "f32";
-        return true;
-      },
-      [&](const ast::I32*) {
-        out << "i32";
-        return true;
-      },
-      [&](const ast::Matrix* mat) {
-        out << "mat" << mat->columns << "x" << mat->rows;
-        if (auto* el_ty = mat->type) {
-          out << "<";
-          if (!EmitType(out, el_ty)) {
-            return false;
-          }
-          out << ">";
-        }
-        return true;
-      },
-      [&](const ast::Pointer* ptr) {
-        out << "ptr<" << ptr->storage_class << ", ";
-        if (!EmitType(out, ptr->type)) {
-          return false;
-        }
-        if (ptr->access != ast::Access::kUndefined) {
-          out << ", ";
-          if (!EmitAccess(out, ptr->access)) {
-            return false;
-          }
-        }
-        out << ">";
-        return true;
-      },
-      [&](const ast::Atomic* atomic) {
-        out << "atomic<";
-        if (!EmitType(out, atomic->type)) {
-          return false;
-        }
-        out << ">";
-        return true;
-      },
-      [&](const ast::Sampler* sampler) {
-        out << "sampler";
-
-        if (sampler->IsComparison()) {
-          out << "_comparison";
-        }
-        return true;
-      },
-      [&](const ast::ExternalTexture*) {
-        out << "texture_external";
-        return true;
-      },
-      [&](const ast::Texture* texture) {
-        out << "texture_";
-        bool ok = Switch(
-            texture,
-            [&](const ast::DepthTexture*) {  //
-              out << "depth_";
-              return true;
-            },
-            [&](const ast::DepthMultisampledTexture*) {  //
-              out << "depth_multisampled_";
-              return true;
-            },
-            [&](const ast::SampledTexture*) {  //
-              /* nothing to emit */
-              return true;
-            },
-            [&](const ast::MultisampledTexture*) {  //
-              out << "multisampled_";
-              return true;
-            },
-            [&](const ast::StorageTexture*) {  //
-              out << "storage_";
-              return true;
-            },
-            [&](Default) {  //
-              diagnostics_.add_error(diag::System::Writer,
-                                     "unknown texture type");
-              return false;
-            });
-        if (!ok) {
-          return false;
-        }
-
-        switch (texture->dim) {
-          case ast::TextureDimension::k1d:
-            out << "1d";
-            break;
-          case ast::TextureDimension::k2d:
-            out << "2d";
-            break;
-          case ast::TextureDimension::k2dArray:
-            out << "2d_array";
-            break;
-          case ast::TextureDimension::k3d:
-            out << "3d";
-            break;
-          case ast::TextureDimension::kCube:
-            out << "cube";
-            break;
-          case ast::TextureDimension::kCubeArray:
-            out << "cube_array";
-            break;
-          default:
-            diagnostics_.add_error(diag::System::Writer,
-                                   "unknown texture dimension");
-            return false;
-        }
-
-        return Switch(
-            texture,
-            [&](const ast::SampledTexture* sampled) {  //
-              out << "<";
-              if (!EmitType(out, sampled->type)) {
-                return false;
-              }
-              out << ">";
-              return true;
-            },
-            [&](const ast::MultisampledTexture* ms) {  //
-              out << "<";
-              if (!EmitType(out, ms->type)) {
-                return false;
-              }
-              out << ">";
-              return true;
-            },
-            [&](const ast::StorageTexture* storage) {  //
-              out << "<";
-              if (!EmitImageFormat(out, storage->format)) {
-                return false;
-              }
-              out << ", ";
-              if (!EmitAccess(out, storage->access)) {
-                return false;
-              }
-              out << ">";
-              return true;
-            },
-            [&](Default) {  //
-              return true;
-            });
-      },
-      [&](const ast::U32*) {
-        out << "u32";
-        return true;
-      },
-      [&](const ast::Vector* vec) {
-        out << "vec" << vec->width;
-        if (auto* el_ty = vec->type) {
-          out << "<";
-          if (!EmitType(out, el_ty)) {
-            return false;
-          }
-          out << ">";
-        }
-        return true;
-      },
-      [&](const ast::Void*) {
-        out << "void";
-        return true;
-      },
-      [&](const ast::TypeName* tn) {
-        out << program_->Symbols().NameFor(tn->name);
-        return true;
-      },
-      [&](Default) {
-        diagnostics_.add_error(
-            diag::System::Writer,
-            "unknown type in EmitType: " + std::string(ty->TypeInfo().name));
-        return false;
-      });
-}
-
-bool GeneratorImpl::EmitStructType(const ast::Struct* str) {
-  if (str->attributes.size()) {
-    if (!EmitAttributes(line(), str->attributes)) {
-      return false;
-    }
-  }
-  line() << "struct " << program_->Symbols().NameFor(str->name) << " {";
-
-  auto add_padding = [&](uint32_t size) {
-    line() << "@size(" << size << ")";
-
-    // Note: u32 is the smallest primitive we currently support. When WGSL
-    // supports smaller types, this will need to be updated.
-    line() << UniqueIdentifier("padding") << " : u32,";
-  };
-
-  increment_indent();
-  uint32_t offset = 0;
-  for (auto* mem : str->members) {
-    // TODO(crbug.com/tint/798) move the @offset attribute handling to the
-    // transform::Wgsl sanitizer.
-    if (auto* mem_sem = program_->Sem().Get(mem)) {
-      offset = utils::RoundUp(mem_sem->Align(), offset);
-      if (uint32_t padding = mem_sem->Offset() - offset) {
-        add_padding(padding);
-        offset += padding;
-      }
-      offset += mem_sem->Size();
-    }
-
-    // Offset attributes no longer exist in the WGSL spec, but are emitted
-    // by the SPIR-V reader and are consumed by the Resolver(). These should not
-    // be emitted, but instead struct padding fields should be emitted.
-    ast::AttributeList attributes_sanitized;
-    attributes_sanitized.reserve(mem->attributes.size());
-    for (auto* attr : mem->attributes) {
-      if (!attr->Is<ast::StructMemberOffsetAttribute>()) {
-        attributes_sanitized.emplace_back(attr);
-      }
-    }
-
-    if (!attributes_sanitized.empty()) {
-      if (!EmitAttributes(line(), attributes_sanitized)) {
-        return false;
-      }
-    }
-
-    auto out = line();
-    out << program_->Symbols().NameFor(mem->symbol) << " : ";
-    if (!EmitType(out, mem->type)) {
-      return false;
-    }
-    out << ",";
-  }
-  decrement_indent();
-
-  line() << "}";
-  return true;
-}
-
-bool GeneratorImpl::EmitVariable(std::ostream& out, const ast::Variable* var) {
-  if (!var->attributes.empty()) {
-    if (!EmitAttributes(out, var->attributes)) {
-      return false;
-    }
-    out << " ";
-  }
-
-  if (var->is_overridable) {
-    out << "override";
-  } else if (var->is_const) {
-    out << "let";
-  } else {
-    out << "var";
-    auto sc = var->declared_storage_class;
-    auto ac = var->declared_access;
-    if (sc != ast::StorageClass::kNone || ac != ast::Access::kUndefined) {
-      out << "<" << sc;
-      if (ac != ast::Access::kUndefined) {
-        out << ", ";
-        if (!EmitAccess(out, ac)) {
-          return false;
-        }
-      }
-      out << ">";
-    }
-  }
-
-  out << " " << program_->Symbols().NameFor(var->symbol);
-
-  if (auto* ty = var->type) {
-    out << " : ";
-    if (!EmitType(out, ty)) {
-      return false;
-    }
-  }
-
-  if (var->constructor != nullptr) {
-    out << " = ";
-    if (!EmitExpression(out, var->constructor)) {
-      return false;
-    }
-  }
-  out << ";";
-
-  return true;
-}
-
-bool GeneratorImpl::EmitAttributes(std::ostream& out,
-                                   const ast::AttributeList& attrs) {
-  bool first = true;
-  for (auto* attr : attrs) {
-    if (!first) {
-      out << " ";
-    }
-    first = false;
-    out << "@";
-    bool ok = Switch(
-        attr,
-        [&](const ast::WorkgroupAttribute* workgroup) {
-          auto values = workgroup->Values();
-          out << "workgroup_size(";
-          for (int i = 0; i < 3; i++) {
-            if (values[i]) {
-              if (i > 0) {
-                out << ", ";
-              }
-              if (!EmitExpression(out, values[i])) {
-                return false;
-              }
-            }
-          }
-          out << ")";
-          return true;
-        },
-        [&](const ast::StageAttribute* stage) {
-          out << "stage(" << stage->stage << ")";
-          return true;
-        },
-        [&](const ast::BindingAttribute* binding) {
-          out << "binding(" << binding->value << ")";
-          return true;
-        },
-        [&](const ast::GroupAttribute* group) {
-          out << "group(" << group->value << ")";
-          return true;
-        },
-        [&](const ast::LocationAttribute* location) {
-          out << "location(" << location->value << ")";
-          return true;
-        },
-        [&](const ast::BuiltinAttribute* builtin) {
-          out << "builtin(" << builtin->builtin << ")";
-          return true;
-        },
-        [&](const ast::InterpolateAttribute* interpolate) {
-          out << "interpolate(" << interpolate->type;
-          if (interpolate->sampling != ast::InterpolationSampling::kNone) {
-            out << ", " << interpolate->sampling;
-          }
-          out << ")";
-          return true;
-        },
-        [&](const ast::InvariantAttribute*) {
-          out << "invariant";
-          return true;
-        },
-        [&](const ast::IdAttribute* override_deco) {
-          out << "id(" << override_deco->value << ")";
-          return true;
-        },
-        [&](const ast::StructMemberSizeAttribute* size) {
-          out << "size(" << size->size << ")";
-          return true;
-        },
-        [&](const ast::StructMemberAlignAttribute* align) {
-          out << "align(" << align->align << ")";
-          return true;
-        },
-        [&](const ast::StrideAttribute* stride) {
-          out << "stride(" << stride->stride << ")";
-          return true;
-        },
-        [&](const ast::InternalAttribute* internal) {
-          out << "internal(" << internal->InternalName() << ")";
-          return true;
-        },
-        [&](Default) {
-          TINT_ICE(Writer, diagnostics_)
-              << "Unsupported attribute '" << attr->TypeInfo().name << "'";
-          return false;
-        });
-
-    if (!ok) {
-      return false;
-    }
-  }
-
-  return true;
-}
-
-bool GeneratorImpl::EmitBinary(std::ostream& out,
-                               const ast::BinaryExpression* expr) {
-  out << "(";
-
-  if (!EmitExpression(out, expr->lhs)) {
-    return false;
-  }
-  out << " ";
-  if (!EmitBinaryOp(out, expr->op)) {
-    return false;
-  }
-  out << " ";
-
-  if (!EmitExpression(out, expr->rhs)) {
-    return false;
-  }
-
-  out << ")";
-  return true;
-}
-
-bool GeneratorImpl::EmitBinaryOp(std::ostream& out, const ast::BinaryOp op) {
-  switch (op) {
-    case ast::BinaryOp::kAnd:
-      out << "&";
-      break;
-    case ast::BinaryOp::kOr:
-      out << "|";
-      break;
-    case ast::BinaryOp::kXor:
-      out << "^";
-      break;
-    case ast::BinaryOp::kLogicalAnd:
-      out << "&&";
-      break;
-    case ast::BinaryOp::kLogicalOr:
-      out << "||";
-      break;
-    case ast::BinaryOp::kEqual:
-      out << "==";
-      break;
-    case ast::BinaryOp::kNotEqual:
-      out << "!=";
-      break;
-    case ast::BinaryOp::kLessThan:
-      out << "<";
-      break;
-    case ast::BinaryOp::kGreaterThan:
-      out << ">";
-      break;
-    case ast::BinaryOp::kLessThanEqual:
-      out << "<=";
-      break;
-    case ast::BinaryOp::kGreaterThanEqual:
-      out << ">=";
-      break;
-    case ast::BinaryOp::kShiftLeft:
-      out << "<<";
-      break;
-    case ast::BinaryOp::kShiftRight:
-      out << ">>";
-      break;
-    case ast::BinaryOp::kAdd:
-      out << "+";
-      break;
-    case ast::BinaryOp::kSubtract:
-      out << "-";
-      break;
-    case ast::BinaryOp::kMultiply:
-      out << "*";
-      break;
-    case ast::BinaryOp::kDivide:
-      out << "/";
-      break;
-    case ast::BinaryOp::kModulo:
-      out << "%";
-      break;
-    case ast::BinaryOp::kNone:
-      diagnostics_.add_error(diag::System::Writer,
-                             "missing binary operation type");
-      return false;
-  }
-  return true;
-}
-
-bool GeneratorImpl::EmitUnaryOp(std::ostream& out,
-                                const ast::UnaryOpExpression* expr) {
-  switch (expr->op) {
-    case ast::UnaryOp::kAddressOf:
-      out << "&";
-      break;
-    case ast::UnaryOp::kComplement:
-      out << "~";
-      break;
-    case ast::UnaryOp::kIndirection:
-      out << "*";
-      break;
-    case ast::UnaryOp::kNot:
-      out << "!";
-      break;
-    case ast::UnaryOp::kNegation:
-      out << "-";
-      break;
-  }
-  out << "(";
-
-  if (!EmitExpression(out, expr->expr)) {
-    return false;
-  }
-
-  out << ")";
-
-  return true;
+    return true;
 }
 
 bool GeneratorImpl::EmitBlock(const ast::BlockStatement* stmt) {
-  line() << "{";
-  if (!EmitStatementsWithIndent(stmt->statements)) {
-    return false;
-  }
-  line() << "}";
+    line() << "{";
+    if (!EmitStatementsWithIndent(stmt->statements)) {
+        return false;
+    }
+    line() << "}";
 
-  return true;
+    return true;
 }
 
 bool GeneratorImpl::EmitStatement(const ast::Statement* stmt) {
-  return Switch(
-      stmt,  //
-      [&](const ast::AssignmentStatement* a) { return EmitAssign(a); },
-      [&](const ast::BlockStatement* b) { return EmitBlock(b); },
-      [&](const ast::BreakStatement* b) { return EmitBreak(b); },
-      [&](const ast::CallStatement* c) {
-        auto out = line();
-        if (!EmitCall(out, c->expr)) {
-          return false;
-        }
-        out << ";";
-        return true;
-      },
-      [&](const ast::CompoundAssignmentStatement* c) {
-        return EmitCompoundAssign(c);
-      },
-      [&](const ast::ContinueStatement* c) { return EmitContinue(c); },
-      [&](const ast::DiscardStatement* d) { return EmitDiscard(d); },
-      [&](const ast::FallthroughStatement* f) { return EmitFallthrough(f); },
-      [&](const ast::IfStatement* i) { return EmitIf(i); },
-      [&](const ast::IncrementDecrementStatement* l) {
-        return EmitIncrementDecrement(l);
-      },
-      [&](const ast::LoopStatement* l) { return EmitLoop(l); },
-      [&](const ast::ForLoopStatement* l) { return EmitForLoop(l); },
-      [&](const ast::ReturnStatement* r) { return EmitReturn(r); },
-      [&](const ast::SwitchStatement* s) { return EmitSwitch(s); },
-      [&](const ast::VariableDeclStatement* v) {
-        return EmitVariable(line(), v->variable);
-      },
-      [&](Default) {
-        diagnostics_.add_error(
-            diag::System::Writer,
-            "unknown statement type: " + std::string(stmt->TypeInfo().name));
-        return false;
-      });
+    return Switch(
+        stmt,  //
+        [&](const ast::AssignmentStatement* a) { return EmitAssign(a); },
+        [&](const ast::BlockStatement* b) { return EmitBlock(b); },
+        [&](const ast::BreakStatement* b) { return EmitBreak(b); },
+        [&](const ast::CallStatement* c) {
+            auto out = line();
+            if (!EmitCall(out, c->expr)) {
+                return false;
+            }
+            out << ";";
+            return true;
+        },
+        [&](const ast::CompoundAssignmentStatement* c) { return EmitCompoundAssign(c); },
+        [&](const ast::ContinueStatement* c) { return EmitContinue(c); },
+        [&](const ast::DiscardStatement* d) { return EmitDiscard(d); },
+        [&](const ast::FallthroughStatement* f) { return EmitFallthrough(f); },
+        [&](const ast::IfStatement* i) { return EmitIf(i); },
+        [&](const ast::IncrementDecrementStatement* l) { return EmitIncrementDecrement(l); },
+        [&](const ast::LoopStatement* l) { return EmitLoop(l); },
+        [&](const ast::ForLoopStatement* l) { return EmitForLoop(l); },
+        [&](const ast::ReturnStatement* r) { return EmitReturn(r); },
+        [&](const ast::SwitchStatement* s) { return EmitSwitch(s); },
+        [&](const ast::VariableDeclStatement* v) { return EmitVariable(line(), v->variable); },
+        [&](Default) {
+            diagnostics_.add_error(diag::System::Writer,
+                                   "unknown statement type: " + std::string(stmt->TypeInfo().name));
+            return false;
+        });
 }
 
 bool GeneratorImpl::EmitStatements(const ast::StatementList& stmts) {
-  for (auto* s : stmts) {
-    if (!EmitStatement(s)) {
-      return false;
+    for (auto* s : stmts) {
+        if (!EmitStatement(s)) {
+            return false;
+        }
     }
-  }
-  return true;
+    return true;
 }
 
 bool GeneratorImpl::EmitStatementsWithIndent(const ast::StatementList& stmts) {
-  ScopedIndent si(this);
-  return EmitStatements(stmts);
+    ScopedIndent si(this);
+    return EmitStatements(stmts);
 }
 
 bool GeneratorImpl::EmitAssign(const ast::AssignmentStatement* stmt) {
-  auto out = line();
+    auto out = line();
 
-  if (!EmitExpression(out, stmt->lhs)) {
-    return false;
-  }
+    if (!EmitExpression(out, stmt->lhs)) {
+        return false;
+    }
 
-  out << " = ";
+    out << " = ";
 
-  if (!EmitExpression(out, stmt->rhs)) {
-    return false;
-  }
+    if (!EmitExpression(out, stmt->rhs)) {
+        return false;
+    }
 
-  out << ";";
+    out << ";";
 
-  return true;
+    return true;
 }
 
 bool GeneratorImpl::EmitBreak(const ast::BreakStatement*) {
-  line() << "break;";
-  return true;
+    line() << "break;";
+    return true;
 }
 
 bool GeneratorImpl::EmitCase(const ast::CaseStatement* stmt) {
-  if (stmt->IsDefault()) {
-    line() << "default: {";
-  } else {
-    auto out = line();
-    out << "case ";
+    if (stmt->IsDefault()) {
+        line() << "default: {";
+    } else {
+        auto out = line();
+        out << "case ";
 
-    bool first = true;
-    for (auto* selector : stmt->selectors) {
-      if (!first) {
-        out << ", ";
-      }
+        bool first = true;
+        for (auto* selector : stmt->selectors) {
+            if (!first) {
+                out << ", ";
+            }
 
-      first = false;
-      if (!EmitLiteral(out, selector)) {
-        return false;
-      }
+            first = false;
+            if (!EmitLiteral(out, selector)) {
+                return false;
+            }
+        }
+        out << ": {";
     }
-    out << ": {";
-  }
 
-  if (!EmitStatementsWithIndent(stmt->body->statements)) {
-    return false;
-  }
+    if (!EmitStatementsWithIndent(stmt->body->statements)) {
+        return false;
+    }
 
-  line() << "}";
-  return true;
+    line() << "}";
+    return true;
 }
 
-bool GeneratorImpl::EmitCompoundAssign(
-    const ast::CompoundAssignmentStatement* stmt) {
-  auto out = line();
+bool GeneratorImpl::EmitCompoundAssign(const ast::CompoundAssignmentStatement* stmt) {
+    auto out = line();
 
-  if (!EmitExpression(out, stmt->lhs)) {
-    return false;
-  }
+    if (!EmitExpression(out, stmt->lhs)) {
+        return false;
+    }
 
-  out << " ";
-  if (!EmitBinaryOp(out, stmt->op)) {
-    return false;
-  }
-  out << "= ";
+    out << " ";
+    if (!EmitBinaryOp(out, stmt->op)) {
+        return false;
+    }
+    out << "= ";
 
-  if (!EmitExpression(out, stmt->rhs)) {
-    return false;
-  }
+    if (!EmitExpression(out, stmt->rhs)) {
+        return false;
+    }
 
-  out << ";";
+    out << ";";
 
-  return true;
+    return true;
 }
 
 bool GeneratorImpl::EmitContinue(const ast::ContinueStatement*) {
-  line() << "continue;";
-  return true;
+    line() << "continue;";
+    return true;
 }
 
 bool GeneratorImpl::EmitFallthrough(const ast::FallthroughStatement*) {
-  line() << "fallthrough;";
-  return true;
+    line() << "fallthrough;";
+    return true;
 }
 
 bool GeneratorImpl::EmitIf(const ast::IfStatement* stmt) {
-  {
-    auto out = line();
-    out << "if (";
-    if (!EmitExpression(out, stmt->condition)) {
-      return false;
+    {
+        auto out = line();
+        out << "if (";
+        if (!EmitExpression(out, stmt->condition)) {
+            return false;
+        }
+        out << ") {";
     }
-    out << ") {";
-  }
 
-  if (!EmitStatementsWithIndent(stmt->body->statements)) {
-    return false;
-  }
-
-  for (auto* e : stmt->else_statements) {
-    if (e->condition) {
-      auto out = line();
-      out << "} else if (";
-      if (!EmitExpression(out, e->condition)) {
+    if (!EmitStatementsWithIndent(stmt->body->statements)) {
         return false;
-      }
-      out << ") {";
-    } else {
-      line() << "} else {";
     }
 
-    if (!EmitStatementsWithIndent(e->body->statements)) {
-      return false;
+    const ast::Statement* e = stmt->else_statement;
+    while (e) {
+        if (auto* elseif = e->As<ast::IfStatement>()) {
+            {
+                auto out = line();
+                out << "} else if (";
+                if (!EmitExpression(out, elseif->condition)) {
+                    return false;
+                }
+                out << ") {";
+            }
+            if (!EmitStatementsWithIndent(elseif->body->statements)) {
+                return false;
+            }
+            e = elseif->else_statement;
+        } else {
+            line() << "} else {";
+            if (!EmitStatementsWithIndent(e->As<ast::BlockStatement>()->statements)) {
+                return false;
+            }
+            break;
+        }
     }
-  }
 
-  line() << "}";
+    line() << "}";
 
-  return true;
+    return true;
 }
 
-bool GeneratorImpl::EmitIncrementDecrement(
-    const ast::IncrementDecrementStatement* stmt) {
-  auto out = line();
-  if (!EmitExpression(out, stmt->lhs)) {
-    return false;
-  }
-  out << (stmt->increment ? "++" : "--") << ";";
-  return true;
+bool GeneratorImpl::EmitIncrementDecrement(const ast::IncrementDecrementStatement* stmt) {
+    auto out = line();
+    if (!EmitExpression(out, stmt->lhs)) {
+        return false;
+    }
+    out << (stmt->increment ? "++" : "--") << ";";
+    return true;
 }
 
 bool GeneratorImpl::EmitDiscard(const ast::DiscardStatement*) {
-  line() << "discard;";
-  return true;
+    line() << "discard;";
+    return true;
 }
 
 bool GeneratorImpl::EmitLoop(const ast::LoopStatement* stmt) {
-  line() << "loop {";
-  increment_indent();
+    line() << "loop {";
+    increment_indent();
 
-  if (!EmitStatements(stmt->body->statements)) {
-    return false;
-  }
-
-  if (stmt->continuing && !stmt->continuing->Empty()) {
-    line();
-    line() << "continuing {";
-    if (!EmitStatementsWithIndent(stmt->continuing->statements)) {
-      return false;
+    if (!EmitStatements(stmt->body->statements)) {
+        return false;
     }
+
+    if (stmt->continuing && !stmt->continuing->Empty()) {
+        line();
+        line() << "continuing {";
+        if (!EmitStatementsWithIndent(stmt->continuing->statements)) {
+            return false;
+        }
+        line() << "}";
+    }
+
+    decrement_indent();
     line() << "}";
-  }
 
-  decrement_indent();
-  line() << "}";
-
-  return true;
+    return true;
 }
 
 bool GeneratorImpl::EmitForLoop(const ast::ForLoopStatement* stmt) {
-  TextBuffer init_buf;
-  if (auto* init = stmt->initializer) {
-    TINT_SCOPED_ASSIGNMENT(current_buffer_, &init_buf);
-    if (!EmitStatement(init)) {
-      return false;
-    }
-  }
-
-  TextBuffer cont_buf;
-  if (auto* cont = stmt->continuing) {
-    TINT_SCOPED_ASSIGNMENT(current_buffer_, &cont_buf);
-    if (!EmitStatement(cont)) {
-      return false;
-    }
-  }
-
-  {
-    auto out = line();
-    out << "for";
-    {
-      ScopedParen sp(out);
-      switch (init_buf.lines.size()) {
-        case 0:  // No initializer
-          break;
-        case 1:  // Single line initializer statement
-          out << TrimSuffix(init_buf.lines[0].content, ";");
-          break;
-        default:  // Block initializer statement
-          for (size_t i = 1; i < init_buf.lines.size(); i++) {
-            // Indent all by the first line
-            init_buf.lines[i].indent += current_buffer_->current_indent;
-          }
-          out << TrimSuffix(init_buf.String(), "\n");
-          break;
-      }
-
-      out << "; ";
-
-      if (auto* cond = stmt->condition) {
-        if (!EmitExpression(out, cond)) {
-          return false;
+    TextBuffer init_buf;
+    if (auto* init = stmt->initializer) {
+        TINT_SCOPED_ASSIGNMENT(current_buffer_, &init_buf);
+        if (!EmitStatement(init)) {
+            return false;
         }
-      }
-
-      out << "; ";
-
-      switch (cont_buf.lines.size()) {
-        case 0:  // No continuing
-          break;
-        case 1:  // Single line continuing statement
-          out << TrimSuffix(cont_buf.lines[0].content, ";");
-          break;
-        default:  // Block continuing statement
-          for (size_t i = 1; i < cont_buf.lines.size(); i++) {
-            // Indent all by the first line
-            cont_buf.lines[i].indent += current_buffer_->current_indent;
-          }
-          out << TrimSuffix(cont_buf.String(), "\n");
-          break;
-      }
     }
-    out << " {";
-  }
 
-  if (!EmitStatementsWithIndent(stmt->body->statements)) {
-    return false;
-  }
+    TextBuffer cont_buf;
+    if (auto* cont = stmt->continuing) {
+        TINT_SCOPED_ASSIGNMENT(current_buffer_, &cont_buf);
+        if (!EmitStatement(cont)) {
+            return false;
+        }
+    }
 
-  line() << "}";
+    {
+        auto out = line();
+        out << "for";
+        {
+            ScopedParen sp(out);
+            switch (init_buf.lines.size()) {
+                case 0:  // No initializer
+                    break;
+                case 1:  // Single line initializer statement
+                    out << TrimSuffix(init_buf.lines[0].content, ";");
+                    break;
+                default:  // Block initializer statement
+                    for (size_t i = 1; i < init_buf.lines.size(); i++) {
+                        // Indent all by the first line
+                        init_buf.lines[i].indent += current_buffer_->current_indent;
+                    }
+                    out << TrimSuffix(init_buf.String(), "\n");
+                    break;
+            }
 
-  return true;
+            out << "; ";
+
+            if (auto* cond = stmt->condition) {
+                if (!EmitExpression(out, cond)) {
+                    return false;
+                }
+            }
+
+            out << "; ";
+
+            switch (cont_buf.lines.size()) {
+                case 0:  // No continuing
+                    break;
+                case 1:  // Single line continuing statement
+                    out << TrimSuffix(cont_buf.lines[0].content, ";");
+                    break;
+                default:  // Block continuing statement
+                    for (size_t i = 1; i < cont_buf.lines.size(); i++) {
+                        // Indent all by the first line
+                        cont_buf.lines[i].indent += current_buffer_->current_indent;
+                    }
+                    out << TrimSuffix(cont_buf.String(), "\n");
+                    break;
+            }
+        }
+        out << " {";
+    }
+
+    if (!EmitStatementsWithIndent(stmt->body->statements)) {
+        return false;
+    }
+
+    line() << "}";
+
+    return true;
 }
 
 bool GeneratorImpl::EmitReturn(const ast::ReturnStatement* stmt) {
-  auto out = line();
-  out << "return";
-  if (stmt->value) {
-    out << " ";
-    if (!EmitExpression(out, stmt->value)) {
-      return false;
+    auto out = line();
+    out << "return";
+    if (stmt->value) {
+        out << " ";
+        if (!EmitExpression(out, stmt->value)) {
+            return false;
+        }
     }
-  }
-  out << ";";
-  return true;
+    out << ";";
+    return true;
 }
 
 bool GeneratorImpl::EmitSwitch(const ast::SwitchStatement* stmt) {
-  {
-    auto out = line();
-    out << "switch(";
-    if (!EmitExpression(out, stmt->condition)) {
-      return false;
+    {
+        auto out = line();
+        out << "switch(";
+        if (!EmitExpression(out, stmt->condition)) {
+            return false;
+        }
+        out << ") {";
     }
-    out << ") {";
-  }
 
-  {
-    ScopedIndent si(this);
-    for (auto* s : stmt->body) {
-      if (!EmitCase(s)) {
-        return false;
-      }
+    {
+        ScopedIndent si(this);
+        for (auto* s : stmt->body) {
+            if (!EmitCase(s)) {
+                return false;
+            }
+        }
     }
-  }
 
-  line() << "}";
-  return true;
+    line() << "}";
+    return true;
 }
 
 }  // namespace tint::writer::wgsl
diff --git a/src/tint/writer/wgsl/generator_impl.h b/src/tint/writer/wgsl/generator_impl.h
index bee8d65..8473b4f 100644
--- a/src/tint/writer/wgsl/generator_impl.h
+++ b/src/tint/writer/wgsl/generator_impl.h
@@ -34,7 +34,7 @@
 #include "src/tint/ast/switch_statement.h"
 #include "src/tint/ast/unary_op_expression.h"
 #include "src/tint/program.h"
-#include "src/tint/sem/storage_texture_type.h"
+#include "src/tint/sem/storage_texture.h"
 #include "src/tint/sem/struct.h"
 #include "src/tint/writer/text_generator.h"
 
@@ -42,173 +42,175 @@
 
 /// Implementation class for WGSL generator
 class GeneratorImpl : public TextGenerator {
- public:
-  /// Constructor
-  /// @param program the program
-  explicit GeneratorImpl(const Program* program);
-  ~GeneratorImpl();
+  public:
+    /// Constructor
+    /// @param program the program
+    explicit GeneratorImpl(const Program* program);
+    ~GeneratorImpl();
 
-  /// Generates the result data
-  /// @returns true on successful generation; false otherwise
-  bool Generate();
+    /// Generates the result data
+    /// @returns true on successful generation; false otherwise
+    bool Generate();
 
-  /// Handles generating a declared type
-  /// @param ty the declared type to generate
-  /// @returns true if the declared type was emitted
-  bool EmitTypeDecl(const ast::TypeDecl* ty);
-  /// Handles an index accessor expression
-  /// @param out the output of the expression stream
-  /// @param expr the expression to emit
-  /// @returns true if the index accessor was emitted
-  bool EmitIndexAccessor(std::ostream& out,
-                         const ast::IndexAccessorExpression* expr);
-  /// Handles an assignment statement
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was emitted successfully
-  bool EmitAssign(const ast::AssignmentStatement* stmt);
-  /// Handles generating a binary expression
-  /// @param out the output of the expression stream
-  /// @param expr the binary expression
-  /// @returns true if the expression was emitted, false otherwise
-  bool EmitBinary(std::ostream& out, const ast::BinaryExpression* expr);
-  /// Handles generating a binary operator
-  /// @param out the output of the expression stream
-  /// @param op the binary operator
-  /// @returns true if the operator was emitted, false otherwise
-  bool EmitBinaryOp(std::ostream& out, const ast::BinaryOp op);
-  /// Handles generating a bitcast expression
-  /// @param out the output of the expression stream
-  /// @param expr the bitcast expression
-  /// @returns true if the bitcast was emitted
-  bool EmitBitcast(std::ostream& out, const ast::BitcastExpression* expr);
-  /// Handles a block statement
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was emitted successfully
-  bool EmitBlock(const ast::BlockStatement* stmt);
-  /// Handles a break statement
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was emitted successfully
-  bool EmitBreak(const ast::BreakStatement* stmt);
-  /// Handles generating a call expression
-  /// @param out the output of the expression stream
-  /// @param expr the call expression
-  /// @returns true if the call expression is emitted
-  bool EmitCall(std::ostream& out, const ast::CallExpression* expr);
-  /// Handles a case statement
-  /// @param stmt the statement
-  /// @returns true if the statment was emitted successfully
-  bool EmitCase(const ast::CaseStatement* stmt);
-  /// Handles a compound assignment statement
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was emitted successfully
-  bool EmitCompoundAssign(const ast::CompoundAssignmentStatement* stmt);
-  /// Handles generating a literal expression
-  /// @param out the output of the expression stream
-  /// @param expr the literal expression expression
-  /// @returns true if the literal expression is emitted
-  bool EmitLiteral(std::ostream& out, const ast::LiteralExpression* expr);
-  /// Handles a continue statement
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was emitted successfully
-  bool EmitContinue(const ast::ContinueStatement* stmt);
-  /// Handles generate an Expression
-  /// @param out the output of the expression stream
-  /// @param expr the expression
-  /// @returns true if the expression was emitted
-  bool EmitExpression(std::ostream& out, const ast::Expression* expr);
-  /// Handles generating a fallthrough statement
-  /// @param stmt the fallthrough statement
-  /// @returns true if the statement was successfully emitted
-  bool EmitFallthrough(const ast::FallthroughStatement* stmt);
-  /// Handles generating a function
-  /// @param func the function to generate
-  /// @returns true if the function was emitted
-  bool EmitFunction(const ast::Function* func);
-  /// Handles generating an identifier expression
-  /// @param out the output of the expression stream
-  /// @param expr the identifier expression
-  /// @returns true if the identifier was emitted
-  bool EmitIdentifier(std::ostream& out, const ast::IdentifierExpression* expr);
-  /// Handles an if statement
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was successfully emitted
-  bool EmitIf(const ast::IfStatement* stmt);
-  /// Handles an increment/decrement statement
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was successfully emitted
-  bool EmitIncrementDecrement(const ast::IncrementDecrementStatement* stmt);
-  /// Handles generating a discard statement
-  /// @param stmt the discard statement
-  /// @returns true if the statement was successfully emitted
-  bool EmitDiscard(const ast::DiscardStatement* stmt);
-  /// Handles a loop statement
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was emtited
-  bool EmitLoop(const ast::LoopStatement* stmt);
-  /// Handles a for-loop statement
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was emtited
-  bool EmitForLoop(const ast::ForLoopStatement* stmt);
-  /// Handles a member accessor expression
-  /// @param out the output of the expression stream
-  /// @param expr the member accessor expression
-  /// @returns true if the member accessor was emitted
-  bool EmitMemberAccessor(std::ostream& out,
-                          const ast::MemberAccessorExpression* expr);
-  /// Handles return statements
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was successfully emitted
-  bool EmitReturn(const ast::ReturnStatement* stmt);
-  /// Handles statement
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was emitted
-  bool EmitStatement(const ast::Statement* stmt);
-  /// Handles a statement list
-  /// @param stmts the statements to emit
-  /// @returns true if the statements were emitted
-  bool EmitStatements(const ast::StatementList& stmts);
-  /// Handles a statement list with an increased indentation
-  /// @param stmts the statements to emit
-  /// @returns true if the statements were emitted
-  bool EmitStatementsWithIndent(const ast::StatementList& stmts);
-  /// Handles generating a switch statement
-  /// @param stmt the statement to emit
-  /// @returns true if the statement was emitted
-  bool EmitSwitch(const ast::SwitchStatement* stmt);
-  /// Handles generating type
-  /// @param out the output of the expression stream
-  /// @param type the type to generate
-  /// @returns true if the type is emitted
-  bool EmitType(std::ostream& out, const ast::Type* type);
-  /// Handles generating a struct declaration
-  /// @param str the struct
-  /// @returns true if the struct is emitted
-  bool EmitStructType(const ast::Struct* str);
-  /// Handles emitting an image format
-  /// @param out the output of the expression stream
-  /// @param fmt the format to generate
-  /// @returns true if the format is emitted
-  bool EmitImageFormat(std::ostream& out, const ast::TexelFormat fmt);
-  /// Handles emitting an access control
-  /// @param out the output of the expression stream
-  /// @param access the access to generate
-  /// @returns true if the access is emitted
-  bool EmitAccess(std::ostream& out, const ast::Access access);
-  /// Handles a unary op expression
-  /// @param out the output of the expression stream
-  /// @param expr the expression to emit
-  /// @returns true if the expression was emitted
-  bool EmitUnaryOp(std::ostream& out, const ast::UnaryOpExpression* expr);
-  /// Handles generating a variable
-  /// @param out the output of the expression stream
-  /// @param var the variable to generate
-  /// @returns true if the variable was emitted
-  bool EmitVariable(std::ostream& out, const ast::Variable* var);
-  /// Handles generating a attribute list
-  /// @param out the output of the expression stream
-  /// @param attrs the attribute list
-  /// @returns true if the attributes were emitted
-  bool EmitAttributes(std::ostream& out, const ast::AttributeList& attrs);
+    /// Handles generating a enable directive
+    /// @param ext the extension kind in the enable directive to generate
+    /// @returns true if the enable directive was emitted
+    bool EmitEnableDirective(const ast::Enable::ExtensionKind ext);
+    /// Handles generating a declared type
+    /// @param ty the declared type to generate
+    /// @returns true if the declared type was emitted
+    bool EmitTypeDecl(const ast::TypeDecl* ty);
+    /// Handles an index accessor expression
+    /// @param out the output of the expression stream
+    /// @param expr the expression to emit
+    /// @returns true if the index accessor was emitted
+    bool EmitIndexAccessor(std::ostream& out, const ast::IndexAccessorExpression* expr);
+    /// Handles an assignment statement
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was emitted successfully
+    bool EmitAssign(const ast::AssignmentStatement* stmt);
+    /// Handles generating a binary expression
+    /// @param out the output of the expression stream
+    /// @param expr the binary expression
+    /// @returns true if the expression was emitted, false otherwise
+    bool EmitBinary(std::ostream& out, const ast::BinaryExpression* expr);
+    /// Handles generating a binary operator
+    /// @param out the output of the expression stream
+    /// @param op the binary operator
+    /// @returns true if the operator was emitted, false otherwise
+    bool EmitBinaryOp(std::ostream& out, const ast::BinaryOp op);
+    /// Handles generating a bitcast expression
+    /// @param out the output of the expression stream
+    /// @param expr the bitcast expression
+    /// @returns true if the bitcast was emitted
+    bool EmitBitcast(std::ostream& out, const ast::BitcastExpression* expr);
+    /// Handles a block statement
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was emitted successfully
+    bool EmitBlock(const ast::BlockStatement* stmt);
+    /// Handles a break statement
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was emitted successfully
+    bool EmitBreak(const ast::BreakStatement* stmt);
+    /// Handles generating a call expression
+    /// @param out the output of the expression stream
+    /// @param expr the call expression
+    /// @returns true if the call expression is emitted
+    bool EmitCall(std::ostream& out, const ast::CallExpression* expr);
+    /// Handles a case statement
+    /// @param stmt the statement
+    /// @returns true if the statment was emitted successfully
+    bool EmitCase(const ast::CaseStatement* stmt);
+    /// Handles a compound assignment statement
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was emitted successfully
+    bool EmitCompoundAssign(const ast::CompoundAssignmentStatement* stmt);
+    /// Handles generating a literal expression
+    /// @param out the output of the expression stream
+    /// @param expr the literal expression expression
+    /// @returns true if the literal expression is emitted
+    bool EmitLiteral(std::ostream& out, const ast::LiteralExpression* expr);
+    /// Handles a continue statement
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was emitted successfully
+    bool EmitContinue(const ast::ContinueStatement* stmt);
+    /// Handles generate an Expression
+    /// @param out the output of the expression stream
+    /// @param expr the expression
+    /// @returns true if the expression was emitted
+    bool EmitExpression(std::ostream& out, const ast::Expression* expr);
+    /// Handles generating a fallthrough statement
+    /// @param stmt the fallthrough statement
+    /// @returns true if the statement was successfully emitted
+    bool EmitFallthrough(const ast::FallthroughStatement* stmt);
+    /// Handles generating a function
+    /// @param func the function to generate
+    /// @returns true if the function was emitted
+    bool EmitFunction(const ast::Function* func);
+    /// Handles generating an identifier expression
+    /// @param out the output of the expression stream
+    /// @param expr the identifier expression
+    /// @returns true if the identifier was emitted
+    bool EmitIdentifier(std::ostream& out, const ast::IdentifierExpression* expr);
+    /// Handles an if statement
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was successfully emitted
+    bool EmitIf(const ast::IfStatement* stmt);
+    /// Handles an increment/decrement statement
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was successfully emitted
+    bool EmitIncrementDecrement(const ast::IncrementDecrementStatement* stmt);
+    /// Handles generating a discard statement
+    /// @param stmt the discard statement
+    /// @returns true if the statement was successfully emitted
+    bool EmitDiscard(const ast::DiscardStatement* stmt);
+    /// Handles a loop statement
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was emtited
+    bool EmitLoop(const ast::LoopStatement* stmt);
+    /// Handles a for-loop statement
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was emtited
+    bool EmitForLoop(const ast::ForLoopStatement* stmt);
+    /// Handles a member accessor expression
+    /// @param out the output of the expression stream
+    /// @param expr the member accessor expression
+    /// @returns true if the member accessor was emitted
+    bool EmitMemberAccessor(std::ostream& out, const ast::MemberAccessorExpression* expr);
+    /// Handles return statements
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was successfully emitted
+    bool EmitReturn(const ast::ReturnStatement* stmt);
+    /// Handles statement
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was emitted
+    bool EmitStatement(const ast::Statement* stmt);
+    /// Handles a statement list
+    /// @param stmts the statements to emit
+    /// @returns true if the statements were emitted
+    bool EmitStatements(const ast::StatementList& stmts);
+    /// Handles a statement list with an increased indentation
+    /// @param stmts the statements to emit
+    /// @returns true if the statements were emitted
+    bool EmitStatementsWithIndent(const ast::StatementList& stmts);
+    /// Handles generating a switch statement
+    /// @param stmt the statement to emit
+    /// @returns true if the statement was emitted
+    bool EmitSwitch(const ast::SwitchStatement* stmt);
+    /// Handles generating type
+    /// @param out the output of the expression stream
+    /// @param type the type to generate
+    /// @returns true if the type is emitted
+    bool EmitType(std::ostream& out, const ast::Type* type);
+    /// Handles generating a struct declaration
+    /// @param str the struct
+    /// @returns true if the struct is emitted
+    bool EmitStructType(const ast::Struct* str);
+    /// Handles emitting an image format
+    /// @param out the output of the expression stream
+    /// @param fmt the format to generate
+    /// @returns true if the format is emitted
+    bool EmitImageFormat(std::ostream& out, const ast::TexelFormat fmt);
+    /// Handles emitting an access control
+    /// @param out the output of the expression stream
+    /// @param access the access to generate
+    /// @returns true if the access is emitted
+    bool EmitAccess(std::ostream& out, const ast::Access access);
+    /// Handles a unary op expression
+    /// @param out the output of the expression stream
+    /// @param expr the expression to emit
+    /// @returns true if the expression was emitted
+    bool EmitUnaryOp(std::ostream& out, const ast::UnaryOpExpression* expr);
+    /// Handles generating a variable
+    /// @param out the output of the expression stream
+    /// @param var the variable to generate
+    /// @returns true if the variable was emitted
+    bool EmitVariable(std::ostream& out, const ast::Variable* var);
+    /// Handles generating a attribute list
+    /// @param out the output of the expression stream
+    /// @param attrs the attribute list
+    /// @returns true if the attributes were emitted
+    bool EmitAttributes(std::ostream& out, const ast::AttributeList& attrs);
 };
 
 }  // namespace tint::writer::wgsl
diff --git a/src/tint/writer/wgsl/generator_impl_alias_type_test.cc b/src/tint/writer/wgsl/generator_impl_alias_type_test.cc
index bc6c365..92a6868 100644
--- a/src/tint/writer/wgsl/generator_impl_alias_type_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_alias_type_test.cc
@@ -20,28 +20,28 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, EmitAlias_F32) {
-  auto* alias = Alias("a", ty.f32());
+    auto* alias = Alias("a", ty.f32());
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitTypeDecl(alias)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(type a = f32;
+    ASSERT_TRUE(gen.EmitTypeDecl(alias)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(type a = f32;
 )");
 }
 
 TEST_F(WgslGeneratorImplTest, EmitTypeDecl_Struct) {
-  auto* s = Structure("A", {
-                               Member("a", ty.f32()),
-                               Member("b", ty.i32()),
-                           });
+    auto* s = Structure("A", {
+                                 Member("a", ty.f32()),
+                                 Member("b", ty.i32()),
+                             });
 
-  auto* alias = Alias("B", ty.Of(s));
+    auto* alias = Alias("B", ty.Of(s));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitTypeDecl(s)) << gen.error();
-  ASSERT_TRUE(gen.EmitTypeDecl(alias)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(struct A {
+    ASSERT_TRUE(gen.EmitTypeDecl(s)) << gen.error();
+    ASSERT_TRUE(gen.EmitTypeDecl(alias)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(struct A {
   a : f32,
   b : i32,
 }
@@ -50,17 +50,17 @@
 }
 
 TEST_F(WgslGeneratorImplTest, EmitAlias_ToStruct) {
-  auto* s = Structure("A", {
-                               Member("a", ty.f32()),
-                               Member("b", ty.i32()),
-                           });
+    auto* s = Structure("A", {
+                                 Member("a", ty.f32()),
+                                 Member("b", ty.i32()),
+                             });
 
-  auto* alias = Alias("B", ty.Of(s));
+    auto* alias = Alias("B", ty.Of(s));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitTypeDecl(alias)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(type B = A;
+    ASSERT_TRUE(gen.EmitTypeDecl(alias)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(type B = A;
 )");
 }
 
diff --git a/src/tint/writer/wgsl/generator_impl_array_accessor_test.cc b/src/tint/writer/wgsl/generator_impl_array_accessor_test.cc
index f0fc79f..2b4e8b4 100644
--- a/src/tint/writer/wgsl/generator_impl_array_accessor_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_array_accessor_test.cc
@@ -14,35 +14,37 @@
 
 #include "src/tint/writer/wgsl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::wgsl {
 namespace {
 
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, IndexAccessor) {
-  Global("ary", ty.array<i32, 10>(), ast::StorageClass::kPrivate);
-  auto* expr = IndexAccessor("ary", 5);
-  WrapInFunction(expr);
+    Global("ary", ty.array<i32, 10>(), ast::StorageClass::kPrivate);
+    auto* expr = IndexAccessor("ary", 5_i);
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), "ary[5]");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), "ary[5i]");
 }
 
 TEST_F(WgslGeneratorImplTest, IndexAccessor_OfDref) {
-  Global("ary", ty.array<i32, 10>(), ast::StorageClass::kPrivate);
+    Global("ary", ty.array<i32, 10>(), ast::StorageClass::kPrivate);
 
-  auto* p = Const("p", nullptr, AddressOf("ary"));
-  auto* expr = IndexAccessor(Deref("p"), 5);
-  WrapInFunction(p, expr);
+    auto* p = Let("p", nullptr, AddressOf("ary"));
+    auto* expr = IndexAccessor(Deref("p"), 5_i);
+    WrapInFunction(p, expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), "(*(p))[5]");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), "(*(p))[5i]");
 }
 
 }  // namespace
diff --git a/src/tint/writer/wgsl/generator_impl_assign_test.cc b/src/tint/writer/wgsl/generator_impl_assign_test.cc
index 39680ef..8d5e75e 100644
--- a/src/tint/writer/wgsl/generator_impl_assign_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_assign_test.cc
@@ -20,17 +20,17 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, Emit_Assign) {
-  auto* lhs = Global("lhs", ty.i32(), ast::StorageClass::kPrivate);
-  auto* rhs = Global("rhs", ty.i32(), ast::StorageClass::kPrivate);
-  auto* assign = Assign(lhs, rhs);
-  WrapInFunction(assign);
+    auto* lhs = Global("lhs", ty.i32(), ast::StorageClass::kPrivate);
+    auto* rhs = Global("rhs", ty.i32(), ast::StorageClass::kPrivate);
+    auto* assign = Assign(lhs, rhs);
+    WrapInFunction(assign);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(assign)) << gen.error();
-  EXPECT_EQ(gen.result(), "  lhs = rhs;\n");
+    ASSERT_TRUE(gen.EmitStatement(assign)) << gen.error();
+    EXPECT_EQ(gen.result(), "  lhs = rhs;\n");
 }
 
 }  // namespace
diff --git a/src/tint/writer/wgsl/generator_impl_binary_test.cc b/src/tint/writer/wgsl/generator_impl_binary_test.cc
index 7999d99..acc4180 100644
--- a/src/tint/writer/wgsl/generator_impl_binary_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_binary_test.cc
@@ -18,62 +18,60 @@
 namespace {
 
 struct BinaryData {
-  const char* result;
-  ast::BinaryOp op;
+    const char* result;
+    ast::BinaryOp op;
 };
 inline std::ostream& operator<<(std::ostream& out, BinaryData data) {
-  out << data.op;
-  return out;
+    out << data.op;
+    return out;
 }
 using WgslBinaryTest = TestParamHelper<BinaryData>;
 TEST_P(WgslBinaryTest, Emit) {
-  auto params = GetParam();
+    auto params = GetParam();
 
-  auto op_ty = [&]() -> const ast::Type* {
-    if (params.op == ast::BinaryOp::kLogicalAnd ||
-        params.op == ast::BinaryOp::kLogicalOr) {
-      return ty.bool_();
-    } else {
-      return ty.u32();
-    }
-  };
+    auto op_ty = [&]() -> const ast::Type* {
+        if (params.op == ast::BinaryOp::kLogicalAnd || params.op == ast::BinaryOp::kLogicalOr) {
+            return ty.bool_();
+        } else {
+            return ty.u32();
+        }
+    };
 
-  Global("left", op_ty(), ast::StorageClass::kPrivate);
-  Global("right", op_ty(), ast::StorageClass::kPrivate);
-  auto* left = Expr("left");
-  auto* right = Expr("right");
+    Global("left", op_ty(), ast::StorageClass::kPrivate);
+    Global("right", op_ty(), ast::StorageClass::kPrivate);
+    auto* left = Expr("left");
+    auto* right = Expr("right");
 
-  auto* expr = create<ast::BinaryExpression>(params.op, left, right);
-  WrapInFunction(expr);
+    auto* expr = create<ast::BinaryExpression>(params.op, left, right);
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), params.result);
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), params.result);
 }
 INSTANTIATE_TEST_SUITE_P(
     WgslGeneratorImplTest,
     WgslBinaryTest,
-    testing::Values(
-        BinaryData{"(left & right)", ast::BinaryOp::kAnd},
-        BinaryData{"(left | right)", ast::BinaryOp::kOr},
-        BinaryData{"(left ^ right)", ast::BinaryOp::kXor},
-        BinaryData{"(left && right)", ast::BinaryOp::kLogicalAnd},
-        BinaryData{"(left || right)", ast::BinaryOp::kLogicalOr},
-        BinaryData{"(left == right)", ast::BinaryOp::kEqual},
-        BinaryData{"(left != right)", ast::BinaryOp::kNotEqual},
-        BinaryData{"(left < right)", ast::BinaryOp::kLessThan},
-        BinaryData{"(left > right)", ast::BinaryOp::kGreaterThan},
-        BinaryData{"(left <= right)", ast::BinaryOp::kLessThanEqual},
-        BinaryData{"(left >= right)", ast::BinaryOp::kGreaterThanEqual},
-        BinaryData{"(left << right)", ast::BinaryOp::kShiftLeft},
-        BinaryData{"(left >> right)", ast::BinaryOp::kShiftRight},
-        BinaryData{"(left + right)", ast::BinaryOp::kAdd},
-        BinaryData{"(left - right)", ast::BinaryOp::kSubtract},
-        BinaryData{"(left * right)", ast::BinaryOp::kMultiply},
-        BinaryData{"(left / right)", ast::BinaryOp::kDivide},
-        BinaryData{"(left % right)", ast::BinaryOp::kModulo}));
+    testing::Values(BinaryData{"(left & right)", ast::BinaryOp::kAnd},
+                    BinaryData{"(left | right)", ast::BinaryOp::kOr},
+                    BinaryData{"(left ^ right)", ast::BinaryOp::kXor},
+                    BinaryData{"(left && right)", ast::BinaryOp::kLogicalAnd},
+                    BinaryData{"(left || right)", ast::BinaryOp::kLogicalOr},
+                    BinaryData{"(left == right)", ast::BinaryOp::kEqual},
+                    BinaryData{"(left != right)", ast::BinaryOp::kNotEqual},
+                    BinaryData{"(left < right)", ast::BinaryOp::kLessThan},
+                    BinaryData{"(left > right)", ast::BinaryOp::kGreaterThan},
+                    BinaryData{"(left <= right)", ast::BinaryOp::kLessThanEqual},
+                    BinaryData{"(left >= right)", ast::BinaryOp::kGreaterThanEqual},
+                    BinaryData{"(left << right)", ast::BinaryOp::kShiftLeft},
+                    BinaryData{"(left >> right)", ast::BinaryOp::kShiftRight},
+                    BinaryData{"(left + right)", ast::BinaryOp::kAdd},
+                    BinaryData{"(left - right)", ast::BinaryOp::kSubtract},
+                    BinaryData{"(left * right)", ast::BinaryOp::kMultiply},
+                    BinaryData{"(left / right)", ast::BinaryOp::kDivide},
+                    BinaryData{"(left % right)", ast::BinaryOp::kModulo}));
 
 }  // namespace
 }  // namespace tint::writer::wgsl
diff --git a/src/tint/writer/wgsl/generator_impl_bitcast_test.cc b/src/tint/writer/wgsl/generator_impl_bitcast_test.cc
index 08d3cb3..c71a8d1 100644
--- a/src/tint/writer/wgsl/generator_impl_bitcast_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_bitcast_test.cc
@@ -14,20 +14,22 @@
 
 #include "src/tint/writer/wgsl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::wgsl {
 namespace {
 
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, EmitExpression_Bitcast) {
-  auto* bitcast = create<ast::BitcastExpression>(ty.f32(), Expr(1));
-  WrapInFunction(bitcast);
+    auto* bitcast = create<ast::BitcastExpression>(ty.f32(), Expr(1_i));
+    WrapInFunction(bitcast);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, bitcast)) << gen.error();
-  EXPECT_EQ(out.str(), "bitcast<f32>(1)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, bitcast)) << gen.error();
+    EXPECT_EQ(out.str(), "bitcast<f32>(1i)");
 }
 
 }  // namespace
diff --git a/src/tint/writer/wgsl/generator_impl_block_test.cc b/src/tint/writer/wgsl/generator_impl_block_test.cc
index f3ba848..ae01200 100644
--- a/src/tint/writer/wgsl/generator_impl_block_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_block_test.cc
@@ -20,15 +20,15 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, Emit_Block) {
-  auto* b = Block(create<ast::DiscardStatement>());
-  WrapInFunction(b);
+    auto* b = Block(create<ast::DiscardStatement>());
+    WrapInFunction(b);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(b)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  {
+    ASSERT_TRUE(gen.EmitStatement(b)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  {
     discard;
   }
 )");
diff --git a/src/tint/writer/wgsl/generator_impl_break_test.cc b/src/tint/writer/wgsl/generator_impl_break_test.cc
index a895277..8f7275a 100644
--- a/src/tint/writer/wgsl/generator_impl_break_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_break_test.cc
@@ -20,15 +20,15 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, Emit_Break) {
-  auto* b = create<ast::BreakStatement>();
-  WrapInFunction(Loop(Block(b)));
+    auto* b = create<ast::BreakStatement>();
+    WrapInFunction(Loop(Block(b)));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(b)) << gen.error();
-  EXPECT_EQ(gen.result(), "  break;\n");
+    ASSERT_TRUE(gen.EmitStatement(b)) << gen.error();
+    EXPECT_EQ(gen.result(), "  break;\n");
 }
 
 }  // namespace
diff --git a/src/tint/writer/wgsl/generator_impl_call_test.cc b/src/tint/writer/wgsl/generator_impl_call_test.cc
index 449e117..0736ad8 100644
--- a/src/tint/writer/wgsl/generator_impl_call_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_call_test.cc
@@ -21,57 +21,57 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, EmitExpression_Call_WithoutParams) {
-  Func("my_func", {}, ty.f32(), {Return(1.23f)});
+    Func("my_func", {}, ty.f32(), {Return(1.23f)});
 
-  auto* call = Call("my_func");
-  WrapInFunction(call);
+    auto* call = Call("my_func");
+    WrapInFunction(call);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
-  EXPECT_EQ(out.str(), "my_func()");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
+    EXPECT_EQ(out.str(), "my_func()");
 }
 
 TEST_F(WgslGeneratorImplTest, EmitExpression_Call_WithParams) {
-  Func("my_func",
-       {
-           Param(Sym(), ty.f32()),
-           Param(Sym(), ty.f32()),
-       },
-       ty.f32(), {Return(1.23f)});
-  Global("param1", ty.f32(), ast::StorageClass::kPrivate);
-  Global("param2", ty.f32(), ast::StorageClass::kPrivate);
+    Func("my_func",
+         {
+             Param(Sym(), ty.f32()),
+             Param(Sym(), ty.f32()),
+         },
+         ty.f32(), {Return(1.23f)});
+    Global("param1", ty.f32(), ast::StorageClass::kPrivate);
+    Global("param2", ty.f32(), ast::StorageClass::kPrivate);
 
-  auto* call = Call("my_func", "param1", "param2");
-  WrapInFunction(call);
+    auto* call = Call("my_func", "param1", "param2");
+    WrapInFunction(call);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
-  EXPECT_EQ(out.str(), "my_func(param1, param2)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, call)) << gen.error();
+    EXPECT_EQ(out.str(), "my_func(param1, param2)");
 }
 
 TEST_F(WgslGeneratorImplTest, EmitStatement_Call) {
-  Func("my_func",
-       {
-           Param(Sym(), ty.f32()),
-           Param(Sym(), ty.f32()),
-       },
-       ty.void_(), ast::StatementList{}, ast::AttributeList{});
-  Global("param1", ty.f32(), ast::StorageClass::kPrivate);
-  Global("param2", ty.f32(), ast::StorageClass::kPrivate);
+    Func("my_func",
+         {
+             Param(Sym(), ty.f32()),
+             Param(Sym(), ty.f32()),
+         },
+         ty.void_(), ast::StatementList{}, ast::AttributeList{});
+    Global("param1", ty.f32(), ast::StorageClass::kPrivate);
+    Global("param2", ty.f32(), ast::StorageClass::kPrivate);
 
-  auto* call = Call("my_func", "param1", "param2");
-  auto* stmt = CallStmt(call);
-  WrapInFunction(stmt);
+    auto* call = Call("my_func", "param1", "param2");
+    auto* stmt = CallStmt(call);
+    WrapInFunction(stmt);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
-  ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
-  EXPECT_EQ(gen.result(), "  my_func(param1, param2);\n");
+    gen.increment_indent();
+    ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
+    EXPECT_EQ(gen.result(), "  my_func(param1, param2);\n");
 }
 
 }  // namespace
diff --git a/src/tint/writer/wgsl/generator_impl_case_test.cc b/src/tint/writer/wgsl/generator_impl_case_test.cc
index 66155ba..c12997e 100644
--- a/src/tint/writer/wgsl/generator_impl_case_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_case_test.cc
@@ -14,54 +14,54 @@
 
 #include "src/tint/writer/wgsl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::wgsl {
 namespace {
 
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, Emit_Case) {
-  auto* s = Switch(1, Case(Expr(5), Block(create<ast::BreakStatement>())),
-                   DefaultCase());
-  WrapInFunction(s);
+    auto* s = Switch(1_i, Case(Expr(5_i), Block(create<ast::BreakStatement>())), DefaultCase());
+    WrapInFunction(s);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitCase(s->body[0])) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  case 5: {
+    ASSERT_TRUE(gen.EmitCase(s->body[0])) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  case 5i: {
     break;
   }
 )");
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_Case_MultipleSelectors) {
-  auto* s =
-      Switch(1, Case({Expr(5), Expr(6)}, Block(create<ast::BreakStatement>())),
-             DefaultCase());
-  WrapInFunction(s);
+    auto* s = Switch(1_i, Case({Expr(5_i), Expr(6_i)}, Block(create<ast::BreakStatement>())),
+                     DefaultCase());
+    WrapInFunction(s);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitCase(s->body[0])) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  case 5, 6: {
+    ASSERT_TRUE(gen.EmitCase(s->body[0])) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  case 5i, 6i: {
     break;
   }
 )");
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_Case_Default) {
-  auto* s = Switch(1, DefaultCase(Block(create<ast::BreakStatement>())));
-  WrapInFunction(s);
+    auto* s = Switch(1_i, DefaultCase(Block(create<ast::BreakStatement>())));
+    WrapInFunction(s);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitCase(s->body[0])) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  default: {
+    ASSERT_TRUE(gen.EmitCase(s->body[0])) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  default: {
     break;
   }
 )");
diff --git a/src/tint/writer/wgsl/generator_impl_cast_test.cc b/src/tint/writer/wgsl/generator_impl_cast_test.cc
index 3e71c32..c423943 100644
--- a/src/tint/writer/wgsl/generator_impl_cast_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_cast_test.cc
@@ -14,31 +14,33 @@
 
 #include "src/tint/writer/wgsl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::wgsl {
 namespace {
 
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, EmitExpression_Cast_Scalar) {
-  auto* cast = Construct<f32>(1);
-  WrapInFunction(cast);
+    auto* cast = Construct<f32>(1_i);
+    WrapInFunction(cast);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, cast)) << gen.error();
-  EXPECT_EQ(out.str(), "f32(1)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, cast)) << gen.error();
+    EXPECT_EQ(out.str(), "f32(1i)");
 }
 
 TEST_F(WgslGeneratorImplTest, EmitExpression_Cast_Vector) {
-  auto* cast = vec3<f32>(vec3<i32>(1, 2, 3));
-  WrapInFunction(cast);
+    auto* cast = vec3<f32>(vec3<i32>(1_i, 2_i, 3_i));
+    WrapInFunction(cast);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, cast)) << gen.error();
-  EXPECT_EQ(out.str(), "vec3<f32>(vec3<i32>(1, 2, 3))");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, cast)) << gen.error();
+    EXPECT_EQ(out.str(), "vec3<f32>(vec3<i32>(1i, 2i, 3i))");
 }
 
 }  // namespace
diff --git a/src/tint/writer/wgsl/generator_impl_constructor_test.cc b/src/tint/writer/wgsl/generator_impl_constructor_test.cc
index 7b99e43..3fbf3f1 100644
--- a/src/tint/writer/wgsl/generator_impl_constructor_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_constructor_test.cc
@@ -15,117 +15,116 @@
 #include "gmock/gmock.h"
 #include "src/tint/writer/wgsl/test_helper.h"
 
+using ::testing::HasSubstr;
+
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::wgsl {
 namespace {
 
-using ::testing::HasSubstr;
-
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, EmitConstructor_Bool) {
-  WrapInFunction(Expr(false));
+    WrapInFunction(Expr(false));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("false"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("false"));
 }
 
 TEST_F(WgslGeneratorImplTest, EmitConstructor_Int) {
-  WrapInFunction(Expr(-12345));
+    WrapInFunction(Expr(i32(-12345)));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("-12345"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("-12345"));
 }
 
 TEST_F(WgslGeneratorImplTest, EmitConstructor_UInt) {
-  WrapInFunction(Expr(56779u));
+    WrapInFunction(Expr(56779_u));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("56779u"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("56779u"));
 }
 
 TEST_F(WgslGeneratorImplTest, EmitConstructor_Float) {
-  // Use a number close to 1<<30 but whose decimal representation ends in 0.
-  WrapInFunction(Expr(static_cast<float>((1 << 30) - 4)));
+    // Use a number close to 1<<30 but whose decimal representation ends in 0.
+    WrapInFunction(Expr(f32((1 << 30) - 4)));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("1073741824.0"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("1073741824.0"));
 }
 
 TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Float) {
-  WrapInFunction(Construct<f32>(Expr(-1.2e-5f)));
+    WrapInFunction(Construct<f32>(Expr(-1.2e-5f)));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("f32(-0.000012)"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("f32(-0.000012)"));
 }
 
 TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Bool) {
-  WrapInFunction(Construct<bool>(true));
+    WrapInFunction(Construct<bool>(true));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("bool(true)"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("bool(true)"));
 }
 
 TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Int) {
-  WrapInFunction(Construct<i32>(-12345));
+    WrapInFunction(Construct<i32>(i32(-12345)));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("i32(-12345)"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("i32(-12345i)"));
 }
 
 TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Uint) {
-  WrapInFunction(Construct<u32>(12345u));
+    WrapInFunction(Construct<u32>(12345_u));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("u32(12345u)"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("u32(12345u)"));
 }
 
 TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Vec) {
-  WrapInFunction(vec3<f32>(1.f, 2.f, 3.f));
+    WrapInFunction(vec3<f32>(1.f, 2.f, 3.f));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("vec3<f32>(1.0, 2.0, 3.0)"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("vec3<f32>(1.0, 2.0, 3.0)"));
 }
 
 TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Mat) {
-  WrapInFunction(
-      mat2x3<f32>(vec3<f32>(1.f, 2.f, 3.f), vec3<f32>(3.f, 4.f, 5.f)));
+    WrapInFunction(mat2x3<f32>(vec3<f32>(1.f, 2.f, 3.f), vec3<f32>(3.f, 4.f, 5.f)));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(), HasSubstr("mat2x3<f32>(vec3<f32>(1.0, 2.0, 3.0), "
-                                      "vec3<f32>(3.0, 4.0, 5.0))"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("mat2x3<f32>(vec3<f32>(1.0, 2.0, 3.0), "
+                                        "vec3<f32>(3.0, 4.0, 5.0))"));
 }
 
 TEST_F(WgslGeneratorImplTest, EmitConstructor_Type_Array) {
-  WrapInFunction(
-      Construct(ty.array(ty.vec3<f32>(), 3), vec3<f32>(1.0f, 2.0f, 3.0f),
-                vec3<f32>(4.0f, 5.0f, 6.0f), vec3<f32>(7.0f, 8.0f, 9.0f)));
+    WrapInFunction(Construct(ty.array(ty.vec3<f32>(), 3_u), vec3<f32>(1.0f, 2.0f, 3.0f),
+                             vec3<f32>(4.0f, 5.0f, 6.0f), vec3<f32>(7.0f, 8.0f, 9.0f)));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_THAT(gen.result(),
-              HasSubstr("array<vec3<f32>, 3>(vec3<f32>(1.0, 2.0, 3.0), "
-                        "vec3<f32>(4.0, 5.0, 6.0), vec3<f32>(7.0, 8.0, 9.0))"));
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_THAT(gen.result(), HasSubstr("array<vec3<f32>, 3u>(vec3<f32>(1.0, 2.0, 3.0), "
+                                        "vec3<f32>(4.0, 5.0, 6.0), vec3<f32>(7.0, 8.0, 9.0))"));
 }
 
 }  // namespace
diff --git a/src/tint/writer/wgsl/generator_impl_continue_test.cc b/src/tint/writer/wgsl/generator_impl_continue_test.cc
index 252a842..46f2bbd 100644
--- a/src/tint/writer/wgsl/generator_impl_continue_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_continue_test.cc
@@ -20,17 +20,17 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, Emit_Continue) {
-  auto* c = Continue();
+    auto* c = Continue();
 
-  WrapInFunction(Loop(Block(If(false, Block(Break())),  //
-                            c)));
+    WrapInFunction(Loop(Block(If(false, Block(Break())),  //
+                              c)));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(c)) << gen.error();
-  EXPECT_EQ(gen.result(), "  continue;\n");
+    ASSERT_TRUE(gen.EmitStatement(c)) << gen.error();
+    EXPECT_EQ(gen.result(), "  continue;\n");
 }
 
 }  // namespace
diff --git a/src/tint/writer/wgsl/generator_impl_discard_test.cc b/src/tint/writer/wgsl/generator_impl_discard_test.cc
index 8e508d3..db176e9 100644
--- a/src/tint/writer/wgsl/generator_impl_discard_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_discard_test.cc
@@ -20,15 +20,15 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, Emit_Discard) {
-  auto* stmt = create<ast::DiscardStatement>();
-  WrapInFunction(stmt);
+    auto* stmt = create<ast::DiscardStatement>();
+    WrapInFunction(stmt);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
-  EXPECT_EQ(gen.result(), "  discard;\n");
+    ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
+    EXPECT_EQ(gen.result(), "  discard;\n");
 }
 
 }  // namespace
diff --git a/src/tint/writer/wgsl/generator_impl_enable_test.cc b/src/tint/writer/wgsl/generator_impl_enable_test.cc
new file mode 100644
index 0000000..f9de371
--- /dev/null
+++ b/src/tint/writer/wgsl/generator_impl_enable_test.cc
@@ -0,0 +1,31 @@
+// Copyright 2022 The Tint Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "src/tint/writer/wgsl/test_helper.h"
+
+namespace tint::writer::wgsl {
+namespace {
+
+using WgslGeneratorImplTest = TestHelper;
+
+TEST_F(WgslGeneratorImplTest, Emit_Enable) {
+    GeneratorImpl& gen = Build();
+
+    ASSERT_TRUE(gen.EmitEnableDirective(ast::Enable::ExtensionKind::kInternalExtensionForTesting));
+    EXPECT_EQ(gen.result(), R"(enable InternalExtensionForTesting;
+)");
+}
+
+}  // namespace
+}  // namespace tint::writer::wgsl
diff --git a/src/tint/writer/wgsl/generator_impl_fallthrough_test.cc b/src/tint/writer/wgsl/generator_impl_fallthrough_test.cc
index 5925460..2b12051 100644
--- a/src/tint/writer/wgsl/generator_impl_fallthrough_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_fallthrough_test.cc
@@ -14,23 +14,25 @@
 
 #include "src/tint/writer/wgsl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::wgsl {
 namespace {
 
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, Emit_Fallthrough) {
-  auto* f = create<ast::FallthroughStatement>();
-  WrapInFunction(Switch(1,                        //
-                        Case(Expr(1), Block(f)),  //
-                        DefaultCase()));
+    auto* f = create<ast::FallthroughStatement>();
+    WrapInFunction(Switch(1_i,                        //
+                          Case(Expr(1_i), Block(f)),  //
+                          DefaultCase()));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
-  EXPECT_EQ(gen.result(), "  fallthrough;\n");
+    ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+    EXPECT_EQ(gen.result(), "  fallthrough;\n");
 }
 
 }  // namespace
diff --git a/src/tint/writer/wgsl/generator_impl_function_test.cc b/src/tint/writer/wgsl/generator_impl_function_test.cc
index 5c053ac..79a95d5 100644
--- a/src/tint/writer/wgsl/generator_impl_function_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_function_test.cc
@@ -17,85 +17,83 @@
 #include "src/tint/ast/workgroup_attribute.h"
 #include "src/tint/writer/wgsl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::wgsl {
 namespace {
 
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, Emit_Function) {
-  auto* func = Func("my_func", ast::VariableList{}, ty.void_(),
-                    ast::StatementList{
-                        Return(),
-                    },
-                    ast::AttributeList{});
+    auto* func = Func("my_func", ast::VariableList{}, ty.void_(),
+                      ast::StatementList{
+                          Return(),
+                      },
+                      ast::AttributeList{});
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitFunction(func));
-  EXPECT_EQ(gen.result(), R"(  fn my_func() {
+    ASSERT_TRUE(gen.EmitFunction(func));
+    EXPECT_EQ(gen.result(), R"(  fn my_func() {
     return;
   }
 )");
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_Function_WithParams) {
-  auto* func = Func(
-      "my_func", ast::VariableList{Param("a", ty.f32()), Param("b", ty.i32())},
-      ty.void_(),
-      ast::StatementList{
-          Return(),
-      },
-      ast::AttributeList{});
+    auto* func =
+        Func("my_func", ast::VariableList{Param("a", ty.f32()), Param("b", ty.i32())}, ty.void_(),
+             ast::StatementList{
+                 Return(),
+             },
+             ast::AttributeList{});
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitFunction(func));
-  EXPECT_EQ(gen.result(), R"(  fn my_func(a : f32, b : i32) {
+    ASSERT_TRUE(gen.EmitFunction(func));
+    EXPECT_EQ(gen.result(), R"(  fn my_func(a : f32, b : i32) {
     return;
   }
 )");
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_Function_WithAttribute_WorkgroupSize) {
-  auto* func = Func("my_func", ast::VariableList{}, ty.void_(),
-                    ast::StatementList{Return()},
-                    ast::AttributeList{
-                        Stage(ast::PipelineStage::kCompute),
-                        WorkgroupSize(2, 4, 6),
-                    });
+    auto* func = Func("my_func", ast::VariableList{}, ty.void_(), ast::StatementList{Return()},
+                      ast::AttributeList{
+                          Stage(ast::PipelineStage::kCompute),
+                          WorkgroupSize(2_i, 4_i, 6_i),
+                      });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitFunction(func));
-  EXPECT_EQ(gen.result(), R"(  @stage(compute) @workgroup_size(2, 4, 6)
+    ASSERT_TRUE(gen.EmitFunction(func));
+    EXPECT_EQ(gen.result(), R"(  @stage(compute) @workgroup_size(2i, 4i, 6i)
   fn my_func() {
     return;
   }
 )");
 }
 
-TEST_F(WgslGeneratorImplTest,
-       Emit_Function_WithAttribute_WorkgroupSize_WithIdent) {
-  GlobalConst("height", ty.i32(), Expr(2));
-  auto* func = Func("my_func", ast::VariableList{}, ty.void_(),
-                    ast::StatementList{Return()},
-                    ast::AttributeList{
-                        Stage(ast::PipelineStage::kCompute),
-                        WorkgroupSize(2, "height"),
-                    });
+TEST_F(WgslGeneratorImplTest, Emit_Function_WithAttribute_WorkgroupSize_WithIdent) {
+    GlobalConst("height", ty.i32(), Expr(2_i));
+    auto* func = Func("my_func", ast::VariableList{}, ty.void_(), ast::StatementList{Return()},
+                      ast::AttributeList{
+                          Stage(ast::PipelineStage::kCompute),
+                          WorkgroupSize(2_i, "height"),
+                      });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitFunction(func));
-  EXPECT_EQ(gen.result(), R"(  @stage(compute) @workgroup_size(2, height)
+    ASSERT_TRUE(gen.EmitFunction(func));
+    EXPECT_EQ(gen.result(), R"(  @stage(compute) @workgroup_size(2i, height)
   fn my_func() {
     return;
   }
@@ -103,44 +101,43 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_Function_EntryPoint_Parameters) {
-  auto* vec4 = ty.vec4<f32>();
-  auto* coord = Param("coord", vec4, {Builtin(ast::Builtin::kPosition)});
-  auto* loc1 = Param("loc1", ty.f32(), {Location(1u)});
-  auto* func = Func("frag_main", ast::VariableList{coord, loc1}, ty.void_(),
-                    ast::StatementList{},
-                    ast::AttributeList{
-                        Stage(ast::PipelineStage::kFragment),
-                    });
+    auto* vec4 = ty.vec4<f32>();
+    auto* coord = Param("coord", vec4, {Builtin(ast::Builtin::kPosition)});
+    auto* loc1 = Param("loc1", ty.f32(), {Location(1u)});
+    auto* func = Func("frag_main", ast::VariableList{coord, loc1}, ty.void_(), ast::StatementList{},
+                      ast::AttributeList{
+                          Stage(ast::PipelineStage::kFragment),
+                      });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitFunction(func));
-  EXPECT_EQ(gen.result(), R"(  @stage(fragment)
+    ASSERT_TRUE(gen.EmitFunction(func));
+    EXPECT_EQ(gen.result(), R"(  @stage(fragment)
   fn frag_main(@builtin(position) coord : vec4<f32>, @location(1) loc1 : f32) {
   }
 )");
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_Function_EntryPoint_ReturnValue) {
-  auto* func = Func("frag_main", ast::VariableList{}, ty.f32(),
-                    ast::StatementList{
-                        Return(1.f),
-                    },
-                    ast::AttributeList{
-                        Stage(ast::PipelineStage::kFragment),
-                    },
-                    ast::AttributeList{
-                        Location(1u),
-                    });
+    auto* func = Func("frag_main", ast::VariableList{}, ty.f32(),
+                      ast::StatementList{
+                          Return(1.f),
+                      },
+                      ast::AttributeList{
+                          Stage(ast::PipelineStage::kFragment),
+                      },
+                      ast::AttributeList{
+                          Location(1u),
+                      });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitFunction(func));
-  EXPECT_EQ(gen.result(), R"(  @stage(fragment)
+    ASSERT_TRUE(gen.EmitFunction(func));
+    EXPECT_EQ(gen.result(), R"(  @stage(fragment)
   fn frag_main() -> @location(1) f32 {
     return 1.0;
   }
@@ -148,77 +145,74 @@
 }
 
 // https://crbug.com/tint/297
-TEST_F(WgslGeneratorImplTest,
-       Emit_Function_Multiple_EntryPoint_With_Same_ModuleVar) {
-  // struct Data {
-  //   d : f32;
-  // };
-  // @binding(0) @group(0) var<storage> data : Data;
-  //
-  // @stage(compute) @workgroup_size(1)
-  // fn a() {
-  //   return;
-  // }
-  //
-  // @stage(compute) @workgroup_size(1)
-  // fn b() {
-  //   return;
-  // }
+TEST_F(WgslGeneratorImplTest, Emit_Function_Multiple_EntryPoint_With_Same_ModuleVar) {
+    // struct Data {
+    //   d : f32;
+    // };
+    // @binding(0) @group(0) var<storage> data : Data;
+    //
+    // @stage(compute) @workgroup_size(1)
+    // fn a() {
+    //   return;
+    // }
+    //
+    // @stage(compute) @workgroup_size(1)
+    // fn b() {
+    //   return;
+    // }
 
-  auto* s = Structure("Data", {Member("d", ty.f32())});
+    auto* s = Structure("Data", {Member("d", ty.f32())});
 
-  Global("data", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(0),
-             create<ast::GroupAttribute>(0),
-         });
+    Global("data", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(0),
+               create<ast::GroupAttribute>(0),
+           });
 
-  {
-    auto* var = Var("v", ty.f32(), ast::StorageClass::kNone,
-                    MemberAccessor("data", "d"));
+    {
+        auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, MemberAccessor("data", "d"));
 
-    Func("a", ast::VariableList{}, ty.void_(),
-         ast::StatementList{
-             Decl(var),
-             Return(),
-         },
-         ast::AttributeList{
-             Stage(ast::PipelineStage::kCompute),
-             WorkgroupSize(1),
-         });
-  }
+        Func("a", ast::VariableList{}, ty.void_(),
+             ast::StatementList{
+                 Decl(var),
+                 Return(),
+             },
+             ast::AttributeList{
+                 Stage(ast::PipelineStage::kCompute),
+                 WorkgroupSize(1_i),
+             });
+    }
 
-  {
-    auto* var = Var("v", ty.f32(), ast::StorageClass::kNone,
-                    MemberAccessor("data", "d"));
+    {
+        auto* var = Var("v", ty.f32(), ast::StorageClass::kNone, MemberAccessor("data", "d"));
 
-    Func("b", ast::VariableList{}, ty.void_(),
-         ast::StatementList{
-             Decl(var),
-             Return(),
-         },
-         ast::AttributeList{
-             Stage(ast::PipelineStage::kCompute),
-             WorkgroupSize(1),
-         });
-  }
+        Func("b", ast::VariableList{}, ty.void_(),
+             ast::StatementList{
+                 Decl(var),
+                 Return(),
+             },
+             ast::AttributeList{
+                 Stage(ast::PipelineStage::kCompute),
+                 WorkgroupSize(1_i),
+             });
+    }
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(struct Data {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(struct Data {
   d : f32,
 }
 
 @binding(0) @group(0) var<storage, read_write> data : Data;
 
-@stage(compute) @workgroup_size(1)
+@stage(compute) @workgroup_size(1i)
 fn a() {
   var v : f32 = data.d;
   return;
 }
 
-@stage(compute) @workgroup_size(1)
+@stage(compute) @workgroup_size(1i)
 fn b() {
   var v : f32 = data.d;
   return;
diff --git a/src/tint/writer/wgsl/generator_impl_global_decl_test.cc b/src/tint/writer/wgsl/generator_impl_global_decl_test.cc
index 251c577..8e1c9a6 100644
--- a/src/tint/writer/wgsl/generator_impl_global_decl_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_global_decl_test.cc
@@ -14,26 +14,28 @@
 
 #include "src/tint/ast/stage_attribute.h"
 #include "src/tint/ast/variable_decl_statement.h"
-#include "src/tint/sem/sampled_texture_type.h"
+#include "src/tint/sem/sampled_texture.h"
 #include "src/tint/writer/wgsl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::wgsl {
 namespace {
 
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, Emit_GlobalDeclAfterFunction) {
-  auto* func_var = Var("a", ty.f32());
-  WrapInFunction(func_var);
+    auto* func_var = Var("a", ty.f32());
+    WrapInFunction(func_var);
 
-  Global("a", ty.f32(), ast::StorageClass::kPrivate);
+    Global("a", ty.f32(), ast::StorageClass::kPrivate);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  @stage(compute) @workgroup_size(1, 1, 1)
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  @stage(compute) @workgroup_size(1i, 1i, 1i)
   fn test_function() {
     var a : f32;
   }
@@ -43,37 +45,37 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_GlobalsInterleaved) {
-  Global("a0", ty.f32(), ast::StorageClass::kPrivate);
+    Global("a0", ty.f32(), ast::StorageClass::kPrivate);
 
-  auto* s0 = Structure("S0", {Member("a", ty.i32())});
+    auto* s0 = Structure("S0", {Member("a", ty.i32())});
 
-  Func("func", ast::VariableList{}, ty.f32(),
-       ast::StatementList{
-           Return("a0"),
-       },
-       ast::AttributeList{});
+    Func("func", ast::VariableList{}, ty.f32(),
+         ast::StatementList{
+             Return("a0"),
+         },
+         ast::AttributeList{});
 
-  Global("a1", ty.f32(), ast::StorageClass::kPrivate);
+    Global("a1", ty.f32(), ast::StorageClass::kPrivate);
 
-  auto* s1 = Structure("S1", {Member("a", ty.i32())});
+    auto* s1 = Structure("S1", {Member("a", ty.i32())});
 
-  Func("main", ast::VariableList{}, ty.void_(),
-       ast::StatementList{
-           Decl(Var("s0", ty.Of(s0))),
-           Decl(Var("s1", ty.Of(s1))),
-           Assign("a1", Call("func")),
-       },
-       ast::AttributeList{
-           Stage(ast::PipelineStage::kCompute),
-           WorkgroupSize(1),
-       });
+    Func("main", ast::VariableList{}, ty.void_(),
+         ast::StatementList{
+             Decl(Var("s0", ty.Of(s0))),
+             Decl(Var("s1", ty.Of(s1))),
+             Assign("a1", Call("func")),
+         },
+         ast::AttributeList{
+             Stage(ast::PipelineStage::kCompute),
+             WorkgroupSize(1_i),
+         });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  var<private> a0 : f32;
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  var<private> a0 : f32;
 
   struct S0 {
     a : i32,
@@ -89,7 +91,7 @@
     a : i32,
   }
 
-  @stage(compute) @workgroup_size(1)
+  @stage(compute) @workgroup_size(1i)
   fn main() {
     var s0 : S0;
     var s1 : S1;
@@ -99,46 +101,46 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_Global_Sampler) {
-  Global("s", ty.sampler(ast::SamplerKind::kSampler),
-         ast::AttributeList{
-             create<ast::GroupAttribute>(0),
-             create<ast::BindingAttribute>(0),
-         });
+    Global("s", ty.sampler(ast::SamplerKind::kSampler),
+           ast::AttributeList{
+               create<ast::GroupAttribute>(0),
+               create<ast::BindingAttribute>(0),
+           });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), "  @group(0) @binding(0) var s : sampler;\n");
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), "  @group(0) @binding(0) var s : sampler;\n");
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_Global_Texture) {
-  auto* st = ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
-  Global("t", st,
-         ast::AttributeList{
-             create<ast::GroupAttribute>(0),
-             create<ast::BindingAttribute>(0),
-         });
+    auto* st = ty.sampled_texture(ast::TextureDimension::k1d, ty.f32());
+    Global("t", st,
+           ast::AttributeList{
+               create<ast::GroupAttribute>(0),
+               create<ast::BindingAttribute>(0),
+           });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), "  @group(0) @binding(0) var t : texture_1d<f32>;\n");
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), "  @group(0) @binding(0) var t : texture_1d<f32>;\n");
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_OverridableConstants) {
-  Override("a", ty.f32(), nullptr);
-  Override("b", ty.f32(), nullptr, {Id(7u)});
+    Override("a", ty.f32(), nullptr);
+    Override("b", ty.f32(), nullptr, {Id(7u)});
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  override a : f32;
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  override a : f32;
 
   @id(7) override b : f32;
 )");
diff --git a/src/tint/writer/wgsl/generator_impl_identifier_test.cc b/src/tint/writer/wgsl/generator_impl_identifier_test.cc
index c1cd64d..c6bccf6 100644
--- a/src/tint/writer/wgsl/generator_impl_identifier_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_identifier_test.cc
@@ -20,15 +20,15 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, EmitIdentifierExpression_Single) {
-  Global("glsl", ty.f32(), ast::StorageClass::kPrivate);
-  auto* i = Expr("glsl");
-  WrapInFunction(i);
+    Global("glsl", ty.f32(), ast::StorageClass::kPrivate);
+    auto* i = Expr("glsl");
+    WrapInFunction(i);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, i)) << gen.error();
-  EXPECT_EQ(out.str(), "glsl");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, i)) << gen.error();
+    EXPECT_EQ(out.str(), "glsl");
 }
 
 }  // namespace
diff --git a/src/tint/writer/wgsl/generator_impl_if_test.cc b/src/tint/writer/wgsl/generator_impl_if_test.cc
index 4818019..18c0ffd 100644
--- a/src/tint/writer/wgsl/generator_impl_if_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_if_test.cc
@@ -20,44 +20,42 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, Emit_If) {
-  Global("cond", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("cond", ty.bool_(), ast::StorageClass::kPrivate);
 
-  auto* cond = Expr("cond");
-  auto* body = Block(Return());
-  auto* i = If(cond, body);
-  WrapInFunction(i);
+    auto* cond = Expr("cond");
+    auto* body = Block(Return());
+    auto* i = If(cond, body);
+    WrapInFunction(i);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(i)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  if (cond) {
+    ASSERT_TRUE(gen.EmitStatement(i)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  if (cond) {
     return;
   }
 )");
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_IfWithElseIf) {
-  Global("cond", ty.bool_(), ast::StorageClass::kPrivate);
-  Global("else_cond", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("cond", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("else_cond", ty.bool_(), ast::StorageClass::kPrivate);
 
-  auto* else_cond = Expr("else_cond");
-  auto* else_body = Block(Return());
+    auto* else_cond = Expr("else_cond");
+    auto* else_body = Block(Return());
 
-  auto* cond = Expr("cond");
-  auto* body = Block(Return());
-  auto* i = If(
-      cond, body,
-      ast::ElseStatementList{create<ast::ElseStatement>(else_cond, else_body)});
-  WrapInFunction(i);
+    auto* cond = Expr("cond");
+    auto* body = Block(Return());
+    auto* i = If(cond, body, Else(If(else_cond, else_body)));
+    WrapInFunction(i);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(i)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  if (cond) {
+    ASSERT_TRUE(gen.EmitStatement(i)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  if (cond) {
     return;
   } else if (else_cond) {
     return;
@@ -66,23 +64,21 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_IfWithElse) {
-  Global("cond", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("cond", ty.bool_(), ast::StorageClass::kPrivate);
 
-  auto* else_body = Block(Return());
+    auto* else_body = Block(Return());
 
-  auto* cond = Expr("cond");
-  auto* body = Block(Return());
-  auto* i = If(
-      cond, body,
-      ast::ElseStatementList{create<ast::ElseStatement>(nullptr, else_body)});
-  WrapInFunction(i);
+    auto* cond = Expr("cond");
+    auto* body = Block(Return());
+    auto* i = If(cond, body, Else(else_body));
+    WrapInFunction(i);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(i)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  if (cond) {
+    ASSERT_TRUE(gen.EmitStatement(i)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  if (cond) {
     return;
   } else {
     return;
@@ -91,30 +87,26 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_IfWithMultiple) {
-  Global("cond", ty.bool_(), ast::StorageClass::kPrivate);
-  Global("else_cond", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("cond", ty.bool_(), ast::StorageClass::kPrivate);
+    Global("else_cond", ty.bool_(), ast::StorageClass::kPrivate);
 
-  auto* else_cond = Expr("else_cond");
+    auto* else_cond = Expr("else_cond");
 
-  auto* else_body = Block(Return());
+    auto* else_body = Block(Return());
 
-  auto* else_body_2 = Block(Return());
+    auto* else_body_2 = Block(Return());
 
-  auto* cond = Expr("cond");
-  auto* body = Block(Return());
-  auto* i = If(cond, body,
-               ast::ElseStatementList{
-                   create<ast::ElseStatement>(else_cond, else_body),
-                   create<ast::ElseStatement>(nullptr, else_body_2),
-               });
-  WrapInFunction(i);
+    auto* cond = Expr("cond");
+    auto* body = Block(Return());
+    auto* i = If(cond, body, Else(If(else_cond, else_body, Else(else_body_2))));
+    WrapInFunction(i);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(i)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  if (cond) {
+    ASSERT_TRUE(gen.EmitStatement(i)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  if (cond) {
     return;
   } else if (else_cond) {
     return;
diff --git a/src/tint/writer/wgsl/generator_impl_literal_test.cc b/src/tint/writer/wgsl/generator_impl_literal_test.cc
index dd3ace8..64d97a4 100644
--- a/src/tint/writer/wgsl/generator_impl_literal_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_literal_test.cc
@@ -24,71 +24,68 @@
 // - 'exponent_bits' is placed in the exponent space.
 //   So, the exponent bias must already be included.
 float MakeFloat(int sign, int biased_exponent, int mantissa) {
-  const uint32_t sign_bit = sign ? 0x80000000u : 0u;
-  // The binary32 exponent is 8 bits, just below the sign.
-  const uint32_t exponent_bits = (biased_exponent & 0xffu) << 23;
-  // The mantissa is the bottom 23 bits.
-  const uint32_t mantissa_bits = (mantissa & 0x7fffffu);
+    const uint32_t sign_bit = sign ? 0x80000000u : 0u;
+    // The binary32 exponent is 8 bits, just below the sign.
+    const uint32_t exponent_bits = (biased_exponent & 0xffu) << 23;
+    // The mantissa is the bottom 23 bits.
+    const uint32_t mantissa_bits = (mantissa & 0x7fffffu);
 
-  uint32_t bits = sign_bit | exponent_bits | mantissa_bits;
-  float result = 0.0f;
-  static_assert(sizeof(result) == sizeof(bits),
-                "expected float and uint32_t to be the same size");
-  std::memcpy(&result, &bits, sizeof(bits));
-  return result;
+    uint32_t bits = sign_bit | exponent_bits | mantissa_bits;
+    float result = 0.0f;
+    static_assert(sizeof(result) == sizeof(bits),
+                  "expected float and uint32_t to be the same size");
+    std::memcpy(&result, &bits, sizeof(bits));
+    return result;
 }
 
 struct FloatData {
-  float value;
-  std::string expected;
+    float value;
+    std::string expected;
 };
 inline std::ostream& operator<<(std::ostream& out, FloatData data) {
-  out << "{" << data.value << "," << data.expected << "}";
-  return out;
+    out << "{" << data.value << "," << data.expected << "}";
+    return out;
 }
 
 using WgslGenerator_FloatLiteralTest = TestParamHelper<FloatData>;
 
 TEST_P(WgslGenerator_FloatLiteralTest, Emit) {
-  auto* v = Expr(GetParam().value);
+    auto* v = Expr(GetParam().value);
 
-  SetResolveOnBuild(false);
-  GeneratorImpl& gen = Build();
+    SetResolveOnBuild(false);
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitLiteral(out, v)) << gen.error();
-  EXPECT_EQ(out.str(), GetParam().expected);
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitLiteral(out, v)) << gen.error();
+    EXPECT_EQ(out.str(), GetParam().expected);
 }
 
 INSTANTIATE_TEST_SUITE_P(Zero,
                          WgslGenerator_FloatLiteralTest,
-                         ::testing::ValuesIn(std::vector<FloatData>{
-                             {0.0f, "0.0"},
-                             {MakeFloat(0, 0, 0), "0.0"},
-                             {MakeFloat(1, 0, 0), "-0.0"}}));
+                         ::testing::ValuesIn(std::vector<FloatData>{{0.0f, "0.0"},
+                                                                    {MakeFloat(0, 0, 0), "0.0"},
+                                                                    {MakeFloat(1, 0, 0), "-0.0"}}));
 
 INSTANTIATE_TEST_SUITE_P(Normal,
                          WgslGenerator_FloatLiteralTest,
-                         ::testing::ValuesIn(std::vector<FloatData>{
-                             {1.0f, "1.0"},
-                             {-1.0f, "-1.0"},
-                             {101.375, "101.375"}}));
+                         ::testing::ValuesIn(std::vector<FloatData>{{1.0f, "1.0"},
+                                                                    {-1.0f, "-1.0"},
+                                                                    {101.375, "101.375"}}));
 
-INSTANTIATE_TEST_SUITE_P(
-    Subnormal,
-    WgslGenerator_FloatLiteralTest,
-    ::testing::ValuesIn(std::vector<FloatData>{
-        {MakeFloat(0, 0, 1), "0x1p-149"},  // Smallest
-        {MakeFloat(1, 0, 1), "-0x1p-149"},
-        {MakeFloat(0, 0, 2), "0x1p-148"},
-        {MakeFloat(1, 0, 2), "-0x1p-148"},
-        {MakeFloat(0, 0, 0x7fffff), "0x1.fffffcp-127"},   // Largest
-        {MakeFloat(1, 0, 0x7fffff), "-0x1.fffffcp-127"},  // Largest
-        {MakeFloat(0, 0, 0xcafebe), "0x1.2bfaf8p-127"},   // Scattered bits
-        {MakeFloat(1, 0, 0xcafebe), "-0x1.2bfaf8p-127"},  // Scattered bits
-        {MakeFloat(0, 0, 0xaaaaa), "0x1.55554p-130"},     // Scattered bits
-        {MakeFloat(1, 0, 0xaaaaa), "-0x1.55554p-130"},    // Scattered bits
-    }));
+INSTANTIATE_TEST_SUITE_P(Subnormal,
+                         WgslGenerator_FloatLiteralTest,
+                         ::testing::ValuesIn(std::vector<FloatData>{
+                             {MakeFloat(0, 0, 1), "0x1p-149"},  // Smallest
+                             {MakeFloat(1, 0, 1), "-0x1p-149"},
+                             {MakeFloat(0, 0, 2), "0x1p-148"},
+                             {MakeFloat(1, 0, 2), "-0x1p-148"},
+                             {MakeFloat(0, 0, 0x7fffff), "0x1.fffffcp-127"},   // Largest
+                             {MakeFloat(1, 0, 0x7fffff), "-0x1.fffffcp-127"},  // Largest
+                             {MakeFloat(0, 0, 0xcafebe), "0x1.2bfaf8p-127"},   // Scattered bits
+                             {MakeFloat(1, 0, 0xcafebe), "-0x1.2bfaf8p-127"},  // Scattered bits
+                             {MakeFloat(0, 0, 0xaaaaa), "0x1.55554p-130"},     // Scattered bits
+                             {MakeFloat(1, 0, 0xaaaaa), "-0x1.55554p-130"},    // Scattered bits
+                         }));
 
 INSTANTIATE_TEST_SUITE_P(Infinity,
                          WgslGenerator_FloatLiteralTest,
diff --git a/src/tint/writer/wgsl/generator_impl_loop_test.cc b/src/tint/writer/wgsl/generator_impl_loop_test.cc
index 71b331a..2d6a8f4 100644
--- a/src/tint/writer/wgsl/generator_impl_loop_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_loop_test.cc
@@ -14,44 +14,46 @@
 
 #include "src/tint/writer/wgsl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::wgsl {
 namespace {
 
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, Emit_Loop) {
-  auto* body = Block(create<ast::DiscardStatement>());
-  auto* continuing = Block();
-  auto* l = Loop(body, continuing);
+    auto* body = Block(create<ast::DiscardStatement>());
+    auto* continuing = Block();
+    auto* l = Loop(body, continuing);
 
-  WrapInFunction(l);
+    WrapInFunction(l);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(l)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  loop {
+    ASSERT_TRUE(gen.EmitStatement(l)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  loop {
     discard;
   }
 )");
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_LoopWithContinuing) {
-  Func("a_statement", {}, ty.void_(), {});
+    Func("a_statement", {}, ty.void_(), {});
 
-  auto* body = Block(create<ast::DiscardStatement>());
-  auto* continuing = Block(CallStmt(Call("a_statement")));
-  auto* l = Loop(body, continuing);
+    auto* body = Block(create<ast::DiscardStatement>());
+    auto* continuing = Block(CallStmt(Call("a_statement")));
+    auto* l = Loop(body, continuing);
 
-  WrapInFunction(l);
+    WrapInFunction(l);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(l)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  loop {
+    ASSERT_TRUE(gen.EmitStatement(l)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  loop {
     discard;
 
     continuing {
@@ -62,23 +64,23 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_ForLoopWithMultiStmtInit) {
-  // var<workgroup> a : atomic<i32>;
-  // for({ignore(1); ignore(2);}; ; ) {
-  //   return;
-  // }
-  Global("a", ty.atomic<i32>(), ast::StorageClass::kWorkgroup);
-  auto* multi_stmt = Block(Ignore(1), Ignore(2));
-  auto* f = For(multi_stmt, nullptr, nullptr, Block(Return()));
-  WrapInFunction(f);
+    // var<workgroup> a : atomic<i32>;
+    // for({ignore(1i); ignore(2i);}; ; ) {
+    //   return;
+    // }
+    Global("a", ty.atomic<i32>(), ast::StorageClass::kWorkgroup);
+    auto* multi_stmt = Block(Ignore(1_i), Ignore(2_i));
+    auto* f = For(multi_stmt, nullptr, nullptr, Block(Return()));
+    WrapInFunction(f);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  for({
-    _ = 1;
-    _ = 2;
+    ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  for({
+    _ = 1i;
+    _ = 2i;
   }; ; ) {
     return;
   }
@@ -86,63 +88,63 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_ForLoopWithSimpleCond) {
-  // for(; true; ) {
-  //   return;
-  // }
+    // for(; true; ) {
+    //   return;
+    // }
 
-  auto* f = For(nullptr, true, nullptr, Block(Return()));
-  WrapInFunction(f);
+    auto* f = For(nullptr, true, nullptr, Block(Return()));
+    WrapInFunction(f);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  for(; true; ) {
+    ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  for(; true; ) {
     return;
   }
 )");
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_ForLoopWithSimpleCont) {
-  // for(; ; i = i + 1) {
-  //   return;
-  // }
+    // for(; ; i = i + 1i) {
+    //   return;
+    // }
 
-  auto* v = Decl(Var("i", ty.i32()));
-  auto* f = For(nullptr, nullptr, Assign("i", Add("i", 1)), Block(Return()));
-  WrapInFunction(v, f);
+    auto* v = Decl(Var("i", ty.i32()));
+    auto* f = For(nullptr, nullptr, Assign("i", Add("i", 1_i)), Block(Return()));
+    WrapInFunction(v, f);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  for(; ; i = (i + 1)) {
+    ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  for(; ; i = (i + 1i)) {
     return;
   }
 )");
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_ForLoopWithMultiStmtCont) {
-  // var<workgroup> a : atomic<i32>;
-  // for(; ; { ignore(1); ignore(2); }) {
-  //   return;
-  // }
+    // var<workgroup> a : atomic<i32>;
+    // for(; ; { ignore(1i); ignore(2i); }) {
+    //   return;
+    // }
 
-  Global("a", ty.atomic<i32>(), ast::StorageClass::kWorkgroup);
-  auto* multi_stmt = Block(Ignore(1), Ignore(2));
-  auto* f = For(nullptr, nullptr, multi_stmt, Block(Return()));
-  WrapInFunction(f);
+    Global("a", ty.atomic<i32>(), ast::StorageClass::kWorkgroup);
+    auto* multi_stmt = Block(Ignore(1_i), Ignore(2_i));
+    auto* f = For(nullptr, nullptr, multi_stmt, Block(Return()));
+    WrapInFunction(f);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  for(; ; {
-    _ = 1;
-    _ = 2;
+    ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  for(; ; {
+    _ = 1i;
+    _ = 2i;
   }) {
     return;
   }
@@ -150,47 +152,46 @@
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_ForLoopWithSimpleInitCondCont) {
-  // for(var i : i32; true; i = i + 1) {
-  //   return;
-  // }
+    // for(var i : i32; true; i = i + 1i) {
+    //   return;
+    // }
 
-  auto* f = For(Decl(Var("i", ty.i32())), true, Assign("i", Add("i", 1)),
-                Block(Return()));
-  WrapInFunction(f);
+    auto* f = For(Decl(Var("i", ty.i32())), true, Assign("i", Add("i", 1_i)), Block(Return()));
+    WrapInFunction(f);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  for(var i : i32; true; i = (i + 1)) {
+    ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  for(var i : i32; true; i = (i + 1i)) {
     return;
   }
 )");
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_ForLoopWithMultiStmtInitCondCont) {
-  // var<workgroup> a : atomic<i32>;
-  // for({ ignore(1); ignore(2); }; true; { ignore(3); ignore(4); }) {
-  //   return;
-  // }
-  Global("a", ty.atomic<i32>(), ast::StorageClass::kWorkgroup);
-  auto* multi_stmt_a = Block(Ignore(1), Ignore(2));
-  auto* multi_stmt_b = Block(Ignore(3), Ignore(4));
-  auto* f = For(multi_stmt_a, Expr(true), multi_stmt_b, Block(Return()));
-  WrapInFunction(f);
+    // var<workgroup> a : atomic<i32>;
+    // for({ ignore(1i); ignore(2i); }; true; { ignore(3i); ignore(4i); }) {
+    //   return;
+    // }
+    Global("a", ty.atomic<i32>(), ast::StorageClass::kWorkgroup);
+    auto* multi_stmt_a = Block(Ignore(1_i), Ignore(2_i));
+    auto* multi_stmt_b = Block(Ignore(3_i), Ignore(4_i));
+    auto* f = For(multi_stmt_a, Expr(true), multi_stmt_b, Block(Return()));
+    WrapInFunction(f);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  for({
-    _ = 1;
-    _ = 2;
+    ASSERT_TRUE(gen.EmitStatement(f)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  for({
+    _ = 1i;
+    _ = 2i;
   }; true; {
-    _ = 3;
-    _ = 4;
+    _ = 3i;
+    _ = 4i;
   }) {
     return;
   }
diff --git a/src/tint/writer/wgsl/generator_impl_member_accessor_test.cc b/src/tint/writer/wgsl/generator_impl_member_accessor_test.cc
index 6e9d036..d8bd349 100644
--- a/src/tint/writer/wgsl/generator_impl_member_accessor_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_member_accessor_test.cc
@@ -20,32 +20,32 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, EmitExpression_MemberAccessor) {
-  auto* s = Structure("Data", {Member("mem", ty.f32())});
-  Global("str", ty.Of(s), ast::StorageClass::kPrivate);
+    auto* s = Structure("Data", {Member("mem", ty.f32())});
+    Global("str", ty.Of(s), ast::StorageClass::kPrivate);
 
-  auto* expr = MemberAccessor("str", "mem");
-  WrapInFunction(expr);
+    auto* expr = MemberAccessor("str", "mem");
+    WrapInFunction(expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), "str.mem");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), "str.mem");
 }
 
 TEST_F(WgslGeneratorImplTest, EmitExpression_MemberAccessor_OfDref) {
-  auto* s = Structure("Data", {Member("mem", ty.f32())});
-  Global("str", ty.Of(s), ast::StorageClass::kPrivate);
+    auto* s = Structure("Data", {Member("mem", ty.f32())});
+    Global("str", ty.Of(s), ast::StorageClass::kPrivate);
 
-  auto* p = Const("p", nullptr, AddressOf("str"));
-  auto* expr = MemberAccessor(Deref("p"), "mem");
-  WrapInFunction(p, expr);
+    auto* p = Let("p", nullptr, AddressOf("str"));
+    auto* expr = MemberAccessor(Deref("p"), "mem");
+    WrapInFunction(p, expr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
-  EXPECT_EQ(out.str(), "(*(p)).mem");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, expr)) << gen.error();
+    EXPECT_EQ(out.str(), "(*(p)).mem");
 }
 
 }  // namespace
diff --git a/src/tint/writer/wgsl/generator_impl_return_test.cc b/src/tint/writer/wgsl/generator_impl_return_test.cc
index 68f4103..ed1027d 100644
--- a/src/tint/writer/wgsl/generator_impl_return_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_return_test.cc
@@ -14,33 +14,35 @@
 
 #include "src/tint/writer/wgsl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::wgsl {
 namespace {
 
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, Emit_Return) {
-  auto* r = Return();
-  WrapInFunction(r);
+    auto* r = Return();
+    WrapInFunction(r);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(r)) << gen.error();
-  EXPECT_EQ(gen.result(), "  return;\n");
+    ASSERT_TRUE(gen.EmitStatement(r)) << gen.error();
+    EXPECT_EQ(gen.result(), "  return;\n");
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_ReturnWithValue) {
-  auto* r = Return(123);
-  Func("f", {}, ty.i32(), {r});
+    auto* r = Return(123_i);
+    Func("f", {}, ty.i32(), {r});
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(r)) << gen.error();
-  EXPECT_EQ(gen.result(), "  return 123;\n");
+    ASSERT_TRUE(gen.EmitStatement(r)) << gen.error();
+    EXPECT_EQ(gen.result(), "  return 123i;\n");
 }
 
 }  // namespace
diff --git a/src/tint/writer/wgsl/generator_impl_switch_test.cc b/src/tint/writer/wgsl/generator_impl_switch_test.cc
index 4d722c5..11424f0 100644
--- a/src/tint/writer/wgsl/generator_impl_switch_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_switch_test.cc
@@ -14,39 +14,41 @@
 
 #include "src/tint/writer/wgsl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::wgsl {
 namespace {
 
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, Emit_Switch) {
-  Global("cond", ty.i32(), ast::StorageClass::kPrivate);
+    Global("cond", ty.i32(), ast::StorageClass::kPrivate);
 
-  auto* def_body = Block(create<ast::BreakStatement>());
-  auto* def = create<ast::CaseStatement>(ast::CaseSelectorList{}, def_body);
+    auto* def_body = Block(create<ast::BreakStatement>());
+    auto* def = create<ast::CaseStatement>(ast::CaseSelectorList{}, def_body);
 
-  ast::CaseSelectorList case_val;
-  case_val.push_back(Expr(5));
+    ast::CaseSelectorList case_val;
+    case_val.push_back(Expr(5_i));
 
-  auto* case_body = Block(create<ast::BreakStatement>());
+    auto* case_body = Block(create<ast::BreakStatement>());
 
-  auto* case_stmt = create<ast::CaseStatement>(case_val, case_body);
+    auto* case_stmt = create<ast::CaseStatement>(case_val, case_body);
 
-  ast::CaseStatementList body;
-  body.push_back(case_stmt);
-  body.push_back(def);
+    ast::CaseStatementList body;
+    body.push_back(case_stmt);
+    body.push_back(def);
 
-  auto* cond = Expr("cond");
-  auto* s = create<ast::SwitchStatement>(cond, body);
-  WrapInFunction(s);
+    auto* cond = Expr("cond");
+    auto* s = create<ast::SwitchStatement>(cond, body);
+    WrapInFunction(s);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(s)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(  switch(cond) {
-    case 5: {
+    ASSERT_TRUE(gen.EmitStatement(s)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(  switch(cond) {
+    case 5i: {
       break;
     }
     default: {
diff --git a/src/tint/writer/wgsl/generator_impl_test.cc b/src/tint/writer/wgsl/generator_impl_test.cc
index b526f55..f8972c7 100644
--- a/src/tint/writer/wgsl/generator_impl_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_test.cc
@@ -21,13 +21,12 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, Generate) {
-  Func("my_func", ast::VariableList{}, ty.void_(), ast::StatementList{},
-       ast::AttributeList{});
+    Func("my_func", ast::VariableList{}, ty.void_(), ast::StatementList{}, ast::AttributeList{});
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.Generate()) << gen.error();
-  EXPECT_EQ(gen.result(), R"(fn my_func() {
+    ASSERT_TRUE(gen.Generate()) << gen.error();
+    EXPECT_EQ(gen.result(), R"(fn my_func() {
 }
 )");
 }
diff --git a/src/tint/writer/wgsl/generator_impl_type_test.cc b/src/tint/writer/wgsl/generator_impl_type_test.cc
index 8dc9add..0973ffa 100644
--- a/src/tint/writer/wgsl/generator_impl_type_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_type_test.cc
@@ -12,153 +12,154 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include "src/tint/sem/depth_texture_type.h"
-#include "src/tint/sem/multisampled_texture_type.h"
-#include "src/tint/sem/sampled_texture_type.h"
+#include "src/tint/sem/depth_texture.h"
+#include "src/tint/sem/multisampled_texture.h"
+#include "src/tint/sem/sampled_texture.h"
 #include "src/tint/writer/wgsl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::wgsl {
 namespace {
 
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, EmitType_Alias) {
-  auto* alias = Alias("alias", ty.f32());
-  auto* alias_ty = ty.Of(alias);
-  WrapInFunction(Var("make_reachable", alias_ty));
+    auto* alias = Alias("alias", ty.f32());
+    auto* alias_ty = ty.Of(alias);
+    WrapInFunction(Var("make_reachable", alias_ty));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, alias_ty)) << gen.error();
-  EXPECT_EQ(out.str(), "alias");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, alias_ty)) << gen.error();
+    EXPECT_EQ(out.str(), "alias");
 }
 
 TEST_F(WgslGeneratorImplTest, EmitType_Array) {
-  auto* arr = ty.array<bool, 4>();
-  Alias("make_type_reachable", arr);
+    auto* arr = ty.array<bool, 4u>();
+    Alias("make_type_reachable", arr);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, arr)) << gen.error();
-  EXPECT_EQ(out.str(), "array<bool, 4>");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, arr)) << gen.error();
+    EXPECT_EQ(out.str(), "array<bool, 4u>");
 }
 
 TEST_F(WgslGeneratorImplTest, EmitType_Array_Attribute) {
-  auto* a = ty.array(ty.bool_(), 4, 16u);
-  Alias("make_type_reachable", a);
+    auto* a = ty.array(ty.bool_(), 4_u, 16u);
+    Alias("make_type_reachable", a);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, a)) << gen.error();
-  EXPECT_EQ(out.str(), "@stride(16) array<bool, 4>");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, a)) << gen.error();
+    EXPECT_EQ(out.str(), "@stride(16) array<bool, 4u>");
 }
 
 TEST_F(WgslGeneratorImplTest, EmitType_RuntimeArray) {
-  auto* a = ty.array(ty.bool_());
-  Alias("make_type_reachable", a);
+    auto* a = ty.array(ty.bool_());
+    Alias("make_type_reachable", a);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, a)) << gen.error();
-  EXPECT_EQ(out.str(), "array<bool>");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, a)) << gen.error();
+    EXPECT_EQ(out.str(), "array<bool>");
 }
 
 TEST_F(WgslGeneratorImplTest, EmitType_Bool) {
-  auto* bool_ = ty.bool_();
-  Alias("make_type_reachable", bool_);
+    auto* bool_ = ty.bool_();
+    Alias("make_type_reachable", bool_);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, bool_)) << gen.error();
-  EXPECT_EQ(out.str(), "bool");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, bool_)) << gen.error();
+    EXPECT_EQ(out.str(), "bool");
 }
 
 TEST_F(WgslGeneratorImplTest, EmitType_F32) {
-  auto* f32 = ty.f32();
-  Alias("make_type_reachable", f32);
+    auto* f32 = ty.f32();
+    Alias("make_type_reachable", f32);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, f32)) << gen.error();
-  EXPECT_EQ(out.str(), "f32");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, f32)) << gen.error();
+    EXPECT_EQ(out.str(), "f32");
 }
 
 TEST_F(WgslGeneratorImplTest, EmitType_I32) {
-  auto* i32 = ty.i32();
-  Alias("make_type_reachable", i32);
+    auto* i32 = ty.i32();
+    Alias("make_type_reachable", i32);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, i32)) << gen.error();
-  EXPECT_EQ(out.str(), "i32");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, i32)) << gen.error();
+    EXPECT_EQ(out.str(), "i32");
 }
 
 TEST_F(WgslGeneratorImplTest, EmitType_Matrix) {
-  auto* mat2x3 = ty.mat2x3<f32>();
-  Alias("make_type_reachable", mat2x3);
+    auto* mat2x3 = ty.mat2x3<f32>();
+    Alias("make_type_reachable", mat2x3);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, mat2x3)) << gen.error();
-  EXPECT_EQ(out.str(), "mat2x3<f32>");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, mat2x3)) << gen.error();
+    EXPECT_EQ(out.str(), "mat2x3<f32>");
 }
 
 TEST_F(WgslGeneratorImplTest, EmitType_Pointer) {
-  auto* p = ty.pointer<f32>(ast::StorageClass::kWorkgroup);
-  Alias("make_type_reachable", p);
+    auto* p = ty.pointer<f32>(ast::StorageClass::kWorkgroup);
+    Alias("make_type_reachable", p);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, p)) << gen.error();
-  EXPECT_EQ(out.str(), "ptr<workgroup, f32>");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, p)) << gen.error();
+    EXPECT_EQ(out.str(), "ptr<workgroup, f32>");
 }
 
 TEST_F(WgslGeneratorImplTest, EmitType_PointerAccessMode) {
-  auto* p =
-      ty.pointer<f32>(ast::StorageClass::kStorage, ast::Access::kReadWrite);
-  Alias("make_type_reachable", p);
+    auto* p = ty.pointer<f32>(ast::StorageClass::kStorage, ast::Access::kReadWrite);
+    Alias("make_type_reachable", p);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, p)) << gen.error();
-  EXPECT_EQ(out.str(), "ptr<storage, f32, read_write>");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, p)) << gen.error();
+    EXPECT_EQ(out.str(), "ptr<storage, f32, read_write>");
 }
 
 TEST_F(WgslGeneratorImplTest, EmitType_Struct) {
-  auto* s = Structure("S", {
-                               Member("a", ty.i32()),
-                               Member("b", ty.f32()),
-                           });
-  auto* s_ty = ty.Of(s);
-  WrapInFunction(Var("make_reachable", s_ty));
+    auto* s = Structure("S", {
+                                 Member("a", ty.i32()),
+                                 Member("b", ty.f32()),
+                             });
+    auto* s_ty = ty.Of(s);
+    WrapInFunction(Var("make_reachable", s_ty));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, s_ty)) << gen.error();
-  EXPECT_EQ(out.str(), "S");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, s_ty)) << gen.error();
+    EXPECT_EQ(out.str(), "S");
 }
 
 TEST_F(WgslGeneratorImplTest, EmitType_StructOffsetDecl) {
-  auto* s = Structure("S", {
-                               Member("a", ty.i32(), {MemberOffset(8)}),
-                               Member("b", ty.f32(), {MemberOffset(16)}),
-                           });
+    auto* s = Structure("S", {
+                                 Member("a", ty.i32(), {MemberOffset(8)}),
+                                 Member("b", ty.f32(), {MemberOffset(16)}),
+                             });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitStructType(s)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(struct S {
+    ASSERT_TRUE(gen.EmitStructType(s)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(struct S {
   @size(8)
   padding : u32,
   a : i32,
@@ -170,16 +171,15 @@
 }
 
 TEST_F(WgslGeneratorImplTest, EmitType_StructOffsetDecl_WithSymbolCollisions) {
-  auto* s =
-      Structure("S", {
-                         Member("tint_0_padding", ty.i32(), {MemberOffset(8)}),
-                         Member("tint_2_padding", ty.f32(), {MemberOffset(16)}),
-                     });
+    auto* s = Structure("S", {
+                                 Member("tint_0_padding", ty.i32(), {MemberOffset(8)}),
+                                 Member("tint_2_padding", ty.f32(), {MemberOffset(16)}),
+                             });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitStructType(s)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(struct S {
+    ASSERT_TRUE(gen.EmitStructType(s)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(struct S {
   @size(8)
   padding : u32,
   tint_0_padding : i32,
@@ -191,15 +191,15 @@
 }
 
 TEST_F(WgslGeneratorImplTest, EmitType_StructAlignDecl) {
-  auto* s = Structure("S", {
-                               Member("a", ty.i32(), {MemberAlign(8)}),
-                               Member("b", ty.f32(), {MemberAlign(16)}),
-                           });
+    auto* s = Structure("S", {
+                                 Member("a", ty.i32(), {MemberAlign(8)}),
+                                 Member("b", ty.f32(), {MemberAlign(16)}),
+                             });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitStructType(s)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(struct S {
+    ASSERT_TRUE(gen.EmitStructType(s)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(struct S {
   @align(8)
   a : i32,
   @align(16)
@@ -209,15 +209,15 @@
 }
 
 TEST_F(WgslGeneratorImplTest, EmitType_StructSizeDecl) {
-  auto* s = Structure("S", {
-                               Member("a", ty.i32(), {MemberSize(16)}),
-                               Member("b", ty.f32(), {MemberSize(32)}),
-                           });
+    auto* s = Structure("S", {
+                                 Member("a", ty.i32(), {MemberSize(16)}),
+                                 Member("b", ty.f32(), {MemberSize(32)}),
+                             });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitStructType(s)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(struct S {
+    ASSERT_TRUE(gen.EmitStructType(s)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(struct S {
   @size(16)
   a : i32,
   @size(32)
@@ -227,15 +227,15 @@
 }
 
 TEST_F(WgslGeneratorImplTest, EmitType_Struct_WithAttribute) {
-  auto* s = Structure("S", {
-                               Member("a", ty.i32()),
-                               Member("b", ty.f32(), {MemberAlign(8)}),
-                           });
+    auto* s = Structure("S", {
+                                 Member("a", ty.i32()),
+                                 Member("b", ty.f32(), {MemberAlign(8)}),
+                             });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitStructType(s)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(struct S {
+    ASSERT_TRUE(gen.EmitStructType(s)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(struct S {
   a : i32,
   @align(8)
   b : f32,
@@ -244,15 +244,14 @@
 }
 
 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::Builtin::kVertexIndex)}),
+                                   Member("b", ty.f32(), {Location(2u)})});
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  ASSERT_TRUE(gen.EmitStructType(s)) << gen.error();
-  EXPECT_EQ(gen.result(), R"(struct S {
+    ASSERT_TRUE(gen.EmitStructType(s)) << gen.error();
+    EXPECT_EQ(gen.result(), R"(struct S {
   @builtin(vertex_index)
   a : u32,
   @location(2)
@@ -262,258 +261,250 @@
 }
 
 TEST_F(WgslGeneratorImplTest, EmitType_U32) {
-  auto* u32 = ty.u32();
-  Alias("make_type_reachable", u32);
+    auto* u32 = ty.u32();
+    Alias("make_type_reachable", u32);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, u32)) << gen.error();
-  EXPECT_EQ(out.str(), "u32");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, u32)) << gen.error();
+    EXPECT_EQ(out.str(), "u32");
 }
 
 TEST_F(WgslGeneratorImplTest, EmitType_Vector) {
-  auto* vec3 = ty.vec3<f32>();
-  Alias("make_type_reachable", vec3);
+    auto* vec3 = ty.vec3<f32>();
+    Alias("make_type_reachable", vec3);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, vec3)) << gen.error();
-  EXPECT_EQ(out.str(), "vec3<f32>");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, vec3)) << gen.error();
+    EXPECT_EQ(out.str(), "vec3<f32>");
 }
 
 struct TextureData {
-  ast::TextureDimension dim;
-  const char* name;
+    ast::TextureDimension dim;
+    const char* name;
 };
 inline std::ostream& operator<<(std::ostream& out, TextureData data) {
-  out << data.name;
-  return out;
+    out << data.name;
+    return out;
 }
 using WgslGenerator_DepthTextureTest = TestParamHelper<TextureData>;
 
 TEST_P(WgslGenerator_DepthTextureTest, EmitType_DepthTexture) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* d = ty.depth_texture(param.dim);
-  Alias("make_type_reachable", d);
+    auto* d = ty.depth_texture(param.dim);
+    Alias("make_type_reachable", d);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, d)) << gen.error();
-  EXPECT_EQ(out.str(), param.name);
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, d)) << gen.error();
+    EXPECT_EQ(out.str(), param.name);
 }
 INSTANTIATE_TEST_SUITE_P(
     WgslGeneratorImplTest,
     WgslGenerator_DepthTextureTest,
-    testing::Values(
-        TextureData{ast::TextureDimension::k2d, "texture_depth_2d"},
-        TextureData{ast::TextureDimension::k2dArray, "texture_depth_2d_array"},
-        TextureData{ast::TextureDimension::kCube, "texture_depth_cube"},
-        TextureData{ast::TextureDimension::kCubeArray,
-                    "texture_depth_cube_array"}));
+    testing::Values(TextureData{ast::TextureDimension::k2d, "texture_depth_2d"},
+                    TextureData{ast::TextureDimension::k2dArray, "texture_depth_2d_array"},
+                    TextureData{ast::TextureDimension::kCube, "texture_depth_cube"},
+                    TextureData{ast::TextureDimension::kCubeArray, "texture_depth_cube_array"}));
 
 using WgslGenerator_SampledTextureTest = TestParamHelper<TextureData>;
 TEST_P(WgslGenerator_SampledTextureTest, EmitType_SampledTexture_F32) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* t = ty.sampled_texture(param.dim, ty.f32());
-  Alias("make_type_reachable", t);
+    auto* t = ty.sampled_texture(param.dim, ty.f32());
+    Alias("make_type_reachable", t);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, t)) << gen.error();
-  EXPECT_EQ(out.str(), std::string(param.name) + "<f32>");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, t)) << gen.error();
+    EXPECT_EQ(out.str(), std::string(param.name) + "<f32>");
 }
 
 TEST_P(WgslGenerator_SampledTextureTest, EmitType_SampledTexture_I32) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* t = ty.sampled_texture(param.dim, ty.i32());
-  Alias("make_type_reachable", t);
+    auto* t = ty.sampled_texture(param.dim, ty.i32());
+    Alias("make_type_reachable", t);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, t)) << gen.error();
-  EXPECT_EQ(out.str(), std::string(param.name) + "<i32>");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, t)) << gen.error();
+    EXPECT_EQ(out.str(), std::string(param.name) + "<i32>");
 }
 
 TEST_P(WgslGenerator_SampledTextureTest, EmitType_SampledTexture_U32) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* t = ty.sampled_texture(param.dim, ty.u32());
-  Alias("make_type_reachable", t);
+    auto* t = ty.sampled_texture(param.dim, ty.u32());
+    Alias("make_type_reachable", t);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, t)) << gen.error();
-  EXPECT_EQ(out.str(), std::string(param.name) + "<u32>");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, t)) << gen.error();
+    EXPECT_EQ(out.str(), std::string(param.name) + "<u32>");
 }
 INSTANTIATE_TEST_SUITE_P(
     WgslGeneratorImplTest,
     WgslGenerator_SampledTextureTest,
-    testing::Values(
-        TextureData{ast::TextureDimension::k1d, "texture_1d"},
-        TextureData{ast::TextureDimension::k2d, "texture_2d"},
-        TextureData{ast::TextureDimension::k2dArray, "texture_2d_array"},
-        TextureData{ast::TextureDimension::k3d, "texture_3d"},
-        TextureData{ast::TextureDimension::kCube, "texture_cube"},
-        TextureData{ast::TextureDimension::kCubeArray, "texture_cube_array"}));
+    testing::Values(TextureData{ast::TextureDimension::k1d, "texture_1d"},
+                    TextureData{ast::TextureDimension::k2d, "texture_2d"},
+                    TextureData{ast::TextureDimension::k2dArray, "texture_2d_array"},
+                    TextureData{ast::TextureDimension::k3d, "texture_3d"},
+                    TextureData{ast::TextureDimension::kCube, "texture_cube"},
+                    TextureData{ast::TextureDimension::kCubeArray, "texture_cube_array"}));
 
 using WgslGenerator_MultiampledTextureTest = TestParamHelper<TextureData>;
 TEST_P(WgslGenerator_MultiampledTextureTest, EmitType_MultisampledTexture_F32) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* t = ty.multisampled_texture(param.dim, ty.f32());
-  Alias("make_type_reachable", t);
+    auto* t = ty.multisampled_texture(param.dim, ty.f32());
+    Alias("make_type_reachable", t);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, t)) << gen.error();
-  EXPECT_EQ(out.str(), std::string(param.name) + "<f32>");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, t)) << gen.error();
+    EXPECT_EQ(out.str(), std::string(param.name) + "<f32>");
 }
 
 TEST_P(WgslGenerator_MultiampledTextureTest, EmitType_MultisampledTexture_I32) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* t = ty.multisampled_texture(param.dim, ty.i32());
-  Alias("make_type_reachable", t);
+    auto* t = ty.multisampled_texture(param.dim, ty.i32());
+    Alias("make_type_reachable", t);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, t)) << gen.error();
-  EXPECT_EQ(out.str(), std::string(param.name) + "<i32>");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, t)) << gen.error();
+    EXPECT_EQ(out.str(), std::string(param.name) + "<i32>");
 }
 
 TEST_P(WgslGenerator_MultiampledTextureTest, EmitType_MultisampledTexture_U32) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* t = ty.multisampled_texture(param.dim, ty.u32());
-  Alias("make_type_reachable", t);
+    auto* t = ty.multisampled_texture(param.dim, ty.u32());
+    Alias("make_type_reachable", t);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, t)) << gen.error();
-  EXPECT_EQ(out.str(), std::string(param.name) + "<u32>");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, t)) << gen.error();
+    EXPECT_EQ(out.str(), std::string(param.name) + "<u32>");
 }
 INSTANTIATE_TEST_SUITE_P(WgslGeneratorImplTest,
                          WgslGenerator_MultiampledTextureTest,
-                         testing::Values(TextureData{
-                             ast::TextureDimension::k2d,
-                             "texture_multisampled_2d"}));
+                         testing::Values(TextureData{ast::TextureDimension::k2d,
+                                                     "texture_multisampled_2d"}));
 
 struct StorageTextureData {
-  ast::TexelFormat fmt;
-  ast::TextureDimension dim;
-  ast::Access access;
-  const char* name;
+    ast::TexelFormat fmt;
+    ast::TextureDimension dim;
+    ast::Access access;
+    const char* name;
 };
 inline std::ostream& operator<<(std::ostream& out, StorageTextureData data) {
-  out << data.name;
-  return out;
+    out << data.name;
+    return out;
 }
 using WgslGenerator_StorageTextureTest = TestParamHelper<StorageTextureData>;
 TEST_P(WgslGenerator_StorageTextureTest, EmitType_StorageTexture) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  auto* t = ty.storage_texture(param.dim, param.fmt, param.access);
-  Global("g", t,
-         ast::AttributeList{
-             create<ast::BindingAttribute>(1),
-             create<ast::GroupAttribute>(2),
-         });
+    auto* t = ty.storage_texture(param.dim, param.fmt, param.access);
+    Global("g", t,
+           ast::AttributeList{
+               create<ast::BindingAttribute>(1),
+               create<ast::GroupAttribute>(2),
+           });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, t)) << gen.error();
-  EXPECT_EQ(out.str(), param.name);
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, t)) << gen.error();
+    EXPECT_EQ(out.str(), param.name);
 }
 INSTANTIATE_TEST_SUITE_P(
     WgslGeneratorImplTest,
     WgslGenerator_StorageTextureTest,
-    testing::Values(
-        StorageTextureData{ast::TexelFormat::kRgba8Sint,
-                           ast::TextureDimension::k1d, ast::Access::kWrite,
-                           "texture_storage_1d<rgba8sint, write>"},
-        StorageTextureData{ast::TexelFormat::kRgba8Sint,
-                           ast::TextureDimension::k2d, ast::Access::kWrite,
-                           "texture_storage_2d<rgba8sint, write>"},
-        StorageTextureData{ast::TexelFormat::kRgba8Sint,
-                           ast::TextureDimension::k2dArray, ast::Access::kWrite,
-                           "texture_storage_2d_array<rgba8sint, write>"},
-        StorageTextureData{ast::TexelFormat::kRgba8Sint,
-                           ast::TextureDimension::k3d, ast::Access::kWrite,
-                           "texture_storage_3d<rgba8sint, write>"}));
+    testing::Values(StorageTextureData{ast::TexelFormat::kRgba8Sint, ast::TextureDimension::k1d,
+                                       ast::Access::kWrite, "texture_storage_1d<rgba8sint, write>"},
+                    StorageTextureData{ast::TexelFormat::kRgba8Sint, ast::TextureDimension::k2d,
+                                       ast::Access::kWrite, "texture_storage_2d<rgba8sint, write>"},
+                    StorageTextureData{ast::TexelFormat::kRgba8Sint,
+                                       ast::TextureDimension::k2dArray, ast::Access::kWrite,
+                                       "texture_storage_2d_array<rgba8sint, write>"},
+                    StorageTextureData{ast::TexelFormat::kRgba8Sint, ast::TextureDimension::k3d,
+                                       ast::Access::kWrite,
+                                       "texture_storage_3d<rgba8sint, write>"}));
 
 struct ImageFormatData {
-  ast::TexelFormat fmt;
-  const char* name;
+    ast::TexelFormat fmt;
+    const char* name;
 };
 inline std::ostream& operator<<(std::ostream& out, ImageFormatData data) {
-  out << data.name;
-  return out;
+    out << data.name;
+    return out;
 }
 using WgslGenerator_ImageFormatTest = TestParamHelper<ImageFormatData>;
 TEST_P(WgslGenerator_ImageFormatTest, EmitType_StorageTexture_ImageFormat) {
-  auto param = GetParam();
+    auto param = GetParam();
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitImageFormat(out, param.fmt)) << gen.error();
-  EXPECT_EQ(out.str(), param.name);
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitImageFormat(out, param.fmt)) << gen.error();
+    EXPECT_EQ(out.str(), param.name);
 }
 
 INSTANTIATE_TEST_SUITE_P(
     WgslGeneratorImplTest,
     WgslGenerator_ImageFormatTest,
-    testing::Values(
-        ImageFormatData{ast::TexelFormat::kR32Uint, "r32uint"},
-        ImageFormatData{ast::TexelFormat::kR32Sint, "r32sint"},
-        ImageFormatData{ast::TexelFormat::kR32Float, "r32float"},
-        ImageFormatData{ast::TexelFormat::kRgba8Unorm, "rgba8unorm"},
-        ImageFormatData{ast::TexelFormat::kRgba8Snorm, "rgba8snorm"},
-        ImageFormatData{ast::TexelFormat::kRgba8Uint, "rgba8uint"},
-        ImageFormatData{ast::TexelFormat::kRgba8Sint, "rgba8sint"},
-        ImageFormatData{ast::TexelFormat::kRg32Uint, "rg32uint"},
-        ImageFormatData{ast::TexelFormat::kRg32Sint, "rg32sint"},
-        ImageFormatData{ast::TexelFormat::kRg32Float, "rg32float"},
-        ImageFormatData{ast::TexelFormat::kRgba16Uint, "rgba16uint"},
-        ImageFormatData{ast::TexelFormat::kRgba16Sint, "rgba16sint"},
-        ImageFormatData{ast::TexelFormat::kRgba16Float, "rgba16float"},
-        ImageFormatData{ast::TexelFormat::kRgba32Uint, "rgba32uint"},
-        ImageFormatData{ast::TexelFormat::kRgba32Sint, "rgba32sint"},
-        ImageFormatData{ast::TexelFormat::kRgba32Float, "rgba32float"}));
+    testing::Values(ImageFormatData{ast::TexelFormat::kR32Uint, "r32uint"},
+                    ImageFormatData{ast::TexelFormat::kR32Sint, "r32sint"},
+                    ImageFormatData{ast::TexelFormat::kR32Float, "r32float"},
+                    ImageFormatData{ast::TexelFormat::kRgba8Unorm, "rgba8unorm"},
+                    ImageFormatData{ast::TexelFormat::kRgba8Snorm, "rgba8snorm"},
+                    ImageFormatData{ast::TexelFormat::kRgba8Uint, "rgba8uint"},
+                    ImageFormatData{ast::TexelFormat::kRgba8Sint, "rgba8sint"},
+                    ImageFormatData{ast::TexelFormat::kRg32Uint, "rg32uint"},
+                    ImageFormatData{ast::TexelFormat::kRg32Sint, "rg32sint"},
+                    ImageFormatData{ast::TexelFormat::kRg32Float, "rg32float"},
+                    ImageFormatData{ast::TexelFormat::kRgba16Uint, "rgba16uint"},
+                    ImageFormatData{ast::TexelFormat::kRgba16Sint, "rgba16sint"},
+                    ImageFormatData{ast::TexelFormat::kRgba16Float, "rgba16float"},
+                    ImageFormatData{ast::TexelFormat::kRgba32Uint, "rgba32uint"},
+                    ImageFormatData{ast::TexelFormat::kRgba32Sint, "rgba32sint"},
+                    ImageFormatData{ast::TexelFormat::kRgba32Float, "rgba32float"}));
 
 TEST_F(WgslGeneratorImplTest, EmitType_Sampler) {
-  auto* sampler = ty.sampler(ast::SamplerKind::kSampler);
-  Alias("make_type_reachable", sampler);
+    auto* sampler = ty.sampler(ast::SamplerKind::kSampler);
+    Alias("make_type_reachable", sampler);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, sampler)) << gen.error();
-  EXPECT_EQ(out.str(), "sampler");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, sampler)) << gen.error();
+    EXPECT_EQ(out.str(), "sampler");
 }
 
 TEST_F(WgslGeneratorImplTest, EmitType_SamplerComparison) {
-  auto* sampler = ty.sampler(ast::SamplerKind::kComparisonSampler);
-  Alias("make_type_reachable", sampler);
+    auto* sampler = ty.sampler(ast::SamplerKind::kComparisonSampler);
+    Alias("make_type_reachable", sampler);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitType(out, sampler)) << gen.error();
-  EXPECT_EQ(out.str(), "sampler_comparison");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitType(out, sampler)) << gen.error();
+    EXPECT_EQ(out.str(), "sampler_comparison");
 }
 
 }  // namespace
diff --git a/src/tint/writer/wgsl/generator_impl_unary_op_test.cc b/src/tint/writer/wgsl/generator_impl_unary_op_test.cc
index 1d19ca9..2c46b44 100644
--- a/src/tint/writer/wgsl/generator_impl_unary_op_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_unary_op_test.cc
@@ -20,70 +20,65 @@
 using WgslUnaryOpTest = TestHelper;
 
 TEST_F(WgslUnaryOpTest, AddressOf) {
-  Global("expr", ty.f32(), ast::StorageClass::kPrivate);
-  auto* op =
-      create<ast::UnaryOpExpression>(ast::UnaryOp::kAddressOf, Expr("expr"));
-  WrapInFunction(op);
+    Global("expr", ty.f32(), ast::StorageClass::kPrivate);
+    auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kAddressOf, Expr("expr"));
+    WrapInFunction(op);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
-  EXPECT_EQ(out.str(), "&(expr)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
+    EXPECT_EQ(out.str(), "&(expr)");
 }
 
 TEST_F(WgslUnaryOpTest, Complement) {
-  Global("expr", ty.u32(), ast::StorageClass::kPrivate);
-  auto* op =
-      create<ast::UnaryOpExpression>(ast::UnaryOp::kComplement, Expr("expr"));
-  WrapInFunction(op);
+    Global("expr", ty.u32(), ast::StorageClass::kPrivate);
+    auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kComplement, Expr("expr"));
+    WrapInFunction(op);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
-  EXPECT_EQ(out.str(), "~(expr)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
+    EXPECT_EQ(out.str(), "~(expr)");
 }
 
 TEST_F(WgslUnaryOpTest, Indirection) {
-  Global("G", ty.f32(), ast::StorageClass::kPrivate);
-  auto* p = Const(
-      "expr", nullptr,
-      create<ast::UnaryOpExpression>(ast::UnaryOp::kAddressOf, Expr("G")));
-  auto* op =
-      create<ast::UnaryOpExpression>(ast::UnaryOp::kIndirection, Expr("expr"));
-  WrapInFunction(p, op);
+    Global("G", ty.f32(), ast::StorageClass::kPrivate);
+    auto* p =
+        Let("expr", nullptr, create<ast::UnaryOpExpression>(ast::UnaryOp::kAddressOf, Expr("G")));
+    auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kIndirection, Expr("expr"));
+    WrapInFunction(p, op);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
-  EXPECT_EQ(out.str(), "*(expr)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
+    EXPECT_EQ(out.str(), "*(expr)");
 }
 
 TEST_F(WgslUnaryOpTest, Not) {
-  Global("expr", ty.bool_(), ast::StorageClass::kPrivate);
-  auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kNot, Expr("expr"));
-  WrapInFunction(op);
+    Global("expr", ty.bool_(), ast::StorageClass::kPrivate);
+    auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kNot, Expr("expr"));
+    WrapInFunction(op);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
-  EXPECT_EQ(out.str(), "!(expr)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
+    EXPECT_EQ(out.str(), "!(expr)");
 }
 
 TEST_F(WgslUnaryOpTest, Negation) {
-  Global("expr", ty.i32(), ast::StorageClass::kPrivate);
-  auto* op =
-      create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation, Expr("expr"));
-  WrapInFunction(op);
+    Global("expr", ty.i32(), ast::StorageClass::kPrivate);
+    auto* op = create<ast::UnaryOpExpression>(ast::UnaryOp::kNegation, Expr("expr"));
+    WrapInFunction(op);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
-  EXPECT_EQ(out.str(), "-(expr)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitExpression(out, op)) << gen.error();
+    EXPECT_EQ(out.str(), "-(expr)");
 }
 
 }  // namespace
diff --git a/src/tint/writer/wgsl/generator_impl_variable_decl_statement_test.cc b/src/tint/writer/wgsl/generator_impl_variable_decl_statement_test.cc
index 5d8a026..a68932c 100644
--- a/src/tint/writer/wgsl/generator_impl_variable_decl_statement_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_variable_decl_statement_test.cc
@@ -15,37 +15,39 @@
 #include "src/tint/ast/variable_decl_statement.h"
 #include "src/tint/writer/wgsl/test_helper.h"
 
+using namespace tint::number_suffixes;  // NOLINT
+
 namespace tint::writer::wgsl {
 namespace {
 
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement) {
-  auto* var = Var("a", ty.f32());
+    auto* var = Var("a", ty.f32());
 
-  auto* stmt = Decl(var);
-  WrapInFunction(stmt);
+    auto* stmt = Decl(var);
+    WrapInFunction(stmt);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
-  EXPECT_EQ(gen.result(), "  var a : f32;\n");
+    ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
+    EXPECT_EQ(gen.result(), "  var a : f32;\n");
 }
 
 TEST_F(WgslGeneratorImplTest, Emit_VariableDeclStatement_InferredType) {
-  auto* var = Var("a", nullptr, ast::StorageClass::kNone, Expr(123));
+    auto* var = Var("a", nullptr, ast::StorageClass::kNone, Expr(123_i));
 
-  auto* stmt = Decl(var);
-  WrapInFunction(stmt);
+    auto* stmt = Decl(var);
+    WrapInFunction(stmt);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  gen.increment_indent();
+    gen.increment_indent();
 
-  ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
-  EXPECT_EQ(gen.result(), "  var a = 123;\n");
+    ASSERT_TRUE(gen.EmitStatement(stmt)) << gen.error();
+    EXPECT_EQ(gen.result(), "  var a = 123i;\n");
 }
 
 }  // namespace
diff --git a/src/tint/writer/wgsl/generator_impl_variable_test.cc b/src/tint/writer/wgsl/generator_impl_variable_test.cc
index 8d239ed..8ebe6c5 100644
--- a/src/tint/writer/wgsl/generator_impl_variable_test.cc
+++ b/src/tint/writer/wgsl/generator_impl_variable_test.cc
@@ -20,108 +20,103 @@
 using WgslGeneratorImplTest = TestHelper;
 
 TEST_F(WgslGeneratorImplTest, EmitVariable) {
-  auto* v = Global("a", ty.f32(), ast::StorageClass::kPrivate);
+    auto* v = Global("a", ty.f32(), ast::StorageClass::kPrivate);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitVariable(out, v)) << gen.error();
-  EXPECT_EQ(out.str(), R"(var<private> a : f32;)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitVariable(out, v)) << gen.error();
+    EXPECT_EQ(out.str(), R"(var<private> a : f32;)");
 }
 
 TEST_F(WgslGeneratorImplTest, EmitVariable_StorageClass) {
-  auto* v = Global("a", ty.f32(), ast::StorageClass::kPrivate);
+    auto* v = Global("a", ty.f32(), ast::StorageClass::kPrivate);
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitVariable(out, v)) << gen.error();
-  EXPECT_EQ(out.str(), R"(var<private> a : f32;)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitVariable(out, v)) << gen.error();
+    EXPECT_EQ(out.str(), R"(var<private> a : f32;)");
 }
 
 TEST_F(WgslGeneratorImplTest, EmitVariable_Access_Read) {
-  auto* s = Structure("S", {Member("a", ty.i32())});
-  auto* v =
-      Global("a", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
-             ast::AttributeList{
-                 create<ast::BindingAttribute>(0),
-                 create<ast::GroupAttribute>(0),
-             });
+    auto* s = Structure("S", {Member("a", ty.i32())});
+    auto* v = Global("a", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kRead,
+                     ast::AttributeList{
+                         create<ast::BindingAttribute>(0),
+                         create<ast::GroupAttribute>(0),
+                     });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitVariable(out, v)) << gen.error();
-  EXPECT_EQ(out.str(), R"(@binding(0) @group(0) var<storage, read> a : S;)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitVariable(out, v)) << gen.error();
+    EXPECT_EQ(out.str(), R"(@binding(0) @group(0) var<storage, read> a : S;)");
 }
 
 TEST_F(WgslGeneratorImplTest, EmitVariable_Access_Write) {
-  auto* s = Structure("S", {Member("a", ty.i32())});
-  auto* v =
-      Global("a", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kWrite,
-             ast::AttributeList{
-                 create<ast::BindingAttribute>(0),
-                 create<ast::GroupAttribute>(0),
-             });
+    auto* s = Structure("S", {Member("a", ty.i32())});
+    auto* v = Global("a", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kWrite,
+                     ast::AttributeList{
+                         create<ast::BindingAttribute>(0),
+                         create<ast::GroupAttribute>(0),
+                     });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitVariable(out, v)) << gen.error();
-  EXPECT_EQ(out.str(), R"(@binding(0) @group(0) var<storage, write> a : S;)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitVariable(out, v)) << gen.error();
+    EXPECT_EQ(out.str(), R"(@binding(0) @group(0) var<storage, write> a : S;)");
 }
 
 TEST_F(WgslGeneratorImplTest, EmitVariable_Access_ReadWrite) {
-  auto* s = Structure("S", {Member("a", ty.i32())});
-  auto* v = Global("a", ty.Of(s), ast::StorageClass::kStorage,
-                   ast::Access::kReadWrite,
-                   ast::AttributeList{
-                       create<ast::BindingAttribute>(0),
-                       create<ast::GroupAttribute>(0),
-                   });
+    auto* s = Structure("S", {Member("a", ty.i32())});
+    auto* v = Global("a", ty.Of(s), ast::StorageClass::kStorage, ast::Access::kReadWrite,
+                     ast::AttributeList{
+                         create<ast::BindingAttribute>(0),
+                         create<ast::GroupAttribute>(0),
+                     });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitVariable(out, v)) << gen.error();
-  EXPECT_EQ(out.str(),
-            R"(@binding(0) @group(0) var<storage, read_write> a : S;)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitVariable(out, v)) << gen.error();
+    EXPECT_EQ(out.str(), R"(@binding(0) @group(0) var<storage, read_write> a : S;)");
 }
 
 TEST_F(WgslGeneratorImplTest, EmitVariable_Decorated) {
-  auto* v = Global("a", ty.sampler(ast::SamplerKind::kSampler),
-                   ast::StorageClass::kNone, nullptr,
-                   ast::AttributeList{
-                       create<ast::GroupAttribute>(1),
-                       create<ast::BindingAttribute>(2),
-                   });
+    auto* v = Global("a", ty.sampler(ast::SamplerKind::kSampler), ast::StorageClass::kNone, nullptr,
+                     ast::AttributeList{
+                         create<ast::GroupAttribute>(1),
+                         create<ast::BindingAttribute>(2),
+                     });
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitVariable(out, v)) << gen.error();
-  EXPECT_EQ(out.str(), R"(@group(1) @binding(2) var a : sampler;)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitVariable(out, v)) << gen.error();
+    EXPECT_EQ(out.str(), R"(@group(1) @binding(2) var a : sampler;)");
 }
 
 TEST_F(WgslGeneratorImplTest, EmitVariable_Constructor) {
-  auto* v = Global("a", ty.f32(), ast::StorageClass::kPrivate, Expr(1.0f));
+    auto* v = Global("a", ty.f32(), ast::StorageClass::kPrivate, Expr(1.0f));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitVariable(out, v)) << gen.error();
-  EXPECT_EQ(out.str(), R"(var<private> a : f32 = 1.0;)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitVariable(out, v)) << gen.error();
+    EXPECT_EQ(out.str(), R"(var<private> a : f32 = 1.0;)");
 }
 
 TEST_F(WgslGeneratorImplTest, EmitVariable_Const) {
-  auto* v = Const("a", ty.f32(), Expr(1.0f));
-  WrapInFunction(Decl(v));
+    auto* v = Let("a", ty.f32(), Expr(1.0f));
+    WrapInFunction(Decl(v));
 
-  GeneratorImpl& gen = Build();
+    GeneratorImpl& gen = Build();
 
-  std::stringstream out;
-  ASSERT_TRUE(gen.EmitVariable(out, v)) << gen.error();
-  EXPECT_EQ(out.str(), R"(let a : f32 = 1.0;)");
+    std::stringstream out;
+    ASSERT_TRUE(gen.EmitVariable(out, v)) << gen.error();
+    EXPECT_EQ(out.str(), R"(let a : f32 = 1.0;)");
 }
 
 }  // namespace
diff --git a/src/tint/writer/wgsl/test_helper.h b/src/tint/writer/wgsl/test_helper.h
index ca320c4..4cf1e93 100644
--- a/src/tint/writer/wgsl/test_helper.h
+++ b/src/tint/writer/wgsl/test_helper.h
@@ -27,34 +27,31 @@
 /// Helper class for testing
 template <typename BASE>
 class TestHelperBase : public BASE, public ProgramBuilder {
- public:
-  TestHelperBase() = default;
+  public:
+    TestHelperBase() = default;
 
-  ~TestHelperBase() override = default;
+    ~TestHelperBase() override = default;
 
-  /// Builds and returns a GeneratorImpl from the program.
-  /// @note The generator is only built once. Multiple calls to Build() will
-  /// return the same GeneratorImpl without rebuilding.
-  /// @return the built generator
-  GeneratorImpl& Build() {
-    if (gen_) {
-      return *gen_;
+    /// Builds and returns a GeneratorImpl from the program.
+    /// @note The generator is only built once. Multiple calls to Build() will
+    /// return the same GeneratorImpl without rebuilding.
+    /// @return the built generator
+    GeneratorImpl& Build() {
+        if (gen_) {
+            return *gen_;
+        }
+        program = std::make_unique<Program>(std::move(*this));
+        diag::Formatter formatter;
+        [&]() { ASSERT_TRUE(program->IsValid()) << formatter.format(program->Diagnostics()); }();
+        gen_ = std::make_unique<GeneratorImpl>(program.get());
+        return *gen_;
     }
-    program = std::make_unique<Program>(std::move(*this));
-    diag::Formatter formatter;
-    [&]() {
-      ASSERT_TRUE(program->IsValid())
-          << formatter.format(program->Diagnostics());
-    }();
-    gen_ = std::make_unique<GeneratorImpl>(program.get());
-    return *gen_;
-  }
 
-  /// The program built with a call to Build()
-  std::unique_ptr<Program> program;
+    /// The program built with a call to Build()
+    std::unique_ptr<Program> program;
 
- private:
-  std::unique_ptr<GeneratorImpl> gen_;
+  private:
+    std::unique_ptr<GeneratorImpl> gen_;
 };
 using TestHelper = TestHelperBase<testing::Test>;
 
diff --git a/src/tint/writer/writer.h b/src/tint/writer/writer.h
index d09622b..ea7016e 100644
--- a/src/tint/writer/writer.h
+++ b/src/tint/writer/writer.h
@@ -21,23 +21,23 @@
 
 /// Base class for the output writers
 class Writer {
- public:
-  virtual ~Writer();
+  public:
+    virtual ~Writer();
 
-  /// @returns the writer error string
-  const std::string& error() const { return error_; }
+    /// @returns the writer error string
+    const std::string& error() const { return error_; }
 
-  /// Converts the module into the desired format
-  /// @returns true on success; false on failure
-  virtual bool Generate() = 0;
+    /// Converts the module into the desired format
+    /// @returns true on success; false on failure
+    virtual bool Generate() = 0;
 
- protected:
-  /// Sets the error string
-  /// @param msg the error message
-  void set_error(const std::string& msg) { error_ = msg; }
+  protected:
+    /// Sets the error string
+    /// @param msg the error message
+    void set_error(const std::string& msg) { error_ = msg; }
 
-  /// An error message, if an error was encountered
-  std::string error_;
+    /// An error message, if an error was encountered
+    std::string error_;
 };
 
 }  // namespace tint::writer
diff --git a/test/tint/BUILD.gn b/test/tint/BUILD.gn
index bb217df..8111273 100644
--- a/test/tint/BUILD.gn
+++ b/test/tint/BUILD.gn
@@ -163,7 +163,7 @@
     "../../src/tint/ast/depth_multisampled_texture_test.cc",
     "../../src/tint/ast/depth_texture_test.cc",
     "../../src/tint/ast/discard_statement_test.cc",
-    "../../src/tint/ast/else_statement_test.cc",
+    "../../src/tint/ast/enable_test.cc",
     "../../src/tint/ast/external_texture_test.cc",
     "../../src/tint/ast/f32_test.cc",
     "../../src/tint/ast/fallthrough_statement_test.cc",
@@ -192,7 +192,6 @@
     "../../src/tint/ast/return_statement_test.cc",
     "../../src/tint/ast/sampled_texture_test.cc",
     "../../src/tint/ast/sampler_test.cc",
-    "../../src/tint/ast/sint_literal_expression_test.cc",
     "../../src/tint/ast/stage_attribute_test.cc",
     "../../src/tint/ast/storage_texture_test.cc",
     "../../src/tint/ast/stride_attribute_test.cc",
@@ -206,7 +205,6 @@
     "../../src/tint/ast/texture_test.cc",
     "../../src/tint/ast/traverse_expressions_test.cc",
     "../../src/tint/ast/u32_test.cc",
-    "../../src/tint/ast/uint_literal_expression_test.cc",
     "../../src/tint/ast/unary_op_expression_test.cc",
     "../../src/tint/ast/variable_decl_statement_test.cc",
     "../../src/tint/ast/variable_test.cc",
@@ -265,6 +263,7 @@
     "../../src/tint/resolver/resolver_test_helper.cc",
     "../../src/tint/resolver/resolver_test_helper.h",
     "../../src/tint/resolver/side_effects_test.cc",
+    "../../src/tint/resolver/source_variable_test.cc",
     "../../src/tint/resolver/storage_class_layout_validation_test.cc",
     "../../src/tint/resolver/storage_class_validation_test.cc",
     "../../src/tint/resolver/struct_layout_test.cc",
@@ -273,6 +272,7 @@
     "../../src/tint/resolver/type_constructor_validation_test.cc",
     "../../src/tint/resolver/type_validation_test.cc",
     "../../src/tint/resolver/validation_test.cc",
+    "../../src/tint/resolver/validator_is_storeable_test.cc",
     "../../src/tint/resolver/var_let_test.cc",
     "../../src/tint/resolver/var_let_validation_test.cc",
   ]
@@ -281,27 +281,27 @@
 
 tint_unittests_source_set("tint_unittests_sem_src") {
   sources = [
-    "../../src/tint/sem/atomic_type_test.cc",
-    "../../src/tint/sem/bool_type_test.cc",
+    "../../src/tint/sem/atomic_test.cc",
+    "../../src/tint/sem/bool_test.cc",
     "../../src/tint/sem/builtin_test.cc",
-    "../../src/tint/sem/depth_multisampled_texture_type_test.cc",
-    "../../src/tint/sem/depth_texture_type_test.cc",
-    "../../src/tint/sem/external_texture_type_test.cc",
-    "../../src/tint/sem/f32_type_test.cc",
-    "../../src/tint/sem/i32_type_test.cc",
-    "../../src/tint/sem/matrix_type_test.cc",
-    "../../src/tint/sem/multisampled_texture_type_test.cc",
-    "../../src/tint/sem/pointer_type_test.cc",
-    "../../src/tint/sem/reference_type_test.cc",
-    "../../src/tint/sem/sampled_texture_type_test.cc",
-    "../../src/tint/sem/sampler_type_test.cc",
+    "../../src/tint/sem/depth_multisampled_texture_test.cc",
+    "../../src/tint/sem/depth_texture_test.cc",
+    "../../src/tint/sem/external_texture_test.cc",
+    "../../src/tint/sem/f32_test.cc",
+    "../../src/tint/sem/i32_test.cc",
+    "../../src/tint/sem/matrix_test.cc",
+    "../../src/tint/sem/multisampled_texture_test.cc",
+    "../../src/tint/sem/pointer_test.cc",
+    "../../src/tint/sem/reference_test.cc",
+    "../../src/tint/sem/sampled_texture_test.cc",
+    "../../src/tint/sem/sampler_test.cc",
     "../../src/tint/sem/sem_array_test.cc",
     "../../src/tint/sem/sem_struct_test.cc",
-    "../../src/tint/sem/storage_texture_type_test.cc",
-    "../../src/tint/sem/texture_type_test.cc",
+    "../../src/tint/sem/storage_texture_test.cc",
+    "../../src/tint/sem/texture_test.cc",
     "../../src/tint/sem/type_manager_test.cc",
-    "../../src/tint/sem/u32_type_test.cc",
-    "../../src/tint/sem/vector_type_test.cc",
+    "../../src/tint/sem/u32_test.cc",
+    "../../src/tint/sem/vector_test.cc",
   ]
 }
 
@@ -357,6 +357,7 @@
 
 tint_unittests_source_set("tint_unittests_utils_src") {
   sources = [
+    "../../src/tint/utils/bitcast_test.cc",
     "../../src/tint/utils/crc32_test.cc",
     "../../src/tint/utils/defer_test.cc",
     "../../src/tint/utils/enum_set_test.cc",
@@ -377,6 +378,7 @@
 tint_unittests_source_set("tint_unittests_writer_src") {
   sources = [
     "../../src/tint/writer/append_vector_test.cc",
+    "../../src/tint/writer/flatten_bindings_test.cc",
     "../../src/tint/writer/float_to_string_test.cc",
     "../../src/tint/writer/generate_external_texture_bindings_test.cc",
     "../../src/tint/writer/text_generator_test.cc",
@@ -482,13 +484,13 @@
     "../../src/tint/reader/wgsl/parser_impl_const_literal_test.cc",
     "../../src/tint/reader/wgsl/parser_impl_continue_stmt_test.cc",
     "../../src/tint/reader/wgsl/parser_impl_continuing_stmt_test.cc",
-    "../../src/tint/reader/wgsl/parser_impl_depth_texture_type_test.cc",
-    "../../src/tint/reader/wgsl/parser_impl_elseif_stmt_test.cc",
+    "../../src/tint/reader/wgsl/parser_impl_depth_texture_test.cc",
+    "../../src/tint/reader/wgsl/parser_impl_enable_directive_test.cc",
     "../../src/tint/reader/wgsl/parser_impl_equality_expression_test.cc",
     "../../src/tint/reader/wgsl/parser_impl_error_msg_test.cc",
     "../../src/tint/reader/wgsl/parser_impl_error_resync_test.cc",
     "../../src/tint/reader/wgsl/parser_impl_exclusive_or_expression_test.cc",
-    "../../src/tint/reader/wgsl/parser_impl_external_texture_type_test.cc",
+    "../../src/tint/reader/wgsl/parser_impl_external_texture_test.cc",
     "../../src/tint/reader/wgsl/parser_impl_for_stmt_test.cc",
     "../../src/tint/reader/wgsl/parser_impl_function_attribute_list_test.cc",
     "../../src/tint/reader/wgsl/parser_impl_function_attribute_test.cc",
@@ -510,14 +512,14 @@
     "../../src/tint/reader/wgsl/parser_impl_primary_expression_test.cc",
     "../../src/tint/reader/wgsl/parser_impl_relational_expression_test.cc",
     "../../src/tint/reader/wgsl/parser_impl_reserved_keyword_test.cc",
-    "../../src/tint/reader/wgsl/parser_impl_sampled_texture_type_test.cc",
-    "../../src/tint/reader/wgsl/parser_impl_sampler_type_test.cc",
+    "../../src/tint/reader/wgsl/parser_impl_sampled_texture_test.cc",
+    "../../src/tint/reader/wgsl/parser_impl_sampler_test.cc",
     "../../src/tint/reader/wgsl/parser_impl_shift_expression_test.cc",
     "../../src/tint/reader/wgsl/parser_impl_singular_expression_test.cc",
     "../../src/tint/reader/wgsl/parser_impl_statement_test.cc",
     "../../src/tint/reader/wgsl/parser_impl_statements_test.cc",
     "../../src/tint/reader/wgsl/parser_impl_storage_class_test.cc",
-    "../../src/tint/reader/wgsl/parser_impl_storage_texture_type_test.cc",
+    "../../src/tint/reader/wgsl/parser_impl_storage_texture_test.cc",
     "../../src/tint/reader/wgsl/parser_impl_struct_attribute_decl_test.cc",
     "../../src/tint/reader/wgsl/parser_impl_struct_body_decl_test.cc",
     "../../src/tint/reader/wgsl/parser_impl_struct_decl_test.cc",
@@ -530,7 +532,7 @@
     "../../src/tint/reader/wgsl/parser_impl_test_helper.cc",
     "../../src/tint/reader/wgsl/parser_impl_test_helper.h",
     "../../src/tint/reader/wgsl/parser_impl_texel_format_test.cc",
-    "../../src/tint/reader/wgsl/parser_impl_texture_sampler_types_test.cc",
+    "../../src/tint/reader/wgsl/parser_impl_texture_sampler_test.cc",
     "../../src/tint/reader/wgsl/parser_impl_type_alias_test.cc",
     "../../src/tint/reader/wgsl/parser_impl_type_decl_test.cc",
     "../../src/tint/reader/wgsl/parser_impl_unary_expression_test.cc",
@@ -562,6 +564,7 @@
     "../../src/tint/writer/wgsl/generator_impl_constructor_test.cc",
     "../../src/tint/writer/wgsl/generator_impl_continue_test.cc",
     "../../src/tint/writer/wgsl/generator_impl_discard_test.cc",
+    "../../src/tint/writer/wgsl/generator_impl_enable_test.cc",
     "../../src/tint/writer/wgsl/generator_impl_fallthrough_test.cc",
     "../../src/tint/writer/wgsl/generator_impl_function_test.cc",
     "../../src/tint/writer/wgsl/generator_impl_global_decl_test.cc",